From 22969c5e17df3cb9ec65c3966b3a1e8f3b544fbb Mon Sep 17 00:00:00 2001 From: Alessio Morale Date: Thu, 18 Aug 2016 12:10:14 +0200 Subject: [PATCH 001/624] LP-385 - Implement camera trigger output handling --- flight/modules/Actuator/actuator.c | 3 +++ shared/uavobjectdefinition/cameradesired.xml | 1 + shared/uavobjectdefinition/hwsettings.xml | 2 +- shared/uavobjectdefinition/mixersettings.xml | 1 + 4 files changed, 6 insertions(+), 1 deletion(-) diff --git a/flight/modules/Actuator/actuator.c b/flight/modules/Actuator/actuator.c index a2a66838f5..c716bf5c2b 100644 --- a/flight/modules/Actuator/actuator.c +++ b/flight/modules/Actuator/actuator.c @@ -471,6 +471,9 @@ static void actuatorTask(__attribute__((unused)) void *parameters) case MIXERSETTINGS_MIXER1TYPE_CAMERAYAW: status[ct] = cameraDesired.Yaw; break; + case MIXERSETTINGS_MIXER1TYPE_CAMERATRIGGER: + status[ct] = cameraDesired.Trigger; + break; default: break; } diff --git a/shared/uavobjectdefinition/cameradesired.xml b/shared/uavobjectdefinition/cameradesired.xml index fe98c940d2..41510047b8 100644 --- a/shared/uavobjectdefinition/cameradesired.xml +++ b/shared/uavobjectdefinition/cameradesired.xml @@ -4,6 +4,7 @@ + diff --git a/shared/uavobjectdefinition/hwsettings.xml b/shared/uavobjectdefinition/hwsettings.xml index bbbbd5200c..5d139d8b7c 100644 --- a/shared/uavobjectdefinition/hwsettings.xml +++ b/shared/uavobjectdefinition/hwsettings.xml @@ -30,7 +30,7 @@ - + CameraRollOrServo1 + From c7e060c04a854737a1c46515314dfc23863faf63 Mon Sep 17 00:00:00 2001 From: Alessio Morale Date: Thu, 18 Aug 2016 12:40:34 +0200 Subject: [PATCH 002/624] LP-385 - Initial CameraControl module commit --- flight/modules/CameraControl/cameracontrol.c | 63 +++++++++++++++++++ .../modules/CameraControl/inc/cameracontrol.h | 36 +++++++++++ .../boards/revolution/firmware/UAVObjects.inc | 2 + .../gcs/src/plugins/uavobjects/uavobjects.pro | 2 + .../cameracontrolactivity.xml | 24 +++++++ .../cameracontrolsettings.xml | 19 ++++++ 6 files changed, 146 insertions(+) create mode 100644 flight/modules/CameraControl/cameracontrol.c create mode 100644 flight/modules/CameraControl/inc/cameracontrol.h create mode 100644 shared/uavobjectdefinition/cameracontrolactivity.xml create mode 100644 shared/uavobjectdefinition/cameracontrolsettings.xml diff --git a/flight/modules/CameraControl/cameracontrol.c b/flight/modules/CameraControl/cameracontrol.c new file mode 100644 index 0000000000..7b3bde0bac --- /dev/null +++ b/flight/modules/CameraControl/cameracontrol.c @@ -0,0 +1,63 @@ +/** + ****************************************************************************** + * + * @file cameracontrol.c + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. + * @brief camera control module. triggers cameras with multiple options + * + * @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 + * + * Additional note on redistribution: The copyright and license notices above + * must be maintained in each individual source file that is a derivative work + * of this source file; otherwise redistribution is prohibited. + */ + +#include +#include "inc/cameracontrol.h" +#include +#include +#include +#include + +/* +// Private variables +static struct CameraControl_data { + portTickType lastSysTime; +} *ccd; +*/ + +//static void setOutput(); + + +/** + * Initialise the module, called on startup + * \returns 0 on success or -1 if initialisation failed + */ +int32_t CameraControlInitialize(void) +{ + return 0; +} + +/* stub: module has no module thread */ +int32_t CameraControlStart(void) +{ + return 0; +} + +MODULE_INITCALL(CameraControlInitialize, CameraControlStart); diff --git a/flight/modules/CameraControl/inc/cameracontrol.h b/flight/modules/CameraControl/inc/cameracontrol.h new file mode 100644 index 0000000000..c3d61f0cca --- /dev/null +++ b/flight/modules/CameraControl/inc/cameracontrol.h @@ -0,0 +1,36 @@ +/** + ****************************************************************************** + * + * @file cameracontrol.h + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. + * @brief camera control module. triggers cameras with multiple options + * + * @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 + * + * Additional note on redistribution: The copyright and license notices above + * must be maintained in each individual source file that is a derivative work + * of this source file; otherwise redistribution is prohibited. + */ + +#ifndef FLIGHT_MODULES_CAMERACONTROL_INC_CAMERACONTROL_H +#define FLIGHT_MODULES_CAMERACONTROL_INC_CAMERACONTROL_H + + + +#endif /* FLIGHT_MODULES_CAMERACONTROL_INC_CAMERACONTROL_H */ diff --git a/flight/targets/boards/revolution/firmware/UAVObjects.inc b/flight/targets/boards/revolution/firmware/UAVObjects.inc index 6100c47502..5774e7ae43 100644 --- a/flight/targets/boards/revolution/firmware/UAVObjects.inc +++ b/flight/targets/boards/revolution/firmware/UAVObjects.inc @@ -112,6 +112,8 @@ UAVOBJSRCFILENAMES += receiveractivity UAVOBJSRCFILENAMES += receiverstatus UAVOBJSRCFILENAMES += cameradesired UAVOBJSRCFILENAMES += camerastabsettings +UAVOBJSRCFILENAMES += cameracontrolsettings +UAVOBJSRCFILENAMES += cameracontrolactivity UAVOBJSRCFILENAMES += altitudeholdsettings UAVOBJSRCFILENAMES += oplinksettings UAVOBJSRCFILENAMES += oplinkstatus diff --git a/ground/gcs/src/plugins/uavobjects/uavobjects.pro b/ground/gcs/src/plugins/uavobjects/uavobjects.pro index 92be038320..942e797421 100644 --- a/ground/gcs/src/plugins/uavobjects/uavobjects.pro +++ b/ground/gcs/src/plugins/uavobjects/uavobjects.pro @@ -59,6 +59,8 @@ UAVOBJS = \ $${UAVOBJ_XML_DIR}/auxmagsettings.xml \ $${UAVOBJ_XML_DIR}/barosensor.xml \ $${UAVOBJ_XML_DIR}/callbackinfo.xml \ + $${UAVOBJ_XML_DIR}/cameracontrolactivity.xml \ + $${UAVOBJ_XML_DIR}/cameracontrolsettings.xml \ $${UAVOBJ_XML_DIR}/cameradesired.xml \ $${UAVOBJ_XML_DIR}/camerastabsettings.xml \ $${UAVOBJ_XML_DIR}/debuglogcontrol.xml \ diff --git a/shared/uavobjectdefinition/cameracontrolactivity.xml b/shared/uavobjectdefinition/cameracontrolactivity.xml new file mode 100644 index 0000000000..8dcf892137 --- /dev/null +++ b/shared/uavobjectdefinition/cameracontrolactivity.xml @@ -0,0 +1,24 @@ + + + Contains position and timestamp of each camera operation + + + + + + + + + + + + + + + + + + + + + diff --git a/shared/uavobjectdefinition/cameracontrolsettings.xml b/shared/uavobjectdefinition/cameracontrolsettings.xml new file mode 100644 index 0000000000..3e0bb9a73d --- /dev/null +++ b/shared/uavobjectdefinition/cameracontrolsettings.xml @@ -0,0 +1,19 @@ + + + Settings for the @ref CameraControl module + + + + + + + + + + + + + + + + From 88a8e767c45459637edcc8e302ea667b80674c57 Mon Sep 17 00:00:00 2001 From: Alessio Morale Date: Thu, 18 Aug 2016 19:25:55 +0200 Subject: [PATCH 003/624] LP_385 - Implement activation/manual override logic, Camera activity "publishing" --- flight/modules/CameraControl/cameracontrol.c | 223 +++++++++++++++++- .../boards/revolution/firmware/Makefile | 1 + shared/uavobjectdefinition/callbackinfo.xml | 3 + .../cameracontrolactivity.xml | 3 +- .../cameracontrolsettings.xml | 8 +- 5 files changed, 230 insertions(+), 8 deletions(-) diff --git a/flight/modules/CameraControl/cameracontrol.c b/flight/modules/CameraControl/cameracontrol.c index 7b3bde0bac..642ee504a8 100644 --- a/flight/modules/CameraControl/cameracontrol.c +++ b/flight/modules/CameraControl/cameracontrol.c @@ -33,16 +33,47 @@ #include #include #include +#include +#include +#include +#include +#include #include +#include +#include -/* // Private variables + +typedef enum { + CAMERASTATUS_Idle = 0, + CAMERASTATUS_Shot, + CAMERASTATUS_Video +} CameraStatus; + static struct CameraControl_data { - portTickType lastSysTime; + int32_t lastTriggerTimeRaw; + float lastTriggerNEDPosition[3]; + CameraControlSettingsData settings; + CameraControlActivityData activity; + DelayedCallbackInfo *callbackHandle; + CameraStatus outputStatus; + CameraStatus lastOutputStatus; + CameraStatus manualInput; + bool autoTriggerEnabled; } *ccd; -*/ -//static void setOutput(); +#define CALLBACK_PRIORITY CALLBACK_PRIORITY_REGULAR +#define CBTASK_PRIORITY CALLBACK_TASK_AUXILIARY +#define STACK_SIZE_BYTES 512 +#define CALLBACK_STD_PERIOD 50 +#define INPUT_DEADBAND 0.1f + +static void CameraControlTask(); +static void SettingsUpdateCb(__attribute__((unused)) UAVObjEvent *ev); +static void UpdateOutput(); +static void PublishActivity(); +static bool checkActivation(); +static void FillActivityInfo(); /** @@ -51,13 +82,197 @@ static struct CameraControl_data { */ int32_t CameraControlInitialize(void) { + ccd = 0; + HwSettingsInitialize(); + HwSettingsOptionalModulesData modules; + HwSettingsOptionalModulesGet(&modules); + if (modules.CameraControl == HWSETTINGS_OPTIONALMODULES_ENABLED) { + ccd = (struct CameraControl_data *)pios_malloc(sizeof(struct CameraControl_data)); + memset(ccd, 0, sizeof(struct CameraControl_data)); + ccd->callbackHandle = PIOS_CALLBACKSCHEDULER_Create(&CameraControlTask, CALLBACK_PRIORITY, CBTASK_PRIORITY, CALLBACKINFO_RUNNING_CAMERACONTROL, STACK_SIZE_BYTES); + CameraControlActivityInitialize(); + CameraDesiredInitialize(); + CameraControlSettingsInitialize(); + CameraControlSettingsConnectCallback(SettingsUpdateCb); + SettingsUpdateCb(NULL); + + // init output: + ccd->outputStatus = CAMERASTATUS_Idle; + UpdateOutput(); + } return 0; } /* stub: module has no module thread */ int32_t CameraControlStart(void) { + if (!ccd) { + return 0; + } + + PIOS_CALLBACKSCHEDULER_Schedule(ccd->callbackHandle, CALLBACK_STD_PERIOD, CALLBACK_UPDATEMODE_LATER); + ccd->lastTriggerTimeRaw = PIOS_DELAY_GetRaw(); return 0; } MODULE_INITCALL(CameraControlInitialize, CameraControlStart); + +static void CameraControlTask() +{ + if (checkActivation()) { + // Manual override + if (ccd->manualInput != CAMERASTATUS_Idle) { + ccd->outputStatus = ccd->manualInput; + ccd->activity.Reason = CAMERACONTROLACTIVITY_REASON_MANUAL; + } else { + if (ccd->autoTriggerEnabled) { + ccd->activity.Reason = CAMERACONTROLACTIVITY_REASON_AUTOTIME; + ccd->outputStatus = CAMERASTATUS_Shot; + } + } + } else { + ccd->outputStatus = CAMERASTATUS_Idle; + } + + UpdateOutput(); + PublishActivity(); + ccd->lastOutputStatus = ccd->outputStatus; + PIOS_CALLBACKSCHEDULER_Schedule(ccd->callbackHandle, CALLBACK_STD_PERIOD, CALLBACK_UPDATEMODE_SOONER); +} + + +static void SettingsUpdateCb(__attribute__((unused)) UAVObjEvent *ev) +{ + CameraControlSettingsGet(&ccd->settings); +} + +static bool checkActivation() +{ + if (ccd->settings.ManualTriggerInput != CAMERACONTROLSETTINGS_MANUALTRIGGERINPUT_NONE) { + uint8_t accessory = ccd->settings.ManualTriggerInput - CAMERACONTROLSETTINGS_MANUALTRIGGERINPUT_ACCESSORY0; + + AccessoryDesiredData accessoryDesired; + AccessoryDesiredInstGet(accessory, &accessoryDesired); + + if (fabsf(accessoryDesired.AccessoryVal - ccd->settings.InputValues.Shot) < INPUT_DEADBAND) { + ccd->manualInput = CAMERASTATUS_Shot; + } else if (fabsf(accessoryDesired.AccessoryVal - ccd->settings.InputValues.Video) < INPUT_DEADBAND) { + ccd->manualInput = CAMERASTATUS_Video; + } else { + ccd->manualInput = CAMERASTATUS_Idle; + } + } + + switch (ccd->settings.AutoTriggerMode) { + case CAMERACONTROLSETTINGS_AUTOTRIGGERMODE_DISABLED: + ccd->autoTriggerEnabled = false; + break; + case CAMERACONTROLSETTINGS_AUTOTRIGGERMODE_WHENARMED: + { + FlightStatusArmedOptions armed; + + FlightStatusArmedGet(&armed); + ccd->autoTriggerEnabled = (armed == FLIGHTSTATUS_ARMED_ARMED); + } + break; + case CAMERACONTROLSETTINGS_AUTOTRIGGERMODE_ALWAYS: + ccd->autoTriggerEnabled = true; + break; + case CAMERACONTROLSETTINGS_AUTOTRIGGERMODE_INPUT: + { + uint8_t accessory = ccd->settings.AutoTriggerInput - CAMERACONTROLSETTINGS_AUTOTRIGGERINPUT_ACCESSORY0; + AccessoryDesiredData accessoryDesired; + AccessoryDesiredInstGet(accessory, &accessoryDesired); + + ccd->autoTriggerEnabled = (accessoryDesired.AccessoryVal > INPUT_DEADBAND); + } + break; + case CAMERACONTROLSETTINGS_AUTOTRIGGERMODE_MISSION: + { + FlightStatusFlightModeOptions flightmode; + FlightStatusFlightModeGet(&flightmode); + ccd->autoTriggerEnabled = (flightmode == FLIGHTSTATUS_FLIGHTMODE_PATHPLANNER); + } + break; + } + return ccd->autoTriggerEnabled || (ccd->manualInput != CAMERASTATUS_Idle); +} + +static void UpdateOutput() +{ + if (ccd->outputStatus != ccd->lastOutputStatus) { + switch (ccd->outputStatus) { + case CAMERASTATUS_Idle: + CameraDesiredTriggerSet(&ccd->settings.OutputValues.Idle); + break; + case CAMERASTATUS_Shot: + CameraDesiredTriggerSet(&ccd->settings.OutputValues.Shot); + break; + case CAMERASTATUS_Video: + CameraDesiredTriggerSet(&ccd->settings.OutputValues.Video); + break; + } + } +} + +static void PublishActivity() +{ + if (ccd->outputStatus != ccd->lastOutputStatus) { + switch (ccd->outputStatus) { + case CAMERASTATUS_Idle: + if (ccd->lastOutputStatus == CAMERASTATUS_Video) { + ccd->activity.Activity = CAMERACONTROLACTIVITY_ACTIVITY_STOPVIDEO; + } else { + ccd->activity.Activity = CAMERACONTROLACTIVITY_ACTIVITY_NONE; + } + break; + case CAMERASTATUS_Shot: + ccd->activity.Activity = CAMERACONTROLACTIVITY_ACTIVITY_TRIGGERPICTURE; + break; + case CAMERASTATUS_Video: + if (ccd->lastOutputStatus != CAMERASTATUS_Video) { + ccd->activity.Activity = CAMERACONTROLACTIVITY_ACTIVITY_STARTVIDEO; + } else { + ccd->activity.Activity = CAMERACONTROLACTIVITY_ACTIVITY_NONE; + } + break; + } + if (ccd->activity.Activity != CAMERACONTROLACTIVITY_ACTIVITY_NONE) { + FillActivityInfo(); + CameraControlActivitySet(&ccd->activity); + } + } +} + +static void FillActivityInfo() +{ + CameraControlActivityData *activity = &ccd->activity; + { + PositionStateData position; + PositionStateGet(&position); + + activity->Latitude = position.North; + activity->Longitude = position.East; + activity->Altitude = -position.Down; + } + { + GPSTimeData time; + GPSTimeGet(&time); + + activity->TriggerYear = time.Year; + activity->TriggerMonth = time.Month; + activity->TriggerDay = time.Day; + activity->TriggerHour = time.Hour; + activity->TriggerMinute = time.Minute; + activity->TriggerSecond = time.Second; + } + activity->SysTS = PIOS_DELAY_GetuS(); + { + AttitudeStateData attitude; + AttitudeStateGet(&attitude); + + activity->Roll = attitude.Roll; + activity->Pitch = attitude.Pitch; + activity->Yaw = attitude.Yaw; + } +} diff --git a/flight/targets/boards/revolution/firmware/Makefile b/flight/targets/boards/revolution/firmware/Makefile index 616f45953c..5ee49d1a22 100644 --- a/flight/targets/boards/revolution/firmware/Makefile +++ b/flight/targets/boards/revolution/firmware/Makefile @@ -42,6 +42,7 @@ MODULES += Actuator MODULES += GPS MODULES += TxPID MODULES += CameraStab +MODULES += CameraControl MODULES += Battery MODULES += FirmwareIAP MODULES += Radio diff --git a/shared/uavobjectdefinition/callbackinfo.xml b/shared/uavobjectdefinition/callbackinfo.xml index 598e4988ab..8dece63b2f 100644 --- a/shared/uavobjectdefinition/callbackinfo.xml +++ b/shared/uavobjectdefinition/callbackinfo.xml @@ -12,6 +12,7 @@ PathPlanner0 PathPlanner1 ManualControl + CameraControl @@ -25,6 +26,7 @@ PathPlanner0 PathPlanner1 ManualControl + CameraControl @@ -42,6 +44,7 @@ PathPlanner0 PathPlanner1 ManualControl + CameraControl diff --git a/shared/uavobjectdefinition/cameracontrolactivity.xml b/shared/uavobjectdefinition/cameracontrolactivity.xml index 8dcf892137..f2628e8486 100644 --- a/shared/uavobjectdefinition/cameracontrolactivity.xml +++ b/shared/uavobjectdefinition/cameracontrolactivity.xml @@ -14,8 +14,9 @@ - + + diff --git a/shared/uavobjectdefinition/cameracontrolsettings.xml b/shared/uavobjectdefinition/cameracontrolsettings.xml index 3e0bb9a73d..514ecff9cd 100644 --- a/shared/uavobjectdefinition/cameracontrolsettings.xml +++ b/shared/uavobjectdefinition/cameracontrolsettings.xml @@ -1,9 +1,11 @@ Settings for the @ref CameraControl module - - - + + + + + From 8f5ec2679c8ca2088680d16e2ff034d5b3159c90 Mon Sep 17 00:00:00 2001 From: Alessio Morale Date: Thu, 18 Aug 2016 19:27:06 +0200 Subject: [PATCH 004/624] LP-385 - add supports for fractional part of second in gps time --- flight/modules/GPS/UBX.c | 2 +- shared/uavobjectdefinition/gpstime.xml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/flight/modules/GPS/UBX.c b/flight/modules/GPS/UBX.c index 19ad461273..e25f3d5dc9 100644 --- a/flight/modules/GPS/UBX.c +++ b/flight/modules/GPS/UBX.c @@ -439,7 +439,7 @@ static void parse_ubx_nav_timeutc(struct UBXPacket *ubx, __attribute__((unused)) GpsTime.Hour = timeutc->hour; GpsTime.Minute = timeutc->min; GpsTime.Second = timeutc->sec; - + GpsTime.MilliSecond = (int16_t)timeutc->nano / 1000000; GPSTimeSet(&GpsTime); } else { // Time is not valid, nothing to do diff --git a/shared/uavobjectdefinition/gpstime.xml b/shared/uavobjectdefinition/gpstime.xml index 1408ba2d83..665d9c45e5 100644 --- a/shared/uavobjectdefinition/gpstime.xml +++ b/shared/uavobjectdefinition/gpstime.xml @@ -7,6 +7,7 @@ + From 3bd8d480683e467c4b71f3dbeb02ca6b17dd0df4 Mon Sep 17 00:00:00 2001 From: Alessio Morale Date: Thu, 18 Aug 2016 19:27:30 +0200 Subject: [PATCH 005/624] LP-385 - use fractional part of second in camera activity --- flight/modules/CameraControl/cameracontrol.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/flight/modules/CameraControl/cameracontrol.c b/flight/modules/CameraControl/cameracontrol.c index 642ee504a8..9ddbd67461 100644 --- a/flight/modules/CameraControl/cameracontrol.c +++ b/flight/modules/CameraControl/cameracontrol.c @@ -265,6 +265,7 @@ static void FillActivityInfo() activity->TriggerHour = time.Hour; activity->TriggerMinute = time.Minute; activity->TriggerSecond = time.Second; + activity->TriggerMilliSecond = time.MilliSecond; } activity->SysTS = PIOS_DELAY_GetuS(); { @@ -275,4 +276,5 @@ static void FillActivityInfo() activity->Pitch = attitude.Pitch; activity->Yaw = attitude.Yaw; } + } From b356408e16e88176c574940f9f5f52cffd1df22d Mon Sep 17 00:00:00 2001 From: Alessio Morale Date: Sun, 28 Aug 2016 22:42:56 +0200 Subject: [PATCH 006/624] LP-385 - Manage time/distance trigger, picture trigger pulse duration --- flight/modules/CameraControl/cameracontrol.c | 70 ++++++++++++++----- .../cameracontrolactivity.xml | 2 +- .../cameracontrolsettings.xml | 2 +- 3 files changed, 56 insertions(+), 18 deletions(-) diff --git a/flight/modules/CameraControl/cameracontrol.c b/flight/modules/CameraControl/cameracontrol.c index 9ddbd67461..02974a0749 100644 --- a/flight/modules/CameraControl/cameracontrol.c +++ b/flight/modules/CameraControl/cameracontrol.c @@ -59,6 +59,7 @@ static struct CameraControl_data { CameraStatus outputStatus; CameraStatus lastOutputStatus; CameraStatus manualInput; + CameraStatus lastManualInput; bool autoTriggerEnabled; } *ccd; @@ -94,6 +95,7 @@ int32_t CameraControlInitialize(void) CameraDesiredInitialize(); CameraControlSettingsInitialize(); CameraControlSettingsConnectCallback(SettingsUpdateCb); + SettingsUpdateCb(NULL); // init output: @@ -119,28 +121,55 @@ MODULE_INITCALL(CameraControlInitialize, CameraControlStart); static void CameraControlTask() { + bool trigger = false; + PositionStateData pos; + if (checkActivation()) { - // Manual override - if (ccd->manualInput != CAMERASTATUS_Idle) { + if (ccd->manualInput != ccd->lastManualInput && ccd->manualInput != CAMERASTATUS_Idle) { + // Manual override ccd->outputStatus = ccd->manualInput; ccd->activity.Reason = CAMERACONTROLACTIVITY_REASON_MANUAL; } else { if (ccd->autoTriggerEnabled) { - ccd->activity.Reason = CAMERACONTROLACTIVITY_REASON_AUTOTIME; - ccd->outputStatus = CAMERASTATUS_Shot; + // check trigger conditions + if (ccd->settings.TimeInterval > 0) { + if (PIOS_DELAY_DiffuS(ccd->lastTriggerTimeRaw) > ccd->settings.TimeInterval * (1000 * 1000)) { + trigger = true; + ccd->activity.Reason = CAMERACONTROLACTIVITY_REASON_AUTOTIME; + } + } + + if (ccd->settings.SpaceInterval > 0) { + PositionStateGet(&pos); + float dn = pos.North - ccd->lastTriggerNEDPosition[0]; + float de = pos.East - ccd->lastTriggerNEDPosition[1]; + float distance = sqrtf((dn * dn) + (de * de)); + ccd->activity.TriggerMilliSecond = (int16_t)distance * 10.0f; + if (distance > ccd->settings.SpaceInterval) { + trigger = true; + ccd->activity.Reason = CAMERACONTROLACTIVITY_REASON_AUTODISTANCE; + } + } } } + } + if (trigger) { + ccd->outputStatus = CAMERASTATUS_Shot; + ccd->lastTriggerTimeRaw = PIOS_DELAY_GetRaw(); + ccd->lastTriggerNEDPosition[0] = pos.North; + ccd->lastTriggerNEDPosition[1] = pos.East; + ccd->lastTriggerNEDPosition[2] = pos.Down; } else { ccd->outputStatus = CAMERASTATUS_Idle; + ccd->activity.Activity = CAMERACONTROLACTIVITY_ACTIVITY_IDLE; } - UpdateOutput(); + ccd->lastManualInput = ccd->manualInput; PublishActivity(); - ccd->lastOutputStatus = ccd->outputStatus; + UpdateOutput(); PIOS_CALLBACKSCHEDULER_Schedule(ccd->callbackHandle, CALLBACK_STD_PERIOD, CALLBACK_UPDATEMODE_SOONER); } - static void SettingsUpdateCb(__attribute__((unused)) UAVObjEvent *ev) { CameraControlSettingsGet(&ccd->settings); @@ -203,7 +232,14 @@ static void UpdateOutput() if (ccd->outputStatus != ccd->lastOutputStatus) { switch (ccd->outputStatus) { case CAMERASTATUS_Idle: - CameraDesiredTriggerSet(&ccd->settings.OutputValues.Idle); + if (CAMERASTATUS_Shot == ccd->lastOutputStatus) { + if (PIOS_DELAY_DiffuS(ccd->lastTriggerTimeRaw) > ccd->settings.TriggerPulseWidth * 1000) { + CameraDesiredTriggerSet(&ccd->settings.OutputValues.Idle); + } else { + // skip updating lastOutputStatus until TriggerPulseWidth elapsed + return; + } + } break; case CAMERASTATUS_Shot: CameraDesiredTriggerSet(&ccd->settings.OutputValues.Shot); @@ -213,6 +249,7 @@ static void UpdateOutput() break; } } + ccd->lastOutputStatus = ccd->outputStatus; } static void PublishActivity() @@ -223,7 +260,7 @@ static void PublishActivity() if (ccd->lastOutputStatus == CAMERASTATUS_Video) { ccd->activity.Activity = CAMERACONTROLACTIVITY_ACTIVITY_STOPVIDEO; } else { - ccd->activity.Activity = CAMERACONTROLACTIVITY_ACTIVITY_NONE; + ccd->activity.Activity = CAMERACONTROLACTIVITY_ACTIVITY_IDLE; } break; case CAMERASTATUS_Shot: @@ -233,11 +270,12 @@ static void PublishActivity() if (ccd->lastOutputStatus != CAMERASTATUS_Video) { ccd->activity.Activity = CAMERACONTROLACTIVITY_ACTIVITY_STARTVIDEO; } else { - ccd->activity.Activity = CAMERACONTROLACTIVITY_ACTIVITY_NONE; + ccd->activity.Activity = CAMERACONTROLACTIVITY_ACTIVITY_IDLE; } break; } - if (ccd->activity.Activity != CAMERACONTROLACTIVITY_ACTIVITY_NONE) { + if (ccd->activity.Activity != CAMERACONTROLACTIVITY_ACTIVITY_IDLE + || ccd->lastOutputStatus != CAMERASTATUS_Shot) { FillActivityInfo(); CameraControlActivitySet(&ccd->activity); } @@ -251,9 +289,9 @@ static void FillActivityInfo() PositionStateData position; PositionStateGet(&position); - activity->Latitude = position.North; - activity->Longitude = position.East; - activity->Altitude = -position.Down; + activity->Latitude = position.North * 1e3f; + activity->Longitude = position.East * 1e3f; + activity->Altitude = -position.Down * 1e3f; } { GPSTimeData time; @@ -267,7 +305,8 @@ static void FillActivityInfo() activity->TriggerSecond = time.Second; activity->TriggerMilliSecond = time.MilliSecond; } - activity->SysTS = PIOS_DELAY_GetuS(); + + activity->SysTS = PIOS_DELAY_GetuS(); { AttitudeStateData attitude; AttitudeStateGet(&attitude); @@ -276,5 +315,4 @@ static void FillActivityInfo() activity->Pitch = attitude.Pitch; activity->Yaw = attitude.Yaw; } - } diff --git a/shared/uavobjectdefinition/cameracontrolactivity.xml b/shared/uavobjectdefinition/cameracontrolactivity.xml index f2628e8486..4490fc6202 100644 --- a/shared/uavobjectdefinition/cameracontrolactivity.xml +++ b/shared/uavobjectdefinition/cameracontrolactivity.xml @@ -14,7 +14,7 @@ - + diff --git a/shared/uavobjectdefinition/cameracontrolsettings.xml b/shared/uavobjectdefinition/cameracontrolsettings.xml index 514ecff9cd..51ef4ccd0e 100644 --- a/shared/uavobjectdefinition/cameracontrolsettings.xml +++ b/shared/uavobjectdefinition/cameracontrolsettings.xml @@ -6,7 +6,7 @@ - + From 4e78da41d3cc807527f2b17c5f967b435447c3ca Mon Sep 17 00:00:00 2001 From: Alessio Morale Date: Sun, 31 Jul 2016 16:08:13 +0200 Subject: [PATCH 007/624] LP-368 - Add coordinate conversion functions, perform some cleanup/optimization --- flight/libraries/CoordinateConversions.c | 147 ++++++++++-------- flight/libraries/inc/CoordinateConversions.h | 23 +-- flight/modules/StateEstimation/filterlla.c | 2 +- flight/tests/math/Makefile | 5 +- .../tests/math/coordinateconversiontest.cpp | 82 ++++++++++ .../math/{unittest.cpp => mathmishtest.cpp} | 0 6 files changed, 180 insertions(+), 79 deletions(-) create mode 100644 flight/tests/math/coordinateconversiontest.cpp rename flight/tests/math/{unittest.cpp => mathmishtest.cpp} (100%) diff --git a/flight/libraries/CoordinateConversions.c b/flight/libraries/CoordinateConversions.c index 61bf9191b3..0b166f9271 100644 --- a/flight/libraries/CoordinateConversions.c +++ b/flight/libraries/CoordinateConversions.c @@ -27,25 +27,29 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include #include #include -#include "CoordinateConversions.h" +#include "inc/CoordinateConversions.h" #define MIN_ALLOWABLE_MAGNITUDE 1e-30f +// Equatorial Radius +#define equatorial_radius 6378137.0d + +// Eccentricity +#define eccentricity 8.1819190842622e-2d +#define equatorial_radius_sq (equatorial_radius * equatorial_radius) +#define eccentricity_sq (eccentricity * eccentricity) + // ****** convert Lat,Lon,Alt to ECEF ************ -void LLA2ECEF(int32_t LLAi[3], double ECEF[3]) +void LLA2ECEF(const int32_t LLAi[3], float ECEF[3]) { - const double a = 6378137.0d; // Equatorial Radius - const double e = 8.1819190842622e-2d; // Eccentricity - const double e2 = e * e; // Eccentricity squared double sinLat, sinLon, cosLat, cosLon; double N; - double LLA[3] = { - (double)LLAi[0] * 1e-7d, - (double)LLAi[1] * 1e-7d, - (double)LLAi[2] * 1e-4d + double LLA[3] = { + ((double)LLAi[0]) * 1e-7d, + ((double)LLAi[1]) * 1e-7d, + ((double)LLAi[2]) * 1e-4d }; sinLat = sin(DEG2RAD_D(LLA[0])); @@ -53,60 +57,53 @@ void LLA2ECEF(int32_t LLAi[3], double ECEF[3]) cosLat = cos(DEG2RAD_D(LLA[0])); cosLon = cos(DEG2RAD_D(LLA[1])); - N = a / sqrt(1.0d - e2 * sinLat * sinLat); // prime vertical radius of curvature + N = equatorial_radius / sqrt(1.0d - eccentricity_sq * sinLat * sinLat); // prime vertical radius of curvature - ECEF[0] = (N + LLA[2]) * cosLat * cosLon; - ECEF[1] = (N + LLA[2]) * cosLat * sinLon; - ECEF[2] = ((1.0d - e2) * N + LLA[2]) * sinLat; + ECEF[0] = (float)((N + LLA[2]) * cosLat * cosLon); + ECEF[1] = (float)((N + LLA[2]) * cosLat * sinLon); + ECEF[2] = (float)(((1.0d - eccentricity_sq) * N + LLA[2]) * sinLat); } // ****** convert ECEF to Lat,Lon,Alt (ITERATIVE!) ********* -uint16_t ECEF2LLA(double ECEF[3], float LLA[3]) +void ECEF2LLA(const float ECEF[3], int32_t LLA[3]) { - /** - * LLA parameter is used to prime the iteration. - * A position within 1 meter of the specified LLA - * will be calculated within at most 3 iterations. - * If unknown: Call with any valid LLA coordinate - * will compute within at most 5 iterations. - * Suggestion: [0,0,0] - **/ - - const double a = 6378137.0f; // Equatorial Radius - const double e = 8.1819190842622e-2f; // Eccentricity - double x = ECEF[0], y = ECEF[1], z = ECEF[2]; - double Lat, N, NplusH, delta, esLat; - uint16_t iter; - -#define MAX_ITER 10 // should not take more than 5 for valid coordinates -#define ACCURACY 1.0e-11d // used to be e-14, but we don't need sub micrometer exact calculations - - LLA[1] = (float)RAD2DEG_D(atan2(y, x)); - Lat = DEG2RAD_D((double)LLA[0]); - esLat = e * sin(Lat); - N = a / sqrt(1 - esLat * esLat); - NplusH = N + (double)LLA[2]; - delta = 1; - iter = 0; - - while (((delta > ACCURACY) || (delta < -ACCURACY)) - && (iter < MAX_ITER)) { - delta = Lat - atan(z / (sqrt(x * x + y * y) * (1 - (N * e * e / NplusH)))); - Lat = Lat - delta; - esLat = e * sin(Lat); - N = a / sqrt(1 - esLat * esLat); - NplusH = sqrt(x * x + y * y) / cos(Lat); - iter += 1; - } +/* b = math.sqrt( asq * (1-esq) ) + bsq = b*b + + ep = math.sqrt((asq - bsq)/bsq) + p = math.sqrt( math.pow(x,2) + math.pow(y,2) ) + th = math.atan2(a*z, b*p) + + lon = math.atan2(y,x) + lat = math.atan2( (z + ep*ep *b * math.pow(math.sin(th),3) ), (p - esq*a*math.pow(math.cos(th),3)) ) + N = a/( math.sqrt(1-esq*math.pow(math.sin(lat),2)) ) + alt = p / math.cos(lat) - N*/ + + const double x = ECEF[0], y = ECEF[1], z = ECEF[2]; - LLA[0] = RAD2DEG_D(Lat); - LLA[2] = NplusH - N; + const double b = sqrt(equatorial_radius_sq * (1 - eccentricity_sq)); + const double bsq = b * b; + const double ep = sqrt((equatorial_radius_sq - bsq) / bsq); - return iter < MAX_ITER; + const double p = sqrt(x * x + y * y); + const double th = atan2(equatorial_radius * z, b * p); + + double lon = atan2(y, x); + + const double lat = atan2( + (z + ep * ep * b * pow(sin(th), 3)), + (p - eccentricity_sq * equatorial_radius * pow(cos(th), 3)) + ); + const double N = equatorial_radius / (sqrt(1 - eccentricity_sq * pow(sin(lat), 2))); + const double alt = p / cos(lat) - N; + + LLA[0] = (int32_t)(RAD2DEG_D(lat) * 1e7d); + LLA[1] = (int32_t)(RAD2DEG_D(lon) * 1e7d) % ((int32_t)(180 * 1e7d)); + LLA[2] = (int32_t)(alt * 1e4d); } // ****** find ECEF to NED rotation matrix ******** -void RneFromLLA(int32_t LLAi[3], float Rne[3][3]) +void RneFromLLA(const int32_t LLAi[3], float Rne[3][3]) { float sinLat, sinLon, cosLat, cosLon; @@ -249,16 +246,30 @@ void Quaternion2zB(const float q[4], float z[3]) // ****** Express LLA in a local NED Base Frame ******** -void LLA2Base(int32_t LLAi[3], double BaseECEF[3], float Rne[3][3], float NED[3]) +void LLA2Base(const int32_t LLAi[3], const float BaseECEF[3], float Rne[3][3], float NED[3]) { - double ECEF[3]; - float diff[3]; + float ECEF[3]; LLA2ECEF(LLAi, ECEF); + ECEF2Base(ECEF, BaseECEF, Rne, NED); +} + +// ****** Express LLA in a local NED Base Frame ******** +void Base2LLA(const float NED[3], const float BaseECEF[3], float Rne[3][3], int32_t LLAi[3]) +{ + float ECEF[3]; + + Base2ECEF(NED, BaseECEF, Rne, ECEF); + ECEF2LLA(ECEF, LLAi); +} +// ****** Express ECEF in a local NED Base Frame ******** +void ECEF2Base(const float ECEF[3], const float BaseECEF[3], float Rne[3][3], float NED[3]) +{ + float diff[3]; - diff[0] = (float)(ECEF[0] - BaseECEF[0]); - diff[1] = (float)(ECEF[1] - BaseECEF[1]); - diff[2] = (float)(ECEF[2] - BaseECEF[2]); + diff[0] = (ECEF[0] - BaseECEF[0]); + diff[1] = (ECEF[1] - BaseECEF[1]); + diff[2] = (ECEF[2] - BaseECEF[2]); NED[0] = Rne[0][0] * diff[0] + Rne[0][1] * diff[1] + Rne[0][2] * diff[2]; NED[1] = Rne[1][0] * diff[0] + Rne[1][1] * diff[1] + Rne[1][2] * diff[2]; @@ -266,19 +277,21 @@ void LLA2Base(int32_t LLAi[3], double BaseECEF[3], float Rne[3][3], float NED[3] } // ****** Express ECEF in a local NED Base Frame ******** -void ECEF2Base(double ECEF[3], double BaseECEF[3], float Rne[3][3], float NED[3]) +void Base2ECEF(const float NED[3], const float BaseECEF[3], float Rne[3][3], float ECEF[3]) { float diff[3]; - diff[0] = (float)(ECEF[0] - BaseECEF[0]); - diff[1] = (float)(ECEF[1] - BaseECEF[1]); - diff[2] = (float)(ECEF[2] - BaseECEF[2]); + diff[0] = Rne[0][0] * NED[0] + Rne[1][0] * NED[1] + Rne[2][0] * NED[2]; + diff[1] = Rne[0][1] * NED[0] + Rne[1][1] * NED[1] + Rne[2][1] * NED[2]; + diff[2] = Rne[0][2] * NED[0] + Rne[1][2] * NED[1] + Rne[2][2] * NED[2]; - NED[0] = Rne[0][0] * diff[0] + Rne[0][1] * diff[1] + Rne[0][2] * diff[2]; - NED[1] = Rne[1][0] * diff[0] + Rne[1][1] * diff[1] + Rne[1][2] * diff[2]; - NED[2] = Rne[2][0] * diff[0] + Rne[2][1] * diff[1] + Rne[2][2] * diff[2]; + + ECEF[0] = diff[0] + BaseECEF[0]; + ECEF[1] = diff[1] + BaseECEF[1]; + ECEF[2] = diff[2] + BaseECEF[2]; } + // ****** convert Rotation Matrix to Quaternion ******** // ****** if R converts from e to b, q is rotation from e to b **** void R2Quaternion(float R[3][3], float q[4]) diff --git a/flight/libraries/inc/CoordinateConversions.h b/flight/libraries/inc/CoordinateConversions.h index 02369c45cf..0ef0a3bc31 100644 --- a/flight/libraries/inc/CoordinateConversions.h +++ b/flight/libraries/inc/CoordinateConversions.h @@ -29,14 +29,23 @@ #ifndef COORDINATECONVERSIONS_H_ #define COORDINATECONVERSIONS_H_ +#include // ****** convert Lat,Lon,Alt to ECEF ************ -void LLA2ECEF(int32_t LLAi[3], double ECEF[3]); +void LLA2ECEF(const int32_t LLAi[3], float ECEF[3]); -// ****** convert ECEF to Lat,Lon,Alt (ITERATIVE!) ********* -uint16_t ECEF2LLA(double ECEF[3], float LLA[3]); +// ****** convert ECEF to Lat,Lon,Alt ********* +void ECEF2LLA(const float ECEF[3], int32_t LLA[3]); -void RneFromLLA(int32_t LLAi[3], float Rne[3][3]); +void RneFromLLA(const int32_t LLAi[3], float Rne[3][3]); + +// ****** Express LLA in a local NED Base Frame and back ******** +void LLA2Base(const int32_t LLAi[3], const float BaseECEF[3], float Rne[3][3], float NED[3]); +void Base2LLA(const float NED[3], const float BaseECEF[3], float Rne[3][3], int32_t LLAi[3]); + +// ****** Express ECEF in a local NED Base Frame and back ******** +void ECEF2Base(const float ECEF[3], const float BaseECEF[3], float Rne[3][3], float NED[3]); +void Base2ECEF(const float NED[3], const float BaseECEF[3], float Rne[3][3], float ECEF[3]); // ****** find rotation matrix from rotation vector void Rv2Rot(float Rv[3], float R[3][3]); @@ -65,12 +74,6 @@ void Quaternion2yB(const float q[4], float y[3]); void QuaternionC2zB(const float q0, const float q1, const float q2, const float q3, float z[3]); void Quaternion2zB(const float q[4], float z[3]); -// ****** Express LLA in a local NED Base Frame ******** -void LLA2Base(int32_t LLAi[3], double BaseECEF[3], float Rne[3][3], float NED[3]); - -// ****** Express ECEF in a local NED Base Frame ******** -void ECEF2Base(double ECEF[3], double BaseECEF[3], float Rne[3][3], float NED[3]); - // ****** convert Rotation Matrix to Quaternion ******** // ****** if R converts from e to b, q is rotation from e to b **** void R2Quaternion(float R[3][3], float q[4]); diff --git a/flight/modules/StateEstimation/filterlla.c b/flight/modules/StateEstimation/filterlla.c index 352e0000c3..1febace770 100644 --- a/flight/modules/StateEstimation/filterlla.c +++ b/flight/modules/StateEstimation/filterlla.c @@ -44,7 +44,7 @@ struct data { GPSSettingsData settings; HomeLocationData home; - double HomeECEF[3]; + float HomeECEF[3]; float HomeRne[3][3]; }; diff --git a/flight/tests/math/Makefile b/flight/tests/math/Makefile index e3ae691da6..b6340d0598 100644 --- a/flight/tests/math/Makefile +++ b/flight/tests/math/Makefile @@ -32,7 +32,10 @@ endif include $(FLIGHT_ROOT_DIR)/make/firmware-defs.mk EXTRAINCDIRS += $(TOPDIR) -EXTRAINCDIRS += $(FLIGHT_ROOT_DIR)/flight/libraries/math +EXTRAINCDIRS += $(FLIGHTLIB)/math +EXTRAINCDIRS += $(FLIGHTLIB) EXTRAINCDIRS += $(PIOS)/inc +SRC += $(FLIGHTLIB)/CoordinateConversions.c + include $(FLIGHT_ROOT_DIR)/make/unittest.mk diff --git a/flight/tests/math/coordinateconversiontest.cpp b/flight/tests/math/coordinateconversiontest.cpp new file mode 100644 index 0000000000..168de169a2 --- /dev/null +++ b/flight/tests/math/coordinateconversiontest.cpp @@ -0,0 +1,82 @@ +#include "gtest/gtest.h" +#define __STDC_WANT_DEC_FP__ /* Tell implementation that we want Decimal FP */ + +#include /* printf */ +#include /* abort */ +#include /* memset */ + +extern "C" { +#include +} + +#define epsilon_deg 0.00001f +#define epsilon_int_deg ((int32_t)(epsilon_deg * 1e7)) +#define epsilon_metric 0.2f +#define epsilon_int_metric ((int32_t)(epsilon_metric * 1e4)) + +// To use a test fixture, derive a class from testing::Test. +class CoordinateConversionsTestRaw : public testing::Test {}; + +// ****** convert Lat,Lon,Alt to ECEF ************ +// void LLA2ECEF(const int32_t LLAi[3], float ECEF[3]); + +// ****** convert ECEF to Lat,Lon,Alt ********* +// void ECEF2LLA(const float ECEF[3], int32_t LLA[3]); + +// void RneFromLLA(const int32_t LLAi[3], float Rne[3][3]); + +// ****** Express LLA in a local NED Base Frame and back ******** +// void LLA2Base(const int32_t LLAi[3], const float BaseECEF[3], float Rne[3][3], float NED[3]); +// void Base2LLA(const float NED[3], const float BaseECEF[3], float Rne[3][3], int32_t LLAi[3]); + +// ****** Express ECEF in a local NED Base Frame and back ******** +// void ECEF2Base(const float ECEF[3], const float BaseECEF[3], float Rne[3][3], float NED[3]); +// void Base2ECEF(const float NED[3], const float BaseECEF[3], float Rne[3][3], float ECEF[3] + +TEST_F(CoordinateConversionsTestRaw, LLA2ECEF) { + int32_t LLAi[3] = { + 419291818, + 125571688, + 50 * 1e4 + }; + int32_t LLAfromECEF[3]; + + float ecef[3]; + + LLA2ECEF(LLAi, ecef); + ECEF2LLA(ecef, LLAfromECEF); + + EXPECT_NEAR(LLAi[0], LLAfromECEF[0], epsilon_int_deg); + EXPECT_NEAR(LLAi[1], LLAfromECEF[1], epsilon_int_deg); + EXPECT_NEAR(LLAi[2], LLAfromECEF[2], epsilon_int_metric); +} + + +TEST_F(CoordinateConversionsTestRaw, LLA2NED) { + int32_t LLAi[3] = { + 419291818, + 125571688, + 50 * 1e4 + }; + int32_t LLAfromNED[3]; + + int32_t HomeLLAi[3] = { + 419291600, + 125571300, + 24 * 1e4 + }; + + float Rne[3][3]; + float baseECEF[3]; + float NED[3]; + + RneFromLLA(HomeLLAi, Rne); + LLA2ECEF(HomeLLAi, baseECEF); + + LLA2Base(LLAi, baseECEF, Rne, NED); + Base2LLA(NED, baseECEF, Rne, LLAfromNED); + + EXPECT_NEAR(LLAi[0], LLAfromNED[0], epsilon_int_deg); + EXPECT_NEAR(LLAi[1], LLAfromNED[1], epsilon_int_deg); + EXPECT_NEAR(LLAi[2], LLAfromNED[2], epsilon_int_metric); +} diff --git a/flight/tests/math/unittest.cpp b/flight/tests/math/mathmishtest.cpp similarity index 100% rename from flight/tests/math/unittest.cpp rename to flight/tests/math/mathmishtest.cpp From 9bb90861673eaa2f42ed0e326218b69276ec4131 Mon Sep 17 00:00:00 2001 From: Alessio Morale Date: Mon, 29 Aug 2016 19:57:34 +0200 Subject: [PATCH 008/624] LP-385 - Convert local coordinates to LL --- flight/modules/CameraControl/cameracontrol.c | 45 ++++++++++++++++++-- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/flight/modules/CameraControl/cameracontrol.c b/flight/modules/CameraControl/cameracontrol.c index 02974a0749..592af55ff5 100644 --- a/flight/modules/CameraControl/cameracontrol.c +++ b/flight/modules/CameraControl/cameracontrol.c @@ -30,6 +30,7 @@ #include #include "inc/cameracontrol.h" +#include #include #include #include @@ -38,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -60,7 +62,9 @@ static struct CameraControl_data { CameraStatus lastOutputStatus; CameraStatus manualInput; CameraStatus lastManualInput; - bool autoTriggerEnabled; + bool autoTriggerEnabled; + float HomeECEF[3]; + float HomeRne[3][3]; } *ccd; #define CALLBACK_PRIORITY CALLBACK_PRIORITY_REGULAR @@ -71,6 +75,7 @@ static struct CameraControl_data { static void CameraControlTask(); static void SettingsUpdateCb(__attribute__((unused)) UAVObjEvent *ev); +static void HomeLocationUpdateCb(__attribute__((unused)) UAVObjEvent *ev); static void UpdateOutput(); static void PublishActivity(); static bool checkActivation(); @@ -95,8 +100,17 @@ int32_t CameraControlInitialize(void) CameraDesiredInitialize(); CameraControlSettingsInitialize(); CameraControlSettingsConnectCallback(SettingsUpdateCb); + HomeLocationInitialize(); + HomeLocationConnectCallback(HomeLocationUpdateCb); + GPSTimeInitialize(); + PositionStateInitialize(); + AttitudeStateInitialize(); + AccessoryDesiredInitialize(); + FlightStatusInitialize(); + SettingsUpdateCb(NULL); + HomeLocationUpdateCb(NULL); // init output: ccd->outputStatus = CAMERASTATUS_Idle; @@ -250,6 +264,7 @@ static void UpdateOutput() } } ccd->lastOutputStatus = ccd->outputStatus; + } static void PublishActivity() @@ -288,10 +303,17 @@ static void FillActivityInfo() { PositionStateData position; PositionStateGet(&position); + int32_t LLAi[3]; + const float pos[3] = { + position.North, + position.East, + position.Down + }; + Base2LLA(pos, ccd->HomeECEF, ccd->HomeRne, LLAi); - activity->Latitude = position.North * 1e3f; - activity->Longitude = position.East * 1e3f; - activity->Altitude = -position.Down * 1e3f; + activity->Latitude = LLAi[0]; + activity->Longitude = LLAi[1]; + activity->Altitude = ((float)LLAi[2]) * 1e-4f; } { GPSTimeData time; @@ -316,3 +338,18 @@ static void FillActivityInfo() activity->Yaw = attitude.Yaw; } } + +static void HomeLocationUpdateCb(__attribute__((unused)) UAVObjEvent *ev) +{ + HomeLocationData home; + + HomeLocationGet(&home); + + int32_t LLAi[3] = { + home.Latitude, + home.Longitude, + home.Altitude + }; + LLA2ECEF(LLAi, ccd->HomeECEF); + RneFromLLA(LLAi, ccd->HomeRne); +} From 7ed8e636896f1dcc060be182eacd0dc7bc2e7035 Mon Sep 17 00:00:00 2001 From: Alessio Morale Date: Mon, 29 Aug 2016 19:57:55 +0200 Subject: [PATCH 009/624] LP-385 - Fix Actuator support for CameraControl --- flight/modules/Actuator/actuator.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/flight/modules/Actuator/actuator.c b/flight/modules/Actuator/actuator.c index c716bf5c2b..6ad511fdc5 100644 --- a/flight/modules/Actuator/actuator.c +++ b/flight/modules/Actuator/actuator.c @@ -89,6 +89,7 @@ static xTaskHandle taskHandle; static FrameType_t frameType = FRAME_TYPE_MULTIROTOR; static SystemSettingsThrustControlOptions thrustType = SYSTEMSETTINGS_THRUSTCONTROL_THROTTLE; static bool camStabEnabled; +static bool camControlEnabled; static uint8_t pinsMode[MAX_MIX_ACTUATORS]; // used to inform the actuator thread that actuator update rate is changed @@ -165,8 +166,8 @@ int32_t ActuatorInitialize() HwSettingsOptionalModulesData optionalModules; HwSettingsInitialize(); HwSettingsOptionalModulesGet(&optionalModules); - camStabEnabled = (optionalModules.CameraStab == HWSETTINGS_OPTIONALMODULES_ENABLED); - + camStabEnabled = (optionalModules.CameraStab == HWSETTINGS_OPTIONALMODULES_ENABLED); + camControlEnabled = (optionalModules.CameraControl == HWSETTINGS_OPTIONALMODULES_ENABLED); // Primary output of this module ActuatorCommandInitialize(); @@ -471,9 +472,6 @@ static void actuatorTask(__attribute__((unused)) void *parameters) case MIXERSETTINGS_MIXER1TYPE_CAMERAYAW: status[ct] = cameraDesired.Yaw; break; - case MIXERSETTINGS_MIXER1TYPE_CAMERATRIGGER: - status[ct] = cameraDesired.Trigger; - break; default: break; } @@ -486,6 +484,14 @@ static void actuatorTask(__attribute__((unused)) void *parameters) command.Channel[ct] = 0; } } + + if (mixer_type == MIXERSETTINGS_MIXER1TYPE_CAMERATRIGGER) { + if (camControlEnabled) { + CameraDesiredTriggerGet(&status[ct]); + } else { + status[ct] = 0; + } + } } // If mixer type is motor we need to find which motor has the highest value and which motor has the lowest value. From 8114d7771ebfdd452a29d23742f52e7abdf02cf4 Mon Sep 17 00:00:00 2001 From: Alessio Morale Date: Mon, 29 Aug 2016 19:58:39 +0200 Subject: [PATCH 010/624] LP-385 - Fix manual trigger --- flight/modules/CameraControl/cameracontrol.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/flight/modules/CameraControl/cameracontrol.c b/flight/modules/CameraControl/cameracontrol.c index 592af55ff5..41ff0d9587 100644 --- a/flight/modules/CameraControl/cameracontrol.c +++ b/flight/modules/CameraControl/cameracontrol.c @@ -141,7 +141,8 @@ static void CameraControlTask() if (checkActivation()) { if (ccd->manualInput != ccd->lastManualInput && ccd->manualInput != CAMERASTATUS_Idle) { // Manual override - ccd->outputStatus = ccd->manualInput; + trigger = true; + ccd->outputStatus = ccd->manualInput; ccd->activity.Reason = CAMERACONTROLACTIVITY_REASON_MANUAL; } else { if (ccd->autoTriggerEnabled) { @@ -264,7 +265,6 @@ static void UpdateOutput() } } ccd->lastOutputStatus = ccd->outputStatus; - } static void PublishActivity() From d000dd63c61852b6304eac5995a2918d0082dc8e Mon Sep 17 00:00:00 2001 From: Alessio Morale Date: Mon, 29 Aug 2016 20:24:58 +0200 Subject: [PATCH 011/624] LP-385 - Add MinimumTimeInterval which define a hard minimum limit between two consecutive shots in auto mode. This is needed to ensure camera can keep up with trigger without loosing shots --- flight/modules/CameraControl/cameracontrol.c | 7 +++++-- shared/uavobjectdefinition/cameracontrolsettings.xml | 3 ++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/flight/modules/CameraControl/cameracontrol.c b/flight/modules/CameraControl/cameracontrol.c index 41ff0d9587..3d05893a65 100644 --- a/flight/modules/CameraControl/cameracontrol.c +++ b/flight/modules/CameraControl/cameracontrol.c @@ -137,6 +137,7 @@ static void CameraControlTask() { bool trigger = false; PositionStateData pos; + uint32_t timeSinceLastShot = PIOS_DELAY_DiffuS(ccd->lastTriggerTimeRaw); if (checkActivation()) { if (ccd->manualInput != ccd->lastManualInput && ccd->manualInput != CAMERASTATUS_Idle) { @@ -145,10 +146,12 @@ static void CameraControlTask() ccd->outputStatus = ccd->manualInput; ccd->activity.Reason = CAMERACONTROLACTIVITY_REASON_MANUAL; } else { - if (ccd->autoTriggerEnabled) { + // MinimumTimeInterval sets a hard limit on time between two consecutive shots, i.e. the minimum time between shots the camera can achieve + if (ccd->autoTriggerEnabled && + timeSinceLastShot > (ccd->settings.MinimumTimeInterval * 1000 * 1000)) { // check trigger conditions if (ccd->settings.TimeInterval > 0) { - if (PIOS_DELAY_DiffuS(ccd->lastTriggerTimeRaw) > ccd->settings.TimeInterval * (1000 * 1000)) { + if (timeSinceLastShot > ccd->settings.TimeInterval * (1000 * 1000)) { trigger = true; ccd->activity.Reason = CAMERACONTROLACTIVITY_REASON_AUTOTIME; } diff --git a/shared/uavobjectdefinition/cameracontrolsettings.xml b/shared/uavobjectdefinition/cameracontrolsettings.xml index 51ef4ccd0e..a940472718 100644 --- a/shared/uavobjectdefinition/cameracontrolsettings.xml +++ b/shared/uavobjectdefinition/cameracontrolsettings.xml @@ -7,8 +7,9 @@ - + + From b04a3929bec22036a62fe65aff7f6f41d8291d8e Mon Sep 17 00:00:00 2001 From: Alessio Morale Date: Mon, 29 Aug 2016 20:35:11 +0200 Subject: [PATCH 012/624] LP-385 - Get system timestamp coherently with system module --- flight/modules/CameraControl/cameracontrol.c | 2 +- shared/uavobjectdefinition/cameracontrolactivity.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/flight/modules/CameraControl/cameracontrol.c b/flight/modules/CameraControl/cameracontrol.c index 3d05893a65..8156c03111 100644 --- a/flight/modules/CameraControl/cameracontrol.c +++ b/flight/modules/CameraControl/cameracontrol.c @@ -331,7 +331,7 @@ static void FillActivityInfo() activity->TriggerMilliSecond = time.MilliSecond; } - activity->SysTS = PIOS_DELAY_GetuS(); + activity->SystemTS = xTaskGetTickCount() * portTICK_RATE_MS; { AttitudeStateData attitude; AttitudeStateGet(&attitude); diff --git a/shared/uavobjectdefinition/cameracontrolactivity.xml b/shared/uavobjectdefinition/cameracontrolactivity.xml index 4490fc6202..d9ffefe977 100644 --- a/shared/uavobjectdefinition/cameracontrolactivity.xml +++ b/shared/uavobjectdefinition/cameracontrolactivity.xml @@ -16,7 +16,7 @@ - + From 6c8dafec3cde63a05079eb524a22dc40ecf803ae Mon Sep 17 00:00:00 2001 From: Alessio Morale Date: Mon, 29 Aug 2016 21:16:52 +0200 Subject: [PATCH 013/624] LP-385 - Add support for all revo class boards --- flight/targets/boards/revonano/firmware/Makefile | 1 + flight/targets/boards/revonano/firmware/UAVObjects.inc | 2 ++ flight/targets/boards/revoproto/firmware/Makefile | 1 + flight/targets/boards/revoproto/firmware/UAVObjects.inc | 6 ++++-- flight/targets/boards/sparky2/firmware/Makefile | 1 + flight/targets/boards/sparky2/firmware/UAVObjects.inc | 4 +++- 6 files changed, 12 insertions(+), 3 deletions(-) diff --git a/flight/targets/boards/revonano/firmware/Makefile b/flight/targets/boards/revonano/firmware/Makefile index 67d01fac7a..1abf5b82a6 100644 --- a/flight/targets/boards/revonano/firmware/Makefile +++ b/flight/targets/boards/revonano/firmware/Makefile @@ -42,6 +42,7 @@ MODULES += Actuator MODULES += GPS MODULES += TxPID MODULES += CameraStab +MODULES += CameraControl MODULES += Battery MODULES += FirmwareIAP MODULES += PathPlanner diff --git a/flight/targets/boards/revonano/firmware/UAVObjects.inc b/flight/targets/boards/revonano/firmware/UAVObjects.inc index 6100c47502..5774e7ae43 100644 --- a/flight/targets/boards/revonano/firmware/UAVObjects.inc +++ b/flight/targets/boards/revonano/firmware/UAVObjects.inc @@ -112,6 +112,8 @@ UAVOBJSRCFILENAMES += receiveractivity UAVOBJSRCFILENAMES += receiverstatus UAVOBJSRCFILENAMES += cameradesired UAVOBJSRCFILENAMES += camerastabsettings +UAVOBJSRCFILENAMES += cameracontrolsettings +UAVOBJSRCFILENAMES += cameracontrolactivity UAVOBJSRCFILENAMES += altitudeholdsettings UAVOBJSRCFILENAMES += oplinksettings UAVOBJSRCFILENAMES += oplinkstatus diff --git a/flight/targets/boards/revoproto/firmware/Makefile b/flight/targets/boards/revoproto/firmware/Makefile index 809fda8266..d8d5124c0b 100644 --- a/flight/targets/boards/revoproto/firmware/Makefile +++ b/flight/targets/boards/revoproto/firmware/Makefile @@ -42,6 +42,7 @@ MODULES += Actuator MODULES += GPS MODULES += TxPID MODULES += CameraStab +MODULES += CameraControl MODULES += Battery MODULES += FirmwareIAP MODULES += PathPlanner diff --git a/flight/targets/boards/revoproto/firmware/UAVObjects.inc b/flight/targets/boards/revoproto/firmware/UAVObjects.inc index cba723f6b3..5774e7ae43 100644 --- a/flight/targets/boards/revoproto/firmware/UAVObjects.inc +++ b/flight/targets/boards/revoproto/firmware/UAVObjects.inc @@ -21,9 +21,9 @@ # (all architectures) UAVOBJSRCFILENAMES = UAVOBJSRCFILENAMES += statusgrounddrive -UAVOBJSRCFILENAMES += statusvtolland UAVOBJSRCFILENAMES += statusvtolautotakeoff UAVOBJSRCFILENAMES += pidstatus +UAVOBJSRCFILENAMES += statusvtolland UAVOBJSRCFILENAMES += vtolselftuningstats UAVOBJSRCFILENAMES += accelgyrosettings UAVOBJSRCFILENAMES += accessorydesired @@ -112,6 +112,8 @@ UAVOBJSRCFILENAMES += receiveractivity UAVOBJSRCFILENAMES += receiverstatus UAVOBJSRCFILENAMES += cameradesired UAVOBJSRCFILENAMES += camerastabsettings +UAVOBJSRCFILENAMES += cameracontrolsettings +UAVOBJSRCFILENAMES += cameracontrolactivity UAVOBJSRCFILENAMES += altitudeholdsettings UAVOBJSRCFILENAMES += oplinksettings UAVOBJSRCFILENAMES += oplinkstatus @@ -125,7 +127,7 @@ UAVOBJSRCFILENAMES += mpugyroaccelsettings UAVOBJSRCFILENAMES += txpidsettings UAVOBJSRCFILENAMES += txpidstatus UAVOBJSRCFILENAMES += takeofflocation -# UAVOBJSRCFILENAMES += perfcounter +UAVOBJSRCFILENAMES += perfcounter UAVOBJSRCFILENAMES += systemidentsettings UAVOBJSRCFILENAMES += systemidentstate diff --git a/flight/targets/boards/sparky2/firmware/Makefile b/flight/targets/boards/sparky2/firmware/Makefile index 7ee3837a40..45c7f28911 100644 --- a/flight/targets/boards/sparky2/firmware/Makefile +++ b/flight/targets/boards/sparky2/firmware/Makefile @@ -42,6 +42,7 @@ MODULES += Actuator MODULES += GPS MODULES += TxPID MODULES += CameraStab +MODULES += CameraControl MODULES += Battery MODULES += FirmwareIAP MODULES += Radio diff --git a/flight/targets/boards/sparky2/firmware/UAVObjects.inc b/flight/targets/boards/sparky2/firmware/UAVObjects.inc index 4835fa6490..5774e7ae43 100644 --- a/flight/targets/boards/sparky2/firmware/UAVObjects.inc +++ b/flight/targets/boards/sparky2/firmware/UAVObjects.inc @@ -17,7 +17,7 @@ # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # -# These are the UAVObjects supposed to be build as part of the target +# These are the UAVObjects supposed to be build as part of the OpenPilot target # (all architectures) UAVOBJSRCFILENAMES = UAVOBJSRCFILENAMES += statusgrounddrive @@ -112,6 +112,8 @@ UAVOBJSRCFILENAMES += receiveractivity UAVOBJSRCFILENAMES += receiverstatus UAVOBJSRCFILENAMES += cameradesired UAVOBJSRCFILENAMES += camerastabsettings +UAVOBJSRCFILENAMES += cameracontrolsettings +UAVOBJSRCFILENAMES += cameracontrolactivity UAVOBJSRCFILENAMES += altitudeholdsettings UAVOBJSRCFILENAMES += oplinksettings UAVOBJSRCFILENAMES += oplinkstatus From 493a48ba2b6156d65a236bc9ab3e89cd9c534eea Mon Sep 17 00:00:00 2001 From: Alessio Morale Date: Sat, 3 Sep 2016 21:44:41 +0200 Subject: [PATCH 014/624] LP-385 - fixes from review --- flight/modules/CameraControl/cameracontrol.c | 4 ++-- flight/modules/GPS/UBX.c | 2 +- flight/targets/boards/sparky2/firmware/UAVObjects.inc | 2 +- shared/uavobjectdefinition/cameracontrolactivity.xml | 6 +++--- shared/uavobjectdefinition/cameracontrolsettings.xml | 8 ++------ shared/uavobjectdefinition/gpstime.xml | 2 +- 6 files changed, 10 insertions(+), 14 deletions(-) diff --git a/flight/modules/CameraControl/cameracontrol.c b/flight/modules/CameraControl/cameracontrol.c index 8156c03111..0e1d24b0b8 100644 --- a/flight/modules/CameraControl/cameracontrol.c +++ b/flight/modules/CameraControl/cameracontrol.c @@ -162,7 +162,7 @@ static void CameraControlTask() float dn = pos.North - ccd->lastTriggerNEDPosition[0]; float de = pos.East - ccd->lastTriggerNEDPosition[1]; float distance = sqrtf((dn * dn) + (de * de)); - ccd->activity.TriggerMilliSecond = (int16_t)distance * 10.0f; + ccd->activity.TriggerMillisecond = (int16_t)distance * 10.0f; if (distance > ccd->settings.SpaceInterval) { trigger = true; ccd->activity.Reason = CAMERACONTROLACTIVITY_REASON_AUTODISTANCE; @@ -328,7 +328,7 @@ static void FillActivityInfo() activity->TriggerHour = time.Hour; activity->TriggerMinute = time.Minute; activity->TriggerSecond = time.Second; - activity->TriggerMilliSecond = time.MilliSecond; + activity->TriggerMillisecond = time.Millisecond; } activity->SystemTS = xTaskGetTickCount() * portTICK_RATE_MS; diff --git a/flight/modules/GPS/UBX.c b/flight/modules/GPS/UBX.c index e25f3d5dc9..11678ceb46 100644 --- a/flight/modules/GPS/UBX.c +++ b/flight/modules/GPS/UBX.c @@ -439,7 +439,7 @@ static void parse_ubx_nav_timeutc(struct UBXPacket *ubx, __attribute__((unused)) GpsTime.Hour = timeutc->hour; GpsTime.Minute = timeutc->min; GpsTime.Second = timeutc->sec; - GpsTime.MilliSecond = (int16_t)timeutc->nano / 1000000; + GpsTime.Millisecond = (int16_t)(timeutc->nano / 1000000); GPSTimeSet(&GpsTime); } else { // Time is not valid, nothing to do diff --git a/flight/targets/boards/sparky2/firmware/UAVObjects.inc b/flight/targets/boards/sparky2/firmware/UAVObjects.inc index 5774e7ae43..f9cd877065 100644 --- a/flight/targets/boards/sparky2/firmware/UAVObjects.inc +++ b/flight/targets/boards/sparky2/firmware/UAVObjects.inc @@ -17,7 +17,7 @@ # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # -# These are the UAVObjects supposed to be build as part of the OpenPilot target +# These are the UAVObjects supposed to be build as part of the target # (all architectures) UAVOBJSRCFILENAMES = UAVOBJSRCFILENAMES += statusgrounddrive diff --git a/shared/uavobjectdefinition/cameracontrolactivity.xml b/shared/uavobjectdefinition/cameracontrolactivity.xml index d9ffefe977..f4fdc35d88 100644 --- a/shared/uavobjectdefinition/cameracontrolactivity.xml +++ b/shared/uavobjectdefinition/cameracontrolactivity.xml @@ -3,7 +3,7 @@ Contains position and timestamp of each camera operation - + @@ -13,7 +13,7 @@ - + @@ -22,4 +22,4 @@ - + \ No newline at end of file diff --git a/shared/uavobjectdefinition/cameracontrolsettings.xml b/shared/uavobjectdefinition/cameracontrolsettings.xml index a940472718..d3403c1e0e 100644 --- a/shared/uavobjectdefinition/cameracontrolsettings.xml +++ b/shared/uavobjectdefinition/cameracontrolsettings.xml @@ -6,7 +6,7 @@ - + @@ -15,8 +15,4 @@ - - - - - + \ No newline at end of file diff --git a/shared/uavobjectdefinition/gpstime.xml b/shared/uavobjectdefinition/gpstime.xml index 665d9c45e5..558b8ce04b 100644 --- a/shared/uavobjectdefinition/gpstime.xml +++ b/shared/uavobjectdefinition/gpstime.xml @@ -7,7 +7,7 @@ - + From 25b2a22122ebfc8bedacac168c267fe81ec86b74 Mon Sep 17 00:00:00 2001 From: Alessio Morale Date: Thu, 8 Sep 2016 02:19:17 +0200 Subject: [PATCH 015/624] LP-385 - Add Image Index --- flight/modules/CameraControl/cameracontrol.c | 18 ++++++++++++------ .../cameracontrolactivity.xml | 1 + 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/flight/modules/CameraControl/cameracontrol.c b/flight/modules/CameraControl/cameracontrol.c index 0e1d24b0b8..7fb4873032 100644 --- a/flight/modules/CameraControl/cameracontrol.c +++ b/flight/modules/CameraControl/cameracontrol.c @@ -62,7 +62,8 @@ static struct CameraControl_data { CameraStatus lastOutputStatus; CameraStatus manualInput; CameraStatus lastManualInput; - bool autoTriggerEnabled; + bool autoTriggerEnabled; + uint16_t ImageId; float HomeECEF[3]; float HomeRne[3][3]; } *ccd; @@ -138,12 +139,13 @@ static void CameraControlTask() bool trigger = false; PositionStateData pos; uint32_t timeSinceLastShot = PIOS_DELAY_DiffuS(ccd->lastTriggerTimeRaw); + CameraStatus newStatus; if (checkActivation()) { if (ccd->manualInput != ccd->lastManualInput && ccd->manualInput != CAMERASTATUS_Idle) { // Manual override - trigger = true; - ccd->outputStatus = ccd->manualInput; + trigger = true; + newStatus = ccd->manualInput; ccd->activity.Reason = CAMERACONTROLACTIVITY_REASON_MANUAL; } else { // MinimumTimeInterval sets a hard limit on time between two consecutive shots, i.e. the minimum time between shots the camera can achieve @@ -152,7 +154,8 @@ static void CameraControlTask() // check trigger conditions if (ccd->settings.TimeInterval > 0) { if (timeSinceLastShot > ccd->settings.TimeInterval * (1000 * 1000)) { - trigger = true; + trigger = true; + newStatus = CAMERASTATUS_Shot; ccd->activity.Reason = CAMERACONTROLACTIVITY_REASON_AUTOTIME; } } @@ -164,7 +167,8 @@ static void CameraControlTask() float distance = sqrtf((dn * dn) + (de * de)); ccd->activity.TriggerMillisecond = (int16_t)distance * 10.0f; if (distance > ccd->settings.SpaceInterval) { - trigger = true; + trigger = true; + newStatus = CAMERASTATUS_Shot; ccd->activity.Reason = CAMERACONTROLACTIVITY_REASON_AUTODISTANCE; } } @@ -172,7 +176,8 @@ static void CameraControlTask() } } if (trigger) { - ccd->outputStatus = CAMERASTATUS_Shot; + ccd->outputStatus = newStatus; + ccd->ImageId++; ccd->lastTriggerTimeRaw = PIOS_DELAY_GetRaw(); ccd->lastTriggerNEDPosition[0] = pos.North; ccd->lastTriggerNEDPosition[1] = pos.East; @@ -331,6 +336,7 @@ static void FillActivityInfo() activity->TriggerMillisecond = time.Millisecond; } + activity->ImageId = ccd->ImageId; activity->SystemTS = xTaskGetTickCount() * portTICK_RATE_MS; { AttitudeStateData attitude; diff --git a/shared/uavobjectdefinition/cameracontrolactivity.xml b/shared/uavobjectdefinition/cameracontrolactivity.xml index f4fdc35d88..bba625e39e 100644 --- a/shared/uavobjectdefinition/cameracontrolactivity.xml +++ b/shared/uavobjectdefinition/cameracontrolactivity.xml @@ -7,6 +7,7 @@ + From 2d926fe082a7cd53823e1045fc424be25dac549f Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Thu, 8 Sep 2016 19:58:47 +0200 Subject: [PATCH 016/624] LP-404 make Makefile more vendor neutral --- Makefile | 39 ++++++++++---------- ground/gcs/src/plugins/uploader/uploader.pro | 7 ++-- 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/Makefile b/Makefile index ff952865c5..318931eb64 100644 --- a/Makefile +++ b/Makefile @@ -50,9 +50,9 @@ export TOOLS_DIR export BUILD_DIR := $(CURDIR)/build export PACKAGE_DIR := $(BUILD_DIR)/package export DIST_DIR := $(BUILD_DIR)/dist -export OPGCSSYNTHDIR := $(BUILD_DIR)/gcs-synthetics +export GCS_SYNTH_DIR := $(BUILD_DIR)/gcs-synthetics -DIRS := $(DL_DIR) $(TOOLS_DIR) $(BUILD_DIR) $(PACKAGE_DIR) $(DIST_DIR) $(OPGCSSYNTHDIR) +DIRS := $(DL_DIR) $(TOOLS_DIR) $(BUILD_DIR) $(PACKAGE_DIR) $(DIST_DIR) $(GCS_SYNTH_DIR) # Naming for binaries and packaging etc,. export ORG_BIG_NAME := LibrePilot @@ -225,9 +225,9 @@ uavobjects_clean: # When building any of the "all_*" targets, tell all sub makefiles to display # additional details on each line of output to describe which build and target -# that each line applies to. The same applies also to all, opfw_resource, +# that each line applies to. The same applies also to all, fw_resource, # package targets -ifneq ($(strip $(filter all_% all opfw_resource package,$(MAKECMDGOALS))),) +ifneq ($(strip $(filter all_% all fw_resource package,$(MAKECMDGOALS))),) export ENABLE_MSG_EXTRA := yes endif @@ -323,38 +323,39 @@ PACKAGE_FW_TARGETS := fw_coptercontrol fw_oplinkmini fw_revolution fw_osd fw_rev # Rules to generate GCS resources used to embed firmware binaries into the GCS. # They are used later by the vehicle setup wizard to update board firmware. # To open a firmware image use ":/firmware/fw_coptercontrol.opfw" -OPFW_RESOURCE := $(OPGCSSYNTHDIR)/opfw_resource.qrc +FW_RESOURCE := $(GCS_SYNTH_DIR)/fw_resource.qrc ifeq ($(WITH_PREBUILT_FW),) FIRMWARE_DIR := $(FLIGHT_OUT_DIR) # We need to build the FW targets -$(OPFW_RESOURCE): $(PACKAGE_FW_TARGETS) +$(FW_RESOURCE): $(PACKAGE_FW_TARGETS) else FIRMWARE_DIR := $(WITH_PREBUILT_FW) endif -OPFW_FILES := $(foreach fw_targ, $(PACKAGE_FW_TARGETS), $(FIRMWARE_DIR)/$(fw_targ)/$(fw_targ).opfw) -OPFW_CONTENTS := \ +FW_FILES := $(foreach fw_targ, $(PACKAGE_FW_TARGETS), $(FIRMWARE_DIR)/$(fw_targ)/$(fw_targ).opfw) +FW_CONTENTS := \ \ \ - $(foreach fw_file, $(OPFW_FILES), $(call system_path,$(fw_file))) \ + $(foreach fw_file, $(FW_FILES), $(call system_path,$(fw_file))) \ \ -.PHONY: opfw_resource -opfw_resource: $(OPFW_RESOURCE) +.PHONY: fw_resource +fw_resource: $(FW_RESOURCE) +fw_resource: $(FW_RESOURCE) -$(OPFW_RESOURCE): | $(OPGCSSYNTHDIR) - @$(ECHO) Generating OPFW resource file $(call toprel, $@) - $(V1) $(ECHO) $(QUOTE)$(OPFW_CONTENTS)$(QUOTE) > $@ +$(FW_RESOURCE): | $(GCS_SYNTH_DIR) + @$(ECHO) Generating FW resource file $(call toprel, $@) + $(V1) $(ECHO) $(QUOTE)$(FW_CONTENTS)$(QUOTE) > $@ -# If opfw_resource or all firmware are requested, GCS should depend on the resource -ifneq ($(strip $(filter opfw_resource all all_fw all_flight package,$(MAKECMDGOALS))),) -$(GCS_MAKEFILE): $(OPFW_RESOURCE) +# If fw_resource or all firmware are requested, GCS should depend on the resource +ifneq ($(strip $(filter fw_resource all all_fw all_flight package,$(MAKECMDGOALS))),) +$(GCS_MAKEFILE): $(FW_RESOURCE) endif # Packaging targets: package -# - builds all firmware, opfw_resource, gcs +# - builds all firmware, fw_resource, gcs # - copies firmware into a package directory # - calls paltform-specific packaging script @@ -712,7 +713,7 @@ help: @$(ECHO) @$(ECHO) " [Packaging]" @$(ECHO) " package - Build and package the platform-dependent package (no clean)" - @$(ECHO) " opfw_resource - Generate resources to embed firmware binaries into the GCS" + @$(ECHO) " fw_resource - Generate resources to embed firmware binaries into the GCS" @$(ECHO) " dist - Generate source archive for distribution" @$(ECHO) " fw_dist - Generate archive of firmware" @$(ECHO) " install - Install GCS to \"DESTDIR\" with prefix \"prefix\" (Linux only)" diff --git a/ground/gcs/src/plugins/uploader/uploader.pro b/ground/gcs/src/plugins/uploader/uploader.pro index 23990f5a28..0d4c97441f 100644 --- a/ground/gcs/src/plugins/uploader/uploader.pro +++ b/ground/gcs/src/plugins/uploader/uploader.pro @@ -63,8 +63,9 @@ FORMS += \ RESOURCES += uploader.qrc -exists( ../../../../../build/gcs-synthetics/opfw_resource.qrc ) { - RESOURCES += ../../../../../build/gcs-synthetics/opfw_resource.qrc +# TODO should use GCS_SYNTH_DIR... but that will break QtCreator +exists( ../../../../../build/gcs-synthetics/fw_resource.qrc ) { + RESOURCES += ../../../../../build/gcs-synthetics/fw_resource.qrc } else { - message("opfw_resource.qrc is not available, automatic firmware upgrades are disabled") + message("fw_resource.qrc is not available, automatic firmware upgrades are disabled") } From cff5dac0884ab06e2909f04268305fe216f63dd0 Mon Sep 17 00:00:00 2001 From: Laurent Lalanne Date: Wed, 14 Sep 2016 14:54:46 +0200 Subject: [PATCH 017/624] LP-407 Add Rssi input value - ReceiverActivity: Ignore Rssi channel if already set --- flight/modules/Receiver/receiver.c | 63 ++++++++++++++++--- .../src/plugins/config/configinputwidget.cpp | 45 ++++++++----- .../src/plugins/config/configinputwidget.h | 1 + .../manualcontrolcommand.xml | 2 +- .../manualcontrolsettings.xml | 38 ++++++----- 5 files changed, 105 insertions(+), 44 deletions(-) diff --git a/flight/modules/Receiver/receiver.c b/flight/modules/Receiver/receiver.c index 900e1194c7..b2308dfa25 100644 --- a/flight/modules/Receiver/receiver.c +++ b/flight/modules/Receiver/receiver.c @@ -114,7 +114,8 @@ static bool updateRcvrActivity(struct rcvr_activity_fsm *fsm); static void resetRcvrStatus(struct rcvr_activity_fsm *fsm); static bool updateRcvrStatus( struct rcvr_activity_fsm *fsm, - ManualControlSettingsChannelGroupsOptions group); + ManualControlSettingsChannelGroupsOptions group, + int8_t rssiValue); #define assumptions \ ( \ @@ -209,6 +210,9 @@ static void receiverTask(__attribute__((unused)) void *parameters) AccessoryDesiredCreateInstance(); AccessoryDesiredCreateInstance(); + // Rssi input + AccessoryDesiredCreateInstance(); + // Whenever the configuration changes, make sure it is safe to fly ManualControlCommandGet(&cmd); @@ -232,6 +236,8 @@ static void receiverTask(__attribute__((unused)) void *parameters) PIOS_WDG_UpdateFlag(PIOS_WDG_MANUAL); #endif + int8_t rssiValue = -1; + // Read settings ManualControlSettingsGet(&settings); SystemSettingsThrustControlGet(&thrustType); @@ -244,7 +250,8 @@ static void receiverTask(__attribute__((unused)) void *parameters) } /* Read signal quality from the group used for the throttle */ (void)updateRcvrStatus(&activity_fsm, - settings.ChannelGroups.Throttle); + settings.ChannelGroups.Throttle, + rssiValue); } if (timeDifferenceMs(lastActivityTime, lastSysTime) > 5000) { resetRcvrActivity(&activity_fsm); @@ -267,6 +274,7 @@ static void receiverTask(__attribute__((unused)) void *parameters) } bool valid_input_detected = true; + bool valid_rssi_input = false; // Read channel values in us for (uint8_t n = 0; n < MANUALCONTROLSETTINGS_CHANNELGROUPS_NUMELEM && n < MANUALCONTROLCOMMAND_CHANNEL_NUMELEM; ++n) { @@ -285,16 +293,27 @@ static void receiverTask(__attribute__((unused)) void *parameters) if (cmd.Channel[n] == (uint16_t)PIOS_RCVR_TIMEOUT) { valid_input_detected = false; } else { + int16_t neutralValue = ManualControlSettingsChannelNeutralToArray(settings.ChannelNeutral)[n]; + + if (n == MANUALCONTROLSETTINGS_CHANNELGROUPS_RSSI) { + // Rssi neutral is ignored and set to min, for 0 - 100% output range + neutralValue = ManualControlSettingsChannelMinToArray(settings.ChannelMin)[n]; + valid_rssi_input = true; + } scaledChannel[n] = scaleChannel(cmd.Channel[n], ManualControlSettingsChannelMaxToArray(settings.ChannelMax)[n], ManualControlSettingsChannelMinToArray(settings.ChannelMin)[n], - ManualControlSettingsChannelNeutralToArray(settings.ChannelNeutral)[n]); + neutralValue); } } + if (valid_rssi_input) { + rssiValue = (int8_t)(scaledChannel[MANUALCONTROLSETTINGS_CHANNELGROUPS_RSSI] * 100); + } /* Read signal quality from the group used for the throttle */ (void)updateRcvrStatus(&activity_fsm, - settings.ChannelGroups.Throttle); + settings.ChannelGroups.Throttle, + rssiValue); // Sanity Check Throttle and Yaw if (settings.ChannelGroups.Yaw >= MANUALCONTROLSETTINGS_CHANNELGROUPS_NONE @@ -383,6 +402,10 @@ static void receiverTask(__attribute__((unused)) void *parameters) valid_input_detected &= validInputRange(settings.ChannelMin.Accessory3, settings.ChannelMax.Accessory3, cmd.Channel[MANUALCONTROLSETTINGS_CHANNELGROUPS_ACCESSORY3]); } + if (settings.ChannelGroups.Rssi != MANUALCONTROLSETTINGS_CHANNELGROUPS_NONE) { + valid_input_detected &= validInputRange(settings.ChannelMin.Rssi, + settings.ChannelMax.Rssi, cmd.Channel[MANUALCONTROLSETTINGS_CHANNELGROUPS_RSSI]); + } // Implement hysteresis loop on connection status if (valid_input_detected && (++connected_count > 10)) { @@ -569,6 +592,18 @@ static void receiverTask(__attribute__((unused)) void *parameters) AlarmsSet(SYSTEMALARMS_ALARM_RECEIVER, SYSTEMALARMS_ALARM_WARNING); } } + // Set Rssi input + if (settings.ChannelGroups.Rssi != MANUALCONTROLSETTINGS_CHANNELGROUPS_NONE) { + accessory.AccessoryVal = scaledChannel[MANUALCONTROLSETTINGS_CHANNELGROUPS_RSSI]; +#ifdef USE_INPUT_LPF + // Allow some Rssi filtering without deadband + applyLPF(&accessory.AccessoryVal, MANUALCONTROLSETTINGS_RESPONSETIME_RSSI, &settings.ResponseTime, 0.0f, dT); +#endif + + if (AccessoryDesiredInstSet(4, &accessory) != 0) { + AlarmsSet(SYSTEMALARMS_ALARM_RECEIVER, SYSTEMALARMS_ALARM_WARNING); + } + } } // Update cmd object @@ -625,6 +660,9 @@ static void updateRcvrActivitySample(uint32_t rcvr_id, uint16_t samples[], uint8 static bool updateRcvrActivityCompare(uint32_t rcvr_id, struct rcvr_activity_fsm *fsm) { bool activity_updated = false; + ManualControlSettingsData settings; + + ManualControlSettingsGet(&settings); /* Compare the current value to the previous sampled value */ for (uint8_t channel = 1; channel <= RCVR_ACTIVITY_MONITOR_CHANNELS_PER_GROUP; channel++) { @@ -637,6 +675,13 @@ static bool updateRcvrActivityCompare(uint32_t rcvr_id, struct rcvr_activity_fsm delta = prev - curr; } + // Ignore activity from this Group/Channel because already used/set for Rssi input + // Without that, the ReceiverActivity will be saturated just with Rssi value activity. + if ((ManualControlSettingsChannelGroupsToArray(settings.ChannelGroups)[MANUALCONTROLSETTINGS_CHANNELGROUPS_RSSI] == fsm->group) && + (ManualControlSettingsChannelNumberToArray(settings.ChannelNumber)[MANUALCONTROLSETTINGS_CHANNELNUMBER_RSSI] == channel)) { + delta = 0; + } + if (delta > RCVR_ACTIVITY_MONITOR_MIN_RANGE) { /* Mark this channel as active */ ReceiverActivityActiveGroupOptions group; @@ -748,16 +793,20 @@ static bool updateRcvrActivity(struct rcvr_activity_fsm *fsm) return activity_updated; } -/* Read signal quality from the specified group */ +/* Read signal quality from the specified group or use Rssi input value if any */ static bool updateRcvrStatus( struct rcvr_activity_fsm *fsm, - ManualControlSettingsChannelGroupsOptions group) + ManualControlSettingsChannelGroupsOptions group, int8_t rssiValue) { extern uint32_t pios_rcvr_group_map[]; bool activity_updated = false; int8_t quality; - quality = PIOS_RCVR_GetQuality(pios_rcvr_group_map[group]); + if (rssiValue > 0) { + quality = rssiValue; + } else { + quality = PIOS_RCVR_GetQuality(pios_rcvr_group_map[group]); + } /* If no driver is detected or any other error then return */ if (quality < 0) { diff --git a/ground/gcs/src/plugins/config/configinputwidget.cpp b/ground/gcs/src/plugins/config/configinputwidget.cpp index 47e075b557..ce49a3692f 100644 --- a/ground/gcs/src/plugins/config/configinputwidget.cpp +++ b/ground/gcs/src/plugins/config/configinputwidget.cpp @@ -83,7 +83,8 @@ ConfigInputWidget::ConfigInputWidget(QWidget *parent) : accessoryDesiredObj0(NULL), accessoryDesiredObj1(NULL), accessoryDesiredObj2(NULL), - accessoryDesiredObj3(NULL) + accessoryDesiredObj3(NULL), + rssiDesiredObj4(NULL) { manualCommandObj = ManualControlCommand::GetInstance(getObjectManager()); manualSettingsObj = ManualControlSettings::GetInstance(getObjectManager()); @@ -94,6 +95,7 @@ ConfigInputWidget::ConfigInputWidget(QWidget *parent) : accessoryDesiredObj1 = AccessoryDesired::GetInstance(getObjectManager(), 1); accessoryDesiredObj2 = AccessoryDesired::GetInstance(getObjectManager(), 2); accessoryDesiredObj3 = AccessoryDesired::GetInstance(getObjectManager(), 3); + rssiDesiredObj4 = AccessoryDesired::GetInstance(getObjectManager(), 4); actuatorSettingsObj = ActuatorSettings::GetInstance(getObjectManager()); systemSettingsObj = SystemSettings::GetInstance(getObjectManager()); @@ -138,7 +140,12 @@ ConfigInputWidget::ConfigInputWidget(QWidget *parent) : // Slider position based on real time Rcinput (allow monitoring) addWidgetBinding("ManualControlCommand", "Channel", inputChannelForm->ui->channelNeutral, index); // Neutral value stored on board (SpinBox) - addWidgetBinding("ManualControlSettings", "ChannelNeutral", inputChannelForm->ui->neutralValue, index); + // Rssi neutral is always set to min + if (index == ManualControlSettings::CHANNELGROUPS_RSSI) { + addWidgetBinding("ManualControlSettings", "ChannelMin", inputChannelForm->ui->neutralValue, index); + } else { + addWidgetBinding("ManualControlSettings", "ChannelNeutral", inputChannelForm->ui->neutralValue, index); + } addWidgetBinding("ManualControlSettings", "ChannelMax", inputChannelForm->ui->channelMax, index); addWidgetBinding("ManualControlSettings", "ChannelMin", inputChannelForm->ui->channelMin, index); addWidgetBinding("ManualControlSettings", "ChannelMax", inputChannelForm->ui->channelMax, index); @@ -153,7 +160,10 @@ ConfigInputWidget::ConfigInputWidget(QWidget *parent) : inputChannelForm->ui->channelRev->setVisible(reversable); // Input filter response time fields supported for some channels only + // Set Neutral field to readonly for Rssi switch (index) { + case ManualControlSettings::CHANNELGROUPS_RSSI: + inputChannelForm->ui->neutralValue->setReadOnly(true); case ManualControlSettings::CHANNELGROUPS_ROLL: case ManualControlSettings::CHANNELGROUPS_PITCH: case ManualControlSettings::CHANNELGROUPS_YAW: @@ -937,7 +947,8 @@ void ConfigInputWidget::wizardTearDownStep(enum wizardSteps step) case wizardIdentifyCenter: manualCommandData = manualCommandObj->getData(); manualSettingsData = manualSettingsObj->getData(); - for (unsigned int i = 0; i < ManualControlCommand::CHANNEL_NUMELEM; ++i) { + // Ignore last Rssi channel + for (unsigned int i = 0; i < ManualControlCommand::CHANNEL_NUMELEM - 1; ++i) { // Set Accessory neutral to middle range if (i >= ManualControlSettings::CHANNELNUMBER_ACCESSORY0) { manualSettingsData.ChannelNeutral[i] = manualSettingsData.ChannelMin[i] + ((manualSettingsData.ChannelMax[i] - manualSettingsData.ChannelMin[i]) / 2); @@ -1935,17 +1946,19 @@ void ConfigInputWidget::updateCalibration() { manualCommandData = manualCommandObj->getData(); for (uint i = 0; i < ManualControlSettings::CHANNELMAX_NUMELEM; ++i) { - if ((!reverse[i] && manualSettingsData.ChannelMin[i] > manualCommandData.Channel[i]) || - (reverse[i] && manualSettingsData.ChannelMin[i] < manualCommandData.Channel[i])) { - manualSettingsData.ChannelMin[i] = manualCommandData.Channel[i]; - } - if ((!reverse[i] && manualSettingsData.ChannelMax[i] < manualCommandData.Channel[i]) || - (reverse[i] && manualSettingsData.ChannelMax[i] > manualCommandData.Channel[i])) { - manualSettingsData.ChannelMax[i] = manualCommandData.Channel[i]; + if (i != ManualControlSettings::CHANNELNUMBER_RSSI) { + if ((!reverse[i] && manualSettingsData.ChannelMin[i] > manualCommandData.Channel[i]) || + (reverse[i] && manualSettingsData.ChannelMin[i] < manualCommandData.Channel[i])) { + manualSettingsData.ChannelMin[i] = manualCommandData.Channel[i]; + } + if ((!reverse[i] && manualSettingsData.ChannelMax[i] < manualCommandData.Channel[i]) || + (reverse[i] && manualSettingsData.ChannelMax[i] > manualCommandData.Channel[i])) { + manualSettingsData.ChannelMax[i] = manualCommandData.Channel[i]; + } } if ((i == ManualControlSettings::CHANNELNUMBER_FLIGHTMODE) || (i == ManualControlSettings::CHANNELNUMBER_THROTTLE)) { adjustSpecialNeutrals(); - } else { + } else if (i != ManualControlSettings::CHANNELNUMBER_RSSI) { // Set Accessory neutral to middle range if (i >= ManualControlSettings::CHANNELNUMBER_ACCESSORY0) { manualSettingsData.ChannelNeutral[i] = manualSettingsData.ChannelMin[i] + ((manualSettingsData.ChannelMax[i] - manualSettingsData.ChannelMin[i]) / 2); @@ -1984,8 +1997,8 @@ void ConfigInputWidget::simpleCalibration(bool enable) flightModeSettingsData = flightModeSettingsObj->getData(); flightModeSettingsData.Arming = FlightModeSettings::ARMING_ALWAYSDISARMED; flightModeSettingsObj->setData(flightModeSettingsData); - - for (unsigned int i = 0; i < ManualControlCommand::CHANNEL_NUMELEM; i++) { + // Ignore last Rssi channel + for (unsigned int i = 0; i < ManualControlCommand::CHANNEL_NUMELEM - 1; i++) { reverse[i] = manualSettingsData.ChannelMax[i] < manualSettingsData.ChannelMin[i]; manualSettingsData.ChannelMin[i] = manualCommandData.Channel[i]; manualSettingsData.ChannelNeutral[i] = manualCommandData.Channel[i]; @@ -2027,7 +2040,7 @@ void ConfigInputWidget::simpleCalibration(bool enable) if ((i == ManualControlSettings::CHANNELNUMBER_FLIGHTMODE) || (i == ManualControlSettings::CHANNELNUMBER_THROTTLE)) { adjustSpecialNeutrals(); checkThrottleRange(); - } else { + } else if (i != ManualControlSettings::CHANNELNUMBER_RSSI) { // Set Accessory neutral to middle range if (i >= ManualControlSettings::CHANNELNUMBER_ACCESSORY0) { manualSettingsData.ChannelNeutral[i] = manualSettingsData.ChannelMin[i] + ((manualSettingsData.ChannelMax[i] - manualSettingsData.ChannelMin[i]) / 2); @@ -2096,8 +2109,8 @@ bool ConfigInputWidget::shouldObjectBeSaved(UAVObject *object) void ConfigInputWidget::resetChannelSettings() { manualSettingsData = manualSettingsObj->getData(); - // Clear all channel data : Channel Type (PPM,PWM..) and Number - for (unsigned int channel = 0; channel < ManualControlSettings::CHANNELNUMBER_NUMELEM; channel++) { + // Clear all channel data : Channel Type (PPM,PWM..) and Number, except for Rssi + for (unsigned int channel = 0; channel < ManualControlSettings::CHANNELNUMBER_NUMELEM - 1; channel++) { manualSettingsData.ChannelGroups[channel] = ManualControlSettings::CHANNELGROUPS_NONE; manualSettingsData.ChannelNumber[channel] = CHANNEL_NUMBER_NONE; UAVObjectUpdaterHelper updateHelper; diff --git a/ground/gcs/src/plugins/config/configinputwidget.h b/ground/gcs/src/plugins/config/configinputwidget.h index a110d62c39..26bda23a14 100644 --- a/ground/gcs/src/plugins/config/configinputwidget.h +++ b/ground/gcs/src/plugins/config/configinputwidget.h @@ -130,6 +130,7 @@ class ConfigInputWidget : public ConfigTaskWidget { AccessoryDesired *accessoryDesiredObj1; AccessoryDesired *accessoryDesiredObj2; AccessoryDesired *accessoryDesiredObj3; + AccessoryDesired *rssiDesiredObj4; ManualControlSettings *manualSettingsObj; ManualControlSettings::DataFields manualSettingsData; diff --git a/shared/uavobjectdefinition/manualcontrolcommand.xml b/shared/uavobjectdefinition/manualcontrolcommand.xml index f50990a079..7654c29edf 100644 --- a/shared/uavobjectdefinition/manualcontrolcommand.xml +++ b/shared/uavobjectdefinition/manualcontrolcommand.xml @@ -8,7 +8,7 @@ - + diff --git a/shared/uavobjectdefinition/manualcontrolsettings.xml b/shared/uavobjectdefinition/manualcontrolsettings.xml index ef1cb93e4c..7b4879b2e4 100644 --- a/shared/uavobjectdefinition/manualcontrolsettings.xml +++ b/shared/uavobjectdefinition/manualcontrolsettings.xml @@ -1,34 +1,32 @@ - Settings to indicate how to decode receiver input by @ref ManualControlModule. - + Settings to indicate how to decode receiver input by @ref ManualControlModule. + + elementnames="Throttle,Roll,Pitch,Yaw,FlightMode,Collective,Accessory0,Accessory1,Accessory2,Accessory3,Rssi"/> + elementnames="Throttle,Roll,Pitch,Yaw,FlightMode,Collective,Accessory0,Accessory1,Accessory2,Accessory3,Rssi"/> + elementnames="Throttle,Roll,Pitch,Yaw,FlightMode,Collective,Accessory0,Accessory1,Accessory2,Accessory3,Rssi"/> + elementnames="Throttle,Roll,Pitch,Yaw,FlightMode,Collective,Accessory0,Accessory1,Accessory2,Accessory3,Rssi"/> + elementnames="Roll,Pitch,Yaw,Collective,Accessory0,Accessory1,Accessory2,Accessory3,Rssi"/> - + - - + - - - - + - - - - + + + + + + From 72aabd30fd8bd151dca8d37f17c8a2ab4032fc2c Mon Sep 17 00:00:00 2001 From: Laurent Lalanne Date: Wed, 14 Sep 2016 14:57:55 +0200 Subject: [PATCH 018/624] LP-407 Pios_Sbus: Set quality to minimum after a failsafe --- flight/pios/common/pios_sbus.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/flight/pios/common/pios_sbus.c b/flight/pios/common/pios_sbus.c index e354a5c5f7..240a7c51c9 100644 --- a/flight/pios/common/pios_sbus.c +++ b/flight/pios/common/pios_sbus.c @@ -125,6 +125,7 @@ static void PIOS_SBus_ResetChannels(struct pios_sbus_state *state) { for (int i = 0; i < PIOS_SBUS_NUM_INPUTS; i++) { state->channel_data[i] = PIOS_RCVR_TIMEOUT; + state->quality = 0.0f; } } @@ -302,6 +303,7 @@ static void PIOS_SBus_UpdateState(struct pios_sbus_state *state, uint8_t b) } #ifndef SBUS_GOOD_FRAME_COUNT /* Present quality as a weighted average of good frames */ + // TODO: Refactor quality computation, give 4% (quality_trend / SBUS_FL_WEIGHTED_AVE) at minimum state->quality = ((state->quality * (SBUS_FL_WEIGHTED_AVE - 1)) + quality_trend) / SBUS_FL_WEIGHTED_AVE; #endif /* SBUS_GOOD_FRAME_COUNT */ From aaf30e7fad65f3987d859eebaa4c77340db8e6a8 Mon Sep 17 00:00:00 2001 From: Laurent Lalanne Date: Fri, 16 Sep 2016 19:41:51 +0200 Subject: [PATCH 019/624] LP-407 Changes from review - Cleannup --- flight/modules/Receiver/receiver.c | 6 +--- .../src/plugins/config/configinputwidget.cpp | 34 +++++++++---------- 2 files changed, 17 insertions(+), 23 deletions(-) diff --git a/flight/modules/Receiver/receiver.c b/flight/modules/Receiver/receiver.c index b2308dfa25..f98850937a 100644 --- a/flight/modules/Receiver/receiver.c +++ b/flight/modules/Receiver/receiver.c @@ -802,11 +802,7 @@ static bool updateRcvrStatus( bool activity_updated = false; int8_t quality; - if (rssiValue > 0) { - quality = rssiValue; - } else { - quality = PIOS_RCVR_GetQuality(pios_rcvr_group_map[group]); - } + quality = (rssiValue > 0) ? rssiValue : PIOS_RCVR_GetQuality(pios_rcvr_group_map[group]); /* If no driver is detected or any other error then return */ if (quality < 0) { diff --git a/ground/gcs/src/plugins/config/configinputwidget.cpp b/ground/gcs/src/plugins/config/configinputwidget.cpp index ce49a3692f..9adcfb8374 100644 --- a/ground/gcs/src/plugins/config/configinputwidget.cpp +++ b/ground/gcs/src/plugins/config/configinputwidget.cpp @@ -842,7 +842,7 @@ void ConfigInputWidget::wizardSetUpStep(enum wizardSteps step) { setTxMovement(nothing); manualSettingsData = manualSettingsObj->getData(); - for (uint i = 0; i < ManualControlSettings::CHANNELMAX_NUMELEM; ++i) { + for (uint i = 0; i < ManualControlSettings::CHANNELNUMBER_RSSI; ++i) { // Preserve the inverted status if (manualSettingsData.ChannelMin[i] <= manualSettingsData.ChannelMax[i]) { manualSettingsData.ChannelMin[i] = manualSettingsData.ChannelNeutral[i]; @@ -948,7 +948,7 @@ void ConfigInputWidget::wizardTearDownStep(enum wizardSteps step) manualCommandData = manualCommandObj->getData(); manualSettingsData = manualSettingsObj->getData(); // Ignore last Rssi channel - for (unsigned int i = 0; i < ManualControlCommand::CHANNEL_NUMELEM - 1; ++i) { + for (unsigned int i = 0; i < ManualControlSettings::CHANNELNUMBER_RSSI; ++i) { // Set Accessory neutral to middle range if (i >= ManualControlSettings::CHANNELNUMBER_ACCESSORY0) { manualSettingsData.ChannelNeutral[i] = manualSettingsData.ChannelMin[i] + ((manualSettingsData.ChannelMax[i] - manualSettingsData.ChannelMin[i]) / 2); @@ -1206,7 +1206,7 @@ void ConfigInputWidget::identifyLimits() bool newFlightModeValue = false; manualCommandData = manualCommandObj->getData(); - for (uint i = 0; i < ManualControlSettings::CHANNELMAX_NUMELEM; ++i) { + for (uint i = 0; i < ManualControlSettings::CHANNELNUMBER_RSSI; ++i) { inputValue = manualCommandData.Channel[i]; // Check if channel is already detected and prevent glitches if ((manualSettingsData.ChannelNumber[i] != CHANNEL_NUMBER_NONE) && @@ -1945,20 +1945,18 @@ void ConfigInputWidget::updateConfigAlarmStatus() void ConfigInputWidget::updateCalibration() { manualCommandData = manualCommandObj->getData(); - for (uint i = 0; i < ManualControlSettings::CHANNELMAX_NUMELEM; ++i) { - if (i != ManualControlSettings::CHANNELNUMBER_RSSI) { - if ((!reverse[i] && manualSettingsData.ChannelMin[i] > manualCommandData.Channel[i]) || - (reverse[i] && manualSettingsData.ChannelMin[i] < manualCommandData.Channel[i])) { - manualSettingsData.ChannelMin[i] = manualCommandData.Channel[i]; - } - if ((!reverse[i] && manualSettingsData.ChannelMax[i] < manualCommandData.Channel[i]) || - (reverse[i] && manualSettingsData.ChannelMax[i] > manualCommandData.Channel[i])) { - manualSettingsData.ChannelMax[i] = manualCommandData.Channel[i]; - } + for (uint i = 0; i < ManualControlSettings::CHANNELNUMBER_RSSI; ++i) { + if ((!reverse[i] && manualSettingsData.ChannelMin[i] > manualCommandData.Channel[i]) || + (reverse[i] && manualSettingsData.ChannelMin[i] < manualCommandData.Channel[i])) { + manualSettingsData.ChannelMin[i] = manualCommandData.Channel[i]; + } + if ((!reverse[i] && manualSettingsData.ChannelMax[i] < manualCommandData.Channel[i]) || + (reverse[i] && manualSettingsData.ChannelMax[i] > manualCommandData.Channel[i])) { + manualSettingsData.ChannelMax[i] = manualCommandData.Channel[i]; } if ((i == ManualControlSettings::CHANNELNUMBER_FLIGHTMODE) || (i == ManualControlSettings::CHANNELNUMBER_THROTTLE)) { adjustSpecialNeutrals(); - } else if (i != ManualControlSettings::CHANNELNUMBER_RSSI) { + } else { // Set Accessory neutral to middle range if (i >= ManualControlSettings::CHANNELNUMBER_ACCESSORY0) { manualSettingsData.ChannelNeutral[i] = manualSettingsData.ChannelMin[i] + ((manualSettingsData.ChannelMax[i] - manualSettingsData.ChannelMin[i]) / 2); @@ -1998,7 +1996,7 @@ void ConfigInputWidget::simpleCalibration(bool enable) flightModeSettingsData.Arming = FlightModeSettings::ARMING_ALWAYSDISARMED; flightModeSettingsObj->setData(flightModeSettingsData); // Ignore last Rssi channel - for (unsigned int i = 0; i < ManualControlCommand::CHANNEL_NUMELEM - 1; i++) { + for (unsigned int i = 0; i < ManualControlSettings::CHANNELNUMBER_RSSI; i++) { reverse[i] = manualSettingsData.ChannelMax[i] < manualSettingsData.ChannelMin[i]; manualSettingsData.ChannelMin[i] = manualCommandData.Channel[i]; manualSettingsData.ChannelNeutral[i] = manualCommandData.Channel[i]; @@ -2036,11 +2034,11 @@ void ConfigInputWidget::simpleCalibration(bool enable) forceOneFlightMode(); } - for (unsigned int i = 0; i < ManualControlCommand::CHANNEL_NUMELEM; i++) { + for (unsigned int i = 0; i < ManualControlSettings::CHANNELNUMBER_RSSI; i++) { if ((i == ManualControlSettings::CHANNELNUMBER_FLIGHTMODE) || (i == ManualControlSettings::CHANNELNUMBER_THROTTLE)) { adjustSpecialNeutrals(); checkThrottleRange(); - } else if (i != ManualControlSettings::CHANNELNUMBER_RSSI) { + } else { // Set Accessory neutral to middle range if (i >= ManualControlSettings::CHANNELNUMBER_ACCESSORY0) { manualSettingsData.ChannelNeutral[i] = manualSettingsData.ChannelMin[i] + ((manualSettingsData.ChannelMax[i] - manualSettingsData.ChannelMin[i]) / 2); @@ -2110,7 +2108,7 @@ void ConfigInputWidget::resetChannelSettings() { manualSettingsData = manualSettingsObj->getData(); // Clear all channel data : Channel Type (PPM,PWM..) and Number, except for Rssi - for (unsigned int channel = 0; channel < ManualControlSettings::CHANNELNUMBER_NUMELEM - 1; channel++) { + for (unsigned int channel = 0; channel < ManualControlSettings::CHANNELNUMBER_RSSI; channel++) { manualSettingsData.ChannelGroups[channel] = ManualControlSettings::CHANNELGROUPS_NONE; manualSettingsData.ChannelNumber[channel] = CHANNEL_NUMBER_NONE; UAVObjectUpdaterHelper updateHelper; From 7170c835b7cadf03ec542e31805a38485dc40eab Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Thu, 22 Sep 2016 09:04:36 +0200 Subject: [PATCH 020/624] LP-404 replace opfw_resource target with fw_resource --- .drone.yml | 2 +- .travis.yml | 2 +- bitbucket-pipelines.yml | 2 +- package/linux/debian/rules | 2 +- package/linux/rpmspec.in | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.drone.yml b/.drone.yml index 3cc9d4365f..b8f8c67b21 100644 --- a/.drone.yml +++ b/.drone.yml @@ -10,7 +10,7 @@ build: - mingw32-make all_sdk_install - git config core.filemode false - mingw32-make build-info && cat build/build-info.txt - - mingw32-make opfw_resource + - mingw32-make fw_resource - mingw32-make gcs - mingw32-make package - mv `ls build/LibrePilot-*.exe` build/$$BRANCH-$$COMMIT-$$arch-package.exe diff --git a/.travis.yml b/.travis.yml index 06c8fe0e86..cb2c739485 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,7 @@ before_install: script: - make config_new CCACHE=ccache - make all_flight - - make opfw_resource + - make fw_resource - make gcs git: diff --git a/bitbucket-pipelines.yml b/bitbucket-pipelines.yml index b73f5e6aa5..7f75b1d65b 100644 --- a/bitbucket-pipelines.yml +++ b/bitbucket-pipelines.yml @@ -7,5 +7,5 @@ pipelines: - apt-get install -y libc6-i386 libudev-dev libusb-1.0-0-dev libsdl1.2-dev python libopenscenegraph-dev libosgearth-dev qt56-meta-minimal qt56svg qt56script qt56serialport qt56multimedia qt56translations qt56tools - make build_sdk_install - make all_flight - - make opfw_resource + - make fw_resource - make gcs diff --git a/package/linux/debian/rules b/package/linux/debian/rules index e636c8a1d8..45b1cfe3df 100755 --- a/package/linux/debian/rules +++ b/package/linux/debian/rules @@ -15,7 +15,7 @@ override_dh_auto_configure: $(MAKE) config_new WITH_PREBUILT_FW=$(CURDIR)/firmware override_dh_auto_build: - dh_auto_build -- opfw_resource gcs + dh_auto_build -- fw_resource gcs override_dh_auto_install: dh_auto_install -- prefix=/usr diff --git a/package/linux/rpmspec.in b/package/linux/rpmspec.in index 35cbc4acab..1b4ac92a0c 100644 --- a/package/linux/rpmspec.in +++ b/package/linux/rpmspec.in @@ -61,7 +61,7 @@ make config_new \ udevrulesdir=%{_udevrulesdir} \ WITH_PREBUILT_FW=$(pwd)/build/firmware -make %{?_smp_mflags} opfw_resource gcs +make %{?_smp_mflags} fw_resource gcs %install From 87035d953cc4229bb3ed7032d43cbe36d8b2795d Mon Sep 17 00:00:00 2001 From: Vladimir Zidar Date: Sat, 24 Sep 2016 01:07:01 +0200 Subject: [PATCH 021/624] LP-412 Allow access to rx & tx callbacks through pios_com device API. --- flight/pios/common/pios_com.c | 77 ++++++++++++++++++++++++++++++++--- flight/pios/inc/pios_com.h | 6 +++ 2 files changed, 78 insertions(+), 5 deletions(-) diff --git a/flight/pios/common/pios_com.c b/flight/pios/common/pios_com.c index 0427dd2f76..a0fc51e1e8 100644 --- a/flight/pios/common/pios_com.c +++ b/flight/pios/common/pios_com.c @@ -119,7 +119,7 @@ int32_t PIOS_COM_Init(uint32_t *com_id, const struct pios_com_driver *driver, ui bool has_rx = (rx_buffer && rx_buffer_len > 0); bool has_tx = (tx_buffer && tx_buffer_len > 0); - PIOS_Assert(has_rx || has_tx); + PIOS_Assert(driver->bind_tx_cb || !has_tx); PIOS_Assert(driver->bind_rx_cb || !has_rx); @@ -153,12 +153,10 @@ int32_t PIOS_COM_Init(uint32_t *com_id, const struct pios_com_driver *driver, ui fifoBuf_init(&com_dev->tx, tx_buffer, tx_buffer_len); #if defined(PIOS_INCLUDE_FREERTOS) vSemaphoreCreateBinary(com_dev->tx_sem); + com_dev->sendbuffer_sem = xSemaphoreCreateMutex(); #endif /* PIOS_INCLUDE_FREERTOS */ (com_dev->driver->bind_tx_cb)(lower_id, PIOS_COM_TxOutCallback, (uint32_t)com_dev); } -#if defined(PIOS_INCLUDE_FREERTOS) - com_dev->sendbuffer_sem = xSemaphoreCreateMutex(); -#endif /* PIOS_INCLUDE_FREERTOS */ *com_id = (uint32_t)com_dev; return 0; @@ -358,6 +356,74 @@ int32_t PIOS_COM_RegisterBaudRateCallback(uint32_t com_id, pios_com_callback_bau return 0; } +int32_t PIOS_COM_ASYNC_TxStart(uint32_t com_id, uint16_t tx_bytes_avail) +{ + struct pios_com_dev *com_dev = (struct pios_com_dev *)com_id; + + if (!PIOS_COM_validate(com_dev)) { + /* Undefined COM port for this board (see pios_board.c) */ + return -1; + } + + /* Invoke the driver function if it exists */ + if (com_dev->driver->tx_start) { + com_dev->driver->tx_start(com_dev->lower_id, tx_bytes_avail); + } + + return 0; +} + +int32_t PIOS_COM_ASYNC_RxStart(uint32_t com_id, uint16_t rx_bytes_avail) +{ + struct pios_com_dev *com_dev = (struct pios_com_dev *)com_id; + + if (!PIOS_COM_validate(com_dev)) { + /* Undefined COM port for this board (see pios_board.c) */ + return -1; + } + + /* Invoke the driver function if it exists */ + if (com_dev->driver->rx_start) { + com_dev->driver->rx_start(com_dev->lower_id, rx_bytes_avail); + } + + return 0; +} + +int32_t PIOS_COM_ASYNC_RegisterRxCallback(uint32_t com_id, pios_com_callback rx_in_cb, uint32_t context) +{ + struct pios_com_dev *com_dev = (struct pios_com_dev *)com_id; + + if (!PIOS_COM_validate(com_dev)) { + /* Undefined COM port for this board (see pios_board.c) */ + return -1; + } + + /* Invoke the driver function if it exists */ + if (com_dev->driver->bind_rx_cb) { + com_dev->driver->bind_rx_cb(com_dev->lower_id, rx_in_cb, context); + } + + return 0; +} + +int32_t PIOS_COM_ASYNC_RegisterTxCallback(uint32_t com_id, pios_com_callback tx_out_cb, uint32_t context) +{ + struct pios_com_dev *com_dev = (struct pios_com_dev *)com_id; + + if (!PIOS_COM_validate(com_dev)) { + /* Undefined COM port for this board (see pios_board.c) */ + return -1; + } + + /* Invoke the driver function if it exists */ + if (com_dev->driver->bind_tx_cb) { + com_dev->driver->bind_tx_cb(com_dev->lower_id, tx_out_cb, context); + } + + return 0; +} + static int32_t PIOS_COM_SendBufferNonBlockingInternal(struct pios_com_dev *com_dev, const uint8_t *buffer, uint16_t len) { PIOS_Assert(com_dev); @@ -411,6 +477,7 @@ int32_t PIOS_COM_SendBufferNonBlocking(uint32_t com_id, const uint8_t *buffer, u /* Undefined COM port for this board (see pios_board.c) */ return -1; } + PIOS_Assert(com_dev->has_tx); #if defined(PIOS_INCLUDE_FREERTOS) if (xSemaphoreTake(com_dev->sendbuffer_sem, 0) != pdTRUE) { return -3; @@ -668,7 +735,7 @@ uint32_t PIOS_COM_Available(uint32_t com_id) return COM_AVAILABLE_TX; } - return COM_AVAILABLE_NONE; /* can this really happen? */ + return COM_AVAILABLE_RXTX; /* This is the case for com_dev without buffers - for async use only */ } return (com_dev->driver->available)(com_dev->lower_id); diff --git a/flight/pios/inc/pios_com.h b/flight/pios/inc/pios_com.h index c2ab7a9bb0..355533957a 100644 --- a/flight/pios/inc/pios_com.h +++ b/flight/pios/inc/pios_com.h @@ -73,6 +73,12 @@ extern int32_t PIOS_COM_SendFormattedString(uint32_t com_id, const char *format, extern uint16_t PIOS_COM_ReceiveBuffer(uint32_t com_id, uint8_t *buf, uint16_t buf_len, uint32_t timeout_ms); extern uint32_t PIOS_COM_Available(uint32_t com_id); +/* Event driven asynchronous API */ +extern int32_t PIOS_COM_ASYNC_TxStart(uint32_t id, uint16_t tx_bytes_avail); +extern int32_t PIOS_COM_ASYNC_RxStart(uint32_t id, uint16_t rx_bytes_avail); +extern int32_t PIOS_COM_ASYNC_RegisterRxCallback(uint32_t id, pios_com_callback rx_in_cb, uint32_t context); +extern int32_t PIOS_COM_ASYNC_RegisterTxCallback(uint32_t id, pios_com_callback tx_out_cb, uint32_t context); + #define COM_AVAILABLE_NONE (0) #define COM_AVAILABLE_RX (1 << 0) #define COM_AVAILABLE_TX (1 << 1) From 5d8274357db2c34ad9948edb10e07fb2ffc1e128 Mon Sep 17 00:00:00 2001 From: Vladimir Zidar Date: Sat, 24 Sep 2016 01:10:31 +0200 Subject: [PATCH 022/624] LP-413 This commit adds PIOS_COM_RegisterAvailableCallback() function. --- flight/pios/common/pios_com.c | 25 +++++++++++++++ flight/pios/inc/pios_com.h | 3 ++ flight/pios/inc/pios_usb.h | 1 + flight/pios/stm32f10x/pios_usb.c | 47 ++++++++++++++++++++++++++-- flight/pios/stm32f10x/pios_usb_cdc.c | 38 ++++++++++++++++++++-- flight/pios/stm32f4xx/pios_usb.c | 47 ++++++++++++++++++++++++++-- flight/pios/stm32f4xx/pios_usb_cdc.c | 42 +++++++++++++++++++++++-- 7 files changed, 193 insertions(+), 10 deletions(-) diff --git a/flight/pios/common/pios_com.c b/flight/pios/common/pios_com.c index 0427dd2f76..8a2686c543 100644 --- a/flight/pios/common/pios_com.c +++ b/flight/pios/common/pios_com.c @@ -674,6 +674,31 @@ uint32_t PIOS_COM_Available(uint32_t com_id) return (com_dev->driver->available)(com_dev->lower_id); } +/* + * Set available callback + * \param[in] port COM port + * \param[in] available_cb Callback function + * \param[in] context context to pass to the callback function + * \return -1 if port not available + * \return 0 on success + */ +int32_t PIOS_COM_RegisterAvailableCallback(uint32_t com_id, pios_com_callback_available available_cb, uint32_t context) +{ + struct pios_com_dev *com_dev = (struct pios_com_dev *)com_id; + + if (!PIOS_COM_validate(com_dev)) { + /* Undefined COM port for this board (see pios_board.c) */ + return -1; + } + + /* Invoke the driver function if it exists */ + if (com_dev->driver->bind_available_cb) { + com_dev->driver->bind_available_cb(com_dev->lower_id, available_cb, context); + } + + return 0; +} + #endif /* PIOS_INCLUDE_COM */ /** diff --git a/flight/pios/inc/pios_com.h b/flight/pios/inc/pios_com.h index c2ab7a9bb0..4bf6a0efab 100644 --- a/flight/pios/inc/pios_com.h +++ b/flight/pios/inc/pios_com.h @@ -38,6 +38,7 @@ typedef uint16_t (*pios_com_callback)(uint32_t context, uint8_t *buf, uint16_t buf_len, uint16_t *headroom, bool *task_woken); typedef void (*pios_com_callback_ctrl_line)(uint32_t context, uint32_t mask, uint32_t state); typedef void (*pios_com_callback_baud_rate)(uint32_t context, uint32_t baud); +typedef void (*pios_com_callback_available)(uint32_t context, uint32_t available); struct pios_com_driver { void (*init)(uint32_t id); @@ -50,6 +51,7 @@ struct pios_com_driver { void (*bind_ctrl_line_cb)(uint32_t id, pios_com_callback_ctrl_line ctrl_line_cb, uint32_t context); void (*bind_baud_rate_cb)(uint32_t id, pios_com_callback_baud_rate baud_rate_cb, uint32_t context); uint32_t (*available)(uint32_t id); + void (*bind_available_cb)(uint32_t id, pios_com_callback_available available_cb, uint32_t context); }; /* Control line definitions */ @@ -72,6 +74,7 @@ extern int32_t PIOS_COM_SendFormattedStringNonBlocking(uint32_t com_id, const ch extern int32_t PIOS_COM_SendFormattedString(uint32_t com_id, const char *format, ...); extern uint16_t PIOS_COM_ReceiveBuffer(uint32_t com_id, uint8_t *buf, uint16_t buf_len, uint32_t timeout_ms); extern uint32_t PIOS_COM_Available(uint32_t com_id); +extern int32_t PIOS_COM_RegisterAvailableCallback(uint32_t com_id, pios_com_callback_available, uint32_t context); #define COM_AVAILABLE_NONE (0) #define COM_AVAILABLE_RX (1 << 0) diff --git a/flight/pios/inc/pios_usb.h b/flight/pios/inc/pios_usb.h index a068a1705a..06ed1d48f1 100644 --- a/flight/pios/inc/pios_usb.h +++ b/flight/pios/inc/pios_usb.h @@ -38,6 +38,7 @@ extern int32_t PIOS_USB_ChangeConnectionState(bool connected); extern bool PIOS_USB_CableConnected(uint8_t id); extern bool PIOS_USB_CheckAvailable(uint32_t id); extern void PIOS_USB_RegisterDisconnectionCallback(void (*disconnectionCB)(void)); +extern void PIOS_USB_RegisterConnectionStateCallback(void (*connectionStateCallback)(bool connected, uint32_t context), uint32_t context); #endif /* PIOS_USB_H */ /** diff --git a/flight/pios/stm32f10x/pios_usb.c b/flight/pios/stm32f10x/pios_usb.c index f79b08c53d..12cd962470 100644 --- a/flight/pios/stm32f10x/pios_usb.c +++ b/flight/pios/stm32f10x/pios_usb.c @@ -38,11 +38,16 @@ #include "pios_usb_priv.h" -#ifdef PIOS_INCLUDE_USB_HID - /* Rx/Tx status */ static bool transfer_possible = false; +#ifdef PIOS_INCLUDE_FREERTOS +struct { + void (*callback)(bool connected, uint32_t context); + uint32_t context; +} connectionState_cb_list[3]; +#endif + enum pios_usb_dev_magic { PIOS_USB_DEV_MAGIC = 0x17365904, }; @@ -51,6 +56,9 @@ struct pios_usb_dev { enum pios_usb_dev_magic magic; const struct pios_usb_cfg *cfg; }; +#ifdef PIOS_INCLUDE_FREERTOS +static void raiseConnectionStateCallback(bool connected); +#endif /** * @brief Validate the usb device structure @@ -175,6 +183,10 @@ int32_t PIOS_USB_ChangeConnectionState(bool Connected) #endif } +#ifdef PIOS_INCLUDE_FREERTOS + raiseConnectionStateCallback(Connected); +#endif + return 0; } @@ -242,7 +254,36 @@ bool PIOS_USB_CheckAvailable(uint32_t id) return PIOS_USB_CableConnected(id) && transfer_possible; } -#endif /* PIOS_INCLUDE_USB_HID */ +#ifdef PIOS_INCLUDE_FREERTOS +void PIOS_USB_RegisterConnectionStateCallback(void (*connectionStateCallback)(bool connected, uint32_t context), uint32_t context) +{ + PIOS_Assert(connectionStateCallback); + + for (uint32_t i = 0; i < NELEMENTS(connectionState_cb_list); i++) { + if (connectionState_cb_list[i].callback == NULL) { + connectionState_cb_list[i].callback = connectionStateCallback; + connectionState_cb_list[i].context = context; + return; + } + } + + PIOS_Assert(0); +} + +static void raiseConnectionStateCallback(bool connected) +{ + uint32_t i = 0; + + while (i < NELEMENTS(connectionState_cb_list) && connectionState_cb_list[i].callback != NULL) { + connectionState_cb_list[i].callback(connected, connectionState_cb_list[i].context); + i++; + } +} +#else /* PIOS_INCLUDE_FREERTOS */ +void PIOS_USB_RegisterConnectionStateCallback(__attribute__((unused)) void (*connectionStateCallback)(bool connected, uint32_t context), __attribute__((unused)) uint32_t context) +{} +#endif /* PIOS_INCLUDE_FREERTOS */ + #endif /* PIOS_INCLUDE_USB */ diff --git a/flight/pios/stm32f10x/pios_usb_cdc.c b/flight/pios/stm32f10x/pios_usb_cdc.c index 84255191f7..ebbaedbd1b 100644 --- a/flight/pios/stm32f10x/pios_usb_cdc.c +++ b/flight/pios/stm32f10x/pios_usb_cdc.c @@ -42,6 +42,8 @@ static void PIOS_USB_CDC_RegisterTxCallback(uint32_t usbcdc_id, pios_com_callback tx_out_cb, uint32_t context); static void PIOS_USB_CDC_RegisterRxCallback(uint32_t usbcdc_id, pios_com_callback rx_in_cb, uint32_t context); static void PIOS_USB_CDC_RegisterBaudRateCallback(uint32_t usbcdc_id, pios_com_callback_baud_rate baud_rate_cb, uint32_t context); +static void PIOS_USB_CDC_RegisterAvailableCallback(uint32_t usbcdc_id, pios_com_callback_available baud_rate_cb, uint32_t context); +static void PIOS_USB_CDC_ChangeConnectionState(bool connected, uint32_t usbcdc_id); static void PIOS_USB_CDC_TxStart(uint32_t usbcdc_id, uint16_t tx_bytes_avail); static void PIOS_USB_CDC_RxStart(uint32_t usbcdc_id, uint16_t rx_bytes_avail); static uint32_t PIOS_USB_CDC_Available(uint32_t usbcdc_id); @@ -53,6 +55,7 @@ const struct pios_com_driver pios_usb_cdc_com_driver = { .bind_rx_cb = PIOS_USB_CDC_RegisterRxCallback, .bind_baud_rate_cb = PIOS_USB_CDC_RegisterBaudRateCallback, .available = PIOS_USB_CDC_Available, + .bind_available_cb = PIOS_USB_CDC_RegisterAvailableCallback, }; enum pios_usb_cdc_dev_magic { @@ -72,6 +75,8 @@ struct pios_usb_cdc_dev { pios_com_callback_baud_rate baud_rate_cb; uint32_t baud_rate_context; + pios_com_callback_available available_cb; + uint32_t available_context; uint8_t rx_packet_buffer[PIOS_USB_BOARD_CDC_DATA_LENGTH]; /* @@ -157,6 +162,8 @@ int32_t PIOS_USB_CDC_Init(uint32_t *usbcdc_id, const struct pios_usb_cdc_cfg *cf pEpInt_IN[cfg->data_tx_ep - 1] = PIOS_USB_CDC_DATA_EP_IN_Callback; pEpInt_OUT[cfg->data_rx_ep - 1] = PIOS_USB_CDC_DATA_EP_OUT_Callback; + PIOS_USB_RegisterConnectionStateCallback(PIOS_USB_CDC_ChangeConnectionState, (uint32_t)usb_cdc_dev); + *usbcdc_id = (uint32_t)usb_cdc_dev; return 0; @@ -366,8 +373,7 @@ static uint32_t PIOS_USB_CDC_Available(uint32_t usbcdc_id) PIOS_Assert(valid); - return (PIOS_USB_CheckAvailable(usb_cdc_dev->lower_id) && - (control_line_state & USB_CDC_CONTROL_LINE_STATE_DTE_PRESENT)) ? COM_AVAILABLE_RXTX : COM_AVAILABLE_NONE; + return PIOS_USB_CheckAvailable(usb_cdc_dev->lower_id) ? COM_AVAILABLE_RXTX : COM_AVAILABLE_NONE; } static struct usb_cdc_line_coding line_coding = { @@ -487,5 +493,33 @@ void PIOS_USB_CDC_SetLineCoding_Completed() } } +static void PIOS_USB_CDC_ChangeConnectionState(__attribute__((unused)) bool connected, uint32_t usbcdc_id) +{ + struct pios_usb_cdc_dev *usb_cdc_dev = (struct pios_usb_cdc_dev *)usbcdc_id; + + bool valid = PIOS_USB_CDC_validate(usb_cdc_dev); + + PIOS_Assert(valid); + + if (usb_cdc_dev->available_cb) { + (usb_cdc_dev->available_cb)(usb_cdc_dev->available_context, PIOS_USB_CDC_Available(usbcdc_id)); + } +} + +static void PIOS_USB_CDC_RegisterAvailableCallback(uint32_t usbcdc_id, pios_com_callback_available available_cb, uint32_t context) +{ + struct pios_usb_cdc_dev *usb_cdc_dev = (struct pios_usb_cdc_dev *)usbcdc_id; + + bool valid = PIOS_USB_CDC_validate(usb_cdc_dev); + + PIOS_Assert(valid); + + /* + * Order is important in these assignments since ISR uses _cb + * field to determine if it's ok to dereference _cb and _context + */ + usb_cdc_dev->available_context = context; + usb_cdc_dev->available_cb = available_cb; +} #endif /* PIOS_INCLUDE_USB_CDC */ diff --git a/flight/pios/stm32f4xx/pios_usb.c b/flight/pios/stm32f4xx/pios_usb.c index b0f59abc42..686120069b 100644 --- a/flight/pios/stm32f4xx/pios_usb.c +++ b/flight/pios/stm32f4xx/pios_usb.c @@ -40,8 +40,15 @@ /* Rx/Tx status */ static uint8_t transfer_possible = 0; +#ifdef PIOS_INCLUDE_FREERTOS static void(*disconnection_cb_list[3]) (void); +struct { + void (*callback)(bool connected, uint32_t context); + uint32_t context; +} connectionState_cb_list[3]; +#endif + enum pios_usb_dev_magic { PIOS_USB_DEV_MAGIC = 0x17365904, }; @@ -55,6 +62,7 @@ struct pios_usb_dev { }; #ifdef PIOS_INCLUDE_FREERTOS static void raiseDisconnectionCallbacks(void); +static void raiseConnectionStateCallback(bool connected); #endif /** * @brief Validate the usb device structure @@ -158,6 +166,10 @@ int32_t PIOS_USB_ChangeConnectionState(bool connected) #endif } +#ifdef PIOS_INCLUDE_FREERTOS + raiseConnectionStateCallback(connected); +#endif + return 0; } @@ -204,6 +216,7 @@ bool PIOS_USB_CheckAvailable(__attribute__((unused)) uint32_t id) * Register a physical disconnection callback * */ +#ifdef PIOS_INCLUDE_FREERTOS void PIOS_USB_RegisterDisconnectionCallback(void (*disconnectionCB)(void)) { PIOS_Assert(disconnectionCB); @@ -215,7 +228,6 @@ void PIOS_USB_RegisterDisconnectionCallback(void (*disconnectionCB)(void)) } PIOS_Assert(0); } -#ifdef PIOS_INCLUDE_FREERTOS static void raiseDisconnectionCallbacks(void) { uint32_t i = 0; @@ -224,7 +236,38 @@ static void raiseDisconnectionCallbacks(void) (disconnection_cb_list[i++])(); } } -#endif + +void PIOS_USB_RegisterConnectionStateCallback(void (*connectionStateCallback)(bool connected, uint32_t context), uint32_t context) +{ + PIOS_Assert(connectionStateCallback); + + for (uint32_t i = 0; i < NELEMENTS(connectionState_cb_list); i++) { + if (connectionState_cb_list[i].callback == NULL) { + connectionState_cb_list[i].callback = connectionStateCallback; + connectionState_cb_list[i].context = context; + return; + } + } + + PIOS_Assert(0); +} + +static void raiseConnectionStateCallback(bool connected) +{ + uint32_t i = 0; + + while (i < NELEMENTS(connectionState_cb_list) && connectionState_cb_list[i].callback != NULL) { + connectionState_cb_list[i].callback(connected, connectionState_cb_list[i].context); + i++; + } +} +#else /* PIOS_INCLUDE_FREERTOS */ +void PIOS_USB_RegisterDisconnectionCallback(__attribute__((unused)) void (*disconnectionCB)(void)) +{} +void PIOS_USB_RegisterConnectionStateCallback(__attribute__((unused)) void (*connectionStateCallback)(bool connected, uint32_t context), __attribute__((unused)) uint32_t context) +{} +#endif /* PIOS_INCLUDE_FREERTOS */ + /* * * Provide STM32 USB OTG BSP layer API diff --git a/flight/pios/stm32f4xx/pios_usb_cdc.c b/flight/pios/stm32f4xx/pios_usb_cdc.c index 62349b1d92..c641264440 100644 --- a/flight/pios/stm32f4xx/pios_usb_cdc.c +++ b/flight/pios/stm32f4xx/pios_usb_cdc.c @@ -42,6 +42,8 @@ static void PIOS_USB_CDC_RegisterTxCallback(uint32_t usbcdc_id, pios_com_callbac static void PIOS_USB_CDC_RegisterRxCallback(uint32_t usbcdc_id, pios_com_callback rx_in_cb, uint32_t context); static void PIOS_USB_CDC_RegisterCtrlLineCallback(uint32_t usbcdc_id, pios_com_callback_ctrl_line ctrl_line_cb, uint32_t context); static void PIOS_USB_CDC_RegisterBaudRateCallback(uint32_t usbcdc_id, pios_com_callback_baud_rate baud_rate_cb, uint32_t context); +static void PIOS_USB_CDC_RegisterAvailableCallback(uint32_t usbcdc_id, pios_com_callback_available baud_rate_cb, uint32_t context); +static void PIOS_USB_CDC_ChangeConnectionState(bool connected, uint32_t usbcdc_id); static void PIOS_USB_CDC_TxStart(uint32_t usbcdc_id, uint16_t tx_bytes_avail); static void PIOS_USB_CDC_RxStart(uint32_t usbcdc_id, uint16_t rx_bytes_avail); static uint32_t PIOS_USB_CDC_Available(uint32_t usbcdc_id); @@ -54,6 +56,7 @@ const struct pios_com_driver pios_usb_cdc_com_driver = { .bind_ctrl_line_cb = PIOS_USB_CDC_RegisterCtrlLineCallback, .bind_baud_rate_cb = PIOS_USB_CDC_RegisterBaudRateCallback, .available = PIOS_USB_CDC_Available, + .bind_available_cb = PIOS_USB_CDC_RegisterAvailableCallback, }; enum pios_usb_cdc_dev_magic { @@ -74,6 +77,8 @@ struct pios_usb_cdc_dev { uint32_t ctrl_line_context; pios_com_callback_baud_rate baud_rate_cb; uint32_t baud_rate_context; + pios_com_callback_available available_cb; + uint32_t available_context; bool usb_ctrl_if_enabled; bool usb_data_if_enabled; @@ -205,6 +210,8 @@ int32_t PIOS_USB_CDC_Init(uint32_t *usbcdc_id, const struct pios_usb_cdc_cfg *cf usb_cdc_dev->usb_data_if_enabled = false; PIOS_USBHOOK_RegisterIfOps(cfg->data_if, &usb_cdc_data_ifops, (uint32_t)usb_cdc_dev); + PIOS_USB_RegisterConnectionStateCallback(PIOS_USB_CDC_ChangeConnectionState, (uint32_t)usb_cdc_dev); + *usbcdc_id = (uint32_t)usb_cdc_dev; return 0; @@ -390,7 +397,7 @@ static void PIOS_USB_CDC_CTRL_IF_DeInit(uint32_t usb_cdc_id) } /* DeRegister endpoint specific callbacks with the USBHOOK layer */ - usb_cdc_dev->usb_data_if_enabled = false; + usb_cdc_dev->usb_ctrl_if_enabled = false; } static uint8_t cdc_altset; @@ -472,8 +479,7 @@ static uint32_t PIOS_USB_CDC_Available(uint32_t usbcdc_id) PIOS_Assert(valid); - return (PIOS_USB_CheckAvailable(usb_cdc_dev->lower_id) && - (control_line_state & USB_CDC_CONTROL_LINE_STATE_DTE_PRESENT)) ? COM_AVAILABLE_RXTX : COM_AVAILABLE_NONE; + return PIOS_USB_CheckAvailable(usb_cdc_dev->lower_id) ? COM_AVAILABLE_RXTX : COM_AVAILABLE_NONE; } /** @@ -721,4 +727,34 @@ static bool PIOS_USB_CDC_DATA_EP_OUT_Callback( return rc; } +static void PIOS_USB_CDC_ChangeConnectionState(__attribute__((unused)) bool connected, uint32_t usbcdc_id) +{ + struct pios_usb_cdc_dev *usb_cdc_dev = (struct pios_usb_cdc_dev *)usbcdc_id; + + bool valid = PIOS_USB_CDC_validate(usb_cdc_dev); + + PIOS_Assert(valid); + + if (usb_cdc_dev->available_cb) { + (usb_cdc_dev->available_cb)(usb_cdc_dev->available_context, PIOS_USB_CDC_Available(usbcdc_id)); + } +} + + +static void PIOS_USB_CDC_RegisterAvailableCallback(uint32_t usbcdc_id, pios_com_callback_available available_cb, uint32_t context) +{ + struct pios_usb_cdc_dev *usb_cdc_dev = (struct pios_usb_cdc_dev *)usbcdc_id; + + bool valid = PIOS_USB_CDC_validate(usb_cdc_dev); + + PIOS_Assert(valid); + + /* + * Order is important in these assignments since ISR uses _cb + * field to determine if it's ok to dereference _cb and _context + */ + usb_cdc_dev->available_context = context; + usb_cdc_dev->available_cb = available_cb; +} + #endif /* PIOS_INCLUDE_USB_CDC */ From 68414cf648f7bd2869d52d8bda42b152e42fa17a Mon Sep 17 00:00:00 2001 From: Vladimir Zidar Date: Mon, 10 Oct 2016 00:29:11 +0200 Subject: [PATCH 023/624] LP-431 Get only necessary data from ManualControlSettings to save on stack usage. --- flight/modules/Receiver/receiver.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/flight/modules/Receiver/receiver.c b/flight/modules/Receiver/receiver.c index f98850937a..7c30dd7b1e 100644 --- a/flight/modules/Receiver/receiver.c +++ b/flight/modules/Receiver/receiver.c @@ -660,9 +660,12 @@ static void updateRcvrActivitySample(uint32_t rcvr_id, uint16_t samples[], uint8 static bool updateRcvrActivityCompare(uint32_t rcvr_id, struct rcvr_activity_fsm *fsm) { bool activity_updated = false; - ManualControlSettingsData settings; - ManualControlSettingsGet(&settings); + ManualControlSettingsChannelGroupsData channelGroups; + ManualControlSettingsChannelNumberData channelNumber; + + ManualControlSettingsChannelGroupsGet(&channelGroups); + ManualControlSettingsChannelNumberGet(&channelNumber); /* Compare the current value to the previous sampled value */ for (uint8_t channel = 1; channel <= RCVR_ACTIVITY_MONITOR_CHANNELS_PER_GROUP; channel++) { @@ -677,8 +680,7 @@ static bool updateRcvrActivityCompare(uint32_t rcvr_id, struct rcvr_activity_fsm // Ignore activity from this Group/Channel because already used/set for Rssi input // Without that, the ReceiverActivity will be saturated just with Rssi value activity. - if ((ManualControlSettingsChannelGroupsToArray(settings.ChannelGroups)[MANUALCONTROLSETTINGS_CHANNELGROUPS_RSSI] == fsm->group) && - (ManualControlSettingsChannelNumberToArray(settings.ChannelNumber)[MANUALCONTROLSETTINGS_CHANNELNUMBER_RSSI] == channel)) { + if(channelGroups.Rssi == fsm->group && channelNumber.Rssi == channel) { delta = 0; } From 092079fb513b5dc975e166344511fe32ceac5737 Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Thu, 8 Sep 2016 19:58:47 +0200 Subject: [PATCH 024/624] LP-404 make Makefile more vendor neutral --- Makefile | 39 ++++++++++---------- ground/gcs/src/plugins/uploader/uploader.pro | 7 ++-- 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/Makefile b/Makefile index ff952865c5..318931eb64 100644 --- a/Makefile +++ b/Makefile @@ -50,9 +50,9 @@ export TOOLS_DIR export BUILD_DIR := $(CURDIR)/build export PACKAGE_DIR := $(BUILD_DIR)/package export DIST_DIR := $(BUILD_DIR)/dist -export OPGCSSYNTHDIR := $(BUILD_DIR)/gcs-synthetics +export GCS_SYNTH_DIR := $(BUILD_DIR)/gcs-synthetics -DIRS := $(DL_DIR) $(TOOLS_DIR) $(BUILD_DIR) $(PACKAGE_DIR) $(DIST_DIR) $(OPGCSSYNTHDIR) +DIRS := $(DL_DIR) $(TOOLS_DIR) $(BUILD_DIR) $(PACKAGE_DIR) $(DIST_DIR) $(GCS_SYNTH_DIR) # Naming for binaries and packaging etc,. export ORG_BIG_NAME := LibrePilot @@ -225,9 +225,9 @@ uavobjects_clean: # When building any of the "all_*" targets, tell all sub makefiles to display # additional details on each line of output to describe which build and target -# that each line applies to. The same applies also to all, opfw_resource, +# that each line applies to. The same applies also to all, fw_resource, # package targets -ifneq ($(strip $(filter all_% all opfw_resource package,$(MAKECMDGOALS))),) +ifneq ($(strip $(filter all_% all fw_resource package,$(MAKECMDGOALS))),) export ENABLE_MSG_EXTRA := yes endif @@ -323,38 +323,39 @@ PACKAGE_FW_TARGETS := fw_coptercontrol fw_oplinkmini fw_revolution fw_osd fw_rev # Rules to generate GCS resources used to embed firmware binaries into the GCS. # They are used later by the vehicle setup wizard to update board firmware. # To open a firmware image use ":/firmware/fw_coptercontrol.opfw" -OPFW_RESOURCE := $(OPGCSSYNTHDIR)/opfw_resource.qrc +FW_RESOURCE := $(GCS_SYNTH_DIR)/fw_resource.qrc ifeq ($(WITH_PREBUILT_FW),) FIRMWARE_DIR := $(FLIGHT_OUT_DIR) # We need to build the FW targets -$(OPFW_RESOURCE): $(PACKAGE_FW_TARGETS) +$(FW_RESOURCE): $(PACKAGE_FW_TARGETS) else FIRMWARE_DIR := $(WITH_PREBUILT_FW) endif -OPFW_FILES := $(foreach fw_targ, $(PACKAGE_FW_TARGETS), $(FIRMWARE_DIR)/$(fw_targ)/$(fw_targ).opfw) -OPFW_CONTENTS := \ +FW_FILES := $(foreach fw_targ, $(PACKAGE_FW_TARGETS), $(FIRMWARE_DIR)/$(fw_targ)/$(fw_targ).opfw) +FW_CONTENTS := \ \ \ - $(foreach fw_file, $(OPFW_FILES), $(call system_path,$(fw_file))) \ + $(foreach fw_file, $(FW_FILES), $(call system_path,$(fw_file))) \ \ -.PHONY: opfw_resource -opfw_resource: $(OPFW_RESOURCE) +.PHONY: fw_resource +fw_resource: $(FW_RESOURCE) +fw_resource: $(FW_RESOURCE) -$(OPFW_RESOURCE): | $(OPGCSSYNTHDIR) - @$(ECHO) Generating OPFW resource file $(call toprel, $@) - $(V1) $(ECHO) $(QUOTE)$(OPFW_CONTENTS)$(QUOTE) > $@ +$(FW_RESOURCE): | $(GCS_SYNTH_DIR) + @$(ECHO) Generating FW resource file $(call toprel, $@) + $(V1) $(ECHO) $(QUOTE)$(FW_CONTENTS)$(QUOTE) > $@ -# If opfw_resource or all firmware are requested, GCS should depend on the resource -ifneq ($(strip $(filter opfw_resource all all_fw all_flight package,$(MAKECMDGOALS))),) -$(GCS_MAKEFILE): $(OPFW_RESOURCE) +# If fw_resource or all firmware are requested, GCS should depend on the resource +ifneq ($(strip $(filter fw_resource all all_fw all_flight package,$(MAKECMDGOALS))),) +$(GCS_MAKEFILE): $(FW_RESOURCE) endif # Packaging targets: package -# - builds all firmware, opfw_resource, gcs +# - builds all firmware, fw_resource, gcs # - copies firmware into a package directory # - calls paltform-specific packaging script @@ -712,7 +713,7 @@ help: @$(ECHO) @$(ECHO) " [Packaging]" @$(ECHO) " package - Build and package the platform-dependent package (no clean)" - @$(ECHO) " opfw_resource - Generate resources to embed firmware binaries into the GCS" + @$(ECHO) " fw_resource - Generate resources to embed firmware binaries into the GCS" @$(ECHO) " dist - Generate source archive for distribution" @$(ECHO) " fw_dist - Generate archive of firmware" @$(ECHO) " install - Install GCS to \"DESTDIR\" with prefix \"prefix\" (Linux only)" diff --git a/ground/gcs/src/plugins/uploader/uploader.pro b/ground/gcs/src/plugins/uploader/uploader.pro index 23990f5a28..0d4c97441f 100644 --- a/ground/gcs/src/plugins/uploader/uploader.pro +++ b/ground/gcs/src/plugins/uploader/uploader.pro @@ -63,8 +63,9 @@ FORMS += \ RESOURCES += uploader.qrc -exists( ../../../../../build/gcs-synthetics/opfw_resource.qrc ) { - RESOURCES += ../../../../../build/gcs-synthetics/opfw_resource.qrc +# TODO should use GCS_SYNTH_DIR... but that will break QtCreator +exists( ../../../../../build/gcs-synthetics/fw_resource.qrc ) { + RESOURCES += ../../../../../build/gcs-synthetics/fw_resource.qrc } else { - message("opfw_resource.qrc is not available, automatic firmware upgrades are disabled") + message("fw_resource.qrc is not available, automatic firmware upgrades are disabled") } From 365f0ca3ad503c9850e3ce6a8487f5a307d64ece Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Mon, 10 Oct 2016 18:49:11 +0200 Subject: [PATCH 025/624] LP-430 add description to serial devices display name will show in the Connections drop down --- ground/gcs/src/plugins/serialconnection/serialplugin.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ground/gcs/src/plugins/serialconnection/serialplugin.cpp b/ground/gcs/src/plugins/serialconnection/serialplugin.cpp index dcaed99191..3bc11cc3f8 100644 --- a/ground/gcs/src/plugins/serialconnection/serialplugin.cpp +++ b/ground/gcs/src/plugins/serialconnection/serialplugin.cpp @@ -139,11 +139,16 @@ QList SerialConnection::availableDevices() // sort the list by port number (nice idea from PT_Dreamer :)) qSort(ports.begin(), ports.end(), sortPorts); + foreach(QSerialPortInfo port, ports) { device d; - d.displayName = port.portName(); d.name = port.portName(); + d.displayName = port.portName(); + if (!port.description().isEmpty()) { + d.displayName += " - " + port.description(); + } + list.append(d); } } From 4a6573db1ed6d3c003fc75f3c461a3e43c21ba57 Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Thu, 20 Oct 2016 00:27:30 +0200 Subject: [PATCH 026/624] LP-430 show serial port description as tooltip in connection drop down --- .../plugins/coreplugin/connectionmanager.cpp | 26 ++++++++++++++++++- .../plugins/coreplugin/connectionmanager.h | 12 +++------ .../gcs/src/plugins/coreplugin/iconnection.h | 1 + .../plugins/serialconnection/serialplugin.cpp | 4 +-- 4 files changed, 31 insertions(+), 12 deletions(-) diff --git a/ground/gcs/src/plugins/coreplugin/connectionmanager.cpp b/ground/gcs/src/plugins/coreplugin/connectionmanager.cpp index a225b97e66..1e1cc0410e 100644 --- a/ground/gcs/src/plugins/coreplugin/connectionmanager.cpp +++ b/ground/gcs/src/plugins/coreplugin/connectionmanager.cpp @@ -40,6 +40,30 @@ #include namespace Core { +QString DevListItem::getConName() const +{ + if (connection == NULL) { + return ""; + } + return connection->shortName() + ": " + device.displayName; +} + +QString DevListItem::getConDescription() const +{ + if (connection == NULL) { + return ""; + } + QString description = device.displayName; + if (!device.description.isEmpty()) { + description += " - " + device.description; + } + // truncate description if too long + if (description.length() > 50) { + description = description.left(50) + "..."; + } + return description; +} + ConnectionManager::ConnectionManager(Internal::MainWindow *mainWindow) : QWidget(mainWindow), m_availableDevList(0), @@ -458,7 +482,7 @@ void ConnectionManager::updateConnectionDropdown() // add all the list again to the combobox foreach(DevListItem d, m_devList) { m_availableDevList->addItem(d.getConName()); - m_availableDevList->setItemData(m_availableDevList->count() - 1, d.getConName(), Qt::ToolTipRole); + m_availableDevList->setItemData(m_availableDevList->count() - 1, d.getConDescription(), Qt::ToolTipRole); if (!m_ioDev && d.getConName().startsWith("USB")) { if (m_mainWindow->generalSettings()->autoConnect() || m_mainWindow->generalSettings()->autoSelect()) { m_availableDevList->setCurrentIndex(m_availableDevList->count() - 1); diff --git a/ground/gcs/src/plugins/coreplugin/connectionmanager.h b/ground/gcs/src/plugins/coreplugin/connectionmanager.h index b19cc7c5dc..50a9257a43 100644 --- a/ground/gcs/src/plugins/coreplugin/connectionmanager.h +++ b/ground/gcs/src/plugins/coreplugin/connectionmanager.h @@ -49,20 +49,16 @@ namespace Internal { class MainWindow; } // namespace Internal -class DevListItem { +class CORE_EXPORT DevListItem { public: DevListItem(IConnection *c, IConnection::device d) : connection(c), device(d) {} DevListItem() : connection(NULL) {} - QString getConName() - { - if (connection == NULL) { - return ""; - } - return connection->shortName() + ": " + device.displayName; - } + QString getConName() const; + + QString getConDescription() const; bool operator==(const DevListItem &rhs) { diff --git a/ground/gcs/src/plugins/coreplugin/iconnection.h b/ground/gcs/src/plugins/coreplugin/iconnection.h index a5ebbc17d0..3a1de98f79 100644 --- a/ground/gcs/src/plugins/coreplugin/iconnection.h +++ b/ground/gcs/src/plugins/coreplugin/iconnection.h @@ -50,6 +50,7 @@ class CORE_EXPORT IConnection : public QObject { struct device { QString name; QString displayName; + QString description; bool operator==(device i) { return this->name == i.name; diff --git a/ground/gcs/src/plugins/serialconnection/serialplugin.cpp b/ground/gcs/src/plugins/serialconnection/serialplugin.cpp index 3bc11cc3f8..964ec45e77 100644 --- a/ground/gcs/src/plugins/serialconnection/serialplugin.cpp +++ b/ground/gcs/src/plugins/serialconnection/serialplugin.cpp @@ -145,9 +145,7 @@ QList SerialConnection::availableDevices() d.name = port.portName(); d.displayName = port.portName(); - if (!port.description().isEmpty()) { - d.displayName += " - " + port.description(); - } + d.description = port.description(); list.append(d); } From 105219e7146aa0d43df120ac69ef8e2a20796816 Mon Sep 17 00:00:00 2001 From: Eric Price Date: Tue, 25 Oct 2016 20:44:59 +0200 Subject: [PATCH 027/624] LP-438: fixed connection manager ugly side effects (triggered by LP-430 ) --- .../plugins/coreplugin/connectionmanager.cpp | 31 ++++++++----------- .../plugins/coreplugin/connectionmanager.h | 3 +- .../setupwizard/pages/controllerpage.cpp | 13 +++----- 3 files changed, 20 insertions(+), 27 deletions(-) diff --git a/ground/gcs/src/plugins/coreplugin/connectionmanager.cpp b/ground/gcs/src/plugins/coreplugin/connectionmanager.cpp index 1e1cc0410e..2831835ece 100644 --- a/ground/gcs/src/plugins/coreplugin/connectionmanager.cpp +++ b/ground/gcs/src/plugins/coreplugin/connectionmanager.cpp @@ -130,8 +130,7 @@ void ConnectionManager::addWidget(QWidget *widget) bool ConnectionManager::connectDevice(DevListItem device) { Q_UNUSED(device); - QString deviceName = m_availableDevList->itemData(m_availableDevList->currentIndex(), Qt::ToolTipRole).toString(); - DevListItem connection_device = findDevice(deviceName); + DevListItem connection_device = findDevice(m_availableDevList->currentIndex()); if (!connection_device.connection) { return false; @@ -279,8 +278,7 @@ void ConnectionManager::onConnectClicked() // Check if we have a ioDev already created: if (!m_ioDev) { // connecting to currently selected device - QString deviceName = m_availableDevList->itemData(m_availableDevList->currentIndex(), Qt::ToolTipRole).toString(); - DevListItem device = findDevice(deviceName); + DevListItem device = findDevice(m_availableDevList->currentIndex()); if (device.connection) { connectDevice(device); } @@ -343,15 +341,15 @@ void ConnectionManager::reconnectCheckSlot() /** * Find a device by its displayed (visible on screen) name */ -DevListItem ConnectionManager::findDevice(const QString &devName) +DevListItem ConnectionManager::findDevice(int devNumber) { foreach(DevListItem d, m_devList) { - if (d.getConName() == devName) { + if (d.displayNumber == devNumber) { return d; } } - qDebug() << "findDevice: cannot find " << devName << " in device list"; + qDebug() << "findDevice: cannot find item in device list"; DevListItem d; d.connection = NULL; @@ -480,28 +478,25 @@ void ConnectionManager::devChanged(IConnection *connection) void ConnectionManager::updateConnectionDropdown() { // add all the list again to the combobox - foreach(DevListItem d, m_devList) { - m_availableDevList->addItem(d.getConName()); - m_availableDevList->setItemData(m_availableDevList->count() - 1, d.getConDescription(), Qt::ToolTipRole); - if (!m_ioDev && d.getConName().startsWith("USB")) { + for (QLinkedList::iterator iter = m_devList.begin(); iter != m_devList.end(); ++iter) { + m_availableDevList->addItem(iter->getConName()); + // record position in the box in the device + iter->displayNumber = m_availableDevList->count() - 1; + m_availableDevList->setItemData(m_availableDevList->count() - 1, iter->getConDescription(), Qt::ToolTipRole); + if (!m_ioDev && iter->getConName().startsWith("USB")) { if (m_mainWindow->generalSettings()->autoConnect() || m_mainWindow->generalSettings()->autoSelect()) { m_availableDevList->setCurrentIndex(m_availableDevList->count() - 1); } if (m_mainWindow->generalSettings()->autoConnect() && polling) { qDebug() << "Automatically opening device"; - connectDevice(d); + connectDevice(*iter); qDebug() << "ConnectionManager::updateConnectionDropdown autoconnected USB device"; } } } if (m_ioDev) { // if a device is connected make it the one selected on the dropbox - for (int i = 0; i < m_availableDevList->count(); i++) { - QString deviceName = m_availableDevList->itemData(i, Qt::ToolTipRole).toString(); - if (m_connectionDevice.getConName() == deviceName) { - m_availableDevList->setCurrentIndex(i); - } - } + m_availableDevList->setCurrentIndex(m_connectionDevice.displayNumber); } // update combo box tooltip onDeviceSelectionChanged(m_availableDevList->currentIndex()); diff --git a/ground/gcs/src/plugins/coreplugin/connectionmanager.h b/ground/gcs/src/plugins/coreplugin/connectionmanager.h index 50a9257a43..f46af6a313 100644 --- a/ground/gcs/src/plugins/coreplugin/connectionmanager.h +++ b/ground/gcs/src/plugins/coreplugin/connectionmanager.h @@ -65,6 +65,7 @@ class CORE_EXPORT DevListItem { return connection == rhs.connection && device == rhs.device; } + int displayNumber = -1; IConnection *connection; IConnection::device device; }; @@ -83,7 +84,7 @@ class CORE_EXPORT ConnectionManager : public QWidget { { return m_connectionDevice; } - DevListItem findDevice(const QString &devName); + DevListItem findDevice(int devNumber); QLinkedList getAvailableDevices() { diff --git a/ground/gcs/src/plugins/setupwizard/pages/controllerpage.cpp b/ground/gcs/src/plugins/setupwizard/pages/controllerpage.cpp index 2235220b48..f84833e96c 100644 --- a/ground/gcs/src/plugins/setupwizard/pages/controllerpage.cpp +++ b/ground/gcs/src/plugins/setupwizard/pages/controllerpage.cpp @@ -170,8 +170,11 @@ void ControllerPage::devicesChanged(QLinkedList devices) // Loop and fill the combo with items from connectionmanager foreach(Core::DevListItem deviceItem, devices) { ui->deviceCombo->addItem(deviceItem.getConName()); + // TODO - have tooltips similar to how connection manager does QString deviceName = (const QString)deviceItem.getConName(); ui->deviceCombo->setItemData(ui->deviceCombo->count() - 1, deviceName, Qt::ToolTipRole); + // we fill a combobox with items in the same order as the connectionmanager, so they should have the same numerical ids. if not, things break. + Q_ASSERT(ui->deviceCombo->count() - 1 == deviceItem.displayNumber); if (!deviceName.startsWith("USB:", Qt::CaseInsensitive)) { ui->deviceCombo->setItemData(ui->deviceCombo->count() - 1, QVariant(0), Qt::UserRole - 1); } @@ -194,13 +197,7 @@ void ControllerPage::connectionStatusChanged() ui->deviceCombo->setEnabled(false); ui->connectButton->setText(tr("Disconnect")); ui->boardTypeCombo->setEnabled(false); - QString connectedDeviceName = m_connectionManager->getCurrentDevice().getConName(); - for (int i = 0; i < ui->deviceCombo->count(); ++i) { - if (connectedDeviceName == ui->deviceCombo->itemData(i, Qt::ToolTipRole).toString()) { - ui->deviceCombo->setCurrentIndex(i); - break; - } - } + ui->deviceCombo->setCurrentIndex(m_connectionManager->getCurrentDevice().displayNumber); SetupWizard::CONTROLLER_TYPE type = getControllerType(); setControllerType(type); @@ -256,7 +253,7 @@ void ControllerPage::connectDisconnect() if (m_connectionManager->isConnected()) { m_connectionManager->disconnectDevice(); } else { - m_connectionManager->connectDevice(m_connectionManager->findDevice(ui->deviceCombo->itemData(ui->deviceCombo->currentIndex(), Qt::ToolTipRole).toString())); + m_connectionManager->connectDevice(m_connectionManager->findDevice(ui->deviceCombo->currentIndex())); } emit completeChanged(); } From 5f89daf426fce95298f5ed607900a5b238bffa38 Mon Sep 17 00:00:00 2001 From: karstentellingnielsen Date: Sat, 29 Oct 2016 15:17:22 +0200 Subject: [PATCH 028/624] LP-442 Update Vagrant files for latest build in order to have a reproducible dev environment. Android build on virtual machine is not verified. --- .../vagrant/vagrant_openpilot_dev/Vagrantfile | 68 +++++++++---------- .../vagrant_openpilot_dev/bootstrap.sh | 6 +- .../vagrant_openpilot_dev/install-tools.sh | 35 +++++++--- 3 files changed, 62 insertions(+), 47 deletions(-) diff --git a/make/vagrant/vagrant_openpilot_dev/Vagrantfile b/make/vagrant/vagrant_openpilot_dev/Vagrantfile index e15a311cb0..7ebe153654 100644 --- a/make/vagrant/vagrant_openpilot_dev/Vagrantfile +++ b/make/vagrant/vagrant_openpilot_dev/Vagrantfile @@ -1,35 +1,33 @@ -# -*- mode: ruby -*- -# vi: set ft=ruby : - -VAGRANTFILE_API_VERSION = "2" - -Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| - - config.vm.box = "ubuntu/trusty64" - #config.vm.box = "jhartman/xubuntu14.04.1" - - config.vm.provider "virtualbox" do |vb| - vb.gui = true - vb.customize ["modifyvm", :id, "--memory", "4096"] - end - - #config.vm.synced_folder "../../projects", "/home/vagrant/projects" - - config.vm.provision :shell, :path => "bootstrap.sh" - - config.ssh.forward_x11=true - - # update definitions - config.vm.provision "shell", inline: "apt-get update" - - # just the basic desktop environment. if you want the addons, you can install them later - config.vm.provision "shell", inline: "apt-get install xubuntu-desktop --no-install-recommends --assume-yes" - - # otherwise icons don't get loaded - config.vm.provision "shell", inline: "apt-get install xubuntu-icon-theme --assume-yes" - - #activate logon with gui and reboot - config.vm.provision "shell", inline: "dpkg-reconfigure lightdm" - config.vm.provision "shell", inline: "reboot" - -end +# -*- mode: ruby -*- +# vi: set ft=ruby : + +VAGRANTFILE_API_VERSION = "2" + +Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| + + config.vm.box = "ubuntu/trusty64" + + config.vm.provider "virtualbox" do |vb| + # GUI can be enabled after provisioning. For now SSH and GUI is not compatible + # vb.gui = true + vb.customize ["modifyvm", :id, "--memory", "4096"] + end + + config.vm.provision :shell, :path => "bootstrap.sh" + + config.ssh.forward_x11=true + + # update definitions + config.vm.provision "shell", inline: "apt-get update" + + # just the basic desktop environment. if you want the addons, you can install them later + config.vm.provision "shell", inline: "apt-get install xubuntu-desktop --no-install-recommends --assume-yes" + + # otherwise icons don't get loaded + config.vm.provision "shell", inline: "apt-get install xubuntu-icon-theme --assume-yes" + + #activate logon with gui and reboot + config.vm.provision "shell", inline: "dpkg-reconfigure lightdm" + config.vm.provision "shell", inline: "reboot" + +end \ No newline at end of file diff --git a/make/vagrant/vagrant_openpilot_dev/bootstrap.sh b/make/vagrant/vagrant_openpilot_dev/bootstrap.sh index 57e1d21a3c..b6ed000581 100644 --- a/make/vagrant/vagrant_openpilot_dev/bootstrap.sh +++ b/make/vagrant/vagrant_openpilot_dev/bootstrap.sh @@ -1,10 +1,10 @@ #!/usr/bin/env bash -apt-get update -apt-get -y upgrade +sudo apt-get update +sudo apt-get --yes --force-yes upgrade # get ourselves some basic toys -apt-get -y install git-core build-essential openssl libssl-dev +sudo apt-get --yes --force-yes install git-core build-essential openssl libssl-dev # install some tools for the vagrant user only by executing # a script AS the vagrant user diff --git a/make/vagrant/vagrant_openpilot_dev/install-tools.sh b/make/vagrant/vagrant_openpilot_dev/install-tools.sh index be9c4f5459..cffbe3f216 100644 --- a/make/vagrant/vagrant_openpilot_dev/install-tools.sh +++ b/make/vagrant/vagrant_openpilot_dev/install-tools.sh @@ -1,5 +1,9 @@ #!/usr/bin/env bash +echo " +Setup a build environment +" + ANDROID_ENV=true ANDROID_STUDIO_VERSION=1.1.0 ANDROID_STUDIO_BUILD=135.1740770 @@ -11,10 +15,14 @@ ANDROID_SDK_URL=http://dl.google.com/android/${ANDROID_SDK_FILE} ANDROID_API_LEVELS=android-20,android-21,android-22 ANDROID_BUILD_TOOLS_VERSION=21.1.2 -sudo apt-get -y install curl build-essential gdb wget \ -debhelper p7zip-full unzip flex bison libsdl1.2-dev libudev-dev libusb-1.0-0-dev libc6-i386 +# Setup a build environment +sudo add-apt-repository --yes ppa:librepilot/tools +sudo apt-get --yes --force-yes update +sudo apt-get --yes --force-yes install build-essential ccache debhelper git-core git-doc flex graphviz bison libudev-dev libusb-1.0-0-dev libsdl1.2-dev python libopenscenegraph-dev qt56-meta-minimal qt56svg qt56script qt56serialport qt56multimedia qt56translations qt56tools qt56quickcontrols libosgearth-dev openscenegraph-plugin-osgearth +sudo apt-get --yes --force-yes install libc6-i386 +# Do Android stuff if [ "$ANDROID_ENV" = "true" ]; then # install java7 @@ -25,7 +33,7 @@ if [ "$ANDROID_ENV" = "true" ]; then # accept the license agreement echo oracle-java7-installer shared/accepted-oracle-license-v1-1 select true | sudo /usr/bin/debconf-set-selections - sudo apt-get -y install oracle-java7-installer + sudo apt-get --yes --force-yes install oracle-java7-installer # make a place to install development tools mkdir -p ~/workspace/tools @@ -63,12 +71,21 @@ if [ "$ANDROID_ENV" = "true" ]; then fi +# Checkout code +mkdir -p ~/workspace/ +cd ~/workspace/ +git clone https://bitbucket.org/librepilot/librepilot.git +cd librepilot +git checkout next + +# The build_sdk_install do not install the ARM build correctly. Add this line for now +# sudo apt --yes --force-yes install gcc-arm-none-eabi +sudo apt-get --yes --force-yes remove gcc-arm-none-eabi + +# Dev Tools Installation +make build_sdk_install -mkdir -p ~/workspace/openpilot -cd ~/workspace/openpilot -git clone git://git.openpilot.org/OpenPilot.git -cd OpenPilot -git checkout -b next origin/next -git pull +# Done +echo Ready to go From c09107b58378b56759028c64df2111fc9cb98afd Mon Sep 17 00:00:00 2001 From: karstentellingnielsen Date: Mon, 31 Oct 2016 20:41:50 +0100 Subject: [PATCH 029/624] LP-442 Android not part of the build be default. Redundant command deleted --- make/vagrant/vagrant_openpilot_dev/install-tools.sh | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/make/vagrant/vagrant_openpilot_dev/install-tools.sh b/make/vagrant/vagrant_openpilot_dev/install-tools.sh index cffbe3f216..319a79a0d9 100644 --- a/make/vagrant/vagrant_openpilot_dev/install-tools.sh +++ b/make/vagrant/vagrant_openpilot_dev/install-tools.sh @@ -4,7 +4,7 @@ echo " Setup a build environment " -ANDROID_ENV=true +ANDROID_ENV=false ANDROID_STUDIO_VERSION=1.1.0 ANDROID_STUDIO_BUILD=135.1740770 ANDROID_STUDIO_FILE=android-studio-ide-$ANDROID_STUDIO_BUILD-linux.zip @@ -78,14 +78,5 @@ git clone https://bitbucket.org/librepilot/librepilot.git cd librepilot git checkout next -# The build_sdk_install do not install the ARM build correctly. Add this line for now -# sudo apt --yes --force-yes install gcc-arm-none-eabi -sudo apt-get --yes --force-yes remove gcc-arm-none-eabi - # Dev Tools Installation make build_sdk_install - -# Done -echo Ready to go - - From 0e0120fedb3a1cf852f6d86e8211a950638f9f68 Mon Sep 17 00:00:00 2001 From: karstentellingnielsen Date: Mon, 31 Oct 2016 20:42:15 +0100 Subject: [PATCH 030/624] LP-442 Updated with links to LibrePilot --- make/vagrant/vagrant_openpilot_dev/README | 25 ++++++++++++++--------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/make/vagrant/vagrant_openpilot_dev/README b/make/vagrant/vagrant_openpilot_dev/README index f7d1154a32..8e20eba3b9 100644 --- a/make/vagrant/vagrant_openpilot_dev/README +++ b/make/vagrant/vagrant_openpilot_dev/README @@ -1,35 +1,40 @@ -vagrant_openpilot_dev - provides a Vagrant box with everything needed to compile OpenPilot code base. +vagrant_openpilot_dev - provides a Vagrant box with everything needed to compile LibrePilot code base. username: vagrant password: vagrant -For details of an OpenPilot development environment please refer to the Development Manual https://wiki.openpilot.org/display/WIKI/OpenPilot+Developer+Manual. +For details of an LibrePilot development environment please refer to the Development Manual https://librepilot.atlassian.net/wiki/display/LPDOC/Linux+-+Building+and+Packaging. To enable Android Studio and Java, edit file install-tools.sh and set ANDROID_ENV=true. You might also want to adjust for the versions it downloads. -If you would like for VirtualBox window to open, this can be useful for running apps, set 'vb.gui = true' in Vagrantfile. +If you would like for VirtualBox window to open, this can be useful for running apps, set 'vb.gui = true' in Vagrant file. For now the vagrant shell (ssh) will not work when starting in GUI mode. -Starting +Setting up +1) Install vagrant on your host (https://www.vagrantup.com/docs/installation/) +2) Download the files in this folder to a working folder on your host. There is no need to retrieve the full repository. +3) in a command line select the working folder +4) Run the command $ vagrant up Once your machine has started up you can ssh into it or log into Xfce (assuming you set vb.gui = true). Any changes you make persist in the Vagrant VM, when you are done run 'vagrant halt', this will turn off the vm and persist your changes. $ vagrant ssh -To begin with Openpilot base source is checked out into ~/workspace/openpilot/OpenPilot. Run the following command to get the rest of the tools in place (this will take a bit of time): - make all_sdk_install -You are now ready to browse the code. +To begin with LibrePilot base source is checked out into ~/workspace/librepilot. All necessary modules are initialized and SDK's installed. + +You are now ready to browse the code. To build the code run the commands: +$ cd ~/workspace/librepilot +$ make all If you wish to start all over: $ vagrant halt $ vagrant destroy -For more information about OpenPilot please visit the forums at http://forums.openpilot.org. +For more information about LibrePilot please visit the forums at https://forum.librepilot.org/. -For more informatin about Vagrant please visit http://docs.vagrantup.com/. +For more information about Vagrant please visit https://www.vagrantup.com/. Based off https://github.com/steveliles/vagrant-boxes/blob/master/debian-android-studio/install-tools.sh - From e7eda529f89b252e1d6808b312743cb504c08237 Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Wed, 12 Oct 2016 22:00:56 +0200 Subject: [PATCH 031/624] LP-434 uavobjectbrowser: expand less when filtering --- .../uavobjectbrowserwidget.cpp | 21 ++++++++----------- .../uavobjectbrowser/uavobjectbrowserwidget.h | 2 -- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowserwidget.cpp b/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowserwidget.cpp index bd6d6ee909..cdca774c91 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowserwidget.cpp +++ b/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowserwidget.cpp @@ -27,22 +27,19 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "uavobjectbrowserwidget.h" + +#include "ui_uavobjectbrowser.h" +#include "ui_viewoptions.h" + #include "uavobjecttreemodel.h" #include "browseritemdelegate.h" #include "treeitem.h" -#include "ui_uavobjectbrowser.h" -#include "ui_viewoptions.h" #include "uavobjectmanager.h" -#include -#include -#include -#include -#include -#include -#include #include "extensionsystem/pluginmanager.h" #include "utils/mustache.h" +#include + UAVObjectBrowserWidget::UAVObjectBrowserWidget(QWidget *parent) : QWidget(parent) { m_viewoptionsDialog = new QDialog(this); @@ -403,14 +400,14 @@ void UAVObjectBrowserWidget::updateDescription() } /** - * @brief UAVObjectBrowserWidget::searchTextChanged Looks for matching text in the UAVO fields + * @brief UAVObjectBrowserWidget::searchLineChanged Looks for matching text in the UAVO fields */ - void UAVObjectBrowserWidget::searchLineChanged(QString searchText) { m_modelProxy->setFilterRegExp(QRegExp(searchText, Qt::CaseInsensitive, QRegExp::FixedString)); if (!searchText.isEmpty()) { - m_browser->treeView->expandAll(); + int depth = m_viewoptions->cbCategorized->isChecked() ? 2 : 1; + m_browser->treeView->expandToDepth(depth); } else { m_browser->treeView->collapseAll(); } diff --git a/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowserwidget.h b/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowserwidget.h index 5ddc5c0a17..d5d536dd71 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowserwidget.h +++ b/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowserwidget.h @@ -35,8 +35,6 @@ #include "objectpersistence.h" #include -#include -#include #include class QPushButton; From 6764b476ca5be0fba39048df7e9945949c21d55d Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Thu, 15 Dec 2016 21:46:21 +0100 Subject: [PATCH 032/624] fix msys2 osgearth dependencies --- ground/gcs/src/libs/osgearth/copydata.pro | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ground/gcs/src/libs/osgearth/copydata.pro b/ground/gcs/src/libs/osgearth/copydata.pro index 2c7b10c8bb..c263520f54 100644 --- a/ground/gcs/src/libs/osgearth/copydata.pro +++ b/ground/gcs/src/libs/osgearth/copydata.pro @@ -56,8 +56,8 @@ osg:win32 { libp11-kit-0.dll \ libffi-6.dll \ libtasn1-6.dll \ - libhogweed-4-2.dll \ - libnettle-6-2.dll \ + libhogweed-4.dll \ + libnettle-6.dll \ libssh2-1.dll \ libnghttp2-14.dll From d21e8803451b70e939e8184949ce1801abfb87c9 Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Thu, 15 Dec 2016 22:44:43 +0100 Subject: [PATCH 033/624] uncrustify --- flight/modules/CameraControl/inc/cameracontrol.h | 1 - flight/modules/Receiver/receiver.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/flight/modules/CameraControl/inc/cameracontrol.h b/flight/modules/CameraControl/inc/cameracontrol.h index c3d61f0cca..50fe3e9e2e 100644 --- a/flight/modules/CameraControl/inc/cameracontrol.h +++ b/flight/modules/CameraControl/inc/cameracontrol.h @@ -32,5 +32,4 @@ #define FLIGHT_MODULES_CAMERACONTROL_INC_CAMERACONTROL_H - #endif /* FLIGHT_MODULES_CAMERACONTROL_INC_CAMERACONTROL_H */ diff --git a/flight/modules/Receiver/receiver.c b/flight/modules/Receiver/receiver.c index 7c30dd7b1e..6bfc46d36f 100644 --- a/flight/modules/Receiver/receiver.c +++ b/flight/modules/Receiver/receiver.c @@ -680,7 +680,7 @@ static bool updateRcvrActivityCompare(uint32_t rcvr_id, struct rcvr_activity_fsm // Ignore activity from this Group/Channel because already used/set for Rssi input // Without that, the ReceiverActivity will be saturated just with Rssi value activity. - if(channelGroups.Rssi == fsm->group && channelNumber.Rssi == channel) { + if (channelGroups.Rssi == fsm->group && channelNumber.Rssi == channel) { delta = 0; } From 58e15feb08656840cd8e737b81662e23d77373f2 Mon Sep 17 00:00:00 2001 From: Jan NIJS Date: Sat, 17 Dec 2016 00:01:55 +0100 Subject: [PATCH 034/624] LP-452 Support the Galileo GNSS on U-blox NEO M8N receiver. The receiver needs to run firmware 3.01 for Galileo to be supported. Firmware 3.01 supports up to 3 simultaneous constellations. By default only GPS and Glonass are enabled. This commit updates the GCS to display the Galileo constellation in a separate color. --- .../gpsdisplay/gpsconstellationwidget.cpp | 16 +++- .../plugins/gpsdisplay/gpsdisplaywidget.ui | 2 +- .../src/plugins/gpsdisplay/gpssnrwidget.cpp | 11 ++- .../plugins/gpsdisplay/images/gpsEarth.svg | 93 ++++++++++++++++++- 4 files changed, 116 insertions(+), 6 deletions(-) diff --git a/ground/gcs/src/plugins/gpsdisplay/gpsconstellationwidget.cpp b/ground/gcs/src/plugins/gpsdisplay/gpsconstellationwidget.cpp index 9fde211c02..2a9df02350 100644 --- a/ground/gcs/src/plugins/gpsdisplay/gpsconstellationwidget.cpp +++ b/ground/gcs/src/plugins/gpsdisplay/gpsconstellationwidget.cpp @@ -118,7 +118,7 @@ void GpsConstellationWidget::updateSat(int index, int prn, int elevation, int az } // TODO: add range checking - satellites[index][0] = prn; + satellites[index][0] = prn; // UBX SVID satellites[index][1] = elevation; satellites[index][2] = azimuth; satellites[index][3] = snr; @@ -129,7 +129,13 @@ void GpsConstellationWidget::updateSat(int index, int prn, int elevation, int az -satIcons[index]->boundingRect().center().y()); satIcons[index]->setTransform(QTransform::fromTranslate(opd.x(), opd.y()), false); - // Show normal GPS, SBAS/QZSS (120-158,193-197 range), BeiDou (33-64, 159-163) or GLONASS (65-96, 255 if unidentified) + // Show satellite constellations in a separate color + // The UBX SVID numbers are defined in appendix A of u-blox8-M8_ReceiverDescrProtSpec_(UBX-13003221)_Public.pdf + // GPS = default + // SBAS 120-158, QZSS 193-197 + // BeiDou 33-64, 159-163 + // GLONASS 65-96, 255 if unidentified + // Galileo 211-246 if ((prn > 119 && prn < 159) || (prn > 192 && prn < 198)) { if (snr) { satIcons[index]->setElementId("satellite-sbas"); @@ -148,6 +154,12 @@ void GpsConstellationWidget::updateSat(int index, int prn, int elevation, int az } else { satIcons[index]->setElementId("sat-beidou-notSeen"); } + } else if (prn > 210 && prn < 247) { + if (snr) { + satIcons[index]->setElementId("satellite-galileo"); + } else { + satIcons[index]->setElementId("sat-galileo-notSeen"); + } } else { if (snr) { satIcons[index]->setElementId("satellite"); diff --git a/ground/gcs/src/plugins/gpsdisplay/gpsdisplaywidget.ui b/ground/gcs/src/plugins/gpsdisplay/gpsdisplaywidget.ui index f0edd26d85..6af532b91c 100644 --- a/ground/gcs/src/plugins/gpsdisplay/gpsdisplaywidget.ui +++ b/ground/gcs/src/plugins/gpsdisplay/gpsdisplaywidget.ui @@ -127,7 +127,7 @@ - <html><head/><body><p>Displays the SNR for each detected sat. GPS satellites are shown in green, GLONASS in cyan, BeiDou in red and SBAS/QZSS in orange. Satellite number (PRN) is displayed inside the bar. Sat SNR is displayed above (in dBHz)</p></body></html> + <html><head/><body><p>Displays the SNR for each detected sat. GPS satellites are shown in green, GLONASS in cyan, BeiDou in red, Galileo in magenta and SBAS/QZSS in orange. Satellite number (PRN) is displayed inside the bar. Sat SNR is displayed above (in dBHz)</p></body></html> false diff --git a/ground/gcs/src/plugins/gpsdisplay/gpssnrwidget.cpp b/ground/gcs/src/plugins/gpsdisplay/gpssnrwidget.cpp index 5e965b46f1..23a8c4275a 100644 --- a/ground/gcs/src/plugins/gpsdisplay/gpssnrwidget.cpp +++ b/ground/gcs/src/plugins/gpsdisplay/gpssnrwidget.cpp @@ -104,14 +104,21 @@ void GpsSnrWidget::drawSat(int index) QRectF boxRect = boxes[index]->boundingRect(); - // Change color for SBAS & QZSS 120-158, 193-197 range - // GLONASS range 65-96 or 255, BeiDou 33-64 or 159-163 + // Show satellite constellations in a separate color + // The UBX SVID numbers are defined in appendix A of u-blox8-M8_ReceiverDescrProtSpec_(UBX-13003221)_Public.pdf + // GPS = default + // SBAS 120-158, QZSS 193-197 + // BeiDou 33-64, 159-163 + // GLONASS 65-96, 255 if unidentified + // Galileo 211-246 if ((prn > 119 && prn < 159) || (prn > 192 && prn < 198)) { boxes[index]->setBrush(QColor("#fd700b")); } else if ((prn > 64 && prn < 97) || 255 == prn) { boxes[index]->setBrush(QColor("Cyan")); } else if ((prn > 32 && prn < 65) || (prn > 158 && prn < 164)) { boxes[index]->setBrush(QColor("Red")); + } else if (prn > 210 && prn < 247) { + boxes[index]->setBrush(QColor("#e162f3")); } else { boxes[index]->setBrush(QColor("Green")); } diff --git a/ground/gcs/src/plugins/gpsdisplay/images/gpsEarth.svg b/ground/gcs/src/plugins/gpsdisplay/images/gpsEarth.svg index a1a9df773e..200160fb1b 100644 --- a/ground/gcs/src/plugins/gpsdisplay/images/gpsEarth.svg +++ b/ground/gcs/src/plugins/gpsdisplay/images/gpsEarth.svg @@ -14,10 +14,21 @@ height="691.54303" id="svg2" version="1.1" - inkscape:version="0.48.4 r9939" + inkscape:version="0.91 r13725" sodipodi:docname="gpsEarth.svg"> + + + + @@ -1003,6 +1014,46 @@ fx="559.92383" fy="182.67093" r="21.496641" /> + + + + + + + + + + + + + + From e5ca71052a80321590b14090b856f84344759054 Mon Sep 17 00:00:00 2001 From: Jan NIJS Date: Sat, 17 Dec 2016 00:04:44 +0100 Subject: [PATCH 035/624] LP-452 Added Galileo as a GNSS configuration option to the GCS. System -> Settings -> GPSSettings -> UbxGNSSMode The options GPS+Galileo and GPS+GLONASS+Galileo have been added. Also corrected PRN mask for EGNOS SBAS information. Active PRN: 120 & 136 , 123 Ref: https://egnos-user-support.essp-sas.eu/new_egnos_ops/index.php --- flight/modules/GPS/GPS.c | 18 ++++++++++++++++++ flight/modules/GPS/inc/UBX.h | 5 +++-- flight/modules/GPS/inc/ubx_autoconfig.h | 1 + flight/modules/GPS/ubx_autoconfig.c | 7 +++++++ shared/uavobjectdefinition/gpssettings.xml | 2 +- 5 files changed, 30 insertions(+), 3 deletions(-) diff --git a/flight/modules/GPS/GPS.c b/flight/modules/GPS/GPS.c index 305fb7148f..dfc2ac2c6a 100644 --- a/flight/modules/GPS/GPS.c +++ b/flight/modules/GPS/GPS.c @@ -727,31 +727,49 @@ void updateGpsSettings(__attribute__((unused)) UAVObjEvent *ev) newconfig.enableGPS = true; newconfig.enableGLONASS = true; newconfig.enableBeiDou = false; + newconfig.enableGalileo = false; break; case GPSSETTINGS_UBXGNSSMODE_GLONASS: newconfig.enableGPS = false; newconfig.enableGLONASS = true; newconfig.enableBeiDou = false; + newconfig.enableGalileo = false; break; case GPSSETTINGS_UBXGNSSMODE_GPS: newconfig.enableGPS = true; newconfig.enableGLONASS = false; newconfig.enableBeiDou = false; + newconfig.enableGalileo = false; break; case GPSSETTINGS_UBXGNSSMODE_GPSBEIDOU: newconfig.enableGPS = true; newconfig.enableGLONASS = false; newconfig.enableBeiDou = true; + newconfig.enableGalileo = false; break; case GPSSETTINGS_UBXGNSSMODE_GLONASSBEIDOU: newconfig.enableGPS = false; newconfig.enableGLONASS = true; newconfig.enableBeiDou = true; + newconfig.enableGalileo = false; + break; + case GPSSETTINGS_UBXGNSSMODE_GPSGALILEO: + newconfig.enableGPS = true; + newconfig.enableGLONASS = false; + newconfig.enableBeiDou = false; + newconfig.enableGalileo = true; + break; + case GPSSETTINGS_UBXGNSSMODE_GPSGLONASSGALILEO: + newconfig.enableGPS = true; + newconfig.enableGLONASS = true; + newconfig.enableBeiDou = false; + newconfig.enableGalileo = true; break; default: newconfig.enableGPS = false; newconfig.enableGLONASS = false; newconfig.enableBeiDou = false; + newconfig.enableGalileo = false; break; } diff --git a/flight/modules/GPS/inc/UBX.h b/flight/modules/GPS/inc/UBX.h index 4615a4a155..f622ea87a0 100644 --- a/flight/modules/GPS/inc/UBX.h +++ b/flight/modules/GPS/inc/UBX.h @@ -460,8 +460,8 @@ struct UBX_CFG_CFG { // ------------------------------------10987654321098765432109876543210 // WAAS 122, 133, 134, 135, 138---------|---------|---------|---------| #define UBX_CFG_SBAS_SCANMODE1_WAAS 0b00000000000001001110000000000100 -// EGNOS 120, 124, 126, 131-------------|---------|---------|---------| -#define UBX_CFG_SBAS_SCANMODE1_EGNOS 0b00000000000000000000100001010001 +// EGNOS 120, 123, 136------------------|---------|---------|---------| +#define UBX_CFG_SBAS_SCANMODE1_EGNOS 0b00000000000000010000000000001001 // MSAS 129, 137------------------------|---------|---------|---------| #define UBX_CFG_SBAS_SCANMODE1_MSAS 0b00000000000000100000001000000000 // GAGAN 127, 128-----------------------|---------|---------|---------| @@ -485,6 +485,7 @@ struct UBX_CFG_SBAS { #define UBX_CFG_GNSS_FLAGS_QZSS_L1CA 0x010000 #define UBX_CFG_GNSS_FLAGS_QZSS_L1SAIF 0x040000 #define UBX_CFG_GNSS_FLAGS_GLONASS_L1OF 0x010000 +#define UBX_CFG_GNSS_FLAGS_GALILEO_E1 0x010000 #define UBX_CFG_GNSS_NUMCH_VER7 22 #define UBX_CFG_GNSS_NUMCH_VER8 32 diff --git a/flight/modules/GPS/inc/ubx_autoconfig.h b/flight/modules/GPS/inc/ubx_autoconfig.h index 8578f1d6b0..44045840c0 100644 --- a/flight/modules/GPS/inc/ubx_autoconfig.h +++ b/flight/modules/GPS/inc/ubx_autoconfig.h @@ -102,6 +102,7 @@ typedef struct { bool enableGPS; bool enableGLONASS; bool enableBeiDou; + bool enableGalileo; } ubx_autoconfig_settings_t; // Sent messages for configuration support diff --git a/flight/modules/GPS/ubx_autoconfig.c b/flight/modules/GPS/ubx_autoconfig.c index 9cfb079d33..e4be2cda80 100644 --- a/flight/modules/GPS/ubx_autoconfig.c +++ b/flight/modules/GPS/ubx_autoconfig.c @@ -397,6 +397,13 @@ static void config_gnss(uint16_t *bytes_to_send) status->working_packet.message.payload.cfg_gnss.cfgBlocks[i].resTrkCh = 8; } break; + case UBX_GNSS_ID_GALILEO: + if (status->currentSettings.enableGalileo) { + status->working_packet.message.payload.cfg_gnss.cfgBlocks[i].flags = UBX_CFG_GNSS_FLAGS_ENABLED | UBX_CFG_GNSS_FLAGS_GALILEO_E1; + status->working_packet.message.payload.cfg_gnss.cfgBlocks[i].maxTrkCh = 10; + status->working_packet.message.payload.cfg_gnss.cfgBlocks[i].resTrkCh = 8; + } + break; default: break; } diff --git a/shared/uavobjectdefinition/gpssettings.xml b/shared/uavobjectdefinition/gpssettings.xml index 0e0be02c91..c5b28c3dc8 100644 --- a/shared/uavobjectdefinition/gpssettings.xml +++ b/shared/uavobjectdefinition/gpssettings.xml @@ -18,7 +18,7 @@ - + From 16acc9a736b9b65d1ca232e6111bbd3c71718f3b Mon Sep 17 00:00:00 2001 From: Jan NIJS Date: Sat, 17 Dec 2016 20:58:25 +0100 Subject: [PATCH 036/624] LP-452 Enhancement from review by Philippe Renon: describe colors in the code. Custom values are used instead of the QColor pre-defined colors to increase contrast against the text. --- ground/gcs/src/plugins/gpsdisplay/gpssnrwidget.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ground/gcs/src/plugins/gpsdisplay/gpssnrwidget.cpp b/ground/gcs/src/plugins/gpsdisplay/gpssnrwidget.cpp index 23a8c4275a..22971b6945 100644 --- a/ground/gcs/src/plugins/gpsdisplay/gpssnrwidget.cpp +++ b/ground/gcs/src/plugins/gpsdisplay/gpssnrwidget.cpp @@ -112,13 +112,13 @@ void GpsSnrWidget::drawSat(int index) // GLONASS 65-96, 255 if unidentified // Galileo 211-246 if ((prn > 119 && prn < 159) || (prn > 192 && prn < 198)) { - boxes[index]->setBrush(QColor("#fd700b")); + boxes[index]->setBrush(QColor("#fd700b")); // orange } else if ((prn > 64 && prn < 97) || 255 == prn) { boxes[index]->setBrush(QColor("Cyan")); } else if ((prn > 32 && prn < 65) || (prn > 158 && prn < 164)) { boxes[index]->setBrush(QColor("Red")); } else if (prn > 210 && prn < 247) { - boxes[index]->setBrush(QColor("#e162f3")); + boxes[index]->setBrush(QColor("#e162f3")); // magenta } else { boxes[index]->setBrush(QColor("Green")); } From f332d48e9b57af017ed0e7ec3c6ab6c5b520a428 Mon Sep 17 00:00:00 2001 From: Laurent Lalanne Date: Wed, 28 Sep 2016 00:02:35 +0200 Subject: [PATCH 037/624] LP-345 RFM22: Add frequency band selection. 433, 868 and 915Mhz band --- flight/pios/common/pios_rfm22b.c | 94 +++++++++++-------- flight/pios/inc/pios_rfm22b.h | 2 +- flight/pios/inc/pios_rfm22b_priv.h | 3 + .../discoveryf4bare/firmware/pios_board.c | 2 +- .../boards/oplinkmini/firmware/pios_board.c | 2 +- .../boards/revolution/firmware/pios_board.c | 2 +- .../boards/sparky2/firmware/pios_board.c | 2 +- shared/uavobjectdefinition/oplinksettings.xml | 7 +- 8 files changed, 66 insertions(+), 48 deletions(-) diff --git a/flight/pios/common/pios_rfm22b.c b/flight/pios/common/pios_rfm22b.c index 1bc83015a0..4d4a9aa461 100644 --- a/flight/pios/common/pios_rfm22b.c +++ b/flight/pios/common/pios_rfm22b.c @@ -66,54 +66,56 @@ #include /* Local Defines */ -#define STACK_SIZE_BYTES 200 -#define TASK_PRIORITY (tskIDLE_PRIORITY + 4) // flight control relevant device driver (ppm link) -#define ISR_TIMEOUT 1 // ms -#define EVENT_QUEUE_SIZE 5 -#define RFM22B_DEFAULT_RX_DATARATE RFM22_datarate_9600 -#define RFM22B_DEFAULT_TX_POWER RFM22_tx_pwr_txpow_0 -#define RFM22B_NOMINAL_CARRIER_FREQUENCY 430000000 -#define RFM22B_LINK_QUALITY_THRESHOLD 20 -#define RFM22B_DEFAULT_MIN_CHANNEL 0 -#define RFM22B_DEFAULT_MAX_CHANNEL 250 -#define RFM22B_PPM_ONLY_DATARATE RFM22_datarate_9600 +#define STACK_SIZE_BYTES 200 +#define TASK_PRIORITY (tskIDLE_PRIORITY + 4) // flight control relevant device driver (ppm link) +#define ISR_TIMEOUT 1 // ms +#define EVENT_QUEUE_SIZE 5 +#define RFM22B_DEFAULT_RX_DATARATE RFM22_datarate_9600 +#define RFM22B_DEFAULT_TX_POWER RFM22_tx_pwr_txpow_0 +#define RFM22B_NOMINAL_CARRIER_FREQUENCY_433 430000000 +#define RFM22B_NOMINAL_CARRIER_FREQUENCY_868 860000000 +#define RFM22B_NOMINAL_CARRIER_FREQUENCY_915 900000000 +#define RFM22B_LINK_QUALITY_THRESHOLD 20 +#define RFM22B_DEFAULT_MIN_CHANNEL 0 +#define RFM22B_DEFAULT_MAX_CHANNEL 250 +#define RFM22B_PPM_ONLY_DATARATE RFM22_datarate_9600 // PPM encoding limits -#define RFM22B_PPM_MIN 1 -#define RFM22B_PPM_MAX 511 -#define RFM22B_PPM_INVALID 0 -#define RFM22B_PPM_SCALE 2 -#define RFM22B_PPM_MIN_US 990 -#define RFM22B_PPM_MAX_US (RFM22B_PPM_MIN_US + (RFM22B_PPM_MAX - RFM22B_PPM_MIN) * RFM22B_PPM_SCALE) +#define RFM22B_PPM_MIN 1 +#define RFM22B_PPM_MAX 511 +#define RFM22B_PPM_INVALID 0 +#define RFM22B_PPM_SCALE 2 +#define RFM22B_PPM_MIN_US 990 +#define RFM22B_PPM_MAX_US (RFM22B_PPM_MIN_US + (RFM22B_PPM_MAX - RFM22B_PPM_MIN) * RFM22B_PPM_SCALE) // The maximum amount of time without activity before initiating a reset. -#define PIOS_RFM22B_SUPERVISOR_TIMEOUT 150 // ms +#define PIOS_RFM22B_SUPERVISOR_TIMEOUT 150 // ms // this is too adjust the RF module so that it is on frequency -#define OSC_LOAD_CAP 0x7F // cap = 12.5pf .. default +#define OSC_LOAD_CAP 0x7F // cap = 12.5pf .. default -#define TX_PREAMBLE_NIBBLES 12 // 7 to 511 (number of nibbles) -#define RX_PREAMBLE_NIBBLES 6 // 5 to 31 (number of nibbles) -#define SYNC_BYTES 4 -#define HEADER_BYTES 4 -#define LENGTH_BYTES 1 +#define TX_PREAMBLE_NIBBLES 12 // 7 to 511 (number of nibbles) +#define RX_PREAMBLE_NIBBLES 6 // 5 to 31 (number of nibbles) +#define SYNC_BYTES 4 +#define HEADER_BYTES 4 +#define LENGTH_BYTES 1 // the size of the rf modules internal FIFO buffers -#define FIFO_SIZE 64 +#define FIFO_SIZE 64 -#define TX_FIFO_HI_WATERMARK 62 // 0-63 -#define TX_FIFO_LO_WATERMARK 32 // 0-63 +#define TX_FIFO_HI_WATERMARK 62 // 0-63 +#define TX_FIFO_LO_WATERMARK 32 // 0-63 -#define RX_FIFO_HI_WATERMARK 32 // 0-63 +#define RX_FIFO_HI_WATERMARK 32 // 0-63 // preamble byte (preceeds SYNC_BYTE's) -#define PREAMBLE_BYTE 0x55 +#define PREAMBLE_BYTE 0x55 // RF sync bytes (32-bit in all) -#define SYNC_BYTE_1 0x2D -#define SYNC_BYTE_2 0xD4 -#define SYNC_BYTE_3 0x4B -#define SYNC_BYTE_4 0x59 +#define SYNC_BYTE_1 0x2D +#define SYNC_BYTE_2 0xD4 +#define SYNC_BYTE_3 0x4B +#define SYNC_BYTE_4 0x59 #ifndef RX_LED_ON #define RX_LED_ON @@ -187,7 +189,7 @@ static enum pios_radio_event rfm22_timeout(struct pios_rfm22b_dev *rfm22b_dev); static enum pios_radio_event rfm22_error(struct pios_rfm22b_dev *rfm22b_dev); static enum pios_radio_event rfm22_fatal_error(struct pios_rfm22b_dev *rfm22b_dev); static void rfm22b_add_rx_status(struct pios_rfm22b_dev *rfm22b_dev, enum pios_rfm22b_rx_packet_status status); -static void rfm22_setNominalCarrierFrequency(struct pios_rfm22b_dev *rfm22b_dev, uint8_t init_chan); +static void rfm22_setNominalCarrierFrequency(struct pios_rfm22b_dev *rfm22b_dev, uint8_t init_chan, uint32_t frequency_hz); static bool rfm22_setFreqHopChannel(struct pios_rfm22b_dev *rfm22b_dev, uint8_t channel); static void rfm22_generateDeviceID(struct pios_rfm22b_dev *rfm22b_dev); static void rfm22_updatePairStatus(struct pios_rfm22b_dev *radio_dev); @@ -391,7 +393,7 @@ static struct pios_rfm22b_dev *g_rfm22b_dev = NULL; * @param[in] slave_num The SPI bus slave number. * @param[in] cfg The device configuration. */ -int32_t PIOS_RFM22B_Init(uint32_t *rfm22b_id, uint32_t spi_id, uint32_t slave_num, const struct pios_rfm22b_cfg *cfg) +int32_t PIOS_RFM22B_Init(uint32_t *rfm22b_id, uint32_t spi_id, uint32_t slave_num, const struct pios_rfm22b_cfg *cfg, OPLinkSettingsRFBandOptions band) { PIOS_DEBUG_Assert(rfm22b_id); PIOS_DEBUG_Assert(cfg); @@ -436,6 +438,20 @@ int32_t PIOS_RFM22B_Init(uint32_t *rfm22b_id, uint32_t spi_id, uint32_t slave_nu rfm22b_dev->stats.rx_seq = 0; rfm22b_dev->stats.tx_failure = 0; + // Set the frequency band + switch (band) { + case OPLINKSETTINGS_RFBAND_915MHZ: + rfm22b_dev->base_freq = RFM22B_NOMINAL_CARRIER_FREQUENCY_915; + break; + case OPLINKSETTINGS_RFBAND_868MHZ: + rfm22b_dev->base_freq = RFM22B_NOMINAL_CARRIER_FREQUENCY_868; + break; + case OPLINKSETTINGS_RFBAND_433MHZ: + default: + rfm22b_dev->base_freq = RFM22B_NOMINAL_CARRIER_FREQUENCY_433; + break; + } + // Initialize the channels. PIOS_RFM22B_SetChannelConfig(*rfm22b_id, RFM22B_DEFAULT_RX_DATARATE, RFM22B_DEFAULT_MIN_CHANNEL, RFM22B_DEFAULT_MAX_CHANNEL, false, true, false); @@ -1566,7 +1582,7 @@ static enum pios_radio_event rfm22_init(struct pios_rfm22b_dev *rfm22b_dev) vTaskDelay(1 + (1 / (portTICK_RATE_MS + 1))); // Initialize the frequency and datarate to te default. - rfm22_setNominalCarrierFrequency(rfm22b_dev, 0); + rfm22_setNominalCarrierFrequency(rfm22b_dev, 0, rfm22b_dev->base_freq); pios_rfm22_setDatarate(rfm22b_dev); return RADIO_EVENT_INITIALIZED; @@ -1656,10 +1672,8 @@ static void pios_rfm22_setDatarate(struct pios_rfm22b_dev *rfm22b_dev) * @param[in] rfm33b_dev The device structure pointer. * @param[in] init_chan The initial channel to tune to. */ -static void rfm22_setNominalCarrierFrequency(struct pios_rfm22b_dev *rfm22b_dev, uint8_t init_chan) +static void rfm22_setNominalCarrierFrequency(struct pios_rfm22b_dev *rfm22b_dev, uint8_t init_chan, uint32_t frequency_hz) { - // Set the frequency channels to start at 430MHz - uint32_t frequency_hz = RFM22B_NOMINAL_CARRIER_FREQUENCY; // The step size is 10MHz / 250 = 40khz, and the step size is specified in 10khz increments. uint8_t freq_hop_step_size = 4; @@ -1682,7 +1696,7 @@ static void rfm22_setNominalCarrierFrequency(struct pios_rfm22b_dev *rfm22b_dev, // Claim the SPI bus. rfm22_claimBus(rfm22b_dev); - // Setthe frequency hopping step size. + // Set the frequency hopping step size. rfm22_write(rfm22b_dev, RFM22_frequency_hopping_step_size, freq_hop_step_size); // frequency hopping channel (0-255) diff --git a/flight/pios/inc/pios_rfm22b.h b/flight/pios/inc/pios_rfm22b.h index 16dd460b27..6158771adc 100644 --- a/flight/pios/inc/pios_rfm22b.h +++ b/flight/pios/inc/pios_rfm22b.h @@ -101,7 +101,7 @@ struct rfm22b_stats { }; /* Public Functions */ -extern int32_t PIOS_RFM22B_Init(uint32_t *rfb22b_id, uint32_t spi_id, uint32_t slave_num, const struct pios_rfm22b_cfg *cfg); +extern int32_t PIOS_RFM22B_Init(uint32_t *rfb22b_id, uint32_t spi_id, uint32_t slave_num, const struct pios_rfm22b_cfg *cfg, OPLinkSettingsRFBandOptions band); extern void PIOS_RFM22B_Reinit(uint32_t rfb22b_id); extern void PIOS_RFM22B_SetTxPower(uint32_t rfm22b_id, enum rfm22b_tx_power tx_pwr); extern void PIOS_RFM22B_SetChannelConfig(uint32_t rfm22b_id, enum rfm22b_datarate datarate, uint8_t min_chan, uint8_t max_chan, bool coordinator, bool ppm_mode, bool ppm_only); diff --git a/flight/pios/inc/pios_rfm22b_priv.h b/flight/pios/inc/pios_rfm22b_priv.h index 953c90fc0b..5a66bd1801 100644 --- a/flight/pios/inc/pios_rfm22b_priv.h +++ b/flight/pios/inc/pios_rfm22b_priv.h @@ -283,6 +283,9 @@ struct pios_rfm22b_dev { // Are we sending / receiving only PPM data? bool ppm_only_mode; + // The base freq in Hertz + uint32_t base_freq; + // The channel list uint8_t channels[RFM22B_NUM_CHANNELS]; // The number of frequency hopping channels. diff --git a/flight/targets/boards/discoveryf4bare/firmware/pios_board.c b/flight/targets/boards/discoveryf4bare/firmware/pios_board.c index a58fd1d312..77c0f357eb 100644 --- a/flight/targets/boards/discoveryf4bare/firmware/pios_board.c +++ b/flight/targets/boards/discoveryf4bare/firmware/pios_board.c @@ -784,7 +784,7 @@ void PIOS_Board_Init(void) if (oplinkSettings.MaxRFPower != OPLINKSETTINGS_MAXRFPOWER_0) { /* Configure the RFM22B device. */ const struct pios_rfm22b_cfg *rfm22b_cfg = PIOS_BOARD_HW_DEFS_GetRfm22Cfg(bdinfo->board_rev); - if (PIOS_RFM22B_Init(&pios_rfm22b_id, PIOS_RFM22_SPI_PORT, rfm22b_cfg->slave_num, rfm22b_cfg)) { + if (PIOS_RFM22B_Init(&pios_rfm22b_id, PIOS_RFM22_SPI_PORT, rfm22b_cfg->slave_num, rfm22b_cfg, oplinkSettings.RFBand)) { PIOS_Assert(0); } diff --git a/flight/targets/boards/oplinkmini/firmware/pios_board.c b/flight/targets/boards/oplinkmini/firmware/pios_board.c index a6f7574ca1..c96321da19 100644 --- a/flight/targets/boards/oplinkmini/firmware/pios_board.c +++ b/flight/targets/boards/oplinkmini/firmware/pios_board.c @@ -413,7 +413,7 @@ void PIOS_Board_Init(void) // Configure the RFM22B device const struct pios_rfm22b_cfg *rfm22b_cfg = PIOS_BOARD_HW_DEFS_GetRfm22Cfg(bdinfo->board_rev); - if (PIOS_RFM22B_Init(&pios_rfm22b_id, PIOS_RFM22_SPI_PORT, rfm22b_cfg->slave_num, rfm22b_cfg)) { + if (PIOS_RFM22B_Init(&pios_rfm22b_id, PIOS_RFM22_SPI_PORT, rfm22b_cfg->slave_num, rfm22b_cfg, oplinkSettings.RFBand)) { PIOS_Assert(0); } diff --git a/flight/targets/boards/revolution/firmware/pios_board.c b/flight/targets/boards/revolution/firmware/pios_board.c index 7f7ddee074..5bb74f47f0 100644 --- a/flight/targets/boards/revolution/firmware/pios_board.c +++ b/flight/targets/boards/revolution/firmware/pios_board.c @@ -912,7 +912,7 @@ void PIOS_Board_Init(void) } else { /* Configure the RFM22B device. */ const struct pios_rfm22b_cfg *rfm22b_cfg = PIOS_BOARD_HW_DEFS_GetRfm22Cfg(bdinfo->board_rev); - if (PIOS_RFM22B_Init(&pios_rfm22b_id, PIOS_RFM22_SPI_PORT, rfm22b_cfg->slave_num, rfm22b_cfg)) { + if (PIOS_RFM22B_Init(&pios_rfm22b_id, PIOS_RFM22_SPI_PORT, rfm22b_cfg->slave_num, rfm22b_cfg, oplinkSettings.RFBand)) { PIOS_Assert(0); } diff --git a/flight/targets/boards/sparky2/firmware/pios_board.c b/flight/targets/boards/sparky2/firmware/pios_board.c index e8a82a2f4d..444653c3b4 100644 --- a/flight/targets/boards/sparky2/firmware/pios_board.c +++ b/flight/targets/boards/sparky2/firmware/pios_board.c @@ -852,7 +852,7 @@ void PIOS_Board_Init(void) } else { /* Configure the RFM22B device. */ const struct pios_rfm22b_cfg *rfm22b_cfg = PIOS_BOARD_HW_DEFS_GetRfm22Cfg(bdinfo->board_rev); - if (PIOS_RFM22B_Init(&pios_rfm22b_id, PIOS_RFM22_SPI_PORT, rfm22b_cfg->slave_num, rfm22b_cfg)) { + if (PIOS_RFM22B_Init(&pios_rfm22b_id, PIOS_RFM22_SPI_PORT, rfm22b_cfg->slave_num, rfm22b_cfg, oplinkSettings.RFBand)) { PIOS_Assert(0); } diff --git a/shared/uavobjectdefinition/oplinksettings.xml b/shared/uavobjectdefinition/oplinksettings.xml index dbf4503602..0fe17836f5 100644 --- a/shared/uavobjectdefinition/oplinksettings.xml +++ b/shared/uavobjectdefinition/oplinksettings.xml @@ -9,6 +9,7 @@ + @@ -16,19 +17,19 @@ - + - + - + From ab8e0400f069c821485bae69ce3659d50ce5478d Mon Sep 17 00:00:00 2001 From: Laurent Lalanne Date: Wed, 28 Sep 2016 00:05:03 +0200 Subject: [PATCH 038/624] LP-345 OPLink: Update GUI with RF Band dropdown --- .../src/plugins/config/configoplinkwidget.cpp | 34 +- .../src/plugins/config/configoplinkwidget.h | 6 + ground/gcs/src/plugins/config/oplink.ui | 477 ++++++++++-------- 3 files changed, 293 insertions(+), 224 deletions(-) diff --git a/ground/gcs/src/plugins/config/configoplinkwidget.cpp b/ground/gcs/src/plugins/config/configoplinkwidget.cpp index 611cb7a178..64b39d0163 100644 --- a/ground/gcs/src/plugins/config/configoplinkwidget.cpp +++ b/ground/gcs/src/plugins/config/configoplinkwidget.cpp @@ -41,7 +41,6 @@ // Channel range and Frequency display static const int MAX_CHANNEL_NUM = 250; static const int MIN_CHANNEL_RANGE = 10; -static const float FIRST_FREQUENCY = 430.000; static const float FREQUENCY_STEP = 0.040; ConfigOPLinkWidget::ConfigOPLinkWidget(QWidget *parent) : ConfigTaskWidget(parent, false), statusUpdated(false) @@ -76,6 +75,7 @@ ConfigOPLinkWidget::ConfigOPLinkWidget(QWidget *parent) : ConfigTaskWidget(paren addWidgetBinding("OPLinkSettings", "LinkType", m_oplink->LinkType); addWidgetBinding("OPLinkSettings", "CoordID", m_oplink->CoordID); addWidgetBinding("OPLinkSettings", "CustomDeviceID", m_oplink->CustomDeviceID); + addWidgetBinding("OPLinkSettings", "RFBand", m_oplink->RFBand); addWidgetBinding("OPLinkSettings", "MinChannel", m_oplink->MinimumChannel); addWidgetBinding("OPLinkSettings", "MaxChannel", m_oplink->MaximumChannel); addWidgetBinding("OPLinkSettings", "MaxRFPower", m_oplink->MaxRFTxPower); @@ -111,6 +111,7 @@ ConfigOPLinkWidget::ConfigOPLinkWidget(QWidget *parent) : ConfigTaskWidget(paren // Connect the selection changed signals. connect(m_oplink->Protocol, SIGNAL(currentIndexChanged(int)), this, SLOT(protocolChanged())); connect(m_oplink->LinkType, SIGNAL(currentIndexChanged(int)), this, SLOT(linkTypeChanged())); + connect(m_oplink->RFBand, SIGNAL(currentIndexChanged(int)), this, SLOT(rfBandChanged())); connect(m_oplink->MinimumChannel, SIGNAL(valueChanged(int)), this, SLOT(minChannelChanged())); connect(m_oplink->MaximumChannel, SIGNAL(valueChanged(int)), this, SLOT(maxChannelChanged())); connect(m_oplink->MainPort, SIGNAL(currentIndexChanged(int)), this, SLOT(mainPortChanged())); @@ -256,6 +257,7 @@ void ConfigOPLinkWidget::updateSettings() m_oplink->UnbindButton->setEnabled(is_enabled && is_bound && !is_coordinator); m_oplink->CustomDeviceID->setEnabled(is_coordinator); + m_oplink->RFBand->setEnabled(is_receiver || is_coordinator); m_oplink->MinimumChannel->setEnabled(is_receiver || is_coordinator); m_oplink->MaximumChannel->setEnabled(is_receiver || is_coordinator); @@ -289,6 +291,27 @@ void ConfigOPLinkWidget::maxChannelChanged() channelChanged(true); } +void ConfigOPLinkWidget::rfBandChanged() +{ + switch (getComboboxSelectedOption(m_oplink->RFBand)) { + case OPLinkSettings::RFBAND_915MHZ: + frequency_base = 900.0f; + frequency_step = FREQUENCY_STEP * 2.0f; + break; + case OPLinkSettings::RFBAND_868MHZ: + frequency_base = 860.0f; + frequency_step = FREQUENCY_STEP * 2.0f; + break; + case OPLinkSettings::RFBAND_433MHZ: + frequency_base = 430.0f; + frequency_step = FREQUENCY_STEP; + break; + } + + // Update frequency display according to the RF band change + updateFrequencyDisplay(); +} + void ConfigOPLinkWidget::channelChanged(bool isMax) { int minChannel = m_oplink->MinimumChannel->value(); @@ -315,9 +338,14 @@ void ConfigOPLinkWidget::channelChanged(bool isMax) m_oplink->MaximumChannel->setValue(maxChannel); m_oplink->MinimumChannel->setValue(minChannel); + updateFrequencyDisplay(); +} + +void ConfigOPLinkWidget::updateFrequencyDisplay() +{ // Calculate and Display frequency in MHz - float minFrequency = FIRST_FREQUENCY + (minChannel * FREQUENCY_STEP); - float maxFrequency = FIRST_FREQUENCY + (maxChannel * FREQUENCY_STEP); + float minFrequency = frequency_base + (m_oplink->MinimumChannel->value() * frequency_step); + float maxFrequency = frequency_base + (m_oplink->MaximumChannel->value() * frequency_step); m_oplink->MinFreq->setText("(" + QString::number(minFrequency, 'f', 3) + " MHz)"); m_oplink->MaxFreq->setText("(" + QString::number(maxFrequency, 'f', 3) + " MHz)"); diff --git a/ground/gcs/src/plugins/config/configoplinkwidget.h b/ground/gcs/src/plugins/config/configoplinkwidget.h index 70043e2573..9cdb37ee9c 100644 --- a/ground/gcs/src/plugins/config/configoplinkwidget.h +++ b/ground/gcs/src/plugins/config/configoplinkwidget.h @@ -46,6 +46,10 @@ class ConfigOPLinkWidget : public ConfigTaskWidget { virtual void refreshWidgetsValuesImpl(UAVObject *obj); private: + // Frequency display settings + float frequency_base; + float frequency_step; + Ui_OPLinkWidget *m_oplink; OPLinkStatus *oplinkStatusObj; @@ -68,7 +72,9 @@ private slots: void minChannelChanged(); void maxChannelChanged(); + void rfBandChanged(); void channelChanged(bool isMax); + void updateFrequencyDisplay(); void mainPortChanged(); void flexiPortChanged(); diff --git a/ground/gcs/src/plugins/config/oplink.ui b/ground/gcs/src/plugins/config/oplink.ui index 546fd0a37a..7c074263ae 100644 --- a/ground/gcs/src/plugins/config/oplink.ui +++ b/ground/gcs/src/plugins/config/oplink.ui @@ -95,30 +95,57 @@ Configuration - - + + + + + 0 + 0 + + + + + 90 + 16777215 + + 50 false - - Flexi Port + + This is the coordinator ID we currently are bound to. +To manually bind to a specific coordinator, just type +or paste its device ID in this box and save. +The device must be rebooted for the binding to take place. - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + 8 + + + Qt::LogicalMoveStyle + + + false - - + + 0 0 + + + 0 + 0 + + 90 @@ -131,15 +158,30 @@ false + + Qt::StrongFocus + - This is the coordinator ID we currently are bound to. -To manually bind to a specific coordinator, just type -or paste its device ID in this box and save. -The device must be rebooted for the binding to take place. + Enter your custom ID for this device as a hexadecimal value, +this allows device clones. Be sure only one device with this +ID transmits at the same time! +Leave blank to use autogenerated Device ID. 8 + + true + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + false + + + + Qt::LogicalMoveStyle @@ -148,17 +190,118 @@ The device must be rebooted for the binding to take place. - - + + + + + 50 + false + + + + Main Port + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + + 80 + 0 + + + + + 50 + false + + + + Max Chan + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 16777215 + 16777215 + + - Clear the binding/coordinator ID + Set the modem protocol + + + Qt::LeftToRight + + + 0 + + + + + + + + 16777215 + 16777215 + + + + Choose the function for the main port. + + + + + + + + 0 + 0 + + + + + 50 + false + - Unbind + Max Power + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - + + + + Qt::Horizontal + + + + 40 + 20 + + + + + @@ -209,24 +352,31 @@ The device must be rebooted for the binding to take place. - - - - - 50 - false - + + + + + 16777215 + 16777215 + - - VCP Port + + Choose the function for the flexi port. - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + Clear the binding/coordinator ID + + + Unbind - - + + 0 @@ -246,27 +396,15 @@ The device must be rebooted for the binding to take place. - Max Chan + Min Chan Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - 0 - 0 - - - - - 80 - 0 - - + + 50 @@ -274,66 +412,53 @@ The device must be rebooted for the binding to take place. - Min Chan + Protocol Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - 16777215 - 16777215 - + + + + + 50 + false + - - Choose the function for the flexi port. + + Com Speed + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - 16777215 - 16777215 - - + + - Set the modem protocol - - - Qt::LeftToRight - - - 0 + Com speed in bps. - - - - - 16777215 - 16777215 - + + + + + 50 + false + - - Choose the function for the USB virtual com port. + + Link Type - - - - - - Com speed in bps. + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - + @@ -384,8 +509,8 @@ The device must be rebooted for the binding to take place. - - + + 50 @@ -393,15 +518,15 @@ The device must be rebooted for the binding to take place. - Protocol + Device ID Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - + + 50 @@ -409,59 +534,26 @@ The device must be rebooted for the binding to take place. - Com Speed + Flexi Port Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - 16777215 - 16777215 - - - - Set the maximum TX output power the modem will use (mW) -0 to disable the modem. - - - Qt::LeftToRight - - - 0 - - - - - + + 50 false - - Link Type - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 50 - false - + + Qt::LeftToRight - Device ID + Coordinator ID Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter @@ -487,88 +579,28 @@ The device must be rebooted for the binding to take place. - - - - - 0 - 0 - - - - - 0 - 0 - - + + - 90 + 16777215 16777215 - - - 50 - false - - - - Qt::StrongFocus - - Enter your custom ID for this device as a hexadecimal value, -this allows device clones. Be sure only one device with this -ID transmits at the same time! -Leave blank to use autogenerated Device ID. - - - 8 - - - true - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - false - - - - - - Qt::LogicalMoveStyle - - - false - - - - - - - - 0 - 0 - - - - - 50 - false - + Set the maximum TX output power the modem will use (mW) +0 to disable the modem. - - Max Power + + Qt::LeftToRight - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + 0 - - + + 50 @@ -576,57 +608,60 @@ Leave blank to use autogenerated Device ID. - Main Port + RF Band Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - + + - 16777215 + 90 16777215 - Choose the function for the main port. + Set the RF Band used. + + + Qt::LeftToRight + + + 0 - - + + 50 false - - Qt::LeftToRight - - Coordinator ID + VCP Port Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - Qt::Horizontal - - + + + - 40 - 20 + 16777215 + 16777215 - + + Choose the function for the USB virtual com port. + + From 7800f49705940bbe3cd6eb1adbf9246a9e3559e5 Mon Sep 17 00:00:00 2001 From: Laurent Lalanne Date: Mon, 3 Oct 2016 14:56:40 +0200 Subject: [PATCH 039/624] LP-346 RFM22 tuning: Add AFC value to OplinkStatus --- flight/modules/System/systemmod.c | 23 +++++++------- flight/pios/common/pios_rfm22b.c | 34 +++++++++++---------- flight/pios/inc/pios_rfm22b.h | 2 +- flight/pios/inc/pios_rfm22b_priv.h | 2 +- shared/uavobjectdefinition/oplinkstatus.xml | 1 + 5 files changed, 33 insertions(+), 29 deletions(-) diff --git a/flight/modules/System/systemmod.c b/flight/modules/System/systemmod.c index 2cf86e7511..d1ff52fd31 100644 --- a/flight/modules/System/systemmod.c +++ b/flight/modules/System/systemmod.c @@ -292,18 +292,19 @@ static void systemTask(__attribute__((unused)) void *parameters) static uint16_t prev_tx_seq = 0; static uint16_t prev_rx_seq = 0; - oplinkStatus.DeviceID = PIOS_RFM22B_DeviceID(pios_rfm22b_id); - oplinkStatus.RxGood = radio_stats.rx_good; - oplinkStatus.RxCorrected = radio_stats.rx_corrected; - oplinkStatus.RxErrors = radio_stats.rx_error; - oplinkStatus.RxMissed = radio_stats.rx_missed; - oplinkStatus.RxFailure = radio_stats.rx_failure; - oplinkStatus.TxDropped = radio_stats.tx_dropped; - oplinkStatus.TxFailure = radio_stats.tx_failure; - oplinkStatus.Resets = radio_stats.resets; - oplinkStatus.Timeouts = radio_stats.timeouts; + oplinkStatus.DeviceID = PIOS_RFM22B_DeviceID(pios_rfm22b_id); + oplinkStatus.RxGood = radio_stats.rx_good; + oplinkStatus.RxCorrected = radio_stats.rx_corrected; + oplinkStatus.RxErrors = radio_stats.rx_error; + oplinkStatus.RxMissed = radio_stats.rx_missed; + oplinkStatus.RxFailure = radio_stats.rx_failure; + oplinkStatus.TxDropped = radio_stats.tx_dropped; + oplinkStatus.TxFailure = radio_stats.tx_failure; + oplinkStatus.Resets = radio_stats.resets; + oplinkStatus.Timeouts = radio_stats.timeouts; oplinkStatus.RSSI = radio_stats.rssi; - oplinkStatus.LinkQuality = radio_stats.link_quality; + oplinkStatus.LinkQuality = radio_stats.link_quality; + oplinkStatus.AFCCorrection = radio_stats.afc_correction; if (first_time) { first_time = false; } else { diff --git a/flight/pios/common/pios_rfm22b.c b/flight/pios/common/pios_rfm22b.c index 4d4a9aa461..07254fd295 100644 --- a/flight/pios/common/pios_rfm22b.c +++ b/flight/pios/common/pios_rfm22b.c @@ -427,16 +427,17 @@ int32_t PIOS_RFM22B_Init(uint32_t *rfm22b_id, uint32_t spi_id, uint32_t slave_nu rfm22b_dev->stats.packets_per_sec = 0; rfm22b_dev->stats.rx_good = 0; rfm22b_dev->stats.rx_corrected = 0; - rfm22b_dev->stats.rx_error = 0; - rfm22b_dev->stats.rx_missed = 0; - rfm22b_dev->stats.tx_dropped = 0; - rfm22b_dev->stats.resets = 0; - rfm22b_dev->stats.timeouts = 0; - rfm22b_dev->stats.link_quality = 0; + rfm22b_dev->stats.rx_error = 0; + rfm22b_dev->stats.rx_missed = 0; + rfm22b_dev->stats.tx_dropped = 0; + rfm22b_dev->stats.resets = 0; + rfm22b_dev->stats.timeouts = 0; + rfm22b_dev->stats.link_quality = 0; rfm22b_dev->stats.rssi = 0; - rfm22b_dev->stats.tx_seq = 0; - rfm22b_dev->stats.rx_seq = 0; - rfm22b_dev->stats.tx_failure = 0; + rfm22b_dev->stats.afc_correction = 0; + rfm22b_dev->stats.tx_seq = 0; + rfm22b_dev->stats.rx_seq = 0; + rfm22b_dev->stats.tx_failure = 0; // Set the frequency band switch (band) { @@ -1072,13 +1073,13 @@ pios_rfm22b_int_result PIOS_RFM22B_ProcessRx(uint32_t rfm22b_id) // read the 10-bit signed afc correction value // bits 9 to 2 - uint16_t afc_correction = (uint16_t)rfm22_read(rfm22b_dev, RFM22_afc_correction_read) << 8; + int16_t afc_correction = (uint16_t)rfm22_read(rfm22b_dev, RFM22_afc_correction_read) << 8; // bits 1 & 0 - afc_correction |= (uint16_t)rfm22_read(rfm22b_dev, RFM22_ook_counter_value1) & 0x00c0; + afc_correction |= (int16_t)rfm22_read(rfm22b_dev, RFM22_ook_counter_value1) & 0x00c0; afc_correction >>= 6; // convert the afc value to Hz int32_t afc_corr = (int32_t)(rfm22b_dev->frequency_step_size * afc_correction + 0.5f); - rfm22b_dev->afc_correction_Hz = (afc_corr < -127) ? -127 : ((afc_corr > 127) ? 127 : afc_corr); + rfm22b_dev->afc_correction_Hz = afc_corr; // read rx signal strength .. 45 = -100dBm, 205 = -20dBm uint8_t rssi = rfm22_read(rfm22b_dev, RFM22_rssi); @@ -1699,8 +1700,8 @@ static void rfm22_setNominalCarrierFrequency(struct pios_rfm22b_dev *rfm22b_dev, // Set the frequency hopping step size. rfm22_write(rfm22b_dev, RFM22_frequency_hopping_step_size, freq_hop_step_size); - // frequency hopping channel (0-255) - rfm22b_dev->frequency_step_size = 156.25f * hbsel; + // frequency step + rfm22b_dev->frequency_step_size = 156.25f * (hbsel + 1); // frequency hopping channel (0-255) rfm22b_dev->channel = init_chan; @@ -2063,9 +2064,10 @@ static enum pios_radio_event radio_receivePacket(struct pios_rfm22b_dev *radio_d radio_dev->rx_destination_id == rfm22_destinationID(radio_dev)) { rfm22_synchronizeClock(radio_dev); } - radio_dev->stats.link_state = OPLINKSTATUS_LINKSTATE_CONNECTED; - radio_dev->last_contact = xTaskGetTickCount(); + radio_dev->stats.link_state = OPLINKSTATUS_LINKSTATE_CONNECTED; + radio_dev->last_contact = xTaskGetTickCount(); radio_dev->stats.rssi = radio_dev->rssi_dBm; + radio_dev->stats.afc_correction = radio_dev->afc_correction_Hz; } else { ret_event = RADIO_EVENT_RX_COMPLETE; } diff --git a/flight/pios/inc/pios_rfm22b.h b/flight/pios/inc/pios_rfm22b.h index 6158771adc..14b6fbaa41 100644 --- a/flight/pios/inc/pios_rfm22b.h +++ b/flight/pios/inc/pios_rfm22b.h @@ -96,7 +96,7 @@ struct rfm22b_stats { uint8_t timeouts; uint8_t link_quality; int8_t rssi; - int8_t afc_correction; + int32_t afc_correction; uint8_t link_state; }; diff --git a/flight/pios/inc/pios_rfm22b_priv.h b/flight/pios/inc/pios_rfm22b_priv.h index 5a66bd1801..9d267d7d6d 100644 --- a/flight/pios/inc/pios_rfm22b_priv.h +++ b/flight/pios/inc/pios_rfm22b_priv.h @@ -297,7 +297,7 @@ struct pios_rfm22b_dev { // current frequency hop channel index uint8_t channel_index; // afc correction reading (in Hz) - int8_t afc_correction_Hz; + int32_t afc_correction_Hz; // The packet timers. portTickType packet_start_ticks; diff --git a/shared/uavobjectdefinition/oplinkstatus.xml b/shared/uavobjectdefinition/oplinkstatus.xml index fdb3d5053d..7d9605c61c 100644 --- a/shared/uavobjectdefinition/oplinkstatus.xml +++ b/shared/uavobjectdefinition/oplinkstatus.xml @@ -19,6 +19,7 @@ + From ea377973fc63f6b74c73dc226d1ce15cd78a536d Mon Sep 17 00:00:00 2001 From: Laurent Lalanne Date: Mon, 3 Oct 2016 18:35:51 +0200 Subject: [PATCH 040/624] LP-346 RFM22 tuning: Add XtalCap value for fine tuning --- flight/pios/common/pios_rfm22b.c | 9 +++++++-- flight/targets/boards/oplinkmini/firmware/pios_board.c | 4 ++++ flight/targets/boards/revolution/board_hw_defs.c | 4 ++-- flight/targets/boards/revolution/firmware/pios_board.c | 5 +++++ flight/targets/boards/sparky2/board_hw_defs.c | 2 +- flight/targets/boards/sparky2/firmware/pios_board.c | 4 ++++ shared/uavobjectdefinition/oplinksettings.xml | 1 + 7 files changed, 24 insertions(+), 5 deletions(-) diff --git a/flight/pios/common/pios_rfm22b.c b/flight/pios/common/pios_rfm22b.c index 07254fd295..1cb46f45f2 100644 --- a/flight/pios/common/pios_rfm22b.c +++ b/flight/pios/common/pios_rfm22b.c @@ -1573,8 +1573,13 @@ static enum pios_radio_event rfm22_init(struct pios_rfm22b_dev *rfm22b_dev) // RX FIFO Almost Full Threshold (0 - 63) rfm22_write(rfm22b_dev, RFM22_rx_fifo_control, RX_FIFO_HI_WATERMARK); - // Set the frequency calibration - rfm22_write(rfm22b_dev, RFM22_xtal_osc_load_cap, rfm22b_dev->cfg.RFXtalCap); + // Set the xtal capacitor for frequency calibration + // Cint = 1.8 pF + 0.085 pF x xlc[6:0] + 3.7 pF x xlc[7] (xtalshift) + // cfg.RFXtalCap 0 to 171 range give Cint = 1.8pF to 16.295pF range + // Default is 127, equal to 12.595pF + rfm22_write(rfm22b_dev, + RFM22_xtal_osc_load_cap, + (rfm22b_dev->cfg.RFXtalCap < 128) ? rfm22b_dev->cfg.RFXtalCap : (rfm22b_dev->cfg.RFXtalCap + 84)); // Release the bus rfm22_releaseBus(rfm22b_dev); diff --git a/flight/targets/boards/oplinkmini/firmware/pios_board.c b/flight/targets/boards/oplinkmini/firmware/pios_board.c index c96321da19..14a109b50e 100644 --- a/flight/targets/boards/oplinkmini/firmware/pios_board.c +++ b/flight/targets/boards/oplinkmini/firmware/pios_board.c @@ -413,6 +413,10 @@ void PIOS_Board_Init(void) // Configure the RFM22B device const struct pios_rfm22b_cfg *rfm22b_cfg = PIOS_BOARD_HW_DEFS_GetRfm22Cfg(bdinfo->board_rev); + + // Set the Xtal capacitor value + pios_rfm22b_cfg.RFXtalCap = oplinkSettings.RFXtalCap; + if (PIOS_RFM22B_Init(&pios_rfm22b_id, PIOS_RFM22_SPI_PORT, rfm22b_cfg->slave_num, rfm22b_cfg, oplinkSettings.RFBand)) { PIOS_Assert(0); } diff --git a/flight/targets/boards/revolution/board_hw_defs.c b/flight/targets/boards/revolution/board_hw_defs.c index 74770d9804..251e6a5f53 100644 --- a/flight/targets/boards/revolution/board_hw_defs.c +++ b/flight/targets/boards/revolution/board_hw_defs.c @@ -640,7 +640,7 @@ static const struct pios_exti_cfg pios_exti_rfm22b_cfg __exti_config = { }, }; -const struct pios_rfm22b_cfg pios_rfm22b_rm1_cfg = { +struct pios_rfm22b_cfg pios_rfm22b_rm1_cfg = { .spi_cfg = &pios_spi_telem_flash_cfg, .exti_cfg = &pios_exti_rfm22b_cfg, .RFXtalCap = 0x7f, @@ -648,7 +648,7 @@ const struct pios_rfm22b_cfg pios_rfm22b_rm1_cfg = { .gpio_direction = GPIO0_RX_GPIO1_TX, }; -const struct pios_rfm22b_cfg pios_rfm22b_rm2_cfg = { +struct pios_rfm22b_cfg pios_rfm22b_rm2_cfg = { .spi_cfg = &pios_spi_telem_flash_cfg, .exti_cfg = &pios_exti_rfm22b_cfg, .RFXtalCap = 0x7f, diff --git a/flight/targets/boards/revolution/firmware/pios_board.c b/flight/targets/boards/revolution/firmware/pios_board.c index 5bb74f47f0..7ac8885237 100644 --- a/flight/targets/boards/revolution/firmware/pios_board.c +++ b/flight/targets/boards/revolution/firmware/pios_board.c @@ -912,6 +912,11 @@ void PIOS_Board_Init(void) } else { /* Configure the RFM22B device. */ const struct pios_rfm22b_cfg *rfm22b_cfg = PIOS_BOARD_HW_DEFS_GetRfm22Cfg(bdinfo->board_rev); + + // Set the Xtal capacitor value + pios_rfm22b_rm1_cfg.RFXtalCap = oplinkSettings.RFXtalCap; + pios_rfm22b_rm2_cfg.RFXtalCap = oplinkSettings.RFXtalCap; + if (PIOS_RFM22B_Init(&pios_rfm22b_id, PIOS_RFM22_SPI_PORT, rfm22b_cfg->slave_num, rfm22b_cfg, oplinkSettings.RFBand)) { PIOS_Assert(0); } diff --git a/flight/targets/boards/sparky2/board_hw_defs.c b/flight/targets/boards/sparky2/board_hw_defs.c index 25afb14e23..2c63d0fcf2 100644 --- a/flight/targets/boards/sparky2/board_hw_defs.c +++ b/flight/targets/boards/sparky2/board_hw_defs.c @@ -431,7 +431,7 @@ static const struct pios_exti_cfg pios_exti_rfm22b_cfg __exti_config = { }, }; -const struct pios_rfm22b_cfg pios_rfm22b_cfg = { +struct pios_rfm22b_cfg pios_rfm22b_cfg = { .spi_cfg = &pios_spi_telem_flash_cfg, .exti_cfg = &pios_exti_rfm22b_cfg, .RFXtalCap = 0x7f, diff --git a/flight/targets/boards/sparky2/firmware/pios_board.c b/flight/targets/boards/sparky2/firmware/pios_board.c index 444653c3b4..266d35a8a1 100644 --- a/flight/targets/boards/sparky2/firmware/pios_board.c +++ b/flight/targets/boards/sparky2/firmware/pios_board.c @@ -852,6 +852,10 @@ void PIOS_Board_Init(void) } else { /* Configure the RFM22B device. */ const struct pios_rfm22b_cfg *rfm22b_cfg = PIOS_BOARD_HW_DEFS_GetRfm22Cfg(bdinfo->board_rev); + + // Set the Xtal capacitor value + pios_rfm22b_cfg.RFXtalCap = oplinkSettings.RFXtalCap; + if (PIOS_RFM22B_Init(&pios_rfm22b_id, PIOS_RFM22_SPI_PORT, rfm22b_cfg->slave_num, rfm22b_cfg, oplinkSettings.RFBand)) { PIOS_Assert(0); } diff --git a/shared/uavobjectdefinition/oplinksettings.xml b/shared/uavobjectdefinition/oplinksettings.xml index 0fe17836f5..1e538934e2 100644 --- a/shared/uavobjectdefinition/oplinksettings.xml +++ b/shared/uavobjectdefinition/oplinksettings.xml @@ -13,6 +13,7 @@ + From 8e1d6f6d86f4fd886c1e4bce5b1cb74afc633c9e Mon Sep 17 00:00:00 2001 From: Laurent Lalanne Date: Mon, 3 Oct 2016 18:48:10 +0200 Subject: [PATCH 041/624] LP-346 RFM22 tuning: Missing AFCCorrection update for OPLink --- flight/modules/OPLink/oplinkmod.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/flight/modules/OPLink/oplinkmod.c b/flight/modules/OPLink/oplinkmod.c index 6727cdde34..eb86e4632d 100644 --- a/flight/modules/OPLink/oplinkmod.c +++ b/flight/modules/OPLink/oplinkmod.c @@ -152,18 +152,19 @@ static void systemTask(__attribute__((unused)) void *parameters) if (pios_rfm22b_id) { // Update the status - oplinkStatus.DeviceID = PIOS_RFM22B_DeviceID(pios_rfm22b_id); - oplinkStatus.RxGood = radio_stats.rx_good; - oplinkStatus.RxCorrected = radio_stats.rx_corrected; - oplinkStatus.RxErrors = radio_stats.rx_error; - oplinkStatus.RxMissed = radio_stats.rx_missed; - oplinkStatus.RxFailure = radio_stats.rx_failure; - oplinkStatus.TxDropped = radio_stats.tx_dropped; - oplinkStatus.TxFailure = radio_stats.tx_failure; - oplinkStatus.Resets = radio_stats.resets; - oplinkStatus.Timeouts = radio_stats.timeouts; + oplinkStatus.DeviceID = PIOS_RFM22B_DeviceID(pios_rfm22b_id); + oplinkStatus.RxGood = radio_stats.rx_good; + oplinkStatus.RxCorrected = radio_stats.rx_corrected; + oplinkStatus.RxErrors = radio_stats.rx_error; + oplinkStatus.RxMissed = radio_stats.rx_missed; + oplinkStatus.RxFailure = radio_stats.rx_failure; + oplinkStatus.TxDropped = radio_stats.tx_dropped; + oplinkStatus.TxFailure = radio_stats.tx_failure; + oplinkStatus.Resets = radio_stats.resets; + oplinkStatus.Timeouts = radio_stats.timeouts; oplinkStatus.RSSI = radio_stats.rssi; - oplinkStatus.LinkQuality = radio_stats.link_quality; + oplinkStatus.LinkQuality = radio_stats.link_quality; + oplinkStatus.AFCCorrection = radio_stats.afc_correction; if (first_time) { first_time = false; } else { From 54fa56d42177e89b3e7503519a6069ad54687f84 Mon Sep 17 00:00:00 2001 From: Laurent Lalanne Date: Mon, 3 Oct 2016 21:30:02 +0200 Subject: [PATCH 042/624] LP-346 RFM22 tuning: Add Gui for tuning. --- .../src/plugins/config/configoplinkwidget.cpp | 7 + ground/gcs/src/plugins/config/oplink.ui | 147 +++++++++++++++--- 2 files changed, 135 insertions(+), 19 deletions(-) diff --git a/ground/gcs/src/plugins/config/configoplinkwidget.cpp b/ground/gcs/src/plugins/config/configoplinkwidget.cpp index 64b39d0163..87ecf8255f 100644 --- a/ground/gcs/src/plugins/config/configoplinkwidget.cpp +++ b/ground/gcs/src/plugins/config/configoplinkwidget.cpp @@ -84,6 +84,9 @@ ConfigOPLinkWidget::ConfigOPLinkWidget(QWidget *parent) : ConfigTaskWidget(paren addWidgetBinding("OPLinkSettings", "FlexiPort", m_oplink->FlexiPort); addWidgetBinding("OPLinkSettings", "VCPPort", m_oplink->VCPPort); + addWidgetBinding("OPLinkSettings", "RFXtalCap", m_oplink->RFXtalCapValue); + addWidgetBinding("OPLinkSettings", "RFXtalCap", m_oplink->RFXtalCapSlider); + addWidgetBinding("OPLinkStatus", "DeviceID", m_oplink->DeviceID); addWidgetBinding("OPLinkStatus", "RxGood", m_oplink->Good); addWidgetBinding("OPLinkStatus", "RxCorrected", m_oplink->Corrected); @@ -104,6 +107,7 @@ ConfigOPLinkWidget::ConfigOPLinkWidget(QWidget *parent) : ConfigTaskWidget(paren addWidgetBinding("OPLinkStatus", "TXRate", m_oplink->TXRate); addWidgetBinding("OPLinkStatus", "RXPacketRate", m_oplink->RXPacketRate); addWidgetBinding("OPLinkStatus", "TXPacketRate", m_oplink->TXPacketRate); + addWidgetBinding("OPLinkStatus", "AFCCorrection", m_oplink->AFCCorrection); // initially hide port combo boxes setPortsVisible(false); @@ -172,6 +176,9 @@ void ConfigOPLinkWidget::updateStatus() m_oplink->PairSignalStrengthBar1->setValue(linkConnected ? m_oplink->RSSI->text().toInt() : -127); m_oplink->PairSignalStrengthLabel1->setText(QString("%1dB").arg(m_oplink->PairSignalStrengthBar1->value())); + int afc_valueKHz = m_oplink->AFCCorrection->text().toInt() / 1000; + m_oplink->AFCCorrectionBar->setValue(afc_valueKHz); + // Enable components based on the board type connected. switch (oplinkStatusObj->boardType()) { case 0x09: // Revolution, DiscoveryF4Bare, RevoNano, RevoProto diff --git a/ground/gcs/src/plugins/config/oplink.ui b/ground/gcs/src/plugins/config/oplink.ui index 7c074263ae..8921518573 100644 --- a/ground/gcs/src/plugins/config/oplink.ui +++ b/ground/gcs/src/plugins/config/oplink.ui @@ -776,7 +776,7 @@ Leave blank to use autogenerated Device ID. - + Qt::Vertical @@ -789,7 +789,7 @@ Leave blank to use autogenerated Device ID. - + @@ -1353,6 +1353,22 @@ Leave blank to use autogenerated Device ID. + + + + + 50 + false + + + + RSSI + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + @@ -1391,22 +1407,6 @@ Leave blank to use autogenerated Device ID. - - - - - 50 - false - - - - RSSI - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - @@ -1866,10 +1866,30 @@ Leave blank to use autogenerated Device ID. + + + + AFC Correction + + + + + + + + 101 + 16777215 + + + + The automatic frequency correction in Hz. + + + - + Qt::Horizontal @@ -1882,6 +1902,95 @@ Leave blank to use autogenerated Device ID. + + + + Frequency Tuning + + + + 9 + + + 9 + + + 9 + + + 9 + + + + + The xtal capacitor value for fine tune frequency and get a AFC value close to zero. Default value is 127. + + + 171 + + + 1 + + + 127 + + + Qt::Horizontal + + + + + + + The xtal capacitor value for fine tune frequency and get a AFC value close to zero. Default value is 127. + + + 171 + + + + + + + Xtal Capacitor + + + + + + + The Automatic Frequency Correction: How much the modem will correct a frequency misalignement between the two modems. + + + -50 + + + 50 + + + 0 + + + Qt::AlignCenter + + + true + + + %v KHz + + + + + + + AFC Correction + + + + + + From 1e920ec67c0b0e6e476616fb253949bc81ee99d6 Mon Sep 17 00:00:00 2001 From: Laurent Lalanne Date: Tue, 4 Oct 2016 00:41:40 +0200 Subject: [PATCH 043/624] LP-346 RFM22 tuning: Allow XtalCap value changes without reboot. --- flight/modules/OPLink/oplinkmod.c | 20 ++++++++++++++++++ flight/modules/System/systemmod.c | 27 +++++++++++++++++++++++++ flight/pios/common/pios_rfm22b.c | 15 ++++++++++++++ flight/pios/inc/pios_rfm22b.h | 1 + ground/gcs/src/plugins/config/oplink.ui | 9 ++++++--- 5 files changed, 69 insertions(+), 3 deletions(-) diff --git a/flight/modules/OPLink/oplinkmod.c b/flight/modules/OPLink/oplinkmod.c index eb86e4632d..b5fec42448 100644 --- a/flight/modules/OPLink/oplinkmod.c +++ b/flight/modules/OPLink/oplinkmod.c @@ -67,9 +67,11 @@ static xTaskHandle systemTaskHandle; static bool stackOverflow; static bool mallocFailed; volatile int initTaskDone = 0; +static OPLinkSettingsData previousOPLinkSettings; // Private functions static void systemTask(void *parameters); +static void checkOPLinkSettingsUpdatedCb(UAVObjEvent *ev); /** * Create the module task. @@ -133,6 +135,8 @@ static void systemTask(__attribute__((unused)) void *parameters) PIOS_SYS_Reset(); } + OPLinkSettingsConnectCallback(checkOPLinkSettingsUpdatedCb); + // Initialize vars lastSysTime = xTaskGetTickCount(); @@ -242,6 +246,22 @@ void vApplicationMallocFailedHook(void) #endif } +/** + * Called whenever OPLink settings changed + */ +static void checkOPLinkSettingsUpdatedCb(__attribute__((unused)) UAVObjEvent *ev) +{ + OPLinkSettingsData currentOPLinkSettings; + + OPLinkSettingsGet(¤tOPLinkSettings); + // Check if RFXtalCap value changed + if (currentOPLinkSettings.RFXtalCap != previousOPLinkSettings.RFXtalCap) { + PIOS_RFM22B_SetXtalCap(pios_rfm22b_id, currentOPLinkSettings.RFXtalCap); + PIOS_RFM22B_Reinit(pios_rfm22b_id); + previousOPLinkSettings = currentOPLinkSettings; + } +} + /** * @} * @} diff --git a/flight/modules/System/systemmod.c b/flight/modules/System/systemmod.c index d1ff52fd31..a1d0a1f6fa 100644 --- a/flight/modules/System/systemmod.c +++ b/flight/modules/System/systemmod.c @@ -129,6 +129,11 @@ static void updateWDGstats(); static uint8_t i2c_error_activity[PIOS_I2C_ERROR_COUNT_NUMELEM]; #endif +#ifdef PIOS_INCLUDE_RFM22B +static OPLinkSettingsData previousOPLinkSettings; +static void checkOPLinkSettingsUpdatedCb(UAVObjEvent *ev); +#endif + extern uintptr_t pios_uavo_settings_fs_id; extern uintptr_t pios_user_fs_id; @@ -231,6 +236,10 @@ static void systemTask(__attribute__((unused)) void *parameters) HwSettingsConnectCallback(checkSettingsUpdatedCb); SystemSettingsConnectCallback(checkSettingsUpdatedCb); +#ifdef PIOS_INCLUDE_RFM22B + OPLinkSettingsConnectCallback(checkOPLinkSettingsUpdatedCb); +#endif + #ifdef DIAG_TASKS TaskInfoData taskInfoData; CallbackInfoData callbackInfoData; @@ -454,6 +463,24 @@ static void checkSettingsUpdatedCb(__attribute__((unused)) UAVObjEvent *ev) } } +#ifdef PIOS_INCLUDE_RFM22B +/** + * Called whenever OPLink settings changed + */ +static void checkOPLinkSettingsUpdatedCb(__attribute__((unused)) UAVObjEvent *ev) +{ + OPLinkSettingsData currentOPLinkSettings; + + OPLinkSettingsGet(¤tOPLinkSettings); + // Check if RFXtalCap value changed + if (currentOPLinkSettings.RFXtalCap != previousOPLinkSettings.RFXtalCap) { + PIOS_RFM22B_SetXtalCap(pios_rfm22b_id, currentOPLinkSettings.RFXtalCap); + PIOS_RFM22B_Reinit(pios_rfm22b_id); + previousOPLinkSettings = currentOPLinkSettings; + } +} +#endif /* ifdef PIOS_INCLUDE_RFM22B */ + #ifdef DIAG_TASKS static void taskMonitorForEachCallback(uint16_t task_id, const struct pios_task_info *task_info, void *context) { diff --git a/flight/pios/common/pios_rfm22b.c b/flight/pios/common/pios_rfm22b.c index 1cb46f45f2..665d0a13a9 100644 --- a/flight/pios/common/pios_rfm22b.c +++ b/flight/pios/common/pios_rfm22b.c @@ -652,6 +652,21 @@ void PIOS_RFM22B_SetChannelConfig(uint32_t rfm22b_id, enum rfm22b_datarate datar } } +/** + * Set a XtalCap + * + * @param[in] rfm22b_id The RFM22B device index. + * @param[in] XtalCap Value. + */ +void PIOS_RFM22B_SetXtalCap(uint32_t rfm22b_id, uint8_t xtal_cap) +{ + struct pios_rfm22b_dev *rfm22b_dev = (struct pios_rfm22b_dev *)rfm22b_id; + + if (PIOS_RFM22B_Validate(rfm22b_dev)) { + rfm22b_dev->cfg.RFXtalCap = xtal_cap; + } +} + /** * Set a modem to be a coordinator or not. * diff --git a/flight/pios/inc/pios_rfm22b.h b/flight/pios/inc/pios_rfm22b.h index 14b6fbaa41..6965328396 100644 --- a/flight/pios/inc/pios_rfm22b.h +++ b/flight/pios/inc/pios_rfm22b.h @@ -105,6 +105,7 @@ extern int32_t PIOS_RFM22B_Init(uint32_t *rfb22b_id, uint32_t spi_id, uint32_t s extern void PIOS_RFM22B_Reinit(uint32_t rfb22b_id); extern void PIOS_RFM22B_SetTxPower(uint32_t rfm22b_id, enum rfm22b_tx_power tx_pwr); extern void PIOS_RFM22B_SetChannelConfig(uint32_t rfm22b_id, enum rfm22b_datarate datarate, uint8_t min_chan, uint8_t max_chan, bool coordinator, bool ppm_mode, bool ppm_only); +extern void PIOS_RFM22B_SetXtalCap(uint32_t rfm22b_id, uint8_t xtal_cap); extern void PIOS_RFM22B_SetCoordinatorID(uint32_t rfm22b_id, uint32_t coord_id); extern void PIOS_RFM22B_SetDeviceID(uint32_t rfm22b_id, uint32_t device_id); extern uint32_t PIOS_RFM22B_DeviceID(uint32_t rfb22b_id); diff --git a/ground/gcs/src/plugins/config/oplink.ui b/ground/gcs/src/plugins/config/oplink.ui index 8921518573..46e0aa298b 100644 --- a/ground/gcs/src/plugins/config/oplink.ui +++ b/ground/gcs/src/plugins/config/oplink.ui @@ -1923,7 +1923,8 @@ Leave blank to use autogenerated Device ID. - The xtal capacitor value for fine tune frequency and get a AFC value close to zero. Default value is 127. + Adjust the xtal capacitor value to fine tune frequency and +get an AFC value close to zero. Default value is 127. 171 @@ -1942,7 +1943,8 @@ Leave blank to use autogenerated Device ID. - The xtal capacitor value for fine tune frequency and get a AFC value close to zero. Default value is 127. + Adjust the xtal capacitor value to fine tune frequency and +get an AFC value close to zero. Default value is 127. 171 @@ -1959,7 +1961,8 @@ Leave blank to use autogenerated Device ID. - The Automatic Frequency Correction: How much the modem will correct a frequency misalignement between the two modems. + The Automatic Frequency Correction: How much the modem will correct +a frequency misalignement between the two modems. -50 From 340d3045583c3565f4d56e529aeee58278381d30 Mon Sep 17 00:00:00 2001 From: Laurent Lalanne Date: Fri, 16 Dec 2016 20:27:07 +0100 Subject: [PATCH 044/624] LP-345 Changes from review - Typos - Initialize previousOPLinkSettings --- flight/modules/OPLink/oplinkmod.c | 12 ++++++++---- flight/modules/System/systemmod.c | 11 +++++++---- .../boards/discoveryf4bare/firmware/pios_board.c | 4 ++-- .../targets/boards/oplinkmini/firmware/pios_board.c | 2 +- .../targets/boards/revolution/firmware/pios_board.c | 4 ++-- flight/targets/boards/sparky2/firmware/pios_board.c | 4 ++-- ground/gcs/src/plugins/config/configoplinkwidget.h | 8 ++++---- 7 files changed, 26 insertions(+), 19 deletions(-) diff --git a/flight/modules/OPLink/oplinkmod.c b/flight/modules/OPLink/oplinkmod.c index b5fec42448..8c0b4195a5 100644 --- a/flight/modules/OPLink/oplinkmod.c +++ b/flight/modules/OPLink/oplinkmod.c @@ -16,7 +16,8 @@ * @{ * * @file oplinkmod.c - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012. + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. + * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012. * @brief System module * * @see The GNU Public License (GPL) Version 3 @@ -71,7 +72,7 @@ static OPLinkSettingsData previousOPLinkSettings; // Private functions static void systemTask(void *parameters); -static void checkOPLinkSettingsUpdatedCb(UAVObjEvent *ev); +static void oplinkSettingsUpdatedCb(UAVObjEvent *ev); /** * Create the module task. @@ -135,7 +136,10 @@ static void systemTask(__attribute__((unused)) void *parameters) PIOS_SYS_Reset(); } - OPLinkSettingsConnectCallback(checkOPLinkSettingsUpdatedCb); + // Initialize previousOPLinkSettings used by callback + OPLinkSettingsGet(&previousOPLinkSettings); + + OPLinkSettingsConnectCallback(oplinkSettingsUpdatedCb); // Initialize vars lastSysTime = xTaskGetTickCount(); @@ -249,7 +253,7 @@ void vApplicationMallocFailedHook(void) /** * Called whenever OPLink settings changed */ -static void checkOPLinkSettingsUpdatedCb(__attribute__((unused)) UAVObjEvent *ev) +static void oplinkSettingsUpdatedCb(__attribute__((unused)) UAVObjEvent *ev) { OPLinkSettingsData currentOPLinkSettings; diff --git a/flight/modules/System/systemmod.c b/flight/modules/System/systemmod.c index a1d0a1f6fa..2a911d5bdc 100644 --- a/flight/modules/System/systemmod.c +++ b/flight/modules/System/systemmod.c @@ -16,7 +16,7 @@ * @{ * * @file systemmod.c - * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015. + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015-2016. * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010-2015. * @brief System module * @@ -131,7 +131,7 @@ static uint8_t i2c_error_activity[PIOS_I2C_ERROR_COUNT_NUMELEM]; #ifdef PIOS_INCLUDE_RFM22B static OPLinkSettingsData previousOPLinkSettings; -static void checkOPLinkSettingsUpdatedCb(UAVObjEvent *ev); +static void oplinkSettingsUpdatedCb(UAVObjEvent *ev); #endif extern uintptr_t pios_uavo_settings_fs_id; @@ -237,7 +237,10 @@ static void systemTask(__attribute__((unused)) void *parameters) SystemSettingsConnectCallback(checkSettingsUpdatedCb); #ifdef PIOS_INCLUDE_RFM22B - OPLinkSettingsConnectCallback(checkOPLinkSettingsUpdatedCb); + // Initialize previousOPLinkSettings used by callback + OPLinkSettingsGet(&previousOPLinkSettings); + + OPLinkSettingsConnectCallback(oplinkSettingsUpdatedCb); #endif #ifdef DIAG_TASKS @@ -467,7 +470,7 @@ static void checkSettingsUpdatedCb(__attribute__((unused)) UAVObjEvent *ev) /** * Called whenever OPLink settings changed */ -static void checkOPLinkSettingsUpdatedCb(__attribute__((unused)) UAVObjEvent *ev) +static void oplinkSettingsUpdatedCb(__attribute__((unused)) UAVObjEvent *ev) { OPLinkSettingsData currentOPLinkSettings; diff --git a/flight/targets/boards/discoveryf4bare/firmware/pios_board.c b/flight/targets/boards/discoveryf4bare/firmware/pios_board.c index 77c0f357eb..f1b3cfe80f 100644 --- a/flight/targets/boards/discoveryf4bare/firmware/pios_board.c +++ b/flight/targets/boards/discoveryf4bare/firmware/pios_board.c @@ -761,10 +761,10 @@ void PIOS_Board_Init(void) } /* hwsettings_rm_flexiport */ - /* Initalize the RFM22B radio COM device. */ + /* Initialize the RFM22B radio COM device. */ #if defined(PIOS_INCLUDE_RFM22B) - /* Fetch the OPinkSettings object. */ + /* Fetch the OPLinkSettings object. */ OPLinkSettingsData oplinkSettings; OPLinkSettingsGet(&oplinkSettings); diff --git a/flight/targets/boards/oplinkmini/firmware/pios_board.c b/flight/targets/boards/oplinkmini/firmware/pios_board.c index 14a109b50e..a3dd3f4afd 100644 --- a/flight/targets/boards/oplinkmini/firmware/pios_board.c +++ b/flight/targets/boards/oplinkmini/firmware/pios_board.c @@ -396,7 +396,7 @@ void PIOS_Board_Init(void) PIOS_SYS_SerialNumberGetBinary(oplinkStatus.CPUSerial); oplinkStatus.BoardRevision = bdinfo->board_rev; - /* Initalize the RFM22B radio COM device. */ + /* Initialize the RFM22B radio COM device. */ if (is_enabled) { if (openlrs) { #if defined(PIOS_INCLUDE_OPENLRS) diff --git a/flight/targets/boards/revolution/firmware/pios_board.c b/flight/targets/boards/revolution/firmware/pios_board.c index 7ac8885237..d6fb08c3e4 100644 --- a/flight/targets/boards/revolution/firmware/pios_board.c +++ b/flight/targets/boards/revolution/firmware/pios_board.c @@ -867,10 +867,10 @@ void PIOS_Board_Init(void) GPIO_WriteBit(pios_sbus_cfg.inv.gpio, pios_sbus_cfg.inv.init.GPIO_Pin, pios_sbus_cfg.gpio_inv_disable); } - /* Initalize the RFM22B radio COM device. */ + /* Initialize the RFM22B radio COM device. */ #if defined(PIOS_INCLUDE_RFM22B) - /* Fetch the OPinkSettings object. */ + /* Fetch the OPLinkSettings object. */ OPLinkSettingsData oplinkSettings; OPLinkSettingsGet(&oplinkSettings); diff --git a/flight/targets/boards/sparky2/firmware/pios_board.c b/flight/targets/boards/sparky2/firmware/pios_board.c index 266d35a8a1..9823bf135f 100644 --- a/flight/targets/boards/sparky2/firmware/pios_board.c +++ b/flight/targets/boards/sparky2/firmware/pios_board.c @@ -807,10 +807,10 @@ void PIOS_Board_Init(void) } /* hwsettings_spk2_mainport */ - /* Initalize the RFM22B radio COM device. */ + /* Initialize the RFM22B radio COM device. */ #if defined(PIOS_INCLUDE_RFM22B) - /* Fetch the OPinkSettings object. */ + /* Fetch the OPLinkSettings object. */ OPLinkSettingsData oplinkSettings; OPLinkSettingsGet(&oplinkSettings); diff --git a/ground/gcs/src/plugins/config/configoplinkwidget.h b/ground/gcs/src/plugins/config/configoplinkwidget.h index 9cdb37ee9c..959e28b7d4 100644 --- a/ground/gcs/src/plugins/config/configoplinkwidget.h +++ b/ground/gcs/src/plugins/config/configoplinkwidget.h @@ -46,15 +46,15 @@ class ConfigOPLinkWidget : public ConfigTaskWidget { virtual void refreshWidgetsValuesImpl(UAVObject *obj); private: - // Frequency display settings - float frequency_base; - float frequency_step; - Ui_OPLinkWidget *m_oplink; OPLinkStatus *oplinkStatusObj; OPLinkSettings *oplinkSettingsObj; + // Frequency display settings + float frequency_base; + float frequency_step; + // Is the status current? bool statusUpdated; From 2872a3467ae368d5373d25c53d162b3be5bb8b20 Mon Sep 17 00:00:00 2001 From: Laurent Lalanne Date: Thu, 22 Dec 2016 18:49:19 +0100 Subject: [PATCH 045/624] LP-345 Simplify xtalcap callback check, reuse PIOS_RFM22B_SetXtalCap at boot --- flight/modules/OPLink/oplinkmod.c | 18 +++++++++--------- flight/modules/System/systemmod.c | 18 +++++++++--------- .../discoveryf4bare/firmware/pios_board.c | 3 ++- .../boards/oplinkmini/firmware/pios_board.c | 4 +--- .../targets/boards/revolution/board_hw_defs.c | 4 ++-- .../boards/revolution/firmware/pios_board.c | 5 +---- flight/targets/boards/sparky2/board_hw_defs.c | 2 +- .../boards/sparky2/firmware/pios_board.c | 4 +--- 8 files changed, 26 insertions(+), 32 deletions(-) diff --git a/flight/modules/OPLink/oplinkmod.c b/flight/modules/OPLink/oplinkmod.c index 8c0b4195a5..a1106a1e94 100644 --- a/flight/modules/OPLink/oplinkmod.c +++ b/flight/modules/OPLink/oplinkmod.c @@ -68,7 +68,7 @@ static xTaskHandle systemTaskHandle; static bool stackOverflow; static bool mallocFailed; volatile int initTaskDone = 0; -static OPLinkSettingsData previousOPLinkSettings; +static uint8_t previousRFXtalCap; // Private functions static void systemTask(void *parameters); @@ -136,9 +136,8 @@ static void systemTask(__attribute__((unused)) void *parameters) PIOS_SYS_Reset(); } - // Initialize previousOPLinkSettings used by callback - OPLinkSettingsGet(&previousOPLinkSettings); - + // Initialize previousRFXtalCap used by callback + OPLinkSettingsRFXtalCapGet(&previousRFXtalCap); OPLinkSettingsConnectCallback(oplinkSettingsUpdatedCb); // Initialize vars @@ -255,14 +254,15 @@ void vApplicationMallocFailedHook(void) */ static void oplinkSettingsUpdatedCb(__attribute__((unused)) UAVObjEvent *ev) { - OPLinkSettingsData currentOPLinkSettings; + uint8_t currentRFXtalCap; + + OPLinkSettingsRFXtalCapGet(¤tRFXtalCap); - OPLinkSettingsGet(¤tOPLinkSettings); // Check if RFXtalCap value changed - if (currentOPLinkSettings.RFXtalCap != previousOPLinkSettings.RFXtalCap) { - PIOS_RFM22B_SetXtalCap(pios_rfm22b_id, currentOPLinkSettings.RFXtalCap); + if (currentRFXtalCap != previousRFXtalCap) { + PIOS_RFM22B_SetXtalCap(pios_rfm22b_id, currentRFXtalCap); PIOS_RFM22B_Reinit(pios_rfm22b_id); - previousOPLinkSettings = currentOPLinkSettings; + previousRFXtalCap = currentRFXtalCap; } } diff --git a/flight/modules/System/systemmod.c b/flight/modules/System/systemmod.c index 2a911d5bdc..a09a77fa3f 100644 --- a/flight/modules/System/systemmod.c +++ b/flight/modules/System/systemmod.c @@ -130,7 +130,7 @@ static uint8_t i2c_error_activity[PIOS_I2C_ERROR_COUNT_NUMELEM]; #endif #ifdef PIOS_INCLUDE_RFM22B -static OPLinkSettingsData previousOPLinkSettings; +static uint8_t previousRFXtalCap; static void oplinkSettingsUpdatedCb(UAVObjEvent *ev); #endif @@ -237,9 +237,8 @@ static void systemTask(__attribute__((unused)) void *parameters) SystemSettingsConnectCallback(checkSettingsUpdatedCb); #ifdef PIOS_INCLUDE_RFM22B - // Initialize previousOPLinkSettings used by callback - OPLinkSettingsGet(&previousOPLinkSettings); - + // Initialize previousRFXtalCap used by callback + OPLinkSettingsRFXtalCapGet(&previousRFXtalCap); OPLinkSettingsConnectCallback(oplinkSettingsUpdatedCb); #endif @@ -472,14 +471,15 @@ static void checkSettingsUpdatedCb(__attribute__((unused)) UAVObjEvent *ev) */ static void oplinkSettingsUpdatedCb(__attribute__((unused)) UAVObjEvent *ev) { - OPLinkSettingsData currentOPLinkSettings; + uint8_t currentRFXtalCap; + + OPLinkSettingsRFXtalCapGet(¤tRFXtalCap); - OPLinkSettingsGet(¤tOPLinkSettings); // Check if RFXtalCap value changed - if (currentOPLinkSettings.RFXtalCap != previousOPLinkSettings.RFXtalCap) { - PIOS_RFM22B_SetXtalCap(pios_rfm22b_id, currentOPLinkSettings.RFXtalCap); + if (currentRFXtalCap != previousRFXtalCap) { + PIOS_RFM22B_SetXtalCap(pios_rfm22b_id, currentRFXtalCap); PIOS_RFM22B_Reinit(pios_rfm22b_id); - previousOPLinkSettings = currentOPLinkSettings; + previousRFXtalCap = currentRFXtalCap; } } #endif /* ifdef PIOS_INCLUDE_RFM22B */ diff --git a/flight/targets/boards/discoveryf4bare/firmware/pios_board.c b/flight/targets/boards/discoveryf4bare/firmware/pios_board.c index f1b3cfe80f..fe2559b326 100644 --- a/flight/targets/boards/discoveryf4bare/firmware/pios_board.c +++ b/flight/targets/boards/discoveryf4bare/firmware/pios_board.c @@ -825,8 +825,9 @@ void PIOS_Board_Init(void) /* Set the radio configuration parameters. */ PIOS_RFM22B_SetDeviceID(pios_rfm22b_id, oplinkSettings.CustomDeviceID); - PIOS_RFM22B_SetChannelConfig(pios_rfm22b_id, datarate, oplinkSettings.MinChannel, oplinkSettings.MaxChannel, is_coordinator, is_oneway, ppm_mode, ppm_only); PIOS_RFM22B_SetCoordinatorID(pios_rfm22b_id, oplinkSettings.CoordID); + PIOS_RFM22B_SetXtalCap(pios_rfm22b_id, oplinkSettings.RFXtalCap); + PIOS_RFM22B_SetChannelConfig(pios_rfm22b_id, datarate, oplinkSettings.MinChannel, oplinkSettings.MaxChannel, is_coordinator, data_mode, ppm_mode); /* Set the PPM callback if we should be receiving PPM. */ if (ppm_mode || (ppm_only && !is_coordinator)) { diff --git a/flight/targets/boards/oplinkmini/firmware/pios_board.c b/flight/targets/boards/oplinkmini/firmware/pios_board.c index a3dd3f4afd..f1e3b78a59 100644 --- a/flight/targets/boards/oplinkmini/firmware/pios_board.c +++ b/flight/targets/boards/oplinkmini/firmware/pios_board.c @@ -414,9 +414,6 @@ void PIOS_Board_Init(void) // Configure the RFM22B device const struct pios_rfm22b_cfg *rfm22b_cfg = PIOS_BOARD_HW_DEFS_GetRfm22Cfg(bdinfo->board_rev); - // Set the Xtal capacitor value - pios_rfm22b_cfg.RFXtalCap = oplinkSettings.RFXtalCap; - if (PIOS_RFM22B_Init(&pios_rfm22b_id, PIOS_RFM22_SPI_PORT, rfm22b_cfg->slave_num, rfm22b_cfg, oplinkSettings.RFBand)) { PIOS_Assert(0); } @@ -489,6 +486,7 @@ void PIOS_Board_Init(void) // Set the radio configuration parameters. PIOS_RFM22B_SetDeviceID(pios_rfm22b_id, oplinkSettings.CustomDeviceID); PIOS_RFM22B_SetCoordinatorID(pios_rfm22b_id, oplinkSettings.CoordID); + PIOS_RFM22B_SetXtalCap(pios_rfm22b_id, oplinkSettings.RFXtalCap); PIOS_RFM22B_SetChannelConfig(pios_rfm22b_id, datarate, oplinkSettings.MinChannel, oplinkSettings.MaxChannel, is_coordinator, data_mode, ppm_mode); /* Set the PPM callback if we should be receiving PPM. */ diff --git a/flight/targets/boards/revolution/board_hw_defs.c b/flight/targets/boards/revolution/board_hw_defs.c index 251e6a5f53..74770d9804 100644 --- a/flight/targets/boards/revolution/board_hw_defs.c +++ b/flight/targets/boards/revolution/board_hw_defs.c @@ -640,7 +640,7 @@ static const struct pios_exti_cfg pios_exti_rfm22b_cfg __exti_config = { }, }; -struct pios_rfm22b_cfg pios_rfm22b_rm1_cfg = { +const struct pios_rfm22b_cfg pios_rfm22b_rm1_cfg = { .spi_cfg = &pios_spi_telem_flash_cfg, .exti_cfg = &pios_exti_rfm22b_cfg, .RFXtalCap = 0x7f, @@ -648,7 +648,7 @@ struct pios_rfm22b_cfg pios_rfm22b_rm1_cfg = { .gpio_direction = GPIO0_RX_GPIO1_TX, }; -struct pios_rfm22b_cfg pios_rfm22b_rm2_cfg = { +const struct pios_rfm22b_cfg pios_rfm22b_rm2_cfg = { .spi_cfg = &pios_spi_telem_flash_cfg, .exti_cfg = &pios_exti_rfm22b_cfg, .RFXtalCap = 0x7f, diff --git a/flight/targets/boards/revolution/firmware/pios_board.c b/flight/targets/boards/revolution/firmware/pios_board.c index d6fb08c3e4..15b0a2f9b9 100644 --- a/flight/targets/boards/revolution/firmware/pios_board.c +++ b/flight/targets/boards/revolution/firmware/pios_board.c @@ -913,10 +913,6 @@ void PIOS_Board_Init(void) /* Configure the RFM22B device. */ const struct pios_rfm22b_cfg *rfm22b_cfg = PIOS_BOARD_HW_DEFS_GetRfm22Cfg(bdinfo->board_rev); - // Set the Xtal capacitor value - pios_rfm22b_rm1_cfg.RFXtalCap = oplinkSettings.RFXtalCap; - pios_rfm22b_rm2_cfg.RFXtalCap = oplinkSettings.RFXtalCap; - if (PIOS_RFM22B_Init(&pios_rfm22b_id, PIOS_RFM22_SPI_PORT, rfm22b_cfg->slave_num, rfm22b_cfg, oplinkSettings.RFBand)) { PIOS_Assert(0); } @@ -960,6 +956,7 @@ void PIOS_Board_Init(void) /* Set the radio configuration parameters. */ PIOS_RFM22B_SetDeviceID(pios_rfm22b_id, oplinkSettings.CustomDeviceID); PIOS_RFM22B_SetCoordinatorID(pios_rfm22b_id, oplinkSettings.CoordID); + PIOS_RFM22B_SetXtalCap(pios_rfm22b_id, oplinkSettings.RFXtalCap); PIOS_RFM22B_SetChannelConfig(pios_rfm22b_id, datarate, oplinkSettings.MinChannel, oplinkSettings.MaxChannel, is_coordinator, data_mode, ppm_mode); /* Set the PPM callback if we should be receiving PPM. */ diff --git a/flight/targets/boards/sparky2/board_hw_defs.c b/flight/targets/boards/sparky2/board_hw_defs.c index 2c63d0fcf2..25afb14e23 100644 --- a/flight/targets/boards/sparky2/board_hw_defs.c +++ b/flight/targets/boards/sparky2/board_hw_defs.c @@ -431,7 +431,7 @@ static const struct pios_exti_cfg pios_exti_rfm22b_cfg __exti_config = { }, }; -struct pios_rfm22b_cfg pios_rfm22b_cfg = { +const struct pios_rfm22b_cfg pios_rfm22b_cfg = { .spi_cfg = &pios_spi_telem_flash_cfg, .exti_cfg = &pios_exti_rfm22b_cfg, .RFXtalCap = 0x7f, diff --git a/flight/targets/boards/sparky2/firmware/pios_board.c b/flight/targets/boards/sparky2/firmware/pios_board.c index 9823bf135f..c73b96aea5 100644 --- a/flight/targets/boards/sparky2/firmware/pios_board.c +++ b/flight/targets/boards/sparky2/firmware/pios_board.c @@ -853,9 +853,6 @@ void PIOS_Board_Init(void) /* Configure the RFM22B device. */ const struct pios_rfm22b_cfg *rfm22b_cfg = PIOS_BOARD_HW_DEFS_GetRfm22Cfg(bdinfo->board_rev); - // Set the Xtal capacitor value - pios_rfm22b_cfg.RFXtalCap = oplinkSettings.RFXtalCap; - if (PIOS_RFM22B_Init(&pios_rfm22b_id, PIOS_RFM22_SPI_PORT, rfm22b_cfg->slave_num, rfm22b_cfg, oplinkSettings.RFBand)) { PIOS_Assert(0); } @@ -899,6 +896,7 @@ void PIOS_Board_Init(void) /* Set the radio configuration parameters. */ PIOS_RFM22B_SetDeviceID(pios_rfm22b_id, oplinkSettings.CustomDeviceID); PIOS_RFM22B_SetCoordinatorID(pios_rfm22b_id, oplinkSettings.CoordID); + PIOS_RFM22B_SetXtalCap(pios_rfm22b_id, oplinkSettings.RFXtalCap); PIOS_RFM22B_SetChannelConfig(pios_rfm22b_id, datarate, oplinkSettings.MinChannel, oplinkSettings.MaxChannel, is_coordinator, data_mode, ppm_mode); /* Set the PPM callback if we should be receiving PPM. */ From ad0d18cfef6a5f7132d7b06d43b7e35d3a36463f Mon Sep 17 00:00:00 2001 From: Laurent Lalanne Date: Wed, 21 Dec 2016 03:16:29 +0100 Subject: [PATCH 046/624] LP-428 Handle different threshold levels for sticks and switches --- flight/modules/ManualControl/armhandler.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/flight/modules/ManualControl/armhandler.c b/flight/modules/ManualControl/armhandler.c index a93586da44..6d067e2db2 100644 --- a/flight/modules/ManualControl/armhandler.c +++ b/flight/modules/ManualControl/armhandler.c @@ -41,8 +41,9 @@ #endif // Private constants -#define ARMED_THRESHOLD 0.20f -#define GROUND_LOW_THROTTLE 0.01f +#define ARMED_THRESHOLD_SWITCH 0.20f +#define ARMED_THRESHOLD_STICK 0.80f +#define GROUND_LOW_THROTTLE 0.01f // Private types typedef enum { @@ -116,7 +117,7 @@ void armHandler(bool newinit, FrameType_t frameType) } // immediate disarm on switch - if (armSwitch && acc.AccessoryVal <= -ARMED_THRESHOLD) { + if (armSwitch && acc.AccessoryVal <= -ARMED_THRESHOLD_SWITCH) { lowThrottle = true; } @@ -209,9 +210,11 @@ void armHandler(bool newinit, FrameType_t frameType) previousArmingInputLevel = 0.0f; } - if ((armingInputLevel <= -ARMED_THRESHOLD) && (previousArmingInputLevel > -ARMED_THRESHOLD)) { + float armedThreshold = armSwitch ? ARMED_THRESHOLD_SWITCH : ARMED_THRESHOLD_STICK; + + if ((armingInputLevel <= -armedThreshold) && (previousArmingInputLevel > -armedThreshold)) { manualArm = true; - } else if ((armingInputLevel >= +ARMED_THRESHOLD) && (previousArmingInputLevel < +ARMED_THRESHOLD)) { + } else if ((armingInputLevel >= +armedThreshold) && (previousArmingInputLevel < +armedThreshold)) { manualDisarm = true; } From 2e854b263f5e53f062ee31f84b4f1584d5719176 Mon Sep 17 00:00:00 2001 From: Laurent Lalanne Date: Fri, 23 Dec 2016 15:34:47 +0100 Subject: [PATCH 047/624] LP-428 Remove unused define --- flight/modules/Receiver/receiver.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/flight/modules/Receiver/receiver.c b/flight/modules/Receiver/receiver.c index 7c30dd7b1e..68eff18aa0 100644 --- a/flight/modules/Receiver/receiver.c +++ b/flight/modules/Receiver/receiver.c @@ -64,8 +64,7 @@ #define TASK_PRIORITY (tskIDLE_PRIORITY + 3) // 3 = flight control #define UPDATE_PERIOD_MS 20 -#define THROTTLE_FAILSAFE -0.1f -#define ARMED_THRESHOLD 0.50f + // safe band to allow a bit of calibration error or trim offset (in microseconds) #define CONNECTION_OFFSET 250 From e0fcb92698bc6e55a14e85a03d556eaeaac14064 Mon Sep 17 00:00:00 2001 From: Laurent Lalanne Date: Sun, 25 Dec 2016 12:49:55 +0100 Subject: [PATCH 048/624] LP-345 Set correct RSSI unit - Define tab navigation order --- .../src/plugins/config/configoplinkwidget.cpp | 2 +- ground/gcs/src/plugins/config/oplink.ui | 108 +++++++++++++++++- 2 files changed, 106 insertions(+), 4 deletions(-) diff --git a/ground/gcs/src/plugins/config/configoplinkwidget.cpp b/ground/gcs/src/plugins/config/configoplinkwidget.cpp index 87ecf8255f..634cab08dc 100644 --- a/ground/gcs/src/plugins/config/configoplinkwidget.cpp +++ b/ground/gcs/src/plugins/config/configoplinkwidget.cpp @@ -174,7 +174,7 @@ void ConfigOPLinkWidget::updateStatus() bool linkConnected = (oplinkStatusObj->linkState() == OPLinkStatus_LinkState::Connected); m_oplink->PairSignalStrengthBar1->setValue(linkConnected ? m_oplink->RSSI->text().toInt() : -127); - m_oplink->PairSignalStrengthLabel1->setText(QString("%1dB").arg(m_oplink->PairSignalStrengthBar1->value())); + m_oplink->PairSignalStrengthLabel1->setText(QString("%1dBm").arg(m_oplink->PairSignalStrengthBar1->value())); int afc_valueKHz = m_oplink->AFCCorrection->text().toInt() / 1000; m_oplink->AFCCorrectionBar->setValue(afc_valueKHz); diff --git a/ground/gcs/src/plugins/config/oplink.ui b/ground/gcs/src/plugins/config/oplink.ui index 46e0aa298b..5e6dfca6ff 100644 --- a/ground/gcs/src/plugins/config/oplink.ui +++ b/ground/gcs/src/plugins/config/oplink.ui @@ -16,6 +16,9 @@ + + Qt::NoFocus + OPLink Configuration @@ -38,6 +41,9 @@ + + Qt::NoFocus + QFrame::NoFrame @@ -367,6 +373,9 @@ Leave blank to use autogenerated Device ID. + + Qt::NoFocus + Clear the binding/coordinator ID @@ -708,7 +717,7 @@ Leave blank to use autogenerated Device ID. - -100dB + -100dBm Qt::AlignCenter @@ -872,6 +881,9 @@ Leave blank to use autogenerated Device ID. false + + Qt::NoFocus + false @@ -909,6 +921,12 @@ Leave blank to use autogenerated Device ID. false + + Qt::NoFocus + + + true + 8 @@ -968,6 +986,9 @@ Leave blank to use autogenerated Device ID. false + + Qt::NoFocus + The modems current state. @@ -1034,6 +1055,9 @@ Leave blank to use autogenerated Device ID. false + + Qt::NoFocus + false @@ -1062,6 +1086,9 @@ Leave blank to use autogenerated Device ID. false + + Qt::NoFocus + false @@ -1106,6 +1133,9 @@ Leave blank to use autogenerated Device ID. false + + Qt::NoFocus + false @@ -1156,6 +1186,9 @@ Leave blank to use autogenerated Device ID. false + + Qt::NoFocus + The percentage of packets that were corrected with error correction @@ -1197,6 +1230,9 @@ Leave blank to use autogenerated Device ID. false + + Qt::NoFocus + false @@ -1231,6 +1267,9 @@ Leave blank to use autogenerated Device ID. false + + Qt::NoFocus + The percentage of packets that were corrected with error correction @@ -1256,6 +1295,9 @@ Leave blank to use autogenerated Device ID. false + + Qt::NoFocus + false @@ -1332,6 +1374,9 @@ Leave blank to use autogenerated Device ID. false + + Qt::NoFocus + true @@ -1399,6 +1444,9 @@ Leave blank to use autogenerated Device ID. false + + Qt::NoFocus + false @@ -1459,6 +1507,9 @@ Leave blank to use autogenerated Device ID. false + + Qt::NoFocus + false @@ -1487,6 +1538,9 @@ Leave blank to use autogenerated Device ID. false + + Qt::NoFocus + The percentage of packets that could not be corrected with error correction @@ -1524,6 +1578,9 @@ Leave blank to use autogenerated Device ID. false + + Qt::NoFocus + The percentage of packets that were not received at all @@ -1549,6 +1606,9 @@ Leave blank to use autogenerated Device ID. false + + Qt::NoFocus + false @@ -1571,6 +1631,9 @@ Leave blank to use autogenerated Device ID. false + + Qt::NoFocus + true @@ -1628,6 +1691,9 @@ Leave blank to use autogenerated Device ID. false + + Qt::NoFocus + The number of packets that were unable to be transmitted @@ -1697,6 +1763,9 @@ Leave blank to use autogenerated Device ID. false + + Qt::NoFocus + The percentage of packets that were not received at all @@ -1744,6 +1813,9 @@ Leave blank to use autogenerated Device ID. false + + Qt::NoFocus + false @@ -1766,6 +1838,9 @@ Leave blank to use autogenerated Device ID. false + + Qt::NoFocus + false @@ -1820,6 +1895,9 @@ Leave blank to use autogenerated Device ID. false + + Qt::NoFocus + false @@ -1842,6 +1920,9 @@ Leave blank to use autogenerated Device ID. false + + Qt::NoFocus + false @@ -1881,6 +1962,9 @@ Leave blank to use autogenerated Device ID. 16777215 + + Qt::NoFocus + The automatic frequency correction in Hz. @@ -1922,6 +2006,9 @@ Leave blank to use autogenerated Device ID. + + Qt::NoFocus + Adjust the xtal capacitor value to fine tune frequency and get an AFC value close to zero. Default value is 127. @@ -2040,6 +2127,9 @@ a frequency misalignement between the two modems. 25 + + Qt::NoFocus + @@ -2097,8 +2187,20 @@ a frequency misalignement between the two modems. - FirmwareVersion - SerialNumber + Protocol + MaxRFTxPower + LinkType + ComSpeed + CustomDeviceID + CoordID + UnbindButton + RFBand + MaximumChannel + MinimumChannel + MainPort + FlexiPort + VCPPort + RFXtalCapValue applyButton saveButton From 530b07872a2b25e6e085b9d8a669a6405f2b726e Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Tue, 27 Dec 2016 16:33:44 +0100 Subject: [PATCH 049/624] LP-460 remove spurious line edit at bottom of UAVObjectBrowser --- ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowser.ui | 1 - 1 file changed, 1 deletion(-) diff --git a/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowser.ui b/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowser.ui index 54a937b6fc..68f28140ab 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowser.ui +++ b/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowser.ui @@ -307,7 +307,6 @@ This space shows a description of the selected UAVObject. - From 7e6494c8a8c7249ac692ce842e1d37863a9885b8 Mon Sep 17 00:00:00 2001 From: Vladimir Zidar Date: Sat, 24 Sep 2016 02:28:45 +0200 Subject: [PATCH 050/624] LP-415 New functions PIOS_Servo_Disable(), PIOS_Servo_Enable() and PIOS_Servo_Config(). Moved timer initialization code to _Enable() function. Removed call to PIOS_TIM_InitChannels(). --- flight/pios/inc/pios_servo.h | 9 +- flight/pios/inc/pios_servo_priv.h | 1 + flight/pios/stm32f4xx/pios_servo.c | 134 ++++++++++++++++++----------- 3 files changed, 94 insertions(+), 50 deletions(-) diff --git a/flight/pios/inc/pios_servo.h b/flight/pios/inc/pios_servo.h index f3e9621ada..f158d4e61e 100644 --- a/flight/pios/inc/pios_servo.h +++ b/flight/pios/inc/pios_servo.h @@ -32,8 +32,9 @@ /* Global types */ enum pios_servo_bank_mode { - PIOS_SERVO_BANK_MODE_PWM = 0, - PIOS_SERVO_BANK_MODE_SINGLE_PULSE = 1 + PIOS_SERVO_BANK_MODE_NONE = 0, + PIOS_SERVO_BANK_MODE_PWM = 1, + PIOS_SERVO_BANK_MODE_SINGLE_PULSE = 2 }; /* Public Functions */ extern void PIOS_Servo_SetHz(const uint16_t *speeds, const uint32_t *clock, uint8_t banks); @@ -42,6 +43,10 @@ extern void PIOS_Servo_Update(); extern void PIOS_Servo_SetBankMode(uint8_t bank, uint8_t mode); extern uint8_t PIOS_Servo_GetPinBank(uint8_t pin); +/* ESC Bridge support */ +extern void PIOS_Servo_Disable(); +extern void PIOS_Servo_Enable(); + #endif /* PIOS_SERVO_H */ /** diff --git a/flight/pios/inc/pios_servo_priv.h b/flight/pios/inc/pios_servo_priv.h index be692cc269..3b19e14f9b 100644 --- a/flight/pios/inc/pios_servo_priv.h +++ b/flight/pios/inc/pios_servo_priv.h @@ -45,6 +45,7 @@ struct pios_servo_cfg { }; extern int32_t PIOS_Servo_Init(const struct pios_servo_cfg *cfg); +const struct pios_servo_cfg *PIOS_Servo_Config(); #endif /* PIOS_SERVO_PRIV_H */ diff --git a/flight/pios/stm32f4xx/pios_servo.c b/flight/pios/stm32f4xx/pios_servo.c index 84a450b7fd..fb37b364c8 100644 --- a/flight/pios/stm32f4xx/pios_servo.c +++ b/flight/pios/stm32f4xx/pios_servo.c @@ -50,19 +50,83 @@ static TIM_TypeDef *pios_servo_bank_timer[PIOS_SERVO_BANKS] = { 0 }; // index of bank used for each pin static uint8_t *pios_servo_pin_bank; +static bool pios_servo_enabled = true; + #define PIOS_SERVO_TIMER_CLOCK 1000000 #define PIOS_SERVO_SAFE_MARGIN 50 + +extern void PIOS_Servo_Disable() +{ + if (!servo_cfg) { + return; + } + pios_servo_enabled = false; + + /* NOTE: Following will stop pulses and force low level on output pins. + * this is ok with ESC and servos, but brushed motors could be in trouble + * if using inverted setup */ + + for (uint8_t i = 0; (i < servo_cfg->num_channels); i++) { + const struct pios_tim_channel *chan = &servo_cfg->channels[i]; + + GPIO_InitTypeDef init = chan->pin.init; + + init.GPIO_Mode = GPIO_Mode_OUT; + GPIO_Init(chan->pin.gpio, &init); + + GPIO_ResetBits(chan->pin.gpio, chan->pin.init.GPIO_Pin); + } +} + +extern void PIOS_Servo_Enable() +{ + if (!servo_cfg) { + return; + } + + for (uint8_t i = 0; (i < servo_cfg->num_channels); i++) { + const struct pios_tim_channel *chan = &servo_cfg->channels[i]; + + GPIO_Init(chan->pin.gpio, &chan->pin.init); + + /* Set up for output compare function */ + switch (chan->timer_chan) { + case TIM_Channel_1: + TIM_OC1Init(chan->timer, &servo_cfg->tim_oc_init); + TIM_OC1PreloadConfig(chan->timer, TIM_OCPreload_Enable); + break; + case TIM_Channel_2: + TIM_OC2Init(chan->timer, &servo_cfg->tim_oc_init); + TIM_OC2PreloadConfig(chan->timer, TIM_OCPreload_Enable); + break; + case TIM_Channel_3: + TIM_OC3Init(chan->timer, &servo_cfg->tim_oc_init); + TIM_OC3PreloadConfig(chan->timer, TIM_OCPreload_Enable); + break; + case TIM_Channel_4: + TIM_OC4Init(chan->timer, &servo_cfg->tim_oc_init); + TIM_OC4PreloadConfig(chan->timer, TIM_OCPreload_Enable); + break; + } + } + + for (uint8_t i = 0; (i < PIOS_SERVO_BANKS); i++) { + TIM_TypeDef *timer = pios_servo_bank_timer[i]; + + if (timer && (pios_servo_bank_mode[i] != PIOS_SERVO_BANK_MODE_NONE)) { + TIM_SelectOnePulseMode(timer, TIM_OPMode_Repetitive); + TIM_Cmd(timer, ENABLE); + } + } + + pios_servo_enabled = true; +} + /** * Initialise Servos */ int32_t PIOS_Servo_Init(const struct pios_servo_cfg *cfg) { - uint32_t tim_id; - - if (PIOS_TIM_InitChannels(&tim_id, cfg->channels, cfg->num_channels, NULL, 0)) { - return -1; - } - /* Store away the requested configuration */ servo_cfg = cfg; pios_servo_pin_bank = pios_malloc(sizeof(uint8_t) * cfg->num_channels); @@ -91,28 +155,10 @@ int32_t PIOS_Servo_Init(const struct pios_servo_cfg *cfg) bank++; } - - /* Set up for output compare function */ - switch (chan->timer_chan) { - case TIM_Channel_1: - TIM_OC1Init(chan->timer, &servo_cfg->tim_oc_init); - TIM_OC1PreloadConfig(chan->timer, TIM_OCPreload_Enable); - break; - case TIM_Channel_2: - TIM_OC2Init(chan->timer, &servo_cfg->tim_oc_init); - TIM_OC2PreloadConfig(chan->timer, TIM_OCPreload_Enable); - break; - case TIM_Channel_3: - TIM_OC3Init(chan->timer, &servo_cfg->tim_oc_init); - TIM_OC3PreloadConfig(chan->timer, TIM_OCPreload_Enable); - break; - case TIM_Channel_4: - TIM_OC4Init(chan->timer, &servo_cfg->tim_oc_init); - TIM_OC4PreloadConfig(chan->timer, TIM_OCPreload_Enable); - break; - } } + PIOS_Servo_Enable(); + return 0; } @@ -121,28 +167,11 @@ void PIOS_Servo_SetBankMode(uint8_t bank, uint8_t mode) PIOS_Assert(bank < PIOS_SERVO_BANKS); pios_servo_bank_mode[bank] = mode; - if (pios_servo_bank_timer[bank]) { - for (uint8_t i = 0; (i < servo_cfg->num_channels); i++) { - if (pios_servo_pin_bank[i] == bank) { - const struct pios_tim_channel *chan = &servo_cfg->channels[i]; - /* Set up for output compare function */ - switch (chan->timer_chan) { - case TIM_Channel_1: - TIM_OC1PolarityConfig(chan->timer, TIM_OCPolarity_High); - break; - case TIM_Channel_2: - TIM_OC2PolarityConfig(chan->timer, TIM_OCPolarity_High); - break; - case TIM_Channel_3: - TIM_OC3PolarityConfig(chan->timer, TIM_OCPolarity_High); - break; - case TIM_Channel_4: - TIM_OC4PolarityConfig(chan->timer, TIM_OCPolarity_High); - break; - } - } - } + if (!pios_servo_enabled) { + return; + } + if (pios_servo_bank_timer[bank]) { // Setup the timer accordingly TIM_SelectOnePulseMode(pios_servo_bank_timer[bank], TIM_OPMode_Repetitive); TIM_Cmd(pios_servo_bank_timer[bank], ENABLE); @@ -152,6 +181,10 @@ void PIOS_Servo_SetBankMode(uint8_t bank, uint8_t mode) void PIOS_Servo_Update() { + if (!pios_servo_enabled) { + return; + } + for (uint8_t i = 0; (i < PIOS_SERVO_BANKS); i++) { const TIM_TypeDef *timer = pios_servo_bank_timer[i]; if (timer && pios_servo_bank_mode[i] == PIOS_SERVO_BANK_MODE_SINGLE_PULSE) { @@ -231,7 +264,7 @@ void PIOS_Servo_SetHz(const uint16_t *speeds, const uint32_t *clock, uint8_t ban void PIOS_Servo_Set(uint8_t servo, uint16_t position) { /* Make sure servo exists */ - if (!servo_cfg || servo >= servo_cfg->num_channels) { + if (!pios_servo_enabled || !servo_cfg || servo >= servo_cfg->num_channels) { return; } @@ -273,4 +306,9 @@ uint8_t PIOS_Servo_GetPinBank(uint8_t pin) } } +const struct pios_servo_cfg *PIOS_Servo_Config() +{ + return servo_cfg; +} + #endif /* PIOS_INCLUDE_SERVO */ From dad4a940367a06295acf46129f5e3f9c224d8f3b Mon Sep 17 00:00:00 2001 From: Vladimir Zidar Date: Sat, 24 Sep 2016 02:39:22 +0200 Subject: [PATCH 051/624] LP-415 Consolidate F1 & F4 version into single one that lives in pios/common/ --- flight/make/apps-defs.mk | 1 + .../pios/{stm32f4xx => common}/pios_servo.c | 27 +- flight/pios/stm32f10x/pios_servo.c | 283 ------------------ .../targets/boards/coptercontrol/pios_board.h | 47 +-- flight/targets/boards/oplinkmini/pios_board.h | 13 +- 5 files changed, 56 insertions(+), 315 deletions(-) rename flight/pios/{stm32f4xx => common}/pios_servo.c (92%) delete mode 100644 flight/pios/stm32f10x/pios_servo.c diff --git a/flight/make/apps-defs.mk b/flight/make/apps-defs.mk index d4d89ce31f..475609c03f 100644 --- a/flight/make/apps-defs.mk +++ b/flight/make/apps-defs.mk @@ -96,6 +96,7 @@ SRC += $(PIOSCOMMON)/pios_exbus.c SRC += $(PIOSCOMMON)/pios_ibus.c SRC += $(PIOSCOMMON)/pios_sdcard.c SRC += $(PIOSCOMMON)/pios_sensors.c +SRC += $(PIOSCOMMON)/pios_servo.c SRC += $(PIOSCOMMON)/pios_openlrs.c SRC += $(PIOSCOMMON)/pios_openlrs_rcvr.c diff --git a/flight/pios/stm32f4xx/pios_servo.c b/flight/pios/common/pios_servo.c similarity index 92% rename from flight/pios/stm32f4xx/pios_servo.c rename to flight/pios/common/pios_servo.c index fb37b364c8..4669b3f29e 100644 --- a/flight/pios/stm32f4xx/pios_servo.c +++ b/flight/pios/common/pios_servo.c @@ -71,7 +71,13 @@ extern void PIOS_Servo_Disable() GPIO_InitTypeDef init = chan->pin.init; +#if defined(STM32F40_41xxx) || defined(STM32F446xx) init.GPIO_Mode = GPIO_Mode_OUT; +#elif defined(STM32F10X_MD) + init.GPIO_Mode = GPIO_Mode_Out_PP; +#else +#error Unsupported MCU +#endif GPIO_Init(chan->pin.gpio, &init); GPIO_ResetBits(chan->pin.gpio, chan->pin.init.GPIO_Pin); @@ -244,13 +250,28 @@ void PIOS_Servo_SetHz(const uint16_t *speeds, const uint32_t *clock, uint8_t ban if (clock[i]) { new_clock = clock[i]; } + + uint32_t apb_clock; + // Choose the correct prescaler value for the APB the timer is attached + +#if defined(STM32F10X_MD) + if (timer == TIM1 || timer == TIM8) { + apb_clock = PIOS_PERIPHERAL_APB2_CLOCK; + } else { + apb_clock = PIOS_PERIPHERAL_APB1_CLOCK; + } +#elif defined(STM32F40_41xxx) || defined(STM32F446xx) if (timer == TIM1 || timer == TIM8 || timer == TIM9 || timer == TIM10 || timer == TIM11) { - TIM_TimeBaseStructure.TIM_Prescaler = (PIOS_PERIPHERAL_APB2_CLOCK / new_clock) - 1; + apb_clock = PIOS_PERIPHERAL_APB2_CLOCK; } else { - TIM_TimeBaseStructure.TIM_Prescaler = (PIOS_PERIPHERAL_APB1_CLOCK / new_clock) - 1; + apb_clock = PIOS_PERIPHERAL_APB1_CLOCK; } - TIM_TimeBaseStructure.TIM_Period = ((new_clock / speeds[i]) - 1); +#else +#error Unsupported MCU +#endif + TIM_TimeBaseStructure.TIM_Prescaler = (apb_clock / new_clock) - 1; + TIM_TimeBaseStructure.TIM_Period = ((new_clock / speeds[i]) - 1); TIM_TimeBaseInit((TIM_TypeDef *)timer, &TIM_TimeBaseStructure); } } diff --git a/flight/pios/stm32f10x/pios_servo.c b/flight/pios/stm32f10x/pios_servo.c deleted file mode 100644 index 76da3d33a5..0000000000 --- a/flight/pios/stm32f10x/pios_servo.c +++ /dev/null @@ -1,283 +0,0 @@ -/** - ****************************************************************************** - * @addtogroup PIOS PIOS Core hardware abstraction layer - * @{ - * @addtogroup PIOS_SERVO RC Servo Functions - * @brief Code to do set RC servo output - * @{ - * - * @file pios_servo.c - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * @brief RC Servo routines (STM32 dependent) - * @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.h" - -#ifdef PIOS_INCLUDE_SERVO - -#include "pios_servo_priv.h" -#include "pios_tim_priv.h" - -/* Private Function Prototypes */ - -static const struct pios_servo_cfg *servo_cfg; - -// determine if the related timer will work in synchronous (or OneShot/OneShot125) One Pulse mode. -static uint8_t pios_servo_bank_mode[PIOS_SERVO_BANKS] = { 0 }; -// used to skip updates when pulse length is higher than update cycle -static uint16_t pios_servo_bank_next_update[PIOS_SERVO_BANKS] = { 0 }; -static uint16_t pios_servo_bank_max_pulse[PIOS_SERVO_BANKS] = { 0 }; -// timer associated to each bank -static TIM_TypeDef *pios_servo_bank_timer[PIOS_SERVO_BANKS] = { 0 }; - -// index of bank used for each pin -static uint8_t *pios_servo_pin_bank; - -#define PIOS_SERVO_TIMER_CLOCK 1000000 -#define PIOS_SERVO_SAFE_MARGIN 50 -/** - * Initialise Servos - */ -int32_t PIOS_Servo_Init(const struct pios_servo_cfg *cfg) -{ - uint32_t tim_id; - - if (PIOS_TIM_InitChannels(&tim_id, cfg->channels, cfg->num_channels, NULL, 0)) { - return -1; - } - - /* Store away the requested configuration */ - servo_cfg = cfg; - pios_servo_pin_bank = pios_malloc(sizeof(uint8_t) * cfg->num_channels); - - uint8_t bank = 0; - /* Configure the channels to be in output compare mode */ - for (uint8_t i = 0; i < cfg->num_channels; i++) { - const struct pios_tim_channel *chan = &servo_cfg->channels[i]; - bool new = true; - /* See if any previous channels use that same timer */ - for (uint8_t j = 0; (j < i) && new; j++) { - new &= chan->timer != servo_cfg->channels[j].timer; - } - - if (new) { - PIOS_Assert(bank < PIOS_SERVO_BANKS); - for (uint8_t j = i; j < servo_cfg->num_channels; j++) { - if (servo_cfg->channels[j].timer == chan->timer) { - pios_servo_pin_bank[j] = bank; - } - } - pios_servo_bank_timer[bank] = chan->timer; - - PIOS_Assert(bank < PIOS_SERVO_BANKS); - - for (uint8_t j = i; j < servo_cfg->num_channels; j++) { - if (servo_cfg->channels[j].timer == chan->timer) { - pios_servo_pin_bank[j] = bank; - } - } - pios_servo_bank_timer[bank] = chan->timer; - - TIM_ARRPreloadConfig(chan->timer, ENABLE); - TIM_CtrlPWMOutputs(chan->timer, ENABLE); - TIM_Cmd(chan->timer, ENABLE); - - bank++; - } - - /* Set up for output compare function */ - switch (chan->timer_chan) { - case TIM_Channel_1: - TIM_OC1Init(chan->timer, &cfg->tim_oc_init); - TIM_OC1PreloadConfig(chan->timer, TIM_OCPreload_Enable); - break; - case TIM_Channel_2: - TIM_OC2Init(chan->timer, &cfg->tim_oc_init); - TIM_OC2PreloadConfig(chan->timer, TIM_OCPreload_Enable); - break; - case TIM_Channel_3: - TIM_OC3Init(chan->timer, &cfg->tim_oc_init); - TIM_OC3PreloadConfig(chan->timer, TIM_OCPreload_Enable); - break; - case TIM_Channel_4: - TIM_OC4Init(chan->timer, &cfg->tim_oc_init); - TIM_OC4PreloadConfig(chan->timer, TIM_OCPreload_Enable); - break; - } - } - - return 0; -} - -/** - * Set the servo update rate (Max 500Hz) - * \param[in] array of rates in Hz - * \param[in] array of timer clocks in Hz - * \param[in] maximum number of banks - */ -void PIOS_Servo_SetHz(const uint16_t *speeds, const uint32_t *clock, uint8_t banks) -{ - PIOS_Assert(banks <= PIOS_SERVO_BANKS); - if (!servo_cfg) { - return; - } - - TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure = servo_cfg->tim_base_init; - TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; - TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; - - for (uint8_t i = 0; i < banks && i < PIOS_SERVO_BANKS; i++) { - const TIM_TypeDef *timer = pios_servo_bank_timer[i]; - if (timer) { - uint32_t new_clock = PIOS_SERVO_TIMER_CLOCK; - if (clock[i]) { - new_clock = clock[i]; - } - TIM_TimeBaseStructure.TIM_Prescaler = (PIOS_MASTER_CLOCK / new_clock) - 1; - TIM_TimeBaseStructure.TIM_Period = ((new_clock / speeds[i]) - 1); - - TIM_TimeBaseInit((TIM_TypeDef *)timer, &TIM_TimeBaseStructure); - } - } -} - -/** - * Set servo position - * \param[in] Servo Servo number (0-7) - * \param[in] Position Servo position in microseconds - */ -void PIOS_Servo_Set(uint8_t servo, uint16_t position) -{ - /* Make sure servo exists */ - if (!servo_cfg || servo >= servo_cfg->num_channels) { - return; - } - - - /* Update the position */ - const struct pios_tim_channel *chan = &servo_cfg->channels[servo]; - uint16_t val = position; - uint16_t margin = chan->timer->ARR / 50; // Leave 2% of period as margin to prevent overlaps - if (val > (chan->timer->ARR - margin)) { - val = chan->timer->ARR - margin; - } - - uint8_t bank = pios_servo_pin_bank[servo]; - if (pios_servo_bank_max_pulse[bank] < val) { - pios_servo_bank_max_pulse[bank] = val; - } - switch (chan->timer_chan) { - case TIM_Channel_1: - TIM_SetCompare1(chan->timer, val); - break; - case TIM_Channel_2: - TIM_SetCompare2(chan->timer, val); - break; - case TIM_Channel_3: - TIM_SetCompare3(chan->timer, val); - break; - case TIM_Channel_4: - TIM_SetCompare4(chan->timer, val); - break; - } -} - -void PIOS_Servo_Update() -{ - for (uint8_t i = 0; (i < PIOS_SERVO_BANKS); i++) { - const TIM_TypeDef *timer = pios_servo_bank_timer[i]; - if (timer && pios_servo_bank_mode[i] == PIOS_SERVO_BANK_MODE_SINGLE_PULSE) { - // a pulse to be generated is longer than cycle period. skip this update. - if (TIM_GetCounter((TIM_TypeDef *)timer) > (uint32_t)(pios_servo_bank_next_update[i] + PIOS_SERVO_SAFE_MARGIN)) { - TIM_GenerateEvent((TIM_TypeDef *)timer, TIM_EventSource_Update); - pios_servo_bank_next_update[i] = pios_servo_bank_max_pulse[i]; - } - } - pios_servo_bank_max_pulse[i] = 0; - } - for (uint8_t i = 0; (i < servo_cfg->num_channels); i++) { - uint8_t bank = pios_servo_pin_bank[i]; - uint8_t mode = pios_servo_bank_mode[bank]; - if (mode == PIOS_SERVO_BANK_MODE_SINGLE_PULSE) { - /* Update the position */ - const struct pios_tim_channel *chan = &servo_cfg->channels[i]; - - switch (chan->timer_chan) { - case TIM_Channel_1: - TIM_SetCompare1(chan->timer, 0); - break; - case TIM_Channel_2: - TIM_SetCompare2(chan->timer, 0); - break; - case TIM_Channel_3: - TIM_SetCompare3(chan->timer, 0); - break; - case TIM_Channel_4: - TIM_SetCompare4(chan->timer, 0); - break; - } - } - } -} - -void PIOS_Servo_SetBankMode(uint8_t bank, uint8_t mode) -{ - PIOS_Assert(bank < PIOS_SERVO_BANKS); - pios_servo_bank_mode[bank] = mode; - - if (pios_servo_bank_timer[bank]) { - for (uint8_t i = 0; (i < servo_cfg->num_channels); i++) { - if (pios_servo_pin_bank[i] == bank) { - const struct pios_tim_channel *chan = &servo_cfg->channels[i]; - /* Set up for output compare function */ - switch (chan->timer_chan) { - case TIM_Channel_1: - TIM_OC1PolarityConfig(chan->timer, TIM_OCPolarity_High); - break; - case TIM_Channel_2: - TIM_OC2PolarityConfig(chan->timer, TIM_OCPolarity_High); - break; - case TIM_Channel_3: - TIM_OC3PolarityConfig(chan->timer, TIM_OCPolarity_High); - break; - case TIM_Channel_4: - TIM_OC4PolarityConfig(chan->timer, TIM_OCPolarity_High); - break; - } - } - } - - // Setup the timer accordingly - TIM_SelectOnePulseMode(pios_servo_bank_timer[bank], TIM_OPMode_Repetitive); - TIM_Cmd(pios_servo_bank_timer[bank], ENABLE); - } -} - - -uint8_t PIOS_Servo_GetPinBank(uint8_t pin) -{ - if (pin < servo_cfg->num_channels) { - return pios_servo_pin_bank[pin]; - } else { - return 0; - } -} - -#endif /* PIOS_INCLUDE_SERVO */ diff --git a/flight/targets/boards/coptercontrol/pios_board.h b/flight/targets/boards/coptercontrol/pios_board.h index 1750b4d9af..3db6fc6392 100644 --- a/flight/targets/boards/coptercontrol/pios_board.h +++ b/flight/targets/boards/coptercontrol/pios_board.h @@ -59,58 +59,59 @@ // ------------------------ // BOOTLOADER_SETTINGS // ------------------------ -#define BOARD_READABLE TRUE -#define BOARD_WRITABLE TRUE -#define MAX_DEL_RETRYS 3 +#define BOARD_READABLE TRUE +#define BOARD_WRITABLE TRUE +#define MAX_DEL_RETRYS 3 // ------------------------ // WATCHDOG_SETTINGS // ------------------------ -#define PIOS_WATCHDOG_TIMEOUT 250 -#define PIOS_WDG_REGISTER BKP_DR4 -#define PIOS_WDG_ACTUATOR 0x0001 -#define PIOS_WDG_STABILIZATION 0x0002 -#define PIOS_WDG_ATTITUDE 0x0004 -#define PIOS_WDG_MANUAL 0x0008 -#define PIOS_WDG_AUTOTUNE 0x0010 +#define PIOS_WATCHDOG_TIMEOUT 250 +#define PIOS_WDG_REGISTER BKP_DR4 +#define PIOS_WDG_ACTUATOR 0x0001 +#define PIOS_WDG_STABILIZATION 0x0002 +#define PIOS_WDG_ATTITUDE 0x0004 +#define PIOS_WDG_MANUAL 0x0008 +#define PIOS_WDG_AUTOTUNE 0x0010 // ------------------------ // TELEMETRY // ------------------------ -#define TELEM_QUEUE_SIZE 10 +#define TELEM_QUEUE_SIZE 10 // ------------------------ // PIOS_LED // ------------------------ -#define PIOS_LED_HEARTBEAT 0 +#define PIOS_LED_HEARTBEAT 0 // ------------------------- // System Settings // ------------------------- -#define PIOS_MASTER_CLOCK 72000000 -#define PIOS_PERIPHERAL_CLOCK (PIOS_MASTER_CLOCK / 2) +#define PIOS_MASTER_CLOCK 72000000 +#define PIOS_PERIPHERAL_APB1_CLOCK (PIOS_MASTER_CLOCK / 2) +#define PIOS_PERIPHERAL_APB2_CLOCK (PIOS_MASTER_CLOCK / 1) // ------------------------- // Interrupt Priorities // ------------------------- -#define PIOS_IRQ_PRIO_LOW 12 // lower than RTOS -#define PIOS_IRQ_PRIO_MID 8 // higher than RTOS -#define PIOS_IRQ_PRIO_HIGH 5 // for SPI, ADC, I2C etc... -#define PIOS_IRQ_PRIO_HIGHEST 4 // for USART etc... +#define PIOS_IRQ_PRIO_LOW 12 // lower than RTOS +#define PIOS_IRQ_PRIO_MID 8 // higher than RTOS +#define PIOS_IRQ_PRIO_HIGH 5 // for SPI, ADC, I2C etc... +#define PIOS_IRQ_PRIO_HIGHEST 4 // for USART etc... // ------------------------ // PIOS_I2C // See also pios_board.c // ------------------------ -#define PIOS_I2C_MAX_DEVS 1 +#define PIOS_I2C_MAX_DEVS 1 extern uint32_t pios_i2c_flexi_adapter_id; -#define PIOS_I2C_MAIN_ADAPTER (pios_i2c_flexi_adapter_id) -#define PIOS_I2C_ESC_ADAPTER (pios_i2c_flexi_adapter_id) -#define PIOS_I2C_BMP085_ADAPTER (pios_i2c_flexi_adapter_id) +#define PIOS_I2C_MAIN_ADAPTER (pios_i2c_flexi_adapter_id) +#define PIOS_I2C_ESC_ADAPTER (pios_i2c_flexi_adapter_id) +#define PIOS_I2C_BMP085_ADAPTER (pios_i2c_flexi_adapter_id) // ------------------------ // PIOS_BMP085 // ------------------------ -#define PIOS_BMP085_OVERSAMPLING 3 +#define PIOS_BMP085_OVERSAMPLING 3 // ------------------------- // SPI diff --git a/flight/targets/boards/oplinkmini/pios_board.h b/flight/targets/boards/oplinkmini/pios_board.h index 749657ea79..672e18335d 100644 --- a/flight/targets/boards/oplinkmini/pios_board.h +++ b/flight/targets/boards/oplinkmini/pios_board.h @@ -137,16 +137,17 @@ // ------------------------- // System Settings // ------------------------- -#define PIOS_MASTER_CLOCK 72000000 -#define PIOS_PERIPHERAL_CLOCK (PIOS_MASTER_CLOCK / 2) +#define PIOS_MASTER_CLOCK 72000000 +#define PIOS_PERIPHERAL_APB1_CLOCK (PIOS_MASTER_CLOCK / 2) +#define PIOS_PERIPHERAL_APB2_CLOCK (PIOS_MASTER_CLOCK / 1) // ------------------------- // Interrupt Priorities // ------------------------- -#define PIOS_IRQ_PRIO_LOW 12 // lower than RTOS -#define PIOS_IRQ_PRIO_MID 8 // higher than RTOS -#define PIOS_IRQ_PRIO_HIGH 5 // for SPI, ADC, I2C etc... -#define PIOS_IRQ_PRIO_HIGHEST 4 // for USART etc... +#define PIOS_IRQ_PRIO_LOW 12 // lower than RTOS +#define PIOS_IRQ_PRIO_MID 8 // higher than RTOS +#define PIOS_IRQ_PRIO_HIGH 5 // for SPI, ADC, I2C etc... +#define PIOS_IRQ_PRIO_HIGHEST 4 // for USART etc... // ------------------------ // PIOS_I2C From 85df731afc876aeb9824f3fccd4501434307d30a Mon Sep 17 00:00:00 2001 From: Vladimir Zidar Date: Mon, 26 Sep 2016 23:17:04 +0200 Subject: [PATCH 052/624] LP-415 Added LP copyright to modified files --- flight/pios/common/pios_servo.c | 5 +++-- flight/pios/inc/pios_servo.h | 3 ++- flight/pios/inc/pios_servo_priv.h | 5 +++-- flight/targets/boards/oplinkmini/pios_board.h | 3 ++- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/flight/pios/common/pios_servo.c b/flight/pios/common/pios_servo.c index 4669b3f29e..f71962013a 100644 --- a/flight/pios/common/pios_servo.c +++ b/flight/pios/common/pios_servo.c @@ -7,7 +7,8 @@ * @{ * * @file pios_servo.c - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012. + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. + * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012. * @brief RC Servo routines (STM32 dependent) * @see The GNU Public License (GPL) Version 3 * @@ -327,7 +328,7 @@ uint8_t PIOS_Servo_GetPinBank(uint8_t pin) } } -const struct pios_servo_cfg *PIOS_Servo_Config() +const struct pios_servo_cfg *PIOS_Servo_GetConfig() { return servo_cfg; } diff --git a/flight/pios/inc/pios_servo.h b/flight/pios/inc/pios_servo.h index f158d4e61e..2000eee255 100644 --- a/flight/pios/inc/pios_servo.h +++ b/flight/pios/inc/pios_servo.h @@ -6,7 +6,8 @@ * @{ * * @file pios_servo.h - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. + * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. * @brief RC Servo functions header. * @see The GNU Public License (GPL) Version 3 * diff --git a/flight/pios/inc/pios_servo_priv.h b/flight/pios/inc/pios_servo_priv.h index 3b19e14f9b..61946fcc2d 100644 --- a/flight/pios/inc/pios_servo_priv.h +++ b/flight/pios/inc/pios_servo_priv.h @@ -7,7 +7,8 @@ * @{ * * @file pios_servo_priv.h - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. + * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. * @brief Servo private structures. * @see The GNU Public License (GPL) Version 3 * @@ -45,7 +46,7 @@ struct pios_servo_cfg { }; extern int32_t PIOS_Servo_Init(const struct pios_servo_cfg *cfg); -const struct pios_servo_cfg *PIOS_Servo_Config(); +const struct pios_servo_cfg *PIOS_Servo_GetConfig(); #endif /* PIOS_SERVO_PRIV_H */ diff --git a/flight/targets/boards/oplinkmini/pios_board.h b/flight/targets/boards/oplinkmini/pios_board.h index 672e18335d..d0277acb83 100644 --- a/flight/targets/boards/oplinkmini/pios_board.h +++ b/flight/targets/boards/oplinkmini/pios_board.h @@ -2,7 +2,8 @@ ****************************************************************************** * * @file pios_board.h - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2013. + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. + * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2013. * @brief Defines PiOS board hardware for the OpenPilot OPLink Mini board. * @see The GNU Public License (GPL) Version 3 * From 282a187357c46b89c7a280ee991dc6b29ad4f2c9 Mon Sep 17 00:00:00 2001 From: Vladimir Zidar Date: Tue, 27 Sep 2016 01:36:00 +0200 Subject: [PATCH 053/624] LP-415 F411 needs check for additional STM32F411xE define --- flight/pios/common/pios_servo.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/flight/pios/common/pios_servo.c b/flight/pios/common/pios_servo.c index f71962013a..905c3e8563 100644 --- a/flight/pios/common/pios_servo.c +++ b/flight/pios/common/pios_servo.c @@ -72,7 +72,7 @@ extern void PIOS_Servo_Disable() GPIO_InitTypeDef init = chan->pin.init; -#if defined(STM32F40_41xxx) || defined(STM32F446xx) +#if defined(STM32F40_41xxx) || defined(STM32F446xx) || defined(STM32F411xE) init.GPIO_Mode = GPIO_Mode_OUT; #elif defined(STM32F10X_MD) init.GPIO_Mode = GPIO_Mode_Out_PP; @@ -262,7 +262,7 @@ void PIOS_Servo_SetHz(const uint16_t *speeds, const uint32_t *clock, uint8_t ban } else { apb_clock = PIOS_PERIPHERAL_APB1_CLOCK; } -#elif defined(STM32F40_41xxx) || defined(STM32F446xx) +#elif defined(STM32F40_41xxx) || defined(STM32F446xx) || defined(STM32F411xE) if (timer == TIM1 || timer == TIM8 || timer == TIM9 || timer == TIM10 || timer == TIM11) { apb_clock = PIOS_PERIPHERAL_APB2_CLOCK; } else { From be03fb20201c6b14272457cd4df0fedca072e735 Mon Sep 17 00:00:00 2001 From: Vladimir Zidar Date: Wed, 28 Sep 2016 16:26:38 +0200 Subject: [PATCH 054/624] LP-415 Added missing AF remap --- flight/pios/common/pios_servo.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/flight/pios/common/pios_servo.c b/flight/pios/common/pios_servo.c index 905c3e8563..7dd2ca3def 100644 --- a/flight/pios/common/pios_servo.c +++ b/flight/pios/common/pios_servo.c @@ -95,6 +95,15 @@ extern void PIOS_Servo_Enable() const struct pios_tim_channel *chan = &servo_cfg->channels[i]; GPIO_Init(chan->pin.gpio, &chan->pin.init); +#if defined(STM32F40_41xxx) || defined(STM32F446xx) || defined(STM32F411xE) + GPIO_PinAFConfig(chan->pin.gpio, chan->pin.pin_source, chan->remap); +#elif defined(STM32F10X_MD) + if (chan->remap) { + GPIO_PinRemapConfig(chan->remap, ENABLE); + } +#else +#error Unsupported MCU +#endif /* Set up for output compare function */ switch (chan->timer_chan) { From fef715b3d645807c939299cd0aa52c236d46323f Mon Sep 17 00:00:00 2001 From: Vladimir Zidar Date: Sun, 1 Jan 2017 16:53:06 +0100 Subject: [PATCH 055/624] LP-463 Use correct timer clock for F1 target. All timers get 72M clock regardless of APB domain they live on. --- flight/pios/common/pios_servo.c | 15 ++++++--------- flight/targets/boards/coptercontrol/pios_board.h | 2 -- flight/targets/boards/oplinkmini/pios_board.h | 2 -- 3 files changed, 6 insertions(+), 13 deletions(-) diff --git a/flight/pios/common/pios_servo.c b/flight/pios/common/pios_servo.c index 7dd2ca3def..61592f5a79 100644 --- a/flight/pios/common/pios_servo.c +++ b/flight/pios/common/pios_servo.c @@ -261,26 +261,23 @@ void PIOS_Servo_SetHz(const uint16_t *speeds, const uint32_t *clock, uint8_t ban new_clock = clock[i]; } - uint32_t apb_clock; + uint32_t timer_clock; // Choose the correct prescaler value for the APB the timer is attached #if defined(STM32F10X_MD) - if (timer == TIM1 || timer == TIM8) { - apb_clock = PIOS_PERIPHERAL_APB2_CLOCK; - } else { - apb_clock = PIOS_PERIPHERAL_APB1_CLOCK; - } + // F1 has both timer clock domains running at master clock speed + timer_clock = PIOS_MASTER_CLOCK; #elif defined(STM32F40_41xxx) || defined(STM32F446xx) || defined(STM32F411xE) if (timer == TIM1 || timer == TIM8 || timer == TIM9 || timer == TIM10 || timer == TIM11) { - apb_clock = PIOS_PERIPHERAL_APB2_CLOCK; + timer_clock = PIOS_PERIPHERAL_APB2_CLOCK; } else { - apb_clock = PIOS_PERIPHERAL_APB1_CLOCK; + timer_clock = PIOS_PERIPHERAL_APB1_CLOCK; } #else #error Unsupported MCU #endif - TIM_TimeBaseStructure.TIM_Prescaler = (apb_clock / new_clock) - 1; + TIM_TimeBaseStructure.TIM_Prescaler = (timer_clock / new_clock) - 1; TIM_TimeBaseStructure.TIM_Period = ((new_clock / speeds[i]) - 1); TIM_TimeBaseInit((TIM_TypeDef *)timer, &TIM_TimeBaseStructure); } diff --git a/flight/targets/boards/coptercontrol/pios_board.h b/flight/targets/boards/coptercontrol/pios_board.h index 3db6fc6392..21281f2290 100644 --- a/flight/targets/boards/coptercontrol/pios_board.h +++ b/flight/targets/boards/coptercontrol/pios_board.h @@ -88,8 +88,6 @@ // System Settings // ------------------------- #define PIOS_MASTER_CLOCK 72000000 -#define PIOS_PERIPHERAL_APB1_CLOCK (PIOS_MASTER_CLOCK / 2) -#define PIOS_PERIPHERAL_APB2_CLOCK (PIOS_MASTER_CLOCK / 1) // ------------------------- // Interrupt Priorities diff --git a/flight/targets/boards/oplinkmini/pios_board.h b/flight/targets/boards/oplinkmini/pios_board.h index d0277acb83..64329e6886 100644 --- a/flight/targets/boards/oplinkmini/pios_board.h +++ b/flight/targets/boards/oplinkmini/pios_board.h @@ -139,8 +139,6 @@ // System Settings // ------------------------- #define PIOS_MASTER_CLOCK 72000000 -#define PIOS_PERIPHERAL_APB1_CLOCK (PIOS_MASTER_CLOCK / 2) -#define PIOS_PERIPHERAL_APB2_CLOCK (PIOS_MASTER_CLOCK / 1) // ------------------------- // Interrupt Priorities From f67c092d6aa949f93621a90f0a4cfdd384fd0932 Mon Sep 17 00:00:00 2001 From: Laurent Lalanne Date: Fri, 30 Dec 2016 15:00:53 +0100 Subject: [PATCH 056/624] LP-462 MWOSD - MSP: Handle Dterm scale --- flight/modules/UAVOMSPBridge/UAVOMSPBridge.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/flight/modules/UAVOMSPBridge/UAVOMSPBridge.c b/flight/modules/UAVOMSPBridge/UAVOMSPBridge.c index cb0c3fb147..c02cc46876 100644 --- a/flight/modules/UAVOMSPBridge/UAVOMSPBridge.c +++ b/flight/modules/UAVOMSPBridge/UAVOMSPBridge.c @@ -676,14 +676,18 @@ static void msp_send_pidnames(struct msp_bridge *m) static void pid_native2msp(const float *native, msp_pid_t *piditem, float scale, unsigned numelem) { for (unsigned i = 0; i < numelem; ++i) { - piditem->values[i] = lroundf(native[i] * scale); + // Handle Dterm scale + float s = (i == 2) ? scale * 100 : scale; + piditem->values[i] = lroundf(native[i] * s); } } static void pid_msp2native(const msp_pid_t *piditem, float *native, float scale, unsigned numelem) { for (unsigned i = 0; i < numelem; ++i) { - native[i] = (float)piditem->values[i] / scale; + // Handle Dterm scale + float s = (i == 2) ? scale * 100 : scale; + native[i] = (float)piditem->values[i] / s; } } From 1b2c20defbba1033f7943c0400306183ed059f06 Mon Sep 17 00:00:00 2001 From: Laurent Lalanne Date: Wed, 28 Dec 2016 03:40:18 +0100 Subject: [PATCH 057/624] LP-461 Remove save warning and UpdateMixer() lock --- .../cfg_vehicletypes/configccpmwidget.cpp | 42 +++++++++---------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/ground/gcs/src/plugins/config/cfg_vehicletypes/configccpmwidget.cpp b/ground/gcs/src/plugins/config/cfg_vehicletypes/configccpmwidget.cpp index 8b962fb4fa..bed4929876 100644 --- a/ground/gcs/src/plugins/config/cfg_vehicletypes/configccpmwidget.cpp +++ b/ground/gcs/src/plugins/config/cfg_vehicletypes/configccpmwidget.cpp @@ -2,7 +2,7 @@ ****************************************************************************** * * @file configccpmwidget.cpp - * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015. + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015-2016. * E. Lafargue & The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. * @addtogroup GCSPlugins GCS Plugins * @{ @@ -31,6 +31,7 @@ #include #include +#include #include "mixersettings.h" #include "systemsettings.h" @@ -246,8 +247,6 @@ ConfigCcpmWidget::ConfigCcpmWidget(QWidget *parent) : // refreshWidgetsValues(QString("HeliCP")); - UpdateType(); - connect(m_aircraft->ccpmAngleW, SIGNAL(valueChanged(double)), this, SLOT(ccpmSwashplateUpdate())); connect(m_aircraft->ccpmAngleX, SIGNAL(valueChanged(double)), this, SLOT(ccpmSwashplateUpdate())); connect(m_aircraft->ccpmAngleY, SIGNAL(valueChanged(double)), this, SLOT(ccpmSwashplateUpdate())); @@ -277,7 +276,7 @@ ConfigCcpmWidget::ConfigCcpmWidget(QWidget *parent) : connect(m_aircraft->ccpmLinkCyclic, SIGNAL(clicked()), this, SLOT(SetUIComponentVisibilities())); connect(m_aircraft->ccpmLinkRoll, SIGNAL(clicked()), this, SLOT(SetUIComponentVisibilities())); - ccpmSwashplateRedraw(); + UpdateType(); } ConfigCcpmWidget::~ConfigCcpmWidget() @@ -398,8 +397,6 @@ void ConfigCcpmWidget::UpdateType() int SingleServoIndex, NumServosDefined; double AdjustmentAngle = 0; - SetUIComponentVisibilities(); - typeText = m_aircraft->ccpmType->currentText(); SingleServoIndex = m_aircraft->ccpmSingleServo->currentIndex(); @@ -977,27 +974,19 @@ void ConfigCcpmWidget::setMixer() int typeInt = m_aircraft->ccpmType->count() - m_aircraft->ccpmType->currentIndex() - 1; - // Exit if currently updatingToHardware or ConfigError + // Exit if currently updatingToHardware, ConfigError or LevelConfigInProgress // Avoid mixer changes if something wrong in config - if (throwConfigError(typeInt) || updatingToHardware) { - return; - } - - if (SwashLvlConfigurationInProgress) { - return; - } - if (updatingToHardware == true) { + if (throwConfigError(typeInt) || updatingToHardware || SwashLvlConfigurationInProgress) { return; } + UpdateMixer(); updatingToHardware = true; MixerSettings *mixerSettings = MixerSettings::GetInstance(getObjectManager()); Q_ASSERT(mixerSettings); MixerSettings::DataFields mixerSettingsData = mixerSettings->getData(); - UpdateMixer(); - // Set up some helper pointers qint8 *mixers[12] = { mixerSettingsData.Mixer1Vector, mixerSettingsData.Mixer2Vector, @@ -1069,8 +1058,11 @@ void ConfigCcpmWidget::setMixer() mixerSettingsData.Curve2Source = MixerSettings::CURVE2SOURCE_THROTTLE; } - mixerSettings->setData(mixerSettingsData); - mixerSettings->updated(); + UAVObjectUpdaterHelper updateHelper; + + mixerSettings->setData(mixerSettingsData, false); + updateHelper.doObjectAndWait(mixerSettings); + updatingToHardware = false; } @@ -1541,8 +1533,10 @@ void ConfigCcpmWidget::setSwashplateLevel(int percent) SwashLvlSpinBoxes[i]->setValue(value); } - actuatorCommand->setData(actuatorCommandData); - actuatorCommand->updated(); + UAVObjectUpdaterHelper updateHelper; + + actuatorCommand->setData(actuatorCommandData, false); + updateHelper.doObjectAndWait(actuatorCommand); SwashLvlServoInterlock = 0; } @@ -1588,8 +1582,10 @@ void ConfigCcpmWidget::SwashLvlSpinBoxChanged(int value) actuatorCommandData.Channel[newSwashLvlConfiguration.ServoChannels[i]] = value; } - actuatorCommand->setData(actuatorCommandData); - actuatorCommand->updated(); + UAVObjectUpdaterHelper updateHelper; + + actuatorCommand->setData(actuatorCommandData, false); + updateHelper.doObjectAndWait(actuatorCommand); } /** From ed665615664ed3db22001519231dfe8ebb6351c9 Mon Sep 17 00:00:00 2001 From: Laurent Lalanne Date: Wed, 28 Dec 2016 04:26:17 +0100 Subject: [PATCH 058/624] LP-461 Update colors --- .../cfg_vehicletypes/configccpmwidget.cpp | 4 +-- .../src/plugins/config/images/ccpm_setup.svg | 32 +++++++------------ 2 files changed, 14 insertions(+), 22 deletions(-) diff --git a/ground/gcs/src/plugins/config/cfg_vehicletypes/configccpmwidget.cpp b/ground/gcs/src/plugins/config/cfg_vehicletypes/configccpmwidget.cpp index bed4929876..6aae50eb20 100644 --- a/ground/gcs/src/plugins/config/cfg_vehicletypes/configccpmwidget.cpp +++ b/ground/gcs/src/plugins/config/cfg_vehicletypes/configccpmwidget.cpp @@ -170,13 +170,13 @@ ConfigCcpmWidget::ConfigCcpmWidget(QWidget *parent) : pen.setCapStyle(Qt::RoundCap); pen.setJoinStyle(Qt::RoundJoin); - QBrush brush(Qt::darkBlue); + QBrush brush(Qt::darkYellow); // creates a default pen QPen pen2; // pen2.setStyle(Qt::DotLine); pen2.setWidth(1); - pen2.setBrush(Qt::blue); + pen2.setBrush(Qt::yellow); // pen2.setCapStyle(Qt::RoundCap); // pen2.setJoinStyle(Qt::RoundJoin); diff --git a/ground/gcs/src/plugins/config/images/ccpm_setup.svg b/ground/gcs/src/plugins/config/images/ccpm_setup.svg index cf06f04e3b..5d75ec977a 100644 --- a/ground/gcs/src/plugins/config/images/ccpm_setup.svg +++ b/ground/gcs/src/plugins/config/images/ccpm_setup.svg @@ -13,7 +13,7 @@ height="400" id="svg2816" version="1.1" - inkscape:version="0.48.5 r10040" + inkscape:version="0.91 r13725" sodipodi:docname="ccpm_setup.svg"> @@ -32,14 +32,6 @@ stdDeviation="2.4480407" id="feGaussianBlur4113" /> - - - image/svg+xml - + @@ -148,7 +140,7 @@ inkscape:connector-curvature="0" transform="matrix(1.0083769,0,0,1.0083769,2.0000001e-6,-3.35076)" /> @@ -176,7 +168,7 @@ style="display:inline"> Date: Thu, 15 Dec 2016 21:44:58 +0100 Subject: [PATCH 059/624] LP-436 upgrade to Qt 5.6.2 --- make/tools.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/make/tools.mk b/make/tools.mk index ecf0462e03..87c39526b9 100644 --- a/make/tools.mk +++ b/make/tools.mk @@ -87,7 +87,7 @@ $(TOOL_REMOVE_TARGETS): TOOLS_URL := http://librepilot.github.io/tools QT_SHORT_VERSION := 5.6 -QT_VERSION := 5.6.1 +QT_VERSION := 5.6.2 ifeq ($(UNAME), Linux) ifeq ($(ARCH), x86_64) From 2e5f3aa60c8beeda24c6cdc24913a687f14c20b1 Mon Sep 17 00:00:00 2001 From: Alessio Morale Date: Thu, 27 Oct 2016 23:08:49 +0200 Subject: [PATCH 060/624] LP-437 - Add support for a secondary radio stream and associated AuxCom driver TODO: find out if there is still free space on current packet and store both streams content --- flight/pios/common/pios_rfm22b.c | 49 +++++++++++++++++++---- flight/pios/common/pios_rfm22b_com.c | 58 ++++++++++++++++++++++++++++ flight/pios/inc/pios_rfm22b_com.h | 7 ++-- flight/pios/inc/pios_rfm22b_priv.h | 8 +++- 4 files changed, 110 insertions(+), 12 deletions(-) diff --git a/flight/pios/common/pios_rfm22b.c b/flight/pios/common/pios_rfm22b.c index 665d0a13a9..86df3ebae2 100644 --- a/flight/pios/common/pios_rfm22b.c +++ b/flight/pios/common/pios_rfm22b.c @@ -420,6 +420,8 @@ int32_t PIOS_RFM22B_Init(uint32_t *rfm22b_id, uint32_t spi_id, uint32_t slave_nu rfm22b_dev->rx_in_cb = NULL; rfm22b_dev->tx_out_cb = NULL; + rfm22b_dev->aux_rx_in_cb = NULL; + rfm22b_dev->aux_tx_out_cb = NULL; // Initialize the PPM callback. rfm22b_dev->ppm_callback = NULL; @@ -1905,10 +1907,28 @@ static enum pios_radio_event radio_txStart(struct pios_rfm22b_dev *radio_dev) } // Append data from the com interface if applicable. - if (!radio_dev->ppm_only_mode && radio_dev->tx_out_cb) { - // Try to get some data to send + if (!radio_dev->ppm_only_mode) { + uint8_t newlen = 0; bool need_yield = false; - len += (radio_dev->tx_out_cb)(radio_dev->tx_out_context, p + len, max_data_len - len, NULL, &need_yield); + uint8_t i = 0; + // Try to get some data to send + while (newlen == 0 && i < 2) { + radio_dev->last_stream_sent = (radio_dev->last_stream_sent + 1) % 2; + if (!radio_dev->last_stream_sent) { + if (radio_dev->tx_out_cb) { + newlen = (radio_dev->tx_out_cb)(radio_dev->tx_out_context, p + len + 1, max_data_len - len - 1, NULL, &need_yield); + } + } else { + if (radio_dev->aux_tx_out_cb) { + newlen = (radio_dev->aux_tx_out_cb)(radio_dev->aux_tx_out_context, p + len + 1, max_data_len - len - 1, NULL, &need_yield); + } + } + i++; + } + if (newlen) { + *(p + len) = radio_dev->last_stream_sent; + len += newlen + 1; + } } // Always send a packet if this modem is a coordinator. @@ -1990,9 +2010,10 @@ static enum pios_radio_event radio_setRxMode(struct pios_rfm22b_dev *rfm22b_dev) */ static enum pios_radio_event radio_receivePacket(struct pios_rfm22b_dev *radio_dev, uint8_t *p, uint16_t rx_len) { - bool good_packet = true; + bool good_packet = true; bool corrected_packet = false; - uint8_t data_len = rx_len; + uint8_t stream_num = 0; + uint8_t data_len = rx_len; // We don't rsencode ppm only packets. if (!radio_dev->ppm_only_mode) { @@ -2073,10 +2094,22 @@ static enum pios_radio_event radio_receivePacket(struct pios_rfm22b_dev *radio_d if (good_packet || corrected_packet) { // Send the data to the com port bool rx_need_yield; - if (radio_dev->rx_in_cb && (data_len > 0) && !radio_dev->ppm_only_mode) { - (radio_dev->rx_in_cb)(radio_dev->rx_in_context, p, data_len, NULL, &rx_need_yield); - } + + if ((data_len > 0) && !radio_dev->ppm_only_mode) { + stream_num = *p; + p++; + data_len--; + if (!stream_num) { + if (radio_dev->rx_in_cb) { + (radio_dev->rx_in_cb)(radio_dev->rx_in_context, p, data_len, NULL, &rx_need_yield); + } + } else { + if (radio_dev->aux_rx_in_cb) { + (radio_dev->aux_rx_in_cb)(radio_dev->aux_rx_in_context, p, data_len, NULL, &rx_need_yield); + } + } + } /* * If the packet is valid and destined for us we synchronize the clock. */ diff --git a/flight/pios/common/pios_rfm22b_com.c b/flight/pios/common/pios_rfm22b_com.c index 1669e10951..a8c4a4a229 100644 --- a/flight/pios/common/pios_rfm22b_com.c +++ b/flight/pios/common/pios_rfm22b_com.c @@ -40,6 +40,10 @@ static void PIOS_RFM22B_COM_RegisterRxCallback(uint32_t rfm22b_id, pios_com_call static void PIOS_RFM22B_COM_RegisterTxCallback(uint32_t rfm22b_id, pios_com_callback tx_out_cb, uint32_t context); static void PIOS_RFM22B_COM_TxStart(uint32_t rfm22b_id, uint16_t tx_bytes_avail); static void PIOS_RFM22B_COM_RxStart(uint32_t rfm22b_id, uint16_t rx_bytes_avail); + +static void PIOS_RFM22B_COM_RegisterAuxRxCallback(uint32_t rfm22b_id, pios_com_callback rx_in_cb, uint32_t context); +static void PIOS_RFM22B_COM_RegisterAuxTxCallback(uint32_t rfm22b_id, pios_com_callback tx_out_cb, uint32_t context); + static uint32_t PIOS_RFM22B_COM_Available(uint32_t rfm22b_com_id); /* Local variables */ @@ -52,6 +56,15 @@ const struct pios_com_driver pios_rfm22b_com_driver = { .available = PIOS_RFM22B_COM_Available }; +/* Local variables */ +const struct pios_com_driver pios_rfm22b_aux_com_driver = { + .set_baud = PIOS_RFM22B_COM_ChangeBaud, + .tx_start = PIOS_RFM22B_COM_TxStart, + .rx_start = PIOS_RFM22B_COM_RxStart, + .bind_tx_cb = PIOS_RFM22B_COM_RegisterAuxTxCallback, + .bind_rx_cb = PIOS_RFM22B_COM_RegisterAuxRxCallback, + .available = PIOS_RFM22B_COM_Available +}; /** * Changes the baud rate of the RFM22B peripheral without re-initialising. * @@ -129,6 +142,51 @@ static void PIOS_RFM22B_COM_RegisterTxCallback(uint32_t rfm22b_id, pios_com_call rfm22b_dev->tx_out_cb = tx_out_cb; } +/** + * Register the callback to pass received data to + * + * @param[in] rfm22b_dev The device ID. + * @param[in] rx_in_cb The Rx callback function. + * @param[in] context The callback context. + */ +static void PIOS_RFM22B_COM_RegisterAuxRxCallback(uint32_t rfm22b_id, pios_com_callback rx_in_cb, uint32_t context) +{ + struct pios_rfm22b_dev *rfm22b_dev = (struct pios_rfm22b_dev *)rfm22b_id; + + if (!PIOS_RFM22B_Validate(rfm22b_dev)) { + return; + } + + /* + * Order is important in these assignments since ISR uses _cb + * field to determine if it's ok to dereference _cb and _context + */ + rfm22b_dev->aux_rx_in_context = context; + rfm22b_dev->aux_rx_in_cb = rx_in_cb; +} + +/** + * Register the callback to get data from. + * + * @param[in] rfm22b_dev The device ID. + * @param[in] rx_in_cb The Tx callback function. + * @param[in] context The callback context. + */ +static void PIOS_RFM22B_COM_RegisterAuxTxCallback(uint32_t rfm22b_id, pios_com_callback tx_out_cb, uint32_t context) +{ + struct pios_rfm22b_dev *rfm22b_dev = (struct pios_rfm22b_dev *)rfm22b_id; + + if (!PIOS_RFM22B_Validate(rfm22b_dev)) { + return; + } + + /* + * Order is important in these assignments since ISR uses _cb + * field to determine if it's ok to dereference _cb and _context + */ + rfm22b_dev->aux_tx_out_context = context; + rfm22b_dev->aux_tx_out_cb = tx_out_cb; +} /** * See if the COM port is alive * diff --git a/flight/pios/inc/pios_rfm22b_com.h b/flight/pios/inc/pios_rfm22b_com.h index f461809a17..537206371f 100644 --- a/flight/pios/inc/pios_rfm22b_com.h +++ b/flight/pios/inc/pios_rfm22b_com.h @@ -28,12 +28,13 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef PIOS_RFM22B_H -#define PIOS_RFM22B_H +#ifndef PIOS_RFM22B_COM_H +#define PIOS_RFM22B_COM_H extern const struct pios_com_driver pios_rfm22b_com_driver; +extern const struct pios_com_driver pios_rfm22b_aux_com_driver; -#endif /* PIOS_RFM22B_H */ +#endif /* PIOS_RFM22B_COM_H */ /** * @} diff --git a/flight/pios/inc/pios_rfm22b_priv.h b/flight/pios/inc/pios_rfm22b_priv.h index 9d267d7d6d..2dee9ae958 100644 --- a/flight/pios/inc/pios_rfm22b_priv.h +++ b/flight/pios/inc/pios_rfm22b_priv.h @@ -206,12 +206,18 @@ struct pios_rfm22b_dev { // ISR pending semaphore xSemaphoreHandle isrPending; - // The COM callback functions. + // The main COM callback functions. pios_com_callback rx_in_cb; uint32_t rx_in_context; pios_com_callback tx_out_cb; uint32_t tx_out_context; + uint8_t last_stream_sent; + // The Aux COM callback functions. + pios_com_callback aux_rx_in_cb; + uint32_t aux_rx_in_context; + pios_com_callback aux_tx_out_cb; + uint32_t aux_tx_out_context; // the transmit power to use for data transmissions uint8_t tx_power; From 0af373a8c77b5eb5a460d053fed7e6a55403818f Mon Sep 17 00:00:00 2001 From: Alessio Morale Date: Thu, 27 Oct 2016 23:09:51 +0200 Subject: [PATCH 061/624] LP-437 - Support for OPLinkMini --- .../boards/oplinkmini/firmware/pios_board.c | 26 ++++++++++++++++--- shared/uavobjectdefinition/oplinksettings.xml | 4 +-- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/flight/targets/boards/oplinkmini/firmware/pios_board.c b/flight/targets/boards/oplinkmini/firmware/pios_board.c index f1e3b78a59..055bc23a33 100644 --- a/flight/targets/boards/oplinkmini/firmware/pios_board.c +++ b/flight/targets/boards/oplinkmini/firmware/pios_board.c @@ -66,19 +66,21 @@ uint32_t pios_com_telem_uart_main_id = 0; uint32_t pios_com_telem_uart_flexi_id = 0; uint32_t pios_com_telemetry_id = 0; uint32_t pios_com_bridge_id = 0; -uint32_t pios_com_vcp_id = 0; +uint32_t pios_com_vcp_id = 0; #if defined(PIOS_INCLUDE_PPM) -uint32_t pios_ppm_rcvr_id = 0; +uint32_t pios_ppm_rcvr_id = 0; #endif #if defined(PIOS_INCLUDE_PPM_OUT) -uint32_t pios_ppm_out_id = 0; +uint32_t pios_ppm_out_id = 0; #endif #if defined(PIOS_INCLUDE_RFM22B) +#include uint32_t pios_rfm22b_id = 0; uint32_t pios_com_rfm22b_id = 0; uint32_t pios_com_radio_id = 0; #endif + uintptr_t pios_uavo_settings_fs_id; uintptr_t pios_user_fs_id = 0; @@ -496,6 +498,24 @@ void PIOS_Board_Init(void) // Reinitialize the modem to affect the changes. PIOS_RFM22B_Reinit(pios_rfm22b_id); + uint8_t oplinksettings_radioaux; + OPLinkSettingsRadioAuxStreamGet(&oplinksettings_radioaux); + switch (oplinksettings_radioaux) { + case OPLINKSETTINGS_RADIOAUXSTREAM_DISABLED: + break; + case OPLINKSETTINGS_RADIOAUXSTREAM_COMBRIDGE: + { + uint8_t *auxrx_buffer = (uint8_t *)pios_malloc(PIOS_COM_TELEM_RX_BUF_LEN); + uint8_t *auxtx_buffer = (uint8_t *)pios_malloc(PIOS_COM_TELEM_TX_BUF_LEN); + PIOS_Assert(auxrx_buffer); + PIOS_Assert(auxtx_buffer); + if (PIOS_COM_Init(&pios_com_bridge_id, &pios_rfm22b_aux_com_driver, pios_rfm22b_id, + auxrx_buffer, PIOS_COM_TELEM_RX_BUF_LEN, + auxtx_buffer, PIOS_COM_TELEM_TX_BUF_LEN)) { + PIOS_Assert(0); + } + } + } } // openlrs } else { oplinkStatus.LinkState = OPLINKSTATUS_LINKSTATE_DISABLED; diff --git a/shared/uavobjectdefinition/oplinksettings.xml b/shared/uavobjectdefinition/oplinksettings.xml index 1e538934e2..2b83d21bd8 100644 --- a/shared/uavobjectdefinition/oplinksettings.xml +++ b/shared/uavobjectdefinition/oplinksettings.xml @@ -21,8 +21,8 @@ - - + + From 14080021b2f77e077767133fa82528d6bd8e86f3 Mon Sep 17 00:00:00 2001 From: Alessio Morale Date: Sat, 29 Oct 2016 19:46:10 +0200 Subject: [PATCH 062/624] LP-437 - Support for Revolution --- .../boards/revolution/firmware/pios_board.c | 28 +++++++++++++++++++ shared/uavobjectdefinition/hwsettings.xml | 3 +- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/flight/targets/boards/revolution/firmware/pios_board.c b/flight/targets/boards/revolution/firmware/pios_board.c index 15b0a2f9b9..d324ef6192 100644 --- a/flight/targets/boards/revolution/firmware/pios_board.c +++ b/flight/targets/boards/revolution/firmware/pios_board.c @@ -260,6 +260,7 @@ uint32_t pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_NONE]; #define PIOS_COM_MSP_TX_BUF_LEN 128 #define PIOS_COM_MSP_RX_BUF_LEN 64 #define PIOS_COM_MAVLINK_TX_BUF_LEN 128 +#define PIOS_COM_MAVLINK_RX_BUF_LEN 128 #if defined(PIOS_INCLUDE_DEBUG_CONSOLE) #define PIOS_COM_DEBUGCONSOLE_TX_BUF_LEN 40 @@ -279,6 +280,7 @@ uint32_t pios_com_mavlink_id = 0; #if defined(PIOS_INCLUDE_RFM22B) uint32_t pios_rfm22b_id = 0; +#include #endif uintptr_t pios_uavo_settings_fs_id; @@ -997,6 +999,32 @@ void PIOS_Board_Init(void) /* Reinitialize the modem. */ PIOS_RFM22B_Reinit(pios_rfm22b_id); + + uint8_t hwsettings_radioaux; + HwSettingsRadioAuxStreamGet(&hwsettings_radioaux); + // TODO: this is in preparation for full mavlink support and is used by LP-368 + uint16_t mavlink_rx_size = PIOS_COM_MAVLINK_RX_BUF_LEN; + + switch (hwsettings_radioaux) { + case HWSETTINGS_RADIOAUXSTREAM_DEBUGCONSOLE: + case HWSETTINGS_RADIOAUXSTREAM_DISABLED: + break; + case HWSETTINGS_RADIOAUXSTREAM_MAVLINK: + { + uint8_t *auxrx_buffer = 0; + if (mavlink_rx_size) { + auxrx_buffer = (uint8_t *)pios_malloc(mavlink_rx_size); + } + uint8_t *auxtx_buffer = (uint8_t *)pios_malloc(PIOS_COM_MAVLINK_TX_BUF_LEN); + PIOS_Assert(auxrx_buffer); + PIOS_Assert(auxtx_buffer); + if (PIOS_COM_Init(&pios_com_mavlink_id, &pios_rfm22b_aux_com_driver, pios_rfm22b_id, + auxrx_buffer, mavlink_rx_size, + auxtx_buffer, PIOS_COM_BRIDGE_TX_BUF_LEN)) { + PIOS_Assert(0); + } + } + } } } else { oplinkStatus.LinkState = OPLINKSTATUS_LINKSTATE_DISABLED; diff --git a/shared/uavobjectdefinition/hwsettings.xml b/shared/uavobjectdefinition/hwsettings.xml index fa31c1040a..ae30f9ec55 100644 --- a/shared/uavobjectdefinition/hwsettings.xml +++ b/shared/uavobjectdefinition/hwsettings.xml @@ -28,7 +28,8 @@ - + + From e39a5a92bcc50c1298e6b609924879e69dc2db66 Mon Sep 17 00:00:00 2001 From: Alessio Morale Date: Sat, 29 Oct 2016 19:57:33 +0200 Subject: [PATCH 063/624] LP-437 - Support for Sparky2 --- .../boards/sparky2/firmware/pios_board.c | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/flight/targets/boards/sparky2/firmware/pios_board.c b/flight/targets/boards/sparky2/firmware/pios_board.c index c73b96aea5..c408d31faf 100644 --- a/flight/targets/boards/sparky2/firmware/pios_board.c +++ b/flight/targets/boards/sparky2/firmware/pios_board.c @@ -212,6 +212,7 @@ uint32_t pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_NONE]; #define PIOS_COM_MSP_RX_BUF_LEN 64 #define PIOS_COM_MAVLINK_TX_BUF_LEN 128 +#define PIOS_COM_MAVLINK_RX_BUF_LEN 128 #if defined(PIOS_INCLUDE_DEBUG_CONSOLE) #define PIOS_COM_DEBUGCONSOLE_TX_BUF_LEN 40 @@ -231,6 +232,7 @@ uint32_t pios_com_vcp_id = 0; #if defined(PIOS_INCLUDE_RFM22B) uint32_t pios_rfm22b_id = 0; +#include #endif uintptr_t pios_uavo_settings_fs_id; @@ -937,6 +939,32 @@ void PIOS_Board_Init(void) /* Reinitialize the modem. */ PIOS_RFM22B_Reinit(pios_rfm22b_id); + // TODO: this is in preparation for full mavlink support and is used by LP-368 + uint16_t mavlink_rx_size = PIOS_COM_MAVLINK_RX_BUF_LEN; + + uint8_t hwsettings_radioaux; + HwSettingsRadioAuxStreamGet(&hwsettings_radioaux); + + switch (hwsettings_radioaux) { + case HWSETTINGS_RADIOAUXSTREAM_DEBUGCONSOLE: + case HWSETTINGS_RADIOAUXSTREAM_DISABLED: + break; + case HWSETTINGS_RADIOAUXSTREAM_MAVLINK: + { + uint8_t *auxrx_buffer = 0; + if (mavlink_rx_size) { + auxrx_buffer = (uint8_t *)pios_malloc(mavlink_rx_size); + } + uint8_t *auxtx_buffer = (uint8_t *)pios_malloc(PIOS_COM_MAVLINK_TX_BUF_LEN); + PIOS_Assert(auxrx_buffer); + PIOS_Assert(auxtx_buffer); + if (PIOS_COM_Init(&pios_com_mavlink_id, &pios_rfm22b_aux_com_driver, pios_rfm22b_id, + auxrx_buffer, mavlink_rx_size, + auxtx_buffer, PIOS_COM_BRIDGE_TX_BUF_LEN)) { + PIOS_Assert(0); + } + } + } } } else { oplinkStatus.LinkState = OPLINKSTATUS_LINKSTATE_DISABLED; From 306c129480cf737892f44274a2a5c0479cf9c37d Mon Sep 17 00:00:00 2001 From: Alessio Morale Date: Sat, 29 Oct 2016 20:56:25 +0200 Subject: [PATCH 064/624] LP-437 - GCS configuration support --- .../src/plugins/config/configoplinkwidget.cpp | 1 + .../src/plugins/config/configrevohwwidget.cpp | 2 ++ .../src/plugins/config/configrevohwwidget.ui | 13 +++++++ .../plugins/config/configsparky2hwwidget.cpp | 2 ++ .../plugins/config/configsparky2hwwidget.ui | 15 ++++++++ ground/gcs/src/plugins/config/oplink.ui | 34 +++++++++++++++++-- 6 files changed, 65 insertions(+), 2 deletions(-) diff --git a/ground/gcs/src/plugins/config/configoplinkwidget.cpp b/ground/gcs/src/plugins/config/configoplinkwidget.cpp index 634cab08dc..d857d3c9df 100644 --- a/ground/gcs/src/plugins/config/configoplinkwidget.cpp +++ b/ground/gcs/src/plugins/config/configoplinkwidget.cpp @@ -83,6 +83,7 @@ ConfigOPLinkWidget::ConfigOPLinkWidget(QWidget *parent) : ConfigTaskWidget(paren addWidgetBinding("OPLinkSettings", "MainPort", m_oplink->MainPort); addWidgetBinding("OPLinkSettings", "FlexiPort", m_oplink->FlexiPort); addWidgetBinding("OPLinkSettings", "VCPPort", m_oplink->VCPPort); + addWidgetBinding("OPLinkSettings", "RadioAuxStream", m_oplink->RadioAuxPort); addWidgetBinding("OPLinkSettings", "RFXtalCap", m_oplink->RFXtalCapValue); addWidgetBinding("OPLinkSettings", "RFXtalCap", m_oplink->RFXtalCapSlider); diff --git a/ground/gcs/src/plugins/config/configrevohwwidget.cpp b/ground/gcs/src/plugins/config/configrevohwwidget.cpp index e5e3bc151f..53d7120c83 100644 --- a/ground/gcs/src/plugins/config/configrevohwwidget.cpp +++ b/ground/gcs/src/plugins/config/configrevohwwidget.cpp @@ -66,6 +66,8 @@ ConfigRevoHWWidget::ConfigRevoHWWidget(QWidget *parent) : ConfigTaskWidget(paren addWidgetBinding("GPSSettings", "DataProtocol", m_ui->cbFlexiGPSProtocol); addWidgetBinding("GPSSettings", "DataProtocol", m_ui->cbRcvrGPSProtocol); + addWidgetBinding("HwSettings", "RadioAuxStream", m_ui->cbRadioAux); + setupCustomCombos(); } diff --git a/ground/gcs/src/plugins/config/configrevohwwidget.ui b/ground/gcs/src/plugins/config/configrevohwwidget.ui index 3ab3da94c8..309100f859 100644 --- a/ground/gcs/src/plugins/config/configrevohwwidget.ui +++ b/ground/gcs/src/plugins/config/configrevohwwidget.ui @@ -530,6 +530,19 @@ + + + + Radio aux Stream + + + Qt::AlignBottom|Qt::AlignHCenter + + + + + + diff --git a/ground/gcs/src/plugins/config/configsparky2hwwidget.cpp b/ground/gcs/src/plugins/config/configsparky2hwwidget.cpp index 178d9d5048..9d80309cad 100644 --- a/ground/gcs/src/plugins/config/configsparky2hwwidget.cpp +++ b/ground/gcs/src/plugins/config/configsparky2hwwidget.cpp @@ -63,6 +63,8 @@ ConfigSparky2HWWidget::ConfigSparky2HWWidget(QWidget *parent) : ConfigTaskWidget addWidgetBinding("GPSSettings", "DataProtocol", m_ui->cbMainGPSProtocol); addWidgetBinding("GPSSettings", "DataProtocol", m_ui->cbFlexiGPSProtocol); + addWidgetBinding("HwSettings", "RadioAuxStream", m_ui->cbRadioAux); + setupCustomCombos(); } diff --git a/ground/gcs/src/plugins/config/configsparky2hwwidget.ui b/ground/gcs/src/plugins/config/configsparky2hwwidget.ui index 97d32924be..c95fd7fbee 100644 --- a/ground/gcs/src/plugins/config/configsparky2hwwidget.ui +++ b/ground/gcs/src/plugins/config/configsparky2hwwidget.ui @@ -457,6 +457,21 @@ + + + + + Radio aux Stream + + + Qt::AlignBottom|Qt::AlignHCenter + + + + + + + diff --git a/ground/gcs/src/plugins/config/oplink.ui b/ground/gcs/src/plugins/config/oplink.ui index 5e6dfca6ff..a0ddf122d1 100644 --- a/ground/gcs/src/plugins/config/oplink.ui +++ b/ground/gcs/src/plugins/config/oplink.ui @@ -55,8 +55,8 @@ 0 0 - 947 - 575 + 926 + 647 @@ -672,6 +672,35 @@ Leave blank to use autogenerated Device ID. + + + + + 50 + false + + + + Radio aux Port + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 16777215 + 16777215 + + + + Choose the function for the radio aux virtual com port. + + + @@ -2200,6 +2229,7 @@ a frequency misalignement between the two modems. MainPort FlexiPort VCPPort + RadioAuxPort RFXtalCapValue applyButton saveButton From 174b616a05a72989198dbde491249ae6195fd338 Mon Sep 17 00:00:00 2001 From: Alessio Morale Date: Fri, 4 Nov 2016 01:50:01 +0100 Subject: [PATCH 065/624] LP-437 - Cosmetic/GCS Fixes from review --- ground/gcs/src/plugins/config/configoplinkwidget.cpp | 4 ++++ ground/gcs/src/plugins/config/configrevohwwidget.ui | 2 +- ground/gcs/src/plugins/config/configsparky2hwwidget.ui | 2 +- ground/gcs/src/plugins/config/oplink.ui | 4 ++-- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/ground/gcs/src/plugins/config/configoplinkwidget.cpp b/ground/gcs/src/plugins/config/configoplinkwidget.cpp index d857d3c9df..4ed80865d0 100644 --- a/ground/gcs/src/plugins/config/configoplinkwidget.cpp +++ b/ground/gcs/src/plugins/config/configoplinkwidget.cpp @@ -209,6 +209,8 @@ void ConfigOPLinkWidget::setPortsVisible(bool visible) m_oplink->FlexiPortLabel->setVisible(visible); m_oplink->VCPPort->setVisible(visible); m_oplink->VCPPortLabel->setVisible(visible); + m_oplink->RadioAuxPort->setVisible(visible); + m_oplink->RadioAuxPortLabel->setVisible(visible); } void ConfigOPLinkWidget::updateInfo() @@ -265,6 +267,8 @@ void ConfigOPLinkWidget::updateSettings() m_oplink->UnbindButton->setEnabled(is_enabled && is_bound && !is_coordinator); m_oplink->CustomDeviceID->setEnabled(is_coordinator); + m_oplink->RadioAuxPort->setEnabled(is_receiver || is_coordinator); + m_oplink->RFBand->setEnabled(is_receiver || is_coordinator); m_oplink->MinimumChannel->setEnabled(is_receiver || is_coordinator); m_oplink->MaximumChannel->setEnabled(is_receiver || is_coordinator); diff --git a/ground/gcs/src/plugins/config/configrevohwwidget.ui b/ground/gcs/src/plugins/config/configrevohwwidget.ui index 309100f859..c3c3c82d6b 100644 --- a/ground/gcs/src/plugins/config/configrevohwwidget.ui +++ b/ground/gcs/src/plugins/config/configrevohwwidget.ui @@ -533,7 +533,7 @@ - Radio aux Stream + Radio Aux Stream Qt::AlignBottom|Qt::AlignHCenter diff --git a/ground/gcs/src/plugins/config/configsparky2hwwidget.ui b/ground/gcs/src/plugins/config/configsparky2hwwidget.ui index c95fd7fbee..0a27b10eb3 100644 --- a/ground/gcs/src/plugins/config/configsparky2hwwidget.ui +++ b/ground/gcs/src/plugins/config/configsparky2hwwidget.ui @@ -461,7 +461,7 @@ - Radio aux Stream + Radio Aux Stream Qt::AlignBottom|Qt::AlignHCenter diff --git a/ground/gcs/src/plugins/config/oplink.ui b/ground/gcs/src/plugins/config/oplink.ui index a0ddf122d1..2a6b2a6dab 100644 --- a/ground/gcs/src/plugins/config/oplink.ui +++ b/ground/gcs/src/plugins/config/oplink.ui @@ -681,7 +681,7 @@ Leave blank to use autogenerated Device ID. - Radio aux Port + Radio Aux Port Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter @@ -697,7 +697,7 @@ Leave blank to use autogenerated Device ID. - Choose the function for the radio aux virtual com port. + Choose the function for the Radio Auxiliary virtual com port. From ce87ce105e3959d6ad4ce75673b801e0364ff2b5 Mon Sep 17 00:00:00 2001 From: Alessio Morale Date: Mon, 18 Jul 2016 01:17:47 +0200 Subject: [PATCH 066/624] LP-443 - Add INS14 to Sparky/Revo --- flight/libraries/inc/insgps.h | 33 +- flight/libraries/insgps14state.c | 986 ++++++++++++++++++ flight/modules/StateEstimation/filterekf.c | 11 +- .../boards/revolution/firmware/Makefile | 2 +- .../targets/boards/sparky2/firmware/Makefile | 2 +- 5 files changed, 1011 insertions(+), 23 deletions(-) create mode 100644 flight/libraries/insgps14state.c diff --git a/flight/libraries/inc/insgps.h b/flight/libraries/inc/insgps.h index c77d44510f..eb39948182 100644 --- a/flight/libraries/inc/insgps.h +++ b/flight/libraries/inc/insgps.h @@ -32,7 +32,8 @@ #ifndef INSGPS_H_ #define INSGPS_H_ -#include "stdint.h" +#include +#include /** * @addtogroup Constants @@ -54,22 +55,24 @@ // Exposed Function Prototypes void INSGPSInit(); -void INSStatePrediction(float gyro_data[3], float accel_data[3], float dT); +void INSStatePrediction(const float gyro_data[3], const float accel_data[3], float dT); void INSCovariancePrediction(float dT); -void INSCorrection(float mag_data[3], float Pos[3], float Vel[3], float BaroAlt, uint16_t SensorsUsed); - -void INSResetP(float PDiag[13]); -void INSGetP(float PDiag[13]); -void INSSetState(float pos[3], float vel[3], float q[4], float gyro_bias[3], float accel_bias[3]); +void INSCorrection(const float mag_data[3], const float Pos[3], const float Vel[3], + float BaroAlt, uint16_t SensorsUsed); +void INSResetP(const float PDiag[13]); +void INSGetVariance(float PDiag[13]); +void INSSetState(const float pos[3], const float vel[3], const float q[4], const float gyro_bias[3], const float accel_bias[3]); void INSSetPosVelVar(float PosVar[3], float VelVar[3]); -void INSSetGyroBias(float gyro_bias[3]); -void INSSetAccelVar(float accel_var[3]); -void INSSetGyroVar(float gyro_var[3]); -void INSSetGyroBiasVar(float gyro_bias_var[3]); -void INSSetMagNorth(float B[3]); -void INSSetMagVar(float scaled_mag_var[3]); -void INSSetBaroVar(float baro_var); -void INSPosVelReset(float pos[3], float vel[3]); +void INSSetGyroBias(const float gyro_bias[3]); +void INSSetAccelVar(const float accel_var[3]); +void INSSetGyroVar(const float gyro_var[3]); +void INSSetGyroBiasVar(const float gyro_bias_var[3]); +void INSSetMagNorth(const float B[3]); +void INSSetMagVar(const float scaled_mag_var[3]); +void INSSetBaroVar(const float baro_var); +void INSSetArmed(bool armed); +void INSPosVelReset(const float pos[3], const float vel[3]); + void MagCorrection(float mag_data[3]); void MagVelBaroCorrection(float mag_data[3], float Vel[3], float BaroAlt); diff --git a/flight/libraries/insgps14state.c b/flight/libraries/insgps14state.c new file mode 100644 index 0000000000..02b9b8faa1 --- /dev/null +++ b/flight/libraries/insgps14state.c @@ -0,0 +1,986 @@ +/** + ****************************************************************************** + * @addtogroup Math + * @{ + * @addtogroup INSGPS + * @{ + * @brief INSGPS is a joint attitude and position estimation EKF + * + * @file insgps.c + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * Tau Labs, http://github.com/TauLabs Copyright (C) 2012-2013. + * The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. + * @brief An INS/GPS algorithm implemented with an EKF. + * + * @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 "insgps.h" +#include +#include +#include +#include +#include +#include + +// constants/macros/typdefs +#define NUMX 14 // number of states, X is the state vector +#define NUMW 10 // number of plant noise inputs, w is disturbance noise vector +#define NUMV 10 // number of measurements, v is the measurement noise vector +#define NUMU 6 // number of deterministic inputs, U is the input vector + +#if defined(GENERAL_COV) +// This might trick people so I have a note here. There is a slower but bigger version of the +// code here but won't fit when debugging disabled (requires -Os) +#define COVARIANCE_PREDICTION_GENERAL +#endif + +// Private functions +void CovariancePrediction(float F[NUMX][NUMX], float G[NUMX][NUMW], + float Q[NUMW], float dT, float P[NUMX][NUMX]); +void SerialUpdate(float H[NUMV][NUMX], float R[NUMV], float Z[NUMV], + float Y[NUMV], float P[NUMX][NUMX], float X[NUMX], + uint16_t SensorsUsed); +void RungeKutta(float X[NUMX], float U[NUMU], float dT); +void StateEq(float X[NUMX], float U[NUMU], float Xdot[NUMX]); +void LinearizeFG(float X[NUMX], float U[NUMU], float F[NUMX][NUMX], + float G[NUMX][NUMW]); +void MeasurementEq(float X[NUMX], float Be[3], float Y[NUMV]); +void LinearizeH(float X[NUMX], float Be[3], float H[NUMV][NUMX]); + + +// Private variables +static struct EKFData { + float F[NUMX][NUMX]; + float G[NUMX][NUMW]; + float H[NUMV][NUMX]; // linearized system matrices + // global to init to zero and maintain zero elements + float Be[3]; // local magnetic unit vector in NED frame + float P[NUMX][NUMX]; + float X[NUMX]; // covariance matrix and state vector + float Q[NUMW]; + float R[NUMV]; // input noise and measurement noise variances + float K[NUMX][NUMV]; // feedback gain matrix +} ekf; + +// Global variables +struct NavStruct Nav; + +// ************* Exposed Functions **************** +// ************************************************* + +uint16_t ins_get_num_states() +{ + return NUMX; +} + +void INSGPSInit() // pretty much just a place holder for now +{ + ekf.Be[0] = 1.0f; + ekf.Be[1] = 0; + ekf.Be[2] = 0; // local magnetic unit vector + + for (int i = 0; i < NUMX; i++) { + for (int j = 0; j < NUMX; j++) { + ekf.P[i][j] = 0.0f; // zero all terms + ekf.F[i][j] = 0.0f; + } + for (int j = 0; j < NUMW; j++) { + ekf.G[i][j] = 0.0f; + } + + for (int j = 0; j < NUMV; j++) { + ekf.H[j][i] = 0.0f; + ekf.K[i][j] = 0.0f; + } + + ekf.X[i] = 0.0f; + } + for (int i = 0; i < NUMW; i++) { + ekf.Q[i] = 0.0f; + } + for (int i = 0; i < NUMV; i++) { + ekf.R[i] = 0.0f; + } + + ekf.P[0][0] = ekf.P[1][1] = ekf.P[2][2] = 25.0f; // initial position variance (m^2) + ekf.P[3][3] = ekf.P[4][4] = ekf.P[5][5] = 5.0f; // initial velocity variance (m/s)^2 + ekf.P[6][6] = ekf.P[7][7] = ekf.P[8][8] = ekf.P[9][9] = 1e-5f; // initial quaternion variance + ekf.P[10][10] = ekf.P[11][11] = ekf.P[12][12] = 1e-6f; // initial gyro bias variance (rad/s)^2 + ekf.P[13][13] = 1e-5f; // initial accel bias variance (deg/s)^2 + + ekf.X[0] = ekf.X[1] = ekf.X[2] = ekf.X[3] = ekf.X[4] = ekf.X[5] = 0.0f; // initial pos and vel (m) + ekf.X[6] = 1.0f; + ekf.X[7] = ekf.X[8] = ekf.X[9] = 0.0f; // initial quaternion (level and North) (m/s) + ekf.X[10] = ekf.X[11] = ekf.X[12] = 0.0f; // initial gyro bias (rad/s) + ekf.X[13] = 0.0f; // initial accel bias + + ekf.Q[0] = ekf.Q[1] = ekf.Q[2] = 1e-5f; // gyro noise variance (rad/s)^2 + ekf.Q[3] = ekf.Q[4] = ekf.Q[5] = 1e-5f; // accelerometer noise variance (m/s^2)^2 + ekf.Q[6] = ekf.Q[7] = 1e-6f; // gyro x and y bias random walk variance (rad/s^2)^2 + ekf.Q[8] = 1e-6f; // gyro z bias random walk variance (rad/s^2)^2 + ekf.Q[9] = 5e-4f; // accel bias random walk variance (m/s^3)^2 + + ekf.R[0] = ekf.R[1] = 0.004f; // High freq GPS horizontal position noise variance (m^2) + ekf.R[2] = 0.036f; // High freq GPS vertical position noise variance (m^2) + ekf.R[3] = ekf.R[4] = 0.004f; // High freq GPS horizontal velocity noise variance (m/s)^2 + ekf.R[5] = 0.004f; // High freq GPS vertical velocity noise variance (m/s)^2 + ekf.R[6] = ekf.R[7] = ekf.R[8] = 0.005f; // magnetometer unit vector noise variance + ekf.R[9] = .05f; // High freq altimeter noise variance (m^2) +} + +// ! Set the current flight state +void INSSetArmed(bool armed) +{ + return; + + // Speed up convergence of accel and gyro bias when not armed + if (armed) { + ekf.Q[9] = 1e-4f; + ekf.Q[8] = 2e-9f; + } else { + ekf.Q[9] = 1e-2f; + ekf.Q[8] = 2e-8f; + } +} + +/** + * Get the current state estimate (null input skips that get) + * @param[out] pos The position in NED space (m) + * @param[out] vel The velocity in NED (m/s) + * @param[out] attitude Quaternion representation of attitude + * @param[out] gyros_bias Estimate of gyro bias (rad/s) + * @param[out] accel_bias Estiamte of the accel bias (m/s^2) + */ +void INSGetState(float *pos, float *vel, float *attitude, float *gyro_bias, float *accel_bias) +{ + if (pos) { + pos[0] = ekf.X[0]; + pos[1] = ekf.X[1]; + pos[2] = ekf.X[2]; + } + + if (vel) { + vel[0] = ekf.X[3]; + vel[1] = ekf.X[4]; + vel[2] = ekf.X[5]; + } + + if (attitude) { + attitude[0] = ekf.X[6]; + attitude[1] = ekf.X[7]; + attitude[2] = ekf.X[8]; + attitude[3] = ekf.X[9]; + } + + if (gyro_bias) { + gyro_bias[0] = ekf.X[10]; + gyro_bias[1] = ekf.X[11]; + gyro_bias[2] = ekf.X[12]; + } + + if (accel_bias) { + accel_bias[0] = 0.0f; + accel_bias[1] = 0.0f; + accel_bias[2] = ekf.X[13]; + } +} + +/** + * Get the variance, for visualizing the filter performance + * @param[out var_out The variances + */ +void INSGetVariance(float *var_out) +{ + for (uint32_t i = 0; i < NUMX; i++) { + var_out[i] = ekf.P[i][i]; + } +} + +void INSResetP(const float *PDiag) +{ + uint8_t i, j; + + // if PDiag[i] nonzero then clear row and column and set diagonal element + for (i = 0; i < NUMX; i++) { + if (PDiag != 0) { + for (j = 0; j < NUMX; j++) { + ekf.P[i][j] = ekf.P[j][i] = 0.0f; + } + ekf.P[i][i] = PDiag[i]; + } + } +} + +void INSSetState(const float pos[3], const float vel[3], const float q[4], const float gyro_bias[3], const float accel_bias[3]) +{ + ekf.X[0] = pos[0]; + ekf.X[1] = pos[1]; + ekf.X[2] = pos[2]; + ekf.X[3] = vel[0]; + ekf.X[4] = vel[1]; + ekf.X[5] = vel[2]; + ekf.X[6] = q[0]; + ekf.X[7] = q[1]; + ekf.X[8] = q[2]; + ekf.X[9] = q[3]; + ekf.X[10] = gyro_bias[0]; + ekf.X[11] = gyro_bias[1]; + ekf.X[12] = gyro_bias[2]; + ekf.X[13] = accel_bias[2]; +} + +void INSPosVelReset(const float pos[3], const float vel[3]) +{ + for (int i = 0; i < 6; i++) { + for (int j = i; j < NUMX; j++) { + ekf.P[i][j] = 0.0f; // zero the first 6 rows and columns + ekf.P[j][i] = 0.0f; + } + } + + ekf.P[0][0] = ekf.P[1][1] = ekf.P[2][2] = 25.0f; // initial position variance (m^2) + ekf.P[3][3] = ekf.P[4][4] = ekf.P[5][5] = 5.0f; // initial velocity variance (m/s)^2 + + ekf.X[0] = pos[0]; + ekf.X[1] = pos[1]; + ekf.X[2] = pos[2]; + ekf.X[3] = vel[0]; + ekf.X[4] = vel[1]; + ekf.X[5] = vel[2]; +} +void INSSetPosVelVar(float PosVar[3], float VelVar[3]) +// void INSSetPosVelVar(float PosVar, float VelVar, float VertPosVar) +{ + ekf.R[0] = PosVar[0]; + ekf.R[1] = PosVar[1]; + ekf.R[2] = PosVar[2]; + ekf.R[3] = VelVar[0]; + ekf.R[4] = VelVar[1]; + ekf.R[5] = VelVar[2]; // Don't change vertical velocity, not measured +} + +void INSSetGyroBias(const float gyro_bias[3]) +{ + ekf.X[10] = gyro_bias[0]; + ekf.X[11] = gyro_bias[1]; + ekf.X[12] = gyro_bias[2]; +} + +void INSSetAccelBias(const float accel_bias[3]) +{ + ekf.X[13] = accel_bias[2]; +} + +void INSSetAccelVar(const float accel_var[3]) +{ + ekf.Q[3] = accel_var[0]; + ekf.Q[4] = accel_var[1]; + ekf.Q[5] = accel_var[2]; +} + +void INSSetGyroVar(const float gyro_var[3]) +{ + ekf.Q[0] = gyro_var[0]; + ekf.Q[1] = gyro_var[1]; + ekf.Q[2] = gyro_var[2]; +} + +void INSSetGyroBiasVar(const float gyro_bias_var[3]) +{ + ekf.Q[6] = gyro_bias_var[0]; + ekf.Q[7] = gyro_bias_var[1]; + ekf.Q[8] = gyro_bias_var[2]; +} + +void INSSetMagVar(const float scaled_mag_var[3]) +{ + ekf.R[6] = scaled_mag_var[0]; + ekf.R[7] = scaled_mag_var[1]; + ekf.R[8] = scaled_mag_var[2]; +} + +void INSSetBaroVar(const float baro_var) +{ + ekf.R[9] = baro_var; +} + +void INSSetMagNorth(const float B[3]) +{ + ekf.Be[0] = B[0]; + ekf.Be[1] = B[1]; + ekf.Be[2] = B[2]; +} + +void INSLimitBias() +{ + // The Z accel bias should never wander too much. This helps ensure the filter + // remains stable. + if (ekf.X[13] > 0.1f) { + ekf.X[13] = 0.1f; + } else if (ekf.X[13] < -0.1f) { + ekf.X[13] = -0.1f; + } + + // Make sure no gyro bias gets to more than 10 deg / s. This should be more than + // enough for well behaving sensors. + const float GYRO_BIAS_LIMIT = DEG2RAD(10); + for (int i = 10; i < 13; i++) { + if (ekf.X[i] < -GYRO_BIAS_LIMIT) { + ekf.X[i] = -GYRO_BIAS_LIMIT; + } else if (ekf.X[i] > GYRO_BIAS_LIMIT) { + ekf.X[i] = GYRO_BIAS_LIMIT; + } + } +} + +void INSStatePrediction(const float gyro_data[3], const float accel_data[3], float dT) +{ + float U[6]; + float qmag; + + // rate gyro inputs in units of rad/s + U[0] = gyro_data[0]; + U[1] = gyro_data[1]; + U[2] = gyro_data[2]; + + // accelerometer inputs in units of m/s + U[3] = accel_data[0]; + U[4] = accel_data[1]; + U[5] = accel_data[2]; + + // EKF prediction step + LinearizeFG(ekf.X, U, ekf.F, ekf.G); + RungeKutta(ekf.X, U, dT); + qmag = sqrtf(ekf.X[6] * ekf.X[6] + ekf.X[7] * ekf.X[7] + ekf.X[8] * ekf.X[8] + ekf.X[9] * ekf.X[9]); + ekf.X[6] /= qmag; + ekf.X[7] /= qmag; + ekf.X[8] /= qmag; + ekf.X[9] /= qmag; + + // Update Nav solution structure + Nav.Pos[0] = ekf.X[0]; + Nav.Pos[1] = ekf.X[1]; + Nav.Pos[2] = ekf.X[2]; + Nav.Vel[0] = ekf.X[3]; + Nav.Vel[1] = ekf.X[4]; + Nav.Vel[2] = ekf.X[5]; + Nav.q[0] = ekf.X[6]; + Nav.q[1] = ekf.X[7]; + Nav.q[2] = ekf.X[8]; + Nav.q[3] = ekf.X[9]; + Nav.gyro_bias[0] = ekf.X[10]; + Nav.gyro_bias[1] = ekf.X[11]; + Nav.gyro_bias[2] = ekf.X[12]; + Nav.gyro_bias[0] = 0.0f; + Nav.gyro_bias[1] = 0.0f; + Nav.gyro_bias[2] = ekf.X[13]; +} + +void INSCovariancePrediction(float dT) +{ + CovariancePrediction(ekf.F, ekf.G, ekf.Q, dT, ekf.P); +} + +void INSCorrection(const float mag_data[3], const float Pos[3], const float Vel[3], + float BaroAlt, uint16_t SensorsUsed) +{ + float Z[10], Y[10]; + float qmag; + + // GPS Position in meters and in local NED frame + Z[0] = Pos[0]; + Z[1] = Pos[1]; + Z[2] = Pos[2]; + + // GPS Velocity in meters and in local NED frame + Z[3] = Vel[0]; + Z[4] = Vel[1]; + Z[5] = Vel[2]; + + if (SensorsUsed & MAG_SENSORS) { + // magnetometer data in any units (use unit vector) and in body frame + float Rbe_a[3][3]; + float q0 = ekf.X[6]; + float q1 = ekf.X[7]; + float q2 = ekf.X[8]; + float q3 = ekf.X[9]; + float k1 = 1.0f / sqrtf(powf(q0 * q1 * 2.0f + q2 * q3 * 2.0f, 2.0f) + powf(q0 * q0 - q1 * q1 - q2 * q2 + q3 * q3, 2.0f)); + float k2 = sqrtf(-powf(q0 * q2 * 2.0f - q1 * q3 * 2.0f, 2.0f) + 1.0f); + + Rbe_a[0][0] = k2; + Rbe_a[0][1] = 0.0f; + Rbe_a[0][2] = q0 * q2 * -2.0f + q1 * q3 * 2.0f; + Rbe_a[1][0] = k1 * (q0 * q1 * 2.0f + q2 * q3 * 2.0f) * (q0 * q2 * 2.0f - q1 * q3 * 2.0f); + Rbe_a[1][1] = k1 * (q0 * q0 - q1 * q1 - q2 * q2 + q3 * q3); + Rbe_a[1][2] = k1 * sqrtf(-powf(q0 * q2 * 2.0f - q1 * q3 * 2.0f, 2.0f) + 1.0f) * (q0 * q1 * 2.0f + q2 * q3 * 2.0f); + Rbe_a[2][0] = k1 * (q0 * q2 * 2.0f - q1 * q3 * 2.0f) * (q0 * q0 - q1 * q1 - q2 * q2 + q3 * q3); + Rbe_a[2][1] = -k1 * (q0 * q1 * 2.0f + q2 * q3 * 2.0f); + Rbe_a[2][2] = k1 * k2 * (q0 * q0 - q1 * q1 - q2 * q2 + q3 * q3); + + Z[6] = Rbe_a[0][0] * mag_data[0] + Rbe_a[1][0] * mag_data[1] + Rbe_a[2][0] * mag_data[2]; + Z[7] = Rbe_a[0][1] * mag_data[0] + Rbe_a[1][1] * mag_data[1] + Rbe_a[2][1] * mag_data[2]; + Z[8] = Rbe_a[0][2] * mag_data[0] + Rbe_a[1][2] * mag_data[1] + Rbe_a[2][2] * mag_data[2]; + } + + // barometric altimeter in meters and in local NED frame + Z[9] = BaroAlt; + + // EKF correction step + LinearizeH(ekf.X, ekf.Be, ekf.H); + MeasurementEq(ekf.X, ekf.Be, Y); + SerialUpdate(ekf.H, ekf.R, Z, Y, ekf.P, ekf.X, SensorsUsed); + qmag = sqrtf(ekf.X[6] * ekf.X[6] + ekf.X[7] * ekf.X[7] + ekf.X[8] * ekf.X[8] + ekf.X[9] * ekf.X[9]); + ekf.X[6] /= qmag; + ekf.X[7] /= qmag; + ekf.X[8] /= qmag; + ekf.X[9] /= qmag; + + INSLimitBias(); +} + +// ************* CovariancePrediction ************* +// Does the prediction step of the Kalman filter for the covariance matrix +// Output, Pnew, overwrites P, the input covariance +// Pnew = (I+F*T)*P*(I+F*T)' + T^2*G*Q*G' +// Q is the discrete time covariance of process noise +// Q is vector of the diagonal for a square matrix with +// dimensions equal to the number of disturbance noise variables +// The General Method is very inefficient,not taking advantage of the sparse F and G +// The first Method is very specific to this implementation +// ************************************************ + +#ifdef COVARIANCE_PREDICTION_GENERAL + +void CovariancePrediction(float F[NUMX][NUMX], float G[NUMX][NUMW], + float Q[NUMW], float dT, float P[NUMX][NUMX]) +{ + float Dummy[NUMX][NUMX], dTsq; + uint8_t i, j, k; + + // Pnew = (I+F*T)*P*(I+F*T)' + T^2*G*Q*G' = T^2[(P/T + F*P)*(I/T + F') + G*Q*G')] + + dTsq = dT * dT; + + for (i = 0; i < NUMX; i++) { // Calculate Dummy = (P/T +F*P) + for (j = 0; j < NUMX; j++) { + Dummy[i][j] = P[i][j] / dT; + for (k = 0; k < NUMX; k++) { + Dummy[i][j] += F[i][k] * P[k][j]; + } + } + } + for (i = 0; i < NUMX; i++) { // Calculate Pnew = Dummy/T + Dummy*F' + G*Qw*G' + for (j = i; j < NUMX; j++) { // Use symmetry, ie only find upper triangular + P[i][j] = Dummy[i][j] / dT; + for (k = 0; k < NUMX; k++) { + P[i][j] += Dummy[i][k] * F[j][k]; // P = Dummy/T + Dummy*F' + } + for (k = 0; k < NUMW; k++) { + P[i][j] += Q[k] * G[i][k] * G[j][k]; // P = Dummy/T + Dummy*F' + G*Q*G' + } + P[j][i] = P[i][j] = P[i][j] * dTsq; // Pnew = T^2*P and fill in lower triangular; + } + } +} + +#else /* ifdef COVARIANCE_PREDICTION_GENERAL */ + +void CovariancePrediction(float F[NUMX][NUMX], float G[NUMX][NUMW], + float Q[NUMW], float dT, float P[NUMX][NUMX]) +{ + float D[NUMX][NUMX], T, Tsq; + uint8_t i, j; + + // Pnew = (I+F*T)*P*(I+F*T)' + T^2*G*Q*G' = scalar expansion from symbolic manipulator + + T = dT; + Tsq = dT * dT; + + for (i = 0; i < NUMX; i++) { // Create a copy of the upper triangular of P + for (j = i; j < NUMX; j++) { + D[i][j] = P[i][j]; + } + } + + // Brute force calculation of the elements of P + P[0][0] = D[3][3] * Tsq + (2 * D[0][3]) * T + D[0][0]; + P[0][1] = P[1][0] = D[3][4] * Tsq + (D[0][4] + D[1][3]) * T + D[0][1]; + P[0][2] = P[2][0] = D[3][5] * Tsq + (D[0][5] + D[2][3]) * T + D[0][2]; + P[0][3] = P[3][0] = (F[3][6] * D[3][6] + F[3][7] * D[3][7] + F[3][8] * D[3][8] + F[3][9] * D[3][9] + F[3][13] * D[3][13]) * Tsq + (D[3][3] + F[3][6] * D[0][6] + F[3][7] * D[0][7] + F[3][8] * D[0][8] + F[3][9] * D[0][9] + F[3][13] * D[0][13]) * T + D[0][3]; + P[0][4] = P[4][0] = (F[4][6] * D[3][6] + F[4][7] * D[3][7] + F[4][8] * D[3][8] + F[4][9] * D[3][9] + F[4][13] * D[3][13]) * Tsq + (D[3][4] + F[4][6] * D[0][6] + F[4][7] * D[0][7] + F[4][8] * D[0][8] + F[4][9] * D[0][9] + F[4][13] * D[0][13]) * T + D[0][4]; + P[0][5] = P[5][0] = (F[5][6] * D[3][6] + F[5][7] * D[3][7] + F[5][8] * D[3][8] + F[5][9] * D[3][9] + F[5][13] * D[3][13]) * Tsq + (D[3][5] + F[5][6] * D[0][6] + F[5][7] * D[0][7] + F[5][8] * D[0][8] + F[5][9] * D[0][9] + F[5][13] * D[0][13]) * T + D[0][5]; + P[0][6] = P[6][0] = (F[6][7] * D[3][7] + F[6][8] * D[3][8] + F[6][9] * D[3][9] + F[6][10] * D[3][10] + F[6][11] * D[3][11] + F[6][12] * D[3][12]) * Tsq + (D[3][6] + F[6][7] * D[0][7] + F[6][8] * D[0][8] + F[6][9] * D[0][9] + F[6][10] * D[0][10] + F[6][11] * D[0][11] + F[6][12] * D[0][12]) * T + D[0][6]; + P[0][7] = P[7][0] = (F[7][6] * D[3][6] + F[7][8] * D[3][8] + F[7][9] * D[3][9] + F[7][10] * D[3][10] + F[7][11] * D[3][11] + F[7][12] * D[3][12]) * Tsq + (D[3][7] + F[7][6] * D[0][6] + F[7][8] * D[0][8] + F[7][9] * D[0][9] + F[7][10] * D[0][10] + F[7][11] * D[0][11] + F[7][12] * D[0][12]) * T + D[0][7]; + P[0][8] = P[8][0] = (F[8][6] * D[3][6] + F[8][7] * D[3][7] + F[8][9] * D[3][9] + F[8][10] * D[3][10] + F[8][11] * D[3][11] + F[8][12] * D[3][12]) * Tsq + (D[3][8] + F[8][6] * D[0][6] + F[8][7] * D[0][7] + F[8][9] * D[0][9] + F[8][10] * D[0][10] + F[8][11] * D[0][11] + F[8][12] * D[0][12]) * T + D[0][8]; + P[0][9] = P[9][0] = (F[9][6] * D[3][6] + F[9][7] * D[3][7] + F[9][8] * D[3][8] + F[9][10] * D[3][10] + F[9][11] * D[3][11] + F[9][12] * D[3][12]) * Tsq + (D[3][9] + F[9][6] * D[0][6] + F[9][7] * D[0][7] + F[9][8] * D[0][8] + F[9][10] * D[0][10] + F[9][11] * D[0][11] + F[9][12] * D[0][12]) * T + D[0][9]; + P[0][10] = P[10][0] = D[3][10] * T + D[0][10]; + P[0][11] = P[11][0] = D[3][11] * T + D[0][11]; + P[0][12] = P[12][0] = D[3][12] * T + D[0][12]; + P[0][13] = P[13][0] = D[3][13] * T + D[0][13]; + P[1][1] = D[4][4] * Tsq + (2 * D[1][4]) * T + D[1][1]; + P[1][2] = P[2][1] = D[4][5] * Tsq + (D[1][5] + D[2][4]) * T + D[1][2]; + P[1][3] = P[3][1] = (F[3][6] * D[4][6] + F[3][7] * D[4][7] + F[3][8] * D[4][8] + F[3][9] * D[4][9] + F[3][13] * D[4][13]) * Tsq + (D[3][4] + F[3][6] * D[1][6] + F[3][7] * D[1][7] + F[3][8] * D[1][8] + F[3][9] * D[1][9] + F[3][13] * D[1][13]) * T + D[1][3]; + P[1][4] = P[4][1] = (F[4][6] * D[4][6] + F[4][7] * D[4][7] + F[4][8] * D[4][8] + F[4][9] * D[4][9] + F[4][13] * D[4][13]) * Tsq + (D[4][4] + F[4][6] * D[1][6] + F[4][7] * D[1][7] + F[4][8] * D[1][8] + F[4][9] * D[1][9] + F[4][13] * D[1][13]) * T + D[1][4]; + P[1][5] = P[5][1] = (F[5][6] * D[4][6] + F[5][7] * D[4][7] + F[5][8] * D[4][8] + F[5][9] * D[4][9] + F[5][13] * D[4][13]) * Tsq + (D[4][5] + F[5][6] * D[1][6] + F[5][7] * D[1][7] + F[5][8] * D[1][8] + F[5][9] * D[1][9] + F[5][13] * D[1][13]) * T + D[1][5]; + P[1][6] = P[6][1] = (F[6][7] * D[4][7] + F[6][8] * D[4][8] + F[6][9] * D[4][9] + F[6][10] * D[4][10] + F[6][11] * D[4][11] + F[6][12] * D[4][12]) * Tsq + (D[4][6] + F[6][7] * D[1][7] + F[6][8] * D[1][8] + F[6][9] * D[1][9] + F[6][10] * D[1][10] + F[6][11] * D[1][11] + F[6][12] * D[1][12]) * T + D[1][6]; + P[1][7] = P[7][1] = (F[7][6] * D[4][6] + F[7][8] * D[4][8] + F[7][9] * D[4][9] + F[7][10] * D[4][10] + F[7][11] * D[4][11] + F[7][12] * D[4][12]) * Tsq + (D[4][7] + F[7][6] * D[1][6] + F[7][8] * D[1][8] + F[7][9] * D[1][9] + F[7][10] * D[1][10] + F[7][11] * D[1][11] + F[7][12] * D[1][12]) * T + D[1][7]; + P[1][8] = P[8][1] = (F[8][6] * D[4][6] + F[8][7] * D[4][7] + F[8][9] * D[4][9] + F[8][10] * D[4][10] + F[8][11] * D[4][11] + F[8][12] * D[4][12]) * Tsq + (D[4][8] + F[8][6] * D[1][6] + F[8][7] * D[1][7] + F[8][9] * D[1][9] + F[8][10] * D[1][10] + F[8][11] * D[1][11] + F[8][12] * D[1][12]) * T + D[1][8]; + P[1][9] = P[9][1] = (F[9][6] * D[4][6] + F[9][7] * D[4][7] + F[9][8] * D[4][8] + F[9][10] * D[4][10] + F[9][11] * D[4][11] + F[9][12] * D[4][12]) * Tsq + (D[4][9] + F[9][6] * D[1][6] + F[9][7] * D[1][7] + F[9][8] * D[1][8] + F[9][10] * D[1][10] + F[9][11] * D[1][11] + F[9][12] * D[1][12]) * T + D[1][9]; + P[1][10] = P[10][1] = D[4][10] * T + D[1][10]; + P[1][11] = P[11][1] = D[4][11] * T + D[1][11]; + P[1][12] = P[12][1] = D[4][12] * T + D[1][12]; + P[1][13] = P[13][1] = D[4][13] * T + D[1][13]; + P[2][2] = D[5][5] * Tsq + (2 * D[2][5]) * T + D[2][2]; + P[2][3] = P[3][2] = (F[3][6] * D[5][6] + F[3][7] * D[5][7] + F[3][8] * D[5][8] + F[3][9] * D[5][9] + F[3][13] * D[5][13]) * Tsq + (D[3][5] + F[3][6] * D[2][6] + F[3][7] * D[2][7] + F[3][8] * D[2][8] + F[3][9] * D[2][9] + F[3][13] * D[2][13]) * T + D[2][3]; + P[2][4] = P[4][2] = (F[4][6] * D[5][6] + F[4][7] * D[5][7] + F[4][8] * D[5][8] + F[4][9] * D[5][9] + F[4][13] * D[5][13]) * Tsq + (D[4][5] + F[4][6] * D[2][6] + F[4][7] * D[2][7] + F[4][8] * D[2][8] + F[4][9] * D[2][9] + F[4][13] * D[2][13]) * T + D[2][4]; + P[2][5] = P[5][2] = (F[5][6] * D[5][6] + F[5][7] * D[5][7] + F[5][8] * D[5][8] + F[5][9] * D[5][9] + F[5][13] * D[5][13]) * Tsq + (D[5][5] + F[5][6] * D[2][6] + F[5][7] * D[2][7] + F[5][8] * D[2][8] + F[5][9] * D[2][9] + F[5][13] * D[2][13]) * T + D[2][5]; + P[2][6] = P[6][2] = (F[6][7] * D[5][7] + F[6][8] * D[5][8] + F[6][9] * D[5][9] + F[6][10] * D[5][10] + F[6][11] * D[5][11] + F[6][12] * D[5][12]) * Tsq + (D[5][6] + F[6][7] * D[2][7] + F[6][8] * D[2][8] + F[6][9] * D[2][9] + F[6][10] * D[2][10] + F[6][11] * D[2][11] + F[6][12] * D[2][12]) * T + D[2][6]; + P[2][7] = P[7][2] = (F[7][6] * D[5][6] + F[7][8] * D[5][8] + F[7][9] * D[5][9] + F[7][10] * D[5][10] + F[7][11] * D[5][11] + F[7][12] * D[5][12]) * Tsq + (D[5][7] + F[7][6] * D[2][6] + F[7][8] * D[2][8] + F[7][9] * D[2][9] + F[7][10] * D[2][10] + F[7][11] * D[2][11] + F[7][12] * D[2][12]) * T + D[2][7]; + P[2][8] = P[8][2] = (F[8][6] * D[5][6] + F[8][7] * D[5][7] + F[8][9] * D[5][9] + F[8][10] * D[5][10] + F[8][11] * D[5][11] + F[8][12] * D[5][12]) * Tsq + (D[5][8] + F[8][6] * D[2][6] + F[8][7] * D[2][7] + F[8][9] * D[2][9] + F[8][10] * D[2][10] + F[8][11] * D[2][11] + F[8][12] * D[2][12]) * T + D[2][8]; + P[2][9] = P[9][2] = (F[9][6] * D[5][6] + F[9][7] * D[5][7] + F[9][8] * D[5][8] + F[9][10] * D[5][10] + F[9][11] * D[5][11] + F[9][12] * D[5][12]) * Tsq + (D[5][9] + F[9][6] * D[2][6] + F[9][7] * D[2][7] + F[9][8] * D[2][8] + F[9][10] * D[2][10] + F[9][11] * D[2][11] + F[9][12] * D[2][12]) * T + D[2][9]; + P[2][10] = P[10][2] = D[5][10] * T + D[2][10]; + P[2][11] = P[11][2] = D[5][11] * T + D[2][11]; + P[2][12] = P[12][2] = D[5][12] * T + D[2][12]; + P[2][13] = P[13][2] = D[5][13] * T + D[2][13]; + P[3][3] = (Q[3] * G[3][3] * G[3][3] + Q[4] * G[3][4] * G[3][4] + Q[5] * G[3][5] * G[3][5] + F[3][6] * (F[3][6] * D[6][6] + F[3][7] * D[6][7] + F[3][8] * D[6][8] + F[3][9] * D[6][9] + F[3][13] * D[6][13]) + F[3][7] * (F[3][6] * D[6][7] + F[3][7] * D[7][7] + F[3][8] * D[7][8] + F[3][9] * D[7][9] + F[3][13] * D[7][13]) + F[3][8] * (F[3][6] * D[6][8] + F[3][7] * D[7][8] + F[3][8] * D[8][8] + F[3][9] * D[8][9] + F[3][13] * D[8][13]) + F[3][9] * (F[3][6] * D[6][9] + F[3][7] * D[7][9] + F[3][8] * D[8][9] + F[3][9] * D[9][9] + F[3][13] * D[9][13]) + F[3][13] * (F[3][6] * D[6][13] + F[3][7] * D[7][13] + F[3][8] * D[8][13] + F[3][9] * D[9][13] + F[3][13] * D[13][13])) * Tsq + (2 * F[3][6] * D[3][6] + 2 * F[3][7] * D[3][7] + 2 * F[3][8] * D[3][8] + 2 * F[3][9] * D[3][9] + 2 * F[3][13] * D[3][13]) * T + D[3][3]; + P[3][4] = P[4][3] = (F[4][6] * (F[3][6] * D[6][6] + F[3][7] * D[6][7] + F[3][8] * D[6][8] + F[3][9] * D[6][9] + F[3][13] * D[6][13]) + F[4][7] * (F[3][6] * D[6][7] + F[3][7] * D[7][7] + F[3][8] * D[7][8] + F[3][9] * D[7][9] + F[3][13] * D[7][13]) + F[4][8] * (F[3][6] * D[6][8] + F[3][7] * D[7][8] + F[3][8] * D[8][8] + F[3][9] * D[8][9] + F[3][13] * D[8][13]) + F[4][9] * (F[3][6] * D[6][9] + F[3][7] * D[7][9] + F[3][8] * D[8][9] + F[3][9] * D[9][9] + F[3][13] * D[9][13]) + F[4][13] * (F[3][6] * D[6][13] + F[3][7] * D[7][13] + F[3][8] * D[8][13] + F[3][9] * D[9][13] + F[3][13] * D[13][13]) + G[3][3] * G[4][3] * Q[3] + G[3][4] * G[4][4] * Q[4] + G[3][5] * G[4][5] * Q[5]) * Tsq + (F[3][6] * D[4][6] + F[4][6] * D[3][6] + F[3][7] * D[4][7] + F[4][7] * D[3][7] + F[3][8] * D[4][8] + F[4][8] * D[3][8] + F[3][9] * D[4][9] + F[4][9] * D[3][9] + F[3][13] * D[4][13] + F[4][13] * D[3][13]) * T + D[3][4]; + P[3][5] = P[5][3] = (F[5][6] * (F[3][6] * D[6][6] + F[3][7] * D[6][7] + F[3][8] * D[6][8] + F[3][9] * D[6][9] + F[3][13] * D[6][13]) + F[5][7] * (F[3][6] * D[6][7] + F[3][7] * D[7][7] + F[3][8] * D[7][8] + F[3][9] * D[7][9] + F[3][13] * D[7][13]) + F[5][8] * (F[3][6] * D[6][8] + F[3][7] * D[7][8] + F[3][8] * D[8][8] + F[3][9] * D[8][9] + F[3][13] * D[8][13]) + F[5][9] * (F[3][6] * D[6][9] + F[3][7] * D[7][9] + F[3][8] * D[8][9] + F[3][9] * D[9][9] + F[3][13] * D[9][13]) + F[5][13] * (F[3][6] * D[6][13] + F[3][7] * D[7][13] + F[3][8] * D[8][13] + F[3][9] * D[9][13] + F[3][13] * D[13][13]) + G[3][3] * G[5][3] * Q[3] + G[3][4] * G[5][4] * Q[4] + G[3][5] * G[5][5] * Q[5]) * Tsq + (F[3][6] * D[5][6] + F[5][6] * D[3][6] + F[3][7] * D[5][7] + F[5][7] * D[3][7] + F[3][8] * D[5][8] + F[5][8] * D[3][8] + F[3][9] * D[5][9] + F[5][9] * D[3][9] + F[3][13] * D[5][13] + F[5][13] * D[3][13]) * T + D[3][5]; + P[3][6] = P[6][3] = (F[6][7] * (F[3][6] * D[6][7] + F[3][7] * D[7][7] + F[3][8] * D[7][8] + F[3][9] * D[7][9] + F[3][13] * D[7][13]) + F[6][8] * (F[3][6] * D[6][8] + F[3][7] * D[7][8] + F[3][8] * D[8][8] + F[3][9] * D[8][9] + F[3][13] * D[8][13]) + F[6][9] * (F[3][6] * D[6][9] + F[3][7] * D[7][9] + F[3][8] * D[8][9] + F[3][9] * D[9][9] + F[3][13] * D[9][13]) + F[6][10] * (F[3][6] * D[6][10] + F[3][7] * D[7][10] + F[3][8] * D[8][10] + F[3][9] * D[9][10] + F[3][13] * D[10][13]) + F[6][11] * (F[3][6] * D[6][11] + F[3][7] * D[7][11] + F[3][8] * D[8][11] + F[3][9] * D[9][11] + F[3][13] * D[11][13]) + F[6][12] * (F[3][6] * D[6][12] + F[3][7] * D[7][12] + F[3][8] * D[8][12] + F[3][9] * D[9][12] + F[3][13] * D[12][13])) * Tsq + (F[3][6] * D[6][6] + F[3][7] * D[6][7] + F[6][7] * D[3][7] + F[3][8] * D[6][8] + F[6][8] * D[3][8] + F[3][9] * D[6][9] + F[6][9] * D[3][9] + F[6][10] * D[3][10] + F[6][11] * D[3][11] + F[6][12] * D[3][12] + F[3][13] * D[6][13]) * T + D[3][6]; + P[3][7] = P[7][3] = (F[7][6] * (F[3][6] * D[6][6] + F[3][7] * D[6][7] + F[3][8] * D[6][8] + F[3][9] * D[6][9] + F[3][13] * D[6][13]) + F[7][8] * (F[3][6] * D[6][8] + F[3][7] * D[7][8] + F[3][8] * D[8][8] + F[3][9] * D[8][9] + F[3][13] * D[8][13]) + F[7][9] * (F[3][6] * D[6][9] + F[3][7] * D[7][9] + F[3][8] * D[8][9] + F[3][9] * D[9][9] + F[3][13] * D[9][13]) + F[7][10] * (F[3][6] * D[6][10] + F[3][7] * D[7][10] + F[3][8] * D[8][10] + F[3][9] * D[9][10] + F[3][13] * D[10][13]) + F[7][11] * (F[3][6] * D[6][11] + F[3][7] * D[7][11] + F[3][8] * D[8][11] + F[3][9] * D[9][11] + F[3][13] * D[11][13]) + F[7][12] * (F[3][6] * D[6][12] + F[3][7] * D[7][12] + F[3][8] * D[8][12] + F[3][9] * D[9][12] + F[3][13] * D[12][13])) * Tsq + (F[3][6] * D[6][7] + F[7][6] * D[3][6] + F[3][7] * D[7][7] + F[3][8] * D[7][8] + F[7][8] * D[3][8] + F[3][9] * D[7][9] + F[7][9] * D[3][9] + F[7][10] * D[3][10] + F[7][11] * D[3][11] + F[7][12] * D[3][12] + F[3][13] * D[7][13]) * T + D[3][7]; + P[3][8] = P[8][3] = (F[8][6] * (F[3][6] * D[6][6] + F[3][7] * D[6][7] + F[3][8] * D[6][8] + F[3][9] * D[6][9] + F[3][13] * D[6][13]) + F[8][7] * (F[3][6] * D[6][7] + F[3][7] * D[7][7] + F[3][8] * D[7][8] + F[3][9] * D[7][9] + F[3][13] * D[7][13]) + F[8][9] * (F[3][6] * D[6][9] + F[3][7] * D[7][9] + F[3][8] * D[8][9] + F[3][9] * D[9][9] + F[3][13] * D[9][13]) + F[8][10] * (F[3][6] * D[6][10] + F[3][7] * D[7][10] + F[3][8] * D[8][10] + F[3][9] * D[9][10] + F[3][13] * D[10][13]) + F[8][11] * (F[3][6] * D[6][11] + F[3][7] * D[7][11] + F[3][8] * D[8][11] + F[3][9] * D[9][11] + F[3][13] * D[11][13]) + F[8][12] * (F[3][6] * D[6][12] + F[3][7] * D[7][12] + F[3][8] * D[8][12] + F[3][9] * D[9][12] + F[3][13] * D[12][13])) * Tsq + (F[3][6] * D[6][8] + F[3][7] * D[7][8] + F[8][6] * D[3][6] + F[8][7] * D[3][7] + F[3][8] * D[8][8] + F[3][9] * D[8][9] + F[8][9] * D[3][9] + F[8][10] * D[3][10] + F[8][11] * D[3][11] + F[8][12] * D[3][12] + F[3][13] * D[8][13]) * T + D[3][8]; + P[3][9] = P[9][3] = (F[9][6] * (F[3][6] * D[6][6] + F[3][7] * D[6][7] + F[3][8] * D[6][8] + F[3][9] * D[6][9] + F[3][13] * D[6][13]) + F[9][7] * (F[3][6] * D[6][7] + F[3][7] * D[7][7] + F[3][8] * D[7][8] + F[3][9] * D[7][9] + F[3][13] * D[7][13]) + F[9][8] * (F[3][6] * D[6][8] + F[3][7] * D[7][8] + F[3][8] * D[8][8] + F[3][9] * D[8][9] + F[3][13] * D[8][13]) + F[9][10] * (F[3][6] * D[6][10] + F[3][7] * D[7][10] + F[3][8] * D[8][10] + F[3][9] * D[9][10] + F[3][13] * D[10][13]) + F[9][11] * (F[3][6] * D[6][11] + F[3][7] * D[7][11] + F[3][8] * D[8][11] + F[3][9] * D[9][11] + F[3][13] * D[11][13]) + F[9][12] * (F[3][6] * D[6][12] + F[3][7] * D[7][12] + F[3][8] * D[8][12] + F[3][9] * D[9][12] + F[3][13] * D[12][13])) * Tsq + (F[9][6] * D[3][6] + F[9][7] * D[3][7] + F[9][8] * D[3][8] + F[3][6] * D[6][9] + F[3][7] * D[7][9] + F[3][8] * D[8][9] + F[3][9] * D[9][9] + F[9][10] * D[3][10] + F[9][11] * D[3][11] + F[9][12] * D[3][12] + F[3][13] * D[9][13]) * T + D[3][9]; + P[3][10] = P[10][3] = (F[3][6] * D[6][10] + F[3][7] * D[7][10] + F[3][8] * D[8][10] + F[3][9] * D[9][10] + F[3][13] * D[10][13]) * T + D[3][10]; + P[3][11] = P[11][3] = (F[3][6] * D[6][11] + F[3][7] * D[7][11] + F[3][8] * D[8][11] + F[3][9] * D[9][11] + F[3][13] * D[11][13]) * T + D[3][11]; + P[3][12] = P[12][3] = (F[3][6] * D[6][12] + F[3][7] * D[7][12] + F[3][8] * D[8][12] + F[3][9] * D[9][12] + F[3][13] * D[12][13]) * T + D[3][12]; + P[3][13] = P[13][3] = (F[3][6] * D[6][13] + F[3][7] * D[7][13] + F[3][8] * D[8][13] + F[3][9] * D[9][13] + F[3][13] * D[13][13]) * T + D[3][13]; + P[4][4] = (Q[3] * G[4][3] * G[4][3] + Q[4] * G[4][4] * G[4][4] + Q[5] * G[4][5] * G[4][5] + F[4][6] * (F[4][6] * D[6][6] + F[4][7] * D[6][7] + F[4][8] * D[6][8] + F[4][9] * D[6][9] + F[4][13] * D[6][13]) + F[4][7] * (F[4][6] * D[6][7] + F[4][7] * D[7][7] + F[4][8] * D[7][8] + F[4][9] * D[7][9] + F[4][13] * D[7][13]) + F[4][8] * (F[4][6] * D[6][8] + F[4][7] * D[7][8] + F[4][8] * D[8][8] + F[4][9] * D[8][9] + F[4][13] * D[8][13]) + F[4][9] * (F[4][6] * D[6][9] + F[4][7] * D[7][9] + F[4][8] * D[8][9] + F[4][9] * D[9][9] + F[4][13] * D[9][13]) + F[4][13] * (F[4][6] * D[6][13] + F[4][7] * D[7][13] + F[4][8] * D[8][13] + F[4][9] * D[9][13] + F[4][13] * D[13][13])) * Tsq + (2 * F[4][6] * D[4][6] + 2 * F[4][7] * D[4][7] + 2 * F[4][8] * D[4][8] + 2 * F[4][9] * D[4][9] + 2 * F[4][13] * D[4][13]) * T + D[4][4]; + P[4][5] = P[5][4] = (F[5][6] * (F[4][6] * D[6][6] + F[4][7] * D[6][7] + F[4][8] * D[6][8] + F[4][9] * D[6][9] + F[4][13] * D[6][13]) + F[5][7] * (F[4][6] * D[6][7] + F[4][7] * D[7][7] + F[4][8] * D[7][8] + F[4][9] * D[7][9] + F[4][13] * D[7][13]) + F[5][8] * (F[4][6] * D[6][8] + F[4][7] * D[7][8] + F[4][8] * D[8][8] + F[4][9] * D[8][9] + F[4][13] * D[8][13]) + F[5][9] * (F[4][6] * D[6][9] + F[4][7] * D[7][9] + F[4][8] * D[8][9] + F[4][9] * D[9][9] + F[4][13] * D[9][13]) + F[5][13] * (F[4][6] * D[6][13] + F[4][7] * D[7][13] + F[4][8] * D[8][13] + F[4][9] * D[9][13] + F[4][13] * D[13][13]) + G[4][3] * G[5][3] * Q[3] + G[4][4] * G[5][4] * Q[4] + G[4][5] * G[5][5] * Q[5]) * Tsq + (F[4][6] * D[5][6] + F[5][6] * D[4][6] + F[4][7] * D[5][7] + F[5][7] * D[4][7] + F[4][8] * D[5][8] + F[5][8] * D[4][8] + F[4][9] * D[5][9] + F[5][9] * D[4][9] + F[4][13] * D[5][13] + F[5][13] * D[4][13]) * T + D[4][5]; + P[4][6] = P[6][4] = (F[6][7] * (F[4][6] * D[6][7] + F[4][7] * D[7][7] + F[4][8] * D[7][8] + F[4][9] * D[7][9] + F[4][13] * D[7][13]) + F[6][8] * (F[4][6] * D[6][8] + F[4][7] * D[7][8] + F[4][8] * D[8][8] + F[4][9] * D[8][9] + F[4][13] * D[8][13]) + F[6][9] * (F[4][6] * D[6][9] + F[4][7] * D[7][9] + F[4][8] * D[8][9] + F[4][9] * D[9][9] + F[4][13] * D[9][13]) + F[6][10] * (F[4][6] * D[6][10] + F[4][7] * D[7][10] + F[4][8] * D[8][10] + F[4][9] * D[9][10] + F[4][13] * D[10][13]) + F[6][11] * (F[4][6] * D[6][11] + F[4][7] * D[7][11] + F[4][8] * D[8][11] + F[4][9] * D[9][11] + F[4][13] * D[11][13]) + F[6][12] * (F[4][6] * D[6][12] + F[4][7] * D[7][12] + F[4][8] * D[8][12] + F[4][9] * D[9][12] + F[4][13] * D[12][13])) * Tsq + (F[4][6] * D[6][6] + F[4][7] * D[6][7] + F[6][7] * D[4][7] + F[4][8] * D[6][8] + F[6][8] * D[4][8] + F[4][9] * D[6][9] + F[6][9] * D[4][9] + F[6][10] * D[4][10] + F[6][11] * D[4][11] + F[6][12] * D[4][12] + F[4][13] * D[6][13]) * T + D[4][6]; + P[4][7] = P[7][4] = (F[7][6] * (F[4][6] * D[6][6] + F[4][7] * D[6][7] + F[4][8] * D[6][8] + F[4][9] * D[6][9] + F[4][13] * D[6][13]) + F[7][8] * (F[4][6] * D[6][8] + F[4][7] * D[7][8] + F[4][8] * D[8][8] + F[4][9] * D[8][9] + F[4][13] * D[8][13]) + F[7][9] * (F[4][6] * D[6][9] + F[4][7] * D[7][9] + F[4][8] * D[8][9] + F[4][9] * D[9][9] + F[4][13] * D[9][13]) + F[7][10] * (F[4][6] * D[6][10] + F[4][7] * D[7][10] + F[4][8] * D[8][10] + F[4][9] * D[9][10] + F[4][13] * D[10][13]) + F[7][11] * (F[4][6] * D[6][11] + F[4][7] * D[7][11] + F[4][8] * D[8][11] + F[4][9] * D[9][11] + F[4][13] * D[11][13]) + F[7][12] * (F[4][6] * D[6][12] + F[4][7] * D[7][12] + F[4][8] * D[8][12] + F[4][9] * D[9][12] + F[4][13] * D[12][13])) * Tsq + (F[4][6] * D[6][7] + F[7][6] * D[4][6] + F[4][7] * D[7][7] + F[4][8] * D[7][8] + F[7][8] * D[4][8] + F[4][9] * D[7][9] + F[7][9] * D[4][9] + F[7][10] * D[4][10] + F[7][11] * D[4][11] + F[7][12] * D[4][12] + F[4][13] * D[7][13]) * T + D[4][7]; + P[4][8] = P[8][4] = (F[8][6] * (F[4][6] * D[6][6] + F[4][7] * D[6][7] + F[4][8] * D[6][8] + F[4][9] * D[6][9] + F[4][13] * D[6][13]) + F[8][7] * (F[4][6] * D[6][7] + F[4][7] * D[7][7] + F[4][8] * D[7][8] + F[4][9] * D[7][9] + F[4][13] * D[7][13]) + F[8][9] * (F[4][6] * D[6][9] + F[4][7] * D[7][9] + F[4][8] * D[8][9] + F[4][9] * D[9][9] + F[4][13] * D[9][13]) + F[8][10] * (F[4][6] * D[6][10] + F[4][7] * D[7][10] + F[4][8] * D[8][10] + F[4][9] * D[9][10] + F[4][13] * D[10][13]) + F[8][11] * (F[4][6] * D[6][11] + F[4][7] * D[7][11] + F[4][8] * D[8][11] + F[4][9] * D[9][11] + F[4][13] * D[11][13]) + F[8][12] * (F[4][6] * D[6][12] + F[4][7] * D[7][12] + F[4][8] * D[8][12] + F[4][9] * D[9][12] + F[4][13] * D[12][13])) * Tsq + (F[4][6] * D[6][8] + F[4][7] * D[7][8] + F[8][6] * D[4][6] + F[8][7] * D[4][7] + F[4][8] * D[8][8] + F[4][9] * D[8][9] + F[8][9] * D[4][9] + F[8][10] * D[4][10] + F[8][11] * D[4][11] + F[8][12] * D[4][12] + F[4][13] * D[8][13]) * T + D[4][8]; + P[4][9] = P[9][4] = (F[9][6] * (F[4][6] * D[6][6] + F[4][7] * D[6][7] + F[4][8] * D[6][8] + F[4][9] * D[6][9] + F[4][13] * D[6][13]) + F[9][7] * (F[4][6] * D[6][7] + F[4][7] * D[7][7] + F[4][8] * D[7][8] + F[4][9] * D[7][9] + F[4][13] * D[7][13]) + F[9][8] * (F[4][6] * D[6][8] + F[4][7] * D[7][8] + F[4][8] * D[8][8] + F[4][9] * D[8][9] + F[4][13] * D[8][13]) + F[9][10] * (F[4][6] * D[6][10] + F[4][7] * D[7][10] + F[4][8] * D[8][10] + F[4][9] * D[9][10] + F[4][13] * D[10][13]) + F[9][11] * (F[4][6] * D[6][11] + F[4][7] * D[7][11] + F[4][8] * D[8][11] + F[4][9] * D[9][11] + F[4][13] * D[11][13]) + F[9][12] * (F[4][6] * D[6][12] + F[4][7] * D[7][12] + F[4][8] * D[8][12] + F[4][9] * D[9][12] + F[4][13] * D[12][13])) * Tsq + (F[9][6] * D[4][6] + F[9][7] * D[4][7] + F[9][8] * D[4][8] + F[4][6] * D[6][9] + F[4][7] * D[7][9] + F[4][8] * D[8][9] + F[4][9] * D[9][9] + F[9][10] * D[4][10] + F[9][11] * D[4][11] + F[9][12] * D[4][12] + F[4][13] * D[9][13]) * T + D[4][9]; + P[4][10] = P[10][4] = (F[4][6] * D[6][10] + F[4][7] * D[7][10] + F[4][8] * D[8][10] + F[4][9] * D[9][10] + F[4][13] * D[10][13]) * T + D[4][10]; + P[4][11] = P[11][4] = (F[4][6] * D[6][11] + F[4][7] * D[7][11] + F[4][8] * D[8][11] + F[4][9] * D[9][11] + F[4][13] * D[11][13]) * T + D[4][11]; + P[4][12] = P[12][4] = (F[4][6] * D[6][12] + F[4][7] * D[7][12] + F[4][8] * D[8][12] + F[4][9] * D[9][12] + F[4][13] * D[12][13]) * T + D[4][12]; + P[4][13] = P[13][4] = (F[4][6] * D[6][13] + F[4][7] * D[7][13] + F[4][8] * D[8][13] + F[4][9] * D[9][13] + F[4][13] * D[13][13]) * T + D[4][13]; + P[5][5] = (Q[3] * G[5][3] * G[5][3] + Q[4] * G[5][4] * G[5][4] + Q[5] * G[5][5] * G[5][5] + F[5][6] * (F[5][6] * D[6][6] + F[5][7] * D[6][7] + F[5][8] * D[6][8] + F[5][9] * D[6][9] + F[5][13] * D[6][13]) + F[5][7] * (F[5][6] * D[6][7] + F[5][7] * D[7][7] + F[5][8] * D[7][8] + F[5][9] * D[7][9] + F[5][13] * D[7][13]) + F[5][8] * (F[5][6] * D[6][8] + F[5][7] * D[7][8] + F[5][8] * D[8][8] + F[5][9] * D[8][9] + F[5][13] * D[8][13]) + F[5][9] * (F[5][6] * D[6][9] + F[5][7] * D[7][9] + F[5][8] * D[8][9] + F[5][9] * D[9][9] + F[5][13] * D[9][13]) + F[5][13] * (F[5][6] * D[6][13] + F[5][7] * D[7][13] + F[5][8] * D[8][13] + F[5][9] * D[9][13] + F[5][13] * D[13][13])) * Tsq + (2 * F[5][6] * D[5][6] + 2 * F[5][7] * D[5][7] + 2 * F[5][8] * D[5][8] + 2 * F[5][9] * D[5][9] + 2 * F[5][13] * D[5][13]) * T + D[5][5]; + P[5][6] = P[6][5] = (F[6][7] * (F[5][6] * D[6][7] + F[5][7] * D[7][7] + F[5][8] * D[7][8] + F[5][9] * D[7][9] + F[5][13] * D[7][13]) + F[6][8] * (F[5][6] * D[6][8] + F[5][7] * D[7][8] + F[5][8] * D[8][8] + F[5][9] * D[8][9] + F[5][13] * D[8][13]) + F[6][9] * (F[5][6] * D[6][9] + F[5][7] * D[7][9] + F[5][8] * D[8][9] + F[5][9] * D[9][9] + F[5][13] * D[9][13]) + F[6][10] * (F[5][6] * D[6][10] + F[5][7] * D[7][10] + F[5][8] * D[8][10] + F[5][9] * D[9][10] + F[5][13] * D[10][13]) + F[6][11] * (F[5][6] * D[6][11] + F[5][7] * D[7][11] + F[5][8] * D[8][11] + F[5][9] * D[9][11] + F[5][13] * D[11][13]) + F[6][12] * (F[5][6] * D[6][12] + F[5][7] * D[7][12] + F[5][8] * D[8][12] + F[5][9] * D[9][12] + F[5][13] * D[12][13])) * Tsq + (F[5][6] * D[6][6] + F[5][7] * D[6][7] + F[6][7] * D[5][7] + F[5][8] * D[6][8] + F[6][8] * D[5][8] + F[5][9] * D[6][9] + F[6][9] * D[5][9] + F[6][10] * D[5][10] + F[6][11] * D[5][11] + F[6][12] * D[5][12] + F[5][13] * D[6][13]) * T + D[5][6]; + P[5][7] = P[7][5] = (F[7][6] * (F[5][6] * D[6][6] + F[5][7] * D[6][7] + F[5][8] * D[6][8] + F[5][9] * D[6][9] + F[5][13] * D[6][13]) + F[7][8] * (F[5][6] * D[6][8] + F[5][7] * D[7][8] + F[5][8] * D[8][8] + F[5][9] * D[8][9] + F[5][13] * D[8][13]) + F[7][9] * (F[5][6] * D[6][9] + F[5][7] * D[7][9] + F[5][8] * D[8][9] + F[5][9] * D[9][9] + F[5][13] * D[9][13]) + F[7][10] * (F[5][6] * D[6][10] + F[5][7] * D[7][10] + F[5][8] * D[8][10] + F[5][9] * D[9][10] + F[5][13] * D[10][13]) + F[7][11] * (F[5][6] * D[6][11] + F[5][7] * D[7][11] + F[5][8] * D[8][11] + F[5][9] * D[9][11] + F[5][13] * D[11][13]) + F[7][12] * (F[5][6] * D[6][12] + F[5][7] * D[7][12] + F[5][8] * D[8][12] + F[5][9] * D[9][12] + F[5][13] * D[12][13])) * Tsq + (F[5][6] * D[6][7] + F[7][6] * D[5][6] + F[5][7] * D[7][7] + F[5][8] * D[7][8] + F[7][8] * D[5][8] + F[5][9] * D[7][9] + F[7][9] * D[5][9] + F[7][10] * D[5][10] + F[7][11] * D[5][11] + F[7][12] * D[5][12] + F[5][13] * D[7][13]) * T + D[5][7]; + P[5][8] = P[8][5] = (F[8][6] * (F[5][6] * D[6][6] + F[5][7] * D[6][7] + F[5][8] * D[6][8] + F[5][9] * D[6][9] + F[5][13] * D[6][13]) + F[8][7] * (F[5][6] * D[6][7] + F[5][7] * D[7][7] + F[5][8] * D[7][8] + F[5][9] * D[7][9] + F[5][13] * D[7][13]) + F[8][9] * (F[5][6] * D[6][9] + F[5][7] * D[7][9] + F[5][8] * D[8][9] + F[5][9] * D[9][9] + F[5][13] * D[9][13]) + F[8][10] * (F[5][6] * D[6][10] + F[5][7] * D[7][10] + F[5][8] * D[8][10] + F[5][9] * D[9][10] + F[5][13] * D[10][13]) + F[8][11] * (F[5][6] * D[6][11] + F[5][7] * D[7][11] + F[5][8] * D[8][11] + F[5][9] * D[9][11] + F[5][13] * D[11][13]) + F[8][12] * (F[5][6] * D[6][12] + F[5][7] * D[7][12] + F[5][8] * D[8][12] + F[5][9] * D[9][12] + F[5][13] * D[12][13])) * Tsq + (F[5][6] * D[6][8] + F[5][7] * D[7][8] + F[8][6] * D[5][6] + F[8][7] * D[5][7] + F[5][8] * D[8][8] + F[5][9] * D[8][9] + F[8][9] * D[5][9] + F[8][10] * D[5][10] + F[8][11] * D[5][11] + F[8][12] * D[5][12] + F[5][13] * D[8][13]) * T + D[5][8]; + P[5][9] = P[9][5] = (F[9][6] * (F[5][6] * D[6][6] + F[5][7] * D[6][7] + F[5][8] * D[6][8] + F[5][9] * D[6][9] + F[5][13] * D[6][13]) + F[9][7] * (F[5][6] * D[6][7] + F[5][7] * D[7][7] + F[5][8] * D[7][8] + F[5][9] * D[7][9] + F[5][13] * D[7][13]) + F[9][8] * (F[5][6] * D[6][8] + F[5][7] * D[7][8] + F[5][8] * D[8][8] + F[5][9] * D[8][9] + F[5][13] * D[8][13]) + F[9][10] * (F[5][6] * D[6][10] + F[5][7] * D[7][10] + F[5][8] * D[8][10] + F[5][9] * D[9][10] + F[5][13] * D[10][13]) + F[9][11] * (F[5][6] * D[6][11] + F[5][7] * D[7][11] + F[5][8] * D[8][11] + F[5][9] * D[9][11] + F[5][13] * D[11][13]) + F[9][12] * (F[5][6] * D[6][12] + F[5][7] * D[7][12] + F[5][8] * D[8][12] + F[5][9] * D[9][12] + F[5][13] * D[12][13])) * Tsq + (F[9][6] * D[5][6] + F[9][7] * D[5][7] + F[9][8] * D[5][8] + F[5][6] * D[6][9] + F[5][7] * D[7][9] + F[5][8] * D[8][9] + F[5][9] * D[9][9] + F[9][10] * D[5][10] + F[9][11] * D[5][11] + F[9][12] * D[5][12] + F[5][13] * D[9][13]) * T + D[5][9]; + P[5][10] = P[10][5] = (F[5][6] * D[6][10] + F[5][7] * D[7][10] + F[5][8] * D[8][10] + F[5][9] * D[9][10] + F[5][13] * D[10][13]) * T + D[5][10]; + P[5][11] = P[11][5] = (F[5][6] * D[6][11] + F[5][7] * D[7][11] + F[5][8] * D[8][11] + F[5][9] * D[9][11] + F[5][13] * D[11][13]) * T + D[5][11]; + P[5][12] = P[12][5] = (F[5][6] * D[6][12] + F[5][7] * D[7][12] + F[5][8] * D[8][12] + F[5][9] * D[9][12] + F[5][13] * D[12][13]) * T + D[5][12]; + P[5][13] = P[13][5] = (F[5][6] * D[6][13] + F[5][7] * D[7][13] + F[5][8] * D[8][13] + F[5][9] * D[9][13] + F[5][13] * D[13][13]) * T + D[5][13]; + P[6][6] = (Q[0] * G[6][0] * G[6][0] + Q[1] * G[6][1] * G[6][1] + Q[2] * G[6][2] * G[6][2] + F[6][7] * (F[6][7] * D[7][7] + F[6][8] * D[7][8] + F[6][9] * D[7][9] + F[6][10] * D[7][10] + F[6][11] * D[7][11] + F[6][12] * D[7][12]) + F[6][8] * (F[6][7] * D[7][8] + F[6][8] * D[8][8] + F[6][9] * D[8][9] + F[6][10] * D[8][10] + F[6][11] * D[8][11] + F[6][12] * D[8][12]) + F[6][9] * (F[6][7] * D[7][9] + F[6][8] * D[8][9] + F[6][9] * D[9][9] + F[6][10] * D[9][10] + F[6][11] * D[9][11] + F[6][12] * D[9][12]) + F[6][10] * (F[6][7] * D[7][10] + F[6][8] * D[8][10] + F[6][9] * D[9][10] + F[6][10] * D[10][10] + F[6][11] * D[10][11] + F[6][12] * D[10][12]) + F[6][11] * (F[6][7] * D[7][11] + F[6][8] * D[8][11] + F[6][9] * D[9][11] + F[6][10] * D[10][11] + F[6][11] * D[11][11] + F[6][12] * D[11][12]) + F[6][12] * (F[6][7] * D[7][12] + F[6][8] * D[8][12] + F[6][9] * D[9][12] + F[6][10] * D[10][12] + F[6][11] * D[11][12] + F[6][12] * D[12][12])) * Tsq + (2 * F[6][7] * D[6][7] + 2 * F[6][8] * D[6][8] + 2 * F[6][9] * D[6][9] + 2 * F[6][10] * D[6][10] + 2 * F[6][11] * D[6][11] + 2 * F[6][12] * D[6][12]) * T + D[6][6]; + P[6][7] = P[7][6] = (F[7][6] * (F[6][7] * D[6][7] + F[6][8] * D[6][8] + F[6][9] * D[6][9] + F[6][10] * D[6][10] + F[6][11] * D[6][11] + F[6][12] * D[6][12]) + F[7][8] * (F[6][7] * D[7][8] + F[6][8] * D[8][8] + F[6][9] * D[8][9] + F[6][10] * D[8][10] + F[6][11] * D[8][11] + F[6][12] * D[8][12]) + F[7][9] * (F[6][7] * D[7][9] + F[6][8] * D[8][9] + F[6][9] * D[9][9] + F[6][10] * D[9][10] + F[6][11] * D[9][11] + F[6][12] * D[9][12]) + F[7][10] * (F[6][7] * D[7][10] + F[6][8] * D[8][10] + F[6][9] * D[9][10] + F[6][10] * D[10][10] + F[6][11] * D[10][11] + F[6][12] * D[10][12]) + F[7][11] * (F[6][7] * D[7][11] + F[6][8] * D[8][11] + F[6][9] * D[9][11] + F[6][10] * D[10][11] + F[6][11] * D[11][11] + F[6][12] * D[11][12]) + F[7][12] * (F[6][7] * D[7][12] + F[6][8] * D[8][12] + F[6][9] * D[9][12] + F[6][10] * D[10][12] + F[6][11] * D[11][12] + F[6][12] * D[12][12]) + G[6][0] * G[7][0] * Q[0] + G[6][1] * G[7][1] * Q[1] + G[6][2] * G[7][2] * Q[2]) * Tsq + (F[7][6] * D[6][6] + F[6][7] * D[7][7] + F[6][8] * D[7][8] + F[7][8] * D[6][8] + F[6][9] * D[7][9] + F[7][9] * D[6][9] + F[6][10] * D[7][10] + F[7][10] * D[6][10] + F[6][11] * D[7][11] + F[7][11] * D[6][11] + F[6][12] * D[7][12] + F[7][12] * D[6][12]) * T + D[6][7]; + P[6][8] = P[8][6] = (F[8][6] * (F[6][7] * D[6][7] + F[6][8] * D[6][8] + F[6][9] * D[6][9] + F[6][10] * D[6][10] + F[6][11] * D[6][11] + F[6][12] * D[6][12]) + F[8][7] * (F[6][7] * D[7][7] + F[6][8] * D[7][8] + F[6][9] * D[7][9] + F[6][10] * D[7][10] + F[6][11] * D[7][11] + F[6][12] * D[7][12]) + F[8][9] * (F[6][7] * D[7][9] + F[6][8] * D[8][9] + F[6][9] * D[9][9] + F[6][10] * D[9][10] + F[6][11] * D[9][11] + F[6][12] * D[9][12]) + F[8][10] * (F[6][7] * D[7][10] + F[6][8] * D[8][10] + F[6][9] * D[9][10] + F[6][10] * D[10][10] + F[6][11] * D[10][11] + F[6][12] * D[10][12]) + F[8][11] * (F[6][7] * D[7][11] + F[6][8] * D[8][11] + F[6][9] * D[9][11] + F[6][10] * D[10][11] + F[6][11] * D[11][11] + F[6][12] * D[11][12]) + F[8][12] * (F[6][7] * D[7][12] + F[6][8] * D[8][12] + F[6][9] * D[9][12] + F[6][10] * D[10][12] + F[6][11] * D[11][12] + F[6][12] * D[12][12]) + G[6][0] * G[8][0] * Q[0] + G[6][1] * G[8][1] * Q[1] + G[6][2] * G[8][2] * Q[2]) * Tsq + (F[6][7] * D[7][8] + F[8][6] * D[6][6] + F[8][7] * D[6][7] + F[6][8] * D[8][8] + F[6][9] * D[8][9] + F[8][9] * D[6][9] + F[6][10] * D[8][10] + F[8][10] * D[6][10] + F[6][11] * D[8][11] + F[8][11] * D[6][11] + F[6][12] * D[8][12] + F[8][12] * D[6][12]) * T + D[6][8]; + P[6][9] = P[9][6] = (F[9][6] * (F[6][7] * D[6][7] + F[6][8] * D[6][8] + F[6][9] * D[6][9] + F[6][10] * D[6][10] + F[6][11] * D[6][11] + F[6][12] * D[6][12]) + F[9][7] * (F[6][7] * D[7][7] + F[6][8] * D[7][8] + F[6][9] * D[7][9] + F[6][10] * D[7][10] + F[6][11] * D[7][11] + F[6][12] * D[7][12]) + F[9][8] * (F[6][7] * D[7][8] + F[6][8] * D[8][8] + F[6][9] * D[8][9] + F[6][10] * D[8][10] + F[6][11] * D[8][11] + F[6][12] * D[8][12]) + F[9][10] * (F[6][7] * D[7][10] + F[6][8] * D[8][10] + F[6][9] * D[9][10] + F[6][10] * D[10][10] + F[6][11] * D[10][11] + F[6][12] * D[10][12]) + F[9][11] * (F[6][7] * D[7][11] + F[6][8] * D[8][11] + F[6][9] * D[9][11] + F[6][10] * D[10][11] + F[6][11] * D[11][11] + F[6][12] * D[11][12]) + F[9][12] * (F[6][7] * D[7][12] + F[6][8] * D[8][12] + F[6][9] * D[9][12] + F[6][10] * D[10][12] + F[6][11] * D[11][12] + F[6][12] * D[12][12]) + G[6][0] * G[9][0] * Q[0] + G[6][1] * G[9][1] * Q[1] + G[6][2] * G[9][2] * Q[2]) * Tsq + (F[9][6] * D[6][6] + F[9][7] * D[6][7] + F[9][8] * D[6][8] + F[6][7] * D[7][9] + F[6][8] * D[8][9] + F[6][9] * D[9][9] + F[6][10] * D[9][10] + F[9][10] * D[6][10] + F[6][11] * D[9][11] + F[9][11] * D[6][11] + F[6][12] * D[9][12] + F[9][12] * D[6][12]) * T + D[6][9]; + P[6][10] = P[10][6] = (F[6][7] * D[7][10] + F[6][8] * D[8][10] + F[6][9] * D[9][10] + F[6][10] * D[10][10] + F[6][11] * D[10][11] + F[6][12] * D[10][12]) * T + D[6][10]; + P[6][11] = P[11][6] = (F[6][7] * D[7][11] + F[6][8] * D[8][11] + F[6][9] * D[9][11] + F[6][10] * D[10][11] + F[6][11] * D[11][11] + F[6][12] * D[11][12]) * T + D[6][11]; + P[6][12] = P[12][6] = (F[6][7] * D[7][12] + F[6][8] * D[8][12] + F[6][9] * D[9][12] + F[6][10] * D[10][12] + F[6][11] * D[11][12] + F[6][12] * D[12][12]) * T + D[6][12]; + P[6][13] = P[13][6] = (F[6][7] * D[7][13] + F[6][8] * D[8][13] + F[6][9] * D[9][13] + F[6][10] * D[10][13] + F[6][11] * D[11][13] + F[6][12] * D[12][13]) * T + D[6][13]; + P[7][7] = (Q[0] * G[7][0] * G[7][0] + Q[1] * G[7][1] * G[7][1] + Q[2] * G[7][2] * G[7][2] + F[7][6] * (F[7][6] * D[6][6] + F[7][8] * D[6][8] + F[7][9] * D[6][9] + F[7][10] * D[6][10] + F[7][11] * D[6][11] + F[7][12] * D[6][12]) + F[7][8] * (F[7][6] * D[6][8] + F[7][8] * D[8][8] + F[7][9] * D[8][9] + F[7][10] * D[8][10] + F[7][11] * D[8][11] + F[7][12] * D[8][12]) + F[7][9] * (F[7][6] * D[6][9] + F[7][8] * D[8][9] + F[7][9] * D[9][9] + F[7][10] * D[9][10] + F[7][11] * D[9][11] + F[7][12] * D[9][12]) + F[7][10] * (F[7][6] * D[6][10] + F[7][8] * D[8][10] + F[7][9] * D[9][10] + F[7][10] * D[10][10] + F[7][11] * D[10][11] + F[7][12] * D[10][12]) + F[7][11] * (F[7][6] * D[6][11] + F[7][8] * D[8][11] + F[7][9] * D[9][11] + F[7][10] * D[10][11] + F[7][11] * D[11][11] + F[7][12] * D[11][12]) + F[7][12] * (F[7][6] * D[6][12] + F[7][8] * D[8][12] + F[7][9] * D[9][12] + F[7][10] * D[10][12] + F[7][11] * D[11][12] + F[7][12] * D[12][12])) * Tsq + (2 * F[7][6] * D[6][7] + 2 * F[7][8] * D[7][8] + 2 * F[7][9] * D[7][9] + 2 * F[7][10] * D[7][10] + 2 * F[7][11] * D[7][11] + 2 * F[7][12] * D[7][12]) * T + D[7][7]; + P[7][8] = P[8][7] = (F[8][6] * (F[7][6] * D[6][6] + F[7][8] * D[6][8] + F[7][9] * D[6][9] + F[7][10] * D[6][10] + F[7][11] * D[6][11] + F[7][12] * D[6][12]) + F[8][7] * (F[7][6] * D[6][7] + F[7][8] * D[7][8] + F[7][9] * D[7][9] + F[7][10] * D[7][10] + F[7][11] * D[7][11] + F[7][12] * D[7][12]) + F[8][9] * (F[7][6] * D[6][9] + F[7][8] * D[8][9] + F[7][9] * D[9][9] + F[7][10] * D[9][10] + F[7][11] * D[9][11] + F[7][12] * D[9][12]) + F[8][10] * (F[7][6] * D[6][10] + F[7][8] * D[8][10] + F[7][9] * D[9][10] + F[7][10] * D[10][10] + F[7][11] * D[10][11] + F[7][12] * D[10][12]) + F[8][11] * (F[7][6] * D[6][11] + F[7][8] * D[8][11] + F[7][9] * D[9][11] + F[7][10] * D[10][11] + F[7][11] * D[11][11] + F[7][12] * D[11][12]) + F[8][12] * (F[7][6] * D[6][12] + F[7][8] * D[8][12] + F[7][9] * D[9][12] + F[7][10] * D[10][12] + F[7][11] * D[11][12] + F[7][12] * D[12][12]) + G[7][0] * G[8][0] * Q[0] + G[7][1] * G[8][1] * Q[1] + G[7][2] * G[8][2] * Q[2]) * Tsq + (F[7][6] * D[6][8] + F[8][6] * D[6][7] + F[8][7] * D[7][7] + F[7][8] * D[8][8] + F[7][9] * D[8][9] + F[8][9] * D[7][9] + F[7][10] * D[8][10] + F[8][10] * D[7][10] + F[7][11] * D[8][11] + F[8][11] * D[7][11] + F[7][12] * D[8][12] + F[8][12] * D[7][12]) * T + D[7][8]; + P[7][9] = P[9][7] = (F[9][6] * (F[7][6] * D[6][6] + F[7][8] * D[6][8] + F[7][9] * D[6][9] + F[7][10] * D[6][10] + F[7][11] * D[6][11] + F[7][12] * D[6][12]) + F[9][7] * (F[7][6] * D[6][7] + F[7][8] * D[7][8] + F[7][9] * D[7][9] + F[7][10] * D[7][10] + F[7][11] * D[7][11] + F[7][12] * D[7][12]) + F[9][8] * (F[7][6] * D[6][8] + F[7][8] * D[8][8] + F[7][9] * D[8][9] + F[7][10] * D[8][10] + F[7][11] * D[8][11] + F[7][12] * D[8][12]) + F[9][10] * (F[7][6] * D[6][10] + F[7][8] * D[8][10] + F[7][9] * D[9][10] + F[7][10] * D[10][10] + F[7][11] * D[10][11] + F[7][12] * D[10][12]) + F[9][11] * (F[7][6] * D[6][11] + F[7][8] * D[8][11] + F[7][9] * D[9][11] + F[7][10] * D[10][11] + F[7][11] * D[11][11] + F[7][12] * D[11][12]) + F[9][12] * (F[7][6] * D[6][12] + F[7][8] * D[8][12] + F[7][9] * D[9][12] + F[7][10] * D[10][12] + F[7][11] * D[11][12] + F[7][12] * D[12][12]) + G[7][0] * G[9][0] * Q[0] + G[7][1] * G[9][1] * Q[1] + G[7][2] * G[9][2] * Q[2]) * Tsq + (F[9][6] * D[6][7] + F[9][7] * D[7][7] + F[9][8] * D[7][8] + F[7][6] * D[6][9] + F[7][8] * D[8][9] + F[7][9] * D[9][9] + F[7][10] * D[9][10] + F[9][10] * D[7][10] + F[7][11] * D[9][11] + F[9][11] * D[7][11] + F[7][12] * D[9][12] + F[9][12] * D[7][12]) * T + D[7][9]; + P[7][10] = P[10][7] = (F[7][6] * D[6][10] + F[7][8] * D[8][10] + F[7][9] * D[9][10] + F[7][10] * D[10][10] + F[7][11] * D[10][11] + F[7][12] * D[10][12]) * T + D[7][10]; + P[7][11] = P[11][7] = (F[7][6] * D[6][11] + F[7][8] * D[8][11] + F[7][9] * D[9][11] + F[7][10] * D[10][11] + F[7][11] * D[11][11] + F[7][12] * D[11][12]) * T + D[7][11]; + P[7][12] = P[12][7] = (F[7][6] * D[6][12] + F[7][8] * D[8][12] + F[7][9] * D[9][12] + F[7][10] * D[10][12] + F[7][11] * D[11][12] + F[7][12] * D[12][12]) * T + D[7][12]; + P[7][13] = P[13][7] = (F[7][6] * D[6][13] + F[7][8] * D[8][13] + F[7][9] * D[9][13] + F[7][10] * D[10][13] + F[7][11] * D[11][13] + F[7][12] * D[12][13]) * T + D[7][13]; + P[8][8] = (Q[0] * G[8][0] * G[8][0] + Q[1] * G[8][1] * G[8][1] + Q[2] * G[8][2] * G[8][2] + F[8][6] * (F[8][6] * D[6][6] + F[8][7] * D[6][7] + F[8][9] * D[6][9] + F[8][10] * D[6][10] + F[8][11] * D[6][11] + F[8][12] * D[6][12]) + F[8][7] * (F[8][6] * D[6][7] + F[8][7] * D[7][7] + F[8][9] * D[7][9] + F[8][10] * D[7][10] + F[8][11] * D[7][11] + F[8][12] * D[7][12]) + F[8][9] * (F[8][6] * D[6][9] + F[8][7] * D[7][9] + F[8][9] * D[9][9] + F[8][10] * D[9][10] + F[8][11] * D[9][11] + F[8][12] * D[9][12]) + F[8][10] * (F[8][6] * D[6][10] + F[8][7] * D[7][10] + F[8][9] * D[9][10] + F[8][10] * D[10][10] + F[8][11] * D[10][11] + F[8][12] * D[10][12]) + F[8][11] * (F[8][6] * D[6][11] + F[8][7] * D[7][11] + F[8][9] * D[9][11] + F[8][10] * D[10][11] + F[8][11] * D[11][11] + F[8][12] * D[11][12]) + F[8][12] * (F[8][6] * D[6][12] + F[8][7] * D[7][12] + F[8][9] * D[9][12] + F[8][10] * D[10][12] + F[8][11] * D[11][12] + F[8][12] * D[12][12])) * Tsq + (2 * F[8][6] * D[6][8] + 2 * F[8][7] * D[7][8] + 2 * F[8][9] * D[8][9] + 2 * F[8][10] * D[8][10] + 2 * F[8][11] * D[8][11] + 2 * F[8][12] * D[8][12]) * T + D[8][8]; + P[8][9] = P[9][8] = (F[9][6] * (F[8][6] * D[6][6] + F[8][7] * D[6][7] + F[8][9] * D[6][9] + F[8][10] * D[6][10] + F[8][11] * D[6][11] + F[8][12] * D[6][12]) + F[9][7] * (F[8][6] * D[6][7] + F[8][7] * D[7][7] + F[8][9] * D[7][9] + F[8][10] * D[7][10] + F[8][11] * D[7][11] + F[8][12] * D[7][12]) + F[9][8] * (F[8][6] * D[6][8] + F[8][7] * D[7][8] + F[8][9] * D[8][9] + F[8][10] * D[8][10] + F[8][11] * D[8][11] + F[8][12] * D[8][12]) + F[9][10] * (F[8][6] * D[6][10] + F[8][7] * D[7][10] + F[8][9] * D[9][10] + F[8][10] * D[10][10] + F[8][11] * D[10][11] + F[8][12] * D[10][12]) + F[9][11] * (F[8][6] * D[6][11] + F[8][7] * D[7][11] + F[8][9] * D[9][11] + F[8][10] * D[10][11] + F[8][11] * D[11][11] + F[8][12] * D[11][12]) + F[9][12] * (F[8][6] * D[6][12] + F[8][7] * D[7][12] + F[8][9] * D[9][12] + F[8][10] * D[10][12] + F[8][11] * D[11][12] + F[8][12] * D[12][12]) + G[8][0] * G[9][0] * Q[0] + G[8][1] * G[9][1] * Q[1] + G[8][2] * G[9][2] * Q[2]) * Tsq + (F[9][6] * D[6][8] + F[9][7] * D[7][8] + F[9][8] * D[8][8] + F[8][6] * D[6][9] + F[8][7] * D[7][9] + F[8][9] * D[9][9] + F[8][10] * D[9][10] + F[9][10] * D[8][10] + F[8][11] * D[9][11] + F[9][11] * D[8][11] + F[8][12] * D[9][12] + F[9][12] * D[8][12]) * T + D[8][9]; + P[8][10] = P[10][8] = (F[8][6] * D[6][10] + F[8][7] * D[7][10] + F[8][9] * D[9][10] + F[8][10] * D[10][10] + F[8][11] * D[10][11] + F[8][12] * D[10][12]) * T + D[8][10]; + P[8][11] = P[11][8] = (F[8][6] * D[6][11] + F[8][7] * D[7][11] + F[8][9] * D[9][11] + F[8][10] * D[10][11] + F[8][11] * D[11][11] + F[8][12] * D[11][12]) * T + D[8][11]; + P[8][12] = P[12][8] = (F[8][6] * D[6][12] + F[8][7] * D[7][12] + F[8][9] * D[9][12] + F[8][10] * D[10][12] + F[8][11] * D[11][12] + F[8][12] * D[12][12]) * T + D[8][12]; + P[8][13] = P[13][8] = (F[8][6] * D[6][13] + F[8][7] * D[7][13] + F[8][9] * D[9][13] + F[8][10] * D[10][13] + F[8][11] * D[11][13] + F[8][12] * D[12][13]) * T + D[8][13]; + P[9][9] = (Q[0] * G[9][0] * G[9][0] + Q[1] * G[9][1] * G[9][1] + Q[2] * G[9][2] * G[9][2] + F[9][6] * (F[9][6] * D[6][6] + F[9][7] * D[6][7] + F[9][8] * D[6][8] + F[9][10] * D[6][10] + F[9][11] * D[6][11] + F[9][12] * D[6][12]) + F[9][7] * (F[9][6] * D[6][7] + F[9][7] * D[7][7] + F[9][8] * D[7][8] + F[9][10] * D[7][10] + F[9][11] * D[7][11] + F[9][12] * D[7][12]) + F[9][8] * (F[9][6] * D[6][8] + F[9][7] * D[7][8] + F[9][8] * D[8][8] + F[9][10] * D[8][10] + F[9][11] * D[8][11] + F[9][12] * D[8][12]) + F[9][10] * (F[9][6] * D[6][10] + F[9][7] * D[7][10] + F[9][8] * D[8][10] + F[9][10] * D[10][10] + F[9][11] * D[10][11] + F[9][12] * D[10][12]) + F[9][11] * (F[9][6] * D[6][11] + F[9][7] * D[7][11] + F[9][8] * D[8][11] + F[9][10] * D[10][11] + F[9][11] * D[11][11] + F[9][12] * D[11][12]) + F[9][12] * (F[9][6] * D[6][12] + F[9][7] * D[7][12] + F[9][8] * D[8][12] + F[9][10] * D[10][12] + F[9][11] * D[11][12] + F[9][12] * D[12][12])) * Tsq + (2 * F[9][6] * D[6][9] + 2 * F[9][7] * D[7][9] + 2 * F[9][8] * D[8][9] + 2 * F[9][10] * D[9][10] + 2 * F[9][11] * D[9][11] + 2 * F[9][12] * D[9][12]) * T + D[9][9]; + P[9][10] = P[10][9] = (F[9][6] * D[6][10] + F[9][7] * D[7][10] + F[9][8] * D[8][10] + F[9][10] * D[10][10] + F[9][11] * D[10][11] + F[9][12] * D[10][12]) * T + D[9][10]; + P[9][11] = P[11][9] = (F[9][6] * D[6][11] + F[9][7] * D[7][11] + F[9][8] * D[8][11] + F[9][10] * D[10][11] + F[9][11] * D[11][11] + F[9][12] * D[11][12]) * T + D[9][11]; + P[9][12] = P[12][9] = (F[9][6] * D[6][12] + F[9][7] * D[7][12] + F[9][8] * D[8][12] + F[9][10] * D[10][12] + F[9][11] * D[11][12] + F[9][12] * D[12][12]) * T + D[9][12]; + P[9][13] = P[13][9] = (F[9][6] * D[6][13] + F[9][7] * D[7][13] + F[9][8] * D[8][13] + F[9][10] * D[10][13] + F[9][11] * D[11][13] + F[9][12] * D[12][13]) * T + D[9][13]; + P[10][10] = Q[6] * Tsq + D[10][10]; + P[10][11] = P[11][10] = D[10][11]; + P[10][12] = P[12][10] = D[10][12]; + P[10][13] = P[13][10] = D[10][13]; + P[11][11] = Q[7] * Tsq + D[11][11]; + P[11][12] = P[12][11] = D[11][12]; + P[11][13] = P[13][11] = D[11][13]; + P[12][12] = Q[8] * Tsq + D[12][12]; + P[12][13] = P[13][12] = D[12][13]; + P[13][13] = Q[9] * Tsq + D[13][13]; +} +#endif /* ifdef COVARIANCE_PREDICTION_GENERAL */ + +// ************* SerialUpdate ******************* +// Does the update step of the Kalman filter for the covariance and estimate +// Outputs are Xnew & Pnew, and are written over P and X +// Z is actual measurement, Y is predicted measurement +// Xnew = X + K*(Z-Y), Pnew=(I-K*H)*P, +// where K=P*H'*inv[H*P*H'+R] +// NOTE the algorithm assumes R (measurement covariance matrix) is diagonal +// i.e. the measurment noises are uncorrelated. +// It therefore uses a serial update that requires no matrix inversion by +// processing the measurements one at a time. +// Algorithm - see Grewal and Andrews, "Kalman Filtering,2nd Ed" p.121 & p.253 +// - or see Simon, "Optimal State Estimation," 1st Ed, p.150 +// The SensorsUsed variable is a bitwise mask indicating which sensors +// should be used in the update. +// ************************************************ + +void SerialUpdate(float H[NUMV][NUMX], float R[NUMV], float Z[NUMV], + float Y[NUMV], float P[NUMX][NUMX], float X[NUMX], + uint16_t SensorsUsed) +{ + float HP[NUMX], HPHR, Error; + uint8_t i, j, k, m; + + // Iterate through all the possible measurements and apply the + // appropriate corrections + for (m = 0; m < NUMV; m++) { + if (SensorsUsed & (0x01 << m)) { // use this sensor for update + for (j = 0; j < NUMX; j++) { // Find Hp = H*P + HP[j] = 0.0f; + for (k = 0; k < NUMX; k++) { + HP[j] += H[m][k] * P[k][j]; + } + } + HPHR = R[m]; // Find HPHR = H*P*H' + R + for (k = 0; k < NUMX; k++) { + HPHR += HP[k] * H[m][k]; + } + + for (k = 0; k < NUMX; k++) { + ekf.K[k][m] = HP[k] / HPHR; // find K = HP/HPHR + } + for (i = 0; i < NUMX; i++) { // Find P(m)= P(m-1) + K*HP + for (j = i; j < NUMX; j++) { + P[i][j] = P[j][i] = + P[i][j] - ekf.K[i][m] * HP[j]; + } + } + + Error = Z[m] - Y[m]; + for (i = 0; i < NUMX; i++) { // Find X(m)= X(m-1) + K*Error + X[i] = X[i] + ekf.K[i][m] * Error; + } + } + } + + INSLimitBias(); +} + +// ************* RungeKutta ********************** +// Does a 4th order Runge Kutta numerical integration step +// Output, Xnew, is written over X +// NOTE the algorithm assumes time invariant state equations and +// constant inputs over integration step +// ************************************************ + +void RungeKutta(float X[NUMX], float U[NUMU], float dT) +{ + float dT2 = + dT / 2.0f, K1[NUMX], K2[NUMX], K3[NUMX], K4[NUMX], Xlast[NUMX]; + uint8_t i; + + for (i = 0; i < NUMX; i++) { + Xlast[i] = X[i]; // make a working copy + } + StateEq(X, U, K1); // k1 = f(x,u) + for (i = 0; i < NUMX; i++) { + X[i] = Xlast[i] + dT2 * K1[i]; + } + StateEq(X, U, K2); // k2 = f(x+0.5*dT*k1,u) + for (i = 0; i < NUMX; i++) { + X[i] = Xlast[i] + dT2 * K2[i]; + } + StateEq(X, U, K3); // k3 = f(x+0.5*dT*k2,u) + for (i = 0; i < NUMX; i++) { + X[i] = Xlast[i] + dT * K3[i]; + } + StateEq(X, U, K4); // k4 = f(x+dT*k3,u) + + // Xnew = X + dT*(k1+2*k2+2*k3+k4)/6 + for (i = 0; i < NUMX; i++) { + X[i] = + Xlast[i] + dT * (K1[i] + 2.0f * K2[i] + 2.0f * K3[i] + + K4[i]) / 6.0f; + } +} + +// ************* Model Specific Stuff *************************** +// *** StateEq, MeasurementEq, LinerizeFG, and LinearizeH ******** +// +// State Variables = [Pos Vel Quaternion GyroBias AccelBias] +// Deterministic Inputs = [AngularVel Accel] +// Disturbance Noise = [GyroNoise AccelNoise GyroRandomWalkNoise AccelRandomWalkNoise] +// +// Measurement Variables = [Pos Vel BodyFrameMagField Altimeter] +// Inputs to Measurement = [EarthFrameMagField] +// +// Notes: Pos and Vel in earth frame +// AngularVel and Accel in body frame +// MagFields are unit vectors +// Xdot is output of StateEq() +// F and G are outputs of LinearizeFG(), all elements not set should be zero +// y is output of OutputEq() +// H is output of LinearizeH(), all elements not set should be zero +// ************************************************ + +void StateEq(float X[NUMX], float U[NUMU], float Xdot[NUMX]) +{ + const float wx = U[0] - X[10]; + const float wy = U[1] - X[11]; + const float wz = U[2] - X[12]; // subtract the biases on gyros + const float ax = U[3]; + const float ay = U[4]; + const float az = U[5] - X[13]; // subtract the biases on accels + const float q0 = X[6]; + const float q1 = X[7]; + const float q2 = X[8]; + const float q3 = X[9]; + + // Pdot = V + Xdot[0] = X[3]; + Xdot[1] = X[4]; + Xdot[2] = X[5]; + + // Vdot = Reb*a + Xdot[3] = + (q0 * q0 + q1 * q1 - q2 * q2 - q3 * q3) * ax + 2.0f * (q1 * q2 - + q0 * q3) * + ay + 2.0f * (q1 * q3 + q0 * q2) * az; + Xdot[4] = + 2.0f * (q1 * q2 + q0 * q3) * ax + (q0 * q0 - q1 * q1 + q2 * q2 - + q3 * q3) * ay + 2.0f * (q2 * q3 - + q0 * q1) * + az; + Xdot[5] = + 2.0f * (q1 * q3 - q0 * q2) * ax + 2.0f * (q2 * q3 + q0 * q1) * ay + + (q0 * q0 - q1 * q1 - q2 * q2 + q3 * q3) * az + PIOS_CONST_MKS_GRAV_ACCEL_F; + + // qdot = Q*w + Xdot[6] = (-q1 * wx - q2 * wy - q3 * wz) / 2.0f; + Xdot[7] = (q0 * wx - q3 * wy + q2 * wz) / 2.0f; + Xdot[8] = (q3 * wx + q0 * wy - q1 * wz) / 2.0f; + Xdot[9] = (-q2 * wx + q1 * wy + q0 * wz) / 2.0f; + + // best guess is that bias stays constant + Xdot[10] = Xdot[11] = Xdot[12] = 0; + + // For accels to make sure things stay stable, assume bias always walks weakly + // towards zero for the horizontal axis. This prevents drifting around an + // unobservable manifold of possible attitudes and gyro biases. The z-axis + // we assume no drift becaues this is teh one we want to estimate most accurately. + Xdot[13] = 0.0f; +} + +/** + * Linearize the state equations around the current state estimate. + * @param[in] X the current state estimate + * @param[in] U the control inputs + * @param[out] F the linearized natural dynamics + * @param[out] G the linearized influence of disturbance model + * + * so the prediction of the next state is + * Xdot = F * X + G * U + * where X is the current state and U is the current input + * + * For reference the state order (in F) is pos, vel, attitude, gyro bias, accel bias + * and the input order is gyro, bias + */ +void LinearizeFG(float X[NUMX], float U[NUMU], float F[NUMX][NUMX], + float G[NUMX][NUMW]) +{ + const float wx = U[0] - X[10]; + const float wy = U[1] - X[11]; + const float wz = U[2] - X[12]; // subtract the biases on gyros + const float ax = U[3]; + const float ay = U[4]; + const float az = U[5] - X[13]; // subtract the biases on accels + const float q0 = X[6]; + const float q1 = X[7]; + const float q2 = X[8]; + const float q3 = X[9]; + + // Pdot = V + F[0][3] = F[1][4] = F[2][5] = 1.0f; + + // dVdot/dq + F[3][6] = 2.0f * (q0 * ax - q3 * ay + q2 * az); + F[3][7] = 2.0f * (q1 * ax + q2 * ay + q3 * az); + F[3][8] = 2.0f * (-q2 * ax + q1 * ay + q0 * az); + F[3][9] = 2.0f * (-q3 * ax - q0 * ay + q1 * az); + F[4][6] = 2.0f * (q3 * ax + q0 * ay - q1 * az); + F[4][7] = 2.0f * (q2 * ax - q1 * ay - q0 * az); + F[4][8] = 2.0f * (q1 * ax + q2 * ay + q3 * az); + F[4][9] = 2.0f * (q0 * ax - q3 * ay + q2 * az); + F[5][6] = 2.0f * (-q2 * ax + q1 * ay + q0 * az); + F[5][7] = 2.0f * (q3 * ax + q0 * ay - q1 * az); + F[5][8] = 2.0f * (-q0 * ax + q3 * ay - q2 * az); + F[5][9] = 2.0f * (q1 * ax + q2 * ay + q3 * az); + + // dVdot/dabias & dVdot/dna - the equations for how the accel input and accel bias influence velocity are the same + F[3][13] = G[3][5] = -2.0f * (q1 * q3 + q0 * q2); + F[4][13] = G[4][5] = 2.0f * (-q2 * q3 + q0 * q1); + F[5][13] = G[5][5] = -q0 * q0 + q1 * q1 + q2 * q2 - q3 * q3; + + // dqdot/dq + F[6][6] = 0; + F[6][7] = -wx / 2.0f; + F[6][8] = -wy / 2.0f; + F[6][9] = -wz / 2.0f; + F[7][6] = wx / 2.0f; + F[7][7] = 0; + F[7][8] = wz / 2.0f; + F[7][9] = -wy / 2.0f; + F[8][6] = wy / 2.0f; + F[8][7] = -wz / 2.0f; + F[8][8] = 0; + F[8][9] = wx / 2.0f; + F[9][6] = wz / 2.0f; + F[9][7] = wy / 2.0f; + F[9][8] = -wx / 2.0f; + F[9][9] = 0; + + // dqdot/dwbias + F[6][10] = q1 / 2.0f; + F[6][11] = q2 / 2.0f; + F[6][12] = q3 / 2.0f; + F[7][10] = -q0 / 2.0f; + F[7][11] = q3 / 2.0f; + F[7][12] = -q2 / 2.0f; + F[8][10] = -q3 / 2.0f; + F[8][11] = -q0 / 2.0f; + F[8][12] = q1 / 2.0f; + F[9][10] = q2 / 2.0f; + F[9][11] = -q1 / 2.0f; + F[9][12] = -q0 / 2.0f; + + // dVdot/dna + G[3][3] = -q0 * q0 - q1 * q1 + q2 * q2 + q3 * q3; G[3][4] = 2 * (-q1 * q2 + q0 * q3); G[3][5] = -2 * (q1 * q3 + q0 * q2); + G[4][3] = -2 * (q1 * q2 + q0 * q3); G[4][4] = -q0 * q0 + q1 * q1 - q2 * q2 + q3 * q3; G[4][5] = 2 * (-q2 * q3 + q0 * q1); + G[5][3] = 2 * (-q1 * q3 + q0 * q2); G[5][4] = -2 * (q2 * q3 + q0 * q1); G[5][5] = -q0 * q0 + q1 * q1 + q2 * q2 - q3 * q3; + + // dqdot/dnw + G[6][0] = q1 / 2.0f; + G[6][1] = q2 / 2.0f; + G[6][2] = q3 / 2.0f; + G[7][0] = -q0 / 2.0f; + G[7][1] = q3 / 2.0f; + G[7][2] = -q2 / 2.0f; + G[8][0] = -q3 / 2.0f; + G[8][1] = -q0 / 2.0f; + G[8][2] = q1 / 2.0f; + G[9][0] = q2 / 2.0f; + G[9][1] = -q1 / 2.0f; + G[9][2] = -q0 / 2.0f; +} + +/** + * Predicts the measurements from the current state. Note + * that this is very similar to @ref LinearizeH except this + * directly computes the outputs instead of a matrix that + * you transform the state by + */ +void MeasurementEq(float X[NUMX], float Be[3], float Y[NUMV]) +{ + const float q0 = X[6]; + const float q1 = X[7]; + const float q2 = X[8]; + const float q3 = X[9]; + + // first six outputs are P and V + Y[0] = X[0]; + Y[1] = X[1]; + Y[2] = X[2]; + Y[3] = X[3]; + Y[4] = X[4]; + Y[5] = X[5]; + + // Rotate Be by only the yaw heading + const float a1 = 2 * q0 * q3 + 2 * q1 * q2; + const float a2 = q0 * q0 + q1 * q1 - q2 * q2 - q3 * q3; + const float r = sqrtf(a1 * a1 + a2 * a2); + const float cP = a2 / r; + const float sP = a1 / r; + Y[6] = Be[0] * cP + Be[1] * sP; + Y[7] = -Be[0] * sP + Be[1] * cP; + Y[8] = 0; // don't care + + // Alt = -Pz + Y[9] = X[2] * -1.0f; +} + +/** + * Linearize the measurement around the current state estiamte + * so the predicted measurements are + * Z = H * X + */ +void LinearizeH(float X[NUMX], float Be[3], float H[NUMV][NUMX]) +{ + const float q0 = X[6]; + const float q1 = X[7]; + const float q2 = X[8]; + const float q3 = X[9]; + + // dP/dP=I; (expect position to measure the position) + H[0][0] = H[1][1] = H[2][2] = 1.0f; + // dV/dV=I; (expect velocity to measure the velocity) + H[3][3] = H[4][4] = H[5][5] = 1.0f; + + // dBb/dq (expected magnetometer readings in the horizontal plane) + // these equations were generated by Rhb(q)*Be which is the matrix that + // rotates the earth magnetic field into the horizontal plane, and then + // taking the partial derivative wrt each term in q. Maniuplated in + // matlab symbolic toolbox + const float Be_0 = Be[0]; + const float Be_1 = Be[1]; + const float a1 = q0 * q3 * 2.0f + q1 * q2 * 2.0f; + const float a1s = a1 * a1; + const float a2 = q0 * q0 + q1 * q1 - q2 * q2 - q3 * q3; + const float a2s = a2 * a2; + const float a3 = 1.0f / powf(a1s + a2s, 3.0f / 2.0f) * (1.0f / 2.0f); + + const float k1 = 1.0f / sqrtf(a1s + a2s); + const float k3 = a3 * a2; + const float k4 = a2 * 4.0f; + const float k5 = a1 * 4.0f; + const float k6 = a3 * a1; + + H[6][6] = Be_0 * q0 * k1 * 2.0f + Be_1 * q3 * k1 * 2.0f - Be_0 * (q0 * k4 + q3 * k5) * k3 - Be_1 * (q0 * k4 + q3 * k5) * k6; + H[6][7] = Be_0 * q1 * k1 * 2.0f + Be_1 * q2 * k1 * 2.0f - Be_0 * (q1 * k4 + q2 * k5) * k3 - Be_1 * (q1 * k4 + q2 * k5) * k6; + H[6][8] = Be_0 * q2 * k1 * -2.0f + Be_1 * q1 * k1 * 2.0f + Be_0 * (q2 * k4 - q1 * k5) * k3 + Be_1 * (q2 * k4 - q1 * k5) * k6; + H[6][9] = Be_1 * q0 * k1 * 2.0f - Be_0 * q3 * k1 * 2.0f + Be_0 * (q3 * k4 - q0 * k5) * k3 + Be_1 * (q3 * k4 - q0 * k5) * k6; + H[7][6] = Be_1 * q0 * k1 * 2.0f - Be_0 * q3 * k1 * 2.0f - Be_1 * (q0 * k4 + q3 * k5) * k3 + Be_0 * (q0 * k4 + q3 * k5) * k6; + H[7][7] = Be_0 * q2 * k1 * -2.0f + Be_1 * q1 * k1 * 2.0f - Be_1 * (q1 * k4 + q2 * k5) * k3 + Be_0 * (q1 * k4 + q2 * k5) * k6; + H[7][8] = Be_0 * q1 * k1 * -2.0f - Be_1 * q2 * k1 * 2.0f + Be_1 * (q2 * k4 - q1 * k5) * k3 - Be_0 * (q2 * k4 - q1 * k5) * k6; + H[7][9] = Be_0 * q0 * k1 * -2.0f - Be_1 * q3 * k1 * 2.0f + Be_1 * (q3 * k4 - q0 * k5) * k3 - Be_0 * (q3 * k4 - q0 * k5) * k6; + H[8][6] = 0.0f; + H[8][7] = 0.0f; + H[8][9] = 0.0f; + + // dAlt/dPz = -1 (expected baro readings) + H[9][2] = -1.0f; +} + +/** + * @} + * @} + */ diff --git a/flight/modules/StateEstimation/filterekf.c b/flight/modules/StateEstimation/filterekf.c index 1fd036afd1..43a139053f 100644 --- a/flight/modules/StateEstimation/filterekf.c +++ b/flight/modules/StateEstimation/filterekf.c @@ -202,8 +202,8 @@ static filterResult filter(stateFilter *self, stateEstimation *state) float dT; uint16_t sensors = 0; - this->work.updated |= state->updated; + this->work.updated |= state->updated; // check magnetometer alarm, discard any magnetometer readings if not OK // during initialization phase (but let them through afterwards) SystemAlarmsAlarmData alarms; @@ -241,10 +241,9 @@ static filterResult filter(stateFilter *self, stateEstimation *state) // Reset the INS algorithm INSGPSInit(); // variance is measured in mGaus, but internally the EKF works with a normalized vector. Scale down by Be^2 - float Be2 = this->homeLocation.Be[0] * this->homeLocation.Be[0] + this->homeLocation.Be[1] * this->homeLocation.Be[1] + this->homeLocation.Be[2] * this->homeLocation.Be[2]; - INSSetMagVar((float[3]) { this->ekfConfiguration.R.MagX / Be2, - this->ekfConfiguration.R.MagY / Be2, - this->ekfConfiguration.R.MagZ / Be2 } + INSSetMagVar((float[3]) { this->ekfConfiguration.R.MagX, + this->ekfConfiguration.R.MagY, + this->ekfConfiguration.R.MagZ } ); INSSetAccelVar((float[3]) { this->ekfConfiguration.Q.AccelX, this->ekfConfiguration.Q.AccelY, @@ -421,7 +420,7 @@ static filterResult filter(stateFilter *self, stateEstimation *state) EKFStateVarianceData vardata; EKFStateVarianceGet(&vardata); - INSGetP(EKFStateVariancePToArray(vardata.P)); + INSGetVariance(EKFStateVariancePToArray(vardata.P)); EKFStateVarianceSet(&vardata); int t; for (t = 0; t < EKFSTATEVARIANCE_P_NUMELEM; t++) { diff --git a/flight/targets/boards/revolution/firmware/Makefile b/flight/targets/boards/revolution/firmware/Makefile index 5ee49d1a22..62e0dd156e 100644 --- a/flight/targets/boards/revolution/firmware/Makefile +++ b/flight/targets/boards/revolution/firmware/Makefile @@ -95,7 +95,7 @@ ifndef TESTAPP SRC += $(FLIGHTLIB)/paths.c SRC += $(FLIGHTLIB)/plans.c SRC += $(FLIGHTLIB)/WorldMagModel.c - SRC += $(FLIGHTLIB)/insgps13state.c + SRC += $(FLIGHTLIB)/insgps14state.c SRC += $(FLIGHTLIB)/auxmagsupport.c SRC += $(FLIGHTLIB)/lednotification.c SRC += $(FLIGHTLIB)/sha1.c diff --git a/flight/targets/boards/sparky2/firmware/Makefile b/flight/targets/boards/sparky2/firmware/Makefile index 45c7f28911..942944f6d9 100644 --- a/flight/targets/boards/sparky2/firmware/Makefile +++ b/flight/targets/boards/sparky2/firmware/Makefile @@ -95,7 +95,7 @@ ifndef TESTAPP SRC += $(FLIGHTLIB)/paths.c SRC += $(FLIGHTLIB)/plans.c SRC += $(FLIGHTLIB)/WorldMagModel.c - SRC += $(FLIGHTLIB)/insgps13state.c + SRC += $(FLIGHTLIB)/insgps14state.c SRC += $(FLIGHTLIB)/auxmagsupport.c SRC += $(FLIGHTLIB)/lednotification.c SRC += $(FLIGHTLIB)/sha1.c From 4f045bc73a69517c3d75ead42a2a49d370f43dfe Mon Sep 17 00:00:00 2001 From: Alessio Morale Date: Mon, 18 Jul 2016 01:18:06 +0200 Subject: [PATCH 067/624] LP-443 - Handle arming --- flight/modules/StateEstimation/filterekf.c | 1 + flight/modules/StateEstimation/inc/stateestimation.h | 3 ++- flight/modules/StateEstimation/stateestimation.c | 8 ++++---- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/flight/modules/StateEstimation/filterekf.c b/flight/modules/StateEstimation/filterekf.c index 43a139053f..8a3103e9c3 100644 --- a/flight/modules/StateEstimation/filterekf.c +++ b/flight/modules/StateEstimation/filterekf.c @@ -202,6 +202,7 @@ static filterResult filter(stateFilter *self, stateEstimation *state) float dT; uint16_t sensors = 0; + INSSetArmed(state->armed); this->work.updated |= state->updated; // check magnetometer alarm, discard any magnetometer readings if not OK diff --git a/flight/modules/StateEstimation/inc/stateestimation.h b/flight/modules/StateEstimation/inc/stateestimation.h index 38d21e599b..c34ba91408 100644 --- a/flight/modules/StateEstimation/inc/stateestimation.h +++ b/flight/modules/StateEstimation/inc/stateestimation.h @@ -70,8 +70,9 @@ typedef struct { float airspeed[2]; float baro[1]; float auxMag[3]; - uint8_t magStatus; float boardMag[3]; + uint8_t magStatus; + bool armed; sensorUpdates updated; } stateEstimation; diff --git a/flight/modules/StateEstimation/stateestimation.c b/flight/modules/StateEstimation/stateestimation.c index 72d28fb007..5a08cf8cca 100644 --- a/flight/modules/StateEstimation/stateestimation.c +++ b/flight/modules/StateEstimation/stateestimation.c @@ -355,7 +355,6 @@ static void StateEstimationCb(void) static stateEstimation states; static uint32_t last_time; static uint16_t bootDelay = 64; - // after system startup, first few sensor readings might be messed up, delay until everything has settled if (bootDelay) { bootDelay--; @@ -373,12 +372,13 @@ static void StateEstimationCb(void) } else { last_time = PIOS_DELAY_GetRaw(); } + FlightStatusArmedOptions fsarmed; + FlightStatusArmedGet(&fsarmed); + states.armed = fsarmed != FLIGHTSTATUS_ARMED_DISARMED; // check if a new filter chain should be initialized if (fusionAlgorithm != revoSettings.FusionAlgorithm) { - FlightStatusData fs; - FlightStatusGet(&fs); - if (fs.Armed == FLIGHTSTATUS_ARMED_DISARMED || fusionAlgorithm == FILTER_INIT_FORCE) { + if (fsarmed == FLIGHTSTATUS_ARMED_DISARMED || fusionAlgorithm == FILTER_INIT_FORCE) { const filterPipeline *newFilterChain; switch ((RevoSettingsFusionAlgorithmOptions)revoSettings.FusionAlgorithm) { case REVOSETTINGS_FUSIONALGORITHM_BASICCOMPLEMENTARY: From 5d8f4b6cdec1ddaf29a67612685ab26e2178dad5 Mon Sep 17 00:00:00 2001 From: Alessio Morale Date: Mon, 18 Jul 2016 01:31:54 +0200 Subject: [PATCH 068/624] LP-443 - Fixes to make ins13 and 14 interchangeable --- flight/libraries/inc/insgps.h | 4 +-- flight/libraries/insgps13state.c | 59 +++++++++++++++++++------------- flight/libraries/insgps14state.c | 2 +- 3 files changed, 38 insertions(+), 27 deletions(-) diff --git a/flight/libraries/inc/insgps.h b/flight/libraries/inc/insgps.h index eb39948182..fabf77b480 100644 --- a/flight/libraries/inc/insgps.h +++ b/flight/libraries/inc/insgps.h @@ -58,11 +58,11 @@ void INSGPSInit(); void INSStatePrediction(const float gyro_data[3], const float accel_data[3], float dT); void INSCovariancePrediction(float dT); void INSCorrection(const float mag_data[3], const float Pos[3], const float Vel[3], - float BaroAlt, uint16_t SensorsUsed); + float BaroAlt, uint16_t SensorsUsed); void INSResetP(const float PDiag[13]); void INSGetVariance(float PDiag[13]); void INSSetState(const float pos[3], const float vel[3], const float q[4], const float gyro_bias[3], const float accel_bias[3]); -void INSSetPosVelVar(float PosVar[3], float VelVar[3]); +void INSSetPosVelVar(const float PosVar[3], const float VelVar[3]); void INSSetGyroBias(const float gyro_bias[3]); void INSSetAccelVar(const float accel_var[3]); void INSSetGyroVar(const float gyro_var[3]); diff --git a/flight/libraries/insgps13state.c b/flight/libraries/insgps13state.c index c311f05d33..a818020353 100644 --- a/flight/libraries/insgps13state.c +++ b/flight/libraries/insgps13state.c @@ -163,7 +163,22 @@ void INSGPSInit() // pretty much just a place holder for now ekf.R[9] = .25f; // High freq altimeter noise variance (m^2) } -void INSResetP(float PDiag[NUMX]) +// ! Set the current flight state +void INSSetArmed(bool armed) +{ + return; + + // Speed up convergence of accel and gyro bias when not armed + if (armed) { + ekf.Q[9] = 1e-4f; + ekf.Q[8] = 2e-9f; + } else { + ekf.Q[9] = 1e-2f; + ekf.Q[8] = 2e-8f; + } +} + +void INSResetP(const float PDiag[NUMX]) { uint8_t i, j; @@ -178,7 +193,7 @@ void INSResetP(float PDiag[NUMX]) } } -void INSGetP(float PDiag[NUMX]) +void INSGetVariance(float PDiag[NUMX]) { uint8_t i; @@ -189,8 +204,7 @@ void INSGetP(float PDiag[NUMX]) } } } - -void INSSetState(float pos[3], float vel[3], float q[4], float gyro_bias[3], __attribute__((unused)) float accel_bias[3]) +void INSSetState(const float pos[3], const float vel[3], const float q[4], const float gyro_bias[3], __attribute__((unused)) const float accel_bias[3]) { /* Note: accel_bias not used in 13 state INS */ ekf.X[0] = pos[0]; @@ -208,7 +222,7 @@ void INSSetState(float pos[3], float vel[3], float q[4], float gyro_bias[3], __a ekf.X[12] = gyro_bias[2]; } -void INSPosVelReset(float pos[3], float vel[3]) +void INSPosVelReset(const float pos[3], const float vel[3]) { for (int i = 0; i < 6; i++) { for (int j = i; j < NUMX; j++) { @@ -228,7 +242,7 @@ void INSPosVelReset(float pos[3], float vel[3]) ekf.X[5] = vel[2]; } -void INSSetPosVelVar(float PosVar[3], float VelVar[3]) +void INSSetPosVelVar(const float PosVar[3], const float VelVar[3]) { ekf.R[0] = PosVar[0]; ekf.R[1] = PosVar[1]; @@ -238,35 +252,35 @@ void INSSetPosVelVar(float PosVar[3], float VelVar[3]) ekf.R[5] = VelVar[2]; } -void INSSetGyroBias(float gyro_bias[3]) +void INSSetGyroBias(const float gyro_bias[3]) { ekf.X[10] = gyro_bias[0]; ekf.X[11] = gyro_bias[1]; ekf.X[12] = gyro_bias[2]; } -void INSSetAccelVar(float accel_var[3]) +void INSSetAccelVar(const float accel_var[3]) { ekf.Q[3] = accel_var[0]; ekf.Q[4] = accel_var[1]; ekf.Q[5] = accel_var[2]; } -void INSSetGyroVar(float gyro_var[3]) +void INSSetGyroVar(const float gyro_var[3]) { ekf.Q[0] = gyro_var[0]; ekf.Q[1] = gyro_var[1]; ekf.Q[2] = gyro_var[2]; } -void INSSetGyroBiasVar(float gyro_bias_var[3]) +void INSSetGyroBiasVar(const float gyro_bias_var[3]) { ekf.Q[6] = gyro_bias_var[0]; ekf.Q[7] = gyro_bias_var[1]; ekf.Q[8] = gyro_bias_var[2]; } -void INSSetMagVar(float scaled_mag_var[3]) +void INSSetMagVar(const float scaled_mag_var[3]) { ekf.R[6] = scaled_mag_var[0]; ekf.R[7] = scaled_mag_var[1]; @@ -278,16 +292,14 @@ void INSSetBaroVar(float baro_var) ekf.R[9] = baro_var; } -void INSSetMagNorth(float B[3]) +void INSSetMagNorth(const float B[3]) { - float invmag = invsqrtf(B[0] * B[0] + B[1] * B[1] + B[2] * B[2]); - - ekf.Be[0] = B[0] * invmag; - ekf.Be[1] = B[1] * invmag; - ekf.Be[2] = B[2] * invmag; + ekf.Be[0] = B[0]; + ekf.Be[1] = B[1]; + ekf.Be[2] = B[2]; } -void INSStatePrediction(float gyro_data[3], float accel_data[3], float dT) +void INSStatePrediction(const float gyro_data[3], const float accel_data[3], float dT) { float U[6]; float invqmag; @@ -371,8 +383,8 @@ void VelBaroCorrection(float Vel[3], float BaroAlt) HORIZ_SENSORS | VERT_SENSORS | BARO_SENSOR); } -void INSCorrection(float mag_data[3], float Pos[3], float Vel[3], - float BaroAlt, uint16_t SensorsUsed) +void INSCorrection(const float mag_data[3], const float Pos[3], const float Vel[3], + const float BaroAlt, uint16_t SensorsUsed) { float Z[10] = { 0 }; float Y[10] = { 0 }; @@ -390,10 +402,9 @@ void INSCorrection(float mag_data[3], float Pos[3], float Vel[3], if (SensorsUsed & MAG_SENSORS) { - float invBmag = invsqrtf(mag_data[0] * mag_data[0] + mag_data[1] * mag_data[1] + mag_data[2] * mag_data[2]); - Z[6] = mag_data[0] * invBmag; - Z[7] = mag_data[1] * invBmag; - Z[8] = mag_data[2] * invBmag; + Z[6] = mag_data[0]; + Z[7] = mag_data[1]; + Z[8] = mag_data[2]; } // barometric altimeter in meters and in local NED frame diff --git a/flight/libraries/insgps14state.c b/flight/libraries/insgps14state.c index 02b9b8faa1..5a22a85cfa 100644 --- a/flight/libraries/insgps14state.c +++ b/flight/libraries/insgps14state.c @@ -265,7 +265,7 @@ void INSPosVelReset(const float pos[3], const float vel[3]) ekf.X[4] = vel[1]; ekf.X[5] = vel[2]; } -void INSSetPosVelVar(float PosVar[3], float VelVar[3]) +void INSSetPosVelVar(const float PosVar[3], const float VelVar[3]) // void INSSetPosVelVar(float PosVar, float VelVar, float VertPosVar) { ekf.R[0] = PosVar[0]; From ff5bd26e1a96708f33246f52002be8d8f290317e Mon Sep 17 00:00:00 2001 From: Alessio Morale Date: Thu, 7 Jul 2016 23:34:36 +0200 Subject: [PATCH 069/624] LP-353 - Allow INS For nav and CF for attitude --- .../modules/StateEstimation/stateestimation.c | 26 +++++++++++++++++++ shared/uavobjectdefinition/revosettings.xml | 2 +- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/flight/modules/StateEstimation/stateestimation.c b/flight/modules/StateEstimation/stateestimation.c index 5a08cf8cca..a727e215ef 100644 --- a/flight/modules/StateEstimation/stateestimation.c +++ b/flight/modules/StateEstimation/stateestimation.c @@ -251,6 +251,29 @@ static const filterPipeline *ekf13Queue = &(filterPipeline) { } }; +static const filterPipeline *ekf13NavCFAttQueue = &(filterPipeline) { + .filter = &magFilter, + .next = &(filterPipeline) { + .filter = &airFilter, + .next = &(filterPipeline) { + .filter = &llaFilter, + .next = &(filterPipeline) { + .filter = &baroFilter, + .next = &(filterPipeline) { + .filter = &ekf13Filter, + .next = &(filterPipeline) { + .filter = &velocityFilter, + .next = &(filterPipeline) { + .filter = &cfmFilter, + .next = NULL, + } + } + } + } + } + } +}; + // Private functions static void settingsUpdatedCb(UAVObjEvent *objEv); @@ -398,6 +421,9 @@ static void StateEstimationCb(void) case REVOSETTINGS_FUSIONALGORITHM_GPSNAVIGATIONINS13: newFilterChain = ekf13Queue; break; + case REVOSETTINGS_FUSIONALGORITHM_GPSNAVIGATIONINS13CF: + newFilterChain = ekf13NavCFAttQueue; + break; default: newFilterChain = NULL; } diff --git a/shared/uavobjectdefinition/revosettings.xml b/shared/uavobjectdefinition/revosettings.xml index 116b842cfe..a99ad9c529 100644 --- a/shared/uavobjectdefinition/revosettings.xml +++ b/shared/uavobjectdefinition/revosettings.xml @@ -2,7 +2,7 @@ Settings for the revo to control the algorithm and what is updated From 7207e9544740636b526018e1a8d4aed18c26c575 Mon Sep 17 00:00:00 2001 From: Laurent Lalanne Date: Wed, 1 Mar 2017 16:12:42 +0100 Subject: [PATCH 158/624] LP-489 Apply SmoothQuickSource changes --- flight/modules/AutoTune/autotune.c | 34 +++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/flight/modules/AutoTune/autotune.c b/flight/modules/AutoTune/autotune.c index 6630ea953d..a5cf0ecc18 100644 --- a/flight/modules/AutoTune/autotune.c +++ b/flight/modules/AutoTune/autotune.c @@ -156,6 +156,7 @@ static uint8_t CheckSettingsRaw(); static void ComputeStabilizationAndSetPidsFromDampAndNoise(float damp, float noise); static void FlightModeSettingsUpdatedCb(UAVObjEvent *ev); static void InitSystemIdent(bool loadDefaults); +static void UpdateSmoothQuickSource(uint8_t smoothQuickSource, bool loadDefaults); static void ProportionPidsSmoothToQuick(); static void UpdateSystemIdentState(const float *X, const float *noise, float dT_s, uint32_t predicts, uint32_t spills, float hover_throttle); static void UpdateStabilizationDesired(bool doingIdent); @@ -249,6 +250,7 @@ static void AutoTuneTask(__attribute__((unused)) void *parameters) uint32_t measureTime = 0; uint32_t updateCounter = 0; enum AUTOTUNE_STATE state = AT_INIT; + uint8_t currentSmoothQuickSource = 0; bool saveSiNeeded = false; bool savePidNeeded = false; @@ -327,6 +329,15 @@ static void AutoTuneTask(__attribute__((unused)) void *parameters) saveSiNeeded = true; } + // Check if the SmoothQuickSource changed, + // allow config changes without reboot or reinit + uint8_t smoothQuickSource; + SystemIdentSettingsSmoothQuickSourceGet(&smoothQuickSource); + if (smoothQuickSource != currentSmoothQuickSource) { + UpdateSmoothQuickSource(smoothQuickSource, true); + currentSmoothQuickSource = smoothQuickSource; + } + ////////////////////////////////////////////////////////////////////////////////////// // if configured to use a slider for smooth-quick and the autotune module is running // (note that the module can be automatically or manually enabled) @@ -355,12 +366,9 @@ static void AutoTuneTask(__attribute__((unused)) void *parameters) if (accessoryToUse != -1 && systemIdentSettings.Complete && !CheckSettings()) { AccessoryDesiredData accessoryValue; AccessoryDesiredInstGet(accessoryToUse, &accessoryValue); - // if the accessory changed more than some percent of total range - // some old PPM receivers use a low resolution chip which only allows about 180 steps out of a range of 2.0 - // a test Taranis transmitter knob has about 0.0233 slop out of a range of 2.0 - // what we are doing here does not need any higher precision than that - // user must move the knob more than 1/85th of the total range (of 2.0) for it to register as changed - if (fabsf(smoothQuickValue - accessoryValue.AccessoryVal) > (2.0f / 85.0f)) { + // if the accessory changed more than 2 percent of total range (~20µs) + // the smoothQuickValue will be changed + if (fabsf(smoothQuickValue - accessoryValue.AccessoryVal) > 0.02f) { smoothQuickValue = accessoryValue.AccessoryVal; // calculate PIDs based on new smoothQuickValue and save to the PID bank ProportionPidsSmoothToQuick(); @@ -727,8 +735,14 @@ static void InitSystemIdent(bool loadDefaults) gyroReadTimeAverageAlpha = 0.99999988f; gyroReadTimeAverage = u.systemIdentState.GyroReadTimeAverage; - uint8_t SmoothQuickSource = systemIdentSettings.SmoothQuickSource; - switch (SmoothQuickSource) { + UpdateSmoothQuickSource(systemIdentSettings.SmoothQuickSource, loadDefaults); +} + + +// Update SmoothQuickSource to be used +static void UpdateSmoothQuickSource(uint8_t smoothQuickSource, bool loadDefaults) +{ + switch (smoothQuickSource) { case SMOOTH_QUICK_ACCESSORY_BASE + 0: // use accessory0 case SMOOTH_QUICK_ACCESSORY_BASE + 1: // use accessory1 case SMOOTH_QUICK_ACCESSORY_BASE + 2: // use accessory2 @@ -737,7 +751,7 @@ static void InitSystemIdent(bool loadDefaults) // disable PID changing with flight mode switch flightModeSwitchTogglePosition = -1; // enable PID changing with accessory0-3 - accessoryToUse = SmoothQuickSource - SMOOTH_QUICK_ACCESSORY_BASE; + accessoryToUse = smoothQuickSource - SMOOTH_QUICK_ACCESSORY_BASE; break; case SMOOTH_QUICK_TOGGLE_BASE + 3: // use flight mode switch toggle with 3 points case SMOOTH_QUICK_TOGGLE_BASE + 5: // use flight mode switch toggle with 5 points @@ -748,7 +762,7 @@ static void InitSystemIdent(bool loadDefaults) smoothQuickValue = 0.0f; } // enable PID changing with flight mode switch - flightModeSwitchTogglePosition = (SmoothQuickSource - 1 - SMOOTH_QUICK_TOGGLE_BASE) / 2; + flightModeSwitchTogglePosition = (smoothQuickSource - 1 - SMOOTH_QUICK_TOGGLE_BASE) / 2; // disable PID changing with accessory0-3 accessoryToUse = -1; break; From e7eeba8475166af6cbf012cfb3fc69b72f9277a1 Mon Sep 17 00:00:00 2001 From: Laurent Lalanne Date: Wed, 1 Mar 2017 17:00:07 +0100 Subject: [PATCH 159/624] LP-489 Round the smoothQuickValue to 0 --- flight/modules/AutoTune/autotune.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/flight/modules/AutoTune/autotune.c b/flight/modules/AutoTune/autotune.c index a5cf0ecc18..9b32420e76 100644 --- a/flight/modules/AutoTune/autotune.c +++ b/flight/modules/AutoTune/autotune.c @@ -316,6 +316,10 @@ static void AutoTuneTask(__attribute__((unused)) void *parameters) if (smoothQuickValue > 1.001f) { smoothQuickValue = -1.0f; } + // Assume the value is 0 + if (fabsf(smoothQuickValue) < 0.001f) { + smoothQuickValue = 0.0f; + } } else { // if they did the 3x FMS toggle while disarmed, set PID's back to the middle of smoothquick smoothQuickValue = 0.0f; From 74bd1589e80e75fc5b3cc4ad35d41c18437fce1a Mon Sep 17 00:00:00 2001 From: Eric Price Date: Wed, 1 Mar 2017 19:51:40 +0100 Subject: [PATCH 160/624] LP-443 modified insgps14state to use spare matrix optimization (similar to insgps13state) as opposed to precompiled prediction equation code --- flight/libraries/insgps14state.c | 363 +++++++++++++------------------ 1 file changed, 156 insertions(+), 207 deletions(-) diff --git a/flight/libraries/insgps14state.c b/flight/libraries/insgps14state.c index 79fe79a97c..bd3944cddf 100644 --- a/flight/libraries/insgps14state.c +++ b/flight/libraries/insgps14state.c @@ -44,28 +44,52 @@ #define NUMW 10 // number of plant noise inputs, w is disturbance noise vector #define NUMV 10 // number of measurements, v is the measurement noise vector #define NUMU 6 // number of deterministic inputs, U is the input vector - -#if defined(GENERAL_COV) -// This might trick people so I have a note here. There is a slower but bigger version of the -// code here but won't fit when debugging disabled (requires -Os) -#define COVARIANCE_PREDICTION_GENERAL -#endif - +#pragma GCC optimize "O3" // Private functions void CovariancePrediction(float F[NUMX][NUMX], float G[NUMX][NUMW], float Q[NUMW], float dT, float P[NUMX][NUMX]); -void SerialUpdate(float H[NUMV][NUMX], float R[NUMV], float Z[NUMV], - float Y[NUMV], float P[NUMX][NUMX], float X[NUMX], - uint16_t SensorsUsed); -void RungeKutta(float X[NUMX], float U[NUMU], float dT); -void StateEq(float X[NUMX], float U[NUMU], float Xdot[NUMX]); -void LinearizeFG(float X[NUMX], float U[NUMU], float F[NUMX][NUMX], - float G[NUMX][NUMW]); -void MeasurementEq(float X[NUMX], float Be[3], float Y[NUMV]); -void LinearizeH(float X[NUMX], float Be[3], float H[NUMV][NUMX]); - +static void SerialUpdate(float H[NUMV][NUMX], float R[NUMV], float Z[NUMV], + float Y[NUMV], float P[NUMX][NUMX], float X[NUMX], + uint16_t SensorsUsed); +static void RungeKutta(float X[NUMX], float U[NUMU], float dT); +static void StateEq(float X[NUMX], float U[NUMU], float Xdot[NUMX]); +static void LinearizeFG(float X[NUMX], float U[NUMU], float F[NUMX][NUMX], + float G[NUMX][NUMW]); +static void MeasurementEq(float X[NUMX], float Be[3], float Y[NUMV]); +static void LinearizeH(float X[NUMX], float Be[3], float H[NUMV][NUMX]); // Private variables + +// speed optimizations, describe matrix sparsity +// derived from state equations in +// LinearizeFG() and LinearizeH(): +// +// usage F: usage G: usage H: +// -0123456789abcd 0123456789 0123456789abcd +// 0...X.......... .......... X............. +// 1....X......... .......... .X............ +// 2.....X........ .......... ..X........... +// 3......XXXX...X ...XXX.... ...X.......... +// 4......XXXX...X ...XXX.... ....X......... +// 5......XXXX...X ...XXX.... .....X........ +// 6.....ooXXXXXX. XXX....... ......XXXX.... +// 7.....oXoXXXXX. XXX....... ......XXXX.... +// 8.....oXXoXXXX. XXX....... ......XXXX.... +// 9.....oXXXoXXX. XXX....... ..X........... +// a.............. .......... .............. +// b.............. .......... +// c.............. .......... +// d.............. .......... + +static int8_t FrowMin[NUMX] = { 3, 4, 5, 6, 6, 6, 5, 5, 5, 5, 14, 14, 14, 14 }; +static int8_t FrowMax[NUMX] = { 3, 4, 5, 13, 13, 13, 12, 12, 12, 12, -1, -1, -1, -1 }; + +static int8_t GrowMin[NUMX] = { 10, 10, 10, 3, 3, 3, 0, 0, 0, 0, 10, 10, 10 }; +static int8_t GrowMax[NUMX] = { -1, -1, -1, 5, 5, 5, 2, 2, 2, 2, -1, -1, -1 }; + +static int8_t HrowMin[NUMV] = { 0, 1, 2, 3, 4, 5, 6, 6, 6, 2 }; +static int8_t HrowMax[NUMV] = { 0, 1, 2, 3, 4, 5, 9, 9, 9, 2 }; + static struct EKFData { float F[NUMX][NUMX]; float G[NUMX][NUMW]; @@ -101,6 +125,7 @@ void INSGPSInit() ekf.P[i][j] = 0.0f; // zero all terms ekf.F[i][j] = 0.0f; } + for (int j = 0; j < NUMW; j++) { ekf.G[i][j] = 0.0f; } @@ -352,7 +377,7 @@ void INSLimitBias() void INSStatePrediction(const float gyro_data[3], const float accel_data[3], float dT) { float U[6]; - float qmag; + float invqmag; // rate gyro inputs in units of rad/s U[0] = gyro_data[0]; @@ -367,11 +392,11 @@ void INSStatePrediction(const float gyro_data[3], const float accel_data[3], flo // EKF prediction step LinearizeFG(ekf.X, U, ekf.F, ekf.G); RungeKutta(ekf.X, U, dT); - qmag = sqrtf(ekf.X[6] * ekf.X[6] + ekf.X[7] * ekf.X[7] + ekf.X[8] * ekf.X[8] + ekf.X[9] * ekf.X[9]); - ekf.X[6] /= qmag; - ekf.X[7] /= qmag; - ekf.X[8] /= qmag; - ekf.X[9] /= qmag; + invqmag = invsqrtf(ekf.X[6] * ekf.X[6] + ekf.X[7] * ekf.X[7] + ekf.X[8] * ekf.X[8] + ekf.X[9] * ekf.X[9]); + ekf.X[6] *= invqmag; + ekf.X[7] *= invqmag; + ekf.X[8] *= invqmag; + ekf.X[9] *= invqmag; // Update Nav solution structure Nav.Pos[0] = ekf.X[0]; @@ -384,12 +409,12 @@ void INSStatePrediction(const float gyro_data[3], const float accel_data[3], flo Nav.q[1] = ekf.X[7]; Nav.q[2] = ekf.X[8]; Nav.q[3] = ekf.X[9]; - Nav.gyro_bias[0] = ekf.X[10]; - Nav.gyro_bias[1] = ekf.X[11]; - Nav.gyro_bias[2] = ekf.X[12]; - Nav.gyro_bias[0] = 0.0f; - Nav.gyro_bias[1] = 0.0f; - Nav.gyro_bias[2] = ekf.X[13]; + Nav.gyro_bias[0] = ekf.X[10]; + Nav.gyro_bias[1] = ekf.X[11]; + Nav.gyro_bias[2] = ekf.X[12]; + Nav.accel_bias[0] = 0.0f; + Nav.accel_bias[1] = 0.0f; + Nav.accel_bias[2] = ekf.X[13]; } void INSCovariancePrediction(float dT) @@ -398,10 +423,10 @@ void INSCovariancePrediction(float dT) } void INSCorrection(const float mag_data[3], const float Pos[3], const float Vel[3], - float BaroAlt, uint16_t SensorsUsed) + const float BaroAlt, uint16_t SensorsUsed) { float Z[10], Y[10]; - float qmag; + float invqmag; // GPS Position in meters and in local NED frame Z[0] = Pos[0]; @@ -445,11 +470,11 @@ void INSCorrection(const float mag_data[3], const float Pos[3], const float Vel[ LinearizeH(ekf.X, ekf.Be, ekf.H); MeasurementEq(ekf.X, ekf.Be, Y); SerialUpdate(ekf.H, ekf.R, Z, Y, ekf.P, ekf.X, SensorsUsed); - qmag = sqrtf(ekf.X[6] * ekf.X[6] + ekf.X[7] * ekf.X[7] + ekf.X[8] * ekf.X[8] + ekf.X[9] * ekf.X[9]); - ekf.X[6] /= qmag; - ekf.X[7] /= qmag; - ekf.X[8] /= qmag; - ekf.X[9] /= qmag; + invqmag = invsqrtf(ekf.X[6] * ekf.X[6] + ekf.X[7] * ekf.X[7] + ekf.X[8] * ekf.X[8] + ekf.X[9] * ekf.X[9]); + ekf.X[6] *= invqmag; + ekf.X[7] *= invqmag; + ekf.X[8] *= invqmag; + ekf.X[9] *= invqmag; INSLimitBias(); } @@ -465,167 +490,85 @@ void INSCorrection(const float mag_data[3], const float Pos[3], const float Vel[ // The first Method is very specific to this implementation // ************************************************ -#ifdef COVARIANCE_PREDICTION_GENERAL - void CovariancePrediction(float F[NUMX][NUMX], float G[NUMX][NUMW], float Q[NUMW], float dT, float P[NUMX][NUMX]) { - float Dummy[NUMX][NUMX], dTsq; - uint8_t i, j, k; + // Pnew = (I+F*T)*P*(I+F*T)' + (T^2)*G*Q*G' = (T^2)[(P/T + F*P)*(I/T + F') + G*Q*G')] - // Pnew = (I+F*T)*P*(I+F*T)' + T^2*G*Q*G' = T^2[(P/T + F*P)*(I/T + F') + G*Q*G')] + const float dT1 = 1.0f / dT; // multiplication is faster than division on fpu. + const float dTsq = dT * dT; - dTsq = dT * dT; + float Dummy[NUMX][NUMX]; + int8_t i; + int8_t k; for (i = 0; i < NUMX; i++) { // Calculate Dummy = (P/T +F*P) + float *Firow = F[i]; + float *Pirow = P[i]; + float *Dirow = Dummy[i]; + const int8_t Fistart = FrowMin[i]; + const int8_t Fiend = FrowMax[i]; + int8_t j; + for (j = 0; j < NUMX; j++) { - Dummy[i][j] = P[i][j] / dT; - for (k = 0; k < NUMX; k++) { - Dummy[i][j] += F[i][k] * P[k][j]; - } + Dirow[j] = Pirow[j] * dT1; // Dummy = P / T ... } - } - for (i = 0; i < NUMX; i++) { // Calculate Pnew = Dummy/T + Dummy*F' + G*Qw*G' - for (j = i; j < NUMX; j++) { // Use symmetry, ie only find upper triangular - P[i][j] = Dummy[i][j] / dT; - for (k = 0; k < NUMX; k++) { - P[i][j] += Dummy[i][k] * F[j][k]; // P = Dummy/T + Dummy*F' - } - for (k = 0; k < NUMW; k++) { - P[i][j] += Q[k] * G[i][k] * G[j][k]; // P = Dummy/T + Dummy*F' + G*Q*G' + for (k = Fistart; k <= Fiend; k++) { + for (j = 0; j < NUMX; j++) { + Dirow[j] += Firow[k] * P[k][j]; // [] + F * P } - P[j][i] = P[i][j] = P[i][j] * dTsq; // Pnew = T^2*P and fill in lower triangular; } } -} + for (i = 0; i < NUMX; i++) { // Calculate Pnew = (T^2) [Dummy/T + Dummy*F' + G*Qw*G'] + float *Dirow = Dummy[i]; + float *Girow = G[i]; + float *Pirow = P[i]; + const int8_t Gistart = GrowMin[i]; + const int8_t Giend = GrowMax[i]; + int8_t j; -#else /* ifdef COVARIANCE_PREDICTION_GENERAL */ -void CovariancePrediction(float F[NUMX][NUMX], float G[NUMX][NUMW], - float Q[NUMW], float dT, float P[NUMX][NUMX]) -{ - float D[NUMX][NUMX], T, Tsq; - uint8_t i, j; - - // Pnew = (I+F*T)*P*(I+F*T)' + T^2*G*Q*G' = scalar expansion from symbolic manipulator + for (j = i; j < NUMX; j++) { // Use symmetry, ie only find upper triangular + float Ptmp = Dirow[j] * dT1; // Pnew = Dummy / T ... + + const float *Fjrow = F[j]; + int8_t Fjstart = FrowMin[j]; + int8_t Fjend = FrowMax[j]; + k = Fjstart; + + while (k <= Fjend - 3) { + Ptmp += Dirow[k] * Fjrow[k]; // [] + Dummy*F' ... + Ptmp += Dirow[k + 1] * Fjrow[k + 1]; + Ptmp += Dirow[k + 2] * Fjrow[k + 2]; + Ptmp += Dirow[k + 3] * Fjrow[k + 3]; + k += 4; + } + while (k <= Fjend) { + Ptmp += Dirow[k] * Fjrow[k]; + k++; + } - T = dT; - Tsq = dT * dT; + float *Gjrow = G[j]; + const int8_t Gjstart = MAX(Gistart, GrowMin[j]); + const int8_t Gjend = MIN(Giend, GrowMax[j]); + k = Gjstart; + while (k <= Gjend - 2) { + Ptmp += Q[k] * Girow[k] * Gjrow[k]; // [] + G*Q*G' ... + Ptmp += Q[k + 1] * Girow[k + 1] * Gjrow[k + 1]; + Ptmp += Q[k + 2] * Girow[k + 2] * Gjrow[k + 2]; + k += 3; + } + if (k <= Gjend) { + Ptmp += Q[k] * Girow[k] * Gjrow[k]; + if (k <= Gjend - 1) { + Ptmp += Q[k + 1] * Girow[k + 1] * Gjrow[k + 1]; + } + } - for (i = 0; i < NUMX; i++) { // Create a copy of the upper triangular of P - for (j = i; j < NUMX; j++) { - D[i][j] = P[i][j]; + P[j][i] = Pirow[j] = Ptmp * dTsq; // [] * (T^2) } } - - // Brute force calculation of the elements of P - P[0][0] = D[3][3] * Tsq + (2 * D[0][3]) * T + D[0][0]; - P[0][1] = P[1][0] = D[3][4] * Tsq + (D[0][4] + D[1][3]) * T + D[0][1]; - P[0][2] = P[2][0] = D[3][5] * Tsq + (D[0][5] + D[2][3]) * T + D[0][2]; - P[0][3] = P[3][0] = (F[3][6] * D[3][6] + F[3][7] * D[3][7] + F[3][8] * D[3][8] + F[3][9] * D[3][9] + F[3][13] * D[3][13]) * Tsq + (D[3][3] + F[3][6] * D[0][6] + F[3][7] * D[0][7] + F[3][8] * D[0][8] + F[3][9] * D[0][9] + F[3][13] * D[0][13]) * T + D[0][3]; - P[0][4] = P[4][0] = (F[4][6] * D[3][6] + F[4][7] * D[3][7] + F[4][8] * D[3][8] + F[4][9] * D[3][9] + F[4][13] * D[3][13]) * Tsq + (D[3][4] + F[4][6] * D[0][6] + F[4][7] * D[0][7] + F[4][8] * D[0][8] + F[4][9] * D[0][9] + F[4][13] * D[0][13]) * T + D[0][4]; - P[0][5] = P[5][0] = (F[5][6] * D[3][6] + F[5][7] * D[3][7] + F[5][8] * D[3][8] + F[5][9] * D[3][9] + F[5][13] * D[3][13]) * Tsq + (D[3][5] + F[5][6] * D[0][6] + F[5][7] * D[0][7] + F[5][8] * D[0][8] + F[5][9] * D[0][9] + F[5][13] * D[0][13]) * T + D[0][5]; - P[0][6] = P[6][0] = (F[6][7] * D[3][7] + F[6][8] * D[3][8] + F[6][9] * D[3][9] + F[6][10] * D[3][10] + F[6][11] * D[3][11] + F[6][12] * D[3][12]) * Tsq + (D[3][6] + F[6][7] * D[0][7] + F[6][8] * D[0][8] + F[6][9] * D[0][9] + F[6][10] * D[0][10] + F[6][11] * D[0][11] + F[6][12] * D[0][12]) * T + D[0][6]; - P[0][7] = P[7][0] = (F[7][6] * D[3][6] + F[7][8] * D[3][8] + F[7][9] * D[3][9] + F[7][10] * D[3][10] + F[7][11] * D[3][11] + F[7][12] * D[3][12]) * Tsq + (D[3][7] + F[7][6] * D[0][6] + F[7][8] * D[0][8] + F[7][9] * D[0][9] + F[7][10] * D[0][10] + F[7][11] * D[0][11] + F[7][12] * D[0][12]) * T + D[0][7]; - P[0][8] = P[8][0] = (F[8][6] * D[3][6] + F[8][7] * D[3][7] + F[8][9] * D[3][9] + F[8][10] * D[3][10] + F[8][11] * D[3][11] + F[8][12] * D[3][12]) * Tsq + (D[3][8] + F[8][6] * D[0][6] + F[8][7] * D[0][7] + F[8][9] * D[0][9] + F[8][10] * D[0][10] + F[8][11] * D[0][11] + F[8][12] * D[0][12]) * T + D[0][8]; - P[0][9] = P[9][0] = (F[9][6] * D[3][6] + F[9][7] * D[3][7] + F[9][8] * D[3][8] + F[9][10] * D[3][10] + F[9][11] * D[3][11] + F[9][12] * D[3][12]) * Tsq + (D[3][9] + F[9][6] * D[0][6] + F[9][7] * D[0][7] + F[9][8] * D[0][8] + F[9][10] * D[0][10] + F[9][11] * D[0][11] + F[9][12] * D[0][12]) * T + D[0][9]; - P[0][10] = P[10][0] = D[3][10] * T + D[0][10]; - P[0][11] = P[11][0] = D[3][11] * T + D[0][11]; - P[0][12] = P[12][0] = D[3][12] * T + D[0][12]; - P[0][13] = P[13][0] = D[3][13] * T + D[0][13]; - P[1][1] = D[4][4] * Tsq + (2 * D[1][4]) * T + D[1][1]; - P[1][2] = P[2][1] = D[4][5] * Tsq + (D[1][5] + D[2][4]) * T + D[1][2]; - P[1][3] = P[3][1] = (F[3][6] * D[4][6] + F[3][7] * D[4][7] + F[3][8] * D[4][8] + F[3][9] * D[4][9] + F[3][13] * D[4][13]) * Tsq + (D[3][4] + F[3][6] * D[1][6] + F[3][7] * D[1][7] + F[3][8] * D[1][8] + F[3][9] * D[1][9] + F[3][13] * D[1][13]) * T + D[1][3]; - P[1][4] = P[4][1] = (F[4][6] * D[4][6] + F[4][7] * D[4][7] + F[4][8] * D[4][8] + F[4][9] * D[4][9] + F[4][13] * D[4][13]) * Tsq + (D[4][4] + F[4][6] * D[1][6] + F[4][7] * D[1][7] + F[4][8] * D[1][8] + F[4][9] * D[1][9] + F[4][13] * D[1][13]) * T + D[1][4]; - P[1][5] = P[5][1] = (F[5][6] * D[4][6] + F[5][7] * D[4][7] + F[5][8] * D[4][8] + F[5][9] * D[4][9] + F[5][13] * D[4][13]) * Tsq + (D[4][5] + F[5][6] * D[1][6] + F[5][7] * D[1][7] + F[5][8] * D[1][8] + F[5][9] * D[1][9] + F[5][13] * D[1][13]) * T + D[1][5]; - P[1][6] = P[6][1] = (F[6][7] * D[4][7] + F[6][8] * D[4][8] + F[6][9] * D[4][9] + F[6][10] * D[4][10] + F[6][11] * D[4][11] + F[6][12] * D[4][12]) * Tsq + (D[4][6] + F[6][7] * D[1][7] + F[6][8] * D[1][8] + F[6][9] * D[1][9] + F[6][10] * D[1][10] + F[6][11] * D[1][11] + F[6][12] * D[1][12]) * T + D[1][6]; - P[1][7] = P[7][1] = (F[7][6] * D[4][6] + F[7][8] * D[4][8] + F[7][9] * D[4][9] + F[7][10] * D[4][10] + F[7][11] * D[4][11] + F[7][12] * D[4][12]) * Tsq + (D[4][7] + F[7][6] * D[1][6] + F[7][8] * D[1][8] + F[7][9] * D[1][9] + F[7][10] * D[1][10] + F[7][11] * D[1][11] + F[7][12] * D[1][12]) * T + D[1][7]; - P[1][8] = P[8][1] = (F[8][6] * D[4][6] + F[8][7] * D[4][7] + F[8][9] * D[4][9] + F[8][10] * D[4][10] + F[8][11] * D[4][11] + F[8][12] * D[4][12]) * Tsq + (D[4][8] + F[8][6] * D[1][6] + F[8][7] * D[1][7] + F[8][9] * D[1][9] + F[8][10] * D[1][10] + F[8][11] * D[1][11] + F[8][12] * D[1][12]) * T + D[1][8]; - P[1][9] = P[9][1] = (F[9][6] * D[4][6] + F[9][7] * D[4][7] + F[9][8] * D[4][8] + F[9][10] * D[4][10] + F[9][11] * D[4][11] + F[9][12] * D[4][12]) * Tsq + (D[4][9] + F[9][6] * D[1][6] + F[9][7] * D[1][7] + F[9][8] * D[1][8] + F[9][10] * D[1][10] + F[9][11] * D[1][11] + F[9][12] * D[1][12]) * T + D[1][9]; - P[1][10] = P[10][1] = D[4][10] * T + D[1][10]; - P[1][11] = P[11][1] = D[4][11] * T + D[1][11]; - P[1][12] = P[12][1] = D[4][12] * T + D[1][12]; - P[1][13] = P[13][1] = D[4][13] * T + D[1][13]; - P[2][2] = D[5][5] * Tsq + (2 * D[2][5]) * T + D[2][2]; - P[2][3] = P[3][2] = (F[3][6] * D[5][6] + F[3][7] * D[5][7] + F[3][8] * D[5][8] + F[3][9] * D[5][9] + F[3][13] * D[5][13]) * Tsq + (D[3][5] + F[3][6] * D[2][6] + F[3][7] * D[2][7] + F[3][8] * D[2][8] + F[3][9] * D[2][9] + F[3][13] * D[2][13]) * T + D[2][3]; - P[2][4] = P[4][2] = (F[4][6] * D[5][6] + F[4][7] * D[5][7] + F[4][8] * D[5][8] + F[4][9] * D[5][9] + F[4][13] * D[5][13]) * Tsq + (D[4][5] + F[4][6] * D[2][6] + F[4][7] * D[2][7] + F[4][8] * D[2][8] + F[4][9] * D[2][9] + F[4][13] * D[2][13]) * T + D[2][4]; - P[2][5] = P[5][2] = (F[5][6] * D[5][6] + F[5][7] * D[5][7] + F[5][8] * D[5][8] + F[5][9] * D[5][9] + F[5][13] * D[5][13]) * Tsq + (D[5][5] + F[5][6] * D[2][6] + F[5][7] * D[2][7] + F[5][8] * D[2][8] + F[5][9] * D[2][9] + F[5][13] * D[2][13]) * T + D[2][5]; - P[2][6] = P[6][2] = (F[6][7] * D[5][7] + F[6][8] * D[5][8] + F[6][9] * D[5][9] + F[6][10] * D[5][10] + F[6][11] * D[5][11] + F[6][12] * D[5][12]) * Tsq + (D[5][6] + F[6][7] * D[2][7] + F[6][8] * D[2][8] + F[6][9] * D[2][9] + F[6][10] * D[2][10] + F[6][11] * D[2][11] + F[6][12] * D[2][12]) * T + D[2][6]; - P[2][7] = P[7][2] = (F[7][6] * D[5][6] + F[7][8] * D[5][8] + F[7][9] * D[5][9] + F[7][10] * D[5][10] + F[7][11] * D[5][11] + F[7][12] * D[5][12]) * Tsq + (D[5][7] + F[7][6] * D[2][6] + F[7][8] * D[2][8] + F[7][9] * D[2][9] + F[7][10] * D[2][10] + F[7][11] * D[2][11] + F[7][12] * D[2][12]) * T + D[2][7]; - P[2][8] = P[8][2] = (F[8][6] * D[5][6] + F[8][7] * D[5][7] + F[8][9] * D[5][9] + F[8][10] * D[5][10] + F[8][11] * D[5][11] + F[8][12] * D[5][12]) * Tsq + (D[5][8] + F[8][6] * D[2][6] + F[8][7] * D[2][7] + F[8][9] * D[2][9] + F[8][10] * D[2][10] + F[8][11] * D[2][11] + F[8][12] * D[2][12]) * T + D[2][8]; - P[2][9] = P[9][2] = (F[9][6] * D[5][6] + F[9][7] * D[5][7] + F[9][8] * D[5][8] + F[9][10] * D[5][10] + F[9][11] * D[5][11] + F[9][12] * D[5][12]) * Tsq + (D[5][9] + F[9][6] * D[2][6] + F[9][7] * D[2][7] + F[9][8] * D[2][8] + F[9][10] * D[2][10] + F[9][11] * D[2][11] + F[9][12] * D[2][12]) * T + D[2][9]; - P[2][10] = P[10][2] = D[5][10] * T + D[2][10]; - P[2][11] = P[11][2] = D[5][11] * T + D[2][11]; - P[2][12] = P[12][2] = D[5][12] * T + D[2][12]; - P[2][13] = P[13][2] = D[5][13] * T + D[2][13]; - P[3][3] = (Q[3] * G[3][3] * G[3][3] + Q[4] * G[3][4] * G[3][4] + Q[5] * G[3][5] * G[3][5] + F[3][6] * (F[3][6] * D[6][6] + F[3][7] * D[6][7] + F[3][8] * D[6][8] + F[3][9] * D[6][9] + F[3][13] * D[6][13]) + F[3][7] * (F[3][6] * D[6][7] + F[3][7] * D[7][7] + F[3][8] * D[7][8] + F[3][9] * D[7][9] + F[3][13] * D[7][13]) + F[3][8] * (F[3][6] * D[6][8] + F[3][7] * D[7][8] + F[3][8] * D[8][8] + F[3][9] * D[8][9] + F[3][13] * D[8][13]) + F[3][9] * (F[3][6] * D[6][9] + F[3][7] * D[7][9] + F[3][8] * D[8][9] + F[3][9] * D[9][9] + F[3][13] * D[9][13]) + F[3][13] * (F[3][6] * D[6][13] + F[3][7] * D[7][13] + F[3][8] * D[8][13] + F[3][9] * D[9][13] + F[3][13] * D[13][13])) * Tsq + (2 * F[3][6] * D[3][6] + 2 * F[3][7] * D[3][7] + 2 * F[3][8] * D[3][8] + 2 * F[3][9] * D[3][9] + 2 * F[3][13] * D[3][13]) * T + D[3][3]; - P[3][4] = P[4][3] = (F[4][6] * (F[3][6] * D[6][6] + F[3][7] * D[6][7] + F[3][8] * D[6][8] + F[3][9] * D[6][9] + F[3][13] * D[6][13]) + F[4][7] * (F[3][6] * D[6][7] + F[3][7] * D[7][7] + F[3][8] * D[7][8] + F[3][9] * D[7][9] + F[3][13] * D[7][13]) + F[4][8] * (F[3][6] * D[6][8] + F[3][7] * D[7][8] + F[3][8] * D[8][8] + F[3][9] * D[8][9] + F[3][13] * D[8][13]) + F[4][9] * (F[3][6] * D[6][9] + F[3][7] * D[7][9] + F[3][8] * D[8][9] + F[3][9] * D[9][9] + F[3][13] * D[9][13]) + F[4][13] * (F[3][6] * D[6][13] + F[3][7] * D[7][13] + F[3][8] * D[8][13] + F[3][9] * D[9][13] + F[3][13] * D[13][13]) + G[3][3] * G[4][3] * Q[3] + G[3][4] * G[4][4] * Q[4] + G[3][5] * G[4][5] * Q[5]) * Tsq + (F[3][6] * D[4][6] + F[4][6] * D[3][6] + F[3][7] * D[4][7] + F[4][7] * D[3][7] + F[3][8] * D[4][8] + F[4][8] * D[3][8] + F[3][9] * D[4][9] + F[4][9] * D[3][9] + F[3][13] * D[4][13] + F[4][13] * D[3][13]) * T + D[3][4]; - P[3][5] = P[5][3] = (F[5][6] * (F[3][6] * D[6][6] + F[3][7] * D[6][7] + F[3][8] * D[6][8] + F[3][9] * D[6][9] + F[3][13] * D[6][13]) + F[5][7] * (F[3][6] * D[6][7] + F[3][7] * D[7][7] + F[3][8] * D[7][8] + F[3][9] * D[7][9] + F[3][13] * D[7][13]) + F[5][8] * (F[3][6] * D[6][8] + F[3][7] * D[7][8] + F[3][8] * D[8][8] + F[3][9] * D[8][9] + F[3][13] * D[8][13]) + F[5][9] * (F[3][6] * D[6][9] + F[3][7] * D[7][9] + F[3][8] * D[8][9] + F[3][9] * D[9][9] + F[3][13] * D[9][13]) + F[5][13] * (F[3][6] * D[6][13] + F[3][7] * D[7][13] + F[3][8] * D[8][13] + F[3][9] * D[9][13] + F[3][13] * D[13][13]) + G[3][3] * G[5][3] * Q[3] + G[3][4] * G[5][4] * Q[4] + G[3][5] * G[5][5] * Q[5]) * Tsq + (F[3][6] * D[5][6] + F[5][6] * D[3][6] + F[3][7] * D[5][7] + F[5][7] * D[3][7] + F[3][8] * D[5][8] + F[5][8] * D[3][8] + F[3][9] * D[5][9] + F[5][9] * D[3][9] + F[3][13] * D[5][13] + F[5][13] * D[3][13]) * T + D[3][5]; - P[3][6] = P[6][3] = (F[6][7] * (F[3][6] * D[6][7] + F[3][7] * D[7][7] + F[3][8] * D[7][8] + F[3][9] * D[7][9] + F[3][13] * D[7][13]) + F[6][8] * (F[3][6] * D[6][8] + F[3][7] * D[7][8] + F[3][8] * D[8][8] + F[3][9] * D[8][9] + F[3][13] * D[8][13]) + F[6][9] * (F[3][6] * D[6][9] + F[3][7] * D[7][9] + F[3][8] * D[8][9] + F[3][9] * D[9][9] + F[3][13] * D[9][13]) + F[6][10] * (F[3][6] * D[6][10] + F[3][7] * D[7][10] + F[3][8] * D[8][10] + F[3][9] * D[9][10] + F[3][13] * D[10][13]) + F[6][11] * (F[3][6] * D[6][11] + F[3][7] * D[7][11] + F[3][8] * D[8][11] + F[3][9] * D[9][11] + F[3][13] * D[11][13]) + F[6][12] * (F[3][6] * D[6][12] + F[3][7] * D[7][12] + F[3][8] * D[8][12] + F[3][9] * D[9][12] + F[3][13] * D[12][13])) * Tsq + (F[3][6] * D[6][6] + F[3][7] * D[6][7] + F[6][7] * D[3][7] + F[3][8] * D[6][8] + F[6][8] * D[3][8] + F[3][9] * D[6][9] + F[6][9] * D[3][9] + F[6][10] * D[3][10] + F[6][11] * D[3][11] + F[6][12] * D[3][12] + F[3][13] * D[6][13]) * T + D[3][6]; - P[3][7] = P[7][3] = (F[7][6] * (F[3][6] * D[6][6] + F[3][7] * D[6][7] + F[3][8] * D[6][8] + F[3][9] * D[6][9] + F[3][13] * D[6][13]) + F[7][8] * (F[3][6] * D[6][8] + F[3][7] * D[7][8] + F[3][8] * D[8][8] + F[3][9] * D[8][9] + F[3][13] * D[8][13]) + F[7][9] * (F[3][6] * D[6][9] + F[3][7] * D[7][9] + F[3][8] * D[8][9] + F[3][9] * D[9][9] + F[3][13] * D[9][13]) + F[7][10] * (F[3][6] * D[6][10] + F[3][7] * D[7][10] + F[3][8] * D[8][10] + F[3][9] * D[9][10] + F[3][13] * D[10][13]) + F[7][11] * (F[3][6] * D[6][11] + F[3][7] * D[7][11] + F[3][8] * D[8][11] + F[3][9] * D[9][11] + F[3][13] * D[11][13]) + F[7][12] * (F[3][6] * D[6][12] + F[3][7] * D[7][12] + F[3][8] * D[8][12] + F[3][9] * D[9][12] + F[3][13] * D[12][13])) * Tsq + (F[3][6] * D[6][7] + F[7][6] * D[3][6] + F[3][7] * D[7][7] + F[3][8] * D[7][8] + F[7][8] * D[3][8] + F[3][9] * D[7][9] + F[7][9] * D[3][9] + F[7][10] * D[3][10] + F[7][11] * D[3][11] + F[7][12] * D[3][12] + F[3][13] * D[7][13]) * T + D[3][7]; - P[3][8] = P[8][3] = (F[8][6] * (F[3][6] * D[6][6] + F[3][7] * D[6][7] + F[3][8] * D[6][8] + F[3][9] * D[6][9] + F[3][13] * D[6][13]) + F[8][7] * (F[3][6] * D[6][7] + F[3][7] * D[7][7] + F[3][8] * D[7][8] + F[3][9] * D[7][9] + F[3][13] * D[7][13]) + F[8][9] * (F[3][6] * D[6][9] + F[3][7] * D[7][9] + F[3][8] * D[8][9] + F[3][9] * D[9][9] + F[3][13] * D[9][13]) + F[8][10] * (F[3][6] * D[6][10] + F[3][7] * D[7][10] + F[3][8] * D[8][10] + F[3][9] * D[9][10] + F[3][13] * D[10][13]) + F[8][11] * (F[3][6] * D[6][11] + F[3][7] * D[7][11] + F[3][8] * D[8][11] + F[3][9] * D[9][11] + F[3][13] * D[11][13]) + F[8][12] * (F[3][6] * D[6][12] + F[3][7] * D[7][12] + F[3][8] * D[8][12] + F[3][9] * D[9][12] + F[3][13] * D[12][13])) * Tsq + (F[3][6] * D[6][8] + F[3][7] * D[7][8] + F[8][6] * D[3][6] + F[8][7] * D[3][7] + F[3][8] * D[8][8] + F[3][9] * D[8][9] + F[8][9] * D[3][9] + F[8][10] * D[3][10] + F[8][11] * D[3][11] + F[8][12] * D[3][12] + F[3][13] * D[8][13]) * T + D[3][8]; - P[3][9] = P[9][3] = (F[9][6] * (F[3][6] * D[6][6] + F[3][7] * D[6][7] + F[3][8] * D[6][8] + F[3][9] * D[6][9] + F[3][13] * D[6][13]) + F[9][7] * (F[3][6] * D[6][7] + F[3][7] * D[7][7] + F[3][8] * D[7][8] + F[3][9] * D[7][9] + F[3][13] * D[7][13]) + F[9][8] * (F[3][6] * D[6][8] + F[3][7] * D[7][8] + F[3][8] * D[8][8] + F[3][9] * D[8][9] + F[3][13] * D[8][13]) + F[9][10] * (F[3][6] * D[6][10] + F[3][7] * D[7][10] + F[3][8] * D[8][10] + F[3][9] * D[9][10] + F[3][13] * D[10][13]) + F[9][11] * (F[3][6] * D[6][11] + F[3][7] * D[7][11] + F[3][8] * D[8][11] + F[3][9] * D[9][11] + F[3][13] * D[11][13]) + F[9][12] * (F[3][6] * D[6][12] + F[3][7] * D[7][12] + F[3][8] * D[8][12] + F[3][9] * D[9][12] + F[3][13] * D[12][13])) * Tsq + (F[9][6] * D[3][6] + F[9][7] * D[3][7] + F[9][8] * D[3][8] + F[3][6] * D[6][9] + F[3][7] * D[7][9] + F[3][8] * D[8][9] + F[3][9] * D[9][9] + F[9][10] * D[3][10] + F[9][11] * D[3][11] + F[9][12] * D[3][12] + F[3][13] * D[9][13]) * T + D[3][9]; - P[3][10] = P[10][3] = (F[3][6] * D[6][10] + F[3][7] * D[7][10] + F[3][8] * D[8][10] + F[3][9] * D[9][10] + F[3][13] * D[10][13]) * T + D[3][10]; - P[3][11] = P[11][3] = (F[3][6] * D[6][11] + F[3][7] * D[7][11] + F[3][8] * D[8][11] + F[3][9] * D[9][11] + F[3][13] * D[11][13]) * T + D[3][11]; - P[3][12] = P[12][3] = (F[3][6] * D[6][12] + F[3][7] * D[7][12] + F[3][8] * D[8][12] + F[3][9] * D[9][12] + F[3][13] * D[12][13]) * T + D[3][12]; - P[3][13] = P[13][3] = (F[3][6] * D[6][13] + F[3][7] * D[7][13] + F[3][8] * D[8][13] + F[3][9] * D[9][13] + F[3][13] * D[13][13]) * T + D[3][13]; - P[4][4] = (Q[3] * G[4][3] * G[4][3] + Q[4] * G[4][4] * G[4][4] + Q[5] * G[4][5] * G[4][5] + F[4][6] * (F[4][6] * D[6][6] + F[4][7] * D[6][7] + F[4][8] * D[6][8] + F[4][9] * D[6][9] + F[4][13] * D[6][13]) + F[4][7] * (F[4][6] * D[6][7] + F[4][7] * D[7][7] + F[4][8] * D[7][8] + F[4][9] * D[7][9] + F[4][13] * D[7][13]) + F[4][8] * (F[4][6] * D[6][8] + F[4][7] * D[7][8] + F[4][8] * D[8][8] + F[4][9] * D[8][9] + F[4][13] * D[8][13]) + F[4][9] * (F[4][6] * D[6][9] + F[4][7] * D[7][9] + F[4][8] * D[8][9] + F[4][9] * D[9][9] + F[4][13] * D[9][13]) + F[4][13] * (F[4][6] * D[6][13] + F[4][7] * D[7][13] + F[4][8] * D[8][13] + F[4][9] * D[9][13] + F[4][13] * D[13][13])) * Tsq + (2 * F[4][6] * D[4][6] + 2 * F[4][7] * D[4][7] + 2 * F[4][8] * D[4][8] + 2 * F[4][9] * D[4][9] + 2 * F[4][13] * D[4][13]) * T + D[4][4]; - P[4][5] = P[5][4] = (F[5][6] * (F[4][6] * D[6][6] + F[4][7] * D[6][7] + F[4][8] * D[6][8] + F[4][9] * D[6][9] + F[4][13] * D[6][13]) + F[5][7] * (F[4][6] * D[6][7] + F[4][7] * D[7][7] + F[4][8] * D[7][8] + F[4][9] * D[7][9] + F[4][13] * D[7][13]) + F[5][8] * (F[4][6] * D[6][8] + F[4][7] * D[7][8] + F[4][8] * D[8][8] + F[4][9] * D[8][9] + F[4][13] * D[8][13]) + F[5][9] * (F[4][6] * D[6][9] + F[4][7] * D[7][9] + F[4][8] * D[8][9] + F[4][9] * D[9][9] + F[4][13] * D[9][13]) + F[5][13] * (F[4][6] * D[6][13] + F[4][7] * D[7][13] + F[4][8] * D[8][13] + F[4][9] * D[9][13] + F[4][13] * D[13][13]) + G[4][3] * G[5][3] * Q[3] + G[4][4] * G[5][4] * Q[4] + G[4][5] * G[5][5] * Q[5]) * Tsq + (F[4][6] * D[5][6] + F[5][6] * D[4][6] + F[4][7] * D[5][7] + F[5][7] * D[4][7] + F[4][8] * D[5][8] + F[5][8] * D[4][8] + F[4][9] * D[5][9] + F[5][9] * D[4][9] + F[4][13] * D[5][13] + F[5][13] * D[4][13]) * T + D[4][5]; - P[4][6] = P[6][4] = (F[6][7] * (F[4][6] * D[6][7] + F[4][7] * D[7][7] + F[4][8] * D[7][8] + F[4][9] * D[7][9] + F[4][13] * D[7][13]) + F[6][8] * (F[4][6] * D[6][8] + F[4][7] * D[7][8] + F[4][8] * D[8][8] + F[4][9] * D[8][9] + F[4][13] * D[8][13]) + F[6][9] * (F[4][6] * D[6][9] + F[4][7] * D[7][9] + F[4][8] * D[8][9] + F[4][9] * D[9][9] + F[4][13] * D[9][13]) + F[6][10] * (F[4][6] * D[6][10] + F[4][7] * D[7][10] + F[4][8] * D[8][10] + F[4][9] * D[9][10] + F[4][13] * D[10][13]) + F[6][11] * (F[4][6] * D[6][11] + F[4][7] * D[7][11] + F[4][8] * D[8][11] + F[4][9] * D[9][11] + F[4][13] * D[11][13]) + F[6][12] * (F[4][6] * D[6][12] + F[4][7] * D[7][12] + F[4][8] * D[8][12] + F[4][9] * D[9][12] + F[4][13] * D[12][13])) * Tsq + (F[4][6] * D[6][6] + F[4][7] * D[6][7] + F[6][7] * D[4][7] + F[4][8] * D[6][8] + F[6][8] * D[4][8] + F[4][9] * D[6][9] + F[6][9] * D[4][9] + F[6][10] * D[4][10] + F[6][11] * D[4][11] + F[6][12] * D[4][12] + F[4][13] * D[6][13]) * T + D[4][6]; - P[4][7] = P[7][4] = (F[7][6] * (F[4][6] * D[6][6] + F[4][7] * D[6][7] + F[4][8] * D[6][8] + F[4][9] * D[6][9] + F[4][13] * D[6][13]) + F[7][8] * (F[4][6] * D[6][8] + F[4][7] * D[7][8] + F[4][8] * D[8][8] + F[4][9] * D[8][9] + F[4][13] * D[8][13]) + F[7][9] * (F[4][6] * D[6][9] + F[4][7] * D[7][9] + F[4][8] * D[8][9] + F[4][9] * D[9][9] + F[4][13] * D[9][13]) + F[7][10] * (F[4][6] * D[6][10] + F[4][7] * D[7][10] + F[4][8] * D[8][10] + F[4][9] * D[9][10] + F[4][13] * D[10][13]) + F[7][11] * (F[4][6] * D[6][11] + F[4][7] * D[7][11] + F[4][8] * D[8][11] + F[4][9] * D[9][11] + F[4][13] * D[11][13]) + F[7][12] * (F[4][6] * D[6][12] + F[4][7] * D[7][12] + F[4][8] * D[8][12] + F[4][9] * D[9][12] + F[4][13] * D[12][13])) * Tsq + (F[4][6] * D[6][7] + F[7][6] * D[4][6] + F[4][7] * D[7][7] + F[4][8] * D[7][8] + F[7][8] * D[4][8] + F[4][9] * D[7][9] + F[7][9] * D[4][9] + F[7][10] * D[4][10] + F[7][11] * D[4][11] + F[7][12] * D[4][12] + F[4][13] * D[7][13]) * T + D[4][7]; - P[4][8] = P[8][4] = (F[8][6] * (F[4][6] * D[6][6] + F[4][7] * D[6][7] + F[4][8] * D[6][8] + F[4][9] * D[6][9] + F[4][13] * D[6][13]) + F[8][7] * (F[4][6] * D[6][7] + F[4][7] * D[7][7] + F[4][8] * D[7][8] + F[4][9] * D[7][9] + F[4][13] * D[7][13]) + F[8][9] * (F[4][6] * D[6][9] + F[4][7] * D[7][9] + F[4][8] * D[8][9] + F[4][9] * D[9][9] + F[4][13] * D[9][13]) + F[8][10] * (F[4][6] * D[6][10] + F[4][7] * D[7][10] + F[4][8] * D[8][10] + F[4][9] * D[9][10] + F[4][13] * D[10][13]) + F[8][11] * (F[4][6] * D[6][11] + F[4][7] * D[7][11] + F[4][8] * D[8][11] + F[4][9] * D[9][11] + F[4][13] * D[11][13]) + F[8][12] * (F[4][6] * D[6][12] + F[4][7] * D[7][12] + F[4][8] * D[8][12] + F[4][9] * D[9][12] + F[4][13] * D[12][13])) * Tsq + (F[4][6] * D[6][8] + F[4][7] * D[7][8] + F[8][6] * D[4][6] + F[8][7] * D[4][7] + F[4][8] * D[8][8] + F[4][9] * D[8][9] + F[8][9] * D[4][9] + F[8][10] * D[4][10] + F[8][11] * D[4][11] + F[8][12] * D[4][12] + F[4][13] * D[8][13]) * T + D[4][8]; - P[4][9] = P[9][4] = (F[9][6] * (F[4][6] * D[6][6] + F[4][7] * D[6][7] + F[4][8] * D[6][8] + F[4][9] * D[6][9] + F[4][13] * D[6][13]) + F[9][7] * (F[4][6] * D[6][7] + F[4][7] * D[7][7] + F[4][8] * D[7][8] + F[4][9] * D[7][9] + F[4][13] * D[7][13]) + F[9][8] * (F[4][6] * D[6][8] + F[4][7] * D[7][8] + F[4][8] * D[8][8] + F[4][9] * D[8][9] + F[4][13] * D[8][13]) + F[9][10] * (F[4][6] * D[6][10] + F[4][7] * D[7][10] + F[4][8] * D[8][10] + F[4][9] * D[9][10] + F[4][13] * D[10][13]) + F[9][11] * (F[4][6] * D[6][11] + F[4][7] * D[7][11] + F[4][8] * D[8][11] + F[4][9] * D[9][11] + F[4][13] * D[11][13]) + F[9][12] * (F[4][6] * D[6][12] + F[4][7] * D[7][12] + F[4][8] * D[8][12] + F[4][9] * D[9][12] + F[4][13] * D[12][13])) * Tsq + (F[9][6] * D[4][6] + F[9][7] * D[4][7] + F[9][8] * D[4][8] + F[4][6] * D[6][9] + F[4][7] * D[7][9] + F[4][8] * D[8][9] + F[4][9] * D[9][9] + F[9][10] * D[4][10] + F[9][11] * D[4][11] + F[9][12] * D[4][12] + F[4][13] * D[9][13]) * T + D[4][9]; - P[4][10] = P[10][4] = (F[4][6] * D[6][10] + F[4][7] * D[7][10] + F[4][8] * D[8][10] + F[4][9] * D[9][10] + F[4][13] * D[10][13]) * T + D[4][10]; - P[4][11] = P[11][4] = (F[4][6] * D[6][11] + F[4][7] * D[7][11] + F[4][8] * D[8][11] + F[4][9] * D[9][11] + F[4][13] * D[11][13]) * T + D[4][11]; - P[4][12] = P[12][4] = (F[4][6] * D[6][12] + F[4][7] * D[7][12] + F[4][8] * D[8][12] + F[4][9] * D[9][12] + F[4][13] * D[12][13]) * T + D[4][12]; - P[4][13] = P[13][4] = (F[4][6] * D[6][13] + F[4][7] * D[7][13] + F[4][8] * D[8][13] + F[4][9] * D[9][13] + F[4][13] * D[13][13]) * T + D[4][13]; - P[5][5] = (Q[3] * G[5][3] * G[5][3] + Q[4] * G[5][4] * G[5][4] + Q[5] * G[5][5] * G[5][5] + F[5][6] * (F[5][6] * D[6][6] + F[5][7] * D[6][7] + F[5][8] * D[6][8] + F[5][9] * D[6][9] + F[5][13] * D[6][13]) + F[5][7] * (F[5][6] * D[6][7] + F[5][7] * D[7][7] + F[5][8] * D[7][8] + F[5][9] * D[7][9] + F[5][13] * D[7][13]) + F[5][8] * (F[5][6] * D[6][8] + F[5][7] * D[7][8] + F[5][8] * D[8][8] + F[5][9] * D[8][9] + F[5][13] * D[8][13]) + F[5][9] * (F[5][6] * D[6][9] + F[5][7] * D[7][9] + F[5][8] * D[8][9] + F[5][9] * D[9][9] + F[5][13] * D[9][13]) + F[5][13] * (F[5][6] * D[6][13] + F[5][7] * D[7][13] + F[5][8] * D[8][13] + F[5][9] * D[9][13] + F[5][13] * D[13][13])) * Tsq + (2 * F[5][6] * D[5][6] + 2 * F[5][7] * D[5][7] + 2 * F[5][8] * D[5][8] + 2 * F[5][9] * D[5][9] + 2 * F[5][13] * D[5][13]) * T + D[5][5]; - P[5][6] = P[6][5] = (F[6][7] * (F[5][6] * D[6][7] + F[5][7] * D[7][7] + F[5][8] * D[7][8] + F[5][9] * D[7][9] + F[5][13] * D[7][13]) + F[6][8] * (F[5][6] * D[6][8] + F[5][7] * D[7][8] + F[5][8] * D[8][8] + F[5][9] * D[8][9] + F[5][13] * D[8][13]) + F[6][9] * (F[5][6] * D[6][9] + F[5][7] * D[7][9] + F[5][8] * D[8][9] + F[5][9] * D[9][9] + F[5][13] * D[9][13]) + F[6][10] * (F[5][6] * D[6][10] + F[5][7] * D[7][10] + F[5][8] * D[8][10] + F[5][9] * D[9][10] + F[5][13] * D[10][13]) + F[6][11] * (F[5][6] * D[6][11] + F[5][7] * D[7][11] + F[5][8] * D[8][11] + F[5][9] * D[9][11] + F[5][13] * D[11][13]) + F[6][12] * (F[5][6] * D[6][12] + F[5][7] * D[7][12] + F[5][8] * D[8][12] + F[5][9] * D[9][12] + F[5][13] * D[12][13])) * Tsq + (F[5][6] * D[6][6] + F[5][7] * D[6][7] + F[6][7] * D[5][7] + F[5][8] * D[6][8] + F[6][8] * D[5][8] + F[5][9] * D[6][9] + F[6][9] * D[5][9] + F[6][10] * D[5][10] + F[6][11] * D[5][11] + F[6][12] * D[5][12] + F[5][13] * D[6][13]) * T + D[5][6]; - P[5][7] = P[7][5] = (F[7][6] * (F[5][6] * D[6][6] + F[5][7] * D[6][7] + F[5][8] * D[6][8] + F[5][9] * D[6][9] + F[5][13] * D[6][13]) + F[7][8] * (F[5][6] * D[6][8] + F[5][7] * D[7][8] + F[5][8] * D[8][8] + F[5][9] * D[8][9] + F[5][13] * D[8][13]) + F[7][9] * (F[5][6] * D[6][9] + F[5][7] * D[7][9] + F[5][8] * D[8][9] + F[5][9] * D[9][9] + F[5][13] * D[9][13]) + F[7][10] * (F[5][6] * D[6][10] + F[5][7] * D[7][10] + F[5][8] * D[8][10] + F[5][9] * D[9][10] + F[5][13] * D[10][13]) + F[7][11] * (F[5][6] * D[6][11] + F[5][7] * D[7][11] + F[5][8] * D[8][11] + F[5][9] * D[9][11] + F[5][13] * D[11][13]) + F[7][12] * (F[5][6] * D[6][12] + F[5][7] * D[7][12] + F[5][8] * D[8][12] + F[5][9] * D[9][12] + F[5][13] * D[12][13])) * Tsq + (F[5][6] * D[6][7] + F[7][6] * D[5][6] + F[5][7] * D[7][7] + F[5][8] * D[7][8] + F[7][8] * D[5][8] + F[5][9] * D[7][9] + F[7][9] * D[5][9] + F[7][10] * D[5][10] + F[7][11] * D[5][11] + F[7][12] * D[5][12] + F[5][13] * D[7][13]) * T + D[5][7]; - P[5][8] = P[8][5] = (F[8][6] * (F[5][6] * D[6][6] + F[5][7] * D[6][7] + F[5][8] * D[6][8] + F[5][9] * D[6][9] + F[5][13] * D[6][13]) + F[8][7] * (F[5][6] * D[6][7] + F[5][7] * D[7][7] + F[5][8] * D[7][8] + F[5][9] * D[7][9] + F[5][13] * D[7][13]) + F[8][9] * (F[5][6] * D[6][9] + F[5][7] * D[7][9] + F[5][8] * D[8][9] + F[5][9] * D[9][9] + F[5][13] * D[9][13]) + F[8][10] * (F[5][6] * D[6][10] + F[5][7] * D[7][10] + F[5][8] * D[8][10] + F[5][9] * D[9][10] + F[5][13] * D[10][13]) + F[8][11] * (F[5][6] * D[6][11] + F[5][7] * D[7][11] + F[5][8] * D[8][11] + F[5][9] * D[9][11] + F[5][13] * D[11][13]) + F[8][12] * (F[5][6] * D[6][12] + F[5][7] * D[7][12] + F[5][8] * D[8][12] + F[5][9] * D[9][12] + F[5][13] * D[12][13])) * Tsq + (F[5][6] * D[6][8] + F[5][7] * D[7][8] + F[8][6] * D[5][6] + F[8][7] * D[5][7] + F[5][8] * D[8][8] + F[5][9] * D[8][9] + F[8][9] * D[5][9] + F[8][10] * D[5][10] + F[8][11] * D[5][11] + F[8][12] * D[5][12] + F[5][13] * D[8][13]) * T + D[5][8]; - P[5][9] = P[9][5] = (F[9][6] * (F[5][6] * D[6][6] + F[5][7] * D[6][7] + F[5][8] * D[6][8] + F[5][9] * D[6][9] + F[5][13] * D[6][13]) + F[9][7] * (F[5][6] * D[6][7] + F[5][7] * D[7][7] + F[5][8] * D[7][8] + F[5][9] * D[7][9] + F[5][13] * D[7][13]) + F[9][8] * (F[5][6] * D[6][8] + F[5][7] * D[7][8] + F[5][8] * D[8][8] + F[5][9] * D[8][9] + F[5][13] * D[8][13]) + F[9][10] * (F[5][6] * D[6][10] + F[5][7] * D[7][10] + F[5][8] * D[8][10] + F[5][9] * D[9][10] + F[5][13] * D[10][13]) + F[9][11] * (F[5][6] * D[6][11] + F[5][7] * D[7][11] + F[5][8] * D[8][11] + F[5][9] * D[9][11] + F[5][13] * D[11][13]) + F[9][12] * (F[5][6] * D[6][12] + F[5][7] * D[7][12] + F[5][8] * D[8][12] + F[5][9] * D[9][12] + F[5][13] * D[12][13])) * Tsq + (F[9][6] * D[5][6] + F[9][7] * D[5][7] + F[9][8] * D[5][8] + F[5][6] * D[6][9] + F[5][7] * D[7][9] + F[5][8] * D[8][9] + F[5][9] * D[9][9] + F[9][10] * D[5][10] + F[9][11] * D[5][11] + F[9][12] * D[5][12] + F[5][13] * D[9][13]) * T + D[5][9]; - P[5][10] = P[10][5] = (F[5][6] * D[6][10] + F[5][7] * D[7][10] + F[5][8] * D[8][10] + F[5][9] * D[9][10] + F[5][13] * D[10][13]) * T + D[5][10]; - P[5][11] = P[11][5] = (F[5][6] * D[6][11] + F[5][7] * D[7][11] + F[5][8] * D[8][11] + F[5][9] * D[9][11] + F[5][13] * D[11][13]) * T + D[5][11]; - P[5][12] = P[12][5] = (F[5][6] * D[6][12] + F[5][7] * D[7][12] + F[5][8] * D[8][12] + F[5][9] * D[9][12] + F[5][13] * D[12][13]) * T + D[5][12]; - P[5][13] = P[13][5] = (F[5][6] * D[6][13] + F[5][7] * D[7][13] + F[5][8] * D[8][13] + F[5][9] * D[9][13] + F[5][13] * D[13][13]) * T + D[5][13]; - P[6][6] = (Q[0] * G[6][0] * G[6][0] + Q[1] * G[6][1] * G[6][1] + Q[2] * G[6][2] * G[6][2] + F[6][7] * (F[6][7] * D[7][7] + F[6][8] * D[7][8] + F[6][9] * D[7][9] + F[6][10] * D[7][10] + F[6][11] * D[7][11] + F[6][12] * D[7][12]) + F[6][8] * (F[6][7] * D[7][8] + F[6][8] * D[8][8] + F[6][9] * D[8][9] + F[6][10] * D[8][10] + F[6][11] * D[8][11] + F[6][12] * D[8][12]) + F[6][9] * (F[6][7] * D[7][9] + F[6][8] * D[8][9] + F[6][9] * D[9][9] + F[6][10] * D[9][10] + F[6][11] * D[9][11] + F[6][12] * D[9][12]) + F[6][10] * (F[6][7] * D[7][10] + F[6][8] * D[8][10] + F[6][9] * D[9][10] + F[6][10] * D[10][10] + F[6][11] * D[10][11] + F[6][12] * D[10][12]) + F[6][11] * (F[6][7] * D[7][11] + F[6][8] * D[8][11] + F[6][9] * D[9][11] + F[6][10] * D[10][11] + F[6][11] * D[11][11] + F[6][12] * D[11][12]) + F[6][12] * (F[6][7] * D[7][12] + F[6][8] * D[8][12] + F[6][9] * D[9][12] + F[6][10] * D[10][12] + F[6][11] * D[11][12] + F[6][12] * D[12][12])) * Tsq + (2 * F[6][7] * D[6][7] + 2 * F[6][8] * D[6][8] + 2 * F[6][9] * D[6][9] + 2 * F[6][10] * D[6][10] + 2 * F[6][11] * D[6][11] + 2 * F[6][12] * D[6][12]) * T + D[6][6]; - P[6][7] = P[7][6] = (F[7][6] * (F[6][7] * D[6][7] + F[6][8] * D[6][8] + F[6][9] * D[6][9] + F[6][10] * D[6][10] + F[6][11] * D[6][11] + F[6][12] * D[6][12]) + F[7][8] * (F[6][7] * D[7][8] + F[6][8] * D[8][8] + F[6][9] * D[8][9] + F[6][10] * D[8][10] + F[6][11] * D[8][11] + F[6][12] * D[8][12]) + F[7][9] * (F[6][7] * D[7][9] + F[6][8] * D[8][9] + F[6][9] * D[9][9] + F[6][10] * D[9][10] + F[6][11] * D[9][11] + F[6][12] * D[9][12]) + F[7][10] * (F[6][7] * D[7][10] + F[6][8] * D[8][10] + F[6][9] * D[9][10] + F[6][10] * D[10][10] + F[6][11] * D[10][11] + F[6][12] * D[10][12]) + F[7][11] * (F[6][7] * D[7][11] + F[6][8] * D[8][11] + F[6][9] * D[9][11] + F[6][10] * D[10][11] + F[6][11] * D[11][11] + F[6][12] * D[11][12]) + F[7][12] * (F[6][7] * D[7][12] + F[6][8] * D[8][12] + F[6][9] * D[9][12] + F[6][10] * D[10][12] + F[6][11] * D[11][12] + F[6][12] * D[12][12]) + G[6][0] * G[7][0] * Q[0] + G[6][1] * G[7][1] * Q[1] + G[6][2] * G[7][2] * Q[2]) * Tsq + (F[7][6] * D[6][6] + F[6][7] * D[7][7] + F[6][8] * D[7][8] + F[7][8] * D[6][8] + F[6][9] * D[7][9] + F[7][9] * D[6][9] + F[6][10] * D[7][10] + F[7][10] * D[6][10] + F[6][11] * D[7][11] + F[7][11] * D[6][11] + F[6][12] * D[7][12] + F[7][12] * D[6][12]) * T + D[6][7]; - P[6][8] = P[8][6] = (F[8][6] * (F[6][7] * D[6][7] + F[6][8] * D[6][8] + F[6][9] * D[6][9] + F[6][10] * D[6][10] + F[6][11] * D[6][11] + F[6][12] * D[6][12]) + F[8][7] * (F[6][7] * D[7][7] + F[6][8] * D[7][8] + F[6][9] * D[7][9] + F[6][10] * D[7][10] + F[6][11] * D[7][11] + F[6][12] * D[7][12]) + F[8][9] * (F[6][7] * D[7][9] + F[6][8] * D[8][9] + F[6][9] * D[9][9] + F[6][10] * D[9][10] + F[6][11] * D[9][11] + F[6][12] * D[9][12]) + F[8][10] * (F[6][7] * D[7][10] + F[6][8] * D[8][10] + F[6][9] * D[9][10] + F[6][10] * D[10][10] + F[6][11] * D[10][11] + F[6][12] * D[10][12]) + F[8][11] * (F[6][7] * D[7][11] + F[6][8] * D[8][11] + F[6][9] * D[9][11] + F[6][10] * D[10][11] + F[6][11] * D[11][11] + F[6][12] * D[11][12]) + F[8][12] * (F[6][7] * D[7][12] + F[6][8] * D[8][12] + F[6][9] * D[9][12] + F[6][10] * D[10][12] + F[6][11] * D[11][12] + F[6][12] * D[12][12]) + G[6][0] * G[8][0] * Q[0] + G[6][1] * G[8][1] * Q[1] + G[6][2] * G[8][2] * Q[2]) * Tsq + (F[6][7] * D[7][8] + F[8][6] * D[6][6] + F[8][7] * D[6][7] + F[6][8] * D[8][8] + F[6][9] * D[8][9] + F[8][9] * D[6][9] + F[6][10] * D[8][10] + F[8][10] * D[6][10] + F[6][11] * D[8][11] + F[8][11] * D[6][11] + F[6][12] * D[8][12] + F[8][12] * D[6][12]) * T + D[6][8]; - P[6][9] = P[9][6] = (F[9][6] * (F[6][7] * D[6][7] + F[6][8] * D[6][8] + F[6][9] * D[6][9] + F[6][10] * D[6][10] + F[6][11] * D[6][11] + F[6][12] * D[6][12]) + F[9][7] * (F[6][7] * D[7][7] + F[6][8] * D[7][8] + F[6][9] * D[7][9] + F[6][10] * D[7][10] + F[6][11] * D[7][11] + F[6][12] * D[7][12]) + F[9][8] * (F[6][7] * D[7][8] + F[6][8] * D[8][8] + F[6][9] * D[8][9] + F[6][10] * D[8][10] + F[6][11] * D[8][11] + F[6][12] * D[8][12]) + F[9][10] * (F[6][7] * D[7][10] + F[6][8] * D[8][10] + F[6][9] * D[9][10] + F[6][10] * D[10][10] + F[6][11] * D[10][11] + F[6][12] * D[10][12]) + F[9][11] * (F[6][7] * D[7][11] + F[6][8] * D[8][11] + F[6][9] * D[9][11] + F[6][10] * D[10][11] + F[6][11] * D[11][11] + F[6][12] * D[11][12]) + F[9][12] * (F[6][7] * D[7][12] + F[6][8] * D[8][12] + F[6][9] * D[9][12] + F[6][10] * D[10][12] + F[6][11] * D[11][12] + F[6][12] * D[12][12]) + G[6][0] * G[9][0] * Q[0] + G[6][1] * G[9][1] * Q[1] + G[6][2] * G[9][2] * Q[2]) * Tsq + (F[9][6] * D[6][6] + F[9][7] * D[6][7] + F[9][8] * D[6][8] + F[6][7] * D[7][9] + F[6][8] * D[8][9] + F[6][9] * D[9][9] + F[6][10] * D[9][10] + F[9][10] * D[6][10] + F[6][11] * D[9][11] + F[9][11] * D[6][11] + F[6][12] * D[9][12] + F[9][12] * D[6][12]) * T + D[6][9]; - P[6][10] = P[10][6] = (F[6][7] * D[7][10] + F[6][8] * D[8][10] + F[6][9] * D[9][10] + F[6][10] * D[10][10] + F[6][11] * D[10][11] + F[6][12] * D[10][12]) * T + D[6][10]; - P[6][11] = P[11][6] = (F[6][7] * D[7][11] + F[6][8] * D[8][11] + F[6][9] * D[9][11] + F[6][10] * D[10][11] + F[6][11] * D[11][11] + F[6][12] * D[11][12]) * T + D[6][11]; - P[6][12] = P[12][6] = (F[6][7] * D[7][12] + F[6][8] * D[8][12] + F[6][9] * D[9][12] + F[6][10] * D[10][12] + F[6][11] * D[11][12] + F[6][12] * D[12][12]) * T + D[6][12]; - P[6][13] = P[13][6] = (F[6][7] * D[7][13] + F[6][8] * D[8][13] + F[6][9] * D[9][13] + F[6][10] * D[10][13] + F[6][11] * D[11][13] + F[6][12] * D[12][13]) * T + D[6][13]; - P[7][7] = (Q[0] * G[7][0] * G[7][0] + Q[1] * G[7][1] * G[7][1] + Q[2] * G[7][2] * G[7][2] + F[7][6] * (F[7][6] * D[6][6] + F[7][8] * D[6][8] + F[7][9] * D[6][9] + F[7][10] * D[6][10] + F[7][11] * D[6][11] + F[7][12] * D[6][12]) + F[7][8] * (F[7][6] * D[6][8] + F[7][8] * D[8][8] + F[7][9] * D[8][9] + F[7][10] * D[8][10] + F[7][11] * D[8][11] + F[7][12] * D[8][12]) + F[7][9] * (F[7][6] * D[6][9] + F[7][8] * D[8][9] + F[7][9] * D[9][9] + F[7][10] * D[9][10] + F[7][11] * D[9][11] + F[7][12] * D[9][12]) + F[7][10] * (F[7][6] * D[6][10] + F[7][8] * D[8][10] + F[7][9] * D[9][10] + F[7][10] * D[10][10] + F[7][11] * D[10][11] + F[7][12] * D[10][12]) + F[7][11] * (F[7][6] * D[6][11] + F[7][8] * D[8][11] + F[7][9] * D[9][11] + F[7][10] * D[10][11] + F[7][11] * D[11][11] + F[7][12] * D[11][12]) + F[7][12] * (F[7][6] * D[6][12] + F[7][8] * D[8][12] + F[7][9] * D[9][12] + F[7][10] * D[10][12] + F[7][11] * D[11][12] + F[7][12] * D[12][12])) * Tsq + (2 * F[7][6] * D[6][7] + 2 * F[7][8] * D[7][8] + 2 * F[7][9] * D[7][9] + 2 * F[7][10] * D[7][10] + 2 * F[7][11] * D[7][11] + 2 * F[7][12] * D[7][12]) * T + D[7][7]; - P[7][8] = P[8][7] = (F[8][6] * (F[7][6] * D[6][6] + F[7][8] * D[6][8] + F[7][9] * D[6][9] + F[7][10] * D[6][10] + F[7][11] * D[6][11] + F[7][12] * D[6][12]) + F[8][7] * (F[7][6] * D[6][7] + F[7][8] * D[7][8] + F[7][9] * D[7][9] + F[7][10] * D[7][10] + F[7][11] * D[7][11] + F[7][12] * D[7][12]) + F[8][9] * (F[7][6] * D[6][9] + F[7][8] * D[8][9] + F[7][9] * D[9][9] + F[7][10] * D[9][10] + F[7][11] * D[9][11] + F[7][12] * D[9][12]) + F[8][10] * (F[7][6] * D[6][10] + F[7][8] * D[8][10] + F[7][9] * D[9][10] + F[7][10] * D[10][10] + F[7][11] * D[10][11] + F[7][12] * D[10][12]) + F[8][11] * (F[7][6] * D[6][11] + F[7][8] * D[8][11] + F[7][9] * D[9][11] + F[7][10] * D[10][11] + F[7][11] * D[11][11] + F[7][12] * D[11][12]) + F[8][12] * (F[7][6] * D[6][12] + F[7][8] * D[8][12] + F[7][9] * D[9][12] + F[7][10] * D[10][12] + F[7][11] * D[11][12] + F[7][12] * D[12][12]) + G[7][0] * G[8][0] * Q[0] + G[7][1] * G[8][1] * Q[1] + G[7][2] * G[8][2] * Q[2]) * Tsq + (F[7][6] * D[6][8] + F[8][6] * D[6][7] + F[8][7] * D[7][7] + F[7][8] * D[8][8] + F[7][9] * D[8][9] + F[8][9] * D[7][9] + F[7][10] * D[8][10] + F[8][10] * D[7][10] + F[7][11] * D[8][11] + F[8][11] * D[7][11] + F[7][12] * D[8][12] + F[8][12] * D[7][12]) * T + D[7][8]; - P[7][9] = P[9][7] = (F[9][6] * (F[7][6] * D[6][6] + F[7][8] * D[6][8] + F[7][9] * D[6][9] + F[7][10] * D[6][10] + F[7][11] * D[6][11] + F[7][12] * D[6][12]) + F[9][7] * (F[7][6] * D[6][7] + F[7][8] * D[7][8] + F[7][9] * D[7][9] + F[7][10] * D[7][10] + F[7][11] * D[7][11] + F[7][12] * D[7][12]) + F[9][8] * (F[7][6] * D[6][8] + F[7][8] * D[8][8] + F[7][9] * D[8][9] + F[7][10] * D[8][10] + F[7][11] * D[8][11] + F[7][12] * D[8][12]) + F[9][10] * (F[7][6] * D[6][10] + F[7][8] * D[8][10] + F[7][9] * D[9][10] + F[7][10] * D[10][10] + F[7][11] * D[10][11] + F[7][12] * D[10][12]) + F[9][11] * (F[7][6] * D[6][11] + F[7][8] * D[8][11] + F[7][9] * D[9][11] + F[7][10] * D[10][11] + F[7][11] * D[11][11] + F[7][12] * D[11][12]) + F[9][12] * (F[7][6] * D[6][12] + F[7][8] * D[8][12] + F[7][9] * D[9][12] + F[7][10] * D[10][12] + F[7][11] * D[11][12] + F[7][12] * D[12][12]) + G[7][0] * G[9][0] * Q[0] + G[7][1] * G[9][1] * Q[1] + G[7][2] * G[9][2] * Q[2]) * Tsq + (F[9][6] * D[6][7] + F[9][7] * D[7][7] + F[9][8] * D[7][8] + F[7][6] * D[6][9] + F[7][8] * D[8][9] + F[7][9] * D[9][9] + F[7][10] * D[9][10] + F[9][10] * D[7][10] + F[7][11] * D[9][11] + F[9][11] * D[7][11] + F[7][12] * D[9][12] + F[9][12] * D[7][12]) * T + D[7][9]; - P[7][10] = P[10][7] = (F[7][6] * D[6][10] + F[7][8] * D[8][10] + F[7][9] * D[9][10] + F[7][10] * D[10][10] + F[7][11] * D[10][11] + F[7][12] * D[10][12]) * T + D[7][10]; - P[7][11] = P[11][7] = (F[7][6] * D[6][11] + F[7][8] * D[8][11] + F[7][9] * D[9][11] + F[7][10] * D[10][11] + F[7][11] * D[11][11] + F[7][12] * D[11][12]) * T + D[7][11]; - P[7][12] = P[12][7] = (F[7][6] * D[6][12] + F[7][8] * D[8][12] + F[7][9] * D[9][12] + F[7][10] * D[10][12] + F[7][11] * D[11][12] + F[7][12] * D[12][12]) * T + D[7][12]; - P[7][13] = P[13][7] = (F[7][6] * D[6][13] + F[7][8] * D[8][13] + F[7][9] * D[9][13] + F[7][10] * D[10][13] + F[7][11] * D[11][13] + F[7][12] * D[12][13]) * T + D[7][13]; - P[8][8] = (Q[0] * G[8][0] * G[8][0] + Q[1] * G[8][1] * G[8][1] + Q[2] * G[8][2] * G[8][2] + F[8][6] * (F[8][6] * D[6][6] + F[8][7] * D[6][7] + F[8][9] * D[6][9] + F[8][10] * D[6][10] + F[8][11] * D[6][11] + F[8][12] * D[6][12]) + F[8][7] * (F[8][6] * D[6][7] + F[8][7] * D[7][7] + F[8][9] * D[7][9] + F[8][10] * D[7][10] + F[8][11] * D[7][11] + F[8][12] * D[7][12]) + F[8][9] * (F[8][6] * D[6][9] + F[8][7] * D[7][9] + F[8][9] * D[9][9] + F[8][10] * D[9][10] + F[8][11] * D[9][11] + F[8][12] * D[9][12]) + F[8][10] * (F[8][6] * D[6][10] + F[8][7] * D[7][10] + F[8][9] * D[9][10] + F[8][10] * D[10][10] + F[8][11] * D[10][11] + F[8][12] * D[10][12]) + F[8][11] * (F[8][6] * D[6][11] + F[8][7] * D[7][11] + F[8][9] * D[9][11] + F[8][10] * D[10][11] + F[8][11] * D[11][11] + F[8][12] * D[11][12]) + F[8][12] * (F[8][6] * D[6][12] + F[8][7] * D[7][12] + F[8][9] * D[9][12] + F[8][10] * D[10][12] + F[8][11] * D[11][12] + F[8][12] * D[12][12])) * Tsq + (2 * F[8][6] * D[6][8] + 2 * F[8][7] * D[7][8] + 2 * F[8][9] * D[8][9] + 2 * F[8][10] * D[8][10] + 2 * F[8][11] * D[8][11] + 2 * F[8][12] * D[8][12]) * T + D[8][8]; - P[8][9] = P[9][8] = (F[9][6] * (F[8][6] * D[6][6] + F[8][7] * D[6][7] + F[8][9] * D[6][9] + F[8][10] * D[6][10] + F[8][11] * D[6][11] + F[8][12] * D[6][12]) + F[9][7] * (F[8][6] * D[6][7] + F[8][7] * D[7][7] + F[8][9] * D[7][9] + F[8][10] * D[7][10] + F[8][11] * D[7][11] + F[8][12] * D[7][12]) + F[9][8] * (F[8][6] * D[6][8] + F[8][7] * D[7][8] + F[8][9] * D[8][9] + F[8][10] * D[8][10] + F[8][11] * D[8][11] + F[8][12] * D[8][12]) + F[9][10] * (F[8][6] * D[6][10] + F[8][7] * D[7][10] + F[8][9] * D[9][10] + F[8][10] * D[10][10] + F[8][11] * D[10][11] + F[8][12] * D[10][12]) + F[9][11] * (F[8][6] * D[6][11] + F[8][7] * D[7][11] + F[8][9] * D[9][11] + F[8][10] * D[10][11] + F[8][11] * D[11][11] + F[8][12] * D[11][12]) + F[9][12] * (F[8][6] * D[6][12] + F[8][7] * D[7][12] + F[8][9] * D[9][12] + F[8][10] * D[10][12] + F[8][11] * D[11][12] + F[8][12] * D[12][12]) + G[8][0] * G[9][0] * Q[0] + G[8][1] * G[9][1] * Q[1] + G[8][2] * G[9][2] * Q[2]) * Tsq + (F[9][6] * D[6][8] + F[9][7] * D[7][8] + F[9][8] * D[8][8] + F[8][6] * D[6][9] + F[8][7] * D[7][9] + F[8][9] * D[9][9] + F[8][10] * D[9][10] + F[9][10] * D[8][10] + F[8][11] * D[9][11] + F[9][11] * D[8][11] + F[8][12] * D[9][12] + F[9][12] * D[8][12]) * T + D[8][9]; - P[8][10] = P[10][8] = (F[8][6] * D[6][10] + F[8][7] * D[7][10] + F[8][9] * D[9][10] + F[8][10] * D[10][10] + F[8][11] * D[10][11] + F[8][12] * D[10][12]) * T + D[8][10]; - P[8][11] = P[11][8] = (F[8][6] * D[6][11] + F[8][7] * D[7][11] + F[8][9] * D[9][11] + F[8][10] * D[10][11] + F[8][11] * D[11][11] + F[8][12] * D[11][12]) * T + D[8][11]; - P[8][12] = P[12][8] = (F[8][6] * D[6][12] + F[8][7] * D[7][12] + F[8][9] * D[9][12] + F[8][10] * D[10][12] + F[8][11] * D[11][12] + F[8][12] * D[12][12]) * T + D[8][12]; - P[8][13] = P[13][8] = (F[8][6] * D[6][13] + F[8][7] * D[7][13] + F[8][9] * D[9][13] + F[8][10] * D[10][13] + F[8][11] * D[11][13] + F[8][12] * D[12][13]) * T + D[8][13]; - P[9][9] = (Q[0] * G[9][0] * G[9][0] + Q[1] * G[9][1] * G[9][1] + Q[2] * G[9][2] * G[9][2] + F[9][6] * (F[9][6] * D[6][6] + F[9][7] * D[6][7] + F[9][8] * D[6][8] + F[9][10] * D[6][10] + F[9][11] * D[6][11] + F[9][12] * D[6][12]) + F[9][7] * (F[9][6] * D[6][7] + F[9][7] * D[7][7] + F[9][8] * D[7][8] + F[9][10] * D[7][10] + F[9][11] * D[7][11] + F[9][12] * D[7][12]) + F[9][8] * (F[9][6] * D[6][8] + F[9][7] * D[7][8] + F[9][8] * D[8][8] + F[9][10] * D[8][10] + F[9][11] * D[8][11] + F[9][12] * D[8][12]) + F[9][10] * (F[9][6] * D[6][10] + F[9][7] * D[7][10] + F[9][8] * D[8][10] + F[9][10] * D[10][10] + F[9][11] * D[10][11] + F[9][12] * D[10][12]) + F[9][11] * (F[9][6] * D[6][11] + F[9][7] * D[7][11] + F[9][8] * D[8][11] + F[9][10] * D[10][11] + F[9][11] * D[11][11] + F[9][12] * D[11][12]) + F[9][12] * (F[9][6] * D[6][12] + F[9][7] * D[7][12] + F[9][8] * D[8][12] + F[9][10] * D[10][12] + F[9][11] * D[11][12] + F[9][12] * D[12][12])) * Tsq + (2 * F[9][6] * D[6][9] + 2 * F[9][7] * D[7][9] + 2 * F[9][8] * D[8][9] + 2 * F[9][10] * D[9][10] + 2 * F[9][11] * D[9][11] + 2 * F[9][12] * D[9][12]) * T + D[9][9]; - P[9][10] = P[10][9] = (F[9][6] * D[6][10] + F[9][7] * D[7][10] + F[9][8] * D[8][10] + F[9][10] * D[10][10] + F[9][11] * D[10][11] + F[9][12] * D[10][12]) * T + D[9][10]; - P[9][11] = P[11][9] = (F[9][6] * D[6][11] + F[9][7] * D[7][11] + F[9][8] * D[8][11] + F[9][10] * D[10][11] + F[9][11] * D[11][11] + F[9][12] * D[11][12]) * T + D[9][11]; - P[9][12] = P[12][9] = (F[9][6] * D[6][12] + F[9][7] * D[7][12] + F[9][8] * D[8][12] + F[9][10] * D[10][12] + F[9][11] * D[11][12] + F[9][12] * D[12][12]) * T + D[9][12]; - P[9][13] = P[13][9] = (F[9][6] * D[6][13] + F[9][7] * D[7][13] + F[9][8] * D[8][13] + F[9][10] * D[10][13] + F[9][11] * D[11][13] + F[9][12] * D[12][13]) * T + D[9][13]; - P[10][10] = Q[6] * Tsq + D[10][10]; - P[10][11] = P[11][10] = D[10][11]; - P[10][12] = P[12][10] = D[10][12]; - P[10][13] = P[13][10] = D[10][13]; - P[11][11] = Q[7] * Tsq + D[11][11]; - P[11][12] = P[12][11] = D[11][12]; - P[11][13] = P[13][11] = D[11][13]; - P[12][12] = Q[8] * Tsq + D[12][12]; - P[12][13] = P[13][12] = D[12][13]; - P[13][13] = Q[9] * Tsq + D[13][13]; } -#endif /* ifdef COVARIANCE_PREDICTION_GENERAL */ // ************* SerialUpdate ******************* // Does the update step of the Kalman filter for the covariance and estimate @@ -642,47 +585,47 @@ void CovariancePrediction(float F[NUMX][NUMX], float G[NUMX][NUMW], // The SensorsUsed variable is a bitwise mask indicating which sensors // should be used in the update. // ************************************************ - void SerialUpdate(float H[NUMV][NUMX], float R[NUMV], float Z[NUMV], float Y[NUMV], float P[NUMX][NUMX], float X[NUMX], uint16_t SensorsUsed) { float HP[NUMX], HPHR, Error; uint8_t i, j, k, m; + float Km[NUMX]; // Iterate through all the possible measurements and apply the // appropriate corrections for (m = 0; m < NUMV; m++) { if (SensorsUsed & (0x01 << m)) { // use this sensor for update for (j = 0; j < NUMX; j++) { // Find Hp = H*P - HP[j] = 0.0f; - for (k = 0; k < NUMX; k++) { + HP[j] = 0; + } + + for (k = HrowMin[m]; k <= HrowMax[m]; k++) { + for (j = 0; j < NUMX; j++) { // Find Hp = H*P HP[j] += H[m][k] * P[k][j]; } } HPHR = R[m]; // Find HPHR = H*P*H' + R - for (k = 0; k < NUMX; k++) { + for (k = HrowMin[m]; k <= HrowMax[m]; k++) { HPHR += HP[k] * H[m][k]; } - + float invHPHR = 1.0f / HPHR; for (k = 0; k < NUMX; k++) { - ekf.K[k][m] = HP[k] / HPHR; // find K = HP/HPHR + Km[k] = HP[k] * invHPHR; // find K = HP/HPHR } for (i = 0; i < NUMX; i++) { // Find P(m)= P(m-1) + K*HP for (j = i; j < NUMX; j++) { - P[i][j] = P[j][i] = - P[i][j] - ekf.K[i][m] * HP[j]; + P[i][j] = P[j][i] = P[i][j] - Km[i] * HP[j]; } } Error = Z[m] - Y[m]; for (i = 0; i < NUMX; i++) { // Find X(m)= X(m-1) + K*Error - X[i] = X[i] + ekf.K[i][m] * Error; + X[i] = X[i] + Km[i] * Error; } } } - - INSLimitBias(); } // ************* RungeKutta ********************** @@ -694,8 +637,8 @@ void SerialUpdate(float H[NUMV][NUMX], float R[NUMV], float Z[NUMV], void RungeKutta(float X[NUMX], float U[NUMU], float dT) { - float dT2 = - dT / 2.0f, K1[NUMX], K2[NUMX], K3[NUMX], K4[NUMX], Xlast[NUMX]; + const float dT2 = dT / 2.0f; + float K1[NUMX], K2[NUMX], K3[NUMX], K4[NUMX], Xlast[NUMX]; uint8_t i; for (i = 0; i < NUMX; i++) { @@ -719,7 +662,7 @@ void RungeKutta(float X[NUMX], float U[NUMU], float dT) for (i = 0; i < NUMX; i++) { X[i] = Xlast[i] + dT * (K1[i] + 2.0f * K2[i] + 2.0f * K3[i] + - K4[i]) / 6.0f; + K4[i]) * (1.0f / 6.0f); } } @@ -873,23 +816,29 @@ void LinearizeFG(float X[NUMX], float U[NUMU], float F[NUMX][NUMX], F[9][12] = -q0 / 2.0f; // dVdot/dna - G[3][3] = -q0 * q0 - q1 * q1 + q2 * q2 + q3 * q3; G[3][4] = 2 * (-q1 * q2 + q0 * q3); G[3][5] = -2 * (q1 * q3 + q0 * q2); - G[4][3] = -2 * (q1 * q2 + q0 * q3); G[4][4] = -q0 * q0 + q1 * q1 - q2 * q2 + q3 * q3; G[4][5] = 2 * (-q2 * q3 + q0 * q1); - G[5][3] = 2 * (-q1 * q3 + q0 * q2); G[5][4] = -2 * (q2 * q3 + q0 * q1); G[5][5] = -q0 * q0 + q1 * q1 + q2 * q2 - q3 * q3; + G[3][3] = -q0 * q0 - q1 * q1 + q2 * q2 + q3 * q3; + G[3][4] = 2 * (-q1 * q2 + q0 * q3); + // G[3][5] = -2 * (q1 * q3 + q0 * q2); // already assigned above + G[4][3] = -2 * (q1 * q2 + q0 * q3); + G[4][4] = -q0 * q0 + q1 * q1 - q2 * q2 + q3 * q3; + // G[4][5] = 2 * (-q2 * q3 + q0 * q1); // already assigned above + G[5][3] = 2 * (-q1 * q3 + q0 * q2); + G[5][4] = -2 * (q2 * q3 + q0 * q1); + // G[5][5] = -q0 * q0 + q1 * q1 + q2 * q2 - q3 * q3; // already assigned above // dqdot/dnw - G[6][0] = q1 / 2.0f; - G[6][1] = q2 / 2.0f; - G[6][2] = q3 / 2.0f; - G[7][0] = -q0 / 2.0f; - G[7][1] = q3 / 2.0f; - G[7][2] = -q2 / 2.0f; - G[8][0] = -q3 / 2.0f; - G[8][1] = -q0 / 2.0f; - G[8][2] = q1 / 2.0f; - G[9][0] = q2 / 2.0f; - G[9][1] = -q1 / 2.0f; - G[9][2] = -q0 / 2.0f; + G[6][0] = q1 / 2.0f; + G[6][1] = q2 / 2.0f; + G[6][2] = q3 / 2.0f; + G[7][0] = -q0 / 2.0f; + G[7][1] = q3 / 2.0f; + G[7][2] = -q2 / 2.0f; + G[8][0] = -q3 / 2.0f; + G[8][1] = -q0 / 2.0f; + G[8][2] = q1 / 2.0f; + G[9][0] = q2 / 2.0f; + G[9][1] = -q1 / 2.0f; + G[9][2] = -q0 / 2.0f; } /** From 3b65559904801d914e5473d8acc644601bca299b Mon Sep 17 00:00:00 2001 From: Eric Price Date: Thu, 2 Mar 2017 09:51:27 +0100 Subject: [PATCH 161/624] LP-443 bugfixes in insgps14state - prevent NaN propagation from bug in magnetometer handling, fix missing dimension in array --- flight/libraries/insgps14state.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/flight/libraries/insgps14state.c b/flight/libraries/insgps14state.c index bd3944cddf..0a498d026d 100644 --- a/flight/libraries/insgps14state.c +++ b/flight/libraries/insgps14state.c @@ -76,7 +76,7 @@ static void LinearizeH(float X[NUMX], float Be[3], float H[NUMV][NUMX]); // 7.....oXoXXXXX. XXX....... ......XXXX.... // 8.....oXXoXXXX. XXX....... ......XXXX.... // 9.....oXXXoXXX. XXX....... ..X........... -// a.............. .......... .............. +// a.............. .......... // b.............. .......... // c.............. .......... // d.............. .......... @@ -84,8 +84,8 @@ static void LinearizeH(float X[NUMX], float Be[3], float H[NUMV][NUMX]); static int8_t FrowMin[NUMX] = { 3, 4, 5, 6, 6, 6, 5, 5, 5, 5, 14, 14, 14, 14 }; static int8_t FrowMax[NUMX] = { 3, 4, 5, 13, 13, 13, 12, 12, 12, 12, -1, -1, -1, -1 }; -static int8_t GrowMin[NUMX] = { 10, 10, 10, 3, 3, 3, 0, 0, 0, 0, 10, 10, 10 }; -static int8_t GrowMax[NUMX] = { -1, -1, -1, 5, 5, 5, 2, 2, 2, 2, -1, -1, -1 }; +static int8_t GrowMin[NUMX] = { 10, 10, 10, 3, 3, 3, 0, 0, 0, 0, 10, 10, 10, 10 }; +static int8_t GrowMax[NUMX] = { -1, -1, -1, 5, 5, 5, 2, 2, 2, 2, -1, -1, -1, -1 }; static int8_t HrowMin[NUMV] = { 0, 1, 2, 3, 4, 5, 6, 6, 6, 2 }; static int8_t HrowMax[NUMV] = { 0, 1, 2, 3, 4, 5, 9, 9, 9, 2 }; @@ -461,6 +461,9 @@ void INSCorrection(const float mag_data[3], const float Pos[3], const float Vel[ Z[6] = Rbe_a[0][0] * mag_data[0] + Rbe_a[1][0] * mag_data[1] + Rbe_a[2][0] * mag_data[2]; Z[7] = Rbe_a[0][1] * mag_data[0] + Rbe_a[1][1] * mag_data[1] + Rbe_a[2][1] * mag_data[2]; Z[8] = Rbe_a[0][2] * mag_data[0] + Rbe_a[1][2] * mag_data[1] + Rbe_a[2][2] * mag_data[2]; + if (!(IS_REAL(Z[6]) && IS_REAL(Z[7]) && IS_REAL(Z[8]))) { + SensorsUsed = SensorsUsed & ~MAG_SENSORS; + } } // barometric altimeter in meters and in local NED frame From e62cf039fb4f37cd7737a972720ce1c76649342b Mon Sep 17 00:00:00 2001 From: Eric Price Date: Thu, 2 Mar 2017 10:30:03 +0100 Subject: [PATCH 162/624] LP-490 move back to insgps13state --- flight/targets/boards/discoveryf4bare/firmware/Makefile | 2 +- flight/targets/boards/revolution/firmware/Makefile | 2 +- flight/targets/boards/revonano/firmware/Makefile | 2 +- flight/targets/boards/revoproto/firmware/Makefile | 2 +- flight/targets/boards/simposix/firmware/Makefile | 2 +- flight/targets/boards/sparky2/firmware/Makefile | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/flight/targets/boards/discoveryf4bare/firmware/Makefile b/flight/targets/boards/discoveryf4bare/firmware/Makefile index 41f1837d05..d9e9c67f4c 100644 --- a/flight/targets/boards/discoveryf4bare/firmware/Makefile +++ b/flight/targets/boards/discoveryf4bare/firmware/Makefile @@ -97,7 +97,7 @@ ifndef TESTAPP SRC += $(FLIGHTLIB)/paths.c SRC += $(FLIGHTLIB)/plans.c SRC += $(FLIGHTLIB)/WorldMagModel.c - SRC += $(FLIGHTLIB)/insgps14state.c + SRC += $(FLIGHTLIB)/insgps13state.c SRC += $(FLIGHTLIB)/auxmagsupport.c SRC += $(FLIGHTLIB)/lednotification.c diff --git a/flight/targets/boards/revolution/firmware/Makefile b/flight/targets/boards/revolution/firmware/Makefile index 62e0dd156e..5ee49d1a22 100644 --- a/flight/targets/boards/revolution/firmware/Makefile +++ b/flight/targets/boards/revolution/firmware/Makefile @@ -95,7 +95,7 @@ ifndef TESTAPP SRC += $(FLIGHTLIB)/paths.c SRC += $(FLIGHTLIB)/plans.c SRC += $(FLIGHTLIB)/WorldMagModel.c - SRC += $(FLIGHTLIB)/insgps14state.c + SRC += $(FLIGHTLIB)/insgps13state.c SRC += $(FLIGHTLIB)/auxmagsupport.c SRC += $(FLIGHTLIB)/lednotification.c SRC += $(FLIGHTLIB)/sha1.c diff --git a/flight/targets/boards/revonano/firmware/Makefile b/flight/targets/boards/revonano/firmware/Makefile index 4c473dbf90..1abf5b82a6 100644 --- a/flight/targets/boards/revonano/firmware/Makefile +++ b/flight/targets/boards/revonano/firmware/Makefile @@ -94,7 +94,7 @@ ifndef TESTAPP SRC += $(FLIGHTLIB)/paths.c SRC += $(FLIGHTLIB)/plans.c SRC += $(FLIGHTLIB)/WorldMagModel.c - SRC += $(FLIGHTLIB)/insgps14state.c + SRC += $(FLIGHTLIB)/insgps13state.c SRC += $(FLIGHTLIB)/lednotification.c SRC += $(FLIGHTLIB)/auxmagsupport.c ## UAVObjects diff --git a/flight/targets/boards/revoproto/firmware/Makefile b/flight/targets/boards/revoproto/firmware/Makefile index f40e1a3086..d8d5124c0b 100644 --- a/flight/targets/boards/revoproto/firmware/Makefile +++ b/flight/targets/boards/revoproto/firmware/Makefile @@ -92,7 +92,7 @@ ifndef TESTAPP SRC += $(FLIGHTLIB)/paths.c SRC += $(FLIGHTLIB)/plans.c SRC += $(FLIGHTLIB)/WorldMagModel.c - SRC += $(FLIGHTLIB)/insgps14state.c + SRC += $(FLIGHTLIB)/insgps13state.c SRC += $(FLIGHTLIB)/auxmagsupport.c ## UAVObjects diff --git a/flight/targets/boards/simposix/firmware/Makefile b/flight/targets/boards/simposix/firmware/Makefile index 033993773d..1849b97401 100644 --- a/flight/targets/boards/simposix/firmware/Makefile +++ b/flight/targets/boards/simposix/firmware/Makefile @@ -106,7 +106,7 @@ SRC += $(FLIGHT_UAVOBJ_DIR)/uavobjectsinit.c SRC += $(FLIGHTLIB)/CoordinateConversions.c SRC += $(FLIGHTLIB)/fifo_buffer.c SRC += $(FLIGHTLIB)/WorldMagModel.c -SRC += $(FLIGHTLIB)/insgps14state.c +SRC += $(FLIGHTLIB)/insgps13state.c SRC += $(FLIGHTLIB)/paths.c SRC += $(FLIGHTLIB)/plans.c SRC += $(FLIGHTLIB)/sanitycheck.c diff --git a/flight/targets/boards/sparky2/firmware/Makefile b/flight/targets/boards/sparky2/firmware/Makefile index 942944f6d9..45c7f28911 100644 --- a/flight/targets/boards/sparky2/firmware/Makefile +++ b/flight/targets/boards/sparky2/firmware/Makefile @@ -95,7 +95,7 @@ ifndef TESTAPP SRC += $(FLIGHTLIB)/paths.c SRC += $(FLIGHTLIB)/plans.c SRC += $(FLIGHTLIB)/WorldMagModel.c - SRC += $(FLIGHTLIB)/insgps14state.c + SRC += $(FLIGHTLIB)/insgps13state.c SRC += $(FLIGHTLIB)/auxmagsupport.c SRC += $(FLIGHTLIB)/lednotification.c SRC += $(FLIGHTLIB)/sha1.c From 23e50ae5f89a4c81c4583e35ad7e19b1397cd68f Mon Sep 17 00:00:00 2001 From: Eric Price Date: Thu, 2 Mar 2017 10:57:00 +0100 Subject: [PATCH 163/624] LP-490 re-introduce correct mag handling (scaling to unit vector) in insgps13state --- flight/libraries/insgps13state.c | 44 ++++++++++++-------------------- 1 file changed, 16 insertions(+), 28 deletions(-) diff --git a/flight/libraries/insgps13state.c b/flight/libraries/insgps13state.c index f6aa54bee1..14f83f2d17 100644 --- a/flight/libraries/insgps13state.c +++ b/flight/libraries/insgps13state.c @@ -280,11 +280,14 @@ void INSSetGyroBiasVar(const float gyro_bias_var[3]) ekf.Q[8] = gyro_bias_var[2]; } -void INSSetMagVar(const float scaled_mag_var[3]) +void INSSetMagVar(const float mag_var[3]) { - ekf.R[6] = scaled_mag_var[0]; - ekf.R[7] = scaled_mag_var[1]; - ekf.R[8] = scaled_mag_var[2]; + // scale variance down to unit vector + float invBmag = invsqrtf(mag_var[0] * mag_var[0] + mag_var[1] * mag_var[1] + mag_var[2] * mag_var[2]); + + ekf.R[6] = mag_var[0] * invBmag; + ekf.R[7] = mag_var[1] * invBmag; + ekf.R[8] = mag_var[2] * invBmag; } void INSSetBaroVar(float baro_var) @@ -294,9 +297,11 @@ void INSSetBaroVar(float baro_var) void INSSetMagNorth(const float B[3]) { - ekf.Be[0] = B[0]; - ekf.Be[1] = B[1]; - ekf.Be[2] = B[2]; + float invmag = invsqrtf(B[0] * B[0] + B[1] * B[1] + B[2] * B[2]); + + ekf.Be[0] = B[0] * invmag; + ekf.Be[1] = B[1] * invmag; + ekf.Be[2] = B[2] * invmag; } void INSStatePrediction(const float gyro_data[3], const float accel_data[3], float dT) @@ -403,27 +408,10 @@ void INSCorrection(const float mag_data[3], const float Pos[3], const float Vel[ if (SensorsUsed & MAG_SENSORS) { // magnetometer data in any units (use unit vector) and in body frame - float Rbe_a[3][3]; - float q0 = ekf.X[6]; - float q1 = ekf.X[7]; - float q2 = ekf.X[8]; - float q3 = ekf.X[9]; - float k1 = 1.0f / sqrtf(powf(q0 * q1 * 2.0f + q2 * q3 * 2.0f, 2.0f) + powf(q0 * q0 - q1 * q1 - q2 * q2 + q3 * q3, 2.0f)); - float k2 = sqrtf(-powf(q0 * q2 * 2.0f - q1 * q3 * 2.0f, 2.0f) + 1.0f); - - Rbe_a[0][0] = k2; - Rbe_a[0][1] = 0.0f; - Rbe_a[0][2] = q0 * q2 * -2.0f + q1 * q3 * 2.0f; - Rbe_a[1][0] = k1 * (q0 * q1 * 2.0f + q2 * q3 * 2.0f) * (q0 * q2 * 2.0f - q1 * q3 * 2.0f); - Rbe_a[1][1] = k1 * (q0 * q0 - q1 * q1 - q2 * q2 + q3 * q3); - Rbe_a[1][2] = k1 * sqrtf(-powf(q0 * q2 * 2.0f - q1 * q3 * 2.0f, 2.0f) + 1.0f) * (q0 * q1 * 2.0f + q2 * q3 * 2.0f); - Rbe_a[2][0] = k1 * (q0 * q2 * 2.0f - q1 * q3 * 2.0f) * (q0 * q0 - q1 * q1 - q2 * q2 + q3 * q3); - Rbe_a[2][1] = -k1 * (q0 * q1 * 2.0f + q2 * q3 * 2.0f); - Rbe_a[2][2] = k1 * k2 * (q0 * q0 - q1 * q1 - q2 * q2 + q3 * q3); - - Z[6] = Rbe_a[0][0] * mag_data[0] + Rbe_a[1][0] * mag_data[1] + Rbe_a[2][0] * mag_data[2]; - Z[7] = Rbe_a[0][1] * mag_data[0] + Rbe_a[1][1] * mag_data[1] + Rbe_a[2][1] * mag_data[2]; - Z[8] = Rbe_a[0][2] * mag_data[0] + Rbe_a[1][2] * mag_data[1] + Rbe_a[2][2] * mag_data[2]; + float invBmag = invsqrtf(mag_data[0] * mag_data[0] + mag_data[1] * mag_data[1] + mag_data[2] * mag_data[2]); + Z[6] = mag_data[0] * invBmag; + Z[7] = mag_data[1] * invBmag; + Z[8] = mag_data[2] * invBmag; } // barometric altimeter in meters and in local NED frame From f17d4eb7603d4e8c28fe637798b706298a044157 Mon Sep 17 00:00:00 2001 From: Eric Price Date: Thu, 2 Mar 2017 12:19:37 +0100 Subject: [PATCH 164/624] LP-490 added new setting for EKF Magnetometer Correction --- shared/uavobjectdefinition/ekfconfiguration.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/shared/uavobjectdefinition/ekfconfiguration.xml b/shared/uavobjectdefinition/ekfconfiguration.xml index bf248a84b1..ca9696dd8b 100644 --- a/shared/uavobjectdefinition/ekfconfiguration.xml +++ b/shared/uavobjectdefinition/ekfconfiguration.xml @@ -66,6 +66,9 @@ FakeGPSVelAirspeed + From 2124393d5fdeeb39324f4e6f7480cf8229a3b455 Mon Sep 17 00:00:00 2001 From: Eric Price Date: Thu, 2 Mar 2017 18:34:37 +0100 Subject: [PATCH 165/624] LP-490 EKF maps magnetometer into horizontal plane based on known HomeLocation.Be value, to not distort Roll+Pitch estimate from mags --- flight/libraries/insgps13state.c | 19 ++++---- flight/modules/StateEstimation/filterekf.c | 52 ++++++++++++++++++++-- 2 files changed, 57 insertions(+), 14 deletions(-) diff --git a/flight/libraries/insgps13state.c b/flight/libraries/insgps13state.c index 14f83f2d17..2631bdb5ae 100644 --- a/flight/libraries/insgps13state.c +++ b/flight/libraries/insgps13state.c @@ -92,6 +92,7 @@ static struct EKFData { float H[NUMV][NUMX]; // local magnetic unit vector in NED frame float Be[3]; + float BeScaleFactor; // covariance matrix and state vector float P[NUMX][NUMX]; float X[NUMX]; @@ -280,14 +281,12 @@ void INSSetGyroBiasVar(const float gyro_bias_var[3]) ekf.Q[8] = gyro_bias_var[2]; } +// must be called AFTER SetMagNorth void INSSetMagVar(const float mag_var[3]) { - // scale variance down to unit vector - float invBmag = invsqrtf(mag_var[0] * mag_var[0] + mag_var[1] * mag_var[1] + mag_var[2] * mag_var[2]); - - ekf.R[6] = mag_var[0] * invBmag; - ekf.R[7] = mag_var[1] * invBmag; - ekf.R[8] = mag_var[2] * invBmag; + ekf.R[6] = mag_var[0] * ekf.BeScaleFactor; + ekf.R[7] = mag_var[1] * ekf.BeScaleFactor; + ekf.R[8] = mag_var[2] * ekf.BeScaleFactor; } void INSSetBaroVar(float baro_var) @@ -297,11 +296,11 @@ void INSSetBaroVar(float baro_var) void INSSetMagNorth(const float B[3]) { - float invmag = invsqrtf(B[0] * B[0] + B[1] * B[1] + B[2] * B[2]); + ekf.BeScaleFactor = invsqrtf(B[0] * B[0] + B[1] * B[1] + B[2] * B[2]); - ekf.Be[0] = B[0] * invmag; - ekf.Be[1] = B[1] * invmag; - ekf.Be[2] = B[2] * invmag; + ekf.Be[0] = B[0] * ekf.BeScaleFactor; + ekf.Be[1] = B[1] * ekf.BeScaleFactor; + ekf.Be[2] = B[2] * ekf.BeScaleFactor; } void INSStatePrediction(const float gyro_data[3], const float accel_data[3], float dT) diff --git a/flight/modules/StateEstimation/filterekf.c b/flight/modules/StateEstimation/filterekf.c index b0cb714b3e..9c7f8e72f9 100644 --- a/flight/modules/StateEstimation/filterekf.c +++ b/flight/modules/StateEstimation/filterekf.c @@ -68,10 +68,11 @@ struct data { stateEstimation work; - bool inited; + bool inited; PiOSDeltatimeConfig dtconfig; - bool navOnly; + bool navOnly; + float magLockAlpha; }; @@ -166,6 +167,15 @@ static int32_t init(stateFilter *self) return 2; } + // calculate Angle between Down vector and homeLocation.Be + float cross[3]; + float magnorm[3] = { this->homeLocation.Be[0], this->homeLocation.Be[1], this->homeLocation.Be[2] }; + vector_normalizef(magnorm, 3); + const float down[3] = { 0, 0, 1 }; + CrossProduct(down, magnorm, cross); + // VectorMagnitude(cross) = sin(Alpha) + // [0,0,1] dot magnorm = magnorm[2] = cos(Alpha) + this->magLockAlpha = atan2f(VectorMagnitude(cross), magnorm[2]); return 0; } @@ -184,6 +194,7 @@ static filterResult filter(stateFilter *self, stateEstimation *state) uint16_t sensors = 0; INSSetArmed(state->armed); + INSSetMagNorth(this->homeLocation.Be); state->navUsed = (this->usePos || this->navOnly); this->work.updated |= state->updated; // check magnetometer alarm, discard any magnetometer readings if not OK @@ -212,6 +223,7 @@ static filterResult filter(stateFilter *self, stateEstimation *state) UNSET_MASK(state->updated, SENSORUPDATES_vel); UNSET_MASK(state->updated, SENSORUPDATES_attitude); UNSET_MASK(state->updated, SENSORUPDATES_gyro); + UNSET_MASK(state->updated, SENSORUPDATES_mag); return FILTERRESULT_OK; } @@ -350,14 +362,46 @@ static filterResult filter(stateFilter *self, stateEstimation *state) if (IS_SET(this->work.updated, SENSORUPDATES_mag)) { sensors |= MAG_SENSORS; + if (this->ekfConfiguration.MapMagnetometerToHorizontalPlane == EKFCONFIGURATION_MAPMAGNETOMETERTOHORIZONTALPLANE_TRUE) { + // Map Magnetometer vector to correspond to the Roll+Pitch of the current Attitude State Estimate (no conflicting gravity) + // Idea: Alpha between Local Down and Mag is invariant of orientation, and identical to Alpha between [0,0,1] and HomeLocation.Be + // which is measured in init() + float R[3][3]; + + // 1. rotate down vector into body frame + Quaternion2R(Nav.q, R); + float local_down[3]; + rot_mult(R, (float[3]) { 0, 0, 1 }, local_down); + // 2. create a rotation vector that is perpendicular to rotated down vector, magnetic field vector and of size magLockAlpha + float rotvec[3]; + CrossProduct(local_down, this->work.mag, rotvec); + vector_normalizef(rotvec, 3); + rotvec[0] *= -this->magLockAlpha; + rotvec[1] *= -this->magLockAlpha; + rotvec[2] *= -this->magLockAlpha; + // 3. rotate artificial magnetometer reading from straight down to correct roll+pitch + // rot_mult(R, (const float[3]) { 0, 0, VectorMagnitude(this->work.mag) }, this->work.mag); + Rv2Rot(rotvec, R); + float MagStrength = VectorMagnitude(this->homeLocation.Be); + local_down[0] *= MagStrength; + local_down[1] *= MagStrength; + local_down[2] *= MagStrength; + rot_mult(R, local_down, this->work.mag); + } + // debug rotated mags + state->mag[0] = this->work.mag[0]; + state->mag[1] = this->work.mag[1]; + state->mag[2] = this->work.mag[2]; + state->updated |= SENSORUPDATES_mag; + } else { + // mag state is delayed until EKF processed it, allows overriding/debugging magnetometer estimate + UNSET_MASK(state->updated, SENSORUPDATES_mag); } if (IS_SET(this->work.updated, SENSORUPDATES_baro)) { sensors |= BARO_SENSOR; } - INSSetMagNorth(this->homeLocation.Be); - if (!this->usePos) { // position and velocity variance used in indoor mode INSSetPosVelVar((float[3]) { this->ekfConfiguration.FakeR.FakeGPSPosIndoor, From 40ebd0a06282122551b7312c5d0d74bf105af86f Mon Sep 17 00:00:00 2001 From: Eric Price Date: Thu, 2 Mar 2017 18:36:06 +0100 Subject: [PATCH 166/624] LP-490 fixed ekf configuration default values for return to insgps13state - no more asymetric variances in body frame that assume certain board orientations to work --- shared/uavobjectdefinition/ekfconfiguration.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/shared/uavobjectdefinition/ekfconfiguration.xml b/shared/uavobjectdefinition/ekfconfiguration.xml index ca9696dd8b..d5fe365cab 100644 --- a/shared/uavobjectdefinition/ekfconfiguration.xml +++ b/shared/uavobjectdefinition/ekfconfiguration.xml @@ -23,7 +23,7 @@ @@ -39,9 +39,9 @@ GPSPosNorth From 14d935a6dd74ebd65b5f8f7f86f4ac28c98cc750 Mon Sep 17 00:00:00 2001 From: Eric Price Date: Thu, 2 Mar 2017 20:47:50 +0100 Subject: [PATCH 167/624] LP-490 changed default gyro process noise to increase filter stability (converges quicker to a stable estimate) --- shared/uavobjectdefinition/ekfconfiguration.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/uavobjectdefinition/ekfconfiguration.xml b/shared/uavobjectdefinition/ekfconfiguration.xml index d5fe365cab..493b89c4d0 100644 --- a/shared/uavobjectdefinition/ekfconfiguration.xml +++ b/shared/uavobjectdefinition/ekfconfiguration.xml @@ -23,7 +23,7 @@ From 40e6b3c39f04bfeb93fbe22337da3adf35892d62 Mon Sep 17 00:00:00 2001 From: Laurent Lalanne Date: Fri, 3 Mar 2017 01:46:10 +0100 Subject: [PATCH 168/624] LP-488 Change ThrustControl name --- flight/modules/AutoTune/autotune.c | 2 +- shared/uavobjectdefinition/systemidentsettings.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/flight/modules/AutoTune/autotune.c b/flight/modules/AutoTune/autotune.c index 9b32420e76..b4fc4924bc 100644 --- a/flight/modules/AutoTune/autotune.c +++ b/flight/modules/AutoTune/autotune.c @@ -842,7 +842,7 @@ static void UpdateStabilizationDesired(bool doingIdent) stabDesired.StabilizationMode.Yaw = STABILIZATIONDESIRED_STABILIZATIONMODE_RATE; } - if (systemIdentSettings.ThrustControl == SYSTEMIDENTSETTINGS_THRUSTCONTROL_AUTO) { + if (systemIdentSettings.ThrustControl == SYSTEMIDENTSETTINGS_THRUSTCONTROL_ALTITUDEVARIO) { stabDesired.StabilizationMode.Thrust = STABILIZATIONDESIRED_STABILIZATIONMODE_ALTITUDEVARIO; } else { stabDesired.StabilizationMode.Thrust = STABILIZATIONDESIRED_STABILIZATIONMODE_MANUAL; diff --git a/shared/uavobjectdefinition/systemidentsettings.xml b/shared/uavobjectdefinition/systemidentsettings.xml index cf354dd1f3..c6aa3d880a 100644 --- a/shared/uavobjectdefinition/systemidentsettings.xml +++ b/shared/uavobjectdefinition/systemidentsettings.xml @@ -58,7 +58,7 @@ - + From e9a0e3ad697667242fbfa07fcc29b07c2b54977e Mon Sep 17 00:00:00 2001 From: Eric Price Date: Tue, 7 Mar 2017 12:12:18 +0100 Subject: [PATCH 169/624] LP-490 cosmetic code cleanup --- flight/modules/StateEstimation/filterekf.c | 1 - 1 file changed, 1 deletion(-) diff --git a/flight/modules/StateEstimation/filterekf.c b/flight/modules/StateEstimation/filterekf.c index 9c7f8e72f9..88943a2f42 100644 --- a/flight/modules/StateEstimation/filterekf.c +++ b/flight/modules/StateEstimation/filterekf.c @@ -380,7 +380,6 @@ static filterResult filter(stateFilter *self, stateEstimation *state) rotvec[1] *= -this->magLockAlpha; rotvec[2] *= -this->magLockAlpha; // 3. rotate artificial magnetometer reading from straight down to correct roll+pitch - // rot_mult(R, (const float[3]) { 0, 0, VectorMagnitude(this->work.mag) }, this->work.mag); Rv2Rot(rotvec, R); float MagStrength = VectorMagnitude(this->homeLocation.Be); local_down[0] *= MagStrength; From 814a882a1dc0d8d938759cef5e7e902eb568c1e1 Mon Sep 17 00:00:00 2001 From: paul Jewell Date: Sat, 10 Dec 2016 09:09:53 +0100 Subject: [PATCH 170/624] LP-289 Manage kp=0 in PIDControlDown::UpdateParameters() --- flight/libraries/pid/pidcontroldown.cpp | 31 ++++++++++++++++++------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/flight/libraries/pid/pidcontroldown.cpp b/flight/libraries/pid/pidcontroldown.cpp index 93e2183716..ee8f33d60c 100644 --- a/flight/libraries/pid/pidcontroldown.cpp +++ b/flight/libraries/pid/pidcontroldown.cpp @@ -91,26 +91,39 @@ void PIDControlDown::Activate() void PIDControlDown::UpdateParameters(float kp, float ki, float kd, float beta, float dT, float velocityMax) { // pid_configure(&PID, kp, ki, kd, ilimit); - float Ti = kp / ki; - float Td = kd / kp; - float Tt = (Ti + Td) / 2.0f; - float kt = 1.0f / Tt; + float Td; + float Ti; + float Tt; + float kt; float N = 10.0f; - float Tf = Td / N; + float Tf; - if (ki < 1e-6f) { - // Avoid Ti being infinite + // Define Td, handling zero kp term (for I or ID controller) + if (kp < 1e-6f) { + Td = 1e6f; + } else { + Td = kd / kp; + } + + // Define Ti, Tt and kt, handling zero ki term (for P or PD controller) + if (ki < 1e-6f) { // Avoid Ti being infinite Ti = 1e6f; // Tt antiwindup time constant - we don't need antiwindup with no I term Tt = 1e6f; kt = 0.0f; + } else { + Ti = kp / ki; + Tt = (Ti + Td) / 2.0f; + kt = 1.0f / Tt; } - + // Define Tf, according to controller type if (kd < 1e-6f) { // PI Controller or P Controller Tf = Ti / N; + } else { + Tf = Td / N; } - + if (beta > 1.0f) { beta = 1.0f; } else if (beta < 0.4f) { From edd3b8689ba48a7d9c12d56ee344b3a79ee15769 Mon Sep 17 00:00:00 2001 From: paul Jewell Date: Sat, 10 Dec 2016 12:43:50 +0100 Subject: [PATCH 171/624] LP-289 Further clean up of PIDControlDown::UpdateParameters() --- flight/libraries/pid/pidcontroldown.cpp | 31 ++++++++++++------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/flight/libraries/pid/pidcontroldown.cpp b/flight/libraries/pid/pidcontroldown.cpp index ee8f33d60c..253eaa682d 100644 --- a/flight/libraries/pid/pidcontroldown.cpp +++ b/flight/libraries/pid/pidcontroldown.cpp @@ -7,7 +7,8 @@ * @{ * * @file pidcontroldown.h - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2015. + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. + * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2015. * @brief Executes PID control for down direction * * @see The GNU Public License (GPL) Version 3 @@ -90,13 +91,13 @@ void PIDControlDown::Activate() void PIDControlDown::UpdateParameters(float kp, float ki, float kd, float beta, float dT, float velocityMax) { - // pid_configure(&PID, kp, ki, kd, ilimit); - float Td; - float Ti; - float Tt; - float kt; - float N = 10.0f; - float Tf; + float Td; // Derivative time constant + float Ti; // Integral time constant + float kt; // Feedback gain for integral windup avoidance + float N = 10.0f; // N is the factor used to determine the + // time constant for derivative filtering + // Why 10? Maybe should be configurable? + float Tf; // Low pass filter time constant for derivative filtering // Define Td, handling zero kp term (for I or ID controller) if (kp < 1e-6f) { @@ -107,23 +108,21 @@ void PIDControlDown::UpdateParameters(float kp, float ki, float kd, float beta, // Define Ti, Tt and kt, handling zero ki term (for P or PD controller) if (ki < 1e-6f) { // Avoid Ti being infinite - Ti = 1e6f; - // Tt antiwindup time constant - we don't need antiwindup with no I term - Tt = 1e6f; kt = 0.0f; } else { Ti = kp / ki; - Tt = (Ti + Td) / 2.0f; - kt = 1.0f / Tt; + kt = 1.0f / Ti; } - // Define Tf, according to controller type + + // Define Tf, according to controller type if (kd < 1e-6f) { // PI Controller or P Controller - Tf = Ti / N; + Tf = 0; // Originally this: (Ti / N) - which creates a D term from + // the integral time constant! } else { Tf = Td / N; } - + if (beta > 1.0f) { beta = 1.0f; } else if (beta < 0.4f) { From c723a06e934fd68bf893d4516ed9188e5c9f0f92 Mon Sep 17 00:00:00 2001 From: paul Jewell Date: Sat, 10 Dec 2016 14:06:13 +0100 Subject: [PATCH 172/624] LP-289 added comments and fixed one typo --- flight/libraries/math/pid.c | 5 +++-- flight/libraries/math/pid.h | 24 +++++++++++++----------- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/flight/libraries/math/pid.c b/flight/libraries/math/pid.c index 6e962c306f..dafff7b155 100644 --- a/flight/libraries/math/pid.c +++ b/flight/libraries/math/pid.c @@ -6,7 +6,8 @@ * @{ * * @file pid.c - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012. + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. + * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2015. * @brief Methods to work with PID structure * * @see The GNU Public License (GPL) Version 3 @@ -159,7 +160,7 @@ void pid_configure(struct pid *pid, float p, float i, float d, float iLim) * @param[in] kp proportional gain * @param[in] ki integral gain. Time constant Ti = kp/ki * @param[in] kd derivative gain. Time constant Td = kd/kp - * @param[in] Tf filtering time = (kd/k)/N, N is in the range of 2 to 20 + * @param[in] Tf filtering time = (kd/kp)/N, N is in the range of 2 to 20 * @param[in] kt tracking gain for anti-windup. Tt = √TiTd and Tt = (Ti + Td)/2 * @param[in] dt delta time increment * @param[in] beta setpoint weight on setpoint in P component. beta=1 error feedback. beta=0 smoothes out response to changes in setpoint diff --git a/flight/libraries/math/pid.h b/flight/libraries/math/pid.h index b6d9e2ae66..eba64a5f95 100644 --- a/flight/libraries/math/pid.h +++ b/flight/libraries/math/pid.h @@ -6,7 +6,9 @@ * @{ * * @file pid.h - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012. + * + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. + * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012. * @brief Methods to work with PID structure * * @see The GNU Public License (GPL) Version 3 @@ -46,17 +48,17 @@ struct pid { // pid2 structure for a PID+setpoint weighting, anti-windup and filtered derivative control struct pid2 { - float u0; - float va; + float u0; // Initial value of r & y - for bumpless transfer + float va; // Actuator float vb; - float kp; - float bi; - float ad; - float bd; - float br; - float beta; - float yold; - float P; + float kp; // proportional gain + float bi; // Integral gain . dT + float ad; // Filtered factor for derivative calculation + float bd; // Constant for derivative calculation + float br; // Time constant for integral calculation + float beta; // Scalar for proportional factor + float yold; // t-1 y value for Integral calculation + float P; // Latest calculated P, I & D values float I; float D; uint8_t reconfigure; From a19bd40259ae6bdafa3399e8854c365accc2e487 Mon Sep 17 00:00:00 2001 From: paul Jewell Date: Sat, 10 Dec 2016 14:07:11 +0100 Subject: [PATCH 173/624] LP-289 cleaned up PIDControlNE::UpdateParameters() --- flight/modules/PathFollower/pidcontrolne.cpp | 47 +++++++++++++------- 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/flight/modules/PathFollower/pidcontrolne.cpp b/flight/modules/PathFollower/pidcontrolne.cpp index 6a8968f24d..5b4a61f115 100644 --- a/flight/modules/PathFollower/pidcontrolne.cpp +++ b/flight/modules/PathFollower/pidcontrolne.cpp @@ -7,7 +7,8 @@ * @{ * * @file PIDControlNE.h - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2015. + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. + * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2015. * @brief Executes PID control loops for NE directions * * @see The GNU Public License (GPL) Version 3 @@ -79,26 +80,38 @@ void PIDControlNE::Activate() void PIDControlNE::UpdateParameters(float kp, float ki, float kd, float beta, float dT, float velocityMax) { - // pid_configure(&PID, kp, ki, kd, ilimit); - float Ti = kp / ki; - float Td = kd / kp; - float Tt = (Ti + Td) / 2.0f; - float kt = 1.0f / Tt; + float Td; // Derivative time constant + float Ti; // Integral time constant + float kt; // Feedback gain for integral windup avoidance + float N = 10.0f; // N is the factor used to determine the + // time constant for derivative filtering + // Why 10? Maybe should be configurable? + float Tf; // Low pass filter time constant for derivative filtering + float u0 = 0.0f; - float N = 10.0f; - float Tf = Td / N; - - if (ki < 1e-6f) { - // Avoid Ti being infinite - Ti = 1e6f; - // Tt antiwindup time constant - we don't need antiwindup with no I term - Tt = 1e6f; + + // Define Td, handling zero kp term (for I or ID controller) + if (kp < 1e-6f) { + Td = 1e6f; + } else { + Td = kd / kp; + } + + // Define Ti, Tt and kt, handling zero ki term (for P or PD controller) + if (ki < 1e-6f) { // Avoid Ti being infinite kt = 0.0f; + } else { + Ti = kp / ki; + kt = 1.0f / Ti; } + // Define Tf, according to controller type if (kd < 1e-6f) { - // PI Controller - Tf = Ti / N; + // PI Controller or P Controller + Tf = 0; // Originally this: (Ti / N) - which creates a D term from + // the integral time constant! + } else { + Tf = Td / N; } if (beta > 1.0f) { @@ -107,6 +120,8 @@ void PIDControlNE::UpdateParameters(float kp, float ki, float kd, float beta, fl beta = 0.4f; } + + pid2_configure(&PIDvel[0], kp, ki, kd, Tf, kt, dT, beta, u0, 0.0f, 1.0f); pid2_configure(&PIDvel[1], kp, ki, kd, Tf, kt, dT, beta, u0, 0.0f, 1.0f); deltaTime = dT; From 143b5e7ab6e7b42e73e52b02e3c7cd411843234b Mon Sep 17 00:00:00 2001 From: paul Jewell Date: Sat, 10 Dec 2016 14:09:33 +0100 Subject: [PATCH 174/624] LP-289 Small change to comment --- flight/libraries/math/pid.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flight/libraries/math/pid.h b/flight/libraries/math/pid.h index eba64a5f95..8533afbf50 100644 --- a/flight/libraries/math/pid.h +++ b/flight/libraries/math/pid.h @@ -49,7 +49,7 @@ struct pid { // pid2 structure for a PID+setpoint weighting, anti-windup and filtered derivative control struct pid2 { float u0; // Initial value of r & y - for bumpless transfer - float va; // Actuator + float va; // Actuator settings for scaling float vb; float kp; // proportional gain float bi; // Integral gain . dT From ebc4b16d9a613ad48037a567554dccbbdc327a43 Mon Sep 17 00:00:00 2001 From: paul Jewell Date: Sun, 11 Dec 2016 05:45:47 +0100 Subject: [PATCH 175/624] LP-289 Clean up comments and uncrustify --- flight/libraries/math/pid.c | 2 +- flight/libraries/math/pid.h | 5 ++--- flight/libraries/pid/pidcontroldown.cpp | 3 +-- flight/modules/PathFollower/pidcontrolne.cpp | 7 ++----- 4 files changed, 6 insertions(+), 11 deletions(-) diff --git a/flight/libraries/math/pid.c b/flight/libraries/math/pid.c index dafff7b155..4fba369848 100644 --- a/flight/libraries/math/pid.c +++ b/flight/libraries/math/pid.c @@ -7,7 +7,7 @@ * * @file pid.c * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. - * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2015. + * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012. * @brief Methods to work with PID structure * * @see The GNU Public License (GPL) Version 3 diff --git a/flight/libraries/math/pid.h b/flight/libraries/math/pid.h index 8533afbf50..321b198c75 100644 --- a/flight/libraries/math/pid.h +++ b/flight/libraries/math/pid.h @@ -6,7 +6,6 @@ * @{ * * @file pid.h - * * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012. * @brief Methods to work with PID structure @@ -49,7 +48,7 @@ struct pid { // pid2 structure for a PID+setpoint weighting, anti-windup and filtered derivative control struct pid2 { float u0; // Initial value of r & y - for bumpless transfer - float va; // Actuator settings for scaling + float va; // Actuator settings for scaling float vb; float kp; // proportional gain float bi; // Integral gain . dT @@ -58,7 +57,7 @@ struct pid2 { float br; // Time constant for integral calculation float beta; // Scalar for proportional factor float yold; // t-1 y value for Integral calculation - float P; // Latest calculated P, I & D values + float P; // Latest calculated P, I & D values float I; float D; uint8_t reconfigure; diff --git a/flight/libraries/pid/pidcontroldown.cpp b/flight/libraries/pid/pidcontroldown.cpp index 253eaa682d..a7eb4a501d 100644 --- a/flight/libraries/pid/pidcontroldown.cpp +++ b/flight/libraries/pid/pidcontroldown.cpp @@ -117,8 +117,7 @@ void PIDControlDown::UpdateParameters(float kp, float ki, float kd, float beta, // Define Tf, according to controller type if (kd < 1e-6f) { // PI Controller or P Controller - Tf = 0; // Originally this: (Ti / N) - which creates a D term from - // the integral time constant! + Tf = 0; } else { Tf = Td / N; } diff --git a/flight/modules/PathFollower/pidcontrolne.cpp b/flight/modules/PathFollower/pidcontrolne.cpp index 5b4a61f115..5e208298fc 100644 --- a/flight/modules/PathFollower/pidcontrolne.cpp +++ b/flight/modules/PathFollower/pidcontrolne.cpp @@ -89,7 +89,7 @@ void PIDControlNE::UpdateParameters(float kp, float ki, float kd, float beta, fl float Tf; // Low pass filter time constant for derivative filtering float u0 = 0.0f; - + // Define Td, handling zero kp term (for I or ID controller) if (kp < 1e-6f) { Td = 1e6f; @@ -108,8 +108,7 @@ void PIDControlNE::UpdateParameters(float kp, float ki, float kd, float beta, fl // Define Tf, according to controller type if (kd < 1e-6f) { // PI Controller or P Controller - Tf = 0; // Originally this: (Ti / N) - which creates a D term from - // the integral time constant! + Tf = 0; } else { Tf = Td / N; } @@ -120,8 +119,6 @@ void PIDControlNE::UpdateParameters(float kp, float ki, float kd, float beta, fl beta = 0.4f; } - - pid2_configure(&PIDvel[0], kp, ki, kd, Tf, kt, dT, beta, u0, 0.0f, 1.0f); pid2_configure(&PIDvel[1], kp, ki, kd, Tf, kt, dT, beta, u0, 0.0f, 1.0f); deltaTime = dT; From fb5f9034eab3ba32f8408b2f4b1a7a5a40ecf644 Mon Sep 17 00:00:00 2001 From: Eric Price Date: Thu, 9 Mar 2017 18:48:36 +0100 Subject: [PATCH 176/624] LP-289 prevent initialization with non-zero pid->I accumulator (dangerous if kI is low) --- flight/libraries/math/pid.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/flight/libraries/math/pid.c b/flight/libraries/math/pid.c index 4fba369848..8f4babcb80 100644 --- a/flight/libraries/math/pid.c +++ b/flight/libraries/math/pid.c @@ -221,7 +221,10 @@ float pid2_apply( pid->D = 0.0f; // t=0, u=u0, y=y0, v=u - pid->I = (pid->u0 - pid->va) / pid->vb - pid->kp * (pid->beta * r - y); + // pid->I = (pid->u0 - pid->va) / pid->vb - pid->kp * (pid->beta * r - y); + // this is dangerous, if pid->I starts nonzero with very low or zero kI, then + // it will never settle! + pid->I = 0.0f; } // compute proportional part From dcb3d760db41665584fa1497a65693158203e152 Mon Sep 17 00:00:00 2001 From: paul Jewell Date: Thu, 9 Mar 2017 19:41:09 +0100 Subject: [PATCH 177/624] LP-289 Updated copyright notices --- flight/libraries/math/pid.c | 2 +- flight/libraries/math/pid.h | 2 +- flight/libraries/pid/pidcontroldown.cpp | 2 +- flight/modules/PathFollower/pidcontrolne.cpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/flight/libraries/math/pid.c b/flight/libraries/math/pid.c index 8f4babcb80..32f386f802 100644 --- a/flight/libraries/math/pid.c +++ b/flight/libraries/math/pid.c @@ -6,7 +6,7 @@ * @{ * * @file pid.c - * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017. * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012. * @brief Methods to work with PID structure * diff --git a/flight/libraries/math/pid.h b/flight/libraries/math/pid.h index 321b198c75..21d19c4d11 100644 --- a/flight/libraries/math/pid.h +++ b/flight/libraries/math/pid.h @@ -6,7 +6,7 @@ * @{ * * @file pid.h - * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017. * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012. * @brief Methods to work with PID structure * diff --git a/flight/libraries/pid/pidcontroldown.cpp b/flight/libraries/pid/pidcontroldown.cpp index a7eb4a501d..0a1455776b 100644 --- a/flight/libraries/pid/pidcontroldown.cpp +++ b/flight/libraries/pid/pidcontroldown.cpp @@ -7,7 +7,7 @@ * @{ * * @file pidcontroldown.h - * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017. * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2015. * @brief Executes PID control for down direction * diff --git a/flight/modules/PathFollower/pidcontrolne.cpp b/flight/modules/PathFollower/pidcontrolne.cpp index 5e208298fc..b947e69526 100644 --- a/flight/modules/PathFollower/pidcontrolne.cpp +++ b/flight/modules/PathFollower/pidcontrolne.cpp @@ -7,7 +7,7 @@ * @{ * * @file PIDControlNE.h - * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017. * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2015. * @brief Executes PID control loops for NE directions * From c056e73b9308555402a16c6ed6ee038b242aeb1a Mon Sep 17 00:00:00 2001 From: paul Jewell Date: Thu, 9 Mar 2017 20:14:07 +0100 Subject: [PATCH 178/624] LP-289 Removed orphaned doxygen addtogroup directives --- flight/libraries/math/pid.c | 5 ----- flight/libraries/math/pid.h | 5 ----- 2 files changed, 10 deletions(-) diff --git a/flight/libraries/math/pid.c b/flight/libraries/math/pid.c index 32f386f802..ab02aa1032 100644 --- a/flight/libraries/math/pid.c +++ b/flight/libraries/math/pid.c @@ -1,10 +1,5 @@ /** ****************************************************************************** - * @addtogroup OpenPilot Math Utilities - * @{ - * @addtogroup Sine and cosine methods that use a cached lookup table - * @{ - * * @file pid.c * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017. * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012. diff --git a/flight/libraries/math/pid.h b/flight/libraries/math/pid.h index 21d19c4d11..a6ef5dcfe6 100644 --- a/flight/libraries/math/pid.h +++ b/flight/libraries/math/pid.h @@ -1,10 +1,5 @@ /** ****************************************************************************** - * @addtogroup OpenPilot Math Utilities - * @{ - * @addtogroup Sine and cosine methods that use a cached lookup table - * @{ - * * @file pid.h * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017. * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012. From d47956c7e6cc5526a31ba92d29765a18eb001bc5 Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Fri, 10 Mar 2017 09:54:40 +0100 Subject: [PATCH 179/624] LP-493 uavobjectbrowser: properly restore highlight color and other attributes when changing view options --- .../src/plugins/uavobjectbrowser/uavobjectbrowserwidget.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowserwidget.cpp b/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowserwidget.cpp index cdca774c91..93b1b76c51 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowserwidget.cpp +++ b/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowserwidget.cpp @@ -271,9 +271,11 @@ void UAVObjectBrowserWidget::updateViewOptions() m_viewoptions->cbMetaData->isChecked(), m_viewoptions->cbScientific->isChecked()); + model->setUnknowObjectColor(m_unknownObjectColor); + model->setRecentlyUpdatedColor(m_recentlyUpdatedColor); model->setManuallyChangedColor(m_manuallyChangedColor); model->setRecentlyUpdatedTimeout(m_recentlyUpdatedTimeout); - model->setUnknowObjectColor(m_unknownObjectColor); + model->setOnlyHilightChangedValues(m_onlyHilightChangedValues); UAVObjectTreeModel *tmpModel = m_model; m_model = model; From a696b961fe1d83712dc53d65f29efda39cf063ac Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Sun, 12 Mar 2017 21:15:20 +0100 Subject: [PATCH 180/624] LP-494 UAVObjectBrowser: properly initialize multi-element enum/bitfield field --- ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp b/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp index 1a07bbea3b..8f5941a488 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp +++ b/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp @@ -227,7 +227,7 @@ void UAVObjectTreeModel::addSingleField(int index, UAVObjectField *field, TreeIt case UAVObjectField::ENUM: { QStringList options = field->getOptions(); - QVariant value = field->getValue(); + QVariant value = field->getValue(index); data.append(options.indexOf(value.toString())); data.append(field->getUnits()); item = new EnumFieldTreeItem(field, index, data); From 1203fa9e665b1ed0236c7456e1b5f064e3366460 Mon Sep 17 00:00:00 2001 From: Vladimir Zidar Date: Wed, 15 Mar 2017 16:33:52 +0100 Subject: [PATCH 181/624] LP-495 F4 USB CDC: remove internal rx_active state tracking and use actual endpoint status instead (like F1) --- flight/pios/inc/pios_usbhook.h | 3 +++ flight/pios/stm32f4xx/pios_usb_cdc.c | 9 +++------ flight/pios/stm32f4xx/pios_usbhook.c | 5 +++++ 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/flight/pios/inc/pios_usbhook.h b/flight/pios/inc/pios_usbhook.h index 2d826bc2a7..0bf154a246 100644 --- a/flight/pios/inc/pios_usbhook.h +++ b/flight/pios/inc/pios_usbhook.h @@ -74,4 +74,7 @@ extern void PIOS_USBHOOK_EndpointRx(uint8_t epnum, uint8_t *buf, uint16_t len); extern void PIOS_USBHOOK_Activate(void); extern void PIOS_USBHOOK_Deactivate(void); +extern uint32_t PIOS_USBHOOK_EndpointGetStatus(uint8_t epnum); + + #endif /* PIOS_USBHOOK_H */ diff --git a/flight/pios/stm32f4xx/pios_usb_cdc.c b/flight/pios/stm32f4xx/pios_usb_cdc.c index c641264440..6f091eaa8a 100644 --- a/flight/pios/stm32f4xx/pios_usb_cdc.c +++ b/flight/pios/stm32f4xx/pios_usb_cdc.c @@ -36,6 +36,7 @@ #include "pios_usb_cdc_priv.h" #include "pios_usb_board_data.h" /* PIOS_BOARD_*_DATA_LENGTH */ #include "pios_usbhook.h" /* PIOS_USBHOOK_* */ +#include "usb_core.h" /* USB_OTG_EP_RX_VALID */ /* Implement COM layer driver API */ static void PIOS_USB_CDC_RegisterTxCallback(uint32_t usbcdc_id, pios_com_callback tx_out_cb, uint32_t context); @@ -84,7 +85,6 @@ struct pios_usb_cdc_dev { bool usb_data_if_enabled; uint8_t rx_packet_buffer[PIOS_USB_BOARD_CDC_DATA_LENGTH] __attribute__((aligned(4))); - volatile bool rx_active; /* * NOTE: This is -1 as somewhat of a hack. It ensures that we always send packets @@ -192,7 +192,6 @@ int32_t PIOS_USB_CDC_Init(uint32_t *usbcdc_id, const struct pios_usb_cdc_cfg *cf pios_usb_cdc_id = (uint32_t)usb_cdc_dev; /* Rx and Tx are not active yet */ - usb_cdc_dev->rx_active = false; usb_cdc_dev->tx_active = false; /* Clear stats */ @@ -275,11 +274,11 @@ static void PIOS_USB_CDC_RxStart(uint32_t usbcdc_id, uint16_t rx_bytes_avail) } // If endpoint was stalled and there is now space make it valid - if (!usb_cdc_dev->rx_active && (rx_bytes_avail >= PIOS_USB_BOARD_CDC_DATA_LENGTH)) { + if ((PIOS_USBHOOK_EndpointGetStatus(usb_cdc_dev->cfg->data_rx_ep) != USB_OTG_EP_RX_VALID) + && (rx_bytes_avail >= PIOS_USB_BOARD_CDC_DATA_LENGTH)) { PIOS_USBHOOK_EndpointRx(usb_cdc_dev->cfg->data_rx_ep, usb_cdc_dev->rx_packet_buffer, sizeof(usb_cdc_dev->rx_packet_buffer)); - usb_cdc_dev->rx_active = true; } } @@ -687,7 +686,6 @@ static bool PIOS_USB_CDC_DATA_EP_OUT_Callback( if (!usb_cdc_dev->rx_in_cb) { /* No Rx call back registered, disable the receiver */ - usb_cdc_dev->rx_active = false; return false; } @@ -714,7 +712,6 @@ static bool PIOS_USB_CDC_DATA_EP_OUT_Callback( rc = true; } else { /* Not enough room left for a message, apply backpressure */ - usb_cdc_dev->rx_active = false; rc = false; } diff --git a/flight/pios/stm32f4xx/pios_usbhook.c b/flight/pios/stm32f4xx/pios_usbhook.c index dc276c4915..0d58a5e10d 100644 --- a/flight/pios/stm32f4xx/pios_usbhook.c +++ b/flight/pios/stm32f4xx/pios_usbhook.c @@ -218,6 +218,11 @@ void PIOS_USBHOOK_EndpointRx(uint8_t epnum, uint8_t *buf, uint16_t len) DCD_EP_PrepareRx(&pios_usb_otg_core_handle, epnum, buf, len); } +uint32_t PIOS_USBHOOK_EndpointGetStatus(uint8_t epnum) +{ + return DCD_GetEPStatus(&pios_usb_otg_core_handle, epnum); +} + /* * Device level hooks into STM USB library */ From c35c949e60cbeb2daef82f0c5ec9a1164e75bacc Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Sun, 19 Mar 2017 19:25:02 +0100 Subject: [PATCH 182/624] LP-496 fix actions on stabilization bank settings on not active tab --- .../config/configstabilizationwidget.cpp | 174 +++++++++--------- .../config/configstabilizationwidget.h | 22 +-- 2 files changed, 94 insertions(+), 102 deletions(-) diff --git a/ground/gcs/src/plugins/config/configstabilizationwidget.cpp b/ground/gcs/src/plugins/config/configstabilizationwidget.cpp index f4691a9cc4..046c31f439 100644 --- a/ground/gcs/src/plugins/config/configstabilizationwidget.cpp +++ b/ground/gcs/src/plugins/config/configstabilizationwidget.cpp @@ -156,19 +156,8 @@ void ConfigStabilizationWidget::setupStabBanksGUI() m_stabTabBars.append(ui->advancedPIDBankTabBar); QAction *defaultStabMenuAction = new QAction(QIcon(":configgadget/images/gear.png"), QString(), this); - QAction *restoreAllAction = new QAction(tr("all to saved"), this); - connect(restoreAllAction, SIGNAL(triggered()), this, SLOT(restoreAllStabBanks())); - QAction *resetAllAction = new QAction(tr("all to default"), this); - connect(resetAllAction, SIGNAL(triggered()), this, SLOT(resetAllStabBanks())); - QAction *restoreCurrentAction = new QAction(tr("to saved"), this); - connect(restoreCurrentAction, SIGNAL(triggered()), this, SLOT(restoreCurrentAction())); - QAction *resetCurrentAction = new QAction(tr("to default"), this); - connect(resetCurrentAction, SIGNAL(triggered()), this, SLOT(resetCurrentStabBank())); - QAction *copyCurrentAction = new QAction(tr("to others"), this); - connect(copyCurrentAction, SIGNAL(triggered()), this, SLOT(copyCurrentStabBank())); - connect(&m_stabSettingsCopyFromSignalMapper, SIGNAL(mapped(int)), this, SLOT(copyFromBankToCurrent(int))); - connect(&m_stabSettingsCopyToSignalMapper, SIGNAL(mapped(int)), this, SLOT(copyToBankFromCurrent(int))); - connect(&m_stabSettingsSwapSignalMapper, SIGNAL(mapped(int)), this, SLOT(swapBankAndCurrent(int))); + + connect(&m_bankActionSignalMapper, SIGNAL(mapped(QString)), this, SLOT(bankAction(QString))); foreach(QTabBar * tabBar, m_stabTabBars) { for (int i = 0; i < m_stabSettingsBankCount; i++) { @@ -179,7 +168,7 @@ void ConfigStabilizationWidget::setupStabBanksGUI() tabButton->setDefaultAction(defaultStabMenuAction); tabButton->setAutoRaise(true); tabButton->setPopupMode(QToolButton::InstantPopup); - tabButton->setToolTip(tr("The functions in this menu effect all fields in the settings banks,\n" + tabButton->setToolTip(tr("The functions in this menu affect all fields in the settings banks,\n" "not only the ones visible on screen.")); QMenu *tabMenu = new QMenu(); QMenu *restoreMenu = new QMenu(tr("Restore")); @@ -188,29 +177,49 @@ void ConfigStabilizationWidget::setupStabBanksGUI() QMenu *swapMenu = new QMenu(tr("Swap")); QAction *menuAction; for (int j = 0; j < m_stabSettingsBankCount; j++) { - if (j == i) { - restoreMenu->addAction(restoreCurrentAction); - resetMenu->addAction(resetCurrentAction); - copyMenu->addAction(copyCurrentAction); - } else { + if (j != i) { menuAction = new QAction(tr("from %1").arg(j + 1), this); - connect(menuAction, SIGNAL(triggered()), &m_stabSettingsCopyFromSignalMapper, SLOT(map())); - m_stabSettingsCopyFromSignalMapper.setMapping(menuAction, j); + connect(menuAction, SIGNAL(triggered()), &m_bankActionSignalMapper, SLOT(map())); + m_bankActionSignalMapper.setMapping(menuAction, QString("copy:%1:%2").arg(i).arg(j)); copyMenu->addAction(menuAction); menuAction = new QAction(tr("to %1").arg(j + 1), this); - connect(menuAction, SIGNAL(triggered()), &m_stabSettingsCopyToSignalMapper, SLOT(map())); - m_stabSettingsCopyToSignalMapper.setMapping(menuAction, j); + connect(menuAction, SIGNAL(triggered()), &m_bankActionSignalMapper, SLOT(map())); + m_bankActionSignalMapper.setMapping(menuAction, QString("copy:%1:%2").arg(j).arg(i)); copyMenu->addAction(menuAction); menuAction = new QAction(tr("with %1").arg(j + 1), this); - connect(menuAction, SIGNAL(triggered()), &m_stabSettingsSwapSignalMapper, SLOT(map())); - m_stabSettingsSwapSignalMapper.setMapping(menuAction, j); + connect(menuAction, SIGNAL(triggered()), &m_bankActionSignalMapper, SLOT(map())); + m_bankActionSignalMapper.setMapping(menuAction, QString("swap:%1:%2").arg(i).arg(j)); swapMenu->addAction(menuAction); } } - restoreMenu->addAction(restoreAllAction); - resetMenu->addAction(resetAllAction); + // copy bank to all others + menuAction = new QAction(tr("to others"), this); + connect(menuAction, SIGNAL(triggered()), &m_bankActionSignalMapper, SLOT(map())); + m_bankActionSignalMapper.setMapping(menuAction, QString("copyAll:%1").arg(i)); + copyMenu->addAction(menuAction); + // restore + menuAction = new QAction(tr("to saved"), this); + connect(menuAction, SIGNAL(triggered()), &m_bankActionSignalMapper, SLOT(map())); + m_bankActionSignalMapper.setMapping(menuAction, QString("restore:%1").arg(i)); + restoreMenu->addAction(menuAction); + // restore all + menuAction = new QAction(tr("all to saved"), this); + connect(menuAction, SIGNAL(triggered()), &m_bankActionSignalMapper, SLOT(map())); + m_bankActionSignalMapper.setMapping(menuAction, "restoreAll"); + restoreMenu->addAction(menuAction); + // reset + menuAction = new QAction(tr("to default"), this); + connect(menuAction, SIGNAL(triggered()), &m_bankActionSignalMapper, SLOT(map())); + m_bankActionSignalMapper.setMapping(menuAction, QString("reset:%1").arg(i)); + resetMenu->addAction(menuAction); + // reset all + menuAction = new QAction(tr("all to default"), this); + connect(menuAction, SIGNAL(triggered()), &m_bankActionSignalMapper, SLOT(map())); + m_bankActionSignalMapper.setMapping(menuAction, "resetAll"); + resetMenu->addAction(menuAction); + // menu tabMenu->addMenu(copyMenu); tabMenu->addMenu(swapMenu); tabMenu->addMenu(resetMenu); @@ -421,34 +430,14 @@ void ConfigStabilizationWidget::replotExpoYaw(int value) replotExpo(value, m_expoPlotCurveYaw); } -void ConfigStabilizationWidget::restoreAllStabBanks() -{ - for (int i = 0; i < m_stabSettingsBankCount; i++) { - restoreStabBank(i); - } -} - -void ConfigStabilizationWidget::resetAllStabBanks() -{ - for (int i = 0; i < m_stabSettingsBankCount; i++) { - resetStabBank(i); - } -} - -void ConfigStabilizationWidget::restoreCurrentAction() -{ - restoreStabBank(m_currentStabSettingsBank); -} - UAVObject *ConfigStabilizationWidget::getStabBankObject(int bank) { return getObject(QString("StabilizationSettingsBank%1").arg(bank + 1)); } -void ConfigStabilizationWidget::resetStabBank(int bank) +void ConfigStabilizationWidget::resetBank(int bank) { - UAVDataObject *stabBankObject = - dynamic_cast(getStabBankObject(bank)); + UAVDataObject *stabBankObject = dynamic_cast(getStabBankObject(bank)); if (stabBankObject) { UAVDataObject *defaultStabBankObject = stabBankObject->dirtyClone(); @@ -458,7 +447,7 @@ void ConfigStabilizationWidget::resetStabBank(int bank) } } -void ConfigStabilizationWidget::restoreStabBank(int bank) +void ConfigStabilizationWidget::restoreBank(int bank) { UAVObject *stabBankObject = getStabBankObject(bank); @@ -485,30 +474,7 @@ void ConfigStabilizationWidget::restoreStabBank(int bank) } } -void ConfigStabilizationWidget::resetCurrentStabBank() -{ - resetStabBank(m_currentStabSettingsBank); -} - -void ConfigStabilizationWidget::copyCurrentStabBank() -{ - UAVObject *fromStabBankObject = getStabBankObject(m_currentStabSettingsBank); - - if (fromStabBankObject) { - quint8 fromStabBankObjectData[fromStabBankObject->getNumBytes()]; - fromStabBankObject->pack(fromStabBankObjectData); - for (int i = 0; i < m_stabSettingsBankCount; i++) { - if (i != m_currentStabSettingsBank) { - UAVObject *toStabBankObject = getStabBankObject(i); - if (toStabBankObject) { - toStabBankObject->unpack(fromStabBankObjectData); - } - } - } - } -} - -void ConfigStabilizationWidget::copyFromBankToBank(int fromBank, int toBank) +void ConfigStabilizationWidget::copyBank(int fromBank, int toBank) { UAVObject *fromStabBankObject = getStabBankObject(fromBank); UAVObject *toStabBankObject = getStabBankObject(toBank); @@ -520,20 +486,10 @@ void ConfigStabilizationWidget::copyFromBankToBank(int fromBank, int toBank) } } -void ConfigStabilizationWidget::copyFromBankToCurrent(int bank) -{ - copyFromBankToBank(bank, m_currentStabSettingsBank); -} - -void ConfigStabilizationWidget::copyToBankFromCurrent(int bank) -{ - copyFromBankToBank(m_currentStabSettingsBank, bank); -} - -void ConfigStabilizationWidget::swapBankAndCurrent(int bank) +void ConfigStabilizationWidget::swapBank(int fromBank, int toBank) { - UAVObject *fromStabBankObject = getStabBankObject(m_currentStabSettingsBank); - UAVObject *toStabBankObject = getStabBankObject(bank); + UAVObject *fromStabBankObject = getStabBankObject(fromBank); + UAVObject *toStabBankObject = getStabBankObject(toBank); if (fromStabBankObject && toStabBankObject) { quint8 fromStabBankObjectData[fromStabBankObject->getNumBytes()]; @@ -545,6 +501,50 @@ void ConfigStabilizationWidget::swapBankAndCurrent(int bank) } } +void ConfigStabilizationWidget::bankAction(const QString &mapping) +{ + QStringList list = mapping.split(":"); + QString action = list[0]; + + if (action == "copy") { + int fromBank = list[1].toInt(); + Q_ASSERT((fromBank >= 0) && (fromBank < m_stabSettingsBankCount)); + int toBank = list[2].toInt(); + Q_ASSERT((toBank >= 0) && (toBank < m_stabSettingsBankCount)); + copyBank(fromBank, toBank); + } else if (action == "copyAll") { + int fromBank = list[1].toInt(); + Q_ASSERT((fromBank >= 0) && (fromBank < m_stabSettingsBankCount)); + for (int toBank = 0; toBank < m_stabSettingsBankCount; toBank++) { + if (fromBank != toBank) { + copyBank(fromBank, toBank); + } + } + } else if (action == "swap") { + int fromBank = list[1].toInt(); + Q_ASSERT((fromBank >= 0) && (fromBank < m_stabSettingsBankCount)); + int toBank = list[2].toInt(); + Q_ASSERT((toBank >= 0) && (toBank < m_stabSettingsBankCount)); + swapBank(fromBank, toBank); + } else if (action == "restore") { + int bank = list[1].toInt(); + Q_ASSERT((bank >= 0) && (bank < m_stabSettingsBankCount)); + restoreBank(bank); + } else if (action == "restoreAll") { + for (int bank = 0; bank < m_stabSettingsBankCount; bank++) { + restoreBank(bank); + } + } else if (action == "reset") { + int bank = list[1].toInt(); + Q_ASSERT((bank >= 0) && (bank < m_stabSettingsBankCount)); + resetBank(bank); + } else if (action == "resetAll") { + for (int bank = 0; bank < m_stabSettingsBankCount; bank++) { + resetBank(bank); + } + } +} + void ConfigStabilizationWidget::realtimeUpdatesSlot(bool value) { ui->realTimeUpdates_6->setChecked(value); diff --git a/ground/gcs/src/plugins/config/configstabilizationwidget.h b/ground/gcs/src/plugins/config/configstabilizationwidget.h index f0a12b4517..525f66c396 100644 --- a/ground/gcs/src/plugins/config/configstabilizationwidget.h +++ b/ground/gcs/src/plugins/config/configstabilizationwidget.h @@ -77,9 +77,8 @@ class ConfigStabilizationWidget : public ConfigTaskWidget { QwtPlotCurve m_expoPlotCurvePitch; QwtPlotCurve m_expoPlotCurveYaw; QwtPlotGrid m_plotGrid; - QSignalMapper m_stabSettingsCopyFromSignalMapper; - QSignalMapper m_stabSettingsCopyToSignalMapper; - QSignalMapper m_stabSettingsSwapSignalMapper; + + QSignalMapper m_bankActionSignalMapper; UAVObject *getStabBankObject(int bank); @@ -87,8 +86,10 @@ class ConfigStabilizationWidget : public ConfigTaskWidget { void updateObjectFromThrottleCurve(); void setupExpoPlot(); void setupStabBanksGUI(); - void resetStabBank(int bank); - void restoreStabBank(int bank); + void resetBank(int bank); + void restoreBank(int bank); + void copyBank(int fromBank, int toBank); + void swapBank(int fromBank, int toBank); private slots: void enableControlsChanged(bool enable); @@ -104,15 +105,6 @@ private slots: void replotExpoPitch(int value); void replotExpoYaw(int value); - void restoreAllStabBanks(); - void resetAllStabBanks(); - void restoreCurrentAction(); - void resetCurrentStabBank(); - void copyCurrentStabBank(); - - void copyFromBankToBank(int fromBank, int toBank); - void copyFromBankToCurrent(int bank); - void copyToBankFromCurrent(int bank); - void swapBankAndCurrent(int bank); + void bankAction(const QString &mapping); }; #endif // ConfigStabilizationWidget_H From 8c3da1139bf55da2befc79a581c459c4f569eea9 Mon Sep 17 00:00:00 2001 From: Corvus Corax Date: Tue, 21 Mar 2017 08:25:35 +0100 Subject: [PATCH 183/624] LP-498 Optionally display currently active PathDesired in map --- .../opmapcontrol/src/mapwidget/images/nav.svg | 126 ++++++++++++++++++ .../src/mapwidget/mapresources.qrc | 1 + .../opmapcontrol/src/mapwidget/mapwidget.pro | 2 + .../opmapcontrol/src/mapwidget/navitem.cpp | 99 ++++++++++++++ .../libs/opmapcontrol/src/mapwidget/navitem.h | 85 ++++++++++++ .../src/mapwidget/opmapwidget.cpp | 12 +- .../opmapcontrol/src/mapwidget/opmapwidget.h | 9 ++ .../src/plugins/opmap/opmapgadgetwidget.cpp | 85 ++++++++++++ .../gcs/src/plugins/opmap/opmapgadgetwidget.h | 3 + 9 files changed, 420 insertions(+), 2 deletions(-) create mode 100644 ground/gcs/src/libs/opmapcontrol/src/mapwidget/images/nav.svg create mode 100644 ground/gcs/src/libs/opmapcontrol/src/mapwidget/navitem.cpp create mode 100644 ground/gcs/src/libs/opmapcontrol/src/mapwidget/navitem.h diff --git a/ground/gcs/src/libs/opmapcontrol/src/mapwidget/images/nav.svg b/ground/gcs/src/libs/opmapcontrol/src/mapwidget/images/nav.svg new file mode 100644 index 0000000000..63fa6a97e8 --- /dev/null +++ b/ground/gcs/src/libs/opmapcontrol/src/mapwidget/images/nav.svg @@ -0,0 +1,126 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/ground/gcs/src/libs/opmapcontrol/src/mapwidget/mapresources.qrc b/ground/gcs/src/libs/opmapcontrol/src/mapwidget/mapresources.qrc index b7709e2cca..3e0c53a0e9 100644 --- a/ground/gcs/src/libs/opmapcontrol/src/mapwidget/mapresources.qrc +++ b/ground/gcs/src/libs/opmapcontrol/src/mapwidget/mapresources.qrc @@ -6,6 +6,7 @@ images/airplane.svg images/home.png images/home.svg + images/nav.svg images/home2.svg images/airplanepip.png images/EasystarBlue.png diff --git a/ground/gcs/src/libs/opmapcontrol/src/mapwidget/mapwidget.pro b/ground/gcs/src/libs/opmapcontrol/src/mapwidget/mapwidget.pro index 5d4e3e3469..1af31f4a62 100644 --- a/ground/gcs/src/libs/opmapcontrol/src/mapwidget/mapwidget.pro +++ b/ground/gcs/src/libs/opmapcontrol/src/mapwidget/mapwidget.pro @@ -12,6 +12,7 @@ SOURCES += mapgraphicitem.cpp \ gpsitem.cpp \ trailitem.cpp \ homeitem.cpp \ + navitem.cpp \ mapripform.cpp \ mapripper.cpp \ traillineitem.cpp \ @@ -39,6 +40,7 @@ HEADERS += mapgraphicitem.h \ uavtrailtype.h \ trailitem.h \ homeitem.h \ + navitem.h \ mapripform.h \ mapripper.h \ traillineitem.h \ diff --git a/ground/gcs/src/libs/opmapcontrol/src/mapwidget/navitem.cpp b/ground/gcs/src/libs/opmapcontrol/src/mapwidget/navitem.cpp new file mode 100644 index 0000000000..164a7712c5 --- /dev/null +++ b/ground/gcs/src/libs/opmapcontrol/src/mapwidget/navitem.cpp @@ -0,0 +1,99 @@ +/** + ****************************************************************************** + * + * @file navitem.cpp + * @author The LibrePilot Team, http://www.openpilot.org Copyright (C) 2017. + * @brief A graphicsItem representing a trail point + * @see The GNU Public License (GPL) Version 3 + * @defgroup OPMapWidget + * @{ + * + *****************************************************************************/ +/* + * 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 "navitem.h" +#include +namespace mapcontrol { +NavItem::NavItem(MapGraphicItem *map, OPMapWidget *parent) : map(map), mapwidget(parent), + toggleRefresh(true), altitude(0) +{ + pic.load(QString::fromUtf8(":/markers/images/nav.svg")); + pic = pic.scaled(30, 30, Qt::IgnoreAspectRatio); + this->setFlag(QGraphicsItem::ItemIgnoresTransformations, true); + this->setFlag(QGraphicsItem::ItemIsMovable, false); + this->setFlag(QGraphicsItem::ItemIsSelectable, true); + localposition = map->FromLatLngToLocal(mapwidget->CurrentPosition()); + this->setPos(localposition.X(), localposition.Y()); + this->setZValue(4); + coord = internals::PointLatLng(50, 50); + RefreshToolTip(); + setCacheMode(QGraphicsItem::DeviceCoordinateCache); + connect(map, SIGNAL(childRefreshPosition()), this, SLOT(RefreshPos())); + connect(map, SIGNAL(childSetOpacity(qreal)), this, SLOT(setOpacitySlot(qreal))); +} + +void NavItem::RefreshToolTip() +{ + QString coord_str = " " + QString::number(coord.Lat(), 'f', 6) + " " + QString::number(coord.Lng(), 'f', 6); + + setToolTip(QString("Waypoint: Nav\nCoordinate:%1\nAltitude:%2\n").arg(coord_str).arg(QString::number(altitude))); +} + + +void NavItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_UNUSED(option); + Q_UNUSED(widget); + painter->drawPixmap(-pic.width() / 2, -pic.height() / 2, pic); +} +QRectF NavItem::boundingRect() const +{ + return QRectF(-pic.width() / 2, -pic.height() / 2, pic.width(), pic.height()); +} + + +int NavItem::type() const +{ + return Type; +} + +void NavItem::RefreshPos() +{ + prepareGeometryChange(); + localposition = map->FromLatLngToLocal(coord); + this->setPos(localposition.X(), localposition.Y()); + + RefreshToolTip(); + + this->update(); + toggleRefresh = false; +} + +void NavItem::setOpacitySlot(qreal opacity) +{ + setOpacity(opacity); +} + + +// Set clickable area as smaller than the bounding rect. +QPainterPath NavItem::shape() const +{ + QPainterPath path; + + path.addEllipse(QRectF(-12, -25, 24, 50)); + return path; +} +} diff --git a/ground/gcs/src/libs/opmapcontrol/src/mapwidget/navitem.h b/ground/gcs/src/libs/opmapcontrol/src/mapwidget/navitem.h new file mode 100644 index 0000000000..86e4bbe5ae --- /dev/null +++ b/ground/gcs/src/libs/opmapcontrol/src/mapwidget/navitem.h @@ -0,0 +1,85 @@ +/** + ****************************************************************************** + * + * @file navitem.h + * @author The LibrePilot Team, http://www.librepilot.org Copyright (C) 2017. + * @brief A graphicsItem representing a WayPoint + * @see The GNU Public License (GPL) Version 3 + * @defgroup OPMapWidget + * @{ + * + *****************************************************************************/ +/* + * 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 NAVITEM_H +#define NAVITEM_H + +#include +#include +#include +#include "../internals/pointlatlng.h" +#include +#include "opmapwidget.h" +namespace mapcontrol { +class NavItem : public QObject, public QGraphicsItem { + Q_OBJECT Q_INTERFACES(QGraphicsItem) +public: + enum { Type = UserType + 4 }; + NavItem(MapGraphicItem *map, OPMapWidget *parent); + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, + QWidget *widget); + QRectF boundingRect() const; + int type() const; + void SetToggleRefresh(bool const & value) + { + toggleRefresh = value; + } + void SetCoord(internals::PointLatLng const & value) + { + coord = value; emit navPositionChanged(value, Altitude()); + } + internals::PointLatLng Coord() const + { + return coord; + } + void SetAltitude(float const & value) + { + altitude = value; emit navPositionChanged(Coord(), Altitude()); + } + float Altitude() const + { + return altitude; + } + void RefreshToolTip(); +private: + + MapGraphicItem *map; + OPMapWidget *mapwidget; + QPixmap pic; + core::Point localposition; + internals::PointLatLng coord; + bool toggleRefresh; + float altitude; +protected: + QPainterPath shape() const; +public slots: + void RefreshPos(); + void setOpacitySlot(qreal opacity); +signals: + void navPositionChanged(internals::PointLatLng coord, float); +}; +} +#endif // NAVITEM_H diff --git a/ground/gcs/src/libs/opmapcontrol/src/mapwidget/opmapwidget.cpp b/ground/gcs/src/libs/opmapcontrol/src/mapwidget/opmapwidget.cpp index f38632da42..1e2cd40925 100644 --- a/ground/gcs/src/libs/opmapcontrol/src/mapwidget/opmapwidget.cpp +++ b/ground/gcs/src/libs/opmapcontrol/src/mapwidget/opmapwidget.cpp @@ -33,8 +33,8 @@ #include namespace mapcontrol { -OPMapWidget::OPMapWidget(QWidget *parent, Configuration *config) : QGraphicsView(parent), configuration(config), UAV(0), GPS(0), Home(0) - , followmouse(true), compass(0), showuav(false), showhome(false), diagTimer(0), diagGraphItem(0), showDiag(false), overlayOpacity(1) +OPMapWidget::OPMapWidget(QWidget *parent, Configuration *config) : QGraphicsView(parent), configuration(config), UAV(0), GPS(0), Home(0), Nav(0) + , followmouse(true), compass(0), showuav(false), showhome(false), diagTimer(0), diagGraphItem(0), showDiag(false), showNav(false), overlayOpacity(1) { setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); core = new internals::Core; @@ -44,6 +44,9 @@ OPMapWidget::OPMapWidget(QWidget *parent, Configuration *config) : QGraphicsView Home = new HomeItem(map, this); Home->setParentItem(map); Home->setZValue(-1); + Nav = new NavItem(map, this); + Nav->setParentItem(map); + Nav->setZValue(-1); setStyleSheet("QToolTip {font-size:8pt; color:blue;opacity: 223; padding:2px; border-width:2px; border-style:solid; border-color: rgb(170, 170, 127);border-radius:4px }"); this->adjustSize(); connect(map, SIGNAL(zoomChanged(double, double, double)), this, SIGNAL(zoomChanged(double, double, double))); @@ -58,6 +61,7 @@ OPMapWidget::OPMapWidget(QWidget *parent, Configuration *config) : QGraphicsView connect(map, SIGNAL(wpdoubleclicked(WayPointItem *)), this, SIGNAL(OnWayPointDoubleClicked(WayPointItem *))); connect(&mscene, SIGNAL(selectionChanged()), this, SLOT(OnSelectionChanged())); SetShowDiagnostics(showDiag); + SetShowNav(showNav); this->setMouseTracking(followmouse); SetShowCompass(true); QPixmapCache::setCacheLimit(64 * 1024); @@ -158,6 +162,10 @@ void OPMapWidget::SetShowHome(const bool &value) { Home->setVisible(value); } +void OPMapWidget::SetShowNav(const bool &value) +{ + Nav->setVisible(value); +} void OPMapWidget::resizeEvent(QResizeEvent *event) { diff --git a/ground/gcs/src/libs/opmapcontrol/src/mapwidget/opmapwidget.h b/ground/gcs/src/libs/opmapcontrol/src/mapwidget/opmapwidget.h index 4f7d9d7fc3..e8519a34ab 100644 --- a/ground/gcs/src/libs/opmapcontrol/src/mapwidget/opmapwidget.h +++ b/ground/gcs/src/libs/opmapcontrol/src/mapwidget/opmapwidget.h @@ -37,6 +37,7 @@ #include "uavitem.h" #include "gpsitem.h" #include "homeitem.h" +#include "navitem.h" #include "mapripper.h" #include "waypointline.h" #include "waypointcircle.h" @@ -50,6 +51,7 @@ namespace mapcontrol { class UAVItem; class GPSItem; class HomeItem; +class NavItem; /** * @brief Collection of static functions to help dealing with various enums used * Contains functions for enumToString conversio, StringToEnum, QStringList of enum values... @@ -500,6 +502,7 @@ class OPMapWidget : public QGraphicsView { UAVItem *UAV; GPSItem *GPS; HomeItem *Home; + NavItem *Nav; void SetShowUAV(bool const & value); bool ShowUAV() const { @@ -510,6 +513,11 @@ class OPMapWidget : public QGraphicsView { { return showhome; } + void SetShowNav(bool const & value); + bool ShowNav() const + { + return showNav; + } void SetShowDiagnostics(bool const & value); void SetUavPic(QString UAVPic); WayPointLine *WPLineCreate(WayPointItem *from, WayPointItem *to, QColor color, bool dashed = false, int width = -1); @@ -540,6 +548,7 @@ class OPMapWidget : public QGraphicsView { QTimer *diagTimer; QGraphicsTextItem *diagGraphItem; bool showDiag; + bool showNav; qreal overlayOpacity; private slots: void diagRefresh(); diff --git a/ground/gcs/src/plugins/opmap/opmapgadgetwidget.cpp b/ground/gcs/src/plugins/opmap/opmapgadgetwidget.cpp index 0b6994bfb6..03092cffd6 100644 --- a/ground/gcs/src/plugins/opmap/opmapgadgetwidget.cpp +++ b/ground/gcs/src/plugins/opmap/opmapgadgetwidget.cpp @@ -50,6 +50,7 @@ #include "uavobject.h" #include "positionstate.h" +#include "pathdesired.h" #include "homelocation.h" #include "gpspositionsensor.h" #include "gyrostate.h" @@ -166,6 +167,7 @@ OPMapGadgetWidget::OPMapGadgetWidget(QWidget *parent) : QWidget(parent) m_map->SetShowHome(true); // display the HOME position on the map m_map->SetShowUAV(true); // display the UAV position on the map + m_map->SetShowNav(false); // initially don't display the NAV position on the map m_map->Home->SetSafeArea(safe_area_radius_list[0]); // set radius (meters) //SHOULDN'T THE DEFAULT BE USER DEFINED? m_map->Home->SetShowSafeArea(true); // show the safe area //SHOULDN'T THE DEFAULT BE USER DEFINED? @@ -213,6 +215,7 @@ OPMapGadgetWidget::OPMapGadgetWidget(QWidget *parent) : QWidget(parent) connect(m_map, SIGNAL(OnWayPointDoubleClicked(WayPointItem *)), this, SLOT(wpDoubleClickEvent(WayPointItem *))); m_map->SetCurrentPosition(m_home_position.coord); // set the map position m_map->Home->SetCoord(m_home_position.coord); // set the HOME position + m_map->Nav->SetCoord(m_home_position.coord); // set the NAV position m_map->UAV->SetUAVPos(m_home_position.coord, 0.0); // set the UAV position m_map->UAV->update(); if (m_map->GPS) { @@ -287,6 +290,7 @@ OPMapGadgetWidget::~OPMapGadgetWidget() disconnect(m_map, 0, 0, 0); m_map->SetShowHome(false); // doing this appears to stop the map lib crashing on exit m_map->SetShowUAV(false); // " " + m_map->SetShowNav(false); // " " } if (m_map) { @@ -442,6 +446,8 @@ void OPMapGadgetWidget::contextMenuEvent(QContextMenuEvent *event) contextMenu.addAction(showDiagnostics); + contextMenu.addAction(showNav); + contextMenu.addAction(showUAVInfo); // Zoom section @@ -670,6 +676,19 @@ void OPMapGadgetWidget::updatePosition() m_map->UAV->updateTextOverlay(); m_map->UAV->update(); // ************* + + // ************* + // update active waypoint position at same update rate + if (m_map->Nav) { + double latitude, longitude, altitude; + getNavPosition(latitude, longitude, altitude); + m_map->Nav->SetCoord(internals::PointLatLng(latitude, longitude)); // set the maps Nav position + m_map->Nav->SetAltitude(altitude); + m_map->Nav->RefreshPos(); + m_map->Nav->update(); + } + m_map->UAV->updateTextOverlay(); + m_map->UAV->update(); } /** @@ -1344,6 +1363,12 @@ void OPMapGadgetWidget::createActions() showDiagnostics->setChecked(false); connect(showDiagnostics, SIGNAL(toggled(bool)), this, SLOT(onShowDiagnostics_toggled(bool))); + showNav = new QAction(tr("Show Nav"), this); + showNav->setStatusTip(tr("Show/Hide pathfollower info")); + showNav->setCheckable(true); + showNav->setChecked(false); + connect(showNav, SIGNAL(toggled(bool)), this, SLOT(onShowNav_toggled(bool))); + showUAVInfo = new QAction(tr("Show UAV Info"), this); showUAVInfo->setStatusTip(tr("Show/Hide the UAV info")); showUAVInfo->setCheckable(true); @@ -1647,6 +1672,15 @@ void OPMapGadgetWidget::onShowDiagnostics_toggled(bool show) m_map->SetShowDiagnostics(show); } +void OPMapGadgetWidget::onShowNav_toggled(bool show) +{ + if (!m_widget || !m_map) { + return; + } + + m_map->SetShowNav(show); +} + void OPMapGadgetWidget::onShowUAVInfo_toggled(bool show) { if (!m_widget || !m_map) { @@ -2236,6 +2270,57 @@ bool OPMapGadgetWidget::getUAVPosition(double &latitude, double &longitude, doub return true; } +bool OPMapGadgetWidget::getNavPosition(double &latitude, double &longitude, double &altitude) +{ + double NED[3]; + double LLA[3]; + double homeLLA[3]; + + Q_ASSERT(obm != NULL); + + PathDesired *pathDesired = PathDesired::GetInstance(obm); + Q_ASSERT(pathDesired != NULL); + PathDesired::DataFields pathDesiredData = pathDesired->getData(); + HomeLocation *homeLocation = HomeLocation::GetInstance(obm); + Q_ASSERT(homeLocation != NULL); + HomeLocation::DataFields homeLocationData = homeLocation->getData(); + + homeLLA[0] = homeLocationData.Latitude / 1.0e7; + homeLLA[1] = homeLocationData.Longitude / 1.0e7; + homeLLA[2] = homeLocationData.Altitude; + + NED[0] = pathDesiredData.End[0]; + NED[1] = pathDesiredData.End[1]; + NED[2] = pathDesiredData.End[2]; + + Utils::CoordinateConversions().NED2LLA_HomeLLA(homeLLA, NED, LLA); + + latitude = LLA[0]; + longitude = LLA[1]; + altitude = LLA[2]; + + if (latitude != latitude) { + latitude = 0; // nan detection + } else if (latitude > 90) { + latitude = 90; + } else if (latitude < -90) { + latitude = -90; + } + + if (longitude != longitude) { + longitude = 0; // nan detection + } else if (longitude > 180) { + longitude = 180; + } else if (longitude < -180) { + longitude = -180; + } + + if (altitude != altitude) { + altitude = 0; // nan detection + } + return true; +} + double OPMapGadgetWidget::getUAV_Yaw() { if (!obm) { diff --git a/ground/gcs/src/plugins/opmap/opmapgadgetwidget.h b/ground/gcs/src/plugins/opmap/opmapgadgetwidget.h index 13d5972584..8ee19b7539 100644 --- a/ground/gcs/src/plugins/opmap/opmapgadgetwidget.h +++ b/ground/gcs/src/plugins/opmap/opmapgadgetwidget.h @@ -174,6 +174,7 @@ private slots: void onCopyMouseLonToClipAct_triggered(); void onShowCompassAct_toggled(bool show); void onShowDiagnostics_toggled(bool show); + void onShowNav_toggled(bool show); void onShowUAVInfo_toggled(bool show); void onShowUAVAct_toggled(bool show); void onShowHomeAct_toggled(bool show); @@ -248,6 +249,7 @@ private slots: QAction *copyMouseLonToClipAct; QAction *showCompassAct; QAction *showDiagnostics; + QAction *showNav; QAction *showUAVInfo; QAction *showHomeAct; QAction *showUAVAct; @@ -308,6 +310,7 @@ private slots: internals::PointLatLng destPoint(internals::PointLatLng source, double bear, double dist); bool getUAVPosition(double &latitude, double &longitude, double &altitude); + bool getNavPosition(double &latitude, double &longitude, double &altitude); double getUAV_Yaw(); void setMapFollowingMode(); From 183bedd8480a77c6a64b04cf701e0cd447ad9549 Mon Sep 17 00:00:00 2001 From: Eric Price Date: Tue, 21 Mar 2017 08:37:30 +0100 Subject: [PATCH 184/624] LP-498 updated copyright headers in modified files --- ground/gcs/src/libs/opmapcontrol/src/mapwidget/navitem.cpp | 4 ++-- ground/gcs/src/libs/opmapcontrol/src/mapwidget/navitem.h | 2 +- .../gcs/src/libs/opmapcontrol/src/mapwidget/opmapwidget.cpp | 3 ++- ground/gcs/src/libs/opmapcontrol/src/mapwidget/opmapwidget.h | 3 ++- ground/gcs/src/plugins/opmap/opmapgadgetwidget.cpp | 3 ++- ground/gcs/src/plugins/opmap/opmapgadgetwidget.h | 3 ++- 6 files changed, 11 insertions(+), 7 deletions(-) diff --git a/ground/gcs/src/libs/opmapcontrol/src/mapwidget/navitem.cpp b/ground/gcs/src/libs/opmapcontrol/src/mapwidget/navitem.cpp index 164a7712c5..a3e6ce0856 100644 --- a/ground/gcs/src/libs/opmapcontrol/src/mapwidget/navitem.cpp +++ b/ground/gcs/src/libs/opmapcontrol/src/mapwidget/navitem.cpp @@ -2,8 +2,8 @@ ****************************************************************************** * * @file navitem.cpp - * @author The LibrePilot Team, http://www.openpilot.org Copyright (C) 2017. - * @brief A graphicsItem representing a trail point + * @author The LibrePilot Project, http://www.openpilot.org Copyright (C) 2017. + * @brief A graphicsItem representing a WayPoint * @see The GNU Public License (GPL) Version 3 * @defgroup OPMapWidget * @{ diff --git a/ground/gcs/src/libs/opmapcontrol/src/mapwidget/navitem.h b/ground/gcs/src/libs/opmapcontrol/src/mapwidget/navitem.h index 86e4bbe5ae..c367740e1c 100644 --- a/ground/gcs/src/libs/opmapcontrol/src/mapwidget/navitem.h +++ b/ground/gcs/src/libs/opmapcontrol/src/mapwidget/navitem.h @@ -2,7 +2,7 @@ ****************************************************************************** * * @file navitem.h - * @author The LibrePilot Team, http://www.librepilot.org Copyright (C) 2017. + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017. * @brief A graphicsItem representing a WayPoint * @see The GNU Public License (GPL) Version 3 * @defgroup OPMapWidget diff --git a/ground/gcs/src/libs/opmapcontrol/src/mapwidget/opmapwidget.cpp b/ground/gcs/src/libs/opmapcontrol/src/mapwidget/opmapwidget.cpp index 1e2cd40925..c9095b74f2 100644 --- a/ground/gcs/src/libs/opmapcontrol/src/mapwidget/opmapwidget.cpp +++ b/ground/gcs/src/libs/opmapcontrol/src/mapwidget/opmapwidget.cpp @@ -2,7 +2,8 @@ ****************************************************************************** * * @file opmapwidget.cpp - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012. + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017. + * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012. * @brief The Map Widget, this is the part exposed to the user * @see The GNU Public License (GPL) Version 3 * @defgroup OPMapWidget diff --git a/ground/gcs/src/libs/opmapcontrol/src/mapwidget/opmapwidget.h b/ground/gcs/src/libs/opmapcontrol/src/mapwidget/opmapwidget.h index e8519a34ab..af79774c7c 100644 --- a/ground/gcs/src/libs/opmapcontrol/src/mapwidget/opmapwidget.h +++ b/ground/gcs/src/libs/opmapcontrol/src/mapwidget/opmapwidget.h @@ -2,7 +2,8 @@ ****************************************************************************** * * @file opmapwidget.h - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012. + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017. + * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012. * @brief The Map Widget, this is the part exposed to the user * @see The GNU Public License (GPL) Version 3 * @defgroup OPMapWidget diff --git a/ground/gcs/src/plugins/opmap/opmapgadgetwidget.cpp b/ground/gcs/src/plugins/opmap/opmapgadgetwidget.cpp index 03092cffd6..8db51bbdaa 100644 --- a/ground/gcs/src/plugins/opmap/opmapgadgetwidget.cpp +++ b/ground/gcs/src/plugins/opmap/opmapgadgetwidget.cpp @@ -2,7 +2,8 @@ ****************************************************************************** * * @file opmapgadgetwidget.cpp - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012. + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017. + * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012. * @addtogroup GCSPlugins GCS Plugins * @{ * @addtogroup OPMapPlugin OpenPilot Map Plugin diff --git a/ground/gcs/src/plugins/opmap/opmapgadgetwidget.h b/ground/gcs/src/plugins/opmap/opmapgadgetwidget.h index 8ee19b7539..02aa9d6f1c 100644 --- a/ground/gcs/src/plugins/opmap/opmapgadgetwidget.h +++ b/ground/gcs/src/plugins/opmap/opmapgadgetwidget.h @@ -2,7 +2,8 @@ ****************************************************************************** * * @file opmapgadgetwidget.h - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012. + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017. + * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012. * @addtogroup GCSPlugins GCS Plugins * @{ * @addtogroup OPMapPlugin OpenPilot Map Plugin From 95fc31a6c8836fd5c0f5e74e3c12452ef18564b0 Mon Sep 17 00:00:00 2001 From: Eric Price Date: Tue, 21 Mar 2017 10:12:17 +0100 Subject: [PATCH 185/624] LP-498 Modified PathDesired Map marker --- .../opmapcontrol/src/mapwidget/images/nav.svg | 118 +++++++++--------- 1 file changed, 56 insertions(+), 62 deletions(-) diff --git a/ground/gcs/src/libs/opmapcontrol/src/mapwidget/images/nav.svg b/ground/gcs/src/libs/opmapcontrol/src/mapwidget/images/nav.svg index 63fa6a97e8..cf98903e0c 100644 --- a/ground/gcs/src/libs/opmapcontrol/src/mapwidget/images/nav.svg +++ b/ground/gcs/src/libs/opmapcontrol/src/mapwidget/images/nav.svg @@ -1,5 +1,6 @@ + @@ -36,17 +37,35 @@ objecttolerance="10" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="0.0875" - inkscape:cx="3193.6065" - inkscape:cy="2405.053" + inkscape:zoom="0.35" + inkscape:cx="289.96988" + inkscape:cy="445.6703" inkscape:document-units="px" inkscape:current-layer="layer1" - showgrid="false" + showgrid="true" showborder="false" inkscape:window-width="1355" inkscape:window-height="722" - inkscape:window-x="4" - inkscape:window-y="24" /> + inkscape:window-x="2059" + inkscape:window-y="89" + inkscape:window-maximized="0" + fit-margin-top="0" + fit-margin-left="0" + fit-margin-right="0" + fit-margin-bottom="0"> + + @@ -62,65 +81,40 @@ inkscape:label="Layer 1" inkscape:groupmode="layer" id="layer1" - transform="translate(2201.53,2081.9236)"> + transform="translate(2200.7315,1976.8204)"> + id="g3810" + transform="matrix(0.70710678,-0.70710678,0.70710678,0.70710678,532.71884,-1603.6253)"> - - + inkscape:connector-curvature="0" + id="path3763" + d="m -2166.0969,-1515.7143 425.1968,70.8661 -425.1968,70.8662 -35.4331,-70.8662 z" + style="fill:#ff00ff;stroke:none" /> + inkscape:connector-curvature="0" + id="path3763-3" + d="m -1173.8338,-1515.6795 -425.1968,70.8661 425.1968,70.8662 35.4331,-70.8662 z" + style="fill:#ff00ff;stroke:none" /> + inkscape:connector-curvature="0" + id="path3763-6" + d="m -1740.8619,-948.95165 70.8661,-425.19675 70.8662,425.19675 -70.8662,35.4331 z" + style="fill:#ff00ff;stroke:none" /> + inkscape:connector-curvature="0" + id="path3763-3-7" + d="m -1740.8271,-1941.2147 70.8661,425.1968 70.8662,-425.1968 -70.8662,-35.4331 z" + style="fill:#ff00ff;stroke:none" /> From 002b292656530a5c035739f036001917a95df09a Mon Sep 17 00:00:00 2001 From: Eric Price Date: Tue, 21 Mar 2017 10:13:22 +0100 Subject: [PATCH 186/624] LP-498 driveby Bugfix in map waypointitem methodology to "search for the home location" --- .../src/mapwidget/mapgraphicitem.h | 6 +- .../src/mapwidget/opmapwidget.cpp | 3 +- .../src/mapwidget/waypointitem.cpp | 67 ++++++++++--------- 3 files changed, 41 insertions(+), 35 deletions(-) diff --git a/ground/gcs/src/libs/opmapcontrol/src/mapwidget/mapgraphicitem.h b/ground/gcs/src/libs/opmapcontrol/src/mapwidget/mapgraphicitem.h index f14c43fbc4..11e778e8a6 100644 --- a/ground/gcs/src/libs/opmapcontrol/src/mapwidget/mapgraphicitem.h +++ b/ground/gcs/src/libs/opmapcontrol/src/mapwidget/mapgraphicitem.h @@ -2,7 +2,8 @@ ****************************************************************************** * * @file mapgraphicitem.h - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012. + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017. + * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012. * @brief The main graphicsItem used on the widget, contains the map and map logic * @see The GNU Public License (GPL) Version 3 * @defgroup OPMapWidget @@ -43,6 +44,7 @@ namespace mapcontrol { class WayPointItem; class OPMapWidget; +class HomeItem; /** * @brief The main graphicsItem used on the widget, contains the map and map logic * @@ -105,6 +107,8 @@ class MapGraphicItem : public QObject, public QGraphicsItem { double ZoomDigi(); double ZoomTotal(); void setOverlayOpacity(qreal value); + + HomeItem *Home; protected: void mouseMoveEvent(QGraphicsSceneMouseEvent *event); void mousePressEvent(QGraphicsSceneMouseEvent *event); diff --git a/ground/gcs/src/libs/opmapcontrol/src/mapwidget/opmapwidget.cpp b/ground/gcs/src/libs/opmapcontrol/src/mapwidget/opmapwidget.cpp index c9095b74f2..ea1301a245 100644 --- a/ground/gcs/src/libs/opmapcontrol/src/mapwidget/opmapwidget.cpp +++ b/ground/gcs/src/libs/opmapcontrol/src/mapwidget/opmapwidget.cpp @@ -43,9 +43,10 @@ OPMapWidget::OPMapWidget(QWidget *parent, Configuration *config) : QGraphicsView mscene.addItem(map); this->setScene(&mscene); Home = new HomeItem(map, this); + map->Home = Home; Home->setParentItem(map); Home->setZValue(-1); - Nav = new NavItem(map, this); + Nav = new NavItem(map, this); Nav->setParentItem(map); Nav->setZValue(-1); setStyleSheet("QToolTip {font-size:8pt; color:blue;opacity: 223; padding:2px; border-width:2px; border-style:solid; border-color: rgb(170, 170, 127);border-radius:4px }"); diff --git a/ground/gcs/src/libs/opmapcontrol/src/mapwidget/waypointitem.cpp b/ground/gcs/src/libs/opmapcontrol/src/mapwidget/waypointitem.cpp index 7a187685c5..25c5810a24 100644 --- a/ground/gcs/src/libs/opmapcontrol/src/mapwidget/waypointitem.cpp +++ b/ground/gcs/src/libs/opmapcontrol/src/mapwidget/waypointitem.cpp @@ -2,7 +2,8 @@ ****************************************************************************** * * @file waypointitem.cpp - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012. + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017. + * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012. * @brief A graphicsItem representing a WayPoint * @see The GNU Public License (GPL) Version 3 * @defgroup OPMapWidget @@ -43,15 +44,15 @@ WayPointItem::WayPointItem(const internals::PointLatLng &coord, int const & alti SetShowNumber(shownumber); RefreshToolTip(); RefreshPos(); - myHome = NULL; - QList list = map->childItems(); - foreach(QGraphicsItem * obj, list) { - HomeItem *h = qgraphicsitem_cast (obj); + myHome = map->Home; + // QList list = map->childItems(); WTF?!?!?!?!???????? + // foreach(QGraphicsItem * obj, list) { + // HomeItem *h = qgraphicsitem_cast (obj); - if (h) { - myHome = h; - } - } + // if (h) { + // myHome = h; + // } + // } if (myHome) { map->Projection()->offSetFromLatLngs(myHome->Coord(), coord, relativeCoord.distance, relativeCoord.bearing); @@ -87,15 +88,15 @@ WayPointItem::WayPointItem(MapGraphicItem *map, bool magicwaypoint) : reached(fa SetShowNumber(shownumber); RefreshToolTip(); RefreshPos(); - myHome = NULL; - QList list = map->childItems(); - foreach(QGraphicsItem * obj, list) { - HomeItem *h = qgraphicsitem_cast (obj); + myHome = map->Home; + // QList list = map->childItems(); WTF?!?!?!?!???????? + // foreach(QGraphicsItem * obj, list) { + // HomeItem *h = qgraphicsitem_cast (obj); - if (h) { - myHome = h; - } - } + // if (h) { + // myHome = h; + // } + // } if (myHome) { coord = map->Projection()->translate(myHome->Coord(), relativeCoord.distance, relativeCoord.bearing); @@ -121,15 +122,15 @@ WayPointItem::WayPointItem(const internals::PointLatLng &coord, int const & alti SetShowNumber(shownumber); RefreshToolTip(); RefreshPos(); - myHome = NULL; - QList list = map->childItems(); - foreach(QGraphicsItem * obj, list) { - HomeItem *h = qgraphicsitem_cast (obj); + myHome = map->Home; + // QList list = map->childItems(); WTF?!?!?!?!???????? + // foreach(QGraphicsItem * obj, list) { + // HomeItem *h = qgraphicsitem_cast (obj); - if (h) { - myHome = h; - } - } + // if (h) { + // myHome = h; + // } + // } if (myHome) { map->Projection()->offSetFromLatLngs(myHome->Coord(), coord, relativeCoord.distance, relativeCoord.bearing); relativeCoord.altitudeRelative = Altitude() - myHome->Altitude(); @@ -143,15 +144,15 @@ WayPointItem::WayPointItem(const internals::PointLatLng &coord, int const & alti WayPointItem::WayPointItem(const distBearingAltitude &relativeCoordenate, const QString &description, MapGraphicItem *map) : relativeCoord(relativeCoordenate), reached(false), description(description), shownumber(true), isDragging(false), map(map) { - myHome = NULL; - QList list = map->childItems(); - foreach(QGraphicsItem * obj, list) { - HomeItem *h = qgraphicsitem_cast (obj); + myHome = map->Home; + // QList list = map->childItems(); WTF?!?!?!?!???????? + // foreach(QGraphicsItem * obj, list) { + // HomeItem *h = qgraphicsitem_cast (obj); - if (h) { - myHome = h; - } - } + // if (h) { + // myHome = h; + // } + // } if (myHome) { connect(myHome, SIGNAL(homePositionChanged(internals::PointLatLng, float)), this, SLOT(onHomePositionChanged(internals::PointLatLng, float))); coord = map->Projection()->translate(myHome->Coord(), relativeCoord.distance, relativeCoord.bearing); From 292c1267fda2da9b413532c1ef6cc915cdc95563 Mon Sep 17 00:00:00 2001 From: Eric Price Date: Wed, 22 Mar 2017 10:24:44 +0100 Subject: [PATCH 187/624] LP-498 corrected comment lines per review suggestion --- .../opmapcontrol/src/mapwidget/navitem.cpp | 2 +- .../src/mapwidget/waypointitem.cpp | 34 ------------------- 2 files changed, 1 insertion(+), 35 deletions(-) diff --git a/ground/gcs/src/libs/opmapcontrol/src/mapwidget/navitem.cpp b/ground/gcs/src/libs/opmapcontrol/src/mapwidget/navitem.cpp index a3e6ce0856..1820135c52 100644 --- a/ground/gcs/src/libs/opmapcontrol/src/mapwidget/navitem.cpp +++ b/ground/gcs/src/libs/opmapcontrol/src/mapwidget/navitem.cpp @@ -2,7 +2,7 @@ ****************************************************************************** * * @file navitem.cpp - * @author The LibrePilot Project, http://www.openpilot.org Copyright (C) 2017. + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017. * @brief A graphicsItem representing a WayPoint * @see The GNU Public License (GPL) Version 3 * @defgroup OPMapWidget diff --git a/ground/gcs/src/libs/opmapcontrol/src/mapwidget/waypointitem.cpp b/ground/gcs/src/libs/opmapcontrol/src/mapwidget/waypointitem.cpp index 25c5810a24..010a5c3937 100644 --- a/ground/gcs/src/libs/opmapcontrol/src/mapwidget/waypointitem.cpp +++ b/ground/gcs/src/libs/opmapcontrol/src/mapwidget/waypointitem.cpp @@ -45,15 +45,6 @@ WayPointItem::WayPointItem(const internals::PointLatLng &coord, int const & alti RefreshToolTip(); RefreshPos(); myHome = map->Home; - // QList list = map->childItems(); WTF?!?!?!?!???????? - // foreach(QGraphicsItem * obj, list) { - // HomeItem *h = qgraphicsitem_cast (obj); - - // if (h) { - // myHome = h; - // } - // } - if (myHome) { map->Projection()->offSetFromLatLngs(myHome->Coord(), coord, relativeCoord.distance, relativeCoord.bearing); relativeCoord.altitudeRelative = Altitude() - myHome->Altitude(); @@ -89,15 +80,6 @@ WayPointItem::WayPointItem(MapGraphicItem *map, bool magicwaypoint) : reached(fa RefreshToolTip(); RefreshPos(); myHome = map->Home; - // QList list = map->childItems(); WTF?!?!?!?!???????? - // foreach(QGraphicsItem * obj, list) { - // HomeItem *h = qgraphicsitem_cast (obj); - - // if (h) { - // myHome = h; - // } - // } - if (myHome) { coord = map->Projection()->translate(myHome->Coord(), relativeCoord.distance, relativeCoord.bearing); SetAltitude(myHome->Altitude() + relativeCoord.altitudeRelative); @@ -123,14 +105,6 @@ WayPointItem::WayPointItem(const internals::PointLatLng &coord, int const & alti RefreshToolTip(); RefreshPos(); myHome = map->Home; - // QList list = map->childItems(); WTF?!?!?!?!???????? - // foreach(QGraphicsItem * obj, list) { - // HomeItem *h = qgraphicsitem_cast (obj); - - // if (h) { - // myHome = h; - // } - // } if (myHome) { map->Projection()->offSetFromLatLngs(myHome->Coord(), coord, relativeCoord.distance, relativeCoord.bearing); relativeCoord.altitudeRelative = Altitude() - myHome->Altitude(); @@ -145,14 +119,6 @@ WayPointItem::WayPointItem(const internals::PointLatLng &coord, int const & alti WayPointItem::WayPointItem(const distBearingAltitude &relativeCoordenate, const QString &description, MapGraphicItem *map) : relativeCoord(relativeCoordenate), reached(false), description(description), shownumber(true), isDragging(false), map(map) { myHome = map->Home; - // QList list = map->childItems(); WTF?!?!?!?!???????? - // foreach(QGraphicsItem * obj, list) { - // HomeItem *h = qgraphicsitem_cast (obj); - - // if (h) { - // myHome = h; - // } - // } if (myHome) { connect(myHome, SIGNAL(homePositionChanged(internals::PointLatLng, float)), this, SLOT(onHomePositionChanged(internals::PointLatLng, float))); coord = map->Projection()->translate(myHome->Coord(), relativeCoord.distance, relativeCoord.bearing); From 364e24e59cfccb68fc92a1624d26589696ea5f1b Mon Sep 17 00:00:00 2001 From: padeler Date: Tue, 21 Mar 2017 23:48:22 +0200 Subject: [PATCH 188/624] LP-483 Updates example scripts, code cleanup --- python/examples/__init__.py | 0 python/examples/example.py | 8 +-- python/examples/example_readlog.py | 94 ++++------------------------ python/examples/example_tuning.py | 13 ++-- python/librepilot/uavtalk/uavtalk.py | 6 +- 5 files changed, 25 insertions(+), 96 deletions(-) create mode 100644 python/examples/__init__.py diff --git a/python/examples/__init__.py b/python/examples/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/python/examples/example.py b/python/examples/example.py index 3fc708512b..a22769f026 100644 --- a/python/examples/example.py +++ b/python/examples/example.py @@ -91,7 +91,7 @@ def stop(self): def showAttitudeViaObserver(self): print "Request fast periodic updates for AttitudeState" - self.objMan.AttitudeState.metadata.telemetryUpdateMode.value = UAVMetaDataObject.UpdateMode.PERIODIC + self.objMan.AttitudeState.metadata.telemetryUpdateMode = UAVMetaDataObject.UpdateMode.PERIODIC self.objMan.AttitudeState.metadata.telemetryUpdatePeriod.value = 50 self.objMan.AttitudeState.metadata.updated() @@ -104,7 +104,7 @@ def showAttitudeViaObserver(self): def showAttitudeViaWait(self): print "Request fast periodic updates for AttitudeState" self.objMan.AttitudeState.metadata.telemetryUpdateMode = UAVMetaDataObject.UpdateMode.PERIODIC - self.objMan.AttitudeState.metadata.telemetryUpdatePeriod = 50 + self.objMan.AttitudeState.metadata.telemetryUpdatePeriod.value = 50 self.objMan.AttitudeState.metadata.updated() while True: @@ -146,10 +146,8 @@ def _onAttitudeUpdate(self, args): def driveServo(self): print "Taking control of self.actuatorCmd" - self.objMan.ActuatorCommand.metadata.access.value = UAVMetaDataObject.Access.READONLY + self.objMan.ActuatorCommand.metadata.access = UAVMetaDataObject.Access.READONLY self.objMan.ActuatorCommand.metadata.updated() - self.objMan.ManualControlCommand.metadata.access.value = UAVMetaDataObject.Access.READONLY - self.objMan.ManualControlCommand.metadata.updated() while True: self.objMan.ActuatorCommand.Channel.value[0] = 1000 diff --git a/python/examples/example_readlog.py b/python/examples/example_readlog.py index 70b5b9fcfb..56bbad901d 100644 --- a/python/examples/example_readlog.py +++ b/python/examples/example_readlog.py @@ -36,12 +36,13 @@ from librepilot.uavtalk.uavtalk import * from librepilot.uavtalk.objectManager import * from librepilot.uavtalk.connectionManager import * - - +from example import UavtalkDemo + + def _hex02(value): return "%02X" % value -class UavtalkDemo(): +class UavtalkLogDemo(UavtalkDemo): def __init__(self): self.nbUpdates = 0 @@ -50,7 +51,7 @@ def __init__(self): self.objMan = None self.connMan = None - def setup(self, port, filename): + def setup(self, filename): print "Opening File \"%s\"" % filename file = open(filename,"rb") if file == None: @@ -58,86 +59,13 @@ def setup(self, port, filename): print "Creating UavTalk" self.uavTalk = UavTalk(None, filename) - + print "Starting ObjectManager" self.objMan = ObjManager(self.uavTalk) self.objMan.importDefinitions() - + print "Starting UavTalk" self.uavTalk.start() - - def stop(self): - if self.uavTalk: - print "Stopping UavTalk" - self.uavTalk.stop() - - def showAttitudeViaObserver(self): - print "Request fast periodic updates for AttitudeActual" - self.objMan.AttitudeActual.metadata.telemetryUpdateMode.value = UAVMetaDataObject.UpdateMode.PERIODIC - self.objMan.AttitudeActual.metadata.telemetryUpdatePeriod.value = 50 - self.objMan.AttitudeActual.metadata.updated() - - print "Install Observer for AttitudeActual updates\n" - self.objMan.regObjectObserver(self.objMan.AttitudeActual, self, "_onAttitudeUpdate") - # Spin until we get interrupted - while True: - time.sleep(1) - - def showAttitudeViaWait(self): - print "Request fast periodic updates for AttitudeActual" - self.objMan.AttitudeActual.metadata.telemetryUpdateMode.value = UAVMetaDataObject.UpdateMode.PERIODIC - self.objMan.AttitudeActual.metadata.telemetryUpdatePeriod.value = 50 - self.objMan.AttitudeActual.metadata.updated() - - while True: - self.objMan.AttitudeActual.waitUpdate() - self._onAttitudeUpdate(self.objMan.AttitudeActual) - - def showAttitudeViaGet(self): - while True: - self.objMan.AttitudeActual.getUpdate() - self._onAttitudeUpdate(self.objMan.AttitudeActual) - - def _onAttitudeUpdate(self, args): - self.nbUpdates += 1 - - now = time.time() - if now-self.lastRateCalc > 1: - self.updateRate = self.nbUpdates/(now-self.lastRateCalc) - self.lastRateCalc = now - self.nbUpdates = 0 - - if self.nbUpdates & 1: - dot = "." - else: - dot= " " - - print " %s Rate: %02.1f Hz " % (dot, self.updateRate), - - roll = self.objMan.AttitudeActual.Roll.value - print "Roll: %-4d " % roll, - i = roll/90 - if i<-1: i=-1 - if i>1: i= 1 - i = int((i+1)*15) - print "-"*i+"*"+"-"*(30-i)+" \r", - - def driveServo(self): - print "Taking control of self.actuatorCmd" - self.objMan.ActuatorCommand.metadata.access.value = UAVMetaDataObject.Access.READONLY - self.objMan.ActuatorCommand.metadata.updated() - self.objMan.ManualControlCommand.metadata.access.value = UAVMetaDataObject.Access.READONLY - self.objMan.ManualControlCommand.metadata.updated() - - while True: - self.objMan.ActuatorCommand.Channel.value[0] = 1000 - self.objMan.ActuatorCommand.updated() - time.sleep(1) - - self.objMan.ActuatorCommand.Channel.value[0] = 2000 - self.objMan.ActuatorCommand.updated() - time.sleep(1) - def printUsage(): appName = os.path.basename(sys.argv[0]) @@ -164,10 +92,12 @@ def printUsage(): logging.basicConfig(level=logging.INFO) try: - demo = UavtalkDemo() - demo.setup(None, filename) - + demo = UavtalkLogDemo() + demo.setup(filename) + while True: + demo.objMan.AttitudeState.waitUpdate() + demo._onAttitudeUpdate(demo.objMan.AttitudeState) except KeyboardInterrupt: pass diff --git a/python/examples/example_tuning.py b/python/examples/example_tuning.py index ff3d166a41..39f562f436 100644 --- a/python/examples/example_tuning.py +++ b/python/examples/example_tuning.py @@ -63,24 +63,25 @@ def printUsage(): serPort = serial.Serial(_port, 57600, timeout=.5) uavTalk = UavTalk(serPort, None) + + print "Starting ObjectManager" objMan = ObjManager(uavTalk) objMan.importDefinitions() + + print "Starting UavTalk" uavTalk.start() - - import objectpersistence + print "Getting Current Settings:" for _ in range(2): # Try only twice to get the settings try: - time.sleep(10) + time.sleep(1) objMan.StabilizationSettingsBank1.getUpdate() except TimeoutException: print "Timeout" pass except KeyboardInterrupt: - os._exit(1) - else: - raise + exit(1) while True: while True: diff --git a/python/librepilot/uavtalk/uavtalk.py b/python/librepilot/uavtalk/uavtalk.py index 9bf78a73fe..6fe304b50e 100644 --- a/python/librepilot/uavtalk/uavtalk.py +++ b/python/librepilot/uavtalk/uavtalk.py @@ -122,12 +122,12 @@ def run(self): self.stop = False if self.uavTalk.logFile is not None: - file = open(self.uavTalk.logFile) + file = open(self.uavTalk.logFile, "rb") while not self.stop: rx = file.read(1) if len(rx) > 0: rx = ord(rx) - self._consumeByte(rx) + self._consumeByte(rx) elif self.uavTalk.serial is not None: while not self.stop: rx = self.uavTalk.serial.read(1) @@ -233,7 +233,7 @@ def _consumeByte(self, rx): elif self.rxState == UavTalkRecThread.STATE_CS: # by now, the CS has been added to the CRC calc, so now the CRC calc should read 0 if self.rxCrc.read() != 0: - logging.error("CRC ERROR") + logging.debug("CRC ERROR") else: self.uavTalk._onRecevedPacket(self.obj, self.rxType, self.rxData) self.rxState = UavTalkRecThread.STATE_SYNC From 775e2a4063e0070e4029f1013509fe805bb3262a Mon Sep 17 00:00:00 2001 From: padeler Date: Thu, 23 Mar 2017 02:17:01 +0200 Subject: [PATCH 189/624] LP-483 Example tuning using accessory0 (by L Laurent) --- python/examples/example_tuning.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/python/examples/example_tuning.py b/python/examples/example_tuning.py index 39f562f436..8e014393e6 100644 --- a/python/examples/example_tuning.py +++ b/python/examples/example_tuning.py @@ -177,11 +177,11 @@ def printUsage(): print while True: try: - # get update of ManualControlCommand - objMan.ManualControlCommand.getUpdate(timeout=.5) - - # calculate value out of Accessory1 input (-1 ... +1) - txControl = objMan.ManualControlCommand.Accessory1.value + # get update of AccessoryDesired + objMan.AccessoryDesired.getUpdate(timeout=.5) + + # calculate value out of Accessory0 input (-1 ... +1) + txControl = objMan.AccessoryDesired.AccessoryVal.value value = tuneFrom + ((txControl+1)/2)*(tuneTo-tuneFrom) PI[PIIndex] = value objMan.StabilizationSettingsBank1.updated() From 2977ec1382d16b1345231c4751246fdd0636ad2f Mon Sep 17 00:00:00 2001 From: Corvus Corax Date: Wed, 22 Mar 2017 15:52:59 +0100 Subject: [PATCH 190/624] LP-500 HoTT bridge module initial create --- .../modules/UAVOHottBridge/uavohottbridge.c | 589 ++++++++++++++++++ 1 file changed, 589 insertions(+) create mode 100644 flight/modules/UAVOHottBridge/uavohottbridge.c diff --git a/flight/modules/UAVOHottBridge/uavohottbridge.c b/flight/modules/UAVOHottBridge/uavohottbridge.c new file mode 100644 index 0000000000..fdc5b0da49 --- /dev/null +++ b/flight/modules/UAVOHottBridge/uavohottbridge.c @@ -0,0 +1,589 @@ +/** + ****************************************************************************** + * @addtogroup OpenPilotModules OpenPilot Modules + * @{ + * @addtogroup UAVOHoTTBridge UAVO to HoTT Bridge Module + * @{ + * + * @file uavohottridge.c + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017. + * @brief Bridges certain UAVObjects to HoTT on USB VCP + * + * @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 + * + * Additional note on redistribution: The copyright and license notices above + * must be maintained in each individual source file that is a derivative work + * of this source file; otherwise redistribution is prohibited. + */ + +#include "openpilot.h" +#include "hwsettings.h" +#include "taskinfo.h" +#include "callbackinfo.h" +/* +#include "insgps.h" + #include "receiverstatus.h" + #include "flightmodesettings.h" + #include "flightbatterysettings.h" + #include "flightbatterystate.h" + #include "gpspositionsensor.h" + #include "manualcontrolsettings.h" + #include "oplinkstatus.h" + #include "accessorydesired.h" + #include "airspeedstate.h" + #include "actuatorsettings.h" + #include "systemstats.h" + #include "systemalarms.h" + #include "takeofflocation.h" + #include "homelocation.h" + #include "stabilizationdesired.h" + #include "stabilizationsettings.h" + #include "stabilizationbank.h" + #include "stabilizationsettingsbank1.h" + #include "stabilizationsettingsbank2.h" + #include "stabilizationsettingsbank3.h" + #include "magstate.h" +#include "manualcontrolcommand.h" +#include "accessorydesired.h" +#include "actuatordesired.h" +#include "auxpositionsensor.h" +#include "pathdesired.h" +#include "poilocation.h" +#include "flightmodesettings.h" +#include "flightstatus.h" +#include "positionstate.h" +#include "velocitystate.h" +#include "attitudestate.h" +#include "gyrostate.h" + */ + +#include "hottbridgestatus.h" +#include "objectpersistence.h" + +#include "pios_sensors.h" + +#if defined(PIOS_INCLUDE_HoTT_BRIDGE) + +struct hott_bridge { + uintptr_t com; + + uint32_t lastPingTimestamp; + uint8_t myPingSequence; + uint8_t remotePingSequence; + PiOSDeltatimeConfig roundtrip; + double roundTripTime; + int32_t pingTimer; + int32_t stateTimer; + int32_t rateTimer; + float rateAccumulator[3]; + uint8_t rx_buffer[HoTTBRIDGEMESSAGE_BUFFERSIZE]; + size_t rx_length; + volatile bool scheduled[HoTTBRIDGEMESSAGE_END_ARRAY_SIZE]; +}; + +#if defined(PIOS_HoTT_STACK_SIZE) +#define STACK_SIZE_BYTES PIOS_HoTT_STACK_SIZE +#else +#define STACK_SIZE_BYTES 2048 +#endif +#define TASK_PRIORITY CALLBACK_TASK_AUXILIARY +#define CALLBACK_PRIORITY CALLBACK_PRIORITY_REGULAR +#define CBTASK_PRIORITY CALLBACK_TASK_AUXILIARY + +static bool module_enabled = false; +static struct hott_bridge *hott; +static int32_t uavoHoTTBridgeInitialize(void); +static void uavoHoTTBridgeRxTask(void *parameters); +static void uavoHoTTBridgeTxTask(void); +static DelayedCallbackInfo *callbackHandle; +static hottbridgemessage_handler ping_handler, ping_r_handler, pong_handler, pong_r_handler, fullstate_estimate_handler, imu_average_handler, gimbal_estimate_handler, flightcontrol_r_handler, pos_estimate_r_handler; +static HoTTBridgeSettingsData settings; +void AttitudeCb(__attribute__((unused)) UAVObjEvent *ev); +void RateCb(__attribute__((unused)) UAVObjEvent *ev); + +static hottbridgemessage_handler *const hottbridgemessagehandlers[HoTTBRIDGEMESSAGE_END_ARRAY_SIZE] = { + ping_handler, + NULL, + NULL, + NULL, + pong_handler, + fullstate_estimate_handler, + imu_average_handler, + gimbal_estimate_handler +}; + + +/** + * Process incoming bytes from an HoTT query thing. + * @param[in] b received byte + * @return true if we should continue processing bytes + */ +static void hott_receive_byte(struct hott_bridge *m, uint8_t b) +{ + m->rx_buffer[m->rx_length] = b; + m->rx_length++; + hottbridgemessage_t *message = (hottbridgemessage_t *)m->rx_buffer; + + // very simple parser - but not a state machine, just a few checks + if (m->rx_length <= offsetof(hottbridgemessage_t, length)) { + // check (partial) magic number - partial is important since we need to restart at any time if garbage is received + uint32_t canary = 0xff; + for (uint32_t t = 1; t < m->rx_length; t++) { + canary = (canary << 8) || 0xff; + } + if ((message->magic & canary) != (HoTTBRIDGEMAGIC & canary)) { + // parse error, not beginning of message + goto rxfailure; + } + } + if (m->rx_length == offsetof(hottbridgemessage_t, timestamp)) { + if (message->length > (uint32_t)(HoTTBRIDGEMESSAGE_BUFFERSIZE - offsetof(hottbridgemessage_t, data))) { + // parse error, no messages are that long + goto rxfailure; + } + } + if (m->rx_length == offsetof(hottbridgemessage_t, crc32)) { + if (message->type >= HoTTBRIDGEMESSAGE_END_ARRAY_SIZE) { + // parse error + goto rxfailure; + } + if (message->length != HoTTBRIDGEMESSAGE_SIZES[message->type]) { + // parse error + goto rxfailure; + } + } + if (m->rx_length < offsetof(hottbridgemessage_t, data)) { + // not a parse failure, just not there yet + return; + } + if (m->rx_length == offsetof(hottbridgemessage_t, data) + HoTTBRIDGEMESSAGE_SIZES[message->type]) { + // complete message received and stored in pointer "message" + // empty buffer for next message + m->rx_length = 0; + + if (PIOS_CRC32_updateCRC(0xffffffff, message->data, message->length) != message->crc32) { + // crc mismatch + goto rxfailure; + } + uint32_t rxpackets; + HoTTBridgeStatusRxPacketsGet(&rxpackets); + rxpackets++; + HoTTBridgeStatusRxPacketsSet(&rxpackets); + switch (message->type) { + case HoTTBRIDGEMESSAGE_PING: + ping_r_handler(m, message); + break; + case HoTTBRIDGEMESSAGE_POS_ESTIMATE: + pos_estimate_r_handler(m, message); + break; + case HoTTBRIDGEMESSAGE_FLIGHTCONTROL: + flightcontrol_r_handler(m, message); + break; + case HoTTBRIDGEMESSAGE_GIMBALCONTROL: + // TODO implement gimbal control somehow + break; + case HoTTBRIDGEMESSAGE_PONG: + pong_r_handler(m, message); + break; + default: + // do nothing at all and discard the message + break; + } + } + return; + +rxfailure: + m->rx_length = 0; + uint32_t rxfail; + HoTTBridgeStatusRxFailGet(&rxfail); + rxfail++; + HoTTBridgeStatusRxFailSet(&rxfail); +} + +static uint32_t hwsettings_rosspeed_enum_to_baud(uint8_t baud) +{ + switch (baud) { + case HWSETTINGS_HoTTSPEED_2400: + return 2400; + + case HWSETTINGS_HoTTSPEED_4800: + return 4800; + + case HWSETTINGS_HoTTSPEED_9600: + return 9600; + + case HWSETTINGS_HoTTSPEED_19200: + return 19200; + + case HWSETTINGS_HoTTSPEED_38400: + return 38400; + + case HWSETTINGS_HoTTSPEED_57600: + return 57600; + + default: + case HWSETTINGS_HoTTSPEED_115200: + return 115200; + } +} + + +/** + * Module start routine automatically called after initialization routine + * @return 0 when was successful + */ +static int32_t uavoHoTTBridgeStart(void) +{ + if (!module_enabled) { + // give port to telemetry if it doesn't have one + // stops board getting stuck in condition where it can't be connected to gcs + if (!PIOS_COM_TELEM_RF) { + PIOS_COM_TELEM_RF = PIOS_COM_HoTT; + } + + return -1; + } + + PIOS_DELTATIME_Init(&ros->roundtrip, 1e-3f, 1e-6f, 10.0f, 1e-1f); + ros->pingTimer = 0; + ros->stateTimer = 0; + ros->rateTimer = 0; + ros->rateAccumulator[0] = 0; + ros->rateAccumulator[1] = 0; + ros->rateAccumulator[2] = 0; + ros->rx_length = 0; + ros->myPingSequence = 0x66; + + xTaskHandle taskHandle; + + xTaskCreate(uavoHoTTBridgeRxTask, "uavoHoTTBridge", STACK_SIZE_BYTES / 4, NULL, TASK_PRIORITY, &taskHandle); + PIOS_TASK_MONITOR_RegisterTask(TASKINFO_RUNNING_UAVOHoTTBRIDGE, taskHandle); + PIOS_CALLBACKSCHEDULER_Dispatch(callbackHandle); + + return 0; +} + +/** + * Module initialization routine + * @return 0 when initialization was successful + */ +static int32_t uavoHoTTBridgeInitialize(void) +{ + if (PIOS_COM_HoTT) { + ros = pios_malloc(sizeof(*ros)); + if (ros != NULL) { + memset(ros, 0x00, sizeof(*ros)); + + ros->com = PIOS_COM_HoTT; + + HoTTBridgeStatusInitialize(); + AUXPositionSensorInitialize(); + HwSettingsInitialize(); + HwSettingsHoTTSpeedOptions rosSpeed; + HwSettingsHoTTSpeedGet(&rosSpeed); + + PIOS_COM_ChangeBaud(PIOS_COM_HoTT, 19200); // HoTT uses 19200 only + // TODO: set COM port to 1-wire here, once PIOS_COM_ioctl is implemented + callbackHandle = PIOS_CALLBACKSCHEDULER_Create(&uavoHoTTBridgeTxTask, CALLBACK_PRIORITY, CBTASK_PRIORITY, CALLBACKINFO_RUNNING_UAVOHoTTBRIDGE, STACK_SIZE_BYTES); + //VelocityStateInitialize(); + //PositionStateInitialize(); + //AttitudeStateInitialize(); + //AttitudeStateConnectCallback(&AttitudeCb); + //GyroStateInitialize(); + //GyroStateConnectCallback(&RateCb); + //FlightStatusInitialize(); + //PathDesiredInitialize(); + //PoiLocationInitialize(); + //ActuatorDesiredInitialize(); + //FlightModeSettingsInitialize(); + //ManualControlCommandInitialize(); + //AccessoryDesiredInitialize(); + + module_enabled = true; + return 0; + } + } + + return -1; +} +MODULE_INITCALL(uavoHoTTBridgeInitialize, uavoHoTTBridgeStart); + +/** various handlers **/ +static void ping_r_handler(struct ros_bridge *rb, rosbridgemessage_t *m) +{ + rosbridgemessage_pingpong_t *data = (rosbridgemessage_pingpong_t *)&(m->data); + + rb->remotePingSequence = data->sequence_number; + rb->scheduled[HoTTBRIDGEMESSAGE_PONG] = true; + PIOS_CALLBACKSCHEDULER_Dispatch(callbackHandle); +} + +static void ping_handler(struct ros_bridge *rb, rosbridgemessage_t *m) +{ + rosbridgemessage_pingpong_t *data = (rosbridgemessage_pingpong_t *)&(m->data); + + data->sequence_number = ++rb->myPingSequence; + rb->roundtrip.last = PIOS_DELAY_GetRaw(); +} + +static void pong_r_handler(struct ros_bridge *rb, rosbridgemessage_t *m) +{ + rosbridgemessage_pingpong_t *data = (rosbridgemessage_pingpong_t *)&(m->data); + + if (data->sequence_number != rb->myPingSequence) { + return; + } + float roundtrip = PIOS_DELTATIME_GetAverageSeconds(&(rb->roundtrip)); + HoTTBridgeStatusPingRoundTripTimeSet(&roundtrip); +} + +static void flightcontrol_r_handler(__attribute__((unused)) struct ros_bridge *rb, rosbridgemessage_t *m) +{ + rosbridgemessage_flightcontrol_t *data = (rosbridgemessage_flightcontrol_t *)&(m->data); + FlightStatusFlightModeOptions mode; + + FlightStatusFlightModeGet(&mode); + if (mode != FLIGHTSTATUS_FLIGHTMODE_HoTTCONTROLLED) { + return; + } + PathDesiredData pathDesired; + PathDesiredGet(&pathDesired); + switch (data->mode) { + case HoTTBRIDGEMESSAGE_FLIGHTCONTROL_MODE_WAYPOINT: + { + FlightModeSettingsPositionHoldOffsetData offset; + FlightModeSettingsPositionHoldOffsetGet(&offset); + pathDesired.End.North = boundf(data->control[0], settings.GeoFenceBoxMin.North, settings.GeoFenceBoxMax.North); + pathDesired.End.East = boundf(data->control[1], settings.GeoFenceBoxMin.East, settings.GeoFenceBoxMax.East); + pathDesired.End.Down = boundf(data->control[2], settings.GeoFenceBoxMin.Down, settings.GeoFenceBoxMax.Down); + pathDesired.Start.North = pathDesired.End.North + offset.Horizontal; + pathDesired.Start.East = pathDesired.End.East; + pathDesired.Start.Down = pathDesired.End.Down; + pathDesired.StartingVelocity = 0.0f; + pathDesired.EndingVelocity = 0.0f; + pathDesired.Mode = PATHDESIRED_MODE_GOTOENDPOINT; + } + break; + case HoTTBRIDGEMESSAGE_FLIGHTCONTROL_MODE_ATTITUDE: + { + pathDesired.ModeParameters[0] = data->control[0]; + pathDesired.ModeParameters[1] = data->control[1]; + pathDesired.ModeParameters[2] = data->control[2]; + pathDesired.ModeParameters[3] = data->control[3]; + pathDesired.Mode = PATHDESIRED_MODE_FIXEDATTITUDE; + } + break; + } + PathDesiredSet(&pathDesired); + PoiLocationData poiLocation; + PoiLocationGet(&poiLocation); + poiLocation.North = data->poi[0]; + poiLocation.East = data->poi[1]; + poiLocation.Down = data->poi[2]; + PoiLocationSet(&poiLocation); +} +static void pos_estimate_r_handler(__attribute__((unused)) struct ros_bridge *rb, rosbridgemessage_t *m) +{ + rosbridgemessage_pos_estimate_t *data = (rosbridgemessage_pos_estimate_t *)&(m->data); + AUXPositionSensorData pos; + + pos.North = data->position[0]; + pos.East = data->position[1]; + pos.Down = data->position[2]; + AUXPositionSensorSet(&pos); +} + +static void pong_handler(struct ros_bridge *rb, rosbridgemessage_t *m) +{ + rosbridgemessage_pingpong_t *data = (rosbridgemessage_pingpong_t *)&(m->data); + + + data->sequence_number = rb->remotePingSequence; +} + +static void fullstate_estimate_handler(__attribute__((unused)) struct ros_bridge *rb, rosbridgemessage_t *m) +{ + PositionStateData pos; + VelocityStateData vel; + AttitudeStateData att; + FlightStatusFlightModeOptions mode; + FlightStatusArmedOptions armed; + float thrust; + AccessoryDesiredData accessory; + ManualControlCommandData manualcontrol; + + ManualControlCommandGet(&manualcontrol); + FlightStatusArmedGet(&armed); + FlightStatusFlightModeGet(&mode); + ActuatorDesiredThrustGet(&thrust); + PositionStateGet(&pos); + VelocityStateGet(&vel); + AttitudeStateGet(&att); + rosbridgemessage_fullstate_estimate_t *data = (rosbridgemessage_fullstate_estimate_t *)&(m->data); + data->quaternion[0] = att.q1; + data->quaternion[1] = att.q2; + data->quaternion[2] = att.q3; + data->quaternion[3] = att.q4; + data->position[0] = pos.North; + data->position[1] = pos.East; + data->position[2] = pos.Down; + data->velocity[0] = vel.North; + data->velocity[1] = vel.East; + data->velocity[2] = vel.Down; + data->rotation[0] = ros->rateAccumulator[0]; + data->rotation[1] = ros->rateAccumulator[1]; + data->rotation[2] = ros->rateAccumulator[2]; + data->thrust = thrust; + data->HoTTControlled = (mode == FLIGHTSTATUS_FLIGHTMODE_HoTTCONTROLLED) ? 1 : 0; + data->FlightMode = manualcontrol.FlightModeSwitchPosition; + data->armed = (armed == FLIGHTSTATUS_ARMED_ARMED) ? 1 : 0; + data->controls[0] = manualcontrol.Roll; + data->controls[1] = manualcontrol.Pitch; + data->controls[2] = manualcontrol.Yaw; + data->controls[3] = manualcontrol.Thrust; + data->controls[4] = manualcontrol.Collective; + data->controls[5] = manualcontrol.Throttle; + for (int t = 0; t < 4; t++) { + if (AccessoryDesiredInstGet(t, &accessory) == 0) { + data->accessory[t] = accessory.AccessoryVal; + } + } + + int x, y; + float *P[13]; + INSGetPAddress(P); + for (x = 0; x < 10; x++) { + for (y = 0; y < 10; y++) { + data->matrix[x * 10 + y] = P[x][y]; + } + } + if (ros->rateTimer >= 1) { + float factor = 1.0f / (float)ros->rateTimer; + data->rotation[0] *= factor; + data->rotation[1] *= factor; + data->rotation[2] *= factor; + ros->rateAccumulator[0] = 0; + ros->rateAccumulator[1] = 0; + ros->rateAccumulator[2] = 0; + ros->rateTimer = 0; + } +} +static void imu_average_handler(__attribute__((unused)) struct ros_bridge *rb, __attribute__((unused)) rosbridgemessage_t *m) +{ + // TODO +} +static void gimbal_estimate_handler(__attribute__((unused)) struct ros_bridge *rb, __attribute__((unused)) rosbridgemessage_t *m) +{ + // TODO +} + +/** + * Main task routine + * @param[in] parameters parameter given by PIOS_Callback_Create() + */ +static void uavoHoTTBridgeTxTask(void) +{ + uint8_t buffer[HoTTBRIDGEMESSAGE_BUFFERSIZE]; // buffer on the stack? could also be in static RAM but not reuseale by other callbacks then + rosbridgemessage_t *message = (rosbridgemessage_t *)buffer; + + for (rosbridgemessagetype_t type = HoTTBRIDGEMESSAGE_PING; type < HoTTBRIDGEMESSAGE_END_ARRAY_SIZE; type++) { + if (ros->scheduled[type] && rosbridgemessagehandlers[type] != NULL) { + message->magic = HoTTBRIDGEMAGIC; + message->length = HoTTBRIDGEMESSAGE_SIZES[type]; + message->type = type; + message->timestamp = PIOS_DELAY_GetuS(); + (*rosbridgemessagehandlers[type])(ros, message); + message->crc32 = PIOS_CRC32_updateCRC(0xffffffff, message->data, message->length); + int32_t ret = PIOS_COM_SendBufferNonBlocking(ros->com, buffer, offsetof(rosbridgemessage_t, data) + message->length); + // int32_t ret = PIOS_COM_SendBuffer(ros->com, buffer, offsetof(rosbridgemessage_t, data) + message->length); + ros->scheduled[type] = false; + if (ret >= 0) { + uint32_t txpackets; + HoTTBridgeStatusTxPacketsGet(&txpackets); + txpackets++; + HoTTBridgeStatusTxPacketsSet(&txpackets); + } else { + uint32_t txfail; + HoTTBridgeStatusTxFailGet(&txfail); + txfail++; + HoTTBridgeStatusTxFailSet(&txfail); + } + PIOS_CALLBACKSCHEDULER_Dispatch(callbackHandle); + return; + } + } + // nothing scheduled, do a ping in 10 secods time +} + +/** + * Event Callback on Gyro updates (called with PIOS_SENSOR_RATE - roughly 500 Hz - from State Estimation) + */ +void RateCb(__attribute__((unused)) UAVObjEvent *ev) +{ + GyroStateData gyr; + + GyroStateGet(&gyr); + ros->rateAccumulator[0] += gyr.x; + ros->rateAccumulator[1] += gyr.y; + ros->rateAccumulator[2] += gyr.z; + ros->rateTimer++; +} + +/** + * Event Callback on Attitude updates (called with PIOS_SENSOR_RATE - roughly 500 Hz - from State Estimation) + */ +void AttitudeCb(__attribute__((unused)) UAVObjEvent *ev) +{ + bool dispatch = false; + + if (++ros->pingTimer >= settings.UpdateRate.Ping && settings.UpdateRate.Ping > 0) { + ros->pingTimer = 0; + dispatch = true; + ros->scheduled[HoTTBRIDGEMESSAGE_PING] = true; + } + if (++ros->stateTimer >= settings.UpdateRate.State && settings.UpdateRate.State > 0) { + ros->stateTimer = 0; + dispatch = true; + ros->scheduled[HoTTBRIDGEMESSAGE_FULLSTATE_ESTIMATE] = true; + } + if (dispatch && callbackHandle) { + PIOS_CALLBACKSCHEDULER_Dispatch(callbackHandle); + } +} + +/** + * Main task routine + * @param[in] parameters parameter given by PIOS_Thread_Create() + */ +static void uavoHoTTBridgeRxTask(__attribute__((unused)) void *parameters) +{ + while (1) { + uint8_t b = 0; + uint16_t count = PIOS_COM_ReceiveBuffer(ros->com, &b, 1, ~0); + if (count) { + ros_receive_byte(ros, b); + } + } +} + +#endif // PIOS_INCLUDE_HoTT_BRIDGE +/** + * @} + * @} + */ From faf894c5306e1e58b5362c2f1ba12d501aef1058 Mon Sep 17 00:00:00 2001 From: Corvus Corax Date: Thu, 23 Mar 2017 08:53:45 +0100 Subject: [PATCH 191/624] LP-500 Added UAVObject for HoTT bridge --- .../targets/boards/revolution/firmware/Makefile | 1 + .../boards/revolution/firmware/UAVObjects.inc | 1 + shared/uavobjectdefinition/hottbridgestatus.xml | 16 ++++++++++++++++ 3 files changed, 18 insertions(+) create mode 100644 shared/uavobjectdefinition/hottbridgestatus.xml diff --git a/flight/targets/boards/revolution/firmware/Makefile b/flight/targets/boards/revolution/firmware/Makefile index 5ee49d1a22..6a51ba5a2b 100644 --- a/flight/targets/boards/revolution/firmware/Makefile +++ b/flight/targets/boards/revolution/firmware/Makefile @@ -55,6 +55,7 @@ MODULES += Notify OPTMODULES += AutoTune OPTMODULES += ComUsbBridge +OPTMODULES += UAVOHottBridge OPTMODULES += UAVOMSPBridge OPTMODULES += UAVOMavlinkBridge diff --git a/flight/targets/boards/revolution/firmware/UAVObjects.inc b/flight/targets/boards/revolution/firmware/UAVObjects.inc index 5774e7ae43..f6d8d79875 100644 --- a/flight/targets/boards/revolution/firmware/UAVObjects.inc +++ b/flight/targets/boards/revolution/firmware/UAVObjects.inc @@ -126,6 +126,7 @@ UAVOBJSRCFILENAMES += poilearnsettings UAVOBJSRCFILENAMES += mpugyroaccelsettings UAVOBJSRCFILENAMES += txpidsettings UAVOBJSRCFILENAMES += txpidstatus +UAVOBJSRCFILENAMES += hottbridgestatus UAVOBJSRCFILENAMES += takeofflocation UAVOBJSRCFILENAMES += perfcounter UAVOBJSRCFILENAMES += systemidentsettings diff --git a/shared/uavobjectdefinition/hottbridgestatus.xml b/shared/uavobjectdefinition/hottbridgestatus.xml new file mode 100644 index 0000000000..06fe13a455 --- /dev/null +++ b/shared/uavobjectdefinition/hottbridgestatus.xml @@ -0,0 +1,16 @@ + + + HoTTBridge Status Information + + + + + + + + + + + + + From 02b5f26a7273ccb7cec46ecd0bd5180465d3ec4b Mon Sep 17 00:00:00 2001 From: Corvus Corax Date: Thu, 23 Mar 2017 10:02:33 +0100 Subject: [PATCH 192/624] LP-500 HoTT Telemetry added device definitions --- flight/targets/boards/revolution/firmware/pios_board.c | 4 ++++ flight/targets/boards/revolution/pios_board.h | 2 ++ 2 files changed, 6 insertions(+) diff --git a/flight/targets/boards/revolution/firmware/pios_board.c b/flight/targets/boards/revolution/firmware/pios_board.c index 9c42aa0ef0..3470af2739 100644 --- a/flight/targets/boards/revolution/firmware/pios_board.c +++ b/flight/targets/boards/revolution/firmware/pios_board.c @@ -251,6 +251,9 @@ uint32_t pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_NONE]; #define PIOS_COM_BRIDGE_RX_BUF_LEN 65 #define PIOS_COM_BRIDGE_TX_BUF_LEN 12 +#define PIOS_COM_HOTT_RX_BUF_LEN 512 +#define PIOS_COM_HOTT_TX_BUF_LEN 512 + #define PIOS_COM_RFM22B_RF_RX_BUF_LEN 512 #define PIOS_COM_RFM22B_RF_TX_BUF_LEN 512 @@ -272,6 +275,7 @@ uint32_t pios_com_telem_usb_id = 0; uint32_t pios_com_telem_rf_id = 0; uint32_t pios_com_rf_id = 0; uint32_t pios_com_bridge_id = 0; +uint32_t pios_com_hott_id = 0; uint32_t pios_com_overo_id = 0; uint32_t pios_com_hkosd_id = 0; uint32_t pios_com_vcp_id = 0; diff --git a/flight/targets/boards/revolution/pios_board.h b/flight/targets/boards/revolution/pios_board.h index a97fdbd670..fb0f469e81 100644 --- a/flight/targets/boards/revolution/pios_board.h +++ b/flight/targets/boards/revolution/pios_board.h @@ -146,6 +146,7 @@ extern uint32_t pios_com_rf_id; extern uint32_t pios_com_gps_id; extern uint32_t pios_com_telem_usb_id; extern uint32_t pios_com_bridge_id; +extern uint32_t pios_com_hott_id; extern uint32_t pios_com_vcp_id; extern uint32_t pios_com_hkosd_id; extern uint32_t pios_com_msp_id; @@ -156,6 +157,7 @@ extern uint32_t pios_com_mavlink_id; #define PIOS_COM_TELEM_RF (pios_com_telem_rf_id) #define PIOS_COM_RF (pios_com_rf_id) #define PIOS_COM_BRIDGE (pios_com_bridge_id) +#define PIOS_COM_HOTT (pios_com_hott_id) #define PIOS_COM_VCP (pios_com_vcp_id) #define PIOS_COM_OSDHK (pios_com_hkosd_id) #define PIOS_COM_MSP (pios_com_msp_id) From a2f833641b46470dabb4aef744b3a75324b87ab4 Mon Sep 17 00:00:00 2001 From: Eric Price Date: Thu, 23 Mar 2017 12:29:39 +0100 Subject: [PATCH 193/624] LP-500 add hottbridgestatus uavobjct to GCS --- ground/gcs/src/plugins/uavobjects/uavobjects.pro | 1 + 1 file changed, 1 insertion(+) diff --git a/ground/gcs/src/plugins/uavobjects/uavobjects.pro b/ground/gcs/src/plugins/uavobjects/uavobjects.pro index 942e797421..23bce4c0bf 100644 --- a/ground/gcs/src/plugins/uavobjects/uavobjects.pro +++ b/ground/gcs/src/plugins/uavobjects/uavobjects.pro @@ -94,6 +94,7 @@ UAVOBJS = \ $${UAVOBJ_XML_DIR}/gyrosensor.xml \ $${UAVOBJ_XML_DIR}/gyrostate.xml \ $${UAVOBJ_XML_DIR}/homelocation.xml \ + $${UAVOBJ_XML_DIR}/hottbridgestatus.xml \ $${UAVOBJ_XML_DIR}/hwsettings.xml \ $${UAVOBJ_XML_DIR}/i2cstats.xml \ $${UAVOBJ_XML_DIR}/magsensor.xml \ From 545f1c863bbfc5146c6cb27eaf1ec33fb4f963f5 Mon Sep 17 00:00:00 2001 From: Eric Price Date: Fri, 24 Mar 2017 07:01:47 +0100 Subject: [PATCH 194/624] LP-500 HoTT Bridge Module ported from TauLabs --- .../UAVOHottBridge/inc/uavohottbridge.h | 379 +++++ .../modules/UAVOHottBridge/uavohottbridge.c | 1269 +++++++++++------ flight/pios/common/pios_com.c | 24 + flight/pios/inc/pios_com.h | 2 + flight/pios/stm32f4xx/pios_usart.c | 32 +- .../boards/revolution/firmware/UAVObjects.inc | 1 + .../revolution/firmware/inc/pios_config.h | 1 + .../boards/revolution/firmware/pios_board.c | 5 + .../gcs/src/plugins/uavobjects/uavobjects.pro | 1 + .../hottbridgesettings.xml | 82 ++ shared/uavobjectdefinition/hwsettings.xml | 4 +- shared/uavobjectdefinition/taskinfo.xml | 3 + 12 files changed, 1346 insertions(+), 457 deletions(-) create mode 100644 flight/modules/UAVOHottBridge/inc/uavohottbridge.h create mode 100644 shared/uavobjectdefinition/hottbridgesettings.xml diff --git a/flight/modules/UAVOHottBridge/inc/uavohottbridge.h b/flight/modules/UAVOHottBridge/inc/uavohottbridge.h new file mode 100644 index 0000000000..470ab63048 --- /dev/null +++ b/flight/modules/UAVOHottBridge/inc/uavohottbridge.h @@ -0,0 +1,379 @@ +/** + ****************************************************************************** + * @addtogroup Modules + * @{ + * @addtogroup UAVOHoTTBridge UAVO to HoTT Bridge Telemetry Module + * @{ + * + * @file uavohottbridge.h + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017. + * Tau Labs, http://taulabs.org, Copyright (C) 2013 + * @brief sends telemery data on HoTT request + * + * @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 + */ + +// timing variables +#define IDLE_TIME 10 // idle line delay to prevent data crashes on telemetry line. +#define DATA_TIME 3 // time between 2 transmitted bytes + +// sizes and lengths +#define climbratesize 50 // defines size of ring buffer for climbrate calculation +#define statussize 21 // number of characters in status line +#define HOTT_MAX_MESSAGE_LENGTH 200 + +// scale factors +#define M_TO_CM 100 // scale m to cm or m/s to cm/s +#define MS_TO_KMH 3.6f // scale m/s to km/h +#define DEG_TO_UINT 0.5f // devide degrees by 2. then the value fits into a byte. + +// offsets. used to make transmitted values unsigned. +#define OFFSET_ALTITUDE 500 // 500m +#define OFFSET_CLIMBRATE 30000 // 30000cm/s or 300m/s +#define OFFSET_CLIMBRATE3S 120 // 120m/s +#define OFFSET_TEMPERATURE 20 // 20 degrees + +// Bits to invert display areas or values +#define VARIO_INVERT_ALT (1 << 0) // altitude +#define VARIO_INVERT_MAX (1 << 1) // max altitude +#define VARIO_INVERT_MIN (1 << 2) // min altitude +#define VARIO_INVERT_CR1S (1 << 3) // climbrate 1s +#define VARIO_INVERT_CR3S (1 << 4) // climbrate 3s +#define VARIO_INVERT_CR10S (1 << 5) // climbrate 10s + +#define GPS_INVERT_HDIST (1 << 0) // home distance +#define GPS_INVERT_SPEED (1 << 1) // speed (kmh) +#define GPS_INVERT_ALT (1 << 2) // altitude +#define GPS_INVERT_CR1S (1 << 3) // climbrate 1s +#define GPS_INVERT_CR3S (1 << 4) // climbrate 3s +#define GPS_INVERT2_POS (1 << 0) // GPS postion values + +#define GAM_INVERT_CELL (1 << 0) // cell voltage +#define GAM_INVERT_BATT1 (1 << 1) // battery 1 voltage +#define GAM_INVERT_BATT2 (1 << 2) // battery 1 voltage +#define GAM_INVERT_TEMP1 (1 << 3) // temperature 1 +#define GAM_INVERT_TEMP2 (1 << 4) // temperature 2 +#define GAM_INVERT_FUEL (1 << 5) // fuel +#define GAM_INVERT2_CURRENT (1 << 0) // current +#define GAM_INVERT2_VOLTAGE (1 << 1) // voltage +#define GAM_INVERT2_ALT (1 << 2) // altitude +#define GAM_INVERT2_CR1S (1 << 3) // climbrate 1s +#define GAM_INVERT2_CR3S (1 << 4) // climbrate 3s + +#define EAM_INVERT_CAPACITY (1 << 0) // capacity +#define EAM_INVERT_BATT1 (1 << 1) // battery 1 voltage +#define EAM_INVERT_BATT2 (1 << 2) // battery 1 voltage +#define EAM_INVERT_TEMP1 (1 << 3) // temperature 1 +#define EAM_INVERT_TEMP2 (1 << 4) // temperature 2 +#define EAM_INVERT_ALT (1 << 5) // altitude +#define EAM_INVERT_CURRENT (1 << 6) // current +#define EAM_INVERT_VOLTAGE (1 << 7) // voltage +#define EAM_INVERT2_ALT (1 << 2) // altitude +#define EAM_INVERT2_CR1S (1 << 3) // climbrate 1s +#define EAM_INVERT2_CR3S (1 << 4) // climbrate 3s + +#define ESC_INVERT_VOLTAGE (1 << 0) // voltage +#define ESC_INVERT_TEMP1 (1 << 1) // temperature 1 +#define ESC_INVERT_TEMP2 (1 << 2) // temperature 2 +#define ESC_INVERT_CURRENT (1 << 3) // current +#define ESC_INVERT_RPM (1 << 4) // rpm +#define ESC_INVERT_CAPACITY (1 << 5) // capacity +#define ESC_INVERT_MAXCURRENT (1 << 6) // maximum current + +// message codes +#define HOTT_TEXT_ID 0x7f // Text request +#define HOTT_BINARY_ID 0x80 // Binary request +#define HOTT_VARIO_ID 0x89 // Vario Module ID +#define HOTT_VARIO_TEXT_ID 0x90 // Vario Module TEXT ID +#define HOTT_GPS_ID 0x8a // GPS Module ID +#define HOTT_GPS_TEXT_ID 0xa0 // GPS Module TEXT ID +#define HOTT_ESC_ID 0x8c // ESC Module ID +#define HOTT_ESC_TEXT_ID 0xc0 // ESC Module TEXT ID +#define HOTT_GAM_ID 0x8d // General Air Module ID +#define HOTT_GAM_TEXT_ID 0xd0 // General Air Module TEXT ID +#define HOTT_EAM_ID 0x8e // Electric Air Module ID +#define HOTT_EAM_TEXT_ID 0xe0 // Electric Air Module TEXT ID +#define HOTT_TEXT_START 0x7b // Start byte Text mode +#define HOTT_START 0x7c // Start byte Binary mode +#define HOTT_STOP 0x7d // End byte +#define HOTT_BUTTON_DEC 0xEB // minus button +#define HOTT_BUTTON_INC 0xED // plus button +#define HOTT_BUTTON_SET 0xE9 // set button +#define HOTT_BUTTON_NIL 0x0F // esc button +#define HOTT_BUTTON_NEXT 0xEE // next button +#define HOTT_BUTTON_PREV 0xE7 // previous button + +// prefined signal tones or spoken announcments +#define HOTT_TONE_A 1 // minimum speed +#define HOTT_TONE_B 2 // sink rate 3 seconds +#define HOTT_TONE_C 3 // sink rate 1 second +#define HOTT_TONE_D 4 // maximum distance +#define HOTT_TONE_E 5 // - +#define HOTT_TONE_F 6 // minimum temperature sensor 1 +#define HOTT_TONE_G 7 // minimum temperature sensor 2 +#define HOTT_TONE_H 8 // maximum temperature sensor 1 +#define HOTT_TONE_I 9 // maximum temperature sensor 2 +#define HOTT_TONE_J 10 // overvoltage sensor 1 +#define HOTT_TONE_K 11 // overvoltage sensor 2 +#define HOTT_TONE_L 12 // maximum speed +#define HOTT_TONE_M 13 // climb rate 3 seconds +#define HOTT_TONE_N 14 // climb rate 1 second +#define HOTT_TONE_O 15 // minimum height +#define HOTT_TONE_P 16 // minimum input voltage +#define HOTT_TONE_Q 17 // minimum cell voltage +#define HOTT_TONE_R 18 // undervoltage sensor 1 +#define HOTT_TONE_S 19 // undervoltage sensor 2 +#define HOTT_TONE_T 20 // minimum rpm +#define HOTT_TONE_U 21 // fuel reserve +#define HOTT_TONE_V 22 // capacity +#define HOTT_TONE_W 23 // maximum current +#define HOTT_TONE_X 24 // maximum input voltage +#define HOTT_TONE_Y 25 // maximum rpm +#define HOTT_TONE_Z 26 // maximum height +#define HOTT_TONE_20M 37 // 20 meters +#define HOTT_TONE_40M 38 // 40 meters +#define HOTT_TONE_60M 39 // 60 meters +#define HOTT_TONE_80M 40 // 80 meters +#define HOTT_TONE_100M 41 // 100 meters +#define HOTT_TONE_42 42 // receiver voltage +#define HOTT_TONE_43 43 // receiver temperature +#define HOTT_TONE_200M 46 // 200 meters +#define HOTT_TONE_400M 47 // 400 meters +#define HOTT_TONE_600M 48 // 600 meters +#define HOTT_TONE_800M 49 // 800 meters +#define HOTT_TONE_1000M 50 // 10000 meters +#define HOTT_TONE_51 51 // maximum servo temperature +#define HOTT_TONE_52 52 // maximum servo position difference + + +// Private types +typedef struct { + uint8_t l; + uint8_t h; +} uword_t; + +// Private structures +struct telemetrydata { + HoTTBridgeSettingsData Settings; + AttitudeStateData Attitude; + BaroSensorData Baro; + FlightBatteryStateData Battery; + FlightStatusData FlightStatus; + GPSPositionSensorData GPS; + GPSTimeData GPStime; + GyroSensorData Gyro; + HomeLocationData Home; + PositionStateData Position; + SystemAlarmsData SysAlarms; + VelocityStateData Velocity; + int16_t climbratebuffer[climbratesize]; + uint8_t climbrate_pointer; + float altitude; + float min_altitude; + float max_altitude; + float altitude_last; + float climbrate1s; + float climbrate3s; + float climbrate10s; + float homedistance; + float homecourse; + uint8_t last_armed; + char statusline[statussize]; +}; + +// VARIO Module message structure +struct hott_vario_message { + uint8_t start; // start byte + uint8_t sensor_id; // VARIO sensor ID + uint8_t warning; // 0…= warning beeps + uint8_t sensor_text_id; // VARIO sensor text ID + uint8_t alarm_inverse; // this inverts specific parts of display + uword_t altitude; // altitude (meters), offset 500, 500 == 0m + uword_t max_altitude; // max. altitude (meters) + uword_t min_altitude; // min. altitude (meters) + uword_t climbrate; // climb rate (0.01m/s), offset 30000, 30000 == 0.00m/s + uword_t climbrate3s; // climb rate (0.01m/3s) + uword_t climbrate10s; // climb rate (0.01m/10s) + uint8_t ascii[21]; // 21 chars of text + uint8_t ascii1; // ASCII Free character [1] (next to Alt) + uint8_t ascii2; // ASCII Free character [2] (next to Dir) + uint8_t ascii3; // ASCII Free character [3] (next to I) + int8_t compass; // 1=2°, -1=-2° + uint8_t version; // version number + uint8_t stop; // stop byte + uint8_t checksum; // Lower 8-bits of all bytes summed +}; + +// GPS Module message structure +struct hott_gps_message { + uint8_t start; // start byte + uint8_t sensor_id; // GPS sensor ID + uint8_t warning; // 0…= warning beeps + uint8_t sensor_text_id; // GPS Sensor text mode ID + uint8_t alarm_inverse1; // this inverts specific parts of display + uint8_t alarm_inverse2; + uint8_t flight_direction; // flight direction (1 = 2°; 0° = north, 90° = east , 180° = south , 270° west) + uword_t gps_speed; // GPS speed (km/h) + uint8_t latitude_ns; // GPS latitude north/south (0 = N) + uword_t latitude_min; // GPS latitude (min) + uword_t latitude_sec; // GPS latitude (sec) + uint8_t longitude_ew; // GPS longitude east/west (0 = E) + uword_t longitude_min; // GPS longitude (min) + uword_t longitude_sec; // GPS longitude (sec) + uword_t distance; // distance from home location (meters) + uword_t altitude; // altitude (meters), offset 500, 500 == 0m + uword_t climbrate; // climb rate (0.01m/s), offset of 30000, 30000 = 0.00 m/s + uint8_t climbrate3s; // climb rate in (m/3s). offset of 120, 120 == 0m/3sec + uint8_t gps_num_sat; // GPS number of satelites + uint8_t gps_fix_char; // GPS FixChar ('D'=DGPS, '2'=2D, '3'=3D) + uint8_t home_direction; // home direction (1=2°, direction from starting point to model position) + int8_t angle_roll; // angle x-direction (roll 1=2°, 255=-2°) + int8_t angle_nick; // angle y-direction (nick) + int8_t angle_compass; // angle z-direction (yaw) + uint8_t gps_hour; // GPS time hours + uint8_t gps_min; // GPS time minutes + uint8_t gps_sec; // GPS time seconds + uint8_t gps_msec; // GPS time .sss + uword_t msl; // MSL or NN altitude + uint8_t vibration; // vibration + uint8_t ascii4; // ASCII Free Character [4] (next to home distance) + uint8_t ascii5; // ASCII Free Character [5] (next to home direction) + uint8_t ascii6; // ASCII Free Character [6] (next to number of sats) + uint8_t version; // version number (0=gps, 1=gyro, 255=multicopter) + uint8_t stop; // stop byte + uint8_t checksum; // Lower 8-bits of all bytes summed +}; + +// General Air Module message structure +struct hott_gam_message { + uint8_t start; // start byte + uint8_t sensor_id; // GAM sensor ID + uint8_t warning; // 0…= warning beeps + uint8_t sensor_text_id; // EAM Sensor text mode ID + uint8_t alarm_inverse1; // this inverts specific parts of display + uint8_t alarm_inverse2; + uint8_t cell1; // cell voltages in 0.02V steps, 210 == 4.2V + uint8_t cell2; + uint8_t cell3; + uint8_t cell4; + uint8_t cell5; + uint8_t cell6; + uword_t batt1_voltage; // battery sensor 1 in 0.1V steps, 50 == 5.5V + uword_t batt2_voltage; // battery sensor 2 voltage + uint8_t temperature1; // temperature 1 in °C, offset of 20, 20 == 0°C + uint8_t temperature2; // temperature 2 + uint8_t fuel_procent; // fuel capacity in %, values from 0..100 + uword_t fuel_ml; // fuel capacity in ml, values from 0..65535 + uword_t rpm; // rpm, scale factor 10, 300 == 3000rpm + uword_t altitude; // altitude in meters, offset of 500, 500 == 0m + uword_t climbrate; // climb rate (0.01m/s), offset of 30000, 30000 = 0.00 m/s + uint8_t climbrate3s; // climb rate (m/3sec). offset of 120, 120 == 0m/3sec + uword_t current; // current in 0.1A steps + uword_t voltage; // main power voltage in 0.1V steps + uword_t capacity; // used battery capacity in 10mAh steps + uword_t speed; // speed in km/h + uint8_t min_cell_volt; // lowest cell voltage in 20mV steps. 124 == 2.48V + uint8_t min_cell_volt_num; // number of the cell with the lowest voltage + uword_t rpm2; // rpm2 in 10 rpm steps, 300 == 3000rpm + uint8_t g_error_number; // general error number (Voice error == 12) + uint8_t pressure; // pressure up to 15bar, 0.1bar steps + uint8_t version; // version number + uint8_t stop; // stop byte + uint8_t checksum; // Lower 8-bits of all bytes summed +}; + +// Electric Air Module message structure +struct hott_eam_message { + uint8_t start; // Start byte + uint8_t sensor_id; // EAM sensor id + uint8_t warning; + uint8_t sensor_text_id; // EAM Sensor text mode ID + uint8_t alarm_inverse1; // this inverts specific parts of display + uint8_t alarm_inverse2; + uint8_t cell1_L; // cell voltages of the lower battery + uint8_t cell2_L; + uint8_t cell3_L; + uint8_t cell4_L; + uint8_t cell5_L; + uint8_t cell6_L; + uint8_t cell7_L; + uint8_t cell1_H; // cell voltages of higher battery + uint8_t cell2_H; + uint8_t cell3_H; + uint8_t cell4_H; + uint8_t cell5_H; + uint8_t cell6_H; + uint8_t cell7_H; + uword_t batt1_voltage; // battery sensor 1 voltage, in steps of 0.02V + uword_t batt2_voltage; // battery sensor 2 voltage, in steps of 0.02V + uint8_t temperature1; // temperature sensor 1. 20 = 0 degrees + uint8_t temperature2; // temperature sensor 2. 20 = 0 degrees + uword_t altitude; // altitude (meters). 500 = 0 meters + uword_t current; // current (A) in steps of 0.1A + uword_t voltage; // main power voltage in steps of 0.1V + uword_t capacity; // used battery capacity in steps of 10mAh + uword_t climbrate; // climb rate in 0.01m/s. 0m/s = 30000 + uint8_t climbrate3s; // climb rate in m/3sec. 0m/3sec = 120 + uword_t rpm; // rpm in steps of 10 rpm + uint8_t electric_min; // estaminated flight time in minutes. + uint8_t electric_sec; // estaminated flight time in seconds. + uword_t speed; // speed in km/h in steps of 1 km/h + uint8_t stop; // Stop byte + uint8_t checksum; // Lower 8-bits of all bytes summed. +}; + +// ESC Module message structure +struct hott_esc_message { + uint8_t start; // Start byte + uint8_t sensor_id; // EAM sensor id + uint8_t warning; + uint8_t sensor_text_id; // ESC Sensor text mode ID + uint8_t alarm_inverse1; + uint8_t alarm_inverse2; + uword_t batt_voltage; // battery voltage in steps of 0.1V + uword_t min_batt_voltage; // min battery voltage + uword_t batt_capacity; // used battery capacity in steps of 10mAh + uint8_t temperatureESC; // temperature of ESC . 20 = 0 degrees + uint8_t max_temperatureESC; // max temperature of ESC + uword_t current; // Current in steps of 0.1A + uword_t max_current; // maximal current + uword_t rpm; // rpm in steps of 10 rpm + uword_t max_rpm; // max rpm + uint8_t temperatureMOT; // motor temperature + uint8_t max_temperatureMOT; // maximal motor temperature + uint8_t dummy[19]; // 19 dummy bytes + uint8_t stop; // Stop byte + uint8_t checksum; // Lower 8-bits of all bytes summed. +}; + +// TEXT message structure +struct hott_text_message { + uint8_t start; // Start byte + uint8_t sensor_id; // TEXT id + uint8_t warning; + uint8_t text[21][8]; // text field 21 columns and 8 rows (bit 7=1 for inverse display) + uint8_t stop; // Stop byte + uint8_t checksum; // Lower 8-bits of all bytes summed. +}; + + +/** + * @} + * @} + */ diff --git a/flight/modules/UAVOHottBridge/uavohottbridge.c b/flight/modules/UAVOHottBridge/uavohottbridge.c index fdc5b0da49..56a442e367 100644 --- a/flight/modules/UAVOHottBridge/uavohottbridge.c +++ b/flight/modules/UAVOHottBridge/uavohottbridge.c @@ -2,12 +2,13 @@ ****************************************************************************** * @addtogroup OpenPilotModules OpenPilot Modules * @{ - * @addtogroup UAVOHoTTBridge UAVO to HoTT Bridge Module + * @addtogroup UAVOHoTTBridge UAVO to HoTT Bridge Telemetry Module * @{ * * @file uavohottridge.c * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017. - * @brief Bridges certain UAVObjects to HoTT on USB VCP + * Tau Labs, http://taulabs.org, Copyright (C) 2013-2014 + * @brief sends telemery data on HoTT request * * @see The GNU Public License (GPL) Version 3 * @@ -36,553 +37,925 @@ #include "hwsettings.h" #include "taskinfo.h" #include "callbackinfo.h" -/* -#include "insgps.h" - #include "receiverstatus.h" - #include "flightmodesettings.h" - #include "flightbatterysettings.h" - #include "flightbatterystate.h" - #include "gpspositionsensor.h" - #include "manualcontrolsettings.h" - #include "oplinkstatus.h" - #include "accessorydesired.h" - #include "airspeedstate.h" - #include "actuatorsettings.h" - #include "systemstats.h" - #include "systemalarms.h" - #include "takeofflocation.h" - #include "homelocation.h" - #include "stabilizationdesired.h" - #include "stabilizationsettings.h" - #include "stabilizationbank.h" - #include "stabilizationsettingsbank1.h" - #include "stabilizationsettingsbank2.h" - #include "stabilizationsettingsbank3.h" - #include "magstate.h" -#include "manualcontrolcommand.h" -#include "accessorydesired.h" -#include "actuatordesired.h" -#include "auxpositionsensor.h" -#include "pathdesired.h" -#include "poilocation.h" -#include "flightmodesettings.h" +#include "hottbridgesettings.h" +#include "attitudestate.h" +#include "barosensor.h" +#include "flightbatterystate.h" #include "flightstatus.h" +#include "gyrosensor.h" +#include "gpspositionsensor.h" +#include "gpstime.h" +#include "homelocation.h" #include "positionstate.h" +#include "systemalarms.h" #include "velocitystate.h" -#include "attitudestate.h" -#include "gyrostate.h" - */ - #include "hottbridgestatus.h" +#include "hottbridgesettings.h" #include "objectpersistence.h" - #include "pios_sensors.h" +#include "uavohottbridge.h" -#if defined(PIOS_INCLUDE_HoTT_BRIDGE) - -struct hott_bridge { - uintptr_t com; - - uint32_t lastPingTimestamp; - uint8_t myPingSequence; - uint8_t remotePingSequence; - PiOSDeltatimeConfig roundtrip; - double roundTripTime; - int32_t pingTimer; - int32_t stateTimer; - int32_t rateTimer; - float rateAccumulator[3]; - uint8_t rx_buffer[HoTTBRIDGEMESSAGE_BUFFERSIZE]; - size_t rx_length; - volatile bool scheduled[HoTTBRIDGEMESSAGE_END_ARRAY_SIZE]; -}; +#if defined(PIOS_INCLUDE_HOTT_BRIDGE) #if defined(PIOS_HoTT_STACK_SIZE) -#define STACK_SIZE_BYTES PIOS_HoTT_STACK_SIZE +#define STACK_SIZE_BYTES PIOS_HoTT_STACK_SIZE #else -#define STACK_SIZE_BYTES 2048 +#define STACK_SIZE_BYTES 2048 #endif -#define TASK_PRIORITY CALLBACK_TASK_AUXILIARY -#define CALLBACK_PRIORITY CALLBACK_PRIORITY_REGULAR -#define CBTASK_PRIORITY CALLBACK_TASK_AUXILIARY +#define TASK_PRIORITY CALLBACK_TASK_AUXILIARY static bool module_enabled = false; -static struct hott_bridge *hott; -static int32_t uavoHoTTBridgeInitialize(void); -static void uavoHoTTBridgeRxTask(void *parameters); -static void uavoHoTTBridgeTxTask(void); -static DelayedCallbackInfo *callbackHandle; -static hottbridgemessage_handler ping_handler, ping_r_handler, pong_handler, pong_r_handler, fullstate_estimate_handler, imu_average_handler, gimbal_estimate_handler, flightcontrol_r_handler, pos_estimate_r_handler; -static HoTTBridgeSettingsData settings; -void AttitudeCb(__attribute__((unused)) UAVObjEvent *ev); -void RateCb(__attribute__((unused)) UAVObjEvent *ev); - -static hottbridgemessage_handler *const hottbridgemessagehandlers[HoTTBRIDGEMESSAGE_END_ARRAY_SIZE] = { - ping_handler, - NULL, - NULL, - NULL, - pong_handler, - fullstate_estimate_handler, - imu_average_handler, - gimbal_estimate_handler -}; +// Private variables +static bool module_enabled; +static struct telemetrydata *telestate; +static HoTTBridgeStatusData status; + +// Private functions +static void uavoHoTTBridgeTask(void *parameters); +static uint16_t build_VARIO_message(struct hott_vario_message *msg); +static uint16_t build_GPS_message(struct hott_gps_message *msg); +static uint16_t build_GAM_message(struct hott_gam_message *msg); +static uint16_t build_EAM_message(struct hott_eam_message *msg); +static uint16_t build_ESC_message(struct hott_esc_message *msg); +static uint16_t build_TEXT_message(struct hott_text_message *msg); +static uint8_t calc_checksum(uint8_t *data, uint16_t size); +static uint8_t generate_warning(); +static void update_telemetrydata(); +static void convert_long2gps(int32_t value, uint8_t *dir, uword_t *min, uword_t *sec); +static uint8_t scale_float2uint8(float value, float scale, float offset); +static int8_t scale_float2int8(float value, float scale, float offset); +static uword_t scale_float2uword(float value, float scale, float offset); /** - * Process incoming bytes from an HoTT query thing. - * @param[in] b received byte - * @return true if we should continue processing bytes + * Module start routine automatically called after initialization routine + * @return 0 when was successful */ -static void hott_receive_byte(struct hott_bridge *m, uint8_t b) +static int32_t uavoHoTTBridgeStart(void) { - m->rx_buffer[m->rx_length] = b; - m->rx_length++; - hottbridgemessage_t *message = (hottbridgemessage_t *)m->rx_buffer; - - // very simple parser - but not a state machine, just a few checks - if (m->rx_length <= offsetof(hottbridgemessage_t, length)) { - // check (partial) magic number - partial is important since we need to restart at any time if garbage is received - uint32_t canary = 0xff; - for (uint32_t t = 1; t < m->rx_length; t++) { - canary = (canary << 8) || 0xff; - } - if ((message->magic & canary) != (HoTTBRIDGEMAGIC & canary)) { - // parse error, not beginning of message - goto rxfailure; - } - } - if (m->rx_length == offsetof(hottbridgemessage_t, timestamp)) { - if (message->length > (uint32_t)(HoTTBRIDGEMESSAGE_BUFFERSIZE - offsetof(hottbridgemessage_t, data))) { - // parse error, no messages are that long - goto rxfailure; - } - } - if (m->rx_length == offsetof(hottbridgemessage_t, crc32)) { - if (message->type >= HoTTBRIDGEMESSAGE_END_ARRAY_SIZE) { - // parse error - goto rxfailure; - } - if (message->length != HoTTBRIDGEMESSAGE_SIZES[message->type]) { - // parse error - goto rxfailure; - } - } - if (m->rx_length < offsetof(hottbridgemessage_t, data)) { - // not a parse failure, just not there yet - return; - } - if (m->rx_length == offsetof(hottbridgemessage_t, data) + HoTTBRIDGEMESSAGE_SIZES[message->type]) { - // complete message received and stored in pointer "message" - // empty buffer for next message - m->rx_length = 0; + status.TxPackets = 0; + status.RxPackets = 0; + status.TxFail = 0; + status.RxFail = 0; - if (PIOS_CRC32_updateCRC(0xffffffff, message->data, message->length) != message->crc32) { - // crc mismatch - goto rxfailure; - } - uint32_t rxpackets; - HoTTBridgeStatusRxPacketsGet(&rxpackets); - rxpackets++; - HoTTBridgeStatusRxPacketsSet(&rxpackets); - switch (message->type) { - case HoTTBRIDGEMESSAGE_PING: - ping_r_handler(m, message); - break; - case HoTTBRIDGEMESSAGE_POS_ESTIMATE: - pos_estimate_r_handler(m, message); - break; - case HoTTBRIDGEMESSAGE_FLIGHTCONTROL: - flightcontrol_r_handler(m, message); - break; - case HoTTBRIDGEMESSAGE_GIMBALCONTROL: - // TODO implement gimbal control somehow - break; - case HoTTBRIDGEMESSAGE_PONG: - pong_r_handler(m, message); - break; - default: - // do nothing at all and discard the message - break; - } + + // Start task + if (module_enabled) { + xTaskHandle taskHandle; + + xTaskCreate(uavoHoTTBridgeTask, "uavoHoTTBridge", STACK_SIZE_BYTES / 4, NULL, TASK_PRIORITY, &taskHandle); + PIOS_TASK_MONITOR_RegisterTask(TASKINFO_RUNNING_UAVOHOTTBRIDGE, taskHandle); } - return; -rxfailure: - m->rx_length = 0; - uint32_t rxfail; - HoTTBridgeStatusRxFailGet(&rxfail); - rxfail++; - HoTTBridgeStatusRxFailSet(&rxfail); + return 0; } -static uint32_t hwsettings_rosspeed_enum_to_baud(uint8_t baud) +/** + * Module initialization routine + * @return 0 when initialization was successful + */ +static int32_t uavoHoTTBridgeInitialize(void) { - switch (baud) { - case HWSETTINGS_HoTTSPEED_2400: - return 2400; - - case HWSETTINGS_HoTTSPEED_4800: - return 4800; - - case HWSETTINGS_HoTTSPEED_9600: - return 9600; - - case HWSETTINGS_HoTTSPEED_19200: - return 19200; - - case HWSETTINGS_HoTTSPEED_38400: - return 38400; - - case HWSETTINGS_HoTTSPEED_57600: - return 57600; - - default: - case HWSETTINGS_HoTTSPEED_115200: - return 115200; + if (PIOS_COM_HOTT) { + module_enabled = true; + // HoTT telemetry baudrate is fixed to 19200 + + PIOS_COM_ChangeBaud(PIOS_COM_HOTT, 19200); + PIOS_COM_SetHalfDuplex(PIOS_COM_HOTT, true); + HoTTBridgeSettingsInitialize(); + HoTTBridgeStatusInitialize(); + + // allocate memory for telemetry data + telestate = (struct telemetrydata *)pios_malloc(sizeof(*telestate)); + + if (telestate == NULL) { + // there is not enough free memory. the module could not run. + module_enabled = false; + return -1; + } + } else { + module_enabled = false; } + return 0; } - +MODULE_INITCALL(uavoHoTTBridgeInitialize, uavoHoTTBridgeStart); /** - * Module start routine automatically called after initialization routine - * @return 0 when was successful + * Main task. It does not return. */ -static int32_t uavoHoTTBridgeStart(void) +static void uavoHoTTBridgeTask(__attribute__((unused)) void *parameters) { - if (!module_enabled) { - // give port to telemetry if it doesn't have one - // stops board getting stuck in condition where it can't be connected to gcs - if (!PIOS_COM_TELEM_RF) { - PIOS_COM_TELEM_RF = PIOS_COM_HoTT; + uint8_t rx_buffer[2]; + uint8_t tx_buffer[HOTT_MAX_MESSAGE_LENGTH]; + uint16_t message_size; + + // clear all state values + memset(telestate, 0, sizeof(*telestate)); + + // initialize timer variables + portTickType lastSysTime = xTaskGetTickCount(); + // idle delay between telemetry request and answer + uint32_t idledelay = IDLE_TIME; + // data delay between transmitted bytes + uint32_t datadelay = DATA_TIME; + + // work on hott telemetry. endless loop. + while (1) { + // clear message size on every loop before processing + message_size = 0; + + // shift receiver buffer. make room for one byte. + rx_buffer[1] = rx_buffer[0]; + + // wait for a byte of telemetry request in data delay interval + while (PIOS_COM_ReceiveBuffer(PIOS_COM_HOTT, rx_buffer, 1, 0) == 0) { + vTaskDelayUntil(&lastSysTime, datadelay / portTICK_RATE_MS); + } + // set start trigger point + lastSysTime = xTaskGetTickCount(); + + // examine received data stream + if (rx_buffer[1] == HOTT_BINARY_ID) { + // first received byte looks like a binary request. check second received byte for a sensor id. + switch (rx_buffer[0]) { + case HOTT_VARIO_ID: + message_size = build_VARIO_message((struct hott_vario_message *)tx_buffer); + break; + case HOTT_GPS_ID: + message_size = build_GPS_message((struct hott_gps_message *)tx_buffer); + break; + case HOTT_GAM_ID: + message_size = build_GAM_message((struct hott_gam_message *)tx_buffer); + break; + case HOTT_EAM_ID: + message_size = build_EAM_message((struct hott_eam_message *)tx_buffer); + break; + case HOTT_ESC_ID: + message_size = build_ESC_message((struct hott_esc_message *)tx_buffer); + break; + default: + message_size = 0; + } + } else if (rx_buffer[1] == HOTT_TEXT_ID) { + // first received byte looks like a text request. check second received byte for a valid button. + switch (rx_buffer[0]) { + case HOTT_BUTTON_DEC: + case HOTT_BUTTON_INC: + case HOTT_BUTTON_SET: + case HOTT_BUTTON_NIL: + case HOTT_BUTTON_NEXT: + case HOTT_BUTTON_PREV: + message_size = build_TEXT_message((struct hott_text_message *)tx_buffer); + break; + default: + message_size = 0; + } } - return -1; - } + // check if a message is in the transmit buffer. + if (message_size > 0) { + status.RxPackets++; - PIOS_DELTATIME_Init(&ros->roundtrip, 1e-3f, 1e-6f, 10.0f, 1e-1f); - ros->pingTimer = 0; - ros->stateTimer = 0; - ros->rateTimer = 0; - ros->rateAccumulator[0] = 0; - ros->rateAccumulator[1] = 0; - ros->rateAccumulator[2] = 0; - ros->rx_length = 0; - ros->myPingSequence = 0x66; + // check idle line before transmit. pause, then check receiver buffer + vTaskDelayUntil(&lastSysTime, idledelay / portTICK_RATE_MS); - xTaskHandle taskHandle; + if (PIOS_COM_ReceiveBuffer(PIOS_COM_HOTT, rx_buffer, 1, 0) == 0) { + // nothing received means idle line. ready to transmit the requested message + for (int i = 0; i < message_size; i++) { + // send message content with pause between each byte + PIOS_COM_SendCharNonBlocking(PIOS_COM_HOTT, tx_buffer[i]); + // grab possible incoming loopback data and throw it away + PIOS_COM_ReceiveBuffer(PIOS_COM_HOTT, rx_buffer, sizeof(rx_buffer), 0); + vTaskDelayUntil(&lastSysTime, datadelay / portTICK_RATE_MS); + } + status.TxPackets++; - xTaskCreate(uavoHoTTBridgeRxTask, "uavoHoTTBridge", STACK_SIZE_BYTES / 4, NULL, TASK_PRIORITY, &taskHandle); - PIOS_TASK_MONITOR_RegisterTask(TASKINFO_RUNNING_UAVOHoTTBRIDGE, taskHandle); - PIOS_CALLBACKSCHEDULER_Dispatch(callbackHandle); - return 0; + // after transmitting the message, any loopback data needs to be cleaned up. + vTaskDelayUntil(&lastSysTime, idledelay / portTICK_RATE_MS); + PIOS_COM_ReceiveBuffer(PIOS_COM_HOTT, tx_buffer, message_size, 0); + } else { + status.RxFail++; + } + HoTTBridgeStatusSet(&status); + } + } } /** - * Module initialization routine - * @return 0 when initialization was successful + * Build requested answer messages. + * \return value sets message size */ -static int32_t uavoHoTTBridgeInitialize(void) +uint16_t build_VARIO_message(struct hott_vario_message *msg) { - if (PIOS_COM_HoTT) { - ros = pios_malloc(sizeof(*ros)); - if (ros != NULL) { - memset(ros, 0x00, sizeof(*ros)); - - ros->com = PIOS_COM_HoTT; - - HoTTBridgeStatusInitialize(); - AUXPositionSensorInitialize(); - HwSettingsInitialize(); - HwSettingsHoTTSpeedOptions rosSpeed; - HwSettingsHoTTSpeedGet(&rosSpeed); - - PIOS_COM_ChangeBaud(PIOS_COM_HoTT, 19200); // HoTT uses 19200 only - // TODO: set COM port to 1-wire here, once PIOS_COM_ioctl is implemented - callbackHandle = PIOS_CALLBACKSCHEDULER_Create(&uavoHoTTBridgeTxTask, CALLBACK_PRIORITY, CBTASK_PRIORITY, CALLBACKINFO_RUNNING_UAVOHoTTBRIDGE, STACK_SIZE_BYTES); - //VelocityStateInitialize(); - //PositionStateInitialize(); - //AttitudeStateInitialize(); - //AttitudeStateConnectCallback(&AttitudeCb); - //GyroStateInitialize(); - //GyroStateConnectCallback(&RateCb); - //FlightStatusInitialize(); - //PathDesiredInitialize(); - //PoiLocationInitialize(); - //ActuatorDesiredInitialize(); - //FlightModeSettingsInitialize(); - //ManualControlCommandInitialize(); - //AccessoryDesiredInitialize(); - - module_enabled = true; - return 0; - } + update_telemetrydata(); + + if (telestate->Settings.Sensor.VARIO == HOTTBRIDGESETTINGS_SENSOR_DISABLED) { + return 0; } - return -1; + // clear message buffer + memset(msg, 0, sizeof(*msg)); + + // message header + msg->start = HOTT_START; + msg->stop = HOTT_STOP; + msg->sensor_id = HOTT_VARIO_ID; + msg->warning = generate_warning(); + msg->sensor_text_id = HOTT_VARIO_TEXT_ID; + + // alarm inverse bits. invert display areas on limits + msg->alarm_inverse |= (telestate->Settings.Limit.MinHeight > telestate->altitude) ? VARIO_INVERT_ALT : 0; + msg->alarm_inverse |= (telestate->Settings.Limit.MaxHeight < telestate->altitude) ? VARIO_INVERT_ALT : 0; + msg->alarm_inverse |= (telestate->Settings.Limit.MaxHeight < telestate->altitude) ? VARIO_INVERT_MAX : 0; + msg->alarm_inverse |= (telestate->Settings.Limit.MinHeight > telestate->altitude) ? VARIO_INVERT_MIN : 0; + msg->alarm_inverse |= (telestate->Settings.Limit.NegDifference1 > telestate->climbrate1s) ? VARIO_INVERT_CR1S : 0; + msg->alarm_inverse |= (telestate->Settings.Limit.PosDifference1 < telestate->climbrate1s) ? VARIO_INVERT_CR1S : 0; + msg->alarm_inverse |= (telestate->Settings.Limit.NegDifference2 > telestate->climbrate3s) ? VARIO_INVERT_CR3S : 0; + msg->alarm_inverse |= (telestate->Settings.Limit.PosDifference2 < telestate->climbrate3s) ? VARIO_INVERT_CR3S : 0; + msg->alarm_inverse |= (telestate->Settings.Limit.NegDifference2 > telestate->climbrate10s) ? VARIO_INVERT_CR10S : 0; + msg->alarm_inverse |= (telestate->Settings.Limit.PosDifference2 < telestate->climbrate10s) ? VARIO_INVERT_CR10S : 0; + + // altitude relative to ground + msg->altitude = scale_float2uword(telestate->altitude, 1, OFFSET_ALTITUDE); + msg->min_altitude = scale_float2uword(telestate->min_altitude, 1, OFFSET_ALTITUDE); + msg->max_altitude = scale_float2uword(telestate->max_altitude, 1, OFFSET_ALTITUDE); + + // climbrate + msg->climbrate = scale_float2uword(telestate->climbrate1s, M_TO_CM, OFFSET_CLIMBRATE); + msg->climbrate3s = scale_float2uword(telestate->climbrate3s, M_TO_CM, OFFSET_CLIMBRATE); + msg->climbrate10s = scale_float2uword(telestate->climbrate10s, M_TO_CM, OFFSET_CLIMBRATE); + + // compass + msg->compass = scale_float2int8(telestate->Attitude.Yaw, DEG_TO_UINT, 0); + + // statusline + memcpy(msg->ascii, telestate->statusline, sizeof(msg->ascii)); + + // free display characters + msg->ascii1 = 0; + msg->ascii2 = 0; + msg->ascii3 = 0; + + msg->checksum = calc_checksum((uint8_t *)msg, sizeof(*msg)); + return sizeof(*msg); } -MODULE_INITCALL(uavoHoTTBridgeInitialize, uavoHoTTBridgeStart); -/** various handlers **/ -static void ping_r_handler(struct ros_bridge *rb, rosbridgemessage_t *m) +uint16_t build_GPS_message(struct hott_gps_message *msg) { - rosbridgemessage_pingpong_t *data = (rosbridgemessage_pingpong_t *)&(m->data); + update_telemetrydata(); - rb->remotePingSequence = data->sequence_number; - rb->scheduled[HoTTBRIDGEMESSAGE_PONG] = true; - PIOS_CALLBACKSCHEDULER_Dispatch(callbackHandle); -} + if (telestate->Settings.Sensor.GPS == HOTTBRIDGESETTINGS_SENSOR_DISABLED) { + return 0; + } -static void ping_handler(struct ros_bridge *rb, rosbridgemessage_t *m) -{ - rosbridgemessage_pingpong_t *data = (rosbridgemessage_pingpong_t *)&(m->data); + // clear message buffer + memset(msg, 0, sizeof(*msg)); + + // message header + msg->start = HOTT_START; + msg->stop = HOTT_STOP; + msg->sensor_id = HOTT_GPS_ID; + msg->warning = generate_warning(); + msg->sensor_text_id = HOTT_GPS_TEXT_ID; + + // alarm inverse bits. invert display areas on limits + msg->alarm_inverse1 |= (telestate->Settings.Limit.MaxDistance < telestate->homedistance) ? GPS_INVERT_HDIST : 0; + msg->alarm_inverse1 |= (telestate->Settings.Limit.MinSpeed > telestate->GPS.Groundspeed) ? GPS_INVERT_SPEED : 0; + msg->alarm_inverse1 |= (telestate->Settings.Limit.MaxSpeed < telestate->GPS.Groundspeed) ? GPS_INVERT_SPEED : 0; + msg->alarm_inverse1 |= (telestate->Settings.Limit.MinHeight > telestate->altitude) ? GPS_INVERT_ALT : 0; + msg->alarm_inverse1 |= (telestate->Settings.Limit.MaxHeight < telestate->altitude) ? GPS_INVERT_ALT : 0; + msg->alarm_inverse1 |= (telestate->Settings.Limit.NegDifference1 > telestate->climbrate1s) ? GPS_INVERT_CR1S : 0; + msg->alarm_inverse1 |= (telestate->Settings.Limit.PosDifference1 < telestate->climbrate1s) ? GPS_INVERT_CR1S : 0; + msg->alarm_inverse1 |= (telestate->Settings.Limit.NegDifference2 > telestate->climbrate3s) ? GPS_INVERT_CR3S : 0; + msg->alarm_inverse1 |= (telestate->Settings.Limit.PosDifference2 < telestate->climbrate3s) ? GPS_INVERT_CR3S : 0; + msg->alarm_inverse2 |= (telestate->SysAlarms.Alarm.GPS != SYSTEMALARMS_ALARM_OK) ? GPS_INVERT2_POS : 0; + + // gps direction, groundspeed and postition + msg->flight_direction = scale_float2uint8(telestate->GPS.Heading, DEG_TO_UINT, 0); + msg->gps_speed = scale_float2uword(telestate->GPS.Groundspeed, MS_TO_KMH, 0); + convert_long2gps(telestate->GPS.Latitude, &msg->latitude_ns, &msg->latitude_min, &msg->latitude_sec); + convert_long2gps(telestate->GPS.Longitude, &msg->longitude_ew, &msg->longitude_min, &msg->longitude_sec); + + // homelocation distance, course and state + msg->distance = scale_float2uword(telestate->homedistance, 1, 0); + msg->home_direction = scale_float2uint8(telestate->homecourse, DEG_TO_UINT, 0); + msg->ascii5 = (telestate->Home.Set ? 'H' : '-'); + + // altitude relative to ground and climb rate + msg->altitude = scale_float2uword(telestate->altitude, 1, OFFSET_ALTITUDE); + msg->climbrate = scale_float2uword(telestate->climbrate1s, M_TO_CM, OFFSET_CLIMBRATE); + msg->climbrate3s = scale_float2uint8(telestate->climbrate3s, 1, OFFSET_CLIMBRATE3S); + + // number of satellites,gps fix and state + msg->gps_num_sat = telestate->GPS.Satellites; + switch (telestate->GPS.Status) { + case GPSPOSITIONSENSOR_STATUS_FIX2D: + msg->gps_fix_char = '2'; + break; + case GPSPOSITIONSENSOR_STATUS_FIX3D: + msg->gps_fix_char = '3'; + break; + default: + msg->gps_fix_char = 0; + } + switch (telestate->SysAlarms.Alarm.GPS) { + case SYSTEMALARMS_ALARM_UNINITIALISED: + msg->ascii6 = 0; + // if there is no gps, show compass flight direction + msg->flight_direction = scale_float2int8((telestate->Attitude.Yaw > 0) ? telestate->Attitude.Yaw : 360 + telestate->Attitude.Yaw, DEG_TO_UINT, 0); + break; + case SYSTEMALARMS_ALARM_OK: + msg->ascii6 = '.'; + break; + case SYSTEMALARMS_ALARM_WARNING: + msg->ascii6 = '?'; + break; + case SYSTEMALARMS_ALARM_ERROR: + case SYSTEMALARMS_ALARM_CRITICAL: + msg->ascii6 = '!'; + break; + default: + msg->ascii6 = 0; + } - data->sequence_number = ++rb->myPingSequence; - rb->roundtrip.last = PIOS_DELAY_GetRaw(); + // model angles + msg->angle_roll = scale_float2int8(telestate->Attitude.Roll, DEG_TO_UINT, 0); + msg->angle_nick = scale_float2int8(telestate->Attitude.Pitch, DEG_TO_UINT, 0); + msg->angle_compass = scale_float2int8(telestate->Attitude.Yaw, DEG_TO_UINT, 0); + + // gps time + msg->gps_hour = telestate->GPStime.Hour; + msg->gps_min = telestate->GPStime.Minute; + msg->gps_sec = telestate->GPStime.Second; + msg->gps_msec = 0; + + // gps MSL (NN) altitude MSL + msg->msl = scale_float2uword(telestate->GPS.Altitude, 1, 0); + + // free display chararacter + msg->ascii4 = 0; + + msg->checksum = calc_checksum((uint8_t *)msg, sizeof(*msg)); + return sizeof(*msg); } -static void pong_r_handler(struct ros_bridge *rb, rosbridgemessage_t *m) +uint16_t build_GAM_message(struct hott_gam_message *msg) { - rosbridgemessage_pingpong_t *data = (rosbridgemessage_pingpong_t *)&(m->data); + update_telemetrydata(); - if (data->sequence_number != rb->myPingSequence) { - return; + if (telestate->Settings.Sensor.GAM == HOTTBRIDGESETTINGS_SENSOR_DISABLED) { + return 0; } - float roundtrip = PIOS_DELTATIME_GetAverageSeconds(&(rb->roundtrip)); - HoTTBridgeStatusPingRoundTripTimeSet(&roundtrip); + + // clear message buffer + memset(msg, 0, sizeof(*msg)); + + // message header + msg->start = HOTT_START; + msg->stop = HOTT_STOP; + msg->sensor_id = HOTT_GAM_ID; + msg->warning = generate_warning(); + msg->sensor_text_id = HOTT_GAM_TEXT_ID; + + // alarm inverse bits. invert display areas on limits + msg->alarm_inverse2 |= (telestate->Settings.Limit.MaxCurrent < telestate->Battery.Current) ? GAM_INVERT2_CURRENT : 0; + msg->alarm_inverse2 |= (telestate->Settings.Limit.MinPowerVoltage > telestate->Battery.Voltage) ? GAM_INVERT2_VOLTAGE : 0; + msg->alarm_inverse2 |= (telestate->Settings.Limit.MaxPowerVoltage < telestate->Battery.Voltage) ? GAM_INVERT2_VOLTAGE : 0; + msg->alarm_inverse2 |= (telestate->Settings.Limit.MinHeight > telestate->altitude) ? GAM_INVERT2_ALT : 0; + msg->alarm_inverse2 |= (telestate->Settings.Limit.MaxHeight < telestate->altitude) ? GAM_INVERT2_ALT : 0; + msg->alarm_inverse2 |= (telestate->Settings.Limit.NegDifference1 > telestate->climbrate1s) ? GAM_INVERT2_CR1S : 0; + msg->alarm_inverse2 |= (telestate->Settings.Limit.PosDifference1 < telestate->climbrate1s) ? GAM_INVERT2_CR1S : 0; + msg->alarm_inverse2 |= (telestate->Settings.Limit.NegDifference2 > telestate->climbrate3s) ? GAM_INVERT2_CR3S : 0; + msg->alarm_inverse2 |= (telestate->Settings.Limit.PosDifference2 < telestate->climbrate3s) ? GAM_INVERT2_CR3S : 0; + + // temperatures + msg->temperature1 = scale_float2uint8(telestate->Gyro.temperature, 1, OFFSET_TEMPERATURE); + msg->temperature2 = scale_float2uint8(telestate->Baro.Temperature, 1, OFFSET_TEMPERATURE); + + // altitude + msg->altitude = scale_float2uword(telestate->altitude, 1, OFFSET_ALTITUDE); + + // climbrate + msg->climbrate = scale_float2uword(telestate->climbrate1s, M_TO_CM, OFFSET_CLIMBRATE); + msg->climbrate3s = scale_float2uint8(telestate->climbrate3s, 1, OFFSET_CLIMBRATE3S); + + // main battery + float voltage = (telestate->Battery.Voltage > 0) ? telestate->Battery.Voltage : 0; + float current = (telestate->Battery.Current > 0) ? telestate->Battery.Current : 0; + float energy = (telestate->Battery.ConsumedEnergy > 0) ? telestate->Battery.ConsumedEnergy : 0; + msg->voltage = scale_float2uword(voltage, 10, 0); + msg->current = scale_float2uword(current, 10, 0); + msg->capacity = scale_float2uword(energy, 0.1f, 0); + + // pressure kPa to 0.1Bar + msg->pressure = scale_float2uint8(telestate->Baro.Pressure, 0.1f, 0); + + msg->checksum = calc_checksum((uint8_t *)msg, sizeof(*msg)); + return sizeof(*msg); } -static void flightcontrol_r_handler(__attribute__((unused)) struct ros_bridge *rb, rosbridgemessage_t *m) +uint16_t build_EAM_message(struct hott_eam_message *msg) { - rosbridgemessage_flightcontrol_t *data = (rosbridgemessage_flightcontrol_t *)&(m->data); - FlightStatusFlightModeOptions mode; - - FlightStatusFlightModeGet(&mode); - if (mode != FLIGHTSTATUS_FLIGHTMODE_HoTTCONTROLLED) { - return; - } - PathDesiredData pathDesired; - PathDesiredGet(&pathDesired); - switch (data->mode) { - case HoTTBRIDGEMESSAGE_FLIGHTCONTROL_MODE_WAYPOINT: - { - FlightModeSettingsPositionHoldOffsetData offset; - FlightModeSettingsPositionHoldOffsetGet(&offset); - pathDesired.End.North = boundf(data->control[0], settings.GeoFenceBoxMin.North, settings.GeoFenceBoxMax.North); - pathDesired.End.East = boundf(data->control[1], settings.GeoFenceBoxMin.East, settings.GeoFenceBoxMax.East); - pathDesired.End.Down = boundf(data->control[2], settings.GeoFenceBoxMin.Down, settings.GeoFenceBoxMax.Down); - pathDesired.Start.North = pathDesired.End.North + offset.Horizontal; - pathDesired.Start.East = pathDesired.End.East; - pathDesired.Start.Down = pathDesired.End.Down; - pathDesired.StartingVelocity = 0.0f; - pathDesired.EndingVelocity = 0.0f; - pathDesired.Mode = PATHDESIRED_MODE_GOTOENDPOINT; - } - break; - case HoTTBRIDGEMESSAGE_FLIGHTCONTROL_MODE_ATTITUDE: - { - pathDesired.ModeParameters[0] = data->control[0]; - pathDesired.ModeParameters[1] = data->control[1]; - pathDesired.ModeParameters[2] = data->control[2]; - pathDesired.ModeParameters[3] = data->control[3]; - pathDesired.Mode = PATHDESIRED_MODE_FIXEDATTITUDE; - } - break; - } - PathDesiredSet(&pathDesired); - PoiLocationData poiLocation; - PoiLocationGet(&poiLocation); - poiLocation.North = data->poi[0]; - poiLocation.East = data->poi[1]; - poiLocation.Down = data->poi[2]; - PoiLocationSet(&poiLocation); + update_telemetrydata(); + + if (telestate->Settings.Sensor.EAM == HOTTBRIDGESETTINGS_SENSOR_DISABLED) { + return 0; + } + + // clear message buffer + memset(msg, 0, sizeof(*msg)); + + // message header + msg->start = HOTT_START; + msg->stop = HOTT_STOP; + msg->sensor_id = HOTT_EAM_ID; + msg->warning = generate_warning(); + msg->sensor_text_id = HOTT_EAM_TEXT_ID; + + // alarm inverse bits. invert display areas on limits + msg->alarm_inverse1 |= (telestate->Settings.Limit.MaxUsedCapacity < telestate->Battery.ConsumedEnergy) ? EAM_INVERT_CAPACITY : 0; + msg->alarm_inverse1 |= (telestate->Settings.Limit.MaxCurrent < telestate->Battery.Current) ? EAM_INVERT_CURRENT : 0; + msg->alarm_inverse1 |= (telestate->Settings.Limit.MinPowerVoltage > telestate->Battery.Voltage) ? EAM_INVERT_VOLTAGE : 0; + msg->alarm_inverse1 |= (telestate->Settings.Limit.MaxPowerVoltage < telestate->Battery.Voltage) ? EAM_INVERT_VOLTAGE : 0; + msg->alarm_inverse2 |= (telestate->Settings.Limit.MinHeight > telestate->altitude) ? EAM_INVERT2_ALT : 0; + msg->alarm_inverse2 |= (telestate->Settings.Limit.MaxHeight < telestate->altitude) ? EAM_INVERT2_ALT : 0; + msg->alarm_inverse2 |= (telestate->Settings.Limit.NegDifference1 > telestate->climbrate1s) ? EAM_INVERT2_CR1S : 0; + msg->alarm_inverse2 |= (telestate->Settings.Limit.PosDifference1 < telestate->climbrate1s) ? EAM_INVERT2_CR1S : 0; + msg->alarm_inverse2 |= (telestate->Settings.Limit.NegDifference2 > telestate->climbrate3s) ? EAM_INVERT2_CR3S : 0; + msg->alarm_inverse2 |= (telestate->Settings.Limit.PosDifference2 < telestate->climbrate3s) ? EAM_INVERT2_CR3S : 0; + + // main battery + float voltage = (telestate->Battery.Voltage > 0) ? telestate->Battery.Voltage : 0; + float current = (telestate->Battery.Current > 0) ? telestate->Battery.Current : 0; + float energy = (telestate->Battery.ConsumedEnergy > 0) ? telestate->Battery.ConsumedEnergy : 0; + msg->voltage = scale_float2uword(voltage, 10, 0); + msg->current = scale_float2uword(current, 10, 0); + msg->capacity = scale_float2uword(energy, 0.1f, 0); + + // temperatures + msg->temperature1 = scale_float2uint8(telestate->Gyro.temperature, 1, OFFSET_TEMPERATURE); + msg->temperature2 = scale_float2uint8(telestate->Baro.Temperature, 1, OFFSET_TEMPERATURE); + + // altitude + msg->altitude = scale_float2uword(telestate->altitude, 1, OFFSET_ALTITUDE); + + // climbrate + msg->climbrate = scale_float2uword(telestate->climbrate1s, M_TO_CM, OFFSET_CLIMBRATE); + msg->climbrate3s = scale_float2uint8(telestate->climbrate3s, 1, OFFSET_CLIMBRATE3S); + + // flight time + float flighttime = (telestate->Battery.EstimatedFlightTime <= 5999) ? telestate->Battery.EstimatedFlightTime : 5999; + msg->electric_min = flighttime / 60; + msg->electric_sec = flighttime - 60 * msg->electric_min; + + msg->checksum = calc_checksum((uint8_t *)msg, sizeof(*msg)); + return sizeof(*msg); } -static void pos_estimate_r_handler(__attribute__((unused)) struct ros_bridge *rb, rosbridgemessage_t *m) + +uint16_t build_ESC_message(struct hott_esc_message *msg) { - rosbridgemessage_pos_estimate_t *data = (rosbridgemessage_pos_estimate_t *)&(m->data); - AUXPositionSensorData pos; + update_telemetrydata(); - pos.North = data->position[0]; - pos.East = data->position[1]; - pos.Down = data->position[2]; - AUXPositionSensorSet(&pos); + if (telestate->Settings.Sensor.ESC == HOTTBRIDGESETTINGS_SENSOR_DISABLED) { + return 0; + } + + // clear message buffer + memset(msg, 0, sizeof(*msg)); + + // message header + msg->start = HOTT_START; + msg->stop = HOTT_STOP; + msg->sensor_id = HOTT_ESC_ID; + msg->warning = 0; + msg->sensor_text_id = HOTT_ESC_TEXT_ID; + + // main batterie + float voltage = (telestate->Battery.Voltage > 0) ? telestate->Battery.Voltage : 0; + float current = (telestate->Battery.Current > 0) ? telestate->Battery.Current : 0; + float max_current = (telestate->Battery.PeakCurrent > 0) ? telestate->Battery.PeakCurrent : 0; + float energy = (telestate->Battery.ConsumedEnergy > 0) ? telestate->Battery.ConsumedEnergy : 0; + msg->batt_voltage = scale_float2uword(voltage, 10, 0); + msg->current = scale_float2uword(current, 10, 0); + msg->max_current = scale_float2uword(max_current, 10, 0); + msg->batt_capacity = scale_float2uword(energy, 0.1f, 0); + + // temperatures + msg->temperatureESC = scale_float2uint8(telestate->Gyro.temperature, 1, OFFSET_TEMPERATURE); + msg->max_temperatureESC = scale_float2uint8(0, 1, OFFSET_TEMPERATURE); + msg->temperatureMOT = scale_float2uint8(telestate->Baro.Temperature, 1, OFFSET_TEMPERATURE); + msg->max_temperatureMOT = scale_float2uint8(0, 1, OFFSET_TEMPERATURE); + + msg->checksum = calc_checksum((uint8_t *)msg, sizeof(*msg)); + return sizeof(*msg); } -static void pong_handler(struct ros_bridge *rb, rosbridgemessage_t *m) +uint16_t build_TEXT_message(struct hott_text_message *msg) { - rosbridgemessage_pingpong_t *data = (rosbridgemessage_pingpong_t *)&(m->data); + update_telemetrydata(); + + // clear message buffer + memset(msg, 0, sizeof(*msg)); + // message header + msg->start = HOTT_START; + msg->stop = HOTT_STOP; + msg->sensor_id = HOTT_TEXT_ID; - data->sequence_number = rb->remotePingSequence; + msg->checksum = calc_checksum((uint8_t *)msg, sizeof(*msg)); + return sizeof(*msg); } -static void fullstate_estimate_handler(__attribute__((unused)) struct ros_bridge *rb, rosbridgemessage_t *m) +/** + * update telemetry data + * this is called on every telemetry request + * calling interval is 200ms depending on TX + * 200ms telemetry request is used as time base for timed calculations (5Hz interval) + */ +void update_telemetrydata() { - PositionStateData pos; - VelocityStateData vel; - AttitudeStateData att; - FlightStatusFlightModeOptions mode; - FlightStatusArmedOptions armed; - float thrust; - AccessoryDesiredData accessory; - ManualControlCommandData manualcontrol; - - ManualControlCommandGet(&manualcontrol); - FlightStatusArmedGet(&armed); - FlightStatusFlightModeGet(&mode); - ActuatorDesiredThrustGet(&thrust); - PositionStateGet(&pos); - VelocityStateGet(&vel); - AttitudeStateGet(&att); - rosbridgemessage_fullstate_estimate_t *data = (rosbridgemessage_fullstate_estimate_t *)&(m->data); - data->quaternion[0] = att.q1; - data->quaternion[1] = att.q2; - data->quaternion[2] = att.q3; - data->quaternion[3] = att.q4; - data->position[0] = pos.North; - data->position[1] = pos.East; - data->position[2] = pos.Down; - data->velocity[0] = vel.North; - data->velocity[1] = vel.East; - data->velocity[2] = vel.Down; - data->rotation[0] = ros->rateAccumulator[0]; - data->rotation[1] = ros->rateAccumulator[1]; - data->rotation[2] = ros->rateAccumulator[2]; - data->thrust = thrust; - data->HoTTControlled = (mode == FLIGHTSTATUS_FLIGHTMODE_HoTTCONTROLLED) ? 1 : 0; - data->FlightMode = manualcontrol.FlightModeSwitchPosition; - data->armed = (armed == FLIGHTSTATUS_ARMED_ARMED) ? 1 : 0; - data->controls[0] = manualcontrol.Roll; - data->controls[1] = manualcontrol.Pitch; - data->controls[2] = manualcontrol.Yaw; - data->controls[3] = manualcontrol.Thrust; - data->controls[4] = manualcontrol.Collective; - data->controls[5] = manualcontrol.Throttle; - for (int t = 0; t < 4; t++) { - if (AccessoryDesiredInstGet(t, &accessory) == 0) { - data->accessory[t] = accessory.AccessoryVal; - } + // update all available data + if (HoTTBridgeSettingsHandle() != NULL) { + HoTTBridgeSettingsGet(&telestate->Settings); + } + if (AttitudeStateHandle() != NULL) { + AttitudeStateGet(&telestate->Attitude); + } + if (BaroSensorHandle() != NULL) { + BaroSensorGet(&telestate->Baro); + } + if (FlightBatteryStateHandle() != NULL) { + FlightBatteryStateGet(&telestate->Battery); + } + if (FlightStatusHandle() != NULL) { + FlightStatusGet(&telestate->FlightStatus); + } + if (GPSPositionSensorHandle() != NULL) { + GPSPositionSensorGet(&telestate->GPS); + } + if (GPSTimeHandle() != NULL) { + GPSTimeGet(&telestate->GPStime); + } + if (GyroSensorHandle() != NULL) { + GyroSensorGet(&telestate->Gyro); + } + if (HomeLocationHandle() != NULL) { + HomeLocationGet(&telestate->Home); + } + if (PositionStateHandle() != NULL) { + PositionStateGet(&telestate->Position); + } + if (SystemAlarmsHandle() != NULL) { + SystemAlarmsGet(&telestate->SysAlarms); + } + if (VelocityStateHandle() != NULL) { + VelocityStateGet(&telestate->Velocity); + } + + // send actual climbrate value to ring buffer as mm per 0.2s values + uint8_t n = telestate->climbrate_pointer; + telestate->climbratebuffer[telestate->climbrate_pointer++] = -telestate->Velocity.Down * 200; + telestate->climbrate_pointer %= climbratesize; + + // calculate avarage climbrates in meters per 1, 3 and 10 second(s) based on 200ms interval + telestate->climbrate1s = 0; + telestate->climbrate3s = 0; + telestate->climbrate10s = 0; + for (uint8_t i = 0; i < climbratesize; i++) { + telestate->climbrate1s += (i < 5) ? telestate->climbratebuffer[n] : 0; + telestate->climbrate3s += (i < 15) ? telestate->climbratebuffer[n] : 0; + telestate->climbrate10s += (i < 50) ? telestate->climbratebuffer[n] : 0; + n += climbratesize - 1; + n %= climbratesize; + } + telestate->climbrate1s = telestate->climbrate1s / 1000; + telestate->climbrate3s = telestate->climbrate3s / 1000; + telestate->climbrate10s = telestate->climbrate10s / 1000; + + // set altitude offset and clear min/max values when arming + if ((telestate->FlightStatus.Armed == FLIGHTSTATUS_ARMED_ARMING) || ((telestate->last_armed != FLIGHTSTATUS_ARMED_ARMED) && (telestate->FlightStatus.Armed == FLIGHTSTATUS_ARMED_ARMED))) { + telestate->min_altitude = 0; + telestate->max_altitude = 0; } + telestate->last_armed = telestate->FlightStatus.Armed; - int x, y; - float *P[13]; - INSGetPAddress(P); - for (x = 0; x < 10; x++) { - for (y = 0; y < 10; y++) { - data->matrix[x * 10 + y] = P[x][y]; + // calculate altitude relative to start position + telestate->altitude = -telestate->Position.Down; + + // check and set min/max values when armed. + if (telestate->FlightStatus.Armed == FLIGHTSTATUS_ARMED_ARMED) { + if (telestate->min_altitude > telestate->altitude) { + telestate->min_altitude = telestate->altitude; + } + if (telestate->max_altitude < telestate->altitude) { + telestate->max_altitude = telestate->altitude; } } - if (ros->rateTimer >= 1) { - float factor = 1.0f / (float)ros->rateTimer; - data->rotation[0] *= factor; - data->rotation[1] *= factor; - data->rotation[2] *= factor; - ros->rateAccumulator[0] = 0; - ros->rateAccumulator[1] = 0; - ros->rateAccumulator[2] = 0; - ros->rateTimer = 0; + + // gps home position and course + telestate->homedistance = sqrtf(telestate->Position.North * telestate->Position.North + telestate->Position.East * telestate->Position.East); + telestate->homecourse = acosf(-telestate->Position.North / telestate->homedistance) / 3.14159265f * 180; + if (telestate->Position.East > 0) { + telestate->homecourse = 360 - telestate->homecourse; + } + + // statusline + const char *txt_unknown = "unknown"; + const char *txt_manual = "Manual"; + const char *txt_stabilized1 = "Stabilized1"; + const char *txt_stabilized2 = "Stabilized2"; + const char *txt_stabilized3 = "Stabilized3"; + const char *txt_stabilized4 = "Stabilized4"; + const char *txt_stabilized5 = "Stabilized5"; + const char *txt_stabilized6 = "Stabilized6"; + const char *txt_positionhold = "PositionHold"; + const char *txt_courselock = "CourseLock"; + const char *txt_velocityroam = "VelocityRoam"; + const char *txt_homeleash = "HomeLeash"; + const char *txt_absoluteposition = "AbsolutePosition"; + const char *txt_returntobase = "ReturnToBase"; + const char *txt_land = "Land"; + const char *txt_pathplanner = "PathPlanner"; + const char *txt_poi = "PointOfInterest"; + const char *txt_autocruise = "AutoCruise"; + const char *txt_autotakeoff = "AutoTakeOff"; + const char *txt_autotune = "Autotune"; + const char *txt_disarmed = "Disarmed"; + const char *txt_arming = "Arming"; + const char *txt_armed = "Armed"; + + const char *txt_flightmode; + switch (telestate->FlightStatus.FlightMode) { + case FLIGHTSTATUS_FLIGHTMODE_MANUAL: + txt_flightmode = txt_manual; + break; + case FLIGHTSTATUS_FLIGHTMODE_STABILIZED1: + txt_flightmode = txt_stabilized1; + break; + case FLIGHTSTATUS_FLIGHTMODE_STABILIZED2: + txt_flightmode = txt_stabilized2; + break; + case FLIGHTSTATUS_FLIGHTMODE_STABILIZED3: + txt_flightmode = txt_stabilized3; + break; + case FLIGHTSTATUS_FLIGHTMODE_STABILIZED4: + txt_flightmode = txt_stabilized4; + break; + case FLIGHTSTATUS_FLIGHTMODE_STABILIZED5: + txt_flightmode = txt_stabilized5; + break; + case FLIGHTSTATUS_FLIGHTMODE_STABILIZED6: + txt_flightmode = txt_stabilized6; + break; + case FLIGHTSTATUS_FLIGHTMODE_POSITIONHOLD: + txt_flightmode = txt_positionhold; + break; + case FLIGHTSTATUS_FLIGHTMODE_COURSELOCK: + txt_flightmode = txt_courselock; + break; + case FLIGHTSTATUS_FLIGHTMODE_VELOCITYROAM: + txt_flightmode = txt_velocityroam; + break; + case FLIGHTSTATUS_FLIGHTMODE_HOMELEASH: + txt_flightmode = txt_homeleash; + break; + case FLIGHTSTATUS_FLIGHTMODE_ABSOLUTEPOSITION: + txt_flightmode = txt_absoluteposition; + break; + case FLIGHTSTATUS_FLIGHTMODE_RETURNTOBASE: + txt_flightmode = txt_returntobase; + break; + case FLIGHTSTATUS_FLIGHTMODE_LAND: + txt_flightmode = txt_land; + break; + case FLIGHTSTATUS_FLIGHTMODE_PATHPLANNER: + txt_flightmode = txt_pathplanner; + break; + case FLIGHTSTATUS_FLIGHTMODE_POI: + txt_flightmode = txt_poi; + break; + case FLIGHTSTATUS_FLIGHTMODE_AUTOCRUISE: + txt_flightmode = txt_autocruise; + break; + case FLIGHTSTATUS_FLIGHTMODE_AUTOTAKEOFF: + txt_flightmode = txt_autotakeoff; + break; + case FLIGHTSTATUS_FLIGHTMODE_AUTOTUNE: + txt_flightmode = txt_autotune; + break; + default: + txt_flightmode = txt_unknown; + } + + const char *txt_armstate; + switch (telestate->FlightStatus.Armed) { + case FLIGHTSTATUS_ARMED_DISARMED: + txt_armstate = txt_disarmed; + break; + case FLIGHTSTATUS_ARMED_ARMING: + txt_armstate = txt_arming; + break; + case FLIGHTSTATUS_ARMED_ARMED: + txt_armstate = txt_armed; + break; + default: + txt_armstate = txt_unknown; } + + snprintf(telestate->statusline, sizeof(telestate->statusline), "%12s,%8s", txt_flightmode, txt_armstate); } -static void imu_average_handler(__attribute__((unused)) struct ros_bridge *rb, __attribute__((unused)) rosbridgemessage_t *m) + +/** + * generate warning beeps or spoken announcements + */ +uint8_t generate_warning() { - // TODO + // set warning tone with hardcoded priority + if ((telestate->Settings.Warning.MinSpeed == HOTTBRIDGESETTINGS_WARNING_ENABLED) && + (telestate->Settings.Limit.MinSpeed > telestate->GPS.Groundspeed * MS_TO_KMH)) { + return HOTT_TONE_A; // maximum speed + } + if ((telestate->Settings.Warning.NegDifference2 == HOTTBRIDGESETTINGS_WARNING_ENABLED) && + (telestate->Settings.Limit.NegDifference2 > telestate->climbrate3s)) { + return HOTT_TONE_B; // sink rate 3s + } + if ((telestate->Settings.Warning.NegDifference1 == HOTTBRIDGESETTINGS_WARNING_ENABLED) && + (telestate->Settings.Limit.NegDifference1 > telestate->climbrate1s)) { + return HOTT_TONE_C; // sink rate 1s + } + if ((telestate->Settings.Warning.MaxDistance == HOTTBRIDGESETTINGS_WARNING_ENABLED) && + (telestate->Settings.Limit.MaxDistance < telestate->homedistance)) { + return HOTT_TONE_D; // maximum distance + } + if ((telestate->Settings.Warning.MinSensor1Temp == HOTTBRIDGESETTINGS_WARNING_ENABLED) && + (telestate->Settings.Limit.MinSensor1Temp > telestate->Gyro.temperature)) { + return HOTT_TONE_F; // minimum temperature sensor 1 + } + if ((telestate->Settings.Warning.MinSensor2Temp == HOTTBRIDGESETTINGS_WARNING_ENABLED) && + (telestate->Settings.Limit.MinSensor2Temp > telestate->Baro.Temperature)) { + return HOTT_TONE_G; // minimum temperature sensor 2 + } + if ((telestate->Settings.Warning.MaxSensor1Temp == HOTTBRIDGESETTINGS_WARNING_ENABLED) && + (telestate->Settings.Limit.MaxSensor1Temp < telestate->Gyro.temperature)) { + return HOTT_TONE_H; // maximum temperature sensor 1 + } + if ((telestate->Settings.Warning.MaxSensor2Temp == HOTTBRIDGESETTINGS_WARNING_ENABLED) && + (telestate->Settings.Limit.MaxSensor2Temp < telestate->Baro.Temperature)) { + return HOTT_TONE_I; // maximum temperature sensor 2 + } + if ((telestate->Settings.Warning.MaxSpeed == HOTTBRIDGESETTINGS_WARNING_ENABLED) && + (telestate->Settings.Limit.MaxSpeed < telestate->GPS.Groundspeed * MS_TO_KMH)) { + return HOTT_TONE_L; // maximum speed + } + if ((telestate->Settings.Warning.PosDifference2 == HOTTBRIDGESETTINGS_WARNING_ENABLED) && + (telestate->Settings.Limit.PosDifference2 > telestate->climbrate3s)) { + return HOTT_TONE_M; // climb rate 3s + } + if ((telestate->Settings.Warning.PosDifference1 == HOTTBRIDGESETTINGS_WARNING_ENABLED) && + (telestate->Settings.Limit.PosDifference1 > telestate->climbrate1s)) { + return HOTT_TONE_N; // climb rate 1s + } + if ((telestate->Settings.Warning.MinHeight == HOTTBRIDGESETTINGS_WARNING_ENABLED) && + (telestate->Settings.Limit.MinHeight > telestate->altitude)) { + return HOTT_TONE_O; // minimum height + } + if ((telestate->Settings.Warning.MinPowerVoltage == HOTTBRIDGESETTINGS_WARNING_ENABLED) && + (telestate->Settings.Limit.MinPowerVoltage > telestate->Battery.Voltage)) { + return HOTT_TONE_P; // minimum input voltage + } + if ((telestate->Settings.Warning.MaxUsedCapacity == HOTTBRIDGESETTINGS_WARNING_ENABLED) && + (telestate->Settings.Limit.MaxUsedCapacity < telestate->Battery.ConsumedEnergy)) { + return HOTT_TONE_V; // capacity + } + if ((telestate->Settings.Warning.MaxCurrent == HOTTBRIDGESETTINGS_WARNING_ENABLED) && + (telestate->Settings.Limit.MaxCurrent < telestate->Battery.Current)) { + return HOTT_TONE_W; // maximum current + } + if ((telestate->Settings.Warning.MaxPowerVoltage == HOTTBRIDGESETTINGS_WARNING_ENABLED) && + (telestate->Settings.Limit.MaxPowerVoltage < telestate->Battery.Voltage)) { + return HOTT_TONE_X; // maximum input voltage + } + if ((telestate->Settings.Warning.MaxHeight == HOTTBRIDGESETTINGS_WARNING_ENABLED) && + (telestate->Settings.Limit.MaxHeight < telestate->altitude)) { + return HOTT_TONE_Z; // maximum height + } + // altitude beeps when crossing altitude limits at 20,40,60,80,100,200,400,600,800 and 1000 meters + if (telestate->Settings.Warning.AltitudeBeep == HOTTBRIDGESETTINGS_WARNING_ENABLED) { + // update altitude when checked for beeps + float last = telestate->altitude_last; + float actual = telestate->altitude; + telestate->altitude_last = telestate->altitude; + if (((last < 20) && (actual >= 20)) || ((last > 20) && (actual <= 20))) { + return HOTT_TONE_20M; + } + if (((last < 40) && (actual >= 40)) || ((last > 40) && (actual <= 40))) { + return HOTT_TONE_40M; + } + if (((last < 60) && (actual >= 60)) || ((last > 60) && (actual <= 60))) { + return HOTT_TONE_60M; + } + if (((last < 80) && (actual >= 80)) || ((last > 80) && (actual <= 80))) { + return HOTT_TONE_80M; + } + if (((last < 100) && (actual >= 100)) || ((last > 100) && (actual <= 100))) { + return HOTT_TONE_100M; + } + if (((last < 200) && (actual >= 200)) || ((last > 200) && (actual <= 200))) { + return HOTT_TONE_200M; + } + if (((last < 400) && (actual >= 400)) || ((last > 400) && (actual <= 400))) { + return HOTT_TONE_400M; + } + if (((last < 600) && (actual >= 600)) || ((last > 600) && (actual <= 600))) { + return HOTT_TONE_600M; + } + if (((last < 800) && (actual >= 800)) || ((last > 800) && (actual <= 800))) { + return HOTT_TONE_800M; + } + if (((last < 1000) && (actual >= 1000)) || ((last > 1000) && (actual <= 1000))) { + return HOTT_TONE_1000M; + } + } + + // there is no warning + return 0; } -static void gimbal_estimate_handler(__attribute__((unused)) struct ros_bridge *rb, __attribute__((unused)) rosbridgemessage_t *m) + +/** + * calculate checksum of data buffer + */ +uint8_t calc_checksum(uint8_t *data, uint16_t size) { - // TODO + uint16_t sum = 0; + + for (int i = 0; i < size; i++) { + sum += data[i]; + } + return sum; } /** - * Main task routine - * @param[in] parameters parameter given by PIOS_Callback_Create() + * scale float value with scale and offset to unsigned byte */ -static void uavoHoTTBridgeTxTask(void) +uint8_t scale_float2uint8(float value, float scale, float offset) { - uint8_t buffer[HoTTBRIDGEMESSAGE_BUFFERSIZE]; // buffer on the stack? could also be in static RAM but not reuseale by other callbacks then - rosbridgemessage_t *message = (rosbridgemessage_t *)buffer; - - for (rosbridgemessagetype_t type = HoTTBRIDGEMESSAGE_PING; type < HoTTBRIDGEMESSAGE_END_ARRAY_SIZE; type++) { - if (ros->scheduled[type] && rosbridgemessagehandlers[type] != NULL) { - message->magic = HoTTBRIDGEMAGIC; - message->length = HoTTBRIDGEMESSAGE_SIZES[type]; - message->type = type; - message->timestamp = PIOS_DELAY_GetuS(); - (*rosbridgemessagehandlers[type])(ros, message); - message->crc32 = PIOS_CRC32_updateCRC(0xffffffff, message->data, message->length); - int32_t ret = PIOS_COM_SendBufferNonBlocking(ros->com, buffer, offsetof(rosbridgemessage_t, data) + message->length); - // int32_t ret = PIOS_COM_SendBuffer(ros->com, buffer, offsetof(rosbridgemessage_t, data) + message->length); - ros->scheduled[type] = false; - if (ret >= 0) { - uint32_t txpackets; - HoTTBridgeStatusTxPacketsGet(&txpackets); - txpackets++; - HoTTBridgeStatusTxPacketsSet(&txpackets); - } else { - uint32_t txfail; - HoTTBridgeStatusTxFailGet(&txfail); - txfail++; - HoTTBridgeStatusTxFailSet(&txfail); - } - PIOS_CALLBACKSCHEDULER_Dispatch(callbackHandle); - return; - } - } - // nothing scheduled, do a ping in 10 secods time + uint16_t temp = (uint16_t)roundf(value * scale + offset); + uint8_t result; + + result = (uint8_t)temp & 0xff; + return result; } /** - * Event Callback on Gyro updates (called with PIOS_SENSOR_RATE - roughly 500 Hz - from State Estimation) + * scale float value with scale and offset to signed byte (int8_t) */ -void RateCb(__attribute__((unused)) UAVObjEvent *ev) +int8_t scale_float2int8(float value, float scale, float offset) { - GyroStateData gyr; + int8_t result = (int8_t)roundf(value * scale + offset); - GyroStateGet(&gyr); - ros->rateAccumulator[0] += gyr.x; - ros->rateAccumulator[1] += gyr.y; - ros->rateAccumulator[2] += gyr.z; - ros->rateTimer++; + return result; } /** - * Event Callback on Attitude updates (called with PIOS_SENSOR_RATE - roughly 500 Hz - from State Estimation) + * scale float value with scale and offset to word */ -void AttitudeCb(__attribute__((unused)) UAVObjEvent *ev) +uword_t scale_float2uword(float value, float scale, float offset) { - bool dispatch = false; + uint16_t temp = (uint16_t)roundf(value * scale + offset); + uword_t result; - if (++ros->pingTimer >= settings.UpdateRate.Ping && settings.UpdateRate.Ping > 0) { - ros->pingTimer = 0; - dispatch = true; - ros->scheduled[HoTTBRIDGEMESSAGE_PING] = true; - } - if (++ros->stateTimer >= settings.UpdateRate.State && settings.UpdateRate.State > 0) { - ros->stateTimer = 0; - dispatch = true; - ros->scheduled[HoTTBRIDGEMESSAGE_FULLSTATE_ESTIMATE] = true; - } - if (dispatch && callbackHandle) { - PIOS_CALLBACKSCHEDULER_Dispatch(callbackHandle); - } + result.l = (uint8_t)temp & 0xff; + result.h = (uint8_t)(temp >> 8) & 0xff; + return result; } /** - * Main task routine - * @param[in] parameters parameter given by PIOS_Thread_Create() + * convert dword gps value into HoTT gps format and write result to given pointers */ -static void uavoHoTTBridgeRxTask(__attribute__((unused)) void *parameters) +void convert_long2gps(int32_t value, uint8_t *dir, uword_t *min, uword_t *sec) { - while (1) { - uint8_t b = 0; - uint16_t count = PIOS_COM_ReceiveBuffer(ros->com, &b, 1, ~0); - if (count) { - ros_receive_byte(ros, b); - } - } + // convert gps decigrad value into degrees, minutes and seconds + uword_t temp; + uint32_t absvalue = abs(value); + uint16_t degrees = (absvalue / 10000000); + uint32_t seconds = (absvalue - degrees * 10000000) * 6; + uint16_t minutes = seconds / 1000000; + + seconds %= 1000000; + seconds = seconds / 100; + uint16_t degmin = degrees * 100 + minutes; + // write results + *dir = (value < 0) ? 1 : 0; + temp.l = (uint8_t)degmin & 0xff; + temp.h = (uint8_t)(degmin >> 8) & 0xff; + *min = temp; + temp.l = (uint8_t)seconds & 0xff; + temp.h = (uint8_t)(seconds >> 8) & 0xff; + *sec = temp; } -#endif // PIOS_INCLUDE_HoTT_BRIDGE +#endif // PIOS_INCLUDE_HOTT_BRIDGE /** * @} * @} diff --git a/flight/pios/common/pios_com.c b/flight/pios/common/pios_com.c index d13a7ca895..a1bfde67ae 100644 --- a/flight/pios/common/pios_com.c +++ b/flight/pios/common/pios_com.c @@ -282,6 +282,30 @@ int32_t PIOS_COM_ChangeBaud(uint32_t com_id, uint32_t baud) return 0; } +/** + * Change the port type to halfduplex (shared rx/tx medium) + * \param[in] port COM port + * \param[in] halfduplex enabled + * \return -1 if port not available + * \return 0 on success + */ +int32_t PIOS_COM_SetHalfDuplex(uint32_t com_id, bool halfduplex) +{ + struct pios_com_dev *com_dev = (struct pios_com_dev *)com_id; + + if (!PIOS_COM_validate(com_dev)) { + /* Undefined COM port for this board (see pios_board.c) */ + return -1; + } + + /* Invoke the driver function if it exists */ + if (com_dev->driver->set_halfduplex) { + com_dev->driver->set_halfduplex(com_dev->lower_id, halfduplex); + } + + return 0; +} + int32_t PIOS_COM_ChangeConfig(uint32_t com_id, enum PIOS_COM_Word_Length word_len, enum PIOS_COM_StopBits stop_bits, enum PIOS_COM_Parity parity, uint32_t baud_rate, enum PIOS_COM_Mode mode) { struct pios_com_dev *com_dev = (struct pios_com_dev *)com_id; diff --git a/flight/pios/inc/pios_com.h b/flight/pios/inc/pios_com.h index 9364e5942e..f576b346fb 100644 --- a/flight/pios/inc/pios_com.h +++ b/flight/pios/inc/pios_com.h @@ -72,6 +72,7 @@ enum PIOS_COM_Mode { struct pios_com_driver { void (*init)(uint32_t id); void (*set_baud)(uint32_t id, uint32_t baud); + void (*set_halfduplex)(uint32_t id, bool halfduplex); void (*set_config)(uint32_t usart_id, enum PIOS_COM_Word_Length word_len, enum PIOS_COM_StopBits stop_bits, enum PIOS_COM_Parity parity, uint32_t baud_rate, enum PIOS_COM_Mode mode); void (*set_ctrl_line)(uint32_t id, uint32_t mask, uint32_t state); void (*tx_start)(uint32_t id, uint16_t tx_bytes_avail); @@ -91,6 +92,7 @@ struct pios_com_driver { /* Public Functions */ extern int32_t PIOS_COM_Init(uint32_t *com_id, const struct pios_com_driver *driver, uint32_t lower_id, uint8_t *rx_buffer, uint16_t rx_buffer_len, uint8_t *tx_buffer, uint16_t tx_buffer_len); extern int32_t PIOS_COM_ChangeBaud(uint32_t com_id, uint32_t baud); +extern int32_t PIOS_COM_SetHalfDuplex(uint32_t com_id, bool halfduplex); extern int32_t PIOS_COM_ChangeConfig(uint32_t com_id, enum PIOS_COM_Word_Length word_len, enum PIOS_COM_StopBits stop_bits, enum PIOS_COM_Parity parity, uint32_t baud_rate, enum PIOS_COM_Mode mode); extern int32_t PIOS_COM_SetCtrlLine(uint32_t com_id, uint32_t mask, uint32_t state); extern int32_t PIOS_COM_RegisterCtrlLineCallback(uint32_t usart_id, pios_com_callback_ctrl_line ctrl_line_cb, uint32_t context); diff --git a/flight/pios/stm32f4xx/pios_usart.c b/flight/pios/stm32f4xx/pios_usart.c index 01d7909638..e594f55e08 100644 --- a/flight/pios/stm32f4xx/pios_usart.c +++ b/flight/pios/stm32f4xx/pios_usart.c @@ -41,6 +41,7 @@ /* Provide a COM driver */ static void PIOS_USART_ChangeBaud(uint32_t usart_id, uint32_t baud); +static void PIOS_USART_SetHalfDuplex(uint32_t usart_id, bool halfduplex); static void PIOS_USART_ChangeConfig(uint32_t usart_id, enum PIOS_COM_Word_Length word_len, enum PIOS_COM_StopBits stop_bits, enum PIOS_COM_Parity parity, uint32_t baud_rate, enum PIOS_COM_Mode mode); static void PIOS_USART_SetCtrlLine(uint32_t usart_id, uint32_t mask, uint32_t state); static void PIOS_USART_RegisterRxCallback(uint32_t usart_id, pios_com_callback rx_in_cb, uint32_t context); @@ -49,13 +50,14 @@ static void PIOS_USART_TxStart(uint32_t usart_id, uint16_t tx_bytes_avail); static void PIOS_USART_RxStart(uint32_t usart_id, uint16_t rx_bytes_avail); const struct pios_com_driver pios_usart_com_driver = { - .set_baud = PIOS_USART_ChangeBaud, - .set_config = PIOS_USART_ChangeConfig, - .set_ctrl_line = PIOS_USART_SetCtrlLine, - .tx_start = PIOS_USART_TxStart, - .rx_start = PIOS_USART_RxStart, - .bind_tx_cb = PIOS_USART_RegisterTxCallback, - .bind_rx_cb = PIOS_USART_RegisterRxCallback, + .set_baud = PIOS_USART_ChangeBaud, + .set_halfduplex = PIOS_USART_SetHalfDuplex, + .set_config = PIOS_USART_ChangeConfig, + .set_ctrl_line = PIOS_USART_SetCtrlLine, + .tx_start = PIOS_USART_TxStart, + .rx_start = PIOS_USART_RxStart, + .bind_tx_cb = PIOS_USART_RegisterTxCallback, + .bind_rx_cb = PIOS_USART_RegisterRxCallback, }; enum pios_usart_dev_magic { @@ -286,6 +288,22 @@ static void PIOS_USART_ChangeBaud(uint32_t usart_id, uint32_t baud) USART_Init(usart_dev->cfg->regs, &usart_dev->init); } +/** + * Sets the USART peripheral into half duplex mode + * \param[in] usart_id USART name (GPS, TELEM, AUX) + * \param[in] bool wether to set half duplex or not + */ +static void PIOS_USART_SetHalfDuplex(uint32_t usart_id, bool halfduplex) +{ + struct pios_usart_dev *usart_dev = (struct pios_usart_dev *)usart_id; + + bool valid = PIOS_USART_validate(usart_dev); + + PIOS_Assert(valid); + + USART_HalfDuplexCmd(usart_dev->cfg->regs, halfduplex ? ENABLE : DISABLE); +} + /** * Changes configuration of the USART peripheral without re-initialising. * \param[in] usart_id USART name (GPS, TELEM, AUX) diff --git a/flight/targets/boards/revolution/firmware/UAVObjects.inc b/flight/targets/boards/revolution/firmware/UAVObjects.inc index f6d8d79875..84195dee9a 100644 --- a/flight/targets/boards/revolution/firmware/UAVObjects.inc +++ b/flight/targets/boards/revolution/firmware/UAVObjects.inc @@ -126,6 +126,7 @@ UAVOBJSRCFILENAMES += poilearnsettings UAVOBJSRCFILENAMES += mpugyroaccelsettings UAVOBJSRCFILENAMES += txpidsettings UAVOBJSRCFILENAMES += txpidstatus +UAVOBJSRCFILENAMES += hottbridgesettings UAVOBJSRCFILENAMES += hottbridgestatus UAVOBJSRCFILENAMES += takeofflocation UAVOBJSRCFILENAMES += perfcounter diff --git a/flight/targets/boards/revolution/firmware/inc/pios_config.h b/flight/targets/boards/revolution/firmware/inc/pios_config.h index efe32a4be4..c50d8c5981 100644 --- a/flight/targets/boards/revolution/firmware/inc/pios_config.h +++ b/flight/targets/boards/revolution/firmware/inc/pios_config.h @@ -119,6 +119,7 @@ #define PIOS_INCLUDE_LED #define PIOS_INCLUDE_IAP #define PIOS_INCLUDE_SERVO +#define PIOS_INCLUDE_HOTT_BRIDGE /* #define PIOS_INCLUDE_I2C_ESC */ /* #define PIOS_INCLUDE_OVERO */ /* #define PIOS_OVERO_SPI */ diff --git a/flight/targets/boards/revolution/firmware/pios_board.c b/flight/targets/boards/revolution/firmware/pios_board.c index 3470af2739..5fd3343e75 100644 --- a/flight/targets/boards/revolution/firmware/pios_board.c +++ b/flight/targets/boards/revolution/firmware/pios_board.c @@ -1048,6 +1048,7 @@ void PIOS_Board_Init(void) case HWSETTINGS_RM_RCVRPORT_PPMMSP: case HWSETTINGS_RM_RCVRPORT_PPMMAVLINK: case HWSETTINGS_RM_RCVRPORT_PPMGPS: + case HWSETTINGS_RM_RCVRPORT_PPMHOTT: #if defined(PIOS_INCLUDE_PPM) PIOS_Board_configure_ppm(&pios_ppm_cfg); @@ -1097,6 +1098,10 @@ void PIOS_Board_Init(void) case HWSETTINGS_RM_RCVRPORT_PPMGPS: PIOS_Board_configure_com(&pios_usart_rcvrport_cfg, PIOS_COM_GPS_RX_BUF_LEN, PIOS_COM_GPS_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_gps_id); break; + case HWSETTINGS_RM_RCVRPORT_HOTT: + case HWSETTINGS_RM_RCVRPORT_PPMHOTT: + PIOS_Board_configure_com(&pios_usart_rcvrport_cfg, PIOS_COM_HOTT_RX_BUF_LEN, PIOS_COM_HOTT_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_hott_id); + break; case HWSETTINGS_RM_RCVRPORT_IBUS: #if defined(PIOS_INCLUDE_IBUS) PIOS_Board_configure_ibus(&pios_usart_ibus_rcvr_cfg); diff --git a/ground/gcs/src/plugins/uavobjects/uavobjects.pro b/ground/gcs/src/plugins/uavobjects/uavobjects.pro index 23bce4c0bf..46236e484e 100644 --- a/ground/gcs/src/plugins/uavobjects/uavobjects.pro +++ b/ground/gcs/src/plugins/uavobjects/uavobjects.pro @@ -94,6 +94,7 @@ UAVOBJS = \ $${UAVOBJ_XML_DIR}/gyrosensor.xml \ $${UAVOBJ_XML_DIR}/gyrostate.xml \ $${UAVOBJ_XML_DIR}/homelocation.xml \ + $${UAVOBJ_XML_DIR}/hottbridgesettings.xml \ $${UAVOBJ_XML_DIR}/hottbridgestatus.xml \ $${UAVOBJ_XML_DIR}/hwsettings.xml \ $${UAVOBJ_XML_DIR}/i2cstats.xml \ diff --git a/shared/uavobjectdefinition/hottbridgesettings.xml b/shared/uavobjectdefinition/hottbridgesettings.xml new file mode 100644 index 0000000000..81964dbc5d --- /dev/null +++ b/shared/uavobjectdefinition/hottbridgesettings.xml @@ -0,0 +1,82 @@ + + + Settings for the @ref HoTT Telemetry Module + + + VARIO + GPS + EAM + GAM + ESC + + + + + AltitudeBeep + MinSpeed + MaxSpeed + NegDifference1 + PosDifference1 + NegDifference2 + PosDifference2 + MinHeight + MaxHeight + MaxDistance + MinPowerVoltage + MaxPowerVoltage + MinSensor1Voltage + MaxSensor1Voltage + MinSensor2Voltage + MaxSensor2Voltage + MinCellVoltage + MaxCurrent + MaxUsedCapacity + MinSensor1Temp + MaxSensor1Temp + MinSensor2Temp + MaxSensor2Temp + MaxServoTemp + MinRPM + MaxRPM + MinFuel + MaxServoDifference + + + + + MinSpeed + MaxSpeed + NegDifference1 + PosDifference1 + NegDifference2 + PosDifference2 + MinHeight + MaxHeight + MaxDistance + MinPowerVoltage + MaxPowerVoltage + MinSensor1Voltage + MaxSensor1Voltage + MinSensor2Voltage + MaxSensor2Voltage + MinCellVoltage + MaxCurrent + MaxUsedCapacity + MinSensor1Temp + MaxSensor1Temp + MinSensor2Temp + MaxSensor2Temp + MaxServoTemp + MinRPM + MaxRPM + MinFuel + MaxServoDifference + + + + + + + + + diff --git a/shared/uavobjectdefinition/hwsettings.xml b/shared/uavobjectdefinition/hwsettings.xml index f0dfe1950b..a8ecde3637 100644 --- a/shared/uavobjectdefinition/hwsettings.xml +++ b/shared/uavobjectdefinition/hwsettings.xml @@ -11,9 +11,9 @@ - + limits="%0905NE:PPM+PWM:PPM+Telemetry:PPM+DebugConsole:PPM+ComBridge:PPM+MSP:PPM+MAVLink:PPM+GPS:PPM+HoTT:Telemetry:DebugConsole:ComBridge:MSP:MAVLink:GPS:HoTT:IBus;"/> diff --git a/shared/uavobjectdefinition/taskinfo.xml b/shared/uavobjectdefinition/taskinfo.xml index 1d7a2f4f19..57a98354f4 100644 --- a/shared/uavobjectdefinition/taskinfo.xml +++ b/shared/uavobjectdefinition/taskinfo.xml @@ -31,6 +31,7 @@ GPS OSDGen + UAVOHoTTBridge UAVOMSPBridge AutoTune UAVOMAVLinkBridge @@ -66,6 +67,7 @@ GPS OSDGen + UAVOHoTTBridge UAVOMSPBridge AutoTune UAVOMAVLinkBridge @@ -105,6 +107,7 @@ GPS OSDGen + UAVOHoTTBridge UAVOMSPBridge AutoTune UAVOMAVLinkBridge From c5ea323770277659087000d6d33e5a1949532b53 Mon Sep 17 00:00:00 2001 From: Eric Price Date: Tue, 28 Mar 2017 07:58:50 +0200 Subject: [PATCH 195/624] LP-500 fixed comment typos found in PR/review --- flight/modules/UAVOHottBridge/uavohottbridge.c | 2 +- shared/uavobjectdefinition/hottbridgestatus.xml | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/flight/modules/UAVOHottBridge/uavohottbridge.c b/flight/modules/UAVOHottBridge/uavohottbridge.c index 56a442e367..9342e0eabb 100644 --- a/flight/modules/UAVOHottBridge/uavohottbridge.c +++ b/flight/modules/UAVOHottBridge/uavohottbridge.c @@ -5,7 +5,7 @@ * @addtogroup UAVOHoTTBridge UAVO to HoTT Bridge Telemetry Module * @{ * - * @file uavohottridge.c + * @file uavohottbridge.c * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017. * Tau Labs, http://taulabs.org, Copyright (C) 2013-2014 * @brief sends telemery data on HoTT request diff --git a/shared/uavobjectdefinition/hottbridgestatus.xml b/shared/uavobjectdefinition/hottbridgestatus.xml index 06fe13a455..89e7249998 100644 --- a/shared/uavobjectdefinition/hottbridgestatus.xml +++ b/shared/uavobjectdefinition/hottbridgestatus.xml @@ -1,7 +1,6 @@ HoTTBridge Status Information - From cae5668e647939d149dcdcffeb2bce6666da10db Mon Sep 17 00:00:00 2001 From: Eric Price Date: Tue, 28 Mar 2017 08:25:34 +0200 Subject: [PATCH 196/624] LP-500 Allow HoTT Telemetry on all USARTS (Rcvr, Flexi and Main) (trivial) --- .../targets/boards/revolution/firmware/pios_board.c | 12 +++++++++--- shared/uavobjectdefinition/hwsettings.xml | 8 ++++---- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/flight/targets/boards/revolution/firmware/pios_board.c b/flight/targets/boards/revolution/firmware/pios_board.c index 5fd3343e75..e5294dc3ec 100644 --- a/flight/targets/boards/revolution/firmware/pios_board.c +++ b/flight/targets/boards/revolution/firmware/pios_board.c @@ -632,6 +632,9 @@ void PIOS_Board_Init(void) } #endif /* PIOS_INCLUDE_HOTT */ break; + case HWSETTINGS_RM_FLEXIPORT_HOTTTELEMETRY: + PIOS_Board_configure_com(&pios_usart_hott_flexi_cfg, PIOS_COM_HOTT_RX_BUF_LEN, PIOS_COM_HOTT_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_hott_id); + break; case HWSETTINGS_RM_FLEXIPORT_EXBUS: #if defined(PIOS_INCLUDE_EXBUS) @@ -844,6 +847,9 @@ void PIOS_Board_Init(void) } #endif /* PIOS_INCLUDE_DEBUG_CONSOLE */ break; + case HWSETTINGS_RM_MAINPORT_HOTTTELEMETRY: + PIOS_Board_configure_com(&pios_usart_main_cfg, PIOS_COM_HOTT_RX_BUF_LEN, PIOS_COM_HOTT_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_hott_id); + break; case HWSETTINGS_RM_MAINPORT_COMBRIDGE: PIOS_Board_configure_com(&pios_usart_main_cfg, PIOS_COM_BRIDGE_RX_BUF_LEN, PIOS_COM_BRIDGE_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_bridge_id); break; @@ -1048,7 +1054,7 @@ void PIOS_Board_Init(void) case HWSETTINGS_RM_RCVRPORT_PPMMSP: case HWSETTINGS_RM_RCVRPORT_PPMMAVLINK: case HWSETTINGS_RM_RCVRPORT_PPMGPS: - case HWSETTINGS_RM_RCVRPORT_PPMHOTT: + case HWSETTINGS_RM_RCVRPORT_PPMHOTTTELEMETRY: #if defined(PIOS_INCLUDE_PPM) PIOS_Board_configure_ppm(&pios_ppm_cfg); @@ -1098,8 +1104,8 @@ void PIOS_Board_Init(void) case HWSETTINGS_RM_RCVRPORT_PPMGPS: PIOS_Board_configure_com(&pios_usart_rcvrport_cfg, PIOS_COM_GPS_RX_BUF_LEN, PIOS_COM_GPS_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_gps_id); break; - case HWSETTINGS_RM_RCVRPORT_HOTT: - case HWSETTINGS_RM_RCVRPORT_PPMHOTT: + case HWSETTINGS_RM_RCVRPORT_HOTTTELEMETRY: + case HWSETTINGS_RM_RCVRPORT_PPMHOTTTELEMETRY: PIOS_Board_configure_com(&pios_usart_rcvrport_cfg, PIOS_COM_HOTT_RX_BUF_LEN, PIOS_COM_HOTT_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_hott_id); break; case HWSETTINGS_RM_RCVRPORT_IBUS: diff --git a/shared/uavobjectdefinition/hwsettings.xml b/shared/uavobjectdefinition/hwsettings.xml index a8ecde3637..fed486c90f 100644 --- a/shared/uavobjectdefinition/hwsettings.xml +++ b/shared/uavobjectdefinition/hwsettings.xml @@ -11,11 +11,11 @@ - - - + limits="%0905NE:PPM+PWM:PPM+Telemetry:PPM+DebugConsole:PPM+ComBridge:PPM+MSP:PPM+MAVLink:PPM+GPS:PPM+HoTT Telemetry:Telemetry:DebugConsole:ComBridge:MSP:MAVLink:GPS:HoTT Telemetry:IBus;"/> + + From ad84e51a0428bebf13f6d696617f56285af13e59 Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Fri, 10 Mar 2017 17:29:53 +0100 Subject: [PATCH 197/624] LP-491 upgrade 3rdparty build to osg 3.5.5 and osgearth 2.8 from osg 3.5.3 and osgearth 2.7 the osg upgrade allows removal of the Qt dependency this means that we don't need to recompile osg and osgearth for all OSes each time we upgrade Qt :) --- make/3rdparty/osgearth/README.TXT | 27 ++++--- make/3rdparty/osgearth/osg-3.4.0.patch | 24 ------ make/3rdparty/osgearth/osg-3.4.patch | 24 ------ make/3rdparty/osgearth/osg-3.5.1.patch | 13 --- make/3rdparty/osgearth/osg-3.5.3.patch | 13 --- .../osgearth/osg-fix-3ds-plugin.patch | 11 +++ make/3rdparty/osgearth/osgearth-2.7.patch | 66 --------------- .../osgearth-geos-3_6_1-support.patch | 80 +++++++++++++++++++ .../osgearth-remove-deprecated-call.patch | 62 ++++++++++++++ make/3rdparty/osgearth/osgearth.mk | 68 +++------------- 10 files changed, 179 insertions(+), 209 deletions(-) delete mode 100644 make/3rdparty/osgearth/osg-3.4.0.patch delete mode 100644 make/3rdparty/osgearth/osg-3.4.patch delete mode 100644 make/3rdparty/osgearth/osg-3.5.1.patch delete mode 100644 make/3rdparty/osgearth/osg-3.5.3.patch create mode 100644 make/3rdparty/osgearth/osg-fix-3ds-plugin.patch delete mode 100644 make/3rdparty/osgearth/osgearth-2.7.patch create mode 100644 make/3rdparty/osgearth/osgearth-geos-3_6_1-support.patch create mode 100644 make/3rdparty/osgearth/osgearth-remove-deprecated-call.patch diff --git a/make/3rdparty/osgearth/README.TXT b/make/3rdparty/osgearth/README.TXT index 07009056ff..5f40a3fb21 100644 --- a/make/3rdparty/osgearth/README.TXT +++ b/make/3rdparty/osgearth/README.TXT @@ -11,7 +11,7 @@ Make sure all LibrePilot SDKs are up to date as the osgEarth build relies on the More details can be found in osgearth.mk. -Linux prerequisites +Linux ---------------------------------- $ sudo apt-get install libzip-dev libpng-dev lipjpeg-dev libtiff5-dev libcurl4-openssl-dev @@ -20,22 +20,13 @@ $ sudo apt-get install libgeos++-dev libgdal-dev Alternative (not tested recently but could work): $ sudo apt-get build-dep openscenegraph -Tested with: - -$ curl --version -curl 7.35.0 (i686-pc-linux-gnu) libcurl/7.35.0 OpenSSL/1.0.1f zlib/1.2.8 libidn/1.28 librtmp/2.3 - -$ gdal-config --version -1.10.1 - - -OSX prerequisites +OSX ---------------------------------- brew install cmake brew install gdal -Windows prerequisites +Windows ---------------------------------- pacman -S mingw-w64-i686-cmake mingw-w64-i686-gdal-minimal @@ -59,6 +50,18 @@ Todo - declare provides= and conflicts with origina gdal in PKGBUILD file (allows to substitute the minimal package when anything depends on the original package) +Dependencies +---------------------------------- + + GDAL GEOS +MSYS2 2.0.1 3.6.1 +Trusty 3.4.2 +Xenial 3.5.0 +OSX 1.11.5 3.6.1 + +$ gdal-config --version +$ geos-config --version + Building ---------------------------------- diff --git a/make/3rdparty/osgearth/osg-3.4.0.patch b/make/3rdparty/osgearth/osg-3.4.0.patch deleted file mode 100644 index e8ebd4457a..0000000000 --- a/make/3rdparty/osgearth/osg-3.4.0.patch +++ /dev/null @@ -1,24 +0,0 @@ -diff --git a/include/osg/OperationThread b/include/osg/OperationThread -index a62157e..75adfba 100644 ---- a/include/osg/OperationThread -+++ b/include/osg/OperationThread -@@ -80,6 +80,7 @@ protected: - _keep(false) {} - - Operation(const Operation& op): -+ Referenced(), - _name(op._name), - _keep(op._keep) {} - -diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt -index 33edf57..d2ea025 100644 ---- a/src/CMakeLists.txt -+++ b/src/CMakeLists.txt -@@ -27,7 +27,6 @@ FOREACH( mylibfolder - osgUI - osgVolume - osgWrappers/serializers -- osgWrappers/deprecated-dotosg - osgPlugins - ) - diff --git a/make/3rdparty/osgearth/osg-3.4.patch b/make/3rdparty/osgearth/osg-3.4.patch deleted file mode 100644 index e8ebd4457a..0000000000 --- a/make/3rdparty/osgearth/osg-3.4.patch +++ /dev/null @@ -1,24 +0,0 @@ -diff --git a/include/osg/OperationThread b/include/osg/OperationThread -index a62157e..75adfba 100644 ---- a/include/osg/OperationThread -+++ b/include/osg/OperationThread -@@ -80,6 +80,7 @@ protected: - _keep(false) {} - - Operation(const Operation& op): -+ Referenced(), - _name(op._name), - _keep(op._keep) {} - -diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt -index 33edf57..d2ea025 100644 ---- a/src/CMakeLists.txt -+++ b/src/CMakeLists.txt -@@ -27,7 +27,6 @@ FOREACH( mylibfolder - osgUI - osgVolume - osgWrappers/serializers -- osgWrappers/deprecated-dotosg - osgPlugins - ) - diff --git a/make/3rdparty/osgearth/osg-3.5.1.patch b/make/3rdparty/osgearth/osg-3.5.1.patch deleted file mode 100644 index 1fe01b80e0..0000000000 --- a/make/3rdparty/osgearth/osg-3.5.1.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/include/osgViewer/View b/include/osgViewer/View -index 472b489..07ef9ce 100644 ---- a/include/osgViewer/View -+++ b/include/osgViewer/View -@@ -127,7 +127,7 @@ class OSGVIEWER_EXPORT View : public osg::View, public osgGA::GUIActionAdapter - /** Set the View's image pager.*/ - void setImagePager(osgDB::ImagePager* ip); - -- template void setImagePager(const osg::ref_ptr* ip) { setImagePager(ip.get()); } -+ template void setImagePager(const osg::ref_ptr& ip) { setImagePager(ip.get()); } - - /** Get the View's image pager.*/ - osgDB::ImagePager* getImagePager(); diff --git a/make/3rdparty/osgearth/osg-3.5.3.patch b/make/3rdparty/osgearth/osg-3.5.3.patch deleted file mode 100644 index df10de9d5a..0000000000 --- a/make/3rdparty/osgearth/osg-3.5.3.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/src/osgPlugins/cfg/CMakeLists.txt b/src/osgPlugins/cfg/CMakeLists.txt -index 972675f..4f7062b 100644 ---- a/src/osgPlugins/cfg/CMakeLists.txt -+++ b/src/osgPlugins/cfg/CMakeLists.txt -@@ -20,7 +20,7 @@ SET(TARGET_H - - # lex/yacc generated files use register that causes warnings with CLang under OSX so disable this warnings. - IF(${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang") -- SET(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} -Wno-deprecated-register) -+ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated-register") - ENDIF() - - # diff --git a/make/3rdparty/osgearth/osg-fix-3ds-plugin.patch b/make/3rdparty/osgearth/osg-fix-3ds-plugin.patch new file mode 100644 index 0000000000..f509cc7836 --- /dev/null +++ b/make/3rdparty/osgearth/osg-fix-3ds-plugin.patch @@ -0,0 +1,11 @@ +--- OpenSceneGraph-OpenSceneGraph-3.5.5/src/osgPlugins/3ds/ReaderWriter3DS.cpp 2017-02-24 13:09:52.785969600 +0100 ++++ OpenSceneGraph-OpenSceneGraph-3.5.5/src/osgPlugins/3ds/ReaderWriter3DS.cpp.orig 2017-02-24 13:01:55.130353400 +0100 +@@ -619,7 +619,7 @@ + { + // add our geometry to group (where our children already are) + // creates geometry under modifier node +- processMesh(drawStateMap,group,mesh,meshAppliedMatPtr); ++ processMesh(drawStateMap,meshTransform,mesh,meshAppliedMatPtr); + return group; + } + else diff --git a/make/3rdparty/osgearth/osgearth-2.7.patch b/make/3rdparty/osgearth/osgearth-2.7.patch deleted file mode 100644 index d6ef84719b..0000000000 --- a/make/3rdparty/osgearth/osgearth-2.7.patch +++ /dev/null @@ -1,66 +0,0 @@ -diff --git a/src/osgEarth/ElevationQuery b/src/osgEarth/ElevationQuery -index d8e4d14..50db567 100644 ---- a/src/osgEarth/ElevationQuery -+++ b/src/osgEarth/ElevationQuery -@@ -37,7 +37,11 @@ namespace osgEarth - - void pruneUnusedDatabaseCache(); - -+#if OSG_VERSION_GREATER_OR_EQUAL(3,5,0) -+ virtual osg::ref_ptr readNodeFile(const std::string& filename); -+#else - virtual osg::Node* readNodeFile(const std::string& filename); -+#endif - - protected: - -diff --git a/src/osgEarth/ElevationQuery.cpp b/src/osgEarth/ElevationQuery.cpp -index 5fb8222..8c03309 100644 ---- a/src/osgEarth/ElevationQuery.cpp -+++ b/src/osgEarth/ElevationQuery.cpp -@@ -55,7 +55,11 @@ void ElevationQueryCacheReadCallback::pruneUnusedDatabaseCache() - { - } - -+#if OSG_VERSION_GREATER_OR_EQUAL(3,5,0) -+osg::ref_ptr ElevationQueryCacheReadCallback::readNodeFile(const std::string& filename) -+#else - osg::Node* ElevationQueryCacheReadCallback::readNodeFile(const std::string& filename) -+#endif - { - // first check to see if file is already loaded. - { -@@ -71,7 +75,7 @@ osg::Node* ElevationQueryCacheReadCallback::readNodeFile(const std::string& file - } - - // now load the file. -- osg::ref_ptr node = osgDB::readNodeFile(filename); -+ osg::ref_ptr node = osgDB::readRefNodeFile(filename); - - // insert into the cache. - if (node.valid()) -@@ -105,7 +109,11 @@ osg::Node* ElevationQueryCacheReadCallback::readNodeFile(const std::string& file - } - } - -+#if OSG_VERSION_GREATER_OR_EQUAL(3,5,0) -+ return node; -+#else - return node.release(); -+#endif - } - - ElevationQuery::ElevationQuery(const Map* map) : -diff --git a/src/osgEarthSymbology/Resource b/src/osgEarthSymbology/Resource -index a8a1441..934fc7d 100644 ---- a/src/osgEarthSymbology/Resource -+++ b/src/osgEarthSymbology/Resource -@@ -33,7 +33,7 @@ namespace osgEarth { namespace Symbology - class OSGEARTHSYMBOLOGY_EXPORT Resource : public Taggable - { - protected: -- Resource(const Resource& rhs,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY) {}; -+ Resource(const Resource& rhs,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY) : Taggable() {}; - Resource( const Config& config =Config() ); - - /** dtor */ diff --git a/make/3rdparty/osgearth/osgearth-geos-3_6_1-support.patch b/make/3rdparty/osgearth/osgearth-geos-3_6_1-support.patch new file mode 100644 index 0000000000..d16d36e65d --- /dev/null +++ b/make/3rdparty/osgearth/osgearth-geos-3_6_1-support.patch @@ -0,0 +1,80 @@ +From 2a0f721b58a3280f151df095ef6cb8a9f063ba25 Mon Sep 17 00:00:00 2001 +From: Philippe Renon +Date: Fri, 13 Jan 2017 15:13:54 +0100 +Subject: [PATCH] support geos 3.6.1 + +--- + src/osgEarthSymbology/GEOS | 3 ++- + src/osgEarthSymbology/GEOS.cpp | 13 ++----------- + 2 files changed, 4 insertions(+), 12 deletions(-) + +diff --git a/src/osgEarthSymbology/GEOS b/src/osgEarthSymbology/GEOS +index b695bb7de..0184f6422 100644 +--- a/src/osgEarthSymbology/GEOS ++++ b/src/osgEarthSymbology/GEOS +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + + namespace osgEarth { namespace Symbology + { +@@ -45,7 +46,7 @@ namespace osgEarth { namespace Symbology + void disposeGeometry(geos::geom::Geometry* input); + + protected: +- geos::geom::GeometryFactory* _factory; ++ geos::geom::GeometryFactory::unique_ptr _factory; + }; + + } } // namespace osgEarth::Features +diff --git a/src/osgEarthSymbology/GEOS.cpp b/src/osgEarthSymbology/GEOS.cpp +index cf04e3309..d87bf461f 100644 +--- a/src/osgEarthSymbology/GEOS.cpp ++++ b/src/osgEarthSymbology/GEOS.cpp +@@ -212,7 +212,7 @@ GEOSContext::GEOSContext() + geos::geom::PrecisionModel* pm = new geos::geom::PrecisionModel(geom::PrecisionModel::FLOATING); + + // Factory will clone the PM +- _factory = new geos::geom::GeometryFactory( pm ); ++ _factory = geos::geom::GeometryFactory::create( pm ); + + // Delete the template. + delete pm; +@@ -220,7 +220,6 @@ GEOSContext::GEOSContext() + + GEOSContext::~GEOSContext() + { +- delete _factory; + } + + geom::Geometry* +@@ -229,12 +228,7 @@ GEOSContext::importGeometry(const Symbology::Geometry* input) + geom::Geometry* output = 0L; + if ( input && input->isValid() ) + { +- output = import( input, _factory ); +- +- // if output is ok, it will have a pointer to f. this is probably a leak. +- // TODO: Check whether this is a leak!! -gw +- //if ( !output ) +- // delete f; ++ output = import( input, _factory.get() ); + } + return output; + } +@@ -327,10 +321,7 @@ GEOSContext::disposeGeometry(geom::Geometry* input) + { + if (input) + { +- geom::GeometryFactory* f = const_cast(input->getFactory()); + _factory->destroyGeometry(input); +- if ( f != _factory ) +- delete f; + } + } + +-- +2.12.0 + diff --git a/make/3rdparty/osgearth/osgearth-remove-deprecated-call.patch b/make/3rdparty/osgearth/osgearth-remove-deprecated-call.patch new file mode 100644 index 0000000000..47f1cee573 --- /dev/null +++ b/make/3rdparty/osgearth/osgearth-remove-deprecated-call.patch @@ -0,0 +1,62 @@ +From b69573f50496f9cdcad2bff5e5e25bf1ecea94e6 Mon Sep 17 00:00:00 2001 +From: gwaldron +Date: Mon, 17 Oct 2016 08:04:31 -0400 +Subject: [PATCH] Removed/patched deprecated called to osg::Referenced + thread-safe reference counting + +--- + src/osgEarth/Locators.cpp | 4 ++-- + src/osgEarth/Registry.cpp | 3 +++ + src/osgEarth/TileSource.cpp | 2 -- + 3 files changed, 5 insertions(+), 4 deletions(-) + +diff --git a/src/osgEarth/Locators.cpp b/src/osgEarth/Locators.cpp +index fb3e825..fcb780c 100644 +--- a/src/osgEarth/Locators.cpp ++++ b/src/osgEarth/Locators.cpp +@@ -29,7 +29,7 @@ _inverseCalculated(false), + _x0(0.0), _x1(1.0), + _y0(0.0), _y1(1.0) + { +- this->setThreadSafeRefUnref(true); ++ //nop + } + + GeoLocator::GeoLocator( const GeoExtent& dataExtent ) : +@@ -38,7 +38,7 @@ _dataExtent( dataExtent ), + _x0(0.0), _x1(1.0), + _y0(0.0), _y1(1.0) + { +- this->setThreadSafeRefUnref(true); ++ //nop + } + + GeoLocator::GeoLocator( const osgTerrain::Locator& prototype, const GeoExtent& dataExtent ) : +diff --git a/src/osgEarth/Registry.cpp b/src/osgEarth/Registry.cpp +index 32a9439..bf95e87 100644 +--- a/src/osgEarth/Registry.cpp ++++ b/src/osgEarth/Registry.cpp +@@ -694,7 +694,10 @@ class RegisterEarthTileExtension + public: + RegisterEarthTileExtension() + { ++#if OSG_VERSION_LESS_THAN(3,5,4) ++ // Method deprecated beyone 3.5.4 since all ref counting is thread-safe by default + osg::Referenced::setThreadSafeReferenceCounting( true ); ++#endif + osgDB::Registry::instance()->addFileExtensionAlias("earth_tile", "earth"); + } + }; +diff --git a/src/osgEarth/TileSource.cpp b/src/osgEarth/TileSource.cpp +index fcdf2b8..28c6f61 100644 +--- a/src/osgEarth/TileSource.cpp ++++ b/src/osgEarth/TileSource.cpp +@@ -218,8 +218,6 @@ _status ( Status::Error("Not initialized") ), + _mode ( 0 ), + _openCalled( false ) + { +- this->setThreadSafeRefUnref( true ); +- + // Initialize the l2 cache size to the options. + int l2CacheSize = *options.L2CacheSize(); + diff --git a/make/3rdparty/osgearth/osgearth.mk b/make/3rdparty/osgearth/osgearth.mk index 44866e7d58..f28ba339a9 100644 --- a/make/3rdparty/osgearth/osgearth.mk +++ b/make/3rdparty/osgearth/osgearth.mk @@ -23,7 +23,7 @@ OSG_BUILD_CONF := Release OSG_NAME_PREFIX := -OSG_NAME_SUFIX := -qt-$(QT_VERSION) +OSG_NAME_SUFIX := ################################ # @@ -31,7 +31,7 @@ OSG_NAME_SUFIX := -qt-$(QT_VERSION) # ################################ -OSG_VERSION := 3.5.3 +OSG_VERSION := 3.5.5 OSG_GIT_TAG := OpenSceneGraph-$(OSG_VERSION) OSG_BASE_NAME := osg-$(OSG_VERSION) @@ -45,14 +45,11 @@ ifeq ($(UNAME), Linux) OSG_CMAKE_GENERATOR := "Unix Makefiles" OSG_CMAKE_MAKE_PROGRAM := make OSG_WINDOWING_SYSTEM := "X11" - # for some reason Qt is not added to the path in make/tools.mk - OSG_BUILD_PATH := $(QT_SDK_PREFIX)/bin:$(PATH) else ifeq ($(UNAME), Darwin) OSG_NAME := $(OSG_BASE_NAME)-clang_64 OSG_CMAKE_GENERATOR := "Unix Makefiles" OSG_CMAKE_MAKE_PROGRAM := make OSG_WINDOWING_SYSTEM := "Cocoa" - OSG_BUILD_PATH := $(QT_SDK_PREFIX)/bin:$(PATH) else ifeq ($(UNAME), Windows) OSG_NAME := $(OSG_BASE_NAME)-$(QT_SDK_ARCH) OSG_CMAKE_GENERATOR := "MinGW Makefiles" @@ -62,7 +59,6 @@ OSG_NAME := $(OSG_NAME_PREFIX)$(OSG_NAME)$(OSG_NAME_SUFIX) OSG_SRC_DIR := $(ROOT_DIR)/3rdparty/osg OSG_BUILD_DIR := $(BUILD_DIR)/3rdparty/$(OSG_NAME) OSG_INSTALL_DIR := $(BUILD_DIR)/3rdparty/install/$(OSG_NAME) -OSG_PATCH_FILE := $(ROOT_DIR)/make/3rdparty/osgearth/osg-$(OSG_VERSION).patch .PHONY: osg osg: @@ -74,17 +70,15 @@ osg: fi ; \ $(CMAKE) -G $(OSG_CMAKE_GENERATOR) -DCMAKE_BUILD_TYPE=$(OSG_BUILD_CONF) \ -DCMAKE_MAKE_PROGRAM=$(MAKE) \ - -DOSG_USE_QT=ON \ -DBUILD_OSG_APPLICATIONS=ON \ -DBUILD_OSG_EXAMPLES=OFF \ - -DBUILD_OPENTHREADS_WITH_QT=OFF \ -DOSG_GL3_AVAILABLE=OFF \ -DOSG_PLUGIN_SEARCH_INSTALL_DIR_FOR_PLUGINS=OFF \ -DCMAKE_OSX_ARCHITECTURES="x86_64" \ -DOSG_WINDOWING_SYSTEM=$(OSG_WINDOWING_SYSTEM) \ -DCMAKE_INSTALL_NAME_DIR=@executable_path/../Plugins \ -DCMAKE_INSTALL_PREFIX=$(OSG_INSTALL_DIR) $(OSG_SRC_DIR) && \ - $(MAKE) && \ + $(MAKE) -j3 && \ $(MAKE) install ; \ ) @@ -99,34 +93,6 @@ package_osg: $(call MD5_GEN_TEMPLATE,$(notdir $(OSG_INSTALL_DIR)).tar.gz) ; \ ) -.PHONY: install_win_osg -install_win_osg: - # curl - $(V1) $(CP) /mingw32/bin/libcurl-4.dll $(OSG_INSTALL_DIR)/bin/ - $(V1) $(CP) /mingw32/bin/libidn-11.dll $(OSG_INSTALL_DIR)/bin/ - $(V1) $(CP) /mingw32/bin/librtmp-1.dll $(OSG_INSTALL_DIR)/bin/ - $(V1) $(CP) /mingw32/bin/libgmp-10.dll $(OSG_INSTALL_DIR)/bin/ - $(V1) $(CP) /mingw32/bin/libgnutls-30.dll $(OSG_INSTALL_DIR)/bin/ - $(V1) $(CP) /mingw32/bin/libp11-kit-0.dll $(OSG_INSTALL_DIR)/bin/ - $(V1) $(CP) /mingw32/bin/libffi-6.dll $(OSG_INSTALL_DIR)/bin/ - $(V1) $(CP) /mingw32/bin/libtasn1-6.dll $(OSG_INSTALL_DIR)/bin/ - $(V1) $(CP) /mingw32/bin/libhogweed-4-1.dll $(OSG_INSTALL_DIR)/bin/ - $(V1) $(CP) /mingw32/bin/libnettle-6-1.dll $(OSG_INSTALL_DIR)/bin/ - $(V1) $(CP) /mingw32/bin/libssh2-1.dll $(OSG_INSTALL_DIR)/bin/ - # gdal - $(V1) $(CP) /mingw32/bin/libgdal-20.dll $(OSG_INSTALL_DIR)/bin/ - $(V1) $(CP) /mingw32/bin/libgeos_c.dll $(OSG_INSTALL_DIR)/bin/ - $(V1) $(CP) /mingw32/bin/libgeos.dll $(OSG_INSTALL_DIR)/bin/ - $(V1) $(CP) /mingw32/bin/libjpeg-8.dll $(OSG_INSTALL_DIR)/bin/ - $(V1) $(CP) /mingw32/bin/libtiff-5.dll $(OSG_INSTALL_DIR)/bin/ - $(V1) $(CP) /mingw32/bin/liblzma-5.dll $(OSG_INSTALL_DIR)/bin/ - $(V1) $(CP) /mingw32/bin/libiconv-2.dll $(OSG_INSTALL_DIR)/bin/ - $(V1) $(CP) /mingw32/bin/zlib1.dll $(OSG_INSTALL_DIR)/bin/ - # other - $(V1) $(CP) /mingw32/bin/libproj-9.dll $(OSG_INSTALL_DIR)/bin/ - $(V1) $(CP) /mingw32/bin/libfreetype-6.dll $(OSG_INSTALL_DIR)/bin/ - $(V1) $(CP) /mingw32/bin/libpng16-16.dll $(OSG_INSTALL_DIR)/bin/ - .NOTPARALLEL: .PHONY: prepare_osg prepare_osg: clone_osg @@ -141,10 +107,7 @@ clone_osg: $(V1) $(GIT) clone --depth 1 --no-checkout -b $(OSG_GIT_TAG) git://github.com/openscenegraph/osg.git $(OSG_SRC_DIR) @$(ECHO) "Checkout osg $(OSG_GIT_TAG)" $(V1) ( $(CD) $(OSG_SRC_DIR) && $(GIT) checkout --force tags/$(OSG_GIT_TAG) ; ) - $(V1) if [ -e $(OSG_PATCH_FILE) ]; then \ - $(ECHO) "Patching osg..." ; \ - ( $(CD) $(OSG_SRC_DIR) && $(GIT) apply $(OSG_PATCH_FILE) ; ) \ - fi + $(V1) ( $(CD) $(OSG_SRC_DIR) && $(GIT) apply $(ROOT_DIR)/make/3rdparty/osgearth/osg-fix-3ds-plugin.patch ; ) .PHONY: clean_osg clean_osg: @@ -168,7 +131,7 @@ clean_all_osg: clean_osg # fix Debug build # add option to not build the applications (in Debug mode in particular) -OSGEARTH_VERSION := 2.7 +OSGEARTH_VERSION := 2.8 OSGEARTH_GIT_TAG := osgearth-$(OSGEARTH_VERSION) OSGEARTH_BASE_NAME := osgearth-$(OSGEARTH_VERSION) @@ -184,8 +147,7 @@ ifeq ($(UNAME), Linux) endif OSGEARTH_CMAKE_GENERATOR := "Unix Makefiles" OSGEARTH_CMAKE_MAKE_PROGRAM := make - # for some reason Qt is not added to the path in make/tools.mk - OSGEARTH_BUILD_PATH := $(QT_SDK_PREFIX)/bin:$(OSG_INSTALL_DIR)/bin:$(PATH) + OSGEARTH_BUILD_PATH := $(OSG_INSTALL_DIR)/bin:$(PATH) ifeq ($(ARCH), x86_64) OSGEARTH_LIB_PATH := $(OSG_INSTALL_DIR)/lib64 else @@ -195,7 +157,7 @@ else ifeq ($(UNAME), Darwin) OSGEARTH_NAME := $(OSGEARTH_BASE_NAME)-clang_64 OSGEARTH_CMAKE_GENERATOR := "Unix Makefiles" OSGEARTH_CMAKE_MAKE_PROGRAM := make - OSGEARTH_BUILD_PATH := $(QT_SDK_PREFIX)/bin:$(OSG_INSTALL_DIR)/bin:$(PATH) + OSGEARTH_BUILD_PATH := $(OSG_INSTALL_DIR)/bin:$(PATH) OSGEARTH_LIB_PATH := $(OSG_INSTALL_DIR)/lib else ifeq ($(UNAME), Windows) OSGEARTH_NAME := $(OSGEARTH_BASE_NAME)-$(QT_SDK_ARCH) @@ -207,7 +169,6 @@ OSGEARTH_NAME := $(OSG_NAME_PREFIX)$(OSGEARTH_NAME)$(OSG_NAME_SUFIX) OSGEARTH_SRC_DIR := $(ROOT_DIR)/3rdparty/osgearth OSGEARTH_BUILD_DIR := $(BUILD_DIR)/3rdparty/$(OSGEARTH_NAME) OSGEARTH_INSTALL_DIR := $(BUILD_DIR)/3rdparty/install/$(OSGEARTH_NAME) -OSGEARTH_PATCH_FILE := $(ROOT_DIR)/make/3rdparty/osgearth/osgearth-$(OSGEARTH_VERSION).patch .PHONY: osgearth osgearth: @@ -222,7 +183,7 @@ osgearth: unset OSG_NOTIFY_LEVEL && \ $(CMAKE) -G $(OSGEARTH_CMAKE_GENERATOR) -DCMAKE_BUILD_TYPE=$(OSGEARTH_BUILD_CONF) \ -DCMAKE_MAKE_PROGRAM=$(MAKE) \ - -DOSGEARTH_USE_QT=ON \ + -DOSGEARTH_USE_QT=OFF \ -DINSTALL_TO_OSG_DIR=OFF \ -DOSG_DIR=$(OSG_INSTALL_DIR) \ -DCMAKE_INCLUDE_PATH=$(OSG_INSTALL_DIR)/include \ @@ -231,7 +192,7 @@ osgearth: -DCMAKE_OSX_ARCHITECTURES="x86_64" \ -DCMAKE_INSTALL_NAME_DIR=@executable_path/../Plugins \ -DCMAKE_INSTALL_PREFIX=$(OSGEARTH_INSTALL_DIR) $(OSGEARTH_SRC_DIR) && \ - $(MAKE) && \ + $(MAKE) -j3 && \ $(MAKE) install ; \ ) @@ -259,10 +220,8 @@ clone_osgearth: $(V1) $(GIT) clone --depth 1 --no-checkout -b $(OSGEARTH_GIT_TAG) git://github.com/gwaldron/osgearth.git $(OSGEARTH_SRC_DIR) @$(ECHO) "Checkout osgearth $(OSGEARTH_GIT_TAG)" $(V1) ( $(CD) $(OSGEARTH_SRC_DIR) && $(GIT) checkout --force tags/$(OSGEARTH_GIT_TAG) ; ) - $(V1) if [ -e $(OSGEARTH_PATCH_FILE) ]; then \ - $(ECHO) "Patching osgearth..." ; \ - ( $(CD) $(OSGEARTH_SRC_DIR) && $(GIT) apply $(OSGEARTH_PATCH_FILE) ; ) \ - fi + $(V1) ( $(CD) $(OSGEARTH_SRC_DIR) && $(GIT) apply $(ROOT_DIR)/make/3rdparty/osgearth/osgearth-remove-deprecated-call.patch ; ) + $(V1) ( $(CD) $(OSGEARTH_SRC_DIR) && $(GIT) apply $(ROOT_DIR)/make/3rdparty/osgearth/osgearth-geos-3_6_1-support.patch ; ) .PHONY: clean_osgearth clean_osgearth: @@ -284,9 +243,4 @@ clean_all_osgearth: clean_osgearth .NOTPARALLEL: .PHONY: all_osg - -ifeq ($(UNAME), Windows) -all_osg: prepare_osg prepare_osgearth osg osgearth install_win_osg package_osg package_osgearth -else all_osg: prepare_osg prepare_osgearth osg osgearth package_osg package_osgearth -endif From 5569bc3fb6d6dcaaf8525bf719230f3a612a9681 Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Wed, 15 Mar 2017 22:00:30 +0100 Subject: [PATCH 198/624] LP-491 update GCS to use osg 3.5.5 and osgearth 2.8 --- make/tools.mk | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/make/tools.mk b/make/tools.mk index 87c39526b9..366030b352 100644 --- a/make/tools.mk +++ b/make/tools.mk @@ -86,16 +86,23 @@ $(TOOL_REMOVE_TARGETS): TOOLS_URL := http://librepilot.github.io/tools +# versions given below are defaults +# and are used only to install the tools on some OSes +# don't assume actual versions to match + QT_SHORT_VERSION := 5.6 QT_VERSION := 5.6.2 +OSG_VERSION := 3.5.5 +OSGEARTH_VERSION := 2.8 + ifeq ($(UNAME), Linux) ifeq ($(ARCH), x86_64) QT_SDK_ARCH := gcc_64 QT_SDK_URL := http://download.qt.io/official_releases/qt/$(QT_SHORT_VERSION)/$(QT_VERSION)/qt-opensource-linux-x64-$(QT_VERSION).run QT_SDK_MD5_URL := http://download.qt.io/official_releases/qt/$(QT_SHORT_VERSION)/$(QT_VERSION)/md5sums.txt - OSG_URL := $(TOOLS_URL)/osg-3.5.3-linux-x64-qt-$(QT_VERSION).tar.gz - OSGEARTH_URL := $(TOOLS_URL)/osgearth-2.7-linux-x64-qt-$(QT_VERSION).tar.gz + OSG_URL := $(TOOLS_URL)/osg-$(OSG_VERSION)-linux-x64.tar.gz + OSGEARTH_URL := $(TOOLS_URL)/osgearth-$(OSGEARTH_VERSION)-linux-x64.tar.gz else # x32 for linux no longer provided as pre-built binaries. endif @@ -109,8 +116,8 @@ else ifeq ($(UNAME), Darwin) QT_SDK_MAINTENANCE_TOOL := /Volumes/qt-opensource-mac-x64-clang-$(QT_VERSION)/qt-opensource-mac-x64-clang-$(QT_VERSION).app/Contents/MacOS/qt-opensource-mac-x64-clang-$(QT_VERSION) UNCRUSTIFY_URL := $(TOOLS_URL)/uncrustify-0.60.tar.gz DOXYGEN_URL := $(TOOLS_URL)/doxygen-1.8.3.1.src.tar.gz - OSG_URL := $(TOOLS_URL)/osg-3.5.3-clang_64-qt-$(QT_VERSION).tar.gz - OSGEARTH_URL := $(TOOLS_URL)/osgearth-2.7-clang_64-qt-$(QT_VERSION).tar.gz + OSG_URL := $(TOOLS_URL)/osg-$(OSG_VERSION)-clang_64.tar.gz + OSGEARTH_URL := $(TOOLS_URL)/osgearth-$(OSGEARTH_VERSION)-clang_64.tar.gz else ifeq ($(UNAME), Windows) QT_SDK_ARCH := mingw492_32 QT_SDK_URL := http://download.qt.io/official_releases/qt/$(QT_SHORT_VERSION)/$(QT_VERSION)/qt-opensource-windows-x86-mingw492-$(QT_VERSION).exe @@ -133,15 +140,15 @@ CCACHE_DIR := $(TOOLS_DIR)/ccache ifeq ($(UNAME), Linux) ifeq ($(ARCH), x86_64) - OSG_SDK_DIR := $(TOOLS_DIR)/osg-3.5.3-linux-x64-qt-$(QT_VERSION) - OSGEARTH_SDK_DIR := $(TOOLS_DIR)/osgearth-2.7-linux-x64-qt-$(QT_VERSION) + OSG_SDK_DIR := $(TOOLS_DIR)/osg-$(OSG_VERSION)-linux-x64 + OSGEARTH_SDK_DIR := $(TOOLS_DIR)/osgearth-$(OSGEARTH_VERSION)-linux-x64 else - OSG_SDK_DIR := $(TOOLS_DIR)/osg-3.5.3-linux-x86-qt-$(QT_VERSION) - OSGEARTH_SDK_DIR := $(TOOLS_DIR)/osgearth-2.7-linux-x86-qt-$(QT_VERSION) + OSG_SDK_DIR := $(TOOLS_DIR)/osg-$(OSG_VERSION)-linux-x86 + OSGEARTH_SDK_DIR := $(TOOLS_DIR)/osgearth-$(OSGEARTH_VERSION)-linux-x86 endif else ifeq ($(UNAME), Darwin) - OSG_SDK_DIR := $(TOOLS_DIR)/osg-3.5.3-clang_64-qt-$(QT_VERSION) - OSGEARTH_SDK_DIR := $(TOOLS_DIR)/osgearth-2.7-clang_64-qt-$(QT_VERSION) + OSG_SDK_DIR := $(TOOLS_DIR)/osg-$(OSG_VERSION)-clang_64 + OSGEARTH_SDK_DIR := $(TOOLS_DIR)/osgearth-$(OSGEARTH_VERSION)-clang_64 else ifeq ($(UNAME), Windows) ifeq ($(ARCH), x86_64) MINGW_DIR := /mingw64 From 2bbd63946b0ca793f619f04b4e8aca78a9e22b25 Mon Sep 17 00:00:00 2001 From: Fernando Lopez Jr Date: Mon, 6 Feb 2017 06:41:35 +0000 Subject: [PATCH 199/624] LP-491 Add Q_NAMESPACE for Qt 5.8 --- ground/gcs/src/experimental/USB_UPLOAD_TOOL/dfu.h | 3 +++ ground/gcs/src/plugins/uploader/dfu.h | 3 +++ 2 files changed, 6 insertions(+) diff --git a/ground/gcs/src/experimental/USB_UPLOAD_TOOL/dfu.h b/ground/gcs/src/experimental/USB_UPLOAD_TOOL/dfu.h index 7fa93daeb2..8c8c8e5018 100644 --- a/ground/gcs/src/experimental/USB_UPLOAD_TOOL/dfu.h +++ b/ground/gcs/src/experimental/USB_UPLOAD_TOOL/dfu.h @@ -46,6 +46,9 @@ class qsspt; class opHID_hidapi; namespace DFU { +#if QT_VERSION >= QT_VERSION_CHECK(5, 8, 0) +Q_NAMESPACE +#endif enum TransferTypes { FW, Descript diff --git a/ground/gcs/src/plugins/uploader/dfu.h b/ground/gcs/src/plugins/uploader/dfu.h index 5dea6fded8..6172a3cd6e 100644 --- a/ground/gcs/src/plugins/uploader/dfu.h +++ b/ground/gcs/src/plugins/uploader/dfu.h @@ -46,6 +46,9 @@ class qsspt; class opHID_hidapi; namespace DFU { +#if QT_VERSION >= QT_VERSION_CHECK(5, 8, 0) +Q_NAMESPACE +#endif enum TransferTypes { FW, Descript From 6aa8fd49f2d1113b68d68ae0d6bd8a5219bd83f0 Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Thu, 16 Mar 2017 00:50:42 +0100 Subject: [PATCH 200/624] LP-491 upgrade to Qt 5.8.0 --- ground/gcs/src/libs/osgearth/copydata.pro | 4 ++- make/tool_install/qt-install.qs | 36 ++++++++++++++--------- make/tools.mk | 10 +++---- 3 files changed, 30 insertions(+), 20 deletions(-) diff --git a/ground/gcs/src/libs/osgearth/copydata.pro b/ground/gcs/src/libs/osgearth/copydata.pro index c263520f54..18070984b2 100644 --- a/ground/gcs/src/libs/osgearth/copydata.pro +++ b/ground/gcs/src/libs/osgearth/copydata.pro @@ -53,6 +53,7 @@ osg:win32 { librtmp-1.dll \ libgmp-10.dll \ libgnutls-30.dll \ + libunistring-2.dll \ libp11-kit-0.dll \ libffi-6.dll \ libtasn1-6.dll \ @@ -184,7 +185,8 @@ osgearth:win32 { libosgEarthAnnotation$${DS}.dll \ libosgEarthFeatures$${DS}.dll \ libosgEarthSymbology$${DS}.dll \ - libosgEarthUtil$${DS}.dll + libosgEarthUtil$${DS}.dll \ + libprotobuf.dll # gdal OSGEARTH_LIBS += \ diff --git a/make/tool_install/qt-install.qs b/make/tool_install/qt-install.qs index 4e98de846b..441d7bbd97 100644 --- a/make/tool_install/qt-install.qs +++ b/make/tool_install/qt-install.qs @@ -1,9 +1,12 @@ /* -silent installer script +Silent installer script -known to work with Qt 5.6.0 and QtIFW 2.1.0 +Known to work with Qt 5.8.0 and QtIFW 2.0.5 -known issues: +Test with: +$ ./qt-opensource-windows-x86-mingw530-5.8.0.exe --verbose --script ../librepilot/make/tool_install/qt-install.qs + +Known issues: - silent but not headless (QtIFW 2.1.0 should support gui.setSilent(true)) - cannot disable forced components (QtCreator, ...) - cannot disable virtual components (doc, examples, ...) @@ -17,7 +20,7 @@ function Controller() var qtInstallTargetDir = installer.environmentVariable("QT_INSTALL_TARGET_DIR"); if (qtInstallTargetDir == "") { - qtInstallTargetDir = installer.environmentVariable("PWD") + "/tools/qt-5.6.0"; + qtInstallTargetDir = installer.environmentVariable("PWD") + "/tools/qt-5.8.0"; console.log("Environment variable QT_INSTALL_TARGET_DIR not set, using default " + qtInstallTargetDir); } installer.setValue("TargetDir", qtInstallTargetDir); @@ -65,6 +68,14 @@ onFinishedCalculateComponentsToInstall = function() //dumpComponents(); } +function disableComponent(componentName) +{ + component = installer.componentByName(componentName) + component.enabled = false + component.forcedInstallation = false + //component.setValue("ForcedInstallation", "false"); +} + // page callbacks // used to setup wizard pages and move the wizard forward @@ -96,25 +107,22 @@ Controller.prototype.ComponentSelectionPageCallback = function() var page = gui.currentPageWidget(); page.deselectAll() if (installer.value("os") == "win") { - selectComponent(page, "qt.56.win32_mingw492"); - selectComponent(page, "qt.tools.win32_mingw492"); + selectComponent(page, "qt.58.win32_mingw53"); + selectComponent(page, "qt.tools.win32_mingw530"); } else if (installer.value("os") == "x11") { - selectComponent(page, "qt.56.gcc"); - selectComponent(page, "qt.56.gcc_64"); + selectComponent(page, "qt.58.gcc"); + selectComponent(page, "qt.58.gcc_64"); } else if (installer.value("os") == "mac") { - selectComponent(page, "qt.56.clang_64"); + selectComponent(page, "qt.58.clang_64"); } - selectComponent(page, "qt.56.qtquickcontrols"); - selectComponent(page, "qt.56.qtscript"); - - //installer.componentByName("qt.tools.qtcreator").setValue("ForcedInstallation", "false"); + //selectComponent(page, "qt.58.qtquickcontrols"); + selectComponent(page, "qt.58.qtscript"); gui.clickButton(buttons.NextButton); } - function selectComponent(page, name) { component = installer.componentByName(name); diff --git a/make/tools.mk b/make/tools.mk index 366030b352..902be7aaf5 100644 --- a/make/tools.mk +++ b/make/tools.mk @@ -90,8 +90,8 @@ TOOLS_URL := http://librepilot.github.io/tools # and are used only to install the tools on some OSes # don't assume actual versions to match -QT_SHORT_VERSION := 5.6 -QT_VERSION := 5.6.2 +QT_SHORT_VERSION := 5.8 +QT_VERSION := 5.8.0 OSG_VERSION := 3.5.5 OSGEARTH_VERSION := 2.8 @@ -119,8 +119,8 @@ else ifeq ($(UNAME), Darwin) OSG_URL := $(TOOLS_URL)/osg-$(OSG_VERSION)-clang_64.tar.gz OSGEARTH_URL := $(TOOLS_URL)/osgearth-$(OSGEARTH_VERSION)-clang_64.tar.gz else ifeq ($(UNAME), Windows) - QT_SDK_ARCH := mingw492_32 - QT_SDK_URL := http://download.qt.io/official_releases/qt/$(QT_SHORT_VERSION)/$(QT_VERSION)/qt-opensource-windows-x86-mingw492-$(QT_VERSION).exe + QT_SDK_ARCH := mingw53_32 + QT_SDK_URL := http://download.qt.io/official_releases/qt/$(QT_SHORT_VERSION)/$(QT_VERSION)/qt-opensource-windows-x86-mingw530-$(QT_VERSION).exe QT_SDK_MD5_URL := http://download.qt.io/official_releases/qt/$(QT_SHORT_VERSION)/$(QT_VERSION)/md5sums.txt NSIS_URL := $(TOOLS_URL)/nsis-2.46-unicode.tar.bz2 MESAWIN_URL := $(TOOLS_URL)/mesawin.tar.gz @@ -349,7 +349,7 @@ endif ############################## define DOWNLOAD_TEMPLATE -@$(ECHO) $(MSG_VERIFYING) $$(call toprel, $(DL_DIR)/$(2)) + @$(ECHO) $(MSG_VERIFYING) $$(call toprel, $(DL_DIR)/$(2)) $(V1) ( \ cd "$(DL_DIR)" && \ $(CURL) $(CURL_OPTIONS) --silent -o "$(DL_DIR)/$(2).md5" "$(3)" && \ From 29005473d428483af7cbf9620d38a5019a9b6fe4 Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Fri, 17 Mar 2017 23:31:53 +0100 Subject: [PATCH 201/624] LP-491 gcs: remove dead code --- ground/gcs/src/libs/utils/fancylineedit.cpp | 316 ----- ground/gcs/src/libs/utils/fancylineedit.h | 105 -- ground/gcs/src/libs/utils/fancymainwindow.cpp | 337 ------ ground/gcs/src/libs/utils/fancymainwindow.h | 102 -- ground/gcs/src/libs/utils/utils.pro | 4 - ground/gcs/src/plugins/config/config.pro | 2 - .../gcs/src/plugins/config/fancytabwidget.cpp | 502 -------- .../gcs/src/plugins/config/fancytabwidget.h | 179 --- .../gcs/src/plugins/coreplugin/coreplugin.pro | 17 +- .../src/plugins/coreplugin/fancyactionbar.cpp | 182 --- .../src/plugins/coreplugin/fancyactionbar.h | 72 -- .../src/plugins/coreplugin/fancyactionbar.qrc | 5 - .../src/plugins/coreplugin/fancytabwidget.cpp | 547 --------- .../src/plugins/coreplugin/fancytabwidget.h | 208 ---- .../coreplugin/images/fancytoolbutton.svg | 539 --------- .../gcs/src/plugins/coreplugin/mainwindow.cpp | 1 - .../gcs/src/plugins/coreplugin/mainwindow.h | 2 - .../src/plugins/coreplugin/manhattanstyle.cpp | 1038 ----------------- .../src/plugins/coreplugin/manhattanstyle.h | 80 -- .../src/plugins/coreplugin/modemanager.cpp | 2 - .../gcs/src/plugins/coreplugin/modemanager.h | 2 - .../gcs/src/plugins/coreplugin/rightpane.cpp | 246 ---- ground/gcs/src/plugins/coreplugin/rightpane.h | 114 -- ground/gcs/src/plugins/coreplugin/sidebar.cpp | 392 ------- ground/gcs/src/plugins/coreplugin/sidebar.h | 178 --- .../src/plugins/coreplugin/styleanimator.cpp | 158 --- .../src/plugins/coreplugin/styleanimator.h | 127 -- .../coreplugin/tabpositionindicator.cpp | 52 - .../plugins/coreplugin/tabpositionindicator.h | 54 - 29 files changed, 1 insertion(+), 5562 deletions(-) delete mode 100644 ground/gcs/src/libs/utils/fancylineedit.cpp delete mode 100644 ground/gcs/src/libs/utils/fancylineedit.h delete mode 100644 ground/gcs/src/libs/utils/fancymainwindow.cpp delete mode 100644 ground/gcs/src/libs/utils/fancymainwindow.h delete mode 100644 ground/gcs/src/plugins/config/fancytabwidget.cpp delete mode 100644 ground/gcs/src/plugins/config/fancytabwidget.h delete mode 100644 ground/gcs/src/plugins/coreplugin/fancyactionbar.cpp delete mode 100644 ground/gcs/src/plugins/coreplugin/fancyactionbar.h delete mode 100644 ground/gcs/src/plugins/coreplugin/fancyactionbar.qrc delete mode 100644 ground/gcs/src/plugins/coreplugin/fancytabwidget.cpp delete mode 100644 ground/gcs/src/plugins/coreplugin/fancytabwidget.h delete mode 100644 ground/gcs/src/plugins/coreplugin/images/fancytoolbutton.svg delete mode 100644 ground/gcs/src/plugins/coreplugin/manhattanstyle.cpp delete mode 100644 ground/gcs/src/plugins/coreplugin/manhattanstyle.h delete mode 100644 ground/gcs/src/plugins/coreplugin/rightpane.cpp delete mode 100644 ground/gcs/src/plugins/coreplugin/rightpane.h delete mode 100644 ground/gcs/src/plugins/coreplugin/sidebar.cpp delete mode 100644 ground/gcs/src/plugins/coreplugin/sidebar.h delete mode 100644 ground/gcs/src/plugins/coreplugin/styleanimator.cpp delete mode 100644 ground/gcs/src/plugins/coreplugin/styleanimator.h delete mode 100644 ground/gcs/src/plugins/coreplugin/tabpositionindicator.cpp delete mode 100644 ground/gcs/src/plugins/coreplugin/tabpositionindicator.h diff --git a/ground/gcs/src/libs/utils/fancylineedit.cpp b/ground/gcs/src/libs/utils/fancylineedit.cpp deleted file mode 100644 index 9e552e2627..0000000000 --- a/ground/gcs/src/libs/utils/fancylineedit.cpp +++ /dev/null @@ -1,316 +0,0 @@ -/** - ****************************************************************************** - * - * @file fancylineedit.cpp - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @brief - * @see The GNU Public License (GPL) Version 3 - * @defgroup - * @{ - * - *****************************************************************************/ -/* - * 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 "fancylineedit.h" - -#include -#include -#include -#include -#include -#include -#include - -enum { margin = 6 }; - -namespace Utils { -static inline QString sideToStyleSheetString(FancyLineEdit::Side side) -{ - return side == FancyLineEdit::Left ? QLatin1String("left") : QLatin1String("right"); -} - -// Format style sheet for the label containing the pixmap. It has a margin on -// the outer side of the whole FancyLineEdit. -static QString labelStyleSheet(FancyLineEdit::Side side) -{ - QString rc = QLatin1String("QLabel { margin-"); - - rc += sideToStyleSheetString(side); - rc += QLatin1String(": "); - rc += QString::number(margin); - rc += QLatin1Char('}'); - return rc; -} - -// --------- FancyLineEditPrivate as QObject with label -// event filter - -class FancyLineEditPrivate : public QObject { -public: - explicit FancyLineEditPrivate(QLineEdit *parent); - - virtual bool eventFilter(QObject *obj, QEvent *event); - - const QString m_leftLabelStyleSheet; - const QString m_rightLabelStyleSheet; - - QLineEdit *m_lineEdit; - QPixmap m_pixmap; - QMenu *m_menu; - QLabel *m_menuLabel; - FancyLineEdit::Side m_side; - bool m_useLayoutDirection; - bool m_menuTabFocusTrigger; - QString m_hintText; - bool m_showingHintText; -}; - - -FancyLineEditPrivate::FancyLineEditPrivate(QLineEdit *parent) : - QObject(parent), - m_leftLabelStyleSheet(labelStyleSheet(FancyLineEdit::Left)), - m_rightLabelStyleSheet(labelStyleSheet(FancyLineEdit::Right)), - m_lineEdit(parent), - m_menu(0), - m_menuLabel(0), - m_side(FancyLineEdit::Left), - m_useLayoutDirection(false), - m_menuTabFocusTrigger(false), - m_showingHintText(false) -{} - -bool FancyLineEditPrivate::eventFilter(QObject *obj, QEvent *event) -{ - if (!m_menu || obj != m_menuLabel) { - return QObject::eventFilter(obj, event); - } - - switch (event->type()) { - case QEvent::MouseButtonPress: - { - const QMouseEvent *me = static_cast(event); - m_menu->exec(me->globalPos()); - return true; - } - case QEvent::FocusIn: - if (m_menuTabFocusTrigger) { - m_lineEdit->setFocus(); - m_menu->exec(m_menuLabel->mapToGlobal(m_menuLabel->rect().center())); - return true; - } - default: - break; - } - return QObject::eventFilter(obj, event); -} - -// --------- FancyLineEdit -FancyLineEdit::FancyLineEdit(QWidget *parent) : - QLineEdit(parent), - m_d(new FancyLineEditPrivate(this)) -{ - m_d->m_menuLabel = new QLabel(this); - m_d->m_menuLabel->installEventFilter(m_d); - updateMenuLabel(); - showHintText(); -} - -FancyLineEdit::~FancyLineEdit() -{} - -// Position the menu label left or right according to size. -// Called when switching side and from resizeEvent. -void FancyLineEdit::positionMenuLabel() -{ - switch (side()) { - case Left: - m_d->m_menuLabel->setGeometry(0, 0, m_d->m_pixmap.width() + margin, height()); - break; - case Right: - m_d->m_menuLabel->setGeometry(width() - m_d->m_pixmap.width() - margin, 0, - m_d->m_pixmap.width() + margin, height()); - break; - } -} - -void FancyLineEdit::updateStyleSheet(Side side) -{ - // Udate the LineEdit style sheet. Make room for the label on the - // respective side and set color according to whether we are showing the - // hint text - QString sheet = QLatin1String("QLineEdit{ padding-"); - - sheet += sideToStyleSheetString(side); - sheet += QLatin1String(": "); - sheet += QString::number(m_d->m_pixmap.width() + margin); - sheet += QLatin1Char(';'); - if (m_d->m_showingHintText) { - sheet += QLatin1String(" color: #BBBBBB;"); - } - sheet += QLatin1Char('}'); - setStyleSheet(sheet); -} - -void FancyLineEdit::updateMenuLabel() -{ - m_d->m_menuLabel->setPixmap(m_d->m_pixmap); - const Side s = side(); - switch (s) { - case Left: - m_d->m_menuLabel->setAlignment(Qt::AlignVCenter | Qt::AlignLeft); - m_d->m_menuLabel->setStyleSheet(m_d->m_leftLabelStyleSheet); - break; - case Right: - m_d->m_menuLabel->setAlignment(Qt::AlignVCenter | Qt::AlignRight); - m_d->m_menuLabel->setStyleSheet(m_d->m_rightLabelStyleSheet); - break; - } - updateStyleSheet(s); - positionMenuLabel(); -} - -void FancyLineEdit::setSide(Side side) -{ - m_d->m_side = side; - updateMenuLabel(); -} - -FancyLineEdit::Side FancyLineEdit::side() const -{ - if (m_d->m_useLayoutDirection) { - return qApp->layoutDirection() == Qt::LeftToRight ? Left : Right; - } - return m_d->m_side; -} - -void FancyLineEdit::resizeEvent(QResizeEvent *) -{ - positionMenuLabel(); -} - -void FancyLineEdit::setPixmap(const QPixmap &pixmap) -{ - m_d->m_pixmap = pixmap; - updateMenuLabel(); -} - -QPixmap FancyLineEdit::pixmap() const -{ - return m_d->m_pixmap; -} - -void FancyLineEdit::setMenu(QMenu *menu) -{ - m_d->m_menu = menu; -} - -QMenu *FancyLineEdit::menu() const -{ - return m_d->m_menu; -} - -bool FancyLineEdit::useLayoutDirection() const -{ - return m_d->m_useLayoutDirection; -} - -void FancyLineEdit::setUseLayoutDirection(bool v) -{ - m_d->m_useLayoutDirection = v; -} - -bool FancyLineEdit::isSideStored() const -{ - return !m_d->m_useLayoutDirection; -} - -bool FancyLineEdit::hasMenuTabFocusTrigger() const -{ - return m_d->m_menuTabFocusTrigger; -} - -void FancyLineEdit::setMenuTabFocusTrigger(bool v) -{ - if (m_d->m_menuTabFocusTrigger == v) { - return; - } - - m_d->m_menuTabFocusTrigger = v; - m_d->m_menuLabel->setFocusPolicy(v ? Qt::TabFocus : Qt::NoFocus); -} - -QString FancyLineEdit::hintText() const -{ - return m_d->m_hintText; -} - -void FancyLineEdit::setHintText(const QString &ht) -{ - // Updating magic to make the property work in Designer. - if (ht == m_d->m_hintText) { - return; - } - hideHintText(); - m_d->m_hintText = ht; - if (!hasFocus() && !ht.isEmpty()) { - showHintText(); - } -} - -void FancyLineEdit::showHintText() -{ - if (!m_d->m_showingHintText && text().isEmpty() && !m_d->m_hintText.isEmpty()) { - m_d->m_showingHintText = true; - setText(m_d->m_hintText); - updateStyleSheet(side()); - } -} - -void FancyLineEdit::hideHintText() -{ - if (m_d->m_showingHintText && !m_d->m_hintText.isEmpty()) { - m_d->m_showingHintText = false; - setText(QString()); - updateStyleSheet(side()); - } -} - -void FancyLineEdit::focusInEvent(QFocusEvent *e) -{ - hideHintText(); - QLineEdit::focusInEvent(e); -} - -void FancyLineEdit::focusOutEvent(QFocusEvent *e) -{ - // Focus out: Switch to displaying the hint text unless - // there is user input - showHintText(); - QLineEdit::focusOutEvent(e); -} - -bool FancyLineEdit::isShowingHintText() const -{ - return m_d->m_showingHintText; -} - -QString FancyLineEdit::typedText() const -{ - return m_d->m_showingHintText ? QString() : text(); -} -} // namespace Utils diff --git a/ground/gcs/src/libs/utils/fancylineedit.h b/ground/gcs/src/libs/utils/fancylineedit.h deleted file mode 100644 index 5ff5f33894..0000000000 --- a/ground/gcs/src/libs/utils/fancylineedit.h +++ /dev/null @@ -1,105 +0,0 @@ -/** - ****************************************************************************** - * - * @file fancylineedit.h - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @brief - * @see The GNU Public License (GPL) Version 3 - * @defgroup - * @{ - * - *****************************************************************************/ -/* - * 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 FANCYLINEEDIT_H -#define FANCYLINEEDIT_H - -#include "utils_global.h" - -#include - -namespace Utils { -class FancyLineEditPrivate; - -/* A line edit with an embedded pixmap on one side that is connected to - * a menu. Additionally, it can display a grayed hintText (like "Type Here to") - * when not focussed and empty. When connecting to the changed signals and - * querying text, one has to be aware that the text is set to that hint - * text if isShowingHintText() returns true (that is, does not contain - * valid user input). - */ -class QTCREATOR_UTILS_EXPORT FancyLineEdit : public QLineEdit { - Q_DISABLE_COPY(FancyLineEdit) - Q_OBJECT Q_ENUMS(Side) - Q_PROPERTY(QPixmap pixmap READ pixmap WRITE setPixmap DESIGNABLE true) - Q_PROPERTY(Side side READ side WRITE setSide DESIGNABLE isSideStored STORED isSideStored) - Q_PROPERTY(bool useLayoutDirection READ useLayoutDirection WRITE setUseLayoutDirection DESIGNABLE true) - Q_PROPERTY(bool menuTabFocusTrigger READ hasMenuTabFocusTrigger WRITE setMenuTabFocusTrigger DESIGNABLE true) - Q_PROPERTY(QString hintText READ hintText WRITE setHintText DESIGNABLE true) - -public: - enum Side { Left, Right }; - - explicit FancyLineEdit(QWidget *parent = 0); - ~FancyLineEdit(); - - QPixmap pixmap() const; - - void setMenu(QMenu *menu); - QMenu *menu() const; - - void setSide(Side side); - Side side() const; - - bool useLayoutDirection() const; - void setUseLayoutDirection(bool v); - - // Set whether tabbing in will trigger the menu. - bool hasMenuTabFocusTrigger() const; - void setMenuTabFocusTrigger(bool v); - - // Hint text that is displayed when no focus is set. - QString hintText() const; - - bool isShowingHintText() const; - - // Convenience for accessing the text that returns "" in case of isShowingHintText(). - QString typedText() const; - -public slots: - void setPixmap(const QPixmap &pixmap); - void setHintText(const QString &ht); - void showHintText(); - void hideHintText(); - -protected: - virtual void resizeEvent(QResizeEvent *e); - virtual void focusInEvent(QFocusEvent *e); - virtual void focusOutEvent(QFocusEvent *e); - -private: - bool isSideStored() const; - void updateMenuLabel(); - void positionMenuLabel(); - void updateStyleSheet(Side side); - - FancyLineEditPrivate *m_d; -}; -} // namespace Utils - -#endif // FANCYLINEEDIT_H diff --git a/ground/gcs/src/libs/utils/fancymainwindow.cpp b/ground/gcs/src/libs/utils/fancymainwindow.cpp deleted file mode 100644 index 6dd3c6fe56..0000000000 --- a/ground/gcs/src/libs/utils/fancymainwindow.cpp +++ /dev/null @@ -1,337 +0,0 @@ -/** - ****************************************************************************** - * - * @file fancymainwindow.cpp - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @brief - * @see The GNU Public License (GPL) Version 3 - * @defgroup - * @{ - * - *****************************************************************************/ -/* - * 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 "fancymainwindow.h" - -#include "qtcassert.h" - -#include -#include -#include -#include - -static const char lockedKeyC[] = "Locked"; -static const char stateKeyC[] = "State"; -static const int settingsVersion = 2; -static const char dockWidgetActiveState[] = "DockWidgetActiveState"; - -namespace Utils { -/*! \class Utils::FancyMainWindow - - \brief MainWindow with dock widgets and additional "lock" functionality - (locking the dock widgets in place) and "reset layout" functionality. - - The dock actions and the additional actions should be accessible - in a Window-menu. - */ - -struct FancyMainWindowPrivate { - FancyMainWindowPrivate(); - - bool m_locked; - bool m_handleDockVisibilityChanges; - - QAction m_menuSeparator1; - QAction m_toggleLockedAction; - QAction m_menuSeparator2; - QAction m_resetLayoutAction; - QDockWidget *m_toolBarDockWidget; -}; - -FancyMainWindowPrivate::FancyMainWindowPrivate() : - m_locked(true), - m_handleDockVisibilityChanges(true), - m_menuSeparator1(0), - m_toggleLockedAction(FancyMainWindow::tr("Locked"), 0), - m_menuSeparator2(0), - m_resetLayoutAction(FancyMainWindow::tr("Reset to Default Layout"), 0), - m_toolBarDockWidget(0) -{ - m_toggleLockedAction.setCheckable(true); - m_toggleLockedAction.setChecked(m_locked); - m_menuSeparator1.setSeparator(true); - m_menuSeparator2.setSeparator(true); -} - -FancyMainWindow::FancyMainWindow(QWidget *parent) : - QMainWindow(parent), d(new FancyMainWindowPrivate) -{ - connect(&d->m_toggleLockedAction, SIGNAL(toggled(bool)), - this, SLOT(setLocked(bool))); - connect(&d->m_resetLayoutAction, SIGNAL(triggered()), - this, SIGNAL(resetLayout())); -} - -FancyMainWindow::~FancyMainWindow() -{ - delete d; -} - -QDockWidget *FancyMainWindow::addDockForWidget(QWidget *widget) -{ - QDockWidget *dockWidget = new QDockWidget(widget->windowTitle(), this); - - dockWidget->setWidget(widget); - // Set an object name to be used in settings, derive from widget name - const QString objectName = widget->objectName(); - if (objectName.isEmpty()) { - dockWidget->setObjectName(QLatin1String("dockWidget") + QString::number(dockWidgets().size() + 1)); - } else { - dockWidget->setObjectName(objectName + QLatin1String("DockWidget")); - } - connect(dockWidget->toggleViewAction(), SIGNAL(triggered()), - this, SLOT(onDockActionTriggered()), Qt::QueuedConnection); - connect(dockWidget, SIGNAL(visibilityChanged(bool)), - this, SLOT(onDockVisibilityChange(bool))); - connect(dockWidget, SIGNAL(topLevelChanged(bool)), - this, SLOT(onTopLevelChanged())); - dockWidget->setProperty(dockWidgetActiveState, true); - updateDockWidget(dockWidget); - return dockWidget; -} - -void FancyMainWindow::updateDockWidget(QDockWidget *dockWidget) -{ - const QDockWidget::DockWidgetFeatures features = - (d->m_locked) ? QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetFloatable - : QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetFloatable; - - if (dockWidget->property("managed_dockwidget").isNull()) { // for the debugger tool bar - QWidget *titleBarWidget = dockWidget->titleBarWidget(); - if (d->m_locked && !titleBarWidget && !dockWidget->isFloating()) { - titleBarWidget = new QWidget(dockWidget); - } else if ((!d->m_locked || dockWidget->isFloating()) && titleBarWidget) { - delete titleBarWidget; - titleBarWidget = 0; - } - dockWidget->setTitleBarWidget(titleBarWidget); - } - dockWidget->setFeatures(features); -} - -void FancyMainWindow::onDockActionTriggered() -{ - QDockWidget *dw = qobject_cast(sender()->parent()); - - if (dw) { - if (dw->isVisible()) { - dw->raise(); - } - } -} - -void FancyMainWindow::onDockVisibilityChange(bool visible) -{ - if (d->m_handleDockVisibilityChanges) { - sender()->setProperty(dockWidgetActiveState, visible); - } -} - -void FancyMainWindow::onTopLevelChanged() -{ - updateDockWidget(qobject_cast(sender())); -} - -void FancyMainWindow::setTrackingEnabled(bool enabled) -{ - if (enabled) { - d->m_handleDockVisibilityChanges = true; - foreach(QDockWidget * dockWidget, dockWidgets()) - dockWidget->setProperty(dockWidgetActiveState, dockWidget->isVisible()); - } else { - d->m_handleDockVisibilityChanges = false; - } -} - -void FancyMainWindow::setLocked(bool locked) -{ - d->m_locked = locked; - foreach(QDockWidget * dockWidget, dockWidgets()) { - updateDockWidget(dockWidget); - } -} - -void FancyMainWindow::hideEvent(QHideEvent *event) -{ - Q_UNUSED(event) - handleVisibilityChanged(false); -} - -void FancyMainWindow::showEvent(QShowEvent *event) -{ - Q_UNUSED(event) - handleVisibilityChanged(true); -} - -void FancyMainWindow::contextMenuEvent(QContextMenuEvent *event) -{ - QMenu *menu = createPopupMenu(); - - menu->exec(event->globalPos()); - delete menu; -} - -void FancyMainWindow::handleVisibilityChanged(bool visible) -{ - d->m_handleDockVisibilityChanges = false; - foreach(QDockWidget * dockWidget, dockWidgets()) { - if (dockWidget->isFloating()) { - dockWidget->setVisible(visible - && dockWidget->property(dockWidgetActiveState).toBool()); - } - } - if (visible) { - d->m_handleDockVisibilityChanges = true; - } -} - -void FancyMainWindow::saveSettings(QSettings *settings) const -{ - QHash hash = saveSettings(); - QHashIterator it(hash); - while (it.hasNext()) { - it.next(); - settings->setValue(it.key(), it.value()); - } -} - -void FancyMainWindow::restoreSettings(const QSettings *settings) -{ - QHash hash; - foreach(const QString &key, settings->childKeys()) { - hash.insert(key, settings->value(key)); - } - restoreSettings(hash); -} - -QHash FancyMainWindow::saveSettings() const -{ - QHash settings; - settings.insert(QLatin1String(stateKeyC), saveState(settingsVersion)); - settings.insert(QLatin1String(lockedKeyC), d->m_locked); - foreach(QDockWidget * dockWidget, dockWidgets()) { - settings.insert(dockWidget->objectName(), - dockWidget->property(dockWidgetActiveState)); - } - return settings; -} - -void FancyMainWindow::restoreSettings(const QHash &settings) -{ - QByteArray ba = settings.value(QLatin1String(stateKeyC), QByteArray()).toByteArray(); - - if (!ba.isEmpty()) { - restoreState(ba, settingsVersion); - } - d->m_locked = settings.value(QLatin1String("Locked"), true).toBool(); - d->m_toggleLockedAction.setChecked(d->m_locked); - foreach(QDockWidget * widget, dockWidgets()) { - widget->setProperty(dockWidgetActiveState, - settings.value(widget->objectName(), false)); - } -} - -QList FancyMainWindow::dockWidgets() const -{ - return findChildren(); -} - -bool FancyMainWindow::isLocked() const -{ - return d->m_locked; -} - -static bool actionLessThan(const QAction *action1, const QAction *action2) -{ - QTC_ASSERT(action1, return true); - QTC_ASSERT(action2, return false); - return action1->text().toLower() < action2->text().toLower(); -} - -QMenu *FancyMainWindow::createPopupMenu() -{ - QList actions; - QList dockwidgets = findChildren(); - for (int i = 0; i < dockwidgets.size(); ++i) { - QDockWidget *dockWidget = dockwidgets.at(i); - if (dockWidget->property("managed_dockwidget").isNull() - && dockWidget->parentWidget() == this) { - actions.append(dockwidgets.at(i)->toggleViewAction()); - } - } - qSort(actions.begin(), actions.end(), actionLessThan); - QMenu *menu = new QMenu(this); - foreach(QAction * action, actions) - menu->addAction(action); - menu->addAction(&d->m_menuSeparator1); - menu->addAction(&d->m_toggleLockedAction); - menu->addAction(&d->m_menuSeparator2); - menu->addAction(&d->m_resetLayoutAction); - return menu; -} - -QAction *FancyMainWindow::menuSeparator1() const -{ - return &d->m_menuSeparator1; -} - -QAction *FancyMainWindow::toggleLockedAction() const -{ - return &d->m_toggleLockedAction; -} - -QAction *FancyMainWindow::menuSeparator2() const -{ - return &d->m_menuSeparator2; -} - -QAction *FancyMainWindow::resetLayoutAction() const -{ - return &d->m_resetLayoutAction; -} - -void FancyMainWindow::setDockActionsVisible(bool v) -{ - foreach(const QDockWidget * dockWidget, dockWidgets()) - dockWidget->toggleViewAction()->setVisible(v); - d->m_toggleLockedAction.setVisible(v); - d->m_menuSeparator1.setVisible(v); - d->m_menuSeparator2.setVisible(v); - d->m_resetLayoutAction.setVisible(v); -} - -QDockWidget *FancyMainWindow::toolBarDockWidget() const -{ - return d->m_toolBarDockWidget; -} - -void FancyMainWindow::setToolBarDockWidget(QDockWidget *dock) -{ - d->m_toolBarDockWidget = dock; -} -} // namespace Utils diff --git a/ground/gcs/src/libs/utils/fancymainwindow.h b/ground/gcs/src/libs/utils/fancymainwindow.h deleted file mode 100644 index 23c4b00c68..0000000000 --- a/ground/gcs/src/libs/utils/fancymainwindow.h +++ /dev/null @@ -1,102 +0,0 @@ -/** - ****************************************************************************** - * - * @file fancymainwindow.h - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @brief - * @see The GNU Public License (GPL) Version 3 - * @defgroup - * @{ - * - *****************************************************************************/ -/* - * 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 FANCYMAINWINDOW_H -#define FANCYMAINWINDOW_H - -#include "utils_global.h" - -#include - -QT_BEGIN_NAMESPACE -class QSettings; -QT_END_NAMESPACE - -namespace Utils { -struct FancyMainWindowPrivate; - -class QTCREATOR_UTILS_EXPORT FancyMainWindow : public QMainWindow { - Q_OBJECT - -public: - explicit FancyMainWindow(QWidget *parent = 0); - virtual ~FancyMainWindow(); - - /* The widget passed in should have an objectname set - * which will then be used as key for QSettings. */ - QDockWidget *addDockForWidget(QWidget *widget); - QList dockWidgets() const; - - void setTrackingEnabled(bool enabled); - bool isLocked() const; - - void saveSettings(QSettings *settings) const; - void restoreSettings(const QSettings *settings); - QHash saveSettings() const; - void restoreSettings(const QHash &settings); - - // Additional context menu actions - QAction *menuSeparator1() const; - QAction *toggleLockedAction() const; - QAction *menuSeparator2() const; - QAction *resetLayoutAction() const; - - // Overwritten to add locked/reset. - virtual QMenu *createPopupMenu(); - - - QDockWidget *toolBarDockWidget() const; - void setToolBarDockWidget(QDockWidget *dock); - -signals: - // Emitted by resetLayoutAction(). Connect to a slot - // restoring the default layout. - void resetLayout(); - -public slots: - void setLocked(bool locked); - void setDockActionsVisible(bool v); - -protected: - void hideEvent(QHideEvent *event); - void showEvent(QShowEvent *event); - void contextMenuEvent(QContextMenuEvent *event); -private slots: - void onDockActionTriggered(); - void onDockVisibilityChange(bool); - void onTopLevelChanged(); - -private: - void updateDockWidget(QDockWidget *dockWidget); - void handleVisibilityChanged(bool visible); - - FancyMainWindowPrivate *d; -}; -} // namespace Utils - -#endif // FANCYMAINWINDOW_H diff --git a/ground/gcs/src/libs/utils/utils.pro b/ground/gcs/src/libs/utils/utils.pro index 4e291df1b2..3654582e6d 100644 --- a/ground/gcs/src/libs/utils/utils.pro +++ b/ground/gcs/src/libs/utils/utils.pro @@ -27,7 +27,6 @@ SOURCES += \ newclasswidget.cpp \ classnamevalidatinglineedit.cpp \ linecolumnlabel.cpp \ - fancylineedit.cpp \ qtcolorbutton.cpp \ savedaction.cpp \ submiteditorwidget.cpp \ @@ -42,7 +41,6 @@ SOURCES += \ stylehelper.cpp \ welcomemodetreewidget.cpp \ iwelcomepage.cpp \ - fancymainwindow.cpp \ detailsbutton.cpp \ detailswidget.cpp \ coordinateconversions.cpp \ @@ -89,7 +87,6 @@ HEADERS += \ newclasswidget.h \ classnamevalidatinglineedit.h \ linecolumnlabel.h \ - fancylineedit.h \ qtcolorbutton.h \ savedaction.h \ submiteditorwidget.h \ @@ -106,7 +103,6 @@ HEADERS += \ stylehelper.h \ welcomemodetreewidget.h \ iwelcomepage.h \ - fancymainwindow.h \ detailsbutton.h \ detailswidget.h \ coordinateconversions.h \ diff --git a/ground/gcs/src/plugins/config/config.pro b/ground/gcs/src/plugins/config/config.pro index e74720999c..5865e0da4a 100644 --- a/ground/gcs/src/plugins/config/config.pro +++ b/ground/gcs/src/plugins/config/config.pro @@ -19,7 +19,6 @@ HEADERS += \ configgadgetwidget.h \ configgadgetfactory.h \ configgadget.h \ - fancytabwidget.h \ configinputwidget.h \ configoutputwidget.h \ configvehicletypewidget.h \ @@ -68,7 +67,6 @@ SOURCES += \ configgadgetwidget.cpp \ configgadgetfactory.cpp \ configgadget.cpp \ - fancytabwidget.cpp \ configinputwidget.cpp \ configoutputwidget.cpp \ configvehicletypewidget.cpp \ diff --git a/ground/gcs/src/plugins/config/fancytabwidget.cpp b/ground/gcs/src/plugins/config/fancytabwidget.cpp deleted file mode 100644 index a34d176e2b..0000000000 --- a/ground/gcs/src/plugins/config/fancytabwidget.cpp +++ /dev/null @@ -1,502 +0,0 @@ -/** - ****************************************************************************** - * - * @file fancytabwidget.cpp - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @addtogroup GCSPlugins GCS Plugins - * @{ - * @addtogroup CorePlugin Core Plugin - * @{ - * @brief The Core GCS plugin - *****************************************************************************/ -/* - * 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 "fancytabwidget.h" -#include -#include - -#include -#include -#include -#include -#include -#include -// #include -#include -#include -#include -#include -#include -#include - -const int FancyTabBar::m_rounding = 22; -const int FancyTabBar::m_textPadding = 4; - -FancyTabBar::FancyTabBar(QWidget *parent, bool isVertical) - : QWidget(parent) -{ - verticalTabs = isVertical; - setIconSize(16); - m_hoverIndex = -1; - m_currentIndex = 0; - if (isVertical) { - setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); - } else { - setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); - } - // setStyle(new QWindowsStyle); - setMinimumWidth(qMax(2 * m_rounding, 40)); - setAttribute(Qt::WA_Hover, true); - setFocusPolicy(Qt::NoFocus); - m_hoverControl.setFrameRange(0, 20); - m_hoverControl.setDuration(130); - m_hoverControl.setCurveShape(QTimeLine::EaseInCurve); - connect(&m_hoverControl, SIGNAL(frameChanged(int)), this, SLOT(updateHover())); - setMouseTracking(true); // Needed for hover events -} - -FancyTabBar::~FancyTabBar() -{ - delete style(); -} - -QSize FancyTabBar::tabSizeHint(bool minimum) const -{ - QFont boldFont(font()); - - boldFont.setPointSizeF(Utils::StyleHelper::sidebarFontSize()); - boldFont.setBold(true); - QFontMetrics fm(boldFont); - int spacing = 6; - int width = 90 + spacing + 2; - - int iconHeight = minimum ? 0 : iconSize; - return QSize(width, iconHeight + spacing + fm.height()); -} - -void FancyTabBar::paintEvent(QPaintEvent *event) -{ - Q_UNUSED(event) - QPainter p(this); - - for (int i = 0; i < count(); ++i) { - if (i != currentIndex()) { - paintTab(&p, i); - } - } - - // paint active tab last, since it overlaps the neighbors - paintTab(&p, currentIndex()); -} - -// Handle hover events for mouse fade ins -void FancyTabBar::mouseMoveEvent(QMouseEvent *e) -{ - if (!m_hoverRect.contains(e->pos())) { - int newHover = -1; - for (int i = 0; i < count(); ++i) { - QRect area = tabRect(i); - if (area.contains(e->pos())) { - newHover = i; - break; - } - } - - m_hoverControl.stop(); - m_hoverIndex = newHover; - update(m_hoverRect); - m_hoverRect = QRect(); - - if (m_hoverIndex >= 0) { - m_hoverRect = tabRect(m_hoverIndex); - m_hoverControl.start(); - } - } -} - -bool FancyTabBar::event(QEvent *event) -{ - if (event->type() == QEvent::ToolTip) { - if (m_hoverIndex >= 0 && m_hoverIndex < m_tabs.count()) { - QString tt = tabToolTip(m_hoverIndex); - if (!tt.isEmpty()) { - QToolTip::showText(static_cast(event)->globalPos(), tt, this); - return true; - } - } - } - return QWidget::event(event); -} - -void FancyTabBar::updateHover() -{ - update(m_hoverRect); -} - -// Resets hover animation on mouse enter -void FancyTabBar::enterEvent(QEvent *e) -{ - Q_UNUSED(e) - m_hoverRect = QRect(); - m_hoverIndex = -1; -} - -// Resets hover animation on mouse enter -void FancyTabBar::leaveEvent(QEvent *e) -{ - Q_UNUSED(e) - if (m_hoverIndex >= 0) { - m_hoverIndex = -1; - update(m_hoverRect); - m_hoverRect = QRect(); - } -} - -void FancyTabBar::updateTabNameIcon(int index, const QIcon &icon, const QString &label) -{ - m_tabs[index].icon = icon; - m_tabs[index].text = label; -} - -QSize FancyTabBar::sizeHint() const -{ - QSize sh = tabSizeHint(); - - if (verticalTabs) { - return QSize(sh.width(), sh.height() * m_tabs.count()); - } - return QSize(sh.width() * m_tabs.count(), sh.height()); -} - -QSize FancyTabBar::minimumSizeHint() const -{ - QSize sh = tabSizeHint(true); - - if (verticalTabs) { - return QSize(sh.width(), sh.height() * m_tabs.count()); - } - return QSize(sh.width() * m_tabs.count(), sh.height()); -} - -QRect FancyTabBar::tabRect(int index) const -{ - QSize sh = tabSizeHint(); - - if (verticalTabs) { - if (sh.height() * m_tabs.count() > height()) { - sh.setHeight(height() / m_tabs.count()); - } - - return QRect(0, index * sh.height(), sh.width(), sh.height()); - } - - if (sh.width() * m_tabs.count() > width()) { - sh.setWidth(width() / m_tabs.count()); - } - - return QRect(index * sh.width(), 0, sh.width(), sh.height()); -} - -void FancyTabBar::mousePressEvent(QMouseEvent *e) -{ - e->accept(); - for (int i = 0; i < m_tabs.count(); ++i) { - if (tabRect(i).contains(e->pos())) { - setCurrentIndex(i); - break; - } - } -} - -void FancyTabBar::paintTab(QPainter *painter, int tabIndex) const -{ - painter->save(); - - QRect rect = tabRect(tabIndex); - - bool selected = (tabIndex == m_currentIndex); - bool hover = (tabIndex == m_hoverIndex); - -#ifdef Q_WS_MAC - hover = false; // Dont hover on Mac -#endif - - QColor background = QColor(0, 0, 0, 10); - QColor hoverColor; - - if (hover) { - hoverColor = QColor(255, 255, 255, m_hoverControl.currentFrame()); - } - - QColor light = QColor(255, 255, 255, 40); - QColor dark = QColor(0, 0, 0, 60); - - if (selected) { - QLinearGradient selectedGradient(rect.bottomRight(), QPoint(rect.center().x(), rect.top())); - selectedGradient.setColorAt(0, Qt::white); - selectedGradient.setColorAt(0.3, Qt::white); - selectedGradient.setColorAt(0.7, QColor(210, 210, 220)); // give a blue-ish color - - painter->fillRect(rect, selectedGradient); - painter->setPen(QColor(200, 200, 200)); - painter->drawLine(rect.topLeft(), rect.bottomLeft()); - painter->setPen(QColor(150, 160, 200)); - painter->drawLine(rect.topRight(), rect.bottomRight()); - } else { - painter->fillRect(rect, background); - if (hover) { - painter->fillRect(rect, hoverColor); - } - painter->setPen(QPen(light, 0)); - painter->drawLine(rect.topLeft(), rect.bottomLeft()); - painter->setPen(QPen(dark, 0)); - painter->drawLine(rect.topRight(), rect.bottomRight()); - } - - QString tabText(this->tabText(tabIndex)); - QRect tabTextRect(tabRect(tabIndex)); - QRect tabIconRect(tabTextRect); - QFont boldFont(painter->font()); - boldFont.setPointSizeF(Utils::StyleHelper::sidebarFontSize()); - boldFont.setBold(true); - painter->setFont(boldFont); - painter->setPen(selected ? Utils::StyleHelper::panelTextColor() : QColor(30, 30, 30, 80)); - int textFlags = Qt::AlignCenter | Qt::AlignBottom | Qt::ElideRight | Qt::TextWordWrap; - painter->drawText(tabTextRect, textFlags, tabText); - painter->setPen(selected ? QColor(60, 60, 60) : Utils::StyleHelper::panelTextColor()); - int textHeight = painter->fontMetrics().boundingRect(QRect(0, 0, width(), height()), Qt::TextWordWrap, tabText).height(); - tabIconRect.adjust(0, 4, 0, -textHeight); - int iconSize = qMin(tabIconRect.width(), tabIconRect.height()); - if (iconSize > 4) { - style()->drawItemPixmap(painter, tabIconRect, Qt::AlignCenter | Qt::AlignVCenter, - tabIcon(tabIndex).pixmap(tabIconRect.size())); - } - painter->translate(0, -1); - painter->drawText(tabTextRect, textFlags, tabText); - painter->restore(); -} - -void FancyTabBar::setCurrentIndex(int index) -{ - bool proceed = true; - emit aboutToChange(&proceed); - - if (!proceed) { - return; - } - m_currentIndex = index; - update(); - emit currentChanged(index); -} - -////// -// FancyColorButton -////// - -class FancyColorButton : public QWidget { -public: - FancyColorButton(QWidget *parent) - : m_parent(parent) - { - setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred); - } - - void mousePressEvent(QMouseEvent *ev) - { - if (ev->modifiers() & Qt::ShiftModifier) { - Utils::StyleHelper::setBaseColor(QColorDialog::getColor(Utils::StyleHelper::baseColor(), m_parent)); - } - } -private: - QWidget *m_parent; -}; - -////// -// FancyTabWidget -////// - -FancyTabWidget::FancyTabWidget(QWidget *parent, bool isVertical) - : QWidget(parent) -{ - m_tabBar = new FancyTabBar(this, isVertical); - m_selectionWidget = new QWidget(this); - QBoxLayout *selectionLayout; - if (isVertical) { - selectionLayout = new QVBoxLayout; - } else { - selectionLayout = new QHBoxLayout; - } - selectionLayout->setSpacing(0); - selectionLayout->setMargin(0); - - Utils::StyledBar *bar = new Utils::StyledBar; - QBoxLayout *layout; - if (isVertical) { - layout = new QHBoxLayout(bar); - } else { - layout = new QVBoxLayout(bar); - } - layout->setMargin(0); - layout->setSpacing(0); - layout->addWidget(new FancyColorButton(this)); - selectionLayout->addWidget(bar); - - selectionLayout->addWidget(m_tabBar, 1); - m_selectionWidget->setLayout(selectionLayout); - if (isVertical) { - m_selectionWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding); - } else { - m_selectionWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); - } - - m_cornerWidgetContainer = new QWidget(this); - if (isVertical) { - m_cornerWidgetContainer->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred); - } else { - m_cornerWidgetContainer->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum); - } - m_cornerWidgetContainer->setAutoFillBackground(false); - - QBoxLayout *cornerWidgetLayout; - if (isVertical) { - cornerWidgetLayout = new QVBoxLayout; - } else { - cornerWidgetLayout = new QHBoxLayout; - } - cornerWidgetLayout->setSpacing(0); - cornerWidgetLayout->setMargin(0); - cornerWidgetLayout->addStretch(); - m_cornerWidgetContainer->setLayout(cornerWidgetLayout); - - selectionLayout->addWidget(m_cornerWidgetContainer, 0); - - m_modesStack = new QStackedLayout; - m_statusBar = new QStatusBar; - m_statusBar->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed); - - QVBoxLayout *vlayout = new QVBoxLayout; - vlayout->setMargin(0); - vlayout->setSpacing(0); - vlayout->addLayout(m_modesStack); - if (!isVertical) { - vlayout->addWidget(m_selectionWidget); - } -// vlayout->addWidget(m_statusBar); //status bar is not used for now - - QHBoxLayout *mainLayout = new QHBoxLayout; - mainLayout->setMargin(0); - mainLayout->setSpacing(1); - if (isVertical) { - mainLayout->addWidget(m_selectionWidget); - } - mainLayout->addLayout(vlayout); - setLayout(mainLayout); - - connect(m_tabBar, SIGNAL(currentChanged(int)), this, SLOT(showWidget(int))); -} - -void FancyTabWidget::insertTab(int index, QWidget *tab, const QIcon &icon, const QString &label) -{ - m_modesStack->insertWidget(index, tab); - m_tabBar->insertTab(index, icon, label); -} - -void FancyTabWidget::removeTab(int index) -{ - m_modesStack->removeWidget(m_modesStack->widget(index)); - m_tabBar->removeTab(index); -} - -void FancyTabWidget::updateTabNameIcon(int index, const QIcon &icon, const QString &label) -{ - m_tabBar->updateTabNameIcon(index, icon, label); - m_tabBar->repaint(); -} - - -void FancyTabWidget::setBackgroundBrush(const QBrush &brush) -{ - QPalette pal = m_tabBar->palette(); - - pal.setBrush(QPalette::Mid, brush); - m_tabBar->setPalette(pal); - pal = m_cornerWidgetContainer->palette(); - pal.setBrush(QPalette::Mid, brush); - m_cornerWidgetContainer->setPalette(pal); -} - -void FancyTabWidget::paintEvent(QPaintEvent *event) -{ - Q_UNUSED(event) - QPainter p(this); - - QRect rect = m_selectionWidget->geometry().adjusted(0, 0, 1, 0); - rect = style()->visualRect(layoutDirection(), geometry(), rect); - Utils::StyleHelper::verticalGradient(&p, rect, rect); - p.setPen(Utils::StyleHelper::borderColor()); - p.drawLine(rect.topLeft(), rect.topRight()); -} - -void FancyTabWidget::insertCornerWidget(int pos, QWidget *widget) -{ - QHBoxLayout *layout = static_cast(m_cornerWidgetContainer->layout()); - - layout->insertWidget(pos, widget); -} - -int FancyTabWidget::cornerWidgetCount() const -{ - return m_cornerWidgetContainer->layout()->count(); -} - -void FancyTabWidget::addCornerWidget(QWidget *widget) -{ - m_cornerWidgetContainer->layout()->addWidget(widget); -} - -int FancyTabWidget::currentIndex() const -{ - return m_tabBar->currentIndex(); -} - -QStatusBar *FancyTabWidget::statusBar() const -{ - return m_statusBar; -} - -void FancyTabWidget::setCurrentIndex(int index) -{ - m_tabBar->setCurrentIndex(index); -} - -void FancyTabWidget::showWidget(int index) -{ - emit currentAboutToShow(index); - - m_modesStack->setCurrentIndex(index); - emit currentChanged(index); -} - -void FancyTabWidget::setTabToolTip(int index, const QString &toolTip) -{ - m_tabBar->setTabToolTip(index, toolTip); -} -QWidget *FancyTabWidget::currentWidget() -{ - return m_modesStack->currentWidget(); -} diff --git a/ground/gcs/src/plugins/config/fancytabwidget.h b/ground/gcs/src/plugins/config/fancytabwidget.h deleted file mode 100644 index a9604169f1..0000000000 --- a/ground/gcs/src/plugins/config/fancytabwidget.h +++ /dev/null @@ -1,179 +0,0 @@ -/** - ****************************************************************************** - * - * @file fancytabwidget.h - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @addtogroup GCSPlugins GCS Plugins - * @{ - * @addtogroup CorePlugin Core Plugin - * @{ - * @brief The Core GCS plugin - *****************************************************************************/ -/* - * 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 FANCYTABWIDGET_H -#define FANCYTABWIDGET_H - -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE -class QPainter; -class QStackedLayout; -class QStatusBar; -QT_END_NAMESPACE - -struct FancyTab { - QIcon icon; - QString text; - QString toolTip; -}; - -class FancyTabBar : public QWidget { - Q_OBJECT - -public: - FancyTabBar(QWidget *parent = 0, bool isVertical = false); - ~FancyTabBar(); - - bool event(QEvent *event); - - void paintEvent(QPaintEvent *event); - void paintTab(QPainter *painter, int tabIndex) const; - void mousePressEvent(QMouseEvent *); - void mouseMoveEvent(QMouseEvent *); - void enterEvent(QEvent *); - void leaveEvent(QEvent *); - - QSize sizeHint() const; - QSize minimumSizeHint() const; - - void insertTab(int index, const QIcon &icon, const QString &label) - { - FancyTab tab; - - tab.icon = icon; - tab.text = label; - m_tabs.insert(index, tab); - } - void removeTab(int index) - { - m_tabs.removeAt(index); - } - void updateTabNameIcon(int index, const QIcon &icon, const QString &label); - void setCurrentIndex(int index); - int currentIndex() const - { - return m_currentIndex; - } - - void setTabToolTip(int index, QString toolTip) - { - m_tabs[index].toolTip = toolTip; - } - QString tabToolTip(int index) const - { - return m_tabs.at(index).toolTip; - } - - void setIconSize(int s) - { - iconSize = s; - } - QIcon tabIcon(int index) const - { - return m_tabs.at(index).icon; - } - QString tabText(int index) const - { - return m_tabs.at(index).text; - } - int count() const - { - return m_tabs.count(); - } - QRect tabRect(int index) const; - - -signals: - void currentChanged(int); - void aboutToChange(bool *); - -public slots: - void updateHover(); - -private: - static const int m_rounding; - static const int m_textPadding; - QTimeLine m_hoverControl; - QRect m_hoverRect; - int m_hoverIndex; - int m_currentIndex; - int iconSize; - QList m_tabs; - bool verticalTabs; - - QSize tabSizeHint(bool minimum = false) const; -}; - -class FancyTabWidget : public QWidget { - Q_OBJECT - -public: - FancyTabWidget(QWidget *parent = 0, bool isVertical = false); - FancyTabBar *m_tabBar; - void insertTab(int index, QWidget *tab, const QIcon &icon, const QString &label); - void removeTab(int index); - void setBackgroundBrush(const QBrush &brush); - void addCornerWidget(QWidget *widget); - void insertCornerWidget(int pos, QWidget *widget); - int cornerWidgetCount() const; - void setTabToolTip(int index, const QString &toolTip); - void updateTabNameIcon(int index, const QIcon &icon, const QString &label); - void setIconSize(int s) - { - m_tabBar->setIconSize(s); - } - - void paintEvent(QPaintEvent *event); - - int currentIndex() const; - QStatusBar *statusBar() const; - - QWidget *currentWidget(); -signals: - void currentAboutToShow(int index); - void currentChanged(int index); - -public slots: - void setCurrentIndex(int index); - -private slots: - void showWidget(int index); - -private: - QWidget *m_cornerWidgetContainer; - QStackedLayout *m_modesStack; - QWidget *m_selectionWidget; - QStatusBar *m_statusBar; -}; - - -#endif // FANCYTABWIDGET_H diff --git a/ground/gcs/src/plugins/coreplugin/coreplugin.pro b/ground/gcs/src/plugins/coreplugin/coreplugin.pro index 427565091a..f380bbf6b6 100644 --- a/ground/gcs/src/plugins/coreplugin/coreplugin.pro +++ b/ground/gcs/src/plugins/coreplugin/coreplugin.pro @@ -24,9 +24,6 @@ DEPENDPATH += \ SOURCES += \ mainwindow.cpp \ - tabpositionindicator.cpp \ - fancyactionbar.cpp \ - fancytabwidget.cpp \ generalsettings.cpp \ uniqueidmanager.cpp \ messagemanager.cpp \ @@ -49,11 +46,7 @@ SOURCES += \ modemanager.cpp \ coreimpl.cpp \ plugindialog.cpp \ - manhattanstyle.cpp \ minisplitter.cpp \ - styleanimator.cpp \ - rightpane.cpp \ - sidebar.cpp \ mimedatabase.cpp \ icore.cpp \ dialogs/ioptionspage.cpp \ @@ -72,9 +65,6 @@ SOURCES += \ HEADERS += \ mainwindow.h \ - tabpositionindicator.h \ - fancyactionbar.h \ - fancytabwidget.h \ generalsettings.h \ uniqueidmanager.h \ messagemanager.h \ @@ -112,11 +102,7 @@ HEADERS += \ modemanager.h \ coreimpl.h \ plugindialog.h \ - manhattanstyle.h \ minisplitter.h \ - styleanimator.h \ - rightpane.h \ - sidebar.h \ mimedatabase.h \ settingsdatabase.h \ eventfilteringmainwindow.h \ @@ -139,8 +125,7 @@ FORMS += \ workspacesettings.ui RESOURCES += \ - core.qrc \ - fancyactionbar.qrc + core.qrc unix:!macx { images.files = images/librepilot_logo_*.png diff --git a/ground/gcs/src/plugins/coreplugin/fancyactionbar.cpp b/ground/gcs/src/plugins/coreplugin/fancyactionbar.cpp deleted file mode 100644 index f9d39a02df..0000000000 --- a/ground/gcs/src/plugins/coreplugin/fancyactionbar.cpp +++ /dev/null @@ -1,182 +0,0 @@ -/** - ****************************************************************************** - * - * @file fancyactionbar.cpp - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @addtogroup GCSPlugins GCS Plugins - * @{ - * @addtogroup CorePlugin Core Plugin - * @{ - * @brief The Core GCS plugin - *****************************************************************************/ -/* - * 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 "fancyactionbar.h" - -#include -#include -#include -#include -#include -#include - -using namespace Core; -using namespace Internal; - -static const char *const svgIdButtonBase = "ButtonBase"; -static const char *const svgIdButtonNormalBase = "ButtonNormalBase"; -static const char *const svgIdButtonNormalOverlay = "ButtonNormalOverlay"; -static const char *const svgIdButtonPressedBase = "ButtonPressedBase"; -static const char *const svgIdButtonPressedOverlay = "ButtonPressedOverlay"; -static const char *const svgIdButtonDisabledOverlay = "ButtonDisabledOverlay"; -static const char *const svgIdButtonHoverOverlay = "ButtonHoverOverlay"; - -static const char *const elementsSvgIds[] = { - svgIdButtonBase, - svgIdButtonNormalBase, - svgIdButtonNormalOverlay, - svgIdButtonPressedBase, - svgIdButtonPressedOverlay, - svgIdButtonDisabledOverlay, - svgIdButtonHoverOverlay -}; - -const QMap &buttonElementsMap() -{ - static QMap result; - - if (result.isEmpty()) { - QSvgRenderer renderer(QLatin1String(":/fancyactionbar/images/fancytoolbutton.svg")); - for (size_t i = 0; i < sizeof(elementsSvgIds) / sizeof(elementsSvgIds[0]); i++) { - QString elementId(elementsSvgIds[i]); - QPicture elementPicture; - QPainter elementPainter(&elementPicture); - renderer.render(&elementPainter, elementId); - result.insert(elementId, elementPicture); - } - } - return result; -} - -FancyToolButton::FancyToolButton(QWidget *parent) - : QToolButton(parent) - , m_buttonElements(buttonElementsMap()) -{ - setAttribute(Qt::WA_Hover, true); - setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); -} - -void FancyToolButton::paintEvent(QPaintEvent *event) -{ - Q_UNUSED(event) - QPainter p(this); - QSize sh(sizeHint()); - double scale = (double)height() / sh.height(); - if (scale < 1) { - p.save(); - p.scale(1, scale); - } - p.drawPicture(0, 0, m_buttonElements.value(svgIdButtonBase)); - p.drawPicture(0, 0, m_buttonElements.value(isDown() ? svgIdButtonPressedBase : svgIdButtonNormalBase)); -#ifndef Q_WS_MAC // Mac UIs usually don't hover - if (underMouse() && isEnabled()) { - p.drawPicture(0, 0, m_buttonElements.value(svgIdButtonHoverOverlay)); - } -#endif - - if (scale < 1) { - p.restore(); - } - - if (!icon().isNull()) { - icon().paint(&p, rect()); - } else { - const int margin = 4; - p.drawText(rect().adjusted(margin, margin, -margin, -margin), Qt::AlignCenter | Qt::TextWordWrap, text()); - } - - if (scale < 1) { - p.scale(1, scale); - } - - if (isEnabled()) { - p.drawPicture(0, 0, m_buttonElements.value(isDown() ? - svgIdButtonPressedOverlay : svgIdButtonNormalOverlay)); - } else { - p.drawPicture(0, 0, m_buttonElements.value(svgIdButtonDisabledOverlay)); - } -} - -void FancyActionBar::paintEvent(QPaintEvent *event) -{ - Q_UNUSED(event) -} - -QSize FancyToolButton::sizeHint() const -{ - return m_buttonElements.value(svgIdButtonBase).boundingRect().size(); -} - -QSize FancyToolButton::minimumSizeHint() const -{ - return QSize(8, 8); -} - -FancyActionBar::FancyActionBar(QWidget *parent) - : QWidget(parent) -{ - m_actionsLayout = new QVBoxLayout; - - QHBoxLayout *centeringLayout = new QHBoxLayout; - centeringLayout->addStretch(); - centeringLayout->addLayout(m_actionsLayout); - centeringLayout->addStretch(); - setLayout(centeringLayout); -} - -void FancyActionBar::insertAction(int index, QAction *action, QMenu *menu) -{ - FancyToolButton *toolButton = new FancyToolButton(this); - - toolButton->setDefaultAction(action); - if (menu) { - toolButton->setMenu(menu); - toolButton->setPopupMode(QToolButton::DelayedPopup); - - // execute action also if a context menu item is select - connect(toolButton, SIGNAL(triggered(QAction *)), - this, SLOT(toolButtonContextMenuActionTriggered(QAction *)), - Qt::QueuedConnection); - } - m_actionsLayout->insertWidget(index, toolButton); -} - -/* - This slot is invoked when a context menu action of a tool button is triggered. - In this case we also want to trigger the default action of the button. - - This allows the user e.g. to select and run a specific run configuration with one click. - */ -void FancyActionBar::toolButtonContextMenuActionTriggered(QAction *action) -{ - if (QToolButton * button = qobject_cast(sender())) { - if (action != button->defaultAction()) { - button->defaultAction()->trigger(); - } - } -} diff --git a/ground/gcs/src/plugins/coreplugin/fancyactionbar.h b/ground/gcs/src/plugins/coreplugin/fancyactionbar.h deleted file mode 100644 index 9d6917ad4b..0000000000 --- a/ground/gcs/src/plugins/coreplugin/fancyactionbar.h +++ /dev/null @@ -1,72 +0,0 @@ -/** - ****************************************************************************** - * - * @file fancyactionbar.h - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @brief - * @addtogroup GCSPlugins GCS Plugins - * @{ - * @addtogroup CorePlugin Core Plugin - * @{ - * @brief The Core GCS plugin - *****************************************************************************/ -/* - * 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 FANCYACTIONBAR_H -#define FANCYACTIONBAR_H - -#include -#include - -QT_BEGIN_NAMESPACE -class QMenu; -class QVBoxLayout; -QT_END_NAMESPACE - -namespace Core { -namespace Internal { -class FancyToolButton : public QToolButton { -public: - FancyToolButton(QWidget *parent = 0); - - void paintEvent(QPaintEvent *event); - QSize sizeHint() const; - QSize minimumSizeHint() const; - -private: - const QMap &m_buttonElements; -}; - -class FancyActionBar : public QWidget { - Q_OBJECT - -public: - FancyActionBar(QWidget *parent = 0); - - void paintEvent(QPaintEvent *event); - void insertAction(int index, QAction *action, QMenu *menu = 0); - -private slots: - void toolButtonContextMenuActionTriggered(QAction *); -private: - QVBoxLayout *m_actionsLayout; -}; -} // namespace Internal -} // namespace Core - -#endif // FANCYACTIONBAR_H diff --git a/ground/gcs/src/plugins/coreplugin/fancyactionbar.qrc b/ground/gcs/src/plugins/coreplugin/fancyactionbar.qrc deleted file mode 100644 index 97ace666bc..0000000000 --- a/ground/gcs/src/plugins/coreplugin/fancyactionbar.qrc +++ /dev/null @@ -1,5 +0,0 @@ - - - images/fancytoolbutton.svg - - diff --git a/ground/gcs/src/plugins/coreplugin/fancytabwidget.cpp b/ground/gcs/src/plugins/coreplugin/fancytabwidget.cpp deleted file mode 100644 index 9b247b8c41..0000000000 --- a/ground/gcs/src/plugins/coreplugin/fancytabwidget.cpp +++ /dev/null @@ -1,547 +0,0 @@ -/** - ****************************************************************************** - * - * @file fancytabwidget.cpp - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @addtogroup GCSPlugins GCS Plugins - * @{ - * @addtogroup CorePlugin Core Plugin - * @{ - * @brief The Core GCS plugin - *****************************************************************************/ -/* - * 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 "fancytabwidget.h" -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace Core; -using namespace Internal; - -const int FancyTabBar::m_rounding = 22; -const int FancyTabBar::m_textPadding = 4; - -void FancyTab::fadeIn() -{ - animator.stop(); - animator.setDuration(80); - animator.setEndValue(40); - animator.start(); -} - -void FancyTab::fadeOut() -{ - animator.stop(); - animator.setDuration(160); - animator.setEndValue(0); - animator.start(); -} - -void FancyTab::setFader(float value) -{ - m_fader = value; - tabbar->update(); -} - -FancyTabBar::FancyTabBar(QWidget *parent) - : QWidget(parent) -{ - m_hoverIndex = -1; - m_currentIndex = -1; - setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); - setStyle(QStyleFactory::create(QLatin1String("windows"))); - setMinimumWidth(qMax(2 * m_rounding, 40)); - setAttribute(Qt::WA_Hover, true); - setFocusPolicy(Qt::NoFocus); - setMouseTracking(true); // Needed for hover events - m_triggerTimer.setSingleShot(true); - - // We use a zerotimer to keep the sidebar responsive - connect(&m_triggerTimer, SIGNAL(timeout()), this, SLOT(emitCurrentIndex())); -} - -FancyTabBar::~FancyTabBar() -{ - delete style(); -} - -QSize FancyTabBar::tabSizeHint(bool minimum) const -{ - QFont boldFont(font()); - - boldFont.setPointSizeF(Utils::StyleHelper::sidebarFontSize()); - boldFont.setBold(true); - QFontMetrics fm(boldFont); - int spacing = 8; - int width = 60 + spacing + 2; - int maxLabelwidth = 0; - for (int tab = 0; tab < count(); ++tab) { - int width = fm.width(tabText(tab)); - if (width > maxLabelwidth) { - maxLabelwidth = width; - } - } - int iconHeight = minimum ? 0 : 32; - return QSize(qMax(width, maxLabelwidth + 4), iconHeight + spacing + fm.height()); -} - -void FancyTabBar::paintEvent(QPaintEvent *event) -{ - Q_UNUSED(event) - QPainter p(this); - - for (int i = 0; i < count(); ++i) { - if (i != currentIndex()) { - paintTab(&p, i); - } - } - - // paint active tab last, since it overlaps the neighbors - if (currentIndex() != -1) { - paintTab(&p, currentIndex()); - } -} - -// Handle hover events for mouse fade ins -void FancyTabBar::mouseMoveEvent(QMouseEvent *e) -{ - int newHover = -1; - - for (int i = 0; i < count(); ++i) { - QRect area = tabRect(i); - if (area.contains(e->pos())) { - newHover = i; - break; - } - } - if (newHover == m_hoverIndex) { - return; - } - - if (validIndex(m_hoverIndex)) { - m_tabs[m_hoverIndex]->fadeOut(); - } - - m_hoverIndex = newHover; - - if (validIndex(m_hoverIndex)) { - m_tabs[m_hoverIndex]->fadeIn(); - m_hoverRect = tabRect(m_hoverIndex); - } -} - -bool FancyTabBar::event(QEvent *event) -{ - if (event->type() == QEvent::ToolTip) { - if (validIndex(m_hoverIndex)) { - QString tt = tabToolTip(m_hoverIndex); - if (!tt.isEmpty()) { - QToolTip::showText(static_cast(event)->globalPos(), tt, this); - return true; - } - } - } - return QWidget::event(event); -} - -// Resets hover animation on mouse enter -void FancyTabBar::enterEvent(QEvent *e) -{ - Q_UNUSED(e) - m_hoverRect = QRect(); - m_hoverIndex = -1; -} - -// Resets hover animation on mouse enter -void FancyTabBar::leaveEvent(QEvent *e) -{ - Q_UNUSED(e) - m_hoverIndex = -1; - m_hoverRect = QRect(); - for (int i = 0; i < m_tabs.count(); ++i) { - m_tabs[i]->fadeOut(); - } -} - -QSize FancyTabBar::sizeHint() const -{ - QSize sh = tabSizeHint(); - - return QSize(sh.width(), sh.height() * m_tabs.count()); -} - -QSize FancyTabBar::minimumSizeHint() const -{ - QSize sh = tabSizeHint(true); - - return QSize(sh.width(), sh.height() * m_tabs.count()); -} - -QRect FancyTabBar::tabRect(int index) const -{ - QSize sh = tabSizeHint(); - - if (sh.height() * m_tabs.count() > height()) { - sh.setHeight(height() / m_tabs.count()); - } - - return QRect(0, index * sh.height(), sh.width(), sh.height()); -} - -// This keeps the sidebar responsive since -// we get a repaint before loading the -// mode itself -void FancyTabBar::emitCurrentIndex() -{ - emit currentChanged(m_currentIndex); -} - -void FancyTabBar::mousePressEvent(QMouseEvent *e) -{ - e->accept(); - for (int index = 0; index < m_tabs.count(); ++index) { - if (tabRect(index).contains(e->pos())) { - if (isTabEnabled(index)) { - m_currentIndex = index; - update(); - m_triggerTimer.start(0); - } - break; - } - } -} - -void FancyTabBar::paintTab(QPainter *painter, int tabIndex) const -{ - if (!validIndex(tabIndex)) { - qWarning("invalid index"); - return; - } - painter->save(); - - QRect rect = tabRect(tabIndex); - bool selected = (tabIndex == m_currentIndex); - bool enabled = isTabEnabled(tabIndex); - - if (selected) { - // background - painter->save(); - QLinearGradient grad(rect.topLeft(), rect.topRight()); - grad.setColorAt(0, QColor(255, 255, 255, 140)); - grad.setColorAt(1, QColor(255, 255, 255, 210)); - painter->fillRect(rect.adjusted(0, 0, 0, -1), grad); - painter->restore(); - - // shadows - painter->setPen(QColor(0, 0, 0, 110)); - painter->drawLine(rect.topLeft() + QPoint(1, -1), rect.topRight() - QPoint(0, 1)); - painter->drawLine(rect.bottomLeft(), rect.bottomRight()); - painter->setPen(QColor(0, 0, 0, 40)); - painter->drawLine(rect.topLeft(), rect.bottomLeft()); - - // highlights - painter->setPen(QColor(255, 255, 255, 50)); - painter->drawLine(rect.topLeft() + QPoint(0, -2), rect.topRight() - QPoint(0, 2)); - painter->drawLine(rect.bottomLeft() + QPoint(0, 1), rect.bottomRight() + QPoint(0, 1)); - painter->setPen(QColor(255, 255, 255, 40)); - painter->drawLine(rect.topLeft() + QPoint(0, 0), rect.topRight()); - painter->drawLine(rect.topRight() + QPoint(0, 1), rect.bottomRight() - QPoint(0, 1)); - painter->drawLine(rect.bottomLeft() + QPoint(0, -1), rect.bottomRight() - QPoint(0, 1)); - } - - QString tabText(this->tabText(tabIndex)); - QRect tabTextRect(rect); - const bool drawIcon = rect.height() > 36; - QRect tabIconRect(tabTextRect); - tabTextRect.translate(0, drawIcon ? -2 : 1); - QFont boldFont(painter->font()); - boldFont.setPointSizeF(Utils::StyleHelper::sidebarFontSize()); - boldFont.setBold(true); - painter->setFont(boldFont); - painter->setPen(selected ? QColor(255, 255, 255, 160) : QColor(0, 0, 0, 110)); - const int textFlags = Qt::AlignCenter | (drawIcon ? Qt::AlignBottom : Qt::AlignVCenter) | Qt::TextWordWrap; - if (enabled) { - painter->drawText(tabTextRect, textFlags, tabText); - painter->setPen(selected ? QColor(60, 60, 60) : Utils::StyleHelper::panelTextColor()); - } else { - painter->setPen(selected ? Utils::StyleHelper::panelTextColor() : QColor(255, 255, 255, 120)); - } - if (!Utils::HostOsInfo::isMacHost() && !selected && enabled) { - painter->save(); - int fader = int(m_tabs[tabIndex]->fader()); - QLinearGradient grad(rect.topLeft(), rect.topRight()); - grad.setColorAt(0, Qt::transparent); - grad.setColorAt(0.5, QColor(255, 255, 255, fader)); - grad.setColorAt(1, Qt::transparent); - painter->fillRect(rect, grad); - painter->setPen(QPen(grad, 1.0)); - painter->drawLine(rect.topLeft(), rect.topRight()); - painter->drawLine(rect.bottomLeft(), rect.bottomRight()); - painter->restore(); - } - - if (!enabled) { - painter->setOpacity(0.7); - } - - if (drawIcon) { - int textHeight = painter->fontMetrics().boundingRect(QRect(0, 0, width(), height()), Qt::TextWordWrap, tabText).height(); - tabIconRect.adjust(0, 4, 0, -textHeight); - Utils::StyleHelper::drawIconWithShadow(tabIcon(tabIndex), tabIconRect, painter, enabled ? QIcon::Normal : QIcon::Disabled); - } - - painter->translate(0, -1); - painter->drawText(tabTextRect, textFlags, tabText); - painter->restore(); -} - -void FancyTabBar::setCurrentIndex(int index) -{ - if (isTabEnabled(index)) { - m_currentIndex = index; - update(); - emit currentChanged(m_currentIndex); - } -} - -void FancyTabBar::setTabEnabled(int index, bool enable) -{ - Q_ASSERT(index < m_tabs.size()); - Q_ASSERT(index >= 0); - - if (index < m_tabs.size() && index >= 0) { - m_tabs[index]->enabled = enable; - update(tabRect(index)); - } -} - -bool FancyTabBar::isTabEnabled(int index) const -{ - Q_ASSERT(index < m_tabs.size()); - Q_ASSERT(index >= 0); - - if (index < m_tabs.size() && index >= 0) { - return m_tabs[index]->enabled; - } - - return false; -} - - -////// -// FancyColorButton -////// - -class FancyColorButton : public QWidget { -public: - FancyColorButton(QWidget *parent) - : m_parent(parent) - { - setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred); - } - - void mousePressEvent(QMouseEvent *ev) - { - if (ev->modifiers() & Qt::ShiftModifier) { - QColor color = QColorDialog::getColor(Utils::StyleHelper::requestedBaseColor(), m_parent); - if (color.isValid()) { - Utils::StyleHelper::setBaseColor(color); - } - } - } -private: - QWidget *m_parent; -}; - -////// -// FancyTabWidget -////// - -FancyTabWidget::FancyTabWidget(QWidget *parent) - : QWidget(parent) -{ - m_tabBar = new FancyTabBar(this); - - m_selectionWidget = new QWidget(this); - QVBoxLayout *selectionLayout = new QVBoxLayout; - selectionLayout->setSpacing(0); - selectionLayout->setMargin(0); - - Utils::StyledBar *bar = new Utils::StyledBar; - QHBoxLayout *layout = new QHBoxLayout(bar); - layout->setMargin(0); - layout->setSpacing(0); - layout->addWidget(new FancyColorButton(this)); - selectionLayout->addWidget(bar); - - selectionLayout->addWidget(m_tabBar, 1); - m_selectionWidget->setLayout(selectionLayout); - m_selectionWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding); - - m_cornerWidgetContainer = new QWidget(this); - m_cornerWidgetContainer->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred); - m_cornerWidgetContainer->setAutoFillBackground(false); - - QVBoxLayout *cornerWidgetLayout = new QVBoxLayout; - cornerWidgetLayout->setSpacing(0); - cornerWidgetLayout->setMargin(0); - cornerWidgetLayout->addStretch(); - m_cornerWidgetContainer->setLayout(cornerWidgetLayout); - - selectionLayout->addWidget(m_cornerWidgetContainer, 0); - - m_modesStack = new QStackedLayout; - m_statusBar = new QStatusBar; - m_statusBar->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed); - - QVBoxLayout *vlayout = new QVBoxLayout; - vlayout->setMargin(0); - vlayout->setSpacing(0); - vlayout->addLayout(m_modesStack); - vlayout->addWidget(m_statusBar); - - QHBoxLayout *mainLayout = new QHBoxLayout; - mainLayout->setMargin(0); - mainLayout->setSpacing(1); - mainLayout->addWidget(m_selectionWidget); - mainLayout->addLayout(vlayout); - setLayout(mainLayout); - - connect(m_tabBar, SIGNAL(currentChanged(int)), this, SLOT(showWidget(int))); -} - -void FancyTabWidget::setSelectionWidgetVisible(bool visible) -{ - m_selectionWidget->setVisible(visible); -} - -bool FancyTabWidget::isSelectionWidgetVisible() const -{ - return m_selectionWidget->isVisible(); -} - -void FancyTabWidget::insertTab(int index, QWidget *tab, const QIcon &icon, const QString &label) -{ - m_modesStack->insertWidget(index, tab); - m_tabBar->insertTab(index, icon, label); -} - -void FancyTabWidget::removeTab(int index) -{ - m_modesStack->removeWidget(m_modesStack->widget(index)); - m_tabBar->removeTab(index); -} - -void FancyTabWidget::setBackgroundBrush(const QBrush &brush) -{ - QPalette pal = m_tabBar->palette(); - - pal.setBrush(QPalette::Mid, brush); - m_tabBar->setPalette(pal); - pal = m_cornerWidgetContainer->palette(); - pal.setBrush(QPalette::Mid, brush); - m_cornerWidgetContainer->setPalette(pal); -} - -void FancyTabWidget::paintEvent(QPaintEvent *event) -{ - Q_UNUSED(event) - if (m_selectionWidget->isVisible()) { - QPainter painter(this); - - QRect rect = m_selectionWidget->rect().adjusted(0, 0, 1, 0); - rect = style()->visualRect(layoutDirection(), geometry(), rect); - Utils::StyleHelper::verticalGradient(&painter, rect, rect); - painter.setPen(Utils::StyleHelper::borderColor()); - painter.drawLine(rect.topRight(), rect.bottomRight()); - - QColor light = Utils::StyleHelper::sidebarHighlight(); - painter.setPen(light); - painter.drawLine(rect.bottomLeft(), rect.bottomRight()); - } -} - -void FancyTabWidget::insertCornerWidget(int pos, QWidget *widget) -{ - QVBoxLayout *layout = static_cast(m_cornerWidgetContainer->layout()); - - layout->insertWidget(pos, widget); -} - -int FancyTabWidget::cornerWidgetCount() const -{ - return m_cornerWidgetContainer->layout()->count(); -} - -void FancyTabWidget::addCornerWidget(QWidget *widget) -{ - m_cornerWidgetContainer->layout()->addWidget(widget); -} - -int FancyTabWidget::currentIndex() const -{ - return m_tabBar->currentIndex(); -} - -QStatusBar *FancyTabWidget::statusBar() const -{ - return m_statusBar; -} - -void FancyTabWidget::setCurrentIndex(int index) -{ - if (m_tabBar->isTabEnabled(index)) { - m_tabBar->setCurrentIndex(index); - } -} - -void FancyTabWidget::showWidget(int index) -{ - emit currentAboutToShow(index); - - m_modesStack->setCurrentIndex(index); - emit currentChanged(index); -} - -void FancyTabWidget::setTabToolTip(int index, const QString &toolTip) -{ - m_tabBar->setTabToolTip(index, toolTip); -} - -void FancyTabWidget::setTabEnabled(int index, bool enable) -{ - m_tabBar->setTabEnabled(index, enable); -} - -bool FancyTabWidget::isTabEnabled(int index) const -{ - return m_tabBar->isTabEnabled(index); -} diff --git a/ground/gcs/src/plugins/coreplugin/fancytabwidget.h b/ground/gcs/src/plugins/coreplugin/fancytabwidget.h deleted file mode 100644 index aef20b2c5b..0000000000 --- a/ground/gcs/src/plugins/coreplugin/fancytabwidget.h +++ /dev/null @@ -1,208 +0,0 @@ -/** - ****************************************************************************** - * - * @file fancytabwidget.h - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @addtogroup GCSPlugins GCS Plugins - * @{ - * @addtogroup CorePlugin Core Plugin - * @{ - * @brief The Core GCS plugin - *****************************************************************************/ -/* - * 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 FANCYTABWIDGET_H -#define FANCYTABWIDGET_H - -#include -#include - -#include -#include - -QT_BEGIN_NAMESPACE -class QPainter; -class QStackedLayout; -class QStatusBar; -QT_END_NAMESPACE - -namespace Core { -namespace Internal { -class FancyTab : public QObject { - Q_OBJECT Q_PROPERTY(float fader READ fader WRITE setFader) -public: - FancyTab(QWidget *tabbar) : enabled(false), tabbar(tabbar), m_fader(0) - { - animator.setPropertyName("fader"); - animator.setTargetObject(this); - } - float fader() - { - return m_fader; - } - void setFader(float value); - - void fadeIn(); - void fadeOut(); - - QIcon icon; - QString text; - QString toolTip; - bool enabled; - -private: - QPropertyAnimation animator; - QWidget *tabbar; - float m_fader; -}; - -class FancyTabBar : public QWidget { - Q_OBJECT - -public: - FancyTabBar(QWidget *parent = 0); - ~FancyTabBar(); - - bool event(QEvent *event); - - void paintEvent(QPaintEvent *event); - void paintTab(QPainter *painter, int tabIndex) const; - void mousePressEvent(QMouseEvent *); - void mouseMoveEvent(QMouseEvent *); - void enterEvent(QEvent *); - void leaveEvent(QEvent *); - bool validIndex(int index) const - { - return index >= 0 && index < m_tabs.count(); - } - - QSize sizeHint() const; - QSize minimumSizeHint() const; - - void setTabEnabled(int index, bool enable); - bool isTabEnabled(int index) const; - - void insertTab(int index, const QIcon &icon, const QString &label) - { - FancyTab *tab = new FancyTab(this); - - tab->icon = icon; - tab->text = label; - m_tabs.insert(index, tab); - updateGeometry(); - } - void setEnabled(int index, bool enabled); - void removeTab(int index) - { - FancyTab *tab = m_tabs.takeAt(index); - - delete tab; - updateGeometry(); - } - void setCurrentIndex(int index); - int currentIndex() const - { - return m_currentIndex; - } - - void setTabToolTip(int index, QString toolTip) - { - m_tabs[index]->toolTip = toolTip; - } - QString tabToolTip(int index) const - { - return m_tabs.at(index)->toolTip; - } - - QIcon tabIcon(int index) const - { - return m_tabs.at(index)->icon; - } - QString tabText(int index) const - { - return m_tabs.at(index)->text; - } - int count() const - { - return m_tabs.count(); - } - QRect tabRect(int index) const; - -signals: - void currentChanged(int); - -public slots: - void emitCurrentIndex(); - -private: - static const int m_rounding; - static const int m_textPadding; - QRect m_hoverRect; - int m_hoverIndex; - int m_currentIndex; - QList m_tabs; - QTimer m_triggerTimer; - QSize tabSizeHint(bool minimum = false) const; -}; - -class FancyTabWidget : public QWidget { - Q_OBJECT - -public: - FancyTabWidget(QWidget *parent = 0); - - void insertTab(int index, QWidget *tab, const QIcon &icon, const QString &label); - void removeTab(int index); - void setBackgroundBrush(const QBrush &brush); - void addCornerWidget(QWidget *widget); - void insertCornerWidget(int pos, QWidget *widget); - int cornerWidgetCount() const; - void setTabToolTip(int index, const QString &toolTip); - - void paintEvent(QPaintEvent *event); - - int currentIndex() const; - QStatusBar *statusBar() const; - - void setTabEnabled(int index, bool enable); - bool isTabEnabled(int index) const; - - bool isSelectionWidgetVisible() const; - -signals: - void currentAboutToShow(int index); - void currentChanged(int index); - -public slots: - void setCurrentIndex(int index); - void setSelectionWidgetVisible(bool visible); - -private slots: - void showWidget(int index); - -private: - FancyTabBar *m_tabBar; - QWidget *m_cornerWidgetContainer; - QStackedLayout *m_modesStack; - QWidget *m_selectionWidget; - QStatusBar *m_statusBar; -}; -} // namespace Internal -} // namespace Core - -#endif // FANCYTABWIDGET_H diff --git a/ground/gcs/src/plugins/coreplugin/images/fancytoolbutton.svg b/ground/gcs/src/plugins/coreplugin/images/fancytoolbutton.svg deleted file mode 100644 index 8c9c0f1d62..0000000000 --- a/ground/gcs/src/plugins/coreplugin/images/fancytoolbutton.svg +++ /dev/null @@ -1,539 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - diff --git a/ground/gcs/src/plugins/coreplugin/mainwindow.cpp b/ground/gcs/src/plugins/coreplugin/mainwindow.cpp index 7fa1be7797..665e9c27d0 100644 --- a/ground/gcs/src/plugins/coreplugin/mainwindow.cpp +++ b/ground/gcs/src/plugins/coreplugin/mainwindow.cpp @@ -54,7 +54,6 @@ #include -#include "rightpane.h" #include "settingsdialog.h" #include "threadmanager.h" #include "uniqueidmanager.h" diff --git a/ground/gcs/src/plugins/coreplugin/mainwindow.h b/ground/gcs/src/plugins/coreplugin/mainwindow.h index c19903424a..37b4906cf0 100644 --- a/ground/gcs/src/plugins/coreplugin/mainwindow.h +++ b/ground/gcs/src/plugins/coreplugin/mainwindow.h @@ -57,7 +57,6 @@ class ConnectionManager; class MessageManager; class MimeDatabase; class ModeManager; -class RightPaneWidget; class SettingsDatabase; class UniqueIDManager; class VariableManager; @@ -70,7 +69,6 @@ class UAVGadgetInstanceManager; namespace Internal { class ActionManagerPrivate; class CoreImpl; -class FancyTabWidget; class GeneralSettings; class ShortcutSettings; class WorkspaceSettings; diff --git a/ground/gcs/src/plugins/coreplugin/manhattanstyle.cpp b/ground/gcs/src/plugins/coreplugin/manhattanstyle.cpp deleted file mode 100644 index 1a5069b8dd..0000000000 --- a/ground/gcs/src/plugins/coreplugin/manhattanstyle.cpp +++ /dev/null @@ -1,1038 +0,0 @@ -/** - ****************************************************************************** - * - * @file manhattanstyle.cpp - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @addtogroup GCSPlugins GCS Plugins - * @{ - * @addtogroup CorePlugin Core Plugin - * @{ - * @brief The Core GCS plugin - *****************************************************************************/ -/* - * 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 "manhattanstyle.h" - -#include "styleanimator.h" - -#include - -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// We define a currently unused state for indicating animations -const QStyle::State State_Animating = QStyle::State(0x00000040); - -// Because designer needs to disable this for widget previews -// we have a custom property that is inherited -bool styleEnabled(const QWidget *widget) -{ - const QWidget *p = widget; - - while (p) { - if (p->property("_q_custom_style_disabled").toBool()) { - return false; - } - p = p->parentWidget(); - } - return true; -} - -// Consider making this a QStyle state -bool panelWidget(const QWidget *widget) -{ - if (!widget) { - return false; - } - - // Do not style dialogs or explicitly ignored widgets - if ((widget->window()->windowFlags() & Qt::WindowType_Mask) == Qt::Dialog) { - return false; - } - - if (qobject_cast(widget)) { - return true; - } - - if (qobject_cast(widget)) { - return styleEnabled(widget); - } - - const QWidget *p = widget; - while (p) { - if (qobject_cast(p) || - qobject_cast(p) || - qobject_cast(p) || - p->property("panelwidget").toBool()) { - return styleEnabled(widget); - } - p = p->parentWidget(); - } - return false; -} - -// Consider making this a QStyle state -bool lightColored(const QWidget *widget) -{ - if (!widget) { - return false; - } - - // Don't style dialogs or explicitly ignored widgets - if ((widget->window()->windowFlags() & Qt::WindowType_Mask) == Qt::Dialog) { - return false; - } - - const QWidget *p = widget; - while (p) { - if (p->property("lightColored").toBool()) { - return true; - } - p = p->parentWidget(); - } - return false; -} - -class ManhattanStylePrivate { -public: - explicit ManhattanStylePrivate(); - void init(); - -public: - const QImage lineeditImage; - const QImage lineeditImage_disabled; - const QPixmap extButtonPixmap; - const QPixmap closeButtonPixmap; - StyleAnimator animator; -}; - -ManhattanStylePrivate::ManhattanStylePrivate() : - lineeditImage(QLatin1String(":/core/images/inputfield.png")), - lineeditImage_disabled(QLatin1String(":/core/images/inputfield_disabled.png")), - extButtonPixmap(QLatin1String(":/core/images/extension.png")), - closeButtonPixmap(QLatin1String(Core::Constants::ICON_CLOSE)) -{} - -ManhattanStyle::ManhattanStyle(const QString &baseStyleName) - : QProxyStyle(QStyleFactory::create(baseStyleName)), - d(new ManhattanStylePrivate()) -{} - -ManhattanStyle::~ManhattanStyle() -{ - delete d; - d = 0; -} - -QPixmap ManhattanStyle::generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap, const QStyleOption *opt) const -{ - return QProxyStyle::generatedIconPixmap(iconMode, pixmap, opt); -} - -QSize ManhattanStyle::sizeFromContents(ContentsType type, const QStyleOption *option, - const QSize &size, const QWidget *widget) const -{ - QSize newSize = QProxyStyle::sizeFromContents(type, option, size, widget); - - if (type == CT_Splitter && widget && widget->property("minisplitter").toBool()) { - return QSize(1, 1); - } else if (type == CT_ComboBox && panelWidget(widget)) { - newSize += QSize(14, 0); - } - return newSize; -} - -QRect ManhattanStyle::subElementRect(SubElement element, const QStyleOption *option, const QWidget *widget) const -{ - return QProxyStyle::subElementRect(element, option, widget); -} - -QRect ManhattanStyle::subControlRect(ComplexControl control, const QStyleOptionComplex *option, - SubControl subControl, const QWidget *widget) const -{ - return QProxyStyle::subControlRect(control, option, subControl, widget); -} - -QStyle::SubControl ManhattanStyle::hitTestComplexControl(ComplexControl control, const QStyleOptionComplex *option, - const QPoint &pos, const QWidget *widget) const -{ - return QProxyStyle::hitTestComplexControl(control, option, pos, widget); -} - -int ManhattanStyle::pixelMetric(PixelMetric metric, const QStyleOption *option, const QWidget *widget) const -{ - int retval = 0; - - retval = QProxyStyle::pixelMetric(metric, option, widget); - switch (metric) { - case PM_SplitterWidth: - if (widget && widget->property("minisplitter").toBool()) { - retval = 1; - } - break; - case PM_ToolBarIconSize: - if (panelWidget(widget)) { - retval = 16; - } - break; - case PM_DockWidgetHandleExtent: - case PM_DockWidgetSeparatorExtent: - return 1; - - case PM_MenuPanelWidth: - case PM_MenuBarHMargin: - case PM_MenuBarVMargin: - case PM_ToolBarFrameWidth: - if (panelWidget(widget)) { - retval = 1; - } - break; - case PM_ButtonShiftVertical: - case PM_ButtonShiftHorizontal: - case PM_MenuBarPanelWidth: - case PM_ToolBarItemMargin: - case PM_ToolBarItemSpacing: - if (panelWidget(widget)) { - retval = 0; - } - break; - case PM_DefaultFrameWidth: - if (qobject_cast(widget) && panelWidget(widget)) { - return 1; - } - break; - default: - break; - } - return retval; -} - -QPalette ManhattanStyle::standardPalette() const -{ - return QProxyStyle::standardPalette(); -} - -void ManhattanStyle::polish(QApplication *app) -{ - return QProxyStyle::polish(app); -} - -void ManhattanStyle::unpolish(QApplication *app) -{ - return QProxyStyle::unpolish(app); -} - -QPalette panelPalette(const QPalette &oldPalette, bool lightColored = false) -{ - QColor color = Utils::StyleHelper::panelTextColor(lightColored); - QPalette pal = oldPalette; - - pal.setBrush(QPalette::All, QPalette::WindowText, color); - pal.setBrush(QPalette::All, QPalette::ButtonText, color); - pal.setBrush(QPalette::All, QPalette::Foreground, color); - color.setAlpha(100); - pal.setBrush(QPalette::Disabled, QPalette::WindowText, color); - pal.setBrush(QPalette::Disabled, QPalette::ButtonText, color); - pal.setBrush(QPalette::Disabled, QPalette::Foreground, color); - return pal; -} - -void ManhattanStyle::polish(QWidget *widget) -{ - QProxyStyle::polish(widget); - - // OxygenStyle forces a rounded widget mask on toolbars and dock widgets - if (baseStyle()->inherits("OxygenStyle") || baseStyle()->inherits("Oxygen::Style")) { - if (qobject_cast(widget) || qobject_cast(widget)) { - widget->removeEventFilter(baseStyle()); - widget->setContentsMargins(0, 0, 0, 0); - } - } - if (panelWidget(widget)) { - // Oxygen and possibly other styles override this - if (qobject_cast(widget)) { - widget->setContentsMargins(0, 0, 0, 0); - } - - widget->setAttribute(Qt::WA_LayoutUsesWidgetRect, true); - if (qobject_cast(widget)) { - widget->setAttribute(Qt::WA_Hover); - widget->setMaximumHeight(Utils::StyleHelper::navigationWidgetHeight() - 2); - } else if (qobject_cast(widget)) { - widget->setAttribute(Qt::WA_Hover); - widget->setMaximumHeight(Utils::StyleHelper::navigationWidgetHeight() - 2); - } else if (qobject_cast(widget)) { - widget->setPalette(panelPalette(widget->palette())); - } else if (widget->property("panelwidget_singlerow").toBool()) { - widget->setFixedHeight(Utils::StyleHelper::navigationWidgetHeight()); - } else if (qobject_cast(widget)) { - widget->setFixedHeight(Utils::StyleHelper::navigationWidgetHeight() + 2); - } else if (qobject_cast(widget)) { - widget->setMaximumHeight(Utils::StyleHelper::navigationWidgetHeight() - 2); - widget->setAttribute(Qt::WA_Hover); - } - } -} - -void ManhattanStyle::unpolish(QWidget *widget) -{ - QProxyStyle::unpolish(widget); - - if (panelWidget(widget)) { - widget->setAttribute(Qt::WA_LayoutUsesWidgetRect, false); - if (qobject_cast(widget)) { - widget->setAttribute(Qt::WA_Hover, false); - } else if (qobject_cast(widget)) { - widget->setAttribute(Qt::WA_Hover, false); - } else if (qobject_cast(widget)) { - widget->setAttribute(Qt::WA_Hover, false); - } - } -} - -void ManhattanStyle::polish(QPalette &pal) -{ - QProxyStyle::polish(pal); -} - -QIcon ManhattanStyle::standardIconImplementation(StandardPixmap standardIcon, const QStyleOption *option, const QWidget *widget) const -{ - QIcon icon; - - switch (standardIcon) { - case QStyle::SP_TitleBarCloseButton: - case QStyle::SP_ToolBarHorizontalExtensionButton: - return QIcon(standardPixmap(standardIcon, option, widget)); - - default: - icon = baseStyle()->standardIcon(standardIcon, option, widget); - } - return icon; -} - -QPixmap ManhattanStyle::standardPixmap(StandardPixmap standardPixmap, const QStyleOption *opt, - const QWidget *widget) const -{ - if (widget && !panelWidget(widget)) { - return QProxyStyle::standardPixmap(standardPixmap, opt, widget); - } - - QPixmap pixmap; - switch (standardPixmap) { - case QStyle::SP_ToolBarHorizontalExtensionButton: - pixmap = d->extButtonPixmap; - break; - case QStyle::SP_TitleBarCloseButton: - pixmap = d->closeButtonPixmap; - break; - default: - pixmap = QProxyStyle::standardPixmap(standardPixmap, opt, widget); - break; - } - return pixmap; -} - -int ManhattanStyle::styleHint(StyleHint hint, const QStyleOption *option, const QWidget *widget, - QStyleHintReturn *returnData) const -{ - int ret = QProxyStyle::styleHint(hint, option, widget, returnData); - - switch (hint) { - // Make project explorer alternate rows all the way - case QStyle::SH_ItemView_PaintAlternatingRowColorsForEmptyArea: - if (widget && widget->property("AlternateEmpty").toBool()) { - ret = true; - } - break; - case QStyle::SH_EtchDisabledText: - if (panelWidget(widget)) { - ret = false; - } - break; - case QStyle::SH_ItemView_ArrowKeysNavigateIntoChildren: - ret = true; - break; - default: - break; - } - return ret; -} - -void ManhattanStyle::drawPrimitive(PrimitiveElement element, const QStyleOption *option, - QPainter *painter, const QWidget *widget) const -{ - if (!panelWidget(widget)) { - return QProxyStyle::drawPrimitive(element, option, painter, widget); - } - - bool animating = (option->state & State_Animating); - int state = option->state; - QRect rect = option->rect; - QRect oldRect; - QRect newRect; - if (widget && (element == PE_PanelButtonTool) && !animating) { - QWidget *w = const_cast (widget); - int oldState = w->property("_q_stylestate").toInt(); - oldRect = w->property("_q_stylerect").toRect(); - newRect = w->rect(); - w->setProperty("_q_stylestate", (int)option->state); - w->setProperty("_q_stylerect", w->rect()); - - // Determine the animated transition - bool doTransition = ((state & State_On) != (oldState & State_On) || - (state & State_MouseOver) != (oldState & State_MouseOver)); - if (oldRect != newRect) { - doTransition = false; - d->animator.stopAnimation(widget); - } - - if (doTransition) { - QImage startImage(option->rect.size(), QImage::Format_ARGB32_Premultiplied); - QImage endImage(option->rect.size(), QImage::Format_ARGB32_Premultiplied); - Animation *anim = d->animator.widgetAnimation(widget); - QStyleOption opt = *option; - opt.state = (QStyle::State)oldState; - opt.state |= State_Animating; - startImage.fill(0); - Transition *t = new Transition; - t->setWidget(w); - QPainter startPainter(&startImage); - if (!anim) { - drawPrimitive(element, &opt, &startPainter, widget); - } else { - anim->paint(&startPainter, &opt); - d->animator.stopAnimation(widget); - } - QStyleOption endOpt = *option; - endOpt.state |= State_Animating; - t->setStartImage(startImage); - d->animator.startAnimation(t); - endImage.fill(0); - QPainter endPainter(&endImage); - drawPrimitive(element, &endOpt, &endPainter, widget); - t->setEndImage(endImage); - if (oldState & State_MouseOver) { - t->setDuration(150); - } else { - t->setDuration(75); - } - t->setStartTime(QTime::currentTime()); - } - } - - switch (element) { - case PE_IndicatorDockWidgetResizeHandle: - painter->fillRect(option->rect, Utils::StyleHelper::borderColor()); - break; - case PE_FrameDockWidget: - QCommonStyle::drawPrimitive(element, option, painter, widget); - break; - case PE_PanelLineEdit: - { - painter->save(); - - // Fill the line edit background - QRect filledRect = option->rect.adjusted(1, 1, -1, -1); - painter->setBrushOrigin(filledRect.topLeft()); - painter->fillRect(filledRect, option->palette.base()); - - if (option->state & State_Enabled) { - Utils::StyleHelper::drawCornerImage(d->lineeditImage, painter, option->rect, 5, 5, 5, 5); - } else { - Utils::StyleHelper::drawCornerImage(d->lineeditImage_disabled, painter, option->rect, 5, 5, 5, 5); - } - - if (option->state & State_HasFocus || option->state & State_MouseOver) { - QColor hover = Utils::StyleHelper::baseColor(); - if (state & State_HasFocus) { - hover.setAlpha(100); - } else { - hover.setAlpha(50); - } - - painter->setPen(QPen(hover, 1)); - painter->drawRect(option->rect.adjusted(1, 1, -2, -2)); - } - painter->restore(); - } - break; - - case PE_FrameStatusBarItem: - break; - - case PE_PanelButtonTool: - { - Animation *anim = d->animator.widgetAnimation(widget); - if (!animating && anim) { - anim->paint(painter, option); - } else { - bool pressed = option->state & State_Sunken || option->state & State_On; - QColor shadow(0, 0, 0, 30); - painter->setPen(shadow); - if (pressed) { - QColor shade(0, 0, 0, 40); - painter->fillRect(rect, shade); - painter->drawLine(rect.topLeft() + QPoint(1, 0), rect.topRight() - QPoint(1, 0)); - painter->drawLine(rect.topLeft(), rect.bottomLeft()); - painter->drawLine(rect.topRight(), rect.bottomRight()); - // painter->drawLine(rect.bottomLeft() + QPoint(1, 0), rect.bottomRight() - QPoint(1, 0)); - QColor highlight(255, 255, 255, 30); - painter->setPen(highlight); - } else if (option->state & State_Enabled && - option->state & State_MouseOver) { - QColor lighter(255, 255, 255, 37); - painter->fillRect(rect, lighter); - } - if (option->state & State_HasFocus && (option->state & State_KeyboardFocusChange)) { - QColor highlight = option->palette.highlight().color(); - highlight.setAlphaF(0.4); - painter->setPen(QPen(highlight.lighter(), 1)); - highlight.setAlphaF(0.3); - painter->setBrush(highlight); - painter->setRenderHint(QPainter::Antialiasing); - QRectF rect = option->rect; - rect.translate(0.5, 0.5); - painter->drawRoundedRect(rect.adjusted(2, 2, -3, -3), 2, 2); - } - } - } - break; - - case PE_PanelStatusBar: - { - painter->save(); - QLinearGradient grad = Utils::StyleHelper::statusBarGradient(rect); - painter->fillRect(rect, grad); - painter->setPen(QColor(255, 255, 255, 60)); - painter->drawLine(rect.topLeft() + QPoint(0, 1), - rect.topRight() + QPoint(0, 1)); - painter->setPen(Utils::StyleHelper::borderColor().darker(110)); - painter->drawLine(rect.topLeft(), rect.topRight()); - painter->restore(); - } - break; - - case PE_IndicatorToolBarSeparator: - { - QColor separatorColor = Utils::StyleHelper::borderColor(); - separatorColor.setAlpha(100); - painter->setPen(separatorColor); - const int margin = 6; - if (option->state & State_Horizontal) { - const int offset = rect.width() / 2; - painter->drawLine(rect.bottomLeft().x() + offset, - rect.bottomLeft().y() - margin, - rect.topLeft().x() + offset, - rect.topLeft().y() + margin); - } else { // Draw vertical separator - const int offset = rect.height() / 2; - painter->setPen(QPen(option->palette.background().color().darker(110))); - painter->drawLine(rect.topLeft().x() + margin, - rect.topLeft().y() + offset, - rect.topRight().x() - margin, - rect.topRight().y() + offset); - } - } - break; - - case PE_IndicatorToolBarHandle: - { - bool horizontal = option->state & State_Horizontal; - painter->save(); - QPainterPath path; - int x = option->rect.x() + (horizontal ? 2 : 6); - int y = option->rect.y() + (horizontal ? 6 : 2); - static const int RectHeight = 2; - if (horizontal) { - while (y < option->rect.height() - RectHeight - 6) { - path.moveTo(x, y); - path.addRect(x, y, RectHeight, RectHeight); - y += 6; - } - } else { - while (x < option->rect.width() - RectHeight - 6) { - path.moveTo(x, y); - path.addRect(x, y, RectHeight, RectHeight); - x += 6; - } - } - - painter->setPen(Qt::NoPen); - QColor dark = Utils::StyleHelper::borderColor(); - dark.setAlphaF(0.4); - - QColor light = Utils::StyleHelper::baseColor(); - light.setAlphaF(0.4); - - painter->fillPath(path, light); - painter->save(); - painter->translate(1, 1); - painter->fillPath(path, dark); - painter->restore(); - painter->translate(3, 3); - painter->fillPath(path, light); - painter->translate(1, 1); - painter->fillPath(path, dark); - painter->restore(); - } - break; - case PE_IndicatorArrowUp: - case PE_IndicatorArrowDown: - case PE_IndicatorArrowRight: - case PE_IndicatorArrowLeft: - { - Utils::StyleHelper::drawArrow(element, painter, option); - } - break; - - default: - QProxyStyle::drawPrimitive(element, option, painter, widget); - break; - } -} - -void ManhattanStyle::drawControl(ControlElement element, const QStyleOption *option, - QPainter *painter, const QWidget *widget) const -{ - if (!panelWidget(widget)) { - return QProxyStyle::drawControl(element, option, painter, widget); - } - - switch (element) { - case CE_Splitter: - painter->fillRect(option->rect, Utils::StyleHelper::borderColor()); - break; - - case CE_TabBarTabShape: - // Most styles draw a single dark outline. This looks rather ugly when combined with our - // single pixel dark separator so we adjust the first tab to compensate for this - - if (const QStyleOptionTabV3 * tab = qstyleoption_cast(option)) { - QStyleOptionTabV3 adjustedTab = *tab; - if (tab->cornerWidgets == QStyleOptionTab::NoCornerWidgets && ( - tab->position == QStyleOptionTab::Beginning || - tab->position == QStyleOptionTab::OnlyOneTab)) { - if (option->direction == Qt::LeftToRight) { - adjustedTab.rect = adjustedTab.rect.adjusted(-1, 0, 0, 0); - } else { - adjustedTab.rect = adjustedTab.rect.adjusted(0, 0, 1, 0); - } - } - QProxyStyle::drawControl(element, &adjustedTab, painter, widget); - return; - } - break; - - case CE_MenuBarItem: - painter->save(); - if (const QStyleOptionMenuItem * mbi = qstyleoption_cast(option)) { - QColor highlightOutline = Utils::StyleHelper::borderColor().lighter(120); - bool act = mbi->state & State_Sunken; - bool dis = !(mbi->state & State_Enabled); - Utils::StyleHelper::menuGradient(painter, option->rect, option->rect); - QStyleOptionMenuItem item = *mbi; - item.rect = mbi->rect; - QPalette pal = mbi->palette; - pal.setBrush(QPalette::ButtonText, dis ? Qt::gray : Qt::black); - item.palette = pal; - QCommonStyle::drawControl(element, &item, painter, widget); - QRect r = option->rect; - - if (act) { - // Fill| - QColor baseColor = Utils::StyleHelper::baseColor(); - QLinearGradient grad(option->rect.topLeft(), option->rect.bottomLeft()); - grad.setColorAt(0, baseColor.lighter(120)); - grad.setColorAt(1, baseColor.lighter(130)); - painter->fillRect(option->rect.adjusted(1, 1, -1, 0), grad); - - // Outline - painter->setPen(QPen(highlightOutline, 0)); - painter->drawLine(QPoint(r.left(), r.top() + 1), QPoint(r.left(), r.bottom())); - painter->drawLine(QPoint(r.right(), r.top() + 1), QPoint(r.right(), r.bottom())); - painter->drawLine(QPoint(r.left() + 1, r.top()), QPoint(r.right() - 1, r.top())); - highlightOutline.setAlpha(60); - painter->setPen(QPen(highlightOutline, 0)); - painter->drawPoint(r.topLeft()); - painter->drawPoint(r.topRight()); - - QPalette pal = mbi->palette; - uint alignment = Qt::AlignCenter | Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine; - if (!styleHint(SH_UnderlineShortcut, mbi, widget)) { - alignment |= Qt::TextHideMnemonic; - } - pal.setBrush(QPalette::Text, dis ? Qt::gray : QColor(0, 0, 0, 60)); - drawItemText(painter, item.rect.translated(0, 1), alignment, pal, mbi->state & State_Enabled, mbi->text, QPalette::Text); - pal.setBrush(QPalette::Text, dis ? Qt::gray : Qt::white); - drawItemText(painter, item.rect, alignment, pal, mbi->state & State_Enabled, mbi->text, QPalette::Text); - } - } - painter->restore(); - break; - - case CE_ComboBoxLabel: - if (const QStyleOptionComboBox * cb = qstyleoption_cast(option)) { - if (panelWidget(widget)) { - painter->save(); - QRect editRect = subControlRect(CC_ComboBox, cb, SC_ComboBoxEditField, widget); - QPalette customPal = cb->palette; - bool drawIcon = !(widget && widget->property("hideicon").toBool()); - - if (!cb->currentIcon.isNull() && drawIcon) { - QIcon::Mode mode = cb->state & State_Enabled ? QIcon::Normal - : QIcon::Disabled; - QPixmap pixmap = cb->currentIcon.pixmap(cb->iconSize, mode); - QRect iconRect(editRect); - iconRect.setWidth(cb->iconSize.width() + 4); - iconRect = alignedRect(cb->direction, - Qt::AlignLeft | Qt::AlignVCenter, - iconRect.size(), editRect); - if (cb->editable) { - painter->fillRect(iconRect, customPal.brush(QPalette::Base)); - } - drawItemPixmap(painter, iconRect, Qt::AlignCenter, pixmap); - - if (cb->direction == Qt::RightToLeft) { - editRect.translate(-4 - cb->iconSize.width(), 0); - } else { - editRect.translate(cb->iconSize.width() + 4, 0); - } - - // Reserve some space for the down-arrow - editRect.adjust(0, 0, -13, 0); - } - - QLatin1Char asterisk('*'); - int elideWidth = editRect.width(); - - bool notElideAsterisk = widget && widget->property("notelideasterisk").toBool() - && cb->currentText.endsWith(asterisk) - && option->fontMetrics.width(cb->currentText) > elideWidth; - - QString text; - if (notElideAsterisk) { - elideWidth -= option->fontMetrics.width(asterisk); - text = asterisk; - } - text.prepend(option->fontMetrics.elidedText(cb->currentText, Qt::ElideRight, elideWidth)); - - if ((option->state & State_Enabled)) { - painter->setPen(QColor(0, 0, 0, 70)); - painter->drawText(editRect.adjusted(1, 0, -1, 0), Qt::AlignLeft | Qt::AlignVCenter, text); - } else { - painter->setOpacity(0.8); - } - painter->setPen(Utils::StyleHelper::panelTextColor()); - painter->drawText(editRect.adjusted(1, 0, -1, 0), Qt::AlignLeft | Qt::AlignVCenter, text); - - painter->restore(); - } else { - QProxyStyle::drawControl(element, option, painter, widget); - } - } - break; - - case CE_SizeGrip: - { - painter->save(); - QColor dark = Qt::white; - dark.setAlphaF(0.1); - int x, y, w, h; - option->rect.getRect(&x, &y, &w, &h); - int sw = qMin(h, w); - if (h > w) { - painter->translate(0, h - w); - } else { - painter->translate(w - h, 0); - } - int sx = x; - int sy = y; - int s = 4; - painter->setPen(dark); - if (option->direction == Qt::RightToLeft) { - sx = x + sw; - for (int i = 0; i < 4; ++i) { - painter->drawLine(x, sy, sx, sw); - sx -= s; - sy += s; - } - } else { - for (int i = 0; i < 4; ++i) { - painter->drawLine(sx, sw, sw, sy); - sx += s; - sy += s; - } - } - painter->restore(); - } - break; - - case CE_MenuBarEmptyArea: - { - Utils::StyleHelper::menuGradient(painter, option->rect, option->rect); - painter->save(); - painter->setPen(Utils::StyleHelper::borderColor()); - painter->drawLine(option->rect.bottomLeft(), option->rect.bottomRight()); - painter->restore(); - } - break; - - case CE_ToolBar: - { - QRect rect = option->rect; - bool horizontal = option->state & State_Horizontal; - rect = option->rect; - - // Map offset for global window gradient - QPoint offset = widget->window()->mapToGlobal(option->rect.topLeft()) - - widget->mapToGlobal(option->rect.topLeft()); - QRect gradientSpan; - if (widget) { - gradientSpan = QRect(offset, widget->window()->size()); - } - - bool drawLightColored = lightColored(widget); - if (horizontal) { - Utils::StyleHelper::horizontalGradient(painter, gradientSpan, rect, drawLightColored); - } else { - Utils::StyleHelper::verticalGradient(painter, gradientSpan, rect, drawLightColored); - } - - if (!drawLightColored) { - painter->setPen(Utils::StyleHelper::borderColor()); - } else { - painter->setPen(QColor(0x888888)); - } - - if (horizontal) { - // Note: This is a hack to determine if the - // toolbar should draw the top or bottom outline - // (needed for the find toolbar for instance) - QColor lighter(Utils::StyleHelper::sidebarHighlight()); - if (drawLightColored) { - lighter = QColor(255, 255, 255, 180); - } - if (widget && widget->property("topBorder").toBool()) { - painter->drawLine(rect.topLeft(), rect.topRight()); - painter->setPen(lighter); - painter->drawLine(rect.topLeft() + QPoint(0, 1), rect.topRight() + QPoint(0, 1)); - } else { - painter->drawLine(rect.bottomLeft(), rect.bottomRight()); - painter->setPen(lighter); - painter->drawLine(rect.topLeft(), rect.topRight()); - } - } else { - painter->drawLine(rect.topLeft(), rect.bottomLeft()); - painter->drawLine(rect.topRight(), rect.bottomRight()); - } - } - break; - - default: - QProxyStyle::drawControl(element, option, painter, widget); - break; - } -} - -void ManhattanStyle::drawComplexControl(ComplexControl control, const QStyleOptionComplex *option, - QPainter *painter, const QWidget *widget) const -{ - if (!panelWidget(widget)) { - return QProxyStyle::drawComplexControl(control, option, painter, widget); - } - - QRect rect = option->rect; - switch (control) { - case CC_ToolButton: - if (const QStyleOptionToolButton * toolbutton = qstyleoption_cast(option)) { - bool reverse = option->direction == Qt::RightToLeft; - bool drawborder = (widget && widget->property("showborder").toBool()); - - if (drawborder) { - drawButtonSeparator(painter, rect, reverse); - } - - QRect button, menuarea; - button = subControlRect(control, toolbutton, SC_ToolButton, widget); - menuarea = subControlRect(control, toolbutton, SC_ToolButtonMenu, widget); - - State bflags = toolbutton->state; - if (bflags & State_AutoRaise) { - if (!(bflags & State_MouseOver)) { - bflags &= ~State_Raised; - } - } - - State mflags = bflags; - if (toolbutton->state & State_Sunken) { - if (toolbutton->activeSubControls & SC_ToolButton) { - bflags |= State_Sunken; - } - if (toolbutton->activeSubControls & SC_ToolButtonMenu) { - mflags |= State_Sunken; - } - } - - QStyleOption tool(0); - tool.palette = toolbutton->palette; - if (toolbutton->subControls & SC_ToolButton) { - tool.rect = button; - tool.state = bflags; - drawPrimitive(PE_PanelButtonTool, &tool, painter, widget); - } - - QStyleOptionToolButton label = *toolbutton; - - label.palette = panelPalette(option->palette, lightColored(widget)); - int fw = pixelMetric(PM_DefaultFrameWidth, option, widget); - label.rect = button.adjusted(fw, fw, -fw, -fw); - - drawControl(CE_ToolButtonLabel, &label, painter, widget); - - if (toolbutton->subControls & SC_ToolButtonMenu) { - tool.state = mflags; - tool.rect = menuarea.adjusted(1, 1, -1, -1); - if (mflags & (State_Sunken | State_On | State_Raised)) { - painter->setPen(Qt::gray); - painter->drawLine(tool.rect.topLeft(), tool.rect.bottomLeft()); - if (mflags & (State_Sunken)) { - QColor shade(0, 0, 0, 50); - painter->fillRect(tool.rect.adjusted(0, -1, 1, 1), shade); - } else if (!Utils::HostOsInfo::isMacHost() && (mflags & State_MouseOver)) { - QColor shade(255, 255, 255, 50); - painter->fillRect(tool.rect.adjusted(0, -1, 1, 1), shade); - } - } - tool.rect = tool.rect.adjusted(2, 2, -2, -2); - drawPrimitive(PE_IndicatorArrowDown, &tool, painter, widget); - } else if (toolbutton->features & QStyleOptionToolButton::HasMenu - && !widget->property("noArrow").toBool()) { - int arrowSize = 6; - QRect ir = toolbutton->rect.adjusted(1, 1, -1, -1); - QStyleOptionToolButton newBtn = *toolbutton; - newBtn.palette = panelPalette(option->palette); - newBtn.rect = QRect(ir.right() - arrowSize - 1, - ir.height() - arrowSize - 2, arrowSize, arrowSize); - drawPrimitive(PE_IndicatorArrowDown, &newBtn, painter, widget); - } - } - break; - - case CC_ComboBox: - if (const QStyleOptionComboBox * cb = qstyleoption_cast(option)) { - painter->save(); - bool isEmpty = cb->currentText.isEmpty() && cb->currentIcon.isNull(); - bool reverse = option->direction == Qt::RightToLeft; - bool drawborder = !(widget && widget->property("hideborder").toBool()); - bool alignarrow = !(widget && widget->property("alignarrow").toBool()); - - if (drawborder) { - drawButtonSeparator(painter, rect, reverse); - } - - QStyleOption toolbutton = *option; - if (isEmpty) { - toolbutton.state &= ~(State_Enabled | State_Sunken); - } - painter->save(); - if (drawborder) { - painter->setClipRect(toolbutton.rect.adjusted(0, 0, -2, 0)); - } - drawPrimitive(PE_PanelButtonTool, &toolbutton, painter, widget); - painter->restore(); - // Draw arrow - int menuButtonWidth = 12; - int left = !reverse ? rect.right() - menuButtonWidth : rect.left(); - int right = !reverse ? rect.right() : rect.left() + menuButtonWidth; - QRect arrowRect((left + right) / 2 + (reverse ? 6 : -6), rect.center().y() - 3, 9, 9); - - if (!alignarrow) { - int labelwidth = option->fontMetrics.width(cb->currentText); - if (reverse) { - arrowRect.moveLeft(qMax(rect.width() - labelwidth - menuButtonWidth - 2, 4)); - } else { - arrowRect.moveLeft(qMin(labelwidth + menuButtonWidth - 2, rect.width() - menuButtonWidth - 4)); - } - } - if (option->state & State_On) { - arrowRect.translate(QProxyStyle::pixelMetric(PM_ButtonShiftHorizontal, option, widget), - QProxyStyle::pixelMetric(PM_ButtonShiftVertical, option, widget)); - } - - QStyleOption arrowOpt = *option; - arrowOpt.rect = arrowRect; - if (isEmpty) { - arrowOpt.state &= ~(State_Enabled | State_Sunken); - } - - if (styleHint(SH_ComboBox_Popup, option, widget)) { - arrowOpt.rect.translate(0, -3); - drawPrimitive(PE_IndicatorArrowUp, &arrowOpt, painter, widget); - arrowOpt.rect.translate(0, 6); - drawPrimitive(PE_IndicatorArrowDown, &arrowOpt, painter, widget); - } else { - drawPrimitive(PE_IndicatorArrowDown, &arrowOpt, painter, widget); - } - - painter->restore(); - } - break; - - default: - QProxyStyle::drawComplexControl(control, option, painter, widget); - break; - } -} - -void ManhattanStyle::drawButtonSeparator(QPainter *painter, const QRect &rect, bool reverse) const -{ - QLinearGradient grad(rect.topRight(), rect.bottomRight()); - - grad.setColorAt(0, QColor(255, 255, 255, 20)); - grad.setColorAt(0.4, QColor(255, 255, 255, 60)); - grad.setColorAt(0.7, QColor(255, 255, 255, 50)); - grad.setColorAt(1, QColor(255, 255, 255, 40)); - painter->setPen(QPen(grad, 0)); - painter->drawLine(rect.topRight(), rect.bottomRight()); - grad.setColorAt(0, QColor(0, 0, 0, 30)); - grad.setColorAt(0.4, QColor(0, 0, 0, 70)); - grad.setColorAt(0.7, QColor(0, 0, 0, 70)); - grad.setColorAt(1, QColor(0, 0, 0, 40)); - painter->setPen(QPen(grad, 0)); - if (!reverse) { - painter->drawLine(rect.topRight() - QPoint(1, 0), rect.bottomRight() - QPoint(1, 0)); - } else { - painter->drawLine(rect.topLeft(), rect.bottomLeft()); - } -} diff --git a/ground/gcs/src/plugins/coreplugin/manhattanstyle.h b/ground/gcs/src/plugins/coreplugin/manhattanstyle.h deleted file mode 100644 index ec00074129..0000000000 --- a/ground/gcs/src/plugins/coreplugin/manhattanstyle.h +++ /dev/null @@ -1,80 +0,0 @@ -/** - ****************************************************************************** - * - * @file manhattanstyle.h - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @addtogroup GCSPlugins GCS Plugins - * @{ - * @addtogroup CorePlugin Core Plugin - * @{ - * @brief The Core GCS plugin - *****************************************************************************/ -/* - * 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 MANHATTANSTYLE_H -#define MANHATTANSTYLE_H - -#include "core_global.h" - -#include - -class ManhattanStylePrivate; - -class CORE_EXPORT ManhattanStyle : public QProxyStyle { - Q_OBJECT - -public: - explicit ManhattanStyle(const QString &baseStyleName); - - ~ManhattanStyle(); - - void drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget = 0) const; - void drawControl(ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget = 0) const; - void drawComplexControl(ComplexControl control, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget = 0) const; - - QSize sizeFromContents(ContentsType type, const QStyleOption *option, const QSize &size, const QWidget *widget) const; - QRect subElementRect(SubElement element, const QStyleOption *option, const QWidget *widget) const; - QRect subControlRect(ComplexControl cc, const QStyleOptionComplex *opt, SubControl sc, const QWidget *widget) const; - - SubControl hitTestComplexControl(ComplexControl control, const QStyleOptionComplex *option, const QPoint &pos, const QWidget *widget = 0) const; - QPixmap standardPixmap(StandardPixmap standardPixmap, const QStyleOption *opt, const QWidget *widget = 0) const; - int styleHint(StyleHint hint, const QStyleOption *option = 0, const QWidget *widget = 0, QStyleHintReturn *returnData = 0) const; - QRect itemRect(QPainter *p, const QRect &r, int flags, bool enabled, const QPixmap *pixmap, const QString &text, int len = -1) const; - QPixmap generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap, const QStyleOption *opt) const; - - int pixelMetric(PixelMetric metric, const QStyleOption *option = 0, const QWidget *widget = 0) const; - - QPalette standardPalette() const; - - void polish(QWidget *widget); - void polish(QPalette &pal); - void polish(QApplication *app); - - void unpolish(QWidget *widget); - void unpolish(QApplication *app); - -protected slots: - QIcon standardIconImplementation(StandardPixmap standardIcon, const QStyleOption *option, const QWidget *widget) const; - -private: - void drawButtonSeparator(QPainter *painter, const QRect &rect, bool reverse) const; - - ManhattanStylePrivate *d; -}; - -#endif // MANHATTANSTYLE_H diff --git a/ground/gcs/src/plugins/coreplugin/modemanager.cpp b/ground/gcs/src/plugins/coreplugin/modemanager.cpp index 79c28779a5..875683169b 100644 --- a/ground/gcs/src/plugins/coreplugin/modemanager.cpp +++ b/ground/gcs/src/plugins/coreplugin/modemanager.cpp @@ -28,8 +28,6 @@ #include "modemanager.h" -#include "fancytabwidget.h" -#include "fancyactionbar.h" #include "utils/mytabwidget.h" #include "icore.h" #include "mainwindow.h" diff --git a/ground/gcs/src/plugins/coreplugin/modemanager.h b/ground/gcs/src/plugins/coreplugin/modemanager.h index 6568f5473a..fc2cf44528 100644 --- a/ground/gcs/src/plugins/coreplugin/modemanager.h +++ b/ground/gcs/src/plugins/coreplugin/modemanager.h @@ -48,8 +48,6 @@ class Command; class IMode; namespace Internal { -class FancyTabWidget; -class FancyActionBar; class MainWindow; } // namespace Internal diff --git a/ground/gcs/src/plugins/coreplugin/rightpane.cpp b/ground/gcs/src/plugins/coreplugin/rightpane.cpp deleted file mode 100644 index a6d93dbaf7..0000000000 --- a/ground/gcs/src/plugins/coreplugin/rightpane.cpp +++ /dev/null @@ -1,246 +0,0 @@ -/** - ****************************************************************************** - * - * @file rightpane.cpp - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @addtogroup GCSPlugins GCS Plugins - * @{ - * @addtogroup CorePlugin Core Plugin - * @{ - * @brief The Core GCS plugin - *****************************************************************************/ -/* - * 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 "rightpane.h" - -#include -#include - -#include - -#include -#include -#include -#include - - -using namespace Core; -using namespace Core::Internal; - -RightPanePlaceHolder *RightPanePlaceHolder::m_current = 0; - -RightPanePlaceHolder *RightPanePlaceHolder::current() -{ - return m_current; -} - -RightPanePlaceHolder::RightPanePlaceHolder(Core::IMode *mode, QWidget *parent) - : QWidget(parent), m_mode(mode) -{ - setLayout(new QVBoxLayout); - layout()->setMargin(0); - connect(Core::ModeManager::instance(), SIGNAL(currentModeChanged(Core::IMode *)), - this, SLOT(currentModeChanged(Core::IMode *))); -} - -RightPanePlaceHolder::~RightPanePlaceHolder() -{ - if (m_current == this) { - RightPaneWidget::instance()->setParent(0); - RightPaneWidget::instance()->hide(); - } -} - -void RightPanePlaceHolder::applyStoredSize(int width) -{ - if (width) { - QSplitter *splitter = qobject_cast(parentWidget()); - if (splitter) { - // A splitter we need to resize the splitter sizes - QList sizes = splitter->sizes(); - int index = splitter->indexOf(this); - int diff = width - sizes.at(index); - int adjust = sizes.count() > 1 ? (diff / (sizes.count() - 1)) : 0; - for (int i = 0; i < sizes.count(); ++i) { - if (i != index) { - sizes[i] -= adjust; - } - } - sizes[index] = width; - splitter->setSizes(sizes); - } else { - QSize s = size(); - s.setWidth(width); - resize(s); - } - } -} - -// This function does work even though the order in which -// the placeHolder get the signal is undefined. -// It does ensure that after all PlaceHolders got the signal -// m_current points to the current PlaceHolder, or zero if there -// is no PlaceHolder in this mode -// And that the parent of the RightPaneWidget gets the correct parent -void RightPanePlaceHolder::currentModeChanged(Core::IMode *mode) -{ - if (m_current == this) { - m_current = 0; - RightPaneWidget::instance()->setParent(0); - RightPaneWidget::instance()->hide(); - } - if (m_mode == mode) { - m_current = this; - - int width = RightPaneWidget::instance()->storedWidth(); - - layout()->addWidget(RightPaneWidget::instance()); - RightPaneWidget::instance()->show(); - - applyStoredSize(width); - setVisible(RightPaneWidget::instance()->isShown()); - } -} - -///// -// RightPaneWidget -///// - - -RightPaneWidget *RightPaneWidget::m_instance = 0; - -RightPaneWidget::RightPaneWidget() - : m_shown(true), m_width(0) -{ - m_instance = this; - - QVBoxLayout *layout = new QVBoxLayout; - layout->setMargin(0); - setLayout(layout); - - ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); - - BaseRightPaneWidget *rpw = pm->getObject(); - if (rpw) { - layout->addWidget(rpw->widget()); - } - connect(pm, SIGNAL(objectAdded(QObject *)), - this, SLOT(objectAdded(QObject *))); - connect(pm, SIGNAL(aboutToRemoveObject(QObject *)), - this, SLOT(aboutToRemoveObject(QObject *))); -} - -RightPaneWidget::~RightPaneWidget() -{ - m_instance = 0; -} - -void RightPaneWidget::objectAdded(QObject *obj) -{ - BaseRightPaneWidget *rpw = qobject_cast(obj); - - if (rpw) { - layout()->addWidget(rpw->widget()); - setFocusProxy(rpw->widget()); - } -} - -void RightPaneWidget::aboutToRemoveObject(QObject *obj) -{ - BaseRightPaneWidget *rpw = qobject_cast(obj); - - if (rpw) { - delete rpw->widget(); - } -} - -RightPaneWidget *RightPaneWidget::instance() -{ - return m_instance; -} - -int RightPaneWidget::storedWidth() -{ - return m_width; -} - -void RightPaneWidget::resizeEvent(QResizeEvent *re) -{ - if (m_width && re->size().width()) { - m_width = re->size().width(); - } - QWidget::resizeEvent(re); -} - -void RightPaneWidget::saveSettings(QSettings *settings) -{ - settings->setValue("RightPane/Visible", isShown()); - settings->setValue("RightPane/Width", m_width); -} - -void RightPaneWidget::readSettings(QSettings *settings) -{ - if (settings->contains("RightPane/Visible")) { - setShown(settings->value("RightPane/Visible").toBool()); - } else { - setShown(false); // TODO set to false - } - - if (settings->contains("RightPane/Width")) { - m_width = settings->value("RightPane/Width").toInt(); - if (!m_width) { - m_width = 500; - } - } else { - m_width = 500; // pixel - } - // Apply - if (RightPanePlaceHolder::m_current) { - RightPanePlaceHolder::m_current->applyStoredSize(m_width); - } -} - -void RightPaneWidget::setShown(bool b) -{ - if (RightPanePlaceHolder::m_current) { - RightPanePlaceHolder::m_current->setVisible(b); - } - m_shown = b; -} - -bool RightPaneWidget::isShown() -{ - return m_shown; -} - -///// -// BaseRightPaneWidget -///// - -BaseRightPaneWidget::BaseRightPaneWidget(QWidget *widget) -{ - m_widget = widget; -} - -BaseRightPaneWidget::~BaseRightPaneWidget() -{} - -QWidget *BaseRightPaneWidget::widget() const -{ - return m_widget; -} diff --git a/ground/gcs/src/plugins/coreplugin/rightpane.h b/ground/gcs/src/plugins/coreplugin/rightpane.h deleted file mode 100644 index e1a9110a6f..0000000000 --- a/ground/gcs/src/plugins/coreplugin/rightpane.h +++ /dev/null @@ -1,114 +0,0 @@ -/** - ****************************************************************************** - * - * @file rightpane.h - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @addtogroup GCSPlugins GCS Plugins - * @{ - * @addtogroup CorePlugin Core Plugin - * @{ - * @brief The Core GCS plugin - *****************************************************************************/ -/* - * 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 RIGHTPANE_H -#define RIGHTPANE_H - -#include "core_global.h" - -#include - -QT_BEGIN_NAMESPACE -class QSettings; -QT_END_NAMESPACE - -namespace Core { -class IMode; -class RightPaneWidget; - -// TODO: The right pane works only for the help plugin atm. It can't cope -// with more than one plugin publishing objects they want in the right pane -// For that the API would need to be different. (Might be that instead of -// adding objects to the pool, there should be a method -// RightPaneWidget::setWidget(QWidget *w) Anyway if a second plugin wants to -// show something there, redesign this API - -class CORE_EXPORT RightPanePlaceHolder : public QWidget { - friend class Core::RightPaneWidget; - Q_OBJECT - -public: - RightPanePlaceHolder(Core::IMode *mode, QWidget *parent = 0); - ~RightPanePlaceHolder(); - static RightPanePlaceHolder *current(); - -private slots: - void currentModeChanged(Core::IMode *); - -private: - void applyStoredSize(int width); - Core::IMode *m_mode; - static RightPanePlaceHolder *m_current; -}; - - -class CORE_EXPORT BaseRightPaneWidget : public QObject { - Q_OBJECT - -public: - BaseRightPaneWidget(QWidget *widget); - ~BaseRightPaneWidget(); - QWidget *widget() const; - -private: - QWidget *m_widget; -}; - - -class CORE_EXPORT RightPaneWidget : public QWidget { - Q_OBJECT - -public: - RightPaneWidget(); - ~RightPaneWidget(); - - void saveSettings(QSettings *settings); - void readSettings(QSettings *settings); - - bool isShown(); - void setShown(bool b); - - static RightPaneWidget *instance(); - - int storedWidth(); - -protected: - void resizeEvent(QResizeEvent *); - -private slots: - void objectAdded(QObject *obj); - void aboutToRemoveObject(QObject *obj); - -private: - bool m_shown; - int m_width; - static RightPaneWidget *m_instance; -}; -} // namespace Core - -#endif // RIGHTPANE_H diff --git a/ground/gcs/src/plugins/coreplugin/sidebar.cpp b/ground/gcs/src/plugins/coreplugin/sidebar.cpp deleted file mode 100644 index 0661e4aa94..0000000000 --- a/ground/gcs/src/plugins/coreplugin/sidebar.cpp +++ /dev/null @@ -1,392 +0,0 @@ -/** - ****************************************************************************** - * - * @file sidebar.cpp - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @addtogroup GCSPlugins GCS Plugins - * @{ - * @addtogroup CorePlugin Core Plugin - * @{ - * @brief The Core GCS plugin - *****************************************************************************/ -/* - * 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 "sidebar.h" -#include "imode.h" -#include "modemanager.h" - -#include "actionmanager/actionmanager.h" - -#include -#include -#include -#include -#include -#include -#include - -using namespace Core; -using namespace Core::Internal; - -SideBarItem::~SideBarItem() -{ - delete m_widget; -} - -SideBar::SideBar(QList itemList, - QList defaultVisible) -{ - setOrientation(Qt::Vertical); - foreach(SideBarItem * item, itemList) { - const QString title = item->widget()->windowTitle(); - - m_itemMap.insert(title, item); - } - foreach(SideBarItem * item, defaultVisible) { - if (!itemList.contains(item)) { - continue; - } - m_defaultVisible.append(item->widget()->windowTitle()); - } - - m_availableItems = m_itemMap.keys(); -} - -SideBar::~SideBar() -{ - qDeleteAll(m_itemMap.values()); -} - -QStringList SideBar::availableItems() const -{ - return m_availableItems; -} - -void SideBar::makeItemAvailable(SideBarItem *item) -{ - QMap::const_iterator it = m_itemMap.constBegin(); - while (it != m_itemMap.constEnd()) { - if (it.value() == item) { - m_availableItems.append(it.key()); - qSort(m_availableItems); - break; - } - ++it; - } -} - -SideBarItem *SideBar::item(const QString &title) -{ - if (m_itemMap.contains(title)) { - m_availableItems.removeAll(title); - return m_itemMap.value(title, NULL); - } - return 0; -} - -SideBarWidget *SideBar::insertSideBarWidget(int position, const QString &title) -{ - SideBarWidget *item = new SideBarWidget(this, title); - - connect(item, SIGNAL(splitMe()), this, SLOT(splitSubWidget())); - connect(item, SIGNAL(closeMe()), this, SLOT(closeSubWidget())); - connect(item, SIGNAL(currentWidgetChanged()), this, SLOT(updateWidgets())); - insertWidget(position, item); - m_widgets.insert(position, item); - updateWidgets(); - return item; -} - -void SideBar::removeSideBarWidget(SideBarWidget *widget) -{ - widget->removeCurrentItem(); - m_widgets.removeOne(widget); - widget->hide(); - widget->deleteLater(); -} - -void SideBar::splitSubWidget() -{ - SideBarWidget *original = qobject_cast(sender()); - int pos = indexOf(original) + 1; - - insertSideBarWidget(pos); - updateWidgets(); -} - -void SideBar::closeSubWidget() -{ - if (m_widgets.count() != 1) { - SideBarWidget *widget = qobject_cast(sender()); - if (!widget) { - return; - } - removeSideBarWidget(widget); - updateWidgets(); - } -} - -void SideBar::updateWidgets() -{ - foreach(SideBarWidget * i, m_widgets) - i->updateAvailableItems(); -} - -void SideBar::saveSettings(QSettings *settings) -{ - QStringList views; - - for (int i = 0; i < m_widgets.count(); ++i) { - views.append(m_widgets.at(i)->currentItemTitle()); - } - settings->setValue("HelpSideBar/Views", views); - settings->setValue("HelpSideBar/Visible", true); // isVisible()); - settings->setValue("HelpSideBar/VerticalPosition", saveState()); - settings->setValue("HelpSideBar/Width", width()); -} - -void SideBar::readSettings(QSettings *settings) -{ - foreach(SideBarWidget * widget, m_widgets) - removeSideBarWidget(widget); - - if (settings->contains("HelpSideBar/Views")) { - QStringList views = settings->value("HelpSideBar/Views").toStringList(); - if (views.count()) { - foreach(const QString &title, views) - insertSideBarWidget(m_widgets.count(), title); - } else { - insertSideBarWidget(0); - } - } else { - foreach(const QString &title, m_defaultVisible) - insertSideBarWidget(m_widgets.count(), title); - } - - if (settings->contains("HelpSideBar/Visible")) { - setVisible(settings->value("HelpSideBar/Visible").toBool()); - } - - if (settings->contains("HelpSideBar/VerticalPosition")) { - restoreState(settings->value("HelpSideBar/VerticalPosition").toByteArray()); - } - - if (settings->contains("HelpSideBar/Width")) { - QSize s = size(); - s.setWidth(settings->value("HelpSideBar/Width").toInt()); - resize(s); - } -} - -void SideBar::activateItem(SideBarItem *item) -{ - QMap::const_iterator it = m_itemMap.constBegin(); - QString title; - while (it != m_itemMap.constEnd()) { - if (it.value() == item) { - title = it.key(); - break; - } - ++it; - } - - if (title.isEmpty()) { - return; - } - - for (int i = 0; i < m_widgets.count(); ++i) { - if (m_widgets.at(i)->currentItemTitle() == title) { - item->widget()->setFocus(); - return; - } - } - - SideBarWidget *widget = m_widgets.first(); - widget->setCurrentItem(title); - updateWidgets(); - item->widget()->setFocus(); -} - -void SideBar::setShortcutMap(const QMap &shortcutMap) -{ - m_shortcutMap = shortcutMap; -} - -QMap SideBar::shortcutMap() const -{ - return m_shortcutMap; -} - - -SideBarWidget::SideBarWidget(SideBar *sideBar, const QString &title) - : m_currentItem(0) - , m_sideBar(sideBar) -{ - m_comboBox = new ComboBox(this); - m_comboBox->setMinimumContentsLength(15); - - m_toolbar = new QToolBar(this); - m_toolbar->setContentsMargins(0, 0, 0, 0); - m_toolbar->addWidget(m_comboBox); - - m_splitButton = new QToolButton; - m_splitButton->setIcon(QIcon(":/core/images/splitbutton_horizontal.png")); - m_splitButton->setToolTip(tr("Split")); - connect(m_splitButton, SIGNAL(clicked(bool)), this, SIGNAL(splitMe())); - - m_closeButton = new QToolButton; - m_closeButton->setIcon(QIcon(":/core/images/closebutton.png")); - m_closeButton->setToolTip(tr("Close")); - - connect(m_closeButton, SIGNAL(clicked(bool)), this, SIGNAL(closeMe())); - - QWidget *spacerItem = new QWidget(this); - spacerItem->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); - m_toolbar->addWidget(spacerItem); - m_splitAction = m_toolbar->addWidget(m_splitButton); - m_toolbar->addWidget(m_closeButton); - - QVBoxLayout *lay = new QVBoxLayout(); - lay->setMargin(0); - lay->setSpacing(0); - setLayout(lay); - lay->addWidget(m_toolbar); - - const QStringList lst = m_sideBar->availableItems(); - QString t = title; - if (lst.count()) { - m_comboBox->addItems(lst); - m_comboBox->setCurrentIndex(0); - if (t.isEmpty()) { - t = m_comboBox->currentText(); - } - } - setCurrentItem(t); - - connect(m_comboBox, SIGNAL(currentIndexChanged(int)), - this, SLOT(setCurrentIndex(int))); -} - -SideBarWidget::~SideBarWidget() -{} - -QString SideBarWidget::currentItemTitle() const -{ - return m_comboBox->currentText(); -} - -void SideBarWidget::setCurrentItem(const QString &title) -{ - if (!title.isEmpty()) { - int idx = m_comboBox->findText(title); - if (idx < 0) { - idx = 0; - } - bool blocked = m_comboBox->blockSignals(true); - m_comboBox->setCurrentIndex(idx); - m_comboBox->blockSignals(blocked); - } - - SideBarItem *item = m_sideBar->item(title); - if (!item) { - return; - } - removeCurrentItem(); - m_currentItem = item; - layout()->addWidget(m_currentItem->widget()); - - // Add buttons and remember their actions for later removal - foreach(QToolButton * b, m_currentItem->createToolBarWidgets()) - m_addedToolBarActions.append(m_toolbar->insertWidget(m_splitAction, b)); -} - -void SideBarWidget::updateAvailableItems() -{ - bool blocked = m_comboBox->blockSignals(true); - QString current = m_comboBox->currentText(); - - m_comboBox->clear(); - QStringList itms = m_sideBar->availableItems(); - if (!current.isEmpty() && !itms.contains(current)) { - itms.append(current); - } - qSort(itms); - m_comboBox->addItems(itms); - int idx = m_comboBox->findText(current); - if (idx < 0) { - idx = 0; - } - m_comboBox->setCurrentIndex(idx); - m_splitButton->setEnabled(itms.count() > 1); - m_comboBox->blockSignals(blocked); -} - -void SideBarWidget::removeCurrentItem() -{ - if (!m_currentItem) { - return; - } - - QWidget *w = m_currentItem->widget(); - layout()->removeWidget(w); - w->setParent(0); - m_sideBar->makeItemAvailable(m_currentItem); - - // Delete custom toolbar widgets - qDeleteAll(m_addedToolBarActions); - m_addedToolBarActions.clear(); - - m_currentItem = 0; -} - -void SideBarWidget::setCurrentIndex(int) -{ - setCurrentItem(m_comboBox->currentText()); - emit currentWidgetChanged(); -} - -Core::Command *SideBarWidget::command(const QString &title) const -{ - const QMap shortcutMap = m_sideBar->shortcutMap(); - - QMap::const_iterator r = shortcutMap.find(title); - if (r != shortcutMap.end()) { - return r.value(); - } - return 0; -} - - -ComboBox::ComboBox(SideBarWidget *sideBarWidget) - : m_sideBarWidget(sideBarWidget) -{} - -bool ComboBox::event(QEvent *e) -{ - if (e->type() == QEvent::ToolTip) { - QString txt = currentText(); - Core::Command *cmd = m_sideBarWidget->command(txt); - if (cmd) { - txt = tr("Activate %1").arg(txt); - setToolTip(cmd->stringWithAppendedShortcut(txt)); - } else { - setToolTip(txt); - } - } - return QComboBox::event(e); -} diff --git a/ground/gcs/src/plugins/coreplugin/sidebar.h b/ground/gcs/src/plugins/coreplugin/sidebar.h deleted file mode 100644 index 59d7b29ba7..0000000000 --- a/ground/gcs/src/plugins/coreplugin/sidebar.h +++ /dev/null @@ -1,178 +0,0 @@ -/** - ****************************************************************************** - * - * @file sidebar.h - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @addtogroup GCSPlugins GCS Plugins - * @{ - * @addtogroup CorePlugin Core Plugin - * @{ - * @brief The Core GCS plugin - *****************************************************************************/ -/* - * 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 SIDEBAR_H -#define SIDEBAR_H - -#include -#include -#include -#include - -#include - -QT_BEGIN_NAMESPACE -class QSettings; -class QToolBar; -class QAction; -class QToolButton; -QT_END_NAMESPACE - -namespace Core { -class Command; - -namespace Internal { -class SideBarWidget; -class ComboBox; -} // namespace Internal - -/* - * An item in the sidebar. Has a widget that is displayed in the sidebar and - * optionally a list of tool buttons that are added to the toolbar above it. - * The window title of the widget is displayed in the combo box. - * - * The SideBarItem takes ownership over the widget. - */ -class CORE_EXPORT SideBarItem { -public: - SideBarItem(QWidget *widget) - : m_widget(widget) - {} - - virtual ~SideBarItem(); - - QWidget *widget() - { - return m_widget; - } - - /* Should always return a new set of tool buttons. - * - * Workaround since there doesn't seem to be a nice way to remove widgets - * that have been added to a QToolBar without either not deleting the - * associated QAction or causing the QToolButton to be deleted. - */ - virtual QList createToolBarWidgets() - { - return QList(); - } - -private: - QWidget *m_widget; -}; - -class CORE_EXPORT SideBar : public MiniSplitter { - Q_OBJECT -public: - /* - * The SideBar takes ownership of the SideBarItems. - */ - SideBar(QList widgetList, - QList defaultVisible); - ~SideBar(); - - QStringList availableItems() const; - void makeItemAvailable(SideBarItem *item); - SideBarItem *item(const QString &title); - - void saveSettings(QSettings *settings); - void readSettings(QSettings *settings); - - void activateItem(SideBarItem *item); - - void setShortcutMap(const QMap &shortcutMap); - QMap shortcutMap() const; - -private slots: - void splitSubWidget(); - void closeSubWidget(); - void updateWidgets(); - -private: - Internal::SideBarWidget *insertSideBarWidget(int position, - const QString &title = QString()); - void removeSideBarWidget(Internal::SideBarWidget *widget); - - QList m_widgets; - - QMap m_itemMap; - QStringList m_availableItems; - QStringList m_defaultVisible; - QMap m_shortcutMap; -}; - -namespace Internal { -class SideBarWidget : public QWidget { - Q_OBJECT -public: - SideBarWidget(SideBar *sideBar, const QString &title); - ~SideBarWidget(); - - QString currentItemTitle() const; - void setCurrentItem(const QString &title); - - void updateAvailableItems(); - void removeCurrentItem(); - - Core::Command *command(const QString &title) const; - -signals: - void splitMe(); - void closeMe(); - void currentWidgetChanged(); - -private slots: - void setCurrentIndex(int); - -private: - ComboBox *m_comboBox; - SideBarItem *m_currentItem; - QToolBar *m_toolbar; - QAction *m_splitAction; - QList m_addedToolBarActions; - SideBar *m_sideBar; - QToolButton *m_splitButton; - QToolButton *m_closeButton; -}; - -class ComboBox : public QComboBox { - Q_OBJECT - -public: - ComboBox(SideBarWidget *sideBarWidget); - -protected: - bool event(QEvent *event); - -private: - SideBarWidget *m_sideBarWidget; -}; -} // namespace Internal -} // namespace Core - -#endif // SIDEBAR_H diff --git a/ground/gcs/src/plugins/coreplugin/styleanimator.cpp b/ground/gcs/src/plugins/coreplugin/styleanimator.cpp deleted file mode 100644 index 9187ee9b05..0000000000 --- a/ground/gcs/src/plugins/coreplugin/styleanimator.cpp +++ /dev/null @@ -1,158 +0,0 @@ -/** - ****************************************************************************** - * - * @file styleanimator.cpp - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @addtogroup GCSPlugins GCS Plugins - * @{ - * @addtogroup CorePlugin Core Plugin - * @{ - * @brief The Core GCS plugin - *****************************************************************************/ -/* - * 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 "styleanimator.h" - -#include - -Animation *StyleAnimator::widgetAnimation(const QWidget *widget) const -{ - if (!widget) { - return 0; - } - foreach(Animation * a, animations) { - if (a->widget() == widget) { - return a; - } - } - return 0; -} - -void Animation::paint(QPainter *painter, const QStyleOption *option) -{ - Q_UNUSED(option) - Q_UNUSED(painter) -} - -void Animation::drawBlendedImage(QPainter *painter, QRect rect, float alpha) -{ - if (m_secondaryImage.isNull() || m_primaryImage.isNull()) { - return; - } - - if (m_tempImage.isNull()) { - m_tempImage = m_secondaryImage; - } - - const int a = qRound(alpha * 256); - const int ia = 256 - a; - const int sw = m_primaryImage.width(); - const int sh = m_primaryImage.height(); - const int bpl = m_primaryImage.bytesPerLine(); - switch (m_primaryImage.depth()) { - case 32: - { - uchar *mixed_data = m_tempImage.bits(); - const uchar *back_data = m_primaryImage.bits(); - const uchar *front_data = m_secondaryImage.bits(); - for (int sy = 0; sy < sh; sy++) { - quint32 *mixed = (quint32 *)mixed_data; - const quint32 *back = (const quint32 *)back_data; - const quint32 *front = (const quint32 *)front_data; - for (int sx = 0; sx < sw; sx++) { - quint32 bp = back[sx]; - quint32 fp = front[sx]; - mixed[sx] = qRgba((qRed(bp) * ia + qRed(fp) * a) >> 8, - (qGreen(bp) * ia + qGreen(fp) * a) >> 8, - (qBlue(bp) * ia + qBlue(fp) * a) >> 8, - (qAlpha(bp) * ia + qAlpha(fp) * a) >> 8); - } - mixed_data += bpl; - back_data += bpl; - front_data += bpl; - } - } - default: - break; - } - painter->drawImage(rect, m_tempImage); -} - -void Transition::paint(QPainter *painter, const QStyleOption *option) -{ - float alpha = 1.0; - - if (m_duration > 0) { - QTime current = QTime::currentTime(); - - if (m_startTime > current) { - m_startTime = current; - } - - int timeDiff = m_startTime.msecsTo(current); - alpha = timeDiff / (float)m_duration; - if (timeDiff > m_duration) { - m_running = false; - alpha = 1.0; - } - } else { - m_running = false; - } - drawBlendedImage(painter, option->rect, alpha); -} - -void StyleAnimator::timerEvent(QTimerEvent *) -{ - for (int i = animations.size() - 1; i >= 0; --i) { - if (animations[i]->widget()) { - animations[i]->widget()->update(); - } - - if (!animations[i]->widget() || - !animations[i]->widget()->isEnabled() || - !animations[i]->widget()->isVisible() || - animations[i]->widget()->window()->isMinimized() || - !animations[i]->running()) { - Animation *a = animations.takeAt(i); - delete a; - } - } - if (animations.size() == 0 && animationTimer.isActive()) { - animationTimer.stop(); - } -} - -void StyleAnimator::stopAnimation(const QWidget *w) -{ - for (int i = animations.size() - 1; i >= 0; --i) { - if (animations[i]->widget() == w) { - Animation *a = animations.takeAt(i); - delete a; - break; - } - } -} - -void StyleAnimator::startAnimation(Animation *t) -{ - stopAnimation(t->widget()); - animations.append(t); - if (animations.size() > 0 && !animationTimer.isActive()) { - animationTimer.start(35, this); - } -} diff --git a/ground/gcs/src/plugins/coreplugin/styleanimator.h b/ground/gcs/src/plugins/coreplugin/styleanimator.h deleted file mode 100644 index 48c9fe8e91..0000000000 --- a/ground/gcs/src/plugins/coreplugin/styleanimator.h +++ /dev/null @@ -1,127 +0,0 @@ -/** - ****************************************************************************** - * - * @file styleanimator.h - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @addtogroup GCSPlugins GCS Plugins - * @{ - * @addtogroup CorePlugin Core Plugin - * @{ - * @brief The Core GCS plugin - *****************************************************************************/ -/* - * 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 ANIMATION_H -#define ANIMATION_H - -#include -#include -#include -#include -#include -#include - -/* - * This is a set of helper classes to allow for widget animations in - * the style. Its mostly taken from Vista style so it should be fully documented - * there. - * - */ - -class Animation { -public: - Animation() : m_running(true) {} - virtual ~Animation() {} - QWidget *widget() const - { - return m_widget; - } - bool running() const - { - return m_running; - } - const QTime &startTime() const - { - return m_startTime; - } - void setRunning(bool val) - { - m_running = val; - } - void setWidget(QWidget *widget) - { - m_widget = widget; - } - void setStartTime(const QTime &startTime) - { - m_startTime = startTime; - } - virtual void paint(QPainter *painter, const QStyleOption *option); - -protected: - void drawBlendedImage(QPainter *painter, QRect rect, float value); - QTime m_startTime; - QPointer m_widget; - QImage m_primaryImage; - QImage m_secondaryImage; - QImage m_tempImage; - bool m_running; -}; - -// Handles state transition animations -class Transition : public Animation { -public: - Transition() : Animation() {} - virtual ~Transition() {} - void setDuration(int duration) - { - m_duration = duration; - } - void setStartImage(const QImage &image) - { - m_primaryImage = image; - } - void setEndImage(const QImage &image) - { - m_secondaryImage = image; - } - virtual void paint(QPainter *painter, const QStyleOption *option); - int duration() const - { - return m_duration; - } - int m_duration; // set time in ms to complete a state transition -}; - -class StyleAnimator : public QObject { - Q_OBJECT - -public: - StyleAnimator(QObject *parent = 0) : QObject(parent) {} - - void timerEvent(QTimerEvent *); - void startAnimation(Animation *); - void stopAnimation(const QWidget *); - Animation *widgetAnimation(const QWidget *) const; - -private: - QBasicTimer animationTimer; - QList animations; -}; - -#endif // ANIMATION_H diff --git a/ground/gcs/src/plugins/coreplugin/tabpositionindicator.cpp b/ground/gcs/src/plugins/coreplugin/tabpositionindicator.cpp deleted file mode 100644 index 35b8a1bb84..0000000000 --- a/ground/gcs/src/plugins/coreplugin/tabpositionindicator.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/** - ****************************************************************************** - * - * @file tabpositionindicator.cpp - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @addtogroup GCSPlugins GCS Plugins - * @{ - * @addtogroup CorePlugin Core Plugin - * @{ - * @brief The Core GCS plugin - *****************************************************************************/ -/* - * 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 "tabpositionindicator.h" - -#include -#include -#include -#include - -using namespace Core::Internal; - -TabPositionIndicator::TabPositionIndicator() - : QWidget(0, Qt::ToolTip) -{} - -void TabPositionIndicator::paintEvent(QPaintEvent *event) -{ - QPainter p(this); - QPen pen = p.pen(); - - pen.setWidth(2); - pen.setColor(palette().color(QPalette::Active, QPalette::LinkVisited)); - pen.setStyle(Qt::DotLine); - p.setPen(pen); - p.drawLine(event->rect().topLeft(), event->rect().bottomLeft()); -} diff --git a/ground/gcs/src/plugins/coreplugin/tabpositionindicator.h b/ground/gcs/src/plugins/coreplugin/tabpositionindicator.h deleted file mode 100644 index c78418c542..0000000000 --- a/ground/gcs/src/plugins/coreplugin/tabpositionindicator.h +++ /dev/null @@ -1,54 +0,0 @@ -/** - ****************************************************************************** - * - * @file tabpositionindicator.h - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @addtogroup GCSPlugins GCS Plugins - * @{ - * @addtogroup CorePlugin Core Plugin - * @{ - * @brief The Core GCS plugin - *****************************************************************************/ -/* - * 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 TABPOSITIONINDICATOR_H -#define TABPOSITIONINDICATOR_H - -#include - -namespace Core { -namespace Internal { -class TabPositionIndicator : public QWidget { - Q_OBJECT - -public: - enum { TABPOSITIONINDICATOR_WIDTH = 2 }; - - TabPositionIndicator(); - int indicatorWidth() - { - return TABPOSITIONINDICATOR_WIDTH; - } - -private: - void paintEvent(QPaintEvent *event); -}; -} // namespace Internal -} // namespace Core - -#endif // TABPOSITIONINDICATOR_H From 07b30ba29042d60ccfb84757f0e37c9c25b9c87e Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Fri, 17 Mar 2017 23:42:59 +0100 Subject: [PATCH 202/624] LP-491 fix a gcs crash at exit when using -log option --- ground/gcs/src/app/main.cpp | 27 +++++++++++++------ ground/gcs/src/libs/utils/filelogger.h | 37 ++++++++++++++------------ 2 files changed, 39 insertions(+), 25 deletions(-) diff --git a/ground/gcs/src/app/main.cpp b/ground/gcs/src/app/main.cpp index 9644bea5cb..ee6e8c35d2 100644 --- a/ground/gcs/src/app/main.cpp +++ b/ground/gcs/src/app/main.cpp @@ -286,7 +286,7 @@ void systemInit() QSurfaceFormat::setDefaultFormat(format); } -static FileLogger *logger; +static FileLogger *logger = NULL; void mainMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg) { @@ -295,14 +295,27 @@ void mainMessageOutput(QtMsgType type, const QMessageLogContext &context, const Q_DECLARE_METATYPE(QtMsgType) -void logInit(QString fileName) +void logInit(QString &fileName) { qRegisterMetaType(); - qInstallMessageHandler(mainMessageOutput); - logger = new FileLogger(); - if (!logger->start(fileName)) { + logger = new FileLogger(fileName); + if (!logger->start()) { + delete logger; + logger = NULL; displayError(msgLogfileOpenFailed(fileName)); + return; } + qInstallMessageHandler(mainMessageOutput); +} + +void logDeinit() +{ + if (!logger) { + return; + } + qInstallMessageHandler(0); + delete logger; + logger = NULL; } AppOptions options() @@ -618,9 +631,7 @@ int main(int argc, char * *argv) qDebug() << "main - GCS ran for" << timer.elapsed() << "ms"; - if (logger) { - delete logger; - } + logDeinit(); return ret; } diff --git a/ground/gcs/src/libs/utils/filelogger.h b/ground/gcs/src/libs/utils/filelogger.h index 8c5b8d3b1b..eddd05f38a 100644 --- a/ground/gcs/src/libs/utils/filelogger.h +++ b/ground/gcs/src/libs/utils/filelogger.h @@ -39,40 +39,34 @@ class QTCREATOR_UTILS_EXPORT FileLogger : public QObject { Q_OBJECT -private: - QTextStream * logStream; - QThread *loggerThread; - bool started; - public: - FileLogger() : QObject(), logStream(NULL), loggerThread(NULL), started(false) + FileLogger(QString &fileName) : QObject(), file(fileName), logStream(NULL), loggerThread(NULL), started(false) {} virtual ~FileLogger() { + qDebug() << "~FileLogger"; stop(); - if (logStream) { - delete logStream; - } + delete logStream; + logStream = NULL; } -public: - bool start(const QString &fileName) + bool start() { if (started) { return false; } - QFile *file = new QFile(fileName); - if (!file->open(QIODevice::WriteOnly | QIODevice::Text)) { + if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { return false; } - logStream = new QTextStream(file); + logStream = new QTextStream(&file); - loggerThread = new QThread(this); - moveToThread(loggerThread); - loggerThread->start(); + // loggerThread = new QThread(this); + moveToThread(&loggerThread); + // connect(&loggerThread, &QThread::finished, this, &QObject::deleteLater); + loggerThread.start(); started = true; @@ -93,6 +87,9 @@ class QTCREATOR_UTILS_EXPORT FileLogger : public QObject { QMetaObject::invokeMethod(this, "doLog", Qt::BlockingQueuedConnection, Q_ARG(QtMsgType, type), Q_ARG(const QString &, msg)); + loggerThread.quit(); + loggerThread.wait(); + return true; } @@ -138,4 +135,10 @@ private slots: out << msg << '\n'; out.flush(); } + +private: + QFile file; + QTextStream *logStream; + QThread loggerThread; + bool started; }; From 6a9ec75439d17c716262d549f88526eab3e63dc2 Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Sun, 19 Mar 2017 14:43:04 +0100 Subject: [PATCH 203/624] LP-491 fix link a3867 hasn't been detected! --- ground/gcs/src/plugins/magicwaypoint/images/positionfield.svg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ground/gcs/src/plugins/magicwaypoint/images/positionfield.svg b/ground/gcs/src/plugins/magicwaypoint/images/positionfield.svg index 256d9bd6dd..e090760bb6 100644 --- a/ground/gcs/src/plugins/magicwaypoint/images/positionfield.svg +++ b/ground/gcs/src/plugins/magicwaypoint/images/positionfield.svg @@ -148,14 +148,14 @@ style="fill:#ff201d;fill-opacity:1;stroke:#ef7d7d;stroke-width:0.39996386;stroke-miterlimit:4;stroke-opacity:0.59336093;stroke-dasharray:none" sodipodi:type="arc" /> - + height="64" /--> Date: Tue, 28 Mar 2017 22:29:02 +0200 Subject: [PATCH 204/624] LP-495 PR comments and uncrustify --- flight/pios/stm32f4xx/pios_usb_cdc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flight/pios/stm32f4xx/pios_usb_cdc.c b/flight/pios/stm32f4xx/pios_usb_cdc.c index 6f091eaa8a..803d653c69 100644 --- a/flight/pios/stm32f4xx/pios_usb_cdc.c +++ b/flight/pios/stm32f4xx/pios_usb_cdc.c @@ -191,7 +191,7 @@ int32_t PIOS_USB_CDC_Init(uint32_t *usbcdc_id, const struct pios_usb_cdc_cfg *cf pios_usb_cdc_id = (uint32_t)usb_cdc_dev; - /* Rx and Tx are not active yet */ + /* Tx is not active yet */ usb_cdc_dev->tx_active = false; /* Clear stats */ From 0b8c7e71346dd012a4d789d98b895e45c416dbac Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Sun, 2 Apr 2017 14:15:41 +0200 Subject: [PATCH 205/624] LP-503 osg: support older version to make Tea CI happy --- ground/gcs/src/libs/osgearth/copydata.pro | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/ground/gcs/src/libs/osgearth/copydata.pro b/ground/gcs/src/libs/osgearth/copydata.pro index c263520f54..018a5db680 100644 --- a/ground/gcs/src/libs/osgearth/copydata.pro +++ b/ground/gcs/src/libs/osgearth/copydata.pro @@ -56,11 +56,19 @@ osg:win32 { libp11-kit-0.dll \ libffi-6.dll \ libtasn1-6.dll \ - libhogweed-4.dll \ - libnettle-6.dll \ libssh2-1.dll \ libnghttp2-14.dll + equals(OSG_VERSION, "3.5.1") { + OSG_LIBS += \ + libhogweed-4-2.dll \ + libnettle-6-2.dll + } else { + OSG_LIBS += \ + libhogweed-4.dll \ + libnettle-6.dll + } + # other OSG_LIBS += \ libjpeg-8.dll \ From 37d1a849457f4ae4d5d08226de36cb75b7435174 Mon Sep 17 00:00:00 2001 From: Laurent Lalanne Date: Fri, 7 Apr 2017 20:02:18 +0200 Subject: [PATCH 206/624] LP-504 Set speed unit to cm/s --- flight/modules/UAVOMSPBridge/UAVOMSPBridge.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flight/modules/UAVOMSPBridge/UAVOMSPBridge.c b/flight/modules/UAVOMSPBridge/UAVOMSPBridge.c index c02cc46876..43bbbe433f 100644 --- a/flight/modules/UAVOMSPBridge/UAVOMSPBridge.c +++ b/flight/modules/UAVOMSPBridge/UAVOMSPBridge.c @@ -531,7 +531,7 @@ static void msp_send_raw_gps(struct msp_bridge *m) data.raw_gps.lat = gps_data.Latitude; data.raw_gps.lon = gps_data.Longitude; data.raw_gps.alt = (uint16_t)gps_data.Altitude; - data.raw_gps.speed = (uint16_t)gps_data.Groundspeed; + data.raw_gps.speed = (uint16_t)(gps_data.Groundspeed * 100.0f); data.raw_gps.ground_course = (int16_t)(gps_data.Heading * 10.0f); msp_send(m, MSP_RAW_GPS, data.buf, sizeof(data)); From 5dff540d0781fd635b793848422703e57a0d7b01 Mon Sep 17 00:00:00 2001 From: Brian Webb Date: Thu, 13 Apr 2017 21:11:49 -0700 Subject: [PATCH 207/624] LP-507 Converts all tick times in the rfm22b driver to ms. --- flight/pios/common/pios_rfm22b.c | 107 +++++++++++++++-------------- flight/pios/inc/pios_rfm22b_priv.h | 3 +- 2 files changed, 58 insertions(+), 52 deletions(-) diff --git a/flight/pios/common/pios_rfm22b.c b/flight/pios/common/pios_rfm22b.c index 4a438b0416..372c11a3ca 100644 --- a/flight/pios/common/pios_rfm22b.c +++ b/flight/pios/common/pios_rfm22b.c @@ -200,14 +200,15 @@ static bool rfm22_isCoordinator(struct pios_rfm22b_dev *rfm22b_dev); static uint32_t rfm22_destinationID(struct pios_rfm22b_dev *rfm22b_dev); static bool rfm22_timeToSend(struct pios_rfm22b_dev *rfm22b_dev); static void rfm22_synchronizeClock(struct pios_rfm22b_dev *rfm22b_dev); -static portTickType rfm22_coordinatorTime(struct pios_rfm22b_dev *rfm22b_dev, portTickType ticks); +static uint32_t rfm22_coordinatorTime(struct pios_rfm22b_dev *rfm22b_dev); static uint8_t rfm22_calcChannel(struct pios_rfm22b_dev *rfm22b_dev, uint8_t index); static uint8_t rfm22_calcChannelFromClock(struct pios_rfm22b_dev *rfm22b_dev); static bool rfm22_changeChannel(struct pios_rfm22b_dev *rfm22b_dev); static void rfm22_clearLEDs(); // Utility functions. -static uint32_t pios_rfm22_time_difference_ms(portTickType start_time, portTickType end_time); +static uint32_t pios_rfm22_time_ms(); +static uint32_t pios_rfm22_time_difference_ms(uint32_t start_time, uint32_t end_time); static struct pios_rfm22b_dev *pios_rfm22_alloc(void); static void rfm22_hmac_sha1(const uint8_t *data, size_t len, uint8_t key[SHA1_DIGEST_LENGTH], uint8_t digest[SHA1_DIGEST_LENGTH]); @@ -810,9 +811,9 @@ bool PIOS_RFM22B_TransmitPacket(uint32_t rfm22b_id, uint8_t *p, uint8_t len) rfm22b_dev->tx_packet_handle = p; rfm22b_dev->stats.tx_byte_count += len; - rfm22b_dev->packet_start_ticks = xTaskGetTickCount(); - if (rfm22b_dev->packet_start_ticks == 0) { - rfm22b_dev->packet_start_ticks = 1; + rfm22b_dev->packet_start_time = pios_rfm22_time_ms(); + if (rfm22b_dev->packet_start_time == 0) { + rfm22b_dev->packet_start_time = 1; } // Claim the SPI bus. @@ -1050,9 +1051,9 @@ pios_rfm22b_int_result PIOS_RFM22B_ProcessRx(uint32_t rfm22b_id) #ifdef PIOS_RFM22B_DEBUG_ON_TELEM D2_LED_ON; #endif // PIOS_RFM22B_DEBUG_ON_TELEM - rfm22b_dev->packet_start_ticks = xTaskGetTickCount(); - if (rfm22b_dev->packet_start_ticks == 0) { - rfm22b_dev->packet_start_ticks = 1; + rfm22b_dev->packet_start_time = pios_rfm22_time_ms(); + if (rfm22b_dev->packet_start_time == 0) { + rfm22b_dev->packet_start_time = 1; } // We detected the preamble, now wait for sync. @@ -1187,7 +1188,7 @@ static void pios_rfm22_task(void *parameters) if (!PIOS_RFM22B_Validate(rfm22b_dev)) { return; } - portTickType lastEventTicks = xTaskGetTickCount(); + uint32_t lastEventTime = pios_rfm22_time_ms(); while (1) { #if defined(PIOS_INCLUDE_WDG) && defined(PIOS_WDG_RFM22B) @@ -1197,7 +1198,7 @@ static void pios_rfm22_task(void *parameters) // Wait for a signal indicating an external interrupt or a pending send/receive request. if (xSemaphoreTake(rfm22b_dev->isrPending, ISR_TIMEOUT / portTICK_RATE_MS) == pdTRUE) { - lastEventTicks = xTaskGetTickCount(); + lastEventTime = pios_rfm22_time_ms(); // Process events through the state machine. enum pios_radio_event event; @@ -1210,14 +1211,14 @@ static void pios_rfm22_task(void *parameters) } } else { // Has it been too long since the last event? - portTickType curTicks = xTaskGetTickCount(); - if (pios_rfm22_time_difference_ms(lastEventTicks, curTicks) > PIOS_RFM22B_SUPERVISOR_TIMEOUT) { + uint32_t curTime = pios_rfm22_time_ms(); + if (pios_rfm22_time_difference_ms(lastEventTime, curTime) > PIOS_RFM22B_SUPERVISOR_TIMEOUT) { // Clear the event queue. enum pios_radio_event event; while (xQueueReceive(rfm22b_dev->eventQueue, &event, 0) == pdTRUE) { // Do nothing; } - lastEventTicks = xTaskGetTickCount(); + lastEventTime = pios_rfm22_time_ms(); // Transsition through an error event. rfm22_process_event(rfm22b_dev, RADIO_EVENT_ERROR); @@ -1229,11 +1230,10 @@ static void pios_rfm22_task(void *parameters) rfm22_process_event(rfm22b_dev, RADIO_EVENT_RX_MODE); } - portTickType curTicks = xTaskGetTickCount(); // Have we been sending / receiving this packet too long? - - if ((rfm22b_dev->packet_start_ticks > 0) && - (pios_rfm22_time_difference_ms(rfm22b_dev->packet_start_ticks, curTicks) > (rfm22b_dev->packet_time * 3))) { + uint32_t curTime = pios_rfm22_time_ms(); + if ((rfm22b_dev->packet_start_time > 0) && + (pios_rfm22_time_difference_ms(rfm22b_dev->packet_start_time, curTime) > (rfm22b_dev->packet_time * 3))) { rfm22_process_event(rfm22b_dev, RADIO_EVENT_TIMEOUT); } @@ -1388,15 +1388,14 @@ static enum pios_radio_event rfm22_init(struct pios_rfm22b_dev *rfm22b_dev) rfm22b_dev->tx_packet_handle = NULL; // Initialize the devide state - rfm22b_dev->rx_buffer_wr = 0; - rfm22b_dev->tx_data_rd = rfm22b_dev->tx_data_wr = 0; + rfm22b_dev->rx_buffer_wr = 0; + rfm22b_dev->tx_data_rd = rfm22b_dev->tx_data_wr = 0; rfm22b_dev->channel = 0; - rfm22b_dev->channel_index = 0; - rfm22b_dev->afc_correction_Hz = 0; - rfm22b_dev->packet_start_ticks = 0; - rfm22b_dev->tx_complete_ticks = 0; - rfm22b_dev->rfm22b_state = RFM22B_STATE_INITIALIZING; - rfm22b_dev->last_contact = 0; + rfm22b_dev->channel_index = 0; + rfm22b_dev->afc_correction_Hz = 0; + rfm22b_dev->packet_start_time = 0; + rfm22b_dev->rfm22b_state = RFM22B_STATE_INITIALIZING; + rfm22b_dev->last_contact = 0; // software reset the RF chip .. following procedure according to Si4x3x Errata (rev. B) rfm22_write_claim(rfm22b_dev, RFM22_op_and_func_ctrl1, RFM22_opfc1_swres); @@ -1807,7 +1806,7 @@ static void rfm22_rxFailure(struct pios_rfm22b_dev *rfm22b_dev) { rfm22b_add_rx_status(rfm22b_dev, RADIO_FAILURE_RX_PACKET); rfm22b_dev->rx_buffer_wr = 0; - rfm22b_dev->packet_start_ticks = 0; + rfm22b_dev->packet_start_time = 0; rfm22b_dev->rfm22b_state = RFM22B_STATE_TRANSITION; } @@ -1944,14 +1943,12 @@ static enum pios_radio_event radio_txData(struct pios_rfm22b_dev *radio_dev) // Is the transmition complete if (res == PIOS_RFM22B_TX_COMPLETE) { - radio_dev->tx_complete_ticks = xTaskGetTickCount(); - // Is this an ACK? ret_event = RADIO_EVENT_RX_MODE; - radio_dev->tx_packet_handle = 0; + radio_dev->tx_packet_handle = 0; radio_dev->tx_data_wr = radio_dev->tx_data_rd = 0; // Start a new transaction - radio_dev->packet_start_ticks = 0; + radio_dev->packet_start_time = 0; #ifdef PIOS_RFM22B_DEBUG_ON_TELEM D1_LED_OFF; @@ -1972,7 +1969,7 @@ static enum pios_radio_event radio_setRxMode(struct pios_rfm22b_dev *rfm22b_dev) if (!PIOS_RFM22B_ReceivePacket((uint32_t)rfm22b_dev, rfm22b_dev->rx_packet)) { return RADIO_EVENT_NUM_EVENTS; } - rfm22b_dev->packet_start_ticks = 0; + rfm22b_dev->packet_start_time = 0; // No event generated return RADIO_EVENT_NUM_EVENTS; @@ -2096,7 +2093,7 @@ static enum pios_radio_event radio_receivePacket(struct pios_rfm22b_dev *radio_d rfm22_synchronizeClock(radio_dev); } radio_dev->stats.link_state = OPLINKSTATUS_LINKSTATE_CONNECTED; - radio_dev->last_contact = xTaskGetTickCount(); + radio_dev->last_contact = pios_rfm22_time_ms(); radio_dev->stats.rssi = radio_dev->rssi_dBm; radio_dev->stats.afc_correction = radio_dev->afc_correction_Hz; } else { @@ -2128,7 +2125,7 @@ static enum pios_radio_event radio_rxData(struct pios_rfm22b_dev *radio_dev) #endif // Start a new transaction - radio_dev->packet_start_ticks = 0; + radio_dev->packet_start_time = 0; break; case PIOS_RFM22B_INT_FAILURE: @@ -2252,7 +2249,7 @@ static void rfm22_updateStats(struct pios_rfm22b_dev *rfm22b_dev) */ static bool rfm22_checkTimeOut(struct pios_rfm22b_dev *rfm22b_dev) { - return pios_rfm22_time_difference_ms(rfm22b_dev->last_contact, xTaskGetTickCount()) >= CONNECTED_TIMEOUT; + return pios_rfm22_time_difference_ms(rfm22b_dev->last_contact, pios_rfm22_time_ms()) >= CONNECTED_TIMEOUT; } /** @@ -2315,7 +2312,7 @@ uint32_t rfm22_destinationID(struct pios_rfm22b_dev *rfm22b_dev) */ static void rfm22_synchronizeClock(struct pios_rfm22b_dev *rfm22b_dev) { - portTickType start_time = rfm22b_dev->packet_start_ticks; + uint32_t start_time = rfm22b_dev->packet_start_time; // This packet was transmitted on channel 0, calculate the time delta that will force us to transmit on channel 0 at the time this packet started. uint16_t frequency_hop_cycle_time = rfm22b_dev->packet_time * rfm22b_dev->num_channels; @@ -2329,17 +2326,19 @@ static void rfm22_synchronizeClock(struct pios_rfm22b_dev *rfm22b_dev) } /** - * Return the extimated current clock ticks count on the coordinator modem. + * Return the estimated current time on the coordinator modem. * This is the master clock used for all synchronization. * * @param[in] rfm22b_dev The device structure */ -static portTickType rfm22_coordinatorTime(struct pios_rfm22b_dev *rfm22b_dev, portTickType ticks) +static uint32_t rfm22_coordinatorTime(struct pios_rfm22b_dev *rfm22b_dev) { + uint32_t time = pios_rfm22_time_ms(); + if (rfm22_isCoordinator(rfm22b_dev)) { - return ticks; + return time; } - return ticks + rfm22b_dev->time_delta; + return time + rfm22b_dev->time_delta; } /** @@ -2349,7 +2348,7 @@ static portTickType rfm22_coordinatorTime(struct pios_rfm22b_dev *rfm22b_dev, po */ static bool rfm22_timeToSend(struct pios_rfm22b_dev *rfm22b_dev) { - portTickType time = rfm22_coordinatorTime(rfm22b_dev, xTaskGetTickCount()); + uint32_t time = rfm22_coordinatorTime(rfm22b_dev); bool is_coordinator = rfm22_isCoordinator(rfm22b_dev); // If this is a one-way link, only the coordinator can send. @@ -2404,10 +2403,10 @@ static uint8_t rfm22_calcChannel(struct pios_rfm22b_dev *rfm22b_dev, uint8_t ind */ static uint8_t rfm22_calcChannelFromClock(struct pios_rfm22b_dev *rfm22b_dev) { - portTickType time = rfm22_coordinatorTime(rfm22b_dev, xTaskGetTickCount()); + uint32_t time = rfm22_coordinatorTime(rfm22b_dev); // Divide time into 8ms blocks. Coordinator sends in first 2 ms, and remote send in 5th and 6th ms. // Channel changes occur in the last 2 ms. - uint8_t n = (time / rfm22b_dev->packet_time) % rfm22b_dev->num_channels; + uint8_t n = (time / rfm22b_dev->packet_time) % rfm22b_dev->num_channels; return rfm22_calcChannel(rfm22b_dev, n); } @@ -2441,7 +2440,7 @@ static bool rfm22_changeChannel(struct pios_rfm22b_dev *rfm22b_dev) static enum pios_radio_event rfm22_txFailure(struct pios_rfm22b_dev *rfm22b_dev) { rfm22b_dev->stats.tx_failure++; - rfm22b_dev->packet_start_ticks = 0; + rfm22b_dev->packet_start_time = 0; rfm22b_dev->tx_data_wr = rfm22b_dev->tx_data_rd = 0; return RADIO_EVENT_TX_START; } @@ -2455,7 +2454,7 @@ static enum pios_radio_event rfm22_txFailure(struct pios_rfm22b_dev *rfm22b_dev) static enum pios_radio_event rfm22_timeout(struct pios_rfm22b_dev *rfm22b_dev) { rfm22b_dev->stats.timeouts++; - rfm22b_dev->packet_start_ticks = 0; + rfm22b_dev->packet_start_time = 0; // Release the Tx packet if it's set. if (rfm22b_dev->tx_packet_handle != 0) { rfm22b_dev->tx_data_rd = rfm22b_dev->tx_data_wr = 0; @@ -2525,20 +2524,28 @@ static enum pios_radio_event rfm22_fatal_error(__attribute__((unused)) struct pi * Utility Functions *****************************************************************************/ +/** + * Get the current time in ms from the ticks counter. + */ +static uint32_t pios_rfm22_time_ms() +{ + return xTaskGetTickCount() * portTICK_RATE_MS; +} + /** * Calculate the time difference between the start time and end time. - * Times are in ticks. Also handles rollover. + * Times are in ms. Also handles rollover. * - * @param[in] start_time The start time in ticks. - * @param[in] end_time The end time in ticks. + * @param[in] start_time The start time in ms. + * @param[in] end_time The end time in ms. */ -static uint32_t pios_rfm22_time_difference_ms(portTickType start_time, portTickType end_time) +static uint32_t pios_rfm22_time_difference_ms(uint32_t start_time, uint32_t end_time) { if (end_time >= start_time) { - return (end_time - start_time) * portTICK_RATE_MS; + return end_time - start_time; } // Rollover - return ((portMAX_DELAY - start_time) + end_time) * portTICK_RATE_MS; + return (UINT32_MAX - start_time) + end_time; } /** diff --git a/flight/pios/inc/pios_rfm22b_priv.h b/flight/pios/inc/pios_rfm22b_priv.h index b684e1dc02..7768cb7f2c 100644 --- a/flight/pios/inc/pios_rfm22b_priv.h +++ b/flight/pios/inc/pios_rfm22b_priv.h @@ -308,8 +308,7 @@ struct pios_rfm22b_dev { int32_t afc_correction_Hz; // The packet timers. - portTickType packet_start_ticks; - portTickType tx_complete_ticks; + portTickType packet_start_time; portTickType time_delta; portTickType last_contact; }; From ece26d20b14c9e0c0eb64bb90afda350043a5e19 Mon Sep 17 00:00:00 2001 From: Brian Webb Date: Thu, 13 Apr 2017 19:43:42 -0700 Subject: [PATCH 208/624] LP-506 Removes pair stats from oplink code. --- flight/modules/OPLink/oplinkmod.c | 3 - flight/modules/System/systemmod.c | 3 - flight/pios/common/pios_rfm22b.c | 81 --------------------- flight/pios/inc/pios_rfm22b.h | 1 - flight/pios/inc/pios_rfm22b_priv.h | 8 +- shared/uavobjectdefinition/oplinkstatus.xml | 2 - 6 files changed, 4 insertions(+), 94 deletions(-) diff --git a/flight/modules/OPLink/oplinkmod.c b/flight/modules/OPLink/oplinkmod.c index a1106a1e94..84dde5ac4a 100644 --- a/flight/modules/OPLink/oplinkmod.c +++ b/flight/modules/OPLink/oplinkmod.c @@ -149,9 +149,6 @@ static void systemTask(__attribute__((unused)) void *parameters) OPLinkStatusData oplinkStatus; OPLinkStatusGet(&oplinkStatus); - // Get the other device stats. - PIOS_RFM22B_GetPairStats(pios_rfm22b_id, oplinkStatus.PairIDs, oplinkStatus.PairSignalStrengths, OPLINKSTATUS_PAIRIDS_NUMELEM); - // Get the stats from the radio device struct rfm22b_stats radio_stats; PIOS_RFM22B_GetStats(pios_rfm22b_id, &radio_stats); diff --git a/flight/modules/System/systemmod.c b/flight/modules/System/systemmod.c index 8d499bc17a..a4d87975b9 100644 --- a/flight/modules/System/systemmod.c +++ b/flight/modules/System/systemmod.c @@ -287,9 +287,6 @@ static void systemTask(__attribute__((unused)) void *parameters) oplinkStatus.HeapRemaining = xPortGetFreeHeapSize(); if (pios_rfm22b_id) { - // Get the other device stats. - PIOS_RFM22B_GetPairStats(pios_rfm22b_id, oplinkStatus.PairIDs, oplinkStatus.PairSignalStrengths, OPLINKSTATUS_PAIRIDS_NUMELEM); - // Get the stats from the radio device struct rfm22b_stats radio_stats; PIOS_RFM22B_GetStats(pios_rfm22b_id, &radio_stats); diff --git a/flight/pios/common/pios_rfm22b.c b/flight/pios/common/pios_rfm22b.c index 4a438b0416..be43c973f9 100644 --- a/flight/pios/common/pios_rfm22b.c +++ b/flight/pios/common/pios_rfm22b.c @@ -192,7 +192,6 @@ static void rfm22b_add_rx_status(struct pios_rfm22b_dev *rfm22b_dev, enum pios_r static void rfm22_setNominalCarrierFrequency(struct pios_rfm22b_dev *rfm22b_dev, uint8_t init_chan, uint32_t frequency_hz); static bool rfm22_setFreqHopChannel(struct pios_rfm22b_dev *rfm22b_dev, uint8_t channel); static void rfm22_generateDeviceID(struct pios_rfm22b_dev *rfm22b_dev); -static void rfm22_updatePairStatus(struct pios_rfm22b_dev *radio_dev); static void rfm22_updateStats(struct pios_rfm22b_dev *rfm22b_dev); static bool rfm22_checkTimeOut(struct pios_rfm22b_dev *rfm22b_dev); static bool rfm22_isConnected(struct pios_rfm22b_dev *rfm22b_dev); @@ -693,31 +692,6 @@ void PIOS_RFM22B_GetStats(uint32_t rfm22b_id, struct rfm22b_stats *stats) *stats = rfm22b_dev->stats; } -/** - * Get the stats of the oter radio devices that are in range. - * - * @param[out] device_ids A pointer to the array to store the device IDs. - * @param[out] RSSIs A pointer to the array to store the RSSI values in. - * @param[in] mx_pairs The length of the pdevice_ids and RSSIs arrays. - * @return The number of pair stats returned. - */ -uint8_t PIOS_RFM22B_GetPairStats(uint32_t rfm22b_id, uint32_t *device_ids, int8_t *RSSIs, uint8_t max_pairs) -{ - struct pios_rfm22b_dev *rfm22b_dev = (struct pios_rfm22b_dev *)rfm22b_id; - - if (!PIOS_RFM22B_Validate(rfm22b_dev)) { - return 0; - } - - uint8_t mp = (max_pairs >= OPLINKSTATUS_PAIRIDS_NUMELEM) ? max_pairs : OPLINKSTATUS_PAIRIDS_NUMELEM; - for (uint8_t i = 0; i < mp; ++i) { - device_ids[i] = rfm22b_dev->pair_stats[i].pairID; - RSSIs[i] = rfm22b_dev->pair_stats[i].rssi; - } - - return mp; -} - /** * Check the radio device for a valid connection * @@ -999,9 +973,6 @@ pios_rfm22b_int_result PIOS_RFM22B_ProcessRx(uint32_t rfm22b_id) // Increment the total byte received count. rfm22b_dev->stats.rx_byte_count += rfm22b_dev->rx_buffer_wr; - // Update the pair status with this packet. - rfm22_updatePairStatus(rfm22b_dev); - // We're finished with Rx mode rfm22b_dev->rfm22b_state = RFM22B_STATE_TRANSITION; @@ -1366,14 +1337,6 @@ static enum pios_radio_event rfm22_init(struct pios_rfm22b_dev *rfm22b_dev) // Clean the LEDs rfm22_clearLEDs(); - // Initialize the detected device statistics. - for (uint8_t i = 0; i < OPLINKSTATUS_PAIRIDS_NUMELEM; ++i) { - rfm22b_dev->pair_stats[i].pairID = 0; - rfm22b_dev->pair_stats[i].rssi = -127; - rfm22b_dev->pair_stats[i].afc_correction = 0; - rfm22b_dev->pair_stats[i].lastContact = 0; - } - // Initlize the link stats. for (uint8_t i = 0; i < RFM22B_RX_PACKET_STATS_LEN; ++i) { rfm22b_dev->rx_packet_stats[i] = 0; @@ -2148,50 +2111,6 @@ static enum pios_radio_event radio_rxData(struct pios_rfm22b_dev *radio_dev) * Link Statistics Functions *****************************************************************************/ -/** - * Update the modem pair status. - * - * @param[in] rfm22b_dev The device structure - */ -static void rfm22_updatePairStatus(struct pios_rfm22b_dev *radio_dev) -{ - int8_t rssi = radio_dev->rssi_dBm; - int8_t afc = radio_dev->afc_correction_Hz; - uint32_t id = radio_dev->rx_destination_id; - - // Have we seen this device recently? - bool found = false; - uint8_t id_idx = 0; - - for (; id_idx < OPLINKSTATUS_PAIRIDS_NUMELEM; ++id_idx) { - if (radio_dev->pair_stats[id_idx].pairID == id) { - found = true; - break; - } - } - - // If we have seen it, update the RSSI and reset the last contact counter - if (found) { - radio_dev->pair_stats[id_idx].rssi = rssi; - radio_dev->pair_stats[id_idx].afc_correction = afc; - radio_dev->pair_stats[id_idx].lastContact = 0; - } else { - // If we haven't seen it, find a slot to put it in. - uint8_t min_idx = 0; - int8_t min_rssi = radio_dev->pair_stats[0].rssi; - for (id_idx = 1; id_idx < OPLINKSTATUS_PAIRIDS_NUMELEM; ++id_idx) { - if (radio_dev->pair_stats[id_idx].rssi < min_rssi) { - min_rssi = radio_dev->pair_stats[id_idx].rssi; - min_idx = id_idx; - } - } - radio_dev->pair_stats[min_idx].pairID = id; - radio_dev->pair_stats[min_idx].rssi = rssi; - radio_dev->pair_stats[min_idx].afc_correction = afc; - radio_dev->pair_stats[min_idx].lastContact = 0; - } -} - /** * Calculate stats from the packet receipt, transmission statistics. * diff --git a/flight/pios/inc/pios_rfm22b.h b/flight/pios/inc/pios_rfm22b.h index e2a2d01465..d2d43533ca 100644 --- a/flight/pios/inc/pios_rfm22b.h +++ b/flight/pios/inc/pios_rfm22b.h @@ -110,7 +110,6 @@ extern void PIOS_RFM22B_SetCoordinatorID(uint32_t rfm22b_id, uint32_t coord_id); extern void PIOS_RFM22B_SetDeviceID(uint32_t rfm22b_id, uint32_t device_id); extern uint32_t PIOS_RFM22B_DeviceID(uint32_t rfb22b_id); extern void PIOS_RFM22B_GetStats(uint32_t rfm22b_id, struct rfm22b_stats *stats); -extern uint8_t PIOS_RFM22B_GetPairStats(uint32_t rfm22b_id, uint32_t *device_ids, int8_t *RSSIs, uint8_t max_pairs); extern bool PIOS_RFM22B_InRxWait(uint32_t rfb22b_id); extern bool PIOS_RFM22B_LinkStatus(uint32_t rfm22b_id); extern bool PIOS_RFM22B_ReceivePacket(uint32_t rfm22b_id, uint8_t *p); diff --git a/flight/pios/inc/pios_rfm22b_priv.h b/flight/pios/inc/pios_rfm22b_priv.h index b684e1dc02..905ddb641b 100644 --- a/flight/pios/inc/pios_rfm22b_priv.h +++ b/flight/pios/inc/pios_rfm22b_priv.h @@ -200,9 +200,6 @@ struct pios_rfm22b_dev { // The task handle xTaskHandle taskHandle; - // The potential paired statistics - rfm22b_pair_stats pair_stats[OPLINKSTATUS_PAIRIDS_NUMELEM]; - // ISR pending semaphore xSemaphoreHandle isrPending; @@ -212,12 +209,15 @@ struct pios_rfm22b_dev { pios_com_callback tx_out_cb; uint32_t tx_out_context; - uint8_t last_stream_sent; // The Aux COM callback functions. pios_com_callback aux_rx_in_cb; uint32_t aux_rx_in_context; pios_com_callback aux_tx_out_cb; uint32_t aux_tx_out_context; + + // Send next packet on primary or aux channel? + bool last_stream_sent; + // the transmit power to use for data transmissions uint8_t tx_power; diff --git a/shared/uavobjectdefinition/oplinkstatus.xml b/shared/uavobjectdefinition/oplinkstatus.xml index 7d9605c61c..73c613fe17 100644 --- a/shared/uavobjectdefinition/oplinkstatus.xml +++ b/shared/uavobjectdefinition/oplinkstatus.xml @@ -25,8 +25,6 @@ - - From dc5eef0cb5e03db244a610cf55ed46d293517d06 Mon Sep 17 00:00:00 2001 From: Brian Webb Date: Thu, 30 Mar 2017 20:06:03 -0700 Subject: [PATCH 209/624] LP-499 Adds support for bridging either radio primary, radio auxilary, and/or VCP to any of the output ports (main, flexi, VCP, HID). Also adds the ability to configure the com speed of the UARTs independent of the air data rate. --- flight/modules/OPLink/oplinkmod.c | 5 + .../modules/RadioComBridge/RadioComBridge.c | 276 +++++------- flight/pios/common/pios_com.c | 38 ++ flight/pios/common/pios_rfm22b.c | 13 +- flight/pios/inc/pios_com.h | 2 + .../targets/boards/oplinkmini/board_hw_defs.c | 4 +- .../boards/oplinkmini/bootloader/main.c | 6 +- .../boards/oplinkmini/firmware/Makefile | 2 +- .../oplinkmini/firmware/inc/pios_config.h | 22 +- .../boards/oplinkmini/firmware/pios_board.c | 341 +++++++++------ flight/targets/boards/oplinkmini/pios_board.h | 57 +-- .../boards/revolution/firmware/pios_board.c | 25 +- .../boards/sparky2/firmware/pios_board.c | 25 +- .../src/plugins/config/configoplinkwidget.cpp | 248 ++++++++--- .../src/plugins/config/configoplinkwidget.h | 4 +- ground/gcs/src/plugins/config/oplink.ui | 407 +++++++++++------- shared/uavobjectdefinition/oplinksettings.xml | 32 +- 17 files changed, 932 insertions(+), 575 deletions(-) diff --git a/flight/modules/OPLink/oplinkmod.c b/flight/modules/OPLink/oplinkmod.c index a1106a1e94..6372dcf765 100644 --- a/flight/modules/OPLink/oplinkmod.c +++ b/flight/modules/OPLink/oplinkmod.c @@ -122,6 +122,11 @@ static void systemTask(__attribute__((unused)) void *parameters) while (!initTaskDone) { vTaskDelay(10); } + +#ifndef PIOS_INCLUDE_WDG +// if no watchdog is enabled, don't reset watchdog in MODULE_TASKCREATE_ALL loop +#define PIOS_WDG_Clear() +#endif /* create all modules thread */ MODULE_TASKCREATE_ALL; diff --git a/flight/modules/RadioComBridge/RadioComBridge.c b/flight/modules/RadioComBridge/RadioComBridge.c index a9b4c70aeb..8353906551 100644 --- a/flight/modules/RadioComBridge/RadioComBridge.c +++ b/flight/modules/RadioComBridge/RadioComBridge.c @@ -41,23 +41,21 @@ #include #include #include -#if defined(PIOS_INCLUDE_FLASH_EEPROM) -#include -#endif #include // **************** // Private constants -#define STACK_SIZE_BYTES 150 -#define TASK_PRIORITY (tskIDLE_PRIORITY + 1) -#define MAX_RETRIES 2 -#define RETRY_TIMEOUT_MS 20 -#define EVENT_QUEUE_SIZE 10 -#define MAX_PORT_DELAY 200 -#define SERIAL_RX_BUF_LEN 100 -#define PPM_INPUT_TIMEOUT 100 +#define TELEM_STACK_SIZE_WORDS 150 +#define PPM_STACK_SIZE_WORDS 150 +#define TASK_PRIORITY (tskIDLE_PRIORITY + 1) +#define MAX_RETRIES 2 +#define RETRY_TIMEOUT_MS 20 +#define EVENT_QUEUE_SIZE 10 +#define MAX_PORT_DELAY 200 +#define SERIAL_RX_BUF_LEN 100 +#define PPM_INPUT_TIMEOUT 100 // **************** @@ -67,10 +65,9 @@ typedef struct { // The task handles. xTaskHandle telemetryTxTaskHandle; xTaskHandle telemetryRxTaskHandle; - xTaskHandle radioTxTaskHandle; - xTaskHandle radioRxTaskHandle; + xTaskHandle telemRadioTxTaskHandle; + xTaskHandle telemRadioRxTaskHandle; xTaskHandle PPMInputTaskHandle; - xTaskHandle serialRxTaskHandle; // The UAVTalk connection on the com side. UAVTalkConnection telemUAVTalkCon; @@ -80,21 +77,12 @@ typedef struct { xQueueHandle uavtalkEventQueue; xQueueHandle radioEventQueue; - // The raw serial Rx buffer - uint8_t serialRxBuf[SERIAL_RX_BUF_LEN]; - // Error statistics. - uint32_t telemetryTxRetries; - uint32_t radioTxRetries; + uint32_t telemetryTxRetries; + uint32_t radioTxRetries; // Is this modem the coordinator - bool isCoordinator; - - // Should we parse UAVTalk? - bool parseUAVTalk; - - // The current configured uart speed - OPLinkSettingsComSpeedOptions comSpeed; + bool isCoordinator; } RadioComBridgeData; // **************** @@ -102,9 +90,8 @@ typedef struct { static void telemetryTxTask(void *parameters); static void telemetryRxTask(void *parameters); -static void serialRxTask(void *parameters); -static void radioTxTask(void *parameters); -static void radioRxTask(void *parameters); +static void telemRadioTxTask(void *parameters); +static void telemRadioRxTask(void *parameters); static void PPMInputTask(void *parameters); static int32_t UAVTalkSendHandler(uint8_t *buf, int32_t length); static int32_t RadioSendHandler(uint8_t *buf, int32_t length); @@ -133,11 +120,6 @@ static int32_t RadioComBridgeStart(void) // Check if this is the coordinator modem data->isCoordinator = (oplinkSettings.Protocol == OPLINKSETTINGS_PROTOCOL_OPLINKCOORDINATOR); - // We will not parse/send UAVTalk if any ports are configured as Serial (except for over the USB HID port). - data->parseUAVTalk = ((oplinkSettings.MainPort != OPLINKSETTINGS_MAINPORT_SERIAL) && - (oplinkSettings.FlexiPort != OPLINKSETTINGS_FLEXIPORT_SERIAL) && - (oplinkSettings.VCPPort != OPLINKSETTINGS_VCPPORT_SERIAL)); - // Set the maximum radio RF power. switch (oplinkSettings.MaxRFPower) { case OPLINKSETTINGS_MAXRFPOWER_125: @@ -186,34 +168,37 @@ static int32_t RadioComBridgeStart(void) ObjectPersistenceConnectCallback(&objectPersistenceUpdatedCb); // Start the primary tasks for receiving/sending UAVTalk packets from the GCS. - xTaskCreate(telemetryTxTask, "telemetryTxTask", STACK_SIZE_BYTES, NULL, TASK_PRIORITY, &(data->telemetryTxTaskHandle)); - xTaskCreate(telemetryRxTask, "telemetryRxTask", STACK_SIZE_BYTES, NULL, TASK_PRIORITY, &(data->telemetryRxTaskHandle)); - if (PIOS_PPM_RECEIVER != 0) { - xTaskCreate(PPMInputTask, "PPMInputTask", STACK_SIZE_BYTES, NULL, TASK_PRIORITY, &(data->PPMInputTaskHandle)); -#ifdef PIOS_INCLUDE_WDG - PIOS_WDG_RegisterFlag(PIOS_WDG_PPMINPUT); + // These tasks are always needed at least for configuration over HID. + xTaskCreate(telemetryTxTask, "telemetryTxTask", TELEM_STACK_SIZE_WORDS, NULL, TASK_PRIORITY, &(data->telemetryTxTaskHandle)); + xTaskCreate(telemetryRxTask, "telemetryRxTask", TELEM_STACK_SIZE_WORDS, NULL, TASK_PRIORITY, &(data->telemetryRxTaskHandle)); +#if defined(PIOS_INCLUDE_WDG) && defined(PIOS_WDG_TELEMETRYTX) + PIOS_WDG_RegisterFlag(PIOS_WDG_TELEMETRYTX); #endif - } - if (!data->parseUAVTalk) { - // If the user wants raw serial communication, we need to spawn another thread to handle it. - xTaskCreate(serialRxTask, "serialRxTask", STACK_SIZE_BYTES, NULL, TASK_PRIORITY, &(data->serialRxTaskHandle)); -#ifdef PIOS_INCLUDE_WDG - PIOS_WDG_RegisterFlag(PIOS_WDG_SERIALRX); +#if defined(PIOS_INCLUDE_WDG) && defined(PIOS_WDG_TELEMETRYRX) + PIOS_WDG_RegisterFlag(PIOS_WDG_TELEMETRYRX); +#endif + // Start the tasks for sending/receiving telemetry over a radio link if a telemetry (GCS) link configured. + if (PIOS_COM_GCS_OUT) { + xTaskCreate(telemRadioTxTask, "telemRadioTxTask", TELEM_STACK_SIZE_WORDS, NULL, TASK_PRIORITY, &(data->telemRadioTxTaskHandle)); + xTaskCreate(telemRadioRxTask, "telemRadioRxTask", TELEM_STACK_SIZE_WORDS, NULL, TASK_PRIORITY, &(data->telemRadioRxTaskHandle)); +#if defined(PIOS_INCLUDE_WDG) && defined(PIOS_WDG_TELEMRADIOTX) + PIOS_WDG_RegisterFlag(PIOS_WDG_TELEMRADIOTX); +#endif +#if defined(PIOS_INCLUDE_WDG) && defined(PIOS_WDG_TELEMRADIORX) + PIOS_WDG_RegisterFlag(PIOS_WDG_TELEMRADIORX); #endif } - xTaskCreate(radioTxTask, "radioTxTask", STACK_SIZE_BYTES, NULL, TASK_PRIORITY, &(data->radioTxTaskHandle)); - xTaskCreate(radioRxTask, "radioRxTask", STACK_SIZE_BYTES, NULL, TASK_PRIORITY, &(data->radioRxTaskHandle)); - // Register the watchdog timers. -#ifdef PIOS_INCLUDE_WDG - PIOS_WDG_RegisterFlag(PIOS_WDG_TELEMETRYTX); - PIOS_WDG_RegisterFlag(PIOS_WDG_TELEMETRYRX); - PIOS_WDG_RegisterFlag(PIOS_WDG_RADIOTX); - PIOS_WDG_RegisterFlag(PIOS_WDG_RADIORX); + // Start the task for reading and processing PPM data if it's configured. + if (PIOS_PPM_RECEIVER) { + xTaskCreate(PPMInputTask, "PPMInputTask", PPM_STACK_SIZE_WORDS, NULL, TASK_PRIORITY, &(data->PPMInputTaskHandle)); +#if defined(PIOS_INCLUDE_WDG) && defined(PIOS_WDG_PPMINPUT) + PIOS_WDG_RegisterFlag(PIOS_WDG_PPMINPUT); #endif + } + return 0; } - return -1; } @@ -248,10 +233,6 @@ static int32_t RadioComBridgeInitialize(void) data->telemetryTxRetries = 0; data->radioTxRetries = 0; - data->parseUAVTalk = true; - data->comSpeed = OPLINKSETTINGS_COMSPEED_9600; - PIOS_COM_RADIO = PIOS_COM_RFM22B; - return 0; } MODULE_INITCALL(RadioComBridgeInitialize, RadioComBridgeStart); @@ -323,9 +304,48 @@ static void updateRadioComBridgeStats() } /** - * @brief Telemetry transmit task, regular priority + * @brief Reads the PPM input device and sends out OPLinkReceiver objects. * - * @param[in] parameters The task parameters + * @param[in] parameters The task parameters (unused) + */ +static void PPMInputTask(__attribute__((unused)) void *parameters) +{ + xSemaphoreHandle sem = PIOS_RCVR_GetSemaphore(PIOS_PPM_RECEIVER, 1); + int16_t channels[RFM22B_PPM_NUM_CHANNELS]; + + while (1) { +#if defined(PIOS_INCLUDE_WDG) && defined(PIOS_WDG_PPMINPUT) + PIOS_WDG_UpdateFlag(PIOS_WDG_PPMINPUT); +#endif + + // Wait for the receiver semaphore. + if (xSemaphoreTake(sem, PPM_INPUT_TIMEOUT) == pdTRUE) { + // Read the receiver inputs. + for (uint8_t i = 0; i < RFM22B_PPM_NUM_CHANNELS; ++i) { + channels[i] = PIOS_RCVR_Read(PIOS_PPM_RECEIVER, i + 1); + } + } else { + // Failsafe + for (uint8_t i = 0; i < RFM22B_PPM_NUM_CHANNELS; ++i) { + channels[i] = PIOS_RCVR_INVALID; + } + } + + // Pass the channel values to the radio device. + PIOS_RFM22B_PPMSet(pios_rfm22b_id, channels, RFM22B_PPM_NUM_CHANNELS); + } +} + + +/**************************************************************************** +* Telemetry tasks and functions +****************************************************************************/ + +/** + * @brief Receives events on the Radio->GCS telemetry stream and sends + * the requested object(s) to the GCS. + * + * @param[in] parameters None. */ static void telemetryTxTask(__attribute__((unused)) void *parameters) { @@ -333,7 +353,7 @@ static void telemetryTxTask(__attribute__((unused)) void *parameters) // Loop forever while (1) { -#ifdef PIOS_INCLUDE_WDG +#if defined(PIOS_INCLUDE_WDG) && defined(PIOS_WDG_TELEMETRYTX) PIOS_WDG_UpdateFlag(PIOS_WDG_TELEMETRYTX); #endif // Wait for queue message @@ -357,16 +377,17 @@ static void telemetryTxTask(__attribute__((unused)) void *parameters) } /** - * @brief Radio tx task. Receive data packets from the com port and send to the radio. + * @brief Receives events on the GCS->Radio telemetry stream and sends + * the requested object(s) over the radio telenetry stream. * - * @param[in] parameters The task parameters + * @param[in] parameters none. */ -static void radioTxTask(__attribute__((unused)) void *parameters) +static void telemRadioTxTask(__attribute__((unused)) void *parameters) { // Task loop while (1) { -#ifdef PIOS_INCLUDE_WDG - PIOS_WDG_UpdateFlag(PIOS_WDG_RADIOTX); +#if defined(PIOS_INCLUDE_WDG) && defined(PIOS_WDG_TELEMRADIOTX) + PIOS_WDG_UpdateFlag(PIOS_WDG_TELEMRADIOTX); #endif // Process the radio event queue, sending UAVObjects over the radio link as necessary. @@ -391,34 +412,24 @@ static void radioTxTask(__attribute__((unused)) void *parameters) } /** - * @brief Radio rx task. Receive data packets from the radio and pass them on. + * @brief Reads data from the radio telemetry port and processes it + * through the Radio->GCS telemetry stream. * * @param[in] parameters The task parameters */ -static void radioRxTask(__attribute__((unused)) void *parameters) +static void telemRadioRxTask(__attribute__((unused)) void *parameters) { // Task loop while (1) { -#ifdef PIOS_INCLUDE_WDG - PIOS_WDG_UpdateFlag(PIOS_WDG_RADIORX); +#if defined(PIOS_INCLUDE_WDG) && defined(PIOS_WDG_TELEMRADIORX) + PIOS_WDG_UpdateFlag(PIOS_WDG_TELEMRADIORX); #endif - if (PIOS_COM_RADIO) { + if (PIOS_COM_GCS_OUT) { uint8_t serial_data[16]; - uint16_t bytes_to_process = PIOS_COM_ReceiveBuffer(PIOS_COM_RADIO, serial_data, sizeof(serial_data), MAX_PORT_DELAY); + uint16_t bytes_to_process = PIOS_COM_ReceiveBuffer(PIOS_COM_GCS_OUT, serial_data, sizeof(serial_data), MAX_PORT_DELAY); if (bytes_to_process > 0) { - if (data->parseUAVTalk) { - // Pass the data through the UAVTalk parser. - ProcessRadioStream(data->radioUAVTalkCon, data->telemUAVTalkCon, serial_data, bytes_to_process); - } else if (PIOS_COM_TELEMETRY) { - // Send the data straight to the telemetry port. - // Following call can fail with -2 error code (buffer full) or -3 error code (could not acquire send mutex) - // It is the caller responsibility to retry in such cases... - int32_t ret = -2; - uint8_t count = 5; - while (count-- > 0 && ret < -1) { - ret = PIOS_COM_SendBufferNonBlocking(PIOS_COM_TELEMETRY, serial_data, bytes_to_process); - } - } + // Pass the data through the UAVTalk parser. + ProcessRadioStream(data->radioUAVTalkCon, data->telemUAVTalkCon, serial_data, bytes_to_process); } } else { vTaskDelay(5); @@ -427,7 +438,8 @@ static void radioRxTask(__attribute__((unused)) void *parameters) } /** - * @brief Receive telemetry from the USB/COM port. + * @brief Reads data from the GCS telemetry port and processes it + * through the GCS->Radio telemetry stream. * * @param[in] parameters The task parameters */ @@ -435,14 +447,15 @@ static void telemetryRxTask(__attribute__((unused)) void *parameters) { // Task loop while (1) { - uint32_t inputPort = data->parseUAVTalk ? PIOS_COM_TELEMETRY : 0; -#ifdef PIOS_INCLUDE_WDG + // uint32_t inputPort = data->parseUAVTalk ? PIOS_COM_TELEMETRY : 0; + uint32_t inputPort = PIOS_COM_GCS; +#if defined(PIOS_INCLUDE_WDG) && defined(PIOS_WDG_TELEMETRYRX) PIOS_WDG_UpdateFlag(PIOS_WDG_TELEMETRYRX); #endif #if defined(PIOS_INCLUDE_USB) // Determine output port (USB takes priority over telemetry port) - if (PIOS_USB_CheckAvailable(0) && PIOS_COM_TELEM_USB_HID) { - inputPort = PIOS_COM_TELEM_USB_HID; + if (PIOS_USB_CheckAvailable(0) && PIOS_COM_HID) { + inputPort = PIOS_COM_HID; } #endif /* PIOS_INCLUDE_USB */ if (inputPort) { @@ -458,73 +471,7 @@ static void telemetryRxTask(__attribute__((unused)) void *parameters) } /** - * @brief Reads the PPM input device and sends out OPLinkReceiver objects. - * - * @param[in] parameters The task parameters (unused) - */ -static void PPMInputTask(__attribute__((unused)) void *parameters) -{ - xSemaphoreHandle sem = PIOS_RCVR_GetSemaphore(PIOS_PPM_RECEIVER, 1); - int16_t channels[RFM22B_PPM_NUM_CHANNELS]; - - while (1) { - #ifdef PIOS_INCLUDE_WDG - PIOS_WDG_UpdateFlag(PIOS_WDG_PPMINPUT); - #endif - - // Wait for the receiver semaphore. - if (xSemaphoreTake(sem, PPM_INPUT_TIMEOUT) == pdTRUE) { - // Read the receiver inputs. - for (uint8_t i = 0; i < RFM22B_PPM_NUM_CHANNELS; ++i) { - channels[i] = PIOS_RCVR_Read(PIOS_PPM_RECEIVER, i + 1); - } - } else { - // Failsafe - for (uint8_t i = 0; i < RFM22B_PPM_NUM_CHANNELS; ++i) { - channels[i] = PIOS_RCVR_INVALID; - } - } - - // Pass the channel values to the radio device. - PIOS_RFM22B_PPMSet(pios_rfm22b_id, channels, RFM22B_PPM_NUM_CHANNELS); - } -} - -/** - * @brief Receive raw serial data from the USB/COM port. - * - * @param[in] parameters The task parameters - */ -static void serialRxTask(__attribute__((unused)) void *parameters) -{ - // Task loop - while (1) { - uint32_t inputPort = PIOS_COM_TELEMETRY; -#ifdef PIOS_INCLUDE_WDG - PIOS_WDG_UpdateFlag(PIOS_WDG_SERIALRX); -#endif - if (inputPort && PIOS_COM_RADIO) { - // Receive some data. - uint16_t bytes_to_process = PIOS_COM_ReceiveBuffer(inputPort, data->serialRxBuf, sizeof(data->serialRxBuf), MAX_PORT_DELAY); - - if (bytes_to_process > 0) { - // Send the data over the radio link. - // Following call can fail with -2 error code (buffer full) or -3 error code (could not acquire send mutex) - // It is the caller responsibility to retry in such cases... - int32_t ret = -2; - uint8_t count = 5; - while (count-- > 0 && ret < -1) { - ret = PIOS_COM_SendBufferNonBlocking(PIOS_COM_RADIO, data->serialRxBuf, bytes_to_process); - } - } - } else { - vTaskDelay(5); - } - } -} - -/** - * @brief Transmit data buffer to the com port. + * @brief Send data from the Radio->GCS telemetry stream to the GCS port. * * @param[in] buf Data buffer to send * @param[in] length Length of buffer @@ -534,12 +481,12 @@ static void serialRxTask(__attribute__((unused)) void *parameters) static int32_t UAVTalkSendHandler(uint8_t *buf, int32_t length) { int32_t ret; - uint32_t outputPort = data->parseUAVTalk ? PIOS_COM_TELEMETRY : 0; + uint32_t outputPort = PIOS_COM_GCS; #if defined(PIOS_INCLUDE_USB) // Determine output port (USB takes priority over telemetry port) - if (PIOS_COM_TELEM_USB_HID && PIOS_COM_Available(PIOS_COM_TELEM_USB_HID)) { - outputPort = PIOS_COM_TELEM_USB_HID; + if (PIOS_COM_HID && PIOS_COM_Available(PIOS_COM_HID)) { + outputPort = PIOS_COM_HID; } #endif /* PIOS_INCLUDE_USB */ if (outputPort) { @@ -557,7 +504,7 @@ static int32_t UAVTalkSendHandler(uint8_t *buf, int32_t length) } /** - * Transmit data buffer to the com port. + * @brief Send data from the GCS telemetry stream to the Radio->GCS port. * * @param[in] buf Data buffer to send * @param[in] length Length of buffer @@ -566,10 +513,7 @@ static int32_t UAVTalkSendHandler(uint8_t *buf, int32_t length) */ static int32_t RadioSendHandler(uint8_t *buf, int32_t length) { - if (!data->parseUAVTalk) { - return length; - } - uint32_t outputPort = PIOS_COM_RADIO; + uint32_t outputPort = PIOS_COM_GCS_OUT; // Don't send any data unless the radio port is available. if (outputPort && PIOS_COM_Available(outputPort)) { diff --git a/flight/pios/common/pios_com.c b/flight/pios/common/pios_com.c index a1bfde67ae..fe5f890619 100644 --- a/flight/pios/common/pios_com.c +++ b/flight/pios/common/pios_com.c @@ -808,6 +808,44 @@ int32_t PIOS_COM_RegisterAvailableCallback(uint32_t com_id, pios_com_callback_av return 0; } +/* + * Callback used to pass data from one ocm port to another in PIOS_COM_LinkComPare. + * \param[in] context The "to" com port + * \param[in] buf The data buffer + * \param[in] buf_len The number of bytes received + * \param[in] headroom Not used + * \param[in] task_woken Not used + */ +static uint16_t PIOS_COM_LinkComPairRxCallback(uint32_t context, uint8_t *buf, uint16_t buf_len, __attribute__((unused)) uint16_t *headroom, __attribute__((unused)) bool *task_woken) +{ + int32_t sent = PIOS_COM_SendBufferNonBlocking(context, buf, buf_len); + + if (sent > 0) { + return sent; + } + return 0; +} + +/* + * Link a pair of com ports so that any data arriving on one is sent out the other. + * \param[in] com1_id The first com port + * \param[in] com2_id The second com port + */ +void PIOS_COM_LinkComPair(uint32_t com1_id, uint32_t com2_id, bool link_ctrl_line, bool link_baud_rate) +{ + PIOS_COM_ASYNC_RegisterRxCallback(com1_id, PIOS_COM_LinkComPairRxCallback, com2_id); + PIOS_COM_ASYNC_RegisterRxCallback(com2_id, PIOS_COM_LinkComPairRxCallback, com1_id); + // Optionally link the control like and baudrate changes between the two. + if (link_ctrl_line) { + PIOS_COM_RegisterCtrlLineCallback(com1_id, (pios_com_callback_ctrl_line)PIOS_COM_SetCtrlLine, com2_id); + PIOS_COM_RegisterCtrlLineCallback(com2_id, (pios_com_callback_ctrl_line)PIOS_COM_SetCtrlLine, com1_id); + } + if (link_baud_rate) { + PIOS_COM_RegisterBaudRateCallback(com1_id, (pios_com_callback_baud_rate)PIOS_COM_ChangeBaud, com2_id); + PIOS_COM_RegisterBaudRateCallback(com2_id, (pios_com_callback_baud_rate)PIOS_COM_ChangeBaud, com1_id); + } +} + #endif /* PIOS_INCLUDE_COM */ /** diff --git a/flight/pios/common/pios_rfm22b.c b/flight/pios/common/pios_rfm22b.c index 4a438b0416..b8640f936f 100644 --- a/flight/pios/common/pios_rfm22b.c +++ b/flight/pios/common/pios_rfm22b.c @@ -808,9 +808,8 @@ bool PIOS_RFM22B_TransmitPacket(uint32_t rfm22b_id, uint8_t *p, uint8_t len) return false; } - rfm22b_dev->tx_packet_handle = p; - rfm22b_dev->stats.tx_byte_count += len; - rfm22b_dev->packet_start_ticks = xTaskGetTickCount(); + rfm22b_dev->tx_packet_handle = p; + rfm22b_dev->packet_start_ticks = xTaskGetTickCount(); if (rfm22b_dev->packet_start_ticks == 0) { rfm22b_dev->packet_start_ticks = 1; } @@ -873,8 +872,6 @@ bool PIOS_RFM22B_TransmitPacket(uint32_t rfm22b_id, uint8_t *p, uint8_t len) // We're in Tx mode. rfm22b_dev->rfm22b_state = RFM22B_STATE_TX_MODE; - TX_LED_ON; - #ifdef PIOS_RFM22B_DEBUG_ON_TELEM D1_LED_ON; #endif @@ -1925,6 +1922,12 @@ static enum pios_radio_event radio_txStart(struct pios_rfm22b_dev *radio_dev) len += RS_ECC_NPARITY; } + // Only count the packet if it contains valid data. + if (radio_dev->ppm_only_mode || (len > RS_ECC_NPARITY)) { + TX_LED_ON; + radio_dev->stats.tx_byte_count += len; + } + // Transmit the packet. PIOS_RFM22B_TransmitPacket((uint32_t)radio_dev, p, len); diff --git a/flight/pios/inc/pios_com.h b/flight/pios/inc/pios_com.h index f576b346fb..eb4ee37a8a 100644 --- a/flight/pios/inc/pios_com.h +++ b/flight/pios/inc/pios_com.h @@ -115,6 +115,8 @@ extern int32_t PIOS_COM_ASYNC_RxStart(uint32_t id, uint16_t rx_bytes_avail); extern int32_t PIOS_COM_ASYNC_RegisterRxCallback(uint32_t id, pios_com_callback rx_in_cb, uint32_t context); extern int32_t PIOS_COM_ASYNC_RegisterTxCallback(uint32_t id, pios_com_callback tx_out_cb, uint32_t context); +extern void PIOS_COM_LinkComPair(uint32_t com1_id, uint32_t com2_id, bool link_ctrl_line, bool link_baud_rate); + #define COM_AVAILABLE_NONE (0) #define COM_AVAILABLE_RX (1 << 0) #define COM_AVAILABLE_TX (1 << 1) diff --git a/flight/targets/boards/oplinkmini/board_hw_defs.c b/flight/targets/boards/oplinkmini/board_hw_defs.c index 548f965ddf..3dde19b94c 100644 --- a/flight/targets/boards/oplinkmini/board_hw_defs.c +++ b/flight/targets/boards/oplinkmini/board_hw_defs.c @@ -691,7 +691,7 @@ const struct pios_ppm_out_cfg pios_flexi_ppm_out_cfg = { /* * SERIAL USART */ -static const struct pios_usart_cfg pios_usart_serial_cfg = { +static const struct pios_usart_cfg pios_usart_main_cfg = { .regs = USART1, .init = { .USART_BaudRate = 57600, @@ -727,7 +727,7 @@ static const struct pios_usart_cfg pios_usart_serial_cfg = { }, }; -static const struct pios_usart_cfg pios_usart_telem_flexi_cfg = { +static const struct pios_usart_cfg pios_usart_flexi_cfg = { .regs = USART3, .init = { .USART_BaudRate = 57600, diff --git a/flight/targets/boards/oplinkmini/bootloader/main.c b/flight/targets/boards/oplinkmini/bootloader/main.c index 28cfcc30b4..2dc3842ed0 100644 --- a/flight/targets/boards/oplinkmini/bootloader/main.c +++ b/flight/targets/boards/oplinkmini/bootloader/main.c @@ -56,6 +56,8 @@ uint32_t sweep_steps2 = 100; // * 5 mS -> 500 mS //////////////////////////////////////// uint8_t tempcount = 0; +extern uint32_t pios_com_telem_usb_id; + /* Extern variables ----------------------------------------------------------*/ DFUStates DeviceState; int16_t status = 0; @@ -211,7 +213,7 @@ uint32_t LedPWM(uint32_t pwm_period, uint32_t pwm_sweep_steps, uint32_t count) uint8_t processRX() { - if (PIOS_COM_MSG_Receive(PIOS_COM_TELEM_USB, mReceive_Buffer, sizeof(mReceive_Buffer))) { + if (PIOS_COM_MSG_Receive(pios_com_telem_usb_id, mReceive_Buffer, sizeof(mReceive_Buffer))) { processComand(mReceive_Buffer); } return TRUE; @@ -219,5 +221,5 @@ uint8_t processRX() int32_t platform_senddata(const uint8_t *msg, uint16_t msg_len) { - return PIOS_COM_MSG_Send(PIOS_COM_TELEM_USB, msg, msg_len); + return PIOS_COM_MSG_Send(pios_com_telem_usb_id, msg, msg_len); } diff --git a/flight/targets/boards/oplinkmini/firmware/Makefile b/flight/targets/boards/oplinkmini/firmware/Makefile index 93261a9824..534bbf5e25 100644 --- a/flight/targets/boards/oplinkmini/firmware/Makefile +++ b/flight/targets/boards/oplinkmini/firmware/Makefile @@ -31,7 +31,7 @@ override USE_DSP_LIB := NO MODULES += RadioComBridge # List of optional modules to include -OPTMODULES = ComUsbBridge +OPTMODULES = # List C source files here (C dependencies are automatically generated). # Use file-extension c for "c-only"-files diff --git a/flight/targets/boards/oplinkmini/firmware/inc/pios_config.h b/flight/targets/boards/oplinkmini/firmware/inc/pios_config.h index 074d876062..78addac306 100644 --- a/flight/targets/boards/oplinkmini/firmware/inc/pios_config.h +++ b/flight/targets/boards/oplinkmini/firmware/inc/pios_config.h @@ -146,26 +146,20 @@ /* #define PIOS_QUATERNION_STABILIZATION */ /* Performance counters */ -#define IDLE_COUNTS_PER_SEC_AT_NO_LOAD 1995998 +#define IDLE_COUNTS_PER_SEC_AT_NO_LOAD 1995998 /* Alarm Thresholds */ -#define HEAP_LIMIT_WARNING 220 -#define HEAP_LIMIT_CRITICAL 40 -#define IRQSTACK_LIMIT_WARNING 100 -#define IRQSTACK_LIMIT_CRITICAL 60 -#define CPULOAD_LIMIT_WARNING 85 -#define CPULOAD_LIMIT_CRITICAL 95 +#define HEAP_LIMIT_WARNING 220 +#define HEAP_LIMIT_CRITICAL 40 +#define IRQSTACK_LIMIT_WARNING 100 +#define IRQSTACK_LIMIT_CRITICAL 60 +#define CPULOAD_LIMIT_WARNING 85 +#define CPULOAD_LIMIT_CRITICAL 95 /* Task stack sizes */ -#define PIOS_ACTUATOR_STACK_SIZE 1020 -#define PIOS_MANUAL_STACK_SIZE 724 -#define PIOS_SYSTEM_STACK_SIZE 460 -#define PIOS_STABILIZATION_STACK_SIZE 524 -#define PIOS_TELEM_STACK_SIZE 800 -#define PIOS_EVENTDISPATCHER_STACK_SIZE 130 /* This can't be too high to stop eventdispatcher thread overflowing */ -#define PIOS_EVENTDISAPTCHER_QUEUE 10 +#define PIOS_EVENTDISAPTCHER_QUEUE 10 #endif /* PIOS_CONFIG_H */ /** diff --git a/flight/targets/boards/oplinkmini/firmware/pios_board.c b/flight/targets/boards/oplinkmini/firmware/pios_board.c index 552aa196d1..7b07878214 100644 --- a/flight/targets/boards/oplinkmini/firmware/pios_board.c +++ b/flight/targets/boards/oplinkmini/firmware/pios_board.c @@ -48,43 +48,44 @@ */ #include "../board_hw_defs.c" -#define PIOS_COM_TELEM_USB_RX_BUF_LEN 256 -#define PIOS_COM_TELEM_USB_TX_BUF_LEN 256 +#define PIOS_COM_TELEM_USB_RX_BUF_LEN 128 +#define PIOS_COM_TELEM_USB_TX_BUF_LEN 128 -#define PIOS_COM_TELEM_VCP_RX_BUF_LEN 256 -#define PIOS_COM_TELEM_VCP_TX_BUF_LEN 256 +#define PIOS_COM_TELEM_VCP_RX_BUF_LEN 128 +#define PIOS_COM_TELEM_VCP_TX_BUF_LEN 128 -#define PIOS_COM_RFM22B_RF_RX_BUF_LEN 256 -#define PIOS_COM_RFM22B_RF_TX_BUF_LEN 256 +#define PIOS_COM_RFM22B_RF_RX_BUF_LEN 128 +#define PIOS_COM_RFM22B_RF_TX_BUF_LEN 128 -#define PIOS_COM_TELEM_RX_BUF_LEN 256 -#define PIOS_COM_TELEM_TX_BUF_LEN 256 +#define PIOS_COM_TELEM_RX_BUF_LEN 128 +#define PIOS_COM_TELEM_TX_BUF_LEN 128 -uint32_t pios_com_telem_usb_id = 0; -uint32_t pios_com_telem_vcp_id = 0; -uint32_t pios_com_telem_uart_main_id = 0; -uint32_t pios_com_telem_uart_flexi_id = 0; -uint32_t pios_com_telemetry_id = 0; -uint32_t pios_com_bridge_id = 0; -uint32_t pios_com_vcp_id = 0; +uint32_t pios_com_hid_id = 0; +uint32_t pios_com_vcp_id = 0; +uint32_t pios_com_main_id = 0; +uint32_t pios_com_flexi_id = 0; +uint32_t pios_com_bridge_id = 0; +uint32_t pios_com_gcs_id = 0; +uint32_t pios_com_gcs_out_id = 0; #if defined(PIOS_INCLUDE_PPM) -uint32_t pios_ppm_rcvr_id = 0; +uint32_t pios_ppm_rcvr_id = 0; #endif #if defined(PIOS_INCLUDE_PPM_OUT) -uint32_t pios_ppm_out_id = 0; +uint32_t pios_ppm_out_id = 0; #endif #if defined(PIOS_INCLUDE_RFM22B) #include -uint32_t pios_rfm22b_id = 0; -uint32_t pios_com_rfm22b_id = 0; -uint32_t pios_com_radio_id = 0; +uint32_t pios_rfm22b_id = 0; +uint32_t pios_com_pri_radio_id = 0; +uint32_t pios_com_aux_radio_id = 0; +uint32_t pios_com_pri_radio_out_id = 0; +uint32_t pios_com_aux_radio_out_id = 0; #endif - uintptr_t pios_uavo_settings_fs_id; -uintptr_t pios_user_fs_id = 0; +uintptr_t pios_user_fs_id = 0; -uint8_t servo_count = 0; +static uint8_t servo_count = 0; /* * Setup a com port based on the passed cfg, driver and buffer sizes. @@ -188,6 +189,22 @@ void PIOS_Board_Init(void) OPLinkStatusInitialize(); #endif /* PIOS_INCLUDE_RFM22B */ + /* Retrieve the settings object. */ + OPLinkSettingsData oplinkSettings; + OPLinkSettingsGet(&oplinkSettings); + + /* Determine the modem protocols */ + bool is_coordinator = (oplinkSettings.Protocol == OPLINKSETTINGS_PROTOCOL_OPLINKCOORDINATOR); + bool openlrs = (oplinkSettings.Protocol == OPLINKSETTINGS_PROTOCOL_OPENLRS); + bool ppm_only = (oplinkSettings.LinkType == OPLINKSETTINGS_LINKTYPE_CONTROL); + bool data_mode = ((oplinkSettings.LinkType == OPLINKSETTINGS_LINKTYPE_DATA) || + (oplinkSettings.LinkType == OPLINKSETTINGS_LINKTYPE_DATAANDCONTROL)); + bool is_enabled = ((oplinkSettings.Protocol != OPLINKSETTINGS_PROTOCOL_DISABLED) && + ((oplinkSettings.MaxRFPower != OPLINKSETTINGS_MAXRFPOWER_0) || openlrs)); + bool ppm_mode = ((oplinkSettings.LinkType == OPLINKSETTINGS_LINKTYPE_CONTROL) || + (oplinkSettings.LinkType == OPLINKSETTINGS_LINKTYPE_DATAANDCONTROL)); + bool servo_main = false; + bool servo_flexi = false; #if defined(PIOS_INCLUDE_TIM) /* Set up pulse timers */ @@ -229,7 +246,7 @@ void PIOS_Board_Init(void) uint8_t *tx_buffer = (uint8_t *)pios_malloc(PIOS_COM_TELEM_USB_TX_BUF_LEN); PIOS_Assert(rx_buffer); PIOS_Assert(tx_buffer); - if (PIOS_COM_Init(&pios_com_telem_usb_id, &pios_usb_hid_com_driver, pios_usb_hid_id, + if (PIOS_COM_Init(&pios_com_hid_id, &pios_usb_hid_com_driver, pios_usb_hid_id, rx_buffer, PIOS_COM_TELEM_USB_RX_BUF_LEN, tx_buffer, PIOS_COM_TELEM_USB_TX_BUF_LEN)) { PIOS_Assert(0); @@ -247,7 +264,7 @@ void PIOS_Board_Init(void) uint8_t *tx_buffer = (uint8_t *)pios_malloc(PIOS_COM_TELEM_VCP_TX_BUF_LEN); PIOS_Assert(rx_buffer); PIOS_Assert(tx_buffer); - if (PIOS_COM_Init(&pios_com_telem_vcp_id, &pios_usb_cdc_com_driver, pios_usb_cdc_id, + if (PIOS_COM_Init(&pios_com_vcp_id, &pios_usb_cdc_com_driver, pios_usb_cdc_id, rx_buffer, PIOS_COM_TELEM_VCP_RX_BUF_LEN, tx_buffer, PIOS_COM_TELEM_VCP_TX_BUF_LEN)) { PIOS_Assert(0); @@ -256,40 +273,40 @@ void PIOS_Board_Init(void) #endif // Configure the main port - OPLinkSettingsData oplinkSettings; - OPLinkSettingsGet(&oplinkSettings); - bool is_coordinator = (oplinkSettings.Protocol == OPLINKSETTINGS_PROTOCOL_OPLINKCOORDINATOR); - bool openlrs = (oplinkSettings.Protocol == OPLINKSETTINGS_PROTOCOL_OPENLRS); - bool ppm_only = (oplinkSettings.LinkType == OPLINKSETTINGS_LINKTYPE_CONTROL); - bool data_mode = ((oplinkSettings.LinkType == OPLINKSETTINGS_LINKTYPE_DATA) || - (oplinkSettings.LinkType == OPLINKSETTINGS_LINKTYPE_DATAANDCONTROL)); - bool is_enabled = ((oplinkSettings.Protocol != OPLINKSETTINGS_PROTOCOL_DISABLED) && - ((oplinkSettings.MaxRFPower != OPLINKSETTINGS_MAXRFPOWER_0) || openlrs)); - bool ppm_mode = ((oplinkSettings.LinkType == OPLINKSETTINGS_LINKTYPE_CONTROL) || - (oplinkSettings.LinkType == OPLINKSETTINGS_LINKTYPE_DATAANDCONTROL)); - bool servo_main = false; - bool servo_flexi = false; + uint32_t mainComSpeed = 0; + switch (oplinkSettings.MainComSpeed) { + case OPLINKSETTINGS_MAINCOMSPEED_4800: + mainComSpeed = 4800; + break; + case OPLINKSETTINGS_MAINCOMSPEED_9600: + mainComSpeed = 9600; + break; + case OPLINKSETTINGS_MAINCOMSPEED_19200: + mainComSpeed = 19200; + break; + case OPLINKSETTINGS_MAINCOMSPEED_38400: + mainComSpeed = 38400; + break; + case OPLINKSETTINGS_MAINCOMSPEED_57600: + mainComSpeed = 57600; + break; + case OPLINKSETTINGS_MAINCOMSPEED_115200: + mainComSpeed = 115200; + break; + case OPLINKSETTINGS_MAINCOMSPEED_DISABLED: + break; + } switch (oplinkSettings.MainPort) { case OPLINKSETTINGS_MAINPORT_TELEMETRY: case OPLINKSETTINGS_MAINPORT_SERIAL: - { - /* Configure the main port for uart serial */ #ifndef PIOS_RFM22B_DEBUG_ON_TELEM - PIOS_Board_configure_com(&pios_usart_serial_cfg, - PIOS_COM_TELEM_RX_BUF_LEN, PIOS_COM_TELEM_TX_BUF_LEN, - &pios_usart_com_driver, &pios_com_telem_uart_main_id); - - PIOS_COM_TELEMETRY = PIOS_COM_TELEM_UART_MAIN; -#endif - break; - } - case OPLINKSETTINGS_MAINPORT_COMBRIDGE: - PIOS_Board_configure_com(&pios_usart_serial_cfg, + PIOS_Board_configure_com(&pios_usart_main_cfg, PIOS_COM_TELEM_RX_BUF_LEN, PIOS_COM_TELEM_TX_BUF_LEN, - &pios_usart_com_driver, &pios_com_bridge_id); + &pios_usart_com_driver, &pios_com_main_id); + PIOS_COM_ChangeBaud(pios_com_main_id, mainComSpeed); +#endif /* !PIOS_RFM22B_DEBUG_ON_TELEM */ break; case OPLINKSETTINGS_MAINPORT_PPM: - { #if defined(PIOS_INCLUDE_PPM) /* PPM input is configured on the coordinator modem and output on the remote modem. */ if (is_coordinator) { @@ -308,35 +325,47 @@ void PIOS_Board_Init(void) #endif /* PIOS_INCLUDE_PPM_OUT */ #endif /* PIOS_INCLUDE_PPM */ break; - } case OPLINKSETTINGS_MAINPORT_PWM: servo_main = true; - break; - case OPLINKSETTINGS_MAINPORT_DISABLED: + default: break; } // Configure the flexi port + uint32_t flexiComSpeed = 0; + switch (oplinkSettings.FlexiComSpeed) { + case OPLINKSETTINGS_FLEXICOMSPEED_4800: + flexiComSpeed = 4800; + break; + case OPLINKSETTINGS_FLEXICOMSPEED_9600: + flexiComSpeed = 9600; + break; + case OPLINKSETTINGS_FLEXICOMSPEED_19200: + flexiComSpeed = 19200; + break; + case OPLINKSETTINGS_FLEXICOMSPEED_38400: + flexiComSpeed = 38400; + break; + case OPLINKSETTINGS_FLEXICOMSPEED_57600: + flexiComSpeed = 57600; + break; + case OPLINKSETTINGS_FLEXICOMSPEED_115200: + flexiComSpeed = 115200; + break; + case OPLINKSETTINGS_FLEXICOMSPEED_DISABLED: + break; + } switch (oplinkSettings.FlexiPort) { case OPLINKSETTINGS_FLEXIPORT_TELEMETRY: case OPLINKSETTINGS_FLEXIPORT_SERIAL: - { - /* Configure the flexi port as uart serial */ - PIOS_Board_configure_com(&pios_usart_telem_flexi_cfg, - PIOS_COM_TELEM_RX_BUF_LEN, PIOS_COM_TELEM_TX_BUF_LEN, - &pios_usart_com_driver, - &pios_com_telem_uart_flexi_id); - PIOS_COM_TELEMETRY = PIOS_COM_TELEM_UART_FLEXI; - break; - } - case OPLINKSETTINGS_FLEXIPORT_COMBRIDGE: - PIOS_Board_configure_com(&pios_usart_telem_flexi_cfg, +#ifndef PIOS_RFM22B_DEBUG_ON_TELEM + PIOS_Board_configure_com(&pios_usart_flexi_cfg, PIOS_COM_TELEM_RX_BUF_LEN, PIOS_COM_TELEM_TX_BUF_LEN, - &pios_usart_com_driver, - &pios_com_bridge_id); + &pios_usart_com_driver, &pios_com_flexi_id); + PIOS_COM_ChangeBaud(pios_com_flexi_id, flexiComSpeed); +#endif /* !PIOS_RFM22B_DEBUG_ON_TELEM */ break; case OPLINKSETTINGS_FLEXIPORT_PPM: - { #if defined(PIOS_INCLUDE_PPM) /* PPM input is configured on the coordinator modem and output on the remote modem. */ if (is_coordinator) { @@ -346,31 +375,22 @@ void PIOS_Board_Init(void) if (PIOS_RCVR_Init(&pios_ppm_rcvr_id, &pios_ppm_rcvr_driver, pios_ppm_id)) { PIOS_Assert(0); } - } else { + } + // For some reason, PPM output on the flexi port doesn't work. +#if defined(PIOS_INCLUDE_PPM_OUT) + else { PIOS_PPM_Out_Init(&pios_ppm_out_id, &pios_flexi_ppm_out_cfg); } +#endif /* PIOS_INCLUDE_PPM_OUT */ #endif /* PIOS_INCLUDE_PPM */ break; - } case OPLINKSETTINGS_FLEXIPORT_PWM: servo_flexi = true; - break; - case OPLINKSETTINGS_FLEXIPORT_DISABLED: - break; - } - - // Configure the USB VCP port - switch (oplinkSettings.VCPPort) { - case OPLINKSETTINGS_VCPPORT_SERIAL: - PIOS_COM_TELEMETRY = PIOS_COM_TELEM_USB_VCP; - break; - case OPLINKSETTINGS_VCPPORT_COMBRIDGE: - PIOS_COM_VCP = PIOS_COM_TELEM_USB_VCP; - break; - case OPLINKSETTINGS_VCPPORT_DISABLED: + default: break; } + /* Configure the PWM servo outputs. */ #if defined(PIOS_INCLUDE_SERVO) if (servo_main) { if (servo_flexi) { @@ -429,33 +449,53 @@ void PIOS_Board_Init(void) uint8_t *tx_buffer = (uint8_t *)pios_malloc(PIOS_COM_RFM22B_RF_TX_BUF_LEN); PIOS_Assert(rx_buffer); PIOS_Assert(tx_buffer); - if (PIOS_COM_Init(&pios_com_rfm22b_id, &pios_rfm22b_com_driver, pios_rfm22b_id, + if (PIOS_COM_Init(&pios_com_pri_radio_id, &pios_rfm22b_com_driver, pios_rfm22b_id, rx_buffer, PIOS_COM_RFM22B_RF_RX_BUF_LEN, tx_buffer, PIOS_COM_RFM22B_RF_TX_BUF_LEN)) { PIOS_Assert(0); } - // Set the RF data rate on the modem to ~2X the selected buad rate because the modem is half duplex. + // Initialize the aux radio com interface + uint8_t *auxrx_buffer = (uint8_t *)pios_malloc(PIOS_COM_TELEM_RX_BUF_LEN); + uint8_t *auxtx_buffer = (uint8_t *)pios_malloc(PIOS_COM_TELEM_TX_BUF_LEN); + PIOS_Assert(auxrx_buffer); + PIOS_Assert(auxtx_buffer); + if (PIOS_COM_Init(&pios_com_aux_radio_id, &pios_rfm22b_aux_com_driver, pios_rfm22b_id, + auxrx_buffer, PIOS_COM_TELEM_RX_BUF_LEN, + auxtx_buffer, PIOS_COM_TELEM_TX_BUF_LEN)) { + PIOS_Assert(0); + } + + // Set the modem (over the air) datarate. enum rfm22b_datarate datarate = RFM22_datarate_64000; - switch (oplinkSettings.ComSpeed) { - case OPLINKSETTINGS_COMSPEED_4800: + switch (oplinkSettings.AirDataRate) { + case OPLINKSETTINGS_AIRDATARATE_9600: datarate = RFM22_datarate_9600; break; - case OPLINKSETTINGS_COMSPEED_9600: + case OPLINKSETTINGS_AIRDATARATE_19200: datarate = RFM22_datarate_19200; break; - case OPLINKSETTINGS_COMSPEED_19200: + case OPLINKSETTINGS_AIRDATARATE_32000: datarate = RFM22_datarate_32000; break; - case OPLINKSETTINGS_COMSPEED_38400: + case OPLINKSETTINGS_AIRDATARATE_57600: + datarate = RFM22_datarate_57600; + break; + case OPLINKSETTINGS_AIRDATARATE_64000: datarate = RFM22_datarate_64000; break; - case OPLINKSETTINGS_COMSPEED_57600: + case OPLINKSETTINGS_AIRDATARATE_100000: datarate = RFM22_datarate_100000; break; - case OPLINKSETTINGS_COMSPEED_115200: + case OPLINKSETTINGS_AIRDATARATE_128000: + datarate = RFM22_datarate_128000; + break; + case OPLINKSETTINGS_AIRDATARATE_192000: datarate = RFM22_datarate_192000; break; + case OPLINKSETTINGS_AIRDATARATE_256000: + datarate = RFM22_datarate_256000; + break; } /* Set the modem Tx power level */ @@ -499,61 +539,92 @@ void PIOS_Board_Init(void) if (ppm_mode || (ppm_only && !is_coordinator)) { PIOS_RFM22B_SetPPMCallback(pios_rfm22b_id, PIOS_Board_PPM_callback, 0); } - - // Reinitialize the modem to affect the changes. - PIOS_RFM22B_Reinit(pios_rfm22b_id); - uint8_t oplinksettings_radioaux; - OPLinkSettingsRadioAuxStreamGet(&oplinksettings_radioaux); - switch (oplinksettings_radioaux) { - case OPLINKSETTINGS_RADIOAUXSTREAM_DISABLED: - break; - case OPLINKSETTINGS_RADIOAUXSTREAM_COMBRIDGE: - { - uint8_t *auxrx_buffer = (uint8_t *)pios_malloc(PIOS_COM_TELEM_RX_BUF_LEN); - uint8_t *auxtx_buffer = (uint8_t *)pios_malloc(PIOS_COM_TELEM_TX_BUF_LEN); - PIOS_Assert(auxrx_buffer); - PIOS_Assert(auxtx_buffer); - if (PIOS_COM_Init(&pios_com_bridge_id, &pios_rfm22b_aux_com_driver, pios_rfm22b_id, - auxrx_buffer, PIOS_COM_TELEM_RX_BUF_LEN, - auxtx_buffer, PIOS_COM_TELEM_TX_BUF_LEN)) { - PIOS_Assert(0); - } - } - } } // openlrs } else { oplinkStatus.LinkState = OPLINKSTATUS_LINKSTATE_DISABLED; } - // Update the object - OPLinkStatusSet(&oplinkStatus); - - // Update the com baud rate. - uint32_t comBaud = 9600; - switch (oplinkSettings.ComSpeed) { - case OPLINKSETTINGS_COMSPEED_4800: - comBaud = 4800; + // Configure the primary radio stream destination. + switch (oplinkSettings.RadioPriStream) { + case OPLINKSETTINGS_RADIOPRISTREAM_DISABLED: + break; + case OPLINKSETTINGS_RADIOPRISTREAM_HID: + // HID is always connected to GCS + pios_com_gcs_id = pios_com_hid_id; + pios_com_gcs_out_id = pios_com_pri_radio_id; + break; + case OPLINKSETTINGS_RADIOPRISTREAM_MAIN: + // Is the main port configured for telemetry (GCS)? + if (oplinkSettings.MainPort == OPLINKSETTINGS_MAINPORT_TELEMETRY) { + pios_com_gcs_id = pios_com_main_id; + pios_com_gcs_out_id = pios_com_pri_radio_id; + } else { + PIOS_COM_LinkComPair(pios_com_pri_radio_id, pios_com_main_id, false, false); + } + break; + case OPLINKSETTINGS_RADIOPRISTREAM_FLEXI: + // Is the flexi port configured for telemetry (GCS)? + if (oplinkSettings.FlexiPort == OPLINKSETTINGS_FLEXIPORT_TELEMETRY) { + pios_com_gcs_id = pios_com_flexi_id; + pios_com_gcs_out_id = pios_com_pri_radio_id; + } else { + PIOS_COM_LinkComPair(pios_com_pri_radio_id, pios_com_flexi_id, false, false); + } + break; + case OPLINKSETTINGS_RADIOPRISTREAM_VCP: + // VCP is never connected to GCS + PIOS_COM_LinkComPair(pios_com_pri_radio_id, pios_com_vcp_id, false, false); break; - case OPLINKSETTINGS_COMSPEED_9600: - comBaud = 9600; + } + + // Configure the Auxiliary radio stream destination. + switch (oplinkSettings.RadioAuxStream) { + case OPLINKSETTINGS_RADIOAUXSTREAM_DISABLED: break; - case OPLINKSETTINGS_COMSPEED_19200: - comBaud = 19200; + case OPLINKSETTINGS_RADIOAUXSTREAM_HID: + // HID is always connected to GCS + pios_com_gcs_id = pios_com_hid_id; + pios_com_gcs_out_id = pios_com_aux_radio_id; break; - case OPLINKSETTINGS_COMSPEED_38400: - comBaud = 38400; + case OPLINKSETTINGS_RADIOAUXSTREAM_MAIN: + // Is the main port configured for telemetry (GCS)? + if (oplinkSettings.MainPort == OPLINKSETTINGS_MAINPORT_TELEMETRY) { + pios_com_gcs_id = pios_com_main_id; + pios_com_gcs_out_id = pios_com_aux_radio_id; + } else { + PIOS_COM_LinkComPair(pios_com_aux_radio_id, pios_com_main_id, false, false); + } break; - case OPLINKSETTINGS_COMSPEED_57600: - comBaud = 57600; + case OPLINKSETTINGS_RADIOAUXSTREAM_FLEXI: + // Is the flexi port configured for telemetry (GCS)? + if (oplinkSettings.FlexiPort == OPLINKSETTINGS_FLEXIPORT_TELEMETRY) { + pios_com_gcs_id = pios_com_flexi_id; + pios_com_gcs_out_id = pios_com_aux_radio_id; + } else { + PIOS_COM_LinkComPair(pios_com_aux_radio_id, pios_com_flexi_id, false, false); + } break; - case OPLINKSETTINGS_COMSPEED_115200: - comBaud = 115200; + case OPLINKSETTINGS_RADIOAUXSTREAM_VCP: + // VCP is never connected to GCS + PIOS_COM_LinkComPair(pios_com_aux_radio_id, pios_com_vcp_id, false, false); break; } - if (PIOS_COM_TELEMETRY) { - PIOS_COM_ChangeBaud(PIOS_COM_TELEMETRY, comBaud); + + // Configure the VCP COM bridge + switch (oplinkSettings.VCPBridge) { + case OPLINKSETTINGS_VCPBRIDGE_MAIN: + PIOS_COM_LinkComPair(pios_com_vcp_id, pios_com_main_id, true, true); + break; + case OPLINKSETTINGS_VCPBRIDGE_FLEXI: + PIOS_COM_LinkComPair(pios_com_vcp_id, pios_com_flexi_id, true, true); + break; + case OPLINKSETTINGS_VCPBRIDGE_DISABLED: + break; } + // Update the object + OPLinkStatusSet(&oplinkStatus); + /* Remap AFIO pin */ GPIO_PinRemapConfig(GPIO_Remap_SWJ_NoJTRST, ENABLE); diff --git a/flight/targets/boards/oplinkmini/pios_board.h b/flight/targets/boards/oplinkmini/pios_board.h index f54e19a898..ab7e3630aa 100644 --- a/flight/targets/boards/oplinkmini/pios_board.h +++ b/flight/targets/boards/oplinkmini/pios_board.h @@ -73,11 +73,10 @@ #define PIOS_WDG_REGISTER BKP_DR4 #define PIOS_WDG_TELEMETRYTX 0x0001 #define PIOS_WDG_TELEMETRYRX 0x0002 -#define PIOS_WDG_RADIOTX 0x0004 -#define PIOS_WDG_RADIORX 0x0008 +#define PIOS_WDG_TELEMRADIOTX 0x0004 +#define PIOS_WDG_TELEMRADIORX 0x0008 #define PIOS_WDG_RFM22B 0x000f #define PIOS_WDG_PPMINPUT 0x0010 -#define PIOS_WDG_SERIALRX 0x0020 // ------------------------ // TELEMETRY @@ -174,30 +173,40 @@ extern uint32_t pios_i2c_flexi_adapter_id; // ------------------------- #define PIOS_COM_MAX_DEVS 5 -extern uint32_t pios_com_telem_usb_id; -extern uint32_t pios_com_telem_vcp_id; -extern uint32_t pios_com_telem_uart_main_id; -extern uint32_t pios_com_telem_uart_flexi_id; -extern uint32_t pios_com_telemetry_id; -extern uint32_t pios_com_rfm22b_id; -extern uint32_t pios_com_radio_id; -extern uint32_t pios_com_bridge_id; +// The direct com ports +extern uint32_t pios_com_hid_id; extern uint32_t pios_com_vcp_id; +extern uint32_t pios_com_main_id; +extern uint32_t pios_com_flexi_id; +extern uint32_t pios_com_pri_radio_id; +extern uint32_t pios_com_aux_radio_id; +// The port that the GCS is connected to +extern uint32_t pios_com_gcs_id; +// The destination port from the GCS port +extern uint32_t pios_com_gcs_out_id; +// The destination port from the VCP com bridge +extern uint32_t pios_com_bridge_id; +// The destination port for the primary radio port +extern uint32_t pios_com_pri_radio_out_id; +// The destination port for the auxiliary radio port. +extern uint32_t pios_com_aux_radio_out_id; +// The PPM IDs extern uint32_t pios_ppm_rcvr_id; extern uint32_t pios_ppm_out_id; -#define PIOS_COM_TELEM_USB_HID (pios_com_telem_usb_id) -#define PIOS_COM_TELEM_USB PIOS_COM_TELEM_USB_HID -#define PIOS_COM_TELEM_USB_VCP (pios_com_telem_vcp_id) -#define PIOS_COM_VCP (pios_com_vcp_id) -#define PIOS_COM_TELEM_UART_MAIN (pios_com_telem_uart_main_id) -#define PIOS_COM_TELEM_UART_FLEXI (pios_com_telem_uart_flexi_id) -#define PIOS_COM_TELEMETRY (pios_com_telemetry_id) -#define PIOS_COM_RFM22B (pios_com_rfm22b_id) -#define PIOS_COM_RADIO (pios_com_radio_id) -#define PIOS_COM_BRIDGE (pios_com_bridge_id) -#define PIOS_PPM_RECEIVER (pios_ppm_rcvr_id) -#define PIOS_PPM_OUTPUT (pios_ppm_out_id) -#define RFM22_DEBUG 1 +#define PIOS_COM_HID (pios_com_hid_id) +#define PIOS_COM_VCP (pios_com_vcp_id) +#define PIOS_COM_MAIN (pios_com_main_id) +#define PIOS_COM_FLEXI (pios_com_flexi_id) +#define PIOS_COM_PRI_RADIO (pios_com_pri_radio_id) +#define PIOS_COM_AUX_RADIO (pios_com_aux_radio_id) +#define PIOS_COM_PRI_RADIO_OUT (pios_com_pri_radio_out_id) +#define PIOS_COM_AUX_RADIO_OUT (pios_com_aux_radio_out_id) +#define PIOS_COM_GCS (pios_com_gcs_id) +#define PIOS_COM_GCS_OUT (pios_com_gcs_out_id) +#define PIOS_COM_BRIDGE (pios_com_bridge_id) +#define PIOS_PPM_RECEIVER (pios_ppm_rcvr_id) +#define PIOS_PPM_OUTPUT (pios_ppm_out_id) +#define RFM22_DEBUG 1 // ------------------------- // ADC diff --git a/flight/targets/boards/revolution/firmware/pios_board.c b/flight/targets/boards/revolution/firmware/pios_board.c index e5294dc3ec..9795c9e97c 100644 --- a/flight/targets/boards/revolution/firmware/pios_board.c +++ b/flight/targets/boards/revolution/firmware/pios_board.c @@ -931,27 +931,36 @@ void PIOS_Board_Init(void) oplinkStatus.LinkState = OPLINKSTATUS_LINKSTATE_ENABLED; - // Set the RF data rate on the modem to ~2X the selected buad rate because the modem is half duplex. + // Set the modem (over the air) datarate. enum rfm22b_datarate datarate = RFM22_datarate_64000; - switch (oplinkSettings.ComSpeed) { - case OPLINKSETTINGS_COMSPEED_4800: + switch (oplinkSettings.AirDataRate) { + case OPLINKSETTINGS_AIRDATARATE_9600: datarate = RFM22_datarate_9600; break; - case OPLINKSETTINGS_COMSPEED_9600: + case OPLINKSETTINGS_AIRDATARATE_19200: datarate = RFM22_datarate_19200; break; - case OPLINKSETTINGS_COMSPEED_19200: + case OPLINKSETTINGS_AIRDATARATE_32000: datarate = RFM22_datarate_32000; break; - case OPLINKSETTINGS_COMSPEED_38400: + case OPLINKSETTINGS_AIRDATARATE_57600: + datarate = RFM22_datarate_57600; + break; + case OPLINKSETTINGS_AIRDATARATE_64000: datarate = RFM22_datarate_64000; break; - case OPLINKSETTINGS_COMSPEED_57600: + case OPLINKSETTINGS_AIRDATARATE_100000: datarate = RFM22_datarate_100000; break; - case OPLINKSETTINGS_COMSPEED_115200: + case OPLINKSETTINGS_AIRDATARATE_128000: + datarate = RFM22_datarate_128000; + break; + case OPLINKSETTINGS_AIRDATARATE_192000: datarate = RFM22_datarate_192000; break; + case OPLINKSETTINGS_AIRDATARATE_256000: + datarate = RFM22_datarate_256000; + break; } /* Set the radio configuration parameters. */ diff --git a/flight/targets/boards/sparky2/firmware/pios_board.c b/flight/targets/boards/sparky2/firmware/pios_board.c index 48cc37df95..270f531523 100644 --- a/flight/targets/boards/sparky2/firmware/pios_board.c +++ b/flight/targets/boards/sparky2/firmware/pios_board.c @@ -861,27 +861,36 @@ void PIOS_Board_Init(void) oplinkStatus.LinkState = OPLINKSTATUS_LINKSTATE_ENABLED; - // Set the RF data rate on the modem to ~2X the selected buad rate because the modem is half duplex. + // Set the modem (over the air) datarate. enum rfm22b_datarate datarate = RFM22_datarate_64000; - switch (oplinkSettings.ComSpeed) { - case OPLINKSETTINGS_COMSPEED_4800: + switch (oplinkSettings.AirDataRate) { + case OPLINKSETTINGS_AIRDATARATE_9600: datarate = RFM22_datarate_9600; break; - case OPLINKSETTINGS_COMSPEED_9600: + case OPLINKSETTINGS_AIRDATARATE_19200: datarate = RFM22_datarate_19200; break; - case OPLINKSETTINGS_COMSPEED_19200: + case OPLINKSETTINGS_AIRDATARATE_32000: datarate = RFM22_datarate_32000; break; - case OPLINKSETTINGS_COMSPEED_38400: + case OPLINKSETTINGS_AIRDATARATE_57600: + datarate = RFM22_datarate_57600; + break; + case OPLINKSETTINGS_AIRDATARATE_64000: datarate = RFM22_datarate_64000; break; - case OPLINKSETTINGS_COMSPEED_57600: + case OPLINKSETTINGS_AIRDATARATE_100000: datarate = RFM22_datarate_100000; break; - case OPLINKSETTINGS_COMSPEED_115200: + case OPLINKSETTINGS_AIRDATARATE_128000: + datarate = RFM22_datarate_128000; + break; + case OPLINKSETTINGS_AIRDATARATE_192000: datarate = RFM22_datarate_192000; break; + case OPLINKSETTINGS_AIRDATARATE_256000: + datarate = RFM22_datarate_256000; + break; } /* Set the radio configuration parameters. */ diff --git a/ground/gcs/src/plugins/config/configoplinkwidget.cpp b/ground/gcs/src/plugins/config/configoplinkwidget.cpp index 886f91ee91..89d57c4d6e 100644 --- a/ground/gcs/src/plugins/config/configoplinkwidget.cpp +++ b/ground/gcs/src/plugins/config/configoplinkwidget.cpp @@ -79,11 +79,14 @@ ConfigOPLinkWidget::ConfigOPLinkWidget(QWidget *parent) : ConfigTaskWidget(paren addWidgetBinding("OPLinkSettings", "MinChannel", m_oplink->MinimumChannel); addWidgetBinding("OPLinkSettings", "MaxChannel", m_oplink->MaximumChannel); addWidgetBinding("OPLinkSettings", "MaxRFPower", m_oplink->MaxRFTxPower); - addWidgetBinding("OPLinkSettings", "ComSpeed", m_oplink->ComSpeed); addWidgetBinding("OPLinkSettings", "MainPort", m_oplink->MainPort); addWidgetBinding("OPLinkSettings", "FlexiPort", m_oplink->FlexiPort); - addWidgetBinding("OPLinkSettings", "VCPPort", m_oplink->VCPPort); - addWidgetBinding("OPLinkSettings", "RadioAuxStream", m_oplink->RadioAuxPort); + addWidgetBinding("OPLinkSettings", "RadioPriStream", m_oplink->RadioPriStream); + addWidgetBinding("OPLinkSettings", "RadioAuxStream", m_oplink->RadioAuxStream); + addWidgetBinding("OPLinkSettings", "VCPBridge", m_oplink->VCPBridge); + addWidgetBinding("OPLinkSettings", "MainComSpeed", m_oplink->MainComSpeed); + addWidgetBinding("OPLinkSettings", "FlexiComSpeed", m_oplink->FlexiComSpeed); + addWidgetBinding("OPLinkSettings", "AirDataRate", m_oplink->AirDataRate); addWidgetBinding("OPLinkSettings", "RFXtalCap", m_oplink->RFXtalCapValue); addWidgetBinding("OPLinkSettings", "RFXtalCap", m_oplink->RFXtalCapSlider); @@ -121,7 +124,9 @@ ConfigOPLinkWidget::ConfigOPLinkWidget(QWidget *parent) : ConfigTaskWidget(paren connect(m_oplink->MaximumChannel, SIGNAL(valueChanged(int)), this, SLOT(maxChannelChanged())); connect(m_oplink->MainPort, SIGNAL(currentIndexChanged(int)), this, SLOT(mainPortChanged())); connect(m_oplink->FlexiPort, SIGNAL(currentIndexChanged(int)), this, SLOT(flexiPortChanged())); - connect(m_oplink->VCPPort, SIGNAL(currentIndexChanged(int)), this, SLOT(vcpPortChanged())); + connect(m_oplink->RadioPriStream, SIGNAL(currentIndexChanged(int)), this, SLOT(radioPriStreamChanged())); + connect(m_oplink->RadioAuxStream, SIGNAL(currentIndexChanged(int)), this, SLOT(radioAuxStreamChanged())); + connect(m_oplink->VCPBridge, SIGNAL(currentIndexChanged(int)), this, SLOT(vcpBridgeChanged())); // Connect the Unbind button connect(m_oplink->UnbindButton, SIGNAL(released()), this, SLOT(unbind())); @@ -203,14 +208,22 @@ void ConfigOPLinkWidget::updateStatus() void ConfigOPLinkWidget::setPortsVisible(bool visible) { + m_oplink->UartsLabel->setVisible(visible); m_oplink->MainPort->setVisible(visible); m_oplink->MainPortLabel->setVisible(visible); m_oplink->FlexiPort->setVisible(visible); m_oplink->FlexiPortLabel->setVisible(visible); - m_oplink->VCPPort->setVisible(visible); - m_oplink->VCPPortLabel->setVisible(visible); - m_oplink->RadioAuxPort->setVisible(visible); - m_oplink->RadioAuxPortLabel->setVisible(visible); + m_oplink->ConnectionsLabel->setVisible(visible); + m_oplink->RadioPriStream->setVisible(visible); + m_oplink->RadioPriStreamLabel->setVisible(visible); + m_oplink->RadioAuxStream->setVisible(visible); + m_oplink->RadioAuxStreamLabel->setVisible(visible); + m_oplink->MainComSpeed->setVisible(visible); + m_oplink->MainComSpeedLabel->setVisible(visible); + m_oplink->FlexiComSpeed->setVisible(visible); + m_oplink->FlexiComSpeedLabel->setVisible(visible); + m_oplink->VCPBridge->setVisible(visible); + m_oplink->VCPBridgeLabel->setVisible(visible); } void ConfigOPLinkWidget::updateInfo() @@ -255,30 +268,35 @@ void ConfigOPLinkWidget::updateSettings() { // qDebug() << "ConfigOPLinkWidget::updateSettings"; - bool is_enabled = !isComboboxOptionSelected(m_oplink->Protocol, OPLinkSettings::PROTOCOL_DISABLED); - bool is_coordinator = isComboboxOptionSelected(m_oplink->Protocol, OPLinkSettings::PROTOCOL_OPLINKCOORDINATOR); - bool is_receiver = isComboboxOptionSelected(m_oplink->Protocol, OPLinkSettings::PROTOCOL_OPLINKRECEIVER); - bool is_openlrs = isComboboxOptionSelected(m_oplink->Protocol, OPLinkSettings::PROTOCOL_OPENLRS); - bool is_ppm_only = isComboboxOptionSelected(m_oplink->LinkType, OPLinkSettings::LINKTYPE_CONTROL); + bool is_enabled = !isComboboxOptionSelected(m_oplink->Protocol, OPLinkSettings::PROTOCOL_DISABLED); + bool is_coordinator = isComboboxOptionSelected(m_oplink->Protocol, OPLinkSettings::PROTOCOL_OPLINKCOORDINATOR); + bool is_receiver = isComboboxOptionSelected(m_oplink->Protocol, OPLinkSettings::PROTOCOL_OPLINKRECEIVER); + bool is_openlrs = isComboboxOptionSelected(m_oplink->Protocol, OPLinkSettings::PROTOCOL_OPENLRS); + bool is_ppm_only = isComboboxOptionSelected(m_oplink->LinkType, OPLinkSettings::LINKTYPE_CONTROL); + bool is_main_serial = isComboboxOptionSelected(m_oplink->MainPort, OPLinkSettings::MAINPORT_SERIAL); + bool is_main_telem = isComboboxOptionSelected(m_oplink->MainPort, OPLinkSettings::MAINPORT_TELEMETRY); + bool is_flexi_serial = isComboboxOptionSelected(m_oplink->FlexiPort, OPLinkSettings::FLEXIPORT_SERIAL); + bool is_flexi_telem = isComboboxOptionSelected(m_oplink->FlexiPort, OPLinkSettings::FLEXIPORT_TELEMETRY); + bool is_vcp_main = isComboboxOptionSelected(m_oplink->VCPBridge, OPLinkSettings::VCPBRIDGE_MAIN); + bool is_vcp_flexi = isComboboxOptionSelected(m_oplink->VCPBridge, OPLinkSettings::VCPBRIDGE_FLEXI); bool is_bound = (m_oplink->CoordID->text() != ""); - m_oplink->ComSpeed->setEnabled(is_enabled && !is_ppm_only && !is_openlrs); + m_oplink->MainPort->setEnabled(is_enabled || is_vcp_main); + m_oplink->FlexiPort->setEnabled(is_enabled || is_vcp_flexi); + m_oplink->MainComSpeed->setEnabled((is_enabled || is_vcp_main) && !is_ppm_only && !is_openlrs && (is_main_serial || is_main_telem)); + m_oplink->FlexiComSpeed->setEnabled((is_enabled || is_vcp_flexi) && !is_ppm_only && !is_openlrs && (is_flexi_serial || is_flexi_telem)); m_oplink->CoordID->setEnabled(is_enabled && is_receiver); m_oplink->UnbindButton->setEnabled(is_enabled && is_bound && !is_coordinator); m_oplink->CustomDeviceID->setEnabled(is_coordinator); - m_oplink->RadioAuxPort->setEnabled(is_receiver || is_coordinator); + m_oplink->RadioPriStream->setEnabled((is_receiver || is_coordinator) && !is_ppm_only); + m_oplink->RadioAuxStream->setEnabled((is_receiver || is_coordinator) && !is_ppm_only); + m_oplink->AirDataRate->setEnabled((is_receiver || is_coordinator) && !is_ppm_only); m_oplink->RFBand->setEnabled(is_receiver || is_coordinator); m_oplink->MinimumChannel->setEnabled(is_receiver || is_coordinator); m_oplink->MaximumChannel->setEnabled(is_receiver || is_coordinator); - enableComboBoxOptionItem(m_oplink->VCPPort, OPLinkSettings::VCPPORT_SERIAL, (is_receiver || is_coordinator)); - - if (isComboboxOptionSelected(m_oplink->VCPPort, OPLinkSettings::VCPPORT_SERIAL) && !(is_receiver || is_coordinator)) { - setComboboxSelectedOption(m_oplink->VCPPort, OPLinkSettings::VCPPORT_DISABLED); - } - m_oplink->LinkType->setEnabled(is_enabled && !is_openlrs); m_oplink->MaxRFTxPower->setEnabled(is_enabled && !is_openlrs); } @@ -366,22 +384,28 @@ void ConfigOPLinkWidget::updateFrequencyDisplay() void ConfigOPLinkWidget::mainPortChanged() { switch (getComboboxSelectedOption(m_oplink->MainPort)) { - case OPLinkSettings::MAINPORT_TELEMETRY: - case OPLinkSettings::MAINPORT_SERIAL: - if (isComboboxOptionSelected(m_oplink->FlexiPort, OPLinkSettings::FLEXIPORT_TELEMETRY) - || isComboboxOptionSelected(m_oplink->FlexiPort, OPLinkSettings::FLEXIPORT_SERIAL)) { - setComboboxSelectedOption(m_oplink->FlexiPort, OPLinkSettings::FLEXIPORT_DISABLED); + case OPLinkSettings::MAINPORT_PPM: + case OPLinkSettings::MAINPORT_PWM: + case OPLinkSettings::MAINPORT_DISABLED: + if (isComboboxOptionSelected(m_oplink->RadioPriStream, OPLinkSettings::RADIOPRISTREAM_MAIN)) { + setComboboxSelectedOption(m_oplink->RadioPriStream, OPLinkSettings::RADIOPRISTREAM_DISABLED); } - break; - case OPLinkSettings::MAINPORT_COMBRIDGE: - if (isComboboxOptionSelected(m_oplink->FlexiPort, OPLinkSettings::FLEXIPORT_COMBRIDGE)) { - setComboboxSelectedOption(m_oplink->FlexiPort, OPLinkSettings::FLEXIPORT_DISABLED); + if (isComboboxOptionSelected(m_oplink->RadioAuxStream, OPLinkSettings::RADIOAUXSTREAM_MAIN)) { + setComboboxSelectedOption(m_oplink->RadioAuxStream, OPLinkSettings::RADIOAUXSTREAM_DISABLED); + } + if (isComboboxOptionSelected(m_oplink->VCPBridge, OPLinkSettings::VCPBRIDGE_MAIN)) { + setComboboxSelectedOption(m_oplink->VCPBridge, OPLinkSettings::VCPBRIDGE_DISABLED); } + m_oplink->MainComSpeed->setEnabled(false); break; - case OPLinkSettings::MAINPORT_PPM: - if (isComboboxOptionSelected(m_oplink->FlexiPort, OPLinkSettings::FLEXIPORT_PPM)) { - setComboboxSelectedOption(m_oplink->FlexiPort, OPLinkSettings::FLEXIPORT_DISABLED); + case OPLinkSettings::MAINPORT_TELEMETRY: + if (isComboboxOptionSelected(m_oplink->FlexiPort, OPLinkSettings::FLEXIPORT_TELEMETRY)) { + setComboboxSelectedOption(m_oplink->FlexiPort, OPLinkSettings::FLEXIPORT_SERIAL); } + case OPLinkSettings::MAINPORT_SERIAL: + m_oplink->MainComSpeed->setEnabled(true); + break; + default: break; } } @@ -389,41 +413,161 @@ void ConfigOPLinkWidget::mainPortChanged() void ConfigOPLinkWidget::flexiPortChanged() { switch (getComboboxSelectedOption(m_oplink->FlexiPort)) { + case OPLinkSettings::FLEXIPORT_PPM: + case OPLinkSettings::FLEXIPORT_PWM: + case OPLinkSettings::FLEXIPORT_DISABLED: + if (isComboboxOptionSelected(m_oplink->RadioPriStream, OPLinkSettings::RADIOPRISTREAM_FLEXI)) { + setComboboxSelectedOption(m_oplink->RadioPriStream, OPLinkSettings::RADIOPRISTREAM_DISABLED); + } + if (isComboboxOptionSelected(m_oplink->RadioAuxStream, OPLinkSettings::RADIOAUXSTREAM_FLEXI)) { + setComboboxSelectedOption(m_oplink->RadioAuxStream, OPLinkSettings::RADIOAUXSTREAM_DISABLED); + } + if (isComboboxOptionSelected(m_oplink->VCPBridge, OPLinkSettings::VCPBRIDGE_FLEXI)) { + setComboboxSelectedOption(m_oplink->VCPBridge, OPLinkSettings::VCPBRIDGE_DISABLED); + } + m_oplink->FlexiComSpeed->setEnabled(false); + break; case OPLinkSettings::FLEXIPORT_TELEMETRY: + if (isComboboxOptionSelected(m_oplink->MainPort, OPLinkSettings::MAINPORT_TELEMETRY)) { + setComboboxSelectedOption(m_oplink->MainPort, OPLinkSettings::MAINPORT_SERIAL); + } + m_oplink->FlexiComSpeed->setEnabled(true); + break; case OPLinkSettings::FLEXIPORT_SERIAL: - if (isComboboxOptionSelected(m_oplink->MainPort, OPLinkSettings::MAINPORT_TELEMETRY) - || isComboboxOptionSelected(m_oplink->MainPort, OPLinkSettings::MAINPORT_SERIAL)) { - setComboboxSelectedOption(m_oplink->MainPort, OPLinkSettings::MAINPORT_DISABLED); + m_oplink->FlexiComSpeed->setEnabled(true); + break; + default: + break; + } +} + +void ConfigOPLinkWidget::radioPriStreamChanged() +{ + switch (getComboboxSelectedOption(m_oplink->RadioPriStream)) { + case OPLinkSettings::RADIOPRISTREAM_DISABLED: + break; + case OPLinkSettings::RADIOPRISTREAM_HID: + if (isComboboxOptionSelected(m_oplink->RadioAuxStream, OPLinkSettings::RADIOAUXSTREAM_HID)) { + setComboboxSelectedOption(m_oplink->RadioAuxStream, OPLinkSettings::RADIOAUXSTREAM_DISABLED); } break; - case OPLinkSettings::FLEXIPORT_COMBRIDGE: - if (isComboboxOptionSelected(m_oplink->MainPort, OPLinkSettings::MAINPORT_COMBRIDGE)) { - setComboboxSelectedOption(m_oplink->MainPort, OPLinkSettings::MAINPORT_DISABLED); + case OPLinkSettings::RADIOPRISTREAM_MAIN: + if (!isComboboxOptionSelected(m_oplink->MainPort, OPLinkSettings::MAINPORT_TELEMETRY) && + !isComboboxOptionSelected(m_oplink->MainPort, OPLinkSettings::MAINPORT_SERIAL)) { + setComboboxSelectedOption(m_oplink->MainPort, OPLinkSettings::MAINPORT_SERIAL); + } + if (isComboboxOptionSelected(m_oplink->RadioAuxStream, OPLinkSettings::RADIOAUXSTREAM_MAIN)) { + setComboboxSelectedOption(m_oplink->RadioAuxStream, OPLinkSettings::RADIOAUXSTREAM_DISABLED); + } + if (isComboboxOptionSelected(m_oplink->VCPBridge, OPLinkSettings::VCPBRIDGE_MAIN)) { + setComboboxSelectedOption(m_oplink->VCPBridge, OPLinkSettings::VCPBRIDGE_DISABLED); } break; - case OPLinkSettings::FLEXIPORT_PPM: - if (isComboboxOptionSelected(m_oplink->MainPort, OPLinkSettings::MAINPORT_PPM)) { - setComboboxSelectedOption(m_oplink->MainPort, OPLinkSettings::MAINPORT_DISABLED); + case OPLinkSettings::RADIOPRISTREAM_FLEXI: + if (!isComboboxOptionSelected(m_oplink->FlexiPort, OPLinkSettings::FLEXIPORT_TELEMETRY) && + !isComboboxOptionSelected(m_oplink->FlexiPort, OPLinkSettings::FLEXIPORT_SERIAL)) { + setComboboxSelectedOption(m_oplink->FlexiPort, OPLinkSettings::FLEXIPORT_SERIAL); + } + if (isComboboxOptionSelected(m_oplink->RadioAuxStream, OPLinkSettings::RADIOAUXSTREAM_FLEXI)) { + setComboboxSelectedOption(m_oplink->RadioAuxStream, OPLinkSettings::RADIOAUXSTREAM_DISABLED); + } + if (isComboboxOptionSelected(m_oplink->VCPBridge, OPLinkSettings::VCPBRIDGE_FLEXI)) { + setComboboxSelectedOption(m_oplink->VCPBridge, OPLinkSettings::VCPBRIDGE_DISABLED); + } + break; + case OPLinkSettings::RADIOPRISTREAM_VCP: + if (!isComboboxOptionSelected(m_oplink->VCPBridge, OPLinkSettings::VCPBRIDGE_DISABLED)) { + setComboboxSelectedOption(m_oplink->VCPBridge, OPLinkSettings::VCPBRIDGE_DISABLED); + } + if (isComboboxOptionSelected(m_oplink->RadioAuxStream, OPLinkSettings::RADIOAUXSTREAM_VCP)) { + setComboboxSelectedOption(m_oplink->RadioAuxStream, OPLinkSettings::RADIOAUXSTREAM_DISABLED); } break; } + updateSettings(); } -void ConfigOPLinkWidget::vcpPortChanged() +void ConfigOPLinkWidget::radioAuxStreamChanged() { - bool vcpComBridgeEnabled = isComboboxOptionSelected(m_oplink->VCPPort, OPLinkSettings::VCPPORT_COMBRIDGE); - - enableComboBoxOptionItem(m_oplink->MainPort, OPLinkSettings::MAINPORT_COMBRIDGE, vcpComBridgeEnabled); - enableComboBoxOptionItem(m_oplink->FlexiPort, OPLinkSettings::FLEXIPORT_COMBRIDGE, vcpComBridgeEnabled); + switch (getComboboxSelectedOption(m_oplink->RadioAuxStream)) { + case OPLinkSettings::RADIOAUXSTREAM_DISABLED: + break; + case OPLinkSettings::RADIOAUXSTREAM_HID: + if (isComboboxOptionSelected(m_oplink->RadioPriStream, OPLinkSettings::RADIOPRISTREAM_HID)) { + setComboboxSelectedOption(m_oplink->RadioPriStream, OPLinkSettings::RADIOPRISTREAM_DISABLED); + } + break; + case OPLinkSettings::RADIOAUXSTREAM_MAIN: + if (!isComboboxOptionSelected(m_oplink->MainPort, OPLinkSettings::MAINPORT_TELEMETRY) && + !isComboboxOptionSelected(m_oplink->MainPort, OPLinkSettings::MAINPORT_SERIAL)) { + setComboboxSelectedOption(m_oplink->MainPort, OPLinkSettings::MAINPORT_SERIAL); + } + if (isComboboxOptionSelected(m_oplink->RadioPriStream, OPLinkSettings::RADIOPRISTREAM_MAIN)) { + setComboboxSelectedOption(m_oplink->RadioPriStream, OPLinkSettings::RADIOPRISTREAM_DISABLED); + } + if (isComboboxOptionSelected(m_oplink->VCPBridge, OPLinkSettings::VCPBRIDGE_MAIN)) { + setComboboxSelectedOption(m_oplink->VCPBridge, OPLinkSettings::VCPBRIDGE_DISABLED); + } + break; + case OPLinkSettings::RADIOAUXSTREAM_FLEXI: + if (!isComboboxOptionSelected(m_oplink->FlexiPort, OPLinkSettings::FLEXIPORT_TELEMETRY) && + !isComboboxOptionSelected(m_oplink->FlexiPort, OPLinkSettings::FLEXIPORT_SERIAL)) { + setComboboxSelectedOption(m_oplink->FlexiPort, OPLinkSettings::FLEXIPORT_SERIAL); + } + if (isComboboxOptionSelected(m_oplink->RadioPriStream, OPLinkSettings::RADIOPRISTREAM_FLEXI)) { + setComboboxSelectedOption(m_oplink->RadioPriStream, OPLinkSettings::RADIOPRISTREAM_DISABLED); + } + if (isComboboxOptionSelected(m_oplink->VCPBridge, OPLinkSettings::VCPBRIDGE_MAIN)) { + setComboboxSelectedOption(m_oplink->VCPBridge, OPLinkSettings::VCPBRIDGE_DISABLED); + } + break; + case OPLinkSettings::RADIOAUXSTREAM_VCP: + if (!isComboboxOptionSelected(m_oplink->VCPBridge, OPLinkSettings::VCPBRIDGE_DISABLED)) { + setComboboxSelectedOption(m_oplink->VCPBridge, OPLinkSettings::VCPBRIDGE_DISABLED); + } + if (isComboboxOptionSelected(m_oplink->RadioPriStream, OPLinkSettings::RADIOPRISTREAM_VCP)) { + setComboboxSelectedOption(m_oplink->RadioPriStream, OPLinkSettings::RADIOPRISTREAM_DISABLED); + } + break; + } + updateSettings(); +} - if (!vcpComBridgeEnabled) { - if (isComboboxOptionSelected(m_oplink->MainPort, OPLinkSettings::MAINPORT_COMBRIDGE)) { - setComboboxSelectedOption(m_oplink->MainPort, OPLinkSettings::MAINPORT_DISABLED); +void ConfigOPLinkWidget::vcpBridgeChanged() +{ + switch (getComboboxSelectedOption(m_oplink->VCPBridge)) { + case OPLinkSettings::VCPBRIDGE_DISABLED: + break; + case OPLinkSettings::VCPBRIDGE_MAIN: + if (!isComboboxOptionSelected(m_oplink->MainPort, OPLinkSettings::MAINPORT_TELEMETRY) && + !isComboboxOptionSelected(m_oplink->MainPort, OPLinkSettings::MAINPORT_SERIAL)) { + setComboboxSelectedOption(m_oplink->MainPort, OPLinkSettings::MAINPORT_SERIAL); + } + if (isComboboxOptionSelected(m_oplink->RadioPriStream, OPLinkSettings::RADIOPRISTREAM_VCP) || + isComboboxOptionSelected(m_oplink->RadioPriStream, OPLinkSettings::RADIOPRISTREAM_MAIN)) { + setComboboxSelectedOption(m_oplink->RadioPriStream, OPLinkSettings::RADIOPRISTREAM_DISABLED); + } + if (isComboboxOptionSelected(m_oplink->RadioAuxStream, OPLinkSettings::RADIOAUXSTREAM_VCP) || + isComboboxOptionSelected(m_oplink->RadioAuxStream, OPLinkSettings::RADIOAUXSTREAM_MAIN)) { + setComboboxSelectedOption(m_oplink->RadioAuxStream, OPLinkSettings::RADIOAUXSTREAM_DISABLED); + } + break; + case OPLinkSettings::VCPBRIDGE_FLEXI: + if (!isComboboxOptionSelected(m_oplink->FlexiPort, OPLinkSettings::FLEXIPORT_TELEMETRY) && + !isComboboxOptionSelected(m_oplink->FlexiPort, OPLinkSettings::FLEXIPORT_SERIAL)) { + setComboboxSelectedOption(m_oplink->FlexiPort, OPLinkSettings::FLEXIPORT_SERIAL); + } + if (isComboboxOptionSelected(m_oplink->RadioPriStream, OPLinkSettings::RADIOPRISTREAM_VCP) || + isComboboxOptionSelected(m_oplink->RadioPriStream, OPLinkSettings::RADIOPRISTREAM_FLEXI)) { + setComboboxSelectedOption(m_oplink->RadioPriStream, OPLinkSettings::RADIOPRISTREAM_DISABLED); } - if (isComboboxOptionSelected(m_oplink->FlexiPort, OPLinkSettings::FLEXIPORT_COMBRIDGE)) { - setComboboxSelectedOption(m_oplink->FlexiPort, OPLinkSettings::FLEXIPORT_DISABLED); + if (isComboboxOptionSelected(m_oplink->RadioAuxStream, OPLinkSettings::RADIOAUXSTREAM_VCP) || + isComboboxOptionSelected(m_oplink->RadioAuxStream, OPLinkSettings::RADIOAUXSTREAM_FLEXI)) { + setComboboxSelectedOption(m_oplink->RadioAuxStream, OPLinkSettings::RADIOAUXSTREAM_DISABLED); } + break; } + updateSettings(); } void ConfigOPLinkWidget::unbind() diff --git a/ground/gcs/src/plugins/config/configoplinkwidget.h b/ground/gcs/src/plugins/config/configoplinkwidget.h index 959e28b7d4..25e9a1b7cb 100644 --- a/ground/gcs/src/plugins/config/configoplinkwidget.h +++ b/ground/gcs/src/plugins/config/configoplinkwidget.h @@ -78,7 +78,9 @@ private slots: void mainPortChanged(); void flexiPortChanged(); - void vcpPortChanged(); + void radioPriStreamChanged(); + void radioAuxStreamChanged(); + void vcpBridgeChanged(); void unbind(); }; diff --git a/ground/gcs/src/plugins/config/oplink.ui b/ground/gcs/src/plugins/config/oplink.ui index 2a6b2a6dab..0ce5929db9 100644 --- a/ground/gcs/src/plugins/config/oplink.ui +++ b/ground/gcs/src/plugins/config/oplink.ui @@ -101,7 +101,7 @@ Configuration - + @@ -138,7 +138,7 @@ The device must be rebooted for the binding to take place. - + @@ -196,7 +196,29 @@ Leave blank to use autogenerated Device ID. - + + + + + 0 + 0 + + + + + 50 + true + + + + Serial Ports + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + @@ -212,20 +234,44 @@ Leave blank to use autogenerated Device ID. - - - - - 0 - 0 - + + + + Choose a function for the main port. - + + + + + + + 50 + false + + + + Speed + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + - 80 - 0 + 16777215 + 16777215 + + Choose the baud rate for the main com port. + + + + + 50 @@ -233,15 +279,38 @@ Leave blank to use autogenerated Device ID. - Max Chan + Flexi Port Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - + + + + Choose a function for the flexi port. + + + + + + + + 50 + false + + + + Speed + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + 16777215 @@ -249,18 +318,102 @@ Leave blank to use autogenerated Device ID. - Set the modem protocol + Choose the baud rate for the main com port. - - Qt::LeftToRight + + + + + + + 0 + 0 + + + + + 50 + true + + + + Connections + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 50 + false + - - 0 + + Radio Primary + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - + + + + Choose a destination for the primary radio stream. + + + + + + + + 50 + false + + + + Air Data Rate + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 90 + 16777215 + + + + Choose the over-the-air baud rate for the radio. + + + + + + + + 50 + false + + + + Radio Auxiliary + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + 16777215 @@ -268,18 +421,53 @@ Leave blank to use autogenerated Device ID. - Choose the function for the main port. + Choose a destination for the auxiliary radio stream. - - + + + + + 50 + false + + + + VCP Bridge + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 16777215 + 16777215 + + + + Choose a destination for the Virtual Com Port bridge connection. + + + + + 0 0 + + + 80 + 0 + + 50 @@ -287,13 +475,32 @@ Leave blank to use autogenerated Device ID. - Max Power + Max Chan Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + 16777215 + 16777215 + + + + Set the modem protocol + + + Qt::LeftToRight + + + 0 + + + @@ -307,7 +514,7 @@ Leave blank to use autogenerated Device ID. - + @@ -358,20 +565,7 @@ Leave blank to use autogenerated Device ID. - - - - - 16777215 - 16777215 - - - - Choose the function for the flexi port. - - - - + Qt::NoFocus @@ -384,7 +578,7 @@ Leave blank to use autogenerated Device ID. - + @@ -428,29 +622,6 @@ Leave blank to use autogenerated Device ID. - - - - - 50 - false - - - - Com Speed - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Com speed in bps. - - - @@ -467,7 +638,7 @@ Leave blank to use autogenerated Device ID. - + @@ -518,7 +689,7 @@ Leave blank to use autogenerated Device ID. - + @@ -534,23 +705,7 @@ Leave blank to use autogenerated Device ID. - - - - - 50 - false - - - - Flexi Port - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - + @@ -588,28 +743,14 @@ Leave blank to use autogenerated Device ID. - - - - - 16777215 - 16777215 - - - - Set the maximum TX output power the modem will use (mW) -0 to disable the modem. - - - Qt::LeftToRight - - - 0 + + + + + 0 + 0 + - - - - 50 @@ -617,15 +758,15 @@ Leave blank to use autogenerated Device ID. - RF Band + Max Power Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - + + 90 @@ -633,7 +774,8 @@ Leave blank to use autogenerated Device ID. - Set the RF Band used. + Set the maximum TX output power the modem will use (mW) +0 to disable the modem. Qt::LeftToRight @@ -643,8 +785,8 @@ Leave blank to use autogenerated Device ID. - - + + 50 @@ -652,52 +794,29 @@ Leave blank to use autogenerated Device ID. - VCP Port + RF Band Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - + + - 16777215 + 90 16777215 - Choose the function for the USB virtual com port. - - - - - - - - 50 - false - - - - Radio Aux Port - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Set the RF Band used. - - - - - - - 16777215 - 16777215 - + + Qt::LeftToRight - - Choose the function for the Radio Auxiliary virtual com port. + + 0 diff --git a/shared/uavobjectdefinition/oplinksettings.xml b/shared/uavobjectdefinition/oplinksettings.xml index 2b83d21bd8..91a1adc731 100644 --- a/shared/uavobjectdefinition/oplinksettings.xml +++ b/shared/uavobjectdefinition/oplinksettings.xml @@ -3,27 +3,33 @@ OPLink configurations options. - - - - - - - - - + - - + + + + + + + + + + + - - + + + + + + + From c16eb9821bb08c73cb6204c718d37ef111e1bf1e Mon Sep 17 00:00:00 2001 From: Laurent Lalanne Date: Sun, 23 Apr 2017 02:08:34 +0200 Subject: [PATCH 210/624] LP-510 Fix OPLM panel display and SMeter --- ground/gcs/src/share/qml/js/uav.js | 8 ++ ground/gcs/src/share/qml/pfd/Panels.qml | 131 +----------------------- 2 files changed, 13 insertions(+), 126 deletions(-) diff --git a/ground/gcs/src/share/qml/js/uav.js b/ground/gcs/src/share/qml/js/uav.js index 789a9f52fe..4ae549713d 100644 --- a/ground/gcs/src/share/qml/js/uav.js +++ b/ground/gcs/src/share/qml/js/uav.js @@ -229,6 +229,14 @@ function isOplmConnected() { return (opLinkStatus.linkState == OPLinkStatus.LinkState.Connected); } +function OplmRSSI() { + return (opLinkStatus.rssi); +} + +function OplmDeviceID() { + return (opLinkStatus.deviceID); +} + function magSourceName() { var auxMagTypeText = ["GPSv9", "Flexi", "I2C", "DJI"]; var magStateSourceText = ["Invalid", "OnBoard", "ExtMag"]; diff --git a/ground/gcs/src/share/qml/pfd/Panels.qml b/ground/gcs/src/share/qml/pfd/Panels.qml index e9a865de01..563fdf561e 100644 --- a/ground/gcs/src/share/qml/pfd/Panels.qml +++ b/ground/gcs/src/share/qml/pfd/Panels.qml @@ -85,11 +85,8 @@ Item { property real smeter_angle - // Needed to get correctly int8 value, reset value (-127) on disconnect - property int oplm0_db: (telemetry_link == 1) ? opLinkStatus.pairSignalStrengths0 : -127 - property int oplm1_db: (telemetry_link == 1) ? opLinkStatus.pairSignalStrengths1 : -127 - property int oplm2_db: (telemetry_link == 1) ? opLinkStatus.pairSignalStrengths2 : -127 - property int oplm3_db: (telemetry_link == 1) ? opLinkStatus.pairSignalStrengths3 : -127 + // Needed to get correctly int8 value + property int oplm_rssi: UAV.OplmRSSI() property real telemetry_sum property real telemetry_sum_old @@ -117,62 +114,11 @@ Item { // Filtering for S-meter. Smeter range -127dB <--> -13dB = S9+60dB Timer { - id: smeter_filter0 + id: smeter_filter interval: 100; running: true; repeat: true - onTriggered: smeter_angle = (0.90 * smeter_angle) + (0.1 * (oplm0_db + 13)) + onTriggered: smeter_angle = (0.90 * smeter_angle) + (0.1 * (oplm_rssi + 13)) } - Timer { - id: smeter_filter1 - interval: 100; repeat: true - onTriggered: smeter_angle = (0.90 * smeter_angle) + (0.1 * (oplm1_db + 13)) - } - - Timer { - id: smeter_filter2 - interval: 100; repeat: true - onTriggered: smeter_angle = (0.90 * smeter_angle) + (0.1 * (oplm2_db + 13)) - } - - Timer { - id: smeter_filter3 - interval: 100; repeat: true - onTriggered: smeter_angle = (0.90 * smeter_angle) + (0.1 * (oplm3_db + 13)) - } - - property int smeter_filter - property variant oplm_pair_id : opLinkStatus.pairIDs0 - - function select_oplm(index){ - smeter_filter0.running = false; - smeter_filter1.running = false; - smeter_filter2.running = false; - smeter_filter3.running = false; - - switch(index) { - case 0: - smeter_filter0.running = true; - smeter_filter = 0; - oplm_pair_id = opLinkStatus.pairIDs0 - break; - case 1: - smeter_filter1.running = true; - smeter_filter = 1; - oplm_pair_id = opLinkStatus.pairIDs1 - break; - case 2: - smeter_filter2.running = true; - smeter_filter = 2; - oplm_pair_id = opLinkStatus.pairIDs2 - break; - case 3: - smeter_filter3.running = true; - smeter_filter = 3; - oplm_pair_id = opLinkStatus.pairIDs3 - break; - } - } - // End Functions // // Start Drawing @@ -783,73 +729,6 @@ Item { } } - SvgElementImage { - id: oplm_button_bg - elementName: "oplm-button-bg" - sceneSize: panels.sceneSize - y: Math.floor(scaledBounds.y * sceneItem.height) - width: smeter_mask.width - - z: oplm_bg.z + 5 - - states: State { - name: "fading" - when: show_panels == true - PropertyChanges { target: oplm_button_bg; x: Math.floor(scaledBounds.x * sceneItem.width) + offset_value; } - } - - transitions: Transition { - SequentialAnimation { - PropertyAnimation { property: "x"; easing.type: anim_type; duration: anim_duration } - } - } - } - - Repeater { - model: 4 - - SvgElementImage { - z: oplm_bg.z + 5 - property variant idButton_oplm: "oplm_button_" + index - property variant idButton_oplm_mousearea: "oplm_button_mousearea" + index - property variant button_color: "button"+index+"_color" - - id: idButton_oplm - - elementName: "oplm-button-" + index - sceneSize: panels.sceneSize - - Rectangle { - anchors.fill: parent - border.color: "red" - border.width: parent.width * 0.04 - radius: border.width*3 - color: "transparent" - opacity: smeter_filter == index ? 0.5 : 0 - } - - MouseArea { - id: idButton_oplm_mousearea; - anchors.fill: parent; - cursorShape: Qt.PointingHandCursor; - visible: display_oplm == true ? 1 : 0 - onClicked: select_oplm(index) - } - - states: State { - name: "fading" - when: show_panels == true - PropertyChanges { target: idButton_oplm; x: Math.floor(scaledBounds.x * sceneItem.width) + offset_value; } - } - - transitions: Transition { - SequentialAnimation { - PropertyAnimation { property: "x"; easing.type: anim_type; duration: anim_duration } - } - } - } - } - SvgElementImage { id: oplm_id_label elementName: "oplm-id-label" @@ -893,7 +772,7 @@ Item { } Text { - text: oplm_pair_id > 0 ? oplm_pair_id.toString(16) : "-- -- -- --" + text: UAV.OplmDeviceID() > 0 ? UAV.OplmDeviceID().toString(16) : "-- -- -- --" anchors.centerIn: parent color: "white" font { From 2d6d0b6974f5409e5f26113894f762a2c217e2d6 Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Mon, 24 Apr 2017 09:34:10 +0200 Subject: [PATCH 211/624] LP-513 gcs: remove unused libs/qtconcurrent --- ground/gcs/src/libs/libs.pro | 1 - .../src/libs/qtconcurrent/QtConcurrentTools | 31 -- ground/gcs/src/libs/qtconcurrent/multitask.h | 199 --------- .../src/libs/qtconcurrent/qtconcurrent.pri | 1 - .../src/libs/qtconcurrent/qtconcurrent.pro | 10 - .../libs/qtconcurrent/qtconcurrent_global.h | 40 -- .../gcs/src/libs/qtconcurrent/runextensions.h | 377 ------------------ ground/gcs/src/libs/utils/filesearch.cpp | 267 ------------- ground/gcs/src/libs/utils/filesearch.h | 60 --- ground/gcs/src/libs/utils/utils.pro | 2 - 10 files changed, 988 deletions(-) delete mode 100644 ground/gcs/src/libs/qtconcurrent/QtConcurrentTools delete mode 100644 ground/gcs/src/libs/qtconcurrent/multitask.h delete mode 100644 ground/gcs/src/libs/qtconcurrent/qtconcurrent.pri delete mode 100644 ground/gcs/src/libs/qtconcurrent/qtconcurrent.pro delete mode 100644 ground/gcs/src/libs/qtconcurrent/qtconcurrent_global.h delete mode 100644 ground/gcs/src/libs/qtconcurrent/runextensions.h delete mode 100644 ground/gcs/src/libs/utils/filesearch.cpp delete mode 100644 ground/gcs/src/libs/utils/filesearch.h diff --git a/ground/gcs/src/libs/libs.pro b/ground/gcs/src/libs/libs.pro index e1b355cf29..975cd60e85 100644 --- a/ground/gcs/src/libs/libs.pro +++ b/ground/gcs/src/libs/libs.pro @@ -4,7 +4,6 @@ CONFIG += ordered SUBDIRS = \ version_info \ qscispinbox\ - qtconcurrent \ aggregation \ extensionsystem \ utils \ diff --git a/ground/gcs/src/libs/qtconcurrent/QtConcurrentTools b/ground/gcs/src/libs/qtconcurrent/QtConcurrentTools deleted file mode 100644 index b8c36c1dd8..0000000000 --- a/ground/gcs/src/libs/qtconcurrent/QtConcurrentTools +++ /dev/null @@ -1,31 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** Commercial Usage -** -** Licensees holding valid Qt Commercial licenses may use this file in -** accordance with the Qt Commercial License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Nokia. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at http://qt.nokia.com/contact. -** -**************************************************************************/ - -#include "qtconcurrent/multitask.h" -#include "qtconcurrent/runextensions.h" diff --git a/ground/gcs/src/libs/qtconcurrent/multitask.h b/ground/gcs/src/libs/qtconcurrent/multitask.h deleted file mode 100644 index bd341b245c..0000000000 --- a/ground/gcs/src/libs/qtconcurrent/multitask.h +++ /dev/null @@ -1,199 +0,0 @@ -/** - ****************************************************************************** - * - * @file multitask.h - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @brief - * @see The GNU Public License (GPL) Version 3 - * @defgroup - * @{ - * - *****************************************************************************/ -/* - * 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 MULTITASK_H -#define MULTITASK_H - -#include "qtconcurrent_global.h" -#include "runextensions.h" - -#include -#include -#include -#include -#include -#include - -#include - -QT_BEGIN_NAMESPACE - -namespace QtConcurrent { -class QTCONCURRENT_EXPORT MultiTaskBase : public QObject, public QRunnable { - Q_OBJECT -protected slots: - virtual void cancelSelf() = 0; - virtual void setFinished() = 0; - virtual void setProgressRange(int min, int max) = 0; - virtual void setProgressValue(int value) = 0; - virtual void setProgressText(QString value) = 0; -}; - -template -class MultiTask : public MultiTaskBase { -public: - MultiTask(void(Class::*fn)(QFutureInterface &), const QList &objects) - : fn(fn), - objects(objects) - { - maxProgress = 100 * objects.size(); - } - - QFuture future() - { - futureInterface.reportStarted(); - return futureInterface.future(); - } - - void run() - { - QThreadPool::globalInstance()->releaseThread(); - - futureInterface.setProgressRange(0, maxProgress); - foreach(Class * object, objects) { - QFutureWatcher *watcher = new QFutureWatcher(); - watchers.insert(object, watcher); - finished.insert(watcher, false); - connect(watcher, SIGNAL(finished()), this, SLOT(setFinished())); - connect(watcher, SIGNAL(progressRangeChanged(int, int)), this, SLOT(setProgressRange(int, int))); - connect(watcher, SIGNAL(progressValueChanged(int)), this, SLOT(setProgressValue(int))); - connect(watcher, SIGNAL(progressTextChanged(QString)), this, SLOT(setProgressText(QString))); - watcher->setFuture(QtConcurrent::run(fn, object)); - } - selfWatcher = new QFutureWatcher(); - connect(selfWatcher, SIGNAL(canceled()), this, SLOT(cancelSelf())); - selfWatcher->setFuture(futureInterface.future()); - loop = new QEventLoop; - loop->exec(); - futureInterface.reportFinished(); - QThreadPool::globalInstance()->reserveThread(); - qDeleteAll(watchers.values()); - delete selfWatcher; - delete loop; - } -protected: - void cancelSelf() - { - foreach(QFutureWatcher *watcher, watchers) - watcher->future().cancel(); - } - - void setFinished() - { - updateProgress(); - QFutureWatcher *watcher = static_cast *>(sender()); - if (finished.contains(watcher)) { - finished[watcher] = true; - } - bool allFinished = true; - const QList finishedValues = finished.values(); - foreach(bool isFinished, finishedValues) { - if (!isFinished) { - allFinished = false; - break; - } - } - if (allFinished) { - loop->quit(); - } - } - - void setProgressRange(int min, int max) - { - Q_UNUSED(min) - Q_UNUSED(max) - updateProgress(); - } - - void setProgressValue(int value) - { - Q_UNUSED(value) - updateProgress(); - } - - void setProgressText(QString value) - { - Q_UNUSED(value) - updateProgressText(); - } -private: - void updateProgress() - { - int progressSum = 0; - const QList *> watchersValues = watchers.values(); - - foreach(QFutureWatcher *watcher, watchersValues) { - if (watcher->progressMinimum() == watcher->progressMaximum()) { - if (watcher->future().isFinished() && !watcher->future().isCanceled()) { - progressSum += 100; - } - } else { - progressSum += 100 * (watcher->progressValue() - watcher->progressMinimum()) / (watcher->progressMaximum() - watcher->progressMinimum()); - } - } - futureInterface.setProgressValue(progressSum); - } - - void updateProgressText() - { - QString text; - const QList *> watchersValues = watchers.values(); - - foreach(QFutureWatcher *watcher, watchersValues) { - if (!watcher->progressText().isEmpty()) { - text += watcher->progressText() + "\n"; - } - } - text = text.trimmed(); - futureInterface.setProgressValueAndText(futureInterface.progressValue(), text); - } - - QFutureInterface futureInterface; - void (Class::*fn)(QFutureInterface &); - QList objects; - - QFutureWatcher *selfWatcher; - QMap *> watchers; - QMap *, bool> finished; - QEventLoop *loop; - int maxProgress; -}; - -template -QFuture run(void (Class::*fn)(QFutureInterface &), const QList &objects, int priority = 0) -{ - MultiTask *task = new MultiTask(fn, objects); - QFuture future = task->future(); - QThreadPool::globalInstance()->start(task, priority); - return future; -} -} // namespace QtConcurrent - -QT_END_NAMESPACE - -#endif // MULTITASK_H diff --git a/ground/gcs/src/libs/qtconcurrent/qtconcurrent.pri b/ground/gcs/src/libs/qtconcurrent/qtconcurrent.pri deleted file mode 100644 index 141de8ee8e..0000000000 --- a/ground/gcs/src/libs/qtconcurrent/qtconcurrent.pri +++ /dev/null @@ -1 +0,0 @@ -LIBS *= -l$$qtLibraryName(QtConcurrent) diff --git a/ground/gcs/src/libs/qtconcurrent/qtconcurrent.pro b/ground/gcs/src/libs/qtconcurrent/qtconcurrent.pro deleted file mode 100644 index e5d1cda2be..0000000000 --- a/ground/gcs/src/libs/qtconcurrent/qtconcurrent.pro +++ /dev/null @@ -1,10 +0,0 @@ -TEMPLATE = lib -TARGET = QtConcurrent -DEFINES += BUILD_QTCONCURRENT - -include(../../library.pri) - -HEADERS += \ - qtconcurrent_global.h \ - multitask.h \ - runextensions.h diff --git a/ground/gcs/src/libs/qtconcurrent/qtconcurrent_global.h b/ground/gcs/src/libs/qtconcurrent/qtconcurrent_global.h deleted file mode 100644 index f1c048b57a..0000000000 --- a/ground/gcs/src/libs/qtconcurrent/qtconcurrent_global.h +++ /dev/null @@ -1,40 +0,0 @@ -/** - ****************************************************************************** - * - * @file qtconcurrent_global.h - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @brief - * @see The GNU Public License (GPL) Version 3 - * @defgroup - * @{ - * - *****************************************************************************/ -/* - * 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 QTCONCURRENT_GLOBAL_H -#define QTCONCURRENT_GLOBAL_H - -#include - -#if defined(BUILD_QTCONCURRENT) -# define QTCONCURRENT_EXPORT Q_DECL_EXPORT -#else -# define QTCONCURRENT_EXPORT Q_DECL_IMPORT -#endif - -#endif // QTCONCURRENT_GLOBAL_H diff --git a/ground/gcs/src/libs/qtconcurrent/runextensions.h b/ground/gcs/src/libs/qtconcurrent/runextensions.h deleted file mode 100644 index 01c8cd5330..0000000000 --- a/ground/gcs/src/libs/qtconcurrent/runextensions.h +++ /dev/null @@ -1,377 +0,0 @@ -/** - ****************************************************************************** - * - * @file runextensions.h - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @brief - * @see The GNU Public License (GPL) Version 3 - * @defgroup - * @{ - * - *****************************************************************************/ -/* - * 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 QTCONCURRENT_RUNEX_H -#define QTCONCURRENT_RUNEX_H - -#include -#include -#include - -QT_BEGIN_NAMESPACE - -namespace QtConcurrent { -template -class StoredInterfaceFunctionCall0 : public QRunnable { -public: - StoredInterfaceFunctionCall0(void(fn)(QFutureInterface &)) - : fn(fn) {} - - QFuture start() - { - futureInterface.reportStarted(); - QFuture future = futureInterface.future(); - QThreadPool::globalInstance()->start(this); - return future; - } - - void run() - { - fn(futureInterface); - futureInterface.reportFinished(); - } -private: - QFutureInterface futureInterface; - FunctionPointer fn; -}; -template -class StoredInterfaceMemberFunctionCall0 : public QRunnable { -public: - StoredInterfaceMemberFunctionCall0(void(Class::*fn)(QFutureInterface &), Class *object) - : fn(fn), object(object) {} - - QFuture start() - { - futureInterface.reportStarted(); - QFuture future = futureInterface.future(); - QThreadPool::globalInstance()->start(this); - return future; - } - - void run() - { - (object->*fn)(futureInterface); - futureInterface.reportFinished(); - } -private: - QFutureInterface futureInterface; - FunctionPointer fn; - Class *object; -}; - -template -class StoredInterfaceFunctionCall1 : public QRunnable { -public: - StoredInterfaceFunctionCall1(void(fn)(QFutureInterface &, Arg1), Arg1 arg1) - : fn(fn), arg1(arg1) {} - - QFuture start() - { - futureInterface.reportStarted(); - QFuture future = futureInterface.future(); - QThreadPool::globalInstance()->start(this); - return future; - } - - void run() - { - fn(futureInterface, arg1); - futureInterface.reportFinished(); - } -private: - QFutureInterface futureInterface; - FunctionPointer fn; - Arg1 arg1; -}; -template -class StoredInterfaceMemberFunctionCall1 : public QRunnable { -public: - StoredInterfaceMemberFunctionCall1(void(Class::*fn)(QFutureInterface &, Arg1), Class *object, Arg1 arg1) - : fn(fn), object(object), arg1(arg1) {} - - QFuture start() - { - futureInterface.reportStarted(); - QFuture future = futureInterface.future(); - QThreadPool::globalInstance()->start(this); - return future; - } - - void run() - { - (object->*fn)(futureInterface, arg1); - futureInterface.reportFinished(); - } -private: - QFutureInterface futureInterface; - FunctionPointer fn; - Class *object; - Arg1 arg1; -}; - -template -class StoredInterfaceFunctionCall2 : public QRunnable { -public: - StoredInterfaceFunctionCall2(void(fn)(QFutureInterface &, Arg1, Arg2), Arg1 arg1, Arg2 arg2) - : fn(fn), arg1(arg1), arg2(arg2) {} - - QFuture start() - { - futureInterface.reportStarted(); - QFuture future = futureInterface.future(); - QThreadPool::globalInstance()->start(this); - return future; - } - - void run() - { - fn(futureInterface, arg1, arg2); - futureInterface.reportFinished(); - } -private: - QFutureInterface futureInterface; - FunctionPointer fn; - Arg1 arg1; Arg2 arg2; -}; -template -class StoredInterfaceMemberFunctionCall2 : public QRunnable { -public: - StoredInterfaceMemberFunctionCall2(void(Class::*fn)(QFutureInterface &, Arg1, Arg2), Class *object, Arg1 arg1, Arg2 arg2) - : fn(fn), object(object), arg1(arg1), arg2(arg2) {} - - QFuture start() - { - futureInterface.reportStarted(); - QFuture future = futureInterface.future(); - QThreadPool::globalInstance()->start(this); - return future; - } - - void run() - { - (object->*fn)(futureInterface, arg1, arg2); - futureInterface.reportFinished(); - } -private: - QFutureInterface futureInterface; - FunctionPointer fn; - Class *object; - Arg1 arg1; Arg2 arg2; -}; - -template -class StoredInterfaceFunctionCall3 : public QRunnable { -public: - StoredInterfaceFunctionCall3(void(fn)(QFutureInterface &, Arg1, Arg2, Arg3), Arg1 arg1, Arg2 arg2, Arg3 arg3) - : fn(fn), arg1(arg1), arg2(arg2), arg3(arg3) {} - - QFuture start() - { - futureInterface.reportStarted(); - QFuture future = futureInterface.future(); - QThreadPool::globalInstance()->start(this); - return future; - } - - void run() - { - fn(futureInterface, arg1, arg2, arg3); - futureInterface.reportFinished(); - } -private: - QFutureInterface futureInterface; - FunctionPointer fn; - Arg1 arg1; Arg2 arg2; Arg3 arg3; -}; -template -class StoredInterfaceMemberFunctionCall3 : public QRunnable { -public: - StoredInterfaceMemberFunctionCall3(void(Class::*fn)(QFutureInterface &, Arg1, Arg2, Arg3), Class *object, Arg1 arg1, Arg2 arg2, Arg3 arg3) - : fn(fn), object(object), arg1(arg1), arg2(arg2), arg3(arg3) {} - - QFuture start() - { - futureInterface.reportStarted(); - QFuture future = futureInterface.future(); - QThreadPool::globalInstance()->start(this); - return future; - } - - void run() - { - (object->*fn)(futureInterface, arg1, arg2, arg3); - futureInterface.reportFinished(); - } -private: - QFutureInterface futureInterface; - FunctionPointer fn; - Class *object; - Arg1 arg1; Arg2 arg2; Arg3 arg3; -}; - -template -class StoredInterfaceFunctionCall4 : public QRunnable { -public: - StoredInterfaceFunctionCall4(void(fn)(QFutureInterface &, Arg1, Arg2, Arg3, Arg4), Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4) - : fn(fn), arg1(arg1), arg2(arg2), arg3(arg3), arg4(arg4) {} - - QFuture start() - { - futureInterface.reportStarted(); - QFuture future = futureInterface.future(); - QThreadPool::globalInstance()->start(this); - return future; - } - - void run() - { - fn(futureInterface, arg1, arg2, arg3, arg4); - futureInterface.reportFinished(); - } -private: - QFutureInterface futureInterface; - FunctionPointer fn; - Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4; -}; -template -class StoredInterfaceMemberFunctionCall4 : public QRunnable { -public: - StoredInterfaceMemberFunctionCall4(void(Class::*fn)(QFutureInterface &, Arg1, Arg2, Arg3, Arg4), Class *object, Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4) - : fn(fn), object(object), arg1(arg1), arg2(arg2), arg3(arg3), arg4(arg4) {} - - QFuture start() - { - futureInterface.reportStarted(); - QFuture future = futureInterface.future(); - QThreadPool::globalInstance()->start(this); - return future; - } - - void run() - { - (object->*fn)(futureInterface, arg1, arg2, arg3, arg4); - futureInterface.reportFinished(); - } -private: - QFutureInterface futureInterface; - FunctionPointer fn; - Class *object; - Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4; -}; - -template -class StoredInterfaceFunctionCall5 : public QRunnable { -public: - StoredInterfaceFunctionCall5(void(fn)(QFutureInterface &, Arg1, Arg2, Arg3, Arg4, Arg5), Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5) - : fn(fn), arg1(arg1), arg2(arg2), arg3(arg3), arg4(arg4), arg5(arg5) {} - - QFuture start() - { - futureInterface.reportStarted(); - QFuture future = futureInterface.future(); - QThreadPool::globalInstance()->start(this); - return future; - } - - void run() - { - fn(futureInterface, arg1, arg2, arg3, arg4, arg5); - futureInterface.reportFinished(); - } -private: - QFutureInterface futureInterface; - FunctionPointer fn; - Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4; Arg5 arg5; -}; -template -class StoredInterfaceMemberFunctionCall5 : public QRunnable { -public: - StoredInterfaceMemberFunctionCall5(void(Class::*fn)(QFutureInterface &, Arg1, Arg2, Arg3, Arg4, Arg5), Class *object, Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5) - : fn(fn), object(object), arg1(arg1), arg2(arg2), arg3(arg3), arg4(arg4), arg5(arg5) {} - - QFuture start() - { - futureInterface.reportStarted(); - QFuture future = futureInterface.future(); - QThreadPool::globalInstance()->start(this); - return future; - } - - void run() - { - (object->*fn)(futureInterface, arg1, arg2, arg3, arg4, arg5); - futureInterface.reportFinished(); - } -private: - QFutureInterface futureInterface; - FunctionPointer fn; - Class *object; - Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4; Arg5 arg5; -}; - -template -QFuture run(void (*functionPointer)(QFutureInterface &)) -{ - return (new StoredInterfaceFunctionCall0 &)>(functionPointer))->start(); -} -template -QFuture run(void (*functionPointer)(QFutureInterface &, Arg1), Arg1 arg1) -{ - return (new StoredInterfaceFunctionCall1 &, Arg1), Arg1>(functionPointer, arg1))->start(); -} -template -QFuture run(void (*functionPointer)(QFutureInterface &, Arg1, Arg2), Arg1 arg1, Arg2 arg2) -{ - return (new StoredInterfaceFunctionCall2 &, Arg1, Arg2), Arg1, Arg2>(functionPointer, arg1, arg2))->start(); -} -template -QFuture run(void (*functionPointer)(QFutureInterface &, Arg1, Arg2, Arg3), Arg1 arg1, Arg2 arg2, Arg3 arg3) -{ - return (new StoredInterfaceFunctionCall3 &, Arg1, Arg2, Arg3), Arg1, Arg2, Arg3>(functionPointer, arg1, arg2, arg3))->start(); -} -template -QFuture run(void (*functionPointer)(QFutureInterface &, Arg1, Arg2, Arg3, Arg4), Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4) -{ - return (new StoredInterfaceFunctionCall4 &, Arg1, Arg2, Arg3, Arg4), Arg1, Arg2, Arg3, Arg4>(functionPointer, arg1, arg2, arg3, arg4))->start(); -} -template -QFuture run(void (*functionPointer)(QFutureInterface &, Arg1, Arg2, Arg3, Arg4, Arg5), Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5) -{ - return (new StoredInterfaceFunctionCall5 &, Arg1, Arg2, Arg3, Arg4, Arg5), Arg1, Arg2, Arg3, Arg4, Arg5>(functionPointer, arg1, arg2, arg3, arg4, arg5))->start(); -} - -template -QFuture run(void (Class::*fn)(QFutureInterface &), Class *object) -{ - return (new StoredInterfaceMemberFunctionCall0 &), Class>(fn, object))->start(); -} -} // namespace QtConcurrent - -QT_END_NAMESPACE - -#endif // QTCONCURRENT_RUNEX_H diff --git a/ground/gcs/src/libs/utils/filesearch.cpp b/ground/gcs/src/libs/utils/filesearch.cpp deleted file mode 100644 index 0c32491047..0000000000 --- a/ground/gcs/src/libs/utils/filesearch.cpp +++ /dev/null @@ -1,267 +0,0 @@ -/** - ****************************************************************************** - * - * @file filesearch.cpp - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @brief - * @see The GNU Public License (GPL) Version 3 - * @defgroup - * @{ - * - *****************************************************************************/ -/* - * 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 "filesearch.h" -#include - -#include -#include -#include -#include -#include -#include -#include - -#include - -using namespace Utils; - -static inline QString msgCanceled(const QString &searchTerm, int numMatches, int numFilesSearched) -{ - return QCoreApplication::translate("Utils::FileSearch", - "%1: canceled. %n occurrences found in %2 files.", - NULL, numMatches). - arg(searchTerm).arg(numFilesSearched); -} - -static inline QString msgFound(const QString &searchTerm, int numMatches, int numFilesSearched) -{ - return QCoreApplication::translate("Utils::FileSearch", - "%1: %n occurrences found in %2 files.", - NULL, numMatches). - arg(searchTerm).arg(numFilesSearched); -} - -static inline QString msgFound(const QString &searchTerm, int numMatches, int numFilesSearched, int filesSize) -{ - return QCoreApplication::translate("Utils::FileSearch", - "%1: %n occurrences found in %2 of %3 files.", - NULL, numMatches). - arg(searchTerm).arg(numFilesSearched).arg(filesSize); -} - -namespace { -void runFileSearch(QFutureInterface &future, - QString searchTerm, - QStringList files, - QTextDocument::FindFlags flags, - QMap fileToContentsMap) -{ - future.setProgressRange(0, files.size()); - int numFilesSearched = 0; - int numMatches = 0; - - bool caseInsensitive = !(flags & QTextDocument::FindCaseSensitively); - bool wholeWord = (flags & QTextDocument::FindWholeWords); - - QByteArray sa = searchTerm.toUtf8(); - int scMaxIndex = sa.length() - 1; - const char *sc = sa.constData(); - - QByteArray sal = searchTerm.toLower().toUtf8(); - const char *scl = sal.constData(); - - QByteArray sau = searchTerm.toUpper().toUtf8(); - const char *scu = sau.constData(); - - int chunkSize = qMax(100000, sa.length()); - - QFile file; - QBuffer buffer; - foreach(QString s, files) { - if (future.isPaused()) { - future.waitForResume(); - } - if (future.isCanceled()) { - future.setProgressValueAndText(numFilesSearched, msgCanceled(searchTerm, numMatches, numFilesSearched)); - break; - } - QIODevice *device; - if (fileToContentsMap.contains(s)) { - buffer.setData(fileToContentsMap.value(s).toLocal8Bit()); - device = &buffer; - } else { - file.setFileName(s); - device = &file; - } - if (!device->open(QIODevice::ReadOnly)) { - continue; - } - int lineNr = 1; - const char *startOfLastLine = NULL; - - bool firstChunk = true; - while (!device->atEnd()) { - if (!firstChunk) { - device->seek(device->pos() - sa.length() + 1); - } - - const QByteArray chunk = device->read(chunkSize); - const char *chunkPtr = chunk.constData(); - startOfLastLine = chunkPtr; - for (const char *regionPtr = chunkPtr; regionPtr < chunkPtr + chunk.length() - scMaxIndex; ++regionPtr) { - const char *regionEnd = regionPtr + scMaxIndex; - - if (*regionPtr == '\n') { - startOfLastLine = regionPtr + 1; - ++lineNr; - } else if ( - // case sensitive - (!caseInsensitive && *regionPtr == sc[0] && *regionEnd == sc[scMaxIndex]) - || - // case insensitive - (caseInsensitive && (*regionPtr == scl[0] || *regionPtr == scu[0]) - && (*regionEnd == scl[scMaxIndex] || *regionEnd == scu[scMaxIndex])) - ) { - const char *afterRegion = regionEnd + 1; - const char *beforeRegion = regionPtr - 1; - bool equal = true; - if (wholeWord && - (isalnum(*beforeRegion) - || (*beforeRegion == '_') - || isalnum(*afterRegion) - || (*afterRegion == '_'))) { - equal = false; - } - - int regionIndex = 1; - for (const char *regionCursor = regionPtr + 1; regionCursor < regionEnd; ++regionCursor, ++regionIndex) { - if ( // case sensitive - (!caseInsensitive && equal && *regionCursor != sc[regionIndex]) - || - // case insensitive - (caseInsensitive && equal && *regionCursor != sc[regionIndex] && *regionCursor != scl[regionIndex] && *regionCursor != scu[regionIndex]) - ) { - equal = false; - } - } - if (equal) { - int textLength = chunk.length() - (startOfLastLine - chunkPtr); - if (textLength > 0) { - QByteArray res; - res.reserve(256); - int i = 0; - int n = 0; - while (startOfLastLine[i] != '\n' && startOfLastLine[i] != '\r' && i < textLength && n++ < 256) { - res.append(startOfLastLine[i++]); - } - future.reportResult(FileSearchResult(s, lineNr, QString(res), - regionPtr - startOfLastLine, sa.length())); - ++numMatches; - } - } - } - } - firstChunk = false; - } - ++numFilesSearched; - future.setProgressValueAndText(numFilesSearched, msgFound(searchTerm, numMatches, numFilesSearched, files.size())); - device->close(); - } - if (!future.isCanceled()) { - future.setProgressValueAndText(numFilesSearched, msgFound(searchTerm, numMatches, numFilesSearched)); - } -} - -void runFileSearchRegExp(QFutureInterface &future, - QString searchTerm, - QStringList files, - QTextDocument::FindFlags flags, - QMap fileToContentsMap) -{ - future.setProgressRange(0, files.size()); - int numFilesSearched = 0; - int numMatches = 0; - if (flags & QTextDocument::FindWholeWords) { - searchTerm = QString::fromLatin1("\\b%1\\b").arg(searchTerm); - } - const Qt::CaseSensitivity caseSensitivity = (flags & QTextDocument::FindCaseSensitively) ? Qt::CaseSensitive : Qt::CaseInsensitive; - const QRegExp expression(searchTerm, caseSensitivity); - - QFile file; - QString str; - QTextStream stream; - foreach(const QString &s, files) { - if (future.isPaused()) { - future.waitForResume(); - } - if (future.isCanceled()) { - future.setProgressValueAndText(numFilesSearched, msgCanceled(searchTerm, numMatches, numFilesSearched)); - break; - } - - bool needsToCloseFile = false; - if (fileToContentsMap.contains(s)) { - str = fileToContentsMap.value(s); - stream.setString(&str); - } else { - file.setFileName(s); - if (!file.open(QIODevice::ReadOnly)) { - continue; - } - needsToCloseFile = true; - stream.setDevice(&file); - } - int lineNr = 1; - QString line; - while (!stream.atEnd()) { - line = stream.readLine(); - int pos = 0; - while ((pos = expression.indexIn(line, pos)) != -1) { - future.reportResult(FileSearchResult(s, lineNr, line, - pos, expression.matchedLength())); - pos += expression.matchedLength(); - } - ++lineNr; - } - ++numFilesSearched; - future.setProgressValueAndText(numFilesSearched, msgFound(searchTerm, numMatches, numFilesSearched, files.size())); - if (needsToCloseFile) { - file.close(); - } - } - if (!future.isCanceled()) { - future.setProgressValueAndText(numFilesSearched, msgFound(searchTerm, numMatches, numFilesSearched)); - } -} -} // namespace - - -QFuture Utils::findInFiles(const QString &searchTerm, const QStringList &files, - QTextDocument::FindFlags flags, QMap fileToContentsMap) -{ - return QtConcurrent::run > - (runFileSearch, searchTerm, files, flags, fileToContentsMap); -} - -QFuture Utils::findInFilesRegExp(const QString &searchTerm, const QStringList &files, - QTextDocument::FindFlags flags, QMap fileToContentsMap) -{ - return QtConcurrent::run > - (runFileSearchRegExp, searchTerm, files, flags, fileToContentsMap); -} diff --git a/ground/gcs/src/libs/utils/filesearch.h b/ground/gcs/src/libs/utils/filesearch.h deleted file mode 100644 index 223af426ad..0000000000 --- a/ground/gcs/src/libs/utils/filesearch.h +++ /dev/null @@ -1,60 +0,0 @@ -/** - ****************************************************************************** - * - * @file filesearch.h - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @brief - * @see The GNU Public License (GPL) Version 3 - * @defgroup - * @{ - * - *****************************************************************************/ -/* - * 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 FILESEARCH_H -#define FILESEARCH_H - -#include "utils_global.h" - -#include -#include -#include -#include - -namespace Utils { -class QTCREATOR_UTILS_EXPORT FileSearchResult { -public: - FileSearchResult() {} - FileSearchResult(QString fileName, int lineNumber, QString matchingLine, int matchStart, int matchLength) - : fileName(fileName), lineNumber(lineNumber), matchingLine(matchingLine), matchStart(matchStart), matchLength(matchLength) - {} - QString fileName; - int lineNumber; - QString matchingLine; - int matchStart; - int matchLength; -}; - -QTCREATOR_UTILS_EXPORT QFuture findInFiles(const QString &searchTerm, const QStringList &files, - QTextDocument::FindFlags flags, QMap fileToContentsMap = QMap()); - -QTCREATOR_UTILS_EXPORT QFuture findInFilesRegExp(const QString &searchTerm, const QStringList &files, - QTextDocument::FindFlags flags, QMap fileToContentsMap = QMap()); -} // namespace Utils - -#endif // FILESEARCH_H diff --git a/ground/gcs/src/libs/utils/utils.pro b/ground/gcs/src/libs/utils/utils.pro index 3654582e6d..60aa5d042e 100644 --- a/ground/gcs/src/libs/utils/utils.pro +++ b/ground/gcs/src/libs/utils/utils.pro @@ -14,7 +14,6 @@ DEFINES += PLUGIN_REL_PATH=$$shell_quote(\"$$relative_path($$GCS_PLUGIN_PATH, $$ SOURCES += \ reloadpromptutils.cpp \ stringutils.cpp \ - filesearch.cpp \ pathchooser.cpp \ pathlisteditor.cpp \ filewizardpage.cpp \ @@ -73,7 +72,6 @@ HEADERS += \ utils_global.h \ reloadpromptutils.h \ stringutils.h \ - filesearch.h \ listutils.h \ pathchooser.h \ pathlisteditor.h \ From dd49ef0166cc5fd48e2b7f901a4e32c027035eb5 Mon Sep 17 00:00:00 2001 From: Vladimir Zidar Date: Wed, 19 Apr 2017 15:55:36 +0200 Subject: [PATCH 212/624] LP-480 work in progress: revo, nano & sparky2 targets ok. --- .../OpenPilotOSX.xcodeproj/project.pbxproj | 628 ++++---- flight/make/apps-defs.mk | 2 + flight/modules/Osd/osdoutput/osdoutput.c | 5 + flight/pios/common/pios_board_io.c | 798 ++++++++++ flight/pios/common/pios_com.c | 37 +- flight/pios/{stm32f4xx => common}/pios_dsm.c | 68 +- flight/pios/common/pios_exbus.c | 12 +- flight/pios/common/pios_hott.c | 10 + flight/pios/common/pios_ibus.c | 12 +- flight/pios/common/pios_sbus.c | 19 +- flight/pios/common/pios_srxl.c | 12 +- flight/pios/common/pios_usb_desc_hid_cdc.c | 16 + flight/pios/common/pios_usb_desc_hid_only.c | 6 + flight/pios/inc/pios_board_hw.h | 56 + flight/pios/inc/pios_board_io.h | 221 +++ flight/pios/inc/pios_com.h | 36 +- flight/pios/inc/pios_dsm_priv.h | 6 - flight/pios/inc/pios_sbus_priv.h | 11 +- flight/pios/inc/pios_stm32.h | 8 +- flight/pios/inc/pios_usart.h | 19 + flight/pios/inc/pios_usart_priv.h | 8 +- flight/pios/inc/pios_usb_desc_hid_cdc_priv.h | 5 + flight/pios/inc/pios_usb_desc_hid_only_priv.h | 4 + flight/pios/stm32f10x/pios_dsm.c | 438 ------ flight/pios/stm32f4xx/pios_usart.c | 69 +- .../firmware/inc/pios_config.h | 1 + .../gpsplatinum/firmware/inc/pios_config.h | 1 + .../targets/boards/revolution/board_hw_defs.c | 1384 +++++------------ .../boards/revolution/bootloader/pios_board.c | 10 +- .../revolution/firmware/inc/pios_config.h | 1 + .../boards/revolution/firmware/pios_board.c | 1080 ++----------- .../targets/boards/revonano/board_hw_defs.c | 707 ++------- .../boards/revonano/bootloader/pios_board.c | 9 +- .../boards/revonano/firmware/pios_board.c | 754 +-------- .../revoproto/firmware/inc/pios_config.h | 1 + flight/targets/boards/sparky2/board_hw_defs.c | 854 ++-------- .../boards/sparky2/bootloader/pios_board.c | 8 +- .../boards/sparky2/firmware/pios_board.c | 1090 ++----------- shared/uavobjectdefinition/hwsettings.xml | 1 + 39 files changed, 2733 insertions(+), 5674 deletions(-) create mode 100644 flight/pios/common/pios_board_io.c rename flight/pios/{stm32f4xx => common}/pios_dsm.c (90%) create mode 100644 flight/pios/inc/pios_board_hw.h create mode 100644 flight/pios/inc/pios_board_io.h delete mode 100644 flight/pios/stm32f10x/pios_dsm.c diff --git a/flight/Project/OpenPilotOSX/OpenPilotOSX.xcodeproj/project.pbxproj b/flight/Project/OpenPilotOSX/OpenPilotOSX.xcodeproj/project.pbxproj index 14b7c9ae29..da24ebb793 100644 --- a/flight/Project/OpenPilotOSX/OpenPilotOSX.xcodeproj/project.pbxproj +++ b/flight/Project/OpenPilotOSX/OpenPilotOSX.xcodeproj/project.pbxproj @@ -1,298 +1,330 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 45; - objects = { - -/* Begin PBXFileReference section */ - 4354B66314FED9FE004BA3B4 /* flight */ = {isa = PBXFileReference; lastKnownFileType = folder; name = flight; path = ../..; sourceTree = SOURCE_ROOT; }; - 65173C9F12EBFD1700D6A7CB /* Makefile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.make; name = Makefile; path = ../../../Makefile; sourceTree = SOURCE_ROOT; }; - 65904F1814632C1700FD9482 /* firmware-defs.mk */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "firmware-defs.mk"; sourceTree = ""; }; - 65904F2214632C1700FD9482 /* board-info.mk */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "board-info.mk"; sourceTree = ""; }; - 65904F2314632C1700FD9482 /* board-info.mk */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "board-info.mk"; sourceTree = ""; }; - 65904F2414632C1700FD9482 /* board-info.mk */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "board-info.mk"; sourceTree = ""; }; - 65904F2514632C1700FD9482 /* board-info.mk */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "board-info.mk"; sourceTree = ""; }; - 65904F2614632C1700FD9482 /* board-info.mk */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "board-info.mk"; sourceTree = ""; }; - 65904F2714632C1700FD9482 /* board-info.mk */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "board-info.mk"; sourceTree = ""; }; - 65904F2814632C1700FD9482 /* version-info.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = "version-info.py"; sourceTree = ""; }; - 65904F2914632C1700FD9482 /* firmware_info.c.template */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = firmware_info.c.template; sourceTree = ""; }; - 65904F2A14632C1700FD9482 /* gcs_version_info.h.template */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gcs_version_info.h.template; sourceTree = ""; }; - 65904F2D14632C1700FD9482 /* README.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README.txt; sourceTree = ""; }; - 65904F2E14632C1700FD9482 /* shell_script.reg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = shell_script.reg; sourceTree = ""; }; - 65904F2F14632C1700FD9482 /* install */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = install; sourceTree = ""; }; - 65904F3014632C1700FD9482 /* make */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = make; sourceTree = ""; }; - 65904F3114632C1700FD9482 /* make.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = make.sh; sourceTree = ""; }; - 65904F3214632C1700FD9482 /* sh.cmd */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = sh.cmd; sourceTree = ""; }; - 65904F34146362F300FD9482 /* board-info.mk */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "board-info.mk"; sourceTree = ""; }; - 65E466BC14E244020075459C /* uavobjectdefinition */ = {isa = PBXFileReference; lastKnownFileType = folder; path = uavobjectdefinition; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXGroup section */ - 08FB7794FE84155DC02AAC07 /* OpenPilotOSX */ = { - isa = PBXGroup; - children = ( - 4354B66314FED9FE004BA3B4 /* flight */, - 65904F1614632C1700FD9482 /* make */, - 65C35E4E12EFB2F3004811C2 /* shared */, - 65173C9F12EBFD1700D6A7CB /* Makefile */, - ); - name = OpenPilotOSX; - sourceTree = ""; - }; - 65904F1614632C1700FD9482 /* make */ = { - isa = PBXGroup; - children = ( - 65904F1714632C1700FD9482 /* boards */, - 65904F1814632C1700FD9482 /* firmware-defs.mk */, - 65904F1914632C1700FD9482 /* scripts */, - 65904F1A14632C1700FD9482 /* templates */, - 65904F1B14632C1700FD9482 /* winx86 */, - ); - name = make; - path = OpenPilotOSX.xcodeproj/../../../../make; - sourceTree = ""; - }; - 65904F1714632C1700FD9482 /* boards */ = { - isa = PBXGroup; - children = ( - 65904F33146362F300FD9482 /* revolution */, - 65904F1C14632C1700FD9482 /* ahrs */, - 65904F1D14632C1700FD9482 /* coptercontrol */, - 65904F1E14632C1700FD9482 /* esc */, - 65904F1F14632C1700FD9482 /* ins */, - 65904F2014632C1700FD9482 /* openpilot */, - 65904F2114632C1700FD9482 /* oplink */, - ); - path = boards; - sourceTree = ""; - }; - 65904F1914632C1700FD9482 /* scripts */ = { - isa = PBXGroup; - children = ( - 65904F2814632C1700FD9482 /* version-info.py */, - ); - path = scripts; - sourceTree = ""; - }; - 65904F1A14632C1700FD9482 /* templates */ = { - isa = PBXGroup; - children = ( - 65904F2914632C1700FD9482 /* firmware_info.c.template */, - 65904F2A14632C1700FD9482 /* gcs_version_info.h.template */, - ); - path = templates; - sourceTree = ""; - }; - 65904F1B14632C1700FD9482 /* winx86 */ = { - isa = PBXGroup; - children = ( - 65904F2B14632C1700FD9482 /* bin */, - 65904F2C14632C1700FD9482 /* cmd */, - 65904F2D14632C1700FD9482 /* README.txt */, - 65904F2E14632C1700FD9482 /* shell_script.reg */, - ); - path = winx86; - sourceTree = ""; - }; - 65904F1C14632C1700FD9482 /* ahrs */ = { - isa = PBXGroup; - children = ( - 65904F2214632C1700FD9482 /* board-info.mk */, - ); - path = ahrs; - sourceTree = ""; - }; - 65904F1D14632C1700FD9482 /* coptercontrol */ = { - isa = PBXGroup; - children = ( - 65904F2314632C1700FD9482 /* board-info.mk */, - ); - path = coptercontrol; - sourceTree = ""; - }; - 65904F1E14632C1700FD9482 /* esc */ = { - isa = PBXGroup; - children = ( - 65904F2414632C1700FD9482 /* board-info.mk */, - ); - path = esc; - sourceTree = ""; - }; - 65904F1F14632C1700FD9482 /* ins */ = { - isa = PBXGroup; - children = ( - 65904F2514632C1700FD9482 /* board-info.mk */, - ); - path = ins; - sourceTree = ""; - }; - 65904F2014632C1700FD9482 /* openpilot */ = { - isa = PBXGroup; - children = ( - 65904F2614632C1700FD9482 /* board-info.mk */, - ); - path = openpilot; - sourceTree = ""; - }; - 65904F2114632C1700FD9482 /* oplink */ = { - isa = PBXGroup; - children = ( - 65904F2714632C1700FD9482 /* board-info.mk */, - ); - path = oplink; - sourceTree = ""; - }; - 65904F2B14632C1700FD9482 /* bin */ = { - isa = PBXGroup; - children = ( - 65904F2F14632C1700FD9482 /* install */, - 65904F3014632C1700FD9482 /* make */, - ); - path = bin; - sourceTree = ""; - }; - 65904F2C14632C1700FD9482 /* cmd */ = { - isa = PBXGroup; - children = ( - 65904F3114632C1700FD9482 /* make.sh */, - 65904F3214632C1700FD9482 /* sh.cmd */, - ); - path = cmd; - sourceTree = ""; - }; - 65904F33146362F300FD9482 /* revolution */ = { - isa = PBXGroup; - children = ( - 65904F34146362F300FD9482 /* board-info.mk */, - ); - path = revolution; - sourceTree = ""; - }; - 65C35E4E12EFB2F3004811C2 /* shared */ = { - isa = PBXGroup; - children = ( - 65E466BC14E244020075459C /* uavobjectdefinition */, - ); - name = shared; - path = ../../../shared; - sourceTree = SOURCE_ROOT; - }; -/* End PBXGroup section */ - -/* Begin PBXLegacyTarget section */ - 6581071511DE809D0049FB12 /* OpenPilotOSX */ = { - isa = PBXLegacyTarget; - buildArgumentsString = "$(ACTION) -f Makefile.posix"; - buildConfigurationList = 6581071A11DE80A30049FB12 /* Build configuration list for PBXLegacyTarget "OpenPilotOSX" */; - buildPhases = ( - ); - buildToolPath = /usr/bin/make; - buildWorkingDirectory = ../../OpenPilot; - dependencies = ( - ); - name = OpenPilotOSX; - passBuildSettingsInEnvironment = 1; - productName = OpenPilotOSX; - }; -/* End PBXLegacyTarget section */ - -/* Begin PBXProject section */ - 08FB7793FE84155DC02AAC07 /* Project object */ = { - isa = PBXProject; - attributes = { - ORGANIZATIONNAME = OpenPilot; - }; - buildConfigurationList = 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "OpenPilotOSX" */; - compatibilityVersion = "Xcode 3.1"; - developmentRegion = English; - hasScannedForEncodings = 1; - knownRegions = ( - English, - Japanese, - French, - German, - ); - mainGroup = 08FB7794FE84155DC02AAC07 /* OpenPilotOSX */; - projectDirPath = ""; - projectRoot = ../../..; - targets = ( - 6581071511DE809D0049FB12 /* OpenPilotOSX */, - ); - }; -/* End PBXProject section */ - -/* Begin XCBuildConfiguration section */ - 1DEB928A08733DD80010E9CD /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - ONLY_ACTIVE_ARCH = YES; - PREBINDING = NO; - SDKROOT = macosx10.6; - }; - name = Debug; - }; - 1DEB928B08733DD80010E9CD /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - PREBINDING = NO; - SDKROOT = macosx10.6; - }; - name = Release; - }; - 6581071611DE809D0049FB12 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - COPY_PHASE_STRIP = NO; - GCC_DYNAMIC_NO_PIC = NO; - GCC_OPTIMIZATION_LEVEL = 0; - PRODUCT_NAME = OpenPilotOSX; - }; - name = Debug; - }; - 6581071711DE809D0049FB12 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - COPY_PHASE_STRIP = YES; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - GCC_ENABLE_FIX_AND_CONTINUE = NO; - PRODUCT_NAME = OpenPilotOSX; - ZERO_LINK = NO; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "OpenPilotOSX" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 1DEB928A08733DD80010E9CD /* Debug */, - 1DEB928B08733DD80010E9CD /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 6581071A11DE80A30049FB12 /* Build configuration list for PBXLegacyTarget "OpenPilotOSX" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 6581071611DE809D0049FB12 /* Debug */, - 6581071711DE809D0049FB12 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 08FB7793FE84155DC02AAC07 /* Project object */; -} +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXFileReference section */ + 4354B66314FED9FE004BA3B4 /* flight */ = {isa = PBXFileReference; lastKnownFileType = folder; name = flight; path = ../..; sourceTree = SOURCE_ROOT; }; + 65173C9F12EBFD1700D6A7CB /* Makefile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.make; name = Makefile; path = ../../../Makefile; sourceTree = SOURCE_ROOT; }; + 65904F1814632C1700FD9482 /* firmware-defs.mk */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "firmware-defs.mk"; sourceTree = ""; }; + 65904F2214632C1700FD9482 /* board-info.mk */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "board-info.mk"; sourceTree = ""; }; + 65904F2314632C1700FD9482 /* board-info.mk */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "board-info.mk"; sourceTree = ""; }; + 65904F2414632C1700FD9482 /* board-info.mk */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "board-info.mk"; sourceTree = ""; }; + 65904F2514632C1700FD9482 /* board-info.mk */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "board-info.mk"; sourceTree = ""; }; + 65904F2614632C1700FD9482 /* board-info.mk */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "board-info.mk"; sourceTree = ""; }; + 65904F2714632C1700FD9482 /* board-info.mk */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "board-info.mk"; sourceTree = ""; }; + 65904F2814632C1700FD9482 /* version-info.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = "version-info.py"; sourceTree = ""; }; + 65904F2914632C1700FD9482 /* firmware_info.c.template */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = firmware_info.c.template; sourceTree = ""; }; + 65904F2A14632C1700FD9482 /* gcs_version_info.h.template */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gcs_version_info.h.template; sourceTree = ""; }; + 65904F2D14632C1700FD9482 /* README.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README.txt; sourceTree = ""; }; + 65904F2E14632C1700FD9482 /* shell_script.reg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = shell_script.reg; sourceTree = ""; }; + 65904F2F14632C1700FD9482 /* install */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = install; sourceTree = ""; }; + 65904F3014632C1700FD9482 /* make */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = make; sourceTree = ""; }; + 65904F3114632C1700FD9482 /* make.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = make.sh; sourceTree = ""; }; + 65904F3214632C1700FD9482 /* sh.cmd */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = sh.cmd; sourceTree = ""; }; + 65904F34146362F300FD9482 /* board-info.mk */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "board-info.mk"; sourceTree = ""; }; + 65E466BC14E244020075459C /* uavobjectdefinition */ = {isa = PBXFileReference; lastKnownFileType = folder; path = uavobjectdefinition; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXGroup section */ + 08FB7794FE84155DC02AAC07 /* OpenPilotOSX */ = { + isa = PBXGroup; + children = ( + 4354B66314FED9FE004BA3B4 /* flight */, + 65904F1614632C1700FD9482 /* make */, + 65C35E4E12EFB2F3004811C2 /* shared */, + 65173C9F12EBFD1700D6A7CB /* Makefile */, + ); + name = OpenPilotOSX; + sourceTree = ""; + }; + 65904F1614632C1700FD9482 /* make */ = { + isa = PBXGroup; + children = ( + 65904F1714632C1700FD9482 /* boards */, + 65904F1814632C1700FD9482 /* firmware-defs.mk */, + 65904F1914632C1700FD9482 /* scripts */, + 65904F1A14632C1700FD9482 /* templates */, + 65904F1B14632C1700FD9482 /* winx86 */, + ); + name = make; + path = OpenPilotOSX.xcodeproj/../../../../make; + sourceTree = ""; + }; + 65904F1714632C1700FD9482 /* boards */ = { + isa = PBXGroup; + children = ( + 65904F33146362F300FD9482 /* revolution */, + 65904F1C14632C1700FD9482 /* ahrs */, + 65904F1D14632C1700FD9482 /* coptercontrol */, + 65904F1E14632C1700FD9482 /* esc */, + 65904F1F14632C1700FD9482 /* ins */, + 65904F2014632C1700FD9482 /* openpilot */, + 65904F2114632C1700FD9482 /* oplink */, + ); + path = boards; + sourceTree = ""; + }; + 65904F1914632C1700FD9482 /* scripts */ = { + isa = PBXGroup; + children = ( + 65904F2814632C1700FD9482 /* version-info.py */, + ); + path = scripts; + sourceTree = ""; + }; + 65904F1A14632C1700FD9482 /* templates */ = { + isa = PBXGroup; + children = ( + 65904F2914632C1700FD9482 /* firmware_info.c.template */, + 65904F2A14632C1700FD9482 /* gcs_version_info.h.template */, + ); + path = templates; + sourceTree = ""; + }; + 65904F1B14632C1700FD9482 /* winx86 */ = { + isa = PBXGroup; + children = ( + 65904F2B14632C1700FD9482 /* bin */, + 65904F2C14632C1700FD9482 /* cmd */, + 65904F2D14632C1700FD9482 /* README.txt */, + 65904F2E14632C1700FD9482 /* shell_script.reg */, + ); + path = winx86; + sourceTree = ""; + }; + 65904F1C14632C1700FD9482 /* ahrs */ = { + isa = PBXGroup; + children = ( + 65904F2214632C1700FD9482 /* board-info.mk */, + ); + path = ahrs; + sourceTree = ""; + }; + 65904F1D14632C1700FD9482 /* coptercontrol */ = { + isa = PBXGroup; + children = ( + 65904F2314632C1700FD9482 /* board-info.mk */, + ); + path = coptercontrol; + sourceTree = ""; + }; + 65904F1E14632C1700FD9482 /* esc */ = { + isa = PBXGroup; + children = ( + 65904F2414632C1700FD9482 /* board-info.mk */, + ); + path = esc; + sourceTree = ""; + }; + 65904F1F14632C1700FD9482 /* ins */ = { + isa = PBXGroup; + children = ( + 65904F2514632C1700FD9482 /* board-info.mk */, + ); + path = ins; + sourceTree = ""; + }; + 65904F2014632C1700FD9482 /* openpilot */ = { + isa = PBXGroup; + children = ( + 65904F2614632C1700FD9482 /* board-info.mk */, + ); + path = openpilot; + sourceTree = ""; + }; + 65904F2114632C1700FD9482 /* oplink */ = { + isa = PBXGroup; + children = ( + 65904F2714632C1700FD9482 /* board-info.mk */, + ); + path = oplink; + sourceTree = ""; + }; + 65904F2B14632C1700FD9482 /* bin */ = { + isa = PBXGroup; + children = ( + 65904F2F14632C1700FD9482 /* install */, + 65904F3014632C1700FD9482 /* make */, + ); + path = bin; + sourceTree = ""; + }; + 65904F2C14632C1700FD9482 /* cmd */ = { + isa = PBXGroup; + children = ( + 65904F3114632C1700FD9482 /* make.sh */, + 65904F3214632C1700FD9482 /* sh.cmd */, + ); + path = cmd; + sourceTree = ""; + }; + 65904F33146362F300FD9482 /* revolution */ = { + isa = PBXGroup; + children = ( + 65904F34146362F300FD9482 /* board-info.mk */, + ); + path = revolution; + sourceTree = ""; + }; + 65C35E4E12EFB2F3004811C2 /* shared */ = { + isa = PBXGroup; + children = ( + 65E466BC14E244020075459C /* uavobjectdefinition */, + ); + name = shared; + path = ../../../shared; + sourceTree = SOURCE_ROOT; + }; +/* End PBXGroup section */ + +/* Begin PBXLegacyTarget section */ + 6581071511DE809D0049FB12 /* OpenPilotOSX */ = { + isa = PBXLegacyTarget; + buildArgumentsString = ef_sparky2; + buildConfigurationList = 6581071A11DE80A30049FB12 /* Build configuration list for PBXLegacyTarget "OpenPilotOSX" */; + buildPhases = ( + ); + buildToolPath = /usr/bin/make; + buildWorkingDirectory = ../../..; + dependencies = ( + ); + name = OpenPilotOSX; + passBuildSettingsInEnvironment = 1; + productName = OpenPilotOSX; + }; +/* End PBXLegacyTarget section */ + +/* Begin PBXProject section */ + 08FB7793FE84155DC02AAC07 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0820; + ORGANIZATIONNAME = OpenPilot; + }; + buildConfigurationList = 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "OpenPilotOSX" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 1; + knownRegions = ( + English, + Japanese, + French, + German, + ); + mainGroup = 08FB7794FE84155DC02AAC07 /* OpenPilotOSX */; + projectDirPath = ""; + projectRoot = ../../..; + targets = ( + 6581071511DE809D0049FB12 /* OpenPilotOSX */, + ); + }; +/* End PBXProject section */ + +/* Begin XCBuildConfiguration section */ + 1DEB928A08733DD80010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + ONLY_ACTIVE_ARCH = YES; + PREBINDING = NO; + SDKROOT = macosx; + }; + name = Debug; + }; + 1DEB928B08733DD80010E9CD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + PREBINDING = NO; + SDKROOT = macosx; + }; + name = Release; + }; + 6581071611DE809D0049FB12 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + PRODUCT_NAME = OpenPilotOSX; + }; + name = Debug; + }; + 6581071711DE809D0049FB12 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + GCC_ENABLE_FIX_AND_CONTINUE = NO; + PRODUCT_NAME = OpenPilotOSX; + ZERO_LINK = NO; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "OpenPilotOSX" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB928A08733DD80010E9CD /* Debug */, + 1DEB928B08733DD80010E9CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 6581071A11DE80A30049FB12 /* Build configuration list for PBXLegacyTarget "OpenPilotOSX" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 6581071611DE809D0049FB12 /* Debug */, + 6581071711DE809D0049FB12 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 08FB7793FE84155DC02AAC07 /* Project object */; +} diff --git a/flight/make/apps-defs.mk b/flight/make/apps-defs.mk index 475609c03f..32623ef690 100644 --- a/flight/make/apps-defs.mk +++ b/flight/make/apps-defs.mk @@ -89,6 +89,7 @@ SRC += $(PIOSCOMMON)/pios_wavplay.c SRC += $(PIOSCOMMON)/pios_rfm22b.c SRC += $(PIOSCOMMON)/pios_rfm22b_com.c SRC += $(PIOSCOMMON)/pios_rcvr.c +SRC += $(PIOSCOMMON)/pios_dsm.c SRC += $(PIOSCOMMON)/pios_sbus.c SRC += $(PIOSCOMMON)/pios_hott.c SRC += $(PIOSCOMMON)/pios_srxl.c @@ -99,6 +100,7 @@ SRC += $(PIOSCOMMON)/pios_sensors.c SRC += $(PIOSCOMMON)/pios_servo.c SRC += $(PIOSCOMMON)/pios_openlrs.c SRC += $(PIOSCOMMON)/pios_openlrs_rcvr.c +SRC += $(PIOSCOMMON)/pios_board_io.c ## Misc library functions SRC += $(FLIGHTLIB)/sanitycheck.c diff --git a/flight/modules/Osd/osdoutput/osdoutput.c b/flight/modules/Osd/osdoutput/osdoutput.c index 88f84d8f72..7f18b47208 100644 --- a/flight/modules/Osd/osdoutput/osdoutput.c +++ b/flight/modules/Osd/osdoutput/osdoutput.c @@ -284,6 +284,11 @@ static int32_t osdoutputInitialize(void) osdoutputEnabled = 0; } #endif + + if (osdoutputEnabled && osd_hk_com_id) { + PIOS_COM_ChangeBaud(osd_hk_com_id, 57600); + } + return 0; } MODULE_INITCALL(osdoutputInitialize, osdoutputStart); diff --git a/flight/pios/common/pios_board_io.c b/flight/pios/common/pios_board_io.c new file mode 100644 index 0000000000..835ca272a8 --- /dev/null +++ b/flight/pios/common/pios_board_io.c @@ -0,0 +1,798 @@ +/** + ****************************************************************************** + * + * @file pios_board_io.c + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017. + * @brief board io setup + * -- + * @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 +#include +#include + +#include "uavobjectmanager.h" + +#include + +#ifdef PIOS_INCLUDE_RCVR +# ifdef PIOS_INCLUDE_HOTT +# include +# endif +# ifdef PIOS_INCLUDE_DSM +# include +# endif +# ifdef PIOS_INCLUDE_SBUS +# include +# endif +# ifdef PIOS_INCLUDE_IBUS +# include +# endif +# ifdef PIOS_INCLUDE_EXBUS +# include +# endif +# ifdef PIOS_INCLUDE_SRXL +# include +# endif +# include +# ifdef PIOS_INCLUDE_GCSRCVR +# include +# endif +#endif /* PIOS_INCLUDE_RCVR */ + +#ifdef PIOS_INCLUDE_RFM22B +# include +# include +# ifdef PIOS_INCLUDE_RCVR +# include +# include +# include +# include +# endif /* PIOS_INCLUDE_RCVR */ +#endif /* PIOS_INCLUDE_RFM22B */ + +#ifdef PIOS_INCLUDE_ADC +# include +#endif + +#ifdef PIOS_INCLUDE_MS5611 +# include +#endif + +#ifdef PIOS_INCLUDE_RCVR +# include "manualcontrolsettings.h" +uint32_t pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_NONE]; /* Receivers */ +#endif /* PIOS_INCLUDE_RCVR */ + +#include "hwsettings.h" +#include "auxmagsettings.h" +#include "gcsreceiver.h" + +#ifdef PIOS_INCLUDE_GPS +uint32_t pios_com_gps_id; /* GPS */ +#endif /* PIOS_INCLUDE_GPS */ + +uint32_t pios_com_bridge_id; /* ComUsbBridge */ +uint32_t pios_com_telem_rf_id; /* Serial port telemetry */ + +#ifdef PIOS_INCLUDE_RFM22B +uint32_t pios_rfm22b_id; /* RFM22B handle */ +uint32_t pios_com_rf_id; /* RFM22B telemetry */ +#endif + +uint32_t pios_com_hkosd_id; /* HK OSD ?? */ +uint32_t pios_com_msp_id; /* MSP */ +uint32_t pios_com_mavlink_id; /* MAVLink */ +uint32_t pios_com_vcp_id; /* USB VCP */ + +#ifdef PIOS_INCLUDE_DEBUG_CONSOLE +uint32_t pios_com_debug_id; /* DebugConsole */ +#endif /* PIOS_INCLUDE_DEBUG_CONSOLE */ + +#ifdef PIOS_INCLUDE_USB + +uint32_t pios_com_telem_usb_id; /* USB telemetry */ + +#ifdef PIOS_INCLUDE_USB_RCTX +uint32_t pios_usb_rctx_id; +#endif + +#if defined(PIOS_INCLUDE_HMC5X83) +# include "pios_hmc5x83.h" +# if defined(PIOS_HMC5X83_HAS_GPIOS) +pios_hmc5x83_dev_t pios_hmc5x83_internal_id; +# endif +#endif + + +#include "pios_usb_board_data_priv.h" +#include "pios_usb_desc_hid_cdc_priv.h" +#include "pios_usb_desc_hid_only_priv.h" +#include "pios_usbhook.h" + + +#if defined(PIOS_INCLUDE_COM_MSG) +/* for bootloader? */ +#include + +#endif /* PIOS_INCLUDE_COM_MSG */ + +void PIOS_BOARD_IO_Configure_USB() +{ + /* Initialize board specific USB data */ + PIOS_USB_BOARD_DATA_Init(); + + /* Flags to determine if various USB interfaces are advertised */ + bool usb_hid_present = false; + bool usb_cdc_present = false; + +#if defined(PIOS_INCLUDE_USB_CDC) + if (PIOS_USB_DESC_HID_CDC_Init()) { + PIOS_Assert(0); + } + usb_hid_present = true; + usb_cdc_present = true; +#else + if (PIOS_USB_DESC_HID_ONLY_Init()) { + PIOS_Assert(0); + } + usb_hid_present = true; +#endif + + uint32_t pios_usb_id; + PIOS_USB_Init(&pios_usb_id, PIOS_BOARD_HW_DEFS_GetUsbCfg(pios_board_info_blob.board_rev)); + + uint8_t hwsettings_usb_vcpport; + uint8_t hwsettings_usb_hidport; + + HwSettingsUSB_VCPPortGet(&hwsettings_usb_vcpport); + HwSettingsUSB_HIDPortGet(&hwsettings_usb_hidport); + +#if defined(PIOS_INCLUDE_USB_CDC) + + if (!usb_cdc_present) { + /* Force VCP port function to disabled if we haven't advertised VCP in our USB descriptor */ + hwsettings_usb_vcpport = HWSETTINGS_USB_VCPPORT_DISABLED; + } + + if (!usb_hid_present) { + /* Force HID port function to disabled if we haven't advertised HID in our USB descriptor */ + hwsettings_usb_hidport = HWSETTINGS_USB_HIDPORT_DISABLED; + } + + /* Why do we need to init these if function is *NONE* ?? */ +#if defined(PIOS_INCLUDE_USB_CDC) + uint32_t pios_usb_cdc_id; + if (PIOS_USB_CDC_Init(&pios_usb_cdc_id, &pios_usb_cdc_cfg, pios_usb_id)) { + PIOS_Assert(0); + } + + uint32_t pios_usb_hid_id; + if (PIOS_USB_HID_Init(&pios_usb_hid_id, &pios_usb_hid_cfg, pios_usb_id)) { + PIOS_Assert(0); + } +#else + uint32_t pios_usb_hid_id; + if (PIOS_USB_HID_Init(&pios_usb_hid_id, &pios_usb_hid_only_cfg, pios_usb_id)) { + PIOS_Assert(0); + } +#endif + + switch (hwsettings_usb_vcpport) { + case HWSETTINGS_USB_VCPPORT_DISABLED: + break; + case HWSETTINGS_USB_VCPPORT_USBTELEMETRY: +#if defined(PIOS_INCLUDE_COM) + if (PIOS_COM_Init(&pios_com_telem_usb_id, &pios_usb_cdc_com_driver, pios_usb_cdc_id, + 0, PIOS_COM_TELEM_USB_RX_BUF_LEN, /* Let Init() allocate this buffer */ + 0, PIOS_COM_TELEM_USB_TX_BUF_LEN)) { /* Let Init() allocate this buffer */ + PIOS_Assert(0); + } +#endif /* PIOS_INCLUDE_COM */ + break; + case HWSETTINGS_USB_VCPPORT_COMBRIDGE: +#if defined(PIOS_INCLUDE_COM) + if (PIOS_COM_Init(&pios_com_vcp_id, &pios_usb_cdc_com_driver, pios_usb_cdc_id, + 0, PIOS_COM_BRIDGE_RX_BUF_LEN, /* Let Init() allocate this buffer */ + 0, PIOS_COM_BRIDGE_TX_BUF_LEN)) { /* Let Init() allocate this buffer */ + PIOS_Assert(0); + } +#endif /* PIOS_INCLUDE_COM */ + break; + case HWSETTINGS_USB_VCPPORT_DEBUGCONSOLE: +#if defined(PIOS_INCLUDE_COM) +#if defined(PIOS_INCLUDE_DEBUG_CONSOLE) + if (PIOS_COM_Init(&pios_com_debug_id, &pios_usb_cdc_com_driver, pios_usb_cdc_id, + 0, 0, /* No RX buffer */ + 0, PIOS_COM_BRIDGE_TX_BUF_LEN)) { /* Let Init() allocate this buffer */ + PIOS_Assert(0); + } +#endif /* PIOS_INCLUDE_DEBUG_CONSOLE */ +#endif /* PIOS_INCLUDE_COM */ + break; + case HWSETTINGS_USB_VCPPORT_MAVLINK: + if (PIOS_COM_Init(&pios_com_mavlink_id, &pios_usb_cdc_com_driver, pios_usb_cdc_id, + 0, PIOS_COM_MAVLINK_RX_BUF_LEN, /* Let Init() allocate this buffer */ + 0, PIOS_COM_MAVLINK_TX_BUF_LEN)) { /* Let Init() allocate this buffer */ + PIOS_Assert(0); + } + break; + } +#endif /* PIOS_INCLUDE_USB_CDC */ + +#if defined(PIOS_INCLUDE_USB_HID) + /* Configure the usb HID port */ + + switch (hwsettings_usb_hidport) { + case HWSETTINGS_USB_HIDPORT_DISABLED: + break; + case HWSETTINGS_USB_HIDPORT_USBTELEMETRY: +#if defined(PIOS_INCLUDE_COM) + { + if (PIOS_COM_Init(&pios_com_telem_usb_id, &pios_usb_hid_com_driver, pios_usb_hid_id, + 0, PIOS_COM_TELEM_USB_RX_BUF_LEN, /* Let Init() allocate this buffer */ + 0, PIOS_COM_TELEM_USB_TX_BUF_LEN)) { /* Let Init() allocate this buffer */ + PIOS_Assert(0); + } + } +#endif /* PIOS_INCLUDE_COM */ + break; + case HWSETTINGS_USB_HIDPORT_RCTRANSMITTER: +#if defined(PIOS_INCLUDE_USB_RCTX) + { + if (PIOS_USB_RCTX_Init(&pios_usb_rctx_id, &pios_usb_rctx_cfg, pios_usb_id)) { /* this will reinstall endpoint callbacks */ + PIOS_Assert(0); + } + } +#endif /* PIOS_INCLUDE_USB_RCTX */ + break; + } + +#endif /* PIOS_INCLUDE_USB_HID */ + + if (usb_hid_present || usb_cdc_present) { + PIOS_USBHOOK_Activate(); + } +} + +#endif /* PIOS_INCLUDE_USB */ + +#ifdef PIOS_INCLUDE_RCVR +# ifdef PIOS_INCLUDE_HOTT +static int32_t PIOS_HOTT_Init_SUMD(uint32_t *id, const struct pios_com_driver *driver, uint32_t lower_id) +{ + return PIOS_HOTT_Init(id, driver, lower_id, PIOS_HOTT_PROTO_SUMD); +} + +static int32_t PIOS_HOTT_Init_SUMH(uint32_t *id, const struct pios_com_driver *driver, uint32_t lower_id) +{ + return PIOS_HOTT_Init(id, driver, lower_id, PIOS_HOTT_PROTO_SUMH); +} +# endif /* PIOS_INCLUDE_HOTT */ +# ifdef PIOS_INCLUDE_DSM +static int32_t PIOS_DSM_Init_Helper(uint32_t *id, const struct pios_com_driver *driver, uint32_t lower_id) +{ + // DSM Bind stuff + uint8_t hwsettings_DSMxBind; + + HwSettingsDSMxBindGet(&hwsettings_DSMxBind); + + return PIOS_DSM_Init(id, driver, lower_id, hwsettings_DSMxBind); +} +# endif +# ifdef PIOS_INCLUDE_SBUS +static int32_t PIOS_SBus_Init_Helper(uint32_t *id, const struct pios_com_driver *driver, uint32_t lower_id) +{ + // sbus-noninverted + + HwSettingsSBusModeOptions hwsettings_SBusMode; + + HwSettingsSBusModeGet(&hwsettings_SBusMode); + + struct pios_sbus_cfg sbus_cfg = { + .non_inverted = (hwsettings_SBusMode == HWSETTINGS_SBUSMODE_NONINVERTED), + }; + + return PIOS_SBus_Init(id, &sbus_cfg, driver, lower_id); +} +# endif +#endif /* ifdef PIOS_INCLUDE_RCVR */ + +struct uart_function { + uint32_t *com_id; + uint16_t com_rx_buf_len; + uint16_t com_tx_buf_len; + int32_t (*rcvr_init)(uint32_t *target, const struct pios_com_driver *driver, uint32_t lower_id); + const struct pios_rcvr_driver *rcvr_driver; + ManualControlSettingsChannelGroupsOptions rcvr_group; +}; + +static const struct uart_function uart_function_map[] = { + [PIOS_BOARD_IO_UART_TELEMETRY] = { + .com_id = &pios_com_telem_rf_id, + .com_rx_buf_len = PIOS_COM_TELEM_RF_RX_BUF_LEN, + .com_tx_buf_len = PIOS_COM_TELEM_RF_TX_BUF_LEN, + }, + + [PIOS_BOARD_IO_UART_MAVLINK] = { + .com_id = &pios_com_mavlink_id, + .com_rx_buf_len = PIOS_COM_MAVLINK_RX_BUF_LEN, + .com_tx_buf_len = PIOS_COM_MAVLINK_TX_BUF_LEN, + }, + + [PIOS_BOARD_IO_UART_MSP] = { + .com_id = &pios_com_msp_id, + .com_rx_buf_len = PIOS_COM_MSP_RX_BUF_LEN, + .com_tx_buf_len = PIOS_COM_MSP_TX_BUF_LEN, + }, + + [PIOS_BOARD_IO_UART_GPS] = { + .com_id = &pios_com_gps_id, + .com_rx_buf_len = PIOS_COM_GPS_RX_BUF_LEN, + .com_tx_buf_len = PIOS_COM_GPS_TX_BUF_LEN, + }, + + [PIOS_BOARD_IO_UART_OSDHK] = { + .com_id = &pios_com_hkosd_id, + .com_rx_buf_len = PIOS_COM_HKOSD_RX_BUF_LEN, + .com_tx_buf_len = PIOS_COM_HKOSD_TX_BUF_LEN, + }, +#ifdef PIOS_INCLUDE_RCVR +# ifdef PIOS_INCLUDE_IBUS + [PIOS_BOARD_IO_UART_IBUS] = { + .rcvr_init = &PIOS_IBUS_Init, + .rcvr_driver = &pios_ibus_rcvr_driver, + .rcvr_group = MANUALCONTROLSETTINGS_CHANNELGROUPS_IBUS, + }, +# endif /* PIOS_INCLUDE_IBUS */ +# ifdef PIOS_INCLUDE_EXBUS + [PIOS_BOARD_IO_UART_EXBUS] = { + .rcvr_init = &PIOS_EXBUS_Init, + .rcvr_driver = &pios_exbus_rcvr_driver, + .rcvr_group = MANUALCONTROLSETTINGS_CHANNELGROUPS_EXBUS, + }, +# endif /* PIOS_INCLUDE_EXBUS */ +# ifdef PIOS_INCLUDE_SRXL + [PIOS_BOARD_IO_UART_SRXL] = { + .rcvr_init = &PIOS_SRXL_Init, + .rcvr_driver = &pios_srxl_rcvr_driver, + .rcvr_group = MANUALCONTROLSETTINGS_CHANNELGROUPS_SRXL, + }, +# endif /* PIOS_INCLUDE_SRXL */ +# ifdef PIOS_INCLUDE_HOTT + [PIOS_BOARD_IO_UART_HOTT_SUMD] = { + .rcvr_init = &PIOS_HOTT_Init_SUMD, + .rcvr_driver = &pios_hott_rcvr_driver, + .rcvr_group = MANUALCONTROLSETTINGS_CHANNELGROUPS_HOTT, + }, + + [PIOS_BOARD_IO_UART_HOTT_SUMH] = { + .rcvr_init = &PIOS_HOTT_Init_SUMH, + .rcvr_driver = &pios_hott_rcvr_driver, + .rcvr_group = MANUALCONTROLSETTINGS_CHANNELGROUPS_HOTT, + }, +# endif /* PIOS_INCLUDE_HOTT */ +# ifdef PIOS_INCLUDE_DSM + [PIOS_BOARD_IO_UART_DSM_MAIN] = { + .rcvr_init = &PIOS_DSM_Init_Helper, + .rcvr_driver = &pios_dsm_rcvr_driver, + .rcvr_group = MANUALCONTROLSETTINGS_CHANNELGROUPS_DSMMAINPORT, + }, + + [PIOS_BOARD_IO_UART_DSM_FLEXI] = { + .rcvr_init = &PIOS_DSM_Init_Helper, + .rcvr_driver = &pios_dsm_rcvr_driver, + .rcvr_group = MANUALCONTROLSETTINGS_CHANNELGROUPS_DSMFLEXIPORT, + }, + + [PIOS_BOARD_IO_UART_DSM_RCVR] = { + .rcvr_init = &PIOS_DSM_Init_Helper, + .rcvr_driver = &pios_dsm_rcvr_driver, + .rcvr_group = MANUALCONTROLSETTINGS_CHANNELGROUPS_DSMRCVRPORT, + }, +# endif /* PIOS_INCLUDE_DSM */ +# ifdef PIOS_INCLUDE_SBUS + [PIOS_BOARD_IO_UART_SBUS] = { + .rcvr_init = &PIOS_SBus_Init_Helper, + .rcvr_driver = &pios_sbus_rcvr_driver, + .rcvr_group = MANUALCONTROLSETTINGS_CHANNELGROUPS_SBUS, + }, +# endif /* PIOS_INCLUDE_SBUS */ +#endif /* PIOS_INCLUDE_RCVR */ +}; + +void PIOS_BOARD_IO_Configure_UART(const struct pios_usart_cfg *hw_config, PIOS_BOARD_IO_UART_Function function) +{ + if (function >= NELEMENTS(uart_function_map)) { + return; + } + + if (uart_function_map[function].com_id) { + uint32_t usart_id; + + if (PIOS_USART_Init(&usart_id, hw_config)) { + PIOS_Assert(0); + } + + if (PIOS_COM_Init(uart_function_map[function].com_id, &pios_usart_com_driver, usart_id, + 0, uart_function_map[function].com_rx_buf_len, + 0, uart_function_map[function].com_tx_buf_len)) { + PIOS_Assert(0); + } + } else if (uart_function_map[function].rcvr_init) { + uint32_t usart_id; + + if (PIOS_USART_Init(&usart_id, hw_config)) { + PIOS_Assert(0); + } + + uint32_t rcvr_driver_id; + + if (uart_function_map[function].rcvr_init(&rcvr_driver_id, &pios_usart_com_driver, usart_id)) { + PIOS_Assert(0); + } + + uint32_t rcvr_id; + if (PIOS_RCVR_Init(&rcvr_id, uart_function_map[function].rcvr_driver, rcvr_driver_id)) { + PIOS_Assert(0); + } + + pios_rcvr_group_map[uart_function_map[function].rcvr_group] = rcvr_id; + } +} + +#ifdef PIOS_INCLUDE_PWM +void PIOS_BOARD_IO_Configure_PWM(const struct pios_pwm_cfg *pwm_cfg) +{ + /* Set up the receiver port. Later this should be optional */ + uint32_t pios_pwm_id; + + PIOS_PWM_Init(&pios_pwm_id, pwm_cfg); + + uint32_t pios_pwm_rcvr_id; + if (PIOS_RCVR_Init(&pios_pwm_rcvr_id, &pios_pwm_rcvr_driver, pios_pwm_id)) { + PIOS_Assert(0); + } + pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_PWM] = pios_pwm_rcvr_id; +} +#endif /* PIOS_INCLUDE_PWM */ + +#ifdef PIOS_INCLUDE_PPM +void PIOS_BOARD_IO_Configure_PPM(const struct pios_ppm_cfg *ppm_cfg) +{ + uint32_t pios_ppm_id; + + PIOS_PPM_Init(&pios_ppm_id, ppm_cfg); + + uint32_t pios_ppm_rcvr_id; + if (PIOS_RCVR_Init(&pios_ppm_rcvr_id, &pios_ppm_rcvr_driver, pios_ppm_id)) { + PIOS_Assert(0); + } + pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_PPM] = pios_ppm_rcvr_id; +} +#endif /* PIOS_INCLUDE_PPM */ + +#ifdef PIOS_INCLUDE_GCSRCVR +void PIOS_BOARD_IO_Configure_GCSRCVR() +{ + GCSReceiverInitialize(); + uint32_t pios_gcsrcvr_id; + PIOS_GCSRCVR_Init(&pios_gcsrcvr_id); + uint32_t pios_gcsrcvr_rcvr_id; + if (PIOS_RCVR_Init(&pios_gcsrcvr_rcvr_id, &pios_gcsrcvr_rcvr_driver, pios_gcsrcvr_id)) { + PIOS_Assert(0); + } + pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_GCS] = pios_gcsrcvr_rcvr_id; +} +#endif /* PIOS_INCLUDE_GCSRCVR */ + +#ifdef PIOS_INCLUDE_RFM22B + +#if defined(PIOS_INCLUDE_OPLINKRCVR) && defined(PIOS_INCLUDE_RCVR) +static void PIOS_Board_PPM_callback(const int16_t *channels) +{ + OPLinkReceiverData opl_rcvr; + + for (uint8_t i = 0; i < OPLINKRECEIVER_CHANNEL_NUMELEM; ++i) { + opl_rcvr.Channel[i] = (i < RFM22B_PPM_NUM_CHANNELS) ? channels[i] : PIOS_RCVR_TIMEOUT; + } + OPLinkReceiverSet(&opl_rcvr); +} +#endif /* PIOS_INCLUDE_OPLINKRCVR && PIOS_INCLUDE_RCVR */ + +void PIOS_BOARD_IO_Configure_RFM22B() +{ +#if defined(PIOS_INCLUDE_RFM22B) + OPLinkSettingsInitialize(); + OPLinkStatusInitialize(); +#endif /* PIOS_INCLUDE_RFM22B */ +#if defined(PIOS_INCLUDE_OPLINKRCVR) && defined(PIOS_INCLUDE_RCVR) + OPLinkReceiverInitialize(); +#endif + /* Initialize the RFM22B radio COM device. */ + + /* Fetch the OPLinkSettings object. */ + OPLinkSettingsData oplinkSettings; + OPLinkSettingsGet(&oplinkSettings); + + // Initialize out status object. + OPLinkStatusData oplinkStatus; + OPLinkStatusGet(&oplinkStatus); + oplinkStatus.BoardType = pios_board_info_blob.board_type; + PIOS_BL_HELPER_FLASH_Read_Description(oplinkStatus.Description, OPLINKSTATUS_DESCRIPTION_NUMELEM); + PIOS_SYS_SerialNumberGetBinary(oplinkStatus.CPUSerial); + oplinkStatus.BoardRevision = pios_board_info_blob.board_rev; + + /* Is the radio turned on? */ + bool is_coordinator = (oplinkSettings.Protocol == OPLINKSETTINGS_PROTOCOL_OPLINKCOORDINATOR); + bool openlrs = (oplinkSettings.Protocol == OPLINKSETTINGS_PROTOCOL_OPENLRS); + bool data_mode = ((oplinkSettings.LinkType == OPLINKSETTINGS_LINKTYPE_DATA) || + (oplinkSettings.LinkType == OPLINKSETTINGS_LINKTYPE_DATAANDCONTROL)); + bool ppm_mode = ((oplinkSettings.LinkType == OPLINKSETTINGS_LINKTYPE_CONTROL) || + (oplinkSettings.LinkType == OPLINKSETTINGS_LINKTYPE_DATAANDCONTROL)); + bool ppm_only = (oplinkSettings.LinkType == OPLINKSETTINGS_LINKTYPE_CONTROL); + bool is_enabled = ((oplinkSettings.Protocol != OPLINKSETTINGS_PROTOCOL_DISABLED) && + ((oplinkSettings.MaxRFPower != OPLINKSETTINGS_MAXRFPOWER_0) || openlrs)); + if (is_enabled) { + if (openlrs) { +#if defined(PIOS_INCLUDE_OPENLRS_RCVR) && defined(PIOS_INCLUDE_RCVR) + uint32_t openlrs_id; + const struct pios_openlrs_cfg *openlrs_cfg = PIOS_BOARD_HW_DEFS_GetOpenLRSCfg(pios_board_info_blob.board_rev); + + PIOS_OpenLRS_Init(&openlrs_id, PIOS_RFM22_SPI_PORT, 0, openlrs_cfg); + { + uint32_t openlrsrcvr_id; + PIOS_OpenLRS_Rcvr_Init(&openlrsrcvr_id, openlrs_id); + uint32_t openlrsrcvr_rcvr_id; + if (PIOS_RCVR_Init(&openlrsrcvr_rcvr_id, &pios_openlrs_rcvr_driver, openlrsrcvr_id)) { + PIOS_Assert(0); + } + pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_OPENLRS] = openlrsrcvr_rcvr_id; + } +#endif /* PIOS_INCLUDE_OPENLRS_RCVR && PIOS_INCLUDE_RCVR */ + } else { + /* Configure the RFM22B device. */ + const struct pios_rfm22b_cfg *rfm22b_cfg = PIOS_BOARD_HW_DEFS_GetRfm22Cfg(pios_board_info_blob.board_rev); + + if (PIOS_RFM22B_Init(&pios_rfm22b_id, PIOS_RFM22_SPI_PORT, rfm22b_cfg->slave_num, rfm22b_cfg, oplinkSettings.RFBand)) { + PIOS_Assert(0); + } + + /* Configure the radio com interface */ + if (PIOS_COM_Init(&pios_com_rf_id, &pios_rfm22b_com_driver, pios_rfm22b_id, + 0, PIOS_COM_RFM22B_RF_RX_BUF_LEN, + 0, PIOS_COM_RFM22B_RF_TX_BUF_LEN)) { + PIOS_Assert(0); + } + + oplinkStatus.LinkState = OPLINKSTATUS_LINKSTATE_ENABLED; + + // Set the modem (over the air) datarate. + enum rfm22b_datarate datarate = RFM22_datarate_64000; + switch (oplinkSettings.AirDataRate) { + case OPLINKSETTINGS_AIRDATARATE_9600: + datarate = RFM22_datarate_9600; + break; + case OPLINKSETTINGS_AIRDATARATE_19200: + datarate = RFM22_datarate_19200; + break; + case OPLINKSETTINGS_AIRDATARATE_32000: + datarate = RFM22_datarate_32000; + break; + case OPLINKSETTINGS_AIRDATARATE_57600: + datarate = RFM22_datarate_57600; + break; + case OPLINKSETTINGS_AIRDATARATE_64000: + datarate = RFM22_datarate_64000; + break; + case OPLINKSETTINGS_AIRDATARATE_100000: + datarate = RFM22_datarate_100000; + break; + case OPLINKSETTINGS_AIRDATARATE_128000: + datarate = RFM22_datarate_128000; + break; + case OPLINKSETTINGS_AIRDATARATE_192000: + datarate = RFM22_datarate_192000; + break; + case OPLINKSETTINGS_AIRDATARATE_256000: + datarate = RFM22_datarate_256000; + break; + } + + /* Set the radio configuration parameters. */ + PIOS_RFM22B_SetDeviceID(pios_rfm22b_id, oplinkSettings.CustomDeviceID); + PIOS_RFM22B_SetCoordinatorID(pios_rfm22b_id, oplinkSettings.CoordID); + PIOS_RFM22B_SetXtalCap(pios_rfm22b_id, oplinkSettings.RFXtalCap); + PIOS_RFM22B_SetChannelConfig(pios_rfm22b_id, datarate, oplinkSettings.MinChannel, oplinkSettings.MaxChannel, is_coordinator, data_mode, ppm_mode); + +#if defined(PIOS_INCLUDE_OPLINKRCVR) && defined(PIOS_INCLUDE_RCVR) + /* Set the PPM callback if we should be receiving PPM. */ + if (ppm_mode || (ppm_only && !is_coordinator)) { + PIOS_RFM22B_SetPPMCallback(pios_rfm22b_id, PIOS_Board_PPM_callback); + } +#endif + /* Set the modem Tx power level */ + switch (oplinkSettings.MaxRFPower) { + case OPLINKSETTINGS_MAXRFPOWER_125: + PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_0); + break; + case OPLINKSETTINGS_MAXRFPOWER_16: + PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_1); + break; + case OPLINKSETTINGS_MAXRFPOWER_316: + PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_2); + break; + case OPLINKSETTINGS_MAXRFPOWER_63: + PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_3); + break; + case OPLINKSETTINGS_MAXRFPOWER_126: + PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_4); + break; + case OPLINKSETTINGS_MAXRFPOWER_25: + PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_5); + break; + case OPLINKSETTINGS_MAXRFPOWER_50: + PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_6); + break; + case OPLINKSETTINGS_MAXRFPOWER_100: + PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_7); + break; + default: + // do nothing + break; + } + + /* Reinitialize the modem. */ + PIOS_RFM22B_Reinit(pios_rfm22b_id); + + // TODO: this is in preparation for full mavlink support and is used by LP-368 + uint16_t mavlink_rx_size = PIOS_COM_MAVLINK_RX_BUF_LEN; + + uint8_t hwsettings_radioaux; + HwSettingsRadioAuxStreamGet(&hwsettings_radioaux); + + switch (hwsettings_radioaux) { + case HWSETTINGS_RADIOAUXSTREAM_DEBUGCONSOLE: + case HWSETTINGS_RADIOAUXSTREAM_DISABLED: + break; + case HWSETTINGS_RADIOAUXSTREAM_MAVLINK: + { + if (PIOS_COM_Init(&pios_com_mavlink_id, &pios_rfm22b_aux_com_driver, pios_rfm22b_id, + 0, mavlink_rx_size, + 0, PIOS_COM_BRIDGE_TX_BUF_LEN)) { + PIOS_Assert(0); + } + } + } + } + } else { + oplinkStatus.LinkState = OPLINKSTATUS_LINKSTATE_DISABLED; + } + + OPLinkStatusSet(&oplinkStatus); + +#if defined(PIOS_INCLUDE_OPLINKRCVR) && defined(PIOS_INCLUDE_RCVR) + uint32_t pios_oplinkrcvr_id; + PIOS_OPLinkRCVR_Init(&pios_oplinkrcvr_id); + uint32_t pios_oplinkrcvr_rcvr_id; + if (PIOS_RCVR_Init(&pios_oplinkrcvr_rcvr_id, &pios_oplinkrcvr_rcvr_driver, pios_oplinkrcvr_id)) { + PIOS_Assert(0); + } + pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_OPLINK] = pios_oplinkrcvr_rcvr_id; +#endif /* PIOS_INCLUDE_OPLINKRCVR && PIOS_INCLUDE_RCVR */ +} +#endif /* ifdef PIOS_INCLUDE_RFM22B */ + +#ifdef PIOS_INCLUDE_I2C +void PIOS_BOARD_IO_Configure_I2C(uint32_t i2c_internal_id, uint32_t i2c_external_id) +{ + // internal HMC5x83 mag +# ifdef PIOS_INCLUDE_HMC5X83_INTERNAL + const struct pios_hmc5x83_cfg *hmc5x83_internal_cfg = PIOS_BOARD_HW_DEFS_GetInternalHMC5x83Cfg(pios_board_info_blob.board_rev); + + if (hmc5x83_internal_cfg) { + // attach the 5x83 mag to internal i2c bus + pios_hmc5x83_internal_id = PIOS_HMC5x83_Init(hmc5x83_internal_cfg, i2c_internal_id, 0); +# ifdef PIOS_INCLUDE_WDG + // give HMC5x83 on I2C some extra time to allow for reset, etc. if needed + // this is not in a loop, so it is safe + PIOS_WDG_Clear(); +# endif /* PIOS_INCLUDE_WDG */ + // add this sensor to the sensor task's list + PIOS_HMC5x83_Register(pios_hmc5x83_internal_id, PIOS_SENSORS_TYPE_3AXIS_MAG); + } + +# endif /* PIOS_INCLUDE_HMC5X83_INTERNAL */ + + // internal ms5611 baro +#if defined(PIOS_INCLUDE_MS5611) + PIOS_MS5611_Init(PIOS_BOARD_HW_DEFS_GetMS5611Cfg(pios_board_info_blob.board_rev), i2c_internal_id); + PIOS_MS5611_Register(); +#endif + + // internal bmp280 baro + // internal MPU6000 imu (i2c) + // internal eeprom (revo nano) - NOT HERE, should be initialized earlier + + + /* Initialize external sensors */ + + // aux mag +# ifdef PIOS_INCLUDE_HMC5X83 + AuxMagSettingsInitialize(); + + AuxMagSettingsTypeOptions option; + AuxMagSettingsTypeGet(&option); + + const struct pios_hmc5x83_cfg *hmc5x83_external_cfg = PIOS_BOARD_HW_DEFS_GetExternalHMC5x83Cfg(pios_board_info_blob.board_rev); + + if (hmc5x83_external_cfg) { + uint32_t i2c_id = 0; + + if (option == AUXMAGSETTINGS_TYPE_FLEXI) { + // i2c_external + i2c_id = i2c_external_id; + } else if (option == AUXMAGSETTINGS_TYPE_I2C) { + // i2c_internal (or Sparky2/F3 dedicated I2C port) + i2c_id = i2c_internal_id; + } + + if (i2c_id) { + uint32_t external_mag = PIOS_HMC5x83_Init(hmc5x83_external_cfg, i2c_id, 0); +# ifdef PIOS_INCLUDE_WDG + // give HMC5x83 on I2C some extra time to allow for reset, etc. if needed + // this is not in a loop, so it is safe + PIOS_WDG_Clear(); +# endif /* PIOS_INCLUDE_WDG */ + // add this sensor to the sensor task's list + // be careful that you don't register a slow, unimportant sensor after registering the fastest sensor + // and before registering some other fast and important sensor + // as that would cause delay and time jitter for the second fast sensor + PIOS_HMC5x83_Register(external_mag, PIOS_SENSORS_TYPE_3AXIS_AUXMAG); + // mag alarm is cleared later, so use I2C + AlarmsSet(SYSTEMALARMS_ALARM_I2C, (external_mag) ? SYSTEMALARMS_ALARM_OK : SYSTEMALARMS_ALARM_WARNING); + } + } +# endif /* PIOS_INCLUDE_HMC5X83 */ + + // external ETASV3 Eagletree Airspeed v3 + // external MS4525D PixHawk Airpeed based on MS4525DO + + // BMA180 accelerometer? + // bmp085/bmp180 baro + + // hmc5843 mag + // i2c esc (?) + // UBX DCC +} +#endif /* ifdef PIOS_INCLUDE_I2C */ + +#ifdef PIOS_INCLUDE_ADC +void PIOS_BOARD_IO_Configure_ADC() +{ + PIOS_ADC_Init(PIOS_BOARD_HW_DEFS_GetAdcCfg(pios_board_info_blob.board_rev)); + uint8_t adc_config[HWSETTINGS_ADCROUTING_NUMELEM]; + HwSettingsADCRoutingArrayGet(adc_config); + for (uint32_t i = 0; i < HWSETTINGS_ADCROUTING_NUMELEM; i++) { + if (adc_config[i] != HWSETTINGS_ADCROUTING_DISABLED) { + PIOS_ADC_PinSetup(i); + } + } +} +#endif /* PIOS_INCLUDE_ADC */ diff --git a/flight/pios/common/pios_com.c b/flight/pios/common/pios_com.c index fe5f890619..26794095f6 100644 --- a/flight/pios/common/pios_com.c +++ b/flight/pios/common/pios_com.c @@ -118,8 +118,18 @@ int32_t PIOS_COM_Init(uint32_t *com_id, const struct pios_com_driver *driver, ui PIOS_Assert(com_id); PIOS_Assert(driver); - bool has_rx = (rx_buffer && rx_buffer_len > 0); - bool has_tx = (tx_buffer && tx_buffer_len > 0); + if ((rx_buffer_len > 0) && !rx_buffer) { + rx_buffer = (uint8_t *)pios_malloc(rx_buffer_len); + PIOS_Assert(rx_buffer); + } + + if ((tx_buffer_len > 0) && !tx_buffer) { + tx_buffer = (uint8_t *)pios_malloc(tx_buffer_len); + PIOS_Assert(tx_buffer); + } + + bool has_rx = (rx_buffer_len > 0); + bool has_tx = (tx_buffer_len > 0); PIOS_Assert(driver->bind_tx_cb || !has_tx); PIOS_Assert(driver->bind_rx_cb || !has_rx); @@ -846,6 +856,29 @@ void PIOS_COM_LinkComPair(uint32_t com1_id, uint32_t com2_id, bool link_ctrl_lin } } +/* + * Invoke driver specific control functions + * \param[in] port COM port + * \param[in] ctl control function number + * \param[inout] control function parameter + * \return 0 on success + */ +int32_t PIOS_COM_Ioctl(uint32_t com_id, uint32_t ctl, void *param) +{ + struct pios_com_dev *com_dev = (struct pios_com_dev *)com_id; + + if (!PIOS_COM_validate(com_dev)) { + /* Undefined COM port for this board (see pios_board.c) */ + return -1; + } + + if (!com_dev->driver->ioctl) { + return -1; + } + + return com_dev->driver->ioctl(com_dev->lower_id, ctl, param); +} + #endif /* PIOS_INCLUDE_COM */ /** diff --git a/flight/pios/stm32f4xx/pios_dsm.c b/flight/pios/common/pios_dsm.c similarity index 90% rename from flight/pios/stm32f4xx/pios_dsm.c rename to flight/pios/common/pios_dsm.c index bdd8244e13..23d3601e3f 100644 --- a/flight/pios/stm32f4xx/pios_dsm.c +++ b/flight/pios/common/pios_dsm.c @@ -78,9 +78,8 @@ struct pios_dsm_state { #define DSM_FL_WEIGHTED_AVE 18 struct pios_dsm_dev { - enum pios_dsm_dev_magic magic; - const struct pios_dsm_cfg *cfg; - struct pios_dsm_state state; + enum pios_dsm_dev_magic magic; + struct pios_dsm_state state; }; /* Allocate DSM device descriptor */ @@ -122,39 +121,42 @@ static bool PIOS_DSM_Validate(struct pios_dsm_dev *dsm_dev) } /* Try to bind DSMx satellite using specified number of pulses */ -static void PIOS_DSM_Bind(struct pios_dsm_dev *dsm_dev, uint8_t bind) +static void PIOS_DSM_Bind(struct stm32_gpio *rxpin, uint8_t bind) { - const struct pios_dsm_cfg *cfg = dsm_dev->cfg; + GPIO_InitTypeDef bindInit = { + .GPIO_Pin = rxpin->init.GPIO_Pin, + .GPIO_Speed = GPIO_Speed_2MHz, + .GPIO_Mode = GPIO_Mode_OUT, + .GPIO_OType = GPIO_OType_PP, + .GPIO_PuPd = GPIO_PuPd_NOPULL + }; - GPIO_InitTypeDef GPIO_InitStructure = cfg->bind.init; - - GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; - - /* just to limit bind pulses */ - if (bind > 10) { - bind = 10; - } - - GPIO_Init(cfg->bind.gpio, &cfg->bind.init); + GPIO_Init(rxpin->gpio, &bindInit); /* RX line, set high */ - GPIO_SetBits(cfg->bind.gpio, cfg->bind.init.GPIO_Pin); + GPIO_SetBits(rxpin->gpio, rxpin->init.GPIO_Pin); /* Wait until the bind window opens. */ while (PIOS_DELAY_GetuS() < DSM_BIND_MIN_DELAY_US) { ; } + /* just to limit bind pulses */ + if (bind > 10) { + bind = 10; + } + for (int i = 0; i < bind; i++) { /* RX line, drive low for 120us */ - GPIO_ResetBits(cfg->bind.gpio, cfg->bind.init.GPIO_Pin); + GPIO_ResetBits(rxpin->gpio, rxpin->init.GPIO_Pin); PIOS_DELAY_WaituS(120); /* RX line, drive high for 120us */ - GPIO_SetBits(cfg->bind.gpio, cfg->bind.init.GPIO_Pin); + GPIO_SetBits(rxpin->gpio, rxpin->init.GPIO_Pin); PIOS_DELAY_WaituS(120); } + /* RX line, set input and wait for data */ - GPIO_Init(cfg->bind.gpio, &GPIO_InitStructure); + GPIO_Init(rxpin->gpio, (GPIO_InitTypeDef *)&rxpin->init); } /* Reset channels in case of lost signal or explicit failsafe receiver flag */ @@ -292,13 +294,11 @@ static void PIOS_DSM_UpdateState(struct pios_dsm_dev *dsm_dev, uint8_t byte) /* Initialise DSM receiver interface */ int32_t PIOS_DSM_Init(uint32_t *dsm_id, - const struct pios_dsm_cfg *cfg, const struct pios_com_driver *driver, uint32_t lower_id, uint8_t bind) { PIOS_DEBUG_Assert(dsm_id); - PIOS_DEBUG_Assert(cfg); PIOS_DEBUG_Assert(driver); struct pios_dsm_dev *dsm_dev; @@ -308,20 +308,36 @@ int32_t PIOS_DSM_Init(uint32_t *dsm_id, return -1; } - /* Bind the configuration to the device instance */ - dsm_dev->cfg = cfg; - /* Bind the receiver if requested */ if (bind) { - PIOS_DSM_Bind(dsm_dev, bind); + struct stm32_gpio rxpin; + + PIOS_DEBUG_Assert(driver->ioctl); + + if ((driver->ioctl)(lower_id, PIOS_IOCTL_USART_GET_RXGPIO, &rxpin) < 0) { + return -1; + } + + PIOS_DSM_Bind(&rxpin, bind); } PIOS_DSM_ResetState(dsm_dev); *dsm_id = (uint32_t)dsm_dev; + + /* Set comm driver parameters */ + PIOS_DEBUG_Assert(driver->set_config); + driver->set_config(lower_id, PIOS_COM_Word_length_8b, PIOS_COM_StopBits_1, PIOS_COM_Parity_No, 115200, PIOS_COM_Mode_Rx); + + /* Set irq priority */ + if (driver->ioctl) { + uint8_t irq_prio = PIOS_IRQ_PRIO_HIGH; + driver->ioctl(lower_id, PIOS_IOCTL_USART_SET_IRQ_PRIO, &irq_prio); + } + /* Set comm driver callback */ - (driver->bind_rx_cb)(lower_id, PIOS_DSM_RxInCallback, *dsm_id); + driver->bind_rx_cb(lower_id, PIOS_DSM_RxInCallback, *dsm_id); if (!PIOS_RTC_RegisterTickCallback(PIOS_DSM_Supervisor, *dsm_id)) { PIOS_DEBUG_Assert(0); diff --git a/flight/pios/common/pios_exbus.c b/flight/pios/common/pios_exbus.c index a65333ea00..c29564075a 100644 --- a/flight/pios/common/pios_exbus.c +++ b/flight/pios/common/pios_exbus.c @@ -307,8 +307,18 @@ int32_t PIOS_EXBUS_Init(uint32_t *exbus_id, *exbus_id = (uint32_t)exbus_dev; + /* Set comm driver parameters */ + PIOS_DEBUG_Assert(driver->set_config); + driver->set_config(lower_id, PIOS_COM_Word_length_8b, PIOS_COM_StopBits_1, PIOS_COM_Parity_No, 125000, PIOS_COM_Mode_Rx); + + /* Set irq priority */ + if (driver->ioctl) { + uint8_t irq_prio = PIOS_IRQ_PRIO_HIGH; + driver->ioctl(lower_id, PIOS_IOCTL_USART_SET_IRQ_PRIO, &irq_prio); + } + /* Set comm driver callback */ - (driver->bind_rx_cb)(lower_id, PIOS_EXBUS_RxInCallback, *exbus_id); + driver->bind_rx_cb(lower_id, PIOS_EXBUS_RxInCallback, *exbus_id); if (!PIOS_RTC_RegisterTickCallback(PIOS_EXBUS_Supervisor, *exbus_id)) { PIOS_DEBUG_Assert(0); diff --git a/flight/pios/common/pios_hott.c b/flight/pios/common/pios_hott.c index a3106edc4d..04f2fc940a 100644 --- a/flight/pios/common/pios_hott.c +++ b/flight/pios/common/pios_hott.c @@ -325,6 +325,16 @@ int32_t PIOS_HOTT_Init(uint32_t *hott_id, *hott_id = (uint32_t)hott_dev; + /* Set comm driver parameters */ + PIOS_DEBUG_Assert(driver->set_config); + driver->set_config(lower_id, PIOS_COM_Word_length_8b, PIOS_COM_StopBits_1, PIOS_COM_Parity_No, 115200, PIOS_COM_Mode_Rx); + + /* Set irq priority */ + if (driver->ioctl) { + uint8_t irq_prio = PIOS_IRQ_PRIO_HIGH; + driver->ioctl(lower_id, PIOS_IOCTL_USART_SET_IRQ_PRIO, &irq_prio); + } + /* Set comm driver callback */ (driver->bind_rx_cb)(lower_id, PIOS_HOTT_RxInCallback, *hott_id); diff --git a/flight/pios/common/pios_ibus.c b/flight/pios/common/pios_ibus.c index e37b430143..953ef88652 100644 --- a/flight/pios/common/pios_ibus.c +++ b/flight/pios/common/pios_ibus.c @@ -174,7 +174,17 @@ int32_t PIOS_IBUS_Init(uint32_t *ibus_id, const struct pios_com_driver *driver, PIOS_Assert(0); } - (driver->bind_rx_cb)(lower_id, PIOS_IBUS_Receive, *ibus_id); + /* Set comm driver parameters */ + PIOS_DEBUG_Assert(driver->set_config); + driver->set_config(lower_id, PIOS_COM_Word_length_8b, PIOS_COM_StopBits_1, PIOS_COM_Parity_No, 115200, PIOS_COM_Mode_Rx); + + /* Set irq priority */ + if (driver->ioctl) { + uint8_t irq_prio = PIOS_IRQ_PRIO_HIGH; + driver->ioctl(lower_id, PIOS_IOCTL_USART_SET_IRQ_PRIO, &irq_prio); + } + + driver->bind_rx_cb(lower_id, PIOS_IBUS_Receive, *ibus_id); return 0; } diff --git a/flight/pios/common/pios_sbus.c b/flight/pios/common/pios_sbus.c index 240a7c51c9..979c6a856c 100644 --- a/flight/pios/common/pios_sbus.c +++ b/flight/pios/common/pios_sbus.c @@ -166,13 +166,22 @@ int32_t PIOS_SBus_Init(uint32_t *sbus_id, *sbus_id = (uint32_t)sbus_dev; - /* Enable inverter clock and enable the inverter */ - (*cfg->gpio_clk_func)(cfg->gpio_clk_periph, ENABLE); - GPIO_Init(cfg->inv.gpio, &cfg->inv.init); - GPIO_WriteBit(cfg->inv.gpio, cfg->inv.init.GPIO_Pin, cfg->gpio_inv_enable); + /* Set rest of the parameters */ + if (driver->set_config) { + driver->set_config(lower_id, PIOS_COM_Word_length_8b, PIOS_COM_StopBits_2, PIOS_COM_Parity_Even, 100000, PIOS_COM_Mode_Rx); + } + + /* Set inverted UART and IRQ priority */ + if (driver->ioctl) { + enum PIOS_USART_Inverted param = cfg->non_inverted ? 0 : PIOS_USART_Inverted_Rx; + driver->ioctl(lower_id, PIOS_IOCTL_USART_SET_INVERTED, ¶m); + + uint8_t irq_prio = PIOS_IRQ_PRIO_HIGH; + driver->ioctl(lower_id, PIOS_IOCTL_USART_SET_IRQ_PRIO, &irq_prio); + } /* Set comm driver callback */ - (driver->bind_rx_cb)(lower_id, PIOS_SBus_RxInCallback, *sbus_id); + driver->bind_rx_cb(lower_id, PIOS_SBus_RxInCallback, *sbus_id); if (!PIOS_RTC_RegisterTickCallback(PIOS_SBus_Supervisor, *sbus_id)) { PIOS_DEBUG_Assert(0); diff --git a/flight/pios/common/pios_srxl.c b/flight/pios/common/pios_srxl.c index 711679829c..b0595ed8e7 100644 --- a/flight/pios/common/pios_srxl.c +++ b/flight/pios/common/pios_srxl.c @@ -156,8 +156,18 @@ int32_t PIOS_SRXL_Init(uint32_t *srxl_id, *srxl_id = (uint32_t)srxl_dev; + /* Set comm driver parameters */ + PIOS_DEBUG_Assert(driver->set_config); + driver->set_config(lower_id, PIOS_COM_Word_length_8b, PIOS_COM_StopBits_1, PIOS_COM_Parity_No, 115200, PIOS_COM_Mode_Rx); + + /* Set irq priority */ + if (driver->ioctl) { + uint8_t irq_prio = PIOS_IRQ_PRIO_HIGH; + driver->ioctl(lower_id, PIOS_IOCTL_USART_SET_IRQ_PRIO, &irq_prio); + } + /* Set comm driver callback */ - (driver->bind_rx_cb)(lower_id, PIOS_SRXL_RxInCallback, *srxl_id); + driver->bind_rx_cb(lower_id, PIOS_SRXL_RxInCallback, *srxl_id); if (!PIOS_RTC_RegisterTickCallback(PIOS_SRXL_Supervisor, *srxl_id)) { PIOS_DEBUG_Assert(0); diff --git a/flight/pios/common/pios_usb_desc_hid_cdc.c b/flight/pios/common/pios_usb_desc_hid_cdc.c index e68e5ab680..d14add637d 100644 --- a/flight/pios/common/pios_usb_desc_hid_cdc.c +++ b/flight/pios/common/pios_usb_desc_hid_cdc.c @@ -317,6 +317,22 @@ static const struct usb_config_hid_cdc config_hid_cdc = { }, }; +const struct pios_usb_cdc_cfg pios_usb_cdc_cfg = { + .ctrl_if = 0, + .ctrl_tx_ep = 2, + + .data_if = 1, + .data_rx_ep = 3, + .data_tx_ep = 3, +}; + +const struct pios_usb_hid_cfg pios_usb_hid_cfg = { + .data_if = 2, + .data_rx_ep = 1, + .data_tx_ep = 1, +}; + + int32_t PIOS_USB_DESC_HID_CDC_Init(void) { PIOS_USBHOOK_RegisterConfig(1, (uint8_t *)&config_hid_cdc, sizeof(config_hid_cdc)); diff --git a/flight/pios/common/pios_usb_desc_hid_only.c b/flight/pios/common/pios_usb_desc_hid_only.c index 89cf9ebe41..ce45013882 100644 --- a/flight/pios/common/pios_usb_desc_hid_only.c +++ b/flight/pios/common/pios_usb_desc_hid_only.c @@ -156,6 +156,12 @@ const struct usb_config_hid_only config_hid_only = { }, }; +const struct pios_usb_hid_cfg pios_usb_hid_only_cfg = { + .data_if = 0, + .data_rx_ep = 1, + .data_tx_ep = 1, +}; + int32_t PIOS_USB_DESC_HID_ONLY_Init(void) { PIOS_USBHOOK_RegisterConfig(1, (uint8_t *)&config_hid_only, sizeof(config_hid_only)); diff --git a/flight/pios/inc/pios_board_hw.h b/flight/pios/inc/pios_board_hw.h new file mode 100644 index 0000000000..ce344b9ce6 --- /dev/null +++ b/flight/pios/inc/pios_board_hw.h @@ -0,0 +1,56 @@ +/** + ****************************************************************************** + * + * @file pios_board_io.h + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017. + * @brief PIOS_BOARD_HW_DEFS 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_BOARD_HW_H +#define PIOS_BOARD_HW_H + +#ifdef PIOS_INCLUDE_LED +const struct pios_gpio_cfg *PIOS_BOARD_HW_DEFS_GetLedCfg(uint32_t board_revision); +#endif +#ifdef PIOS_INCLUDE_USB +const struct pios_usb_cfg *PIOS_BOARD_HW_DEFS_GetUsbCfg(uint32_t board_revision); +#endif +#ifdef PIOS_INCLUDE_RFM22B +const struct pios_rfm22b_cfg *PIOS_BOARD_HW_DEFS_GetRfm22Cfg(uint32_t board_revision); +#endif +#ifdef PIOS_INCLUDE_OPENLRS +const struct pios_openlrs_cfg *PIOS_BOARD_HW_DEFS_GetOpenLRSCfg(uint32_t board_revision); +#endif +# ifdef PIOS_INCLUDE_HMC5X83_INTERNAL +const struct pios_hmc5x83_cfg *PIOS_BOARD_HW_DEFS_GetInternalHMC5x83Cfg(uint32_t board_revision); +# endif +#ifdef PIOS_INCLUDE_HMC5X83 +const struct pios_hmc5x83_cfg *PIOS_BOARD_HW_DEFS_GetExternalHMC5x83Cfg(uint32_t board_revision); +#endif +#ifdef PIOS_INCLUDE_MS5611 +const struct pios_ms5611_cfg *PIOS_BOARD_HW_DEFS_GetMS5611Cfg(uint32_t board_revision); +#endif +#ifdef PIOS_INCLUDE_BMP280 +const struct pios_bmp280_cfg *PIOS_BOARD_HW_DEFS_GetBMP280Cfg(uint32_t board_revision); +#endif +#ifdef PIOS_INCLUDE_ADC +const struct pios_adc_cfg *PIOS_BOARD_HW_DEFS_GetAdcCfg(uint32_t board_revision); +#endif +#endif /* PIOS_BOARD_HW_H */ diff --git a/flight/pios/inc/pios_board_io.h b/flight/pios/inc/pios_board_io.h new file mode 100644 index 0000000000..bbcd5c2cc6 --- /dev/null +++ b/flight/pios/inc/pios_board_io.h @@ -0,0 +1,221 @@ +/** + ****************************************************************************** + * + * @file pios_board_io.h + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017. + * @brief board io setup + * -- + * @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_BOARD_IO_H +#define PIOS_BOARD_IO_H + +#include "pios.h" + + +#ifdef PIOS_INCLUDE_USB +#include +#endif + +#include + +#ifdef PIOS_INCLUDE_PWM +#include +#endif + +#ifdef PIOS_INCLUDE_PPM +#include +#endif + +#ifdef PIOS_INCLUDE_OPENLRS +#include +#endif + +#ifdef PIOS_INCLUDE_RCVR +extern uint32_t pios_rcvr_group_map[]; /* Receivers */ +#endif + +/* GPS */ +#ifdef PIOS_INCLUDE_GPS +extern uint32_t pios_com_gps_id; +# define PIOS_COM_GPS (pios_com_gps_id) +# ifndef PIOS_COM_GPS_RX_BUF_LEN +# define PIOS_COM_GPS_RX_BUF_LEN 128 +# endif +# ifndef PIOS_COM_GPS_TX_BUF_LEN +# define PIOS_COM_GPS_TX_BUF_LEN 32 +# endif +#endif /* PIOS_INCLUDE_GPS */ + + +/* ComUsbBridge */ +extern uint32_t pios_com_bridge_id; +#define PIOS_COM_BRIDGE (pios_com_bridge_id) +#ifndef PIOS_COM_BRIDGE_RX_BUF_LEN +# define PIOS_COM_BRIDGE_RX_BUF_LEN 65 +#endif +#ifndef PIOS_COM_BRIDGE_TX_BUF_LEN +# define PIOS_COM_BRIDGE_TX_BUF_LEN 12 +#endif + + +/* USB telemetry */ +extern uint32_t pios_com_telem_usb_id; +#define PIOS_COM_TELEM_USB (pios_com_telem_usb_id) +#ifndef PIOS_COM_TELEM_USB_RX_BUF_LEN +# define PIOS_COM_TELEM_USB_RX_BUF_LEN 65 +#endif +#ifndef PIOS_COM_TELEM_USB_TX_BUF_LEN +#define PIOS_COM_TELEM_USB_TX_BUF_LEN 65 +#endif + +/* Serial port telemetry */ +extern uint32_t pios_com_telem_rf_id; +#define PIOS_COM_TELEM_RF (pios_com_telem_rf_id) +#ifndef PIOS_COM_TELEM_RF_RX_BUF_LEN +# define PIOS_COM_TELEM_RF_RX_BUF_LEN 512 +#endif +#ifndef PIOS_COM_TELEM_RF_TX_BUF_LEN +# define PIOS_COM_TELEM_RF_TX_BUF_LEN 512 +#endif + + +/* RFM22B telemetry */ +#ifdef PIOS_INCLUDE_RFM22B +extern uint32_t pios_com_rf_id; +# define PIOS_COM_RF (pios_com_rf_id) +# ifndef PIOS_COM_RFM22B_RF_RX_BUF_LEN +# define PIOS_COM_RFM22B_RF_RX_BUF_LEN 512 +# endif +# ifndef PIOS_COM_RFM22B_RF_TX_BUF_LEN +# define PIOS_COM_RFM22B_RF_TX_BUF_LEN 512 +# endif +#endif + + +/* HK OSD ?? */ +extern uint32_t pios_com_hkosd_id; +#define PIOS_COM_OSDHK (pios_com_hkosd_id) +#ifndef PIOS_COM_HKOSD_RX_BUF_LEN +# define PIOS_COM_HKOSD_RX_BUF_LEN 22 +#endif +#ifndef PIOS_COM_HKOSD_TX_BUF_LEN +# define PIOS_COM_HKOSD_TX_BUF_LEN 22 +#endif + +/* MSP */ +extern uint32_t pios_com_msp_id; +#define PIOS_COM_MSP (pios_com_msp_id) +#ifndef PIOS_COM_MSP_TX_BUF_LEN +# define PIOS_COM_MSP_TX_BUF_LEN 128 +#endif +#ifndef PIOS_COM_MSP_RX_BUF_LEN +# define PIOS_COM_MSP_RX_BUF_LEN 64 +#endif + +/* MAVLink */ +extern uint32_t pios_com_mavlink_id; +#define PIOS_COM_MAVLINK (pios_com_mavlink_id) +#ifndef PIOS_COM_MAVLINK_TX_BUF_LEN +# define PIOS_COM_MAVLINK_TX_BUF_LEN 128 +#endif +#ifndef PIOS_COM_MAVLINK_RX_BUF_LEN +# define PIOS_COM_MAVLINK_RX_BUF_LEN 128 +#endif + +/* USB VCP */ +extern uint32_t pios_com_vcp_id; +#define PIOS_COM_VCP (pios_com_vcp_id) + + +#ifdef PIOS_INCLUDE_DEBUG_CONSOLE +extern uint32_t pios_com_debug_id; +#define PIOS_COM_DEBUG (pios_com_debug_id) +#ifndef PIOS_COM_DEBUGCONSOLE_TX_BUF_LEN +# define PIOS_COM_DEBUGCONSOLE_TX_BUF_LEN 40 +#endif +#endif /* PIOS_INCLUDE_DEBUG_CONSOLE */ + +#ifdef PIOS_INCLUDE_USB_RCTX +extern uint32_t pios_usb_rctx_id; +#endif /* PIOS_INCLUDE_USB_RCTX */ + +#if defined(PIOS_INCLUDE_HMC5X83) && defined(PIOS_HMC5X83_HAS_GPIOS) +#include +extern pios_hmc5x83_dev_t pios_hmc5x83_internal_id; +#endif + +typedef enum { + PIOS_BOARD_IO_UART_NONE, + PIOS_BOARD_IO_UART_TELEMETRY, /* com */ + PIOS_BOARD_IO_UART_MAVLINK, /* com */ + PIOS_BOARD_IO_UART_MSP, /* com */ + PIOS_BOARD_IO_UART_GPS, /* com */ + PIOS_BOARD_IO_UART_COMBRIDGE, /* com */ + PIOS_BOARD_IO_UART_DEBUGCONSOLE, /* com */ + PIOS_BOARD_IO_UART_OSDHK, /* com */ + PIOS_BOARD_IO_UART_SBUS, /* rcvr */ + PIOS_BOARD_IO_UART_DSM_MAIN, /* rcvr */ + PIOS_BOARD_IO_UART_DSM_FLEXI, /* rcvr */ + PIOS_BOARD_IO_UART_DSM_RCVR, /* rcvr */ + PIOS_BOARD_IO_UART_HOTT_SUMD, /* rcvr */ + PIOS_BOARD_IO_UART_HOTT_SUMH, /* rcvr */ + PIOS_BOARD_IO_UART_SRXL, /* rcvr */ + PIOS_BOARD_IO_UART_IBUS, /* rcvr */ + PIOS_BOARD_IO_UART_EXBUS, /* rcvr */ +} PIOS_BOARD_IO_UART_Function; + +#ifdef PIOS_INCLUDE_USB +void PIOS_BOARD_IO_Configure_USB(); +# if defined(PIOS_INCLUDE_USB_HID) +# include +extern const struct pios_usb_hid_cfg pios_usb_hid_cfg; +# endif /* PIOS_INCLUDE_USB_HID */ +#endif /* PIOS_INCLUDE_USB */ +#ifdef PIOS_INCLUDE_PWM +void PIOS_BOARD_IO_Configure_PWM(const struct pios_pwm_cfg *pwm_cfg); +#endif +#ifdef PIOS_INCLUDE_PPM +void PIOS_BOARD_IO_Configure_PPM(const struct pios_ppm_cfg *ppm_cfg); +#endif + +void PIOS_BOARD_IO_Configure_UART(const struct pios_usart_cfg *usart_cfg, PIOS_BOARD_IO_UART_Function function); + +#ifdef PIOS_INCLUDE_RFM22B +void PIOS_BOARD_IO_Configure_RFM22B(); +#endif + +#ifdef PIOS_INCLUDE_I2C +void PIOS_BOARD_IO_Configure_I2C(uint32_t i2c_internal_id, uint32_t i2c_external_id); +#endif + +#ifdef PIOS_INCLUDE_GCSRCVR +void PIOS_BOARD_IO_Configure_GCSRCVR(); +#endif + +#ifdef PIOS_INCLUDE_WS2811 +void PIOS_BOARD_IO_Configure_WS2811(); +#endif + +#ifdef PIOS_INCLUDE_ADC +void PIOS_BOARD_IO_Configure_ADC(); +#endif + + +#endif /* PIOS_BOARD_IO_H */ diff --git a/flight/pios/inc/pios_com.h b/flight/pios/inc/pios_com.h index eb4ee37a8a..a150691a38 100644 --- a/flight/pios/inc/pios_com.h +++ b/flight/pios/inc/pios_com.h @@ -70,7 +70,6 @@ enum PIOS_COM_Mode { }; struct pios_com_driver { - void (*init)(uint32_t id); void (*set_baud)(uint32_t id, uint32_t baud); void (*set_halfduplex)(uint32_t id, bool halfduplex); void (*set_config)(uint32_t usart_id, enum PIOS_COM_Word_Length word_len, enum PIOS_COM_StopBits stop_bits, enum PIOS_COM_Parity parity, uint32_t baud_rate, enum PIOS_COM_Mode mode); @@ -83,6 +82,7 @@ struct pios_com_driver { void (*bind_baud_rate_cb)(uint32_t id, pios_com_callback_baud_rate baud_rate_cb, uint32_t context); uint32_t (*available)(uint32_t id); void (*bind_available_cb)(uint32_t id, pios_com_callback_available available_cb, uint32_t context); + int32_t (*ioctl)(uint32_t id, uint32_t ctl, void *param); }; /* Control line definitions */ @@ -117,10 +117,36 @@ extern int32_t PIOS_COM_ASYNC_RegisterTxCallback(uint32_t id, pios_com_callback extern void PIOS_COM_LinkComPair(uint32_t com1_id, uint32_t com2_id, bool link_ctrl_line, bool link_baud_rate); -#define COM_AVAILABLE_NONE (0) -#define COM_AVAILABLE_RX (1 << 0) -#define COM_AVAILABLE_TX (1 << 1) -#define COM_AVAILABLE_RXTX (COM_AVAILABLE_RX | COM_AVAILABLE_TX) +#define COM_AVAILABLE_NONE (0) +#define COM_AVAILABLE_RX (1 << 0) +#define COM_AVAILABLE_TX (1 << 1) +#define COM_AVAILABLE_RXTX (COM_AVAILABLE_RX | COM_AVAILABLE_TX) + +/* ioctl */ +extern int32_t PIOS_COM_Ioctl(uint32_t com_id, uint32_t ctl, void *param); + +#define COM_IOCTL_NRBITS 16 +#define COM_IOCTL_TYPEBITS 16 + +#define COM_IOCTL_NRMASK ((1 << COM_IOCTL_NRBITS) - 1) +#define COM_IOCTL_TYPEMASK ((1 << COM_IOCTL_TYPEBITS) - 1) + +#define COM_IOCTL_NRSHIFT 0 +#define COM_IOCTL_TYPESHIFT (COM_IOCTL_NRSHIFT + COM_IOCTL_NRBITS) + +#define COM_IOCTL(type, nr, pt) \ + (((type) << COM_IOCTL_TYPESHIFT) | \ + ((nr) << COM_IOCTL_NRSHIFT)) + +/* used to decode ioctl numbers.. */ +#define COM_IOCTL_TYPE(nr) (((nr) >> COM_IOCTL_TYPESHIFT) & COM_IOCTL_TYPEMASK) +#define COM_IOCTL_NR(nr) (((nr) >> COM_IOCTL_NRSHIFT) & COM_IOCTL_NRMASK) + +enum pios_com_ioctl_type { + COM_IOCTL_TYPE_USART, + COM_IOCTL_TYPE_USB_CDC, + COM_IOCTL_TYPE_SOFT_UART, +}; #endif /* PIOS_COM_H */ diff --git a/flight/pios/inc/pios_dsm_priv.h b/flight/pios/inc/pios_dsm_priv.h index 40607e93ee..6e7ce1106b 100644 --- a/flight/pios/inc/pios_dsm_priv.h +++ b/flight/pios/inc/pios_dsm_priv.h @@ -109,15 +109,9 @@ */ // #define DSM_LOST_FRAME_COUNTER -/* DSM receiver instance configuration */ -struct pios_dsm_cfg { - struct stm32_gpio bind; -}; - extern const struct pios_rcvr_driver pios_dsm_rcvr_driver; extern int32_t PIOS_DSM_Init(uint32_t *dsm_id, - const struct pios_dsm_cfg *cfg, const struct pios_com_driver *driver, uint32_t lower_id, uint8_t bind); diff --git a/flight/pios/inc/pios_sbus_priv.h b/flight/pios/inc/pios_sbus_priv.h index 791683831b..e99a4adca5 100644 --- a/flight/pios/inc/pios_sbus_priv.h +++ b/flight/pios/inc/pios_sbus_priv.h @@ -84,11 +84,12 @@ * S.Bus configuration programmable invertor */ struct pios_sbus_cfg { - struct stm32_gpio inv; - void (*gpio_clk_func)(uint32_t periph, FunctionalState state); - uint32_t gpio_clk_periph; - BitAction gpio_inv_enable; - BitAction gpio_inv_disable; + bool non_inverted; +// struct stm32_gpio inv; +// void (*gpio_clk_func)(uint32_t periph, FunctionalState state); +// uint32_t gpio_clk_periph; +// BitAction gpio_inv_enable; +// BitAction gpio_inv_disable; }; extern const struct pios_rcvr_driver pios_sbus_rcvr_driver; diff --git a/flight/pios/inc/pios_stm32.h b/flight/pios/inc/pios_stm32.h index 01aefe059c..03eaa26993 100644 --- a/flight/pios/inc/pios_stm32.h +++ b/flight/pios/inc/pios_stm32.h @@ -60,7 +60,13 @@ struct stm32_dma { struct stm32_gpio { GPIO_TypeDef *gpio; GPIO_InitTypeDef init; - uint8_t pin_source; + uint8_t pin_source; /* do we really need this, or we can get it from init.GPIO_Pin ? */ +}; + +struct stm32_gpio_action { + struct stm32_gpio pin; + BitAction on; + BitAction off; }; /** diff --git a/flight/pios/inc/pios_usart.h b/flight/pios/inc/pios_usart.h index 379223a6f5..49ac3c92a8 100644 --- a/flight/pios/inc/pios_usart.h +++ b/flight/pios/inc/pios_usart.h @@ -34,6 +34,25 @@ /* Global Types */ /* Public Functions */ +/* USART Ioctls */ + +enum PIOS_USART_Inverted { + PIOS_USART_Inverted_None = 0, + PIOS_USART_Inverted_Rx = (1 << 0), + PIOS_USART_Inverted_Tx = (1 << 1), + PIOS_USART_Inverted_RxTx = (PIOS_USART_Inverted_Rx | PIOS_USART_Inverted_Tx) +}; + +#define PIOS_IOCTL_USART_SET_INVERTED COM_IOCTL(COM_IOCTL_TYPE_USART, 1, enum PIOS_USART_Inverted) +#define PIOS_IOCTL_USART_SET_SWAPPIN COM_IOCTL(COM_IOCTL_TYPE_USART, 2, bool) +#define PIOS_IOCTL_USART_SET_ONEWIRE COM_IOCTL(COM_IOCTL_TYPE_USART, 3, bool) + +#define PIOS_IOCTL_USART_GET_RXGPIO COM_IOCTL(COM_IOCTL_TYPE_USART, 4, struct stm32_gpio) +#define PIOS_IOCTL_USART_GET_TXGPIO COM_IOCTL(COM_IOCTL_TYPE_USART, 5, struct stm32_gpio) + +/* PIOS_IRQ_PRIO_ values */ +#define PIOS_IOCTL_USART_SET_IRQ_PRIO COM_IOCTL(COM_IOCTL_TYPE_USART, 6, uint8_t) + #endif /* PIOS_USART_H */ /** diff --git a/flight/pios/inc/pios_usart_priv.h b/flight/pios/inc/pios_usart_priv.h index 68a44bc9df..d939e1f44c 100644 --- a/flight/pios/inc/pios_usart_priv.h +++ b/flight/pios/inc/pios_usart_priv.h @@ -41,15 +41,17 @@ extern const struct pios_com_driver pios_usart_com_driver; struct pios_usart_cfg { USART_TypeDef *regs; uint32_t remap; /* GPIO_Remap_* */ - USART_InitTypeDef init; struct stm32_gpio rx; struct stm32_gpio tx; struct stm32_gpio dtr; - struct stm32_irq irq; + + /* provide hook for board specific ioctls */ + int32_t (*ioctl)(uint32_t id, uint32_t ctl, void *param); }; extern int32_t PIOS_USART_Init(uint32_t *usart_id, const struct pios_usart_cfg *cfg); -extern const struct pios_usart_cfg *PIOS_USART_GetConfig(uint32_t usart_id); + +const struct pios_usart_cfg *PIOS_USART_GetConfig(uint32_t usart_id); #endif /* PIOS_USART_PRIV_H */ diff --git a/flight/pios/inc/pios_usb_desc_hid_cdc_priv.h b/flight/pios/inc/pios_usb_desc_hid_cdc_priv.h index a828a1c6fd..6a3145a8b9 100644 --- a/flight/pios/inc/pios_usb_desc_hid_cdc_priv.h +++ b/flight/pios/inc/pios_usb_desc_hid_cdc_priv.h @@ -31,9 +31,14 @@ #define PIOS_USB_DESC_HID_CDC_PRIV_H #include +#include +#include extern int32_t PIOS_USB_DESC_HID_CDC_Init(void); +extern const struct pios_usb_cdc_cfg pios_usb_cdc_cfg; +extern const struct pios_usb_hid_cfg pios_usb_hid_cfg; + #endif /* PIOS_USB_DESC_HID_CDC_PRIV_H */ /** diff --git a/flight/pios/inc/pios_usb_desc_hid_only_priv.h b/flight/pios/inc/pios_usb_desc_hid_only_priv.h index 6d98c3967f..b9c9dcda2c 100644 --- a/flight/pios/inc/pios_usb_desc_hid_only_priv.h +++ b/flight/pios/inc/pios_usb_desc_hid_only_priv.h @@ -31,9 +31,13 @@ #define PIOS_USB_DESC_HID_ONLY_PRIV_H #include +#include extern int32_t PIOS_USB_DESC_HID_ONLY_Init(void); +extern const struct pios_usb_hid_cfg pios_usb_hid_only_cfg; + + #endif /* PIOS_USB_DESC_HID_ONLY_PRIV_H */ /** diff --git a/flight/pios/stm32f10x/pios_dsm.c b/flight/pios/stm32f10x/pios_dsm.c deleted file mode 100644 index 44fa484be1..0000000000 --- a/flight/pios/stm32f10x/pios_dsm.c +++ /dev/null @@ -1,438 +0,0 @@ -/** - ****************************************************************************** - * @addtogroup PIOS PIOS Core hardware abstraction layer - * @{ - * @addtogroup PIOS_DSM Spektrum/JR DSMx satellite receiver functions - * @brief Code to bind and read Spektrum/JR DSMx satellite receiver serial stream - * @{ - * - * @file pios_dsm.c - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2011. - * @brief Code bind and read Spektrum/JR DSMx satellite receiver serial stream - * @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.h" - -#ifdef PIOS_INCLUDE_DSM - -#include "pios_dsm_priv.h" - -// *** UNTESTED CODE *** -#undef DSM_LINK_QUALITY - -/* Forward Declarations */ -static int32_t PIOS_DSM_Get(uint32_t rcvr_id, uint8_t channel); -static uint8_t PIOS_DSM_Quality_Get(uint32_t rcvr_id); -static uint16_t PIOS_DSM_RxInCallback(uint32_t context, - uint8_t *buf, - uint16_t buf_len, - uint16_t *headroom, - bool *need_yield); -static void PIOS_DSM_Supervisor(uint32_t dsm_id); - -/* Local Variables */ -const struct pios_rcvr_driver pios_dsm_rcvr_driver = { - .read = PIOS_DSM_Get, - .get_quality = PIOS_DSM_Quality_Get -}; - -enum pios_dsm_dev_magic { - PIOS_DSM_DEV_MAGIC = 0x44534d78, -}; - -struct pios_dsm_state { - uint16_t channel_data[PIOS_DSM_NUM_INPUTS]; - uint8_t received_data[DSM_FRAME_LENGTH]; - uint8_t receive_timer; - uint8_t failsafe_timer; - uint8_t frame_found; - uint8_t byte_count; - uint8_t frames_lost_last; - float quality; -}; - -/* With an DSM frame rate of 11ms (90Hz) averaging over 18 samples - * gives about a 200ms response. - */ -#define DSM_FL_WEIGHTED_AVE 18 - -struct pios_dsm_dev { - enum pios_dsm_dev_magic magic; - const struct pios_dsm_cfg *cfg; - struct pios_dsm_state state; -}; - -/* Allocate DSM device descriptor */ -#if defined(PIOS_INCLUDE_FREERTOS) -static struct pios_dsm_dev *PIOS_DSM_Alloc(void) -{ - struct pios_dsm_dev *dsm_dev; - - dsm_dev = (struct pios_dsm_dev *)pios_malloc(sizeof(*dsm_dev)); - if (!dsm_dev) { - return NULL; - } - - dsm_dev->magic = PIOS_DSM_DEV_MAGIC; - return dsm_dev; -} -#else -static struct pios_dsm_dev pios_dsm_devs[PIOS_DSM_MAX_DEVS]; -static uint8_t pios_dsm_num_devs; -static struct pios_dsm_dev *PIOS_DSM_Alloc(void) -{ - struct pios_dsm_dev *dsm_dev; - - if (pios_dsm_num_devs >= PIOS_DSM_MAX_DEVS) { - return NULL; - } - - dsm_dev = &pios_dsm_devs[pios_dsm_num_devs++]; - dsm_dev->magic = PIOS_DSM_DEV_MAGIC; - - return dsm_dev; -} -#endif /* if defined(PIOS_INCLUDE_FREERTOS) */ - -/* Validate DSM device descriptor */ -static bool PIOS_DSM_Validate(struct pios_dsm_dev *dsm_dev) -{ - return dsm_dev->magic == PIOS_DSM_DEV_MAGIC; -} - -/* Try to bind DSMx satellite using specified number of pulses */ -static void PIOS_DSM_Bind(struct pios_dsm_dev *dsm_dev, uint8_t bind) -{ - const struct pios_dsm_cfg *cfg = dsm_dev->cfg; - - GPIO_InitTypeDef GPIO_InitStructure; - - GPIO_InitStructure.GPIO_Pin = cfg->bind.init.GPIO_Pin; - GPIO_InitStructure.GPIO_Speed = cfg->bind.init.GPIO_Speed; - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; - - /* just to limit bind pulses */ - if (bind > 10) { - bind = 10; - } - - GPIO_Init(cfg->bind.gpio, &cfg->bind.init); - - /* RX line, set high */ - GPIO_SetBits(cfg->bind.gpio, cfg->bind.init.GPIO_Pin); - - /* on CC works up to 140ms, guess bind window is around 20-140ms after power up */ - PIOS_DELAY_WaitmS(20); - - for (int i = 0; i < bind; i++) { - /* RX line, drive low for 120us */ - GPIO_ResetBits(cfg->bind.gpio, cfg->bind.init.GPIO_Pin); - PIOS_DELAY_WaituS(120); - /* RX line, drive high for 120us */ - GPIO_SetBits(cfg->bind.gpio, cfg->bind.init.GPIO_Pin); - PIOS_DELAY_WaituS(120); - } - /* RX line, set input and wait for data */ - GPIO_Init(cfg->bind.gpio, &GPIO_InitStructure); -} - -/* Reset channels in case of lost signal or explicit failsafe receiver flag */ -static void PIOS_DSM_ResetChannels(struct pios_dsm_dev *dsm_dev) -{ - struct pios_dsm_state *state = &(dsm_dev->state); - - for (int i = 0; i < PIOS_DSM_NUM_INPUTS; i++) { - state->channel_data[i] = PIOS_RCVR_TIMEOUT; - } -} - -/* Reset DSM receiver state */ -static void PIOS_DSM_ResetState(struct pios_dsm_dev *dsm_dev) -{ - struct pios_dsm_state *state = &(dsm_dev->state); - - state->receive_timer = 0; - state->failsafe_timer = 0; - state->frame_found = 0; - state->quality = 0.0f; - state->frames_lost_last = 0; - PIOS_DSM_ResetChannels(dsm_dev); -} - -/** - * Check and unroll complete frame data. - * \output 0 frame data accepted - * \output -1 frame error found - */ -static int PIOS_DSM_UnrollChannels(struct pios_dsm_dev *dsm_dev) -{ - struct pios_dsm_state *state = &(dsm_dev->state); - /* Fix resolution for detection. */ - static uint8_t resolution = 11; - uint32_t channel_log = 0; - - // *** UNTESTED CODE *** -#ifdef DSM_LINK_QUALITY - /* increment the lost frame counter */ - uint8_t frames_lost = state->received_data[0]; - - /* We only get a lost frame count when the next good frame comes in */ - /* Present quality as a weighted average of good frames */ - /* First consider the bad frames */ - for (int i = 0; i < frames_lost - state->frames_lost_last; i++) { - state->quality = (state->quality * (DSM_FL_WEIGHTED_AVE - 1)) / - DSM_FL_WEIGHTED_AVE; - } - /* And now the good frame */ - state->quality = ((state->quality * (DSM_FL_WEIGHTED_AVE - 1)) + - 100) / DSM_FL_WEIGHTED_AVE; - - state->frames_lost_last = frames_lost; -#endif /* DSM_LINK_QUALITY */ - - /* unroll channels */ - uint8_t *s = &(state->received_data[2]); - uint16_t mask = (resolution == 10) ? 0x03ff : 0x07ff; - - for (int i = 0; i < DSM_CHANNELS_PER_FRAME; i++) { - uint16_t word = ((uint16_t)s[0] << 8) | s[1]; - s += 2; - - /* skip empty channel slot */ - if (word == 0xffff) { - continue; - } - - /* minimal data validation */ - if ((i > 0) && (word & DSM_2ND_FRAME_MASK)) { - /* invalid frame data, ignore rest of the frame */ - goto stream_error; - } - - /* extract and save the channel value */ - uint8_t channel_num = (word >> resolution) & 0x0f; - if (channel_num < PIOS_DSM_NUM_INPUTS) { - if (channel_log & (1 << channel_num)) { - /* Found duplicate. This should happen when in 11 bit */ - /* mode and the data is 10 bits */ - if (resolution == 10) { - return -1; - } - resolution = 10; - return PIOS_DSM_UnrollChannels(dsm_dev); - } - - if ((channel_log & 0xFF) == 0x55) { - /* This pattern indicates 10 bit pattern */ - if (resolution == 11) { - return -1; - } - resolution = 11; - return PIOS_DSM_UnrollChannels(dsm_dev); - } - - state->channel_data[channel_num] = (word & mask); - /* keep track of this channel */ - channel_log |= (1 << channel_num); - } - } - - /* all channels processed */ - return 0; - -stream_error: - /* either DSM2 selected with DSMX stream found, or vice-versa */ - return -1; -} - -/* Update decoder state processing input byte from the DSMx stream */ -static void PIOS_DSM_UpdateState(struct pios_dsm_dev *dsm_dev, uint8_t byte) -{ - struct pios_dsm_state *state = &(dsm_dev->state); - - if (state->frame_found) { - /* receiving the data frame */ - if (state->byte_count < DSM_FRAME_LENGTH) { - /* store next byte */ - state->received_data[state->byte_count++] = byte; - if (state->byte_count == DSM_FRAME_LENGTH) { - /* full frame received - process and wait for new one */ - if (!PIOS_DSM_UnrollChannels(dsm_dev)) { - /* data looking good */ - state->failsafe_timer = 0; - } - - /* prepare for the next frame */ - state->frame_found = 0; - } - } - } -} - -/* Initialise DSM receiver interface */ -int32_t PIOS_DSM_Init(uint32_t *dsm_id, - const struct pios_dsm_cfg *cfg, - const struct pios_com_driver *driver, - uint32_t lower_id, - uint8_t bind) -{ - PIOS_DEBUG_Assert(dsm_id); - PIOS_DEBUG_Assert(cfg); - PIOS_DEBUG_Assert(driver); - - struct pios_dsm_dev *dsm_dev; - - dsm_dev = (struct pios_dsm_dev *)PIOS_DSM_Alloc(); - if (!dsm_dev) { - return -1; - } - - /* Bind the configuration to the device instance */ - dsm_dev->cfg = cfg; - - /* Bind the receiver if requested */ - if (bind) { - PIOS_DSM_Bind(dsm_dev, bind); - } - - PIOS_DSM_ResetState(dsm_dev); - - *dsm_id = (uint32_t)dsm_dev; - - /* Set comm driver callback */ - (driver->bind_rx_cb)(lower_id, PIOS_DSM_RxInCallback, *dsm_id); - - if (!PIOS_RTC_RegisterTickCallback(PIOS_DSM_Supervisor, *dsm_id)) { - PIOS_DEBUG_Assert(0); - } - - return 0; -} - -/* Comm byte received callback */ -static uint16_t PIOS_DSM_RxInCallback(uint32_t context, - uint8_t *buf, - uint16_t buf_len, - uint16_t *headroom, - bool *need_yield) -{ - struct pios_dsm_dev *dsm_dev = (struct pios_dsm_dev *)context; - - bool valid = PIOS_DSM_Validate(dsm_dev); - - PIOS_Assert(valid); - - /* process byte(s) and clear receive timer */ - for (uint8_t i = 0; i < buf_len; i++) { - PIOS_DSM_UpdateState(dsm_dev, buf[i]); - dsm_dev->state.receive_timer = 0; - } - - /* Always signal that we can accept another byte */ - if (headroom) { - *headroom = DSM_FRAME_LENGTH; - } - - /* We never need a yield */ - *need_yield = false; - - /* Always indicate that all bytes were consumed */ - return buf_len; -} - -/** - * Get the value of an input channel - * \param[in] channel Number of the channel desired (zero based) - * \output PIOS_RCVR_INVALID channel not available - * \output PIOS_RCVR_TIMEOUT failsafe condition or missing receiver - * \output >=0 channel value - */ -static int32_t PIOS_DSM_Get(uint32_t rcvr_id, uint8_t channel) -{ - struct pios_dsm_dev *dsm_dev = (struct pios_dsm_dev *)rcvr_id; - - if (!PIOS_DSM_Validate(dsm_dev)) { - return PIOS_RCVR_INVALID; - } - - /* return error if channel is not available */ - if (channel >= PIOS_DSM_NUM_INPUTS) { - return PIOS_RCVR_INVALID; - } - - /* may also be PIOS_RCVR_TIMEOUT set by other function */ - return dsm_dev->state.channel_data[channel]; -} - -/** - * Input data supervisor is called periodically and provides - * two functions: frame syncing and failsafe triggering. - * - * DSM frames come at 11ms or 22ms rate at 115200bps. - * RTC timer is running at 625Hz (1.6ms). So with divider 5 it gives - * 8ms pause between frames which is good for both DSM frame rates. - * - * Data receive function must clear the receive_timer to confirm new - * data reception. If no new data received in 100ms, we must call the - * failsafe function which clears all channels. - */ -static void PIOS_DSM_Supervisor(uint32_t dsm_id) -{ - struct pios_dsm_dev *dsm_dev = (struct pios_dsm_dev *)dsm_id; - - bool valid = PIOS_DSM_Validate(dsm_dev); - - PIOS_Assert(valid); - - struct pios_dsm_state *state = &(dsm_dev->state); - - /* waiting for new frame if no bytes were received in 8ms */ - if (++state->receive_timer > 4) { - state->frame_found = 1; - state->byte_count = 0; - state->receive_timer = 0; - } - - /* activate failsafe if no frames have arrived in 102.4ms */ - if (++state->failsafe_timer > 64) { - PIOS_DSM_ResetChannels(dsm_dev); - state->failsafe_timer = 0; - } -} - -static uint8_t PIOS_DSM_Quality_Get(uint32_t dsm_id) -{ - struct pios_dsm_dev *dsm_dev = (struct pios_dsm_dev *)dsm_id; - - bool valid = PIOS_DSM_Validate(dsm_dev); - - PIOS_Assert(valid); - - struct pios_dsm_state *state = &(dsm_dev->state); - - return (uint8_t)(state->quality + 0.5f); -} - -#endif /* PIOS_INCLUDE_DSM */ - -/** - * @} - * @} - */ diff --git a/flight/pios/stm32f4xx/pios_usart.c b/flight/pios/stm32f4xx/pios_usart.c index e594f55e08..950cbac770 100644 --- a/flight/pios/stm32f4xx/pios_usart.c +++ b/flight/pios/stm32f4xx/pios_usart.c @@ -48,6 +48,7 @@ static void PIOS_USART_RegisterRxCallback(uint32_t usart_id, pios_com_callback r static void PIOS_USART_RegisterTxCallback(uint32_t usart_id, pios_com_callback tx_out_cb, uint32_t context); static void PIOS_USART_TxStart(uint32_t usart_id, uint16_t tx_bytes_avail); static void PIOS_USART_RxStart(uint32_t usart_id, uint16_t rx_bytes_avail); +static int32_t PIOS_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param); const struct pios_com_driver pios_usart_com_driver = { .set_baud = PIOS_USART_ChangeBaud, @@ -58,6 +59,7 @@ const struct pios_com_driver pios_usart_com_driver = { .rx_start = PIOS_USART_RxStart, .bind_tx_cb = PIOS_USART_RegisterTxCallback, .bind_rx_cb = PIOS_USART_RegisterRxCallback, + .ioctl = PIOS_USART_Ioctl, }; enum pios_usart_dev_magic { @@ -72,6 +74,7 @@ struct pios_usart_dev { uint32_t rx_in_context; pios_com_callback tx_out_cb; uint32_t tx_out_context; + uint8_t irq_channel; }; static bool PIOS_USART_validate(struct pios_usart_dev *usart_dev) @@ -79,6 +82,30 @@ static bool PIOS_USART_validate(struct pios_usart_dev *usart_dev) return usart_dev->magic == PIOS_USART_DEV_MAGIC; } +const struct pios_usart_cfg *PIOS_USART_GetConfig(uint32_t usart_id) +{ + struct pios_usart_dev *usart_dev = (struct pios_usart_dev *)usart_id; + + bool valid = PIOS_USART_validate(usart_dev); + + PIOS_Assert(valid); + + return usart_dev->cfg; +} + +static int32_t PIOS_USART_SetIrqPrio(struct pios_usart_dev *usart_dev, uint8_t irq_prio) +{ + NVIC_InitTypeDef init = { + .NVIC_IRQChannel = usart_dev->irq_channel, + .NVIC_IRQChannelPreemptionPriority = irq_prio, + .NVIC_IRQChannelCmd = ENABLE, + }; + + NVIC_Init(&init); + + return 0; +} + #if defined(PIOS_INCLUDE_FREERTOS) static struct pios_usart_dev *PIOS_USART_alloc(void) { @@ -179,10 +206,10 @@ int32_t PIOS_USART_Init(uint32_t *usart_id, const struct pios_usart_cfg *cfg) } /* Bind the configuration to the device instance */ - usart_dev->cfg = cfg; + usart_dev->cfg = cfg; /* Copy the comm parameter structure */ - usart_dev->init = cfg->init; + USART_StructInit(&usart_dev->init); // 9600 8n1 /* Map pins to USART function */ /* note __builtin_ctz() due to the difference between GPIO_PinX and GPIO_PinSourceX */ @@ -214,24 +241,32 @@ int32_t PIOS_USART_Init(uint32_t *usart_id, const struct pios_usart_cfg *cfg) switch ((uint32_t)usart_dev->cfg->regs) { case (uint32_t)USART1: PIOS_USART_1_id = (uint32_t)usart_dev; + usart_dev->irq_channel = USART1_IRQn; break; case (uint32_t)USART2: PIOS_USART_2_id = (uint32_t)usart_dev; + usart_dev->irq_channel = USART2_IRQn; break; +#if !defined(STM32F411xE) case (uint32_t)USART3: PIOS_USART_3_id = (uint32_t)usart_dev; + usart_dev->irq_channel = USART3_IRQn; break; case (uint32_t)UART4: PIOS_USART_4_id = (uint32_t)usart_dev; + usart_dev->irq_channel = UART4_IRQn; break; case (uint32_t)UART5: PIOS_USART_5_id = (uint32_t)usart_dev; + usart_dev->irq_channel = UART5_IRQn; break; +#endif /* STM32F411xE */ case (uint32_t)USART6: PIOS_USART_6_id = (uint32_t)usart_dev; + usart_dev->irq_channel = USART6_IRQn; break; } - NVIC_Init((NVIC_InitTypeDef *)&(usart_dev->cfg->irq.init)); + PIOS_USART_SetIrqPrio(usart_dev, PIOS_IRQ_PRIO_MID); USART_ITConfig(usart_dev->cfg->regs, USART_IT_RXNE, ENABLE); USART_ITConfig(usart_dev->cfg->regs, USART_IT_TXE, ENABLE); @@ -494,6 +529,34 @@ static void PIOS_USART_generic_irq_handler(uint32_t usart_id) #endif /* PIOS_INCLUDE_FREERTOS */ } +static int32_t PIOS_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param) +{ + struct pios_usart_dev *usart_dev = (struct pios_usart_dev *)usart_id; + + bool valid = PIOS_USART_validate(usart_dev); + + PIOS_Assert(valid); + + switch (ctl) { + case PIOS_IOCTL_USART_SET_IRQ_PRIO: + return PIOS_USART_SetIrqPrio(usart_dev, *(uint8_t *)param); + + case PIOS_IOCTL_USART_GET_RXGPIO: + *(struct stm32_gpio *)param = usart_dev->cfg->rx; + break; + case PIOS_IOCTL_USART_GET_TXGPIO: + *(struct stm32_gpio *)param = usart_dev->cfg->tx; + break; + default: + if (usart_dev->cfg->ioctl) { + return usart_dev->cfg->ioctl(usart_id, ctl, param); + } + return -1; + } + + return 0; +} + #endif /* PIOS_INCLUDE_USART */ /** diff --git a/flight/targets/boards/discoveryf4bare/firmware/inc/pios_config.h b/flight/targets/boards/discoveryf4bare/firmware/inc/pios_config.h index 47388c9887..aae41c922d 100644 --- a/flight/targets/boards/discoveryf4bare/firmware/inc/pios_config.h +++ b/flight/targets/boards/discoveryf4bare/firmware/inc/pios_config.h @@ -86,6 +86,7 @@ // #define PIOS_MPU6000_ACCEL /* #define PIOS_INCLUDE_HMC5843 */ #define PIOS_INCLUDE_HMC5X83 +#define PIOS_INCLUDE_HMC5X83_INTERNAL // #define PIOS_HMC5X83_HAS_GPIOS /* #define PIOS_INCLUDE_BMP085 */ // #define PIOS_INCLUDE_MS5611 diff --git a/flight/targets/boards/gpsplatinum/firmware/inc/pios_config.h b/flight/targets/boards/gpsplatinum/firmware/inc/pios_config.h index 5a36646cf1..1b557810cf 100644 --- a/flight/targets/boards/gpsplatinum/firmware/inc/pios_config.h +++ b/flight/targets/boards/gpsplatinum/firmware/inc/pios_config.h @@ -83,6 +83,7 @@ // #define PIOS_MPU6000_ACCEL /* #define PIOS_INCLUDE_HMC5843 */ #define PIOS_INCLUDE_HMC5X83 +#define PIOS_INCLUDE_HMC5X83_INTERNAL // #define PIOS_HMC5X83_HAS_GPIOS /* #define PIOS_INCLUDE_BMP085 */ /* #define PIOS_INCLUDE_MS5611 */ diff --git a/flight/targets/boards/revolution/board_hw_defs.c b/flight/targets/boards/revolution/board_hw_defs.c index 9e33beeb28..7e040bdb91 100644 --- a/flight/targets/boards/revolution/board_hw_defs.c +++ b/flight/targets/boards/revolution/board_hw_defs.c @@ -26,6 +26,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + #if defined(PIOS_INCLUDE_LED) #include @@ -788,31 +789,22 @@ static const struct flashfs_logfs_cfg flashfs_internal_cfg = { #include -#ifdef PIOS_INCLUDE_COM_TELEM - /* * MAIN USART */ + +// Inverter for SBUS handling +#define MAIN_USART_INVERTER_GPIO GPIOC +#define MAIN_USART_INVERTER_PIN GPIO_Pin_0 +#define MAIN_USART_INVERTER_ENABLE Bit_SET +#define MAIN_USART_INVERTER_DISABLE Bit_RESET + +static int32_t PIOS_BOARD_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param); + static const struct pios_usart_cfg pios_usart_main_cfg = { .regs = USART1, .remap = GPIO_AF_USART1, - .init = { - .USART_BaudRate = 57600, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx | USART_Mode_Tx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART1_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { + .rx = { .gpio = GPIOA, .init = { .GPIO_Pin = GPIO_Pin_10, @@ -822,7 +814,7 @@ static const struct pios_usart_cfg pios_usart_main_cfg = { .GPIO_PuPd = GPIO_PuPd_UP }, }, - .tx = { + .tx = { .gpio = GPIOA, .init = { .GPIO_Pin = GPIO_Pin_9, @@ -832,45 +824,29 @@ static const struct pios_usart_cfg pios_usart_main_cfg = { .GPIO_PuPd = GPIO_PuPd_UP }, }, + .ioctl = PIOS_BOARD_USART_Ioctl, }; -#endif /* PIOS_INCLUDE_COM_TELEM */ -#ifdef PIOS_INCLUDE_DSM - -#include "pios_dsm_priv.h" -static const struct pios_usart_cfg pios_usart_dsm_main_cfg = { - .regs = USART1, - .remap = GPIO_AF_USART1, - .init = { - .USART_BaudRate = 115200, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART1_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { - .gpio = GPIOA, +/* + * FLEXI PORT + */ +static const struct pios_usart_cfg pios_usart_flexi_cfg = { + .regs = USART3, + .remap = GPIO_AF_USART3, + .rx = { + .gpio = GPIOB, .init = { - .GPIO_Pin = GPIO_Pin_10, + .GPIO_Pin = GPIO_Pin_11, .GPIO_Speed = GPIO_Speed_2MHz, .GPIO_Mode = GPIO_Mode_AF, .GPIO_OType = GPIO_OType_PP, .GPIO_PuPd = GPIO_PuPd_UP }, }, - .tx = { - .gpio = GPIOA, + .tx = { + .gpio = GPIOB, .init = { - .GPIO_Pin = GPIO_Pin_9, + .GPIO_Pin = GPIO_Pin_10, .GPIO_Speed = GPIO_Speed_2MHz, .GPIO_Mode = GPIO_Mode_AF, .GPIO_OType = GPIO_OType_PP, @@ -879,700 +855,178 @@ static const struct pios_usart_cfg pios_usart_dsm_main_cfg = { }, }; -// Because of the inverter on the main port this will not -// work. Notice the mode is set to IN to maintain API -// compatibility but protect the pins -static const struct pios_dsm_cfg pios_dsm_main_cfg = { - .bind = { - .gpio = GPIOA, +/* FLEXI-IO (Receiver) port */ +static const struct pios_usart_cfg pios_usart_flexiio_cfg = { + .regs = USART6, + .remap = GPIO_AF_USART6, + .dtr = { + // FlexIO pin 9 + .gpio = GPIOC, .init = { - .GPIO_Pin = GPIO_Pin_10, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_IN, + .GPIO_Pin = GPIO_Pin_8, + .GPIO_Speed = GPIO_Speed_25MHz, + .GPIO_Mode = GPIO_Mode_OUT, .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_NOPULL }, }, -}; - -#endif /* PIOS_INCLUDE_DSM */ - -#include -#if defined(PIOS_INCLUDE_SBUS) -/* - * S.Bus USART - */ -#include -static const struct pios_usart_cfg pios_usart_sbus_main_cfg = { - .regs = USART1, - .remap = GPIO_AF_USART1, - .init = { - .USART_BaudRate = 100000, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_Even, - .USART_StopBits = USART_StopBits_2, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART1_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { - .gpio = GPIOA, + .tx = { + // * 7: PC6 = TIM8 CH1, USART6 TX + .gpio = GPIOC, .init = { - .GPIO_Pin = GPIO_Pin_10, + .GPIO_Pin = GPIO_Pin_6, .GPIO_Speed = GPIO_Speed_2MHz, .GPIO_Mode = GPIO_Mode_AF, .GPIO_OType = GPIO_OType_PP, .GPIO_PuPd = GPIO_PuPd_UP }, + .pin_source = GPIO_PinSource6, }, - .tx = { - .gpio = GPIOA, - .init = { - .GPIO_Pin = GPIO_Pin_9, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_OUT, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_NOPULL - }, - }, -}; - -#endif /* PIOS_INCLUDE_SBUS */ -// Need this defined regardless to be able to turn it off -static const struct pios_sbus_cfg pios_sbus_cfg = { - /* Inverter configuration */ - .inv = { + .rx = { + // * 8: PC7 = TIM8 CH2, USART6 RX .gpio = GPIOC, .init = { - .GPIO_Pin = GPIO_Pin_0, + .GPIO_Pin = GPIO_Pin_7, .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_OUT, + .GPIO_Mode = GPIO_Mode_AF, .GPIO_OType = GPIO_OType_PP, .GPIO_PuPd = GPIO_PuPd_UP }, - }, - .gpio_inv_enable = Bit_SET, - .gpio_inv_disable = Bit_RESET, - .gpio_clk_func = RCC_AHB1PeriphClockCmd, - .gpio_clk_periph = RCC_AHB1Periph_GPIOC, + .pin_source = GPIO_PinSource7, + } }; -#ifdef PIOS_INCLUDE_COM_FLEXI +#if defined(PIOS_INCLUDE_COM) + +#include + +#endif /* PIOS_INCLUDE_COM */ + +#if defined(PIOS_INCLUDE_I2C) + +#include + /* - * FLEXI PORT + * I2C Adapters */ -static const struct pios_usart_cfg pios_usart_flexi_cfg = { - .regs = USART3, - .remap = GPIO_AF_USART3, - .init = { - .USART_BaudRate = 57600, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = - USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx | USART_Mode_Tx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART3_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, +void PIOS_I2C_mag_pressure_adapter_ev_irq_handler(void); +void PIOS_I2C_mag_pressureadapter_er_irq_handler(void); +void I2C1_EV_IRQHandler() +__attribute__((alias("PIOS_I2C_mag_pressure_adapter_ev_irq_handler"))); +void I2C1_ER_IRQHandler() +__attribute__((alias("PIOS_I2C_mag_pressure_adapter_er_irq_handler"))); + +static const struct pios_i2c_adapter_cfg pios_i2c_mag_pressure_adapter_cfg = { + .regs = I2C1, + .remapSCL = GPIO_AF_I2C1, + .remapSDA = GPIO_AF_I2C1, + .init = { + .I2C_Mode = I2C_Mode_I2C, + .I2C_OwnAddress1 = 0, + .I2C_Ack = I2C_Ack_Enable, + .I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit, + .I2C_DutyCycle = I2C_DutyCycle_2, + .I2C_ClockSpeed = 400000, /* bits/s */ }, - .rx = { + .transfer_timeout_ms = 50, + .scl = { .gpio = GPIOB, .init = { - .GPIO_Pin = GPIO_Pin_11, - .GPIO_Speed = GPIO_Speed_2MHz, + .GPIO_Pin = GPIO_Pin_8, .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP + .GPIO_Speed = GPIO_Speed_50MHz, + .GPIO_OType = GPIO_OType_OD, + .GPIO_PuPd = GPIO_PuPd_NOPULL, }, }, - .tx = { + .sda = { .gpio = GPIOB, .init = { - .GPIO_Pin = GPIO_Pin_10, - .GPIO_Speed = GPIO_Speed_2MHz, + .GPIO_Pin = GPIO_Pin_9, .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP + .GPIO_Speed = GPIO_Speed_50MHz, + .GPIO_OType = GPIO_OType_OD, + .GPIO_PuPd = GPIO_PuPd_NOPULL, }, }, -}; - -#endif /* PIOS_INCLUDE_COM_FLEXI */ - -#ifdef PIOS_INCLUDE_DSM - -#include "pios_dsm_priv.h" -static const struct pios_usart_cfg pios_usart_dsm_flexi_cfg = { - .regs = USART3, - .remap = GPIO_AF_USART3, - .init = { - .USART_BaudRate = 115200, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART3_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, + .event = { + .flags = 0, /* FIXME: check this */ + .init = { + .NVIC_IRQChannel = I2C1_EV_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGHEST, .NVIC_IRQChannelSubPriority = 0, .NVIC_IRQChannelCmd = ENABLE, }, }, - .rx = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_11, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP + .error = { + .flags = 0, /* FIXME: check this */ + .init = { + .NVIC_IRQChannel = I2C1_ER_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGHEST, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, }, }, - .tx = { +}; + +uint32_t pios_i2c_mag_pressure_adapter_id; +void PIOS_I2C_mag_pressure_adapter_ev_irq_handler(void) +{ + /* Call into the generic code to handle the IRQ for this specific device */ + PIOS_I2C_EV_IRQ_Handler(pios_i2c_mag_pressure_adapter_id); +} + +void PIOS_I2C_mag_pressure_adapter_er_irq_handler(void) +{ + /* Call into the generic code to handle the IRQ for this specific device */ + PIOS_I2C_ER_IRQ_Handler(pios_i2c_mag_pressure_adapter_id); +} + + +void PIOS_I2C_flexiport_adapter_ev_irq_handler(void); +void PIOS_I2C_flexiport_adapter_er_irq_handler(void); +void I2C2_EV_IRQHandler() __attribute__((alias("PIOS_I2C_flexiport_adapter_ev_irq_handler"))); +void I2C2_ER_IRQHandler() __attribute__((alias("PIOS_I2C_flexiport_adapter_er_irq_handler"))); + +static const struct pios_i2c_adapter_cfg pios_i2c_flexiport_adapter_cfg = { + .regs = I2C2, + .remapSCL = GPIO_AF_I2C2, + .remapSDA = GPIO_AF_I2C2, + .init = { + .I2C_Mode = I2C_Mode_I2C, + .I2C_OwnAddress1 = 0, + .I2C_Ack = I2C_Ack_Enable, + .I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit, + .I2C_DutyCycle = I2C_DutyCycle_2, + .I2C_ClockSpeed = 400000, /* bits/s */ + }, + .transfer_timeout_ms = 50, + .scl = { .gpio = GPIOB, .init = { .GPIO_Pin = GPIO_Pin_10, - .GPIO_Speed = GPIO_Speed_2MHz, .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP + .GPIO_Speed = GPIO_Speed_50MHz, + .GPIO_OType = GPIO_OType_OD, + .GPIO_PuPd = GPIO_PuPd_UP, }, }, -}; - -static const struct pios_dsm_cfg pios_dsm_flexi_cfg = { - .bind = { + .sda = { .gpio = GPIOB, .init = { .GPIO_Pin = GPIO_Pin_11, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_OUT, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_NOPULL + .GPIO_Mode = GPIO_Mode_AF, + .GPIO_Speed = GPIO_Speed_50MHz, + .GPIO_OType = GPIO_OType_OD, + .GPIO_PuPd = GPIO_PuPd_UP, }, }, -}; - -#endif /* PIOS_INCLUDE_DSM */ - -#if defined(PIOS_INCLUDE_SRXL) -/* - * SRXL USART - */ -#include - -static const struct pios_usart_cfg pios_usart_srxl_flexi_cfg = { - .regs = USART3, - .remap = GPIO_AF_USART3, - .init = { - .USART_BaudRate = 115200, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART3_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_11, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, - .tx = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_10, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_OUT, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, -}; - -#endif /* PIOS_INCLUDE_SRXL */ - -#if defined(PIOS_INCLUDE_HOTT) -/* - * HOTT USART - */ -#include - -static const struct pios_usart_cfg pios_usart_hott_flexi_cfg = { - .regs = USART3, - .remap = GPIO_AF_USART3, - .init = { - .USART_BaudRate = 115200, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART3_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_11, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, - .tx = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_10, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_OUT, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, -}; - -#endif /* PIOS_INCLUDE_HOTT */ - -#if defined(PIOS_INCLUDE_IBUS) -/* - * IBUS USART - */ -#include - -static const struct pios_usart_cfg pios_usart_ibus_flexi_cfg = { - .regs = USART3, - .remap = GPIO_AF_USART3, - .init = { - .USART_BaudRate = 115200, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART3_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_11, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, - .tx = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_10, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_OUT, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, -}; - -static const struct pios_usart_cfg pios_usart_ibus_rcvr_cfg = { - .regs = USART6, - .remap = GPIO_AF_USART6, - .init = { - .USART_BaudRate = 115200, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART6_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { - .gpio = GPIOC, - .init = { - .GPIO_Pin = GPIO_Pin_7, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, -}; - -#endif /* PIOS_INCLUDE_IBUS */ - -#if defined(PIOS_INCLUDE_EXBUS) -/* - * EXBUS USART - */ -#include - -static const struct pios_usart_cfg pios_usart_exbus_flexi_cfg = { - .regs = USART3, - .remap = GPIO_AF_USART3, - .init = { - .USART_BaudRate = 125000, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART3_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_11, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, - .tx = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_10, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_OUT, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, -}; - -#endif /* PIOS_INCLUDE_EXBUS */ - -/* - * HK OSD - */ -static const struct pios_usart_cfg pios_usart_hkosd_main_cfg = { - .regs = USART1, - .remap = GPIO_AF_USART1, - .init = { - .USART_BaudRate = 57600, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx | USART_Mode_Tx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART1_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { - .gpio = GPIOA, - .init = { - .GPIO_Pin = GPIO_Pin_10, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, - .tx = { - .gpio = GPIOA, - .init = { - .GPIO_Pin = GPIO_Pin_9, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, -}; - -static const struct pios_usart_cfg pios_usart_hkosd_flexi_cfg = { - .regs = USART3, - .remap = GPIO_AF_USART3, - .init = { - .USART_BaudRate = 57600, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx | USART_Mode_Tx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART3_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_11, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, - .tx = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_10, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, -}; - -static const struct pios_usart_cfg pios_usart_rcvrport_cfg = { - .regs = USART6, - .remap = GPIO_AF_USART6, - .init = { - .USART_BaudRate = 57600, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx | USART_Mode_Tx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART6_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - - .dtr = { - // FlexIO pin 9 - .gpio = GPIOC, - .init = { - .GPIO_Pin = GPIO_Pin_8, - .GPIO_Speed = GPIO_Speed_25MHz, - .GPIO_Mode = GPIO_Mode_OUT, - .GPIO_OType = GPIO_OType_PP, - }, - }, - - .tx = { - // * 7: PC6 = TIM8 CH1, USART6 TX - .gpio = GPIOC, - .init = { - .GPIO_Pin = GPIO_Pin_6, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - .pin_source = GPIO_PinSource6, - }, - - .rx = { - // * 8: PC7 = TIM8 CH2, USART6 RX - .gpio = GPIOC, - .init = { - .GPIO_Pin = GPIO_Pin_7, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - .pin_source = GPIO_PinSource7, - } -}; - -#if defined(PIOS_INCLUDE_COM) - -#include - -#endif /* PIOS_INCLUDE_COM */ - -#if defined(PIOS_INCLUDE_I2C) - -#include - -/* - * I2C Adapters - */ -void PIOS_I2C_mag_pressure_adapter_ev_irq_handler(void); -void PIOS_I2C_mag_pressureadapter_er_irq_handler(void); -void I2C1_EV_IRQHandler() -__attribute__((alias("PIOS_I2C_mag_pressure_adapter_ev_irq_handler"))); -void I2C1_ER_IRQHandler() -__attribute__((alias("PIOS_I2C_mag_pressure_adapter_er_irq_handler"))); - -static const struct pios_i2c_adapter_cfg pios_i2c_mag_pressure_adapter_cfg = { - .regs = I2C1, - .remapSCL = GPIO_AF_I2C1, - .remapSDA = GPIO_AF_I2C1, - .init = { - .I2C_Mode = I2C_Mode_I2C, - .I2C_OwnAddress1 = 0, - .I2C_Ack = I2C_Ack_Enable, - .I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit, - .I2C_DutyCycle = I2C_DutyCycle_2, - .I2C_ClockSpeed = 400000, /* bits/s */ - }, - .transfer_timeout_ms = 50, - .scl = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_8, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_Speed = GPIO_Speed_50MHz, - .GPIO_OType = GPIO_OType_OD, - .GPIO_PuPd = GPIO_PuPd_NOPULL, - }, - }, - .sda = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_9, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_Speed = GPIO_Speed_50MHz, - .GPIO_OType = GPIO_OType_OD, - .GPIO_PuPd = GPIO_PuPd_NOPULL, - }, - }, - .event = { - .flags = 0, /* FIXME: check this */ - .init = { - .NVIC_IRQChannel = I2C1_EV_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGHEST, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .error = { - .flags = 0, /* FIXME: check this */ - .init = { - .NVIC_IRQChannel = I2C1_ER_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGHEST, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, -}; - -uint32_t pios_i2c_mag_pressure_adapter_id; -void PIOS_I2C_mag_pressure_adapter_ev_irq_handler(void) -{ - /* Call into the generic code to handle the IRQ for this specific device */ - PIOS_I2C_EV_IRQ_Handler(pios_i2c_mag_pressure_adapter_id); -} - -void PIOS_I2C_mag_pressure_adapter_er_irq_handler(void) -{ - /* Call into the generic code to handle the IRQ for this specific device */ - PIOS_I2C_ER_IRQ_Handler(pios_i2c_mag_pressure_adapter_id); -} - - -void PIOS_I2C_flexiport_adapter_ev_irq_handler(void); -void PIOS_I2C_flexiport_adapter_er_irq_handler(void); -void I2C2_EV_IRQHandler() __attribute__((alias("PIOS_I2C_flexiport_adapter_ev_irq_handler"))); -void I2C2_ER_IRQHandler() __attribute__((alias("PIOS_I2C_flexiport_adapter_er_irq_handler"))); - -static const struct pios_i2c_adapter_cfg pios_i2c_flexiport_adapter_cfg = { - .regs = I2C2, - .remapSCL = GPIO_AF_I2C2, - .remapSDA = GPIO_AF_I2C2, - .init = { - .I2C_Mode = I2C_Mode_I2C, - .I2C_OwnAddress1 = 0, - .I2C_Ack = I2C_Ack_Enable, - .I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit, - .I2C_DutyCycle = I2C_DutyCycle_2, - .I2C_ClockSpeed = 400000, /* bits/s */ - }, - .transfer_timeout_ms = 50, - .scl = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_10, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_Speed = GPIO_Speed_50MHz, - .GPIO_OType = GPIO_OType_OD, - .GPIO_PuPd = GPIO_PuPd_UP, - }, - }, - .sda = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_11, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_Speed = GPIO_Speed_50MHz, - .GPIO_OType = GPIO_OType_OD, - .GPIO_PuPd = GPIO_PuPd_UP, - }, - }, - .event = { - .flags = 0, /* FIXME: check this */ - .init = { - .NVIC_IRQChannel = I2C2_EV_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGHEST, + .event = { + .flags = 0, /* FIXME: check this */ + .init = { + .NVIC_IRQChannel = I2C2_EV_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGHEST, .NVIC_IRQChannelSubPriority = 0, .NVIC_IRQChannelCmd = ENABLE, }, @@ -1797,212 +1251,24 @@ static const struct pios_tim_clock_cfg tim_12_cfg = { * Using TIM3, TIM9, TIM2, TIM5 */ #include +#include + static const struct pios_tim_channel pios_tim_servoport_all_pins[] = { - { - .timer = TIM3, - .timer_chan = TIM_Channel_3, - .pin = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_0, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - .pin_source = GPIO_PinSource0, - }, - .remap = GPIO_AF_TIM3, - }, - { - .timer = TIM3, - .timer_chan = TIM_Channel_4, - .pin = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_1, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - .pin_source = GPIO_PinSource1, - }, - .remap = GPIO_AF_TIM3, - }, - { - .timer = TIM9, - .timer_chan = TIM_Channel_2, - .pin = { - .gpio = GPIOA, - .init = { - .GPIO_Pin = GPIO_Pin_3, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - .pin_source = GPIO_PinSource3, - }, - .remap = GPIO_AF_TIM9, - }, - { - .timer = TIM2, - .timer_chan = TIM_Channel_3, - .pin = { - .gpio = GPIOA, - .init = { - .GPIO_Pin = GPIO_Pin_2, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - .pin_source = GPIO_PinSource2, - }, - .remap = GPIO_AF_TIM2, - }, - { - .timer = TIM5, - .timer_chan = TIM_Channel_2, - .pin = { - .gpio = GPIOA, - .init = { - .GPIO_Pin = GPIO_Pin_1, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - .pin_source = GPIO_PinSource1, - }, - .remap = GPIO_AF_TIM5, - }, - { - .timer = TIM5, - .timer_chan = TIM_Channel_1, - .pin = { - .gpio = GPIOA, - .init = { - .GPIO_Pin = GPIO_Pin_0, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - .pin_source = GPIO_PinSource0, - }, - .remap = GPIO_AF_TIM5, - }, + TIM_SERVO_CHANNEL_CONFIG(TIM3, 3, B, 0), + TIM_SERVO_CHANNEL_CONFIG(TIM3, 4, B, 1), + TIM_SERVO_CHANNEL_CONFIG(TIM9, 2, A, 3), + TIM_SERVO_CHANNEL_CONFIG(TIM2, 3, A, 2), + TIM_SERVO_CHANNEL_CONFIG(TIM5, 2, A, 1), + TIM_SERVO_CHANNEL_CONFIG(TIM5, 1, A, 0), // PWM pins on FlexiIO(receiver) port - { - // * 6: PB15 = SPI2 MOSI, TIM12 CH2 - - .timer = TIM12, - .timer_chan = TIM_Channel_2, - .pin = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_15, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - .pin_source = GPIO_PinSource15, - }, - .remap = GPIO_AF_TIM12, - }, - { - // * 7: PC6 = TIM8 CH1, USART6 TX - .timer = TIM8, - .timer_chan = TIM_Channel_1, - .pin = { - .gpio = GPIOC, - .init = { - .GPIO_Pin = GPIO_Pin_6, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - .pin_source = GPIO_PinSource6, - }, - .remap = GPIO_AF_TIM8, - }, - - { - // * 8: PC7 = TIM8 CH2, USART6 RX - .timer = TIM8, - .timer_chan = TIM_Channel_2, - .pin = { - .gpio = GPIOC, - .init = { - .GPIO_Pin = GPIO_Pin_7, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - .pin_source = GPIO_PinSource7, - }, - .remap = GPIO_AF_TIM8, - }, - - { - // * 9: PC8 = TIM8 CH3 - .timer = TIM8, - .timer_chan = TIM_Channel_3, - .pin = { - .gpio = GPIOC, - .init = { - .GPIO_Pin = GPIO_Pin_8, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - .pin_source = GPIO_PinSource8, - }, - .remap = GPIO_AF_TIM8, - }, - - { - // * 10: PC9 = TIM8 CH4 - .timer = TIM8, - .timer_chan = TIM_Channel_4, - .pin = { - .gpio = GPIOC, - .init = { - .GPIO_Pin = GPIO_Pin_9, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - .pin_source = GPIO_PinSource9, - }, - .remap = GPIO_AF_TIM8, - }, - - { - // * 5: PB14 = SPI2 MISO, TIM12 CH1, USART3 RTS - .timer = TIM12, - .timer_chan = TIM_Channel_1, - .pin = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_14, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - .pin_source = GPIO_PinSource14, - }, - .remap = GPIO_AF_TIM12, - }, + TIM_SERVO_CHANNEL_CONFIG(TIM12, 2, B, 15), // * 6: PB15 = SPI2 MOSI, TIM12 CH2 + TIM_SERVO_CHANNEL_CONFIG(TIM8, 1, C, 6), // * 7: PC6 = TIM8 CH1, USART6 TX + TIM_SERVO_CHANNEL_CONFIG(TIM8, 2, C, 7), // * 8: PC7 = TIM8 CH2, USART6 RX + TIM_SERVO_CHANNEL_CONFIG(TIM8, 3, C, 8), // * 9: PC8 = TIM8 CH3 + TIM_SERVO_CHANNEL_CONFIG(TIM8, 4, C, 9), // * 10: PC9 = TIM8 CH4 + TIM_SERVO_CHANNEL_CONFIG(TIM12, 1, B, 14), // * 5: PB14 = SPI2 MISO, TIM12 CH1, USART3 RTS }; + #define PIOS_SERVOPORT_ALL_PINS_PWMOUT 6 #define PIOS_SERVOPORT_ALL_PINS_PWMOUT_IN_PPM 11 #define PIOS_SERVOPORT_ALL_PINS_PWMOUT_IN 12 @@ -2060,102 +1326,12 @@ const struct pios_servo_cfg pios_servo_cfg_out_in = { #if defined(PIOS_INCLUDE_PWM) || defined(PIOS_INCLUDE_PPM) #include static const struct pios_tim_channel pios_tim_rcvrport_all_channels[] = { - { - .timer = TIM12, - .timer_chan = TIM_Channel_1, - .pin = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_14, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - .pin_source = GPIO_PinSource14, - }, - .remap = GPIO_AF_TIM12, - }, - { - .timer = TIM12, - .timer_chan = TIM_Channel_2, - .pin = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_15, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - .pin_source = GPIO_PinSource15, - }, - .remap = GPIO_AF_TIM12, - }, - { - .timer = TIM8, - .timer_chan = TIM_Channel_1, - .pin = { - .gpio = GPIOC, - .init = { - .GPIO_Pin = GPIO_Pin_6, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - .pin_source = GPIO_PinSource6, - }, - .remap = GPIO_AF_TIM8, - }, - { - .timer = TIM8, - .timer_chan = TIM_Channel_2, - .pin = { - .gpio = GPIOC, - .init = { - .GPIO_Pin = GPIO_Pin_7, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - .pin_source = GPIO_PinSource7, - }, - .remap = GPIO_AF_TIM8, - }, - { - .timer = TIM8, - .timer_chan = TIM_Channel_3, - .pin = { - .gpio = GPIOC, - .init = { - .GPIO_Pin = GPIO_Pin_8, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - .pin_source = GPIO_PinSource8, - }, - .remap = GPIO_AF_TIM8, - }, - { - .timer = TIM8, - .timer_chan = TIM_Channel_4, - .pin = { - .gpio = GPIOC, - .init = { - .GPIO_Pin = GPIO_Pin_9, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - .pin_source = GPIO_PinSource9, - }, - .remap = GPIO_AF_TIM8, - }, + TIM_SERVO_CHANNEL_CONFIG(TIM12, 1, B, 14), + TIM_SERVO_CHANNEL_CONFIG(TIM12, 2, B, 15), + TIM_SERVO_CHANNEL_CONFIG(TIM8, 1, C, 6), + TIM_SERVO_CHANNEL_CONFIG(TIM8, 2, C, 7), + TIM_SERVO_CHANNEL_CONFIG(TIM8, 3, C, 8), + TIM_SERVO_CHANNEL_CONFIG(TIM8, 4, C, 9), }; const struct pios_pwm_cfg pios_pwm_cfg = { @@ -2285,37 +1461,6 @@ const struct pios_usb_cfg *PIOS_BOARD_HW_DEFS_GetUsbCfg(uint32_t board_revision) #endif /* PIOS_INCLUDE_COM_MSG */ -#if defined(PIOS_INCLUDE_USB_HID) && !defined(PIOS_INCLUDE_USB_CDC) -#include - -const struct pios_usb_hid_cfg pios_usb_hid_cfg = { - .data_if = 0, - .data_rx_ep = 1, - .data_tx_ep = 1, -}; -#endif /* PIOS_INCLUDE_USB_HID && !PIOS_INCLUDE_USB_CDC */ - -#if defined(PIOS_INCLUDE_USB_HID) && defined(PIOS_INCLUDE_USB_CDC) -#include - -const struct pios_usb_cdc_cfg pios_usb_cdc_cfg = { - .ctrl_if = 0, - .ctrl_tx_ep = 2, - - .data_if = 1, - .data_rx_ep = 3, - .data_tx_ep = 3, -}; - -#include - -const struct pios_usb_hid_cfg pios_usb_hid_cfg = { - .data_if = 2, - .data_rx_ep = 1, - .data_tx_ep = 1, -}; -#endif /* PIOS_INCLUDE_USB_HID && PIOS_INCLUDE_USB_CDC */ - #ifdef PIOS_INCLUDE_WS2811 #include #include @@ -2450,3 +1595,198 @@ void PIOS_WS2811_irq_handler(void) PIOS_WS2811_DMA_irq_handler(); } #endif // PIOS_INCLUDE_WS2811 + +/** + * Sensor configurations + */ +#if defined(PIOS_INCLUDE_ADC) +#include "pios_adc_priv.h" +void PIOS_ADC_DMC_irq_handler(void); +void DMA2_Stream4_IRQHandler(void) __attribute__((alias("PIOS_ADC_DMC_irq_handler"))); + +struct pios_adc_cfg pios_adc_cfg = { + .adc_dev = ADC1, + .dma = { + .irq = { + .flags = (DMA_FLAG_TCIF4 | DMA_FLAG_TEIF4 | DMA_FLAG_HTIF4), + .init = { + .NVIC_IRQChannel = DMA2_Stream4_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_LOW, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, + .rx = { + .channel = DMA2_Stream4, + .init = { + .DMA_Channel = DMA_Channel_0, + .DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR + }, + } + }, + .half_flag = DMA_IT_HTIF4, + .full_flag = DMA_IT_TCIF4, +}; + +void PIOS_ADC_DMC_irq_handler(void) +{ + /* Call into the generic code to handle the IRQ for this specific device */ + PIOS_ADC_DMA_Handler(); +} + +const struct pios_adc_cfg *PIOS_BOARD_HW_DEFS_GetAdcCfg(__attribute__((unused)) uint32_t board_revision) +{ + return &pios_adc_cfg; +} +#endif /* if defined(PIOS_INCLUDE_ADC) */ + +#if defined(PIOS_INCLUDE_HMC5X83) +#include "pios_hmc5x83.h" + +#ifdef PIOS_HMC5X83_HAS_GPIOS +bool pios_board_internal_mag_handler() +{ + return PIOS_HMC5x83_IRQHandler(pios_hmc5x83_internal_id); +} + +static const struct pios_exti_cfg pios_exti_hmc5x83_cfg __exti_config = { + .vector = pios_board_internal_mag_handler, + .line = EXTI_Line7, + .pin = { + .gpio = GPIOB, + .init = { + .GPIO_Pin = GPIO_Pin_7, + .GPIO_Speed = GPIO_Speed_100MHz, + .GPIO_Mode = GPIO_Mode_IN, + .GPIO_OType = GPIO_OType_OD, + .GPIO_PuPd = GPIO_PuPd_NOPULL, + }, + }, + .irq = { + .init = { + .NVIC_IRQChannel = EXTI9_5_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_LOW, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, + .exti = { + .init = { + .EXTI_Line = EXTI_Line7, // matches above GPIO pin + .EXTI_Mode = EXTI_Mode_Interrupt, + .EXTI_Trigger = EXTI_Trigger_Rising, + .EXTI_LineCmd = ENABLE, + }, + }, +}; +#endif /* PIOS_HMC5X83_HAS_GPIOS */ + +static const struct pios_hmc5x83_cfg pios_hmc5x83_internal_cfg = { +#ifdef PIOS_HMC5X83_HAS_GPIOS + .exti_cfg = &pios_exti_hmc5x83_cfg, +#endif + .M_ODR = PIOS_HMC5x83_ODR_75, + .Meas_Conf = PIOS_HMC5x83_MEASCONF_NORMAL, + .Gain = PIOS_HMC5x83_GAIN_1_9, + .Mode = PIOS_HMC5x83_MODE_CONTINUOUS, + .TempCompensation = false, + .Driver = &PIOS_HMC5x83_I2C_DRIVER, + .Orientation = PIOS_HMC5X83_ORIENTATION_EAST_NORTH_UP, +}; + +const struct pios_hmc5x83_cfg *PIOS_BOARD_HW_DEFS_GetInternalHMC5x83Cfg(__attribute__((unused)) uint32_t board_revision) +{ + return &pios_hmc5x83_internal_cfg; +} + +static const struct pios_hmc5x83_cfg pios_hmc5x83_external_cfg = { +#ifdef PIOS_HMC5X83_HAS_GPIOS + .exti_cfg = NULL, +#endif + .M_ODR = PIOS_HMC5x83_ODR_75, // if you change this for auxmag, change AUX_MAG_SKIP in sensors.c + .Meas_Conf = PIOS_HMC5x83_MEASCONF_NORMAL, + .Gain = PIOS_HMC5x83_GAIN_1_9, + .Mode = PIOS_HMC5x83_MODE_CONTINUOUS, + .TempCompensation = false, + .Driver = &PIOS_HMC5x83_I2C_DRIVER, + .Orientation = PIOS_HMC5X83_ORIENTATION_EAST_NORTH_UP, // ENU for GPSV9, WND for typical I2C mag +}; + +const struct pios_hmc5x83_cfg *PIOS_BOARD_HW_DEFS_GetExternalHMC5x83Cfg(__attribute__((unused)) uint32_t board_revision) +{ + return &pios_hmc5x83_external_cfg; +} +#endif /* PIOS_INCLUDE_HMC5X83 */ + +/** + * Configuration for the MS5611 chip + */ +#if defined(PIOS_INCLUDE_MS5611) +#include "pios_ms5611.h" +static const struct pios_ms5611_cfg pios_ms5611_cfg = { + .oversampling = MS5611_OSR_4096, +}; +const struct pios_ms5611_cfg *PIOS_BOARD_HW_DEFS_GetMS5611Cfg(__attribute__((unused)) uint32_t board_revision) +{ + return &pios_ms5611_cfg; +} +#endif /* PIOS_INCLUDE_MS5611 */ + + +/** + * Configuration for the MPU6000 chip + */ +#if defined(PIOS_INCLUDE_MPU6000) +#include "pios_mpu6000.h" +#include "pios_mpu6000_config.h" +static const struct pios_exti_cfg pios_exti_mpu6000_cfg __exti_config = { + .vector = PIOS_MPU6000_IRQHandler, + .line = EXTI_Line4, + .pin = { + .gpio = GPIOC, + .init = { + .GPIO_Pin = GPIO_Pin_4, + .GPIO_Speed = GPIO_Speed_100MHz, + .GPIO_Mode = GPIO_Mode_IN, + .GPIO_OType = GPIO_OType_OD, + .GPIO_PuPd = GPIO_PuPd_NOPULL, + }, + }, + .irq = { + .init = { + .NVIC_IRQChannel = EXTI4_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, + .exti = { + .init = { + .EXTI_Line = EXTI_Line4, // matches above GPIO pin + .EXTI_Mode = EXTI_Mode_Interrupt, + .EXTI_Trigger = EXTI_Trigger_Rising, + .EXTI_LineCmd = ENABLE, + }, + }, +}; + +static const struct pios_mpu6000_cfg pios_mpu6000_cfg = { + .exti_cfg = &pios_exti_mpu6000_cfg, + .Fifo_store = PIOS_MPU6000_FIFO_TEMP_OUT | PIOS_MPU6000_FIFO_GYRO_X_OUT | PIOS_MPU6000_FIFO_GYRO_Y_OUT | PIOS_MPU6000_FIFO_GYRO_Z_OUT, + // Clock at 8 khz + .Smpl_rate_div_no_dlp = 0, + // with dlp on output rate is 1000Hz + .Smpl_rate_div_dlp = 0, + .interrupt_cfg = PIOS_MPU6000_INT_CLR_ANYRD, + .interrupt_en = PIOS_MPU6000_INTEN_DATA_RDY, + .User_ctl = PIOS_MPU6000_USERCTL_DIS_I2C, + .Pwr_mgmt_clk = PIOS_MPU6000_PWRMGMT_PLL_X_CLK, + .accel_range = PIOS_MPU6000_ACCEL_8G, + .gyro_range = PIOS_MPU6000_SCALE_2000_DEG, + .filter = PIOS_MPU6000_LOWPASS_256_HZ, + .orientation = PIOS_MPU6000_TOP_180DEG, + .fast_prescaler = PIOS_SPI_PRESCALER_4, + .std_prescaler = PIOS_SPI_PRESCALER_64, + .max_downsample = 20, +}; +#endif /* PIOS_INCLUDE_MPU6000 */ diff --git a/flight/targets/boards/revolution/bootloader/pios_board.c b/flight/targets/boards/revolution/bootloader/pios_board.c index 5352c7f73b..e0065e2a9c 100644 --- a/flight/targets/boards/revolution/bootloader/pios_board.c +++ b/flight/targets/boards/revolution/bootloader/pios_board.c @@ -25,6 +25,7 @@ #include #include +#include /* * Pull in the board-specific static HW definitions. @@ -39,6 +40,13 @@ uint32_t pios_com_telem_usb_id; static bool board_init_complete = false; + +static int32_t PIOS_BOARD_USART_Ioctl(__attribute__((unused)) uint32_t usart_id, __attribute__((unused)) uint32_t ctl, __attribute__((unused)) void *param) +{ + return -1; +} + + void PIOS_Board_Init() { if (board_init_complete) { @@ -68,7 +76,7 @@ void PIOS_Board_Init() #if defined(PIOS_INCLUDE_USB_HID) && defined(PIOS_INCLUDE_COM_MSG) uint32_t pios_usb_hid_id; - if (PIOS_USB_HID_Init(&pios_usb_hid_id, &pios_usb_hid_cfg, pios_usb_id)) { + if (PIOS_USB_HID_Init(&pios_usb_hid_id, &pios_usb_hid_only_cfg, pios_usb_id)) { PIOS_Assert(0); } if (PIOS_COM_MSG_Init(&pios_com_telem_usb_id, &pios_usb_hid_com_driver, pios_usb_hid_id)) { diff --git a/flight/targets/boards/revolution/firmware/inc/pios_config.h b/flight/targets/boards/revolution/firmware/inc/pios_config.h index c50d8c5981..ead7372078 100644 --- a/flight/targets/boards/revolution/firmware/inc/pios_config.h +++ b/flight/targets/boards/revolution/firmware/inc/pios_config.h @@ -86,6 +86,7 @@ #define PIOS_MPU6000_ACCEL /* #define PIOS_INCLUDE_HMC5843 */ #define PIOS_INCLUDE_HMC5X83 +#define PIOS_INCLUDE_HMC5X83_INTERNAL #define PIOS_HMC5X83_HAS_GPIOS /* #define PIOS_INCLUDE_BMP085 */ #define PIOS_INCLUDE_MS5611 diff --git a/flight/targets/boards/revolution/firmware/pios_board.c b/flight/targets/boards/revolution/firmware/pios_board.c index 9795c9e97c..cc1f93ddf2 100644 --- a/flight/targets/boards/revolution/firmware/pios_board.c +++ b/flight/targets/boards/revolution/firmware/pios_board.c @@ -30,21 +30,15 @@ #include #include #include -#include -#include -#include -#include -#include -#include -#include #include #include -#include #ifdef PIOS_INCLUDE_INSTRUMENTATION #include #endif +#include + /* * Pull in the board-specific static HW definitions. * Including .c files is a bit ugly but this allows all of @@ -55,344 +49,72 @@ */ #include "../board_hw_defs.c" -/** - * Sensor configurations - */ -#if defined(PIOS_INCLUDE_ADC) -#include "pios_adc_priv.h" -void PIOS_ADC_DMC_irq_handler(void); -void DMA2_Stream4_IRQHandler(void) __attribute__((alias("PIOS_ADC_DMC_irq_handler"))); - -struct pios_adc_cfg pios_adc_cfg = { - .adc_dev = ADC1, - .dma = { - .irq = { - .flags = (DMA_FLAG_TCIF4 | DMA_FLAG_TEIF4 | DMA_FLAG_HTIF4), - .init = { - .NVIC_IRQChannel = DMA2_Stream4_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_LOW, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { - .channel = DMA2_Stream4, - .init = { - .DMA_Channel = DMA_Channel_0, - .DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR - }, - } - }, - .half_flag = DMA_IT_HTIF4, - .full_flag = DMA_IT_TCIF4, -}; - -void PIOS_ADC_DMC_irq_handler(void) -{ - /* Call into the generic code to handle the IRQ for this specific device */ - PIOS_ADC_DMA_Handler(); -} -#endif /* if defined(PIOS_INCLUDE_ADC) */ - -#if defined(PIOS_INCLUDE_HMC5X83) -#include "pios_hmc5x83.h" -pios_hmc5x83_dev_t onboard_mag = 0; -pios_hmc5x83_dev_t external_mag = 0; - -#ifdef PIOS_HMC5X83_HAS_GPIOS -bool pios_board_internal_mag_handler() -{ - return PIOS_HMC5x83_IRQHandler(onboard_mag); -} - -static const struct pios_exti_cfg pios_exti_hmc5x83_cfg __exti_config = { - .vector = pios_board_internal_mag_handler, - .line = EXTI_Line7, - .pin = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_7, - .GPIO_Speed = GPIO_Speed_100MHz, - .GPIO_Mode = GPIO_Mode_IN, - .GPIO_OType = GPIO_OType_OD, - .GPIO_PuPd = GPIO_PuPd_NOPULL, - }, - }, - .irq = { - .init = { - .NVIC_IRQChannel = EXTI9_5_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_LOW, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .exti = { - .init = { - .EXTI_Line = EXTI_Line7, // matches above GPIO pin - .EXTI_Mode = EXTI_Mode_Interrupt, - .EXTI_Trigger = EXTI_Trigger_Rising, - .EXTI_LineCmd = ENABLE, - }, - }, -}; -#endif /* PIOS_HMC5X83_HAS_GPIOS */ - -static const struct pios_hmc5x83_cfg pios_hmc5x83_internal_cfg = { -#ifdef PIOS_HMC5X83_HAS_GPIOS - .exti_cfg = &pios_exti_hmc5x83_cfg, -#endif - .M_ODR = PIOS_HMC5x83_ODR_75, - .Meas_Conf = PIOS_HMC5x83_MEASCONF_NORMAL, - .Gain = PIOS_HMC5x83_GAIN_1_9, - .Mode = PIOS_HMC5x83_MODE_CONTINUOUS, - .TempCompensation = false, - .Driver = &PIOS_HMC5x83_I2C_DRIVER, - .Orientation = PIOS_HMC5X83_ORIENTATION_EAST_NORTH_UP, -}; -static const struct pios_hmc5x83_cfg pios_hmc5x83_external_cfg = { -#ifdef PIOS_HMC5X83_HAS_GPIOS - .exti_cfg = NULL, -#endif - .M_ODR = PIOS_HMC5x83_ODR_75, // if you change this for auxmag, change AUX_MAG_SKIP in sensors.c - .Meas_Conf = PIOS_HMC5x83_MEASCONF_NORMAL, - .Gain = PIOS_HMC5x83_GAIN_1_9, - .Mode = PIOS_HMC5x83_MODE_CONTINUOUS, - .TempCompensation = false, - .Driver = &PIOS_HMC5x83_I2C_DRIVER, - .Orientation = PIOS_HMC5X83_ORIENTATION_EAST_NORTH_UP, // ENU for GPSV9, WND for typical I2C mag -}; -#endif /* PIOS_INCLUDE_HMC5X83 */ +uintptr_t pios_uavo_settings_fs_id; +uintptr_t pios_user_fs_id; -/** - * Configuration for the MS5611 chip - */ -#if defined(PIOS_INCLUDE_MS5611) -#include "pios_ms5611.h" -static const struct pios_ms5611_cfg pios_ms5611_cfg = { - .oversampling = MS5611_OSR_4096, +static const PIOS_BOARD_IO_UART_Function flexiio_function_map[] = { + [HWSETTINGS_RM_RCVRPORT_PPMTELEMETRY] = PIOS_BOARD_IO_UART_TELEMETRY, + [HWSETTINGS_RM_RCVRPORT_PPMDEBUGCONSOLE] = PIOS_BOARD_IO_UART_DEBUGCONSOLE, + [HWSETTINGS_RM_RCVRPORT_PPMCOMBRIDGE] = PIOS_BOARD_IO_UART_COMBRIDGE, + [HWSETTINGS_RM_RCVRPORT_PPMMSP] = PIOS_BOARD_IO_UART_MSP, + [HWSETTINGS_RM_RCVRPORT_PPMMAVLINK] = PIOS_BOARD_IO_UART_MAVLINK, + [HWSETTINGS_RM_RCVRPORT_PPMGPS] = PIOS_BOARD_IO_UART_GPS, + [HWSETTINGS_RM_RCVRPORT_TELEMETRY] = PIOS_BOARD_IO_UART_TELEMETRY, + [HWSETTINGS_RM_RCVRPORT_DEBUGCONSOLE] = PIOS_BOARD_IO_UART_DEBUGCONSOLE, + [HWSETTINGS_RM_RCVRPORT_COMBRIDGE] = PIOS_BOARD_IO_UART_COMBRIDGE, + [HWSETTINGS_RM_RCVRPORT_MSP] = PIOS_BOARD_IO_UART_MSP, + [HWSETTINGS_RM_RCVRPORT_MAVLINK] = PIOS_BOARD_IO_UART_MAVLINK, + [HWSETTINGS_RM_RCVRPORT_GPS] = PIOS_BOARD_IO_UART_GPS, + [HWSETTINGS_RM_RCVRPORT_IBUS] = PIOS_BOARD_IO_UART_IBUS, }; -#endif /* PIOS_INCLUDE_MS5611 */ - -/** - * Configuration for the MPU6000 chip - */ -#if defined(PIOS_INCLUDE_MPU6000) -#include "pios_mpu6000.h" -#include "pios_mpu6000_config.h" -static const struct pios_exti_cfg pios_exti_mpu6000_cfg __exti_config = { - .vector = PIOS_MPU6000_IRQHandler, - .line = EXTI_Line4, - .pin = { - .gpio = GPIOC, - .init = { - .GPIO_Pin = GPIO_Pin_4, - .GPIO_Speed = GPIO_Speed_100MHz, - .GPIO_Mode = GPIO_Mode_IN, - .GPIO_OType = GPIO_OType_OD, - .GPIO_PuPd = GPIO_PuPd_NOPULL, - }, - }, - .irq = { - .init = { - .NVIC_IRQChannel = EXTI4_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .exti = { - .init = { - .EXTI_Line = EXTI_Line4, // matches above GPIO pin - .EXTI_Mode = EXTI_Mode_Interrupt, - .EXTI_Trigger = EXTI_Trigger_Rising, - .EXTI_LineCmd = ENABLE, - }, - }, +static const PIOS_BOARD_IO_UART_Function main_function_map[] = { + [HWSETTINGS_RM_MAINPORT_TELEMETRY] = PIOS_BOARD_IO_UART_TELEMETRY, + [HWSETTINGS_RM_MAINPORT_GPS] = PIOS_BOARD_IO_UART_GPS, + [HWSETTINGS_RM_MAINPORT_SBUS] = PIOS_BOARD_IO_UART_SBUS, + [HWSETTINGS_RM_MAINPORT_DSM] = PIOS_BOARD_IO_UART_DSM_MAIN, + [HWSETTINGS_RM_MAINPORT_DEBUGCONSOLE] = PIOS_BOARD_IO_UART_DEBUGCONSOLE, + [HWSETTINGS_RM_MAINPORT_COMBRIDGE] = PIOS_BOARD_IO_UART_COMBRIDGE, + [HWSETTINGS_RM_MAINPORT_OSDHK] = PIOS_BOARD_IO_UART_OSDHK, + [HWSETTINGS_RM_MAINPORT_MSP] = PIOS_BOARD_IO_UART_MSP, + [HWSETTINGS_RM_MAINPORT_MAVLINK] = PIOS_BOARD_IO_UART_MAVLINK, }; -static const struct pios_mpu6000_cfg pios_mpu6000_cfg = { - .exti_cfg = &pios_exti_mpu6000_cfg, - .Fifo_store = PIOS_MPU6000_FIFO_TEMP_OUT | PIOS_MPU6000_FIFO_GYRO_X_OUT | PIOS_MPU6000_FIFO_GYRO_Y_OUT | PIOS_MPU6000_FIFO_GYRO_Z_OUT, - // Clock at 8 khz - .Smpl_rate_div_no_dlp = 0, - // with dlp on output rate is 1000Hz - .Smpl_rate_div_dlp = 0, - .interrupt_cfg = PIOS_MPU6000_INT_CLR_ANYRD, - .interrupt_en = PIOS_MPU6000_INTEN_DATA_RDY, - .User_ctl = PIOS_MPU6000_USERCTL_DIS_I2C, - .Pwr_mgmt_clk = PIOS_MPU6000_PWRMGMT_PLL_X_CLK, - .accel_range = PIOS_MPU6000_ACCEL_8G, - .gyro_range = PIOS_MPU6000_SCALE_2000_DEG, - .filter = PIOS_MPU6000_LOWPASS_256_HZ, - .orientation = PIOS_MPU6000_TOP_180DEG, - .fast_prescaler = PIOS_SPI_PRESCALER_4, - .std_prescaler = PIOS_SPI_PRESCALER_64, - .max_downsample = 20, +static const PIOS_BOARD_IO_UART_Function flexi_function_map[] = { + [HWSETTINGS_RM_FLEXIPORT_TELEMETRY] = PIOS_BOARD_IO_UART_TELEMETRY, + [HWSETTINGS_RM_FLEXIPORT_GPS] = PIOS_BOARD_IO_UART_GPS, + [HWSETTINGS_RM_FLEXIPORT_DSM] = PIOS_BOARD_IO_UART_DSM_FLEXI, + [HWSETTINGS_RM_FLEXIPORT_EXBUS] = PIOS_BOARD_IO_UART_EXBUS, + [HWSETTINGS_RM_FLEXIPORT_HOTTSUMD] = PIOS_BOARD_IO_UART_HOTT_SUMD, + [HWSETTINGS_RM_FLEXIPORT_HOTTSUMH] = PIOS_BOARD_IO_UART_HOTT_SUMH, + [HWSETTINGS_RM_FLEXIPORT_SRXL] = PIOS_BOARD_IO_UART_SRXL, + [HWSETTINGS_RM_FLEXIPORT_IBUS] = PIOS_BOARD_IO_UART_IBUS, + [HWSETTINGS_RM_FLEXIPORT_DEBUGCONSOLE] = PIOS_BOARD_IO_UART_DEBUGCONSOLE, + [HWSETTINGS_RM_FLEXIPORT_COMBRIDGE] = PIOS_BOARD_IO_UART_COMBRIDGE, + [HWSETTINGS_RM_FLEXIPORT_OSDHK] = PIOS_BOARD_IO_UART_OSDHK, + [HWSETTINGS_RM_FLEXIPORT_MSP] = PIOS_BOARD_IO_UART_MSP, + [HWSETTINGS_RM_FLEXIPORT_MAVLINK] = PIOS_BOARD_IO_UART_MAVLINK, }; -#endif /* PIOS_INCLUDE_MPU6000 */ - -/* One slot per selectable receiver group. - * eg. PWM, PPM, GCS, SPEKTRUM1, SPEKTRUM2, SBUS - * NOTE: No slot in this map for NONE. - */ -uint32_t pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_NONE]; - -#define PIOS_COM_TELEM_RF_RX_BUF_LEN 512 -#define PIOS_COM_TELEM_RF_TX_BUF_LEN 512 - -#define PIOS_COM_GPS_RX_BUF_LEN 128 -#define PIOS_COM_GPS_TX_BUF_LEN 32 - -#define PIOS_COM_TELEM_USB_RX_BUF_LEN 65 -#define PIOS_COM_TELEM_USB_TX_BUF_LEN 65 - -#define PIOS_COM_BRIDGE_RX_BUF_LEN 65 -#define PIOS_COM_BRIDGE_TX_BUF_LEN 12 - -#define PIOS_COM_HOTT_RX_BUF_LEN 512 -#define PIOS_COM_HOTT_TX_BUF_LEN 512 - -#define PIOS_COM_RFM22B_RF_RX_BUF_LEN 512 -#define PIOS_COM_RFM22B_RF_TX_BUF_LEN 512 - -#define PIOS_COM_HKOSD_RX_BUF_LEN 22 -#define PIOS_COM_HKOSD_TX_BUF_LEN 22 - -#define PIOS_COM_MSP_TX_BUF_LEN 128 -#define PIOS_COM_MSP_RX_BUF_LEN 64 -#define PIOS_COM_MAVLINK_TX_BUF_LEN 128 -#define PIOS_COM_MAVLINK_RX_BUF_LEN 128 - -#if defined(PIOS_INCLUDE_DEBUG_CONSOLE) -#define PIOS_COM_DEBUGCONSOLE_TX_BUF_LEN 40 -uint32_t pios_com_debug_id; -#endif /* PIOS_INCLUDE_DEBUG_CONSOLE */ - -uint32_t pios_com_gps_id = 0; -uint32_t pios_com_telem_usb_id = 0; -uint32_t pios_com_telem_rf_id = 0; -uint32_t pios_com_rf_id = 0; -uint32_t pios_com_bridge_id = 0; -uint32_t pios_com_hott_id = 0; -uint32_t pios_com_overo_id = 0; -uint32_t pios_com_hkosd_id = 0; -uint32_t pios_com_vcp_id = 0; -uint32_t pios_com_msp_id = 0; -uint32_t pios_com_mavlink_id = 0; - -#if defined(PIOS_INCLUDE_RFM22B) -uint32_t pios_rfm22b_id = 0; -#include -#endif - -uintptr_t pios_uavo_settings_fs_id; -uintptr_t pios_user_fs_id; - -/* - * Setup a com port based on the passed cfg, driver and buffer sizes. - * tx size = 0 make the port rx only - * rx size = 0 make the port tx only - * having both tx and rx size = 0 is not valid and will fail further down in PIOS_COM_Init() - */ -static void PIOS_Board_configure_com(const struct pios_usart_cfg *usart_port_cfg, uint16_t rx_buf_len, uint16_t tx_buf_len, - const struct pios_com_driver *com_driver, uint32_t *pios_com_id) -{ - uint32_t pios_usart_id; - - if (PIOS_USART_Init(&pios_usart_id, usart_port_cfg)) { - PIOS_Assert(0); - } - - uint8_t *rx_buffer = 0, *tx_buffer = 0; - - if (rx_buf_len > 0) { - rx_buffer = (uint8_t *)pios_malloc(rx_buf_len); - PIOS_Assert(rx_buffer); - } - - if (tx_buf_len > 0) { - tx_buffer = (uint8_t *)pios_malloc(tx_buf_len); - PIOS_Assert(tx_buffer); - } - - if (PIOS_COM_Init(pios_com_id, com_driver, pios_usart_id, - rx_buffer, rx_buf_len, - tx_buffer, tx_buf_len)) { - PIOS_Assert(0); - } -} - -static void PIOS_Board_configure_dsm(const struct pios_usart_cfg *pios_usart_dsm_cfg, const struct pios_dsm_cfg *pios_dsm_cfg, - const struct pios_com_driver *usart_com_driver, - ManualControlSettingsChannelGroupsOptions channelgroup, uint8_t *bind) -{ - uint32_t pios_usart_dsm_id; - - if (PIOS_USART_Init(&pios_usart_dsm_id, pios_usart_dsm_cfg)) { - PIOS_Assert(0); - } - - uint32_t pios_dsm_id; - if (PIOS_DSM_Init(&pios_dsm_id, pios_dsm_cfg, usart_com_driver, - pios_usart_dsm_id, *bind)) { - PIOS_Assert(0); - } - - uint32_t pios_dsm_rcvr_id; - if (PIOS_RCVR_Init(&pios_dsm_rcvr_id, &pios_dsm_rcvr_driver, pios_dsm_id)) { - PIOS_Assert(0); - } - pios_rcvr_group_map[channelgroup] = pios_dsm_rcvr_id; -} - -static void PIOS_Board_configure_ibus(const struct pios_usart_cfg *usart_cfg) -{ - uint32_t pios_usart_ibus_id; - - if (PIOS_USART_Init(&pios_usart_ibus_id, usart_cfg)) { - PIOS_Assert(0); - } - - uint32_t pios_ibus_id; - if (PIOS_IBUS_Init(&pios_ibus_id, &pios_usart_com_driver, pios_usart_ibus_id)) { - PIOS_Assert(0); - } - uint32_t pios_ibus_rcvr_id; - if (PIOS_RCVR_Init(&pios_ibus_rcvr_id, &pios_ibus_rcvr_driver, pios_ibus_id)) { - PIOS_Assert(0); - } - pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_IBUS] = pios_ibus_rcvr_id; -} - -static void PIOS_Board_configure_pwm(const struct pios_pwm_cfg *pwm_cfg) +int32_t PIOS_BOARD_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param) { - /* Set up the receiver port. Later this should be optional */ - uint32_t pios_pwm_id; + const struct pios_usart_cfg *usart_cfg = PIOS_USART_GetConfig(usart_id); - PIOS_PWM_Init(&pios_pwm_id, pwm_cfg); + switch (ctl) { + case PIOS_IOCTL_USART_SET_INVERTED: + if (usart_cfg->regs == pios_usart_main_cfg.regs) { /* main port */ + GPIO_WriteBit(MAIN_USART_INVERTER_GPIO, + MAIN_USART_INVERTER_PIN, + (*(enum PIOS_USART_Inverted *)param & PIOS_USART_Inverted_Rx) ? MAIN_USART_INVERTER_ENABLE : MAIN_USART_INVERTER_DISABLE); - uint32_t pios_pwm_rcvr_id; - if (PIOS_RCVR_Init(&pios_pwm_rcvr_id, &pios_pwm_rcvr_driver, pios_pwm_id)) { - PIOS_Assert(0); + return 0; + } + break; } - pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_PWM] = pios_pwm_rcvr_id; -} - -static void PIOS_Board_configure_ppm(const struct pios_ppm_cfg *ppm_cfg) -{ - uint32_t pios_ppm_id; - PIOS_PPM_Init(&pios_ppm_id, ppm_cfg); - - uint32_t pios_ppm_rcvr_id; - if (PIOS_RCVR_Init(&pios_ppm_rcvr_id, &pios_ppm_rcvr_driver, pios_ppm_id)) { - PIOS_Assert(0); - } - pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_PPM] = pios_ppm_rcvr_id; + return -1; } /** @@ -400,9 +122,6 @@ static void PIOS_Board_configure_ppm(const struct pios_ppm_cfg *ppm_cfg) * initializes all the core subsystems on this specific hardware * called from System/openpilot.c */ - -#include - void PIOS_Board_Init(void) { const struct pios_board_info *bdinfo = &pios_board_info_blob; @@ -473,10 +192,6 @@ void PIOS_Board_Init(void) EventDispatcherInitialize(); UAVObjInitialize(); HwSettingsInitialize(); -#if defined(PIOS_INCLUDE_RFM22B) - OPLinkSettingsInitialize(); - OPLinkStatusInitialize(); -#endif /* PIOS_INCLUDE_RFM22B */ /* Initialize the alarms library */ AlarmsInitialize(); @@ -503,537 +218,71 @@ void PIOS_Board_Init(void) } /* Configure IO ports */ - uint8_t hwsettings_DSMxBind; - HwSettingsDSMxBindGet(&hwsettings_DSMxBind); /* Configure FlexiPort */ uint8_t hwsettings_flexiport; HwSettingsRM_FlexiPortGet(&hwsettings_flexiport); - switch (hwsettings_flexiport) { - case HWSETTINGS_RM_FLEXIPORT_DISABLED: - break; - case HWSETTINGS_RM_FLEXIPORT_TELEMETRY: - PIOS_Board_configure_com(&pios_usart_flexi_cfg, PIOS_COM_TELEM_RF_RX_BUF_LEN, PIOS_COM_TELEM_RF_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_telem_rf_id); - break; - case HWSETTINGS_RM_FLEXIPORT_I2C: -#if defined(PIOS_INCLUDE_I2C) - if (PIOS_I2C_Init(&pios_i2c_flexiport_adapter_id, &pios_i2c_flexiport_adapter_cfg)) { - PIOS_Assert(0); - } - PIOS_DELAY_WaitmS(50); // this was after the other PIOS_I2C_Init(), so I copied it here too -#ifdef PIOS_INCLUDE_WDG - // give HMC5x83 on I2C some extra time to allow for reset, etc. if needed - // this is not in a loop, so it is safe - // leave this here even if PIOS_INCLUDE_HMC5X83 is undefined - // to avoid making something else fail when HMC5X83 is removed - PIOS_WDG_Clear(); -#endif /* PIOS_INCLUDE_WDG */ -#if defined(PIOS_INCLUDE_HMC5X83) - // get auxmag type - AuxMagSettingsTypeOptions option; - AuxMagSettingsInitialize(); - AuxMagSettingsTypeGet(&option); - // if the aux mag type is FlexiPort then set it up - if (option == AUXMAGSETTINGS_TYPE_FLEXI) { - // attach the 5x83 mag to the previously inited I2C2 - external_mag = PIOS_HMC5x83_Init(&pios_hmc5x83_external_cfg, pios_i2c_flexiport_adapter_id, 0); -#ifdef PIOS_INCLUDE_WDG - // give HMC5x83 on I2C some extra time to allow for reset, etc. if needed - // this is not in a loop, so it is safe - PIOS_WDG_Clear(); -#endif /* PIOS_INCLUDE_WDG */ - // add this sensor to the sensor task's list - // be careful that you don't register a slow, unimportant sensor after registering the fastest sensor - // and before registering some other fast and important sensor - // as that would cause delay and time jitter for the second fast sensor - PIOS_HMC5x83_Register(external_mag, PIOS_SENSORS_TYPE_3AXIS_AUXMAG); - // mag alarm is cleared later, so use I2C - AlarmsSet(SYSTEMALARMS_ALARM_I2C, (external_mag) ? SYSTEMALARMS_ALARM_OK : SYSTEMALARMS_ALARM_WARNING); - } -#endif /* PIOS_INCLUDE_HMC5X83 */ -#endif /* PIOS_INCLUDE_I2C */ - break; - case HWSETTINGS_RM_FLEXIPORT_GPS: - PIOS_Board_configure_com(&pios_usart_flexi_cfg, PIOS_COM_GPS_RX_BUF_LEN, PIOS_COM_GPS_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_gps_id); - break; - case HWSETTINGS_RM_FLEXIPORT_DSM: - // TODO: Define the various Channelgroup for Revo dsm inputs and handle here - PIOS_Board_configure_dsm(&pios_usart_dsm_flexi_cfg, &pios_dsm_flexi_cfg, - &pios_usart_com_driver, MANUALCONTROLSETTINGS_CHANNELGROUPS_DSMFLEXIPORT, &hwsettings_DSMxBind); - break; - case HWSETTINGS_RM_FLEXIPORT_DEBUGCONSOLE: -#if defined(PIOS_INCLUDE_DEBUG_CONSOLE) - { - PIOS_Board_configure_com(&pios_usart_flexi_cfg, 0, PIOS_COM_DEBUGCONSOLE_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_debug_id); - } -#endif /* PIOS_INCLUDE_DEBUG_CONSOLE */ - break; - case HWSETTINGS_RM_FLEXIPORT_COMBRIDGE: - PIOS_Board_configure_com(&pios_usart_flexi_cfg, PIOS_COM_BRIDGE_RX_BUF_LEN, PIOS_COM_BRIDGE_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_bridge_id); - break; - case HWSETTINGS_RM_FLEXIPORT_MSP: - PIOS_Board_configure_com(&pios_usart_flexi_cfg, PIOS_COM_MSP_RX_BUF_LEN, PIOS_COM_MSP_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_msp_id); - break; - case HWSETTINGS_RM_FLEXIPORT_MAVLINK: - PIOS_Board_configure_com(&pios_usart_flexi_cfg, 0, PIOS_COM_MAVLINK_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_mavlink_id); - break; - case HWSETTINGS_RM_FLEXIPORT_OSDHK: - PIOS_Board_configure_com(&pios_usart_hkosd_flexi_cfg, PIOS_COM_HKOSD_RX_BUF_LEN, PIOS_COM_HKOSD_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_hkosd_id); - break; - - case HWSETTINGS_RM_FLEXIPORT_SRXL: -#if defined(PIOS_INCLUDE_SRXL) - { - uint32_t pios_usart_srxl_id; - if (PIOS_USART_Init(&pios_usart_srxl_id, &pios_usart_srxl_flexi_cfg)) { - PIOS_Assert(0); - } - - uint32_t pios_srxl_id; - if (PIOS_SRXL_Init(&pios_srxl_id, &pios_usart_com_driver, pios_usart_srxl_id)) { - PIOS_Assert(0); - } - - uint32_t pios_srxl_rcvr_id; - if (PIOS_RCVR_Init(&pios_srxl_rcvr_id, &pios_srxl_rcvr_driver, pios_srxl_id)) { - PIOS_Assert(0); - } - pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_SRXL] = pios_srxl_rcvr_id; - } -#endif /* PIOS_INCLUDE_SRXL */ - break; - - case HWSETTINGS_RM_FLEXIPORT_IBUS: -#if defined(PIOS_INCLUDE_IBUS) - PIOS_Board_configure_ibus(&pios_usart_ibus_flexi_cfg); -#endif /* PIOS_INCLUDE_IBUS */ - break; - case HWSETTINGS_RM_FLEXIPORT_HOTTSUMD: - case HWSETTINGS_RM_FLEXIPORT_HOTTSUMH: -#if defined(PIOS_INCLUDE_HOTT) - { - uint32_t pios_usart_hott_id; - if (PIOS_USART_Init(&pios_usart_hott_id, &pios_usart_hott_flexi_cfg)) { - PIOS_Assert(0); - } + if (hwsettings_flexiport < NELEMENTS(flexi_function_map)) { + PIOS_BOARD_IO_Configure_UART(&pios_usart_flexi_cfg, flexi_function_map[hwsettings_flexiport]); + } - uint32_t pios_hott_id; - if (PIOS_HOTT_Init(&pios_hott_id, &pios_usart_com_driver, pios_usart_hott_id, - hwsettings_flexiport == HWSETTINGS_RM_FLEXIPORT_HOTTSUMD ? PIOS_HOTT_PROTO_SUMD : PIOS_HOTT_PROTO_SUMH)) { - PIOS_Assert(0); - } +#if defined(PIOS_INCLUDE_I2C) + /* Set up internal I2C bus */ + if (PIOS_I2C_Init(&pios_i2c_mag_pressure_adapter_id, &pios_i2c_mag_pressure_adapter_cfg)) { + PIOS_DEBUG_Assert(0); + } + PIOS_DELAY_WaitmS(50); - uint32_t pios_hott_rcvr_id; - if (PIOS_RCVR_Init(&pios_hott_rcvr_id, &pios_hott_rcvr_driver, pios_hott_id)) { - PIOS_Assert(0); - } - pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_HOTT] = pios_hott_rcvr_id; + if (hwsettings_flexiport == HWSETTINGS_RM_FLEXIPORT_I2C) { + if (PIOS_I2C_Init(&pios_i2c_flexiport_adapter_id, &pios_i2c_flexiport_adapter_cfg)) { + PIOS_Assert(0); } -#endif /* PIOS_INCLUDE_HOTT */ - break; - case HWSETTINGS_RM_FLEXIPORT_HOTTTELEMETRY: - PIOS_Board_configure_com(&pios_usart_hott_flexi_cfg, PIOS_COM_HOTT_RX_BUF_LEN, PIOS_COM_HOTT_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_hott_id); - break; - - case HWSETTINGS_RM_FLEXIPORT_EXBUS: -#if defined(PIOS_INCLUDE_EXBUS) - { - uint32_t pios_usart_exbus_id; - if (PIOS_USART_Init(&pios_usart_exbus_id, &pios_usart_exbus_flexi_cfg)) { - PIOS_Assert(0); - } - - uint32_t pios_exbus_id; - if (PIOS_EXBUS_Init(&pios_exbus_id, &pios_usart_com_driver, pios_usart_exbus_id)) { - PIOS_Assert(0); - } + PIOS_DELAY_WaitmS(50); + } - uint32_t pios_exbus_rcvr_id; - if (PIOS_RCVR_Init(&pios_exbus_rcvr_id, &pios_exbus_rcvr_driver, pios_exbus_id)) { - PIOS_Assert(0); - } - pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_EXBUS] = pios_exbus_rcvr_id; - } -#endif /* PIOS_INCLUDE_EXBUS */ - break; - } /* hwsettings_rm_flexiport */ + PIOS_BOARD_IO_Configure_I2C(pios_i2c_mag_pressure_adapter_id, pios_i2c_flexiport_adapter_id); +#endif - /* Moved this here to allow binding on flexiport */ + /* Moved this here to allow DSM binding on flexiport */ #if defined(PIOS_INCLUDE_FLASH) if (PIOS_FLASHFS_Logfs_Init(&pios_user_fs_id, &flashfs_external_user_cfg, &pios_jedec_flash_driver, flash_id)) { PIOS_DEBUG_Assert(0); } #endif /* if defined(PIOS_INCLUDE_FLASH) */ -#if defined(PIOS_INCLUDE_USB) - /* Initialize board specific USB data */ - PIOS_USB_BOARD_DATA_Init(); - /* Flags to determine if various USB interfaces are advertised */ - bool usb_hid_present = false; - bool usb_cdc_present = false; - -#if defined(PIOS_INCLUDE_USB_CDC) - if (PIOS_USB_DESC_HID_CDC_Init()) { - PIOS_Assert(0); - } - usb_hid_present = true; - usb_cdc_present = true; -#else - if (PIOS_USB_DESC_HID_ONLY_Init()) { - PIOS_Assert(0); - } - usb_hid_present = true; +#if defined(PIOS_INCLUDE_USB) + PIOS_BOARD_IO_Configure_USB(); #endif - uint32_t pios_usb_id; - PIOS_USB_Init(&pios_usb_id, PIOS_BOARD_HW_DEFS_GetUsbCfg(bdinfo->board_rev)); - -#if defined(PIOS_INCLUDE_USB_CDC) - - uint8_t hwsettings_usb_vcpport; - /* Configure the USB VCP port */ - HwSettingsUSB_VCPPortGet(&hwsettings_usb_vcpport); - - if (!usb_cdc_present) { - /* Force VCP port function to disabled if we haven't advertised VCP in our USB descriptor */ - hwsettings_usb_vcpport = HWSETTINGS_USB_VCPPORT_DISABLED; - } - uint32_t pios_usb_cdc_id; - if (PIOS_USB_CDC_Init(&pios_usb_cdc_id, &pios_usb_cdc_cfg, pios_usb_id)) { - PIOS_Assert(0); - } - - uint32_t pios_usb_hid_id; - if (PIOS_USB_HID_Init(&pios_usb_hid_id, &pios_usb_hid_cfg, pios_usb_id)) { - PIOS_Assert(0); - } - - switch (hwsettings_usb_vcpport) { - case HWSETTINGS_USB_VCPPORT_DISABLED: - break; - case HWSETTINGS_USB_VCPPORT_USBTELEMETRY: -#if defined(PIOS_INCLUDE_COM) - { - uint8_t *rx_buffer = (uint8_t *)pios_malloc(PIOS_COM_TELEM_USB_RX_BUF_LEN); - uint8_t *tx_buffer = (uint8_t *)pios_malloc(PIOS_COM_TELEM_USB_TX_BUF_LEN); - PIOS_Assert(rx_buffer); - PIOS_Assert(tx_buffer); - if (PIOS_COM_Init(&pios_com_telem_usb_id, &pios_usb_cdc_com_driver, pios_usb_cdc_id, - rx_buffer, PIOS_COM_TELEM_USB_RX_BUF_LEN, - tx_buffer, PIOS_COM_TELEM_USB_TX_BUF_LEN)) { - PIOS_Assert(0); - } - } -#endif /* PIOS_INCLUDE_COM */ - break; - case HWSETTINGS_USB_VCPPORT_COMBRIDGE: -#if defined(PIOS_INCLUDE_COM) - { - uint8_t *rx_buffer = (uint8_t *)pios_malloc(PIOS_COM_BRIDGE_RX_BUF_LEN); - uint8_t *tx_buffer = (uint8_t *)pios_malloc(PIOS_COM_BRIDGE_TX_BUF_LEN); - PIOS_Assert(rx_buffer); - PIOS_Assert(tx_buffer); - if (PIOS_COM_Init(&pios_com_vcp_id, &pios_usb_cdc_com_driver, pios_usb_cdc_id, - rx_buffer, PIOS_COM_BRIDGE_RX_BUF_LEN, - tx_buffer, PIOS_COM_BRIDGE_TX_BUF_LEN)) { - PIOS_Assert(0); - } - } -#endif /* PIOS_INCLUDE_COM */ - break; - case HWSETTINGS_USB_VCPPORT_DEBUGCONSOLE: -#if defined(PIOS_INCLUDE_COM) -#if defined(PIOS_INCLUDE_DEBUG_CONSOLE) - { - uint8_t *tx_buffer = (uint8_t *)pios_malloc(PIOS_COM_DEBUGCONSOLE_TX_BUF_LEN); - PIOS_Assert(tx_buffer); - if (PIOS_COM_Init(&pios_com_debug_id, &pios_usb_cdc_com_driver, pios_usb_cdc_id, - NULL, 0, - tx_buffer, PIOS_COM_DEBUGCONSOLE_TX_BUF_LEN)) { - PIOS_Assert(0); - } - } -#endif /* PIOS_INCLUDE_DEBUG_CONSOLE */ -#endif /* PIOS_INCLUDE_COM */ - - break; - } -#endif /* PIOS_INCLUDE_USB_CDC */ - -#if defined(PIOS_INCLUDE_USB_HID) - /* Configure the usb HID port */ - uint8_t hwsettings_usb_hidport; - HwSettingsUSB_HIDPortGet(&hwsettings_usb_hidport); - - if (!usb_hid_present) { - /* Force HID port function to disabled if we haven't advertised HID in our USB descriptor */ - hwsettings_usb_hidport = HWSETTINGS_USB_HIDPORT_DISABLED; - } - - switch (hwsettings_usb_hidport) { - case HWSETTINGS_USB_HIDPORT_DISABLED: - break; - case HWSETTINGS_USB_HIDPORT_USBTELEMETRY: -#if defined(PIOS_INCLUDE_COM) - { - uint8_t *rx_buffer = (uint8_t *)pios_malloc(PIOS_COM_TELEM_USB_RX_BUF_LEN); - uint8_t *tx_buffer = (uint8_t *)pios_malloc(PIOS_COM_TELEM_USB_TX_BUF_LEN); - PIOS_Assert(rx_buffer); - PIOS_Assert(tx_buffer); - if (PIOS_COM_Init(&pios_com_telem_usb_id, &pios_usb_hid_com_driver, pios_usb_hid_id, - rx_buffer, PIOS_COM_TELEM_USB_RX_BUF_LEN, - tx_buffer, PIOS_COM_TELEM_USB_TX_BUF_LEN)) { - PIOS_Assert(0); - } - } -#endif /* PIOS_INCLUDE_COM */ - break; - } - -#endif /* PIOS_INCLUDE_USB_HID */ + /* Configure main USART port */ - if (usb_hid_present || usb_cdc_present) { - PIOS_USBHOOK_Activate(); + /* Initialize inverter gpio and set it to off */ + { + GPIO_InitTypeDef inverterGPIOInit = { + .GPIO_Pin = MAIN_USART_INVERTER_PIN, + .GPIO_Speed = GPIO_Speed_2MHz, + .GPIO_Mode = GPIO_Mode_OUT, + .GPIO_OType = GPIO_OType_PP, + .GPIO_PuPd = GPIO_PuPd_UP + }; + + GPIO_Init(MAIN_USART_INVERTER_GPIO, &inverterGPIOInit); + GPIO_WriteBit(MAIN_USART_INVERTER_GPIO, + MAIN_USART_INVERTER_PIN, + MAIN_USART_INVERTER_DISABLE); } -#endif /* PIOS_INCLUDE_USB */ - /* Configure main USART port */ uint8_t hwsettings_mainport; HwSettingsRM_MainPortGet(&hwsettings_mainport); - switch (hwsettings_mainport) { - case HWSETTINGS_RM_MAINPORT_DISABLED: - break; - case HWSETTINGS_RM_MAINPORT_TELEMETRY: - PIOS_Board_configure_com(&pios_usart_main_cfg, PIOS_COM_TELEM_RF_RX_BUF_LEN, PIOS_COM_TELEM_RF_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_telem_rf_id); - break; - case HWSETTINGS_RM_MAINPORT_GPS: - PIOS_Board_configure_com(&pios_usart_main_cfg, PIOS_COM_GPS_RX_BUF_LEN, PIOS_COM_GPS_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_gps_id); - break; - case HWSETTINGS_RM_MAINPORT_SBUS: -#if defined(PIOS_INCLUDE_SBUS) - { - uint32_t pios_usart_sbus_id; - if (PIOS_USART_Init(&pios_usart_sbus_id, &pios_usart_sbus_main_cfg)) { - PIOS_Assert(0); - } - - uint32_t pios_sbus_id; - if (PIOS_SBus_Init(&pios_sbus_id, &pios_sbus_cfg, &pios_usart_com_driver, pios_usart_sbus_id)) { - PIOS_Assert(0); - } - - uint32_t pios_sbus_rcvr_id; - if (PIOS_RCVR_Init(&pios_sbus_rcvr_id, &pios_sbus_rcvr_driver, pios_sbus_id)) { - PIOS_Assert(0); - } - pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_SBUS] = pios_sbus_rcvr_id; - } -#endif - break; - case HWSETTINGS_RM_MAINPORT_DSM: - // Force binding to zero on the main port - hwsettings_DSMxBind = 0; - // TODO: Define the various Channelgroup for Revo dsm inputs and handle here - PIOS_Board_configure_dsm(&pios_usart_dsm_main_cfg, &pios_dsm_main_cfg, - &pios_usart_com_driver, MANUALCONTROLSETTINGS_CHANNELGROUPS_DSMMAINPORT, &hwsettings_DSMxBind); - break; - case HWSETTINGS_RM_MAINPORT_DEBUGCONSOLE: -#if defined(PIOS_INCLUDE_DEBUG_CONSOLE) - { - PIOS_Board_configure_com(&pios_usart_main_cfg, 0, PIOS_COM_DEBUGCONSOLE_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_debug_id); - } -#endif /* PIOS_INCLUDE_DEBUG_CONSOLE */ - break; - case HWSETTINGS_RM_MAINPORT_HOTTTELEMETRY: - PIOS_Board_configure_com(&pios_usart_main_cfg, PIOS_COM_HOTT_RX_BUF_LEN, PIOS_COM_HOTT_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_hott_id); - break; - case HWSETTINGS_RM_MAINPORT_COMBRIDGE: - PIOS_Board_configure_com(&pios_usart_main_cfg, PIOS_COM_BRIDGE_RX_BUF_LEN, PIOS_COM_BRIDGE_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_bridge_id); - break; - case HWSETTINGS_RM_MAINPORT_MSP: - PIOS_Board_configure_com(&pios_usart_main_cfg, PIOS_COM_MSP_RX_BUF_LEN, PIOS_COM_MSP_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_msp_id); - break; - case HWSETTINGS_RM_MAINPORT_MAVLINK: - PIOS_Board_configure_com(&pios_usart_main_cfg, 0, PIOS_COM_MAVLINK_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_mavlink_id); - break; - case HWSETTINGS_RM_MAINPORT_OSDHK: - PIOS_Board_configure_com(&pios_usart_hkosd_main_cfg, PIOS_COM_HKOSD_RX_BUF_LEN, PIOS_COM_HKOSD_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_hkosd_id); - break; - } /* hwsettings_rm_mainport */ - - if (hwsettings_mainport != HWSETTINGS_RM_MAINPORT_SBUS) { - GPIO_Init(pios_sbus_cfg.inv.gpio, &pios_sbus_cfg.inv.init); - GPIO_WriteBit(pios_sbus_cfg.inv.gpio, pios_sbus_cfg.inv.init.GPIO_Pin, pios_sbus_cfg.gpio_inv_disable); + if (hwsettings_mainport < NELEMENTS(main_function_map)) { + PIOS_BOARD_IO_Configure_UART(&pios_usart_main_cfg, main_function_map[hwsettings_mainport]); } - /* Initialize the RFM22B radio COM device. */ #if defined(PIOS_INCLUDE_RFM22B) - - /* Fetch the OPLinkSettings object. */ - OPLinkSettingsData oplinkSettings; - OPLinkSettingsGet(&oplinkSettings); - - // Initialize out status object. - OPLinkStatusData oplinkStatus; - OPLinkStatusGet(&oplinkStatus); - oplinkStatus.BoardType = bdinfo->board_type; - PIOS_BL_HELPER_FLASH_Read_Description(oplinkStatus.Description, OPLINKSTATUS_DESCRIPTION_NUMELEM); - PIOS_SYS_SerialNumberGetBinary(oplinkStatus.CPUSerial); - oplinkStatus.BoardRevision = bdinfo->board_rev; - - /* Is the radio turned on? */ - bool is_coordinator = (oplinkSettings.Protocol == OPLINKSETTINGS_PROTOCOL_OPLINKCOORDINATOR); - bool openlrs = (oplinkSettings.Protocol == OPLINKSETTINGS_PROTOCOL_OPENLRS); - bool data_mode = ((oplinkSettings.LinkType == OPLINKSETTINGS_LINKTYPE_DATA) || - (oplinkSettings.LinkType == OPLINKSETTINGS_LINKTYPE_DATAANDCONTROL)); - bool ppm_mode = ((oplinkSettings.LinkType == OPLINKSETTINGS_LINKTYPE_CONTROL) || - (oplinkSettings.LinkType == OPLINKSETTINGS_LINKTYPE_DATAANDCONTROL)); - bool is_enabled = ((oplinkSettings.Protocol != OPLINKSETTINGS_PROTOCOL_DISABLED) && - ((oplinkSettings.MaxRFPower != OPLINKSETTINGS_MAXRFPOWER_0) || openlrs)); - if (is_enabled) { - if (openlrs) { -#if defined(PIOS_INCLUDE_OPENLRS_RCVR) - const struct pios_openlrs_cfg *openlrs_cfg = PIOS_BOARD_HW_DEFS_GetOpenLRSCfg(bdinfo->board_rev); - uint32_t openlrs_id; - - PIOS_OpenLRS_Init(&openlrs_id, PIOS_RFM22_SPI_PORT, 0, openlrs_cfg); - { - uint32_t openlrsrcvr_id; - PIOS_OpenLRS_Rcvr_Init(&openlrsrcvr_id, openlrs_id); - uint32_t openlrsrcvr_rcvr_id; - if (PIOS_RCVR_Init(&openlrsrcvr_rcvr_id, &pios_openlrs_rcvr_driver, openlrsrcvr_id)) { - PIOS_Assert(0); - } - pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_OPENLRS] = openlrsrcvr_rcvr_id; - } -#endif /* PIOS_INCLUDE_OPENLRS_RCVR */ - } else { - /* Configure the RFM22B device. */ - const struct pios_rfm22b_cfg *rfm22b_cfg = PIOS_BOARD_HW_DEFS_GetRfm22Cfg(bdinfo->board_rev); - - if (PIOS_RFM22B_Init(&pios_rfm22b_id, PIOS_RFM22_SPI_PORT, rfm22b_cfg->slave_num, rfm22b_cfg, oplinkSettings.RFBand)) { - PIOS_Assert(0); - } - - /* Configure the radio com interface */ - uint8_t *rx_buffer = (uint8_t *)pios_malloc(PIOS_COM_RFM22B_RF_RX_BUF_LEN); - uint8_t *tx_buffer = (uint8_t *)pios_malloc(PIOS_COM_RFM22B_RF_TX_BUF_LEN); - PIOS_Assert(rx_buffer); - PIOS_Assert(tx_buffer); - if (PIOS_COM_Init(&pios_com_rf_id, &pios_rfm22b_com_driver, pios_rfm22b_id, - rx_buffer, PIOS_COM_RFM22B_RF_RX_BUF_LEN, - tx_buffer, PIOS_COM_RFM22B_RF_TX_BUF_LEN)) { - PIOS_Assert(0); - } - - oplinkStatus.LinkState = OPLINKSTATUS_LINKSTATE_ENABLED; - - // Set the modem (over the air) datarate. - enum rfm22b_datarate datarate = RFM22_datarate_64000; - switch (oplinkSettings.AirDataRate) { - case OPLINKSETTINGS_AIRDATARATE_9600: - datarate = RFM22_datarate_9600; - break; - case OPLINKSETTINGS_AIRDATARATE_19200: - datarate = RFM22_datarate_19200; - break; - case OPLINKSETTINGS_AIRDATARATE_32000: - datarate = RFM22_datarate_32000; - break; - case OPLINKSETTINGS_AIRDATARATE_57600: - datarate = RFM22_datarate_57600; - break; - case OPLINKSETTINGS_AIRDATARATE_64000: - datarate = RFM22_datarate_64000; - break; - case OPLINKSETTINGS_AIRDATARATE_100000: - datarate = RFM22_datarate_100000; - break; - case OPLINKSETTINGS_AIRDATARATE_128000: - datarate = RFM22_datarate_128000; - break; - case OPLINKSETTINGS_AIRDATARATE_192000: - datarate = RFM22_datarate_192000; - break; - case OPLINKSETTINGS_AIRDATARATE_256000: - datarate = RFM22_datarate_256000; - break; - } - - /* Set the radio configuration parameters. */ - PIOS_RFM22B_SetDeviceID(pios_rfm22b_id, oplinkSettings.CustomDeviceID); - PIOS_RFM22B_SetCoordinatorID(pios_rfm22b_id, oplinkSettings.CoordID); - PIOS_RFM22B_SetXtalCap(pios_rfm22b_id, oplinkSettings.RFXtalCap); - PIOS_RFM22B_SetChannelConfig(pios_rfm22b_id, datarate, oplinkSettings.MinChannel, oplinkSettings.MaxChannel, is_coordinator, data_mode, ppm_mode); - - /* Set the modem Tx power level */ - switch (oplinkSettings.MaxRFPower) { - case OPLINKSETTINGS_MAXRFPOWER_125: - PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_0); - break; - case OPLINKSETTINGS_MAXRFPOWER_16: - PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_1); - break; - case OPLINKSETTINGS_MAXRFPOWER_316: - PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_2); - break; - case OPLINKSETTINGS_MAXRFPOWER_63: - PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_3); - break; - case OPLINKSETTINGS_MAXRFPOWER_126: - PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_4); - break; - case OPLINKSETTINGS_MAXRFPOWER_25: - PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_5); - break; - case OPLINKSETTINGS_MAXRFPOWER_50: - PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_6); - break; - case OPLINKSETTINGS_MAXRFPOWER_100: - PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_7); - break; - default: - // do nothing - break; - } - - /* Reinitialize the modem. */ - PIOS_RFM22B_Reinit(pios_rfm22b_id); - - uint8_t hwsettings_radioaux; - HwSettingsRadioAuxStreamGet(&hwsettings_radioaux); - // TODO: this is in preparation for full mavlink support and is used by LP-368 - uint16_t mavlink_rx_size = PIOS_COM_MAVLINK_RX_BUF_LEN; - - switch (hwsettings_radioaux) { - case HWSETTINGS_RADIOAUXSTREAM_DEBUGCONSOLE: - case HWSETTINGS_RADIOAUXSTREAM_DISABLED: - break; - case HWSETTINGS_RADIOAUXSTREAM_MAVLINK: - { - uint8_t *auxrx_buffer = 0; - if (mavlink_rx_size) { - auxrx_buffer = (uint8_t *)pios_malloc(mavlink_rx_size); - } - uint8_t *auxtx_buffer = (uint8_t *)pios_malloc(PIOS_COM_MAVLINK_TX_BUF_LEN); - PIOS_Assert(auxrx_buffer); - PIOS_Assert(auxtx_buffer); - if (PIOS_COM_Init(&pios_com_mavlink_id, &pios_rfm22b_aux_com_driver, pios_rfm22b_id, - auxrx_buffer, mavlink_rx_size, - auxtx_buffer, PIOS_COM_BRIDGE_TX_BUF_LEN)) { - PIOS_Assert(0); - } - } - } - } - } else { - oplinkStatus.LinkState = OPLINKSTATUS_LINKSTATE_DISABLED; - } - - OPLinkStatusSet(&oplinkStatus); + PIOS_BOARD_IO_Configure_RFM22B(); #endif /* PIOS_INCLUDE_RFM22B */ #if defined(PIOS_INCLUDE_PWM) || defined(PIOS_INCLUDE_PPM) @@ -1046,12 +295,16 @@ void PIOS_Board_Init(void) uint8_t hwsettings_rcvrport; HwSettingsRM_RcvrPortGet(&hwsettings_rcvrport); + if (hwsettings_rcvrport < NELEMENTS(flexiio_function_map)) { + PIOS_BOARD_IO_Configure_UART(&pios_usart_flexiio_cfg, flexiio_function_map[hwsettings_rcvrport]); + } + // Configure rcvrport PPM/PWM/OUTPUTS switch (hwsettings_rcvrport) { case HWSETTINGS_RM_RCVRPORT_PWM: #if defined(PIOS_INCLUDE_PWM) /* Set up the receiver port. Later this should be optional */ - PIOS_Board_configure_pwm(&pios_pwm_cfg); + PIOS_BOARD_IO_Configure_PWM(&pios_pwm_cfg); #endif /* PIOS_INCLUDE_PWM */ break; case HWSETTINGS_RM_RCVRPORT_PPM: @@ -1065,7 +318,7 @@ void PIOS_Board_Init(void) case HWSETTINGS_RM_RCVRPORT_PPMGPS: case HWSETTINGS_RM_RCVRPORT_PPMHOTTTELEMETRY: #if defined(PIOS_INCLUDE_PPM) - PIOS_Board_configure_ppm(&pios_ppm_cfg); + PIOS_BOARD_IO_Configure_PPM(&pios_ppm_cfg); if (hwsettings_rcvrport == HWSETTINGS_RM_RCVRPORT_PPMOUTPUTS) { // configure servo outputs and the remaining 5 inputs as outputs @@ -1074,7 +327,7 @@ void PIOS_Board_Init(void) // enable pwm on the remaining channels if (hwsettings_rcvrport == HWSETTINGS_RM_RCVRPORT_PPMPWM) { - PIOS_Board_configure_pwm(&pios_pwm_ppm_cfg); + PIOS_BOARD_IO_Configure_PWM(&pios_pwm_ppm_cfg); } break; @@ -1084,69 +337,9 @@ void PIOS_Board_Init(void) pios_servo_cfg = &pios_servo_cfg_out_in; break; } - - // Configure rcvrport usart - switch (hwsettings_rcvrport) { - case HWSETTINGS_RM_RCVRPORT_TELEMETRY: - case HWSETTINGS_RM_RCVRPORT_PPMTELEMETRY: - PIOS_Board_configure_com(&pios_usart_rcvrport_cfg, PIOS_COM_TELEM_RF_RX_BUF_LEN, PIOS_COM_TELEM_RF_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_telem_rf_id); - break; - case HWSETTINGS_RM_RCVRPORT_DEBUGCONSOLE: - case HWSETTINGS_RM_RCVRPORT_PPMDEBUGCONSOLE: -#if defined(PIOS_INCLUDE_DEBUG_CONSOLE) - PIOS_Board_configure_com(&pios_usart_rcvrport_cfg, 0, PIOS_COM_DEBUGCONSOLE_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_debug_id); -#endif /* PIOS_INCLUDE_DEBUG_CONSOLE */ - break; - case HWSETTINGS_RM_RCVRPORT_COMBRIDGE: - case HWSETTINGS_RM_RCVRPORT_PPMCOMBRIDGE: - PIOS_Board_configure_com(&pios_usart_rcvrport_cfg, PIOS_COM_BRIDGE_RX_BUF_LEN, PIOS_COM_BRIDGE_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_bridge_id); - break; - case HWSETTINGS_RM_RCVRPORT_MSP: - case HWSETTINGS_RM_RCVRPORT_PPMMSP: - PIOS_Board_configure_com(&pios_usart_rcvrport_cfg, PIOS_COM_MSP_RX_BUF_LEN, PIOS_COM_MSP_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_msp_id); - break; - case HWSETTINGS_RM_RCVRPORT_MAVLINK: - case HWSETTINGS_RM_RCVRPORT_PPMMAVLINK: - PIOS_Board_configure_com(&pios_usart_rcvrport_cfg, 0, PIOS_COM_MAVLINK_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_mavlink_id); - break; - case HWSETTINGS_RM_RCVRPORT_GPS: - case HWSETTINGS_RM_RCVRPORT_PPMGPS: - PIOS_Board_configure_com(&pios_usart_rcvrport_cfg, PIOS_COM_GPS_RX_BUF_LEN, PIOS_COM_GPS_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_gps_id); - break; - case HWSETTINGS_RM_RCVRPORT_HOTTTELEMETRY: - case HWSETTINGS_RM_RCVRPORT_PPMHOTTTELEMETRY: - PIOS_Board_configure_com(&pios_usart_rcvrport_cfg, PIOS_COM_HOTT_RX_BUF_LEN, PIOS_COM_HOTT_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_hott_id); - break; - case HWSETTINGS_RM_RCVRPORT_IBUS: -#if defined(PIOS_INCLUDE_IBUS) - PIOS_Board_configure_ibus(&pios_usart_ibus_rcvr_cfg); -#endif /* PIOS_INCLUDE_IBUS */ - break; - } - -#if defined(PIOS_INCLUDE_GCSRCVR) - GCSReceiverInitialize(); - uint32_t pios_gcsrcvr_id; - PIOS_GCSRCVR_Init(&pios_gcsrcvr_id); - uint32_t pios_gcsrcvr_rcvr_id; - if (PIOS_RCVR_Init(&pios_gcsrcvr_rcvr_id, &pios_gcsrcvr_rcvr_driver, pios_gcsrcvr_id)) { - PIOS_Assert(0); - } - pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_GCS] = pios_gcsrcvr_rcvr_id; -#endif /* PIOS_INCLUDE_GCSRCVR */ - -#if defined(PIOS_INCLUDE_OPLINKRCVR) - { - OPLinkReceiverInitialize(); - uint32_t pios_oplinkrcvr_id; - PIOS_OPLinkRCVR_Init(&pios_oplinkrcvr_id, pios_rfm22b_id); - uint32_t pios_oplinkrcvr_rcvr_id; - if (PIOS_RCVR_Init(&pios_oplinkrcvr_rcvr_id, &pios_oplinkrcvr_rcvr_driver, pios_oplinkrcvr_id)) { - PIOS_Assert(0); - } - pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_OPLINK] = pios_oplinkrcvr_rcvr_id; - } -#endif /* PIOS_INCLUDE_OPLINKRCVR */ +#ifdef PIOS_INCLUDE_GCSRCVR + PIOS_BOARD_IO_Configure_GCSRCVR(); +#endif #ifndef PIOS_ENABLE_DEBUG_PINS // pios_servo_cfg points to the correct configuration based on input port settings @@ -1155,76 +348,33 @@ void PIOS_Board_Init(void) PIOS_DEBUG_Init(pios_tim_servoport_all_pins, NELEMENTS(pios_tim_servoport_all_pins)); #endif - // Disable GPIO_A8 Pullup to prevent wrong results on battery voltage readout - GPIO_InitTypeDef gpioA8 = { - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_IN, - .GPIO_PuPd = GPIO_PuPd_NOPULL, - .GPIO_Pin = GPIO_Pin_8, - .GPIO_OType = GPIO_OType_OD, - }; - GPIO_Init(GPIOA, &gpioA8); - - // init I2C1 for use with the internal mag and baro - if (PIOS_I2C_Init(&pios_i2c_mag_pressure_adapter_id, &pios_i2c_mag_pressure_adapter_cfg)) { - PIOS_DEBUG_Assert(0); - } - PIOS_DELAY_WaitmS(50); - -#if defined(PIOS_INCLUDE_ADC) - PIOS_ADC_Init(&pios_adc_cfg); -#endif - #if defined(PIOS_INCLUDE_MPU6000) PIOS_MPU6000_Init(pios_spi_gyro_id, 0, &pios_mpu6000_cfg); PIOS_MPU6000_CONFIG_Configure(); PIOS_MPU6000_Register(); #endif -#ifdef PIOS_INCLUDE_WDG - // give HMC5x83 on I2C some extra time to allow for reset, etc. if needed - // this is not in a loop, so it is safe - // leave this here even if PIOS_INCLUDE_HMC5X83 is undefined - // to avoid making something else fail when HMC5X83 is removed - PIOS_WDG_Clear(); -#endif /* PIOS_INCLUDE_WDG */ - -#if defined(PIOS_INCLUDE_HMC5X83) - // attach the 5x83 mag to the previously inited I2C1 - onboard_mag = PIOS_HMC5x83_Init(&pios_hmc5x83_internal_cfg, pios_i2c_mag_pressure_adapter_id, 0); -#ifdef PIOS_INCLUDE_WDG - // give HMC5x83 on I2C some extra time to allow for reset, etc. if needed - // this is not in a loop, so it is safe - PIOS_WDG_Clear(); -#endif /* PIOS_INCLUDE_WDG */ - // add this sensor to the sensor task's list - PIOS_HMC5x83_Register(onboard_mag, PIOS_SENSORS_TYPE_3AXIS_MAG); -#endif - -#if defined(PIOS_INCLUDE_MS5611) - PIOS_MS5611_Init(&pios_ms5611_cfg, pios_i2c_mag_pressure_adapter_id); - PIOS_MS5611_Register(); -#endif - - #ifdef PIOS_INCLUDE_WS2811 -#include +#ifdef PIOS_INCLUDE_WS2811 HwSettingsWS2811LED_OutOptions ws2811_pin_settings; HwSettingsWS2811LED_OutGet(&ws2811_pin_settings); - + if (ws2811_pin_settings != HWSETTINGS_WS2811LED_OUT_DISABLED && ws2811_pin_settings < NELEMENTS(pios_ws2811_pin_cfg)) { PIOS_WS2811_Init(&pios_ws2811_cfg, &pios_ws2811_pin_cfg[ws2811_pin_settings]); } #endif // PIOS_INCLUDE_WS2811 + #ifdef PIOS_INCLUDE_ADC - { - uint8_t adc_config[HWSETTINGS_ADCROUTING_NUMELEM]; - HwSettingsADCRoutingArrayGet(adc_config); - for (uint32_t i = 0; i < HWSETTINGS_ADCROUTING_NUMELEM; i++) { - if (adc_config[i] != HWSETTINGS_ADCROUTING_DISABLED) { - PIOS_ADC_PinSetup(i); - } - } - } + // Disable GPIO_A8 Pullup to prevent wrong results on battery voltage readout + GPIO_InitTypeDef gpioA8 = { + .GPIO_Speed = GPIO_Speed_2MHz, + .GPIO_Mode = GPIO_Mode_IN, + .GPIO_PuPd = GPIO_PuPd_NOPULL, + .GPIO_Pin = GPIO_Pin_8, + .GPIO_OType = GPIO_OType_OD, + }; + GPIO_Init(GPIOA, &gpioA8); + + PIOS_BOARD_IO_Configure_ADC(); #endif // PIOS_INCLUDE_ADC DEBUG_PRINTF(2, "Board complete\r\n"); diff --git a/flight/targets/boards/revonano/board_hw_defs.c b/flight/targets/boards/revonano/board_hw_defs.c index 63f0199138..e84a8cc356 100644 --- a/flight/targets/boards/revonano/board_hw_defs.c +++ b/flight/targets/boards/revonano/board_hw_defs.c @@ -52,8 +52,8 @@ // Inverter for SBUS handling #define MAIN_USART_INVERTER_GPIO GPIOC #define MAIN_USART_INVERTER_PIN GPIO_Pin_15 -#define MAIN_USART_INVERTER_CLOCK_FUNC RCC_AHB1PeriphClockCmd -#define MAIN_USART_INVERTER_CLOCK_PERIPH RCC_AHB1Periph_GPIOC +#define MAIN_USART_INVERTER_ENABLE Bit_SET +#define MAIN_USART_INVERTER_DISABLE Bit_RESET #define FLEXI_USART_REGS USART1 #define FLEXI_USART_REMAP GPIO_AF_USART1 @@ -240,75 +240,15 @@ void PIOS_SPI_gyro_irq_handler(void) #include -#ifdef PIOS_INCLUDE_COM_TELEM - /* * MAIN USART */ -static const struct pios_usart_cfg pios_usart_main_cfg = { - .regs = MAIN_USART_REGS, - .remap = MAIN_USART_REMAP, - .init = { - .USART_BaudRate = 57600, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx | USART_Mode_Tx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = MAIN_USART_IRQ, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { - .gpio = MAIN_USART_RX_GPIO, - .init = { - .GPIO_Pin = MAIN_USART_RX_PIN, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, - .tx = { - .gpio = MAIN_USART_TX_GPIO, - .init = { - .GPIO_Pin = MAIN_USART_TX_PIN, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, -}; -#endif /* PIOS_INCLUDE_COM_TELEM */ -#ifdef PIOS_INCLUDE_DSM +static int32_t PIOS_BOARD_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param); -#include "pios_dsm_priv.h" -static const struct pios_usart_cfg pios_usart_dsm_main_cfg = { +static const struct pios_usart_cfg pios_usart_main_cfg = { .regs = MAIN_USART_REGS, .remap = MAIN_USART_REMAP, - .init = { - .USART_BaudRate = 115200, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = MAIN_USART_IRQ, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, .rx = { .gpio = MAIN_USART_RX_GPIO, .init = { @@ -329,472 +269,15 @@ static const struct pios_usart_cfg pios_usart_dsm_main_cfg = { .GPIO_PuPd = GPIO_PuPd_UP }, }, + .ioctl = PIOS_BOARD_USART_Ioctl, }; -// Because of the inverter on the main port this will not -// work. Notice the mode is set to IN to maintain API -// compatibility but protect the pins -static const struct pios_dsm_cfg pios_dsm_main_cfg = { - .bind = { - .gpio = MAIN_USART_RX_GPIO, - .init = { - .GPIO_Pin = MAIN_USART_RX_PIN, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_IN, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_NOPULL - }, - }, -}; - -#endif /* PIOS_INCLUDE_DSM */ - - -#include -#if defined(PIOS_INCLUDE_SBUS) -/* - * S.Bus USART - */ -#include - -static const struct pios_usart_cfg pios_usart_sbus_main_cfg = { - .regs = MAIN_USART_REGS, - .remap = MAIN_USART_REMAP, - .init = { - .USART_BaudRate = 99999, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_Even, - .USART_StopBits = USART_StopBits_2, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = MAIN_USART_IRQ, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { - .gpio = MAIN_USART_RX_GPIO, - .init = { - .GPIO_Pin = MAIN_USART_RX_PIN, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, - .tx = { - .gpio = MAIN_USART_TX_GPIO, - .init = { - .GPIO_Pin = MAIN_USART_TX_PIN, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_OUT, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_NOPULL - }, - }, -}; - -#endif /* PIOS_INCLUDE_SBUS */ - -// Need this defined regardless to be able to turn it off -static const struct pios_sbus_cfg pios_sbus_cfg = { - /* Inverter configuration */ - .inv = { - .gpio = MAIN_USART_INVERTER_GPIO, - .init = { - .GPIO_Pin = MAIN_USART_INVERTER_PIN, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_OUT, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, - .gpio_inv_enable = Bit_SET, - .gpio_inv_disable = Bit_RESET, - .gpio_clk_func = MAIN_USART_INVERTER_CLOCK_FUNC, - .gpio_clk_periph = MAIN_USART_INVERTER_CLOCK_PERIPH, -}; - - -#ifdef PIOS_INCLUDE_COM_FLEXI /* * FLEXI PORT */ static const struct pios_usart_cfg pios_usart_flexi_cfg = { .regs = FLEXI_USART_REGS, .remap = FLEXI_USART_REMAP, - .init = { - .USART_BaudRate = 57600, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = - USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx | USART_Mode_Tx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = FLEXI_USART_IRQ, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { - .gpio = FLEXI_USART_RX_GPIO, - .init = { - .GPIO_Pin = FLEXI_USART_RX_PIN, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, - .tx = { - .gpio = FLEXI_USART_TX_GPIO, - .init = { - .GPIO_Pin = FLEXI_USART_TX_PIN, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, - .dtr = { - .gpio = FLEXI_USART_DTR_GPIO, - .init = { - .GPIO_Pin = FLEXI_USART_DTR_PIN, - .GPIO_Speed = GPIO_Speed_25MHz, - .GPIO_Mode = GPIO_Mode_OUT, - .GPIO_OType = GPIO_OType_PP, - }, - }, -}; - -#endif /* PIOS_INCLUDE_COM_FLEXI */ - -#ifdef PIOS_INCLUDE_DSM - -#include "pios_dsm_priv.h" -static const struct pios_usart_cfg pios_usart_dsm_flexi_cfg = { - .regs = FLEXI_USART_REGS, - .remap = FLEXI_USART_REMAP, - .init = { - .USART_BaudRate = 115200, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = FLEXI_USART_IRQ, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { - .gpio = FLEXI_USART_RX_GPIO, - .init = { - .GPIO_Pin = FLEXI_USART_RX_PIN, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, - .tx = { - .gpio = FLEXI_USART_TX_GPIO, - .init = { - .GPIO_Pin = FLEXI_USART_TX_PIN, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, -}; - -static const struct pios_dsm_cfg pios_dsm_flexi_cfg = { - .bind = { - .gpio = FLEXI_USART_RX_GPIO, - .init = { - .GPIO_Pin = FLEXI_USART_RX_PIN, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_OUT, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_NOPULL - }, - }, -}; - -#endif /* PIOS_INCLUDE_DSM */ - -#if defined(PIOS_INCLUDE_HOTT) -/* - * HOTT USART - */ -#include - -static const struct pios_usart_cfg pios_usart_hott_flexi_cfg = { - .regs = FLEXI_USART_REGS, - .remap = FLEXI_USART_REMAP, - .init = { - .USART_BaudRate = 115200, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = FLEXI_USART_IRQ, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { - .gpio = FLEXI_USART_RX_GPIO, - .init = { - .GPIO_Pin = FLEXI_USART_RX_PIN, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, - .tx = { - .gpio = FLEXI_USART_TX_GPIO, - .init = { - .GPIO_Pin = FLEXI_USART_TX_PIN, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_OUT, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, -}; - -#endif /* PIOS_INCLUDE_HOTT */ - -#if defined(PIOS_INCLUDE_SRXL) -/* - * SRXL USART - */ -#include - -static const struct pios_usart_cfg pios_usart_srxl_flexi_cfg = { - .regs = FLEXI_USART_REGS, - .remap = FLEXI_USART_REMAP, - .init = { - .USART_BaudRate = 115200, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = FLEXI_USART_IRQ, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { - .gpio = FLEXI_USART_RX_GPIO, - .init = { - .GPIO_Pin = FLEXI_USART_RX_PIN, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, - .tx = { - .gpio = FLEXI_USART_TX_GPIO, - .init = { - .GPIO_Pin = FLEXI_USART_TX_PIN, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_OUT, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, -}; - -#endif /* PIOS_INCLUDE_SRXL */ - -#if defined(PIOS_INCLUDE_IBUS) -/* - * IBUS USART - */ -#include - -static const struct pios_usart_cfg pios_usart_ibus_flexi_cfg = { - .regs = FLEXI_USART_REGS, - .remap = FLEXI_USART_REMAP, - .init = { - .USART_BaudRate = 115200, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = FLEXI_USART_IRQ, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { - .gpio = FLEXI_USART_RX_GPIO, - .init = { - .GPIO_Pin = FLEXI_USART_RX_PIN, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, - .tx = { - .gpio = FLEXI_USART_TX_GPIO, - .init = { - .GPIO_Pin = FLEXI_USART_TX_PIN, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_OUT, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, -}; - -#endif /* PIOS_INCLUDE_IBUS */ - -#if defined(PIOS_INCLUDE_EXBUS) -/* - * EXBUS USART - */ -#include - -static const struct pios_usart_cfg pios_usart_exbus_flexi_cfg = { - .regs = FLEXI_USART_REGS, - .remap = FLEXI_USART_REMAP, - .init = { - .USART_BaudRate = 125000, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = FLEXI_USART_IRQ, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { - .gpio = FLEXI_USART_RX_GPIO, - .init = { - .GPIO_Pin = FLEXI_USART_RX_PIN, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, - .tx = { - .gpio = FLEXI_USART_TX_GPIO, - .init = { - .GPIO_Pin = FLEXI_USART_TX_PIN, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_OUT, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, -}; - -#endif /* PIOS_INCLUDE_EXBUS */ - -/* - * HK OSD - */ -static const struct pios_usart_cfg pios_usart_hkosd_main_cfg = { - .regs = MAIN_USART_REGS, - .remap = MAIN_USART_REMAP, - .init = { - .USART_BaudRate = 57600, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx | USART_Mode_Tx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = MAIN_USART_IRQ, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { - .gpio = MAIN_USART_RX_GPIO, - .init = { - .GPIO_Pin = MAIN_USART_RX_PIN, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, - .tx = { - .gpio = MAIN_USART_TX_GPIO, - .init = { - .GPIO_Pin = MAIN_USART_TX_PIN, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, -}; - -static const struct pios_usart_cfg pios_usart_hkosd_flexi_cfg = { - .regs = FLEXI_USART_REGS, - .remap = FLEXI_USART_REMAP, - .init = { - .USART_BaudRate = 57600, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx | USART_Mode_Tx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = FLEXI_USART_IRQ, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, .rx = { .gpio = FLEXI_USART_RX_GPIO, .init = { @@ -815,6 +298,15 @@ static const struct pios_usart_cfg pios_usart_hkosd_flexi_cfg = { .GPIO_PuPd = GPIO_PuPd_UP }, }, +// .dtr = { +// .gpio = FLEXI_USART_DTR_GPIO, +// .init = { +// .GPIO_Pin = FLEXI_USART_DTR_PIN, +// .GPIO_Speed = GPIO_Speed_25MHz, +// .GPIO_Mode = GPIO_Mode_OUT, +// .GPIO_OType = GPIO_OType_PP, +// }, +// }, }; #if defined(PIOS_INCLUDE_COM) @@ -1347,37 +839,6 @@ const struct pios_usb_cfg *PIOS_BOARD_HW_DEFS_GetUsbCfg(uint32_t board_revision) #endif /* PIOS_INCLUDE_COM_MSG */ -#if defined(PIOS_INCLUDE_USB_HID) && !defined(PIOS_INCLUDE_USB_CDC) -#include - -const struct pios_usb_hid_cfg pios_usb_hid_cfg = { - .data_if = 0, - .data_rx_ep = 1, - .data_tx_ep = 1, -}; -#endif /* PIOS_INCLUDE_USB_HID && !PIOS_INCLUDE_USB_CDC */ - -#if defined(PIOS_INCLUDE_USB_HID) && defined(PIOS_INCLUDE_USB_CDC) -#include - -const struct pios_usb_cdc_cfg pios_usb_cdc_cfg = { - .ctrl_if = 0, - .ctrl_tx_ep = 2, - - .data_if = 1, - .data_rx_ep = 3, - .data_tx_ep = 3, -}; - -#include - -const struct pios_usb_hid_cfg pios_usb_hid_cfg = { - .data_if = 2, - .data_rx_ep = 1, - .data_tx_ep = 1, -}; -#endif /* PIOS_INCLUDE_USB_HID && PIOS_INCLUDE_USB_CDC */ - #ifdef PIOS_INCLUDE_WS2811 #include #include @@ -1470,3 +931,143 @@ struct pios_flash_eeprom_cfg flash_main_chip_cfg = { }; // .i2c_address = 0x50, #endif /* PIOS_INCLUDE_FLASH_EEPROM */ + +/** + * Sensor configurations + */ + + + +#if defined(PIOS_INCLUDE_ADC) + +#include "pios_adc_priv.h" +void PIOS_ADC_DMC_irq_handler(void); +void DMA2_Stream4_IRQHandler(void) __attribute__((alias("PIOS_ADC_DMC_irq_handler"))); +struct pios_adc_cfg pios_adc_cfg = { + .adc_dev = ADC1, + .dma = { + .irq = { + .flags = (DMA_FLAG_TCIF4 | DMA_FLAG_TEIF4 | DMA_FLAG_HTIF4), + .init = { + .NVIC_IRQChannel = DMA2_Stream4_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_LOW, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, + .rx = { + .channel = DMA2_Stream4, + .init = { + .DMA_Channel = DMA_Channel_0, + .DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR + }, + } + }, + .half_flag = DMA_IT_HTIF4, + .full_flag = DMA_IT_TCIF4, +}; +void PIOS_ADC_DMC_irq_handler(void) +{ + /* Call into the generic code to handle the IRQ for this specific device */ + PIOS_ADC_DMA_Handler(); +} + +const struct pios_adc_cfg *PIOS_BOARD_HW_DEFS_GetAdcCfg(__attribute__((unused)) uint32_t board_revision) +{ + return &pios_adc_cfg; +} +#endif /* if defined(PIOS_INCLUDE_ADC) */ + +#if defined(PIOS_INCLUDE_HMC5X83) +#include "pios_hmc5x83.h" + +static const struct pios_hmc5x83_cfg pios_hmc5x83_external_cfg = { +#ifdef PIOS_HMC5X83_HAS_GPIOS + .exti_cfg = NULL, +#endif + .M_ODR = PIOS_HMC5x83_ODR_75, // if you change this for auxmag, change AUX_MAG_SKIP in sensors.c + .Meas_Conf = PIOS_HMC5x83_MEASCONF_NORMAL, + .Gain = PIOS_HMC5x83_GAIN_1_9, + .Mode = PIOS_HMC5x83_MODE_CONTINUOUS, + .TempCompensation = false, + .Driver = &PIOS_HMC5x83_I2C_DRIVER, + .Orientation = PIOS_HMC5X83_ORIENTATION_EAST_NORTH_UP, // ENU for GPSV9, WND for typical I2C mag +}; + +const struct pios_hmc5x83_cfg *PIOS_BOARD_HW_DEFS_GetExternalHMC5x83Cfg(__attribute__((unused)) uint32_t board_revision) +{ + return &pios_hmc5x83_external_cfg; +} +#endif /* PIOS_INCLUDE_HMC5X83 */ + +/** + * Configuration for the MS5611 chip + */ +#if defined(PIOS_INCLUDE_MS5611) +#include "pios_ms5611.h" +static const struct pios_ms5611_cfg pios_ms5611_cfg = { + .oversampling = MS5611_OSR_4096, +}; +const struct pios_ms5611_cfg *PIOS_BOARD_HW_DEFS_GetMS5611Cfg(__attribute__((unused)) uint32_t board_revision) +{ + return &pios_ms5611_cfg; +} +#endif /* PIOS_INCLUDE_MS5611 */ + +/** + * Configuration for the MPU9250 chip + */ +#if defined(PIOS_INCLUDE_MPU9250) +#include "pios_mpu9250.h" +#include "pios_mpu9250_config.h" +static const struct pios_exti_cfg pios_exti_mpu9250_cfg __exti_config = { + .vector = PIOS_MPU9250_IRQHandler, + .line = EXTI_Line15, + .pin = { + .gpio = GPIOA, + .init = { + .GPIO_Pin = GPIO_Pin_15, + .GPIO_Speed = GPIO_Speed_100MHz, + .GPIO_Mode = GPIO_Mode_IN, + .GPIO_OType = GPIO_OType_OD, + .GPIO_PuPd = GPIO_PuPd_NOPULL, + }, + }, + .irq = { + .init = { + .NVIC_IRQChannel = EXTI15_10_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, + .exti = { + .init = { + .EXTI_Line = EXTI_Line15, // matches above GPIO pin + .EXTI_Mode = EXTI_Mode_Interrupt, + .EXTI_Trigger = EXTI_Trigger_Rising, + .EXTI_LineCmd = ENABLE, + }, + }, +}; + +static const struct pios_mpu9250_cfg pios_mpu9250_cfg = { + .exti_cfg = &pios_exti_mpu9250_cfg, + .Fifo_store = 0, + // Clock at 8 khz + .Smpl_rate_div_no_dlp = 0, + // with dlp on output rate is 1000Hz + .Smpl_rate_div_dlp = 0, + .interrupt_cfg = PIOS_MPU9250_INT_CLR_ANYRD, // | PIOS_MPU9250_INT_LATCH_EN, + .interrupt_en = PIOS_MPU9250_INTEN_DATA_RDY, + .User_ctl = PIOS_MPU9250_USERCTL_DIS_I2C | PIOS_MPU9250_USERCTL_I2C_MST_EN, + .Pwr_mgmt_clk = PIOS_MPU9250_PWRMGMT_PLL_Z_CLK, + .accel_range = PIOS_MPU9250_ACCEL_8G, + .gyro_range = PIOS_MPU9250_SCALE_2000_DEG, + .filter = PIOS_MPU9250_LOWPASS_256_HZ, + .orientation = PIOS_MPU9250_TOP_180DEG, + .fast_prescaler = PIOS_SPI_PRESCALER_4, + .std_prescaler = PIOS_SPI_PRESCALER_64, + .max_downsample = 26, +}; +#endif /* PIOS_INCLUDE_MPU9250 */ diff --git a/flight/targets/boards/revonano/bootloader/pios_board.c b/flight/targets/boards/revonano/bootloader/pios_board.c index 5352c7f73b..595eac507f 100644 --- a/flight/targets/boards/revonano/bootloader/pios_board.c +++ b/flight/targets/boards/revonano/bootloader/pios_board.c @@ -25,6 +25,7 @@ #include #include +#include /* * Pull in the board-specific static HW definitions. @@ -39,6 +40,12 @@ uint32_t pios_com_telem_usb_id; static bool board_init_complete = false; + +static int32_t PIOS_BOARD_USART_Ioctl(__attribute__((unused)) uint32_t usart_id, __attribute__((unused)) uint32_t ctl, __attribute__((unused)) void *param) +{ + return -1; +} + void PIOS_Board_Init() { if (board_init_complete) { @@ -68,7 +75,7 @@ void PIOS_Board_Init() #if defined(PIOS_INCLUDE_USB_HID) && defined(PIOS_INCLUDE_COM_MSG) uint32_t pios_usb_hid_id; - if (PIOS_USB_HID_Init(&pios_usb_hid_id, &pios_usb_hid_cfg, pios_usb_id)) { + if (PIOS_USB_HID_Init(&pios_usb_hid_id, &pios_usb_hid_only_cfg, pios_usb_id)) { PIOS_Assert(0); } if (PIOS_COM_MSG_Init(&pios_com_telem_usb_id, &pios_usb_hid_com_driver, pios_usb_hid_id)) { diff --git a/flight/targets/boards/revonano/firmware/pios_board.c b/flight/targets/boards/revonano/firmware/pios_board.c index 0de1b0eed1..6d95791f4b 100644 --- a/flight/targets/boards/revonano/firmware/pios_board.c +++ b/flight/targets/boards/revonano/firmware/pios_board.c @@ -30,21 +30,18 @@ #include #include #include -#include -#include -#include -#include -#include #include #include -#include -#include -#include + +#include "sanitycheck.h" +#include "actuatorsettings.h" #ifdef PIOS_INCLUDE_INSTRUMENTATION #include #endif +#include + /* * Pull in the board-specific static HW definitions. * Including .c files is a bit ugly but this allows all of @@ -55,300 +52,69 @@ */ #include "../board_hw_defs.c" +uintptr_t pios_uavo_settings_fs_id; +uintptr_t pios_user_fs_id; + static SystemAlarmsExtendedAlarmStatusOptions RevoNanoConfigHook(); static void ActuatorSettingsUpdatedCb(UAVObjEvent *ev); -/** - * Sensor configurations - */ - -#if defined(PIOS_INCLUDE_ADC) - -#include "pios_adc_priv.h" -void PIOS_ADC_DMC_irq_handler(void); -void DMA2_Stream4_IRQHandler(void) __attribute__((alias("PIOS_ADC_DMC_irq_handler"))); -struct pios_adc_cfg pios_adc_cfg = { - .adc_dev = ADC1, - .dma = { - .irq = { - .flags = (DMA_FLAG_TCIF4 | DMA_FLAG_TEIF4 | DMA_FLAG_HTIF4), - .init = { - .NVIC_IRQChannel = DMA2_Stream4_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_LOW, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { - .channel = DMA2_Stream4, - .init = { - .DMA_Channel = DMA_Channel_0, - .DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR - }, - } - }, - .half_flag = DMA_IT_HTIF4, - .full_flag = DMA_IT_TCIF4, -}; -void PIOS_ADC_DMC_irq_handler(void) -{ - /* Call into the generic code to handle the IRQ for this specific device */ - PIOS_ADC_DMA_Handler(); -} -#endif /* if defined(PIOS_INCLUDE_ADC) */ - -#if defined(PIOS_INCLUDE_HMC5X83) -#include "pios_hmc5x83.h" -pios_hmc5x83_dev_t external_mag = 0; - -static const struct pios_hmc5x83_cfg pios_hmc5x83_external_cfg = { -#ifdef PIOS_HMC5X83_HAS_GPIOS - .exti_cfg = NULL, -#endif - .M_ODR = PIOS_HMC5x83_ODR_75, // if you change this for auxmag, change AUX_MAG_SKIP in sensors.c - .Meas_Conf = PIOS_HMC5x83_MEASCONF_NORMAL, - .Gain = PIOS_HMC5x83_GAIN_1_9, - .Mode = PIOS_HMC5x83_MODE_CONTINUOUS, - .TempCompensation = false, - .Driver = &PIOS_HMC5x83_I2C_DRIVER, - .Orientation = PIOS_HMC5X83_ORIENTATION_EAST_NORTH_UP, // ENU for GPSV9, WND for typical I2C mag -}; -#endif /* PIOS_INCLUDE_HMC5X83 */ /** - * Configuration for the MS5611 chip + * PIOS_Board_Init() + * initializes all the core subsystems on this specific hardware + * called from System/openpilot.c */ -#if defined(PIOS_INCLUDE_MS5611) -#include "pios_ms5611.h" -static const struct pios_ms5611_cfg pios_ms5611_cfg = { - .oversampling = MS5611_OSR_4096, -}; -#endif /* PIOS_INCLUDE_MS5611 */ -/** - * Configuration for the MPU9250 chip - */ -#if defined(PIOS_INCLUDE_MPU9250) -#include "pios_mpu9250.h" -#include "pios_mpu9250_config.h" -static const struct pios_exti_cfg pios_exti_mpu9250_cfg __exti_config = { - .vector = PIOS_MPU9250_IRQHandler, - .line = EXTI_Line15, - .pin = { - .gpio = GPIOA, - .init = { - .GPIO_Pin = GPIO_Pin_15, - .GPIO_Speed = GPIO_Speed_100MHz, - .GPIO_Mode = GPIO_Mode_IN, - .GPIO_OType = GPIO_OType_OD, - .GPIO_PuPd = GPIO_PuPd_NOPULL, - }, - }, - .irq = { - .init = { - .NVIC_IRQChannel = EXTI15_10_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .exti = { - .init = { - .EXTI_Line = EXTI_Line15, // matches above GPIO pin - .EXTI_Mode = EXTI_Mode_Interrupt, - .EXTI_Trigger = EXTI_Trigger_Rising, - .EXTI_LineCmd = ENABLE, - }, - }, -}; +#include -static const struct pios_mpu9250_cfg pios_mpu9250_cfg = { - .exti_cfg = &pios_exti_mpu9250_cfg, - .Fifo_store = 0, - // Clock at 8 khz - .Smpl_rate_div_no_dlp = 0, - // with dlp on output rate is 1000Hz - .Smpl_rate_div_dlp = 0, - .interrupt_cfg = PIOS_MPU9250_INT_CLR_ANYRD, // | PIOS_MPU9250_INT_LATCH_EN, - .interrupt_en = PIOS_MPU9250_INTEN_DATA_RDY, - .User_ctl = PIOS_MPU9250_USERCTL_DIS_I2C | PIOS_MPU9250_USERCTL_I2C_MST_EN, - .Pwr_mgmt_clk = PIOS_MPU9250_PWRMGMT_PLL_Z_CLK, - .accel_range = PIOS_MPU9250_ACCEL_8G, - .gyro_range = PIOS_MPU9250_SCALE_2000_DEG, - .filter = PIOS_MPU9250_LOWPASS_256_HZ, - .orientation = PIOS_MPU9250_TOP_180DEG, - .fast_prescaler = PIOS_SPI_PRESCALER_4, - .std_prescaler = PIOS_SPI_PRESCALER_64, - .max_downsample = 26, +static const PIOS_BOARD_IO_UART_Function flexi_function_map[] = { + [HWSETTINGS_RM_FLEXIPORT_TELEMETRY] = PIOS_BOARD_IO_UART_TELEMETRY, + [HWSETTINGS_RM_FLEXIPORT_GPS] = PIOS_BOARD_IO_UART_GPS, + [HWSETTINGS_RM_FLEXIPORT_DSM] = PIOS_BOARD_IO_UART_DSM_FLEXI, + [HWSETTINGS_RM_FLEXIPORT_EXBUS] = PIOS_BOARD_IO_UART_EXBUS, + [HWSETTINGS_RM_FLEXIPORT_HOTTSUMD] = PIOS_BOARD_IO_UART_HOTT_SUMD, + [HWSETTINGS_RM_FLEXIPORT_HOTTSUMH] = PIOS_BOARD_IO_UART_HOTT_SUMH, + [HWSETTINGS_RM_FLEXIPORT_SRXL] = PIOS_BOARD_IO_UART_SRXL, + [HWSETTINGS_RM_FLEXIPORT_IBUS] = PIOS_BOARD_IO_UART_IBUS, + [HWSETTINGS_RM_FLEXIPORT_DEBUGCONSOLE] = PIOS_BOARD_IO_UART_DEBUGCONSOLE, + [HWSETTINGS_RM_FLEXIPORT_COMBRIDGE] = PIOS_BOARD_IO_UART_COMBRIDGE, + [HWSETTINGS_RM_FLEXIPORT_OSDHK] = PIOS_BOARD_IO_UART_OSDHK, + [HWSETTINGS_RM_FLEXIPORT_MSP] = PIOS_BOARD_IO_UART_MSP, + [HWSETTINGS_RM_FLEXIPORT_MAVLINK] = PIOS_BOARD_IO_UART_MAVLINK, }; -#endif /* PIOS_INCLUDE_MPU9250 */ - - -/* One slot per selectable receiver group. - * eg. PWM, PPM, GCS, SPEKTRUM1, SPEKTRUM2, SBUS - * NOTE: No slot in this map for NONE. - */ -uint32_t pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_NONE]; - -#define PIOS_COM_TELEM_RF_RX_BUF_LEN 512 -#define PIOS_COM_TELEM_RF_TX_BUF_LEN 512 - -#define PIOS_COM_GPS_RX_BUF_LEN 128 -#define PIOS_COM_GPS_TX_BUF_LEN 32 - -#define PIOS_COM_TELEM_USB_RX_BUF_LEN 65 -#define PIOS_COM_TELEM_USB_TX_BUF_LEN 65 - -#define PIOS_COM_BRIDGE_RX_BUF_LEN 65 -#define PIOS_COM_BRIDGE_TX_BUF_LEN 12 - -#define PIOS_COM_RFM22B_RF_RX_BUF_LEN 512 -#define PIOS_COM_RFM22B_RF_TX_BUF_LEN 512 - -#define PIOS_COM_HKOSD_RX_BUF_LEN 22 -#define PIOS_COM_HKOSD_TX_BUF_LEN 22 - -#define PIOS_COM_MSP_TX_BUF_LEN 128 -#define PIOS_COM_MSP_RX_BUF_LEN 64 - -#define PIOS_COM_MAVLINK_TX_BUF_LEN 128 - -#if defined(PIOS_INCLUDE_DEBUG_CONSOLE) -#define PIOS_COM_DEBUGCONSOLE_TX_BUF_LEN 40 -uint32_t pios_com_debug_id; -#endif /* PIOS_INCLUDE_DEBUG_CONSOLE */ - -uint32_t pios_com_gps_id = 0; -uint32_t pios_com_telem_usb_id = 0; -uint32_t pios_com_telem_rf_id = 0; -uint32_t pios_com_rf_id = 0; -uint32_t pios_com_bridge_id = 0; -uint32_t pios_com_overo_id = 0; -uint32_t pios_com_hkosd_id = 0; -uint32_t pios_com_msp_id = 0; -uint32_t pios_com_vcp_id = 0; -uint32_t pios_com_mavlink_id = 0; - -uintptr_t pios_uavo_settings_fs_id; -uintptr_t pios_user_fs_id; - -/* - * Setup a com port based on the passed cfg, driver and buffer sizes. - * tx size = 0 make the port rx only - * rx size = 0 make the port tx only - * having both tx and rx size = 0 is not valid and will fail further down in PIOS_COM_Init() - */ -static void PIOS_Board_configure_com(const struct pios_usart_cfg *usart_port_cfg, uint16_t rx_buf_len, uint16_t tx_buf_len, - const struct pios_com_driver *com_driver, uint32_t *pios_com_id) -{ - uint32_t pios_usart_id; - - if (PIOS_USART_Init(&pios_usart_id, usart_port_cfg)) { - PIOS_Assert(0); - } - - uint8_t *rx_buffer = 0, *tx_buffer = 0; - - if (rx_buf_len > 0) { - rx_buffer = (uint8_t *)pios_malloc(rx_buf_len); - PIOS_Assert(rx_buffer); - } - - if (tx_buf_len > 0) { - tx_buffer = (uint8_t *)pios_malloc(tx_buf_len); - PIOS_Assert(tx_buffer); - } - - if (PIOS_COM_Init(pios_com_id, com_driver, pios_usart_id, - rx_buffer, rx_buf_len, - tx_buffer, tx_buf_len)) { - PIOS_Assert(0); - } -} - -static void PIOS_Board_configure_dsm(const struct pios_usart_cfg *pios_usart_dsm_cfg, const struct pios_dsm_cfg *pios_dsm_cfg, - const struct pios_com_driver *usart_com_driver, - ManualControlSettingsChannelGroupsOptions channelgroup, uint8_t *bind) -{ - uint32_t pios_usart_dsm_id; - - if (PIOS_USART_Init(&pios_usart_dsm_id, pios_usart_dsm_cfg)) { - PIOS_Assert(0); - } - - uint32_t pios_dsm_id; - if (PIOS_DSM_Init(&pios_dsm_id, pios_dsm_cfg, usart_com_driver, - pios_usart_dsm_id, *bind)) { - PIOS_Assert(0); - } - - uint32_t pios_dsm_rcvr_id; - if (PIOS_RCVR_Init(&pios_dsm_rcvr_id, &pios_dsm_rcvr_driver, pios_dsm_id)) { - PIOS_Assert(0); - } - pios_rcvr_group_map[channelgroup] = pios_dsm_rcvr_id; -} - -static void PIOS_Board_configure_ibus(const struct pios_usart_cfg *usart_cfg) -{ - uint32_t pios_usart_ibus_id; - - if (PIOS_USART_Init(&pios_usart_ibus_id, usart_cfg)) { - PIOS_Assert(0); - } - - uint32_t pios_ibus_id; - if (PIOS_IBUS_Init(&pios_ibus_id, &pios_usart_com_driver, pios_usart_ibus_id)) { - PIOS_Assert(0); - } - - uint32_t pios_ibus_rcvr_id; - if (PIOS_RCVR_Init(&pios_ibus_rcvr_id, &pios_ibus_rcvr_driver, pios_ibus_id)) { - PIOS_Assert(0); - } - - pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_IBUS] = pios_ibus_rcvr_id; -} - -static void PIOS_Board_configure_pwm(const struct pios_pwm_cfg *pwm_cfg) -{ - /* Set up the receiver port. Later this should be optional */ - uint32_t pios_pwm_id; - PIOS_PWM_Init(&pios_pwm_id, pwm_cfg); - - uint32_t pios_pwm_rcvr_id; - if (PIOS_RCVR_Init(&pios_pwm_rcvr_id, &pios_pwm_rcvr_driver, pios_pwm_id)) { - PIOS_Assert(0); - } - pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_PWM] = pios_pwm_rcvr_id; -} +static const PIOS_BOARD_IO_UART_Function main_function_map[] = { + [HWSETTINGS_RM_MAINPORT_TELEMETRY] = PIOS_BOARD_IO_UART_TELEMETRY, + [HWSETTINGS_RM_MAINPORT_GPS] = PIOS_BOARD_IO_UART_GPS, + [HWSETTINGS_RM_MAINPORT_SBUS] = PIOS_BOARD_IO_UART_SBUS, + [HWSETTINGS_RM_MAINPORT_DSM] = PIOS_BOARD_IO_UART_DSM_MAIN, + [HWSETTINGS_RM_MAINPORT_DEBUGCONSOLE] = PIOS_BOARD_IO_UART_DEBUGCONSOLE, + [HWSETTINGS_RM_MAINPORT_COMBRIDGE] = PIOS_BOARD_IO_UART_COMBRIDGE, + [HWSETTINGS_RM_MAINPORT_OSDHK] = PIOS_BOARD_IO_UART_OSDHK, + [HWSETTINGS_RM_MAINPORT_MSP] = PIOS_BOARD_IO_UART_MSP, + [HWSETTINGS_RM_MAINPORT_MAVLINK] = PIOS_BOARD_IO_UART_MAVLINK, +}; -static void PIOS_Board_configure_ppm(const struct pios_ppm_cfg *ppm_cfg) +int32_t PIOS_BOARD_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param) { - uint32_t pios_ppm_id; - - PIOS_PPM_Init(&pios_ppm_id, ppm_cfg); - - uint32_t pios_ppm_rcvr_id; - if (PIOS_RCVR_Init(&pios_ppm_rcvr_id, &pios_ppm_rcvr_driver, pios_ppm_id)) { - PIOS_Assert(0); + const struct pios_usart_cfg *usart_cfg = PIOS_USART_GetConfig(usart_id); + + switch (ctl) { + case PIOS_IOCTL_USART_SET_INVERTED: + if (usart_cfg->regs == pios_usart_main_cfg.regs) { /* main port */ + GPIO_WriteBit(MAIN_USART_INVERTER_GPIO, + MAIN_USART_INVERTER_PIN, + (*(enum PIOS_USART_Inverted *)param & PIOS_USART_Inverted_Rx) ? MAIN_USART_INVERTER_ENABLE : MAIN_USART_INVERTER_DISABLE); + + return 0; + } + break; } - pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_PPM] = pios_ppm_rcvr_id; + + return -1; } -/** - * PIOS_Board_Init() - * initializes all the core subsystems on this specific hardware - * called from System/openpilot.c - */ - -#include - void PIOS_Board_Init(void) { - /* Delay system */ - PIOS_DELAY_Init(); - const struct pios_board_info *bdinfo = &pios_board_info_blob; #if defined(PIOS_INCLUDE_LED) @@ -425,10 +191,6 @@ void PIOS_Board_Init(void) EventDispatcherInitialize(); UAVObjInitialize(); HwSettingsInitialize(); -#if defined(PIOS_INCLUDE_RFM22B) - OPLinkSettingsInitialize(); - OPLinkStatusInitialize(); -#endif /* PIOS_INCLUDE_RFM22B */ /* Initialize the alarms library */ AlarmsInitialize(); @@ -451,365 +213,43 @@ void PIOS_Board_Init(void) HwSettingsSetDefaults(HwSettingsHandle(), 0); AlarmsSet(SYSTEMALARMS_ALARM_BOOTFAULT, SYSTEMALARMS_ALARM_CRITICAL); } - - - // PIOS_IAP_Init(); - + #if defined(PIOS_INCLUDE_USB) - /* Initialize board specific USB data */ - PIOS_USB_BOARD_DATA_Init(); - - /* Flags to determine if various USB interfaces are advertised */ - bool usb_hid_present = false; - bool usb_cdc_present = false; - -#if defined(PIOS_INCLUDE_USB_CDC) - if (PIOS_USB_DESC_HID_CDC_Init()) { - PIOS_Assert(0); - } - usb_hid_present = true; - usb_cdc_present = true; -#else - if (PIOS_USB_DESC_HID_ONLY_Init()) { - PIOS_Assert(0); - } - usb_hid_present = true; + PIOS_BOARD_IO_Configure_USB(); #endif - uint32_t pios_usb_id; - PIOS_USB_Init(&pios_usb_id, PIOS_BOARD_HW_DEFS_GetUsbCfg(bdinfo->board_rev)); - -#if defined(PIOS_INCLUDE_USB_CDC) - - uint8_t hwsettings_usb_vcpport; - /* Configure the USB VCP port */ - HwSettingsUSB_VCPPortGet(&hwsettings_usb_vcpport); - - if (!usb_cdc_present) { - /* Force VCP port function to disabled if we haven't advertised VCP in our USB descriptor */ - hwsettings_usb_vcpport = HWSETTINGS_USB_VCPPORT_DISABLED; - } - uint32_t pios_usb_cdc_id; - if (PIOS_USB_CDC_Init(&pios_usb_cdc_id, &pios_usb_cdc_cfg, pios_usb_id)) { - PIOS_Assert(0); - } - - uint32_t pios_usb_hid_id; - if (PIOS_USB_HID_Init(&pios_usb_hid_id, &pios_usb_hid_cfg, pios_usb_id)) { - PIOS_Assert(0); - } - - switch (hwsettings_usb_vcpport) { - case HWSETTINGS_USB_VCPPORT_DISABLED: - break; - case HWSETTINGS_USB_VCPPORT_USBTELEMETRY: -#if defined(PIOS_INCLUDE_COM) - { - uint8_t *rx_buffer = (uint8_t *)pios_malloc(PIOS_COM_TELEM_USB_RX_BUF_LEN); - uint8_t *tx_buffer = (uint8_t *)pios_malloc(PIOS_COM_TELEM_USB_TX_BUF_LEN); - PIOS_Assert(rx_buffer); - PIOS_Assert(tx_buffer); - if (PIOS_COM_Init(&pios_com_telem_usb_id, &pios_usb_cdc_com_driver, pios_usb_cdc_id, - rx_buffer, PIOS_COM_TELEM_USB_RX_BUF_LEN, - tx_buffer, PIOS_COM_TELEM_USB_TX_BUF_LEN)) { - PIOS_Assert(0); - } - } -#endif /* PIOS_INCLUDE_COM */ - break; - case HWSETTINGS_USB_VCPPORT_COMBRIDGE: -#if defined(PIOS_INCLUDE_COM) - { - uint8_t *rx_buffer = (uint8_t *)pios_malloc(PIOS_COM_BRIDGE_RX_BUF_LEN); - uint8_t *tx_buffer = (uint8_t *)pios_malloc(PIOS_COM_BRIDGE_TX_BUF_LEN); - PIOS_Assert(rx_buffer); - PIOS_Assert(tx_buffer); - if (PIOS_COM_Init(&pios_com_vcp_id, &pios_usb_cdc_com_driver, pios_usb_cdc_id, - rx_buffer, PIOS_COM_BRIDGE_RX_BUF_LEN, - tx_buffer, PIOS_COM_BRIDGE_TX_BUF_LEN)) { - PIOS_Assert(0); - } - } -#endif /* PIOS_INCLUDE_COM */ - break; - case HWSETTINGS_USB_VCPPORT_DEBUGCONSOLE: -#if defined(PIOS_INCLUDE_COM) -#if defined(PIOS_INCLUDE_DEBUG_CONSOLE) - { - uint8_t *tx_buffer = (uint8_t *)pios_malloc(PIOS_COM_DEBUGCONSOLE_TX_BUF_LEN); - PIOS_Assert(tx_buffer); - if (PIOS_COM_Init(&pios_com_debug_id, &pios_usb_cdc_com_driver, pios_usb_cdc_id, - NULL, 0, - tx_buffer, PIOS_COM_DEBUGCONSOLE_TX_BUF_LEN)) { - PIOS_Assert(0); - } - } -#endif /* PIOS_INCLUDE_DEBUG_CONSOLE */ -#endif /* PIOS_INCLUDE_COM */ - - break; - } -#endif /* PIOS_INCLUDE_USB_CDC */ - -#if defined(PIOS_INCLUDE_USB_HID) - /* Configure the usb HID port */ - uint8_t hwsettings_usb_hidport; - HwSettingsUSB_HIDPortGet(&hwsettings_usb_hidport); - - if (!usb_hid_present) { - /* Force HID port function to disabled if we haven't advertised HID in our USB descriptor */ - hwsettings_usb_hidport = HWSETTINGS_USB_HIDPORT_DISABLED; - } - - switch (hwsettings_usb_hidport) { - case HWSETTINGS_USB_HIDPORT_DISABLED: - break; - case HWSETTINGS_USB_HIDPORT_USBTELEMETRY: -#if defined(PIOS_INCLUDE_COM) - { - uint8_t *rx_buffer = (uint8_t *)pios_malloc(PIOS_COM_TELEM_USB_RX_BUF_LEN); - uint8_t *tx_buffer = (uint8_t *)pios_malloc(PIOS_COM_TELEM_USB_TX_BUF_LEN); - PIOS_Assert(rx_buffer); - PIOS_Assert(tx_buffer); - if (PIOS_COM_Init(&pios_com_telem_usb_id, &pios_usb_hid_com_driver, pios_usb_hid_id, - rx_buffer, PIOS_COM_TELEM_USB_RX_BUF_LEN, - tx_buffer, PIOS_COM_TELEM_USB_TX_BUF_LEN)) { - PIOS_Assert(0); - } - } -#endif /* PIOS_INCLUDE_COM */ - break; - } - -#endif /* PIOS_INCLUDE_USB_HID */ - - if (usb_hid_present || usb_cdc_present) { - PIOS_USBHOOK_Activate(); + /* Configure FlexiPort */ + uint8_t hwsettings_flexiport; + HwSettingsRM_FlexiPortGet(&hwsettings_flexiport); + + if (hwsettings_flexiport < NELEMENTS(flexi_function_map)) { + PIOS_BOARD_IO_Configure_UART(&pios_usart_flexi_cfg, flexi_function_map[hwsettings_flexiport]); } -#endif /* PIOS_INCLUDE_USB */ - - /* Configure IO ports */ - uint8_t hwsettings_DSMxBind; - HwSettingsDSMxBindGet(&hwsettings_DSMxBind); /* Configure main USART port */ + + /* Initialize inverter gpio and set it to off */ + { + GPIO_InitTypeDef inverterGPIOInit = { + .GPIO_Pin = MAIN_USART_INVERTER_PIN, + .GPIO_Speed = GPIO_Speed_2MHz, + .GPIO_Mode = GPIO_Mode_OUT, + .GPIO_OType = GPIO_OType_PP, + .GPIO_PuPd = GPIO_PuPd_UP + }; + + GPIO_Init(MAIN_USART_INVERTER_GPIO, &inverterGPIOInit); + GPIO_WriteBit(MAIN_USART_INVERTER_GPIO, + MAIN_USART_INVERTER_PIN, + MAIN_USART_INVERTER_DISABLE); + } + uint8_t hwsettings_mainport; HwSettingsRM_MainPortGet(&hwsettings_mainport); - switch (hwsettings_mainport) { - case HWSETTINGS_RM_MAINPORT_DISABLED: - break; - case HWSETTINGS_RM_MAINPORT_TELEMETRY: - PIOS_Board_configure_com(&pios_usart_main_cfg, PIOS_COM_TELEM_RF_RX_BUF_LEN, PIOS_COM_TELEM_RF_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_telem_rf_id); - break; - case HWSETTINGS_RM_MAINPORT_GPS: - PIOS_Board_configure_com(&pios_usart_main_cfg, PIOS_COM_GPS_RX_BUF_LEN, PIOS_COM_GPS_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_gps_id); - break; - case HWSETTINGS_RM_MAINPORT_SBUS: -#if defined(PIOS_INCLUDE_SBUS) - { - uint32_t pios_usart_sbus_id; - if (PIOS_USART_Init(&pios_usart_sbus_id, &pios_usart_sbus_main_cfg)) { - PIOS_Assert(0); - } - - uint32_t pios_sbus_id; - if (PIOS_SBus_Init(&pios_sbus_id, &pios_sbus_cfg, &pios_usart_com_driver, pios_usart_sbus_id)) { - PIOS_Assert(0); - } - - uint32_t pios_sbus_rcvr_id; - if (PIOS_RCVR_Init(&pios_sbus_rcvr_id, &pios_sbus_rcvr_driver, pios_sbus_id)) { - PIOS_Assert(0); - } - pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_SBUS] = pios_sbus_rcvr_id; - } -#endif - break; - case HWSETTINGS_RM_MAINPORT_DSM: - { - // Force binding to zero on the main port - hwsettings_DSMxBind = 0; - - // TODO: Define the various Channelgroup for Revo dsm inputs and handle here - PIOS_Board_configure_dsm(&pios_usart_dsm_main_cfg, &pios_dsm_main_cfg, - &pios_usart_com_driver, MANUALCONTROLSETTINGS_CHANNELGROUPS_DSMMAINPORT, &hwsettings_DSMxBind); + + if (hwsettings_mainport < NELEMENTS(main_function_map)) { + PIOS_BOARD_IO_Configure_UART(&pios_usart_main_cfg, main_function_map[hwsettings_mainport]); } - break; - case HWSETTINGS_RM_MAINPORT_DEBUGCONSOLE: -#if defined(PIOS_INCLUDE_DEBUG_CONSOLE) - { - PIOS_Board_configure_com(&pios_usart_main_cfg, 0, PIOS_COM_DEBUGCONSOLE_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_debug_id); - } -#endif /* PIOS_INCLUDE_DEBUG_CONSOLE */ - break; - case HWSETTINGS_RM_MAINPORT_COMBRIDGE: - PIOS_Board_configure_com(&pios_usart_main_cfg, PIOS_COM_BRIDGE_RX_BUF_LEN, PIOS_COM_BRIDGE_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_bridge_id); - break; - case HWSETTINGS_RM_MAINPORT_MSP: - PIOS_Board_configure_com(&pios_usart_main_cfg, PIOS_COM_MSP_RX_BUF_LEN, PIOS_COM_MSP_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_msp_id); - break; - case HWSETTINGS_RM_MAINPORT_MAVLINK: - PIOS_Board_configure_com(&pios_usart_main_cfg, 0, PIOS_COM_MAVLINK_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_mavlink_id); - break; - case HWSETTINGS_RM_MAINPORT_OSDHK: - PIOS_Board_configure_com(&pios_usart_hkosd_main_cfg, PIOS_COM_HKOSD_RX_BUF_LEN, PIOS_COM_HKOSD_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_hkosd_id); - break; - } /* hwsettings_rm_mainport */ - - if (hwsettings_mainport != HWSETTINGS_RM_MAINPORT_SBUS) { - GPIO_Init(pios_sbus_cfg.inv.gpio, &pios_sbus_cfg.inv.init); - GPIO_WriteBit(pios_sbus_cfg.inv.gpio, pios_sbus_cfg.inv.init.GPIO_Pin, pios_sbus_cfg.gpio_inv_disable); - } - - /* Configure FlexiPort */ - uint8_t hwsettings_flexiport; - HwSettingsRM_FlexiPortGet(&hwsettings_flexiport); - switch (hwsettings_flexiport) { - case HWSETTINGS_RM_FLEXIPORT_DISABLED: - break; - case HWSETTINGS_RM_FLEXIPORT_TELEMETRY: - PIOS_Board_configure_com(&pios_usart_flexi_cfg, PIOS_COM_TELEM_RF_RX_BUF_LEN, PIOS_COM_TELEM_RF_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_telem_rf_id); - break; - case HWSETTINGS_RM_FLEXIPORT_I2C: -#if defined(PIOS_INCLUDE_I2C) - if (PIOS_I2C_Init(&pios_i2c_flexiport_adapter_id, &pios_i2c_flexiport_adapter_cfg)) { - PIOS_Assert(0); - } - PIOS_DELAY_WaitmS(50); // this was after the other PIOS_I2C_Init(), so I copied it here too -#ifdef PIOS_INCLUDE_WDG - // give HMC5x83 on I2C some extra time to allow for reset, etc. if needed - // this is not in a loop, so it is safe - // leave this here even if PIOS_INCLUDE_HMC5X83 is undefined - // to avoid making something else fail when HMC5X83 is removed - PIOS_WDG_Clear(); -#endif /* PIOS_INCLUDE_WDG */ -#if defined(PIOS_INCLUDE_HMC5X83) - // get auxmag type - AuxMagSettingsTypeOptions option; - AuxMagSettingsInitialize(); - AuxMagSettingsTypeGet(&option); - // if the aux mag type is FlexiPort then set it up - if (option == AUXMAGSETTINGS_TYPE_FLEXI) { - // attach the 5x83 mag to the previously inited I2C2 - external_mag = PIOS_HMC5x83_Init(&pios_hmc5x83_external_cfg, pios_i2c_flexiport_adapter_id, 0); -#ifdef PIOS_INCLUDE_WDG - // give HMC5x83 on I2C some extra time to allow for reset, etc. if needed - // this is not in a loop, so it is safe - PIOS_WDG_Clear(); -#endif /* PIOS_INCLUDE_WDG */ - // add this sensor to the sensor task's list - // be careful that you don't register a slow, unimportant sensor after registering the fastest sensor - // and before registering some other fast and important sensor - // as that would cause delay and time jitter for the second fast sensor - PIOS_HMC5x83_Register(external_mag, PIOS_SENSORS_TYPE_3AXIS_AUXMAG); - // mag alarm is cleared later, so use I2C - AlarmsSet(SYSTEMALARMS_ALARM_I2C, (external_mag) ? SYSTEMALARMS_ALARM_OK : SYSTEMALARMS_ALARM_WARNING); - } -#endif /* PIOS_INCLUDE_HMC5X83 */ -#endif /* PIOS_INCLUDE_I2C */ - break; - case HWSETTINGS_RM_FLEXIPORT_GPS: - PIOS_Board_configure_com(&pios_usart_flexi_cfg, PIOS_COM_GPS_RX_BUF_LEN, PIOS_COM_GPS_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_gps_id); - break; - case HWSETTINGS_RM_FLEXIPORT_DSM: - // TODO: Define the various Channelgroup for Revo dsm inputs and handle here - PIOS_Board_configure_dsm(&pios_usart_dsm_flexi_cfg, &pios_dsm_flexi_cfg, - &pios_usart_com_driver, MANUALCONTROLSETTINGS_CHANNELGROUPS_DSMFLEXIPORT, &hwsettings_DSMxBind); - break; - case HWSETTINGS_RM_FLEXIPORT_DEBUGCONSOLE: -#if defined(PIOS_INCLUDE_DEBUG_CONSOLE) - { - PIOS_Board_configure_com(&pios_usart_flexi_cfg, 0, PIOS_COM_DEBUGCONSOLE_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_debug_id); - } -#endif /* PIOS_INCLUDE_DEBUG_CONSOLE */ - break; - case HWSETTINGS_RM_FLEXIPORT_COMBRIDGE: - PIOS_Board_configure_com(&pios_usart_flexi_cfg, PIOS_COM_BRIDGE_RX_BUF_LEN, PIOS_COM_BRIDGE_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_bridge_id); - break; - case HWSETTINGS_RM_FLEXIPORT_MSP: - PIOS_Board_configure_com(&pios_usart_flexi_cfg, PIOS_COM_MSP_RX_BUF_LEN, PIOS_COM_MSP_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_msp_id); - break; - case HWSETTINGS_RM_FLEXIPORT_MAVLINK: - PIOS_Board_configure_com(&pios_usart_flexi_cfg, 0, PIOS_COM_MAVLINK_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_mavlink_id); - break; - case HWSETTINGS_RM_FLEXIPORT_OSDHK: - PIOS_Board_configure_com(&pios_usart_hkosd_flexi_cfg, PIOS_COM_HKOSD_RX_BUF_LEN, PIOS_COM_HKOSD_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_hkosd_id); - break; - case HWSETTINGS_RM_FLEXIPORT_SRXL: -#if defined(PIOS_INCLUDE_SRXL) - { - uint32_t pios_usart_srxl_id; - if (PIOS_USART_Init(&pios_usart_srxl_id, &pios_usart_srxl_flexi_cfg)) { - PIOS_Assert(0); - } - - uint32_t pios_srxl_id; - if (PIOS_SRXL_Init(&pios_srxl_id, &pios_usart_com_driver, pios_usart_srxl_id)) { - PIOS_Assert(0); - } - - uint32_t pios_srxl_rcvr_id; - if (PIOS_RCVR_Init(&pios_srxl_rcvr_id, &pios_srxl_rcvr_driver, pios_srxl_id)) { - PIOS_Assert(0); - } - pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_SRXL] = pios_srxl_rcvr_id; - } -#endif /* PIOS_INCLUDE_SRXL */ - break; - - case HWSETTINGS_RM_FLEXIPORT_IBUS: -#if defined(PIOS_INCLUDE_IBUS) - PIOS_Board_configure_ibus(&pios_usart_ibus_flexi_cfg); -#endif /* PIOS_INCLUDE_IBUS */ - break; - - case HWSETTINGS_RM_FLEXIPORT_HOTTSUMD: - case HWSETTINGS_RM_FLEXIPORT_HOTTSUMH: -#if defined(PIOS_INCLUDE_HOTT) - { - uint32_t pios_usart_hott_id; - if (PIOS_USART_Init(&pios_usart_hott_id, &pios_usart_hott_flexi_cfg)) { - PIOS_Assert(0); - } - - uint32_t pios_hott_id; - if (PIOS_HOTT_Init(&pios_hott_id, &pios_usart_com_driver, pios_usart_hott_id, - hwsettings_flexiport == HWSETTINGS_RM_FLEXIPORT_HOTTSUMD ? PIOS_HOTT_PROTO_SUMD : PIOS_HOTT_PROTO_SUMH)) { - PIOS_Assert(0); - } - - uint32_t pios_hott_rcvr_id; - if (PIOS_RCVR_Init(&pios_hott_rcvr_id, &pios_hott_rcvr_driver, pios_hott_id)) { - PIOS_Assert(0); - } - pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_HOTT] = pios_hott_rcvr_id; - } -#endif /* PIOS_INCLUDE_HOTT */ - break; - - case HWSETTINGS_RM_FLEXIPORT_EXBUS: -#if defined(PIOS_INCLUDE_EXBUS) - { - uint32_t pios_usart_exbus_id; - if (PIOS_USART_Init(&pios_usart_exbus_id, &pios_usart_exbus_flexi_cfg)) { - PIOS_Assert(0); - } - - uint32_t pios_exbus_id; - if (PIOS_EXBUS_Init(&pios_exbus_id, &pios_usart_com_driver, pios_usart_exbus_id)) { - PIOS_Assert(0); - } - - uint32_t pios_exbus_rcvr_id; - if (PIOS_RCVR_Init(&pios_exbus_rcvr_id, &pios_exbus_rcvr_driver, pios_exbus_id)) { - PIOS_Assert(0); - } - pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_EXBUS] = pios_exbus_rcvr_id; - } -#endif /* PIOS_INCLUDE_EXBUS */ - break; - } /* hwsettings_rm_flexiport */ - #if defined(PIOS_INCLUDE_PWM) || defined(PIOS_INCLUDE_PPM) @@ -828,7 +268,7 @@ void PIOS_Board_Init(void) case HWSETTINGS_RM_RCVRPORT_PWM: #if defined(PIOS_INCLUDE_PWM) /* Set up the receiver port. Later this should be optional */ - PIOS_Board_configure_pwm(&pios_pwm_cfg); + PIOS_BOARD_IO_Configure_PWM(&pios_pwm_cfg); #endif /* PIOS_INCLUDE_PWM */ break; case HWSETTINGS_RM_RCVRPORT_PPM: @@ -840,7 +280,7 @@ void PIOS_Board_Init(void) pios_servo_cfg = &pios_servo_cfg_out_in_ppm; } - PIOS_Board_configure_ppm(&pios_ppm_cfg); + PIOS_BOARD_IO_Configure_PPM(&pios_ppm_cfg); break; #endif /* PIOS_INCLUDE_PPM */ @@ -851,16 +291,9 @@ void PIOS_Board_Init(void) } -#if defined(PIOS_INCLUDE_GCSRCVR) - GCSReceiverInitialize(); - uint32_t pios_gcsrcvr_id; - PIOS_GCSRCVR_Init(&pios_gcsrcvr_id); - uint32_t pios_gcsrcvr_rcvr_id; - if (PIOS_RCVR_Init(&pios_gcsrcvr_rcvr_id, &pios_gcsrcvr_rcvr_driver, pios_gcsrcvr_id)) { - PIOS_Assert(0); - } - pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_GCS] = pios_gcsrcvr_rcvr_id; -#endif /* PIOS_INCLUDE_GCSRCVR */ +#ifdef PIOS_INCLUDE_GCSRCVR + PIOS_BOARD_IO_Configure_GCSRCVR(); +#endif #ifdef PIOS_INCLUDE_WS2811 #include @@ -885,7 +318,7 @@ void PIOS_Board_Init(void) PIOS_DELAY_WaitmS(50); #if defined(PIOS_INCLUDE_ADC) - PIOS_ADC_Init(&pios_adc_cfg); + PIOS_BOARD_IO_Configure_ADC(); #endif #if defined(PIOS_INCLUDE_MPU9250) @@ -895,21 +328,6 @@ void PIOS_Board_Init(void) PIOS_MPU9250_MagRegister(); #endif -#if defined(PIOS_INCLUDE_MS5611) - PIOS_MS5611_Init(&pios_ms5611_cfg, pios_i2c_pressure_adapter_id); - PIOS_MS5611_Register(); -#endif - -#ifdef PIOS_INCLUDE_ADC - uint8_t adc_config[HWSETTINGS_ADCROUTING_NUMELEM]; - HwSettingsADCRoutingArrayGet(adc_config); - for (uint32_t i = 0; i < HWSETTINGS_ADCROUTING_NUMELEM; i++) { - if (adc_config[i] != HWSETTINGS_ADCROUTING_DISABLED) { - PIOS_ADC_PinSetup(i); - } - } -#endif - // Attach the board config check hook SANITYCHECK_AttachHook(&RevoNanoConfigHook); // trigger a config check if actuatorsettings are updated diff --git a/flight/targets/boards/revoproto/firmware/inc/pios_config.h b/flight/targets/boards/revoproto/firmware/inc/pios_config.h index 4682648554..ceeaf0ea1a 100644 --- a/flight/targets/boards/revoproto/firmware/inc/pios_config.h +++ b/flight/targets/boards/revoproto/firmware/inc/pios_config.h @@ -83,6 +83,7 @@ #define PIOS_MPU6000_ACCEL /* #define PIOS_INCLUDE_HMC5843 */ #define PIOS_INCLUDE_HMC5X83 +#define PIOS_INCLUDE_HMC5X83_INTERNAL #define PIOS_HMC5X83_HAS_GPIOS /* #define PIOS_INCLUDE_BMP085 */ #define PIOS_INCLUDE_MS5611 diff --git a/flight/targets/boards/sparky2/board_hw_defs.c b/flight/targets/boards/sparky2/board_hw_defs.c index 25afb14e23..3a531ce1e6 100644 --- a/flight/targets/boards/sparky2/board_hw_defs.c +++ b/flight/targets/boards/sparky2/board_hw_defs.c @@ -542,566 +542,13 @@ static const struct flashfs_logfs_cfg flashfs_internal_cfg = { #include -#ifdef PIOS_INCLUDE_COM_TELEM - -/* - * MAIN PORT - */ -static const struct pios_usart_cfg pios_usart_main_cfg = { - .regs = USART1, - .remap = GPIO_AF_USART1, - .init = { - .USART_BaudRate = 57600, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx | USART_Mode_Tx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART1_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { - .gpio = GPIOA, - .init = { - .GPIO_Pin = GPIO_Pin_10, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, - .tx = { - .gpio = GPIOA, - .init = { - .GPIO_Pin = GPIO_Pin_9, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, -}; -#endif /* PIOS_INCLUDE_COM_TELEM */ - -#ifdef PIOS_INCLUDE_DSM - -#include "pios_dsm_priv.h" -static const struct pios_usart_cfg pios_usart_dsm_main_cfg = { - .regs = USART1, - .remap = GPIO_AF_USART1, - .init = { - .USART_BaudRate = 115200, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART1_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { - .gpio = GPIOA, - .init = { - .GPIO_Pin = GPIO_Pin_10, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, - .tx = { - .gpio = GPIOA, - .init = { - .GPIO_Pin = GPIO_Pin_9, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, -}; - -// Because of the inverter on the main port this will not -// work. Notice the mode is set to IN to maintain API -// compatibility but protect the pins -static const struct pios_dsm_cfg pios_dsm_main_cfg = { - .bind = { - .gpio = GPIOA, - .init = { - .GPIO_Pin = GPIO_Pin_10, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_IN, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_NOPULL - }, - }, -}; - -#endif /* PIOS_INCLUDE_DSM */ - -#ifdef PIOS_INCLUDE_COM_FLEXI -/* - * FLEXI PORT - */ -static const struct pios_usart_cfg pios_usart_flexi_cfg = { - .regs = USART3, - .remap = GPIO_AF_USART3, - .init = { - .USART_BaudRate = 57600, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = - USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx | USART_Mode_Tx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART3_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_11, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, - .tx = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_10, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, -}; - -#endif /* PIOS_INCLUDE_COM_FLEXI */ - -#ifdef PIOS_INCLUDE_DSM - -#include "pios_dsm_priv.h" -static const struct pios_usart_cfg pios_usart_dsm_flexi_cfg = { - .regs = USART3, - .remap = GPIO_AF_USART3, - .init = { - .USART_BaudRate = 115200, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART3_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_11, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, - .tx = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_10, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, -}; - -static const struct pios_dsm_cfg pios_dsm_flexi_cfg = { - .bind = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_11, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_OUT, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_NOPULL - }, - }, -}; - -#endif /* PIOS_INCLUDE_DSM */ - -#if defined(PIOS_INCLUDE_SRXL) -/* - * SRXL USART - */ -#include - -static const struct pios_usart_cfg pios_usart_srxl_flexi_cfg = { - .regs = USART3, - .remap = GPIO_AF_USART3, - .init = { - .USART_BaudRate = 115200, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART3_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_11, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, - .tx = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_10, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_OUT, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, -}; - -static const struct pios_usart_cfg pios_usart_srxl_rcvr_cfg = { - .regs = USART6, - .remap = GPIO_AF_USART6, - .init = { - .USART_BaudRate = 115200, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART6_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { - .gpio = GPIOC, - .init = { - .GPIO_Pin = GPIO_Pin_7, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, -}; - -#endif /* PIOS_INCLUDE_SRXL */ - -#if defined(PIOS_INCLUDE_IBUS) -/* - * IBUS USART - */ -#include - -static const struct pios_usart_cfg pios_usart_ibus_flexi_cfg = { - .regs = USART3, - .remap = GPIO_AF_USART3, - .init = { - .USART_BaudRate = 115200, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART3_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_11, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, - .tx = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_10, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_OUT, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, -}; - -static const struct pios_usart_cfg pios_usart_ibus_rcvr_cfg = { - .regs = USART6, - .remap = GPIO_AF_USART6, - .init = { - .USART_BaudRate = 115200, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART6_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { - .gpio = GPIOC, - .init = { - .GPIO_Pin = GPIO_Pin_7, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, -}; - -#endif /* PIOS_INCLUDE_IBUS */ - -// these were copied from Revo support -// they might need to be further modified for Sparky2 support -#if defined(PIOS_INCLUDE_HOTT) -/* - * HOTT USART - */ -#include - -static const struct pios_usart_cfg pios_usart_hott_flexi_cfg = { - .regs = USART3, - .remap = GPIO_AF_USART3, - .init = { - .USART_BaudRate = 115200, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART3_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_11, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, - .tx = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_10, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_OUT, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, -}; - -static const struct pios_usart_cfg pios_usart_hott_rcvr_cfg = { - .regs = USART6, - .remap = GPIO_AF_USART6, - .init = { - .USART_BaudRate = 115200, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART6_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { - .gpio = GPIOC, - .init = { - .GPIO_Pin = GPIO_Pin_7, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, -}; - -#endif /* PIOS_INCLUDE_HOTT */ - -#if defined(PIOS_INCLUDE_EXBUS) /* - * EXBUS USART + * MAIN PORT */ -#include - -static const struct pios_usart_cfg pios_usart_exbus_flexi_cfg = { - .regs = USART3, - .remap = GPIO_AF_USART3, - .init = { - .USART_BaudRate = 125000, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART3_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_11, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, - .tx = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_10, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_OUT, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, -}; - -static const struct pios_usart_cfg pios_usart_exbus_rcvr_cfg = { - .regs = USART6, - .remap = GPIO_AF_USART6, - .init = { - .USART_BaudRate = 125000, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART6_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { - .gpio = GPIOC, - .init = { - .GPIO_Pin = GPIO_Pin_7, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, -}; -#endif /* PIOS_INCLUDE_EXBUS */ - -/* - * HK OSD - */ -static const struct pios_usart_cfg pios_usart_hkosd_main_cfg = { +static const struct pios_usart_cfg pios_usart_main_cfg = { .regs = USART1, .remap = GPIO_AF_USART1, - .init = { - .USART_BaudRate = 57600, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx | USART_Mode_Tx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART1_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, .rx = { .gpio = GPIOA, .init = { @@ -1124,25 +571,12 @@ static const struct pios_usart_cfg pios_usart_hkosd_main_cfg = { }, }; -static const struct pios_usart_cfg pios_usart_hkosd_flexi_cfg = { +/* + * FLEXI PORT + */ +static const struct pios_usart_cfg pios_usart_flexi_cfg = { .regs = USART3, .remap = GPIO_AF_USART3, - .init = { - .USART_BaudRate = 57600, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx | USART_Mode_Tx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART3_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, .rx = { .gpio = GPIOB, .init = { @@ -1170,103 +604,18 @@ static const struct pios_usart_cfg pios_usart_hkosd_flexi_cfg = { * RCVR PORT */ -#if defined(PIOS_INCLUDE_SBUS) -/* - * S.Bus USART - */ -#include - -static const struct pios_usart_cfg pios_usart_sbus_rcvr_cfg = { - .regs = USART6, - .remap = GPIO_AF_USART6, - .init = { - .USART_BaudRate = 100000, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_Even, - .USART_StopBits = USART_StopBits_2, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART6_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { - .gpio = GPIOC, - .init = { - .GPIO_Pin = GPIO_Pin_7, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, -}; - - -static const struct pios_sbus_cfg pios_sbus_cfg = { - /* Inverter configuration */ - .inv = { - .gpio = GPIOC, - .init = { - .GPIO_Pin = GPIO_Pin_6, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_OUT, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, - .gpio_inv_enable = Bit_SET, - .gpio_inv_disable = Bit_RESET, - .gpio_clk_func = RCC_AHB1PeriphClockCmd, - .gpio_clk_periph = RCC_AHB1Periph_GPIOC, -}; - -#endif /* PIOS_INCLUDE_SBUS */ +// Inverter for SBUS handling +#define RCVR_USART_INVERTER_GPIO GPIOC +#define RCVR_USART_INVERTER_PIN GPIO_Pin_4 +#define RCVR_USART_INVERTER_ENABLE Bit_SET +#define RCVR_USART_INVERTER_DISABLE Bit_RESET -#ifdef PIOS_INCLUDE_DSM +static int32_t PIOS_BOARD_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param); -// It looks like TL notes originally came from OP's pios_dsm_main_cfg -// (TL note) Because of the inverter on the main port this will not -// (TL note) work. Notice the mode is set to IN to maintain API -// (TL note) compatibility but protect the pins -static const struct pios_dsm_cfg pios_dsm_rcvr_cfg = { - .bind = { - .gpio = GPIOC, - .init = { - .GPIO_Pin = GPIO_Pin_7, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_OUT, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_NOPULL - }, - }, -}; - -static const struct pios_usart_cfg pios_usart_dsm_rcvr_cfg = { +static const struct pios_usart_cfg pios_usart_rcvr_cfg = { .regs = USART6, .remap = GPIO_AF_USART6, - .init = { - .USART_BaudRate = 115200, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART6_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, .rx = { .gpio = GPIOC, .init = { @@ -1277,11 +626,9 @@ static const struct pios_usart_cfg pios_usart_dsm_rcvr_cfg = { .GPIO_PuPd = GPIO_PuPd_UP }, }, + .ioctl = PIOS_BOARD_USART_Ioctl, }; -#endif /* PIOS_INCLUDE_DSM */ - - #if defined(PIOS_INCLUDE_COM) #include @@ -1720,7 +1067,7 @@ static const struct pios_ppm_cfg pios_ppm_cfg = { #if defined(PIOS_INCLUDE_USB) #include "pios_usb_priv.h" -static const struct pios_usb_cfg pios_usb_main_rm2_cfg = { +static const struct pios_usb_cfg pios_usb_main_spk2_cfg = { .irq = { .init = { .NVIC_IRQChannel = OTG_FS_IRQn, @@ -1743,7 +1090,7 @@ static const struct pios_usb_cfg pios_usb_main_rm2_cfg = { const struct pios_usb_cfg *PIOS_BOARD_HW_DEFS_GetUsbCfg(__attribute__((unused)) uint32_t board_revision) { - return &pios_usb_main_rm2_cfg; + return &pios_usb_main_spk2_cfg; } #include "pios_usb_board_data_priv.h" @@ -1759,37 +1106,6 @@ const struct pios_usb_cfg *PIOS_BOARD_HW_DEFS_GetUsbCfg(__attribute__((unused)) #endif /* PIOS_INCLUDE_COM_MSG */ -#if defined(PIOS_INCLUDE_USB_HID) && !defined(PIOS_INCLUDE_USB_CDC) -#include - -const struct pios_usb_hid_cfg pios_usb_hid_cfg = { - .data_if = 0, - .data_rx_ep = 1, - .data_tx_ep = 1, -}; -#endif /* PIOS_INCLUDE_USB_HID && !PIOS_INCLUDE_USB_CDC */ - -#if defined(PIOS_INCLUDE_USB_HID) && defined(PIOS_INCLUDE_USB_CDC) -#include - -const struct pios_usb_cdc_cfg pios_usb_cdc_cfg = { - .ctrl_if = 0, - .ctrl_tx_ep = 2, - - .data_if = 1, - .data_rx_ep = 3, - .data_tx_ep = 3, -}; - -#include - -const struct pios_usb_hid_cfg pios_usb_hid_cfg = { - .data_if = 2, - .data_rx_ep = 1, - .data_tx_ep = 1, -}; -#endif /* PIOS_INCLUDE_USB_HID && PIOS_INCLUDE_USB_CDC */ - #ifdef PIOS_INCLUDE_WS2811 #include #include @@ -1906,3 +1222,141 @@ void PIOS_WS2811_irq_handler(void) PIOS_WS2811_DMA_irq_handler(); } #endif // PIOS_INCLUDE_WS2811 + +/** + * Sensor configurations + */ + +#if defined(PIOS_INCLUDE_ADC) + +#include "pios_adc_priv.h" +void PIOS_ADC_DMC_irq_handler(void); +void DMA2_Stream4_IRQHandler(void) __attribute__((alias("PIOS_ADC_DMC_irq_handler"))); +struct pios_adc_cfg pios_adc_cfg = { + .adc_dev = ADC1, + .dma = { + .irq = { + .flags = (DMA_FLAG_TCIF4 | DMA_FLAG_TEIF4 | DMA_FLAG_HTIF4), + .init = { + .NVIC_IRQChannel = DMA2_Stream4_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_LOW, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, + .rx = { + .channel = DMA2_Stream4, + .init = { + .DMA_Channel = DMA_Channel_0, + .DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR + }, + } + }, + .half_flag = DMA_IT_HTIF4, + .full_flag = DMA_IT_TCIF4, +}; +void PIOS_ADC_DMC_irq_handler(void) +{ + /* Call into the generic code to handle the IRQ for this specific device */ + PIOS_ADC_DMA_Handler(); +} + +const struct pios_adc_cfg *PIOS_BOARD_HW_DEFS_GetAdcCfg(__attribute__((unused)) uint32_t board_revision) +{ + return &pios_adc_cfg; +} +#endif /* if defined(PIOS_INCLUDE_ADC) */ + +#if defined(PIOS_INCLUDE_HMC5X83) +#include "pios_hmc5x83.h" + +static const struct pios_hmc5x83_cfg pios_hmc5x83_external_cfg = { +#ifdef PIOS_HMC5X83_HAS_GPIOS + .exti_cfg = NULL, +#endif /* PIOS_HMC5X83_HAS_GPIOS */ + .M_ODR = PIOS_HMC5x83_ODR_75, + .Meas_Conf = PIOS_HMC5x83_MEASCONF_NORMAL, + .Gain = PIOS_HMC5x83_GAIN_1_9, + .Mode = PIOS_HMC5x83_MODE_CONTINUOUS, + .Driver = &PIOS_HMC5x83_I2C_DRIVER, + .Orientation = PIOS_HMC5X83_ORIENTATION_EAST_NORTH_UP, +}; + +const struct pios_hmc5x83_cfg *PIOS_BOARD_HW_DEFS_GetExternalHMC5x83Cfg(__attribute__((unused)) uint32_t board_revision) +{ + return &pios_hmc5x83_external_cfg; +} +#endif /* PIOS_INCLUDE_HMC5X83 */ + +/** + * Configuration for the MS5611 chip + */ +#if defined(PIOS_INCLUDE_MS5611) +#include "pios_ms5611.h" +static const struct pios_ms5611_cfg pios_ms5611_cfg = { + .oversampling = MS5611_OSR_4096, +}; +const struct pios_ms5611_cfg *PIOS_BOARD_HW_DEFS_GetMS5611Cfg(__attribute__((unused)) uint32_t board_revision) +{ + return &pios_ms5611_cfg; +} +#endif /* PIOS_INCLUDE_MS5611 */ + +/** + * Configuration for the MPU9250 chip + */ +#if defined(PIOS_INCLUDE_MPU9250) +#include "pios_mpu9250.h" +#include "pios_mpu9250_config.h" +static const struct pios_exti_cfg pios_exti_mpu9250_cfg __exti_config = { + .vector = PIOS_MPU9250_IRQHandler, + .line = EXTI_Line5, + .pin = { + .gpio = GPIOC, + .init = { + .GPIO_Pin = GPIO_Pin_5, + .GPIO_Speed = GPIO_Speed_100MHz, + .GPIO_Mode = GPIO_Mode_IN, + .GPIO_OType = GPIO_OType_OD, + .GPIO_PuPd = GPIO_PuPd_NOPULL, + }, + }, + .irq = { + .init = { + .NVIC_IRQChannel = EXTI9_5_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, + .exti = { + .init = { + .EXTI_Line = EXTI_Line5, // matches above GPIO pin + .EXTI_Mode = EXTI_Mode_Interrupt, + .EXTI_Trigger = EXTI_Trigger_Rising, + .EXTI_LineCmd = ENABLE, + }, + }, +}; + +static const struct pios_mpu9250_cfg pios_mpu9250_cfg = { + .exti_cfg = &pios_exti_mpu9250_cfg, + .Fifo_store = 0, + // Clock at 8 khz + .Smpl_rate_div_no_dlp = 0, + // with dlp on output rate is 1000Hz + .Smpl_rate_div_dlp = 0, + .interrupt_cfg = PIOS_MPU9250_INT_CLR_ANYRD, // | PIOS_MPU9250_INT_LATCH_EN, + .interrupt_en = PIOS_MPU9250_INTEN_DATA_RDY, + .User_ctl = PIOS_MPU9250_USERCTL_DIS_I2C | PIOS_MPU9250_USERCTL_I2C_MST_EN, + .Pwr_mgmt_clk = PIOS_MPU9250_PWRMGMT_PLL_Z_CLK, + .accel_range = PIOS_MPU9250_ACCEL_8G, + .gyro_range = PIOS_MPU9250_SCALE_2000_DEG, + .filter = PIOS_MPU9250_LOWPASS_256_HZ, + .orientation = PIOS_MPU9250_TOP_180DEG, + .fast_prescaler = PIOS_SPI_PRESCALER_4, + .std_prescaler = PIOS_SPI_PRESCALER_64, + .max_downsample = 26, +}; +#endif /* PIOS_INCLUDE_MPU9250 */ + diff --git a/flight/targets/boards/sparky2/bootloader/pios_board.c b/flight/targets/boards/sparky2/bootloader/pios_board.c index 5352c7f73b..f93555938d 100644 --- a/flight/targets/boards/sparky2/bootloader/pios_board.c +++ b/flight/targets/boards/sparky2/bootloader/pios_board.c @@ -39,6 +39,12 @@ uint32_t pios_com_telem_usb_id; static bool board_init_complete = false; + +static int32_t PIOS_BOARD_USART_Ioctl(__attribute__((unused)) uint32_t usart_id, __attribute__((unused)) uint32_t ctl, __attribute__((unused)) void *param) +{ + return -1; +} + void PIOS_Board_Init() { if (board_init_complete) { @@ -68,7 +74,7 @@ void PIOS_Board_Init() #if defined(PIOS_INCLUDE_USB_HID) && defined(PIOS_INCLUDE_COM_MSG) uint32_t pios_usb_hid_id; - if (PIOS_USB_HID_Init(&pios_usb_hid_id, &pios_usb_hid_cfg, pios_usb_id)) { + if (PIOS_USB_HID_Init(&pios_usb_hid_id, &pios_usb_hid_only_cfg, pios_usb_id)) { PIOS_Assert(0); } if (PIOS_COM_MSG_Init(&pios_com_telem_usb_id, &pios_usb_hid_com_driver, pios_usb_hid_id)) { diff --git a/flight/targets/boards/sparky2/firmware/pios_board.c b/flight/targets/boards/sparky2/firmware/pios_board.c index 270f531523..1c0561dcb7 100644 --- a/flight/targets/boards/sparky2/firmware/pios_board.c +++ b/flight/targets/boards/sparky2/firmware/pios_board.c @@ -30,22 +30,18 @@ #include #include #include -#include -#include -#include -#include -#include -#include -#include #include #include -#include -#include -#include #ifdef PIOS_INCLUDE_INSTRUMENTATION #include #endif +#ifdef PIOS_INCLUDE_WS2811 +#include +#endif + +#include + /* * Pull in the board-specific static HW definitions. @@ -57,338 +53,63 @@ */ #include "../board_hw_defs.c" -/** - * Sensor configurations - */ - -#if defined(PIOS_INCLUDE_ADC) +uintptr_t pios_uavo_settings_fs_id; +uintptr_t pios_user_fs_id; -#include "pios_adc_priv.h" -void PIOS_ADC_DMC_irq_handler(void); -void DMA2_Stream4_IRQHandler(void) __attribute__((alias("PIOS_ADC_DMC_irq_handler"))); -struct pios_adc_cfg pios_adc_cfg = { - .adc_dev = ADC1, - .dma = { - .irq = { - .flags = (DMA_FLAG_TCIF4 | DMA_FLAG_TEIF4 | DMA_FLAG_HTIF4), - .init = { - .NVIC_IRQChannel = DMA2_Stream4_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_LOW, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { - .channel = DMA2_Stream4, - .init = { - .DMA_Channel = DMA_Channel_0, - .DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR - }, - } - }, - .half_flag = DMA_IT_HTIF4, - .full_flag = DMA_IT_TCIF4, +static const PIOS_BOARD_IO_UART_Function rcvr_function_map[] = { + [HWSETTINGS_SPK2_RCVRPORT_SBUS] = PIOS_BOARD_IO_UART_SBUS, + [HWSETTINGS_SPK2_RCVRPORT_DSM] = PIOS_BOARD_IO_UART_DSM_RCVR, + [HWSETTINGS_SPK2_RCVRPORT_SRXL] = PIOS_BOARD_IO_UART_SRXL, + [HWSETTINGS_SPK2_RCVRPORT_IBUS] = PIOS_BOARD_IO_UART_IBUS, + [HWSETTINGS_SPK2_RCVRPORT_EXBUS] = PIOS_BOARD_IO_UART_EXBUS, + [HWSETTINGS_SPK2_RCVRPORT_HOTTSUMD] = PIOS_BOARD_IO_UART_HOTT_SUMD, + [HWSETTINGS_SPK2_RCVRPORT_HOTTSUMH] = PIOS_BOARD_IO_UART_HOTT_SUMH, }; -void PIOS_ADC_DMC_irq_handler(void) -{ - /* Call into the generic code to handle the IRQ for this specific device */ - PIOS_ADC_DMA_Handler(); -} - -#endif /* if defined(PIOS_INCLUDE_ADC) */ - -#if defined(PIOS_INCLUDE_HMC5X83) -#include "pios_hmc5x83.h" -pios_hmc5x83_dev_t i2c_port_mag = 0; -pios_hmc5x83_dev_t flexi_port_mag = 0; -static const struct pios_hmc5x83_cfg pios_hmc5x83_cfg = { -#ifdef PIOS_HMC5X83_HAS_GPIOS - .exti_cfg = NULL, -#endif /* PIOS_HMC5X83_HAS_GPIOS */ - .M_ODR = PIOS_HMC5x83_ODR_75, - .Meas_Conf = PIOS_HMC5x83_MEASCONF_NORMAL, - .Gain = PIOS_HMC5x83_GAIN_1_9, - .Mode = PIOS_HMC5x83_MODE_CONTINUOUS, - .Driver = &PIOS_HMC5x83_I2C_DRIVER, - .Orientation = PIOS_HMC5X83_ORIENTATION_EAST_NORTH_UP, +static const PIOS_BOARD_IO_UART_Function main_function_map[] = { + [HWSETTINGS_SPK2_MAINPORT_TELEMETRY] = PIOS_BOARD_IO_UART_TELEMETRY, + [HWSETTINGS_SPK2_MAINPORT_GPS] = PIOS_BOARD_IO_UART_GPS, + [HWSETTINGS_SPK2_MAINPORT_DSM] = PIOS_BOARD_IO_UART_DSM_MAIN, + [HWSETTINGS_SPK2_MAINPORT_DEBUGCONSOLE] = PIOS_BOARD_IO_UART_DEBUGCONSOLE, + [HWSETTINGS_SPK2_MAINPORT_COMBRIDGE] = PIOS_BOARD_IO_UART_COMBRIDGE, + [HWSETTINGS_SPK2_MAINPORT_OSDHK] = PIOS_BOARD_IO_UART_OSDHK, + [HWSETTINGS_SPK2_MAINPORT_MSP] = PIOS_BOARD_IO_UART_MSP, + [HWSETTINGS_SPK2_MAINPORT_MAVLINK] = PIOS_BOARD_IO_UART_MAVLINK, }; -#endif /* PIOS_INCLUDE_HMC5X83 */ -/** - * Configuration for the MS5611 chip - */ -#if defined(PIOS_INCLUDE_MS5611) -#include "pios_ms5611.h" -static const struct pios_ms5611_cfg pios_ms5611_cfg = { - .oversampling = MS5611_OSR_4096, +static const PIOS_BOARD_IO_UART_Function flexi_function_map[] = { + [HWSETTINGS_SPK2_FLEXIPORT_TELEMETRY] = PIOS_BOARD_IO_UART_TELEMETRY, + [HWSETTINGS_SPK2_FLEXIPORT_GPS] = PIOS_BOARD_IO_UART_GPS, + [HWSETTINGS_SPK2_FLEXIPORT_DSM] = PIOS_BOARD_IO_UART_DSM_FLEXI, + [HWSETTINGS_SPK2_FLEXIPORT_EXBUS] = PIOS_BOARD_IO_UART_EXBUS, + [HWSETTINGS_SPK2_FLEXIPORT_HOTTSUMD] = PIOS_BOARD_IO_UART_HOTT_SUMD, + [HWSETTINGS_SPK2_FLEXIPORT_HOTTSUMH] = PIOS_BOARD_IO_UART_HOTT_SUMH, + [HWSETTINGS_SPK2_FLEXIPORT_SRXL] = PIOS_BOARD_IO_UART_SRXL, + [HWSETTINGS_SPK2_FLEXIPORT_IBUS] = PIOS_BOARD_IO_UART_IBUS, + [HWSETTINGS_SPK2_FLEXIPORT_DEBUGCONSOLE] = PIOS_BOARD_IO_UART_DEBUGCONSOLE, + [HWSETTINGS_SPK2_FLEXIPORT_COMBRIDGE] = PIOS_BOARD_IO_UART_COMBRIDGE, + [HWSETTINGS_SPK2_FLEXIPORT_OSDHK] = PIOS_BOARD_IO_UART_OSDHK, + [HWSETTINGS_SPK2_FLEXIPORT_MSP] = PIOS_BOARD_IO_UART_MSP, + [HWSETTINGS_SPK2_FLEXIPORT_MAVLINK] = PIOS_BOARD_IO_UART_MAVLINK, }; -#endif /* PIOS_INCLUDE_MS5611 */ - -/** - * Configuration for the MPU9250 chip - */ -#if defined(PIOS_INCLUDE_MPU9250) -#include "pios_mpu9250.h" -#include "pios_mpu9250_config.h" -static const struct pios_exti_cfg pios_exti_mpu9250_cfg __exti_config = { - .vector = PIOS_MPU9250_IRQHandler, - .line = EXTI_Line5, - .pin = { - .gpio = GPIOC, - .init = { - .GPIO_Pin = GPIO_Pin_5, - .GPIO_Speed = GPIO_Speed_100MHz, - .GPIO_Mode = GPIO_Mode_IN, - .GPIO_OType = GPIO_OType_OD, - .GPIO_PuPd = GPIO_PuPd_NOPULL, - }, - }, - .irq = { - .init = { - .NVIC_IRQChannel = EXTI9_5_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .exti = { - .init = { - .EXTI_Line = EXTI_Line5, // matches above GPIO pin - .EXTI_Mode = EXTI_Mode_Interrupt, - .EXTI_Trigger = EXTI_Trigger_Rising, - .EXTI_LineCmd = ENABLE, - }, - }, -}; - -static const struct pios_mpu9250_cfg pios_mpu9250_cfg = { - .exti_cfg = &pios_exti_mpu9250_cfg, - .Fifo_store = 0, - // Clock at 8 khz - .Smpl_rate_div_no_dlp = 0, - // with dlp on output rate is 1000Hz - .Smpl_rate_div_dlp = 0, - .interrupt_cfg = PIOS_MPU9250_INT_CLR_ANYRD, // | PIOS_MPU9250_INT_LATCH_EN, - .interrupt_en = PIOS_MPU9250_INTEN_DATA_RDY, - .User_ctl = PIOS_MPU9250_USERCTL_DIS_I2C | PIOS_MPU9250_USERCTL_I2C_MST_EN, - .Pwr_mgmt_clk = PIOS_MPU9250_PWRMGMT_PLL_Z_CLK, - .accel_range = PIOS_MPU9250_ACCEL_8G, - .gyro_range = PIOS_MPU9250_SCALE_2000_DEG, - .filter = PIOS_MPU9250_LOWPASS_256_HZ, - .orientation = PIOS_MPU9250_TOP_180DEG, - .fast_prescaler = PIOS_SPI_PRESCALER_4, - .std_prescaler = PIOS_SPI_PRESCALER_64, - .max_downsample = 26, -}; -#endif /* PIOS_INCLUDE_MPU9250 */ - - -/* One slot per selectable receiver group. - * eg. PWM, PPM, GCS, SPEKTRUM1, SPEKTRUM2, SBUS - * NOTE: No slot in this map for NONE. - */ -uint32_t pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_NONE]; - -#define PIOS_COM_TELEM_RF_RX_BUF_LEN 512 -#define PIOS_COM_TELEM_RF_TX_BUF_LEN 512 - -#define PIOS_COM_GPS_RX_BUF_LEN 128 -#define PIOS_COM_GPS_TX_BUF_LEN 32 - -#define PIOS_COM_TELEM_USB_RX_BUF_LEN 65 -#define PIOS_COM_TELEM_USB_TX_BUF_LEN 65 - -#define PIOS_COM_BRIDGE_RX_BUF_LEN 65 -#define PIOS_COM_BRIDGE_TX_BUF_LEN 12 - -#define PIOS_COM_RFM22B_RF_RX_BUF_LEN 512 -#define PIOS_COM_RFM22B_RF_TX_BUF_LEN 512 - -#define PIOS_COM_HKOSD_RX_BUF_LEN 22 -#define PIOS_COM_HKOSD_TX_BUF_LEN 22 - -#define PIOS_COM_MSP_TX_BUF_LEN 128 -#define PIOS_COM_MSP_RX_BUF_LEN 64 - -#define PIOS_COM_MAVLINK_TX_BUF_LEN 128 -#define PIOS_COM_MAVLINK_RX_BUF_LEN 128 - -#if defined(PIOS_INCLUDE_DEBUG_CONSOLE) -#define PIOS_COM_DEBUGCONSOLE_TX_BUF_LEN 40 -uint32_t pios_com_debug_id; -#endif /* PIOS_INCLUDE_DEBUG_CONSOLE */ - -uint32_t pios_com_gps_id = 0; -uint32_t pios_com_telem_usb_id = 0; -uint32_t pios_com_telem_rf_id = 0; -uint32_t pios_com_rf_id = 0; -uint32_t pios_com_bridge_id = 0; -uint32_t pios_com_overo_id = 0; -uint32_t pios_com_hkosd_id = 0; -uint32_t pios_com_msp_id = 0; -uint32_t pios_com_mavlink_id = 0; -uint32_t pios_com_vcp_id = 0; - -#if defined(PIOS_INCLUDE_RFM22B) -uint32_t pios_rfm22b_id = 0; -#include -#endif - -uintptr_t pios_uavo_settings_fs_id; -uintptr_t pios_user_fs_id; - -/* - * Setup a com port based on the passed cfg, driver and buffer sizes. - * tx size = 0 make the port rx only - * rx size = 0 make the port tx only - * having both tx and rx size = 0 is not valid and will fail further down in PIOS_COM_Init() - */ -static void PIOS_Board_configure_com(const struct pios_usart_cfg *usart_port_cfg, uint16_t rx_buf_len, uint16_t tx_buf_len, - const struct pios_com_driver *com_driver, uint32_t *pios_com_id) -{ - uint32_t pios_usart_id; - - if (PIOS_USART_Init(&pios_usart_id, usart_port_cfg)) { - PIOS_Assert(0); - } - - uint8_t *rx_buffer = 0, *tx_buffer = 0; - - if (rx_buf_len > 0) { - rx_buffer = (uint8_t *)pios_malloc(rx_buf_len); - PIOS_Assert(rx_buffer); - } - - if (tx_buf_len > 0) { - tx_buffer = (uint8_t *)pios_malloc(tx_buf_len); - PIOS_Assert(tx_buffer); - } - - if (PIOS_COM_Init(pios_com_id, com_driver, pios_usart_id, - rx_buffer, rx_buf_len, - tx_buffer, tx_buf_len)) { - PIOS_Assert(0); - } -} - -static void PIOS_Board_configure_dsm(const struct pios_usart_cfg *pios_usart_dsm_cfg, const struct pios_dsm_cfg *pios_dsm_cfg, - const struct pios_com_driver *usart_com_driver, - ManualControlSettingsChannelGroupsOptions channelgroup, uint8_t *bind) -{ - uint32_t pios_usart_dsm_id; - - if (PIOS_USART_Init(&pios_usart_dsm_id, pios_usart_dsm_cfg)) { - PIOS_Assert(0); - } - - uint32_t pios_dsm_id; - if (PIOS_DSM_Init(&pios_dsm_id, pios_dsm_cfg, usart_com_driver, - pios_usart_dsm_id, *bind)) { - PIOS_Assert(0); - } - - uint32_t pios_dsm_rcvr_id; - if (PIOS_RCVR_Init(&pios_dsm_rcvr_id, &pios_dsm_rcvr_driver, pios_dsm_id)) { - PIOS_Assert(0); - } - pios_rcvr_group_map[channelgroup] = pios_dsm_rcvr_id; -} -static void PIOS_Board_configure_ppm(const struct pios_ppm_cfg *ppm_cfg) +int32_t PIOS_BOARD_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param) { - uint32_t pios_ppm_id; - - PIOS_PPM_Init(&pios_ppm_id, ppm_cfg); - - uint32_t pios_ppm_rcvr_id; - if (PIOS_RCVR_Init(&pios_ppm_rcvr_id, &pios_ppm_rcvr_driver, pios_ppm_id)) { - PIOS_Assert(0); - } - pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_PPM] = pios_ppm_rcvr_id; -} - -static void PIOS_Board_configure_srxl(const struct pios_usart_cfg *usart_cfg) -{ - uint32_t pios_usart_srxl_id; - - if (PIOS_USART_Init(&pios_usart_srxl_id, usart_cfg)) { - PIOS_Assert(0); - } - - uint32_t pios_srxl_id; - if (PIOS_SRXL_Init(&pios_srxl_id, &pios_usart_com_driver, pios_usart_srxl_id)) { - PIOS_Assert(0); - } - - uint32_t pios_srxl_rcvr_id; - if (PIOS_RCVR_Init(&pios_srxl_rcvr_id, &pios_srxl_rcvr_driver, pios_srxl_id)) { - PIOS_Assert(0); - } - - pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_SRXL] = pios_srxl_rcvr_id; -} - -static void PIOS_Board_configure_ibus(const struct pios_usart_cfg *usart_cfg) -{ - uint32_t pios_usart_ibus_id; - - if (PIOS_USART_Init(&pios_usart_ibus_id, usart_cfg)) { - PIOS_Assert(0); - } - - uint32_t pios_ibus_id; - if (PIOS_IBUS_Init(&pios_ibus_id, &pios_usart_com_driver, pios_usart_ibus_id)) { - PIOS_Assert(0); - } - - uint32_t pios_ibus_rcvr_id; - if (PIOS_RCVR_Init(&pios_ibus_rcvr_id, &pios_ibus_rcvr_driver, pios_ibus_id)) { - PIOS_Assert(0); - } - - pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_IBUS] = pios_ibus_rcvr_id; -} - - -static void PIOS_Board_configure_exbus(const struct pios_usart_cfg *usart_cfg) -{ - uint32_t pios_usart_exbus_id; - - if (PIOS_USART_Init(&pios_usart_exbus_id, usart_cfg)) { - PIOS_Assert(0); - } - - uint32_t pios_exbus_id; - if (PIOS_EXBUS_Init(&pios_exbus_id, &pios_usart_com_driver, pios_usart_exbus_id)) { - PIOS_Assert(0); - } - - uint32_t pios_exbus_rcvr_id; - if (PIOS_RCVR_Init(&pios_exbus_rcvr_id, &pios_exbus_rcvr_driver, pios_exbus_id)) { - PIOS_Assert(0); - } - pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_EXBUS] = pios_exbus_rcvr_id; -} - -static void PIOS_Board_configure_hott(const struct pios_usart_cfg *usart_cfg, enum pios_hott_proto proto) -{ - uint32_t pios_usart_hott_id; - - if (PIOS_USART_Init(&pios_usart_hott_id, usart_cfg)) { - PIOS_Assert(0); - } - - uint32_t pios_hott_id; - if (PIOS_HOTT_Init(&pios_hott_id, &pios_usart_com_driver, pios_usart_hott_id, proto)) { - PIOS_Assert(0); - } - - uint32_t pios_hott_rcvr_id; - if (PIOS_RCVR_Init(&pios_hott_rcvr_id, &pios_hott_rcvr_driver, pios_hott_id)) { - PIOS_Assert(0); + const struct pios_usart_cfg *usart_cfg = PIOS_USART_GetConfig(usart_id); + + switch (ctl) { + case PIOS_IOCTL_USART_SET_INVERTED: + if (usart_cfg->regs == pios_usart_rcvr_cfg.regs) { /* rcvr port */ + GPIO_WriteBit(RCVR_USART_INVERTER_GPIO, + RCVR_USART_INVERTER_PIN, + (*(enum PIOS_USART_Inverted *)param & PIOS_USART_Inverted_Rx) ? RCVR_USART_INVERTER_ENABLE : RCVR_USART_INVERTER_DISABLE); + + return 0; + } + break; } - pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_HOTT] = pios_hott_rcvr_id; + + return -1; } /** @@ -397,13 +118,8 @@ static void PIOS_Board_configure_hott(const struct pios_usart_cfg *usart_cfg, en * called from System/openpilot.c */ -#include - void PIOS_Board_Init(void) { - /* Delay system */ - PIOS_DELAY_Init(); - const struct pios_board_info *bdinfo = &pios_board_info_blob; #if defined(PIOS_INCLUDE_LED) @@ -427,12 +143,6 @@ void PIOS_Board_Init(void) PIOS_DEBUG_Assert(0); } -#ifdef PIOS_INCLUDE_I2C - if (PIOS_I2C_Init(&pios_i2c_mag_pressure_adapter_id, &pios_i2c_mag_pressure_adapter_cfg)) { - PIOS_DEBUG_Assert(0); - } -#endif - #if defined(PIOS_INCLUDE_FLASH) /* Connect flash to the appropriate interface and configure it */ uintptr_t flash_id = 0; @@ -477,13 +187,6 @@ void PIOS_Board_Init(void) EventDispatcherInitialize(); UAVObjInitialize(); HwSettingsInitialize(); -#if defined(PIOS_INCLUDE_RFM22B) - OPLinkSettingsInitialize(); - OPLinkStatusInitialize(); -#endif /* PIOS_INCLUDE_RFM22B */ -#if defined(PIOS_INCLUDE_HMC5X83) - AuxMagSettingsInitialize(); -#endif /* PIOS_INCLUDE_HMC5X83 */ /* Initialize the alarms library */ AlarmsInitialize(); @@ -511,110 +214,31 @@ void PIOS_Board_Init(void) } /* Configure IO ports */ - uint8_t hwsettings_DSMxBind; - HwSettingsDSMxBindGet(&hwsettings_DSMxBind); /* Configure FlexiPort */ uint8_t hwsettings_flexiport; HwSettingsSPK2_FlexiPortGet(&hwsettings_flexiport); - switch (hwsettings_flexiport) { - case HWSETTINGS_SPK2_FLEXIPORT_DISABLED: - break; - case HWSETTINGS_SPK2_FLEXIPORT_TELEMETRY: - PIOS_Board_configure_com(&pios_usart_flexi_cfg, PIOS_COM_TELEM_RF_RX_BUF_LEN, PIOS_COM_TELEM_RF_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_telem_rf_id); - break; - case HWSETTINGS_SPK2_FLEXIPORT_I2C: + + if (hwsettings_flexiport < NELEMENTS(flexi_function_map)) { + PIOS_BOARD_IO_Configure_UART(&pios_usart_flexi_cfg, flexi_function_map[hwsettings_flexiport]); + } + #if defined(PIOS_INCLUDE_I2C) -#if defined(PIOS_INCLUDE_HMC5X83) - { - // get auxmag type - AuxMagSettingsTypeOptions option; - AuxMagSettingsTypeGet(&option); - // the FlexiPort type is I2C, so if the AuxMag type is Flexi(Port) then set it up - if (option == AUXMAGSETTINGS_TYPE_FLEXI) { - if (PIOS_I2C_Init(&pios_i2c_flexiport_adapter_id, &pios_i2c_flexiport_adapter_cfg)) { - PIOS_Assert(0); - } - PIOS_DELAY_WaitmS(50); // this was after the other PIOS_I2C_Init(), so I copied it here too -#ifdef PIOS_INCLUDE_WDG - // give HMC5x83 on I2C some extra time to allow for reset, etc. if needed - // this is not in a loop, so it is safe - // leave this here even if PIOS_INCLUDE_HMC5X83 is undefined - // to avoid making something else fail when HMC5X83 is removed - PIOS_WDG_Clear(); -#endif /* PIOS_INCLUDE_WDG */ - // attach the 5x83 mag to the previously inited I2C2 - flexi_port_mag = PIOS_HMC5x83_Init(&pios_hmc5x83_cfg, pios_i2c_flexiport_adapter_id, 0); -#ifdef PIOS_INCLUDE_WDG - // give HMC5x83 on I2C some extra time to allow for reset, etc. if needed - // this is not in a loop, so it is safe - PIOS_WDG_Clear(); -#endif /* PIOS_INCLUDE_WDG */ - // add this sensor to the sensor task's list - // be careful that you don't register a slow, unimportant sensor after registering the fastest sensor - // and before registering some other fast and important sensor - // as that would cause delay and time jitter for the second fast sensor - PIOS_HMC5x83_Register(flexi_port_mag, PIOS_SENSORS_TYPE_3AXIS_AUXMAG); - // mag alarm is cleared later, so use I2C - AlarmsSet(SYSTEMALARMS_ALARM_I2C, (flexi_port_mag) ? SYSTEMALARMS_ALARM_OK : SYSTEMALARMS_ALARM_WARNING); - } - } -#endif /* PIOS_INCLUDE_HMC5X83 */ -#endif /* PIOS_INCLUDE_I2C */ - break; - case HWSETTINGS_SPK2_FLEXIPORT_GPS: - PIOS_Board_configure_com(&pios_usart_flexi_cfg, PIOS_COM_GPS_RX_BUF_LEN, PIOS_COM_GPS_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_gps_id); - break; - case HWSETTINGS_SPK2_FLEXIPORT_DSM: - // TODO: Define the various Channelgroup for Sparky2 dsm inputs and handle here - PIOS_Board_configure_dsm(&pios_usart_dsm_flexi_cfg, &pios_dsm_flexi_cfg, - &pios_usart_com_driver, MANUALCONTROLSETTINGS_CHANNELGROUPS_DSMFLEXIPORT, &hwsettings_DSMxBind); - break; - case HWSETTINGS_SPK2_FLEXIPORT_DEBUGCONSOLE: -#if defined(PIOS_INCLUDE_DEBUG_CONSOLE) - { - PIOS_Board_configure_com(&pios_usart_flexi_cfg, 0, PIOS_COM_DEBUGCONSOLE_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_debug_id); + /* Set up internal I2C bus */ + if (PIOS_I2C_Init(&pios_i2c_mag_pressure_adapter_id, &pios_i2c_mag_pressure_adapter_cfg)) { + PIOS_DEBUG_Assert(0); + } + PIOS_DELAY_WaitmS(50); + + if (hwsettings_flexiport == HWSETTINGS_RM_FLEXIPORT_I2C) { + if (PIOS_I2C_Init(&pios_i2c_flexiport_adapter_id, &pios_i2c_flexiport_adapter_cfg)) { + PIOS_Assert(0); } -#endif /* PIOS_INCLUDE_DEBUG_CONSOLE */ - break; - case HWSETTINGS_SPK2_FLEXIPORT_COMBRIDGE: - PIOS_Board_configure_com(&pios_usart_flexi_cfg, PIOS_COM_BRIDGE_RX_BUF_LEN, PIOS_COM_BRIDGE_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_bridge_id); - break; - case HWSETTINGS_SPK2_FLEXIPORT_MSP: - PIOS_Board_configure_com(&pios_usart_flexi_cfg, PIOS_COM_MSP_RX_BUF_LEN, PIOS_COM_MSP_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_msp_id); - break; - case HWSETTINGS_SPK2_FLEXIPORT_MAVLINK: - PIOS_Board_configure_com(&pios_usart_flexi_cfg, 0, PIOS_COM_MAVLINK_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_mavlink_id); - break; - case HWSETTINGS_SPK2_FLEXIPORT_OSDHK: - PIOS_Board_configure_com(&pios_usart_hkosd_flexi_cfg, PIOS_COM_HKOSD_RX_BUF_LEN, PIOS_COM_HKOSD_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_hkosd_id); - break; - case HWSETTINGS_SPK2_FLEXIPORT_SRXL: -#if defined(PIOS_INCLUDE_SRXL) - PIOS_Board_configure_srxl(&pios_usart_srxl_flexi_cfg); -#endif /* PIOS_INCLUDE_SRXL */ - break; - - case HWSETTINGS_SPK2_FLEXIPORT_IBUS: -#if defined(PIOS_INCLUDE_IBUS) - PIOS_Board_configure_ibus(&pios_usart_ibus_flexi_cfg); -#endif /* PIOS_INCLUDE_IBUS */ - break; - - case HWSETTINGS_SPK2_FLEXIPORT_HOTTSUMD: - case HWSETTINGS_SPK2_FLEXIPORT_HOTTSUMH: -#if defined(PIOS_INCLUDE_HOTT) - PIOS_Board_configure_hott(&pios_usart_hott_flexi_cfg, - hwsettings_flexiport == HWSETTINGS_SPK2_FLEXIPORT_HOTTSUMD ? PIOS_HOTT_PROTO_SUMD : PIOS_HOTT_PROTO_SUMH); -#endif /* PIOS_INCLUDE_HOTT */ - break; - - case HWSETTINGS_SPK2_FLEXIPORT_EXBUS: -#if defined(PIOS_INCLUDE_EXBUS) - PIOS_Board_configure_exbus(&pios_usart_exbus_flexi_cfg); -#endif /* PIOS_INCLUDE_EXBUS */ - break; - } /* hwsettings_spk2_flexiport */ + PIOS_DELAY_WaitmS(50); + } + + PIOS_BOARD_IO_Configure_I2C(pios_i2c_mag_pressure_adapter_id, pios_i2c_flexiport_adapter_id); +#endif /* Moved this here to allow binding on flexiport */ #if defined(PIOS_INCLUDE_FLASH) @@ -624,472 +248,62 @@ void PIOS_Board_Init(void) #endif /* if defined(PIOS_INCLUDE_FLASH) */ #if defined(PIOS_INCLUDE_USB) - /* Initialize board specific USB data */ - PIOS_USB_BOARD_DATA_Init(); - - /* Flags to determine if various USB interfaces are advertised */ - bool usb_hid_present = false; - bool usb_cdc_present = false; - -#if defined(PIOS_INCLUDE_USB_CDC) - if (PIOS_USB_DESC_HID_CDC_Init()) { - PIOS_Assert(0); - } - usb_hid_present = true; - usb_cdc_present = true; -#else - if (PIOS_USB_DESC_HID_ONLY_Init()) { - PIOS_Assert(0); - } - usb_hid_present = true; + PIOS_BOARD_IO_Configure_USB(); #endif - uint32_t pios_usb_id; - PIOS_USB_Init(&pios_usb_id, PIOS_BOARD_HW_DEFS_GetUsbCfg(bdinfo->board_rev)); - -#if defined(PIOS_INCLUDE_USB_CDC) - - uint8_t hwsettings_usb_vcpport; - /* Configure the USB VCP port */ - HwSettingsUSB_VCPPortGet(&hwsettings_usb_vcpport); - - if (!usb_cdc_present) { - /* Force VCP port function to disabled if we haven't advertised VCP in our USB descriptor */ - hwsettings_usb_vcpport = HWSETTINGS_USB_VCPPORT_DISABLED; - } - uint32_t pios_usb_cdc_id; - if (PIOS_USB_CDC_Init(&pios_usb_cdc_id, &pios_usb_cdc_cfg, pios_usb_id)) { - PIOS_Assert(0); - } - - uint32_t pios_usb_hid_id; - if (PIOS_USB_HID_Init(&pios_usb_hid_id, &pios_usb_hid_cfg, pios_usb_id)) { - PIOS_Assert(0); - } - - switch (hwsettings_usb_vcpport) { - case HWSETTINGS_USB_VCPPORT_DISABLED: - break; - case HWSETTINGS_USB_VCPPORT_USBTELEMETRY: -#if defined(PIOS_INCLUDE_COM) - { - uint8_t *rx_buffer = (uint8_t *)pios_malloc(PIOS_COM_TELEM_USB_RX_BUF_LEN); - uint8_t *tx_buffer = (uint8_t *)pios_malloc(PIOS_COM_TELEM_USB_TX_BUF_LEN); - PIOS_Assert(rx_buffer); - PIOS_Assert(tx_buffer); - if (PIOS_COM_Init(&pios_com_telem_usb_id, &pios_usb_cdc_com_driver, pios_usb_cdc_id, - rx_buffer, PIOS_COM_TELEM_USB_RX_BUF_LEN, - tx_buffer, PIOS_COM_TELEM_USB_TX_BUF_LEN)) { - PIOS_Assert(0); - } - } -#endif /* PIOS_INCLUDE_COM */ - break; - case HWSETTINGS_USB_VCPPORT_COMBRIDGE: -#if defined(PIOS_INCLUDE_COM) - { - uint8_t *rx_buffer = (uint8_t *)pios_malloc(PIOS_COM_BRIDGE_RX_BUF_LEN); - uint8_t *tx_buffer = (uint8_t *)pios_malloc(PIOS_COM_BRIDGE_TX_BUF_LEN); - PIOS_Assert(rx_buffer); - PIOS_Assert(tx_buffer); - if (PIOS_COM_Init(&pios_com_vcp_id, &pios_usb_cdc_com_driver, pios_usb_cdc_id, - rx_buffer, PIOS_COM_BRIDGE_RX_BUF_LEN, - tx_buffer, PIOS_COM_BRIDGE_TX_BUF_LEN)) { - PIOS_Assert(0); - } - } -#endif /* PIOS_INCLUDE_COM */ - break; - case HWSETTINGS_USB_VCPPORT_DEBUGCONSOLE: -#if defined(PIOS_INCLUDE_COM) -#if defined(PIOS_INCLUDE_DEBUG_CONSOLE) - { - uint8_t *tx_buffer = (uint8_t *)pios_malloc(PIOS_COM_DEBUGCONSOLE_TX_BUF_LEN); - PIOS_Assert(tx_buffer); - if (PIOS_COM_Init(&pios_com_debug_id, &pios_usb_cdc_com_driver, pios_usb_cdc_id, - NULL, 0, - tx_buffer, PIOS_COM_DEBUGCONSOLE_TX_BUF_LEN)) { - PIOS_Assert(0); - } - } -#endif /* PIOS_INCLUDE_DEBUG_CONSOLE */ -#endif /* PIOS_INCLUDE_COM */ - - break; - } -#endif /* PIOS_INCLUDE_USB_CDC */ - -#if defined(PIOS_INCLUDE_USB_HID) - /* Configure the usb HID port */ - uint8_t hwsettings_usb_hidport; - HwSettingsUSB_HIDPortGet(&hwsettings_usb_hidport); - - if (!usb_hid_present) { - /* Force HID port function to disabled if we haven't advertised HID in our USB descriptor */ - hwsettings_usb_hidport = HWSETTINGS_USB_HIDPORT_DISABLED; - } - - switch (hwsettings_usb_hidport) { - case HWSETTINGS_USB_HIDPORT_DISABLED: - break; - case HWSETTINGS_USB_HIDPORT_USBTELEMETRY: -#if defined(PIOS_INCLUDE_COM) - { - uint8_t *rx_buffer = (uint8_t *)pios_malloc(PIOS_COM_TELEM_USB_RX_BUF_LEN); - uint8_t *tx_buffer = (uint8_t *)pios_malloc(PIOS_COM_TELEM_USB_TX_BUF_LEN); - PIOS_Assert(rx_buffer); - PIOS_Assert(tx_buffer); - if (PIOS_COM_Init(&pios_com_telem_usb_id, &pios_usb_hid_com_driver, pios_usb_hid_id, - rx_buffer, PIOS_COM_TELEM_USB_RX_BUF_LEN, - tx_buffer, PIOS_COM_TELEM_USB_TX_BUF_LEN)) { - PIOS_Assert(0); - } - } -#endif /* PIOS_INCLUDE_COM */ - break; - } - -#endif /* PIOS_INCLUDE_USB_HID */ - - if (usb_hid_present || usb_cdc_present) { - PIOS_USBHOOK_Activate(); - } -#endif /* PIOS_INCLUDE_USB */ - - - /* Configure main USART port */ uint8_t hwsettings_mainport; HwSettingsSPK2_MainPortGet(&hwsettings_mainport); - switch (hwsettings_mainport) { - case HWSETTINGS_SPK2_MAINPORT_DISABLED: - break; - case HWSETTINGS_SPK2_MAINPORT_TELEMETRY: - PIOS_Board_configure_com(&pios_usart_main_cfg, PIOS_COM_TELEM_RF_RX_BUF_LEN, PIOS_COM_TELEM_RF_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_telem_rf_id); - break; - case HWSETTINGS_SPK2_MAINPORT_GPS: - PIOS_Board_configure_com(&pios_usart_main_cfg, PIOS_COM_GPS_RX_BUF_LEN, PIOS_COM_GPS_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_gps_id); - break; - case HWSETTINGS_SPK2_MAINPORT_DSM: - // Force binding to zero on the main port - hwsettings_DSMxBind = 0; - - // TODO: Define the various Channelgroup for Sparky2 dsm inputs and handle here - PIOS_Board_configure_dsm(&pios_usart_dsm_main_cfg, &pios_dsm_main_cfg, - &pios_usart_com_driver, MANUALCONTROLSETTINGS_CHANNELGROUPS_DSMMAINPORT, &hwsettings_DSMxBind); - break; - case HWSETTINGS_SPK2_MAINPORT_DEBUGCONSOLE: -#if defined(PIOS_INCLUDE_DEBUG_CONSOLE) - { - PIOS_Board_configure_com(&pios_usart_main_cfg, 0, PIOS_COM_DEBUGCONSOLE_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_debug_id); - } -#endif /* PIOS_INCLUDE_DEBUG_CONSOLE */ - break; - case HWSETTINGS_SPK2_MAINPORT_COMBRIDGE: - PIOS_Board_configure_com(&pios_usart_main_cfg, PIOS_COM_BRIDGE_RX_BUF_LEN, PIOS_COM_BRIDGE_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_bridge_id); - break; - case HWSETTINGS_SPK2_MAINPORT_MSP: - PIOS_Board_configure_com(&pios_usart_main_cfg, PIOS_COM_MSP_RX_BUF_LEN, PIOS_COM_MSP_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_msp_id); - break; - case HWSETTINGS_SPK2_MAINPORT_MAVLINK: - PIOS_Board_configure_com(&pios_usart_main_cfg, 0, PIOS_COM_MAVLINK_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_mavlink_id); - break; - case HWSETTINGS_SPK2_MAINPORT_OSDHK: - PIOS_Board_configure_com(&pios_usart_hkosd_main_cfg, PIOS_COM_HKOSD_RX_BUF_LEN, PIOS_COM_HKOSD_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_hkosd_id); - break; - } /* hwsettings_spk2_mainport */ - - - /* Initialize the RFM22B radio COM device. */ -#if defined(PIOS_INCLUDE_RFM22B) - - /* Fetch the OPLinkSettings object. */ - OPLinkSettingsData oplinkSettings; - OPLinkSettingsGet(&oplinkSettings); - - // Initialize out status object. - OPLinkStatusData oplinkStatus; - OPLinkStatusGet(&oplinkStatus); - oplinkStatus.BoardType = bdinfo->board_type; - PIOS_BL_HELPER_FLASH_Read_Description(oplinkStatus.Description, OPLINKSTATUS_DESCRIPTION_NUMELEM); - PIOS_SYS_SerialNumberGetBinary(oplinkStatus.CPUSerial); - oplinkStatus.BoardRevision = bdinfo->board_rev; - - /* Is the radio turned on? */ - bool is_coordinator = (oplinkSettings.Protocol == OPLINKSETTINGS_PROTOCOL_OPLINKCOORDINATOR); - bool openlrs = (oplinkSettings.Protocol == OPLINKSETTINGS_PROTOCOL_OPENLRS); - bool data_mode = ((oplinkSettings.LinkType == OPLINKSETTINGS_LINKTYPE_DATA) || - (oplinkSettings.LinkType == OPLINKSETTINGS_LINKTYPE_DATAANDCONTROL)); - bool ppm_mode = ((oplinkSettings.LinkType == OPLINKSETTINGS_LINKTYPE_CONTROL) || - (oplinkSettings.LinkType == OPLINKSETTINGS_LINKTYPE_DATAANDCONTROL)); - bool is_enabled = ((oplinkSettings.Protocol != OPLINKSETTINGS_PROTOCOL_DISABLED) && - ((oplinkSettings.MaxRFPower != OPLINKSETTINGS_MAXRFPOWER_0) || openlrs)); - if (is_enabled) { - if (openlrs) { -#if defined(PIOS_INCLUDE_OPENLRS_RCVR) - const struct pios_openlrs_cfg *openlrs_cfg = PIOS_BOARD_HW_DEFS_GetOpenLRSCfg(); - uint32_t openlrs_id; - - PIOS_OpenLRS_Init(&openlrs_id, PIOS_RFM22_SPI_PORT, 0, openlrs_cfg); - { - uint32_t openlrsrcvr_id; - PIOS_OpenLRS_Rcvr_Init(&openlrsrcvr_id, openlrs_id); - uint32_t openlrsrcvr_rcvr_id; - if (PIOS_RCVR_Init(&openlrsrcvr_rcvr_id, &pios_openlrs_rcvr_driver, openlrsrcvr_id)) { - PIOS_Assert(0); - } - pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_OPENLRS] = openlrsrcvr_rcvr_id; - } -#endif /* PIOS_INCLUDE_OPENLRS_RCVR */ - } else { - /* Configure the RFM22B device. */ - const struct pios_rfm22b_cfg *rfm22b_cfg = PIOS_BOARD_HW_DEFS_GetRfm22Cfg(bdinfo->board_rev); - - if (PIOS_RFM22B_Init(&pios_rfm22b_id, PIOS_RFM22_SPI_PORT, rfm22b_cfg->slave_num, rfm22b_cfg, oplinkSettings.RFBand)) { - PIOS_Assert(0); - } - - /* Configure the radio com interface */ - uint8_t *rx_buffer = (uint8_t *)pios_malloc(PIOS_COM_RFM22B_RF_RX_BUF_LEN); - uint8_t *tx_buffer = (uint8_t *)pios_malloc(PIOS_COM_RFM22B_RF_TX_BUF_LEN); - PIOS_Assert(rx_buffer); - PIOS_Assert(tx_buffer); - if (PIOS_COM_Init(&pios_com_rf_id, &pios_rfm22b_com_driver, pios_rfm22b_id, - rx_buffer, PIOS_COM_RFM22B_RF_RX_BUF_LEN, - tx_buffer, PIOS_COM_RFM22B_RF_TX_BUF_LEN)) { - PIOS_Assert(0); - } - - oplinkStatus.LinkState = OPLINKSTATUS_LINKSTATE_ENABLED; - - // Set the modem (over the air) datarate. - enum rfm22b_datarate datarate = RFM22_datarate_64000; - switch (oplinkSettings.AirDataRate) { - case OPLINKSETTINGS_AIRDATARATE_9600: - datarate = RFM22_datarate_9600; - break; - case OPLINKSETTINGS_AIRDATARATE_19200: - datarate = RFM22_datarate_19200; - break; - case OPLINKSETTINGS_AIRDATARATE_32000: - datarate = RFM22_datarate_32000; - break; - case OPLINKSETTINGS_AIRDATARATE_57600: - datarate = RFM22_datarate_57600; - break; - case OPLINKSETTINGS_AIRDATARATE_64000: - datarate = RFM22_datarate_64000; - break; - case OPLINKSETTINGS_AIRDATARATE_100000: - datarate = RFM22_datarate_100000; - break; - case OPLINKSETTINGS_AIRDATARATE_128000: - datarate = RFM22_datarate_128000; - break; - case OPLINKSETTINGS_AIRDATARATE_192000: - datarate = RFM22_datarate_192000; - break; - case OPLINKSETTINGS_AIRDATARATE_256000: - datarate = RFM22_datarate_256000; - break; - } - - /* Set the radio configuration parameters. */ - PIOS_RFM22B_SetDeviceID(pios_rfm22b_id, oplinkSettings.CustomDeviceID); - PIOS_RFM22B_SetCoordinatorID(pios_rfm22b_id, oplinkSettings.CoordID); - PIOS_RFM22B_SetXtalCap(pios_rfm22b_id, oplinkSettings.RFXtalCap); - PIOS_RFM22B_SetChannelConfig(pios_rfm22b_id, datarate, oplinkSettings.MinChannel, oplinkSettings.MaxChannel, is_coordinator, data_mode, ppm_mode); - - /* Set the modem Tx poer level */ - switch (oplinkSettings.MaxRFPower) { - case OPLINKSETTINGS_MAXRFPOWER_125: - PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_0); - break; - case OPLINKSETTINGS_MAXRFPOWER_16: - PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_1); - break; - case OPLINKSETTINGS_MAXRFPOWER_316: - PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_2); - break; - case OPLINKSETTINGS_MAXRFPOWER_63: - PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_3); - break; - case OPLINKSETTINGS_MAXRFPOWER_126: - PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_4); - break; - case OPLINKSETTINGS_MAXRFPOWER_25: - PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_5); - break; - case OPLINKSETTINGS_MAXRFPOWER_50: - PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_6); - break; - case OPLINKSETTINGS_MAXRFPOWER_100: - PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_7); - break; - default: - // do nothing - break; - } - - /* Reinitialize the modem. */ - PIOS_RFM22B_Reinit(pios_rfm22b_id); - // TODO: this is in preparation for full mavlink support and is used by LP-368 - uint16_t mavlink_rx_size = PIOS_COM_MAVLINK_RX_BUF_LEN; - - uint8_t hwsettings_radioaux; - HwSettingsRadioAuxStreamGet(&hwsettings_radioaux); - - switch (hwsettings_radioaux) { - case HWSETTINGS_RADIOAUXSTREAM_DEBUGCONSOLE: - case HWSETTINGS_RADIOAUXSTREAM_DISABLED: - break; - case HWSETTINGS_RADIOAUXSTREAM_MAVLINK: - { - uint8_t *auxrx_buffer = 0; - if (mavlink_rx_size) { - auxrx_buffer = (uint8_t *)pios_malloc(mavlink_rx_size); - } - uint8_t *auxtx_buffer = (uint8_t *)pios_malloc(PIOS_COM_MAVLINK_TX_BUF_LEN); - PIOS_Assert(auxrx_buffer); - PIOS_Assert(auxtx_buffer); - if (PIOS_COM_Init(&pios_com_mavlink_id, &pios_rfm22b_aux_com_driver, pios_rfm22b_id, - auxrx_buffer, mavlink_rx_size, - auxtx_buffer, PIOS_COM_BRIDGE_TX_BUF_LEN)) { - PIOS_Assert(0); - } - } - } - } - } else { - oplinkStatus.LinkState = OPLINKSTATUS_LINKSTATE_DISABLED; + if (hwsettings_mainport < NELEMENTS(main_function_map)) { + PIOS_BOARD_IO_Configure_UART(&pios_usart_main_cfg, main_function_map[hwsettings_mainport]); } - - OPLinkStatusSet(&oplinkStatus); + +#if defined(PIOS_INCLUDE_RFM22B) + PIOS_BOARD_IO_Configure_RFM22B(); #endif /* PIOS_INCLUDE_RFM22B */ -#if 1 -#if defined(PIOS_INCLUDE_PPM) - const struct pios_servo_cfg *pios_servo_cfg; - // default to servo outputs only - pios_servo_cfg = &pios_servo_cfg_out; -#endif -#endif + /* Initialize inverter gpio and set it to off */ + { + GPIO_InitTypeDef inverterGPIOInit = { + .GPIO_Pin = RCVR_USART_INVERTER_PIN, + .GPIO_Speed = GPIO_Speed_2MHz, + .GPIO_Mode = GPIO_Mode_OUT, + .GPIO_OType = GPIO_OType_PP, + .GPIO_PuPd = GPIO_PuPd_UP + }; + + GPIO_Init(RCVR_USART_INVERTER_GPIO, &inverterGPIOInit); + GPIO_WriteBit(RCVR_USART_INVERTER_GPIO, + RCVR_USART_INVERTER_PIN, + RCVR_USART_INVERTER_DISABLE); + } // Configure the receiver port // Sparky2 receiver input on PC7 TIM8 CH2 // include PPM,S.Bus,DSM,SRXL,IBus,EX.Bus,HoTT SUMD,HoTT SUMH + /* Configure the receiver port*/ + uint8_t hwsettings_rcvrport; HwSettingsSPK2_RcvrPortGet(&hwsettings_rcvrport); - - switch (hwsettings_rcvrport) { - case HWSETTINGS_SPK2_RCVRPORT_PPM: -#if defined(PIOS_INCLUDE_PPM) - PIOS_Board_configure_ppm(&pios_ppm_cfg); -#endif /* PIOS_INCLUDE_PPM */ - break; - case HWSETTINGS_SPK2_RCVRPORT_SBUS: -#if defined(PIOS_INCLUDE_SBUS) - { - uint32_t pios_usart_sbus_id; - if (PIOS_USART_Init(&pios_usart_sbus_id, &pios_usart_sbus_rcvr_cfg)) { - PIOS_Assert(0); - } - - uint32_t pios_sbus_id; - if (PIOS_SBus_Init(&pios_sbus_id, &pios_sbus_cfg, &pios_usart_com_driver, pios_usart_sbus_id)) { - PIOS_Assert(0); - } - - uint32_t pios_sbus_rcvr_id; - if (PIOS_RCVR_Init(&pios_sbus_rcvr_id, &pios_sbus_rcvr_driver, pios_sbus_id)) { - PIOS_Assert(0); - } - pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_SBUS] = pios_sbus_rcvr_id; - } -#endif - break; - case HWSETTINGS_SPK2_RCVRPORT_SRXL: -#if defined(PIOS_INCLUDE_SRXL) - PIOS_Board_configure_srxl(&pios_usart_srxl_rcvr_cfg); -#endif /* PIOS_INCLUDE_SRXL */ - break; - case HWSETTINGS_SPK2_RCVRPORT_IBUS: -#if defined(PIOS_INCLUDE_IBUS) - PIOS_Board_configure_ibus(&pios_usart_ibus_rcvr_cfg); -#endif /* PIOS_INCLUDE_IBUS */ - break; - case HWSETTINGS_SPK2_RCVRPORT_HOTTSUMD: - case HWSETTINGS_SPK2_RCVRPORT_HOTTSUMH: -#if defined(PIOS_INCLUDE_HOTT) - PIOS_Board_configure_hott(&pios_usart_hott_rcvr_cfg, - hwsettings_rcvrport == HWSETTINGS_SPK2_RCVRPORT_HOTTSUMD ? PIOS_HOTT_PROTO_SUMD : PIOS_HOTT_PROTO_SUMH); -#endif /* PIOS_INCLUDE_HOTT */ - break; - - case HWSETTINGS_SPK2_RCVRPORT_EXBUS: -#if defined(PIOS_INCLUDE_EXBUS) - PIOS_Board_configure_exbus(&pios_usart_exbus_rcvr_cfg); -#endif /* PIOS_INCLUDE_EXBUS */ - break; - case HWSETTINGS_SPK2_RCVRPORT_DSM: - // TODO: Define the various Channelgroup for Sparky2 dsm inputs and handle here - PIOS_Board_configure_dsm(&pios_usart_dsm_rcvr_cfg, &pios_dsm_rcvr_cfg, - &pios_usart_com_driver, MANUALCONTROLSETTINGS_CHANNELGROUPS_DSMRCVRPORT, &hwsettings_DSMxBind); - break; - default: - break; + + if (hwsettings_rcvrport < NELEMENTS(rcvr_function_map)) { + PIOS_BOARD_IO_Configure_UART(&pios_usart_rcvr_cfg, rcvr_function_map[hwsettings_rcvrport]); } - if (hwsettings_rcvrport != HWSETTINGS_SPK2_RCVRPORT_SBUS) { - GPIO_Init(pios_sbus_cfg.inv.gpio, &pios_sbus_cfg.inv.init); - GPIO_WriteBit(pios_sbus_cfg.inv.gpio, pios_sbus_cfg.inv.init.GPIO_Pin, pios_sbus_cfg.gpio_inv_disable); - } - -#if defined(PIOS_INCLUDE_GCSRCVR) - GCSReceiverInitialize(); - uint32_t pios_gcsrcvr_id; - PIOS_GCSRCVR_Init(&pios_gcsrcvr_id); - uint32_t pios_gcsrcvr_rcvr_id; - if (PIOS_RCVR_Init(&pios_gcsrcvr_rcvr_id, &pios_gcsrcvr_rcvr_driver, pios_gcsrcvr_id)) { - PIOS_Assert(0); +#if defined(PIOS_INCLUDE_PPM) + if(hwsettings_rcvrport == HWSETTINGS_SPK2_RCVRPORT_PPM) { + PIOS_BOARD_IO_Configure_PPM(&pios_ppm_cfg); } - pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_GCS] = pios_gcsrcvr_rcvr_id; -#endif /* PIOS_INCLUDE_GCSRCVR */ +#endif -#if defined(PIOS_INCLUDE_OPLINKRCVR) - { - OPLinkReceiverInitialize(); - uint32_t pios_oplinkrcvr_id; - PIOS_OPLinkRCVR_Init(&pios_oplinkrcvr_id, pios_rfm22b_id); - uint32_t pios_oplinkrcvr_rcvr_id; - if (PIOS_RCVR_Init(&pios_oplinkrcvr_rcvr_id, &pios_oplinkrcvr_rcvr_driver, pios_oplinkrcvr_id)) { - PIOS_Assert(0); - } - pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_OPLINK] = pios_oplinkrcvr_rcvr_id; - } -#endif /* PIOS_INCLUDE_OPLINKRCVR */ +#ifdef PIOS_INCLUDE_GCSRCVR + PIOS_BOARD_IO_Configure_GCSRCVR(); +#endif -#if 1 #ifndef PIOS_ENABLE_DEBUG_PINS - // pios_servo_cfg points to the correct configuration based on input port settings - PIOS_Servo_Init(pios_servo_cfg); + PIOS_Servo_Init(&pios_servo_cfg_out); #else PIOS_DEBUG_Init(pios_tim_servoport_all_pins, NELEMENTS(pios_tim_servoport_all_pins)); #endif -#endif - - // Disable GPIO_A8 Pullup to prevent wrong results on battery voltage readout - GPIO_InitTypeDef gpioA8 = { - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_IN, - .GPIO_PuPd = GPIO_PuPd_NOPULL, - .GPIO_Pin = GPIO_Pin_8, - .GPIO_OType = GPIO_OType_OD, - }; - GPIO_Init(GPIOA, &gpioA8); - -#if defined(PIOS_INCLUDE_ADC) - PIOS_ADC_Init(&pios_adc_cfg); -#endif #if defined(PIOS_INCLUDE_MPU9250) PIOS_MPU9250_Init(pios_spi_gyro_id, 0, &pios_mpu9250_cfg); @@ -1098,71 +312,7 @@ void PIOS_Board_Init(void) PIOS_MPU9250_MagRegister(); #endif -#if 0 -#ifdef PIOS_INCLUDE_WDG - // give HMC5x83 on I2C some extra time to allow for reset, etc. if needed - // this is not in a loop, so it is safe - // leave this here even if PIOS_INCLUDE_HMC5X83 is undefined - // to avoid making something else fail when HMC5X83 is removed - PIOS_WDG_Clear(); -#endif /* PIOS_INCLUDE_WDG */ - -#if defined(PIOS_INCLUDE_HMC5X83) - // on board mag is in the MPU9250 - // this hmc5x83 mag is an external mag - i2c_port_mag = PIOS_HMC5x83_Init(&pios_hmc5x83_cfg, pios_i2c_mag_pressure_adapter_id, 0); -#ifdef PIOS_INCLUDE_WDG - // give HMC5x83 on I2C some extra time to allow for reset, etc. if needed - // this is not in a loop, so it is safe - PIOS_WDG_Clear(); -#endif /* PIOS_INCLUDE_WDG */ - PIOS_HMC5x83_Register(i2c_port_mag, PIOS_SENSORS_TYPE_3AXIS_AUXMAG); -#endif /* PIOS_INCLUDE_HMC5X83 */ - -#else /* if 0 */ - -#if defined(PIOS_INCLUDE_I2C) -#ifdef PIOS_INCLUDE_WDG - // give HMC5x83 on I2C some extra time to allow for reset, etc. if needed - // this is not in a loop, so it is safe - // leave this here even if PIOS_INCLUDE_HMC5X83 is undefined - // to avoid making something else fail when HMC5X83 is removed - PIOS_WDG_Clear(); -#endif /* PIOS_INCLUDE_WDG */ -#if defined(PIOS_INCLUDE_HMC5X83) - // get auxmag type - HwSettingsSPK2_I2CPortOptions i2cOption; - AuxMagSettingsTypeOptions option; - HwSettingsSPK2_I2CPortGet(&i2cOption); - AuxMagSettingsTypeGet(&option); - // if the I2CPort type is I2C(Port) and the AuxMag type is I2C(Port) then set it up - if (i2cOption == HWSETTINGS_SPK2_I2CPORT_I2C && option == AUXMAGSETTINGS_TYPE_I2C) { - // attach the 5x83 mag to the previously inited I2C2 - i2c_port_mag = PIOS_HMC5x83_Init(&pios_hmc5x83_cfg, pios_i2c_mag_pressure_adapter_id, 0); -#ifdef PIOS_INCLUDE_WDG - // give HMC5x83 on I2C some extra time to allow for reset, etc. if needed - // this is not in a loop, so it is safe - PIOS_WDG_Clear(); -#endif /* PIOS_INCLUDE_WDG */ - // add this sensor to the sensor task's list - // be careful that you don't register a slow, unimportant sensor after registering the fastest sensor - // and before registering some other fast and important sensor - // as that would cause delay and time jitter for the second fast sensor - PIOS_HMC5x83_Register(i2c_port_mag, PIOS_SENSORS_TYPE_3AXIS_AUXMAG); - // mag alarm is cleared later, so use I2C - AlarmsSet(SYSTEMALARMS_ALARM_I2C, (i2c_port_mag) ? SYSTEMALARMS_ALARM_OK : SYSTEMALARMS_ALARM_WARNING); - } -#endif /* PIOS_INCLUDE_HMC5X83 */ -#endif /* PIOS_INCLUDE_I2C */ -#endif /* 0 */ - -#if defined(PIOS_INCLUDE_MS5611) - PIOS_MS5611_Init(&pios_ms5611_cfg, pios_i2c_mag_pressure_adapter_id); - PIOS_MS5611_Register(); -#endif /* PIOS_INCLUDE_MS5611 */ - - #ifdef PIOS_INCLUDE_WS2811 -#include +#ifdef PIOS_INCLUDE_WS2811 HwSettingsWS2811LED_OutOptions ws2811_pin_settings; HwSettingsWS2811LED_OutGet(&ws2811_pin_settings); @@ -1170,17 +320,21 @@ void PIOS_Board_Init(void) PIOS_WS2811_Init(&pios_ws2811_cfg, &pios_ws2811_pin_cfg[ws2811_pin_settings]); } #endif // PIOS_INCLUDE_WS2811 + #ifdef PIOS_INCLUDE_ADC - { - uint8_t adc_config[HWSETTINGS_ADCROUTING_NUMELEM]; - HwSettingsADCRoutingArrayGet(adc_config); - for (uint32_t i = 0; i < HWSETTINGS_ADCROUTING_NUMELEM; i++) { - if (adc_config[i] != HWSETTINGS_ADCROUTING_DISABLED) { - PIOS_ADC_PinSetup(i); - } - } - } -#endif // PIOS_INCLUDE_ADC + // Disable GPIO_A8 Pullup to prevent wrong results on battery voltage readout + GPIO_InitTypeDef gpioA8 = { + .GPIO_Speed = GPIO_Speed_2MHz, + .GPIO_Mode = GPIO_Mode_IN, + .GPIO_PuPd = GPIO_PuPd_NOPULL, + .GPIO_Pin = GPIO_Pin_8, + .GPIO_OType = GPIO_OType_OD, + }; + GPIO_Init(GPIOA, &gpioA8); + + PIOS_BOARD_IO_Configure_ADC(); +#endif /* PIOS_INCLUDE_ADC */ + } /** diff --git a/shared/uavobjectdefinition/hwsettings.xml b/shared/uavobjectdefinition/hwsettings.xml index fed486c90f..6f74f84251 100644 --- a/shared/uavobjectdefinition/hwsettings.xml +++ b/shared/uavobjectdefinition/hwsettings.xml @@ -34,6 +34,7 @@ + From c0adcb904bd15f9680e34a7035859d74c5ca0739 Mon Sep 17 00:00:00 2001 From: Vladimir Zidar Date: Wed, 19 Apr 2017 15:57:00 +0200 Subject: [PATCH 213/624] LP-480 build discoveryf4bare --- .../OpenPilotOSX.xcodeproj/project.pbxproj | 2 +- flight/pios/common/pios_board_io.c | 9 +- .../boards/discoveryf4bare/board_hw_defs.c | 883 ++++------------ .../discoveryf4bare/bootloader/pios_board.c | 10 +- .../discoveryf4bare/firmware/pios_board.c | 992 +++--------------- .../boards/revolution/bootloader/pios_board.c | 1 - 6 files changed, 398 insertions(+), 1499 deletions(-) diff --git a/flight/Project/OpenPilotOSX/OpenPilotOSX.xcodeproj/project.pbxproj b/flight/Project/OpenPilotOSX/OpenPilotOSX.xcodeproj/project.pbxproj index da24ebb793..bf7efbcf1e 100644 --- a/flight/Project/OpenPilotOSX/OpenPilotOSX.xcodeproj/project.pbxproj +++ b/flight/Project/OpenPilotOSX/OpenPilotOSX.xcodeproj/project.pbxproj @@ -184,7 +184,7 @@ /* Begin PBXLegacyTarget section */ 6581071511DE809D0049FB12 /* OpenPilotOSX */ = { isa = PBXLegacyTarget; - buildArgumentsString = ef_sparky2; + buildArgumentsString = ef_discoveryf4bare; buildConfigurationList = 6581071A11DE80A30049FB12 /* Build configuration list for PBXLegacyTarget "OpenPilotOSX" */; buildPhases = ( ); diff --git a/flight/pios/common/pios_board_io.c b/flight/pios/common/pios_board_io.c index 835ca272a8..f3b2ac92e7 100644 --- a/flight/pios/common/pios_board_io.c +++ b/flight/pios/common/pios_board_io.c @@ -708,14 +708,19 @@ void PIOS_BOARD_IO_Configure_I2C(uint32_t i2c_internal_id, uint32_t i2c_external if (hmc5x83_internal_cfg) { // attach the 5x83 mag to internal i2c bus - pios_hmc5x83_internal_id = PIOS_HMC5x83_Init(hmc5x83_internal_cfg, i2c_internal_id, 0); + + pios_hmc5x83_dev_t internal_mag = PIOS_HMC5x83_Init(hmc5x83_internal_cfg, i2c_internal_id, 0); # ifdef PIOS_INCLUDE_WDG // give HMC5x83 on I2C some extra time to allow for reset, etc. if needed // this is not in a loop, so it is safe PIOS_WDG_Clear(); # endif /* PIOS_INCLUDE_WDG */ + +#ifdef PIOS_HMC5X83_HAS_GPIOS + pios_hmc5x83_internal_id = internal_mag; +#endif // add this sensor to the sensor task's list - PIOS_HMC5x83_Register(pios_hmc5x83_internal_id, PIOS_SENSORS_TYPE_3AXIS_MAG); + PIOS_HMC5x83_Register(internal_mag, PIOS_SENSORS_TYPE_3AXIS_MAG); } # endif /* PIOS_INCLUDE_HMC5X83_INTERNAL */ diff --git a/flight/targets/boards/discoveryf4bare/board_hw_defs.c b/flight/targets/boards/discoveryf4bare/board_hw_defs.c index 0c833776b6..678a1500a4 100644 --- a/flight/targets/boards/discoveryf4bare/board_hw_defs.c +++ b/flight/targets/boards/discoveryf4bare/board_hw_defs.c @@ -602,75 +602,20 @@ static const struct flashfs_logfs_cfg flashfs_internal_user_cfg = { #include -#ifdef PIOS_INCLUDE_COM_TELEM - /* * MAIN USART */ -static const struct pios_usart_cfg pios_usart_main_cfg = { - .regs = USART1, - .remap = GPIO_AF_USART1, - .init = { - .USART_BaudRate = 57600, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx | USART_Mode_Tx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART1_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { - .gpio = GPIOA, - .init = { - .GPIO_Pin = GPIO_Pin_10, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, - .tx = { - .gpio = GPIOA, - .init = { - .GPIO_Pin = GPIO_Pin_9, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, -}; -#endif /* PIOS_INCLUDE_COM_TELEM */ +// Inverter for SBUS handling +#define MAIN_USART_INVERTER_GPIO GPIOC +#define MAIN_USART_INVERTER_PIN GPIO_Pin_0 +#define MAIN_USART_INVERTER_ENABLE Bit_SET +#define MAIN_USART_INVERTER_DISABLE Bit_RESET -#ifdef PIOS_INCLUDE_DSM +static int32_t PIOS_BOARD_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param); -#include "pios_dsm_priv.h" -static const struct pios_usart_cfg pios_usart_dsm_main_cfg = { +static const struct pios_usart_cfg pios_usart_main_cfg = { .regs = USART1, .remap = GPIO_AF_USART1, - .init = { - .USART_BaudRate = 115200, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART1_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, .rx = { .gpio = GPIOA, .init = { @@ -691,166 +636,15 @@ static const struct pios_usart_cfg pios_usart_dsm_main_cfg = { .GPIO_PuPd = GPIO_PuPd_UP }, }, + .ioctl = PIOS_BOARD_USART_Ioctl, }; -// Because of the inverter on the main port this will not -// work. Notice the mode is set to IN to maintain API -// compatibility but protect the pins -static const struct pios_dsm_cfg pios_dsm_main_cfg = { - .bind = { - .gpio = GPIOA, - .init = { - .GPIO_Pin = GPIO_Pin_10, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_IN, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_NOPULL - }, - }, -}; - -#endif /* PIOS_INCLUDE_DSM */ - -#include -#if defined(PIOS_INCLUDE_SBUS) -/* - * S.Bus USART - */ -#include - -static const struct pios_usart_cfg pios_usart_sbus_main_cfg = { - .regs = USART1, - .remap = GPIO_AF_USART1, - .init = { - .USART_BaudRate = 100000, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_Even, - .USART_StopBits = USART_StopBits_2, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART1_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { - .gpio = GPIOA, - .init = { - .GPIO_Pin = GPIO_Pin_10, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, - .tx = { - .gpio = GPIOA, - .init = { - .GPIO_Pin = GPIO_Pin_9, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_OUT, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_NOPULL - }, - }, -}; - -#endif /* PIOS_INCLUDE_SBUS */ - -// Need this defined regardless to be able to turn it off -static const struct pios_sbus_cfg pios_sbus_cfg = { - /* Inverter configuration */ - .inv = { - .gpio = GPIOC, - .init = { - .GPIO_Pin = GPIO_Pin_0, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_OUT, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, - .gpio_inv_enable = Bit_SET, - .gpio_inv_disable = Bit_RESET, - .gpio_clk_func = RCC_AHB1PeriphClockCmd, - .gpio_clk_periph = RCC_AHB1Periph_GPIOC, -}; - - -#ifdef PIOS_INCLUDE_COM_FLEXI /* * FLEXI PORT */ static const struct pios_usart_cfg pios_usart_flexi_cfg = { .regs = USART3, .remap = GPIO_AF_USART3, - .init = { - .USART_BaudRate = 57600, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = - USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx | USART_Mode_Tx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART3_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_11, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, - .tx = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_10, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, -}; - -#endif /* PIOS_INCLUDE_COM_FLEXI */ - -#ifdef PIOS_INCLUDE_DSM - -#include "pios_dsm_priv.h" -static const struct pios_usart_cfg pios_usart_dsm_flexi_cfg = { - .regs = USART3, - .remap = GPIO_AF_USART3, - .init = { - .USART_BaudRate = 115200, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART3_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, .rx = { .gpio = GPIOB, .init = { @@ -873,126 +667,10 @@ static const struct pios_usart_cfg pios_usart_dsm_flexi_cfg = { }, }; -static const struct pios_dsm_cfg pios_dsm_flexi_cfg = { - .bind = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_11, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_OUT, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_NOPULL - }, - }, -}; - -#endif /* PIOS_INCLUDE_DSM */ -/* - * HK OSD - */ -static const struct pios_usart_cfg pios_usart_hkosd_main_cfg = { - .regs = USART1, - .remap = GPIO_AF_USART1, - .init = { - .USART_BaudRate = 57600, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx | USART_Mode_Tx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART1_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { - .gpio = GPIOA, - .init = { - .GPIO_Pin = GPIO_Pin_10, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, - .tx = { - .gpio = GPIOA, - .init = { - .GPIO_Pin = GPIO_Pin_9, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, -}; - -static const struct pios_usart_cfg pios_usart_hkosd_flexi_cfg = { - .regs = USART3, - .remap = GPIO_AF_USART3, - .init = { - .USART_BaudRate = 57600, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx | USART_Mode_Tx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART3_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_11, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, - .tx = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_10, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, -}; - -static const struct pios_usart_cfg pios_usart_rcvrport_cfg = { +static const struct pios_usart_cfg pios_usart_flexiio_cfg = { .regs = USART6, .remap = GPIO_AF_USART6, - .init = { - .USART_BaudRate = 57600, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx | USART_Mode_Tx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART6_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .dtr = { // FlexIO pin 9 .gpio = GPIOC, @@ -1385,212 +1063,24 @@ static const struct pios_tim_clock_cfg tim_12_cfg = { * Using TIM3, TIM9, TIM2, TIM5 */ #include +#include + static const struct pios_tim_channel pios_tim_servoport_all_pins[] = { - { - .timer = TIM3, - .timer_chan = TIM_Channel_3, - .pin = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_0, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - .pin_source = GPIO_PinSource0, - }, - .remap = GPIO_AF_TIM3, - }, - { - .timer = TIM3, - .timer_chan = TIM_Channel_4, - .pin = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_1, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - .pin_source = GPIO_PinSource1, - }, - .remap = GPIO_AF_TIM3, - }, - { - .timer = TIM9, - .timer_chan = TIM_Channel_2, - .pin = { - .gpio = GPIOA, - .init = { - .GPIO_Pin = GPIO_Pin_3, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - .pin_source = GPIO_PinSource3, - }, - .remap = GPIO_AF_TIM9, - }, - { - .timer = TIM2, - .timer_chan = TIM_Channel_3, - .pin = { - .gpio = GPIOA, - .init = { - .GPIO_Pin = GPIO_Pin_2, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - .pin_source = GPIO_PinSource2, - }, - .remap = GPIO_AF_TIM2, - }, - { - .timer = TIM5, - .timer_chan = TIM_Channel_2, - .pin = { - .gpio = GPIOA, - .init = { - .GPIO_Pin = GPIO_Pin_1, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - .pin_source = GPIO_PinSource1, - }, - .remap = GPIO_AF_TIM5, - }, - { - .timer = TIM5, - .timer_chan = TIM_Channel_1, - .pin = { - .gpio = GPIOA, - .init = { - .GPIO_Pin = GPIO_Pin_0, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - .pin_source = GPIO_PinSource0, - }, - .remap = GPIO_AF_TIM5, - }, + TIM_SERVO_CHANNEL_CONFIG(TIM3, 3, B, 0), + TIM_SERVO_CHANNEL_CONFIG(TIM3, 4, B, 1), + TIM_SERVO_CHANNEL_CONFIG(TIM9, 2, A, 3), + TIM_SERVO_CHANNEL_CONFIG(TIM2, 3, A, 2), + TIM_SERVO_CHANNEL_CONFIG(TIM5, 2, A, 1), + TIM_SERVO_CHANNEL_CONFIG(TIM5, 1, A, 0), // PWM pins on FlexiIO(receiver) port - { - // * 6: PB15 = SPI2 MOSI, TIM12 CH2 - - .timer = TIM12, - .timer_chan = TIM_Channel_2, - .pin = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_15, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - .pin_source = GPIO_PinSource15, - }, - .remap = GPIO_AF_TIM12, - }, - { - // * 7: PC6 = TIM8 CH1, USART6 TX - .timer = TIM8, - .timer_chan = TIM_Channel_1, - .pin = { - .gpio = GPIOC, - .init = { - .GPIO_Pin = GPIO_Pin_6, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - .pin_source = GPIO_PinSource6, - }, - .remap = GPIO_AF_TIM8, - }, - - { - // * 8: PC7 = TIM8 CH2, USART6 RX - .timer = TIM8, - .timer_chan = TIM_Channel_2, - .pin = { - .gpio = GPIOC, - .init = { - .GPIO_Pin = GPIO_Pin_7, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - .pin_source = GPIO_PinSource7, - }, - .remap = GPIO_AF_TIM8, - }, - - { - // * 9: PC8 = TIM8 CH3 - .timer = TIM8, - .timer_chan = TIM_Channel_3, - .pin = { - .gpio = GPIOC, - .init = { - .GPIO_Pin = GPIO_Pin_8, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - .pin_source = GPIO_PinSource8, - }, - .remap = GPIO_AF_TIM8, - }, - - { - // * 10: PC9 = TIM8 CH4 - .timer = TIM8, - .timer_chan = TIM_Channel_4, - .pin = { - .gpio = GPIOC, - .init = { - .GPIO_Pin = GPIO_Pin_9, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - .pin_source = GPIO_PinSource9, - }, - .remap = GPIO_AF_TIM8, - }, - - { - // * 5: PB14 = SPI2 MISO, TIM12 CH1, USART3 RTS - .timer = TIM12, - .timer_chan = TIM_Channel_1, - .pin = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_14, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - .pin_source = GPIO_PinSource14, - }, - .remap = GPIO_AF_TIM12, - }, + TIM_SERVO_CHANNEL_CONFIG(TIM12, 2, B, 15), // * 6: PB15 = SPI2 MOSI, TIM12 CH2 + TIM_SERVO_CHANNEL_CONFIG(TIM8, 1, C, 6), // * 7: PC6 = TIM8 CH1, USART6 TX + TIM_SERVO_CHANNEL_CONFIG(TIM8, 2, C, 7), // * 8: PC7 = TIM8 CH2, USART6 RX + TIM_SERVO_CHANNEL_CONFIG(TIM8, 3, C, 8), // * 9: PC8 = TIM8 CH3 + TIM_SERVO_CHANNEL_CONFIG(TIM8, 4, C, 9), // * 10: PC9 = TIM8 CH4 + TIM_SERVO_CHANNEL_CONFIG(TIM12, 1, B, 14), // * 5: PB14 = SPI2 MISO, TIM12 CH1, USART3 RTS }; + #define PIOS_SERVOPORT_ALL_PINS_PWMOUT 6 #define PIOS_SERVOPORT_ALL_PINS_PWMOUT_IN_PPM 11 #define PIOS_SERVOPORT_ALL_PINS_PWMOUT_IN 12 @@ -1648,102 +1138,12 @@ const struct pios_servo_cfg pios_servo_cfg_out_in = { #if defined(PIOS_INCLUDE_PWM) || defined(PIOS_INCLUDE_PPM) #include static const struct pios_tim_channel pios_tim_rcvrport_all_channels[] = { - { - .timer = TIM12, - .timer_chan = TIM_Channel_1, - .pin = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_14, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - .pin_source = GPIO_PinSource14, - }, - .remap = GPIO_AF_TIM12, - }, - { - .timer = TIM12, - .timer_chan = TIM_Channel_2, - .pin = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_15, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - .pin_source = GPIO_PinSource15, - }, - .remap = GPIO_AF_TIM12, - }, - { - .timer = TIM8, - .timer_chan = TIM_Channel_1, - .pin = { - .gpio = GPIOC, - .init = { - .GPIO_Pin = GPIO_Pin_6, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - .pin_source = GPIO_PinSource6, - }, - .remap = GPIO_AF_TIM8, - }, - { - .timer = TIM8, - .timer_chan = TIM_Channel_2, - .pin = { - .gpio = GPIOC, - .init = { - .GPIO_Pin = GPIO_Pin_7, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - .pin_source = GPIO_PinSource7, - }, - .remap = GPIO_AF_TIM8, - }, - { - .timer = TIM8, - .timer_chan = TIM_Channel_3, - .pin = { - .gpio = GPIOC, - .init = { - .GPIO_Pin = GPIO_Pin_8, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - .pin_source = GPIO_PinSource8, - }, - .remap = GPIO_AF_TIM8, - }, - { - .timer = TIM8, - .timer_chan = TIM_Channel_4, - .pin = { - .gpio = GPIOC, - .init = { - .GPIO_Pin = GPIO_Pin_9, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - .pin_source = GPIO_PinSource9, - }, - .remap = GPIO_AF_TIM8, - }, + TIM_SERVO_CHANNEL_CONFIG(TIM12, 1, B, 14), + TIM_SERVO_CHANNEL_CONFIG(TIM12, 2, B, 15), + TIM_SERVO_CHANNEL_CONFIG(TIM8, 1, C, 6), + TIM_SERVO_CHANNEL_CONFIG(TIM8, 2, C, 7), + TIM_SERVO_CHANNEL_CONFIG(TIM8, 3, C, 8), + TIM_SERVO_CHANNEL_CONFIG(TIM8, 4, C, 9), }; const struct pios_pwm_cfg pios_pwm_cfg = { @@ -1840,36 +1240,6 @@ const struct pios_usb_cfg *PIOS_BOARD_HW_DEFS_GetUsbCfg(__attribute__((unused)) #endif /* PIOS_INCLUDE_COM_MSG */ -#if defined(PIOS_INCLUDE_USB_HID) && !defined(PIOS_INCLUDE_USB_CDC) -#include - -const struct pios_usb_hid_cfg pios_usb_hid_cfg = { - .data_if = 0, - .data_rx_ep = 1, - .data_tx_ep = 1, -}; -#endif /* PIOS_INCLUDE_USB_HID && !PIOS_INCLUDE_USB_CDC */ - -#if defined(PIOS_INCLUDE_USB_HID) && defined(PIOS_INCLUDE_USB_CDC) -#include - -const struct pios_usb_cdc_cfg pios_usb_cdc_cfg = { - .ctrl_if = 0, - .ctrl_tx_ep = 2, - - .data_if = 1, - .data_rx_ep = 3, - .data_tx_ep = 3, -}; - -#include - -const struct pios_usb_hid_cfg pios_usb_hid_cfg = { - .data_if = 2, - .data_rx_ep = 1, - .data_tx_ep = 1, -}; -#endif /* PIOS_INCLUDE_USB_HID && PIOS_INCLUDE_USB_CDC */ #ifdef PIOS_INCLUDE_WS2811 #include #define PIOS_WS2811_TIM_DIVIDER (PIOS_PERIPHERAL_APB2_CLOCK / (800000 * PIOS_WS2811_TIM_PERIOD)) @@ -1936,3 +1306,196 @@ void PIOS_WS2811_irq_handler(void) PIOS_WS2811_DMA_irq_handler(); } #endif // PIOS_INCLUDE_WS2811 + +/** + * Sensor configurations + */ + +#if defined(PIOS_INCLUDE_ADC) +#include "pios_adc_priv.h" +void PIOS_ADC_DMC_irq_handler(void); +void DMA2_Stream4_IRQHandler(void) __attribute__((alias("PIOS_ADC_DMC_irq_handler"))); +struct pios_adc_cfg pios_adc_cfg = { + .adc_dev = ADC1, + .dma = { + .irq = { + .flags = (DMA_FLAG_TCIF4 | DMA_FLAG_TEIF4 | DMA_FLAG_HTIF4), + .init = { + .NVIC_IRQChannel = DMA2_Stream4_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_LOW, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, + .rx = { + .channel = DMA2_Stream4, + .init = { + .DMA_Channel = DMA_Channel_0, + .DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR + }, + } + }, + .half_flag = DMA_IT_HTIF4, + .full_flag = DMA_IT_TCIF4, +}; +void PIOS_ADC_DMC_irq_handler(void) +{ + /* Call into the generic code to handle the IRQ for this specific device */ + PIOS_ADC_DMA_Handler(); +} + +const struct pios_adc_cfg *PIOS_BOARD_HW_DEFS_GetAdcCfg(__attribute__((unused)) uint32_t board_revision) +{ + return &pios_adc_cfg; +} +#endif /* if defined(PIOS_INCLUDE_ADC) */ + +#if defined(PIOS_INCLUDE_HMC5X83) +#include "pios_hmc5x83.h" + +#ifdef PIOS_HMC5X83_HAS_GPIOS +bool pios_board_internal_mag_handler() +{ + return PIOS_HMC5x83_IRQHandler(pios_hmc5x83_internal_id); +} + +static const struct pios_exti_cfg pios_exti_hmc5x83_cfg __exti_config = { + .vector = pios_board_internal_mag_handler, + .line = EXTI_Line7, + .pin = { + .gpio = GPIOB, + .init = { + .GPIO_Pin = GPIO_Pin_7, + .GPIO_Speed = GPIO_Speed_100MHz, + .GPIO_Mode = GPIO_Mode_IN, + .GPIO_OType = GPIO_OType_OD, + .GPIO_PuPd = GPIO_PuPd_NOPULL, + }, + }, + .irq = { + .init = { + .NVIC_IRQChannel = EXTI9_5_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_LOW, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, + .exti = { + .init = { + .EXTI_Line = EXTI_Line7, // matches above GPIO pin + .EXTI_Mode = EXTI_Mode_Interrupt, + .EXTI_Trigger = EXTI_Trigger_Rising, + .EXTI_LineCmd = ENABLE, + }, + }, +}; +#endif /* PIOS_HMC5X83_HAS_GPIOS */ + +static const struct pios_hmc5x83_cfg pios_hmc5x83_internal_cfg = { +#ifdef PIOS_HMC5X83_HAS_GPIOS + .exti_cfg = &pios_exti_hmc5x83_cfg, +#endif + .M_ODR = PIOS_HMC5x83_ODR_75, + .Meas_Conf = PIOS_HMC5x83_MEASCONF_NORMAL, + .Gain = PIOS_HMC5x83_GAIN_1_9, + .Mode = PIOS_HMC5x83_MODE_CONTINUOUS, + .TempCompensation = false, + .Driver = &PIOS_HMC5x83_I2C_DRIVER, + .Orientation = PIOS_HMC5X83_ORIENTATION_EAST_NORTH_UP, +}; + +static const struct pios_hmc5x83_cfg pios_hmc5x83_external_cfg = { +#ifdef PIOS_HMC5X83_HAS_GPIOS + .exti_cfg = NULL, +#endif + .M_ODR = PIOS_HMC5x83_ODR_75, // if you change this for auxmag, change AUX_MAG_SKIP in sensors.c + .Meas_Conf = PIOS_HMC5x83_MEASCONF_NORMAL, + .Gain = PIOS_HMC5x83_GAIN_1_9, + .Mode = PIOS_HMC5x83_MODE_CONTINUOUS, + .TempCompensation = false, + .Driver = &PIOS_HMC5x83_I2C_DRIVER, + .Orientation = PIOS_HMC5X83_ORIENTATION_EAST_NORTH_UP, // ENU for GPSV9, WND for typical I2C mag +}; + +const struct pios_hmc5x83_cfg *PIOS_BOARD_HW_DEFS_GetInternalHMC5x83Cfg(__attribute__((unused)) uint32_t board_revision) +{ + return &pios_hmc5x83_internal_cfg; +} + +const struct pios_hmc5x83_cfg *PIOS_BOARD_HW_DEFS_GetExternalHMC5x83Cfg(__attribute__((unused)) uint32_t board_revision) +{ + return &pios_hmc5x83_external_cfg; +} +#endif /* PIOS_INCLUDE_HMC5X83 */ + +/** + * Configuration for the MS5611 chip + */ +#if defined(PIOS_INCLUDE_MS5611) +#include "pios_ms5611.h" +static const struct pios_ms5611_cfg pios_ms5611_cfg = { + .oversampling = MS5611_OSR_512, +}; +const struct pios_ms5611_cfg *PIOS_BOARD_HW_DEFS_GetMS5611Cfg(__attribute__((unused)) uint32_t board_revision) +{ + return &pios_ms5611_cfg; +} +#endif /* PIOS_INCLUDE_MS5611 */ + + +/** + * Configuration for the MPU6000 chip + */ +#if defined(PIOS_INCLUDE_MPU6000) +#include "pios_mpu6000.h" +#include "pios_mpu6000_config.h" +static const struct pios_exti_cfg pios_exti_mpu6000_cfg __exti_config = { + .vector = PIOS_MPU6000_IRQHandler, + .line = EXTI_Line4, + .pin = { + .gpio = GPIOC, + .init = { + .GPIO_Pin = GPIO_Pin_4, + .GPIO_Speed = GPIO_Speed_100MHz, + .GPIO_Mode = GPIO_Mode_IN, + .GPIO_OType = GPIO_OType_OD, + .GPIO_PuPd = GPIO_PuPd_NOPULL, + }, + }, + .irq = { + .init = { + .NVIC_IRQChannel = EXTI4_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, + .exti = { + .init = { + .EXTI_Line = EXTI_Line4, // matches above GPIO pin + .EXTI_Mode = EXTI_Mode_Interrupt, + .EXTI_Trigger = EXTI_Trigger_Rising, + .EXTI_LineCmd = ENABLE, + }, + }, +}; + +static const struct pios_mpu6000_cfg pios_mpu6000_cfg = { + .exti_cfg = &pios_exti_mpu6000_cfg, + .Fifo_store = PIOS_MPU6000_FIFO_TEMP_OUT | PIOS_MPU6000_FIFO_GYRO_X_OUT | PIOS_MPU6000_FIFO_GYRO_Y_OUT | PIOS_MPU6000_FIFO_GYRO_Z_OUT, + // Clock at 8 khz, downsampled by 12 for 666Hz + .Smpl_rate_div_no_dlp = 11, + // with dlp on output rate is 500Hz + .Smpl_rate_div_dlp = 1, + .interrupt_cfg = PIOS_MPU6000_INT_CLR_ANYRD, + .interrupt_en = PIOS_MPU6000_INTEN_DATA_RDY, + .User_ctl = PIOS_MPU6000_USERCTL_FIFO_EN | PIOS_MPU6000_USERCTL_DIS_I2C, + .Pwr_mgmt_clk = PIOS_MPU6000_PWRMGMT_PLL_X_CLK, + .accel_range = PIOS_MPU6000_ACCEL_8G, + .gyro_range = PIOS_MPU6000_SCALE_2000_DEG, + .filter = PIOS_MPU6000_LOWPASS_256_HZ, + .orientation = PIOS_MPU6000_TOP_180DEG +}; +#endif /* PIOS_INCLUDE_MPU6000 */ + + diff --git a/flight/targets/boards/discoveryf4bare/bootloader/pios_board.c b/flight/targets/boards/discoveryf4bare/bootloader/pios_board.c index 5352c7f73b..b867b81d79 100644 --- a/flight/targets/boards/discoveryf4bare/bootloader/pios_board.c +++ b/flight/targets/boards/discoveryf4bare/bootloader/pios_board.c @@ -25,7 +25,7 @@ #include #include - +#include /* * Pull in the board-specific static HW definitions. * Including .c files is a bit ugly but this allows all of @@ -39,6 +39,12 @@ uint32_t pios_com_telem_usb_id; static bool board_init_complete = false; + +static int32_t PIOS_BOARD_USART_Ioctl(__attribute__((unused)) uint32_t usart_id, __attribute__((unused)) uint32_t ctl, __attribute__((unused)) void *param) +{ + return -1; +} + void PIOS_Board_Init() { if (board_init_complete) { @@ -68,7 +74,7 @@ void PIOS_Board_Init() #if defined(PIOS_INCLUDE_USB_HID) && defined(PIOS_INCLUDE_COM_MSG) uint32_t pios_usb_hid_id; - if (PIOS_USB_HID_Init(&pios_usb_hid_id, &pios_usb_hid_cfg, pios_usb_id)) { + if (PIOS_USB_HID_Init(&pios_usb_hid_id, &pios_usb_hid_only_cfg, pios_usb_id)) { PIOS_Assert(0); } if (PIOS_COM_MSG_Init(&pios_com_telem_usb_id, &pios_usb_hid_com_driver, pios_usb_hid_id)) { diff --git a/flight/targets/boards/discoveryf4bare/firmware/pios_board.c b/flight/targets/boards/discoveryf4bare/firmware/pios_board.c index 782cdb1cae..bac459834c 100644 --- a/flight/targets/boards/discoveryf4bare/firmware/pios_board.c +++ b/flight/targets/boards/discoveryf4bare/firmware/pios_board.c @@ -30,19 +30,16 @@ #include #include #include -#include -#include -#include -#include -#include #include -#include -#include +#include + #ifdef PIOS_INCLUDE_INSTRUMENTATION #include #endif +#include + /* * Pull in the board-specific static HW definitions. * Including .c files is a bit ugly but this allows all of @@ -53,312 +50,72 @@ */ #include "../board_hw_defs.c" -/** - * Sensor configurations - */ - -#if defined(PIOS_INCLUDE_ADC) -#include "pios_adc_priv.h" -void PIOS_ADC_DMC_irq_handler(void); -void DMA2_Stream4_IRQHandler(void) __attribute__((alias("PIOS_ADC_DMC_irq_handler"))); -struct pios_adc_cfg pios_adc_cfg = { - .adc_dev = ADC1, - .dma = { - .irq = { - .flags = (DMA_FLAG_TCIF4 | DMA_FLAG_TEIF4 | DMA_FLAG_HTIF4), - .init = { - .NVIC_IRQChannel = DMA2_Stream4_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_LOW, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { - .channel = DMA2_Stream4, - .init = { - .DMA_Channel = DMA_Channel_0, - .DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR - }, - } - }, - .half_flag = DMA_IT_HTIF4, - .full_flag = DMA_IT_TCIF4, -}; -void PIOS_ADC_DMC_irq_handler(void) -{ - /* Call into the generic code to handle the IRQ for this specific device */ - PIOS_ADC_DMA_Handler(); -} - -#endif /* if defined(PIOS_INCLUDE_ADC) */ - -#if defined(PIOS_INCLUDE_HMC5X83) -#include "pios_hmc5x83.h" -pios_hmc5x83_dev_t onboard_mag = 0; -pios_hmc5x83_dev_t external_mag = 0; - -bool pios_board_internal_mag_handler() -{ - return PIOS_HMC5x83_IRQHandler(onboard_mag); -} - -static const struct pios_exti_cfg pios_exti_hmc5x83_cfg __exti_config = { - .vector = pios_board_internal_mag_handler, - .line = EXTI_Line7, - .pin = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_7, - .GPIO_Speed = GPIO_Speed_100MHz, - .GPIO_Mode = GPIO_Mode_IN, - .GPIO_OType = GPIO_OType_OD, - .GPIO_PuPd = GPIO_PuPd_NOPULL, - }, - }, - .irq = { - .init = { - .NVIC_IRQChannel = EXTI9_5_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_LOW, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .exti = { - .init = { - .EXTI_Line = EXTI_Line7, // matches above GPIO pin - .EXTI_Mode = EXTI_Mode_Interrupt, - .EXTI_Trigger = EXTI_Trigger_Rising, - .EXTI_LineCmd = ENABLE, - }, - }, -}; -static const struct pios_hmc5x83_cfg pios_hmc5x83_internal_cfg = { -#ifdef PIOS_HMC5X83_HAS_GPIOS - .exti_cfg = &pios_exti_hmc5x83_cfg, -#endif - .M_ODR = PIOS_HMC5x83_ODR_75, - .Meas_Conf = PIOS_HMC5x83_MEASCONF_NORMAL, - .Gain = PIOS_HMC5x83_GAIN_1_9, - .Mode = PIOS_HMC5x83_MODE_CONTINUOUS, - .TempCompensation = false, - .Driver = &PIOS_HMC5x83_I2C_DRIVER, - .Orientation = PIOS_HMC5X83_ORIENTATION_EAST_NORTH_UP, -}; - -static const struct pios_hmc5x83_cfg pios_hmc5x83_external_cfg = { -#ifdef PIOS_HMC5X83_HAS_GPIOS - .exti_cfg = NULL, -#endif - .M_ODR = PIOS_HMC5x83_ODR_75, // if you change this for auxmag, change AUX_MAG_SKIP in sensors.c - .Meas_Conf = PIOS_HMC5x83_MEASCONF_NORMAL, - .Gain = PIOS_HMC5x83_GAIN_1_9, - .Mode = PIOS_HMC5x83_MODE_CONTINUOUS, - .TempCompensation = false, - .Driver = &PIOS_HMC5x83_I2C_DRIVER, - .Orientation = PIOS_HMC5X83_ORIENTATION_EAST_NORTH_UP, // ENU for GPSV9, WND for typical I2C mag -}; -#endif /* PIOS_INCLUDE_HMC5X83 */ +uintptr_t pios_uavo_settings_fs_id; +uintptr_t pios_user_fs_id; -/** - * Configuration for the MS5611 chip - */ -#if defined(PIOS_INCLUDE_MS5611) -#include "pios_ms5611.h" -static const struct pios_ms5611_cfg pios_ms5611_cfg = { - .oversampling = MS5611_OSR_512, +static const PIOS_BOARD_IO_UART_Function flexiio_function_map[] = { + [HWSETTINGS_RM_RCVRPORT_PPMTELEMETRY] = PIOS_BOARD_IO_UART_TELEMETRY, + [HWSETTINGS_RM_RCVRPORT_PPMDEBUGCONSOLE] = PIOS_BOARD_IO_UART_DEBUGCONSOLE, + [HWSETTINGS_RM_RCVRPORT_PPMCOMBRIDGE] = PIOS_BOARD_IO_UART_COMBRIDGE, + [HWSETTINGS_RM_RCVRPORT_PPMMSP] = PIOS_BOARD_IO_UART_MSP, + [HWSETTINGS_RM_RCVRPORT_PPMMAVLINK] = PIOS_BOARD_IO_UART_MAVLINK, + [HWSETTINGS_RM_RCVRPORT_PPMGPS] = PIOS_BOARD_IO_UART_GPS, + [HWSETTINGS_RM_RCVRPORT_TELEMETRY] = PIOS_BOARD_IO_UART_TELEMETRY, + [HWSETTINGS_RM_RCVRPORT_DEBUGCONSOLE] = PIOS_BOARD_IO_UART_DEBUGCONSOLE, + [HWSETTINGS_RM_RCVRPORT_COMBRIDGE] = PIOS_BOARD_IO_UART_COMBRIDGE, + [HWSETTINGS_RM_RCVRPORT_MSP] = PIOS_BOARD_IO_UART_MSP, + [HWSETTINGS_RM_RCVRPORT_MAVLINK] = PIOS_BOARD_IO_UART_MAVLINK, + [HWSETTINGS_RM_RCVRPORT_GPS] = PIOS_BOARD_IO_UART_GPS, + [HWSETTINGS_RM_RCVRPORT_IBUS] = PIOS_BOARD_IO_UART_IBUS, }; -#endif /* PIOS_INCLUDE_MS5611 */ - -/** - * Configuration for the MPU6000 chip - */ -#if defined(PIOS_INCLUDE_MPU6000) -#include "pios_mpu6000.h" -#include "pios_mpu6000_config.h" -static const struct pios_exti_cfg pios_exti_mpu6000_cfg __exti_config = { - .vector = PIOS_MPU6000_IRQHandler, - .line = EXTI_Line4, - .pin = { - .gpio = GPIOC, - .init = { - .GPIO_Pin = GPIO_Pin_4, - .GPIO_Speed = GPIO_Speed_100MHz, - .GPIO_Mode = GPIO_Mode_IN, - .GPIO_OType = GPIO_OType_OD, - .GPIO_PuPd = GPIO_PuPd_NOPULL, - }, - }, - .irq = { - .init = { - .NVIC_IRQChannel = EXTI4_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .exti = { - .init = { - .EXTI_Line = EXTI_Line4, // matches above GPIO pin - .EXTI_Mode = EXTI_Mode_Interrupt, - .EXTI_Trigger = EXTI_Trigger_Rising, - .EXTI_LineCmd = ENABLE, - }, - }, +static const PIOS_BOARD_IO_UART_Function main_function_map[] = { + [HWSETTINGS_RM_MAINPORT_TELEMETRY] = PIOS_BOARD_IO_UART_TELEMETRY, + [HWSETTINGS_RM_MAINPORT_GPS] = PIOS_BOARD_IO_UART_GPS, + [HWSETTINGS_RM_MAINPORT_SBUS] = PIOS_BOARD_IO_UART_SBUS, + [HWSETTINGS_RM_MAINPORT_DSM] = PIOS_BOARD_IO_UART_DSM_MAIN, + [HWSETTINGS_RM_MAINPORT_DEBUGCONSOLE] = PIOS_BOARD_IO_UART_DEBUGCONSOLE, + [HWSETTINGS_RM_MAINPORT_COMBRIDGE] = PIOS_BOARD_IO_UART_COMBRIDGE, + [HWSETTINGS_RM_MAINPORT_OSDHK] = PIOS_BOARD_IO_UART_OSDHK, + [HWSETTINGS_RM_MAINPORT_MSP] = PIOS_BOARD_IO_UART_MSP, + [HWSETTINGS_RM_MAINPORT_MAVLINK] = PIOS_BOARD_IO_UART_MAVLINK, }; -static const struct pios_mpu6000_cfg pios_mpu6000_cfg = { - .exti_cfg = &pios_exti_mpu6000_cfg, - .Fifo_store = PIOS_MPU6000_FIFO_TEMP_OUT | PIOS_MPU6000_FIFO_GYRO_X_OUT | PIOS_MPU6000_FIFO_GYRO_Y_OUT | PIOS_MPU6000_FIFO_GYRO_Z_OUT, - // Clock at 8 khz, downsampled by 12 for 666Hz - .Smpl_rate_div_no_dlp = 11, - // with dlp on output rate is 500Hz - .Smpl_rate_div_dlp = 1, - .interrupt_cfg = PIOS_MPU6000_INT_CLR_ANYRD, - .interrupt_en = PIOS_MPU6000_INTEN_DATA_RDY, - .User_ctl = PIOS_MPU6000_USERCTL_FIFO_EN | PIOS_MPU6000_USERCTL_DIS_I2C, - .Pwr_mgmt_clk = PIOS_MPU6000_PWRMGMT_PLL_X_CLK, - .accel_range = PIOS_MPU6000_ACCEL_8G, - .gyro_range = PIOS_MPU6000_SCALE_2000_DEG, - .filter = PIOS_MPU6000_LOWPASS_256_HZ, - .orientation = PIOS_MPU6000_TOP_180DEG +static const PIOS_BOARD_IO_UART_Function flexi_function_map[] = { + [HWSETTINGS_RM_FLEXIPORT_TELEMETRY] = PIOS_BOARD_IO_UART_TELEMETRY, + [HWSETTINGS_RM_FLEXIPORT_GPS] = PIOS_BOARD_IO_UART_GPS, + [HWSETTINGS_RM_FLEXIPORT_DSM] = PIOS_BOARD_IO_UART_DSM_FLEXI, + [HWSETTINGS_RM_FLEXIPORT_EXBUS] = PIOS_BOARD_IO_UART_EXBUS, + [HWSETTINGS_RM_FLEXIPORT_HOTTSUMD] = PIOS_BOARD_IO_UART_HOTT_SUMD, + [HWSETTINGS_RM_FLEXIPORT_HOTTSUMH] = PIOS_BOARD_IO_UART_HOTT_SUMH, + [HWSETTINGS_RM_FLEXIPORT_SRXL] = PIOS_BOARD_IO_UART_SRXL, + [HWSETTINGS_RM_FLEXIPORT_IBUS] = PIOS_BOARD_IO_UART_IBUS, + [HWSETTINGS_RM_FLEXIPORT_DEBUGCONSOLE] = PIOS_BOARD_IO_UART_DEBUGCONSOLE, + [HWSETTINGS_RM_FLEXIPORT_COMBRIDGE] = PIOS_BOARD_IO_UART_COMBRIDGE, + [HWSETTINGS_RM_FLEXIPORT_OSDHK] = PIOS_BOARD_IO_UART_OSDHK, + [HWSETTINGS_RM_FLEXIPORT_MSP] = PIOS_BOARD_IO_UART_MSP, + [HWSETTINGS_RM_FLEXIPORT_MAVLINK] = PIOS_BOARD_IO_UART_MAVLINK, }; -#endif /* PIOS_INCLUDE_MPU6000 */ - -/* One slot per selectable receiver group. - * eg. PWM, PPM, GCS, SPEKTRUM1, SPEKTRUM2, SBUS - * NOTE: No slot in this map for NONE. - */ -uint32_t pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_NONE]; - -#define PIOS_COM_TELEM_RF_RX_BUF_LEN 512 -#define PIOS_COM_TELEM_RF_TX_BUF_LEN 512 -#define PIOS_COM_GPS_RX_BUF_LEN 128 -#define PIOS_COM_GPS_TX_BUF_LEN 32 -#define PIOS_COM_TELEM_USB_RX_BUF_LEN 65 -#define PIOS_COM_TELEM_USB_TX_BUF_LEN 65 - -#define PIOS_COM_BRIDGE_RX_BUF_LEN 65 -#define PIOS_COM_BRIDGE_TX_BUF_LEN 12 - -#define PIOS_COM_RFM22B_RF_RX_BUF_LEN 512 -#define PIOS_COM_RFM22B_RF_TX_BUF_LEN 512 - -#define PIOS_COM_HKOSD_RX_BUF_LEN 22 -#define PIOS_COM_HKOSD_TX_BUF_LEN 22 - -#define PIOS_COM_MSP_TX_BUF_LEN 128 -#define PIOS_COM_MSP_RX_BUF_LEN 64 - -#define PIOS_COM_MAVLINK_TX_BUF_LEN 128 - -#if defined(PIOS_INCLUDE_DEBUG_CONSOLE) -#define PIOS_COM_DEBUGCONSOLE_TX_BUF_LEN 40 -uint32_t pios_com_debug_id; -#endif /* PIOS_INCLUDE_DEBUG_CONSOLE */ - -uint32_t pios_com_gps_id = 0; -uint32_t pios_com_telem_usb_id = 0; -uint32_t pios_com_telem_rf_id = 0; -uint32_t pios_com_bridge_id = 0; -uint32_t pios_com_overo_id = 0; -uint32_t pios_com_hkosd_id = 0; -uint32_t pios_com_msp_id = 0; -uint32_t pios_com_mavlink_id = 0; -uint32_t pios_com_vcp_id = 0; - -#if defined(PIOS_INCLUDE_RFM22B) -uint32_t pios_rfm22b_id = 0; -#endif - -uintptr_t pios_uavo_settings_fs_id; -uintptr_t pios_user_fs_id; - -/* - * Setup a com port based on the passed cfg, driver and buffer sizes. - * tx size = 0 make the port rx only - * rx size = 0 make the port tx only - * having both tx and rx size = 0 is not valid and will fail further down in PIOS_COM_Init() - */ -static void PIOS_Board_configure_com(const struct pios_usart_cfg *usart_port_cfg, uint16_t rx_buf_len, uint16_t tx_buf_len, - const struct pios_com_driver *com_driver, uint32_t *pios_com_id) +int32_t PIOS_BOARD_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param) { - uint32_t pios_usart_id; - - if (PIOS_USART_Init(&pios_usart_id, usart_port_cfg)) { - PIOS_Assert(0); - } - - uint8_t *rx_buffer = 0, *tx_buffer = 0; - - if (rx_buf_len > 0) { - rx_buffer = (uint8_t *)pios_malloc(rx_buf_len); - PIOS_Assert(rx_buffer); - } - - if (tx_buf_len > 0) { - tx_buffer = (uint8_t *)pios_malloc(tx_buf_len); - PIOS_Assert(tx_buffer); - } - - if (PIOS_COM_Init(pios_com_id, com_driver, pios_usart_id, - rx_buffer, rx_buf_len, - tx_buffer, tx_buf_len)) { - PIOS_Assert(0); - } -} - -static void PIOS_Board_configure_dsm(const struct pios_usart_cfg *pios_usart_dsm_cfg, const struct pios_dsm_cfg *pios_dsm_cfg, - const struct pios_com_driver *usart_com_driver, - ManualControlSettingsChannelGroupsOptions channelgroup, uint8_t *bind) -{ - uint32_t pios_usart_dsm_id; - - if (PIOS_USART_Init(&pios_usart_dsm_id, pios_usart_dsm_cfg)) { - PIOS_Assert(0); - } - - uint32_t pios_dsm_id; - if (PIOS_DSM_Init(&pios_dsm_id, pios_dsm_cfg, usart_com_driver, - pios_usart_dsm_id, *bind)) { - PIOS_Assert(0); - } - - uint32_t pios_dsm_rcvr_id; - if (PIOS_RCVR_Init(&pios_dsm_rcvr_id, &pios_dsm_rcvr_driver, pios_dsm_id)) { - PIOS_Assert(0); - } - pios_rcvr_group_map[channelgroup] = pios_dsm_rcvr_id; -} - -static void PIOS_Board_configure_pwm(const struct pios_pwm_cfg *pwm_cfg) -{ - /* Set up the receiver port. Later this should be optional */ - uint32_t pios_pwm_id; - - PIOS_PWM_Init(&pios_pwm_id, pwm_cfg); - - uint32_t pios_pwm_rcvr_id; - if (PIOS_RCVR_Init(&pios_pwm_rcvr_id, &pios_pwm_rcvr_driver, pios_pwm_id)) { - PIOS_Assert(0); - } - pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_PWM] = pios_pwm_rcvr_id; -} - -static void PIOS_Board_configure_ppm(const struct pios_ppm_cfg *ppm_cfg) -{ - uint32_t pios_ppm_id; - - PIOS_PPM_Init(&pios_ppm_id, ppm_cfg); - - uint32_t pios_ppm_rcvr_id; - if (PIOS_RCVR_Init(&pios_ppm_rcvr_id, &pios_ppm_rcvr_driver, pios_ppm_id)) { - PIOS_Assert(0); + const struct pios_usart_cfg *usart_cfg = PIOS_USART_GetConfig(usart_id); + + switch (ctl) { + case PIOS_IOCTL_USART_SET_INVERTED: + if (usart_cfg->regs == pios_usart_main_cfg.regs) { /* main port */ + GPIO_WriteBit(MAIN_USART_INVERTER_GPIO, + MAIN_USART_INVERTER_PIN, + (*(enum PIOS_USART_Inverted *)param & PIOS_USART_Inverted_Rx) ? MAIN_USART_INVERTER_ENABLE : MAIN_USART_INVERTER_DISABLE); + + return 0; + } + break; } - pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_PPM] = pios_ppm_rcvr_id; + + return -1; } /** @@ -366,14 +123,8 @@ static void PIOS_Board_configure_ppm(const struct pios_ppm_cfg *ppm_cfg) * initializes all the core subsystems on this specific hardware * called from System/openpilot.c */ - -#include - void PIOS_Board_Init(void) { - /* Delay system */ - PIOS_DELAY_Init(); - const struct pios_board_info *bdinfo = &pios_board_info_blob; #if defined(PIOS_INCLUDE_LED) @@ -446,12 +197,7 @@ void PIOS_Board_Init(void) /* Initialize UAVObject libraries */ EventDispatcherInitialize(); UAVObjInitialize(); - HwSettingsInitialize(); -#if defined(PIOS_INCLUDE_RFM22B) - OPLinkSettingsInitialize(); - OPLinkStatusInitialize(); -#endif /* PIOS_INCLUDE_RFM22B */ /* Initialize the alarms library */ AlarmsInitialize(); @@ -477,397 +223,67 @@ void PIOS_Board_Init(void) AlarmsSet(SYSTEMALARMS_ALARM_BOOTFAULT, SYSTEMALARMS_ALARM_CRITICAL); } - - // PIOS_IAP_Init(); - -#if defined(PIOS_INCLUDE_USB) - /* Initialize board specific USB data */ - PIOS_USB_BOARD_DATA_Init(); - - /* Flags to determine if various USB interfaces are advertised */ - bool usb_hid_present = false; - bool usb_cdc_present = false; - -#if defined(PIOS_INCLUDE_USB_CDC) - if (PIOS_USB_DESC_HID_CDC_Init()) { - PIOS_Assert(0); - } - usb_hid_present = true; - usb_cdc_present = true; -#else - if (PIOS_USB_DESC_HID_ONLY_Init()) { - PIOS_Assert(0); - } - usb_hid_present = true; -#endif - - uint32_t pios_usb_id; - PIOS_USB_Init(&pios_usb_id, PIOS_BOARD_HW_DEFS_GetUsbCfg(bdinfo->board_rev)); - -#if defined(PIOS_INCLUDE_USB_CDC) - - uint8_t hwsettings_usb_vcpport; - /* Configure the USB VCP port */ - HwSettingsUSB_VCPPortGet(&hwsettings_usb_vcpport); - - if (!usb_cdc_present) { - /* Force VCP port function to disabled if we haven't advertised VCP in our USB descriptor */ - hwsettings_usb_vcpport = HWSETTINGS_USB_VCPPORT_DISABLED; - } - uint32_t pios_usb_cdc_id; - if (PIOS_USB_CDC_Init(&pios_usb_cdc_id, &pios_usb_cdc_cfg, pios_usb_id)) { - PIOS_Assert(0); - } - - uint32_t pios_usb_hid_id; - if (PIOS_USB_HID_Init(&pios_usb_hid_id, &pios_usb_hid_cfg, pios_usb_id)) { - PIOS_Assert(0); - } - - switch (hwsettings_usb_vcpport) { - case HWSETTINGS_USB_VCPPORT_DISABLED: - break; - case HWSETTINGS_USB_VCPPORT_USBTELEMETRY: -#if defined(PIOS_INCLUDE_COM) - { - uint8_t *rx_buffer = (uint8_t *)pios_malloc(PIOS_COM_TELEM_USB_RX_BUF_LEN); - uint8_t *tx_buffer = (uint8_t *)pios_malloc(PIOS_COM_TELEM_USB_TX_BUF_LEN); - PIOS_Assert(rx_buffer); - PIOS_Assert(tx_buffer); - if (PIOS_COM_Init(&pios_com_telem_usb_id, &pios_usb_cdc_com_driver, pios_usb_cdc_id, - rx_buffer, PIOS_COM_TELEM_USB_RX_BUF_LEN, - tx_buffer, PIOS_COM_TELEM_USB_TX_BUF_LEN)) { - PIOS_Assert(0); - } - } -#endif /* PIOS_INCLUDE_COM */ - break; - case HWSETTINGS_USB_VCPPORT_COMBRIDGE: -#if defined(PIOS_INCLUDE_COM) - { - uint8_t *rx_buffer = (uint8_t *)pios_malloc(PIOS_COM_BRIDGE_RX_BUF_LEN); - uint8_t *tx_buffer = (uint8_t *)pios_malloc(PIOS_COM_BRIDGE_TX_BUF_LEN); - PIOS_Assert(rx_buffer); - PIOS_Assert(tx_buffer); - if (PIOS_COM_Init(&pios_com_vcp_id, &pios_usb_cdc_com_driver, pios_usb_cdc_id, - rx_buffer, PIOS_COM_BRIDGE_RX_BUF_LEN, - tx_buffer, PIOS_COM_BRIDGE_TX_BUF_LEN)) { - PIOS_Assert(0); - } - } -#endif /* PIOS_INCLUDE_COM */ - break; - case HWSETTINGS_USB_VCPPORT_DEBUGCONSOLE: -#if defined(PIOS_INCLUDE_COM) -#if defined(PIOS_INCLUDE_DEBUG_CONSOLE) - { - uint8_t *tx_buffer = (uint8_t *)pios_malloc(PIOS_COM_DEBUGCONSOLE_TX_BUF_LEN); - PIOS_Assert(tx_buffer); - if (PIOS_COM_Init(&pios_com_debug_id, &pios_usb_cdc_com_driver, pios_usb_cdc_id, - NULL, 0, - tx_buffer, PIOS_COM_DEBUGCONSOLE_TX_BUF_LEN)) { - PIOS_Assert(0); - } - } -#endif /* PIOS_INCLUDE_DEBUG_CONSOLE */ -#endif /* PIOS_INCLUDE_COM */ - - break; - } -#endif /* PIOS_INCLUDE_USB_CDC */ - -#if defined(PIOS_INCLUDE_USB_HID) - /* Configure the usb HID port */ - uint8_t hwsettings_usb_hidport; - HwSettingsUSB_HIDPortGet(&hwsettings_usb_hidport); - - if (!usb_hid_present) { - /* Force HID port function to disabled if we haven't advertised HID in our USB descriptor */ - hwsettings_usb_hidport = HWSETTINGS_USB_HIDPORT_DISABLED; - } - - switch (hwsettings_usb_hidport) { - case HWSETTINGS_USB_HIDPORT_DISABLED: - break; - case HWSETTINGS_USB_HIDPORT_USBTELEMETRY: -#if defined(PIOS_INCLUDE_COM) - { - uint8_t *rx_buffer = (uint8_t *)pios_malloc(PIOS_COM_TELEM_USB_RX_BUF_LEN); - uint8_t *tx_buffer = (uint8_t *)pios_malloc(PIOS_COM_TELEM_USB_TX_BUF_LEN); - PIOS_Assert(rx_buffer); - PIOS_Assert(tx_buffer); - if (PIOS_COM_Init(&pios_com_telem_usb_id, &pios_usb_hid_com_driver, pios_usb_hid_id, - rx_buffer, PIOS_COM_TELEM_USB_RX_BUF_LEN, - tx_buffer, PIOS_COM_TELEM_USB_TX_BUF_LEN)) { - PIOS_Assert(0); - } - } -#endif /* PIOS_INCLUDE_COM */ - break; - } - -#endif /* PIOS_INCLUDE_USB_HID */ - - if (usb_hid_present || usb_cdc_present) { - PIOS_USBHOOK_Activate(); - } -#endif /* PIOS_INCLUDE_USB */ - /* Configure IO ports */ - uint8_t hwsettings_DSMxBind; - HwSettingsDSMxBindGet(&hwsettings_DSMxBind); - - /* Configure main USART port */ - uint8_t hwsettings_mainport; - HwSettingsRM_MainPortGet(&hwsettings_mainport); - switch (hwsettings_mainport) { - case HWSETTINGS_RM_MAINPORT_DISABLED: - break; - case HWSETTINGS_RM_MAINPORT_TELEMETRY: - PIOS_Board_configure_com(&pios_usart_main_cfg, PIOS_COM_TELEM_RF_RX_BUF_LEN, PIOS_COM_TELEM_RF_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_telem_rf_id); - break; - case HWSETTINGS_RM_MAINPORT_GPS: - PIOS_Board_configure_com(&pios_usart_main_cfg, PIOS_COM_GPS_RX_BUF_LEN, PIOS_COM_GPS_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_gps_id); - break; - case HWSETTINGS_RM_MAINPORT_SBUS: -#if defined(PIOS_INCLUDE_SBUS) - { - uint32_t pios_usart_sbus_id; - if (PIOS_USART_Init(&pios_usart_sbus_id, &pios_usart_sbus_main_cfg)) { - PIOS_Assert(0); - } - - uint32_t pios_sbus_id; - if (PIOS_SBus_Init(&pios_sbus_id, &pios_sbus_cfg, &pios_usart_com_driver, pios_usart_sbus_id)) { - PIOS_Assert(0); - } - - uint32_t pios_sbus_rcvr_id; - if (PIOS_RCVR_Init(&pios_sbus_rcvr_id, &pios_sbus_rcvr_driver, pios_sbus_id)) { - PIOS_Assert(0); - } - pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_SBUS] = pios_sbus_rcvr_id; - } -#endif - break; - case HWSETTINGS_RM_MAINPORT_DSM: - // Force binding to zero on the main port - hwsettings_DSMxBind = 0; - - // TODO: Define the various Channelgroup for Revo dsm inputs and handle here - PIOS_Board_configure_dsm(&pios_usart_dsm_main_cfg, &pios_dsm_main_cfg, - &pios_usart_com_driver, MANUALCONTROLSETTINGS_CHANNELGROUPS_DSMMAINPORT, &hwsettings_DSMxBind); - break; - case HWSETTINGS_RM_MAINPORT_DEBUGCONSOLE: -#if defined(PIOS_INCLUDE_DEBUG_CONSOLE) - { - PIOS_Board_configure_com(&pios_usart_main_cfg, 0, PIOS_COM_DEBUGCONSOLE_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_debug_id); - } -#endif /* PIOS_INCLUDE_DEBUG_CONSOLE */ - break; - case HWSETTINGS_RM_MAINPORT_COMBRIDGE: - PIOS_Board_configure_com(&pios_usart_main_cfg, PIOS_COM_BRIDGE_RX_BUF_LEN, PIOS_COM_BRIDGE_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_bridge_id); - break; - case HWSETTINGS_RM_MAINPORT_MSP: - PIOS_Board_configure_com(&pios_usart_main_cfg, PIOS_COM_MSP_RX_BUF_LEN, PIOS_COM_MSP_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_msp_id); - break; - case HWSETTINGS_RM_MAINPORT_MAVLINK: - PIOS_Board_configure_com(&pios_usart_main_cfg, 0, PIOS_COM_MAVLINK_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_mavlink_id); - break; - case HWSETTINGS_RM_MAINPORT_OSDHK: - PIOS_Board_configure_com(&pios_usart_hkosd_main_cfg, PIOS_COM_HKOSD_RX_BUF_LEN, PIOS_COM_HKOSD_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_hkosd_id); - break; - } /* hwsettings_rm_mainport */ - - if (hwsettings_mainport != HWSETTINGS_RM_MAINPORT_SBUS) { - GPIO_Init(pios_sbus_cfg.inv.gpio, &pios_sbus_cfg.inv.init); - GPIO_WriteBit(pios_sbus_cfg.inv.gpio, pios_sbus_cfg.inv.init.GPIO_Pin, pios_sbus_cfg.gpio_inv_disable); - } - + /* Configure FlexiPort */ uint8_t hwsettings_flexiport; HwSettingsRM_FlexiPortGet(&hwsettings_flexiport); - switch (hwsettings_flexiport) { - case HWSETTINGS_RM_FLEXIPORT_DISABLED: - break; - case HWSETTINGS_RM_FLEXIPORT_TELEMETRY: - PIOS_Board_configure_com(&pios_usart_flexi_cfg, PIOS_COM_TELEM_RF_RX_BUF_LEN, PIOS_COM_TELEM_RF_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_telem_rf_id); - break; - case HWSETTINGS_RM_FLEXIPORT_I2C: + + if (hwsettings_flexiport < NELEMENTS(flexi_function_map)) { + PIOS_BOARD_IO_Configure_UART(&pios_usart_flexi_cfg, flexi_function_map[hwsettings_flexiport]); + } + #if defined(PIOS_INCLUDE_I2C) + /* Set up internal I2C bus */ + if (PIOS_I2C_Init(&pios_i2c_mag_pressure_adapter_id, &pios_i2c_mag_pressure_adapter_cfg)) { + PIOS_DEBUG_Assert(0); + } + PIOS_DELAY_WaitmS(50); + + if (hwsettings_flexiport == HWSETTINGS_RM_FLEXIPORT_I2C) { if (PIOS_I2C_Init(&pios_i2c_flexiport_adapter_id, &pios_i2c_flexiport_adapter_cfg)) { PIOS_Assert(0); } - PIOS_DELAY_WaitmS(50); // this was after the other PIOS_I2C_Init(), so I copied it here too -#ifdef PIOS_INCLUDE_WDG - // give HMC5x83 on I2C some extra time to allow for reset, etc. if needed - // this is not in a loop, so it is safe - // leave this here even if PIOS_INCLUDE_HMC5X83 is undefined - // to avoid making something else fail when HMC5X83 is removed - PIOS_WDG_Clear(); -#endif /* PIOS_INCLUDE_WDG */ -#if defined(PIOS_INCLUDE_HMC5X83) - // get auxmag type - AuxMagSettingsTypeOptions option; - AuxMagSettingsInitialize(); - AuxMagSettingsTypeGet(&option); - // if the aux mag type is FlexiPort then set it up - if (option == AUXMAGSETTINGS_TYPE_FLEXI) { - // attach the 5x83 mag to the previously inited I2C2 - external_mag = PIOS_HMC5x83_Init(&pios_hmc5x83_external_cfg, pios_i2c_flexiport_adapter_id, 0); -#ifdef PIOS_INCLUDE_WDG - // give HMC5x83 on I2C some extra time to allow for reset, etc. if needed - // this is not in a loop, so it is safe - PIOS_WDG_Clear(); -#endif /* PIOS_INCLUDE_WDG */ - // add this sensor to the sensor task's list - // be careful that you don't register a slow, unimportant sensor after registering the fastest sensor - // and before registering some other fast and important sensor - // as that would cause delay and time jitter for the second fast sensor - PIOS_HMC5x83_Register(external_mag, PIOS_SENSORS_TYPE_3AXIS_AUXMAG); - // mag alarm is cleared later, so use I2C - AlarmsSet(SYSTEMALARMS_ALARM_I2C, (external_mag) ? SYSTEMALARMS_ALARM_OK : SYSTEMALARMS_ALARM_WARNING); - } -#endif /* PIOS_INCLUDE_HMC5X83 */ -#endif /* PIOS_INCLUDE_I2C */ - break; - case HWSETTINGS_RM_FLEXIPORT_GPS: - PIOS_Board_configure_com(&pios_usart_flexi_cfg, PIOS_COM_GPS_RX_BUF_LEN, PIOS_COM_GPS_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_gps_id); - break; - case HWSETTINGS_RM_FLEXIPORT_DSM: - // TODO: Define the various Channelgroup for Revo dsm inputs and handle here - PIOS_Board_configure_dsm(&pios_usart_dsm_flexi_cfg, &pios_dsm_flexi_cfg, - &pios_usart_com_driver, MANUALCONTROLSETTINGS_CHANNELGROUPS_DSMFLEXIPORT, &hwsettings_DSMxBind); - break; - case HWSETTINGS_RM_FLEXIPORT_DEBUGCONSOLE: -#if defined(PIOS_INCLUDE_DEBUG_CONSOLE) - { - PIOS_Board_configure_com(&pios_usart_flexi_cfg, 0, PIOS_COM_DEBUGCONSOLE_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_debug_id); - } -#endif /* PIOS_INCLUDE_DEBUG_CONSOLE */ - break; - case HWSETTINGS_RM_FLEXIPORT_COMBRIDGE: - PIOS_Board_configure_com(&pios_usart_flexi_cfg, PIOS_COM_BRIDGE_RX_BUF_LEN, PIOS_COM_BRIDGE_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_bridge_id); - break; - case HWSETTINGS_RM_FLEXIPORT_MSP: - PIOS_Board_configure_com(&pios_usart_flexi_cfg, PIOS_COM_MSP_RX_BUF_LEN, PIOS_COM_MSP_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_msp_id); - break; - case HWSETTINGS_RM_FLEXIPORT_MAVLINK: - PIOS_Board_configure_com(&pios_usart_flexi_cfg, 0, PIOS_COM_MAVLINK_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_mavlink_id); - break; - case HWSETTINGS_RM_FLEXIPORT_OSDHK: - PIOS_Board_configure_com(&pios_usart_hkosd_flexi_cfg, PIOS_COM_HKOSD_RX_BUF_LEN, PIOS_COM_HKOSD_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_hkosd_id); - break; - } /* hwsettings_rm_flexiport */ - - - /* Initialize the RFM22B radio COM device. */ -#if defined(PIOS_INCLUDE_RFM22B) - - /* Fetch the OPLinkSettings object. */ - OPLinkSettingsData oplinkSettings; - OPLinkSettingsGet(&oplinkSettings); - - // Initialize out status object. - OPLinkStatusData oplinkStatus; - OPLinkStatusGet(&oplinkStatus); - oplinkStatus.BoardType = bdinfo->board_type; - PIOS_BL_HELPER_FLASH_Read_Description(oplinkStatus.Description, OPLINKSTATUS_DESCRIPTION_NUMELEM); - PIOS_SYS_SerialNumberGetBinary(oplinkStatus.CPUSerial); - oplinkStatus.BoardRevision = bdinfo->board_rev; - - /* Is the radio turned on? */ - bool is_coordinator = (oplinkSettings.Coordinator == OPLINKSETTINGS_COORDINATOR_TRUE); - bool is_oneway = (oplinkSettings.OneWay == OPLINKSETTINGS_ONEWAY_TRUE); - bool ppm_mode = (oplinkSettings.PPM == OPLINKSETTINGS_PPM_TRUE); - if (oplinkSettings.MaxRFPower != OPLINKSETTINGS_MAXRFPOWER_0) { - /* Configure the RFM22B device. */ - const struct pios_rfm22b_cfg *rfm22b_cfg = PIOS_BOARD_HW_DEFS_GetRfm22Cfg(bdinfo->board_rev); - if (PIOS_RFM22B_Init(&pios_rfm22b_id, PIOS_RFM22_SPI_PORT, rfm22b_cfg->slave_num, rfm22b_cfg, oplinkSettings.RFBand)) { - PIOS_Assert(0); - } - - /* Configure the radio com interface */ - uint8_t *rx_buffer = (uint8_t *)pios_malloc(PIOS_COM_RFM22B_RF_RX_BUF_LEN); - uint8_t *tx_buffer = (uint8_t *)pios_malloc(PIOS_COM_RFM22B_RF_TX_BUF_LEN); - PIOS_Assert(rx_buffer); - PIOS_Assert(tx_buffer); - if (PIOS_COM_Init(&pios_com_telem_rf_id, &pios_rfm22b_com_driver, pios_rfm22b_id, - rx_buffer, PIOS_COM_RFM22B_RF_RX_BUF_LEN, - tx_buffer, PIOS_COM_RFM22B_RF_TX_BUF_LEN)) { - PIOS_Assert(0); - } - oplinkStatus.LinkState = OPLINKSTATUS_LINKSTATE_ENABLED; - - // Set the RF data rate on the modem to ~2X the selected buad rate because the modem is half duplex. - enum rfm22b_datarate datarate = RFM22_datarate_64000; - switch (oplinkSettings.ComSpeed) { - case OPLINKSETTINGS_COMSPEED_4800: - datarate = RFM22_datarate_9600; - break; - case OPLINKSETTINGS_COMSPEED_9600: - datarate = RFM22_datarate_19200; - break; - case OPLINKSETTINGS_COMSPEED_19200: - datarate = RFM22_datarate_32000; - break; - case OPLINKSETTINGS_COMSPEED_38400: - datarate = RFM22_datarate_64000; - break; - case OPLINKSETTINGS_COMSPEED_57600: - datarate = RFM22_datarate_100000; - break; - case OPLINKSETTINGS_COMSPEED_115200: - datarate = RFM22_datarate_192000; - break; - } - - /* Set the radio configuration parameters. */ - PIOS_RFM22B_SetDeviceID(pios_rfm22b_id, oplinkSettings.CustomDeviceID); - PIOS_RFM22B_SetCoordinatorID(pios_rfm22b_id, oplinkSettings.CoordID); - PIOS_RFM22B_SetXtalCap(pios_rfm22b_id, oplinkSettings.RFXtalCap); - PIOS_RFM22B_SetChannelConfig(pios_rfm22b_id, datarate, oplinkSettings.MinChannel, oplinkSettings.MaxChannel, is_coordinator, data_mode, ppm_mode); + PIOS_DELAY_WaitmS(50); + } + + PIOS_BOARD_IO_Configure_I2C(pios_i2c_mag_pressure_adapter_id, pios_i2c_flexiport_adapter_id); +#endif - /* Set the modem Tx power level */ - switch (oplinkSettings.MaxRFPower) { - case OPLINKSETTINGS_MAXRFPOWER_125: - PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_0); - break; - case OPLINKSETTINGS_MAXRFPOWER_16: - PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_1); - break; - case OPLINKSETTINGS_MAXRFPOWER_316: - PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_2); - break; - case OPLINKSETTINGS_MAXRFPOWER_63: - PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_3); - break; - case OPLINKSETTINGS_MAXRFPOWER_126: - PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_4); - break; - case OPLINKSETTINGS_MAXRFPOWER_25: - PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_5); - break; - case OPLINKSETTINGS_MAXRFPOWER_50: - PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_6); - break; - case OPLINKSETTINGS_MAXRFPOWER_100: - PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_7); - break; - default: - // do nothing - break; - } +#if defined(PIOS_INCLUDE_USB) + PIOS_BOARD_IO_Configure_USB(); +#endif - /* Reinitialize the modem. */ - PIOS_RFM22B_Reinit(pios_rfm22b_id); - } else { - oplinkStatus.LinkState = OPLINKSTATUS_LINKSTATE_DISABLED; + /* Configure main USART port */ + + /* Initialize inverter gpio and set it to off */ + { + GPIO_InitTypeDef inverterGPIOInit = { + .GPIO_Pin = MAIN_USART_INVERTER_PIN, + .GPIO_Speed = GPIO_Speed_2MHz, + .GPIO_Mode = GPIO_Mode_OUT, + .GPIO_OType = GPIO_OType_PP, + .GPIO_PuPd = GPIO_PuPd_UP + }; + + GPIO_Init(MAIN_USART_INVERTER_GPIO, &inverterGPIOInit); + GPIO_WriteBit(MAIN_USART_INVERTER_GPIO, + MAIN_USART_INVERTER_PIN, + MAIN_USART_INVERTER_DISABLE); + } + + uint8_t hwsettings_mainport; + HwSettingsRM_MainPortGet(&hwsettings_mainport); + + if (hwsettings_mainport < NELEMENTS(main_function_map)) { + PIOS_BOARD_IO_Configure_UART(&pios_usart_main_cfg, main_function_map[hwsettings_mainport]); } - - OPLinkStatusSet(&oplinkStatus); + +#if defined(PIOS_INCLUDE_RFM22B) + PIOS_BOARD_IO_Configure_RFM22B(); #endif /* PIOS_INCLUDE_RFM22B */ + #if defined(PIOS_INCLUDE_PWM) || defined(PIOS_INCLUDE_PPM) const struct pios_servo_cfg *pios_servo_cfg; @@ -878,99 +294,51 @@ void PIOS_Board_Init(void) /* Configure the receiver port*/ uint8_t hwsettings_rcvrport; HwSettingsRM_RcvrPortGet(&hwsettings_rcvrport); - // + + if (hwsettings_rcvrport < NELEMENTS(flexiio_function_map)) { + PIOS_BOARD_IO_Configure_UART(&pios_usart_flexiio_cfg, flexiio_function_map[hwsettings_rcvrport]); + } + + // Configure rcvrport PPM/PWM/OUTPUTS switch (hwsettings_rcvrport) { - case HWSETTINGS_RM_RCVRPORT_DISABLED: - break; - case HWSETTINGS_RM_RCVRPORT_PWM: + case HWSETTINGS_RM_RCVRPORT_PWM: #if defined(PIOS_INCLUDE_PWM) - /* Set up the receiver port. Later this should be optional */ - PIOS_Board_configure_pwm(&pios_pwm_cfg); + /* Set up the receiver port. Later this should be optional */ + PIOS_BOARD_IO_Configure_PWM(&pios_pwm_cfg); #endif /* PIOS_INCLUDE_PWM */ - break; - case HWSETTINGS_RM_RCVRPORT_PPM: - case HWSETTINGS_RM_RCVRPORT_PPMOUTPUTS: - case HWSETTINGS_RM_RCVRPORT_PPMPWM: - case HWSETTINGS_RM_RCVRPORT_PPMTELEMETRY: - case HWSETTINGS_RM_RCVRPORT_PPMDEBUGCONSOLE: - case HWSETTINGS_RM_RCVRPORT_PPMCOMBRIDGE: - case HWSETTINGS_RM_RCVRPORT_PPMMSP: - case HWSETTINGS_RM_RCVRPORT_PPMMAVLINK: - case HWSETTINGS_RM_RCVRPORT_PPMGPS: + break; + case HWSETTINGS_RM_RCVRPORT_PPM: + case HWSETTINGS_RM_RCVRPORT_PPMOUTPUTS: + case HWSETTINGS_RM_RCVRPORT_PPMPWM: + case HWSETTINGS_RM_RCVRPORT_PPMTELEMETRY: + case HWSETTINGS_RM_RCVRPORT_PPMDEBUGCONSOLE: + case HWSETTINGS_RM_RCVRPORT_PPMCOMBRIDGE: + case HWSETTINGS_RM_RCVRPORT_PPMMSP: + case HWSETTINGS_RM_RCVRPORT_PPMMAVLINK: + case HWSETTINGS_RM_RCVRPORT_PPMGPS: #if defined(PIOS_INCLUDE_PPM) - if (hwsettings_rcvrport == HWSETTINGS_RM_RCVRPORT_PPMOUTPUTS) { - // configure servo outputs and the remaining 5 inputs as outputs - pios_servo_cfg = &pios_servo_cfg_out_in_ppm; - } - - PIOS_Board_configure_ppm(&pios_ppm_cfg); - - // enable pwm on the remaining channels - if (hwsettings_rcvrport == HWSETTINGS_RM_RCVRPORT_PPMPWM) { - PIOS_Board_configure_pwm(&pios_pwm_ppm_cfg); - } - - break; + PIOS_BOARD_IO_Configure_PPM(&pios_ppm_cfg); + + if (hwsettings_rcvrport == HWSETTINGS_RM_RCVRPORT_PPMOUTPUTS) { + // configure servo outputs and the remaining 5 inputs as outputs + pios_servo_cfg = &pios_servo_cfg_out_in_ppm; + } + + // enable pwm on the remaining channels + if (hwsettings_rcvrport == HWSETTINGS_RM_RCVRPORT_PPMPWM) { + PIOS_BOARD_IO_Configure_PWM(&pios_pwm_ppm_cfg); + } + + break; #endif /* PIOS_INCLUDE_PPM */ - case HWSETTINGS_RM_RCVRPORT_OUTPUTS: - // configure only the servo outputs - pios_servo_cfg = &pios_servo_cfg_out_in; - break; - } - - // Configure rcvrport usart - switch (hwsettings_rcvrport) { - case HWSETTINGS_RM_RCVRPORT_TELEMETRY: - case HWSETTINGS_RM_RCVRPORT_PPMTELEMETRY: - PIOS_Board_configure_com(&pios_usart_rcvrport_cfg, PIOS_COM_TELEM_RF_RX_BUF_LEN, PIOS_COM_TELEM_RF_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_telem_rf_id); - break; - case HWSETTINGS_RM_RCVRPORT_DEBUGCONSOLE: - case HWSETTINGS_RM_RCVRPORT_PPMDEBUGCONSOLE: -#if defined(PIOS_INCLUDE_DEBUG_CONSOLE) - PIOS_Board_configure_com(&pios_usart_rcvrport_cfg, 0, PIOS_COM_DEBUGCONSOLE_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_debug_id); -#endif /* PIOS_INCLUDE_DEBUG_CONSOLE */ - break; - case HWSETTINGS_RM_RCVRPORT_COMBRIDGE: - case HWSETTINGS_RM_RCVRPORT_PPMCOMBRIDGE: - PIOS_Board_configure_com(&pios_usart_rcvrport_cfg, PIOS_COM_BRIDGE_RX_BUF_LEN, PIOS_COM_BRIDGE_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_bridge_id); - break; - case HWSETTINGS_RM_RCVRPORT_MSP: - case HWSETTINGS_RM_RCVRPORT_PPMMSP: - PIOS_Board_configure_com(&pios_usart_rcvrport_cfg, PIOS_COM_MSP_RX_BUF_LEN, PIOS_COM_MSP_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_msp_id); - break; - case HWSETTINGS_RM_RCVRPORT_MAVLINK: - case HWSETTINGS_RM_RCVRPORT_PPMMAVLINK: - PIOS_Board_configure_com(&pios_usart_rcvrport_cfg, 0, PIOS_COM_MAVLINK_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_mavlink_id); - break; - case HWSETTINGS_RM_RCVRPORT_GPS: - case HWSETTINGS_RM_RCVRPORT_PPMGPS: - PIOS_Board_configure_com(&pios_usart_rcvrport_cfg, PIOS_COM_GPS_RX_BUF_LEN, PIOS_COM_GPS_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_gps_id); - break; - } - -#if defined(PIOS_INCLUDE_GCSRCVR) - GCSReceiverInitialize(); - uint32_t pios_gcsrcvr_id; - PIOS_GCSRCVR_Init(&pios_gcsrcvr_id); - uint32_t pios_gcsrcvr_rcvr_id; - if (PIOS_RCVR_Init(&pios_gcsrcvr_rcvr_id, &pios_gcsrcvr_rcvr_driver, pios_gcsrcvr_id)) { - PIOS_Assert(0); - } - pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_GCS] = pios_gcsrcvr_rcvr_id; -#endif /* PIOS_INCLUDE_GCSRCVR */ - -#if defined(PIOS_INCLUDE_OPLINKRCVR) - { - OPLinkReceiverInitialize(); - uint32_t pios_oplinkrcvr_id; - PIOS_OPLinkRCVR_Init(&pios_oplinkrcvr_id, pios_rfm22b_id); - uint32_t pios_oplinkrcvr_rcvr_id; - if (PIOS_RCVR_Init(&pios_oplinkrcvr_rcvr_id, &pios_oplinkrcvr_rcvr_driver, pios_oplinkrcvr_id)) { - PIOS_Assert(0); - } - pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_OPLINK] = pios_oplinkrcvr_rcvr_id; + case HWSETTINGS_RM_RCVRPORT_OUTPUTS: + // configure only the servo outputs + pios_servo_cfg = &pios_servo_cfg_out_in; + break; } -#endif /* PIOS_INCLUDE_OPLINKRCVR */ +#ifdef PIOS_INCLUDE_GCSRCVR + PIOS_BOARD_IO_Configure_GCSRCVR(); +#endif #ifndef PIOS_ENABLE_DEBUG_PINS // pios_servo_cfg points to the correct configuration based on input port settings @@ -979,6 +347,17 @@ void PIOS_Board_Init(void) PIOS_DEBUG_Init(pios_tim_servoport_all_pins, NELEMENTS(pios_tim_servoport_all_pins)); #endif +#if defined(PIOS_INCLUDE_MPU6000) + PIOS_MPU6000_Init(pios_spi_gyro_id, 0, &pios_mpu6000_cfg); + PIOS_MPU6000_CONFIG_Configure(); + PIOS_MPU6000_Register(); +#endif + +#ifdef PIOS_INCLUDE_WS2811 + PIOS_WS2811_Init(&pios_ws2811_cfg, &pios_ws2811_pin_cfg); +#endif // PIOS_INCLUDE_WS2811 + +#ifdef PIOS_INCLUDE_ADC // Disable GPIO_A8 Pullup to prevent wrong results on battery voltage readout GPIO_InitTypeDef gpioA8 = { .GPIO_Speed = GPIO_Speed_2MHz, @@ -988,61 +367,8 @@ void PIOS_Board_Init(void) .GPIO_OType = GPIO_OType_OD, }; GPIO_Init(GPIOA, &gpioA8); - - // init I2C1 for use with the internal mag and baro - if (PIOS_I2C_Init(&pios_i2c_mag_pressure_adapter_id, &pios_i2c_mag_pressure_adapter_cfg)) { - PIOS_DEBUG_Assert(0); - } - - PIOS_DELAY_WaitmS(50); - -#if defined(PIOS_INCLUDE_ADC) - PIOS_ADC_Init(&pios_adc_cfg); -#endif - -#ifdef PIOS_INCLUDE_WDG - // give HMC5x83 on I2C some extra time to allow for reset, etc. if needed - // this is not in a loop, so it is safe - // leave this here even if PIOS_INCLUDE_HMC5X83 is undefined - // to avoid making something else fail when HMC5X83 is removed - PIOS_WDG_Clear(); -#endif /* PIOS_INCLUDE_WDG */ - -#if defined(PIOS_INCLUDE_HMC5X83) - // attach the 5x83 mag to the previously inited I2C1 - onboard_mag = PIOS_HMC5x83_Init(&pios_hmc5x83_internal_cfg, pios_i2c_mag_pressure_adapter_id, 0); -#ifdef PIOS_INCLUDE_WDG - // give HMC5x83 on I2C some extra time to allow for reset, etc. if needed - // this is not in a loop, so it is safe - PIOS_WDG_Clear(); -#endif /* PIOS_INCLUDE_WDG */ - // add this sensor to the sensor task's list - PIOS_HMC5x83_Register(onboard_mag, PIOS_SENSORS_TYPE_3AXIS_MAG); -#endif - -#if defined(PIOS_INCLUDE_MS5611) - PIOS_MS5611_Init(&pios_ms5611_cfg, pios_i2c_mag_pressure_adapter_id); -#endif - -#if defined(PIOS_INCLUDE_MPU6000) - PIOS_MPU6000_Init(pios_spi_gyro_id, 0, &pios_mpu6000_cfg); - PIOS_MPU6000_CONFIG_Configure(); -#endif - -#ifdef PIOS_INCLUDE_WS2811 -#include - PIOS_WS2811_Init(&pios_ws2811_cfg, &pios_ws2811_pin_cfg); -#endif // PIOS_INCLUDE_WS2811 -#ifdef PIOS_INCLUDE_ADC - { - uint8_t adc_config[HWSETTINGS_ADCROUTING_NUMELEM]; - HwSettingsADCRoutingArrayGet(adc_config); - for (uint32_t i = 0; i < HWSETTINGS_ADCROUTING_NUMELEM; i++) { - if (adc_config[i] != HWSETTINGS_ADCROUTING_DISABLED) { - PIOS_ADC_PinSetup(i); - } - } - } + + PIOS_BOARD_IO_Configure_ADC(); #endif // PIOS_INCLUDE_ADC } diff --git a/flight/targets/boards/revolution/bootloader/pios_board.c b/flight/targets/boards/revolution/bootloader/pios_board.c index e0065e2a9c..595eac507f 100644 --- a/flight/targets/boards/revolution/bootloader/pios_board.c +++ b/flight/targets/boards/revolution/bootloader/pios_board.c @@ -46,7 +46,6 @@ static int32_t PIOS_BOARD_USART_Ioctl(__attribute__((unused)) uint32_t usart_id, return -1; } - void PIOS_Board_Init() { if (board_init_complete) { From ddc4f3d8556ed55723ca6c4f40295b54922610f3 Mon Sep 17 00:00:00 2001 From: Vladimir Zidar Date: Wed, 19 Apr 2017 15:57:34 +0200 Subject: [PATCH 214/624] LP-480 coptercontrol build ok --- .../OpenPilotOSX.xcodeproj/project.pbxproj | 2 +- flight/modules/ComUsbBridge/ComUsbBridge.c | 2 + flight/modules/GPS/GPS.c | 1 + flight/modules/Osd/osdoutput/osdoutput.c | 2 + flight/modules/Telemetry/telemetry.c | 2 + flight/modules/UAVOMSPBridge/UAVOMSPBridge.c | 2 + .../UAVOMavlinkBridge/UAVOMavlinkBridge.c | 3 + flight/pios/common/pios_board_io.c | 9 +- flight/pios/common/pios_dsm.c | 4 + flight/pios/common/pios_usb_desc_hid_cdc.c | 4 + flight/pios/inc/pios_usb_desc_hid_cdc_priv.h | 2 + flight/pios/stm32f10x/inc/pios_servo_config.h | 49 + flight/pios/stm32f10x/pios_sys.c | 60 +- flight/pios/stm32f10x/pios_usart.c | 79 +- flight/pios/stm32f4xx/pios_usart.c | 2 +- .../boards/coptercontrol/board_hw_defs.c | 866 +++--------------- .../boards/coptercontrol/bootloader/main.c | 1 + .../coptercontrol/bootloader/pios_board.c | 10 +- .../coptercontrol/firmware/pios_board.c | 665 ++------------ .../targets/boards/coptercontrol/pios_board.h | 35 +- .../boards/discoveryf4bare/pios_board.h | 28 - flight/targets/boards/revolution/pios_board.h | 32 - flight/targets/boards/revonano/pios_board.h | 31 - flight/targets/boards/sparky2/pios_board.h | 30 - 24 files changed, 418 insertions(+), 1503 deletions(-) create mode 100644 flight/pios/stm32f10x/inc/pios_servo_config.h diff --git a/flight/Project/OpenPilotOSX/OpenPilotOSX.xcodeproj/project.pbxproj b/flight/Project/OpenPilotOSX/OpenPilotOSX.xcodeproj/project.pbxproj index bf7efbcf1e..1bdc89da67 100644 --- a/flight/Project/OpenPilotOSX/OpenPilotOSX.xcodeproj/project.pbxproj +++ b/flight/Project/OpenPilotOSX/OpenPilotOSX.xcodeproj/project.pbxproj @@ -184,7 +184,7 @@ /* Begin PBXLegacyTarget section */ 6581071511DE809D0049FB12 /* OpenPilotOSX */ = { isa = PBXLegacyTarget; - buildArgumentsString = ef_discoveryf4bare; + buildArgumentsString = ef_coptercontrol; buildConfigurationList = 6581071A11DE80A30049FB12 /* Build configuration list for PBXLegacyTarget "OpenPilotOSX" */; buildPhases = ( ); diff --git a/flight/modules/ComUsbBridge/ComUsbBridge.c b/flight/modules/ComUsbBridge/ComUsbBridge.c index 15f9f5db97..fdc9a01440 100644 --- a/flight/modules/ComUsbBridge/ComUsbBridge.c +++ b/flight/modules/ComUsbBridge/ComUsbBridge.c @@ -36,6 +36,8 @@ #include +#include + // **************** // Private functions diff --git a/flight/modules/GPS/GPS.c b/flight/modules/GPS/GPS.c index dfc2ac2c6a..b9ce967c4f 100644 --- a/flight/modules/GPS/GPS.c +++ b/flight/modules/GPS/GPS.c @@ -45,6 +45,7 @@ #include "WorldMagModel.h" #include "CoordinateConversions.h" #include +#include #include "GPS.h" #include "NMEA.h" diff --git a/flight/modules/Osd/osdoutput/osdoutput.c b/flight/modules/Osd/osdoutput/osdoutput.c index 7f18b47208..f600aa148c 100644 --- a/flight/modules/Osd/osdoutput/osdoutput.c +++ b/flight/modules/Osd/osdoutput/osdoutput.c @@ -43,6 +43,8 @@ #include "hwsettings.h" #include "flightstatus.h" +#include + static bool osdoutputEnabled; enum osd_hk_sync { diff --git a/flight/modules/Telemetry/telemetry.c b/flight/modules/Telemetry/telemetry.c index 9796e8f599..a3bbf0a776 100644 --- a/flight/modules/Telemetry/telemetry.c +++ b/flight/modules/Telemetry/telemetry.c @@ -69,6 +69,8 @@ #include "hwsettings.h" #include "taskinfo.h" +#include + // Private constants #define MAX_QUEUE_SIZE TELEM_QUEUE_SIZE // Three different stack size parameter are accepted for Telemetry(RX PIOS_TELEM_RX_STACK_SIZE) diff --git a/flight/modules/UAVOMSPBridge/UAVOMSPBridge.c b/flight/modules/UAVOMSPBridge/UAVOMSPBridge.c index 43bbbe433f..6114a963c2 100644 --- a/flight/modules/UAVOMSPBridge/UAVOMSPBridge.c +++ b/flight/modules/UAVOMSPBridge/UAVOMSPBridge.c @@ -68,6 +68,8 @@ #include "pios_sensors.h" +#include + #define PIOS_INCLUDE_MSP_BRIDGE diff --git a/flight/modules/UAVOMavlinkBridge/UAVOMavlinkBridge.c b/flight/modules/UAVOMavlinkBridge/UAVOMavlinkBridge.c index bca1ab6fad..03f97252df 100644 --- a/flight/modules/UAVOMavlinkBridge/UAVOMavlinkBridge.c +++ b/flight/modules/UAVOMavlinkBridge/UAVOMavlinkBridge.c @@ -58,6 +58,9 @@ #include "custom_types.h" +#include + + #define OPLINK_LOW_RSSI -110 #define OPLINK_HIGH_RSSI -10 diff --git a/flight/pios/common/pios_board_io.c b/flight/pios/common/pios_board_io.c index f3b2ac92e7..7b742b7581 100644 --- a/flight/pios/common/pios_board_io.c +++ b/flight/pios/common/pios_board_io.c @@ -110,6 +110,7 @@ uint32_t pios_com_debug_id; /* DebugConsole */ uint32_t pios_com_telem_usb_id; /* USB telemetry */ #ifdef PIOS_INCLUDE_USB_RCTX +# include "pios_usb_rctx_priv.h" uint32_t pios_usb_rctx_id; #endif @@ -255,10 +256,8 @@ void PIOS_BOARD_IO_Configure_USB() break; case HWSETTINGS_USB_HIDPORT_RCTRANSMITTER: #if defined(PIOS_INCLUDE_USB_RCTX) - { - if (PIOS_USB_RCTX_Init(&pios_usb_rctx_id, &pios_usb_rctx_cfg, pios_usb_id)) { /* this will reinstall endpoint callbacks */ - PIOS_Assert(0); - } + if (PIOS_USB_RCTX_Init(&pios_usb_rctx_id, &pios_usb_rctx_cfg, pios_usb_id)) { /* this will reinstall endpoint callbacks */ + PIOS_Assert(0); } #endif /* PIOS_INCLUDE_USB_RCTX */ break; @@ -266,9 +265,11 @@ void PIOS_BOARD_IO_Configure_USB() #endif /* PIOS_INCLUDE_USB_HID */ +#ifndef STM32F10X if (usb_hid_present || usb_cdc_present) { PIOS_USBHOOK_Activate(); } +#endif } #endif /* PIOS_INCLUDE_USB */ diff --git a/flight/pios/common/pios_dsm.c b/flight/pios/common/pios_dsm.c index 23d3601e3f..af52ce9854 100644 --- a/flight/pios/common/pios_dsm.c +++ b/flight/pios/common/pios_dsm.c @@ -126,9 +126,13 @@ static void PIOS_DSM_Bind(struct stm32_gpio *rxpin, uint8_t bind) GPIO_InitTypeDef bindInit = { .GPIO_Pin = rxpin->init.GPIO_Pin, .GPIO_Speed = GPIO_Speed_2MHz, +#ifdef STM32F10X + .GPIO_Mode = GPIO_Mode_Out_PP, +#else .GPIO_Mode = GPIO_Mode_OUT, .GPIO_OType = GPIO_OType_PP, .GPIO_PuPd = GPIO_PuPd_NOPULL +#endif }; GPIO_Init(rxpin->gpio, &bindInit); diff --git a/flight/pios/common/pios_usb_desc_hid_cdc.c b/flight/pios/common/pios_usb_desc_hid_cdc.c index d14add637d..14bb69f61d 100644 --- a/flight/pios/common/pios_usb_desc_hid_cdc.c +++ b/flight/pios/common/pios_usb_desc_hid_cdc.c @@ -332,6 +332,10 @@ const struct pios_usb_hid_cfg pios_usb_hid_cfg = { .data_tx_ep = 1, }; +const struct pios_usb_rctx_cfg pios_usb_rctx_cfg = { + .data_if = 2, + .data_tx_ep = 1, +}; int32_t PIOS_USB_DESC_HID_CDC_Init(void) { diff --git a/flight/pios/inc/pios_usb_desc_hid_cdc_priv.h b/flight/pios/inc/pios_usb_desc_hid_cdc_priv.h index 6a3145a8b9..77d3b23478 100644 --- a/flight/pios/inc/pios_usb_desc_hid_cdc_priv.h +++ b/flight/pios/inc/pios_usb_desc_hid_cdc_priv.h @@ -33,11 +33,13 @@ #include #include #include +#include extern int32_t PIOS_USB_DESC_HID_CDC_Init(void); extern const struct pios_usb_cdc_cfg pios_usb_cdc_cfg; extern const struct pios_usb_hid_cfg pios_usb_hid_cfg; +extern const struct pios_usb_rctx_cfg pios_usb_rctx_cfg; #endif /* PIOS_USB_DESC_HID_CDC_PRIV_H */ diff --git a/flight/pios/stm32f10x/inc/pios_servo_config.h b/flight/pios/stm32f10x/inc/pios_servo_config.h new file mode 100644 index 0000000000..b5464ebaea --- /dev/null +++ b/flight/pios/stm32f10x/inc/pios_servo_config.h @@ -0,0 +1,49 @@ +/** + ****************************************************************************** + * + * @file pios_servp_config.h + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017. + * @brief Architecture specific macros and 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_SERVO_CONFIG_H_ +#define PIOS_SERVO_CONFIG_H_ + +/** + * Generic servo pin configuration structure for an STM32F10x + */ +#define TIM_SERVO_CHANNEL_CONFIG(_timer, _channel, _gpio, _pin, _remap) \ +{ \ + .timer = _timer, \ + .timer_chan = TIM_Channel_##_channel, \ + .pin = { \ + .gpio = GPIO##_gpio, \ + .init = { \ + .GPIO_Pin = GPIO_Pin_##_pin, \ + .GPIO_Mode = GPIO_Mode_IPD, \ + .GPIO_Speed = GPIO_Speed_2MHz,\ + }, \ + .pin_source = GPIO_PinSource##_pin, \ + }, \ + .remap = _remap, \ +} + + +#endif /* PIOS_SERVO_CONFIG_H_ */ diff --git a/flight/pios/stm32f10x/pios_sys.c b/flight/pios/stm32f10x/pios_sys.c index 63791fa22e..19a6061b65 100644 --- a/flight/pios/stm32f10x/pios_sys.c +++ b/flight/pios/stm32f10x/pios_sys.c @@ -53,9 +53,63 @@ void PIOS_SYS_Init(void) /* Init the delay system */ PIOS_DELAY_Init(); - /* Enable GPIOA, GPIOB, GPIOC, GPIOD, GPIOE and AFIO clocks */ - RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE | - RCC_APB2Periph_AFIO, ENABLE); + /* + * Turn on all the peripheral clocks. + * Micromanaging clocks makes no sense given the power situation in the system, so + * light up everything we might reasonably use here and just leave it on. + */ + + RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1 | + RCC_AHBPeriph_DMA2, + ENABLE); + + RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 | + RCC_APB1Periph_TIM3 | + RCC_APB1Periph_TIM4 | + RCC_APB1Periph_TIM5 | + RCC_APB1Periph_TIM6 | + RCC_APB1Periph_TIM7 | + RCC_APB1Periph_TIM12 | + RCC_APB1Periph_TIM13 | + RCC_APB1Periph_TIM14 | + RCC_APB1Periph_WWDG | + RCC_APB1Periph_SPI2 | + RCC_APB1Periph_SPI3 | + RCC_APB1Periph_USART2 | + RCC_APB1Periph_USART3 | + RCC_APB1Periph_UART4 | + RCC_APB1Periph_UART5 | + RCC_APB1Periph_I2C1 | + RCC_APB1Periph_I2C2 | + RCC_APB1Periph_USB | + RCC_APB1Periph_CAN1 | + RCC_APB1Periph_CAN2 | + RCC_APB1Periph_BKP | + RCC_APB1Periph_PWR | + RCC_APB1Periph_DAC, + ENABLE); + + + RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | + RCC_APB2Periph_GPIOB | + RCC_APB2Periph_GPIOC | + RCC_APB2Periph_GPIOD | + RCC_APB2Periph_GPIOE | + RCC_APB2Periph_ADC1 | + RCC_APB2Periph_ADC2 | + RCC_APB2Periph_ADC3 | + RCC_APB2Periph_TIM1 | + RCC_APB2Periph_TIM8 | + RCC_APB2Periph_TIM9 | + RCC_APB2Periph_TIM10 | + RCC_APB2Periph_TIM11 | + RCC_APB2Periph_TIM15 | + RCC_APB2Periph_TIM16 | + RCC_APB2Periph_TIM17 | + RCC_APB2Periph_SPI1 | + RCC_APB2Periph_USART1 | + RCC_APB2Periph_AFIO, + ENABLE); #if (PIOS_USB_ENABLED) /* Ensure that pull-up is active on detect pin */ diff --git a/flight/pios/stm32f10x/pios_usart.c b/flight/pios/stm32f10x/pios_usart.c index 82cd577cd2..bc165f38fc 100644 --- a/flight/pios/stm32f10x/pios_usart.c +++ b/flight/pios/stm32f10x/pios_usart.c @@ -43,6 +43,7 @@ static void PIOS_USART_RegisterRxCallback(uint32_t usart_id, pios_com_callback r static void PIOS_USART_RegisterTxCallback(uint32_t usart_id, pios_com_callback tx_out_cb, uint32_t context); static void PIOS_USART_TxStart(uint32_t usart_id, uint16_t tx_bytes_avail); static void PIOS_USART_RxStart(uint32_t usart_id, uint16_t rx_bytes_avail); +static int32_t PIOS_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param); const struct pios_com_driver pios_usart_com_driver = { .set_baud = PIOS_USART_ChangeBaud, @@ -51,6 +52,7 @@ const struct pios_com_driver pios_usart_com_driver = { .rx_start = PIOS_USART_RxStart, .bind_tx_cb = PIOS_USART_RegisterTxCallback, .bind_rx_cb = PIOS_USART_RegisterRxCallback, + .ioctl = PIOS_USART_Ioctl, }; enum pios_usart_dev_magic { @@ -67,6 +69,7 @@ struct pios_usart_dev { uint32_t tx_out_context; uint32_t rx_dropped; + uint8_t irq_channel; }; static bool PIOS_USART_validate(struct pios_usart_dev *usart_dev) @@ -74,6 +77,30 @@ static bool PIOS_USART_validate(struct pios_usart_dev *usart_dev) return usart_dev->magic == PIOS_USART_DEV_MAGIC; } +const struct pios_usart_cfg *PIOS_USART_GetConfig(uint32_t usart_id) +{ + struct pios_usart_dev *usart_dev = (struct pios_usart_dev *)usart_id; + + bool valid = PIOS_USART_validate(usart_dev); + + PIOS_Assert(valid); + + return usart_dev->cfg; +} + +static int32_t PIOS_USART_SetIrqPrio(struct pios_usart_dev *usart_dev, uint8_t irq_prio) +{ + NVIC_InitTypeDef init = { + .NVIC_IRQChannel = usart_dev->irq_channel, + .NVIC_IRQChannelPreemptionPriority = irq_prio, + .NVIC_IRQChannelCmd = ENABLE, + }; + + NVIC_Init(&init); + + return 0; +} + #if defined(PIOS_INCLUDE_FREERTOS) static struct pios_usart_dev *PIOS_USART_alloc(void) { @@ -155,8 +182,8 @@ int32_t PIOS_USART_Init(uint32_t *usart_id, const struct pios_usart_cfg *cfg) /* Bind the configuration to the device instance */ usart_dev->cfg = cfg; - /* Copy the comm parameter structure */ - usart_dev->init = cfg->init; + /* Initialize the comm parameter structure */ + USART_StructInit(&usart_dev->init); // 9600 8n1 /* Enable the USART Pins Software Remapping */ if (usart_dev->cfg->remap) { @@ -167,19 +194,6 @@ int32_t PIOS_USART_Init(uint32_t *usart_id, const struct pios_usart_cfg *cfg) GPIO_Init(usart_dev->cfg->rx.gpio, &usart_dev->cfg->rx.init); GPIO_Init(usart_dev->cfg->tx.gpio, &usart_dev->cfg->tx.init); - /* Enable USART clock */ - switch ((uint32_t)usart_dev->cfg->regs) { - case (uint32_t)USART1: - RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); - break; - case (uint32_t)USART2: - RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); - break; - case (uint32_t)USART3: - RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE); - break; - } - /* Configure the USART */ USART_Init(usart_dev->cfg->regs, &usart_dev->init); @@ -189,15 +203,20 @@ int32_t PIOS_USART_Init(uint32_t *usart_id, const struct pios_usart_cfg *cfg) switch ((uint32_t)usart_dev->cfg->regs) { case (uint32_t)USART1: PIOS_USART_1_id = (uint32_t)usart_dev; + usart_dev->irq_channel = USART1_IRQn; break; case (uint32_t)USART2: PIOS_USART_2_id = (uint32_t)usart_dev; + usart_dev->irq_channel = USART2_IRQn; break; case (uint32_t)USART3: PIOS_USART_3_id = (uint32_t)usart_dev; + usart_dev->irq_channel = USART3_IRQn; break; } - NVIC_Init(&usart_dev->cfg->irq.init); + + PIOS_USART_SetIrqPrio(usart_dev, PIOS_IRQ_PRIO_MID); + USART_ITConfig(usart_dev->cfg->regs, USART_IT_RXNE, ENABLE); USART_ITConfig(usart_dev->cfg->regs, USART_IT_TXE, ENABLE); @@ -430,6 +449,34 @@ static void PIOS_USART_generic_irq_handler(uint32_t usart_id) #endif /* PIOS_INCLUDE_FREERTOS */ } +static int32_t PIOS_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param) +{ + struct pios_usart_dev *usart_dev = (struct pios_usart_dev *)usart_id; + + bool valid = PIOS_USART_validate(usart_dev); + + PIOS_Assert(valid); + + switch (ctl) { + case PIOS_IOCTL_USART_SET_IRQ_PRIO: + return PIOS_USART_SetIrqPrio(usart_dev, *(uint8_t *)param); + + case PIOS_IOCTL_USART_GET_RXGPIO: + *(struct stm32_gpio *)param = usart_dev->cfg->rx; + break; + case PIOS_IOCTL_USART_GET_TXGPIO: + *(struct stm32_gpio *)param = usart_dev->cfg->tx; + break; + default: + if (usart_dev->cfg->ioctl) { + return usart_dev->cfg->ioctl(usart_id, ctl, param); + } + return -1; + } + + return 0; +} + #endif /* PIOS_INCLUDE_USART */ /** diff --git a/flight/pios/stm32f4xx/pios_usart.c b/flight/pios/stm32f4xx/pios_usart.c index 950cbac770..c6f72674df 100644 --- a/flight/pios/stm32f4xx/pios_usart.c +++ b/flight/pios/stm32f4xx/pios_usart.c @@ -208,7 +208,7 @@ int32_t PIOS_USART_Init(uint32_t *usart_id, const struct pios_usart_cfg *cfg) /* Bind the configuration to the device instance */ usart_dev->cfg = cfg; - /* Copy the comm parameter structure */ + /* Initialize the comm parameter structure */ USART_StructInit(&usart_dev->init); // 9600 8n1 /* Map pins to USART function */ diff --git a/flight/targets/boards/coptercontrol/board_hw_defs.c b/flight/targets/boards/coptercontrol/board_hw_defs.c index 4222540ef3..f44e552f5a 100644 --- a/flight/targets/boards/coptercontrol/board_hw_defs.c +++ b/flight/targets/boards/coptercontrol/board_hw_defs.c @@ -549,732 +549,59 @@ static const struct pios_tim_clock_cfg tim_4_cfg = { }, }; -static const struct pios_tim_channel pios_tim_rcvrport_all_channels[] = { - { - .timer = TIM4, - .timer_chan = TIM_Channel_1, - .pin = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_6, - .GPIO_Mode = GPIO_Mode_IPD, - .GPIO_Speed = GPIO_Speed_2MHz, - }, - }, - }, - { - .timer = TIM3, - .timer_chan = TIM_Channel_2, - .pin = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_5, - .GPIO_Mode = GPIO_Mode_IPD, - .GPIO_Speed = GPIO_Speed_2MHz, - }, - }, - .remap = GPIO_PartialRemap_TIM3, - }, - { - .timer = TIM3, - .timer_chan = TIM_Channel_3, - .pin = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_0, - .GPIO_Mode = GPIO_Mode_IPD, - .GPIO_Speed = GPIO_Speed_2MHz, - }, - }, - }, - { - .timer = TIM3, - .timer_chan = TIM_Channel_4, - .pin = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_1, - .GPIO_Mode = GPIO_Mode_IPD, - .GPIO_Speed = GPIO_Speed_2MHz, - }, - }, - }, - { - .timer = TIM2, - .timer_chan = TIM_Channel_1, - .pin = { - .gpio = GPIOA, - .init = { - .GPIO_Pin = GPIO_Pin_0, - .GPIO_Mode = GPIO_Mode_IPD, - .GPIO_Speed = GPIO_Speed_2MHz, - }, - }, - }, - { - .timer = TIM2, - .timer_chan = TIM_Channel_2, - .pin = { - .gpio = GPIOA, - .init = { - .GPIO_Pin = GPIO_Pin_1, - .GPIO_Mode = GPIO_Mode_IPD, - .GPIO_Speed = GPIO_Speed_2MHz, - }, - }, - }, -}; - -static const struct pios_tim_channel pios_tim_servoport_all_pins[] = { - { - .timer = TIM4, - .timer_chan = TIM_Channel_4, - .pin = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_9, - .GPIO_Mode = GPIO_Mode_AF_PP, - .GPIO_Speed = GPIO_Speed_2MHz, - }, - }, - }, - { - .timer = TIM4, - .timer_chan = TIM_Channel_3, - .pin = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_8, - .GPIO_Mode = GPIO_Mode_AF_PP, - .GPIO_Speed = GPIO_Speed_2MHz, - }, - }, - }, - { - .timer = TIM4, - .timer_chan = TIM_Channel_2, - .pin = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_7, - .GPIO_Mode = GPIO_Mode_AF_PP, - .GPIO_Speed = GPIO_Speed_2MHz, - }, - }, - }, - { - .timer = TIM1, - .timer_chan = TIM_Channel_1, - .pin = { - .gpio = GPIOA, - .init = { - .GPIO_Pin = GPIO_Pin_8, - .GPIO_Mode = GPIO_Mode_AF_PP, - .GPIO_Speed = GPIO_Speed_2MHz, - }, - }, - }, - { - .timer = TIM3, - .timer_chan = TIM_Channel_1, - .pin = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_4, - .GPIO_Mode = GPIO_Mode_AF_PP, - .GPIO_Speed = GPIO_Speed_2MHz, - }, - }, - .remap = GPIO_PartialRemap_TIM3, - }, - { - .timer = TIM2, - .timer_chan = TIM_Channel_3, - .pin = { - .gpio = GPIOA, - .init = { - .GPIO_Pin = GPIO_Pin_2, - .GPIO_Mode = GPIO_Mode_AF_PP, - .GPIO_Speed = GPIO_Speed_2MHz, - }, - }, - }, -}; - - -static const struct pios_tim_channel pios_tim_servoport_rcvrport_pins[] = { - { - .timer = TIM4, - .timer_chan = TIM_Channel_4, - .pin = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_9, - .GPIO_Mode = GPIO_Mode_AF_PP, - .GPIO_Speed = GPIO_Speed_2MHz, - }, - }, - }, - { - .timer = TIM4, - .timer_chan = TIM_Channel_3, - .pin = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_8, - .GPIO_Mode = GPIO_Mode_AF_PP, - .GPIO_Speed = GPIO_Speed_2MHz, - }, - }, - }, - { - .timer = TIM4, - .timer_chan = TIM_Channel_2, - .pin = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_7, - .GPIO_Mode = GPIO_Mode_AF_PP, - .GPIO_Speed = GPIO_Speed_2MHz, - }, - }, - }, - { - .timer = TIM1, - .timer_chan = TIM_Channel_1, - .pin = { - .gpio = GPIOA, - .init = { - .GPIO_Pin = GPIO_Pin_8, - .GPIO_Mode = GPIO_Mode_AF_PP, - .GPIO_Speed = GPIO_Speed_2MHz, - }, - }, - }, - { - .timer = TIM3, - .timer_chan = TIM_Channel_1, - .pin = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_4, - .GPIO_Mode = GPIO_Mode_AF_PP, - .GPIO_Speed = GPIO_Speed_2MHz, - }, - }, - .remap = GPIO_PartialRemap_TIM3, - }, - { - .timer = TIM2, - .timer_chan = TIM_Channel_3, - .pin = { - .gpio = GPIOA, - .init = { - .GPIO_Pin = GPIO_Pin_2, - .GPIO_Mode = GPIO_Mode_AF_PP, - .GPIO_Speed = GPIO_Speed_2MHz, - }, - }, - }, - - // Receiver port pins - // S3-S6 inputs are used as outputs in this case - { - .timer = TIM3, - .timer_chan = TIM_Channel_3, - .pin = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_0, - .GPIO_Mode = GPIO_Mode_AF_PP, - .GPIO_Speed = GPIO_Speed_2MHz, - }, - }, - }, - { - .timer = TIM3, - .timer_chan = TIM_Channel_4, - .pin = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_1, - .GPIO_Mode = GPIO_Mode_AF_PP, - .GPIO_Speed = GPIO_Speed_2MHz, - }, - }, - }, - { - .timer = TIM2, - .timer_chan = TIM_Channel_1, - .pin = { - .gpio = GPIOA, - .init = { - .GPIO_Pin = GPIO_Pin_0, - .GPIO_Mode = GPIO_Mode_AF_PP, - .GPIO_Speed = GPIO_Speed_2MHz, - }, - }, - }, - { - .timer = TIM2, - .timer_chan = TIM_Channel_2, - .pin = { - .gpio = GPIOA, - .init = { - .GPIO_Pin = GPIO_Pin_1, - .GPIO_Mode = GPIO_Mode_AF_PP, - .GPIO_Speed = GPIO_Speed_2MHz, - }, - }, - }, -}; - -static const struct pios_tim_channel pios_tim_ppm_flexi_port = { - .timer = TIM2, - .timer_chan = TIM_Channel_4, - .pin = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_11, - .GPIO_Mode = GPIO_Mode_IPD, - .GPIO_Speed = GPIO_Speed_2MHz, - }, - }, - .remap = GPIO_PartialRemap2_TIM2, -}; - -#if defined(PIOS_INCLUDE_USART) - -#include "pios_usart_priv.h" - -static const struct pios_usart_cfg pios_usart_generic_main_cfg = { - .regs = USART1, - .init = { - .USART_BaudRate = 57600, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx | USART_Mode_Tx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART1_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { - .gpio = GPIOA, - .init = { - .GPIO_Pin = GPIO_Pin_10, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_IPU, - }, - }, - .tx = { - .gpio = GPIOA, - .init = { - .GPIO_Pin = GPIO_Pin_9, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF_PP, - }, - }, -}; - -static const struct pios_usart_cfg pios_usart_generic_flexi_cfg = { - .regs = USART3, - .init = { - .USART_BaudRate = 57600, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx | USART_Mode_Tx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART3_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_11, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_IPU, - }, - }, - .tx = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_10, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF_PP, - }, - }, -}; - -#if defined(PIOS_INCLUDE_DSM) -/* - * Spektrum/JR DSM USART - */ -#include - -static const struct pios_usart_cfg pios_usart_dsm_main_cfg = { - .regs = USART1, - .init = { - .USART_BaudRate = 115200, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART1_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { - .gpio = GPIOA, - .init = { - .GPIO_Pin = GPIO_Pin_10, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_IPU, - }, - }, - .tx = { - .gpio = GPIOA, - .init = { - .GPIO_Pin = GPIO_Pin_9, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_IN_FLOATING, - }, - }, -}; - -static const struct pios_dsm_cfg pios_dsm_main_cfg = { - .bind = { - .gpio = GPIOA, - .init = { - .GPIO_Pin = GPIO_Pin_10, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_Out_PP, - }, - }, -}; - -static const struct pios_usart_cfg pios_usart_dsm_flexi_cfg = { - .regs = USART3, - .init = { - .USART_BaudRate = 115200, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART3_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_11, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_IPU, - }, - }, - .tx = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_10, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_IN_FLOATING, - }, - }, -}; - -static const struct pios_dsm_cfg pios_dsm_flexi_cfg = { - .bind = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_11, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_Out_PP, - }, - }, -}; - -#endif /* PIOS_INCLUDE_DSM */ - -#if defined(PIOS_INCLUDE_HOTT) -/* - * HOTT USART - */ -#include - -static const struct pios_usart_cfg pios_usart_hott_flexi_cfg = { - .regs = USART3, - .init = { - .USART_BaudRate = 115200, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART3_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_11, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_IPU, - }, - }, - .tx = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_10, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_IN_FLOATING, - }, - }, -}; -#endif /* PIOS_INCLUDE_HOTT */ - -#if defined(PIOS_INCLUDE_EXBUS) -/* - * EXBUS USART - */ -#include +#include "pios_servo_config.h" -static const struct pios_usart_cfg pios_usart_exbus_flexi_cfg = { - .regs = USART3, - .init = { - .USART_BaudRate = 125000, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART3_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_11, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_IPU, - }, - }, - .tx = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_10, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_IN_FLOATING, - }, - }, +static const struct pios_tim_channel pios_tim_rcvrport_all_channels[] = { + TIM_SERVO_CHANNEL_CONFIG(TIM4, 1, B, 6, 0), + TIM_SERVO_CHANNEL_CONFIG(TIM3, 2, B, 5, GPIO_PartialRemap_TIM3), + TIM_SERVO_CHANNEL_CONFIG(TIM3, 3, B, 0, 0), + TIM_SERVO_CHANNEL_CONFIG(TIM3, 4, B, 1, 0), + TIM_SERVO_CHANNEL_CONFIG(TIM2, 1, A, 0, 0), + TIM_SERVO_CHANNEL_CONFIG(TIM2, 2, A, 1, 0), }; -#endif /* PIOS_INCLUDE_EXBUS */ - -#if defined(PIOS_INCLUDE_SRXL) -/* - * SRXL USART - */ -#include -static const struct pios_usart_cfg pios_usart_srxl_flexi_cfg = { - .regs = USART3, - .init = { - .USART_BaudRate = 115200, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART3_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_11, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_IPU, - }, - }, - .tx = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_10, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_IN_FLOATING, - }, - }, +static const struct pios_tim_channel pios_tim_servoport_all_pins[] = { + TIM_SERVO_CHANNEL_CONFIG(TIM4, 4, B, 9, 0), + TIM_SERVO_CHANNEL_CONFIG(TIM4, 3, B, 8, 0), + TIM_SERVO_CHANNEL_CONFIG(TIM4, 2, B, 7, 0), + TIM_SERVO_CHANNEL_CONFIG(TIM1, 1, A, 8, 0), + TIM_SERVO_CHANNEL_CONFIG(TIM3, 1, B, 4, GPIO_PartialRemap_TIM3), + TIM_SERVO_CHANNEL_CONFIG(TIM2, 3, A, 2, 0), }; -#endif /* PIOS_INCLUDE_SRXL */ -#if defined(PIOS_INCLUDE_IBUS) -/* - * IBUS USART - */ -#include +static const struct pios_tim_channel pios_tim_servoport_rcvrport_pins[] = { + TIM_SERVO_CHANNEL_CONFIG(TIM4, 4, B, 9, 0), + TIM_SERVO_CHANNEL_CONFIG(TIM4, 3, B, 8, 0), + TIM_SERVO_CHANNEL_CONFIG(TIM4, 2, B, 7, 0), + TIM_SERVO_CHANNEL_CONFIG(TIM1, 1, A, 8, 0), + TIM_SERVO_CHANNEL_CONFIG(TIM3, 1, B, 4, GPIO_PartialRemap_TIM3), + TIM_SERVO_CHANNEL_CONFIG(TIM2, 3, A, 2, 0), -static const struct pios_usart_cfg pios_usart_ibus_flexi_cfg = { - .regs = USART3, - .init = { - .USART_BaudRate = 115200, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART3_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_11, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_IPU, - }, - }, - .tx = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_10, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_IN_FLOATING, - }, - }, + // Receiver port pins + // S3-S6 inputs are used as outputs in this case + TIM_SERVO_CHANNEL_CONFIG(TIM3, 3, B, 0, 0), + TIM_SERVO_CHANNEL_CONFIG(TIM3, 4, B, 1, 0), + TIM_SERVO_CHANNEL_CONFIG(TIM2, 1, A, 0, 0), + TIM_SERVO_CHANNEL_CONFIG(TIM2, 2, A, 1, 0), }; -#endif /* PIOS_INCLUDE_IBUS */ +static const struct pios_tim_channel pios_tim_ppm_flexi_port = TIM_SERVO_CHANNEL_CONFIG(TIM2, 4, B, 11, GPIO_PartialRemap2_TIM2); -#if defined(PIOS_INCLUDE_SBUS) -/* - * S.Bus USART - */ -#include +#if defined(PIOS_INCLUDE_USART) -static const struct pios_usart_cfg pios_usart_sbus_main_cfg = { - .regs = USART1, - .init = { - .USART_BaudRate = 100000, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_Even, - .USART_StopBits = USART_StopBits_2, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART1_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { - .gpio = GPIOA, - .init = { - .GPIO_Pin = GPIO_Pin_10, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_IPU, - }, - }, - .tx = { - .gpio = GPIOA, - .init = { - .GPIO_Pin = GPIO_Pin_9, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_IN_FLOATING, - }, - }, -}; +#include "pios_usart_priv.h" -static const struct pios_sbus_cfg pios_sbus_cfg = { - /* Inverter configuration */ - .inv = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_2, - .GPIO_Mode = GPIO_Mode_Out_PP, - .GPIO_Speed = GPIO_Speed_2MHz, - }, - }, - .gpio_clk_func = RCC_APB2PeriphClockCmd, - .gpio_clk_periph = RCC_APB2Periph_GPIOB, - .gpio_inv_enable = Bit_SET, -}; +// Inverter for SBUS handling +#define MAIN_USART_INVERTER_GPIO GPIOB +#define MAIN_USART_INVERTER_PIN GPIO_Pin_2 +#define MAIN_USART_INVERTER_ENABLE Bit_SET +#define MAIN_USART_INVERTER_DISABLE Bit_RESET -#endif /* PIOS_INCLUDE_SBUS */ +static int32_t PIOS_BOARD_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param); -/* - * HK OSD - */ -static const struct pios_usart_cfg pios_usart_hkosd_main_cfg = { +static const struct pios_usart_cfg pios_usart_main_cfg = { .regs = USART1, - .init = { - .USART_BaudRate = 57600, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx | USART_Mode_Tx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART1_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, .rx = { .gpio = GPIOA, .init = { @@ -1291,26 +618,11 @@ static const struct pios_usart_cfg pios_usart_hkosd_main_cfg = { .GPIO_Mode = GPIO_Mode_AF_PP, }, }, + .ioctl = PIOS_BOARD_USART_Ioctl, }; -static const struct pios_usart_cfg pios_usart_hkosd_flexi_cfg = { +static const struct pios_usart_cfg pios_usart_flexi_cfg = { .regs = USART3, - .init = { - .USART_BaudRate = 57600, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx | USART_Mode_Tx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART3_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, .rx = { .gpio = GPIOB, .init = { @@ -1329,7 +641,6 @@ static const struct pios_usart_cfg pios_usart_hkosd_flexi_cfg = { }, }; - #endif /* PIOS_INCLUDE_USART */ #if defined(PIOS_INCLUDE_COM) @@ -1653,6 +964,23 @@ static const struct pios_usb_cfg pios_usb_main_cfg_cc3d = { .vsense_active_low = false }; +const struct pios_usb_cfg *PIOS_BOARD_HW_DEFS_GetUsbCfg(uint32_t board_revision) +{ + switch (board_revision) { + case BOARD_REVISION_CC: + return &pios_usb_main_cfg_cc; + + break; + case BOARD_REVISION_CC3D: + return &pios_usb_main_cfg_cc3d; + + break; + default: + PIOS_DEBUG_Assert(0); + } + return NULL; +} + #include "pios_usb_board_data_priv.h" #include "pios_usb_desc_hid_cdc_priv.h" #include "pios_usb_desc_hid_only_priv.h" @@ -1665,36 +993,60 @@ static const struct pios_usb_cfg pios_usb_main_cfg_cc3d = { #endif /* PIOS_INCLUDE_COM_MSG */ -#if defined(PIOS_INCLUDE_USB_HID) -#include - -const struct pios_usb_hid_cfg pios_usb_hid_cfg = { - .data_if = 2, - .data_rx_ep = 1, - .data_tx_ep = 1, +/** + * Configuration for MPU6000 chip + */ +#if defined(PIOS_INCLUDE_MPU6000) +#include "pios_mpu6000.h" +#include "pios_mpu6000_config.h" +static const struct pios_exti_cfg pios_exti_mpu6000_cfg __exti_config = { + .vector = PIOS_MPU6000_IRQHandler, + .line = EXTI_Line3, + .pin = { + .gpio = GPIOA, + .init = { + .GPIO_Pin = GPIO_Pin_3, + .GPIO_Speed = GPIO_Speed_10MHz, + .GPIO_Mode = GPIO_Mode_IN_FLOATING, + }, + }, + .irq = { + .init = { + .NVIC_IRQChannel = EXTI3_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, + .exti = { + .init = { + .EXTI_Line = EXTI_Line3, // matches above GPIO pin + .EXTI_Mode = EXTI_Mode_Interrupt, + .EXTI_Trigger = EXTI_Trigger_Rising, + .EXTI_LineCmd = ENABLE, + }, + }, }; -#endif /* PIOS_INCLUDE_USB_HID */ - -#if defined(PIOS_INCLUDE_USB_RCTX) -#include - -const struct pios_usb_rctx_cfg pios_usb_rctx_cfg = { - .data_if = 2, - .data_tx_ep = 1, +static const struct pios_mpu6000_cfg pios_mpu6000_cfg = { + .exti_cfg = &pios_exti_mpu6000_cfg, + .Fifo_store = PIOS_MPU6000_FIFO_TEMP_OUT | PIOS_MPU6000_FIFO_GYRO_X_OUT | PIOS_MPU6000_FIFO_GYRO_Y_OUT | PIOS_MPU6000_FIFO_GYRO_Z_OUT, + // Clock at 8 khz, downsampled by 8 for 1000 Hz + .Smpl_rate_div_no_dlp = 7, + // Clock at 1 khz, downsampled by 1 for 1000 Hz + .Smpl_rate_div_dlp = 0, + .interrupt_cfg = PIOS_MPU6000_INT_CLR_ANYRD, + .interrupt_en = PIOS_MPU6000_INTEN_DATA_RDY, + .User_ctl = PIOS_MPU6000_USERCTL_DIS_I2C, + .Pwr_mgmt_clk = PIOS_MPU6000_PWRMGMT_PLL_X_CLK, + .accel_range = PIOS_MPU6000_ACCEL_8G, + .gyro_range = PIOS_MPU6000_SCALE_2000_DEG, + .filter = PIOS_MPU6000_LOWPASS_256_HZ, + .orientation = PIOS_MPU6000_TOP_180DEG, + .fast_prescaler = PIOS_SPI_PRESCALER_4, + .std_prescaler = PIOS_SPI_PRESCALER_64, + .max_downsample = 2 }; +#endif /* PIOS_INCLUDE_MPU6000 */ -#endif /* PIOS_INCLUDE_USB_RCTX */ - -#if defined(PIOS_INCLUDE_USB_CDC) -#include -const struct pios_usb_cdc_cfg pios_usb_cdc_cfg = { - .ctrl_if = 0, - .ctrl_tx_ep = 2, - - .data_if = 1, - .data_rx_ep = 3, - .data_tx_ep = 3, -}; -#endif /* PIOS_INCLUDE_USB_CDC */ diff --git a/flight/targets/boards/coptercontrol/bootloader/main.c b/flight/targets/boards/coptercontrol/bootloader/main.c index 20549d1fa0..3495976df3 100644 --- a/flight/targets/boards/coptercontrol/bootloader/main.c +++ b/flight/targets/boards/coptercontrol/bootloader/main.c @@ -34,6 +34,7 @@ #include #include #include +#include extern void FLASH_Download(); #define BSL_HOLD_STATE ((PIOS_USB_DETECT_GPIO_PORT->IDR & PIOS_USB_DETECT_GPIO_PIN) ? 0 : 1) diff --git a/flight/targets/boards/coptercontrol/bootloader/pios_board.c b/flight/targets/boards/coptercontrol/bootloader/pios_board.c index 4fd27d5ee3..dda9fa5f59 100644 --- a/flight/targets/boards/coptercontrol/bootloader/pios_board.c +++ b/flight/targets/boards/coptercontrol/bootloader/pios_board.c @@ -44,6 +44,14 @@ uint32_t pios_com_telem_usb_id; * called from System/openpilot.c */ static bool board_init_complete = false; + +#if defined(PIOS_INCLUDE_USART) +static int32_t PIOS_BOARD_USART_Ioctl(__attribute__((unused)) uint32_t usart_id, __attribute__((unused)) uint32_t ctl, __attribute__((unused)) void *param) +{ + return -1; +} +#endif + void PIOS_Board_Init(void) { if (board_init_complete) { @@ -84,7 +92,7 @@ void PIOS_Board_Init(void) } #if defined(PIOS_INCLUDE_USB_HID) && defined(PIOS_INCLUDE_COM_MSG) uint32_t pios_usb_hid_id; - if (PIOS_USB_HID_Init(&pios_usb_hid_id, &pios_usb_hid_cfg, pios_usb_id)) { + if (PIOS_USB_HID_Init(&pios_usb_hid_id, &pios_usb_hid_only_cfg, pios_usb_id)) { PIOS_Assert(0); } if (PIOS_COM_MSG_Init(&pios_com_telem_usb_id, &pios_usb_hid_com_driver, pios_usb_hid_id)) { diff --git a/flight/targets/boards/coptercontrol/firmware/pios_board.c b/flight/targets/boards/coptercontrol/firmware/pios_board.c index 7556dff228..fdc6f517f3 100644 --- a/flight/targets/boards/coptercontrol/firmware/pios_board.c +++ b/flight/targets/boards/coptercontrol/firmware/pios_board.c @@ -30,12 +30,11 @@ #include #include #include -#include -#include #include #include #include + #ifdef PIOS_INCLUDE_INSTRUMENTATION #include #endif @@ -43,6 +42,8 @@ #include #endif +#include + /* * Pull in the board-specific static HW definitions. * Including .c files is a bit ugly but this allows all of @@ -53,185 +54,59 @@ */ #include "../board_hw_defs.c" -/* One slot per selectable receiver group. - * eg. PWM, PPM, GCS, DSMMAINPORT, DSMFLEXIPORT, SBUS - * NOTE: No slot in this map for NONE. - */ -uint32_t pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_NONE]; - static SystemAlarmsExtendedAlarmStatusOptions CopterControlConfigHook(); static void ActuatorSettingsUpdatedCb(UAVObjEvent *ev); -#define PIOS_COM_TELEM_RF_RX_BUF_LEN 32 -#define PIOS_COM_TELEM_RF_TX_BUF_LEN 12 - -#define PIOS_COM_GPS_RX_BUF_LEN 32 - -#define PIOS_COM_TELEM_USB_RX_BUF_LEN 65 -#define PIOS_COM_TELEM_USB_TX_BUF_LEN 65 - -#define PIOS_COM_BRIDGE_RX_BUF_LEN 65 -#define PIOS_COM_BRIDGE_TX_BUF_LEN 12 - -#define PIOS_COM_HKOSD_TX_BUF_LEN 22 - -#define PIOS_COM_MSP_TX_BUF_LEN 128 -#define PIOS_COM_MSP_RX_BUF_LEN 64 - -#define PIOS_COM_MAVLINK_TX_BUF_LEN 128 - -#if defined(PIOS_INCLUDE_DEBUG_CONSOLE) -#define PIOS_COM_DEBUGCONSOLE_TX_BUF_LEN 40 -uint32_t pios_com_debug_id; -#endif /* PIOS_INCLUDE_DEBUG_CONSOLE */ - -uint32_t pios_com_telem_rf_id; -uint32_t pios_com_telem_usb_id; -uint32_t pios_com_vcp_id; -uint32_t pios_com_gps_id; -uint32_t pios_com_bridge_id; -uint32_t pios_com_hkosd_id; -uint32_t pios_com_msp_id; -uint32_t pios_com_mavlink_id; -uint32_t pios_usb_rctx_id; - uintptr_t pios_uavo_settings_fs_id; uintptr_t pios_user_fs_id = 0; +static const PIOS_BOARD_IO_UART_Function main_function_map[] = { + [HWSETTINGS_CC_MAINPORT_TELEMETRY] = PIOS_BOARD_IO_UART_TELEMETRY, + [HWSETTINGS_CC_MAINPORT_GPS] = PIOS_BOARD_IO_UART_GPS, + [HWSETTINGS_CC_MAINPORT_SBUS] = PIOS_BOARD_IO_UART_SBUS, + [HWSETTINGS_CC_MAINPORT_DSM] = PIOS_BOARD_IO_UART_DSM_MAIN, + [HWSETTINGS_CC_MAINPORT_DEBUGCONSOLE] = PIOS_BOARD_IO_UART_DEBUGCONSOLE, + [HWSETTINGS_CC_MAINPORT_COMBRIDGE] = PIOS_BOARD_IO_UART_COMBRIDGE, + [HWSETTINGS_CC_MAINPORT_OSDHK] = PIOS_BOARD_IO_UART_OSDHK, + [HWSETTINGS_CC_MAINPORT_MSP] = PIOS_BOARD_IO_UART_MSP, + [HWSETTINGS_CC_MAINPORT_MAVLINK] = PIOS_BOARD_IO_UART_MAVLINK, +}; -/* - * Setup a com port based on the passed cfg, driver and buffer sizes. - * tx size = 0 make the port rx only - * rx size = 0 make the port tx only - * having both tx and rx size = 0 is not valid and will fail further down in PIOS_COM_Init() - */ -static void PIOS_Board_configure_com(const struct pios_usart_cfg *usart_port_cfg, uint16_t rx_buf_len, uint16_t tx_buf_len, - const struct pios_com_driver *com_driver, uint32_t *pios_com_id) -{ - uint32_t pios_usart_id; - - if (PIOS_USART_Init(&pios_usart_id, usart_port_cfg)) { - PIOS_Assert(0); - } - - uint8_t *rx_buffer = 0, *tx_buffer = 0; - - if (rx_buf_len > 0) { - rx_buffer = (uint8_t *)pios_malloc(rx_buf_len); - PIOS_Assert(rx_buffer); - } - - if (tx_buf_len > 0) { - tx_buffer = (uint8_t *)pios_malloc(tx_buf_len); - PIOS_Assert(tx_buffer); - } - - if (PIOS_COM_Init(pios_com_id, com_driver, pios_usart_id, - rx_buffer, rx_buf_len, - tx_buffer, tx_buf_len)) { - PIOS_Assert(0); - } -} - -static void PIOS_Board_configure_dsm(const struct pios_usart_cfg *pios_usart_dsm_cfg, const struct pios_dsm_cfg *pios_dsm_cfg, - const struct pios_com_driver *usart_com_driver, - ManualControlSettingsChannelGroupsOptions channelgroup, uint8_t *bind) -{ - uint32_t pios_usart_dsm_id; - - if (PIOS_USART_Init(&pios_usart_dsm_id, pios_usart_dsm_cfg)) { - PIOS_Assert(0); - } - - uint32_t pios_dsm_id; - if (PIOS_DSM_Init(&pios_dsm_id, pios_dsm_cfg, usart_com_driver, - pios_usart_dsm_id, *bind)) { - PIOS_Assert(0); - } - - uint32_t pios_dsm_rcvr_id; - if (PIOS_RCVR_Init(&pios_dsm_rcvr_id, &pios_dsm_rcvr_driver, pios_dsm_id)) { - PIOS_Assert(0); - } - pios_rcvr_group_map[channelgroup] = pios_dsm_rcvr_id; -} +static const PIOS_BOARD_IO_UART_Function flexi_function_map[] = { + [HWSETTINGS_CC_FLEXIPORT_TELEMETRY] = PIOS_BOARD_IO_UART_TELEMETRY, + [HWSETTINGS_CC_FLEXIPORT_GPS] = PIOS_BOARD_IO_UART_GPS, + [HWSETTINGS_CC_FLEXIPORT_DSM] = PIOS_BOARD_IO_UART_DSM_FLEXI, + [HWSETTINGS_CC_FLEXIPORT_EXBUS] = PIOS_BOARD_IO_UART_EXBUS, + [HWSETTINGS_CC_FLEXIPORT_HOTTSUMD] = PIOS_BOARD_IO_UART_HOTT_SUMD, + [HWSETTINGS_CC_FLEXIPORT_HOTTSUMH] = PIOS_BOARD_IO_UART_HOTT_SUMH, + [HWSETTINGS_CC_FLEXIPORT_SRXL] = PIOS_BOARD_IO_UART_SRXL, + [HWSETTINGS_CC_FLEXIPORT_IBUS] = PIOS_BOARD_IO_UART_IBUS, + [HWSETTINGS_CC_FLEXIPORT_DEBUGCONSOLE] = PIOS_BOARD_IO_UART_DEBUGCONSOLE, + [HWSETTINGS_CC_FLEXIPORT_COMBRIDGE] = PIOS_BOARD_IO_UART_COMBRIDGE, + [HWSETTINGS_CC_FLEXIPORT_OSDHK] = PIOS_BOARD_IO_UART_OSDHK, + [HWSETTINGS_CC_FLEXIPORT_MSP] = PIOS_BOARD_IO_UART_MSP, + [HWSETTINGS_CC_FLEXIPORT_MAVLINK] = PIOS_BOARD_IO_UART_MAVLINK, +}; -static void PIOS_Board_configure_ibus(const struct pios_usart_cfg *usart_cfg) +int32_t PIOS_BOARD_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param) { - uint32_t pios_usart_ibus_id; - - if (PIOS_USART_Init(&pios_usart_ibus_id, usart_cfg)) { - PIOS_Assert(0); - } - - uint32_t pios_ibus_id; - if (PIOS_IBUS_Init(&pios_ibus_id, &pios_usart_com_driver, pios_usart_ibus_id)) { - PIOS_Assert(0); - } - - uint32_t pios_ibus_rcvr_id; - if (PIOS_RCVR_Init(&pios_ibus_rcvr_id, &pios_ibus_rcvr_driver, pios_ibus_id)) { - PIOS_Assert(0); + const struct pios_usart_cfg *usart_cfg = PIOS_USART_GetConfig(usart_id); + + switch (ctl) { + case PIOS_IOCTL_USART_SET_INVERTED: + if (usart_cfg->regs == pios_usart_main_cfg.regs) { /* main port */ + GPIO_WriteBit(MAIN_USART_INVERTER_GPIO, + MAIN_USART_INVERTER_PIN, + (*(enum PIOS_USART_Inverted *)param & PIOS_USART_Inverted_Rx) ? MAIN_USART_INVERTER_ENABLE : MAIN_USART_INVERTER_DISABLE); + + return 0; + } + break; } - - pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_IBUS] = pios_ibus_rcvr_id; + + return -1; } -/** - * Configuration for MPU6000 chip - */ -#if defined(PIOS_INCLUDE_MPU6000) -#include "pios_mpu6000.h" -#include "pios_mpu6000_config.h" -static const struct pios_exti_cfg pios_exti_mpu6000_cfg __exti_config = { - .vector = PIOS_MPU6000_IRQHandler, - .line = EXTI_Line3, - .pin = { - .gpio = GPIOA, - .init = { - .GPIO_Pin = GPIO_Pin_3, - .GPIO_Speed = GPIO_Speed_10MHz, - .GPIO_Mode = GPIO_Mode_IN_FLOATING, - }, - }, - .irq = { - .init = { - .NVIC_IRQChannel = EXTI3_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .exti = { - .init = { - .EXTI_Line = EXTI_Line3, // matches above GPIO pin - .EXTI_Mode = EXTI_Mode_Interrupt, - .EXTI_Trigger = EXTI_Trigger_Rising, - .EXTI_LineCmd = ENABLE, - }, - }, -}; - -static const struct pios_mpu6000_cfg pios_mpu6000_cfg = { - .exti_cfg = &pios_exti_mpu6000_cfg, - .Fifo_store = PIOS_MPU6000_FIFO_TEMP_OUT | PIOS_MPU6000_FIFO_GYRO_X_OUT | PIOS_MPU6000_FIFO_GYRO_Y_OUT | PIOS_MPU6000_FIFO_GYRO_Z_OUT, - // Clock at 8 khz, downsampled by 8 for 1000 Hz - .Smpl_rate_div_no_dlp = 7, - // Clock at 1 khz, downsampled by 1 for 1000 Hz - .Smpl_rate_div_dlp = 0, - .interrupt_cfg = PIOS_MPU6000_INT_CLR_ANYRD, - .interrupt_en = PIOS_MPU6000_INTEN_DATA_RDY, - .User_ctl = PIOS_MPU6000_USERCTL_DIS_I2C, - .Pwr_mgmt_clk = PIOS_MPU6000_PWRMGMT_PLL_X_CLK, - .accel_range = PIOS_MPU6000_ACCEL_8G, - .gyro_range = PIOS_MPU6000_SCALE_2000_DEG, - .filter = PIOS_MPU6000_LOWPASS_256_HZ, - .orientation = PIOS_MPU6000_TOP_180DEG, - .fast_prescaler = PIOS_SPI_PRESCALER_4, - .std_prescaler = PIOS_SPI_PRESCALER_64, - .max_downsample = 2 -}; -#endif /* PIOS_INCLUDE_MPU6000 */ /** * PIOS_Board_Init() @@ -352,368 +227,53 @@ void PIOS_Board_Init(void) PIOS_TIM_InitClock(&tim_4_cfg); #if defined(PIOS_INCLUDE_USB) - /* Initialize board specific USB data */ - PIOS_USB_BOARD_DATA_Init(); - - - /* Flags to determine if various USB interfaces are advertised */ - bool usb_hid_present = false; - bool usb_cdc_present = false; - -#if defined(PIOS_INCLUDE_USB_CDC) - if (PIOS_USB_DESC_HID_CDC_Init()) { - PIOS_Assert(0); - } - usb_hid_present = true; - usb_cdc_present = true; -#else - if (PIOS_USB_DESC_HID_ONLY_Init()) { - PIOS_Assert(0); - } - usb_hid_present = true; + PIOS_BOARD_IO_Configure_USB(); #endif - uint32_t pios_usb_id; - - switch (bdinfo->board_rev) { - case BOARD_REVISION_CC: - PIOS_USB_Init(&pios_usb_id, &pios_usb_main_cfg_cc); - break; - case BOARD_REVISION_CC3D: - PIOS_USB_Init(&pios_usb_id, &pios_usb_main_cfg_cc3d); - break; - default: - PIOS_Assert(0); - } - -#if defined(PIOS_INCLUDE_USB_CDC) - - uint8_t hwsettings_usb_vcpport; - /* Configure the USB VCP port */ - HwSettingsUSB_VCPPortGet(&hwsettings_usb_vcpport); - - if (!usb_cdc_present) { - /* Force VCP port function to disabled if we haven't advertised VCP in our USB descriptor */ - hwsettings_usb_vcpport = HWSETTINGS_USB_VCPPORT_DISABLED; + /* Configure FlexiPort */ + uint8_t hwsettings_flexiport; + HwSettingsCC_FlexiPortGet(&hwsettings_flexiport); + + if (hwsettings_flexiport < NELEMENTS(flexi_function_map)) { + PIOS_BOARD_IO_Configure_UART(&pios_usart_flexi_cfg, flexi_function_map[hwsettings_flexiport]); } - switch (hwsettings_usb_vcpport) { - case HWSETTINGS_USB_VCPPORT_DISABLED: - break; - case HWSETTINGS_USB_VCPPORT_USBTELEMETRY: -#if defined(PIOS_INCLUDE_COM) - { - uint32_t pios_usb_cdc_id; - if (PIOS_USB_CDC_Init(&pios_usb_cdc_id, &pios_usb_cdc_cfg, pios_usb_id)) { - PIOS_Assert(0); - } - uint8_t *rx_buffer = (uint8_t *)pios_malloc(PIOS_COM_TELEM_USB_RX_BUF_LEN); - uint8_t *tx_buffer = (uint8_t *)pios_malloc(PIOS_COM_TELEM_USB_TX_BUF_LEN); - PIOS_Assert(rx_buffer); - PIOS_Assert(tx_buffer); - if (PIOS_COM_Init(&pios_com_telem_usb_id, &pios_usb_cdc_com_driver, pios_usb_cdc_id, - rx_buffer, PIOS_COM_TELEM_USB_RX_BUF_LEN, - tx_buffer, PIOS_COM_TELEM_USB_TX_BUF_LEN)) { - PIOS_Assert(0); - } - } -#endif /* PIOS_INCLUDE_COM */ - break; - case HWSETTINGS_USB_VCPPORT_COMBRIDGE: -#if defined(PIOS_INCLUDE_COM) - { - uint32_t pios_usb_cdc_id; - if (PIOS_USB_CDC_Init(&pios_usb_cdc_id, &pios_usb_cdc_cfg, pios_usb_id)) { - PIOS_Assert(0); - } - uint8_t *rx_buffer = (uint8_t *)pios_malloc(PIOS_COM_BRIDGE_RX_BUF_LEN); - uint8_t *tx_buffer = (uint8_t *)pios_malloc(PIOS_COM_BRIDGE_TX_BUF_LEN); - PIOS_Assert(rx_buffer); - PIOS_Assert(tx_buffer); - if (PIOS_COM_Init(&pios_com_vcp_id, &pios_usb_cdc_com_driver, pios_usb_cdc_id, - rx_buffer, PIOS_COM_BRIDGE_RX_BUF_LEN, - tx_buffer, PIOS_COM_BRIDGE_TX_BUF_LEN)) { - PIOS_Assert(0); - } - } -#endif /* PIOS_INCLUDE_COM */ - break; - case HWSETTINGS_USB_VCPPORT_DEBUGCONSOLE: -#if defined(PIOS_INCLUDE_COM) -#if defined(PIOS_INCLUDE_DEBUG_CONSOLE) - { - uint32_t pios_usb_cdc_id; - if (PIOS_USB_CDC_Init(&pios_usb_cdc_id, &pios_usb_cdc_cfg, pios_usb_id)) { - PIOS_Assert(0); - } - uint8_t *tx_buffer = (uint8_t *)pios_malloc(PIOS_COM_DEBUGCONSOLE_TX_BUF_LEN); - PIOS_Assert(tx_buffer); - if (PIOS_COM_Init(&pios_com_debug_id, &pios_usb_cdc_com_driver, pios_usb_cdc_id, - NULL, 0, - tx_buffer, PIOS_COM_DEBUGCONSOLE_TX_BUF_LEN)) { - PIOS_Assert(0); - } - } -#endif /* PIOS_INCLUDE_DEBUG_CONSOLE */ -#endif /* PIOS_INCLUDE_COM */ - break; - } -#endif /* PIOS_INCLUDE_USB_CDC */ - -#if defined(PIOS_INCLUDE_USB_HID) - /* Configure the usb HID port */ - uint8_t hwsettings_usb_hidport; - HwSettingsUSB_HIDPortGet(&hwsettings_usb_hidport); - - if (!usb_hid_present) { - /* Force HID port function to disabled if we haven't advertised HID in our USB descriptor */ - hwsettings_usb_hidport = HWSETTINGS_USB_HIDPORT_DISABLED; - } - - switch (hwsettings_usb_hidport) { - case HWSETTINGS_USB_HIDPORT_DISABLED: - break; - case HWSETTINGS_USB_HIDPORT_USBTELEMETRY: -#if defined(PIOS_INCLUDE_COM) - { - uint32_t pios_usb_hid_id; - if (PIOS_USB_HID_Init(&pios_usb_hid_id, &pios_usb_hid_cfg, pios_usb_id)) { - PIOS_Assert(0); - } - uint8_t *rx_buffer = (uint8_t *)pios_malloc(PIOS_COM_TELEM_USB_RX_BUF_LEN); - uint8_t *tx_buffer = (uint8_t *)pios_malloc(PIOS_COM_TELEM_USB_TX_BUF_LEN); - PIOS_Assert(rx_buffer); - PIOS_Assert(tx_buffer); - if (PIOS_COM_Init(&pios_com_telem_usb_id, &pios_usb_hid_com_driver, pios_usb_hid_id, - rx_buffer, PIOS_COM_TELEM_USB_RX_BUF_LEN, - tx_buffer, PIOS_COM_TELEM_USB_TX_BUF_LEN)) { - PIOS_Assert(0); - } - } -#endif /* PIOS_INCLUDE_COM */ - break; - case HWSETTINGS_USB_HIDPORT_RCTRANSMITTER: -#if defined(PIOS_INCLUDE_USB_RCTX) - { - if (PIOS_USB_RCTX_Init(&pios_usb_rctx_id, &pios_usb_rctx_cfg, pios_usb_id)) { - PIOS_Assert(0); - } - } -#endif /* PIOS_INCLUDE_USB_RCTX */ - break; - } - -#endif /* PIOS_INCLUDE_USB_HID */ - -#endif /* PIOS_INCLUDE_USB */ - - /* Configure the main IO port */ - uint8_t hwsettings_DSMxBind; - HwSettingsDSMxBindGet(&hwsettings_DSMxBind); - uint8_t hwsettings_cc_mainport; - HwSettingsCC_MainPortGet(&hwsettings_cc_mainport); - - switch (hwsettings_cc_mainport) { - case HWSETTINGS_CC_MAINPORT_DISABLED: - break; - case HWSETTINGS_CC_MAINPORT_TELEMETRY: -#if defined(PIOS_INCLUDE_TELEMETRY_RF) - PIOS_Board_configure_com(&pios_usart_generic_main_cfg, PIOS_COM_TELEM_RF_RX_BUF_LEN, PIOS_COM_TELEM_RF_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_telem_rf_id); -#endif /* PIOS_INCLUDE_TELEMETRY_RF */ - break; - case HWSETTINGS_CC_MAINPORT_SBUS: -#if defined(PIOS_INCLUDE_SBUS) - { - uint32_t pios_usart_sbus_id; - if (PIOS_USART_Init(&pios_usart_sbus_id, &pios_usart_sbus_main_cfg)) { - PIOS_Assert(0); - } - - uint32_t pios_sbus_id; - if (PIOS_SBus_Init(&pios_sbus_id, &pios_sbus_cfg, &pios_usart_com_driver, pios_usart_sbus_id)) { - PIOS_Assert(0); - } - - uint32_t pios_sbus_rcvr_id; - if (PIOS_RCVR_Init(&pios_sbus_rcvr_id, &pios_sbus_rcvr_driver, pios_sbus_id)) { - PIOS_Assert(0); - } - pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_SBUS] = pios_sbus_rcvr_id; - } -#endif /* PIOS_INCLUDE_SBUS */ - break; - case HWSETTINGS_CC_MAINPORT_GPS: -#if defined(PIOS_INCLUDE_GPS) - PIOS_Board_configure_com(&pios_usart_generic_main_cfg, PIOS_COM_GPS_RX_BUF_LEN, 0, &pios_usart_com_driver, &pios_com_gps_id); -#endif /* PIOS_INCLUDE_GPS */ - break; - case HWSETTINGS_CC_MAINPORT_DSM: -#if defined(PIOS_INCLUDE_DSM) - PIOS_Board_configure_dsm(&pios_usart_dsm_main_cfg, &pios_dsm_main_cfg, - &pios_usart_com_driver, MANUALCONTROLSETTINGS_CHANNELGROUPS_DSMMAINPORT, &hwsettings_DSMxBind); -#endif /* PIOS_INCLUDE_DSM */ - break; - case HWSETTINGS_CC_MAINPORT_DEBUGCONSOLE: -#if defined(PIOS_INCLUDE_COM) -#if defined(PIOS_INCLUDE_DEBUG_CONSOLE) - PIOS_Board_configure_com(&pios_usart_generic_main_cfg, 0, PIOS_COM_DEBUGCONSOLE_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_debug_id); -#endif /* PIOS_INCLUDE_DEBUG_CONSOLE */ -#endif /* PIOS_INCLUDE_COM */ - break; - case HWSETTINGS_CC_MAINPORT_COMBRIDGE: - PIOS_Board_configure_com(&pios_usart_generic_main_cfg, PIOS_COM_BRIDGE_RX_BUF_LEN, PIOS_COM_BRIDGE_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_bridge_id); - break; - case HWSETTINGS_CC_MAINPORT_MSP: - PIOS_Board_configure_com(&pios_usart_generic_main_cfg, PIOS_COM_MSP_RX_BUF_LEN, PIOS_COM_MSP_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_msp_id); - break; - case HWSETTINGS_CC_MAINPORT_MAVLINK: - PIOS_Board_configure_com(&pios_usart_generic_main_cfg, 0, PIOS_COM_MAVLINK_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_mavlink_id); - break; - case HWSETTINGS_CC_MAINPORT_OSDHK: - PIOS_Board_configure_com(&pios_usart_hkosd_main_cfg, 0, PIOS_COM_HKOSD_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_hkosd_id); - break; - } - - /* Configure the flexi port */ - uint8_t hwsettings_cc_flexiport; - HwSettingsCC_FlexiPortGet(&hwsettings_cc_flexiport); - - switch (hwsettings_cc_flexiport) { - case HWSETTINGS_CC_FLEXIPORT_DISABLED: - break; - case HWSETTINGS_CC_FLEXIPORT_TELEMETRY: -#if defined(PIOS_INCLUDE_TELEMETRY_RF) - PIOS_Board_configure_com(&pios_usart_generic_flexi_cfg, PIOS_COM_TELEM_RF_RX_BUF_LEN, PIOS_COM_TELEM_RF_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_telem_rf_id); -#endif /* PIOS_INCLUDE_TELEMETRY_RF */ - break; - case HWSETTINGS_CC_FLEXIPORT_COMBRIDGE: - PIOS_Board_configure_com(&pios_usart_generic_flexi_cfg, PIOS_COM_BRIDGE_RX_BUF_LEN, PIOS_COM_BRIDGE_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_bridge_id); - break; - case HWSETTINGS_CC_FLEXIPORT_MSP: - PIOS_Board_configure_com(&pios_usart_generic_flexi_cfg, PIOS_COM_MSP_RX_BUF_LEN, PIOS_COM_MSP_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_msp_id); - break; - case HWSETTINGS_CC_FLEXIPORT_MAVLINK: - PIOS_Board_configure_com(&pios_usart_generic_flexi_cfg, 0, PIOS_COM_MAVLINK_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_mavlink_id); - break; - case HWSETTINGS_CC_FLEXIPORT_GPS: -#if defined(PIOS_INCLUDE_GPS) - PIOS_Board_configure_com(&pios_usart_generic_flexi_cfg, PIOS_COM_GPS_RX_BUF_LEN, 0, &pios_usart_com_driver, &pios_com_gps_id); -#endif /* PIOS_INCLUDE_GPS */ - break; - case HWSETTINGS_CC_FLEXIPORT_PPM: -#if defined(PIOS_INCLUDE_PPM_FLEXI) - { - uint32_t pios_ppm_id; - PIOS_PPM_Init(&pios_ppm_id, &pios_ppm_flexi_cfg); - - uint32_t pios_ppm_rcvr_id; - if (PIOS_RCVR_Init(&pios_ppm_rcvr_id, &pios_ppm_rcvr_driver, pios_ppm_id)) { - PIOS_Assert(0); - } - pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_PPM] = pios_ppm_rcvr_id; - } -#endif /* PIOS_INCLUDE_PPM_FLEXI */ - break; - case HWSETTINGS_CC_FLEXIPORT_DSM: -#if defined(PIOS_INCLUDE_DSM) - PIOS_Board_configure_dsm(&pios_usart_dsm_flexi_cfg, &pios_dsm_flexi_cfg, - &pios_usart_com_driver, MANUALCONTROLSETTINGS_CHANNELGROUPS_DSMFLEXIPORT, &hwsettings_DSMxBind); -#endif /* PIOS_INCLUDE_DSM */ - break; - - case HWSETTINGS_CC_FLEXIPORT_HOTTSUMD: - case HWSETTINGS_CC_FLEXIPORT_HOTTSUMH: -#if defined(PIOS_INCLUDE_HOTT) - { - uint32_t pios_usart_hott_id; - if (PIOS_USART_Init(&pios_usart_hott_id, &pios_usart_hott_flexi_cfg)) { - PIOS_Assert(0); - } - - uint32_t pios_hott_id; - if (PIOS_HOTT_Init(&pios_hott_id, &pios_usart_com_driver, pios_usart_hott_id, - hwsettings_cc_flexiport == HWSETTINGS_CC_FLEXIPORT_HOTTSUMD ? PIOS_HOTT_PROTO_SUMD : PIOS_HOTT_PROTO_SUMH)) { - PIOS_Assert(0); - } - - uint32_t pios_hott_rcvr_id; - if (PIOS_RCVR_Init(&pios_hott_rcvr_id, &pios_hott_rcvr_driver, pios_hott_id)) { - PIOS_Assert(0); - } - pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_HOTT] = pios_hott_rcvr_id; - } -#endif /* PIOS_INCLUDE_HOTT */ - break; - - case HWSETTINGS_CC_FLEXIPORT_EXBUS: -#if defined(PIOS_INCLUDE_EXBUS) - { - uint32_t pios_usart_exbus_id; - if (PIOS_USART_Init(&pios_usart_exbus_id, &pios_usart_exbus_flexi_cfg)) { - PIOS_Assert(0); - } - - uint32_t pios_exbus_id; - if (PIOS_EXBUS_Init(&pios_exbus_id, &pios_usart_com_driver, pios_usart_exbus_id)) { - PIOS_Assert(0); - } - - uint32_t pios_exbus_rcvr_id; - if (PIOS_RCVR_Init(&pios_exbus_rcvr_id, &pios_exbus_rcvr_driver, pios_exbus_id)) { - PIOS_Assert(0); - } - pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_EXBUS] = pios_exbus_rcvr_id; - } -#endif /* PIOS_INCLUDE_EXBUS */ - break; - - case HWSETTINGS_CC_FLEXIPORT_SRXL: -#if defined(PIOS_INCLUDE_SRXL) - { - uint32_t pios_usart_srxl_id; - if (PIOS_USART_Init(&pios_usart_srxl_id, &pios_usart_srxl_flexi_cfg)) { - PIOS_Assert(0); - } - - uint32_t pios_srxl_id; - if (PIOS_SRXL_Init(&pios_srxl_id, &pios_usart_com_driver, pios_usart_srxl_id)) { - PIOS_Assert(0); - } - - uint32_t pios_srxl_rcvr_id; - if (PIOS_RCVR_Init(&pios_srxl_rcvr_id, &pios_srxl_rcvr_driver, pios_srxl_id)) { - PIOS_Assert(0); - } - pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_SRXL] = pios_srxl_rcvr_id; - } -#endif /* PIOS_INCLUDE_SRXL */ - break; - - case HWSETTINGS_CC_FLEXIPORT_IBUS: -#if defined(PIOS_INCLUDE_IBUS) - PIOS_Board_configure_ibus(&pios_usart_ibus_flexi_cfg); -#endif /* PIOS_INCLUDE_IBUS */ - break; - - case HWSETTINGS_CC_FLEXIPORT_DEBUGCONSOLE: -#if defined(PIOS_INCLUDE_COM) -#if defined(PIOS_INCLUDE_DEBUG_CONSOLE) - PIOS_Board_configure_com(&pios_usart_generic_flexi_cfg, 0, PIOS_COM_DEBUGCONSOLE_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_debug_id); -#endif /* PIOS_INCLUDE_DEBUG_CONSOLE */ -#endif /* PIOS_INCLUDE_COM */ - break; - case HWSETTINGS_CC_FLEXIPORT_I2C: + switch(hwsettings_flexiport) { + case HWSETTINGS_CC_FLEXIPORT_I2C: #if defined(PIOS_INCLUDE_I2C) - { if (PIOS_I2C_Init(&pios_i2c_flexi_adapter_id, &pios_i2c_flexi_adapter_cfg)) { PIOS_Assert(0); } - } #endif /* PIOS_INCLUDE_I2C */ - break; - case HWSETTINGS_CC_FLEXIPORT_OSDHK: - PIOS_Board_configure_com(&pios_usart_hkosd_flexi_cfg, 0, PIOS_COM_HKOSD_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_hkosd_id); - break; + break; + case HWSETTINGS_CC_FLEXIPORT_PPM: +#if defined(PIOS_INCLUDE_PPM_FLEXI) + PIOS_BOARD_IO_Configure_PPM(&pios_ppm_flexi_cfg); +#endif /* PIOS_INCLUDE_PPM_FLEXI */ + break; + } + + /* Configure main USART port */ + + /* Initialize inverter gpio and set it to off */ + { + GPIO_InitTypeDef inverterGPIOInit = { + .GPIO_Pin = MAIN_USART_INVERTER_PIN, + .GPIO_Mode = GPIO_Mode_Out_PP, + .GPIO_Speed = GPIO_Speed_2MHz, + }; + + GPIO_Init(MAIN_USART_INVERTER_GPIO, &inverterGPIOInit); + GPIO_WriteBit(MAIN_USART_INVERTER_GPIO, + MAIN_USART_INVERTER_PIN, + MAIN_USART_INVERTER_DISABLE); + } + + uint8_t hwsettings_mainport; + HwSettingsCC_MainPortGet(&hwsettings_mainport); + + if (hwsettings_mainport < NELEMENTS(main_function_map)) { + PIOS_BOARD_IO_Configure_UART(&pios_usart_main_cfg, main_function_map[hwsettings_mainport]); } /* Configure the rcvr port */ @@ -731,79 +291,32 @@ void PIOS_Board_Init(void) break; case HWSETTINGS_CC_RCVRPORT_PWMNOONESHOT: #if defined(PIOS_INCLUDE_PWM) - { - uint32_t pios_pwm_id; - PIOS_PWM_Init(&pios_pwm_id, &pios_pwm_cfg); - - uint32_t pios_pwm_rcvr_id; - if (PIOS_RCVR_Init(&pios_pwm_rcvr_id, &pios_pwm_rcvr_driver, pios_pwm_id)) { - PIOS_Assert(0); - } - pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_PWM] = pios_pwm_rcvr_id; - } + PIOS_BOARD_IO_Configure_PWM(&pios_pwm_cfg); #endif /* PIOS_INCLUDE_PWM */ break; case HWSETTINGS_CC_RCVRPORT_PPMNOONESHOT: case HWSETTINGS_CC_RCVRPORT_PPMOUTPUTSNOONESHOT: case HWSETTINGS_CC_RCVRPORT_PPM_PIN8ONESHOT: #if defined(PIOS_INCLUDE_PPM) - { - uint32_t pios_ppm_id; - if (hwsettings_rcvrport == HWSETTINGS_CC_RCVRPORT_PPM_PIN8ONESHOT) { - PIOS_PPM_Init(&pios_ppm_id, &pios_ppm_pin8_cfg); - } else { - PIOS_PPM_Init(&pios_ppm_id, &pios_ppm_cfg); - } - - uint32_t pios_ppm_rcvr_id; - if (PIOS_RCVR_Init(&pios_ppm_rcvr_id, &pios_ppm_rcvr_driver, pios_ppm_id)) { - PIOS_Assert(0); - } - pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_PPM] = pios_ppm_rcvr_id; - } + PIOS_BOARD_IO_Configure_PPM((hwsettings_rcvrport == HWSETTINGS_CC_RCVRPORT_PPM_PIN8ONESHOT) ? &pios_ppm_pin8_cfg : &pios_ppm_cfg); #endif /* PIOS_INCLUDE_PPM */ break; case HWSETTINGS_CC_RCVRPORT_PPMPWMNOONESHOT: /* This is a combination of PPM and PWM inputs */ #if defined(PIOS_INCLUDE_PPM) - { - uint32_t pios_ppm_id; - PIOS_PPM_Init(&pios_ppm_id, &pios_ppm_cfg); - - uint32_t pios_ppm_rcvr_id; - if (PIOS_RCVR_Init(&pios_ppm_rcvr_id, &pios_ppm_rcvr_driver, pios_ppm_id)) { - PIOS_Assert(0); - } - pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_PPM] = pios_ppm_rcvr_id; - } + PIOS_BOARD_IO_Configure_PPM(&pios_ppm_cfg); #endif /* PIOS_INCLUDE_PPM */ #if defined(PIOS_INCLUDE_PWM) - { - uint32_t pios_pwm_id; - PIOS_PWM_Init(&pios_pwm_id, &pios_pwm_with_ppm_cfg); - - uint32_t pios_pwm_rcvr_id; - if (PIOS_RCVR_Init(&pios_pwm_rcvr_id, &pios_pwm_rcvr_driver, pios_pwm_id)) { - PIOS_Assert(0); - } - pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_PWM] = pios_pwm_rcvr_id; - } + PIOS_BOARD_IO_Configure_PWM(&pios_pwm_with_ppm_cfg); #endif /* PIOS_INCLUDE_PWM */ break; case HWSETTINGS_CC_RCVRPORT_OUTPUTSONESHOT: break; } -#if defined(PIOS_INCLUDE_GCSRCVR) - GCSReceiverInitialize(); - uint32_t pios_gcsrcvr_id; - PIOS_GCSRCVR_Init(&pios_gcsrcvr_id); - uint32_t pios_gcsrcvr_rcvr_id; - if (PIOS_RCVR_Init(&pios_gcsrcvr_rcvr_id, &pios_gcsrcvr_rcvr_driver, pios_gcsrcvr_id)) { - PIOS_Assert(0); - } - pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_GCS] = pios_gcsrcvr_rcvr_id; -#endif /* PIOS_INCLUDE_GCSRCVR */ +#ifdef PIOS_INCLUDE_GCSRCVR + PIOS_BOARD_IO_Configure_GCSRCVR(); +#endif /* Remap AFIO pin for PB4 (Servo 5 Out)*/ GPIO_PinRemapConfig(GPIO_Remap_SWJ_NoJTRST, ENABLE); diff --git a/flight/targets/boards/coptercontrol/pios_board.h b/flight/targets/boards/coptercontrol/pios_board.h index 54e7d2fc89..f01fe9cc81 100644 --- a/flight/targets/boards/coptercontrol/pios_board.h +++ b/flight/targets/boards/coptercontrol/pios_board.h @@ -130,36 +130,25 @@ extern uint32_t pios_i2c_flexi_adapter_id; // ------------------------- #define PIOS_COM_MAX_DEVS 3 -extern uint32_t pios_com_telem_rf_id; -#define PIOS_COM_TELEM_RF (pios_com_telem_rf_id) +#define PIOS_COM_TELEM_RF_RX_BUF_LEN 32 +#define PIOS_COM_TELEM_RF_TX_BUF_LEN 12 -#if defined(PIOS_INCLUDE_GPS) -extern uint32_t pios_com_gps_id; -#define PIOS_COM_GPS (pios_com_gps_id) -#endif /* PIOS_INCLUDE_GPS */ +#define PIOS_COM_GPS_RX_BUF_LEN 32 -extern uint32_t pios_com_bridge_id; -#define PIOS_COM_BRIDGE (pios_com_bridge_id) +#define PIOS_COM_TELEM_USB_RX_BUF_LEN 65 +#define PIOS_COM_TELEM_USB_TX_BUF_LEN 65 -extern uint32_t pios_com_vcp_id; -#define PIOS_COM_VCP (pios_com_vcp_id) +#define PIOS_COM_BRIDGE_RX_BUF_LEN 65 +#define PIOS_COM_BRIDGE_TX_BUF_LEN 12 -extern uint32_t pios_com_telem_usb_id; -#define PIOS_COM_TELEM_USB (pios_com_telem_usb_id) +#define PIOS_COM_HKOSD_TX_BUF_LEN 22 -#if defined(PIOS_INCLUDE_DEBUG_CONSOLE) -extern uint32_t pios_com_debug_id; -#define PIOS_COM_DEBUG (pios_com_debug_id) -#endif /* PIOS_INCLUDE_DEBUG_CONSOLE */ +#define PIOS_COM_MSP_TX_BUF_LEN 128 +#define PIOS_COM_MSP_RX_BUF_LEN 64 -extern uint32_t pios_com_hkosd_id; -#define PIOS_COM_OSDHK (pios_com_hkosd_id) +#define PIOS_COM_MAVLINK_TX_BUF_LEN 128 -extern uint32_t pios_com_msp_id; -#define PIOS_COM_MSP (pios_com_msp_id) - -extern uint32_t pios_com_mavlink_id; -#define PIOS_COM_MAVLINK (pios_com_mavlink_id) +#define PIOS_COM_DEBUGCONSOLE_TX_BUF_LEN 40 // ------------------------- // ADC diff --git a/flight/targets/boards/discoveryf4bare/pios_board.h b/flight/targets/boards/discoveryf4bare/pios_board.h index a6373ccd39..4b129899d5 100644 --- a/flight/targets/boards/discoveryf4bare/pios_board.h +++ b/flight/targets/boards/discoveryf4bare/pios_board.h @@ -122,34 +122,6 @@ extern uint32_t pios_i2c_flexiport_adapter_id; // See also pios_board.c // ------------------------- #define PIOS_COM_MAX_DEVS 4 -extern uint32_t pios_com_telem_rf_id; -extern uint32_t pios_com_gps_id; -extern uint32_t pios_com_telem_usb_id; -extern uint32_t pios_com_bridge_id; -extern uint32_t pios_com_vcp_id; -extern uint32_t pios_com_hkosd_id; -extern uint32_t pios_com_msp_id; -extern uint32_t pios_com_mavlink_id; - -#define PIOS_COM_GPS (pios_com_gps_id) -#define PIOS_COM_TELEM_USB (pios_com_telem_usb_id) -#define PIOS_COM_TELEM_RF (pios_com_telem_rf_id) -#define PIOS_COM_BRIDGE (pios_com_bridge_id) -#define PIOS_COM_VCP (pios_com_vcp_id) -#define PIOS_COM_OSDHK (pios_com_hkosd_id) -#define PIOS_COM_MSP (pios_com_msp_id) -#define PIOS_COM_MAVLINK (pios_com_mavlink_id) - -#if defined(PIOS_INCLUDE_DEBUG_CONSOLE) -extern uint32_t pios_com_debug_id; -#define PIOS_COM_DEBUG (pios_com_debug_id) -#endif /* PIOS_INCLUDE_DEBUG_CONSOLE */ - -#if defined(PIOS_INCLUDE_RFM22B) -extern uint32_t pios_rfm22b_id; -extern uint32_t pios_spi_telem_flash_id; -#define PIOS_RFM22_SPI_PORT (pios_spi_telem_flash_id) -#endif /* PIOS_INCLUDE_RFM22B */ // ------------------------- // Packet Handler diff --git a/flight/targets/boards/revolution/pios_board.h b/flight/targets/boards/revolution/pios_board.h index fb0f469e81..122cdb71f6 100644 --- a/flight/targets/boards/revolution/pios_board.h +++ b/flight/targets/boards/revolution/pios_board.h @@ -141,38 +141,6 @@ extern uint32_t pios_i2c_flexiport_adapter_id; // See also pios_board.c // ------------------------- #define PIOS_COM_MAX_DEVS 4 -extern uint32_t pios_com_telem_rf_id; -extern uint32_t pios_com_rf_id; -extern uint32_t pios_com_gps_id; -extern uint32_t pios_com_telem_usb_id; -extern uint32_t pios_com_bridge_id; -extern uint32_t pios_com_hott_id; -extern uint32_t pios_com_vcp_id; -extern uint32_t pios_com_hkosd_id; -extern uint32_t pios_com_msp_id; -extern uint32_t pios_com_mavlink_id; - -#define PIOS_COM_GPS (pios_com_gps_id) -#define PIOS_COM_TELEM_USB (pios_com_telem_usb_id) -#define PIOS_COM_TELEM_RF (pios_com_telem_rf_id) -#define PIOS_COM_RF (pios_com_rf_id) -#define PIOS_COM_BRIDGE (pios_com_bridge_id) -#define PIOS_COM_HOTT (pios_com_hott_id) -#define PIOS_COM_VCP (pios_com_vcp_id) -#define PIOS_COM_OSDHK (pios_com_hkosd_id) -#define PIOS_COM_MSP (pios_com_msp_id) -#define PIOS_COM_MAVLINK (pios_com_mavlink_id) - -#if defined(PIOS_INCLUDE_DEBUG_CONSOLE) -extern uint32_t pios_com_debug_id; -#define PIOS_COM_DEBUG (pios_com_debug_id) -#endif /* PIOS_INCLUDE_DEBUG_CONSOLE */ - -#if defined(PIOS_INCLUDE_RFM22B) -extern uint32_t pios_rfm22b_id; -extern uint32_t pios_spi_telem_flash_id; -#define PIOS_RFM22_SPI_PORT (pios_spi_telem_flash_id) -#endif /* PIOS_INCLUDE_RFM22B */ // ------------------------- // Packet Handler diff --git a/flight/targets/boards/revonano/pios_board.h b/flight/targets/boards/revonano/pios_board.h index 43c55959c3..5e1909dfde 100644 --- a/flight/targets/boards/revonano/pios_board.h +++ b/flight/targets/boards/revonano/pios_board.h @@ -141,37 +141,6 @@ extern uint32_t pios_i2c_flexiport_adapter_id; // See also pios_board.c // ------------------------- #define PIOS_COM_MAX_DEVS 4 -extern uint32_t pios_com_telem_rf_id; -extern uint32_t pios_com_rf_id; -extern uint32_t pios_com_gps_id; -extern uint32_t pios_com_telem_usb_id; -extern uint32_t pios_com_bridge_id; -extern uint32_t pios_com_vcp_id; -extern uint32_t pios_com_hkosd_id; -extern uint32_t pios_com_msp_id; -extern uint32_t pios_com_mavlink_id; - -#define PIOS_COM_GPS (pios_com_gps_id) -#define PIOS_COM_TELEM_USB (pios_com_telem_usb_id) -#define PIOS_COM_TELEM_RF (pios_com_telem_rf_id) -#define PIOS_COM_RF (pios_com_rf_id) -#define PIOS_COM_BRIDGE (pios_com_bridge_id) -#define PIOS_COM_VCP (pios_com_vcp_id) -#define PIOS_COM_OSDHK (pios_com_hkosd_id) -#define PIOS_COM_MSP (pios_com_msp_id) -#define PIOS_COM_MAVLINK (pios_com_mavlink_id) - -#if defined(PIOS_INCLUDE_DEBUG_CONSOLE) -extern uint32_t pios_com_debug_id; -#define PIOS_COM_DEBUG (pios_com_debug_id) -#endif /* PIOS_INCLUDE_DEBUG_CONSOLE */ - -#if defined(PIOS_INCLUDE_RFM22B) -extern uint32_t pios_rfm22b_id; -extern uint32_t pios_spi_telem_flash_id; -#define PIOS_RFM22_SPI_PORT (pios_spi_telem_flash_id) -#endif /* PIOS_INCLUDE_RFM22B */ - // ------------------------- // Packet Handler // ------------------------- diff --git a/flight/targets/boards/sparky2/pios_board.h b/flight/targets/boards/sparky2/pios_board.h index 63986b0fb8..37fe24a121 100644 --- a/flight/targets/boards/sparky2/pios_board.h +++ b/flight/targets/boards/sparky2/pios_board.h @@ -143,36 +143,6 @@ extern uint32_t pios_i2c_flexiport_adapter_id; // See also pios_board.c // ------------------------- #define PIOS_COM_MAX_DEVS 4 -extern uint32_t pios_com_telem_rf_id; -extern uint32_t pios_com_rf_id; -extern uint32_t pios_com_gps_id; -extern uint32_t pios_com_telem_usb_id; -extern uint32_t pios_com_bridge_id; -extern uint32_t pios_com_vcp_id; -extern uint32_t pios_com_hkosd_id; -extern uint32_t pios_com_msp_id; -extern uint32_t pios_com_mavlink_id; - -#define PIOS_COM_GPS (pios_com_gps_id) -#define PIOS_COM_TELEM_USB (pios_com_telem_usb_id) -#define PIOS_COM_TELEM_RF (pios_com_telem_rf_id) -#define PIOS_COM_RF (pios_com_rf_id) -#define PIOS_COM_BRIDGE (pios_com_bridge_id) -#define PIOS_COM_VCP (pios_com_vcp_id) -#define PIOS_COM_OSDHK (pios_com_hkosd_id) -#define PIOS_COM_MSP (pios_com_msp_id) -#define PIOS_COM_MAVLINK (pios_com_mavlink_id) - -#if defined(PIOS_INCLUDE_DEBUG_CONSOLE) -extern uint32_t pios_com_debug_id; -#define PIOS_COM_DEBUG (pios_com_debug_id) -#endif /* PIOS_INCLUDE_DEBUG_CONSOLE */ - -#if defined(PIOS_INCLUDE_RFM22B) -extern uint32_t pios_rfm22b_id; -extern uint32_t pios_spi_telem_flash_id; -#define PIOS_RFM22_SPI_PORT (pios_spi_telem_flash_id) -#endif /* PIOS_INCLUDE_RFM22B */ // ------------------------- // Packet Handler From 5cebebe33b0eabbe3eba8902725bbce5df14760e Mon Sep 17 00:00:00 2001 From: Vladimir Zidar Date: Tue, 21 Feb 2017 18:48:00 +0100 Subject: [PATCH 215/624] LP-480 More work in progress. --- flight/modules/System/systemmod.c | 2 +- flight/pios/common/pios_board_io.c | 82 ++++++++++--------- flight/pios/common/pios_usb_desc_hid_cdc.c | 3 +- flight/pios/inc/pios_board_io.h | 31 ++++++- flight/pios/inc/pios_usb_desc_hid_cdc_priv.h | 6 +- .../discoveryf4bare/firmware/pios_board.c | 12 ++- .../targets/boards/oplinkmini/board_hw_defs.c | 55 ------------- .../boards/revolution/firmware/pios_board.c | 13 ++- .../boards/sparky2/firmware/pios_board.c | 13 ++- shared/uavobjectdefinition/hwsettings.xml | 2 +- 10 files changed, 114 insertions(+), 105 deletions(-) diff --git a/flight/modules/System/systemmod.c b/flight/modules/System/systemmod.c index a4d87975b9..fb59876be5 100644 --- a/flight/modules/System/systemmod.c +++ b/flight/modules/System/systemmod.c @@ -62,7 +62,7 @@ #include #include #include - +#include #ifdef PIOS_INCLUDE_INSTRUMENTATION #include diff --git a/flight/pios/common/pios_board_io.c b/flight/pios/common/pios_board_io.c index 7b742b7581..7fa5c327e2 100644 --- a/flight/pios/common/pios_board_io.c +++ b/flight/pios/common/pios_board_io.c @@ -354,6 +354,17 @@ static const struct uart_function uart_function_map[] = { .com_rx_buf_len = PIOS_COM_HKOSD_RX_BUF_LEN, .com_tx_buf_len = PIOS_COM_HKOSD_TX_BUF_LEN, }, +#ifdef PIOS_INCLUDE_DEBUG_CONSOLE + [PIOS_BOARD_IO_UART_DEBUGCONSOLE] = { + .com_id = &pios_com_debug_id, + .com_tx_buf_len = PIOS_COM_DEBUGCONSOLE_TX_BUF_LEN, + }, +#endif + [PIOS_BOARD_IO_UART_COMBRIDGE] = { + .com_id = &pios_com_bridge_id, + .com_rx_buf_len = PIOS_COM_BRIDGE_RX_BUF_LEN, + .com_tx_buf_len = PIOS_COM_BRIDGE_TX_BUF_LEN, + }, #ifdef PIOS_INCLUDE_RCVR # ifdef PIOS_INCLUDE_IBUS [PIOS_BOARD_IO_UART_IBUS] = { @@ -505,19 +516,7 @@ void PIOS_BOARD_IO_Configure_GCSRCVR() #ifdef PIOS_INCLUDE_RFM22B -#if defined(PIOS_INCLUDE_OPLINKRCVR) && defined(PIOS_INCLUDE_RCVR) -static void PIOS_Board_PPM_callback(const int16_t *channels) -{ - OPLinkReceiverData opl_rcvr; - - for (uint8_t i = 0; i < OPLINKRECEIVER_CHANNEL_NUMELEM; ++i) { - opl_rcvr.Channel[i] = (i < RFM22B_PPM_NUM_CHANNELS) ? channels[i] : PIOS_RCVR_TIMEOUT; - } - OPLinkReceiverSet(&opl_rcvr); -} -#endif /* PIOS_INCLUDE_OPLINKRCVR && PIOS_INCLUDE_RCVR */ - -void PIOS_BOARD_IO_Configure_RFM22B() +void PIOS_BOARD_IO_Configure_RFM22B(uint32_t spi_id, PIOS_BOARD_IO_RADIOAUX_Function radioaux_function) { #if defined(PIOS_INCLUDE_RFM22B) OPLinkSettingsInitialize(); @@ -547,7 +546,6 @@ void PIOS_BOARD_IO_Configure_RFM22B() (oplinkSettings.LinkType == OPLINKSETTINGS_LINKTYPE_DATAANDCONTROL)); bool ppm_mode = ((oplinkSettings.LinkType == OPLINKSETTINGS_LINKTYPE_CONTROL) || (oplinkSettings.LinkType == OPLINKSETTINGS_LINKTYPE_DATAANDCONTROL)); - bool ppm_only = (oplinkSettings.LinkType == OPLINKSETTINGS_LINKTYPE_CONTROL); bool is_enabled = ((oplinkSettings.Protocol != OPLINKSETTINGS_PROTOCOL_DISABLED) && ((oplinkSettings.MaxRFPower != OPLINKSETTINGS_MAXRFPOWER_0) || openlrs)); if (is_enabled) { @@ -556,22 +554,22 @@ void PIOS_BOARD_IO_Configure_RFM22B() uint32_t openlrs_id; const struct pios_openlrs_cfg *openlrs_cfg = PIOS_BOARD_HW_DEFS_GetOpenLRSCfg(pios_board_info_blob.board_rev); - PIOS_OpenLRS_Init(&openlrs_id, PIOS_RFM22_SPI_PORT, 0, openlrs_cfg); - { - uint32_t openlrsrcvr_id; - PIOS_OpenLRS_Rcvr_Init(&openlrsrcvr_id, openlrs_id); - uint32_t openlrsrcvr_rcvr_id; - if (PIOS_RCVR_Init(&openlrsrcvr_rcvr_id, &pios_openlrs_rcvr_driver, openlrsrcvr_id)) { - PIOS_Assert(0); - } - pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_OPENLRS] = openlrsrcvr_rcvr_id; + uint32_t openlrs_id; + PIOS_OpenLRS_Init(&openlrs_id, spi_id, 0, openlrs_cfg); + + uint32_t openlrsrcvr_id; + PIOS_OpenLRS_Rcvr_Init(&openlrsrcvr_id, openlrs_id); + + uint32_t openlrsrcvr_rcvr_id; + if (PIOS_RCVR_Init(&openlrsrcvr_rcvr_id, &pios_openlrs_rcvr_driver, openlrsrcvr_id)) { + PIOS_Assert(0); } #endif /* PIOS_INCLUDE_OPENLRS_RCVR && PIOS_INCLUDE_RCVR */ } else { /* Configure the RFM22B device. */ const struct pios_rfm22b_cfg *rfm22b_cfg = PIOS_BOARD_HW_DEFS_GetRfm22Cfg(pios_board_info_blob.board_rev); - if (PIOS_RFM22B_Init(&pios_rfm22b_id, PIOS_RFM22_SPI_PORT, rfm22b_cfg->slave_num, rfm22b_cfg, oplinkSettings.RFBand)) { + if (PIOS_RFM22B_Init(&pios_rfm22b_id, spi_id, rfm22b_cfg->slave_num, rfm22b_cfg, oplinkSettings.RFBand)) { PIOS_Assert(0); } @@ -622,12 +620,6 @@ void PIOS_BOARD_IO_Configure_RFM22B() PIOS_RFM22B_SetXtalCap(pios_rfm22b_id, oplinkSettings.RFXtalCap); PIOS_RFM22B_SetChannelConfig(pios_rfm22b_id, datarate, oplinkSettings.MinChannel, oplinkSettings.MaxChannel, is_coordinator, data_mode, ppm_mode); -#if defined(PIOS_INCLUDE_OPLINKRCVR) && defined(PIOS_INCLUDE_RCVR) - /* Set the PPM callback if we should be receiving PPM. */ - if (ppm_mode || (ppm_only && !is_coordinator)) { - PIOS_RFM22B_SetPPMCallback(pios_rfm22b_id, PIOS_Board_PPM_callback); - } -#endif /* Set the modem Tx power level */ switch (oplinkSettings.MaxRFPower) { case OPLINKSETTINGS_MAXRFPOWER_125: @@ -665,22 +657,32 @@ void PIOS_BOARD_IO_Configure_RFM22B() // TODO: this is in preparation for full mavlink support and is used by LP-368 uint16_t mavlink_rx_size = PIOS_COM_MAVLINK_RX_BUF_LEN; - uint8_t hwsettings_radioaux; - HwSettingsRadioAuxStreamGet(&hwsettings_radioaux); - - switch (hwsettings_radioaux) { - case HWSETTINGS_RADIOAUXSTREAM_DEBUGCONSOLE: - case HWSETTINGS_RADIOAUXSTREAM_DISABLED: - break; - case HWSETTINGS_RADIOAUXSTREAM_MAVLINK: - { + switch (radioaux_function) { + default: ; + case PIOS_BOARD_IO_RADIOAUX_DEBUGCONSOLE: +#ifdef PIOS_INCLUDE_DEBUG_CONSOLE + if (PIOS_COM_Init(&pios_com_debug_id, &pios_rfm22b_aux_com_driver, pios_rfm22b_id, + 0, 0, + 0, PIOS_COM_DEBUGCONSOLE_TX_BUF_LEN)) { + PIOS_Assert(0); + } +#endif + break; + case PIOS_BOARD_IO_RADIOAUX_COMBRIDGE: + if(PIOS_COM_Init(&pios_com_bridge_id, &pios_rfm22b_aux_com_driver, pios_rfm22b_id, + 0, PIOS_COM_BRIDGE_RX_BUF_LEN, + 0, PIOS_COM_BRIDGE_TX_BUF_LEN)) + { + PIOS_Assert(0); + } + break; + case PIOS_BOARD_IO_RADIOAUX_MAVLINK: if (PIOS_COM_Init(&pios_com_mavlink_id, &pios_rfm22b_aux_com_driver, pios_rfm22b_id, 0, mavlink_rx_size, 0, PIOS_COM_BRIDGE_TX_BUF_LEN)) { PIOS_Assert(0); } } - } } } else { oplinkStatus.LinkState = OPLINKSTATUS_LINKSTATE_DISABLED; diff --git a/flight/pios/common/pios_usb_desc_hid_cdc.c b/flight/pios/common/pios_usb_desc_hid_cdc.c index 14bb69f61d..255bf6dce4 100644 --- a/flight/pios/common/pios_usb_desc_hid_cdc.c +++ b/flight/pios/common/pios_usb_desc_hid_cdc.c @@ -331,11 +331,12 @@ const struct pios_usb_hid_cfg pios_usb_hid_cfg = { .data_rx_ep = 1, .data_tx_ep = 1, }; - +#ifdef PIOS_INCLUDE_USB_RCTX const struct pios_usb_rctx_cfg pios_usb_rctx_cfg = { .data_if = 2, .data_tx_ep = 1, }; +#endif int32_t PIOS_USB_DESC_HID_CDC_Init(void) { diff --git a/flight/pios/inc/pios_board_io.h b/flight/pios/inc/pios_board_io.h index bbcd5c2cc6..6b374deba0 100644 --- a/flight/pios/inc/pios_board_io.h +++ b/flight/pios/inc/pios_board_io.h @@ -98,7 +98,8 @@ extern uint32_t pios_com_telem_rf_id; /* RFM22B telemetry */ #ifdef PIOS_INCLUDE_RFM22B -extern uint32_t pios_com_rf_id; +extern uint32_t pios_rfm22b_id; /* RFM22B handle */ +extern uint32_t pios_com_rf_id; /* oplink telemetry */ # define PIOS_COM_RF (pios_com_rf_id) # ifndef PIOS_COM_RFM22B_RF_RX_BUF_LEN # define PIOS_COM_RFM22B_RF_RX_BUF_LEN 512 @@ -179,10 +180,34 @@ typedef enum { PIOS_BOARD_IO_UART_SRXL, /* rcvr */ PIOS_BOARD_IO_UART_IBUS, /* rcvr */ PIOS_BOARD_IO_UART_EXBUS, /* rcvr */ +// PIOS_BOARD_IO_UART_FRSKY_SPORT_TELEMETRY, /* com */ } PIOS_BOARD_IO_UART_Function; +typedef enum { + PIOS_BOARD_IO_RADIOAUX_NONE, + PIOS_BOARD_IO_RADIOAUX_MAVLINK, + PIOS_BOARD_IO_RADIOAUX_COMBRIDGE, + PIOS_BOARD_IO_RADIOAUX_DEBUGCONSOLE, +// PIOS_BOARD_IO_RADIOAUX_FRSKY_SPORT_TELEMETRY, +} PIOS_BOARD_IO_RADIOAUX_Function; + +typedef enum { + PIOS_BOARD_IO_USB_HID_NONE, + PIOS_BOARD_IO_USB_HID_TELEMETRY, + PIOS_BOARD_IO_USB_HID_RCTX, +} PIOS_BOARD_IO_USB_HID_Function; + +typedef enum { + PIOS_BOARD_IO_USB_CDC_NONE, + PIOS_BOARD_IO_USB_CDC_TELEMETRY, + PIOS_BOARD_IO_USB_CDC_COMBRIDGE, + PIOS_BOARD_IO_USB_CDC_MAVLINK, + PIOS_BOARD_IO_USB_CDC_DEBUGCONSOLE, +// PIOS_BOARD_IO_USB_CDC_MSP, +} PIOS_BOARD_IO_USB_CDC_Function; + #ifdef PIOS_INCLUDE_USB -void PIOS_BOARD_IO_Configure_USB(); +void PIOS_BOARD_IO_Configure_USB(PIOS_BOARD_IO_USB_HID_Function hid_function, PIOS_BOARD_IO_USB_CDC_Function cdc_function); # if defined(PIOS_INCLUDE_USB_HID) # include extern const struct pios_usb_hid_cfg pios_usb_hid_cfg; @@ -198,7 +223,7 @@ void PIOS_BOARD_IO_Configure_PPM(const struct pios_ppm_cfg *ppm_cfg); void PIOS_BOARD_IO_Configure_UART(const struct pios_usart_cfg *usart_cfg, PIOS_BOARD_IO_UART_Function function); #ifdef PIOS_INCLUDE_RFM22B -void PIOS_BOARD_IO_Configure_RFM22B(); +void PIOS_BOARD_IO_Configure_RFM22B(uint32_t spi_id, PIOS_BOARD_IO_RADIOAUX_Function function); #endif #ifdef PIOS_INCLUDE_I2C diff --git a/flight/pios/inc/pios_usb_desc_hid_cdc_priv.h b/flight/pios/inc/pios_usb_desc_hid_cdc_priv.h index 77d3b23478..1ff5c12985 100644 --- a/flight/pios/inc/pios_usb_desc_hid_cdc_priv.h +++ b/flight/pios/inc/pios_usb_desc_hid_cdc_priv.h @@ -33,13 +33,17 @@ #include #include #include -#include +#ifdef PIOS_INCLUDE_USB_RCTX +# include +#endif extern int32_t PIOS_USB_DESC_HID_CDC_Init(void); extern const struct pios_usb_cdc_cfg pios_usb_cdc_cfg; extern const struct pios_usb_hid_cfg pios_usb_hid_cfg; +#ifdef PIOS_INCLUDE_USB_RCTX extern const struct pios_usb_rctx_cfg pios_usb_rctx_cfg; +#endif #endif /* PIOS_USB_DESC_HID_CDC_PRIV_H */ diff --git a/flight/targets/boards/discoveryf4bare/firmware/pios_board.c b/flight/targets/boards/discoveryf4bare/firmware/pios_board.c index bac459834c..7e8c49c521 100644 --- a/flight/targets/boards/discoveryf4bare/firmware/pios_board.c +++ b/flight/targets/boards/discoveryf4bare/firmware/pios_board.c @@ -98,6 +98,11 @@ static const PIOS_BOARD_IO_UART_Function flexi_function_map[] = { [HWSETTINGS_RM_FLEXIPORT_MAVLINK] = PIOS_BOARD_IO_UART_MAVLINK, }; +static const PIOS_BOARD_IO_RADIOAUX_Function radioaux_function_map[] = { + [HWSETTINGS_RADIOAUXSTREAM_DEBUGCONSOLE] = PIOS_BOARD_IO_RADIOAUX_DEBUGCONSOLE, + [HWSETTINGS_RADIOAUXSTREAM_MAVLINK] = PIOS_BOARD_IO_RADIOAUX_MAVLINK, + [HWSETTINGS_RADIOAUXSTREAM_COMBRIDGE] = PIOS_BOARD_IO_RADIOAUX_COMBRIDGE, +}; int32_t PIOS_BOARD_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param) { @@ -280,7 +285,12 @@ void PIOS_Board_Init(void) } #if defined(PIOS_INCLUDE_RFM22B) - PIOS_BOARD_IO_Configure_RFM22B(); + uint8_t hwsettings_radioaux; + HwSettingsRadioAuxStreamGet(&hwsettings_radioaux); + + if(hwsettings_radioaux < NELEMENTS(radioaux_function_map)) { + PIOS_BOARD_IO_Configure_RFM22B(pios_spi_telem_flash_id, radioaux_function_map[hwsettings_radioaux]); + } #endif /* PIOS_INCLUDE_RFM22B */ diff --git a/flight/targets/boards/oplinkmini/board_hw_defs.c b/flight/targets/boards/oplinkmini/board_hw_defs.c index 3dde19b94c..d05d3dbfbd 100644 --- a/flight/targets/boards/oplinkmini/board_hw_defs.c +++ b/flight/targets/boards/oplinkmini/board_hw_defs.c @@ -693,22 +693,6 @@ const struct pios_ppm_out_cfg pios_flexi_ppm_out_cfg = { */ static const struct pios_usart_cfg pios_usart_main_cfg = { .regs = USART1, - .init = { - .USART_BaudRate = 57600, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx | USART_Mode_Tx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART1_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, .rx = { .gpio = GPIOA, .init = { @@ -729,22 +713,6 @@ static const struct pios_usart_cfg pios_usart_main_cfg = { static const struct pios_usart_cfg pios_usart_flexi_cfg = { .regs = USART3, - .init = { - .USART_BaudRate = 57600, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx | USART_Mode_Tx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART3_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, .rx = { .gpio = GPIOB, .init = { @@ -839,29 +807,6 @@ static const struct pios_usb_cfg pios_usb_main_cfg = { #endif /* PIOS_INCLUDE_COM_MSG */ -#if defined(PIOS_INCLUDE_USB_HID) -#include - -const struct pios_usb_hid_cfg pios_usb_hid_cfg = { - .data_if = 2, - .data_rx_ep = 1, - .data_tx_ep = 1, -}; -#endif /* PIOS_INCLUDE_USB_HID */ - -#if defined(PIOS_INCLUDE_USB_CDC) -#include - -const struct pios_usb_cdc_cfg pios_usb_cdc_cfg = { - .ctrl_if = 0, - .ctrl_tx_ep = 2, - - .data_if = 1, - .data_rx_ep = 3, - .data_tx_ep = 3, -}; -#endif /* PIOS_INCLUDE_USB_CDC */ - #if defined(PIOS_INCLUDE_FLASH_EEPROM) #include diff --git a/flight/targets/boards/revolution/firmware/pios_board.c b/flight/targets/boards/revolution/firmware/pios_board.c index cc1f93ddf2..60bdfce814 100644 --- a/flight/targets/boards/revolution/firmware/pios_board.c +++ b/flight/targets/boards/revolution/firmware/pios_board.c @@ -97,6 +97,12 @@ static const PIOS_BOARD_IO_UART_Function flexi_function_map[] = { [HWSETTINGS_RM_FLEXIPORT_MAVLINK] = PIOS_BOARD_IO_UART_MAVLINK, }; +static const PIOS_BOARD_IO_RADIOAUX_Function radioaux_function_map[] = { + [HWSETTINGS_RADIOAUXSTREAM_DEBUGCONSOLE] = PIOS_BOARD_IO_RADIOAUX_DEBUGCONSOLE, + [HWSETTINGS_RADIOAUXSTREAM_MAVLINK] = PIOS_BOARD_IO_RADIOAUX_MAVLINK, + [HWSETTINGS_RADIOAUXSTREAM_COMBRIDGE] = PIOS_BOARD_IO_RADIOAUX_COMBRIDGE, +}; + int32_t PIOS_BOARD_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param) { @@ -282,7 +288,12 @@ void PIOS_Board_Init(void) } #if defined(PIOS_INCLUDE_RFM22B) - PIOS_BOARD_IO_Configure_RFM22B(); + uint8_t hwsettings_radioaux; + HwSettingsRadioAuxStreamGet(&hwsettings_radioaux); + + if(hwsettings_radioaux < NELEMENTS(radioaux_function_map)) { + PIOS_BOARD_IO_Configure_RFM22B(pios_spi_telem_flash_id, radioaux_function_map[hwsettings_radioaux]); + } #endif /* PIOS_INCLUDE_RFM22B */ #if defined(PIOS_INCLUDE_PWM) || defined(PIOS_INCLUDE_PPM) diff --git a/flight/targets/boards/sparky2/firmware/pios_board.c b/flight/targets/boards/sparky2/firmware/pios_board.c index 1c0561dcb7..28e232e366 100644 --- a/flight/targets/boards/sparky2/firmware/pios_board.c +++ b/flight/targets/boards/sparky2/firmware/pios_board.c @@ -93,6 +93,12 @@ static const PIOS_BOARD_IO_UART_Function flexi_function_map[] = { [HWSETTINGS_SPK2_FLEXIPORT_MAVLINK] = PIOS_BOARD_IO_UART_MAVLINK, }; +static const PIOS_BOARD_IO_RADIOAUX_Function radioaux_function_map[] = { + [HWSETTINGS_RADIOAUXSTREAM_DEBUGCONSOLE] = PIOS_BOARD_IO_RADIOAUX_DEBUGCONSOLE, + [HWSETTINGS_RADIOAUXSTREAM_MAVLINK] = PIOS_BOARD_IO_RADIOAUX_MAVLINK, + [HWSETTINGS_RADIOAUXSTREAM_COMBRIDGE] = PIOS_BOARD_IO_RADIOAUX_COMBRIDGE, +}; + int32_t PIOS_BOARD_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param) { const struct pios_usart_cfg *usart_cfg = PIOS_USART_GetConfig(usart_id); @@ -258,7 +264,12 @@ void PIOS_Board_Init(void) } #if defined(PIOS_INCLUDE_RFM22B) - PIOS_BOARD_IO_Configure_RFM22B(); + uint8_t hwsettings_radioaux; + HwSettingsRadioAuxStreamGet(&hwsettings_radioaux); + + if(hwsettings_radioaux < NELEMENTS(radioaux_function_map)) { + PIOS_BOARD_IO_Configure_RFM22B(pios_spi_telem_flash_id, radioaux_function_map[hwsettings_radioaux]); + } #endif /* PIOS_INCLUDE_RFM22B */ /* Initialize inverter gpio and set it to off */ diff --git a/shared/uavobjectdefinition/hwsettings.xml b/shared/uavobjectdefinition/hwsettings.xml index 6f74f84251..0f4aa1b75d 100644 --- a/shared/uavobjectdefinition/hwsettings.xml +++ b/shared/uavobjectdefinition/hwsettings.xml @@ -29,7 +29,7 @@ - + From c9f6ba55a0e68919378ee9ceb1fbe0697d8f576c Mon Sep 17 00:00:00 2001 From: Vladimir Zidar Date: Thu, 13 Apr 2017 15:12:40 +0200 Subject: [PATCH 216/624] LP-480 USB config cleanup. Coptercontrol & Revo tested. Booted. Usb functional. --- .../OpenPilotOSX.xcodeproj/project.pbxproj | 2 +- .../modules/UAVOHottBridge/uavohottbridge.c | 2 + flight/pios/common/pios_board_io.c | 160 ++++++++---------- flight/pios/inc/pios_board_io.h | 38 ++--- flight/pios/stm32f10x/pios_sys.c | 4 +- .../boards/coptercontrol/board_hw_defs.c | 10 -- .../coptercontrol/bootloader/pios_board.c | 4 + .../boards/revolution/bootloader/main.c | 1 + .../targets/boards/revonano/bootloader/main.c | 1 + 9 files changed, 98 insertions(+), 124 deletions(-) diff --git a/flight/Project/OpenPilotOSX/OpenPilotOSX.xcodeproj/project.pbxproj b/flight/Project/OpenPilotOSX/OpenPilotOSX.xcodeproj/project.pbxproj index 1bdc89da67..7e01ae919e 100644 --- a/flight/Project/OpenPilotOSX/OpenPilotOSX.xcodeproj/project.pbxproj +++ b/flight/Project/OpenPilotOSX/OpenPilotOSX.xcodeproj/project.pbxproj @@ -184,7 +184,7 @@ /* Begin PBXLegacyTarget section */ 6581071511DE809D0049FB12 /* OpenPilotOSX */ = { isa = PBXLegacyTarget; - buildArgumentsString = ef_coptercontrol; + buildArgumentsString = ef_revolution; buildConfigurationList = 6581071A11DE80A30049FB12 /* Build configuration list for PBXLegacyTarget "OpenPilotOSX" */; buildPhases = ( ); diff --git a/flight/modules/UAVOHottBridge/uavohottbridge.c b/flight/modules/UAVOHottBridge/uavohottbridge.c index 9342e0eabb..663045d088 100644 --- a/flight/modules/UAVOHottBridge/uavohottbridge.c +++ b/flight/modules/UAVOHottBridge/uavohottbridge.c @@ -55,6 +55,8 @@ #include "pios_sensors.h" #include "uavohottbridge.h" +#include "pios_board_io.h" + #if defined(PIOS_INCLUDE_HOTT_BRIDGE) #if defined(PIOS_HoTT_STACK_SIZE) diff --git a/flight/pios/common/pios_board_io.c b/flight/pios/common/pios_board_io.c index 7fa5c327e2..0848531fb3 100644 --- a/flight/pios/common/pios_board_io.c +++ b/flight/pios/common/pios_board_io.c @@ -105,6 +105,10 @@ uint32_t pios_com_vcp_id; /* USB VCP */ uint32_t pios_com_debug_id; /* DebugConsole */ #endif /* PIOS_INCLUDE_DEBUG_CONSOLE */ +#ifdef PIOS_INCLUDE_HOTT_BRIDGE +uint32_t pios_com_hott_id; +#endif + #ifdef PIOS_INCLUDE_USB uint32_t pios_com_telem_usb_id; /* USB telemetry */ @@ -134,105 +138,83 @@ pios_hmc5x83_dev_t pios_hmc5x83_internal_id; #endif /* PIOS_INCLUDE_COM_MSG */ +#if defined(PIOS_INCLUDE_USB_CDC) +static void PIOS_BOARD_IO_VCP_Init(uint32_t *com_id, uint16_t rx_buf_len, uint16_t tx_buf_len, uint32_t pios_usb_id) +{ +#if defined(PIOS_INCLUDE_COM) + uint32_t pios_usb_cdc_id = 0; + if (PIOS_USB_CDC_Init(&pios_usb_cdc_id, &pios_usb_cdc_cfg, pios_usb_id)) { + PIOS_Assert(0); + } + if (PIOS_COM_Init(com_id, &pios_usb_cdc_com_driver, pios_usb_cdc_id, + 0, rx_buf_len, /* Let Init() allocate this buffer */ + 0, tx_buf_len)) { /* Let Init() allocate this buffer */ + PIOS_Assert(0); + } +#endif /* PIOS_INCLUDE_COM */ +} +#endif + +static void PIOS_BOARD_IO_HID_Init(uint32_t *com_id, uint16_t rx_buf_len, uint16_t tx_buf_len, uint32_t pios_usb_id) +{ +#ifdef PIOS_INCLUDE_USB_CDC + const struct pios_usb_hid_cfg *hid_cfg = &pios_usb_hid_cfg; +#else + const struct pios_usb_hid_cfg *hid_cfg = &pios_usb_hid_only_cfg; +#endif + uint32_t pios_usb_hid_id; + if (PIOS_USB_HID_Init(&pios_usb_hid_id, hid_cfg, pios_usb_id)) { + PIOS_Assert(0); + } + + if (PIOS_COM_Init(com_id, &pios_usb_hid_com_driver, pios_usb_hid_id, + 0, rx_buf_len, /* Let Init() allocate this buffer */ + 0, tx_buf_len)) { /* Let Init() allocate this buffer */ + PIOS_Assert(0); + } +} + void PIOS_BOARD_IO_Configure_USB() { /* Initialize board specific USB data */ PIOS_USB_BOARD_DATA_Init(); - /* Flags to determine if various USB interfaces are advertised */ - bool usb_hid_present = false; - bool usb_cdc_present = false; + uint8_t hwsettings_usb_hidport; + HwSettingsUSB_HIDPortGet(&hwsettings_usb_hidport); #if defined(PIOS_INCLUDE_USB_CDC) + uint8_t hwsettings_usb_vcpport; + HwSettingsUSB_VCPPortGet(&hwsettings_usb_vcpport); + if (PIOS_USB_DESC_HID_CDC_Init()) { PIOS_Assert(0); } - usb_hid_present = true; - usb_cdc_present = true; #else if (PIOS_USB_DESC_HID_ONLY_Init()) { PIOS_Assert(0); } - usb_hid_present = true; #endif uint32_t pios_usb_id; PIOS_USB_Init(&pios_usb_id, PIOS_BOARD_HW_DEFS_GetUsbCfg(pios_board_info_blob.board_rev)); - uint8_t hwsettings_usb_vcpport; - uint8_t hwsettings_usb_hidport; - - HwSettingsUSB_VCPPortGet(&hwsettings_usb_vcpport); - HwSettingsUSB_HIDPortGet(&hwsettings_usb_hidport); - -#if defined(PIOS_INCLUDE_USB_CDC) - - if (!usb_cdc_present) { - /* Force VCP port function to disabled if we haven't advertised VCP in our USB descriptor */ - hwsettings_usb_vcpport = HWSETTINGS_USB_VCPPORT_DISABLED; - } - - if (!usb_hid_present) { - /* Force HID port function to disabled if we haven't advertised HID in our USB descriptor */ - hwsettings_usb_hidport = HWSETTINGS_USB_HIDPORT_DISABLED; - } - - /* Why do we need to init these if function is *NONE* ?? */ #if defined(PIOS_INCLUDE_USB_CDC) - uint32_t pios_usb_cdc_id; - if (PIOS_USB_CDC_Init(&pios_usb_cdc_id, &pios_usb_cdc_cfg, pios_usb_id)) { - PIOS_Assert(0); - } - - uint32_t pios_usb_hid_id; - if (PIOS_USB_HID_Init(&pios_usb_hid_id, &pios_usb_hid_cfg, pios_usb_id)) { - PIOS_Assert(0); - } -#else - uint32_t pios_usb_hid_id; - if (PIOS_USB_HID_Init(&pios_usb_hid_id, &pios_usb_hid_only_cfg, pios_usb_id)) { - PIOS_Assert(0); - } -#endif - switch (hwsettings_usb_vcpport) { case HWSETTINGS_USB_VCPPORT_DISABLED: break; case HWSETTINGS_USB_VCPPORT_USBTELEMETRY: -#if defined(PIOS_INCLUDE_COM) - if (PIOS_COM_Init(&pios_com_telem_usb_id, &pios_usb_cdc_com_driver, pios_usb_cdc_id, - 0, PIOS_COM_TELEM_USB_RX_BUF_LEN, /* Let Init() allocate this buffer */ - 0, PIOS_COM_TELEM_USB_TX_BUF_LEN)) { /* Let Init() allocate this buffer */ - PIOS_Assert(0); - } -#endif /* PIOS_INCLUDE_COM */ + PIOS_BOARD_IO_VCP_Init(&pios_com_telem_usb_id, PIOS_COM_TELEM_USB_RX_BUF_LEN, PIOS_COM_TELEM_USB_TX_BUF_LEN, pios_usb_id); break; case HWSETTINGS_USB_VCPPORT_COMBRIDGE: -#if defined(PIOS_INCLUDE_COM) - if (PIOS_COM_Init(&pios_com_vcp_id, &pios_usb_cdc_com_driver, pios_usb_cdc_id, - 0, PIOS_COM_BRIDGE_RX_BUF_LEN, /* Let Init() allocate this buffer */ - 0, PIOS_COM_BRIDGE_TX_BUF_LEN)) { /* Let Init() allocate this buffer */ - PIOS_Assert(0); - } -#endif /* PIOS_INCLUDE_COM */ + PIOS_BOARD_IO_VCP_Init(&pios_com_vcp_id, PIOS_COM_BRIDGE_RX_BUF_LEN, PIOS_COM_BRIDGE_TX_BUF_LEN, pios_usb_id); break; case HWSETTINGS_USB_VCPPORT_DEBUGCONSOLE: -#if defined(PIOS_INCLUDE_COM) #if defined(PIOS_INCLUDE_DEBUG_CONSOLE) - if (PIOS_COM_Init(&pios_com_debug_id, &pios_usb_cdc_com_driver, pios_usb_cdc_id, - 0, 0, /* No RX buffer */ - 0, PIOS_COM_BRIDGE_TX_BUF_LEN)) { /* Let Init() allocate this buffer */ - PIOS_Assert(0); - } + PIOS_BOARD_IO_VCP_Init(&pios_com_debug_id, 0, PIOS_COM_BRIDGE_TX_BUF_LEN, pios_usb_id); #endif /* PIOS_INCLUDE_DEBUG_CONSOLE */ -#endif /* PIOS_INCLUDE_COM */ break; case HWSETTINGS_USB_VCPPORT_MAVLINK: - if (PIOS_COM_Init(&pios_com_mavlink_id, &pios_usb_cdc_com_driver, pios_usb_cdc_id, - 0, PIOS_COM_MAVLINK_RX_BUF_LEN, /* Let Init() allocate this buffer */ - 0, PIOS_COM_MAVLINK_TX_BUF_LEN)) { /* Let Init() allocate this buffer */ - PIOS_Assert(0); - } + PIOS_BOARD_IO_VCP_Init(&pios_com_mavlink_id, PIOS_COM_MAVLINK_RX_BUF_LEN, PIOS_COM_MAVLINK_TX_BUF_LEN, pios_usb_id); break; } #endif /* PIOS_INCLUDE_USB_CDC */ @@ -244,19 +226,11 @@ void PIOS_BOARD_IO_Configure_USB() case HWSETTINGS_USB_HIDPORT_DISABLED: break; case HWSETTINGS_USB_HIDPORT_USBTELEMETRY: -#if defined(PIOS_INCLUDE_COM) - { - if (PIOS_COM_Init(&pios_com_telem_usb_id, &pios_usb_hid_com_driver, pios_usb_hid_id, - 0, PIOS_COM_TELEM_USB_RX_BUF_LEN, /* Let Init() allocate this buffer */ - 0, PIOS_COM_TELEM_USB_TX_BUF_LEN)) { /* Let Init() allocate this buffer */ - PIOS_Assert(0); - } - } -#endif /* PIOS_INCLUDE_COM */ + PIOS_BOARD_IO_HID_Init(&pios_com_telem_usb_id, PIOS_COM_TELEM_USB_RX_BUF_LEN, PIOS_COM_TELEM_USB_TX_BUF_LEN, pios_usb_id); break; case HWSETTINGS_USB_HIDPORT_RCTRANSMITTER: #if defined(PIOS_INCLUDE_USB_RCTX) - if (PIOS_USB_RCTX_Init(&pios_usb_rctx_id, &pios_usb_rctx_cfg, pios_usb_id)) { /* this will reinstall endpoint callbacks */ + if (PIOS_USB_RCTX_Init(&pios_usb_rctx_id, &pios_usb_rctx_cfg, pios_usb_id)) { PIOS_Assert(0); } #endif /* PIOS_INCLUDE_USB_RCTX */ @@ -266,9 +240,7 @@ void PIOS_BOARD_IO_Configure_USB() #endif /* PIOS_INCLUDE_USB_HID */ #ifndef STM32F10X - if (usb_hid_present || usb_cdc_present) { - PIOS_USBHOOK_Activate(); - } + PIOS_USBHOOK_Activate(); #endif } @@ -354,6 +326,13 @@ static const struct uart_function uart_function_map[] = { .com_rx_buf_len = PIOS_COM_HKOSD_RX_BUF_LEN, .com_tx_buf_len = PIOS_COM_HKOSD_TX_BUF_LEN, }, +#ifdef PIOS_INCLUDE_HOTT_BRIDGE + [PIOS_BOARD_IO_UART_HOTT_BRIDGE] = { + .com_id = &pios_com_hott_id, + .com_rx_buf_len = PIOS_COM_HOTT_BRIDGE_RX_BUF_LEN, + .com_tx_buf_len = PIOS_COM_HOTT_BRIDGE_TX_BUF_LEN, + }, +#endif #ifdef PIOS_INCLUDE_DEBUG_CONSOLE [PIOS_BOARD_IO_UART_DEBUGCONSOLE] = { .com_id = &pios_com_debug_id, @@ -554,7 +533,6 @@ void PIOS_BOARD_IO_Configure_RFM22B(uint32_t spi_id, PIOS_BOARD_IO_RADIOAUX_Func uint32_t openlrs_id; const struct pios_openlrs_cfg *openlrs_cfg = PIOS_BOARD_HW_DEFS_GetOpenLRSCfg(pios_board_info_blob.board_rev); - uint32_t openlrs_id; PIOS_OpenLRS_Init(&openlrs_id, spi_id, 0, openlrs_cfg); uint32_t openlrsrcvr_id; @@ -564,6 +542,7 @@ void PIOS_BOARD_IO_Configure_RFM22B(uint32_t spi_id, PIOS_BOARD_IO_RADIOAUX_Func if (PIOS_RCVR_Init(&openlrsrcvr_rcvr_id, &pios_openlrs_rcvr_driver, openlrsrcvr_id)) { PIOS_Assert(0); } + pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_OPENLRS] = openlrsrcvr_rcvr_id; #endif /* PIOS_INCLUDE_OPENLRS_RCVR && PIOS_INCLUDE_RCVR */ } else { /* Configure the RFM22B device. */ @@ -572,6 +551,15 @@ void PIOS_BOARD_IO_Configure_RFM22B(uint32_t spi_id, PIOS_BOARD_IO_RADIOAUX_Func if (PIOS_RFM22B_Init(&pios_rfm22b_id, spi_id, rfm22b_cfg->slave_num, rfm22b_cfg, oplinkSettings.RFBand)) { PIOS_Assert(0); } +#if defined(PIOS_INCLUDE_OPLINKRCVR) && defined(PIOS_INCLUDE_RCVR) + uint32_t pios_oplinkrcvr_id; + PIOS_OPLinkRCVR_Init(&pios_oplinkrcvr_id, pios_rfm22b_id); + uint32_t pios_oplinkrcvr_rcvr_id; + if (PIOS_RCVR_Init(&pios_oplinkrcvr_rcvr_id, &pios_oplinkrcvr_rcvr_driver, pios_oplinkrcvr_id)) { + PIOS_Assert(0); + } + pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_OPLINK] = pios_oplinkrcvr_rcvr_id; +#endif /* PIOS_INCLUDE_OPLINKRCVR && PIOS_INCLUDE_RCVR */ /* Configure the radio com interface */ if (PIOS_COM_Init(&pios_com_rf_id, &pios_rfm22b_com_driver, pios_rfm22b_id, @@ -689,16 +677,6 @@ void PIOS_BOARD_IO_Configure_RFM22B(uint32_t spi_id, PIOS_BOARD_IO_RADIOAUX_Func } OPLinkStatusSet(&oplinkStatus); - -#if defined(PIOS_INCLUDE_OPLINKRCVR) && defined(PIOS_INCLUDE_RCVR) - uint32_t pios_oplinkrcvr_id; - PIOS_OPLinkRCVR_Init(&pios_oplinkrcvr_id); - uint32_t pios_oplinkrcvr_rcvr_id; - if (PIOS_RCVR_Init(&pios_oplinkrcvr_rcvr_id, &pios_oplinkrcvr_rcvr_driver, pios_oplinkrcvr_id)) { - PIOS_Assert(0); - } - pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_OPLINK] = pios_oplinkrcvr_rcvr_id; -#endif /* PIOS_INCLUDE_OPLINKRCVR && PIOS_INCLUDE_RCVR */ } #endif /* ifdef PIOS_INCLUDE_RFM22B */ diff --git a/flight/pios/inc/pios_board_io.h b/flight/pios/inc/pios_board_io.h index 6b374deba0..57dd3736ea 100644 --- a/flight/pios/inc/pios_board_io.h +++ b/flight/pios/inc/pios_board_io.h @@ -140,6 +140,18 @@ extern uint32_t pios_com_mavlink_id; # define PIOS_COM_MAVLINK_RX_BUF_LEN 128 #endif +/* HoTT Telemetry */ +#ifdef PIOS_INCLUDE_HOTT_BRIDGE +# ifndef PIOS_COM_HOTT_BRIDGE_RX_BUF_LEN +# define PIOS_COM_HOTT_BRIDGE_RX_BUF_LEN 512 +# endif +# ifndef PIOS_COM_HOTT_BRIDGE_TX_BUF_LEN +# define PIOS_COM_HOTT_BRIDGE_TX_BUF_LEN 512 +# endif +extern uint32_t pios_com_hott_id; +# define PIOS_COM_HOTT (pios_com_hott_id) +#endif + /* USB VCP */ extern uint32_t pios_com_vcp_id; #define PIOS_COM_VCP (pios_com_vcp_id) @@ -181,6 +193,7 @@ typedef enum { PIOS_BOARD_IO_UART_IBUS, /* rcvr */ PIOS_BOARD_IO_UART_EXBUS, /* rcvr */ // PIOS_BOARD_IO_UART_FRSKY_SPORT_TELEMETRY, /* com */ + PIOS_BOARD_IO_UART_HOTT_BRIDGE, /* com */ } PIOS_BOARD_IO_UART_Function; typedef enum { @@ -191,27 +204,12 @@ typedef enum { // PIOS_BOARD_IO_RADIOAUX_FRSKY_SPORT_TELEMETRY, } PIOS_BOARD_IO_RADIOAUX_Function; -typedef enum { - PIOS_BOARD_IO_USB_HID_NONE, - PIOS_BOARD_IO_USB_HID_TELEMETRY, - PIOS_BOARD_IO_USB_HID_RCTX, -} PIOS_BOARD_IO_USB_HID_Function; - -typedef enum { - PIOS_BOARD_IO_USB_CDC_NONE, - PIOS_BOARD_IO_USB_CDC_TELEMETRY, - PIOS_BOARD_IO_USB_CDC_COMBRIDGE, - PIOS_BOARD_IO_USB_CDC_MAVLINK, - PIOS_BOARD_IO_USB_CDC_DEBUGCONSOLE, -// PIOS_BOARD_IO_USB_CDC_MSP, -} PIOS_BOARD_IO_USB_CDC_Function; - #ifdef PIOS_INCLUDE_USB -void PIOS_BOARD_IO_Configure_USB(PIOS_BOARD_IO_USB_HID_Function hid_function, PIOS_BOARD_IO_USB_CDC_Function cdc_function); -# if defined(PIOS_INCLUDE_USB_HID) -# include -extern const struct pios_usb_hid_cfg pios_usb_hid_cfg; -# endif /* PIOS_INCLUDE_USB_HID */ +void PIOS_BOARD_IO_Configure_USB(); +//# if defined(PIOS_INCLUDE_USB_HID) +//# include +//extern const struct pios_usb_hid_cfg pios_usb_hid_cfg; +//# endif /* PIOS_INCLUDE_USB_HID */ #endif /* PIOS_INCLUDE_USB */ #ifdef PIOS_INCLUDE_PWM void PIOS_BOARD_IO_Configure_PWM(const struct pios_pwm_cfg *pwm_cfg); diff --git a/flight/pios/stm32f10x/pios_sys.c b/flight/pios/stm32f10x/pios_sys.c index 19a6061b65..4644293b21 100644 --- a/flight/pios/stm32f10x/pios_sys.c +++ b/flight/pios/stm32f10x/pios_sys.c @@ -82,8 +82,8 @@ void PIOS_SYS_Init(void) RCC_APB1Periph_I2C1 | RCC_APB1Periph_I2C2 | RCC_APB1Periph_USB | - RCC_APB1Periph_CAN1 | - RCC_APB1Periph_CAN2 | +// RCC_APB1Periph_CAN1 | /* bxCAN unfortunately interferes with USB */ +// RCC_APB1Periph_CAN2 | RCC_APB1Periph_BKP | RCC_APB1Periph_PWR | RCC_APB1Periph_DAC, diff --git a/flight/targets/boards/coptercontrol/board_hw_defs.c b/flight/targets/boards/coptercontrol/board_hw_defs.c index f44e552f5a..d4d97f589d 100644 --- a/flight/targets/boards/coptercontrol/board_hw_defs.c +++ b/flight/targets/boards/coptercontrol/board_hw_defs.c @@ -981,18 +981,8 @@ const struct pios_usb_cfg *PIOS_BOARD_HW_DEFS_GetUsbCfg(uint32_t board_revision) return NULL; } -#include "pios_usb_board_data_priv.h" -#include "pios_usb_desc_hid_cdc_priv.h" -#include "pios_usb_desc_hid_only_priv.h" - #endif /* PIOS_INCLUDE_USB */ -#if defined(PIOS_INCLUDE_COM_MSG) - -#include - -#endif /* PIOS_INCLUDE_COM_MSG */ - /** * Configuration for MPU6000 chip */ diff --git a/flight/targets/boards/coptercontrol/bootloader/pios_board.c b/flight/targets/boards/coptercontrol/bootloader/pios_board.c index dda9fa5f59..466566d553 100644 --- a/flight/targets/boards/coptercontrol/bootloader/pios_board.c +++ b/flight/targets/boards/coptercontrol/bootloader/pios_board.c @@ -36,6 +36,10 @@ */ #include "../board_hw_defs.c" +#include "pios_usb_board_data_priv.h" +#include "pios_usb_desc_hid_only_priv.h" +#include + uint32_t pios_com_telem_usb_id; /** diff --git a/flight/targets/boards/revolution/bootloader/main.c b/flight/targets/boards/revolution/bootloader/main.c index 09a54a0947..aa5c7999a5 100644 --- a/flight/targets/boards/revolution/bootloader/main.c +++ b/flight/targets/boards/revolution/bootloader/main.c @@ -35,6 +35,7 @@ #include /* PIOS_USBHOOK_* */ #include #include +#include extern void FLASH_Download(); void check_bor(); diff --git a/flight/targets/boards/revonano/bootloader/main.c b/flight/targets/boards/revonano/bootloader/main.c index 09a54a0947..aa5c7999a5 100644 --- a/flight/targets/boards/revonano/bootloader/main.c +++ b/flight/targets/boards/revonano/bootloader/main.c @@ -35,6 +35,7 @@ #include /* PIOS_USBHOOK_* */ #include #include +#include extern void FLASH_Download(); void check_bor(); From 9eb1f3b5e5293ac4fde2b9ccd8a60bb15b03371c Mon Sep 17 00:00:00 2001 From: Vladimir Zidar Date: Wed, 19 Apr 2017 15:58:31 +0200 Subject: [PATCH 217/624] LP-480 Moved sensors initialization to pios_board_sensors.c --- flight/make/apps-defs.mk | 1 + flight/pios/common/pios_board_io.c | 177 +++-------------- flight/pios/common/pios_board_sensors.c | 187 ++++++++++++++++++ flight/pios/common/pios_usb_desc_hid_cdc.c | 2 +- flight/pios/inc/pios_board_hw.h | 6 + flight/pios/inc/pios_board_io.h | 38 ++-- flight/pios/inc/pios_board_sensors.h | 33 ++++ flight/pios/stm32f10x/inc/pios_servo_config.h | 28 +-- flight/pios/stm32f10x/pios_sys.c | 10 +- flight/pios/stm32f10x/pios_usart.c | 56 +++--- flight/pios/stm32f4xx/pios_usart.c | 2 +- .../boards/coptercontrol/board_hw_defs.c | 59 +++--- .../coptercontrol/firmware/pios_board.c | 82 ++++---- .../targets/boards/coptercontrol/pios_board.h | 10 +- .../boards/discoveryf4bare/board_hw_defs.c | 73 +++---- .../boards/discoveryf4bare/bootloader/main.c | 1 + .../discoveryf4bare/firmware/pios_board.c | 138 +++++++------ .../boards/discoveryf4bare/pios_board.h | 31 +-- .../targets/boards/oplinkmini/board_hw_defs.c | 8 +- .../targets/boards/revolution/board_hw_defs.c | 51 ++--- .../boards/revolution/firmware/pios_board.c | 29 ++- flight/targets/boards/revolution/pios_board.h | 34 ++-- .../targets/boards/revonano/board_hw_defs.c | 91 ++++----- .../boards/revonano/firmware/pios_board.c | 66 +++---- flight/targets/boards/revonano/pios_board.h | 34 ++-- flight/targets/boards/sparky2/board_hw_defs.c | 59 +++--- .../boards/sparky2/firmware/pios_board.c | 91 ++++----- flight/targets/boards/sparky2/pios_board.h | 35 ++-- 28 files changed, 766 insertions(+), 666 deletions(-) create mode 100644 flight/pios/common/pios_board_sensors.c create mode 100644 flight/pios/inc/pios_board_sensors.h diff --git a/flight/make/apps-defs.mk b/flight/make/apps-defs.mk index 32623ef690..7b661bb8e2 100644 --- a/flight/make/apps-defs.mk +++ b/flight/make/apps-defs.mk @@ -101,6 +101,7 @@ SRC += $(PIOSCOMMON)/pios_servo.c SRC += $(PIOSCOMMON)/pios_openlrs.c SRC += $(PIOSCOMMON)/pios_openlrs_rcvr.c SRC += $(PIOSCOMMON)/pios_board_io.c +SRC += $(PIOSCOMMON)/pios_board_sensors.c ## Misc library functions SRC += $(FLIGHTLIB)/sanitycheck.c diff --git a/flight/pios/common/pios_board_io.c b/flight/pios/common/pios_board_io.c index 0848531fb3..6ee7880514 100644 --- a/flight/pios/common/pios_board_io.c +++ b/flight/pios/common/pios_board_io.c @@ -67,21 +67,12 @@ # endif /* PIOS_INCLUDE_RCVR */ #endif /* PIOS_INCLUDE_RFM22B */ -#ifdef PIOS_INCLUDE_ADC -# include -#endif - -#ifdef PIOS_INCLUDE_MS5611 -# include -#endif - #ifdef PIOS_INCLUDE_RCVR # include "manualcontrolsettings.h" uint32_t pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_NONE]; /* Receivers */ #endif /* PIOS_INCLUDE_RCVR */ #include "hwsettings.h" -#include "auxmagsettings.h" #include "gcsreceiver.h" #ifdef PIOS_INCLUDE_GPS @@ -118,14 +109,6 @@ uint32_t pios_com_telem_usb_id; /* USB telemetry */ uint32_t pios_usb_rctx_id; #endif -#if defined(PIOS_INCLUDE_HMC5X83) -# include "pios_hmc5x83.h" -# if defined(PIOS_HMC5X83_HAS_GPIOS) -pios_hmc5x83_dev_t pios_hmc5x83_internal_id; -# endif -#endif - - #include "pios_usb_board_data_priv.h" #include "pios_usb_desc_hid_cdc_priv.h" #include "pios_usb_desc_hid_only_priv.h" @@ -185,7 +168,7 @@ void PIOS_BOARD_IO_Configure_USB() #if defined(PIOS_INCLUDE_USB_CDC) uint8_t hwsettings_usb_vcpport; HwSettingsUSB_VCPPortGet(&hwsettings_usb_vcpport); - + if (PIOS_USB_DESC_HID_CDC_Init()) { PIOS_Assert(0); } @@ -297,38 +280,38 @@ struct uart_function { }; static const struct uart_function uart_function_map[] = { - [PIOS_BOARD_IO_UART_TELEMETRY] = { + [PIOS_BOARD_IO_UART_TELEMETRY] = { .com_id = &pios_com_telem_rf_id, .com_rx_buf_len = PIOS_COM_TELEM_RF_RX_BUF_LEN, .com_tx_buf_len = PIOS_COM_TELEM_RF_TX_BUF_LEN, }, - [PIOS_BOARD_IO_UART_MAVLINK] = { + [PIOS_BOARD_IO_UART_MAVLINK] = { .com_id = &pios_com_mavlink_id, .com_rx_buf_len = PIOS_COM_MAVLINK_RX_BUF_LEN, .com_tx_buf_len = PIOS_COM_MAVLINK_TX_BUF_LEN, }, - [PIOS_BOARD_IO_UART_MSP] = { + [PIOS_BOARD_IO_UART_MSP] = { .com_id = &pios_com_msp_id, .com_rx_buf_len = PIOS_COM_MSP_RX_BUF_LEN, .com_tx_buf_len = PIOS_COM_MSP_TX_BUF_LEN, }, - [PIOS_BOARD_IO_UART_GPS] = { + [PIOS_BOARD_IO_UART_GPS] = { .com_id = &pios_com_gps_id, .com_rx_buf_len = PIOS_COM_GPS_RX_BUF_LEN, .com_tx_buf_len = PIOS_COM_GPS_TX_BUF_LEN, }, - [PIOS_BOARD_IO_UART_OSDHK] = { + [PIOS_BOARD_IO_UART_OSDHK] = { .com_id = &pios_com_hkosd_id, .com_rx_buf_len = PIOS_COM_HKOSD_RX_BUF_LEN, .com_tx_buf_len = PIOS_COM_HKOSD_TX_BUF_LEN, }, #ifdef PIOS_INCLUDE_HOTT_BRIDGE - [PIOS_BOARD_IO_UART_HOTT_BRIDGE] = { - .com_id = &pios_com_hott_id, + [PIOS_BOARD_IO_UART_HOTT_BRIDGE] = { + .com_id = &pios_com_hott_id, .com_rx_buf_len = PIOS_COM_HOTT_BRIDGE_RX_BUF_LEN, .com_tx_buf_len = PIOS_COM_HOTT_BRIDGE_TX_BUF_LEN, }, @@ -339,67 +322,67 @@ static const struct uart_function uart_function_map[] = { .com_tx_buf_len = PIOS_COM_DEBUGCONSOLE_TX_BUF_LEN, }, #endif - [PIOS_BOARD_IO_UART_COMBRIDGE] = { + [PIOS_BOARD_IO_UART_COMBRIDGE] = { .com_id = &pios_com_bridge_id, .com_rx_buf_len = PIOS_COM_BRIDGE_RX_BUF_LEN, .com_tx_buf_len = PIOS_COM_BRIDGE_TX_BUF_LEN, }, #ifdef PIOS_INCLUDE_RCVR # ifdef PIOS_INCLUDE_IBUS - [PIOS_BOARD_IO_UART_IBUS] = { + [PIOS_BOARD_IO_UART_IBUS] = { .rcvr_init = &PIOS_IBUS_Init, .rcvr_driver = &pios_ibus_rcvr_driver, .rcvr_group = MANUALCONTROLSETTINGS_CHANNELGROUPS_IBUS, }, # endif /* PIOS_INCLUDE_IBUS */ # ifdef PIOS_INCLUDE_EXBUS - [PIOS_BOARD_IO_UART_EXBUS] = { + [PIOS_BOARD_IO_UART_EXBUS] = { .rcvr_init = &PIOS_EXBUS_Init, .rcvr_driver = &pios_exbus_rcvr_driver, .rcvr_group = MANUALCONTROLSETTINGS_CHANNELGROUPS_EXBUS, }, # endif /* PIOS_INCLUDE_EXBUS */ # ifdef PIOS_INCLUDE_SRXL - [PIOS_BOARD_IO_UART_SRXL] = { + [PIOS_BOARD_IO_UART_SRXL] = { .rcvr_init = &PIOS_SRXL_Init, .rcvr_driver = &pios_srxl_rcvr_driver, .rcvr_group = MANUALCONTROLSETTINGS_CHANNELGROUPS_SRXL, }, # endif /* PIOS_INCLUDE_SRXL */ # ifdef PIOS_INCLUDE_HOTT - [PIOS_BOARD_IO_UART_HOTT_SUMD] = { + [PIOS_BOARD_IO_UART_HOTT_SUMD] = { .rcvr_init = &PIOS_HOTT_Init_SUMD, .rcvr_driver = &pios_hott_rcvr_driver, .rcvr_group = MANUALCONTROLSETTINGS_CHANNELGROUPS_HOTT, }, - [PIOS_BOARD_IO_UART_HOTT_SUMH] = { + [PIOS_BOARD_IO_UART_HOTT_SUMH] = { .rcvr_init = &PIOS_HOTT_Init_SUMH, .rcvr_driver = &pios_hott_rcvr_driver, .rcvr_group = MANUALCONTROLSETTINGS_CHANNELGROUPS_HOTT, }, # endif /* PIOS_INCLUDE_HOTT */ # ifdef PIOS_INCLUDE_DSM - [PIOS_BOARD_IO_UART_DSM_MAIN] = { + [PIOS_BOARD_IO_UART_DSM_MAIN] = { .rcvr_init = &PIOS_DSM_Init_Helper, .rcvr_driver = &pios_dsm_rcvr_driver, .rcvr_group = MANUALCONTROLSETTINGS_CHANNELGROUPS_DSMMAINPORT, }, - [PIOS_BOARD_IO_UART_DSM_FLEXI] = { + [PIOS_BOARD_IO_UART_DSM_FLEXI] = { .rcvr_init = &PIOS_DSM_Init_Helper, .rcvr_driver = &pios_dsm_rcvr_driver, .rcvr_group = MANUALCONTROLSETTINGS_CHANNELGROUPS_DSMFLEXIPORT, }, - [PIOS_BOARD_IO_UART_DSM_RCVR] = { + [PIOS_BOARD_IO_UART_DSM_RCVR] = { .rcvr_init = &PIOS_DSM_Init_Helper, .rcvr_driver = &pios_dsm_rcvr_driver, .rcvr_group = MANUALCONTROLSETTINGS_CHANNELGROUPS_DSMRCVRPORT, }, # endif /* PIOS_INCLUDE_DSM */ # ifdef PIOS_INCLUDE_SBUS - [PIOS_BOARD_IO_UART_SBUS] = { + [PIOS_BOARD_IO_UART_SBUS] = { .rcvr_init = &PIOS_SBus_Init_Helper, .rcvr_driver = &pios_sbus_rcvr_driver, .rcvr_group = MANUALCONTROLSETTINGS_CHANNELGROUPS_SBUS, @@ -495,7 +478,7 @@ void PIOS_BOARD_IO_Configure_GCSRCVR() #ifdef PIOS_INCLUDE_RFM22B -void PIOS_BOARD_IO_Configure_RFM22B(uint32_t spi_id, PIOS_BOARD_IO_RADIOAUX_Function radioaux_function) +void PIOS_BOARD_IO_Configure_RFM22B(PIOS_BOARD_IO_RADIOAUX_Function radioaux_function) { #if defined(PIOS_INCLUDE_RFM22B) OPLinkSettingsInitialize(); @@ -533,11 +516,11 @@ void PIOS_BOARD_IO_Configure_RFM22B(uint32_t spi_id, PIOS_BOARD_IO_RADIOAUX_Func uint32_t openlrs_id; const struct pios_openlrs_cfg *openlrs_cfg = PIOS_BOARD_HW_DEFS_GetOpenLRSCfg(pios_board_info_blob.board_rev); - PIOS_OpenLRS_Init(&openlrs_id, spi_id, 0, openlrs_cfg); + PIOS_OpenLRS_Init(&openlrs_id, PIOS_SPI_RFM22B_ADAPTER, 0, openlrs_cfg); uint32_t openlrsrcvr_id; PIOS_OpenLRS_Rcvr_Init(&openlrsrcvr_id, openlrs_id); - + uint32_t openlrsrcvr_rcvr_id; if (PIOS_RCVR_Init(&openlrsrcvr_rcvr_id, &pios_openlrs_rcvr_driver, openlrsrcvr_id)) { PIOS_Assert(0); @@ -548,7 +531,7 @@ void PIOS_BOARD_IO_Configure_RFM22B(uint32_t spi_id, PIOS_BOARD_IO_RADIOAUX_Func /* Configure the RFM22B device. */ const struct pios_rfm22b_cfg *rfm22b_cfg = PIOS_BOARD_HW_DEFS_GetRfm22Cfg(pios_board_info_blob.board_rev); - if (PIOS_RFM22B_Init(&pios_rfm22b_id, spi_id, rfm22b_cfg->slave_num, rfm22b_cfg, oplinkSettings.RFBand)) { + if (PIOS_RFM22B_Init(&pios_rfm22b_id, PIOS_SPI_RFM22B_ADAPTER, rfm22b_cfg->slave_num, rfm22b_cfg, oplinkSettings.RFBand)) { PIOS_Assert(0); } #if defined(PIOS_INCLUDE_OPLINKRCVR) && defined(PIOS_INCLUDE_RCVR) @@ -646,7 +629,7 @@ void PIOS_BOARD_IO_Configure_RFM22B(uint32_t spi_id, PIOS_BOARD_IO_RADIOAUX_Func uint16_t mavlink_rx_size = PIOS_COM_MAVLINK_RX_BUF_LEN; switch (radioaux_function) { - default: ; + default:; case PIOS_BOARD_IO_RADIOAUX_DEBUGCONSOLE: #ifdef PIOS_INCLUDE_DEBUG_CONSOLE if (PIOS_COM_Init(&pios_com_debug_id, &pios_rfm22b_aux_com_driver, pios_rfm22b_id, @@ -655,15 +638,14 @@ void PIOS_BOARD_IO_Configure_RFM22B(uint32_t spi_id, PIOS_BOARD_IO_RADIOAUX_Func PIOS_Assert(0); } #endif - break; + break; case PIOS_BOARD_IO_RADIOAUX_COMBRIDGE: - if(PIOS_COM_Init(&pios_com_bridge_id, &pios_rfm22b_aux_com_driver, pios_rfm22b_id, - 0, PIOS_COM_BRIDGE_RX_BUF_LEN, - 0, PIOS_COM_BRIDGE_TX_BUF_LEN)) - { + if (PIOS_COM_Init(&pios_com_bridge_id, &pios_rfm22b_aux_com_driver, pios_rfm22b_id, + 0, PIOS_COM_BRIDGE_RX_BUF_LEN, + 0, PIOS_COM_BRIDGE_TX_BUF_LEN)) { PIOS_Assert(0); } - break; + break; case PIOS_BOARD_IO_RADIOAUX_MAVLINK: if (PIOS_COM_Init(&pios_com_mavlink_id, &pios_rfm22b_aux_com_driver, pios_rfm22b_id, 0, mavlink_rx_size, @@ -679,106 +661,3 @@ void PIOS_BOARD_IO_Configure_RFM22B(uint32_t spi_id, PIOS_BOARD_IO_RADIOAUX_Func OPLinkStatusSet(&oplinkStatus); } #endif /* ifdef PIOS_INCLUDE_RFM22B */ - -#ifdef PIOS_INCLUDE_I2C -void PIOS_BOARD_IO_Configure_I2C(uint32_t i2c_internal_id, uint32_t i2c_external_id) -{ - // internal HMC5x83 mag -# ifdef PIOS_INCLUDE_HMC5X83_INTERNAL - const struct pios_hmc5x83_cfg *hmc5x83_internal_cfg = PIOS_BOARD_HW_DEFS_GetInternalHMC5x83Cfg(pios_board_info_blob.board_rev); - - if (hmc5x83_internal_cfg) { - // attach the 5x83 mag to internal i2c bus - - pios_hmc5x83_dev_t internal_mag = PIOS_HMC5x83_Init(hmc5x83_internal_cfg, i2c_internal_id, 0); -# ifdef PIOS_INCLUDE_WDG - // give HMC5x83 on I2C some extra time to allow for reset, etc. if needed - // this is not in a loop, so it is safe - PIOS_WDG_Clear(); -# endif /* PIOS_INCLUDE_WDG */ - -#ifdef PIOS_HMC5X83_HAS_GPIOS - pios_hmc5x83_internal_id = internal_mag; -#endif - // add this sensor to the sensor task's list - PIOS_HMC5x83_Register(internal_mag, PIOS_SENSORS_TYPE_3AXIS_MAG); - } - -# endif /* PIOS_INCLUDE_HMC5X83_INTERNAL */ - - // internal ms5611 baro -#if defined(PIOS_INCLUDE_MS5611) - PIOS_MS5611_Init(PIOS_BOARD_HW_DEFS_GetMS5611Cfg(pios_board_info_blob.board_rev), i2c_internal_id); - PIOS_MS5611_Register(); -#endif - - // internal bmp280 baro - // internal MPU6000 imu (i2c) - // internal eeprom (revo nano) - NOT HERE, should be initialized earlier - - - /* Initialize external sensors */ - - // aux mag -# ifdef PIOS_INCLUDE_HMC5X83 - AuxMagSettingsInitialize(); - - AuxMagSettingsTypeOptions option; - AuxMagSettingsTypeGet(&option); - - const struct pios_hmc5x83_cfg *hmc5x83_external_cfg = PIOS_BOARD_HW_DEFS_GetExternalHMC5x83Cfg(pios_board_info_blob.board_rev); - - if (hmc5x83_external_cfg) { - uint32_t i2c_id = 0; - - if (option == AUXMAGSETTINGS_TYPE_FLEXI) { - // i2c_external - i2c_id = i2c_external_id; - } else if (option == AUXMAGSETTINGS_TYPE_I2C) { - // i2c_internal (or Sparky2/F3 dedicated I2C port) - i2c_id = i2c_internal_id; - } - - if (i2c_id) { - uint32_t external_mag = PIOS_HMC5x83_Init(hmc5x83_external_cfg, i2c_id, 0); -# ifdef PIOS_INCLUDE_WDG - // give HMC5x83 on I2C some extra time to allow for reset, etc. if needed - // this is not in a loop, so it is safe - PIOS_WDG_Clear(); -# endif /* PIOS_INCLUDE_WDG */ - // add this sensor to the sensor task's list - // be careful that you don't register a slow, unimportant sensor after registering the fastest sensor - // and before registering some other fast and important sensor - // as that would cause delay and time jitter for the second fast sensor - PIOS_HMC5x83_Register(external_mag, PIOS_SENSORS_TYPE_3AXIS_AUXMAG); - // mag alarm is cleared later, so use I2C - AlarmsSet(SYSTEMALARMS_ALARM_I2C, (external_mag) ? SYSTEMALARMS_ALARM_OK : SYSTEMALARMS_ALARM_WARNING); - } - } -# endif /* PIOS_INCLUDE_HMC5X83 */ - - // external ETASV3 Eagletree Airspeed v3 - // external MS4525D PixHawk Airpeed based on MS4525DO - - // BMA180 accelerometer? - // bmp085/bmp180 baro - - // hmc5843 mag - // i2c esc (?) - // UBX DCC -} -#endif /* ifdef PIOS_INCLUDE_I2C */ - -#ifdef PIOS_INCLUDE_ADC -void PIOS_BOARD_IO_Configure_ADC() -{ - PIOS_ADC_Init(PIOS_BOARD_HW_DEFS_GetAdcCfg(pios_board_info_blob.board_rev)); - uint8_t adc_config[HWSETTINGS_ADCROUTING_NUMELEM]; - HwSettingsADCRoutingArrayGet(adc_config); - for (uint32_t i = 0; i < HWSETTINGS_ADCROUTING_NUMELEM; i++) { - if (adc_config[i] != HWSETTINGS_ADCROUTING_DISABLED) { - PIOS_ADC_PinSetup(i); - } - } -} -#endif /* PIOS_INCLUDE_ADC */ diff --git a/flight/pios/common/pios_board_sensors.c b/flight/pios/common/pios_board_sensors.c new file mode 100644 index 0000000000..fecfe17dde --- /dev/null +++ b/flight/pios/common/pios_board_sensors.c @@ -0,0 +1,187 @@ +/** + ****************************************************************************** + * + * @file pios_board_sensors.c + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017. + * @brief board sensors setup + * -- + * @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_board_info.h" +#include "pios_board_sensors.h" +#include "pios_board_hw.h" + +#include "uavobjectmanager.h" +#include "auxmagsettings.h" +#include "hwsettings.h" +#include + +#ifdef PIOS_INCLUDE_MPU6000 +# include +# include +#endif + +#ifdef PIOS_INCLUDE_MS5611 +# include +#endif + +#if defined(PIOS_INCLUDE_ADXL345) +# include +#endif + +#ifdef PIOS_INCLUDE_MPU9250 +# include +# include +#endif + +#if defined(PIOS_INCLUDE_HMC5X83) +# include "pios_hmc5x83.h" +# if defined(PIOS_HMC5X83_HAS_GPIOS) +pios_hmc5x83_dev_t pios_hmc5x83_internal_id; +# endif +#endif + +#ifdef PIOS_INCLUDE_ADC +# include "pios_adc_priv.h" +#endif + +void PIOS_BOARD_Sensors_Configure() +{ +#ifdef PIOS_INCLUDE_MPU6000 + const struct pios_mpu6000_cfg *mpu6000_cfg = PIOS_BOARD_HW_DEFS_GetMPU6000Cfg(pios_board_info_blob.board_rev); + if (mpu6000_cfg) { + PIOS_MPU6000_Init(PIOS_SPI_MPU6000_ADAPTER, 0, mpu6000_cfg); + PIOS_MPU6000_CONFIG_Configure(); +#ifndef PIOS_EXCLUDE_ADVANCED_FEATURES + PIOS_MPU6000_Register(); +#endif + } +#endif /* PIOS_INCLUDE_MPU6000 */ + +#ifdef PIOS_INCLUDE_ADXL345 + PIOS_ADXL345_Init(PIOS_SPI_ADXL345_ADAPTER, 0); +#endif + +#ifdef PIOS_INCLUDE_MPU9250 + const struct pios_mpu9250_cfg *mpu9250_cfg = PIOS_BOARD_HW_DEFS_GetMPU9250Cfg(pios_board_info_blob.board_rev); + if (mpu9250_cfg) { + PIOS_MPU9250_Init(PIOS_SPI_MPU9250_ADAPTER, 0, mpu9250_cfg); + PIOS_MPU9250_CONFIG_Configure(); + PIOS_MPU9250_MainRegister(); + PIOS_MPU9250_MagRegister(); + } +#endif /* PIOS_INCLUDE_MPU9250 */ + + + // internal HMC5x83 mag +# ifdef PIOS_INCLUDE_HMC5X83_INTERNAL + const struct pios_hmc5x83_cfg *hmc5x83_internal_cfg = PIOS_BOARD_HW_DEFS_GetInternalHMC5x83Cfg(pios_board_info_blob.board_rev); + + if (hmc5x83_internal_cfg) { + // attach the 5x83 mag to internal i2c bus + + pios_hmc5x83_dev_t internal_mag = PIOS_HMC5x83_Init(hmc5x83_internal_cfg, PIOS_I2C_HMC5X83_INTERNAL_ADAPTER, 0); +# ifdef PIOS_INCLUDE_WDG + // give HMC5x83 on I2C some extra time to allow for reset, etc. if needed + // this is not in a loop, so it is safe + PIOS_WDG_Clear(); +# endif /* PIOS_INCLUDE_WDG */ + +#ifdef PIOS_HMC5X83_HAS_GPIOS + pios_hmc5x83_internal_id = internal_mag; +#endif + // add this sensor to the sensor task's list + PIOS_HMC5x83_Register(internal_mag, PIOS_SENSORS_TYPE_3AXIS_MAG); + } + +# endif /* PIOS_INCLUDE_HMC5X83_INTERNAL */ + +# ifdef PIOS_INCLUDE_HMC5X83 + AuxMagSettingsInitialize(); + + AuxMagSettingsTypeOptions option; + AuxMagSettingsTypeGet(&option); + + const struct pios_hmc5x83_cfg *hmc5x83_external_cfg = PIOS_BOARD_HW_DEFS_GetExternalHMC5x83Cfg(pios_board_info_blob.board_rev); + + if (hmc5x83_external_cfg) { + uint32_t i2c_id = 0; + + if (option == AUXMAGSETTINGS_TYPE_FLEXI) { + // i2c_external + i2c_id = PIOS_I2C_EXTERNAL_ADAPTER; + } else if (option == AUXMAGSETTINGS_TYPE_I2C) { + // i2c_internal (or Sparky2/F3 dedicated I2C port) + i2c_id = PIOS_I2C_FLEXI_ADAPTER; + } + + if (i2c_id) { + uint32_t external_mag = PIOS_HMC5x83_Init(hmc5x83_external_cfg, i2c_id, 0); +# ifdef PIOS_INCLUDE_WDG + // give HMC5x83 on I2C some extra time to allow for reset, etc. if needed + // this is not in a loop, so it is safe + PIOS_WDG_Clear(); +# endif /* PIOS_INCLUDE_WDG */ + // add this sensor to the sensor task's list + // be careful that you don't register a slow, unimportant sensor after registering the fastest sensor + // and before registering some other fast and important sensor + // as that would cause delay and time jitter for the second fast sensor + PIOS_HMC5x83_Register(external_mag, PIOS_SENSORS_TYPE_3AXIS_AUXMAG); + // mag alarm is cleared later, so use I2C + AlarmsSet(SYSTEMALARMS_ALARM_I2C, (external_mag) ? SYSTEMALARMS_ALARM_OK : SYSTEMALARMS_ALARM_WARNING); + } + } +# endif /* PIOS_INCLUDE_HMC5X83 */ + + // internal ms5611 baro +#if defined(PIOS_INCLUDE_MS5611) + const struct pios_ms5611_cfg *ms5611_cfg = PIOS_BOARD_HW_DEFS_GetMS5611Cfg(pios_board_info_blob.board_rev); + if (ms5611_cfg) { + PIOS_MS5611_Init(ms5611_cfg, PIOS_I2C_MS5611_INTERNAL_ADAPTER); + PIOS_MS5611_Register(); + } +#endif + +#ifdef PIOS_INCLUDE_ADC + PIOS_ADC_Init(PIOS_BOARD_HW_DEFS_GetAdcCfg(pios_board_info_blob.board_rev)); +#ifndef PIOS_EXCLUDE_ADVANCED_FEATURES + uint8_t adc_config[HWSETTINGS_ADCROUTING_NUMELEM]; + HwSettingsADCRoutingArrayGet(adc_config); + for (uint32_t i = 0; i < HWSETTINGS_ADCROUTING_NUMELEM; i++) { + if (adc_config[i] != HWSETTINGS_ADCROUTING_DISABLED) { + PIOS_ADC_PinSetup(i); + } + } +#endif +#endif /* PIOS_INCLUDE_ADC */ + + // internal bmp280 baro + // internal MPU6000 imu (i2c) + + // external ETASV3 Eagletree Airspeed v3 + // external MS4525D PixHawk Airpeed based on MS4525DO + + // BMA180 accelerometer? + // bmp085/bmp180 baro + + // hmc5843 mag + // i2c esc (?) + // UBX DCC +} diff --git a/flight/pios/common/pios_usb_desc_hid_cdc.c b/flight/pios/common/pios_usb_desc_hid_cdc.c index 255bf6dce4..fe2a606980 100644 --- a/flight/pios/common/pios_usb_desc_hid_cdc.c +++ b/flight/pios/common/pios_usb_desc_hid_cdc.c @@ -320,7 +320,7 @@ static const struct usb_config_hid_cdc config_hid_cdc = { const struct pios_usb_cdc_cfg pios_usb_cdc_cfg = { .ctrl_if = 0, .ctrl_tx_ep = 2, - + .data_if = 1, .data_rx_ep = 3, .data_tx_ep = 3, diff --git a/flight/pios/inc/pios_board_hw.h b/flight/pios/inc/pios_board_hw.h index ce344b9ce6..4c786d99a6 100644 --- a/flight/pios/inc/pios_board_hw.h +++ b/flight/pios/inc/pios_board_hw.h @@ -53,4 +53,10 @@ const struct pios_bmp280_cfg *PIOS_BOARD_HW_DEFS_GetBMP280Cfg(uint32_t board_rev #ifdef PIOS_INCLUDE_ADC const struct pios_adc_cfg *PIOS_BOARD_HW_DEFS_GetAdcCfg(uint32_t board_revision); #endif +#ifdef PIOS_INCLUDE_MPU6000 +const struct pios_mpu6000_cfg *PIOS_BOARD_HW_DEFS_GetMPU6000Cfg(uint32_t board_revision); +#endif +#ifdef PIOS_INCLUDE_MPU9250 +const struct pios_mpu9250_cfg *PIOS_BOARD_HW_DEFS_GetMPU9250Cfg(uint32_t board_revision); +#endif #endif /* PIOS_BOARD_HW_H */ diff --git a/flight/pios/inc/pios_board_io.h b/flight/pios/inc/pios_board_io.h index 57dd3736ea..9ba4dc0d0f 100644 --- a/flight/pios/inc/pios_board_io.h +++ b/flight/pios/inc/pios_board_io.h @@ -112,32 +112,32 @@ extern uint32_t pios_com_rf_id; /* oplink telemetry */ /* HK OSD ?? */ extern uint32_t pios_com_hkosd_id; -#define PIOS_COM_OSDHK (pios_com_hkosd_id) +#define PIOS_COM_OSDHK (pios_com_hkosd_id) #ifndef PIOS_COM_HKOSD_RX_BUF_LEN -# define PIOS_COM_HKOSD_RX_BUF_LEN 22 +# define PIOS_COM_HKOSD_RX_BUF_LEN 22 #endif #ifndef PIOS_COM_HKOSD_TX_BUF_LEN -# define PIOS_COM_HKOSD_TX_BUF_LEN 22 +# define PIOS_COM_HKOSD_TX_BUF_LEN 22 #endif /* MSP */ extern uint32_t pios_com_msp_id; -#define PIOS_COM_MSP (pios_com_msp_id) +#define PIOS_COM_MSP (pios_com_msp_id) #ifndef PIOS_COM_MSP_TX_BUF_LEN -# define PIOS_COM_MSP_TX_BUF_LEN 128 +# define PIOS_COM_MSP_TX_BUF_LEN 128 #endif #ifndef PIOS_COM_MSP_RX_BUF_LEN -# define PIOS_COM_MSP_RX_BUF_LEN 64 +# define PIOS_COM_MSP_RX_BUF_LEN 64 #endif /* MAVLink */ extern uint32_t pios_com_mavlink_id; -#define PIOS_COM_MAVLINK (pios_com_mavlink_id) +#define PIOS_COM_MAVLINK (pios_com_mavlink_id) #ifndef PIOS_COM_MAVLINK_TX_BUF_LEN -# define PIOS_COM_MAVLINK_TX_BUF_LEN 128 +# define PIOS_COM_MAVLINK_TX_BUF_LEN 128 #endif #ifndef PIOS_COM_MAVLINK_RX_BUF_LEN -# define PIOS_COM_MAVLINK_RX_BUF_LEN 128 +# define PIOS_COM_MAVLINK_RX_BUF_LEN 128 #endif /* HoTT Telemetry */ @@ -149,7 +149,7 @@ extern uint32_t pios_com_mavlink_id; # define PIOS_COM_HOTT_BRIDGE_TX_BUF_LEN 512 # endif extern uint32_t pios_com_hott_id; -# define PIOS_COM_HOTT (pios_com_hott_id) +# define PIOS_COM_HOTT (pios_com_hott_id) #endif /* USB VCP */ @@ -192,7 +192,7 @@ typedef enum { PIOS_BOARD_IO_UART_SRXL, /* rcvr */ PIOS_BOARD_IO_UART_IBUS, /* rcvr */ PIOS_BOARD_IO_UART_EXBUS, /* rcvr */ -// PIOS_BOARD_IO_UART_FRSKY_SPORT_TELEMETRY, /* com */ +// PIOS_BOARD_IO_UART_FRSKY_SPORT_TELEMETRY, /* com */ PIOS_BOARD_IO_UART_HOTT_BRIDGE, /* com */ } PIOS_BOARD_IO_UART_Function; @@ -201,15 +201,15 @@ typedef enum { PIOS_BOARD_IO_RADIOAUX_MAVLINK, PIOS_BOARD_IO_RADIOAUX_COMBRIDGE, PIOS_BOARD_IO_RADIOAUX_DEBUGCONSOLE, -// PIOS_BOARD_IO_RADIOAUX_FRSKY_SPORT_TELEMETRY, +// PIOS_BOARD_IO_RADIOAUX_FRSKY_SPORT_TELEMETRY, } PIOS_BOARD_IO_RADIOAUX_Function; #ifdef PIOS_INCLUDE_USB void PIOS_BOARD_IO_Configure_USB(); -//# if defined(PIOS_INCLUDE_USB_HID) -//# include -//extern const struct pios_usb_hid_cfg pios_usb_hid_cfg; -//# endif /* PIOS_INCLUDE_USB_HID */ +// # if defined(PIOS_INCLUDE_USB_HID) +// # include +// extern const struct pios_usb_hid_cfg pios_usb_hid_cfg; +// # endif /* PIOS_INCLUDE_USB_HID */ #endif /* PIOS_INCLUDE_USB */ #ifdef PIOS_INCLUDE_PWM void PIOS_BOARD_IO_Configure_PWM(const struct pios_pwm_cfg *pwm_cfg); @@ -221,11 +221,7 @@ void PIOS_BOARD_IO_Configure_PPM(const struct pios_ppm_cfg *ppm_cfg); void PIOS_BOARD_IO_Configure_UART(const struct pios_usart_cfg *usart_cfg, PIOS_BOARD_IO_UART_Function function); #ifdef PIOS_INCLUDE_RFM22B -void PIOS_BOARD_IO_Configure_RFM22B(uint32_t spi_id, PIOS_BOARD_IO_RADIOAUX_Function function); -#endif - -#ifdef PIOS_INCLUDE_I2C -void PIOS_BOARD_IO_Configure_I2C(uint32_t i2c_internal_id, uint32_t i2c_external_id); +void PIOS_BOARD_IO_Configure_RFM22B(PIOS_BOARD_IO_RADIOAUX_Function function); #endif #ifdef PIOS_INCLUDE_GCSRCVR diff --git a/flight/pios/inc/pios_board_sensors.h b/flight/pios/inc/pios_board_sensors.h new file mode 100644 index 0000000000..71a2920624 --- /dev/null +++ b/flight/pios/inc/pios_board_sensors.h @@ -0,0 +1,33 @@ +/** + ****************************************************************************** + * + * @file pios_board_sensors.h + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017. + * @brief board sensors setup + * -- + * @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_BOARD_SENSORS_H +#define PIOS_BOARD_SENSORS_H + +#include "pios.h" + +void PIOS_BOARD_Sensors_Configure(); + +#endif /* PIOS_BOARD_SENSORS_H */ diff --git a/flight/pios/stm32f10x/inc/pios_servo_config.h b/flight/pios/stm32f10x/inc/pios_servo_config.h index b5464ebaea..f8a03fcb75 100644 --- a/flight/pios/stm32f10x/inc/pios_servo_config.h +++ b/flight/pios/stm32f10x/inc/pios_servo_config.h @@ -30,20 +30,20 @@ * Generic servo pin configuration structure for an STM32F10x */ #define TIM_SERVO_CHANNEL_CONFIG(_timer, _channel, _gpio, _pin, _remap) \ -{ \ - .timer = _timer, \ - .timer_chan = TIM_Channel_##_channel, \ - .pin = { \ - .gpio = GPIO##_gpio, \ - .init = { \ - .GPIO_Pin = GPIO_Pin_##_pin, \ - .GPIO_Mode = GPIO_Mode_IPD, \ - .GPIO_Speed = GPIO_Speed_2MHz,\ - }, \ - .pin_source = GPIO_PinSource##_pin, \ - }, \ - .remap = _remap, \ -} + { \ + .timer = _timer, \ + .timer_chan = TIM_Channel_##_channel, \ + .pin = { \ + .gpio = GPIO##_gpio, \ + .init = { \ + .GPIO_Pin = GPIO_Pin_##_pin, \ + .GPIO_Mode = GPIO_Mode_IPD, \ + .GPIO_Speed = GPIO_Speed_2MHz, \ + }, \ + .pin_source = GPIO_PinSource##_pin, \ + }, \ + .remap = _remap, \ + } #endif /* PIOS_SERVO_CONFIG_H_ */ diff --git a/flight/pios/stm32f10x/pios_sys.c b/flight/pios/stm32f10x/pios_sys.c index 4644293b21..012e6b7301 100644 --- a/flight/pios/stm32f10x/pios_sys.c +++ b/flight/pios/stm32f10x/pios_sys.c @@ -58,11 +58,11 @@ void PIOS_SYS_Init(void) * Micromanaging clocks makes no sense given the power situation in the system, so * light up everything we might reasonably use here and just leave it on. */ - + RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1 | RCC_AHBPeriph_DMA2, ENABLE); - + RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 | RCC_APB1Periph_TIM3 | RCC_APB1Periph_TIM4 | @@ -82,13 +82,13 @@ void PIOS_SYS_Init(void) RCC_APB1Periph_I2C1 | RCC_APB1Periph_I2C2 | RCC_APB1Periph_USB | -// RCC_APB1Periph_CAN1 | /* bxCAN unfortunately interferes with USB */ -// RCC_APB1Periph_CAN2 | +// RCC_APB1Periph_CAN1 | /* bxCAN unfortunately interferes with USB */ +// RCC_APB1Periph_CAN2 | RCC_APB1Periph_BKP | RCC_APB1Periph_PWR | RCC_APB1Periph_DAC, ENABLE); - + RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | diff --git a/flight/pios/stm32f10x/pios_usart.c b/flight/pios/stm32f10x/pios_usart.c index bc165f38fc..cc2d13fc0f 100644 --- a/flight/pios/stm32f10x/pios_usart.c +++ b/flight/pios/stm32f10x/pios_usart.c @@ -52,7 +52,7 @@ const struct pios_com_driver pios_usart_com_driver = { .rx_start = PIOS_USART_RxStart, .bind_tx_cb = PIOS_USART_RegisterTxCallback, .bind_rx_cb = PIOS_USART_RegisterRxCallback, - .ioctl = PIOS_USART_Ioctl, + .ioctl = PIOS_USART_Ioctl, }; enum pios_usart_dev_magic { @@ -69,7 +69,7 @@ struct pios_usart_dev { uint32_t tx_out_context; uint32_t rx_dropped; - uint8_t irq_channel; + uint8_t irq_channel; }; static bool PIOS_USART_validate(struct pios_usart_dev *usart_dev) @@ -80,11 +80,11 @@ static bool PIOS_USART_validate(struct pios_usart_dev *usart_dev) const struct pios_usart_cfg *PIOS_USART_GetConfig(uint32_t usart_id) { struct pios_usart_dev *usart_dev = (struct pios_usart_dev *)usart_id; - + bool valid = PIOS_USART_validate(usart_dev); - + PIOS_Assert(valid); - + return usart_dev->cfg; } @@ -95,9 +95,9 @@ static int32_t PIOS_USART_SetIrqPrio(struct pios_usart_dev *usart_dev, uint8_t i .NVIC_IRQChannelPreemptionPriority = irq_prio, .NVIC_IRQChannelCmd = ENABLE, }; - + NVIC_Init(&init); - + return 0; } @@ -180,7 +180,7 @@ int32_t PIOS_USART_Init(uint32_t *usart_id, const struct pios_usart_cfg *cfg) } /* Bind the configuration to the device instance */ - usart_dev->cfg = cfg; + usart_dev->cfg = cfg; /* Initialize the comm parameter structure */ USART_StructInit(&usart_dev->init); // 9600 8n1 @@ -214,9 +214,9 @@ int32_t PIOS_USART_Init(uint32_t *usart_id, const struct pios_usart_cfg *cfg) usart_dev->irq_channel = USART3_IRQn; break; } - + PIOS_USART_SetIrqPrio(usart_dev, PIOS_IRQ_PRIO_MID); - + USART_ITConfig(usart_dev->cfg->regs, USART_IT_RXNE, ENABLE); USART_ITConfig(usart_dev->cfg->regs, USART_IT_TXE, ENABLE); @@ -452,28 +452,28 @@ static void PIOS_USART_generic_irq_handler(uint32_t usart_id) static int32_t PIOS_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param) { struct pios_usart_dev *usart_dev = (struct pios_usart_dev *)usart_id; - + bool valid = PIOS_USART_validate(usart_dev); - + PIOS_Assert(valid); - + switch (ctl) { - case PIOS_IOCTL_USART_SET_IRQ_PRIO: - return PIOS_USART_SetIrqPrio(usart_dev, *(uint8_t *)param); - - case PIOS_IOCTL_USART_GET_RXGPIO: - *(struct stm32_gpio *)param = usart_dev->cfg->rx; - break; - case PIOS_IOCTL_USART_GET_TXGPIO: - *(struct stm32_gpio *)param = usart_dev->cfg->tx; - break; - default: - if (usart_dev->cfg->ioctl) { - return usart_dev->cfg->ioctl(usart_id, ctl, param); - } - return -1; + case PIOS_IOCTL_USART_SET_IRQ_PRIO: + return PIOS_USART_SetIrqPrio(usart_dev, *(uint8_t *)param); + + case PIOS_IOCTL_USART_GET_RXGPIO: + *(struct stm32_gpio *)param = usart_dev->cfg->rx; + break; + case PIOS_IOCTL_USART_GET_TXGPIO: + *(struct stm32_gpio *)param = usart_dev->cfg->tx; + break; + default: + if (usart_dev->cfg->ioctl) { + return usart_dev->cfg->ioctl(usart_id, ctl, param); + } + return -1; } - + return 0; } diff --git a/flight/pios/stm32f4xx/pios_usart.c b/flight/pios/stm32f4xx/pios_usart.c index c6f72674df..7b9f936495 100644 --- a/flight/pios/stm32f4xx/pios_usart.c +++ b/flight/pios/stm32f4xx/pios_usart.c @@ -59,7 +59,7 @@ const struct pios_com_driver pios_usart_com_driver = { .rx_start = PIOS_USART_RxStart, .bind_tx_cb = PIOS_USART_RegisterTxCallback, .bind_rx_cb = PIOS_USART_RegisterRxCallback, - .ioctl = PIOS_USART_Ioctl, + .ioctl = PIOS_USART_Ioctl, }; enum pios_usart_dev_magic { diff --git a/flight/targets/boards/coptercontrol/board_hw_defs.c b/flight/targets/boards/coptercontrol/board_hw_defs.c index d4d97f589d..9fde0bb45e 100644 --- a/flight/targets/boards/coptercontrol/board_hw_defs.c +++ b/flight/targets/boards/coptercontrol/board_hw_defs.c @@ -186,11 +186,11 @@ static const struct pios_spi_cfg pios_spi_gyro_cfg = { }, }; -static uint32_t pios_spi_gyro_id; +uint32_t pios_spi_gyro_adapter_id; void PIOS_SPI_gyro_irq_handler(void) { /* Call into the generic code to handle the IRQ for this specific device */ - PIOS_SPI_IRQ_Handler(pios_spi_gyro_id); + PIOS_SPI_IRQ_Handler(pios_spi_gyro_adapter_id); } @@ -402,11 +402,11 @@ static const struct pios_spi_cfg pios_spi_flash_accel_cfg_cc = { }, }; -static uint32_t pios_spi_flash_accel_id; +uint32_t pios_spi_flash_accel_adapter_id; void PIOS_SPI_flash_accel_irq_handler(void) { /* Call into the generic code to handle the IRQ for this specific device */ - PIOS_SPI_IRQ_Handler(pios_spi_flash_accel_id); + PIOS_SPI_IRQ_Handler(pios_spi_flash_accel_adapter_id); } #endif /* PIOS_INCLUDE_SPI */ @@ -485,6 +485,11 @@ void PIOS_ADC_handler() { PIOS_ADC_DMA_Handler(); } + +const struct pios_adc_cfg *PIOS_BOARD_HW_DEFS_GetAdcCfg(__attribute__((unused)) uint32_t board_revision) +{ + return &pios_adc_cfg; +} #endif /* if defined(PIOS_INCLUDE_ADC) */ #include "pios_tim_priv.h" @@ -593,16 +598,16 @@ static const struct pios_tim_channel pios_tim_ppm_flexi_port = TIM_SERVO_CHANNEL #include "pios_usart_priv.h" // Inverter for SBUS handling -#define MAIN_USART_INVERTER_GPIO GPIOB -#define MAIN_USART_INVERTER_PIN GPIO_Pin_2 -#define MAIN_USART_INVERTER_ENABLE Bit_SET -#define MAIN_USART_INVERTER_DISABLE Bit_RESET +#define MAIN_USART_INVERTER_GPIO GPIOB +#define MAIN_USART_INVERTER_PIN GPIO_Pin_2 +#define MAIN_USART_INVERTER_ENABLE Bit_SET +#define MAIN_USART_INVERTER_DISABLE Bit_RESET static int32_t PIOS_BOARD_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param); static const struct pios_usart_cfg pios_usart_main_cfg = { .regs = USART1, - .rx = { + .rx = { .gpio = GPIOA, .init = { .GPIO_Pin = GPIO_Pin_10, @@ -610,7 +615,7 @@ static const struct pios_usart_cfg pios_usart_main_cfg = { .GPIO_Mode = GPIO_Mode_IPU, }, }, - .tx = { + .tx = { .gpio = GPIOA, .init = { .GPIO_Pin = GPIO_Pin_9, @@ -618,12 +623,12 @@ static const struct pios_usart_cfg pios_usart_main_cfg = { .GPIO_Mode = GPIO_Mode_AF_PP, }, }, - .ioctl = PIOS_BOARD_USART_Ioctl, + .ioctl = PIOS_BOARD_USART_Ioctl, }; static const struct pios_usart_cfg pios_usart_flexi_cfg = { .regs = USART3, - .rx = { + .rx = { .gpio = GPIOB, .init = { .GPIO_Pin = GPIO_Pin_11, @@ -631,7 +636,7 @@ static const struct pios_usart_cfg pios_usart_flexi_cfg = { .GPIO_Mode = GPIO_Mode_IPU, }, }, - .tx = { + .tx = { .gpio = GPIOB, .init = { .GPIO_Pin = GPIO_Pin_10, @@ -967,16 +972,16 @@ static const struct pios_usb_cfg pios_usb_main_cfg_cc3d = { const struct pios_usb_cfg *PIOS_BOARD_HW_DEFS_GetUsbCfg(uint32_t board_revision) { switch (board_revision) { - case BOARD_REVISION_CC: - return &pios_usb_main_cfg_cc; - - break; - case BOARD_REVISION_CC3D: - return &pios_usb_main_cfg_cc3d; - - break; - default: - PIOS_DEBUG_Assert(0); + case BOARD_REVISION_CC: + return &pios_usb_main_cfg_cc; + + break; + case BOARD_REVISION_CC3D: + return &pios_usb_main_cfg_cc3d; + + break; + default: + PIOS_DEBUG_Assert(0); } return NULL; } @@ -988,7 +993,6 @@ const struct pios_usb_cfg *PIOS_BOARD_HW_DEFS_GetUsbCfg(uint32_t board_revision) */ #if defined(PIOS_INCLUDE_MPU6000) #include "pios_mpu6000.h" -#include "pios_mpu6000_config.h" static const struct pios_exti_cfg pios_exti_mpu6000_cfg __exti_config = { .vector = PIOS_MPU6000_IRQHandler, .line = EXTI_Line3, @@ -1037,6 +1041,9 @@ static const struct pios_mpu6000_cfg pios_mpu6000_cfg = { .std_prescaler = PIOS_SPI_PRESCALER_64, .max_downsample = 2 }; -#endif /* PIOS_INCLUDE_MPU6000 */ - +const struct pios_mpu6000_cfg *PIOS_BOARD_HW_DEFS_GetMPU6000Cfg(__attribute__((unused)) uint32_t board_revision) +{ + return &pios_mpu6000_cfg; +} +#endif /* PIOS_INCLUDE_MPU6000 */ diff --git a/flight/targets/boards/coptercontrol/firmware/pios_board.c b/flight/targets/boards/coptercontrol/firmware/pios_board.c index fdc6f517f3..baffcae280 100644 --- a/flight/targets/boards/coptercontrol/firmware/pios_board.c +++ b/flight/targets/boards/coptercontrol/firmware/pios_board.c @@ -38,11 +38,9 @@ #ifdef PIOS_INCLUDE_INSTRUMENTATION #include #endif -#if defined(PIOS_INCLUDE_ADXL345) -#include -#endif #include +#include /* * Pull in the board-specific static HW definitions. @@ -91,19 +89,19 @@ static const PIOS_BOARD_IO_UART_Function flexi_function_map[] = { int32_t PIOS_BOARD_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param) { const struct pios_usart_cfg *usart_cfg = PIOS_USART_GetConfig(usart_id); - + switch (ctl) { - case PIOS_IOCTL_USART_SET_INVERTED: - if (usart_cfg->regs == pios_usart_main_cfg.regs) { /* main port */ - GPIO_WriteBit(MAIN_USART_INVERTER_GPIO, - MAIN_USART_INVERTER_PIN, - (*(enum PIOS_USART_Inverted *)param & PIOS_USART_Inverted_Rx) ? MAIN_USART_INVERTER_ENABLE : MAIN_USART_INVERTER_DISABLE); - - return 0; - } - break; + case PIOS_IOCTL_USART_SET_INVERTED: + if (usart_cfg->regs == pios_usart_main_cfg.regs) { /* main port */ + GPIO_WriteBit(MAIN_USART_INVERTER_GPIO, + MAIN_USART_INVERTER_PIN, + (*(enum PIOS_USART_Inverted *)param & PIOS_USART_Inverted_Rx) ? MAIN_USART_INVERTER_ENABLE : MAIN_USART_INVERTER_DISABLE); + + return 0; + } + break; } - + return -1; } @@ -133,12 +131,12 @@ void PIOS_Board_Init(void) switch (bdinfo->board_rev) { case BOARD_REVISION_CC: - if (PIOS_SPI_Init(&pios_spi_flash_accel_id, &pios_spi_flash_accel_cfg_cc)) { + if (PIOS_SPI_Init(&pios_spi_flash_accel_adapter_id, &pios_spi_flash_accel_cfg_cc)) { PIOS_Assert(0); } break; case BOARD_REVISION_CC3D: - if (PIOS_SPI_Init(&pios_spi_flash_accel_id, &pios_spi_flash_accel_cfg_cc3d)) { + if (PIOS_SPI_Init(&pios_spi_flash_accel_adapter_id, &pios_spi_flash_accel_cfg_cc3d)) { PIOS_Assert(0); } break; @@ -151,7 +149,7 @@ void PIOS_Board_Init(void) uintptr_t flash_id; switch (bdinfo->board_rev) { case BOARD_REVISION_CC: - if (PIOS_Flash_Jedec_Init(&flash_id, pios_spi_flash_accel_id, 1)) { + if (PIOS_Flash_Jedec_Init(&flash_id, pios_spi_flash_accel_adapter_id, 1)) { PIOS_DEBUG_Assert(0); } if (PIOS_FLASHFS_Logfs_Init(&pios_uavo_settings_fs_id, &flashfs_w25x_cfg, &pios_jedec_flash_driver, flash_id)) { @@ -159,7 +157,7 @@ void PIOS_Board_Init(void) } break; case BOARD_REVISION_CC3D: - if (PIOS_Flash_Jedec_Init(&flash_id, pios_spi_flash_accel_id, 0)) { + if (PIOS_Flash_Jedec_Init(&flash_id, pios_spi_flash_accel_adapter_id, 0)) { PIOS_DEBUG_Assert(0); } if (PIOS_FLASHFS_Logfs_Init(&pios_uavo_settings_fs_id, &flashfs_m25p_cfg, &pios_jedec_flash_driver, flash_id)) { @@ -233,28 +231,28 @@ void PIOS_Board_Init(void) /* Configure FlexiPort */ uint8_t hwsettings_flexiport; HwSettingsCC_FlexiPortGet(&hwsettings_flexiport); - + if (hwsettings_flexiport < NELEMENTS(flexi_function_map)) { PIOS_BOARD_IO_Configure_UART(&pios_usart_flexi_cfg, flexi_function_map[hwsettings_flexiport]); } - switch(hwsettings_flexiport) { - case HWSETTINGS_CC_FLEXIPORT_I2C: + switch (hwsettings_flexiport) { + case HWSETTINGS_CC_FLEXIPORT_I2C: #if defined(PIOS_INCLUDE_I2C) - if (PIOS_I2C_Init(&pios_i2c_flexi_adapter_id, &pios_i2c_flexi_adapter_cfg)) { - PIOS_Assert(0); - } + if (PIOS_I2C_Init(&pios_i2c_flexi_adapter_id, &pios_i2c_flexi_adapter_cfg)) { + PIOS_Assert(0); + } #endif /* PIOS_INCLUDE_I2C */ - break; - case HWSETTINGS_CC_FLEXIPORT_PPM: + break; + case HWSETTINGS_CC_FLEXIPORT_PPM: #if defined(PIOS_INCLUDE_PPM_FLEXI) - PIOS_BOARD_IO_Configure_PPM(&pios_ppm_flexi_cfg); + PIOS_BOARD_IO_Configure_PPM(&pios_ppm_flexi_cfg); #endif /* PIOS_INCLUDE_PPM_FLEXI */ - break; + break; } /* Configure main USART port */ - + /* Initialize inverter gpio and set it to off */ { GPIO_InitTypeDef inverterGPIOInit = { @@ -262,16 +260,16 @@ void PIOS_Board_Init(void) .GPIO_Mode = GPIO_Mode_Out_PP, .GPIO_Speed = GPIO_Speed_2MHz, }; - + GPIO_Init(MAIN_USART_INVERTER_GPIO, &inverterGPIOInit); GPIO_WriteBit(MAIN_USART_INVERTER_GPIO, MAIN_USART_INVERTER_PIN, MAIN_USART_INVERTER_DISABLE); } - + uint8_t hwsettings_mainport; HwSettingsCC_MainPortGet(&hwsettings_mainport); - + if (hwsettings_mainport < NELEMENTS(main_function_map)) { PIOS_BOARD_IO_Configure_UART(&pios_usart_main_cfg, main_function_map[hwsettings_mainport]); } @@ -298,7 +296,7 @@ void PIOS_Board_Init(void) case HWSETTINGS_CC_RCVRPORT_PPMOUTPUTSNOONESHOT: case HWSETTINGS_CC_RCVRPORT_PPM_PIN8ONESHOT: #if defined(PIOS_INCLUDE_PPM) - PIOS_BOARD_IO_Configure_PPM((hwsettings_rcvrport == HWSETTINGS_CC_RCVRPORT_PPM_PIN8ONESHOT) ? &pios_ppm_pin8_cfg : &pios_ppm_cfg); + PIOS_BOARD_IO_Configure_PPM((hwsettings_rcvrport == HWSETTINGS_CC_RCVRPORT_PPM_PIN8ONESHOT) ? &pios_ppm_pin8_cfg : &pios_ppm_cfg); #endif /* PIOS_INCLUDE_PPM */ break; case HWSETTINGS_CC_RCVRPORT_PPMPWMNOONESHOT: @@ -341,33 +339,23 @@ void PIOS_Board_Init(void) switch (bdinfo->board_rev) { case BOARD_REVISION_CC: - // Revision 1 with invensense gyros, start the ADC -#if defined(PIOS_INCLUDE_ADC) - PIOS_ADC_Init(&pios_adc_cfg); -#endif -#if defined(PIOS_INCLUDE_ADXL345) - PIOS_ADXL345_Init(pios_spi_flash_accel_id, 0); -#endif break; case BOARD_REVISION_CC3D: // Revision 2 with MPU6000 gyros, start a SPI interface and connect to it GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE); -#if defined(PIOS_INCLUDE_MPU6000) - // Set up the SPI interface to the serial flash - if (PIOS_SPI_Init(&pios_spi_gyro_id, &pios_spi_gyro_cfg)) { + // Set up the SPI interface to the mpu6000 + if (PIOS_SPI_Init(&pios_spi_gyro_adapter_id, &pios_spi_gyro_cfg)) { PIOS_Assert(0); } - PIOS_MPU6000_Init(pios_spi_gyro_id, 0, &pios_mpu6000_cfg); - PIOS_MPU6000_CONFIG_Configure(); - init_test = !PIOS_MPU6000_Driver.test(0); -#endif /* PIOS_INCLUDE_MPU6000 */ break; default: PIOS_Assert(0); } + PIOS_BOARD_Sensors_Configure(); + /* Make sure we have at least one telemetry link configured or else fail initialization */ PIOS_Assert(pios_com_telem_rf_id || pios_com_telem_usb_id); diff --git a/flight/targets/boards/coptercontrol/pios_board.h b/flight/targets/boards/coptercontrol/pios_board.h index f01fe9cc81..b256057499 100644 --- a/flight/targets/boards/coptercontrol/pios_board.h +++ b/flight/targets/boards/coptercontrol/pios_board.h @@ -116,19 +116,23 @@ extern uint32_t pios_i2c_flexi_adapter_id; // // See also pios_board.c // ------------------------- -#define PIOS_SPI_MAX_DEVS 2 +#define PIOS_SPI_MAX_DEVS 2 +extern uint32_t pios_spi_gyro_adapter_id; +#define PIOS_SPI_MPU6000_ADAPTER (pios_spi_gyro_adapter_id) +extern uint32_t pios_spi_flash_accel_adapter_id; +#define PIOS_SPI_ADXL345_ADAPTER (pios_spi_flash_accel_adapter_id) // ------------------------- // PIOS_USART // ------------------------- -#define PIOS_USART_MAX_DEVS 2 +#define PIOS_USART_MAX_DEVS 2 // ------------------------- // PIOS_COM // // See also pios_board.c // ------------------------- -#define PIOS_COM_MAX_DEVS 3 +#define PIOS_COM_MAX_DEVS 3 #define PIOS_COM_TELEM_RF_RX_BUF_LEN 32 #define PIOS_COM_TELEM_RF_TX_BUF_LEN 12 diff --git a/flight/targets/boards/discoveryf4bare/board_hw_defs.c b/flight/targets/boards/discoveryf4bare/board_hw_defs.c index 678a1500a4..bcae0c028b 100644 --- a/flight/targets/boards/discoveryf4bare/board_hw_defs.c +++ b/flight/targets/boards/discoveryf4bare/board_hw_defs.c @@ -343,15 +343,15 @@ static const struct pios_spi_cfg pios_spi_gyro_cfg = { } }; -static uint32_t pios_spi_gyro_id; +uint32_t pios_spi_gyro_adapter_id; void PIOS_SPI_gyro_irq_handler(void) { /* Call into the generic code to handle the IRQ for this specific device */ - PIOS_SPI_IRQ_Handler(pios_spi_gyro_id); + PIOS_SPI_IRQ_Handler(pios_spi_gyro_adapter_id); } -#if false +#ifdef PIOS_INCLUDE_RFM22B /* * SPI3 Interface * Used for Flash and the RFM22B @@ -479,11 +479,11 @@ static const struct pios_spi_cfg pios_spi_telem_flash_cfg = { }, }; -uint32_t pios_spi_telem_flash_id; +uint32_t pios_spi_telem_flash_adapter_id; void PIOS_SPI_telem_flash_irq_handler(void) { /* Call into the generic code to handle the IRQ for this specific device */ - PIOS_SPI_IRQ_Handler(pios_spi_telem_flash_id); + PIOS_SPI_IRQ_Handler(pios_spi_telem_flash_adapter_id); } @@ -606,17 +606,17 @@ static const struct flashfs_logfs_cfg flashfs_internal_user_cfg = { * MAIN USART */ // Inverter for SBUS handling -#define MAIN_USART_INVERTER_GPIO GPIOC -#define MAIN_USART_INVERTER_PIN GPIO_Pin_0 -#define MAIN_USART_INVERTER_ENABLE Bit_SET -#define MAIN_USART_INVERTER_DISABLE Bit_RESET +#define MAIN_USART_INVERTER_GPIO GPIOC +#define MAIN_USART_INVERTER_PIN GPIO_Pin_0 +#define MAIN_USART_INVERTER_ENABLE Bit_SET +#define MAIN_USART_INVERTER_DISABLE Bit_RESET static int32_t PIOS_BOARD_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param); static const struct pios_usart_cfg pios_usart_main_cfg = { .regs = USART1, .remap = GPIO_AF_USART1, - .rx = { + .rx = { .gpio = GPIOA, .init = { .GPIO_Pin = GPIO_Pin_10, @@ -626,7 +626,7 @@ static const struct pios_usart_cfg pios_usart_main_cfg = { .GPIO_PuPd = GPIO_PuPd_UP }, }, - .tx = { + .tx = { .gpio = GPIOA, .init = { .GPIO_Pin = GPIO_Pin_9, @@ -636,7 +636,7 @@ static const struct pios_usart_cfg pios_usart_main_cfg = { .GPIO_PuPd = GPIO_PuPd_UP }, }, - .ioctl = PIOS_BOARD_USART_Ioctl, + .ioctl = PIOS_BOARD_USART_Ioctl, }; /* @@ -645,7 +645,7 @@ static const struct pios_usart_cfg pios_usart_main_cfg = { static const struct pios_usart_cfg pios_usart_flexi_cfg = { .regs = USART3, .remap = GPIO_AF_USART3, - .rx = { + .rx = { .gpio = GPIOB, .init = { .GPIO_Pin = GPIO_Pin_11, @@ -655,7 +655,7 @@ static const struct pios_usart_cfg pios_usart_flexi_cfg = { .GPIO_PuPd = GPIO_PuPd_UP }, }, - .tx = { + .tx = { .gpio = GPIOB, .init = { .GPIO_Pin = GPIO_Pin_10, @@ -671,7 +671,7 @@ static const struct pios_usart_cfg pios_usart_flexi_cfg = { static const struct pios_usart_cfg pios_usart_flexiio_cfg = { .regs = USART6, .remap = GPIO_AF_USART6, - .dtr = { + .dtr = { // FlexIO pin 9 .gpio = GPIOC, .init = { @@ -682,7 +682,7 @@ static const struct pios_usart_cfg pios_usart_flexiio_cfg = { }, }, - .tx = { + .tx = { // * 7: PC6 = TIM8 CH1, USART6 TX .gpio = GPIOC, .init = { @@ -692,10 +692,10 @@ static const struct pios_usart_cfg pios_usart_flexiio_cfg = { .GPIO_OType = GPIO_OType_PP, .GPIO_PuPd = GPIO_PuPd_UP }, - .pin_source = GPIO_PinSource6, + .pin_source = GPIO_PinSource6, }, - .rx = { + .rx = { // * 8: PC7 = TIM8 CH2, USART6 RX .gpio = GPIOC, .init = { @@ -705,7 +705,7 @@ static const struct pios_usart_cfg pios_usart_flexiio_cfg = { .GPIO_OType = GPIO_OType_PP, .GPIO_PuPd = GPIO_PuPd_UP }, - .pin_source = GPIO_PinSource7, + .pin_source = GPIO_PinSource7, } }; @@ -1066,18 +1066,18 @@ static const struct pios_tim_clock_cfg tim_12_cfg = { #include static const struct pios_tim_channel pios_tim_servoport_all_pins[] = { - TIM_SERVO_CHANNEL_CONFIG(TIM3, 3, B, 0), - TIM_SERVO_CHANNEL_CONFIG(TIM3, 4, B, 1), - TIM_SERVO_CHANNEL_CONFIG(TIM9, 2, A, 3), - TIM_SERVO_CHANNEL_CONFIG(TIM2, 3, A, 2), - TIM_SERVO_CHANNEL_CONFIG(TIM5, 2, A, 1), - TIM_SERVO_CHANNEL_CONFIG(TIM5, 1, A, 0), + TIM_SERVO_CHANNEL_CONFIG(TIM3, 3, B, 0), + TIM_SERVO_CHANNEL_CONFIG(TIM3, 4, B, 1), + TIM_SERVO_CHANNEL_CONFIG(TIM9, 2, A, 3), + TIM_SERVO_CHANNEL_CONFIG(TIM2, 3, A, 2), + TIM_SERVO_CHANNEL_CONFIG(TIM5, 2, A, 1), + TIM_SERVO_CHANNEL_CONFIG(TIM5, 1, A, 0), // PWM pins on FlexiIO(receiver) port TIM_SERVO_CHANNEL_CONFIG(TIM12, 2, B, 15), // * 6: PB15 = SPI2 MOSI, TIM12 CH2 - TIM_SERVO_CHANNEL_CONFIG(TIM8, 1, C, 6), // * 7: PC6 = TIM8 CH1, USART6 TX - TIM_SERVO_CHANNEL_CONFIG(TIM8, 2, C, 7), // * 8: PC7 = TIM8 CH2, USART6 RX - TIM_SERVO_CHANNEL_CONFIG(TIM8, 3, C, 8), // * 9: PC8 = TIM8 CH3 - TIM_SERVO_CHANNEL_CONFIG(TIM8, 4, C, 9), // * 10: PC9 = TIM8 CH4 + TIM_SERVO_CHANNEL_CONFIG(TIM8, 1, C, 6), // * 7: PC6 = TIM8 CH1, USART6 TX + TIM_SERVO_CHANNEL_CONFIG(TIM8, 2, C, 7), // * 8: PC7 = TIM8 CH2, USART6 RX + TIM_SERVO_CHANNEL_CONFIG(TIM8, 3, C, 8), // * 9: PC8 = TIM8 CH3 + TIM_SERVO_CHANNEL_CONFIG(TIM8, 4, C, 9), // * 10: PC9 = TIM8 CH4 TIM_SERVO_CHANNEL_CONFIG(TIM12, 1, B, 14), // * 5: PB14 = SPI2 MISO, TIM12 CH1, USART3 RTS }; @@ -1140,10 +1140,10 @@ const struct pios_servo_cfg pios_servo_cfg_out_in = { static const struct pios_tim_channel pios_tim_rcvrport_all_channels[] = { TIM_SERVO_CHANNEL_CONFIG(TIM12, 1, B, 14), TIM_SERVO_CHANNEL_CONFIG(TIM12, 2, B, 15), - TIM_SERVO_CHANNEL_CONFIG(TIM8, 1, C, 6), - TIM_SERVO_CHANNEL_CONFIG(TIM8, 2, C, 7), - TIM_SERVO_CHANNEL_CONFIG(TIM8, 3, C, 8), - TIM_SERVO_CHANNEL_CONFIG(TIM8, 4, C, 9), + TIM_SERVO_CHANNEL_CONFIG(TIM8, 1, C, 6), + TIM_SERVO_CHANNEL_CONFIG(TIM8, 2, C, 7), + TIM_SERVO_CHANNEL_CONFIG(TIM8, 3, C, 8), + TIM_SERVO_CHANNEL_CONFIG(TIM8, 4, C, 9), }; const struct pios_pwm_cfg pios_pwm_cfg = { @@ -1448,7 +1448,6 @@ const struct pios_ms5611_cfg *PIOS_BOARD_HW_DEFS_GetMS5611Cfg(__attribute__((unu */ #if defined(PIOS_INCLUDE_MPU6000) #include "pios_mpu6000.h" -#include "pios_mpu6000_config.h" static const struct pios_exti_cfg pios_exti_mpu6000_cfg __exti_config = { .vector = PIOS_MPU6000_IRQHandler, .line = EXTI_Line4, @@ -1496,6 +1495,10 @@ static const struct pios_mpu6000_cfg pios_mpu6000_cfg = { .filter = PIOS_MPU6000_LOWPASS_256_HZ, .orientation = PIOS_MPU6000_TOP_180DEG }; -#endif /* PIOS_INCLUDE_MPU6000 */ +const struct pios_mpu6000_cfg *PIOS_BOARD_HW_DEFS_GetMPU6000Cfg(__attribute__((unused)) uint32_t board_revision) +{ + return &pios_mpu6000_cfg; +} +#endif /* PIOS_INCLUDE_MPU6000 */ diff --git a/flight/targets/boards/discoveryf4bare/bootloader/main.c b/flight/targets/boards/discoveryf4bare/bootloader/main.c index 09a54a0947..aa5c7999a5 100644 --- a/flight/targets/boards/discoveryf4bare/bootloader/main.c +++ b/flight/targets/boards/discoveryf4bare/bootloader/main.c @@ -35,6 +35,7 @@ #include /* PIOS_USBHOOK_* */ #include #include +#include extern void FLASH_Download(); void check_bor(); diff --git a/flight/targets/boards/discoveryf4bare/firmware/pios_board.c b/flight/targets/boards/discoveryf4bare/firmware/pios_board.c index 7e8c49c521..5ffc19ec6c 100644 --- a/flight/targets/boards/discoveryf4bare/firmware/pios_board.c +++ b/flight/targets/boards/discoveryf4bare/firmware/pios_board.c @@ -39,6 +39,7 @@ #endif #include +#include /* * Pull in the board-specific static HW definitions. @@ -101,25 +102,25 @@ static const PIOS_BOARD_IO_UART_Function flexi_function_map[] = { static const PIOS_BOARD_IO_RADIOAUX_Function radioaux_function_map[] = { [HWSETTINGS_RADIOAUXSTREAM_DEBUGCONSOLE] = PIOS_BOARD_IO_RADIOAUX_DEBUGCONSOLE, [HWSETTINGS_RADIOAUXSTREAM_MAVLINK] = PIOS_BOARD_IO_RADIOAUX_MAVLINK, - [HWSETTINGS_RADIOAUXSTREAM_COMBRIDGE] = PIOS_BOARD_IO_RADIOAUX_COMBRIDGE, + [HWSETTINGS_RADIOAUXSTREAM_COMBRIDGE] = PIOS_BOARD_IO_RADIOAUX_COMBRIDGE, }; int32_t PIOS_BOARD_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param) { const struct pios_usart_cfg *usart_cfg = PIOS_USART_GetConfig(usart_id); - + switch (ctl) { - case PIOS_IOCTL_USART_SET_INVERTED: - if (usart_cfg->regs == pios_usart_main_cfg.regs) { /* main port */ - GPIO_WriteBit(MAIN_USART_INVERTER_GPIO, - MAIN_USART_INVERTER_PIN, - (*(enum PIOS_USART_Inverted *)param & PIOS_USART_Inverted_Rx) ? MAIN_USART_INVERTER_ENABLE : MAIN_USART_INVERTER_DISABLE); - - return 0; - } - break; + case PIOS_IOCTL_USART_SET_INVERTED: + if (usart_cfg->regs == pios_usart_main_cfg.regs) { /* main port */ + GPIO_WriteBit(MAIN_USART_INVERTER_GPIO, + MAIN_USART_INVERTER_PIN, + (*(enum PIOS_USART_Inverted *)param & PIOS_USART_Inverted_Rx) ? MAIN_USART_INVERTER_ENABLE : MAIN_USART_INVERTER_DISABLE); + + return 0; + } + break; } - + return -1; } @@ -143,17 +144,20 @@ void PIOS_Board_Init(void) #endif -#if false +#ifdef PIOS_INCLUDE_MPU6000 /* Set up the SPI interface to the gyro/acelerometer */ - if (PIOS_SPI_Init(&pios_spi_gyro_id, &pios_spi_gyro_cfg)) { + if (PIOS_SPI_Init(&pios_spi_gyro_adapter_id, &pios_spi_gyro_cfg)) { PIOS_DEBUG_Assert(0); } +#endif /* PIOS_INCLUDE_MPU6000 */ - /* Set up the SPI interface to the flash and rfm22b */ - if (PIOS_SPI_Init(&pios_spi_telem_flash_id, &pios_spi_telem_flash_cfg)) { +#ifdef PIOS_INCLUDE_RFM22B + /* Set up the SPI interface to the rfm22b */ + if (PIOS_SPI_Init(&pios_spi_telem_flash_adapter_id, &pios_spi_telem_flash_cfg)) { PIOS_DEBUG_Assert(0); } -#endif +#endif /* PIOS_INCLUDE_RFM22B */ + #if defined(PIOS_INCLUDE_FLASH) /* Connect flash to the appropriate interface and configure it */ uintptr_t flash_id; @@ -229,30 +233,28 @@ void PIOS_Board_Init(void) } /* Configure IO ports */ - + /* Configure FlexiPort */ uint8_t hwsettings_flexiport; HwSettingsRM_FlexiPortGet(&hwsettings_flexiport); - + if (hwsettings_flexiport < NELEMENTS(flexi_function_map)) { PIOS_BOARD_IO_Configure_UART(&pios_usart_flexi_cfg, flexi_function_map[hwsettings_flexiport]); } - + #if defined(PIOS_INCLUDE_I2C) /* Set up internal I2C bus */ if (PIOS_I2C_Init(&pios_i2c_mag_pressure_adapter_id, &pios_i2c_mag_pressure_adapter_cfg)) { PIOS_DEBUG_Assert(0); } PIOS_DELAY_WaitmS(50); - + if (hwsettings_flexiport == HWSETTINGS_RM_FLEXIPORT_I2C) { if (PIOS_I2C_Init(&pios_i2c_flexiport_adapter_id, &pios_i2c_flexiport_adapter_cfg)) { PIOS_Assert(0); } PIOS_DELAY_WaitmS(50); } - - PIOS_BOARD_IO_Configure_I2C(pios_i2c_mag_pressure_adapter_id, pios_i2c_flexiport_adapter_id); #endif #if defined(PIOS_INCLUDE_USB) @@ -260,7 +262,7 @@ void PIOS_Board_Init(void) #endif /* Configure main USART port */ - + /* Initialize inverter gpio and set it to off */ { GPIO_InitTypeDef inverterGPIOInit = { @@ -270,30 +272,30 @@ void PIOS_Board_Init(void) .GPIO_OType = GPIO_OType_PP, .GPIO_PuPd = GPIO_PuPd_UP }; - + GPIO_Init(MAIN_USART_INVERTER_GPIO, &inverterGPIOInit); GPIO_WriteBit(MAIN_USART_INVERTER_GPIO, MAIN_USART_INVERTER_PIN, MAIN_USART_INVERTER_DISABLE); } - + uint8_t hwsettings_mainport; HwSettingsRM_MainPortGet(&hwsettings_mainport); - + if (hwsettings_mainport < NELEMENTS(main_function_map)) { PIOS_BOARD_IO_Configure_UART(&pios_usart_main_cfg, main_function_map[hwsettings_mainport]); } - + #if defined(PIOS_INCLUDE_RFM22B) uint8_t hwsettings_radioaux; HwSettingsRadioAuxStreamGet(&hwsettings_radioaux); - if(hwsettings_radioaux < NELEMENTS(radioaux_function_map)) { + if (hwsettings_radioaux < NELEMENTS(radioaux_function_map)) { PIOS_BOARD_IO_Configure_RFM22B(pios_spi_telem_flash_id, radioaux_function_map[hwsettings_radioaux]); } #endif /* PIOS_INCLUDE_RFM22B */ - + #if defined(PIOS_INCLUDE_PWM) || defined(PIOS_INCLUDE_PPM) const struct pios_servo_cfg *pios_servo_cfg; @@ -304,47 +306,47 @@ void PIOS_Board_Init(void) /* Configure the receiver port*/ uint8_t hwsettings_rcvrport; HwSettingsRM_RcvrPortGet(&hwsettings_rcvrport); - + if (hwsettings_rcvrport < NELEMENTS(flexiio_function_map)) { PIOS_BOARD_IO_Configure_UART(&pios_usart_flexiio_cfg, flexiio_function_map[hwsettings_rcvrport]); } - + // Configure rcvrport PPM/PWM/OUTPUTS switch (hwsettings_rcvrport) { - case HWSETTINGS_RM_RCVRPORT_PWM: + case HWSETTINGS_RM_RCVRPORT_PWM: #if defined(PIOS_INCLUDE_PWM) - /* Set up the receiver port. Later this should be optional */ - PIOS_BOARD_IO_Configure_PWM(&pios_pwm_cfg); + /* Set up the receiver port. Later this should be optional */ + PIOS_BOARD_IO_Configure_PWM(&pios_pwm_cfg); #endif /* PIOS_INCLUDE_PWM */ - break; - case HWSETTINGS_RM_RCVRPORT_PPM: - case HWSETTINGS_RM_RCVRPORT_PPMOUTPUTS: - case HWSETTINGS_RM_RCVRPORT_PPMPWM: - case HWSETTINGS_RM_RCVRPORT_PPMTELEMETRY: - case HWSETTINGS_RM_RCVRPORT_PPMDEBUGCONSOLE: - case HWSETTINGS_RM_RCVRPORT_PPMCOMBRIDGE: - case HWSETTINGS_RM_RCVRPORT_PPMMSP: - case HWSETTINGS_RM_RCVRPORT_PPMMAVLINK: - case HWSETTINGS_RM_RCVRPORT_PPMGPS: + break; + case HWSETTINGS_RM_RCVRPORT_PPM: + case HWSETTINGS_RM_RCVRPORT_PPMOUTPUTS: + case HWSETTINGS_RM_RCVRPORT_PPMPWM: + case HWSETTINGS_RM_RCVRPORT_PPMTELEMETRY: + case HWSETTINGS_RM_RCVRPORT_PPMDEBUGCONSOLE: + case HWSETTINGS_RM_RCVRPORT_PPMCOMBRIDGE: + case HWSETTINGS_RM_RCVRPORT_PPMMSP: + case HWSETTINGS_RM_RCVRPORT_PPMMAVLINK: + case HWSETTINGS_RM_RCVRPORT_PPMGPS: #if defined(PIOS_INCLUDE_PPM) - PIOS_BOARD_IO_Configure_PPM(&pios_ppm_cfg); - - if (hwsettings_rcvrport == HWSETTINGS_RM_RCVRPORT_PPMOUTPUTS) { - // configure servo outputs and the remaining 5 inputs as outputs - pios_servo_cfg = &pios_servo_cfg_out_in_ppm; - } - - // enable pwm on the remaining channels - if (hwsettings_rcvrport == HWSETTINGS_RM_RCVRPORT_PPMPWM) { - PIOS_BOARD_IO_Configure_PWM(&pios_pwm_ppm_cfg); - } - - break; + PIOS_BOARD_IO_Configure_PPM(&pios_ppm_cfg); + + if (hwsettings_rcvrport == HWSETTINGS_RM_RCVRPORT_PPMOUTPUTS) { + // configure servo outputs and the remaining 5 inputs as outputs + pios_servo_cfg = &pios_servo_cfg_out_in_ppm; + } + + // enable pwm on the remaining channels + if (hwsettings_rcvrport == HWSETTINGS_RM_RCVRPORT_PPMPWM) { + PIOS_BOARD_IO_Configure_PWM(&pios_pwm_ppm_cfg); + } + + break; #endif /* PIOS_INCLUDE_PPM */ - case HWSETTINGS_RM_RCVRPORT_OUTPUTS: - // configure only the servo outputs - pios_servo_cfg = &pios_servo_cfg_out_in; - break; + case HWSETTINGS_RM_RCVRPORT_OUTPUTS: + // configure only the servo outputs + pios_servo_cfg = &pios_servo_cfg_out_in; + break; } #ifdef PIOS_INCLUDE_GCSRCVR PIOS_BOARD_IO_Configure_GCSRCVR(); @@ -357,16 +359,12 @@ void PIOS_Board_Init(void) PIOS_DEBUG_Init(pios_tim_servoport_all_pins, NELEMENTS(pios_tim_servoport_all_pins)); #endif -#if defined(PIOS_INCLUDE_MPU6000) - PIOS_MPU6000_Init(pios_spi_gyro_id, 0, &pios_mpu6000_cfg); - PIOS_MPU6000_CONFIG_Configure(); - PIOS_MPU6000_Register(); -#endif - + PIOS_BOARD_Sensors_Configure(); + #ifdef PIOS_INCLUDE_WS2811 PIOS_WS2811_Init(&pios_ws2811_cfg, &pios_ws2811_pin_cfg); #endif // PIOS_INCLUDE_WS2811 - + #ifdef PIOS_INCLUDE_ADC // Disable GPIO_A8 Pullup to prevent wrong results on battery voltage readout GPIO_InitTypeDef gpioA8 = { @@ -377,8 +375,6 @@ void PIOS_Board_Init(void) .GPIO_OType = GPIO_OType_OD, }; GPIO_Init(GPIOA, &gpioA8); - - PIOS_BOARD_IO_Configure_ADC(); #endif // PIOS_INCLUDE_ADC } diff --git a/flight/targets/boards/discoveryf4bare/pios_board.h b/flight/targets/boards/discoveryf4bare/pios_board.h index 4b129899d5..9c3d1ba73f 100644 --- a/flight/targets/boards/discoveryf4bare/pios_board.h +++ b/flight/targets/boards/discoveryf4bare/pios_board.h @@ -85,29 +85,34 @@ // PIOS_SPI // See also pios_board.c // ------------------------ -#define PIOS_SPI_MAX_DEVS 3 +#define PIOS_SPI_MAX_DEVS 3 +extern uint32_t pios_spi_telem_flash_adapter_id; +#define PIOS_SPI_RFM22B_ADAPTER (pios_spi_telem_flash_adapter_id) +extern uint32_t pios_spi_gyro_adapter_id; +#define PIOS_SPI_MPU6000_ADAPTER (pios_spi_gyro_adapter_id) // ------------------------ // PIOS_WDG // ------------------------ -#define PIOS_WATCHDOG_TIMEOUT 250 -#define PIOS_WDG_REGISTER RTC_BKP_DR4 -#define PIOS_WDG_ACTUATOR 0x0001 -#define PIOS_WDG_STABILIZATION 0x0002 -#define PIOS_WDG_ATTITUDE 0x0004 -#define PIOS_WDG_MANUAL 0x0008 -#define PIOS_WDG_SENSORS 0x0010 +#define PIOS_WATCHDOG_TIMEOUT 250 +#define PIOS_WDG_REGISTER RTC_BKP_DR4 +#define PIOS_WDG_ACTUATOR 0x0001 +#define PIOS_WDG_STABILIZATION 0x0002 +#define PIOS_WDG_ATTITUDE 0x0004 +#define PIOS_WDG_MANUAL 0x0008 +#define PIOS_WDG_SENSORS 0x0010 // ------------------------ // PIOS_I2C // See also pios_board.c // ------------------------ -#define PIOS_I2C_MAX_DEVS 3 +#define PIOS_I2C_MAX_DEVS 3 extern uint32_t pios_i2c_mag_pressure_adapter_id; -#define PIOS_I2C_MAIN_ADAPTER (pios_i2c_mag_pressure_adapter_id) +#define PIOS_I2C_HMC5X83_INTERNAL_ADAPTER (pios_i2c_mag_pressure_adapter_id) extern uint32_t pios_i2c_flexiport_adapter_id; -#define PIOS_I2C_FLEXI_ADAPTER (pios_i2c_flexiport_adapter_id) -#define PIOS_I2C_ETASV3_ADAPTER (PIOS_I2C_FLEXI_ADAPTER) +#define PIOS_I2C_FLEXI_ADAPTER (pios_i2c_flexiport_adapter_id) +#define PIOS_I2C_ETASV3_ADAPTER (PIOS_I2C_FLEXI_ADAPTER) +#define PIOS_I2C_EXTERNAL_ADAPTER (PIOS_I2C_FLEXI_ADAPTER) // ------------------------- // PIOS_USART @@ -121,7 +126,7 @@ extern uint32_t pios_i2c_flexiport_adapter_id; // // See also pios_board.c // ------------------------- -#define PIOS_COM_MAX_DEVS 4 +#define PIOS_COM_MAX_DEVS 4 // ------------------------- // Packet Handler diff --git a/flight/targets/boards/oplinkmini/board_hw_defs.c b/flight/targets/boards/oplinkmini/board_hw_defs.c index d05d3dbfbd..0810721cb1 100644 --- a/flight/targets/boards/oplinkmini/board_hw_defs.c +++ b/flight/targets/boards/oplinkmini/board_hw_defs.c @@ -693,7 +693,7 @@ const struct pios_ppm_out_cfg pios_flexi_ppm_out_cfg = { */ static const struct pios_usart_cfg pios_usart_main_cfg = { .regs = USART1, - .rx = { + .rx = { .gpio = GPIOA, .init = { .GPIO_Pin = GPIO_Pin_10, @@ -701,7 +701,7 @@ static const struct pios_usart_cfg pios_usart_main_cfg = { .GPIO_Mode = GPIO_Mode_IPU, }, }, - .tx = { + .tx = { .gpio = GPIOA, .init = { .GPIO_Pin = GPIO_Pin_9, @@ -713,7 +713,7 @@ static const struct pios_usart_cfg pios_usart_main_cfg = { static const struct pios_usart_cfg pios_usart_flexi_cfg = { .regs = USART3, - .rx = { + .rx = { .gpio = GPIOB, .init = { .GPIO_Pin = GPIO_Pin_11, @@ -721,7 +721,7 @@ static const struct pios_usart_cfg pios_usart_flexi_cfg = { .GPIO_Mode = GPIO_Mode_IPU, }, }, - .tx = { + .tx = { .gpio = GPIOB, .init = { .GPIO_Pin = GPIO_Pin_10, diff --git a/flight/targets/boards/revolution/board_hw_defs.c b/flight/targets/boards/revolution/board_hw_defs.c index 7e040bdb91..6edf839f95 100644 --- a/flight/targets/boards/revolution/board_hw_defs.c +++ b/flight/targets/boards/revolution/board_hw_defs.c @@ -464,11 +464,11 @@ static const struct pios_spi_cfg pios_spi_gyro_cfg = { } }; -static uint32_t pios_spi_gyro_id; +uint32_t pios_spi_gyro_adapter_id; void PIOS_SPI_gyro_irq_handler(void) { /* Call into the generic code to handle the IRQ for this specific device */ - PIOS_SPI_IRQ_Handler(pios_spi_gyro_id); + PIOS_SPI_IRQ_Handler(pios_spi_gyro_adapter_id); } @@ -599,11 +599,11 @@ static const struct pios_spi_cfg pios_spi_telem_flash_cfg = { }, }; -uint32_t pios_spi_telem_flash_id; +uint32_t pios_spi_telem_flash_adapter_id; void PIOS_SPI_telem_flash_irq_handler(void) { /* Call into the generic code to handle the IRQ for this specific device */ - PIOS_SPI_IRQ_Handler(pios_spi_telem_flash_id); + PIOS_SPI_IRQ_Handler(pios_spi_telem_flash_adapter_id); } @@ -794,10 +794,10 @@ static const struct flashfs_logfs_cfg flashfs_internal_cfg = { */ // Inverter for SBUS handling -#define MAIN_USART_INVERTER_GPIO GPIOC -#define MAIN_USART_INVERTER_PIN GPIO_Pin_0 -#define MAIN_USART_INVERTER_ENABLE Bit_SET -#define MAIN_USART_INVERTER_DISABLE Bit_RESET +#define MAIN_USART_INVERTER_GPIO GPIOC +#define MAIN_USART_INVERTER_PIN GPIO_Pin_0 +#define MAIN_USART_INVERTER_ENABLE Bit_SET +#define MAIN_USART_INVERTER_DISABLE Bit_RESET static int32_t PIOS_BOARD_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param); @@ -1254,18 +1254,18 @@ static const struct pios_tim_clock_cfg tim_12_cfg = { #include static const struct pios_tim_channel pios_tim_servoport_all_pins[] = { - TIM_SERVO_CHANNEL_CONFIG(TIM3, 3, B, 0), - TIM_SERVO_CHANNEL_CONFIG(TIM3, 4, B, 1), - TIM_SERVO_CHANNEL_CONFIG(TIM9, 2, A, 3), - TIM_SERVO_CHANNEL_CONFIG(TIM2, 3, A, 2), - TIM_SERVO_CHANNEL_CONFIG(TIM5, 2, A, 1), - TIM_SERVO_CHANNEL_CONFIG(TIM5, 1, A, 0), + TIM_SERVO_CHANNEL_CONFIG(TIM3, 3, B, 0), + TIM_SERVO_CHANNEL_CONFIG(TIM3, 4, B, 1), + TIM_SERVO_CHANNEL_CONFIG(TIM9, 2, A, 3), + TIM_SERVO_CHANNEL_CONFIG(TIM2, 3, A, 2), + TIM_SERVO_CHANNEL_CONFIG(TIM5, 2, A, 1), + TIM_SERVO_CHANNEL_CONFIG(TIM5, 1, A, 0), // PWM pins on FlexiIO(receiver) port TIM_SERVO_CHANNEL_CONFIG(TIM12, 2, B, 15), // * 6: PB15 = SPI2 MOSI, TIM12 CH2 - TIM_SERVO_CHANNEL_CONFIG(TIM8, 1, C, 6), // * 7: PC6 = TIM8 CH1, USART6 TX - TIM_SERVO_CHANNEL_CONFIG(TIM8, 2, C, 7), // * 8: PC7 = TIM8 CH2, USART6 RX - TIM_SERVO_CHANNEL_CONFIG(TIM8, 3, C, 8), // * 9: PC8 = TIM8 CH3 - TIM_SERVO_CHANNEL_CONFIG(TIM8, 4, C, 9), // * 10: PC9 = TIM8 CH4 + TIM_SERVO_CHANNEL_CONFIG(TIM8, 1, C, 6), // * 7: PC6 = TIM8 CH1, USART6 TX + TIM_SERVO_CHANNEL_CONFIG(TIM8, 2, C, 7), // * 8: PC7 = TIM8 CH2, USART6 RX + TIM_SERVO_CHANNEL_CONFIG(TIM8, 3, C, 8), // * 9: PC8 = TIM8 CH3 + TIM_SERVO_CHANNEL_CONFIG(TIM8, 4, C, 9), // * 10: PC9 = TIM8 CH4 TIM_SERVO_CHANNEL_CONFIG(TIM12, 1, B, 14), // * 5: PB14 = SPI2 MISO, TIM12 CH1, USART3 RTS }; @@ -1328,10 +1328,10 @@ const struct pios_servo_cfg pios_servo_cfg_out_in = { static const struct pios_tim_channel pios_tim_rcvrport_all_channels[] = { TIM_SERVO_CHANNEL_CONFIG(TIM12, 1, B, 14), TIM_SERVO_CHANNEL_CONFIG(TIM12, 2, B, 15), - TIM_SERVO_CHANNEL_CONFIG(TIM8, 1, C, 6), - TIM_SERVO_CHANNEL_CONFIG(TIM8, 2, C, 7), - TIM_SERVO_CHANNEL_CONFIG(TIM8, 3, C, 8), - TIM_SERVO_CHANNEL_CONFIG(TIM8, 4, C, 9), + TIM_SERVO_CHANNEL_CONFIG(TIM8, 1, C, 6), + TIM_SERVO_CHANNEL_CONFIG(TIM8, 2, C, 7), + TIM_SERVO_CHANNEL_CONFIG(TIM8, 3, C, 8), + TIM_SERVO_CHANNEL_CONFIG(TIM8, 4, C, 9), }; const struct pios_pwm_cfg pios_pwm_cfg = { @@ -1738,7 +1738,6 @@ const struct pios_ms5611_cfg *PIOS_BOARD_HW_DEFS_GetMS5611Cfg(__attribute__((unu */ #if defined(PIOS_INCLUDE_MPU6000) #include "pios_mpu6000.h" -#include "pios_mpu6000_config.h" static const struct pios_exti_cfg pios_exti_mpu6000_cfg __exti_config = { .vector = PIOS_MPU6000_IRQHandler, .line = EXTI_Line4, @@ -1789,4 +1788,10 @@ static const struct pios_mpu6000_cfg pios_mpu6000_cfg = { .std_prescaler = PIOS_SPI_PRESCALER_64, .max_downsample = 20, }; + +const struct pios_mpu6000_cfg *PIOS_BOARD_HW_DEFS_GetMPU6000Cfg(__attribute__((unused)) uint32_t board_revision) +{ + return &pios_mpu6000_cfg; +} + #endif /* PIOS_INCLUDE_MPU6000 */ diff --git a/flight/targets/boards/revolution/firmware/pios_board.c b/flight/targets/boards/revolution/firmware/pios_board.c index 60bdfce814..47279154e7 100644 --- a/flight/targets/boards/revolution/firmware/pios_board.c +++ b/flight/targets/boards/revolution/firmware/pios_board.c @@ -38,6 +38,7 @@ #endif #include +#include /* * Pull in the board-specific static HW definitions. @@ -100,7 +101,7 @@ static const PIOS_BOARD_IO_UART_Function flexi_function_map[] = { static const PIOS_BOARD_IO_RADIOAUX_Function radioaux_function_map[] = { [HWSETTINGS_RADIOAUXSTREAM_DEBUGCONSOLE] = PIOS_BOARD_IO_RADIOAUX_DEBUGCONSOLE, [HWSETTINGS_RADIOAUXSTREAM_MAVLINK] = PIOS_BOARD_IO_RADIOAUX_MAVLINK, - [HWSETTINGS_RADIOAUXSTREAM_COMBRIDGE] = PIOS_BOARD_IO_RADIOAUX_COMBRIDGE, + [HWSETTINGS_RADIOAUXSTREAM_COMBRIDGE] = PIOS_BOARD_IO_RADIOAUX_COMBRIDGE, }; @@ -143,12 +144,12 @@ void PIOS_Board_Init(void) #endif /* Set up the SPI interface to the gyro/acelerometer */ - if (PIOS_SPI_Init(&pios_spi_gyro_id, &pios_spi_gyro_cfg)) { + if (PIOS_SPI_Init(&pios_spi_gyro_adapter_id, &pios_spi_gyro_cfg)) { PIOS_DEBUG_Assert(0); } /* Set up the SPI interface to the flash and rfm22b */ - if (PIOS_SPI_Init(&pios_spi_telem_flash_id, &pios_spi_telem_flash_cfg)) { + if (PIOS_SPI_Init(&pios_spi_telem_flash_adapter_id, &pios_spi_telem_flash_cfg)) { PIOS_DEBUG_Assert(0); } @@ -157,7 +158,7 @@ void PIOS_Board_Init(void) uintptr_t flash_id; // Initialize the external USER flash - if (PIOS_Flash_Jedec_Init(&flash_id, pios_spi_telem_flash_id, 1)) { + if (PIOS_Flash_Jedec_Init(&flash_id, pios_spi_telem_flash_adapter_id, 1)) { PIOS_DEBUG_Assert(0); } @@ -246,8 +247,6 @@ void PIOS_Board_Init(void) } PIOS_DELAY_WaitmS(50); } - - PIOS_BOARD_IO_Configure_I2C(pios_i2c_mag_pressure_adapter_id, pios_i2c_flexiport_adapter_id); #endif /* Moved this here to allow DSM binding on flexiport */ @@ -273,7 +272,7 @@ void PIOS_Board_Init(void) .GPIO_OType = GPIO_OType_PP, .GPIO_PuPd = GPIO_PuPd_UP }; - + GPIO_Init(MAIN_USART_INVERTER_GPIO, &inverterGPIOInit); GPIO_WriteBit(MAIN_USART_INVERTER_GPIO, MAIN_USART_INVERTER_PIN, @@ -290,9 +289,9 @@ void PIOS_Board_Init(void) #if defined(PIOS_INCLUDE_RFM22B) uint8_t hwsettings_radioaux; HwSettingsRadioAuxStreamGet(&hwsettings_radioaux); - - if(hwsettings_radioaux < NELEMENTS(radioaux_function_map)) { - PIOS_BOARD_IO_Configure_RFM22B(pios_spi_telem_flash_id, radioaux_function_map[hwsettings_radioaux]); + + if (hwsettings_radioaux < NELEMENTS(radioaux_function_map)) { + PIOS_BOARD_IO_Configure_RFM22B(radioaux_function_map[hwsettings_radioaux]); } #endif /* PIOS_INCLUDE_RFM22B */ @@ -359,16 +358,12 @@ void PIOS_Board_Init(void) PIOS_DEBUG_Init(pios_tim_servoport_all_pins, NELEMENTS(pios_tim_servoport_all_pins)); #endif -#if defined(PIOS_INCLUDE_MPU6000) - PIOS_MPU6000_Init(pios_spi_gyro_id, 0, &pios_mpu6000_cfg); - PIOS_MPU6000_CONFIG_Configure(); - PIOS_MPU6000_Register(); -#endif + PIOS_BOARD_Sensors_Configure(); #ifdef PIOS_INCLUDE_WS2811 HwSettingsWS2811LED_OutOptions ws2811_pin_settings; HwSettingsWS2811LED_OutGet(&ws2811_pin_settings); - + if (ws2811_pin_settings != HWSETTINGS_WS2811LED_OUT_DISABLED && ws2811_pin_settings < NELEMENTS(pios_ws2811_pin_cfg)) { PIOS_WS2811_Init(&pios_ws2811_cfg, &pios_ws2811_pin_cfg[ws2811_pin_settings]); } @@ -384,8 +379,6 @@ void PIOS_Board_Init(void) .GPIO_OType = GPIO_OType_OD, }; GPIO_Init(GPIOA, &gpioA8); - - PIOS_BOARD_IO_Configure_ADC(); #endif // PIOS_INCLUDE_ADC DEBUG_PRINTF(2, "Board complete\r\n"); diff --git a/flight/targets/boards/revolution/pios_board.h b/flight/targets/boards/revolution/pios_board.h index 122cdb71f6..6c4f67aaac 100644 --- a/flight/targets/boards/revolution/pios_board.h +++ b/flight/targets/boards/revolution/pios_board.h @@ -103,30 +103,36 @@ // PIOS_SPI // See also pios_board.c // ------------------------ -#define PIOS_SPI_MAX_DEVS 3 +#define PIOS_SPI_MAX_DEVS 3 +extern uint32_t pios_spi_gyro_adapter_id; +#define PIOS_SPI_MPU6000_ADAPTER (pios_spi_gyro_adapter_id) +extern uint32_t pios_spi_telem_flash_adapter_id; +#define PIOS_SPI_RFM22B_ADAPTER (pios_spi_telem_flash_adapter_id) // ------------------------ // PIOS_WDG // ------------------------ -#define PIOS_WATCHDOG_TIMEOUT 250 -#define PIOS_WDG_REGISTER RTC_BKP_DR4 -#define PIOS_WDG_ACTUATOR 0x0001 -#define PIOS_WDG_STABILIZATION 0x0002 -#define PIOS_WDG_ATTITUDE 0x0004 -#define PIOS_WDG_MANUAL 0x0008 -#define PIOS_WDG_SENSORS 0x0010 +#define PIOS_WATCHDOG_TIMEOUT 250 +#define PIOS_WDG_REGISTER RTC_BKP_DR4 +#define PIOS_WDG_ACTUATOR 0x0001 +#define PIOS_WDG_STABILIZATION 0x0002 +#define PIOS_WDG_ATTITUDE 0x0004 +#define PIOS_WDG_MANUAL 0x0008 +#define PIOS_WDG_SENSORS 0x0010 // ------------------------ // PIOS_I2C // See also pios_board.c // ------------------------ -#define PIOS_I2C_MAX_DEVS 3 +#define PIOS_I2C_MAX_DEVS 3 extern uint32_t pios_i2c_mag_pressure_adapter_id; -#define PIOS_I2C_MAIN_ADAPTER (pios_i2c_mag_pressure_adapter_id) +#define PIOS_I2C_HMC5X83_INTERNAL_ADAPTER (pios_i2c_mag_pressure_adapter_id) +#define PIOS_I2C_MS5611_INTERNAL_ADAPTER (pios_i2c_mag_pressure_adapter_id) extern uint32_t pios_i2c_flexiport_adapter_id; -#define PIOS_I2C_FLEXI_ADAPTER (pios_i2c_flexiport_adapter_id) -#define PIOS_I2C_ETASV3_ADAPTER (PIOS_I2C_FLEXI_ADAPTER) -#define PIOS_I2C_MS4525DO_ADAPTER (PIOS_I2C_FLEXI_ADAPTER) +#define PIOS_I2C_FLEXI_ADAPTER (pios_i2c_flexiport_adapter_id) +#define PIOS_I2C_ETASV3_ADAPTER (PIOS_I2C_FLEXI_ADAPTER) +#define PIOS_I2C_MS4525DO_ADAPTER (PIOS_I2C_FLEXI_ADAPTER) +#define PIOS_I2C_EXTERNAL_ADAPTER (PIOS_I2C_FLEXI_ADAPTER) // ------------------------- // PIOS_USART @@ -140,7 +146,7 @@ extern uint32_t pios_i2c_flexiport_adapter_id; // // See also pios_board.c // ------------------------- -#define PIOS_COM_MAX_DEVS 4 +#define PIOS_COM_MAX_DEVS 4 // ------------------------- // Packet Handler diff --git a/flight/targets/boards/revonano/board_hw_defs.c b/flight/targets/boards/revonano/board_hw_defs.c index e84a8cc356..fb4d9f129c 100644 --- a/flight/targets/boards/revonano/board_hw_defs.c +++ b/flight/targets/boards/revonano/board_hw_defs.c @@ -42,29 +42,29 @@ * o5 | PA0 | TIM5_CH1 | ADC1_0 * o6 | PA1 | TIM5_CH2 | ADC1_1 */ -#define MAIN_USART_REGS USART2 -#define MAIN_USART_REMAP GPIO_AF_USART2 -#define MAIN_USART_IRQ USART2_IRQn -#define MAIN_USART_RX_GPIO GPIOA -#define MAIN_USART_RX_PIN GPIO_Pin_3 -#define MAIN_USART_TX_GPIO GPIOA -#define MAIN_USART_TX_PIN GPIO_Pin_2 +#define MAIN_USART_REGS USART2 +#define MAIN_USART_REMAP GPIO_AF_USART2 +#define MAIN_USART_IRQ USART2_IRQn +#define MAIN_USART_RX_GPIO GPIOA +#define MAIN_USART_RX_PIN GPIO_Pin_3 +#define MAIN_USART_TX_GPIO GPIOA +#define MAIN_USART_TX_PIN GPIO_Pin_2 // Inverter for SBUS handling -#define MAIN_USART_INVERTER_GPIO GPIOC -#define MAIN_USART_INVERTER_PIN GPIO_Pin_15 -#define MAIN_USART_INVERTER_ENABLE Bit_SET -#define MAIN_USART_INVERTER_DISABLE Bit_RESET - -#define FLEXI_USART_REGS USART1 -#define FLEXI_USART_REMAP GPIO_AF_USART1 -#define FLEXI_USART_IRQ USART1_IRQn -#define FLEXI_USART_RX_GPIO GPIOB -#define FLEXI_USART_RX_PIN GPIO_Pin_7 -#define FLEXI_USART_TX_GPIO GPIOB -#define FLEXI_USART_TX_PIN GPIO_Pin_6 +#define MAIN_USART_INVERTER_GPIO GPIOC +#define MAIN_USART_INVERTER_PIN GPIO_Pin_15 +#define MAIN_USART_INVERTER_ENABLE Bit_SET +#define MAIN_USART_INVERTER_DISABLE Bit_RESET + +#define FLEXI_USART_REGS USART1 +#define FLEXI_USART_REMAP GPIO_AF_USART1 +#define FLEXI_USART_IRQ USART1_IRQn +#define FLEXI_USART_RX_GPIO GPIOB +#define FLEXI_USART_RX_PIN GPIO_Pin_7 +#define FLEXI_USART_TX_GPIO GPIOB +#define FLEXI_USART_TX_PIN GPIO_Pin_6 // ReceiverPort pin 3 -#define FLEXI_USART_DTR_GPIO GPIOB -#define FLEXI_USART_DTR_PIN GPIO_Pin_10 +#define FLEXI_USART_DTR_GPIO GPIOB +#define FLEXI_USART_DTR_PIN GPIO_Pin_10 #if defined(PIOS_INCLUDE_LED) @@ -115,8 +115,8 @@ const struct pios_gpio_cfg *PIOS_BOARD_HW_DEFS_GetLedCfg(__attribute__((unused)) #include /* - * SPI1 Interface - * Used for MPU6000 gyro and accelerometer + * SPI2 Interface + * Used for MPU9250 gyro and accelerometer */ void PIOS_SPI_gyro_irq_handler(void); void DMA1_Stream3_IRQHandler(void) __attribute__((alias("PIOS_SPI_gyro_irq_handler"))); @@ -229,11 +229,11 @@ static const struct pios_spi_cfg pios_spi_gyro_cfg = { } }; -static uint32_t pios_spi_gyro_id; +uint32_t pios_spi_gyro_adapter_id; void PIOS_SPI_gyro_irq_handler(void) { /* Call into the generic code to handle the IRQ for this specific device */ - PIOS_SPI_IRQ_Handler(pios_spi_gyro_id); + PIOS_SPI_IRQ_Handler(pios_spi_gyro_adapter_id); } #endif /* PIOS_INCLUDE_SPI */ @@ -249,7 +249,7 @@ static int32_t PIOS_BOARD_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *par static const struct pios_usart_cfg pios_usart_main_cfg = { .regs = MAIN_USART_REGS, .remap = MAIN_USART_REMAP, - .rx = { + .rx = { .gpio = MAIN_USART_RX_GPIO, .init = { .GPIO_Pin = MAIN_USART_RX_PIN, @@ -259,7 +259,7 @@ static const struct pios_usart_cfg pios_usart_main_cfg = { .GPIO_PuPd = GPIO_PuPd_UP }, }, - .tx = { + .tx = { .gpio = MAIN_USART_TX_GPIO, .init = { .GPIO_Pin = MAIN_USART_TX_PIN, @@ -278,7 +278,7 @@ static const struct pios_usart_cfg pios_usart_main_cfg = { static const struct pios_usart_cfg pios_usart_flexi_cfg = { .regs = FLEXI_USART_REGS, .remap = FLEXI_USART_REMAP, - .rx = { + .rx = { .gpio = FLEXI_USART_RX_GPIO, .init = { .GPIO_Pin = FLEXI_USART_RX_PIN, @@ -288,7 +288,7 @@ static const struct pios_usart_cfg pios_usart_flexi_cfg = { .GPIO_PuPd = GPIO_PuPd_UP }, }, - .tx = { + .tx = { .gpio = FLEXI_USART_TX_GPIO, .init = { .GPIO_Pin = FLEXI_USART_TX_PIN, @@ -298,15 +298,15 @@ static const struct pios_usart_cfg pios_usart_flexi_cfg = { .GPIO_PuPd = GPIO_PuPd_UP }, }, -// .dtr = { -// .gpio = FLEXI_USART_DTR_GPIO, -// .init = { -// .GPIO_Pin = FLEXI_USART_DTR_PIN, -// .GPIO_Speed = GPIO_Speed_25MHz, -// .GPIO_Mode = GPIO_Mode_OUT, -// .GPIO_OType = GPIO_OType_PP, -// }, -// }, +// .dtr = { +// .gpio = FLEXI_USART_DTR_GPIO, +// .init = { +// .GPIO_Pin = FLEXI_USART_DTR_PIN, +// .GPIO_Speed = GPIO_Speed_25MHz, +// .GPIO_Mode = GPIO_Mode_OUT, +// .GPIO_OType = GPIO_OType_PP, +// }, +// }, }; #if defined(PIOS_INCLUDE_COM) @@ -329,7 +329,7 @@ __attribute__((alias("PIOS_I2C_pressure_adapter_ev_irq_handler"))); void I2C3_ER_IRQHandler() __attribute__((alias("PIOS_I2C_pressure_adapter_er_irq_handler"))); -static const struct pios_i2c_adapter_cfg pios_i2c_pressure_adapter_cfg = { +static const struct pios_i2c_adapter_cfg pios_i2c_eeprom_pressure_adapter_cfg = { .regs = I2C3, .remapSCL = GPIO_AF_I2C3, .remapSDA = GPIO_AF9_I2C3, @@ -382,17 +382,17 @@ static const struct pios_i2c_adapter_cfg pios_i2c_pressure_adapter_cfg = { }, }; -uint32_t pios_i2c_pressure_adapter_id; +uint32_t pios_i2c_eeprom_pressure_adapter_id; void PIOS_I2C_pressure_adapter_ev_irq_handler(void) { /* Call into the generic code to handle the IRQ for this specific device */ - PIOS_I2C_EV_IRQ_Handler(pios_i2c_pressure_adapter_id); + PIOS_I2C_EV_IRQ_Handler(pios_i2c_eeprom_pressure_adapter_id); } void PIOS_I2C_pressure_adapter_er_irq_handler(void) { /* Call into the generic code to handle the IRQ for this specific device */ - PIOS_I2C_ER_IRQ_Handler(pios_i2c_pressure_adapter_id); + PIOS_I2C_ER_IRQ_Handler(pios_i2c_eeprom_pressure_adapter_id); } @@ -937,7 +937,6 @@ struct pios_flash_eeprom_cfg flash_main_chip_cfg = { */ - #if defined(PIOS_INCLUDE_ADC) #include "pios_adc_priv.h" @@ -1019,7 +1018,6 @@ const struct pios_ms5611_cfg *PIOS_BOARD_HW_DEFS_GetMS5611Cfg(__attribute__((unu */ #if defined(PIOS_INCLUDE_MPU9250) #include "pios_mpu9250.h" -#include "pios_mpu9250_config.h" static const struct pios_exti_cfg pios_exti_mpu9250_cfg __exti_config = { .vector = PIOS_MPU9250_IRQHandler, .line = EXTI_Line15, @@ -1070,4 +1068,9 @@ static const struct pios_mpu9250_cfg pios_mpu9250_cfg = { .std_prescaler = PIOS_SPI_PRESCALER_64, .max_downsample = 26, }; + +const struct pios_mpu9250_cfg *PIOS_BOARD_HW_DEFS_GetMPU9250Cfg(__attribute__((unused)) uint32_t board_revision) +{ + return &pios_mpu9250_cfg; +} #endif /* PIOS_INCLUDE_MPU9250 */ diff --git a/flight/targets/boards/revonano/firmware/pios_board.c b/flight/targets/boards/revonano/firmware/pios_board.c index 6d95791f4b..d4883768d9 100644 --- a/flight/targets/boards/revonano/firmware/pios_board.c +++ b/flight/targets/boards/revonano/firmware/pios_board.c @@ -41,6 +41,7 @@ #endif #include +#include /* * Pull in the board-specific static HW definitions. @@ -97,19 +98,19 @@ static const PIOS_BOARD_IO_UART_Function main_function_map[] = { int32_t PIOS_BOARD_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param) { const struct pios_usart_cfg *usart_cfg = PIOS_USART_GetConfig(usart_id); - + switch (ctl) { - case PIOS_IOCTL_USART_SET_INVERTED: - if (usart_cfg->regs == pios_usart_main_cfg.regs) { /* main port */ - GPIO_WriteBit(MAIN_USART_INVERTER_GPIO, - MAIN_USART_INVERTER_PIN, - (*(enum PIOS_USART_Inverted *)param & PIOS_USART_Inverted_Rx) ? MAIN_USART_INVERTER_ENABLE : MAIN_USART_INVERTER_DISABLE); - - return 0; - } - break; + case PIOS_IOCTL_USART_SET_INVERTED: + if (usart_cfg->regs == pios_usart_main_cfg.regs) { /* main port */ + GPIO_WriteBit(MAIN_USART_INVERTER_GPIO, + MAIN_USART_INVERTER_PIN, + (*(enum PIOS_USART_Inverted *)param & PIOS_USART_Inverted_Rx) ? MAIN_USART_INVERTER_ENABLE : MAIN_USART_INVERTER_DISABLE); + + return 0; + } + break; } - + return -1; } @@ -129,18 +130,12 @@ void PIOS_Board_Init(void) #endif /* Set up the SPI interface to the gyro/acelerometer */ - if (PIOS_SPI_Init(&pios_spi_gyro_id, &pios_spi_gyro_cfg)) { + if (PIOS_SPI_Init(&pios_spi_gyro_adapter_id, &pios_spi_gyro_cfg)) { PIOS_DEBUG_Assert(0); } -#if false - /* Set up the SPI interface to the flash and rfm22b */ - if (PIOS_SPI_Init(&pios_spi_telem_flash_id, &pios_spi_telem_flash_cfg)) { - PIOS_DEBUG_Assert(0); - } -#endif #ifdef PIOS_INCLUDE_I2C - if (PIOS_I2C_Init(&pios_i2c_pressure_adapter_id, &pios_i2c_pressure_adapter_cfg)) { + if (PIOS_I2C_Init(&pios_i2c_eeprom_pressure_adapter_id, &pios_i2c_eeprom_pressure_adapter_cfg)) { PIOS_DEBUG_Assert(0); } #endif @@ -150,7 +145,7 @@ void PIOS_Board_Init(void) uintptr_t flash_id = 0; // Initialize the external USER flash - if (PIOS_Flash_EEPROM_Init(&flash_id, &flash_main_chip_cfg, pios_i2c_pressure_adapter_id, 0x50)) { + if (PIOS_Flash_EEPROM_Init(&flash_id, &flash_main_chip_cfg, pios_i2c_eeprom_pressure_adapter_id, 0x50)) { PIOS_DEBUG_Assert(0); } @@ -213,7 +208,7 @@ void PIOS_Board_Init(void) HwSettingsSetDefaults(HwSettingsHandle(), 0); AlarmsSet(SYSTEMALARMS_ALARM_BOOTFAULT, SYSTEMALARMS_ALARM_CRITICAL); } - + #if defined(PIOS_INCLUDE_USB) PIOS_BOARD_IO_Configure_USB(); #endif @@ -221,21 +216,21 @@ void PIOS_Board_Init(void) /* Configure FlexiPort */ uint8_t hwsettings_flexiport; HwSettingsRM_FlexiPortGet(&hwsettings_flexiport); - + if (hwsettings_flexiport < NELEMENTS(flexi_function_map)) { PIOS_BOARD_IO_Configure_UART(&pios_usart_flexi_cfg, flexi_function_map[hwsettings_flexiport]); } /* Configure main USART port */ - + /* Initialize inverter gpio and set it to off */ { GPIO_InitTypeDef inverterGPIOInit = { - .GPIO_Pin = MAIN_USART_INVERTER_PIN, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_OUT, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP + .GPIO_Pin = MAIN_USART_INVERTER_PIN, + .GPIO_Speed = GPIO_Speed_2MHz, + .GPIO_Mode = GPIO_Mode_OUT, + .GPIO_OType = GPIO_OType_PP, + .GPIO_PuPd = GPIO_PuPd_UP }; GPIO_Init(MAIN_USART_INVERTER_GPIO, &inverterGPIOInit); @@ -243,10 +238,10 @@ void PIOS_Board_Init(void) MAIN_USART_INVERTER_PIN, MAIN_USART_INVERTER_DISABLE); } - + uint8_t hwsettings_mainport; HwSettingsRM_MainPortGet(&hwsettings_mainport); - + if (hwsettings_mainport < NELEMENTS(main_function_map)) { PIOS_BOARD_IO_Configure_UART(&pios_usart_main_cfg, main_function_map[hwsettings_mainport]); } @@ -317,16 +312,7 @@ void PIOS_Board_Init(void) PIOS_DELAY_WaitmS(50); -#if defined(PIOS_INCLUDE_ADC) - PIOS_BOARD_IO_Configure_ADC(); -#endif - -#if defined(PIOS_INCLUDE_MPU9250) - PIOS_MPU9250_Init(pios_spi_gyro_id, 0, &pios_mpu9250_cfg); - PIOS_MPU9250_CONFIG_Configure(); - PIOS_MPU9250_MainRegister(); - PIOS_MPU9250_MagRegister(); -#endif + PIOS_BOARD_Sensors_Configure(); // Attach the board config check hook SANITYCHECK_AttachHook(&RevoNanoConfigHook); diff --git a/flight/targets/boards/revonano/pios_board.h b/flight/targets/boards/revonano/pios_board.h index 5e1909dfde..79a884a02e 100644 --- a/flight/targets/boards/revonano/pios_board.h +++ b/flight/targets/boards/revonano/pios_board.h @@ -103,30 +103,32 @@ // PIOS_SPI // See also pios_board.c // ------------------------ -#define PIOS_SPI_MAX_DEVS 3 - +#define PIOS_SPI_MAX_DEVS 3 +extern uint32_t pios_spi_gyro_adapter_id; +#define PIOS_SPI_MPU9250_ADAPTER (pios_spi_gyro_adapter_id) // ------------------------ // PIOS_WDG // ------------------------ -#define PIOS_WATCHDOG_TIMEOUT 500 -#define PIOS_WDG_REGISTER RTC_BKP_DR4 -#define PIOS_WDG_ACTUATOR 0x0001 -#define PIOS_WDG_STABILIZATION 0x0002 -#define PIOS_WDG_ATTITUDE 0x0004 -#define PIOS_WDG_MANUAL 0x0008 -#define PIOS_WDG_SENSORS 0x0010 +#define PIOS_WATCHDOG_TIMEOUT 500 +#define PIOS_WDG_REGISTER RTC_BKP_DR4 +#define PIOS_WDG_ACTUATOR 0x0001 +#define PIOS_WDG_STABILIZATION 0x0002 +#define PIOS_WDG_ATTITUDE 0x0004 +#define PIOS_WDG_MANUAL 0x0008 +#define PIOS_WDG_SENSORS 0x0010 // ------------------------ // PIOS_I2C // See also pios_board.c // ------------------------ -#define PIOS_I2C_MAX_DEVS 3 -extern uint32_t pios_i2c_mag_pressure_adapter_id; -#define PIOS_I2C_MAIN_ADAPTER (pios_i2c_mag_pressure_adapter_id) +#define PIOS_I2C_MAX_DEVS 3 +extern uint32_t pios_i2c_eeprom_pressure_adapter_id; +#define PIOS_I2C_MS5611_INTERNAL_ADAPTER (pios_i2c_eeprom_pressure_adapter_id) extern uint32_t pios_i2c_flexiport_adapter_id; -#define PIOS_I2C_FLEXI_ADAPTER (pios_i2c_flexiport_adapter_id) -#define PIOS_I2C_ETASV3_ADAPTER (PIOS_I2C_FLEXI_ADAPTER) -#define PIOS_I2C_MS4525DO_ADAPTER (PIOS_I2C_FLEXI_ADAPTER) +#define PIOS_I2C_FLEXI_ADAPTER (pios_i2c_flexiport_adapter_id) +#define PIOS_I2C_ETASV3_ADAPTER (PIOS_I2C_FLEXI_ADAPTER) +#define PIOS_I2C_MS4525DO_ADAPTER (PIOS_I2C_FLEXI_ADAPTER) +#define PIOS_I2C_EXTERNAL_ADAPTER (PIOS_I2C_FLEXI_ADAPTER) // ------------------------- // PIOS_USART @@ -140,7 +142,7 @@ extern uint32_t pios_i2c_flexiport_adapter_id; // // See also pios_board.c // ------------------------- -#define PIOS_COM_MAX_DEVS 4 +#define PIOS_COM_MAX_DEVS 4 // ------------------------- // Packet Handler // ------------------------- diff --git a/flight/targets/boards/sparky2/board_hw_defs.c b/flight/targets/boards/sparky2/board_hw_defs.c index 3a531ce1e6..8316bc3df5 100644 --- a/flight/targets/boards/sparky2/board_hw_defs.c +++ b/flight/targets/boards/sparky2/board_hw_defs.c @@ -254,11 +254,11 @@ static const struct pios_spi_cfg pios_spi_gyro_cfg = { } }; -static uint32_t pios_spi_gyro_id; +uint32_t pios_spi_gyro_adapter_id; void PIOS_SPI_gyro_irq_handler(void) { /* Call into the generic code to handle the IRQ for this specific device */ - PIOS_SPI_IRQ_Handler(pios_spi_gyro_id); + PIOS_SPI_IRQ_Handler(pios_spi_gyro_adapter_id); } @@ -389,11 +389,11 @@ static const struct pios_spi_cfg pios_spi_telem_flash_cfg = { }, }; -uint32_t pios_spi_telem_flash_id; +uint32_t pios_spi_telem_flash_adapter_id; void PIOS_SPI_telem_flash_irq_handler(void) { /* Call into the generic code to handle the IRQ for this specific device */ - PIOS_SPI_IRQ_Handler(pios_spi_telem_flash_id); + PIOS_SPI_IRQ_Handler(pios_spi_telem_flash_adapter_id); } @@ -549,7 +549,7 @@ static const struct flashfs_logfs_cfg flashfs_internal_cfg = { static const struct pios_usart_cfg pios_usart_main_cfg = { .regs = USART1, .remap = GPIO_AF_USART1, - .rx = { + .rx = { .gpio = GPIOA, .init = { .GPIO_Pin = GPIO_Pin_10, @@ -559,7 +559,7 @@ static const struct pios_usart_cfg pios_usart_main_cfg = { .GPIO_PuPd = GPIO_PuPd_UP }, }, - .tx = { + .tx = { .gpio = GPIOA, .init = { .GPIO_Pin = GPIO_Pin_9, @@ -577,7 +577,7 @@ static const struct pios_usart_cfg pios_usart_main_cfg = { static const struct pios_usart_cfg pios_usart_flexi_cfg = { .regs = USART3, .remap = GPIO_AF_USART3, - .rx = { + .rx = { .gpio = GPIOB, .init = { .GPIO_Pin = GPIO_Pin_11, @@ -587,7 +587,7 @@ static const struct pios_usart_cfg pios_usart_flexi_cfg = { .GPIO_PuPd = GPIO_PuPd_UP }, }, - .tx = { + .tx = { .gpio = GPIOB, .init = { .GPIO_Pin = GPIO_Pin_10, @@ -605,10 +605,10 @@ static const struct pios_usart_cfg pios_usart_flexi_cfg = { */ // Inverter for SBUS handling -#define RCVR_USART_INVERTER_GPIO GPIOC -#define RCVR_USART_INVERTER_PIN GPIO_Pin_4 -#define RCVR_USART_INVERTER_ENABLE Bit_SET -#define RCVR_USART_INVERTER_DISABLE Bit_RESET +#define RCVR_USART_INVERTER_GPIO GPIOC +#define RCVR_USART_INVERTER_PIN GPIO_Pin_4 +#define RCVR_USART_INVERTER_ENABLE Bit_SET +#define RCVR_USART_INVERTER_DISABLE Bit_RESET static int32_t PIOS_BOARD_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param); @@ -616,7 +616,7 @@ static int32_t PIOS_BOARD_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *par static const struct pios_usart_cfg pios_usart_rcvr_cfg = { .regs = USART6, .remap = GPIO_AF_USART6, - .rx = { + .rx = { .gpio = GPIOC, .init = { .GPIO_Pin = GPIO_Pin_7, @@ -626,7 +626,7 @@ static const struct pios_usart_cfg pios_usart_rcvr_cfg = { .GPIO_PuPd = GPIO_PuPd_UP }, }, - .ioctl = PIOS_BOARD_USART_Ioctl, + .ioctl = PIOS_BOARD_USART_Ioctl, }; #if defined(PIOS_INCLUDE_COM) @@ -642,14 +642,14 @@ static const struct pios_usart_cfg pios_usart_rcvr_cfg = { /* * I2C Adapters */ -void PIOS_i2c_mag_pressure_adapter_ev_irq_handler(void); -void PIOS_i2c_mag_pressure_adapter_er_irq_handler(void); +void PIOS_i2c_pressure_adapter_ev_irq_handler(void); +void PIOS_i2c_pressure_adapter_er_irq_handler(void); void I2C1_EV_IRQHandler() -__attribute__((alias("PIOS_i2c_mag_pressure_adapter_ev_irq_handler"))); +__attribute__((alias("PIOS_i2c_pressure_adapter_ev_irq_handler"))); void I2C1_ER_IRQHandler() -__attribute__((alias("PIOS_i2c_mag_pressure_adapter_er_irq_handler"))); +__attribute__((alias("PIOS_i2c_pressure_adapter_er_irq_handler"))); -static const struct pios_i2c_adapter_cfg pios_i2c_mag_pressure_adapter_cfg = { +static const struct pios_i2c_adapter_cfg pios_i2c_pressure_adapter_cfg = { .regs = I2C1, .remapSCL = GPIO_AF_I2C1, .remapSDA = GPIO_AF_I2C1, @@ -702,17 +702,17 @@ static const struct pios_i2c_adapter_cfg pios_i2c_mag_pressure_adapter_cfg = { }, }; -uint32_t pios_i2c_mag_pressure_adapter_id; -void PIOS_i2c_mag_pressure_adapter_ev_irq_handler(void) +uint32_t pios_i2c_pressure_adapter_id; +void PIOS_i2c_pressure_adapter_ev_irq_handler(void) { /* Call into the generic code to handle the IRQ for this specific device */ - PIOS_I2C_EV_IRQ_Handler(pios_i2c_mag_pressure_adapter_id); + PIOS_I2C_EV_IRQ_Handler(pios_i2c_pressure_adapter_id); } -void PIOS_i2c_mag_pressure_adapter_er_irq_handler(void) +void PIOS_i2c_pressure_adapter_er_irq_handler(void) { /* Call into the generic code to handle the IRQ for this specific device */ - PIOS_I2C_ER_IRQ_Handler(pios_i2c_mag_pressure_adapter_id); + PIOS_I2C_ER_IRQ_Handler(pios_i2c_pressure_adapter_id); } @@ -788,8 +788,8 @@ void PIOS_I2C_flexiport_adapter_er_irq_handler(void) } -void PIOS_i2c_mag_pressure_adapter_ev_irq_handler(void); -void PIOS_i2c_mag_pressure_adapter_er_irq_handler(void); +void PIOS_i2c_pressure_adapter_ev_irq_handler(void); +void PIOS_i2c_pressure_adapter_er_irq_handler(void); #endif /* PIOS_INCLUDE_I2C */ @@ -1307,7 +1307,6 @@ const struct pios_ms5611_cfg *PIOS_BOARD_HW_DEFS_GetMS5611Cfg(__attribute__((unu */ #if defined(PIOS_INCLUDE_MPU9250) #include "pios_mpu9250.h" -#include "pios_mpu9250_config.h" static const struct pios_exti_cfg pios_exti_mpu9250_cfg __exti_config = { .vector = PIOS_MPU9250_IRQHandler, .line = EXTI_Line5, @@ -1358,5 +1357,9 @@ static const struct pios_mpu9250_cfg pios_mpu9250_cfg = { .std_prescaler = PIOS_SPI_PRESCALER_64, .max_downsample = 26, }; -#endif /* PIOS_INCLUDE_MPU9250 */ +const struct pios_mpu9250_cfg *PIOS_BOARD_HW_DEFS_GetMPU9250Cfg(__attribute__((unused)) uint32_t board_revision) +{ + return &pios_mpu9250_cfg; +} +#endif /* PIOS_INCLUDE_MPU9250 */ diff --git a/flight/targets/boards/sparky2/firmware/pios_board.c b/flight/targets/boards/sparky2/firmware/pios_board.c index 28e232e366..a9b72f4856 100644 --- a/flight/targets/boards/sparky2/firmware/pios_board.c +++ b/flight/targets/boards/sparky2/firmware/pios_board.c @@ -41,7 +41,7 @@ #endif #include - +#include /* * Pull in the board-specific static HW definitions. @@ -57,24 +57,24 @@ uintptr_t pios_uavo_settings_fs_id; uintptr_t pios_user_fs_id; static const PIOS_BOARD_IO_UART_Function rcvr_function_map[] = { - [HWSETTINGS_SPK2_RCVRPORT_SBUS] = PIOS_BOARD_IO_UART_SBUS, - [HWSETTINGS_SPK2_RCVRPORT_DSM] = PIOS_BOARD_IO_UART_DSM_RCVR, - [HWSETTINGS_SPK2_RCVRPORT_SRXL] = PIOS_BOARD_IO_UART_SRXL, - [HWSETTINGS_SPK2_RCVRPORT_IBUS] = PIOS_BOARD_IO_UART_IBUS, - [HWSETTINGS_SPK2_RCVRPORT_EXBUS] = PIOS_BOARD_IO_UART_EXBUS, + [HWSETTINGS_SPK2_RCVRPORT_SBUS] = PIOS_BOARD_IO_UART_SBUS, + [HWSETTINGS_SPK2_RCVRPORT_DSM] = PIOS_BOARD_IO_UART_DSM_RCVR, + [HWSETTINGS_SPK2_RCVRPORT_SRXL] = PIOS_BOARD_IO_UART_SRXL, + [HWSETTINGS_SPK2_RCVRPORT_IBUS] = PIOS_BOARD_IO_UART_IBUS, + [HWSETTINGS_SPK2_RCVRPORT_EXBUS] = PIOS_BOARD_IO_UART_EXBUS, [HWSETTINGS_SPK2_RCVRPORT_HOTTSUMD] = PIOS_BOARD_IO_UART_HOTT_SUMD, [HWSETTINGS_SPK2_RCVRPORT_HOTTSUMH] = PIOS_BOARD_IO_UART_HOTT_SUMH, }; static const PIOS_BOARD_IO_UART_Function main_function_map[] = { - [HWSETTINGS_SPK2_MAINPORT_TELEMETRY] = PIOS_BOARD_IO_UART_TELEMETRY, - [HWSETTINGS_SPK2_MAINPORT_GPS] = PIOS_BOARD_IO_UART_GPS, - [HWSETTINGS_SPK2_MAINPORT_DSM] = PIOS_BOARD_IO_UART_DSM_MAIN, + [HWSETTINGS_SPK2_MAINPORT_TELEMETRY] = PIOS_BOARD_IO_UART_TELEMETRY, + [HWSETTINGS_SPK2_MAINPORT_GPS] = PIOS_BOARD_IO_UART_GPS, + [HWSETTINGS_SPK2_MAINPORT_DSM] = PIOS_BOARD_IO_UART_DSM_MAIN, [HWSETTINGS_SPK2_MAINPORT_DEBUGCONSOLE] = PIOS_BOARD_IO_UART_DEBUGCONSOLE, [HWSETTINGS_SPK2_MAINPORT_COMBRIDGE] = PIOS_BOARD_IO_UART_COMBRIDGE, - [HWSETTINGS_SPK2_MAINPORT_OSDHK] = PIOS_BOARD_IO_UART_OSDHK, - [HWSETTINGS_SPK2_MAINPORT_MSP] = PIOS_BOARD_IO_UART_MSP, - [HWSETTINGS_SPK2_MAINPORT_MAVLINK] = PIOS_BOARD_IO_UART_MAVLINK, + [HWSETTINGS_SPK2_MAINPORT_OSDHK] = PIOS_BOARD_IO_UART_OSDHK, + [HWSETTINGS_SPK2_MAINPORT_MSP] = PIOS_BOARD_IO_UART_MSP, + [HWSETTINGS_SPK2_MAINPORT_MAVLINK] = PIOS_BOARD_IO_UART_MAVLINK, }; static const PIOS_BOARD_IO_UART_Function flexi_function_map[] = { @@ -96,25 +96,25 @@ static const PIOS_BOARD_IO_UART_Function flexi_function_map[] = { static const PIOS_BOARD_IO_RADIOAUX_Function radioaux_function_map[] = { [HWSETTINGS_RADIOAUXSTREAM_DEBUGCONSOLE] = PIOS_BOARD_IO_RADIOAUX_DEBUGCONSOLE, [HWSETTINGS_RADIOAUXSTREAM_MAVLINK] = PIOS_BOARD_IO_RADIOAUX_MAVLINK, - [HWSETTINGS_RADIOAUXSTREAM_COMBRIDGE] = PIOS_BOARD_IO_RADIOAUX_COMBRIDGE, + [HWSETTINGS_RADIOAUXSTREAM_COMBRIDGE] = PIOS_BOARD_IO_RADIOAUX_COMBRIDGE, }; int32_t PIOS_BOARD_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param) { const struct pios_usart_cfg *usart_cfg = PIOS_USART_GetConfig(usart_id); - + switch (ctl) { - case PIOS_IOCTL_USART_SET_INVERTED: - if (usart_cfg->regs == pios_usart_rcvr_cfg.regs) { /* rcvr port */ - GPIO_WriteBit(RCVR_USART_INVERTER_GPIO, - RCVR_USART_INVERTER_PIN, - (*(enum PIOS_USART_Inverted *)param & PIOS_USART_Inverted_Rx) ? RCVR_USART_INVERTER_ENABLE : RCVR_USART_INVERTER_DISABLE); - - return 0; - } - break; + case PIOS_IOCTL_USART_SET_INVERTED: + if (usart_cfg->regs == pios_usart_rcvr_cfg.regs) { /* rcvr port */ + GPIO_WriteBit(RCVR_USART_INVERTER_GPIO, + RCVR_USART_INVERTER_PIN, + (*(enum PIOS_USART_Inverted *)param & PIOS_USART_Inverted_Rx) ? RCVR_USART_INVERTER_ENABLE : RCVR_USART_INVERTER_DISABLE); + + return 0; + } + break; } - + return -1; } @@ -140,12 +140,12 @@ void PIOS_Board_Init(void) #endif /* Set up the SPI interface to the gyro/acelerometer */ - if (PIOS_SPI_Init(&pios_spi_gyro_id, &pios_spi_gyro_cfg)) { + if (PIOS_SPI_Init(&pios_spi_gyro_adapter_id, &pios_spi_gyro_cfg)) { PIOS_DEBUG_Assert(0); } /* Set up the SPI interface to the flash and rfm22b */ - if (PIOS_SPI_Init(&pios_spi_telem_flash_id, &pios_spi_telem_flash_cfg)) { + if (PIOS_SPI_Init(&pios_spi_telem_flash_adapter_id, &pios_spi_telem_flash_cfg)) { PIOS_DEBUG_Assert(0); } @@ -154,7 +154,7 @@ void PIOS_Board_Init(void) uintptr_t flash_id = 0; // Initialize the external USER flash - if (PIOS_Flash_Jedec_Init(&flash_id, pios_spi_telem_flash_id, 1)) { + if (PIOS_Flash_Jedec_Init(&flash_id, pios_spi_telem_flash_adapter_id, 1)) { PIOS_DEBUG_Assert(0); } @@ -224,26 +224,24 @@ void PIOS_Board_Init(void) /* Configure FlexiPort */ uint8_t hwsettings_flexiport; HwSettingsSPK2_FlexiPortGet(&hwsettings_flexiport); - + if (hwsettings_flexiport < NELEMENTS(flexi_function_map)) { PIOS_BOARD_IO_Configure_UART(&pios_usart_flexi_cfg, flexi_function_map[hwsettings_flexiport]); } - + #if defined(PIOS_INCLUDE_I2C) /* Set up internal I2C bus */ - if (PIOS_I2C_Init(&pios_i2c_mag_pressure_adapter_id, &pios_i2c_mag_pressure_adapter_cfg)) { + if (PIOS_I2C_Init(&pios_i2c_pressure_adapter_id, &pios_i2c_pressure_adapter_cfg)) { PIOS_DEBUG_Assert(0); } PIOS_DELAY_WaitmS(50); - + if (hwsettings_flexiport == HWSETTINGS_RM_FLEXIPORT_I2C) { if (PIOS_I2C_Init(&pios_i2c_flexiport_adapter_id, &pios_i2c_flexiport_adapter_cfg)) { PIOS_Assert(0); } PIOS_DELAY_WaitmS(50); } - - PIOS_BOARD_IO_Configure_I2C(pios_i2c_mag_pressure_adapter_id, pios_i2c_flexiport_adapter_id); #endif /* Moved this here to allow binding on flexiport */ @@ -259,16 +257,17 @@ void PIOS_Board_Init(void) uint8_t hwsettings_mainport; HwSettingsSPK2_MainPortGet(&hwsettings_mainport); + if (hwsettings_mainport < NELEMENTS(main_function_map)) { PIOS_BOARD_IO_Configure_UART(&pios_usart_main_cfg, main_function_map[hwsettings_mainport]); } - + #if defined(PIOS_INCLUDE_RFM22B) uint8_t hwsettings_radioaux; HwSettingsRadioAuxStreamGet(&hwsettings_radioaux); - - if(hwsettings_radioaux < NELEMENTS(radioaux_function_map)) { - PIOS_BOARD_IO_Configure_RFM22B(pios_spi_telem_flash_id, radioaux_function_map[hwsettings_radioaux]); + + if (hwsettings_radioaux < NELEMENTS(radioaux_function_map)) { + PIOS_BOARD_IO_Configure_RFM22B(radioaux_function_map[hwsettings_radioaux]); } #endif /* PIOS_INCLUDE_RFM22B */ @@ -281,7 +280,7 @@ void PIOS_Board_Init(void) .GPIO_OType = GPIO_OType_PP, .GPIO_PuPd = GPIO_PuPd_UP }; - + GPIO_Init(RCVR_USART_INVERTER_GPIO, &inverterGPIOInit); GPIO_WriteBit(RCVR_USART_INVERTER_GPIO, RCVR_USART_INVERTER_PIN, @@ -292,16 +291,16 @@ void PIOS_Board_Init(void) // Sparky2 receiver input on PC7 TIM8 CH2 // include PPM,S.Bus,DSM,SRXL,IBus,EX.Bus,HoTT SUMD,HoTT SUMH /* Configure the receiver port*/ - + uint8_t hwsettings_rcvrport; HwSettingsSPK2_RcvrPortGet(&hwsettings_rcvrport); - + if (hwsettings_rcvrport < NELEMENTS(rcvr_function_map)) { PIOS_BOARD_IO_Configure_UART(&pios_usart_rcvr_cfg, rcvr_function_map[hwsettings_rcvrport]); } #if defined(PIOS_INCLUDE_PPM) - if(hwsettings_rcvrport == HWSETTINGS_SPK2_RCVRPORT_PPM) { + if (hwsettings_rcvrport == HWSETTINGS_SPK2_RCVRPORT_PPM) { PIOS_BOARD_IO_Configure_PPM(&pios_ppm_cfg); } #endif @@ -316,12 +315,7 @@ void PIOS_Board_Init(void) PIOS_DEBUG_Init(pios_tim_servoport_all_pins, NELEMENTS(pios_tim_servoport_all_pins)); #endif -#if defined(PIOS_INCLUDE_MPU9250) - PIOS_MPU9250_Init(pios_spi_gyro_id, 0, &pios_mpu9250_cfg); - PIOS_MPU9250_CONFIG_Configure(); - PIOS_MPU9250_MainRegister(); - PIOS_MPU9250_MagRegister(); -#endif + PIOS_BOARD_Sensors_Configure(); #ifdef PIOS_INCLUDE_WS2811 HwSettingsWS2811LED_OutOptions ws2811_pin_settings; @@ -342,10 +336,7 @@ void PIOS_Board_Init(void) .GPIO_OType = GPIO_OType_OD, }; GPIO_Init(GPIOA, &gpioA8); - - PIOS_BOARD_IO_Configure_ADC(); #endif /* PIOS_INCLUDE_ADC */ - } /** diff --git a/flight/targets/boards/sparky2/pios_board.h b/flight/targets/boards/sparky2/pios_board.h index 37fe24a121..d63e5cf3e2 100644 --- a/flight/targets/boards/sparky2/pios_board.h +++ b/flight/targets/boards/sparky2/pios_board.h @@ -105,30 +105,35 @@ // PIOS_SPI // See also pios_board.c // ------------------------ -#define PIOS_SPI_MAX_DEVS 3 +#define PIOS_SPI_MAX_DEVS 3 +extern uint32_t pios_spi_telem_flash_adapter_id; +#define PIOS_SPI_RFM22B_ADAPTER (pios_spi_telem_flash_adapter_id) +extern uint32_t pios_spi_gyro_adapter_id; +#define PIOS_SPI_MPU9250_ADAPTER (pios_spi_gyro_adapter_id) // ------------------------ // PIOS_WDG // ------------------------ -#define PIOS_WATCHDOG_TIMEOUT 250 -#define PIOS_WDG_REGISTER RTC_BKP_DR4 -#define PIOS_WDG_ACTUATOR 0x0001 -#define PIOS_WDG_STABILIZATION 0x0002 -#define PIOS_WDG_ATTITUDE 0x0004 -#define PIOS_WDG_MANUAL 0x0008 -#define PIOS_WDG_SENSORS 0x0010 +#define PIOS_WATCHDOG_TIMEOUT 250 +#define PIOS_WDG_REGISTER RTC_BKP_DR4 +#define PIOS_WDG_ACTUATOR 0x0001 +#define PIOS_WDG_STABILIZATION 0x0002 +#define PIOS_WDG_ATTITUDE 0x0004 +#define PIOS_WDG_MANUAL 0x0008 +#define PIOS_WDG_SENSORS 0x0010 // ------------------------ // PIOS_I2C // See also pios_board.c // ------------------------ -#define PIOS_I2C_MAX_DEVS 3 -extern uint32_t pios_i2c_mag_pressure_adapter_id; -#define PIOS_I2C_MAIN_ADAPTER (pios_i2c_mag_pressure_adapter_id) +#define PIOS_I2C_MAX_DEVS 3 +extern uint32_t pios_i2c_pressure_adapter_id; +#define PIOS_I2C_MS5611_INTERNAL_ADAPTER (pios_i2c_pressure_adapter_id) +#define PIOS_I2C_EXTERNAL_ADAPTER (pios_i2c_pressure_adapter_id) extern uint32_t pios_i2c_flexiport_adapter_id; -#define PIOS_I2C_FLEXI_ADAPTER (pios_i2c_flexiport_adapter_id) -#define PIOS_I2C_ETASV3_ADAPTER (PIOS_I2C_FLEXI_ADAPTER) -#define PIOS_I2C_MS4525DO_ADAPTER (PIOS_I2C_FLEXI_ADAPTER) +#define PIOS_I2C_FLEXI_ADAPTER (pios_i2c_flexiport_adapter_id) +#define PIOS_I2C_ETASV3_ADAPTER (PIOS_I2C_FLEXI_ADAPTER) +#define PIOS_I2C_MS4525DO_ADAPTER (PIOS_I2C_FLEXI_ADAPTER) // ------------------------- // PIOS_USART @@ -142,7 +147,7 @@ extern uint32_t pios_i2c_flexiport_adapter_id; // // See also pios_board.c // ------------------------- -#define PIOS_COM_MAX_DEVS 4 +#define PIOS_COM_MAX_DEVS 4 // ------------------------- // Packet Handler From 16020c18390fcdf100547ab8632a08536c3a524b Mon Sep 17 00:00:00 2001 From: Vladimir Zidar Date: Sat, 15 Apr 2017 01:48:13 +0200 Subject: [PATCH 218/624] LP-480 GPSplatinum pios_usart fixes. Bootloader now fits again. --- .../OpenPilotOSX.xcodeproj/project.pbxproj | 2 +- flight/pios/common/pios_com.c | 4 ++ flight/pios/stm32f0x/pios_usart.c | 52 ++++++++++++++----- .../boards/gpsplatinum/board_hw_defs.c | 34 ++++++------ .../gpsplatinum/bootloader/pios_board.c | 3 ++ .../boards/gpsplatinum/firmware/pios_board.c | 2 + 6 files changed, 65 insertions(+), 32 deletions(-) diff --git a/flight/Project/OpenPilotOSX/OpenPilotOSX.xcodeproj/project.pbxproj b/flight/Project/OpenPilotOSX/OpenPilotOSX.xcodeproj/project.pbxproj index 7e01ae919e..c224603ce8 100644 --- a/flight/Project/OpenPilotOSX/OpenPilotOSX.xcodeproj/project.pbxproj +++ b/flight/Project/OpenPilotOSX/OpenPilotOSX.xcodeproj/project.pbxproj @@ -184,7 +184,7 @@ /* Begin PBXLegacyTarget section */ 6581071511DE809D0049FB12 /* OpenPilotOSX */ = { isa = PBXLegacyTarget; - buildArgumentsString = ef_revolution; + buildArgumentsString = ef_gpsplatinum; buildConfigurationList = 6581071A11DE80A30049FB12 /* Build configuration list for PBXLegacyTarget "OpenPilotOSX" */; buildPhases = ( ); diff --git a/flight/pios/common/pios_com.c b/flight/pios/common/pios_com.c index 26794095f6..1a813ba3ca 100644 --- a/flight/pios/common/pios_com.c +++ b/flight/pios/common/pios_com.c @@ -119,12 +119,16 @@ int32_t PIOS_COM_Init(uint32_t *com_id, const struct pios_com_driver *driver, ui PIOS_Assert(driver); if ((rx_buffer_len > 0) && !rx_buffer) { +#if defined(PIOS_INCLUDE_FREERTOS) rx_buffer = (uint8_t *)pios_malloc(rx_buffer_len); +#endif PIOS_Assert(rx_buffer); } if ((tx_buffer_len > 0) && !tx_buffer) { +#if defined(PIOS_INCLUDE_FREERTOS) tx_buffer = (uint8_t *)pios_malloc(tx_buffer_len); +#endif PIOS_Assert(tx_buffer); } diff --git a/flight/pios/stm32f0x/pios_usart.c b/flight/pios/stm32f0x/pios_usart.c index 0ce5de3cc4..21a1dceed3 100644 --- a/flight/pios/stm32f0x/pios_usart.c +++ b/flight/pios/stm32f0x/pios_usart.c @@ -38,7 +38,9 @@ #define PIOS_UART_TX_BUFFER 10 /* Provide a COM driver */ static void PIOS_USART_ChangeBaud(uint32_t usart_id, uint32_t baud); +#ifndef BOOTLOADER static void PIOS_USART_ChangeConfig(uint32_t usart_id, enum PIOS_COM_Word_Length word_len, enum PIOS_COM_StopBits stop_bits, enum PIOS_COM_Parity parity, uint32_t baud_rate, enum PIOS_COM_Mode mode); +#endif static void PIOS_USART_RegisterRxCallback(uint32_t usart_id, pios_com_callback rx_in_cb, uint32_t context); static void PIOS_USART_RegisterTxCallback(uint32_t usart_id, pios_com_callback tx_out_cb, uint32_t context); static void PIOS_USART_TxStart(uint32_t usart_id, uint16_t tx_bytes_avail); @@ -46,7 +48,9 @@ static void PIOS_USART_RxStart(uint32_t usart_id, uint16_t rx_bytes_avail); const struct pios_com_driver pios_usart_com_driver = { .set_baud = PIOS_USART_ChangeBaud, +#ifndef BOOTLOADER .set_config = PIOS_USART_ChangeConfig, +#endif .tx_start = PIOS_USART_TxStart, .rx_start = PIOS_USART_RxStart, .bind_tx_cb = PIOS_USART_RegisterTxCallback, @@ -71,6 +75,7 @@ struct pios_usart_dev { uint8_t tx_buffer[PIOS_UART_TX_BUFFER]; uint8_t tx_len; uint8_t tx_pos; + uint8_t irq_channel; }; static struct pios_usart_dev *PIOS_USART_validate(uint32_t usart_id) @@ -138,13 +143,27 @@ static void PIOS_USART_2_irq_handler(void) { PIOS_USART_generic_irq_handler(PIOS_USART_2_id); } - +#if defined(STM32F072) static uint32_t PIOS_USART_3_id; void USART3_IRQHandler(void) __attribute__((alias("PIOS_USART_3_irq_handler"))); static void PIOS_USART_3_irq_handler(void) { PIOS_USART_generic_irq_handler(PIOS_USART_3_id); } +#endif + +static int32_t PIOS_USART_SetIrqPrio(struct pios_usart_dev *usart_dev, uint8_t irq_prio) +{ + NVIC_InitTypeDef init = { + .NVIC_IRQChannel = usart_dev->irq_channel, + .NVIC_IRQChannelPriority = irq_prio, + .NVIC_IRQChannelCmd = ENABLE, + }; + + NVIC_Init(&init); + + return 0; +} /** * Initialise a single USART device @@ -162,10 +181,10 @@ int32_t PIOS_USART_Init(uint32_t *usart_id, const struct pios_usart_cfg *cfg) } /* Bind the configuration to the device instance */ - usart_dev->cfg = cfg; + usart_dev->cfg = cfg; - /* Copy the comm parameter structure */ - usart_dev->init = cfg->init; + /* Initialize the comm parameter structure */ + USART_StructInit(&usart_dev->init); // 9600 8n1 /* Enable the USART Pins Software Remapping */ if (usart_dev->cfg->remap) { @@ -182,22 +201,27 @@ int32_t PIOS_USART_Init(uint32_t *usart_id, const struct pios_usart_cfg *cfg) case (uint32_t)USART1: RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); PIOS_USART_1_id = (uint32_t)usart_dev; + usart_dev->irq_channel = USART1_IRQn; break; case (uint32_t)USART2: RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); PIOS_USART_2_id = (uint32_t)usart_dev; + usart_dev->irq_channel = USART2_IRQn; break; +#if defined(STM32F072) case (uint32_t)USART3: RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE); PIOS_USART_3_id = (uint32_t)usart_dev; + usart_dev->irq_channel = USART3_4_IRQn; break; +#endif } /* Configure the USART */ USART_Init(cfg->regs, (USART_InitTypeDef *)&usart_dev->init); *usart_id = (uint32_t)usart_dev; - NVIC_Init((NVIC_InitTypeDef *)&cfg->irq.init); + PIOS_USART_SetIrqPrio(usart_dev, PIOS_IRQ_PRIO_MID); USART_ITConfig(cfg->regs, USART_IT_RXNE, ENABLE); USART_ITConfig(cfg->regs, USART_IT_TXE, ENABLE); USART_ITConfig(cfg->regs, USART_IT_ORE, DISABLE); @@ -238,7 +262,7 @@ static void PIOS_USART_ChangeBaud(uint32_t usart_id, uint32_t baud) USART_Cmd(usart_dev->cfg->regs, ENABLE); } - +#ifndef BOOTLOADER /** * Changes configuration of the USART peripheral without re-initialising. * \param[in] usart_id USART name (GPS, TELEM, AUX) @@ -323,6 +347,7 @@ static void PIOS_USART_ChangeConfig(uint32_t usart_id, */ USART_Cmd(usart_dev->cfg->regs, ENABLE); } +#endif /* BOOTLOADER */ static void PIOS_USART_RegisterRxCallback(uint32_t usart_id, pios_com_callback rx_in_cb, uint32_t context) { @@ -358,8 +383,8 @@ static void PIOS_USART_generic_irq_handler(uint32_t usart_id) /* Check if RXNE flag is set */ bool rx_need_yield = false; - if (USART_GetITStatus(usart_dev->cfg->regs, USART_IT_RXNE) != RESET) { - uint8_t byte = USART_ReceiveData(usart_dev->cfg->regs) & 0x00FF; + if (usart_dev->cfg->regs->ISR & USART_ISR_RXNE) { + uint8_t byte = usart_dev->cfg->regs->RDR & 0xFF; if (usart_dev->rx_in_cb) { uint16_t rc; rc = (usart_dev->rx_in_cb)(usart_dev->rx_in_context, &byte, 1, NULL, &rx_need_yield); @@ -372,7 +397,7 @@ static void PIOS_USART_generic_irq_handler(uint32_t usart_id) /* Check if TXE flag is set */ bool tx_need_yield = false; - if (USART_GetITStatus(usart_dev->cfg->regs, USART_IT_TXE) != RESET) { + if (usart_dev->cfg->regs->ISR & USART_ISR_TXE) { if (usart_dev->tx_out_cb) { if (!usart_dev->tx_len) { usart_dev->tx_len = (usart_dev->tx_out_cb)(usart_dev->tx_out_context, usart_dev->tx_buffer, PIOS_UART_TX_BUFFER, NULL, &tx_need_yield); @@ -380,19 +405,18 @@ static void PIOS_USART_generic_irq_handler(uint32_t usart_id) } if (usart_dev->tx_len > 0) { /* Send the byte we've been given */ - USART_SendData(usart_dev->cfg->regs, usart_dev->tx_buffer[usart_dev->tx_pos++]); + usart_dev->cfg->regs->TDR = usart_dev->tx_buffer[usart_dev->tx_pos++]; usart_dev->tx_len--; } else { /* No bytes to send, disable TXE interrupt */ - USART_ITConfig(usart_dev->cfg->regs, USART_IT_TXE, DISABLE); + usart_dev->cfg->regs->CR1 &= ~(USART_CR1_TXEIE); } } else { /* No bytes to send, disable TXE interrupt */ - USART_ITConfig(usart_dev->cfg->regs, USART_IT_TXE, DISABLE); + usart_dev->cfg->regs->CR1 &= ~(USART_CR1_TXEIE); } } - USART_ClearITPendingBit(usart_dev->cfg->regs, USART_IT_ORE); - USART_ClearITPendingBit(usart_dev->cfg->regs, USART_IT_TC); + usart_dev->cfg->regs->ICR = USART_ICR_ORECF | USART_ICR_TCCF; #if defined(PIOS_INCLUDE_FREERTOS) if (rx_need_yield || tx_need_yield) { vPortYield(); diff --git a/flight/targets/boards/gpsplatinum/board_hw_defs.c b/flight/targets/boards/gpsplatinum/board_hw_defs.c index 83b7f4528f..1243db383f 100644 --- a/flight/targets/boards/gpsplatinum/board_hw_defs.c +++ b/flight/targets/boards/gpsplatinum/board_hw_defs.c @@ -268,22 +268,22 @@ static const struct pios_hmc5x83_cfg pios_mag_cfg = { static const struct pios_usart_cfg pios_usart_generic_main_cfg = { .regs = USART1, .remap = GPIO_AF_1, - .init = { - .USART_BaudRate = 57600, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx | USART_Mode_Tx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART1_IRQn, - .NVIC_IRQChannelPriority = PIOS_IRQ_PRIO_MID, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { +// .init = { +// .USART_BaudRate = 57600, +// .USART_WordLength = USART_WordLength_8b, +// .USART_Parity = USART_Parity_No, +// .USART_StopBits = USART_StopBits_1, +// .USART_HardwareFlowControl = USART_HardwareFlowControl_None, +// .USART_Mode = USART_Mode_Rx | USART_Mode_Tx, +// }, +// .irq = { +// .init = { +// .NVIC_IRQChannel = USART1_IRQn, +// .NVIC_IRQChannelPriority = PIOS_IRQ_PRIO_MID, +// .NVIC_IRQChannelCmd = ENABLE, +// }, +// }, + .rx = { .gpio = GPIOA, .init = { .GPIO_Pin = GPIO_Pin_10, @@ -292,7 +292,7 @@ static const struct pios_usart_cfg pios_usart_generic_main_cfg = { .GPIO_Mode = GPIO_Mode_AF, }, }, - .tx = { + .tx = { .gpio = GPIOA, .init = { .GPIO_Pin = GPIO_Pin_9, diff --git a/flight/targets/boards/gpsplatinum/bootloader/pios_board.c b/flight/targets/boards/gpsplatinum/bootloader/pios_board.c index 14bddba5e4..8c3d730df5 100644 --- a/flight/targets/boards/gpsplatinum/bootloader/pios_board.c +++ b/flight/targets/boards/gpsplatinum/bootloader/pios_board.c @@ -70,9 +70,12 @@ void setupCom() if (PIOS_USART_Init(&pios_usart_generic_id, &pios_usart_generic_main_cfg)) { PIOS_Assert(0); } + if (PIOS_COM_Init(&PIOS_COM_TELEM_USB, &pios_usart_com_driver, pios_usart_generic_id, rx_buffer, PIOS_COM_MAIN_RX_BUF_LEN, tx_buffer, PIOS_COM_MAIN_TX_BUF_LEN)) { PIOS_Assert(0); } + + PIOS_COM_ChangeBaud(PIOS_COM_TELEM_USB, 57600); } diff --git a/flight/targets/boards/gpsplatinum/firmware/pios_board.c b/flight/targets/boards/gpsplatinum/firmware/pios_board.c index d8b29bd223..4bc62fda36 100644 --- a/flight/targets/boards/gpsplatinum/firmware/pios_board.c +++ b/flight/targets/boards/gpsplatinum/firmware/pios_board.c @@ -114,6 +114,8 @@ void PIOS_Board_Init(void) tx_buffer, PIOS_COM_MAIN_TX_BUF_LEN)) { PIOS_Assert(0); } + + PIOS_COM_ChangeBaud(pios_com_main_id, 57600); } #endif From a6f7cc6cdf312c577b22da95c1e3787ce2463a55 Mon Sep 17 00:00:00 2001 From: Vladimir Zidar Date: Sat, 15 Apr 2017 01:48:53 +0200 Subject: [PATCH 219/624] LP-480 gpsplatinum board_hw_defs cleanup --- flight/targets/boards/gpsplatinum/board_hw_defs.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/flight/targets/boards/gpsplatinum/board_hw_defs.c b/flight/targets/boards/gpsplatinum/board_hw_defs.c index 1243db383f..489d49bf5d 100644 --- a/flight/targets/boards/gpsplatinum/board_hw_defs.c +++ b/flight/targets/boards/gpsplatinum/board_hw_defs.c @@ -268,21 +268,6 @@ static const struct pios_hmc5x83_cfg pios_mag_cfg = { static const struct pios_usart_cfg pios_usart_generic_main_cfg = { .regs = USART1, .remap = GPIO_AF_1, -// .init = { -// .USART_BaudRate = 57600, -// .USART_WordLength = USART_WordLength_8b, -// .USART_Parity = USART_Parity_No, -// .USART_StopBits = USART_StopBits_1, -// .USART_HardwareFlowControl = USART_HardwareFlowControl_None, -// .USART_Mode = USART_Mode_Rx | USART_Mode_Tx, -// }, -// .irq = { -// .init = { -// .NVIC_IRQChannel = USART1_IRQn, -// .NVIC_IRQChannelPriority = PIOS_IRQ_PRIO_MID, -// .NVIC_IRQChannelCmd = ENABLE, -// }, -// }, .rx = { .gpio = GPIOA, .init = { From 83326eaca3c59529270e69d2013d85f4337d8606 Mon Sep 17 00:00:00 2001 From: Vladimir Zidar Date: Sun, 16 Apr 2017 02:38:42 +0200 Subject: [PATCH 220/624] LP-480 all targets build nicely. --- .../OpenPilotOSX.xcodeproj/project.pbxproj | 2 +- flight/pios/common/pios_board_io.c | 81 +- flight/pios/common/pios_board_sensors.c | 39 +- flight/pios/inc/pios_board_hw.h | 11 +- flight/pios/inc/pios_board_io.h | 31 +- .../boards/coptercontrol/board_hw_defs.c | 13 +- .../coptercontrol/bootloader/pios_board.c | 7 - .../boards/discoveryf4bare/board_hw_defs.c | 4 +- .../discoveryf4bare/bootloader/pios_board.c | 5 - .../boards/gpsplatinum/board_hw_defs.c | 2 +- .../targets/boards/oplinkmini/board_hw_defs.c | 7 +- .../boards/oplinkmini/bootloader/main.c | 1 + .../boards/oplinkmini/bootloader/pios_board.c | 2 +- flight/targets/boards/oplinkmini/pios_board.h | 5 +- flight/targets/boards/osd/board_hw_defs.c | 100 +-- .../boards/osd/bootloader/pios_board.c | 11 +- .../targets/boards/osd/firmware/pios_board.c | 139 +-- .../targets/boards/revolution/board_hw_defs.c | 16 +- .../boards/revolution/bootloader/pios_board.c | 13 +- .../targets/boards/revonano/board_hw_defs.c | 2 + .../boards/revonano/bootloader/pios_board.c | 5 - .../targets/boards/revoproto/board_hw_defs.c | 747 +++++++-------- .../boards/revoproto/bootloader/main.c | 1 + .../boards/revoproto/bootloader/pios_board.c | 9 +- .../boards/revoproto/firmware/pios_board.c | 849 +++--------------- flight/targets/boards/revoproto/pios_board.h | 77 +- flight/targets/boards/sparky2/board_hw_defs.c | 4 +- .../targets/boards/sparky2/bootloader/main.c | 1 + .../boards/sparky2/bootloader/pios_board.c | 6 - 29 files changed, 649 insertions(+), 1541 deletions(-) diff --git a/flight/Project/OpenPilotOSX/OpenPilotOSX.xcodeproj/project.pbxproj b/flight/Project/OpenPilotOSX/OpenPilotOSX.xcodeproj/project.pbxproj index c224603ce8..d2a27e5745 100644 --- a/flight/Project/OpenPilotOSX/OpenPilotOSX.xcodeproj/project.pbxproj +++ b/flight/Project/OpenPilotOSX/OpenPilotOSX.xcodeproj/project.pbxproj @@ -184,7 +184,7 @@ /* Begin PBXLegacyTarget section */ 6581071511DE809D0049FB12 /* OpenPilotOSX */ = { isa = PBXLegacyTarget; - buildArgumentsString = ef_gpsplatinum; + buildArgumentsString = ef_osd; buildConfigurationList = 6581071A11DE80A30049FB12 /* Build configuration list for PBXLegacyTarget "OpenPilotOSX" */; buildPhases = ( ); diff --git a/flight/pios/common/pios_board_io.c b/flight/pios/common/pios_board_io.c index 6ee7880514..6b639c1503 100644 --- a/flight/pios/common/pios_board_io.c +++ b/flight/pios/common/pios_board_io.c @@ -87,6 +87,10 @@ uint32_t pios_rfm22b_id; /* RFM22B handle */ uint32_t pios_com_rf_id; /* RFM22B telemetry */ #endif +#ifdef PIOS_INCLUDE_OPENLRS +uint32_t pios_openlrs_id; /* OpenLRS handle */ +#endif + uint32_t pios_com_hkosd_id; /* HK OSD ?? */ uint32_t pios_com_msp_id; /* MSP */ uint32_t pios_com_mavlink_id; /* MAVLink */ @@ -157,18 +161,47 @@ static void PIOS_BOARD_IO_HID_Init(uint32_t *com_id, uint16_t rx_buf_len, uint16 } } -void PIOS_BOARD_IO_Configure_USB() +PIOS_BOARD_IO_USB_HID_Function PIOS_BOARD_IO_HWSettings_USB_HID_Function() { - /* Initialize board specific USB data */ - PIOS_USB_BOARD_DATA_Init(); - + static const PIOS_BOARD_IO_USB_HID_Function map[] = { + [HWSETTINGS_USB_HIDPORT_USBTELEMETRY] = PIOS_BOARD_IO_USB_HID_TELEMETRY, + [HWSETTINGS_USB_HIDPORT_RCTRANSMITTER] = PIOS_BOARD_IO_USB_HID_RCTX, + }; uint8_t hwsettings_usb_hidport; + HwSettingsUSB_HIDPortGet(&hwsettings_usb_hidport); -#if defined(PIOS_INCLUDE_USB_CDC) + return (hwsettings_usb_hidport < NELEMENTS(map)) ? map[hwsettings_usb_hidport] : PIOS_BOARD_IO_USB_HID_NONE; +} + +PIOS_BOARD_IO_USB_VCP_Function PIOS_BOARD_IO_HWSettings_USB_VCP_Function() +{ + static const PIOS_BOARD_IO_USB_VCP_Function map[] = { + [HWSETTINGS_USB_VCPPORT_USBTELEMETRY] = PIOS_BOARD_IO_USB_VCP_TELEMETRY, + [HWSETTINGS_USB_VCPPORT_COMBRIDGE] = PIOS_BOARD_IO_USB_VCP_COMBRIDGE, + [HWSETTINGS_USB_VCPPORT_DEBUGCONSOLE] = PIOS_BOARD_IO_USB_VCP_DEBUGCONSOLE, + [HWSETTINGS_USB_VCPPORT_MAVLINK] = PIOS_BOARD_IO_USB_VCP_MAVLINK, + }; + uint8_t hwsettings_usb_vcpport; + HwSettingsUSB_VCPPortGet(&hwsettings_usb_vcpport); + return (hwsettings_usb_vcpport < NELEMENTS(map)) ? map[hwsettings_usb_vcpport] : PIOS_BOARD_IO_USB_VCP_NONE; +} + +void PIOS_BOARD_IO_Configure_USB() +{ + PIOS_BOARD_IO_Configure_USB_Function(PIOS_BOARD_IO_HWSettings_USB_HID_Function(), + PIOS_BOARD_IO_HWSettings_USB_VCP_Function()); +} + +void PIOS_BOARD_IO_Configure_USB_Function(PIOS_BOARD_IO_USB_HID_Function hid_function, __attribute__((unused)) PIOS_BOARD_IO_USB_VCP_Function vcp_function) +{ + /* Initialize board specific USB data */ + PIOS_USB_BOARD_DATA_Init(); + +#if defined(PIOS_INCLUDE_USB_CDC) if (PIOS_USB_DESC_HID_CDC_Init()) { PIOS_Assert(0); } @@ -182,21 +215,21 @@ void PIOS_BOARD_IO_Configure_USB() PIOS_USB_Init(&pios_usb_id, PIOS_BOARD_HW_DEFS_GetUsbCfg(pios_board_info_blob.board_rev)); #if defined(PIOS_INCLUDE_USB_CDC) - switch (hwsettings_usb_vcpport) { - case HWSETTINGS_USB_VCPPORT_DISABLED: + switch (vcp_function) { + case PIOS_BOARD_IO_USB_VCP_NONE: break; - case HWSETTINGS_USB_VCPPORT_USBTELEMETRY: + case PIOS_BOARD_IO_USB_VCP_TELEMETRY: PIOS_BOARD_IO_VCP_Init(&pios_com_telem_usb_id, PIOS_COM_TELEM_USB_RX_BUF_LEN, PIOS_COM_TELEM_USB_TX_BUF_LEN, pios_usb_id); break; - case HWSETTINGS_USB_VCPPORT_COMBRIDGE: + case PIOS_BOARD_IO_USB_VCP_COMBRIDGE: PIOS_BOARD_IO_VCP_Init(&pios_com_vcp_id, PIOS_COM_BRIDGE_RX_BUF_LEN, PIOS_COM_BRIDGE_TX_BUF_LEN, pios_usb_id); break; - case HWSETTINGS_USB_VCPPORT_DEBUGCONSOLE: + case PIOS_BOARD_IO_USB_VCP_DEBUGCONSOLE: #if defined(PIOS_INCLUDE_DEBUG_CONSOLE) PIOS_BOARD_IO_VCP_Init(&pios_com_debug_id, 0, PIOS_COM_BRIDGE_TX_BUF_LEN, pios_usb_id); #endif /* PIOS_INCLUDE_DEBUG_CONSOLE */ break; - case HWSETTINGS_USB_VCPPORT_MAVLINK: + case PIOS_BOARD_IO_USB_VCP_MAVLINK: PIOS_BOARD_IO_VCP_Init(&pios_com_mavlink_id, PIOS_COM_MAVLINK_RX_BUF_LEN, PIOS_COM_MAVLINK_TX_BUF_LEN, pios_usb_id); break; } @@ -205,13 +238,13 @@ void PIOS_BOARD_IO_Configure_USB() #if defined(PIOS_INCLUDE_USB_HID) /* Configure the usb HID port */ - switch (hwsettings_usb_hidport) { - case HWSETTINGS_USB_HIDPORT_DISABLED: + switch (hid_function) { + case PIOS_BOARD_IO_USB_HID_NONE: break; - case HWSETTINGS_USB_HIDPORT_USBTELEMETRY: + case PIOS_BOARD_IO_USB_HID_TELEMETRY: PIOS_BOARD_IO_HID_Init(&pios_com_telem_usb_id, PIOS_COM_TELEM_USB_RX_BUF_LEN, PIOS_COM_TELEM_USB_TX_BUF_LEN, pios_usb_id); break; - case HWSETTINGS_USB_HIDPORT_RCTRANSMITTER: + case PIOS_BOARD_IO_USB_HID_RCTX: #if defined(PIOS_INCLUDE_USB_RCTX) if (PIOS_USB_RCTX_Init(&pios_usb_rctx_id, &pios_usb_rctx_cfg, pios_usb_id)) { PIOS_Assert(0); @@ -274,9 +307,11 @@ struct uart_function { uint32_t *com_id; uint16_t com_rx_buf_len; uint16_t com_tx_buf_len; +#ifdef PIOS_INCLUDE_RCVR int32_t (*rcvr_init)(uint32_t *target, const struct pios_com_driver *driver, uint32_t lower_id); const struct pios_rcvr_driver *rcvr_driver; ManualControlSettingsChannelGroupsOptions rcvr_group; +#endif }; static const struct uart_function uart_function_map[] = { @@ -297,13 +332,13 @@ static const struct uart_function uart_function_map[] = { .com_rx_buf_len = PIOS_COM_MSP_RX_BUF_LEN, .com_tx_buf_len = PIOS_COM_MSP_TX_BUF_LEN, }, - +#ifdef PIOS_INCLUDE_GPS [PIOS_BOARD_IO_UART_GPS] = { .com_id = &pios_com_gps_id, .com_rx_buf_len = PIOS_COM_GPS_RX_BUF_LEN, .com_tx_buf_len = PIOS_COM_GPS_TX_BUF_LEN, }, - +#endif [PIOS_BOARD_IO_UART_OSDHK] = { .com_id = &pios_com_hkosd_id, .com_rx_buf_len = PIOS_COM_HKOSD_RX_BUF_LEN, @@ -409,7 +444,9 @@ void PIOS_BOARD_IO_Configure_UART(const struct pios_usart_cfg *hw_config, PIOS_B 0, uart_function_map[function].com_tx_buf_len)) { PIOS_Assert(0); } - } else if (uart_function_map[function].rcvr_init) { + } +#ifdef PIOS_INCLUDE_RCVR + else if (uart_function_map[function].rcvr_init) { uint32_t usart_id; if (PIOS_USART_Init(&usart_id, hw_config)) { @@ -429,6 +466,7 @@ void PIOS_BOARD_IO_Configure_UART(const struct pios_usart_cfg *hw_config, PIOS_B pios_rcvr_group_map[uart_function_map[function].rcvr_group] = rcvr_id; } +#endif /* PIOS_INCLUDE_RCVR */ } #ifdef PIOS_INCLUDE_PWM @@ -513,13 +551,12 @@ void PIOS_BOARD_IO_Configure_RFM22B(PIOS_BOARD_IO_RADIOAUX_Function radioaux_fun if (is_enabled) { if (openlrs) { #if defined(PIOS_INCLUDE_OPENLRS_RCVR) && defined(PIOS_INCLUDE_RCVR) - uint32_t openlrs_id; const struct pios_openlrs_cfg *openlrs_cfg = PIOS_BOARD_HW_DEFS_GetOpenLRSCfg(pios_board_info_blob.board_rev); - PIOS_OpenLRS_Init(&openlrs_id, PIOS_SPI_RFM22B_ADAPTER, 0, openlrs_cfg); + PIOS_OpenLRS_Init(&pios_openlrs_id, PIOS_SPI_RFM22B_ADAPTER, 0, openlrs_cfg); uint32_t openlrsrcvr_id; - PIOS_OpenLRS_Rcvr_Init(&openlrsrcvr_id, openlrs_id); + PIOS_OpenLRS_Rcvr_Init(&openlrsrcvr_id, pios_openlrs_id); uint32_t openlrsrcvr_rcvr_id; if (PIOS_RCVR_Init(&openlrsrcvr_rcvr_id, &pios_openlrs_rcvr_driver, openlrsrcvr_id)) { @@ -529,7 +566,7 @@ void PIOS_BOARD_IO_Configure_RFM22B(PIOS_BOARD_IO_RADIOAUX_Function radioaux_fun #endif /* PIOS_INCLUDE_OPENLRS_RCVR && PIOS_INCLUDE_RCVR */ } else { /* Configure the RFM22B device. */ - const struct pios_rfm22b_cfg *rfm22b_cfg = PIOS_BOARD_HW_DEFS_GetRfm22Cfg(pios_board_info_blob.board_rev); + const struct pios_rfm22b_cfg *rfm22b_cfg = PIOS_BOARD_HW_DEFS_GetRfm22bCfg(pios_board_info_blob.board_rev); if (PIOS_RFM22B_Init(&pios_rfm22b_id, PIOS_SPI_RFM22B_ADAPTER, rfm22b_cfg->slave_num, rfm22b_cfg, oplinkSettings.RFBand)) { PIOS_Assert(0); diff --git a/flight/pios/common/pios_board_sensors.c b/flight/pios/common/pios_board_sensors.c index fecfe17dde..3b0e58b6cb 100644 --- a/flight/pios/common/pios_board_sensors.c +++ b/flight/pios/common/pios_board_sensors.c @@ -42,7 +42,7 @@ # include #endif -#if defined(PIOS_INCLUDE_ADXL345) +#ifdef PIOS_INCLUDE_ADXL345 # include #endif @@ -51,13 +51,21 @@ # include #endif -#if defined(PIOS_INCLUDE_HMC5X83) +#ifdef PIOS_INCLUDE_HMC5X83 # include "pios_hmc5x83.h" -# if defined(PIOS_HMC5X83_HAS_GPIOS) +# ifdef PIOS_HMC5X83_HAS_GPIOS pios_hmc5x83_dev_t pios_hmc5x83_internal_id; # endif #endif +#ifdef PIOS_INCLUDE_L3GD20 +# include "pios_l3gd20.h" +#endif + +#ifdef PIOS_INCLUDE_BMA180 +# include "pios_bma180.h" +#endif + #ifdef PIOS_INCLUDE_ADC # include "pios_adc_priv.h" #endif @@ -75,10 +83,6 @@ void PIOS_BOARD_Sensors_Configure() } #endif /* PIOS_INCLUDE_MPU6000 */ -#ifdef PIOS_INCLUDE_ADXL345 - PIOS_ADXL345_Init(PIOS_SPI_ADXL345_ADAPTER, 0); -#endif - #ifdef PIOS_INCLUDE_MPU9250 const struct pios_mpu9250_cfg *mpu9250_cfg = PIOS_BOARD_HW_DEFS_GetMPU9250Cfg(pios_board_info_blob.board_rev); if (mpu9250_cfg) { @@ -89,6 +93,27 @@ void PIOS_BOARD_Sensors_Configure() } #endif /* PIOS_INCLUDE_MPU9250 */ +#ifdef PIOS_INCLUDE_ADXL345 + if (PIOS_BOARD_HW_DEFS_GetADXL345Cfg(pios_board_info_blob.board_rev)) { + PIOS_ADXL345_Init(PIOS_SPI_ADXL345_ADAPTER, 0); + } +#endif +#if defined(PIOS_INCLUDE_L3GD20) + const struct pios_l3gd20_cfg *l3gd20_cfg = PIOS_BOARD_HW_DEFS_GetL3GD20Cfg(pios_board_info_blob.board_rev); + if (l3gd20_cfg) { + PIOS_Assert(0); // L3gd20 has not been ported to Sensor framework!!! + PIOS_L3GD20_Init(PIOS_SPI_L3GD20_ADAPTER, 0, l3gd20_cfg); + PIOS_Assert(PIOS_L3GD20_Test() == 0); + } +#endif +#if defined(PIOS_INCLUDE_BMA180) + const struct pios_bma180_cfg *bma180_cfg = PIOS_BOARD_HW_DEFS_GetBMA180Cfg(pios_board_info_blob.board_rev); + if (bma180_cfg) { + PIOS_Assert(0); // BMA180 has not been ported to Sensor framework!!! + PIOS_BMA180_Init(PIOS_SPI_BMA180_ADAPTER, 0, bma180_cfg); + PIOS_Assert(PIOS_BMA180_Test() == 0); + } +#endif // internal HMC5x83 mag # ifdef PIOS_INCLUDE_HMC5X83_INTERNAL diff --git a/flight/pios/inc/pios_board_hw.h b/flight/pios/inc/pios_board_hw.h index 4c786d99a6..53d3054f87 100644 --- a/flight/pios/inc/pios_board_hw.h +++ b/flight/pios/inc/pios_board_hw.h @@ -33,7 +33,7 @@ const struct pios_gpio_cfg *PIOS_BOARD_HW_DEFS_GetLedCfg(uint32_t board_revision const struct pios_usb_cfg *PIOS_BOARD_HW_DEFS_GetUsbCfg(uint32_t board_revision); #endif #ifdef PIOS_INCLUDE_RFM22B -const struct pios_rfm22b_cfg *PIOS_BOARD_HW_DEFS_GetRfm22Cfg(uint32_t board_revision); +const struct pios_rfm22b_cfg *PIOS_BOARD_HW_DEFS_GetRfm22bCfg(uint32_t board_revision); #endif #ifdef PIOS_INCLUDE_OPENLRS const struct pios_openlrs_cfg *PIOS_BOARD_HW_DEFS_GetOpenLRSCfg(uint32_t board_revision); @@ -59,4 +59,13 @@ const struct pios_mpu6000_cfg *PIOS_BOARD_HW_DEFS_GetMPU6000Cfg(uint32_t board_r #ifdef PIOS_INCLUDE_MPU9250 const struct pios_mpu9250_cfg *PIOS_BOARD_HW_DEFS_GetMPU9250Cfg(uint32_t board_revision); #endif +#ifdef PIOS_INCLUDE_ADXL345 +bool PIOS_BOARD_HW_DEFS_GetADXL345Cfg(uint32_t board_revision); +#endif +#ifdef PIOS_INCLUDE_L3GD20 +const struct pios_l3gd20_cfg *PIOS_BOARD_HW_DEFS_GetL3GD20Cfg(uint32_t board_revision); +#endif +#ifdef PIOS_INCLUDE_BMA180 +const struct pios_bma180_cfg *PIOS_BOARD_HW_DEFS_GetBMA180Cfg(uint32_t board_revision); +#endif #endif /* PIOS_BOARD_HW_H */ diff --git a/flight/pios/inc/pios_board_io.h b/flight/pios/inc/pios_board_io.h index 9ba4dc0d0f..d186f5ea52 100644 --- a/flight/pios/inc/pios_board_io.h +++ b/flight/pios/inc/pios_board_io.h @@ -95,7 +95,6 @@ extern uint32_t pios_com_telem_rf_id; # define PIOS_COM_TELEM_RF_TX_BUF_LEN 512 #endif - /* RFM22B telemetry */ #ifdef PIOS_INCLUDE_RFM22B extern uint32_t pios_rfm22b_id; /* RFM22B handle */ @@ -109,6 +108,10 @@ extern uint32_t pios_com_rf_id; /* oplink telemetry */ # endif #endif +#ifdef PIOS_INCLUDE_OPENLRS +extern uint32_t pios_openlrs_id; /* openlrs handle */ +#endif + /* HK OSD ?? */ extern uint32_t pios_com_hkosd_id; @@ -175,7 +178,7 @@ extern pios_hmc5x83_dev_t pios_hmc5x83_internal_id; #endif typedef enum { - PIOS_BOARD_IO_UART_NONE, + PIOS_BOARD_IO_UART_NONE = 0, PIOS_BOARD_IO_UART_TELEMETRY, /* com */ PIOS_BOARD_IO_UART_MAVLINK, /* com */ PIOS_BOARD_IO_UART_MSP, /* com */ @@ -197,7 +200,7 @@ typedef enum { } PIOS_BOARD_IO_UART_Function; typedef enum { - PIOS_BOARD_IO_RADIOAUX_NONE, + PIOS_BOARD_IO_RADIOAUX_NONE = 0, PIOS_BOARD_IO_RADIOAUX_MAVLINK, PIOS_BOARD_IO_RADIOAUX_COMBRIDGE, PIOS_BOARD_IO_RADIOAUX_DEBUGCONSOLE, @@ -206,11 +209,23 @@ typedef enum { #ifdef PIOS_INCLUDE_USB void PIOS_BOARD_IO_Configure_USB(); -// # if defined(PIOS_INCLUDE_USB_HID) -// # include -// extern const struct pios_usb_hid_cfg pios_usb_hid_cfg; -// # endif /* PIOS_INCLUDE_USB_HID */ -#endif /* PIOS_INCLUDE_USB */ + +typedef enum { + PIOS_BOARD_IO_USB_HID_NONE = 0, + PIOS_BOARD_IO_USB_HID_TELEMETRY, + PIOS_BOARD_IO_USB_HID_RCTX, +} PIOS_BOARD_IO_USB_HID_Function; + +typedef enum { + PIOS_BOARD_IO_USB_VCP_NONE = 0, + PIOS_BOARD_IO_USB_VCP_TELEMETRY, + PIOS_BOARD_IO_USB_VCP_COMBRIDGE, + PIOS_BOARD_IO_USB_VCP_DEBUGCONSOLE, + PIOS_BOARD_IO_USB_VCP_MAVLINK, +} PIOS_BOARD_IO_USB_VCP_Function; + +void PIOS_BOARD_IO_Configure_USB_Function(PIOS_BOARD_IO_USB_HID_Function hid_function, PIOS_BOARD_IO_USB_VCP_Function vcp_function); +#endif #ifdef PIOS_INCLUDE_PWM void PIOS_BOARD_IO_Configure_PWM(const struct pios_pwm_cfg *pwm_cfg); #endif diff --git a/flight/targets/boards/coptercontrol/board_hw_defs.c b/flight/targets/boards/coptercontrol/board_hw_defs.c index 9fde0bb45e..d6b93ff4c0 100644 --- a/flight/targets/boards/coptercontrol/board_hw_defs.c +++ b/flight/targets/boards/coptercontrol/board_hw_defs.c @@ -486,9 +486,9 @@ void PIOS_ADC_handler() PIOS_ADC_DMA_Handler(); } -const struct pios_adc_cfg *PIOS_BOARD_HW_DEFS_GetAdcCfg(__attribute__((unused)) uint32_t board_revision) +const struct pios_adc_cfg *PIOS_BOARD_HW_DEFS_GetAdcCfg(uint32_t board_revision) { - return &pios_adc_cfg; + return (board_revision == BOARD_REVISION_CC) ? &pios_adc_cfg : 0; } #endif /* if defined(PIOS_INCLUDE_ADC) */ @@ -1044,6 +1044,13 @@ static const struct pios_mpu6000_cfg pios_mpu6000_cfg = { const struct pios_mpu6000_cfg *PIOS_BOARD_HW_DEFS_GetMPU6000Cfg(__attribute__((unused)) uint32_t board_revision) { - return &pios_mpu6000_cfg; + return (board_revision == BOARD_REVISION_CC3D) ? &pios_mpu6000_cfg : 0; } #endif /* PIOS_INCLUDE_MPU6000 */ + +#ifdef PIOS_INCLUDE_ADXL345 +bool PIOS_BOARD_HW_DEFS_GetADXL345Cfg(uint32_t board_revision) +{ + return board_revision == BOARD_REVISION_CC; +} +#endif diff --git a/flight/targets/boards/coptercontrol/bootloader/pios_board.c b/flight/targets/boards/coptercontrol/bootloader/pios_board.c index 466566d553..39c4e9e8a7 100644 --- a/flight/targets/boards/coptercontrol/bootloader/pios_board.c +++ b/flight/targets/boards/coptercontrol/bootloader/pios_board.c @@ -49,13 +49,6 @@ uint32_t pios_com_telem_usb_id; */ static bool board_init_complete = false; -#if defined(PIOS_INCLUDE_USART) -static int32_t PIOS_BOARD_USART_Ioctl(__attribute__((unused)) uint32_t usart_id, __attribute__((unused)) uint32_t ctl, __attribute__((unused)) void *param) -{ - return -1; -} -#endif - void PIOS_Board_Init(void) { if (board_init_complete) { diff --git a/flight/targets/boards/discoveryf4bare/board_hw_defs.c b/flight/targets/boards/discoveryf4bare/board_hw_defs.c index bcae0c028b..15b2012a84 100644 --- a/flight/targets/boards/discoveryf4bare/board_hw_defs.c +++ b/flight/targets/boards/discoveryf4bare/board_hw_defs.c @@ -537,7 +537,7 @@ const struct pios_rfm22b_cfg pios_rfm22b_rm2_cfg = { .gpio_direction = GPIO0_TX_GPIO1_RX, }; -const struct pios_rfm22b_cfg *PIOS_BOARD_HW_DEFS_GetRfm22Cfg(uint32_t board_revision) +const struct pios_rfm22b_cfg *PIOS_BOARD_HW_DEFS_GetRfm22bCfg(uint32_t board_revision) { switch (board_revision) { case 2: @@ -600,6 +600,7 @@ static const struct flashfs_logfs_cfg flashfs_internal_user_cfg = { }; #endif /* PIOS_INCLUDE_FLASH */ +#ifdef PIOS_INCLUDE_USART #include /* @@ -708,6 +709,7 @@ static const struct pios_usart_cfg pios_usart_flexiio_cfg = { .pin_source = GPIO_PinSource7, } }; +#endif /* PIOS_INCLUDE_USART */ #if defined(PIOS_INCLUDE_COM) diff --git a/flight/targets/boards/discoveryf4bare/bootloader/pios_board.c b/flight/targets/boards/discoveryf4bare/bootloader/pios_board.c index b867b81d79..fd64e58fa0 100644 --- a/flight/targets/boards/discoveryf4bare/bootloader/pios_board.c +++ b/flight/targets/boards/discoveryf4bare/bootloader/pios_board.c @@ -40,11 +40,6 @@ uint32_t pios_com_telem_usb_id; static bool board_init_complete = false; -static int32_t PIOS_BOARD_USART_Ioctl(__attribute__((unused)) uint32_t usart_id, __attribute__((unused)) uint32_t ctl, __attribute__((unused)) void *param) -{ - return -1; -} - void PIOS_Board_Init() { if (board_init_complete) { diff --git a/flight/targets/boards/gpsplatinum/board_hw_defs.c b/flight/targets/boards/gpsplatinum/board_hw_defs.c index 489d49bf5d..7b19737f42 100644 --- a/flight/targets/boards/gpsplatinum/board_hw_defs.c +++ b/flight/targets/boards/gpsplatinum/board_hw_defs.c @@ -268,7 +268,7 @@ static const struct pios_hmc5x83_cfg pios_mag_cfg = { static const struct pios_usart_cfg pios_usart_generic_main_cfg = { .regs = USART1, .remap = GPIO_AF_1, - .rx = { + .rx = { .gpio = GPIOA, .init = { .GPIO_Pin = GPIO_Pin_10, diff --git a/flight/targets/boards/oplinkmini/board_hw_defs.c b/flight/targets/boards/oplinkmini/board_hw_defs.c index 0810721cb1..85130655db 100644 --- a/flight/targets/boards/oplinkmini/board_hw_defs.c +++ b/flight/targets/boards/oplinkmini/board_hw_defs.c @@ -307,7 +307,7 @@ struct pios_rfm22b_cfg pios_rfm22b_cfg = { }; // ! Compatibility layer for various hardware revisions -const struct pios_rfm22b_cfg *PIOS_BOARD_HW_DEFS_GetRfm22Cfg(__attribute__((unused)) uint32_t board_revision) +const struct pios_rfm22b_cfg *PIOS_BOARD_HW_DEFS_GetRfm22bCfg(__attribute__((unused)) uint32_t board_revision) { return &pios_rfm22b_cfg; } @@ -795,6 +795,11 @@ static const struct pios_usb_cfg pios_usb_main_cfg = { .vsense_active_low = false }; +const struct pios_usb_cfg *PIOS_BOARD_HW_DEFS_GetUsbCfg(__attribute__((unused)) uint32_t board_revision) +{ + return &pios_usb_main_cfg; +} + #include "pios_usb_board_data_priv.h" #include "pios_usb_desc_hid_cdc_priv.h" #include "pios_usb_desc_hid_only_priv.h" diff --git a/flight/targets/boards/oplinkmini/bootloader/main.c b/flight/targets/boards/oplinkmini/bootloader/main.c index 2dc3842ed0..566caea735 100644 --- a/flight/targets/boards/oplinkmini/bootloader/main.c +++ b/flight/targets/boards/oplinkmini/bootloader/main.c @@ -34,6 +34,7 @@ #include #include #include +#include extern void FLASH_Download(); #define BSL_HOLD_STATE ((PIOS_USB_DETECT_GPIO_PORT->IDR & PIOS_USB_DETECT_GPIO_PIN) ? 0 : 1) diff --git a/flight/targets/boards/oplinkmini/bootloader/pios_board.c b/flight/targets/boards/oplinkmini/bootloader/pios_board.c index 4dad876dc1..5eea6e97a5 100644 --- a/flight/targets/boards/oplinkmini/bootloader/pios_board.c +++ b/flight/targets/boards/oplinkmini/bootloader/pios_board.c @@ -76,7 +76,7 @@ void PIOS_Board_Init(void) } #if defined(PIOS_INCLUDE_USB_HID) && defined(PIOS_INCLUDE_COM_MSG) uint32_t pios_usb_hid_id; - if (PIOS_USB_HID_Init(&pios_usb_hid_id, &pios_usb_hid_cfg, pios_usb_id)) { + if (PIOS_USB_HID_Init(&pios_usb_hid_id, &pios_usb_hid_only_cfg, pios_usb_id)) { PIOS_Assert(0); } if (PIOS_COM_MSG_Init(&pios_com_telem_usb_id, &pios_usb_hid_com_driver, pios_usb_hid_id)) { diff --git a/flight/targets/boards/oplinkmini/pios_board.h b/flight/targets/boards/oplinkmini/pios_board.h index ab7e3630aa..e96c0b12d6 100644 --- a/flight/targets/boards/oplinkmini/pios_board.h +++ b/flight/targets/boards/oplinkmini/pios_board.h @@ -159,12 +159,13 @@ extern uint32_t pios_i2c_flexi_adapter_id; // PIOS_SPI // See also pios_board.c // ------------------------ -#define PIOS_SPI_MAX_DEVS 1 +#define PIOS_SPI_MAX_DEVS 1 +#define PIOS_SPI_RFM22B_ADAPTER (pios_spi_rfm22b_id) // ------------------------- // PIOS_USART // ------------------------- -#define PIOS_USART_MAX_DEVS 3 +#define PIOS_USART_MAX_DEVS 3 // ------------------------- // PIOS_COM diff --git a/flight/targets/boards/osd/board_hw_defs.c b/flight/targets/boards/osd/board_hw_defs.c index ed86e0915c..d38d509ce6 100644 --- a/flight/targets/boards/osd/board_hw_defs.c +++ b/flight/targets/boards/osd/board_hw_defs.c @@ -233,24 +233,7 @@ void PIOS_SPI_sdcard_irq_handler(void) static const struct pios_usart_cfg pios_usart_gps_cfg = { .regs = USART1, .remap = GPIO_AF_USART1, - .init = { - .USART_BaudRate = 57600, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = - USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx | USART_Mode_Tx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART1_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_LOW, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { + .rx = { .gpio = GPIOA, .init = { .GPIO_Pin = GPIO_Pin_10, @@ -260,7 +243,7 @@ static const struct pios_usart_cfg pios_usart_gps_cfg = { .GPIO_PuPd = GPIO_PuPd_UP }, }, - .tx = { + .tx = { .gpio = GPIOA, .init = { .GPIO_Pin = GPIO_Pin_9, @@ -280,24 +263,7 @@ static const struct pios_usart_cfg pios_usart_gps_cfg = { static const struct pios_usart_cfg pios_usart_aux_cfg = { .regs = USART2, .remap = GPIO_AF_USART2, - .init = { - .USART_BaudRate = 57600, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = - USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx | USART_Mode_Tx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART2_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { + .rx = { .gpio = GPIOA, .init = { .GPIO_Pin = GPIO_Pin_3, @@ -307,7 +273,7 @@ static const struct pios_usart_cfg pios_usart_aux_cfg = { .GPIO_PuPd = GPIO_PuPd_UP }, }, - .tx = { + .tx = { .gpio = GPIOA, .init = { .GPIO_Pin = GPIO_Pin_2, @@ -328,24 +294,7 @@ static const struct pios_usart_cfg pios_usart_aux_cfg = { static const struct pios_usart_cfg pios_usart_telem_main_cfg = { .regs = UART4, .remap = GPIO_AF_UART4, - .init = { - .USART_BaudRate = 57600, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = - USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx | USART_Mode_Tx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = UART4_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { + .rx = { .gpio = GPIOA, .init = { .GPIO_Pin = GPIO_Pin_1, @@ -355,7 +304,7 @@ static const struct pios_usart_cfg pios_usart_telem_main_cfg = { .GPIO_PuPd = GPIO_PuPd_UP }, }, - .tx = { + .tx = { .gpio = GPIOA, .init = { .GPIO_Pin = GPIO_Pin_0, @@ -509,41 +458,12 @@ static const struct pios_usb_cfg pios_usb_main_cfg = { .vsense_active_low = false }; -#include "pios_usb_board_data_priv.h" -#include "pios_usb_desc_hid_cdc_priv.h" -#include "pios_usb_desc_hid_only_priv.h" -#include "pios_usbhook.h" - +const struct pios_usb_cfg *PIOS_BOARD_HW_DEFS_GetUsbCfg(__attribute__((unused)) uint32_t board_revision) +{ + return &pios_usb_main_cfg; +} #endif /* PIOS_INCLUDE_USB */ -#if defined(PIOS_INCLUDE_COM_MSG) - -#include - -#endif /* PIOS_INCLUDE_COM_MSG */ - -#if defined(PIOS_INCLUDE_USB_HID) -#include - -const struct pios_usb_hid_cfg pios_usb_hid_cfg = { - .data_if = 2, - .data_rx_ep = 1, - .data_tx_ep = 1, -}; -#endif /* PIOS_INCLUDE_USB_HID */ - -#if defined(PIOS_INCLUDE_USB_CDC) -#include - -const struct pios_usb_cdc_cfg pios_usb_cdc_cfg = { - .ctrl_if = 0, - .ctrl_tx_ep = 2, - - .data_if = 1, - .data_rx_ep = 3, - .data_tx_ep = 3, -}; -#endif /* PIOS_INCLUDE_USB_CDC */ #if defined(PIOS_INCLUDE_VIDEO) diff --git a/flight/targets/boards/osd/bootloader/pios_board.c b/flight/targets/boards/osd/bootloader/pios_board.c index 7e9858f18a..bbd7232e9d 100644 --- a/flight/targets/boards/osd/bootloader/pios_board.c +++ b/flight/targets/boards/osd/bootloader/pios_board.c @@ -26,6 +26,15 @@ #include #include + +#include "pios_usb_board_data_priv.h" +#include "pios_usb_desc_hid_cdc_priv.h" +#include "pios_usb_desc_hid_only_priv.h" +#include "pios_usbhook.h" + +#include + + /* * Pull in the board-specific static HW definitions. * Including .c files is a bit ugly but this allows all of @@ -64,7 +73,7 @@ void PIOS_Board_Init() #if defined(PIOS_INCLUDE_USB_HID) && defined(PIOS_INCLUDE_COM_MSG) uint32_t pios_usb_hid_id; - if (PIOS_USB_HID_Init(&pios_usb_hid_id, &pios_usb_hid_cfg, pios_usb_id)) { + if (PIOS_USB_HID_Init(&pios_usb_hid_id, &pios_usb_hid_only_cfg, pios_usb_id)) { PIOS_Assert(0); } if (PIOS_COM_MSG_Init(&pios_com_telem_usb_id, &pios_usb_hid_com_driver, pios_usb_hid_id)) { diff --git a/flight/targets/boards/osd/firmware/pios_board.c b/flight/targets/boards/osd/firmware/pios_board.c index 680c93c2e4..5a7f5649ad 100644 --- a/flight/targets/boards/osd/firmware/pios_board.c +++ b/flight/targets/boards/osd/firmware/pios_board.c @@ -31,6 +31,8 @@ #include #include +#include + /* * Pull in the board-specific static HW definitions. * Including .c files is a bit ugly but this allows all of @@ -84,25 +86,10 @@ void PIOS_ADC_DMC_irq_handler(void) static void Clock(uint32_t spektrum_id); - -#define PIOS_COM_TELEM_RF_RX_BUF_LEN 128 -#define PIOS_COM_TELEM_RF_TX_BUF_LEN 128 - -#define PIOS_COM_AUX_RX_BUF_LEN 512 -#define PIOS_COM_AUX_TX_BUF_LEN 512 - -#define PIOS_COM_GPS_RX_BUF_LEN 32 - -#define PIOS_COM_TELEM_USB_RX_BUF_LEN 65 -#define PIOS_COM_TELEM_USB_TX_BUF_LEN 65 - -#define PIOS_COM_BRIDGE_RX_BUF_LEN 65 -#define PIOS_COM_BRIDGE_TX_BUF_LEN 12 +#define PIOS_COM_AUX_RX_BUF_LEN 512 +#define PIOS_COM_AUX_TX_BUF_LEN 512 uint32_t pios_com_aux_id; -uint32_t pios_com_gps_id; -uint32_t pios_com_telem_usb_id; -uint32_t pios_com_telem_rf_id; uintptr_t pios_uavo_settings_fs_id; uintptr_t pios_user_fs_id = 0; @@ -216,125 +203,9 @@ void PIOS_Board_Init(void) #endif #if defined(PIOS_INCLUDE_USB) - /* Initialize board specific USB data */ - PIOS_USB_BOARD_DATA_Init(); - - /* Flags to determine if various USB interfaces are advertised */ - bool usb_hid_present = false; - bool usb_cdc_present = false; - -#if defined(PIOS_INCLUDE_USB_CDC) - if (PIOS_USB_DESC_HID_CDC_Init()) { - PIOS_Assert(0); - } - usb_hid_present = true; - usb_cdc_present = true; -#else - if (PIOS_USB_DESC_HID_ONLY_Init()) { - PIOS_Assert(0); - } - usb_hid_present = true; + PIOS_BOARD_IO_Configure_USB(); #endif - uint32_t pios_usb_id; - PIOS_USB_Init(&pios_usb_id, &pios_usb_main_cfg); - -#if defined(PIOS_INCLUDE_USB_CDC) - - uint8_t hwsettings_usb_vcpport; - /* Configure the USB VCP port */ - HwSettingsUSB_VCPPortGet(&hwsettings_usb_vcpport); - - if (!usb_cdc_present) { - /* Force VCP port function to disabled if we haven't advertised VCP in our USB descriptor */ - hwsettings_usb_vcpport = HWSETTINGS_USB_VCPPORT_DISABLED; - } - - switch (hwsettings_usb_vcpport) { - case HWSETTINGS_USB_VCPPORT_DISABLED: - break; - case HWSETTINGS_USB_VCPPORT_USBTELEMETRY: -#if defined(PIOS_INCLUDE_COM) - { - uint32_t pios_usb_cdc_id; - if (PIOS_USB_CDC_Init(&pios_usb_cdc_id, &pios_usb_cdc_cfg, pios_usb_id)) { - PIOS_Assert(0); - } - uint8_t *rx_buffer = (uint8_t *)pios_malloc(PIOS_COM_TELEM_USB_RX_BUF_LEN); - uint8_t *tx_buffer = (uint8_t *)pios_malloc(PIOS_COM_TELEM_USB_TX_BUF_LEN); - PIOS_Assert(rx_buffer); - PIOS_Assert(tx_buffer); - if (PIOS_COM_Init(&pios_com_telem_usb_id, &pios_usb_cdc_com_driver, pios_usb_cdc_id, - rx_buffer, PIOS_COM_TELEM_USB_RX_BUF_LEN, - tx_buffer, PIOS_COM_TELEM_USB_TX_BUF_LEN)) { - PIOS_Assert(0); - } - } -#endif /* PIOS_INCLUDE_COM */ - break; - case HWSETTINGS_USB_VCPPORT_COMBRIDGE: -#if defined(PIOS_INCLUDE_COM) - { - uint32_t pios_usb_cdc_id; - if (PIOS_USB_CDC_Init(&pios_usb_cdc_id, &pios_usb_cdc_cfg, pios_usb_id)) { - PIOS_Assert(0); - } - uint8_t *rx_buffer = (uint8_t *)pios_malloc(PIOS_COM_BRIDGE_RX_BUF_LEN); - uint8_t *tx_buffer = (uint8_t *)pios_malloc(PIOS_COM_BRIDGE_TX_BUF_LEN); - PIOS_Assert(rx_buffer); - PIOS_Assert(tx_buffer); - if (PIOS_COM_Init(&pios_com_vcp_id, &pios_usb_cdc_com_driver, pios_usb_cdc_id, - rx_buffer, PIOS_COM_BRIDGE_RX_BUF_LEN, - tx_buffer, PIOS_COM_BRIDGE_TX_BUF_LEN)) { - PIOS_Assert(0); - } - } -#endif /* PIOS_INCLUDE_COM */ - break; - } -#endif /* PIOS_INCLUDE_USB_CDC */ - -#if defined(PIOS_INCLUDE_USB_HID) - /* Configure the usb HID port */ - uint8_t hwsettings_usb_hidport; - HwSettingsUSB_HIDPortGet(&hwsettings_usb_hidport); - - if (!usb_hid_present) { - /* Force HID port function to disabled if we haven't advertised HID in our USB descriptor */ - hwsettings_usb_hidport = HWSETTINGS_USB_HIDPORT_DISABLED; - } - - switch (hwsettings_usb_hidport) { - case HWSETTINGS_USB_HIDPORT_DISABLED: - break; - case HWSETTINGS_USB_HIDPORT_USBTELEMETRY: -#if defined(PIOS_INCLUDE_COM) - { - uint32_t pios_usb_hid_id; - if (PIOS_USB_HID_Init(&pios_usb_hid_id, &pios_usb_hid_cfg, pios_usb_id)) { - PIOS_Assert(0); - } - uint8_t *rx_buffer = (uint8_t *)pios_malloc(PIOS_COM_TELEM_USB_RX_BUF_LEN); - uint8_t *tx_buffer = (uint8_t *)pios_malloc(PIOS_COM_TELEM_USB_TX_BUF_LEN); - PIOS_Assert(rx_buffer); - PIOS_Assert(tx_buffer); - if (PIOS_COM_Init(&pios_com_telem_usb_id, &pios_usb_hid_com_driver, pios_usb_hid_id, - rx_buffer, PIOS_COM_TELEM_USB_RX_BUF_LEN, - tx_buffer, PIOS_COM_TELEM_USB_TX_BUF_LEN)) { - PIOS_Assert(0); - } - } -#endif /* PIOS_INCLUDE_COM */ - break; - } - -#endif /* PIOS_INCLUDE_USB_HID */ - - if (usb_hid_present || usb_cdc_present) { - PIOS_USBHOOK_Activate(); - } -#endif /* PIOS_INCLUDE_USB */ - #if defined(PIOS_INCLUDE_COM) #if defined(PIOS_INCLUDE_GPS) diff --git a/flight/targets/boards/revolution/board_hw_defs.c b/flight/targets/boards/revolution/board_hw_defs.c index 6edf839f95..e4ff0a76e6 100644 --- a/flight/targets/boards/revolution/board_hw_defs.c +++ b/flight/targets/boards/revolution/board_hw_defs.c @@ -657,7 +657,7 @@ const struct pios_rfm22b_cfg pios_rfm22b_rm2_cfg = { .gpio_direction = GPIO0_TX_GPIO1_RX, }; -const struct pios_rfm22b_cfg *PIOS_BOARD_HW_DEFS_GetRfm22Cfg(uint32_t board_revision) +const struct pios_rfm22b_cfg *PIOS_BOARD_HW_DEFS_GetRfm22bCfg(uint32_t board_revision) { switch (board_revision) { case 2: @@ -787,6 +787,7 @@ static const struct flashfs_logfs_cfg flashfs_internal_cfg = { #endif /* PIOS_INCLUDE_FLASH */ +#ifdef PIOS_INCLUDE_USART #include /* @@ -896,6 +897,7 @@ static const struct pios_usart_cfg pios_usart_flexiio_cfg = { .pin_source = GPIO_PinSource7, } }; +#endif /* PIOS_INCLUDE_USART */ #if defined(PIOS_INCLUDE_COM) @@ -1447,20 +1449,8 @@ const struct pios_usb_cfg *PIOS_BOARD_HW_DEFS_GetUsbCfg(uint32_t board_revision) } return NULL; } - -#include "pios_usb_board_data_priv.h" -#include "pios_usb_desc_hid_cdc_priv.h" -#include "pios_usb_desc_hid_only_priv.h" -#include "pios_usbhook.h" - #endif /* PIOS_INCLUDE_USB */ -#if defined(PIOS_INCLUDE_COM_MSG) - -#include - -#endif /* PIOS_INCLUDE_COM_MSG */ - #ifdef PIOS_INCLUDE_WS2811 #include #include diff --git a/flight/targets/boards/revolution/bootloader/pios_board.c b/flight/targets/boards/revolution/bootloader/pios_board.c index 595eac507f..8c0394c04d 100644 --- a/flight/targets/boards/revolution/bootloader/pios_board.c +++ b/flight/targets/boards/revolution/bootloader/pios_board.c @@ -27,6 +27,14 @@ #include #include + +#include "pios_usb_board_data_priv.h" +#include "pios_usb_desc_hid_cdc_priv.h" +#include "pios_usb_desc_hid_only_priv.h" +#include "pios_usbhook.h" + +#include + /* * Pull in the board-specific static HW definitions. * Including .c files is a bit ugly but this allows all of @@ -41,11 +49,6 @@ uint32_t pios_com_telem_usb_id; static bool board_init_complete = false; -static int32_t PIOS_BOARD_USART_Ioctl(__attribute__((unused)) uint32_t usart_id, __attribute__((unused)) uint32_t ctl, __attribute__((unused)) void *param) -{ - return -1; -} - void PIOS_Board_Init() { if (board_init_complete) { diff --git a/flight/targets/boards/revonano/board_hw_defs.c b/flight/targets/boards/revonano/board_hw_defs.c index fb4d9f129c..00540256a8 100644 --- a/flight/targets/boards/revonano/board_hw_defs.c +++ b/flight/targets/boards/revonano/board_hw_defs.c @@ -238,6 +238,7 @@ void PIOS_SPI_gyro_irq_handler(void) #endif /* PIOS_INCLUDE_SPI */ +#ifdef PIOS_INCLUDE_USART #include /* @@ -308,6 +309,7 @@ static const struct pios_usart_cfg pios_usart_flexi_cfg = { // }, // }, }; +#endif /* PIOS_INCLUDE_USART */ #if defined(PIOS_INCLUDE_COM) diff --git a/flight/targets/boards/revonano/bootloader/pios_board.c b/flight/targets/boards/revonano/bootloader/pios_board.c index 595eac507f..3639353b95 100644 --- a/flight/targets/boards/revonano/bootloader/pios_board.c +++ b/flight/targets/boards/revonano/bootloader/pios_board.c @@ -41,11 +41,6 @@ uint32_t pios_com_telem_usb_id; static bool board_init_complete = false; -static int32_t PIOS_BOARD_USART_Ioctl(__attribute__((unused)) uint32_t usart_id, __attribute__((unused)) uint32_t ctl, __attribute__((unused)) void *param) -{ - return -1; -} - void PIOS_Board_Init() { if (board_init_complete) { diff --git a/flight/targets/boards/revoproto/board_hw_defs.c b/flight/targets/boards/revoproto/board_hw_defs.c index bda92eb18c..fb47680fe8 100644 --- a/flight/targets/boards/revoproto/board_hw_defs.c +++ b/flight/targets/boards/revoproto/board_hw_defs.c @@ -195,7 +195,7 @@ static const struct pios_spi_cfg pios_spi_accel_cfg = { } }; -static uint32_t pios_spi_accel_id; +uint32_t pios_spi_accel_id; void PIOS_SPI_accel_irq_handler(void) { /* Call into the generic code to handle the IRQ for this specific device */ @@ -612,7 +612,6 @@ void PIOS_OVERO_irq_handler(void) #endif /* PIOS_OVERO_SPI */ - #include #ifdef PIOS_INCLUDE_COM_TELEM @@ -622,24 +621,7 @@ void PIOS_OVERO_irq_handler(void) static const struct pios_usart_cfg pios_usart_telem_cfg = { .regs = USART2, .remap = GPIO_AF_USART2, - .init = { - .USART_BaudRate = 57600, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = - USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx | USART_Mode_Tx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART2_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { + .rx = { .gpio = GPIOD, .init = { .GPIO_Pin = GPIO_Pin_6, @@ -649,7 +631,7 @@ static const struct pios_usart_cfg pios_usart_telem_cfg = { .GPIO_PuPd = GPIO_PuPd_UP }, }, - .tx = { + .tx = { .gpio = GPIOD, .init = { .GPIO_Pin = GPIO_Pin_5, @@ -670,24 +652,7 @@ static const struct pios_usart_cfg pios_usart_telem_cfg = { static const struct pios_usart_cfg pios_usart_gps_cfg = { .regs = USART1, .remap = GPIO_AF_USART1, - .init = { - .USART_BaudRate = 57600, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = - USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx | USART_Mode_Tx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART1_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { + .rx = { .gpio = GPIOA, .init = { .GPIO_Pin = GPIO_Pin_10, @@ -697,7 +662,7 @@ static const struct pios_usart_cfg pios_usart_gps_cfg = { .GPIO_PuPd = GPIO_PuPd_UP }, }, - .tx = { + .tx = { .gpio = GPIOA, .init = { .GPIO_Pin = GPIO_Pin_9, @@ -718,24 +683,7 @@ static const struct pios_usart_cfg pios_usart_gps_cfg = { static const struct pios_usart_cfg pios_usart_aux_cfg = { .regs = USART6, .remap = GPIO_AF_USART6, - .init = { - .USART_BaudRate = 57600, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = - USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx | USART_Mode_Tx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART6_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { + .rx = { .gpio = GPIOC, .init = { .GPIO_Pin = GPIO_Pin_7, @@ -745,7 +693,7 @@ static const struct pios_usart_cfg pios_usart_aux_cfg = { .GPIO_PuPd = GPIO_PuPd_UP }, }, - .tx = { + .tx = { .gpio = GPIOC, .init = { .GPIO_Pin = GPIO_Pin_6, @@ -763,27 +711,19 @@ static const struct pios_usart_cfg pios_usart_aux_cfg = { /* * AUX USART SBUS ( UART/ S Bus label on rev2) */ + +// Inverter for SBUS handling +#define MAIN_USART_INVERTER_GPIO GPIOC +#define MAIN_USART_INVERTER_PIN GPIO_Pin_3 +#define MAIN_USART_INVERTER_ENABLE Bit_SET +#define MAIN_USART_INVERTER_DISABLE Bit_RESET + +static int32_t PIOS_BOARD_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param); + static const struct pios_usart_cfg pios_usart_auxsbus_cfg = { .regs = UART4, .remap = GPIO_AF_UART4, - .init = { - .USART_BaudRate = 57600, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = - USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx | USART_Mode_Tx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = UART4_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { + .rx = { .gpio = GPIOA, .init = { .GPIO_Pin = GPIO_Pin_1, @@ -793,7 +733,7 @@ static const struct pios_usart_cfg pios_usart_auxsbus_cfg = { .GPIO_PuPd = GPIO_PuPd_UP }, }, - .tx = { + .tx = { .gpio = GPIOA, .init = { .GPIO_Pin = GPIO_Pin_0, @@ -803,6 +743,7 @@ static const struct pios_usart_cfg pios_usart_auxsbus_cfg = { .GPIO_PuPd = GPIO_PuPd_UP }, }, + .ioctl = PIOS_BOARD_USART_Ioctl, }; #endif /* PIOS_INCLUDE_COM_AUXSBUS */ @@ -814,24 +755,7 @@ static const struct pios_usart_cfg pios_usart_auxsbus_cfg = { static const struct pios_usart_cfg pios_usart_flexi_cfg = { .regs = USART3, .remap = GPIO_AF_USART3, - .init = { - .USART_BaudRate = 57600, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = - USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx | USART_Mode_Tx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART3_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { + .rx = { .gpio = GPIOB, .init = { .GPIO_Pin = GPIO_Pin_10, @@ -841,7 +765,7 @@ static const struct pios_usart_cfg pios_usart_flexi_cfg = { .GPIO_PuPd = GPIO_PuPd_UP }, }, - .tx = { + .tx = { .gpio = GPIOB, .init = { .GPIO_Pin = GPIO_Pin_11, @@ -855,327 +779,6 @@ static const struct pios_usart_cfg pios_usart_flexi_cfg = { #endif /* PIOS_INCLUDE_COM_FLEXI */ -#if defined(PIOS_INCLUDE_DSM) -/* - * Spektrum/JR DSM USART - */ -#include - -static const struct pios_usart_cfg pios_usart_dsm_aux_cfg = { - .regs = USART6, - .remap = GPIO_AF_USART6, - .init = { - .USART_BaudRate = 115200, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART6_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { - .gpio = GPIOC, - .init = { - .GPIO_Pin = GPIO_Pin_7, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, - .tx = { - .gpio = GPIOC, - .init = { - .GPIO_Pin = GPIO_Pin_6, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, -}; - -static const struct pios_dsm_cfg pios_dsm_aux_cfg = { - .bind = { - .gpio = GPIOC, - .init = { - .GPIO_Pin = GPIO_Pin_7, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_OUT, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_NOPULL - }, - }, -}; - -static const struct pios_usart_cfg pios_usart_dsm_auxsbus_cfg = { - .regs = UART4, - .remap = GPIO_AF_UART4, - .init = { - .USART_BaudRate = 115200, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = UART4_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { - .gpio = GPIOA, - .init = { - .GPIO_Pin = GPIO_Pin_1, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, - .tx = { - .gpio = GPIOA, - .init = { - .GPIO_Pin = GPIO_Pin_0, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, -}; - -static const struct pios_dsm_cfg pios_dsm_auxsbus_cfg = { - .bind = { - .gpio = GPIOA, - .init = { - .GPIO_Pin = GPIO_Pin_1, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_OUT, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_NOPULL - }, - }, -}; - -static const struct pios_usart_cfg pios_usart_dsm_flexi_cfg = { - .regs = USART3, - .remap = GPIO_AF_USART3, - .init = { - .USART_BaudRate = 115200, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART3_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_11, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, - .tx = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_10, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, -}; - -static const struct pios_dsm_cfg pios_dsm_flexi_cfg = { - .bind = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_11, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_OUT, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_NOPULL - }, - }, -}; - -#endif /* PIOS_INCLUDE_DSM */ - -#if defined(PIOS_INCLUDE_SBUS) -/* - * S.Bus USART - */ -#include - -static const struct pios_usart_cfg pios_usart_sbus_auxsbus_cfg = { - .regs = UART4, - .remap = GPIO_AF_UART4, - .init = { - .USART_BaudRate = 100000, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_Even, - .USART_StopBits = USART_StopBits_2, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = UART4_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { - .gpio = GPIOA, - .init = { - .GPIO_Pin = GPIO_Pin_1, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, - .tx = { - .gpio = GPIOA, - .init = { - .GPIO_Pin = GPIO_Pin_0, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_OUT, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_NOPULL - }, - }, -}; - -static const struct pios_sbus_cfg pios_sbus_cfg = { - /* Inverter configuration */ - .inv = { - .gpio = GPIOC, - .init = { - .GPIO_Pin = GPIO_Pin_3, - .GPIO_Mode = GPIO_Mode_OUT, - .GPIO_OType = GPIO_OType_PP, - .GPIO_Speed = GPIO_Speed_2MHz, - }, - }, - .gpio_inv_enable = Bit_SET, - .gpio_inv_disable = Bit_RESET, - .gpio_clk_func = RCC_AHB1PeriphClockCmd, - .gpio_clk_periph = RCC_AHB1Periph_GPIOC, -}; - -#endif /* PIOS_INCLUDE_SBUS */ - -/* - * HK OSD - */ -static const struct pios_usart_cfg pios_usart_hkosd_auxsbus_cfg = { - .regs = UART4, - .remap = GPIO_AF_UART4, - .init = { - .USART_BaudRate = 57600, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx | USART_Mode_Tx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = UART4_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { - .gpio = GPIOA, - .init = { - .GPIO_Pin = GPIO_Pin_1, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, - .tx = { - .gpio = GPIOA, - .init = { - .GPIO_Pin = GPIO_Pin_0, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, -}; - -static const struct pios_usart_cfg pios_usart_hkosd_aux_cfg = { - .regs = USART6, - .remap = GPIO_AF_USART6, - .init = { - .USART_BaudRate = 57600, - .USART_WordLength = USART_WordLength_8b, - .USART_Parity = USART_Parity_No, - .USART_StopBits = USART_StopBits_1, - .USART_HardwareFlowControl = USART_HardwareFlowControl_None, - .USART_Mode = USART_Mode_Rx | USART_Mode_Tx, - }, - .irq = { - .init = { - .NVIC_IRQChannel = USART6_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { - .gpio = GPIOC, - .init = { - .GPIO_Pin = GPIO_Pin_7, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, - .tx = { - .gpio = GPIOC, - .init = { - .GPIO_Pin = GPIO_Pin_6, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_AF, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }, - }, -}; - #if defined(PIOS_INCLUDE_COM) #include @@ -2031,47 +1634,297 @@ static const struct pios_usb_cfg pios_usb_main_cfg = { }, .vsense_active_low = false }; +const struct pios_usb_cfg *PIOS_BOARD_HW_DEFS_GetUsbCfg(__attribute__((unused)) uint32_t board_revision) +{ + return &pios_usb_main_cfg; +} +#endif /* PIOS_INCLUDE_USB */ -#include "pios_usb_board_data_priv.h" -#include "pios_usb_desc_hid_cdc_priv.h" -#include "pios_usb_desc_hid_only_priv.h" -#include "pios_usbhook.h" -#endif /* PIOS_INCLUDE_USB */ +/** + * Sensor configurations + */ + +#if defined(PIOS_INCLUDE_ADC) +#include "pios_adc_priv.h" +void PIOS_ADC_DMC_irq_handler(void); +void DMA2_Stream4_IRQHandler(void) __attribute__((alias("PIOS_ADC_DMC_irq_handler"))); +struct pios_adc_cfg pios_adc_cfg = { + .adc_dev = ADC1, + .dma = { + .irq = { + .flags = (DMA_FLAG_TCIF4 | DMA_FLAG_TEIF4 | DMA_FLAG_HTIF4), + .init = { + .NVIC_IRQChannel = DMA2_Stream4_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_LOW, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, + .rx = { + .channel = DMA2_Stream4, + .init = { + .DMA_Channel = DMA_Channel_0, + .DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR + }, + } + }, + .half_flag = DMA_IT_HTIF4, + .full_flag = DMA_IT_TCIF4, +}; +void PIOS_ADC_DMC_irq_handler(void) +{ + /* Call into the generic code to handle the IRQ for this specific device */ + PIOS_ADC_DMA_Handler(); +} +const struct pios_adc_cfg *PIOS_BOARD_HW_DEFS_GetAdcCfg(__attribute__((unused)) uint32_t board_revision) +{ + return &pios_adc_cfg; +} +#endif /* if defined(PIOS_INCLUDE_ADC) */ + +#if defined(PIOS_INCLUDE_HMC5X83) +#include "pios_hmc5x83.h" -#if defined(PIOS_INCLUDE_COM_MSG) +#ifdef PIOS_HMC5X83_HAS_GPIOS +bool pios_board_internal_mag_handler() +{ + return PIOS_HMC5x83_IRQHandler(pios_hmc5x83_internal_id); +} +static const struct pios_exti_cfg pios_exti_hmc5x83_cfg __exti_config = { + .vector = pios_board_internal_mag_handler, + .line = EXTI_Line5, + .pin = { + .gpio = GPIOB, + .init = { + .GPIO_Pin = GPIO_Pin_5, + .GPIO_Speed = GPIO_Speed_100MHz, + .GPIO_Mode = GPIO_Mode_IN, + .GPIO_OType = GPIO_OType_OD, + .GPIO_PuPd = GPIO_PuPd_NOPULL, + }, + }, + .irq = { + .init = { + .NVIC_IRQChannel = EXTI9_5_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_LOW, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, + .exti = { + .init = { + .EXTI_Line = EXTI_Line5, // matches above GPIO pin + .EXTI_Mode = EXTI_Mode_Interrupt, + .EXTI_Trigger = EXTI_Trigger_Rising, + .EXTI_LineCmd = ENABLE, + }, + }, +}; +#endif /* PIOS_HMC5X83_HAS_GPIOS */ + +static const struct pios_hmc5x83_cfg pios_hmc5x83_internal_cfg = { +#ifdef PIOS_HMC5X83_HAS_GPIOS + .exti_cfg = &pios_exti_hmc5x83_cfg, +#endif + .M_ODR = PIOS_HMC5x83_ODR_75, + .Meas_Conf = PIOS_HMC5x83_MEASCONF_NORMAL, + .Gain = PIOS_HMC5x83_GAIN_1_9, + .Mode = PIOS_HMC5x83_MODE_CONTINUOUS, + .TempCompensation = false, + .Driver = &PIOS_HMC5x83_I2C_DRIVER, + .Orientation = PIOS_HMC5X83_ORIENTATION_EAST_NORTH_UP, +}; -#include +const struct pios_hmc5x83_cfg *PIOS_BOARD_HW_DEFS_GetInternalHMC5x83Cfg(__attribute__((unused)) uint32_t board_revision) +{ + return &pios_hmc5x83_internal_cfg; +} -#endif /* PIOS_INCLUDE_COM_MSG */ +static const struct pios_hmc5x83_cfg pios_hmc5x83_external_cfg = { +#ifdef PIOS_HMC5X83_HAS_GPIOS + .exti_cfg = NULL, +#endif + .M_ODR = PIOS_HMC5x83_ODR_75, // if you change this for auxmag, change AUX_MAG_SKIP in sensors.c + .Meas_Conf = PIOS_HMC5x83_MEASCONF_NORMAL, + .Gain = PIOS_HMC5x83_GAIN_1_9, + .Mode = PIOS_HMC5x83_MODE_CONTINUOUS, + .TempCompensation = false, + .Driver = &PIOS_HMC5x83_I2C_DRIVER, + .Orientation = PIOS_HMC5X83_ORIENTATION_EAST_NORTH_UP, +}; -#if defined(PIOS_INCLUDE_USB_HID) && !defined(PIOS_INCLUDE_USB_CDC) -#include +const struct pios_hmc5x83_cfg *PIOS_BOARD_HW_DEFS_GetExternalHMC5x83Cfg(__attribute__((unused)) uint32_t board_revision) +{ + return &pios_hmc5x83_external_cfg; +} +#endif /* PIOS_INCLUDE_HMC5X83 */ -const struct pios_usb_hid_cfg pios_usb_hid_cfg = { - .data_if = 0, - .data_rx_ep = 1, - .data_tx_ep = 1, +/** + * Configuration for the MS5611 chip + */ +#if defined(PIOS_INCLUDE_MS5611) +#include "pios_ms5611.h" +static const struct pios_ms5611_cfg pios_ms5611_cfg = { + .oversampling = MS5611_OSR_4096, }; -#endif /* PIOS_INCLUDE_USB_HID && !PIOS_INCLUDE_USB_CDC */ +const struct pios_ms5611_cfg *PIOS_BOARD_HW_DEFS_GetMS5611Cfg(__attribute__((unused)) uint32_t board_revision) +{ + return &pios_ms5611_cfg; +} +#endif /* PIOS_INCLUDE_MS5611 */ -#if defined(PIOS_INCLUDE_USB_HID) && defined(PIOS_INCLUDE_USB_CDC) -#include +/** + * Configuration for the BMA180 chip + */ +#if defined(PIOS_INCLUDE_BMA180) +#include "pios_bma180.h" +static const struct pios_exti_cfg pios_exti_bma180_cfg __exti_config = { + .vector = PIOS_BMA180_IRQHandler, + .line = EXTI_Line4, + .pin = { + .gpio = GPIOC, + .init = { + .GPIO_Pin = GPIO_Pin_4, + .GPIO_Speed = GPIO_Speed_100MHz, + .GPIO_Mode = GPIO_Mode_IN, + .GPIO_OType = GPIO_OType_OD, + .GPIO_PuPd = GPIO_PuPd_NOPULL, + }, + }, + .irq = { + .init = { + .NVIC_IRQChannel = EXTI4_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_LOW, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, + .exti = { + .init = { + .EXTI_Line = EXTI_Line4, // matches above GPIO pin + .EXTI_Mode = EXTI_Mode_Interrupt, + .EXTI_Trigger = EXTI_Trigger_Rising, + .EXTI_LineCmd = ENABLE, + }, + }, +}; +static const struct pios_bma180_cfg pios_bma180_cfg = { + .exti_cfg = &pios_exti_bma180_cfg, + .bandwidth = BMA_BW_600HZ, + .range = BMA_RANGE_8G, +}; +const struct pios_bma180_cfg *PIOS_BOARD_HW_DEFS_GetBMA180Cfg(uint32_t board_revision) +{ + return (board_revision == 0x01) ? &pios_bma180_cfg : 0; +} +#endif /* PIOS_INCLUDE_BMA180 */ -const struct pios_usb_cdc_cfg pios_usb_cdc_cfg = { - .ctrl_if = 1, - .ctrl_tx_ep = 2, +/** + * Configuration for the MPU6000 chip + */ +#if defined(PIOS_INCLUDE_MPU6000) +#include "pios_mpu6000.h" +static const struct pios_exti_cfg pios_exti_mpu6000_cfg __exti_config = { + .vector = PIOS_MPU6000_IRQHandler, + .line = EXTI_Line8, + .pin = { + .gpio = GPIOD, + .init = { + .GPIO_Pin = GPIO_Pin_8, + .GPIO_Speed = GPIO_Speed_100MHz, + .GPIO_Mode = GPIO_Mode_IN, + .GPIO_OType = GPIO_OType_OD, + .GPIO_PuPd = GPIO_PuPd_NOPULL, + }, + }, + .irq = { + .init = { + .NVIC_IRQChannel = EXTI9_5_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, + .exti = { + .init = { + .EXTI_Line = EXTI_Line8, // matches above GPIO pin + .EXTI_Mode = EXTI_Mode_Interrupt, + .EXTI_Trigger = EXTI_Trigger_Rising, + .EXTI_LineCmd = ENABLE, + }, + }, +}; - .data_if = 2, - .data_rx_ep = 3, - .data_tx_ep = 3, +static const struct pios_mpu6000_cfg pios_mpu6000_cfg = { + .exti_cfg = &pios_exti_mpu6000_cfg, + .Fifo_store = PIOS_MPU6000_FIFO_TEMP_OUT | PIOS_MPU6000_FIFO_GYRO_X_OUT | PIOS_MPU6000_FIFO_GYRO_Y_OUT | PIOS_MPU6000_FIFO_GYRO_Z_OUT, + // Clock at 8 khz + .Smpl_rate_div_no_dlp = 0, + // with dlp on output rate is 1000Hz + .Smpl_rate_div_dlp = 0, + .interrupt_cfg = PIOS_MPU6000_INT_CLR_ANYRD, + .interrupt_en = PIOS_MPU6000_INTEN_DATA_RDY, + .User_ctl = PIOS_MPU6000_USERCTL_DIS_I2C, + .Pwr_mgmt_clk = PIOS_MPU6000_PWRMGMT_PLL_X_CLK, + .accel_range = PIOS_MPU6000_ACCEL_8G, + .gyro_range = PIOS_MPU6000_SCALE_2000_DEG, + .filter = PIOS_MPU6000_LOWPASS_256_HZ, + .orientation = PIOS_MPU6000_TOP_0DEG, + .fast_prescaler = PIOS_SPI_PRESCALER_4, + .std_prescaler = PIOS_SPI_PRESCALER_64, + .max_downsample = 16, }; -#include +const struct pios_mpu6000_cfg *PIOS_BOARD_HW_DEFS_GetMPU6000Cfg(uint32_t board_revision) +{ + return (board_revision == 0x02) ? &pios_mpu6000_cfg : 0; +} +#endif /* PIOS_INCLUDE_MPU6000 */ + +/** + * Configuration for L3GD20 chip + */ +#if defined(PIOS_INCLUDE_L3GD20) +#include "pios_l3gd20.h" +static const struct pios_exti_cfg pios_exti_l3gd20_cfg __exti_config = { + .vector = PIOS_L3GD20_IRQHandler, + .line = EXTI_Line8, + .pin = { + .gpio = GPIOD, + .init = { + .GPIO_Pin = GPIO_Pin_8, + .GPIO_Speed = GPIO_Speed_100MHz, + .GPIO_Mode = GPIO_Mode_IN, + .GPIO_OType = GPIO_OType_OD, + .GPIO_PuPd = GPIO_PuPd_NOPULL, + }, + }, + .irq = { + .init = { + .NVIC_IRQChannel = EXTI9_5_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, + .exti = { + .init = { + .EXTI_Line = EXTI_Line8, // matches above GPIO pin + .EXTI_Mode = EXTI_Mode_Interrupt, + .EXTI_Trigger = EXTI_Trigger_Rising, + .EXTI_LineCmd = ENABLE, + }, + }, +}; -const struct pios_usb_hid_cfg pios_usb_hid_cfg = { - .data_if = 2, - .data_rx_ep = 1, - .data_tx_ep = 1, +static const struct pios_l3gd20_cfg pios_l3gd20_cfg = { + .exti_cfg = &pios_exti_l3gd20_cfg, + .range = PIOS_L3GD20_SCALE_500_DEG, }; -#endif /* PIOS_INCLUDE_USB_HID && PIOS_INCLUDE_USB_CDC */ + +const struct pios_l3gd20_cfg *PIOS_BOARD_HW_DEFS_GetL3GD20Cfg(uint32_t board_revision) +{ + return (board_revision == 0x01) ? &pios_l3gd20_cfg : 0; +} +#endif /* PIOS_INCLUDE_L3GD20 */ diff --git a/flight/targets/boards/revoproto/bootloader/main.c b/flight/targets/boards/revoproto/bootloader/main.c index 09a54a0947..aa5c7999a5 100644 --- a/flight/targets/boards/revoproto/bootloader/main.c +++ b/flight/targets/boards/revoproto/bootloader/main.c @@ -35,6 +35,7 @@ #include /* PIOS_USBHOOK_* */ #include #include +#include extern void FLASH_Download(); void check_bor(); diff --git a/flight/targets/boards/revoproto/bootloader/pios_board.c b/flight/targets/boards/revoproto/bootloader/pios_board.c index 7e9858f18a..72fda9e5d7 100644 --- a/flight/targets/boards/revoproto/bootloader/pios_board.c +++ b/flight/targets/boards/revoproto/bootloader/pios_board.c @@ -26,6 +26,13 @@ #include #include +#include "pios_usb_board_data_priv.h" +#include "pios_usb_desc_hid_cdc_priv.h" +#include "pios_usb_desc_hid_only_priv.h" +#include "pios_usbhook.h" + +#include + /* * Pull in the board-specific static HW definitions. * Including .c files is a bit ugly but this allows all of @@ -64,7 +71,7 @@ void PIOS_Board_Init() #if defined(PIOS_INCLUDE_USB_HID) && defined(PIOS_INCLUDE_COM_MSG) uint32_t pios_usb_hid_id; - if (PIOS_USB_HID_Init(&pios_usb_hid_id, &pios_usb_hid_cfg, pios_usb_id)) { + if (PIOS_USB_HID_Init(&pios_usb_hid_id, &pios_usb_hid_only_cfg, pios_usb_id)) { PIOS_Assert(0); } if (PIOS_COM_MSG_Init(&pios_com_telem_usb_id, &pios_usb_hid_com_driver, pios_usb_hid_id)) { diff --git a/flight/targets/boards/revoproto/firmware/pios_board.c b/flight/targets/boards/revoproto/firmware/pios_board.c index 025acce6eb..167f19bd00 100644 --- a/flight/targets/boards/revoproto/firmware/pios_board.c +++ b/flight/targets/boards/revoproto/firmware/pios_board.c @@ -31,7 +31,9 @@ #include #include #include -#include + +#include +#include /* * Pull in the board-specific static HW definitions. @@ -43,377 +45,38 @@ */ #include "../board_hw_defs.c" -/** - * Sensor configurations - */ - -#if defined(PIOS_INCLUDE_ADC) -#include "pios_adc_priv.h" -void PIOS_ADC_DMC_irq_handler(void); -void DMA2_Stream4_IRQHandler(void) __attribute__((alias("PIOS_ADC_DMC_irq_handler"))); -struct pios_adc_cfg pios_adc_cfg = { - .adc_dev = ADC1, - .dma = { - .irq = { - .flags = (DMA_FLAG_TCIF4 | DMA_FLAG_TEIF4 | DMA_FLAG_HTIF4), - .init = { - .NVIC_IRQChannel = DMA2_Stream4_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_LOW, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .rx = { - .channel = DMA2_Stream4, - .init = { - .DMA_Channel = DMA_Channel_0, - .DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR - }, - } - }, - .half_flag = DMA_IT_HTIF4, - .full_flag = DMA_IT_TCIF4, -}; -void PIOS_ADC_DMC_irq_handler(void) -{ - /* Call into the generic code to handle the IRQ for this specific device */ - PIOS_ADC_DMA_Handler(); -} - -#endif /* if defined(PIOS_INCLUDE_ADC) */ - -#if defined(PIOS_INCLUDE_HMC5X83) -#include "pios_hmc5x83.h" - -pios_hmc5x83_dev_t onboard_mag = 0; -pios_hmc5x83_dev_t external_mag = 0; - -#ifdef PIOS_HMC5X83_HAS_GPIOS -bool pios_board_internal_mag_handler() -{ - return PIOS_HMC5x83_IRQHandler(onboard_mag); -} -static const struct pios_exti_cfg pios_exti_hmc5x83_cfg __exti_config = { - .vector = pios_board_internal_mag_handler, - .line = EXTI_Line5, - .pin = { - .gpio = GPIOB, - .init = { - .GPIO_Pin = GPIO_Pin_5, - .GPIO_Speed = GPIO_Speed_100MHz, - .GPIO_Mode = GPIO_Mode_IN, - .GPIO_OType = GPIO_OType_OD, - .GPIO_PuPd = GPIO_PuPd_NOPULL, - }, - }, - .irq = { - .init = { - .NVIC_IRQChannel = EXTI9_5_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_LOW, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .exti = { - .init = { - .EXTI_Line = EXTI_Line5, // matches above GPIO pin - .EXTI_Mode = EXTI_Mode_Interrupt, - .EXTI_Trigger = EXTI_Trigger_Rising, - .EXTI_LineCmd = ENABLE, - }, - }, -}; -#endif /* PIOS_HMC5X83_HAS_GPIOS */ - -static const struct pios_hmc5x83_cfg pios_hmc5x83_internal_cfg = { -#ifdef PIOS_HMC5X83_HAS_GPIOS - .exti_cfg = &pios_exti_hmc5x83_cfg, -#endif - .M_ODR = PIOS_HMC5x83_ODR_75, - .Meas_Conf = PIOS_HMC5x83_MEASCONF_NORMAL, - .Gain = PIOS_HMC5x83_GAIN_1_9, - .Mode = PIOS_HMC5x83_MODE_CONTINUOUS, - .TempCompensation = false, - .Driver = &PIOS_HMC5x83_I2C_DRIVER, - .Orientation = PIOS_HMC5X83_ORIENTATION_EAST_NORTH_UP, -}; - -static const struct pios_hmc5x83_cfg pios_hmc5x83_external_cfg = { -#ifdef PIOS_HMC5X83_HAS_GPIOS - .exti_cfg = NULL, -#endif - .M_ODR = PIOS_HMC5x83_ODR_75, // if you change this for auxmag, change AUX_MAG_SKIP in sensors.c - .Meas_Conf = PIOS_HMC5x83_MEASCONF_NORMAL, - .Gain = PIOS_HMC5x83_GAIN_1_9, - .Mode = PIOS_HMC5x83_MODE_CONTINUOUS, - .TempCompensation = false, - .Driver = &PIOS_HMC5x83_I2C_DRIVER, - .Orientation = PIOS_HMC5X83_ORIENTATION_EAST_NORTH_UP, -}; -#endif /* PIOS_INCLUDE_HMC5X83 */ - -/** - * Configuration for the MS5611 chip - */ -#if defined(PIOS_INCLUDE_MS5611) -#include "pios_ms5611.h" -static const struct pios_ms5611_cfg pios_ms5611_cfg = { - .oversampling = MS5611_OSR_4096, -}; -#endif /* PIOS_INCLUDE_MS5611 */ - -/** - * Configuration for the BMA180 chip - */ -#if defined(PIOS_INCLUDE_BMA180) -#include "pios_bma180.h" -static const struct pios_exti_cfg pios_exti_bma180_cfg __exti_config = { - .vector = PIOS_BMA180_IRQHandler, - .line = EXTI_Line4, - .pin = { - .gpio = GPIOC, - .init = { - .GPIO_Pin = GPIO_Pin_4, - .GPIO_Speed = GPIO_Speed_100MHz, - .GPIO_Mode = GPIO_Mode_IN, - .GPIO_OType = GPIO_OType_OD, - .GPIO_PuPd = GPIO_PuPd_NOPULL, - }, - }, - .irq = { - .init = { - .NVIC_IRQChannel = EXTI4_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_LOW, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .exti = { - .init = { - .EXTI_Line = EXTI_Line4, // matches above GPIO pin - .EXTI_Mode = EXTI_Mode_Interrupt, - .EXTI_Trigger = EXTI_Trigger_Rising, - .EXTI_LineCmd = ENABLE, - }, - }, -}; -static const struct pios_bma180_cfg pios_bma180_cfg = { - .exti_cfg = &pios_exti_bma180_cfg, - .bandwidth = BMA_BW_600HZ, - .range = BMA_RANGE_8G, -}; -#endif /* PIOS_INCLUDE_BMA180 */ - -/** - * Configuration for the MPU6000 chip - */ -#if defined(PIOS_INCLUDE_MPU6000) -#include "pios_mpu6000.h" -#include "pios_mpu6000_config.h" -static const struct pios_exti_cfg pios_exti_mpu6000_cfg __exti_config = { - .vector = PIOS_MPU6000_IRQHandler, - .line = EXTI_Line8, - .pin = { - .gpio = GPIOD, - .init = { - .GPIO_Pin = GPIO_Pin_8, - .GPIO_Speed = GPIO_Speed_100MHz, - .GPIO_Mode = GPIO_Mode_IN, - .GPIO_OType = GPIO_OType_OD, - .GPIO_PuPd = GPIO_PuPd_NOPULL, - }, - }, - .irq = { - .init = { - .NVIC_IRQChannel = EXTI9_5_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .exti = { - .init = { - .EXTI_Line = EXTI_Line8, // matches above GPIO pin - .EXTI_Mode = EXTI_Mode_Interrupt, - .EXTI_Trigger = EXTI_Trigger_Rising, - .EXTI_LineCmd = ENABLE, - }, - }, -}; - -static const struct pios_mpu6000_cfg pios_mpu6000_cfg = { - .exti_cfg = &pios_exti_mpu6000_cfg, - .Fifo_store = PIOS_MPU6000_FIFO_TEMP_OUT | PIOS_MPU6000_FIFO_GYRO_X_OUT | PIOS_MPU6000_FIFO_GYRO_Y_OUT | PIOS_MPU6000_FIFO_GYRO_Z_OUT, - // Clock at 8 khz - .Smpl_rate_div_no_dlp = 0, - // with dlp on output rate is 1000Hz - .Smpl_rate_div_dlp = 0, - .interrupt_cfg = PIOS_MPU6000_INT_CLR_ANYRD, - .interrupt_en = PIOS_MPU6000_INTEN_DATA_RDY, - .User_ctl = PIOS_MPU6000_USERCTL_DIS_I2C, - .Pwr_mgmt_clk = PIOS_MPU6000_PWRMGMT_PLL_X_CLK, - .accel_range = PIOS_MPU6000_ACCEL_8G, - .gyro_range = PIOS_MPU6000_SCALE_2000_DEG, - .filter = PIOS_MPU6000_LOWPASS_256_HZ, - .orientation = PIOS_MPU6000_TOP_0DEG, - .fast_prescaler = PIOS_SPI_PRESCALER_4, - .std_prescaler = PIOS_SPI_PRESCALER_64, - .max_downsample = 16, -}; -#endif /* PIOS_INCLUDE_MPU6000 */ - -/** - * Configuration for L3GD20 chip - */ -#if defined(PIOS_INCLUDE_L3GD20) -#include "pios_l3gd20.h" -static const struct pios_exti_cfg pios_exti_l3gd20_cfg __exti_config = { - .vector = PIOS_L3GD20_IRQHandler, - .line = EXTI_Line8, - .pin = { - .gpio = GPIOD, - .init = { - .GPIO_Pin = GPIO_Pin_8, - .GPIO_Speed = GPIO_Speed_100MHz, - .GPIO_Mode = GPIO_Mode_IN, - .GPIO_OType = GPIO_OType_OD, - .GPIO_PuPd = GPIO_PuPd_NOPULL, - }, - }, - .irq = { - .init = { - .NVIC_IRQChannel = EXTI9_5_IRQn, - .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, - .NVIC_IRQChannelSubPriority = 0, - .NVIC_IRQChannelCmd = ENABLE, - }, - }, - .exti = { - .init = { - .EXTI_Line = EXTI_Line8, // matches above GPIO pin - .EXTI_Mode = EXTI_Mode_Interrupt, - .EXTI_Trigger = EXTI_Trigger_Rising, - .EXTI_LineCmd = ENABLE, - }, - }, -}; - -static const struct pios_l3gd20_cfg pios_l3gd20_cfg = { - .exti_cfg = &pios_exti_l3gd20_cfg, - .range = PIOS_L3GD20_SCALE_500_DEG, -}; -#endif /* PIOS_INCLUDE_L3GD20 */ - -/* One slot per selectable receiver group. - * eg. PWM, PPM, GCS, SPEKTRUM1, SPEKTRUM2, SBUS - * NOTE: No slot in this map for NONE. - */ -uint32_t pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_NONE]; - -#define PIOS_COM_TELEM_RF_RX_BUF_LEN 512 -#define PIOS_COM_TELEM_RF_TX_BUF_LEN 512 - -#define PIOS_COM_GPS_RX_BUF_LEN 32 - -#define PIOS_COM_TELEM_USB_RX_BUF_LEN 65 -#define PIOS_COM_TELEM_USB_TX_BUF_LEN 65 - -#define PIOS_COM_BRIDGE_RX_BUF_LEN 65 -#define PIOS_COM_BRIDGE_TX_BUF_LEN 12 - -#define PIOS_COM_AUX_RX_BUF_LEN 512 -#define PIOS_COM_AUX_TX_BUF_LEN 512 - -#define PIOS_COM_HKOSD_RX_BUF_LEN 22 -#define PIOS_COM_HKOSD_TX_BUF_LEN 22 - -#define PIOS_COM_MSP_TX_BUF_LEN 128 -#define PIOS_COM_MSP_RX_BUF_LEN 64 - -#define PIOS_COM_MAVLINK_TX_BUF_LEN 128 - -uint32_t pios_com_aux_id = 0; -uint32_t pios_com_gps_id = 0; -uint32_t pios_com_telem_usb_id = 0; -uint32_t pios_com_telem_rf_id = 0; -uint32_t pios_com_bridge_id = 0; -uint32_t pios_com_overo_id = 0; -uint32_t pios_com_hkosd_id = 0; -uint32_t pios_com_msp_id = 0; -uint32_t pios_com_mavlink_id = 0; - uintptr_t pios_uavo_settings_fs_id; uintptr_t pios_user_fs_id; -uint32_t pios_com_vcp_id = 0; - -/* - * Setup a com port based on the passed cfg, driver and buffer sizes. tx size = 0 make the port rx only +/** + * PIOS_Board_Init() + * initializes all the core subsystems on this specific hardware + * called from System/openpilot.c */ -static void PIOS_Board_configure_com(const struct pios_usart_cfg *usart_port_cfg, uint16_t rx_buf_len, uint16_t tx_buf_len, - const struct pios_com_driver *com_driver, uint32_t *pios_com_id) -{ - uint32_t pios_usart_id; - if (PIOS_USART_Init(&pios_usart_id, usart_port_cfg)) { - PIOS_Assert(0); - } - - uint8_t *rx_buffer = (uint8_t *)pios_malloc(rx_buf_len); - PIOS_Assert(rx_buffer); - if (tx_buf_len > 0) { // this is the case for rx/tx ports - uint8_t *tx_buffer = (uint8_t *)pios_malloc(tx_buf_len); - PIOS_Assert(tx_buffer); - - if (PIOS_COM_Init(pios_com_id, com_driver, pios_usart_id, - rx_buffer, rx_buf_len, - tx_buffer, tx_buf_len)) { - PIOS_Assert(0); - } - } else { // rx only port - if (PIOS_COM_Init(pios_com_id, com_driver, pios_usart_id, - rx_buffer, rx_buf_len, - NULL, 0)) { - PIOS_Assert(0); - } - } -} +#include -static void PIOS_Board_configure_dsm(const struct pios_usart_cfg *pios_usart_dsm_cfg, const struct pios_dsm_cfg *pios_dsm_cfg, - const struct pios_com_driver *usart_com_driver, - ManualControlSettingsChannelGroupsOptions channelgroup, uint8_t *bind) +int32_t PIOS_BOARD_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param) { - uint32_t pios_usart_dsm_id; + const struct pios_usart_cfg *usart_cfg = PIOS_USART_GetConfig(usart_id); - if (PIOS_USART_Init(&pios_usart_dsm_id, pios_usart_dsm_cfg)) { - PIOS_Assert(0); - } + switch (ctl) { + case PIOS_IOCTL_USART_SET_INVERTED: + if (usart_cfg->regs == pios_usart_auxsbus_cfg.regs) { /* main port */ + GPIO_WriteBit(MAIN_USART_INVERTER_GPIO, + MAIN_USART_INVERTER_PIN, + (*(enum PIOS_USART_Inverted *)param & PIOS_USART_Inverted_Rx) ? MAIN_USART_INVERTER_ENABLE : MAIN_USART_INVERTER_DISABLE); - uint32_t pios_dsm_id; - if (PIOS_DSM_Init(&pios_dsm_id, pios_dsm_cfg, usart_com_driver, - pios_usart_dsm_id, *bind)) { - PIOS_Assert(0); + return 0; + } + break; } - uint32_t pios_dsm_rcvr_id; - if (PIOS_RCVR_Init(&pios_dsm_rcvr_id, &pios_dsm_rcvr_driver, pios_dsm_id)) { - PIOS_Assert(0); - } - pios_rcvr_group_map[channelgroup] = pios_dsm_rcvr_id; + return -1; } -/** - * PIOS_Board_Init() - * initializes all the core subsystems on this specific hardware - * called from System/openpilot.c - */ - -#include - void PIOS_Board_Init(void) { - const struct pios_board_info *bdinfo = &pios_board_info_blob; - /* Delay system */ PIOS_DELAY_Init(); @@ -516,293 +179,117 @@ void PIOS_Board_Init(void) // PIOS_IAP_Init(); + /* Configure USB */ #if defined(PIOS_INCLUDE_USB) - /* Initialize board specific USB data */ - PIOS_USB_BOARD_DATA_Init(); - - /* Flags to determine if various USB interfaces are advertised */ - bool usb_hid_present = false; - bool usb_cdc_present = false; - -#if defined(PIOS_INCLUDE_USB_CDC) - if (PIOS_USB_DESC_HID_CDC_Init()) { - PIOS_Assert(0); - } - usb_hid_present = true; - usb_cdc_present = true; -#else - if (PIOS_USB_DESC_HID_ONLY_Init()) { - PIOS_Assert(0); - } - usb_hid_present = true; + PIOS_BOARD_IO_Configure_USB(); #endif - uint32_t pios_usb_id; - PIOS_USB_Init(&pios_usb_id, &pios_usb_main_cfg); - -#if defined(PIOS_INCLUDE_USB_CDC) - - uint8_t hwsettings_usb_vcpport; - /* Configure the USB VCP port */ - HwSettingsUSB_VCPPortGet(&hwsettings_usb_vcpport); - - if (!usb_cdc_present) { - /* Force VCP port function to disabled if we haven't advertised VCP in our USB descriptor */ - hwsettings_usb_vcpport = HWSETTINGS_USB_VCPPORT_DISABLED; - } - - uint32_t pios_usb_cdc_id; - if (PIOS_USB_CDC_Init(&pios_usb_cdc_id, &pios_usb_cdc_cfg, pios_usb_id)) { - PIOS_Assert(0); - } - - uint32_t pios_usb_hid_id; - if (PIOS_USB_HID_Init(&pios_usb_hid_id, &pios_usb_hid_cfg, pios_usb_id)) { - PIOS_Assert(0); - } - - switch (hwsettings_usb_vcpport) { - case HWSETTINGS_USB_VCPPORT_DISABLED: - break; - case HWSETTINGS_USB_VCPPORT_USBTELEMETRY: -#if defined(PIOS_INCLUDE_COM) - { - uint8_t *rx_buffer = (uint8_t *)pios_malloc(PIOS_COM_TELEM_USB_RX_BUF_LEN); - uint8_t *tx_buffer = (uint8_t *)pios_malloc(PIOS_COM_TELEM_USB_TX_BUF_LEN); - PIOS_Assert(rx_buffer); - PIOS_Assert(tx_buffer); - if (PIOS_COM_Init(&pios_com_telem_usb_id, &pios_usb_cdc_com_driver, pios_usb_cdc_id, - rx_buffer, PIOS_COM_TELEM_USB_RX_BUF_LEN, - tx_buffer, PIOS_COM_TELEM_USB_TX_BUF_LEN)) { - PIOS_Assert(0); - } - } -#endif /* PIOS_INCLUDE_COM */ - break; - case HWSETTINGS_USB_VCPPORT_COMBRIDGE: -#if defined(PIOS_INCLUDE_COM) - { - uint8_t *rx_buffer = (uint8_t *)pios_malloc(PIOS_COM_BRIDGE_RX_BUF_LEN); - uint8_t *tx_buffer = (uint8_t *)pios_malloc(PIOS_COM_BRIDGE_TX_BUF_LEN); - PIOS_Assert(rx_buffer); - PIOS_Assert(tx_buffer); - if (PIOS_COM_Init(&pios_com_vcp_id, &pios_usb_cdc_com_driver, pios_usb_cdc_id, - rx_buffer, PIOS_COM_BRIDGE_RX_BUF_LEN, - tx_buffer, PIOS_COM_BRIDGE_TX_BUF_LEN)) { - PIOS_Assert(0); - } - } -#endif /* PIOS_INCLUDE_COM */ - break; - case HWSETTINGS_USB_VCPPORT_DEBUGCONSOLE: -#if defined(PIOS_INCLUDE_COM) -#if defined(PIOS_INCLUDE_DEBUG_CONSOLE) - { - uint8_t *tx_buffer = (uint8_t *)pios_malloc(PIOS_COM_DEBUGCONSOLE_TX_BUF_LEN); - PIOS_Assert(tx_buffer); - if (PIOS_COM_Init(&pios_com_debug_id, &pios_usb_cdc_com_driver, pios_usb_cdc_id, - NULL, 0, - tx_buffer, PIOS_COM_DEBUGCONSOLE_TX_BUF_LEN)) { - PIOS_Assert(0); - } - } -#endif /* PIOS_INCLUDE_DEBUG_CONSOLE */ -#endif /* PIOS_INCLUDE_COM */ - - break; - } -#endif /* PIOS_INCLUDE_USB_CDC */ - -#if defined(PIOS_INCLUDE_USB_HID) - /* Configure the usb HID port */ - uint8_t hwsettings_usb_hidport; - HwSettingsUSB_HIDPortGet(&hwsettings_usb_hidport); - - if (!usb_hid_present) { - /* Force HID port function to disabled if we haven't advertised HID in our USB descriptor */ - hwsettings_usb_hidport = HWSETTINGS_USB_HIDPORT_DISABLED; - } - - switch (hwsettings_usb_hidport) { - case HWSETTINGS_USB_HIDPORT_DISABLED: - break; - case HWSETTINGS_USB_HIDPORT_USBTELEMETRY: -#if defined(PIOS_INCLUDE_COM) - { - uint8_t *rx_buffer = (uint8_t *)pios_malloc(PIOS_COM_TELEM_USB_RX_BUF_LEN); - uint8_t *tx_buffer = (uint8_t *)pios_malloc(PIOS_COM_TELEM_USB_TX_BUF_LEN); - PIOS_Assert(rx_buffer); - PIOS_Assert(tx_buffer); - if (PIOS_COM_Init(&pios_com_telem_usb_id, &pios_usb_hid_com_driver, pios_usb_hid_id, - rx_buffer, PIOS_COM_TELEM_USB_RX_BUF_LEN, - tx_buffer, PIOS_COM_TELEM_USB_TX_BUF_LEN)) { - PIOS_Assert(0); - } - } -#endif /* PIOS_INCLUDE_COM */ - break; - } - -#endif /* PIOS_INCLUDE_USB_HID */ + /* Initialize inverter gpio and set it to off */ + { + GPIO_InitTypeDef inverterGPIOInit = { + .GPIO_Pin = MAIN_USART_INVERTER_PIN, + .GPIO_Speed = GPIO_Speed_2MHz, + .GPIO_Mode = GPIO_Mode_OUT, + .GPIO_OType = GPIO_OType_PP, + .GPIO_PuPd = GPIO_PuPd_UP + }; - if (usb_hid_present || usb_cdc_present) { - PIOS_USBHOOK_Activate(); + GPIO_Init(MAIN_USART_INVERTER_GPIO, &inverterGPIOInit); + GPIO_WriteBit(MAIN_USART_INVERTER_GPIO, + MAIN_USART_INVERTER_PIN, + MAIN_USART_INVERTER_DISABLE); } -#endif /* PIOS_INCLUDE_USB */ /* Configure IO ports */ - uint8_t hwsettings_DSMxBind; - HwSettingsDSMxBindGet(&hwsettings_DSMxBind); /* Configure Telemetry port */ + static const PIOS_BOARD_IO_UART_Function usart_telem_function_map[] = { + [HWSETTINGS_RV_TELEMETRYPORT_TELEMETRY] = PIOS_BOARD_IO_UART_TELEMETRY, +// [HWSETTINGS_RV_TELEMETRYPORT_COMAUX] = ?? &pios_com_aux_id // UNUSED + [HWSETTINGS_RV_TELEMETRYPORT_COMBRIDGE] = PIOS_BOARD_IO_UART_COMBRIDGE, + [HWSETTINGS_RV_TELEMETRYPORT_MSP] = PIOS_BOARD_IO_UART_MSP, + [HWSETTINGS_RV_TELEMETRYPORT_MAVLINK] = PIOS_BOARD_IO_UART_MAVLINK + }; + uint8_t hwsettings_rv_telemetryport; HwSettingsRV_TelemetryPortGet(&hwsettings_rv_telemetryport); - switch (hwsettings_rv_telemetryport) { - case HWSETTINGS_RV_TELEMETRYPORT_DISABLED: - break; - case HWSETTINGS_RV_TELEMETRYPORT_TELEMETRY: - PIOS_Board_configure_com(&pios_usart_telem_cfg, PIOS_COM_TELEM_RF_RX_BUF_LEN, PIOS_COM_TELEM_RF_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_telem_rf_id); - break; - case HWSETTINGS_RV_TELEMETRYPORT_COMAUX: - PIOS_Board_configure_com(&pios_usart_telem_cfg, PIOS_COM_AUX_RX_BUF_LEN, PIOS_COM_AUX_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_aux_id); - break; - case HWSETTINGS_RV_TELEMETRYPORT_COMBRIDGE: - PIOS_Board_configure_com(&pios_usart_telem_cfg, PIOS_COM_BRIDGE_RX_BUF_LEN, PIOS_COM_BRIDGE_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_bridge_id); - break; - case HWSETTINGS_RV_TELEMETRYPORT_MSP: - PIOS_Board_configure_com(&pios_usart_telem_cfg, PIOS_COM_MSP_RX_BUF_LEN, PIOS_COM_MSP_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_msp_id); - break; - case HWSETTINGS_RV_TELEMETRYPORT_MAVLINK: - PIOS_Board_configure_com(&pios_usart_telem_cfg, 0, PIOS_COM_MAVLINK_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_mavlink_id); - break; - } /* hwsettings_rv_telemetryport */ + if (hwsettings_rv_telemetryport < NELEMENTS(usart_telem_function_map)) { + PIOS_BOARD_IO_Configure_UART(&pios_usart_telem_cfg, usart_telem_function_map[hwsettings_rv_telemetryport]); + } + /* Configure GPS port */ + static const PIOS_BOARD_IO_UART_Function usart_gps_function_map[] = { + [HWSETTINGS_RV_GPSPORT_TELEMETRY] = PIOS_BOARD_IO_UART_TELEMETRY, + [HWSETTINGS_RV_GPSPORT_GPS] = PIOS_BOARD_IO_UART_GPS, +// [HWSETTINGS_RV_GPSPORT_COMAUX] = + [HWSETTINGS_RV_GPSPORT_COMBRIDGE] = PIOS_BOARD_IO_UART_COMBRIDGE, + [HWSETTINGS_RV_GPSPORT_MSP] = PIOS_BOARD_IO_UART_MSP, + [HWSETTINGS_RV_GPSPORT_MAVLINK] = PIOS_BOARD_IO_UART_MAVLINK, + }; + uint8_t hwsettings_rv_gpsport; HwSettingsRV_GPSPortGet(&hwsettings_rv_gpsport); - switch (hwsettings_rv_gpsport) { - case HWSETTINGS_RV_GPSPORT_DISABLED: - break; - case HWSETTINGS_RV_GPSPORT_TELEMETRY: - PIOS_Board_configure_com(&pios_usart_gps_cfg, PIOS_COM_TELEM_RF_RX_BUF_LEN, PIOS_COM_TELEM_RF_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_telem_rf_id); - break; - - case HWSETTINGS_RV_GPSPORT_GPS: - PIOS_Board_configure_com(&pios_usart_gps_cfg, PIOS_COM_GPS_RX_BUF_LEN, 0, &pios_usart_com_driver, &pios_com_gps_id); - break; - - case HWSETTINGS_RV_GPSPORT_COMAUX: - PIOS_Board_configure_com(&pios_usart_gps_cfg, PIOS_COM_AUX_RX_BUF_LEN, PIOS_COM_AUX_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_aux_id); - break; - - case HWSETTINGS_RV_GPSPORT_COMBRIDGE: - PIOS_Board_configure_com(&pios_usart_gps_cfg, PIOS_COM_BRIDGE_RX_BUF_LEN, PIOS_COM_BRIDGE_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_bridge_id); - break; - case HWSETTINGS_RV_GPSPORT_MSP: - PIOS_Board_configure_com(&pios_usart_gps_cfg, PIOS_COM_MSP_RX_BUF_LEN, PIOS_COM_MSP_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_msp_id); - break; - case HWSETTINGS_RV_GPSPORT_MAVLINK: - PIOS_Board_configure_com(&pios_usart_gps_cfg, 0, PIOS_COM_MAVLINK_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_mavlink_id); - break; - } /* hwsettings_rv_gpsport */ + if (hwsettings_rv_gpsport < NELEMENTS(usart_gps_function_map)) { + PIOS_BOARD_IO_Configure_UART(&pios_usart_gps_cfg, usart_gps_function_map[hwsettings_rv_gpsport]); + } /* Configure AUXPort */ + static const PIOS_BOARD_IO_UART_Function usart_aux_function_map[] = { + [HWSETTINGS_RV_AUXPORT_TELEMETRY] = PIOS_BOARD_IO_UART_TELEMETRY, + [HWSETTINGS_RV_AUXPORT_DSM] = PIOS_BOARD_IO_UART_DSM_MAIN, + // [HWSETTINGS_RV_AUXPORT_COMAUX] = + [HWSETTINGS_RV_AUXPORT_COMBRIDGE] = PIOS_BOARD_IO_UART_COMBRIDGE, + [HWSETTINGS_RV_AUXPORT_MSP] = PIOS_BOARD_IO_UART_MSP, + [HWSETTINGS_RV_AUXPORT_MAVLINK] = PIOS_BOARD_IO_UART_MAVLINK, + [HWSETTINGS_RV_AUXPORT_OSDHK] = PIOS_BOARD_IO_UART_OSDHK, + }; + uint8_t hwsettings_rv_auxport; HwSettingsRV_AuxPortGet(&hwsettings_rv_auxport); - switch (hwsettings_rv_auxport) { - case HWSETTINGS_RV_AUXPORT_DISABLED: - break; + if (hwsettings_rv_auxport < NELEMENTS(usart_aux_function_map)) { + PIOS_BOARD_IO_Configure_UART(&pios_usart_aux_cfg, usart_aux_function_map[hwsettings_rv_auxport]); + } - case HWSETTINGS_RV_AUXPORT_TELEMETRY: - PIOS_Board_configure_com(&pios_usart_aux_cfg, PIOS_COM_TELEM_RF_RX_BUF_LEN, PIOS_COM_TELEM_RF_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_telem_rf_id); - break; + /* Configure AUXSbusPort */ + static const PIOS_BOARD_IO_UART_Function usart_auxsbus_function_map[] = { + [HWSETTINGS_RV_AUXSBUSPORT_SBUS] = PIOS_BOARD_IO_UART_SBUS, + [HWSETTINGS_RV_AUXSBUSPORT_DSM] = PIOS_BOARD_IO_UART_DSM_MAIN, /* MAIN group, same as usart_aux! */ + // [HWSETTINGS_RV_AUXSBUSPORT_COMAUX] = + [HWSETTINGS_RV_AUXSBUSPORT_COMBRIDGE] = PIOS_BOARD_IO_UART_COMBRIDGE, + [HWSETTINGS_RV_AUXSBUSPORT_MSP] = PIOS_BOARD_IO_UART_MSP, + [HWSETTINGS_RV_AUXSBUSPORT_MAVLINK] = PIOS_BOARD_IO_UART_MAVLINK, + [HWSETTINGS_RV_AUXSBUSPORT_OSDHK] = PIOS_BOARD_IO_UART_OSDHK, + }; - case HWSETTINGS_RV_AUXPORT_DSM: - // TODO: Define the various Channelgroup for Revo dsm inputs and handle here - PIOS_Board_configure_dsm(&pios_usart_dsm_aux_cfg, &pios_dsm_aux_cfg, - &pios_usart_com_driver, MANUALCONTROLSETTINGS_CHANNELGROUPS_DSMMAINPORT, &hwsettings_DSMxBind); - break; - case HWSETTINGS_RV_AUXPORT_COMAUX: - PIOS_Board_configure_com(&pios_usart_aux_cfg, PIOS_COM_AUX_RX_BUF_LEN, PIOS_COM_AUX_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_aux_id); - break; - case HWSETTINGS_RV_AUXPORT_COMBRIDGE: - PIOS_Board_configure_com(&pios_usart_aux_cfg, PIOS_COM_BRIDGE_RX_BUF_LEN, PIOS_COM_BRIDGE_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_bridge_id); - break; - case HWSETTINGS_RV_AUXPORT_MSP: - PIOS_Board_configure_com(&pios_usart_aux_cfg, PIOS_COM_MSP_RX_BUF_LEN, PIOS_COM_MSP_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_msp_id); - break; - case HWSETTINGS_RV_AUXPORT_MAVLINK: - PIOS_Board_configure_com(&pios_usart_aux_cfg, 0, PIOS_COM_MAVLINK_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_mavlink_id); - break; - case HWSETTINGS_RV_AUXPORT_OSDHK: - PIOS_Board_configure_com(&pios_usart_hkosd_aux_cfg, PIOS_COM_HKOSD_RX_BUF_LEN, PIOS_COM_HKOSD_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_hkosd_id); - break; - } /* hwsettings_rv_auxport */ - /* Configure AUXSbusPort */ - // TODO: ensure that the serial invertion pin is setted correctly uint8_t hwsettings_rv_auxsbusport; HwSettingsRV_AuxSBusPortGet(&hwsettings_rv_auxsbusport); - switch (hwsettings_rv_auxsbusport) { - case HWSETTINGS_RV_AUXSBUSPORT_DISABLED: - break; - case HWSETTINGS_RV_AUXSBUSPORT_SBUS: -#ifdef PIOS_INCLUDE_SBUS - { - uint32_t pios_usart_sbus_id; - if (PIOS_USART_Init(&pios_usart_sbus_id, &pios_usart_sbus_auxsbus_cfg)) { - PIOS_Assert(0); - } - - uint32_t pios_sbus_id; - if (PIOS_SBus_Init(&pios_sbus_id, &pios_sbus_cfg, &pios_usart_com_driver, pios_usart_sbus_id)) { - PIOS_Assert(0); - } - - uint32_t pios_sbus_rcvr_id; - if (PIOS_RCVR_Init(&pios_sbus_rcvr_id, &pios_sbus_rcvr_driver, pios_sbus_id)) { - PIOS_Assert(0); - } - pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_SBUS] = pios_sbus_rcvr_id; - } -#endif /* PIOS_INCLUDE_SBUS */ - break; - - case HWSETTINGS_RV_AUXSBUSPORT_DSM: - // TODO: Define the various Channelgroup for Revo dsm inputs and handle here - PIOS_Board_configure_dsm(&pios_usart_dsm_auxsbus_cfg, &pios_dsm_auxsbus_cfg, - &pios_usart_com_driver, MANUALCONTROLSETTINGS_CHANNELGROUPS_DSMMAINPORT, &hwsettings_DSMxBind); - break; - case HWSETTINGS_RV_AUXSBUSPORT_COMAUX: - PIOS_Board_configure_com(&pios_usart_auxsbus_cfg, PIOS_COM_AUX_RX_BUF_LEN, PIOS_COM_AUX_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_aux_id); - break; - case HWSETTINGS_RV_AUXSBUSPORT_COMBRIDGE: - PIOS_Board_configure_com(&pios_usart_auxsbus_cfg, PIOS_COM_BRIDGE_RX_BUF_LEN, PIOS_COM_BRIDGE_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_bridge_id); - break; - case HWSETTINGS_RV_AUXSBUSPORT_MSP: - PIOS_Board_configure_com(&pios_usart_auxsbus_cfg, PIOS_COM_MSP_RX_BUF_LEN, PIOS_COM_MSP_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_msp_id); - break; - case HWSETTINGS_RV_AUXSBUSPORT_MAVLINK: - PIOS_Board_configure_com(&pios_usart_auxsbus_cfg, 0, PIOS_COM_MAVLINK_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_mavlink_id); - break; - case HWSETTINGS_RV_AUXSBUSPORT_OSDHK: - PIOS_Board_configure_com(&pios_usart_hkosd_auxsbus_cfg, PIOS_COM_HKOSD_RX_BUF_LEN, PIOS_COM_HKOSD_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_hkosd_id); - break; - } /* hwsettings_rv_auxport */ + if (hwsettings_rv_auxsbusport < NELEMENTS(usart_auxsbus_function_map)) { + PIOS_BOARD_IO_Configure_UART(&pios_usart_auxsbus_cfg, usart_auxsbus_function_map[hwsettings_rv_auxsbusport]); + } /* Configure FlexiPort */ + static const PIOS_BOARD_IO_UART_Function usart_flexi_function_map[] = { + [HWSETTINGS_RV_FLEXIPORT_DSM] = PIOS_BOARD_IO_UART_DSM_FLEXI, + // [HWSETTINGS_RV_FLEXIPORT_COMAUX] = + [HWSETTINGS_RV_FLEXIPORT_COMBRIDGE] = PIOS_BOARD_IO_UART_COMBRIDGE, + [HWSETTINGS_RV_FLEXIPORT_MSP] = PIOS_BOARD_IO_UART_MSP, + [HWSETTINGS_RV_FLEXIPORT_MAVLINK] = PIOS_BOARD_IO_UART_MAVLINK, + }; uint8_t hwsettings_rv_flexiport; HwSettingsRV_FlexiPortGet(&hwsettings_rv_flexiport); - switch (hwsettings_rv_flexiport) { - case HWSETTINGS_RV_FLEXIPORT_DISABLED: - break; - case HWSETTINGS_RV_FLEXIPORT_I2C: + if (hwsettings_rv_flexiport < NELEMENTS(usart_flexi_function_map)) { + PIOS_BOARD_IO_Configure_UART(&pios_usart_flexi_cfg, usart_flexi_function_map[hwsettings_rv_flexiport]); + } + #if defined(PIOS_INCLUDE_I2C) + if (hwsettings_rv_flexiport == HWSETTINGS_RV_FLEXIPORT_I2C) { if (PIOS_I2C_Init(&pios_i2c_flexiport_adapter_id, &pios_i2c_flexiport_adapter_cfg)) { PIOS_Assert(0); } @@ -814,47 +301,8 @@ void PIOS_Board_Init(void) // to avoid making something else fail when HMC5X83 is removed PIOS_WDG_Clear(); #endif /* PIOS_INCLUDE_WDG */ -#if defined(PIOS_INCLUDE_HMC5X83) - // get auxmag type - AuxMagSettingsTypeOptions option; - AuxMagSettingsInitialize(); - AuxMagSettingsTypeGet(&option); - // if the aux mag type is FlexiPort then set it up - if (option == AUXMAGSETTINGS_TYPE_FLEXI) { - // attach the 5x83 mag to the previously inited I2C2 - external_mag = PIOS_HMC5x83_Init(&pios_hmc5x83_external_cfg, pios_i2c_flexiport_adapter_id, 0); -#ifdef PIOS_INCLUDE_WDG - // give HMC5x83 on I2C some extra time to allow for reset, etc. if needed - // this is not in a loop, so it is safe - PIOS_WDG_Clear(); -#endif /* PIOS_INCLUDE_WDG */ - // add this sensor to the sensor task's list - PIOS_HMC5x83_Register(external_mag, PIOS_SENSORS_TYPE_3AXIS_AUXMAG); - // mag alarm is cleared later, so use I2C - AlarmsSet(SYSTEMALARMS_ALARM_I2C, (external_mag) ? SYSTEMALARMS_ALARM_OK : SYSTEMALARMS_ALARM_WARNING); - } -#endif /* PIOS_INCLUDE_HMC5X83 */ + } #endif /* PIOS_INCLUDE_I2C */ - break; - case HWSETTINGS_RV_FLEXIPORT_DSM: - // TODO: Define the various Channelgroup for Revo dsm inputs and handle here - PIOS_Board_configure_dsm(&pios_usart_dsm_flexi_cfg, &pios_dsm_flexi_cfg, - &pios_usart_com_driver, MANUALCONTROLSETTINGS_CHANNELGROUPS_DSMMAINPORT, &hwsettings_DSMxBind); - break; - case HWSETTINGS_RV_FLEXIPORT_COMAUX: - PIOS_Board_configure_com(&pios_usart_flexi_cfg, PIOS_COM_AUX_RX_BUF_LEN, PIOS_COM_AUX_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_aux_id); - break; - case HWSETTINGS_RV_FLEXIPORT_COMBRIDGE: - PIOS_Board_configure_com(&pios_usart_flexi_cfg, PIOS_COM_BRIDGE_RX_BUF_LEN, PIOS_COM_BRIDGE_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_bridge_id); - break; - case HWSETTINGS_RV_FLEXIPORT_MSP: - PIOS_Board_configure_com(&pios_usart_flexi_cfg, PIOS_COM_MSP_RX_BUF_LEN, PIOS_COM_MSP_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_msp_id); - break; - case HWSETTINGS_RV_FLEXIPORT_MAVLINK: - PIOS_Board_configure_com(&pios_usart_flexi_cfg, 0, PIOS_COM_MAVLINK_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_mavlink_id); - break; - } /* hwsettings_rv_flexiport */ - /* Configure the receiver port*/ uint8_t hwsettings_rcvrport; @@ -865,32 +313,13 @@ void PIOS_Board_Init(void) break; case HWSETTINGS_RV_RCVRPORT_PWM: #if defined(PIOS_INCLUDE_PWM) - { - /* Set up the receiver port. Later this should be optional */ - uint32_t pios_pwm_id; - PIOS_PWM_Init(&pios_pwm_id, &pios_pwm_cfg); - - uint32_t pios_pwm_rcvr_id; - if (PIOS_RCVR_Init(&pios_pwm_rcvr_id, &pios_pwm_rcvr_driver, pios_pwm_id)) { - PIOS_Assert(0); - } - pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_PWM] = pios_pwm_rcvr_id; - } + PIOS_BOARD_IO_Configure_PWM(&pios_pwm_cfg); #endif /* PIOS_INCLUDE_PWM */ break; case HWSETTINGS_RV_RCVRPORT_PPM: case HWSETTINGS_RV_RCVRPORT_PPMOUTPUTS: #if defined(PIOS_INCLUDE_PPM) - { - uint32_t pios_ppm_id; - PIOS_PPM_Init(&pios_ppm_id, &pios_ppm_cfg); - - uint32_t pios_ppm_rcvr_id; - if (PIOS_RCVR_Init(&pios_ppm_rcvr_id, &pios_ppm_rcvr_driver, pios_ppm_id)) { - PIOS_Assert(0); - } - pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_PPM] = pios_ppm_rcvr_id; - } + PIOS_BOARD_IO_Configure_PPM(&pios_ppm_cfg); #endif /* PIOS_INCLUDE_PPM */ case HWSETTINGS_RV_RCVRPORT_OUTPUTS: @@ -929,17 +358,9 @@ void PIOS_Board_Init(void) } #endif - -#if defined(PIOS_INCLUDE_GCSRCVR) - GCSReceiverInitialize(); - uint32_t pios_gcsrcvr_id; - PIOS_GCSRCVR_Init(&pios_gcsrcvr_id); - uint32_t pios_gcsrcvr_rcvr_id; - if (PIOS_RCVR_Init(&pios_gcsrcvr_rcvr_id, &pios_gcsrcvr_rcvr_driver, pios_gcsrcvr_id)) { - PIOS_Assert(0); - } - pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_GCS] = pios_gcsrcvr_rcvr_id; -#endif /* PIOS_INCLUDE_GCSRCVR */ +#ifdef PIOS_INCLUDE_GCSRCVR + PIOS_BOARD_IO_Configure_GCSRCVR(); +#endif #ifndef PIOS_ENABLE_DEBUG_PINS switch (hwsettings_rcvrport) { @@ -972,69 +393,7 @@ void PIOS_Board_Init(void) PIOS_DELAY_WaitmS(50); -#if defined(PIOS_INCLUDE_ADC) - PIOS_ADC_Init(&pios_adc_cfg); -#endif - -#ifdef PIOS_INCLUDE_WDG - // give HMC5x83 on I2C some extra time to allow for reset, etc. if needed - // this is not in a loop, so it is safe - // leave this here even if PIOS_INCLUDE_HMC5X83 is undefined - // to avoid making something else fail when HMC5X83 is removed - PIOS_WDG_Clear(); -#endif /* PIOS_INCLUDE_WDG */ - -#if defined(PIOS_INCLUDE_HMC5X83) - // attach the 5x83 mag to the previously inited I2C1 - onboard_mag = PIOS_HMC5x83_Init(&pios_hmc5x83_internal_cfg, pios_i2c_mag_adapter_id, 0); -#ifdef PIOS_INCLUDE_WDG - // give HMC5x83 on I2C some extra time to allow for reset, etc. if needed - // this is not in a loop, so it is safe - PIOS_WDG_Clear(); -#endif /* PIOS_INCLUDE_WDG */ - // add this sensor to the sensor task's list - PIOS_HMC5x83_Register(onboard_mag, PIOS_SENSORS_TYPE_3AXIS_MAG); -#endif - -#if defined(PIOS_INCLUDE_MS5611) - PIOS_MS5611_Init(&pios_ms5611_cfg, pios_i2c_pressure_adapter_id); - PIOS_MS5611_Register(); -#endif - - switch (bdinfo->board_rev) { - case 0x01: -#if defined(PIOS_INCLUDE_L3GD20) - PIOS_Assert(0); // L3gd20 has not been ported to Sensor framework!!! - PIOS_L3GD20_Init(pios_spi_gyro_id, 0, &pios_l3gd20_cfg); - PIOS_Assert(PIOS_L3GD20_Test() == 0); -#endif -#if defined(PIOS_INCLUDE_BMA180) - PIOS_Assert(0); // BMA180 has not been ported to Sensor framework!!! - PIOS_BMA180_Init(pios_spi_accel_id, 0, &pios_bma180_cfg); - PIOS_Assert(PIOS_BMA180_Test() == 0); -#endif - break; - case 0x02: -#if defined(PIOS_INCLUDE_MPU6000) - PIOS_MPU6000_Init(pios_spi_gyro_id, 0, &pios_mpu6000_cfg); - PIOS_MPU6000_CONFIG_Configure(); - PIOS_MPU6000_Register(); -#endif - break; - default: - PIOS_DEBUG_Assert(0); - } -#ifdef PIOS_INCLUDE_ADC - { - uint8_t adc_config[HWSETTINGS_ADCROUTING_NUMELEM]; - HwSettingsADCRoutingArrayGet(adc_config); - for (uint32_t i = 0; i < HWSETTINGS_ADCROUTING_NUMELEM; i++) { - if (adc_config[i] != HWSETTINGS_ADCROUTING_DISABLED) { - PIOS_ADC_PinSetup(i); - } - } - } -#endif // PIOS_INCLUDE_ADC + PIOS_BOARD_Sensors_Configure(); } /** diff --git a/flight/targets/boards/revoproto/pios_board.h b/flight/targets/boards/revoproto/pios_board.h index 60572cdc73..66d4c5cfe5 100644 --- a/flight/targets/boards/revoproto/pios_board.h +++ b/flight/targets/boards/revoproto/pios_board.h @@ -81,30 +81,41 @@ // PIOS_SPI // See also pios_board.c // ------------------------ -#define PIOS_SPI_MAX_DEVS 3 +#define PIOS_SPI_MAX_DEVS 3 +extern uint32_t pios_spi_gyro_id; +extern uint32_t pios_spi_accel_id; +#define PIOS_SPI_L3GD20_ADAPTER (pios_spi_gyro_id) +#define PIOS_SPI_BMA180_ADAPTER (pios_spi_accel_id) +#define PIOS_SPI_MPU6000_ADAPTER (pios_spi_gyro_id) // ------------------------ // PIOS_WDG // ------------------------ -#define PIOS_WATCHDOG_TIMEOUT 250 -#define PIOS_WDG_REGISTER RTC_BKP_DR4 -#define PIOS_WDG_ACTUATOR 0x0001 -#define PIOS_WDG_STABILIZATION 0x0002 -#define PIOS_WDG_ATTITUDE 0x0004 -#define PIOS_WDG_MANUAL 0x0008 -#define PIOS_WDG_SENSORS 0x0010 -#define PIOS_WDG_AUTOTUNE 0x0020 +#define PIOS_WATCHDOG_TIMEOUT 250 +#define PIOS_WDG_REGISTER RTC_BKP_DR4 +#define PIOS_WDG_ACTUATOR 0x0001 +#define PIOS_WDG_STABILIZATION 0x0002 +#define PIOS_WDG_ATTITUDE 0x0004 +#define PIOS_WDG_MANUAL 0x0008 +#define PIOS_WDG_SENSORS 0x0010 +#define PIOS_WDG_AUTOTUNE 0x0020 // ------------------------ // PIOS_I2C // See also pios_board.c // ------------------------ -#define PIOS_I2C_MAX_DEVS 3 +#define PIOS_I2C_MAX_DEVS 3 extern uint32_t pios_i2c_mag_adapter_id; -#define PIOS_I2C_MAIN_ADAPTER (pios_i2c_mag_adapter_id) +extern uint32_t pios_i2c_pressure_adapter_id; + +#define PIOS_I2C_MS5611_INTERNAL_ADAPTER (pios_i2c_pressure_adapter_id) +#define PIOS_I2C_HMC5X83_INTERNAL_ADAPTER (pios_i2c_mag_adapter_id) + extern uint32_t pios_i2c_flexiport_adapter_id; -#define PIOS_I2C_FLEXI_ADAPTER (pios_i2c_flexiport_adapter_id) -#define PIOS_I2C_ETASV3_ADAPTER (PIOS_I2C_FLEXI_ADAPTER) +#define PIOS_I2C_FLEXI_ADAPTER (pios_i2c_flexiport_adapter_id) +#define PIOS_I2C_ETASV3_ADAPTER (PIOS_I2C_FLEXI_ADAPTER) +#define PIOS_I2C_EXTERNAL_ADAPTER (pios_i2c_flexiport_adapter_id) + // ------------------------- // PIOS_USART @@ -119,26 +130,26 @@ extern uint32_t pios_i2c_flexiport_adapter_id; // See also pios_board.c // ------------------------- #define PIOS_COM_MAX_DEVS 4 -extern uint32_t pios_com_telem_rf_id; -extern uint32_t pios_com_gps_id; -extern uint32_t pios_com_aux_id; -extern uint32_t pios_com_telem_usb_id; -extern uint32_t pios_com_bridge_id; -extern uint32_t pios_com_vcp_id; -extern uint32_t pios_com_hkosd_id; -extern uint32_t pios_com_msp_id; -extern uint32_t pios_com_mavlink_id; - -#define PIOS_COM_AUX (pios_com_aux_id) -#define PIOS_COM_GPS (pios_com_gps_id) -#define PIOS_COM_TELEM_USB (pios_com_telem_usb_id) -#define PIOS_COM_TELEM_RF (pios_com_telem_rf_id) -#define PIOS_COM_BRIDGE (pios_com_bridge_id) -#define PIOS_COM_VCP (pios_com_vcp_id) -#define PIOS_COM_DEBUG PIOS_COM_AUX -#define PIOS_COM_OSDHK (pios_com_hkosd_id) -#define PIOS_COM_MSP (pios_com_msp_id) -#define PIOS_COM_MAVLINK (pios_com_mavlink_id) +// extern uint32_t pios_com_telem_rf_id; +// extern uint32_t pios_com_gps_id; +// extern uint32_t pios_com_aux_id; +// extern uint32_t pios_com_telem_usb_id; +// extern uint32_t pios_com_bridge_id; +// extern uint32_t pios_com_vcp_id; +// extern uint32_t pios_com_hkosd_id; +// extern uint32_t pios_com_msp_id; +// extern uint32_t pios_com_mavlink_id; +// +// #define PIOS_COM_AUX (pios_com_aux_id) +// #define PIOS_COM_GPS (pios_com_gps_id) +// #define PIOS_COM_TELEM_USB (pios_com_telem_usb_id) +// #define PIOS_COM_TELEM_RF (pios_com_telem_rf_id) +// #define PIOS_COM_BRIDGE (pios_com_bridge_id) +// #define PIOS_COM_VCP (pios_com_vcp_id) +// #define PIOS_COM_DEBUG PIOS_COM_AUX +// #define PIOS_COM_OSDHK (pios_com_hkosd_id) +// #define PIOS_COM_MSP (pios_com_msp_id) +// #define PIOS_COM_MAVLINK (pios_com_mavlink_id) // ------------------------ // TELEMETRY diff --git a/flight/targets/boards/sparky2/board_hw_defs.c b/flight/targets/boards/sparky2/board_hw_defs.c index 8316bc3df5..18ed6962f0 100644 --- a/flight/targets/boards/sparky2/board_hw_defs.c +++ b/flight/targets/boards/sparky2/board_hw_defs.c @@ -439,7 +439,7 @@ const struct pios_rfm22b_cfg pios_rfm22b_cfg = { .gpio_direction = GPIO0_TX_GPIO1_RX, }; -const struct pios_rfm22b_cfg *PIOS_BOARD_HW_DEFS_GetRfm22Cfg(__attribute__((unused)) uint32_t board_revision) +const struct pios_rfm22b_cfg *PIOS_BOARD_HW_DEFS_GetRfm22bCfg(__attribute__((unused)) uint32_t board_revision) { return &pios_rfm22b_cfg; } @@ -540,6 +540,7 @@ static const struct flashfs_logfs_cfg flashfs_internal_cfg = { #endif /* PIOS_INCLUDE_FLASH */ +#ifdef PIOS_INCLUDE_USART #include /* @@ -628,6 +629,7 @@ static const struct pios_usart_cfg pios_usart_rcvr_cfg = { }, .ioctl = PIOS_BOARD_USART_Ioctl, }; +#endif /* PIOS_INCLUDE_USART */ #if defined(PIOS_INCLUDE_COM) diff --git a/flight/targets/boards/sparky2/bootloader/main.c b/flight/targets/boards/sparky2/bootloader/main.c index 70b18409e4..02d53d9488 100644 --- a/flight/targets/boards/sparky2/bootloader/main.c +++ b/flight/targets/boards/sparky2/bootloader/main.c @@ -36,6 +36,7 @@ #include /* PIOS_USBHOOK_* */ #include #include +#include extern void FLASH_Download(); void check_bor(); diff --git a/flight/targets/boards/sparky2/bootloader/pios_board.c b/flight/targets/boards/sparky2/bootloader/pios_board.c index f93555938d..dfdbcbfcee 100644 --- a/flight/targets/boards/sparky2/bootloader/pios_board.c +++ b/flight/targets/boards/sparky2/bootloader/pios_board.c @@ -25,7 +25,6 @@ #include #include - /* * Pull in the board-specific static HW definitions. * Including .c files is a bit ugly but this allows all of @@ -40,11 +39,6 @@ uint32_t pios_com_telem_usb_id; static bool board_init_complete = false; -static int32_t PIOS_BOARD_USART_Ioctl(__attribute__((unused)) uint32_t usart_id, __attribute__((unused)) uint32_t ctl, __attribute__((unused)) void *param) -{ - return -1; -} - void PIOS_Board_Init() { if (board_init_complete) { From 1548312823aec256b086e49aa5b4a4ee46d65ce7 Mon Sep 17 00:00:00 2001 From: Vladimir Zidar Date: Sun, 16 Apr 2017 02:44:07 +0200 Subject: [PATCH 221/624] LP-480 CopterControl will expect ADC_Init() only if board revision has analog gyro, so be prepared to get NULL from PIOS_BOARD_HW_DEFS_GetAdcCfg() --- flight/pios/common/pios_board_sensors.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/flight/pios/common/pios_board_sensors.c b/flight/pios/common/pios_board_sensors.c index 3b0e58b6cb..7d204757fe 100644 --- a/flight/pios/common/pios_board_sensors.c +++ b/flight/pios/common/pios_board_sensors.c @@ -185,16 +185,19 @@ void PIOS_BOARD_Sensors_Configure() #endif #ifdef PIOS_INCLUDE_ADC - PIOS_ADC_Init(PIOS_BOARD_HW_DEFS_GetAdcCfg(pios_board_info_blob.board_rev)); -#ifndef PIOS_EXCLUDE_ADVANCED_FEATURES - uint8_t adc_config[HWSETTINGS_ADCROUTING_NUMELEM]; - HwSettingsADCRoutingArrayGet(adc_config); - for (uint32_t i = 0; i < HWSETTINGS_ADCROUTING_NUMELEM; i++) { - if (adc_config[i] != HWSETTINGS_ADCROUTING_DISABLED) { - PIOS_ADC_PinSetup(i); + const struct pios_adc_cfg *adc_cfg = PIOS_BOARD_HW_DEFS_GetAdcCfg(pios_board_info_blob.board_rev); + if(adc_cfg) { + PIOS_ADC_Init(adc_cfg); +# ifndef PIOS_EXCLUDE_ADVANCED_FEATURES + uint8_t adc_config[HWSETTINGS_ADCROUTING_NUMELEM]; + HwSettingsADCRoutingArrayGet(adc_config); + for (uint32_t i = 0; i < HWSETTINGS_ADCROUTING_NUMELEM; i++) { + if (adc_config[i] != HWSETTINGS_ADCROUTING_DISABLED) { + PIOS_ADC_PinSetup(i); + } } +# endif } -#endif #endif /* PIOS_INCLUDE_ADC */ // internal bmp280 baro From 280e771ded933b12f86ff140b07b08a3ed259eca Mon Sep 17 00:00:00 2001 From: Vladimir Zidar Date: Sun, 16 Apr 2017 18:11:20 +0200 Subject: [PATCH 222/624] LP-480 Make PIOS_BOARD_IO_USB_[VCP|HID]_Function enums based on HWSETTINGS_USB_[HID|VCP]PORT values to allow simple type casting. --- flight/pios/common/pios_board_io.c | 34 +++++------------------------- flight/pios/inc/pios_board_io.h | 20 +++++++++++------- 2 files changed, 17 insertions(+), 37 deletions(-) diff --git a/flight/pios/common/pios_board_io.c b/flight/pios/common/pios_board_io.c index 6b639c1503..78c59e6826 100644 --- a/flight/pios/common/pios_board_io.c +++ b/flight/pios/common/pios_board_io.c @@ -161,39 +161,15 @@ static void PIOS_BOARD_IO_HID_Init(uint32_t *com_id, uint16_t rx_buf_len, uint16 } } -PIOS_BOARD_IO_USB_HID_Function PIOS_BOARD_IO_HWSettings_USB_HID_Function() +void PIOS_BOARD_IO_Configure_USB() { - static const PIOS_BOARD_IO_USB_HID_Function map[] = { - [HWSETTINGS_USB_HIDPORT_USBTELEMETRY] = PIOS_BOARD_IO_USB_HID_TELEMETRY, - [HWSETTINGS_USB_HIDPORT_RCTRANSMITTER] = PIOS_BOARD_IO_USB_HID_RCTX, - }; uint8_t hwsettings_usb_hidport; - - HwSettingsUSB_HIDPortGet(&hwsettings_usb_hidport); - - return (hwsettings_usb_hidport < NELEMENTS(map)) ? map[hwsettings_usb_hidport] : PIOS_BOARD_IO_USB_HID_NONE; -} - -PIOS_BOARD_IO_USB_VCP_Function PIOS_BOARD_IO_HWSettings_USB_VCP_Function() -{ - static const PIOS_BOARD_IO_USB_VCP_Function map[] = { - [HWSETTINGS_USB_VCPPORT_USBTELEMETRY] = PIOS_BOARD_IO_USB_VCP_TELEMETRY, - [HWSETTINGS_USB_VCPPORT_COMBRIDGE] = PIOS_BOARD_IO_USB_VCP_COMBRIDGE, - [HWSETTINGS_USB_VCPPORT_DEBUGCONSOLE] = PIOS_BOARD_IO_USB_VCP_DEBUGCONSOLE, - [HWSETTINGS_USB_VCPPORT_MAVLINK] = PIOS_BOARD_IO_USB_VCP_MAVLINK, - }; - uint8_t hwsettings_usb_vcpport; - + + HwSettingsUSB_HIDPortGet(&hwsettings_usb_hidport); HwSettingsUSB_VCPPortGet(&hwsettings_usb_vcpport); - - return (hwsettings_usb_vcpport < NELEMENTS(map)) ? map[hwsettings_usb_vcpport] : PIOS_BOARD_IO_USB_VCP_NONE; -} - -void PIOS_BOARD_IO_Configure_USB() -{ - PIOS_BOARD_IO_Configure_USB_Function(PIOS_BOARD_IO_HWSettings_USB_HID_Function(), - PIOS_BOARD_IO_HWSettings_USB_VCP_Function()); + + PIOS_BOARD_IO_Configure_USB_Function((PIOS_BOARD_IO_USB_HID_Function)hwsettings_usb_hidport, (PIOS_BOARD_IO_USB_VCP_Function)hwsettings_usb_vcpport); } void PIOS_BOARD_IO_Configure_USB_Function(PIOS_BOARD_IO_USB_HID_Function hid_function, __attribute__((unused)) PIOS_BOARD_IO_USB_VCP_Function vcp_function) diff --git a/flight/pios/inc/pios_board_io.h b/flight/pios/inc/pios_board_io.h index d186f5ea52..1d929228ae 100644 --- a/flight/pios/inc/pios_board_io.h +++ b/flight/pios/inc/pios_board_io.h @@ -208,23 +208,27 @@ typedef enum { } PIOS_BOARD_IO_RADIOAUX_Function; #ifdef PIOS_INCLUDE_USB +# ifndef BOOTLOADER +# include "hwsettings.h" + void PIOS_BOARD_IO_Configure_USB(); typedef enum { - PIOS_BOARD_IO_USB_HID_NONE = 0, - PIOS_BOARD_IO_USB_HID_TELEMETRY, - PIOS_BOARD_IO_USB_HID_RCTX, + PIOS_BOARD_IO_USB_HID_NONE = HWSETTINGS_USB_HIDPORT_DISABLED, + PIOS_BOARD_IO_USB_HID_TELEMETRY = HWSETTINGS_USB_HIDPORT_USBTELEMETRY, + PIOS_BOARD_IO_USB_HID_RCTX = HWSETTINGS_USB_HIDPORT_RCTRANSMITTER, } PIOS_BOARD_IO_USB_HID_Function; typedef enum { - PIOS_BOARD_IO_USB_VCP_NONE = 0, - PIOS_BOARD_IO_USB_VCP_TELEMETRY, - PIOS_BOARD_IO_USB_VCP_COMBRIDGE, - PIOS_BOARD_IO_USB_VCP_DEBUGCONSOLE, - PIOS_BOARD_IO_USB_VCP_MAVLINK, + PIOS_BOARD_IO_USB_VCP_NONE = HWSETTINGS_USB_VCPPORT_DISABLED, + PIOS_BOARD_IO_USB_VCP_TELEMETRY = HWSETTINGS_USB_VCPPORT_USBTELEMETRY, + PIOS_BOARD_IO_USB_VCP_COMBRIDGE = HWSETTINGS_USB_VCPPORT_COMBRIDGE, + PIOS_BOARD_IO_USB_VCP_DEBUGCONSOLE = HWSETTINGS_USB_VCPPORT_DEBUGCONSOLE, + PIOS_BOARD_IO_USB_VCP_MAVLINK = HWSETTINGS_USB_VCPPORT_MAVLINK, } PIOS_BOARD_IO_USB_VCP_Function; void PIOS_BOARD_IO_Configure_USB_Function(PIOS_BOARD_IO_USB_HID_Function hid_function, PIOS_BOARD_IO_USB_VCP_Function vcp_function); +# endif #endif #ifdef PIOS_INCLUDE_PWM void PIOS_BOARD_IO_Configure_PWM(const struct pios_pwm_cfg *pwm_cfg); From 97210850c39db0be927ca7ea3b4a5d3d428a1aab Mon Sep 17 00:00:00 2001 From: Vladimir Zidar Date: Sun, 16 Apr 2017 18:13:55 +0200 Subject: [PATCH 223/624] LP-480 add missing #include --- flight/pios/inc/pios_board_io.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/flight/pios/inc/pios_board_io.h b/flight/pios/inc/pios_board_io.h index 1d929228ae..2c94895280 100644 --- a/flight/pios/inc/pios_board_io.h +++ b/flight/pios/inc/pios_board_io.h @@ -209,7 +209,8 @@ typedef enum { #ifdef PIOS_INCLUDE_USB # ifndef BOOTLOADER -# include "hwsettings.h" +# include "uavobjectmanager.h" +# include "hwsettings.h" void PIOS_BOARD_IO_Configure_USB(); From 9d01cbe4d43a9c33f3962c5f2327e6eb30da28d4 Mon Sep 17 00:00:00 2001 From: Vladimir Zidar Date: Sun, 16 Apr 2017 14:06:28 -0700 Subject: [PATCH 224/624] LP-480 Comments out PIOS_INCLUDE_USART and PIOS_INCLUDE_PWM from simposix pios_config.h to allow simposix fw build. --- flight/pios/inc/pios_board_io.h | 4 ++++ flight/targets/boards/simposix/firmware/inc/pios_config.h | 6 +++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/flight/pios/inc/pios_board_io.h b/flight/pios/inc/pios_board_io.h index 2c94895280..de46a8bae5 100644 --- a/flight/pios/inc/pios_board_io.h +++ b/flight/pios/inc/pios_board_io.h @@ -33,7 +33,9 @@ #include #endif +#ifdef PIOS_INCLUDE_USART #include +#endif #ifdef PIOS_INCLUDE_PWM #include @@ -238,7 +240,9 @@ void PIOS_BOARD_IO_Configure_PWM(const struct pios_pwm_cfg *pwm_cfg); void PIOS_BOARD_IO_Configure_PPM(const struct pios_ppm_cfg *ppm_cfg); #endif +#ifdef PIOS_INCLUDE_USART void PIOS_BOARD_IO_Configure_UART(const struct pios_usart_cfg *usart_cfg, PIOS_BOARD_IO_UART_Function function); +#endif #ifdef PIOS_INCLUDE_RFM22B void PIOS_BOARD_IO_Configure_RFM22B(PIOS_BOARD_IO_RADIOAUX_Function function); diff --git a/flight/targets/boards/simposix/firmware/inc/pios_config.h b/flight/targets/boards/simposix/firmware/inc/pios_config.h index d422ddeff5..36f84be851 100644 --- a/flight/targets/boards/simposix/firmware/inc/pios_config.h +++ b/flight/targets/boards/simposix/firmware/inc/pios_config.h @@ -52,7 +52,7 @@ #define PIOS_INCLUDE_SPI #define PIOS_INCLUDE_SYS #define PIOS_INCLUDE_TASK_MONITOR -#define PIOS_INCLUDE_USART +//#define PIOS_INCLUDE_USART // #define PIOS_INCLUDE_USB #define PIOS_INCLUDE_USB_HID // #define PIOS_INCLUDE_GPIO @@ -87,8 +87,8 @@ #define PIOS_INCLUDE_RCVR #define PIOS_INCLUDE_DSM // #define PIOS_INCLUDE_SBUS -#define PIOS_INCLUDE_PPM -#define PIOS_INCLUDE_PWM +//#define PIOS_INCLUDE_PPM +//#define PIOS_INCLUDE_PWM /* #define PIOS_INCLUDE_GCSRCVR */ /* #define PIOS_INCLUDE_OPLINKRCVR */ #define PIOS_INCLUDE_IAP From 86022e2defced66e523f9416eceb0c1d8f832f92 Mon Sep 17 00:00:00 2001 From: Vladimir Zidar Date: Sun, 16 Apr 2017 22:35:57 +0200 Subject: [PATCH 225/624] LP-480 removed unused PIOS_BOARD_IO_Configure_WS2811() and PIOS_BOARD_IO_Configure_ADC() from pios_board_io.h --- flight/pios/inc/pios_board_io.h | 9 --------- 1 file changed, 9 deletions(-) diff --git a/flight/pios/inc/pios_board_io.h b/flight/pios/inc/pios_board_io.h index de46a8bae5..75a4f18cd0 100644 --- a/flight/pios/inc/pios_board_io.h +++ b/flight/pios/inc/pios_board_io.h @@ -252,13 +252,4 @@ void PIOS_BOARD_IO_Configure_RFM22B(PIOS_BOARD_IO_RADIOAUX_Function function); void PIOS_BOARD_IO_Configure_GCSRCVR(); #endif -#ifdef PIOS_INCLUDE_WS2811 -void PIOS_BOARD_IO_Configure_WS2811(); -#endif - -#ifdef PIOS_INCLUDE_ADC -void PIOS_BOARD_IO_Configure_ADC(); -#endif - - #endif /* PIOS_BOARD_IO_H */ From 05ee4b8dace8715753e4b63938c5e49c28120c10 Mon Sep 17 00:00:00 2001 From: Vladimir Zidar Date: Mon, 17 Apr 2017 00:50:08 +0200 Subject: [PATCH 226/624] LP-480 Move PIOS_COM_SetHalfDuplex() functionality to IOCTL. Remove RX/TX mode and change parameter order for PIOS_COM_ChangeConfig() and com driver set_config to match the databits/parity/stopbits scheme (like for example 8N1). --- .../modules/UAVOHottBridge/uavohottbridge.c | 3 +- flight/pios/common/pios_board_io.c | 4 +- flight/pios/common/pios_board_sensors.c | 2 +- flight/pios/common/pios_com.c | 28 +--- flight/pios/common/pios_dsm.c | 2 +- flight/pios/common/pios_exbus.c | 2 +- flight/pios/common/pios_hott.c | 2 +- flight/pios/common/pios_ibus.c | 2 +- flight/pios/common/pios_sbus.c | 2 +- flight/pios/common/pios_srxl.c | 2 +- flight/pios/inc/pios_board_io.h | 8 +- flight/pios/inc/pios_com.h | 6 +- flight/pios/inc/pios_usart.h | 12 +- flight/pios/stm32f0x/pios_usart.c | 103 +++++++------ flight/pios/stm32f10x/pios_usart.c | 98 ++++++------ flight/pios/stm32f4xx/pios_usart.c | 142 ++++++++---------- .../simposix/firmware/inc/pios_config.h | 6 +- 17 files changed, 200 insertions(+), 224 deletions(-) diff --git a/flight/modules/UAVOHottBridge/uavohottbridge.c b/flight/modules/UAVOHottBridge/uavohottbridge.c index 663045d088..2fbab124e1 100644 --- a/flight/modules/UAVOHottBridge/uavohottbridge.c +++ b/flight/modules/UAVOHottBridge/uavohottbridge.c @@ -123,7 +123,8 @@ static int32_t uavoHoTTBridgeInitialize(void) // HoTT telemetry baudrate is fixed to 19200 PIOS_COM_ChangeBaud(PIOS_COM_HOTT, 19200); - PIOS_COM_SetHalfDuplex(PIOS_COM_HOTT, true); + bool param = true; + PIOS_COM_Ioctl(PIOS_COM_HOTT, PIOS_IOCTL_USART_SET_HALFDUPLEX, ¶m); HoTTBridgeSettingsInitialize(); HoTTBridgeStatusInitialize(); diff --git a/flight/pios/common/pios_board_io.c b/flight/pios/common/pios_board_io.c index 78c59e6826..e43b3053c5 100644 --- a/flight/pios/common/pios_board_io.c +++ b/flight/pios/common/pios_board_io.c @@ -165,10 +165,10 @@ void PIOS_BOARD_IO_Configure_USB() { uint8_t hwsettings_usb_hidport; uint8_t hwsettings_usb_vcpport; - + HwSettingsUSB_HIDPortGet(&hwsettings_usb_hidport); HwSettingsUSB_VCPPortGet(&hwsettings_usb_vcpport); - + PIOS_BOARD_IO_Configure_USB_Function((PIOS_BOARD_IO_USB_HID_Function)hwsettings_usb_hidport, (PIOS_BOARD_IO_USB_VCP_Function)hwsettings_usb_vcpport); } diff --git a/flight/pios/common/pios_board_sensors.c b/flight/pios/common/pios_board_sensors.c index 7d204757fe..4abfe1e021 100644 --- a/flight/pios/common/pios_board_sensors.c +++ b/flight/pios/common/pios_board_sensors.c @@ -186,7 +186,7 @@ void PIOS_BOARD_Sensors_Configure() #ifdef PIOS_INCLUDE_ADC const struct pios_adc_cfg *adc_cfg = PIOS_BOARD_HW_DEFS_GetAdcCfg(pios_board_info_blob.board_rev); - if(adc_cfg) { + if (adc_cfg) { PIOS_ADC_Init(adc_cfg); # ifndef PIOS_EXCLUDE_ADVANCED_FEATURES uint8_t adc_config[HWSETTINGS_ADCROUTING_NUMELEM]; diff --git a/flight/pios/common/pios_com.c b/flight/pios/common/pios_com.c index 1a813ba3ca..fb8fe30448 100644 --- a/flight/pios/common/pios_com.c +++ b/flight/pios/common/pios_com.c @@ -296,31 +296,7 @@ int32_t PIOS_COM_ChangeBaud(uint32_t com_id, uint32_t baud) return 0; } -/** - * Change the port type to halfduplex (shared rx/tx medium) - * \param[in] port COM port - * \param[in] halfduplex enabled - * \return -1 if port not available - * \return 0 on success - */ -int32_t PIOS_COM_SetHalfDuplex(uint32_t com_id, bool halfduplex) -{ - struct pios_com_dev *com_dev = (struct pios_com_dev *)com_id; - - if (!PIOS_COM_validate(com_dev)) { - /* Undefined COM port for this board (see pios_board.c) */ - return -1; - } - - /* Invoke the driver function if it exists */ - if (com_dev->driver->set_halfduplex) { - com_dev->driver->set_halfduplex(com_dev->lower_id, halfduplex); - } - - return 0; -} - -int32_t PIOS_COM_ChangeConfig(uint32_t com_id, enum PIOS_COM_Word_Length word_len, enum PIOS_COM_StopBits stop_bits, enum PIOS_COM_Parity parity, uint32_t baud_rate, enum PIOS_COM_Mode mode) +int32_t PIOS_COM_ChangeConfig(uint32_t com_id, enum PIOS_COM_Word_Length word_len, enum PIOS_COM_Parity parity, enum PIOS_COM_StopBits stop_bits, uint32_t baud_rate) { struct pios_com_dev *com_dev = (struct pios_com_dev *)com_id; @@ -331,7 +307,7 @@ int32_t PIOS_COM_ChangeConfig(uint32_t com_id, enum PIOS_COM_Word_Length word_le /* Invoke the driver function if it exists */ if (com_dev->driver->set_config) { - com_dev->driver->set_config(com_dev->lower_id, word_len, stop_bits, parity, baud_rate, mode); + com_dev->driver->set_config(com_dev->lower_id, word_len, parity, stop_bits, baud_rate); } return 0; diff --git a/flight/pios/common/pios_dsm.c b/flight/pios/common/pios_dsm.c index af52ce9854..747e2b91f4 100644 --- a/flight/pios/common/pios_dsm.c +++ b/flight/pios/common/pios_dsm.c @@ -332,7 +332,7 @@ int32_t PIOS_DSM_Init(uint32_t *dsm_id, /* Set comm driver parameters */ PIOS_DEBUG_Assert(driver->set_config); - driver->set_config(lower_id, PIOS_COM_Word_length_8b, PIOS_COM_StopBits_1, PIOS_COM_Parity_No, 115200, PIOS_COM_Mode_Rx); + driver->set_config(lower_id, PIOS_COM_Word_length_8b, PIOS_COM_Parity_No, PIOS_COM_StopBits_1, 115200); /* Set irq priority */ if (driver->ioctl) { diff --git a/flight/pios/common/pios_exbus.c b/flight/pios/common/pios_exbus.c index c29564075a..edb4162335 100644 --- a/flight/pios/common/pios_exbus.c +++ b/flight/pios/common/pios_exbus.c @@ -309,7 +309,7 @@ int32_t PIOS_EXBUS_Init(uint32_t *exbus_id, /* Set comm driver parameters */ PIOS_DEBUG_Assert(driver->set_config); - driver->set_config(lower_id, PIOS_COM_Word_length_8b, PIOS_COM_StopBits_1, PIOS_COM_Parity_No, 125000, PIOS_COM_Mode_Rx); + driver->set_config(lower_id, PIOS_COM_Word_length_8b, PIOS_COM_Parity_No, PIOS_COM_StopBits_1, 125000); /* Set irq priority */ if (driver->ioctl) { diff --git a/flight/pios/common/pios_hott.c b/flight/pios/common/pios_hott.c index 04f2fc940a..c823cc8fe8 100644 --- a/flight/pios/common/pios_hott.c +++ b/flight/pios/common/pios_hott.c @@ -327,7 +327,7 @@ int32_t PIOS_HOTT_Init(uint32_t *hott_id, /* Set comm driver parameters */ PIOS_DEBUG_Assert(driver->set_config); - driver->set_config(lower_id, PIOS_COM_Word_length_8b, PIOS_COM_StopBits_1, PIOS_COM_Parity_No, 115200, PIOS_COM_Mode_Rx); + driver->set_config(lower_id, PIOS_COM_Word_length_8b, PIOS_COM_Parity_No, PIOS_COM_StopBits_1, 115200); /* Set irq priority */ if (driver->ioctl) { diff --git a/flight/pios/common/pios_ibus.c b/flight/pios/common/pios_ibus.c index 953ef88652..8dd4595e6c 100644 --- a/flight/pios/common/pios_ibus.c +++ b/flight/pios/common/pios_ibus.c @@ -176,7 +176,7 @@ int32_t PIOS_IBUS_Init(uint32_t *ibus_id, const struct pios_com_driver *driver, /* Set comm driver parameters */ PIOS_DEBUG_Assert(driver->set_config); - driver->set_config(lower_id, PIOS_COM_Word_length_8b, PIOS_COM_StopBits_1, PIOS_COM_Parity_No, 115200, PIOS_COM_Mode_Rx); + driver->set_config(lower_id, PIOS_COM_Word_length_8b, PIOS_COM_Parity_No, PIOS_COM_StopBits_1, 115200); /* Set irq priority */ if (driver->ioctl) { diff --git a/flight/pios/common/pios_sbus.c b/flight/pios/common/pios_sbus.c index 979c6a856c..f7cd3f4750 100644 --- a/flight/pios/common/pios_sbus.c +++ b/flight/pios/common/pios_sbus.c @@ -168,7 +168,7 @@ int32_t PIOS_SBus_Init(uint32_t *sbus_id, /* Set rest of the parameters */ if (driver->set_config) { - driver->set_config(lower_id, PIOS_COM_Word_length_8b, PIOS_COM_StopBits_2, PIOS_COM_Parity_Even, 100000, PIOS_COM_Mode_Rx); + driver->set_config(lower_id, PIOS_COM_Word_length_8b, PIOS_COM_Parity_Even, PIOS_COM_StopBits_2, 100000); } /* Set inverted UART and IRQ priority */ diff --git a/flight/pios/common/pios_srxl.c b/flight/pios/common/pios_srxl.c index b0595ed8e7..4dcd69d85c 100644 --- a/flight/pios/common/pios_srxl.c +++ b/flight/pios/common/pios_srxl.c @@ -158,7 +158,7 @@ int32_t PIOS_SRXL_Init(uint32_t *srxl_id, /* Set comm driver parameters */ PIOS_DEBUG_Assert(driver->set_config); - driver->set_config(lower_id, PIOS_COM_Word_length_8b, PIOS_COM_StopBits_1, PIOS_COM_Parity_No, 115200, PIOS_COM_Mode_Rx); + driver->set_config(lower_id, PIOS_COM_Word_length_8b, PIOS_COM_Parity_No, PIOS_COM_StopBits_1, 115200); /* Set irq priority */ if (driver->ioctl) { diff --git a/flight/pios/inc/pios_board_io.h b/flight/pios/inc/pios_board_io.h index 75a4f18cd0..cf0533b023 100644 --- a/flight/pios/inc/pios_board_io.h +++ b/flight/pios/inc/pios_board_io.h @@ -224,15 +224,15 @@ typedef enum { typedef enum { PIOS_BOARD_IO_USB_VCP_NONE = HWSETTINGS_USB_VCPPORT_DISABLED, - PIOS_BOARD_IO_USB_VCP_TELEMETRY = HWSETTINGS_USB_VCPPORT_USBTELEMETRY, - PIOS_BOARD_IO_USB_VCP_COMBRIDGE = HWSETTINGS_USB_VCPPORT_COMBRIDGE, + PIOS_BOARD_IO_USB_VCP_TELEMETRY = HWSETTINGS_USB_VCPPORT_USBTELEMETRY, + PIOS_BOARD_IO_USB_VCP_COMBRIDGE = HWSETTINGS_USB_VCPPORT_COMBRIDGE, PIOS_BOARD_IO_USB_VCP_DEBUGCONSOLE = HWSETTINGS_USB_VCPPORT_DEBUGCONSOLE, PIOS_BOARD_IO_USB_VCP_MAVLINK = HWSETTINGS_USB_VCPPORT_MAVLINK, } PIOS_BOARD_IO_USB_VCP_Function; void PIOS_BOARD_IO_Configure_USB_Function(PIOS_BOARD_IO_USB_HID_Function hid_function, PIOS_BOARD_IO_USB_VCP_Function vcp_function); -# endif -#endif +# endif // ifndef BOOTLOADER +#endif // ifdef PIOS_INCLUDE_USB #ifdef PIOS_INCLUDE_PWM void PIOS_BOARD_IO_Configure_PWM(const struct pios_pwm_cfg *pwm_cfg); #endif diff --git a/flight/pios/inc/pios_com.h b/flight/pios/inc/pios_com.h index a150691a38..113f38d6fd 100644 --- a/flight/pios/inc/pios_com.h +++ b/flight/pios/inc/pios_com.h @@ -71,8 +71,7 @@ enum PIOS_COM_Mode { struct pios_com_driver { void (*set_baud)(uint32_t id, uint32_t baud); - void (*set_halfduplex)(uint32_t id, bool halfduplex); - void (*set_config)(uint32_t usart_id, enum PIOS_COM_Word_Length word_len, enum PIOS_COM_StopBits stop_bits, enum PIOS_COM_Parity parity, uint32_t baud_rate, enum PIOS_COM_Mode mode); + void (*set_config)(uint32_t usart_id, enum PIOS_COM_Word_Length word_len, enum PIOS_COM_Parity parity, enum PIOS_COM_StopBits stop_bits, uint32_t baud_rate); void (*set_ctrl_line)(uint32_t id, uint32_t mask, uint32_t state); void (*tx_start)(uint32_t id, uint16_t tx_bytes_avail); void (*rx_start)(uint32_t id, uint16_t rx_bytes_avail); @@ -92,8 +91,7 @@ struct pios_com_driver { /* Public Functions */ extern int32_t PIOS_COM_Init(uint32_t *com_id, const struct pios_com_driver *driver, uint32_t lower_id, uint8_t *rx_buffer, uint16_t rx_buffer_len, uint8_t *tx_buffer, uint16_t tx_buffer_len); extern int32_t PIOS_COM_ChangeBaud(uint32_t com_id, uint32_t baud); -extern int32_t PIOS_COM_SetHalfDuplex(uint32_t com_id, bool halfduplex); -extern int32_t PIOS_COM_ChangeConfig(uint32_t com_id, enum PIOS_COM_Word_Length word_len, enum PIOS_COM_StopBits stop_bits, enum PIOS_COM_Parity parity, uint32_t baud_rate, enum PIOS_COM_Mode mode); +extern int32_t PIOS_COM_ChangeConfig(uint32_t com_id, enum PIOS_COM_Word_Length word_len, enum PIOS_COM_Parity parity, enum PIOS_COM_StopBits stop_bits, uint32_t baud_rate); extern int32_t PIOS_COM_SetCtrlLine(uint32_t com_id, uint32_t mask, uint32_t state); extern int32_t PIOS_COM_RegisterCtrlLineCallback(uint32_t usart_id, pios_com_callback_ctrl_line ctrl_line_cb, uint32_t context); extern int32_t PIOS_COM_RegisterBaudRateCallback(uint32_t usart_id, pios_com_callback_baud_rate baud_rate_cb, uint32_t context); diff --git a/flight/pios/inc/pios_usart.h b/flight/pios/inc/pios_usart.h index 49ac3c92a8..35e35c89ba 100644 --- a/flight/pios/inc/pios_usart.h +++ b/flight/pios/inc/pios_usart.h @@ -43,15 +43,15 @@ enum PIOS_USART_Inverted { PIOS_USART_Inverted_RxTx = (PIOS_USART_Inverted_Rx | PIOS_USART_Inverted_Tx) }; -#define PIOS_IOCTL_USART_SET_INVERTED COM_IOCTL(COM_IOCTL_TYPE_USART, 1, enum PIOS_USART_Inverted) -#define PIOS_IOCTL_USART_SET_SWAPPIN COM_IOCTL(COM_IOCTL_TYPE_USART, 2, bool) -#define PIOS_IOCTL_USART_SET_ONEWIRE COM_IOCTL(COM_IOCTL_TYPE_USART, 3, bool) +#define PIOS_IOCTL_USART_SET_INVERTED COM_IOCTL(COM_IOCTL_TYPE_USART, 1, enum PIOS_USART_Inverted) +#define PIOS_IOCTL_USART_SET_SWAPPIN COM_IOCTL(COM_IOCTL_TYPE_USART, 2, bool) +#define PIOS_IOCTL_USART_SET_HALFDUPLEX COM_IOCTL(COM_IOCTL_TYPE_USART, 3, bool) -#define PIOS_IOCTL_USART_GET_RXGPIO COM_IOCTL(COM_IOCTL_TYPE_USART, 4, struct stm32_gpio) -#define PIOS_IOCTL_USART_GET_TXGPIO COM_IOCTL(COM_IOCTL_TYPE_USART, 5, struct stm32_gpio) +#define PIOS_IOCTL_USART_GET_RXGPIO COM_IOCTL(COM_IOCTL_TYPE_USART, 4, struct stm32_gpio) +#define PIOS_IOCTL_USART_GET_TXGPIO COM_IOCTL(COM_IOCTL_TYPE_USART, 5, struct stm32_gpio) /* PIOS_IRQ_PRIO_ values */ -#define PIOS_IOCTL_USART_SET_IRQ_PRIO COM_IOCTL(COM_IOCTL_TYPE_USART, 6, uint8_t) +#define PIOS_IOCTL_USART_SET_IRQ_PRIO COM_IOCTL(COM_IOCTL_TYPE_USART, 6, uint8_t) #endif /* PIOS_USART_H */ diff --git a/flight/pios/stm32f0x/pios_usart.c b/flight/pios/stm32f0x/pios_usart.c index 21a1dceed3..7666bc8df6 100644 --- a/flight/pios/stm32f0x/pios_usart.c +++ b/flight/pios/stm32f0x/pios_usart.c @@ -39,7 +39,7 @@ /* Provide a COM driver */ static void PIOS_USART_ChangeBaud(uint32_t usart_id, uint32_t baud); #ifndef BOOTLOADER -static void PIOS_USART_ChangeConfig(uint32_t usart_id, enum PIOS_COM_Word_Length word_len, enum PIOS_COM_StopBits stop_bits, enum PIOS_COM_Parity parity, uint32_t baud_rate, enum PIOS_COM_Mode mode); +static void PIOS_USART_ChangeConfig(uint32_t usart_id, enum PIOS_COM_Word_Length word_len, enum PIOS_COM_Parity parity, enum PIOS_COM_StopBits stop_bits, uint32_t baud_rate); #endif static void PIOS_USART_RegisterRxCallback(uint32_t usart_id, pios_com_callback rx_in_cb, uint32_t context); static void PIOS_USART_RegisterTxCallback(uint32_t usart_id, pios_com_callback tx_out_cb, uint32_t context); @@ -186,15 +186,8 @@ int32_t PIOS_USART_Init(uint32_t *usart_id, const struct pios_usart_cfg *cfg) /* Initialize the comm parameter structure */ USART_StructInit(&usart_dev->init); // 9600 8n1 - /* Enable the USART Pins Software Remapping */ - if (usart_dev->cfg->remap) { - GPIO_PinAFConfig(cfg->rx.gpio, __builtin_ctz(cfg->rx.init.GPIO_Pin), cfg->remap); - GPIO_PinAFConfig(cfg->tx.gpio, __builtin_ctz(cfg->tx.init.GPIO_Pin), cfg->remap); - } - - /* Initialize the USART Rx and Tx pins */ - GPIO_Init(cfg->rx.gpio, (GPIO_InitTypeDef *)&cfg->rx.init); - GPIO_Init(cfg->tx.gpio, (GPIO_InitTypeDef *)&cfg->tx.init); + /* We will set modes later, depending on installed callbacks */ + usart_dev->init.USART_Mode = 0; /* Enable USART clock */ switch ((uint32_t)cfg->regs) { @@ -217,21 +210,51 @@ int32_t PIOS_USART_Init(uint32_t *usart_id, const struct pios_usart_cfg *cfg) #endif } - /* Configure the USART */ - USART_Init(cfg->regs, (USART_InitTypeDef *)&usart_dev->init); *usart_id = (uint32_t)usart_dev; PIOS_USART_SetIrqPrio(usart_dev, PIOS_IRQ_PRIO_MID); - USART_ITConfig(cfg->regs, USART_IT_RXNE, ENABLE); - USART_ITConfig(cfg->regs, USART_IT_TXE, ENABLE); - USART_ITConfig(cfg->regs, USART_IT_ORE, DISABLE); - USART_ITConfig(cfg->regs, USART_IT_TC, DISABLE); - /* Enable USART */ - USART_Cmd(cfg->regs, ENABLE); + + /* Disable overrun detection */ + USART_OverrunDetectionConfig(usart_dev->cfg->regs, USART_OVRDetection_Disable); return 0; } +static void PIOS_USART_Setup(struct pios_usart_dev *usart_dev) +{ + /* Configure RX GPIO */ + if ((usart_dev->init.USART_Mode & USART_Mode_Rx) && (usart_dev->cfg->rx.gpio)) { + if (usart_dev->cfg->remap) { + GPIO_PinAFConfig(usart_dev->cfg->rx.gpio, + __builtin_ctz(usart_dev->cfg->rx.init.GPIO_Pin), + usart_dev->cfg->remap); + } + + GPIO_Init(usart_dev->cfg->rx.gpio, (GPIO_InitTypeDef *)&usart_dev->cfg->rx.init); + + USART_ITConfig(usart_dev->cfg->regs, USART_IT_RXNE, ENABLE); + } + + /* Configure TX GPIO */ + if ((usart_dev->init.USART_Mode & USART_Mode_Tx) && usart_dev->cfg->tx.gpio) { + if (usart_dev->cfg->remap) { + GPIO_PinAFConfig(usart_dev->cfg->tx.gpio, + __builtin_ctz(usart_dev->cfg->tx.init.GPIO_Pin), + usart_dev->cfg->remap); + } + + GPIO_Init(usart_dev->cfg->tx.gpio, (GPIO_InitTypeDef *)&usart_dev->cfg->tx.init); + } + + /* Write new configuration */ + USART_Init(usart_dev->cfg->regs, &usart_dev->init); + + /* + * Re enable USART. + */ + USART_Cmd(usart_dev->cfg->regs, ENABLE); +} + static void PIOS_USART_RxStart(uint32_t usart_id, __attribute__((unused)) uint16_t rx_bytes_avail) { const struct pios_usart_dev *usart_dev = PIOS_USART_validate(usart_id); @@ -257,10 +280,7 @@ static void PIOS_USART_ChangeBaud(uint32_t usart_id, uint32_t baud) /* Use our working copy of the usart init structure */ usart_dev->init.USART_BaudRate = baud; - /* Write back the modified configuration */ - USART_Init(usart_dev->cfg->regs, &usart_dev->init); - - USART_Cmd(usart_dev->cfg->regs, ENABLE); + PIOS_USART_Setup(usart_dev); } #ifndef BOOTLOADER /** @@ -275,10 +295,9 @@ static void PIOS_USART_ChangeBaud(uint32_t usart_id, uint32_t baud) */ static void PIOS_USART_ChangeConfig(uint32_t usart_id, enum PIOS_COM_Word_Length word_len, - enum PIOS_COM_StopBits stop_bits, enum PIOS_COM_Parity parity, - uint32_t baud_rate, - enum PIOS_COM_Mode mode) + enum PIOS_COM_StopBits stop_bits, + uint32_t baud_rate) { struct pios_usart_dev *usart_dev = PIOS_USART_validate(usart_id); @@ -325,27 +344,7 @@ static void PIOS_USART_ChangeConfig(uint32_t usart_id, usart_dev->init.USART_BaudRate = baud_rate; } - switch (mode) { - case PIOS_COM_Mode_Rx: - usart_dev->init.USART_Mode = USART_Mode_Rx; - break; - case PIOS_COM_Mode_Tx: - usart_dev->init.USART_Mode = USART_Mode_Tx; - break; - case PIOS_COM_Mode_RxTx: - usart_dev->init.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; - break; - default: - break; - } - - /* Write back the modified configuration */ - USART_Init(usart_dev->cfg->regs, &usart_dev->init); - - /* - * Re enable USART. - */ - USART_Cmd(usart_dev->cfg->regs, ENABLE); + PIOS_USART_Setup(usart_dev); } #endif /* BOOTLOADER */ @@ -357,8 +356,12 @@ static void PIOS_USART_RegisterRxCallback(uint32_t usart_id, pios_com_callback r * Order is important in these assignments since ISR uses _cb * field to determine if it's ok to dereference _cb and _context */ - usart_dev->rx_in_context = context; + usart_dev->rx_in_context = context; usart_dev->rx_in_cb = rx_in_cb; + + usart_dev->init.USART_Mode |= USART_Mode_Rx; + + PIOS_USART_Setup(usart_dev); } static void PIOS_USART_RegisterTxCallback(uint32_t usart_id, pios_com_callback tx_out_cb, uint32_t context) @@ -369,8 +372,12 @@ static void PIOS_USART_RegisterTxCallback(uint32_t usart_id, pios_com_callback t * Order is important in these assignments since ISR uses _cb * field to determine if it's ok to dereference _cb and _context */ - usart_dev->tx_out_context = context; + usart_dev->tx_out_context = context; usart_dev->tx_out_cb = tx_out_cb; + + usart_dev->init.USART_Mode |= USART_Mode_Tx; + + PIOS_USART_Setup(usart_dev); } static void PIOS_USART_generic_irq_handler(uint32_t usart_id) diff --git a/flight/pios/stm32f10x/pios_usart.c b/flight/pios/stm32f10x/pios_usart.c index cc2d13fc0f..cc1e232323 100644 --- a/flight/pios/stm32f10x/pios_usart.c +++ b/flight/pios/stm32f10x/pios_usart.c @@ -37,7 +37,7 @@ #include /* Provide a COM driver */ -static void PIOS_USART_ChangeConfig(uint32_t usart_id, enum PIOS_COM_Word_Length word_len, enum PIOS_COM_StopBits stop_bits, enum PIOS_COM_Parity parity, uint32_t baud_rate, enum PIOS_COM_Mode mode); +static void PIOS_USART_ChangeConfig(uint32_t usart_id, enum PIOS_COM_Word_Length word_len, enum PIOS_COM_Parity parity, enum PIOS_COM_StopBits stop_bits, uint32_t baud_rate); static void PIOS_USART_ChangeBaud(uint32_t usart_id, uint32_t baud); static void PIOS_USART_RegisterRxCallback(uint32_t usart_id, pios_com_callback rx_in_cb, uint32_t context); static void PIOS_USART_RegisterTxCallback(uint32_t usart_id, pios_com_callback tx_out_cb, uint32_t context); @@ -185,17 +185,10 @@ int32_t PIOS_USART_Init(uint32_t *usart_id, const struct pios_usart_cfg *cfg) /* Initialize the comm parameter structure */ USART_StructInit(&usart_dev->init); // 9600 8n1 - /* Enable the USART Pins Software Remapping */ - if (usart_dev->cfg->remap) { - GPIO_PinRemapConfig(usart_dev->cfg->remap, ENABLE); - } - - /* Initialize the USART Rx and Tx pins */ - GPIO_Init(usart_dev->cfg->rx.gpio, &usart_dev->cfg->rx.init); - GPIO_Init(usart_dev->cfg->tx.gpio, &usart_dev->cfg->tx.init); + /* We will set modes later, depending on installed callbacks */ + usart_dev->init.USART_Mode = 0; - /* Configure the USART */ - USART_Init(usart_dev->cfg->regs, &usart_dev->init); + /* DTR handling? */ *usart_id = (uint32_t)usart_dev; @@ -217,18 +210,44 @@ int32_t PIOS_USART_Init(uint32_t *usart_id, const struct pios_usart_cfg *cfg) PIOS_USART_SetIrqPrio(usart_dev, PIOS_IRQ_PRIO_MID); - USART_ITConfig(usart_dev->cfg->regs, USART_IT_RXNE, ENABLE); - USART_ITConfig(usart_dev->cfg->regs, USART_IT_TXE, ENABLE); - - /* Enable USART */ - USART_Cmd(usart_dev->cfg->regs, ENABLE); - return 0; out_fail: return -1; } +static void PIOS_USART_Setup(struct pios_usart_dev *usart_dev) +{ + /* Configure RX GPIO */ + if ((usart_dev->init.USART_Mode & USART_Mode_Rx) && (usart_dev->cfg->rx.gpio)) { + if (usart_dev->cfg->remap) { + GPIO_PinRemapConfig(usart_dev->cfg->remap, ENABLE); + } + + GPIO_Init(usart_dev->cfg->rx.gpio, (GPIO_InitTypeDef *)&usart_dev->cfg->rx.init); + + USART_ITConfig(usart_dev->cfg->regs, USART_IT_RXNE, ENABLE); + } + + /* Configure TX GPIO */ + if ((usart_dev->init.USART_Mode & USART_Mode_Tx) && usart_dev->cfg->tx.gpio) { + if (usart_dev->cfg->remap) { + GPIO_PinRemapConfig(usart_dev->cfg->remap, ENABLE); + } + + GPIO_Init(usart_dev->cfg->tx.gpio, (GPIO_InitTypeDef *)&usart_dev->cfg->tx.init); + } + + /* Write new configuration */ + USART_Init(usart_dev->cfg->regs, &usart_dev->init); + + /* + * Re enable USART. + */ + USART_Cmd(usart_dev->cfg->regs, ENABLE); +} + + static void PIOS_USART_RxStart(uint32_t usart_id, __attribute__((unused)) uint16_t rx_bytes_avail) { struct pios_usart_dev *usart_dev = (struct pios_usart_dev *)usart_id; @@ -266,8 +285,7 @@ static void PIOS_USART_ChangeBaud(uint32_t usart_id, uint32_t baud) /* Use our working copy of the usart init structure */ usart_dev->init.USART_BaudRate = baud; - /* Write back the modified configuration */ - USART_Init(usart_dev->cfg->regs, &usart_dev->init); + PIOS_USART_Setup(usart_dev); } /** @@ -282,10 +300,9 @@ static void PIOS_USART_ChangeBaud(uint32_t usart_id, uint32_t baud) */ static void PIOS_USART_ChangeConfig(uint32_t usart_id, enum PIOS_COM_Word_Length word_len, - enum PIOS_COM_StopBits stop_bits, enum PIOS_COM_Parity parity, - uint32_t baud_rate, - enum PIOS_COM_Mode mode) + enum PIOS_COM_StopBits stop_bits, + uint32_t baud_rate) { struct pios_usart_dev *usart_dev = (struct pios_usart_dev *)usart_id; @@ -339,27 +356,7 @@ static void PIOS_USART_ChangeConfig(uint32_t usart_id, usart_dev->init.USART_BaudRate = baud_rate; } - switch (mode) { - case PIOS_COM_Mode_Rx: - usart_dev->init.USART_Mode = USART_Mode_Rx; - break; - case PIOS_COM_Mode_Tx: - usart_dev->init.USART_Mode = USART_Mode_Tx; - break; - case PIOS_COM_Mode_RxTx: - usart_dev->init.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; - break; - default: - break; - } - - /* Write back the modified configuration */ - USART_Init(usart_dev->cfg->regs, &usart_dev->init); - - /* - * Re enable USART. - */ - USART_Cmd(usart_dev->cfg->regs, ENABLE); + PIOS_USART_Setup(usart_dev); } static void PIOS_USART_RegisterRxCallback(uint32_t usart_id, pios_com_callback rx_in_cb, uint32_t context) @@ -374,8 +371,12 @@ static void PIOS_USART_RegisterRxCallback(uint32_t usart_id, pios_com_callback r * Order is important in these assignments since ISR uses _cb * field to determine if it's ok to dereference _cb and _context */ - usart_dev->rx_in_context = context; + usart_dev->rx_in_context = context; usart_dev->rx_in_cb = rx_in_cb; + + usart_dev->init.USART_Mode |= USART_Mode_Rx; + + PIOS_USART_Setup(usart_dev); } static void PIOS_USART_RegisterTxCallback(uint32_t usart_id, pios_com_callback tx_out_cb, uint32_t context) @@ -390,8 +391,12 @@ static void PIOS_USART_RegisterTxCallback(uint32_t usart_id, pios_com_callback t * Order is important in these assignments since ISR uses _cb * field to determine if it's ok to dereference _cb and _context */ - usart_dev->tx_out_context = context; + usart_dev->tx_out_context = context; usart_dev->tx_out_cb = tx_out_cb; + + usart_dev->init.USART_Mode |= USART_Mode_Tx; + + PIOS_USART_Setup(usart_dev); } static void PIOS_USART_generic_irq_handler(uint32_t usart_id) @@ -467,6 +472,9 @@ static int32_t PIOS_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param) case PIOS_IOCTL_USART_GET_TXGPIO: *(struct stm32_gpio *)param = usart_dev->cfg->tx; break; + case PIOS_IOCTL_USART_SET_HALFDUPLEX: + USART_HalfDuplexCmd(usart_dev->cfg->regs, *(bool *)param ? ENABLE : DISABLE); + break; default: if (usart_dev->cfg->ioctl) { return usart_dev->cfg->ioctl(usart_id, ctl, param); diff --git a/flight/pios/stm32f4xx/pios_usart.c b/flight/pios/stm32f4xx/pios_usart.c index 7b9f936495..3731bb6580 100644 --- a/flight/pios/stm32f4xx/pios_usart.c +++ b/flight/pios/stm32f4xx/pios_usart.c @@ -41,8 +41,7 @@ /* Provide a COM driver */ static void PIOS_USART_ChangeBaud(uint32_t usart_id, uint32_t baud); -static void PIOS_USART_SetHalfDuplex(uint32_t usart_id, bool halfduplex); -static void PIOS_USART_ChangeConfig(uint32_t usart_id, enum PIOS_COM_Word_Length word_len, enum PIOS_COM_StopBits stop_bits, enum PIOS_COM_Parity parity, uint32_t baud_rate, enum PIOS_COM_Mode mode); +static void PIOS_USART_ChangeConfig(uint32_t usart_id, enum PIOS_COM_Word_Length word_len, enum PIOS_COM_Parity parity, enum PIOS_COM_StopBits stop_bits, uint32_t baud_rate); static void PIOS_USART_SetCtrlLine(uint32_t usart_id, uint32_t mask, uint32_t state); static void PIOS_USART_RegisterRxCallback(uint32_t usart_id, pios_com_callback rx_in_cb, uint32_t context); static void PIOS_USART_RegisterTxCallback(uint32_t usart_id, pios_com_callback tx_out_cb, uint32_t context); @@ -51,15 +50,14 @@ static void PIOS_USART_RxStart(uint32_t usart_id, uint16_t rx_bytes_avail); static int32_t PIOS_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param); const struct pios_com_driver pios_usart_com_driver = { - .set_baud = PIOS_USART_ChangeBaud, - .set_halfduplex = PIOS_USART_SetHalfDuplex, - .set_config = PIOS_USART_ChangeConfig, - .set_ctrl_line = PIOS_USART_SetCtrlLine, - .tx_start = PIOS_USART_TxStart, - .rx_start = PIOS_USART_RxStart, - .bind_tx_cb = PIOS_USART_RegisterTxCallback, - .bind_rx_cb = PIOS_USART_RegisterRxCallback, - .ioctl = PIOS_USART_Ioctl, + .set_baud = PIOS_USART_ChangeBaud, + .set_config = PIOS_USART_ChangeConfig, + .set_ctrl_line = PIOS_USART_SetCtrlLine, + .tx_start = PIOS_USART_TxStart, + .rx_start = PIOS_USART_RxStart, + .bind_tx_cb = PIOS_USART_RegisterTxCallback, + .bind_rx_cb = PIOS_USART_RegisterRxCallback, + .ioctl = PIOS_USART_Ioctl, }; enum pios_usart_dev_magic { @@ -211,20 +209,9 @@ int32_t PIOS_USART_Init(uint32_t *usart_id, const struct pios_usart_cfg *cfg) /* Initialize the comm parameter structure */ USART_StructInit(&usart_dev->init); // 9600 8n1 - /* Map pins to USART function */ - /* note __builtin_ctz() due to the difference between GPIO_PinX and GPIO_PinSourceX */ - if (usart_dev->cfg->remap) { - GPIO_PinAFConfig(usart_dev->cfg->rx.gpio, - __builtin_ctz(usart_dev->cfg->rx.init.GPIO_Pin), - usart_dev->cfg->remap); - GPIO_PinAFConfig(usart_dev->cfg->tx.gpio, - __builtin_ctz(usart_dev->cfg->tx.init.GPIO_Pin), - usart_dev->cfg->remap); - } + /* We will set modes later, depending on installed callbacks */ + usart_dev->init.USART_Mode = 0; - /* Initialize the USART Rx and Tx pins */ - GPIO_Init(usart_dev->cfg->rx.gpio, (GPIO_InitTypeDef *)&usart_dev->cfg->rx.init); - GPIO_Init(usart_dev->cfg->tx.gpio, (GPIO_InitTypeDef *)&usart_dev->cfg->tx.init); /* If a DTR line is specified, initialize it */ if (usart_dev->cfg->dtr.gpio) { @@ -232,9 +219,6 @@ int32_t PIOS_USART_Init(uint32_t *usart_id, const struct pios_usart_cfg *cfg) PIOS_USART_SetCtrlLine((uint32_t)usart_dev, COM_CTRL_LINE_DTR_MASK, 0); } - /* Configure the USART */ - USART_Init(usart_dev->cfg->regs, (USART_InitTypeDef *)&usart_dev->init); - *usart_id = (uint32_t)usart_dev; /* Configure USART Interrupts */ @@ -267,13 +251,6 @@ int32_t PIOS_USART_Init(uint32_t *usart_id, const struct pios_usart_cfg *cfg) break; } PIOS_USART_SetIrqPrio(usart_dev, PIOS_IRQ_PRIO_MID); - USART_ITConfig(usart_dev->cfg->regs, USART_IT_RXNE, ENABLE); - USART_ITConfig(usart_dev->cfg->regs, USART_IT_TXE, ENABLE); - - // FIXME XXX Clear / reset uart here - sends NUL char else - - /* Enable USART */ - USART_Cmd(usart_dev->cfg->regs, ENABLE); return 0; @@ -281,6 +258,42 @@ int32_t PIOS_USART_Init(uint32_t *usart_id, const struct pios_usart_cfg *cfg) return -1; } +static void PIOS_USART_Setup(struct pios_usart_dev *usart_dev) +{ + /* Configure RX GPIO */ + if ((usart_dev->init.USART_Mode & USART_Mode_Rx) && (usart_dev->cfg->rx.gpio)) { + if (usart_dev->cfg->remap) { + GPIO_PinAFConfig(usart_dev->cfg->rx.gpio, + __builtin_ctz(usart_dev->cfg->rx.init.GPIO_Pin), + usart_dev->cfg->remap); + } + + GPIO_Init(usart_dev->cfg->rx.gpio, (GPIO_InitTypeDef *)&usart_dev->cfg->rx.init); + + /* just enable RX right away, cause rcvr modules do not call rx_start method */ + USART_ITConfig(usart_dev->cfg->regs, USART_IT_RXNE, ENABLE); + } + + /* Configure TX GPIO */ + if ((usart_dev->init.USART_Mode & USART_Mode_Tx) && usart_dev->cfg->tx.gpio) { + if (usart_dev->cfg->remap) { + GPIO_PinAFConfig(usart_dev->cfg->tx.gpio, + __builtin_ctz(usart_dev->cfg->tx.init.GPIO_Pin), + usart_dev->cfg->remap); + } + + GPIO_Init(usart_dev->cfg->tx.gpio, (GPIO_InitTypeDef *)&usart_dev->cfg->tx.init); + } + + /* Write new configuration */ + USART_Init(usart_dev->cfg->regs, &usart_dev->init); + + /* + * Re enable USART. + */ + USART_Cmd(usart_dev->cfg->regs, ENABLE); +} + static void PIOS_USART_RxStart(uint32_t usart_id, __attribute__((unused)) uint16_t rx_bytes_avail) { struct pios_usart_dev *usart_dev = (struct pios_usart_dev *)usart_id; @@ -319,24 +332,7 @@ static void PIOS_USART_ChangeBaud(uint32_t usart_id, uint32_t baud) /* Use our working copy of the usart init structure */ usart_dev->init.USART_BaudRate = baud; - /* Write back the modified configuration */ - USART_Init(usart_dev->cfg->regs, &usart_dev->init); -} - -/** - * Sets the USART peripheral into half duplex mode - * \param[in] usart_id USART name (GPS, TELEM, AUX) - * \param[in] bool wether to set half duplex or not - */ -static void PIOS_USART_SetHalfDuplex(uint32_t usart_id, bool halfduplex) -{ - struct pios_usart_dev *usart_dev = (struct pios_usart_dev *)usart_id; - - bool valid = PIOS_USART_validate(usart_dev); - - PIOS_Assert(valid); - - USART_HalfDuplexCmd(usart_dev->cfg->regs, halfduplex ? ENABLE : DISABLE); + PIOS_USART_Setup(usart_dev); } /** @@ -351,10 +347,9 @@ static void PIOS_USART_SetHalfDuplex(uint32_t usart_id, bool halfduplex) */ static void PIOS_USART_ChangeConfig(uint32_t usart_id, enum PIOS_COM_Word_Length word_len, - enum PIOS_COM_StopBits stop_bits, enum PIOS_COM_Parity parity, - uint32_t baud_rate, - enum PIOS_COM_Mode mode) + enum PIOS_COM_StopBits stop_bits, + uint32_t baud_rate) { struct pios_usart_dev *usart_dev = (struct pios_usart_dev *)usart_id; @@ -408,27 +403,7 @@ static void PIOS_USART_ChangeConfig(uint32_t usart_id, usart_dev->init.USART_BaudRate = baud_rate; } - switch (mode) { - case PIOS_COM_Mode_Rx: - usart_dev->init.USART_Mode = USART_Mode_Rx; - break; - case PIOS_COM_Mode_Tx: - usart_dev->init.USART_Mode = USART_Mode_Tx; - break; - case PIOS_COM_Mode_RxTx: - usart_dev->init.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; - break; - default: - break; - } - - /* Write back the modified configuration */ - USART_Init(usart_dev->cfg->regs, &usart_dev->init); - - /* - * Re enable USART. - */ - USART_Cmd(usart_dev->cfg->regs, ENABLE); + PIOS_USART_Setup(usart_dev); } static void PIOS_USART_SetCtrlLine(uint32_t usart_id, uint32_t mask, uint32_t state) @@ -459,8 +434,12 @@ static void PIOS_USART_RegisterRxCallback(uint32_t usart_id, pios_com_callback r * Order is important in these assignments since ISR uses _cb * field to determine if it's ok to dereference _cb and _context */ - usart_dev->rx_in_context = context; + usart_dev->rx_in_context = context; usart_dev->rx_in_cb = rx_in_cb; + + usart_dev->init.USART_Mode |= USART_Mode_Rx; + + PIOS_USART_Setup(usart_dev); } static void PIOS_USART_RegisterTxCallback(uint32_t usart_id, pios_com_callback tx_out_cb, uint32_t context) @@ -475,8 +454,12 @@ static void PIOS_USART_RegisterTxCallback(uint32_t usart_id, pios_com_callback t * Order is important in these assignments since ISR uses _cb * field to determine if it's ok to dereference _cb and _context */ - usart_dev->tx_out_context = context; + usart_dev->tx_out_context = context; usart_dev->tx_out_cb = tx_out_cb; + + usart_dev->init.USART_Mode |= USART_Mode_Tx; + + PIOS_USART_Setup(usart_dev); } static void PIOS_USART_generic_irq_handler(uint32_t usart_id) @@ -547,6 +530,9 @@ static int32_t PIOS_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param) case PIOS_IOCTL_USART_GET_TXGPIO: *(struct stm32_gpio *)param = usart_dev->cfg->tx; break; + case PIOS_IOCTL_USART_SET_HALFDUPLEX: + USART_HalfDuplexCmd(usart_dev->cfg->regs, *(bool *)param ? ENABLE : DISABLE); + break; default: if (usart_dev->cfg->ioctl) { return usart_dev->cfg->ioctl(usart_id, ctl, param); diff --git a/flight/targets/boards/simposix/firmware/inc/pios_config.h b/flight/targets/boards/simposix/firmware/inc/pios_config.h index 36f84be851..8e29dc590f 100644 --- a/flight/targets/boards/simposix/firmware/inc/pios_config.h +++ b/flight/targets/boards/simposix/firmware/inc/pios_config.h @@ -52,7 +52,7 @@ #define PIOS_INCLUDE_SPI #define PIOS_INCLUDE_SYS #define PIOS_INCLUDE_TASK_MONITOR -//#define PIOS_INCLUDE_USART +// #define PIOS_INCLUDE_USART // #define PIOS_INCLUDE_USB #define PIOS_INCLUDE_USB_HID // #define PIOS_INCLUDE_GPIO @@ -87,8 +87,8 @@ #define PIOS_INCLUDE_RCVR #define PIOS_INCLUDE_DSM // #define PIOS_INCLUDE_SBUS -//#define PIOS_INCLUDE_PPM -//#define PIOS_INCLUDE_PWM +// #define PIOS_INCLUDE_PPM +// #define PIOS_INCLUDE_PWM /* #define PIOS_INCLUDE_GCSRCVR */ /* #define PIOS_INCLUDE_OPLINKRCVR */ #define PIOS_INCLUDE_IAP From bb68ed2c5a88e65a5fb9ad60a4eb009ae55f90fb Mon Sep 17 00:00:00 2001 From: Vladimir Zidar Date: Fri, 21 Apr 2017 12:01:42 +0200 Subject: [PATCH 227/624] LP-480 RevoNano USART2 sbus baud rate workaround --- flight/pios/common/pios_sbus.c | 6 +++++- flight/targets/boards/revonano/pios_board.h | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/flight/pios/common/pios_sbus.c b/flight/pios/common/pios_sbus.c index f7cd3f4750..e424aa8f6e 100644 --- a/flight/pios/common/pios_sbus.c +++ b/flight/pios/common/pios_sbus.c @@ -35,6 +35,10 @@ // Define to report number of frames since last dropped instead of weighted ave #undef SBUS_GOOD_FRAME_COUNT +#ifndef PIOS_SBUS_BAUD_RATE +#define PIOS_SBUS_BAUD_RATE 100000 +#endif + #include #include "pios_sbus_priv.h" @@ -168,7 +172,7 @@ int32_t PIOS_SBus_Init(uint32_t *sbus_id, /* Set rest of the parameters */ if (driver->set_config) { - driver->set_config(lower_id, PIOS_COM_Word_length_8b, PIOS_COM_Parity_Even, PIOS_COM_StopBits_2, 100000); + driver->set_config(lower_id, PIOS_COM_Word_length_8b, PIOS_COM_Parity_Even, PIOS_COM_StopBits_2, PIOS_SBUS_BAUD_RATE); } /* Set inverted UART and IRQ priority */ diff --git a/flight/targets/boards/revonano/pios_board.h b/flight/targets/boards/revonano/pios_board.h index 79a884a02e..f6bcc20f23 100644 --- a/flight/targets/boards/revonano/pios_board.h +++ b/flight/targets/boards/revonano/pios_board.h @@ -233,7 +233,7 @@ extern uint32_t pios_packet_handler; // ------------------------- #define PIOS_SBUS_MAX_DEVS 1 #define PIOS_SBUS_NUM_INPUTS (16 + 2) - +#define PIOS_SBUS_BAUD_RATE 99999 /* f411 / 96mhz sysclk / usart2 baud rate weirdness */ // ------------------------- // Receiver HOTT input // ------------------------- From 3d876d703572b5a0c6d20418f15cee0eb2c00f84 Mon Sep 17 00:00:00 2001 From: Vladimir Zidar Date: Mon, 24 Apr 2017 16:10:18 +0200 Subject: [PATCH 228/624] LP-480 Removed RadioAuxStream function from PIOS_BOARD_IO_Configure_RFM22B(), added another function to configure radioaux from hwsettings (revo & sparky2 only). --- .../OpenPilotOSX.xcodeproj/project.pbxproj | 2 +- .../modules/RadioComBridge/RadioComBridge.c | 4 +- flight/pios/common/pios_board_io.c | 106 ++++---- flight/pios/common/pios_rfm22b.c | 4 +- flight/pios/inc/pios_board_io.h | 46 ++-- .../coptercontrol/firmware/pios_board.c | 12 +- .../discoveryf4bare/firmware/pios_board.c | 20 +- .../boards/oplinkmini/firmware/pios_board.c | 229 ++---------------- flight/targets/boards/oplinkmini/pios_board.h | 10 +- .../boards/revolution/firmware/pios_board.c | 21 +- .../boards/revonano/firmware/pios_board.c | 6 +- .../boards/revoproto/firmware/pios_board.c | 6 +- .../boards/sparky2/firmware/pios_board.c | 16 +- 13 files changed, 142 insertions(+), 340 deletions(-) diff --git a/flight/Project/OpenPilotOSX/OpenPilotOSX.xcodeproj/project.pbxproj b/flight/Project/OpenPilotOSX/OpenPilotOSX.xcodeproj/project.pbxproj index d2a27e5745..f4baa02916 100644 --- a/flight/Project/OpenPilotOSX/OpenPilotOSX.xcodeproj/project.pbxproj +++ b/flight/Project/OpenPilotOSX/OpenPilotOSX.xcodeproj/project.pbxproj @@ -184,7 +184,7 @@ /* Begin PBXLegacyTarget section */ 6581071511DE809D0049FB12 /* OpenPilotOSX */ = { isa = PBXLegacyTarget; - buildArgumentsString = ef_osd; + buildArgumentsString = ef_oplinkmini; buildConfigurationList = 6581071A11DE80A30049FB12 /* Build configuration list for PBXLegacyTarget "OpenPilotOSX" */; buildPhases = ( ); diff --git a/flight/modules/RadioComBridge/RadioComBridge.c b/flight/modules/RadioComBridge/RadioComBridge.c index 8353906551..0ffa41bc85 100644 --- a/flight/modules/RadioComBridge/RadioComBridge.c +++ b/flight/modules/RadioComBridge/RadioComBridge.c @@ -41,8 +41,9 @@ #include #include #include - +#include #include +#include // **************** // Private constants @@ -57,6 +58,7 @@ #define SERIAL_RX_BUF_LEN 100 #define PPM_INPUT_TIMEOUT 100 +#define PIOS_PPM_RECEIVER pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_PPM] // **************** // Private types diff --git a/flight/pios/common/pios_board_io.c b/flight/pios/common/pios_board_io.c index e43b3053c5..025b4cec05 100644 --- a/flight/pios/common/pios_board_io.c +++ b/flight/pios/common/pios_board_io.c @@ -84,7 +84,8 @@ uint32_t pios_com_telem_rf_id; /* Serial port telemetry */ #ifdef PIOS_INCLUDE_RFM22B uint32_t pios_rfm22b_id; /* RFM22B handle */ -uint32_t pios_com_rf_id; /* RFM22B telemetry */ +uint32_t pios_com_pri_radio_id; /* oplink primary com stream */ +uint32_t pios_com_aux_radio_id; /* oplink aux com stream */ #endif #ifdef PIOS_INCLUDE_OPENLRS @@ -402,6 +403,24 @@ static const struct uart_function uart_function_map[] = { #endif /* PIOS_INCLUDE_RCVR */ }; +void PIOS_BOARD_IO_Configure_UART_COM(const struct pios_usart_cfg *hw_config, + uint16_t rx_buf_len, + uint16_t tx_buf_len, + uint32_t *com_id) +{ + uint32_t usart_id; + + if (PIOS_USART_Init(&usart_id, hw_config)) { + PIOS_Assert(0); + } + + if (PIOS_COM_Init(com_id, &pios_usart_com_driver, usart_id, + 0, rx_buf_len, + 0, tx_buf_len)) { + PIOS_Assert(0); + } +} + void PIOS_BOARD_IO_Configure_UART(const struct pios_usart_cfg *hw_config, PIOS_BOARD_IO_UART_Function function) { if (function >= NELEMENTS(uart_function_map)) { @@ -409,17 +428,10 @@ void PIOS_BOARD_IO_Configure_UART(const struct pios_usart_cfg *hw_config, PIOS_B } if (uart_function_map[function].com_id) { - uint32_t usart_id; - - if (PIOS_USART_Init(&usart_id, hw_config)) { - PIOS_Assert(0); - } - - if (PIOS_COM_Init(uart_function_map[function].com_id, &pios_usart_com_driver, usart_id, - 0, uart_function_map[function].com_rx_buf_len, - 0, uart_function_map[function].com_tx_buf_len)) { - PIOS_Assert(0); - } + PIOS_BOARD_IO_Configure_UART_COM(hw_config, + uart_function_map[function].com_rx_buf_len, + uart_function_map[function].com_tx_buf_len, + uart_function_map[function].com_id); } #ifdef PIOS_INCLUDE_RCVR else if (uart_function_map[function].rcvr_init) { @@ -446,7 +458,7 @@ void PIOS_BOARD_IO_Configure_UART(const struct pios_usart_cfg *hw_config, PIOS_B } #ifdef PIOS_INCLUDE_PWM -void PIOS_BOARD_IO_Configure_PWM(const struct pios_pwm_cfg *pwm_cfg) +void PIOS_BOARD_IO_Configure_PWM_RCVR(const struct pios_pwm_cfg *pwm_cfg) { /* Set up the receiver port. Later this should be optional */ uint32_t pios_pwm_id; @@ -462,7 +474,7 @@ void PIOS_BOARD_IO_Configure_PWM(const struct pios_pwm_cfg *pwm_cfg) #endif /* PIOS_INCLUDE_PWM */ #ifdef PIOS_INCLUDE_PPM -void PIOS_BOARD_IO_Configure_PPM(const struct pios_ppm_cfg *ppm_cfg) +void PIOS_BOARD_IO_Configure_PPM_RCVR(const struct pios_ppm_cfg *ppm_cfg) { uint32_t pios_ppm_id; @@ -477,7 +489,7 @@ void PIOS_BOARD_IO_Configure_PPM(const struct pios_ppm_cfg *ppm_cfg) #endif /* PIOS_INCLUDE_PPM */ #ifdef PIOS_INCLUDE_GCSRCVR -void PIOS_BOARD_IO_Configure_GCSRCVR() +void PIOS_BOARD_IO_Configure_GCS_RCVR() { GCSReceiverInitialize(); uint32_t pios_gcsrcvr_id; @@ -492,7 +504,7 @@ void PIOS_BOARD_IO_Configure_GCSRCVR() #ifdef PIOS_INCLUDE_RFM22B -void PIOS_BOARD_IO_Configure_RFM22B(PIOS_BOARD_IO_RADIOAUX_Function radioaux_function) +void PIOS_BOARD_IO_Configure_RFM22B() { #if defined(PIOS_INCLUDE_RFM22B) OPLinkSettingsInitialize(); @@ -558,9 +570,16 @@ void PIOS_BOARD_IO_Configure_RFM22B(PIOS_BOARD_IO_RADIOAUX_Function radioaux_fun #endif /* PIOS_INCLUDE_OPLINKRCVR && PIOS_INCLUDE_RCVR */ /* Configure the radio com interface */ - if (PIOS_COM_Init(&pios_com_rf_id, &pios_rfm22b_com_driver, pios_rfm22b_id, - 0, PIOS_COM_RFM22B_RF_RX_BUF_LEN, - 0, PIOS_COM_RFM22B_RF_TX_BUF_LEN)) { + if (PIOS_COM_Init(&pios_com_pri_radio_id, &pios_rfm22b_com_driver, pios_rfm22b_id, + 0, PIOS_COM_PRI_RADIO_RX_BUF_LEN, + 0, PIOS_COM_PRI_RADIO_TX_BUF_LEN)) { + PIOS_Assert(0); + } + + // Initialize the aux radio com interface + if (PIOS_COM_Init(&pios_com_aux_radio_id, &pios_rfm22b_aux_com_driver, pios_rfm22b_id, + 0, PIOS_COM_AUX_RADIO_RX_BUF_LEN, + 0, PIOS_COM_AUX_RADIO_TX_BUF_LEN)) { PIOS_Assert(0); } @@ -637,35 +656,6 @@ void PIOS_BOARD_IO_Configure_RFM22B(PIOS_BOARD_IO_RADIOAUX_Function radioaux_fun /* Reinitialize the modem. */ PIOS_RFM22B_Reinit(pios_rfm22b_id); - - // TODO: this is in preparation for full mavlink support and is used by LP-368 - uint16_t mavlink_rx_size = PIOS_COM_MAVLINK_RX_BUF_LEN; - - switch (radioaux_function) { - default:; - case PIOS_BOARD_IO_RADIOAUX_DEBUGCONSOLE: -#ifdef PIOS_INCLUDE_DEBUG_CONSOLE - if (PIOS_COM_Init(&pios_com_debug_id, &pios_rfm22b_aux_com_driver, pios_rfm22b_id, - 0, 0, - 0, PIOS_COM_DEBUGCONSOLE_TX_BUF_LEN)) { - PIOS_Assert(0); - } -#endif - break; - case PIOS_BOARD_IO_RADIOAUX_COMBRIDGE: - if (PIOS_COM_Init(&pios_com_bridge_id, &pios_rfm22b_aux_com_driver, pios_rfm22b_id, - 0, PIOS_COM_BRIDGE_RX_BUF_LEN, - 0, PIOS_COM_BRIDGE_TX_BUF_LEN)) { - PIOS_Assert(0); - } - break; - case PIOS_BOARD_IO_RADIOAUX_MAVLINK: - if (PIOS_COM_Init(&pios_com_mavlink_id, &pios_rfm22b_aux_com_driver, pios_rfm22b_id, - 0, mavlink_rx_size, - 0, PIOS_COM_BRIDGE_TX_BUF_LEN)) { - PIOS_Assert(0); - } - } } } else { oplinkStatus.LinkState = OPLINKSTATUS_LINKSTATE_DISABLED; @@ -673,4 +663,24 @@ void PIOS_BOARD_IO_Configure_RFM22B(PIOS_BOARD_IO_RADIOAUX_Function radioaux_fun OPLinkStatusSet(&oplinkStatus); } + + +void PIOS_BOARD_IO_Configure_RadioAuxStream(HwSettingsRadioAuxStreamOptions radioaux) +{ + switch (radioaux) { + case HWSETTINGS_RADIOAUXSTREAM_DEBUGCONSOLE: +#ifdef PIOS_INCLUDE_DEBUG_CONSOLE + pios_com_debug_id = pios_com_aux_radio_id; +#endif + break; + case HWSETTINGS_RADIOAUXSTREAM_MAVLINK: + pios_com_mavlink_id = pios_com_aux_radio_id; + break; + case HWSETTINGS_RADIOAUXSTREAM_COMBRIDGE: + pios_com_bridge_id = pios_com_aux_radio_id; + break; + case HWSETTINGS_RADIOAUXSTREAM_DISABLED: + break; + } +} #endif /* ifdef PIOS_INCLUDE_RFM22B */ diff --git a/flight/pios/common/pios_rfm22b.c b/flight/pios/common/pios_rfm22b.c index 7fa05e07b2..0579c99a97 100644 --- a/flight/pios/common/pios_rfm22b.c +++ b/flight/pios/common/pios_rfm22b.c @@ -783,8 +783,8 @@ bool PIOS_RFM22B_TransmitPacket(uint32_t rfm22b_id, uint8_t *p, uint8_t len) return false; } - rfm22b_dev->tx_packet_handle = p; - rfm22b_dev->packet_start_time = pios_rfm22_time_ms(); + rfm22b_dev->tx_packet_handle = p; + rfm22b_dev->packet_start_time = pios_rfm22_time_ms(); if (rfm22b_dev->packet_start_time == 0) { rfm22b_dev->packet_start_time = 1; } diff --git a/flight/pios/inc/pios_board_io.h b/flight/pios/inc/pios_board_io.h index cf0533b023..34e01704e3 100644 --- a/flight/pios/inc/pios_board_io.h +++ b/flight/pios/inc/pios_board_io.h @@ -91,22 +91,31 @@ extern uint32_t pios_com_telem_usb_id; extern uint32_t pios_com_telem_rf_id; #define PIOS_COM_TELEM_RF (pios_com_telem_rf_id) #ifndef PIOS_COM_TELEM_RF_RX_BUF_LEN -# define PIOS_COM_TELEM_RF_RX_BUF_LEN 512 +# define PIOS_COM_TELEM_RF_RX_BUF_LEN 128 #endif #ifndef PIOS_COM_TELEM_RF_TX_BUF_LEN -# define PIOS_COM_TELEM_RF_TX_BUF_LEN 512 +# define PIOS_COM_TELEM_RF_TX_BUF_LEN 128 #endif /* RFM22B telemetry */ #ifdef PIOS_INCLUDE_RFM22B extern uint32_t pios_rfm22b_id; /* RFM22B handle */ -extern uint32_t pios_com_rf_id; /* oplink telemetry */ -# define PIOS_COM_RF (pios_com_rf_id) -# ifndef PIOS_COM_RFM22B_RF_RX_BUF_LEN -# define PIOS_COM_RFM22B_RF_RX_BUF_LEN 512 +extern uint32_t pios_com_pri_radio_id; /* oplink primary com stream */ +extern uint32_t pios_com_aux_radio_id; /* oplink aux com stream */ +# define PIOS_COM_RF (pios_com_pri_radio_id) +# define PIOS_COM_PRI_RADIO (pios_com_pri_radio_id) +# define PIOS_COM_AUX_RADIO (pios_com_aux_radio_id) +# ifndef PIOS_COM_PRI_RADIO_RX_BUF_LEN +# define PIOS_COM_PRI_RADIO_RX_BUF_LEN 128 # endif -# ifndef PIOS_COM_RFM22B_RF_TX_BUF_LEN -# define PIOS_COM_RFM22B_RF_TX_BUF_LEN 512 +# ifndef PIOS_COM_PRI_RADIO_TX_BUF_LEN +# define PIOS_COM_PRI_RADIO_TX_BUF_LEN 128 +# endif +# ifndef PIOS_COM_AUX_RADIO_RX_BUF_LEN +# define PIOS_COM_AUX_RADIO_RX_BUF_LEN 128 +# endif +# ifndef PIOS_COM_AUX_RADIO_TX_BUF_LEN +# define PIOS_COM_AUX_RADIO_TX_BUF_LEN 128 # endif #endif @@ -201,13 +210,6 @@ typedef enum { PIOS_BOARD_IO_UART_HOTT_BRIDGE, /* com */ } PIOS_BOARD_IO_UART_Function; -typedef enum { - PIOS_BOARD_IO_RADIOAUX_NONE = 0, - PIOS_BOARD_IO_RADIOAUX_MAVLINK, - PIOS_BOARD_IO_RADIOAUX_COMBRIDGE, - PIOS_BOARD_IO_RADIOAUX_DEBUGCONSOLE, -// PIOS_BOARD_IO_RADIOAUX_FRSKY_SPORT_TELEMETRY, -} PIOS_BOARD_IO_RADIOAUX_Function; #ifdef PIOS_INCLUDE_USB # ifndef BOOTLOADER @@ -234,22 +236,26 @@ void PIOS_BOARD_IO_Configure_USB_Function(PIOS_BOARD_IO_USB_HID_Function hid_fun # endif // ifndef BOOTLOADER #endif // ifdef PIOS_INCLUDE_USB #ifdef PIOS_INCLUDE_PWM -void PIOS_BOARD_IO_Configure_PWM(const struct pios_pwm_cfg *pwm_cfg); +void PIOS_BOARD_IO_Configure_PWM_RCVR(const struct pios_pwm_cfg *pwm_cfg); #endif #ifdef PIOS_INCLUDE_PPM -void PIOS_BOARD_IO_Configure_PPM(const struct pios_ppm_cfg *ppm_cfg); +void PIOS_BOARD_IO_Configure_PPM_RCVR(const struct pios_ppm_cfg *ppm_cfg); #endif - #ifdef PIOS_INCLUDE_USART void PIOS_BOARD_IO_Configure_UART(const struct pios_usart_cfg *usart_cfg, PIOS_BOARD_IO_UART_Function function); +void PIOS_BOARD_IO_Configure_UART_COM(const struct pios_usart_cfg *hw_config, + uint16_t rx_buf_len, + uint16_t tx_buf_len, + uint32_t *com_id); #endif #ifdef PIOS_INCLUDE_RFM22B -void PIOS_BOARD_IO_Configure_RFM22B(PIOS_BOARD_IO_RADIOAUX_Function function); +void PIOS_BOARD_IO_Configure_RFM22B(); +void PIOS_BOARD_IO_Configure_RadioAuxStream(HwSettingsRadioAuxStreamOptions radioaux); /* not for OPLM */ #endif #ifdef PIOS_INCLUDE_GCSRCVR -void PIOS_BOARD_IO_Configure_GCSRCVR(); +void PIOS_BOARD_IO_Configure_GCS_RCVR(); #endif #endif /* PIOS_BOARD_IO_H */ diff --git a/flight/targets/boards/coptercontrol/firmware/pios_board.c b/flight/targets/boards/coptercontrol/firmware/pios_board.c index baffcae280..47509d2942 100644 --- a/flight/targets/boards/coptercontrol/firmware/pios_board.c +++ b/flight/targets/boards/coptercontrol/firmware/pios_board.c @@ -246,7 +246,7 @@ void PIOS_Board_Init(void) break; case HWSETTINGS_CC_FLEXIPORT_PPM: #if defined(PIOS_INCLUDE_PPM_FLEXI) - PIOS_BOARD_IO_Configure_PPM(&pios_ppm_flexi_cfg); + PIOS_BOARD_IO_Configure_PPM_RCVR(&pios_ppm_flexi_cfg); #endif /* PIOS_INCLUDE_PPM_FLEXI */ break; } @@ -289,23 +289,23 @@ void PIOS_Board_Init(void) break; case HWSETTINGS_CC_RCVRPORT_PWMNOONESHOT: #if defined(PIOS_INCLUDE_PWM) - PIOS_BOARD_IO_Configure_PWM(&pios_pwm_cfg); + PIOS_BOARD_IO_Configure_PWM_RCVR(&pios_pwm_cfg); #endif /* PIOS_INCLUDE_PWM */ break; case HWSETTINGS_CC_RCVRPORT_PPMNOONESHOT: case HWSETTINGS_CC_RCVRPORT_PPMOUTPUTSNOONESHOT: case HWSETTINGS_CC_RCVRPORT_PPM_PIN8ONESHOT: #if defined(PIOS_INCLUDE_PPM) - PIOS_BOARD_IO_Configure_PPM((hwsettings_rcvrport == HWSETTINGS_CC_RCVRPORT_PPM_PIN8ONESHOT) ? &pios_ppm_pin8_cfg : &pios_ppm_cfg); + PIOS_BOARD_IO_Configure_PPM_RCVR((hwsettings_rcvrport == HWSETTINGS_CC_RCVRPORT_PPM_PIN8ONESHOT) ? &pios_ppm_pin8_cfg : &pios_ppm_cfg); #endif /* PIOS_INCLUDE_PPM */ break; case HWSETTINGS_CC_RCVRPORT_PPMPWMNOONESHOT: /* This is a combination of PPM and PWM inputs */ #if defined(PIOS_INCLUDE_PPM) - PIOS_BOARD_IO_Configure_PPM(&pios_ppm_cfg); + PIOS_BOARD_IO_Configure_PPM_RCVR(&pios_ppm_cfg); #endif /* PIOS_INCLUDE_PPM */ #if defined(PIOS_INCLUDE_PWM) - PIOS_BOARD_IO_Configure_PWM(&pios_pwm_with_ppm_cfg); + PIOS_BOARD_IO_Configure_PWM_RCVR(&pios_pwm_with_ppm_cfg); #endif /* PIOS_INCLUDE_PWM */ break; case HWSETTINGS_CC_RCVRPORT_OUTPUTSONESHOT: @@ -313,7 +313,7 @@ void PIOS_Board_Init(void) } #ifdef PIOS_INCLUDE_GCSRCVR - PIOS_BOARD_IO_Configure_GCSRCVR(); + PIOS_BOARD_IO_Configure_GCS_RCVR(); #endif /* Remap AFIO pin for PB4 (Servo 5 Out)*/ diff --git a/flight/targets/boards/discoveryf4bare/firmware/pios_board.c b/flight/targets/boards/discoveryf4bare/firmware/pios_board.c index 5ffc19ec6c..544f98c789 100644 --- a/flight/targets/boards/discoveryf4bare/firmware/pios_board.c +++ b/flight/targets/boards/discoveryf4bare/firmware/pios_board.c @@ -99,12 +99,6 @@ static const PIOS_BOARD_IO_UART_Function flexi_function_map[] = { [HWSETTINGS_RM_FLEXIPORT_MAVLINK] = PIOS_BOARD_IO_UART_MAVLINK, }; -static const PIOS_BOARD_IO_RADIOAUX_Function radioaux_function_map[] = { - [HWSETTINGS_RADIOAUXSTREAM_DEBUGCONSOLE] = PIOS_BOARD_IO_RADIOAUX_DEBUGCONSOLE, - [HWSETTINGS_RADIOAUXSTREAM_MAVLINK] = PIOS_BOARD_IO_RADIOAUX_MAVLINK, - [HWSETTINGS_RADIOAUXSTREAM_COMBRIDGE] = PIOS_BOARD_IO_RADIOAUX_COMBRIDGE, -}; - int32_t PIOS_BOARD_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param) { const struct pios_usart_cfg *usart_cfg = PIOS_USART_GetConfig(usart_id); @@ -287,12 +281,12 @@ void PIOS_Board_Init(void) } #if defined(PIOS_INCLUDE_RFM22B) + PIOS_BOARD_IO_Configure_RFM22B(); + uint8_t hwsettings_radioaux; HwSettingsRadioAuxStreamGet(&hwsettings_radioaux); - if (hwsettings_radioaux < NELEMENTS(radioaux_function_map)) { - PIOS_BOARD_IO_Configure_RFM22B(pios_spi_telem_flash_id, radioaux_function_map[hwsettings_radioaux]); - } + PIOS_BOARD_IO_Configure_RadioAuxStream(hwsettings_radioaux); #endif /* PIOS_INCLUDE_RFM22B */ @@ -316,7 +310,7 @@ void PIOS_Board_Init(void) case HWSETTINGS_RM_RCVRPORT_PWM: #if defined(PIOS_INCLUDE_PWM) /* Set up the receiver port. Later this should be optional */ - PIOS_BOARD_IO_Configure_PWM(&pios_pwm_cfg); + PIOS_BOARD_IO_Configure_PWM_RCVR(&pios_pwm_cfg); #endif /* PIOS_INCLUDE_PWM */ break; case HWSETTINGS_RM_RCVRPORT_PPM: @@ -329,7 +323,7 @@ void PIOS_Board_Init(void) case HWSETTINGS_RM_RCVRPORT_PPMMAVLINK: case HWSETTINGS_RM_RCVRPORT_PPMGPS: #if defined(PIOS_INCLUDE_PPM) - PIOS_BOARD_IO_Configure_PPM(&pios_ppm_cfg); + PIOS_BOARD_IO_Configure_PPM_RCVR(&pios_ppm_cfg); if (hwsettings_rcvrport == HWSETTINGS_RM_RCVRPORT_PPMOUTPUTS) { // configure servo outputs and the remaining 5 inputs as outputs @@ -338,7 +332,7 @@ void PIOS_Board_Init(void) // enable pwm on the remaining channels if (hwsettings_rcvrport == HWSETTINGS_RM_RCVRPORT_PPMPWM) { - PIOS_BOARD_IO_Configure_PWM(&pios_pwm_ppm_cfg); + PIOS_BOARD_IO_Configure_PWM_RCVR(&pios_pwm_ppm_cfg); } break; @@ -349,7 +343,7 @@ void PIOS_Board_Init(void) break; } #ifdef PIOS_INCLUDE_GCSRCVR - PIOS_BOARD_IO_Configure_GCSRCVR(); + PIOS_BOARD_IO_Configure_GCS_RCVR(); #endif #ifndef PIOS_ENABLE_DEBUG_PINS diff --git a/flight/targets/boards/oplinkmini/firmware/pios_board.c b/flight/targets/boards/oplinkmini/firmware/pios_board.c index 7b07878214..61730031e8 100644 --- a/flight/targets/boards/oplinkmini/firmware/pios_board.c +++ b/flight/targets/boards/oplinkmini/firmware/pios_board.c @@ -37,6 +37,7 @@ #ifdef PIOS_INCLUDE_SERVO #include #endif +#include /* * Pull in the board-specific static HW definitions. @@ -48,36 +49,17 @@ */ #include "../board_hw_defs.c" -#define PIOS_COM_TELEM_USB_RX_BUF_LEN 128 -#define PIOS_COM_TELEM_USB_TX_BUF_LEN 128 - -#define PIOS_COM_TELEM_VCP_RX_BUF_LEN 128 -#define PIOS_COM_TELEM_VCP_TX_BUF_LEN 128 - -#define PIOS_COM_RFM22B_RF_RX_BUF_LEN 128 -#define PIOS_COM_RFM22B_RF_TX_BUF_LEN 128 - -#define PIOS_COM_TELEM_RX_BUF_LEN 128 -#define PIOS_COM_TELEM_TX_BUF_LEN 128 - uint32_t pios_com_hid_id = 0; -uint32_t pios_com_vcp_id = 0; +// uint32_t pios_com_vcp_id = 0; /* this is provided by pios_board_io.c */ uint32_t pios_com_main_id = 0; uint32_t pios_com_flexi_id = 0; -uint32_t pios_com_bridge_id = 0; uint32_t pios_com_gcs_id = 0; uint32_t pios_com_gcs_out_id = 0; -#if defined(PIOS_INCLUDE_PPM) -uint32_t pios_ppm_rcvr_id = 0; -#endif #if defined(PIOS_INCLUDE_PPM_OUT) uint32_t pios_ppm_out_id = 0; #endif #if defined(PIOS_INCLUDE_RFM22B) #include -uint32_t pios_rfm22b_id = 0; -uint32_t pios_com_pri_radio_id = 0; -uint32_t pios_com_aux_radio_id = 0; uint32_t pios_com_pri_radio_out_id = 0; uint32_t pios_com_aux_radio_out_id = 0; #endif @@ -87,41 +69,6 @@ uintptr_t pios_user_fs_id = 0; static uint8_t servo_count = 0; -/* - * Setup a com port based on the passed cfg, driver and buffer sizes. - * tx size of 0 make the port rx only - * rx size of 0 make the port tx only - * having both tx and rx size of 0 is not valid and will fail further down in PIOS_COM_Init() - */ -static void PIOS_Board_configure_com(const struct pios_usart_cfg *usart_port_cfg, uint16_t rx_buf_len, uint16_t tx_buf_len, - const struct pios_com_driver *com_driver, uint32_t *pios_com_id) -{ - uint32_t pios_usart_id; - - if (PIOS_USART_Init(&pios_usart_id, usart_port_cfg)) { - PIOS_Assert(0); - } - - uint8_t *rx_buffer = 0, *tx_buffer = 0; - - if (rx_buf_len > 0) { - rx_buffer = (uint8_t *)pios_malloc(rx_buf_len); - PIOS_Assert(rx_buffer); - } - - if (tx_buf_len > 0) { - tx_buffer = (uint8_t *)pios_malloc(tx_buf_len); - PIOS_Assert(tx_buffer); - } - - if (PIOS_COM_Init(pios_com_id, com_driver, pios_usart_id, - rx_buffer, rx_buf_len, - tx_buffer, tx_buf_len)) { - PIOS_Assert(0); - } -} - - // Forward definitions static void PIOS_Board_PPM_callback(uint32_t context, const int16_t *channels); @@ -184,10 +131,7 @@ void PIOS_Board_Init(void) PIOS_IAP_WriteBootCmd(2, 0); } -#if defined(PIOS_INCLUDE_RFM22B) OPLinkSettingsInitialize(); - OPLinkStatusInitialize(); -#endif /* PIOS_INCLUDE_RFM22B */ /* Retrieve the settings object. */ OPLinkSettingsData oplinkSettings; @@ -195,12 +139,7 @@ void PIOS_Board_Init(void) /* Determine the modem protocols */ bool is_coordinator = (oplinkSettings.Protocol == OPLINKSETTINGS_PROTOCOL_OPLINKCOORDINATOR); - bool openlrs = (oplinkSettings.Protocol == OPLINKSETTINGS_PROTOCOL_OPENLRS); bool ppm_only = (oplinkSettings.LinkType == OPLINKSETTINGS_LINKTYPE_CONTROL); - bool data_mode = ((oplinkSettings.LinkType == OPLINKSETTINGS_LINKTYPE_DATA) || - (oplinkSettings.LinkType == OPLINKSETTINGS_LINKTYPE_DATAANDCONTROL)); - bool is_enabled = ((oplinkSettings.Protocol != OPLINKSETTINGS_PROTOCOL_DISABLED) && - ((oplinkSettings.MaxRFPower != OPLINKSETTINGS_MAXRFPOWER_0) || openlrs)); bool ppm_mode = ((oplinkSettings.LinkType == OPLINKSETTINGS_LINKTYPE_CONTROL) || (oplinkSettings.LinkType == OPLINKSETTINGS_LINKTYPE_DATAANDCONTROL)); bool servo_main = false; @@ -300,9 +239,9 @@ void PIOS_Board_Init(void) case OPLINKSETTINGS_MAINPORT_TELEMETRY: case OPLINKSETTINGS_MAINPORT_SERIAL: #ifndef PIOS_RFM22B_DEBUG_ON_TELEM - PIOS_Board_configure_com(&pios_usart_main_cfg, - PIOS_COM_TELEM_RX_BUF_LEN, PIOS_COM_TELEM_TX_BUF_LEN, - &pios_usart_com_driver, &pios_com_main_id); + PIOS_BOARD_IO_Configure_UART_COM(&pios_usart_main_cfg, + PIOS_COM_TELEM_RF_RX_BUF_LEN, PIOS_COM_TELEM_RF_TX_BUF_LEN, + &pios_com_main_id); PIOS_COM_ChangeBaud(pios_com_main_id, mainComSpeed); #endif /* !PIOS_RFM22B_DEBUG_ON_TELEM */ break; @@ -310,12 +249,7 @@ void PIOS_Board_Init(void) #if defined(PIOS_INCLUDE_PPM) /* PPM input is configured on the coordinator modem and output on the remote modem. */ if (is_coordinator) { - uint32_t pios_ppm_id; - PIOS_PPM_Init(&pios_ppm_id, &pios_ppm_main_cfg); - - if (PIOS_RCVR_Init(&pios_ppm_rcvr_id, &pios_ppm_rcvr_driver, pios_ppm_id)) { - PIOS_Assert(0); - } + PIOS_BOARD_IO_Configure_PPM_RCVR(&pios_ppm_main_cfg); } // For some reason, PPM output on the main port doesn't work. #if defined(PIOS_INCLUDE_PPM_OUT) @@ -359,9 +293,9 @@ void PIOS_Board_Init(void) case OPLINKSETTINGS_FLEXIPORT_TELEMETRY: case OPLINKSETTINGS_FLEXIPORT_SERIAL: #ifndef PIOS_RFM22B_DEBUG_ON_TELEM - PIOS_Board_configure_com(&pios_usart_flexi_cfg, - PIOS_COM_TELEM_RX_BUF_LEN, PIOS_COM_TELEM_TX_BUF_LEN, - &pios_usart_com_driver, &pios_com_flexi_id); + PIOS_BOARD_IO_Configure_UART_COM(&pios_usart_flexi_cfg, + PIOS_COM_TELEM_RF_RX_BUF_LEN, PIOS_COM_TELEM_RF_TX_BUF_LEN, + &pios_com_flexi_id); PIOS_COM_ChangeBaud(pios_com_flexi_id, flexiComSpeed); #endif /* !PIOS_RFM22B_DEBUG_ON_TELEM */ break; @@ -369,12 +303,7 @@ void PIOS_Board_Init(void) #if defined(PIOS_INCLUDE_PPM) /* PPM input is configured on the coordinator modem and output on the remote modem. */ if (is_coordinator) { - uint32_t pios_ppm_id; - PIOS_PPM_Init(&pios_ppm_id, &pios_ppm_flexi_cfg); - - if (PIOS_RCVR_Init(&pios_ppm_rcvr_id, &pios_ppm_rcvr_driver, pios_ppm_id)) { - PIOS_Assert(0); - } + PIOS_BOARD_IO_Configure_PPM_RCVR(&pios_ppm_flexi_cfg); } // For some reason, PPM output on the flexi port doesn't work. #if defined(PIOS_INCLUDE_PPM_OUT) @@ -410,138 +339,11 @@ void PIOS_Board_Init(void) PIOS_Servo_SetBankMode(1, PIOS_SERVO_BANK_MODE_PWM); #endif - // Initialize out status object. - OPLinkStatusData oplinkStatus; - OPLinkStatusGet(&oplinkStatus); - - // Get our hardware information. - const struct pios_board_info *bdinfo = &pios_board_info_blob; - - oplinkStatus.BoardType = bdinfo->board_type; - PIOS_BL_HELPER_FLASH_Read_Description(oplinkStatus.Description, OPLINKSTATUS_DESCRIPTION_NUMELEM); - PIOS_SYS_SerialNumberGetBinary(oplinkStatus.CPUSerial); - oplinkStatus.BoardRevision = bdinfo->board_rev; + PIOS_BOARD_IO_Configure_RFM22B(); - /* Initialize the RFM22B radio COM device. */ - if (is_enabled) { - if (openlrs) { -#if defined(PIOS_INCLUDE_OPENLRS) - const struct pios_openlrs_cfg *openlrs_cfg = PIOS_BOARD_HW_DEFS_GetOpenLRSCfg(bdinfo->board_rev); - uint32_t openlrs_id; - - oplinkStatus.LinkState = OPLINKSTATUS_LINKSTATE_ENABLED; - - PIOS_OpenLRS_Init(&openlrs_id, PIOS_RFM22_SPI_PORT, 0, openlrs_cfg); - PIOS_OpenLRS_RegisterPPMCallback(openlrs_id, PIOS_Board_PPM_callback, 0); -#endif /* PIOS_INCLUDE_OPENLRS */ - } else { - oplinkStatus.LinkState = OPLINKSTATUS_LINKSTATE_ENABLED; - - // Configure the RFM22B device - const struct pios_rfm22b_cfg *rfm22b_cfg = PIOS_BOARD_HW_DEFS_GetRfm22Cfg(bdinfo->board_rev); - - if (PIOS_RFM22B_Init(&pios_rfm22b_id, PIOS_RFM22_SPI_PORT, rfm22b_cfg->slave_num, rfm22b_cfg, oplinkSettings.RFBand)) { - PIOS_Assert(0); - } - - // Configure the radio com interface - uint8_t *rx_buffer = (uint8_t *)pios_malloc(PIOS_COM_RFM22B_RF_RX_BUF_LEN); - uint8_t *tx_buffer = (uint8_t *)pios_malloc(PIOS_COM_RFM22B_RF_TX_BUF_LEN); - PIOS_Assert(rx_buffer); - PIOS_Assert(tx_buffer); - if (PIOS_COM_Init(&pios_com_pri_radio_id, &pios_rfm22b_com_driver, pios_rfm22b_id, - rx_buffer, PIOS_COM_RFM22B_RF_RX_BUF_LEN, - tx_buffer, PIOS_COM_RFM22B_RF_TX_BUF_LEN)) { - PIOS_Assert(0); - } - - // Initialize the aux radio com interface - uint8_t *auxrx_buffer = (uint8_t *)pios_malloc(PIOS_COM_TELEM_RX_BUF_LEN); - uint8_t *auxtx_buffer = (uint8_t *)pios_malloc(PIOS_COM_TELEM_TX_BUF_LEN); - PIOS_Assert(auxrx_buffer); - PIOS_Assert(auxtx_buffer); - if (PIOS_COM_Init(&pios_com_aux_radio_id, &pios_rfm22b_aux_com_driver, pios_rfm22b_id, - auxrx_buffer, PIOS_COM_TELEM_RX_BUF_LEN, - auxtx_buffer, PIOS_COM_TELEM_TX_BUF_LEN)) { - PIOS_Assert(0); - } - - // Set the modem (over the air) datarate. - enum rfm22b_datarate datarate = RFM22_datarate_64000; - switch (oplinkSettings.AirDataRate) { - case OPLINKSETTINGS_AIRDATARATE_9600: - datarate = RFM22_datarate_9600; - break; - case OPLINKSETTINGS_AIRDATARATE_19200: - datarate = RFM22_datarate_19200; - break; - case OPLINKSETTINGS_AIRDATARATE_32000: - datarate = RFM22_datarate_32000; - break; - case OPLINKSETTINGS_AIRDATARATE_57600: - datarate = RFM22_datarate_57600; - break; - case OPLINKSETTINGS_AIRDATARATE_64000: - datarate = RFM22_datarate_64000; - break; - case OPLINKSETTINGS_AIRDATARATE_100000: - datarate = RFM22_datarate_100000; - break; - case OPLINKSETTINGS_AIRDATARATE_128000: - datarate = RFM22_datarate_128000; - break; - case OPLINKSETTINGS_AIRDATARATE_192000: - datarate = RFM22_datarate_192000; - break; - case OPLINKSETTINGS_AIRDATARATE_256000: - datarate = RFM22_datarate_256000; - break; - } - - /* Set the modem Tx power level */ - switch (oplinkSettings.MaxRFPower) { - case OPLINKSETTINGS_MAXRFPOWER_125: - PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_0); - break; - case OPLINKSETTINGS_MAXRFPOWER_16: - PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_1); - break; - case OPLINKSETTINGS_MAXRFPOWER_316: - PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_2); - break; - case OPLINKSETTINGS_MAXRFPOWER_63: - PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_3); - break; - case OPLINKSETTINGS_MAXRFPOWER_126: - PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_4); - break; - case OPLINKSETTINGS_MAXRFPOWER_25: - PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_5); - break; - case OPLINKSETTINGS_MAXRFPOWER_50: - PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_6); - break; - case OPLINKSETTINGS_MAXRFPOWER_100: - PIOS_RFM22B_SetTxPower(pios_rfm22b_id, RFM22_tx_pwr_txpow_7); - break; - default: - // do nothing - break; - } - - // Set the radio configuration parameters. - PIOS_RFM22B_SetDeviceID(pios_rfm22b_id, oplinkSettings.CustomDeviceID); - PIOS_RFM22B_SetCoordinatorID(pios_rfm22b_id, oplinkSettings.CoordID); - PIOS_RFM22B_SetXtalCap(pios_rfm22b_id, oplinkSettings.RFXtalCap); - PIOS_RFM22B_SetChannelConfig(pios_rfm22b_id, datarate, oplinkSettings.MinChannel, oplinkSettings.MaxChannel, is_coordinator, data_mode, ppm_mode); - - /* Set the PPM callback if we should be receiving PPM. */ - if (ppm_mode || (ppm_only && !is_coordinator)) { - PIOS_RFM22B_SetPPMCallback(pios_rfm22b_id, PIOS_Board_PPM_callback, 0); - } - } // openlrs - } else { - oplinkStatus.LinkState = OPLINKSTATUS_LINKSTATE_DISABLED; + /* Set the PPM callback if we should be receiving PPM. */ + if (ppm_mode || (ppm_only && !is_coordinator)) { + PIOS_RFM22B_SetPPMCallback(pios_rfm22b_id, PIOS_Board_PPM_callback, 0); } // Configure the primary radio stream destination. @@ -622,9 +424,6 @@ void PIOS_Board_Init(void) break; } - // Update the object - OPLinkStatusSet(&oplinkStatus); - /* Remap AFIO pin */ GPIO_PinRemapConfig(GPIO_Remap_SWJ_NoJTRST, ENABLE); diff --git a/flight/targets/boards/oplinkmini/pios_board.h b/flight/targets/boards/oplinkmini/pios_board.h index e96c0b12d6..15f07034b4 100644 --- a/flight/targets/boards/oplinkmini/pios_board.h +++ b/flight/targets/boards/oplinkmini/pios_board.h @@ -172,7 +172,13 @@ extern uint32_t pios_i2c_flexi_adapter_id; // // See also pios_board.c // ------------------------- -#define PIOS_COM_MAX_DEVS 5 +#define PIOS_COM_MAX_DEVS 5 + +#define PIOS_COM_TELEM_USB_RX_BUF_LEN 128 +#define PIOS_COM_TELEM_USB_TX_BUF_LEN 128 + +#define PIOS_COM_TELEM_VCP_RX_BUF_LEN 128 +#define PIOS_COM_TELEM_VCP_TX_BUF_LEN 128 // The direct com ports extern uint32_t pios_com_hid_id; @@ -192,7 +198,6 @@ extern uint32_t pios_com_pri_radio_out_id; // The destination port for the auxiliary radio port. extern uint32_t pios_com_aux_radio_out_id; // The PPM IDs -extern uint32_t pios_ppm_rcvr_id; extern uint32_t pios_ppm_out_id; #define PIOS_COM_HID (pios_com_hid_id) #define PIOS_COM_VCP (pios_com_vcp_id) @@ -205,7 +210,6 @@ extern uint32_t pios_ppm_out_id; #define PIOS_COM_GCS (pios_com_gcs_id) #define PIOS_COM_GCS_OUT (pios_com_gcs_out_id) #define PIOS_COM_BRIDGE (pios_com_bridge_id) -#define PIOS_PPM_RECEIVER (pios_ppm_rcvr_id) #define PIOS_PPM_OUTPUT (pios_ppm_out_id) #define RFM22_DEBUG 1 diff --git a/flight/targets/boards/revolution/firmware/pios_board.c b/flight/targets/boards/revolution/firmware/pios_board.c index 47279154e7..e958bb7c80 100644 --- a/flight/targets/boards/revolution/firmware/pios_board.c +++ b/flight/targets/boards/revolution/firmware/pios_board.c @@ -98,13 +98,6 @@ static const PIOS_BOARD_IO_UART_Function flexi_function_map[] = { [HWSETTINGS_RM_FLEXIPORT_MAVLINK] = PIOS_BOARD_IO_UART_MAVLINK, }; -static const PIOS_BOARD_IO_RADIOAUX_Function radioaux_function_map[] = { - [HWSETTINGS_RADIOAUXSTREAM_DEBUGCONSOLE] = PIOS_BOARD_IO_RADIOAUX_DEBUGCONSOLE, - [HWSETTINGS_RADIOAUXSTREAM_MAVLINK] = PIOS_BOARD_IO_RADIOAUX_MAVLINK, - [HWSETTINGS_RADIOAUXSTREAM_COMBRIDGE] = PIOS_BOARD_IO_RADIOAUX_COMBRIDGE, -}; - - int32_t PIOS_BOARD_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param) { const struct pios_usart_cfg *usart_cfg = PIOS_USART_GetConfig(usart_id); @@ -287,12 +280,12 @@ void PIOS_Board_Init(void) } #if defined(PIOS_INCLUDE_RFM22B) + PIOS_BOARD_IO_Configure_RFM22B(); + uint8_t hwsettings_radioaux; HwSettingsRadioAuxStreamGet(&hwsettings_radioaux); - if (hwsettings_radioaux < NELEMENTS(radioaux_function_map)) { - PIOS_BOARD_IO_Configure_RFM22B(radioaux_function_map[hwsettings_radioaux]); - } + PIOS_BOARD_IO_Configure_RadioAuxStream(hwsettings_radioaux); #endif /* PIOS_INCLUDE_RFM22B */ #if defined(PIOS_INCLUDE_PWM) || defined(PIOS_INCLUDE_PPM) @@ -314,7 +307,7 @@ void PIOS_Board_Init(void) case HWSETTINGS_RM_RCVRPORT_PWM: #if defined(PIOS_INCLUDE_PWM) /* Set up the receiver port. Later this should be optional */ - PIOS_BOARD_IO_Configure_PWM(&pios_pwm_cfg); + PIOS_BOARD_IO_Configure_PWM_RCVR(&pios_pwm_cfg); #endif /* PIOS_INCLUDE_PWM */ break; case HWSETTINGS_RM_RCVRPORT_PPM: @@ -328,7 +321,7 @@ void PIOS_Board_Init(void) case HWSETTINGS_RM_RCVRPORT_PPMGPS: case HWSETTINGS_RM_RCVRPORT_PPMHOTTTELEMETRY: #if defined(PIOS_INCLUDE_PPM) - PIOS_BOARD_IO_Configure_PPM(&pios_ppm_cfg); + PIOS_BOARD_IO_Configure_PPM_RCVR(&pios_ppm_cfg); if (hwsettings_rcvrport == HWSETTINGS_RM_RCVRPORT_PPMOUTPUTS) { // configure servo outputs and the remaining 5 inputs as outputs @@ -337,7 +330,7 @@ void PIOS_Board_Init(void) // enable pwm on the remaining channels if (hwsettings_rcvrport == HWSETTINGS_RM_RCVRPORT_PPMPWM) { - PIOS_BOARD_IO_Configure_PWM(&pios_pwm_ppm_cfg); + PIOS_BOARD_IO_Configure_PWM_RCVR(&pios_pwm_ppm_cfg); } break; @@ -348,7 +341,7 @@ void PIOS_Board_Init(void) break; } #ifdef PIOS_INCLUDE_GCSRCVR - PIOS_BOARD_IO_Configure_GCSRCVR(); + PIOS_BOARD_IO_Configure_GCS_RCVR(); #endif #ifndef PIOS_ENABLE_DEBUG_PINS diff --git a/flight/targets/boards/revonano/firmware/pios_board.c b/flight/targets/boards/revonano/firmware/pios_board.c index d4883768d9..5f8fb7799c 100644 --- a/flight/targets/boards/revonano/firmware/pios_board.c +++ b/flight/targets/boards/revonano/firmware/pios_board.c @@ -263,7 +263,7 @@ void PIOS_Board_Init(void) case HWSETTINGS_RM_RCVRPORT_PWM: #if defined(PIOS_INCLUDE_PWM) /* Set up the receiver port. Later this should be optional */ - PIOS_BOARD_IO_Configure_PWM(&pios_pwm_cfg); + PIOS_BOARD_IO_Configure_PWM_RCVR(&pios_pwm_cfg); #endif /* PIOS_INCLUDE_PWM */ break; case HWSETTINGS_RM_RCVRPORT_PPM: @@ -275,7 +275,7 @@ void PIOS_Board_Init(void) pios_servo_cfg = &pios_servo_cfg_out_in_ppm; } - PIOS_BOARD_IO_Configure_PPM(&pios_ppm_cfg); + PIOS_BOARD_IO_Configure_PPM_RCVR(&pios_ppm_cfg); break; #endif /* PIOS_INCLUDE_PPM */ @@ -287,7 +287,7 @@ void PIOS_Board_Init(void) #ifdef PIOS_INCLUDE_GCSRCVR - PIOS_BOARD_IO_Configure_GCSRCVR(); + PIOS_BOARD_IO_Configure_GCS_RCVR(); #endif #ifdef PIOS_INCLUDE_WS2811 diff --git a/flight/targets/boards/revoproto/firmware/pios_board.c b/flight/targets/boards/revoproto/firmware/pios_board.c index 167f19bd00..66242f413f 100644 --- a/flight/targets/boards/revoproto/firmware/pios_board.c +++ b/flight/targets/boards/revoproto/firmware/pios_board.c @@ -313,13 +313,13 @@ void PIOS_Board_Init(void) break; case HWSETTINGS_RV_RCVRPORT_PWM: #if defined(PIOS_INCLUDE_PWM) - PIOS_BOARD_IO_Configure_PWM(&pios_pwm_cfg); + PIOS_BOARD_IO_Configure_PWM_RCVR(&pios_pwm_cfg); #endif /* PIOS_INCLUDE_PWM */ break; case HWSETTINGS_RV_RCVRPORT_PPM: case HWSETTINGS_RV_RCVRPORT_PPMOUTPUTS: #if defined(PIOS_INCLUDE_PPM) - PIOS_BOARD_IO_Configure_PPM(&pios_ppm_cfg); + PIOS_BOARD_IO_Configure_PPM_RCVR(&pios_ppm_cfg); #endif /* PIOS_INCLUDE_PPM */ case HWSETTINGS_RV_RCVRPORT_OUTPUTS: @@ -359,7 +359,7 @@ void PIOS_Board_Init(void) #endif #ifdef PIOS_INCLUDE_GCSRCVR - PIOS_BOARD_IO_Configure_GCSRCVR(); + PIOS_BOARD_IO_Configure_GCS_RCVR(); #endif #ifndef PIOS_ENABLE_DEBUG_PINS diff --git a/flight/targets/boards/sparky2/firmware/pios_board.c b/flight/targets/boards/sparky2/firmware/pios_board.c index a9b72f4856..d9d7fd9ee5 100644 --- a/flight/targets/boards/sparky2/firmware/pios_board.c +++ b/flight/targets/boards/sparky2/firmware/pios_board.c @@ -93,12 +93,6 @@ static const PIOS_BOARD_IO_UART_Function flexi_function_map[] = { [HWSETTINGS_SPK2_FLEXIPORT_MAVLINK] = PIOS_BOARD_IO_UART_MAVLINK, }; -static const PIOS_BOARD_IO_RADIOAUX_Function radioaux_function_map[] = { - [HWSETTINGS_RADIOAUXSTREAM_DEBUGCONSOLE] = PIOS_BOARD_IO_RADIOAUX_DEBUGCONSOLE, - [HWSETTINGS_RADIOAUXSTREAM_MAVLINK] = PIOS_BOARD_IO_RADIOAUX_MAVLINK, - [HWSETTINGS_RADIOAUXSTREAM_COMBRIDGE] = PIOS_BOARD_IO_RADIOAUX_COMBRIDGE, -}; - int32_t PIOS_BOARD_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param) { const struct pios_usart_cfg *usart_cfg = PIOS_USART_GetConfig(usart_id); @@ -263,12 +257,12 @@ void PIOS_Board_Init(void) } #if defined(PIOS_INCLUDE_RFM22B) + PIOS_BOARD_IO_Configure_RFM22B(); + uint8_t hwsettings_radioaux; HwSettingsRadioAuxStreamGet(&hwsettings_radioaux); - if (hwsettings_radioaux < NELEMENTS(radioaux_function_map)) { - PIOS_BOARD_IO_Configure_RFM22B(radioaux_function_map[hwsettings_radioaux]); - } + PIOS_BOARD_IO_Configure_RadioAuxStream(hwsettings_radioaux); #endif /* PIOS_INCLUDE_RFM22B */ /* Initialize inverter gpio and set it to off */ @@ -301,12 +295,12 @@ void PIOS_Board_Init(void) #if defined(PIOS_INCLUDE_PPM) if (hwsettings_rcvrport == HWSETTINGS_SPK2_RCVRPORT_PPM) { - PIOS_BOARD_IO_Configure_PPM(&pios_ppm_cfg); + PIOS_BOARD_IO_Configure_PPM_RCVR(&pios_ppm_cfg); } #endif #ifdef PIOS_INCLUDE_GCSRCVR - PIOS_BOARD_IO_Configure_GCSRCVR(); + PIOS_BOARD_IO_Configure_GCS_RCVR(); #endif #ifndef PIOS_ENABLE_DEBUG_PINS From 4c2659e92f55ae66d28c09890ba5a3089da5ede7 Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Mon, 24 Apr 2017 09:50:05 +0200 Subject: [PATCH 229/624] LP-513 gcs: remove QtCreator cruft --- .../utils/classnamevalidatinglineedit.cpp | 151 ----- .../libs/utils/classnamevalidatinglineedit.h | 75 --- ground/gcs/src/libs/utils/codegeneration.cpp | 105 ---- ground/gcs/src/libs/utils/codegeneration.h | 66 --- .../libs/utils/filenamevalidatinglineedit.cpp | 138 ----- .../libs/utils/filenamevalidatinglineedit.h | 65 --- .../gcs/src/libs/utils/filewizarddialog.cpp | 66 --- ground/gcs/src/libs/utils/filewizarddialog.h | 61 -- ground/gcs/src/libs/utils/filewizardpage.cpp | 129 ----- ground/gcs/src/libs/utils/filewizardpage.h | 85 --- ground/gcs/src/libs/utils/filewizardpage.ui | 54 -- ground/gcs/src/libs/utils/newclasswidget.cpp | 535 ----------------- ground/gcs/src/libs/utils/newclasswidget.h | 163 ------ ground/gcs/src/libs/utils/newclasswidget.ui | 181 ------ ground/gcs/src/libs/utils/parameteraction.cpp | 85 --- ground/gcs/src/libs/utils/parameteraction.h | 79 --- ground/gcs/src/libs/utils/pathlisteditor.cpp | 324 ----------- ground/gcs/src/libs/utils/pathlisteditor.h | 103 ---- .../gcs/src/libs/utils/projectintropage.cpp | 210 ------- ground/gcs/src/libs/utils/projectintropage.h | 99 ---- ground/gcs/src/libs/utils/projectintropage.ui | 116 ---- .../utils/projectnamevalidatinglineedit.cpp | 59 -- .../utils/projectnamevalidatinglineedit.h | 48 -- .../gcs/src/libs/utils/reloadpromptutils.cpp | 70 --- ground/gcs/src/libs/utils/reloadpromptutils.h | 46 -- ground/gcs/src/libs/utils/savedaction.cpp | 489 ---------------- ground/gcs/src/libs/utils/savedaction.h | 124 ---- .../gcs/src/libs/utils/submiteditorwidget.cpp | 537 ------------------ .../gcs/src/libs/utils/submiteditorwidget.h | 142 ----- .../gcs/src/libs/utils/submiteditorwidget.ui | 72 --- .../gcs/src/libs/utils/submitfieldwidget.cpp | 389 ------------- ground/gcs/src/libs/utils/submitfieldwidget.h | 93 --- .../gcs/src/libs/utils/uncommentselection.cpp | 161 ------ .../gcs/src/libs/utils/uncommentselection.h | 42 -- ground/gcs/src/libs/utils/utils.pro | 35 -- ground/gcs/src/libs/utils/utils.qrc | 1 - 36 files changed, 5198 deletions(-) delete mode 100644 ground/gcs/src/libs/utils/classnamevalidatinglineedit.cpp delete mode 100644 ground/gcs/src/libs/utils/classnamevalidatinglineedit.h delete mode 100644 ground/gcs/src/libs/utils/codegeneration.cpp delete mode 100644 ground/gcs/src/libs/utils/codegeneration.h delete mode 100644 ground/gcs/src/libs/utils/filenamevalidatinglineedit.cpp delete mode 100644 ground/gcs/src/libs/utils/filenamevalidatinglineedit.h delete mode 100644 ground/gcs/src/libs/utils/filewizarddialog.cpp delete mode 100644 ground/gcs/src/libs/utils/filewizarddialog.h delete mode 100644 ground/gcs/src/libs/utils/filewizardpage.cpp delete mode 100644 ground/gcs/src/libs/utils/filewizardpage.h delete mode 100644 ground/gcs/src/libs/utils/filewizardpage.ui delete mode 100644 ground/gcs/src/libs/utils/newclasswidget.cpp delete mode 100644 ground/gcs/src/libs/utils/newclasswidget.h delete mode 100644 ground/gcs/src/libs/utils/newclasswidget.ui delete mode 100644 ground/gcs/src/libs/utils/parameteraction.cpp delete mode 100644 ground/gcs/src/libs/utils/parameteraction.h delete mode 100644 ground/gcs/src/libs/utils/pathlisteditor.cpp delete mode 100644 ground/gcs/src/libs/utils/pathlisteditor.h delete mode 100644 ground/gcs/src/libs/utils/projectintropage.cpp delete mode 100644 ground/gcs/src/libs/utils/projectintropage.h delete mode 100644 ground/gcs/src/libs/utils/projectintropage.ui delete mode 100644 ground/gcs/src/libs/utils/projectnamevalidatinglineedit.cpp delete mode 100644 ground/gcs/src/libs/utils/projectnamevalidatinglineedit.h delete mode 100644 ground/gcs/src/libs/utils/reloadpromptutils.cpp delete mode 100644 ground/gcs/src/libs/utils/reloadpromptutils.h delete mode 100644 ground/gcs/src/libs/utils/savedaction.cpp delete mode 100644 ground/gcs/src/libs/utils/savedaction.h delete mode 100644 ground/gcs/src/libs/utils/submiteditorwidget.cpp delete mode 100644 ground/gcs/src/libs/utils/submiteditorwidget.h delete mode 100644 ground/gcs/src/libs/utils/submiteditorwidget.ui delete mode 100644 ground/gcs/src/libs/utils/submitfieldwidget.cpp delete mode 100644 ground/gcs/src/libs/utils/submitfieldwidget.h delete mode 100644 ground/gcs/src/libs/utils/uncommentselection.cpp delete mode 100644 ground/gcs/src/libs/utils/uncommentselection.h diff --git a/ground/gcs/src/libs/utils/classnamevalidatinglineedit.cpp b/ground/gcs/src/libs/utils/classnamevalidatinglineedit.cpp deleted file mode 100644 index d1a1e7d9d4..0000000000 --- a/ground/gcs/src/libs/utils/classnamevalidatinglineedit.cpp +++ /dev/null @@ -1,151 +0,0 @@ -/** - ****************************************************************************** - * - * @file classnamevalidatinglineedit.cpp - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @brief - * @see The GNU Public License (GPL) Version 3 - * @defgroup - * @{ - * - *****************************************************************************/ -/* - * 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 "classnamevalidatinglineedit.h" - -#include - -#include -#include - -namespace Utils { -struct ClassNameValidatingLineEditPrivate { - ClassNameValidatingLineEditPrivate(); - - const QRegExp m_nameRegexp; - const QString m_namespaceDelimiter; - bool m_namespacesEnabled; - bool m_lowerCaseFileName; -}; - -// Match something like "Namespace1::Namespace2::ClassName". -ClassNameValidatingLineEditPrivate::ClassNameValidatingLineEditPrivate() : - m_nameRegexp(QLatin1String("[a-zA-Z_][a-zA-Z0-9_]*(::[a-zA-Z_][a-zA-Z0-9_]*)*")), - m_namespaceDelimiter(QLatin1String("::")), - m_namespacesEnabled(false), - m_lowerCaseFileName(true) -{ - QTC_ASSERT(m_nameRegexp.isValid(), return ); -} - -// --------------------- ClassNameValidatingLineEdit -ClassNameValidatingLineEdit::ClassNameValidatingLineEdit(QWidget *parent) : - Utils::BaseValidatingLineEdit(parent), - m_d(new ClassNameValidatingLineEditPrivate) -{} - -ClassNameValidatingLineEdit::~ClassNameValidatingLineEdit() -{ - delete m_d; -} - -bool ClassNameValidatingLineEdit::namespacesEnabled() const -{ - return m_d->m_namespacesEnabled; -} - -void ClassNameValidatingLineEdit::setNamespacesEnabled(bool b) -{ - m_d->m_namespacesEnabled = b; -} - -bool ClassNameValidatingLineEdit::validate(const QString &value, QString *errorMessage) const -{ - if (!m_d->m_namespacesEnabled && value.contains(QLatin1Char(':'))) { - if (errorMessage) { - *errorMessage = tr("The class name must not contain namespace delimiters."); - } - return false; - } else if (value.isEmpty()) { - if (errorMessage) { - *errorMessage = tr("Please enter a class name."); - } - return false; - } else if (!m_d->m_nameRegexp.exactMatch(value)) { - if (errorMessage) { - *errorMessage = tr("The class name contains invalid characters."); - } - return false; - } - return true; -} - -void ClassNameValidatingLineEdit::slotChanged(const QString &t) -{ - Utils::BaseValidatingLineEdit::slotChanged(t); - - if (isValid()) { - // Suggest file names, strip namespaces - QString fileName = m_d->m_lowerCaseFileName ? t.toLower() : t; - if (m_d->m_namespacesEnabled) { - const int namespaceIndex = fileName.lastIndexOf(m_d->m_namespaceDelimiter); - if (namespaceIndex != -1) { - fileName.remove(0, namespaceIndex + m_d->m_namespaceDelimiter.size()); - } - } - emit updateFileName(fileName); - } -} - -QString ClassNameValidatingLineEdit::createClassName(const QString &name) -{ - // Remove spaces and convert the adjacent characters to uppercase - QString className = name; - QRegExp spaceMatcher(QLatin1String(" +(\\w)"), Qt::CaseSensitive, QRegExp::RegExp2); - - QTC_ASSERT(spaceMatcher.isValid(), /**/); - int pos; - while ((pos = spaceMatcher.indexIn(className)) != -1) { - className.replace(pos, spaceMatcher.matchedLength(), - spaceMatcher.cap(1).toUpper()); - } - - // Filter out any remaining invalid characters - className.remove(QRegExp(QLatin1String("[^a-zA-Z0-9_]"))); - - // If the first character is numeric, prefix the name with a "_" - if (className.at(0).isNumber()) { - className.prepend(QLatin1Char('_')); - } else { - // Convert the first character to uppercase - className.replace(0, 1, className.left(1).toUpper()); - } - - return className; -} - -bool ClassNameValidatingLineEdit::lowerCaseFileName() const -{ - return m_d->m_lowerCaseFileName; -} - -void ClassNameValidatingLineEdit::setLowerCaseFileName(bool v) -{ - m_d->m_lowerCaseFileName = v; -} -} // namespace Utils diff --git a/ground/gcs/src/libs/utils/classnamevalidatinglineedit.h b/ground/gcs/src/libs/utils/classnamevalidatinglineedit.h deleted file mode 100644 index e656c6079c..0000000000 --- a/ground/gcs/src/libs/utils/classnamevalidatinglineedit.h +++ /dev/null @@ -1,75 +0,0 @@ -/** - ****************************************************************************** - * - * @file classnamevalidatinglineedit.h - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @brief - * @see The GNU Public License (GPL) Version 3 - * @defgroup - * @{ - * - *****************************************************************************/ -/* - * 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 CLASSNAMEVALIDATINGLINEEDIT_H -#define CLASSNAMEVALIDATINGLINEEDIT_H - -#include "utils_global.h" -#include "basevalidatinglineedit.h" - -namespace Utils { -struct ClassNameValidatingLineEditPrivate; - -/* A Line edit that validates a C++ class name and emits a signal - * to derive suggested file names from it. */ - -class QTCREATOR_UTILS_EXPORT ClassNameValidatingLineEdit - : public Utils::BaseValidatingLineEdit { - Q_DISABLE_COPY(ClassNameValidatingLineEdit) - Q_PROPERTY(bool namespacesEnabled READ namespacesEnabled WRITE setNamespacesEnabled DESIGNABLE true) - Q_PROPERTY(bool lowerCaseFileName READ lowerCaseFileName WRITE setLowerCaseFileName) - Q_OBJECT - -public: - explicit ClassNameValidatingLineEdit(QWidget *parent = 0); - virtual ~ClassNameValidatingLineEdit(); - - bool namespacesEnabled() const; - void setNamespacesEnabled(bool b); - - bool lowerCaseFileName() const; - void setLowerCaseFileName(bool v); - - // Clean an input string to get a valid class name. - static QString createClassName(const QString &name); - -signals: - // Will be emitted with a suggestion for a base name of the - // source/header file of the class. - void updateFileName(const QString &t); - -protected: - virtual bool validate(const QString &value, QString *errorMessage) const; - virtual void slotChanged(const QString &t); - -private: - ClassNameValidatingLineEditPrivate *m_d; -}; -} // namespace Utils - -#endif // CLASSNAMEVALIDATINGLINEEDIT_H diff --git a/ground/gcs/src/libs/utils/codegeneration.cpp b/ground/gcs/src/libs/utils/codegeneration.cpp deleted file mode 100644 index db9e640ea0..0000000000 --- a/ground/gcs/src/libs/utils/codegeneration.cpp +++ /dev/null @@ -1,105 +0,0 @@ -/** - ****************************************************************************** - * - * @file codegeneration.cpp - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @brief - * @see The GNU Public License (GPL) Version 3 - * @defgroup - * @{ - * - *****************************************************************************/ -/* - * 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 "codegeneration.h" - -#include -#include -#include - -namespace Utils { -QTCREATOR_UTILS_EXPORT QString fileNameToCppIdentifier(const QString &s) -{ - QString rc; - const int len = s.size(); - const QChar underscore = QLatin1Char('_'); - const QChar dot = QLatin1Char('.'); - - for (int i = 0; i < len; i++) { - const QChar c = s.at(i); - if (c == underscore || c.isLetterOrNumber()) { - rc += c; - } else if (c == dot) { - rc += underscore; - } - } - return rc; -} - -QTCREATOR_UTILS_EXPORT QString headerGuard(const QString &file) -{ - const QFileInfo fi(file); - QString rc = fileNameToCppIdentifier(fi.completeBaseName()).toUpper(); - - rc += QLatin1Char('_'); - rc += fileNameToCppIdentifier(fi.suffix()).toUpper(); - return rc; -} - -QTCREATOR_UTILS_EXPORT -void writeIncludeFileDirective(const QString &file, bool globalInclude, - QTextStream &str) -{ - const QChar opening = globalInclude ? QLatin1Char('<') : QLatin1Char('"'); - const QChar closing = globalInclude ? QLatin1Char('>') : QLatin1Char('"'); - - str << QLatin1String("#include ") << opening << file << closing << QLatin1Char('\n'); -} - -QTCREATOR_UTILS_EXPORT -QString writeOpeningNameSpaces(const QStringList &l, const QString &indent, - QTextStream &str) -{ - const int count = l.size(); - QString rc; - - if (count) { - str << '\n'; - for (int i = 0; i < count; i++) { - str << rc << "namespace " << l.at(i) << " {\n"; - rc += indent; - } - } - return rc; -} - -QTCREATOR_UTILS_EXPORT -void writeClosingNameSpaces(const QStringList &l, const QString &indent, - QTextStream &str) -{ - if (!l.empty()) { - str << '\n'; - } - for (int i = l.size() - 1; i >= 0; i--) { - if (i) { - str << QString(indent.size() * i, QLatin1Char(' ')); - } - str << "} // namespace " << l.at(i) << '\n'; - } -} -} // namespace Utils diff --git a/ground/gcs/src/libs/utils/codegeneration.h b/ground/gcs/src/libs/utils/codegeneration.h deleted file mode 100644 index bba0f8b3ae..0000000000 --- a/ground/gcs/src/libs/utils/codegeneration.h +++ /dev/null @@ -1,66 +0,0 @@ -/** - ****************************************************************************** - * - * @file codegeneration.h - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @brief - * @see The GNU Public License (GPL) Version 3 - * @defgroup - * @{ - * - *****************************************************************************/ -/* - * 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 CODEGENERATION_H -#define CODEGENERATION_H - -#include "utils_global.h" -#include - -QT_BEGIN_NAMESPACE -class QTextStream; -class QStringList; -QT_END_NAMESPACE - -namespace Utils { -// Convert a file name to a Cpp identifier (stripping invalid characters -// or replacing them by an underscore). -QTCREATOR_UTILS_EXPORT QString fileNameToCppIdentifier(const QString &s); - -QTCREATOR_UTILS_EXPORT QString headerGuard(const QString &file); - -QTCREATOR_UTILS_EXPORT -void writeIncludeFileDirective(const QString &file, - bool globalInclude, - QTextStream &str); - -// Write opening namespaces and return an indentation string to be used -// in the following code if there are any. -QTCREATOR_UTILS_EXPORT -QString writeOpeningNameSpaces(const QStringList &namespaces, - const QString &indent, - QTextStream &str); - -// Close namespacesnamespaces -QTCREATOR_UTILS_EXPORT -void writeClosingNameSpaces(const QStringList &namespaces, - const QString &indent, - QTextStream &str); -} // namespace Utils - -#endif // CODEGENERATION_H diff --git a/ground/gcs/src/libs/utils/filenamevalidatinglineedit.cpp b/ground/gcs/src/libs/utils/filenamevalidatinglineedit.cpp deleted file mode 100644 index 09fad9c86c..0000000000 --- a/ground/gcs/src/libs/utils/filenamevalidatinglineedit.cpp +++ /dev/null @@ -1,138 +0,0 @@ -/** - ****************************************************************************** - * - * @file filenamevalidatinglineedit.cpp - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @brief - * @see The GNU Public License (GPL) Version 3 - * @defgroup - * @{ - * - *****************************************************************************/ -/* - * 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 "filenamevalidatinglineedit.h" -#include "qtcassert.h" - -#include -#include - -namespace Utils { -#define WINDOWS_DEVICES "CON|AUX|PRN|COM1|COM2|LPT1|LPT2|NUL" - -// Naming a file like a device name will break on Windows, even if it is -// "com1.txt". Since we are cross-platform, we generally disallow such file -// names. -static const QRegExp &windowsDeviceNoSubDirPattern() -{ - static const QRegExp rc(QLatin1String(WINDOWS_DEVICES), - Qt::CaseInsensitive); - - QTC_ASSERT(rc.isValid(), return rc); - return rc; -} - -static const QRegExp &windowsDeviceSubDirPattern() -{ - static const QRegExp rc(QLatin1String(".*[/\\\\](" WINDOWS_DEVICES ")"), Qt::CaseInsensitive); - - QTC_ASSERT(rc.isValid(), return rc); - return rc; -} - -// ----------- FileNameValidatingLineEdit -FileNameValidatingLineEdit::FileNameValidatingLineEdit(QWidget *parent) : - BaseValidatingLineEdit(parent), - m_allowDirectories(false), - m_unused(0) -{} - -bool FileNameValidatingLineEdit::allowDirectories() const -{ - return m_allowDirectories; -} - -void FileNameValidatingLineEdit::setAllowDirectories(bool v) -{ - m_allowDirectories = v; -} - -/* Validate a file base name, check for forbidden characters/strings. */ - -#ifdef Q_OS_WIN -# define SLASHES "/\\" -#else -# define SLASHES "/" -#endif - -static const char *notAllowedCharsSubDir = "?:&*\"|#%<> "; -static const char *notAllowedCharsNoSubDir = "?:&*\"|#%<> " SLASHES; - -static const char *notAllowedSubStrings[] = { ".." }; - -bool FileNameValidatingLineEdit::validateFileName(const QString &name, - bool allowDirectories, - QString *errorMessage /* = 0*/) -{ - if (name.isEmpty()) { - if (errorMessage) { - *errorMessage = tr("The name must not be empty"); - } - return false; - } - // Characters - const char *notAllowedChars = allowDirectories ? notAllowedCharsSubDir : notAllowedCharsNoSubDir; - for (const char *c = notAllowedChars; *c; c++) { - if (name.contains(QLatin1Char(*c))) { - if (errorMessage) { - *errorMessage = tr("The name must not contain any of the characters '%1'.").arg(QLatin1String(notAllowedChars)); - } - return false; - } - } - // Substrings - const int notAllowedSubStringCount = sizeof(notAllowedSubStrings) / sizeof(const char *); - for (int s = 0; s < notAllowedSubStringCount; s++) { - const QLatin1String notAllowedSubString(notAllowedSubStrings[s]); - if (name.contains(notAllowedSubString)) { - if (errorMessage) { - *errorMessage = tr("The name must not contain '%1'.").arg(QString(notAllowedSubString)); - } - return false; - } - } - // Windows devices - bool matchesWinDevice = windowsDeviceNoSubDirPattern().exactMatch(name); - if (!matchesWinDevice && allowDirectories) { - matchesWinDevice = windowsDeviceSubDirPattern().exactMatch(name); - } - if (matchesWinDevice) { - if (errorMessage) { - *errorMessage = tr("The name must not match that of a MS Windows device. (%1)."). - arg(windowsDeviceNoSubDirPattern().pattern().replace(QLatin1Char('|'), QLatin1Char(','))); - } - return false; - } - return true; -} - -bool FileNameValidatingLineEdit::validate(const QString &value, QString *errorMessage) const -{ - return validateFileName(value, m_allowDirectories, errorMessage); -} -} // namespace Utils diff --git a/ground/gcs/src/libs/utils/filenamevalidatinglineedit.h b/ground/gcs/src/libs/utils/filenamevalidatinglineedit.h deleted file mode 100644 index 81e0436d78..0000000000 --- a/ground/gcs/src/libs/utils/filenamevalidatinglineedit.h +++ /dev/null @@ -1,65 +0,0 @@ -/** - ****************************************************************************** - * - * @file filenamevalidatinglineedit.h - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @brief - * @see The GNU Public License (GPL) Version 3 - * @defgroup - * @{ - * - *****************************************************************************/ -/* - * 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 FILENAMEVALIDATINGLINEEDIT_H -#define FILENAMEVALIDATINGLINEEDIT_H - -#include "basevalidatinglineedit.h" - -namespace Utils { -/** - * A control that let's the user choose a file name, based on a QLineEdit. Has - * some validation logic for embedding into QWizardPage. - */ -class QTCREATOR_UTILS_EXPORT FileNameValidatingLineEdit : public BaseValidatingLineEdit { - Q_OBJECT Q_DISABLE_COPY(FileNameValidatingLineEdit) - Q_PROPERTY(bool allowDirectories READ allowDirectories WRITE setAllowDirectories) -public: - explicit FileNameValidatingLineEdit(QWidget *parent = 0); - - static bool validateFileName(const QString &name, - bool allowDirectories = false, - QString *errorMessage = 0); - - /** - * Sets whether entering directories is allowed. This will enable the user - * to enter slashes in the filename. Default is off. - */ - bool allowDirectories() const; - void setAllowDirectories(bool v); - -protected: - virtual bool validate(const QString &value, QString *errorMessage) const; - -private: - bool m_allowDirectories; - void *m_unused; -}; -} // namespace Utils - -#endif // FILENAMEVALIDATINGLINEEDIT_H diff --git a/ground/gcs/src/libs/utils/filewizarddialog.cpp b/ground/gcs/src/libs/utils/filewizarddialog.cpp deleted file mode 100644 index 88fdb06163..0000000000 --- a/ground/gcs/src/libs/utils/filewizarddialog.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/** - ****************************************************************************** - * - * @file filewizarddialog.cpp - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @brief - * @see The GNU Public License (GPL) Version 3 - * @defgroup - * @{ - * - *****************************************************************************/ -/* - * 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 "filewizarddialog.h" -#include "filewizardpage.h" - -#include - -namespace Utils { -FileWizardDialog::FileWizardDialog(QWidget *parent) : - QWizard(parent), - m_filePage(new FileWizardPage) -{ - setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); - setOption(QWizard::NoCancelButton, false); - setOption(QWizard::NoDefaultButton, false); - setPixmap(QWizard::WatermarkPixmap, QPixmap(QLatin1String(":/core/images/qtwatermark.png"))); - addPage(m_filePage); - connect(m_filePage, SIGNAL(activated()), button(QWizard::FinishButton), SLOT(animateClick())); -} - -QString FileWizardDialog::name() const -{ - return m_filePage->name(); -} - -QString FileWizardDialog::path() const -{ - return m_filePage->path(); -} - -void FileWizardDialog::setPath(const QString &path) -{ - m_filePage->setPath(path); -} - -void FileWizardDialog::setName(const QString &name) -{ - m_filePage->setName(name); -} -} // namespace Utils diff --git a/ground/gcs/src/libs/utils/filewizarddialog.h b/ground/gcs/src/libs/utils/filewizarddialog.h deleted file mode 100644 index 88d1262bc9..0000000000 --- a/ground/gcs/src/libs/utils/filewizarddialog.h +++ /dev/null @@ -1,61 +0,0 @@ -/** - ****************************************************************************** - * - * @file filewizarddialog.h - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @brief - * @see The GNU Public License (GPL) Version 3 - * @defgroup - * @{ - * - *****************************************************************************/ -/* - * 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 FILEWIZARDDIALOG_H -#define FILEWIZARDDIALOG_H - -#include "utils_global.h" - -#include - -namespace Utils { -class FileWizardPage; - -/* - Standard wizard for a single file letting the user choose name - and path. Custom pages can be added via Core::IWizardExtension. - */ - -class QTCREATOR_UTILS_EXPORT FileWizardDialog : public QWizard { - Q_OBJECT Q_DISABLE_COPY(FileWizardDialog) -public: - explicit FileWizardDialog(QWidget *parent = 0); - - QString name() const; - QString path() const; - -public slots: - void setPath(const QString &path); - void setName(const QString &name); - -private: - FileWizardPage *m_filePage; -}; -} // namespace Utils - -#endif // FILEWIZARDDIALOG_H diff --git a/ground/gcs/src/libs/utils/filewizardpage.cpp b/ground/gcs/src/libs/utils/filewizardpage.cpp deleted file mode 100644 index f25fb3d4bc..0000000000 --- a/ground/gcs/src/libs/utils/filewizardpage.cpp +++ /dev/null @@ -1,129 +0,0 @@ -/** - ****************************************************************************** - * - * @file filewizardpage.cpp - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @brief - * @see The GNU Public License (GPL) Version 3 - * @defgroup - * @{ - * - *****************************************************************************/ -/* - * 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 "filewizardpage.h" -#include "ui_filewizardpage.h" - -namespace Utils { -struct FileWizardPagePrivate { - FileWizardPagePrivate(); - Ui::WizardPage m_ui; - bool m_complete; -}; - -FileWizardPagePrivate::FileWizardPagePrivate() : - m_complete(false) -{} - -FileWizardPage::FileWizardPage(QWidget *parent) : - QWizardPage(parent), - m_d(new FileWizardPagePrivate) -{ - m_d->m_ui.setupUi(this); - connect(m_d->m_ui.pathChooser, SIGNAL(validChanged()), this, SLOT(slotValidChanged())); - connect(m_d->m_ui.nameLineEdit, SIGNAL(validChanged()), this, SLOT(slotValidChanged())); - - connect(m_d->m_ui.pathChooser, SIGNAL(returnPressed()), this, SLOT(slotActivated())); - connect(m_d->m_ui.nameLineEdit, SIGNAL(validReturnPressed()), this, SLOT(slotActivated())); -} - -FileWizardPage::~FileWizardPage() -{ - delete m_d; -} - -QString FileWizardPage::name() const -{ - return m_d->m_ui.nameLineEdit->text(); -} - -QString FileWizardPage::path() const -{ - return m_d->m_ui.pathChooser->path(); -} - -void FileWizardPage::setPath(const QString &path) -{ - m_d->m_ui.pathChooser->setPath(path); -} - -void FileWizardPage::setName(const QString &name) -{ - m_d->m_ui.nameLineEdit->setText(name); -} - -void FileWizardPage::changeEvent(QEvent *e) -{ - QWizardPage::changeEvent(e); - - switch (e->type()) { - case QEvent::LanguageChange: - m_d->m_ui.retranslateUi(this); - break; - default: - break; - } -} - -bool FileWizardPage::isComplete() const -{ - return m_d->m_complete; -} - -void FileWizardPage::setNameLabel(const QString &label) -{ - m_d->m_ui.nameLabel->setText(label); -} - -void FileWizardPage::setPathLabel(const QString &label) -{ - m_d->m_ui.pathLabel->setText(label); -} - -void FileWizardPage::slotValidChanged() -{ - const bool newComplete = m_d->m_ui.pathChooser->isValid() && m_d->m_ui.nameLineEdit->isValid(); - - if (newComplete != m_d->m_complete) { - m_d->m_complete = newComplete; - emit completeChanged(); - } -} - -void FileWizardPage::slotActivated() -{ - if (m_d->m_complete) { - emit activated(); - } -} - -bool FileWizardPage::validateBaseName(const QString &name, QString *errorMessage /* = 0*/) -{ - return FileNameValidatingLineEdit::validateFileName(name, false, errorMessage); -} -} // namespace Utils diff --git a/ground/gcs/src/libs/utils/filewizardpage.h b/ground/gcs/src/libs/utils/filewizardpage.h deleted file mode 100644 index 569d31f0f9..0000000000 --- a/ground/gcs/src/libs/utils/filewizardpage.h +++ /dev/null @@ -1,85 +0,0 @@ -/** - ****************************************************************************** - * - * @file filewizardpage.h - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @brief - * @see The GNU Public License (GPL) Version 3 - * @defgroup - * @{ - * - *****************************************************************************/ -/* - * 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 FILEWIZARDPAGE_H -#define FILEWIZARDPAGE_H - -#include "utils_global.h" - -#include - -namespace Utils { -struct FileWizardPagePrivate; - -/** - * Standard wizard page for a single file letting the user choose name - * and path. Sets the "FileNames" QWizard field. - * - * The name and path labels can be changed. By default they are simply "Name:" - * and "Path:". - */ -class QTCREATOR_UTILS_EXPORT FileWizardPage : public QWizardPage { - Q_OBJECT Q_DISABLE_COPY(FileWizardPage) - Q_PROPERTY(QString path READ path WRITE setPath DESIGNABLE true) - Q_PROPERTY(QString name READ name WRITE setName DESIGNABLE true) -public: - explicit FileWizardPage(QWidget *parent = 0); - virtual ~FileWizardPage(); - - QString name() const; - QString path() const; - - virtual bool isComplete() const; - - void setNameLabel(const QString &label); - void setPathLabel(const QString &label); - - // Validate a base name entry field (potentially containing extension) - static bool validateBaseName(const QString &name, QString *errorMessage = 0); - -signals: - void activated(); - void pathChanged(); - -public slots: - void setPath(const QString &path); - void setName(const QString &name); - -private slots: - void slotValidChanged(); - void slotActivated(); - -protected: - virtual void changeEvent(QEvent *e); - -private: - FileWizardPagePrivate *m_d; -}; -} // namespace Utils - -#endif // FILEWIZARDPAGE_H diff --git a/ground/gcs/src/libs/utils/filewizardpage.ui b/ground/gcs/src/libs/utils/filewizardpage.ui deleted file mode 100644 index 2657a586bd..0000000000 --- a/ground/gcs/src/libs/utils/filewizardpage.ui +++ /dev/null @@ -1,54 +0,0 @@ - - - Utils::WizardPage - - - - 0 - 0 - 196 - 68 - - - - Choose the location - - - - - - Name: - - - - - - - - - - Path: - - - - - - - - - - - Utils::PathChooser - QWidget -
pathchooser.h
- 1 -
- - Utils::FileNameValidatingLineEdit - QLineEdit -
filenamevalidatinglineedit.h
-
-
- - -
diff --git a/ground/gcs/src/libs/utils/newclasswidget.cpp b/ground/gcs/src/libs/utils/newclasswidget.cpp deleted file mode 100644 index 74152983b7..0000000000 --- a/ground/gcs/src/libs/utils/newclasswidget.cpp +++ /dev/null @@ -1,535 +0,0 @@ -/** - ****************************************************************************** - * - * @file newclasswidget.cpp - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @brief - * @see The GNU Public License (GPL) Version 3 - * @defgroup - * @{ - * - *****************************************************************************/ -/* - * 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 "newclasswidget.h" -#include "ui_newclasswidget.h" - -#include - -#include -#include -#include -#include -#include -#include - -enum { debugNewClassWidget = 0 }; - -namespace Utils { -struct NewClassWidgetPrivate { - NewClassWidgetPrivate(); - - Ui::NewClassWidget m_ui; - QString m_headerExtension; - QString m_sourceExtension; - QString m_formExtension; - bool m_valid; - bool m_classEdited; - // Store the "visible" values to prevent the READ accessors from being - // fooled by a temporarily hidden widget - bool m_baseClassInputVisible; - bool m_formInputVisible; - bool m_pathInputVisible; - bool m_qobjectCheckBoxVisible; - bool m_formInputCheckable; -}; - -NewClassWidgetPrivate::NewClassWidgetPrivate() : - m_headerExtension(QLatin1String("h")), - m_sourceExtension(QLatin1String("cpp")), - m_formExtension(QLatin1String("ui")), - m_valid(false), - m_classEdited(false), - m_baseClassInputVisible(true), - m_formInputVisible(true), - m_pathInputVisible(true), - m_qobjectCheckBoxVisible(false), - m_formInputCheckable(false) - -{} - -// --------------------- NewClassWidget -NewClassWidget::NewClassWidget(QWidget *parent) : - QWidget(parent), - m_d(new NewClassWidgetPrivate) -{ - m_d->m_ui.setupUi(this); - - m_d->m_ui.baseClassComboBox->setEditable(false); - - connect(m_d->m_ui.classLineEdit, SIGNAL(updateFileName(QString)), - this, SLOT(slotUpdateFileNames(QString))); - connect(m_d->m_ui.classLineEdit, SIGNAL(textEdited(QString)), - this, SLOT(classNameEdited())); - connect(m_d->m_ui.baseClassComboBox, SIGNAL(currentIndexChanged(int)), - this, SLOT(suggestClassNameFromBase())); - connect(m_d->m_ui.baseClassComboBox, SIGNAL(editTextChanged(QString)), - this, SLOT(slotValidChanged())); - connect(m_d->m_ui.classLineEdit, SIGNAL(validChanged()), - this, SLOT(slotValidChanged())); - connect(m_d->m_ui.headerFileLineEdit, SIGNAL(validChanged()), - this, SLOT(slotValidChanged())); - connect(m_d->m_ui.sourceFileLineEdit, SIGNAL(validChanged()), - this, SLOT(slotValidChanged())); - connect(m_d->m_ui.formFileLineEdit, SIGNAL(validChanged()), - this, SLOT(slotValidChanged())); - connect(m_d->m_ui.pathChooser, SIGNAL(validChanged()), - this, SLOT(slotValidChanged())); - - connect(m_d->m_ui.classLineEdit, SIGNAL(validReturnPressed()), - this, SLOT(slotActivated())); - connect(m_d->m_ui.headerFileLineEdit, SIGNAL(validReturnPressed()), - this, SLOT(slotActivated())); - connect(m_d->m_ui.sourceFileLineEdit, SIGNAL(validReturnPressed()), - this, SLOT(slotActivated())); - connect(m_d->m_ui.formFileLineEdit, SIGNAL(validReturnPressed()), - this, SLOT(slotActivated())); - connect(m_d->m_ui.formFileLineEdit, SIGNAL(validReturnPressed()), - this, SLOT(slotActivated())); - connect(m_d->m_ui.pathChooser, SIGNAL(returnPressed()), - this, SLOT(slotActivated())); - - connect(m_d->m_ui.generateFormCheckBox, SIGNAL(stateChanged(int)), - this, SLOT(slotFormInputChecked())); - - m_d->m_ui.generateFormCheckBox->setChecked(true); - setFormInputCheckable(false, true); - setClassType(NoClassType); -} - -NewClassWidget::~NewClassWidget() -{ - delete m_d; -} - -void NewClassWidget::classNameEdited() -{ - if (debugNewClassWidget) { - qDebug() << Q_FUNC_INFO << m_d->m_headerExtension << m_d->m_sourceExtension; - } - m_d->m_classEdited = true; -} - -void NewClassWidget::suggestClassNameFromBase() -{ - if (debugNewClassWidget) { - qDebug() << Q_FUNC_INFO << m_d->m_headerExtension << m_d->m_sourceExtension; - } - if (m_d->m_classEdited) { - return; - } - // Suggest a class unless edited ("QMainWindow"->"MainWindow") - QString base = baseClassName(); - if (base.startsWith(QLatin1Char('Q'))) { - base.remove(0, 1); - setClassName(base); - } -} - -QStringList NewClassWidget::baseClassChoices() const -{ - QStringList rc; - const int count = m_d->m_ui.baseClassComboBox->count(); - - for (int i = 0; i < count; i++) { - rc.push_back(m_d->m_ui.baseClassComboBox->itemText(i)); - } - return rc; -} - -void NewClassWidget::setBaseClassChoices(const QStringList &choices) -{ - m_d->m_ui.baseClassComboBox->clear(); - m_d->m_ui.baseClassComboBox->addItems(choices); -} - -void NewClassWidget::setBaseClassInputVisible(bool visible) -{ - m_d->m_baseClassInputVisible = visible; - m_d->m_ui.baseClassLabel->setVisible(visible); - m_d->m_ui.baseClassComboBox->setVisible(visible); -} - -void NewClassWidget::setBaseClassEditable(bool editable) -{ - m_d->m_ui.baseClassComboBox->setEditable(editable); -} - -bool NewClassWidget::isBaseClassInputVisible() const -{ - return m_d->m_baseClassInputVisible; -} - -bool NewClassWidget::isBaseClassEditable() const -{ - return m_d->m_ui.baseClassComboBox->isEditable(); -} - -void NewClassWidget::setFormInputVisible(bool visible) -{ - m_d->m_formInputVisible = visible; - m_d->m_ui.formLabel->setVisible(visible); - m_d->m_ui.formFileLineEdit->setVisible(visible); -} - -bool NewClassWidget::isFormInputVisible() const -{ - return m_d->m_formInputVisible; -} - -void NewClassWidget::setFormInputCheckable(bool checkable) -{ - setFormInputCheckable(checkable, false); -} - -void NewClassWidget::setFormInputCheckable(bool checkable, bool force) -{ - if (!force && checkable == m_d->m_formInputCheckable) { - return; - } - m_d->m_formInputCheckable = checkable; - m_d->m_ui.generateFormLabel->setVisible(checkable); - m_d->m_ui.generateFormCheckBox->setVisible(checkable); -} - -void NewClassWidget::setFormInputChecked(bool v) -{ - m_d->m_ui.generateFormCheckBox->setChecked(v); -} - -bool NewClassWidget::formInputCheckable() const -{ - return m_d->m_formInputCheckable; -} - -bool NewClassWidget::formInputChecked() const -{ - return m_d->m_ui.generateFormCheckBox->isChecked(); -} - -void NewClassWidget::slotFormInputChecked() -{ - const bool checked = formInputChecked(); - - m_d->m_ui.formLabel->setEnabled(checked); - m_d->m_ui.formFileLineEdit->setEnabled(checked); -} - -void NewClassWidget::setPathInputVisible(bool visible) -{ - m_d->m_pathInputVisible = visible; - m_d->m_ui.pathLabel->setVisible(visible); - m_d->m_ui.pathChooser->setVisible(visible); -} - -bool NewClassWidget::isPathInputVisible() const -{ - return m_d->m_pathInputVisible; -} - -void NewClassWidget::setClassName(const QString &suggestedName) -{ - if (debugNewClassWidget) { - qDebug() << Q_FUNC_INFO << suggestedName << m_d->m_headerExtension << m_d->m_sourceExtension; - } - m_d->m_ui.classLineEdit->setText(ClassNameValidatingLineEdit::createClassName(suggestedName)); -} - -QString NewClassWidget::className() const -{ - return m_d->m_ui.classLineEdit->text(); -} - -QString NewClassWidget::baseClassName() const -{ - return m_d->m_ui.baseClassComboBox->currentText(); -} - -void NewClassWidget::setBaseClassName(const QString &c) -{ - const int index = m_d->m_ui.baseClassComboBox->findText(c); - - if (index != -1) { - m_d->m_ui.baseClassComboBox->setCurrentIndex(index); - suggestClassNameFromBase(); - } -} - -QString NewClassWidget::sourceFileName() const -{ - return m_d->m_ui.sourceFileLineEdit->text(); -} - -QString NewClassWidget::headerFileName() const -{ - return m_d->m_ui.headerFileLineEdit->text(); -} - -QString NewClassWidget::formFileName() const -{ - return m_d->m_ui.formFileLineEdit->text(); -} - -QString NewClassWidget::path() const -{ - return m_d->m_ui.pathChooser->path(); -} - -void NewClassWidget::setPath(const QString &path) -{ - m_d->m_ui.pathChooser->setPath(path); -} - -bool NewClassWidget::namespacesEnabled() const -{ - return m_d->m_ui.classLineEdit->namespacesEnabled(); -} - -void NewClassWidget::setNamespacesEnabled(bool b) -{ - m_d->m_ui.classLineEdit->setNamespacesEnabled(b); -} - -QString NewClassWidget::sourceExtension() const -{ - return m_d->m_sourceExtension; -} - -void NewClassWidget::setSourceExtension(const QString &e) -{ - if (debugNewClassWidget) { - qDebug() << Q_FUNC_INFO << e; - } - m_d->m_sourceExtension = fixSuffix(e); -} - -QString NewClassWidget::headerExtension() const -{ - return m_d->m_headerExtension; -} - -void NewClassWidget::setHeaderExtension(const QString &e) -{ - if (debugNewClassWidget) { - qDebug() << Q_FUNC_INFO << e; - } - m_d->m_headerExtension = fixSuffix(e); -} - -QString NewClassWidget::formExtension() const -{ - return m_d->m_formExtension; -} - -void NewClassWidget::setFormExtension(const QString &e) -{ - if (debugNewClassWidget) { - qDebug() << Q_FUNC_INFO << e; - } - m_d->m_formExtension = fixSuffix(e); -} - -bool NewClassWidget::allowDirectories() const -{ - return m_d->m_ui.headerFileLineEdit->allowDirectories(); -} - -void NewClassWidget::setAllowDirectories(bool v) -{ - // We keep all in sync - if (allowDirectories() != v) { - m_d->m_ui.sourceFileLineEdit->setAllowDirectories(v); - m_d->m_ui.headerFileLineEdit->setAllowDirectories(v); - m_d->m_ui.formFileLineEdit->setAllowDirectories(v); - } -} - -bool NewClassWidget::lowerCaseFiles() const -{ - return m_d->m_ui.classLineEdit->lowerCaseFileName(); -} - -void NewClassWidget::setLowerCaseFiles(bool v) -{ - m_d->m_ui.classLineEdit->setLowerCaseFileName(v); -} - -NewClassWidget::ClassType NewClassWidget::classType() const -{ - return static_cast(m_d->m_ui.classTypeComboBox->currentIndex()); -} - -void NewClassWidget::setClassType(ClassType ct) -{ - m_d->m_ui.classTypeComboBox->setCurrentIndex(ct); -} - -bool NewClassWidget::isClassTypeComboVisible() const -{ - return m_d->m_ui.classTypeLabel->isVisible(); -} - -void NewClassWidget::setClassTypeComboVisible(bool v) -{ - m_d->m_ui.classTypeLabel->setVisible(v); - m_d->m_ui.classTypeComboBox->setVisible(v); -} - -void NewClassWidget::slotValidChanged() -{ - const bool newValid = isValid(); - - if (newValid != m_d->m_valid) { - m_d->m_valid = newValid; - emit validChanged(); - } -} - -bool NewClassWidget::isValid(QString *error) const -{ - if (!m_d->m_ui.classLineEdit->isValid()) { - if (error) { - *error = m_d->m_ui.classLineEdit->errorMessage(); - } - return false; - } - - if (isBaseClassInputVisible() && isBaseClassEditable()) { - // TODO: Should this be a ClassNameValidatingComboBox? - QRegExp classNameValidator(QLatin1String("[a-zA-Z_][a-zA-Z0-9_]*(::[a-zA-Z_][a-zA-Z0-9_]*)*")); - const QString baseClass = m_d->m_ui.baseClassComboBox->currentText().trimmed(); - if (!baseClass.isEmpty() && !classNameValidator.exactMatch(baseClass)) { - if (error) { - *error = tr("Invalid base class name"); - } - return false; - } - } - - if (!m_d->m_ui.headerFileLineEdit->isValid()) { - if (error) { - *error = tr("Invalid header file name: '%1'").arg(m_d->m_ui.headerFileLineEdit->errorMessage()); - } - return false; - } - - if (!m_d->m_ui.sourceFileLineEdit->isValid()) { - if (error) { - *error = tr("Invalid source file name: '%1'").arg(m_d->m_ui.sourceFileLineEdit->errorMessage()); - } - return false; - } - - if (isFormInputVisible()) { - if (!m_d->m_ui.formFileLineEdit->isValid()) { - if (error) { - *error = tr("Invalid form file name: '%1'").arg(m_d->m_ui.formFileLineEdit->errorMessage()); - } - return false; - } - } - - if (isPathInputVisible()) { - if (!m_d->m_ui.pathChooser->isValid()) { - if (error) { - *error = m_d->m_ui.pathChooser->errorMessage(); - } - return false; - } - } - return true; -} - -void NewClassWidget::triggerUpdateFileNames() -{ - m_d->m_ui.classLineEdit->triggerChanged(); -} - -void NewClassWidget::slotUpdateFileNames(const QString &baseName) -{ - if (debugNewClassWidget) { - qDebug() << Q_FUNC_INFO << baseName << m_d->m_headerExtension << m_d->m_sourceExtension; - } - const QChar dot = QLatin1Char('.'); - m_d->m_ui.sourceFileLineEdit->setText(baseName + dot + m_d->m_sourceExtension); - m_d->m_ui.headerFileLineEdit->setText(baseName + dot + m_d->m_headerExtension); - m_d->m_ui.formFileLineEdit->setText(baseName + dot + m_d->m_formExtension); -} - -void NewClassWidget::slotActivated() -{ - if (m_d->m_valid) { - emit activated(); - } -} - -QString NewClassWidget::fixSuffix(const QString &suffix) -{ - QString s = suffix; - - if (s.startsWith(QLatin1Char('.'))) { - s.remove(0, 1); - } - return s; -} - -// Utility to add a suffix to a file unless the user specified one -static QString ensureSuffix(QString f, const QString &extension) -{ - const QChar dot = QLatin1Char('.'); - - if (f.contains(dot)) { - return f; - } - f += dot; - f += extension; - return f; -} - -// If a non-empty name was passed, expand to directory and suffix -static QString expandFileName(const QDir &dir, const QString name, const QString &extension) -{ - if (name.isEmpty()) { - return QString(); - } - return dir.absoluteFilePath(ensureSuffix(name, extension)); -} - -QStringList NewClassWidget::files() const -{ - QStringList rc; - const QDir dir = QDir(path()); - - rc.push_back(expandFileName(dir, headerFileName(), headerExtension())); - rc.push_back(expandFileName(dir, sourceFileName(), sourceExtension())); - if (isFormInputVisible()) { - rc.push_back(expandFileName(dir, formFileName(), formExtension())); - } - return rc; -} -} // namespace Utils diff --git a/ground/gcs/src/libs/utils/newclasswidget.h b/ground/gcs/src/libs/utils/newclasswidget.h deleted file mode 100644 index ccb89162d5..0000000000 --- a/ground/gcs/src/libs/utils/newclasswidget.h +++ /dev/null @@ -1,163 +0,0 @@ -/** - ****************************************************************************** - * - * @file newclasswidget.h - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @brief - * @see The GNU Public License (GPL) Version 3 - * @defgroup - * @{ - * - *****************************************************************************/ -/* - * 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 NEWCLASSWIDGET_H -#define NEWCLASSWIDGET_H - -#include "utils_global.h" - -#include - -QT_BEGIN_NAMESPACE -class QStringList; -QT_END_NAMESPACE - -namespace Utils { -struct NewClassWidgetPrivate; - -/** - * NewClassWidget: Utility widget for 'New Class' wizards. Prompts the user - * to enter a class name (optionally derived from some base class) and file - * names for header, source and form files. Has some smart logic to derive - * the file names from the class name. - */ -class QTCREATOR_UTILS_EXPORT NewClassWidget : public QWidget { - Q_DISABLE_COPY(NewClassWidget) - Q_OBJECT Q_PROPERTY(bool namespacesEnabled READ namespacesEnabled WRITE setNamespacesEnabled DESIGNABLE true) - Q_PROPERTY(bool baseClassInputVisible READ isBaseClassInputVisible WRITE setBaseClassInputVisible DESIGNABLE true) - Q_PROPERTY(bool baseClassEditable READ isBaseClassEditable WRITE setBaseClassEditable DESIGNABLE false) - Q_PROPERTY(bool formInputVisible READ isFormInputVisible WRITE setFormInputVisible DESIGNABLE true) - Q_PROPERTY(bool pathInputVisible READ isPathInputVisible WRITE setPathInputVisible DESIGNABLE true) - Q_PROPERTY(bool classTypeComboVisible READ isClassTypeComboVisible WRITE setClassTypeComboVisible DESIGNABLE true) - Q_PROPERTY(QString className READ className WRITE setClassName DESIGNABLE true) - Q_PROPERTY(QString baseClassName READ baseClassName WRITE setBaseClassName DESIGNABLE true) - Q_PROPERTY(QString sourceFileName READ sourceFileName DESIGNABLE false) - Q_PROPERTY(QString headerFileName READ headerFileName DESIGNABLE false) - Q_PROPERTY(QString formFileName READ formFileName DESIGNABLE false) - Q_PROPERTY(QString path READ path WRITE setPath DESIGNABLE true) - Q_PROPERTY(QStringList baseClassChoices READ baseClassChoices WRITE setBaseClassChoices DESIGNABLE true) - Q_PROPERTY(QString sourceExtension READ sourceExtension WRITE setSourceExtension DESIGNABLE true) - Q_PROPERTY(QString headerExtension READ headerExtension WRITE setHeaderExtension DESIGNABLE true) - Q_PROPERTY(QString formExtension READ formExtension WRITE setFormExtension DESIGNABLE true) - Q_PROPERTY(bool formInputCheckable READ formInputCheckable WRITE setFormInputCheckable DESIGNABLE true) - Q_PROPERTY(bool formInputChecked READ formInputChecked WRITE setFormInputChecked DESIGNABLE true) - Q_PROPERTY(bool allowDirectories READ allowDirectories WRITE setAllowDirectories) - Q_PROPERTY(bool lowerCaseFiles READ lowerCaseFiles WRITE setLowerCaseFiles) - Q_PROPERTY(ClassType classType READ classType WRITE setClassType) - // Utility "USER" property for wizards containing file names. - Q_PROPERTY(QStringList files READ files DESIGNABLE false USER true) - Q_ENUMS(ClassType) -public: - enum ClassType { NoClassType, ClassInheritsQObject, ClassInheritsQWidget }; - - explicit NewClassWidget(QWidget *parent = 0); - ~NewClassWidget(); - - bool namespacesEnabled() const; - bool isBaseClassInputVisible() const; - bool isBaseClassEditable() const; - bool isFormInputVisible() const; - bool isPathInputVisible() const; - bool formInputCheckable() const; - bool formInputChecked() const; - - QString className() const; - QString baseClassName() const; - QString sourceFileName() const; - QString headerFileName() const; - QString formFileName() const; - QString path() const; - QStringList baseClassChoices() const; - QString sourceExtension() const; - QString headerExtension() const; - QString formExtension() const; - bool allowDirectories() const; - bool lowerCaseFiles() const; - ClassType classType() const; - bool isClassTypeComboVisible() const; - - bool isValid(QString *error = 0) const; - - QStringList files() const; - -signals: - void validChanged(); - void activated(); - -public slots: - void setNamespacesEnabled(bool b); - void setBaseClassInputVisible(bool visible); - void setBaseClassEditable(bool editable); - void setFormInputVisible(bool visible); - void setPathInputVisible(bool visible); - void setFormInputCheckable(bool v); - void setFormInputChecked(bool v); - - /** - * The name passed into the new class widget will be reformatted to be a - * valid class name. - */ - void setClassName(const QString &suggestedName); - void setBaseClassName(const QString &); - void setPath(const QString &path); - void setBaseClassChoices(const QStringList &choices); - void setSourceExtension(const QString &e); - void setHeaderExtension(const QString &e); - void setFormExtension(const QString &e); - void setAllowDirectories(bool v); - void setLowerCaseFiles(bool v); - void setClassType(ClassType ct); - void setClassTypeComboVisible(bool v); - - /** - * Suggest a class name from the base class by stripping the leading 'Q' - * character. This will happen automagically if the base class combo - * changes until the class line edited is manually edited. - */ - void suggestClassNameFromBase(); - -public slots: - /** Trigger an update (after changing settings) */ - void triggerUpdateFileNames(); - -private slots: - void slotUpdateFileNames(const QString &t); - void slotValidChanged(); - void slotActivated(); - void classNameEdited(); - void slotFormInputChecked(); - -private: - void setFormInputCheckable(bool checkable, bool force); - - QString fixSuffix(const QString &suffix); - NewClassWidgetPrivate *m_d; -}; -} // namespace Utils - -#endif // NEWCLASSWIDGET_H diff --git a/ground/gcs/src/libs/utils/newclasswidget.ui b/ground/gcs/src/libs/utils/newclasswidget.ui deleted file mode 100644 index 2e725644bc..0000000000 --- a/ground/gcs/src/libs/utils/newclasswidget.ui +++ /dev/null @@ -1,181 +0,0 @@ - - - Utils::NewClassWidget - - - - 0 - 0 - 418 - 291 - - - - - QFormLayout::ExpandingFieldsGrow - - - 0 - - - - - Class name: - - - - - - - - - - Base class: - - - - - - - - 0 - 0 - - - - - - - - Type information: - - - - - - - - None - - - - - Inherits QObject - - - - - Inherits QWidget - - - - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 0 - 0 - - - - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 0 - 0 - - - - - - - - Header file: - - - - - - - - - - Source file: - - - - - - - - - - Generate form: - - - - - - - - - - - - - - Form file: - - - - - - - - - - Path: - - - - - - - - - - - Utils::ClassNameValidatingLineEdit - QLineEdit -
utils/classnamevalidatinglineedit.h
-
- - Utils::FileNameValidatingLineEdit - QLineEdit -
utils/filenamevalidatinglineedit.h
-
- - Utils::PathChooser - QWidget -
utils/pathchooser.h
- 1 -
-
- - -
diff --git a/ground/gcs/src/libs/utils/parameteraction.cpp b/ground/gcs/src/libs/utils/parameteraction.cpp deleted file mode 100644 index 74e5cde8d5..0000000000 --- a/ground/gcs/src/libs/utils/parameteraction.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/** - ****************************************************************************** - * - * @file parameteraction.cpp - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @brief - * @see The GNU Public License (GPL) Version 3 - * @defgroup - * @{ - * - *****************************************************************************/ -/* - * 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 "parameteraction.h" - -namespace Utils { -ParameterAction::ParameterAction(const QString &emptyText, - const QString ¶meterText, - EnablingMode mode, - QObject *parent) : - QAction(emptyText, parent), - m_emptyText(emptyText), - m_parameterText(parameterText), - m_enablingMode(mode) -{} - -QString ParameterAction::emptyText() const -{ - return m_emptyText; -} - -void ParameterAction::setEmptyText(const QString &t) -{ - m_emptyText = t; -} - -QString ParameterAction::parameterText() const -{ - return m_parameterText; -} - -void ParameterAction::setParameterText(const QString &t) -{ - m_parameterText = t; -} - -ParameterAction::EnablingMode ParameterAction::enablingMode() const -{ - return m_enablingMode; -} - -void ParameterAction::setEnablingMode(EnablingMode m) -{ - m_enablingMode = m; -} - -void ParameterAction::setParameter(const QString &p) -{ - const bool enabled = !p.isEmpty(); - - if (enabled) { - setText(m_parameterText.arg(p)); - } else { - setText(m_emptyText); - } - if (m_enablingMode == EnabledWithParameter) { - setEnabled(enabled); - } -} -} diff --git a/ground/gcs/src/libs/utils/parameteraction.h b/ground/gcs/src/libs/utils/parameteraction.h deleted file mode 100644 index 52cee193f6..0000000000 --- a/ground/gcs/src/libs/utils/parameteraction.h +++ /dev/null @@ -1,79 +0,0 @@ -/** - ****************************************************************************** - * - * @file parameteraction.h - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @brief - * @see The GNU Public License (GPL) Version 3 - * @defgroup - * @{ - * - *****************************************************************************/ -/* - * 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 PARAMETERACTION_H -#define PARAMETERACTION_H - -#include "utils_global.h" - -#include - -namespace Utils { -/* ParameterAction: Intended for actions that act on a 'current', - * string-type parameter (typically file name) and have 2 states: - * 1) displaying "Do XX" (empty text) - * 2) displaying "Do XX with %1". - * Provides a slot to set the parameter, changing display - * and enabled state accordingly. - * The text passed in should already be translated; parameterText - * should contain a %1 where the parameter is to be inserted. */ - -class QTCREATOR_UTILS_EXPORT ParameterAction : public QAction { - Q_ENUMS(EnablingMode) - Q_PROPERTY(QString emptyText READ emptyText WRITE setEmptyText) - Q_PROPERTY(QString parameterText READ parameterText WRITE setParameterText) - Q_PROPERTY(EnablingMode enablingMode READ enablingMode WRITE setEnablingMode) - Q_OBJECT -public: - enum EnablingMode { AlwaysEnabled, EnabledWithParameter }; - - explicit ParameterAction(const QString &emptyText, - const QString ¶meterText, - EnablingMode em = AlwaysEnabled, - QObject *parent = 0); - - QString emptyText() const; - void setEmptyText(const QString &); - - QString parameterText() const; - void setParameterText(const QString &); - - EnablingMode enablingMode() const; - void setEnablingMode(EnablingMode m); - -public slots: - void setParameter(const QString &); - -private: - QString m_emptyText; - QString m_parameterText; - EnablingMode m_enablingMode; -}; -} - -#endif // PARAMETERACTION_H diff --git a/ground/gcs/src/libs/utils/pathlisteditor.cpp b/ground/gcs/src/libs/utils/pathlisteditor.cpp deleted file mode 100644 index 92c3eed99c..0000000000 --- a/ground/gcs/src/libs/utils/pathlisteditor.cpp +++ /dev/null @@ -1,324 +0,0 @@ -/** - ****************************************************************************** - * - * @file pathlisteditor.cpp - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @brief - * @see The GNU Public License (GPL) Version 3 - * @defgroup - * @{ - * - *****************************************************************************/ -/* - * 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 "pathlisteditor.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -namespace Utils { -// ------------ PathListPlainTextEdit: -// Replaces the platform separator ';',':' by '\n' -// when inserting, allowing for pasting in paths -// from the terminal or such. - -class PathListPlainTextEdit : public QPlainTextEdit { -public: - explicit PathListPlainTextEdit(QWidget *parent = 0); -protected: - virtual void insertFromMimeData(const QMimeData *source); -}; - -PathListPlainTextEdit::PathListPlainTextEdit(QWidget *parent) : - QPlainTextEdit(parent) -{ - // No wrapping, scroll at all events - setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); - setLineWrapMode(QPlainTextEdit::NoWrap); -} - -void PathListPlainTextEdit::insertFromMimeData(const QMimeData *source) -{ - if (source->hasText()) { - // replace separator - QString text = source->text().trimmed(); - text.replace(PathListEditor::separator(), QLatin1Char('\n')); - QSharedPointer fixed(new QMimeData); - fixed->setText(text); - QPlainTextEdit::insertFromMimeData(fixed.data()); - } else { - QPlainTextEdit::insertFromMimeData(source); - } -} - -// ------------ PathListEditorPrivate -struct PathListEditorPrivate { - PathListEditorPrivate(); - - QHBoxLayout *layout; - QVBoxLayout *buttonLayout; - QToolButton *toolButton; - QMenu *buttonMenu; - QPlainTextEdit *edit; - QSignalMapper *envVarMapper; - QString fileDialogTitle; -}; - -PathListEditorPrivate::PathListEditorPrivate() : - layout(new QHBoxLayout), - buttonLayout(new QVBoxLayout), - toolButton(new QToolButton), - buttonMenu(new QMenu), - edit(new PathListPlainTextEdit), - envVarMapper(0) -{ - layout->setMargin(0); - layout->addWidget(edit); - buttonLayout->addWidget(toolButton); - buttonLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Ignored, QSizePolicy::MinimumExpanding)); - layout->addLayout(buttonLayout); -} - -PathListEditor::PathListEditor(QWidget *parent) : - QWidget(parent), - m_d(new PathListEditorPrivate) -{ - setLayout(m_d->layout); - m_d->toolButton->setPopupMode(QToolButton::MenuButtonPopup); - m_d->toolButton->setText(tr("Insert...")); - m_d->toolButton->setMenu(m_d->buttonMenu); - connect(m_d->toolButton, SIGNAL(clicked()), this, SLOT(slotInsert())); - - addAction(tr("Add..."), this, SLOT(slotAdd())); - addAction(tr("Delete line"), this, SLOT(deletePathAtCursor())); - addAction(tr("Clear"), this, SLOT(clear())); -} - -PathListEditor::~PathListEditor() -{ - delete m_d; -} - -static inline QAction *createAction(QObject *parent, const QString &text, QObject *receiver, const char *slotFunc) -{ - QAction *rc = new QAction(text, parent); - QObject::connect(rc, SIGNAL(triggered()), receiver, slotFunc); - - return rc; -} - -QAction *PathListEditor::addAction(const QString &text, QObject *receiver, const char *slotFunc) -{ - QAction *rc = createAction(this, text, receiver, slotFunc); - - m_d->buttonMenu->addAction(rc); - return rc; -} - -QAction *PathListEditor::insertAction(int index /* -1 */, const QString &text, QObject *receiver, const char *slotFunc) -{ - // Find the 'before' action - QAction *beforeAction = 0; - - if (index >= 0) { - const QList actions = m_d->buttonMenu->actions(); - if (index < actions.size()) { - beforeAction = actions.at(index); - } - } - QAction *rc = createAction(this, text, receiver, slotFunc); - if (beforeAction) { - m_d->buttonMenu->insertAction(beforeAction, rc); - } else { - m_d->buttonMenu->addAction(rc); - } - return rc; -} - -int PathListEditor::lastAddActionIndex() -{ - return 0; // Insert/Add -} - -QString PathListEditor::pathListString() const -{ - return pathList().join(separator()); -} - -QStringList PathListEditor::pathList() const -{ - const QString text = m_d->edit->toPlainText().trimmed(); - - if (text.isEmpty()) { - return QStringList(); - } - // trim each line - QStringList rc = text.split(QLatin1Char('\n'), QString::SkipEmptyParts); - const QStringList::iterator end = rc.end(); - for (QStringList::iterator it = rc.begin(); it != end; ++it) { - *it = it->trimmed(); - } - return rc; -} - -void PathListEditor::setPathList(const QStringList &l) -{ - m_d->edit->setPlainText(l.join(QString(QLatin1Char('\n')))); -} - -void PathListEditor::setPathList(const QString &pathString) -{ - if (pathString.isEmpty()) { - clear(); - } else { - setPathList(pathString.split(separator(), QString::SkipEmptyParts)); - } -} - -void PathListEditor::setPathListFromEnvVariable(const QString &var) -{ - setPathList(qgetenv(var.toLocal8Bit())); -} - -QString PathListEditor::fileDialogTitle() const -{ - return m_d->fileDialogTitle; -} - -void PathListEditor::setFileDialogTitle(const QString &l) -{ - m_d->fileDialogTitle = l; -} - -void PathListEditor::clear() -{ - m_d->edit->clear(); -} - -void PathListEditor::slotAdd() -{ - const QString dir = QFileDialog::getExistingDirectory(this, m_d->fileDialogTitle); - - if (!dir.isEmpty()) { - appendPath(QDir::toNativeSeparators(dir)); - } -} - -void PathListEditor::slotInsert() -{ - const QString dir = QFileDialog::getExistingDirectory(this, m_d->fileDialogTitle); - - if (!dir.isEmpty()) { - insertPathAtCursor(QDir::toNativeSeparators(dir)); - } -} - -QChar PathListEditor::separator() -{ -#ifdef Q_OS_WIN - static const QChar rc(QLatin1Char(';')); -#else - static const QChar rc(QLatin1Char(':')); -#endif - return rc; -} - -// Add a button "Import from 'Path'" -void PathListEditor::addEnvVariableImportAction(const QString &var) -{ - if (!m_d->envVarMapper) { - m_d->envVarMapper = new QSignalMapper(this); - connect(m_d->envVarMapper, SIGNAL(mapped(QString)), this, SLOT(setPathListFromEnvVariable(QString))); - } - - QAction *a = insertAction(lastAddActionIndex() + 1, - tr("From \"%1\"").arg(var), m_d->envVarMapper, SLOT(map())); - m_d->envVarMapper->setMapping(a, var); -} - -QString PathListEditor::text() const -{ - return m_d->edit->toPlainText(); -} - -void PathListEditor::setText(const QString &t) -{ - m_d->edit->setPlainText(t); -} - -void PathListEditor::insertPathAtCursor(const QString &path) -{ - // If the cursor is at an empty line or at end(), - // just insert. Else insert line before - QTextCursor cursor = m_d->edit->textCursor(); - QTextBlock block = cursor.block(); - const bool needNewLine = !block.text().isEmpty(); - - if (needNewLine) { - cursor.movePosition(QTextCursor::StartOfLine, QTextCursor::MoveAnchor); - cursor.insertBlock(); - cursor.movePosition(QTextCursor::PreviousBlock, QTextCursor::MoveAnchor); - } - cursor.insertText(path); - if (needNewLine) { - cursor.movePosition(QTextCursor::StartOfLine, QTextCursor::MoveAnchor); - m_d->edit->setTextCursor(cursor); - } -} - -void PathListEditor::appendPath(const QString &path) -{ - QString paths = text().trimmed(); - - if (!paths.isEmpty()) { - paths += QLatin1Char('\n'); - } - paths += path; - setText(paths); -} - -void PathListEditor::deletePathAtCursor() -{ - // Delete current line - QTextCursor cursor = m_d->edit->textCursor(); - - if (cursor.block().isValid()) { - cursor.movePosition(QTextCursor::StartOfLine, QTextCursor::MoveAnchor); - // Select down or until end of [last] line - if (!cursor.movePosition(QTextCursor::Down, QTextCursor::KeepAnchor)) { - cursor.movePosition(QTextCursor::EndOfLine, QTextCursor::KeepAnchor); - } - cursor.removeSelectedText(); - m_d->edit->setTextCursor(cursor); - } -} -} // namespace Utils diff --git a/ground/gcs/src/libs/utils/pathlisteditor.h b/ground/gcs/src/libs/utils/pathlisteditor.h deleted file mode 100644 index cc82b9d3dd..0000000000 --- a/ground/gcs/src/libs/utils/pathlisteditor.h +++ /dev/null @@ -1,103 +0,0 @@ -/** - ****************************************************************************** - * - * @file pathlisteditor.h - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @brief - * @see The GNU Public License (GPL) Version 3 - * @defgroup - * @{ - * - *****************************************************************************/ -/* - * 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 PATHLISTEDITOR_H -#define PATHLISTEDITOR_H - -#include "utils_global.h" - -#include -#include - -QT_BEGIN_NAMESPACE -class QAction; -QT_END_NAMESPACE - -namespace Utils { -struct PathListEditorPrivate; - -/** - * A control that let's the user edit a list of (directory) paths - * using the platform separator (';',':'). Typically used for - * path lists controlled by environment variables, such as - * PATH. It is based on a QPlainTextEdit as it should - * allow for convenient editing and non-directory type elements like - * "etc/mydir1:$SPECIAL_SYNTAX:/etc/mydir2". - * When pasting text into it, the platform separator will be replaced - * by new line characters for convenience. - */ - -class QTCREATOR_UTILS_EXPORT PathListEditor : public QWidget { - Q_DISABLE_COPY(PathListEditor) - Q_OBJECT Q_PROPERTY(QStringList pathList READ pathList WRITE setPathList DESIGNABLE true) - Q_PROPERTY(QString fileDialogTitle READ fileDialogTitle WRITE setFileDialogTitle DESIGNABLE true) - -public: - explicit PathListEditor(QWidget *parent = 0); - virtual ~PathListEditor(); - - QString pathListString() const; - QStringList pathList() const; - QString fileDialogTitle() const; - - static QChar separator(); - - // Add a convenience action "Import from 'Path'" (environment variable) - void addEnvVariableImportAction(const QString &var); - -public slots: - void clear(); - void setPathList(const QStringList &l); - void setPathList(const QString &pathString); - void setPathListFromEnvVariable(const QString &var); - void setFileDialogTitle(const QString &l); - -protected: - // Index after which to insert further "Add" actions - static int lastAddActionIndex(); - QAction *insertAction(int index /* -1 */, const QString &text, QObject *receiver, const char *slotFunc); - QAction *addAction(const QString &text, QObject *receiver, const char *slotFunc); - - QString text() const; - void setText(const QString &); - -protected slots: - void insertPathAtCursor(const QString &); - void deletePathAtCursor(); - void appendPath(const QString &); - -private slots: - void slotAdd(); - void slotInsert(); - -private: - PathListEditorPrivate *m_d; -}; -} // namespace Utils - -#endif // PATHLISTEDITOR_H diff --git a/ground/gcs/src/libs/utils/projectintropage.cpp b/ground/gcs/src/libs/utils/projectintropage.cpp deleted file mode 100644 index 4cf4c43dab..0000000000 --- a/ground/gcs/src/libs/utils/projectintropage.cpp +++ /dev/null @@ -1,210 +0,0 @@ -/** - ****************************************************************************** - * - * @file projectintropage.cpp - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @brief - * @see The GNU Public License (GPL) Version 3 - * @defgroup - * @{ - * - *****************************************************************************/ -/* - * 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 "projectintropage.h" -#include "filewizardpage.h" -#include "ui_projectintropage.h" - -#include -#include -#include - -namespace Utils { -struct ProjectIntroPagePrivate { - ProjectIntroPagePrivate(); - Ui::ProjectIntroPage m_ui; - bool m_complete; - // Status label style sheets - const QString m_errorStyleSheet; - const QString m_warningStyleSheet; - const QString m_hintStyleSheet; -}; - -ProjectIntroPagePrivate::ProjectIntroPagePrivate() : - m_complete(false), - m_errorStyleSheet(QLatin1String("background : red;")), - m_warningStyleSheet(QLatin1String("background : yellow;")), - m_hintStyleSheet() -{} - -ProjectIntroPage::ProjectIntroPage(QWidget *parent) : - QWizardPage(parent), - m_d(new ProjectIntroPagePrivate) -{ - m_d->m_ui.setupUi(this); - hideStatusLabel(); - m_d->m_ui.nameLineEdit->setInitialText(tr("")); - m_d->m_ui.nameLineEdit->setFocus(Qt::TabFocusReason); - connect(m_d->m_ui.pathChooser, SIGNAL(changed(QString)), this, SLOT(slotChanged())); - connect(m_d->m_ui.nameLineEdit, SIGNAL(textChanged(QString)), this, SLOT(slotChanged())); - connect(m_d->m_ui.pathChooser, SIGNAL(returnPressed()), this, SLOT(slotActivated())); - connect(m_d->m_ui.nameLineEdit, SIGNAL(validReturnPressed()), this, SLOT(slotActivated())); -} - -void ProjectIntroPage::insertControl(int row, QWidget *label, QWidget *control) -{ - m_d->m_ui.formLayout->insertRow(row, label, control); -} - -ProjectIntroPage::~ProjectIntroPage() -{ - delete m_d; -} - -QString ProjectIntroPage::name() const -{ - return m_d->m_ui.nameLineEdit->text(); -} - -QString ProjectIntroPage::path() const -{ - return m_d->m_ui.pathChooser->path(); -} - -void ProjectIntroPage::setPath(const QString &path) -{ - m_d->m_ui.pathChooser->setPath(path); -} - -void ProjectIntroPage::setName(const QString &name) -{ - m_d->m_ui.nameLineEdit->setText(name); -} - -QString ProjectIntroPage::description() const -{ - return m_d->m_ui.descriptionLabel->text(); -} - -void ProjectIntroPage::setDescription(const QString &description) -{ - m_d->m_ui.descriptionLabel->setText(description); -} - -void ProjectIntroPage::changeEvent(QEvent *e) -{ - QWizardPage::changeEvent(e); - - switch (e->type()) { - case QEvent::LanguageChange: - m_d->m_ui.retranslateUi(this); - break; - default: - break; - } -} - -bool ProjectIntroPage::isComplete() const -{ - return m_d->m_complete; -} - -bool ProjectIntroPage::validate() -{ - // Validate and display status - if (!m_d->m_ui.pathChooser->isValid()) { - displayStatusMessage(Error, m_d->m_ui.pathChooser->errorMessage()); - return false; - } - - // Name valid? Ignore 'DisplayingInitialText' state. - bool nameValid = false; - switch (m_d->m_ui.nameLineEdit->state()) { - case BaseValidatingLineEdit::Invalid: - displayStatusMessage(Error, m_d->m_ui.nameLineEdit->errorMessage()); - return false; - - case BaseValidatingLineEdit::DisplayingInitialText: - break; - case BaseValidatingLineEdit::Valid: - nameValid = true; - break; - } - - // Check existence of the directory - QString projectDir = path(); - projectDir += QDir::separator(); - projectDir += m_d->m_ui.nameLineEdit->text(); - const QFileInfo projectDirFile(projectDir); - if (!projectDirFile.exists()) { // All happy - hideStatusLabel(); - return nameValid; - } - - if (projectDirFile.isDir()) { - displayStatusMessage(Warning, tr("The project already exists.")); - return nameValid;; - } - // Not a directory, but something else, likely causing directory creation to fail - displayStatusMessage(Error, tr("A file with that name already exists.")); - return false; -} - -void ProjectIntroPage::slotChanged() -{ - const bool newComplete = validate(); - - if (newComplete != m_d->m_complete) { - m_d->m_complete = newComplete; - emit completeChanged(); - } -} - -void ProjectIntroPage::slotActivated() -{ - if (m_d->m_complete) { - emit activated(); - } -} - -bool ProjectIntroPage::validateProjectDirectory(const QString &name, QString *errorMessage) -{ - return ProjectNameValidatingLineEdit::validateProjectName(name, errorMessage); -} - -void ProjectIntroPage::displayStatusMessage(StatusLabelMode m, const QString &s) -{ - switch (m) { - case Error: - m_d->m_ui.stateLabel->setStyleSheet(m_d->m_errorStyleSheet); - break; - case Warning: - m_d->m_ui.stateLabel->setStyleSheet(m_d->m_warningStyleSheet); - break; - case Hint: - m_d->m_ui.stateLabel->setStyleSheet(m_d->m_hintStyleSheet); - break; - } - m_d->m_ui.stateLabel->setText(s); -} - -void ProjectIntroPage::hideStatusLabel() -{ - displayStatusMessage(Hint, QString()); -} -} // namespace Utils diff --git a/ground/gcs/src/libs/utils/projectintropage.h b/ground/gcs/src/libs/utils/projectintropage.h deleted file mode 100644 index c1c6eddc20..0000000000 --- a/ground/gcs/src/libs/utils/projectintropage.h +++ /dev/null @@ -1,99 +0,0 @@ -/** - ****************************************************************************** - * - * @file projectintropage.h - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @brief - * @see The GNU Public License (GPL) Version 3 - * @defgroup - * @{ - * - *****************************************************************************/ -/* - * 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 PROJECTINTROPAGE_H -#define PROJECTINTROPAGE_H - -#include "utils_global.h" - -#include - -namespace Utils { -struct ProjectIntroPagePrivate; - -/* Standard wizard page for a single file letting the user choose name - * and path. Looks similar to FileWizardPage, but provides additional - * functionality: - * - Description label at the top for displaying introductory text - * - It does on the fly validation (connected to changed()) and displays - * warnings/errors in a status label at the bottom (the page is complete - * when fully validated, validatePage() is thus not implemented). - * - * Note: Careful when changing projectintropage.ui. It must have main - * geometry cleared and QLayout::SetMinimumSize constraint on the main - * layout, otherwise, QWizard will squeeze it due to its strange expanding - * hacks. */ - -class QTCREATOR_UTILS_EXPORT ProjectIntroPage : public QWizardPage { - Q_OBJECT Q_DISABLE_COPY(ProjectIntroPage) - Q_PROPERTY(QString description READ description WRITE setPath DESIGNABLE true) - Q_PROPERTY(QString path READ path WRITE setPath DESIGNABLE true) - Q_PROPERTY(QString name READ name WRITE setName DESIGNABLE true) -public: - explicit ProjectIntroPage(QWidget *parent = 0); - virtual ~ProjectIntroPage(); - - QString name() const; - QString path() const; - QString description() const; - - // Insert an additional control into the form layout for the target. - void insertControl(int row, QWidget *label, QWidget *control); - - virtual bool isComplete() const; - - // Validate a project directory name entry field - static bool validateProjectDirectory(const QString &name, QString *errorMessage); - -signals: - void activated(); - -public slots: - void setPath(const QString &path); - void setName(const QString &name); - void setDescription(const QString &description); - -private slots: - void slotChanged(); - void slotActivated(); - -protected: - virtual void changeEvent(QEvent *e); - -private: - enum StatusLabelMode { Error, Warning, Hint }; - - bool validate(); - void displayStatusMessage(StatusLabelMode m, const QString &); - void hideStatusLabel(); - - ProjectIntroPagePrivate *m_d; -}; -} // namespace Utils - -#endif // PROJECTINTROPAGE_H diff --git a/ground/gcs/src/libs/utils/projectintropage.ui b/ground/gcs/src/libs/utils/projectintropage.ui deleted file mode 100644 index a37da218c3..0000000000 --- a/ground/gcs/src/libs/utils/projectintropage.ui +++ /dev/null @@ -1,116 +0,0 @@ - - - Utils::ProjectIntroPage - - - - 0 - 0 - 208 - 143 - - - - Introduction and project location - - - - QLayout::SetMinimumSize - - - - - true - - - - - - - Qt::Vertical - - - QSizePolicy::MinimumExpanding - - - - 0 - 0 - - - - - - - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - Name: - - - - - - - - - - Create in: - - - - - - - - - - - - - Qt::Horizontal - - - - 0 - 0 - - - - - - - - - - true - - - - - - - - Utils::PathChooser - QWidget -
pathchooser.h
- 1 -
- - Utils::ProjectNameValidatingLineEdit - QLineEdit -
projectnamevalidatinglineedit.h
-
-
- - -
diff --git a/ground/gcs/src/libs/utils/projectnamevalidatinglineedit.cpp b/ground/gcs/src/libs/utils/projectnamevalidatinglineedit.cpp deleted file mode 100644 index 56f9ebc4a0..0000000000 --- a/ground/gcs/src/libs/utils/projectnamevalidatinglineedit.cpp +++ /dev/null @@ -1,59 +0,0 @@ -/** - ****************************************************************************** - * - * @file projectnamevalidatinglineedit.cpp - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @brief - * @see The GNU Public License (GPL) Version 3 - * @defgroup - * @{ - * - *****************************************************************************/ -/* - * 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 "projectnamevalidatinglineedit.h" -#include "filenamevalidatinglineedit.h" - -namespace Utils { -ProjectNameValidatingLineEdit::ProjectNameValidatingLineEdit(QWidget *parent) - : BaseValidatingLineEdit(parent) -{} - -bool ProjectNameValidatingLineEdit::validateProjectName(const QString &name, QString *errorMessage /* = 0*/) -{ - // Validation is file name + checking for dots - if (!FileNameValidatingLineEdit::validateFileName(name, false, errorMessage)) { - return false; - } - - // We don't want dots in the directory name for some legacy Windows - // reason. Since we are cross-platform, we generally disallow it. - if (name.contains(QLatin1Char('.'))) { - if (errorMessage) { - *errorMessage = tr("The name must not contain the '.'-character."); - } - return false; - } - return true; -} - -bool ProjectNameValidatingLineEdit::validate(const QString &value, QString *errorMessage) const -{ - return validateProjectName(value, errorMessage); -} -} // namespace Utils diff --git a/ground/gcs/src/libs/utils/projectnamevalidatinglineedit.h b/ground/gcs/src/libs/utils/projectnamevalidatinglineedit.h deleted file mode 100644 index 0ddde939e7..0000000000 --- a/ground/gcs/src/libs/utils/projectnamevalidatinglineedit.h +++ /dev/null @@ -1,48 +0,0 @@ -/** - ****************************************************************************** - * - * @file projectnamevalidatinglineedit.h - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @brief - * @see The GNU Public License (GPL) Version 3 - * @defgroup - * @{ - * - *****************************************************************************/ -/* - * 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 PROJECTNAMEVALIDATINGLINEEDIT_H -#define PROJECTNAMEVALIDATINGLINEEDIT_H - -#include "basevalidatinglineedit.h" - -namespace Utils { -class QTCREATOR_UTILS_EXPORT ProjectNameValidatingLineEdit : public BaseValidatingLineEdit { - Q_OBJECT Q_DISABLE_COPY(ProjectNameValidatingLineEdit) - -public: - explicit ProjectNameValidatingLineEdit(QWidget *parent = 0); - - static bool validateProjectName(const QString &name, QString *errorMessage /* = 0*/); - -protected: - virtual bool validate(const QString &value, QString *errorMessage) const; -}; -} // namespace Utils - -#endif // PROJECTNAMEVALIDATINGLINEEDIT_H diff --git a/ground/gcs/src/libs/utils/reloadpromptutils.cpp b/ground/gcs/src/libs/utils/reloadpromptutils.cpp deleted file mode 100644 index 38f043e420..0000000000 --- a/ground/gcs/src/libs/utils/reloadpromptutils.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/** - ****************************************************************************** - * - * @file reloadpromptutils.cpp - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @brief - * @see The GNU Public License (GPL) Version 3 - * @defgroup - * @{ - * - *****************************************************************************/ -/* - * 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 "reloadpromptutils.h" - -#include -#include -#include - -using namespace Utils; - -QTCREATOR_UTILS_EXPORT Utils::ReloadPromptAnswer Utils::reloadPrompt(const QString &fileName, bool modified, QWidget *parent) -{ - const QString title = QCoreApplication::translate("Utils::reloadPrompt", "File Changed"); - QString msg; - - if (modified) { - msg = QCoreApplication::translate("Utils::reloadPrompt", - "The unsaved file %1 has been changed outside Qt Creator. Do you want to reload it and discard your changes?").arg(QDir::toNativeSeparators(fileName)); - } else { - msg = QCoreApplication::translate("Utils::reloadPrompt", - "The file %1 has changed outside Qt Creator. Do you want to reload it?").arg(QDir::toNativeSeparators(fileName)); - } - return reloadPrompt(title, msg, parent); -} - -QTCREATOR_UTILS_EXPORT Utils::ReloadPromptAnswer Utils::reloadPrompt(const QString &title, const QString &prompt, QWidget *parent) -{ - switch (QMessageBox::question(parent, title, prompt, - QMessageBox::Yes | QMessageBox::YesToAll | QMessageBox::No | QMessageBox::NoToAll, - QMessageBox::YesToAll)) { - case QMessageBox::Yes: - return ReloadCurrent; - - case QMessageBox::YesToAll: - return ReloadAll; - - case QMessageBox::No: - return ReloadSkipCurrent; - - default: - break; - } - return ReloadNone; -} diff --git a/ground/gcs/src/libs/utils/reloadpromptutils.h b/ground/gcs/src/libs/utils/reloadpromptutils.h deleted file mode 100644 index e5bd2f54cb..0000000000 --- a/ground/gcs/src/libs/utils/reloadpromptutils.h +++ /dev/null @@ -1,46 +0,0 @@ -/** - ****************************************************************************** - * - * @file reloadpromptutils.h - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @brief - * @see The GNU Public License (GPL) Version 3 - * @defgroup - * @{ - * - *****************************************************************************/ -/* - * 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 RELOADPROMPTUTILS_H -#define RELOADPROMPTUTILS_H - -#include "utils_global.h" - -QT_BEGIN_NAMESPACE -class QString; -class QWidget; -QT_END_NAMESPACE - -namespace Utils { -enum ReloadPromptAnswer { ReloadCurrent, ReloadAll, ReloadSkipCurrent, ReloadNone }; - -QTCREATOR_UTILS_EXPORT ReloadPromptAnswer reloadPrompt(const QString &fileName, bool modified, QWidget *parent); -QTCREATOR_UTILS_EXPORT ReloadPromptAnswer reloadPrompt(const QString &title, const QString &prompt, QWidget *parent); -} // namespace Utils - -#endif // RELOADPROMPTUTILS_H diff --git a/ground/gcs/src/libs/utils/savedaction.cpp b/ground/gcs/src/libs/utils/savedaction.cpp deleted file mode 100644 index 3dc5af5385..0000000000 --- a/ground/gcs/src/libs/utils/savedaction.cpp +++ /dev/null @@ -1,489 +0,0 @@ -/** - ****************************************************************************** - * - * @file savedaction.cpp - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @brief - * @see The GNU Public License (GPL) Version 3 - * @defgroup - * @{ - * - *****************************************************************************/ -/* - * 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 - -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include - - -using namespace Utils; - - -////////////////////////////////////////////////////////////////////////// -// -// SavedAction -// -////////////////////////////////////////////////////////////////////////// - -/*! - \class Utils::SavedAction - - \brief The SavedAction class is a helper class for actions with persistent - state. - - \ingroup utils - - */ - -SavedAction::SavedAction(QObject *parent) - : QAction(parent) -{ - m_widget = 0; - connect(this, SIGNAL(triggered(bool)), this, SLOT(actionTriggered(bool))); -} - - -/*! - Returns the current value of the object. - - \sa setValue() - */ -QVariant SavedAction::value() const -{ - return m_value; -} - - -/*! - Sets the current value of the object. If the value changed and - \a doemit is true, the \c valueChanged() signal will be emitted. - - \sa value() - */ -void SavedAction::setValue(const QVariant &value, bool doemit) -{ - if (value == m_value) { - return; - } - m_value = value; - if (this->isCheckable()) { - this->setChecked(m_value.toBool()); - } - if (doemit) { - emit valueChanged(m_value); - } -} - - -/*! - Returns the default value to be used when the item does not exist yet - in the settings. - - \sa setDefaultValue() - */ -QVariant SavedAction::defaultValue() const -{ - return m_defaultValue; -} - - -/*! - Sets the default value to be used when the item does not exist yet - in the settings. - - \sa defaultValue() - */ -void SavedAction::setDefaultValue(const QVariant &value) -{ - m_defaultValue = value; -} - - -/*! - Returns the key to be used when accessing the settings. - - \sa settingsKey() - */ -QString SavedAction::settingsKey() const -{ - return m_settingsKey; -} - - -/*! - Sets the key to be used when accessing the settings. - - \sa settingsKey() - */ -void SavedAction::setSettingsKey(const QString &key) -{ - m_settingsKey = key; -} - - -/*! - Sets the key and group to be used when accessing the settings. - - \sa settingsKey() - */ -void SavedAction::setSettingsKey(const QString &group, const QString &key) -{ - m_settingsKey = key; - m_settingsGroup = group; -} - - -/*! - Sets the key to be used when accessing the settings. - - \sa settingsKey() - */ -QString SavedAction::settingsGroup() const -{ - return m_settingsGroup; -} - -/*! - Sets the group to be used when accessing the settings. - - \sa settingsGroup() - */ -void SavedAction::setSettingsGroup(const QString &group) -{ - m_settingsGroup = group; -} - -QString SavedAction::textPattern() const -{ - return m_textPattern; -} - -void SavedAction::setTextPattern(const QString &value) -{ - m_textPattern = value; -} - -QString SavedAction::toString() const -{ - return QLatin1String("value: ") + m_value.toString() - + QLatin1String(" defaultvalue: ") + m_defaultValue.toString() - + QLatin1String(" settingskey: ") + m_settingsGroup - + '/' + m_settingsKey; -} - -/*! - \fn QAction *SavedAction::updatedAction(const QString &text) - - Adjust the \c text() of the underlying action. - - This can be used to update the item shortly before e.g. a menu is shown. - - If the item's \c textPattern() is empty the \a text will be used - verbatim. - - Otherwise, the behaviour depends on \a text: if it is non-empty, - \c QString(textPattern()).arg(text), otherwise, \c textPattern() - with the "%1" placeholder removed will be used. - - \sa textPattern(), setTextPattern() - */ -QAction *SavedAction::updatedAction(const QString &text0) -{ - QString text = text0; - bool enabled = true; - - if (!m_textPattern.isEmpty()) { - if (text.isEmpty()) { - text = m_textPattern; - text.remove("\"%1\""); - text.remove("%1"); - enabled = false; - } else { - text = m_textPattern.arg(text0); - } - } - this->setEnabled(enabled); - this->setData(text0); - this->setText(text); - return this; -} - -/* - Uses \c settingsGroup() and \c settingsKey() to restore the - item from \a settings, - - \sa settingsKey(), settingsGroup(), writeSettings() - */ -void SavedAction::readSettings(QSettings *settings) -{ - if (m_settingsGroup.isEmpty() || m_settingsKey.isEmpty()) { - return; - } - settings->beginGroup(m_settingsGroup); - QVariant var = settings->value(m_settingsKey, m_defaultValue); - // work around old ini files containing @Invalid() entries - if (isCheckable() && !var.isValid()) { - var = false; - } - setValue(var); - // qDebug() << "READING: " << var.isValid() << m_settingsKey << " -> " << m_value - // << " (default: " << m_defaultValue << ")" << var; - settings->endGroup(); -} - -/* - Uses \c settingsGroup() and \c settingsKey() to write the - item to \a settings, - - \sa settingsKey(), settingsGroup(), readSettings() - */ -void SavedAction::writeSettings(QSettings *settings) -{ - if (m_settingsGroup.isEmpty() || m_settingsKey.isEmpty()) { - return; - } - settings->beginGroup(m_settingsGroup); - settings->setValue(m_settingsKey, m_value); - // qDebug() << "WRITING: " << m_settingsKey << " -> " << toString(); - settings->endGroup(); -} - -/* - A \c SavedAction can be connected to a widget, typically a - checkbox, radiobutton, or a lineedit in some configuration dialog. - - The widget will retrieve its contents from the SavedAction's - value, and - depending on the \a ApplyMode - either write - changes back immediately, or when \s SavedAction::apply() - is called explicitly. - - \sa apply(), disconnectWidget() - */ -void SavedAction::connectWidget(QWidget *widget, ApplyMode applyMode) -{ - QTC_ASSERT(!m_widget, - qDebug() << "ALREADY CONNECTED: " << widget << m_widget << toString(); return ); - m_widget = widget; - m_applyMode = applyMode; - - if (QAbstractButton * button = qobject_cast(widget)) { - if (button->isCheckable()) { - button->setChecked(m_value.toBool()); - connect(button, SIGNAL(clicked(bool)), - this, SLOT(checkableButtonClicked(bool))); - } else { - connect(button, SIGNAL(clicked()), - this, SLOT(uncheckableButtonClicked())); - } - } else if (QSpinBox * spinBox = qobject_cast(widget)) { - spinBox->setValue(m_value.toInt()); - - // qDebug() << "SETTING VALUE" << spinBox->value(); - connect(spinBox, SIGNAL(valueChanged(int)), - this, SLOT(spinBoxValueChanged(int))); - connect(spinBox, SIGNAL(valueChanged(QString)), - this, SLOT(spinBoxValueChanged(QString))); - } else if (QDoubleSpinBox * doubleSpinBox = qobject_cast(widget)) { - doubleSpinBox->setValue(m_value.toDouble()); - // qDebug() << "SETTING VALUE" << doubleSpinBox->value(); - connect(doubleSpinBox, SIGNAL(valueChanged(double)), - this, SLOT(doubleSpinBoxValueChanged(double))); - connect(doubleSpinBox, SIGNAL(valueChanged(QString)), - this, SLOT(doubleSpinBoxValueChanged(QString))); - } else if (QLineEdit * lineEdit = qobject_cast(widget)) { - lineEdit->setText(m_value.toString()); - // qDebug() << "SETTING TEXT" << lineEdit->text(); - connect(lineEdit, SIGNAL(editingFinished()), - this, SLOT(lineEditEditingFinished())); - } else if (PathChooser * pathChooser = qobject_cast(widget)) { - pathChooser->setPath(m_value.toString()); - connect(pathChooser, SIGNAL(editingFinished()), - this, SLOT(pathChooserEditingFinished())); - connect(pathChooser, SIGNAL(browsingFinished()), - this, SLOT(pathChooserEditingFinished())); - } else { - qDebug() << "Cannot connect widget " << widget << toString(); - } -} - -/* - Disconnects the \c SavedAction from a widget. - - \sa apply(), connectWidget() - */ -void SavedAction::disconnectWidget() -{ - m_widget = 0; -} - -void SavedAction::apply(QSettings *s) -{ - if (QAbstractButton * button = qobject_cast(m_widget)) { - setValue(button->isChecked()); - } else if (QLineEdit * lineEdit = qobject_cast(m_widget)) { - setValue(lineEdit->text()); - } else if (QSpinBox * spinBox = qobject_cast(m_widget)) { - setValue(spinBox->value()); - } else if (QDoubleSpinBox * doubleSpinBox = qobject_cast(m_widget)) { - setValue(doubleSpinBox->value()); - } else if (PathChooser * pathChooser = qobject_cast(m_widget)) { - setValue(pathChooser->path()); - } - if (s) { - writeSettings(s); - } -} - -void SavedAction::uncheckableButtonClicked() -{ - QAbstractButton *button = qobject_cast(sender()); - - QTC_ASSERT(button, return ); - // qDebug() << "UNCHECKABLE BUTTON: " << sender(); - QAction::trigger(); -} - -void SavedAction::checkableButtonClicked(bool) -{ - QAbstractButton *button = qobject_cast(sender()); - - QTC_ASSERT(button, return ); - // qDebug() << "CHECKABLE BUTTON: " << sender(); - if (m_applyMode == ImmediateApply) { - setValue(button->isChecked()); - } -} - -void SavedAction::lineEditEditingFinished() -{ - QLineEdit *lineEdit = qobject_cast(sender()); - - QTC_ASSERT(lineEdit, return ); - if (m_applyMode == ImmediateApply) { - setValue(lineEdit->text()); - } -} - -void SavedAction::spinBoxValueChanged(int value) -{ - QSpinBox *spinBox = qobject_cast(sender()); - - QTC_ASSERT(spinBox, return ); - if (m_applyMode == ImmediateApply) { - setValue(value); - } -} - -void SavedAction::spinBoxValueChanged(QString value) -{ - QSpinBox *spinBox = qobject_cast(sender()); - - QTC_ASSERT(spinBox, return ); - if (m_applyMode == ImmediateApply) { - setValue(value); - } -} - -void SavedAction::doubleSpinBoxValueChanged(double value) -{ - QDoubleSpinBox *doubleSpinBox = qobject_cast(sender()); - - QTC_ASSERT(doubleSpinBox, return ); - if (m_applyMode == ImmediateApply) { - setValue(value); - } -} - -void SavedAction::doubleSpinBoxValueChanged(QString value) -{ - QDoubleSpinBox *doubleSpinBox = qobject_cast(sender()); - - QTC_ASSERT(doubleSpinBox, return ); - if (m_applyMode == ImmediateApply) { - setValue(value); - } -} - -void SavedAction::pathChooserEditingFinished() -{ - PathChooser *pathChooser = qobject_cast(sender()); - - QTC_ASSERT(pathChooser, return ); - if (m_applyMode == ImmediateApply) { - setValue(pathChooser->path()); - } -} - -void SavedAction::actionTriggered(bool) -{ - if (isCheckable()) { - setValue(isChecked()); - } - if (actionGroup() && actionGroup()->isExclusive()) { - // FIXME: should be taken care of more directly - foreach(QAction * act, actionGroup()->actions()) - if (SavedAction * dact = qobject_cast(act)) { - dact->setValue(bool(act == this)); - } - } -} - -void SavedAction::trigger(const QVariant &data) -{ - setData(data); - QAction::trigger(); -} - - -////////////////////////////////////////////////////////////////////////// -// -// SavedActionSet -// -////////////////////////////////////////////////////////////////////////// - -void SavedActionSet::insert(SavedAction *action, QWidget *widget) -{ - m_list.append(action); - if (widget) { - action->connectWidget(widget); - } -} - -void SavedActionSet::apply(QSettings *settings) -{ - foreach(SavedAction * action, m_list) - action->apply(settings); -} - -void SavedActionSet::finish() -{ - foreach(SavedAction * action, m_list) - action->disconnectWidget(); -} diff --git a/ground/gcs/src/libs/utils/savedaction.h b/ground/gcs/src/libs/utils/savedaction.h deleted file mode 100644 index 9f8721bde2..0000000000 --- a/ground/gcs/src/libs/utils/savedaction.h +++ /dev/null @@ -1,124 +0,0 @@ -/** - ****************************************************************************** - * - * @file savedaction.h - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @brief - * @see The GNU Public License (GPL) Version 3 - * @defgroup - * @{ - * - *****************************************************************************/ -/* - * 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 SAVED_ACTION_H -#define SAVED_ACTION_H - -#include "utils_global.h" - -#include -#include -#include - -#include - -QT_BEGIN_NAMESPACE -class QSettings; -QT_END_NAMESPACE - -namespace Utils { -enum ApplyMode { ImmediateApply, DeferedApply }; - -class QTCREATOR_UTILS_EXPORT SavedAction : public QAction { - Q_OBJECT - -public: - SavedAction(QObject *parent = 0); - - virtual QVariant value() const; - Q_SLOT virtual void setValue(const QVariant &value, bool doemit = true); - - virtual QVariant defaultValue() const; - Q_SLOT virtual void setDefaultValue(const QVariant &value); - - virtual QAction *updatedAction(const QString &newText); - Q_SLOT virtual void trigger(const QVariant &data); - - // used for persistency - virtual QString settingsKey() const; - Q_SLOT virtual void setSettingsKey(const QString &key); - Q_SLOT virtual void setSettingsKey(const QString &group, const QString &key); - - virtual QString settingsGroup() const; - Q_SLOT virtual void setSettingsGroup(const QString &group); - - virtual void readSettings(QSettings *settings); - Q_SLOT virtual void writeSettings(QSettings *settings); - - virtual void connectWidget(QWidget *widget, ApplyMode applyMode = DeferedApply); - virtual void disconnectWidget(); - Q_SLOT virtual void apply(QSettings *settings); - - virtual QString textPattern() const; - Q_SLOT virtual void setTextPattern(const QString &value); - - QString toString() const; - -signals: - void valueChanged(const QVariant &newValue); - -private: - Q_SLOT void uncheckableButtonClicked(); - Q_SLOT void checkableButtonClicked(bool); - Q_SLOT void lineEditEditingFinished(); - Q_SLOT void pathChooserEditingFinished(); - Q_SLOT void actionTriggered(bool); - Q_SLOT void spinBoxValueChanged(int); - Q_SLOT void spinBoxValueChanged(QString); - Q_SLOT void doubleSpinBoxValueChanged(double); - Q_SLOT void doubleSpinBoxValueChanged(QString); - - QVariant m_value; - QVariant m_defaultValue; - QString m_settingsKey; - QString m_settingsGroup; - QString m_textPattern; - QString m_textData; - QWidget *m_widget; - ApplyMode m_applyMode; -}; - -class QTCREATOR_UTILS_EXPORT SavedActionSet { -public: - SavedActionSet() {} - ~SavedActionSet() {} - - void insert(SavedAction *action, QWidget *widget); - void apply(QSettings *settings); - void finish(); - void clear() - { - m_list.clear(); - } - -private: - QList m_list; -}; -} // namespace Utils - -#endif // SAVED_ACTION_H diff --git a/ground/gcs/src/libs/utils/submiteditorwidget.cpp b/ground/gcs/src/libs/utils/submiteditorwidget.cpp deleted file mode 100644 index 2551715b89..0000000000 --- a/ground/gcs/src/libs/utils/submiteditorwidget.cpp +++ /dev/null @@ -1,537 +0,0 @@ -/** - ****************************************************************************** - * - * @file submiteditorwidget.cpp - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @brief - * @see The GNU Public License (GPL) Version 3 - * @defgroup - * @{ - * - *****************************************************************************/ -/* - * 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 "submiteditorwidget.h" -#include "submitfieldwidget.h" -#include "ui_submiteditorwidget.h" - -#include -#include -#include - -#include -#include -#include -#include -#include - -enum { debug = 0 }; -enum { defaultLineWidth = 72 }; - -namespace Utils { -// QActionPushButton: A push button tied to an action -// (similar to a QToolButton) -class QActionPushButton : public QPushButton { - Q_OBJECT -public: - explicit QActionPushButton(QAction *a); - -private slots: - void actionChanged(); -}; - -QActionPushButton::QActionPushButton(QAction *a) : - QPushButton(a->icon(), a->text()) -{ - connect(a, SIGNAL(changed()), this, SLOT(actionChanged())); - connect(this, SIGNAL(clicked()), a, SLOT(trigger())); - setEnabled(a->isEnabled()); -} - -void QActionPushButton::actionChanged() -{ - if (const QAction * a = qobject_cast(sender())) { - setEnabled(a->isEnabled()); - } -} - -// Helpers to retrieve model data -static inline bool listModelChecked(const QAbstractItemModel *model, int row, int column = 0) -{ - const QModelIndex checkableIndex = model->index(row, column, QModelIndex()); - - return model->data(checkableIndex, Qt::CheckStateRole).toInt() == Qt::Checked; -} - -static inline QString listModelText(const QAbstractItemModel *model, int row, int column) -{ - const QModelIndex index = model->index(row, column, QModelIndex()); - - return model->data(index, Qt::DisplayRole).toString(); -} - -// Find a check item in a model -static bool listModelContainsCheckedItem(const QAbstractItemModel *model) -{ - const int count = model->rowCount(); - - for (int i = 0; i < count; i++) { - if (listModelChecked(model, i, 0)) { - return true; - } - } - return false; -} - -// Convenience to extract a list of selected indexes -QList selectedRows(const QAbstractItemView *view) -{ - const QModelIndexList indexList = view->selectionModel()->selectedRows(0); - - if (indexList.empty()) { - return QList(); - } - QList rc; - const QModelIndexList::const_iterator cend = indexList.constEnd(); - for (QModelIndexList::const_iterator it = indexList.constBegin(); it != cend; ++it) { - rc.push_back(it->row()); - } - return rc; -} - -// ----------- SubmitEditorWidgetPrivate - -struct SubmitEditorWidgetPrivate { - // A pair of position/action to extend context menus - typedef QPair > AdditionalContextMenuAction; - - SubmitEditorWidgetPrivate(); - - Ui::SubmitEditorWidget m_ui; - bool m_filesSelected; - bool m_filesChecked; - int m_fileNameColumn; - int m_activatedRow; - - QList descriptionEditContextMenuActions; - QVBoxLayout *m_fieldLayout; - QList m_fieldWidgets; - int m_lineWidth; -}; - -SubmitEditorWidgetPrivate::SubmitEditorWidgetPrivate() : - m_filesSelected(false), - m_filesChecked(false), - m_fileNameColumn(1), - m_activatedRow(-1), - m_fieldLayout(0), - m_lineWidth(defaultLineWidth) -{} - -SubmitEditorWidget::SubmitEditorWidget(QWidget *parent) : - QWidget(parent), - m_d(new SubmitEditorWidgetPrivate) -{ - m_d->m_ui.setupUi(this); - m_d->m_ui.description->setContextMenuPolicy(Qt::CustomContextMenu); - m_d->m_ui.description->setLineWrapMode(QTextEdit::NoWrap); - m_d->m_ui.description->setWordWrapMode(QTextOption::WordWrap); - connect(m_d->m_ui.description, SIGNAL(customContextMenuRequested(QPoint)), - this, SLOT(editorCustomContextMenuRequested(QPoint))); - - // File List - m_d->m_ui.fileView->setSelectionMode(QAbstractItemView::ExtendedSelection); - m_d->m_ui.fileView->setRootIsDecorated(false); - connect(m_d->m_ui.fileView, SIGNAL(doubleClicked(QModelIndex)), - this, SLOT(diffActivated(QModelIndex))); - - setFocusPolicy(Qt::StrongFocus); - setFocusProxy(m_d->m_ui.description); -} - -SubmitEditorWidget::~SubmitEditorWidget() -{ - delete m_d; -} - -void SubmitEditorWidget::registerActions(QAction *editorUndoAction, QAction *editorRedoAction, - QAction *submitAction, QAction *diffAction) -{ - if (editorUndoAction) { - editorUndoAction->setEnabled(m_d->m_ui.description->document()->isUndoAvailable()); - connect(m_d->m_ui.description, SIGNAL(undoAvailable(bool)), editorUndoAction, SLOT(setEnabled(bool))); - connect(editorUndoAction, SIGNAL(triggered()), m_d->m_ui.description, SLOT(undo())); - } - if (editorRedoAction) { - editorRedoAction->setEnabled(m_d->m_ui.description->document()->isRedoAvailable()); - connect(m_d->m_ui.description, SIGNAL(redoAvailable(bool)), editorRedoAction, SLOT(setEnabled(bool))); - connect(editorRedoAction, SIGNAL(triggered()), m_d->m_ui.description, SLOT(redo())); - } - - if (submitAction) { - if (debug) { - int count = 0; - if (const QAbstractItemModel * model = m_d->m_ui.fileView->model()) { - count = model->rowCount(); - } - qDebug() << Q_FUNC_INFO << submitAction << count << "items" << m_d->m_filesChecked; - } - submitAction->setEnabled(m_d->m_filesChecked); - connect(this, SIGNAL(fileCheckStateChanged(bool)), submitAction, SLOT(setEnabled(bool))); - m_d->m_ui.buttonLayout->addWidget(new QActionPushButton(submitAction)); - } - if (diffAction) { - if (debug) { - qDebug() << diffAction << m_d->m_filesSelected; - } - diffAction->setEnabled(m_d->m_filesSelected); - connect(this, SIGNAL(fileSelectionChanged(bool)), diffAction, SLOT(setEnabled(bool))); - connect(diffAction, SIGNAL(triggered()), this, SLOT(triggerDiffSelected())); - m_d->m_ui.buttonLayout->addWidget(new QActionPushButton(diffAction)); - } -} - -void SubmitEditorWidget::unregisterActions(QAction *editorUndoAction, QAction *editorRedoAction, - QAction *submitAction, QAction *diffAction) -{ - if (editorUndoAction) { - disconnect(m_d->m_ui.description, SIGNAL(undoAvailableChanged(bool)), editorUndoAction, SLOT(setEnabled(bool))); - disconnect(editorUndoAction, SIGNAL(triggered()), m_d->m_ui.description, SLOT(undo())); - } - if (editorRedoAction) { - disconnect(m_d->m_ui.description, SIGNAL(redoAvailableChanged(bool)), editorRedoAction, SLOT(setEnabled(bool))); - disconnect(editorRedoAction, SIGNAL(triggered()), m_d->m_ui.description, SLOT(redo())); - } - - if (submitAction) { - disconnect(this, SIGNAL(fileCheckStateChanged(bool)), submitAction, SLOT(setEnabled(bool))); - } - - if (diffAction) { - disconnect(this, SIGNAL(fileSelectionChanged(bool)), diffAction, SLOT(setEnabled(bool))); - disconnect(diffAction, SIGNAL(triggered()), this, SLOT(triggerDiffSelected())); - } -} - -// Make sure we have one terminating NL -static inline QString trimMessageText(const QString &t) -{ - QString rc = t.trimmed(); - - rc += QLatin1Char('\n'); - return rc; -} - -// Extract the wrapped text from a text edit, which performs -// the wrapping only optically. -static QString wrappedText(const QTextEdit *e) -{ - const QChar newLine = QLatin1Char('\n'); - QString rc; - QTextCursor cursor(e->document()); - - cursor.movePosition(QTextCursor::Start); - while (!cursor.atEnd()) { - cursor.select(QTextCursor::LineUnderCursor); - rc += cursor.selectedText(); - rc += newLine; - cursor.movePosition(QTextCursor::EndOfLine); // Mac needs it - cursor.movePosition(QTextCursor::Right); - } - return rc; -} - -QString SubmitEditorWidget::descriptionText() const -{ - QString rc = trimMessageText(lineWrap() ? wrappedText(m_d->m_ui.description) : m_d->m_ui.description->toPlainText()); - - // append field entries - foreach(const SubmitFieldWidget * fw, m_d->m_fieldWidgets) - rc += fw->fieldValues(); - return rc; -} - -void SubmitEditorWidget::setDescriptionText(const QString &text) -{ - m_d->m_ui.description->setPlainText(text); -} - -bool SubmitEditorWidget::lineWrap() const -{ - return m_d->m_ui.description->lineWrapMode() != QTextEdit::NoWrap; -} - -void SubmitEditorWidget::setLineWrap(bool v) -{ - if (debug) { - qDebug() << Q_FUNC_INFO << v; - } - if (v) { - m_d->m_ui.description->setLineWrapColumnOrWidth(m_d->m_lineWidth); - m_d->m_ui.description->setLineWrapMode(QTextEdit::FixedColumnWidth); - } else { - m_d->m_ui.description->setLineWrapMode(QTextEdit::NoWrap); - } -} - -int SubmitEditorWidget::lineWrapWidth() const -{ - return m_d->m_lineWidth; -} - -void SubmitEditorWidget::setLineWrapWidth(int v) -{ - if (debug) { - qDebug() << Q_FUNC_INFO << v << lineWrap(); - } - if (m_d->m_lineWidth == v) { - return; - } - m_d->m_lineWidth = v; - if (lineWrap()) { - m_d->m_ui.description->setLineWrapColumnOrWidth(v); - } -} - -int SubmitEditorWidget::fileNameColumn() const -{ - return m_d->m_fileNameColumn; -} - -void SubmitEditorWidget::setFileNameColumn(int c) -{ - m_d->m_fileNameColumn = c; -} - -QAbstractItemView::SelectionMode SubmitEditorWidget::fileListSelectionMode() const -{ - return m_d->m_ui.fileView->selectionMode(); -} - -void SubmitEditorWidget::setFileListSelectionMode(QAbstractItemView::SelectionMode sm) -{ - m_d->m_ui.fileView->setSelectionMode(sm); -} - -void SubmitEditorWidget::setFileModel(QAbstractItemModel *model) -{ - m_d->m_ui.fileView->clearSelection(); // trigger the change signals - - m_d->m_ui.fileView->setModel(model); - - if (model->rowCount()) { - const int columnCount = model->columnCount(); - for (int c = 0; c < columnCount; c++) { - m_d->m_ui.fileView->resizeColumnToContents(c); - } - } - - connect(model, SIGNAL(dataChanged(QModelIndex, QModelIndex)), - this, SLOT(updateSubmitAction())); - connect(model, SIGNAL(modelReset()), - this, SLOT(updateSubmitAction())); - connect(model, SIGNAL(rowsInserted(QModelIndex, int, int)), - this, SLOT(updateSubmitAction())); - connect(model, SIGNAL(rowsRemoved(QModelIndex, int, int)), - this, SLOT(updateSubmitAction())); - connect(m_d->m_ui.fileView->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), - this, SLOT(updateDiffAction())); - updateActions(); -} - -QAbstractItemModel *SubmitEditorWidget::fileModel() const -{ - return m_d->m_ui.fileView->model(); -} - -QStringList SubmitEditorWidget::selectedFiles() const -{ - const QList selection = selectedRows(m_d->m_ui.fileView); - - if (selection.empty()) { - return QStringList(); - } - - QStringList rc; - const QAbstractItemModel *model = m_d->m_ui.fileView->model(); - const int count = selection.size(); - for (int i = 0; i < count; i++) { - rc.push_back(listModelText(model, selection.at(i), fileNameColumn())); - } - return rc; -} - -QStringList SubmitEditorWidget::checkedFiles() const -{ - QStringList rc; - const QAbstractItemModel *model = m_d->m_ui.fileView->model(); - - if (!model) { - return rc; - } - const int count = model->rowCount(); - for (int i = 0; i < count; i++) { - if (listModelChecked(model, i, 0)) { - rc.push_back(listModelText(model, i, fileNameColumn())); - } - } - return rc; -} - -QTextEdit *SubmitEditorWidget::descriptionEdit() const -{ - return m_d->m_ui.description; -} - -void SubmitEditorWidget::triggerDiffSelected() -{ - const QStringList sel = selectedFiles(); - - if (!sel.empty()) { - emit diffSelected(sel); - } -} - -void SubmitEditorWidget::diffActivatedDelayed() -{ - const QStringList files = QStringList(listModelText(m_d->m_ui.fileView->model(), m_d->m_activatedRow, fileNameColumn())); - emit diffSelected(files); -} - -void SubmitEditorWidget::diffActivated(const QModelIndex &index) -{ - // We need to delay the signal, otherwise, the diff editor will not - // be in the foreground. - m_d->m_activatedRow = index.row(); - QTimer::singleShot(0, this, SLOT(diffActivatedDelayed())); -} - -void SubmitEditorWidget::updateActions() -{ - updateSubmitAction(); - updateDiffAction(); -} - -// Enable submit depending on having checked files -void SubmitEditorWidget::updateSubmitAction() -{ - const bool newFilesCheckedState = hasCheckedFiles(); - - if (m_d->m_filesChecked != newFilesCheckedState) { - m_d->m_filesChecked = newFilesCheckedState; - emit fileCheckStateChanged(m_d->m_filesChecked); - } -} - -// Enable diff depending on selected files -void SubmitEditorWidget::updateDiffAction() -{ - const bool filesSelected = hasSelection(); - - if (m_d->m_filesSelected != filesSelected) { - m_d->m_filesSelected = filesSelected; - emit fileSelectionChanged(m_d->m_filesSelected); - } -} - -bool SubmitEditorWidget::hasSelection() const -{ - // Not present until model is set - if (const QItemSelectionModel * sm = m_d->m_ui.fileView->selectionModel()) { - return sm->hasSelection(); - } - return false; -} - -bool SubmitEditorWidget::hasCheckedFiles() const -{ - if (const QAbstractItemModel * model = m_d->m_ui.fileView->model()) { - return listModelContainsCheckedItem(model); - } - return false; -} - -void SubmitEditorWidget::changeEvent(QEvent *e) -{ - QWidget::changeEvent(e); - - switch (e->type()) { - case QEvent::LanguageChange: - m_d->m_ui.retranslateUi(this); - break; - default: - break; - } -} - -void SubmitEditorWidget::insertTopWidget(QWidget *w) -{ - m_d->m_ui.vboxLayout->insertWidget(0, w); -} - -void SubmitEditorWidget::addSubmitFieldWidget(SubmitFieldWidget *f) -{ - if (!m_d->m_fieldLayout) { - // VBox with horizontal, expanding spacer - m_d->m_fieldLayout = new QVBoxLayout; - QHBoxLayout *outerLayout = new QHBoxLayout; - outerLayout->addLayout(m_d->m_fieldLayout); - outerLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Ignored)); - QBoxLayout *descrLayout = qobject_cast(m_d->m_ui.descriptionBox->layout()); - Q_ASSERT(descrLayout); - descrLayout->addLayout(outerLayout); - } - m_d->m_fieldLayout->addWidget(f); - m_d->m_fieldWidgets.push_back(f); -} - -QList SubmitEditorWidget::submitFieldWidgets() const -{ - return m_d->m_fieldWidgets; -} - -void SubmitEditorWidget::addDescriptionEditContextMenuAction(QAction *a) -{ - m_d->descriptionEditContextMenuActions.push_back(SubmitEditorWidgetPrivate::AdditionalContextMenuAction(-1, a)); -} - -void SubmitEditorWidget::insertDescriptionEditContextMenuAction(int pos, QAction *a) -{ - m_d->descriptionEditContextMenuActions.push_back(SubmitEditorWidgetPrivate::AdditionalContextMenuAction(pos, a)); -} - -void SubmitEditorWidget::editorCustomContextMenuRequested(const QPoint &pos) -{ - QMenu *menu = m_d->m_ui.description->createStandardContextMenu(); - - // Extend - foreach(const SubmitEditorWidgetPrivate::AdditionalContextMenuAction & a, m_d->descriptionEditContextMenuActions) { - if (a.second) { - if (a.first >= 0) { - menu->insertAction(menu->actions().at(a.first), a.second); - } else { - menu->addAction(a.second); - } - } - } - menu->exec(m_d->m_ui.description->mapToGlobal(pos)); - delete menu; -} -} // namespace Utils - -#include "submiteditorwidget.moc" diff --git a/ground/gcs/src/libs/utils/submiteditorwidget.h b/ground/gcs/src/libs/utils/submiteditorwidget.h deleted file mode 100644 index 3782cf49c3..0000000000 --- a/ground/gcs/src/libs/utils/submiteditorwidget.h +++ /dev/null @@ -1,142 +0,0 @@ -/** - ****************************************************************************** - * - * @file submiteditorwidget.h - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @brief - * @see The GNU Public License (GPL) Version 3 - * @defgroup - * @{ - * - *****************************************************************************/ -/* - * 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 SUBMITEDITORWIDGET_H -#define SUBMITEDITORWIDGET_H - -#include "utils_global.h" - -#include -#include - -QT_BEGIN_NAMESPACE -class QTextEdit; -class QListWidgetItem; -class QAction; -class QAbstractItemModel; -class QModelIndex; -class QLineEdit; -QT_END_NAMESPACE - -namespace Utils { -class SubmitFieldWidget; -struct SubmitEditorWidgetPrivate; - -/* The submit editor presents the commit message in a text editor and an - * checkable list of modified files in a list window. The user can delete - * files from the list by unchecking them or diff the selection - * by doubleclicking. A list model which contains the file in a column - * specified by fileNameColumn should be set using setFileModel(). - * - * Additionally, standard creator actions can be registered: - * Undo/redo will be set up to work with the description editor. - * Submit will be set up to be enabled according to checkstate. - * Diff will be set up to trigger diffSelected(). - * - * Note that the actions are connected by signals; in the rare event that there - * are several instances of the SubmitEditorWidget belonging to the same - * context active, the actions must be registered/unregistered in the editor - * change event. - * Care should be taken to ensure the widget is deleted properly when the - * editor closes. */ - -class QTCREATOR_UTILS_EXPORT SubmitEditorWidget : public QWidget { - Q_OBJECT Q_DISABLE_COPY(SubmitEditorWidget) - Q_PROPERTY(QString descriptionText READ descriptionText WRITE setDescriptionText DESIGNABLE true) - Q_PROPERTY(int fileNameColumn READ fileNameColumn WRITE setFileNameColumn DESIGNABLE false) - Q_PROPERTY(QAbstractItemView::SelectionMode fileListSelectionMode READ fileListSelectionMode WRITE setFileListSelectionMode DESIGNABLE true) - Q_PROPERTY(bool lineWrap READ lineWrap WRITE setLineWrap DESIGNABLE true) - Q_PROPERTY(int lineWrapWidth READ lineWrapWidth WRITE setLineWrapWidth DESIGNABLE true) -public: - explicit SubmitEditorWidget(QWidget *parent = 0); - virtual ~SubmitEditorWidget(); - - void registerActions(QAction *editorUndoAction, QAction *editorRedoAction, - QAction *submitAction = 0, QAction *diffAction = 0); - void unregisterActions(QAction *editorUndoAction, QAction *editorRedoAction, - QAction *submitAction = 0, QAction *diffAction = 0); - - QString descriptionText() const; - void setDescriptionText(const QString &text); - - int fileNameColumn() const; - void setFileNameColumn(int c); - - bool lineWrap() const; - void setLineWrap(bool); - - int lineWrapWidth() const; - void setLineWrapWidth(int); - - QAbstractItemView::SelectionMode fileListSelectionMode() const; - void setFileListSelectionMode(QAbstractItemView::SelectionMode sm); - - void setFileModel(QAbstractItemModel *model); - QAbstractItemModel *fileModel() const; - - // Files to be included in submit - QStringList checkedFiles() const; - - // Selected files for diff - QStringList selectedFiles() const; - - QTextEdit *descriptionEdit() const; - - void addDescriptionEditContextMenuAction(QAction *a); - void insertDescriptionEditContextMenuAction(int pos, QAction *a); - - void addSubmitFieldWidget(SubmitFieldWidget *f); - QList submitFieldWidgets() const; - -signals: - void diffSelected(const QStringList &); - void fileSelectionChanged(bool someFileSelected); - void fileCheckStateChanged(bool someFileChecked); - -protected: - virtual void changeEvent(QEvent *e); - void insertTopWidget(QWidget *w); - -private slots: - void triggerDiffSelected(); - void diffActivated(const QModelIndex &index); - void diffActivatedDelayed(); - void updateActions(); - void updateSubmitAction(); - void updateDiffAction(); - void editorCustomContextMenuRequested(const QPoint &); - -private: - bool hasSelection() const; - bool hasCheckedFiles() const; - - SubmitEditorWidgetPrivate *m_d; -}; -} // namespace Utils - -#endif // SUBMITEDITORWIDGET_H diff --git a/ground/gcs/src/libs/utils/submiteditorwidget.ui b/ground/gcs/src/libs/utils/submiteditorwidget.ui deleted file mode 100644 index 957210e40a..0000000000 --- a/ground/gcs/src/libs/utils/submiteditorwidget.ui +++ /dev/null @@ -1,72 +0,0 @@ - - - Utils::SubmitEditorWidget - - - - 0 - 0 - 582 - 502 - - - - Subversion Submit - - - - - - Des&cription - - - true - - - - - - false - - - - - - - - - - F&iles - - - true - - - - - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - diff --git a/ground/gcs/src/libs/utils/submitfieldwidget.cpp b/ground/gcs/src/libs/utils/submitfieldwidget.cpp deleted file mode 100644 index 902701a91e..0000000000 --- a/ground/gcs/src/libs/utils/submitfieldwidget.cpp +++ /dev/null @@ -1,389 +0,0 @@ -/** - ****************************************************************************** - * - * @file submitfieldwidget.cpp - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @brief - * @see The GNU Public License (GPL) Version 3 - * @defgroup - * @{ - * - *****************************************************************************/ -/* - * 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 "submitfieldwidget.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -enum { debug = 0 }; -enum { spacing = 2 }; - -static void inline setComboBlocked(QComboBox *cb, int index) -{ - const bool blocked = cb->blockSignals(true); - - cb->setCurrentIndex(index); - cb->blockSignals(blocked); -} - -namespace Utils { -// Field/Row entry -struct FieldEntry { - FieldEntry(); - void createGui(const QIcon &removeIcon); - void deleteGuiLater(); - - QComboBox *combo; - QHBoxLayout *layout; - QLineEdit *lineEdit; - QToolBar *toolBar; - QToolButton *clearButton; - QToolButton *browseButton; - int comboIndex; -}; - -FieldEntry::FieldEntry() : - combo(0), - layout(0), - lineEdit(0), - toolBar(0), - clearButton(0), - browseButton(0), - comboIndex(0) -{} - -void FieldEntry::createGui(const QIcon &removeIcon) -{ - layout = new QHBoxLayout; - layout->setMargin(0); - layout->setSpacing(spacing); - combo = new QComboBox; - layout->addWidget(combo); - lineEdit = new QLineEdit; - layout->addWidget(lineEdit); - toolBar = new QToolBar; - toolBar->setProperty("_q_custom_style_disabled", QVariant(true)); - layout->addWidget(toolBar); - clearButton = new QToolButton; - clearButton->setIcon(removeIcon); - toolBar->addWidget(clearButton); - browseButton = new QToolButton; - browseButton->setText(QLatin1String("...")); - toolBar->addWidget(browseButton); -} - -void FieldEntry::deleteGuiLater() -{ - clearButton->deleteLater(); - browseButton->deleteLater(); - toolBar->deleteLater(); - lineEdit->deleteLater(); - combo->deleteLater(); - layout->deleteLater(); -} - -// ------- SubmitFieldWidgetPrivate -struct SubmitFieldWidgetPrivate { - SubmitFieldWidgetPrivate(); - - int findSender(const QObject *o) const; - int findField(const QString &f, int excluded = -1) const; - inline QString fieldText(int) const; - inline QString fieldValue(int) const; - inline void focusField(int); - - const QIcon removeFieldIcon; - QStringList fields; - QCompleter *completer; - bool hasBrowseButton; - bool allowDuplicateFields; - - QList fieldEntries; - QVBoxLayout *layout; -}; - -SubmitFieldWidgetPrivate::SubmitFieldWidgetPrivate() : - removeFieldIcon(QLatin1String(":/utils/images/removesubmitfield.png")), - completer(0), - hasBrowseButton(false), - allowDuplicateFields(false), - layout(0) -{} - -int SubmitFieldWidgetPrivate::findSender(const QObject *o) const -{ - const int count = fieldEntries.size(); - - for (int i = 0; i < count; i++) { - const FieldEntry &fe = fieldEntries.at(i); - if (fe.combo == o || fe.browseButton == o || fe.clearButton == o || fe.lineEdit == o) { - return i; - } - } - return -1; -} - -int SubmitFieldWidgetPrivate::findField(const QString &ft, int excluded) const -{ - const int count = fieldEntries.size(); - - for (int i = 0; i < count; i++) { - if (i != excluded && fieldText(i) == ft) { - return i; - } - } - return -1; -} - -QString SubmitFieldWidgetPrivate::fieldText(int pos) const -{ - return fieldEntries.at(pos).combo->currentText(); -} - -QString SubmitFieldWidgetPrivate::fieldValue(int pos) const -{ - return fieldEntries.at(pos).lineEdit->text(); -} - -void SubmitFieldWidgetPrivate::focusField(int pos) -{ - fieldEntries.at(pos).lineEdit->setFocus(Qt::TabFocusReason); -} - -// SubmitFieldWidget -SubmitFieldWidget::SubmitFieldWidget(QWidget *parent) : - QWidget(parent), - m_d(new SubmitFieldWidgetPrivate) -{ - m_d->layout = new QVBoxLayout; - m_d->layout->setMargin(0); - m_d->layout->setSpacing(spacing); - setLayout(m_d->layout); -} - -SubmitFieldWidget::~SubmitFieldWidget() -{ - delete m_d; -} - -void SubmitFieldWidget::setFields(const QStringList & f) -{ - // remove old fields - for (int i = m_d->fieldEntries.size() - 1; i >= 0; i--) { - removeField(i); - } - - m_d->fields = f; - if (!f.empty()) { - createField(f.front()); - } -} - -QStringList SubmitFieldWidget::fields() const -{ - return m_d->fields; -} - -bool SubmitFieldWidget::hasBrowseButton() const -{ - return m_d->hasBrowseButton; -} - -void SubmitFieldWidget::setHasBrowseButton(bool d) -{ - if (m_d->hasBrowseButton == d) { - return; - } - m_d->hasBrowseButton = d; - foreach(const FieldEntry &fe, m_d->fieldEntries) - fe.browseButton->setVisible(d); -} - -bool SubmitFieldWidget::allowDuplicateFields() const -{ - return m_d->allowDuplicateFields; -} - -void SubmitFieldWidget::setAllowDuplicateFields(bool v) -{ - m_d->allowDuplicateFields = v; -} - -QCompleter *SubmitFieldWidget::completer() const -{ - return m_d->completer; -} - -void SubmitFieldWidget::setCompleter(QCompleter *c) -{ - if (c == m_d->completer) { - return; - } - m_d->completer = c; - foreach(const FieldEntry &fe, m_d->fieldEntries) - fe.lineEdit->setCompleter(c); -} - -QString SubmitFieldWidget::fieldValue(int pos) const -{ - return m_d->fieldValue(pos); -} - -void SubmitFieldWidget::setFieldValue(int pos, const QString &value) -{ - m_d->fieldEntries.at(pos).lineEdit->setText(value); -} - -QString SubmitFieldWidget::fieldValues() const -{ - const QChar blank = QLatin1Char(' '); - const QChar newLine = QLatin1Char('\n'); - // Format as "RevBy: value\nSigned-Off: value\n" - QString rc; - - foreach(const FieldEntry &fe, m_d->fieldEntries) { - const QString value = fe.lineEdit->text().trimmed(); - - if (!value.isEmpty()) { - rc += fe.combo->currentText(); - rc += blank; - rc += value; - rc += newLine; - } - } - return rc; -} - -void SubmitFieldWidget::createField(const QString &f) -{ - FieldEntry fe; - - fe.createGui(m_d->removeFieldIcon); - fe.combo->addItems(m_d->fields); - if (!f.isEmpty()) { - const int index = fe.combo->findText(f); - if (index != -1) { - setComboBlocked(fe.combo, index); - fe.comboIndex = index; - } - } - - connect(fe.browseButton, SIGNAL(clicked()), this, SLOT(slotBrowseButtonClicked())); - if (!m_d->hasBrowseButton) { - fe.browseButton->setVisible(false); - } - - if (m_d->completer) { - fe.lineEdit->setCompleter(m_d->completer); - } - - connect(fe.combo, SIGNAL(currentIndexChanged(int)), - this, SLOT(slotComboIndexChanged(int))); - connect(fe.clearButton, SIGNAL(clicked()), - this, SLOT(slotRemove())); - m_d->layout->addLayout(fe.layout); - m_d->fieldEntries.push_back(fe); -} - -void SubmitFieldWidget::slotRemove() -{ - // Never remove first entry - const int index = m_d->findSender(sender()); - - switch (index) { - case -1: - break; - case 0: - m_d->fieldEntries.front().lineEdit->clear(); - break; - default: - removeField(index); - break; - } -} - -void SubmitFieldWidget::removeField(int index) -{ - FieldEntry fe = m_d->fieldEntries.takeAt(index); - QLayoutItem *item = m_d->layout->takeAt(index); - - fe.deleteGuiLater(); - delete item; -} - -void SubmitFieldWidget::slotComboIndexChanged(int comboIndex) -{ - const int pos = m_d->findSender(sender()); - - if (debug) { - qDebug() << '>' << Q_FUNC_INFO << pos; - } - if (pos == -1) { - return; - } - // Accept new index or reset combo to previous value? - int &previousIndex = m_d->fieldEntries[pos].comboIndex; - if (comboIndexChange(pos, comboIndex)) { - previousIndex = comboIndex; - } else { - setComboBlocked(m_d->fieldEntries.at(pos).combo, previousIndex); - } - if (debug) { - qDebug() << '<' << Q_FUNC_INFO << pos; - } -} - -// Handle change of a combo. Return "false" if the combo -// is to be reset (refuse new field). -bool SubmitFieldWidget::comboIndexChange(int pos, int index) -{ - const QString newField = m_d->fieldEntries.at(pos).combo->itemText(index); - - // If the field is visible elsewhere: focus the existing one and refuse - if (!m_d->allowDuplicateFields) { - const int existingFieldIndex = m_d->findField(newField, pos); - if (existingFieldIndex != -1) { - m_d->focusField(existingFieldIndex); - return false; - } - } - // Empty value: just change the field - if (m_d->fieldValue(pos).isEmpty()) { - return true; - } - // Non-empty: Create a new field and reset the triggering combo - createField(newField); - return false; -} - -void SubmitFieldWidget::slotBrowseButtonClicked() -{ - const int pos = m_d->findSender(sender()); - emit browseButtonClicked(pos, m_d->fieldText(pos)); -} -} diff --git a/ground/gcs/src/libs/utils/submitfieldwidget.h b/ground/gcs/src/libs/utils/submitfieldwidget.h deleted file mode 100644 index 4dc3ea3942..0000000000 --- a/ground/gcs/src/libs/utils/submitfieldwidget.h +++ /dev/null @@ -1,93 +0,0 @@ -/** - ****************************************************************************** - * - * @file submitfieldwidget.h - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @brief - * @see The GNU Public License (GPL) Version 3 - * @defgroup - * @{ - * - *****************************************************************************/ -/* - * 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 SUBMITFIELDWIDGET_H -#define SUBMITFIELDWIDGET_H - -#include "utils_global.h" - -#include - -QT_BEGIN_NAMESPACE -class QCompleter; -QT_END_NAMESPACE - -namespace Utils { -struct SubmitFieldWidgetPrivate; - -/* A widget for editing submit message fields like "reviewed-by:", - * "signed-off-by:". It displays them in a vertical row of combo/line edit fields - * that is modeled after the target address controls of mail clients. - * When choosing a different field in the combo, a new row is opened if text - * has been entered for the current field. Optionally, a "Browse..." button and - * completer can be added. */ -class QTCREATOR_UTILS_EXPORT SubmitFieldWidget : public QWidget { - Q_OBJECT Q_PROPERTY(QStringList fields READ fields WRITE setFields DESIGNABLE true) - Q_PROPERTY(bool hasBrowseButton READ hasBrowseButton WRITE setHasBrowseButton DESIGNABLE true) - Q_PROPERTY(bool allowDuplicateFields READ allowDuplicateFields WRITE setAllowDuplicateFields DESIGNABLE true) - -public: - explicit SubmitFieldWidget(QWidget *parent = 0); - virtual ~SubmitFieldWidget(); - - QStringList fields() const; - void setFields(const QStringList &); - - bool hasBrowseButton() const; - void setHasBrowseButton(bool d); - - // Allow several entries for fields ("reviewed-by: a", "reviewed-by: b") - bool allowDuplicateFields() const; - void setAllowDuplicateFields(bool); - - QCompleter *completer() const; - void setCompleter(QCompleter *c); - - QString fieldValue(int pos) const; - void setFieldValue(int pos, const QString &value); - - QString fieldValues() const; - -signals: - void browseButtonClicked(int pos, const QString &field); - -private slots: - void slotRemove(); - void slotComboIndexChanged(int); - void slotBrowseButtonClicked(); - -private: - void removeField(int index); - bool comboIndexChange(int fieldNumber, int index); - void createField(const QString &f); - - SubmitFieldWidgetPrivate *m_d; -}; -} - -#endif // SUBMITFIELDWIDGET_H diff --git a/ground/gcs/src/libs/utils/uncommentselection.cpp b/ground/gcs/src/libs/utils/uncommentselection.cpp deleted file mode 100644 index f58c624359..0000000000 --- a/ground/gcs/src/libs/utils/uncommentselection.cpp +++ /dev/null @@ -1,161 +0,0 @@ -/** - ****************************************************************************** - * - * @file uncommentselection.cpp - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @brief - * @see The GNU Public License (GPL) Version 3 - * @defgroup - * @{ - * - *****************************************************************************/ -/* - * 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 "uncommentselection.h" -#include -#include -#include -#include - -void Utils::unCommentSelection(QPlainTextEdit *edit) -{ - QTextCursor cursor = edit->textCursor(); - QTextDocument *doc = cursor.document(); - - cursor.beginEditBlock(); - - int pos = cursor.position(); - int anchor = cursor.anchor(); - int start = qMin(anchor, pos); - int end = qMax(anchor, pos); - bool anchorIsStart = (anchor == start); - - QTextBlock startBlock = doc->findBlock(start); - QTextBlock endBlock = doc->findBlock(end); - - if (end > start && endBlock.position() == end) { - --end; - endBlock = endBlock.previous(); - } - - bool doCStyleUncomment = false; - bool doCStyleComment = false; - bool doCppStyleUncomment = false; - - bool hasSelection = cursor.hasSelection(); - - if (hasSelection) { - QString startText = startBlock.text(); - int startPos = start - startBlock.position(); - bool hasLeadingCharacters = !startText.left(startPos).trimmed().isEmpty(); - if ((startPos >= 2 - && startText.at(startPos - 2) == QLatin1Char('/') - && startText.at(startPos - 1) == QLatin1Char('*'))) { - startPos -= 2; - start -= 2; - } - - bool hasSelStart = (startPos < startText.length() - 2 - && startText.at(startPos) == QLatin1Char('/') - && startText.at(startPos + 1) == QLatin1Char('*')); - - - QString endText = endBlock.text(); - int endPos = end - endBlock.position(); - bool hasTrailingCharacters = !endText.left(endPos).remove(QLatin1String("//")).trimmed().isEmpty() - && !endText.mid(endPos).trimmed().isEmpty(); - if ((endPos <= endText.length() - 2 - && endText.at(endPos) == QLatin1Char('*') - && endText.at(endPos + 1) == QLatin1Char('/'))) { - endPos += 2; - end += 2; - } - - bool hasSelEnd = (endPos >= 2 - && endText.at(endPos - 2) == QLatin1Char('*') - && endText.at(endPos - 1) == QLatin1Char('/')); - - doCStyleUncomment = hasSelStart && hasSelEnd; - doCStyleComment = !doCStyleUncomment && (hasLeadingCharacters || hasTrailingCharacters); - } - - if (doCStyleUncomment) { - cursor.setPosition(end); - cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor, 2); - cursor.removeSelectedText(); - cursor.setPosition(start); - cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, 2); - cursor.removeSelectedText(); - } else if (doCStyleComment) { - cursor.setPosition(end); - cursor.insertText(QLatin1String("*/")); - cursor.setPosition(start); - cursor.insertText(QLatin1String("/*")); - } else { - endBlock = endBlock.next(); - doCppStyleUncomment = true; - for (QTextBlock block = startBlock; block != endBlock; block = block.next()) { - QString text = block.text(); - if (!text.trimmed().startsWith(QLatin1String("//"))) { - doCppStyleUncomment = false; - break; - } - } - for (QTextBlock block = startBlock; block != endBlock; block = block.next()) { - if (doCppStyleUncomment) { - QString text = block.text(); - int i = 0; - while (i < text.size() - 1) { - if (text.at(i) == QLatin1Char('/') - && text.at(i + 1) == QLatin1Char('/')) { - cursor.setPosition(block.position() + i); - cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, 2); - cursor.removeSelectedText(); - break; - } - if (!text.at(i).isSpace()) { - break; - } - ++i; - } - } else { - cursor.setPosition(block.position()); - cursor.insertText(QLatin1String("//")); - } - } - } - - // adjust selection when commenting out - if (hasSelection && !doCStyleUncomment && !doCppStyleUncomment) { - cursor = edit->textCursor(); - if (!doCStyleComment) { - start = startBlock.position(); // move the double slashes into the selection - } - int lastSelPos = anchorIsStart ? cursor.position() : cursor.anchor(); - if (anchorIsStart) { - cursor.setPosition(start); - cursor.setPosition(lastSelPos, QTextCursor::KeepAnchor); - } else { - cursor.setPosition(lastSelPos); - cursor.setPosition(start, QTextCursor::KeepAnchor); - } - edit->setTextCursor(cursor); - } - - cursor.endEditBlock(); -} diff --git a/ground/gcs/src/libs/utils/uncommentselection.h b/ground/gcs/src/libs/utils/uncommentselection.h deleted file mode 100644 index 56c9f376d4..0000000000 --- a/ground/gcs/src/libs/utils/uncommentselection.h +++ /dev/null @@ -1,42 +0,0 @@ -/** - ****************************************************************************** - * - * @file uncommentselection.h - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * Parts by Nokia Corporation (qt-info@nokia.com) Copyright (C) 2009. - * @brief - * @see The GNU Public License (GPL) Version 3 - * @defgroup - * @{ - * - *****************************************************************************/ -/* - * 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 UNCOMMENTSELECTION_H -#define UNCOMMENTSELECTION_H - -#include "utils_global.h" - -QT_BEGIN_NAMESPACE -class QPlainTextEdit; -QT_END_NAMESPACE - -namespace Utils { -QTCREATOR_UTILS_EXPORT void unCommentSelection(QPlainTextEdit *edit); -} // end of namespace Utils - -#endif // UNCOMMENTSELECTION_H diff --git a/ground/gcs/src/libs/utils/utils.pro b/ground/gcs/src/libs/utils/utils.pro index 60aa5d042e..41307d0363 100644 --- a/ground/gcs/src/libs/utils/utils.pro +++ b/ground/gcs/src/libs/utils/utils.pro @@ -12,28 +12,13 @@ DEFINES += LIB_REL_PATH=$$shell_quote(\"$$relative_path($$GCS_LIBRARY_PATH, $$GC DEFINES += PLUGIN_REL_PATH=$$shell_quote(\"$$relative_path($$GCS_PLUGIN_PATH, $$GCS_APP_PATH)\") SOURCES += \ - reloadpromptutils.cpp \ stringutils.cpp \ pathchooser.cpp \ - pathlisteditor.cpp \ - filewizardpage.cpp \ - filewizarddialog.cpp \ - projectintropage.cpp \ basevalidatinglineedit.cpp \ - filenamevalidatinglineedit.cpp \ - projectnamevalidatinglineedit.cpp \ - codegeneration.cpp \ - newclasswidget.cpp \ - classnamevalidatinglineedit.cpp \ linecolumnlabel.cpp \ qtcolorbutton.cpp \ - savedaction.cpp \ - submiteditorwidget.cpp \ synchronousprocess.cpp \ - submitfieldwidget.cpp \ consoleprocess.cpp \ - uncommentselection.cpp \ - parameteraction.cpp \ treewidgetcolumnstretcher.cpp \ checkablemessagebox.cpp \ styledbar.cpp \ @@ -56,7 +41,6 @@ SOURCES += \ mustache.cpp \ textbubbleslider.cpp - SOURCES += xmlconfig.cpp win32 { @@ -70,30 +54,15 @@ else:SOURCES += consoleprocess_unix.cpp HEADERS += \ utils_global.h \ - reloadpromptutils.h \ stringutils.h \ listutils.h \ pathchooser.h \ - pathlisteditor.h \ - filewizardpage.h \ - filewizarddialog.h \ - projectintropage.h \ basevalidatinglineedit.h \ - filenamevalidatinglineedit.h \ - projectnamevalidatinglineedit.h \ - codegeneration.h \ - newclasswidget.h \ - classnamevalidatinglineedit.h \ linecolumnlabel.h \ qtcolorbutton.h \ - savedaction.h \ - submiteditorwidget.h \ abstractprocess.h \ consoleprocess.h \ synchronousprocess.h \ - submitfieldwidget.h \ - uncommentselection.h \ - parameteraction.h \ treewidgetcolumnstretcher.h \ checkablemessagebox.h \ qtcassert.h \ @@ -121,10 +90,6 @@ HEADERS += \ HEADERS += xmlconfig.h FORMS += \ - filewizardpage.ui \ - projectintropage.ui \ - newclasswidget.ui \ - submiteditorwidget.ui \ checkablemessagebox.ui RESOURCES += utils.qrc diff --git a/ground/gcs/src/libs/utils/utils.qrc b/ground/gcs/src/libs/utils/utils.qrc index ee388cc664..3e639b708d 100644 --- a/ground/gcs/src/libs/utils/utils.qrc +++ b/ground/gcs/src/libs/utils/utils.qrc @@ -1,6 +1,5 @@ - images/removesubmitfield.png fonts/PTS75F.ttf From 888e421de0b21cdf770db09c26920ae875405dcc Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Mon, 24 Apr 2017 21:23:54 +0200 Subject: [PATCH 230/624] LP-513 unrelated uncrustify --- flight/pios/common/pios_rfm22b.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/flight/pios/common/pios_rfm22b.c b/flight/pios/common/pios_rfm22b.c index 7fa05e07b2..0579c99a97 100644 --- a/flight/pios/common/pios_rfm22b.c +++ b/flight/pios/common/pios_rfm22b.c @@ -783,8 +783,8 @@ bool PIOS_RFM22B_TransmitPacket(uint32_t rfm22b_id, uint8_t *p, uint8_t len) return false; } - rfm22b_dev->tx_packet_handle = p; - rfm22b_dev->packet_start_time = pios_rfm22_time_ms(); + rfm22b_dev->tx_packet_handle = p; + rfm22b_dev->packet_start_time = pios_rfm22_time_ms(); if (rfm22b_dev->packet_start_time == 0) { rfm22b_dev->packet_start_time = 1; } From 01f5baaed297d608ad274794c5b6fdc36d29a55f Mon Sep 17 00:00:00 2001 From: Vladimir Zidar Date: Tue, 25 Apr 2017 13:11:37 +0200 Subject: [PATCH 231/624] LP-480 Removed PIOS_BOARD_USART_Ioctl() and moved inverter handling to pios_usart directly. Handling is now conditionally built in based on PIOS_USART_INVERTER_PORT define. --- flight/pios/common/pios_dsm.c | 2 +- flight/pios/inc/pios_com.h | 2 + flight/pios/inc/pios_usart.h | 3 ++ flight/pios/stm32f10x/pios_usart.c | 48 +++++++++++++++-- flight/pios/stm32f4xx/pios_usart.c | 51 ++++++++++++++++--- .../boards/coptercontrol/board_hw_defs.c | 9 ---- .../coptercontrol/firmware/pios_board.c | 35 ------------- .../targets/boards/coptercontrol/pios_board.h | 15 ++++-- .../boards/discoveryf4bare/board_hw_defs.c | 8 --- .../discoveryf4bare/firmware/pios_board.c | 36 ------------- .../boards/discoveryf4bare/pios_board.h | 8 ++- .../targets/boards/revolution/board_hw_defs.c | 9 ---- .../boards/revolution/firmware/pios_board.c | 36 ------------- flight/targets/boards/revolution/pios_board.h | 8 ++- .../targets/boards/revonano/board_hw_defs.c | 42 +++++++-------- .../boards/revonano/firmware/pios_board.c | 36 ------------- flight/targets/boards/revonano/pios_board.h | 8 ++- .../targets/boards/revoproto/board_hw_defs.c | 9 ---- .../boards/revoproto/firmware/pios_board.c | 36 ------------- flight/targets/boards/revoproto/pios_board.h | 8 ++- flight/targets/boards/sparky2/board_hw_defs.c | 10 ---- .../boards/sparky2/firmware/pios_board.c | 35 ------------- flight/targets/boards/sparky2/pios_board.h | 9 +++- 23 files changed, 158 insertions(+), 305 deletions(-) diff --git a/flight/pios/common/pios_dsm.c b/flight/pios/common/pios_dsm.c index 747e2b91f4..9f66a1aff8 100644 --- a/flight/pios/common/pios_dsm.c +++ b/flight/pios/common/pios_dsm.c @@ -318,7 +318,7 @@ int32_t PIOS_DSM_Init(uint32_t *dsm_id, PIOS_DEBUG_Assert(driver->ioctl); - if ((driver->ioctl)(lower_id, PIOS_IOCTL_USART_GET_RXGPIO, &rxpin) < 0) { + if ((driver->ioctl)(lower_id, PIOS_IOCTL_USART_GET_DSMBIND, &rxpin) < 0) { return -1; } diff --git a/flight/pios/inc/pios_com.h b/flight/pios/inc/pios_com.h index 113f38d6fd..4b827ad8de 100644 --- a/flight/pios/inc/pios_com.h +++ b/flight/pios/inc/pios_com.h @@ -146,6 +146,8 @@ enum pios_com_ioctl_type { COM_IOCTL_TYPE_SOFT_UART, }; +#define COM_IOCTL_ENOSYS (-1) /* Function not implemented */ + #endif /* PIOS_COM_H */ /** diff --git a/flight/pios/inc/pios_usart.h b/flight/pios/inc/pios_usart.h index 35e35c89ba..18208f4a44 100644 --- a/flight/pios/inc/pios_usart.h +++ b/flight/pios/inc/pios_usart.h @@ -53,6 +53,9 @@ enum PIOS_USART_Inverted { /* PIOS_IRQ_PRIO_ values */ #define PIOS_IOCTL_USART_SET_IRQ_PRIO COM_IOCTL(COM_IOCTL_TYPE_USART, 6, uint8_t) +#define PIOS_IOCTL_USART_GET_DSMBIND COM_IOCTL(COM_IOCTL_TYPE_USART, 7, struct stm32_gpio) + + #endif /* PIOS_USART_H */ /** diff --git a/flight/pios/stm32f10x/pios_usart.c b/flight/pios/stm32f10x/pios_usart.c index cc1e232323..4f3881ac34 100644 --- a/flight/pios/stm32f10x/pios_usart.c +++ b/flight/pios/stm32f10x/pios_usart.c @@ -190,7 +190,21 @@ int32_t PIOS_USART_Init(uint32_t *usart_id, const struct pios_usart_cfg *cfg) /* DTR handling? */ - *usart_id = (uint32_t)usart_dev; +#ifdef PIOS_USART_INVERTER_PORT + /* Initialize inverter gpio and set it to off */ + if (usart_dev->cfg->regs == PIOS_USART_INVERTER_PORT) { + GPIO_InitTypeDef inverterGPIOInit = { + .GPIO_Pin = PIOS_USART_INVERTER_PIN, + .GPIO_Mode = GPIO_Mode_Out_PP, + .GPIO_Speed = GPIO_Speed_2MHz, + }; + GPIO_Init(PIOS_USART_INVERTER_GPIO, &inverterGPIOInit); + + GPIO_WriteBit(PIOS_USART_INVERTER_GPIO, + PIOS_USART_INVERTER_PIN, + PIOS_USART_INVERTER_DISABLE); + } +#endif /* Configure USART Interrupts */ switch ((uint32_t)usart_dev->cfg->regs) { @@ -210,6 +224,8 @@ int32_t PIOS_USART_Init(uint32_t *usart_id, const struct pios_usart_cfg *cfg) PIOS_USART_SetIrqPrio(usart_dev, PIOS_IRQ_PRIO_MID); + *usart_id = (uint32_t)usart_dev; + return 0; out_fail: @@ -462,10 +478,35 @@ static int32_t PIOS_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param) PIOS_Assert(valid); + /* First try board specific IOCTL to allow overriding default functions */ + if (usart_dev->cfg->ioctl) { + int32_t ret = usart_dev->cfg->ioctl(usart_id, ctl, param); + if (ret != COM_IOCTL_ENOSYS) { + return ret; + } + } + switch (ctl) { case PIOS_IOCTL_USART_SET_IRQ_PRIO: return PIOS_USART_SetIrqPrio(usart_dev, *(uint8_t *)param); +#ifdef PIOS_USART_INVERTER_PORT + case PIOS_IOCTL_USART_SET_INVERTED: + if (usart_dev->cfg->regs != PIOS_USART_INVERTER_PORT) { + return COM_IOCTL_ENOSYS; /* don't know how */ + } + GPIO_WriteBit(PIOS_USART_INVERTER_GPIO, + PIOS_USART_INVERTER_PIN, + (*(enum PIOS_USART_Inverted *)param & PIOS_USART_Inverted_Rx) ? PIOS_USART_INVERTER_ENABLE : PIOS_USART_INVERTER_DISABLE); + + break; +#endif /* PIOS_USART_INVERTER_PORT */ + case PIOS_IOCTL_USART_GET_DSMBIND: +#ifdef PIOS_USART_INVERTER_PORT + if (usart_dev->cfg->regs == PIOS_USART_INVERTER_PORT) { + return -2; /* do not allow dsm bind on port with inverter */ + } +#endif /* otherwise, return RXGPIO */ case PIOS_IOCTL_USART_GET_RXGPIO: *(struct stm32_gpio *)param = usart_dev->cfg->rx; break; @@ -476,10 +517,7 @@ static int32_t PIOS_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param) USART_HalfDuplexCmd(usart_dev->cfg->regs, *(bool *)param ? ENABLE : DISABLE); break; default: - if (usart_dev->cfg->ioctl) { - return usart_dev->cfg->ioctl(usart_id, ctl, param); - } - return -1; + return COM_IOCTL_ENOSYS; /* unknown ioctl */ } return 0; diff --git a/flight/pios/stm32f4xx/pios_usart.c b/flight/pios/stm32f4xx/pios_usart.c index 3731bb6580..c14a07c5de 100644 --- a/flight/pios/stm32f4xx/pios_usart.c +++ b/flight/pios/stm32f4xx/pios_usart.c @@ -218,8 +218,23 @@ int32_t PIOS_USART_Init(uint32_t *usart_id, const struct pios_usart_cfg *cfg) GPIO_Init(usart_dev->cfg->dtr.gpio, (GPIO_InitTypeDef *)&usart_dev->cfg->dtr.init); PIOS_USART_SetCtrlLine((uint32_t)usart_dev, COM_CTRL_LINE_DTR_MASK, 0); } - - *usart_id = (uint32_t)usart_dev; +#ifdef PIOS_USART_INVERTER_PORT + /* Initialize inverter gpio and set it to off */ + if (usart_dev->cfg->regs == PIOS_USART_INVERTER_PORT) { + GPIO_InitTypeDef inverterGPIOInit = { + .GPIO_Pin = PIOS_USART_INVERTER_PIN, + .GPIO_Speed = GPIO_Speed_2MHz, + .GPIO_Mode = GPIO_Mode_OUT, + .GPIO_OType = GPIO_OType_PP, + .GPIO_PuPd = GPIO_PuPd_UP + }; + GPIO_Init(PIOS_USART_INVERTER_GPIO, &inverterGPIOInit); + + GPIO_WriteBit(PIOS_USART_INVERTER_GPIO, + PIOS_USART_INVERTER_PIN, + PIOS_USART_INVERTER_DISABLE); + } +#endif /* Configure USART Interrupts */ switch ((uint32_t)usart_dev->cfg->regs) { @@ -252,6 +267,8 @@ int32_t PIOS_USART_Init(uint32_t *usart_id, const struct pios_usart_cfg *cfg) } PIOS_USART_SetIrqPrio(usart_dev, PIOS_IRQ_PRIO_MID); + *usart_id = (uint32_t)usart_dev; + return 0; out_fail: @@ -520,10 +537,35 @@ static int32_t PIOS_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param) PIOS_Assert(valid); + /* First try board specific IOCTL to allow overriding default functions */ + if (usart_dev->cfg->ioctl) { + int32_t ret = usart_dev->cfg->ioctl(usart_id, ctl, param); + if (ret != COM_IOCTL_ENOSYS) { + return ret; + } + } + switch (ctl) { case PIOS_IOCTL_USART_SET_IRQ_PRIO: return PIOS_USART_SetIrqPrio(usart_dev, *(uint8_t *)param); +#ifdef PIOS_USART_INVERTER_PORT + case PIOS_IOCTL_USART_SET_INVERTED: + if (usart_dev->cfg->regs != PIOS_USART_INVERTER_PORT) { + return COM_IOCTL_ENOSYS; /* don't know how */ + } + GPIO_WriteBit(PIOS_USART_INVERTER_GPIO, + PIOS_USART_INVERTER_PIN, + (*(enum PIOS_USART_Inverted *)param & PIOS_USART_Inverted_Rx) ? PIOS_USART_INVERTER_ENABLE : PIOS_USART_INVERTER_DISABLE); + + break; +#endif /* PIOS_USART_INVERTER_PORT */ + case PIOS_IOCTL_USART_GET_DSMBIND: +#ifdef PIOS_USART_INVERTER_PORT + if (usart_dev->cfg->regs == PIOS_USART_INVERTER_PORT) { + return -2; /* do not allow dsm bind on port with inverter */ + } +#endif /* otherwise, return RXGPIO */ case PIOS_IOCTL_USART_GET_RXGPIO: *(struct stm32_gpio *)param = usart_dev->cfg->rx; break; @@ -534,10 +576,7 @@ static int32_t PIOS_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param) USART_HalfDuplexCmd(usart_dev->cfg->regs, *(bool *)param ? ENABLE : DISABLE); break; default: - if (usart_dev->cfg->ioctl) { - return usart_dev->cfg->ioctl(usart_id, ctl, param); - } - return -1; + return COM_IOCTL_ENOSYS; /* unknown ioctl */ } return 0; diff --git a/flight/targets/boards/coptercontrol/board_hw_defs.c b/flight/targets/boards/coptercontrol/board_hw_defs.c index d6b93ff4c0..949234a6d9 100644 --- a/flight/targets/boards/coptercontrol/board_hw_defs.c +++ b/flight/targets/boards/coptercontrol/board_hw_defs.c @@ -597,14 +597,6 @@ static const struct pios_tim_channel pios_tim_ppm_flexi_port = TIM_SERVO_CHANNEL #include "pios_usart_priv.h" -// Inverter for SBUS handling -#define MAIN_USART_INVERTER_GPIO GPIOB -#define MAIN_USART_INVERTER_PIN GPIO_Pin_2 -#define MAIN_USART_INVERTER_ENABLE Bit_SET -#define MAIN_USART_INVERTER_DISABLE Bit_RESET - -static int32_t PIOS_BOARD_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param); - static const struct pios_usart_cfg pios_usart_main_cfg = { .regs = USART1, .rx = { @@ -623,7 +615,6 @@ static const struct pios_usart_cfg pios_usart_main_cfg = { .GPIO_Mode = GPIO_Mode_AF_PP, }, }, - .ioctl = PIOS_BOARD_USART_Ioctl, }; static const struct pios_usart_cfg pios_usart_flexi_cfg = { diff --git a/flight/targets/boards/coptercontrol/firmware/pios_board.c b/flight/targets/boards/coptercontrol/firmware/pios_board.c index 47509d2942..06f9d54acd 100644 --- a/flight/targets/boards/coptercontrol/firmware/pios_board.c +++ b/flight/targets/boards/coptercontrol/firmware/pios_board.c @@ -86,26 +86,6 @@ static const PIOS_BOARD_IO_UART_Function flexi_function_map[] = { [HWSETTINGS_CC_FLEXIPORT_MAVLINK] = PIOS_BOARD_IO_UART_MAVLINK, }; -int32_t PIOS_BOARD_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param) -{ - const struct pios_usart_cfg *usart_cfg = PIOS_USART_GetConfig(usart_id); - - switch (ctl) { - case PIOS_IOCTL_USART_SET_INVERTED: - if (usart_cfg->regs == pios_usart_main_cfg.regs) { /* main port */ - GPIO_WriteBit(MAIN_USART_INVERTER_GPIO, - MAIN_USART_INVERTER_PIN, - (*(enum PIOS_USART_Inverted *)param & PIOS_USART_Inverted_Rx) ? MAIN_USART_INVERTER_ENABLE : MAIN_USART_INVERTER_DISABLE); - - return 0; - } - break; - } - - return -1; -} - - /** * PIOS_Board_Init() * initializes all the core subsystems on this specific hardware @@ -252,21 +232,6 @@ void PIOS_Board_Init(void) } /* Configure main USART port */ - - /* Initialize inverter gpio and set it to off */ - { - GPIO_InitTypeDef inverterGPIOInit = { - .GPIO_Pin = MAIN_USART_INVERTER_PIN, - .GPIO_Mode = GPIO_Mode_Out_PP, - .GPIO_Speed = GPIO_Speed_2MHz, - }; - - GPIO_Init(MAIN_USART_INVERTER_GPIO, &inverterGPIOInit); - GPIO_WriteBit(MAIN_USART_INVERTER_GPIO, - MAIN_USART_INVERTER_PIN, - MAIN_USART_INVERTER_DISABLE); - } - uint8_t hwsettings_mainport; HwSettingsCC_MainPortGet(&hwsettings_mainport); diff --git a/flight/targets/boards/coptercontrol/pios_board.h b/flight/targets/boards/coptercontrol/pios_board.h index b256057499..370955e2af 100644 --- a/flight/targets/boards/coptercontrol/pios_board.h +++ b/flight/targets/boards/coptercontrol/pios_board.h @@ -116,16 +116,23 @@ extern uint32_t pios_i2c_flexi_adapter_id; // // See also pios_board.c // ------------------------- -#define PIOS_SPI_MAX_DEVS 2 +#define PIOS_SPI_MAX_DEVS 2 extern uint32_t pios_spi_gyro_adapter_id; -#define PIOS_SPI_MPU6000_ADAPTER (pios_spi_gyro_adapter_id) +#define PIOS_SPI_MPU6000_ADAPTER (pios_spi_gyro_adapter_id) extern uint32_t pios_spi_flash_accel_adapter_id; -#define PIOS_SPI_ADXL345_ADAPTER (pios_spi_flash_accel_adapter_id) +#define PIOS_SPI_ADXL345_ADAPTER (pios_spi_flash_accel_adapter_id) // ------------------------- // PIOS_USART // ------------------------- -#define PIOS_USART_MAX_DEVS 2 +#define PIOS_USART_MAX_DEVS 2 + +// Inverter for SBUS handling +#define PIOS_USART_INVERTER_PORT USART1 +#define PIOS_USART_INVERTER_GPIO GPIOB +#define PIOS_USART_INVERTER_PIN GPIO_Pin_2 +#define PIOS_USART_INVERTER_ENABLE Bit_SET +#define PIOS_USART_INVERTER_DISABLE Bit_RESET // ------------------------- // PIOS_COM diff --git a/flight/targets/boards/discoveryf4bare/board_hw_defs.c b/flight/targets/boards/discoveryf4bare/board_hw_defs.c index 15b2012a84..629038f582 100644 --- a/flight/targets/boards/discoveryf4bare/board_hw_defs.c +++ b/flight/targets/boards/discoveryf4bare/board_hw_defs.c @@ -606,13 +606,6 @@ static const struct flashfs_logfs_cfg flashfs_internal_user_cfg = { /* * MAIN USART */ -// Inverter for SBUS handling -#define MAIN_USART_INVERTER_GPIO GPIOC -#define MAIN_USART_INVERTER_PIN GPIO_Pin_0 -#define MAIN_USART_INVERTER_ENABLE Bit_SET -#define MAIN_USART_INVERTER_DISABLE Bit_RESET - -static int32_t PIOS_BOARD_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param); static const struct pios_usart_cfg pios_usart_main_cfg = { .regs = USART1, @@ -637,7 +630,6 @@ static const struct pios_usart_cfg pios_usart_main_cfg = { .GPIO_PuPd = GPIO_PuPd_UP }, }, - .ioctl = PIOS_BOARD_USART_Ioctl, }; /* diff --git a/flight/targets/boards/discoveryf4bare/firmware/pios_board.c b/flight/targets/boards/discoveryf4bare/firmware/pios_board.c index 544f98c789..e7d8e9c27a 100644 --- a/flight/targets/boards/discoveryf4bare/firmware/pios_board.c +++ b/flight/targets/boards/discoveryf4bare/firmware/pios_board.c @@ -99,25 +99,6 @@ static const PIOS_BOARD_IO_UART_Function flexi_function_map[] = { [HWSETTINGS_RM_FLEXIPORT_MAVLINK] = PIOS_BOARD_IO_UART_MAVLINK, }; -int32_t PIOS_BOARD_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param) -{ - const struct pios_usart_cfg *usart_cfg = PIOS_USART_GetConfig(usart_id); - - switch (ctl) { - case PIOS_IOCTL_USART_SET_INVERTED: - if (usart_cfg->regs == pios_usart_main_cfg.regs) { /* main port */ - GPIO_WriteBit(MAIN_USART_INVERTER_GPIO, - MAIN_USART_INVERTER_PIN, - (*(enum PIOS_USART_Inverted *)param & PIOS_USART_Inverted_Rx) ? MAIN_USART_INVERTER_ENABLE : MAIN_USART_INVERTER_DISABLE); - - return 0; - } - break; - } - - return -1; -} - /** * PIOS_Board_Init() * initializes all the core subsystems on this specific hardware @@ -256,23 +237,6 @@ void PIOS_Board_Init(void) #endif /* Configure main USART port */ - - /* Initialize inverter gpio and set it to off */ - { - GPIO_InitTypeDef inverterGPIOInit = { - .GPIO_Pin = MAIN_USART_INVERTER_PIN, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_OUT, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }; - - GPIO_Init(MAIN_USART_INVERTER_GPIO, &inverterGPIOInit); - GPIO_WriteBit(MAIN_USART_INVERTER_GPIO, - MAIN_USART_INVERTER_PIN, - MAIN_USART_INVERTER_DISABLE); - } - uint8_t hwsettings_mainport; HwSettingsRM_MainPortGet(&hwsettings_mainport); diff --git a/flight/targets/boards/discoveryf4bare/pios_board.h b/flight/targets/boards/discoveryf4bare/pios_board.h index 9c3d1ba73f..926887822b 100644 --- a/flight/targets/boards/discoveryf4bare/pios_board.h +++ b/flight/targets/boards/discoveryf4bare/pios_board.h @@ -119,7 +119,13 @@ extern uint32_t pios_i2c_flexiport_adapter_id; // // See also pios_board.c // ------------------------- -#define PIOS_USART_MAX_DEVS 5 +#define PIOS_USART_MAX_DEVS 5 +// Inverter for SBUS handling +#define PIOS_USART_INVERTER_PORT USART1 +#define PIOS_USART_INVERTER_GPIO GPIOC +#define PIOS_USART_INVERTER_PIN GPIO_Pin_0 +#define PIOS_USART_INVERTER_ENABLE Bit_SET +#define PIOS_USART_INVERTER_DISABLE Bit_RESET // ------------------------- // PIOS_COM diff --git a/flight/targets/boards/revolution/board_hw_defs.c b/flight/targets/boards/revolution/board_hw_defs.c index e4ff0a76e6..e99ec15437 100644 --- a/flight/targets/boards/revolution/board_hw_defs.c +++ b/flight/targets/boards/revolution/board_hw_defs.c @@ -794,14 +794,6 @@ static const struct flashfs_logfs_cfg flashfs_internal_cfg = { * MAIN USART */ -// Inverter for SBUS handling -#define MAIN_USART_INVERTER_GPIO GPIOC -#define MAIN_USART_INVERTER_PIN GPIO_Pin_0 -#define MAIN_USART_INVERTER_ENABLE Bit_SET -#define MAIN_USART_INVERTER_DISABLE Bit_RESET - -static int32_t PIOS_BOARD_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param); - static const struct pios_usart_cfg pios_usart_main_cfg = { .regs = USART1, .remap = GPIO_AF_USART1, @@ -825,7 +817,6 @@ static const struct pios_usart_cfg pios_usart_main_cfg = { .GPIO_PuPd = GPIO_PuPd_UP }, }, - .ioctl = PIOS_BOARD_USART_Ioctl, }; /* diff --git a/flight/targets/boards/revolution/firmware/pios_board.c b/flight/targets/boards/revolution/firmware/pios_board.c index e958bb7c80..63494acd0b 100644 --- a/flight/targets/boards/revolution/firmware/pios_board.c +++ b/flight/targets/boards/revolution/firmware/pios_board.c @@ -98,25 +98,6 @@ static const PIOS_BOARD_IO_UART_Function flexi_function_map[] = { [HWSETTINGS_RM_FLEXIPORT_MAVLINK] = PIOS_BOARD_IO_UART_MAVLINK, }; -int32_t PIOS_BOARD_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param) -{ - const struct pios_usart_cfg *usart_cfg = PIOS_USART_GetConfig(usart_id); - - switch (ctl) { - case PIOS_IOCTL_USART_SET_INVERTED: - if (usart_cfg->regs == pios_usart_main_cfg.regs) { /* main port */ - GPIO_WriteBit(MAIN_USART_INVERTER_GPIO, - MAIN_USART_INVERTER_PIN, - (*(enum PIOS_USART_Inverted *)param & PIOS_USART_Inverted_Rx) ? MAIN_USART_INVERTER_ENABLE : MAIN_USART_INVERTER_DISABLE); - - return 0; - } - break; - } - - return -1; -} - /** * PIOS_Board_Init() * initializes all the core subsystems on this specific hardware @@ -255,23 +236,6 @@ void PIOS_Board_Init(void) #endif /* Configure main USART port */ - - /* Initialize inverter gpio and set it to off */ - { - GPIO_InitTypeDef inverterGPIOInit = { - .GPIO_Pin = MAIN_USART_INVERTER_PIN, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_OUT, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }; - - GPIO_Init(MAIN_USART_INVERTER_GPIO, &inverterGPIOInit); - GPIO_WriteBit(MAIN_USART_INVERTER_GPIO, - MAIN_USART_INVERTER_PIN, - MAIN_USART_INVERTER_DISABLE); - } - uint8_t hwsettings_mainport; HwSettingsRM_MainPortGet(&hwsettings_mainport); diff --git a/flight/targets/boards/revolution/pios_board.h b/flight/targets/boards/revolution/pios_board.h index 6c4f67aaac..c58bf75e03 100644 --- a/flight/targets/boards/revolution/pios_board.h +++ b/flight/targets/boards/revolution/pios_board.h @@ -139,7 +139,13 @@ extern uint32_t pios_i2c_flexiport_adapter_id; // // See also pios_board.c // ------------------------- -#define PIOS_USART_MAX_DEVS 5 +#define PIOS_USART_MAX_DEVS 5 + +#define PIOS_USART_INVERTER_PORT USART1 +#define PIOS_USART_INVERTER_GPIO GPIOC +#define PIOS_USART_INVERTER_PIN GPIO_Pin_0 +#define PIOS_USART_INVERTER_ENABLE Bit_SET +#define PIOS_USART_INVERTER_DISABLE Bit_RESET // ------------------------- // PIOS_COM diff --git a/flight/targets/boards/revonano/board_hw_defs.c b/flight/targets/boards/revonano/board_hw_defs.c index 00540256a8..6a4aee3d27 100644 --- a/flight/targets/boards/revonano/board_hw_defs.c +++ b/flight/targets/boards/revonano/board_hw_defs.c @@ -42,29 +42,24 @@ * o5 | PA0 | TIM5_CH1 | ADC1_0 * o6 | PA1 | TIM5_CH2 | ADC1_1 */ -#define MAIN_USART_REGS USART2 -#define MAIN_USART_REMAP GPIO_AF_USART2 -#define MAIN_USART_IRQ USART2_IRQn -#define MAIN_USART_RX_GPIO GPIOA -#define MAIN_USART_RX_PIN GPIO_Pin_3 -#define MAIN_USART_TX_GPIO GPIOA -#define MAIN_USART_TX_PIN GPIO_Pin_2 -// Inverter for SBUS handling -#define MAIN_USART_INVERTER_GPIO GPIOC -#define MAIN_USART_INVERTER_PIN GPIO_Pin_15 -#define MAIN_USART_INVERTER_ENABLE Bit_SET -#define MAIN_USART_INVERTER_DISABLE Bit_RESET - -#define FLEXI_USART_REGS USART1 -#define FLEXI_USART_REMAP GPIO_AF_USART1 -#define FLEXI_USART_IRQ USART1_IRQn -#define FLEXI_USART_RX_GPIO GPIOB -#define FLEXI_USART_RX_PIN GPIO_Pin_7 -#define FLEXI_USART_TX_GPIO GPIOB -#define FLEXI_USART_TX_PIN GPIO_Pin_6 +#define MAIN_USART_REGS USART2 +#define MAIN_USART_REMAP GPIO_AF_USART2 +#define MAIN_USART_IRQ USART2_IRQn +#define MAIN_USART_RX_GPIO GPIOA +#define MAIN_USART_RX_PIN GPIO_Pin_3 +#define MAIN_USART_TX_GPIO GPIOA +#define MAIN_USART_TX_PIN GPIO_Pin_2 + +#define FLEXI_USART_REGS USART1 +#define FLEXI_USART_REMAP GPIO_AF_USART1 +#define FLEXI_USART_IRQ USART1_IRQn +#define FLEXI_USART_RX_GPIO GPIOB +#define FLEXI_USART_RX_PIN GPIO_Pin_7 +#define FLEXI_USART_TX_GPIO GPIOB +#define FLEXI_USART_TX_PIN GPIO_Pin_6 // ReceiverPort pin 3 -#define FLEXI_USART_DTR_GPIO GPIOB -#define FLEXI_USART_DTR_PIN GPIO_Pin_10 +#define FLEXI_USART_DTR_GPIO GPIOB +#define FLEXI_USART_DTR_PIN GPIO_Pin_10 #if defined(PIOS_INCLUDE_LED) @@ -245,8 +240,6 @@ void PIOS_SPI_gyro_irq_handler(void) * MAIN USART */ -static int32_t PIOS_BOARD_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param); - static const struct pios_usart_cfg pios_usart_main_cfg = { .regs = MAIN_USART_REGS, .remap = MAIN_USART_REMAP, @@ -270,7 +263,6 @@ static const struct pios_usart_cfg pios_usart_main_cfg = { .GPIO_PuPd = GPIO_PuPd_UP }, }, - .ioctl = PIOS_BOARD_USART_Ioctl, }; /* diff --git a/flight/targets/boards/revonano/firmware/pios_board.c b/flight/targets/boards/revonano/firmware/pios_board.c index 5f8fb7799c..42cb939d81 100644 --- a/flight/targets/boards/revonano/firmware/pios_board.c +++ b/flight/targets/boards/revonano/firmware/pios_board.c @@ -95,25 +95,6 @@ static const PIOS_BOARD_IO_UART_Function main_function_map[] = { [HWSETTINGS_RM_MAINPORT_MAVLINK] = PIOS_BOARD_IO_UART_MAVLINK, }; -int32_t PIOS_BOARD_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param) -{ - const struct pios_usart_cfg *usart_cfg = PIOS_USART_GetConfig(usart_id); - - switch (ctl) { - case PIOS_IOCTL_USART_SET_INVERTED: - if (usart_cfg->regs == pios_usart_main_cfg.regs) { /* main port */ - GPIO_WriteBit(MAIN_USART_INVERTER_GPIO, - MAIN_USART_INVERTER_PIN, - (*(enum PIOS_USART_Inverted *)param & PIOS_USART_Inverted_Rx) ? MAIN_USART_INVERTER_ENABLE : MAIN_USART_INVERTER_DISABLE); - - return 0; - } - break; - } - - return -1; -} - void PIOS_Board_Init(void) { const struct pios_board_info *bdinfo = &pios_board_info_blob; @@ -222,23 +203,6 @@ void PIOS_Board_Init(void) } /* Configure main USART port */ - - /* Initialize inverter gpio and set it to off */ - { - GPIO_InitTypeDef inverterGPIOInit = { - .GPIO_Pin = MAIN_USART_INVERTER_PIN, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_OUT, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }; - - GPIO_Init(MAIN_USART_INVERTER_GPIO, &inverterGPIOInit); - GPIO_WriteBit(MAIN_USART_INVERTER_GPIO, - MAIN_USART_INVERTER_PIN, - MAIN_USART_INVERTER_DISABLE); - } - uint8_t hwsettings_mainport; HwSettingsRM_MainPortGet(&hwsettings_mainport); diff --git a/flight/targets/boards/revonano/pios_board.h b/flight/targets/boards/revonano/pios_board.h index f6bcc20f23..47940f9618 100644 --- a/flight/targets/boards/revonano/pios_board.h +++ b/flight/targets/boards/revonano/pios_board.h @@ -135,7 +135,13 @@ extern uint32_t pios_i2c_flexiport_adapter_id; // // See also pios_board.c // ------------------------- -#define PIOS_USART_MAX_DEVS 5 +#define PIOS_USART_MAX_DEVS 5 +// Inverter for SBUS handling +#define PIOS_USART_INVERTER_PORT USART2 +#define PIOS_USART_INVERTER_GPIO GPIOC +#define PIOS_USART_INVERTER_PIN GPIO_Pin_15 +#define PIOS_USART_INVERTER_ENABLE Bit_SET +#define PIOS_USART_INVERTER_DISABLE Bit_RESET // ------------------------- // PIOS_COM diff --git a/flight/targets/boards/revoproto/board_hw_defs.c b/flight/targets/boards/revoproto/board_hw_defs.c index fb47680fe8..b35a522459 100644 --- a/flight/targets/boards/revoproto/board_hw_defs.c +++ b/flight/targets/boards/revoproto/board_hw_defs.c @@ -712,14 +712,6 @@ static const struct pios_usart_cfg pios_usart_aux_cfg = { * AUX USART SBUS ( UART/ S Bus label on rev2) */ -// Inverter for SBUS handling -#define MAIN_USART_INVERTER_GPIO GPIOC -#define MAIN_USART_INVERTER_PIN GPIO_Pin_3 -#define MAIN_USART_INVERTER_ENABLE Bit_SET -#define MAIN_USART_INVERTER_DISABLE Bit_RESET - -static int32_t PIOS_BOARD_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param); - static const struct pios_usart_cfg pios_usart_auxsbus_cfg = { .regs = UART4, .remap = GPIO_AF_UART4, @@ -743,7 +735,6 @@ static const struct pios_usart_cfg pios_usart_auxsbus_cfg = { .GPIO_PuPd = GPIO_PuPd_UP }, }, - .ioctl = PIOS_BOARD_USART_Ioctl, }; #endif /* PIOS_INCLUDE_COM_AUXSBUS */ diff --git a/flight/targets/boards/revoproto/firmware/pios_board.c b/flight/targets/boards/revoproto/firmware/pios_board.c index 66242f413f..bf957aeb1d 100644 --- a/flight/targets/boards/revoproto/firmware/pios_board.c +++ b/flight/targets/boards/revoproto/firmware/pios_board.c @@ -56,25 +56,6 @@ uintptr_t pios_user_fs_id; #include -int32_t PIOS_BOARD_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param) -{ - const struct pios_usart_cfg *usart_cfg = PIOS_USART_GetConfig(usart_id); - - switch (ctl) { - case PIOS_IOCTL_USART_SET_INVERTED: - if (usart_cfg->regs == pios_usart_auxsbus_cfg.regs) { /* main port */ - GPIO_WriteBit(MAIN_USART_INVERTER_GPIO, - MAIN_USART_INVERTER_PIN, - (*(enum PIOS_USART_Inverted *)param & PIOS_USART_Inverted_Rx) ? MAIN_USART_INVERTER_ENABLE : MAIN_USART_INVERTER_DISABLE); - - return 0; - } - break; - } - - return -1; -} - void PIOS_Board_Init(void) { /* Delay system */ @@ -183,23 +164,6 @@ void PIOS_Board_Init(void) #if defined(PIOS_INCLUDE_USB) PIOS_BOARD_IO_Configure_USB(); #endif - - /* Initialize inverter gpio and set it to off */ - { - GPIO_InitTypeDef inverterGPIOInit = { - .GPIO_Pin = MAIN_USART_INVERTER_PIN, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_OUT, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }; - - GPIO_Init(MAIN_USART_INVERTER_GPIO, &inverterGPIOInit); - GPIO_WriteBit(MAIN_USART_INVERTER_GPIO, - MAIN_USART_INVERTER_PIN, - MAIN_USART_INVERTER_DISABLE); - } - /* Configure IO ports */ /* Configure Telemetry port */ diff --git a/flight/targets/boards/revoproto/pios_board.h b/flight/targets/boards/revoproto/pios_board.h index 66d4c5cfe5..71a562dbf7 100644 --- a/flight/targets/boards/revoproto/pios_board.h +++ b/flight/targets/boards/revoproto/pios_board.h @@ -122,7 +122,13 @@ extern uint32_t pios_i2c_flexiport_adapter_id; // // See also pios_board.c // ------------------------- -#define PIOS_USART_MAX_DEVS 5 +#define PIOS_USART_MAX_DEVS 5 +// Inverter for SBUS handling +#define PIOS_USART_INVERTER_PORT UART4 +#define PIOS_USART_INVERTER_GPIO GPIOC +#define PIOS_USART_INVERTER_PIN GPIO_Pin_3 +#define PIOS_USART_INVERTER_ENABLE Bit_SET +#define PIOS_USART_INVERTER_DISABLE Bit_RESET // ------------------------- // PIOS_COM diff --git a/flight/targets/boards/sparky2/board_hw_defs.c b/flight/targets/boards/sparky2/board_hw_defs.c index 18ed6962f0..f7134734db 100644 --- a/flight/targets/boards/sparky2/board_hw_defs.c +++ b/flight/targets/boards/sparky2/board_hw_defs.c @@ -605,15 +605,6 @@ static const struct pios_usart_cfg pios_usart_flexi_cfg = { * RCVR PORT */ -// Inverter for SBUS handling -#define RCVR_USART_INVERTER_GPIO GPIOC -#define RCVR_USART_INVERTER_PIN GPIO_Pin_4 -#define RCVR_USART_INVERTER_ENABLE Bit_SET -#define RCVR_USART_INVERTER_DISABLE Bit_RESET - -static int32_t PIOS_BOARD_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param); - - static const struct pios_usart_cfg pios_usart_rcvr_cfg = { .regs = USART6, .remap = GPIO_AF_USART6, @@ -627,7 +618,6 @@ static const struct pios_usart_cfg pios_usart_rcvr_cfg = { .GPIO_PuPd = GPIO_PuPd_UP }, }, - .ioctl = PIOS_BOARD_USART_Ioctl, }; #endif /* PIOS_INCLUDE_USART */ diff --git a/flight/targets/boards/sparky2/firmware/pios_board.c b/flight/targets/boards/sparky2/firmware/pios_board.c index d9d7fd9ee5..4fc33f4abf 100644 --- a/flight/targets/boards/sparky2/firmware/pios_board.c +++ b/flight/targets/boards/sparky2/firmware/pios_board.c @@ -93,25 +93,6 @@ static const PIOS_BOARD_IO_UART_Function flexi_function_map[] = { [HWSETTINGS_SPK2_FLEXIPORT_MAVLINK] = PIOS_BOARD_IO_UART_MAVLINK, }; -int32_t PIOS_BOARD_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param) -{ - const struct pios_usart_cfg *usart_cfg = PIOS_USART_GetConfig(usart_id); - - switch (ctl) { - case PIOS_IOCTL_USART_SET_INVERTED: - if (usart_cfg->regs == pios_usart_rcvr_cfg.regs) { /* rcvr port */ - GPIO_WriteBit(RCVR_USART_INVERTER_GPIO, - RCVR_USART_INVERTER_PIN, - (*(enum PIOS_USART_Inverted *)param & PIOS_USART_Inverted_Rx) ? RCVR_USART_INVERTER_ENABLE : RCVR_USART_INVERTER_DISABLE); - - return 0; - } - break; - } - - return -1; -} - /** * PIOS_Board_Init() * initializes all the core subsystems on this specific hardware @@ -265,22 +246,6 @@ void PIOS_Board_Init(void) PIOS_BOARD_IO_Configure_RadioAuxStream(hwsettings_radioaux); #endif /* PIOS_INCLUDE_RFM22B */ - /* Initialize inverter gpio and set it to off */ - { - GPIO_InitTypeDef inverterGPIOInit = { - .GPIO_Pin = RCVR_USART_INVERTER_PIN, - .GPIO_Speed = GPIO_Speed_2MHz, - .GPIO_Mode = GPIO_Mode_OUT, - .GPIO_OType = GPIO_OType_PP, - .GPIO_PuPd = GPIO_PuPd_UP - }; - - GPIO_Init(RCVR_USART_INVERTER_GPIO, &inverterGPIOInit); - GPIO_WriteBit(RCVR_USART_INVERTER_GPIO, - RCVR_USART_INVERTER_PIN, - RCVR_USART_INVERTER_DISABLE); - } - // Configure the receiver port // Sparky2 receiver input on PC7 TIM8 CH2 // include PPM,S.Bus,DSM,SRXL,IBus,EX.Bus,HoTT SUMD,HoTT SUMH diff --git a/flight/targets/boards/sparky2/pios_board.h b/flight/targets/boards/sparky2/pios_board.h index d63e5cf3e2..9213d1d6e1 100644 --- a/flight/targets/boards/sparky2/pios_board.h +++ b/flight/targets/boards/sparky2/pios_board.h @@ -140,7 +140,14 @@ extern uint32_t pios_i2c_flexiport_adapter_id; // // See also pios_board.c // ------------------------- -#define PIOS_USART_MAX_DEVS 5 +#define PIOS_USART_MAX_DEVS 5 + +// Inverter for SBUS handling +#define PIOS_USART_INVERTER_PORT USART6 +#define PIOS_USART_INVERTER_GPIO GPIOC +#define PIOS_USART_INVERTER_PIN GPIO_Pin_4 +#define PIOS_USART_INVERTER_ENABLE Bit_SET +#define PIOS_USART_INVERTER_DISABLE Bit_RESET // ------------------------- // PIOS_COM From 1ebfb701f6fefa45fa5202216f6e054d1a8f5ccb Mon Sep 17 00:00:00 2001 From: Vladimir Zidar Date: Mon, 27 Mar 2017 15:51:43 +0200 Subject: [PATCH 232/624] LP-479 Initial DShot implementation, F4 & F1 --- flight/modules/Actuator/actuator.c | 34 +- flight/pios/common/pios_servo.c | 410 ++++++++++++++---- flight/pios/inc/pios_delay.h | 3 +- flight/pios/inc/pios_servo.h | 8 +- flight/pios/stm32f0x/inc/pios_delay_raw.h | 36 ++ flight/pios/stm32f10x/inc/pios_delay_raw.h | 43 ++ flight/pios/stm32f10x/pios_delay.c | 22 +- flight/pios/stm32f4xx/inc/pios_delay_raw.h | 43 ++ flight/pios/stm32f4xx/pios_delay.c | 24 +- .../src/plugins/config/configoutputwidget.cpp | 39 +- .../src/plugins/config/configoutputwidget.h | 1 + .../src/plugins/config/outputchannelform.cpp | 25 +- .../src/plugins/config/outputchannelform.h | 1 + .../uavobjectdefinition/actuatorsettings.xml | 3 +- 14 files changed, 550 insertions(+), 142 deletions(-) create mode 100644 flight/pios/stm32f0x/inc/pios_delay_raw.h create mode 100644 flight/pios/stm32f10x/inc/pios_delay_raw.h create mode 100644 flight/pios/stm32f4xx/inc/pios_delay_raw.h diff --git a/flight/modules/Actuator/actuator.c b/flight/modules/Actuator/actuator.c index 6ad511fdc5..0944a356d0 100644 --- a/flight/modules/Actuator/actuator.c +++ b/flight/modules/Actuator/actuator.c @@ -960,6 +960,12 @@ static bool set_channel(uint8_t mixer_channel, uint16_t value) // Remap 1000-2000 range to 5-25µs PIOS_Servo_Set(actuatorSettings.ChannelAddr[mixer_channel], (value * ACTUATOR_MULTISHOT_PULSE_FACTOR) - 180); break; + case ACTUATORSETTINGS_BANKMODE_DSHOT: + if (value > 0) { + value += 47; /* skip over reserved values */ + } + PIOS_Servo_Set(actuatorSettings.ChannelAddr[mixer_channel], value); + break; default: PIOS_Servo_Set(actuatorSettings.ChannelAddr[mixer_channel], value); break; @@ -990,9 +996,15 @@ static void actuator_update_rate_if_changed(bool force_update) { static uint16_t prevBankUpdateFreq[ACTUATORSETTINGS_BANKUPDATEFREQ_NUMELEM]; static uint8_t prevBankMode[ACTUATORSETTINGS_BANKMODE_NUMELEM]; + static uint16_t prevDShotMode; bool updateMode = force_update || (memcmp(prevBankMode, actuatorSettings.BankMode, sizeof(prevBankMode)) != 0); bool updateFreq = force_update || (memcmp(prevBankUpdateFreq, actuatorSettings.BankUpdateFreq, sizeof(prevBankUpdateFreq)) != 0); + if (force_update || (prevDShotMode != actuatorSettings.DShotMode)) { + PIOS_Servo_DSHot_Rate(actuatorSettings.DShotMode); + prevDShotMode = actuatorSettings.DShotMode; + } + // check if any setting is changed if (updateMode || updateFreq) { /* Something has changed, apply the settings to HW */ @@ -1000,30 +1012,36 @@ static void actuator_update_rate_if_changed(bool force_update) uint16_t freq[ACTUATORSETTINGS_BANKUPDATEFREQ_NUMELEM]; uint32_t clock[ACTUATORSETTINGS_BANKUPDATEFREQ_NUMELEM] = { 0 }; for (uint8_t i = 0; i < ACTUATORSETTINGS_BANKMODE_NUMELEM; i++) { - if (force_update || (actuatorSettings.BankMode[i] != prevBankMode[i])) { - PIOS_Servo_SetBankMode(i, - actuatorSettings.BankMode[i] == - ACTUATORSETTINGS_BANKMODE_PWM ? - PIOS_SERVO_BANK_MODE_PWM : - PIOS_SERVO_BANK_MODE_SINGLE_PULSE - ); - } + enum pios_servo_bank_mode servo_bank_mode = PIOS_SERVO_BANK_MODE_PWM; + switch (actuatorSettings.BankMode[i]) { case ACTUATORSETTINGS_BANKMODE_ONESHOT125: case ACTUATORSETTINGS_BANKMODE_ONESHOT42: case ACTUATORSETTINGS_BANKMODE_MULTISHOT: freq[i] = 100; // Value must be small enough so CCr isn't update until the PIOS_Servo_Update is triggered clock[i] = ACTUATOR_ONESHOT_CLOCK; // Setup an 12MHz timer clock + servo_bank_mode = PIOS_SERVO_BANK_MODE_SINGLE_PULSE; break; case ACTUATORSETTINGS_BANKMODE_PWMSYNC: freq[i] = 100; clock[i] = ACTUATOR_PWM_CLOCK; + servo_bank_mode = PIOS_SERVO_BANK_MODE_SINGLE_PULSE; + break; + case ACTUATORSETTINGS_BANKMODE_DSHOT: + freq[i] = 100; + clock[i] = ACTUATOR_PWM_CLOCK; + servo_bank_mode = PIOS_SERVO_BANK_MODE_DSHOT; break; default: // PWM freq[i] = actuatorSettings.BankUpdateFreq[i]; clock[i] = ACTUATOR_PWM_CLOCK; + servo_bank_mode = PIOS_SERVO_BANK_MODE_PWM; break; } + + if (force_update || (actuatorSettings.BankMode[i] != prevBankMode[i])) { + PIOS_Servo_SetBankMode(i, servo_bank_mode); + } } memcpy(prevBankMode, diff --git a/flight/pios/common/pios_servo.c b/flight/pios/common/pios_servo.c index 61592f5a79..41c703b875 100644 --- a/flight/pios/common/pios_servo.c +++ b/flight/pios/common/pios_servo.c @@ -38,24 +38,48 @@ /* Private Function Prototypes */ +#define PIOS_SERVO_GPIO_BANKS 3 + static const struct pios_servo_cfg *servo_cfg; -// determine if the related timer will work in synchronous (or OneShot/OneShot125) One Pulse mode. -static uint8_t pios_servo_bank_mode[PIOS_SERVO_BANKS] = { 0 }; -// used to skip updates when pulse length is higher than update cycle -static uint16_t pios_servo_bank_next_update[PIOS_SERVO_BANKS] = { 0 }; -static uint16_t pios_servo_bank_max_pulse[PIOS_SERVO_BANKS] = { 0 }; -// timer associated to each bank -static TIM_TypeDef *pios_servo_bank_timer[PIOS_SERVO_BANKS] = { 0 }; +static volatile uint32_t *pios_servo_bsrr[PIOS_SERVO_GPIO_BANKS]; // GPIO banks + +struct pios_servo_bank { + enum pios_servo_bank_mode mode; + uint16_t next_update; + uint16_t max_pulse; + TIM_TypeDef *timer; +}; + +struct pios_servo_pin { + struct pios_servo_bank *bank; + uint8_t bank_nr; + uint8_t gpio_bank; + uint16_t value; +}; + + +static struct pios_servo_bank pios_servo_banks[PIOS_SERVO_BANKS]; +static struct pios_servo_pin *pios_servo_pins; + -// index of bank used for each pin -static uint8_t *pios_servo_pin_bank; +// Dshot timing +static uint32_t pios_dshot_t0h_raw; +static uint32_t pios_dshot_t1h_raw; +static uint32_t pios_dshot_t_raw; static bool pios_servo_enabled = true; #define PIOS_SERVO_TIMER_CLOCK 1000000 #define PIOS_SERVO_SAFE_MARGIN 50 + +#define DSHOT_TIMING_ADJUST 8 +#define DSHOT_T0H_DIV 2666 +#define DSHOT_T1H_DIV 1333 +#define DSHOT_NUM_BITS 16 + + extern void PIOS_Servo_Disable() { if (!servo_cfg) { @@ -79,65 +103,123 @@ extern void PIOS_Servo_Disable() #else #error Unsupported MCU #endif - GPIO_Init(chan->pin.gpio, &init); - GPIO_ResetBits(chan->pin.gpio, chan->pin.init.GPIO_Pin); + + GPIO_Init(chan->pin.gpio, &init); } } -extern void PIOS_Servo_Enable() +static void PIOS_Servo_SetupBank(uint8_t bank_nr) { - if (!servo_cfg) { + struct pios_servo_bank *bank = &pios_servo_banks[bank_nr]; + + if (!bank->timer) { return; } + // Setup the timer accordingly + switch (bank->mode) { + case PIOS_SERVO_BANK_MODE_PWM: + case PIOS_SERVO_BANK_MODE_SINGLE_PULSE: + TIM_ARRPreloadConfig(bank->timer, ENABLE); + TIM_CtrlPWMOutputs(bank->timer, ENABLE); + TIM_SelectOnePulseMode(bank->timer, TIM_OPMode_Repetitive); + TIM_Cmd(bank->timer, ENABLE); + break; + default:; + // do not manage timers otherwise + } + + // Setup GPIO/AF for (uint8_t i = 0; (i < servo_cfg->num_channels); i++) { const struct pios_tim_channel *chan = &servo_cfg->channels[i]; - GPIO_Init(chan->pin.gpio, &chan->pin.init); + if (chan->timer != bank->timer) { // Not interested in this bank + continue; + } + + switch (bank->mode) { + case PIOS_SERVO_BANK_MODE_PWM: + case PIOS_SERVO_BANK_MODE_SINGLE_PULSE: + GPIO_Init(chan->pin.gpio, &chan->pin.init); #if defined(STM32F40_41xxx) || defined(STM32F446xx) || defined(STM32F411xE) - GPIO_PinAFConfig(chan->pin.gpio, chan->pin.pin_source, chan->remap); + GPIO_PinAFConfig(chan->pin.gpio, chan->pin.pin_source, chan->remap); #elif defined(STM32F10X_MD) - if (chan->remap) { - GPIO_PinRemapConfig(chan->remap, ENABLE); - } + if (chan->remap) { + GPIO_PinRemapConfig(chan->remap, ENABLE); + } #else #error Unsupported MCU #endif - /* Set up for output compare function */ - switch (chan->timer_chan) { - case TIM_Channel_1: - TIM_OC1Init(chan->timer, &servo_cfg->tim_oc_init); - TIM_OC1PreloadConfig(chan->timer, TIM_OCPreload_Enable); - break; - case TIM_Channel_2: - TIM_OC2Init(chan->timer, &servo_cfg->tim_oc_init); - TIM_OC2PreloadConfig(chan->timer, TIM_OCPreload_Enable); - break; - case TIM_Channel_3: - TIM_OC3Init(chan->timer, &servo_cfg->tim_oc_init); - TIM_OC3PreloadConfig(chan->timer, TIM_OCPreload_Enable); - break; - case TIM_Channel_4: - TIM_OC4Init(chan->timer, &servo_cfg->tim_oc_init); - TIM_OC4PreloadConfig(chan->timer, TIM_OCPreload_Enable); + /* Set up for output compare function */ + switch (chan->timer_chan) { + case TIM_Channel_1: + TIM_OC1Init(chan->timer, &servo_cfg->tim_oc_init); + TIM_OC1PreloadConfig(chan->timer, TIM_OCPreload_Enable); + break; + case TIM_Channel_2: + TIM_OC2Init(chan->timer, &servo_cfg->tim_oc_init); + TIM_OC2PreloadConfig(chan->timer, TIM_OCPreload_Enable); + break; + case TIM_Channel_3: + TIM_OC3Init(chan->timer, &servo_cfg->tim_oc_init); + TIM_OC3PreloadConfig(chan->timer, TIM_OCPreload_Enable); + break; + case TIM_Channel_4: + TIM_OC4Init(chan->timer, &servo_cfg->tim_oc_init); + TIM_OC4PreloadConfig(chan->timer, TIM_OCPreload_Enable); + break; + } + break; + + case PIOS_SERVO_BANK_MODE_DSHOT: + { + GPIO_InitTypeDef init = chan->pin.init; + +#if defined(STM32F40_41xxx) || defined(STM32F446xx) || defined(STM32F411xE) + init.GPIO_Mode = GPIO_Mode_OUT; +#elif defined(STM32F10X_MD) + init.GPIO_Mode = GPIO_Mode_Out_PP; +#else +#error Unsupported MCU +#endif + GPIO_ResetBits(chan->pin.gpio, chan->pin.init.GPIO_Pin); + + GPIO_Init(chan->pin.gpio, &init); + } + break; + + default:; } } +} - for (uint8_t i = 0; (i < PIOS_SERVO_BANKS); i++) { - TIM_TypeDef *timer = pios_servo_bank_timer[i]; +extern void PIOS_Servo_Enable() +{ + if (!servo_cfg) { + return; + } - if (timer && (pios_servo_bank_mode[i] != PIOS_SERVO_BANK_MODE_NONE)) { - TIM_SelectOnePulseMode(timer, TIM_OPMode_Repetitive); - TIM_Cmd(timer, ENABLE); - } + for (uint8_t i = 0; (i < PIOS_SERVO_BANKS); i++) { + PIOS_Servo_SetupBank(i); } pios_servo_enabled = true; } +void PIOS_Servo_DSHot_Rate(uint32_t rate_in_khz) +{ + uint32_t raw_hz = PIOS_DELAY_GetRawHz(); + + uint32_t tmp = raw_hz / rate_in_khz; + + pios_dshot_t0h_raw = (tmp / DSHOT_T0H_DIV) - DSHOT_TIMING_ADJUST; + pios_dshot_t1h_raw = (tmp / DSHOT_T1H_DIV) - DSHOT_TIMING_ADJUST; + pios_dshot_t_raw = (tmp / 1000) - DSHOT_TIMING_ADJUST; +} + /** * Initialise Servos */ @@ -145,9 +227,19 @@ int32_t PIOS_Servo_Init(const struct pios_servo_cfg *cfg) { /* Store away the requested configuration */ servo_cfg = cfg; - pios_servo_pin_bank = pios_malloc(sizeof(uint8_t) * cfg->num_channels); - uint8_t bank = 0; + pios_servo_pins = pios_malloc(sizeof(*pios_servo_pins) * cfg->num_channels); + PIOS_Assert(pios_servo_pins); + + memset(pios_servo_pins, 0, sizeof(*pios_servo_pins) * cfg->num_channels); + + /* set default dshot timinig */ + PIOS_Servo_DSHot_Rate(300); + + + uint8_t timer_bank = 0; + uint8_t gpio_bank = 0; + for (uint8_t i = 0; (i < servo_cfg->num_channels); i++) { const struct pios_tim_channel *chan = &servo_cfg->channels[i]; bool new = true; @@ -157,20 +249,53 @@ int32_t PIOS_Servo_Init(const struct pios_servo_cfg *cfg) } if (new) { - PIOS_Assert(bank < PIOS_SERVO_BANKS); + PIOS_Assert(timer_bank < PIOS_SERVO_BANKS); + struct pios_servo_bank *bank = &pios_servo_banks[timer_bank]; + + for (uint8_t j = i; j < servo_cfg->num_channels; j++) { if (servo_cfg->channels[j].timer == chan->timer) { - pios_servo_pin_bank[j] = bank; + pios_servo_pins[j].bank = bank; + pios_servo_pins[j].bank_nr = timer_bank; } } - pios_servo_bank_timer[bank] = chan->timer; - TIM_ARRPreloadConfig(chan->timer, ENABLE); - TIM_CtrlPWMOutputs(chan->timer, ENABLE); + bank->timer = chan->timer; + bank->mode = PIOS_SERVO_BANK_MODE_NONE; + TIM_Cmd(chan->timer, DISABLE); - bank++; + timer_bank++; + } + + // now map gpio banks + new = true; + for (uint8_t j = 0; (j < i) && new; j++) { + new &= chan->pin.gpio != servo_cfg->channels[j].pin.gpio; } + + if (new) { + PIOS_Assert(gpio_bank < PIOS_SERVO_GPIO_BANKS); + + for (uint8_t j = i; j < servo_cfg->num_channels; j++) { + if (servo_cfg->channels[j].pin.gpio == chan->pin.gpio) { + pios_servo_pins[j].gpio_bank = gpio_bank; + } + } +#if defined(STM32F40_41xxx) || defined(STM32F446xx) || defined(STM32F411xE) + pios_servo_bsrr[gpio_bank] = (uint32_t *)&chan->pin.gpio->BSRRL; +#else + pios_servo_bsrr[gpio_bank] = &chan->pin.gpio->BSRR; +#endif + + ++gpio_bank; + } + } + + static uint32_t dummy_bsrr; + + for (int i = gpio_bank; i < PIOS_SERVO_GPIO_BANKS; ++i) { + pios_servo_bsrr[gpio_bank] = &dummy_bsrr; } PIOS_Servo_Enable(); @@ -181,17 +306,121 @@ int32_t PIOS_Servo_Init(const struct pios_servo_cfg *cfg) void PIOS_Servo_SetBankMode(uint8_t bank, uint8_t mode) { PIOS_Assert(bank < PIOS_SERVO_BANKS); - pios_servo_bank_mode[bank] = mode; + pios_servo_banks[bank].mode = mode; if (!pios_servo_enabled) { return; } - if (pios_servo_bank_timer[bank]) { - // Setup the timer accordingly - TIM_SelectOnePulseMode(pios_servo_bank_timer[bank], TIM_OPMode_Repetitive); - TIM_Cmd(pios_servo_bank_timer[bank], ENABLE); + PIOS_Servo_SetupBank(bank); +} + +static void PIOS_Servo_DShot_Update() +{ + uint32_t next; + uint32_t data[PIOS_SERVO_GPIO_BANKS]; + uint16_t pins[PIOS_SERVO_GPIO_BANKS]; + uint16_t buffer[DSHOT_NUM_BITS][PIOS_SERVO_GPIO_BANKS]; + + for (uint8_t i = 0; i < PIOS_SERVO_GPIO_BANKS; ++i) { + pins[i] = 0; + } + + bool has_dshot = false; + + memset(buffer, 0, sizeof(buffer)); + + for (uint8_t i = 0; (i < servo_cfg->num_channels); i++) { + struct pios_servo_pin *pin = &pios_servo_pins[i]; + + if (pin->bank->mode != PIOS_SERVO_BANK_MODE_DSHOT) { + continue; + } + + has_dshot = true; + + uint16_t payload = pin->value; + if (payload > 2047) { + payload = 2047; + } + + payload <<= 5; + + payload |= ((payload >> 4) & 0xf) ^ + ((payload >> 8) & 0xf) ^ + ((payload >> 12) & 0xf); + + uint16_t gpio_pin = servo_cfg->channels[i].pin.init.GPIO_Pin; + + for (int j = 0; j < DSHOT_NUM_BITS; ++j) { + if (!(payload & 0x8000)) { + buffer[j][pin->gpio_bank] |= gpio_pin; + } + payload <<= 1; + } + + pins[pin->gpio_bank] |= gpio_pin; + + pin->value = 0; + } + + if (!has_dshot) { + return; + } + + PIOS_IRQ_Disable(); + + uint32_t start = PIOS_DELAY_GetRaw(); + + for (int i = 0; i < DSHOT_NUM_BITS; ++i) { + // single bit: + + COMPILER_BARRIER(); + // 1. write 3x BSRR to set gpio high + for (int j = 0; j < PIOS_SERVO_GPIO_BANKS; ++j) { + *(pios_servo_bsrr[j]) = (uint32_t)pins[j]; + } + + // Prep data + for (int j = 0; j < PIOS_SERVO_GPIO_BANKS; ++j) { + data[j] = buffer[i][j] << 16; + } + + // 2. wait until T0H, write 3x BSRR to clear whatever bits are set to 0 + next = start + pios_dshot_t0h_raw; + while ((next - PIOS_DELAY_GetRaw()) < pios_dshot_t0h_raw) { + ; + } + + COMPILER_BARRIER(); + for (int j = 0; j < PIOS_SERVO_GPIO_BANKS; ++j) { + *(pios_servo_bsrr[j]) = data[j]; + } + + // Prep data + for (int j = 0; j < PIOS_SERVO_GPIO_BANKS; ++j) { + data[j] = (uint32_t)pins[j] << 16; + } + + // 3. wait until T1H, then write 3x BSRR to set all to low + next = start + pios_dshot_t1h_raw; + while ((next - PIOS_DELAY_GetRaw()) < pios_dshot_t1h_raw) { + ; + } + + COMPILER_BARRIER(); + for (int j = 0; j < PIOS_SERVO_GPIO_BANKS; ++j) { + *(pios_servo_bsrr[j]) = data[j]; + } + + // 4. wait until Tend + start += pios_dshot_t_raw; + while ((start - PIOS_DELAY_GetRaw()) < pios_dshot_t_raw) { + ; + } } + + PIOS_IRQ_Enable(); } @@ -202,20 +431,19 @@ void PIOS_Servo_Update() } for (uint8_t i = 0; (i < PIOS_SERVO_BANKS); i++) { - const TIM_TypeDef *timer = pios_servo_bank_timer[i]; - if (timer && pios_servo_bank_mode[i] == PIOS_SERVO_BANK_MODE_SINGLE_PULSE) { + struct pios_servo_bank *bank = &pios_servo_banks[i]; + if (bank->timer && (bank->mode == PIOS_SERVO_BANK_MODE_SINGLE_PULSE)) { // a pulse to be generated is longer than cycle period. skip this update. - if (TIM_GetCounter((TIM_TypeDef *)timer) > (uint32_t)(pios_servo_bank_next_update[i] + PIOS_SERVO_SAFE_MARGIN)) { - TIM_GenerateEvent((TIM_TypeDef *)timer, TIM_EventSource_Update); - pios_servo_bank_next_update[i] = pios_servo_bank_max_pulse[i]; + if (TIM_GetCounter((TIM_TypeDef *)bank->timer) > (uint32_t)(bank->next_update + PIOS_SERVO_SAFE_MARGIN)) { + TIM_GenerateEvent((TIM_TypeDef *)bank->timer, TIM_EventSource_Update); + bank->next_update = bank->max_pulse; } } - pios_servo_bank_max_pulse[i] = 0; + bank->max_pulse = 0; } + for (uint8_t i = 0; (i < servo_cfg->num_channels); i++) { - uint8_t bank = pios_servo_pin_bank[i]; - uint8_t mode = pios_servo_bank_mode[bank]; - if (mode == PIOS_SERVO_BANK_MODE_SINGLE_PULSE) { + if (pios_servo_pins[i].bank->mode == PIOS_SERVO_BANK_MODE_SINGLE_PULSE) { /* Update the position */ const struct pios_tim_channel *chan = &servo_cfg->channels[i]; @@ -235,6 +463,8 @@ void PIOS_Servo_Update() } } } + + PIOS_Servo_DShot_Update(); } /** * Set the servo update rate (Max 500Hz) @@ -254,7 +484,7 @@ void PIOS_Servo_SetHz(const uint16_t *speeds, const uint32_t *clock, uint8_t ban TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; for (uint8_t i = 0; i < banks && i < PIOS_SERVO_BANKS; i++) { - const TIM_TypeDef *timer = pios_servo_bank_timer[i]; + const TIM_TypeDef *timer = pios_servo_banks[i].timer; if (timer) { uint32_t new_clock = PIOS_SERVO_TIMER_CLOCK; if (clock[i]) { @@ -298,37 +528,43 @@ void PIOS_Servo_Set(uint8_t servo, uint16_t position) /* Update the position */ + + pios_servo_pins[servo].value = position; + const struct pios_tim_channel *chan = &servo_cfg->channels[servo]; - uint16_t val = position; - uint16_t margin = chan->timer->ARR / 50; // Leave 2% of period as margin to prevent overlaps - if (val > (chan->timer->ARR - margin)) { - val = chan->timer->ARR - margin; - } + struct pios_servo_bank *bank = pios_servo_pins[servo].bank; - uint8_t bank = pios_servo_pin_bank[servo]; - if (pios_servo_bank_max_pulse[bank] < val) { - pios_servo_bank_max_pulse[bank] = val; - } - switch (chan->timer_chan) { - case TIM_Channel_1: - TIM_SetCompare1(chan->timer, val); - break; - case TIM_Channel_2: - TIM_SetCompare2(chan->timer, val); - break; - case TIM_Channel_3: - TIM_SetCompare3(chan->timer, val); - break; - case TIM_Channel_4: - TIM_SetCompare4(chan->timer, val); - break; + if ((bank->mode == PIOS_SERVO_BANK_MODE_SINGLE_PULSE) || (bank->mode == PIOS_SERVO_BANK_MODE_PWM)) { + uint16_t val = position; + uint16_t margin = chan->timer->ARR / 50; // Leave 2% of period as margin to prevent overlaps + if (val > (chan->timer->ARR - margin)) { + val = chan->timer->ARR - margin; + } + + if (bank->max_pulse < val) { + bank->max_pulse = val; + } + switch (chan->timer_chan) { + case TIM_Channel_1: + TIM_SetCompare1(chan->timer, val); + break; + case TIM_Channel_2: + TIM_SetCompare2(chan->timer, val); + break; + case TIM_Channel_3: + TIM_SetCompare3(chan->timer, val); + break; + case TIM_Channel_4: + TIM_SetCompare4(chan->timer, val); + break; + } } } uint8_t PIOS_Servo_GetPinBank(uint8_t pin) { if (pin < servo_cfg->num_channels) { - return pios_servo_pin_bank[pin]; + return pios_servo_pins[pin].bank_nr; } else { return 0; } diff --git a/flight/pios/inc/pios_delay.h b/flight/pios/inc/pios_delay.h index 63546d75d6..45fbed7a83 100644 --- a/flight/pios/inc/pios_delay.h +++ b/flight/pios/inc/pios_delay.h @@ -32,13 +32,14 @@ #ifndef PIOS_DELAY_H #define PIOS_DELAY_H +#include "pios_delay_raw.h" + /* Public Functions */ extern int32_t PIOS_DELAY_Init(void); extern int32_t PIOS_DELAY_WaituS(uint32_t uS); extern int32_t PIOS_DELAY_WaitmS(uint32_t mS); extern uint32_t PIOS_DELAY_GetuS(); extern uint32_t PIOS_DELAY_GetuSSince(uint32_t t); -extern uint32_t PIOS_DELAY_GetRaw(); extern uint32_t PIOS_DELAY_DiffuS(uint32_t raw); extern uint32_t PIOS_DELAY_DiffuS2(uint32_t raw, uint32_t later); diff --git a/flight/pios/inc/pios_servo.h b/flight/pios/inc/pios_servo.h index 2000eee255..bcc1fff223 100644 --- a/flight/pios/inc/pios_servo.h +++ b/flight/pios/inc/pios_servo.h @@ -33,15 +33,17 @@ /* Global types */ enum pios_servo_bank_mode { - PIOS_SERVO_BANK_MODE_NONE = 0, - PIOS_SERVO_BANK_MODE_PWM = 1, - PIOS_SERVO_BANK_MODE_SINGLE_PULSE = 2 + PIOS_SERVO_BANK_MODE_NONE = 0, + PIOS_SERVO_BANK_MODE_PWM = 1, + PIOS_SERVO_BANK_MODE_SINGLE_PULSE = 2, + PIOS_SERVO_BANK_MODE_DSHOT = 3, }; /* Public Functions */ extern void PIOS_Servo_SetHz(const uint16_t *speeds, const uint32_t *clock, uint8_t banks); extern void PIOS_Servo_Set(uint8_t Servo, uint16_t Position); extern void PIOS_Servo_Update(); extern void PIOS_Servo_SetBankMode(uint8_t bank, uint8_t mode); +extern void PIOS_Servo_DSHot_Rate(uint32_t rate_in_khz); extern uint8_t PIOS_Servo_GetPinBank(uint8_t pin); /* ESC Bridge support */ diff --git a/flight/pios/stm32f0x/inc/pios_delay_raw.h b/flight/pios/stm32f0x/inc/pios_delay_raw.h new file mode 100644 index 0000000000..769ea2f5ea --- /dev/null +++ b/flight/pios/stm32f0x/inc/pios_delay_raw.h @@ -0,0 +1,36 @@ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_DELAY Delay Functions + * @brief PiOS Delay functionality + * @{ + * + * @file pios_delay_raw.h + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016-2017. + * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief Settings functions 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 PIOS_DELAY_RAW_H +#define PIOS_DELAY_RAW_H + +extern uint32_t PIOS_DELAY_GetRaw(); + +#endif /* PIOS_DELAY_RAW_H */ diff --git a/flight/pios/stm32f10x/inc/pios_delay_raw.h b/flight/pios/stm32f10x/inc/pios_delay_raw.h new file mode 100644 index 0000000000..6a49415633 --- /dev/null +++ b/flight/pios/stm32f10x/inc/pios_delay_raw.h @@ -0,0 +1,43 @@ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_DELAY Delay Functions + * @brief PiOS Delay functionality + * @{ + * + * @file pios_delay_raw.h + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016-2017. + * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief Settings functions 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 PIOS_DELAY_RAW_H +#define PIOS_DELAY_RAW_H + +/* these should be defined by CMSIS, but they aren't */ +#define DWT_CTRL (*(volatile uint32_t *)0xe0001000) +#define CYCCNTENA (1 << 0) +#define DWT_CYCCNT (*(volatile uint32_t *)0xe0001004) + +#define PIOS_DELAY_GetRaw() (DWT_CYCCNT) + +extern uint32_t PIOS_DELAY_GetRawHz(); + +#endif /* PIOS_DELAY_RAW_H */ diff --git a/flight/pios/stm32f10x/pios_delay.c b/flight/pios/stm32f10x/pios_delay.c index 9effa1ec7d..9907f2c175 100644 --- a/flight/pios/stm32f10x/pios_delay.c +++ b/flight/pios/stm32f10x/pios_delay.c @@ -34,14 +34,9 @@ #ifdef PIOS_INCLUDE_DELAY -/* these should be defined by CMSIS, but they aren't */ -#define DWT_CTRL (*(volatile uint32_t *)0xe0001000) -#define CYCCNTENA (1 << 0) -#define DWT_CYCCNT (*(volatile uint32_t *)0xe0001004) - - /* cycles per microsecond */ static uint32_t us_ticks; +static uint32_t raw_hz; /** * Initialises the Timer used by PIOS_DELAY functions. @@ -57,6 +52,7 @@ int32_t PIOS_DELAY_Init(void) RCC_GetClocksFreq(&clocks); us_ticks = clocks.SYSCLK_Frequency / 1000000; PIOS_DEBUG_Assert(us_ticks > 1); + raw_hz = clocks.SYSCLK_Frequency; /* turn on access to the DWT registers */ CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; @@ -84,7 +80,7 @@ int32_t PIOS_DELAY_WaituS(uint32_t uS) uint32_t last_count = DWT_CYCCNT; for (;;) { - uint32_t current_count = DWT_CYCCNT; + uint32_t current_count = PIOS_DELAY_GetRaw(); uint32_t elapsed_uS; /* measure the time elapsed since the last time we checked */ @@ -135,7 +131,7 @@ int32_t PIOS_DELAY_WaitmS(uint32_t mS) */ uint32_t PIOS_DELAY_GetuS(void) { - return DWT_CYCCNT / us_ticks; + return PIOS_DELAY_GetRaw() / us_ticks; } /** @@ -149,12 +145,12 @@ uint32_t PIOS_DELAY_GetuSSince(uint32_t t) } /** - * @brief Get the raw delay timer, useful for timing - * @return Unitless value (uint32 wrap around) + * @brief Get the raw delay timer frequency + * @return raw delay timer frequency in Hz */ -uint32_t PIOS_DELAY_GetRaw() +uint32_t PIOS_DELAY_GetRawHz() { - return DWT_CYCCNT; + return raw_hz; } /** @@ -163,7 +159,7 @@ uint32_t PIOS_DELAY_GetRaw() */ uint32_t PIOS_DELAY_DiffuS(uint32_t raw) { - uint32_t diff = DWT_CYCCNT - raw; + uint32_t diff = PIOS_DELAY_GetRaw() - raw; return diff / us_ticks; } diff --git a/flight/pios/stm32f4xx/inc/pios_delay_raw.h b/flight/pios/stm32f4xx/inc/pios_delay_raw.h new file mode 100644 index 0000000000..6a49415633 --- /dev/null +++ b/flight/pios/stm32f4xx/inc/pios_delay_raw.h @@ -0,0 +1,43 @@ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_DELAY Delay Functions + * @brief PiOS Delay functionality + * @{ + * + * @file pios_delay_raw.h + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016-2017. + * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief Settings functions 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 PIOS_DELAY_RAW_H +#define PIOS_DELAY_RAW_H + +/* these should be defined by CMSIS, but they aren't */ +#define DWT_CTRL (*(volatile uint32_t *)0xe0001000) +#define CYCCNTENA (1 << 0) +#define DWT_CYCCNT (*(volatile uint32_t *)0xe0001004) + +#define PIOS_DELAY_GetRaw() (DWT_CYCCNT) + +extern uint32_t PIOS_DELAY_GetRawHz(); + +#endif /* PIOS_DELAY_RAW_H */ diff --git a/flight/pios/stm32f4xx/pios_delay.c b/flight/pios/stm32f4xx/pios_delay.c index f9c5d62b1c..272afc3f2b 100644 --- a/flight/pios/stm32f4xx/pios_delay.c +++ b/flight/pios/stm32f4xx/pios_delay.c @@ -35,14 +35,9 @@ #ifdef PIOS_INCLUDE_DELAY -/* these should be defined by CMSIS, but they aren't */ -#define DWT_CTRL (*(volatile uint32_t *)0xe0001000) -#define CYCCNTENA (1 << 0) -#define DWT_CYCCNT (*(volatile uint32_t *)0xe0001004) - - /* cycles per microsecond */ static uint32_t us_ticks; +static uint32_t raw_hz; /** * Initialises the Timer used by PIOS_DELAY functions. @@ -58,6 +53,7 @@ int32_t PIOS_DELAY_Init(void) RCC_GetClocksFreq(&clocks); us_ticks = clocks.SYSCLK_Frequency / 1000000; PIOS_DEBUG_Assert(us_ticks > 1); + raw_hz = clocks.SYSCLK_Frequency; /* turn on access to the DWT registers */ CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; @@ -82,10 +78,10 @@ int32_t PIOS_DELAY_Init(void) int32_t PIOS_DELAY_WaituS(uint32_t uS) { uint32_t elapsed = 0; - uint32_t last_count = DWT_CYCCNT; + uint32_t last_count = PIOS_DELAY_GetRaw(); for (;;) { - uint32_t current_count = DWT_CYCCNT; + uint32_t current_count = PIOS_DELAY_GetRaw(); uint32_t elapsed_uS; /* measure the time elapsed since the last time we checked */ @@ -136,7 +132,7 @@ int32_t PIOS_DELAY_WaitmS(uint32_t mS) */ uint32_t PIOS_DELAY_GetuS() { - return DWT_CYCCNT / us_ticks; + return PIOS_DELAY_GetRaw() / us_ticks; } /** @@ -150,12 +146,12 @@ uint32_t PIOS_DELAY_GetuSSince(uint32_t t) } /** - * @brief Get the raw delay timer, useful for timing - * @return Unitless value (uint32 wrap around) + * @brief Get the raw delay timer frequency + * @return raw delay timer frequency in Hz */ -uint32_t PIOS_DELAY_GetRaw() +uint32_t PIOS_DELAY_GetRawHz() { - return DWT_CYCCNT; + return raw_hz; } /** @@ -164,7 +160,7 @@ uint32_t PIOS_DELAY_GetRaw() */ uint32_t PIOS_DELAY_DiffuS(uint32_t raw) { - uint32_t diff = DWT_CYCCNT - raw; + uint32_t diff = PIOS_DELAY_GetRaw() - raw; return diff / us_ticks; } diff --git a/ground/gcs/src/plugins/config/configoutputwidget.cpp b/ground/gcs/src/plugins/config/configoutputwidget.cpp index 0c7613f5be..301ff871ae 100644 --- a/ground/gcs/src/plugins/config/configoutputwidget.cpp +++ b/ground/gcs/src/plugins/config/configoutputwidget.cpp @@ -51,6 +51,9 @@ #include #include +#define MAXOUTPUT_VALUE 2500 +#define MINOUTPUT_VALUE 500 + ConfigOutputWidget::ConfigOutputWidget(QWidget *parent) : ConfigTaskWidget(parent) { m_ui = new Ui_OutputWidget(); @@ -396,11 +399,18 @@ void ConfigOutputWidget::refreshWidgetsValuesImpl(UAVObject *obj) int minValue = actuatorSettingsData.ChannelMin[outputChannelForm->index()]; int maxValue = actuatorSettingsData.ChannelMax[outputChannelForm->index()]; - outputChannelForm->setRange(minValue, maxValue); if (channelBanks.count() > i) { - outputChannelForm->setBank(QString("%1").arg(channelBanks.at(i))); - outputChannelForm->setColor(m_banks.at(channelBanks.at(i++) - 1).color()); + int bankNumber = channelBanks.at(i); + OutputBankControls bankControls = m_banks.at(bankNumber - 1); + + setChannelLimits(outputChannelForm, &bankControls); + + outputChannelForm->setBank(QString("%1").arg(bankNumber)); + outputChannelForm->setColor(bankControls.color()); + + i++; } + outputChannelForm->setRange(minValue, maxValue); int neutral = actuatorSettingsData.ChannelNeutral[outputChannelForm->index()]; outputChannelForm->setNeutral(neutral); } @@ -480,18 +490,41 @@ void ConfigOutputWidget::updateAlwaysStabilizeStatus() } } +void ConfigOutputWidget::setChannelLimits(OutputChannelForm *channelForm, OutputBankControls *bankControls) +{ + switch (bankControls->modeCombo()->currentIndex()) { + case ActuatorSettings::BANKMODE_DSHOT: + channelForm->setLimits(0, 0, 0, 2000); + break; + // case ActuatorSettings::BANKMODE_BRUSHED: + // channelForm->setLimits(0, 0, 0, 100); // 0 to 100% + // break; + default:; + channelForm->setLimits(MINOUTPUT_VALUE, MAXOUTPUT_VALUE, MINOUTPUT_VALUE, MAXOUTPUT_VALUE); + } +} + void ConfigOutputWidget::onBankTypeChange() { QComboBox *bankModeCombo = qobject_cast(sender()); if (bankModeCombo != NULL) { + int bankNumber = 1; + QList outputChannelForms = findChildren(); foreach(OutputBankControls controls, m_banks) { if (controls.modeCombo() == bankModeCombo) { bool enabled = bankModeCombo->currentIndex() == ActuatorSettings::BANKMODE_PWM; controls.rateCombo()->setEnabled(enabled); controls.rateCombo()->setCurrentIndex(enabled ? 1 : 0); + foreach(OutputChannelForm * outputChannelForm, outputChannelForms) { + if (outputChannelForm->bank().toInt() == bankNumber) { + setChannelLimits(outputChannelForm, &controls); + } + } break; } + + bankNumber++; } } } diff --git a/ground/gcs/src/plugins/config/configoutputwidget.h b/ground/gcs/src/plugins/config/configoutputwidget.h index bca11ddb06..b7e27e114e 100644 --- a/ground/gcs/src/plugins/config/configoutputwidget.h +++ b/ground/gcs/src/plugins/config/configoutputwidget.h @@ -104,6 +104,7 @@ class ConfigOutputWidget : public ConfigTaskWidget { void assignOutputChannel(UAVDataObject *obj, QString &str); void setColor(QWidget *widget, const QColor color); void sendAllChannelTests(); + void setChannelLimits(OutputChannelForm *channelForm, OutputBankControls *bankControls); private slots: void updateWarnings(UAVObject *); diff --git a/ground/gcs/src/plugins/config/outputchannelform.cpp b/ground/gcs/src/plugins/config/outputchannelform.cpp index b093956a18..973ff94c48 100644 --- a/ground/gcs/src/plugins/config/outputchannelform.cpp +++ b/ground/gcs/src/plugins/config/outputchannelform.cpp @@ -29,9 +29,6 @@ #include "ui_outputchannelform.h" -#define MAXOUTPUT_VALUE 2500 -#define MINOUTPUT_VALUE 500 - OutputChannelForm::OutputChannelForm(const int index, QWidget *parent) : ChannelForm(index, parent), ui(new Ui::outputChannelForm), m_inChannelTest(false) { @@ -50,14 +47,6 @@ OutputChannelForm::OutputChannelForm(const int index, QWidget *parent) : ui->actuatorLink->setChecked(false); connect(ui->actuatorLink, SIGNAL(toggled(bool)), this, SLOT(linkToggled(bool))); - // Set limits - ui->actuatorMin->setMaximum(MAXOUTPUT_VALUE); - ui->actuatorMax->setMaximum(MAXOUTPUT_VALUE); - ui->actuatorValue->setMaximum(MAXOUTPUT_VALUE); - ui->actuatorMin->setMinimum(MINOUTPUT_VALUE); - ui->actuatorMax->setMinimum(MINOUTPUT_VALUE); - ui->actuatorValue->setMinimum(MINOUTPUT_VALUE); - setChannelRange(); disableMouseWheelEvents(); @@ -144,7 +133,7 @@ void OutputChannelForm::linkToggled(bool state) if (!parent()) { return; } - int min = MAXOUTPUT_VALUE; + int min = ui->actuatorValue->maximum(); int linked_count = 0; QList outputChannelForms = parent()->findChildren(); // set the linked channels of the parent widget to the same value @@ -213,6 +202,18 @@ void OutputChannelForm::setNeutral(int value) ui->actuatorNeutral->setValue(value); } +/** + * + * Set + */ +void OutputChannelForm::setLimits(int min_low, int min_high, int max_low, int max_high) +{ + ui->actuatorMin->setMaximum(min_high); + ui->actuatorMax->setMaximum(max_high); + ui->actuatorMin->setMinimum(min_low); + ui->actuatorMax->setMinimum(max_low); +} + /** * Set minimal and maximal channel value. */ diff --git a/ground/gcs/src/plugins/config/outputchannelform.h b/ground/gcs/src/plugins/config/outputchannelform.h index 25cd5375a7..ab63dabfab 100644 --- a/ground/gcs/src/plugins/config/outputchannelform.h +++ b/ground/gcs/src/plugins/config/outputchannelform.h @@ -62,6 +62,7 @@ public slots: void setRange(int minimum, int maximum); void enableChannelTest(bool state); QString outputMixerType(); + void setLimits(int min_low, int min_high, int max_low, int max_high); signals: void channelChanged(int index, int value); diff --git a/shared/uavobjectdefinition/actuatorsettings.xml b/shared/uavobjectdefinition/actuatorsettings.xml index 6aaed72f7a..07fe0478ad 100644 --- a/shared/uavobjectdefinition/actuatorsettings.xml +++ b/shared/uavobjectdefinition/actuatorsettings.xml @@ -2,7 +2,8 @@ Settings for the @ref ActuatorModule that controls the channel assignments for the mixer based on AircraftType - + + From 3a102d3a645d2e4a567e102294fd69822d8d3b0e Mon Sep 17 00:00:00 2001 From: Vladimir Zidar Date: Mon, 27 Mar 2017 16:04:40 +0200 Subject: [PATCH 233/624] LP-479 The ui->actuatorValue does not have limits (it is used as label only) so use ui->actuatorMax instead. --- ground/gcs/src/plugins/config/outputchannelform.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ground/gcs/src/plugins/config/outputchannelform.cpp b/ground/gcs/src/plugins/config/outputchannelform.cpp index 973ff94c48..85e697f319 100644 --- a/ground/gcs/src/plugins/config/outputchannelform.cpp +++ b/ground/gcs/src/plugins/config/outputchannelform.cpp @@ -133,7 +133,7 @@ void OutputChannelForm::linkToggled(bool state) if (!parent()) { return; } - int min = ui->actuatorValue->maximum(); + int min = ui->actuatorMax->maximum(); int linked_count = 0; QList outputChannelForms = parent()->findChildren(); // set the linked channels of the parent widget to the same value From 3b39f1b4cea0abc3fcb81c80419bfc8e25498c32 Mon Sep 17 00:00:00 2001 From: Vladimir Zidar Date: Fri, 21 Apr 2017 04:54:41 -0700 Subject: [PATCH 234/624] LP-479 fix simposix firmware build --- flight/pios/inc/pios_delay.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/flight/pios/inc/pios_delay.h b/flight/pios/inc/pios_delay.h index 45fbed7a83..e59aa1421d 100644 --- a/flight/pios/inc/pios_delay.h +++ b/flight/pios/inc/pios_delay.h @@ -32,7 +32,9 @@ #ifndef PIOS_DELAY_H #define PIOS_DELAY_H +#ifndef USE_SIM_POSIX #include "pios_delay_raw.h" +#endif /* Public Functions */ extern int32_t PIOS_DELAY_Init(void); From 50fce728f821e58d5c5d0431a7d4ec408447e286 Mon Sep 17 00:00:00 2001 From: Vladimir Zidar Date: Fri, 21 Apr 2017 14:54:21 +0200 Subject: [PATCH 235/624] LP-479 Addressed PR comments --- flight/modules/Actuator/actuator.c | 1 + flight/pios/common/pios_servo.c | 6 +++++- ground/gcs/src/plugins/config/configoutputwidget.cpp | 5 +++-- ground/gcs/src/plugins/config/outputchannelform.cpp | 10 +++++----- ground/gcs/src/plugins/config/outputchannelform.h | 2 +- 5 files changed, 15 insertions(+), 9 deletions(-) diff --git a/flight/modules/Actuator/actuator.c b/flight/modules/Actuator/actuator.c index 0944a356d0..7a4f4353b3 100644 --- a/flight/modules/Actuator/actuator.c +++ b/flight/modules/Actuator/actuator.c @@ -961,6 +961,7 @@ static bool set_channel(uint8_t mixer_channel, uint16_t value) PIOS_Servo_Set(actuatorSettings.ChannelAddr[mixer_channel], (value * ACTUATOR_MULTISHOT_PULSE_FACTOR) - 180); break; case ACTUATORSETTINGS_BANKMODE_DSHOT: + // Remap 0-2000 range to: 0 = disarmed, 1 to 47 = Reserved for special commands, 48 to 2047 = Active throttle control. if (value > 0) { value += 47; /* skip over reserved values */ } diff --git a/flight/pios/common/pios_servo.c b/flight/pios/common/pios_servo.c index 41c703b875..01be0971e5 100644 --- a/flight/pios/common/pios_servo.c +++ b/flight/pios/common/pios_servo.c @@ -28,6 +28,10 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* + * DShot: Tribute belongs to dRonin, http://dRonin.org/ for sparking the idea of + * using gpio bitbang as more general solution over using timer dma. + */ #include "pios.h" @@ -233,7 +237,7 @@ int32_t PIOS_Servo_Init(const struct pios_servo_cfg *cfg) memset(pios_servo_pins, 0, sizeof(*pios_servo_pins) * cfg->num_channels); - /* set default dshot timinig */ + /* set default dshot timing */ PIOS_Servo_DSHot_Rate(300); diff --git a/ground/gcs/src/plugins/config/configoutputwidget.cpp b/ground/gcs/src/plugins/config/configoutputwidget.cpp index 301ff871ae..c4887c2925 100644 --- a/ground/gcs/src/plugins/config/configoutputwidget.cpp +++ b/ground/gcs/src/plugins/config/configoutputwidget.cpp @@ -405,7 +405,7 @@ void ConfigOutputWidget::refreshWidgetsValuesImpl(UAVObject *obj) setChannelLimits(outputChannelForm, &bankControls); - outputChannelForm->setBank(QString("%1").arg(bankNumber)); + outputChannelForm->setBank(QString::number(bankNumber)); outputChannelForm->setColor(bankControls.color()); i++; @@ -499,8 +499,9 @@ void ConfigOutputWidget::setChannelLimits(OutputChannelForm *channelForm, Output // case ActuatorSettings::BANKMODE_BRUSHED: // channelForm->setLimits(0, 0, 0, 100); // 0 to 100% // break; - default:; + default: channelForm->setLimits(MINOUTPUT_VALUE, MAXOUTPUT_VALUE, MINOUTPUT_VALUE, MAXOUTPUT_VALUE); + break; } } diff --git a/ground/gcs/src/plugins/config/outputchannelform.cpp b/ground/gcs/src/plugins/config/outputchannelform.cpp index 85e697f319..09bab754c2 100644 --- a/ground/gcs/src/plugins/config/outputchannelform.cpp +++ b/ground/gcs/src/plugins/config/outputchannelform.cpp @@ -206,12 +206,12 @@ void OutputChannelForm::setNeutral(int value) * * Set */ -void OutputChannelForm::setLimits(int min_low, int min_high, int max_low, int max_high) +void OutputChannelForm::setLimits(int actuatorMinMinimum, int actuatorMinMaximum, int actuatorMaxMinimum, int actuatorMaxMaximum) { - ui->actuatorMin->setMaximum(min_high); - ui->actuatorMax->setMaximum(max_high); - ui->actuatorMin->setMinimum(min_low); - ui->actuatorMax->setMinimum(max_low); + ui->actuatorMin->setMaximum(actuatorMinMaximum); + ui->actuatorMax->setMaximum(actuatorMaxMaximum); + ui->actuatorMin->setMinimum(actuatorMinMinimum); + ui->actuatorMax->setMinimum(actuatorMaxMinimum); } /** diff --git a/ground/gcs/src/plugins/config/outputchannelform.h b/ground/gcs/src/plugins/config/outputchannelform.h index ab63dabfab..1cf3899d75 100644 --- a/ground/gcs/src/plugins/config/outputchannelform.h +++ b/ground/gcs/src/plugins/config/outputchannelform.h @@ -62,7 +62,7 @@ public slots: void setRange(int minimum, int maximum); void enableChannelTest(bool state); QString outputMixerType(); - void setLimits(int min_low, int min_high, int max_low, int max_high); + void setLimits(int actuatorMinMinimum, int actuatorMinMaximum, int actuatorMaxMinimum, int actuatorMaxMaximum); signals: void channelChanged(int index, int value); From 58e70c8849ec4ffb8916c387aabfd09a97aa1e94 Mon Sep 17 00:00:00 2001 From: Vladimir Zidar Date: Tue, 25 Apr 2017 18:40:54 +0200 Subject: [PATCH 236/624] LP-480 reverted irelevant .xcodeproj file --- .../OpenPilotOSX.xcodeproj/project.pbxproj | 628 +++++++++--------- 1 file changed, 298 insertions(+), 330 deletions(-) diff --git a/flight/Project/OpenPilotOSX/OpenPilotOSX.xcodeproj/project.pbxproj b/flight/Project/OpenPilotOSX/OpenPilotOSX.xcodeproj/project.pbxproj index f4baa02916..14b7c9ae29 100644 --- a/flight/Project/OpenPilotOSX/OpenPilotOSX.xcodeproj/project.pbxproj +++ b/flight/Project/OpenPilotOSX/OpenPilotOSX.xcodeproj/project.pbxproj @@ -1,330 +1,298 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXFileReference section */ - 4354B66314FED9FE004BA3B4 /* flight */ = {isa = PBXFileReference; lastKnownFileType = folder; name = flight; path = ../..; sourceTree = SOURCE_ROOT; }; - 65173C9F12EBFD1700D6A7CB /* Makefile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.make; name = Makefile; path = ../../../Makefile; sourceTree = SOURCE_ROOT; }; - 65904F1814632C1700FD9482 /* firmware-defs.mk */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "firmware-defs.mk"; sourceTree = ""; }; - 65904F2214632C1700FD9482 /* board-info.mk */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "board-info.mk"; sourceTree = ""; }; - 65904F2314632C1700FD9482 /* board-info.mk */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "board-info.mk"; sourceTree = ""; }; - 65904F2414632C1700FD9482 /* board-info.mk */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "board-info.mk"; sourceTree = ""; }; - 65904F2514632C1700FD9482 /* board-info.mk */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "board-info.mk"; sourceTree = ""; }; - 65904F2614632C1700FD9482 /* board-info.mk */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "board-info.mk"; sourceTree = ""; }; - 65904F2714632C1700FD9482 /* board-info.mk */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "board-info.mk"; sourceTree = ""; }; - 65904F2814632C1700FD9482 /* version-info.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = "version-info.py"; sourceTree = ""; }; - 65904F2914632C1700FD9482 /* firmware_info.c.template */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = firmware_info.c.template; sourceTree = ""; }; - 65904F2A14632C1700FD9482 /* gcs_version_info.h.template */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gcs_version_info.h.template; sourceTree = ""; }; - 65904F2D14632C1700FD9482 /* README.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README.txt; sourceTree = ""; }; - 65904F2E14632C1700FD9482 /* shell_script.reg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = shell_script.reg; sourceTree = ""; }; - 65904F2F14632C1700FD9482 /* install */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = install; sourceTree = ""; }; - 65904F3014632C1700FD9482 /* make */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = make; sourceTree = ""; }; - 65904F3114632C1700FD9482 /* make.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = make.sh; sourceTree = ""; }; - 65904F3214632C1700FD9482 /* sh.cmd */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = sh.cmd; sourceTree = ""; }; - 65904F34146362F300FD9482 /* board-info.mk */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "board-info.mk"; sourceTree = ""; }; - 65E466BC14E244020075459C /* uavobjectdefinition */ = {isa = PBXFileReference; lastKnownFileType = folder; path = uavobjectdefinition; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXGroup section */ - 08FB7794FE84155DC02AAC07 /* OpenPilotOSX */ = { - isa = PBXGroup; - children = ( - 4354B66314FED9FE004BA3B4 /* flight */, - 65904F1614632C1700FD9482 /* make */, - 65C35E4E12EFB2F3004811C2 /* shared */, - 65173C9F12EBFD1700D6A7CB /* Makefile */, - ); - name = OpenPilotOSX; - sourceTree = ""; - }; - 65904F1614632C1700FD9482 /* make */ = { - isa = PBXGroup; - children = ( - 65904F1714632C1700FD9482 /* boards */, - 65904F1814632C1700FD9482 /* firmware-defs.mk */, - 65904F1914632C1700FD9482 /* scripts */, - 65904F1A14632C1700FD9482 /* templates */, - 65904F1B14632C1700FD9482 /* winx86 */, - ); - name = make; - path = OpenPilotOSX.xcodeproj/../../../../make; - sourceTree = ""; - }; - 65904F1714632C1700FD9482 /* boards */ = { - isa = PBXGroup; - children = ( - 65904F33146362F300FD9482 /* revolution */, - 65904F1C14632C1700FD9482 /* ahrs */, - 65904F1D14632C1700FD9482 /* coptercontrol */, - 65904F1E14632C1700FD9482 /* esc */, - 65904F1F14632C1700FD9482 /* ins */, - 65904F2014632C1700FD9482 /* openpilot */, - 65904F2114632C1700FD9482 /* oplink */, - ); - path = boards; - sourceTree = ""; - }; - 65904F1914632C1700FD9482 /* scripts */ = { - isa = PBXGroup; - children = ( - 65904F2814632C1700FD9482 /* version-info.py */, - ); - path = scripts; - sourceTree = ""; - }; - 65904F1A14632C1700FD9482 /* templates */ = { - isa = PBXGroup; - children = ( - 65904F2914632C1700FD9482 /* firmware_info.c.template */, - 65904F2A14632C1700FD9482 /* gcs_version_info.h.template */, - ); - path = templates; - sourceTree = ""; - }; - 65904F1B14632C1700FD9482 /* winx86 */ = { - isa = PBXGroup; - children = ( - 65904F2B14632C1700FD9482 /* bin */, - 65904F2C14632C1700FD9482 /* cmd */, - 65904F2D14632C1700FD9482 /* README.txt */, - 65904F2E14632C1700FD9482 /* shell_script.reg */, - ); - path = winx86; - sourceTree = ""; - }; - 65904F1C14632C1700FD9482 /* ahrs */ = { - isa = PBXGroup; - children = ( - 65904F2214632C1700FD9482 /* board-info.mk */, - ); - path = ahrs; - sourceTree = ""; - }; - 65904F1D14632C1700FD9482 /* coptercontrol */ = { - isa = PBXGroup; - children = ( - 65904F2314632C1700FD9482 /* board-info.mk */, - ); - path = coptercontrol; - sourceTree = ""; - }; - 65904F1E14632C1700FD9482 /* esc */ = { - isa = PBXGroup; - children = ( - 65904F2414632C1700FD9482 /* board-info.mk */, - ); - path = esc; - sourceTree = ""; - }; - 65904F1F14632C1700FD9482 /* ins */ = { - isa = PBXGroup; - children = ( - 65904F2514632C1700FD9482 /* board-info.mk */, - ); - path = ins; - sourceTree = ""; - }; - 65904F2014632C1700FD9482 /* openpilot */ = { - isa = PBXGroup; - children = ( - 65904F2614632C1700FD9482 /* board-info.mk */, - ); - path = openpilot; - sourceTree = ""; - }; - 65904F2114632C1700FD9482 /* oplink */ = { - isa = PBXGroup; - children = ( - 65904F2714632C1700FD9482 /* board-info.mk */, - ); - path = oplink; - sourceTree = ""; - }; - 65904F2B14632C1700FD9482 /* bin */ = { - isa = PBXGroup; - children = ( - 65904F2F14632C1700FD9482 /* install */, - 65904F3014632C1700FD9482 /* make */, - ); - path = bin; - sourceTree = ""; - }; - 65904F2C14632C1700FD9482 /* cmd */ = { - isa = PBXGroup; - children = ( - 65904F3114632C1700FD9482 /* make.sh */, - 65904F3214632C1700FD9482 /* sh.cmd */, - ); - path = cmd; - sourceTree = ""; - }; - 65904F33146362F300FD9482 /* revolution */ = { - isa = PBXGroup; - children = ( - 65904F34146362F300FD9482 /* board-info.mk */, - ); - path = revolution; - sourceTree = ""; - }; - 65C35E4E12EFB2F3004811C2 /* shared */ = { - isa = PBXGroup; - children = ( - 65E466BC14E244020075459C /* uavobjectdefinition */, - ); - name = shared; - path = ../../../shared; - sourceTree = SOURCE_ROOT; - }; -/* End PBXGroup section */ - -/* Begin PBXLegacyTarget section */ - 6581071511DE809D0049FB12 /* OpenPilotOSX */ = { - isa = PBXLegacyTarget; - buildArgumentsString = ef_oplinkmini; - buildConfigurationList = 6581071A11DE80A30049FB12 /* Build configuration list for PBXLegacyTarget "OpenPilotOSX" */; - buildPhases = ( - ); - buildToolPath = /usr/bin/make; - buildWorkingDirectory = ../../..; - dependencies = ( - ); - name = OpenPilotOSX; - passBuildSettingsInEnvironment = 1; - productName = OpenPilotOSX; - }; -/* End PBXLegacyTarget section */ - -/* Begin PBXProject section */ - 08FB7793FE84155DC02AAC07 /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 0820; - ORGANIZATIONNAME = OpenPilot; - }; - buildConfigurationList = 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "OpenPilotOSX" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 1; - knownRegions = ( - English, - Japanese, - French, - German, - ); - mainGroup = 08FB7794FE84155DC02AAC07 /* OpenPilotOSX */; - projectDirPath = ""; - projectRoot = ../../..; - targets = ( - 6581071511DE809D0049FB12 /* OpenPilotOSX */, - ); - }; -/* End PBXProject section */ - -/* Begin XCBuildConfiguration section */ - 1DEB928A08733DD80010E9CD /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - ONLY_ACTIVE_ARCH = YES; - PREBINDING = NO; - SDKROOT = macosx; - }; - name = Debug; - }; - 1DEB928B08733DD80010E9CD /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - PREBINDING = NO; - SDKROOT = macosx; - }; - name = Release; - }; - 6581071611DE809D0049FB12 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - COPY_PHASE_STRIP = NO; - GCC_DYNAMIC_NO_PIC = NO; - GCC_OPTIMIZATION_LEVEL = 0; - PRODUCT_NAME = OpenPilotOSX; - }; - name = Debug; - }; - 6581071711DE809D0049FB12 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - COPY_PHASE_STRIP = YES; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - GCC_ENABLE_FIX_AND_CONTINUE = NO; - PRODUCT_NAME = OpenPilotOSX; - ZERO_LINK = NO; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "OpenPilotOSX" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 1DEB928A08733DD80010E9CD /* Debug */, - 1DEB928B08733DD80010E9CD /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 6581071A11DE80A30049FB12 /* Build configuration list for PBXLegacyTarget "OpenPilotOSX" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 6581071611DE809D0049FB12 /* Debug */, - 6581071711DE809D0049FB12 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 08FB7793FE84155DC02AAC07 /* Project object */; -} +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 45; + objects = { + +/* Begin PBXFileReference section */ + 4354B66314FED9FE004BA3B4 /* flight */ = {isa = PBXFileReference; lastKnownFileType = folder; name = flight; path = ../..; sourceTree = SOURCE_ROOT; }; + 65173C9F12EBFD1700D6A7CB /* Makefile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.make; name = Makefile; path = ../../../Makefile; sourceTree = SOURCE_ROOT; }; + 65904F1814632C1700FD9482 /* firmware-defs.mk */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "firmware-defs.mk"; sourceTree = ""; }; + 65904F2214632C1700FD9482 /* board-info.mk */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "board-info.mk"; sourceTree = ""; }; + 65904F2314632C1700FD9482 /* board-info.mk */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "board-info.mk"; sourceTree = ""; }; + 65904F2414632C1700FD9482 /* board-info.mk */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "board-info.mk"; sourceTree = ""; }; + 65904F2514632C1700FD9482 /* board-info.mk */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "board-info.mk"; sourceTree = ""; }; + 65904F2614632C1700FD9482 /* board-info.mk */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "board-info.mk"; sourceTree = ""; }; + 65904F2714632C1700FD9482 /* board-info.mk */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "board-info.mk"; sourceTree = ""; }; + 65904F2814632C1700FD9482 /* version-info.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = "version-info.py"; sourceTree = ""; }; + 65904F2914632C1700FD9482 /* firmware_info.c.template */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = firmware_info.c.template; sourceTree = ""; }; + 65904F2A14632C1700FD9482 /* gcs_version_info.h.template */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gcs_version_info.h.template; sourceTree = ""; }; + 65904F2D14632C1700FD9482 /* README.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README.txt; sourceTree = ""; }; + 65904F2E14632C1700FD9482 /* shell_script.reg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = shell_script.reg; sourceTree = ""; }; + 65904F2F14632C1700FD9482 /* install */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = install; sourceTree = ""; }; + 65904F3014632C1700FD9482 /* make */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = make; sourceTree = ""; }; + 65904F3114632C1700FD9482 /* make.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = make.sh; sourceTree = ""; }; + 65904F3214632C1700FD9482 /* sh.cmd */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = sh.cmd; sourceTree = ""; }; + 65904F34146362F300FD9482 /* board-info.mk */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "board-info.mk"; sourceTree = ""; }; + 65E466BC14E244020075459C /* uavobjectdefinition */ = {isa = PBXFileReference; lastKnownFileType = folder; path = uavobjectdefinition; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXGroup section */ + 08FB7794FE84155DC02AAC07 /* OpenPilotOSX */ = { + isa = PBXGroup; + children = ( + 4354B66314FED9FE004BA3B4 /* flight */, + 65904F1614632C1700FD9482 /* make */, + 65C35E4E12EFB2F3004811C2 /* shared */, + 65173C9F12EBFD1700D6A7CB /* Makefile */, + ); + name = OpenPilotOSX; + sourceTree = ""; + }; + 65904F1614632C1700FD9482 /* make */ = { + isa = PBXGroup; + children = ( + 65904F1714632C1700FD9482 /* boards */, + 65904F1814632C1700FD9482 /* firmware-defs.mk */, + 65904F1914632C1700FD9482 /* scripts */, + 65904F1A14632C1700FD9482 /* templates */, + 65904F1B14632C1700FD9482 /* winx86 */, + ); + name = make; + path = OpenPilotOSX.xcodeproj/../../../../make; + sourceTree = ""; + }; + 65904F1714632C1700FD9482 /* boards */ = { + isa = PBXGroup; + children = ( + 65904F33146362F300FD9482 /* revolution */, + 65904F1C14632C1700FD9482 /* ahrs */, + 65904F1D14632C1700FD9482 /* coptercontrol */, + 65904F1E14632C1700FD9482 /* esc */, + 65904F1F14632C1700FD9482 /* ins */, + 65904F2014632C1700FD9482 /* openpilot */, + 65904F2114632C1700FD9482 /* oplink */, + ); + path = boards; + sourceTree = ""; + }; + 65904F1914632C1700FD9482 /* scripts */ = { + isa = PBXGroup; + children = ( + 65904F2814632C1700FD9482 /* version-info.py */, + ); + path = scripts; + sourceTree = ""; + }; + 65904F1A14632C1700FD9482 /* templates */ = { + isa = PBXGroup; + children = ( + 65904F2914632C1700FD9482 /* firmware_info.c.template */, + 65904F2A14632C1700FD9482 /* gcs_version_info.h.template */, + ); + path = templates; + sourceTree = ""; + }; + 65904F1B14632C1700FD9482 /* winx86 */ = { + isa = PBXGroup; + children = ( + 65904F2B14632C1700FD9482 /* bin */, + 65904F2C14632C1700FD9482 /* cmd */, + 65904F2D14632C1700FD9482 /* README.txt */, + 65904F2E14632C1700FD9482 /* shell_script.reg */, + ); + path = winx86; + sourceTree = ""; + }; + 65904F1C14632C1700FD9482 /* ahrs */ = { + isa = PBXGroup; + children = ( + 65904F2214632C1700FD9482 /* board-info.mk */, + ); + path = ahrs; + sourceTree = ""; + }; + 65904F1D14632C1700FD9482 /* coptercontrol */ = { + isa = PBXGroup; + children = ( + 65904F2314632C1700FD9482 /* board-info.mk */, + ); + path = coptercontrol; + sourceTree = ""; + }; + 65904F1E14632C1700FD9482 /* esc */ = { + isa = PBXGroup; + children = ( + 65904F2414632C1700FD9482 /* board-info.mk */, + ); + path = esc; + sourceTree = ""; + }; + 65904F1F14632C1700FD9482 /* ins */ = { + isa = PBXGroup; + children = ( + 65904F2514632C1700FD9482 /* board-info.mk */, + ); + path = ins; + sourceTree = ""; + }; + 65904F2014632C1700FD9482 /* openpilot */ = { + isa = PBXGroup; + children = ( + 65904F2614632C1700FD9482 /* board-info.mk */, + ); + path = openpilot; + sourceTree = ""; + }; + 65904F2114632C1700FD9482 /* oplink */ = { + isa = PBXGroup; + children = ( + 65904F2714632C1700FD9482 /* board-info.mk */, + ); + path = oplink; + sourceTree = ""; + }; + 65904F2B14632C1700FD9482 /* bin */ = { + isa = PBXGroup; + children = ( + 65904F2F14632C1700FD9482 /* install */, + 65904F3014632C1700FD9482 /* make */, + ); + path = bin; + sourceTree = ""; + }; + 65904F2C14632C1700FD9482 /* cmd */ = { + isa = PBXGroup; + children = ( + 65904F3114632C1700FD9482 /* make.sh */, + 65904F3214632C1700FD9482 /* sh.cmd */, + ); + path = cmd; + sourceTree = ""; + }; + 65904F33146362F300FD9482 /* revolution */ = { + isa = PBXGroup; + children = ( + 65904F34146362F300FD9482 /* board-info.mk */, + ); + path = revolution; + sourceTree = ""; + }; + 65C35E4E12EFB2F3004811C2 /* shared */ = { + isa = PBXGroup; + children = ( + 65E466BC14E244020075459C /* uavobjectdefinition */, + ); + name = shared; + path = ../../../shared; + sourceTree = SOURCE_ROOT; + }; +/* End PBXGroup section */ + +/* Begin PBXLegacyTarget section */ + 6581071511DE809D0049FB12 /* OpenPilotOSX */ = { + isa = PBXLegacyTarget; + buildArgumentsString = "$(ACTION) -f Makefile.posix"; + buildConfigurationList = 6581071A11DE80A30049FB12 /* Build configuration list for PBXLegacyTarget "OpenPilotOSX" */; + buildPhases = ( + ); + buildToolPath = /usr/bin/make; + buildWorkingDirectory = ../../OpenPilot; + dependencies = ( + ); + name = OpenPilotOSX; + passBuildSettingsInEnvironment = 1; + productName = OpenPilotOSX; + }; +/* End PBXLegacyTarget section */ + +/* Begin PBXProject section */ + 08FB7793FE84155DC02AAC07 /* Project object */ = { + isa = PBXProject; + attributes = { + ORGANIZATIONNAME = OpenPilot; + }; + buildConfigurationList = 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "OpenPilotOSX" */; + compatibilityVersion = "Xcode 3.1"; + developmentRegion = English; + hasScannedForEncodings = 1; + knownRegions = ( + English, + Japanese, + French, + German, + ); + mainGroup = 08FB7794FE84155DC02AAC07 /* OpenPilotOSX */; + projectDirPath = ""; + projectRoot = ../../..; + targets = ( + 6581071511DE809D0049FB12 /* OpenPilotOSX */, + ); + }; +/* End PBXProject section */ + +/* Begin XCBuildConfiguration section */ + 1DEB928A08733DD80010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + ONLY_ACTIVE_ARCH = YES; + PREBINDING = NO; + SDKROOT = macosx10.6; + }; + name = Debug; + }; + 1DEB928B08733DD80010E9CD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + PREBINDING = NO; + SDKROOT = macosx10.6; + }; + name = Release; + }; + 6581071611DE809D0049FB12 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + PRODUCT_NAME = OpenPilotOSX; + }; + name = Debug; + }; + 6581071711DE809D0049FB12 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + GCC_ENABLE_FIX_AND_CONTINUE = NO; + PRODUCT_NAME = OpenPilotOSX; + ZERO_LINK = NO; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "OpenPilotOSX" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB928A08733DD80010E9CD /* Debug */, + 1DEB928B08733DD80010E9CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 6581071A11DE80A30049FB12 /* Build configuration list for PBXLegacyTarget "OpenPilotOSX" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 6581071611DE809D0049FB12 /* Debug */, + 6581071711DE809D0049FB12 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 08FB7793FE84155DC02AAC07 /* Project object */; +} From ce3cba9d40deebe3ef2010c3af26aa98ea01cc28 Mon Sep 17 00:00:00 2001 From: Vladimir Zidar Date: Wed, 26 Apr 2017 16:57:38 +0200 Subject: [PATCH 237/624] LP-479 Set lowest acceptable dshot rate to 150khz to avoid possible division by zero and unreasonably slow rates. --- flight/pios/common/pios_servo.c | 4 ++++ shared/uavobjectdefinition/actuatorsettings.xml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/flight/pios/common/pios_servo.c b/flight/pios/common/pios_servo.c index 01be0971e5..6352734345 100644 --- a/flight/pios/common/pios_servo.c +++ b/flight/pios/common/pios_servo.c @@ -215,6 +215,10 @@ extern void PIOS_Servo_Enable() void PIOS_Servo_DSHot_Rate(uint32_t rate_in_khz) { + if (rate_in_khz < 150) { + rate_in_khz = 150; + } + uint32_t raw_hz = PIOS_DELAY_GetRawHz(); uint32_t tmp = raw_hz / rate_in_khz; diff --git a/shared/uavobjectdefinition/actuatorsettings.xml b/shared/uavobjectdefinition/actuatorsettings.xml index 07fe0478ad..034dc619ca 100644 --- a/shared/uavobjectdefinition/actuatorsettings.xml +++ b/shared/uavobjectdefinition/actuatorsettings.xml @@ -3,7 +3,7 @@ Settings for the @ref ActuatorModule that controls the channel assignments for the mixer based on AircraftType - + From 792746f7758597142fb5e1f08de54206d68b50f4 Mon Sep 17 00:00:00 2001 From: Vladimir Zidar Date: Thu, 27 Apr 2017 15:44:39 +0200 Subject: [PATCH 238/624] LP-480 DSM: do not fail to initialize driver for ports without bind capability. --- flight/pios/common/pios_dsm.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/flight/pios/common/pios_dsm.c b/flight/pios/common/pios_dsm.c index 9f66a1aff8..a935e22c39 100644 --- a/flight/pios/common/pios_dsm.c +++ b/flight/pios/common/pios_dsm.c @@ -318,11 +318,9 @@ int32_t PIOS_DSM_Init(uint32_t *dsm_id, PIOS_DEBUG_Assert(driver->ioctl); - if ((driver->ioctl)(lower_id, PIOS_IOCTL_USART_GET_DSMBIND, &rxpin) < 0) { - return -1; + if ((driver->ioctl)(lower_id, PIOS_IOCTL_USART_GET_DSMBIND, &rxpin) == 0) { + PIOS_DSM_Bind(&rxpin, bind); } - - PIOS_DSM_Bind(&rxpin, bind); } PIOS_DSM_ResetState(dsm_dev); From a116bd23133aa5bafc171e9dd353aad124f3dce5 Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Wed, 3 May 2017 09:00:37 +0200 Subject: [PATCH 239/624] LP-516 gps: issuing a JumpToApp in bootloader mode will not hang board anymore ssp_dfu guard variable was preventing any user triggered JumpToApp to be fully completed --- flight/targets/boards/gpsplatinum/bootloader/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/flight/targets/boards/gpsplatinum/bootloader/main.c b/flight/targets/boards/gpsplatinum/bootloader/main.c index a11fa2f3d6..8f49d55c3f 100644 --- a/flight/targets/boards/gpsplatinum/bootloader/main.c +++ b/flight/targets/boards/gpsplatinum/bootloader/main.c @@ -161,10 +161,10 @@ int main() } led_pwm_step(period1, sweep_steps1, stopwatch, false); led_pwm_step(period2, sweep_steps2, stopwatch, true); - JumpToApp |= (stopwatch > BL_WAIT_TIME) && ((DeviceState == BLidle) || (DeviceState == DFUidle)); + JumpToApp |= !ssp_dfu && (stopwatch > BL_WAIT_TIME) && ((DeviceState == BLidle) || (DeviceState == DFUidle)); DataDownload(start); - if (JumpToApp == true && !ssp_dfu) { + if (JumpToApp == true) { jump_to_app(); } } From 4e3f480304f70082442061607d05ecd5407476ff Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Wed, 3 May 2017 09:01:23 +0200 Subject: [PATCH 240/624] LP-516 gps: bump bootloader version (from 1 to 2) --- flight/targets/boards/gpsplatinum/board-info.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flight/targets/boards/gpsplatinum/board-info.mk b/flight/targets/boards/gpsplatinum/board-info.mk index c86ef35b8c..60485b0470 100644 --- a/flight/targets/boards/gpsplatinum/board-info.mk +++ b/flight/targets/boards/gpsplatinum/board-info.mk @@ -1,6 +1,6 @@ BOARD_TYPE := 0x0A BOARD_REVISION := 0x01 -BOOTLOADER_VERSION := 0x01 +BOOTLOADER_VERSION := 0x02 HW_TYPE := 0x01 MCU := cortex-m0 From 1d04b95323bc4cbf824d456b7072116014630314 Mon Sep 17 00:00:00 2001 From: Laurent Lalanne Date: Fri, 5 May 2017 19:44:18 +0200 Subject: [PATCH 241/624] LP-510 Changes from review - Add some limits and conditions for Rssi and S-Meter --- ground/gcs/src/share/qml/js/uav.js | 8 ++++---- ground/gcs/src/share/qml/pfd/Panels.qml | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ground/gcs/src/share/qml/js/uav.js b/ground/gcs/src/share/qml/js/uav.js index 4ae549713d..d01500e86c 100644 --- a/ground/gcs/src/share/qml/js/uav.js +++ b/ground/gcs/src/share/qml/js/uav.js @@ -229,12 +229,12 @@ function isOplmConnected() { return (opLinkStatus.linkState == OPLinkStatus.LinkState.Connected); } -function OplmRSSI() { - return (opLinkStatus.rssi); +function oplmRSSI() { + return (opLinkStatus.rssi > -13) ? -13 : opLinkStatus.rssi; } -function OplmDeviceID() { - return (opLinkStatus.deviceID); +function oplmDeviceID() { + return opLinkStatus.deviceID; } function magSourceName() { diff --git a/ground/gcs/src/share/qml/pfd/Panels.qml b/ground/gcs/src/share/qml/pfd/Panels.qml index 563fdf561e..69c1513a84 100644 --- a/ground/gcs/src/share/qml/pfd/Panels.qml +++ b/ground/gcs/src/share/qml/pfd/Panels.qml @@ -86,7 +86,7 @@ Item { property real smeter_angle // Needed to get correctly int8 value - property int oplm_rssi: UAV.OplmRSSI() + property int oplm_rssi: telemetry_link ? UAV.oplmRSSI() : -127 property real telemetry_sum property real telemetry_sum_old @@ -772,7 +772,7 @@ Item { } Text { - text: UAV.OplmDeviceID() > 0 ? UAV.OplmDeviceID().toString(16) : "-- -- -- --" + text: (UAV.oplmDeviceID() > 0) ? UAV.oplmDeviceID().toString(16) : "-- -- -- --" anchors.centerIn: parent color: "white" font { From faaa60862f6c157ec061742e2f39f5851cae3999 Mon Sep 17 00:00:00 2001 From: Laurent Lalanne Date: Mon, 1 May 2017 00:22:08 +0200 Subject: [PATCH 242/624] LP-505 Refactor OPlink tab GUI --- .../src/plugins/config/configoplinkwidget.cpp | 28 +- .../src/plugins/config/configoplinkwidget.h | 2 +- ground/gcs/src/plugins/config/oplink.ui | 2091 +++++++++-------- 3 files changed, 1086 insertions(+), 1035 deletions(-) diff --git a/ground/gcs/src/plugins/config/configoplinkwidget.cpp b/ground/gcs/src/plugins/config/configoplinkwidget.cpp index 89d57c4d6e..ad42e82648 100644 --- a/ground/gcs/src/plugins/config/configoplinkwidget.cpp +++ b/ground/gcs/src/plugins/config/configoplinkwidget.cpp @@ -113,8 +113,8 @@ ConfigOPLinkWidget::ConfigOPLinkWidget(QWidget *parent) : ConfigTaskWidget(paren addWidgetBinding("OPLinkStatus", "TXPacketRate", m_oplink->TXPacketRate); addWidgetBinding("OPLinkStatus", "AFCCorrection", m_oplink->AFCCorrection); - // initially hide port combo boxes - setPortsVisible(false); + // initially hide Oplink Mini options + setOPLMOptionsVisible(false); // Connect the selection changed signals. connect(m_oplink->Protocol, SIGNAL(currentIndexChanged(int)), this, SLOT(protocolChanged())); @@ -189,10 +189,10 @@ void ConfigOPLinkWidget::updateStatus() switch (oplinkStatusObj->boardType()) { case 0x09: // Revolution, DiscoveryF4Bare, RevoNano, RevoProto case 0x92: // Sparky2 - setPortsVisible(false); + setOPLMOptionsVisible(false); break; case 0x03: // OPLinkMini - setPortsVisible(true); + setOPLMOptionsVisible(true); break; default: // This shouldn't happen. @@ -206,24 +206,10 @@ void ConfigOPLinkWidget::updateStatus() } } -void ConfigOPLinkWidget::setPortsVisible(bool visible) +void ConfigOPLinkWidget::setOPLMOptionsVisible(bool visible) { - m_oplink->UartsLabel->setVisible(visible); - m_oplink->MainPort->setVisible(visible); - m_oplink->MainPortLabel->setVisible(visible); - m_oplink->FlexiPort->setVisible(visible); - m_oplink->FlexiPortLabel->setVisible(visible); - m_oplink->ConnectionsLabel->setVisible(visible); - m_oplink->RadioPriStream->setVisible(visible); - m_oplink->RadioPriStreamLabel->setVisible(visible); - m_oplink->RadioAuxStream->setVisible(visible); - m_oplink->RadioAuxStreamLabel->setVisible(visible); - m_oplink->MainComSpeed->setVisible(visible); - m_oplink->MainComSpeedLabel->setVisible(visible); - m_oplink->FlexiComSpeed->setVisible(visible); - m_oplink->FlexiComSpeedLabel->setVisible(visible); - m_oplink->VCPBridge->setVisible(visible); - m_oplink->VCPBridgeLabel->setVisible(visible); + m_oplink->UartsGroupBox->setVisible(visible); + m_oplink->ConnectionsGroupBox->setVisible(visible); } void ConfigOPLinkWidget::updateInfo() diff --git a/ground/gcs/src/plugins/config/configoplinkwidget.h b/ground/gcs/src/plugins/config/configoplinkwidget.h index 25e9a1b7cb..f8b72d4cb0 100644 --- a/ground/gcs/src/plugins/config/configoplinkwidget.h +++ b/ground/gcs/src/plugins/config/configoplinkwidget.h @@ -62,7 +62,7 @@ class ConfigOPLinkWidget : public ConfigTaskWidget { void updateInfo(); void updateSettings(); - void setPortsVisible(bool visible); + void setOPLMOptionsVisible(bool visible); private slots: void connected(); diff --git a/ground/gcs/src/plugins/config/oplink.ui b/ground/gcs/src/plugins/config/oplink.ui index 0ce5929db9..7616704e2d 100644 --- a/ground/gcs/src/plugins/config/oplink.ui +++ b/ground/gcs/src/plugins/config/oplink.ui @@ -55,910 +55,37 @@ 0 0 - 926 - 647 + 936 + 754 - - - - 0 + + + + Qt::Vertical - - 0 + + + 20 + 40 + - - 0 + + + + + + + 430 + 0 + - - 0 - - - - - true - - - - 0 - 0 - - - - - 900 - 16777215 - - - - - 50 - false - - - - Configuration - - - - - - - 0 - 0 - - - - - 90 - 16777215 - - - - - 50 - false - - - - This is the coordinator ID we currently are bound to. -To manually bind to a specific coordinator, just type -or paste its device ID in this box and save. -The device must be rebooted for the binding to take place. - - - 8 - - - Qt::LogicalMoveStyle - - - false - - - - - - - - 0 - 0 - - - - - 0 - 0 - - - - - 90 - 16777215 - - - - - 50 - false - - - - Qt::StrongFocus - - - Enter your custom ID for this device as a hexadecimal value, -this allows device clones. Be sure only one device with this -ID transmits at the same time! -Leave blank to use autogenerated Device ID. - - - 8 - - - true - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - false - - - - - - Qt::LogicalMoveStyle - - - false - - - - - - - - 0 - 0 - - - - - 50 - true - - - - Serial Ports - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 50 - false - - - - Main Port - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Choose a function for the main port. - - - - - - - - 50 - false - - - - Speed - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 16777215 - 16777215 - - - - Choose the baud rate for the main com port. - - - - - - - - 50 - false - - - - Flexi Port - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Choose a function for the flexi port. - - - - - - - - 50 - false - - - - Speed - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 16777215 - 16777215 - - - - Choose the baud rate for the main com port. - - - - - - - - 0 - 0 - - - - - 50 - true - - - - Connections - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 50 - false - - - - Radio Primary - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Choose a destination for the primary radio stream. - - - - - - - - 50 - false - - - - Air Data Rate - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 90 - 16777215 - - - - Choose the over-the-air baud rate for the radio. - - - - - - - - 50 - false - - - - Radio Auxiliary - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 16777215 - 16777215 - - - - Choose a destination for the auxiliary radio stream. - - - - - - - - 50 - false - - - - VCP Bridge - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 16777215 - 16777215 - - - - Choose a destination for the Virtual Com Port bridge connection. - - - - - - - - 0 - 0 - - - - - 80 - 0 - - - - - 50 - false - - - - Max Chan - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 16777215 - 16777215 - - - - Set the modem protocol - - - Qt::LeftToRight - - - 0 - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - 0 - 0 - - - - - 60 - 16777215 - - - - - 50 - false - - - - Channel 0 is 430 MHz, channel 250 is 440 MHz, and the channel spacing is 40 KHz. - - - 250 - - - - - - - - 0 - 0 - - - - - 16777215 - 16777215 - - - - 440.000 (MHz) - - - - - - - - - Qt::NoFocus - - - Clear the binding/coordinator ID - - - Unbind - - - - - - - - 0 - 0 - - - - - 80 - 0 - - - - - 50 - false - - - - Min Chan - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 50 - false - - - - Protocol - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 50 - false - - - - Link Type - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - - - 0 - 0 - - - - - 60 - 16777215 - - - - - 50 - false - - - - Channel 0 is 430 MHz, channel 250 is 440 MHz, and the channel spacing is 40 KHz. - - - 250 - - - - - - - - 0 - 0 - - - - - 16777215 - 16777215 - - - - 430.000 (MHz) - - - - - - - - - - 50 - false - - - - Device ID - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 50 - false - - - - Qt::LeftToRight - - - Coordinator ID - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 16777215 - 16777215 - - - - Configure what type of packets will be sent over the link - - - Qt::LeftToRight - - - 0 - - - - - - - - 0 - 0 - - - - - 50 - false - - - - Max Power - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 90 - 16777215 - - - - Set the maximum TX output power the modem will use (mW) -0 to disable the modem. - - - Qt::LeftToRight - - - 0 - - - - - - - - 50 - false - - - - RF Band - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 90 - 16777215 - - - - Set the RF Band used. - - - Qt::LeftToRight - - - 0 - - - - - - - - - - - 0 - 0 - - - - - 150 - 16777215 - - - - RX Level - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - 0 - 0 - - - - - 100 - 0 - - - - - 50 - false - - - - -100dBm - - - Qt::AlignCenter - - - - - - - - - - 0 - 0 - - - - - 30 - 16777215 - - - - - 0 - 0 - - - - Qt::RightToLeft - - - false - - - -127 - - - 0 - - - -127 - - - Qt::AlignCenter - - - false - - - Qt::Vertical - - - false - - - %v dBm - - - - - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - 430 - 0 - - - - - 1050 - 16777215 - + + + 1050 + 16777215 + @@ -2079,6 +1206,22 @@ Leave blank to use autogenerated Device ID. + + + + + 101 + 16777215 + + + + Qt::NoFocus + + + The automatic frequency correction in Hz. + + + @@ -2102,26 +1245,10 @@ Leave blank to use autogenerated Device ID. - - - - - 101 - 16777215 - - - - Qt::NoFocus - - - The automatic frequency correction in Hz. - - - - + Qt::Horizontal @@ -2134,100 +1261,1037 @@ Leave blank to use autogenerated Device ID. - - - - Frequency Tuning + + + + 0 - - - 9 - - - 9 - - - 9 - - - 9 - - - - - Qt::NoFocus + + + + Frequency Settings + + + + 9 - - Adjust the xtal capacitor value to fine tune frequency and + + 9 + + + 9 + + + 9 + + + + + + + + 0 + 0 + + + + + 60 + 16777215 + + + + + 50 + false + + + + Channel 0 is 430 MHz, channel 250 is 440 MHz, and the channel spacing is 40 KHz. + + + 250 + + + + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + 430.000 (MHz) + + + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 50 + false + + + + From Channel + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 50 + false + + + + RF Band + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 90 + 16777215 + + + + Set the RF Band used. + + + Qt::LeftToRight + + + 0 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + 0 + 0 + + + + + 60 + 16777215 + + + + + 50 + false + + + + Channel 0 is 430 MHz, channel 250 is 440 MHz, and the channel spacing is 40 KHz. + + + 250 + + + + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + 440.000 (MHz) + + + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 50 + false + + + + To Channel + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + true + + + + 0 + 0 + + + + + 900 + 16777215 + + + + + 50 + false + + + + Configuration + + + + + + + 50 + false + + + + Device ID + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 50 + false + + + + Qt::LeftToRight + + + Coordinator ID + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 50 + false + + + + Link Type + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + Configure what type of packets will be sent over the link + + + Qt::LeftToRight + + + 0 + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 90 + 16777215 + + + + + 50 + false + + + + Qt::StrongFocus + + + Enter your custom ID for this device as a hexadecimal value, +this allows device clones. Be sure only one device with this +ID transmits at the same time! +Leave blank to use autogenerated Device ID. + + + 8 + + + true + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + false + + + + + + Qt::LogicalMoveStyle + + + false + + + + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + Set the maximum TX output power the modem will use (mW) +0 to disable the modem. + + + Qt::LeftToRight + + + 0 + + + + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + Set the modem protocol + + + Qt::LeftToRight + + + 0 + + + + + + + + 0 + 0 + + + + + 50 + false + + + + Max Power + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + + 50 + false + + + + Mode + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 50 + false + + + + Air Data Rate + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + Choose the over-the-air baud rate for the radio. + + + + + + + + + + 0 + 0 + + + + + 90 + 16777215 + + + + + 50 + false + + + + This is the coordinator ID we currently are bound to. +To manually bind to a specific coordinator, just type +or paste its device ID in this box and save. +The device must be rebooted for the binding to take place. + + + 8 + + + Qt::LogicalMoveStyle + + + false + + + + + + + + 0 + 0 + + + + Qt::NoFocus + + + Clear the binding/coordinator ID + + + Unbind + + + + + + + + + + + + 0 + + + + + Connections + + + + + + + 0 + 0 + + + + + 50 + false + + + + Radio Primary + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + Choose a destination for the primary radio stream. + + + + + + + + 50 + false + + + + VCP Bridge + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 50 + false + + + + Radio Auxiliary + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 16777215 + 16777215 + + + + Choose a destination for the auxiliary radio stream. + + + + + + + + 16777215 + 16777215 + + + + Choose a destination for the Virtual Com Port bridge connection. + + + + + + + + + + Serial Ports + + + + + + + 16777215 + 16777215 + + + + Choose the baud rate for the main com port. + + + + + + + + 50 + false + + + + Speed + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Choose a function for the flexi port. + + + + + + + + 50 + false + + + + Main Port + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 50 + false + + + + Speed + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 50 + false + + + + Flexi Port + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + Choose the baud rate for the main com port. + + + + + + + + 0 + 0 + + + + Choose a function for the main port. + + + + + + + + + + + + Frequency Tuning + + + + + + Xtal Capacitor + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + AFC Correction + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Qt::NoFocus + + + Adjust the xtal capacitor value to fine tune frequency and get an AFC value close to zero. Default value is 127. - - - 171 - - - 1 - - - 127 - - - Qt::Horizontal - - - - - - - Adjust the xtal capacitor value to fine tune frequency and + + + 171 + + + 1 + + + 127 + + + Qt::Horizontal + + + + + + + Adjust the xtal capacitor value to fine tune frequency and get an AFC value close to zero. Default value is 127. - - - 171 - - - - - - - Xtal Capacitor - - - - - - - The Automatic Frequency Correction: How much the modem will correct + + + 171 + + + + + + + The Automatic Frequency Correction: How much the modem will correct a frequency misalignement between the two modems. - - - -50 - - - 50 - - - 0 - - - Qt::AlignCenter - - - true - - - %v KHz - - - - - - - AFC Correction - - - - - + + + -50 + + + 50 + + + 0 + + + Qt::AlignCenter + + + true + + + %v KHz + + + + + + + + + + + 0 + 0 + + + + + 150 + 16777215 + + + + RX Level + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + 0 + 0 + + + + + 100 + 0 + + + + + 50 + false + + + + -100dBm + + + Qt::AlignCenter + + + + + + + + + + 0 + 0 + + + + + 30 + 16777215 + + + + + 0 + 0 + + + + Qt::RightToLeft + + + false + + + -127 + + + 0 + + + -127 + + + Qt::AlignCenter + + + false + + + Qt::Vertical + + + false + + + %v dBm + + + + + + + + + @@ -2337,18 +2401,19 @@ a frequency misalignement between the two modems. Protocol MaxRFTxPower - LinkType - ComSpeed CustomDeviceID - CoordID - UnbindButton - RFBand - MaximumChannel - MinimumChannel + LinkType + AirDataRate + RadioPriStream + RadioAuxStream + VCPBridge MainPort + MainComSpeed FlexiPort - VCPPort - RadioAuxPort + FlexiComSpeed + RFBand + MinimumChannel + MaximumChannel RFXtalCapValue applyButton saveButton From 0b8fea6fe7e7ee56c8b1c8d5d22b295dd2c19666 Mon Sep 17 00:00:00 2001 From: Laurent Lalanne Date: Mon, 1 May 2017 02:11:19 +0200 Subject: [PATCH 243/624] LP-505 Refine OPLM uart/speed visibility --- ground/gcs/src/plugins/config/configoplinkwidget.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ground/gcs/src/plugins/config/configoplinkwidget.cpp b/ground/gcs/src/plugins/config/configoplinkwidget.cpp index ad42e82648..8e01659547 100644 --- a/ground/gcs/src/plugins/config/configoplinkwidget.cpp +++ b/ground/gcs/src/plugins/config/configoplinkwidget.cpp @@ -267,10 +267,10 @@ void ConfigOPLinkWidget::updateSettings() bool is_vcp_flexi = isComboboxOptionSelected(m_oplink->VCPBridge, OPLinkSettings::VCPBRIDGE_FLEXI); bool is_bound = (m_oplink->CoordID->text() != ""); - m_oplink->MainPort->setEnabled(is_enabled || is_vcp_main); - m_oplink->FlexiPort->setEnabled(is_enabled || is_vcp_flexi); - m_oplink->MainComSpeed->setEnabled((is_enabled || is_vcp_main) && !is_ppm_only && !is_openlrs && (is_main_serial || is_main_telem)); - m_oplink->FlexiComSpeed->setEnabled((is_enabled || is_vcp_flexi) && !is_ppm_only && !is_openlrs && (is_flexi_serial || is_flexi_telem)); + m_oplink->MainPort->setEnabled((is_enabled && !is_openlrs) || is_vcp_main); + m_oplink->FlexiPort->setEnabled((is_enabled && !is_openlrs) || is_vcp_flexi); + m_oplink->MainComSpeed->setEnabled(is_enabled && !is_openlrs && !is_ppm_only && !is_vcp_main && (is_main_serial || is_main_telem)); + m_oplink->FlexiComSpeed->setEnabled(is_enabled && !is_openlrs && !is_ppm_only && !is_vcp_flexi && (is_flexi_serial || is_flexi_telem)); m_oplink->CoordID->setEnabled(is_enabled && is_receiver); m_oplink->UnbindButton->setEnabled(is_enabled && is_bound && !is_coordinator); m_oplink->CustomDeviceID->setEnabled(is_coordinator); From cac880794162e8a40151309bd7722355f8b57849 Mon Sep 17 00:00:00 2001 From: Laurent Lalanne Date: Mon, 1 May 2017 04:30:58 +0200 Subject: [PATCH 244/624] LP-505 Fix AuxStreamFlexi typo --- ground/gcs/src/plugins/config/configoplinkwidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ground/gcs/src/plugins/config/configoplinkwidget.cpp b/ground/gcs/src/plugins/config/configoplinkwidget.cpp index 8e01659547..b1149671d4 100644 --- a/ground/gcs/src/plugins/config/configoplinkwidget.cpp +++ b/ground/gcs/src/plugins/config/configoplinkwidget.cpp @@ -503,7 +503,7 @@ void ConfigOPLinkWidget::radioAuxStreamChanged() if (isComboboxOptionSelected(m_oplink->RadioPriStream, OPLinkSettings::RADIOPRISTREAM_FLEXI)) { setComboboxSelectedOption(m_oplink->RadioPriStream, OPLinkSettings::RADIOPRISTREAM_DISABLED); } - if (isComboboxOptionSelected(m_oplink->VCPBridge, OPLinkSettings::VCPBRIDGE_MAIN)) { + if (isComboboxOptionSelected(m_oplink->VCPBridge, OPLinkSettings::VCPBRIDGE_FLEXI)) { setComboboxSelectedOption(m_oplink->VCPBridge, OPLinkSettings::VCPBRIDGE_DISABLED); } break; From f2cc267435da2b4023274b5377f0ef39df4fda4f Mon Sep 17 00:00:00 2001 From: Laurent Lalanne Date: Mon, 1 May 2017 04:32:34 +0200 Subject: [PATCH 245/624] LP-505 Disable serial-telemetry options per stream/vcp used --- .../src/plugins/config/configoplinkwidget.cpp | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/ground/gcs/src/plugins/config/configoplinkwidget.cpp b/ground/gcs/src/plugins/config/configoplinkwidget.cpp index b1149671d4..66e0f38561 100644 --- a/ground/gcs/src/plugins/config/configoplinkwidget.cpp +++ b/ground/gcs/src/plugins/config/configoplinkwidget.cpp @@ -267,6 +267,27 @@ void ConfigOPLinkWidget::updateSettings() bool is_vcp_flexi = isComboboxOptionSelected(m_oplink->VCPBridge, OPLinkSettings::VCPBRIDGE_FLEXI); bool is_bound = (m_oplink->CoordID->text() != ""); + bool is_stream_main = isComboboxOptionSelected(m_oplink->RadioPriStream, OPLinkSettings::RADIOPRISTREAM_MAIN) || + isComboboxOptionSelected(m_oplink->RadioAuxStream, OPLinkSettings::RADIOAUXSTREAM_MAIN); + bool is_stream_flexi = isComboboxOptionSelected(m_oplink->RadioPriStream, OPLinkSettings::RADIOPRISTREAM_FLEXI) || + isComboboxOptionSelected(m_oplink->RadioAuxStream, OPLinkSettings::RADIOAUXSTREAM_FLEXI); + + if (!is_stream_main && !is_vcp_main && (is_main_serial || is_main_telem)) { + setComboboxSelectedOption(m_oplink->MainPort, OPLinkSettings::MAINPORT_DISABLED); + is_main_serial = false; + is_main_telem = false; + } + if (!is_stream_flexi && !is_vcp_flexi && (is_flexi_serial || is_flexi_telem)) { + setComboboxSelectedOption(m_oplink->FlexiPort, OPLinkSettings::FLEXIPORT_DISABLED); + is_flexi_serial = false; + is_flexi_telem = false; + } + + enableComboBoxOptionItem(m_oplink->FlexiPort, OPLinkSettings::FLEXIPORT_TELEMETRY, is_stream_flexi); + enableComboBoxOptionItem(m_oplink->FlexiPort, OPLinkSettings::FLEXIPORT_SERIAL, (is_stream_flexi || is_vcp_flexi)); + enableComboBoxOptionItem(m_oplink->MainPort, OPLinkSettings::MAINPORT_TELEMETRY, is_stream_main); + enableComboBoxOptionItem(m_oplink->MainPort, OPLinkSettings::MAINPORT_SERIAL, (is_stream_main || is_vcp_main)); + m_oplink->MainPort->setEnabled((is_enabled && !is_openlrs) || is_vcp_main); m_oplink->FlexiPort->setEnabled((is_enabled && !is_openlrs) || is_vcp_flexi); m_oplink->MainComSpeed->setEnabled(is_enabled && !is_openlrs && !is_ppm_only && !is_vcp_main && (is_main_serial || is_main_telem)); From b42d6d0ecfff4672171c983fe79ce27a739d8a67 Mon Sep 17 00:00:00 2001 From: Laurent Lalanne Date: Fri, 5 May 2017 23:48:33 +0200 Subject: [PATCH 246/624] LP-505 Change the channel tooltip according to the RFBand used. --- .../src/plugins/config/configoplinkwidget.cpp | 18 ++++++++++++------ .../src/plugins/config/configoplinkwidget.h | 1 + ground/gcs/src/plugins/config/oplink.ui | 6 ------ 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/ground/gcs/src/plugins/config/configoplinkwidget.cpp b/ground/gcs/src/plugins/config/configoplinkwidget.cpp index 66e0f38561..bfb1b557d3 100644 --- a/ground/gcs/src/plugins/config/configoplinkwidget.cpp +++ b/ground/gcs/src/plugins/config/configoplinkwidget.cpp @@ -332,16 +332,19 @@ void ConfigOPLinkWidget::rfBandChanged() { switch (getComboboxSelectedOption(m_oplink->RFBand)) { case OPLinkSettings::RFBAND_915MHZ: - frequency_base = 900.0f; - frequency_step = FREQUENCY_STEP * 2.0f; + frequency_base = 900.0f; + frequency_step = FREQUENCY_STEP * 2.0f; + channel_tooltip = tr("Channel 0 is 900 MHz, channel 250 is 920 MHz, and the channel spacing is 80 KHz."); break; case OPLinkSettings::RFBAND_868MHZ: - frequency_base = 860.0f; - frequency_step = FREQUENCY_STEP * 2.0f; + frequency_base = 860.0f; + frequency_step = FREQUENCY_STEP * 2.0f; + channel_tooltip = tr("Channel 0 is 860 MHz, channel 250 is 880 MHz, and the channel spacing is 80 KHz."); break; case OPLinkSettings::RFBAND_433MHZ: - frequency_base = 430.0f; - frequency_step = FREQUENCY_STEP; + frequency_base = 430.0f; + frequency_step = FREQUENCY_STEP; + channel_tooltip = tr("Channel 0 is 430 MHz, channel 250 is 440 MHz, and the channel spacing is 40 KHz."); break; } @@ -386,6 +389,9 @@ void ConfigOPLinkWidget::updateFrequencyDisplay() m_oplink->MinFreq->setText("(" + QString::number(minFrequency, 'f', 3) + " MHz)"); m_oplink->MaxFreq->setText("(" + QString::number(maxFrequency, 'f', 3) + " MHz)"); + + m_oplink->MinimumChannel->setToolTip(channel_tooltip); + m_oplink->MaximumChannel->setToolTip(channel_tooltip); } void ConfigOPLinkWidget::mainPortChanged() diff --git a/ground/gcs/src/plugins/config/configoplinkwidget.h b/ground/gcs/src/plugins/config/configoplinkwidget.h index f8b72d4cb0..7ea09347b9 100644 --- a/ground/gcs/src/plugins/config/configoplinkwidget.h +++ b/ground/gcs/src/plugins/config/configoplinkwidget.h @@ -54,6 +54,7 @@ class ConfigOPLinkWidget : public ConfigTaskWidget { // Frequency display settings float frequency_base; float frequency_step; + QString channel_tooltip; // Is the status current? bool statusUpdated; diff --git a/ground/gcs/src/plugins/config/oplink.ui b/ground/gcs/src/plugins/config/oplink.ui index 7616704e2d..262419ae24 100644 --- a/ground/gcs/src/plugins/config/oplink.ui +++ b/ground/gcs/src/plugins/config/oplink.ui @@ -1306,9 +1306,6 @@ false - - Channel 0 is 430 MHz, channel 250 is 440 MHz, and the channel spacing is 40 KHz. - 250 @@ -1433,9 +1430,6 @@ false - - Channel 0 is 430 MHz, channel 250 is 440 MHz, and the channel spacing is 40 KHz. - 250 From d3280b0bbf734e0d1e49aa9d7ad17750e529233b Mon Sep 17 00:00:00 2001 From: Laurent Lalanne Date: Sun, 7 May 2017 12:30:57 +0200 Subject: [PATCH 247/624] LP-505 Add erase/unbind button icon - Cleanup names and logic --- .../src/plugins/config/configoplinkwidget.cpp | 52 +++-- .../src/plugins/config/configoplinkwidget.h | 1 + ground/gcs/src/plugins/config/oplink.ui | 203 ++++++++++++------ ground/gcs/src/plugins/coreplugin/core.qrc | 1 + 4 files changed, 166 insertions(+), 91 deletions(-) diff --git a/ground/gcs/src/plugins/config/configoplinkwidget.cpp b/ground/gcs/src/plugins/config/configoplinkwidget.cpp index bfb1b557d3..cee73e36a3 100644 --- a/ground/gcs/src/plugins/config/configoplinkwidget.cpp +++ b/ground/gcs/src/plugins/config/configoplinkwidget.cpp @@ -68,8 +68,9 @@ ConfigOPLinkWidget::ConfigOPLinkWidget(QWidget *parent) : ConfigTaskWidget(paren addWidget(m_oplink->MinFreq); addWidget(m_oplink->MaxFreq); addWidget(m_oplink->UnbindButton); - addWidget(m_oplink->PairSignalStrengthBar1); - addWidget(m_oplink->PairSignalStrengthLabel1); + addWidget(m_oplink->ClearDeviceButton); + addWidget(m_oplink->SignalStrengthBar); + addWidget(m_oplink->SignalStrengthLabel); addWidgetBinding("OPLinkSettings", "Protocol", m_oplink->Protocol); addWidgetBinding("OPLinkSettings", "LinkType", m_oplink->LinkType); @@ -128,8 +129,9 @@ ConfigOPLinkWidget::ConfigOPLinkWidget(QWidget *parent) : ConfigTaskWidget(paren connect(m_oplink->RadioAuxStream, SIGNAL(currentIndexChanged(int)), this, SLOT(radioAuxStreamChanged())); connect(m_oplink->VCPBridge, SIGNAL(currentIndexChanged(int)), this, SLOT(vcpBridgeChanged())); - // Connect the Unbind button + // Connect the Unbind and ClearDevice buttons connect(m_oplink->UnbindButton, SIGNAL(released()), this, SLOT(unbind())); + connect(m_oplink->ClearDeviceButton, SIGNAL(released()), this, SLOT(clearDeviceID())); // all upper case hex m_oplink->CustomDeviceID->setInputMask(">HHHHHHHH"); @@ -179,8 +181,8 @@ void ConfigOPLinkWidget::updateStatus() m_oplink->LinkState->setText(linkField->getValue().toString()); bool linkConnected = (oplinkStatusObj->linkState() == OPLinkStatus_LinkState::Connected); - m_oplink->PairSignalStrengthBar1->setValue(linkConnected ? m_oplink->RSSI->text().toInt() : -127); - m_oplink->PairSignalStrengthLabel1->setText(QString("%1dBm").arg(m_oplink->PairSignalStrengthBar1->value())); + m_oplink->SignalStrengthBar->setValue(linkConnected ? m_oplink->RSSI->text().toInt() : -127); + m_oplink->SignalStrengthLabel->setText(QString("%1dBm").arg(m_oplink->SignalStrengthBar->value())); int afc_valueKHz = m_oplink->AFCCorrection->text().toInt() / 1000; m_oplink->AFCCorrectionBar->setValue(afc_valueKHz); @@ -254,10 +256,9 @@ void ConfigOPLinkWidget::updateSettings() { // qDebug() << "ConfigOPLinkWidget::updateSettings"; - bool is_enabled = !isComboboxOptionSelected(m_oplink->Protocol, OPLinkSettings::PROTOCOL_DISABLED); bool is_coordinator = isComboboxOptionSelected(m_oplink->Protocol, OPLinkSettings::PROTOCOL_OPLINKCOORDINATOR); bool is_receiver = isComboboxOptionSelected(m_oplink->Protocol, OPLinkSettings::PROTOCOL_OPLINKRECEIVER); - bool is_openlrs = isComboboxOptionSelected(m_oplink->Protocol, OPLinkSettings::PROTOCOL_OPENLRS); + bool is_oplink = (is_receiver || is_coordinator); bool is_ppm_only = isComboboxOptionSelected(m_oplink->LinkType, OPLinkSettings::LINKTYPE_CONTROL); bool is_main_serial = isComboboxOptionSelected(m_oplink->MainPort, OPLinkSettings::MAINPORT_SERIAL); bool is_main_telem = isComboboxOptionSelected(m_oplink->MainPort, OPLinkSettings::MAINPORT_TELEMETRY); @@ -265,6 +266,7 @@ void ConfigOPLinkWidget::updateSettings() bool is_flexi_telem = isComboboxOptionSelected(m_oplink->FlexiPort, OPLinkSettings::FLEXIPORT_TELEMETRY); bool is_vcp_main = isComboboxOptionSelected(m_oplink->VCPBridge, OPLinkSettings::VCPBRIDGE_MAIN); bool is_vcp_flexi = isComboboxOptionSelected(m_oplink->VCPBridge, OPLinkSettings::VCPBRIDGE_FLEXI); + bool is_custom_id = (m_oplink->CustomDeviceID->text() != ""); bool is_bound = (m_oplink->CoordID->text() != ""); bool is_stream_main = isComboboxOptionSelected(m_oplink->RadioPriStream, OPLinkSettings::RADIOPRISTREAM_MAIN) || @@ -288,24 +290,25 @@ void ConfigOPLinkWidget::updateSettings() enableComboBoxOptionItem(m_oplink->MainPort, OPLinkSettings::MAINPORT_TELEMETRY, is_stream_main); enableComboBoxOptionItem(m_oplink->MainPort, OPLinkSettings::MAINPORT_SERIAL, (is_stream_main || is_vcp_main)); - m_oplink->MainPort->setEnabled((is_enabled && !is_openlrs) || is_vcp_main); - m_oplink->FlexiPort->setEnabled((is_enabled && !is_openlrs) || is_vcp_flexi); - m_oplink->MainComSpeed->setEnabled(is_enabled && !is_openlrs && !is_ppm_only && !is_vcp_main && (is_main_serial || is_main_telem)); - m_oplink->FlexiComSpeed->setEnabled(is_enabled && !is_openlrs && !is_ppm_only && !is_vcp_flexi && (is_flexi_serial || is_flexi_telem)); - m_oplink->CoordID->setEnabled(is_enabled && is_receiver); - m_oplink->UnbindButton->setEnabled(is_enabled && is_bound && !is_coordinator); + m_oplink->MainPort->setEnabled(is_oplink || is_vcp_main); + m_oplink->FlexiPort->setEnabled(is_oplink || is_vcp_flexi); + m_oplink->MainComSpeed->setEnabled(is_oplink && !is_ppm_only && !is_vcp_main && (is_main_serial || is_main_telem)); + m_oplink->FlexiComSpeed->setEnabled(is_oplink && !is_ppm_only && !is_vcp_flexi && (is_flexi_serial || is_flexi_telem)); + m_oplink->CoordID->setEnabled(is_receiver); + m_oplink->UnbindButton->setEnabled(is_receiver && is_bound); m_oplink->CustomDeviceID->setEnabled(is_coordinator); + m_oplink->ClearDeviceButton->setEnabled(is_coordinator && is_custom_id); - m_oplink->RadioPriStream->setEnabled((is_receiver || is_coordinator) && !is_ppm_only); - m_oplink->RadioAuxStream->setEnabled((is_receiver || is_coordinator) && !is_ppm_only); + m_oplink->RadioPriStream->setEnabled(is_oplink && !is_ppm_only); + m_oplink->RadioAuxStream->setEnabled(is_oplink && !is_ppm_only); - m_oplink->AirDataRate->setEnabled((is_receiver || is_coordinator) && !is_ppm_only); - m_oplink->RFBand->setEnabled(is_receiver || is_coordinator); - m_oplink->MinimumChannel->setEnabled(is_receiver || is_coordinator); - m_oplink->MaximumChannel->setEnabled(is_receiver || is_coordinator); + m_oplink->AirDataRate->setEnabled(is_oplink && !is_ppm_only); + m_oplink->RFBand->setEnabled(is_oplink); + m_oplink->MinimumChannel->setEnabled(is_oplink); + m_oplink->MaximumChannel->setEnabled(is_oplink); - m_oplink->LinkType->setEnabled(is_enabled && !is_openlrs); - m_oplink->MaxRFTxPower->setEnabled(is_enabled && !is_openlrs); + m_oplink->LinkType->setEnabled(is_oplink); + m_oplink->MaxRFTxPower->setEnabled(is_oplink); } void ConfigOPLinkWidget::protocolChanged() @@ -598,3 +601,10 @@ void ConfigOPLinkWidget::unbind() oplinkSettingsObj->setModemParams((quint16)0); oplinkSettingsObj->setFlags((quint16)0); } + +void ConfigOPLinkWidget::clearDeviceID() +{ + // Clear the device ID + oplinkSettingsObj->setCustomDeviceID(0); + m_oplink->CustomDeviceID->clear(); +} diff --git a/ground/gcs/src/plugins/config/configoplinkwidget.h b/ground/gcs/src/plugins/config/configoplinkwidget.h index 7ea09347b9..74a4f58c17 100644 --- a/ground/gcs/src/plugins/config/configoplinkwidget.h +++ b/ground/gcs/src/plugins/config/configoplinkwidget.h @@ -84,6 +84,7 @@ private slots: void vcpBridgeChanged(); void unbind(); + void clearDeviceID(); }; #endif // CONFIGOPLINKWIDGET_H diff --git a/ground/gcs/src/plugins/config/oplink.ui b/ground/gcs/src/plugins/config/oplink.ui index 262419ae24..dddcebb76b 100644 --- a/ground/gcs/src/plugins/config/oplink.ui +++ b/ground/gcs/src/plugins/config/oplink.ui @@ -1543,7 +1543,7 @@ - + @@ -1578,7 +1578,7 @@ - + @@ -1603,65 +1603,7 @@ - - - - - 0 - 0 - - - - - 0 - 0 - - - - - 90 - 16777215 - - - - - 50 - false - - - - Qt::StrongFocus - - - Enter your custom ID for this device as a hexadecimal value, -this allows device clones. Be sure only one device with this -ID transmits at the same time! -Leave blank to use autogenerated Device ID. - - - 8 - - - true - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - false - - - - - - Qt::LogicalMoveStyle - - - false - - - - + @@ -1687,7 +1629,7 @@ Leave blank to use autogenerated Device ID. - + @@ -1712,7 +1654,7 @@ Leave blank to use autogenerated Device ID. - + @@ -1756,7 +1698,7 @@ Leave blank to use autogenerated Device ID. - + @@ -1772,7 +1714,7 @@ Leave blank to use autogenerated Device ID. - + @@ -1791,7 +1733,7 @@ Leave blank to use autogenerated Device ID. - + @@ -1833,7 +1775,7 @@ The device must be rebooted for the binding to take place. - + 0 0 @@ -1845,10 +1787,128 @@ The device must be rebooted for the binding to take place. Clear the binding/coordinator ID - Unbind + + + + + :/core/images/clear_left.png:/core/images/clear_left.png + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 10 + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 90 + 16777215 + + + + + 50 + false + + + + Qt::StrongFocus + + + Enter your custom ID for this device as a hexadecimal value, +this allows device clones. Be sure only one device with this +ID transmits at the same time! +Leave blank to use autogenerated Device ID. + + + 8 + + + true + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + false + + + + + + Qt::LogicalMoveStyle + + + false + + + + + + + + 0 + 0 + + + + Qt::NoFocus + + + Clear the device ID and leave it autogenerated + + + + + + + :/core/images/clear_left.png:/core/images/clear_left.png + + + + Qt::Horizontal + + + + 40 + 20 + + + + @@ -2199,7 +2259,7 @@ a frequency misalignement between the two modems. - + 0 @@ -2229,7 +2289,7 @@ a frequency misalignement between the two modems. - + 0 @@ -2396,6 +2456,9 @@ a frequency misalignement between the two modems. Protocol MaxRFTxPower CustomDeviceID + ClearDeviceButton + CoordID + UnbindButton LinkType AirDataRate RadioPriStream diff --git a/ground/gcs/src/plugins/coreplugin/core.qrc b/ground/gcs/src/plugins/coreplugin/core.qrc index 0a7e4c4a44..a0ce8099a7 100644 --- a/ground/gcs/src/plugins/coreplugin/core.qrc +++ b/ground/gcs/src/plugins/coreplugin/core.qrc @@ -7,6 +7,7 @@ images/librepilot_logo_32.png images/clean_pane_small.png images/clear.png + images/clear_left.png images/closebutton.png images/dir.png images/editcopy.png From eb59d7381f21151f7a68147ad6b00c583001e3ed Mon Sep 17 00:00:00 2001 From: Laurent Lalanne Date: Sun, 7 May 2017 22:01:12 +0200 Subject: [PATCH 248/624] LP-505 Check customID and coordID changes - Use isEmpty() --- .../src/plugins/config/configoplinkwidget.cpp | 16 ++++++++++++++-- .../gcs/src/plugins/config/configoplinkwidget.h | 2 ++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/ground/gcs/src/plugins/config/configoplinkwidget.cpp b/ground/gcs/src/plugins/config/configoplinkwidget.cpp index cee73e36a3..438b88dc8c 100644 --- a/ground/gcs/src/plugins/config/configoplinkwidget.cpp +++ b/ground/gcs/src/plugins/config/configoplinkwidget.cpp @@ -120,6 +120,8 @@ ConfigOPLinkWidget::ConfigOPLinkWidget(QWidget *parent) : ConfigTaskWidget(paren // Connect the selection changed signals. connect(m_oplink->Protocol, SIGNAL(currentIndexChanged(int)), this, SLOT(protocolChanged())); connect(m_oplink->LinkType, SIGNAL(currentIndexChanged(int)), this, SLOT(linkTypeChanged())); + connect(m_oplink->CustomDeviceID, SIGNAL(textChanged(QString)), this, SLOT(customIDChanged())); + connect(m_oplink->CoordID, SIGNAL(textChanged(QString)), this, SLOT(coordIDChanged())); connect(m_oplink->RFBand, SIGNAL(currentIndexChanged(int)), this, SLOT(rfBandChanged())); connect(m_oplink->MinimumChannel, SIGNAL(valueChanged(int)), this, SLOT(minChannelChanged())); connect(m_oplink->MaximumChannel, SIGNAL(valueChanged(int)), this, SLOT(maxChannelChanged())); @@ -266,8 +268,8 @@ void ConfigOPLinkWidget::updateSettings() bool is_flexi_telem = isComboboxOptionSelected(m_oplink->FlexiPort, OPLinkSettings::FLEXIPORT_TELEMETRY); bool is_vcp_main = isComboboxOptionSelected(m_oplink->VCPBridge, OPLinkSettings::VCPBRIDGE_MAIN); bool is_vcp_flexi = isComboboxOptionSelected(m_oplink->VCPBridge, OPLinkSettings::VCPBRIDGE_FLEXI); - bool is_custom_id = (m_oplink->CustomDeviceID->text() != ""); - bool is_bound = (m_oplink->CoordID->text() != ""); + bool is_custom_id = !m_oplink->CustomDeviceID->text().isEmpty(); + bool is_bound = !m_oplink->CoordID->text().isEmpty(); bool is_stream_main = isComboboxOptionSelected(m_oplink->RadioPriStream, OPLinkSettings::RADIOPRISTREAM_MAIN) || isComboboxOptionSelected(m_oplink->RadioAuxStream, OPLinkSettings::RADIOAUXSTREAM_MAIN); @@ -321,6 +323,16 @@ void ConfigOPLinkWidget::linkTypeChanged() updateSettings(); } +void ConfigOPLinkWidget::customIDChanged() +{ + updateSettings(); +} + +void ConfigOPLinkWidget::coordIDChanged() +{ + updateSettings(); +} + void ConfigOPLinkWidget::minChannelChanged() { channelChanged(false); diff --git a/ground/gcs/src/plugins/config/configoplinkwidget.h b/ground/gcs/src/plugins/config/configoplinkwidget.h index 74a4f58c17..156b8a3bbe 100644 --- a/ground/gcs/src/plugins/config/configoplinkwidget.h +++ b/ground/gcs/src/plugins/config/configoplinkwidget.h @@ -70,6 +70,8 @@ private slots: void protocolChanged(); void linkTypeChanged(); + void customIDChanged(); + void coordIDChanged(); void minChannelChanged(); void maxChannelChanged(); From ba5e5695db89c3d7a6b8f1b2d2c8eca3a56e9f67 Mon Sep 17 00:00:00 2001 From: Laurent Lalanne Date: Tue, 9 May 2017 22:10:57 +0200 Subject: [PATCH 249/624] LP-505 Handle OpenLRS unbinding --- .../src/plugins/config/configoplinkwidget.cpp | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/ground/gcs/src/plugins/config/configoplinkwidget.cpp b/ground/gcs/src/plugins/config/configoplinkwidget.cpp index 438b88dc8c..9ded0884e4 100644 --- a/ground/gcs/src/plugins/config/configoplinkwidget.cpp +++ b/ground/gcs/src/plugins/config/configoplinkwidget.cpp @@ -258,6 +258,7 @@ void ConfigOPLinkWidget::updateSettings() { // qDebug() << "ConfigOPLinkWidget::updateSettings"; + bool is_openlrs = isComboboxOptionSelected(m_oplink->Protocol, OPLinkSettings::PROTOCOL_OPENLRS); bool is_coordinator = isComboboxOptionSelected(m_oplink->Protocol, OPLinkSettings::PROTOCOL_OPLINKCOORDINATOR); bool is_receiver = isComboboxOptionSelected(m_oplink->Protocol, OPLinkSettings::PROTOCOL_OPLINKRECEIVER); bool is_oplink = (is_receiver || is_coordinator); @@ -296,8 +297,10 @@ void ConfigOPLinkWidget::updateSettings() m_oplink->FlexiPort->setEnabled(is_oplink || is_vcp_flexi); m_oplink->MainComSpeed->setEnabled(is_oplink && !is_ppm_only && !is_vcp_main && (is_main_serial || is_main_telem)); m_oplink->FlexiComSpeed->setEnabled(is_oplink && !is_ppm_only && !is_vcp_flexi && (is_flexi_serial || is_flexi_telem)); - m_oplink->CoordID->setEnabled(is_receiver); - m_oplink->UnbindButton->setEnabled(is_receiver && is_bound); + m_oplink->CoordID->setEnabled(is_receiver || is_openlrs); + m_oplink->CoordID->setReadOnly(is_openlrs); + m_oplink->UnbindButton->setEnabled((is_receiver && is_bound) || is_openlrs); + m_oplink->CustomDeviceID->setEnabled(is_coordinator); m_oplink->ClearDeviceButton->setEnabled(is_coordinator && is_custom_id); @@ -601,22 +604,22 @@ void ConfigOPLinkWidget::vcpBridgeChanged() void ConfigOPLinkWidget::unbind() { // Clear the coordinator ID - oplinkSettingsObj->setCoordID(0); m_oplink->CoordID->clear(); - // Clear the OpenLRS settings - oplinkSettingsObj->setVersion((quint16)0); - oplinkSettingsObj->setSerialBaudrate(0); - oplinkSettingsObj->setRFFrequency(0); - oplinkSettingsObj->setRFPower((quint16)0); - oplinkSettingsObj->setRFChannelSpacing((quint16)0); - oplinkSettingsObj->setModemParams((quint16)0); - oplinkSettingsObj->setFlags((quint16)0); + // Clear the OpenLRS settings when needed + if (isComboboxOptionSelected(m_oplink->Protocol, OPLinkSettings::PROTOCOL_OPENLRS)) { + oplinkSettingsObj->setVersion((quint16)0); + oplinkSettingsObj->setSerialBaudrate(0); + oplinkSettingsObj->setRFFrequency(0); + oplinkSettingsObj->setRFPower((quint16)0); + oplinkSettingsObj->setRFChannelSpacing((quint16)0); + oplinkSettingsObj->setModemParams((quint16)0); + oplinkSettingsObj->setFlags((quint16)0); + } } void ConfigOPLinkWidget::clearDeviceID() { - // Clear the device ID - oplinkSettingsObj->setCustomDeviceID(0); + // Clear the OPLM device ID m_oplink->CustomDeviceID->clear(); } From 289285cadb5a830204b83b8d806c2643e7dca5b2 Mon Sep 17 00:00:00 2001 From: Laurent Lalanne Date: Wed, 10 May 2017 15:13:32 +0200 Subject: [PATCH 250/624] LP-505 Use clear() for OpenLRS settings reset --- .../gcs/src/plugins/config/configoplinkwidget.cpp | 14 +++++++------- ground/gcs/src/plugins/uavobjects/uavobjectfield.h | 3 ++- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/ground/gcs/src/plugins/config/configoplinkwidget.cpp b/ground/gcs/src/plugins/config/configoplinkwidget.cpp index 9ded0884e4..cb53e3444c 100644 --- a/ground/gcs/src/plugins/config/configoplinkwidget.cpp +++ b/ground/gcs/src/plugins/config/configoplinkwidget.cpp @@ -608,13 +608,13 @@ void ConfigOPLinkWidget::unbind() // Clear the OpenLRS settings when needed if (isComboboxOptionSelected(m_oplink->Protocol, OPLinkSettings::PROTOCOL_OPENLRS)) { - oplinkSettingsObj->setVersion((quint16)0); - oplinkSettingsObj->setSerialBaudrate(0); - oplinkSettingsObj->setRFFrequency(0); - oplinkSettingsObj->setRFPower((quint16)0); - oplinkSettingsObj->setRFChannelSpacing((quint16)0); - oplinkSettingsObj->setModemParams((quint16)0); - oplinkSettingsObj->setFlags((quint16)0); + QStringList openLRS_settings; + openLRS_settings << "Version" << "SerialBaudrate" << "ModemParams" << "Flags" \ + << "RFFrequency" << "RFPower" << "RFChannelSpacing" << "HopChannel"; + + for (int i = 0; i < openLRS_settings.size(); ++i) { + oplinkSettingsObj->getField(openLRS_settings[i])->clear(); + } } } diff --git a/ground/gcs/src/plugins/uavobjects/uavobjectfield.h b/ground/gcs/src/plugins/uavobjects/uavobjectfield.h index 42a3de0769..2c82cce950 100644 --- a/ground/gcs/src/plugins/uavobjects/uavobjectfield.h +++ b/ground/gcs/src/plugins/uavobjects/uavobjectfield.h @@ -80,6 +80,8 @@ class UAVOBJECTS_EXPORT UAVObjectField : public QObject { bool isText(); QString toString(); + void clear(); + void toXML(QXmlStreamWriter *xmlWriter); void fromXML(QXmlStreamReader *xmlReader); @@ -106,7 +108,6 @@ class UAVOBJECTS_EXPORT UAVObjectField : public QObject { quint8 *data; UAVObject *obj; QMap > elementLimits; - void clear(); void constructorInitialize(const QString & name, const QString & description, const QString & units, FieldType type, const QStringList & elementNames, const QStringList & options, const QString &limits); void limitsInitialize(const QString &limits); }; From 8e87f8b793bb78c13005c80ac0e155b7b27127ba Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Sun, 7 May 2017 18:06:35 +0200 Subject: [PATCH 251/624] LP-517 gcs: rework main sequencing to allow file logging of application shutdown --- ground/gcs/src/app/main.cpp | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/ground/gcs/src/app/main.cpp b/ground/gcs/src/app/main.cpp index ee6e8c35d2..3ea43d9e48 100644 --- a/ground/gcs/src/app/main.cpp +++ b/ground/gcs/src/app/main.cpp @@ -403,14 +403,14 @@ void loadFactoryDefaults(QSettings &settings, AppOptionValues &appOptionValues) qDebug() << "Configuration file" << fileName << "was loaded."; } -void overrideSettings(QSettings &settings, int argc, char * *argv) +void overrideSettings(QSettings &settings, const QStringList &arguments) { // Options like -D My/setting=test QRegExp rx("([^=]+)=(.*)"); - for (int i = 0; i < argc; ++i) { - if (CONFIG_OPTION == QString(argv[i])) { - if (rx.indexIn(argv[++i]) > -1) { + for (int i = 0; i < arguments.size(); ++i) { + if (CONFIG_OPTION == arguments[i]) { + if (rx.indexIn(arguments[++i]) > -1) { QString key = rx.cap(1); QString value = rx.cap(2); qDebug() << "User setting" << key << "set to value" << value; @@ -443,15 +443,12 @@ void loadTranslators(QString language, QTranslator &translator, QTranslator &qtT } } -int main(int argc, char * *argv) +int runApplication(int argc, char * *argv) { QElapsedTimer timer; timer.start(); - // low level init - systemInit(); - // create application SharedTools::QtSingleApplication app(APP_NAME, argc, argv); @@ -508,7 +505,7 @@ int main(int argc, char * *argv) // override settings with command line provided values // take notice that the overridden values will be saved in the user settings and will continue to be effective // in subsequent GCS runs - overrideSettings(settings, argc, argv); + overrideSettings(settings, app.arguments()); // initialize GCS locale // use the value defined by the General/Locale setting or default to system Locale. @@ -625,12 +622,21 @@ int main(int argc, char * *argv) delete splash; } - qDebug() << "main - main took" << timer.elapsed() << "ms"; - + qDebug() << "main - starting GCS took" << timer.elapsed() << "ms"; int ret = app.exec(); - qDebug() << "main - GCS ran for" << timer.elapsed() << "ms"; + return ret; +} + +int main(int argc, char * *argv) +{ + // low level init + systemInit(); + + int ret = runApplication(argc, argv); + + // close log file if needed logDeinit(); return ret; From 44869bb934538f1d96759a6fd1383e3c367af18c Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Sun, 7 May 2017 18:13:29 +0200 Subject: [PATCH 252/624] LP-517 gcs: flush when writing to uavtalk log to avoid device full errors UAVTalk checks that (io->bytesToWrite() < TX_BUFFER_SIZE) and, since upgrading to Qt 5.8.0, that test fails when writting to log file Apparently Qt 5.8.0 has increased the file buffer size or made some change to file handling Flushing after each write works around this issue. --- ground/gcs/src/libs/utils/logfile.cpp | 29 +++++++++++++++++++++++++++ ground/gcs/src/libs/utils/logfile.h | 28 ++++++++++++++++++++++++-- 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/ground/gcs/src/libs/utils/logfile.cpp b/ground/gcs/src/libs/utils/logfile.cpp index 520085b733..6764a2e72e 100644 --- a/ground/gcs/src/libs/utils/logfile.cpp +++ b/ground/gcs/src/libs/utils/logfile.cpp @@ -1,4 +1,29 @@ +/** + ****************************************************************************** + * + * @file logfile.cpp + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017. + * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @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 "logfile.h" + #include #include @@ -72,6 +97,10 @@ qint64 LogFile::writeData(const char *data, qint64 dataSize) m_file.write((char *)&dataSize, sizeof(dataSize)); qint64 written = m_file.write(data, dataSize); + + // flush (needed to avoid UAVTalk device full errors) + m_file.flush(); + if (written != -1) { emit bytesWritten(written); } diff --git a/ground/gcs/src/libs/utils/logfile.h b/ground/gcs/src/libs/utils/logfile.h index 88319109d4..012871e490 100644 --- a/ground/gcs/src/libs/utils/logfile.h +++ b/ground/gcs/src/libs/utils/logfile.h @@ -1,6 +1,32 @@ +/** + ****************************************************************************** + * + * @file logfile.h + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017. + * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @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 LOGFILE_H #define LOGFILE_H +#include "utils_global.h" + #include #include #include @@ -8,7 +34,6 @@ #include #include #include -#include "utils_global.h" class QTCREATOR_UTILS_EXPORT LogFile : public QIODevice { Q_OBJECT @@ -66,7 +91,6 @@ protected slots: double m_lastPlayed; QMutex m_mutex; - int m_timeOffset; double m_playbackSpeed; From faf0fe758ac26c77e26a7156548c4109cb154b09 Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Sun, 7 May 2017 18:28:52 +0200 Subject: [PATCH 253/624] LP-517 gcs: fix double free when stopping uavtalk logging --- .../gcs/src/plugins/logging/loggingplugin.cpp | 106 +++++++++--------- .../gcs/src/plugins/logging/loggingplugin.h | 16 ++- 2 files changed, 62 insertions(+), 60 deletions(-) diff --git a/ground/gcs/src/plugins/logging/loggingplugin.cpp b/ground/gcs/src/plugins/logging/loggingplugin.cpp index da3efbe9be..2f9bbc32e3 100644 --- a/ground/gcs/src/plugins/logging/loggingplugin.cpp +++ b/ground/gcs/src/plugins/logging/loggingplugin.cpp @@ -2,7 +2,8 @@ ****************************************************************************** * * @file logging.cpp - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017. + * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. * @see The GNU Public License (GPL) Version 3 * @brief Import/Export Plugin * @addtogroup GCSPlugins GCS Plugins @@ -86,8 +87,7 @@ void LoggingConnection::startReplay(QString file) { logFile.setFileName(file); if (logFile.open(QIODevice::ReadOnly)) { - qDebug() << "Replaying " << file; - // state = REPLAY; + qDebug() << "LoggingConnection - replaying " << file; logFile.startReplay(); } } @@ -102,7 +102,6 @@ void LoggingConnection::closeDevice(const QString &deviceName) } } - QString LoggingConnection::connectionName() { return QString("Logfile replay"); @@ -113,10 +112,12 @@ QString LoggingConnection::shortName() return QString("Logfile"); } +LoggingThread::LoggingThread() : QThread(), uavTalk(0) +{} LoggingThread::~LoggingThread() { - stopLogging(); + delete uavTalk; } /** @@ -125,7 +126,7 @@ LoggingThread::~LoggingThread() * @param[in] file File name to write to * @param[in] parent plugin */ -bool LoggingThread::openFile(QString file, LoggingPlugin *parent) +bool LoggingThread::openFile(QString file) { logFile.setFileName(file); logFile.open(QIODevice::WriteOnly); @@ -134,7 +135,6 @@ bool LoggingThread::openFile(QString file, LoggingPlugin *parent) UAVObjectManager *objManager = pm->getObject(); uavTalk = new UAVTalk(&logFile, objManager); - connect(parent, SIGNAL(stopLoggingSignal()), this, SLOT(stopLogging())); return true; }; @@ -150,16 +150,24 @@ void LoggingThread::objectUpdated(UAVObject *obj) QWriteLocker locker(&lock); if (!uavTalk->sendObject(obj, false, false)) { - qDebug() << "Error logging " << obj->getName(); + qDebug() << "LoggingThread - error logging" << obj->getName(); } }; + +void LoggingThread::run() +{ + qDebug() << "LoggingThread - run"; + startLogging(); +} + /** * Connect signals from all the objects updates to the write routine then * run event loop */ -void LoggingThread::run() +void LoggingThread::startLogging() { + qDebug() << "LoggingThread - start logging"; ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); UAVObjectManager *objManager = pm->getObject(); @@ -173,29 +181,27 @@ void LoggingThread::run() for (j = (*i).constBegin(); j != (*i).constEnd(); ++j) { connect(*j, SIGNAL(objectUpdated(UAVObject *)), (LoggingThread *)this, SLOT(objectUpdated(UAVObject *))); objects++; - // qDebug() << "Detected " << j[0]; } } GCSTelemetryStats *gcsStatsObj = GCSTelemetryStats::GetInstance(objManager); GCSTelemetryStats::DataFields gcsStats = gcsStatsObj->getData(); if (gcsStats.Status == GCSTelemetryStats::STATUS_CONNECTED) { - qDebug() << "Logging: connected already, ask for all settings"; + qDebug() << "LoggingThread - connected, ask for all settings"; retrieveSettings(); } else { - qDebug() << "Logging: not connected, do no ask for settings"; + qDebug() << "LoggingThread - not connected, do not ask for settings"; } - exec(); } - /** * Pass this command to the correct thread then close the file */ void LoggingThread::stopLogging() { + qDebug() << "LoggingThread - stop logging"; QWriteLocker locker(&lock); // Disconnect all objects we registered with: @@ -214,8 +220,11 @@ void LoggingThread::stopLogging() } logFile.close(); - qDebug() << "File closed"; + quit(); + + // wait for thread to finish + wait(); } /** @@ -237,12 +246,11 @@ void LoggingThread::retrieveSettings() } } // Start retrieving - qDebug() << QString("Logging: retrieve settings objects from the autopilot (%1 objects)") + qDebug() << QString("LoggingThread - retrieve settings objects from the autopilot (%1 objects)") .arg(queue.length()); retrieveNextObject(); } - /** * Retrieve the next object in the queue */ @@ -250,7 +258,7 @@ void LoggingThread::retrieveNextObject() { // If queue is empty return if (queue.isEmpty()) { - qDebug() << "Logging: Object retrieval completed"; + qDebug() << "LoggingThread - Object retrieval completed"; return; } // Get next object from the queue @@ -278,17 +286,11 @@ void LoggingThread::transactionCompleted(UAVObject *obj, bool success) if (gcsStats.Status == GCSTelemetryStats::STATUS_CONNECTED) { retrieveNextObject(); } else { - qDebug() << "Logging: Object retrieval has been cancelled"; + qDebug() << "LoggingThread - object retrieval has been cancelled"; queue.clear(); } } - -/**************************************************************** - Logging plugin - ********************************/ - - LoggingPlugin::LoggingPlugin() : state(IDLE), loggingThread(NULL), @@ -299,10 +301,7 @@ LoggingPlugin::LoggingPlugin() : LoggingPlugin::~LoggingPlugin() { - delete loggingThread; - - // Don't delete it, the plugin manager will do it: - // delete logConnection; + stopLogging(); } /** @@ -313,8 +312,6 @@ bool LoggingPlugin::initialize(const QStringList & args, QString *errMsg) Q_UNUSED(args); Q_UNUSED(errMsg); - loggingThread = NULL; - // Add Menu entry Core::ActionManager *am = Core::ICore::instance()->actionManager(); Core::ActionContainer *ac = am->actionContainer(Core::Constants::M_TOOLS); @@ -333,7 +330,6 @@ bool LoggingPlugin::initialize(const QStringList & args, QString *errMsg) connect(cmd->action(), SIGNAL(triggered(bool)), this, SLOT(toggleLogging())); - mf = new LoggingGadgetFactory(this); addAutoReleasedObject(mf); @@ -359,10 +355,8 @@ void LoggingPlugin::toggleLogging() } startLogging(fileName); - cmd->action()->setText(tr("Stop logging")); } else if (state == LOGGING) { stopLogging(); - cmd->action()->setText(tr("Start logging...")); } } @@ -372,20 +366,20 @@ void LoggingPlugin::toggleLogging() */ void LoggingPlugin::startLogging(QString file) { - qDebug() << "Logging to " << file; - // We have to delete the previous logging thread if is was still there! - if (loggingThread) { - delete loggingThread; - } + qDebug() << "LoggingPlugin - start logging to " << file; + // needed ? + stopLogging(); + // Start logging thread loggingThread = new LoggingThread(); - if (loggingThread->openFile(file, this)) { - connect(loggingThread, SIGNAL(finished()), this, SLOT(loggingStopped())); - state = LOGGING; + if (loggingThread->openFile(file)) { + connect(loggingThread, &LoggingThread::finished, this, &LoggingPlugin::loggingStopped); loggingThread->start(); - emit stateChanged("LOGGING"); + loggingStarted(); } else { + delete loggingThread; + loggingThread = NULL; QErrorMessage err; - err.showMessage("Unable to open file for logging"); + err.showMessage(tr("Unable to open file for logging")); err.exec(); } } @@ -395,11 +389,23 @@ void LoggingPlugin::startLogging(QString file) */ void LoggingPlugin::stopLogging() { - emit stopLoggingSignal(); + if (!loggingThread) { + return; + } - disconnect(this, SIGNAL(stopLoggingSignal()), 0, 0); + qDebug() << "LoggingPlugin - stop logging"; + loggingThread->stopLogging(); + + delete loggingThread; + loggingThread = NULL; } +void LoggingPlugin::loggingStarted() +{ + state = LOGGING; + cmd->action()->setText(tr("Stop logging")); + emit stateChanged("LOGGING"); +} /** * Receive the logging stopped signal from the LoggingThread @@ -409,12 +415,9 @@ void LoggingPlugin::loggingStopped() { if (state == LOGGING) { state = IDLE; + cmd->action()->setText(tr("Start logging...")); + emit stateChanged("IDLE"); } - - emit stateChanged("IDLE"); - - delete loggingThread; - loggingThread = NULL; } /** @@ -445,6 +448,7 @@ void LoggingPlugin::shutdown() { // Do nothing } + /** * @} * @} diff --git a/ground/gcs/src/plugins/logging/loggingplugin.h b/ground/gcs/src/plugins/logging/loggingplugin.h index 7c2ed74060..8b482db16c 100644 --- a/ground/gcs/src/plugins/logging/loggingplugin.h +++ b/ground/gcs/src/plugins/logging/loggingplugin.h @@ -1,7 +1,8 @@ /** ****************************************************************************** * @file loggingplugin.h - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017. + * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. * @see The GNU Public License (GPL) Version 3 * @addtogroup GCSPlugins GCS Plugins * @{ @@ -72,12 +73,10 @@ class LoggingConnection return &logFile; } - private: LogFile logFile; LoggingPlugin *loggingPlugin; - protected slots: void onEnumerationChanged(); void startReplay(QString file); @@ -86,19 +85,20 @@ protected slots: bool m_deviceOpened; }; - class LoggingThread : public QThread { Q_OBJECT public: + LoggingThread(); virtual ~LoggingThread(); - bool openFile(QString file, LoggingPlugin *parent); + bool openFile(QString file); private slots: void objectUpdated(UAVObject *obj); void transactionCompleted(UAVObject *obj, bool success); public slots: + void startLogging(); void stopLogging(); protected: @@ -138,15 +138,12 @@ class LoggingPlugin : public ExtensionSystem::IPlugin { } void setLogMenuTitle(QString str); - signals: - void stopLoggingSignal(void); - void stopReplaySignal(void); void stateChanged(QString); - protected: enum { IDLE, LOGGING, REPLAY } state; + LoggingThread *loggingThread; // These are used for replay, logging in its own thread @@ -156,6 +153,7 @@ private slots: void toggleLogging(); void startLogging(QString file); void stopLogging(); + void loggingStarted(); void loggingStopped(); void replayStarted(); void replayStopped(); From 8c744a331dfb901cac2e577ebefcf40500ad06bc Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Tue, 9 May 2017 22:17:14 +0200 Subject: [PATCH 254/624] LP-517 gcs: fix uavtalk logging timer threading issues make sure QTimer stop and start are always called from owner thread --- ground/gcs/src/libs/utils/logfile.cpp | 12 ++--- ground/gcs/src/libs/utils/logfile.h | 8 +++- .../gcs/src/plugins/logging/loggingplugin.cpp | 45 ++++++++++--------- .../gcs/src/plugins/logging/loggingplugin.h | 17 +++---- 4 files changed, 43 insertions(+), 39 deletions(-) diff --git a/ground/gcs/src/libs/utils/logfile.cpp b/ground/gcs/src/libs/utils/logfile.cpp index 6764a2e72e..3f19dacf63 100644 --- a/ground/gcs/src/libs/utils/logfile.cpp +++ b/ground/gcs/src/libs/utils/logfile.cpp @@ -29,6 +29,7 @@ LogFile::LogFile(QObject *parent) : QIODevice(parent), + m_timer(this), m_lastTimeStamp(0), m_lastPlayed(0), m_timeOffset(0), @@ -55,6 +56,7 @@ bool LogFile::open(OpenMode mode) // connection manager call... return true; } + qDebug() << "LogFile - open" << fileName(); if (m_file.open(mode) == false) { qDebug() << "Unable to open " << m_file.fileName() << " for logging"; @@ -74,11 +76,8 @@ bool LogFile::open(OpenMode mode) void LogFile::close() { + qDebug() << "LogFile - close" << fileName(); emit aboutToClose(); - - if (m_timer.isActive()) { - m_timer.stop(); - } m_file.close(); QIODevice::close(); } @@ -183,6 +182,7 @@ void LogFile::timerFired() bool LogFile::startReplay() { + qDebug() << "LogFile - startReplay"; m_dataBuffer.clear(); m_myTime.restart(); m_timeOffset = 0; @@ -196,7 +196,9 @@ bool LogFile::startReplay() bool LogFile::stopReplay() { - close(); + qDebug() << "LogFile - stopReplay"; + m_timer.stop(); + emit replayFinished(); return true; } diff --git a/ground/gcs/src/libs/utils/logfile.h b/ground/gcs/src/libs/utils/logfile.h index 012871e490..19e9d35905 100644 --- a/ground/gcs/src/libs/utils/logfile.h +++ b/ground/gcs/src/libs/utils/logfile.h @@ -45,6 +45,10 @@ class QTCREATOR_UTILS_EXPORT LogFile : public QIODevice { return m_file.bytesToWrite(); }; bool open(OpenMode mode); + QString fileName() + { + return m_file.fileName(); + }; void setFileName(QString name) { m_file.setFileName(name); @@ -53,8 +57,6 @@ class QTCREATOR_UTILS_EXPORT LogFile : public QIODevice { qint64 writeData(const char *data, qint64 dataSize); qint64 readData(char *data, qint64 maxlen); - bool startReplay(); - bool stopReplay(); void useProvidedTimeStamp(bool useProvidedTimeStamp) { m_useProvidedTimeStamp = useProvidedTimeStamp; @@ -71,6 +73,8 @@ public slots: m_playbackSpeed = val; qDebug() << "Playback speed is now" << m_playbackSpeed; }; + bool startReplay(); + bool stopReplay(); void pauseReplay(); void resumeReplay(); diff --git a/ground/gcs/src/plugins/logging/loggingplugin.cpp b/ground/gcs/src/plugins/logging/loggingplugin.cpp index 2f9bbc32e3..cc7e7cccc3 100644 --- a/ground/gcs/src/plugins/logging/loggingplugin.cpp +++ b/ground/gcs/src/plugins/logging/loggingplugin.cpp @@ -30,6 +30,8 @@ #include "loggingplugin.h" #include "logginggadgetfactory.h" + +#include #include #include #include @@ -45,17 +47,14 @@ #include "uavobjectmanager.h" -LoggingConnection::LoggingConnection(LoggingPlugin *loggingPlugin) : - loggingPlugin(loggingPlugin), - m_deviceOpened(false) +LoggingConnection::LoggingConnection() : + m_deviceOpened(false), logFile() {} LoggingConnection::~LoggingConnection() -{} - -void LoggingConnection::onEnumerationChanged() { - emit availableDevChanged(this); + // make sure to close device to kill timers appropriately + closeDevice(""); } QList LoggingConnection::availableDevices() @@ -71,34 +70,37 @@ QList LoggingConnection::availableDevices() QIODevice *LoggingConnection::openDevice(const QString &deviceName) { - loggingPlugin->stopLogging(); closeDevice(deviceName); QString fileName = QFileDialog::getOpenFileName(NULL, tr("Open file"), QString(""), tr("OpenPilot Log (*.opl)")); if (!fileName.isNull()) { - startReplay(fileName); + logFile.setFileName(fileName); + if (logFile.open(QIODevice::ReadOnly)) { + // call startReplay on correct thread to avoid error from LogFile's replay QTimer + // you can't start or stop the timer from a thread other than the QTimer owner thread. + // note that the LogFile IO device (and thus its owned QTimer) is moved to a dedicated thread by the TelemetryManager + Qt::ConnectionType ct = (QApplication::instance()->thread() == logFile.thread()) ? Qt::DirectConnection : Qt::BlockingQueuedConnection; + QMetaObject::invokeMethod(&logFile, "startReplay", ct); + m_deviceOpened = true; + } return &logFile; } return NULL; } -void LoggingConnection::startReplay(QString file) -{ - logFile.setFileName(file); - if (logFile.open(QIODevice::ReadOnly)) { - qDebug() << "LoggingConnection - replaying " << file; - logFile.startReplay(); - } -} - void LoggingConnection::closeDevice(const QString &deviceName) { Q_UNUSED(deviceName); - // we have to delete the serial connection we created + if (logFile.isOpen()) { - logFile.close(); m_deviceOpened = false; + // call stoptReplay on correct thread to avoid error from LogFile's replay QTimer + // you can't start or stop the timer from a thread other than the QTimer owner thread. + // note that the LogFile IO device (and thus its owned QTimer) is moved to a dedicated thread by the TelemetryManager + Qt::ConnectionType ct = (QApplication::instance()->thread() == logFile.thread()) ? Qt::DirectConnection : Qt::BlockingQueuedConnection; + QMetaObject::invokeMethod(&logFile, "stopReplay", ct); + logFile.close(); } } @@ -294,7 +296,7 @@ void LoggingThread::transactionCompleted(UAVObject *obj, bool success) LoggingPlugin::LoggingPlugin() : state(IDLE), loggingThread(NULL), - logConnection(new LoggingConnection(this)), + logConnection(new LoggingConnection()), mf(NULL), cmd(NULL) {} @@ -302,6 +304,7 @@ LoggingPlugin::LoggingPlugin() : LoggingPlugin::~LoggingPlugin() { stopLogging(); + // logConnection will be auto released } /** diff --git a/ground/gcs/src/plugins/logging/loggingplugin.h b/ground/gcs/src/plugins/logging/loggingplugin.h index 8b482db16c..6b0ecbdbbd 100644 --- a/ground/gcs/src/plugins/logging/loggingplugin.h +++ b/ground/gcs/src/plugins/logging/loggingplugin.h @@ -50,14 +50,14 @@ class LoggingGadgetFactory; * Plugin will add a instance of this class to the pool, * so the connection manager can use it. */ -class LoggingConnection - : public Core::IConnection { +class LoggingConnection : public Core::IConnection { Q_OBJECT public: - LoggingConnection(LoggingPlugin *loggingPlugin); + LoggingConnection(); virtual ~LoggingConnection(); virtual QList availableDevices(); + virtual QIODevice *openDevice(const QString &deviceName); virtual void closeDevice(const QString &deviceName); @@ -74,15 +74,8 @@ class LoggingConnection } private: - LogFile logFile; - LoggingPlugin *loggingPlugin; - -protected slots: - void onEnumerationChanged(); - void startReplay(QString file); - -protected: bool m_deviceOpened; + LogFile logFile; }; class LoggingThread : public QThread { @@ -103,9 +96,11 @@ public slots: protected: void run(); + QReadWriteLock lock; LogFile logFile; UAVTalk *uavTalk; +private slots: private: QQueue queue; From f4b53b75c1467a36b27f1da2a73c25d187202c06 Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Thu, 11 May 2017 01:09:43 +0200 Subject: [PATCH 255/624] LP-517 gcs: declare uavtalk log file as a sequential device fixes spurious "UAVTalk - error : bad type" errors when replaying a log file --- ground/gcs/src/libs/utils/logfile.cpp | 5 +++++ ground/gcs/src/libs/utils/logfile.h | 3 +++ 2 files changed, 8 insertions(+) diff --git a/ground/gcs/src/libs/utils/logfile.cpp b/ground/gcs/src/libs/utils/logfile.cpp index 3f19dacf63..87ff6500ee 100644 --- a/ground/gcs/src/libs/utils/logfile.cpp +++ b/ground/gcs/src/libs/utils/logfile.cpp @@ -38,6 +38,11 @@ LogFile::LogFile(QObject *parent) : m_useProvidedTimeStamp(false) { connect(&m_timer, SIGNAL(timeout()), this, SLOT(timerFired())); + +bool LogFile::isSequential() const +{ + // returning true fixes "UAVTalk - error : bad type" errors when replaying a log file + return true; } /** diff --git a/ground/gcs/src/libs/utils/logfile.h b/ground/gcs/src/libs/utils/logfile.h index 19e9d35905..dad9286218 100644 --- a/ground/gcs/src/libs/utils/logfile.h +++ b/ground/gcs/src/libs/utils/logfile.h @@ -39,6 +39,9 @@ class QTCREATOR_UTILS_EXPORT LogFile : public QIODevice { Q_OBJECT public: explicit LogFile(QObject *parent = 0); + + bool isSequential() const; + qint64 bytesAvailable() const; qint64 bytesToWrite() const { From 5220cb0d6ff73e768b9d174efb0410e5f2baa6e9 Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Thu, 11 May 2017 01:56:30 +0200 Subject: [PATCH 256/624] LP-517 gcs: make uavtalk log file more robust and thread safe --- ground/gcs/src/libs/utils/logfile.cpp | 97 ++++++++++++++++++--------- ground/gcs/src/libs/utils/logfile.h | 34 ++++++---- 2 files changed, 86 insertions(+), 45 deletions(-) diff --git a/ground/gcs/src/libs/utils/logfile.cpp b/ground/gcs/src/libs/utils/logfile.cpp index 87ff6500ee..3706319c7a 100644 --- a/ground/gcs/src/libs/utils/logfile.cpp +++ b/ground/gcs/src/libs/utils/logfile.cpp @@ -27,17 +27,18 @@ #include #include -LogFile::LogFile(QObject *parent) : - QIODevice(parent), +LogFile::LogFile(QObject *parent) : QIODevice(parent), m_timer(this), - m_lastTimeStamp(0), + m_previousTimeStamp(0), + m_nextTimeStamp(0), m_lastPlayed(0), m_timeOffset(0), m_playbackSpeed(1.0), - m_nextTimeStamp(0), - m_useProvidedTimeStamp(false) + m_useProvidedTimeStamp(false), + m_providedTimeStamp(0) { - connect(&m_timer, SIGNAL(timeout()), this, SLOT(timerFired())); + connect(&m_timer, &QTimer::timeout, this, &LogFile::timerFired); +} bool LogFile::isSequential() const { @@ -64,7 +65,7 @@ bool LogFile::open(OpenMode mode) qDebug() << "LogFile - open" << fileName(); if (m_file.open(mode) == false) { - qDebug() << "Unable to open " << m_file.fileName() << " for logging"; + qWarning() << "Unable to open " << m_file.fileName() << " for logging"; return false; } @@ -93,9 +94,9 @@ qint64 LogFile::writeData(const char *data, qint64 dataSize) return dataSize; } - // If m_nextTimeStamp != -1 then use this timestamp instead of the timer + // If needed, use provided timestamp instead of the GCS timer // This is used when saving logs from on-board logging - quint32 timeStamp = m_useProvidedTimeStamp ? m_nextTimeStamp : m_myTime.elapsed(); + quint32 timeStamp = m_useProvidedTimeStamp ? m_providedTimeStamp : m_myTime.elapsed(); m_file.write((char *)&timeStamp, sizeof(timeStamp)); m_file.write((char *)&dataSize, sizeof(dataSize)); @@ -112,67 +113,83 @@ qint64 LogFile::writeData(const char *data, qint64 dataSize) return dataSize; } -qint64 LogFile::readData(char *data, qint64 maxSize) +qint64 LogFile::readData(char *data, qint64 maxlen) { QMutexLocker locker(&m_mutex); - qint64 toRead = qMin(maxSize, (qint64)m_dataBuffer.size()); - memcpy(data, m_dataBuffer.data(), toRead); - m_dataBuffer.remove(0, toRead); - return toRead; + qint64 len = qMin(maxlen, (qint64)m_dataBuffer.size()); + + if (len) { + memcpy(data, m_dataBuffer.data(), len); + m_dataBuffer.remove(0, len); + } + + return len; } qint64 LogFile::bytesAvailable() const { - return m_dataBuffer.size(); + QMutexLocker locker(&m_mutex); + + qint64 len = m_dataBuffer.size(); + + return len; } void LogFile::timerFired() { - qint64 dataSize; - if (m_file.bytesAvailable() > 4) { int time; time = m_myTime.elapsed(); // TODO: going back in time will be a problem - while ((m_lastPlayed + ((double)(time - m_timeOffset) * m_playbackSpeed) > m_lastTimeStamp)) { + while ((m_lastPlayed + ((double)(time - m_timeOffset) * m_playbackSpeed) > m_nextTimeStamp)) { m_lastPlayed += ((double)(time - m_timeOffset) * m_playbackSpeed); + + // read data size + qint64 dataSize; if (m_file.bytesAvailable() < (qint64)sizeof(dataSize)) { + qDebug() << "LogFile - end of log file reached"; stopReplay(); return; } - m_file.read((char *)&dataSize, sizeof(dataSize)); + // check size consistency if (dataSize < 1 || dataSize > (1024 * 1024)) { - qDebug() << "Error: Logfile corrupted! Unlikely packet size: " << dataSize << "\n"; + qWarning() << "LogFile - corrupted log file! Unlikely packet size:" << dataSize; stopReplay(); return; } + // read data if (m_file.bytesAvailable() < dataSize) { + qDebug() << "LogFile - end of log file reached"; stopReplay(); return; } + QByteArray data = m_file.read(dataSize); + // make data available m_mutex.lock(); - m_dataBuffer.append(m_file.read(dataSize)); + m_dataBuffer.append(data); m_mutex.unlock(); emit readyRead(); - if (m_file.bytesAvailable() < (qint64)sizeof(m_lastTimeStamp)) { + // read next timestamp + if (m_file.bytesAvailable() < (qint64)sizeof(m_nextTimeStamp)) { + qDebug() << "LogFile - end of log file reached"; stopReplay(); return; } + m_previousTimeStamp = m_nextTimeStamp; + m_file.read((char *)&m_nextTimeStamp, sizeof(m_nextTimeStamp)); - int save = m_lastTimeStamp; - m_file.read((char *)&m_lastTimeStamp, sizeof(m_lastTimeStamp)); // some validity checks - if (m_lastTimeStamp < save // logfile goes back in time - || (m_lastTimeStamp - save) > (60 * 60 * 1000)) { // gap of more than 60 minutes) - qDebug() << "Error: Logfile corrupted! Unlikely timestamp " << m_lastTimeStamp << " after " << save << "\n"; + if ((m_nextTimeStamp < m_previousTimeStamp) // logfile goes back in time + || ((m_nextTimeStamp - m_previousTimeStamp) > 60 * 60 * 1000)) { // gap of more than 60 minutes + qWarning() << "LogFile - corrupted log file! Unlikely timestamp:" << m_nextTimeStamp << "after" << m_previousTimeStamp; stopReplay(); return; } @@ -181,26 +198,44 @@ void LogFile::timerFired() time = m_myTime.elapsed(); } } else { + qDebug() << "LogFile - end of log file reached"; stopReplay(); } } bool LogFile::startReplay() { + if (!m_file.isOpen() || m_timer.isActive()) { + return false; + } qDebug() << "LogFile - startReplay"; - m_dataBuffer.clear(); + m_myTime.restart(); - m_timeOffset = 0; - m_lastPlayed = 0; - m_file.read((char *)&m_lastTimeStamp, sizeof(m_lastTimeStamp)); + m_timeOffset = 0; + m_lastPlayed = 0; + m_previousTimeStamp = 0; + m_nextTimeStamp = 0; + m_dataBuffer.clear(); + + // read next timestamp + if (m_file.bytesAvailable() < (qint64)sizeof(m_nextTimeStamp)) { + qWarning() << "LogFile - invalid log file!"; + return false; + } + m_file.read((char *)&m_nextTimeStamp, sizeof(m_nextTimeStamp)); + m_timer.setInterval(10); m_timer.start(); + emit replayStarted(); return true; } bool LogFile::stopReplay() { + if (!m_file.isOpen() || !m_timer.isActive()) { + return false; + } qDebug() << "LogFile - stopReplay"; m_timer.stop(); diff --git a/ground/gcs/src/libs/utils/logfile.h b/ground/gcs/src/libs/utils/logfile.h index dad9286218..396ed95e8c 100644 --- a/ground/gcs/src/libs/utils/logfile.h +++ b/ground/gcs/src/libs/utils/logfile.h @@ -40,15 +40,7 @@ class QTCREATOR_UTILS_EXPORT LogFile : public QIODevice { public: explicit LogFile(QObject *parent = 0); - bool isSequential() const; - - qint64 bytesAvailable() const; - qint64 bytesToWrite() const - { - return m_file.bytesToWrite(); - }; - bool open(OpenMode mode); - QString fileName() + QString fileName() const { return m_file.fileName(); }; @@ -56,7 +48,18 @@ class QTCREATOR_UTILS_EXPORT LogFile : public QIODevice { { m_file.setFileName(name); }; + + bool isSequential() const; + + bool open(OpenMode mode); void close(); + + qint64 bytesAvailable() const; + qint64 bytesToWrite() const + { + return m_file.bytesToWrite(); + }; + qint64 writeData(const char *data, qint64 dataSize); qint64 readData(char *data, qint64 maxlen); @@ -65,9 +68,9 @@ class QTCREATOR_UTILS_EXPORT LogFile : public QIODevice { m_useProvidedTimeStamp = useProvidedTimeStamp; } - void setNextTimeStamp(quint32 nextTimestamp) + void setNextTimeStamp(quint32 providedTimestamp) { - m_nextTimeStamp = nextTimestamp; + m_providedTimeStamp = providedTimestamp; } public slots: @@ -94,16 +97,19 @@ protected slots: QTimer m_timer; QTime m_myTime; QFile m_file; - qint32 m_lastTimeStamp; + qint32 m_previousTimeStamp; + qint32 m_nextTimeStamp; double m_lastPlayed; - QMutex m_mutex; + // QMutex wants to be mutable + // http://stackoverflow.com/questions/25521570/can-mutex-locking-function-be-marked-as-const + mutable QMutex m_mutex; int m_timeOffset; double m_playbackSpeed; private: - quint32 m_nextTimeStamp; bool m_useProvidedTimeStamp; + qint32 m_providedTimeStamp; }; #endif // LOGFILE_H From 3b8bfabf2860eff4f37ae813cbf0082a9a530721 Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Thu, 11 May 2017 02:53:30 +0200 Subject: [PATCH 257/624] LP-517 gcs: fix uavtalk logging UI state handling fix issues affecting the UI fix LP-271 : it was not possible to log after a replay remove the possibility to log while replaying more translation aware --- ground/gcs/src/libs/utils/logfile.cpp | 32 +++++- ground/gcs/src/libs/utils/logfile.h | 7 +- ground/gcs/src/plugins/logging/logging.ui | 39 ++++++-- .../plugins/logging/logginggadgetwidget.cpp | 52 +++++++--- .../src/plugins/logging/logginggadgetwidget.h | 9 +- .../gcs/src/plugins/logging/loggingplugin.cpp | 97 +++++++++++-------- .../gcs/src/plugins/logging/loggingplugin.h | 52 +++++----- 7 files changed, 183 insertions(+), 105 deletions(-) diff --git a/ground/gcs/src/libs/utils/logfile.cpp b/ground/gcs/src/libs/utils/logfile.cpp index 3706319c7a..95b400d688 100644 --- a/ground/gcs/src/libs/utils/logfile.cpp +++ b/ground/gcs/src/libs/utils/logfile.cpp @@ -34,6 +34,7 @@ LogFile::LogFile(QObject *parent) : QIODevice(parent), m_lastPlayed(0), m_timeOffset(0), m_playbackSpeed(1.0), + paused(false), m_useProvidedTimeStamp(false), m_providedTimeStamp(0) { @@ -203,6 +204,11 @@ void LogFile::timerFired() } } +bool LogFile::isPlaying() const +{ + return m_file.isOpen() && m_timer.isActive(); +} + bool LogFile::startReplay() { if (!m_file.isOpen() || m_timer.isActive()) { @@ -226,6 +232,7 @@ bool LogFile::startReplay() m_timer.setInterval(10); m_timer.start(); + paused = false; emit replayStarted(); return true; @@ -233,23 +240,42 @@ bool LogFile::startReplay() bool LogFile::stopReplay() { - if (!m_file.isOpen() || !m_timer.isActive()) { + if (!m_file.isOpen() || !(m_timer.isActive() || paused)) { return false; } qDebug() << "LogFile - stopReplay"; m_timer.stop(); + paused = false; emit replayFinished(); return true; } -void LogFile::pauseReplay() +bool LogFile::pauseReplay() { + if (!m_timer.isActive()) { + return false; + } + qDebug() << "LogFile - pauseReplay"; m_timer.stop(); + paused = true; + + // hack to notify UI that replay paused + emit replayStarted(); + return true; } -void LogFile::resumeReplay() +bool LogFile::resumeReplay() { + if (m_timer.isActive()) { + return false; + } + qDebug() << "LogFile - resumeReplay"; m_timeOffset = m_myTime.elapsed(); m_timer.start(); + paused = false; + + // hack to notify UI that replay resumed + emit replayStarted(); + return true; } diff --git a/ground/gcs/src/libs/utils/logfile.h b/ground/gcs/src/libs/utils/logfile.h index 396ed95e8c..3c3616e208 100644 --- a/ground/gcs/src/libs/utils/logfile.h +++ b/ground/gcs/src/libs/utils/logfile.h @@ -51,6 +51,8 @@ class QTCREATOR_UTILS_EXPORT LogFile : public QIODevice { bool isSequential() const; + bool isPlaying() const; + bool open(OpenMode mode); void close(); @@ -81,8 +83,8 @@ public slots: }; bool startReplay(); bool stopReplay(); - void pauseReplay(); - void resumeReplay(); + bool pauseReplay(); + bool resumeReplay(); protected slots: void timerFired(); @@ -106,6 +108,7 @@ protected slots: int m_timeOffset; double m_playbackSpeed; + bool paused; private: bool m_useProvidedTimeStamp; diff --git a/ground/gcs/src/plugins/logging/logging.ui b/ground/gcs/src/plugins/logging/logging.ui index b5fa5b1107..05bad61aab 100644 --- a/ground/gcs/src/plugins/logging/logging.ui +++ b/ground/gcs/src/plugins/logging/logging.ui @@ -6,7 +6,7 @@ 0 0 - 536 + 439 122 @@ -29,15 +29,15 @@ - + QLayout::SetNoConstraint - + - - 30 + + 0 0 @@ -57,10 +57,10 @@ - + - - 30 + + 0 0 @@ -71,7 +71,7 @@ - Pause + Pause @@ -79,6 +79,19 @@ + + + + Qt::Horizontal + + + + 40 + 20 + + + + @@ -88,8 +101,14 @@ + + + 75 + true + + - Idle + <Status> diff --git a/ground/gcs/src/plugins/logging/logginggadgetwidget.cpp b/ground/gcs/src/plugins/logging/logginggadgetwidget.cpp index 9c18386821..659a65b305 100644 --- a/ground/gcs/src/plugins/logging/logginggadgetwidget.cpp +++ b/ground/gcs/src/plugins/logging/logginggadgetwidget.cpp @@ -25,17 +25,15 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "logginggadgetwidget.h" + #include "ui_logging.h" -#include -#include +#include + #include -#include -#include #include -#include -LoggingGadgetWidget::LoggingGadgetWidget(QWidget *parent) : QLabel(parent) +LoggingGadgetWidget::LoggingGadgetWidget(QWidget *parent) : QWidget(parent), loggingPlugin(NULL) { m_logging = new Ui_Logging(); m_logging->setupUi(this); @@ -52,20 +50,42 @@ LoggingGadgetWidget::~LoggingGadgetWidget() void LoggingGadgetWidget::setPlugin(LoggingPlugin *p) { loggingPlugin = p; - connect(p, SIGNAL(stateChanged(QString)), this, SLOT(stateChanged(QString))); - connect(m_logging->playButton, SIGNAL(clicked()), p->getLogfile(), SLOT(resumeReplay())); - connect(m_logging->playButton, SIGNAL(clicked()), scpPlugin, SLOT(startPlotting())); - connect(m_logging->pauseButton, SIGNAL(clicked()), p->getLogfile(), SLOT(pauseReplay())); - connect(m_logging->pauseButton, SIGNAL(clicked()), scpPlugin, SLOT(stopPlotting())); - connect(m_logging->playbackSpeed, SIGNAL(valueChanged(double)), p->getLogfile(), SLOT(setReplaySpeed(double))); - void pauseReplay(); - void resumeReplay(); -} + connect(m_logging->playButton, &QPushButton::clicked, scpPlugin, &ScopeGadgetFactory::startPlotting); + connect(m_logging->pauseButton, &QPushButton::clicked, scpPlugin, &ScopeGadgetFactory::stopPlotting); + + LogFile *logFile = loggingPlugin->getLogfile(); + connect(m_logging->playButton, &QPushButton::clicked, logFile, &LogFile::resumeReplay); + connect(m_logging->pauseButton, &QPushButton::clicked, logFile, &LogFile::pauseReplay); + connect(m_logging->playbackSpeed, static_cast(&QDoubleSpinBox::valueChanged), logFile, &LogFile::setReplaySpeed); -void LoggingGadgetWidget::stateChanged(QString status) + connect(loggingPlugin, &LoggingPlugin::stateChanged, this, &LoggingGadgetWidget::stateChanged); + + stateChanged(loggingPlugin->getState()); +} + +void LoggingGadgetWidget::stateChanged(LoggingPlugin::State state) { + QString status; + bool enabled = false; + + switch (state) { + case LoggingPlugin::IDLE: + status = tr("Idle"); + break; + case LoggingPlugin::LOGGING: + status = tr("Logging"); + break; + case LoggingPlugin::REPLAY: + status = tr("Replaying"); + enabled = true; + break; + } m_logging->statusLabel->setText(status); + + bool playing = loggingPlugin->getLogfile()->isPlaying(); + m_logging->playButton->setEnabled(enabled && !playing); + m_logging->pauseButton->setEnabled(enabled && playing); } /** diff --git a/ground/gcs/src/plugins/logging/logginggadgetwidget.h b/ground/gcs/src/plugins/logging/logginggadgetwidget.h index 05e7605056..60b268e218 100644 --- a/ground/gcs/src/plugins/logging/logginggadgetwidget.h +++ b/ground/gcs/src/plugins/logging/logginggadgetwidget.h @@ -28,16 +28,17 @@ #ifndef LoggingGADGETWIDGET_H_ #define LoggingGADGETWIDGET_H_ -#include +#include "loggingplugin.h" + #include "extensionsystem/pluginmanager.h" #include "scope/scopeplugin.h" #include "scope/scopegadgetfactory.h" +#include class Ui_Logging; -class LoggingPlugin; -class LoggingGadgetWidget : public QLabel { +class LoggingGadgetWidget : public QWidget { Q_OBJECT public: @@ -46,7 +47,7 @@ class LoggingGadgetWidget : public QLabel { void setPlugin(LoggingPlugin *p); protected slots: - void stateChanged(QString status); + void stateChanged(LoggingPlugin::State state); signals: void pause(); diff --git a/ground/gcs/src/plugins/logging/loggingplugin.cpp b/ground/gcs/src/plugins/logging/loggingplugin.cpp index cc7e7cccc3..3d7580e56d 100644 --- a/ground/gcs/src/plugins/logging/loggingplugin.cpp +++ b/ground/gcs/src/plugins/logging/loggingplugin.cpp @@ -29,7 +29,14 @@ */ #include "loggingplugin.h" + +#include "gcstelemetrystats.h" + #include "logginggadgetfactory.h" +#include "uavobjectmanager.h" +#include +#include +#include #include #include @@ -41,11 +48,7 @@ #include #include #include - -#include #include -#include "uavobjectmanager.h" - LoggingConnection::LoggingConnection() : m_deviceOpened(false), logFile() @@ -159,7 +162,6 @@ void LoggingThread::objectUpdated(UAVObject *obj) void LoggingThread::run() { - qDebug() << "LoggingThread - run"; startLogging(); } @@ -170,6 +172,7 @@ void LoggingThread::run() void LoggingThread::startLogging() { qDebug() << "LoggingThread - start logging"; + ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); UAVObjectManager *objManager = pm->getObject(); @@ -181,7 +184,7 @@ void LoggingThread::startLogging() for (i = list.constBegin(); i != list.constEnd(); ++i) { for (j = (*i).constBegin(); j != (*i).constEnd(); ++j) { - connect(*j, SIGNAL(objectUpdated(UAVObject *)), (LoggingThread *)this, SLOT(objectUpdated(UAVObject *))); + connect(*j, &UAVObject::objectUpdated, this, &LoggingThread::objectUpdated); objects++; } } @@ -199,13 +202,15 @@ void LoggingThread::startLogging() } /** - * Pass this command to the correct thread then close the file + * Disconnect signals from all the objects, close the log file and stop + * the event loop */ void LoggingThread::stopLogging() { - qDebug() << "LoggingThread - stop logging"; QWriteLocker locker(&lock); + qDebug() << "LoggingThread - stop logging"; + // Disconnect all objects we registered with: ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); UAVObjectManager *objManager = pm->getObject(); @@ -217,7 +222,7 @@ void LoggingThread::stopLogging() for (i = list.constBegin(); i != list.constEnd(); ++i) { for (j = (*i).constBegin(); j != (*i).constEnd(); ++j) { - disconnect(*j, SIGNAL(objectUpdated(UAVObject *)), (LoggingThread *)this, SLOT(objectUpdated(UAVObject *))); + disconnect(*j, &UAVObject::objectUpdated, this, &LoggingThread::objectUpdated); } } @@ -248,8 +253,7 @@ void LoggingThread::retrieveSettings() } } // Start retrieving - qDebug() << QString("LoggingThread - retrieve settings objects from the autopilot (%1 objects)") - .arg(queue.length()); + qDebug() << "LoggingThread - retrieving" << queue.length() << "objects"; retrieveNextObject(); } @@ -266,7 +270,7 @@ void LoggingThread::retrieveNextObject() // Get next object from the queue UAVObject *obj = queue.dequeue(); // Connect to object - connect(obj, SIGNAL(transactionCompleted(UAVObject *, bool)), this, SLOT(transactionCompleted(UAVObject *, bool))); + connect(obj, &UAVObject::transactionCompleted, this, &LoggingThread::transactionCompleted); // Request update obj->requestUpdate(); } @@ -294,11 +298,10 @@ void LoggingThread::transactionCompleted(UAVObject *obj, bool success) } LoggingPlugin::LoggingPlugin() : + loggingCommand(NULL), state(IDLE), loggingThread(NULL), - logConnection(new LoggingConnection()), - mf(NULL), - cmd(NULL) + logConnection(new LoggingConnection()) {} LoggingPlugin::~LoggingPlugin() @@ -319,26 +322,28 @@ bool LoggingPlugin::initialize(const QStringList & args, QString *errMsg) Core::ActionManager *am = Core::ICore::instance()->actionManager(); Core::ActionContainer *ac = am->actionContainer(Core::Constants::M_TOOLS); - // Command to start logging - cmd = am->registerAction(new QAction(this), - "LoggingPlugin.Logging", - QList() << - Core::Constants::C_GLOBAL_ID); - cmd->setDefaultKeySequence(QKeySequence("Ctrl+L")); - cmd->action()->setText(tr("Start logging...")); + // Command to start/stop logging + loggingCommand = am->registerAction(new QAction(this), + "LoggingPlugin.Logging", + QList() << + Core::Constants::C_GLOBAL_ID); + loggingCommand->setDefaultKeySequence(QKeySequence("Ctrl+L")); ac->menu()->addSeparator(); ac->appendGroup("Logging"); - ac->addAction(cmd, "Logging"); + ac->addAction(loggingCommand, "Logging"); - connect(cmd->action(), SIGNAL(triggered(bool)), this, SLOT(toggleLogging())); + connect(loggingCommand->action(), &QAction::triggered, this, &LoggingPlugin::toggleLogging); - mf = new LoggingGadgetFactory(this); + LoggingGadgetFactory *mf = new LoggingGadgetFactory(this); addAutoReleasedObject(mf); // Map signal from end of replay to replay stopped - connect(getLogfile(), SIGNAL(replayFinished()), this, SLOT(replayStopped())); - connect(getLogfile(), SIGNAL(replayStarted()), this, SLOT(replayStarted())); + connect(getLogfile(), &LogFile::replayFinished, this, &LoggingPlugin::replayStopped); + connect(getLogfile(), &LogFile::replayStarted, this, &LoggingPlugin::replayStarted); + + // update state and command + loggingStopped(); return true; } @@ -369,7 +374,6 @@ void LoggingPlugin::toggleLogging() */ void LoggingPlugin::startLogging(QString file) { - qDebug() << "LoggingPlugin - start logging to " << file; // needed ? stopLogging(); // Start logging thread @@ -396,7 +400,6 @@ void LoggingPlugin::stopLogging() return; } - qDebug() << "LoggingPlugin - stop logging"; loggingThread->stopLogging(); delete loggingThread; @@ -405,9 +408,11 @@ void LoggingPlugin::stopLogging() void LoggingPlugin::loggingStarted() { - state = LOGGING; - cmd->action()->setText(tr("Stop logging")); - emit stateChanged("LOGGING"); + loggingCommand->action()->setText(tr("Stop logging")); + if (state == IDLE) { + state = LOGGING; + emit stateChanged(state); + } } /** @@ -416,32 +421,38 @@ void LoggingPlugin::loggingStarted() */ void LoggingPlugin::loggingStopped() { + loggingCommand->action()->setText(tr("Start logging...")); if (state == LOGGING) { state = IDLE; - cmd->action()->setText(tr("Start logging...")); - emit stateChanged("IDLE"); + emit stateChanged(state); } } /** - * Received the replay stopped signal from the LogFile + * Received the replay started signal from the LogFile */ -void LoggingPlugin::replayStopped() +void LoggingPlugin::replayStarted() { - state = IDLE; - emit stateChanged("IDLE"); + if (state == LOGGING) { + stopLogging(); + } + loggingCommand->action()->setEnabled(false); + state = REPLAY; + emit stateChanged(state); } /** - * Received the replay started signal from the LogFile + * Received the replay stopped signal from the LogFile */ -void LoggingPlugin::replayStarted() +void LoggingPlugin::replayStopped() { - state = REPLAY; - emit stateChanged("REPLAY"); + loggingCommand->action()->setEnabled(true); + if (state == REPLAY) { + state = IDLE; + emit stateChanged(state); + } } - void LoggingPlugin::extensionsInitialized() { addAutoReleasedObject(logConnection); diff --git a/ground/gcs/src/plugins/logging/loggingplugin.h b/ground/gcs/src/plugins/logging/loggingplugin.h index 6b0ecbdbbd..7a1925ad08 100644 --- a/ground/gcs/src/plugins/logging/loggingplugin.h +++ b/ground/gcs/src/plugins/logging/loggingplugin.h @@ -30,21 +30,24 @@ #include #include -#include #include #include -#include "uavobjectmanager.h" -#include "gcstelemetrystats.h" -#include #include #include #include #include +class UAVObject; +class UAVDataObject; +class UAVTalk; class LoggingPlugin; class LoggingGadgetFactory; +namespace Core { +class Command; +} + /** * Define a connection via the IConnection interface * Plugin will add a instance of this class to the pool, @@ -86,10 +89,6 @@ class LoggingThread : public QThread { bool openFile(QString file); -private slots: - void objectUpdated(UAVObject *obj); - void transactionCompleted(UAVObject *obj, bool success); - public slots: void startLogging(); void stopLogging(); @@ -97,13 +96,15 @@ public slots: protected: void run(); - QReadWriteLock lock; - LogFile logFile; - UAVTalk *uavTalk; private slots: + void objectUpdated(UAVObject *obj); + void transactionCompleted(UAVObject *obj, bool success); private: + QReadWriteLock lock; QQueue queue; + LogFile logFile; + UAVTalk *uavTalk; void retrieveSettings(); void retrieveNextObject(); @@ -116,6 +117,8 @@ class LoggingPlugin : public ExtensionSystem::IPlugin { friend class LoggingConnection; public: + enum State { IDLE, LOGGING, REPLAY }; + LoggingPlugin(); ~LoggingPlugin(); @@ -123,26 +126,18 @@ class LoggingPlugin : public ExtensionSystem::IPlugin { bool initialize(const QStringList & arguments, QString *errorString); void shutdown(); - LoggingConnection *getLogConnection() - { - return logConnection; - }; LogFile *getLogfile() { return logConnection->getLogfile(); } - void setLogMenuTitle(QString str); - -signals: - void stateChanged(QString); -protected: - enum { IDLE, LOGGING, REPLAY } state; - - LoggingThread *loggingThread; + State getState() + { + return state; + } - // These are used for replay, logging in its own thread - LoggingConnection *logConnection; +signals: + void stateChanged(State); private slots: void toggleLogging(); @@ -154,8 +149,11 @@ private slots: void replayStopped(); private: - LoggingGadgetFactory *mf; - Core::Command *cmd; + Core::Command *loggingCommand; + State state; + // These are used for replay, logging in its own thread + LoggingThread *loggingThread; + LoggingConnection *logConnection; }; #endif /* LoggingPLUGIN_H_ */ /** From 0f8f560b36b9aa9048878ebebe7dd6ec94cfa744 Mon Sep 17 00:00:00 2001 From: Laurent Lalanne Date: Mon, 15 May 2017 21:31:53 +0200 Subject: [PATCH 258/624] LP-505 Oplm Gui: Add missing image --- .../src/plugins/coreplugin/images/clear_left.png | Bin 0 -> 388 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 ground/gcs/src/plugins/coreplugin/images/clear_left.png diff --git a/ground/gcs/src/plugins/coreplugin/images/clear_left.png b/ground/gcs/src/plugins/coreplugin/images/clear_left.png new file mode 100644 index 0000000000000000000000000000000000000000..ea11a3e4d270c13c32e6e90c59d1a897605b5def GIT binary patch literal 388 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmSN`?>!lvI6;RN#5=* z4F5rJ!QSPQfg+swZf?au8Uz>_4jZ=j0~wqJ9+5ynZb1-ctWSxb2oz*5@$_|Nzr@HW zpvxQLdK8qXij)R^#MrO!b@ zCG%>=S)Rg5*9-*%r|3r}x&1#|BmHCXlO^@LPwYQ3YkfnU&2|%}{r!(Q4s6S1NQwOR zW$ts!(pcsREd}?#pZVNl*tRXV@Z83A+UG29Z96J)*nsEbjcZX`uVq~?tqNIlZ@t3r zXUj6@soBZ#PfPu|ZRIMhu0;v6)Eag(L`_S5WBBpj;#KimJ2q7B{m$?`Bvi2T|5@cd z*B6=#3Uc-;*0ea~f6DCOvpkfpdAT_-B($C>X|IaG95u^elj(7Dl$7%K-}{y_`89ZJ6T-G@yGywn+!j=U9 literal 0 HcmV?d00001 From ff2504c61ff29b7de0957f12c7abe4c62b5f26e5 Mon Sep 17 00:00:00 2001 From: Brian Webb Date: Wed, 17 May 2017 19:00:58 -0700 Subject: [PATCH 259/624] Adds a port of the Tau Labs/dRonin FrSKY Sensor Hub module. --- .../UAVOFrSKYSensorHubBridge.c | 761 ++++++++++++++++++ flight/pios/common/pios_board_io.c | 42 +- flight/pios/inc/pios_board_io.h | 23 +- .../boards/discoveryf4bare/firmware/Makefile | 1 + .../firmware/inc/pios_config.h | 1 + .../discoveryf4bare/firmware/pios_board.c | 51 +- .../boards/revolution/firmware/Makefile | 1 + .../revolution/firmware/inc/pios_config.h | 1 + .../boards/revolution/firmware/pios_board.c | 51 +- .../targets/boards/revonano/firmware/Makefile | 1 + .../revonano/firmware/inc/pios_config.h | 1 + .../boards/revonano/firmware/pios_board.c | 33 +- .../targets/boards/sparky2/firmware/Makefile | 1 + .../boards/sparky2/firmware/inc/pios_config.h | 1 + .../boards/sparky2/firmware/pios_board.c | 18 +- shared/uavobjectdefinition/hwsettings.xml | 20 +- shared/uavobjectdefinition/taskinfo.xml | 13 +- 17 files changed, 910 insertions(+), 110 deletions(-) create mode 100644 flight/modules/UAVOFrSKYSensorHubBridge/UAVOFrSKYSensorHubBridge.c diff --git a/flight/modules/UAVOFrSKYSensorHubBridge/UAVOFrSKYSensorHubBridge.c b/flight/modules/UAVOFrSKYSensorHubBridge/UAVOFrSKYSensorHubBridge.c new file mode 100644 index 0000000000..cc6385734b --- /dev/null +++ b/flight/modules/UAVOFrSKYSensorHubBridge/UAVOFrSKYSensorHubBridge.c @@ -0,0 +1,761 @@ +/** + ****************************************************************************** + * @addtogroup LibrePilotModules LibrePilot Modules + * @{ + * @addtogroup UAVOFrSKYSensorHubBridge UAVO to FrSKY Bridge Module + * @{ + * + * @file UAVOFrSKYSensorHubBridge.c + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017. + * dRonin, http://dRonin.org/, Copyright (C) 2016 + * Tau Labs, http://taulabs.org, Copyright (C) 2014 + * @brief Bridges selected UAVObjects to FrSKY Sensor Hub + * @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, see + * + * Additional note on redistribution: The copyright and license notices above + * must be maintained in each individual source file that is a derivative work + * of this source file; otherwise redistribution is prohibited. + */ + +// **************** +#include "pios.h" +#include "pios_board_io.h" +#include "openpilot.h" +#include "flightbatterysettings.h" +#include "flightbatterystate.h" +#include "homelocation.h" +#include "flightstatus.h" +#include "pios_thread.h" +#include "barosensor.h" +#include "accelsensor.h" +#include "gpspositionsensor.h" +#include "taskinfo.h" + +// **************** +// Private functions + +static void uavoFrSKYSensorHubBridgeTask(void *parameters); + +static uint16_t frsky_pack_altitude( + float altitude, + uint8_t *serial_buf); + +static uint16_t frsky_pack_temperature_01( + float temperature_01, + uint8_t *serial_buf); + +static uint16_t frsky_pack_temperature_02( + float temperature_02, + uint8_t *serial_buf); + +static uint16_t frsky_pack_accel( + float accels_x, + float accels_y, + float accels_z, + uint8_t *serial_buf); + +static uint16_t frsky_pack_cellvoltage( + uint8_t cell, + float cell_voltage, + uint8_t *serial_buf); + +static uint16_t frsky_pack_fas( + float voltage, + float current, + uint8_t *serial_buf); + +static uint16_t frsky_pack_rpm( + uint16_t rpm, + uint8_t *serial_buf); + +static uint16_t frsky_pack_gps( + float course, + int32_t latitude, + int32_t longitude, + float altitude, + float speed, + uint8_t *serial_buf); + +static uint16_t frsky_pack_fuel( + float fuel_level, + uint8_t *serial_buf); + +static uint16_t frsky_pack_stop( + uint8_t *serial_buf); + +static int16_t frsky_acceleration_unit(float accel); + +static void frsky_serialize_value(uint8_t valueid, + uint8_t *value, + uint8_t *serial_buf, + uint8_t *index); + +static void frsky_write_userdata_byte(uint8_t byte, + uint8_t *serial_buf, + uint8_t *index); + +static bool frame_trigger(uint8_t frame_num); +// **************** +// Private constants + + +#if defined(PIOS_FRSKY_SENSOR_HUB_STACK_SIZE) +#define STACK_SIZE_BYTES PIOS_FRSKY_SENSOR_HUB_STACK_SIZE +#else +#define STACK_SIZE_BYTES 672 +#endif + +#define TASK_PRIORITY (tskIDLE_PRIORITY) +#define TASK_RATE_HZ 10 + +#define FRSKY_MAX_PACKET_LEN 106 +#define FRSKY_BAUD_RATE 9600 + +#define FRSKY_FRAME_DATA_HEADER 0x5E +#define FRSKY_FRAME_STOP 0x5E + +enum FRSKY_VALUE_ID { + FRSKY_GPS_ALTITUDE_INTEGER = 0x01, + FRSKY_GPS_ALTITUDE_DECIMAL = FRSKY_GPS_ALTITUDE_INTEGER + 8, + FRSKY_TEMPERATURE_1 = 0x02, + FRSKY_RPM = 0x03, + FRSKY_FUEL_LEVEL = 0x04, + FRSKY_TEMPERATURE_2 = 0x05, + FRSKY_VOLTAGE = 0x06, + FRSKY_ALTITUDE_INTEGER = 0x10, + FRSKY_ALTITUDE_DECIMAL = 0x21, + FRSKY_GPS_SPEED_INTEGER = 0x11, + FRSKY_GPS_SPEED_DECIMAL = 0x11 + 8, + FRSKY_GPS_LONGITUDE_INTEGER = 0x12, + FRSKY_GPS_LONGITUDE_DECIMAL = FRSKY_GPS_LONGITUDE_INTEGER + 8, + FRSKY_GPS_E_W = 0x1A + 8, + FRSKY_GPS_LATITUDE_INTEGER = 0x13, + FRSKY_GPS_LATITUDE_DECIMAL = FRSKY_GPS_LATITUDE_INTEGER + 8, + FRSKY_GPS_N_S = 0x1B + 8, + FRSKY_GPS_COURSE_INTEGER = 0x14, + FRSKY_GPS_COURSE_DECIMAL = FRSKY_GPS_COURSE_INTEGER + 8, + FRSKY_DATE_MONTH = 0x15, + FRSKY_DATE_YEAR = 0x16, + FRSKY_HOUR_MINUTE = 0x17, + FRSKY_SECOND = 0x18, + FRSKY_ACCELERATION_X = 0x24, + FRSKY_ACCELERATION_Y = 0x25, + FRSKY_ACCELERATION_Z = 0x26, + FRSKY_VOLTAGE_AMPERE_SENSOR_INTEGER = 0x3A, + FRSKY_VOLTAGE_AMPERE_SENSOR_DECIMAL = 0x3B, + FRSKY_CURRENT = 0x28, +}; + +enum FRSKY_FRAME { + FRSKY_FRAME_VARIO, + FRSKY_FRAME_BATTERY, + FRSKY_FRAME_GPS, +}; + +static const uint8_t frsky_rates[] = { + [FRSKY_FRAME_VARIO] = 5, // 5Hz + [FRSKY_FRAME_BATTERY] = 5, // 5Hz + [FRSKY_FRAME_GPS] = 2, // 1Hz +}; + +#define MAXSTREAMS sizeof(frsky_rates) +#define KNOTS2M_PER_SECOND 0.514444F +#define GRAVITY 9.8F + +// **************** +// Private variables + +static struct { + uint32_t frsky_port; + uint8_t frame_ticks[MAXSTREAMS]; + uint8_t serial_buf[FRSKY_MAX_PACKET_LEN]; +} *shub_global; + +/** + * Start the module + * \return -1 if start failed + * \return 0 on success + */ +static int32_t uavoFrSKYSensorHubBridgeStart(void) +{ + if (shub_global) { + xTaskHandle taskHandle; + xTaskCreate(uavoFrSKYSensorHubBridgeTask, "uavoFrSKYSensorHubBridge", STACK_SIZE_BYTES / 4, NULL, TASK_PRIORITY, &taskHandle); + PIOS_TASK_MONITOR_RegisterTask(TASKINFO_RUNNING_UAVOFRSKYSENSORHUBBRIDGE, taskHandle); + return 0; + } + return -1; +} + +/** + * Initialize the module + * \return -1 if initialization failed + * \return 0 on success + */ +static int32_t uavoFrSKYSensorHubBridgeInitialize(void) +{ + uintptr_t frsky_port = PIOS_COM_FRSKY_SENSORHUB; + + if (frsky_port) { + shub_global = pios_malloc(sizeof(*shub_global)); + + if (shub_global == 0) { + return -1; + } + + PIOS_COM_ChangeBaud(frsky_port, FRSKY_BAUD_RATE); + + shub_global->frsky_port = frsky_port; + + for (uint32_t x = 0; x < MAXSTREAMS; ++x) { + shub_global->frame_ticks[x] = + (TASK_RATE_HZ / frsky_rates[x]); + } + + return 0; + } + + + return -1; +} +MODULE_INITCALL(uavoFrSKYSensorHubBridgeInitialize, uavoFrSKYSensorHubBridgeStart); + +/** + * Main task. It does not return. + */ +static void uavoFrSKYSensorHubBridgeTask(__attribute__((unused)) void *parameters) +{ + uint32_t lastSysTime = PIOS_Thread_Systime(); + + // Main task loop + while (1) { + PIOS_Thread_Sleep_Until(&lastSysTime, 1000 / TASK_RATE_HZ); + + if (frame_trigger(FRSKY_FRAME_VARIO)) { + uint16_t msg_length = 0; + + // Get the accelerometer values + float accX = 0, accY = 0, accZ = 0; + if (AccelSensorHandle() != NULL) { + AccelSensorxGet(&accX); + AccelSensoryGet(&accY); + AccelSensorzGet(&accZ); + } + msg_length += frsky_pack_accel( + accX, + accY, + accZ, + shub_global->serial_buf + msg_length); + + // Get the altritude from the barometer. + float altitude; + if (BaroSensorHandle() != NULL) { + BaroSensorAltitudeGet(&altitude); + } + msg_length += frsky_pack_altitude( + altitude, + shub_global->serial_buf + msg_length); + msg_length += frsky_pack_stop(shub_global->serial_buf + msg_length); + + PIOS_COM_SendBuffer(shub_global->frsky_port, + shub_global->serial_buf, msg_length); + } + + if (frame_trigger(FRSKY_FRAME_BATTERY)) { + uint16_t msg_length = 0; + + FlightBatteryStateData batState; + if (FlightBatteryStateHandle() != NULL) { + FlightBatteryStateGet(&batState); + } + + float voltage = voltage = batState.Voltage; + + float current = current = batState.Current; + + // As long as there is no voltage for each cell + // all cells will have the same voltage. + // Receiver will know number of cells. + FlightBatterySettingsData batSettings; + if (FlightBatterySettingsHandle() != NULL) { + FlightBatterySettingsGet(&batSettings); + } + if (batState.NbCellsAutodetected == FLIGHTBATTERYSTATE_NBCELLSAUTODETECTED_TRUE) { + batSettings.NbCells = batState.NbCells; + } + + if (batSettings.NbCells > 0) { + float cell_v = voltage / batSettings.NbCells; + for (uint8_t i = 0; i < batSettings.NbCells; ++i) { + msg_length += frsky_pack_cellvoltage( + i, + cell_v, + shub_global->serial_buf + msg_length); + } + } + + msg_length += frsky_pack_fas( + voltage, + current, + shub_global->serial_buf + msg_length); + + if (batSettings.Capacity > 0) { + float fuel = 1.0f - batState.ConsumedEnergy / batSettings.Capacity; + msg_length += frsky_pack_fuel( + fuel, + shub_global->serial_buf + msg_length); + } + + msg_length += frsky_pack_stop(shub_global->serial_buf + msg_length); + + PIOS_COM_SendBuffer(shub_global->frsky_port, + shub_global->serial_buf, msg_length); + } + + if (frame_trigger(FRSKY_FRAME_GPS)) { + uint16_t msg_length = 0; + + /** + * Encodes ARM status and flight mode number as RPM value + * Since there is no RPM information in any UAVO available, + * we will intentionally misuse this item to encode other useful information. + * It will encode flight status as three-digit number as follow: + * most left digit encodes arm status (200=armed, 100=disarmed) + * two most right digits encode flight mode number (see FlightStatus UAVO FlightMode enum) + * To work properly on Taranis, you have to set Blades to "60" in telemetry setting + */ + FlightStatusData flight_status; + FlightStatusGet(&flight_status); + + uint16_t status = 0; + float hdop, vdop; + + status = (flight_status.Armed == FLIGHTSTATUS_ARMED_ARMED) ? 200 : 100; + status += flight_status.FlightMode; + + msg_length += frsky_pack_rpm(status, shub_global->serial_buf + msg_length); + + uint8_t hl_set = HOMELOCATION_SET_FALSE; + + GPSPositionSensorData gpsPosData; + if (GPSPositionSensorHandle() != NULL) { + GPSPositionSensorGet(&gpsPosData); + } + + if (HomeLocationHandle() != NULL) { + HomeLocationSetGet(&hl_set); + } + + /** + * Encode GPS status and visible satellites as T1 value + * We will intentionally misuse this item to encode other useful information. + * Right-most two digits encode visible satellite count, left-most digit has following meaning: + * 1 - no GPS connected + * 2 - no fix + * 3 - 2D fix + * 4 - 3D fix + * 5 - 3D fix and HomeLocation is SET - should be safe for navigation + */ + switch (gpsPosData.Status) { + case GPSPOSITIONSENSOR_STATUS_NOGPS: + status = 100; + break; + case GPSPOSITIONSENSOR_STATUS_NOFIX: + status = 200; + break; + case GPSPOSITIONSENSOR_STATUS_FIX2D: + status = 300; + break; + case GPSPOSITIONSENSOR_STATUS_FIX3D: + if (hl_set == HOMELOCATION_SET_TRUE) { + status = 500; + } else { + status = 400; + } + break; + } + + if (gpsPosData.Satellites > 0) { + status += gpsPosData.Satellites; + } + + msg_length += frsky_pack_temperature_01((float)status, shub_global->serial_buf + msg_length); + + /** + * Encode GPS HDOP and VDOP as T2 value + * We will intentionally misuse this item to encode other useful information. + * VDOP in the upper 16 bits, max 256 (2.56 * 100) + * HDOP in the lower 16 bits, max 256 (2.56 * 100) + */ + hdop = gpsPosData.HDOP * 100.0f; + hdop = 0; + + if (hdop > 255.0f) { + hdop = 255.0f; + } + + vdop = gpsPosData.VDOP * 100.0f; + vdop = 0; + + if (vdop > 255.0f) { + vdop = 255.0f; + } + + msg_length += frsky_pack_temperature_02((vdop * 256 + hdop), shub_global->serial_buf + msg_length); + + if (gpsPosData.Status == GPSPOSITIONSENSOR_STATUS_FIX2D || + gpsPosData.Status == GPSPOSITIONSENSOR_STATUS_FIX3D) { + msg_length += frsky_pack_gps( + gpsPosData.Heading, + gpsPosData.Latitude, + gpsPosData.Longitude, + gpsPosData.Altitude, + gpsPosData.Groundspeed, + shub_global->serial_buf + msg_length); + } else { + msg_length += frsky_pack_gps(0, 0, 0, 0, 0, shub_global->serial_buf + msg_length); + } + + msg_length += frsky_pack_stop(shub_global->serial_buf + msg_length); + + PIOS_COM_SendBuffer(shub_global->frsky_port, + shub_global->serial_buf, msg_length); + } + } +} + +static bool frame_trigger(uint8_t frame_num) +{ + uint8_t rate = frsky_rates[frame_num]; + + if (rate == 0) { + return false; + } + + if (shub_global->frame_ticks[frame_num] == 0) { + // we're triggering now, setup the next trigger point + if (rate > TASK_RATE_HZ) { + rate = TASK_RATE_HZ; + } + shub_global->frame_ticks[frame_num] = (TASK_RATE_HZ / rate); + return true; + } + + // count down at 50Hz + shub_global->frame_ticks[frame_num]--; + return false; +} + +/** + * Writes altitude to buffer + * \return number of bytes written to the buffer + */ +static uint16_t frsky_pack_altitude(float altitude, uint8_t *serial_buf) +{ + uint8_t index = 0; + + float altitudeInteger = 0.0f; + + uint16_t decimalValue = lroundf(modff(altitude, &altitudeInteger) * 100); + int16_t integerValue = lroundf(altitude); + + frsky_serialize_value(FRSKY_ALTITUDE_INTEGER, (uint8_t *)&integerValue, serial_buf, &index); + frsky_serialize_value(FRSKY_ALTITUDE_DECIMAL, (uint8_t *)&decimalValue, serial_buf, &index); + + return index; +} + +/** + * Writes baro temperature to buffer + * \return number of bytes written to the buffer + */ +static uint16_t frsky_pack_temperature_01( + float temperature_01, + uint8_t *serial_buf) +{ + uint8_t index = 0; + + int16_t temperature = lroundf(temperature_01); + + frsky_serialize_value(FRSKY_TEMPERATURE_1, (uint8_t *)&temperature, serial_buf, &index); + + return index; +} + +/** + * Writes accel temperature to buffer + * \return number of bytes written to the buffer + */ +static uint16_t frsky_pack_temperature_02( + float temperature_02, + uint8_t *serial_buf) +{ + uint8_t index = 0; + + int16_t temperature = lroundf(temperature_02); + + frsky_serialize_value(FRSKY_TEMPERATURE_2, (uint8_t *)&temperature, serial_buf, &index); + + return index; +} + +/** + * Writes acceleration values to buffer + * \return number of bytes written to the buffer + */ +static uint16_t frsky_pack_accel( + float accels_x, + float accels_y, + float accels_z, + uint8_t *serial_buf) +{ + uint8_t index = 0; + + int16_t accel = frsky_acceleration_unit(accels_x); + + frsky_serialize_value(FRSKY_ACCELERATION_X, (uint8_t *)&accel, serial_buf, &index); + + accel = frsky_acceleration_unit(accels_y); + frsky_serialize_value(FRSKY_ACCELERATION_Y, (uint8_t *)&accel, serial_buf, &index); + + accel = frsky_acceleration_unit(accels_z); + frsky_serialize_value(FRSKY_ACCELERATION_Z, (uint8_t *)&accel, serial_buf, &index); + + return index; +} + +static uint16_t frsky_pack_cellvoltage( + uint8_t cell, + float cell_voltage, + uint8_t *serial_buf) +{ + // its not possible to address more than 15 cells + if (cell > 15) { + return 0; + } + + uint8_t index = 0; + uint16_t v = lroundf((cell_voltage / 4.2f) * 2100); + if (v > 2100) { + v = 2100; + } + + uint16_t voltage = ((v & 0x00ff) << 8) | (cell << 4) | ((v & 0x0f00) >> 8); + frsky_serialize_value(FRSKY_VOLTAGE, (uint8_t *)&voltage, serial_buf, &index); + + return index; +} +/** + * Writes battery values to buffer + * \return number of bytes written to the buffer + */ +static uint16_t frsky_pack_fas( + float voltage, + float current, + uint8_t *serial_buf) +{ + uint8_t index = 0; + + voltage = (voltage * 110.0f) / 21.0f; + + uint16_t integerValue = lroundf(voltage) / 100; + uint16_t decimalValue = lroundf(voltage - integerValue); + + frsky_serialize_value(FRSKY_VOLTAGE_AMPERE_SENSOR_INTEGER, (uint8_t *)&integerValue, serial_buf, &index); + frsky_serialize_value(FRSKY_VOLTAGE_AMPERE_SENSOR_DECIMAL, (uint8_t *)&decimalValue, serial_buf, &index); + + integerValue = lroundf(current * 10); + frsky_serialize_value(FRSKY_CURRENT, (uint8_t *)&integerValue, serial_buf, &index); + + return index; +} + +/** + * Writes rpm value to buffer + * \return number of bytes written to the buffer + */ +static uint16_t frsky_pack_rpm(uint16_t rpm, uint8_t *serial_buf) +{ + uint8_t index = 0; + + frsky_serialize_value(FRSKY_RPM, (uint8_t *)&rpm, serial_buf, &index); + + return index; +} + +/** + * Writes fuel value [0.0 ... 1.0] to buffer + * \return number of bytes written to the buffer + */ +static uint16_t frsky_pack_fuel( + float fuel_level, + uint8_t *serial_buf) +{ + uint8_t index = 0; + + uint16_t level = lroundf(abs(fuel_level * 100)); + + // Use fixed levels here because documentation says so. + if (level > 94) { + level = 100; + } else if (level > 69) { + level = 75; + } else if (level > 44) { + level = 50; + } else if (level > 19) { + level = 25; + } else { + level = 0; + } + + frsky_serialize_value(FRSKY_FUEL_LEVEL, (uint8_t *)&level, serial_buf, &index); + + return index; +} + +/** + * Writes gps values to buffer + * \return number of bytes written to the buffer + */ +static uint16_t frsky_pack_gps( + float course, + int32_t latitude, + int32_t longitude, + float altitude, + float speed, + uint8_t *serial_buf) +{ + uint8_t index = 0; + + { + float courseInteger = 0.0f; + uint16_t decimalValue = lroundf(modff(course, &courseInteger) * 100); + uint16_t integerValue = lroundf(courseInteger); + + frsky_serialize_value(FRSKY_GPS_COURSE_INTEGER, (uint8_t *)&integerValue, serial_buf, &index); + frsky_serialize_value(FRSKY_GPS_COURSE_DECIMAL, (uint8_t *)&decimalValue, serial_buf, &index); + } + + // latitude + { + uint16_t integerValue = (abs(latitude) / 100000); + uint16_t decimalValue = (abs(latitude) / 10) % 10000; + + frsky_serialize_value(FRSKY_GPS_LATITUDE_INTEGER, (uint8_t *)&integerValue, serial_buf, &index); + frsky_serialize_value(FRSKY_GPS_LATITUDE_DECIMAL, (uint8_t *)&decimalValue, serial_buf, &index); + + uint16_t hemisphere = 'N'; + if (latitude < 0) { + hemisphere = 'S'; + } + frsky_serialize_value(FRSKY_GPS_N_S, (uint8_t *)&hemisphere, serial_buf, &index); + } + + // longitude + { + uint16_t integerValue = (abs(longitude) / 100000); + uint16_t decimalValue = (abs(longitude) / 10) % 10000; + + uint16_t hemisphere = 'E'; + if (longitude < 0) { + hemisphere = 'W'; + } + + frsky_serialize_value(FRSKY_GPS_LONGITUDE_INTEGER, (uint8_t *)&integerValue, serial_buf, &index); + frsky_serialize_value(FRSKY_GPS_LONGITUDE_DECIMAL, (uint8_t *)&decimalValue, serial_buf, &index); + + frsky_serialize_value(FRSKY_GPS_E_W, (uint8_t *)&hemisphere, serial_buf, &index); + } + + // speed + { + float knots = speed / KNOTS2M_PER_SECOND; + + float knotsInteger = 0.0f; + uint16_t decimalValue = lroundf(modff(knots, &knotsInteger) * 100); + int16_t integerValue = lroundf(knotsInteger); + + frsky_serialize_value(FRSKY_GPS_SPEED_INTEGER, (uint8_t *)&integerValue, serial_buf, &index); + frsky_serialize_value(FRSKY_GPS_SPEED_DECIMAL, (uint8_t *)&decimalValue, serial_buf, &index); + } + + // altitude + { + float altitudeInteger = 0.0F; + uint16_t decimalValue = lroundf(modff(altitude, &altitudeInteger) * 100); + int16_t integerValue = lroundf(altitudeInteger); + + frsky_serialize_value(FRSKY_GPS_ALTITUDE_INTEGER, (uint8_t *)&integerValue, serial_buf, &index); + frsky_serialize_value(FRSKY_GPS_ALTITUDE_DECIMAL, (uint8_t *)&decimalValue, serial_buf, &index); + } + + return index; +} + +/** + * Writes stop byte to buffer + * \return number of bytes written to the buffer + */ +static uint16_t frsky_pack_stop(uint8_t *serial_buf) +{ + serial_buf[0] = FRSKY_FRAME_STOP; + + return 1; +} + +/** + * Convert acceleration value to frsky acceleration unit + * \return Acceleration value + */ +static int16_t frsky_acceleration_unit(float accel) +{ + accel = accel / GRAVITY; // convert to gravity + accel *= 1000; + return lroundf(accel); +} + +/** + * Write value to buffer + */ +static void frsky_serialize_value(uint8_t valueid, uint8_t *value, uint8_t *serial_buf, uint8_t *index) +{ + serial_buf[(*index)++] = FRSKY_FRAME_DATA_HEADER; + serial_buf[(*index)++] = valueid; + + frsky_write_userdata_byte(value[0], serial_buf, index); + frsky_write_userdata_byte(value[1], serial_buf, index); +} + +/** + * Write a byte to the buffer and do byte stuffing if needed. + */ +static void frsky_write_userdata_byte(uint8_t byte, uint8_t *serial_buf, uint8_t *index) +{ + // ** byte stuffing + if ((byte == 0x5E) || (byte == 0x5D)) { + serial_buf[(*index)++] = 0x5D; + serial_buf[(*index)++] = ~(byte ^ 0x60); + } else { + serial_buf[(*index)++] = byte; + } +} + +/** + * @} + * @} + */ diff --git a/flight/pios/common/pios_board_io.c b/flight/pios/common/pios_board_io.c index 025b4cec05..d2b236fb8a 100644 --- a/flight/pios/common/pios_board_io.c +++ b/flight/pios/common/pios_board_io.c @@ -95,6 +95,7 @@ uint32_t pios_openlrs_id; /* OpenLRS handle */ uint32_t pios_com_hkosd_id; /* HK OSD ?? */ uint32_t pios_com_msp_id; /* MSP */ uint32_t pios_com_mavlink_id; /* MAVLink */ +uint32_t pios_com_frsky_sensorhub_id; /* Frsky Sensorhub */ uint32_t pios_com_vcp_id; /* USB VCP */ #ifdef PIOS_INCLUDE_DEBUG_CONSOLE @@ -292,109 +293,116 @@ struct uart_function { }; static const struct uart_function uart_function_map[] = { - [PIOS_BOARD_IO_UART_TELEMETRY] = { + [PIOS_BOARD_IO_UART_TELEMETRY] = { .com_id = &pios_com_telem_rf_id, .com_rx_buf_len = PIOS_COM_TELEM_RF_RX_BUF_LEN, .com_tx_buf_len = PIOS_COM_TELEM_RF_TX_BUF_LEN, }, - [PIOS_BOARD_IO_UART_MAVLINK] = { + [PIOS_BOARD_IO_UART_MAVLINK] = { .com_id = &pios_com_mavlink_id, .com_rx_buf_len = PIOS_COM_MAVLINK_RX_BUF_LEN, .com_tx_buf_len = PIOS_COM_MAVLINK_TX_BUF_LEN, }, - [PIOS_BOARD_IO_UART_MSP] = { + [PIOS_BOARD_IO_UART_MSP] = { .com_id = &pios_com_msp_id, .com_rx_buf_len = PIOS_COM_MSP_RX_BUF_LEN, .com_tx_buf_len = PIOS_COM_MSP_TX_BUF_LEN, }, #ifdef PIOS_INCLUDE_GPS - [PIOS_BOARD_IO_UART_GPS] = { + [PIOS_BOARD_IO_UART_GPS] = { .com_id = &pios_com_gps_id, .com_rx_buf_len = PIOS_COM_GPS_RX_BUF_LEN, .com_tx_buf_len = PIOS_COM_GPS_TX_BUF_LEN, }, #endif - [PIOS_BOARD_IO_UART_OSDHK] = { + [PIOS_BOARD_IO_UART_OSDHK] = { .com_id = &pios_com_hkosd_id, .com_rx_buf_len = PIOS_COM_HKOSD_RX_BUF_LEN, .com_tx_buf_len = PIOS_COM_HKOSD_TX_BUF_LEN, }, +#ifdef PIOS_INCLUDE_FRSKY_SENSORHUB + [PIOS_BOARD_IO_UART_FRSKY_SENSORHUB] = { + .com_id = &pios_com_frsky_sensorhub_id, + .com_rx_buf_len = PIOS_COM_FRSKY_SENSORHUB_RX_BUF_LEN, + .com_tx_buf_len = PIOS_COM_FRSKY_SENSORHUB_TX_BUF_LEN, + }, +#endif #ifdef PIOS_INCLUDE_HOTT_BRIDGE - [PIOS_BOARD_IO_UART_HOTT_BRIDGE] = { + [PIOS_BOARD_IO_UART_HOTT_BRIDGE] = { .com_id = &pios_com_hott_id, .com_rx_buf_len = PIOS_COM_HOTT_BRIDGE_RX_BUF_LEN, .com_tx_buf_len = PIOS_COM_HOTT_BRIDGE_TX_BUF_LEN, }, #endif #ifdef PIOS_INCLUDE_DEBUG_CONSOLE - [PIOS_BOARD_IO_UART_DEBUGCONSOLE] = { + [PIOS_BOARD_IO_UART_DEBUGCONSOLE] = { .com_id = &pios_com_debug_id, .com_tx_buf_len = PIOS_COM_DEBUGCONSOLE_TX_BUF_LEN, }, #endif - [PIOS_BOARD_IO_UART_COMBRIDGE] = { + [PIOS_BOARD_IO_UART_COMBRIDGE] = { .com_id = &pios_com_bridge_id, .com_rx_buf_len = PIOS_COM_BRIDGE_RX_BUF_LEN, .com_tx_buf_len = PIOS_COM_BRIDGE_TX_BUF_LEN, }, #ifdef PIOS_INCLUDE_RCVR # ifdef PIOS_INCLUDE_IBUS - [PIOS_BOARD_IO_UART_IBUS] = { + [PIOS_BOARD_IO_UART_IBUS] = { .rcvr_init = &PIOS_IBUS_Init, .rcvr_driver = &pios_ibus_rcvr_driver, .rcvr_group = MANUALCONTROLSETTINGS_CHANNELGROUPS_IBUS, }, # endif /* PIOS_INCLUDE_IBUS */ # ifdef PIOS_INCLUDE_EXBUS - [PIOS_BOARD_IO_UART_EXBUS] = { + [PIOS_BOARD_IO_UART_EXBUS] = { .rcvr_init = &PIOS_EXBUS_Init, .rcvr_driver = &pios_exbus_rcvr_driver, .rcvr_group = MANUALCONTROLSETTINGS_CHANNELGROUPS_EXBUS, }, # endif /* PIOS_INCLUDE_EXBUS */ # ifdef PIOS_INCLUDE_SRXL - [PIOS_BOARD_IO_UART_SRXL] = { + [PIOS_BOARD_IO_UART_SRXL] = { .rcvr_init = &PIOS_SRXL_Init, .rcvr_driver = &pios_srxl_rcvr_driver, .rcvr_group = MANUALCONTROLSETTINGS_CHANNELGROUPS_SRXL, }, # endif /* PIOS_INCLUDE_SRXL */ # ifdef PIOS_INCLUDE_HOTT - [PIOS_BOARD_IO_UART_HOTT_SUMD] = { + [PIOS_BOARD_IO_UART_HOTT_SUMD] = { .rcvr_init = &PIOS_HOTT_Init_SUMD, .rcvr_driver = &pios_hott_rcvr_driver, .rcvr_group = MANUALCONTROLSETTINGS_CHANNELGROUPS_HOTT, }, - [PIOS_BOARD_IO_UART_HOTT_SUMH] = { + [PIOS_BOARD_IO_UART_HOTT_SUMH] = { .rcvr_init = &PIOS_HOTT_Init_SUMH, .rcvr_driver = &pios_hott_rcvr_driver, .rcvr_group = MANUALCONTROLSETTINGS_CHANNELGROUPS_HOTT, }, # endif /* PIOS_INCLUDE_HOTT */ # ifdef PIOS_INCLUDE_DSM - [PIOS_BOARD_IO_UART_DSM_MAIN] = { + [PIOS_BOARD_IO_UART_DSM_MAIN] = { .rcvr_init = &PIOS_DSM_Init_Helper, .rcvr_driver = &pios_dsm_rcvr_driver, .rcvr_group = MANUALCONTROLSETTINGS_CHANNELGROUPS_DSMMAINPORT, }, - [PIOS_BOARD_IO_UART_DSM_FLEXI] = { + [PIOS_BOARD_IO_UART_DSM_FLEXI] = { .rcvr_init = &PIOS_DSM_Init_Helper, .rcvr_driver = &pios_dsm_rcvr_driver, .rcvr_group = MANUALCONTROLSETTINGS_CHANNELGROUPS_DSMFLEXIPORT, }, - [PIOS_BOARD_IO_UART_DSM_RCVR] = { + [PIOS_BOARD_IO_UART_DSM_RCVR] = { .rcvr_init = &PIOS_DSM_Init_Helper, .rcvr_driver = &pios_dsm_rcvr_driver, .rcvr_group = MANUALCONTROLSETTINGS_CHANNELGROUPS_DSMRCVRPORT, }, # endif /* PIOS_INCLUDE_DSM */ # ifdef PIOS_INCLUDE_SBUS - [PIOS_BOARD_IO_UART_SBUS] = { + [PIOS_BOARD_IO_UART_SBUS] = { .rcvr_init = &PIOS_SBus_Init_Helper, .rcvr_driver = &pios_sbus_rcvr_driver, .rcvr_group = MANUALCONTROLSETTINGS_CHANNELGROUPS_SBUS, diff --git a/flight/pios/inc/pios_board_io.h b/flight/pios/inc/pios_board_io.h index 34e01704e3..2e09f516ee 100644 --- a/flight/pios/inc/pios_board_io.h +++ b/flight/pios/inc/pios_board_io.h @@ -157,25 +157,35 @@ extern uint32_t pios_com_mavlink_id; /* HoTT Telemetry */ #ifdef PIOS_INCLUDE_HOTT_BRIDGE # ifndef PIOS_COM_HOTT_BRIDGE_RX_BUF_LEN -# define PIOS_COM_HOTT_BRIDGE_RX_BUF_LEN 512 +# define PIOS_COM_HOTT_BRIDGE_RX_BUF_LEN 512 # endif # ifndef PIOS_COM_HOTT_BRIDGE_TX_BUF_LEN -# define PIOS_COM_HOTT_BRIDGE_TX_BUF_LEN 512 +# define PIOS_COM_HOTT_BRIDGE_TX_BUF_LEN 512 # endif extern uint32_t pios_com_hott_id; -# define PIOS_COM_HOTT (pios_com_hott_id) +# define PIOS_COM_HOTT (pios_com_hott_id) +#endif + +/* Frsky Sensorhub */ +extern uint32_t pios_com_frsky_sensorhub_id; +#define PIOS_COM_FRSKY_SENSORHUB (pios_com_frsky_sensorhub_id) +#ifndef PIOS_COM_FRSKY_SENSORHUB_TX_BUF_LEN +# define PIOS_COM_FRSKY_SENSORHUB_TX_BUF_LEN 128 +#endif +#ifndef PIOS_COM_FRSKY_SENSORHUB_RX_BUF_LEN +# define PIOS_COM_FRSKY_SENSORHUB_RX_BUF_LEN 128 #endif /* USB VCP */ extern uint32_t pios_com_vcp_id; -#define PIOS_COM_VCP (pios_com_vcp_id) +#define PIOS_COM_VCP (pios_com_vcp_id) #ifdef PIOS_INCLUDE_DEBUG_CONSOLE extern uint32_t pios_com_debug_id; -#define PIOS_COM_DEBUG (pios_com_debug_id) +#define PIOS_COM_DEBUG (pios_com_debug_id) #ifndef PIOS_COM_DEBUGCONSOLE_TX_BUF_LEN -# define PIOS_COM_DEBUGCONSOLE_TX_BUF_LEN 40 +# define PIOS_COM_DEBUGCONSOLE_TX_BUF_LEN 40 #endif #endif /* PIOS_INCLUDE_DEBUG_CONSOLE */ @@ -208,6 +218,7 @@ typedef enum { PIOS_BOARD_IO_UART_EXBUS, /* rcvr */ // PIOS_BOARD_IO_UART_FRSKY_SPORT_TELEMETRY, /* com */ PIOS_BOARD_IO_UART_HOTT_BRIDGE, /* com */ + PIOS_BOARD_IO_UART_FRSKY_SENSORHUB, /* com */ } PIOS_BOARD_IO_UART_Function; diff --git a/flight/targets/boards/discoveryf4bare/firmware/Makefile b/flight/targets/boards/discoveryf4bare/firmware/Makefile index d9e9c67f4c..00b576cd5b 100644 --- a/flight/targets/boards/discoveryf4bare/firmware/Makefile +++ b/flight/targets/boards/discoveryf4bare/firmware/Makefile @@ -59,6 +59,7 @@ OPTMODULES += AutoTune OPTMODULES += ComUsbBridge OPTMODULES += UAVOMSPBridge OPTMODULES += UAVOMavlinkBridge +OPTMODULES += UAVOFrSKYSensorHubBridge SRC += $(FLIGHTLIB)/notification.c diff --git a/flight/targets/boards/discoveryf4bare/firmware/inc/pios_config.h b/flight/targets/boards/discoveryf4bare/firmware/inc/pios_config.h index aae41c922d..efdfb07fd9 100644 --- a/flight/targets/boards/discoveryf4bare/firmware/inc/pios_config.h +++ b/flight/targets/boards/discoveryf4bare/firmware/inc/pios_config.h @@ -153,6 +153,7 @@ #define PIOS_INCLUDE_GPS_UBX_PARSER #define PIOS_INCLUDE_GPS_DJI_PARSER #define PIOS_GPS_SETS_HOMELOCATION +#define PIOS_INCLUDE_FRSKY_SENSORHUB /* Stabilization options */ /* #define PIOS_QUATERNION_STABILIZATION */ diff --git a/flight/targets/boards/discoveryf4bare/firmware/pios_board.c b/flight/targets/boards/discoveryf4bare/firmware/pios_board.c index e7d8e9c27a..4791d9badd 100644 --- a/flight/targets/boards/discoveryf4bare/firmware/pios_board.c +++ b/flight/targets/boards/discoveryf4bare/firmware/pios_board.c @@ -59,44 +59,47 @@ static const PIOS_BOARD_IO_UART_Function flexiio_function_map[] = { [HWSETTINGS_RM_RCVRPORT_PPMTELEMETRY] = PIOS_BOARD_IO_UART_TELEMETRY, [HWSETTINGS_RM_RCVRPORT_PPMDEBUGCONSOLE] = PIOS_BOARD_IO_UART_DEBUGCONSOLE, [HWSETTINGS_RM_RCVRPORT_PPMCOMBRIDGE] = PIOS_BOARD_IO_UART_COMBRIDGE, - [HWSETTINGS_RM_RCVRPORT_PPMMSP] = PIOS_BOARD_IO_UART_MSP, - [HWSETTINGS_RM_RCVRPORT_PPMMAVLINK] = PIOS_BOARD_IO_UART_MAVLINK, - [HWSETTINGS_RM_RCVRPORT_PPMGPS] = PIOS_BOARD_IO_UART_GPS, - [HWSETTINGS_RM_RCVRPORT_TELEMETRY] = PIOS_BOARD_IO_UART_TELEMETRY, - [HWSETTINGS_RM_RCVRPORT_DEBUGCONSOLE] = PIOS_BOARD_IO_UART_DEBUGCONSOLE, - [HWSETTINGS_RM_RCVRPORT_COMBRIDGE] = PIOS_BOARD_IO_UART_COMBRIDGE, + [HWSETTINGS_RM_RCVRPORT_PPMMSP] = PIOS_BOARD_IO_UART_MSP, + [HWSETTINGS_RM_RCVRPORT_PPMMAVLINK] = PIOS_BOARD_IO_UART_MAVLINK, + [HWSETTINGS_RM_RCVRPORT_PPMGPS] = PIOS_BOARD_IO_UART_GPS, + [HWSETTINGS_RM_RCVRPORT_TELEMETRY] = PIOS_BOARD_IO_UART_TELEMETRY, + [HWSETTINGS_RM_RCVRPORT_DEBUGCONSOLE] = PIOS_BOARD_IO_UART_DEBUGCONSOLE, + [HWSETTINGS_RM_RCVRPORT_COMBRIDGE] = PIOS_BOARD_IO_UART_COMBRIDGE, [HWSETTINGS_RM_RCVRPORT_MSP] = PIOS_BOARD_IO_UART_MSP, - [HWSETTINGS_RM_RCVRPORT_MAVLINK] = PIOS_BOARD_IO_UART_MAVLINK, - [HWSETTINGS_RM_RCVRPORT_GPS] = PIOS_BOARD_IO_UART_GPS, + [HWSETTINGS_RM_RCVRPORT_MAVLINK] = PIOS_BOARD_IO_UART_MAVLINK, + [HWSETTINGS_RM_RCVRPORT_GPS] = PIOS_BOARD_IO_UART_GPS, [HWSETTINGS_RM_RCVRPORT_IBUS] = PIOS_BOARD_IO_UART_IBUS, + [HWSETTINGS_RM_RCVRPORT_FRSKYSENSORHUB] = PIOS_BOARD_IO_UART_FRSKY_SENSORHUB, }; static const PIOS_BOARD_IO_UART_Function main_function_map[] = { [HWSETTINGS_RM_MAINPORT_TELEMETRY] = PIOS_BOARD_IO_UART_TELEMETRY, - [HWSETTINGS_RM_MAINPORT_GPS] = PIOS_BOARD_IO_UART_GPS, - [HWSETTINGS_RM_MAINPORT_SBUS] = PIOS_BOARD_IO_UART_SBUS, - [HWSETTINGS_RM_MAINPORT_DSM] = PIOS_BOARD_IO_UART_DSM_MAIN, - [HWSETTINGS_RM_MAINPORT_DEBUGCONSOLE] = PIOS_BOARD_IO_UART_DEBUGCONSOLE, - [HWSETTINGS_RM_MAINPORT_COMBRIDGE] = PIOS_BOARD_IO_UART_COMBRIDGE, - [HWSETTINGS_RM_MAINPORT_OSDHK] = PIOS_BOARD_IO_UART_OSDHK, - [HWSETTINGS_RM_MAINPORT_MSP] = PIOS_BOARD_IO_UART_MSP, - [HWSETTINGS_RM_MAINPORT_MAVLINK] = PIOS_BOARD_IO_UART_MAVLINK, + [HWSETTINGS_RM_MAINPORT_GPS] = PIOS_BOARD_IO_UART_GPS, + [HWSETTINGS_RM_MAINPORT_SBUS] = PIOS_BOARD_IO_UART_SBUS, + [HWSETTINGS_RM_MAINPORT_DSM] = PIOS_BOARD_IO_UART_DSM_MAIN, + [HWSETTINGS_RM_MAINPORT_DEBUGCONSOLE] = PIOS_BOARD_IO_UART_DEBUGCONSOLE, + [HWSETTINGS_RM_MAINPORT_COMBRIDGE] = PIOS_BOARD_IO_UART_COMBRIDGE, + [HWSETTINGS_RM_MAINPORT_OSDHK] = PIOS_BOARD_IO_UART_OSDHK, + [HWSETTINGS_RM_MAINPORT_MSP] = PIOS_BOARD_IO_UART_MSP, + [HWSETTINGS_RM_MAINPORT_MAVLINK] = PIOS_BOARD_IO_UART_MAVLINK, + [HWSETTINGS_RM_MAINPORT_FRSKYSENSORHUB] = PIOS_BOARD_IO_UART_FRSKY_SENSORHUB, }; static const PIOS_BOARD_IO_UART_Function flexi_function_map[] = { - [HWSETTINGS_RM_FLEXIPORT_TELEMETRY] = PIOS_BOARD_IO_UART_TELEMETRY, + [HWSETTINGS_RM_FLEXIPORT_TELEMETRY] = PIOS_BOARD_IO_UART_TELEMETRY, [HWSETTINGS_RM_FLEXIPORT_GPS] = PIOS_BOARD_IO_UART_GPS, [HWSETTINGS_RM_FLEXIPORT_DSM] = PIOS_BOARD_IO_UART_DSM_FLEXI, - [HWSETTINGS_RM_FLEXIPORT_EXBUS] = PIOS_BOARD_IO_UART_EXBUS, - [HWSETTINGS_RM_FLEXIPORT_HOTTSUMD] = PIOS_BOARD_IO_UART_HOTT_SUMD, - [HWSETTINGS_RM_FLEXIPORT_HOTTSUMH] = PIOS_BOARD_IO_UART_HOTT_SUMH, + [HWSETTINGS_RM_FLEXIPORT_EXBUS] = PIOS_BOARD_IO_UART_EXBUS, + [HWSETTINGS_RM_FLEXIPORT_HOTTSUMD] = PIOS_BOARD_IO_UART_HOTT_SUMD, + [HWSETTINGS_RM_FLEXIPORT_HOTTSUMH] = PIOS_BOARD_IO_UART_HOTT_SUMH, [HWSETTINGS_RM_FLEXIPORT_SRXL] = PIOS_BOARD_IO_UART_SRXL, [HWSETTINGS_RM_FLEXIPORT_IBUS] = PIOS_BOARD_IO_UART_IBUS, - [HWSETTINGS_RM_FLEXIPORT_DEBUGCONSOLE] = PIOS_BOARD_IO_UART_DEBUGCONSOLE, - [HWSETTINGS_RM_FLEXIPORT_COMBRIDGE] = PIOS_BOARD_IO_UART_COMBRIDGE, - [HWSETTINGS_RM_FLEXIPORT_OSDHK] = PIOS_BOARD_IO_UART_OSDHK, + [HWSETTINGS_RM_FLEXIPORT_DEBUGCONSOLE] = PIOS_BOARD_IO_UART_DEBUGCONSOLE, + [HWSETTINGS_RM_FLEXIPORT_COMBRIDGE] = PIOS_BOARD_IO_UART_COMBRIDGE, + [HWSETTINGS_RM_FLEXIPORT_OSDHK] = PIOS_BOARD_IO_UART_OSDHK, [HWSETTINGS_RM_FLEXIPORT_MSP] = PIOS_BOARD_IO_UART_MSP, - [HWSETTINGS_RM_FLEXIPORT_MAVLINK] = PIOS_BOARD_IO_UART_MAVLINK, + [HWSETTINGS_RM_FLEXIPORT_MAVLINK] = PIOS_BOARD_IO_UART_MAVLINK, + [HWSETTINGS_RM_FLEXIPORT_FRSKYSENSORHUB] = PIOS_BOARD_IO_UART_FRSKY_SENSORHUB, }; /** diff --git a/flight/targets/boards/revolution/firmware/Makefile b/flight/targets/boards/revolution/firmware/Makefile index 6a51ba5a2b..7013d484ea 100644 --- a/flight/targets/boards/revolution/firmware/Makefile +++ b/flight/targets/boards/revolution/firmware/Makefile @@ -58,6 +58,7 @@ OPTMODULES += ComUsbBridge OPTMODULES += UAVOHottBridge OPTMODULES += UAVOMSPBridge OPTMODULES += UAVOMavlinkBridge +OPTMODULES += UAVOFrSKYSensorHubBridge SRC += $(FLIGHTLIB)/notification.c diff --git a/flight/targets/boards/revolution/firmware/inc/pios_config.h b/flight/targets/boards/revolution/firmware/inc/pios_config.h index ead7372078..ca67832aea 100644 --- a/flight/targets/boards/revolution/firmware/inc/pios_config.h +++ b/flight/targets/boards/revolution/firmware/inc/pios_config.h @@ -160,6 +160,7 @@ #define PIOS_INCLUDE_GPS_UBX_PARSER #define PIOS_INCLUDE_GPS_DJI_PARSER #define PIOS_GPS_SETS_HOMELOCATION +#define PIOS_INCLUDE_FRSKY_SENSORHUB /* Stabilization options */ #define PIOS_QUATERNION_STABILIZATION diff --git a/flight/targets/boards/revolution/firmware/pios_board.c b/flight/targets/boards/revolution/firmware/pios_board.c index 63494acd0b..92db65637d 100644 --- a/flight/targets/boards/revolution/firmware/pios_board.c +++ b/flight/targets/boards/revolution/firmware/pios_board.c @@ -58,44 +58,47 @@ static const PIOS_BOARD_IO_UART_Function flexiio_function_map[] = { [HWSETTINGS_RM_RCVRPORT_PPMTELEMETRY] = PIOS_BOARD_IO_UART_TELEMETRY, [HWSETTINGS_RM_RCVRPORT_PPMDEBUGCONSOLE] = PIOS_BOARD_IO_UART_DEBUGCONSOLE, [HWSETTINGS_RM_RCVRPORT_PPMCOMBRIDGE] = PIOS_BOARD_IO_UART_COMBRIDGE, - [HWSETTINGS_RM_RCVRPORT_PPMMSP] = PIOS_BOARD_IO_UART_MSP, - [HWSETTINGS_RM_RCVRPORT_PPMMAVLINK] = PIOS_BOARD_IO_UART_MAVLINK, - [HWSETTINGS_RM_RCVRPORT_PPMGPS] = PIOS_BOARD_IO_UART_GPS, - [HWSETTINGS_RM_RCVRPORT_TELEMETRY] = PIOS_BOARD_IO_UART_TELEMETRY, - [HWSETTINGS_RM_RCVRPORT_DEBUGCONSOLE] = PIOS_BOARD_IO_UART_DEBUGCONSOLE, - [HWSETTINGS_RM_RCVRPORT_COMBRIDGE] = PIOS_BOARD_IO_UART_COMBRIDGE, + [HWSETTINGS_RM_RCVRPORT_PPMMSP] = PIOS_BOARD_IO_UART_MSP, + [HWSETTINGS_RM_RCVRPORT_PPMMAVLINK] = PIOS_BOARD_IO_UART_MAVLINK, + [HWSETTINGS_RM_RCVRPORT_PPMGPS] = PIOS_BOARD_IO_UART_GPS, + [HWSETTINGS_RM_RCVRPORT_TELEMETRY] = PIOS_BOARD_IO_UART_TELEMETRY, + [HWSETTINGS_RM_RCVRPORT_DEBUGCONSOLE] = PIOS_BOARD_IO_UART_DEBUGCONSOLE, + [HWSETTINGS_RM_RCVRPORT_COMBRIDGE] = PIOS_BOARD_IO_UART_COMBRIDGE, [HWSETTINGS_RM_RCVRPORT_MSP] = PIOS_BOARD_IO_UART_MSP, - [HWSETTINGS_RM_RCVRPORT_MAVLINK] = PIOS_BOARD_IO_UART_MAVLINK, - [HWSETTINGS_RM_RCVRPORT_GPS] = PIOS_BOARD_IO_UART_GPS, + [HWSETTINGS_RM_RCVRPORT_MAVLINK] = PIOS_BOARD_IO_UART_MAVLINK, + [HWSETTINGS_RM_RCVRPORT_GPS] = PIOS_BOARD_IO_UART_GPS, [HWSETTINGS_RM_RCVRPORT_IBUS] = PIOS_BOARD_IO_UART_IBUS, + [HWSETTINGS_RM_RCVRPORT_FRSKYSENSORHUB] = PIOS_BOARD_IO_UART_FRSKY_SENSORHUB, }; static const PIOS_BOARD_IO_UART_Function main_function_map[] = { [HWSETTINGS_RM_MAINPORT_TELEMETRY] = PIOS_BOARD_IO_UART_TELEMETRY, - [HWSETTINGS_RM_MAINPORT_GPS] = PIOS_BOARD_IO_UART_GPS, - [HWSETTINGS_RM_MAINPORT_SBUS] = PIOS_BOARD_IO_UART_SBUS, - [HWSETTINGS_RM_MAINPORT_DSM] = PIOS_BOARD_IO_UART_DSM_MAIN, - [HWSETTINGS_RM_MAINPORT_DEBUGCONSOLE] = PIOS_BOARD_IO_UART_DEBUGCONSOLE, - [HWSETTINGS_RM_MAINPORT_COMBRIDGE] = PIOS_BOARD_IO_UART_COMBRIDGE, - [HWSETTINGS_RM_MAINPORT_OSDHK] = PIOS_BOARD_IO_UART_OSDHK, - [HWSETTINGS_RM_MAINPORT_MSP] = PIOS_BOARD_IO_UART_MSP, - [HWSETTINGS_RM_MAINPORT_MAVLINK] = PIOS_BOARD_IO_UART_MAVLINK, + [HWSETTINGS_RM_MAINPORT_GPS] = PIOS_BOARD_IO_UART_GPS, + [HWSETTINGS_RM_MAINPORT_SBUS] = PIOS_BOARD_IO_UART_SBUS, + [HWSETTINGS_RM_MAINPORT_DSM] = PIOS_BOARD_IO_UART_DSM_MAIN, + [HWSETTINGS_RM_MAINPORT_DEBUGCONSOLE] = PIOS_BOARD_IO_UART_DEBUGCONSOLE, + [HWSETTINGS_RM_MAINPORT_COMBRIDGE] = PIOS_BOARD_IO_UART_COMBRIDGE, + [HWSETTINGS_RM_MAINPORT_OSDHK] = PIOS_BOARD_IO_UART_OSDHK, + [HWSETTINGS_RM_MAINPORT_MSP] = PIOS_BOARD_IO_UART_MSP, + [HWSETTINGS_RM_MAINPORT_MAVLINK] = PIOS_BOARD_IO_UART_MAVLINK, + [HWSETTINGS_RM_MAINPORT_FRSKYSENSORHUB] = PIOS_BOARD_IO_UART_FRSKY_SENSORHUB, }; static const PIOS_BOARD_IO_UART_Function flexi_function_map[] = { - [HWSETTINGS_RM_FLEXIPORT_TELEMETRY] = PIOS_BOARD_IO_UART_TELEMETRY, + [HWSETTINGS_RM_FLEXIPORT_TELEMETRY] = PIOS_BOARD_IO_UART_TELEMETRY, [HWSETTINGS_RM_FLEXIPORT_GPS] = PIOS_BOARD_IO_UART_GPS, [HWSETTINGS_RM_FLEXIPORT_DSM] = PIOS_BOARD_IO_UART_DSM_FLEXI, - [HWSETTINGS_RM_FLEXIPORT_EXBUS] = PIOS_BOARD_IO_UART_EXBUS, - [HWSETTINGS_RM_FLEXIPORT_HOTTSUMD] = PIOS_BOARD_IO_UART_HOTT_SUMD, - [HWSETTINGS_RM_FLEXIPORT_HOTTSUMH] = PIOS_BOARD_IO_UART_HOTT_SUMH, + [HWSETTINGS_RM_FLEXIPORT_EXBUS] = PIOS_BOARD_IO_UART_EXBUS, + [HWSETTINGS_RM_FLEXIPORT_HOTTSUMD] = PIOS_BOARD_IO_UART_HOTT_SUMD, + [HWSETTINGS_RM_FLEXIPORT_HOTTSUMH] = PIOS_BOARD_IO_UART_HOTT_SUMH, [HWSETTINGS_RM_FLEXIPORT_SRXL] = PIOS_BOARD_IO_UART_SRXL, [HWSETTINGS_RM_FLEXIPORT_IBUS] = PIOS_BOARD_IO_UART_IBUS, - [HWSETTINGS_RM_FLEXIPORT_DEBUGCONSOLE] = PIOS_BOARD_IO_UART_DEBUGCONSOLE, - [HWSETTINGS_RM_FLEXIPORT_COMBRIDGE] = PIOS_BOARD_IO_UART_COMBRIDGE, - [HWSETTINGS_RM_FLEXIPORT_OSDHK] = PIOS_BOARD_IO_UART_OSDHK, + [HWSETTINGS_RM_FLEXIPORT_DEBUGCONSOLE] = PIOS_BOARD_IO_UART_DEBUGCONSOLE, + [HWSETTINGS_RM_FLEXIPORT_COMBRIDGE] = PIOS_BOARD_IO_UART_COMBRIDGE, + [HWSETTINGS_RM_FLEXIPORT_OSDHK] = PIOS_BOARD_IO_UART_OSDHK, [HWSETTINGS_RM_FLEXIPORT_MSP] = PIOS_BOARD_IO_UART_MSP, - [HWSETTINGS_RM_FLEXIPORT_MAVLINK] = PIOS_BOARD_IO_UART_MAVLINK, + [HWSETTINGS_RM_FLEXIPORT_MAVLINK] = PIOS_BOARD_IO_UART_MAVLINK, + [HWSETTINGS_RM_FLEXIPORT_FRSKYSENSORHUB] = PIOS_BOARD_IO_UART_FRSKY_SENSORHUB, }; /** diff --git a/flight/targets/boards/revonano/firmware/Makefile b/flight/targets/boards/revonano/firmware/Makefile index 1abf5b82a6..4030c03758 100644 --- a/flight/targets/boards/revonano/firmware/Makefile +++ b/flight/targets/boards/revonano/firmware/Makefile @@ -56,6 +56,7 @@ OPTMODULES += AutoTune OPTMODULES += ComUsbBridge OPTMODULES += UAVOMSPBridge OPTMODULES += UAVOMavlinkBridge +OPTMODULES += UAVOFrSKYSensorHubBridge SRC += $(FLIGHTLIB)/notification.c diff --git a/flight/targets/boards/revonano/firmware/inc/pios_config.h b/flight/targets/boards/revonano/firmware/inc/pios_config.h index 49a64f09a9..3f37497b1c 100644 --- a/flight/targets/boards/revonano/firmware/inc/pios_config.h +++ b/flight/targets/boards/revonano/firmware/inc/pios_config.h @@ -160,6 +160,7 @@ #define PIOS_INCLUDE_GPS_UBX_PARSER #define PIOS_INCLUDE_GPS_DJI_PARSER #define PIOS_GPS_SETS_HOMELOCATION +#define PIOS_INCLUDE_FRSKY_SENSORHUB /* Stabilization options */ #define PIOS_QUATERNION_STABILIZATION diff --git a/flight/targets/boards/revonano/firmware/pios_board.c b/flight/targets/boards/revonano/firmware/pios_board.c index 42cb939d81..5bbf3f237b 100644 --- a/flight/targets/boards/revonano/firmware/pios_board.c +++ b/flight/targets/boards/revonano/firmware/pios_board.c @@ -68,31 +68,32 @@ static void ActuatorSettingsUpdatedCb(UAVObjEvent *ev); #include static const PIOS_BOARD_IO_UART_Function flexi_function_map[] = { - [HWSETTINGS_RM_FLEXIPORT_TELEMETRY] = PIOS_BOARD_IO_UART_TELEMETRY, + [HWSETTINGS_RM_FLEXIPORT_TELEMETRY] = PIOS_BOARD_IO_UART_TELEMETRY, [HWSETTINGS_RM_FLEXIPORT_GPS] = PIOS_BOARD_IO_UART_GPS, [HWSETTINGS_RM_FLEXIPORT_DSM] = PIOS_BOARD_IO_UART_DSM_FLEXI, - [HWSETTINGS_RM_FLEXIPORT_EXBUS] = PIOS_BOARD_IO_UART_EXBUS, - [HWSETTINGS_RM_FLEXIPORT_HOTTSUMD] = PIOS_BOARD_IO_UART_HOTT_SUMD, - [HWSETTINGS_RM_FLEXIPORT_HOTTSUMH] = PIOS_BOARD_IO_UART_HOTT_SUMH, + [HWSETTINGS_RM_FLEXIPORT_EXBUS] = PIOS_BOARD_IO_UART_EXBUS, + [HWSETTINGS_RM_FLEXIPORT_HOTTSUMD] = PIOS_BOARD_IO_UART_HOTT_SUMD, + [HWSETTINGS_RM_FLEXIPORT_HOTTSUMH] = PIOS_BOARD_IO_UART_HOTT_SUMH, [HWSETTINGS_RM_FLEXIPORT_SRXL] = PIOS_BOARD_IO_UART_SRXL, [HWSETTINGS_RM_FLEXIPORT_IBUS] = PIOS_BOARD_IO_UART_IBUS, - [HWSETTINGS_RM_FLEXIPORT_DEBUGCONSOLE] = PIOS_BOARD_IO_UART_DEBUGCONSOLE, - [HWSETTINGS_RM_FLEXIPORT_COMBRIDGE] = PIOS_BOARD_IO_UART_COMBRIDGE, - [HWSETTINGS_RM_FLEXIPORT_OSDHK] = PIOS_BOARD_IO_UART_OSDHK, + [HWSETTINGS_RM_FLEXIPORT_DEBUGCONSOLE] = PIOS_BOARD_IO_UART_DEBUGCONSOLE, + [HWSETTINGS_RM_FLEXIPORT_COMBRIDGE] = PIOS_BOARD_IO_UART_COMBRIDGE, + [HWSETTINGS_RM_FLEXIPORT_OSDHK] = PIOS_BOARD_IO_UART_OSDHK, [HWSETTINGS_RM_FLEXIPORT_MSP] = PIOS_BOARD_IO_UART_MSP, - [HWSETTINGS_RM_FLEXIPORT_MAVLINK] = PIOS_BOARD_IO_UART_MAVLINK, + [HWSETTINGS_RM_FLEXIPORT_MAVLINK] = PIOS_BOARD_IO_UART_MAVLINK, + [HWSETTINGS_RM_FLEXIPORT_FRSKYSENSORHUB] = PIOS_BOARD_IO_UART_FRSKY_SENSORHUB, }; static const PIOS_BOARD_IO_UART_Function main_function_map[] = { [HWSETTINGS_RM_MAINPORT_TELEMETRY] = PIOS_BOARD_IO_UART_TELEMETRY, - [HWSETTINGS_RM_MAINPORT_GPS] = PIOS_BOARD_IO_UART_GPS, - [HWSETTINGS_RM_MAINPORT_SBUS] = PIOS_BOARD_IO_UART_SBUS, - [HWSETTINGS_RM_MAINPORT_DSM] = PIOS_BOARD_IO_UART_DSM_MAIN, - [HWSETTINGS_RM_MAINPORT_DEBUGCONSOLE] = PIOS_BOARD_IO_UART_DEBUGCONSOLE, - [HWSETTINGS_RM_MAINPORT_COMBRIDGE] = PIOS_BOARD_IO_UART_COMBRIDGE, - [HWSETTINGS_RM_MAINPORT_OSDHK] = PIOS_BOARD_IO_UART_OSDHK, - [HWSETTINGS_RM_MAINPORT_MSP] = PIOS_BOARD_IO_UART_MSP, - [HWSETTINGS_RM_MAINPORT_MAVLINK] = PIOS_BOARD_IO_UART_MAVLINK, + [HWSETTINGS_RM_MAINPORT_GPS] = PIOS_BOARD_IO_UART_GPS, + [HWSETTINGS_RM_MAINPORT_SBUS] = PIOS_BOARD_IO_UART_SBUS, + [HWSETTINGS_RM_MAINPORT_DSM] = PIOS_BOARD_IO_UART_DSM_MAIN, + [HWSETTINGS_RM_MAINPORT_DEBUGCONSOLE] = PIOS_BOARD_IO_UART_DEBUGCONSOLE, + [HWSETTINGS_RM_MAINPORT_COMBRIDGE] = PIOS_BOARD_IO_UART_COMBRIDGE, + [HWSETTINGS_RM_MAINPORT_OSDHK] = PIOS_BOARD_IO_UART_OSDHK, + [HWSETTINGS_RM_MAINPORT_MSP] = PIOS_BOARD_IO_UART_MSP, + [HWSETTINGS_RM_MAINPORT_FRSKYSENSORHUB] = PIOS_BOARD_IO_UART_FRSKY_SENSORHUB, }; void PIOS_Board_Init(void) diff --git a/flight/targets/boards/sparky2/firmware/Makefile b/flight/targets/boards/sparky2/firmware/Makefile index 45c7f28911..6e3ab127db 100644 --- a/flight/targets/boards/sparky2/firmware/Makefile +++ b/flight/targets/boards/sparky2/firmware/Makefile @@ -57,6 +57,7 @@ OPTMODULES += AutoTune OPTMODULES += ComUsbBridge OPTMODULES += UAVOMSPBridge OPTMODULES += UAVOMavlinkBridge +OPTMODULES += UAVOFrSKYSensorHubBridge SRC += $(FLIGHTLIB)/notification.c diff --git a/flight/targets/boards/sparky2/firmware/inc/pios_config.h b/flight/targets/boards/sparky2/firmware/inc/pios_config.h index e823a82a12..6082f9be91 100644 --- a/flight/targets/boards/sparky2/firmware/inc/pios_config.h +++ b/flight/targets/boards/sparky2/firmware/inc/pios_config.h @@ -163,6 +163,7 @@ #define PIOS_INCLUDE_GPS_UBX_PARSER #define PIOS_INCLUDE_GPS_DJI_PARSER #define PIOS_GPS_SETS_HOMELOCATION +#define PIOS_INCLUDE_FRSKY_SENSORHUB /* Stabilization options */ #define PIOS_QUATERNION_STABILIZATION diff --git a/flight/targets/boards/sparky2/firmware/pios_board.c b/flight/targets/boards/sparky2/firmware/pios_board.c index 4fc33f4abf..80d0e0d7be 100644 --- a/flight/targets/boards/sparky2/firmware/pios_board.c +++ b/flight/targets/boards/sparky2/firmware/pios_board.c @@ -75,22 +75,24 @@ static const PIOS_BOARD_IO_UART_Function main_function_map[] = { [HWSETTINGS_SPK2_MAINPORT_OSDHK] = PIOS_BOARD_IO_UART_OSDHK, [HWSETTINGS_SPK2_MAINPORT_MSP] = PIOS_BOARD_IO_UART_MSP, [HWSETTINGS_SPK2_MAINPORT_MAVLINK] = PIOS_BOARD_IO_UART_MAVLINK, + [HWSETTINGS_SPK2_MAINPORT_FRSKYSENSORHUB] = PIOS_BOARD_IO_UART_FRSKY_SENSORHUB, }; static const PIOS_BOARD_IO_UART_Function flexi_function_map[] = { - [HWSETTINGS_SPK2_FLEXIPORT_TELEMETRY] = PIOS_BOARD_IO_UART_TELEMETRY, + [HWSETTINGS_SPK2_FLEXIPORT_TELEMETRY] = PIOS_BOARD_IO_UART_TELEMETRY, [HWSETTINGS_SPK2_FLEXIPORT_GPS] = PIOS_BOARD_IO_UART_GPS, [HWSETTINGS_SPK2_FLEXIPORT_DSM] = PIOS_BOARD_IO_UART_DSM_FLEXI, - [HWSETTINGS_SPK2_FLEXIPORT_EXBUS] = PIOS_BOARD_IO_UART_EXBUS, - [HWSETTINGS_SPK2_FLEXIPORT_HOTTSUMD] = PIOS_BOARD_IO_UART_HOTT_SUMD, - [HWSETTINGS_SPK2_FLEXIPORT_HOTTSUMH] = PIOS_BOARD_IO_UART_HOTT_SUMH, + [HWSETTINGS_SPK2_FLEXIPORT_EXBUS] = PIOS_BOARD_IO_UART_EXBUS, + [HWSETTINGS_SPK2_FLEXIPORT_HOTTSUMD] = PIOS_BOARD_IO_UART_HOTT_SUMD, + [HWSETTINGS_SPK2_FLEXIPORT_HOTTSUMH] = PIOS_BOARD_IO_UART_HOTT_SUMH, [HWSETTINGS_SPK2_FLEXIPORT_SRXL] = PIOS_BOARD_IO_UART_SRXL, [HWSETTINGS_SPK2_FLEXIPORT_IBUS] = PIOS_BOARD_IO_UART_IBUS, - [HWSETTINGS_SPK2_FLEXIPORT_DEBUGCONSOLE] = PIOS_BOARD_IO_UART_DEBUGCONSOLE, - [HWSETTINGS_SPK2_FLEXIPORT_COMBRIDGE] = PIOS_BOARD_IO_UART_COMBRIDGE, - [HWSETTINGS_SPK2_FLEXIPORT_OSDHK] = PIOS_BOARD_IO_UART_OSDHK, + [HWSETTINGS_SPK2_FLEXIPORT_DEBUGCONSOLE] = PIOS_BOARD_IO_UART_DEBUGCONSOLE, + [HWSETTINGS_SPK2_FLEXIPORT_COMBRIDGE] = PIOS_BOARD_IO_UART_COMBRIDGE, + [HWSETTINGS_SPK2_FLEXIPORT_OSDHK] = PIOS_BOARD_IO_UART_OSDHK, [HWSETTINGS_SPK2_FLEXIPORT_MSP] = PIOS_BOARD_IO_UART_MSP, - [HWSETTINGS_SPK2_FLEXIPORT_MAVLINK] = PIOS_BOARD_IO_UART_MAVLINK, + [HWSETTINGS_SPK2_FLEXIPORT_MAVLINK] = PIOS_BOARD_IO_UART_MAVLINK, + [HWSETTINGS_SPK2_FLEXIPORT_FRSKYSENSORHUB] = PIOS_BOARD_IO_UART_FRSKY_SENSORHUB, }; /** diff --git a/shared/uavobjectdefinition/hwsettings.xml b/shared/uavobjectdefinition/hwsettings.xml index 0f4aa1b75d..10a3c0b6d7 100644 --- a/shared/uavobjectdefinition/hwsettings.xml +++ b/shared/uavobjectdefinition/hwsettings.xml @@ -2,7 +2,7 @@ Selection of optional hardware configurations. - + @@ -11,15 +11,15 @@ - - - + limits="%0905NE:PPM+PWM:PPM+Telemetry:PPM+DebugConsole:PPM+ComBridge:PPM+MSP:PPM+MAVLink:PPM+GPS:PPM+HoTT Telemetry:Telemetry:DebugConsole:ComBridge:MSP:MAVLink:GPS:HoTT Telemetry:IBus;"/> + + - - + + @@ -29,12 +29,12 @@ - + - - + + diff --git a/shared/uavobjectdefinition/taskinfo.xml b/shared/uavobjectdefinition/taskinfo.xml index 57a98354f4..6748754217 100644 --- a/shared/uavobjectdefinition/taskinfo.xml +++ b/shared/uavobjectdefinition/taskinfo.xml @@ -1,7 +1,7 @@ - Task information - + Task information + System @@ -33,8 +33,9 @@ OSDGen UAVOHoTTBridge UAVOMSPBridge - AutoTune + UAVOFrskySensorHubBridge UAVOMAVLinkBridge + AutoTune @@ -69,8 +70,9 @@ OSDGen UAVOHoTTBridge UAVOMSPBridge - AutoTune + UAVOFrskySensorHubBridge UAVOMAVLinkBridge + AutoTune @@ -109,8 +111,9 @@ OSDGen UAVOHoTTBridge UAVOMSPBridge - AutoTune + UAVOFrskySensorHubBridge UAVOMAVLinkBridge + AutoTune From 8edd7c1d7cbe1bbba450380ba13e9a8d9a604ae9 Mon Sep 17 00:00:00 2001 From: Vladimir Zidar Date: Thu, 18 May 2017 12:39:03 +0200 Subject: [PATCH 260/624] LP-519 F1: revert pios_sys.c clock management. Due to older (than f3 & f4) gpio architecture, we should not allow clocks for multiple peripherals with alternate functions routed to same io pin. --- flight/pios/stm32f10x/pios_sys.c | 57 +++--------------------------- flight/pios/stm32f10x/pios_usart.c | 3 ++ 2 files changed, 7 insertions(+), 53 deletions(-) diff --git a/flight/pios/stm32f10x/pios_sys.c b/flight/pios/stm32f10x/pios_sys.c index 012e6b7301..849bb83cdb 100644 --- a/flight/pios/stm32f10x/pios_sys.c +++ b/flight/pios/stm32f10x/pios_sys.c @@ -53,63 +53,14 @@ void PIOS_SYS_Init(void) /* Init the delay system */ PIOS_DELAY_Init(); - /* - * Turn on all the peripheral clocks. - * Micromanaging clocks makes no sense given the power situation in the system, so - * light up everything we might reasonably use here and just leave it on. - */ - + /* Enable DMA */ RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1 | RCC_AHBPeriph_DMA2, ENABLE); - RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 | - RCC_APB1Periph_TIM3 | - RCC_APB1Periph_TIM4 | - RCC_APB1Periph_TIM5 | - RCC_APB1Periph_TIM6 | - RCC_APB1Periph_TIM7 | - RCC_APB1Periph_TIM12 | - RCC_APB1Periph_TIM13 | - RCC_APB1Periph_TIM14 | - RCC_APB1Periph_WWDG | - RCC_APB1Periph_SPI2 | - RCC_APB1Periph_SPI3 | - RCC_APB1Periph_USART2 | - RCC_APB1Periph_USART3 | - RCC_APB1Periph_UART4 | - RCC_APB1Periph_UART5 | - RCC_APB1Periph_I2C1 | - RCC_APB1Periph_I2C2 | - RCC_APB1Periph_USB | -// RCC_APB1Periph_CAN1 | /* bxCAN unfortunately interferes with USB */ -// RCC_APB1Periph_CAN2 | - RCC_APB1Periph_BKP | - RCC_APB1Periph_PWR | - RCC_APB1Periph_DAC, - ENABLE); - - - RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | - RCC_APB2Periph_GPIOB | - RCC_APB2Periph_GPIOC | - RCC_APB2Periph_GPIOD | - RCC_APB2Periph_GPIOE | - RCC_APB2Periph_ADC1 | - RCC_APB2Periph_ADC2 | - RCC_APB2Periph_ADC3 | - RCC_APB2Periph_TIM1 | - RCC_APB2Periph_TIM8 | - RCC_APB2Periph_TIM9 | - RCC_APB2Periph_TIM10 | - RCC_APB2Periph_TIM11 | - RCC_APB2Periph_TIM15 | - RCC_APB2Periph_TIM16 | - RCC_APB2Periph_TIM17 | - RCC_APB2Periph_SPI1 | - RCC_APB2Periph_USART1 | - RCC_APB2Periph_AFIO, - ENABLE); + /* Enable GPIOA, GPIOB, GPIOC, GPIOD, GPIOE and AFIO clocks */ + RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE | + RCC_APB2Periph_AFIO, ENABLE); #if (PIOS_USB_ENABLED) /* Ensure that pull-up is active on detect pin */ diff --git a/flight/pios/stm32f10x/pios_usart.c b/flight/pios/stm32f10x/pios_usart.c index 4f3881ac34..5b051efada 100644 --- a/flight/pios/stm32f10x/pios_usart.c +++ b/flight/pios/stm32f10x/pios_usart.c @@ -211,14 +211,17 @@ int32_t PIOS_USART_Init(uint32_t *usart_id, const struct pios_usart_cfg *cfg) case (uint32_t)USART1: PIOS_USART_1_id = (uint32_t)usart_dev; usart_dev->irq_channel = USART1_IRQn; + RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); break; case (uint32_t)USART2: PIOS_USART_2_id = (uint32_t)usart_dev; usart_dev->irq_channel = USART2_IRQn; + RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); break; case (uint32_t)USART3: PIOS_USART_3_id = (uint32_t)usart_dev; usart_dev->irq_channel = USART3_IRQn; + RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE); break; } From fc6f426e2caf336277afd2bdaba9bd338267d45f Mon Sep 17 00:00:00 2001 From: Vladimir Zidar Date: Thu, 18 May 2017 12:40:53 +0200 Subject: [PATCH 261/624] LP-519 F1: Manage GPIO_Mode from pios_servo.c to allow universal timer pin configuration with TIM_SERVO_CHANNEL_CONFIG() macro. --- flight/pios/common/pios_servo.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/flight/pios/common/pios_servo.c b/flight/pios/common/pios_servo.c index 6352734345..d0ca5f6b91 100644 --- a/flight/pios/common/pios_servo.c +++ b/flight/pios/common/pios_servo.c @@ -142,19 +142,22 @@ static void PIOS_Servo_SetupBank(uint8_t bank_nr) continue; } + GPIO_InitTypeDef init = chan->pin.init; + switch (bank->mode) { case PIOS_SERVO_BANK_MODE_PWM: case PIOS_SERVO_BANK_MODE_SINGLE_PULSE: - GPIO_Init(chan->pin.gpio, &chan->pin.init); #if defined(STM32F40_41xxx) || defined(STM32F446xx) || defined(STM32F411xE) GPIO_PinAFConfig(chan->pin.gpio, chan->pin.pin_source, chan->remap); #elif defined(STM32F10X_MD) + init.GPIO_Mode = GPIO_Mode_AF_PP; if (chan->remap) { GPIO_PinRemapConfig(chan->remap, ENABLE); } #else #error Unsupported MCU #endif + GPIO_Init(chan->pin.gpio, &init); /* Set up for output compare function */ switch (chan->timer_chan) { @@ -180,8 +183,6 @@ static void PIOS_Servo_SetupBank(uint8_t bank_nr) case PIOS_SERVO_BANK_MODE_DSHOT: { - GPIO_InitTypeDef init = chan->pin.init; - #if defined(STM32F40_41xxx) || defined(STM32F446xx) || defined(STM32F411xE) init.GPIO_Mode = GPIO_Mode_OUT; #elif defined(STM32F10X_MD) From 659b7d07339457c2946c784f533a88e6041c46ff Mon Sep 17 00:00:00 2001 From: Vladimir Zidar Date: Thu, 25 May 2017 13:39:28 +0200 Subject: [PATCH 262/624] LP-512 STM's standard libraries for F30x (CMSIS, StdPeriph and USB Device) --- .../pios/stm32f30x/libraries/.no-auto-format | 0 .../Device/ST/STM32F30x/Include/stm32f30x.h | 9086 +++++++++++++++++ .../ST/STM32F30x/Include/system_stm32f30x.h | 76 + .../inc/stm32f30x_adc.h | 820 ++ .../inc/stm32f30x_can.h | 643 ++ .../inc/stm32f30x_comp.h | 435 + .../inc/stm32f30x_crc.h | 121 + .../inc/stm32f30x_dac.h | 322 + .../inc/stm32f30x_dbgmcu.h | 110 + .../inc/stm32f30x_dma.h | 436 + .../inc/stm32f30x_exti.h | 234 + .../inc/stm32f30x_flash.h | 334 + .../inc/stm32f30x_fmc.h | 722 ++ .../inc/stm32f30x_gpio.h | 404 + .../inc/stm32f30x_hrtim.h | 2741 +++++ .../inc/stm32f30x_i2c.h | 477 + .../inc/stm32f30x_iwdg.h | 153 + .../inc/stm32f30x_misc.h | 204 + .../inc/stm32f30x_opamp.h | 277 + .../inc/stm32f30x_pwr.h | 187 + .../inc/stm32f30x_rcc.h | 731 ++ .../inc/stm32f30x_rtc.h | 852 ++ .../inc/stm32f30x_spi.h | 608 ++ .../inc/stm32f30x_syscfg.h | 427 + .../inc/stm32f30x_tim.h | 1360 +++ .../inc/stm32f30x_usart.h | 607 ++ .../inc/stm32f30x_wwdg.h | 109 + .../src/stm32f30x_adc.c | 2401 +++++ .../src/stm32f30x_can.c | 1629 +++ .../src/stm32f30x_comp.c | 507 + .../src/stm32f30x_crc.c | 354 + .../src/stm32f30x_dac.c | 754 ++ .../src/stm32f30x_dbgmcu.c | 216 + .../src/stm32f30x_dma.c | 866 ++ .../src/stm32f30x_exti.c | 349 + .../src/stm32f30x_flash.c | 1186 +++ .../src/stm32f30x_fmc.c | 1001 ++ .../src/stm32f30x_gpio.c | 545 + .../src/stm32f30x_hrtim.c | 4103 ++++++++ .../src/stm32f30x_i2c.c | 1585 +++ .../src/stm32f30x_iwdg.c | 288 + .../src/stm32f30x_misc.c | 230 + .../src/stm32f30x_opamp.c | 575 ++ .../src/stm32f30x_pwr.c | 538 + .../src/stm32f30x_rcc.c | 2017 ++++ .../src/stm32f30x_rtc.c | 2598 +++++ .../src/stm32f30x_spi.c | 1417 +++ .../src/stm32f30x_syscfg.c | 569 ++ .../src/stm32f30x_tim.c | 4006 ++++++++ .../src/stm32f30x_usart.c | 2084 ++++ .../src/stm32f30x_wwdg.c | 304 + .../STM32_USB-FS-Device_Driver/inc/usb_core.h | 259 + .../STM32_USB-FS-Device_Driver/inc/usb_def.h | 92 + .../STM32_USB-FS-Device_Driver/inc/usb_init.h | 62 + .../STM32_USB-FS-Device_Driver/inc/usb_int.h | 45 + .../STM32_USB-FS-Device_Driver/inc/usb_lib.h | 52 + .../STM32_USB-FS-Device_Driver/inc/usb_mem.h | 45 + .../STM32_USB-FS-Device_Driver/inc/usb_regs.h | 680 ++ .../STM32_USB-FS-Device_Driver/inc/usb_sil.h | 47 + .../STM32_USB-FS-Device_Driver/inc/usb_type.h | 54 + .../STM32_USB-FS-Device_Driver/src/usb_core.c | 1033 ++ .../STM32_USB-FS-Device_Driver/src/usb_init.c | 76 + .../STM32_USB-FS-Device_Driver/src/usb_int.c | 195 + .../STM32_USB-FS-Device_Driver/src/usb_mem.c | 87 + .../STM32_USB-FS-Device_Driver/src/usb_regs.c | 760 ++ .../STM32_USB-FS-Device_Driver/src/usb_sil.c | 103 + 66 files changed, 56188 insertions(+) create mode 100644 flight/pios/stm32f30x/libraries/.no-auto-format create mode 100644 flight/pios/stm32f30x/libraries/CMSIS3/Device/ST/STM32F30x/Include/stm32f30x.h create mode 100644 flight/pios/stm32f30x/libraries/CMSIS3/Device/ST/STM32F30x/Include/system_stm32f30x.h create mode 100755 flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_adc.h create mode 100755 flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_can.h create mode 100755 flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_comp.h create mode 100755 flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_crc.h create mode 100755 flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_dac.h create mode 100755 flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_dbgmcu.h create mode 100755 flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_dma.h create mode 100755 flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_exti.h create mode 100755 flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_flash.h create mode 100755 flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_fmc.h create mode 100755 flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_gpio.h create mode 100755 flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_hrtim.h create mode 100755 flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_i2c.h create mode 100755 flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_iwdg.h create mode 100755 flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_misc.h create mode 100755 flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_opamp.h create mode 100755 flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_pwr.h create mode 100755 flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_rcc.h create mode 100755 flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_rtc.h create mode 100755 flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_spi.h create mode 100755 flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_syscfg.h create mode 100755 flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_tim.h create mode 100755 flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_usart.h create mode 100755 flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_wwdg.h create mode 100755 flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_adc.c create mode 100755 flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_can.c create mode 100755 flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_comp.c create mode 100755 flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_crc.c create mode 100755 flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_dac.c create mode 100755 flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_dbgmcu.c create mode 100755 flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_dma.c create mode 100755 flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_exti.c create mode 100755 flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_flash.c create mode 100755 flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_fmc.c create mode 100755 flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_gpio.c create mode 100755 flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_hrtim.c create mode 100755 flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_i2c.c create mode 100755 flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_iwdg.c create mode 100755 flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_misc.c create mode 100755 flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_opamp.c create mode 100755 flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_pwr.c create mode 100755 flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_rcc.c create mode 100755 flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_rtc.c create mode 100755 flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_spi.c create mode 100755 flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_syscfg.c create mode 100755 flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_tim.c create mode 100755 flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_usart.c create mode 100755 flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_wwdg.c create mode 100755 flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/inc/usb_core.h create mode 100755 flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/inc/usb_def.h create mode 100755 flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/inc/usb_init.h create mode 100755 flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/inc/usb_int.h create mode 100755 flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/inc/usb_lib.h create mode 100755 flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/inc/usb_mem.h create mode 100755 flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/inc/usb_regs.h create mode 100755 flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/inc/usb_sil.h create mode 100755 flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/inc/usb_type.h create mode 100755 flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/src/usb_core.c create mode 100755 flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/src/usb_init.c create mode 100755 flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/src/usb_int.c create mode 100755 flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/src/usb_mem.c create mode 100755 flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/src/usb_regs.c create mode 100755 flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/src/usb_sil.c diff --git a/flight/pios/stm32f30x/libraries/.no-auto-format b/flight/pios/stm32f30x/libraries/.no-auto-format new file mode 100644 index 0000000000..e69de29bb2 diff --git a/flight/pios/stm32f30x/libraries/CMSIS3/Device/ST/STM32F30x/Include/stm32f30x.h b/flight/pios/stm32f30x/libraries/CMSIS3/Device/ST/STM32F30x/Include/stm32f30x.h new file mode 100644 index 0000000000..7683e7376d --- /dev/null +++ b/flight/pios/stm32f30x/libraries/CMSIS3/Device/ST/STM32F30x/Include/stm32f30x.h @@ -0,0 +1,9086 @@ +/** + ****************************************************************************** + * @file stm32f30x.h + * @author MCD Application Team + * @version V1.2.2 + * @date 27-February-2015 + * @brief CMSIS Cortex-M4 Device Peripheral Access Layer Header File. + * This file contains all the peripheral registers definitions, bits + * definitions and memory mapping for STM32F30x devices. + * + * The file is the unique include file that the application programmer + * is using in the C source code, usually in main.c. This file contains: + * - Configuration section that allows to select: + * - The device used in the target application + * - To use or not the peripheral’s drivers in application code(i.e. + * code will be based on direct access to peripheral’s registers + * rather than drivers API), this option is controlled by + * "#define USE_STDPERIPH_DRIVER" + * - To change few application-specific parameters such as the HSE + * crystal frequency + * - Data structures and the address mapping for all peripherals + * - Peripheral registers declarations and bits definition + * - Macros to access peripheral registers hardware + * + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/** @addtogroup CMSIS + * @{ + */ + +/** @addtogroup stm32f30x + * @{ + */ + +#ifndef __STM32F30x_H +#define __STM32F30x_H + +#ifdef __cplusplus + extern "C" { +#endif /* __cplusplus */ + +/** @addtogroup Library_configuration_section + * @{ + */ + +/* Uncomment the line below according to the target STM32 device used in your + application + */ + +/* Old STM32F30X definition, maintained for legacy purpose */ +#if defined(STM32F30X) + #define STM32F303xC +#endif /* STM32F30X */ + +#if !defined (STM32F303xC) && !defined (STM32F334x8) && !defined (STM32F302x8) && !defined (STM32F303xE) +/* #define STM32F303xC */ /*!< STM32F303CB, STM32F303CC, STM32F303RB, STM32F303RC, STM32F303VB, STM32F303VC + STM32F302CB, STM32F302CC, STM32F302RC, STM32F302RB, STM32F302VC, STM32F302VB, + STM32F358CC, STM32F358RC and STM32F358VC Devices */ +/* #define STM32F334x8 */ /*!< STM32F334C4, STM32F334K4, STM32F334C6, STM32F334R6, STM32F334K6, STM32F334C8, STM32F334R8, STM32F334K8, + STM32F303K8, STM32F303K6, STM32F303C8, STM32F303C6, STM32F303R8, STM32F303R6 and STM32F328C8 Devices */ +/* #define STM32F302x8 */ /*!< STM32F302K6, STM32F302K8, STM32F302C6, STM32F302C8, STM32F302R6, STM32F302R8, + STM32F301K8, STM32F301C8, STM32F301R8, STM32F301K6, STM32F301C6, STM32F301R6, STM32F313K8 and STM32F318C8 Devices */ +/* #define STM32F303xE */ /*!< STM32F303CE, STM32F303CD, STM32F303RE, STM32F303RD, STM32F303VE, STM32F303VD, STM32F303ZE, + STM32F303ZD, STM32F302CE, STM32F302CD, STM32F302RE, STM32F302RD, STM32F302VE, STM32F302ZE, + STM32F302ZD and STM32F398VE Devices */ +#endif /* STM32F303xC || STM32F334x8 || STM32F302x8 || STM32F303xE */ + + +/* Tip: To avoid modifying this file each time you need to switch between these + devices, you can define the device in your toolchain compiler preprocessor. + */ + +#if !defined (STM32F303xC) && !defined (STM32F334x8) && !defined (STM32F302x8) && !defined (STM32F303xE) + #error "Please select first the target STM32F30X device used in your application (in stm32f30x.h file)" +#endif + +#if !defined (USE_STDPERIPH_DRIVER) +/** + * @brief Comment the line below if you will not use the peripherals drivers. + In this case, these drivers will not be included and the application code will + be based on direct access to peripherals registers + */ + /* #define USE_STDPERIPH_DRIVER */ +#endif /* USE_STDPERIPH_DRIVER */ + +/** + * @brief In the following line adjust the value of External High Speed oscillator (HSE) + used in your application + + Tip: To avoid modifying this file each time you need to use different HSE, you + can define the HSE value in your toolchain compiler preprocessor. + */ +#if !defined (HSE_VALUE) + #define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +/** + * @brief In the following line adjust the External High Speed oscillator (HSE) Startup + Timeout value + */ +#if !defined (HSE_STARTUP_TIMEOUT) + #define HSE_STARTUP_TIMEOUT ((uint16_t)0x5000) /*!< Time out for HSE start up */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief In the following line adjust the Internal High Speed oscillator (HSI) Startup + Timeout value + */ +#if !defined (HSI_STARTUP_TIMEOUT) + #define HSI_STARTUP_TIMEOUT ((uint16_t)0x5000) /*!< Time out for HSI start up */ +#endif /* HSI_STARTUP_TIMEOUT */ + +#if !defined (HSI_VALUE) + #define HSI_VALUE ((uint32_t)8000000) +#endif /* HSI_VALUE */ /*!< Value of the Internal High Speed oscillator in Hz. + The real value may vary depending on the variations + in voltage and temperature. */ +#if !defined (LSI_VALUE) + #define LSI_VALUE ((uint32_t)40000) +#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz + The real value may vary depending on the variations + in voltage and temperature. */ +#if !defined (LSE_VALUE) + #define LSE_VALUE ((uint32_t)32768) /*!< Value of the External Low Speed oscillator in Hz */ +#endif /* LSE_VALUE */ + + +/** + * @brief STM32F30x Standard Peripherals Library version number V1.2.2 + */ +#define __STM32F30X_STDPERIPH_VERSION_MAIN (0x01) /*!< [31:24] main version */ +#define __STM32F30X_STDPERIPH_VERSION_SUB1 (0x02) /*!< [23:16] sub1 version */ +#define __STM32F30X_STDPERIPH_VERSION_SUB2 (0x02) /*!< [15:8] sub2 version */ +#define __STM32F30X_STDPERIPH_VERSION_RC (0x00) /*!< [7:0] release candidate */ +#define __STM32F30X_STDPERIPH_VERSION ( (__STM32F30X_STDPERIPH_VERSION_MAIN << 24)\ + |(__STM32F30X_STDPERIPH_VERSION_SUB1 << 16)\ + |(__STM32F30X_STDPERIPH_VERSION_SUB2 << 8)\ + |(__STM32F30X_STDPERIPH_VERSION_RC)) + +/** + * @} + */ + +/** @addtogroup Configuration_section_for_CMSIS + * @{ + */ + +/** + * @brief Configuration of the Cortex-M4 Processor and Core Peripherals + */ +#define __CM4_REV 0x0001 /*!< Core revision r0p1 */ +#define __MPU_PRESENT 1 /*!< STM32F30X provide an MPU */ +#define __NVIC_PRIO_BITS 4 /*!< STM32F30X uses 4 Bits for the Priority Levels */ +#define __Vendor_SysTickConfig 0 /*!< Set to 1 if different SysTick Config is used */ +#define __FPU_PRESENT 1 /*!< STM32F30X provide an FPU */ + + +/** + * @brief STM32F30X Interrupt Number Definition, according to the selected device + * in @ref Library_configuration_section + */ +typedef enum IRQn +{ +/****** Cortex-M4 Processor Exceptions Numbers ****************************************************************/ + NonMaskableInt_IRQn = -14, /*!< 2 Non Maskable Interrupt */ + MemoryManagement_IRQn = -12, /*!< 4 Cortex-M4 Memory Management Interrupt */ + BusFault_IRQn = -11, /*!< 5 Cortex-M4 Bus Fault Interrupt */ + UsageFault_IRQn = -10, /*!< 6 Cortex-M4 Usage Fault Interrupt */ + SVCall_IRQn = -5, /*!< 11 Cortex-M4 SV Call Interrupt */ + DebugMonitor_IRQn = -4, /*!< 12 Cortex-M4 Debug Monitor Interrupt */ + PendSV_IRQn = -2, /*!< 14 Cortex-M4 Pend SV Interrupt */ + SysTick_IRQn = -1, /*!< 15 Cortex-M4 System Tick Interrupt */ +/****** STM32 specific Interrupt Numbers **********************************************************************/ +#ifdef STM32F303xC + WWDG_IRQn = 0, /*!< Window WatchDog Interrupt */ + PVD_IRQn = 1, /*!< PVD through EXTI Line detection Interrupt */ + TAMPER_STAMP_IRQn = 2, /*!< Tamper and TimeStamp interrupts */ + RTC_WKUP_IRQn = 3, /*!< RTC Wakeup interrupt through the EXTI lines 17, 19 & 20 */ + FLASH_IRQn = 4, /*!< FLASH global Interrupt */ + RCC_IRQn = 5, /*!< RCC global Interrupt */ + EXTI0_IRQn = 6, /*!< EXTI Line0 Interrupt */ + EXTI1_IRQn = 7, /*!< EXTI Line1 Interrupt */ + EXTI2_TS_IRQn = 8, /*!< EXTI Line2 Interrupt and Touch Sense Interrupt */ + EXTI3_IRQn = 9, /*!< EXTI Line3 Interrupt */ + EXTI4_IRQn = 10, /*!< EXTI Line4 Interrupt */ + DMA1_Channel1_IRQn = 11, /*!< DMA1 Channel 1 Interrupt */ + DMA1_Channel2_IRQn = 12, /*!< DMA1 Channel 2 Interrupt */ + DMA1_Channel3_IRQn = 13, /*!< DMA1 Channel 3 Interrupt */ + DMA1_Channel4_IRQn = 14, /*!< DMA1 Channel 4 Interrupt */ + DMA1_Channel5_IRQn = 15, /*!< DMA1 Channel 5 Interrupt */ + DMA1_Channel6_IRQn = 16, /*!< DMA1 Channel 6 Interrupt */ + DMA1_Channel7_IRQn = 17, /*!< DMA1 Channel 7 Interrupt */ + ADC1_2_IRQn = 18, /*!< ADC1 & ADC2 Interrupts */ + USB_HP_CAN1_TX_IRQn = 19, /*!< USB Device High Priority or CAN1 TX Interrupts */ + USB_LP_CAN1_RX0_IRQn = 20, /*!< USB Device Low Priority or CAN1 RX0 Interrupts */ + CAN1_RX1_IRQn = 21, /*!< CAN1 RX1 Interrupt */ + CAN1_SCE_IRQn = 22, /*!< CAN1 SCE Interrupt */ + EXTI9_5_IRQn = 23, /*!< External Line[9:5] Interrupts */ + TIM1_BRK_TIM15_IRQn = 24, /*!< TIM1 Break and TIM15 Interrupts */ + TIM1_UP_TIM16_IRQn = 25, /*!< TIM1 Update and TIM16 Interrupts */ + TIM1_TRG_COM_TIM17_IRQn = 26, /*!< TIM1 Trigger and Commutation and TIM17 Interrupt */ + TIM1_CC_IRQn = 27, /*!< TIM1 Capture Compare Interrupt */ + TIM2_IRQn = 28, /*!< TIM2 global Interrupt */ + TIM3_IRQn = 29, /*!< TIM3 global Interrupt */ + TIM4_IRQn = 30, /*!< TIM4 global Interrupt */ + I2C1_EV_IRQn = 31, /*!< I2C1 Event Interrupt */ + I2C1_ER_IRQn = 32, /*!< I2C1 Error Interrupt */ + I2C2_EV_IRQn = 33, /*!< I2C2 Event Interrupt */ + I2C2_ER_IRQn = 34, /*!< I2C2 Error Interrupt */ + SPI1_IRQn = 35, /*!< SPI1 global Interrupt */ + SPI2_IRQn = 36, /*!< SPI2 global Interrupt */ + USART1_IRQn = 37, /*!< USART1 global Interrupt */ + USART2_IRQn = 38, /*!< USART2 global Interrupt */ + USART3_IRQn = 39, /*!< USART3 global Interrupt */ + EXTI15_10_IRQn = 40, /*!< External Line[15:10] Interrupts */ + RTC_Alarm_IRQn = 41, /*!< RTC Alarm (A and B) through EXTI Line Interrupt */ + USBWakeUp_IRQn = 42, /*!< USB Wakeup Interrupt */ + TIM8_BRK_IRQn = 43, /*!< TIM8 Break Interrupt */ + TIM8_UP_IRQn = 44, /*!< TIM8 Update Interrupt */ + TIM8_TRG_COM_IRQn = 45, /*!< TIM8 Trigger and Commutation Interrupt */ + TIM8_CC_IRQn = 46, /*!< TIM8 Capture Compare Interrupt */ + ADC3_IRQn = 47, /*!< ADC3 global Interrupt */ + SPI3_IRQn = 51, /*!< SPI3 global Interrupt */ + UART4_IRQn = 52, /*!< UART4 global Interrupt */ + UART5_IRQn = 53, /*!< UART5 global Interrupt */ + TIM6_DAC_IRQn = 54, /*!< TIM6 global and DAC1&2 underrun error interrupts */ + TIM7_IRQn = 55, /*!< TIM7 global Interrupt */ + DMA2_Channel1_IRQn = 56, /*!< DMA2 Channel 1 global Interrupt */ + DMA2_Channel2_IRQn = 57, /*!< DMA2 Channel 2 global Interrupt */ + DMA2_Channel3_IRQn = 58, /*!< DMA2 Channel 3 global Interrupt */ + DMA2_Channel4_IRQn = 59, /*!< DMA2 Channel 4 global Interrupt */ + DMA2_Channel5_IRQn = 60, /*!< DMA2 Channel 5 global Interrupt */ + ADC4_IRQn = 61, /*!< ADC4 global Interrupt */ + COMP1_2_3_IRQn = 64, /*!< COMP1, COMP2 and COMP3 global Interrupt */ + COMP4_5_6_IRQn = 65, /*!< COMP5, COMP6 and COMP4 global Interrupt */ + COMP7_IRQn = 66, /*!< COMP7 global Interrupt */ + USB_HP_IRQn = 74, /*!< USB High Priority global Interrupt remap */ + USB_LP_IRQn = 75, /*!< USB Low Priority global Interrupt remap */ + USBWakeUp_RMP_IRQn = 76, /*!< USB Wakeup Interrupt remap */ + FPU_IRQn = 81 /*!< Floating point Interrupt */ +#endif /* STM32F303xC */ +#ifdef STM32F334x8 + WWDG_IRQn = 0, /*!< Window WatchDog Interrupt */ + PVD_IRQn = 1, /*!< PVD through EXTI Line detection Interrupt */ + TAMPER_STAMP_IRQn = 2, /*!< Tamper and TimeStamp interrupts */ + RTC_WKUP_IRQn = 3, /*!< RTC Wakeup interrupt through the EXTI lines 17, 19 & 20 */ + FLASH_IRQn = 4, /*!< FLASH global Interrupt */ + RCC_IRQn = 5, /*!< RCC global Interrupt */ + EXTI0_IRQn = 6, /*!< EXTI Line0 Interrupt */ + EXTI1_IRQn = 7, /*!< EXTI Line1 Interrupt */ + EXTI2_TS_IRQn = 8, /*!< EXTI Line2 Interrupt and Touch Sense Interrupt */ + EXTI3_IRQn = 9, /*!< EXTI Line3 Interrupt */ + EXTI4_IRQn = 10, /*!< EXTI Line4 Interrupt */ + DMA1_Channel1_IRQn = 11, /*!< DMA1 Channel 1 Interrupt */ + DMA1_Channel2_IRQn = 12, /*!< DMA1 Channel 2 Interrupt */ + DMA1_Channel3_IRQn = 13, /*!< DMA1 Channel 3 Interrupt */ + DMA1_Channel4_IRQn = 14, /*!< DMA1 Channel 4 Interrupt */ + DMA1_Channel5_IRQn = 15, /*!< DMA1 Channel 5 Interrupt */ + DMA1_Channel6_IRQn = 16, /*!< DMA1 Channel 6 Interrupt */ + DMA1_Channel7_IRQn = 17, /*!< DMA1 Channel 7 Interrupt */ + ADC1_2_IRQn = 18, /*!< ADC1 & ADC2 Interrupts */ + CAN1_TX_IRQn = 19, /*!< CAN1 TX Interrupts */ + CAN1_RX0_IRQn = 20, /*!< CAN1 RX0 Interrupts */ + CAN1_RX1_IRQn = 21, /*!< CAN1 RX1 Interrupt */ + CAN1_SCE_IRQn = 22, /*!< CAN1 SCE Interrupt */ + EXTI9_5_IRQn = 23, /*!< External Line[9:5] Interrupts */ + TIM1_BRK_TIM15_IRQn = 24, /*!< TIM1 Break and TIM15 Interrupts */ + TIM1_UP_TIM16_IRQn = 25, /*!< TIM1 Update and TIM16 Interrupts */ + TIM1_TRG_COM_TIM17_IRQn = 26, /*!< TIM1 Trigger and Commutation and TIM17 Interrupt */ + TIM1_CC_IRQn = 27, /*!< TIM1 Capture Compare Interrupt */ + TIM2_IRQn = 28, /*!< TIM2 global Interrupt */ + TIM3_IRQn = 29, /*!< TIM3 global Interrupt */ + I2C1_EV_IRQn = 31, /*!< I2C1 Event Interrupt */ + I2C1_ER_IRQn = 32, /*!< I2C1 Error Interrupt */ + SPI1_IRQn = 35, /*!< SPI1 global Interrupt */ + USART1_IRQn = 37, /*!< USART1 global Interrupt */ + USART2_IRQn = 38, /*!< USART2 global Interrupt */ + USART3_IRQn = 39, /*!< USART3 global Interrupt */ + EXTI15_10_IRQn = 40, /*!< External Line[15:10] Interrupts */ + RTC_Alarm_IRQn = 41, /*!< RTC Alarm (A and B) through EXTI Line Interrupt */ + TIM6_DAC1_IRQn = 54, /*!< TIM6 global and DAC1 underrun error interrupts */ + TIM7_DAC2_IRQn = 55, /*!< TIM7 global and DAC2 underrun error Interrupt */ + COMP2_IRQn = 64, /*!< COMP2 global Interrupt */ + COMP4_6_IRQn = 65, /*!< COMP6 and COMP4 global Interrupt */ + HRTIM1_Master_IRQn = 67, /*!< HRTIM Master Timer global Interrupts */ + HRTIM1_TIMA_IRQn = 68, /*!< HRTIM Timer A global Interrupt */ + HRTIM1_TIMB_IRQn = 69, /*!< HRTIM Timer B global Interrupt */ + HRTIM1_TIMC_IRQn = 70, /*!< HRTIM Timer C global Interrupt */ + HRTIM1_TIMD_IRQn = 71, /*!< HRTIM Timer D global Interrupt */ + HRTIM1_TIME_IRQn = 72, /*!< HRTIM Timer E global Interrupt */ + HRTIM1_FLT_IRQn = 73, /*!< HRTIM Fault global Interrupt */ + FPU_IRQn = 81 /*!< Floating point Interrupt */ +#endif /* STM32F334x8 */ +#ifdef STM32F302x8 + WWDG_IRQn = 0, /*!< Window WatchDog Interrupt */ + PVD_IRQn = 1, /*!< PVD through EXTI Line detection Interrupt */ + TAMPER_STAMP_IRQn = 2, /*!< Tamper and TimeStamp interrupts */ + RTC_WKUP_IRQn = 3, /*!< RTC Wakeup interrupt through the EXTI lines 20 */ + FLASH_IRQn = 4, /*!< FLASH global Interrupt */ + RCC_IRQn = 5, /*!< RCC global Interrupt */ + EXTI0_IRQn = 6, /*!< EXTI Line0 Interrupt */ + EXTI1_IRQn = 7, /*!< EXTI Line1 Interrupt */ + EXTI2_TS_IRQn = 8, /*!< EXTI Line2 Interrupt and Touch Sense Interrupt */ + EXTI3_IRQn = 9, /*!< EXTI Line3 Interrupt */ + EXTI4_IRQn = 10, /*!< EXTI Line4 Interrupt */ + DMA1_Channel1_IRQn = 11, /*!< DMA1 Channel 1 Interrupt */ + DMA1_Channel2_IRQn = 12, /*!< DMA1 Channel 2 Interrupt */ + DMA1_Channel3_IRQn = 13, /*!< DMA1 Channel 3 Interrupt */ + DMA1_Channel4_IRQn = 14, /*!< DMA1 Channel 4 Interrupt */ + DMA1_Channel5_IRQn = 15, /*!< DMA1 Channel 5 Interrupt */ + DMA1_Channel6_IRQn = 16, /*!< DMA1 Channel 6 Interrupt */ + DMA1_Channel7_IRQn = 17, /*!< DMA1 Channel 7 Interrupt */ + ADC1_IRQn = 18, /*!< ADC1 Interrupts */ + USB_HP_CAN1_TX_IRQn = 19, /*!< USB Device High Priority or CAN1 TX Interrupts */ + USB_LP_CAN1_RX0_IRQn = 20, /*!< USB Device Low Priority or CAN1 RX0 Interrupts */ + CAN1_RX1_IRQn = 21, /*!< CAN1 RX1 Interrupt */ + CAN1_SCE_IRQn = 22, /*!< CAN1 SCE Interrupt */ + EXTI9_5_IRQn = 23, /*!< External Line[9:5] Interrupts */ + TIM1_BRK_TIM15_IRQn = 24, /*!< TIM1 Break and TIM15 Interrupts */ + TIM1_UP_TIM16_IRQn = 25, /*!< TIM1 Update and TIM16 Interrupts */ + TIM1_TRG_COM_TIM17_IRQn = 26, /*!< TIM1 Trigger and Commutation and TIM17 Interrupt */ + TIM1_CC_IRQn = 27, /*!< TIM1 Capture Compare Interrupt */ + TIM2_IRQn = 28, /*!< TIM2 global Interrupt */ + I2C1_EV_IRQn = 31, /*!< I2C1 Event Interrupt */ + I2C1_ER_IRQn = 32, /*!< I2C1 Error Interrupt */ + I2C2_EV_IRQn = 33, /*!< I2C2 Event Interrupt */ + I2C2_ER_IRQn = 34, /*!< I2C2 Error Interrupt */ + SPI2_IRQn = 36, /*!< SPI2 global Interrupt */ + USART1_IRQn = 37, /*!< USART1 global Interrupt */ + USART2_IRQn = 38, /*!< USART2 global Interrupt */ + USART3_IRQn = 39, /*!< USART3 global Interrupt */ + EXTI15_10_IRQn = 40, /*!< External Line[15:10] Interrupts */ + RTC_Alarm_IRQn = 41, /*!< RTC Alarm (A and B) through EXTI Line Interrupt */ + USBWakeUp_IRQn = 42, /*!< USB Wakeup Interrupt */ + SPI3_IRQn = 51, /*!< SPI3 global Interrupt */ + TIM6_DAC_IRQn = 54, /*!< TIM6 global and DAC1&2 underrun error interrupts */ + COMP2_IRQn = 64, /*!< COMP2 global Interrupt */ + COMP4_6_IRQn = 65, /*!< COMP5, COMP6 and COMP4 global Interrupt */ + COMP7_IRQn = 66, /*!< COMP7 global Interrupt */ + I2C3_EV_IRQn = 72, /*!< I2C3 Event Interrupt */ + I2C3_ER_IRQn = 73, /*!< I2C3 Error Interrupt */ + USB_HP_IRQn = 74, /*!< USB High Priority global Interrupt remap */ + USB_LP_IRQn = 75, /*!< USB Low Priority global Interrupt remap */ + USBWakeUp_RMP_IRQn = 76, /*!< USB Wakeup Interrupt remap */ + FPU_IRQn = 81 /*!< Floating point Interrupt */ +#endif /* STM32F302x8 */ +#ifdef STM32F303xE + WWDG_IRQn = 0, /*!< Window WatchDog Interrupt */ + PVD_IRQn = 1, /*!< PVD through EXTI Line detection Interrupt */ + TAMPER_STAMP_IRQn = 2, /*!< Tamper and TimeStamp interrupts */ + RTC_WKUP_IRQn = 3, /*!< RTC Wakeup interrupt through the EXTI lines 17, 19 & 20 */ + FLASH_IRQn = 4, /*!< FLASH global Interrupt */ + RCC_IRQn = 5, /*!< RCC global Interrupt */ + EXTI0_IRQn = 6, /*!< EXTI Line0 Interrupt */ + EXTI1_IRQn = 7, /*!< EXTI Line1 Interrupt */ + EXTI2_TS_IRQn = 8, /*!< EXTI Line2 Interrupt and Touch Sense Interrupt */ + EXTI3_IRQn = 9, /*!< EXTI Line3 Interrupt */ + EXTI4_IRQn = 10, /*!< EXTI Line4 Interrupt */ + DMA1_Channel1_IRQn = 11, /*!< DMA1 Channel 1 Interrupt */ + DMA1_Channel2_IRQn = 12, /*!< DMA1 Channel 2 Interrupt */ + DMA1_Channel3_IRQn = 13, /*!< DMA1 Channel 3 Interrupt */ + DMA1_Channel4_IRQn = 14, /*!< DMA1 Channel 4 Interrupt */ + DMA1_Channel5_IRQn = 15, /*!< DMA1 Channel 5 Interrupt */ + DMA1_Channel6_IRQn = 16, /*!< DMA1 Channel 6 Interrupt */ + DMA1_Channel7_IRQn = 17, /*!< DMA1 Channel 7 Interrupt */ + ADC1_2_IRQn = 18, /*!< ADC1 & ADC2 Interrupts */ + USB_HP_CAN1_TX_IRQn = 19, /*!< USB Device High Priority or CAN1 TX Interrupts */ + USB_LP_CAN1_RX0_IRQn = 20, /*!< USB Device Low Priority or CAN1 RX0 Interrupts */ + CAN1_RX1_IRQn = 21, /*!< CAN1 RX1 Interrupt */ + CAN1_SCE_IRQn = 22, /*!< CAN1 SCE Interrupt */ + EXTI9_5_IRQn = 23, /*!< External Line[9:5] Interrupts */ + TIM1_BRK_TIM15_IRQn = 24, /*!< TIM1 Break and TIM15 Interrupts */ + TIM1_UP_TIM16_IRQn = 25, /*!< TIM1 Update and TIM16 Interrupts */ + TIM1_TRG_COM_TIM17_IRQn = 26, /*!< TIM1 Trigger and Commutation and TIM17 Interrupt */ + TIM1_CC_IRQn = 27, /*!< TIM1 Capture Compare Interrupt */ + TIM2_IRQn = 28, /*!< TIM2 global Interrupt */ + TIM3_IRQn = 29, /*!< TIM3 global Interrupt */ + TIM4_IRQn = 30, /*!< TIM4 global Interrupt */ + I2C1_EV_IRQn = 31, /*!< I2C1 Event Interrupt */ + I2C1_ER_IRQn = 32, /*!< I2C1 Error Interrupt */ + I2C2_EV_IRQn = 33, /*!< I2C2 Event Interrupt */ + I2C2_ER_IRQn = 34, /*!< I2C2 Error Interrupt */ + SPI1_IRQn = 35, /*!< SPI1 global Interrupt */ + SPI2_IRQn = 36, /*!< SPI2 global Interrupt */ + USART1_IRQn = 37, /*!< USART1 global Interrupt */ + USART2_IRQn = 38, /*!< USART2 global Interrupt */ + USART3_IRQn = 39, /*!< USART3 global Interrupt */ + EXTI15_10_IRQn = 40, /*!< External Line[15:10] Interrupts */ + RTC_Alarm_IRQn = 41, /*!< RTC Alarm (A and B) through EXTI Line Interrupt */ + USBWakeUp_IRQn = 42, /*!< USB Wakeup Interrupt */ + TIM8_BRK_IRQn = 43, /*!< TIM8 Break Interrupt */ + TIM8_UP_IRQn = 44, /*!< TIM8 Update Interrupt */ + TIM8_TRG_COM_IRQn = 45, /*!< TIM8 Trigger and Commutation Interrupt */ + TIM8_CC_IRQn = 46, /*!< TIM8 Capture Compare Interrupt */ + ADC3_IRQn = 47, /*!< ADC3 global Interrupt */ + FMC_IRQn = 48, /*!< FMC global Interrupt */ + SPI3_IRQn = 51, /*!< SPI3 global Interrupt */ + UART4_IRQn = 52, /*!< UART4 global Interrupt */ + UART5_IRQn = 53, /*!< UART5 global Interrupt */ + TIM6_DAC_IRQn = 54, /*!< TIM6 global and DAC1&2 underrun error interrupts */ + TIM7_IRQn = 55, /*!< TIM7 global Interrupt */ + DMA2_Channel1_IRQn = 56, /*!< DMA2 Channel 1 global Interrupt */ + DMA2_Channel2_IRQn = 57, /*!< DMA2 Channel 2 global Interrupt */ + DMA2_Channel3_IRQn = 58, /*!< DMA2 Channel 3 global Interrupt */ + DMA2_Channel4_IRQn = 59, /*!< DMA2 Channel 4 global Interrupt */ + DMA2_Channel5_IRQn = 60, /*!< DMA2 Channel 5 global Interrupt */ + ADC4_IRQn = 61, /*!< ADC4 global Interrupt */ + COMP1_2_3_IRQn = 64, /*!< COMP1, COMP2 and COMP3 global Interrupt */ + COMP4_5_6_IRQn = 65, /*!< COMP5, COMP6 and COMP4 global Interrupt */ + COMP7_IRQn = 66, /*!< COMP7 global Interrupt */ + I2C3_EV_IRQn = 72, /*!< I2C3 event interrupt */ + I2C3_ER_IRQn = 73, /*!< I2C3 error interrupt */ + USB_HP_IRQn = 74, /*!< USB High Priority global Interrupt remap */ + USB_LP_IRQn = 75, /*!< USB Low Priority global Interrupt remap */ + USBWakeUp_RMP_IRQn = 76, /*!< USB Wakeup Interrupt remap */ + TIM20_BRK_IRQn = 77, /*!< TIM20 Break Interrupt */ + TIM20_UP_IRQn = 78, /*!< TIM20 Update Interrupt */ + TIM20_TRG_COM_IRQn = 79, /*!< TIM20 Trigger and Commutation Interrupt */ + TIM20_CC_IRQn = 80, /*!< TIM20 Capture Compare Interrupt */ + FPU_IRQn = 81, /*!< Floating point Interrupt */ + SPI4_IRQn = 84 /*!< SPI4 global Interrupt */ +#endif /* STM32F303xE */ +} IRQn_Type; + +/** + * @} + */ + +#include "core_cm4.h" /* Cortex-M4 processor and core peripherals */ +#include "system_stm32f30x.h" /* STM32F30x System Header */ +#include + +/** @addtogroup Exported_types + * @{ + */ +/*!< STM32F10x Standard Peripheral Library old types (maintained for legacy purpose) */ +typedef int32_t s32; +typedef int16_t s16; +typedef int8_t s8; + +typedef const int32_t sc32; /*!< Read Only */ +typedef const int16_t sc16; /*!< Read Only */ +typedef const int8_t sc8; /*!< Read Only */ + +typedef __IO int32_t vs32; +typedef __IO int16_t vs16; +typedef __IO int8_t vs8; + +typedef __I int32_t vsc32; /*!< Read Only */ +typedef __I int16_t vsc16; /*!< Read Only */ +typedef __I int8_t vsc8; /*!< Read Only */ + +typedef uint32_t u32; +typedef uint16_t u16; +typedef uint8_t u8; + +typedef const uint32_t uc32; /*!< Read Only */ +typedef const uint16_t uc16; /*!< Read Only */ +typedef const uint8_t uc8; /*!< Read Only */ + +typedef __IO uint32_t vu32; +typedef __IO uint16_t vu16; +typedef __IO uint8_t vu8; + +typedef __I uint32_t vuc32; /*!< Read Only */ +typedef __I uint16_t vuc16; /*!< Read Only */ +typedef __I uint8_t vuc8; /*!< Read Only */ + +typedef enum {RESET = 0, SET = !RESET} FlagStatus, ITStatus; + +typedef enum {DISABLE = 0, ENABLE = !DISABLE} FunctionalState; +#define IS_FUNCTIONAL_STATE(STATE) (((STATE) == DISABLE) || ((STATE) == ENABLE)) + +typedef enum {ERROR = 0, SUCCESS = !ERROR} ErrorStatus; + +/** + * @} + */ + +/** @addtogroup Peripheral_registers_structures + * @{ + */ + +/** + * @brief Analog to Digital Converter + */ + +typedef struct +{ + __IO uint32_t ISR; /*!< ADC Interrupt and Status Register, Address offset: 0x00 */ + __IO uint32_t IER; /*!< ADC Interrupt Enable Register, Address offset: 0x04 */ + __IO uint32_t CR; /*!< ADC control register, Address offset: 0x08 */ + __IO uint32_t CFGR; /*!< ADC Configuration register, Address offset: 0x0C */ + uint32_t RESERVED0; /*!< Reserved, 0x010 */ + __IO uint32_t SMPR1; /*!< ADC sample time register 1, Address offset: 0x14 */ + __IO uint32_t SMPR2; /*!< ADC sample time register 2, Address offset: 0x18 */ + uint32_t RESERVED1; /*!< Reserved, 0x01C */ + __IO uint32_t TR1; /*!< ADC watchdog threshold register 1, Address offset: 0x20 */ + __IO uint32_t TR2; /*!< ADC watchdog threshold register 2, Address offset: 0x24 */ + __IO uint32_t TR3; /*!< ADC watchdog threshold register 3, Address offset: 0x28 */ + uint32_t RESERVED2; /*!< Reserved, 0x02C */ + __IO uint32_t SQR1; /*!< ADC regular sequence register 1, Address offset: 0x30 */ + __IO uint32_t SQR2; /*!< ADC regular sequence register 2, Address offset: 0x34 */ + __IO uint32_t SQR3; /*!< ADC regular sequence register 3, Address offset: 0x38 */ + __IO uint32_t SQR4; /*!< ADC regular sequence register 4, Address offset: 0x3C */ + __IO uint32_t DR; /*!< ADC regular data register, Address offset: 0x40 */ + uint32_t RESERVED3; /*!< Reserved, 0x044 */ + uint32_t RESERVED4; /*!< Reserved, 0x048 */ + __IO uint32_t JSQR; /*!< ADC injected sequence register, Address offset: 0x4C */ + uint32_t RESERVED5[4]; /*!< Reserved, 0x050 - 0x05C */ + __IO uint32_t OFR1; /*!< ADC offset register 1, Address offset: 0x60 */ + __IO uint32_t OFR2; /*!< ADC offset register 2, Address offset: 0x64 */ + __IO uint32_t OFR3; /*!< ADC offset register 3, Address offset: 0x68 */ + __IO uint32_t OFR4; /*!< ADC offset register 4, Address offset: 0x6C */ + uint32_t RESERVED6[4]; /*!< Reserved, 0x070 - 0x07C */ + __IO uint32_t JDR1; /*!< ADC injected data register 1, Address offset: 0x80 */ + __IO uint32_t JDR2; /*!< ADC injected data register 2, Address offset: 0x84 */ + __IO uint32_t JDR3; /*!< ADC injected data register 3, Address offset: 0x88 */ + __IO uint32_t JDR4; /*!< ADC injected data register 4, Address offset: 0x8C */ + uint32_t RESERVED7[4]; /*!< Reserved, 0x090 - 0x09C */ + __IO uint32_t AWD2CR; /*!< ADC Analog Watchdog 2 Configuration Register, Address offset: 0xA0 */ + __IO uint32_t AWD3CR; /*!< ADC Analog Watchdog 3 Configuration Register, Address offset: 0xA4 */ + uint32_t RESERVED8; /*!< Reserved, 0x0A8 */ + uint32_t RESERVED9; /*!< Reserved, 0x0AC */ + __IO uint32_t DIFSEL; /*!< ADC Differential Mode Selection Register, Address offset: 0xB0 */ + __IO uint32_t CALFACT; /*!< ADC Calibration Factors, Address offset: 0xB4 */ + +} ADC_TypeDef; + +typedef struct +{ + __IO uint32_t CSR; /*!< ADC Common status register, Address offset: ADC1/3 base address + 0x300 */ + uint32_t RESERVED; /*!< Reserved, ADC1/3 base address + 0x304 */ + __IO uint32_t CCR; /*!< ADC common control register, Address offset: ADC1/3 base address + 0x308 */ + __IO uint32_t CDR; /*!< ADC common regular data register for dual + modes, Address offset: ADC1/3 base address + 0x30A */ +} ADC_Common_TypeDef; + + +/** + * @brief Controller Area Network TxMailBox + */ +typedef struct +{ + __IO uint32_t TIR; /*!< CAN TX mailbox identifier register */ + __IO uint32_t TDTR; /*!< CAN mailbox data length control and time stamp register */ + __IO uint32_t TDLR; /*!< CAN mailbox data low register */ + __IO uint32_t TDHR; /*!< CAN mailbox data high register */ +} CAN_TxMailBox_TypeDef; + +/** + * @brief Controller Area Network FIFOMailBox + */ +typedef struct +{ + __IO uint32_t RIR; /*!< CAN receive FIFO mailbox identifier register */ + __IO uint32_t RDTR; /*!< CAN receive FIFO mailbox data length control and time stamp register */ + __IO uint32_t RDLR; /*!< CAN receive FIFO mailbox data low register */ + __IO uint32_t RDHR; /*!< CAN receive FIFO mailbox data high register */ +} CAN_FIFOMailBox_TypeDef; + +/** + * @brief Controller Area Network FilterRegister + */ +typedef struct +{ + __IO uint32_t FR1; /*!< CAN Filter bank register 1 */ + __IO uint32_t FR2; /*!< CAN Filter bank register 1 */ +} CAN_FilterRegister_TypeDef; + +/** + * @brief Controller Area Network + */ +typedef struct +{ + __IO uint32_t MCR; /*!< CAN master control register, Address offset: 0x00 */ + __IO uint32_t MSR; /*!< CAN master status register, Address offset: 0x04 */ + __IO uint32_t TSR; /*!< CAN transmit status register, Address offset: 0x08 */ + __IO uint32_t RF0R; /*!< CAN receive FIFO 0 register, Address offset: 0x0C */ + __IO uint32_t RF1R; /*!< CAN receive FIFO 1 register, Address offset: 0x10 */ + __IO uint32_t IER; /*!< CAN interrupt enable register, Address offset: 0x14 */ + __IO uint32_t ESR; /*!< CAN error status register, Address offset: 0x18 */ + __IO uint32_t BTR; /*!< CAN bit timing register, Address offset: 0x1C */ + uint32_t RESERVED0[88]; /*!< Reserved, 0x020 - 0x17F */ + CAN_TxMailBox_TypeDef sTxMailBox[3]; /*!< CAN Tx MailBox, Address offset: 0x180 - 0x1AC */ + CAN_FIFOMailBox_TypeDef sFIFOMailBox[2]; /*!< CAN FIFO MailBox, Address offset: 0x1B0 - 0x1CC */ + uint32_t RESERVED1[12]; /*!< Reserved, 0x1D0 - 0x1FF */ + __IO uint32_t FMR; /*!< CAN filter master register, Address offset: 0x200 */ + __IO uint32_t FM1R; /*!< CAN filter mode register, Address offset: 0x204 */ + uint32_t RESERVED2; /*!< Reserved, 0x208 */ + __IO uint32_t FS1R; /*!< CAN filter scale register, Address offset: 0x20C */ + uint32_t RESERVED3; /*!< Reserved, 0x210 */ + __IO uint32_t FFA1R; /*!< CAN filter FIFO assignment register, Address offset: 0x214 */ + uint32_t RESERVED4; /*!< Reserved, 0x218 */ + __IO uint32_t FA1R; /*!< CAN filter activation register, Address offset: 0x21C */ + uint32_t RESERVED5[8]; /*!< Reserved, 0x220-0x23F */ + CAN_FilterRegister_TypeDef sFilterRegister[28]; /*!< CAN Filter Register, Address offset: 0x240-0x31C */ +} CAN_TypeDef; + + +/** + * @brief Analog Comparators + */ + +typedef struct +{ + __IO uint32_t CSR; /*!< Comparator control Status register, Address offset: 0x00 */ +} COMP_TypeDef; + +/** + * @brief CRC calculation unit + */ + +typedef struct +{ + __IO uint32_t DR; /*!< CRC Data register, Address offset: 0x00 */ + __IO uint8_t IDR; /*!< CRC Independent data register, Address offset: 0x04 */ + uint8_t RESERVED0; /*!< Reserved, 0x05 */ + uint16_t RESERVED1; /*!< Reserved, 0x06 */ + __IO uint32_t CR; /*!< CRC Control register, Address offset: 0x08 */ + uint32_t RESERVED2; /*!< Reserved, 0x0C */ + __IO uint32_t INIT; /*!< Initial CRC value register, Address offset: 0x10 */ + __IO uint32_t POL; /*!< CRC polynomial register, Address offset: 0x14 */ +} CRC_TypeDef; + +/** + * @brief Digital to Analog Converter + */ + +typedef struct +{ + __IO uint32_t CR; /*!< DAC control register, Address offset: 0x00 */ + __IO uint32_t SWTRIGR; /*!< DAC software trigger register, Address offset: 0x04 */ + __IO uint32_t DHR12R1; /*!< DAC channel1 12-bit right-aligned data holding register, Address offset: 0x08 */ + __IO uint32_t DHR12L1; /*!< DAC channel1 12-bit left aligned data holding register, Address offset: 0x0C */ + __IO uint32_t DHR8R1; /*!< DAC channel1 8-bit right aligned data holding register, Address offset: 0x10 */ + __IO uint32_t DHR12R2; /*!< DAC channel2 12-bit right aligned data holding register, Address offset: 0x14 */ + __IO uint32_t DHR12L2; /*!< DAC channel2 12-bit left aligned data holding register, Address offset: 0x18 */ + __IO uint32_t DHR8R2; /*!< DAC channel2 8-bit right-aligned data holding register, Address offset: 0x1C */ + __IO uint32_t DHR12RD; /*!< Dual DAC 12-bit right-aligned data holding register, Address offset: 0x20 */ + __IO uint32_t DHR12LD; /*!< DUAL DAC 12-bit left aligned data holding register, Address offset: 0x24 */ + __IO uint32_t DHR8RD; /*!< DUAL DAC 8-bit right aligned data holding register, Address offset: 0x28 */ + __IO uint32_t DOR1; /*!< DAC channel1 data output register, Address offset: 0x2C */ + __IO uint32_t DOR2; /*!< DAC channel2 data output register, Address offset: 0x30 */ + __IO uint32_t SR; /*!< DAC status register, Address offset: 0x34 */ +} DAC_TypeDef; + +/** + * @brief Debug MCU + */ + +typedef struct +{ + __IO uint32_t IDCODE; /*!< MCU device ID code, Address offset: 0x00 */ + __IO uint32_t CR; /*!< Debug MCU configuration register, Address offset: 0x04 */ + __IO uint32_t APB1FZ; /*!< Debug MCU APB1 freeze register, Address offset: 0x08 */ + __IO uint32_t APB2FZ; /*!< Debug MCU APB2 freeze register, Address offset: 0x0C */ +}DBGMCU_TypeDef; + +/** + * @brief DMA Controller + */ + +typedef struct +{ + __IO uint32_t CCR; /*!< DMA channel x configuration register */ + __IO uint32_t CNDTR; /*!< DMA channel x number of data register */ + __IO uint32_t CPAR; /*!< DMA channel x peripheral address register */ + __IO uint32_t CMAR; /*!< DMA channel x memory address register */ +} DMA_Channel_TypeDef; + +typedef struct +{ + __IO uint32_t ISR; /*!< DMA interrupt status register, Address offset: 0x00 */ + __IO uint32_t IFCR; /*!< DMA interrupt clear flag register, Address offset: 0x04 */ +} DMA_TypeDef; + +/** + * @brief External Interrupt/Event Controller + */ + +typedef struct +{ + __IO uint32_t IMR; /*!< EXTI Interrupt mask register, Address offset: 0x00 */ + __IO uint32_t EMR; /*!< EXTI Event mask register, Address offset: 0x04 */ + __IO uint32_t RTSR; /*!< EXTI Rising trigger selection register, Address offset: 0x08 */ + __IO uint32_t FTSR; /*!< EXTI Falling trigger selection register, Address offset: 0x0C */ + __IO uint32_t SWIER; /*!< EXTI Software interrupt event register, Address offset: 0x10 */ + __IO uint32_t PR; /*!< EXTI Pending register, Address offset: 0x14 */ + uint32_t RESERVED1; /*!< Reserved, 0x18 */ + uint32_t RESERVED2; /*!< Reserved, 0x1C */ + __IO uint32_t IMR2; /*!< EXTI Interrupt mask register, Address offset: 0x20 */ + __IO uint32_t EMR2; /*!< EXTI Event mask register, Address offset: 0x24 */ + __IO uint32_t RTSR2; /*!< EXTI Rising trigger selection register, Address offset: 0x28 */ + __IO uint32_t FTSR2; /*!< EXTI Falling trigger selection register, Address offset: 0x2C */ + __IO uint32_t SWIER2; /*!< EXTI Software interrupt event register, Address offset: 0x30 */ + __IO uint32_t PR2; /*!< EXTI Pending register, Address offset: 0x34 */ +}EXTI_TypeDef; + +/** + * @brief FLASH Registers + */ + +typedef struct +{ + __IO uint32_t ACR; /*!< FLASH access control register, Address offset: 0x00 */ + __IO uint32_t KEYR; /*!< FLASH key register, Address offset: 0x04 */ + __IO uint32_t OPTKEYR; /*!< FLASH option key register, Address offset: 0x08 */ + __IO uint32_t SR; /*!< FLASH status register, Address offset: 0x0C */ + __IO uint32_t CR; /*!< FLASH control register, Address offset: 0x10 */ + __IO uint32_t AR; /*!< FLASH address register, Address offset: 0x14 */ + uint32_t RESERVED; /*!< Reserved, 0x18 */ + __IO uint32_t OBR; /*!< FLASH Option byte register, Address offset: 0x1C */ + __IO uint32_t WRPR; /*!< FLASH Write register, Address offset: 0x20 */ + +} FLASH_TypeDef; + +/** + * @brief Flexible Memory Controller + */ + +typedef struct +{ + __IO uint32_t BTCR[8]; /*!< NOR/PSRAM chip-select control register(BCR) and chip-select timing register(BTR), Address offset: 0x00-1C */ +} FMC_Bank1_TypeDef; + +/** + * @brief Flexible Memory Controller Bank1E + */ + +typedef struct +{ + __IO uint32_t BWTR[7]; /*!< NOR/PSRAM write timing registers, Address offset: 0x104-0x11C */ +} FMC_Bank1E_TypeDef; + +/** + * @brief Flexible Memory Controller Bank2 + */ + +typedef struct +{ + __IO uint32_t PCR2; /*!< NAND Flash control register 2, Address offset: 0x60 */ + __IO uint32_t SR2; /*!< NAND Flash FIFO status and interrupt register 2, Address offset: 0x64 */ + __IO uint32_t PMEM2; /*!< NAND Flash Common memory space timing register 2, Address offset: 0x68 */ + __IO uint32_t PATT2; /*!< NAND Flash Attribute memory space timing register 2, Address offset: 0x6C */ + uint32_t RESERVED0; /*!< Reserved, 0x70 */ + __IO uint32_t ECCR2; /*!< NAND Flash ECC result registers 2, Address offset: 0x74 */ +} FMC_Bank2_TypeDef; + +/** + * @brief Flexible Memory Controller Bank3 + */ + +typedef struct +{ + __IO uint32_t PCR3; /*!< NAND Flash control register 3, Address offset: 0x80 */ + __IO uint32_t SR3; /*!< NAND Flash FIFO status and interrupt register 3, Address offset: 0x84 */ + __IO uint32_t PMEM3; /*!< NAND Flash Common memory space timing register 3, Address offset: 0x88 */ + __IO uint32_t PATT3; /*!< NAND Flash Attribute memory space timing register 3, Address offset: 0x8C */ + uint32_t RESERVED0; /*!< Reserved, 0x90 */ + __IO uint32_t ECCR3; /*!< NAND Flash ECC result registers 3, Address offset: 0x94 */ +} FMC_Bank3_TypeDef; + +/** + * @brief Flexible Memory Controller Bank4 + */ + +typedef struct +{ + __IO uint32_t PCR4; /*!< PC Card control register 4, Address offset: 0xA0 */ + __IO uint32_t SR4; /*!< PC Card FIFO status and interrupt register 4, Address offset: 0xA4 */ + __IO uint32_t PMEM4; /*!< PC Card Common memory space timing register 4, Address offset: 0xA8 */ + __IO uint32_t PATT4; /*!< PC Card Attribute memory space timing register 4, Address offset: 0xAC */ + __IO uint32_t PIO4; /*!< PC Card I/O space timing register 4, Address offset: 0xB0 */ +} FMC_Bank4_TypeDef; + +/** + * @brief Option Bytes Registers + */ +typedef struct +{ + __IO uint16_t RDP; /*!
© COPYRIGHT 2015 STMicroelectronics
+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/** @addtogroup CMSIS + * @{ + */ + +/** @addtogroup stm32f30x_system + * @{ + */ + +/** + * @brief Define to prevent recursive inclusion + */ +#ifndef __SYSTEM_STM32F30X_H +#define __SYSTEM_STM32F30X_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Exported types ------------------------------------------------------------*/ +extern uint32_t SystemCoreClock; /*!< System Clock Frequency (Core Clock) */ +/* Exported constants --------------------------------------------------------*/ +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions ------------------------------------------------------- */ + +/** @addtogroup STM32F30x_System_Exported_Functions + * @{ + */ + +extern void SystemInit(void); +extern void SystemCoreClockUpdate(void); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /*__SYSTEM_STM32F30X_H */ + +/** + * @} + */ + +/** + * @} + */ +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_adc.h b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_adc.h new file mode 100755 index 0000000000..00724e95a1 --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_adc.h @@ -0,0 +1,820 @@ +/** + ****************************************************************************** + * @file stm32f30x_adc.h + * @author MCD Application Team + * @version V1.2.3 + * @date 10-July-2015 + * @brief This file contains all the functions prototypes for the ADC firmware + * library. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F30x_ADC_H +#define __STM32F30x_ADC_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f30x.h" + +/** @addtogroup STM32F30x_StdPeriph_Driver + * @{ + */ + +/** @addtogroup ADC + * @{ + */ + +/* Exported types ------------------------------------------------------------*/ + +/** + * @brief ADC Init structure definition + */ +typedef struct +{ + + uint32_t ADC_ContinuousConvMode; /*!< Specifies whether the conversion is performed in + Continuous or Single mode. + This parameter can be set to ENABLE or DISABLE. */ + uint32_t ADC_Resolution; /*!< Configures the ADC resolution. + This parameter can be a value of @ref ADC_resolution */ + uint32_t ADC_ExternalTrigConvEvent; /*!< Defines the external trigger used to start the analog + to digital conversion of regular channels. This parameter + can be a value of @ref ADC_external_trigger_sources_for_regular_channels_conversion */ + uint32_t ADC_ExternalTrigEventEdge; /*!< Select the external trigger edge and enable the trigger of a regular group. + This parameter can be a value of + @ref ADC_external_trigger_edge_for_regular_channels_conversion */ + uint32_t ADC_DataAlign; /*!< Specifies whether the ADC data alignment is left or right. + This parameter can be a value of @ref ADC_data_align */ + uint32_t ADC_OverrunMode; /*!< Specifies the way data overrun are managed. + This parameter can be set to ENABLE or DISABLE. */ + uint32_t ADC_AutoInjMode; /*!< Enable/disable automatic injected group conversion after + regular group conversion. + This parameter can be set to ENABLE or DISABLE. */ + uint8_t ADC_NbrOfRegChannel; /*!< Specifies the number of ADC channels that will be converted + using the sequencer for regular channel group. + This parameter must range from 1 to 16. */ +}ADC_InitTypeDef; + +/** + * @} + */ +/** + * @brief ADC Init structure definition + */ +typedef struct +{ + + uint32_t ADC_ExternalTrigInjecConvEvent; /*!< Defines the external trigger used to start the analog + to digital conversion of injected channels. This parameter + can be a value of @ref ADC_external_trigger_sources_for_Injected_channels_conversion */ + uint32_t ADC_ExternalTrigInjecEventEdge; /*!< Select the external trigger edge and enable the trigger of an injected group. + This parameter can be a value of + @ref ADC_external_trigger_edge_for_Injected_channels_conversion */ + uint8_t ADC_NbrOfInjecChannel; /*!< Specifies the number of ADC channels that will be converted + using the sequencer for injected channel group. + This parameter must range from 1 to 4. */ + uint32_t ADC_InjecSequence1; + uint32_t ADC_InjecSequence2; + uint32_t ADC_InjecSequence3; + uint32_t ADC_InjecSequence4; +}ADC_InjectedInitTypeDef; + +/** + * @} + */ +typedef struct +{ + uint32_t ADC_Mode; /*!< Configures the ADC to operate in + independent or multi mode. + This parameter can be a value of @ref ADC_mode */ + uint32_t ADC_Clock; /*!< Select the clock of the ADC. The clock is common for both master + and slave ADCs. + This parameter can be a value of @ref ADC_Clock */ + uint32_t ADC_DMAAccessMode; /*!< Configures the Direct memory access mode for multi ADC mode. + This parameter can be a value of + @ref ADC_Direct_memory_access_mode_for_multi_mode */ + uint32_t ADC_DMAMode; /*!< Configures the DMA mode for ADC. + This parameter can be a value of @ref ADC_DMA_Mode_definition */ + uint8_t ADC_TwoSamplingDelay; /*!< Configures the Delay between 2 sampling phases. + This parameter can be a value between 0x0 and 0xF */ + +}ADC_CommonInitTypeDef; + +/* Exported constants --------------------------------------------------------*/ + +/** @defgroup ADC_Exported_Constants + * @{ + */ + +#define IS_ADC_ALL_PERIPH(PERIPH) (((PERIPH) == ADC1) || \ + ((PERIPH) == ADC2) || \ + ((PERIPH) == ADC3) || \ + ((PERIPH) == ADC4)) + +#define IS_ADC_DMA_PERIPH(PERIPH) (((PERIPH) == ADC1) || \ + ((PERIPH) == ADC2) || \ + ((PERIPH) == ADC3) || \ + ((PERIPH) == ADC4)) + +/** @defgroup ADC_ContinuousConvMode + * @{ + */ +#define ADC_ContinuousConvMode_Enable ((uint32_t)0x00002000) /*!< ADC continuous conversion mode enable */ +#define ADC_ContinuousConvMode_Disable ((uint32_t)0x00000000) /*!< ADC continuous conversion mode disable */ +#define IS_ADC_CONVMODE(MODE) (((MODE) == ADC_ContinuousConvMode_Enable) || \ + ((MODE) == ADC_ContinuousConvMode_Disable)) +/** + * @} + */ +/** @defgroup ADC_OverunMode + * @{ + */ +#define ADC_OverrunMode_Enable ((uint32_t)0x00001000) /*!< ADC Overrun Mode enable */ +#define ADC_OverrunMode_Disable ((uint32_t)0x00000000) /*!< ADC Overrun Mode disable */ +#define IS_ADC_OVRUNMODE(MODE) (((MODE) == ADC_OverrunMode_Enable) || \ + ((MODE) == ADC_OverrunMode_Disable)) +/** + * @} + */ +/** @defgroup ADC_AutoInjecMode + * @{ + */ +#define ADC_AutoInjec_Enable ((uint32_t)0x02000000) /*!< ADC Auto injected Mode enable */ +#define ADC_AutoInjec_Disable ((uint32_t)0x00000000) /*!< ADC Auto injected Mode disable */ +#define IS_ADC_AUTOINJECMODE(MODE) (((MODE) == ADC_AutoInjec_Enable) || \ + ((MODE) == ADC_AutoInjec_Disable)) +/** + * @} + */ +/** @defgroup ADC_resolution + * @{ + */ +#define ADC_Resolution_12b ((uint32_t)0x00000000) /*!< ADC 12-bit resolution */ +#define ADC_Resolution_10b ((uint32_t)0x00000008) /*!< ADC 10-bit resolution */ +#define ADC_Resolution_8b ((uint32_t)0x00000010) /*!< ADC 8-bit resolution */ +#define ADC_Resolution_6b ((uint32_t)0x00000018) /*!< ADC 6-bit resolution */ +#define IS_ADC_RESOLUTION(RESOLUTION) (((RESOLUTION) == ADC_Resolution_12b) || \ + ((RESOLUTION) == ADC_Resolution_10b) || \ + ((RESOLUTION) == ADC_Resolution_8b) || \ + ((RESOLUTION) == ADC_Resolution_6b)) + +/** + * @} + */ + + +/** @defgroup ADC_external_trigger_edge_for_regular_channels_conversion + * @{ + */ +#define ADC_ExternalTrigEventEdge_None ((uint16_t)0x0000) /*!< ADC No external trigger for regular conversion */ +#define ADC_ExternalTrigEventEdge_RisingEdge ((uint16_t)0x0400) /*!< ADC external trigger rising edge for regular conversion */ +#define ADC_ExternalTrigEventEdge_FallingEdge ((uint16_t)0x0800) /*!< ADC ADC external trigger falling edge for regular conversion */ +#define ADC_ExternalTrigEventEdge_BothEdge ((uint16_t)0x0C00) /*!< ADC ADC external trigger both edges for regular conversion */ + +#define IS_EXTERNALTRIG_EDGE(EDGE) (((EDGE) == ADC_ExternalTrigEventEdge_None) || \ + ((EDGE) == ADC_ExternalTrigEventEdge_RisingEdge) || \ + ((EDGE) == ADC_ExternalTrigEventEdge_FallingEdge) || \ + ((EDGE) == ADC_ExternalTrigEventEdge_BothEdge)) + +/** + * @} + */ + +/** @defgroup ADC_external_trigger_edge_for_Injected_channels_conversion + * @{ + */ +#define ADC_ExternalTrigInjecEventEdge_None ((uint16_t)0x0000) /*!< ADC No external trigger for regular conversion */ +#define ADC_ExternalTrigInjecEventEdge_RisingEdge ((uint16_t)0x0040) /*!< ADC external trigger rising edge for injected conversion */ +#define ADC_ExternalTrigInjecEventEdge_FallingEdge ((uint16_t)0x0080) /*!< ADC external trigger falling edge for injected conversion */ +#define ADC_ExternalTrigInjecEventEdge_BothEdge ((uint16_t)0x00C0) /*!< ADC external trigger both edges for injected conversion */ + +#define IS_EXTERNALTRIGINJ_EDGE(EDGE) (((EDGE) == ADC_ExternalTrigInjecEventEdge_None) || \ + ((EDGE) == ADC_ExternalTrigInjecEventEdge_RisingEdge) || \ + ((EDGE) == ADC_ExternalTrigInjecEventEdge_FallingEdge) || \ + ((EDGE) == ADC_ExternalTrigInjecEventEdge_BothEdge)) + +/** @defgroup ADC_external_trigger_sources_for_regular_channels_conversion + * @{ + */ +#define ADC_ExternalTrigConvEvent_0 ((uint16_t)0x0000) /*!< ADC external trigger event 0 */ +#define ADC_ExternalTrigConvEvent_1 ((uint16_t)0x0040) /*!< ADC external trigger event 1 */ +#define ADC_ExternalTrigConvEvent_2 ((uint16_t)0x0080) /*!< ADC external trigger event 2 */ +#define ADC_ExternalTrigConvEvent_3 ((uint16_t)0x00C0) /*!< ADC external trigger event 3 */ +#define ADC_ExternalTrigConvEvent_4 ((uint16_t)0x0100) /*!< ADC external trigger event 4 */ +#define ADC_ExternalTrigConvEvent_5 ((uint16_t)0x0140) /*!< ADC external trigger event 5 */ +#define ADC_ExternalTrigConvEvent_6 ((uint16_t)0x0180) /*!< ADC external trigger event 6 */ +#define ADC_ExternalTrigConvEvent_7 ((uint16_t)0x01C0) /*!< ADC external trigger event 7 */ +#define ADC_ExternalTrigConvEvent_8 ((uint16_t)0x0200) /*!< ADC external trigger event 8 */ +#define ADC_ExternalTrigConvEvent_9 ((uint16_t)0x0240) /*!< ADC external trigger event 9 */ +#define ADC_ExternalTrigConvEvent_10 ((uint16_t)0x0280) /*!< ADC external trigger event 10 */ +#define ADC_ExternalTrigConvEvent_11 ((uint16_t)0x02C0) /*!< ADC external trigger event 11 */ +#define ADC_ExternalTrigConvEvent_12 ((uint16_t)0x0300) /*!< ADC external trigger event 12 */ +#define ADC_ExternalTrigConvEvent_13 ((uint16_t)0x0340) /*!< ADC external trigger event 13 */ +#define ADC_ExternalTrigConvEvent_14 ((uint16_t)0x0380) /*!< ADC external trigger event 14 */ +#define ADC_ExternalTrigConvEvent_15 ((uint16_t)0x03C0) /*!< ADC external trigger event 15 */ + +#define IS_ADC_EXT_TRIG(REGTRIG) (((REGTRIG) == ADC_ExternalTrigConvEvent_0) || \ + ((REGTRIG) == ADC_ExternalTrigConvEvent_1) || \ + ((REGTRIG) == ADC_ExternalTrigConvEvent_2) || \ + ((REGTRIG) == ADC_ExternalTrigConvEvent_3) || \ + ((REGTRIG) == ADC_ExternalTrigConvEvent_4) || \ + ((REGTRIG) == ADC_ExternalTrigConvEvent_5) || \ + ((REGTRIG) == ADC_ExternalTrigConvEvent_6) || \ + ((REGTRIG) == ADC_ExternalTrigConvEvent_7) || \ + ((REGTRIG) == ADC_ExternalTrigConvEvent_8) || \ + ((REGTRIG) == ADC_ExternalTrigConvEvent_9) || \ + ((REGTRIG) == ADC_ExternalTrigConvEvent_10) || \ + ((REGTRIG) == ADC_ExternalTrigConvEvent_11) || \ + ((REGTRIG) == ADC_ExternalTrigConvEvent_12) || \ + ((REGTRIG) == ADC_ExternalTrigConvEvent_13) || \ + ((REGTRIG) == ADC_ExternalTrigConvEvent_14) || \ + ((REGTRIG) == ADC_ExternalTrigConvEvent_15)) + +/** + * @} + */ + +/** @defgroup ADC_external_trigger_sources_for_Injected_channels_conversion + * @{ + */ + +#define ADC_ExternalTrigInjecConvEvent_0 ((uint16_t)0x0000) /*!< ADC external trigger for injected conversion event 0 */ +#define ADC_ExternalTrigInjecConvEvent_1 ((uint16_t)0x0004) /*!< ADC external trigger for injected conversion event 1 */ +#define ADC_ExternalTrigInjecConvEvent_2 ((uint16_t)0x0008) /*!< ADC external trigger for injected conversion event 2 */ +#define ADC_ExternalTrigInjecConvEvent_3 ((uint16_t)0x000C) /*!< ADC external trigger for injected conversion event 3 */ +#define ADC_ExternalTrigInjecConvEvent_4 ((uint16_t)0x0010) /*!< ADC external trigger for injected conversion event 4 */ +#define ADC_ExternalTrigInjecConvEvent_5 ((uint16_t)0x0014) /*!< ADC external trigger for injected conversion event 5 */ +#define ADC_ExternalTrigInjecConvEvent_6 ((uint16_t)0x0018) /*!< ADC external trigger for injected conversion event 6 */ +#define ADC_ExternalTrigInjecConvEvent_7 ((uint16_t)0x001C) /*!< ADC external trigger for injected conversion event 7 */ +#define ADC_ExternalTrigInjecConvEvent_8 ((uint16_t)0x0020) /*!< ADC external trigger for injected conversion event 8 */ +#define ADC_ExternalTrigInjecConvEvent_9 ((uint16_t)0x0024) /*!< ADC external trigger for injected conversion event 9 */ +#define ADC_ExternalTrigInjecConvEvent_10 ((uint16_t)0x0028) /*!< ADC external trigger for injected conversion event 10 */ +#define ADC_ExternalTrigInjecConvEvent_11 ((uint16_t)0x002C) /*!< ADC external trigger for injected conversion event 11 */ +#define ADC_ExternalTrigInjecConvEvent_12 ((uint16_t)0x0030) /*!< ADC external trigger for injected conversion event 12 */ +#define ADC_ExternalTrigInjecConvEvent_13 ((uint16_t)0x0034) /*!< ADC external trigger for injected conversion event 13 */ +#define ADC_ExternalTrigInjecConvEvent_14 ((uint16_t)0x0038) /*!< ADC external trigger for injected conversion event 14 */ +#define ADC_ExternalTrigInjecConvEvent_15 ((uint16_t)0x003C) /*!< ADC external trigger for injected conversion event 15 */ + +#define IS_ADC_EXT_INJEC_TRIG(INJTRIG) (((INJTRIG) == ADC_ExternalTrigInjecConvEvent_0) || \ + ((INJTRIG) == ADC_ExternalTrigInjecConvEvent_1) || \ + ((INJTRIG) == ADC_ExternalTrigInjecConvEvent_2) || \ + ((INJTRIG) == ADC_ExternalTrigInjecConvEvent_3) || \ + ((INJTRIG) == ADC_ExternalTrigInjecConvEvent_4) || \ + ((INJTRIG) == ADC_ExternalTrigInjecConvEvent_5) || \ + ((INJTRIG) == ADC_ExternalTrigInjecConvEvent_6) || \ + ((INJTRIG) == ADC_ExternalTrigInjecConvEvent_7) || \ + ((INJTRIG) == ADC_ExternalTrigInjecConvEvent_8) || \ + ((INJTRIG) == ADC_ExternalTrigInjecConvEvent_9) || \ + ((INJTRIG) == ADC_ExternalTrigInjecConvEvent_10) || \ + ((INJTRIG) == ADC_ExternalTrigInjecConvEvent_11) || \ + ((INJTRIG) == ADC_ExternalTrigInjecConvEvent_12) || \ + ((INJTRIG) == ADC_ExternalTrigInjecConvEvent_13) || \ + ((INJTRIG) == ADC_ExternalTrigInjecConvEvent_14) || \ + ((INJTRIG) == ADC_ExternalTrigInjecConvEvent_15)) +/** + * @} + */ +/** @defgroup ADC_data_align + * @{ + */ + +#define ADC_DataAlign_Right ((uint32_t)0x00000000) /*!< ADC Data alignment right */ +#define ADC_DataAlign_Left ((uint32_t)0x00000020) /*!< ADC Data alignment left */ +#define IS_ADC_DATA_ALIGN(ALIGN) (((ALIGN) == ADC_DataAlign_Right) || \ + ((ALIGN) == ADC_DataAlign_Left)) +/** + * @} + */ + +/** @defgroup ADC_channels + * @{ + */ + +#define ADC_Channel_1 ((uint8_t)0x01) /*!< ADC Channel 1 */ +#define ADC_Channel_2 ((uint8_t)0x02) /*!< ADC Channel 2 */ +#define ADC_Channel_3 ((uint8_t)0x03) /*!< ADC Channel 3 */ +#define ADC_Channel_4 ((uint8_t)0x04) /*!< ADC Channel 4 */ +#define ADC_Channel_5 ((uint8_t)0x05) /*!< ADC Channel 5 */ +#define ADC_Channel_6 ((uint8_t)0x06) /*!< ADC Channel 6 */ +#define ADC_Channel_7 ((uint8_t)0x07) /*!< ADC Channel 7 */ +#define ADC_Channel_8 ((uint8_t)0x08) /*!< ADC Channel 8 */ +#define ADC_Channel_9 ((uint8_t)0x09) /*!< ADC Channel 9 */ +#define ADC_Channel_10 ((uint8_t)0x0A) /*!< ADC Channel 10 */ +#define ADC_Channel_11 ((uint8_t)0x0B) /*!< ADC Channel 11 */ +#define ADC_Channel_12 ((uint8_t)0x0C) /*!< ADC Channel 12 */ +#define ADC_Channel_13 ((uint8_t)0x0D) /*!< ADC Channel 13 */ +#define ADC_Channel_14 ((uint8_t)0x0E) /*!< ADC Channel 14 */ +#define ADC_Channel_15 ((uint8_t)0x0F) /*!< ADC Channel 15 */ +#define ADC_Channel_16 ((uint8_t)0x10) /*!< ADC Channel 16 */ +#define ADC_Channel_17 ((uint8_t)0x11) /*!< ADC Channel 17 */ +#define ADC_Channel_18 ((uint8_t)0x12) /*!< ADC Channel 18 */ + +#define ADC_Channel_TempSensor ((uint8_t)ADC_Channel_16) +#define ADC_Channel_Vrefint ((uint8_t)ADC_Channel_18) +#define ADC_Channel_Vbat ((uint8_t)ADC_Channel_17) + +#define IS_ADC_CHANNEL(CHANNEL) (((CHANNEL) == ADC_Channel_1) || \ + ((CHANNEL) == ADC_Channel_2) || \ + ((CHANNEL) == ADC_Channel_3) || \ + ((CHANNEL) == ADC_Channel_4) || \ + ((CHANNEL) == ADC_Channel_5) || \ + ((CHANNEL) == ADC_Channel_6) || \ + ((CHANNEL) == ADC_Channel_7) || \ + ((CHANNEL) == ADC_Channel_8) || \ + ((CHANNEL) == ADC_Channel_9) || \ + ((CHANNEL) == ADC_Channel_10) || \ + ((CHANNEL) == ADC_Channel_11) || \ + ((CHANNEL) == ADC_Channel_12) || \ + ((CHANNEL) == ADC_Channel_13) || \ + ((CHANNEL) == ADC_Channel_14) || \ + ((CHANNEL) == ADC_Channel_15) || \ + ((CHANNEL) == ADC_Channel_16) || \ + ((CHANNEL) == ADC_Channel_17) || \ + ((CHANNEL) == ADC_Channel_18)) +#define IS_ADC_DIFFCHANNEL(CHANNEL) (((CHANNEL) == ADC_Channel_1) || \ + ((CHANNEL) == ADC_Channel_2) || \ + ((CHANNEL) == ADC_Channel_3) || \ + ((CHANNEL) == ADC_Channel_4) || \ + ((CHANNEL) == ADC_Channel_5) || \ + ((CHANNEL) == ADC_Channel_6) || \ + ((CHANNEL) == ADC_Channel_7) || \ + ((CHANNEL) == ADC_Channel_8) || \ + ((CHANNEL) == ADC_Channel_9) || \ + ((CHANNEL) == ADC_Channel_10) || \ + ((CHANNEL) == ADC_Channel_11) || \ + ((CHANNEL) == ADC_Channel_12) || \ + ((CHANNEL) == ADC_Channel_13) || \ + ((CHANNEL) == ADC_Channel_14)) +/** + * @} + */ + +/** @defgroup ADC_mode + * @{ + */ +#define ADC_Mode_Independent ((uint32_t)0x00000000) /*!< ADC independent mode */ +#define ADC_Mode_CombRegSimulInjSimul ((uint32_t)0x00000001) /*!< ADC multi ADC mode: Combined Regular simultaneous injected simultaneous mode */ +#define ADC_Mode_CombRegSimulAltTrig ((uint32_t)0x00000002) /*!< ADC multi ADC mode: Combined Regular simultaneous Alternate trigger mode */ +#define ADC_Mode_InjSimul ((uint32_t)0x00000005) /*!< ADC multi ADC mode: Injected simultaneous mode */ +#define ADC_Mode_RegSimul ((uint32_t)0x00000006) /*!< ADC multi ADC mode: Regular simultaneous mode */ +#define ADC_Mode_Interleave ((uint32_t)0x00000007) /*!< ADC multi ADC mode: Interleave mode */ +#define ADC_Mode_AltTrig ((uint32_t)0x00000009) /*!< ADC multi ADC mode: Alternate Trigger mode */ + +#define IS_ADC_MODE(MODE) (((MODE) == ADC_Mode_Independent) || \ + ((MODE) == ADC_Mode_CombRegSimulInjSimul) || \ + ((MODE) == ADC_Mode_CombRegSimulAltTrig) || \ + ((MODE) == ADC_Mode_InjSimul) || \ + ((MODE) == ADC_Mode_RegSimul) || \ + ((MODE) == ADC_Mode_Interleave) || \ + ((MODE) == ADC_Mode_AltTrig)) + +/** + * @} + */ + +/** @defgroup ADC_Clock + * @{ + */ +#define ADC_Clock_AsynClkMode ((uint32_t)0x00000000) /*!< ADC Asynchronous clock mode */ +#define ADC_Clock_SynClkModeDiv1 ((uint32_t)0x00010000) /*!< Synchronous clock mode divided by 1 */ +#define ADC_Clock_SynClkModeDiv2 ((uint32_t)0x00020000) /*!< Synchronous clock mode divided by 2 */ +#define ADC_Clock_SynClkModeDiv4 ((uint32_t)0x00030000) /*!< Synchronous clock mode divided by 4 */ +#define IS_ADC_CLOCKMODE(CLOCK) (((CLOCK) == ADC_Clock_AsynClkMode) ||\ + ((CLOCK) == ADC_Clock_SynClkModeDiv1) ||\ + ((CLOCK) == ADC_Clock_SynClkModeDiv2)||\ + ((CLOCK) == ADC_Clock_SynClkModeDiv4)) +/** + * @} + */ +/** @defgroup ADC_Direct_memory_access_mode_for_multi_mode + * @{ + */ +#define ADC_DMAAccessMode_Disabled ((uint32_t)0x00000000) /*!< DMA mode disabled */ +#define ADC_DMAAccessMode_1 ((uint32_t)0x00008000) /*!< DMA mode enabled for 12 and 10-bit resolution (6 bit) */ +#define ADC_DMAAccessMode_2 ((uint32_t)0x0000C000) /*!< DMA mode enabled for 8 and 6-bit resolution (8bit) */ +#define IS_ADC_DMA_ACCESS_MODE(MODE) (((MODE) == ADC_DMAAccessMode_Disabled) || \ + ((MODE) == ADC_DMAAccessMode_1) || \ + ((MODE) == ADC_DMAAccessMode_2)) + +/** + * @} + */ +/** @defgroup ADC_sampling_time + * @{ + */ + +#define ADC_SampleTime_1Cycles5 ((uint8_t)0x00) /*!< ADC sampling time 1.5 cycle */ +#define ADC_SampleTime_2Cycles5 ((uint8_t)0x01) /*!< ADC sampling time 2.5 cycles */ +#define ADC_SampleTime_4Cycles5 ((uint8_t)0x02) /*!< ADC sampling time 4.5 cycles */ +#define ADC_SampleTime_7Cycles5 ((uint8_t)0x03) /*!< ADC sampling time 7.5 cycles */ +#define ADC_SampleTime_19Cycles5 ((uint8_t)0x04) /*!< ADC sampling time 19.5 cycles */ +#define ADC_SampleTime_61Cycles5 ((uint8_t)0x05) /*!< ADC sampling time 61.5 cycles */ +#define ADC_SampleTime_181Cycles5 ((uint8_t)0x06) /*!< ADC sampling time 181.5 cycles */ +#define ADC_SampleTime_601Cycles5 ((uint8_t)0x07) /*!< ADC sampling time 601.5 cycles */ +#define IS_ADC_SAMPLE_TIME(TIME) (((TIME) == ADC_SampleTime_1Cycles5) || \ + ((TIME) == ADC_SampleTime_2Cycles5) || \ + ((TIME) == ADC_SampleTime_4Cycles5) || \ + ((TIME) == ADC_SampleTime_7Cycles5) || \ + ((TIME) == ADC_SampleTime_19Cycles5) || \ + ((TIME) == ADC_SampleTime_61Cycles5) || \ + ((TIME) == ADC_SampleTime_181Cycles5) || \ + ((TIME) == ADC_SampleTime_601Cycles5)) +/** + * @} + */ + +/** @defgroup ADC_injected_Channel_selection + * @{ + */ + +#define ADC_InjectedChannel_1 ADC_Channel_1 /*!< ADC Injected channel 1 */ +#define ADC_InjectedChannel_2 ADC_Channel_2 /*!< ADC Injected channel 2 */ +#define ADC_InjectedChannel_3 ADC_Channel_3 /*!< ADC Injected channel 3 */ +#define ADC_InjectedChannel_4 ADC_Channel_4 /*!< ADC Injected channel 4 */ +#define ADC_InjectedChannel_5 ADC_Channel_5 /*!< ADC Injected channel 5 */ +#define ADC_InjectedChannel_6 ADC_Channel_6 /*!< ADC Injected channel 6 */ +#define ADC_InjectedChannel_7 ADC_Channel_7 /*!< ADC Injected channel 7 */ +#define ADC_InjectedChannel_8 ADC_Channel_8 /*!< ADC Injected channel 8 */ +#define ADC_InjectedChannel_9 ADC_Channel_9 /*!< ADC Injected channel 9 */ +#define ADC_InjectedChannel_10 ADC_Channel_10 /*!< ADC Injected channel 10 */ +#define ADC_InjectedChannel_11 ADC_Channel_11 /*!< ADC Injected channel 11 */ +#define ADC_InjectedChannel_12 ADC_Channel_12 /*!< ADC Injected channel 12 */ +#define ADC_InjectedChannel_13 ADC_Channel_13 /*!< ADC Injected channel 13 */ +#define ADC_InjectedChannel_14 ADC_Channel_14 /*!< ADC Injected channel 14 */ +#define ADC_InjectedChannel_15 ADC_Channel_15 /*!< ADC Injected channel 15 */ +#define ADC_InjectedChannel_16 ADC_Channel_16 /*!< ADC Injected channel 16 */ +#define ADC_InjectedChannel_17 ADC_Channel_17 /*!< ADC Injected channel 17 */ +#define ADC_InjectedChannel_18 ADC_Channel_18 /*!< ADC Injected channel 18 */ + +#define IS_ADC_INJECTED_CHANNEL(CHANNEL) (((CHANNEL) == ADC_InjectedChannel_1) || \ + ((CHANNEL) == ADC_InjectedChannel_2) || \ + ((CHANNEL) == ADC_InjectedChannel_3) || \ + ((CHANNEL) == ADC_InjectedChannel_4) ||\ + ((CHANNEL) == ADC_InjectedChannel_5) ||\ + ((CHANNEL) == ADC_InjectedChannel_6) ||\ + ((CHANNEL) == ADC_InjectedChannel_7) ||\ + ((CHANNEL) == ADC_InjectedChannel_8) ||\ + ((CHANNEL) == ADC_InjectedChannel_9) ||\ + ((CHANNEL) == ADC_InjectedChannel_10) ||\ + ((CHANNEL) == ADC_InjectedChannel_11) ||\ + ((CHANNEL) == ADC_InjectedChannel_12) ||\ + ((CHANNEL) == ADC_InjectedChannel_13) ||\ + ((CHANNEL) == ADC_InjectedChannel_14) ||\ + ((CHANNEL) == ADC_InjectedChannel_15) ||\ + ((CHANNEL) == ADC_InjectedChannel_16) ||\ + ((CHANNEL) == ADC_InjectedChannel_17) ||\ + ((CHANNEL) == ADC_InjectedChannel_18)) +/** + * @} + */ + +/** @defgroup ADC_injected_Sequence_selection + * @{ + */ + +#define ADC_InjectedSequence_1 ADC_Channel_1 /*!< ADC Injected sequence 1 */ +#define ADC_InjectedSequence_2 ADC_Channel_2 /*!< ADC Injected sequence 2 */ +#define ADC_InjectedSequence_3 ADC_Channel_3 /*!< ADC Injected sequence 3 */ +#define ADC_InjectedSequence_4 ADC_Channel_4 /*!< ADC Injected sequence 4 */ +#define IS_ADC_INJECTED_SEQUENCE(SEQUENCE) (((SEQUENCE) == ADC_InjectedSequence_1) || \ + ((SEQUENCE) == ADC_InjectedSequence_2) || \ + ((SEQUENCE) == ADC_InjectedSequence_3) || \ + ((SEQUENCE) == ADC_InjectedSequence_4)) +/** + * @} + */ + +/** @defgroup ADC_analog_watchdog_selection + * @{ + */ + +#define ADC_AnalogWatchdog_SingleRegEnable ((uint32_t)0x00C00000) /*!< ADC Analog watchdog single regular mode */ +#define ADC_AnalogWatchdog_SingleInjecEnable ((uint32_t)0x01400000) /*!< ADC Analog watchdog single injected mode */ +#define ADC_AnalogWatchdog_SingleRegOrInjecEnable ((uint32_t)0x01C00000) /*!< ADC Analog watchdog single regular or injected mode */ +#define ADC_AnalogWatchdog_AllRegEnable ((uint32_t)0x00800000) /*!< ADC Analog watchdog all regular mode */ +#define ADC_AnalogWatchdog_AllInjecEnable ((uint32_t)0x01000000) /*!< ADC Analog watchdog all injected mode */ +#define ADC_AnalogWatchdog_AllRegAllInjecEnable ((uint32_t)0x01800000) /*!< ADC Analog watchdog all regular and all injected mode */ +#define ADC_AnalogWatchdog_None ((uint32_t)0x00000000) /*!< ADC Analog watchdog off */ + +#define IS_ADC_ANALOG_WATCHDOG(WATCHDOG) (((WATCHDOG) == ADC_AnalogWatchdog_SingleRegEnable) || \ + ((WATCHDOG) == ADC_AnalogWatchdog_SingleInjecEnable) || \ + ((WATCHDOG) == ADC_AnalogWatchdog_SingleRegOrInjecEnable) || \ + ((WATCHDOG) == ADC_AnalogWatchdog_AllRegEnable) || \ + ((WATCHDOG) == ADC_AnalogWatchdog_AllInjecEnable) || \ + ((WATCHDOG) == ADC_AnalogWatchdog_AllRegAllInjecEnable) || \ + ((WATCHDOG) == ADC_AnalogWatchdog_None)) +/** + * @} + */ + +/** @defgroup ADC_Calibration_Mode_definition + * @{ + */ +#define ADC_CalibrationMode_Single ((uint32_t)0x00000000) /*!< ADC Calibration for single ended channel */ +#define ADC_CalibrationMode_Differential ((uint32_t)0x40000000) /*!< ADC Calibration for differential channel */ + +#define IS_ADC_CALIBRATION_MODE(MODE) (((MODE) == ADC_CalibrationMode_Single) ||((MODE) == ADC_CalibrationMode_Differential)) + +/** + * @} + */ + +/** @defgroup ADC_DMA_Mode_definition + * @{ + */ +#define ADC_DMAMode_OneShot ((uint32_t)0x00000000) /*!< ADC DMA Oneshot mode */ +#define ADC_DMAMode_Circular ((uint32_t)0x00000002) /*!< ADC DMA circular mode */ + +#define IS_ADC_DMA_MODE(MODE) (((MODE) == ADC_DMAMode_OneShot) || ((MODE) == ADC_DMAMode_Circular)) +/** + * @} + */ + +/** @defgroup ADC_interrupts_definition + * @{ + */ + +#define ADC_IT_RDY ((uint16_t)0x0001) /*!< ADC Ready (ADRDY) interrupt source */ +#define ADC_IT_EOSMP ((uint16_t)0x0002) /*!< ADC End of Sampling interrupt source */ +#define ADC_IT_EOC ((uint16_t)0x0004) /*!< ADC End of Regular Conversion interrupt source */ +#define ADC_IT_EOS ((uint16_t)0x0008) /*!< ADC End of Regular sequence of Conversions interrupt source */ +#define ADC_IT_OVR ((uint16_t)0x0010) /*!< ADC overrun interrupt source */ +#define ADC_IT_JEOC ((uint16_t)0x0020) /*!< ADC End of Injected Conversion interrupt source */ +#define ADC_IT_JEOS ((uint16_t)0x0040) /*!< ADC End of Injected sequence of Conversions interrupt source */ +#define ADC_IT_AWD1 ((uint16_t)0x0080) /*!< ADC Analog watchdog 1 interrupt source */ +#define ADC_IT_AWD2 ((uint16_t)0x0100) /*!< ADC Analog watchdog 2 interrupt source */ +#define ADC_IT_AWD3 ((uint16_t)0x0200) /*!< ADC Analog watchdog 3 interrupt source */ +#define ADC_IT_JQOVF ((uint16_t)0x0400) /*!< ADC Injected Context Queue Overflow interrupt source */ + + +#define IS_ADC_IT(IT) ((((IT) & (uint16_t)0xF800) == 0x0000) && ((IT) != 0x0000)) + +#define IS_ADC_GET_IT(IT) (((IT) == ADC_IT_RDY) || ((IT) == ADC_IT_EOSMP) || \ + ((IT) == ADC_IT_EOC) || ((IT) == ADC_IT_EOS) || \ + ((IT) == ADC_IT_OVR) || ((IT) == ADC_IT_EOS) || \ + ((IT) == ADC_IT_JEOS) || ((IT) == ADC_IT_AWD1) || \ + ((IT) == ADC_IT_AWD2) || ((IT) == ADC_IT_AWD3) || \ + ((IT) == ADC_IT_JQOVF)) +/** + * @} + */ + +/** @defgroup ADC_flags_definition + * @{ + */ + +#define ADC_FLAG_RDY ((uint16_t)0x0001) /*!< ADC Ready (ADRDY) flag */ +#define ADC_FLAG_EOSMP ((uint16_t)0x0002) /*!< ADC End of Sampling flag */ +#define ADC_FLAG_EOC ((uint16_t)0x0004) /*!< ADC End of Regular Conversion flag */ +#define ADC_FLAG_EOS ((uint16_t)0x0008) /*!< ADC End of Regular sequence of Conversions flag */ +#define ADC_FLAG_OVR ((uint16_t)0x0010) /*!< ADC overrun flag */ +#define ADC_FLAG_JEOC ((uint16_t)0x0020) /*!< ADC End of Injected Conversion flag */ +#define ADC_FLAG_JEOS ((uint16_t)0x0040) /*!< ADC End of Injected sequence of Conversions flag */ +#define ADC_FLAG_AWD1 ((uint16_t)0x0080) /*!< ADC Analog watchdog 1 flag */ +#define ADC_FLAG_AWD2 ((uint16_t)0x0100) /*!< ADC Analog watchdog 2 flag */ +#define ADC_FLAG_AWD3 ((uint16_t)0x0200) /*!< ADC Analog watchdog 3 flag */ +#define ADC_FLAG_JQOVF ((uint16_t)0x0400) /*!< ADC Injected Context Queue Overflow flag */ + +#define IS_ADC_CLEAR_FLAG(FLAG) ((((FLAG) & (uint16_t)0xF800) == 0x0000) && ((FLAG) != 0x0000)) +#define IS_ADC_GET_FLAG(FLAG) (((FLAG) == ADC_FLAG_RDY) || ((FLAG) == ADC_FLAG_EOSMP) || \ + ((FLAG) == ADC_FLAG_EOC) || ((FLAG) == ADC_FLAG_EOS) || \ + ((FLAG) == ADC_FLAG_OVR) || ((FLAG) == ADC_FLAG_JEOC) || \ + ((FLAG) == ADC_FLAG_JEOS) || ((FLAG) == ADC_FLAG_AWD1) || \ + ((FLAG) == ADC_FLAG_AWD2) || ((FLAG) == ADC_FLAG_AWD3) || \ + ((FLAG) == ADC_FLAG_JQOVF)) +/** + * @} + */ + +/** @defgroup ADC_Common_flags_definition + * @{ + */ + +#define ADC_FLAG_MSTRDY ((uint32_t)0x00000001) /*!< ADC Master Ready (ADRDY) flag */ +#define ADC_FLAG_MSTEOSMP ((uint32_t)0x00000002) /*!< ADC Master End of Sampling flag */ +#define ADC_FLAG_MSTEOC ((uint32_t)0x00000004) /*!< ADC Master End of Regular Conversion flag */ +#define ADC_FLAG_MSTEOS ((uint32_t)0x00000008) /*!< ADC Master End of Regular sequence of Conversions flag */ +#define ADC_FLAG_MSTOVR ((uint32_t)0x00000010) /*!< ADC Master overrun flag */ +#define ADC_FLAG_MSTJEOC ((uint32_t)0x00000020) /*!< ADC Master End of Injected Conversion flag */ +#define ADC_FLAG_MSTJEOS ((uint32_t)0x00000040) /*!< ADC Master End of Injected sequence of Conversions flag */ +#define ADC_FLAG_MSTAWD1 ((uint32_t)0x00000080) /*!< ADC Master Analog watchdog 1 flag */ +#define ADC_FLAG_MSTAWD2 ((uint32_t)0x00000100) /*!< ADC Master Analog watchdog 2 flag */ +#define ADC_FLAG_MSTAWD3 ((uint32_t)0x00000200) /*!< ADC Master Analog watchdog 3 flag */ +#define ADC_FLAG_MSTJQOVF ((uint32_t)0x00000400) /*!< ADC Master Injected Context Queue Overflow flag */ + +#define ADC_FLAG_SLVRDY ((uint32_t)0x00010000) /*!< ADC Slave Ready (ADRDY) flag */ +#define ADC_FLAG_SLVEOSMP ((uint32_t)0x00020000) /*!< ADC Slave End of Sampling flag */ +#define ADC_FLAG_SLVEOC ((uint32_t)0x00040000) /*!< ADC Slave End of Regular Conversion flag */ +#define ADC_FLAG_SLVEOS ((uint32_t)0x00080000) /*!< ADC Slave End of Regular sequence of Conversions flag */ +#define ADC_FLAG_SLVOVR ((uint32_t)0x00100000) /*!< ADC Slave overrun flag */ +#define ADC_FLAG_SLVJEOC ((uint32_t)0x00200000) /*!< ADC Slave End of Injected Conversion flag */ +#define ADC_FLAG_SLVJEOS ((uint32_t)0x00400000) /*!< ADC Slave End of Injected sequence of Conversions flag */ +#define ADC_FLAG_SLVAWD1 ((uint32_t)0x00800000) /*!< ADC Slave Analog watchdog 1 flag */ +#define ADC_FLAG_SLVAWD2 ((uint32_t)0x01000000) /*!< ADC Slave Analog watchdog 2 flag */ +#define ADC_FLAG_SLVAWD3 ((uint32_t)0x02000000) /*!< ADC Slave Analog watchdog 3 flag */ +#define ADC_FLAG_SLVJQOVF ((uint32_t)0x04000000) /*!< ADC Slave Injected Context Queue Overflow flag */ + +#define IS_ADC_CLEAR_COMMONFLAG(FLAG) ((((FLAG) & (uint32_t)0xF800F800) == 0x0000) && ((FLAG) != 0x00000000)) +#define IS_ADC_GET_COMMONFLAG(FLAG) (((FLAG) == ADC_FLAG_MSTRDY) || ((FLAG) == ADC_FLAG_MSTEOSMP) || \ + ((FLAG) == ADC_FLAG_MSTEOC) || ((FLAG) == ADC_FLAG_MSTEOS) || \ + ((FLAG) == ADC_FLAG_MSTOVR) || ((FLAG) == ADC_FLAG_MSTEOS) || \ + ((FLAG) == ADC_FLAG_MSTJEOS) || ((FLAG) == ADC_FLAG_MSTAWD1) || \ + ((FLAG) == ADC_FLAG_MSTAWD2) || ((FLAG) == ADC_FLAG_MSTAWD3) || \ + ((FLAG) == ADC_FLAG_MSTJQOVF) || \ + ((FLAG) == ADC_FLAG_SLVRDY) || ((FLAG) == ADC_FLAG_SLVEOSMP) || \ + ((FLAG) == ADC_FLAG_SLVEOC) || ((FLAG) == ADC_FLAG_SLVEOS) || \ + ((FLAG) == ADC_FLAG_SLVOVR) || ((FLAG) == ADC_FLAG_SLVEOS) || \ + ((FLAG) == ADC_FLAG_SLVJEOS) || ((FLAG) == ADC_FLAG_SLVAWD1) || \ + ((FLAG) == ADC_FLAG_SLVAWD2) || ((FLAG) == ADC_FLAG_SLVAWD3) || \ + ((FLAG) == ADC_FLAG_SLVJQOVF)) +/** + * @} + */ + +/** @defgroup ADC_thresholds + * @{ + */ + +#define IS_ADC_THRESHOLD(THRESHOLD) ((THRESHOLD) <= 0xFFF) + +/** + * @} + */ + +/** @defgroup ADC_injected_offset + * @{ + */ + +#define IS_ADC_OFFSET(OFFSET) ((OFFSET) <= 0xFFF) + +/** + * @} + */ + +/** @defgroup ADC_injected_length + * @{ + */ + +#define IS_ADC_INJECTED_LENGTH(LENGTH) (((LENGTH) >= 0x1) && ((LENGTH) <= 0x4)) + +/** + * @} + */ + + +/** @defgroup ADC_regular_length + * @{ + */ + +#define IS_ADC_REGULAR_LENGTH(LENGTH) (((LENGTH) >= 0x1) && ((LENGTH) <= 0x10)) +/** + * @} + */ + +/** @defgroup ADC_regular_discontinuous_mode_number + * @{ + */ + +#define IS_ADC_REGULAR_DISC_NUMBER(NUMBER) (((NUMBER) >= 0x1) && ((NUMBER) <= 0x8)) + +/** + * @} + */ + +/** @defgroup ADC_two_sampling_delay_number + * @{ + */ +#define IS_ADC_TWOSAMPLING_DELAY(DELAY) (((DELAY) <= 0xF)) + +/** + * @} + */ +/** + * @} + */ + + +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions ------------------------------------------------------- */ + +/* Function used to set the ADC configuration to the default reset state *****/ +void ADC_DeInit(ADC_TypeDef* ADCx); + +/* Initialization and Configuration functions *********************************/ +void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct); +void ADC_StructInit(ADC_InitTypeDef* ADC_InitStruct); +void ADC_InjectedInit(ADC_TypeDef* ADCx, ADC_InjectedInitTypeDef* ADC_InjectedInitStruct); +void ADC_InjectedStructInit(ADC_InjectedInitTypeDef* ADC_InjectedInitStruct); +void ADC_CommonInit(ADC_TypeDef* ADCx, ADC_CommonInitTypeDef* ADC_CommonInitStruct); +void ADC_CommonStructInit(ADC_CommonInitTypeDef* ADC_CommonInitStruct); + +void ADC_Cmd(ADC_TypeDef* ADCx, FunctionalState NewState); +void ADC_StartCalibration(ADC_TypeDef* ADCx); +uint32_t ADC_GetCalibrationValue(ADC_TypeDef* ADCx); +void ADC_SetCalibrationValue(ADC_TypeDef* ADCx, uint32_t ADC_Calibration); +void ADC_SelectCalibrationMode(ADC_TypeDef* ADCx, uint32_t ADC_CalibrationMode); +FlagStatus ADC_GetCalibrationStatus(ADC_TypeDef* ADCx); +void ADC_DisableCmd(ADC_TypeDef* ADCx); +FlagStatus ADC_GetDisableCmdStatus(ADC_TypeDef* ADCx); +void ADC_VoltageRegulatorCmd(ADC_TypeDef* ADCx, FunctionalState NewState); +void ADC_SelectDifferentialMode(ADC_TypeDef* ADCx, uint8_t ADC_Channel, FunctionalState NewState); +void ADC_SelectQueueOfContextMode(ADC_TypeDef* ADCx, FunctionalState NewState); +void ADC_AutoDelayCmd(ADC_TypeDef* ADCx, FunctionalState NewState); + +/* Analog Watchdog configuration functions ************************************/ +void ADC_AnalogWatchdogCmd(ADC_TypeDef* ADCx, uint32_t ADC_AnalogWatchdog); +void ADC_AnalogWatchdog1ThresholdsConfig(ADC_TypeDef* ADCx, uint16_t HighThreshold, uint16_t LowThreshold); +void ADC_AnalogWatchdog2ThresholdsConfig(ADC_TypeDef* ADCx, uint8_t HighThreshold, uint8_t LowThreshold); +void ADC_AnalogWatchdog3ThresholdsConfig(ADC_TypeDef* ADCx, uint8_t HighThreshold, uint8_t LowThreshold); +void ADC_AnalogWatchdog1SingleChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel); +void ADC_AnalogWatchdog2SingleChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel); +void ADC_AnalogWatchdog3SingleChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel); + +/* Temperature Sensor, Vrefint and Vbat management function */ +void ADC_TempSensorCmd(ADC_TypeDef* ADCx, FunctionalState NewState); +void ADC_VrefintCmd(ADC_TypeDef* ADCx, FunctionalState NewState); +void ADC_VbatCmd(ADC_TypeDef* ADCx, FunctionalState NewState); + +/* Channels Configuration functions ***********************************/ +void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime); +void ADC_RegularChannelSequencerLengthConfig(ADC_TypeDef* ADCx, uint8_t SequencerLength); +void ADC_ExternalTriggerConfig(ADC_TypeDef* ADCx, uint16_t ADC_ExternalTrigConvEvent, uint16_t ADC_ExternalTrigEventEdge); + +void ADC_StartConversion(ADC_TypeDef* ADCx); +FlagStatus ADC_GetStartConversionStatus(ADC_TypeDef* ADCx); +void ADC_StopConversion(ADC_TypeDef* ADCx); +void ADC_DiscModeChannelCountConfig(ADC_TypeDef* ADCx, uint8_t Number); +void ADC_DiscModeCmd(ADC_TypeDef* ADCx, FunctionalState NewState); +uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx); +uint32_t ADC_GetDualModeConversionValue(ADC_TypeDef* ADCx); + +void ADC_SetChannelOffset1(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint16_t Offset); +void ADC_SetChannelOffset2(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint16_t Offset); +void ADC_SetChannelOffset3(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint16_t Offset); +void ADC_SetChannelOffset4(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint16_t Offset); + +void ADC_ChannelOffset1Cmd(ADC_TypeDef* ADCx, FunctionalState NewState); +void ADC_ChannelOffset2Cmd(ADC_TypeDef* ADCx, FunctionalState NewState); +void ADC_ChannelOffset3Cmd(ADC_TypeDef* ADCx, FunctionalState NewState); +void ADC_ChannelOffset4Cmd(ADC_TypeDef* ADCx, FunctionalState NewState); + +/* Regular Channels DMA Configuration functions *******************************/ +void ADC_DMACmd(ADC_TypeDef* ADCx, FunctionalState NewState); +void ADC_DMAConfig(ADC_TypeDef* ADCx, uint32_t ADC_DMAMode); + +/* Injected channels Configuration functions **********************************/ +void ADC_InjectedChannelSampleTimeConfig(ADC_TypeDef* ADCx, uint8_t ADC_InjectedChannel, uint8_t ADC_SampleTime); +void ADC_StartInjectedConversion(ADC_TypeDef* ADCx); +FlagStatus ADC_GetStartInjectedConversionStatus(ADC_TypeDef* ADCx); +void ADC_StopInjectedConversion(ADC_TypeDef* ADCx); +void ADC_AutoInjectedConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState); +void ADC_InjectedDiscModeCmd(ADC_TypeDef* ADCx, FunctionalState NewState); +uint16_t ADC_GetInjectedConversionValue(ADC_TypeDef* ADCx, uint8_t ADC_InjectedChannel); + +/* ADC Dual Modes Configuration functions *************************************/ +FlagStatus ADC_GetCommonFlagStatus(ADC_TypeDef* ADCx, uint32_t ADC_FLAG); +void ADC_ClearCommonFlag(ADC_TypeDef* ADCx, uint32_t ADC_FLAG); + +/* Interrupts and flags management functions **********************************/ +void ADC_ITConfig(ADC_TypeDef* ADCx, uint32_t ADC_IT, FunctionalState NewState); +FlagStatus ADC_GetFlagStatus(ADC_TypeDef* ADCx, uint32_t ADC_FLAG); +void ADC_ClearFlag(ADC_TypeDef* ADCx, uint32_t ADC_FLAG); +ITStatus ADC_GetITStatus(ADC_TypeDef* ADCx, uint32_t ADC_IT); +void ADC_ClearITPendingBit(ADC_TypeDef* ADCx, uint32_t ADC_IT); + +#ifdef __cplusplus +} +#endif + +#endif /*__STM32F30x_ADC_H */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_can.h b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_can.h new file mode 100755 index 0000000000..dbac025334 --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_can.h @@ -0,0 +1,643 @@ +/** + ****************************************************************************** + * @file stm32f30x_can.h + * @author MCD Application Team + * @version V1.2.3 + * @date 10-July-2015 + * @brief This file contains all the functions prototypes for the CAN firmware + * library. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F30x_CAN_H +#define __STM32F30x_CAN_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f30x.h" + +/** @addtogroup STM32F30x_StdPeriph_Driver + * @{ + */ + +/** @addtogroup CAN + * @{ + */ + +/* Exported types ------------------------------------------------------------*/ + +#define IS_CAN_ALL_PERIPH(PERIPH) (((PERIPH) == CAN1)) + +/** + * @brief CAN init structure definition + */ +typedef struct +{ + uint16_t CAN_Prescaler; /*!< Specifies the length of a time quantum. + It ranges from 1 to 1024. */ + + uint8_t CAN_Mode; /*!< Specifies the CAN operating mode. + This parameter can be a value of @ref CAN_operating_mode */ + + uint8_t CAN_SJW; /*!< Specifies the maximum number of time quanta + the CAN hardware is allowed to lengthen or + shorten a bit to perform resynchronization. + This parameter can be a value of @ref CAN_synchronisation_jump_width */ + + uint8_t CAN_BS1; /*!< Specifies the number of time quanta in Bit + Segment 1. This parameter can be a value of + @ref CAN_time_quantum_in_bit_segment_1 */ + + uint8_t CAN_BS2; /*!< Specifies the number of time quanta in Bit Segment 2. + This parameter can be a value of @ref CAN_time_quantum_in_bit_segment_2 */ + + FunctionalState CAN_TTCM; /*!< Enable or disable the time triggered communication mode. + This parameter can be set either to ENABLE or DISABLE. */ + + FunctionalState CAN_ABOM; /*!< Enable or disable the automatic bus-off management. + This parameter can be set either to ENABLE or DISABLE. */ + + FunctionalState CAN_AWUM; /*!< Enable or disable the automatic wake-up mode. + This parameter can be set either to ENABLE or DISABLE. */ + + FunctionalState CAN_NART; /*!< Enable or disable the non-automatic retransmission mode. + This parameter can be set either to ENABLE or DISABLE. */ + + FunctionalState CAN_RFLM; /*!< Enable or disable the Receive FIFO Locked mode. + This parameter can be set either to ENABLE or DISABLE. */ + + FunctionalState CAN_TXFP; /*!< Enable or disable the transmit FIFO priority. + This parameter can be set either to ENABLE or DISABLE. */ +} CAN_InitTypeDef; + +/** + * @brief CAN filter init structure definition + */ +typedef struct +{ + uint16_t CAN_FilterIdHigh; /*!< Specifies the filter identification number (MSBs for a 32-bit + configuration, first one for a 16-bit configuration). + This parameter can be a value between 0x0000 and 0xFFFF */ + + uint16_t CAN_FilterIdLow; /*!< Specifies the filter identification number (LSBs for a 32-bit + configuration, second one for a 16-bit configuration). + This parameter can be a value between 0x0000 and 0xFFFF */ + + uint16_t CAN_FilterMaskIdHigh; /*!< Specifies the filter mask number or identification number, + according to the mode (MSBs for a 32-bit configuration, + first one for a 16-bit configuration). + This parameter can be a value between 0x0000 and 0xFFFF */ + + uint16_t CAN_FilterMaskIdLow; /*!< Specifies the filter mask number or identification number, + according to the mode (LSBs for a 32-bit configuration, + second one for a 16-bit configuration). + This parameter can be a value between 0x0000 and 0xFFFF */ + + uint16_t CAN_FilterFIFOAssignment; /*!< Specifies the FIFO (0 or 1) which will be assigned to the filter. + This parameter can be a value of @ref CAN_filter_FIFO */ + + uint8_t CAN_FilterNumber; /*!< Specifies the filter which will be initialized. It ranges from 0 to 13. */ + + uint8_t CAN_FilterMode; /*!< Specifies the filter mode to be initialized. + This parameter can be a value of @ref CAN_filter_mode */ + + uint8_t CAN_FilterScale; /*!< Specifies the filter scale. + This parameter can be a value of @ref CAN_filter_scale */ + + FunctionalState CAN_FilterActivation; /*!< Enable or disable the filter. + This parameter can be set either to ENABLE or DISABLE. */ +} CAN_FilterInitTypeDef; + +/** + * @brief CAN Tx message structure definition + */ +typedef struct +{ + uint32_t StdId; /*!< Specifies the standard identifier. + This parameter can be a value between 0 to 0x7FF. */ + + uint32_t ExtId; /*!< Specifies the extended identifier. + This parameter can be a value between 0 to 0x1FFFFFFF. */ + + uint8_t IDE; /*!< Specifies the type of identifier for the message that + will be transmitted. This parameter can be a value + of @ref CAN_identifier_type */ + + uint8_t RTR; /*!< Specifies the type of frame for the message that will + be transmitted. This parameter can be a value of + @ref CAN_remote_transmission_request */ + + uint8_t DLC; /*!< Specifies the length of the frame that will be + transmitted. This parameter can be a value between + 0 to 8 */ + + uint8_t Data[8]; /*!< Contains the data to be transmitted. It ranges from 0 + to 0xFF. */ +} CanTxMsg; + +/** + * @brief CAN Rx message structure definition + */ +typedef struct +{ + uint32_t StdId; /*!< Specifies the standard identifier. + This parameter can be a value between 0 to 0x7FF. */ + + uint32_t ExtId; /*!< Specifies the extended identifier. + This parameter can be a value between 0 to 0x1FFFFFFF. */ + + uint8_t IDE; /*!< Specifies the type of identifier for the message that + will be received. This parameter can be a value of + @ref CAN_identifier_type */ + + uint8_t RTR; /*!< Specifies the type of frame for the received message. + This parameter can be a value of + @ref CAN_remote_transmission_request */ + + uint8_t DLC; /*!< Specifies the length of the frame that will be received. + This parameter can be a value between 0 to 8 */ + + uint8_t Data[8]; /*!< Contains the data to be received. It ranges from 0 to + 0xFF. */ + + uint8_t FMI; /*!< Specifies the index of the filter the message stored in + the mailbox passes through. This parameter can be a + value between 0 to 0xFF */ +} CanRxMsg; + +/* Exported constants --------------------------------------------------------*/ + +/** @defgroup CAN_Exported_Constants + * @{ + */ + +/** @defgroup CAN_InitStatus + * @{ + */ + +#define CAN_InitStatus_Failed ((uint8_t)0x00) /*!< CAN initialization failed */ +#define CAN_InitStatus_Success ((uint8_t)0x01) /*!< CAN initialization OK */ + + +/* Legacy defines */ +#define CANINITFAILED CAN_InitStatus_Failed +#define CANINITOK CAN_InitStatus_Success +/** + * @} + */ + +/** @defgroup CAN_operating_mode + * @{ + */ + +#define CAN_Mode_Normal ((uint8_t)0x00) /*!< normal mode */ +#define CAN_Mode_LoopBack ((uint8_t)0x01) /*!< loopback mode */ +#define CAN_Mode_Silent ((uint8_t)0x02) /*!< silent mode */ +#define CAN_Mode_Silent_LoopBack ((uint8_t)0x03) /*!< loopback combined with silent mode */ + +#define IS_CAN_MODE(MODE) (((MODE) == CAN_Mode_Normal) || \ + ((MODE) == CAN_Mode_LoopBack)|| \ + ((MODE) == CAN_Mode_Silent) || \ + ((MODE) == CAN_Mode_Silent_LoopBack)) +/** + * @} + */ + + + /** + * @defgroup CAN_operating_mode + * @{ + */ +#define CAN_OperatingMode_Initialization ((uint8_t)0x00) /*!< Initialization mode */ +#define CAN_OperatingMode_Normal ((uint8_t)0x01) /*!< Normal mode */ +#define CAN_OperatingMode_Sleep ((uint8_t)0x02) /*!< sleep mode */ + + +#define IS_CAN_OPERATING_MODE(MODE) (((MODE) == CAN_OperatingMode_Initialization) ||\ + ((MODE) == CAN_OperatingMode_Normal)|| \ + ((MODE) == CAN_OperatingMode_Sleep)) +/** + * @} + */ + +/** + * @defgroup CAN_operating_mode_status + * @{ + */ + +#define CAN_ModeStatus_Failed ((uint8_t)0x00) /*!< CAN entering the specific mode failed */ +#define CAN_ModeStatus_Success ((uint8_t)!CAN_ModeStatus_Failed) /*!< CAN entering the specific mode Succeed */ +/** + * @} + */ + +/** @defgroup CAN_synchronisation_jump_width + * @{ + */ +#define CAN_SJW_1tq ((uint8_t)0x00) /*!< 1 time quantum */ +#define CAN_SJW_2tq ((uint8_t)0x01) /*!< 2 time quantum */ +#define CAN_SJW_3tq ((uint8_t)0x02) /*!< 3 time quantum */ +#define CAN_SJW_4tq ((uint8_t)0x03) /*!< 4 time quantum */ + +#define IS_CAN_SJW(SJW) (((SJW) == CAN_SJW_1tq) || ((SJW) == CAN_SJW_2tq)|| \ + ((SJW) == CAN_SJW_3tq) || ((SJW) == CAN_SJW_4tq)) +/** + * @} + */ + +/** @defgroup CAN_time_quantum_in_bit_segment_1 + * @{ + */ +#define CAN_BS1_1tq ((uint8_t)0x00) /*!< 1 time quantum */ +#define CAN_BS1_2tq ((uint8_t)0x01) /*!< 2 time quantum */ +#define CAN_BS1_3tq ((uint8_t)0x02) /*!< 3 time quantum */ +#define CAN_BS1_4tq ((uint8_t)0x03) /*!< 4 time quantum */ +#define CAN_BS1_5tq ((uint8_t)0x04) /*!< 5 time quantum */ +#define CAN_BS1_6tq ((uint8_t)0x05) /*!< 6 time quantum */ +#define CAN_BS1_7tq ((uint8_t)0x06) /*!< 7 time quantum */ +#define CAN_BS1_8tq ((uint8_t)0x07) /*!< 8 time quantum */ +#define CAN_BS1_9tq ((uint8_t)0x08) /*!< 9 time quantum */ +#define CAN_BS1_10tq ((uint8_t)0x09) /*!< 10 time quantum */ +#define CAN_BS1_11tq ((uint8_t)0x0A) /*!< 11 time quantum */ +#define CAN_BS1_12tq ((uint8_t)0x0B) /*!< 12 time quantum */ +#define CAN_BS1_13tq ((uint8_t)0x0C) /*!< 13 time quantum */ +#define CAN_BS1_14tq ((uint8_t)0x0D) /*!< 14 time quantum */ +#define CAN_BS1_15tq ((uint8_t)0x0E) /*!< 15 time quantum */ +#define CAN_BS1_16tq ((uint8_t)0x0F) /*!< 16 time quantum */ + +#define IS_CAN_BS1(BS1) ((BS1) <= CAN_BS1_16tq) +/** + * @} + */ + +/** @defgroup CAN_time_quantum_in_bit_segment_2 + * @{ + */ +#define CAN_BS2_1tq ((uint8_t)0x00) /*!< 1 time quantum */ +#define CAN_BS2_2tq ((uint8_t)0x01) /*!< 2 time quantum */ +#define CAN_BS2_3tq ((uint8_t)0x02) /*!< 3 time quantum */ +#define CAN_BS2_4tq ((uint8_t)0x03) /*!< 4 time quantum */ +#define CAN_BS2_5tq ((uint8_t)0x04) /*!< 5 time quantum */ +#define CAN_BS2_6tq ((uint8_t)0x05) /*!< 6 time quantum */ +#define CAN_BS2_7tq ((uint8_t)0x06) /*!< 7 time quantum */ +#define CAN_BS2_8tq ((uint8_t)0x07) /*!< 8 time quantum */ + +#define IS_CAN_BS2(BS2) ((BS2) <= CAN_BS2_8tq) +/** + * @} + */ + +/** @defgroup CAN_clock_prescaler + * @{ + */ +#define IS_CAN_PRESCALER(PRESCALER) (((PRESCALER) >= 1) && ((PRESCALER) <= 1024)) +/** + * @} + */ + +/** @defgroup CAN_filter_number + * @{ + */ +#define IS_CAN_FILTER_NUMBER(NUMBER) ((NUMBER) <= 27) +/** + * @} + */ + +/** @defgroup CAN_filter_mode + * @{ + */ +#define CAN_FilterMode_IdMask ((uint8_t)0x00) /*!< identifier/mask mode */ +#define CAN_FilterMode_IdList ((uint8_t)0x01) /*!< identifier list mode */ + +#define IS_CAN_FILTER_MODE(MODE) (((MODE) == CAN_FilterMode_IdMask) || \ + ((MODE) == CAN_FilterMode_IdList)) +/** + * @} + */ + +/** @defgroup CAN_filter_scale + * @{ + */ +#define CAN_FilterScale_16bit ((uint8_t)0x00) /*!< Two 16-bit filters */ +#define CAN_FilterScale_32bit ((uint8_t)0x01) /*!< One 32-bit filter */ + +#define IS_CAN_FILTER_SCALE(SCALE) (((SCALE) == CAN_FilterScale_16bit) || \ + ((SCALE) == CAN_FilterScale_32bit)) +/** + * @} + */ + +/** @defgroup CAN_filter_FIFO + * @{ + */ +#define CAN_Filter_FIFO0 ((uint8_t)0x00) /*!< Filter FIFO 0 assignment for filter x */ +#define CAN_Filter_FIFO1 ((uint8_t)0x01) /*!< Filter FIFO 1 assignment for filter x */ +#define IS_CAN_FILTER_FIFO(FIFO) (((FIFO) == CAN_FilterFIFO0) || \ + ((FIFO) == CAN_FilterFIFO1)) + +/* Legacy defines */ +#define CAN_FilterFIFO0 CAN_Filter_FIFO0 +#define CAN_FilterFIFO1 CAN_Filter_FIFO1 +/** + * @} + */ + +/** @defgroup CAN_Start_bank_filter_for_slave_CAN + * @{ + */ +#define IS_CAN_BANKNUMBER(BANKNUMBER) (((BANKNUMBER) >= 1) && ((BANKNUMBER) <= 27)) +/** + * @} + */ + +/** @defgroup CAN_Tx + * @{ + */ +#define IS_CAN_TRANSMITMAILBOX(TRANSMITMAILBOX) ((TRANSMITMAILBOX) <= ((uint8_t)0x02)) +#define IS_CAN_STDID(STDID) ((STDID) <= ((uint32_t)0x7FF)) +#define IS_CAN_EXTID(EXTID) ((EXTID) <= ((uint32_t)0x1FFFFFFF)) +#define IS_CAN_DLC(DLC) ((DLC) <= ((uint8_t)0x08)) +/** + * @} + */ + +/** @defgroup CAN_identifier_type + * @{ + */ +#define CAN_Id_Standard ((uint32_t)0x00000000) /*!< Standard Id */ +#define CAN_Id_Extended ((uint32_t)0x00000004) /*!< Extended Id */ +#define IS_CAN_IDTYPE(IDTYPE) (((IDTYPE) == CAN_Id_Standard) || \ + ((IDTYPE) == CAN_Id_Extended)) + +/* Legacy defines */ +#define CAN_ID_STD CAN_Id_Standard +#define CAN_ID_EXT CAN_Id_Extended +/** + * @} + */ + +/** @defgroup CAN_remote_transmission_request + * @{ + */ +#define CAN_RTR_Data ((uint32_t)0x00000000) /*!< Data frame */ +#define CAN_RTR_Remote ((uint32_t)0x00000002) /*!< Remote frame */ +#define IS_CAN_RTR(RTR) (((RTR) == CAN_RTR_Data) || ((RTR) == CAN_RTR_Remote)) + +/* Legacy defines */ +#define CAN_RTR_DATA CAN_RTR_Data +#define CAN_RTR_REMOTE CAN_RTR_Remote +/** + * @} + */ + +/** @defgroup CAN_transmit_constants + * @{ + */ +#define CAN_TxStatus_Failed ((uint8_t)0x00)/*!< CAN transmission failed */ +#define CAN_TxStatus_Ok ((uint8_t)0x01) /*!< CAN transmission succeeded */ +#define CAN_TxStatus_Pending ((uint8_t)0x02) /*!< CAN transmission pending */ +#define CAN_TxStatus_NoMailBox ((uint8_t)0x04) /*!< CAN cell did not provide + an empty mailbox */ +/* Legacy defines */ +#define CANTXFAILED CAN_TxStatus_Failed +#define CANTXOK CAN_TxStatus_Ok +#define CANTXPENDING CAN_TxStatus_Pending +#define CAN_NO_MB CAN_TxStatus_NoMailBox +/** + * @} + */ + +/** @defgroup CAN_receive_FIFO_number_constants + * @{ + */ +#define CAN_FIFO0 ((uint8_t)0x00) /*!< CAN FIFO 0 used to receive */ +#define CAN_FIFO1 ((uint8_t)0x01) /*!< CAN FIFO 1 used to receive */ + +#define IS_CAN_FIFO(FIFO) (((FIFO) == CAN_FIFO0) || ((FIFO) == CAN_FIFO1)) +/** + * @} + */ + +/** @defgroup CAN_sleep_constants + * @{ + */ +#define CAN_Sleep_Failed ((uint8_t)0x00) /*!< CAN did not enter the sleep mode */ +#define CAN_Sleep_Ok ((uint8_t)0x01) /*!< CAN entered the sleep mode */ + +/* Legacy defines */ +#define CANSLEEPFAILED CAN_Sleep_Failed +#define CANSLEEPOK CAN_Sleep_Ok +/** + * @} + */ + +/** @defgroup CAN_wake_up_constants + * @{ + */ +#define CAN_WakeUp_Failed ((uint8_t)0x00) /*!< CAN did not leave the sleep mode */ +#define CAN_WakeUp_Ok ((uint8_t)0x01) /*!< CAN leaved the sleep mode */ + +/* Legacy defines */ +#define CANWAKEUPFAILED CAN_WakeUp_Failed +#define CANWAKEUPOK CAN_WakeUp_Ok +/** + * @} + */ + +/** + * @defgroup CAN_Error_Code_constants + * @{ + */ +#define CAN_ErrorCode_NoErr ((uint8_t)0x00) /*!< No Error */ +#define CAN_ErrorCode_StuffErr ((uint8_t)0x10) /*!< Stuff Error */ +#define CAN_ErrorCode_FormErr ((uint8_t)0x20) /*!< Form Error */ +#define CAN_ErrorCode_ACKErr ((uint8_t)0x30) /*!< Acknowledgment Error */ +#define CAN_ErrorCode_BitRecessiveErr ((uint8_t)0x40) /*!< Bit Recessive Error */ +#define CAN_ErrorCode_BitDominantErr ((uint8_t)0x50) /*!< Bit Dominant Error */ +#define CAN_ErrorCode_CRCErr ((uint8_t)0x60) /*!< CRC Error */ +#define CAN_ErrorCode_SoftwareSetErr ((uint8_t)0x70) /*!< Software Set Error */ +/** + * @} + */ + +/** @defgroup CAN_flags + * @{ + */ +/* If the flag is 0x3XXXXXXX, it means that it can be used with CAN_GetFlagStatus() + and CAN_ClearFlag() functions. */ +/* If the flag is 0x1XXXXXXX, it means that it can only be used with + CAN_GetFlagStatus() function. */ + +/* Transmit Flags */ +#define CAN_FLAG_RQCP0 ((uint32_t)0x38000001) /*!< Request MailBox0 Flag */ +#define CAN_FLAG_RQCP1 ((uint32_t)0x38000100) /*!< Request MailBox1 Flag */ +#define CAN_FLAG_RQCP2 ((uint32_t)0x38010000) /*!< Request MailBox2 Flag */ + +/* Receive Flags */ +#define CAN_FLAG_FMP0 ((uint32_t)0x12000003) /*!< FIFO 0 Message Pending Flag */ +#define CAN_FLAG_FF0 ((uint32_t)0x32000008) /*!< FIFO 0 Full Flag */ +#define CAN_FLAG_FOV0 ((uint32_t)0x32000010) /*!< FIFO 0 Overrun Flag */ +#define CAN_FLAG_FMP1 ((uint32_t)0x14000003) /*!< FIFO 1 Message Pending Flag */ +#define CAN_FLAG_FF1 ((uint32_t)0x34000008) /*!< FIFO 1 Full Flag */ +#define CAN_FLAG_FOV1 ((uint32_t)0x34000010) /*!< FIFO 1 Overrun Flag */ + +/* Operating Mode Flags */ +#define CAN_FLAG_WKU ((uint32_t)0x31000008) /*!< Wake up Flag */ +#define CAN_FLAG_SLAK ((uint32_t)0x31000012) /*!< Sleep acknowledge Flag */ +/* @note When SLAK interrupt is disabled (SLKIE=0), no polling on SLAKI is possible. + In this case the SLAK bit can be polled.*/ + +/* Error Flags */ +#define CAN_FLAG_EWG ((uint32_t)0x10F00001) /*!< Error Warning Flag */ +#define CAN_FLAG_EPV ((uint32_t)0x10F00002) /*!< Error Passive Flag */ +#define CAN_FLAG_BOF ((uint32_t)0x10F00004) /*!< Bus-Off Flag */ +#define CAN_FLAG_LEC ((uint32_t)0x30F00070) /*!< Last error code Flag */ + +#define IS_CAN_GET_FLAG(FLAG) (((FLAG) == CAN_FLAG_LEC) || ((FLAG) == CAN_FLAG_BOF) || \ + ((FLAG) == CAN_FLAG_EPV) || ((FLAG) == CAN_FLAG_EWG) || \ + ((FLAG) == CAN_FLAG_WKU) || ((FLAG) == CAN_FLAG_FOV0) || \ + ((FLAG) == CAN_FLAG_FF0) || ((FLAG) == CAN_FLAG_FMP0) || \ + ((FLAG) == CAN_FLAG_FOV1) || ((FLAG) == CAN_FLAG_FF1) || \ + ((FLAG) == CAN_FLAG_FMP1) || ((FLAG) == CAN_FLAG_RQCP2) || \ + ((FLAG) == CAN_FLAG_RQCP1)|| ((FLAG) == CAN_FLAG_RQCP0) || \ + ((FLAG) == CAN_FLAG_SLAK )) + +#define IS_CAN_CLEAR_FLAG(FLAG)(((FLAG) == CAN_FLAG_LEC) || ((FLAG) == CAN_FLAG_RQCP2) || \ + ((FLAG) == CAN_FLAG_RQCP1) || ((FLAG) == CAN_FLAG_RQCP0) || \ + ((FLAG) == CAN_FLAG_FF0) || ((FLAG) == CAN_FLAG_FOV0) ||\ + ((FLAG) == CAN_FLAG_FF1) || ((FLAG) == CAN_FLAG_FOV1) || \ + ((FLAG) == CAN_FLAG_WKU) || ((FLAG) == CAN_FLAG_SLAK)) +/** + * @} + */ + + +/** @defgroup CAN_interrupts + * @{ + */ +#define CAN_IT_TME ((uint32_t)0x00000001) /*!< Transmit mailbox empty Interrupt*/ + +/* Receive Interrupts */ +#define CAN_IT_FMP0 ((uint32_t)0x00000002) /*!< FIFO 0 message pending Interrupt*/ +#define CAN_IT_FF0 ((uint32_t)0x00000004) /*!< FIFO 0 full Interrupt*/ +#define CAN_IT_FOV0 ((uint32_t)0x00000008) /*!< FIFO 0 overrun Interrupt*/ +#define CAN_IT_FMP1 ((uint32_t)0x00000010) /*!< FIFO 1 message pending Interrupt*/ +#define CAN_IT_FF1 ((uint32_t)0x00000020) /*!< FIFO 1 full Interrupt*/ +#define CAN_IT_FOV1 ((uint32_t)0x00000040) /*!< FIFO 1 overrun Interrupt*/ + +/* Operating Mode Interrupts */ +#define CAN_IT_WKU ((uint32_t)0x00010000) /*!< Wake-up Interrupt*/ +#define CAN_IT_SLK ((uint32_t)0x00020000) /*!< Sleep acknowledge Interrupt*/ + +/* Error Interrupts */ +#define CAN_IT_EWG ((uint32_t)0x00000100) /*!< Error warning Interrupt*/ +#define CAN_IT_EPV ((uint32_t)0x00000200) /*!< Error passive Interrupt*/ +#define CAN_IT_BOF ((uint32_t)0x00000400) /*!< Bus-off Interrupt*/ +#define CAN_IT_LEC ((uint32_t)0x00000800) /*!< Last error code Interrupt*/ +#define CAN_IT_ERR ((uint32_t)0x00008000) /*!< Error Interrupt*/ + +/* Flags named as Interrupts : kept only for FW compatibility */ +#define CAN_IT_RQCP0 CAN_IT_TME +#define CAN_IT_RQCP1 CAN_IT_TME +#define CAN_IT_RQCP2 CAN_IT_TME + + +#define IS_CAN_IT(IT) (((IT) == CAN_IT_TME) || ((IT) == CAN_IT_FMP0) ||\ + ((IT) == CAN_IT_FF0) || ((IT) == CAN_IT_FOV0) ||\ + ((IT) == CAN_IT_FMP1) || ((IT) == CAN_IT_FF1) ||\ + ((IT) == CAN_IT_FOV1) || ((IT) == CAN_IT_EWG) ||\ + ((IT) == CAN_IT_EPV) || ((IT) == CAN_IT_BOF) ||\ + ((IT) == CAN_IT_LEC) || ((IT) == CAN_IT_ERR) ||\ + ((IT) == CAN_IT_WKU) || ((IT) == CAN_IT_SLK)) + +#define IS_CAN_CLEAR_IT(IT) (((IT) == CAN_IT_TME) || ((IT) == CAN_IT_FF0) ||\ + ((IT) == CAN_IT_FOV0)|| ((IT) == CAN_IT_FF1) ||\ + ((IT) == CAN_IT_FOV1)|| ((IT) == CAN_IT_EWG) ||\ + ((IT) == CAN_IT_EPV) || ((IT) == CAN_IT_BOF) ||\ + ((IT) == CAN_IT_LEC) || ((IT) == CAN_IT_ERR) ||\ + ((IT) == CAN_IT_WKU) || ((IT) == CAN_IT_SLK)) +/** + * @} + */ + +/** + * @} + */ + +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions --------------------------------------------------------*/ + +/* Function used to set the CAN configuration to the default reset state *****/ +void CAN_DeInit(CAN_TypeDef* CANx); + +/* Initialization and Configuration functions *********************************/ +uint8_t CAN_Init(CAN_TypeDef* CANx, CAN_InitTypeDef* CAN_InitStruct); +void CAN_FilterInit(CAN_FilterInitTypeDef* CAN_FilterInitStruct); +void CAN_StructInit(CAN_InitTypeDef* CAN_InitStruct); +void CAN_SlaveStartBank(uint8_t CAN_BankNumber); +void CAN_DBGFreeze(CAN_TypeDef* CANx, FunctionalState NewState); +void CAN_TTComModeCmd(CAN_TypeDef* CANx, FunctionalState NewState); + +/* CAN Frames Transmission functions ******************************************/ +uint8_t CAN_Transmit(CAN_TypeDef* CANx, CanTxMsg* TxMessage); +uint8_t CAN_TransmitStatus(CAN_TypeDef* CANx, uint8_t TransmitMailbox); +void CAN_CancelTransmit(CAN_TypeDef* CANx, uint8_t Mailbox); + +/* CAN Frames Reception functions *********************************************/ +void CAN_Receive(CAN_TypeDef* CANx, uint8_t FIFONumber, CanRxMsg* RxMessage); +void CAN_FIFORelease(CAN_TypeDef* CANx, uint8_t FIFONumber); +uint8_t CAN_MessagePending(CAN_TypeDef* CANx, uint8_t FIFONumber); + +/* Operation modes functions **************************************************/ +uint8_t CAN_OperatingModeRequest(CAN_TypeDef* CANx, uint8_t CAN_OperatingMode); +uint8_t CAN_Sleep(CAN_TypeDef* CANx); +uint8_t CAN_WakeUp(CAN_TypeDef* CANx); + +/* CAN Bus Error management functions *****************************************/ +uint8_t CAN_GetLastErrorCode(CAN_TypeDef* CANx); +uint8_t CAN_GetReceiveErrorCounter(CAN_TypeDef* CANx); +uint8_t CAN_GetLSBTransmitErrorCounter(CAN_TypeDef* CANx); + +/* Interrupts and flags management functions **********************************/ +void CAN_ITConfig(CAN_TypeDef* CANx, uint32_t CAN_IT, FunctionalState NewState); +FlagStatus CAN_GetFlagStatus(CAN_TypeDef* CANx, uint32_t CAN_FLAG); +void CAN_ClearFlag(CAN_TypeDef* CANx, uint32_t CAN_FLAG); +ITStatus CAN_GetITStatus(CAN_TypeDef* CANx, uint32_t CAN_IT); +void CAN_ClearITPendingBit(CAN_TypeDef* CANx, uint32_t CAN_IT); + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F30x_CAN_H */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_comp.h b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_comp.h new file mode 100755 index 0000000000..b3ebab997d --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_comp.h @@ -0,0 +1,435 @@ +/** + ****************************************************************************** + * @file stm32f30x_comp.h + * @author MCD Application Team + * @version V1.2.3 + * @date 10-July-2015 + * @brief This file contains all the functions prototypes for the COMP firmware + * library. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F30x_COMP_H +#define __STM32F30x_COMP_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f30x.h" + +/** @addtogroup STM32F30x_StdPeriph_Driver + * @{ + */ + +/** @addtogroup COMP + * @{ + */ + +/* Exported types ------------------------------------------------------------*/ + +/** + * @brief COMP Init structure definition + */ + +typedef struct +{ + + uint32_t COMP_InvertingInput; /*!< Selects the inverting input of the comparator. + This parameter can be a value of @ref COMP_InvertingInput */ + + uint32_t COMP_NonInvertingInput; /*!< Selects the non inverting input of the comparator. + This parameter can be a value of @ref COMP_NonInvertingInput */ + + uint32_t COMP_Output; /*!< Selects the output redirection of the comparator. + This parameter can be a value of @ref COMP_Output */ + + uint32_t COMP_BlankingSrce; /*!< Selects the output blanking source of the comparator. + This parameter can be a value of @ref COMP_BlankingSrce */ + + uint32_t COMP_OutputPol; /*!< Selects the output polarity of the comparator. + This parameter can be a value of @ref COMP_OutputPoloarity */ + + uint32_t COMP_Hysteresis; /*!< Selects the hysteresis voltage of the comparator. + This parameter can be a value of @ref COMP_Hysteresis */ + + uint32_t COMP_Mode; /*!< Selects the operating mode of the comparator + and allows to adjust the speed/consumption. + This parameter can be a value of @ref COMP_Mode */ +}COMP_InitTypeDef; + +/* Exported constants --------------------------------------------------------*/ + +/** @defgroup COMP_Exported_Constants + * @{ + */ + +/** @defgroup COMP_Selection + * @{ + */ + +#define COMP_Selection_COMP1 ((uint32_t)0x00000000) /*!< COMP1 Selection */ +#define COMP_Selection_COMP2 ((uint32_t)0x00000004) /*!< COMP2 Selection */ +#define COMP_Selection_COMP3 ((uint32_t)0x00000008) /*!< COMP3 Selection */ +#define COMP_Selection_COMP4 ((uint32_t)0x0000000C) /*!< COMP4 Selection */ +#define COMP_Selection_COMP5 ((uint32_t)0x00000010) /*!< COMP5 Selection */ +#define COMP_Selection_COMP6 ((uint32_t)0x00000014) /*!< COMP6 Selection */ +#define COMP_Selection_COMP7 ((uint32_t)0x00000018) /*!< COMP7 Selection */ + +#define IS_COMP_ALL_PERIPH(PERIPH) (((PERIPH) == COMP_Selection_COMP1) || \ + ((PERIPH) == COMP_Selection_COMP2) || \ + ((PERIPH) == COMP_Selection_COMP3) || \ + ((PERIPH) == COMP_Selection_COMP4) || \ + ((PERIPH) == COMP_Selection_COMP5) || \ + ((PERIPH) == COMP_Selection_COMP6) || \ + ((PERIPH) == COMP_Selection_COMP7)) + +/** + * @} + */ + +/** @defgroup COMP_InvertingInput + * @{ + */ + +#define COMP_InvertingInput_1_4VREFINT ((uint32_t)0x00000000) /*!< 1/4 VREFINT connected to comparator inverting input */ +#define COMP_InvertingInput_1_2VREFINT COMP_CSR_COMPxINSEL_0 /*!< 1/2 VREFINT connected to comparator inverting input */ +#define COMP_InvertingInput_3_4VREFINT COMP_CSR_COMPxINSEL_1 /*!< 3/4 VREFINT connected to comparator inverting input */ +#define COMP_InvertingInput_VREFINT ((uint32_t)0x00000030) /*!< VREFINT connected to comparator inverting input */ +#define COMP_InvertingInput_DAC1OUT1 COMP_CSR_COMPxINSEL_2 /*!< DAC1_OUT1 (PA4) connected to comparator inverting input */ +#define COMP_InvertingInput_DAC1OUT2 ((uint32_t)0x00000050) /*!< DAC1_OUT2 (PA5) connected to comparator inverting input */ + +#define COMP_InvertingInput_IO1 ((uint32_t)0x00000060) /*!< I/O1 (PA0 for COMP1, PA2 for COMP2, PD15 for COMP3, + PE8 for COMP4, PD13 for COMP5, PD10 for COMP6, + PC0 for COMP7) connected to comparator inverting input */ + +#define COMP_InvertingInput_IO2 COMP_CSR_COMPxINSEL /*!< I/O2 (PB12 for COMP3, PB2 for COMP4, PB10 for COMP5, + PB15 for COMP6) connected to comparator inverting input. + It is valid only for STM32F303xC devices */ + +#define COMP_InvertingInput_DAC2OUT1 COMP_CSR_COMPxINSEL_3 /*!< DAC2_OUT1 (PA6) connected to comparator inverting input */ + +#define IS_COMP_INVERTING_INPUT(INPUT) (((INPUT) == COMP_InvertingInput_1_4VREFINT) || \ + ((INPUT) == COMP_InvertingInput_1_2VREFINT) || \ + ((INPUT) == COMP_InvertingInput_3_4VREFINT) || \ + ((INPUT) == COMP_InvertingInput_VREFINT) || \ + ((INPUT) == COMP_InvertingInput_DAC1OUT1) || \ + ((INPUT) == COMP_InvertingInput_DAC1OUT2) || \ + ((INPUT) == COMP_InvertingInput_IO1) || \ + ((INPUT) == COMP_InvertingInput_IO2) || \ + ((INPUT) == COMP_InvertingInput_DAC2OUT1)) +/** + * @} + */ + +/** @defgroup COMP_NonInvertingInput + * @{ + */ + +#define COMP_NonInvertingInput_IO1 ((uint32_t)0x00000000) /*!< I/O1 (PA1 for COMP1, PA7 for COMP2, PB14 for COMP3, + PB0 for COMP4, PD12 for COMP5, PD11 for COMP6, + PA0 for COMP7) connected to comparator non inverting input */ + +#define COMP_NonInvertingInput_IO2 COMP_CSR_COMPxNONINSEL /*!< I/O2 (PA3 for COMP2, PD14 for COMP3, PE7 for COMP4, PB13 for COMP5, + PB11 for COMP6, PC1 for COMP7) connected to comparator non inverting input */ + +#define IS_COMP_NONINVERTING_INPUT(INPUT) (((INPUT) == COMP_NonInvertingInput_IO1) || \ + ((INPUT) == COMP_NonInvertingInput_IO2)) +/** + * @} + */ + +/** @defgroup COMP_Output + * @{ + */ + +#define COMP_Output_None ((uint32_t)0x00000000) /*!< COMP output isn't connected to other peripherals */ + +/* Output Redirection common for all comparators COMP1...COMP7 */ +#define COMP_Output_TIM1BKIN COMP_CSR_COMPxOUTSEL_0 /*!< COMP output connected to TIM1 Break Input (BKIN) */ +#define COMP_Output_TIM1BKIN2 ((uint32_t)0x00000800) /*!< COMP output connected to TIM1 Break Input 2 (BKIN2) */ +#define COMP_Output_TIM8BKIN ((uint32_t)0x00000C00) /*!< COMP output connected to TIM8 Break Input (BKIN) */ +#define COMP_Output_TIM8BKIN2 ((uint32_t)0x00001000) /*!< COMP output connected to TIM8 Break Input 2 (BKIN2) */ +#define COMP_Output_TIM1BKIN2_TIM8BKIN2 ((uint32_t)0x00001400) /*!< COMP output connected to TIM1 Break Input 2 and TIM8 Break Input 2 */ +#define COMP_Output_TIM20BKIN ((uint32_t)0x00003000) /*!< COMP output connected to TIM20 Break Input (BKIN) */ +#define COMP_Output_TIM20BKIN2 ((uint32_t)0x00003400) /*!< COMP output connected to TIM20 Break Input 2 (BKIN2) */ +#define COMP_Output_TIM1BKIN2_TIM8BKIN2_TIM20BKIN2 ((uint32_t)0x00001400) /*!< COMP output connected to TIM1 Break Input 2, TIM8 Break Input 2 and TIM20 Break Input2 */ + +/* Output Redirection common for COMP1 and COMP2 */ +#define COMP_Output_TIM1OCREFCLR ((uint32_t)0x00001800) /*!< COMP output connected to TIM1 OCREF Clear */ +#define COMP_Output_TIM1IC1 ((uint32_t)0x00001C00) /*!< COMP output connected to TIM1 Input Capture 1 */ +#define COMP_Output_TIM2IC4 ((uint32_t)0x00002000) /*!< COMP output connected to TIM2 Input Capture 4 */ +#define COMP_Output_TIM2OCREFCLR ((uint32_t)0x00002400) /*!< COMP output connected to TIM2 OCREF Clear */ +#define COMP_Output_TIM3IC1 ((uint32_t)0x00002800) /*!< COMP output connected to TIM3 Input Capture 1 */ +#define COMP_Output_TIM3OCREFCLR ((uint32_t)0x00002C00) /*!< COMP output connected to TIM3 OCREF Clear */ + +/* Output Redirection specific to COMP2 */ +#define COMP_Output_HRTIM1_FLT6 ((uint32_t)0x00003000) /*!< COMP output connected to HRTIM1 FLT6 */ +#define COMP_Output_HRTIM1_EE1_2 ((uint32_t)0x00003400) /*!< COMP output connected to HRTIM1 EE1_2*/ +#define COMP_Output_HRTIM1_EE6_2 ((uint32_t)0x00003800) /*!< COMP output connected to HRTIM1 EE6_2 */ +#define COMP_Output_TIM20OCREFCLR ((uint32_t)0x00003C00) /*!< COMP output connected to TIM20 OCREF Clear */ + +/* Output Redirection specific to COMP3 */ +#define COMP_Output_TIM4IC1 ((uint32_t)0x00001C00) /*!< COMP output connected to TIM4 Input Capture 1 */ +#define COMP_Output_TIM3IC2 ((uint32_t)0x00002000) /*!< COMP output connected to TIM3 Input Capture 2 */ +#define COMP_Output_TIM15IC1 ((uint32_t)0x00002800) /*!< COMP output connected to TIM15 Input Capture 1 */ +#define COMP_Output_TIM15BKIN ((uint32_t)0x00002C00) /*!< COMP output connected to TIM15 Break Input (BKIN) */ + +/* Output Redirection specific to COMP4 */ +#define COMP_Output_TIM3IC3 ((uint32_t)0x00001800) /*!< COMP output connected to TIM3 Input Capture 3 */ +#define COMP_Output_TIM8OCREFCLR ((uint32_t)0x00001C00) /*!< COMP output connected to TIM8 OCREF Clear */ +#define COMP_Output_TIM15IC2 ((uint32_t)0x00002000) /*!< COMP output connected to TIM15 Input Capture 2 */ +#define COMP_Output_TIM4IC2 ((uint32_t)0x00002400) /*!< COMP output connected to TIM4 Input Capture 2 */ +#define COMP_Output_TIM15OCREFCLR ((uint32_t)0x00002800) /*!< COMP output connected to TIM15 OCREF Clear */ + +#define COMP_Output_HRTIM1_FLT7 ((uint32_t)0x00003000) /*!< COMP output connected to HRTIM1 FLT7 */ +#define COMP_Output_HRTIM1_EE2_2 ((uint32_t)0x00003400) /*!< COMP output connected to HRTIM1 EE2_2*/ +#define COMP_Output_HRTIM1_EE7_2 ((uint32_t)0x00003800) /*!< COMP output connected to HRTIM1 EE7_2 */ + +/* Output Redirection specific to COMP5 */ +#define COMP_Output_TIM2IC1 ((uint32_t)0x00001800) /*!< COMP output connected to TIM2 Input Capture 1 */ +#define COMP_Output_TIM17IC1 ((uint32_t)0x00002000) /*!< COMP output connected to TIM17 Input Capture 1 */ +#define COMP_Output_TIM4IC3 ((uint32_t)0x00002400) /*!< COMP output connected to TIM4 Input Capture 3 */ +#define COMP_Output_TIM16BKIN ((uint32_t)0x00002800) /*!< COMP output connected to TIM16 Break Input (BKIN) */ + +/* Output Redirection specific to COMP6 */ +#define COMP_Output_TIM2IC2 ((uint32_t)0x00001800) /*!< COMP output connected to TIM2 Input Capture 2 */ +#define COMP_Output_COMP6TIM2OCREFCLR ((uint32_t)0x00002000) /*!< COMP output connected to TIM2 OCREF Clear */ +#define COMP_Output_TIM16OCREFCLR ((uint32_t)0x00002400) /*!< COMP output connected to TIM16 OCREF Clear */ +#define COMP_Output_TIM16IC1 ((uint32_t)0x00002800) /*!< COMP output connected to TIM16 Input Capture 1 */ +#define COMP_Output_TIM4IC4 ((uint32_t)0x00002C00) /*!< COMP output connected to TIM4 Input Capture 4 */ + +#define COMP_Output_HRTIM1_FLT8 ((uint32_t)0x00003000) /*!< COMP output connected to HRTIM1 FLT8 */ +#define COMP_Output_HRTIM1_EE3_2 ((uint32_t)0x00003400) /*!< COMP output connected to HRTIM1 EE3_2*/ +#define COMP_Output_HRTIM1_EE8_2 ((uint32_t)0x00003800) /*!< COMP output connected to HRTIM1 EE8_2 */ + +/* Output Redirection specific to COMP7 */ +#define COMP_Output_TIM2IC3 ((uint32_t)0x00002000) /*!< COMP output connected to TIM2 Input Capture 3 */ +#define COMP_Output_TIM1IC2 ((uint32_t)0x00002400) /*!< COMP output connected to TIM1 Input Capture 2 */ +#define COMP_Output_TIM17OCREFCLR ((uint32_t)0x00002800) /*!< COMP output connected to TIM16 OCREF Clear */ +#define COMP_Output_TIM17BKIN ((uint32_t)0x00002C00) /*!< COMP output connected to TIM16 Break Input (BKIN) */ + +#define IS_COMP_OUTPUT(OUTPUT) (((OUTPUT) == COMP_Output_None) || \ + ((OUTPUT) == COMP_Output_TIM1BKIN) || \ + ((OUTPUT) == COMP_Output_TIM1IC1) || \ + ((OUTPUT) == COMP_Output_TIM1OCREFCLR) || \ + ((OUTPUT) == COMP_Output_TIM2IC4) || \ + ((OUTPUT) == COMP_Output_TIM2OCREFCLR) || \ + ((OUTPUT) == COMP_Output_COMP6TIM2OCREFCLR) || \ + ((OUTPUT) == COMP_Output_TIM3IC1) || \ + ((OUTPUT) == COMP_Output_TIM3OCREFCLR) || \ + ((OUTPUT) == COMP_Output_TIM8BKIN) || \ + ((OUTPUT) == COMP_Output_TIM1BKIN2) || \ + ((OUTPUT) == COMP_Output_TIM8BKIN2) || \ + ((OUTPUT) == COMP_Output_TIM2OCREFCLR) || \ + ((OUTPUT) == COMP_Output_TIM1BKIN2_TIM8BKIN2) || \ + ((OUTPUT) == COMP_Output_TIM3IC2) || \ + ((OUTPUT) == COMP_Output_TIM4IC1) || \ + ((OUTPUT) == COMP_Output_TIM15IC1) || \ + ((OUTPUT) == COMP_Output_TIM15BKIN) || \ + ((OUTPUT) == COMP_Output_TIM8OCREFCLR) || \ + ((OUTPUT) == COMP_Output_TIM3IC3) || \ + ((OUTPUT) == COMP_Output_TIM4IC1) || \ + ((OUTPUT) == COMP_Output_TIM15IC1) || \ + ((OUTPUT) == COMP_Output_TIM2IC1) || \ + ((OUTPUT) == COMP_Output_TIM4IC3) || \ + ((OUTPUT) == COMP_Output_TIM16BKIN) || \ + ((OUTPUT) == COMP_Output_TIM17IC1) || \ + ((OUTPUT) == COMP_Output_TIM2IC2) || \ + ((OUTPUT) == COMP_Output_TIM16IC1) || \ + ((OUTPUT) == COMP_Output_TIM4IC4) || \ + ((OUTPUT) == COMP_Output_TIM16OCREFCLR) || \ + ((OUTPUT) == COMP_Output_TIM2IC3) || \ + ((OUTPUT) == COMP_Output_TIM1IC2) || \ + ((OUTPUT) == COMP_Output_TIM17BKIN) || \ + ((OUTPUT) == COMP_Output_TIM17OCREFCLR) || \ + ((OUTPUT) == COMP_Output_HRTIM1_FLT6) || \ + ((OUTPUT) == COMP_Output_HRTIM1_EE1_2) || \ + ((OUTPUT) == COMP_Output_HRTIM1_EE6_2) || \ + ((OUTPUT) == COMP_Output_HRTIM1_FLT7) || \ + ((OUTPUT) == COMP_Output_HRTIM1_EE2_2) || \ + ((OUTPUT) == COMP_Output_HRTIM1_EE7_2) || \ + ((OUTPUT) == COMP_Output_HRTIM1_FLT8) || \ + ((OUTPUT) == COMP_Output_HRTIM1_EE3_2) || \ + ((OUTPUT) == COMP_Output_HRTIM1_EE8_2) || \ + ((OUTPUT) == COMP_Output_TIM20BKIN) || \ + ((OUTPUT) == COMP_Output_TIM20BKIN2) || \ + ((OUTPUT) == COMP_Output_TIM1BKIN2_TIM8BKIN2_TIM20BKIN2)|| \ + ((OUTPUT) == COMP_Output_TIM20OCREFCLR)) + +/** + * @} + */ + +/** @defgroup COMP_BlankingSrce + * @{ + */ + +/* No blanking source can be selected for all comparators */ +#define COMP_BlankingSrce_None ((uint32_t)0x00000000) /*!< No blanking source */ + +/* Blanking source common for COMP1, COMP2, COMP3 and COMP7 */ +#define COMP_BlankingSrce_TIM1OC5 COMP_CSR_COMPxBLANKING_0 /*!< TIM1 OC5 selected as blanking source for compartor */ + +/* Blanking source common for COMP1 and COMP2 */ +#define COMP_BlankingSrce_TIM2OC3 COMP_CSR_COMPxBLANKING_1 /*!< TIM2 OC5 selected as blanking source for compartor */ + +/* Blanking source common for COMP1, COMP2 and COMP5 */ +#define COMP_BlankingSrce_TIM3OC3 ((uint32_t)0x000C0000) /*!< TIM2 OC3 selected as blanking source for compartor */ + +/* Blanking source common for COMP3 and COMP6 */ +#define COMP_BlankingSrce_TIM2OC4 ((uint32_t)0x000C0000) /*!< TIM2 OC4 selected as blanking source for compartor */ + +/* Blanking source common for COMP4, COMP5, COMP6 and COMP7 */ +#define COMP_BlankingSrce_TIM8OC5 COMP_CSR_COMPxBLANKING_1 /*!< TIM8 OC5 selected as blanking source for compartor */ + +/* Blanking source for COMP4 */ +#define COMP_BlankingSrce_TIM3OC4 COMP_CSR_COMPxBLANKING_0 /*!< TIM3 OC4 selected as blanking source for compartor */ +#define COMP_BlankingSrce_TIM15OC1 ((uint32_t)0x000C0000) /*!< TIM15 OC1 selected as blanking source for compartor */ + +/* Blanking source common for COMP6 and COMP7 */ +#define COMP_BlankingSrce_TIM15OC2 COMP_CSR_COMPxBLANKING_2 /*!< TIM15 OC2 selected as blanking source for compartor */ + +#define IS_COMP_BLANKING_SOURCE(SOURCE) (((SOURCE) == COMP_BlankingSrce_None) || \ + ((SOURCE) == COMP_BlankingSrce_TIM1OC5) || \ + ((SOURCE) == COMP_BlankingSrce_TIM2OC3) || \ + ((SOURCE) == COMP_BlankingSrce_TIM3OC3) || \ + ((SOURCE) == COMP_BlankingSrce_TIM2OC4) || \ + ((SOURCE) == COMP_BlankingSrce_TIM8OC5) || \ + ((SOURCE) == COMP_BlankingSrce_TIM3OC4) || \ + ((SOURCE) == COMP_BlankingSrce_TIM15OC1) || \ + ((SOURCE) == COMP_BlankingSrce_TIM15OC2)) +/** + * @} + */ + +/** @defgroup COMP_OutputPoloarity + * @{ + */ +#define COMP_OutputPol_NonInverted ((uint32_t)0x00000000) /*!< COMP output on GPIO isn't inverted */ +#define COMP_OutputPol_Inverted COMP_CSR_COMPxPOL /*!< COMP output on GPIO is inverted */ + +#define IS_COMP_OUTPUT_POL(POL) (((POL) == COMP_OutputPol_NonInverted) || \ + ((POL) == COMP_OutputPol_Inverted)) + +/** + * @} + */ + +/** @defgroup COMP_Hysteresis + * @{ + */ +/* Please refer to the electrical characteristics in the device datasheet for + the hysteresis level */ +#define COMP_Hysteresis_No 0x00000000 /*!< No hysteresis */ +#define COMP_Hysteresis_Low COMP_CSR_COMPxHYST_0 /*!< Hysteresis level low */ +#define COMP_Hysteresis_Medium COMP_CSR_COMPxHYST_1 /*!< Hysteresis level medium */ +#define COMP_Hysteresis_High COMP_CSR_COMPxHYST /*!< Hysteresis level high */ + +#define IS_COMP_HYSTERESIS(HYSTERESIS) (((HYSTERESIS) == COMP_Hysteresis_No) || \ + ((HYSTERESIS) == COMP_Hysteresis_Low) || \ + ((HYSTERESIS) == COMP_Hysteresis_Medium) || \ + ((HYSTERESIS) == COMP_Hysteresis_High)) +/** + * @} + */ + +/** @defgroup COMP_Mode + * @{ + */ +/* Please refer to the electrical characteristics in the device datasheet for + the power consumption values */ +#define COMP_Mode_HighSpeed 0x00000000 /*!< High Speed */ +#define COMP_Mode_MediumSpeed COMP_CSR_COMPxMODE_0 /*!< Medium Speed */ +#define COMP_Mode_LowPower COMP_CSR_COMPxMODE_1 /*!< Low power mode */ +#define COMP_Mode_UltraLowPower COMP_CSR_COMPxMODE /*!< Ultra-low power mode */ + +#define IS_COMP_MODE(MODE) (((MODE) == COMP_Mode_UltraLowPower) || \ + ((MODE) == COMP_Mode_LowPower) || \ + ((MODE) == COMP_Mode_MediumSpeed) || \ + ((MODE) == COMP_Mode_HighSpeed)) +/** + * @} + */ + +/** @defgroup COMP_OutputLevel + * @{ + */ +/* When output polarity is not inverted, comparator output is high when + the non-inverting input is at a higher voltage than the inverting input */ +#define COMP_OutputLevel_High COMP_CSR_COMPxOUT +/* When output polarity is not inverted, comparator output is low when + the non-inverting input is at a lower voltage than the inverting input*/ +#define COMP_OutputLevel_Low ((uint32_t)0x00000000) + +/** + * @} + */ + +/** @defgroup COMP_WindowMode + * @{ + */ +#define IS_COMP_WINDOW(WINDOW) (((WINDOW) == COMP_Selection_COMP2) || \ + ((WINDOW) == COMP_Selection_COMP4) || \ + ((WINDOW) == COMP_Selection_COMP6)) +/** + * @} + */ + +/** + * @} + */ + +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions ------------------------------------------------------- */ + +/* Function used to set the COMP configuration to the default reset state ****/ +void COMP_DeInit(uint32_t COMP_Selection); + +/* Initialization and Configuration functions *********************************/ +void COMP_Init(uint32_t COMP_Selection, COMP_InitTypeDef* COMP_InitStruct); +void COMP_StructInit(COMP_InitTypeDef* COMP_InitStruct); +void COMP_Cmd(uint32_t COMP_Selection, FunctionalState NewState); +void COMP_SwitchCmd(uint32_t COMP_Selection, FunctionalState NewState); +uint32_t COMP_GetOutputLevel(uint32_t COMP_Selection); + +/* Window mode control function ***********************************************/ +void COMP_WindowCmd(uint32_t COMP_Selection, FunctionalState NewState); + +/* COMP configuration locking function ****************************************/ +void COMP_LockConfig(uint32_t COMP_Selection); + +#ifdef __cplusplus +} +#endif + +#endif /*__STM32F30x_COMP_H */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_crc.h b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_crc.h new file mode 100755 index 0000000000..50db40dafc --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_crc.h @@ -0,0 +1,121 @@ +/** + ****************************************************************************** + * @file stm32f30x_crc.h + * @author MCD Application Team + * @version V1.2.3 + * @date 10-July-2015 + * @brief This file contains all the functions prototypes for the CRC firmware + * library. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F30x_CRC_H +#define __STM32F30x_CRC_H + +#ifdef __cplusplus + extern "C" { +#endif + +/*!< Includes ----------------------------------------------------------------*/ +#include "stm32f30x.h" + +/** @addtogroup STM32F30x_StdPeriph_Driver + * @{ + */ + +/** @addtogroup CRC + * @{ + */ + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +/** @defgroup CRC_ReverseInputData + * @{ + */ +#define CRC_ReverseInputData_No ((uint32_t)0x00000000) /*!< No reverse operation of Input Data */ +#define CRC_ReverseInputData_8bits CRC_CR_REV_IN_0 /*!< Reverse operation of Input Data on 8 bits */ +#define CRC_ReverseInputData_16bits CRC_CR_REV_IN_1 /*!< Reverse operation of Input Data on 16 bits */ +#define CRC_ReverseInputData_32bits CRC_CR_REV_IN /*!< Reverse operation of Input Data on 32 bits */ + +#define IS_CRC_REVERSE_INPUT_DATA(DATA) (((DATA) == CRC_ReverseInputData_No) || \ + ((DATA) == CRC_ReverseInputData_8bits) || \ + ((DATA) == CRC_ReverseInputData_16bits) || \ + ((DATA) == CRC_ReverseInputData_32bits)) + +/** + * @} + */ + +/** @defgroup CRC_PolynomialSize + * @{ + */ +#define CRC_PolSize_7 CRC_CR_POLSIZE /*!< 7-bit polynomial for CRC calculation */ +#define CRC_PolSize_8 CRC_CR_POLSIZE_1 /*!< 8-bit polynomial for CRC calculation */ +#define CRC_PolSize_16 CRC_CR_POLSIZE_0 /*!< 16-bit polynomial for CRC calculation */ +#define CRC_PolSize_32 ((uint32_t)0x00000000)/*!< 32-bit polynomial for CRC calculation */ + +#define IS_CRC_POL_SIZE(SIZE) (((SIZE) == CRC_PolSize_7) || \ + ((SIZE) == CRC_PolSize_8) || \ + ((SIZE) == CRC_PolSize_16) || \ + ((SIZE) == CRC_PolSize_32)) + +/** + * @} + */ + +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions ------------------------------------------------------- */ +/* Configuration of the CRC computation unit **********************************/ +void CRC_DeInit(void); +void CRC_ResetDR(void); +void CRC_PolynomialSizeSelect(uint32_t CRC_PolSize); +void CRC_ReverseInputDataSelect(uint32_t CRC_ReverseInputData); +void CRC_ReverseOutputDataCmd(FunctionalState NewState); +void CRC_SetInitRegister(uint32_t CRC_InitValue); +void CRC_SetPolynomial(uint32_t CRC_Pol); + +/* CRC computation ************************************************************/ +uint32_t CRC_CalcCRC(uint32_t CRC_Data); +uint32_t CRC_CalcCRC16bits(uint16_t CRC_Data); +uint32_t CRC_CalcCRC8bits(uint8_t CRC_Data); +uint32_t CRC_CalcBlockCRC(uint32_t pBuffer[], uint32_t BufferLength); +uint32_t CRC_GetCRC(void); + +/* Independent register (IDR) access (write/read) *****************************/ +void CRC_SetIDRegister(uint8_t CRC_IDValue); +uint8_t CRC_GetIDRegister(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F30x_CRC_H */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_dac.h b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_dac.h new file mode 100755 index 0000000000..9481708450 --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_dac.h @@ -0,0 +1,322 @@ +/** + ****************************************************************************** + * @file stm32f30x_dac.h + * @author MCD Application Team + * @version V1.2.3 + * @date 10-July-2015 + * @brief This file contains all the functions prototypes for the DAC firmware + * library. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F30x_DAC_H +#define __STM32F30x_DAC_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f30x.h" + +/** @addtogroup STM32F30x_StdPeriph_Driver + * @{ + */ + +/** @addtogroup DAC + * @{ + */ + +/* Exported types ------------------------------------------------------------*/ +#define DAC_CR_DMAUDRIE ((uint32_t)0x00002000) /*!< DAC channel DMA underrun interrupt enable */ + +/** + * @brief DAC Init structure definition + */ + +typedef struct +{ + uint32_t DAC_Trigger; /*!< Specifies the external trigger for the selected DAC channel. + This parameter can be a value of @ref DAC_trigger_selection */ + + uint32_t DAC_WaveGeneration; /*!< Specifies whether DAC channel noise waves or triangle waves + are generated, or whether no wave is generated. + This parameter can be a value of @ref DAC_wave_generation */ + + uint32_t DAC_LFSRUnmask_TriangleAmplitude; /*!< Specifies the LFSR mask for noise wave generation or + the maximum amplitude triangle generation for the DAC channel. + This parameter can be a value of @ref DAC_lfsrunmask_triangleamplitude */ + + uint32_t DAC_Buffer_Switch; /*!< Specifies whether the DAC channel output buffer is enabled or disabled or + the DAC channel output switch is enabled or disabled. + This parameter can be a value of @ref DAC_buffer_switch */ +}DAC_InitTypeDef; + +/* Exported constants --------------------------------------------------------*/ + +/** @defgroup DAC_Exported_Constants + * @{ + */ + +#define IS_DAC_ALL_PERIPH(PERIPH) (((PERIPH) == DAC1) || \ + ((PERIPH) == DAC2)) + +#define IS_DAC_LIST1_PERIPH(PERIPH) (((PERIPH) == DAC1)) + +/** @defgroup DAC_trigger_selection + * @{ + */ + +#define DAC_Trigger_None ((uint32_t)0x00000000) /*!< Conversion is automatic once the DAC1_DHRxxxx register + has been loaded, and not by external trigger */ +#define DAC_Trigger_T6_TRGO ((uint32_t)0x00000004) /*!< TIM6 TRGO selected as external conversion trigger for DAC1/2 channel1/2 */ +#define DAC_Trigger_T3_TRGO ((uint32_t)0x0000000C) /*!< TIM3 TRGO selected as external conversion trigger for DAC1/2 channel1/2 */ +#define DAC_Trigger_T8_TRGO ((uint32_t)0x0000000C) /*!< TIM8 TRGO selected as external conversion trigger for DAC1 channel1/2 */ +#define DAC_Trigger_T7_TRGO ((uint32_t)0x00000014) /*!< TIM7 TRGO selected as external conversion trigger for DAC1/2 channel1/2 */ +#define DAC_Trigger_T15_TRGO ((uint32_t)0x0000001C) /*!< TIM15 TRGO selected as external conversion trigger for DAC1/2 channel1/2 */ +#define DAC_Trigger_HRTIM1_DACTRG1 ((uint32_t)0x0000001C) /*!< HRTIM1 DACTRG1 selected as external conversion trigger for DAC1 channel1/2 */ +#define DAC_Trigger_T2_TRGO ((uint32_t)0x00000024) /*!< TIM2 TRGO selected as external conversion trigger for DAC1/2 channel1/2 */ +#define DAC_Trigger_T4_TRGO ((uint32_t)0x0000002C) /*!< TIM4 TRGO selected as external conversion trigger for DAC channel */ +#define DAC_Trigger_HRTIM1_DACTRG2 ((uint32_t)0x0000002C) /*!< HRTIM1 DACTRG2 selected as external conversion trigger for DAC1 channel1/2 */ +#define DAC_Trigger_HRTIM1_DACTRG3 ((uint32_t)0x0000002C) /*!< HRTIM1 DACTRG3 selected as external conversion trigger for DAC2 channel1 */ +#define DAC_Trigger_Ext_IT9 ((uint32_t)0x00000034) /*!< EXTI Line9 event selected as external conversion trigger for DAC1/2 channel1/2 */ +#define DAC_Trigger_Software ((uint32_t)0x0000003C) /*!< Conversion started by software trigger for DAC1/2 channel1/2 */ + +#define IS_DAC_TRIGGER(TRIGGER) (((TRIGGER) == DAC_Trigger_None) || \ + ((TRIGGER) == DAC_Trigger_T6_TRGO) || \ + ((TRIGGER) == DAC_Trigger_T3_TRGO) || \ + ((TRIGGER) == DAC_Trigger_T8_TRGO) || \ + ((TRIGGER) == DAC_Trigger_T7_TRGO) || \ + ((TRIGGER) == DAC_Trigger_T15_TRGO) || \ + ((TRIGGER) == DAC_Trigger_HRTIM1_DACTRG1)|| \ + ((TRIGGER) == DAC_Trigger_T2_TRGO) || \ + ((TRIGGER) == DAC_Trigger_T4_TRGO) || \ + ((TRIGGER) == DAC_Trigger_HRTIM1_DACTRG2)|| \ + ((TRIGGER) == DAC_Trigger_HRTIM1_DACTRG3)|| \ + ((TRIGGER) == DAC_Trigger_Ext_IT9) || \ + ((TRIGGER) == DAC_Trigger_Software)) + +/** + * @} + */ + +/** @defgroup DAC_wave_generation + * @{ + */ + +#define DAC_WaveGeneration_None ((uint32_t)0x00000000) +#define DAC_WaveGeneration_Noise ((uint32_t)0x00000040) +#define DAC_WaveGeneration_Triangle ((uint32_t)0x00000080) + +#define IS_DAC_GENERATE_WAVE(WAVE) (((WAVE) == DAC_WaveGeneration_None) || \ + ((WAVE) == DAC_WaveGeneration_Noise) || \ + ((WAVE) == DAC_WaveGeneration_Triangle)) +/** + * @} + */ + +/** @defgroup DAC_lfsrunmask_triangleamplitude + * @{ + */ + +#define DAC_LFSRUnmask_Bit0 ((uint32_t)0x00000000) /*!< Unmask DAC channel LFSR bit0 for noise wave generation */ +#define DAC_LFSRUnmask_Bits1_0 ((uint32_t)0x00000100) /*!< Unmask DAC channel LFSR bit[1:0] for noise wave generation */ +#define DAC_LFSRUnmask_Bits2_0 ((uint32_t)0x00000200) /*!< Unmask DAC channel LFSR bit[2:0] for noise wave generation */ +#define DAC_LFSRUnmask_Bits3_0 ((uint32_t)0x00000300) /*!< Unmask DAC channel LFSR bit[3:0] for noise wave generation */ +#define DAC_LFSRUnmask_Bits4_0 ((uint32_t)0x00000400) /*!< Unmask DAC channel LFSR bit[4:0] for noise wave generation */ +#define DAC_LFSRUnmask_Bits5_0 ((uint32_t)0x00000500) /*!< Unmask DAC channel LFSR bit[5:0] for noise wave generation */ +#define DAC_LFSRUnmask_Bits6_0 ((uint32_t)0x00000600) /*!< Unmask DAC channel LFSR bit[6:0] for noise wave generation */ +#define DAC_LFSRUnmask_Bits7_0 ((uint32_t)0x00000700) /*!< Unmask DAC channel LFSR bit[7:0] for noise wave generation */ +#define DAC_LFSRUnmask_Bits8_0 ((uint32_t)0x00000800) /*!< Unmask DAC channel LFSR bit[8:0] for noise wave generation */ +#define DAC_LFSRUnmask_Bits9_0 ((uint32_t)0x00000900) /*!< Unmask DAC channel LFSR bit[9:0] for noise wave generation */ +#define DAC_LFSRUnmask_Bits10_0 ((uint32_t)0x00000A00) /*!< Unmask DAC channel LFSR bit[10:0] for noise wave generation */ +#define DAC_LFSRUnmask_Bits11_0 ((uint32_t)0x00000B00) /*!< Unmask DAC channel LFSR bit[11:0] for noise wave generation */ +#define DAC_TriangleAmplitude_1 ((uint32_t)0x00000000) /*!< Select max triangle amplitude of 1 */ +#define DAC_TriangleAmplitude_3 ((uint32_t)0x00000100) /*!< Select max triangle amplitude of 3 */ +#define DAC_TriangleAmplitude_7 ((uint32_t)0x00000200) /*!< Select max triangle amplitude of 7 */ +#define DAC_TriangleAmplitude_15 ((uint32_t)0x00000300) /*!< Select max triangle amplitude of 15 */ +#define DAC_TriangleAmplitude_31 ((uint32_t)0x00000400) /*!< Select max triangle amplitude of 31 */ +#define DAC_TriangleAmplitude_63 ((uint32_t)0x00000500) /*!< Select max triangle amplitude of 63 */ +#define DAC_TriangleAmplitude_127 ((uint32_t)0x00000600) /*!< Select max triangle amplitude of 127 */ +#define DAC_TriangleAmplitude_255 ((uint32_t)0x00000700) /*!< Select max triangle amplitude of 255 */ +#define DAC_TriangleAmplitude_511 ((uint32_t)0x00000800) /*!< Select max triangle amplitude of 511 */ +#define DAC_TriangleAmplitude_1023 ((uint32_t)0x00000900) /*!< Select max triangle amplitude of 1023 */ +#define DAC_TriangleAmplitude_2047 ((uint32_t)0x00000A00) /*!< Select max triangle amplitude of 2047 */ +#define DAC_TriangleAmplitude_4095 ((uint32_t)0x00000B00) /*!< Select max triangle amplitude of 4095 */ + +#define IS_DAC_LFSR_UNMASK_TRIANGLE_AMPLITUDE(VALUE) (((VALUE) == DAC_LFSRUnmask_Bit0) || \ + ((VALUE) == DAC_LFSRUnmask_Bits1_0) || \ + ((VALUE) == DAC_LFSRUnmask_Bits2_0) || \ + ((VALUE) == DAC_LFSRUnmask_Bits3_0) || \ + ((VALUE) == DAC_LFSRUnmask_Bits4_0) || \ + ((VALUE) == DAC_LFSRUnmask_Bits5_0) || \ + ((VALUE) == DAC_LFSRUnmask_Bits6_0) || \ + ((VALUE) == DAC_LFSRUnmask_Bits7_0) || \ + ((VALUE) == DAC_LFSRUnmask_Bits8_0) || \ + ((VALUE) == DAC_LFSRUnmask_Bits9_0) || \ + ((VALUE) == DAC_LFSRUnmask_Bits10_0) || \ + ((VALUE) == DAC_LFSRUnmask_Bits11_0) || \ + ((VALUE) == DAC_TriangleAmplitude_1) || \ + ((VALUE) == DAC_TriangleAmplitude_3) || \ + ((VALUE) == DAC_TriangleAmplitude_7) || \ + ((VALUE) == DAC_TriangleAmplitude_15) || \ + ((VALUE) == DAC_TriangleAmplitude_31) || \ + ((VALUE) == DAC_TriangleAmplitude_63) || \ + ((VALUE) == DAC_TriangleAmplitude_127) || \ + ((VALUE) == DAC_TriangleAmplitude_255) || \ + ((VALUE) == DAC_TriangleAmplitude_511) || \ + ((VALUE) == DAC_TriangleAmplitude_1023) || \ + ((VALUE) == DAC_TriangleAmplitude_2047) || \ + ((VALUE) == DAC_TriangleAmplitude_4095)) +/** + * @} + */ + +/** @defgroup DAC_buffer_switch + * @{ + */ + +#define DAC_BufferSwitch_Disable ((uint32_t)0x00000000) +#define DAC_BufferSwitch_Enable ((uint32_t)0x00000002) + +#define IS_DAC_BUFFER_SWITCH_STATE(STATE) (((STATE) == DAC_BufferSwitch_Enable) || \ + ((STATE) == DAC_BufferSwitch_Disable)) +/** + * @} + */ + +/** @defgroup DAC_Channel_selection + * @{ + */ +#define DAC_Channel_1 ((uint32_t)0x00000000) +#define DAC_Channel_2 ((uint32_t)0x00000010) + +#define IS_DAC_CHANNEL(CHANNEL) (((CHANNEL) == DAC_Channel_1) || \ + ((CHANNEL) == DAC_Channel_2)) +/** + * @} + */ + +/** @defgroup DAC_data_alignement + * @{ + */ + +#define DAC_Align_12b_R ((uint32_t)0x00000000) +#define DAC_Align_12b_L ((uint32_t)0x00000004) +#define DAC_Align_8b_R ((uint32_t)0x00000008) + +#define IS_DAC_ALIGN(ALIGN) (((ALIGN) == DAC_Align_12b_R) || \ + ((ALIGN) == DAC_Align_12b_L) || \ + ((ALIGN) == DAC_Align_8b_R)) +/** + * @} + */ + +/** @defgroup DAC_wave_generation + * @{ + */ + +#define DAC_Wave_Noise ((uint32_t)0x00000040) +#define DAC_Wave_Triangle ((uint32_t)0x00000080) + +#define IS_DAC_WAVE(WAVE) (((WAVE) == DAC_Wave_Noise) || \ + ((WAVE) == DAC_Wave_Triangle)) +/** + * @} + */ + +/** @defgroup DAC_data + * @{ + */ + +#define IS_DAC_DATA(DATA) ((DATA) <= 0xFFF0) +/** + * @} + */ + +/** @defgroup DAC_interrupts_definition + * @{ + */ +#define DAC_IT_DMAUDR ((uint32_t)0x00002000) +#define IS_DAC_IT(IT) (((IT) == DAC_IT_DMAUDR)) + +/** + * @} + */ + +/** @defgroup DAC_flags_definition + * @{ + */ + +#define DAC_FLAG_DMAUDR ((uint32_t)0x00002000) +#define IS_DAC_FLAG(FLAG) (((FLAG) == DAC_FLAG_DMAUDR)) + +/** + * @} + */ + +/** + * @} + */ + +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions --------------------------------------------------------*/ + +/* Function used to set the DAC configuration to the default reset state *****/ +void DAC_DeInit(DAC_TypeDef* DACx); + +/* DAC channels configuration: trigger, output buffer, data format functions */ +void DAC_Init(DAC_TypeDef* DACx, uint32_t DAC_Channel, DAC_InitTypeDef* DAC_InitStruct); +void DAC_StructInit(DAC_InitTypeDef* DAC_InitStruct); +void DAC_Cmd(DAC_TypeDef* DACx, uint32_t DAC_Channel, FunctionalState NewState); +void DAC_SoftwareTriggerCmd(DAC_TypeDef* DACx, uint32_t DAC_Channel, FunctionalState NewState); +void DAC_DualSoftwareTriggerCmd(DAC_TypeDef* DACx, FunctionalState NewState); +void DAC_WaveGenerationCmd(DAC_TypeDef* DACx, uint32_t DAC_Channel, uint32_t DAC_Wave, FunctionalState NewState); +void DAC_SetChannel1Data(DAC_TypeDef* DACx, uint32_t DAC_Align, uint16_t Data); +void DAC_SetChannel2Data(DAC_TypeDef* DACx, uint32_t DAC_Align, uint16_t Data); +void DAC_SetDualChannelData(DAC_TypeDef* DACx, uint32_t DAC_Align, uint16_t Data2, uint16_t Data1); +uint16_t DAC_GetDataOutputValue(DAC_TypeDef* DACx, uint32_t DAC_Channel); + +/* DMA management functions ***************************************************/ +void DAC_DMACmd(DAC_TypeDef* DACx, uint32_t DAC_Channel, FunctionalState NewState); + +/* Interrupts and flags management functions **********************************/ +void DAC_ITConfig(DAC_TypeDef* DACx, uint32_t DAC_Channel, uint32_t DAC_IT, FunctionalState NewState); +FlagStatus DAC_GetFlagStatus(DAC_TypeDef* DACx, uint32_t DAC_Channel, uint32_t DAC_FLAG); +void DAC_ClearFlag(DAC_TypeDef* DACx, uint32_t DAC_Channel, uint32_t DAC_FLAG); +ITStatus DAC_GetITStatus(DAC_TypeDef* DACx, uint32_t DAC_Channel, uint32_t DAC_IT); +void DAC_ClearITPendingBit(DAC_TypeDef* DACx, uint32_t DAC_Channel, uint32_t DAC_IT); + +#ifdef __cplusplus +} +#endif + +#endif /*__STM32F30x_DAC_H */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_dbgmcu.h b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_dbgmcu.h new file mode 100755 index 0000000000..0968bb60e4 --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_dbgmcu.h @@ -0,0 +1,110 @@ +/** + ****************************************************************************** + * @file stm32f30x_dbgmcu.h + * @author MCD Application Team + * @version V1.2.3 + * @date 10-July-2015 + * @brief This file contains all the functions prototypes for the DBGMCU firmware library. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F30x_DBGMCU_H +#define __STM32F30x_DBGMCU_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f30x.h" + +/** @addtogroup STM32F30x_StdPeriph_Driver + * @{ + */ + +/** @addtogroup DBGMCU + * @{ + */ + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +/** @defgroup DBGMCU_Exported_Constants + * @{ + */ +#define DBGMCU_SLEEP ((uint32_t)0x00000001) +#define DBGMCU_STOP ((uint32_t)0x00000002) +#define DBGMCU_STANDBY ((uint32_t)0x00000004) +#define IS_DBGMCU_PERIPH(PERIPH) ((((PERIPH) & 0xFFFFFFF8) == 0x00) && ((PERIPH) != 0x00)) + +#define DBGMCU_TIM2_STOP ((uint32_t)0x00000001) +#define DBGMCU_TIM3_STOP ((uint32_t)0x00000002) +#define DBGMCU_TIM4_STOP ((uint32_t)0x00000004) +#define DBGMCU_TIM6_STOP ((uint32_t)0x00000010) +#define DBGMCU_TIM7_STOP ((uint32_t)0x00000020) +#define DBGMCU_RTC_STOP ((uint32_t)0x00000400) +#define DBGMCU_WWDG_STOP ((uint32_t)0x00000800) +#define DBGMCU_IWDG_STOP ((uint32_t)0x00001000) +#define DBGMCU_I2C1_SMBUS_TIMEOUT ((uint32_t)0x00200000) +#define DBGMCU_I2C2_SMBUS_TIMEOUT ((uint32_t)0x00400000) +#define DBGMCU_CAN1_STOP ((uint32_t)0x02000000) +#define DBGMCU_I2C3_SMBUS_TIMEOUT ((uint32_t)0x40000000) + +#define IS_DBGMCU_APB1PERIPH(PERIPH) ((((PERIPH) & 0xBD9FE3C8) == 0x00) && ((PERIPH) != 0x00)) + +#define DBGMCU_TIM1_STOP ((uint32_t)0x00000001) +#define DBGMCU_TIM8_STOP ((uint32_t)0x00000002) +#define DBGMCU_TIM15_STOP ((uint32_t)0x00000004) +#define DBGMCU_TIM16_STOP ((uint32_t)0x00000008) +#define DBGMCU_TIM17_STOP ((uint32_t)0x00000010) +#define DBGMCU_TIM20_STOP ((uint32_t)0x00000020) +#define IS_DBGMCU_APB2PERIPH(PERIPH) ((((PERIPH) & 0xFFFFFFC0) == 0x00) && ((PERIPH) != 0x00)) + +/** + * @} + */ + +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions --------------------------------------------------------*/ +/* Device and Revision ID management functions ********************************/ +uint32_t DBGMCU_GetREVID(void); +uint32_t DBGMCU_GetDEVID(void); + +/* Peripherals Configuration functions ****************************************/ +void DBGMCU_Config(uint32_t DBGMCU_Periph, FunctionalState NewState); +void DBGMCU_APB1PeriphConfig(uint32_t DBGMCU_Periph, FunctionalState NewState); +void DBGMCU_APB2PeriphConfig(uint32_t DBGMCU_Periph, FunctionalState NewState); + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F30x_DBGMCU_H */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_dma.h b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_dma.h new file mode 100755 index 0000000000..e05d27149c --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_dma.h @@ -0,0 +1,436 @@ +/** + ****************************************************************************** + * @file stm32f30x_dma.h + * @author MCD Application Team + * @version V1.2.3 + * @date 10-July-2015 + * @brief This file contains all the functions prototypes for the DMA firmware + * library. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F30x_DMA_H +#define __STM32F30x_DMA_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f30x.h" + +/** @addtogroup STM32F30x_StdPeriph_Driver + * @{ + */ + +/** @addtogroup DMA + * @{ + */ + +/* Exported types ------------------------------------------------------------*/ + +/** + * @brief DMA Init structures definition + */ +typedef struct +{ + uint32_t DMA_PeripheralBaseAddr; /*!< Specifies the peripheral base address for DMAy Channelx. */ + + uint32_t DMA_MemoryBaseAddr; /*!< Specifies the memory base address for DMAy Channelx. */ + + uint32_t DMA_DIR; /*!< Specifies if the peripheral is the source or destination. + This parameter can be a value of @ref DMA_data_transfer_direction */ + + uint16_t DMA_BufferSize; /*!< Specifies the buffer size, in data unit, of the specified Channel. + The data unit is equal to the configuration set in DMA_PeripheralDataSize + or DMA_MemoryDataSize members depending in the transfer direction. */ + + uint32_t DMA_PeripheralInc; /*!< Specifies whether the Peripheral address register is incremented or not. + This parameter can be a value of @ref DMA_peripheral_incremented_mode */ + + uint32_t DMA_MemoryInc; /*!< Specifies whether the memory address register is incremented or not. + This parameter can be a value of @ref DMA_memory_incremented_mode */ + + uint32_t DMA_PeripheralDataSize; /*!< Specifies the Peripheral data width. + This parameter can be a value of @ref DMA_peripheral_data_size */ + + uint32_t DMA_MemoryDataSize; /*!< Specifies the Memory data width. + This parameter can be a value of @ref DMA_memory_data_size */ + + uint32_t DMA_Mode; /*!< Specifies the operation mode of the DMAy Channelx. + This parameter can be a value of @ref DMA_circular_normal_mode + @note: The circular buffer mode cannot be used if the memory-to-memory + data transfer is configured on the selected Channel */ + + uint32_t DMA_Priority; /*!< Specifies the software priority for the DMAy Channelx. + This parameter can be a value of @ref DMA_priority_level */ + + uint32_t DMA_M2M; /*!< Specifies if the DMAy Channelx will be used in memory-to-memory transfer. + This parameter can be a value of @ref DMA_memory_to_memory */ +}DMA_InitTypeDef; + +/* Exported constants --------------------------------------------------------*/ + +/** @defgroup DMA_Exported_Constants + * @{ + */ + +#define IS_DMA_ALL_PERIPH(PERIPH) (((PERIPH) == DMA1_Channel1) || \ + ((PERIPH) == DMA1_Channel2) || \ + ((PERIPH) == DMA1_Channel3) || \ + ((PERIPH) == DMA1_Channel4) || \ + ((PERIPH) == DMA1_Channel5) || \ + ((PERIPH) == DMA1_Channel6) || \ + ((PERIPH) == DMA1_Channel7) || \ + ((PERIPH) == DMA2_Channel1) || \ + ((PERIPH) == DMA2_Channel2) || \ + ((PERIPH) == DMA2_Channel3) || \ + ((PERIPH) == DMA2_Channel4) || \ + ((PERIPH) == DMA2_Channel5)) + +/** @defgroup DMA_data_transfer_direction + * @{ + */ + +#define DMA_DIR_PeripheralSRC ((uint32_t)0x00000000) +#define DMA_DIR_PeripheralDST DMA_CCR_DIR + +#define IS_DMA_DIR(DIR) (((DIR) == DMA_DIR_PeripheralSRC) || \ + ((DIR) == DMA_DIR_PeripheralDST)) +/** + * @} + */ + + +/** @defgroup DMA_peripheral_incremented_mode + * @{ + */ + +#define DMA_PeripheralInc_Disable ((uint32_t)0x00000000) +#define DMA_PeripheralInc_Enable DMA_CCR_PINC + +#define IS_DMA_PERIPHERAL_INC_STATE(STATE) (((STATE) == DMA_PeripheralInc_Disable) || \ + ((STATE) == DMA_PeripheralInc_Enable)) +/** + * @} + */ + +/** @defgroup DMA_memory_incremented_mode + * @{ + */ + +#define DMA_MemoryInc_Disable ((uint32_t)0x00000000) +#define DMA_MemoryInc_Enable DMA_CCR_MINC + +#define IS_DMA_MEMORY_INC_STATE(STATE) (((STATE) == DMA_MemoryInc_Disable) || \ + ((STATE) == DMA_MemoryInc_Enable)) +/** + * @} + */ + +/** @defgroup DMA_peripheral_data_size + * @{ + */ + +#define DMA_PeripheralDataSize_Byte ((uint32_t)0x00000000) +#define DMA_PeripheralDataSize_HalfWord DMA_CCR_PSIZE_0 +#define DMA_PeripheralDataSize_Word DMA_CCR_PSIZE_1 + +#define IS_DMA_PERIPHERAL_DATA_SIZE(SIZE) (((SIZE) == DMA_PeripheralDataSize_Byte) || \ + ((SIZE) == DMA_PeripheralDataSize_HalfWord) || \ + ((SIZE) == DMA_PeripheralDataSize_Word)) +/** + * @} + */ + +/** @defgroup DMA_memory_data_size + * @{ + */ + +#define DMA_MemoryDataSize_Byte ((uint32_t)0x00000000) +#define DMA_MemoryDataSize_HalfWord DMA_CCR_MSIZE_0 +#define DMA_MemoryDataSize_Word DMA_CCR_MSIZE_1 + +#define IS_DMA_MEMORY_DATA_SIZE(SIZE) (((SIZE) == DMA_MemoryDataSize_Byte) || \ + ((SIZE) == DMA_MemoryDataSize_HalfWord) || \ + ((SIZE) == DMA_MemoryDataSize_Word)) +/** + * @} + */ + +/** @defgroup DMA_circular_normal_mode + * @{ + */ + +#define DMA_Mode_Normal ((uint32_t)0x00000000) +#define DMA_Mode_Circular DMA_CCR_CIRC + +#define IS_DMA_MODE(MODE) (((MODE) == DMA_Mode_Normal) || ((MODE) == DMA_Mode_Circular)) +/** + * @} + */ + +/** @defgroup DMA_priority_level + * @{ + */ + +#define DMA_Priority_VeryHigh DMA_CCR_PL +#define DMA_Priority_High DMA_CCR_PL_1 +#define DMA_Priority_Medium DMA_CCR_PL_0 +#define DMA_Priority_Low ((uint32_t)0x00000000) + +#define IS_DMA_PRIORITY(PRIORITY) (((PRIORITY) == DMA_Priority_VeryHigh) || \ + ((PRIORITY) == DMA_Priority_High) || \ + ((PRIORITY) == DMA_Priority_Medium) || \ + ((PRIORITY) == DMA_Priority_Low)) +/** + * @} + */ + +/** @defgroup DMA_memory_to_memory + * @{ + */ + +#define DMA_M2M_Disable ((uint32_t)0x00000000) +#define DMA_M2M_Enable DMA_CCR_MEM2MEM + +#define IS_DMA_M2M_STATE(STATE) (((STATE) == DMA_M2M_Disable) || ((STATE) == DMA_M2M_Enable)) + +/** + * @} + */ + +/** @defgroup DMA_interrupts_definition + * @{ + */ + +#define DMA_IT_TC ((uint32_t)0x00000002) +#define DMA_IT_HT ((uint32_t)0x00000004) +#define DMA_IT_TE ((uint32_t)0x00000008) +#define IS_DMA_CONFIG_IT(IT) ((((IT) & 0xFFFFFFF1) == 0x00) && ((IT) != 0x00)) + +#define DMA1_IT_GL1 ((uint32_t)0x00000001) +#define DMA1_IT_TC1 ((uint32_t)0x00000002) +#define DMA1_IT_HT1 ((uint32_t)0x00000004) +#define DMA1_IT_TE1 ((uint32_t)0x00000008) +#define DMA1_IT_GL2 ((uint32_t)0x00000010) +#define DMA1_IT_TC2 ((uint32_t)0x00000020) +#define DMA1_IT_HT2 ((uint32_t)0x00000040) +#define DMA1_IT_TE2 ((uint32_t)0x00000080) +#define DMA1_IT_GL3 ((uint32_t)0x00000100) +#define DMA1_IT_TC3 ((uint32_t)0x00000200) +#define DMA1_IT_HT3 ((uint32_t)0x00000400) +#define DMA1_IT_TE3 ((uint32_t)0x00000800) +#define DMA1_IT_GL4 ((uint32_t)0x00001000) +#define DMA1_IT_TC4 ((uint32_t)0x00002000) +#define DMA1_IT_HT4 ((uint32_t)0x00004000) +#define DMA1_IT_TE4 ((uint32_t)0x00008000) +#define DMA1_IT_GL5 ((uint32_t)0x00010000) +#define DMA1_IT_TC5 ((uint32_t)0x00020000) +#define DMA1_IT_HT5 ((uint32_t)0x00040000) +#define DMA1_IT_TE5 ((uint32_t)0x00080000) +#define DMA1_IT_GL6 ((uint32_t)0x00100000) +#define DMA1_IT_TC6 ((uint32_t)0x00200000) +#define DMA1_IT_HT6 ((uint32_t)0x00400000) +#define DMA1_IT_TE6 ((uint32_t)0x00800000) +#define DMA1_IT_GL7 ((uint32_t)0x01000000) +#define DMA1_IT_TC7 ((uint32_t)0x02000000) +#define DMA1_IT_HT7 ((uint32_t)0x04000000) +#define DMA1_IT_TE7 ((uint32_t)0x08000000) + +#define DMA2_IT_GL1 ((uint32_t)0x10000001) +#define DMA2_IT_TC1 ((uint32_t)0x10000002) +#define DMA2_IT_HT1 ((uint32_t)0x10000004) +#define DMA2_IT_TE1 ((uint32_t)0x10000008) +#define DMA2_IT_GL2 ((uint32_t)0x10000010) +#define DMA2_IT_TC2 ((uint32_t)0x10000020) +#define DMA2_IT_HT2 ((uint32_t)0x10000040) +#define DMA2_IT_TE2 ((uint32_t)0x10000080) +#define DMA2_IT_GL3 ((uint32_t)0x10000100) +#define DMA2_IT_TC3 ((uint32_t)0x10000200) +#define DMA2_IT_HT3 ((uint32_t)0x10000400) +#define DMA2_IT_TE3 ((uint32_t)0x10000800) +#define DMA2_IT_GL4 ((uint32_t)0x10001000) +#define DMA2_IT_TC4 ((uint32_t)0x10002000) +#define DMA2_IT_HT4 ((uint32_t)0x10004000) +#define DMA2_IT_TE4 ((uint32_t)0x10008000) +#define DMA2_IT_GL5 ((uint32_t)0x10010000) +#define DMA2_IT_TC5 ((uint32_t)0x10020000) +#define DMA2_IT_HT5 ((uint32_t)0x10040000) +#define DMA2_IT_TE5 ((uint32_t)0x10080000) + +#define IS_DMA_CLEAR_IT(IT) (((((IT) & 0xF0000000) == 0x00) || (((IT) & 0xEFF00000) == 0x00)) && ((IT) != 0x00)) + +#define IS_DMA_GET_IT(IT) (((IT) == DMA1_IT_GL1) || ((IT) == DMA1_IT_TC1) || \ + ((IT) == DMA1_IT_HT1) || ((IT) == DMA1_IT_TE1) || \ + ((IT) == DMA1_IT_GL2) || ((IT) == DMA1_IT_TC2) || \ + ((IT) == DMA1_IT_HT2) || ((IT) == DMA1_IT_TE2) || \ + ((IT) == DMA1_IT_GL3) || ((IT) == DMA1_IT_TC3) || \ + ((IT) == DMA1_IT_HT3) || ((IT) == DMA1_IT_TE3) || \ + ((IT) == DMA1_IT_GL4) || ((IT) == DMA1_IT_TC4) || \ + ((IT) == DMA1_IT_HT4) || ((IT) == DMA1_IT_TE4) || \ + ((IT) == DMA1_IT_GL5) || ((IT) == DMA1_IT_TC5) || \ + ((IT) == DMA1_IT_HT5) || ((IT) == DMA1_IT_TE5) || \ + ((IT) == DMA1_IT_GL6) || ((IT) == DMA1_IT_TC6) || \ + ((IT) == DMA1_IT_HT6) || ((IT) == DMA1_IT_TE6) || \ + ((IT) == DMA1_IT_GL7) || ((IT) == DMA1_IT_TC7) || \ + ((IT) == DMA1_IT_HT7) || ((IT) == DMA1_IT_TE7) || \ + ((IT) == DMA2_IT_GL1) || ((IT) == DMA2_IT_TC1) || \ + ((IT) == DMA2_IT_HT1) || ((IT) == DMA2_IT_TE1) || \ + ((IT) == DMA2_IT_GL2) || ((IT) == DMA2_IT_TC2) || \ + ((IT) == DMA2_IT_HT2) || ((IT) == DMA2_IT_TE2) || \ + ((IT) == DMA2_IT_GL3) || ((IT) == DMA2_IT_TC3) || \ + ((IT) == DMA2_IT_HT3) || ((IT) == DMA2_IT_TE3) || \ + ((IT) == DMA2_IT_GL4) || ((IT) == DMA2_IT_TC4) || \ + ((IT) == DMA2_IT_HT4) || ((IT) == DMA2_IT_TE4) || \ + ((IT) == DMA2_IT_GL5) || ((IT) == DMA2_IT_TC5) || \ + ((IT) == DMA2_IT_HT5) || ((IT) == DMA2_IT_TE5)) + +/** + * @} + */ + +/** @defgroup DMA_flags_definition + * @{ + */ + +#define DMA1_FLAG_GL1 ((uint32_t)0x00000001) +#define DMA1_FLAG_TC1 ((uint32_t)0x00000002) +#define DMA1_FLAG_HT1 ((uint32_t)0x00000004) +#define DMA1_FLAG_TE1 ((uint32_t)0x00000008) +#define DMA1_FLAG_GL2 ((uint32_t)0x00000010) +#define DMA1_FLAG_TC2 ((uint32_t)0x00000020) +#define DMA1_FLAG_HT2 ((uint32_t)0x00000040) +#define DMA1_FLAG_TE2 ((uint32_t)0x00000080) +#define DMA1_FLAG_GL3 ((uint32_t)0x00000100) +#define DMA1_FLAG_TC3 ((uint32_t)0x00000200) +#define DMA1_FLAG_HT3 ((uint32_t)0x00000400) +#define DMA1_FLAG_TE3 ((uint32_t)0x00000800) +#define DMA1_FLAG_GL4 ((uint32_t)0x00001000) +#define DMA1_FLAG_TC4 ((uint32_t)0x00002000) +#define DMA1_FLAG_HT4 ((uint32_t)0x00004000) +#define DMA1_FLAG_TE4 ((uint32_t)0x00008000) +#define DMA1_FLAG_GL5 ((uint32_t)0x00010000) +#define DMA1_FLAG_TC5 ((uint32_t)0x00020000) +#define DMA1_FLAG_HT5 ((uint32_t)0x00040000) +#define DMA1_FLAG_TE5 ((uint32_t)0x00080000) +#define DMA1_FLAG_GL6 ((uint32_t)0x00100000) +#define DMA1_FLAG_TC6 ((uint32_t)0x00200000) +#define DMA1_FLAG_HT6 ((uint32_t)0x00400000) +#define DMA1_FLAG_TE6 ((uint32_t)0x00800000) +#define DMA1_FLAG_GL7 ((uint32_t)0x01000000) +#define DMA1_FLAG_TC7 ((uint32_t)0x02000000) +#define DMA1_FLAG_HT7 ((uint32_t)0x04000000) +#define DMA1_FLAG_TE7 ((uint32_t)0x08000000) + +#define DMA2_FLAG_GL1 ((uint32_t)0x10000001) +#define DMA2_FLAG_TC1 ((uint32_t)0x10000002) +#define DMA2_FLAG_HT1 ((uint32_t)0x10000004) +#define DMA2_FLAG_TE1 ((uint32_t)0x10000008) +#define DMA2_FLAG_GL2 ((uint32_t)0x10000010) +#define DMA2_FLAG_TC2 ((uint32_t)0x10000020) +#define DMA2_FLAG_HT2 ((uint32_t)0x10000040) +#define DMA2_FLAG_TE2 ((uint32_t)0x10000080) +#define DMA2_FLAG_GL3 ((uint32_t)0x10000100) +#define DMA2_FLAG_TC3 ((uint32_t)0x10000200) +#define DMA2_FLAG_HT3 ((uint32_t)0x10000400) +#define DMA2_FLAG_TE3 ((uint32_t)0x10000800) +#define DMA2_FLAG_GL4 ((uint32_t)0x10001000) +#define DMA2_FLAG_TC4 ((uint32_t)0x10002000) +#define DMA2_FLAG_HT4 ((uint32_t)0x10004000) +#define DMA2_FLAG_TE4 ((uint32_t)0x10008000) +#define DMA2_FLAG_GL5 ((uint32_t)0x10010000) +#define DMA2_FLAG_TC5 ((uint32_t)0x10020000) +#define DMA2_FLAG_HT5 ((uint32_t)0x10040000) +#define DMA2_FLAG_TE5 ((uint32_t)0x10080000) + +#define IS_DMA_CLEAR_FLAG(FLAG) (((((FLAG) & 0xF0000000) == 0x00) || (((FLAG) & 0xEFF00000) == 0x00)) && ((FLAG) != 0x00)) + +#define IS_DMA_GET_FLAG(FLAG) (((FLAG) == DMA1_FLAG_GL1) || ((FLAG) == DMA1_FLAG_TC1) || \ + ((FLAG) == DMA1_FLAG_HT1) || ((FLAG) == DMA1_FLAG_TE1) || \ + ((FLAG) == DMA1_FLAG_GL2) || ((FLAG) == DMA1_FLAG_TC2) || \ + ((FLAG) == DMA1_FLAG_HT2) || ((FLAG) == DMA1_FLAG_TE2) || \ + ((FLAG) == DMA1_FLAG_GL3) || ((FLAG) == DMA1_FLAG_TC3) || \ + ((FLAG) == DMA1_FLAG_HT3) || ((FLAG) == DMA1_FLAG_TE3) || \ + ((FLAG) == DMA1_FLAG_GL4) || ((FLAG) == DMA1_FLAG_TC4) || \ + ((FLAG) == DMA1_FLAG_HT4) || ((FLAG) == DMA1_FLAG_TE4) || \ + ((FLAG) == DMA1_FLAG_GL5) || ((FLAG) == DMA1_FLAG_TC5) || \ + ((FLAG) == DMA1_FLAG_HT5) || ((FLAG) == DMA1_FLAG_TE5) || \ + ((FLAG) == DMA1_FLAG_GL6) || ((FLAG) == DMA1_FLAG_TC6) || \ + ((FLAG) == DMA1_FLAG_HT6) || ((FLAG) == DMA1_FLAG_TE6) || \ + ((FLAG) == DMA1_FLAG_GL7) || ((FLAG) == DMA1_FLAG_TC7) || \ + ((FLAG) == DMA1_FLAG_HT7) || ((FLAG) == DMA1_FLAG_TE7) || \ + ((FLAG) == DMA2_FLAG_GL1) || ((FLAG) == DMA2_FLAG_TC1) || \ + ((FLAG) == DMA2_FLAG_HT1) || ((FLAG) == DMA2_FLAG_TE1) || \ + ((FLAG) == DMA2_FLAG_GL2) || ((FLAG) == DMA2_FLAG_TC2) || \ + ((FLAG) == DMA2_FLAG_HT2) || ((FLAG) == DMA2_FLAG_TE2) || \ + ((FLAG) == DMA2_FLAG_GL3) || ((FLAG) == DMA2_FLAG_TC3) || \ + ((FLAG) == DMA2_FLAG_HT3) || ((FLAG) == DMA2_FLAG_TE3) || \ + ((FLAG) == DMA2_FLAG_GL4) || ((FLAG) == DMA2_FLAG_TC4) || \ + ((FLAG) == DMA2_FLAG_HT4) || ((FLAG) == DMA2_FLAG_TE4) || \ + ((FLAG) == DMA2_FLAG_GL5) || ((FLAG) == DMA2_FLAG_TC5) || \ + ((FLAG) == DMA2_FLAG_HT5) || ((FLAG) == DMA2_FLAG_TE5)) + +/** + * @} + */ + +/** + * @} + */ + +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions ------------------------------------------------------- */ + +/* Function used to set the DMA configuration to the default reset state ******/ +void DMA_DeInit(DMA_Channel_TypeDef* DMAy_Channelx); + +/* Initialization and Configuration functions *********************************/ +void DMA_Init(DMA_Channel_TypeDef* DMAy_Channelx, DMA_InitTypeDef* DMA_InitStruct); +void DMA_StructInit(DMA_InitTypeDef* DMA_InitStruct); +void DMA_Cmd(DMA_Channel_TypeDef* DMAy_Channelx, FunctionalState NewState); + +/* Data Counter functions******************************************************/ +void DMA_SetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx, uint16_t DataNumber); +uint16_t DMA_GetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx); + +/* Interrupts and flags management functions **********************************/ +void DMA_ITConfig(DMA_Channel_TypeDef* DMAy_Channelx, uint32_t DMA_IT, FunctionalState NewState); +FlagStatus DMA_GetFlagStatus(uint32_t DMAy_FLAG); +void DMA_ClearFlag(uint32_t DMAy_FLAG); +ITStatus DMA_GetITStatus(uint32_t DMAy_IT); +void DMA_ClearITPendingBit(uint32_t DMAy_IT); + +#ifdef __cplusplus +} +#endif + +#endif /*__STM32F30x_DMA_H */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_exti.h b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_exti.h new file mode 100755 index 0000000000..120141044c --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_exti.h @@ -0,0 +1,234 @@ +/** + ****************************************************************************** + * @file stm32f30x_exti.h + * @author MCD Application Team + * @version V1.2.3 + * @date 10-July-2015 + * @brief This file contains all the functions prototypes for the EXTI + * firmware library. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F30x_EXTI_H +#define __STM32F30x_EXTI_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f30x.h" + +/** @addtogroup STM32F30x_StdPeriph_Driver + * @{ + */ + +/** @addtogroup EXTI + * @{ + */ + +/* Exported types ------------------------------------------------------------*/ + +/** + * @brief EXTI mode enumeration + */ + +typedef enum +{ + EXTI_Mode_Interrupt = 0x00, + EXTI_Mode_Event = 0x04 +}EXTIMode_TypeDef; + +#define IS_EXTI_MODE(MODE) (((MODE) == EXTI_Mode_Interrupt) || ((MODE) == EXTI_Mode_Event)) + +/** + * @brief EXTI Trigger enumeration + */ + +typedef enum +{ + EXTI_Trigger_Rising = 0x08, + EXTI_Trigger_Falling = 0x0C, + EXTI_Trigger_Rising_Falling = 0x10 +}EXTITrigger_TypeDef; + +#define IS_EXTI_TRIGGER(TRIGGER) (((TRIGGER) == EXTI_Trigger_Rising) || \ + ((TRIGGER) == EXTI_Trigger_Falling) || \ + ((TRIGGER) == EXTI_Trigger_Rising_Falling)) +/** + * @brief EXTI Init Structure definition + */ + +typedef struct +{ + uint32_t EXTI_Line; /*!< Specifies the EXTI lines to be enabled or disabled. + This parameter can be any combination of @ref EXTI_Lines */ + + EXTIMode_TypeDef EXTI_Mode; /*!< Specifies the mode for the EXTI lines. + This parameter can be a value of @ref EXTIMode_TypeDef */ + + EXTITrigger_TypeDef EXTI_Trigger; /*!< Specifies the trigger signal active edge for the EXTI lines. + This parameter can be a value of @ref EXTITrigger_TypeDef */ + + FunctionalState EXTI_LineCmd; /*!< Specifies the new state of the selected EXTI lines. + This parameter can be set either to ENABLE or DISABLE */ +}EXTI_InitTypeDef; + +/* Exported constants --------------------------------------------------------*/ + +/** @defgroup EXTI_Exported_Constants + * @{ + */ +/** @defgroup EXTI_Lines + * @{ + */ + +#define EXTI_Line0 ((uint32_t)0x00) /*!< External interrupt line 0 */ +#define EXTI_Line1 ((uint32_t)0x01) /*!< External interrupt line 1 */ +#define EXTI_Line2 ((uint32_t)0x02) /*!< External interrupt line 2 */ +#define EXTI_Line3 ((uint32_t)0x03) /*!< External interrupt line 3 */ +#define EXTI_Line4 ((uint32_t)0x04) /*!< External interrupt line 4 */ +#define EXTI_Line5 ((uint32_t)0x05) /*!< External interrupt line 5 */ +#define EXTI_Line6 ((uint32_t)0x06) /*!< External interrupt line 6 */ +#define EXTI_Line7 ((uint32_t)0x07) /*!< External interrupt line 7 */ +#define EXTI_Line8 ((uint32_t)0x08) /*!< External interrupt line 8 */ +#define EXTI_Line9 ((uint32_t)0x09) /*!< External interrupt line 9 */ +#define EXTI_Line10 ((uint32_t)0x0A) /*!< External interrupt line 10 */ +#define EXTI_Line11 ((uint32_t)0x0B) /*!< External interrupt line 11 */ +#define EXTI_Line12 ((uint32_t)0x0C) /*!< External interrupt line 12 */ +#define EXTI_Line13 ((uint32_t)0x0D) /*!< External interrupt line 13 */ +#define EXTI_Line14 ((uint32_t)0x0E) /*!< External interrupt line 14 */ +#define EXTI_Line15 ((uint32_t)0x0F) /*!< External interrupt line 15 */ +#define EXTI_Line16 ((uint32_t)0x10) /*!< External interrupt line 16 + Connected to the PVD Output */ +#define EXTI_Line17 ((uint32_t)0x11) /*!< Internal interrupt line 17 + Connected to the RTC Alarm + event */ +#define EXTI_Line18 ((uint32_t)0x12) /*!< Internal interrupt line 18 + Connected to the USB Device + Wakeup from suspend event */ +#define EXTI_Line19 ((uint32_t)0x13) /*!< Internal interrupt line 19 + Connected to the RTC Tamper + and Time Stamp events */ +#define EXTI_Line20 ((uint32_t)0x14) /*!< Internal interrupt line 20 + Connected to the RTC wakeup + event */ +#define EXTI_Line21 ((uint32_t)0x15) /*!< Internal interrupt line 21 + Connected to the Comparator 1 + event */ +#define EXTI_Line22 ((uint32_t)0x16) /*!< Internal interrupt line 22 + Connected to the Comparator 2 + event */ +#define EXTI_Line23 ((uint32_t)0x17) /*!< Internal interrupt line 23 + Connected to the I2C1 wakeup + event */ +#define EXTI_Line24 ((uint32_t)0x18) /*!< Internal interrupt line 24 + Connected to the I2C2 wakeup + event */ +#define EXTI_Line25 ((uint32_t)0x19) /*!< Internal interrupt line 25 + Connected to the USART1 wakeup + event */ +#define EXTI_Line26 ((uint32_t)0x1A) /*!< Internal interrupt line 26 + Connected to the USART2 wakeup + event */ +#define EXTI_Line27 ((uint32_t)0x1B) /*!< Internal interrupt line 27 + reserved */ +#define EXTI_Line28 ((uint32_t)0x1C) /*!< Internal interrupt line 28 + Connected to the USART3 wakeup + event */ +#define EXTI_Line29 ((uint32_t)0x1D) /*!< Internal interrupt line 29 + Connected to the Comparator 3 + event */ +#define EXTI_Line30 ((uint32_t)0x1E) /*!< Internal interrupt line 30 + Connected to the Comparator 4 + event */ +#define EXTI_Line31 ((uint32_t)0x1F) /*!< Internal interrupt line 31 + Connected to the Comparator 5 + event */ +#define EXTI_Line32 ((uint32_t)0x20) /*!< Internal interrupt line 32 + Connected to the Comparator 6 + event */ +#define EXTI_Line33 ((uint32_t)0x21) /*!< Internal interrupt line 33 + Connected to the Comparator 7 + event */ +#define EXTI_Line34 ((uint32_t)0x22) /*!< Internal interrupt line 34 + Connected to the USART4 wakeup + event */ +#define EXTI_Line35 ((uint32_t)0x23) /*!< Internal interrupt line 35 + Connected to the USART5 wakeup + event */ + +#define IS_EXTI_LINE_ALL(LINE) ((LINE) <= 0x23) +#define IS_EXTI_LINE_EXT(LINE) (((LINE) <= 0x16) || (((LINE) == EXTI_Line29) || ((LINE) == EXTI_Line30) || \ + ((LINE) == EXTI_Line31) || ((LINE) == EXTI_Line32) || ((LINE) == EXTI_Line33))) + +#define IS_GET_EXTI_LINE(LINE) (((LINE) == EXTI_Line0) || ((LINE) == EXTI_Line1) || \ + ((LINE) == EXTI_Line2) || ((LINE) == EXTI_Line3) || \ + ((LINE) == EXTI_Line4) || ((LINE) == EXTI_Line5) || \ + ((LINE) == EXTI_Line6) || ((LINE) == EXTI_Line7) || \ + ((LINE) == EXTI_Line8) || ((LINE) == EXTI_Line9) || \ + ((LINE) == EXTI_Line10) || ((LINE) == EXTI_Line11) || \ + ((LINE) == EXTI_Line12) || ((LINE) == EXTI_Line13) || \ + ((LINE) == EXTI_Line14) || ((LINE) == EXTI_Line15) || \ + ((LINE) == EXTI_Line16) || ((LINE) == EXTI_Line17) || \ + ((LINE) == EXTI_Line18) || ((LINE) == EXTI_Line19) || \ + ((LINE) == EXTI_Line20) || ((LINE) == EXTI_Line21) || \ + ((LINE) == EXTI_Line22) || ((LINE) == EXTI_Line29) || \ + ((LINE) == EXTI_Line30) || ((LINE) == EXTI_Line31) || \ + ((LINE) == EXTI_Line32) || ((LINE) == EXTI_Line33)) +/** + * @} + */ + +/** + * @} + */ + +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions ------------------------------------------------------- */ +/* Function used to set the EXTI configuration to the default reset state *****/ +void EXTI_DeInit(void); + +/* Initialization and Configuration functions *********************************/ +void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct); +void EXTI_StructInit(EXTI_InitTypeDef* EXTI_InitStruct); +void EXTI_GenerateSWInterrupt(uint32_t EXTI_Line); + +/* Interrupts and flags management functions **********************************/ +FlagStatus EXTI_GetFlagStatus(uint32_t EXTI_Line); +void EXTI_ClearFlag(uint32_t EXTI_Line); +ITStatus EXTI_GetITStatus(uint32_t EXTI_Line); +void EXTI_ClearITPendingBit(uint32_t EXTI_Line); + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F30x_EXTI_H */ +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_flash.h b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_flash.h new file mode 100755 index 0000000000..4d0d1d4e85 --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_flash.h @@ -0,0 +1,334 @@ +/** + ****************************************************************************** + * @file stm32f30x_flash.h + * @author MCD Application Team + * @version V1.2.3 + * @date 10-July-2015 + * @brief This file contains all the functions prototypes for the FLASH + * firmware library. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F30x_FLASH_H +#define __STM32F30x_FLASH_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f30x.h" + +/** @addtogroup STM32F30x_StdPeriph_Driver + * @{ + */ + +/** @addtogroup FLASH + * @{ + */ + +/* Exported types ------------------------------------------------------------*/ +/** + * @brief FLASH Status + */ +typedef enum +{ + FLASH_BUSY = 1, + FLASH_ERROR_WRP, + FLASH_ERROR_PROGRAM, + FLASH_COMPLETE, + FLASH_TIMEOUT +}FLASH_Status; + +/* Exported constants --------------------------------------------------------*/ + +/** @defgroup FLASH_Exported_Constants + * @{ + */ + +/** @defgroup Flash_Latency + * @{ + */ +#define FLASH_Latency_0 ((uint8_t)0x0000) /*!< FLASH Zero Latency cycle */ +#define FLASH_Latency_1 FLASH_ACR_LATENCY_0 /*!< FLASH One Latency cycle */ +#define FLASH_Latency_2 FLASH_ACR_LATENCY_1 /*!< FLASH Two Latency cycles */ + +#define IS_FLASH_LATENCY(LATENCY) (((LATENCY) == FLASH_Latency_0) || \ + ((LATENCY) == FLASH_Latency_1) || \ + ((LATENCY) == FLASH_Latency_2)) +/** + * @} + */ + +/** @defgroup FLASH_Interrupts + * @{ + */ + +#define FLASH_IT_EOP FLASH_CR_EOPIE /*!< End of programming interrupt source */ +#define FLASH_IT_ERR FLASH_CR_ERRIE /*!< Error interrupt source */ +#define IS_FLASH_IT(IT) ((((IT) & (uint32_t)0xFFFFEBFF) == 0x00000000) && (((IT) != 0x00000000))) +/** + * @} + */ +/** @defgroup FLASH_Address + * @{ + */ + +#define IS_FLASH_PROGRAM_ADDRESS(ADDRESS) (((ADDRESS) >= 0x08000000) && ((ADDRESS) <= 0x0803FFFF)) + +/** + * @} + */ + +/** @defgroup FLASH_OB_DATA_ADDRESS + * @{ + */ +#define IS_OB_DATA_ADDRESS(ADDRESS) (((ADDRESS) == 0x1FFFF804) || ((ADDRESS) == 0x1FFFF806)) + +/** + * @} + */ + +/** @defgroup Option_Bytes_Write_Protection + * @{ + */ + +#define OB_WRP_Pages0to1 ((uint32_t)0x00000001) /* Write protection of page 0 to 1 */ +#define OB_WRP_Pages2to3 ((uint32_t)0x00000002) /* Write protection of page 2 to 3 */ +#define OB_WRP_Pages4to5 ((uint32_t)0x00000004) /* Write protection of page 4 to 5 */ +#define OB_WRP_Pages6to7 ((uint32_t)0x00000008) /* Write protection of page 6 to 7 */ +#define OB_WRP_Pages8to9 ((uint32_t)0x00000010) /* Write protection of page 8 to 9 */ +#define OB_WRP_Pages10to11 ((uint32_t)0x00000020) /* Write protection of page 10 to 11 */ +#define OB_WRP_Pages12to13 ((uint32_t)0x00000040) /* Write protection of page 12 to 13 */ +#define OB_WRP_Pages14to15 ((uint32_t)0x00000080) /* Write protection of page 14 to 15 */ +#define OB_WRP_Pages16to17 ((uint32_t)0x00000100) /* Write protection of page 16 to 17 */ +#define OB_WRP_Pages18to19 ((uint32_t)0x00000200) /* Write protection of page 18 to 19 */ +#define OB_WRP_Pages20to21 ((uint32_t)0x00000400) /* Write protection of page 20 to 21 */ +#define OB_WRP_Pages22to23 ((uint32_t)0x00000800) /* Write protection of page 22 to 23 */ +#define OB_WRP_Pages24to25 ((uint32_t)0x00001000) /* Write protection of page 24 to 25 */ +#define OB_WRP_Pages26to27 ((uint32_t)0x00002000) /* Write protection of page 26 to 27 */ +#define OB_WRP_Pages28to29 ((uint32_t)0x00004000) /* Write protection of page 28 to 29 */ +#define OB_WRP_Pages30to31 ((uint32_t)0x00008000) /* Write protection of page 30 to 31 */ +#define OB_WRP_Pages32to33 ((uint32_t)0x00010000) /* Write protection of page 32 to 33 */ +#define OB_WRP_Pages34to35 ((uint32_t)0x00020000) /* Write protection of page 34 to 35 */ +#define OB_WRP_Pages36to37 ((uint32_t)0x00040000) /* Write protection of page 36 to 37 */ +#define OB_WRP_Pages38to39 ((uint32_t)0x00080000) /* Write protection of page 38 to 39 */ +#define OB_WRP_Pages40to41 ((uint32_t)0x00100000) /* Write protection of page 40 to 41 */ +#define OB_WRP_Pages42to43 ((uint32_t)0x00200000) /* Write protection of page 42 to 43 */ +#define OB_WRP_Pages44to45 ((uint32_t)0x00400000) /* Write protection of page 44 to 45 */ +#define OB_WRP_Pages46to47 ((uint32_t)0x00800000) /* Write protection of page 46 to 47 */ +#define OB_WRP_Pages48to49 ((uint32_t)0x01000000) /* Write protection of page 48 to 49 */ +#define OB_WRP_Pages50to51 ((uint32_t)0x02000000) /* Write protection of page 50 to 51 */ +#define OB_WRP_Pages52to53 ((uint32_t)0x04000000) /* Write protection of page 52 to 53 */ +#define OB_WRP_Pages54to55 ((uint32_t)0x08000000) /* Write protection of page 54 to 55 */ +#define OB_WRP_Pages56to57 ((uint32_t)0x10000000) /* Write protection of page 56 to 57 */ +#define OB_WRP_Pages58to59 ((uint32_t)0x20000000) /* Write protection of page 58 to 59 */ +#define OB_WRP_Pages60to61 ((uint32_t)0x40000000) /* Write protection of page 60 to 61 */ + +#ifdef STM32F303xE +#define OB_WRP_Pages62to263 ((uint32_t)0x80000000) /* Write protection of page 62 to 263 */ +#else +#define OB_WRP_Pages62to127 ((uint32_t)0x80000000) /* Write protection of page 62 to 127 */ +#endif /* STM32F303xE */ + +#define OB_WRP_AllPages ((uint32_t)0xFFFFFFFF) /*!< Write protection of all Sectors */ + +#define IS_OB_WRP(PAGE) (((PAGE) != 0x0000000)) + +/** + * @} + */ + +/** @defgroup Option_Bytes_Read_Protection + * @{ + */ + +/** + * @brief Read Protection Level + */ +#define OB_RDP_Level_0 ((uint8_t)0xAA) +#define OB_RDP_Level_1 ((uint8_t)0xBB) +/*#define OB_RDP_Level_2 ((uint8_t)0xCC)*/ /* Warning: When enabling read protection level 2 + it's no more possible to go back to level 1 or 0 */ + +#define IS_OB_RDP(LEVEL) (((LEVEL) == OB_RDP_Level_0)||\ + ((LEVEL) == OB_RDP_Level_1))/*||\ + ((LEVEL) == OB_RDP_Level_2))*/ +/** + * @} + */ + +/** @defgroup Option_Bytes_IWatchdog + * @{ + */ + +#define OB_IWDG_SW ((uint8_t)0x01) /*!< Software IWDG selected */ +#define OB_IWDG_HW ((uint8_t)0x00) /*!< Hardware IWDG selected */ +#define IS_OB_IWDG_SOURCE(SOURCE) (((SOURCE) == OB_IWDG_SW) || ((SOURCE) == OB_IWDG_HW)) + +/** + * @} + */ + +/** @defgroup Option_Bytes_nRST_STOP + * @{ + */ + +#define OB_STOP_NoRST ((uint8_t)0x02) /*!< No reset generated when entering in STOP */ +#define OB_STOP_RST ((uint8_t)0x00) /*!< Reset generated when entering in STOP */ +#define IS_OB_STOP_SOURCE(SOURCE) (((SOURCE) == OB_STOP_NoRST) || ((SOURCE) == OB_STOP_RST)) + +/** + * @} + */ + +/** @defgroup Option_Bytes_nRST_STDBY + * @{ + */ + +#define OB_STDBY_NoRST ((uint8_t)0x04) /*!< No reset generated when entering in STANDBY */ +#define OB_STDBY_RST ((uint8_t)0x00) /*!< Reset generated when entering in STANDBY */ +#define IS_OB_STDBY_SOURCE(SOURCE) (((SOURCE) == OB_STDBY_NoRST) || ((SOURCE) == OB_STDBY_RST)) + +/** + * @} + */ +/** @defgroup Option_Bytes_BOOT1 + * @{ + */ + +#define OB_BOOT1_RESET ((uint8_t)0x00) /*!< BOOT1 Reset */ +#define OB_BOOT1_SET ((uint8_t)0x10) /*!< BOOT1 Set */ +#define IS_OB_BOOT1(BOOT1) (((BOOT1) == OB_BOOT1_RESET) || ((BOOT1) == OB_BOOT1_SET)) + +/** + * @} + */ +/** @defgroup Option_Bytes_VDDA_Analog_Monitoring + * @{ + */ + +#define OB_VDDA_ANALOG_ON ((uint8_t)0x20) /*!< Analog monitoring on VDDA Power source ON */ +#define OB_VDDA_ANALOG_OFF ((uint8_t)0x00) /*!< Analog monitoring on VDDA Power source OFF */ + +#define IS_OB_VDDA_ANALOG(ANALOG) (((ANALOG) == OB_VDDA_ANALOG_ON) || ((ANALOG) == OB_VDDA_ANALOG_OFF)) + +/** + * @} + */ + +/** @defgroup FLASH_Option_Bytes_SRAM_Parity_Enable + * @{ + */ + +#define OB_SRAM_PARITY_SET ((uint8_t)0x00) /*!< SRAM parity enable Set */ +#define OB_SRAM_PARITY_RESET ((uint8_t)0x40) /*!< SRAM parity enable reset */ + +#define IS_OB_SRAM_PARITY(PARITY) (((PARITY) == OB_SRAM_PARITY_SET) || ((PARITY) == OB_SRAM_PARITY_RESET)) + +/** + * @} + */ + +/** @defgroup FLASH_Flags + * @{ + */ + +#define FLASH_FLAG_BSY FLASH_SR_BSY /*!< FLASH Busy flag */ +#define FLASH_FLAG_PGERR FLASH_SR_PGERR /*!< FLASH Programming error flag */ +#define FLASH_FLAG_WRPERR FLASH_SR_WRPERR /*!< FLASH Write protected error flag */ +#define FLASH_FLAG_EOP FLASH_SR_EOP /*!< FLASH End of Programming flag */ + +#define IS_FLASH_CLEAR_FLAG(FLAG) ((((FLAG) & (uint32_t)0xFFFFFFCB) == 0x00000000) && ((FLAG) != 0x00000000)) + +#define IS_FLASH_GET_FLAG(FLAG) (((FLAG) == FLASH_FLAG_BSY) || ((FLAG) == FLASH_FLAG_PGERR) || \ + ((FLAG) == FLASH_FLAG_WRPERR) || ((FLAG) == FLASH_FLAG_EOP)) +/** + * @} + */ +/** @defgroup Timeout_definition + * @{ + */ +#define FLASH_ER_PRG_TIMEOUT ((uint32_t)0x000B0000) + +/** + * @} + */ + +/** + * @} + */ + +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions --------------------------------------------------------*/ + +/* FLASH Interface configuration functions ************************************/ +void FLASH_SetLatency(uint32_t FLASH_Latency); +void FLASH_HalfCycleAccessCmd(FunctionalState NewState); +void FLASH_PrefetchBufferCmd(FunctionalState NewState); + +/* FLASH Memory Programming functions *****************************************/ +void FLASH_Unlock(void); +void FLASH_Lock(void); +FLASH_Status FLASH_ErasePage(uint32_t Page_Address); +FLASH_Status FLASH_EraseAllPages(void); +FLASH_Status FLASH_ProgramWord(uint32_t Address, uint32_t Data); +FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data); + +/* Option Bytes Programming functions *****************************************/ +void FLASH_OB_Unlock(void); +void FLASH_OB_Lock(void); +void FLASH_OB_Launch(void); +FLASH_Status FLASH_OB_Erase(void); +FLASH_Status FLASH_OB_EnableWRP(uint32_t OB_WRP); +FLASH_Status FLASH_OB_RDPConfig(uint8_t OB_RDP); +FLASH_Status FLASH_OB_UserConfig(uint8_t OB_IWDG, uint8_t OB_STOP, uint8_t OB_STDBY); +FLASH_Status FLASH_OB_BOOTConfig(uint8_t OB_BOOT1); +FLASH_Status FLASH_OB_VDDAConfig(uint8_t OB_VDDA_ANALOG); +FLASH_Status FLASH_OB_SRAMParityConfig(uint8_t OB_SRAM_Parity); +FLASH_Status FLASH_OB_WriteUser(uint8_t OB_USER); +FLASH_Status FLASH_ProgramOptionByteData(uint32_t Address, uint8_t Data); +uint8_t FLASH_OB_GetUser(void); +uint32_t FLASH_OB_GetWRP(void); +FlagStatus FLASH_OB_GetRDP(void); + +/* Interrupts and flags management functions **********************************/ +void FLASH_ITConfig(uint32_t FLASH_IT, FunctionalState NewState); +FlagStatus FLASH_GetFlagStatus(uint32_t FLASH_FLAG); +void FLASH_ClearFlag(uint32_t FLASH_FLAG); +FLASH_Status FLASH_GetStatus(void); +FLASH_Status FLASH_WaitForLastOperation(uint32_t Timeout); + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F30x_FLASH_H */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_fmc.h b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_fmc.h new file mode 100755 index 0000000000..eb8c434e8f --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_fmc.h @@ -0,0 +1,722 @@ +/** + ****************************************************************************** + * @file stm32f30x_fmc.h + * @author MCD Application Team + * @version V1.2.3 + * @date 10-July-2015 + * @brief This file contains all the functions prototypes for the FMC firmware + * library. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F30x_FMC_H +#define __STM32F30x_FMC_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f30x.h" + +/** @addtogroup STM32F30x_StdPeriph_Driver + * @{ + */ + +/** @addtogroup FMC + * @{ + */ + +/* Exported types ------------------------------------------------------------*/ + +/** + * @brief Timing parameters For NOR/SRAM Banks + */ +typedef struct +{ + uint32_t FMC_AddressSetupTime; /*!< Defines the number of HCLK cycles to configure + the duration of the address setup time. + This parameter can be a value between 0 and 15. + @note This parameter is not used with synchronous NOR Flash memories. */ + + uint32_t FMC_AddressHoldTime; /*!< Defines the number of HCLK cycles to configure + the duration of the address hold time. + This parameter can be a value between 1 and 15. + @note This parameter is not used with synchronous NOR Flash memories.*/ + + uint32_t FMC_DataSetupTime; /*!< Defines the number of HCLK cycles to configure + the duration of the data setup time. + This parameter can be a value between 1 and 255. + @note This parameter is used for SRAMs, ROMs and asynchronous multiplexed NOR Flash memories. */ + + uint32_t FMC_BusTurnAroundDuration; /*!< Defines the number of HCLK cycles to configure + the duration of the bus turnaround. + This parameter can be a value between 0 and 15. + @note This parameter is only used for multiplexed NOR Flash memories. */ + + uint32_t FMC_CLKDivision; /*!< Defines the period of CLK clock output signal, expressed in number of HCLK cycles. + This parameter can be a value between 2 and 16. + @note This parameter is not used for asynchronous NOR Flash, SRAM or ROM accesses. */ + + uint32_t FMC_DataLatency; /*!< Defines the number of memory clock cycles to issue + to the memory before getting the first data. + The parameter value depends on the memory type as shown below: + - It must be set to 0 in case of a CRAM + - It is don't care in asynchronous NOR, SRAM or ROM accesses + - It may assume a value between 2 and 17 in NOR Flash memories + with synchronous burst mode enable */ + + uint32_t FMC_AccessMode; /*!< Specifies the asynchronous access mode. + This parameter can be a value of @ref FMC_Access_Mode */ +}FMC_NORSRAMTimingInitTypeDef; + +/** + * @brief FMC NOR/SRAM Init structure definition + */ +typedef struct +{ + uint32_t FMC_Bank; /*!< Specifies the NOR/SRAM memory bank that will be used. + This parameter can be a value of @ref FMC_NORSRAM_Bank */ + + uint32_t FMC_DataAddressMux; /*!< Specifies whether the address and data values are + multiplexed on the databus or not. + This parameter can be a value of @ref FMC_Data_Address_Bus_Multiplexing */ + + uint32_t FMC_MemoryType; /*!< Specifies the type of external memory attached to + the corresponding memory bank. + This parameter can be a value of @ref FMC_Memory_Type */ + + uint32_t FMC_MemoryDataWidth; /*!< Specifies the external memory device width. + This parameter can be a value of @ref FMC_NORSRAM_Data_Width */ + + uint32_t FMC_BurstAccessMode; /*!< Enables or disables the burst access mode for Flash memory, + valid only with synchronous burst Flash memories. + This parameter can be a value of @ref FMC_Burst_Access_Mode */ + + uint32_t FMC_WaitSignalPolarity; /*!< Specifies the wait signal polarity, valid only when accessing + the Flash memory in burst mode. + This parameter can be a value of @ref FMC_Wait_Signal_Polarity */ + + uint32_t FMC_WrapMode; /*!< Enables or disables the Wrapped burst access mode for Flash + memory, valid only when accessing Flash memories in burst mode. + This parameter can be a value of @ref FMC_Wrap_Mode */ + + uint32_t FMC_WaitSignalActive; /*!< Specifies if the wait signal is asserted by the memory one + clock cycle before the wait state or during the wait state, + valid only when accessing memories in burst mode. + This parameter can be a value of @ref FMC_Wait_Timing */ + + uint32_t FMC_WriteOperation; /*!< Enables or disables the write operation in the selected bank by the FMC. + This parameter can be a value of @ref FMC_Write_Operation */ + + uint32_t FMC_WaitSignal; /*!< Enables or disables the wait state insertion via wait + signal, valid for Flash memory access in burst mode. + This parameter can be a value of @ref FMC_Wait_Signal */ + + uint32_t FMC_ExtendedMode; /*!< Enables or disables the extended mode. + This parameter can be a value of @ref FMC_Extended_Mode */ + + uint32_t FMC_AsynchronousWait; /*!< Enables or disables wait signal during asynchronous transfers, + valid only with asynchronous Flash memories. + This parameter can be a value of @ref FMC_AsynchronousWait */ + + uint32_t FMC_WriteBurst; /*!< Enables or disables the write burst operation. + This parameter can be a value of @ref FMC_Write_Burst */ + + + FMC_NORSRAMTimingInitTypeDef* FMC_ReadWriteTimingStruct; /*!< Timing Parameters for write and read access if the Extended Mode is not used*/ + + FMC_NORSRAMTimingInitTypeDef* FMC_WriteTimingStruct; /*!< Timing Parameters for write access if the Extended Mode is used*/ +}FMC_NORSRAMInitTypeDef; + +/** + * @brief Timing parameters For FMC NAND and PCCARD Banks + */ +typedef struct +{ + uint32_t FMC_SetupTime; /*!< Defines the number of HCLK cycles to setup address before + the command assertion for NAND-Flash read or write access + to common/Attribute or I/O memory space (depending on + the memory space timing to be configured). + This parameter can be a value between 0 and 255.*/ + + uint32_t FMC_WaitSetupTime; /*!< Defines the minimum number of HCLK cycles to assert the + command for NAND-Flash read or write access to + common/Attribute or I/O memory space (depending on the + memory space timing to be configured). + This parameter can be a number between 0 and 255 */ + + uint32_t FMC_HoldSetupTime; /*!< Defines the number of HCLK clock cycles to hold address + (and data for write access) after the command de-assertion + for NAND-Flash read or write access to common/Attribute + or I/O memory space (depending on the memory space timing + to be configured). + This parameter can be a number between 0 and 255 */ + + uint32_t FMC_HiZSetupTime; /*!< Defines the number of HCLK clock cycles during which the + databus is kept in HiZ after the start of a NAND-Flash + write access to common/Attribute or I/O memory space (depending + on the memory space timing to be configured). + This parameter can be a number between 0 and 255 */ +}FMC_NAND_PCCARDTimingInitTypeDef; + +/** + * @brief FMC NAND Init structure definition + */ +typedef struct +{ + uint32_t FMC_Bank; /*!< Specifies the NAND memory bank that will be used. + This parameter can be a value of @ref FMC_NAND_Bank */ + + uint32_t FMC_Waitfeature; /*!< Enables or disables the Wait feature for the NAND Memory Bank. + This parameter can be any value of @ref FMC_Wait_feature */ + + uint32_t FMC_MemoryDataWidth; /*!< Specifies the external memory device width. + This parameter can be any value of @ref FMC_NAND_Data_Width */ + + uint32_t FMC_ECC; /*!< Enables or disables the ECC computation. + This parameter can be any value of @ref FMC_ECC */ + + uint32_t FMC_ECCPageSize; /*!< Defines the page size for the extended ECC. + This parameter can be any value of @ref FMC_ECC_Page_Size */ + + uint32_t FMC_TCLRSetupTime; /*!< Defines the number of HCLK cycles to configure the + delay between CLE low and RE low. + This parameter can be a value between 0 and 255. */ + + uint32_t FMC_TARSetupTime; /*!< Defines the number of HCLK cycles to configure the + delay between ALE low and RE low. + This parameter can be a number between 0 and 255 */ + + FMC_NAND_PCCARDTimingInitTypeDef* FMC_CommonSpaceTimingStruct; /*!< FMC Common Space Timing */ + + FMC_NAND_PCCARDTimingInitTypeDef* FMC_AttributeSpaceTimingStruct; /*!< FMC Attribute Space Timing */ +}FMC_NANDInitTypeDef; + +/** + * @brief FMC PCCARD Init structure definition + */ + +typedef struct +{ + uint32_t FMC_Waitfeature; /*!< Enables or disables the Wait feature for the Memory Bank. + This parameter can be any value of @ref FMC_Wait_feature */ + + uint32_t FMC_TCLRSetupTime; /*!< Defines the number of HCLK cycles to configure the + delay between CLE low and RE low. + This parameter can be a value between 0 and 255. */ + + uint32_t FMC_TARSetupTime; /*!< Defines the number of HCLK cycles to configure the + delay between ALE low and RE low. + This parameter can be a number between 0 and 255 */ + + + FMC_NAND_PCCARDTimingInitTypeDef* FMC_CommonSpaceTimingStruct; /*!< FMC Common Space Timing */ + + FMC_NAND_PCCARDTimingInitTypeDef* FMC_AttributeSpaceTimingStruct; /*!< FMC Attribute Space Timing */ + + FMC_NAND_PCCARDTimingInitTypeDef* FMC_IOSpaceTimingStruct; /*!< FMC IO Space Timing */ +}FMC_PCCARDInitTypeDef; + + +/* Exported constants --------------------------------------------------------*/ + +/** @defgroup FMC_Exported_Constants + * @{ + */ + +/** @defgroup FMC_NORSRAM_Bank + * @{ + */ +#define FMC_Bank1_NORSRAM1 ((uint32_t)0x00000000) +#define FMC_Bank1_NORSRAM2 ((uint32_t)0x00000002) +#define FMC_Bank1_NORSRAM3 ((uint32_t)0x00000004) +#define FMC_Bank1_NORSRAM4 ((uint32_t)0x00000006) + +#define IS_FMC_NORSRAM_BANK(BANK) (((BANK) == FMC_Bank1_NORSRAM1) || \ + ((BANK) == FMC_Bank1_NORSRAM2) || \ + ((BANK) == FMC_Bank1_NORSRAM3) || \ + ((BANK) == FMC_Bank1_NORSRAM4)) +/** + * @} + */ + +/** @defgroup FMC_NAND_Bank + * @{ + */ +#define FMC_Bank2_NAND ((uint32_t)0x00000010) +#define FMC_Bank3_NAND ((uint32_t)0x00000100) + +#define IS_FMC_NAND_BANK(BANK) (((BANK) == FMC_Bank2_NAND) || \ + ((BANK) == FMC_Bank3_NAND)) +/** + * @} + */ + +/** @defgroup FMC_PCCARD_Bank + * @{ + */ +#define FMC_Bank4_PCCARD ((uint32_t)0x00001000) +/** + * @} + */ + + +/** @defgroup FMC_NOR_SRAM_Controller + * @{ + */ + +/** @defgroup FMC_Data_Address_Bus_Multiplexing + * @{ + */ + +#define FMC_DataAddressMux_Disable ((uint32_t)0x00000000) +#define FMC_DataAddressMux_Enable ((uint32_t)0x00000002) + +#define IS_FMC_MUX(MUX) (((MUX) == FMC_DataAddressMux_Disable) || \ + ((MUX) == FMC_DataAddressMux_Enable)) +/** + * @} + */ + +/** @defgroup FMC_Memory_Type + * @{ + */ + +#define FMC_MemoryType_SRAM ((uint32_t)0x00000000) +#define FMC_MemoryType_PSRAM ((uint32_t)0x00000004) +#define FMC_MemoryType_NOR ((uint32_t)0x00000008) + +#define IS_FMC_MEMORY(MEMORY) (((MEMORY) == FMC_MemoryType_SRAM) || \ + ((MEMORY) == FMC_MemoryType_PSRAM)|| \ + ((MEMORY) == FMC_MemoryType_NOR)) +/** + * @} + */ + +/** @defgroup FMC_NORSRAM_Data_Width + * @{ + */ + +#define FMC_NORSRAM_MemoryDataWidth_8b ((uint32_t)0x00000000) +#define FMC_NORSRAM_MemoryDataWidth_16b ((uint32_t)0x00000010) + +#define IS_FMC_NORSRAM_MEMORY_WIDTH(WIDTH) (((WIDTH) == FMC_NORSRAM_MemoryDataWidth_8b) || \ + ((WIDTH) == FMC_NORSRAM_MemoryDataWidth_16b)) +/** + * @} + */ + +/** @defgroup FMC_Burst_Access_Mode + * @{ + */ + +#define FMC_BurstAccessMode_Disable ((uint32_t)0x00000000) +#define FMC_BurstAccessMode_Enable ((uint32_t)0x00000100) + +#define IS_FMC_BURSTMODE(STATE) (((STATE) == FMC_BurstAccessMode_Disable) || \ + ((STATE) == FMC_BurstAccessMode_Enable)) +/** + * @} + */ + +/** @defgroup FMC_AsynchronousWait + * @{ + */ +#define FMC_AsynchronousWait_Disable ((uint32_t)0x00000000) +#define FMC_AsynchronousWait_Enable ((uint32_t)0x00008000) + +#define IS_FMC_ASYNWAIT(STATE) (((STATE) == FMC_AsynchronousWait_Disable) || \ + ((STATE) == FMC_AsynchronousWait_Enable)) +/** + * @} + */ + +/** @defgroup FMC_Wait_Signal_Polarity + * @{ + */ +#define FMC_WaitSignalPolarity_Low ((uint32_t)0x00000000) +#define FMC_WaitSignalPolarity_High ((uint32_t)0x00000200) + +#define IS_FMC_WAIT_POLARITY(POLARITY) (((POLARITY) == FMC_WaitSignalPolarity_Low) || \ + ((POLARITY) == FMC_WaitSignalPolarity_High)) +/** + * @} + */ + +/** @defgroup FMC_Wrap_Mode + * @{ + */ +#define FMC_WrapMode_Disable ((uint32_t)0x00000000) +#define FMC_WrapMode_Enable ((uint32_t)0x00000400) + +#define IS_FMC_WRAP_MODE(MODE) (((MODE) == FMC_WrapMode_Disable) || \ + ((MODE) == FMC_WrapMode_Enable)) +/** + * @} + */ + +/** @defgroup FMC_Wait_Timing + * @{ + */ +#define FMC_WaitSignalActive_BeforeWaitState ((uint32_t)0x00000000) +#define FMC_WaitSignalActive_DuringWaitState ((uint32_t)0x00000800) + +#define IS_FMC_WAIT_SIGNAL_ACTIVE(ACTIVE) (((ACTIVE) == FMC_WaitSignalActive_BeforeWaitState) || \ + ((ACTIVE) == FMC_WaitSignalActive_DuringWaitState)) +/** + * @} + */ + +/** @defgroup FMC_Write_Operation + * @{ + */ +#define FMC_WriteOperation_Disable ((uint32_t)0x00000000) +#define FMC_WriteOperation_Enable ((uint32_t)0x00001000) + +#define IS_FMC_WRITE_OPERATION(OPERATION) (((OPERATION) == FMC_WriteOperation_Disable) || \ + ((OPERATION) == FMC_WriteOperation_Enable)) +/** + * @} + */ + +/** @defgroup FMC_Wait_Signal + * @{ + */ +#define FMC_WaitSignal_Disable ((uint32_t)0x00000000) +#define FMC_WaitSignal_Enable ((uint32_t)0x00002000) + +#define IS_FMC_WAITE_SIGNAL(SIGNAL) (((SIGNAL) == FMC_WaitSignal_Disable) || \ + ((SIGNAL) == FMC_WaitSignal_Enable)) +/** + * @} + */ + +/** @defgroup FMC_Extended_Mode + * @{ + */ +#define FMC_ExtendedMode_Disable ((uint32_t)0x00000000) +#define FMC_ExtendedMode_Enable ((uint32_t)0x00004000) + +#define IS_FMC_EXTENDED_MODE(MODE) (((MODE) == FMC_ExtendedMode_Disable) || \ + ((MODE) == FMC_ExtendedMode_Enable)) +/** + * @} + */ + +/** @defgroup FMC_Write_Burst + * @{ + */ + +#define FMC_WriteBurst_Disable ((uint32_t)0x00000000) +#define FMC_WriteBurst_Enable ((uint32_t)0x00080000) + +#define IS_FMC_WRITE_BURST(BURST) (((BURST) == FMC_WriteBurst_Disable) || \ + ((BURST) == FMC_WriteBurst_Enable)) +/** + * @} + */ + +/** @defgroup FMC_Continous_Clock + * @{ + */ + +#define FMC_CClock_SyncOnly ((uint32_t)0x00000000) +#define FMC_CClock_SyncAsync ((uint32_t)0x00100000) + +#define IS_FMC_CONTINOUS_CLOCK(CCLOCK) (((CCLOCK) == FMC_CClock_SyncOnly) || \ + ((CCLOCK) == FMC_CClock_SyncAsync)) +/** + * @} + */ + +/** @defgroup FMC_Address_Setup_Time + * @{ + */ +#define IS_FMC_ADDRESS_SETUP_TIME(TIME) ((TIME) <= 15) +/** + * @} + */ + +/** @defgroup FMC_Address_Hold_Time + * @{ + */ +#define IS_FMC_ADDRESS_HOLD_TIME(TIME) (((TIME) > 0) && ((TIME) <= 15)) +/** + * @} + */ + +/** @defgroup FMC_Data_Setup_Time + * @{ + */ +#define IS_FMC_DATASETUP_TIME(TIME) (((TIME) > 0) && ((TIME) <= 255)) +/** + * @} + */ + +/** @defgroup FMC_Bus_Turn_around_Duration + * @{ + */ +#define IS_FMC_TURNAROUND_TIME(TIME) ((TIME) <= 15) +/** + * @} + */ + +/** @defgroup FMC_CLK_Division + * @{ + */ +#define IS_FMC_CLK_DIV(DIV) (((DIV) > 1) && ((DIV) <= 16)) +/** + * @} + */ + +/** @defgroup FMC_Data_Latency + * @{ + */ +#define IS_FMC_DATA_LATENCY(LATENCY) (((LATENCY) > 1) && ((LATENCY) <= 17)) +/** + * @} + */ + +/** @defgroup FMC_Access_Mode + * @{ + */ +#define FMC_AccessMode_A ((uint32_t)0x00000000) +#define FMC_AccessMode_B ((uint32_t)0x10000000) +#define FMC_AccessMode_C ((uint32_t)0x20000000) +#define FMC_AccessMode_D ((uint32_t)0x30000000) + +#define IS_FMC_ACCESS_MODE(MODE) (((MODE) == FMC_AccessMode_A) || \ + ((MODE) == FMC_AccessMode_B) || \ + ((MODE) == FMC_AccessMode_C) || \ + ((MODE) == FMC_AccessMode_D)) +/** + * @} + */ + +/** + * @} + */ + +/** @defgroup FMC_NAND_PCCARD_Controller + * @{ + */ + +/** @defgroup FMC_Wait_feature + * @{ + */ +#define FMC_Waitfeature_Disable ((uint32_t)0x00000000) +#define FMC_Waitfeature_Enable ((uint32_t)0x00000002) + +#define IS_FMC_WAIT_FEATURE(FEATURE) (((FEATURE) == FMC_Waitfeature_Disable) || \ + ((FEATURE) == FMC_Waitfeature_Enable)) +/** + * @} + */ + +/** @defgroup FMC_NAND_Data_Width + * @{ + */ +#define FMC_NAND_MemoryDataWidth_8b ((uint32_t)0x00000000) +#define FMC_NAND_MemoryDataWidth_16b ((uint32_t)0x00000010) + +#define IS_FMC_NAND_MEMORY_WIDTH(WIDTH) (((WIDTH) == FMC_NAND_MemoryDataWidth_8b) || \ + ((WIDTH) == FMC_NAND_MemoryDataWidth_16b)) +/** + * @} + */ + +/** @defgroup FMC_ECC + * @{ + */ +#define FMC_ECC_Disable ((uint32_t)0x00000000) +#define FMC_ECC_Enable ((uint32_t)0x00000040) + +#define IS_FMC_ECC_STATE(STATE) (((STATE) == FMC_ECC_Disable) || \ + ((STATE) == FMC_ECC_Enable)) +/** + * @} + */ + +/** @defgroup FMC_ECC_Page_Size + * @{ + */ +#define FMC_ECCPageSize_256Bytes ((uint32_t)0x00000000) +#define FMC_ECCPageSize_512Bytes ((uint32_t)0x00020000) +#define FMC_ECCPageSize_1024Bytes ((uint32_t)0x00040000) +#define FMC_ECCPageSize_2048Bytes ((uint32_t)0x00060000) +#define FMC_ECCPageSize_4096Bytes ((uint32_t)0x00080000) +#define FMC_ECCPageSize_8192Bytes ((uint32_t)0x000A0000) + +#define IS_FMC_ECCPAGE_SIZE(SIZE) (((SIZE) == FMC_ECCPageSize_256Bytes) || \ + ((SIZE) == FMC_ECCPageSize_512Bytes) || \ + ((SIZE) == FMC_ECCPageSize_1024Bytes) || \ + ((SIZE) == FMC_ECCPageSize_2048Bytes) || \ + ((SIZE) == FMC_ECCPageSize_4096Bytes) || \ + ((SIZE) == FMC_ECCPageSize_8192Bytes)) +/** + * @} + */ + +/** @defgroup FMC_TCLR_Setup_Time + * @{ + */ +#define IS_FMC_TCLR_TIME(TIME) ((TIME) <= 255) +/** + * @} + */ + +/** @defgroup FMC_TAR_Setup_Time + * @{ + */ +#define IS_FMC_TAR_TIME(TIME) ((TIME) <= 255) +/** + * @} + */ + +/** @defgroup FMC_Setup_Time + * @{ + */ +#define IS_FMC_SETUP_TIME(TIME) ((TIME) <= 255) +/** + * @} + */ + +/** @defgroup FMC_Wait_Setup_Time + * @{ + */ +#define IS_FMC_WAIT_TIME(TIME) ((TIME) <= 255) +/** + * @} + */ + +/** @defgroup FMC_Hold_Setup_Time + * @{ + */ +#define IS_FMC_HOLD_TIME(TIME) ((TIME) <= 255) +/** + * @} + */ + +/** @defgroup FMC_HiZ_Setup_Time + * @{ + */ +#define IS_FMC_HIZ_TIME(TIME) ((TIME) <= 255) +/** + * @} + */ + +/** + * @} + */ + +/** @defgroup FMC_Interrupt_sources + * @{ + */ +#define FMC_IT_RisingEdge ((uint32_t)0x00000008) +#define FMC_IT_Level ((uint32_t)0x00000010) +#define FMC_IT_FallingEdge ((uint32_t)0x00000020) + +#define IS_FMC_IT(IT) ((((IT) & (uint32_t)0xFFFFBFC7) == 0x00000000) && ((IT) != 0x00000000)) +#define IS_FMC_GET_IT(IT) (((IT) == FMC_IT_RisingEdge) || \ + ((IT) == FMC_IT_Level) || \ + ((IT) == FMC_IT_FallingEdge)) + +#define IS_FMC_IT_BANK(BANK) (((BANK) == FMC_Bank2_NAND) || \ + ((BANK) == FMC_Bank3_NAND) || \ + ((BANK) == FMC_Bank4_PCCARD)) +/** + * @} + */ + +/** @defgroup FMC_Flags + * @{ + */ +#define FMC_FLAG_RisingEdge ((uint32_t)0x00000001) +#define FMC_FLAG_Level ((uint32_t)0x00000002) +#define FMC_FLAG_FallingEdge ((uint32_t)0x00000004) +#define FMC_FLAG_FEMPT ((uint32_t)0x00000040) + +#define IS_FMC_GET_FLAG(FLAG) (((FLAG) == FMC_FLAG_RisingEdge) || \ + ((FLAG) == FMC_FLAG_Level) || \ + ((FLAG) == FMC_FLAG_FallingEdge) || \ + ((FLAG) == FMC_FLAG_FEMPT)) + +#define IS_FMC_GETFLAG_BANK(BANK) (((BANK) == FMC_Bank2_NAND) || \ + ((BANK) == FMC_Bank3_NAND) || \ + ((BANK) == FMC_Bank4_PCCARD)) + +#define IS_FMC_CLEAR_FLAG(FLAG) ((((FLAG) & (uint32_t)0xFFFFFFF8) == 0x00000000) && ((FLAG) != 0x00000000)) + + +/** + * @} + */ + +/** + * @} + */ + + +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions --------------------------------------------------------*/ + +/* NOR/SRAM Controller functions **********************************************/ +void FMC_NORSRAMDeInit(uint32_t FMC_Bank); +void FMC_NORSRAMInit(FMC_NORSRAMInitTypeDef* FMC_NORSRAMInitStruct); +void FMC_NORSRAMStructInit(FMC_NORSRAMInitTypeDef* FMC_NORSRAMInitStruct); +void FMC_NORSRAMCmd(uint32_t FMC_Bank, FunctionalState NewState); + +/* NAND Controller functions **************************************************/ +void FMC_NANDDeInit(uint32_t FMC_Bank); +void FMC_NANDInit(FMC_NANDInitTypeDef* FMC_NANDInitStruct); +void FMC_NANDStructInit(FMC_NANDInitTypeDef* FMC_NANDInitStruct); +void FMC_NANDCmd(uint32_t FMC_Bank, FunctionalState NewState); +void FMC_NANDECCCmd(uint32_t FMC_Bank, FunctionalState NewState); +uint32_t FMC_GetECC(uint32_t FMC_Bank); + +/* PCCARD Controller functions ************************************************/ +void FMC_PCCARDDeInit(void); +void FMC_PCCARDInit(FMC_PCCARDInitTypeDef* FMC_PCCARDInitStruct); +void FMC_PCCARDStructInit(FMC_PCCARDInitTypeDef* FMC_PCCARDInitStruct); +void FMC_PCCARDCmd(FunctionalState NewState); + +/* Interrupts and flags management functions **********************************/ +void FMC_ITConfig(uint32_t FMC_Bank, uint32_t FMC_IT, FunctionalState NewState); +FlagStatus FMC_GetFlagStatus(uint32_t FMC_Bank, uint32_t FMC_FLAG); +void FMC_ClearFlag(uint32_t FMC_Bank, uint32_t FMC_FLAG); +ITStatus FMC_GetITStatus(uint32_t FMC_Bank, uint32_t FMC_IT); +void FMC_ClearITPendingBit(uint32_t FMC_Bank, uint32_t FMC_IT); + +#ifdef __cplusplus +} +#endif + +#endif /*__STM32F30x_FMC_H */ +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_gpio.h b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_gpio.h new file mode 100755 index 0000000000..3fd578771a --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_gpio.h @@ -0,0 +1,404 @@ +/** + ****************************************************************************** + * @file stm32f30x_gpio.h + * @author MCD Application Team + * @version V1.2.3 + * @date 10-July-2015 + * @brief This file contains all the functions prototypes for the GPIO + * firmware library. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F30x_GPIO_H +#define __STM32F30x_GPIO_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f30x.h" + +/** @addtogroup STM32F30x_StdPeriph_Driver + * @{ + */ + +/** @addtogroup GPIO + * @{ + */ + +/* Exported types ------------------------------------------------------------*/ + +#define IS_GPIO_ALL_PERIPH(PERIPH) (((PERIPH) == GPIOA) || \ + ((PERIPH) == GPIOB) || \ + ((PERIPH) == GPIOC) || \ + ((PERIPH) == GPIOD) || \ + ((PERIPH) == GPIOE) || \ + ((PERIPH) == GPIOF) || \ + ((PERIPH) == GPIOG) || \ + ((PERIPH) == GPIOH)) + +#define IS_GPIO_LIST_PERIPH(PERIPH) (((PERIPH) == GPIOA) || \ + ((PERIPH) == GPIOB) || \ + ((PERIPH) == GPIOC)|| \ + ((PERIPH) == GPIOD) || \ + ((PERIPH) == GPIOF)) +/** @defgroup Configuration_Mode_enumeration + * @{ + */ +typedef enum +{ + GPIO_Mode_IN = 0x00, /*!< GPIO Input Mode */ + GPIO_Mode_OUT = 0x01, /*!< GPIO Output Mode */ + GPIO_Mode_AF = 0x02, /*!< GPIO Alternate function Mode */ + GPIO_Mode_AN = 0x03 /*!< GPIO Analog In/Out Mode */ +}GPIOMode_TypeDef; + +#define IS_GPIO_MODE(MODE) (((MODE) == GPIO_Mode_IN)|| ((MODE) == GPIO_Mode_OUT) || \ + ((MODE) == GPIO_Mode_AF)|| ((MODE) == GPIO_Mode_AN)) +/** + * @} + */ + +/** @defgroup Output_type_enumeration + * @{ + */ +typedef enum +{ + GPIO_OType_PP = 0x00, + GPIO_OType_OD = 0x01 +}GPIOOType_TypeDef; + +#define IS_GPIO_OTYPE(OTYPE) (((OTYPE) == GPIO_OType_PP) || ((OTYPE) == GPIO_OType_OD)) + +/** + * @} + */ + +/** @defgroup Output_Maximum_frequency_enumeration + * @{ + */ +typedef enum +{ + GPIO_Speed_Level_1 = 0x01, /*!< Fast Speed */ + GPIO_Speed_Level_2 = 0x02, /*!< Meduim Speed */ + GPIO_Speed_Level_3 = 0x03 /*!< High Speed */ +}GPIOSpeed_TypeDef; + +#define IS_GPIO_SPEED(SPEED) (((SPEED) == GPIO_Speed_Level_1) || ((SPEED) == GPIO_Speed_Level_2) || \ + ((SPEED) == GPIO_Speed_Level_3)) +/** + * @} + */ + +/** @defgroup Configuration_Pull-Up_Pull-Down_enumeration + * @{ + */ +typedef enum +{ + GPIO_PuPd_NOPULL = 0x00, + GPIO_PuPd_UP = 0x01, + GPIO_PuPd_DOWN = 0x02 +}GPIOPuPd_TypeDef; + +#define IS_GPIO_PUPD(PUPD) (((PUPD) == GPIO_PuPd_NOPULL) || ((PUPD) == GPIO_PuPd_UP) || \ + ((PUPD) == GPIO_PuPd_DOWN)) +/** + * @} + */ + +/** @defgroup Bit_SET_and_Bit_RESET_enumeration + * @{ + */ +typedef enum +{ + Bit_RESET = 0, + Bit_SET +}BitAction; + +#define IS_GPIO_BIT_ACTION(ACTION) (((ACTION) == Bit_RESET) || ((ACTION) == Bit_SET)) +/** + * @} + */ + +/** + * @brief GPIO Init structure definition + */ +typedef struct +{ + uint32_t GPIO_Pin; /*!< Specifies the GPIO pins to be configured. + This parameter can be any value of @ref GPIO_pins_define */ + + GPIOMode_TypeDef GPIO_Mode; /*!< Specifies the operating mode for the selected pins. + This parameter can be a value of @ref GPIOMode_TypeDef */ + + GPIOSpeed_TypeDef GPIO_Speed; /*!< Specifies the speed for the selected pins. + This parameter can be a value of @ref GPIOSpeed_TypeDef */ + + GPIOOType_TypeDef GPIO_OType; /*!< Specifies the operating output type for the selected pins. + This parameter can be a value of @ref GPIOOType_TypeDef */ + + GPIOPuPd_TypeDef GPIO_PuPd; /*!< Specifies the operating Pull-up/Pull down for the selected pins. + This parameter can be a value of @ref GPIOPuPd_TypeDef */ +}GPIO_InitTypeDef; + +/* Exported constants --------------------------------------------------------*/ + +/** @defgroup GPIO_Exported_Constants + * @{ + */ + +/** @defgroup GPIO_pins_define + * @{ + */ +#define GPIO_Pin_0 ((uint16_t)0x0001) /*!< Pin 0 selected */ +#define GPIO_Pin_1 ((uint16_t)0x0002) /*!< Pin 1 selected */ +#define GPIO_Pin_2 ((uint16_t)0x0004) /*!< Pin 2 selected */ +#define GPIO_Pin_3 ((uint16_t)0x0008) /*!< Pin 3 selected */ +#define GPIO_Pin_4 ((uint16_t)0x0010) /*!< Pin 4 selected */ +#define GPIO_Pin_5 ((uint16_t)0x0020) /*!< Pin 5 selected */ +#define GPIO_Pin_6 ((uint16_t)0x0040) /*!< Pin 6 selected */ +#define GPIO_Pin_7 ((uint16_t)0x0080) /*!< Pin 7 selected */ +#define GPIO_Pin_8 ((uint16_t)0x0100) /*!< Pin 8 selected */ +#define GPIO_Pin_9 ((uint16_t)0x0200) /*!< Pin 9 selected */ +#define GPIO_Pin_10 ((uint16_t)0x0400) /*!< Pin 10 selected */ +#define GPIO_Pin_11 ((uint16_t)0x0800) /*!< Pin 11 selected */ +#define GPIO_Pin_12 ((uint16_t)0x1000) /*!< Pin 12 selected */ +#define GPIO_Pin_13 ((uint16_t)0x2000) /*!< Pin 13 selected */ +#define GPIO_Pin_14 ((uint16_t)0x4000) /*!< Pin 14 selected */ +#define GPIO_Pin_15 ((uint16_t)0x8000) /*!< Pin 15 selected */ +#define GPIO_Pin_All ((uint16_t)0xFFFF) /*!< All pins selected */ + +#define IS_GPIO_PIN(PIN) ((PIN) != (uint16_t)0x00) + +#define IS_GET_GPIO_PIN(PIN) (((PIN) == GPIO_Pin_0) || \ + ((PIN) == GPIO_Pin_1) || \ + ((PIN) == GPIO_Pin_2) || \ + ((PIN) == GPIO_Pin_3) || \ + ((PIN) == GPIO_Pin_4) || \ + ((PIN) == GPIO_Pin_5) || \ + ((PIN) == GPIO_Pin_6) || \ + ((PIN) == GPIO_Pin_7) || \ + ((PIN) == GPIO_Pin_8) || \ + ((PIN) == GPIO_Pin_9) || \ + ((PIN) == GPIO_Pin_10) || \ + ((PIN) == GPIO_Pin_11) || \ + ((PIN) == GPIO_Pin_12) || \ + ((PIN) == GPIO_Pin_13) || \ + ((PIN) == GPIO_Pin_14) || \ + ((PIN) == GPIO_Pin_15)) + +/** + * @} + */ + +/** @defgroup GPIO_Pin_sources + * @{ + */ +#define GPIO_PinSource0 ((uint8_t)0x00) +#define GPIO_PinSource1 ((uint8_t)0x01) +#define GPIO_PinSource2 ((uint8_t)0x02) +#define GPIO_PinSource3 ((uint8_t)0x03) +#define GPIO_PinSource4 ((uint8_t)0x04) +#define GPIO_PinSource5 ((uint8_t)0x05) +#define GPIO_PinSource6 ((uint8_t)0x06) +#define GPIO_PinSource7 ((uint8_t)0x07) +#define GPIO_PinSource8 ((uint8_t)0x08) +#define GPIO_PinSource9 ((uint8_t)0x09) +#define GPIO_PinSource10 ((uint8_t)0x0A) +#define GPIO_PinSource11 ((uint8_t)0x0B) +#define GPIO_PinSource12 ((uint8_t)0x0C) +#define GPIO_PinSource13 ((uint8_t)0x0D) +#define GPIO_PinSource14 ((uint8_t)0x0E) +#define GPIO_PinSource15 ((uint8_t)0x0F) + +#define IS_GPIO_PIN_SOURCE(PINSOURCE) (((PINSOURCE) == GPIO_PinSource0) || \ + ((PINSOURCE) == GPIO_PinSource1) || \ + ((PINSOURCE) == GPIO_PinSource2) || \ + ((PINSOURCE) == GPIO_PinSource3) || \ + ((PINSOURCE) == GPIO_PinSource4) || \ + ((PINSOURCE) == GPIO_PinSource5) || \ + ((PINSOURCE) == GPIO_PinSource6) || \ + ((PINSOURCE) == GPIO_PinSource7) || \ + ((PINSOURCE) == GPIO_PinSource8) || \ + ((PINSOURCE) == GPIO_PinSource9) || \ + ((PINSOURCE) == GPIO_PinSource10) || \ + ((PINSOURCE) == GPIO_PinSource11) || \ + ((PINSOURCE) == GPIO_PinSource12) || \ + ((PINSOURCE) == GPIO_PinSource13) || \ + ((PINSOURCE) == GPIO_PinSource14) || \ + ((PINSOURCE) == GPIO_PinSource15)) +/** + * @} + */ + +/** @defgroup GPIO_Alternate_function_selection_define + * @{ + */ + +/** + * @brief AF 0 selection + */ +#define GPIO_AF_0 ((uint8_t)0x00) /* JTCK-SWCLK, JTDI, JTDO/TRACESW0, JTMS-SWDAT, + MCO, NJTRST, TRACED, TRACECK */ +/** + * @brief AF 1 selection + */ +#define GPIO_AF_1 ((uint8_t)0x01) /* OUT, TIM2, TIM15, TIM16, TIM17 */ + +/** + * @brief AF 2 selection + */ +#define GPIO_AF_2 ((uint8_t)0x02) /* COMP1_OUT, TIM1, TIM2, TIM3, TIM4, TIM8, TIM15, TIM16 */ + +/** + * @brief AF 3 selection + */ +#define GPIO_AF_3 ((uint8_t)0x03) /* COMP7_OUT, TIM8, TIM15, Touch, HRTIM1 */ + +/** + * @brief AF 4 selection + */ +#define GPIO_AF_4 ((uint8_t)0x04) /* I2C1, I2C2, TIM1, TIM8, TIM16, TIM17 */ + +/** + * @brief AF 5 selection + */ +#define GPIO_AF_5 ((uint8_t)0x05) /* IR_OUT, I2S2, I2S3, SPI1, SPI2, TIM8, USART4, USART5 */ + +/** + * @brief AF 6 selection + */ +#define GPIO_AF_6 ((uint8_t)0x06) /* IR_OUT, I2S2, I2S3, SPI2, SPI3, TIM1, TIM8 */ + +/** + * @brief AF 7 selection + */ +#define GPIO_AF_7 ((uint8_t)0x07) /* AOP2_OUT, CAN, COMP3_OUT, COMP5_OUT, COMP6_OUT, + USART1, USART2, USART3 */ + +/** + * @brief AF 8 selection + */ +#define GPIO_AF_8 ((uint8_t)0x08) /* COMP1_OUT, COMP2_OUT, COMP3_OUT, COMP4_OUT, + COMP5_OUT, COMP6_OUT */ + +/** + * @brief AF 9 selection + */ +#define GPIO_AF_9 ((uint8_t)0x09) /* AOP4_OUT, CAN, TIM1, TIM8, TIM15 */ + +/** + * @brief AF 10 selection + */ +#define GPIO_AF_10 ((uint8_t)0x0A) /* AOP1_OUT, AOP3_OUT, TIM2, TIM3, TIM4, TIM8, TIM17 */ + +/** + * @brief AF 11 selection + */ +#define GPIO_AF_11 ((uint8_t)0x0B) /* TIM1, TIM8 */ + +/** + * @brief AF 12 selection + */ +#define GPIO_AF_12 ((uint8_t)0x0C) /* TIM1, HRTIM1 */ + +/** + * @brief AF 13 selection + */ +#define GPIO_AF_13 ((uint8_t)0x0D) /* HRTIM1, AOP2_OUT */ + +/** + * @brief AF 14 selection + */ +#define GPIO_AF_14 ((uint8_t)0x0E) /* USBDM, USBDP */ + +/** + * @brief AF 15 selection + */ +#define GPIO_AF_15 ((uint8_t)0x0F) /* OUT */ + +#define IS_GPIO_AF(AF) (((AF) == GPIO_AF_0)||((AF) == GPIO_AF_1)||\ + ((AF) == GPIO_AF_2)||((AF) == GPIO_AF_3)||\ + ((AF) == GPIO_AF_4)||((AF) == GPIO_AF_5)||\ + ((AF) == GPIO_AF_6)||((AF) == GPIO_AF_7)||\ + ((AF) == GPIO_AF_8)||((AF) == GPIO_AF_9)||\ + ((AF) == GPIO_AF_10)||((AF) == GPIO_AF_11)||\ + ((AF) == GPIO_AF_12)||((AF) == GPIO_AF_13)||\ + ((AF) == GPIO_AF_14)||((AF) == GPIO_AF_15)) + +/** + * @} + */ + +/** @defgroup GPIO_Speed_Legacy + * @{ + */ + +#define GPIO_Speed_10MHz GPIO_Speed_Level_1 /*!< Fast Speed:10MHz */ +#define GPIO_Speed_2MHz GPIO_Speed_Level_2 /*!< Medium Speed:2MHz */ +#define GPIO_Speed_50MHz GPIO_Speed_Level_3 /*!< High Speed:50MHz */ + +/** + * @} + */ + +/** + * @} + */ + +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions ------------------------------------------------------- */ +/* Function used to set the GPIO configuration to the default reset state *****/ +void GPIO_DeInit(GPIO_TypeDef* GPIOx); + +/* Initialization and Configuration functions *********************************/ +void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct); +void GPIO_StructInit(GPIO_InitTypeDef* GPIO_InitStruct); +void GPIO_PinLockConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); + +/* GPIO Read and Write functions **********************************************/ +uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); +uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx); +uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); +uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx); +void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); +void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); +void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal); +void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal); + +/* GPIO Alternate functions configuration functions ***************************/ +void GPIO_PinAFConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_PinSource, uint8_t GPIO_AF); + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F30x_GPIO_H */ +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_hrtim.h b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_hrtim.h new file mode 100755 index 0000000000..56a6eed72b --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_hrtim.h @@ -0,0 +1,2741 @@ +/** + ****************************************************************************** + * @file stm32f30x_hrtim.h + * @author MCD Application Team + * @version V1.2.3 + * @date 10-July-2015 + * @brief This file contains all the functions prototypes for the HRTIM firmware + * library. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F30x_HRTIM_H +#define __STM32F30x_HRTIM_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f30x.h" + +/** @addtogroup STM32F30x_StdPeriph_Driver + * @{ + */ + +/** @addtogroup ADC + * @{ + */ + +/* Exported types ------------------------------------------------------------*/ + +/** + * @brief HRTIM Configuration Structure definition - Time base related parameters + */ +typedef struct +{ + uint32_t Period; /*!< Specifies the timer period + The period value must be above 3 periods of the fHRTIM clock. + Maximum value is = 0xFFDF */ + uint32_t RepetitionCounter; /*!< Specifies the timer repetition period + This parameter must be a number between Min_Data = 0x00 and Max_Data = 0xFF. */ + uint32_t PrescalerRatio; /*!< Specifies the timer clock prescaler ratio. + This parameter can be any value of @ref HRTIM_PrescalerRatio */ + uint32_t Mode; /*!< Specifies the counter operating mode + This parameter can be any value of @ref HRTIM_Mode */ +} HRTIM_BaseInitTypeDef; +/** + * @brief Waveform mode initialization parameters definition + */ +typedef struct { + uint32_t HalfModeEnable; /*!< Specifies whether or not half mode is enabled + This parameter can be a combination of @ref HRTIM_HalfModeEnable */ + uint32_t StartOnSync; /*!< Specifies whether or not timer is reset by a rising edge on the synchronization input (when enabled) + This parameter can be a combination of @ref HRTIM_StartOnSyncInputEvent */ + uint32_t ResetOnSync; /*!< Specifies whether or not timer is reset by a rising edge on the synchronization input (when enabled) + This parameter can be a combination of @ref HRTIM_ResetOnSyncInputEvent */ + uint32_t DACSynchro; /*!< Indicates whether or not the a DAC synchronization event is generated + This parameter can be any value of @ref HRTIM_DACSynchronization */ + uint32_t PreloadEnable; /*!< Specifies whether or not register preload is enabled + This parameter can be a combination of @ref HRTIM_RegisterPreloadEnable */ + uint32_t UpdateGating; /*!< Specifies how the update occurs with respect to a burst DMA transaction or + update enable inputs (Slave timers only) + This parameter can be any value of @ref HRTIM_UpdateGating */ + uint32_t BurstMode; /*!< Specifies how the timer behaves during a burst mode operation + This parameter can be a combination of @ref HRTIM_TimerBurstMode */ + uint32_t RepetitionUpdate; /*!< Specifies whether or not registers update is triggered by the repetition event + This parameter can be a combination of @ref HRTIM_TimerRepetitionUpdate */ +} HRTIM_TimerInitTypeDef; + +/** + * @brief Basic output compare mode configuration definition + */ +typedef struct { + uint32_t Mode; /*!< Specifies the output compare mode (toggle, active, inactive) + This parameter can be a combination of @ref HRTIM_BasicOCMode */ + uint32_t Pulse; /*!< Specifies the compare value to be loaded into the Compare Register. + The compare value must be above or equal to 3 periods of the fHRTIM clock */ + uint32_t Polarity; /*!< Specifies the output polarity + This parameter can be any value of @ref HRTIM_Output_Polarity */ + uint32_t IdleState; /*!< Specifies whether the output level is active or inactive when in IDLE state + This parameter can be any value of @ref HRTIM_OutputIDLEState */ +} HRTIM_BasicOCChannelCfgTypeDef; + +/** + * @brief Basic PWM output mode configuration definition + */ +typedef struct { + uint32_t Pulse; /*!< Specifies the compare value to be loaded into the Compare Register. + The compare value must be above or equal to 3 periods of the fHRTIM clock */ + uint32_t Polarity; /*!< Specifies the output polarity + This parameter can be any value of @ref HRTIM_OutputPolarity */ + uint32_t IdleState; /*!< Specifies whether the output level is active or inactive when in IDLE state + This parameter can be any value of @ref HRTIM_OutputIDLEState */ +} HRTIM_BasicPWMChannelCfgTypeDef; + +/** + * @brief Basic capture mode configuration definition + */ +typedef struct { + uint32_t CaptureUnit; /*!< Specifies the external event Channel + This parameter can be any 'EEVx' value of @ref HRTIM_CaptureUnit */ + uint32_t Event; /*!< Specifies the external event triggering the capture + This parameter can be any 'EEVx' value of @ref HRTIM_ExternalEventChannels */ + uint32_t EventPolarity; /*!< Specifies the polarity of the external event (in case of level sensitivity) + This parameter can be a value of @ref HRTIM_ExternalEventPolarity */ + uint32_t EventSensitivity; /*!< Specifies the sensitivity of the external event + This parameter can be a value of @ref HRTIM_ExternalEventSensitivity */ + uint32_t EventFilter; /*!< Defines the frequency used to sample the External Event and the length of the digital filter + This parameter can be a value of @ref HRTIM_ExternalEventFilter */ +} HRTIM_BasicCaptureChannelCfgTypeDef; + +/** + * @brief Basic One Pulse mode configuration definition + */ +typedef struct { + uint32_t Pulse; /*!< Specifies the compare value to be loaded into the Compare Register. + The compare value must be above or equal to 3 periods of the fHRTIM clock */ + uint32_t OutputPolarity; /*!< Specifies the output polarity + This parameter can be any value of @ref HRTIM_Output_Polarity */ + uint32_t OutputIdleState; /*!< Specifies whether the output level is active or inactive when in IDLE state + This parameter can be any value of @ref HRTIM_Output_IDLE_State */ + uint32_t Event; /*!< Specifies the external event triggering the pulse generation + This parameter can be any 'EEVx' value of @ref HRTIM_Capture_Unit_Trigger */ + uint32_t EventPolarity; /*!< Specifies the polarity of the external event (in case of level sensitivity) + This parameter can be a value of @ref HRTIM_ExternalEventPolarity */ + uint32_t EventSensitivity; /*!< Specifies the sensitivity of the external event + This parameter can be a value of @ref HRTIM_ExternalEventSensitivity */ + uint32_t EventFilter; /*!< Defines the frequency used to sample the External Event and the length of the digital filter + This parameter can be a value of @ref HRTIM_ExternalEventFilter */ +} HRTIM_BasicOnePulseChannelCfgTypeDef; + +/** + * @brief Timer configuration definition + */ +typedef struct { + uint32_t PushPull; /*!< Specifies whether or not the push-pull mode is enabled + This parameter can be a value of @ref HRTIM_TimerPushPullMode */ + uint32_t FaultEnable; /*!< Specifies which fault channels are enabled for the timer + This parameter can be a combination of @ref HRTIM_TimerFaultEnabling */ + uint32_t FaultLock; /*!< Specifies whether or not fault enabling status is write protected + This parameter can be a value of @ref HRTIM_TimerFaultLock */ + uint32_t DeadTimeInsertion; /*!< Specifies whether or not dead time insertion is enabled for the timer + This parameter can be a value of @ref HRTIM_TimerDeadtimeInsertion */ + uint32_t DelayedProtectionMode; /*!< Specifies the delayed protection mode + This parameter can be a value of @ref HRTIM_TimerDelayedProtectionMode */ + uint32_t UpdateTrigger; /*!< Specifies source(s) triggering the timer registers update + This parameter can be a combination of @ref HRTIM_TimerUpdateTrigger */ + uint32_t ResetTrigger; /*!< Specifies source(s) triggering the timer counter reset + This parameter can be a combination of @ref HRTIM_TimerResetTrigger */ + uint32_t ResetUpdate; /*!< Specifies whether or not registers update is triggered when the timer counter is reset + This parameter can be a combination of @ref HRTIM_TimerResetUpdate */ +} HRTIM_TimerCfgTypeDef; + +/** + * @brief Compare unit configuration definition + */ +typedef struct { + uint32_t CompareValue; /*!< Specifies the compare value of the timer compare unit + the minimum value must be greater than or equal to 3 periods of the fHRTIM clock + the maximum value must be less than or equal to 0xFFFF - 1 periods of the fHRTIM clock */ + uint32_t AutoDelayedMode; /*!< Specifies the auto delayed mode for compare unit 2 or 4 + This parameter can be a value of @ref HRTIM_CompareUnitAutoDelayedMode */ + uint32_t AutoDelayedTimeout; /*!< Specifies compare value for timing unit 1 or 3 when auto delayed mode with time out is selected + CompareValue + AutoDelayedTimeout must be less than 0xFFFF */ +} HRTIM_CompareCfgTypeDef; + +/** + * @brief Capture unit configuration definition + */ +typedef struct { + uint32_t Trigger; /*!< Specifies source(s) triggering the capture + This parameter can be a combination of @ref HRTIM_CaptureUnitTrigger */ +} HRTIM_CaptureCfgTypeDef; + +/** + * @brief Output configuration definition + */ +typedef struct { + uint32_t Polarity; /*!< Specifies the output polarity + This parameter can be any value of @ref HRTIM_Output_Polarity */ + uint32_t SetSource; /*!< Specifies the event(s) transitioning the output from its inactive level to its active level + This parameter can be any value of @ref HRTIM_OutputSetSource */ + uint32_t ResetSource; /*!< Specifies the event(s) transitioning the output from its active level to its inactive level + This parameter can be any value of @ref HRTIM_OutputResetSource */ + uint32_t IdleMode; /*!< Specifies whether or not the output is affected by a burst mode operation + This parameter can be any value of @ref HRTIM_OutputIdleMode */ + uint32_t IdleState; /*!< Specifies whether the output level is active or inactive when in IDLE state + This parameter can be any value of @ref HRTIM_OutputIDLEState */ + uint32_t FaultState; /*!< Specifies whether the output level is active or inactive when in FAULT state + This parameter can be any value of @ref HRTIM_OutputFAULTState */ + uint32_t ChopperModeEnable; /*!< Indicates whether or not the chopper mode is enabled + This parameter can be any value of @ref HRTIM_OutputChopperModeEnable */ + uint32_t BurstModeEntryDelayed; /* !HRTIM_MASTER.MCR |= (__TIMERS__)) + +/* The counter of a timing unit is disabled only if all the timer outputs */ +/* are disabled and no capture is configured */ +#define HRTIM_TAOEN_MASK (HRTIM_OENR_TA2OEN | HRTIM_OENR_TA1OEN) +#define HRTIM_TBOEN_MASK (HRTIM_OENR_TB2OEN | HRTIM_OENR_TB1OEN) +#define HRTIM_TCOEN_MASK (HRTIM_OENR_TC2OEN | HRTIM_OENR_TC1OEN) +#define HRTIM_TDOEN_MASK (HRTIM_OENR_TD2OEN | HRTIM_OENR_TD1OEN) +#define HRTIM_TEOEN_MASK (HRTIM_OENR_TE2OEN | HRTIM_OENR_TE1OEN) +#define __HRTIM_DISABLE(__HANDLE__, __TIMERS__)\ + do {\ + if (((__TIMERS__) & HRTIM_TIMERID_MASTER) == HRTIM_TIMERID_MASTER)\ + {\ + ((__HANDLE__)->HRTIM_MASTER.MCR &= ~HRTIM_TIMERID_MASTER);\ + }\ + if (((__TIMERS__) & HRTIM_TIMERID_TIMER_A) == HRTIM_TIMERID_TIMER_A)\ + {\ + if (((__HANDLE__)->HRTIM_COMMON.OENR & HRTIM_TAOEN_MASK) == RESET)\ + {\ + ((__HANDLE__)->HRTIM_MASTER.MCR &= ~HRTIM_TIMERID_TIMER_A);\ + }\ + }\ + if (((__TIMERS__) & HRTIM_TIMERID_TIMER_B) == HRTIM_TIMERID_TIMER_B)\ + {\ + if (((__HANDLE__)->HRTIM_COMMON.OENR & HRTIM_TBOEN_MASK) == RESET)\ + {\ + ((__HANDLE__)->HRTIM_MASTER.MCR &= ~HRTIM_TIMERID_TIMER_B);\ + }\ + }\ + if (((__TIMERS__) & HRTIM_TIMERID_TIMER_C) == HRTIM_TIMERID_TIMER_C)\ + {\ + if (((__HANDLE__)->HRTIM_COMMON.OENR & HRTIM_TCOEN_MASK) == RESET)\ + {\ + ((__HANDLE__)->HRTIM_MASTER.MCR &= ~HRTIM_TIMERID_TIMER_C);\ + }\ + }\ + if (((__TIMERS__) & HRTIM_TIMERID_TIMER_D) == HRTIM_TIMERID_TIMER_D)\ + {\ + if (((__HANDLE__)->HRTIM_COMMON.OENR & HRTIM_TDOEN_MASK) == RESET)\ + {\ + ((__HANDLE__)->HRTIM_MASTER.MCR &= ~HRTIM_TIMERID_TIMER_D);\ + }\ + }\ + if (((__TIMERS__) & HRTIM_TIMERID_TIMER_E) == HRTIM_TIMERID_TIMER_E)\ + {\ + if (((__HANDLE__)->HRTIM_COMMON.OENR & HRTIM_TEOEN_MASK) == RESET)\ + {\ + ((__HANDLE__)->HRTIM_MASTER.MCR &= ~HRTIM_TIMERID_TIMER_E);\ + }\ + }\ + } while(0) + +/* Exported functions --------------------------------------------------------*/ + +/* Simple time base related functions *****************************************/ +void HRTIM_SimpleBase_Init(HRTIM_TypeDef* HRTIMx, uint32_t TimerIdx, HRTIM_BaseInitTypeDef* HRTIM_BaseInitStruct); + +void HRTIM_DeInit(HRTIM_TypeDef* HRTIMx); + +void HRTIM_SimpleBaseStart(HRTIM_TypeDef *HRTIMx, uint32_t TimerIdx); +void HRTIM_SimpleBaseStop(HRTIM_TypeDef *HRTIMx, uint32_t TimerIdx); + +/* Simple output compare related functions ************************************/ +void HRTIM_SimpleOC_Init(HRTIM_TypeDef * HRTIMx, uint32_t TimerIdx, HRTIM_BaseInitTypeDef* HRTIM_BaseInitStruct); + +void HRTIM_SimpleOCChannelConfig(HRTIM_TypeDef *HRTIMx, + uint32_t TimerIdx, + uint32_t OCChannel, + HRTIM_BasicOCChannelCfgTypeDef* pBasicOCChannelCfg); + +void HRTIM_SimpleOCStart(HRTIM_TypeDef *HRTIMx, + uint32_t TimerIdx, + uint32_t OCChannel); +void HRTIM_SimpleOCStop(HRTIM_TypeDef * HRTIMx, + uint32_t TimerIdx, + uint32_t OCChannel); +/* Simple PWM output related functions ****************************************/ +void HRTIM_SimplePWM_Init(HRTIM_TypeDef * HRTIMx, uint32_t TimerIdx, HRTIM_BaseInitTypeDef* HRTIM_BaseInitStruct); + +void HRTIM_SimplePWMChannelConfig(HRTIM_TypeDef *HRTIMx, + uint32_t TimerIdx, + uint32_t PWMChannel, + HRTIM_BasicPWMChannelCfgTypeDef* pBasicPWMChannelCfg); + +void HRTIM_SimplePWMStart(HRTIM_TypeDef * HRTIMx, + uint32_t TimerIdx, + uint32_t PWMChannel); +void HRTIM_SimplePWMStop(HRTIM_TypeDef * HRTIMx, + uint32_t TimerIdx, + uint32_t PWMChannel); +/* Simple capture related functions *******************************************/ +void HRTIM_SimpleCapture_Init(HRTIM_TypeDef * HRTIMx, uint32_t TimerIdx, HRTIM_BaseInitTypeDef* HRTIM_BaseInitStruct); + +void HRTIM_SimpleCaptureChannelConfig(HRTIM_TypeDef *HRTIMx, + uint32_t TimerIdx, + uint32_t CaptureChannel, + HRTIM_BasicCaptureChannelCfgTypeDef* pBasicCaptureChannelCfg); + +void HRTIM_SimpleCaptureStart(HRTIM_TypeDef * HRTIMx, + uint32_t TimerIdx, + uint32_t CaptureChannel); +void HRTIM_SimpleCaptureStop(HRTIM_TypeDef * HRTIMx, + uint32_t TimerIdx, + uint32_t CaptureChannel); +/* SImple one pulse related functions *****************************************/ +void HRTIM_SimpleOnePulse_Init(HRTIM_TypeDef * HRTIMx, uint32_t TimerIdx, HRTIM_BaseInitTypeDef* HRTIM_BaseInitStruct); + +void HRTIM_SimpleOnePulseChannelConfig(HRTIM_TypeDef *HRTIMx, + uint32_t TimerIdx, + uint32_t OnePulseChannel, + HRTIM_BasicOnePulseChannelCfgTypeDef* pBasicOnePulseChannelCfg); + +void HRTIM_SimpleOnePulseStart(HRTIM_TypeDef * HRTIMx, + uint32_t TimerIdx, + uint32_t OnePulseChannel); +void HRTIM_SimpleOnePulseStop(HRTIM_TypeDef * HRTIM_, + uint32_t TimerIdx, + uint32_t OnePulseChannel); +/* Waveform related functions *************************************************/ +void HRTIM_Waveform_Init(HRTIM_TypeDef * HRTIMx, + uint32_t TimerIdx, + HRTIM_BaseInitTypeDef* HRTIM_BaseInitStruct, + HRTIM_TimerInitTypeDef* HRTIM_TimerInitStruct); + +void HRTIM_WaveformTimerConfig(HRTIM_TypeDef *HRTIMx, + uint32_t TimerIdx, + HRTIM_TimerCfgTypeDef * HRTIM_TimerCfgStruct); + +void HRTIM_WaveformCompareConfig(HRTIM_TypeDef *HRTIMx, + uint32_t TimerIdx, + uint32_t CompareUnit, + HRTIM_CompareCfgTypeDef* pCompareCfg); + +void HRTIM_SlaveSetCompare(HRTIM_TypeDef * HRTIMx, + uint32_t TimerIdx, + uint32_t CompareUnit, + uint32_t Compare); + +void HRTIM_MasterSetCompare(HRTIM_TypeDef * HRTIMx, + uint32_t CompareUnit, + uint32_t Compare); + +void HRTIM_WaveformCaptureConfig(HRTIM_TypeDef *HRTIMx, + uint32_t TimerIdx, + uint32_t CaptureUnit, + HRTIM_CaptureCfgTypeDef* pCaptureCfg); + +void HRTIM_TimerEventFilteringConfig(HRTIM_TypeDef *HRTIMx, + uint32_t TimerIdx, + uint32_t Event, + HRTIM_TimerEventFilteringCfgTypeDef * pTimerEventFilteringCfg); + +void HRTIM_DeadTimeConfig(HRTIM_TypeDef *HRTIMx, + uint32_t TimerIdx, + HRTIM_DeadTimeCfgTypeDef* pDeadTimeCfg); + +void HRTIM_ChopperModeConfig(HRTIM_TypeDef *HRTIMx, + uint32_t TimerIdx, + HRTIM_ChopperModeCfgTypeDef* pChopperModeCfg); + +void HRTIM_BurstDMAConfig(HRTIM_TypeDef *HRTIMx, + uint32_t TimerIdx, + uint32_t RegistersToUpdate); + +void HRTIM_SynchronizationConfig(HRTIM_TypeDef *HRTIMx, + HRTIM_SynchroCfgTypeDef * pSynchroCfg); + +void HRTIM_BurstModeConfig(HRTIM_TypeDef *HRTIMx, + HRTIM_BurstModeCfgTypeDef* pBurstModeCfg); + +void HRTIM_EventConfig(HRTIM_TypeDef *HRTIMx, + uint32_t Event, + HRTIM_EventCfgTypeDef* pEventCfg); + +void HRTIM_EventPrescalerConfig(HRTIM_TypeDef *HRTIMx, + uint32_t Prescaler); + +void HRTIM_FaultConfig(HRTIM_TypeDef *hrtim, + HRTIM_FaultCfgTypeDef* pFaultCfg, + uint32_t Fault); + +void HRTIM_FaultPrescalerConfig(HRTIM_TypeDef *HRTIMx, + uint32_t Prescaler); +void HRTIM_FaultModeCtl(HRTIM_TypeDef * HRTIMx, uint32_t Fault, uint32_t Enable); + +void HRTIM_ADCTriggerConfig(HRTIM_TypeDef *HRTIMx, + uint32_t ADCTrigger, + HRTIM_ADCTriggerCfgTypeDef* pADCTriggerCfg); + +void HRTIM_WaveformCounterStart(HRTIM_TypeDef *HRTIMx, + uint32_t TimersToStart); + +void HRTIM_WaveformCounterStop(HRTIM_TypeDef *HRTIMx, + uint32_t TimersToStop); + +void HRTIM_WaveformOutputStart(HRTIM_TypeDef *HRTIMx, + uint32_t OutputsToStart); +void HRTIM_WaveformOutputStop(HRTIM_TypeDef * HRTIM_, + uint32_t OutputsToStop); + +void HRTIM_DLLCalibrationStart(HRTIM_TypeDef *HRTIMx, + uint32_t CalibrationRate); + +/* Interrupt/flags and DMA management */ +void HRTIM_ITConfig(HRTIM_TypeDef * HRTIMx, uint32_t TimerIdx, uint32_t HRTIM_TIM_IT, FunctionalState NewState); +void HRTIM_ITCommonConfig(HRTIM_TypeDef * HRTIMx, uint32_t HRTIM_CommonIT, FunctionalState NewState); + +void HRTIM_ClearFlag(HRTIM_TypeDef * HRTIMx, uint32_t TimerIdx, uint32_t HRTIM_FLAG); +void HRTIM_ClearCommonFlag(HRTIM_TypeDef * HRTIMx, uint32_t HRTIM_CommonFLAG); + +void HRTIM_ClearITPendingBit(HRTIM_TypeDef * HRTIMx, uint32_t TimerIdx, uint32_t HRTIM_IT); +void HRTIM_ClearCommonITPendingBit(HRTIM_TypeDef * HRTIMx, uint32_t HRTIM_CommonIT); + +FlagStatus HRTIM_GetFlagStatus(HRTIM_TypeDef * HRTIMx, uint32_t TimerIdx, uint32_t HRTIM_FLAG); +FlagStatus HRTIM_GetCommonFlagStatus(HRTIM_TypeDef * HRTIMx, uint32_t HRTIM_CommonFLAG); + +ITStatus HRTIM_GetITStatus(HRTIM_TypeDef * HRTIMx, uint32_t TimerIdx, uint32_t HRTIM_IT); +ITStatus HRTIM_GetCommonITStatus(HRTIM_TypeDef * HRTIMx, uint32_t HRTIM_CommonIT); + + +void HRTIM_DMACmd(HRTIM_TypeDef* HRTIMx, uint32_t TimerIdx, uint32_t HRTIM_DMA, FunctionalState NewState); + +void HRTIM_BurstModeCtl(HRTIM_TypeDef *HRTIMx, + uint32_t Enable); + +void HRTIM_SoftwareCapture(HRTIM_TypeDef *HRTIMx, + uint32_t TimerIdx, + uint32_t CaptureUnit); + +void HRTIM_SoftwareUpdate(HRTIM_TypeDef *HRTIMx, + uint32_t TimersToUpdate); + +void HRTIM_SoftwareReset(HRTIM_TypeDef *HRTIMx, + uint32_t TimersToReset); + + +uint32_t HRTIM_GetCapturedValue(HRTIM_TypeDef *HRTIMx, + uint32_t TimerIdx, + uint32_t CaptureUnit); + +void HRTIM_WaveformOutputConfig(HRTIM_TypeDef * HRTIMx, + uint32_t TimerIdx, + uint32_t Output, + HRTIM_OutputCfgTypeDef * pOutputCfg); + +void HRTIM_WaveformSetOutputLevel(HRTIM_TypeDef *HRTIMx, + uint32_t TimerIdx, + uint32_t Output, + uint32_t OutputLevel); + +uint32_t HRTIM_WaveformGetOutputLevel(HRTIM_TypeDef *HRTIMx, + uint32_t TimerIdx, + uint32_t Output); + +uint32_t HRTIM_WaveformGetOutputState(HRTIM_TypeDef * HRTIMx, + uint32_t TimerIdx, + uint32_t Output); + +uint32_t HRTIM_GetDelayedProtectionStatus(HRTIM_TypeDef *HRTIMx, + uint32_t TimerIdx, + uint32_t Output); + +uint32_t HRTIM_GetBurstStatus(HRTIM_TypeDef *HRTIMx); + +uint32_t HRTIM_GetCurrentPushPullStatus(HRTIM_TypeDef *HRTIMx, + uint32_t TimerIdx); + +uint32_t HRTIM_GetIdlePushPullStatus(HRTIM_TypeDef *HRTIMx, + uint32_t TimerIdx); +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F30x_HRTIM_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_i2c.h b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_i2c.h new file mode 100755 index 0000000000..1def7513a4 --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_i2c.h @@ -0,0 +1,477 @@ +/** + ****************************************************************************** + * @file stm32f30x_i2c.h + * @author MCD Application Team + * @version V1.2.3 + * @date 10-July-2015 + * @brief This file contains all the functions prototypes for the I2C firmware + * library. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F30x_I2C_H +#define __STM32F30x_I2C_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f30x.h" + +/** @addtogroup STM32F30x_StdPeriph_Driver + * @{ + */ + +/** @addtogroup I2C + * @{ + */ + +/* Exported types ------------------------------------------------------------*/ + +/** + * @brief I2C Init structure definition + */ + +typedef struct +{ + uint32_t I2C_Timing; /*!< Specifies the I2C_TIMINGR_register value. + This parameter calculated by referring to I2C initialization + section in Reference manual*/ + + uint32_t I2C_AnalogFilter; /*!< Enables or disables analog noise filter. + This parameter can be a value of @ref I2C_Analog_Filter */ + + uint32_t I2C_DigitalFilter; /*!< Configures the digital noise filter. + This parameter can be a number between 0x00 and 0x0F */ + + uint32_t I2C_Mode; /*!< Specifies the I2C mode. + This parameter can be a value of @ref I2C_mode */ + + uint32_t I2C_OwnAddress1; /*!< Specifies the device own address 1. + This parameter can be a 7-bit or 10-bit address */ + + uint32_t I2C_Ack; /*!< Enables or disables the acknowledgement. + This parameter can be a value of @ref I2C_acknowledgement */ + + uint32_t I2C_AcknowledgedAddress; /*!< Specifies if 7-bit or 10-bit address is acknowledged. + This parameter can be a value of @ref I2C_acknowledged_address */ +}I2C_InitTypeDef; + +/* Exported constants --------------------------------------------------------*/ + + +/** @defgroup I2C_Exported_Constants + * @{ + */ + +#define IS_I2C_ALL_PERIPH(PERIPH) (((PERIPH) == I2C1) || \ + ((PERIPH) == I2C2)) + +/** @defgroup I2C_Analog_Filter + * @{ + */ + +#define I2C_AnalogFilter_Enable ((uint32_t)0x00000000) +#define I2C_AnalogFilter_Disable I2C_CR1_ANFOFF + +#define IS_I2C_ANALOG_FILTER(FILTER) (((FILTER) == I2C_AnalogFilter_Enable) || \ + ((FILTER) == I2C_AnalogFilter_Disable)) +/** + * @} + */ + +/** @defgroup I2C_Digital_Filter + * @{ + */ + +#define IS_I2C_DIGITAL_FILTER(FILTER) ((FILTER) <= 0x0000000F) +/** + * @} + */ + +/** @defgroup I2C_mode + * @{ + */ + +#define I2C_Mode_I2C ((uint32_t)0x00000000) +#define I2C_Mode_SMBusDevice I2C_CR1_SMBDEN +#define I2C_Mode_SMBusHost I2C_CR1_SMBHEN + +#define IS_I2C_MODE(MODE) (((MODE) == I2C_Mode_I2C) || \ + ((MODE) == I2C_Mode_SMBusDevice) || \ + ((MODE) == I2C_Mode_SMBusHost)) +/** + * @} + */ + +/** @defgroup I2C_acknowledgement + * @{ + */ + +#define I2C_Ack_Enable ((uint32_t)0x00000000) +#define I2C_Ack_Disable I2C_CR2_NACK + +#define IS_I2C_ACK(ACK) (((ACK) == I2C_Ack_Enable) || \ + ((ACK) == I2C_Ack_Disable)) +/** + * @} + */ + +/** @defgroup I2C_acknowledged_address + * @{ + */ + +#define I2C_AcknowledgedAddress_7bit ((uint32_t)0x00000000) +#define I2C_AcknowledgedAddress_10bit I2C_OAR1_OA1MODE + +#define IS_I2C_ACKNOWLEDGE_ADDRESS(ADDRESS) (((ADDRESS) == I2C_AcknowledgedAddress_7bit) || \ + ((ADDRESS) == I2C_AcknowledgedAddress_10bit)) +/** + * @} + */ + +/** @defgroup I2C_own_address1 + * @{ + */ + +#define IS_I2C_OWN_ADDRESS1(ADDRESS1) ((ADDRESS1) <= (uint32_t)0x000003FF) +/** + * @} + */ + +/** @defgroup I2C_transfer_direction + * @{ + */ + +#define I2C_Direction_Transmitter ((uint16_t)0x0000) +#define I2C_Direction_Receiver ((uint16_t)0x0400) + +#define IS_I2C_DIRECTION(DIRECTION) (((DIRECTION) == I2C_Direction_Transmitter) || \ + ((DIRECTION) == I2C_Direction_Receiver)) +/** + * @} + */ + +/** @defgroup I2C_DMA_transfer_requests + * @{ + */ + +#define I2C_DMAReq_Tx I2C_CR1_TXDMAEN +#define I2C_DMAReq_Rx I2C_CR1_RXDMAEN + +#define IS_I2C_DMA_REQ(REQ) ((((REQ) & (uint32_t)0xFFFF3FFF) == 0x00) && ((REQ) != 0x00)) +/** + * @} + */ + +/** @defgroup I2C_slave_address + * @{ + */ + +#define IS_I2C_SLAVE_ADDRESS(ADDRESS) ((ADDRESS) <= (uint16_t)0x03FF) +/** + * @} + */ + + +/** @defgroup I2C_own_address2 + * @{ + */ + +#define IS_I2C_OWN_ADDRESS2(ADDRESS2) ((ADDRESS2) <= (uint16_t)0x00FF) + +/** + * @} + */ + +/** @defgroup I2C_own_address2_mask + * @{ + */ + +#define I2C_OA2_NoMask ((uint8_t)0x00) +#define I2C_OA2_Mask01 ((uint8_t)0x01) +#define I2C_OA2_Mask02 ((uint8_t)0x02) +#define I2C_OA2_Mask03 ((uint8_t)0x03) +#define I2C_OA2_Mask04 ((uint8_t)0x04) +#define I2C_OA2_Mask05 ((uint8_t)0x05) +#define I2C_OA2_Mask06 ((uint8_t)0x06) +#define I2C_OA2_Mask07 ((uint8_t)0x07) + +#define IS_I2C_OWN_ADDRESS2_MASK(MASK) (((MASK) == I2C_OA2_NoMask) || \ + ((MASK) == I2C_OA2_Mask01) || \ + ((MASK) == I2C_OA2_Mask02) || \ + ((MASK) == I2C_OA2_Mask03) || \ + ((MASK) == I2C_OA2_Mask04) || \ + ((MASK) == I2C_OA2_Mask05) || \ + ((MASK) == I2C_OA2_Mask06) || \ + ((MASK) == I2C_OA2_Mask07)) + +/** + * @} + */ + +/** @defgroup I2C_timeout + * @{ + */ + +#define IS_I2C_TIMEOUT(TIMEOUT) ((TIMEOUT) <= (uint16_t)0x0FFF) + +/** + * @} + */ + +/** @defgroup I2C_registers + * @{ + */ + +#define I2C_Register_CR1 ((uint8_t)0x00) +#define I2C_Register_CR2 ((uint8_t)0x04) +#define I2C_Register_OAR1 ((uint8_t)0x08) +#define I2C_Register_OAR2 ((uint8_t)0x0C) +#define I2C_Register_TIMINGR ((uint8_t)0x10) +#define I2C_Register_TIMEOUTR ((uint8_t)0x14) +#define I2C_Register_ISR ((uint8_t)0x18) +#define I2C_Register_ICR ((uint8_t)0x1C) +#define I2C_Register_PECR ((uint8_t)0x20) +#define I2C_Register_RXDR ((uint8_t)0x24) +#define I2C_Register_TXDR ((uint8_t)0x28) + +#define IS_I2C_REGISTER(REGISTER) (((REGISTER) == I2C_Register_CR1) || \ + ((REGISTER) == I2C_Register_CR2) || \ + ((REGISTER) == I2C_Register_OAR1) || \ + ((REGISTER) == I2C_Register_OAR2) || \ + ((REGISTER) == I2C_Register_TIMINGR) || \ + ((REGISTER) == I2C_Register_TIMEOUTR) || \ + ((REGISTER) == I2C_Register_ISR) || \ + ((REGISTER) == I2C_Register_ICR) || \ + ((REGISTER) == I2C_Register_PECR) || \ + ((REGISTER) == I2C_Register_RXDR) || \ + ((REGISTER) == I2C_Register_TXDR)) +/** + * @} + */ + +/** @defgroup I2C_interrupts_definition + * @{ + */ + +#define I2C_IT_ERRI I2C_CR1_ERRIE +#define I2C_IT_TCI I2C_CR1_TCIE +#define I2C_IT_STOPI I2C_CR1_STOPIE +#define I2C_IT_NACKI I2C_CR1_NACKIE +#define I2C_IT_ADDRI I2C_CR1_ADDRIE +#define I2C_IT_RXI I2C_CR1_RXIE +#define I2C_IT_TXI I2C_CR1_TXIE + +#define IS_I2C_CONFIG_IT(IT) ((((IT) & (uint32_t)0xFFFFFF01) == 0x00) && ((IT) != 0x00)) + +/** + * @} + */ + +/** @defgroup I2C_flags_definition + * @{ + */ + +#define I2C_FLAG_TXE I2C_ISR_TXE +#define I2C_FLAG_TXIS I2C_ISR_TXIS +#define I2C_FLAG_RXNE I2C_ISR_RXNE +#define I2C_FLAG_ADDR I2C_ISR_ADDR +#define I2C_FLAG_NACKF I2C_ISR_NACKF +#define I2C_FLAG_STOPF I2C_ISR_STOPF +#define I2C_FLAG_TC I2C_ISR_TC +#define I2C_FLAG_TCR I2C_ISR_TCR +#define I2C_FLAG_BERR I2C_ISR_BERR +#define I2C_FLAG_ARLO I2C_ISR_ARLO +#define I2C_FLAG_OVR I2C_ISR_OVR +#define I2C_FLAG_PECERR I2C_ISR_PECERR +#define I2C_FLAG_TIMEOUT I2C_ISR_TIMEOUT +#define I2C_FLAG_ALERT I2C_ISR_ALERT +#define I2C_FLAG_BUSY I2C_ISR_BUSY + +#define IS_I2C_CLEAR_FLAG(FLAG) ((((FLAG) & (uint32_t)0xFFFF4000) == 0x00) && ((FLAG) != 0x00)) + +#define IS_I2C_GET_FLAG(FLAG) (((FLAG) == I2C_FLAG_TXE) || ((FLAG) == I2C_FLAG_TXIS) || \ + ((FLAG) == I2C_FLAG_RXNE) || ((FLAG) == I2C_FLAG_ADDR) || \ + ((FLAG) == I2C_FLAG_NACKF) || ((FLAG) == I2C_FLAG_STOPF) || \ + ((FLAG) == I2C_FLAG_TC) || ((FLAG) == I2C_FLAG_TCR) || \ + ((FLAG) == I2C_FLAG_BERR) || ((FLAG) == I2C_FLAG_ARLO) || \ + ((FLAG) == I2C_FLAG_OVR) || ((FLAG) == I2C_FLAG_PECERR) || \ + ((FLAG) == I2C_FLAG_TIMEOUT) || ((FLAG) == I2C_FLAG_ALERT) || \ + ((FLAG) == I2C_FLAG_BUSY)) + +/** + * @} + */ + + +/** @defgroup I2C_interrupts_definition + * @{ + */ + +#define I2C_IT_TXIS I2C_ISR_TXIS +#define I2C_IT_RXNE I2C_ISR_RXNE +#define I2C_IT_ADDR I2C_ISR_ADDR +#define I2C_IT_NACKF I2C_ISR_NACKF +#define I2C_IT_STOPF I2C_ISR_STOPF +#define I2C_IT_TC I2C_ISR_TC +#define I2C_IT_TCR I2C_ISR_TCR +#define I2C_IT_BERR I2C_ISR_BERR +#define I2C_IT_ARLO I2C_ISR_ARLO +#define I2C_IT_OVR I2C_ISR_OVR +#define I2C_IT_PECERR I2C_ISR_PECERR +#define I2C_IT_TIMEOUT I2C_ISR_TIMEOUT +#define I2C_IT_ALERT I2C_ISR_ALERT + +#define IS_I2C_CLEAR_IT(IT) ((((IT) & (uint32_t)0xFFFFC001) == 0x00) && ((IT) != 0x00)) + +#define IS_I2C_GET_IT(IT) (((IT) == I2C_IT_TXIS) || ((IT) == I2C_IT_RXNE) || \ + ((IT) == I2C_IT_ADDR) || ((IT) == I2C_IT_NACKF) || \ + ((IT) == I2C_IT_STOPF) || ((IT) == I2C_IT_TC) || \ + ((IT) == I2C_IT_TCR) || ((IT) == I2C_IT_BERR) || \ + ((IT) == I2C_IT_ARLO) || ((IT) == I2C_IT_OVR) || \ + ((IT) == I2C_IT_PECERR) || ((IT) == I2C_IT_TIMEOUT) || \ + ((IT) == I2C_IT_ALERT)) + + +/** + * @} + */ + +/** @defgroup I2C_ReloadEndMode_definition + * @{ + */ + +#define I2C_Reload_Mode I2C_CR2_RELOAD +#define I2C_AutoEnd_Mode I2C_CR2_AUTOEND +#define I2C_SoftEnd_Mode ((uint32_t)0x00000000) + + +#define IS_RELOAD_END_MODE(MODE) (((MODE) == I2C_Reload_Mode) || \ + ((MODE) == I2C_AutoEnd_Mode) || \ + ((MODE) == I2C_SoftEnd_Mode)) + + +/** + * @} + */ + +/** @defgroup I2C_StartStopMode_definition + * @{ + */ + +#define I2C_No_StartStop ((uint32_t)0x00000000) +#define I2C_Generate_Stop I2C_CR2_STOP +#define I2C_Generate_Start_Read (uint32_t)(I2C_CR2_START | I2C_CR2_RD_WRN) +#define I2C_Generate_Start_Write I2C_CR2_START + + +#define IS_START_STOP_MODE(MODE) (((MODE) == I2C_Generate_Stop) || \ + ((MODE) == I2C_Generate_Start_Read) || \ + ((MODE) == I2C_Generate_Start_Write) || \ + ((MODE) == I2C_No_StartStop)) + + +/** + * @} + */ + +/** + * @} + */ + +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions ------------------------------------------------------- */ + + +/* Initialization and Configuration functions *********************************/ +void I2C_DeInit(I2C_TypeDef* I2Cx); +void I2C_Init(I2C_TypeDef* I2Cx, I2C_InitTypeDef* I2C_InitStruct); +void I2C_StructInit(I2C_InitTypeDef* I2C_InitStruct); +void I2C_Cmd(I2C_TypeDef* I2Cx, FunctionalState NewState); +void I2C_SoftwareResetCmd(I2C_TypeDef* I2Cx); +void I2C_ITConfig(I2C_TypeDef* I2Cx, uint32_t I2C_IT, FunctionalState NewState); +void I2C_StretchClockCmd(I2C_TypeDef* I2Cx, FunctionalState NewState); +void I2C_StopModeCmd(I2C_TypeDef* I2Cx, FunctionalState NewState); +void I2C_DualAddressCmd(I2C_TypeDef* I2Cx, FunctionalState NewState); +void I2C_OwnAddress2Config(I2C_TypeDef* I2Cx, uint16_t Address, uint8_t Mask); +void I2C_GeneralCallCmd(I2C_TypeDef* I2Cx, FunctionalState NewState); +void I2C_SlaveByteControlCmd(I2C_TypeDef* I2Cx, FunctionalState NewState); +void I2C_SlaveAddressConfig(I2C_TypeDef* I2Cx, uint16_t Address); +void I2C_10BitAddressingModeCmd(I2C_TypeDef* I2Cx, FunctionalState NewState); + +/* Communications handling functions ******************************************/ +void I2C_AutoEndCmd(I2C_TypeDef* I2Cx, FunctionalState NewState); +void I2C_ReloadCmd(I2C_TypeDef* I2Cx, FunctionalState NewState); +void I2C_NumberOfBytesConfig(I2C_TypeDef* I2Cx, uint8_t Number_Bytes); +void I2C_MasterRequestConfig(I2C_TypeDef* I2Cx, uint16_t I2C_Direction); +void I2C_GenerateSTART(I2C_TypeDef* I2Cx, FunctionalState NewState); +void I2C_GenerateSTOP(I2C_TypeDef* I2Cx, FunctionalState NewState); +void I2C_10BitAddressHeaderCmd(I2C_TypeDef* I2Cx, FunctionalState NewState); +void I2C_AcknowledgeConfig(I2C_TypeDef* I2Cx, FunctionalState NewState); +uint8_t I2C_GetAddressMatched(I2C_TypeDef* I2Cx); +uint16_t I2C_GetTransferDirection(I2C_TypeDef* I2Cx); +void I2C_TransferHandling(I2C_TypeDef* I2Cx, uint16_t Address, uint8_t Number_Bytes, uint32_t ReloadEndMode, uint32_t StartStopMode); + +/* SMBUS management functions ************************************************/ +void I2C_SMBusAlertCmd(I2C_TypeDef* I2Cx, FunctionalState NewState); +void I2C_ClockTimeoutCmd(I2C_TypeDef* I2Cx, FunctionalState NewState); +void I2C_ExtendedClockTimeoutCmd(I2C_TypeDef* I2Cx, FunctionalState NewState); +void I2C_IdleClockTimeoutCmd(I2C_TypeDef* I2Cx, FunctionalState NewState); +void I2C_TimeoutAConfig(I2C_TypeDef* I2Cx, uint16_t Timeout); +void I2C_TimeoutBConfig(I2C_TypeDef* I2Cx, uint16_t Timeout); +void I2C_CalculatePEC(I2C_TypeDef* I2Cx, FunctionalState NewState); +void I2C_PECRequestCmd(I2C_TypeDef* I2Cx, FunctionalState NewState); +uint8_t I2C_GetPEC(I2C_TypeDef* I2Cx); + +/* I2C registers management functions *****************************************/ +uint32_t I2C_ReadRegister(I2C_TypeDef* I2Cx, uint8_t I2C_Register); + +/* Data transfers management functions ****************************************/ +void I2C_SendData(I2C_TypeDef* I2Cx, uint8_t Data); +uint8_t I2C_ReceiveData(I2C_TypeDef* I2Cx); + +/* DMA transfers management functions *****************************************/ +void I2C_DMACmd(I2C_TypeDef* I2Cx, uint32_t I2C_DMAReq, FunctionalState NewState); + +/* Interrupts and flags management functions **********************************/ +FlagStatus I2C_GetFlagStatus(I2C_TypeDef* I2Cx, uint32_t I2C_FLAG); +void I2C_ClearFlag(I2C_TypeDef* I2Cx, uint32_t I2C_FLAG); +ITStatus I2C_GetITStatus(I2C_TypeDef* I2Cx, uint32_t I2C_IT); +void I2C_ClearITPendingBit(I2C_TypeDef* I2Cx, uint32_t I2C_IT); + + +#ifdef __cplusplus +} +#endif + +#endif /*__STM32F30x_I2C_H */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_iwdg.h b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_iwdg.h new file mode 100755 index 0000000000..519bda9f1e --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_iwdg.h @@ -0,0 +1,153 @@ +/** + ****************************************************************************** + * @file stm32f30x_iwdg.h + * @author MCD Application Team + * @version V1.2.3 + * @date 10-July-2015 + * @brief This file contains all the functions prototypes for the IWDG + * firmware library. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F30x_IWDG_H +#define __STM32F30x_IWDG_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f30x.h" + +/** @addtogroup STM32F30x_StdPeriph_Driver + * @{ + */ + +/** @addtogroup IWDG + * @{ + */ + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +/** @defgroup IWDG_Exported_Constants + * @{ + */ + +/** @defgroup IWDG_WriteAccess + * @{ + */ + +#define IWDG_WriteAccess_Enable ((uint16_t)0x5555) +#define IWDG_WriteAccess_Disable ((uint16_t)0x0000) +#define IS_IWDG_WRITE_ACCESS(ACCESS) (((ACCESS) == IWDG_WriteAccess_Enable) || \ + ((ACCESS) == IWDG_WriteAccess_Disable)) +/** + * @} + */ + +/** @defgroup IWDG_prescaler + * @{ + */ + +#define IWDG_Prescaler_4 ((uint8_t)0x00) +#define IWDG_Prescaler_8 ((uint8_t)0x01) +#define IWDG_Prescaler_16 ((uint8_t)0x02) +#define IWDG_Prescaler_32 ((uint8_t)0x03) +#define IWDG_Prescaler_64 ((uint8_t)0x04) +#define IWDG_Prescaler_128 ((uint8_t)0x05) +#define IWDG_Prescaler_256 ((uint8_t)0x06) +#define IS_IWDG_PRESCALER(PRESCALER) (((PRESCALER) == IWDG_Prescaler_4) || \ + ((PRESCALER) == IWDG_Prescaler_8) || \ + ((PRESCALER) == IWDG_Prescaler_16) || \ + ((PRESCALER) == IWDG_Prescaler_32) || \ + ((PRESCALER) == IWDG_Prescaler_64) || \ + ((PRESCALER) == IWDG_Prescaler_128)|| \ + ((PRESCALER) == IWDG_Prescaler_256)) +/** + * @} + */ + +/** @defgroup IWDG_Flag + * @{ + */ + +#define IWDG_FLAG_PVU ((uint16_t)0x0001) +#define IWDG_FLAG_RVU ((uint16_t)0x0002) +#define IWDG_FLAG_WVU ((uint16_t)0x0002) +#define IS_IWDG_FLAG(FLAG) (((FLAG) == IWDG_FLAG_PVU) || ((FLAG) == IWDG_FLAG_RVU) || \ + ((FLAG) == IWDG_FLAG_WVU)) +/** + * @} + */ + +/** @defgroup IWDG_Reload_Value + * @{ + */ +#define IS_IWDG_RELOAD(RELOAD) ((RELOAD) <= 0xFFF) + +/** + * @} + */ + +/** @defgroup IWDG_CounterWindow_Value + * @{ + */ +#define IS_IWDG_WINDOW_VALUE(VALUE) ((VALUE) <= 0xFFF) +/** + * @} + */ + +/** + * @} + */ + +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions --------------------------------------------------------*/ + +/* Prescaler and Counter configuration functions ******************************/ +void IWDG_WriteAccessCmd(uint16_t IWDG_WriteAccess); +void IWDG_SetPrescaler(uint8_t IWDG_Prescaler); +void IWDG_SetReload(uint16_t Reload); +void IWDG_ReloadCounter(void); +void IWDG_SetWindowValue(uint16_t WindowValue); + +/* IWDG activation function ***************************************************/ +void IWDG_Enable(void); + +/* Flag management function ***************************************************/ +FlagStatus IWDG_GetFlagStatus(uint16_t IWDG_FLAG); + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F30x_IWDG_H */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_misc.h b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_misc.h new file mode 100755 index 0000000000..7d66b7e0c6 --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_misc.h @@ -0,0 +1,204 @@ +/** + ****************************************************************************** + * @file stm32f30x_misc.h + * @author MCD Application Team + * @version V1.2.3 + * @date 10-July-2015 + * @brief This file contains all the functions prototypes for the miscellaneous + * firmware library functions (add-on to CMSIS functions). + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F30x_MISC_H +#define __STM32F30x_MISC_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f30x.h" + +/** @addtogroup STM32F30x_StdPeriph_Driver + * @{ + */ + +/** @addtogroup MISC + * @{ + */ + +/* Exported types ------------------------------------------------------------*/ + +/** + * @brief NVIC Init Structure definition + */ + +typedef struct +{ + uint8_t NVIC_IRQChannel; /*!< Specifies the IRQ channel to be enabled or disabled. + This parameter can be a value of @ref IRQn_Type (For + the complete STM32 Devices IRQ Channels list, please + refer to stm32f30x.h file) */ + + uint8_t NVIC_IRQChannelPreemptionPriority; /*!< Specifies the pre-emption priority for the IRQ channel + specified in NVIC_IRQChannel. This parameter can be a value + between 0 and 15. + A lower priority value indicates a higher priority */ + + + uint8_t NVIC_IRQChannelSubPriority; /*!< Specifies the subpriority level for the IRQ channel specified + in NVIC_IRQChannel. This parameter can be a value + between 0 and 15. + A lower priority value indicates a higher priority */ + + FunctionalState NVIC_IRQChannelCmd; /*!< Specifies whether the IRQ channel defined in NVIC_IRQChannel + will be enabled or disabled. + This parameter can be set either to ENABLE or DISABLE */ +} NVIC_InitTypeDef; + +/** + * +@verbatim + The table below gives the allowed values of the pre-emption priority and subpriority according + to the Priority Grouping configuration performed by NVIC_PriorityGroupConfig function + ============================================================================================================================ + NVIC_PriorityGroup | NVIC_IRQChannelPreemptionPriority | NVIC_IRQChannelSubPriority | Description + ============================================================================================================================ + NVIC_PriorityGroup_0 | 0 | 0-15 | 0 bits for pre-emption priority + | | | 4 bits for subpriority + ---------------------------------------------------------------------------------------------------------------------------- + NVIC_PriorityGroup_1 | 0-1 | 0-7 | 1 bits for pre-emption priority + | | | 3 bits for subpriority + ---------------------------------------------------------------------------------------------------------------------------- + NVIC_PriorityGroup_2 | 0-3 | 0-3 | 2 bits for pre-emption priority + | | | 2 bits for subpriority + ---------------------------------------------------------------------------------------------------------------------------- + NVIC_PriorityGroup_3 | 0-7 | 0-1 | 3 bits for pre-emption priority + | | | 1 bits for subpriority + ---------------------------------------------------------------------------------------------------------------------------- + NVIC_PriorityGroup_4 | 0-15 | 0 | 4 bits for pre-emption priority + | | | 0 bits for subpriority + ============================================================================================================================ +@endverbatim +*/ + +/* Exported constants --------------------------------------------------------*/ + +/** @defgroup MISC_Exported_Constants + * @{ + */ + +/** @defgroup MISC_Vector_Table_Base + * @{ + */ + +#define NVIC_VectTab_RAM ((uint32_t)0x20000000) +#define NVIC_VectTab_FLASH ((uint32_t)0x08000000) +#define IS_NVIC_VECTTAB(VECTTAB) (((VECTTAB) == NVIC_VectTab_RAM) || \ + ((VECTTAB) == NVIC_VectTab_FLASH)) +/** + * @} + */ + +/** @defgroup MISC_System_Low_Power + * @{ + */ + +#define NVIC_LP_SEVONPEND ((uint8_t)0x10) +#define NVIC_LP_SLEEPDEEP ((uint8_t)0x04) +#define NVIC_LP_SLEEPONEXIT ((uint8_t)0x02) +#define IS_NVIC_LP(LP) (((LP) == NVIC_LP_SEVONPEND) || \ + ((LP) == NVIC_LP_SLEEPDEEP) || \ + ((LP) == NVIC_LP_SLEEPONEXIT)) +/** + * @} + */ + +/** @defgroup MISC_Preemption_Priority_Group + * @{ + */ + +#define NVIC_PriorityGroup_0 ((uint32_t)0x700) /*!< 0 bits for pre-emption priority + 4 bits for subpriority */ +#define NVIC_PriorityGroup_1 ((uint32_t)0x600) /*!< 1 bits for pre-emption priority + 3 bits for subpriority */ +#define NVIC_PriorityGroup_2 ((uint32_t)0x500) /*!< 2 bits for pre-emption priority + 2 bits for subpriority */ +#define NVIC_PriorityGroup_3 ((uint32_t)0x400) /*!< 3 bits for pre-emption priority + 1 bits for subpriority */ +#define NVIC_PriorityGroup_4 ((uint32_t)0x300) /*!< 4 bits for pre-emption priority + 0 bits for subpriority */ + +#define IS_NVIC_PRIORITY_GROUP(GROUP) (((GROUP) == NVIC_PriorityGroup_0) || \ + ((GROUP) == NVIC_PriorityGroup_1) || \ + ((GROUP) == NVIC_PriorityGroup_2) || \ + ((GROUP) == NVIC_PriorityGroup_3) || \ + ((GROUP) == NVIC_PriorityGroup_4)) + +#define IS_NVIC_PREEMPTION_PRIORITY(PRIORITY) ((PRIORITY) < 0x10) + +#define IS_NVIC_SUB_PRIORITY(PRIORITY) ((PRIORITY) < 0x10) + +#define IS_NVIC_OFFSET(OFFSET) ((OFFSET) < 0x000FFFFF) + +/** + * @} + */ + +/** @defgroup MISC_SysTick_clock_source + */ + +#define SysTick_CLKSource_HCLK_Div8 ((uint32_t)0xFFFFFFFB) +#define SysTick_CLKSource_HCLK ((uint32_t)0x00000004) +#define IS_SYSTICK_CLK_SOURCE(SOURCE) (((SOURCE) == SysTick_CLKSource_HCLK) || \ + ((SOURCE) == SysTick_CLKSource_HCLK_Div8)) +/** + * @} + */ + +/** + * @} + */ + +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions --------------------------------------------------------*/ + +void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup); +void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct); +void NVIC_SetVectorTable(uint32_t NVIC_VectTab, uint32_t Offset); +void NVIC_SystemLPConfig(uint8_t LowPowerMode, FunctionalState NewState); +void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource); + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F30x_MISC_H */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_opamp.h b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_opamp.h new file mode 100755 index 0000000000..5edd6060ac --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_opamp.h @@ -0,0 +1,277 @@ +/** + ****************************************************************************** + * @file stm32f30x_opamp.h + * @author MCD Application Team + * @version V1.2.3 + * @date 10-July-2015 + * @brief This file contains all the functions prototypes for the operational + * amplifiers (OPAMP) firmware library. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F30x_OPAMP_H +#define __STM32F30x_OPAMP_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f30x.h" + +/** @addtogroup STM32F30x_StdPeriph_Driver + * @{ + */ + +/** @addtogroup OPAMP + * @{ + */ + +/* Exported types ------------------------------------------------------------*/ + +/** + * @brief OPAMP Init structure definition + */ + +typedef struct +{ + + uint32_t OPAMP_InvertingInput; /*!< Selects the inverting input of the operational amplifier. + This parameter can be a value of @ref OPAMP_InvertingInput */ + + uint32_t OPAMP_NonInvertingInput; /*!< Selects the non inverting input of the operational amplifier. + This parameter can be a value of @ref OPAMP_NonInvertingInput */ + +}OPAMP_InitTypeDef; + +/* Exported constants --------------------------------------------------------*/ + +/** @defgroup OPAMP_Exported_Constants + * @{ + */ + +/** @defgroup OPAMP_Selection + * @{ + */ + +#define OPAMP_Selection_OPAMP1 ((uint32_t)0x00000000) /*!< OPAMP1 Selection */ +#define OPAMP_Selection_OPAMP2 ((uint32_t)0x00000004) /*!< OPAMP2 Selection */ +#define OPAMP_Selection_OPAMP3 ((uint32_t)0x00000008) /*!< OPAMP3 Selection */ +#define OPAMP_Selection_OPAMP4 ((uint32_t)0x0000000C) /*!< OPAMP4 Selection */ + +#define IS_OPAMP_ALL_PERIPH(PERIPH) (((PERIPH) == OPAMP_Selection_OPAMP1) || \ + ((PERIPH) == OPAMP_Selection_OPAMP2) || \ + ((PERIPH) == OPAMP_Selection_OPAMP3) || \ + ((PERIPH) == OPAMP_Selection_OPAMP4)) + +/** + * @} + */ + +/** @defgroup OPAMP_InvertingInput + * @{ + */ + +#define OPAMP_InvertingInput_IO1 ((uint32_t)0x00000000) /*!< IO1 (PC5 for OPAMP1 and OPAMP2, PB10 for OPAMP3 and OPAMP4) + connected to OPAMPx inverting input */ +#define OPAMP_InvertingInput_IO2 OPAMP_CSR_VMSEL_0 /*!< IO2 (PA3 for OPAMP1, PA5 for OPAMP2, PB2 for OPAMP3, PD8 for OPAMP4) + connected to OPAMPx inverting input */ +#define OPAMP_InvertingInput_PGA OPAMP_CSR_VMSEL_1 /*!< Resistor feedback output connected to OPAMPx inverting input (PGA mode) */ +#define OPAMP_InvertingInput_Vout OPAMP_CSR_VMSEL /*!< Vout connected to OPAMPx inverting input (follower mode) */ + +#define IS_OPAMP_INVERTING_INPUT(INPUT) (((INPUT) == OPAMP_InvertingInput_IO1) || \ + ((INPUT) == OPAMP_InvertingInput_IO2) || \ + ((INPUT) == OPAMP_InvertingInput_PGA) || \ + ((INPUT) == OPAMP_InvertingInput_Vout)) +/** + * @} + */ + +/** @defgroup OPAMP_NonInvertingInput + * @{ + */ + +#define OPAMP_NonInvertingInput_IO1 ((uint32_t)0x00000000) /*!< IO1 (PA7 for OPAMP1, PD14 for OPAMP2, PB13 for OPAMP3, PD11 for OPAMP4) + connected to OPAMPx non inverting input */ +#define OPAMP_NonInvertingInput_IO2 OPAMP_CSR_VPSEL_0 /*!< IO2 (PA5 for OPAMP1, PB14 for OPAMP2, PA5 for OPAMP3, PB11 for OPAMP4) + connected to OPAMPx non inverting input */ +#define OPAMP_NonInvertingInput_IO3 OPAMP_CSR_VPSEL_1 /*!< IO3 (PA3 for OPAMP1, PB0 for OPAMP2, PA1 for OPAMP3, PA4 for OPAMP4) + connected to OPAMPx non inverting input */ +#define OPAMP_NonInvertingInput_IO4 OPAMP_CSR_VPSEL /*!< IO4 (PA1 for OPAMP1, PA7 for OPAMP2, PB0 for OPAMP3, PB13 for OPAMP4) + connected to OPAMPx non inverting input */ + +#define IS_OPAMP_NONINVERTING_INPUT(INPUT) (((INPUT) == OPAMP_NonInvertingInput_IO1) || \ + ((INPUT) == OPAMP_NonInvertingInput_IO2) || \ + ((INPUT) == OPAMP_NonInvertingInput_IO3) || \ + ((INPUT) == OPAMP_NonInvertingInput_IO4)) +/** + * @} + */ + +/** @defgroup OPAMP_PGAGain_Config + * @{ + */ + +#define OPAMP_OPAMP_PGAGain_2 ((uint32_t)0x00000000) +#define OPAMP_OPAMP_PGAGain_4 OPAMP_CSR_PGGAIN_0 +#define OPAMP_OPAMP_PGAGain_8 OPAMP_CSR_PGGAIN_1 +#define OPAMP_OPAMP_PGAGain_16 ((uint32_t)0x0000C000) + +#define IS_OPAMP_PGAGAIN(GAIN) (((GAIN) == OPAMP_OPAMP_PGAGain_2) || \ + ((GAIN) == OPAMP_OPAMP_PGAGain_4) || \ + ((GAIN) == OPAMP_OPAMP_PGAGain_8) || \ + ((GAIN) == OPAMP_OPAMP_PGAGain_16)) +/** + * @} + */ + +/** @defgroup OPAMP_PGAConnect_Config + * @{ + */ + +#define OPAMP_PGAConnect_No ((uint32_t)0x00000000) +#define OPAMP_PGAConnect_IO1 OPAMP_CSR_PGGAIN_3 +#define OPAMP_PGAConnect_IO2 ((uint32_t)0x00030000) + +#define IS_OPAMP_PGACONNECT(CONNECT) (((CONNECT) == OPAMP_PGAConnect_No) || \ + ((CONNECT) == OPAMP_PGAConnect_IO1) || \ + ((CONNECT) == OPAMP_PGAConnect_IO2)) +/** + * @} + */ + +/** @defgroup OPAMP_SecondaryInvertingInput + * @{ + */ + +#define IS_OPAMP_SECONDARY_INVINPUT(INVINPUT) (((INVINPUT) == OPAMP_InvertingInput_IO1) || \ + ((INVINPUT) == OPAMP_InvertingInput_IO2)) +/** + * @} + */ + +/** @defgroup OPAMP_Input + * @{ + */ + +#define OPAMP_Input_Inverting ((uint32_t)0x00000018) /*!< Inverting input */ +#define OPAMP_Input_NonInverting ((uint32_t)0x00000013) /*!< Non inverting input */ + +#define IS_OPAMP_INPUT(INPUT) (((INPUT) == OPAMP_Input_Inverting) || \ + ((INPUT) == OPAMP_Input_NonInverting)) + +/** + * @} + */ + +/** @defgroup OPAMP_Vref + * @{ + */ + +#define OPAMP_Vref_3VDDA ((uint32_t)0x00000000) /*!< OPMAP Vref = 3.3% VDDA */ +#define OPAMP_Vref_10VDDA OPAMP_CSR_CALSEL_0 /*!< OPMAP Vref = 10% VDDA */ +#define OPAMP_Vref_50VDDA OPAMP_CSR_CALSEL_1 /*!< OPMAP Vref = 50% VDDA */ +#define OPAMP_Vref_90VDDA OPAMP_CSR_CALSEL /*!< OPMAP Vref = 90% VDDA */ + +#define IS_OPAMP_VREF(VREF) (((VREF) == OPAMP_Vref_3VDDA) || \ + ((VREF) == OPAMP_Vref_10VDDA) || \ + ((VREF) == OPAMP_Vref_50VDDA) || \ + ((VREF) == OPAMP_Vref_90VDDA)) + +/** + * @} + */ + +/** @defgroup OPAMP_Trimming + */ + +#define OPAMP_Trimming_Factory ((uint32_t)0x00000000) /*!< Factory trimming */ +#define OPAMP_Trimming_User OPAMP_CSR_USERTRIM /*!< User trimming */ + +#define IS_OPAMP_TRIMMING(TRIMMING) (((TRIMMING) == OPAMP_Trimming_Factory) || \ + ((TRIMMING) == OPAMP_Trimming_User)) + +/** + * @} + */ + +/** @defgroup OPAMP_TrimValue + * @{ + */ + +#define IS_OPAMP_TRIMMINGVALUE(VALUE) ((VALUE) <= 0x0000001F) /*!< Trimming value */ + +/** + * @} + */ + +/** @defgroup OPAMP_OutputLevel + * @{ + */ + +#define OPAMP_OutputLevel_High OPAMP_CSR_OUTCAL +#define OPAMP_OutputLevel_Low ((uint32_t)0x00000000) + +/** + * @} + */ + +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions ------------------------------------------------------- */ + +/* Function used to set the OPAMP configuration to the default reset state ***/ +void OPAMP_DeInit(uint32_t OPAMP_Selection); + +/* Initialization and Configuration functions *********************************/ +void OPAMP_Init(uint32_t OPAMP_Selection, OPAMP_InitTypeDef* OPAMP_InitStruct); +void OPAMP_StructInit(OPAMP_InitTypeDef* OPAMP_InitStruct); +void OPAMP_PGAConfig(uint32_t OPAMP_Selection, uint32_t OPAMP_PGAGain, uint32_t OPAMP_PGAConnect); +void OPAMP_VrefConfig(uint32_t OPAMP_Selection, uint32_t OPAMP_Vref); +void OPAMP_VrefConnectADCCmd(uint32_t OPAMP_Selection, FunctionalState NewState); +void OPAMP_TimerControlledMuxConfig(uint32_t OPAMP_Selection, OPAMP_InitTypeDef* OPAMP_InitStruct); +void OPAMP_TimerControlledMuxCmd(uint32_t OPAMP_Selection, FunctionalState NewState); +void OPAMP_Cmd(uint32_t OPAMP_Selection, FunctionalState NewState); +uint32_t OPAMP_GetOutputLevel(uint32_t OPAMP_Selection); + +/* Calibration functions ******************************************************/ +void OPAMP_VrefConnectNonInvertingInput(uint32_t OPAMP_Selection, FunctionalState NewState); +void OPAMP_OffsetTrimModeSelect(uint32_t OPAMP_Selection, uint32_t OPAMP_Trimming); +void OPAMP_OffsetTrimConfig(uint32_t OPAMP_Selection, uint32_t OPAMP_Input, uint32_t OPAMP_TrimValue); +void OPAMP_StartCalibration(uint32_t OPAMP_Selection, FunctionalState NewState); + +/* OPAMP configuration locking function ***************************************/ +void OPAMP_LockConfig(uint32_t OPAMP_Selection); + +#ifdef __cplusplus +} +#endif + +#endif /*__STM32F30x_OPAMP_H */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_pwr.h b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_pwr.h new file mode 100755 index 0000000000..dc96dedf7b --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_pwr.h @@ -0,0 +1,187 @@ +/** + ****************************************************************************** + * @file stm32f30x_pwr.h + * @author MCD Application Team + * @version V1.2.3 + * @date 10-July-2015 + * @brief This file contains all the functions prototypes for the PWR firmware + * library. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F30x_PWR_H +#define __STM32F30x_PWR_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f30x.h" + +/** @addtogroup STM32F30x_StdPeriph_Driver + * @{ + */ + +/** @addtogroup PWR + * @{ + */ + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +/** @defgroup PWR_Exported_Constants + * @{ + */ + +/** @defgroup PWR_PVD_detection_level + * @{ + */ + +#define PWR_PVDLevel_0 PWR_CR_PLS_LEV0 +#define PWR_PVDLevel_1 PWR_CR_PLS_LEV1 +#define PWR_PVDLevel_2 PWR_CR_PLS_LEV2 +#define PWR_PVDLevel_3 PWR_CR_PLS_LEV3 +#define PWR_PVDLevel_4 PWR_CR_PLS_LEV4 +#define PWR_PVDLevel_5 PWR_CR_PLS_LEV5 +#define PWR_PVDLevel_6 PWR_CR_PLS_LEV6 +#define PWR_PVDLevel_7 PWR_CR_PLS_LEV7 + +#define IS_PWR_PVD_LEVEL(LEVEL) (((LEVEL) == PWR_PVDLevel_0) || ((LEVEL) == PWR_PVDLevel_1)|| \ + ((LEVEL) == PWR_PVDLevel_2) || ((LEVEL) == PWR_PVDLevel_3)|| \ + ((LEVEL) == PWR_PVDLevel_4) || ((LEVEL) == PWR_PVDLevel_5)|| \ + ((LEVEL) == PWR_PVDLevel_6) || ((LEVEL) == PWR_PVDLevel_7)) +/** + * @} + */ + +/** @defgroup PWR_WakeUp_Pins + * @{ + */ + +#define PWR_WakeUpPin_1 PWR_CSR_EWUP1 +#define PWR_WakeUpPin_2 PWR_CSR_EWUP2 +#define PWR_WakeUpPin_3 PWR_CSR_EWUP3 +#define IS_PWR_WAKEUP_PIN(PIN) (((PIN) == PWR_WakeUpPin_1) || \ + ((PIN) == PWR_WakeUpPin_2) || \ + ((PIN) == PWR_WakeUpPin_3)) +/** + * @} + */ + + +/** @defgroup PWR_Regulator_state_is_Sleep_STOP_mode + * @{ + */ + +#define PWR_Regulator_ON ((uint32_t)0x00000000) +#define PWR_Regulator_LowPower PWR_CR_LPSDSR +#define IS_PWR_REGULATOR(REGULATOR) (((REGULATOR) == PWR_Regulator_ON) || \ + ((REGULATOR) == PWR_Regulator_LowPower)) +/** + * @} + */ + +/** @defgroup PWR_SLEEP_mode_entry + * @{ + */ + +#define PWR_SLEEPEntry_WFI ((uint8_t)0x01) +#define PWR_SLEEPEntry_WFE ((uint8_t)0x02) +#define IS_PWR_SLEEP_ENTRY(ENTRY) (((ENTRY) == PWR_SLEEPEntry_WFI) || ((ENTRY) == PWR_SLEEPEntry_WFE)) + +/** + * @} + */ + +/** @defgroup PWR_STOP_mode_entry + * @{ + */ + +#define PWR_STOPEntry_WFI ((uint8_t)0x01) +#define PWR_STOPEntry_WFE ((uint8_t)0x02) +#define IS_PWR_STOP_ENTRY(ENTRY) (((ENTRY) == PWR_STOPEntry_WFI) || ((ENTRY) == PWR_STOPEntry_WFE)) + +/** + * @} + */ + +/** @defgroup PWR_Flag + * @{ + */ + +#define PWR_FLAG_WU PWR_CSR_WUF +#define PWR_FLAG_SB PWR_CSR_SBF +#define PWR_FLAG_PVDO PWR_CSR_PVDO +#define PWR_FLAG_VREFINTRDY PWR_CSR_VREFINTRDYF + +#define IS_PWR_GET_FLAG(FLAG) (((FLAG) == PWR_FLAG_WU) || ((FLAG) == PWR_FLAG_SB) || \ + ((FLAG) == PWR_FLAG_PVDO) || ((FLAG) == PWR_FLAG_VREFINTRDY)) + +#define IS_PWR_CLEAR_FLAG(FLAG) (((FLAG) == PWR_FLAG_WU) || ((FLAG) == PWR_FLAG_SB)) +/** + * @} + */ + +/** + * @} + */ + +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions ------------------------------------------------------- */ + +/* Function used to set the PWR configuration to the default reset state ******/ +void PWR_DeInit(void); + +/* Backup Domain Access function **********************************************/ +void PWR_BackupAccessCmd(FunctionalState NewState); + +/* PVD configuration functions ************************************************/ +void PWR_PVDLevelConfig(uint32_t PWR_PVDLevel); +void PWR_PVDCmd(FunctionalState NewState); + +/* WakeUp pins configuration functions ****************************************/ +void PWR_WakeUpPinCmd(uint32_t PWR_WakeUpPin, FunctionalState NewState); + +/* Low Power modes configuration functions ************************************/ +void PWR_EnterSleepMode(uint8_t PWR_SLEEPEntry); +void PWR_EnterSTOPMode(uint32_t PWR_Regulator, uint8_t PWR_STOPEntry); +void PWR_EnterSTANDBYMode(void); + +/* Flags management functions *************************************************/ +FlagStatus PWR_GetFlagStatus(uint32_t PWR_FLAG); +void PWR_ClearFlag(uint32_t PWR_FLAG); + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F30x_PWR_H */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_rcc.h b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_rcc.h new file mode 100755 index 0000000000..13391f6636 --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_rcc.h @@ -0,0 +1,731 @@ +/** + ****************************************************************************** + * @file stm32f30x_rcc.h + * @author MCD Application Team + * @version V1.2.3 + * @date 10-July-2015 + * @brief This file contains all the functions prototypes for the RCC + * firmware library. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F30x_RCC_H +#define __STM32F30x_RCC_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f30x.h" + +/** @addtogroup STM32F30x_StdPeriph_Driver + * @{ + */ + +/** @addtogroup RCC + * @{ + */ + +/* Exported types ------------------------------------------------------------*/ + +typedef struct +{ + uint32_t SYSCLK_Frequency; + uint32_t HCLK_Frequency; + uint32_t PCLK1_Frequency; + uint32_t PCLK2_Frequency; + uint32_t ADC12CLK_Frequency; + uint32_t ADC34CLK_Frequency; + uint32_t I2C1CLK_Frequency; + uint32_t I2C2CLK_Frequency; + uint32_t I2C3CLK_Frequency; + uint32_t TIM1CLK_Frequency; + uint32_t HRTIM1CLK_Frequency; + uint32_t TIM8CLK_Frequency; + uint32_t TIM2CLK_Frequency; + uint32_t TIM3CLK_Frequency; + uint32_t USART1CLK_Frequency; + uint32_t USART2CLK_Frequency; + uint32_t USART3CLK_Frequency; + uint32_t UART4CLK_Frequency; + uint32_t UART5CLK_Frequency; + uint32_t TIM15CLK_Frequency; + uint32_t TIM16CLK_Frequency; + uint32_t TIM17CLK_Frequency; + uint32_t TIM20CLK_Frequency; +}RCC_ClocksTypeDef; + +/* Exported constants --------------------------------------------------------*/ + +/** @defgroup RCC_Exported_Constants + * @{ + */ + +/** @defgroup RCC_HSE_configuration + * @{ + */ + +#define RCC_HSE_OFF ((uint8_t)0x00) +#define RCC_HSE_ON ((uint8_t)0x01) +#define RCC_HSE_Bypass ((uint8_t)0x05) +#define IS_RCC_HSE(HSE) (((HSE) == RCC_HSE_OFF) || ((HSE) == RCC_HSE_ON) || \ + ((HSE) == RCC_HSE_Bypass)) + +/** + * @} + */ + +/** @defgroup RCC_PLL_Clock_Source + * @{ + */ +#define RCC_PLLSource_HSI RCC_CFGR_PLLSRC_HSI_PREDIV /*!< Only applicable for STM32F303xE devices */ +#define RCC_PLLSource_HSI_Div2 RCC_CFGR_PLLSRC_HSI_Div2 +#define RCC_PLLSource_PREDIV1 RCC_CFGR_PLLSRC_PREDIV1 + +#define IS_RCC_PLL_SOURCE(SOURCE) (((SOURCE) == RCC_PLLSource_HSI_Div2) || \ + ((SOURCE) == RCC_PLLSource_PREDIV1)|| \ + ((SOURCE) == RCC_PLLSource_HSI)) + +/** + * @} + */ + +/** @defgroup RCC_PLL_Multiplication_Factor + * @{ + */ + +#define RCC_PLLMul_2 RCC_CFGR_PLLMULL2 +#define RCC_PLLMul_3 RCC_CFGR_PLLMULL3 +#define RCC_PLLMul_4 RCC_CFGR_PLLMULL4 +#define RCC_PLLMul_5 RCC_CFGR_PLLMULL5 +#define RCC_PLLMul_6 RCC_CFGR_PLLMULL6 +#define RCC_PLLMul_7 RCC_CFGR_PLLMULL7 +#define RCC_PLLMul_8 RCC_CFGR_PLLMULL8 +#define RCC_PLLMul_9 RCC_CFGR_PLLMULL9 +#define RCC_PLLMul_10 RCC_CFGR_PLLMULL10 +#define RCC_PLLMul_11 RCC_CFGR_PLLMULL11 +#define RCC_PLLMul_12 RCC_CFGR_PLLMULL12 +#define RCC_PLLMul_13 RCC_CFGR_PLLMULL13 +#define RCC_PLLMul_14 RCC_CFGR_PLLMULL14 +#define RCC_PLLMul_15 RCC_CFGR_PLLMULL15 +#define RCC_PLLMul_16 RCC_CFGR_PLLMULL16 +#define IS_RCC_PLL_MUL(MUL) (((MUL) == RCC_PLLMul_2) || ((MUL) == RCC_PLLMul_3) || \ + ((MUL) == RCC_PLLMul_4) || ((MUL) == RCC_PLLMul_5) || \ + ((MUL) == RCC_PLLMul_6) || ((MUL) == RCC_PLLMul_7) || \ + ((MUL) == RCC_PLLMul_8) || ((MUL) == RCC_PLLMul_9) || \ + ((MUL) == RCC_PLLMul_10) || ((MUL) == RCC_PLLMul_11) || \ + ((MUL) == RCC_PLLMul_12) || ((MUL) == RCC_PLLMul_13) || \ + ((MUL) == RCC_PLLMul_14) || ((MUL) == RCC_PLLMul_15) || \ + ((MUL) == RCC_PLLMul_16)) +/** + * @} + */ + +/** @defgroup RCC_PREDIV1_division_factor + * @{ + */ +#define RCC_PREDIV1_Div1 RCC_CFGR2_PREDIV1_DIV1 +#define RCC_PREDIV1_Div2 RCC_CFGR2_PREDIV1_DIV2 +#define RCC_PREDIV1_Div3 RCC_CFGR2_PREDIV1_DIV3 +#define RCC_PREDIV1_Div4 RCC_CFGR2_PREDIV1_DIV4 +#define RCC_PREDIV1_Div5 RCC_CFGR2_PREDIV1_DIV5 +#define RCC_PREDIV1_Div6 RCC_CFGR2_PREDIV1_DIV6 +#define RCC_PREDIV1_Div7 RCC_CFGR2_PREDIV1_DIV7 +#define RCC_PREDIV1_Div8 RCC_CFGR2_PREDIV1_DIV8 +#define RCC_PREDIV1_Div9 RCC_CFGR2_PREDIV1_DIV9 +#define RCC_PREDIV1_Div10 RCC_CFGR2_PREDIV1_DIV10 +#define RCC_PREDIV1_Div11 RCC_CFGR2_PREDIV1_DIV11 +#define RCC_PREDIV1_Div12 RCC_CFGR2_PREDIV1_DIV12 +#define RCC_PREDIV1_Div13 RCC_CFGR2_PREDIV1_DIV13 +#define RCC_PREDIV1_Div14 RCC_CFGR2_PREDIV1_DIV14 +#define RCC_PREDIV1_Div15 RCC_CFGR2_PREDIV1_DIV15 +#define RCC_PREDIV1_Div16 RCC_CFGR2_PREDIV1_DIV16 + +#define IS_RCC_PREDIV1(PREDIV1) (((PREDIV1) == RCC_PREDIV1_Div1) || ((PREDIV1) == RCC_PREDIV1_Div2) || \ + ((PREDIV1) == RCC_PREDIV1_Div3) || ((PREDIV1) == RCC_PREDIV1_Div4) || \ + ((PREDIV1) == RCC_PREDIV1_Div5) || ((PREDIV1) == RCC_PREDIV1_Div6) || \ + ((PREDIV1) == RCC_PREDIV1_Div7) || ((PREDIV1) == RCC_PREDIV1_Div8) || \ + ((PREDIV1) == RCC_PREDIV1_Div9) || ((PREDIV1) == RCC_PREDIV1_Div10) || \ + ((PREDIV1) == RCC_PREDIV1_Div11) || ((PREDIV1) == RCC_PREDIV1_Div12) || \ + ((PREDIV1) == RCC_PREDIV1_Div13) || ((PREDIV1) == RCC_PREDIV1_Div14) || \ + ((PREDIV1) == RCC_PREDIV1_Div15) || ((PREDIV1) == RCC_PREDIV1_Div16)) +/** + * @} + */ + +/** @defgroup RCC_System_Clock_Source + * @{ + */ + +#define RCC_SYSCLKSource_HSI RCC_CFGR_SW_HSI +#define RCC_SYSCLKSource_HSE RCC_CFGR_SW_HSE +#define RCC_SYSCLKSource_PLLCLK RCC_CFGR_SW_PLL +#define IS_RCC_SYSCLK_SOURCE(SOURCE) (((SOURCE) == RCC_SYSCLKSource_HSI) || \ + ((SOURCE) == RCC_SYSCLKSource_HSE) || \ + ((SOURCE) == RCC_SYSCLKSource_PLLCLK)) +/** + * @} + */ + +/** @defgroup RCC_AHB_Clock_Source + * @{ + */ + +#define RCC_SYSCLK_Div1 RCC_CFGR_HPRE_DIV1 +#define RCC_SYSCLK_Div2 RCC_CFGR_HPRE_DIV2 +#define RCC_SYSCLK_Div4 RCC_CFGR_HPRE_DIV4 +#define RCC_SYSCLK_Div8 RCC_CFGR_HPRE_DIV8 +#define RCC_SYSCLK_Div16 RCC_CFGR_HPRE_DIV16 +#define RCC_SYSCLK_Div64 RCC_CFGR_HPRE_DIV64 +#define RCC_SYSCLK_Div128 RCC_CFGR_HPRE_DIV128 +#define RCC_SYSCLK_Div256 RCC_CFGR_HPRE_DIV256 +#define RCC_SYSCLK_Div512 RCC_CFGR_HPRE_DIV512 +#define IS_RCC_HCLK(HCLK) (((HCLK) == RCC_SYSCLK_Div1) || ((HCLK) == RCC_SYSCLK_Div2) || \ + ((HCLK) == RCC_SYSCLK_Div4) || ((HCLK) == RCC_SYSCLK_Div8) || \ + ((HCLK) == RCC_SYSCLK_Div16) || ((HCLK) == RCC_SYSCLK_Div64) || \ + ((HCLK) == RCC_SYSCLK_Div128) || ((HCLK) == RCC_SYSCLK_Div256) || \ + ((HCLK) == RCC_SYSCLK_Div512)) +/** + * @} + */ + +/** @defgroup RCC_APB1_APB2_clock_source + * @{ + */ + +#define RCC_HCLK_Div1 ((uint32_t)0x00000000) +#define RCC_HCLK_Div2 ((uint32_t)0x00000400) +#define RCC_HCLK_Div4 ((uint32_t)0x00000500) +#define RCC_HCLK_Div8 ((uint32_t)0x00000600) +#define RCC_HCLK_Div16 ((uint32_t)0x00000700) +#define IS_RCC_PCLK(PCLK) (((PCLK) == RCC_HCLK_Div1) || ((PCLK) == RCC_HCLK_Div2) || \ + ((PCLK) == RCC_HCLK_Div4) || ((PCLK) == RCC_HCLK_Div8) || \ + ((PCLK) == RCC_HCLK_Div16)) +/** + * @} + */ + +/** @defgroup RCC_ADC_clock_source + * @{ + */ + +/* ADC1 & ADC2 */ +#define RCC_ADC12PLLCLK_OFF ((uint32_t)0x00000000) +#define RCC_ADC12PLLCLK_Div1 ((uint32_t)0x00000100) +#define RCC_ADC12PLLCLK_Div2 ((uint32_t)0x00000110) +#define RCC_ADC12PLLCLK_Div4 ((uint32_t)0x00000120) +#define RCC_ADC12PLLCLK_Div6 ((uint32_t)0x00000130) +#define RCC_ADC12PLLCLK_Div8 ((uint32_t)0x00000140) +#define RCC_ADC12PLLCLK_Div10 ((uint32_t)0x00000150) +#define RCC_ADC12PLLCLK_Div12 ((uint32_t)0x00000160) +#define RCC_ADC12PLLCLK_Div16 ((uint32_t)0x00000170) +#define RCC_ADC12PLLCLK_Div32 ((uint32_t)0x00000180) +#define RCC_ADC12PLLCLK_Div64 ((uint32_t)0x00000190) +#define RCC_ADC12PLLCLK_Div128 ((uint32_t)0x000001A0) +#define RCC_ADC12PLLCLK_Div256 ((uint32_t)0x000001B0) + +/* ADC3 & ADC4 */ +#define RCC_ADC34PLLCLK_OFF ((uint32_t)0x10000000) +#define RCC_ADC34PLLCLK_Div1 ((uint32_t)0x10002000) +#define RCC_ADC34PLLCLK_Div2 ((uint32_t)0x10002200) +#define RCC_ADC34PLLCLK_Div4 ((uint32_t)0x10002400) +#define RCC_ADC34PLLCLK_Div6 ((uint32_t)0x10002600) +#define RCC_ADC34PLLCLK_Div8 ((uint32_t)0x10002800) +#define RCC_ADC34PLLCLK_Div10 ((uint32_t)0x10002A00) +#define RCC_ADC34PLLCLK_Div12 ((uint32_t)0x10002C00) +#define RCC_ADC34PLLCLK_Div16 ((uint32_t)0x10002E00) +#define RCC_ADC34PLLCLK_Div32 ((uint32_t)0x10003000) +#define RCC_ADC34PLLCLK_Div64 ((uint32_t)0x10003200) +#define RCC_ADC34PLLCLK_Div128 ((uint32_t)0x10003400) +#define RCC_ADC34PLLCLK_Div256 ((uint32_t)0x10003600) + +#define IS_RCC_ADCCLK(ADCCLK) (((ADCCLK) == RCC_ADC12PLLCLK_OFF) || ((ADCCLK) == RCC_ADC12PLLCLK_Div1) || \ + ((ADCCLK) == RCC_ADC12PLLCLK_Div2) || ((ADCCLK) == RCC_ADC12PLLCLK_Div4) || \ + ((ADCCLK) == RCC_ADC12PLLCLK_Div6) || ((ADCCLK) == RCC_ADC12PLLCLK_Div8) || \ + ((ADCCLK) == RCC_ADC12PLLCLK_Div10) || ((ADCCLK) == RCC_ADC12PLLCLK_Div12) || \ + ((ADCCLK) == RCC_ADC12PLLCLK_Div16) || ((ADCCLK) == RCC_ADC12PLLCLK_Div32) || \ + ((ADCCLK) == RCC_ADC12PLLCLK_Div64) || ((ADCCLK) == RCC_ADC12PLLCLK_Div128) || \ + ((ADCCLK) == RCC_ADC12PLLCLK_Div256) || ((ADCCLK) == RCC_ADC34PLLCLK_OFF) || \ + ((ADCCLK) == RCC_ADC34PLLCLK_Div1) || ((ADCCLK) == RCC_ADC34PLLCLK_Div2) || \ + ((ADCCLK) == RCC_ADC34PLLCLK_Div4) || ((ADCCLK) == RCC_ADC34PLLCLK_Div6) || \ + ((ADCCLK) == RCC_ADC34PLLCLK_Div8) || ((ADCCLK) == RCC_ADC34PLLCLK_Div10) || \ + ((ADCCLK) == RCC_ADC34PLLCLK_Div12) || ((ADCCLK) == RCC_ADC34PLLCLK_Div16) || \ + ((ADCCLK) == RCC_ADC34PLLCLK_Div32) || ((ADCCLK) == RCC_ADC34PLLCLK_Div64) || \ + ((ADCCLK) == RCC_ADC34PLLCLK_Div128) || ((ADCCLK) == RCC_ADC34PLLCLK_Div256)) + +/** + * @} + */ + +/** @defgroup RCC_TIM_clock_source + * @{ + */ + +#define RCC_TIM1CLK_PCLK ((uint32_t)0x00000000) +#define RCC_TIM1CLK_PLLCLK RCC_CFGR3_TIM1SW + +#define RCC_TIM8CLK_PCLK ((uint32_t)0x10000000) +#define RCC_TIM8CLK_PLLCLK ((uint32_t)0x10000200) + +#define RCC_TIM15CLK_PCLK ((uint32_t)0x20000000) +#define RCC_TIM15CLK_PLLCLK ((uint32_t)0x20000400) + +#define RCC_TIM16CLK_PCLK ((uint32_t)0x30000000) +#define RCC_TIM16CLK_PLLCLK ((uint32_t)0x30000800) + +#define RCC_TIM17CLK_PCLK ((uint32_t)0x40000000) +#define RCC_TIM17CLK_PLLCLK ((uint32_t)0x40002000) + +#define RCC_TIM20CLK_PCLK ((uint32_t)0x50000000) +#define RCC_TIM20CLK_PLLCLK ((uint32_t)0x50008000) + +#define RCC_TIM2CLK_PCLK ((uint32_t)0x60000000) +#define RCC_TIM2CLK_PLLCLK ((uint32_t)0x61000000) + +#define RCC_TIM3TIM4CLK_PCLK ((uint32_t)0x70000000) +#define RCC_TIM3TIM4CLK_PLLCLK ((uint32_t)0x72000000) + +#define IS_RCC_TIMCLK(TIMCLK) (((TIMCLK) == RCC_TIM1CLK_PCLK) || ((TIMCLK) == RCC_TIM1CLK_PLLCLK) || \ + ((TIMCLK) == RCC_TIM8CLK_PCLK) || ((TIMCLK) == RCC_TIM8CLK_PLLCLK) || \ + ((TIMCLK) == RCC_TIM15CLK_PCLK) || ((TIMCLK) == RCC_TIM15CLK_PLLCLK) || \ + ((TIMCLK) == RCC_TIM16CLK_PCLK) || ((TIMCLK) == RCC_TIM16CLK_PLLCLK) || \ + ((TIMCLK) == RCC_TIM17CLK_PCLK) || ((TIMCLK) == RCC_TIM17CLK_PLLCLK)|| \ + ((TIMCLK) == RCC_TIM20CLK_PCLK) || ((TIMCLK) == RCC_TIM20CLK_PLLCLK)|| \ + ((TIMCLK) == RCC_TIM2CLK_PCLK) || ((TIMCLK) == RCC_TIM2CLK_PLLCLK)|| \ + ((TIMCLK) == RCC_TIM3TIM4CLK_PCLK) || ((TIMCLK) == RCC_TIM3TIM4CLK_PLLCLK)) +/* legacy RCC_TIM_clock_source*/ +#define RCC_TIM1CLK_HCLK RCC_TIM1CLK_PCLK +#define RCC_TIM8CLK_HCLK RCC_TIM8CLK_PCLK +#define RCC_TIM15CLK_HCLK RCC_TIM15CLK_PCLK +#define RCC_TIM16CLK_HCLK RCC_TIM16CLK_PCLK +#define RCC_TIM17CLK_HCLK RCC_TIM17CLK_PCLK +#define RCC_TIM20CLK_HCLK RCC_TIM20CLK_PCLK +#define RCC_TIM2CLK_HCLK RCC_TIM2CLK_PCLK +#define RCC_TIM3CLK_HCLK RCC_TIM3TIM4CLK_PCLK +#define RCC_TIM3CLK_PLLCLK RCC_TIM3TIM4CLK_PLLCLK +/** + * @} + */ + +/** @defgroup RCC_HRTIM_clock_source + * @{ + */ + +#define RCC_HRTIM1CLK_HCLK ((uint32_t)0x00000000) +#define RCC_HRTIM1CLK_PLLCLK RCC_CFGR3_HRTIM1SW + +#define IS_RCC_HRTIMCLK(HRTIMCLK) (((HRTIMCLK) == RCC_HRTIM1CLK_HCLK) || ((HRTIMCLK) == RCC_HRTIM1CLK_PLLCLK)) + +/** + * @} + */ + +/** @defgroup RCC_I2C_clock_source + * @{ + */ + +#define RCC_I2C1CLK_HSI ((uint32_t)0x00000000) +#define RCC_I2C1CLK_SYSCLK RCC_CFGR3_I2C1SW + +#define RCC_I2C2CLK_HSI ((uint32_t)0x10000000) +#define RCC_I2C2CLK_SYSCLK ((uint32_t)0x10000020) + +#define RCC_I2C3CLK_HSI ((uint32_t)0x20000000) +#define RCC_I2C3CLK_SYSCLK ((uint32_t)0x20000040) + +#define IS_RCC_I2CCLK(I2CCLK) (((I2CCLK) == RCC_I2C1CLK_HSI) || ((I2CCLK) == RCC_I2C1CLK_SYSCLK) || \ + ((I2CCLK) == RCC_I2C2CLK_HSI) || ((I2CCLK) == RCC_I2C2CLK_SYSCLK) || \ + ((I2CCLK) == RCC_I2C3CLK_HSI) || ((I2CCLK) == RCC_I2C3CLK_SYSCLK)) + +/** + * @} + */ + +/** @defgroup RCC_USART_clock_source + * @{ + */ + +#define RCC_USART1CLK_PCLK ((uint32_t)0x10000000) +#define RCC_USART1CLK_SYSCLK ((uint32_t)0x10000001) +#define RCC_USART1CLK_LSE ((uint32_t)0x10000002) +#define RCC_USART1CLK_HSI ((uint32_t)0x10000003) + +#define RCC_USART2CLK_PCLK ((uint32_t)0x20000000) +#define RCC_USART2CLK_SYSCLK ((uint32_t)0x20010000) +#define RCC_USART2CLK_LSE ((uint32_t)0x20020000) +#define RCC_USART2CLK_HSI ((uint32_t)0x20030000) + +#define RCC_USART3CLK_PCLK ((uint32_t)0x30000000) +#define RCC_USART3CLK_SYSCLK ((uint32_t)0x30040000) +#define RCC_USART3CLK_LSE ((uint32_t)0x30080000) +#define RCC_USART3CLK_HSI ((uint32_t)0x300C0000) + +#define RCC_UART4CLK_PCLK ((uint32_t)0x40000000) +#define RCC_UART4CLK_SYSCLK ((uint32_t)0x40100000) +#define RCC_UART4CLK_LSE ((uint32_t)0x40200000) +#define RCC_UART4CLK_HSI ((uint32_t)0x40300000) + +#define RCC_UART5CLK_PCLK ((uint32_t)0x50000000) +#define RCC_UART5CLK_SYSCLK ((uint32_t)0x50400000) +#define RCC_UART5CLK_LSE ((uint32_t)0x50800000) +#define RCC_UART5CLK_HSI ((uint32_t)0x50C00000) + +#define IS_RCC_USARTCLK(USARTCLK) (((USARTCLK) == RCC_USART1CLK_PCLK) || ((USARTCLK) == RCC_USART1CLK_SYSCLK) || \ + ((USARTCLK) == RCC_USART1CLK_LSE) || ((USARTCLK) == RCC_USART1CLK_HSI) ||\ + ((USARTCLK) == RCC_USART2CLK_PCLK) || ((USARTCLK) == RCC_USART2CLK_SYSCLK) || \ + ((USARTCLK) == RCC_USART2CLK_LSE) || ((USARTCLK) == RCC_USART2CLK_HSI) || \ + ((USARTCLK) == RCC_USART3CLK_PCLK) || ((USARTCLK) == RCC_USART3CLK_SYSCLK) || \ + ((USARTCLK) == RCC_USART3CLK_LSE) || ((USARTCLK) == RCC_USART3CLK_HSI) || \ + ((USARTCLK) == RCC_UART4CLK_PCLK) || ((USARTCLK) == RCC_UART4CLK_SYSCLK) || \ + ((USARTCLK) == RCC_UART4CLK_LSE) || ((USARTCLK) == RCC_UART4CLK_HSI) || \ + ((USARTCLK) == RCC_UART5CLK_PCLK) || ((USARTCLK) == RCC_UART5CLK_SYSCLK) || \ + ((USARTCLK) == RCC_UART5CLK_LSE) || ((USARTCLK) == RCC_UART5CLK_HSI)) + +/** + * @} + */ + +/** @defgroup RCC_Interrupt_Source + * @{ + */ + +#define RCC_IT_LSIRDY ((uint8_t)0x01) +#define RCC_IT_LSERDY ((uint8_t)0x02) +#define RCC_IT_HSIRDY ((uint8_t)0x04) +#define RCC_IT_HSERDY ((uint8_t)0x08) +#define RCC_IT_PLLRDY ((uint8_t)0x10) +#define RCC_IT_CSS ((uint8_t)0x80) + +#define IS_RCC_IT(IT) ((((IT) & (uint8_t)0xC0) == 0x00) && ((IT) != 0x00)) + +#define IS_RCC_GET_IT(IT) (((IT) == RCC_IT_LSIRDY) || ((IT) == RCC_IT_LSERDY) || \ + ((IT) == RCC_IT_HSIRDY) || ((IT) == RCC_IT_HSERDY) || \ + ((IT) == RCC_IT_PLLRDY) || ((IT) == RCC_IT_CSS)) + + +#define IS_RCC_CLEAR_IT(IT) ((((IT) & (uint8_t)0x40) == 0x00) && ((IT) != 0x00)) + +/** + * @} + */ + +/** @defgroup RCC_LSE_configuration + * @{ + */ + +#define RCC_LSE_OFF ((uint32_t)0x00000000) +#define RCC_LSE_ON RCC_BDCR_LSEON +#define RCC_LSE_Bypass ((uint32_t)(RCC_BDCR_LSEON | RCC_BDCR_LSEBYP)) +#define IS_RCC_LSE(LSE) (((LSE) == RCC_LSE_OFF) || ((LSE) == RCC_LSE_ON) || \ + ((LSE) == RCC_LSE_Bypass)) +/** + * @} + */ + +/** @defgroup RCC_RTC_Clock_Source + * @{ + */ + +#define RCC_RTCCLKSource_LSE RCC_BDCR_RTCSEL_LSE +#define RCC_RTCCLKSource_LSI RCC_BDCR_RTCSEL_LSI +#define RCC_RTCCLKSource_HSE_Div32 RCC_BDCR_RTCSEL_HSE + +#define IS_RCC_RTCCLK_SOURCE(SOURCE) (((SOURCE) == RCC_RTCCLKSource_LSE) || \ + ((SOURCE) == RCC_RTCCLKSource_LSI) || \ + ((SOURCE) == RCC_RTCCLKSource_HSE_Div32)) +/** + * @} + */ + +/** @defgroup RCC_I2S_Clock_Source + * @{ + */ +#define RCC_I2S2CLKSource_SYSCLK ((uint8_t)0x00) +#define RCC_I2S2CLKSource_Ext ((uint8_t)0x01) + +#define IS_RCC_I2SCLK_SOURCE(SOURCE) (((SOURCE) == RCC_I2S2CLKSource_SYSCLK) || ((SOURCE) == RCC_I2S2CLKSource_Ext)) + +/** @defgroup RCC_LSE_Drive_Configuration + * @{ + */ + +#define RCC_LSEDrive_Low ((uint32_t)0x00000000) +#define RCC_LSEDrive_MediumLow RCC_BDCR_LSEDRV_0 +#define RCC_LSEDrive_MediumHigh RCC_BDCR_LSEDRV_1 +#define RCC_LSEDrive_High RCC_BDCR_LSEDRV +#define IS_RCC_LSE_DRIVE(DRIVE) (((DRIVE) == RCC_LSEDrive_Low) || ((DRIVE) == RCC_LSEDrive_MediumLow) || \ + ((DRIVE) == RCC_LSEDrive_MediumHigh) || ((DRIVE) == RCC_LSEDrive_High)) +/** + * @} + */ + +/** @defgroup RCC_AHB_Peripherals + * @{ + */ + +#define RCC_AHBPeriph_ADC34 RCC_AHBENR_ADC34EN +#define RCC_AHBPeriph_ADC12 RCC_AHBENR_ADC12EN +#define RCC_AHBPeriph_GPIOA RCC_AHBENR_GPIOAEN +#define RCC_AHBPeriph_GPIOB RCC_AHBENR_GPIOBEN +#define RCC_AHBPeriph_GPIOC RCC_AHBENR_GPIOCEN +#define RCC_AHBPeriph_GPIOD RCC_AHBENR_GPIODEN +#define RCC_AHBPeriph_GPIOE RCC_AHBENR_GPIOEEN +#define RCC_AHBPeriph_GPIOF RCC_AHBENR_GPIOFEN +#define RCC_AHBPeriph_GPIOG RCC_AHBENR_GPIOGEN +#define RCC_AHBPeriph_GPIOH RCC_AHBENR_GPIOHEN +#define RCC_AHBPeriph_TS RCC_AHBENR_TSEN +#define RCC_AHBPeriph_CRC RCC_AHBENR_CRCEN +#define RCC_AHBPeriph_FMC RCC_AHBENR_FMCEN +#define RCC_AHBPeriph_FLITF RCC_AHBENR_FLITFEN +#define RCC_AHBPeriph_SRAM RCC_AHBENR_SRAMEN +#define RCC_AHBPeriph_DMA2 RCC_AHBENR_DMA2EN +#define RCC_AHBPeriph_DMA1 RCC_AHBENR_DMA1EN + +#define IS_RCC_AHB_PERIPH(PERIPH) ((((PERIPH) & 0xCE00FF88) == 0x00) && ((PERIPH) != 0x00)) +#define IS_RCC_AHB_RST_PERIPH(PERIPH) ((((PERIPH) & 0xCE00FFDF) == 0x00) && ((PERIPH) != 0x00)) + +/** + * @} + */ + +/** @defgroup RCC_APB2_Peripherals + * @{ + */ + +#define RCC_APB2Periph_SYSCFG RCC_APB2ENR_SYSCFGEN +#define RCC_APB2Periph_TIM1 RCC_APB2ENR_TIM1EN +#define RCC_APB2Periph_SPI1 RCC_APB2ENR_SPI1EN +#define RCC_APB2Periph_TIM8 RCC_APB2ENR_TIM8EN +#define RCC_APB2Periph_USART1 RCC_APB2ENR_USART1EN +#define RCC_APB2Periph_SPI4 RCC_APB2ENR_SPI4EN +#define RCC_APB2Periph_TIM15 RCC_APB2ENR_TIM15EN +#define RCC_APB2Periph_TIM16 RCC_APB2ENR_TIM16EN +#define RCC_APB2Periph_TIM17 RCC_APB2ENR_TIM17EN +#define RCC_APB2Periph_TIM20 RCC_APB2ENR_TIM20EN +#define RCC_APB2Periph_HRTIM1 RCC_APB2ENR_HRTIM1 + +#define IS_RCC_APB2_PERIPH(PERIPH) ((((PERIPH) & 0xDFE807FE) == 0x00) && ((PERIPH) != 0x00)) + +/** + * @} + */ + +/** @defgroup RCC_APB1_Peripherals + * @{ + */ +#define RCC_APB1Periph_TIM2 RCC_APB1ENR_TIM2EN +#define RCC_APB1Periph_TIM3 RCC_APB1ENR_TIM3EN +#define RCC_APB1Periph_TIM4 RCC_APB1ENR_TIM4EN +#define RCC_APB1Periph_TIM6 RCC_APB1ENR_TIM6EN +#define RCC_APB1Periph_TIM7 RCC_APB1ENR_TIM7EN +#define RCC_APB1Periph_WWDG RCC_APB1ENR_WWDGEN +#define RCC_APB1Periph_SPI2 RCC_APB1ENR_SPI2EN +#define RCC_APB1Periph_SPI3 RCC_APB1ENR_SPI3EN +#define RCC_APB1Periph_USART2 RCC_APB1ENR_USART2EN +#define RCC_APB1Periph_USART3 RCC_APB1ENR_USART3EN +#define RCC_APB1Periph_UART4 RCC_APB1ENR_UART4EN +#define RCC_APB1Periph_UART5 RCC_APB1ENR_UART5EN +#define RCC_APB1Periph_I2C1 RCC_APB1ENR_I2C1EN +#define RCC_APB1Periph_I2C2 RCC_APB1ENR_I2C2EN +#define RCC_APB1Periph_USB RCC_APB1ENR_USBEN +#define RCC_APB1Periph_CAN1 RCC_APB1ENR_CAN1EN +#define RCC_APB1Periph_PWR RCC_APB1ENR_PWREN +#define RCC_APB1Periph_DAC1 RCC_APB1ENR_DAC1EN +#define RCC_APB1Periph_I2C3 RCC_APB1ENR_I2C3EN +#define RCC_APB1Periph_DAC2 RCC_APB1ENR_DAC2EN +#define RCC_APB1Periph_DAC RCC_APB1Periph_DAC1 + + +#define IS_RCC_APB1_PERIPH(PERIPH) ((((PERIPH) & 0x890137C8) == 0x00) && ((PERIPH) != 0x00)) +/** + * @} + */ + +/** @defgroup RCC_MCO_Clock_Source + * @{ + */ + +#define RCC_MCOSource_NoClock ((uint8_t)0x00) +#define RCC_MCOSource_LSI ((uint8_t)0x02) +#define RCC_MCOSource_LSE ((uint8_t)0x03) +#define RCC_MCOSource_SYSCLK ((uint8_t)0x04) +#define RCC_MCOSource_HSI ((uint8_t)0x05) +#define RCC_MCOSource_HSE ((uint8_t)0x06) +#define RCC_MCOSource_PLLCLK_Div2 ((uint8_t)0x07) +#define RCC_MCOSource_PLLCLK ((uint8_t)0x87) + +#define IS_RCC_MCO_SOURCE(SOURCE) (((SOURCE) == RCC_MCOSource_NoClock) ||((SOURCE) == RCC_MCOSource_SYSCLK) ||\ + ((SOURCE) == RCC_MCOSource_HSI) || ((SOURCE) == RCC_MCOSource_HSE) || \ + ((SOURCE) == RCC_MCOSource_LSI) || ((SOURCE) == RCC_MCOSource_LSE) || \ + ((SOURCE) == RCC_MCOSource_PLLCLK_Div2)|| ((SOURCE) == RCC_MCOSource_PLLCLK)) +/** + * @} + */ + +/** @defgroup RCC_MCOPrescaler + * @{ + */ + +#define RCC_MCOPrescaler_1 RCC_CFGR_MCO_PRE_1 +#define RCC_MCOPrescaler_2 RCC_CFGR_MCO_PRE_2 +#define RCC_MCOPrescaler_4 RCC_CFGR_MCO_PRE_4 +#define RCC_MCOPrescaler_8 RCC_CFGR_MCO_PRE_8 +#define RCC_MCOPrescaler_16 RCC_CFGR_MCO_PRE_16 +#define RCC_MCOPrescaler_32 RCC_CFGR_MCO_PRE_32 +#define RCC_MCOPrescaler_64 RCC_CFGR_MCO_PRE_64 +#define RCC_MCOPrescaler_128 RCC_CFGR_MCO_PRE_128 + +#define IS_RCC_MCO_PRESCALER(PRESCALER) (((PRESCALER) == RCC_MCOPrescaler_1) || \ + ((PRESCALER) == RCC_MCOPrescaler_2) || \ + ((PRESCALER) == RCC_MCOPrescaler_4) || \ + ((PRESCALER) == RCC_MCOPrescaler_8) || \ + ((PRESCALER) == RCC_MCOPrescaler_16) || \ + ((PRESCALER) == RCC_MCOPrescaler_32) || \ + ((PRESCALER) == RCC_MCOPrescaler_64) || \ + ((PRESCALER) == RCC_MCOPrescaler_128)) +/** + * @} + */ + +/** @defgroup RCC_USB_Device_clock_source + * @{ + */ + +#define RCC_USBCLKSource_PLLCLK_1Div5 ((uint8_t)0x00) +#define RCC_USBCLKSource_PLLCLK_Div1 ((uint8_t)0x01) + +#define IS_RCC_USBCLK_SOURCE(SOURCE) (((SOURCE) == RCC_USBCLKSource_PLLCLK_1Div5) || \ + ((SOURCE) == RCC_USBCLKSource_PLLCLK_Div1)) +/** + * @} + */ + +/** @defgroup RCC_Flag + * @{ + */ +#define RCC_FLAG_HSIRDY ((uint8_t)0x01) +#define RCC_FLAG_HSERDY ((uint8_t)0x11) +#define RCC_FLAG_PLLRDY ((uint8_t)0x19) +#define RCC_FLAG_MCOF ((uint8_t)0x9C) +#define RCC_FLAG_LSERDY ((uint8_t)0x21) +#define RCC_FLAG_LSIRDY ((uint8_t)0x41) +#define RCC_FLAG_OBLRST ((uint8_t)0x59) +#define RCC_FLAG_PINRST ((uint8_t)0x5A) +#define RCC_FLAG_PORRST ((uint8_t)0x5B) +#define RCC_FLAG_SFTRST ((uint8_t)0x5C) +#define RCC_FLAG_IWDGRST ((uint8_t)0x5D) +#define RCC_FLAG_WWDGRST ((uint8_t)0x5E) +#define RCC_FLAG_LPWRRST ((uint8_t)0x5F) + +#define IS_RCC_FLAG(FLAG) (((FLAG) == RCC_FLAG_HSIRDY) || ((FLAG) == RCC_FLAG_HSERDY) || \ + ((FLAG) == RCC_FLAG_PLLRDY) || ((FLAG) == RCC_FLAG_LSERDY) || \ + ((FLAG) == RCC_FLAG_LSIRDY) || ((FLAG) == RCC_FLAG_OBLRST) || \ + ((FLAG) == RCC_FLAG_PINRST) || ((FLAG) == RCC_FLAG_PORRST) || \ + ((FLAG) == RCC_FLAG_SFTRST) || ((FLAG) == RCC_FLAG_IWDGRST)|| \ + ((FLAG) == RCC_FLAG_WWDGRST)|| ((FLAG) == RCC_FLAG_LPWRRST)|| \ + ((FLAG) == RCC_FLAG_MCOF)) + +#define IS_RCC_HSI_CALIBRATION_VALUE(VALUE) ((VALUE) <= 0x1F) + +/** + * @} + */ + +/** + * @} + */ + +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions ------------------------------------------------------- */ + +/* Function used to set the RCC clock configuration to the default reset state */ +void RCC_DeInit(void); + +/* Internal/external clocks, PLL, CSS and MCO configuration functions *********/ +void RCC_HSEConfig(uint8_t RCC_HSE); +ErrorStatus RCC_WaitForHSEStartUp(void); +void RCC_AdjustHSICalibrationValue(uint8_t HSICalibrationValue); +void RCC_HSICmd(FunctionalState NewState); +void RCC_LSEConfig(uint32_t RCC_LSE); +void RCC_LSEDriveConfig(uint32_t RCC_LSEDrive); +void RCC_LSICmd(FunctionalState NewState); +void RCC_PLLConfig(uint32_t RCC_PLLSource, uint32_t RCC_PLLMul); +void RCC_PLLCmd(FunctionalState NewState); +void RCC_PREDIV1Config(uint32_t RCC_PREDIV1_Div); +void RCC_ClockSecuritySystemCmd(FunctionalState NewState); +#ifdef STM32F303xC + void RCC_MCOConfig(uint8_t RCC_MCOSource); +#else + void RCC_MCOConfig(uint8_t RCC_MCOSource,uint32_t RCC_MCOPrescaler); +#endif /* STM32F303xC */ + +/* System, AHB and APB busses clocks configuration functions ******************/ +void RCC_SYSCLKConfig(uint32_t RCC_SYSCLKSource); +uint8_t RCC_GetSYSCLKSource(void); +void RCC_HCLKConfig(uint32_t RCC_SYSCLK); +void RCC_PCLK1Config(uint32_t RCC_HCLK); +void RCC_PCLK2Config(uint32_t RCC_HCLK); +void RCC_GetClocksFreq(RCC_ClocksTypeDef* RCC_Clocks); + +/* Peripheral clocks configuration functions **********************************/ +void RCC_ADCCLKConfig(uint32_t RCC_PLLCLK); +void RCC_I2CCLKConfig(uint32_t RCC_I2CCLK); +void RCC_TIMCLKConfig(uint32_t RCC_TIMCLK); +void RCC_HRTIM1CLKConfig(uint32_t RCC_HRTIMCLK); +void RCC_I2SCLKConfig(uint32_t RCC_I2SCLKSource); +void RCC_USARTCLKConfig(uint32_t RCC_USARTCLK); +void RCC_USBCLKConfig(uint32_t RCC_USBCLKSource); + +void RCC_RTCCLKConfig(uint32_t RCC_RTCCLKSource); +void RCC_RTCCLKCmd(FunctionalState NewState); +void RCC_BackupResetCmd(FunctionalState NewState); + +void RCC_AHBPeriphClockCmd(uint32_t RCC_AHBPeriph, FunctionalState NewState); +void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState); +void RCC_APB1PeriphClockCmd(uint32_t RCC_APB1Periph, FunctionalState NewState); + +void RCC_AHBPeriphResetCmd(uint32_t RCC_AHBPeriph, FunctionalState NewState); +void RCC_APB2PeriphResetCmd(uint32_t RCC_APB2Periph, FunctionalState NewState); +void RCC_APB1PeriphResetCmd(uint32_t RCC_APB1Periph, FunctionalState NewState); + +/* Interrupts and flags management functions **********************************/ +void RCC_ITConfig(uint8_t RCC_IT, FunctionalState NewState); +FlagStatus RCC_GetFlagStatus(uint8_t RCC_FLAG); +void RCC_ClearFlag(void); +ITStatus RCC_GetITStatus(uint8_t RCC_IT); +void RCC_ClearITPendingBit(uint8_t RCC_IT); + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F30x_RCC_H */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_rtc.h b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_rtc.h new file mode 100755 index 0000000000..b6841a962a --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_rtc.h @@ -0,0 +1,852 @@ +/** + ****************************************************************************** + * @file stm32f30x_rtc.h + * @author MCD Application Team + * @version V1.2.3 + * @date 10-July-2015 + * @brief This file contains all the functions prototypes for the RTC firmware + * library. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F30x_RTC_H +#define __STM32F30x_RTC_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f30x.h" + +/** @addtogroup STM32F30x_StdPeriph_Driver + * @{ + */ + +/** @addtogroup RTC + * @{ + */ + +/* Exported types ------------------------------------------------------------*/ + +/** + * @brief RTC Init structures definition + */ +typedef struct +{ + uint32_t RTC_HourFormat; /*!< Specifies the RTC Hour Format. + This parameter can be a value of @ref RTC_Hour_Formats */ + + uint32_t RTC_AsynchPrediv; /*!< Specifies the RTC Asynchronous Predivider value. + This parameter must be set to a value lower than 0x7F */ + + uint32_t RTC_SynchPrediv; /*!< Specifies the RTC Synchronous Predivider value. + This parameter must be set to a value lower than 0x1FFF */ +}RTC_InitTypeDef; + +/** + * @brief RTC Time structure definition + */ +typedef struct +{ + uint8_t RTC_Hours; /*!< Specifies the RTC Time Hour. + This parameter must be set to a value in the 0-12 range + if the RTC_HourFormat_12 is selected or 0-23 range if + the RTC_HourFormat_24 is selected. */ + + uint8_t RTC_Minutes; /*!< Specifies the RTC Time Minutes. + This parameter must be set to a value in the 0-59 range. */ + + uint8_t RTC_Seconds; /*!< Specifies the RTC Time Seconds. + This parameter must be set to a value in the 0-59 range. */ + + uint8_t RTC_H12; /*!< Specifies the RTC AM/PM Time. + This parameter can be a value of @ref RTC_AM_PM_Definitions */ +}RTC_TimeTypeDef; + +/** + * @brief RTC Date structure definition + */ +typedef struct +{ + uint8_t RTC_WeekDay; /*!< Specifies the RTC Date WeekDay. + This parameter can be a value of @ref RTC_WeekDay_Definitions */ + + uint8_t RTC_Month; /*!< Specifies the RTC Date Month (in BCD format). + This parameter can be a value of @ref RTC_Month_Date_Definitions */ + + uint8_t RTC_Date; /*!< Specifies the RTC Date. + This parameter must be set to a value in the 1-31 range. */ + + uint8_t RTC_Year; /*!< Specifies the RTC Date Year. + This parameter must be set to a value in the 0-99 range. */ +}RTC_DateTypeDef; + +/** + * @brief RTC Alarm structure definition + */ +typedef struct +{ + RTC_TimeTypeDef RTC_AlarmTime; /*!< Specifies the RTC Alarm Time members. */ + + uint32_t RTC_AlarmMask; /*!< Specifies the RTC Alarm Masks. + This parameter can be a value of @ref RTC_AlarmMask_Definitions */ + + uint32_t RTC_AlarmDateWeekDaySel; /*!< Specifies the RTC Alarm is on Date or WeekDay. + This parameter can be a value of @ref RTC_AlarmDateWeekDay_Definitions */ + + uint8_t RTC_AlarmDateWeekDay; /*!< Specifies the RTC Alarm Date/WeekDay. + If the Alarm Date is selected, this parameter + must be set to a value in the 1-31 range. + If the Alarm WeekDay is selected, this + parameter can be a value of @ref RTC_WeekDay_Definitions */ +}RTC_AlarmTypeDef; + +/* Exported constants --------------------------------------------------------*/ + +/** @defgroup RTC_Exported_Constants + * @{ + */ + + +/** @defgroup RTC_Hour_Formats + * @{ + */ +#define RTC_HourFormat_24 ((uint32_t)0x00000000) +#define RTC_HourFormat_12 ((uint32_t)0x00000040) +#define IS_RTC_HOUR_FORMAT(FORMAT) (((FORMAT) == RTC_HourFormat_12) || \ + ((FORMAT) == RTC_HourFormat_24)) +/** + * @} + */ + +/** @defgroup RTC_Asynchronous_Predivider + * @{ + */ +#define IS_RTC_ASYNCH_PREDIV(PREDIV) ((PREDIV) <= 0x7F) + +/** + * @} + */ + + +/** @defgroup RTC_Synchronous_Predivider + * @{ + */ +#define IS_RTC_SYNCH_PREDIV(PREDIV) ((PREDIV) <= 0x7FFF) + +/** + * @} + */ + +/** @defgroup RTC_Time_Definitions + * @{ + */ +#define IS_RTC_HOUR12(HOUR) (((HOUR) > 0) && ((HOUR) <= 12)) +#define IS_RTC_HOUR24(HOUR) ((HOUR) <= 23) +#define IS_RTC_MINUTES(MINUTES) ((MINUTES) <= 59) +#define IS_RTC_SECONDS(SECONDS) ((SECONDS) <= 59) + +/** + * @} + */ + +/** @defgroup RTC_AM_PM_Definitions + * @{ + */ +#define RTC_H12_AM ((uint8_t)0x00) +#define RTC_H12_PM ((uint8_t)0x40) +#define IS_RTC_H12(PM) (((PM) == RTC_H12_AM) || ((PM) == RTC_H12_PM)) + +/** + * @} + */ + +/** @defgroup RTC_Year_Date_Definitions + * @{ + */ +#define IS_RTC_YEAR(YEAR) ((YEAR) <= 99) + +/** + * @} + */ + +/** @defgroup RTC_Month_Date_Definitions + * @{ + */ + +/* Coded in BCD format */ +#define RTC_Month_January ((uint8_t)0x01) +#define RTC_Month_February ((uint8_t)0x02) +#define RTC_Month_March ((uint8_t)0x03) +#define RTC_Month_April ((uint8_t)0x04) +#define RTC_Month_May ((uint8_t)0x05) +#define RTC_Month_June ((uint8_t)0x06) +#define RTC_Month_July ((uint8_t)0x07) +#define RTC_Month_August ((uint8_t)0x08) +#define RTC_Month_September ((uint8_t)0x09) +#define RTC_Month_October ((uint8_t)0x10) +#define RTC_Month_November ((uint8_t)0x11) +#define RTC_Month_December ((uint8_t)0x12) +#define IS_RTC_MONTH(MONTH) (((MONTH) >= 1) && ((MONTH) <= 12)) +#define IS_RTC_DATE(DATE) (((DATE) >= 1) && ((DATE) <= 31)) + +/** + * @} + */ + +/** @defgroup RTC_WeekDay_Definitions + * @{ + */ + +#define RTC_Weekday_Monday ((uint8_t)0x01) +#define RTC_Weekday_Tuesday ((uint8_t)0x02) +#define RTC_Weekday_Wednesday ((uint8_t)0x03) +#define RTC_Weekday_Thursday ((uint8_t)0x04) +#define RTC_Weekday_Friday ((uint8_t)0x05) +#define RTC_Weekday_Saturday ((uint8_t)0x06) +#define RTC_Weekday_Sunday ((uint8_t)0x07) +#define IS_RTC_WEEKDAY(WEEKDAY) (((WEEKDAY) == RTC_Weekday_Monday) || \ + ((WEEKDAY) == RTC_Weekday_Tuesday) || \ + ((WEEKDAY) == RTC_Weekday_Wednesday) || \ + ((WEEKDAY) == RTC_Weekday_Thursday) || \ + ((WEEKDAY) == RTC_Weekday_Friday) || \ + ((WEEKDAY) == RTC_Weekday_Saturday) || \ + ((WEEKDAY) == RTC_Weekday_Sunday)) +/** + * @} + */ + + +/** @defgroup RTC_Alarm_Definitions + * @{ + */ +#define IS_RTC_ALARM_DATE_WEEKDAY_DATE(DATE) (((DATE) > 0) && ((DATE) <= 31)) +#define IS_RTC_ALARM_DATE_WEEKDAY_WEEKDAY(WEEKDAY) (((WEEKDAY) == RTC_Weekday_Monday) || \ + ((WEEKDAY) == RTC_Weekday_Tuesday) || \ + ((WEEKDAY) == RTC_Weekday_Wednesday) || \ + ((WEEKDAY) == RTC_Weekday_Thursday) || \ + ((WEEKDAY) == RTC_Weekday_Friday) || \ + ((WEEKDAY) == RTC_Weekday_Saturday) || \ + ((WEEKDAY) == RTC_Weekday_Sunday)) + +/** + * @} + */ + + +/** @defgroup RTC_AlarmDateWeekDay_Definitions + * @{ + */ +#define RTC_AlarmDateWeekDaySel_Date ((uint32_t)0x00000000) +#define RTC_AlarmDateWeekDaySel_WeekDay ((uint32_t)0x40000000) + +#define IS_RTC_ALARM_DATE_WEEKDAY_SEL(SEL) (((SEL) == RTC_AlarmDateWeekDaySel_Date) || \ + ((SEL) == RTC_AlarmDateWeekDaySel_WeekDay)) + +/** + * @} + */ + + +/** @defgroup RTC_AlarmMask_Definitions + * @{ + */ +#define RTC_AlarmMask_None ((uint32_t)0x00000000) +#define RTC_AlarmMask_DateWeekDay ((uint32_t)0x80000000) +#define RTC_AlarmMask_Hours ((uint32_t)0x00800000) +#define RTC_AlarmMask_Minutes ((uint32_t)0x00008000) +#define RTC_AlarmMask_Seconds ((uint32_t)0x00000080) +#define RTC_AlarmMask_All ((uint32_t)0x80808080) +#define IS_ALARM_MASK(MASK) (((MASK) & 0x7F7F7F7F) == (uint32_t)RESET) + +/** + * @} + */ + +/** @defgroup RTC_Alarms_Definitions + * @{ + */ +#define RTC_Alarm_A ((uint32_t)0x00000100) +#define RTC_Alarm_B ((uint32_t)0x00000200) +#define IS_RTC_ALARM(ALARM) (((ALARM) == RTC_Alarm_A) || ((ALARM) == RTC_Alarm_B)) +#define IS_RTC_CMD_ALARM(ALARM) (((ALARM) & (RTC_Alarm_A | RTC_Alarm_B)) != (uint32_t)RESET) + +/** + * @} + */ + +/** @defgroup RTC_Alarm_Sub_Seconds_Masks_Definitions + * @{ + */ +#define RTC_AlarmSubSecondMask_All ((uint32_t)0x00000000) /*!< All Alarm SS fields are masked. + There is no comparison on sub seconds + for Alarm */ +#define RTC_AlarmSubSecondMask_SS14_1 ((uint32_t)0x01000000) /*!< SS[14:1] are don't care in Alarm + comparison. Only SS[0] is compared. */ +#define RTC_AlarmSubSecondMask_SS14_2 ((uint32_t)0x02000000) /*!< SS[14:2] are don't care in Alarm + comparison. Only SS[1:0] are compared */ +#define RTC_AlarmSubSecondMask_SS14_3 ((uint32_t)0x03000000) /*!< SS[14:3] are don't care in Alarm + comparison. Only SS[2:0] are compared */ +#define RTC_AlarmSubSecondMask_SS14_4 ((uint32_t)0x04000000) /*!< SS[14:4] are don't care in Alarm + comparison. Only SS[3:0] are compared */ +#define RTC_AlarmSubSecondMask_SS14_5 ((uint32_t)0x05000000) /*!< SS[14:5] are don't care in Alarm + comparison. Only SS[4:0] are compared */ +#define RTC_AlarmSubSecondMask_SS14_6 ((uint32_t)0x06000000) /*!< SS[14:6] are don't care in Alarm + comparison. Only SS[5:0] are compared */ +#define RTC_AlarmSubSecondMask_SS14_7 ((uint32_t)0x07000000) /*!< SS[14:7] are don't care in Alarm + comparison. Only SS[6:0] are compared */ +#define RTC_AlarmSubSecondMask_SS14_8 ((uint32_t)0x08000000) /*!< SS[14:8] are don't care in Alarm + comparison. Only SS[7:0] are compared */ +#define RTC_AlarmSubSecondMask_SS14_9 ((uint32_t)0x09000000) /*!< SS[14:9] are don't care in Alarm + comparison. Only SS[8:0] are compared */ +#define RTC_AlarmSubSecondMask_SS14_10 ((uint32_t)0x0A000000) /*!< SS[14:10] are don't care in Alarm + comparison. Only SS[9:0] are compared */ +#define RTC_AlarmSubSecondMask_SS14_11 ((uint32_t)0x0B000000) /*!< SS[14:11] are don't care in Alarm + comparison. Only SS[10:0] are compared */ +#define RTC_AlarmSubSecondMask_SS14_12 ((uint32_t)0x0C000000) /*!< SS[14:12] are don't care in Alarm + comparison.Only SS[11:0] are compared */ +#define RTC_AlarmSubSecondMask_SS14_13 ((uint32_t)0x0D000000) /*!< SS[14:13] are don't care in Alarm + comparison. Only SS[12:0] are compared */ +#define RTC_AlarmSubSecondMask_SS14 ((uint32_t)0x0E000000) /*!< SS[14] is don't care in Alarm + comparison.Only SS[13:0] are compared */ +#define RTC_AlarmSubSecondMask_None ((uint32_t)0x0F000000) /*!< SS[14:0] are compared and must match + to activate alarm. */ +#define IS_RTC_ALARM_SUB_SECOND_MASK(MASK) (((MASK) == RTC_AlarmSubSecondMask_All) || \ + ((MASK) == RTC_AlarmSubSecondMask_SS14_1) || \ + ((MASK) == RTC_AlarmSubSecondMask_SS14_2) || \ + ((MASK) == RTC_AlarmSubSecondMask_SS14_3) || \ + ((MASK) == RTC_AlarmSubSecondMask_SS14_4) || \ + ((MASK) == RTC_AlarmSubSecondMask_SS14_5) || \ + ((MASK) == RTC_AlarmSubSecondMask_SS14_6) || \ + ((MASK) == RTC_AlarmSubSecondMask_SS14_7) || \ + ((MASK) == RTC_AlarmSubSecondMask_SS14_8) || \ + ((MASK) == RTC_AlarmSubSecondMask_SS14_9) || \ + ((MASK) == RTC_AlarmSubSecondMask_SS14_10) || \ + ((MASK) == RTC_AlarmSubSecondMask_SS14_11) || \ + ((MASK) == RTC_AlarmSubSecondMask_SS14_12) || \ + ((MASK) == RTC_AlarmSubSecondMask_SS14_13) || \ + ((MASK) == RTC_AlarmSubSecondMask_SS14) || \ + ((MASK) == RTC_AlarmSubSecondMask_None)) +/** + * @} + */ + +/** @defgroup RTC_Alarm_Sub_Seconds_Value + * @{ + */ + +#define IS_RTC_ALARM_SUB_SECOND_VALUE(VALUE) ((VALUE) <= 0x00007FFF) + +/** + * @} + */ + +/** @defgroup RTC_Wakeup_Timer_Definitions + * @{ + */ +#define RTC_WakeUpClock_RTCCLK_Div16 ((uint32_t)0x00000000) +#define RTC_WakeUpClock_RTCCLK_Div8 ((uint32_t)0x00000001) +#define RTC_WakeUpClock_RTCCLK_Div4 ((uint32_t)0x00000002) +#define RTC_WakeUpClock_RTCCLK_Div2 ((uint32_t)0x00000003) +#define RTC_WakeUpClock_CK_SPRE_16bits ((uint32_t)0x00000004) +#define RTC_WakeUpClock_CK_SPRE_17bits ((uint32_t)0x00000006) +#define IS_RTC_WAKEUP_CLOCK(CLOCK) (((CLOCK) == RTC_WakeUpClock_RTCCLK_Div16) || \ + ((CLOCK) == RTC_WakeUpClock_RTCCLK_Div8) || \ + ((CLOCK) == RTC_WakeUpClock_RTCCLK_Div4) || \ + ((CLOCK) == RTC_WakeUpClock_RTCCLK_Div2) || \ + ((CLOCK) == RTC_WakeUpClock_CK_SPRE_16bits) || \ + ((CLOCK) == RTC_WakeUpClock_CK_SPRE_17bits)) +#define IS_RTC_WAKEUP_COUNTER(COUNTER) ((COUNTER) <= 0xFFFF) +/** + * @} + */ + +/** @defgroup RTC_Time_Stamp_Edges_definitions + * @{ + */ +#define RTC_TimeStampEdge_Rising ((uint32_t)0x00000000) +#define RTC_TimeStampEdge_Falling ((uint32_t)0x00000008) +#define IS_RTC_TIMESTAMP_EDGE(EDGE) (((EDGE) == RTC_TimeStampEdge_Rising) || \ + ((EDGE) == RTC_TimeStampEdge_Falling)) +/** + * @} + */ + +/** @defgroup RTC_Output_selection_Definitions + * @{ + */ +#define RTC_Output_Disable ((uint32_t)0x00000000) +#define RTC_Output_AlarmA ((uint32_t)0x00200000) +#define RTC_Output_AlarmB ((uint32_t)0x00400000) +#define RTC_Output_WakeUp ((uint32_t)0x00600000) + +#define IS_RTC_OUTPUT(OUTPUT) (((OUTPUT) == RTC_Output_Disable) || \ + ((OUTPUT) == RTC_Output_AlarmA) || \ + ((OUTPUT) == RTC_Output_AlarmB) || \ + ((OUTPUT) == RTC_Output_WakeUp)) + +/** + * @} + */ + +/** @defgroup RTC_Output_Polarity_Definitions + * @{ + */ +#define RTC_OutputPolarity_High ((uint32_t)0x00000000) +#define RTC_OutputPolarity_Low ((uint32_t)0x00100000) +#define IS_RTC_OUTPUT_POL(POL) (((POL) == RTC_OutputPolarity_High) || \ + ((POL) == RTC_OutputPolarity_Low)) +/** + * @} + */ + +/** @defgroup RTC_Digital_Calibration_Definitions + * @{ + */ +#define RTC_CalibSign_Positive ((uint32_t)0x00000000) +#define RTC_CalibSign_Negative ((uint32_t)0x00000080) +#define IS_RTC_CALIB_SIGN(SIGN) (((SIGN) == RTC_CalibSign_Positive) || \ + ((SIGN) == RTC_CalibSign_Negative)) +#define IS_RTC_CALIB_VALUE(VALUE) ((VALUE) < 0x20) + +/** + * @} + */ + + /** @defgroup RTC_Calib_Output_selection_Definitions + * @{ + */ +#define RTC_CalibOutput_512Hz ((uint32_t)0x00000000) +#define RTC_CalibOutput_1Hz ((uint32_t)0x00080000) +#define IS_RTC_CALIB_OUTPUT(OUTPUT) (((OUTPUT) == RTC_CalibOutput_512Hz) || \ + ((OUTPUT) == RTC_CalibOutput_1Hz)) +/** + * @} + */ + +/** @defgroup RTC_Smooth_calib_period_Definitions + * @{ + */ +#define RTC_SmoothCalibPeriod_32sec ((uint32_t)0x00000000) /*!< if RTCCLK = 32768 Hz, Smooth calibation + period is 32s, else 2exp20 RTCCLK seconds */ +#define RTC_SmoothCalibPeriod_16sec ((uint32_t)0x00002000) /*!< if RTCCLK = 32768 Hz, Smooth calibation + period is 16s, else 2exp19 RTCCLK seconds */ +#define RTC_SmoothCalibPeriod_8sec ((uint32_t)0x00004000) /*!< if RTCCLK = 32768 Hz, Smooth calibation + period is 8s, else 2exp18 RTCCLK seconds */ +#define IS_RTC_SMOOTH_CALIB_PERIOD(PERIOD) (((PERIOD) == RTC_SmoothCalibPeriod_32sec) || \ + ((PERIOD) == RTC_SmoothCalibPeriod_16sec) || \ + ((PERIOD) == RTC_SmoothCalibPeriod_8sec)) + +/** + * @} + */ + +/** @defgroup RTC_Smooth_calib_Plus_pulses_Definitions + * @{ + */ +#define RTC_SmoothCalibPlusPulses_Set ((uint32_t)0x00008000) /*!< The number of RTCCLK pulses added + during a X -second window = Y - CALM[8:0]. + with Y = 512, 256, 128 when X = 32, 16, 8 */ +#define RTC_SmoothCalibPlusPulses_Reset ((uint32_t)0x00000000) /*!< The number of RTCCLK pulses subbstited + during a 32-second window = CALM[8:0]. */ +#define IS_RTC_SMOOTH_CALIB_PLUS(PLUS) (((PLUS) == RTC_SmoothCalibPlusPulses_Set) || \ + ((PLUS) == RTC_SmoothCalibPlusPulses_Reset)) + +/** + * @} + */ + +/** @defgroup RTC_Smooth_calib_Minus_pulses_Definitions + * @{ + */ +#define IS_RTC_SMOOTH_CALIB_MINUS(VALUE) ((VALUE) <= 0x000001FF) + +/** + * @} + */ + +/** @defgroup RTC_DayLightSaving_Definitions + * @{ + */ +#define RTC_DayLightSaving_SUB1H ((uint32_t)0x00020000) +#define RTC_DayLightSaving_ADD1H ((uint32_t)0x00010000) +#define IS_RTC_DAYLIGHT_SAVING(SAVE) (((SAVE) == RTC_DayLightSaving_SUB1H) || \ + ((SAVE) == RTC_DayLightSaving_ADD1H)) + +#define RTC_StoreOperation_Reset ((uint32_t)0x00000000) +#define RTC_StoreOperation_Set ((uint32_t)0x00040000) +#define IS_RTC_STORE_OPERATION(OPERATION) (((OPERATION) == RTC_StoreOperation_Reset) || \ + ((OPERATION) == RTC_StoreOperation_Set)) +/** + * @} + */ + +/** @defgroup RTC_Tamper_Trigger_Definitions + * @{ + */ +#define RTC_TamperTrigger_RisingEdge ((uint32_t)0x00000000) +#define RTC_TamperTrigger_FallingEdge ((uint32_t)0x00000001) +#define RTC_TamperTrigger_LowLevel ((uint32_t)0x00000000) +#define RTC_TamperTrigger_HighLevel ((uint32_t)0x00000001) +#define IS_RTC_TAMPER_TRIGGER(TRIGGER) (((TRIGGER) == RTC_TamperTrigger_RisingEdge) || \ + ((TRIGGER) == RTC_TamperTrigger_FallingEdge) || \ + ((TRIGGER) == RTC_TamperTrigger_LowLevel) || \ + ((TRIGGER) == RTC_TamperTrigger_HighLevel)) + +/** + * @} + */ + +/** @defgroup RTC_Tamper_Filter_Definitions + * @{ + */ +#define RTC_TamperFilter_Disable ((uint32_t)0x00000000) /*!< Tamper filter is disabled */ + +#define RTC_TamperFilter_2Sample ((uint32_t)0x00000800) /*!< Tamper is activated after 2 + consecutive samples at the active level */ +#define RTC_TamperFilter_4Sample ((uint32_t)0x00001000) /*!< Tamper is activated after 4 + consecutive samples at the active level */ +#define RTC_TamperFilter_8Sample ((uint32_t)0x00001800) /*!< Tamper is activated after 8 + consecutive samples at the active leve. */ +#define IS_RTC_TAMPER_FILTER(FILTER) (((FILTER) == RTC_TamperFilter_Disable) || \ + ((FILTER) == RTC_TamperFilter_2Sample) || \ + ((FILTER) == RTC_TamperFilter_4Sample) || \ + ((FILTER) == RTC_TamperFilter_8Sample)) +/** + * @} + */ + +/** @defgroup RTC_Tamper_Sampling_Frequencies_Definitions + * @{ + */ +#define RTC_TamperSamplingFreq_RTCCLK_Div32768 ((uint32_t)0x00000000) /*!< Each of the tamper inputs are sampled + with a frequency = RTCCLK / 32768 */ +#define RTC_TamperSamplingFreq_RTCCLK_Div16384 ((uint32_t)0x000000100) /*!< Each of the tamper inputs are sampled + with a frequency = RTCCLK / 16384 */ +#define RTC_TamperSamplingFreq_RTCCLK_Div8192 ((uint32_t)0x00000200) /*!< Each of the tamper inputs are sampled + with a frequency = RTCCLK / 8192 */ +#define RTC_TamperSamplingFreq_RTCCLK_Div4096 ((uint32_t)0x00000300) /*!< Each of the tamper inputs are sampled + with a frequency = RTCCLK / 4096 */ +#define RTC_TamperSamplingFreq_RTCCLK_Div2048 ((uint32_t)0x00000400) /*!< Each of the tamper inputs are sampled + with a frequency = RTCCLK / 2048 */ +#define RTC_TamperSamplingFreq_RTCCLK_Div1024 ((uint32_t)0x00000500) /*!< Each of the tamper inputs are sampled + with a frequency = RTCCLK / 1024 */ +#define RTC_TamperSamplingFreq_RTCCLK_Div512 ((uint32_t)0x00000600) /*!< Each of the tamper inputs are sampled + with a frequency = RTCCLK / 512 */ +#define RTC_TamperSamplingFreq_RTCCLK_Div256 ((uint32_t)0x00000700) /*!< Each of the tamper inputs are sampled + with a frequency = RTCCLK / 256 */ +#define IS_RTC_TAMPER_SAMPLING_FREQ(FREQ) (((FREQ) ==RTC_TamperSamplingFreq_RTCCLK_Div32768) || \ + ((FREQ) ==RTC_TamperSamplingFreq_RTCCLK_Div16384) || \ + ((FREQ) ==RTC_TamperSamplingFreq_RTCCLK_Div8192) || \ + ((FREQ) ==RTC_TamperSamplingFreq_RTCCLK_Div4096) || \ + ((FREQ) ==RTC_TamperSamplingFreq_RTCCLK_Div2048) || \ + ((FREQ) ==RTC_TamperSamplingFreq_RTCCLK_Div1024) || \ + ((FREQ) ==RTC_TamperSamplingFreq_RTCCLK_Div512) || \ + ((FREQ) ==RTC_TamperSamplingFreq_RTCCLK_Div256)) + +/** + * @} + */ + + /** @defgroup RTC_Tamper_Pin_Precharge_Duration_Definitions + * @{ + */ +#define RTC_TamperPrechargeDuration_1RTCCLK ((uint32_t)0x00000000) /*!< Tamper pins are pre-charged before + sampling during 1 RTCCLK cycle */ +#define RTC_TamperPrechargeDuration_2RTCCLK ((uint32_t)0x00002000) /*!< Tamper pins are pre-charged before + sampling during 2 RTCCLK cycles */ +#define RTC_TamperPrechargeDuration_4RTCCLK ((uint32_t)0x00004000) /*!< Tamper pins are pre-charged before + sampling during 4 RTCCLK cycles */ +#define RTC_TamperPrechargeDuration_8RTCCLK ((uint32_t)0x00006000) /*!< Tamper pins are pre-charged before + sampling during 8 RTCCLK cycles */ + +#define IS_RTC_TAMPER_PRECHARGE_DURATION(DURATION) (((DURATION) == RTC_TamperPrechargeDuration_1RTCCLK) || \ + ((DURATION) == RTC_TamperPrechargeDuration_2RTCCLK) || \ + ((DURATION) == RTC_TamperPrechargeDuration_4RTCCLK) || \ + ((DURATION) == RTC_TamperPrechargeDuration_8RTCCLK)) +/** + * @} + */ + +/** @defgroup RTC_Tamper_Pins_Definitions + * @{ + */ +#define RTC_Tamper_1 RTC_TAFCR_TAMP1E /*!< Tamper detection enable for + input tamper 1 */ +#define RTC_Tamper_2 RTC_TAFCR_TAMP2E /*!< Tamper detection enable for + input tamper 2 */ +#define RTC_Tamper_3 RTC_TAFCR_TAMP3E /*!< Tamper detection enable for + input tamper 3 */ + +#define IS_RTC_TAMPER(TAMPER) ((((TAMPER) & (uint32_t)0xFFFFFFD6) == 0x00) && ((TAMPER) != (uint32_t)RESET)) + + +/** + * @} + */ + +/** @defgroup RTC_Output_Type_ALARM_OUT + * @{ + */ +#define RTC_OutputType_OpenDrain ((uint32_t)0x00000000) +#define RTC_OutputType_PushPull ((uint32_t)0x00040000) +#define IS_RTC_OUTPUT_TYPE(TYPE) (((TYPE) == RTC_OutputType_OpenDrain) || \ + ((TYPE) == RTC_OutputType_PushPull)) + +/** + * @} + */ + +/** @defgroup RTC_Add_1_Second_Parameter_Definitions + * @{ + */ +#define RTC_ShiftAdd1S_Reset ((uint32_t)0x00000000) +#define RTC_ShiftAdd1S_Set ((uint32_t)0x80000000) +#define IS_RTC_SHIFT_ADD1S(SEL) (((SEL) == RTC_ShiftAdd1S_Reset) || \ + ((SEL) == RTC_ShiftAdd1S_Set)) +/** + * @} + */ + +/** @defgroup RTC_Substract_Fraction_Of_Second_Value + * @{ + */ +#define IS_RTC_SHIFT_SUBFS(FS) ((FS) <= 0x00007FFF) + +/** + * @} + */ + +/** @defgroup RTC_Backup_Registers_Definitions + * @{ + */ + +#define RTC_BKP_DR0 ((uint32_t)0x00000000) +#define RTC_BKP_DR1 ((uint32_t)0x00000001) +#define RTC_BKP_DR2 ((uint32_t)0x00000002) +#define RTC_BKP_DR3 ((uint32_t)0x00000003) +#define RTC_BKP_DR4 ((uint32_t)0x00000004) +#define RTC_BKP_DR5 ((uint32_t)0x00000005) +#define RTC_BKP_DR6 ((uint32_t)0x00000006) +#define RTC_BKP_DR7 ((uint32_t)0x00000007) +#define RTC_BKP_DR8 ((uint32_t)0x00000008) +#define RTC_BKP_DR9 ((uint32_t)0x00000009) +#define RTC_BKP_DR10 ((uint32_t)0x0000000A) +#define RTC_BKP_DR11 ((uint32_t)0x0000000B) +#define RTC_BKP_DR12 ((uint32_t)0x0000000C) +#define RTC_BKP_DR13 ((uint32_t)0x0000000D) +#define RTC_BKP_DR14 ((uint32_t)0x0000000E) +#define RTC_BKP_DR15 ((uint32_t)0x0000000F) +#define IS_RTC_BKP(BKP) (((BKP) == RTC_BKP_DR0) || \ + ((BKP) == RTC_BKP_DR1) || \ + ((BKP) == RTC_BKP_DR2) || \ + ((BKP) == RTC_BKP_DR3) || \ + ((BKP) == RTC_BKP_DR4) || \ + ((BKP) == RTC_BKP_DR5) || \ + ((BKP) == RTC_BKP_DR6) || \ + ((BKP) == RTC_BKP_DR7) || \ + ((BKP) == RTC_BKP_DR8) || \ + ((BKP) == RTC_BKP_DR9) || \ + ((BKP) == RTC_BKP_DR10) || \ + ((BKP) == RTC_BKP_DR11) || \ + ((BKP) == RTC_BKP_DR12) || \ + ((BKP) == RTC_BKP_DR13) || \ + ((BKP) == RTC_BKP_DR14) || \ + ((BKP) == RTC_BKP_DR15)) +/** + * @} + */ + +/** @defgroup RTC_Input_parameter_format_definitions + * @{ + */ +#define RTC_Format_BIN ((uint32_t)0x000000000) +#define RTC_Format_BCD ((uint32_t)0x000000001) +#define IS_RTC_FORMAT(FORMAT) (((FORMAT) == RTC_Format_BIN) || ((FORMAT) == RTC_Format_BCD)) + +/** + * @} + */ + +/** @defgroup RTC_Flags_Definitions + * @{ + */ +#define RTC_FLAG_RECALPF ((uint32_t)0x00010000) +#define RTC_FLAG_TAMP3F ((uint32_t)0x00008000) +#define RTC_FLAG_TAMP2F ((uint32_t)0x00004000) +#define RTC_FLAG_TAMP1F ((uint32_t)0x00002000) +#define RTC_FLAG_TSOVF ((uint32_t)0x00001000) +#define RTC_FLAG_TSF ((uint32_t)0x00000800) +#define RTC_FLAG_WUTF ((uint32_t)0x00000400) +#define RTC_FLAG_ALRBF ((uint32_t)0x00000200) +#define RTC_FLAG_ALRAF ((uint32_t)0x00000100) +#define RTC_FLAG_INITF ((uint32_t)0x00000040) +#define RTC_FLAG_RSF ((uint32_t)0x00000020) +#define RTC_FLAG_INITS ((uint32_t)0x00000010) +#define RTC_FLAG_SHPF ((uint32_t)0x00000008) +#define RTC_FLAG_WUTWF ((uint32_t)0x00000004) +#define RTC_FLAG_ALRBWF ((uint32_t)0x00000002) +#define RTC_FLAG_ALRAWF ((uint32_t)0x00000001) +#define IS_RTC_GET_FLAG(FLAG) (((FLAG) == RTC_FLAG_TSOVF) || ((FLAG) == RTC_FLAG_TSF) || \ + ((FLAG) == RTC_FLAG_WUTF) || ((FLAG) == RTC_FLAG_ALRBF) || \ + ((FLAG) == RTC_FLAG_ALRAF) || ((FLAG) == RTC_FLAG_INITF) || \ + ((FLAG) == RTC_FLAG_RSF) || ((FLAG) == RTC_FLAG_WUTWF) || \ + ((FLAG) == RTC_FLAG_ALRBWF) || ((FLAG) == RTC_FLAG_ALRAWF) || \ + ((FLAG) == RTC_FLAG_TAMP1F) || ((FLAG) == RTC_FLAG_TAMP2F) || \ + ((FLAG) == RTC_FLAG_TAMP3F) || ((FLAG) == RTC_FLAG_RECALPF) || \ + ((FLAG) == RTC_FLAG_SHPF)) +#define IS_RTC_CLEAR_FLAG(FLAG) (((FLAG) != (uint32_t)RESET) && (((FLAG) & 0xFFFF00DF) == (uint32_t)RESET)) + +/** + * @} + */ + +/** @defgroup RTC_Interrupts_Definitions + * @{ + */ +#define RTC_IT_TS ((uint32_t)0x00008000) +#define RTC_IT_WUT ((uint32_t)0x00004000) +#define RTC_IT_ALRB ((uint32_t)0x00002000) +#define RTC_IT_ALRA ((uint32_t)0x00001000) +#define RTC_IT_TAMP ((uint32_t)0x00000004) /* Used only to Enable the Tamper Interrupt */ +#define RTC_IT_TAMP1 ((uint32_t)0x00020000) +#define RTC_IT_TAMP2 ((uint32_t)0x00040000) +#define RTC_IT_TAMP3 ((uint32_t)0x00080000) + + +#define IS_RTC_CONFIG_IT(IT) (((IT) != (uint32_t)RESET) && (((IT) & 0xFFFF0FFB) == (uint32_t)RESET)) +#define IS_RTC_GET_IT(IT) (((IT) == RTC_IT_TS) || ((IT) == RTC_IT_WUT) || \ + ((IT) == RTC_IT_ALRB) || ((IT) == RTC_IT_ALRA) || \ + ((IT) == RTC_IT_TAMP1) || ((IT) == RTC_IT_TAMP2) || \ + ((IT) == RTC_IT_TAMP3)) +#define IS_RTC_CLEAR_IT(IT) (((IT) != (uint32_t)RESET) && (((IT) & 0xFFF10FFF) == (uint32_t)RESET)) + +/** + * @} + */ + +/** + * @} + */ + + +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions ------------------------------------------------------- */ + +/* Function used to set the RTC configuration to the default reset state *****/ +ErrorStatus RTC_DeInit(void); + + +/* Initialization and Configuration functions *********************************/ +ErrorStatus RTC_Init(RTC_InitTypeDef* RTC_InitStruct); +void RTC_StructInit(RTC_InitTypeDef* RTC_InitStruct); +void RTC_WriteProtectionCmd(FunctionalState NewState); +ErrorStatus RTC_EnterInitMode(void); +void RTC_ExitInitMode(void); +ErrorStatus RTC_WaitForSynchro(void); +ErrorStatus RTC_RefClockCmd(FunctionalState NewState); +void RTC_BypassShadowCmd(FunctionalState NewState); + +/* Time and Date configuration functions **************************************/ +ErrorStatus RTC_SetTime(uint32_t RTC_Format, RTC_TimeTypeDef* RTC_TimeStruct); +void RTC_TimeStructInit(RTC_TimeTypeDef* RTC_TimeStruct); +void RTC_GetTime(uint32_t RTC_Format, RTC_TimeTypeDef* RTC_TimeStruct); +uint32_t RTC_GetSubSecond(void); +ErrorStatus RTC_SetDate(uint32_t RTC_Format, RTC_DateTypeDef* RTC_DateStruct); +void RTC_DateStructInit(RTC_DateTypeDef* RTC_DateStruct); +void RTC_GetDate(uint32_t RTC_Format, RTC_DateTypeDef* RTC_DateStruct); + +/* Alarms (Alarm A and Alarm B) configuration functions **********************/ +void RTC_SetAlarm(uint32_t RTC_Format, uint32_t RTC_Alarm, RTC_AlarmTypeDef* RTC_AlarmStruct); +void RTC_AlarmStructInit(RTC_AlarmTypeDef* RTC_AlarmStruct); +void RTC_GetAlarm(uint32_t RTC_Format, uint32_t RTC_Alarm, RTC_AlarmTypeDef* RTC_AlarmStruct); +ErrorStatus RTC_AlarmCmd(uint32_t RTC_Alarm, FunctionalState NewState); +void RTC_AlarmSubSecondConfig(uint32_t RTC_Alarm, uint32_t RTC_AlarmSubSecondValue, uint32_t RTC_AlarmSubSecondMask); +uint32_t RTC_GetAlarmSubSecond(uint32_t RTC_Alarm); + +/* WakeUp Timer configuration functions ***************************************/ +void RTC_WakeUpClockConfig(uint32_t RTC_WakeUpClock); +void RTC_SetWakeUpCounter(uint32_t RTC_WakeUpCounter); +uint32_t RTC_GetWakeUpCounter(void); +ErrorStatus RTC_WakeUpCmd(FunctionalState NewState); + +/* Daylight Saving configuration functions ************************************/ +void RTC_DayLightSavingConfig(uint32_t RTC_DayLightSaving, uint32_t RTC_StoreOperation); +uint32_t RTC_GetStoreOperation(void); + +/* Output pin Configuration function ******************************************/ +void RTC_OutputConfig(uint32_t RTC_Output, uint32_t RTC_OutputPolarity); + +/* Digital Calibration configuration functions ********************************/ +void RTC_CalibOutputCmd(FunctionalState NewState); +void RTC_CalibOutputConfig(uint32_t RTC_CalibOutput); +ErrorStatus RTC_SmoothCalibConfig(uint32_t RTC_SmoothCalibPeriod, + uint32_t RTC_SmoothCalibPlusPulses, + uint32_t RTC_SmouthCalibMinusPulsesValue); + +/* TimeStamp configuration functions ******************************************/ +void RTC_TimeStampCmd(uint32_t RTC_TimeStampEdge, FunctionalState NewState); +void RTC_GetTimeStamp(uint32_t RTC_Format, RTC_TimeTypeDef* RTC_StampTimeStruct, + RTC_DateTypeDef* RTC_StampDateStruct); +uint32_t RTC_GetTimeStampSubSecond(void); + +/* Tampers configuration functions ********************************************/ +void RTC_TamperTriggerConfig(uint32_t RTC_Tamper, uint32_t RTC_TamperTrigger); +void RTC_TamperCmd(uint32_t RTC_Tamper, FunctionalState NewState); +void RTC_TamperFilterConfig(uint32_t RTC_TamperFilter); +void RTC_TamperSamplingFreqConfig(uint32_t RTC_TamperSamplingFreq); +void RTC_TamperPinsPrechargeDuration(uint32_t RTC_TamperPrechargeDuration); +void RTC_TimeStampOnTamperDetectionCmd(FunctionalState NewState); +void RTC_TamperPullUpCmd(FunctionalState NewState); + +/* Backup Data Registers configuration functions ******************************/ +void RTC_WriteBackupRegister(uint32_t RTC_BKP_DR, uint32_t Data); +uint32_t RTC_ReadBackupRegister(uint32_t RTC_BKP_DR); + +/* Output Type Config configuration functions *********************************/ +void RTC_OutputTypeConfig(uint32_t RTC_OutputType); + +/* RTC_Shift_control_synchonisation_functions *********************************/ +ErrorStatus RTC_SynchroShiftConfig(uint32_t RTC_ShiftAdd1S, uint32_t RTC_ShiftSubFS); + +/* Interrupts and flags management functions **********************************/ +void RTC_ITConfig(uint32_t RTC_IT, FunctionalState NewState); +FlagStatus RTC_GetFlagStatus(uint32_t RTC_FLAG); +void RTC_ClearFlag(uint32_t RTC_FLAG); +ITStatus RTC_GetITStatus(uint32_t RTC_IT); +void RTC_ClearITPendingBit(uint32_t RTC_IT); + +#ifdef __cplusplus +} +#endif + +#endif /*__STM32F30x_RTC_H */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_spi.h b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_spi.h new file mode 100755 index 0000000000..088fb2a894 --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_spi.h @@ -0,0 +1,608 @@ +/** + ****************************************************************************** + * @file stm32f30x_spi.h + * @author MCD Application Team + * @version V1.2.3 + * @date 10-July-2015 + * @brief This file contains all the functions prototypes for the SPI + * firmware library. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F30x_SPI_H +#define __STM32F30x_SPI_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f30x.h" + +/** @addtogroup STM32F30x_StdPeriph_Driver + * @{ + */ + +/** @addtogroup SPI + * @{ + */ + +/* Exported types ------------------------------------------------------------*/ + +/** + * @brief SPI Init structure definition + */ + +typedef struct +{ + uint16_t SPI_Direction; /*!< Specifies the SPI unidirectional or bidirectional data mode. + This parameter can be a value of @ref SPI_data_direction */ + + uint16_t SPI_Mode; /*!< Specifies the SPI mode (Master/Slave). + This parameter can be a value of @ref SPI_mode */ + + uint16_t SPI_DataSize; /*!< Specifies the SPI data size. + This parameter can be a value of @ref SPI_data_size */ + + uint16_t SPI_CPOL; /*!< Specifies the serial clock steady state. + This parameter can be a value of @ref SPI_Clock_Polarity */ + + uint16_t SPI_CPHA; /*!< Specifies the clock active edge for the bit capture. + This parameter can be a value of @ref SPI_Clock_Phase */ + + uint16_t SPI_NSS; /*!< Specifies whether the NSS signal is managed by + hardware (NSS pin) or by software using the SSI bit. + This parameter can be a value of @ref SPI_Slave_Select_management */ + + uint16_t SPI_BaudRatePrescaler; /*!< Specifies the Baud Rate prescaler value which will be + used to configure the transmit and receive SCK clock. + This parameter can be a value of @ref SPI_BaudRate_Prescaler. + @note The communication clock is derived from the master + clock. The slave clock does not need to be set. */ + + uint16_t SPI_FirstBit; /*!< Specifies whether data transfers start from MSB or LSB bit. + This parameter can be a value of @ref SPI_MSB_LSB_transmission */ + + uint16_t SPI_CRCPolynomial; /*!< Specifies the polynomial used for the CRC calculation. */ +}SPI_InitTypeDef; + + +/** + * @brief I2S Init structure definition + */ + +typedef struct +{ + uint16_t I2S_Mode; /*!< Specifies the I2S operating mode. + This parameter can be a value of @ref I2S_Mode */ + + uint16_t I2S_Standard; /*!< Specifies the standard used for the I2S communication. + This parameter can be a value of @ref I2S_Standard */ + + uint16_t I2S_DataFormat; /*!< Specifies the data format for the I2S communication. + This parameter can be a value of @ref I2S_Data_Format */ + + uint16_t I2S_MCLKOutput; /*!< Specifies whether the I2S MCLK output is enabled or not. + This parameter can be a value of @ref I2S_MCLK_Output */ + + uint32_t I2S_AudioFreq; /*!< Specifies the frequency selected for the I2S communication. + This parameter can be a value of @ref I2S_Audio_Frequency */ + + uint16_t I2S_CPOL; /*!< Specifies the idle state of the I2S clock. + This parameter can be a value of @ref I2S_Clock_Polarity */ +}I2S_InitTypeDef; + +/* Exported constants --------------------------------------------------------*/ + +/** @defgroup SPI_Exported_Constants + * @{ + */ + +#define IS_SPI_ALL_PERIPH(PERIPH) (((PERIPH) == SPI1) || \ + ((PERIPH) == SPI2) || \ + ((PERIPH) == SPI3) || \ + ((PERIPH) == SPI4)) + +#define IS_SPI_ALL_PERIPH_EXT(PERIPH) (((PERIPH) == SPI1) || \ + ((PERIPH) == SPI2) || \ + ((PERIPH) == SPI3) || \ + ((PERIPH) == SPI4) || \ + ((PERIPH) == I2S2ext) || \ + ((PERIPH) == I2S3ext)) + +#define IS_SPI_23_PERIPH(PERIPH) (((PERIPH) == SPI2) || \ + ((PERIPH) == SPI3)) + +#define IS_SPI_23_PERIPH_EXT(PERIPH) (((PERIPH) == SPI2) || \ + ((PERIPH) == SPI3) || \ + ((PERIPH) == I2S2ext) || \ + ((PERIPH) == I2S3ext)) + +#define IS_I2S_EXT_PERIPH(PERIPH) (((PERIPH) == I2S2ext) || \ + ((PERIPH) == I2S3ext)) + +/** @defgroup SPI_data_direction + * @{ + */ + +#define SPI_Direction_2Lines_FullDuplex ((uint16_t)0x0000) +#define SPI_Direction_2Lines_RxOnly ((uint16_t)0x0400) +#define SPI_Direction_1Line_Rx ((uint16_t)0x8000) +#define SPI_Direction_1Line_Tx ((uint16_t)0xC000) +#define IS_SPI_DIRECTION_MODE(MODE) (((MODE) == SPI_Direction_2Lines_FullDuplex) || \ + ((MODE) == SPI_Direction_2Lines_RxOnly) || \ + ((MODE) == SPI_Direction_1Line_Rx) || \ + ((MODE) == SPI_Direction_1Line_Tx)) +/** + * @} + */ + +/** @defgroup SPI_mode + * @{ + */ + +#define SPI_Mode_Master ((uint16_t)0x0104) +#define SPI_Mode_Slave ((uint16_t)0x0000) +#define IS_SPI_MODE(MODE) (((MODE) == SPI_Mode_Master) || \ + ((MODE) == SPI_Mode_Slave)) +/** + * @} + */ + +/** @defgroup SPI_data_size + * @{ + */ + +#define SPI_DataSize_4b ((uint16_t)0x0300) +#define SPI_DataSize_5b ((uint16_t)0x0400) +#define SPI_DataSize_6b ((uint16_t)0x0500) +#define SPI_DataSize_7b ((uint16_t)0x0600) +#define SPI_DataSize_8b ((uint16_t)0x0700) +#define SPI_DataSize_9b ((uint16_t)0x0800) +#define SPI_DataSize_10b ((uint16_t)0x0900) +#define SPI_DataSize_11b ((uint16_t)0x0A00) +#define SPI_DataSize_12b ((uint16_t)0x0B00) +#define SPI_DataSize_13b ((uint16_t)0x0C00) +#define SPI_DataSize_14b ((uint16_t)0x0D00) +#define SPI_DataSize_15b ((uint16_t)0x0E00) +#define SPI_DataSize_16b ((uint16_t)0x0F00) +#define IS_SPI_DATA_SIZE(SIZE) (((SIZE) == SPI_DataSize_4b) || \ + ((SIZE) == SPI_DataSize_5b) || \ + ((SIZE) == SPI_DataSize_6b) || \ + ((SIZE) == SPI_DataSize_7b) || \ + ((SIZE) == SPI_DataSize_8b) || \ + ((SIZE) == SPI_DataSize_9b) || \ + ((SIZE) == SPI_DataSize_10b) || \ + ((SIZE) == SPI_DataSize_11b) || \ + ((SIZE) == SPI_DataSize_12b) || \ + ((SIZE) == SPI_DataSize_13b) || \ + ((SIZE) == SPI_DataSize_14b) || \ + ((SIZE) == SPI_DataSize_15b) || \ + ((SIZE) == SPI_DataSize_16b)) +/** + * @} + */ + +/** @defgroup SPI_CRC_length + * @{ + */ + +#define SPI_CRCLength_8b ((uint16_t)0x0000) +#define SPI_CRCLength_16b ((uint16_t)0x0800) +#define IS_SPI_CRC_LENGTH(LENGTH) (((LENGTH) == SPI_CRCLength_8b) || \ + ((LENGTH) == SPI_CRCLength_16b)) +/** + * @} + */ + +/** @defgroup SPI_Clock_Polarity + * @{ + */ + +#define SPI_CPOL_Low ((uint16_t)0x0000) +#define SPI_CPOL_High ((uint16_t)0x0002) +#define IS_SPI_CPOL(CPOL) (((CPOL) == SPI_CPOL_Low) || \ + ((CPOL) == SPI_CPOL_High)) +/** + * @} + */ + +/** @defgroup SPI_Clock_Phase + * @{ + */ + +#define SPI_CPHA_1Edge ((uint16_t)0x0000) +#define SPI_CPHA_2Edge ((uint16_t)0x0001) +#define IS_SPI_CPHA(CPHA) (((CPHA) == SPI_CPHA_1Edge) || \ + ((CPHA) == SPI_CPHA_2Edge)) +/** + * @} + */ + +/** @defgroup SPI_Slave_Select_management + * @{ + */ + +#define SPI_NSS_Soft ((uint16_t)0x0200) +#define SPI_NSS_Hard ((uint16_t)0x0000) +#define IS_SPI_NSS(NSS) (((NSS) == SPI_NSS_Soft) || \ + ((NSS) == SPI_NSS_Hard)) +/** + * @} + */ + +/** @defgroup SPI_BaudRate_Prescaler + * @{ + */ + +#define SPI_BaudRatePrescaler_2 ((uint16_t)0x0000) +#define SPI_BaudRatePrescaler_4 ((uint16_t)0x0008) +#define SPI_BaudRatePrescaler_8 ((uint16_t)0x0010) +#define SPI_BaudRatePrescaler_16 ((uint16_t)0x0018) +#define SPI_BaudRatePrescaler_32 ((uint16_t)0x0020) +#define SPI_BaudRatePrescaler_64 ((uint16_t)0x0028) +#define SPI_BaudRatePrescaler_128 ((uint16_t)0x0030) +#define SPI_BaudRatePrescaler_256 ((uint16_t)0x0038) +#define IS_SPI_BAUDRATE_PRESCALER(PRESCALER) (((PRESCALER) == SPI_BaudRatePrescaler_2) || \ + ((PRESCALER) == SPI_BaudRatePrescaler_4) || \ + ((PRESCALER) == SPI_BaudRatePrescaler_8) || \ + ((PRESCALER) == SPI_BaudRatePrescaler_16) || \ + ((PRESCALER) == SPI_BaudRatePrescaler_32) || \ + ((PRESCALER) == SPI_BaudRatePrescaler_64) || \ + ((PRESCALER) == SPI_BaudRatePrescaler_128) || \ + ((PRESCALER) == SPI_BaudRatePrescaler_256)) +/** + * @} + */ + +/** @defgroup SPI_MSB_LSB_transmission + * @{ + */ + +#define SPI_FirstBit_MSB ((uint16_t)0x0000) +#define SPI_FirstBit_LSB ((uint16_t)0x0080) +#define IS_SPI_FIRST_BIT(BIT) (((BIT) == SPI_FirstBit_MSB) || \ + ((BIT) == SPI_FirstBit_LSB)) +/** + * @} + */ + +/** @defgroup I2S_Mode + * @{ + */ + +#define I2S_Mode_SlaveTx ((uint16_t)0x0000) +#define I2S_Mode_SlaveRx ((uint16_t)0x0100) +#define I2S_Mode_MasterTx ((uint16_t)0x0200) +#define I2S_Mode_MasterRx ((uint16_t)0x0300) +#define IS_I2S_MODE(MODE) (((MODE) == I2S_Mode_SlaveTx) || \ + ((MODE) == I2S_Mode_SlaveRx) || \ + ((MODE) == I2S_Mode_MasterTx)|| \ + ((MODE) == I2S_Mode_MasterRx)) +/** + * @} + */ + +/** @defgroup I2S_Standard + * @{ + */ + +#define I2S_Standard_Phillips ((uint16_t)0x0000) +#define I2S_Standard_MSB ((uint16_t)0x0010) +#define I2S_Standard_LSB ((uint16_t)0x0020) +#define I2S_Standard_PCMShort ((uint16_t)0x0030) +#define I2S_Standard_PCMLong ((uint16_t)0x00B0) +#define IS_I2S_STANDARD(STANDARD) (((STANDARD) == I2S_Standard_Phillips) || \ + ((STANDARD) == I2S_Standard_MSB) || \ + ((STANDARD) == I2S_Standard_LSB) || \ + ((STANDARD) == I2S_Standard_PCMShort) || \ + ((STANDARD) == I2S_Standard_PCMLong)) +/** + * @} + */ + +/** @defgroup I2S_Data_Format + * @{ + */ + +#define I2S_DataFormat_16b ((uint16_t)0x0000) +#define I2S_DataFormat_16bextended ((uint16_t)0x0001) +#define I2S_DataFormat_24b ((uint16_t)0x0003) +#define I2S_DataFormat_32b ((uint16_t)0x0005) +#define IS_I2S_DATA_FORMAT(FORMAT) (((FORMAT) == I2S_DataFormat_16b) || \ + ((FORMAT) == I2S_DataFormat_16bextended) || \ + ((FORMAT) == I2S_DataFormat_24b) || \ + ((FORMAT) == I2S_DataFormat_32b)) +/** + * @} + */ + +/** @defgroup I2S_MCLK_Output + * @{ + */ + +#define I2S_MCLKOutput_Enable ((uint16_t)0x0200) +#define I2S_MCLKOutput_Disable ((uint16_t)0x0000) +#define IS_I2S_MCLK_OUTPUT(OUTPUT) (((OUTPUT) == I2S_MCLKOutput_Enable) || \ + ((OUTPUT) == I2S_MCLKOutput_Disable)) +/** + * @} + */ + +/** @defgroup I2S_Audio_Frequency + * @{ + */ + +#define I2S_AudioFreq_192k ((uint32_t)192000) +#define I2S_AudioFreq_96k ((uint32_t)96000) +#define I2S_AudioFreq_48k ((uint32_t)48000) +#define I2S_AudioFreq_44k ((uint32_t)44100) +#define I2S_AudioFreq_32k ((uint32_t)32000) +#define I2S_AudioFreq_22k ((uint32_t)22050) +#define I2S_AudioFreq_16k ((uint32_t)16000) +#define I2S_AudioFreq_11k ((uint32_t)11025) +#define I2S_AudioFreq_8k ((uint32_t)8000) +#define I2S_AudioFreq_Default ((uint32_t)2) + +#define IS_I2S_AUDIO_FREQ(FREQ) ((((FREQ) >= I2S_AudioFreq_8k) && \ + ((FREQ) <= I2S_AudioFreq_192k)) || \ + ((FREQ) == I2S_AudioFreq_Default)) +/** + * @} + */ + +/** @defgroup I2S_Clock_Polarity + * @{ + */ + +#define I2S_CPOL_Low ((uint16_t)0x0000) +#define I2S_CPOL_High ((uint16_t)0x0008) +#define IS_I2S_CPOL(CPOL) (((CPOL) == I2S_CPOL_Low) || \ + ((CPOL) == I2S_CPOL_High)) +/** + * @} + */ + +/** @defgroup SPI_FIFO_reception_threshold + * @{ + */ + +#define SPI_RxFIFOThreshold_HF ((uint16_t)0x0000) +#define SPI_RxFIFOThreshold_QF ((uint16_t)0x1000) +#define IS_SPI_RX_FIFO_THRESHOLD(THRESHOLD) (((THRESHOLD) == SPI_RxFIFOThreshold_HF) || \ + ((THRESHOLD) == SPI_RxFIFOThreshold_QF)) +/** + * @} + */ + +/** @defgroup SPI_I2S_DMA_transfer_requests + * @{ + */ + +#define SPI_I2S_DMAReq_Tx ((uint16_t)0x0002) +#define SPI_I2S_DMAReq_Rx ((uint16_t)0x0001) +#define IS_SPI_I2S_DMA_REQ(REQ) ((((REQ) & (uint16_t)0xFFFC) == 0x00) && ((REQ) != 0x00)) +/** + * @} + */ + +/** @defgroup SPI_last_DMA_transfers + * @{ + */ + +#define SPI_LastDMATransfer_TxEvenRxEven ((uint16_t)0x0000) +#define SPI_LastDMATransfer_TxOddRxEven ((uint16_t)0x4000) +#define SPI_LastDMATransfer_TxEvenRxOdd ((uint16_t)0x2000) +#define SPI_LastDMATransfer_TxOddRxOdd ((uint16_t)0x6000) +#define IS_SPI_LAST_DMA_TRANSFER(TRANSFER) (((TRANSFER) == SPI_LastDMATransfer_TxEvenRxEven) || \ + ((TRANSFER) == SPI_LastDMATransfer_TxOddRxEven) || \ + ((TRANSFER) == SPI_LastDMATransfer_TxEvenRxOdd) || \ + ((TRANSFER) == SPI_LastDMATransfer_TxOddRxOdd)) +/** + * @} + */ +/** @defgroup SPI_NSS_internal_software_management + * @{ + */ + +#define SPI_NSSInternalSoft_Set ((uint16_t)0x0100) +#define SPI_NSSInternalSoft_Reset ((uint16_t)0xFEFF) +#define IS_SPI_NSS_INTERNAL(INTERNAL) (((INTERNAL) == SPI_NSSInternalSoft_Set) || \ + ((INTERNAL) == SPI_NSSInternalSoft_Reset)) +/** + * @} + */ + +/** @defgroup SPI_CRC_Transmit_Receive + * @{ + */ + +#define SPI_CRC_Tx ((uint8_t)0x00) +#define SPI_CRC_Rx ((uint8_t)0x01) +#define IS_SPI_CRC(CRC) (((CRC) == SPI_CRC_Tx) || ((CRC) == SPI_CRC_Rx)) +/** + * @} + */ + +/** @defgroup SPI_direction_transmit_receive + * @{ + */ + +#define SPI_Direction_Rx ((uint16_t)0xBFFF) +#define SPI_Direction_Tx ((uint16_t)0x4000) +#define IS_SPI_DIRECTION(DIRECTION) (((DIRECTION) == SPI_Direction_Rx) || \ + ((DIRECTION) == SPI_Direction_Tx)) +/** + * @} + */ + +/** @defgroup SPI_I2S_interrupts_definition + * @{ + */ + +#define SPI_I2S_IT_TXE ((uint8_t)0x71) +#define SPI_I2S_IT_RXNE ((uint8_t)0x60) +#define SPI_I2S_IT_ERR ((uint8_t)0x50) + +#define IS_SPI_I2S_CONFIG_IT(IT) (((IT) == SPI_I2S_IT_TXE) || \ + ((IT) == SPI_I2S_IT_RXNE) || \ + ((IT) == SPI_I2S_IT_ERR)) + +#define I2S_IT_UDR ((uint8_t)0x53) +#define SPI_IT_MODF ((uint8_t)0x55) +#define SPI_I2S_IT_OVR ((uint8_t)0x56) +#define SPI_I2S_IT_FRE ((uint8_t)0x58) + +#define IS_SPI_I2S_GET_IT(IT) (((IT) == SPI_I2S_IT_RXNE) || ((IT) == SPI_I2S_IT_TXE) || \ + ((IT) == SPI_I2S_IT_OVR) || ((IT) == SPI_IT_MODF) || \ + ((IT) == SPI_I2S_IT_FRE)|| ((IT) == I2S_IT_UDR)) +/** + * @} + */ + + +/** @defgroup SPI_transmission_fifo_status_level + * @{ + */ + +#define SPI_TransmissionFIFOStatus_Empty ((uint16_t)0x0000) +#define SPI_TransmissionFIFOStatus_1QuarterFull ((uint16_t)0x0800) +#define SPI_TransmissionFIFOStatus_HalfFull ((uint16_t)0x1000) +#define SPI_TransmissionFIFOStatus_Full ((uint16_t)0x1800) + +/** + * @} + */ + +/** @defgroup SPI_reception_fifo_status_level + * @{ + */ +#define SPI_ReceptionFIFOStatus_Empty ((uint16_t)0x0000) +#define SPI_ReceptionFIFOStatus_1QuarterFull ((uint16_t)0x0200) +#define SPI_ReceptionFIFOStatus_HalfFull ((uint16_t)0x0400) +#define SPI_ReceptionFIFOStatus_Full ((uint16_t)0x0600) + +/** + * @} + */ + + +/** @defgroup SPI_I2S_flags_definition + * @{ + */ + +#define SPI_I2S_FLAG_RXNE ((uint16_t)0x0001) +#define SPI_I2S_FLAG_TXE ((uint16_t)0x0002) +#define I2S_FLAG_CHSIDE ((uint16_t)0x0004) +#define I2S_FLAG_UDR ((uint16_t)0x0008) +#define SPI_FLAG_CRCERR ((uint16_t)0x0010) +#define SPI_FLAG_MODF ((uint16_t)0x0020) +#define SPI_I2S_FLAG_OVR ((uint16_t)0x0040) +#define SPI_I2S_FLAG_BSY ((uint16_t)0x0080) +#define SPI_I2S_FLAG_FRE ((uint16_t)0x0100) + + + +#define IS_SPI_CLEAR_FLAG(FLAG) (((FLAG) == SPI_FLAG_CRCERR)) +#define IS_SPI_I2S_GET_FLAG(FLAG) (((FLAG) == SPI_I2S_FLAG_BSY) || ((FLAG) == SPI_I2S_FLAG_OVR) || \ + ((FLAG) == SPI_FLAG_MODF) || ((FLAG) == SPI_FLAG_CRCERR) || \ + ((FLAG) == SPI_I2S_FLAG_TXE) || ((FLAG) == SPI_I2S_FLAG_RXNE)|| \ + ((FLAG) == SPI_I2S_FLAG_FRE)|| ((FLAG) == I2S_FLAG_CHSIDE)|| \ + ((FLAG) == I2S_FLAG_UDR)) +/** + * @} + */ + +/** @defgroup SPI_CRC_polynomial + * @{ + */ + +#define IS_SPI_CRC_POLYNOMIAL(POLYNOMIAL) ((POLYNOMIAL) >= 0x1) +/** + * @} + */ + +/** + * @} + */ + +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions ------------------------------------------------------- */ + +/* Function used to set the SPI configuration to the default reset state*******/ +void SPI_I2S_DeInit(SPI_TypeDef* SPIx); + +/* Initialization and Configuration functions *********************************/ +void SPI_Init(SPI_TypeDef* SPIx, SPI_InitTypeDef* SPI_InitStruct); +void I2S_Init(SPI_TypeDef* SPIx, I2S_InitTypeDef* I2S_InitStruct); +void SPI_StructInit(SPI_InitTypeDef* SPI_InitStruct); +void I2S_StructInit(I2S_InitTypeDef* I2S_InitStruct); +void SPI_TIModeCmd(SPI_TypeDef* SPIx, FunctionalState NewState); +void SPI_NSSPulseModeCmd(SPI_TypeDef* SPIx, FunctionalState NewState); +void SPI_Cmd(SPI_TypeDef* SPIx, FunctionalState NewState); +void I2S_Cmd(SPI_TypeDef* SPIx, FunctionalState NewState); +void SPI_DataSizeConfig(SPI_TypeDef* SPIx, uint16_t SPI_DataSize); +void SPI_RxFIFOThresholdConfig(SPI_TypeDef* SPIx, uint16_t SPI_RxFIFOThreshold); +void SPI_BiDirectionalLineConfig(SPI_TypeDef* SPIx, uint16_t SPI_Direction); +void SPI_NSSInternalSoftwareConfig(SPI_TypeDef* SPIx, uint16_t SPI_NSSInternalSoft); +void SPI_SSOutputCmd(SPI_TypeDef* SPIx, FunctionalState NewState); +void I2S_FullDuplexConfig(SPI_TypeDef* I2Sxext, I2S_InitTypeDef* I2S_InitStruct); + +/* Data transfers functions ***************************************************/ +void SPI_SendData8(SPI_TypeDef* SPIx, uint8_t Data); +void SPI_I2S_SendData16(SPI_TypeDef* SPIx, uint16_t Data); +uint8_t SPI_ReceiveData8(SPI_TypeDef* SPIx); +uint16_t SPI_I2S_ReceiveData16(SPI_TypeDef* SPIx); + +/* Hardware CRC Calculation functions *****************************************/ +void SPI_CRCLengthConfig(SPI_TypeDef* SPIx, uint16_t SPI_CRCLength); +void SPI_CalculateCRC(SPI_TypeDef* SPIx, FunctionalState NewState); +void SPI_TransmitCRC(SPI_TypeDef* SPIx); +uint16_t SPI_GetCRC(SPI_TypeDef* SPIx, uint8_t SPI_CRC); +uint16_t SPI_GetCRCPolynomial(SPI_TypeDef* SPIx); + +/* DMA transfers management functions *****************************************/ +void SPI_I2S_DMACmd(SPI_TypeDef* SPIx, uint16_t SPI_I2S_DMAReq, FunctionalState NewState); +void SPI_LastDMATransferCmd(SPI_TypeDef* SPIx, uint16_t SPI_LastDMATransfer); + +/* Interrupts and flags management functions **********************************/ +void SPI_I2S_ITConfig(SPI_TypeDef* SPIx, uint8_t SPI_I2S_IT, FunctionalState NewState); +uint16_t SPI_GetTransmissionFIFOStatus(SPI_TypeDef* SPIx); +uint16_t SPI_GetReceptionFIFOStatus(SPI_TypeDef* SPIx); +FlagStatus SPI_I2S_GetFlagStatus(SPI_TypeDef* SPIx, uint16_t SPI_I2S_FLAG); +void SPI_I2S_ClearFlag(SPI_TypeDef* SPIx, uint16_t SPI_I2S_FLAG); +ITStatus SPI_I2S_GetITStatus(SPI_TypeDef* SPIx, uint8_t SPI_I2S_IT); + +#ifdef __cplusplus +} +#endif + +#endif /*__STM32F30x_SPI_H */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_syscfg.h b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_syscfg.h new file mode 100755 index 0000000000..cbf3bddc18 --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_syscfg.h @@ -0,0 +1,427 @@ +/** + ****************************************************************************** + * @file stm32f30x_syscfg.h + * @author MCD Application Team + * @version V1.2.3 + * @date 10-July-2015 + * @brief This file contains all the functions prototypes for the SYSCFG firmware + * library. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/*!< Define to prevent recursive inclusion -----------------------------------*/ +#ifndef __STM32F30x_SYSCFG_H +#define __STM32F30x_SYSCFG_H + +#ifdef __cplusplus + extern "C" { +#endif + +/*!< Includes ----------------------------------------------------------------*/ +#include "stm32f30x.h" + +/** @addtogroup STM32F30x_StdPeriph_Driver + * @{ + */ + +/** @addtogroup SYSCFG + * @{ + */ + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +/** @defgroup SYSCFG_Exported_Constants + * @{ + */ + +/** @defgroup SYSCFG_EXTI_Port_Sources + * @{ + */ +#define EXTI_PortSourceGPIOA ((uint8_t)0x00) +#define EXTI_PortSourceGPIOB ((uint8_t)0x01) +#define EXTI_PortSourceGPIOC ((uint8_t)0x02) +#define EXTI_PortSourceGPIOD ((uint8_t)0x03) +#define EXTI_PortSourceGPIOE ((uint8_t)0x04) +#define EXTI_PortSourceGPIOF ((uint8_t)0x05) +#define EXTI_PortSourceGPIOG ((uint8_t)0x06) +#define EXTI_PortSourceGPIOH ((uint8_t)0x07) + +#define IS_EXTI_PORT_SOURCE(PORTSOURCE) (((PORTSOURCE) == EXTI_PortSourceGPIOA) || \ + ((PORTSOURCE) == EXTI_PortSourceGPIOB) || \ + ((PORTSOURCE) == EXTI_PortSourceGPIOC) || \ + ((PORTSOURCE) == EXTI_PortSourceGPIOD) || \ + ((PORTSOURCE) == EXTI_PortSourceGPIOE) || \ + ((PORTSOURCE) == EXTI_PortSourceGPIOF)|| \ + ((PORTSOURCE) == EXTI_PortSourceGPIOG)|| \ + ((PORTSOURCE) == EXTI_PortSourceGPIOH)) +/** + * @} + */ + +/** @defgroup SYSCFG_EXTI_Pin_sources + * @{ + */ +#define EXTI_PinSource0 ((uint8_t)0x00) +#define EXTI_PinSource1 ((uint8_t)0x01) +#define EXTI_PinSource2 ((uint8_t)0x02) +#define EXTI_PinSource3 ((uint8_t)0x03) +#define EXTI_PinSource4 ((uint8_t)0x04) +#define EXTI_PinSource5 ((uint8_t)0x05) +#define EXTI_PinSource6 ((uint8_t)0x06) +#define EXTI_PinSource7 ((uint8_t)0x07) +#define EXTI_PinSource8 ((uint8_t)0x08) +#define EXTI_PinSource9 ((uint8_t)0x09) +#define EXTI_PinSource10 ((uint8_t)0x0A) +#define EXTI_PinSource11 ((uint8_t)0x0B) +#define EXTI_PinSource12 ((uint8_t)0x0C) +#define EXTI_PinSource13 ((uint8_t)0x0D) +#define EXTI_PinSource14 ((uint8_t)0x0E) +#define EXTI_PinSource15 ((uint8_t)0x0F) + +#define IS_EXTI_PIN_SOURCE(PINSOURCE) (((PINSOURCE) == EXTI_PinSource0) || \ + ((PINSOURCE) == EXTI_PinSource1) || \ + ((PINSOURCE) == EXTI_PinSource2) || \ + ((PINSOURCE) == EXTI_PinSource3) || \ + ((PINSOURCE) == EXTI_PinSource4) || \ + ((PINSOURCE) == EXTI_PinSource5) || \ + ((PINSOURCE) == EXTI_PinSource6) || \ + ((PINSOURCE) == EXTI_PinSource7) || \ + ((PINSOURCE) == EXTI_PinSource8) || \ + ((PINSOURCE) == EXTI_PinSource9) || \ + ((PINSOURCE) == EXTI_PinSource10) || \ + ((PINSOURCE) == EXTI_PinSource11) || \ + ((PINSOURCE) == EXTI_PinSource12) || \ + ((PINSOURCE) == EXTI_PinSource13) || \ + ((PINSOURCE) == EXTI_PinSource14) || \ + ((PINSOURCE) == EXTI_PinSource15)) +/** + * @} + */ + +/** @defgroup SYSCFG_Memory_Remap_Config + * @{ + */ +#define SYSCFG_MemoryRemap_Flash ((uint8_t)0x00) +#define SYSCFG_MemoryRemap_SystemMemory ((uint8_t)0x01) +#define SYSCFG_MemoryRemap_SRAM ((uint8_t)0x03) +#define SYSCFG_MemoryRemap_FMC ((uint8_t)0x04) + + +#define IS_SYSCFG_MEMORY_REMAP(REMAP) (((REMAP) == SYSCFG_MemoryRemap_Flash) || \ + ((REMAP) == SYSCFG_MemoryRemap_SystemMemory) || \ + ((REMAP) == SYSCFG_MemoryRemap_SRAM) || \ + ((REMAP) == SYSCFG_MemoryRemap_FMC)) + +/** + * @} + */ + +/** @defgroup SYSCFG_DMA_Remap_Config + * @{ + */ +#define SYSCFG_DMARemap_TIM17 SYSCFG_CFGR1_TIM17_DMA_RMP /*!< Remap TIM17 DMA requests from channel1 to channel2 */ +#define SYSCFG_DMARemap_TIM16 SYSCFG_CFGR1_TIM16_DMA_RMP /*!< Remap TIM16 DMA requests from channel3 to channel4 */ +#define SYSCFG_DMARemap_ADC2ADC4 SYSCFG_CFGR1_ADC24_DMA_RMP /*!< Remap ADC2 and ADC4 DMA requests */ + +#define SYSCFG_DMARemap_TIM6DAC1Ch1 SYSCFG_CFGR1_TIM6DAC1Ch1_DMA_RMP /* Remap TIM6/DAC1 Ch1 DMA requests */ +#define SYSCFG_DMARemap_TIM7DAC1Ch2 SYSCFG_CFGR1_TIM7DAC1Ch2_DMA_RMP /* Remap TIM7/DAC1 Ch2 DMA requests */ +#define SYSCFG_DMARemap_DAC2Ch1 SYSCFG_CFGR1_DAC2Ch1_DMA_RMP /* Remap DAC2 Ch1 DMA requests */ + +#define SYSCFG_DMARemapCh2_SPI1_RX ((uint32_t)0x80000003) /* Remap SPI1 RX DMA CH2 requests */ +#define SYSCFG_DMARemapCh4_SPI1_RX ((uint32_t)0x80000001) /* Remap SPI1 RX DMA CH4 requests */ +#define SYSCFG_DMARemapCh6_SPI1_RX ((uint32_t)0x80000002) /* Remap SPI1 RX DMA CH6 requests */ + +#define SYSCFG_DMARemapCh3_SPI1_TX ((uint32_t)0x8000000C) /* Remap SPI1 TX DMA CH2 requests */ +#define SYSCFG_DMARemapCh5_SPI1_TX ((uint32_t)0x80000004) /* Remap SPI1 TX DMA CH5 requests */ +#define SYSCFG_DMARemapCh7_SPI1_TX ((uint32_t)0x80000008) /* Remap SPI1 TX DMA CH7 requests */ + +#define SYSCFG_DMARemapCh7_I2C1_RX ((uint32_t)0x80000030) /* Remap I2C1 RX DMA CH7 requests */ +#define SYSCFG_DMARemapCh3_I2C1_RX ((uint32_t)0x80000010) /* Remap I2C1 RX DMA CH3 requests */ +#define SYSCFG_DMARemapCh5_I2C1_RX ((uint32_t)0x80000020) /* Remap I2C1 RX DMA CH5 requests */ + +#define SYSCFG_DMARemapCh6_I2C1_TX ((uint32_t)0x800000C0) /* Remap I2C1 TX DMA CH6 requests */ +#define SYSCFG_DMARemapCh2_I2C1_TX ((uint32_t)0x80000040) /* Remap I2C1 TX DMA CH2 requests */ +#define SYSCFG_DMARemapCh4_I2C1_TX ((uint32_t)0x80000080) /* Remap I2C1 TX DMA CH4 requests */ + +#define SYSCFG_DMARemapCh4_ADC2 ((uint32_t)0x80000300) /* Remap ADC2 DMA1 Ch4 requests */ +#define SYSCFG_DMARemapCh2_ADC2 ((uint32_t)0x80000200) /* Remap ADC2 DMA1 Ch2 requests */ + +/* SYSCFG_DMA_Remap_Legacy */ +#define SYSCFG_DMARemap_TIM6DAC1 SYSCFG_DMARemap_TIM6DAC1Ch1 /*!< Remap TIM6/DAC1 DMA requests */ +#define SYSCFG_DMARemap_TIM7DAC2 SYSCFG_DMARemap_TIM7DAC1Ch2 /*!< Remap TIM7/DAC2 DMA requests */ + +#define IS_SYSCFG_DMA_REMAP(REMAP) (((REMAP) == SYSCFG_DMARemap_TIM17) || \ + ((REMAP) == SYSCFG_DMARemap_TIM16) || \ + ((REMAP) == SYSCFG_DMARemap_ADC2ADC4) || \ + ((REMAP) == SYSCFG_DMARemap_TIM6DAC1Ch1) || \ + ((REMAP) == SYSCFG_DMARemap_TIM7DAC1Ch2) || \ + ((REMAP) == SYSCFG_DMARemap_DAC2Ch1) || \ + ((REMAP) == SYSCFG_DMARemapCh2_SPI1_RX) || \ + ((REMAP) == SYSCFG_DMARemapCh4_SPI1_RX) || \ + ((REMAP) == SYSCFG_DMARemapCh6_SPI1_RX) || \ + ((REMAP) == SYSCFG_DMARemapCh5_SPI1_TX) || \ + ((REMAP) == SYSCFG_DMARemapCh5_SPI1_TX) || \ + ((REMAP) == SYSCFG_DMARemapCh7_SPI1_TX) || \ + ((REMAP) == SYSCFG_DMARemapCh7_I2C1_RX) || \ + ((REMAP) == SYSCFG_DMARemapCh3_I2C1_RX) || \ + ((REMAP) == SYSCFG_DMARemapCh5_I2C1_RX) || \ + ((REMAP) == SYSCFG_DMARemapCh6_I2C1_TX) || \ + ((REMAP) == SYSCFG_DMARemapCh2_I2C1_TX) || \ + ((REMAP) == SYSCFG_DMARemapCh4_I2C1_TX) || \ + ((REMAP) == SYSCFG_DMARemapCh4_ADC2) || \ + ((REMAP) == SYSCFG_DMARemapCh2_ADC2)) + +/** + * @} + */ + +/** @defgroup SYSCFG_Trigger_Remap_Config + * @{ + */ +#define SYSCFG_TriggerRemap_DACTIM3 SYSCFG_CFGR1_DAC1_TRIG1_RMP /*!< Remap DAC trigger to TIM3 */ +#define SYSCFG_TriggerRemap_TIM1TIM17 SYSCFG_CFGR1_TIM1_ITR3_RMP /*!< Remap TIM1 ITR3 to TIM17 OC */ +#define SYSCFG_TriggerRemap_DACHRTIM1_TRIG1 ((uint32_t)0x80010000) /*!< Remap DAC trigger to HRTIM1 TRIG1 */ +#define SYSCFG_TriggerRemap_DACHRTIM1_TRIG2 ((uint32_t)0x80020000) /*!< Remap DAC trigger to HRTIM1 TRIG2 */ + +#define IS_SYSCFG_TRIGGER_REMAP(REMAP) (((REMAP) == SYSCFG_TriggerRemap_DACTIM3) || \ + ((REMAP) == SYSCFG_TriggerRemap_DACHRTIM1_TRIG1) || \ + ((REMAP) == SYSCFG_TriggerRemap_DACHRTIM1_TRIG2) || \ + ((REMAP) == SYSCFG_TriggerRemap_TIM1TIM17)) + +/** + * @} + */ + +/** @defgroup SYSCFG_EncoderRemap_Config + * @{ + */ +#define SYSCFG_EncoderRemap_No ((uint32_t)0x00000000) /*!< No redirection */ +#define SYSCFG_EncoderRemap_TIM2 SYSCFG_CFGR1_ENCODER_MODE_0 /*!< Timer 2 IC1 and IC2 connected to TIM15 IC1 and IC2 */ +#define SYSCFG_EncoderRemap_TIM3 SYSCFG_CFGR1_ENCODER_MODE_1 /*!< Timer 3 IC1 and IC2 connected to TIM15 IC1 and IC2 */ +#define SYSCFG_EncoderRemap_TIM4 SYSCFG_CFGR1_ENCODER_MODE /*!< Timer 4 IC1 and IC2 connected to TIM15 IC1 and IC2 */ + +#define IS_SYSCFG_ENCODER_REMAP(REMAP) (((REMAP) == SYSCFG_EncoderRemap_No) || \ + ((REMAP) == SYSCFG_EncoderRemap_TIM2) || \ + ((REMAP) == SYSCFG_EncoderRemap_TIM3) || \ + ((REMAP) == SYSCFG_EncoderRemap_TIM4)) + +/** + * @} + */ + +/** @defgroup SYSCFG_I2C_FastModePlus_Config + * @{ + */ +#define SYSCFG_I2CFastModePlus_PB6 SYSCFG_CFGR1_I2C_PB6_FMP /*!< Enable Fast Mode Plus on PB6 */ +#define SYSCFG_I2CFastModePlus_PB7 SYSCFG_CFGR1_I2C_PB7_FMP /*!< Enable Fast Mode Plus on PB7 */ +#define SYSCFG_I2CFastModePlus_PB8 SYSCFG_CFGR1_I2C_PB8_FMP /*!< Enable Fast Mode Plus on PB8 */ +#define SYSCFG_I2CFastModePlus_PB9 SYSCFG_CFGR1_I2C_PB9_FMP /*!< Enable Fast Mode Plus on PB9 */ +#define SYSCFG_I2CFastModePlus_I2C1 SYSCFG_CFGR1_I2C1_FMP /*!< Enable Fast Mode Plus on I2C1 pins */ +#define SYSCFG_I2CFastModePlus_I2C2 SYSCFG_CFGR1_I2C2_FMP /*!< Enable Fast Mode Plus on I2C2 pins */ +#define SYSCFG_I2CFastModePlus_I2C3 SYSCFG_CFGR1_I2C3_FMP /*!< Enable Fast Mode Plus on I2C3 pins */ + +#define IS_SYSCFG_I2C_FMP(PIN) (((PIN) == SYSCFG_I2CFastModePlus_PB6) || \ + ((PIN) == SYSCFG_I2CFastModePlus_PB7) || \ + ((PIN) == SYSCFG_I2CFastModePlus_PB8) || \ + ((PIN) == SYSCFG_I2CFastModePlus_PB9) || \ + ((PIN) == SYSCFG_I2CFastModePlus_I2C1) || \ + ((PIN) == SYSCFG_I2CFastModePlus_I2C2)|| \ + ((PIN) == SYSCFG_I2CFastModePlus_I2C3)) + +/** + * @} + */ + +/** @defgroup SYSCFG_FPU_Interrupt_Config + * @{ + */ +#define SYSCFG_IT_IXC SYSCFG_CFGR1_FPU_IE_5 /*!< Inexact Interrupt enable (interrupt disabled by default) */ +#define SYSCFG_IT_IDC SYSCFG_CFGR1_FPU_IE_4 /*!< Input denormal Interrupt enable */ +#define SYSCFG_IT_OFC SYSCFG_CFGR1_FPU_IE_3 /*!< Overflow Interrupt enable */ +#define SYSCFG_IT_UFC SYSCFG_CFGR1_FPU_IE_2 /*!< Underflow Interrupt enable */ +#define SYSCFG_IT_DZC SYSCFG_CFGR1_FPU_IE_1 /*!< Divide-by-zero Interrupt enable */ +#define SYSCFG_IT_IOC SYSCFG_CFGR1_FPU_IE_0 /*!< Invalid operation Interrupt enable */ + +#define IS_SYSCFG_IT(IT) ((((IT) & (uint32_t)0x03FFFFFF) == 0) && ((IT) != 0)) + +/** + * @} + */ + +/** @defgroup SYSCFG_Lock_Config + * @{ + */ +#define SYSCFG_Break_PVD SYSCFG_CFGR2_PVD_LOCK /*!< Enables and locks the PVD connection with TIM1/8/15/16/17 Break Input and also the PVD_EN and PVDSEL[2:0] bits of the Power Control Interface */ +#define SYSCFG_Break_SRAMParity SYSCFG_CFGR2_SRAM_PARITY_LOCK /*!< Enables and locks the SRAM_PARITY error signal with Break Input of TIM1/8/15/16/17 */ +#define SYSCFG_Break_Lockup SYSCFG_CFGR2_LOCKUP_LOCK /*!< Enables and locks the LOCKUP output of CortexM4 with Break Input of TIM1/8/15/16/17 */ + +#define IS_SYSCFG_LOCK_CONFIG(CONFIG) (((CONFIG) == SYSCFG_Break_PVD) || \ + ((CONFIG) == SYSCFG_Break_SRAMParity) || \ + ((CONFIG) == SYSCFG_Break_Lockup)) + +/** + * @} + */ + +/** @defgroup ADC_Trigger_Remapping + * @{ + */ +#define REMAPADCTRIGGER_ADC12_EXT2 SYSCFG_CFGR4_ADC12_EXT2_RMP /*!< Input trigger of ADC12 regular channel EXT2 + 0: No remap (TIM1_CC3) + 1: Remap (TIM20_TRGO) */ +#define REMAPADCTRIGGER_ADC12_EXT3 SYSCFG_CFGR4_ADC12_EXT3_RMP /*!< Input trigger of ADC12 regular channel EXT3 + 0: No remap (TIM2_CC2) + 1: Remap (TIM20_TRGO2) */ +#define REMAPADCTRIGGER_ADC12_EXT5 SYSCFG_CFGR4_ADC12_EXT5_RMP /*!< Input trigger of ADC12 regular channel EXT5 + 0: No remap (TIM4_CC4) + 1: Remap (TIM20_CC1) */ +#define REMAPADCTRIGGER_ADC12_EXT13 SYSCFG_CFGR4_ADC12_EXT13_RMP /*!< Input trigger of ADC12 regular channel EXT13 + 0: No remap (TIM6_TRGO) + 1: Remap (TIM20_CC2) */ +#define REMAPADCTRIGGER_ADC12_EXT15 SYSCFG_CFGR4_ADC12_EXT15_RMP /*!< Input trigger of ADC12 regular channel EXT15 + 0: No remap (TIM3_CC4) + 1: Remap (TIM20_CC3) */ +#define REMAPADCTRIGGER_ADC12_JEXT3 SYSCFG_CFGR4_ADC12_JEXT3_RMP /*!< Input trigger of ADC12 injected channel JEXT3 + 0: No remap (TIM2_CC1) + 1: Remap (TIM20_TRGO) */ +#define REMAPADCTRIGGER_ADC12_JEXT6 SYSCFG_CFGR4_ADC12_JEXT6_RMP /*!< Input trigger of ADC12 injected channel JEXT6 + 0: No remap (EXTI line 15) + 1: Remap (TIM20_TRGO2) */ +#define REMAPADCTRIGGER_ADC12_JEXT13 SYSCFG_CFGR4_ADC12_JEXT13_RMP /*!< Input trigger of ADC12 injected channel JEXT13 + 0: No remap (TIM3_CC1) + 1: Remap (TIM20_CC4) */ +#define REMAPADCTRIGGER_ADC34_EXT5 SYSCFG_CFGR4_ADC34_EXT5_RMP /*!< Input trigger of ADC34 regular channel EXT5 + 0: No remap (EXTI line 2) + 1: Remap (TIM20_TRGO) */ +#define REMAPADCTRIGGER_ADC34_EXT6 SYSCFG_CFGR4_ADC34_EXT6_RMP /*!< Input trigger of ADC34 regular channel EXT6 + 0: No remap (TIM4_CC1) + 1: Remap (TIM20_TRGO2) */ +#define REMAPADCTRIGGER_ADC34_EXT15 SYSCFG_CFGR4_ADC34_EXT15_RMP /*!< Input trigger of ADC34 regular channel EXT15 + 0: No remap (TIM2_CC1) + 1: Remap (TIM20_CC1) */ +#define REMAPADCTRIGGER_ADC34_JEXT5 SYSCFG_CFGR4_ADC34_JEXT5_RMP /*!< Input trigger of ADC34 injected channel JEXT5 + 0: No remap (TIM4_CC3) + 1: Remap (TIM20_TRGO) */ +#define REMAPADCTRIGGER_ADC34_JEXT11 SYSCFG_CFGR4_ADC34_JEXT11_RMP /*!< Input trigger of ADC34 injected channel JEXT11 + 0: No remap (TIM1_CC3) + 1: Remap (TIM20_TRGO2) */ +#define REMAPADCTRIGGER_ADC34_JEXT14 SYSCFG_CFGR4_ADC34_JEXT14_RMP /*!< Input trigger of ADC34 injected channel JEXT14 + 0: No remap (TIM7_TRGO) + 1: Remap (TIM20_CC2) */ + +#define IS_SYSCFG_ADC_TRIGGER_REMAP(RMP) (((RMP) == REMAPADCTRIGGER_ADC12_EXT2) || \ + ((RMP) == REMAPADCTRIGGER_ADC12_EXT3) || \ + ((RMP) == REMAPADCTRIGGER_ADC12_EXT5) || \ + ((RMP) == REMAPADCTRIGGER_ADC12_EXT13) || \ + ((RMP) == REMAPADCTRIGGER_ADC12_EXT15) || \ + ((RMP) == REMAPADCTRIGGER_ADC12_JEXT3) || \ + ((RMP) == REMAPADCTRIGGER_ADC12_JEXT6) || \ + ((RMP) == REMAPADCTRIGGER_ADC12_JEXT13) || \ + ((RMP) == REMAPADCTRIGGER_ADC34_EXT5) || \ + ((RMP) == REMAPADCTRIGGER_ADC34_EXT6) || \ + ((RMP) == REMAPADCTRIGGER_ADC34_EXT15) || \ + ((RMP) == REMAPADCTRIGGER_ADC34_JEXT5) || \ + ((RMP) == REMAPADCTRIGGER_ADC34_JEXT11) || \ + ((RMP) == REMAPADCTRIGGER_ADC34_JEXT14)) + +/** + * @} + */ + +/** @defgroup SYSCFG_SRAMWRP_Config + * @{ + */ +#define SYSCFG_SRAMWRP_Page0 SYSCFG_RCR_PAGE0 /*!< ICODE SRAM Write protection page 0 */ +#define SYSCFG_SRAMWRP_Page1 SYSCFG_RCR_PAGE1 /*!< ICODE SRAM Write protection page 1 */ +#define SYSCFG_SRAMWRP_Page2 SYSCFG_RCR_PAGE2 /*!< ICODE SRAM Write protection page 2 */ +#define SYSCFG_SRAMWRP_Page3 SYSCFG_RCR_PAGE3 /*!< ICODE SRAM Write protection page 3 */ +#define SYSCFG_SRAMWRP_Page4 SYSCFG_RCR_PAGE4 /*!< ICODE SRAM Write protection page 4 */ +#define SYSCFG_SRAMWRP_Page5 SYSCFG_RCR_PAGE5 /*!< ICODE SRAM Write protection page 5 */ +#define SYSCFG_SRAMWRP_Page6 SYSCFG_RCR_PAGE6 /*!< ICODE SRAM Write protection page 6 */ +#define SYSCFG_SRAMWRP_Page7 SYSCFG_RCR_PAGE7 /*!< ICODE SRAM Write protection page 7 */ +#define SYSCFG_SRAMWRP_Page8 SYSCFG_RCR_PAGE8 /*!< ICODE SRAM Write protection page 8 */ +#define SYSCFG_SRAMWRP_Page9 SYSCFG_RCR_PAGE9 /*!< ICODE SRAM Write protection page 9 */ +#define SYSCFG_SRAMWRP_Page10 SYSCFG_RCR_PAGE10 /*!< ICODE SRAM Write protection page 10 */ +#define SYSCFG_SRAMWRP_Page11 SYSCFG_RCR_PAGE11 /*!< ICODE SRAM Write protection page 11 */ +#define SYSCFG_SRAMWRP_Page12 SYSCFG_RCR_PAGE12 /*!< ICODE SRAM Write protection page 12 */ +#define SYSCFG_SRAMWRP_Page13 SYSCFG_RCR_PAGE13 /*!< ICODE SRAM Write protection page 13 */ +#define SYSCFG_SRAMWRP_Page14 SYSCFG_RCR_PAGE14 /*!< ICODE SRAM Write protection page 14 */ +#define SYSCFG_SRAMWRP_Page15 SYSCFG_RCR_PAGE15 /*!< ICODE SRAM Write protection page 15 */ + +#define IS_SYSCFG_PAGE(PAGE)((((PAGE) & (uint32_t)0xFFFF0000) == 0x00000000) && ((PAGE) != 0x00000000)) + +/** + * @} + */ + +/** @defgroup SYSCFG_flags_definition + * @{ + */ + +#define SYSCFG_FLAG_PE SYSCFG_CFGR2_SRAM_PE + +#define IS_SYSCFG_FLAG(FLAG) (((FLAG) == SYSCFG_FLAG_PE)) + +/** + * @} + */ + +/** + * @} + */ + +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions ------------------------------------------------------- */ + +/* Function used to set the SYSCFG configuration to the default reset state **/ +void SYSCFG_DeInit(void); + +/* SYSCFG configuration functions *********************************************/ +void SYSCFG_MemoryRemapConfig(uint32_t SYSCFG_MemoryRemap); +void SYSCFG_DMAChannelRemapConfig(uint32_t SYSCFG_DMARemap, FunctionalState NewState); +void SYSCFG_TriggerRemapConfig(uint32_t SYSCFG_TriggerRemap, FunctionalState NewState); +void SYSCFG_EncoderRemapConfig(uint32_t SYSCFG_EncoderRemap); +void SYSCFG_USBInterruptLineRemapCmd(FunctionalState NewState); +void SYSCFG_I2CFastModePlusConfig(uint32_t SYSCFG_I2CFastModePlus, FunctionalState NewState); +void SYSCFG_ITConfig(uint32_t SYSCFG_IT, FunctionalState NewState); +void SYSCFG_EXTILineConfig(uint8_t EXTI_PortSourceGPIOx, uint8_t EXTI_PinSourcex); +void SYSCFG_BreakConfig(uint32_t SYSCFG_Break); +void SYSCFG_BypassParityCheckDisable(void); +void SYSCFG_ADCTriggerRemapConfig(uint32_t SYSCFG_ADCTriggerRemap, FunctionalState NewState); +void SYSCFG_SRAMWRPEnable(uint32_t SYSCFG_SRAMWRP); +FlagStatus SYSCFG_GetFlagStatus(uint32_t SYSCFG_Flag); +void SYSCFG_ClearFlag(uint32_t SYSCFG_Flag); + +#ifdef __cplusplus +} +#endif + +#endif /*__STM32F30x_SYSCFG_H */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_tim.h b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_tim.h new file mode 100755 index 0000000000..4837de7514 --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_tim.h @@ -0,0 +1,1360 @@ +/** + ****************************************************************************** + * @file stm32f30x_tim.h + * @author MCD Application Team + * @version V1.2.3 + * @date 10-July-2015 + * @brief This file contains all the functions prototypes for the TIM firmware + * library. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F30x_TIM_H +#define __STM32F30x_TIM_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f30x.h" + +/** @addtogroup stm32f30x_StdPeriph_Driver + * @{ + */ + +/** @addtogroup TIM + * @{ + */ + +/* Exported types ------------------------------------------------------------*/ + +/** + * @brief TIM Time Base Init structure definition + * @note This structure is used with all TIMx except for TIM6 and TIM7. + */ + +typedef struct +{ + uint16_t TIM_Prescaler; /*!< Specifies the prescaler value used to divide the TIM clock. + This parameter can be a number between 0x0000 and 0xFFFF */ + + uint16_t TIM_CounterMode; /*!< Specifies the counter mode. + This parameter can be a value of @ref TIM_Counter_Mode */ + + uint32_t TIM_Period; /*!< Specifies the period value to be loaded into the active + Auto-Reload Register at the next update event. + This parameter must be a number between 0x0000 and 0xFFFF. */ + + uint16_t TIM_ClockDivision; /*!< Specifies the clock division. + This parameter can be a value of @ref TIM_Clock_Division_CKD */ + + uint16_t TIM_RepetitionCounter; /*!< Specifies the repetition counter value. Each time the RCR downcounter + reaches zero, an update event is generated and counting restarts + from the RCR value (N). + This means in PWM mode that (N+1) corresponds to: + - the number of PWM periods in edge-aligned mode + - the number of half PWM period in center-aligned mode + This parameter must be a number between 0x00 and 0xFF. + @note This parameter is valid only for TIM1 and TIM8. */ +} TIM_TimeBaseInitTypeDef; + +/** + * @brief TIM Output Compare Init structure definition + */ + +typedef struct +{ + uint32_t TIM_OCMode; /*!< Specifies the TIM mode. + This parameter can be a value of @ref TIM_Output_Compare_and_PWM_modes */ + + uint16_t TIM_OutputState; /*!< Specifies the TIM Output Compare state. + This parameter can be a value of @ref TIM_Output_Compare_State */ + + uint16_t TIM_OutputNState; /*!< Specifies the TIM complementary Output Compare state. + This parameter can be a value of @ref TIM_Output_Compare_N_State + @note This parameter is valid only for TIM1 and TIM8. */ + + uint32_t TIM_Pulse; /*!< Specifies the pulse value to be loaded into the Capture Compare Register. + This parameter can be a number between 0x0000 and 0xFFFF */ + + uint16_t TIM_OCPolarity; /*!< Specifies the output polarity. + This parameter can be a value of @ref TIM_Output_Compare_Polarity */ + + uint16_t TIM_OCNPolarity; /*!< Specifies the complementary output polarity. + This parameter can be a value of @ref TIM_Output_Compare_N_Polarity + @note This parameter is valid only for TIM1 and TIM8. */ + + uint16_t TIM_OCIdleState; /*!< Specifies the TIM Output Compare pin state during Idle state. + This parameter can be a value of @ref TIM_Output_Compare_Idle_State + @note This parameter is valid only for TIM1 and TIM8. */ + + uint16_t TIM_OCNIdleState; /*!< Specifies the TIM Output Compare pin state during Idle state. + This parameter can be a value of @ref TIM_Output_Compare_N_Idle_State + @note This parameter is valid only for TIM1 and TIM8. */ +} TIM_OCInitTypeDef; + +/** + * @brief TIM Input Capture Init structure definition + */ + +typedef struct +{ + + uint16_t TIM_Channel; /*!< Specifies the TIM channel. + This parameter can be a value of @ref TIM_Channel */ + + uint16_t TIM_ICPolarity; /*!< Specifies the active edge of the input signal. + This parameter can be a value of @ref TIM_Input_Capture_Polarity */ + + uint16_t TIM_ICSelection; /*!< Specifies the input. + This parameter can be a value of @ref TIM_Input_Capture_Selection */ + + uint16_t TIM_ICPrescaler; /*!< Specifies the Input Capture Prescaler. + This parameter can be a value of @ref TIM_Input_Capture_Prescaler */ + + uint16_t TIM_ICFilter; /*!< Specifies the input capture filter. + This parameter can be a number between 0x0 and 0xF */ +} TIM_ICInitTypeDef; + +/** + * @brief BDTR structure definition + * @note This structure is used only with TIM1 and TIM8. + */ + +typedef struct +{ + + uint16_t TIM_OSSRState; /*!< Specifies the Off-State selection used in Run mode. + This parameter can be a value of @ref TIM_OSSR_Off_State_Selection_for_Run_mode_state */ + + uint16_t TIM_OSSIState; /*!< Specifies the Off-State used in Idle state. + This parameter can be a value of @ref TIM_OSSI_Off_State_Selection_for_Idle_mode_state */ + + uint16_t TIM_LOCKLevel; /*!< Specifies the LOCK level parameters. + This parameter can be a value of @ref TIM_Lock_level */ + + uint16_t TIM_DeadTime; /*!< Specifies the delay time between the switching-off and the + switching-on of the outputs. + This parameter can be a number between 0x00 and 0xFF */ + + uint16_t TIM_Break; /*!< Specifies whether the TIM Break input is enabled or not. + This parameter can be a value of @ref TIM_Break_Input_enable_disable */ + + uint16_t TIM_BreakPolarity; /*!< Specifies the TIM Break Input pin polarity. + This parameter can be a value of @ref TIM_Break_Polarity */ + + uint16_t TIM_AutomaticOutput; /*!< Specifies whether the TIM Automatic Output feature is enabled or not. + This parameter can be a value of @ref TIM_AOE_Bit_Set_Reset */ +} TIM_BDTRInitTypeDef; + +/* Exported constants --------------------------------------------------------*/ + +/** @defgroup TIM_Exported_constants + * @{ + */ + +#define IS_TIM_ALL_PERIPH(PERIPH) (((PERIPH) == TIM1) || \ + ((PERIPH) == TIM2) || \ + ((PERIPH) == TIM3) || \ + ((PERIPH) == TIM4) || \ + ((PERIPH) == TIM6) || \ + ((PERIPH) == TIM7) || \ + ((PERIPH) == TIM8) || \ + ((PERIPH) == TIM15) || \ + ((PERIPH) == TIM16) || \ + ((PERIPH) == TIM17) || \ + ((PERIPH) == TIM20)) + +/* LIST1: TIM1, TIM2, TIM3, TIM4, TIM8, TIM15, TIM16, TIM20 and TIM17 */ +#define IS_TIM_LIST1_PERIPH(PERIPH) (((PERIPH) == TIM1) || \ + ((PERIPH) == TIM2) || \ + ((PERIPH) == TIM3) || \ + ((PERIPH) == TIM4) || \ + ((PERIPH) == TIM8) || \ + ((PERIPH) == TIM15) || \ + ((PERIPH) == TIM16) || \ + ((PERIPH) == TIM17) || \ + ((PERIPH) == TIM20)) + +/* LIST2: TIM1, TIM2, TIM3, TIM4, TIM8, TIM20 and TIM15 */ +#define IS_TIM_LIST2_PERIPH(PERIPH) (((PERIPH) == TIM1) || \ + ((PERIPH) == TIM2) || \ + ((PERIPH) == TIM3) || \ + ((PERIPH) == TIM4) || \ + ((PERIPH) == TIM8) || \ + ((PERIPH) == TIM15)|| \ + ((PERIPH) == TIM20)) + +/* LIST3: TIM1, TIM2, TIM3, TIM4, TIM20 and TIM8 */ +#define IS_TIM_LIST3_PERIPH(PERIPH) (((PERIPH) == TIM1) || \ + ((PERIPH) == TIM2) || \ + ((PERIPH) == TIM3) || \ + ((PERIPH) == TIM4) || \ + ((PERIPH) == TIM8) || \ + ((PERIPH) == TIM20)) + +/* LIST4: TIM1, TIM20 and TIM8 */ +#define IS_TIM_LIST4_PERIPH(PERIPH) (((PERIPH) == TIM1) ||\ + ((PERIPH) == TIM8) ||\ + ((PERIPH) == TIM20)) + +/* LIST5: TIM1, TIM2, TIM3, TIM4, TIM5, TIM6, TIM7 and TIM8 */ +#define IS_TIM_LIST5_PERIPH(PERIPH) (((PERIPH) == TIM1) || \ + ((PERIPH) == TIM2) || \ + ((PERIPH) == TIM3) || \ + ((PERIPH) == TIM4) || \ + ((PERIPH) == TIM6) || \ + ((PERIPH) == TIM7) || \ + ((PERIPH) == TIM8)) +/* LIST6: TIM1, TIM8, TIM15, TIM16, TIM20 and TIM17 */ +#define IS_TIM_LIST6_PERIPH(PERIPH) (((PERIPH) == TIM1) || \ + ((PERIPH) == TIM8) || \ + ((PERIPH) == TIM15) || \ + ((PERIPH) == TIM16) || \ + ((PERIPH) == TIM17) || \ + ((PERIPH) == TIM20)) + +/* LIST5: TIM1, TIM2, TIM3, TIM4, TIM5, TIM6, TIM7, TIM20 and TIM8 */ +#define IS_TIM_LIST7_PERIPH(PERIPH) (((PERIPH) == TIM1) || \ + ((PERIPH) == TIM2) || \ + ((PERIPH) == TIM3) || \ + ((PERIPH) == TIM4) || \ + ((PERIPH) == TIM6) || \ + ((PERIPH) == TIM7) || \ + ((PERIPH) == TIM8) || \ + ((PERIPH) == TIM15)|| \ + ((PERIPH) == TIM20)) + +/* LIST8: TIM16 (option register) */ +#define IS_TIM_LIST8_PERIPH(PERIPH) (((PERIPH) == TIM16)|| \ + ((PERIPH) == TIM1) ||\ + ((PERIPH) == TIM8) ||\ + ((PERIPH) == TIM20)) + +/** @defgroup TIM_Output_Compare_and_PWM_modes + * @{ + */ + +#define TIM_OCMode_Timing ((uint32_t)0x00000) +#define TIM_OCMode_Active ((uint32_t)0x00010) +#define TIM_OCMode_Inactive ((uint32_t)0x00020) +#define TIM_OCMode_Toggle ((uint32_t)0x00030) +#define TIM_OCMode_PWM1 ((uint32_t)0x00060) +#define TIM_OCMode_PWM2 ((uint32_t)0x00070) + +#define TIM_OCMode_Retrigerrable_OPM1 ((uint32_t)0x10000) +#define TIM_OCMode_Retrigerrable_OPM2 ((uint32_t)0x10010) +#define TIM_OCMode_Combined_PWM1 ((uint32_t)0x10040) +#define TIM_OCMode_Combined_PWM2 ((uint32_t)0x10050) +#define TIM_OCMode_Asymmetric_PWM1 ((uint32_t)0x10060) +#define TIM_OCMode_Asymmetric_PWM2 ((uint32_t)0x10070) + +#define IS_TIM_OC_MODE(MODE) (((MODE) == TIM_OCMode_Timing) || \ + ((MODE) == TIM_OCMode_Active) || \ + ((MODE) == TIM_OCMode_Inactive) || \ + ((MODE) == TIM_OCMode_Toggle)|| \ + ((MODE) == TIM_OCMode_PWM1) || \ + ((MODE) == TIM_OCMode_PWM2) || \ + ((MODE) == TIM_OCMode_Retrigerrable_OPM1) || \ + ((MODE) == TIM_OCMode_Retrigerrable_OPM2) || \ + ((MODE) == TIM_OCMode_Combined_PWM1) || \ + ((MODE) == TIM_OCMode_Combined_PWM2) || \ + ((MODE) == TIM_OCMode_Asymmetric_PWM1) || \ + ((MODE) == TIM_OCMode_Asymmetric_PWM2)) + +#define IS_TIM_OCM(MODE) (((MODE) == TIM_OCMode_Timing) || \ + ((MODE) == TIM_OCMode_Active) || \ + ((MODE) == TIM_OCMode_Inactive) || \ + ((MODE) == TIM_OCMode_Toggle)|| \ + ((MODE) == TIM_OCMode_PWM1) || \ + ((MODE) == TIM_OCMode_PWM2) || \ + ((MODE) == TIM_ForcedAction_Active) || \ + ((MODE) == TIM_ForcedAction_InActive) || \ + ((MODE) == TIM_OCMode_Retrigerrable_OPM1) || \ + ((MODE) == TIM_OCMode_Retrigerrable_OPM2) || \ + ((MODE) == TIM_OCMode_Combined_PWM1) || \ + ((MODE) == TIM_OCMode_Combined_PWM2) || \ + ((MODE) == TIM_OCMode_Asymmetric_PWM1) || \ + ((MODE) == TIM_OCMode_Asymmetric_PWM2)) +/** + * @} + */ + +/** @defgroup TIM_One_Pulse_Mode + * @{ + */ + +#define TIM_OPMode_Single ((uint16_t)0x0008) +#define TIM_OPMode_Repetitive ((uint16_t)0x0000) +#define IS_TIM_OPM_MODE(MODE) (((MODE) == TIM_OPMode_Single) || \ + ((MODE) == TIM_OPMode_Repetitive)) +/** + * @} + */ + +/** @defgroup TIM_Channel + * @{ + */ + +#define TIM_Channel_1 ((uint16_t)0x0000) +#define TIM_Channel_2 ((uint16_t)0x0004) +#define TIM_Channel_3 ((uint16_t)0x0008) +#define TIM_Channel_4 ((uint16_t)0x000C) +#define TIM_Channel_5 ((uint16_t)0x0010) +#define TIM_Channel_6 ((uint16_t)0x0014) + +#define IS_TIM_CHANNEL(CHANNEL) (((CHANNEL) == TIM_Channel_1) || \ + ((CHANNEL) == TIM_Channel_2) || \ + ((CHANNEL) == TIM_Channel_3) || \ + ((CHANNEL) == TIM_Channel_4)) + +#define IS_TIM_PWMI_CHANNEL(CHANNEL) (((CHANNEL) == TIM_Channel_1) || \ + ((CHANNEL) == TIM_Channel_2)) +#define IS_TIM_COMPLEMENTARY_CHANNEL(CHANNEL) (((CHANNEL) == TIM_Channel_1) || \ + ((CHANNEL) == TIM_Channel_2) || \ + ((CHANNEL) == TIM_Channel_3)) +/** + * @} + */ + +/** @defgroup TIM_Clock_Division_CKD + * @{ + */ + +#define TIM_CKD_DIV1 ((uint16_t)0x0000) +#define TIM_CKD_DIV2 ((uint16_t)0x0100) +#define TIM_CKD_DIV4 ((uint16_t)0x0200) +#define IS_TIM_CKD_DIV(DIV) (((DIV) == TIM_CKD_DIV1) || \ + ((DIV) == TIM_CKD_DIV2) || \ + ((DIV) == TIM_CKD_DIV4)) +/** + * @} + */ + +/** @defgroup TIM_Counter_Mode + * @{ + */ + +#define TIM_CounterMode_Up ((uint16_t)0x0000) +#define TIM_CounterMode_Down ((uint16_t)0x0010) +#define TIM_CounterMode_CenterAligned1 ((uint16_t)0x0020) +#define TIM_CounterMode_CenterAligned2 ((uint16_t)0x0040) +#define TIM_CounterMode_CenterAligned3 ((uint16_t)0x0060) +#define IS_TIM_COUNTER_MODE(MODE) (((MODE) == TIM_CounterMode_Up) || \ + ((MODE) == TIM_CounterMode_Down) || \ + ((MODE) == TIM_CounterMode_CenterAligned1) || \ + ((MODE) == TIM_CounterMode_CenterAligned2) || \ + ((MODE) == TIM_CounterMode_CenterAligned3)) +/** + * @} + */ + +/** @defgroup TIM_Output_Compare_Polarity + * @{ + */ + +#define TIM_OCPolarity_High ((uint16_t)0x0000) +#define TIM_OCPolarity_Low ((uint16_t)0x0002) +#define IS_TIM_OC_POLARITY(POLARITY) (((POLARITY) == TIM_OCPolarity_High) || \ + ((POLARITY) == TIM_OCPolarity_Low)) +/** + * @} + */ + +/** @defgroup TIM_Output_Compare_N_Polarity + * @{ + */ + +#define TIM_OCNPolarity_High ((uint16_t)0x0000) +#define TIM_OCNPolarity_Low ((uint16_t)0x0008) +#define IS_TIM_OCN_POLARITY(POLARITY) (((POLARITY) == TIM_OCNPolarity_High) || \ + ((POLARITY) == TIM_OCNPolarity_Low)) +/** + * @} + */ + +/** @defgroup TIM_Output_Compare_State + * @{ + */ + +#define TIM_OutputState_Disable ((uint16_t)0x0000) +#define TIM_OutputState_Enable ((uint16_t)0x0001) +#define IS_TIM_OUTPUT_STATE(STATE) (((STATE) == TIM_OutputState_Disable) || \ + ((STATE) == TIM_OutputState_Enable)) +/** + * @} + */ + +/** @defgroup TIM_Output_Compare_N_State + * @{ + */ + +#define TIM_OutputNState_Disable ((uint16_t)0x0000) +#define TIM_OutputNState_Enable ((uint16_t)0x0004) +#define IS_TIM_OUTPUTN_STATE(STATE) (((STATE) == TIM_OutputNState_Disable) || \ + ((STATE) == TIM_OutputNState_Enable)) +/** + * @} + */ + +/** @defgroup TIM_Capture_Compare_State + * @{ + */ + +#define TIM_CCx_Enable ((uint16_t)0x0001) +#define TIM_CCx_Disable ((uint16_t)0x0000) +#define IS_TIM_CCX(CCX) (((CCX) == TIM_CCx_Enable) || \ + ((CCX) == TIM_CCx_Disable)) +/** + * @} + */ + +/** @defgroup TIM_Capture_Compare_N_State + * @{ + */ + +#define TIM_CCxN_Enable ((uint16_t)0x0004) +#define TIM_CCxN_Disable ((uint16_t)0x0000) +#define IS_TIM_CCXN(CCXN) (((CCXN) == TIM_CCxN_Enable) || \ + ((CCXN) == TIM_CCxN_Disable)) +/** + * @} + */ + +/** @defgroup TIM_Break_Input_enable_disable + * @{ + */ + +#define TIM_Break_Enable ((uint16_t)0x1000) +#define TIM_Break_Disable ((uint16_t)0x0000) +#define IS_TIM_BREAK_STATE(STATE) (((STATE) == TIM_Break_Enable) || \ + ((STATE) == TIM_Break_Disable)) +/** + * @} + */ + +/** @defgroup TIM_Break1_Input_enable_disable + * @{ + */ + +#define TIM_Break1_Enable ((uint32_t)0x00001000) +#define TIM_Break1_Disable ((uint32_t)0x00000000) +#define IS_TIM_BREAK1_STATE(STATE) (((STATE) == TIM_Break1_Enable) || \ + ((STATE) == TIM_Break1_Disable)) +/** + * @} + */ + +/** @defgroup TIM_Break2_Input_enable_disable + * @{ + */ + +#define TIM_Break2_Enable ((uint32_t)0x01000000) +#define TIM_Break2_Disable ((uint32_t)0x00000000) +#define IS_TIM_BREAK2_STATE(STATE) (((STATE) == TIM_Break2_Enable) || \ + ((STATE) == TIM_Break2_Disable)) +/** + * @} + */ + +/** @defgroup TIM_Break_Polarity + * @{ + */ + +#define TIM_BreakPolarity_Low ((uint16_t)0x0000) +#define TIM_BreakPolarity_High ((uint16_t)0x2000) +#define IS_TIM_BREAK_POLARITY(POLARITY) (((POLARITY) == TIM_BreakPolarity_Low) || \ + ((POLARITY) == TIM_BreakPolarity_High)) +/** + * @} + */ + +/** @defgroup TIM_Break1_Polarity + * @{ + */ + +#define TIM_Break1Polarity_Low ((uint32_t)0x00000000) +#define TIM_Break1Polarity_High ((uint32_t)0x00002000) +#define IS_TIM_BREAK1_POLARITY(POLARITY) (((POLARITY) == TIM_Break1Polarity_Low) || \ + ((POLARITY) == TIM_Break1Polarity_High)) +/** + * @} + */ + +/** @defgroup TIM_Break2_Polarity + * @{ + */ + +#define TIM_Break2Polarity_Low ((uint32_t)0x00000000) +#define TIM_Break2Polarity_High ((uint32_t)0x02000000) +#define IS_TIM_BREAK2_POLARITY(POLARITY) (((POLARITY) == TIM_Break2Polarity_Low) || \ + ((POLARITY) == TIM_Break2Polarity_High)) +/** + * @} + */ + +/** @defgroup TIM_Break1_Filter + * @{ + */ + +#define IS_TIM_BREAK1_FILTER(FILTER) ((FILTER) <= 0xF) +/** + * @} + */ + +/** @defgroup TIM_Break2_Filter + * @{ + */ + +#define IS_TIM_BREAK2_FILTER(FILTER) ((FILTER) <= 0xF) +/** + * @} + */ + +/** @defgroup TIM_AOE_Bit_Set_Reset + * @{ + */ + +#define TIM_AutomaticOutput_Enable ((uint16_t)0x4000) +#define TIM_AutomaticOutput_Disable ((uint16_t)0x0000) +#define IS_TIM_AUTOMATIC_OUTPUT_STATE(STATE) (((STATE) == TIM_AutomaticOutput_Enable) || \ + ((STATE) == TIM_AutomaticOutput_Disable)) +/** + * @} + */ + +/** @defgroup TIM_Lock_level + * @{ + */ + +#define TIM_LOCKLevel_OFF ((uint16_t)0x0000) +#define TIM_LOCKLevel_1 ((uint16_t)0x0100) +#define TIM_LOCKLevel_2 ((uint16_t)0x0200) +#define TIM_LOCKLevel_3 ((uint16_t)0x0300) +#define IS_TIM_LOCK_LEVEL(LEVEL) (((LEVEL) == TIM_LOCKLevel_OFF) || \ + ((LEVEL) == TIM_LOCKLevel_1) || \ + ((LEVEL) == TIM_LOCKLevel_2) || \ + ((LEVEL) == TIM_LOCKLevel_3)) +/** + * @} + */ + +/** @defgroup TIM_OSSI_Off_State_Selection_for_Idle_mode_state + * @{ + */ + +#define TIM_OSSIState_Enable ((uint16_t)0x0400) +#define TIM_OSSIState_Disable ((uint16_t)0x0000) +#define IS_TIM_OSSI_STATE(STATE) (((STATE) == TIM_OSSIState_Enable) || \ + ((STATE) == TIM_OSSIState_Disable)) +/** + * @} + */ + +/** @defgroup TIM_OSSR_Off_State_Selection_for_Run_mode_state + * @{ + */ + +#define TIM_OSSRState_Enable ((uint16_t)0x0800) +#define TIM_OSSRState_Disable ((uint16_t)0x0000) +#define IS_TIM_OSSR_STATE(STATE) (((STATE) == TIM_OSSRState_Enable) || \ + ((STATE) == TIM_OSSRState_Disable)) +/** + * @} + */ + +/** @defgroup TIM_Output_Compare_Idle_State + * @{ + */ + +#define TIM_OCIdleState_Set ((uint16_t)0x0100) +#define TIM_OCIdleState_Reset ((uint16_t)0x0000) +#define IS_TIM_OCIDLE_STATE(STATE) (((STATE) == TIM_OCIdleState_Set) || \ + ((STATE) == TIM_OCIdleState_Reset)) +/** + * @} + */ + +/** @defgroup TIM_Output_Compare_N_Idle_State + * @{ + */ + +#define TIM_OCNIdleState_Set ((uint16_t)0x0200) +#define TIM_OCNIdleState_Reset ((uint16_t)0x0000) +#define IS_TIM_OCNIDLE_STATE(STATE) (((STATE) == TIM_OCNIdleState_Set) || \ + ((STATE) == TIM_OCNIdleState_Reset)) +/** + * @} + */ + +/** @defgroup TIM_Input_Capture_Polarity + * @{ + */ + +#define TIM_ICPolarity_Rising ((uint16_t)0x0000) +#define TIM_ICPolarity_Falling ((uint16_t)0x0002) +#define TIM_ICPolarity_BothEdge ((uint16_t)0x000A) +#define IS_TIM_IC_POLARITY(POLARITY) (((POLARITY) == TIM_ICPolarity_Rising) || \ + ((POLARITY) == TIM_ICPolarity_Falling)|| \ + ((POLARITY) == TIM_ICPolarity_BothEdge)) +/** + * @} + */ + +/** @defgroup TIM_Input_Capture_Selection + * @{ + */ + +#define TIM_ICSelection_DirectTI ((uint16_t)0x0001) /*!< TIM Input 1, 2, 3 or 4 is selected to be + connected to IC1, IC2, IC3 or IC4, respectively */ +#define TIM_ICSelection_IndirectTI ((uint16_t)0x0002) /*!< TIM Input 1, 2, 3 or 4 is selected to be + connected to IC2, IC1, IC4 or IC3, respectively. */ +#define TIM_ICSelection_TRC ((uint16_t)0x0003) /*!< TIM Input 1, 2, 3 or 4 is selected to be connected to TRC. */ +#define IS_TIM_IC_SELECTION(SELECTION) (((SELECTION) == TIM_ICSelection_DirectTI) || \ + ((SELECTION) == TIM_ICSelection_IndirectTI) || \ + ((SELECTION) == TIM_ICSelection_TRC)) +/** + * @} + */ + +/** @defgroup TIM_Input_Capture_Prescaler + * @{ + */ + +#define TIM_ICPSC_DIV1 ((uint16_t)0x0000) /*!< Capture performed each time an edge is detected on the capture input. */ +#define TIM_ICPSC_DIV2 ((uint16_t)0x0004) /*!< Capture performed once every 2 events. */ +#define TIM_ICPSC_DIV4 ((uint16_t)0x0008) /*!< Capture performed once every 4 events. */ +#define TIM_ICPSC_DIV8 ((uint16_t)0x000C) /*!< Capture performed once every 8 events. */ +#define IS_TIM_IC_PRESCALER(PRESCALER) (((PRESCALER) == TIM_ICPSC_DIV1) || \ + ((PRESCALER) == TIM_ICPSC_DIV2) || \ + ((PRESCALER) == TIM_ICPSC_DIV4) || \ + ((PRESCALER) == TIM_ICPSC_DIV8)) +/** + * @} + */ + +/** @defgroup TIM_interrupt_sources + * @{ + */ + +#define TIM_IT_Update ((uint16_t)0x0001) +#define TIM_IT_CC1 ((uint16_t)0x0002) +#define TIM_IT_CC2 ((uint16_t)0x0004) +#define TIM_IT_CC3 ((uint16_t)0x0008) +#define TIM_IT_CC4 ((uint16_t)0x0010) +#define TIM_IT_COM ((uint16_t)0x0020) +#define TIM_IT_Trigger ((uint16_t)0x0040) +#define TIM_IT_Break ((uint16_t)0x0080) +#define IS_TIM_IT(IT) ((((IT) & (uint16_t)0xFF00) == 0x0000) && ((IT) != 0x0000)) + +#define IS_TIM_GET_IT(IT) (((IT) == TIM_IT_Update) || \ + ((IT) == TIM_IT_CC1) || \ + ((IT) == TIM_IT_CC2) || \ + ((IT) == TIM_IT_CC3) || \ + ((IT) == TIM_IT_CC4) || \ + ((IT) == TIM_IT_COM) || \ + ((IT) == TIM_IT_Trigger) || \ + ((IT) == TIM_IT_Break)) +/** + * @} + */ + +/** @defgroup TIM_DMA_Base_address + * @{ + */ + +#define TIM_DMABase_CR1 ((uint16_t)0x0000) +#define TIM_DMABase_CR2 ((uint16_t)0x0001) +#define TIM_DMABase_SMCR ((uint16_t)0x0002) +#define TIM_DMABase_DIER ((uint16_t)0x0003) +#define TIM_DMABase_SR ((uint16_t)0x0004) +#define TIM_DMABase_EGR ((uint16_t)0x0005) +#define TIM_DMABase_CCMR1 ((uint16_t)0x0006) +#define TIM_DMABase_CCMR2 ((uint16_t)0x0007) +#define TIM_DMABase_CCER ((uint16_t)0x0008) +#define TIM_DMABase_CNT ((uint16_t)0x0009) +#define TIM_DMABase_PSC ((uint16_t)0x000A) +#define TIM_DMABase_ARR ((uint16_t)0x000B) +#define TIM_DMABase_RCR ((uint16_t)0x000C) +#define TIM_DMABase_CCR1 ((uint16_t)0x000D) +#define TIM_DMABase_CCR2 ((uint16_t)0x000E) +#define TIM_DMABase_CCR3 ((uint16_t)0x000F) +#define TIM_DMABase_CCR4 ((uint16_t)0x0010) +#define TIM_DMABase_BDTR ((uint16_t)0x0011) +#define TIM_DMABase_DCR ((uint16_t)0x0012) +#define TIM_DMABase_OR ((uint16_t)0x0013) +#define TIM_DMABase_CCMR3 ((uint16_t)0x0014) +#define TIM_DMABase_CCR5 ((uint16_t)0x0015) +#define TIM_DMABase_CCR6 ((uint16_t)0x0016) +#define IS_TIM_DMA_BASE(BASE) (((BASE) == TIM_DMABase_CR1) || \ + ((BASE) == TIM_DMABase_CR2) || \ + ((BASE) == TIM_DMABase_SMCR) || \ + ((BASE) == TIM_DMABase_DIER) || \ + ((BASE) == TIM_DMABase_SR) || \ + ((BASE) == TIM_DMABase_EGR) || \ + ((BASE) == TIM_DMABase_CCMR1) || \ + ((BASE) == TIM_DMABase_CCMR2) || \ + ((BASE) == TIM_DMABase_CCER) || \ + ((BASE) == TIM_DMABase_CNT) || \ + ((BASE) == TIM_DMABase_PSC) || \ + ((BASE) == TIM_DMABase_ARR) || \ + ((BASE) == TIM_DMABase_RCR) || \ + ((BASE) == TIM_DMABase_CCR1) || \ + ((BASE) == TIM_DMABase_CCR2) || \ + ((BASE) == TIM_DMABase_CCR3) || \ + ((BASE) == TIM_DMABase_CCR4) || \ + ((BASE) == TIM_DMABase_BDTR) || \ + ((BASE) == TIM_DMABase_DCR) || \ + ((BASE) == TIM_DMABase_OR) || \ + ((BASE) == TIM_DMABase_CCMR3) || \ + ((BASE) == TIM_DMABase_CCR5) || \ + ((BASE) == TIM_DMABase_CCR6)) +/** + * @} + */ + +/** @defgroup TIM_DMA_Burst_Length + * @{ + */ + +#define TIM_DMABurstLength_1Transfer ((uint16_t)0x0000) +#define TIM_DMABurstLength_2Transfers ((uint16_t)0x0100) +#define TIM_DMABurstLength_3Transfers ((uint16_t)0x0200) +#define TIM_DMABurstLength_4Transfers ((uint16_t)0x0300) +#define TIM_DMABurstLength_5Transfers ((uint16_t)0x0400) +#define TIM_DMABurstLength_6Transfers ((uint16_t)0x0500) +#define TIM_DMABurstLength_7Transfers ((uint16_t)0x0600) +#define TIM_DMABurstLength_8Transfers ((uint16_t)0x0700) +#define TIM_DMABurstLength_9Transfers ((uint16_t)0x0800) +#define TIM_DMABurstLength_10Transfers ((uint16_t)0x0900) +#define TIM_DMABurstLength_11Transfers ((uint16_t)0x0A00) +#define TIM_DMABurstLength_12Transfers ((uint16_t)0x0B00) +#define TIM_DMABurstLength_13Transfers ((uint16_t)0x0C00) +#define TIM_DMABurstLength_14Transfers ((uint16_t)0x0D00) +#define TIM_DMABurstLength_15Transfers ((uint16_t)0x0E00) +#define TIM_DMABurstLength_16Transfers ((uint16_t)0x0F00) +#define TIM_DMABurstLength_17Transfers ((uint16_t)0x1000) +#define TIM_DMABurstLength_18Transfers ((uint16_t)0x1100) +#define IS_TIM_DMA_LENGTH(LENGTH) (((LENGTH) == TIM_DMABurstLength_1Transfer) || \ + ((LENGTH) == TIM_DMABurstLength_2Transfers) || \ + ((LENGTH) == TIM_DMABurstLength_3Transfers) || \ + ((LENGTH) == TIM_DMABurstLength_4Transfers) || \ + ((LENGTH) == TIM_DMABurstLength_5Transfers) || \ + ((LENGTH) == TIM_DMABurstLength_6Transfers) || \ + ((LENGTH) == TIM_DMABurstLength_7Transfers) || \ + ((LENGTH) == TIM_DMABurstLength_8Transfers) || \ + ((LENGTH) == TIM_DMABurstLength_9Transfers) || \ + ((LENGTH) == TIM_DMABurstLength_10Transfers) || \ + ((LENGTH) == TIM_DMABurstLength_11Transfers) || \ + ((LENGTH) == TIM_DMABurstLength_12Transfers) || \ + ((LENGTH) == TIM_DMABurstLength_13Transfers) || \ + ((LENGTH) == TIM_DMABurstLength_14Transfers) || \ + ((LENGTH) == TIM_DMABurstLength_15Transfers) || \ + ((LENGTH) == TIM_DMABurstLength_16Transfers) || \ + ((LENGTH) == TIM_DMABurstLength_17Transfers) || \ + ((LENGTH) == TIM_DMABurstLength_18Transfers)) +/** + * @} + */ + +/** @defgroup TIM_DMA_sources + * @{ + */ + +#define TIM_DMA_Update ((uint16_t)0x0100) +#define TIM_DMA_CC1 ((uint16_t)0x0200) +#define TIM_DMA_CC2 ((uint16_t)0x0400) +#define TIM_DMA_CC3 ((uint16_t)0x0800) +#define TIM_DMA_CC4 ((uint16_t)0x1000) +#define TIM_DMA_COM ((uint16_t)0x2000) +#define TIM_DMA_Trigger ((uint16_t)0x4000) +#define IS_TIM_DMA_SOURCE(SOURCE) ((((SOURCE) & (uint16_t)0x80FF) == 0x0000) && ((SOURCE) != 0x0000)) + +/** + * @} + */ + +/** @defgroup TIM_External_Trigger_Prescaler + * @{ + */ + +#define TIM_ExtTRGPSC_OFF ((uint16_t)0x0000) +#define TIM_ExtTRGPSC_DIV2 ((uint16_t)0x1000) +#define TIM_ExtTRGPSC_DIV4 ((uint16_t)0x2000) +#define TIM_ExtTRGPSC_DIV8 ((uint16_t)0x3000) +#define IS_TIM_EXT_PRESCALER(PRESCALER) (((PRESCALER) == TIM_ExtTRGPSC_OFF) || \ + ((PRESCALER) == TIM_ExtTRGPSC_DIV2) || \ + ((PRESCALER) == TIM_ExtTRGPSC_DIV4) || \ + ((PRESCALER) == TIM_ExtTRGPSC_DIV8)) +/** + * @} + */ + +/** @defgroup TIM_Internal_Trigger_Selection + * @{ + */ + +#define TIM_TS_ITR0 ((uint16_t)0x0000) +#define TIM_TS_ITR1 ((uint16_t)0x0010) +#define TIM_TS_ITR2 ((uint16_t)0x0020) +#define TIM_TS_ITR3 ((uint16_t)0x0030) +#define TIM_TS_TI1F_ED ((uint16_t)0x0040) +#define TIM_TS_TI1FP1 ((uint16_t)0x0050) +#define TIM_TS_TI2FP2 ((uint16_t)0x0060) +#define TIM_TS_ETRF ((uint16_t)0x0070) +#define IS_TIM_TRIGGER_SELECTION(SELECTION) (((SELECTION) == TIM_TS_ITR0) || \ + ((SELECTION) == TIM_TS_ITR1) || \ + ((SELECTION) == TIM_TS_ITR2) || \ + ((SELECTION) == TIM_TS_ITR3) || \ + ((SELECTION) == TIM_TS_TI1F_ED) || \ + ((SELECTION) == TIM_TS_TI1FP1) || \ + ((SELECTION) == TIM_TS_TI2FP2) || \ + ((SELECTION) == TIM_TS_ETRF)) +#define IS_TIM_INTERNAL_TRIGGER_SELECTION(SELECTION) (((SELECTION) == TIM_TS_ITR0) || \ + ((SELECTION) == TIM_TS_ITR1) || \ + ((SELECTION) == TIM_TS_ITR2) || \ + ((SELECTION) == TIM_TS_ITR3)) +/** + * @} + */ + +/** @defgroup TIM_TIx_External_Clock_Source + * @{ + */ + +#define TIM_TIxExternalCLK1Source_TI1 ((uint16_t)0x0050) +#define TIM_TIxExternalCLK1Source_TI2 ((uint16_t)0x0060) +#define TIM_TIxExternalCLK1Source_TI1ED ((uint16_t)0x0040) + +/** + * @} + */ + +/** @defgroup TIM_External_Trigger_Polarity + * @{ + */ +#define TIM_ExtTRGPolarity_Inverted ((uint16_t)0x8000) +#define TIM_ExtTRGPolarity_NonInverted ((uint16_t)0x0000) +#define IS_TIM_EXT_POLARITY(POLARITY) (((POLARITY) == TIM_ExtTRGPolarity_Inverted) || \ + ((POLARITY) == TIM_ExtTRGPolarity_NonInverted)) +/** + * @} + */ + +/** @defgroup TIM_Prescaler_Reload_Mode + * @{ + */ + +#define TIM_PSCReloadMode_Update ((uint16_t)0x0000) +#define TIM_PSCReloadMode_Immediate ((uint16_t)0x0001) +#define IS_TIM_PRESCALER_RELOAD(RELOAD) (((RELOAD) == TIM_PSCReloadMode_Update) || \ + ((RELOAD) == TIM_PSCReloadMode_Immediate)) +/** + * @} + */ + +/** @defgroup TIM_Forced_Action + * @{ + */ + +#define TIM_ForcedAction_Active ((uint16_t)0x0050) +#define TIM_ForcedAction_InActive ((uint16_t)0x0040) +#define IS_TIM_FORCED_ACTION(ACTION) (((ACTION) == TIM_ForcedAction_Active) || \ + ((ACTION) == TIM_ForcedAction_InActive)) +/** + * @} + */ + +/** @defgroup TIM_Encoder_Mode + * @{ + */ + +#define TIM_EncoderMode_TI1 ((uint16_t)0x0001) +#define TIM_EncoderMode_TI2 ((uint16_t)0x0002) +#define TIM_EncoderMode_TI12 ((uint16_t)0x0003) +#define IS_TIM_ENCODER_MODE(MODE) (((MODE) == TIM_EncoderMode_TI1) || \ + ((MODE) == TIM_EncoderMode_TI2) || \ + ((MODE) == TIM_EncoderMode_TI12)) +/** + * @} + */ + + +/** @defgroup TIM_Event_Source + * @{ + */ + +#define TIM_EventSource_Update ((uint16_t)0x0001) +#define TIM_EventSource_CC1 ((uint16_t)0x0002) +#define TIM_EventSource_CC2 ((uint16_t)0x0004) +#define TIM_EventSource_CC3 ((uint16_t)0x0008) +#define TIM_EventSource_CC4 ((uint16_t)0x0010) +#define TIM_EventSource_COM ((uint16_t)0x0020) +#define TIM_EventSource_Trigger ((uint16_t)0x0040) +#define TIM_EventSource_Break ((uint16_t)0x0080) +#define TIM_EventSource_Break2 ((uint16_t)0x0100) +#define IS_TIM_EVENT_SOURCE(SOURCE) ((((SOURCE) & (uint16_t)0xFE00) == 0x0000) && ((SOURCE) != 0x0000)) + +/** + * @} + */ + +/** @defgroup TIM_Update_Source + * @{ + */ + +#define TIM_UpdateSource_Global ((uint16_t)0x0000) /*!< Source of update is the counter overflow/underflow + or the setting of UG bit, or an update generation + through the slave mode controller. */ +#define TIM_UpdateSource_Regular ((uint16_t)0x0001) /*!< Source of update is counter overflow/underflow. */ +#define IS_TIM_UPDATE_SOURCE(SOURCE) (((SOURCE) == TIM_UpdateSource_Global) || \ + ((SOURCE) == TIM_UpdateSource_Regular)) +/** + * @} + */ + +/** @defgroup TIM_Output_Compare_Preload_State + * @{ + */ + +#define TIM_OCPreload_Enable ((uint16_t)0x0008) +#define TIM_OCPreload_Disable ((uint16_t)0x0000) +#define IS_TIM_OCPRELOAD_STATE(STATE) (((STATE) == TIM_OCPreload_Enable) || \ + ((STATE) == TIM_OCPreload_Disable)) +/** + * @} + */ + +/** @defgroup TIM_Output_Compare_Fast_State + * @{ + */ + +#define TIM_OCFast_Enable ((uint16_t)0x0004) +#define TIM_OCFast_Disable ((uint16_t)0x0000) +#define IS_TIM_OCFAST_STATE(STATE) (((STATE) == TIM_OCFast_Enable) || \ + ((STATE) == TIM_OCFast_Disable)) + +/** + * @} + */ + +/** @defgroup TIM_Output_Compare_Clear_State + * @{ + */ + +#define TIM_OCClear_Enable ((uint16_t)0x0080) +#define TIM_OCClear_Disable ((uint16_t)0x0000) +#define IS_TIM_OCCLEAR_STATE(STATE) (((STATE) == TIM_OCClear_Enable) || \ + ((STATE) == TIM_OCClear_Disable)) +/** + * @} + */ + +/** @defgroup TIM_Trigger_Output_Source + * @{ + */ + +#define TIM_TRGOSource_Reset ((uint16_t)0x0000) +#define TIM_TRGOSource_Enable ((uint16_t)0x0010) +#define TIM_TRGOSource_Update ((uint16_t)0x0020) +#define TIM_TRGOSource_OC1 ((uint16_t)0x0030) +#define TIM_TRGOSource_OC1Ref ((uint16_t)0x0040) +#define TIM_TRGOSource_OC2Ref ((uint16_t)0x0050) +#define TIM_TRGOSource_OC3Ref ((uint16_t)0x0060) +#define TIM_TRGOSource_OC4Ref ((uint16_t)0x0070) +#define IS_TIM_TRGO_SOURCE(SOURCE) (((SOURCE) == TIM_TRGOSource_Reset) || \ + ((SOURCE) == TIM_TRGOSource_Enable) || \ + ((SOURCE) == TIM_TRGOSource_Update) || \ + ((SOURCE) == TIM_TRGOSource_OC1) || \ + ((SOURCE) == TIM_TRGOSource_OC1Ref) || \ + ((SOURCE) == TIM_TRGOSource_OC2Ref) || \ + ((SOURCE) == TIM_TRGOSource_OC3Ref) || \ + ((SOURCE) == TIM_TRGOSource_OC4Ref)) + + +#define TIM_TRGO2Source_Reset ((uint32_t)0x00000000) +#define TIM_TRGO2Source_Enable ((uint32_t)0x00100000) +#define TIM_TRGO2Source_Update ((uint32_t)0x00200000) +#define TIM_TRGO2Source_OC1 ((uint32_t)0x00300000) +#define TIM_TRGO2Source_OC1Ref ((uint32_t)0x00400000) +#define TIM_TRGO2Source_OC2Ref ((uint32_t)0x00500000) +#define TIM_TRGO2Source_OC3Ref ((uint32_t)0x00600000) +#define TIM_TRGO2Source_OC4Ref ((uint32_t)0x00700000) +#define TIM_TRGO2Source_OC5Ref ((uint32_t)0x00800000) +#define TIM_TRGO2Source_OC6Ref ((uint32_t)0x00900000) +#define TIM_TRGO2Source_OC4Ref_RisingFalling ((uint32_t)0x00A00000) +#define TIM_TRGO2Source_OC6Ref_RisingFalling ((uint32_t)0x00B00000) +#define TIM_TRGO2Source_OC4RefRising_OC6RefRising ((uint32_t)0x00C00000) +#define TIM_TRGO2Source_OC4RefRising_OC6RefFalling ((uint32_t)0x00D00000) +#define TIM_TRGO2Source_OC5RefRising_OC6RefRising ((uint32_t)0x00E00000) +#define TIM_TRGO2Source_OC5RefRising_OC6RefFalling ((uint32_t)0x00F00000) +#define IS_TIM_TRGO2_SOURCE(SOURCE) (((SOURCE) == TIM_TRGO2Source_Reset) || \ + ((SOURCE) == TIM_TRGO2Source_Enable) || \ + ((SOURCE) == TIM_TRGO2Source_Update) || \ + ((SOURCE) == TIM_TRGO2Source_OC1) || \ + ((SOURCE) == TIM_TRGO2Source_OC1Ref) || \ + ((SOURCE) == TIM_TRGO2Source_OC2Ref) || \ + ((SOURCE) == TIM_TRGO2Source_OC3Ref) || \ + ((SOURCE) == TIM_TRGO2Source_OC4Ref) || \ + ((SOURCE) == TIM_TRGO2Source_OC5Ref) || \ + ((SOURCE) == TIM_TRGO2Source_OC6Ref) || \ + ((SOURCE) == TIM_TRGO2Source_OC4Ref_RisingFalling) || \ + ((SOURCE) == TIM_TRGO2Source_OC6Ref_RisingFalling) || \ + ((SOURCE) == TIM_TRGO2Source_OC4RefRising_OC6RefRising) || \ + ((SOURCE) == TIM_TRGO2Source_OC4RefRising_OC6RefFalling) || \ + ((SOURCE) == TIM_TRGO2Source_OC5RefRising_OC6RefRising) || \ + ((SOURCE) == TIM_TRGO2Source_OC5RefRising_OC6RefFalling)) +/** + * @} + */ + +/** @defgroup TIM_Slave_Mode + * @{ + */ + +#define TIM_SlaveMode_Reset ((uint32_t)0x00004) +#define TIM_SlaveMode_Gated ((uint32_t)0x00005) +#define TIM_SlaveMode_Trigger ((uint32_t)0x00006) +#define TIM_SlaveMode_External1 ((uint32_t)0x00007) +#define TIM_SlaveMode_Combined_ResetTrigger ((uint32_t)0x10000) +#define IS_TIM_SLAVE_MODE(MODE) (((MODE) == TIM_SlaveMode_Reset) || \ + ((MODE) == TIM_SlaveMode_Gated) || \ + ((MODE) == TIM_SlaveMode_Trigger) || \ + ((MODE) == TIM_SlaveMode_External1) || \ + ((MODE) == TIM_SlaveMode_Combined_ResetTrigger)) +/** + * @} + */ + +/** @defgroup TIM_Master_Slave_Mode + * @{ + */ + +#define TIM_MasterSlaveMode_Enable ((uint16_t)0x0080) +#define TIM_MasterSlaveMode_Disable ((uint16_t)0x0000) +#define IS_TIM_MSM_STATE(STATE) (((STATE) == TIM_MasterSlaveMode_Enable) || \ + ((STATE) == TIM_MasterSlaveMode_Disable)) +/** + * @} + */ +/** @defgroup TIM_Remap + * @{ + */ +#define TIM16_GPIO ((uint16_t)0x0000) +#define TIM16_RTC_CLK ((uint16_t)0x0001) +#define TIM16_HSEDiv32 ((uint16_t)0x0002) +#define TIM16_MCO ((uint16_t)0x0003) + +#define TIM1_ADC1_AWDG1 ((uint16_t)0x0001) +#define TIM1_ADC1_AWDG2 ((uint16_t)0x0002) +#define TIM1_ADC1_AWDG3 ((uint16_t)0x0003) +#define TIM1_ADC4_AWDG1 ((uint16_t)0x0004) +#define TIM1_ADC4_AWDG2 ((uint16_t)0x0008) +#define TIM1_ADC4_AWDG3 ((uint16_t)0x000C) + +#define TIM8_ADC2_AWDG1 ((uint16_t)0x0001) +#define TIM8_ADC2_AWDG2 ((uint16_t)0x0002) +#define TIM8_ADC2_AWDG3 ((uint16_t)0x0003) +#define TIM8_ADC3_AWDG1 ((uint16_t)0x0004) +#define TIM8_ADC3_AWDG2 ((uint16_t)0x0008) +#define TIM8_ADC3_AWDG3 ((uint16_t)0x000C) + +#define TIM20_ADC3_AWDG1 ((uint16_t)0x0001) +#define TIM20_ADC3_AWDG2 ((uint16_t)0x0002) +#define TIM20_ADC3_AWDG3 ((uint16_t)0x0003) +#define TIM20_ADC4_AWDG1 ((uint16_t)0x0004) +#define TIM20_ADC4_AWDG2 ((uint16_t)0x0008) +#define TIM20_ADC4_AWDG3 ((uint16_t)0x000C) + +#define IS_TIM_REMAP(TIM_REMAP) (((TIM_REMAP) == TIM16_GPIO)|| \ + ((TIM_REMAP) == TIM16_RTC_CLK) || \ + ((TIM_REMAP) == TIM16_HSEDiv32) || \ + ((TIM_REMAP) == TIM16_MCO) ||\ + ((TIM_REMAP) == TIM1_ADC1_AWDG1) ||\ + ((TIM_REMAP) == TIM1_ADC1_AWDG2) ||\ + ((TIM_REMAP) == TIM1_ADC1_AWDG3) ||\ + ((TIM_REMAP) == TIM1_ADC4_AWDG1) ||\ + ((TIM_REMAP) == TIM1_ADC4_AWDG2) ||\ + ((TIM_REMAP) == TIM1_ADC4_AWDG3) ||\ + ((TIM_REMAP) == TIM8_ADC2_AWDG1) ||\ + ((TIM_REMAP) == TIM8_ADC2_AWDG2) ||\ + ((TIM_REMAP) == TIM8_ADC2_AWDG3) ||\ + ((TIM_REMAP) == TIM8_ADC3_AWDG1) ||\ + ((TIM_REMAP) == TIM8_ADC3_AWDG2) ||\ + ((TIM_REMAP) == TIM8_ADC3_AWDG3) ||\ + ((TIM_REMAP) == TIM20_ADC3_AWDG1)||\ + ((TIM_REMAP) == TIM20_ADC3_AWDG2)||\ + ((TIM_REMAP) == TIM20_ADC3_AWDG3)||\ + ((TIM_REMAP) == TIM20_ADC4_AWDG1)||\ + ((TIM_REMAP) == TIM20_ADC4_AWDG2)||\ + ((TIM_REMAP) == TIM20_ADC4_AWDG3)) + +/** + * @} + */ +/** @defgroup TIM_Flags + * @{ + */ + +#define TIM_FLAG_Update ((uint32_t)0x00001) +#define TIM_FLAG_CC1 ((uint32_t)0x00002) +#define TIM_FLAG_CC2 ((uint32_t)0x00004) +#define TIM_FLAG_CC3 ((uint32_t)0x00008) +#define TIM_FLAG_CC4 ((uint32_t)0x00010) +#define TIM_FLAG_COM ((uint32_t)0x00020) +#define TIM_FLAG_Trigger ((uint32_t)0x00040) +#define TIM_FLAG_Break ((uint32_t)0x00080) +#define TIM_FLAG_Break2 ((uint32_t)0x00100) +#define TIM_FLAG_CC1OF ((uint32_t)0x00200) +#define TIM_FLAG_CC2OF ((uint32_t)0x00400) +#define TIM_FLAG_CC3OF ((uint32_t)0x00800) +#define TIM_FLAG_CC4OF ((uint32_t)0x01000) +#define TIM_FLAG_CC5 ((uint32_t)0x10000) +#define TIM_FLAG_CC6 ((uint32_t)0x20000) +#define IS_TIM_GET_FLAG(FLAG) (((FLAG) == TIM_FLAG_Update) || \ + ((FLAG) == TIM_FLAG_CC1) || \ + ((FLAG) == TIM_FLAG_CC2) || \ + ((FLAG) == TIM_FLAG_CC3) || \ + ((FLAG) == TIM_FLAG_CC4) || \ + ((FLAG) == TIM_FLAG_COM) || \ + ((FLAG) == TIM_FLAG_Trigger) || \ + ((FLAG) == TIM_FLAG_Break) || \ + ((FLAG) == TIM_FLAG_Break2) || \ + ((FLAG) == TIM_FLAG_CC1OF) || \ + ((FLAG) == TIM_FLAG_CC2OF) || \ + ((FLAG) == TIM_FLAG_CC3OF) || \ + ((FLAG) == TIM_FLAG_CC4OF) ||\ + ((FLAG) == TIM_FLAG_CC5) ||\ + ((FLAG) == TIM_FLAG_CC6)) + +#define IS_TIM_CLEAR_FLAG(TIM_FLAG) ((((TIM_FLAG) & (uint32_t)0xE000) == 0x0000) && ((TIM_FLAG) != 0x0000)) +/** + * @} + */ + +/** @defgroup TIM_OCReferenceClear + * @{ + */ +#define TIM_OCReferenceClear_ETRF ((uint16_t)0x0008) +#define TIM_OCReferenceClear_OCREFCLR ((uint16_t)0x0000) +#define TIM_OCREFERENCECECLEAR_SOURCE(SOURCE) (((SOURCE) == TIM_OCReferenceClear_ETRF) || \ + ((SOURCE) == TIM_OCReferenceClear_OCREFCLR)) + +/** @defgroup TIM_Input_Capture_Filer_Value + * @{ + */ + +#define IS_TIM_IC_FILTER(ICFILTER) ((ICFILTER) <= 0xF) +/** + * @} + */ + +/** @defgroup TIM_External_Trigger_Filter + * @{ + */ + +#define IS_TIM_EXT_FILTER(EXTFILTER) ((EXTFILTER) <= 0xF) +/** + * @} + */ + +/** @defgroup TIM_Legacy + * @{ + */ + +#define TIM_DMABurstLength_1Byte TIM_DMABurstLength_1Transfer +#define TIM_DMABurstLength_2Bytes TIM_DMABurstLength_2Transfers +#define TIM_DMABurstLength_3Bytes TIM_DMABurstLength_3Transfers +#define TIM_DMABurstLength_4Bytes TIM_DMABurstLength_4Transfers +#define TIM_DMABurstLength_5Bytes TIM_DMABurstLength_5Transfers +#define TIM_DMABurstLength_6Bytes TIM_DMABurstLength_6Transfers +#define TIM_DMABurstLength_7Bytes TIM_DMABurstLength_7Transfers +#define TIM_DMABurstLength_8Bytes TIM_DMABurstLength_8Transfers +#define TIM_DMABurstLength_9Bytes TIM_DMABurstLength_9Transfers +#define TIM_DMABurstLength_10Bytes TIM_DMABurstLength_10Transfers +#define TIM_DMABurstLength_11Bytes TIM_DMABurstLength_11Transfers +#define TIM_DMABurstLength_12Bytes TIM_DMABurstLength_12Transfers +#define TIM_DMABurstLength_13Bytes TIM_DMABurstLength_13Transfers +#define TIM_DMABurstLength_14Bytes TIM_DMABurstLength_14Transfers +#define TIM_DMABurstLength_15Bytes TIM_DMABurstLength_15Transfers +#define TIM_DMABurstLength_16Bytes TIM_DMABurstLength_16Transfers +#define TIM_DMABurstLength_17Bytes TIM_DMABurstLength_17Transfers +#define TIM_DMABurstLength_18Bytes TIM_DMABurstLength_18Transfers +/** + * @} + */ + +/** + * @} + */ + +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions --------------------------------------------------------*/ + +/* TimeBase management ********************************************************/ +void TIM_DeInit(TIM_TypeDef* TIMx); +void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct); +void TIM_TimeBaseStructInit(TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct); +void TIM_PrescalerConfig(TIM_TypeDef* TIMx, uint16_t Prescaler, uint16_t TIM_PSCReloadMode); +void TIM_CounterModeConfig(TIM_TypeDef* TIMx, uint16_t TIM_CounterMode); +void TIM_SetCounter(TIM_TypeDef* TIMx, uint32_t Counter); +void TIM_SetAutoreload(TIM_TypeDef* TIMx, uint32_t Autoreload); +uint32_t TIM_GetCounter(TIM_TypeDef* TIMx); +uint16_t TIM_GetPrescaler(TIM_TypeDef* TIMx); +void TIM_UpdateDisableConfig(TIM_TypeDef* TIMx, FunctionalState NewState); +void TIM_UpdateRequestConfig(TIM_TypeDef* TIMx, uint16_t TIM_UpdateSource); +void TIM_UIFRemap(TIM_TypeDef* TIMx, FunctionalState NewState); +void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState); +void TIM_SelectOnePulseMode(TIM_TypeDef* TIMx, uint16_t TIM_OPMode); +void TIM_SetClockDivision(TIM_TypeDef* TIMx, uint16_t TIM_CKD); +void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState); + +/* Output Compare management **************************************************/ +void TIM_OC1Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct); +void TIM_OC2Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct); +void TIM_OC3Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct); +void TIM_OC4Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct); +void TIM_OC5Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct); +void TIM_OC6Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct); +void TIM_SelectGC5C1(TIM_TypeDef* TIMx, FunctionalState NewState); +void TIM_SelectGC5C2(TIM_TypeDef* TIMx, FunctionalState NewState); +void TIM_SelectGC5C3(TIM_TypeDef* TIMx, FunctionalState NewState); +void TIM_OCStructInit(TIM_OCInitTypeDef* TIM_OCInitStruct); +void TIM_SelectOCxM(TIM_TypeDef* TIMx, uint16_t TIM_Channel, uint32_t TIM_OCMode); +void TIM_SetCompare1(TIM_TypeDef* TIMx, uint32_t Compare1); +void TIM_SetCompare2(TIM_TypeDef* TIMx, uint32_t Compare2); +void TIM_SetCompare3(TIM_TypeDef* TIMx, uint32_t Compare3); +void TIM_SetCompare4(TIM_TypeDef* TIMx, uint32_t Compare4); +void TIM_SetCompare5(TIM_TypeDef* TIMx, uint32_t Compare5); +void TIM_SetCompare6(TIM_TypeDef* TIMx, uint32_t Compare6); +void TIM_ForcedOC1Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction); +void TIM_ForcedOC2Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction); +void TIM_ForcedOC3Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction); +void TIM_ForcedOC4Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction); +void TIM_ForcedOC5Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction); +void TIM_ForcedOC6Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction); +void TIM_OC1PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload); +void TIM_OC2PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload); +void TIM_OC3PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload); +void TIM_OC4PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload); +void TIM_OC5PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload); +void TIM_OC6PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload); +void TIM_OC1FastConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCFast); +void TIM_OC2FastConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCFast); +void TIM_OC3FastConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCFast); +void TIM_OC4FastConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCFast); +void TIM_ClearOC1Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear); +void TIM_ClearOC2Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear); +void TIM_ClearOC3Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear); +void TIM_ClearOC4Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear); +void TIM_ClearOC5Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear); +void TIM_ClearOC6Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear); +void TIM_SelectOCREFClear(TIM_TypeDef* TIMx, uint16_t TIM_OCReferenceClear); +void TIM_OC1PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity); +void TIM_OC1NPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCNPolarity); +void TIM_OC2PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity); +void TIM_OC2NPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCNPolarity); +void TIM_OC3PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity); +void TIM_OC3NPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCNPolarity); +void TIM_OC4PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity); +void TIM_OC5PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity); +void TIM_OC6PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity); +void TIM_CCxCmd(TIM_TypeDef* TIMx, uint16_t TIM_Channel, uint16_t TIM_CCx); +void TIM_CCxNCmd(TIM_TypeDef* TIMx, uint16_t TIM_Channel, uint16_t TIM_CCxN); + +/* Input Capture management ***************************************************/ +void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct); +void TIM_ICStructInit(TIM_ICInitTypeDef* TIM_ICInitStruct); +void TIM_PWMIConfig(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct); +uint32_t TIM_GetCapture1(TIM_TypeDef* TIMx); +uint32_t TIM_GetCapture2(TIM_TypeDef* TIMx); +uint32_t TIM_GetCapture3(TIM_TypeDef* TIMx); +uint32_t TIM_GetCapture4(TIM_TypeDef* TIMx); +void TIM_SetIC1Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC); +void TIM_SetIC2Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC); +void TIM_SetIC3Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC); +void TIM_SetIC4Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC); + +/* Advanced-control timers (TIM1 and TIM8) specific features ******************/ +void TIM_BDTRConfig(TIM_TypeDef* TIMx, TIM_BDTRInitTypeDef *TIM_BDTRInitStruct); +void TIM_Break1Config(TIM_TypeDef* TIMx, uint32_t TIM_Break1Polarity, uint8_t TIM_Break1Filter); +void TIM_Break2Config(TIM_TypeDef* TIMx, uint32_t TIM_Break2Polarity, uint8_t TIM_Break2Filter); +void TIM_Break1Cmd(TIM_TypeDef* TIMx, FunctionalState NewState); +void TIM_Break2Cmd(TIM_TypeDef* TIMx, FunctionalState NewState); +void TIM_BDTRStructInit(TIM_BDTRInitTypeDef* TIM_BDTRInitStruct); +void TIM_CtrlPWMOutputs(TIM_TypeDef* TIMx, FunctionalState NewState); +void TIM_SelectCOM(TIM_TypeDef* TIMx, FunctionalState NewState); +void TIM_CCPreloadControl(TIM_TypeDef* TIMx, FunctionalState NewState); + +/* Interrupts, DMA and flags management ***************************************/ +void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState); +void TIM_GenerateEvent(TIM_TypeDef* TIMx, uint16_t TIM_EventSource); +FlagStatus TIM_GetFlagStatus(TIM_TypeDef* TIMx, uint32_t TIM_FLAG); +void TIM_ClearFlag(TIM_TypeDef* TIMx, uint16_t TIM_FLAG); +ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t TIM_IT); +void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT); +void TIM_DMAConfig(TIM_TypeDef* TIMx, uint16_t TIM_DMABase, uint16_t TIM_DMABurstLength); +void TIM_DMACmd(TIM_TypeDef* TIMx, uint16_t TIM_DMASource, FunctionalState NewState); +void TIM_SelectCCDMA(TIM_TypeDef* TIMx, FunctionalState NewState); + +/* Clocks management **********************************************************/ +void TIM_InternalClockConfig(TIM_TypeDef* TIMx); +void TIM_ITRxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource); +void TIM_TIxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_TIxExternalCLKSource, + uint16_t TIM_ICPolarity, uint16_t ICFilter); +void TIM_ETRClockMode1Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity, + uint16_t ExtTRGFilter); +void TIM_ETRClockMode2Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, + uint16_t TIM_ExtTRGPolarity, uint16_t ExtTRGFilter); + +/* Synchronization management *************************************************/ +void TIM_SelectInputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource); +void TIM_SelectOutputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_TRGOSource); +void TIM_SelectOutputTrigger2(TIM_TypeDef* TIMx, uint32_t TIM_TRGO2Source); +void TIM_SelectSlaveMode(TIM_TypeDef* TIMx, uint32_t TIM_SlaveMode); +void TIM_SelectMasterSlaveMode(TIM_TypeDef* TIMx, uint16_t TIM_MasterSlaveMode); +void TIM_ETRConfig(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity, + uint16_t ExtTRGFilter); + +/* Specific interface management **********************************************/ +void TIM_EncoderInterfaceConfig(TIM_TypeDef* TIMx, uint16_t TIM_EncoderMode, + uint16_t TIM_IC1Polarity, uint16_t TIM_IC2Polarity); +void TIM_SelectHallSensor(TIM_TypeDef* TIMx, FunctionalState NewState); + +/* Specific remapping management **********************************************/ +void TIM_RemapConfig(TIM_TypeDef* TIMx, uint16_t TIM_Remap); + +#ifdef __cplusplus +} +#endif + +#endif /*__STM32F30x_TIM_H */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_usart.h b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_usart.h new file mode 100755 index 0000000000..4a62acd878 --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_usart.h @@ -0,0 +1,607 @@ +/** + ****************************************************************************** + * @file stm32f30x_usart.h + * @author MCD Application Team + * @version V1.2.3 + * @date 10-July-2015 + * @brief This file contains all the functions prototypes for the USART + * firmware library. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F30x_USART_H +#define __STM32F30x_USART_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f30x.h" + +/** @addtogroup STM32F30x_StdPeriph_Driver + * @{ + */ + +/** @addtogroup USART + * @{ + */ + +/* Exported types ------------------------------------------------------------*/ + + + +/** + * @brief USART Init Structure definition + */ + +typedef struct +{ + uint32_t USART_BaudRate; /*!< This member configures the USART communication baud rate. + The baud rate is computed using the following formula: + - IntegerDivider = ((PCLKx) / (16 * (USART_InitStruct->USART_BaudRate))) + - FractionalDivider = ((IntegerDivider - ((uint32_t) IntegerDivider)) * 16) + 0.5 */ + + uint32_t USART_WordLength; /*!< Specifies the number of data bits transmitted or received in a frame. + This parameter can be a value of @ref USART_Word_Length */ + + uint32_t USART_StopBits; /*!< Specifies the number of stop bits transmitted. + This parameter can be a value of @ref USART_Stop_Bits */ + + uint32_t USART_Parity; /*!< Specifies the parity mode. + This parameter can be a value of @ref USART_Parity + @note When parity is enabled, the computed parity is inserted + at the MSB position of the transmitted data (9th bit when + the word length is set to 9 data bits; 8th bit when the + word length is set to 8 data bits). */ + + uint32_t USART_Mode; /*!< Specifies whether the Receive or Transmit mode is enabled or disabled. + This parameter can be a value of @ref USART_Mode */ + + uint32_t USART_HardwareFlowControl; /*!< Specifies whether the hardware flow control mode is enabled + or disabled. + This parameter can be a value of @ref USART_Hardware_Flow_Control*/ +} USART_InitTypeDef; + +/** + * @brief USART Clock Init Structure definition + */ + +typedef struct +{ + uint32_t USART_Clock; /*!< Specifies whether the USART clock is enabled or disabled. + This parameter can be a value of @ref USART_Clock */ + + uint32_t USART_CPOL; /*!< Specifies the steady state of the serial clock. + This parameter can be a value of @ref USART_Clock_Polarity */ + + uint32_t USART_CPHA; /*!< Specifies the clock transition on which the bit capture is made. + This parameter can be a value of @ref USART_Clock_Phase */ + + uint32_t USART_LastBit; /*!< Specifies whether the clock pulse corresponding to the last transmitted + data bit (MSB) has to be output on the SCLK pin in synchronous mode. + This parameter can be a value of @ref USART_Last_Bit */ +} USART_ClockInitTypeDef; + +/* Exported constants --------------------------------------------------------*/ + +/** @defgroup USART_Exported_Constants + * @{ + */ + +#define IS_USART_ALL_PERIPH(PERIPH) (((PERIPH) == USART1) || \ + ((PERIPH) == USART2) || \ + ((PERIPH) == USART3) || \ + ((PERIPH) == UART4) || \ + ((PERIPH) == UART5)) + +#define IS_USART_123_PERIPH(PERIPH) (((PERIPH) == USART1) || \ + ((PERIPH) == USART2) || \ + ((PERIPH) == USART3)) + +#define IS_USART_1234_PERIPH(PERIPH) (((PERIPH) == USART1) || \ + ((PERIPH) == USART2) || \ + ((PERIPH) == USART3) || \ + ((PERIPH) == UART4)) + + +/** @defgroup USART_Word_Length + * @{ + */ + +#define USART_WordLength_8b ((uint32_t)0x00000000) +#define USART_WordLength_9b USART_CR1_M +#define IS_USART_WORD_LENGTH(LENGTH) (((LENGTH) == USART_WordLength_8b) || \ + ((LENGTH) == USART_WordLength_9b)) +/** + * @} + */ + +/** @defgroup USART_Stop_Bits + * @{ + */ + +#define USART_StopBits_1 ((uint32_t)0x00000000) +#define USART_StopBits_2 USART_CR2_STOP_1 +#define USART_StopBits_1_5 (USART_CR2_STOP_0 | USART_CR2_STOP_1) +#define IS_USART_STOPBITS(STOPBITS) (((STOPBITS) == USART_StopBits_1) || \ + ((STOPBITS) == USART_StopBits_2) || \ + ((STOPBITS) == USART_StopBits_1_5)) +/** + * @} + */ + +/** @defgroup USART_Parity + * @{ + */ + +#define USART_Parity_No ((uint32_t)0x00000000) +#define USART_Parity_Even USART_CR1_PCE +#define USART_Parity_Odd (USART_CR1_PCE | USART_CR1_PS) +#define IS_USART_PARITY(PARITY) (((PARITY) == USART_Parity_No) || \ + ((PARITY) == USART_Parity_Even) || \ + ((PARITY) == USART_Parity_Odd)) +/** + * @} + */ + +/** @defgroup USART_Mode + * @{ + */ + +#define USART_Mode_Rx USART_CR1_RE +#define USART_Mode_Tx USART_CR1_TE +#define IS_USART_MODE(MODE) ((((MODE) & (uint32_t)0xFFFFFFF3) == 0x00) && \ + ((MODE) != (uint32_t)0x00)) +/** + * @} + */ + +/** @defgroup USART_Hardware_Flow_Control + * @{ + */ + +#define USART_HardwareFlowControl_None ((uint32_t)0x00000000) +#define USART_HardwareFlowControl_RTS USART_CR3_RTSE +#define USART_HardwareFlowControl_CTS USART_CR3_CTSE +#define USART_HardwareFlowControl_RTS_CTS (USART_CR3_RTSE | USART_CR3_CTSE) +#define IS_USART_HARDWARE_FLOW_CONTROL(CONTROL)\ + (((CONTROL) == USART_HardwareFlowControl_None) || \ + ((CONTROL) == USART_HardwareFlowControl_RTS) || \ + ((CONTROL) == USART_HardwareFlowControl_CTS) || \ + ((CONTROL) == USART_HardwareFlowControl_RTS_CTS)) +/** + * @} + */ + +/** @defgroup USART_Clock + * @{ + */ + +#define USART_Clock_Disable ((uint32_t)0x00000000) +#define USART_Clock_Enable USART_CR2_CLKEN +#define IS_USART_CLOCK(CLOCK) (((CLOCK) == USART_Clock_Disable) || \ + ((CLOCK) == USART_Clock_Enable)) +/** + * @} + */ + +/** @defgroup USART_Clock_Polarity + * @{ + */ + +#define USART_CPOL_Low ((uint32_t)0x00000000) +#define USART_CPOL_High USART_CR2_CPOL +#define IS_USART_CPOL(CPOL) (((CPOL) == USART_CPOL_Low) || ((CPOL) == USART_CPOL_High)) + +/** + * @} + */ + +/** @defgroup USART_Clock_Phase + * @{ + */ + +#define USART_CPHA_1Edge ((uint32_t)0x00000000) +#define USART_CPHA_2Edge USART_CR2_CPHA +#define IS_USART_CPHA(CPHA) (((CPHA) == USART_CPHA_1Edge) || ((CPHA) == USART_CPHA_2Edge)) + +/** + * @} + */ + +/** @defgroup USART_Last_Bit + * @{ + */ + +#define USART_LastBit_Disable ((uint32_t)0x00000000) +#define USART_LastBit_Enable USART_CR2_LBCL +#define IS_USART_LASTBIT(LASTBIT) (((LASTBIT) == USART_LastBit_Disable) || \ + ((LASTBIT) == USART_LastBit_Enable)) +/** + * @} + */ + +/** @defgroup USART_DMA_Requests + * @{ + */ + +#define USART_DMAReq_Tx USART_CR3_DMAT +#define USART_DMAReq_Rx USART_CR3_DMAR +#define IS_USART_DMAREQ(DMAREQ) ((((DMAREQ) & (uint32_t)0xFFFFFF3F) == 0x00) && \ + ((DMAREQ) != (uint32_t)0x00)) + +/** + * @} + */ + +/** @defgroup USART_DMA_Recception_Error + * @{ + */ + +#define USART_DMAOnError_Enable ((uint32_t)0x00000000) +#define USART_DMAOnError_Disable USART_CR3_DDRE +#define IS_USART_DMAONERROR(DMAERROR) (((DMAERROR) == USART_DMAOnError_Disable)|| \ + ((DMAERROR) == USART_DMAOnError_Enable)) +/** + * @} + */ + +/** @defgroup USART_MuteMode_WakeUp_methods + * @{ + */ + +#define USART_WakeUp_IdleLine ((uint32_t)0x00000000) +#define USART_WakeUp_AddressMark USART_CR1_WAKE +#define IS_USART_MUTEMODE_WAKEUP(WAKEUP) (((WAKEUP) == USART_WakeUp_IdleLine) || \ + ((WAKEUP) == USART_WakeUp_AddressMark)) +/** + * @} + */ + +/** @defgroup USART_Address_Detection + * @{ + */ + +#define USART_AddressLength_4b ((uint32_t)0x00000000) +#define USART_AddressLength_7b USART_CR2_ADDM7 +#define IS_USART_ADDRESS_DETECTION(ADDRESS) (((ADDRESS) == USART_AddressLength_4b) || \ + ((ADDRESS) == USART_AddressLength_7b)) +/** + * @} + */ + +/** @defgroup USART_StopMode_WakeUp_methods + * @{ + */ + +#define USART_WakeUpSource_AddressMatch ((uint32_t)0x00000000) +#define USART_WakeUpSource_StartBit USART_CR3_WUS_1 +#define USART_WakeUpSource_RXNE (uint32_t)(USART_CR3_WUS_0 | USART_CR3_WUS_1) +#define IS_USART_STOPMODE_WAKEUPSOURCE(SOURCE) (((SOURCE) == USART_WakeUpSource_AddressMatch) || \ + ((SOURCE) == USART_WakeUpSource_StartBit) || \ + ((SOURCE) == USART_WakeUpSource_RXNE)) +/** + * @} + */ + +/** @defgroup USART_LIN_Break_Detection_Length + * @{ + */ + +#define USART_LINBreakDetectLength_10b ((uint32_t)0x00000000) +#define USART_LINBreakDetectLength_11b USART_CR2_LBDL +#define IS_USART_LIN_BREAK_DETECT_LENGTH(LENGTH) \ + (((LENGTH) == USART_LINBreakDetectLength_10b) || \ + ((LENGTH) == USART_LINBreakDetectLength_11b)) +/** + * @} + */ + +/** @defgroup USART_IrDA_Low_Power + * @{ + */ + +#define USART_IrDAMode_LowPower USART_CR3_IRLP +#define USART_IrDAMode_Normal ((uint32_t)0x00000000) +#define IS_USART_IRDA_MODE(MODE) (((MODE) == USART_IrDAMode_LowPower) || \ + ((MODE) == USART_IrDAMode_Normal)) +/** + * @} + */ + +/** @defgroup USART_DE_Polarity + * @{ + */ + +#define USART_DEPolarity_High ((uint32_t)0x00000000) +#define USART_DEPolarity_Low USART_CR3_DEP +#define IS_USART_DE_POLARITY(POLARITY) (((POLARITY) == USART_DEPolarity_Low) || \ + ((POLARITY) == USART_DEPolarity_High)) +/** + * @} + */ + +/** @defgroup USART_Inversion_Pins + * @{ + */ + +#define USART_InvPin_Tx USART_CR2_TXINV +#define USART_InvPin_Rx USART_CR2_RXINV +#define IS_USART_INVERSTION_PIN(PIN) ((((PIN) & (uint32_t)0xFFFCFFFF) == 0x00) && \ + ((PIN) != (uint32_t)0x00)) + +/** + * @} + */ + +/** @defgroup USART_AutoBaudRate_Mode + * @{ + */ + +#define USART_AutoBaudRate_StartBit ((uint32_t)0x00000000) +#define USART_AutoBaudRate_FallingEdge USART_CR2_ABRMODE_0 +#define USART_AutoBaudRate_0x7FFrame USART_CR2_ABRMODE_1 +#define USART_AutoBaudRate_0x55Frame (USART_CR2_ABRMODE_0 | USART_CR2_ABRMODE_1) +#define IS_USART_AUTOBAUDRATE_MODE(MODE) (((MODE) == USART_AutoBaudRate_StartBit) || \ + ((MODE) == USART_AutoBaudRate_FallingEdge) || \ + ((MODE) == USART_AutoBaudRate_0x7FFrame) || \ + ((MODE) == USART_AutoBaudRate_0x55Frame)) +/** + * @} + */ + +/** @defgroup USART_OVR_DETECTION + * @{ + */ + +#define USART_OVRDetection_Enable ((uint32_t)0x00000000) +#define USART_OVRDetection_Disable USART_CR3_OVRDIS +#define IS_USART_OVRDETECTION(OVR) (((OVR) == USART_OVRDetection_Enable)|| \ + ((OVR) == USART_OVRDetection_Disable)) +/** + * @} + */ +/** @defgroup USART_Request + * @{ + */ + +#define USART_Request_ABRRQ USART_RQR_ABRRQ +#define USART_Request_SBKRQ USART_RQR_SBKRQ +#define USART_Request_MMRQ USART_RQR_MMRQ +#define USART_Request_RXFRQ USART_RQR_RXFRQ +#define USART_Request_TXFRQ USART_RQR_TXFRQ + +#define IS_USART_REQUEST(REQUEST) (((REQUEST) == USART_Request_TXFRQ) || \ + ((REQUEST) == USART_Request_RXFRQ) || \ + ((REQUEST) == USART_Request_MMRQ) || \ + ((REQUEST) == USART_Request_SBKRQ) || \ + ((REQUEST) == USART_Request_ABRRQ)) +/** + * @} + */ + +/** @defgroup USART_Flags + * @{ + */ +#define USART_FLAG_REACK USART_ISR_REACK +#define USART_FLAG_TEACK USART_ISR_TEACK +#define USART_FLAG_WU USART_ISR_WUF +#define USART_FLAG_RWU USART_ISR_RWU +#define USART_FLAG_SBK USART_ISR_SBKF +#define USART_FLAG_CM USART_ISR_CMF +#define USART_FLAG_BUSY USART_ISR_BUSY +#define USART_FLAG_ABRF USART_ISR_ABRF +#define USART_FLAG_ABRE USART_ISR_ABRE +#define USART_FLAG_EOB USART_ISR_EOBF +#define USART_FLAG_RTO USART_ISR_RTOF +#define USART_FLAG_nCTSS USART_ISR_CTS +#define USART_FLAG_CTS USART_ISR_CTSIF +#define USART_FLAG_LBD USART_ISR_LBD +#define USART_FLAG_TXE USART_ISR_TXE +#define USART_FLAG_TC USART_ISR_TC +#define USART_FLAG_RXNE USART_ISR_RXNE +#define USART_FLAG_IDLE USART_ISR_IDLE +#define USART_FLAG_ORE USART_ISR_ORE +#define USART_FLAG_NE USART_ISR_NE +#define USART_FLAG_FE USART_ISR_FE +#define USART_FLAG_PE USART_ISR_PE +#define IS_USART_FLAG(FLAG) (((FLAG) == USART_FLAG_PE) || ((FLAG) == USART_FLAG_TXE) || \ + ((FLAG) == USART_FLAG_TC) || ((FLAG) == USART_FLAG_RXNE) || \ + ((FLAG) == USART_FLAG_IDLE) || ((FLAG) == USART_FLAG_LBD) || \ + ((FLAG) == USART_FLAG_CTS) || ((FLAG) == USART_FLAG_ORE) || \ + ((FLAG) == USART_FLAG_NE) || ((FLAG) == USART_FLAG_FE) || \ + ((FLAG) == USART_FLAG_nCTSS) || ((FLAG) == USART_FLAG_RTO) || \ + ((FLAG) == USART_FLAG_EOB) || ((FLAG) == USART_FLAG_ABRE) || \ + ((FLAG) == USART_FLAG_ABRF) || ((FLAG) == USART_FLAG_BUSY) || \ + ((FLAG) == USART_FLAG_CM) || ((FLAG) == USART_FLAG_SBK) || \ + ((FLAG) == USART_FLAG_RWU) || ((FLAG) == USART_FLAG_WU) || \ + ((FLAG) == USART_FLAG_TEACK)|| ((FLAG) == USART_FLAG_REACK)) + +#define IS_USART_CLEAR_FLAG(FLAG) (((FLAG) == USART_FLAG_WU) || ((FLAG) == USART_FLAG_TC) || \ + ((FLAG) == USART_FLAG_IDLE) || ((FLAG) == USART_FLAG_ORE) || \ + ((FLAG) == USART_FLAG_NE) || ((FLAG) == USART_FLAG_FE) || \ + ((FLAG) == USART_FLAG_LBD) || ((FLAG) == USART_FLAG_CTS) || \ + ((FLAG) == USART_FLAG_RTO) || ((FLAG) == USART_FLAG_EOB) || \ + ((FLAG) == USART_FLAG_CM) || ((FLAG) == USART_FLAG_PE)) +/** + * @} + */ + +/** @defgroup USART_Interrupt_definition + * @brief USART Interrupt definition + * USART_IT possible values + * Elements values convention: 0xZZZZYYXX + * XX: Position of the corresponding Interrupt + * YY: Register index + * ZZZZ: Flag position + * @{ + */ + +#define USART_IT_WU ((uint32_t)0x00140316) +#define USART_IT_CM ((uint32_t)0x0011010E) +#define USART_IT_EOB ((uint32_t)0x000C011B) +#define USART_IT_RTO ((uint32_t)0x000B011A) +#define USART_IT_PE ((uint32_t)0x00000108) +#define USART_IT_TXE ((uint32_t)0x00070107) +#define USART_IT_TC ((uint32_t)0x00060106) +#define USART_IT_RXNE ((uint32_t)0x00050105) +#define USART_IT_IDLE ((uint32_t)0x00040104) +#define USART_IT_LBD ((uint32_t)0x00080206) +#define USART_IT_CTS ((uint32_t)0x0009030A) +#define USART_IT_ERR ((uint32_t)0x00000300) +#define USART_IT_ORE ((uint32_t)0x00030300) +#define USART_IT_NE ((uint32_t)0x00020300) +#define USART_IT_FE ((uint32_t)0x00010300) + +#define IS_USART_CONFIG_IT(IT) (((IT) == USART_IT_PE) || ((IT) == USART_IT_TXE) || \ + ((IT) == USART_IT_TC) || ((IT) == USART_IT_RXNE) || \ + ((IT) == USART_IT_IDLE) || ((IT) == USART_IT_LBD) || \ + ((IT) == USART_IT_CTS) || ((IT) == USART_IT_ERR) || \ + ((IT) == USART_IT_RTO) || ((IT) == USART_IT_EOB) || \ + ((IT) == USART_IT_CM) || ((IT) == USART_IT_WU)) + +#define IS_USART_GET_IT(IT) (((IT) == USART_IT_PE) || ((IT) == USART_IT_TXE) || \ + ((IT) == USART_IT_TC) || ((IT) == USART_IT_RXNE) || \ + ((IT) == USART_IT_IDLE) || ((IT) == USART_IT_LBD) || \ + ((IT) == USART_IT_CTS) || ((IT) == USART_IT_ORE) || \ + ((IT) == USART_IT_NE) || ((IT) == USART_IT_FE) || \ + ((IT) == USART_IT_RTO) || ((IT) == USART_IT_EOB) || \ + ((IT) == USART_IT_CM) || ((IT) == USART_IT_WU)) + +#define IS_USART_CLEAR_IT(IT) (((IT) == USART_IT_TC) || ((IT) == USART_IT_PE) || \ + ((IT) == USART_IT_FE) || ((IT) == USART_IT_NE) || \ + ((IT) == USART_IT_ORE) || ((IT) == USART_IT_IDLE) || \ + ((IT) == USART_IT_LBD) || ((IT) == USART_IT_CTS) || \ + ((IT) == USART_IT_RTO) || ((IT) == USART_IT_EOB) || \ + ((IT) == USART_IT_CM) || ((IT) == USART_IT_WU)) +/** + * @} + */ + +/** @defgroup USART_Global_definition + * @{ + */ + +#define IS_USART_BAUDRATE(BAUDRATE) (((BAUDRATE) > 0) && ((BAUDRATE) < 0x005B8D81)) +#define IS_USART_DE_ASSERTION_DEASSERTION_TIME(TIME) ((TIME) <= 0x1F) +#define IS_USART_AUTO_RETRY_COUNTER(COUNTER) ((COUNTER) <= 0x7) +#define IS_USART_TIMEOUT(TIMEOUT) ((TIMEOUT) <= 0x00FFFFFF) +#define IS_USART_DATA(DATA) ((DATA) <= 0x1FF) + +/** + * @} + */ + +/** + * @} + */ + +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions ------------------------------------------------------- */ + +/* Initialization and Configuration functions *********************************/ +void USART_DeInit(USART_TypeDef* USARTx); +void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct); +void USART_StructInit(USART_InitTypeDef* USART_InitStruct); +void USART_ClockInit(USART_TypeDef* USARTx, USART_ClockInitTypeDef* USART_ClockInitStruct); +void USART_ClockStructInit(USART_ClockInitTypeDef* USART_ClockInitStruct); +void USART_Cmd(USART_TypeDef* USARTx, FunctionalState NewState); +void USART_DirectionModeCmd(USART_TypeDef* USARTx, uint32_t USART_DirectionMode, FunctionalState NewState); +void USART_SetPrescaler(USART_TypeDef* USARTx, uint8_t USART_Prescaler); +void USART_OverSampling8Cmd(USART_TypeDef* USARTx, FunctionalState NewState); +void USART_OneBitMethodCmd(USART_TypeDef* USARTx, FunctionalState NewState); +void USART_MSBFirstCmd(USART_TypeDef* USARTx, FunctionalState NewState); +void USART_DataInvCmd(USART_TypeDef* USARTx, FunctionalState NewState); +void USART_InvPinCmd(USART_TypeDef* USARTx, uint32_t USART_InvPin, FunctionalState NewState); +void USART_SWAPPinCmd(USART_TypeDef* USARTx, FunctionalState NewState); +void USART_ReceiverTimeOutCmd(USART_TypeDef* USARTx, FunctionalState NewState); +void USART_SetReceiverTimeOut(USART_TypeDef* USARTx, uint32_t USART_ReceiverTimeOut); + +/* STOP Mode functions ********************************************************/ +void USART_STOPModeCmd(USART_TypeDef* USARTx, FunctionalState NewState); +void USART_StopModeWakeUpSourceConfig(USART_TypeDef* USARTx, uint32_t USART_WakeUpSource); + +/* AutoBaudRate functions *****************************************************/ +void USART_AutoBaudRateCmd(USART_TypeDef* USARTx, FunctionalState NewState); +void USART_AutoBaudRateConfig(USART_TypeDef* USARTx, uint32_t USART_AutoBaudRate); + +/* Data transfers functions ***************************************************/ +void USART_SendData(USART_TypeDef* USARTx, uint16_t Data); +uint16_t USART_ReceiveData(USART_TypeDef* USARTx); + +/* Multi-Processor Communication functions ************************************/ +void USART_SetAddress(USART_TypeDef* USARTx, uint8_t USART_Address); +void USART_MuteModeWakeUpConfig(USART_TypeDef* USARTx, uint32_t USART_WakeUp); +void USART_MuteModeCmd(USART_TypeDef* USARTx, FunctionalState NewState); +void USART_AddressDetectionConfig(USART_TypeDef* USARTx, uint32_t USART_AddressLength); +/* LIN mode functions *********************************************************/ +void USART_LINBreakDetectLengthConfig(USART_TypeDef* USARTx, uint32_t USART_LINBreakDetectLength); +void USART_LINCmd(USART_TypeDef* USARTx, FunctionalState NewState); + +/* Half-duplex mode function **************************************************/ +void USART_HalfDuplexCmd(USART_TypeDef* USARTx, FunctionalState NewState); + +/* Smartcard mode functions ***************************************************/ +void USART_SmartCardCmd(USART_TypeDef* USARTx, FunctionalState NewState); +void USART_SmartCardNACKCmd(USART_TypeDef* USARTx, FunctionalState NewState); +void USART_SetGuardTime(USART_TypeDef* USARTx, uint8_t USART_GuardTime); +void USART_SetAutoRetryCount(USART_TypeDef* USARTx, uint8_t USART_AutoCount); +void USART_SetBlockLength(USART_TypeDef* USARTx, uint8_t USART_BlockLength); + +/* IrDA mode functions ********************************************************/ +void USART_IrDAConfig(USART_TypeDef* USARTx, uint32_t USART_IrDAMode); +void USART_IrDACmd(USART_TypeDef* USARTx, FunctionalState NewState); + +/* RS485 mode functions *******************************************************/ +void USART_DECmd(USART_TypeDef* USARTx, FunctionalState NewState); +void USART_DEPolarityConfig(USART_TypeDef* USARTx, uint32_t USART_DEPolarity); +void USART_SetDEAssertionTime(USART_TypeDef* USARTx, uint32_t USART_DEAssertionTime); +void USART_SetDEDeassertionTime(USART_TypeDef* USARTx, uint32_t USART_DEDeassertionTime); + +/* DMA transfers management functions *****************************************/ +void USART_DMACmd(USART_TypeDef* USARTx, uint32_t USART_DMAReq, FunctionalState NewState); +void USART_DMAReceptionErrorConfig(USART_TypeDef* USARTx, uint32_t USART_DMAOnError); + +/* Interrupts and flags management functions **********************************/ +void USART_ITConfig(USART_TypeDef* USARTx, uint32_t USART_IT, FunctionalState NewState); +void USART_RequestCmd(USART_TypeDef* USARTx, uint32_t USART_Request, FunctionalState NewState); +void USART_OverrunDetectionConfig(USART_TypeDef* USARTx, uint32_t USART_OVRDetection); +FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint32_t USART_FLAG); +void USART_ClearFlag(USART_TypeDef* USARTx, uint32_t USART_FLAG); +ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint32_t USART_IT); +void USART_ClearITPendingBit(USART_TypeDef* USARTx, uint32_t USART_IT); + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F30x_USART_H */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_wwdg.h b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_wwdg.h new file mode 100755 index 0000000000..b3ddd36c90 --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/inc/stm32f30x_wwdg.h @@ -0,0 +1,109 @@ +/** + ****************************************************************************** + * @file stm32f30x_wwdg.h + * @author MCD Application Team + * @version V1.2.3 + * @date 10-July-2015 + * @brief This file contains all the functions prototypes for the WWDG + * firmware library. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F30x_WWDG_H +#define __STM32F30x_WWDG_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f30x.h" + +/** @addtogroup STM32F30x_StdPeriph_Driver + * @{ + */ + +/** @addtogroup WWDG + * @{ + */ +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +/** @defgroup WWDG_Exported_Constants + * @{ + */ + +/** @defgroup WWDG_Prescaler + * @{ + */ + +#define WWDG_Prescaler_1 ((uint32_t)0x00000000) +#define WWDG_Prescaler_2 ((uint32_t)0x00000080) +#define WWDG_Prescaler_4 ((uint32_t)0x00000100) +#define WWDG_Prescaler_8 ((uint32_t)0x00000180) +#define IS_WWDG_PRESCALER(PRESCALER) (((PRESCALER) == WWDG_Prescaler_1) || \ + ((PRESCALER) == WWDG_Prescaler_2) || \ + ((PRESCALER) == WWDG_Prescaler_4) || \ + ((PRESCALER) == WWDG_Prescaler_8)) +#define IS_WWDG_WINDOW_VALUE(VALUE) ((VALUE) <= 0x7F) +#define IS_WWDG_COUNTER(COUNTER) (((COUNTER) >= 0x40) && ((COUNTER) <= 0x7F)) + +/** + * @} + */ + +/** + * @} + */ + +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions ------------------------------------------------------- */ +/* Function used to set the WWDG configuration to the default reset state ****/ +void WWDG_DeInit(void); + +/* Prescaler, Refresh window and Counter configuration functions **************/ +void WWDG_SetPrescaler(uint32_t WWDG_Prescaler); +void WWDG_SetWindowValue(uint8_t WindowValue); +void WWDG_EnableIT(void); +void WWDG_SetCounter(uint8_t Counter); + +/* WWDG activation functions **************************************************/ +void WWDG_Enable(uint8_t Counter); + +/* Interrupts and flags management functions **********************************/ +FlagStatus WWDG_GetFlagStatus(void); +void WWDG_ClearFlag(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F30x_WWDG_H */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_adc.c b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_adc.c new file mode 100755 index 0000000000..44da04dbcd --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_adc.c @@ -0,0 +1,2401 @@ +/** + ****************************************************************************** + * @file stm32f30x_adc.c + * @author MCD Application Team + * @version V1.2.3 + * @date 10-July-2015 + * @brief This file provides firmware functions to manage the following + * functionalities of the Analog to Digital Convertor (ADC) peripheral: + * + Initialization and Configuration + * + Analog Watchdog configuration + * + Temperature Sensor, Vbat & Vrefint (Internal Reference Voltage) management + * + Regular Channels Configuration + * + Regular Channels DMA Configuration + * + Injected channels Configuration + * + Interrupts and flags management + * + Dual mode configuration + * + @verbatim + ============================================================================== + ##### How to use this driver ##### + ============================================================================== + [..] + (#) select the ADC clock using the function RCC_ADCCLKConfig() + (#) Enable the ADC interface clock using RCC_AHBPeriphClockCmd(); + (#) ADC pins configuration + (++) Enable the clock for the ADC GPIOs using the following function: + RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOx, ENABLE); + (++) Configure these ADC pins in analog mode using GPIO_Init(); + (#) Configure the ADC conversion resolution, data alignment, external + trigger and edge, sequencer lenght and Enable/Disable the continuous mode + using the ADC_Init() function. + (#) Activate the ADC peripheral using ADC_Cmd() function. + + *** ADC channels group configuration *** + ======================================== + [..] + (+) To configure the ADC channels features, use ADC_Init(), ADC_InjectedInit() + and/or ADC_RegularChannelConfig() functions. + (+) To activate the continuous mode, use the ADC_ContinuousModeCmd() + function. + (+) To activate the Discontinuous mode, use the ADC_DiscModeCmd() functions. + (+) To activate the overrun mode, use the ADC_OverrunModeCmd() functions. + (+) To activate the calibration mode, use the ADC_StartCalibration() functions. + (+) To read the ADC converted values, use the ADC_GetConversionValue() + function. + + *** DMA for ADC channels features configuration *** + =================================================== + [..] + (+) To enable the DMA mode for ADC channels group, use the ADC_DMACmd() function. + (+) To configure the DMA transfer request, use ADC_DMAConfig() function. + + @endverbatim + * + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f30x_adc.h" +#include "stm32f30x_rcc.h" + +/** @addtogroup STM32F30x_StdPeriph_Driver + * @{ + */ + +/** @defgroup ADC + * @brief ADC driver modules + * @{ + */ + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ + +/* CFGR register Mask */ +#define CFGR_CLEAR_Mask ((uint32_t)0xFDFFC007) + +/* JSQR register Mask */ +#define JSQR_CLEAR_Mask ((uint32_t)0x00000000) + +/* ADC ADON mask */ +#define CCR_CLEAR_MASK ((uint32_t)0xFFFC10E0) + +/* ADC JDRx registers offset */ +#define JDR_Offset ((uint8_t)0x80) + +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/* Private function prototypes -----------------------------------------------*/ +/* Private functions ---------------------------------------------------------*/ + +/** @defgroup ADC_Private_Functions + * @{ + */ + +/** @defgroup ADC_Group1 Initialization and Configuration functions + * @brief Initialization and Configuration functions + * +@verbatim + =============================================================================== + ##### Initialization and Configuration functions ##### + =============================================================================== + [..] + This section provides functions allowing to: + (#) Initialize and configure the ADC injected and/or regular channels and dual mode. + (#) Management of the calibration process + (#) ADC Power-on Power-off + (#) Single ended or differential mode + (#) Enabling the queue of context and the auto delay mode + (#) The number of ADC conversions that will be done using the sequencer for regular + channel group + (#) Enable or disable the ADC peripheral + +@endverbatim + * @{ + */ + +/** + * @brief Deinitializes the ADCx peripheral registers to their default reset values. + * @param ADCx: where x can be 1, 2,3 or 4 to select the ADC peripheral. + * @retval None + */ +void ADC_DeInit(ADC_TypeDef* ADCx) +{ + /* Check the parameters */ + assert_param(IS_ADC_ALL_PERIPH(ADCx)); + + + if((ADCx == ADC1) || (ADCx == ADC2)) + { + /* Enable ADC1/ADC2 reset state */ + RCC_AHBPeriphResetCmd(RCC_AHBPeriph_ADC12, ENABLE); + /* Release ADC1/ADC2 from reset state */ + RCC_AHBPeriphResetCmd(RCC_AHBPeriph_ADC12, DISABLE); + } + else if((ADCx == ADC3) || (ADCx == ADC4)) + { + /* Enable ADC3/ADC4 reset state */ + RCC_AHBPeriphResetCmd(RCC_AHBPeriph_ADC34, ENABLE); + /* Release ADC3/ADC4 from reset state */ + RCC_AHBPeriphResetCmd(RCC_AHBPeriph_ADC34, DISABLE); + } +} +/** + * @brief Initializes the ADCx peripheral according to the specified parameters + * in the ADC_InitStruct. + * @param ADCx: where x can be 1, 2, 3 or 4 to select the ADC peripheral. + * @param ADC_InitStruct: pointer to an ADC_InitTypeDef structure that contains + * the configuration information for the specified ADC peripheral. + * @retval None + */ +void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct) +{ + uint32_t tmpreg1 = 0; + /* Check the parameters */ + assert_param(IS_ADC_ALL_PERIPH(ADCx)); + assert_param(IS_ADC_CONVMODE(ADC_InitStruct->ADC_ContinuousConvMode)); + assert_param(IS_ADC_RESOLUTION(ADC_InitStruct->ADC_Resolution)); + assert_param(IS_ADC_EXT_TRIG(ADC_InitStruct->ADC_ExternalTrigConvEvent)); + assert_param(IS_EXTERNALTRIG_EDGE(ADC_InitStruct->ADC_ExternalTrigEventEdge)); + assert_param(IS_ADC_DATA_ALIGN(ADC_InitStruct->ADC_DataAlign)); + assert_param(IS_ADC_OVRUNMODE(ADC_InitStruct->ADC_OverrunMode)); + assert_param(IS_ADC_AUTOINJECMODE(ADC_InitStruct->ADC_AutoInjMode)); + assert_param(IS_ADC_REGULAR_LENGTH(ADC_InitStruct->ADC_NbrOfRegChannel)); + + /*---------------------------- ADCx CFGR Configuration -----------------*/ + /* Get the ADCx CFGR value */ + tmpreg1 = ADCx->CFGR; + /* Clear SCAN bit */ + tmpreg1 &= CFGR_CLEAR_Mask; + /* Configure ADCx: scan conversion mode */ + /* Set SCAN bit according to ADC_ScanConvMode value */ + tmpreg1 |= (uint32_t)ADC_InitStruct->ADC_ContinuousConvMode | + ADC_InitStruct->ADC_Resolution| + ADC_InitStruct->ADC_ExternalTrigConvEvent| + ADC_InitStruct->ADC_ExternalTrigEventEdge| + ADC_InitStruct->ADC_DataAlign| + ADC_InitStruct->ADC_OverrunMode| + ADC_InitStruct->ADC_AutoInjMode; + + /* Write to ADCx CFGR */ + ADCx->CFGR = tmpreg1; + + /*---------------------------- ADCx SQR1 Configuration -----------------*/ + /* Get the ADCx SQR1 value */ + tmpreg1 = ADCx->SQR1; + /* Clear L bits */ + tmpreg1 &= ~(uint32_t)(ADC_SQR1_L); + /* Configure ADCx: regular channel sequence length */ + /* Set L bits according to ADC_NbrOfRegChannel value */ + tmpreg1 |= (uint32_t) (ADC_InitStruct->ADC_NbrOfRegChannel - 1); + /* Write to ADCx SQR1 */ + ADCx->SQR1 = tmpreg1; + +} + +/** + * @brief Fills each ADC_InitStruct member with its default value. + * @param ADC_InitStruct : pointer to an ADC_InitTypeDef structure which will be initialized. + * @retval None + */ +void ADC_StructInit(ADC_InitTypeDef* ADC_InitStruct) +{ + /* Reset ADC init structure parameters values */ + ADC_InitStruct->ADC_ContinuousConvMode = DISABLE; + ADC_InitStruct->ADC_Resolution = ADC_Resolution_12b; + ADC_InitStruct->ADC_ExternalTrigConvEvent = ADC_ExternalTrigConvEvent_0; + ADC_InitStruct->ADC_ExternalTrigEventEdge = ADC_ExternalTrigEventEdge_None; + ADC_InitStruct->ADC_DataAlign = ADC_DataAlign_Right; + ADC_InitStruct->ADC_OverrunMode = DISABLE; + ADC_InitStruct->ADC_AutoInjMode = DISABLE; + ADC_InitStruct->ADC_NbrOfRegChannel = 1; +} + +/** + * @brief Initializes the ADCx peripheral according to the specified parameters + * in the ADC_InitStruct. + * @param ADCx: where x can be 1, 2, 3 or 4 to select the ADC peripheral. + * @param ADC_InjectInitStruct: pointer to an ADC_InjecInitTypeDef structure that contains + * the configuration information for the specified ADC injected channel. + * @retval None + */ +void ADC_InjectedInit(ADC_TypeDef* ADCx, ADC_InjectedInitTypeDef* ADC_InjectedInitStruct) +{ + uint32_t tmpreg1 = 0; + /* Check the parameters */ + assert_param(IS_ADC_ALL_PERIPH(ADCx)); + assert_param(IS_ADC_EXT_INJEC_TRIG(ADC_InjectedInitStruct->ADC_ExternalTrigInjecConvEvent)); + assert_param(IS_EXTERNALTRIGINJ_EDGE(ADC_InjectedInitStruct->ADC_ExternalTrigInjecEventEdge)); + assert_param(IS_ADC_INJECTED_LENGTH(ADC_InjectedInitStruct->ADC_NbrOfInjecChannel)); + assert_param(IS_ADC_INJECTED_CHANNEL(ADC_InjectedInitStruct->ADC_InjecSequence1)); + assert_param(IS_ADC_INJECTED_CHANNEL(ADC_InjectedInitStruct->ADC_InjecSequence2)); + assert_param(IS_ADC_INJECTED_CHANNEL(ADC_InjectedInitStruct->ADC_InjecSequence3)); + assert_param(IS_ADC_INJECTED_CHANNEL(ADC_InjectedInitStruct->ADC_InjecSequence4)); + + /*---------------------------- ADCx JSQR Configuration -----------------*/ + /* Get the ADCx JSQR value */ + tmpreg1 = ADCx->JSQR; + /* Clear L bits */ + tmpreg1 &= JSQR_CLEAR_Mask; + /* Configure ADCx: Injected channel sequence length, external trigger, + external trigger edge and sequences + */ + tmpreg1 = (uint32_t) ((ADC_InjectedInitStruct->ADC_NbrOfInjecChannel - (uint8_t)1) | + ADC_InjectedInitStruct->ADC_ExternalTrigInjecConvEvent | + ADC_InjectedInitStruct->ADC_ExternalTrigInjecEventEdge | + (uint32_t)((ADC_InjectedInitStruct->ADC_InjecSequence1) << 8) | + (uint32_t)((ADC_InjectedInitStruct->ADC_InjecSequence2) << 14) | + (uint32_t)((ADC_InjectedInitStruct->ADC_InjecSequence3) << 20) | + (uint32_t)((ADC_InjectedInitStruct->ADC_InjecSequence4) << 26)); + /* Write to ADCx SQR1 */ + ADCx->JSQR = tmpreg1; +} + +/** + * @brief Fills each ADC_InjectedInitStruct member with its default value. + * @param ADC_InjectedInitStruct : pointer to an ADC_InjectedInitTypeDef structure which will be initialized. + * @retval None + */ +void ADC_InjectedStructInit(ADC_InjectedInitTypeDef* ADC_InjectedInitStruct) +{ + ADC_InjectedInitStruct->ADC_ExternalTrigInjecConvEvent = ADC_ExternalTrigInjecConvEvent_0; + ADC_InjectedInitStruct->ADC_ExternalTrigInjecEventEdge = ADC_ExternalTrigInjecEventEdge_None; + ADC_InjectedInitStruct->ADC_NbrOfInjecChannel = 1; + ADC_InjectedInitStruct->ADC_InjecSequence1 = ADC_InjectedChannel_1; + ADC_InjectedInitStruct->ADC_InjecSequence2 = ADC_InjectedChannel_1; + ADC_InjectedInitStruct->ADC_InjecSequence3 = ADC_InjectedChannel_1; + ADC_InjectedInitStruct->ADC_InjecSequence4 = ADC_InjectedChannel_1; +} + +/** + * @brief Initializes the ADCs peripherals according to the specified parameters + * in the ADC_CommonInitStruct. + * @param ADCx: where x can be 1 or 4 to select the ADC peripheral. + * @param ADC_CommonInitStruct: pointer to an ADC_CommonInitTypeDef structure + * that contains the configuration information for All ADCs peripherals. + * @retval None + */ +void ADC_CommonInit(ADC_TypeDef* ADCx, ADC_CommonInitTypeDef* ADC_CommonInitStruct) +{ + uint32_t tmpreg1 = 0; + /* Check the parameters */ + assert_param(IS_ADC_MODE(ADC_CommonInitStruct->ADC_Mode)); + assert_param(IS_ADC_CLOCKMODE(ADC_CommonInitStruct->ADC_Clock)); + assert_param(IS_ADC_DMA_MODE(ADC_CommonInitStruct->ADC_DMAMode)); + assert_param(IS_ADC_DMA_ACCESS_MODE(ADC_CommonInitStruct->ADC_DMAAccessMode)); + assert_param(IS_ADC_TWOSAMPLING_DELAY(ADC_CommonInitStruct->ADC_TwoSamplingDelay)); + + if((ADCx == ADC1) || (ADCx == ADC2)) + { + /* Get the ADC CCR value */ + tmpreg1 = ADC1_2->CCR; + + /* Clear MULTI, DELAY, DMA and ADCPRE bits */ + tmpreg1 &= CCR_CLEAR_MASK; + } + else + { + /* Get the ADC CCR value */ + tmpreg1 = ADC3_4->CCR; + + /* Clear MULTI, DELAY, DMA and ADCPRE bits */ + tmpreg1 &= CCR_CLEAR_MASK; + } + /*---------------------------- ADC CCR Configuration -----------------*/ + /* Configure ADCx: Multi mode, Delay between two sampling time, ADC clock, DMA mode + and DMA access mode for dual mode */ + /* Set MULTI bits according to ADC_Mode value */ + /* Set CKMODE bits according to ADC_Clock value */ + /* Set MDMA bits according to ADC_DMAAccessMode value */ + /* Set DMACFG bits according to ADC_DMAMode value */ + /* Set DELAY bits according to ADC_TwoSamplingDelay value */ + tmpreg1 |= (uint32_t)(ADC_CommonInitStruct->ADC_Mode | + ADC_CommonInitStruct->ADC_Clock | + ADC_CommonInitStruct->ADC_DMAAccessMode | + (uint32_t)(ADC_CommonInitStruct->ADC_DMAMode << 12) | + (uint32_t)((uint32_t)ADC_CommonInitStruct->ADC_TwoSamplingDelay << 8)); + + if((ADCx == ADC1) || (ADCx == ADC2)) + { + /* Write to ADC CCR */ + ADC1_2->CCR = tmpreg1; + } + else + { + /* Write to ADC CCR */ + ADC3_4->CCR = tmpreg1; + } +} + +/** + * @brief Fills each ADC_CommonInitStruct member with its default value. + * @param ADC_CommonInitStruct: pointer to an ADC_CommonInitTypeDef structure + * which will be initialized. + * @retval None + */ +void ADC_CommonStructInit(ADC_CommonInitTypeDef* ADC_CommonInitStruct) +{ + /* Initialize the ADC_Mode member */ + ADC_CommonInitStruct->ADC_Mode = ADC_Mode_Independent; + + /* initialize the ADC_Clock member */ + ADC_CommonInitStruct->ADC_Clock = ADC_Clock_AsynClkMode; + + /* Initialize the ADC_DMAAccessMode member */ + ADC_CommonInitStruct->ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; + + /* Initialize the ADC_DMAMode member */ + ADC_CommonInitStruct->ADC_DMAMode = ADC_DMAMode_OneShot; + + /* Initialize the ADC_TwoSamplingDelay member */ + ADC_CommonInitStruct->ADC_TwoSamplingDelay = 0; + +} + +/** + * @brief Enables or disables the specified ADC peripheral. + * @param ADCx: where x can be 1, 2, 3 or 4 to select the ADC peripheral. + * @param NewState: new state of the ADCx peripheral. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void ADC_Cmd(ADC_TypeDef* ADCx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_ADC_ALL_PERIPH(ADCx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Set the ADEN bit */ + ADCx->CR |= ADC_CR_ADEN; + } + else + { + /* Disable the selected ADC peripheral: Set the ADDIS bit */ + ADCx->CR |= ADC_CR_ADDIS; + } +} + +/** + * @brief Starts the selected ADC calibration process. + * @param ADCx: where x can be 1, 2, 3 or 4 to select the ADC peripheral. + * @retval None + */ +void ADC_StartCalibration(ADC_TypeDef* ADCx) +{ + /* Check the parameters */ + assert_param(IS_ADC_ALL_PERIPH(ADCx)); + + /* Set the ADCAL bit */ + ADCx->CR |= ADC_CR_ADCAL; +} + +/** + * @brief Returns the ADCx calibration value. + * @param ADCx: where x can be 1, 2, 3 or 4 to select the ADC peripheral. + * @retval None + */ +uint32_t ADC_GetCalibrationValue(ADC_TypeDef* ADCx) +{ + /* Check the parameters */ + assert_param(IS_ADC_ALL_PERIPH(ADCx)); + + /* Return the selected ADC calibration value */ + return (uint32_t)ADCx->CALFACT; +} + +/** + * @brief Sets the ADCx calibration register. + * @param ADCx: where x can be 1, 2, 3 or 4 to select the ADC peripheral. + * @retval None + */ +void ADC_SetCalibrationValue(ADC_TypeDef* ADCx, uint32_t ADC_Calibration) +{ + /* Check the parameters */ + assert_param(IS_ADC_ALL_PERIPH(ADCx)); + + /* Set the ADC calibration register value */ + ADCx->CALFACT = ADC_Calibration; +} + +/** + * @brief Select the ADC calibration mode. + * @param ADCx: where x can be 1, 2, 3 or 4 to select the ADC peripheral. + * @param ADC_CalibrationMode: the ADC calibration mode. + * This parameter can be one of the following values: + * @arg ADC_CalibrationMode_Single: to select the calibration for single channel + * @arg ADC_CalibrationMode_Differential: to select the calibration for differential channel + * @retval None + */ +void ADC_SelectCalibrationMode(ADC_TypeDef* ADCx, uint32_t ADC_CalibrationMode) +{ + /* Check the parameters */ + assert_param(IS_ADC_ALL_PERIPH(ADCx)); + assert_param(IS_ADC_CALIBRATION_MODE(ADC_CalibrationMode)); + /* Set or Reset the ADCALDIF bit */ + ADCx->CR &= (~ADC_CR_ADCALDIF); + ADCx->CR |= ADC_CalibrationMode; + +} + +/** + * @brief Gets the selected ADC calibration status. + * @param ADCx: where x can be 1, 2, 3 or 4 to select the ADC peripheral. + * @retval The new state of ADC calibration (SET or RESET). + */ +FlagStatus ADC_GetCalibrationStatus(ADC_TypeDef* ADCx) +{ + FlagStatus bitstatus = RESET; + /* Check the parameters */ + assert_param(IS_ADC_ALL_PERIPH(ADCx)); + /* Check the status of CAL bit */ + if ((ADCx->CR & ADC_CR_ADCAL) != (uint32_t)RESET) + { + /* CAL bit is set: calibration on going */ + bitstatus = SET; + } + else + { + /* CAL bit is reset: end of calibration */ + bitstatus = RESET; + } + /* Return the CAL bit status */ + return bitstatus; +} + +/** + * @brief ADC Disable Command. + * @param ADCx: where x can be 1, 2, 3 or 4 to select the ADC peripheral. + * @retval None + */ +void ADC_DisableCmd(ADC_TypeDef* ADCx) +{ + /* Check the parameters */ + assert_param(IS_ADC_ALL_PERIPH(ADCx)); + + /* Set the ADDIS bit */ + ADCx->CR |= ADC_CR_ADDIS; +} + + +/** + * @brief Gets the selected ADC disable command Status. + * @param ADCx: where x can be 1, 2, 3 or 4 to select the ADC peripheral. + * @retval The new state of ADC ADC disable command (SET or RESET). + */ +FlagStatus ADC_GetDisableCmdStatus(ADC_TypeDef* ADCx) +{ + FlagStatus bitstatus = RESET; + /* Check the parameters */ + assert_param(IS_ADC_ALL_PERIPH(ADCx)); + + /* Check the status of ADDIS bit */ + if ((ADCx->CR & ADC_CR_ADDIS) != (uint32_t)RESET) + { + /* ADDIS bit is set */ + bitstatus = SET; + } + else + { + /* ADDIS bit is reset */ + bitstatus = RESET; + } + /* Return the ADDIS bit status */ + return bitstatus; +} + +/** + * @brief Enables or disables the specified ADC Voltage Regulator. + * @param ADCx: where x can be 1, 2, 3 or 4 to select the ADC peripheral. + * @param NewState: new state of the ADCx Voltage Regulator. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void ADC_VoltageRegulatorCmd(ADC_TypeDef* ADCx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_ADC_ALL_PERIPH(ADCx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + /* set the intermediate state before moving the ADC voltage regulator + from enable state to disable state or from disable state to enable state */ + ADCx->CR &= ~(ADC_CR_ADVREGEN); + + if (NewState != DISABLE) + { + /* Set the ADVREGEN bit 0 */ + ADCx->CR |= ADC_CR_ADVREGEN_0; + } + else + { + /* Set the ADVREGEN bit 1 */ + ADCx->CR |=ADC_CR_ADVREGEN_1; + } +} + +/** + * @brief Selects the differential mode for a specific channel + * @param ADCx: where x can be 1, 2, 3 or 4 to select the ADC peripheral. + * @param ADC_Channel: the ADC channel to configure for the analog watchdog. + * This parameter can be one of the following values: + * @arg ADC_Channel_1: ADC Channel1 selected + * @arg ADC_Channel_2: ADC Channel2 selected + * @arg ADC_Channel_3: ADC Channel3 selected + * @arg ADC_Channel_4: ADC Channel4 selected + * @arg ADC_Channel_5: ADC Channel5 selected + * @arg ADC_Channel_6: ADC Channel6 selected + * @arg ADC_Channel_7: ADC Channel7 selected + * @arg ADC_Channel_8: ADC Channel8 selected + * @arg ADC_Channel_9: ADC Channel9 selected + * @arg ADC_Channel_10: ADC Channel10 selected + * @arg ADC_Channel_11: ADC Channel11 selected + * @arg ADC_Channel_12: ADC Channel12 selected + * @arg ADC_Channel_13: ADC Channel13 selected + * @arg ADC_Channel_14: ADC Channel14 selected + * @note : Channel 15, 16 and 17 are fixed to single-ended inputs mode. + * @retval None + */ +void ADC_SelectDifferentialMode(ADC_TypeDef* ADCx, uint8_t ADC_Channel, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_ADC_ALL_PERIPH(ADCx)); + assert_param(IS_ADC_DIFFCHANNEL(ADC_Channel)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Set the DIFSEL bit */ + ADCx->DIFSEL |= (uint32_t)(1 << ADC_Channel ); + } + else + { + /* Reset the DIFSEL bit */ + ADCx->DIFSEL &= ~(uint32_t)(1 << ADC_Channel); + } +} + +/** + * @brief Selects the Queue Of Context Mode for injected channels. + * @param ADCx: where x can be 1, 2, 3 or 4 to select the ADC peripheral. + * @param NewState: new state of the Queue Of Context Mode. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void ADC_SelectQueueOfContextMode(ADC_TypeDef* ADCx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_ADC_ALL_PERIPH(ADCx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Set the JQM bit */ + ADCx->CFGR |= (uint32_t)(ADC_CFGR_JQM ); + } + else + { + /* Reset the JQM bit */ + ADCx->CFGR &= ~(uint32_t)(ADC_CFGR_JQM); + } +} + +/** + * @brief Selects the ADC Delayed Conversion Mode. + * @param ADCx: where x can be 1, 2, 3 or 4 to select the ADC peripheral. + * @param NewState: new state of the ADC Delayed Conversion Mode. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void ADC_AutoDelayCmd(ADC_TypeDef* ADCx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_ADC_ALL_PERIPH(ADCx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Set the AUTDLY bit */ + ADCx->CFGR |= (uint32_t)(ADC_CFGR_AUTDLY ); + } + else + { + /* Reset the AUTDLY bit */ + ADCx->CFGR &= ~(uint32_t)(ADC_CFGR_AUTDLY); + } +} + +/** + * @} + */ + +/** @defgroup ADC_Group2 Analog Watchdog configuration functions + * @brief Analog Watchdog configuration functions + * +@verbatim + =============================================================================== + ##### Analog Watchdog configuration functions ##### + =============================================================================== + + [..] This section provides functions allowing to configure the 3 Analog Watchdogs + (AWDG1, AWDG2 and AWDG3) in the ADC. + + [..] A typical configuration Analog Watchdog is done following these steps : + (#) The ADC guarded channel(s) is (are) selected using the functions: + (++) ADC_AnalogWatchdog1SingleChannelConfig(). + (++) ADC_AnalogWatchdog2SingleChannelConfig(). + (++) ADC_AnalogWatchdog3SingleChannelConfig(). + + (#) The Analog watchdog lower and higher threshold are configured using the functions: + (++) ADC_AnalogWatchdog1ThresholdsConfig(). + (++) ADC_AnalogWatchdog2ThresholdsConfig(). + (++) ADC_AnalogWatchdog3ThresholdsConfig(). + + (#) The Analog watchdog is enabled and configured to enable the check, on one + or more channels, using the function: + (++) ADC_AnalogWatchdogCmd(). + +@endverbatim + * @{ + */ + +/** + * @brief Enables or disables the analog watchdog on single/all regular + * or injected channels + * @param ADCx: where x can be 1, 2, 3 or 4 to select the ADC peripheral. + * @param ADC_AnalogWatchdog: the ADC analog watchdog configuration. + * This parameter can be one of the following values: + * @arg ADC_AnalogWatchdog_SingleRegEnable: Analog watchdog on a single regular channel + * @arg ADC_AnalogWatchdog_SingleInjecEnable: Analog watchdog on a single injected channel + * @arg ADC_AnalogWatchdog_SingleRegOrInjecEnable: Analog watchdog on a single regular or injected channel + * @arg ADC_AnalogWatchdog_AllRegEnable: Analog watchdog on all regular channel + * @arg ADC_AnalogWatchdog_AllInjecEnable: Analog watchdog on all injected channel + * @arg ADC_AnalogWatchdog_AllRegAllInjecEnable: Analog watchdog on all regular and injected channels + * @arg ADC_AnalogWatchdog_None: No channel guarded by the analog watchdog + * @retval None + */ +void ADC_AnalogWatchdogCmd(ADC_TypeDef* ADCx, uint32_t ADC_AnalogWatchdog) +{ + uint32_t tmpreg = 0; + /* Check the parameters */ + assert_param(IS_ADC_ALL_PERIPH(ADCx)); + assert_param(IS_ADC_ANALOG_WATCHDOG(ADC_AnalogWatchdog)); + /* Get the old register value */ + tmpreg = ADCx->CFGR; + /* Clear AWDEN, AWDENJ and AWDSGL bits */ + tmpreg &= ~(uint32_t)(ADC_CFGR_AWD1SGL|ADC_CFGR_AWD1EN|ADC_CFGR_JAWD1EN); + /* Set the analog watchdog enable mode */ + tmpreg |= ADC_AnalogWatchdog; + /* Store the new register value */ + ADCx->CFGR = tmpreg; +} + +/** + * @brief Configures the high and low thresholds of the analog watchdog1. + * @param ADCx: where x can be 1, 2, 3 or 4 to select the ADC peripheral. + * @param HighThreshold: the ADC analog watchdog High threshold value. + * This parameter must be a 12bit value. + * @param LowThreshold: the ADC analog watchdog Low threshold value. + * This parameter must be a 12bit value. + * @retval None + */ +void ADC_AnalogWatchdog1ThresholdsConfig(ADC_TypeDef* ADCx, uint16_t HighThreshold, + uint16_t LowThreshold) +{ + /* Check the parameters */ + assert_param(IS_ADC_ALL_PERIPH(ADCx)); + assert_param(IS_ADC_THRESHOLD(HighThreshold)); + assert_param(IS_ADC_THRESHOLD(LowThreshold)); + /* Set the ADCx high threshold */ + ADCx->TR1 &= ~(uint32_t)ADC_TR1_HT1; + ADCx->TR1 |= (uint32_t)((uint32_t)HighThreshold << 16); + + /* Set the ADCx low threshold */ + ADCx->TR1 &= ~(uint32_t)ADC_TR1_LT1; + ADCx->TR1 |= LowThreshold; +} + +/** + * @brief Configures the high and low thresholds of the analog watchdog2. + * @param ADCx: where x can be 1, 2, 3 or 4 to select the ADC peripheral. + * @param HighThreshold: the ADC analog watchdog High threshold value. + * This parameter must be a 8bit value. + * @param LowThreshold: the ADC analog watchdog Low threshold value. + * This parameter must be a 8bit value. + * @retval None + */ +void ADC_AnalogWatchdog2ThresholdsConfig(ADC_TypeDef* ADCx, uint8_t HighThreshold, + uint8_t LowThreshold) +{ + /* Check the parameters */ + assert_param(IS_ADC_ALL_PERIPH(ADCx)); + + /* Set the ADCx high threshold */ + ADCx->TR2 &= ~(uint32_t)ADC_TR2_HT2; + ADCx->TR2 |= (uint32_t)((uint32_t)HighThreshold << 16); + + /* Set the ADCx low threshold */ + ADCx->TR2 &= ~(uint32_t)ADC_TR2_LT2; + ADCx->TR2 |= LowThreshold; +} + +/** + * @brief Configures the high and low thresholds of the analog watchdog3. + * @param ADCx: where x can be 1, 2, 3 or 4 to select the ADC peripheral. + * @param HighThreshold: the ADC analog watchdog High threshold value. + * This parameter must be a 8bit value. + * @param LowThreshold: the ADC analog watchdog Low threshold value. + * This parameter must be a 8bit value. + * @retval None + */ +void ADC_AnalogWatchdog3ThresholdsConfig(ADC_TypeDef* ADCx, uint8_t HighThreshold, + uint8_t LowThreshold) +{ + /* Check the parameters */ + assert_param(IS_ADC_ALL_PERIPH(ADCx)); + + /* Set the ADCx high threshold */ + ADCx->TR3 &= ~(uint32_t)ADC_TR3_HT3; + ADCx->TR3 |= (uint32_t)((uint32_t)HighThreshold << 16); + + /* Set the ADCx low threshold */ + ADCx->TR3 &= ~(uint32_t)ADC_TR3_LT3; + ADCx->TR3 |= LowThreshold; +} + +/** + * @brief Configures the analog watchdog 2 guarded single channel + * @param ADCx: where x can be 1, 2, 3 or 4 to select the ADC peripheral. + * @param ADC_Channel: the ADC channel to configure for the analog watchdog. + * This parameter can be one of the following values: + * @arg ADC_Channel_1: ADC Channel1 selected + * @arg ADC_Channel_2: ADC Channel2 selected + * @arg ADC_Channel_3: ADC Channel3 selected + * @arg ADC_Channel_4: ADC Channel4 selected + * @arg ADC_Channel_5: ADC Channel5 selected + * @arg ADC_Channel_6: ADC Channel6 selected + * @arg ADC_Channel_7: ADC Channel7 selected + * @arg ADC_Channel_8: ADC Channel8 selected + * @arg ADC_Channel_9: ADC Channel9 selected + * @arg ADC_Channel_10: ADC Channel10 selected + * @arg ADC_Channel_11: ADC Channel11 selected + * @arg ADC_Channel_12: ADC Channel12 selected + * @arg ADC_Channel_13: ADC Channel13 selected + * @arg ADC_Channel_14: ADC Channel14 selected + * @arg ADC_Channel_15: ADC Channel15 selected + * @arg ADC_Channel_16: ADC Channel16 selected + * @arg ADC_Channel_17: ADC Channel17 selected + * @arg ADC_Channel_18: ADC Channel18 selected + * @retval None + */ +void ADC_AnalogWatchdog1SingleChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel) +{ + uint32_t tmpreg = 0; + /* Check the parameters */ + assert_param(IS_ADC_ALL_PERIPH(ADCx)); + assert_param(IS_ADC_CHANNEL(ADC_Channel)); + /* Get the old register value */ + tmpreg = ADCx->CFGR; + /* Clear the Analog watchdog channel select bits */ + tmpreg &= ~(uint32_t)ADC_CFGR_AWD1CH; + /* Set the Analog watchdog channel */ + tmpreg |= (uint32_t)((uint32_t)ADC_Channel << 26); + /* Store the new register value */ + ADCx->CFGR = tmpreg; +} + +/** + * @brief Configures the analog watchdog 2 guarded single channel + * @param ADCx: where x can be 1, 2, 3 or 4 to select the ADC peripheral. + * @param ADC_Channel: the ADC channel to configure for the analog watchdog. + * This parameter can be one of the following values: + * @arg ADC_Channel_1: ADC Channel1 selected + * @arg ADC_Channel_2: ADC Channel2 selected + * @arg ADC_Channel_3: ADC Channel3 selected + * @arg ADC_Channel_4: ADC Channel4 selected + * @arg ADC_Channel_5: ADC Channel5 selected + * @arg ADC_Channel_6: ADC Channel6 selected + * @arg ADC_Channel_7: ADC Channel7 selected + * @arg ADC_Channel_8: ADC Channel8 selected + * @arg ADC_Channel_9: ADC Channel9 selected + * @arg ADC_Channel_10: ADC Channel10 selected + * @arg ADC_Channel_11: ADC Channel11 selected + * @arg ADC_Channel_12: ADC Channel12 selected + * @arg ADC_Channel_13: ADC Channel13 selected + * @arg ADC_Channel_14: ADC Channel14 selected + * @arg ADC_Channel_15: ADC Channel15 selected + * @arg ADC_Channel_16: ADC Channel16 selected + * @arg ADC_Channel_17: ADC Channel17 selected + * @arg ADC_Channel_18: ADC Channel18 selected + * @retval None + */ +void ADC_AnalogWatchdog2SingleChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel) +{ + uint32_t tmpreg = 0; + /* Check the parameters */ + assert_param(IS_ADC_ALL_PERIPH(ADCx)); + assert_param(IS_ADC_CHANNEL(ADC_Channel)); + /* Get the old register value */ + tmpreg = ADCx->AWD2CR; + /* Clear the Analog watchdog channel select bits */ + tmpreg &= ~(uint32_t)ADC_AWD2CR_AWD2CH; + /* Set the Analog watchdog channel */ + tmpreg |= (uint32_t)1 << (ADC_Channel); + /* Store the new register value */ + ADCx->AWD2CR |= tmpreg; +} + +/** + * @brief Configures the analog watchdog 3 guarded single channel + * @param ADCx: where x can be 1, 2, 3 or 4 to select the ADC peripheral. + * @param ADC_Channel: the ADC channel to configure for the analog watchdog. + * This parameter can be one of the following values: + * @arg ADC_Channel_1: ADC Channel1 selected + * @arg ADC_Channel_2: ADC Channel2 selected + * @arg ADC_Channel_3: ADC Channel3 selected + * @arg ADC_Channel_4: ADC Channel4 selected + * @arg ADC_Channel_5: ADC Channel5 selected + * @arg ADC_Channel_6: ADC Channel6 selected + * @arg ADC_Channel_7: ADC Channel7 selected + * @arg ADC_Channel_8: ADC Channel8 selected + * @arg ADC_Channel_9: ADC Channel9 selected + * @arg ADC_Channel_10: ADC Channel10 selected + * @arg ADC_Channel_11: ADC Channel11 selected + * @arg ADC_Channel_12: ADC Channel12 selected + * @arg ADC_Channel_13: ADC Channel13 selected + * @arg ADC_Channel_14: ADC Channel14 selected + * @arg ADC_Channel_15: ADC Channel15 selected + * @arg ADC_Channel_16: ADC Channel16 selected + * @arg ADC_Channel_17: ADC Channel17 selected + * @arg ADC_Channel_18: ADC Channel18 selected + * @retval None + */ +void ADC_AnalogWatchdog3SingleChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel) +{ + uint32_t tmpreg = 0; + /* Check the parameters */ + assert_param(IS_ADC_ALL_PERIPH(ADCx)); + assert_param(IS_ADC_CHANNEL(ADC_Channel)); + /* Get the old register value */ + tmpreg = ADCx->AWD3CR; + /* Clear the Analog watchdog channel select bits */ + tmpreg &= ~(uint32_t)ADC_AWD3CR_AWD3CH; + /* Set the Analog watchdog channel */ + tmpreg |= (uint32_t)1 << (ADC_Channel); + /* Store the new register value */ + ADCx->AWD3CR |= tmpreg; +} + +/** + * @} + */ + +/** @defgroup ADC_Group3 Temperature Sensor - Vrefint (Internal Reference Voltage) and VBAT management functions + * @brief Vbat, Temperature Sensor & Vrefint (Internal Reference Voltage) management function + * +@verbatim + ==================================================================================================== + ##### Temperature Sensor - Vrefint (Internal Reference Voltage) and VBAT management functions ##### + ==================================================================================================== + + [..] This section provides a function allowing to enable/ disable the internal + connections between the ADC and the Vbat/2, Temperature Sensor and the Vrefint source. + + [..] A typical configuration to get the Temperature sensor and Vrefint channels + voltages is done following these steps : + (#) Enable the internal connection of Vbat/2, Temperature sensor and Vrefint sources + with the ADC channels using: + (++) ADC_TempSensorCmd() + (++) ADC_VrefintCmd() + (++) ADC_VbatCmd() + + (#) select the ADC_Channel_TempSensor and/or ADC_Channel_Vrefint and/or ADC_Channel_Vbat using + (++) ADC_RegularChannelConfig() or + (++) ADC_InjectedInit() functions + + (#) Get the voltage values, using: + (++) ADC_GetConversionValue() or + (++) ADC_GetInjectedConversionValue(). + +@endverbatim + * @{ + */ + +/** + * @brief Enables or disables the temperature sensor channel. + * @param ADCx: where x can be 1 to select the ADC peripheral. + * @param NewState: new state of the temperature sensor. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void ADC_TempSensorCmd(ADC_TypeDef* ADCx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable the temperature sensor channel*/ + ADC1_2->CCR |= ADC12_CCR_TSEN; + } + else + { + /* Disable the temperature sensor channel*/ + ADC1_2->CCR &= ~(uint32_t)ADC12_CCR_TSEN; + } +} + +/** + * @brief Enables or disables the Vrefint channel. + * @param ADCx: where x can be 1 or 4 to select the ADC peripheral. + * @param NewState: new state of the Vrefint. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void ADC_VrefintCmd(ADC_TypeDef* ADCx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_ADC_ALL_PERIPH(ADCx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if((ADCx == ADC1) || (ADCx == ADC2)) + { + if (NewState != DISABLE) + { + /* Enable the Vrefint channel*/ + ADC1_2->CCR |= ADC12_CCR_VREFEN; + } + else + { + /* Disable the Vrefint channel*/ + ADC1_2->CCR &= ~(uint32_t)ADC12_CCR_VREFEN; + } + } + else + { + if (NewState != DISABLE) + { + /* Enable the Vrefint channel*/ + ADC3_4->CCR |= ADC34_CCR_VREFEN; + } + else + { + /* Disable the Vrefint channel*/ + ADC3_4->CCR &= ~(uint32_t)ADC34_CCR_VREFEN; + } + } +} + +/** + * @brief Enables or disables the Vbat channel. + * @param ADCx: where x can be 1 to select the ADC peripheral. + * @param NewState: new state of the Vbat. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void ADC_VbatCmd(ADC_TypeDef* ADCx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable the Vbat channel*/ + ADC1_2->CCR |= ADC12_CCR_VBATEN; + } + else + { + /* Disable the Vbat channel*/ + ADC1_2->CCR &= ~(uint32_t)ADC12_CCR_VBATEN; + } +} + +/** + * @} + */ + +/** @defgroup ADC_Group4 Regular Channels Configuration functions + * @brief Regular Channels Configuration functions + * +@verbatim + =============================================================================== + ##### Channels Configuration functions ##### + =============================================================================== + + [..] This section provides functions allowing to manage the ADC regular channels. + + [..] To configure a regular sequence of channels use: + (#) ADC_RegularChannelConfig() + this function allows: + (++) Configure the rank in the regular group sequencer for each channel + (++) Configure the sampling time for each channel + + (#) ADC_RegularChannelSequencerLengthConfig() to set the length of the regular sequencer + + [..] The regular trigger is configured using the following functions: + (#) ADC_SelectExternalTrigger() + (#) ADC_ExternalTriggerPolarityConfig() + + [..] The start and the stop conversion are controlled by: + (#) ADC_StartConversion() + (#) ADC_StopConversion() + + [..] + (@)Please Note that the following features for regular channels are configured + using the ADC_Init() function : + (++) continuous mode activation + (++) Resolution + (++) Data Alignement + (++) Overrun Mode. + + [..] Get the conversion data: This subsection provides an important function in + the ADC peripheral since it returns the converted data of the current + regular channel. When the Conversion value is read, the EOC Flag is + automatically cleared. + + [..] To configure the discontinuous mode, the following functions should be used: + (#) ADC_DiscModeChannelCountConfig() to configure the number of discontinuous channel to be converted. + (#) ADC_DiscModeCmd() to enable the discontinuous mode. + + [..] To configure and enable/disable the Channel offset use the functions: + (++) ADC_SetChannelOffset1() + (++) ADC_SetChannelOffset2() + (++) ADC_SetChannelOffset3() + (++) ADC_SetChannelOffset4() + (++) ADC_ChannelOffset1Cmd() + (++) ADC_ChannelOffset2Cmd() + (++) ADC_ChannelOffset3Cmd() + (++) ADC_ChannelOffset4Cmd() + +@endverbatim + * @{ + */ + +/** + * @brief Configures for the selected ADC regular channel its corresponding + * rank in the sequencer and its sample time. + * @param ADCx: where x can be 1, 2, 3 or 4 to select the ADC peripheral. + * @param ADC_Channel: the ADC channel to configure. + * This parameter can be one of the following values: + * @arg ADC_Channel_1: ADC Channel1 selected + * @arg ADC_Channel_2: ADC Channel2 selected + * @arg ADC_Channel_3: ADC Channel3 selected + * @arg ADC_Channel_4: ADC Channel4 selected + * @arg ADC_Channel_5: ADC Channel5 selected + * @arg ADC_Channel_6: ADC Channel6 selected + * @arg ADC_Channel_7: ADC Channel7 selected + * @arg ADC_Channel_8: ADC Channel8 selected + * @arg ADC_Channel_9: ADC Channel9 selected + * @arg ADC_Channel_10: ADC Channel10 selected + * @arg ADC_Channel_11: ADC Channel11 selected + * @arg ADC_Channel_12: ADC Channel12 selected + * @arg ADC_Channel_13: ADC Channel13 selected + * @arg ADC_Channel_14: ADC Channel14 selected + * @arg ADC_Channel_15: ADC Channel15 selected + * @arg ADC_Channel_16: ADC Channel16 selected + * @arg ADC_Channel_17: ADC Channel17 selected + * @arg ADC_Channel_18: ADC Channel18 selected + * @param Rank: The rank in the regular group sequencer. This parameter must be between 1 to 16. + * @param ADC_SampleTime: The sample time value to be set for the selected channel. + * This parameter can be one of the following values: + * @arg ADC_SampleTime_1Cycles5: Sample time equal to 1.5 cycles + * @arg ADC_SampleTime_2Cycles5: Sample time equal to 2.5 cycles + * @arg ADC_SampleTime_4Cycles5: Sample time equal to 4.5 cycles + * @arg ADC_SampleTime_7Cycles5: Sample time equal to 7.5 cycles + * @arg ADC_SampleTime_19Cycles5: Sample time equal to 19.5 cycles + * @arg ADC_SampleTime_61Cycles5: Sample time equal to 61.5 cycles + * @arg ADC_SampleTime_181Cycles5: Sample time equal to 181.5 cycles + * @arg ADC_SampleTime_601Cycles5: Sample time equal to 601.5 cycles + * @retval None + */ +void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime) +{ + uint32_t tmpreg1 = 0, tmpreg2 = 0; + /* Check the parameters */ + assert_param(IS_ADC_ALL_PERIPH(ADCx)); + assert_param(IS_ADC_CHANNEL(ADC_Channel)); + assert_param(IS_ADC_SAMPLE_TIME(ADC_SampleTime)); + + /* Regular sequence configuration */ + /* For Rank 1 to 4 */ + if (Rank < 5) + { + /* Get the old register value */ + tmpreg1 = ADCx->SQR1; + /* Calculate the mask to clear */ + tmpreg2 = 0x1F << (6 * (Rank )); + /* Clear the old SQx bits for the selected rank */ + tmpreg1 &= ~tmpreg2; + /* Calculate the mask to set */ + tmpreg2 = (uint32_t)(ADC_Channel) << (6 * (Rank)); + /* Set the SQx bits for the selected rank */ + tmpreg1 |= tmpreg2; + /* Store the new register value */ + ADCx->SQR1 = tmpreg1; + } + /* For Rank 5 to 9 */ + else if (Rank < 10) + { + /* Get the old register value */ + tmpreg1 = ADCx->SQR2; + /* Calculate the mask to clear */ + tmpreg2 = ADC_SQR2_SQ5 << (6 * (Rank - 5)); + /* Clear the old SQx bits for the selected rank */ + tmpreg1 &= ~tmpreg2; + /* Calculate the mask to set */ + tmpreg2 = (uint32_t)(ADC_Channel) << (6 * (Rank - 5)); + /* Set the SQx bits for the selected rank */ + tmpreg1 |= tmpreg2; + /* Store the new register value */ + ADCx->SQR2 = tmpreg1; + } + /* For Rank 10 to 14 */ + else if (Rank < 15) + { + /* Get the old register value */ + tmpreg1 = ADCx->SQR3; + /* Calculate the mask to clear */ + tmpreg2 = ADC_SQR3_SQ10 << (6 * (Rank - 10)); + /* Clear the old SQx bits for the selected rank */ + tmpreg1 &= ~tmpreg2; + /* Calculate the mask to set */ + tmpreg2 = (uint32_t)(ADC_Channel) << (6 * (Rank - 10)); + /* Set the SQx bits for the selected rank */ + tmpreg1 |= tmpreg2; + /* Store the new register value */ + ADCx->SQR3 = tmpreg1; + } + else + { + /* Get the old register value */ + tmpreg1 = ADCx->SQR4; + /* Calculate the mask to clear */ + tmpreg2 = ADC_SQR3_SQ15 << (6 * (Rank - 15)); + /* Clear the old SQx bits for the selected rank */ + tmpreg1 &= ~tmpreg2; + /* Calculate the mask to set */ + tmpreg2 = (uint32_t)(ADC_Channel) << (6 * (Rank - 15)); + /* Set the SQx bits for the selected rank */ + tmpreg1 |= tmpreg2; + /* Store the new register value */ + ADCx->SQR4 = tmpreg1; + } + + /* Channel sampling configuration */ + /* if ADC_Channel_10 ... ADC_Channel_18 is selected */ + if (ADC_Channel > ADC_Channel_9) + { + /* Get the old register value */ + tmpreg1 = ADCx->SMPR2; + /* Calculate the mask to clear */ + tmpreg2 = ADC_SMPR2_SMP10 << (3 * (ADC_Channel - 10)); + /* Clear the old channel sample time */ + ADCx->SMPR2 &= ~tmpreg2; + /* Calculate the mask to set */ + ADCx->SMPR2 |= (uint32_t)ADC_SampleTime << (3 * (ADC_Channel - 10)); + + } + else /* ADC_Channel include in ADC_Channel_[0..9] */ + { + /* Get the old register value */ + tmpreg1 = ADCx->SMPR1; + /* Calculate the mask to clear */ + tmpreg2 = ADC_SMPR1_SMP1 << (3 * (ADC_Channel - 1)); + /* Clear the old channel sample time */ + ADCx->SMPR1 &= ~tmpreg2; + /* Calculate the mask to set */ + ADCx->SMPR1 |= (uint32_t)ADC_SampleTime << (3 * (ADC_Channel)); + } +} + +/** + * @brief Sets the ADC regular channel sequence lenght. + * @param ADCx: where x can be 1, 2 or 3 to select the ADC peripheral. + * @param SequenceLength: The Regular sequence length. This parameter must be between 1 to 16. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void ADC_RegularChannelSequencerLengthConfig(ADC_TypeDef* ADCx, uint8_t SequencerLength) +{ + /* Check the parameters */ + assert_param(IS_ADC_ALL_PERIPH(ADCx)); + + /* Configure the ADC sequence lenght */ + ADCx->SQR1 &= ~(uint32_t)ADC_SQR1_L; + ADCx->SQR1 |= (uint32_t)(SequencerLength - 1); +} + +/** + * @brief External Trigger Enable and Polarity Selection for regular channels. + * @param ADCx: where x can be 1, 2, 3 or 4 to select the ADC peripheral. + * @param ADC_ExternalTrigConvEvent: ADC external Trigger source. + * This parameter can be one of the following values: + * @arg ADC_ExternalTrigger_Event0: External trigger event 0 + * @arg ADC_ExternalTrigger_Event1: External trigger event 1 + * @arg ADC_ExternalTrigger_Event2: External trigger event 2 + * @arg ADC_ExternalTrigger_Event3: External trigger event 3 + * @arg ADC_ExternalTrigger_Event4: External trigger event 4 + * @arg ADC_ExternalTrigger_Event5: External trigger event 5 + * @arg ADC_ExternalTrigger_Event6: External trigger event 6 + * @arg ADC_ExternalTrigger_Event7: External trigger event 7 + * @arg ADC_ExternalTrigger_Event8: External trigger event 8 + * @arg ADC_ExternalTrigger_Event9: External trigger event 9 + * @arg ADC_ExternalTrigger_Event10: External trigger event 10 + * @arg ADC_ExternalTrigger_Event11: External trigger event 11 + * @arg ADC_ExternalTrigger_Event12: External trigger event 12 + * @arg ADC_ExternalTrigger_Event13: External trigger event 13 + * @arg ADC_ExternalTrigger_Event14: External trigger event 14 + * @arg ADC_ExternalTrigger_Event15: External trigger event 15 + * @param ADC_ExternalTrigEventEdge: ADC external Trigger Polarity. + * This parameter can be one of the following values: + * @arg ADC_ExternalTrigEventEdge_OFF: Hardware trigger detection disabled + * (conversions can be launched by software) + * @arg ADC_ExternalTrigEventEdge_RisingEdge: Hardware trigger detection on the rising edge + * @arg ADC_ExternalTrigEventEdge_FallingEdge: Hardware trigger detection on the falling edge + * @arg ADC_ExternalTrigEventEdge_BothEdge: Hardware trigger detection on both the rising and falling edges + * @retval None + */ +void ADC_ExternalTriggerConfig(ADC_TypeDef* ADCx, uint16_t ADC_ExternalTrigConvEvent, uint16_t ADC_ExternalTrigEventEdge) +{ + /* Check the parameters */ + assert_param(IS_ADC_ALL_PERIPH(ADCx)); + assert_param(IS_ADC_EXT_TRIG(ADC_ExternalTrigConvEvent)); + assert_param(IS_EXTERNALTRIG_EDGE(ADC_ExternalTrigEventEdge)); + + /* Disable the selected ADC conversion on external event */ + ADCx->CFGR &= ~(ADC_CFGR_EXTEN | ADC_CFGR_EXTSEL); + ADCx->CFGR |= (uint32_t)(ADC_ExternalTrigEventEdge | ADC_ExternalTrigConvEvent); +} + +/** + * @brief Enables or disables the selected ADC start conversion . + * @param ADCx: where x can be 1, 2, 3 or 4 to select the ADC peripheral. + * @retval None + */ +void ADC_StartConversion(ADC_TypeDef* ADCx) +{ + /* Check the parameters */ + assert_param(IS_ADC_ALL_PERIPH(ADCx)); + + /* Set the ADSTART bit */ + ADCx->CR |= ADC_CR_ADSTART; +} + +/** + * @brief Gets the selected ADC start conversion Status. + * @param ADCx: where x can be 1, 2, 3 or 4 to select the ADC peripheral. + * @retval The new state of ADC start conversion (SET or RESET). + */ +FlagStatus ADC_GetStartConversionStatus(ADC_TypeDef* ADCx) +{ + FlagStatus bitstatus = RESET; + /* Check the parameters */ + assert_param(IS_ADC_ALL_PERIPH(ADCx)); + /* Check the status of ADSTART bit */ + if ((ADCx->CR & ADC_CR_ADSTART) != (uint32_t)RESET) + { + /* ADSTART bit is set */ + bitstatus = SET; + } + else + { + /* ADSTART bit is reset */ + bitstatus = RESET; + } + /* Return the ADSTART bit status */ + return bitstatus; +} + +/** + * @brief Stops the selected ADC ongoing conversion. + * @param ADCx: where x can be 1, 2, 3 or 4 to select the ADC peripheral. + * @retval None + */ +void ADC_StopConversion(ADC_TypeDef* ADCx) +{ + /* Check the parameters */ + assert_param(IS_ADC_ALL_PERIPH(ADCx)); + + /* Set the ADSTP bit */ + ADCx->CR |= ADC_CR_ADSTP; +} + + +/** + * @brief Configures the discontinuous mode for the selected ADC regular + * group channel. + * @param ADCx: where x can be 1, 2, 3 or 4 to select the ADC peripheral. + * @param Number: specifies the discontinuous mode regular channel + * count value. This number must be between 1 and 8. + * @retval None + */ +void ADC_DiscModeChannelCountConfig(ADC_TypeDef* ADCx, uint8_t Number) +{ + uint32_t tmpreg1 = 0; + uint32_t tmpreg2 = 0; + /* Check the parameters */ + assert_param(IS_ADC_ALL_PERIPH(ADCx)); + assert_param(IS_ADC_REGULAR_DISC_NUMBER(Number)); + /* Get the old register value */ + tmpreg1 = ADCx->CFGR; + /* Clear the old discontinuous mode channel count */ + tmpreg1 &= ~(uint32_t)(ADC_CFGR_DISCNUM); + /* Set the discontinuous mode channel count */ + tmpreg2 = Number - 1; + tmpreg1 |= tmpreg2 << 17; + /* Store the new register value */ + ADCx->CFGR = tmpreg1; +} + +/** + * @brief Enables or disables the discontinuous mode on regular group + * channel for the specified ADC + * @param ADCx: where x can be 1, 2, 3 or 4 to select the ADC peripheral. + * @param NewState: new state of the selected ADC discontinuous mode + * on regular group channel. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void ADC_DiscModeCmd(ADC_TypeDef* ADCx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_ADC_ALL_PERIPH(ADCx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + if (NewState != DISABLE) + { + /* Enable the selected ADC regular discontinuous mode */ + ADCx->CFGR |= ADC_CFGR_DISCEN; + } + else + { + /* Disable the selected ADC regular discontinuous mode */ + ADCx->CFGR &= ~(uint32_t)(ADC_CFGR_DISCEN); + } +} + +/** + * @brief Returns the last ADCx conversion result data for regular channel. + * @param ADCx: where x can be 1, 2, 3 or 4 to select the ADC peripheral. + * @retval The Data conversion value. + */ +uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx) +{ + /* Check the parameters */ + assert_param(IS_ADC_ALL_PERIPH(ADCx)); + /* Return the selected ADC conversion value */ + return (uint16_t) ADCx->DR; +} + +/** + * @brief Returns the last ADC1, ADC2, ADC3 and ADC4 regular conversions results + * data in the selected dual mode. + * @param ADCx: where x can be 1, 2, 3 or 4 to select the ADC peripheral. + * @retval The Data conversion value. + * @note In dual mode, the value returned by this function is as following + * Data[15:0] : these bits contain the regular data of the Master ADC. + * Data[31:16]: these bits contain the regular data of the Slave ADC. + */ +uint32_t ADC_GetDualModeConversionValue(ADC_TypeDef* ADCx) +{ + uint32_t tmpreg1 = 0; + + /* Check the parameters */ + assert_param(IS_ADC_ALL_PERIPH(ADCx)); + + if((ADCx == ADC1) || (ADCx== ADC2)) + { + /* Get the dual mode conversion value */ + tmpreg1 = ADC1_2->CDR; + } + else + { + /* Get the dual mode conversion value */ + tmpreg1 = ADC3_4->CDR; + } + /* Return the dual mode conversion value */ + return (uint32_t) tmpreg1; +} + +/** + * @brief Set the ADC channels conversion value offset1 + * @param ADCx: where x can be 1, 2, 3 or 4 to select the ADC peripheral. + * @param ADC_Channel: the ADC channel to configure. + * This parameter can be one of the following values: + * @arg ADC_Channel_1: ADC Channel1 selected + * @arg ADC_Channel_2: ADC Channel2 selected + * @arg ADC_Channel_3: ADC Channel3 selected + * @arg ADC_Channel_4: ADC Channel4 selected + * @arg ADC_Channel_5: ADC Channel5 selected + * @arg ADC_Channel_6: ADC Channel6 selected + * @arg ADC_Channel_7: ADC Channel7 selected + * @arg ADC_Channel_8: ADC Channel8 selected + * @arg ADC_Channel_9: ADC Channel9 selected + * @arg ADC_Channel_10: ADC Channel10 selected + * @arg ADC_Channel_11: ADC Channel11 selected + * @arg ADC_Channel_12: ADC Channel12 selected + * @arg ADC_Channel_13: ADC Channel13 selected + * @arg ADC_Channel_14: ADC Channel14 selected + * @arg ADC_Channel_15: ADC Channel15 selected + * @arg ADC_Channel_16: ADC Channel16 selected + * @arg ADC_Channel_17: ADC Channel17 selected + * @arg ADC_Channel_18: ADC Channel18 selected + * @param Offset: the offset value for the selected ADC Channel + * This parameter must be a 12bit value. + * @retval None + */ +void ADC_SetChannelOffset1(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint16_t Offset) +{ + /* Check the parameters */ + assert_param(IS_ADC_ALL_PERIPH(ADCx)); + assert_param(IS_ADC_CHANNEL(ADC_Channel)); + assert_param(IS_ADC_OFFSET(Offset)); + + /* Select the Channel */ + ADCx->OFR1 &= ~ (uint32_t) ADC_OFR1_OFFSET1_CH; + ADCx->OFR1 |= (uint32_t)((uint32_t)ADC_Channel << 26); + + /* Set the data offset */ + ADCx->OFR1 &= ~ (uint32_t) ADC_OFR1_OFFSET1; + ADCx->OFR1 |= (uint32_t)Offset; +} + +/** + * @brief Set the ADC channels conversion value offset2 + * @param ADCx: where x can be 1, 2, 3 or 4 to select the ADC peripheral. + * @param ADC_Channel: the ADC channel to configure. + * This parameter can be one of the following values: + * @arg ADC_Channel_1: ADC Channel1 selected + * @arg ADC_Channel_2: ADC Channel2 selected + * @arg ADC_Channel_3: ADC Channel3 selected + * @arg ADC_Channel_4: ADC Channel4 selected + * @arg ADC_Channel_5: ADC Channel5 selected + * @arg ADC_Channel_6: ADC Channel6 selected + * @arg ADC_Channel_7: ADC Channel7 selected + * @arg ADC_Channel_8: ADC Channel8 selected + * @arg ADC_Channel_9: ADC Channel9 selected + * @arg ADC_Channel_10: ADC Channel10 selected + * @arg ADC_Channel_11: ADC Channel11 selected + * @arg ADC_Channel_12: ADC Channel12 selected + * @arg ADC_Channel_13: ADC Channel13 selected + * @arg ADC_Channel_14: ADC Channel14 selected + * @arg ADC_Channel_15: ADC Channel15 selected + * @arg ADC_Channel_16: ADC Channel16 selected + * @arg ADC_Channel_17: ADC Channel17 selected + * @arg ADC_Channel_18: ADC Channel18 selected + * @param Offset: the offset value for the selected ADC Channel + * This parameter must be a 12bit value. + * @retval None + */ +void ADC_SetChannelOffset2(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint16_t Offset) +{ + /* Check the parameters */ + assert_param(IS_ADC_ALL_PERIPH(ADCx)); + assert_param(IS_ADC_CHANNEL(ADC_Channel)); + assert_param(IS_ADC_OFFSET(Offset)); + + /* Select the Channel */ + ADCx->OFR2 &= ~ (uint32_t) ADC_OFR2_OFFSET2_CH; + ADCx->OFR2 |= (uint32_t)((uint32_t)ADC_Channel << 26); + + /* Set the data offset */ + ADCx->OFR2 &= ~ (uint32_t) ADC_OFR2_OFFSET2; + ADCx->OFR2 |= (uint32_t)Offset; +} + +/** + * @brief Set the ADC channels conversion value offset3 + * @param ADCx: where x can be 1, 2, 3 or 4 to select the ADC peripheral. + * @param ADC_Channel: the ADC channel to configure. + * This parameter can be one of the following values: + * @arg ADC_Channel_1: ADC Channel1 selected + * @arg ADC_Channel_2: ADC Channel2 selected + * @arg ADC_Channel_3: ADC Channel3 selected + * @arg ADC_Channel_4: ADC Channel4 selected + * @arg ADC_Channel_5: ADC Channel5 selected + * @arg ADC_Channel_6: ADC Channel6 selected + * @arg ADC_Channel_7: ADC Channel7 selected + * @arg ADC_Channel_8: ADC Channel8 selected + * @arg ADC_Channel_9: ADC Channel9 selected + * @arg ADC_Channel_10: ADC Channel10 selected + * @arg ADC_Channel_11: ADC Channel11 selected + * @arg ADC_Channel_12: ADC Channel12 selected + * @arg ADC_Channel_13: ADC Channel13 selected + * @arg ADC_Channel_14: ADC Channel14 selected + * @arg ADC_Channel_15: ADC Channel15 selected + * @arg ADC_Channel_16: ADC Channel16 selected + * @arg ADC_Channel_17: ADC Channel17 selected + * @arg ADC_Channel_18: ADC Channel18 selected + * @param Offset: the offset value for the selected ADC Channel + * This parameter must be a 12bit value. + * @retval None + */ +void ADC_SetChannelOffset3(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint16_t Offset) +{ + /* Check the parameters */ + assert_param(IS_ADC_ALL_PERIPH(ADCx)); + assert_param(IS_ADC_CHANNEL(ADC_Channel)); + assert_param(IS_ADC_OFFSET(Offset)); + + /* Select the Channel */ + ADCx->OFR3 &= ~ (uint32_t) ADC_OFR3_OFFSET3_CH; + ADCx->OFR3 |= (uint32_t)((uint32_t)ADC_Channel << 26); + + /* Set the data offset */ + ADCx->OFR3 &= ~ (uint32_t) ADC_OFR3_OFFSET3; + ADCx->OFR3 |= (uint32_t)Offset; +} + +/** + * @brief Set the ADC channels conversion value offset4 + * @param ADCx: where x can be 1, 2, 3 or 4 to select the ADC peripheral. + * @param ADC_Channel: the ADC channel to configure. + * This parameter can be one of the following values: + * @arg ADC_Channel_1: ADC Channel1 selected + * @arg ADC_Channel_2: ADC Channel2 selected + * @arg ADC_Channel_3: ADC Channel3 selected + * @arg ADC_Channel_4: ADC Channel4 selected + * @arg ADC_Channel_5: ADC Channel5 selected + * @arg ADC_Channel_6: ADC Channel6 selected + * @arg ADC_Channel_7: ADC Channel7 selected + * @arg ADC_Channel_8: ADC Channel8 selected + * @arg ADC_Channel_9: ADC Channel9 selected + * @arg ADC_Channel_10: ADC Channel10 selected + * @arg ADC_Channel_11: ADC Channel11 selected + * @arg ADC_Channel_12: ADC Channel12 selected + * @arg ADC_Channel_13: ADC Channel13 selected + * @arg ADC_Channel_14: ADC Channel14 selected + * @arg ADC_Channel_15: ADC Channel15 selected + * @arg ADC_Channel_16: ADC Channel16 selected + * @arg ADC_Channel_17: ADC Channel17 selected + * @arg ADC_Channel_18: ADC Channel18 selected + * @param Offset: the offset value for the selected ADC Channel + * This parameter must be a 12bit value. + * @retval None + */ +void ADC_SetChannelOffset4(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint16_t Offset) +{ + /* Check the parameters */ + assert_param(IS_ADC_ALL_PERIPH(ADCx)); + assert_param(IS_ADC_CHANNEL(ADC_Channel)); + assert_param(IS_ADC_OFFSET(Offset)); + + /* Select the Channel */ + ADCx->OFR4 &= ~ (uint32_t) ADC_OFR4_OFFSET4_CH; + ADCx->OFR4 |= (uint32_t)((uint32_t)ADC_Channel << 26); + + /* Set the data offset */ + ADCx->OFR4 &= ~ (uint32_t) ADC_OFR4_OFFSET4; + ADCx->OFR4 |= (uint32_t)Offset; +} + +/** + * @brief Enables or disables the Offset1. + * @param ADCx: where x can be 1, 2, 3 or 4 to select the ADC peripheral. + * @param NewState: new state of the ADCx offset1. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void ADC_ChannelOffset1Cmd(ADC_TypeDef* ADCx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_ADC_ALL_PERIPH(ADCx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Set the OFFSET1_EN bit */ + ADCx->OFR1 |= ADC_OFR1_OFFSET1_EN; + } + else + { + /* Reset the OFFSET1_EN bit */ + ADCx->OFR1 &= ~(ADC_OFR1_OFFSET1_EN); + } +} + +/** + * @brief Enables or disables the Offset2. + * @param ADCx: where x can be 1, 2, 3 or 4 to select the ADC peripheral. + * @param NewState: new state of the ADCx offset2. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void ADC_ChannelOffset2Cmd(ADC_TypeDef* ADCx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_ADC_ALL_PERIPH(ADCx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Set the OFFSET1_EN bit */ + ADCx->OFR2 |= ADC_OFR2_OFFSET2_EN; + } + else + { + /* Reset the OFFSET1_EN bit */ + ADCx->OFR2 &= ~(ADC_OFR2_OFFSET2_EN); + } +} + +/** + * @brief Enables or disables the Offset3. + * @param ADCx: where x can be 1, 2, 3 or 4 to select the ADC peripheral. + * @param NewState: new state of the ADCx offset3. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void ADC_ChannelOffset3Cmd(ADC_TypeDef* ADCx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_ADC_ALL_PERIPH(ADCx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Set the OFFSET1_EN bit */ + ADCx->OFR3 |= ADC_OFR3_OFFSET3_EN; + } + else + { + /* Reset the OFFSET1_EN bit */ + ADCx->OFR3 &= ~(ADC_OFR3_OFFSET3_EN); + } +} + +/** + * @brief Enables or disables the Offset4. + * @param ADCx: where x can be 1, 2, 3 or 4 to select the ADC peripheral. + * @param NewState: new state of the ADCx offset4. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void ADC_ChannelOffset4Cmd(ADC_TypeDef* ADCx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_ADC_ALL_PERIPH(ADCx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Set the OFFSET1_EN bit */ + ADCx->OFR4 |= ADC_OFR4_OFFSET4_EN; + } + else + { + /* Reset the OFFSET1_EN bit */ + ADCx->OFR4 &= ~(ADC_OFR4_OFFSET4_EN); + } +} + +/** + * @} + */ + +/** @defgroup ADC_Group5 Regular Channels DMA Configuration functions + * @brief Regular Channels DMA Configuration functions + * +@verbatim + =============================================================================== + ##### Regular Channels DMA Configuration functions ##### + =============================================================================== + + [..] This section provides functions allowing to configure the DMA for ADC regular + channels. Since converted regular channel values are stored into a unique data register, + it is useful to use DMA for conversion of more than one regular channel. This + avoids the loss of the data already stored in the ADC Data register. + + (#) ADC_DMACmd() function is used to enable the ADC DMA mode, after each + conversion of a regular channel, a DMA request is generated. + (#) ADC_DMAConfig() function is used to select between the one shot DMA mode + or the circular DMA mode + +@endverbatim + * @{ + */ + +/** + * @brief Enables or disables the specified ADC DMA request. + * @param ADCx: where x can be 1, 2, 3 or 4 to select the ADC peripheral. + * @param NewState: new state of the selected ADC DMA transfer. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void ADC_DMACmd(ADC_TypeDef* ADCx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_ADC_DMA_PERIPH(ADCx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + if (NewState != DISABLE) + { + /* Enable the selected ADC DMA request */ + ADCx->CFGR |= ADC_CFGR_DMAEN; + } + else + { + /* Disable the selected ADC DMA request */ + ADCx->CFGR &= ~(uint32_t)ADC_CFGR_DMAEN; + } +} + +/** + * @brief Configure ADC DMA mode. + * @param ADCx: where x can be 1, 2, 3 or 4 to select the ADC peripheral. + * @param ADC_DMAMode: select the ADC DMA mode. + * This parameter can be one of the following values: + * @arg ADC_DMAMode_OneShot: ADC DMA Oneshot mode + * @arg ADC_DMAMode_Circular: ADC DMA circular mode + * @retval None + */ +void ADC_DMAConfig(ADC_TypeDef* ADCx, uint32_t ADC_DMAMode) +{ + /* Check the parameters */ + assert_param(IS_ADC_DMA_PERIPH(ADCx)); + assert_param(IS_ADC_DMA_MODE(ADC_DMAMode)); + + /* Set or reset the DMACFG bit */ + ADCx->CFGR &= ~(uint32_t)ADC_CFGR_DMACFG; + ADCx->CFGR |= ADC_DMAMode; +} + +/** + * @} + */ + +/** @defgroup ADC_Group6 Injected channels Configuration functions + * @brief Injected channels Configuration functions + * +@verbatim + =============================================================================== + ##### Injected channels Configuration functions ##### + =============================================================================== + + [..] This section provide functions allowing to manage the ADC Injected channels, + it is composed of : + + (#) Configuration functions for Injected channels sample time + (#) Functions to start and stop the injected conversion + (#) unction to select the discontinuous mode + (#) Function to get the Specified Injected channel conversion data: This subsection + provides an important function in the ADC peripheral since it returns the + converted data of the specific injected channel. + +@endverbatim + * @{ + */ + +/** + * @brief Configures for the selected ADC injected channel its corresponding + * sample time. + * @param ADCx: where x can be 1, 2, 3 or 4 to select the ADC peripheral. + * @param ADC_Channel: the ADC channel to configure. + * This parameter can be one of the following values: + * @arg ADC_InjectedChannel_1: ADC Channel1 selected + * @arg ADC_InjectedChannel_2: ADC Channel2 selected + * @arg ADC_InjectedChannel_3: ADC Channel3 selected + * @arg ADC_InjectedChannel_4: ADC Channel4 selected + * @arg ADC_InjectedChannel_5: ADC Channel5 selected + * @arg ADC_InjectedChannel_6: ADC Channel6 selected + * @arg ADC_InjectedChannel_7: ADC Channel7 selected + * @arg ADC_InjectedChannel_8: ADC Channel8 selected + * @arg ADC_InjectedChannel_9: ADC Channel9 selected + * @arg ADC_InjectedChannel_10: ADC Channel10 selected + * @arg ADC_InjectedChannel_11: ADC Channel11 selected + * @arg ADC_InjectedChannel_12: ADC Channel12 selected + * @arg ADC_InjectedChannel_13: ADC Channel13 selected + * @arg ADC_InjectedChannel_14: ADC Channel14 selected + * @arg ADC_InjectedChannel_15: ADC Channel15 selected + * @arg ADC_InjectedChannel_16: ADC Channel16 selected + * @arg ADC_InjectedChannel_17: ADC Channel17 selected + * @arg ADC_InjectedChannel_18: ADC Channel18 selected + * @param ADC_SampleTime: The sample time value to be set for the selected channel. + * This parameter can be one of the following values: + * @arg ADC_SampleTime_1Cycles5: Sample time equal to 1.5 cycles + * @arg ADC_SampleTime_2Cycles5: Sample time equal to 2.5 cycles + * @arg ADC_SampleTime_4Cycles5: Sample time equal to 4.5 cycles + * @arg ADC_SampleTime_7Cycles5: Sample time equal to 7.5 cycles + * @arg ADC_SampleTime_19Cycles5: Sample time equal to 19.5 cycles + * @arg ADC_SampleTime_61Cycles5: Sample time equal to 61.5 cycles + * @arg ADC_SampleTime_181Cycles5: Sample time equal to 181.5 cycles + * @arg ADC_SampleTime_601Cycles5: Sample time equal to 601.5 cycles + * @retval None + */ +void ADC_InjectedChannelSampleTimeConfig(ADC_TypeDef* ADCx, uint8_t ADC_InjectedChannel, uint8_t ADC_SampleTime) +{ + uint32_t tmpreg1 = 0; + /* Check the parameters */ + assert_param(IS_ADC_ALL_PERIPH(ADCx)); + assert_param(IS_ADC_INJECTED_CHANNEL(ADC_InjectedChannel)); + assert_param(IS_ADC_SAMPLE_TIME(ADC_SampleTime)); + + /* Channel sampling configuration */ + /* if ADC_InjectedChannel_10 ... ADC_InjectedChannel_18 is selected */ + if (ADC_InjectedChannel > ADC_InjectedChannel_9) + { + /* Calculate the mask to clear */ + tmpreg1 = ADC_SMPR2_SMP10 << (3 * (ADC_InjectedChannel - 10)); + /* Clear the old channel sample time */ + ADCx->SMPR2 &= ~tmpreg1; + /* Calculate the mask to set */ + ADCx->SMPR2 |= (uint32_t)ADC_SampleTime << (3 * (ADC_InjectedChannel - 10)); + + } + else /* ADC_InjectedChannel include in ADC_InjectedChannel_[0..9] */ + { + /* Calculate the mask to clear */ + tmpreg1 = ADC_SMPR1_SMP1 << (3 * (ADC_InjectedChannel - 1)); + /* Clear the old channel sample time */ + ADCx->SMPR1 &= ~tmpreg1; + /* Calculate the mask to set */ + ADCx->SMPR1 |= (uint32_t)ADC_SampleTime << (3 * (ADC_InjectedChannel)); + } +} + +/** + * @brief Enables or disables the selected ADC start of the injected + * channels conversion. + * @param ADCx: where x can be 1, 2, 3 or 4 to select the ADC peripheral. + * @param NewState: new state of the selected ADC software start injected conversion. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void ADC_StartInjectedConversion(ADC_TypeDef* ADCx) +{ + /* Check the parameters */ + assert_param(IS_ADC_ALL_PERIPH(ADCx)); + + /* Enable the selected ADC conversion for injected group on external event and start the selected + ADC injected conversion */ + ADCx->CR |= ADC_CR_JADSTART; +} + +/** + * @brief Stops the selected ADC ongoing injected conversion. + * @param ADCx: where x can be 1, 2, 3 or 4 to select the ADC peripheral. + * @retval None + */ +void ADC_StopInjectedConversion(ADC_TypeDef* ADCx) +{ + /* Check the parameters */ + assert_param(IS_ADC_ALL_PERIPH(ADCx)); + + /* Set the JADSTP bit */ + ADCx->CR |= ADC_CR_JADSTP; +} + +/** + * @brief Gets the selected ADC Software start injected conversion Status. + * @param ADCx: where x can be 1, 2, 3 or 4 to select the ADC peripheral. + * @retval The new state of ADC start injected conversion (SET or RESET). + */ +FlagStatus ADC_GetStartInjectedConversionStatus(ADC_TypeDef* ADCx) +{ + FlagStatus bitstatus = RESET; + /* Check the parameters */ + assert_param(IS_ADC_ALL_PERIPH(ADCx)); + + /* Check the status of JADSTART bit */ + if ((ADCx->CR & ADC_CR_JADSTART) != (uint32_t)RESET) + { + /* JADSTART bit is set */ + bitstatus = SET; + } + else + { + /* JADSTART bit is reset */ + bitstatus = RESET; + } + /* Return the JADSTART bit status */ + return bitstatus; +} + +/** + * @brief Enables or disables the selected ADC automatic injected group + * conversion after regular one. + * @param ADCx: where x can be 1, 2, 3 or 4 to select the ADC peripheral. + * @param NewState: new state of the selected ADC auto injected conversion + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void ADC_AutoInjectedConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_ADC_ALL_PERIPH(ADCx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + if (NewState != DISABLE) + { + /* Enable the selected ADC automatic injected group conversion */ + ADCx->CFGR |= ADC_CFGR_JAUTO; + } + else + { + /* Disable the selected ADC automatic injected group conversion */ + ADCx->CFGR &= ~ADC_CFGR_JAUTO; + } +} + +/** + * @brief Enables or disables the discontinuous mode for injected group + * channel for the specified ADC + * @param ADCx: where x can be 1, 2, 3 or 4 to select the ADC peripheral. + * @param NewState: new state of the selected ADC discontinuous mode + * on injected group channel. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void ADC_InjectedDiscModeCmd(ADC_TypeDef* ADCx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_ADC_ALL_PERIPH(ADCx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + if (NewState != DISABLE) + { + /* Enable the selected ADC injected discontinuous mode */ + ADCx->CFGR |= ADC_CFGR_JDISCEN; + } + else + { + /* Disable the selected ADC injected discontinuous mode */ + ADCx->CFGR &= ~ADC_CFGR_JDISCEN; + } +} + +/** + * @brief Returns the ADC injected channel conversion result + * @param ADCx: where x can be 1, 2, 3 or 4 to select the ADC peripheral. + * @param ADC_InjectedSequence: the converted ADC injected sequence. + * This parameter can be one of the following values: + * @arg ADC_InjectedSequence_1: Injected Sequence1 selected + * @arg ADC_InjectedSequence_2: Injected Sequence2 selected + * @arg ADC_InjectedSequence_3: Injected Sequence3 selected + * @arg ADC_InjectedSequence_4: Injected Sequence4 selected + * @retval The Data conversion value. + */ +uint16_t ADC_GetInjectedConversionValue(ADC_TypeDef* ADCx, uint8_t ADC_InjectedSequence) +{ + __IO uint32_t tmp = 0; + + /* Check the parameters */ + assert_param(IS_ADC_ALL_PERIPH(ADCx)); + assert_param(IS_ADC_INJECTED_SEQUENCE(ADC_InjectedSequence)); + + tmp = (uint32_t)ADCx; + tmp += ((ADC_InjectedSequence - 1 )<< 2) + JDR_Offset; + + /* Returns the selected injected channel conversion data value */ + return (uint16_t) (*(__IO uint32_t*) tmp); +} + +/** + * @} + */ + +/** @defgroup ADC_Group7 Interrupts and flags management functions + * @brief Interrupts and flags management functions + * +@verbatim + =============================================================================== + ##### Interrupts and flags management functions ##### + =============================================================================== + + [..] This section provides functions allowing to configure the ADC Interrupts, get + the status and clear flags and Interrupts pending bits. + + [..] The ADC provide 11 Interrupts sources and 11 Flags which can be divided into 3 groups: + + (#) Flags and Interrupts for ADC regular channels + (##)Flags + (+) ADC_FLAG_RDY: ADC Ready flag + (+) ADC_FLAG_EOSMP: ADC End of Sampling flag + (+) ADC_FLAG_EOC: ADC End of Regular Conversion flag. + (+) ADC_FLAG_EOS: ADC End of Regular sequence of Conversions flag + (+) ADC_FLAG_OVR: ADC overrun flag + + (##) Interrupts + (+) ADC_IT_RDY: ADC Ready interrupt source + (+) ADC_IT_EOSMP: ADC End of Sampling interrupt source + (+) ADC_IT_EOC: ADC End of Regular Conversion interrupt source + (+) ADC_IT_EOS: ADC End of Regular sequence of Conversions interrupt + (+) ADC_IT_OVR: ADC overrun interrupt source + + + (#) Flags and Interrupts for ADC regular channels + (##)Flags + (+) ADC_FLAG_JEOC: ADC Ready flag + (+) ADC_FLAG_JEOS: ADC End of Sampling flag + (+) ADC_FLAG_JQOVF: ADC End of Regular Conversion flag. + + (##) Interrupts + (+) ADC_IT_JEOC: ADC End of Injected Conversion interrupt source + (+) ADC_IT_JEOS: ADC End of Injected sequence of Conversions interrupt source + (+) ADC_IT_JQOVF: ADC Injected Context Queue Overflow interrupt source + + (#) General Flags and Interrupts for the ADC + (##)Flags + (+) ADC_FLAG_AWD1: ADC Analog watchdog 1 flag + (+) ADC_FLAG_AWD2: ADC Analog watchdog 2 flag + (+) ADC_FLAG_AWD3: ADC Analog watchdog 3 flag + + (##)Flags + (+) ADC_IT_AWD1: ADC Analog watchdog 1 interrupt source + (+) ADC_IT_AWD2: ADC Analog watchdog 2 interrupt source + (+) ADC_IT_AWD3: ADC Analog watchdog 3 interrupt source + + (#) Flags for ADC dual mode + (##)Flags for Master + (+) ADC_FLAG_MSTRDY: ADC master Ready (ADRDY) flag + (+) ADC_FLAG_MSTEOSMP: ADC master End of Sampling flag + (+) ADC_FLAG_MSTEOC: ADC master End of Regular Conversion flag + (+) ADC_FLAG_MSTEOS: ADC master End of Regular sequence of Conversions flag + (+) ADC_FLAG_MSTOVR: ADC master overrun flag + (+) ADC_FLAG_MSTJEOC: ADC master End of Injected Conversion flag + (+) ADC_FLAG_MSTJEOS: ADC master End of Injected sequence of Conversions flag + (+) ADC_FLAG_MSTAWD1: ADC master Analog watchdog 1 flag + (+) ADC_FLAG_MSTAWD2: ADC master Analog watchdog 2 flag + (+) ADC_FLAG_MSTAWD3: ADC master Analog watchdog 3 flag + (+) ADC_FLAG_MSTJQOVF: ADC master Injected Context Queue Overflow flag + + (##) Flags for Slave + (+) ADC_FLAG_SLVRDY: ADC slave Ready (ADRDY) flag + (+) ADC_FLAG_SLVEOSMP: ADC slave End of Sampling flag + (+) ADC_FLAG_SLVEOC: ADC slave End of Regular Conversion flag + (+) ADC_FLAG_SLVEOS: ADC slave End of Regular sequence of Conversions flag + (+) ADC_FLAG_SLVOVR: ADC slave overrun flag + (+) ADC_FLAG_SLVJEOC: ADC slave End of Injected Conversion flag + (+) ADC_FLAG_SLVJEOS: ADC slave End of Injected sequence of Conversions flag + (+) ADC_FLAG_SLVAWD1: ADC slave Analog watchdog 1 flag + (+) ADC_FLAG_SLVAWD2: ADC slave Analog watchdog 2 flag + (+) ADC_FLAG_SLVAWD3: ADC slave Analog watchdog 3 flag + (+) ADC_FLAG_SLVJQOVF: ADC slave Injected Context Queue Overflow flag + + The user should identify which mode will be used in his application to manage + the ADC controller events: Polling mode or Interrupt mode. + + In the Polling Mode it is advised to use the following functions: + - ADC_GetFlagStatus() : to check if flags events occur. + - ADC_ClearFlag() : to clear the flags events. + + In the Interrupt Mode it is advised to use the following functions: + - ADC_ITConfig() : to enable or disable the interrupt source. + - ADC_GetITStatus() : to check if Interrupt occurs. + - ADC_ClearITPendingBit() : to clear the Interrupt pending Bit + (corresponding Flag). +@endverbatim + * @{ + */ + +/** + * @brief Enables or disables the specified ADC interrupts. + * @param ADCx: where x can be 1, 2 or 3 to select the ADC peripheral. + * @param ADC_IT: specifies the ADC interrupt sources to be enabled or disabled. + * This parameter can be any combination of the following values: + * @arg ADC_IT_RDY: ADC Ready (ADRDY) interrupt source + * @arg ADC_IT_EOSMP: ADC End of Sampling interrupt source + * @arg ADC_IT_EOC: ADC End of Regular Conversion interrupt source + * @arg ADC_IT_EOS: ADC End of Regular sequence of Conversions interrupt source + * @arg ADC_IT_OVR: ADC overrun interrupt source + * @arg ADC_IT_JEOC: ADC End of Injected Conversion interrupt source + * @arg ADC_IT_JEOS: ADC End of Injected sequence of Conversions interrupt source + * @arg ADC_IT_AWD1: ADC Analog watchdog 1 interrupt source + * @arg ADC_IT_AWD2: ADC Analog watchdog 2 interrupt source + * @arg ADC_IT_AWD3: ADC Analog watchdog 3 interrupt source + * @arg ADC_IT_JQOVF: ADC Injected Context Queue Overflow interrupt source + * @param NewState: new state of the specified ADC interrupts. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void ADC_ITConfig(ADC_TypeDef* ADCx, uint32_t ADC_IT, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_ADC_ALL_PERIPH(ADCx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + assert_param(IS_ADC_IT(ADC_IT)); + + if (NewState != DISABLE) + { + /* Enable the selected ADC interrupts */ + ADCx->IER |= ADC_IT; + } + else + { + /* Disable the selected ADC interrupts */ + ADCx->IER &= (~(uint32_t)ADC_IT); + } +} + +/** + * @brief Checks whether the specified ADC flag is set or not. + * @param ADCx: where x can be 1, 2, 3 or 4 to select the ADC peripheral. + * @param ADC_FLAG: specifies the flag to check. + * This parameter can be one of the following values: + * @arg ADC_FLAG_RDY: ADC Ready (ADRDY) flag + * @arg ADC_FLAG_EOSMP: ADC End of Sampling flag + * @arg ADC_FLAG_EOC: ADC End of Regular Conversion flag + * @arg ADC_FLAG_EOS: ADC End of Regular sequence of Conversions flag + * @arg ADC_FLAG_OVR: ADC overrun flag + * @arg ADC_FLAG_JEOC: ADC End of Injected Conversion flag + * @arg ADC_FLAG_JEOS: ADC End of Injected sequence of Conversions flag + * @arg ADC_FLAG_AWD1: ADC Analog watchdog 1 flag + * @arg ADC_FLAG_AWD2: ADC Analog watchdog 2 flag + * @arg ADC_FLAG_AWD3: ADC Analog watchdog 3 flag + * @arg ADC_FLAG_JQOVF: ADC Injected Context Queue Overflow flag + * @retval The new state of ADC_FLAG (SET or RESET). + */ +FlagStatus ADC_GetFlagStatus(ADC_TypeDef* ADCx, uint32_t ADC_FLAG) +{ + FlagStatus bitstatus = RESET; + /* Check the parameters */ + assert_param(IS_ADC_ALL_PERIPH(ADCx)); + assert_param(IS_ADC_GET_FLAG(ADC_FLAG)); + + /* Check the status of the specified ADC flag */ + if ((ADCx->ISR & ADC_FLAG) != (uint32_t)RESET) + { + /* ADC_FLAG is set */ + bitstatus = SET; + } + else + { + /* ADC_FLAG is reset */ + bitstatus = RESET; + } + /* Return the ADC_FLAG status */ + return bitstatus; +} + +/** + * @brief Clears the ADCx's pending flags. + * @param ADCx: where x can be 1, 2, 3 or 4 to select the ADC peripheral. + * @param ADC_FLAG: specifies the flag to clear. + * This parameter can be any combination of the following values: + * @arg ADC_FLAG_RDY: ADC Ready (ADRDY) flag + * @arg ADC_FLAG_EOSMP: ADC End of Sampling flag + * @arg ADC_FLAG_EOC: ADC End of Regular Conversion flag + * @arg ADC_FLAG_EOS: ADC End of Regular sequence of Conversions flag + * @arg ADC_FLAG_OVR: ADC overrun flag + * @arg ADC_FLAG_JEOC: ADC End of Injected Conversion flag + * @arg ADC_FLAG_JEOS: ADC End of Injected sequence of Conversions flag + * @arg ADC_FLAG_AWD1: ADC Analog watchdog 1 flag + * @arg ADC_FLAG_AWD2: ADC Analog watchdog 2 flag + * @arg ADC_FLAG_AWD3: ADC Analog watchdog 3 flag + * @arg ADC_FLAG_JQOVF: ADC Injected Context Queue Overflow flag + * @retval None + */ +void ADC_ClearFlag(ADC_TypeDef* ADCx, uint32_t ADC_FLAG) +{ + /* Check the parameters */ + assert_param(IS_ADC_ALL_PERIPH(ADCx)); + assert_param(IS_ADC_CLEAR_FLAG(ADC_FLAG)); + /* Clear the selected ADC flags */ + ADCx->ISR = (uint32_t)ADC_FLAG; +} + +/** + * @brief Checks whether the specified ADC flag is set or not. + * @param ADCx: where x can be 1, 2, 3 or 4 to select the ADC peripheral. + * @param ADC_FLAG: specifies the master or slave flag to check. + * This parameter can be one of the following values: + * @arg ADC_FLAG_MSTRDY: ADC master Ready (ADRDY) flag + * @arg ADC_FLAG_MSTEOSMP: ADC master End of Sampling flag + * @arg ADC_FLAG_MSTEOC: ADC master End of Regular Conversion flag + * @arg ADC_FLAG_MSTEOS: ADC master End of Regular sequence of Conversions flag + * @arg ADC_FLAG_MSTOVR: ADC master overrun flag + * @arg ADC_FLAG_MSTJEOC: ADC master End of Injected Conversion flag + * @arg ADC_FLAG_MSTJEOS: ADC master End of Injected sequence of Conversions flag + * @arg ADC_FLAG_MSTAWD1: ADC master Analog watchdog 1 flag + * @arg ADC_FLAG_MSTAWD2: ADC master Analog watchdog 2 flag + * @arg ADC_FLAG_MSTAWD3: ADC master Analog watchdog 3 flag + * @arg ADC_FLAG_MSTJQOVF: ADC master Injected Context Queue Overflow flag + * @arg ADC_FLAG_SLVRDY: ADC slave Ready (ADRDY) flag + * @arg ADC_FLAG_SLVEOSMP: ADC slave End of Sampling flag + * @arg ADC_FLAG_SLVEOC: ADC slave End of Regular Conversion flag + * @arg ADC_FLAG_SLVEOS: ADC slave End of Regular sequence of Conversions flag + * @arg ADC_FLAG_SLVOVR: ADC slave overrun flag + * @arg ADC_FLAG_SLVJEOC: ADC slave End of Injected Conversion flag + * @arg ADC_FLAG_SLVJEOS: ADC slave End of Injected sequence of Conversions flag + * @arg ADC_FLAG_SLVAWD1: ADC slave Analog watchdog 1 flag + * @arg ADC_FLAG_SLVAWD2: ADC slave Analog watchdog 2 flag + * @arg ADC_FLAG_SLVAWD3: ADC slave Analog watchdog 3 flag + * @arg ADC_FLAG_SLVJQOVF: ADC slave Injected Context Queue Overflow flag + * @retval The new state of ADC_FLAG (SET or RESET). + */ +FlagStatus ADC_GetCommonFlagStatus(ADC_TypeDef* ADCx, uint32_t ADC_FLAG) +{ + uint32_t tmpreg1 = 0; + FlagStatus bitstatus = RESET; + + /* Check the parameters */ + assert_param(IS_ADC_ALL_PERIPH(ADCx)); + assert_param(IS_ADC_GET_COMMONFLAG(ADC_FLAG)); + + if((ADCx == ADC1) || (ADCx == ADC2)) + { + tmpreg1 = ADC1_2->CSR; + } + else + { + tmpreg1 = ADC3_4->CSR; + } + /* Check the status of the specified ADC flag */ + if ((tmpreg1 & ADC_FLAG) != (uint32_t)RESET) + { + /* ADC_FLAG is set */ + bitstatus = SET; + } + else + { + /* ADC_FLAG is reset */ + bitstatus = RESET; + } + /* Return the ADC_FLAG status */ + return bitstatus; +} + +/** + * @brief Clears the ADCx's pending flags. + * @param ADCx: where x can be 1, 2, 3 or 4 to select the ADC peripheral. + * @param ADC_FLAG: specifies the master or slave flag to clear. + * This parameter can be one of the following values: + * @arg ADC_FLAG_MSTRDY: ADC master Ready (ADRDY) flag + * @arg ADC_FLAG_MSTEOSMP: ADC master End of Sampling flag + * @arg ADC_FLAG_MSTEOC: ADC master End of Regular Conversion flag + * @arg ADC_FLAG_MSTEOS: ADC master End of Regular sequence of Conversions flag + * @arg ADC_FLAG_MSTOVR: ADC master overrun flag + * @arg ADC_FLAG_MSTJEOC: ADC master End of Injected Conversion flag + * @arg ADC_FLAG_MSTJEOS: ADC master End of Injected sequence of Conversions flag + * @arg ADC_FLAG_MSTAWD1: ADC master Analog watchdog 1 flag + * @arg ADC_FLAG_MSTAWD2: ADC master Analog watchdog 2 flag + * @arg ADC_FLAG_MSTAWD3: ADC master Analog watchdog 3 flag + * @arg ADC_FLAG_MSTJQOVF: ADC master Injected Context Queue Overflow flag + * @arg ADC_FLAG_SLVRDY: ADC slave Ready (ADRDY) flag + * @arg ADC_FLAG_SLVEOSMP: ADC slave End of Sampling flag + * @arg ADC_FLAG_SLVEOC: ADC slave End of Regular Conversion flag + * @arg ADC_FLAG_SLVEOS: ADC slave End of Regular sequence of Conversions flag + * @arg ADC_FLAG_SLVOVR: ADC slave overrun flag + * @arg ADC_FLAG_SLVJEOC: ADC slave End of Injected Conversion flag + * @arg ADC_FLAG_SLVJEOS: ADC slave End of Injected sequence of Conversions flag + * @arg ADC_FLAG_SLVAWD1: ADC slave Analog watchdog 1 flag + * @arg ADC_FLAG_SLVAWD2: ADC slave Analog watchdog 2 flag + * @arg ADC_FLAG_SLVAWD3: ADC slave Analog watchdog 3 flag + * @arg ADC_FLAG_SLVJQOVF: ADC slave Injected Context Queue Overflow flag + * @retval None + */ +void ADC_ClearCommonFlag(ADC_TypeDef* ADCx, uint32_t ADC_FLAG) +{ + /* Check the parameters */ + assert_param(IS_ADC_ALL_PERIPH(ADCx)); + assert_param(IS_ADC_CLEAR_COMMONFLAG(ADC_FLAG)); + + if((ADCx == ADC1) || (ADCx == ADC2)) + { + /* Clear the selected ADC flags */ + ADC1_2->CSR |= (uint32_t)ADC_FLAG; + } + else + { + /* Clear the selected ADC flags */ + ADC3_4->CSR |= (uint32_t)ADC_FLAG; + } +} + +/** + * @brief Checks whether the specified ADC interrupt has occurred or not. + * @param ADCx: where x can be 1, 2 or 3 to select the ADC peripheral. + * @param ADC_IT: specifies the ADC interrupt source to check. + * This parameter can be one of the following values: + * @arg ADC_IT_RDY: ADC Ready (ADRDY) interrupt source + * @arg ADC_IT_EOSMP: ADC End of Sampling interrupt source + * @arg ADC_IT_EOC: ADC End of Regular Conversion interrupt source + * @arg ADC_IT_EOS: ADC End of Regular sequence of Conversions interrupt source + * @arg ADC_IT_OVR: ADC overrun interrupt source + * @arg ADC_IT_JEOC: ADC End of Injected Conversion interrupt source + * @arg ADC_IT_JEOS: ADC End of Injected sequence of Conversions interrupt source + * @arg ADC_IT_AWD1: ADC Analog watchdog 1 interrupt source + * @arg ADC_IT_AWD2: ADC Analog watchdog 2 interrupt source + * @arg ADC_IT_AWD3: ADC Analog watchdog 3 interrupt source + * @arg ADC_IT_JQOVF: ADC Injected Context Queue Overflow interrupt source + * @retval The new state of ADC_IT (SET or RESET). + */ +ITStatus ADC_GetITStatus(ADC_TypeDef* ADCx, uint32_t ADC_IT) +{ + ITStatus bitstatus = RESET; + uint16_t itstatus = 0x0, itenable = 0x0; + /* Check the parameters */ + assert_param(IS_ADC_ALL_PERIPH(ADCx)); + assert_param(IS_ADC_GET_IT(ADC_IT)); + + itstatus = ADCx->ISR & ADC_IT; + + itenable = ADCx->IER & ADC_IT; + if ((itstatus != (uint32_t)RESET) && (itenable != (uint32_t)RESET)) + { + bitstatus = SET; + } + else + { + bitstatus = RESET; + } + return bitstatus; +} + +/** + * @brief Clears the ADCx's interrupt pending bits. + * @param ADCx: where x can be 1, 2 or 3 to select the ADC peripheral. + * @param ADC_IT: specifies the ADC interrupt pending bit to clear. + * This parameter can be any combination of the following values: + * @arg ADC_IT_RDY: ADC Ready (ADRDY) interrupt source + * @arg ADC_IT_EOSMP: ADC End of Sampling interrupt source + * @arg ADC_IT_EOC: ADC End of Regular Conversion interrupt source + * @arg ADC_IT_EOS: ADC End of Regular sequence of Conversions interrupt source + * @arg ADC_IT_OVR: ADC overrun interrupt source + * @arg ADC_IT_JEOC: ADC End of Injected Conversion interrupt source + * @arg ADC_IT_JEOS: ADC End of Injected sequence of Conversions interrupt source + * @arg ADC_IT_AWD1: ADC Analog watchdog 1 interrupt source + * @arg ADC_IT_AWD2: ADC Analog watchdog 2 interrupt source + * @arg ADC_IT_AWD3: ADC Analog watchdog 3 interrupt source + * @arg ADC_IT_JQOVF: ADC Injected Context Queue Overflow interrupt source + * @retval None + */ +void ADC_ClearITPendingBit(ADC_TypeDef* ADCx, uint32_t ADC_IT) +{ + /* Check the parameters */ + assert_param(IS_ADC_ALL_PERIPH(ADCx)); + assert_param(IS_ADC_IT(ADC_IT)); + /* Clear the selected ADC interrupt pending bit */ + ADCx->ISR = (uint32_t)ADC_IT; +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_can.c b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_can.c new file mode 100755 index 0000000000..40b5a90751 --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_can.c @@ -0,0 +1,1629 @@ +/** + ****************************************************************************** + * @file stm32f30x_can.c + * @author MCD Application Team + * @version V1.2.3 + * @date 10-July-2015 + * @brief This file provides firmware functions to manage the following + * functionalities of the Controller area network (CAN) peripheral: + * + Initialization and Configuration + * + CAN Frames Transmission + * + CAN Frames Reception + * + Operation modes switch + * + Error management + * + Interrupts and flags + * + @verbatim + + =============================================================================== + ##### How to use this driver ##### + =============================================================================== + [..] + (#) Enable the CAN controller interface clock using + RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE); + (#) CAN pins configuration: + (++) Enable the clock for the CAN GPIOs using the following function: + RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOx, ENABLE); + (++) Connect the involved CAN pins to AF9 using the following function + GPIO_PinAFConfig(GPIOx, GPIO_PinSourcex, GPIO_AF_CANx); + (++) Configure these CAN pins in alternate function mode by calling + the function GPIO_Init(); + (#) Initialize and configure the CAN using CAN_Init() and + CAN_FilterInit() functions. + (#) Transmit the desired CAN frame using CAN_Transmit() function. + (#) Check the transmission of a CAN frame using CAN_TransmitStatus() function. + (#) Cancel the transmission of a CAN frame using CAN_CancelTransmit() function. + (#) Receive a CAN frame using CAN_Recieve() function. + (#) Release the receive FIFOs using CAN_FIFORelease() function. + (#) Return the number of pending received frames using CAN_MessagePending() function. + (#) To control CAN events you can use one of the following two methods: + (++) Check on CAN flags using the CAN_GetFlagStatus() function. + (++) Use CAN interrupts through the function CAN_ITConfig() at initialization + phase and CAN_GetITStatus() function into interrupt routines to check + if the event has occurred or not. + After checking on a flag you should clear it using CAN_ClearFlag() + function. And after checking on an interrupt event you should clear it + using CAN_ClearITPendingBit() function. + + @endverbatim + * + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f30x_can.h" +#include "stm32f30x_rcc.h" + +/** @addtogroup STM32F30x_StdPeriph_Driver + * @{ + */ + +/** @defgroup CAN + * @brief CAN driver modules + * @{ + */ +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ + +/* CAN Master Control Register bits */ +#define MCR_DBF ((uint32_t)0x00010000) /* software master reset */ + +/* CAN Mailbox Transmit Request */ +#define TMIDxR_TXRQ ((uint32_t)0x00000001) /* Transmit mailbox request */ + +/* CAN Filter Master Register bits */ +#define FMR_FINIT ((uint32_t)0x00000001) /* Filter init mode */ + +/* Time out for INAK bit */ +#define INAK_TIMEOUT ((uint32_t)0x00FFFFFF) +/* Time out for SLAK bit */ +#define SLAK_TIMEOUT ((uint32_t)0x00FFFFFF) + +/* Flags in TSR register */ +#define CAN_FLAGS_TSR ((uint32_t)0x08000000) +/* Flags in RF1R register */ +#define CAN_FLAGS_RF1R ((uint32_t)0x04000000) +/* Flags in RF0R register */ +#define CAN_FLAGS_RF0R ((uint32_t)0x02000000) +/* Flags in MSR register */ +#define CAN_FLAGS_MSR ((uint32_t)0x01000000) +/* Flags in ESR register */ +#define CAN_FLAGS_ESR ((uint32_t)0x00F00000) + +/* Mailboxes definition */ +#define CAN_TXMAILBOX_0 ((uint8_t)0x00) +#define CAN_TXMAILBOX_1 ((uint8_t)0x01) +#define CAN_TXMAILBOX_2 ((uint8_t)0x02) + +#define CAN_MODE_MASK ((uint32_t) 0x00000003) + +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/* Private function prototypes -----------------------------------------------*/ +/* Private functions ---------------------------------------------------------*/ +static ITStatus CheckITStatus(uint32_t CAN_Reg, uint32_t It_Bit); + +/** @defgroup CAN_Private_Functions + * @{ + */ + +/** @defgroup CAN_Group1 Initialization and Configuration functions + * @brief Initialization and Configuration functions + * +@verbatim + =============================================================================== + ##### Initialization and Configuration functions ##### + =============================================================================== + [..] This section provides functions allowing to: + (+) Initialize the CAN peripherals : Prescaler, operating mode, the maximum + number of time quanta to perform resynchronization, the number of time + quanta in Bit Segment 1 and 2 and many other modes. + (+) Configure the CAN reception filter. + (+) Select the start bank filter for slave CAN. + (+) Enable or disable the Debug Freeze mode for CAN. + (+) Enable or disable the CAN Time Trigger Operation communication mode. + +@endverbatim + * @{ + */ + +/** + * @brief Deinitializes the CAN peripheral registers to their default reset values. + * @param CANx: where x can be 1 to select the CAN1 peripheral. + * @retval None. + */ +void CAN_DeInit(CAN_TypeDef* CANx) +{ + /* Check the parameters */ + assert_param(IS_CAN_ALL_PERIPH(CANx)); + + /* Enable CAN1 reset state */ + RCC_APB1PeriphResetCmd(RCC_APB1Periph_CAN1, ENABLE); + /* Release CAN1 from reset state */ + RCC_APB1PeriphResetCmd(RCC_APB1Periph_CAN1, DISABLE); +} + +/** + * @brief Initializes the CAN peripheral according to the specified + * parameters in the CAN_InitStruct. + * @param CANx: where x can be 1 to select the CAN1 peripheral. + * @param CAN_InitStruct: pointer to a CAN_InitTypeDef structure that contains + * the configuration information for the CAN peripheral. + * @retval Constant indicates initialization succeed which will be + * CAN_InitStatus_Failed or CAN_InitStatus_Success. + */ +uint8_t CAN_Init(CAN_TypeDef* CANx, CAN_InitTypeDef* CAN_InitStruct) +{ + uint8_t InitStatus = CAN_InitStatus_Failed; + __IO uint32_t wait_ack = 0x00000000; + /* Check the parameters */ + assert_param(IS_CAN_ALL_PERIPH(CANx)); + assert_param(IS_FUNCTIONAL_STATE(CAN_InitStruct->CAN_TTCM)); + assert_param(IS_FUNCTIONAL_STATE(CAN_InitStruct->CAN_ABOM)); + assert_param(IS_FUNCTIONAL_STATE(CAN_InitStruct->CAN_AWUM)); + assert_param(IS_FUNCTIONAL_STATE(CAN_InitStruct->CAN_NART)); + assert_param(IS_FUNCTIONAL_STATE(CAN_InitStruct->CAN_RFLM)); + assert_param(IS_FUNCTIONAL_STATE(CAN_InitStruct->CAN_TXFP)); + assert_param(IS_CAN_MODE(CAN_InitStruct->CAN_Mode)); + assert_param(IS_CAN_SJW(CAN_InitStruct->CAN_SJW)); + assert_param(IS_CAN_BS1(CAN_InitStruct->CAN_BS1)); + assert_param(IS_CAN_BS2(CAN_InitStruct->CAN_BS2)); + assert_param(IS_CAN_PRESCALER(CAN_InitStruct->CAN_Prescaler)); + + /* Exit from sleep mode */ + CANx->MCR &= (~(uint32_t)CAN_MCR_SLEEP); + + /* Request initialisation */ + CANx->MCR |= CAN_MCR_INRQ ; + + /* Wait the acknowledge */ + while (((CANx->MSR & CAN_MSR_INAK) != CAN_MSR_INAK) && (wait_ack != INAK_TIMEOUT)) + { + wait_ack++; + } + + /* Check acknowledge */ + if ((CANx->MSR & CAN_MSR_INAK) != CAN_MSR_INAK) + { + InitStatus = CAN_InitStatus_Failed; + } + else + { + /* Set the time triggered communication mode */ + if (CAN_InitStruct->CAN_TTCM == ENABLE) + { + CANx->MCR |= CAN_MCR_TTCM; + } + else + { + CANx->MCR &= ~(uint32_t)CAN_MCR_TTCM; + } + + /* Set the automatic bus-off management */ + if (CAN_InitStruct->CAN_ABOM == ENABLE) + { + CANx->MCR |= CAN_MCR_ABOM; + } + else + { + CANx->MCR &= ~(uint32_t)CAN_MCR_ABOM; + } + + /* Set the automatic wake-up mode */ + if (CAN_InitStruct->CAN_AWUM == ENABLE) + { + CANx->MCR |= CAN_MCR_AWUM; + } + else + { + CANx->MCR &= ~(uint32_t)CAN_MCR_AWUM; + } + + /* Set the no automatic retransmission */ + if (CAN_InitStruct->CAN_NART == ENABLE) + { + CANx->MCR |= CAN_MCR_NART; + } + else + { + CANx->MCR &= ~(uint32_t)CAN_MCR_NART; + } + + /* Set the receive FIFO locked mode */ + if (CAN_InitStruct->CAN_RFLM == ENABLE) + { + CANx->MCR |= CAN_MCR_RFLM; + } + else + { + CANx->MCR &= ~(uint32_t)CAN_MCR_RFLM; + } + + /* Set the transmit FIFO priority */ + if (CAN_InitStruct->CAN_TXFP == ENABLE) + { + CANx->MCR |= CAN_MCR_TXFP; + } + else + { + CANx->MCR &= ~(uint32_t)CAN_MCR_TXFP; + } + + /* Set the bit timing register */ + CANx->BTR = (uint32_t)((uint32_t)CAN_InitStruct->CAN_Mode << 30) | \ + ((uint32_t)CAN_InitStruct->CAN_SJW << 24) | \ + ((uint32_t)CAN_InitStruct->CAN_BS1 << 16) | \ + ((uint32_t)CAN_InitStruct->CAN_BS2 << 20) | \ + ((uint32_t)CAN_InitStruct->CAN_Prescaler - 1); + + /* Request leave initialisation */ + CANx->MCR &= ~(uint32_t)CAN_MCR_INRQ; + + /* Wait the acknowledge */ + wait_ack = 0; + + while (((CANx->MSR & CAN_MSR_INAK) == CAN_MSR_INAK) && (wait_ack != INAK_TIMEOUT)) + { + wait_ack++; + } + + /* ...and check acknowledged */ + if ((CANx->MSR & CAN_MSR_INAK) == CAN_MSR_INAK) + { + InitStatus = CAN_InitStatus_Failed; + } + else + { + InitStatus = CAN_InitStatus_Success ; + } + } + + /* At this step, return the status of initialization */ + return InitStatus; +} + +/** + * @brief Configures the CAN reception filter according to the specified + * parameters in the CAN_FilterInitStruct. + * @param CAN_FilterInitStruct: pointer to a CAN_FilterInitTypeDef structure that + * contains the configuration information. + * @retval None + */ +void CAN_FilterInit(CAN_FilterInitTypeDef* CAN_FilterInitStruct) +{ + uint32_t filter_number_bit_pos = 0; + /* Check the parameters */ + assert_param(IS_CAN_FILTER_NUMBER(CAN_FilterInitStruct->CAN_FilterNumber)); + assert_param(IS_CAN_FILTER_MODE(CAN_FilterInitStruct->CAN_FilterMode)); + assert_param(IS_CAN_FILTER_SCALE(CAN_FilterInitStruct->CAN_FilterScale)); + assert_param(IS_CAN_FILTER_FIFO(CAN_FilterInitStruct->CAN_FilterFIFOAssignment)); + assert_param(IS_FUNCTIONAL_STATE(CAN_FilterInitStruct->CAN_FilterActivation)); + + filter_number_bit_pos = ((uint32_t)1) << CAN_FilterInitStruct->CAN_FilterNumber; + + /* Initialisation mode for the filter */ + CAN1->FMR |= FMR_FINIT; + + /* Filter Deactivation */ + CAN1->FA1R &= ~(uint32_t)filter_number_bit_pos; + + /* Filter Scale */ + if (CAN_FilterInitStruct->CAN_FilterScale == CAN_FilterScale_16bit) + { + /* 16-bit scale for the filter */ + CAN1->FS1R &= ~(uint32_t)filter_number_bit_pos; + + /* First 16-bit identifier and First 16-bit mask */ + /* Or First 16-bit identifier and Second 16-bit identifier */ + CAN1->sFilterRegister[CAN_FilterInitStruct->CAN_FilterNumber].FR1 = + ((0x0000FFFF & (uint32_t)CAN_FilterInitStruct->CAN_FilterMaskIdLow) << 16) | + (0x0000FFFF & (uint32_t)CAN_FilterInitStruct->CAN_FilterIdLow); + + /* Second 16-bit identifier and Second 16-bit mask */ + /* Or Third 16-bit identifier and Fourth 16-bit identifier */ + CAN1->sFilterRegister[CAN_FilterInitStruct->CAN_FilterNumber].FR2 = + ((0x0000FFFF & (uint32_t)CAN_FilterInitStruct->CAN_FilterMaskIdHigh) << 16) | + (0x0000FFFF & (uint32_t)CAN_FilterInitStruct->CAN_FilterIdHigh); + } + + if (CAN_FilterInitStruct->CAN_FilterScale == CAN_FilterScale_32bit) + { + /* 32-bit scale for the filter */ + CAN1->FS1R |= filter_number_bit_pos; + /* 32-bit identifier or First 32-bit identifier */ + CAN1->sFilterRegister[CAN_FilterInitStruct->CAN_FilterNumber].FR1 = + ((0x0000FFFF & (uint32_t)CAN_FilterInitStruct->CAN_FilterIdHigh) << 16) | + (0x0000FFFF & (uint32_t)CAN_FilterInitStruct->CAN_FilterIdLow); + /* 32-bit mask or Second 32-bit identifier */ + CAN1->sFilterRegister[CAN_FilterInitStruct->CAN_FilterNumber].FR2 = + ((0x0000FFFF & (uint32_t)CAN_FilterInitStruct->CAN_FilterMaskIdHigh) << 16) | + (0x0000FFFF & (uint32_t)CAN_FilterInitStruct->CAN_FilterMaskIdLow); + } + + /* Filter Mode */ + if (CAN_FilterInitStruct->CAN_FilterMode == CAN_FilterMode_IdMask) + { + /*Id/Mask mode for the filter*/ + CAN1->FM1R &= ~(uint32_t)filter_number_bit_pos; + } + else /* CAN_FilterInitStruct->CAN_FilterMode == CAN_FilterMode_IdList */ + { + /*Identifier list mode for the filter*/ + CAN1->FM1R |= (uint32_t)filter_number_bit_pos; + } + + /* Filter FIFO assignment */ + if (CAN_FilterInitStruct->CAN_FilterFIFOAssignment == CAN_Filter_FIFO0) + { + /* FIFO 0 assignation for the filter */ + CAN1->FFA1R &= ~(uint32_t)filter_number_bit_pos; + } + + if (CAN_FilterInitStruct->CAN_FilterFIFOAssignment == CAN_Filter_FIFO1) + { + /* FIFO 1 assignation for the filter */ + CAN1->FFA1R |= (uint32_t)filter_number_bit_pos; + } + + /* Filter activation */ + if (CAN_FilterInitStruct->CAN_FilterActivation == ENABLE) + { + CAN1->FA1R |= filter_number_bit_pos; + } + + /* Leave the initialisation mode for the filter */ + CAN1->FMR &= ~FMR_FINIT; +} + +/** + * @brief Fills each CAN_InitStruct member with its default value. + * @param CAN_InitStruct: pointer to a CAN_InitTypeDef structure which ill be initialized. + * @retval None + */ +void CAN_StructInit(CAN_InitTypeDef* CAN_InitStruct) +{ + /* Reset CAN init structure parameters values */ + + /* Initialize the time triggered communication mode */ + CAN_InitStruct->CAN_TTCM = DISABLE; + + /* Initialize the automatic bus-off management */ + CAN_InitStruct->CAN_ABOM = DISABLE; + + /* Initialize the automatic wake-up mode */ + CAN_InitStruct->CAN_AWUM = DISABLE; + + /* Initialize the no automatic retransmission */ + CAN_InitStruct->CAN_NART = DISABLE; + + /* Initialize the receive FIFO locked mode */ + CAN_InitStruct->CAN_RFLM = DISABLE; + + /* Initialize the transmit FIFO priority */ + CAN_InitStruct->CAN_TXFP = DISABLE; + + /* Initialize the CAN_Mode member */ + CAN_InitStruct->CAN_Mode = CAN_Mode_Normal; + + /* Initialize the CAN_SJW member */ + CAN_InitStruct->CAN_SJW = CAN_SJW_1tq; + + /* Initialize the CAN_BS1 member */ + CAN_InitStruct->CAN_BS1 = CAN_BS1_4tq; + + /* Initialize the CAN_BS2 member */ + CAN_InitStruct->CAN_BS2 = CAN_BS2_3tq; + + /* Initialize the CAN_Prescaler member */ + CAN_InitStruct->CAN_Prescaler = 1; +} + +/** + * @brief Select the start bank filter for slave CAN. + * @param CAN_BankNumber: Select the start slave bank filter from 1..27. + * @retval None + */ +void CAN_SlaveStartBank(uint8_t CAN_BankNumber) +{ + /* Check the parameters */ + assert_param(IS_CAN_BANKNUMBER(CAN_BankNumber)); + + /* Enter Initialisation mode for the filter */ + CAN1->FMR |= FMR_FINIT; + + /* Select the start slave bank */ + CAN1->FMR &= (uint32_t)0xFFFFC0F1 ; + CAN1->FMR |= (uint32_t)(CAN_BankNumber)<<8; + + /* Leave Initialisation mode for the filter */ + CAN1->FMR &= ~FMR_FINIT; +} + +/** + * @brief Enables or disables the DBG Freeze for CAN. + * @param CANx: where x can be 1 or 2 to select the CAN peripheral. + * @param NewState: new state of the CAN peripheral. + * This parameter can be: ENABLE (CAN reception/transmission is frozen + * during debug. Reception FIFOs can still be accessed/controlled normally) + * or DISABLE (CAN is working during debug). + * @retval None + */ +void CAN_DBGFreeze(CAN_TypeDef* CANx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_CAN_ALL_PERIPH(CANx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable Debug Freeze */ + CANx->MCR |= MCR_DBF; + } + else + { + /* Disable Debug Freeze */ + CANx->MCR &= ~MCR_DBF; + } +} + +/** + * @brief Enables or disables the CAN Time TriggerOperation communication mode. + * @note DLC must be programmed as 8 in order Time Stamp (2 bytes) to be + * sent over the CAN bus. + * @param CANx: where x can be 1 or 2 to select the CAN peripheral. + * @param NewState: Mode new state. This parameter can be: ENABLE or DISABLE. + * When enabled, Time stamp (TIME[15:0]) value is sent in the last two + * data bytes of the 8-byte message: TIME[7:0] in data byte 6 and TIME[15:8] + * in data byte 7. + * @retval None + */ +void CAN_TTComModeCmd(CAN_TypeDef* CANx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_CAN_ALL_PERIPH(CANx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + if (NewState != DISABLE) + { + /* Enable the TTCM mode */ + CANx->MCR |= CAN_MCR_TTCM; + + /* Set TGT bits */ + CANx->sTxMailBox[0].TDTR |= ((uint32_t)CAN_TDT0R_TGT); + CANx->sTxMailBox[1].TDTR |= ((uint32_t)CAN_TDT1R_TGT); + CANx->sTxMailBox[2].TDTR |= ((uint32_t)CAN_TDT2R_TGT); + } + else + { + /* Disable the TTCM mode */ + CANx->MCR &= (uint32_t)(~(uint32_t)CAN_MCR_TTCM); + + /* Reset TGT bits */ + CANx->sTxMailBox[0].TDTR &= ((uint32_t)~CAN_TDT0R_TGT); + CANx->sTxMailBox[1].TDTR &= ((uint32_t)~CAN_TDT1R_TGT); + CANx->sTxMailBox[2].TDTR &= ((uint32_t)~CAN_TDT2R_TGT); + } +} +/** + * @} + */ + + +/** @defgroup CAN_Group2 CAN Frames Transmission functions + * @brief CAN Frames Transmission functions + * +@verbatim + =============================================================================== + ##### CAN Frames Transmission functions ##### + =============================================================================== + [..] This section provides functions allowing to + (+) Initiate and transmit a CAN frame message (if there is an empty mailbox). + (+) Check the transmission status of a CAN Frame. + (+) Cancel a transmit request. + +@endverbatim + * @{ + */ + +/** + * @brief Initiates and transmits a CAN frame message. + * @param CANx: where x can be 1 or 2 to select the CAN peripheral. + * @param TxMessage: pointer to a structure which contains CAN Id, CAN DLC and CAN data. + * @retval The number of the mailbox that is used for transmission or + * CAN_TxStatus_NoMailBox if there is no empty mailbox. + */ +uint8_t CAN_Transmit(CAN_TypeDef* CANx, CanTxMsg* TxMessage) +{ + uint8_t transmit_mailbox = 0; + /* Check the parameters */ + assert_param(IS_CAN_ALL_PERIPH(CANx)); + assert_param(IS_CAN_IDTYPE(TxMessage->IDE)); + assert_param(IS_CAN_RTR(TxMessage->RTR)); + assert_param(IS_CAN_DLC(TxMessage->DLC)); + + /* Select one empty transmit mailbox */ + if ((CANx->TSR&CAN_TSR_TME0) == CAN_TSR_TME0) + { + transmit_mailbox = 0; + } + else if ((CANx->TSR&CAN_TSR_TME1) == CAN_TSR_TME1) + { + transmit_mailbox = 1; + } + else if ((CANx->TSR&CAN_TSR_TME2) == CAN_TSR_TME2) + { + transmit_mailbox = 2; + } + else + { + transmit_mailbox = CAN_TxStatus_NoMailBox; + } + + if (transmit_mailbox != CAN_TxStatus_NoMailBox) + { + /* Set up the Id */ + CANx->sTxMailBox[transmit_mailbox].TIR &= TMIDxR_TXRQ; + if (TxMessage->IDE == CAN_Id_Standard) + { + assert_param(IS_CAN_STDID(TxMessage->StdId)); + CANx->sTxMailBox[transmit_mailbox].TIR |= ((TxMessage->StdId << 21) | \ + TxMessage->RTR); + } + else + { + assert_param(IS_CAN_EXTID(TxMessage->ExtId)); + CANx->sTxMailBox[transmit_mailbox].TIR |= ((TxMessage->ExtId << 3) | \ + TxMessage->IDE | \ + TxMessage->RTR); + } + + /* Set up the DLC */ + TxMessage->DLC &= (uint8_t)0x0000000F; + CANx->sTxMailBox[transmit_mailbox].TDTR &= (uint32_t)0xFFFFFFF0; + CANx->sTxMailBox[transmit_mailbox].TDTR |= TxMessage->DLC; + + /* Set up the data field */ + CANx->sTxMailBox[transmit_mailbox].TDLR = (((uint32_t)TxMessage->Data[3] << 24) | + ((uint32_t)TxMessage->Data[2] << 16) | + ((uint32_t)TxMessage->Data[1] << 8) | + ((uint32_t)TxMessage->Data[0])); + CANx->sTxMailBox[transmit_mailbox].TDHR = (((uint32_t)TxMessage->Data[7] << 24) | + ((uint32_t)TxMessage->Data[6] << 16) | + ((uint32_t)TxMessage->Data[5] << 8) | + ((uint32_t)TxMessage->Data[4])); + /* Request transmission */ + CANx->sTxMailBox[transmit_mailbox].TIR |= TMIDxR_TXRQ; + } + return transmit_mailbox; +} + +/** + * @brief Checks the transmission status of a CAN Frame. + * @param CANx: where x can be 1 to select the CAN1 peripheral. + * @param TransmitMailbox: the number of the mailbox that is used for transmission. + * @retval CAN_TxStatus_Ok if the CAN driver transmits the message, + * CAN_TxStatus_Failed in an other case. + */ +uint8_t CAN_TransmitStatus(CAN_TypeDef* CANx, uint8_t TransmitMailbox) +{ + uint32_t state = 0; + + /* Check the parameters */ + assert_param(IS_CAN_ALL_PERIPH(CANx)); + assert_param(IS_CAN_TRANSMITMAILBOX(TransmitMailbox)); + + switch (TransmitMailbox) + { + case (CAN_TXMAILBOX_0): + state = CANx->TSR & (CAN_TSR_RQCP0 | CAN_TSR_TXOK0 | CAN_TSR_TME0); + break; + case (CAN_TXMAILBOX_1): + state = CANx->TSR & (CAN_TSR_RQCP1 | CAN_TSR_TXOK1 | CAN_TSR_TME1); + break; + case (CAN_TXMAILBOX_2): + state = CANx->TSR & (CAN_TSR_RQCP2 | CAN_TSR_TXOK2 | CAN_TSR_TME2); + break; + default: + state = CAN_TxStatus_Failed; + break; + } + switch (state) + { + /* transmit pending */ + case (0x0): state = CAN_TxStatus_Pending; + break; + /* transmit failed */ + case (CAN_TSR_RQCP0 | CAN_TSR_TME0): state = CAN_TxStatus_Failed; + break; + case (CAN_TSR_RQCP1 | CAN_TSR_TME1): state = CAN_TxStatus_Failed; + break; + case (CAN_TSR_RQCP2 | CAN_TSR_TME2): state = CAN_TxStatus_Failed; + break; + /* transmit succeeded */ + case (CAN_TSR_RQCP0 | CAN_TSR_TXOK0 | CAN_TSR_TME0):state = CAN_TxStatus_Ok; + break; + case (CAN_TSR_RQCP1 | CAN_TSR_TXOK1 | CAN_TSR_TME1):state = CAN_TxStatus_Ok; + break; + case (CAN_TSR_RQCP2 | CAN_TSR_TXOK2 | CAN_TSR_TME2):state = CAN_TxStatus_Ok; + break; + default: state = CAN_TxStatus_Failed; + break; + } + return (uint8_t) state; +} + +/** + * @brief Cancels a transmit request. + * @param CANx: where x can be 1 to select the CAN1 peripheral. + * @param Mailbox: Mailbox number. + * @retval None + */ +void CAN_CancelTransmit(CAN_TypeDef* CANx, uint8_t Mailbox) +{ + /* Check the parameters */ + assert_param(IS_CAN_ALL_PERIPH(CANx)); + assert_param(IS_CAN_TRANSMITMAILBOX(Mailbox)); + /* abort transmission */ + switch (Mailbox) + { + case (CAN_TXMAILBOX_0): CANx->TSR |= CAN_TSR_ABRQ0; + break; + case (CAN_TXMAILBOX_1): CANx->TSR |= CAN_TSR_ABRQ1; + break; + case (CAN_TXMAILBOX_2): CANx->TSR |= CAN_TSR_ABRQ2; + break; + default: + break; + } +} +/** + * @} + */ + + +/** @defgroup CAN_Group3 CAN Frames Reception functions + * @brief CAN Frames Reception functions + * +@verbatim + =============================================================================== + ##### CAN Frames Reception functions ##### + =============================================================================== + [..] This section provides functions allowing to + (+) Receive a correct CAN frame. + (+) Release a specified receive FIFO (2 FIFOs are available). + (+) Return the number of the pending received CAN frames. + +@endverbatim + * @{ + */ + +/** + * @brief Receives a correct CAN frame. + * @param CANx: where x can be 1 to select the CAN1 peripheral. + * @param FIFONumber: Receive FIFO number, CAN_FIFO0 or CAN_FIFO1. + * @param RxMessage: pointer to a structure receive frame which contains CAN Id, + * CAN DLC, CAN data and FMI number. + * @retval None + */ +void CAN_Receive(CAN_TypeDef* CANx, uint8_t FIFONumber, CanRxMsg* RxMessage) +{ + /* Check the parameters */ + assert_param(IS_CAN_ALL_PERIPH(CANx)); + assert_param(IS_CAN_FIFO(FIFONumber)); + /* Get the Id */ + RxMessage->IDE = (uint8_t)0x04 & CANx->sFIFOMailBox[FIFONumber].RIR; + if (RxMessage->IDE == CAN_Id_Standard) + { + RxMessage->StdId = (uint32_t)0x000007FF & (CANx->sFIFOMailBox[FIFONumber].RIR >> 21); + } + else + { + RxMessage->ExtId = (uint32_t)0x1FFFFFFF & (CANx->sFIFOMailBox[FIFONumber].RIR >> 3); + } + + RxMessage->RTR = (uint8_t)0x02 & CANx->sFIFOMailBox[FIFONumber].RIR; + /* Get the DLC */ + RxMessage->DLC = (uint8_t)0x0F & CANx->sFIFOMailBox[FIFONumber].RDTR; + /* Get the FMI */ + RxMessage->FMI = (uint8_t)0xFF & (CANx->sFIFOMailBox[FIFONumber].RDTR >> 8); + /* Get the data field */ + RxMessage->Data[0] = (uint8_t)0xFF & CANx->sFIFOMailBox[FIFONumber].RDLR; + RxMessage->Data[1] = (uint8_t)0xFF & (CANx->sFIFOMailBox[FIFONumber].RDLR >> 8); + RxMessage->Data[2] = (uint8_t)0xFF & (CANx->sFIFOMailBox[FIFONumber].RDLR >> 16); + RxMessage->Data[3] = (uint8_t)0xFF & (CANx->sFIFOMailBox[FIFONumber].RDLR >> 24); + RxMessage->Data[4] = (uint8_t)0xFF & CANx->sFIFOMailBox[FIFONumber].RDHR; + RxMessage->Data[5] = (uint8_t)0xFF & (CANx->sFIFOMailBox[FIFONumber].RDHR >> 8); + RxMessage->Data[6] = (uint8_t)0xFF & (CANx->sFIFOMailBox[FIFONumber].RDHR >> 16); + RxMessage->Data[7] = (uint8_t)0xFF & (CANx->sFIFOMailBox[FIFONumber].RDHR >> 24); + /* Release the FIFO */ + /* Release FIFO0 */ + if (FIFONumber == CAN_FIFO0) + { + CANx->RF0R |= CAN_RF0R_RFOM0; + } + /* Release FIFO1 */ + else /* FIFONumber == CAN_FIFO1 */ + { + CANx->RF1R |= CAN_RF1R_RFOM1; + } +} + +/** + * @brief Releases the specified receive FIFO. + * @param CANx: where x can be 1 to select the CAN1 peripheral. + * @param FIFONumber: FIFO to release, CAN_FIFO0 or CAN_FIFO1. + * @retval None + */ +void CAN_FIFORelease(CAN_TypeDef* CANx, uint8_t FIFONumber) +{ + /* Check the parameters */ + assert_param(IS_CAN_ALL_PERIPH(CANx)); + assert_param(IS_CAN_FIFO(FIFONumber)); + /* Release FIFO0 */ + if (FIFONumber == CAN_FIFO0) + { + CANx->RF0R |= CAN_RF0R_RFOM0; + } + /* Release FIFO1 */ + else /* FIFONumber == CAN_FIFO1 */ + { + CANx->RF1R |= CAN_RF1R_RFOM1; + } +} + +/** + * @brief Returns the number of pending received messages. + * @param CANx: where x can be 1 to select the CAN1 peripheral. + * @param FIFONumber: Receive FIFO number, CAN_FIFO0 or CAN_FIFO1. + * @retval NbMessage : which is the number of pending message. + */ +uint8_t CAN_MessagePending(CAN_TypeDef* CANx, uint8_t FIFONumber) +{ + uint8_t message_pending=0; + /* Check the parameters */ + assert_param(IS_CAN_ALL_PERIPH(CANx)); + assert_param(IS_CAN_FIFO(FIFONumber)); + if (FIFONumber == CAN_FIFO0) + { + message_pending = (uint8_t)(CANx->RF0R&(uint32_t)0x03); + } + else if (FIFONumber == CAN_FIFO1) + { + message_pending = (uint8_t)(CANx->RF1R&(uint32_t)0x03); + } + else + { + message_pending = 0; + } + return message_pending; +} +/** + * @} + */ + + +/** @defgroup CAN_Group4 CAN Operation modes functions + * @brief CAN Operation modes functions + * +@verbatim + =============================================================================== + ##### CAN Operation modes functions ##### + =============================================================================== + [..] This section provides functions allowing to select the CAN Operation modes: + (+) sleep mode. + (+) normal mode. + (+) initialization mode. + +@endverbatim + * @{ + */ + + +/** + * @brief Selects the CAN Operation mode. + * @param CAN_OperatingMode: CAN Operating Mode. + * This parameter can be one of @ref CAN_OperatingMode_TypeDef enumeration. + * @retval status of the requested mode which can be: + * - CAN_ModeStatus_Failed: CAN failed entering the specific mode + * - CAN_ModeStatus_Success: CAN Succeed entering the specific mode + */ +uint8_t CAN_OperatingModeRequest(CAN_TypeDef* CANx, uint8_t CAN_OperatingMode) +{ + uint8_t status = CAN_ModeStatus_Failed; + + /* Timeout for INAK or also for SLAK bits*/ + uint32_t timeout = INAK_TIMEOUT; + + /* Check the parameters */ + assert_param(IS_CAN_ALL_PERIPH(CANx)); + assert_param(IS_CAN_OPERATING_MODE(CAN_OperatingMode)); + + if (CAN_OperatingMode == CAN_OperatingMode_Initialization) + { + /* Request initialisation */ + CANx->MCR = (uint32_t)((CANx->MCR & (uint32_t)(~(uint32_t)CAN_MCR_SLEEP)) | CAN_MCR_INRQ); + + /* Wait the acknowledge */ + while (((CANx->MSR & CAN_MODE_MASK) != CAN_MSR_INAK) && (timeout != 0)) + { + timeout--; + } + if ((CANx->MSR & CAN_MODE_MASK) != CAN_MSR_INAK) + { + status = CAN_ModeStatus_Failed; + } + else + { + status = CAN_ModeStatus_Success; + } + } + else if (CAN_OperatingMode == CAN_OperatingMode_Normal) + { + /* Request leave initialisation and sleep mode and enter Normal mode */ + CANx->MCR &= (uint32_t)(~(CAN_MCR_SLEEP|CAN_MCR_INRQ)); + + /* Wait the acknowledge */ + while (((CANx->MSR & CAN_MODE_MASK) != 0) && (timeout!=0)) + { + timeout--; + } + if ((CANx->MSR & CAN_MODE_MASK) != 0) + { + status = CAN_ModeStatus_Failed; + } + else + { + status = CAN_ModeStatus_Success; + } + } + else if (CAN_OperatingMode == CAN_OperatingMode_Sleep) + { + /* Request Sleep mode */ + CANx->MCR = (uint32_t)((CANx->MCR & (uint32_t)(~(uint32_t)CAN_MCR_INRQ)) | CAN_MCR_SLEEP); + + /* Wait the acknowledge */ + while (((CANx->MSR & CAN_MODE_MASK) != CAN_MSR_SLAK) && (timeout!=0)) + { + timeout--; + } + if ((CANx->MSR & CAN_MODE_MASK) != CAN_MSR_SLAK) + { + status = CAN_ModeStatus_Failed; + } + else + { + status = CAN_ModeStatus_Success; + } + } + else + { + status = CAN_ModeStatus_Failed; + } + + return (uint8_t) status; +} + +/** + * @brief Enters the Sleep (low power) mode. + * @param CANx: where x can be 1 to select the CAN1 peripheral. + * @retval CAN_Sleep_Ok if sleep entered, CAN_Sleep_Failed otherwise. + */ +uint8_t CAN_Sleep(CAN_TypeDef* CANx) +{ + uint8_t sleepstatus = CAN_Sleep_Failed; + + /* Check the parameters */ + assert_param(IS_CAN_ALL_PERIPH(CANx)); + + /* Request Sleep mode */ + CANx->MCR = (((CANx->MCR) & (uint32_t)(~(uint32_t)CAN_MCR_INRQ)) | CAN_MCR_SLEEP); + + /* Sleep mode status */ + if ((CANx->MSR & (CAN_MSR_SLAK|CAN_MSR_INAK)) == CAN_MSR_SLAK) + { + /* Sleep mode not entered */ + sleepstatus = CAN_Sleep_Ok; + } + /* return sleep mode status */ + return (uint8_t)sleepstatus; +} + +/** + * @brief Wakes up the CAN peripheral from sleep mode . + * @param CANx: where x can be 1 to select the CAN1 peripheral. + * @retval CAN_WakeUp_Ok if sleep mode left, CAN_WakeUp_Failed otherwise. + */ +uint8_t CAN_WakeUp(CAN_TypeDef* CANx) +{ + uint32_t wait_slak = SLAK_TIMEOUT; + uint8_t wakeupstatus = CAN_WakeUp_Failed; + + /* Check the parameters */ + assert_param(IS_CAN_ALL_PERIPH(CANx)); + + /* Wake up request */ + CANx->MCR &= ~(uint32_t)CAN_MCR_SLEEP; + + /* Sleep mode status */ + while(((CANx->MSR & CAN_MSR_SLAK) == CAN_MSR_SLAK)&&(wait_slak!=0x00)) + { + wait_slak--; + } + if((CANx->MSR & CAN_MSR_SLAK) != CAN_MSR_SLAK) + { + /* wake up done : Sleep mode exited */ + wakeupstatus = CAN_WakeUp_Ok; + } + /* return wakeup status */ + return (uint8_t)wakeupstatus; +} +/** + * @} + */ + + +/** @defgroup CAN_Group5 CAN Bus Error management functions + * @brief CAN Bus Error management functions + * +@verbatim + =============================================================================== + ##### CAN Bus Error management functions ##### + =============================================================================== + [..] This section provides functions allowing to + (+) Return the CANx's last error code (LEC). + (+) Return the CANx Receive Error Counter (REC). + (+) Return the LSB of the 9-bit CANx Transmit Error Counter(TEC). + [..] + (@) If TEC is greater than 255, The CAN is in bus-off state. + (@) If REC or TEC are greater than 96, an Error warning flag occurs. + (@) If REC or TEC are greater than 127, an Error Passive Flag occurs. + +@endverbatim + * @{ + */ + +/** + * @brief Returns the CANx's last error code (LEC). + * @param CANx: where x can be 1 to select the CAN1 peripheral. + * @retval Error code: + * - CAN_ERRORCODE_NoErr: No Error + * - CAN_ERRORCODE_StuffErr: Stuff Error + * - CAN_ERRORCODE_FormErr: Form Error + * - CAN_ERRORCODE_ACKErr : Acknowledgment Error + * - CAN_ERRORCODE_BitRecessiveErr: Bit Recessive Error + * - CAN_ERRORCODE_BitDominantErr: Bit Dominant Error + * - CAN_ERRORCODE_CRCErr: CRC Error + * - CAN_ERRORCODE_SoftwareSetErr: Software Set Error + */ +uint8_t CAN_GetLastErrorCode(CAN_TypeDef* CANx) +{ + uint8_t errorcode=0; + + /* Check the parameters */ + assert_param(IS_CAN_ALL_PERIPH(CANx)); + + /* Get the error code*/ + errorcode = (((uint8_t)CANx->ESR) & (uint8_t)CAN_ESR_LEC); + + /* Return the error code*/ + return errorcode; +} + +/** + * @brief Returns the CANx Receive Error Counter (REC). + * @note In case of an error during reception, this counter is incremented + * by 1 or by 8 depending on the error condition as defined by the CAN + * standard. After every successful reception, the counter is + * decremented by 1 or reset to 120 if its value was higher than 128. + * When the counter value exceeds 127, the CAN controller enters the + * error passive state. + * @param CANx: where x can be 1 or 2 to select the CAN peripheral. + * @retval CAN Receive Error Counter. + */ +uint8_t CAN_GetReceiveErrorCounter(CAN_TypeDef* CANx) +{ + uint8_t counter=0; + + /* Check the parameters */ + assert_param(IS_CAN_ALL_PERIPH(CANx)); + + /* Get the Receive Error Counter*/ + counter = (uint8_t)((CANx->ESR & CAN_ESR_REC)>> 24); + + /* Return the Receive Error Counter*/ + return counter; +} + + +/** + * @brief Returns the LSB of the 9-bit CANx Transmit Error Counter(TEC). + * @param CANx: where x can be 1 or 2 to select the CAN peripheral. + * @retval LSB of the 9-bit CAN Transmit Error Counter. + */ +uint8_t CAN_GetLSBTransmitErrorCounter(CAN_TypeDef* CANx) +{ + uint8_t counter=0; + + /* Check the parameters */ + assert_param(IS_CAN_ALL_PERIPH(CANx)); + + /* Get the LSB of the 9-bit CANx Transmit Error Counter(TEC) */ + counter = (uint8_t)((CANx->ESR & CAN_ESR_TEC)>> 16); + + /* Return the LSB of the 9-bit CANx Transmit Error Counter(TEC) */ + return counter; +} +/** + * @} + */ + +/** @defgroup CAN_Group6 Interrupts and flags management functions + * @brief Interrupts and flags management functions + * +@verbatim + =============================================================================== + ##### Interrupts and flags management functions ##### + =============================================================================== + [..] This section provides functions allowing to configure the CAN Interrupts + and to get the status and clear flags and Interrupts pending bits. + [..] The CAN provides 14 Interrupts sources and 15 Flags: + + *** Flags *** + ============= + [..] The 15 flags can be divided on 4 groups: + (+) Transmit Flags: + (++) CAN_FLAG_RQCP0. + (++) CAN_FLAG_RQCP1. + (++) CAN_FLAG_RQCP2: Request completed MailBoxes 0, 1 and 2 Flags + Set when the last request (transmit or abort) has + been performed. + (+) Receive Flags: + (++) CAN_FLAG_FMP0. + (++) CAN_FLAG_FMP1: FIFO 0 and 1 Message Pending Flags; + Set to signal that messages are pending in the receive FIFO. + These Flags are cleared only by hardware. + (++) CAN_FLAG_FF0. + (++) CAN_FLAG_FF1: FIFO 0 and 1 Full Flags; + Set when three messages are stored in the selected FIFO. + (++) CAN_FLAG_FOV0. + (++) CAN_FLAG_FOV1: FIFO 0 and 1 Overrun Flags; + Set when a new message has been received and passed the filter + while the FIFO was full. + (+) Operating Mode Flags: + (++) CAN_FLAG_WKU: Wake up Flag; + Set to signal that a SOF bit has been detected while the CAN + hardware was in Sleep mode. + (++) CAN_FLAG_SLAK: Sleep acknowledge Flag; + Set to signal that the CAN has entered Sleep Mode. + (+) Error Flags: + (++) CAN_FLAG_EWG: Error Warning Flag; + Set when the warning limit has been reached (Receive Error Counter + or Transmit Error Counter greater than 96). + This Flag is cleared only by hardware. + (++) CAN_FLAG_EPV: Error Passive Flag; + Set when the Error Passive limit has been reached (Receive Error + Counter or Transmit Error Counter greater than 127). + This Flag is cleared only by hardware. + (++) CAN_FLAG_BOF: Bus-Off Flag; + Set when CAN enters the bus-off state. The bus-off state is + entered on TEC overflow, greater than 255. + This Flag is cleared only by hardware. + (++) CAN_FLAG_LEC: Last error code Flag; + Set If a message has been transferred (reception or transmission) + with error, and the error code is hold. + + *** Interrupts *** + ================== + [..] The 14 interrupts can be divided on 4 groups: + (+) Transmit interrupt: + (++) CAN_IT_TME: Transmit mailbox empty Interrupt; + If enabled, this interrupt source is pending when no transmit + request are pending for Tx mailboxes. + (+) Receive Interrupts: + (++) CAN_IT_FMP0. + (++) CAN_IT_FMP1: FIFO 0 and FIFO1 message pending Interrupts; + If enabled, these interrupt sources are pending when messages + are pending in the receive FIFO. + The corresponding interrupt pending bits are cleared only by hardware. + (++) CAN_IT_FF0. + (++) CAN_IT_FF1: FIFO 0 and FIFO1 full Interrupts; + If enabled, these interrupt sources are pending when three messages + are stored in the selected FIFO. + (++) CAN_IT_FOV0. + (++) CAN_IT_FOV1: FIFO 0 and FIFO1 overrun Interrupts; + If enabled, these interrupt sources are pending when a new message + has been received and passed the filter while the FIFO was full. + (+) Operating Mode Interrupts: + (++) CAN_IT_WKU: Wake-up Interrupt; + If enabled, this interrupt source is pending when a SOF bit has + been detected while the CAN hardware was in Sleep mode. + (++) CAN_IT_SLK: Sleep acknowledge Interrupt: + If enabled, this interrupt source is pending when the CAN has + entered Sleep Mode. + (+) Error Interrupts: + (++) CAN_IT_EWG: Error warning Interrupt; + If enabled, this interrupt source is pending when the warning limit + has been reached (Receive Error Counter or Transmit Error Counter=96). + (++) CAN_IT_EPV: Error passive Interrupt; + If enabled, this interrupt source is pending when the Error Passive + limit has been reached (Receive Error Counter or Transmit Error Counter>127). + (++) CAN_IT_BOF: Bus-off Interrupt; + If enabled, this interrupt source is pending when CAN enters + the bus-off state. The bus-off state is entered on TEC overflow, + greater than 255. + This Flag is cleared only by hardware. + (++) CAN_IT_LEC: Last error code Interrupt; + If enabled, this interrupt source is pending when a message has + been transferred (reception or transmission) with error and the + error code is hold. + (++) CAN_IT_ERR: Error Interrupt; + If enabled, this interrupt source is pending when an error condition + is pending. + [..] Managing the CAN controller events: + The user should identify which mode will be used in his application to manage + the CAN controller events: Polling mode or Interrupt mode. + (+) In the Polling Mode it is advised to use the following functions: + (++) CAN_GetFlagStatus() : to check if flags events occur. + (++) CAN_ClearFlag() : to clear the flags events. + (+) In the Interrupt Mode it is advised to use the following functions: + (++) CAN_ITConfig() : to enable or disable the interrupt source. + (++) CAN_GetITStatus() : to check if Interrupt occurs. + (++) CAN_ClearITPendingBit() : to clear the Interrupt pending Bit + (corresponding Flag). + This function has no impact on CAN_IT_FMP0 and CAN_IT_FMP1 Interrupts + pending bits since there are cleared only by hardware. + +@endverbatim + * @{ + */ +/** + * @brief Enables or disables the specified CANx interrupts. + * @param CANx: where x can be 1 or 2 to select the CAN peripheral. + * @param CAN_IT: specifies the CAN interrupt sources to be enabled or disabled. + * This parameter can be: + * @arg CAN_IT_TME: Transmit mailbox empty Interrupt + * @arg CAN_IT_FMP0: FIFO 0 message pending Interrupt + * @arg CAN_IT_FF0: FIFO 0 full Interrupt + * @arg CAN_IT_FOV0: FIFO 0 overrun Interrupt + * @arg CAN_IT_FMP1: FIFO 1 message pending Interrupt + * @arg CAN_IT_FF1: FIFO 1 full Interrupt + * @arg CAN_IT_FOV1: FIFO 1 overrun Interrupt + * @arg CAN_IT_WKU: Wake-up Interrupt + * @arg CAN_IT_SLK: Sleep acknowledge Interrupt + * @arg CAN_IT_EWG: Error warning Interrupt + * @arg CAN_IT_EPV: Error passive Interrupt + * @arg CAN_IT_BOF: Bus-off Interrupt + * @arg CAN_IT_LEC: Last error code Interrupt + * @arg CAN_IT_ERR: Error Interrupt + * @param NewState: new state of the CAN interrupts. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void CAN_ITConfig(CAN_TypeDef* CANx, uint32_t CAN_IT, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_CAN_ALL_PERIPH(CANx)); + assert_param(IS_CAN_IT(CAN_IT)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable the selected CANx interrupt */ + CANx->IER |= CAN_IT; + } + else + { + /* Disable the selected CANx interrupt */ + CANx->IER &= ~CAN_IT; + } +} +/** + * @brief Checks whether the specified CAN flag is set or not. + * @param CANx: where x can be 1 or 2 to select the CAN peripheral. + * @param CAN_FLAG: specifies the flag to check. + * This parameter can be one of the following values: + * @arg CAN_FLAG_RQCP0: Request MailBox0 Flag + * @arg CAN_FLAG_RQCP1: Request MailBox1 Flag + * @arg CAN_FLAG_RQCP2: Request MailBox2 Flag + * @arg CAN_FLAG_FMP0: FIFO 0 Message Pending Flag + * @arg CAN_FLAG_FF0: FIFO 0 Full Flag + * @arg CAN_FLAG_FOV0: FIFO 0 Overrun Flag + * @arg CAN_FLAG_FMP1: FIFO 1 Message Pending Flag + * @arg CAN_FLAG_FF1: FIFO 1 Full Flag + * @arg CAN_FLAG_FOV1: FIFO 1 Overrun Flag + * @arg CAN_FLAG_WKU: Wake up Flag + * @arg CAN_FLAG_SLAK: Sleep acknowledge Flag + * @arg CAN_FLAG_EWG: Error Warning Flag + * @arg CAN_FLAG_EPV: Error Passive Flag + * @arg CAN_FLAG_BOF: Bus-Off Flag + * @arg CAN_FLAG_LEC: Last error code Flag + * @retval The new state of CAN_FLAG (SET or RESET). + */ +FlagStatus CAN_GetFlagStatus(CAN_TypeDef* CANx, uint32_t CAN_FLAG) +{ + FlagStatus bitstatus = RESET; + + /* Check the parameters */ + assert_param(IS_CAN_ALL_PERIPH(CANx)); + assert_param(IS_CAN_GET_FLAG(CAN_FLAG)); + + + if((CAN_FLAG & CAN_FLAGS_ESR) != (uint32_t)RESET) + { + /* Check the status of the specified CAN flag */ + if ((CANx->ESR & (CAN_FLAG & 0x000FFFFF)) != (uint32_t)RESET) + { + /* CAN_FLAG is set */ + bitstatus = SET; + } + else + { + /* CAN_FLAG is reset */ + bitstatus = RESET; + } + } + else if((CAN_FLAG & CAN_FLAGS_MSR) != (uint32_t)RESET) + { + /* Check the status of the specified CAN flag */ + if ((CANx->MSR & (CAN_FLAG & 0x000FFFFF)) != (uint32_t)RESET) + { + /* CAN_FLAG is set */ + bitstatus = SET; + } + else + { + /* CAN_FLAG is reset */ + bitstatus = RESET; + } + } + else if((CAN_FLAG & CAN_FLAGS_TSR) != (uint32_t)RESET) + { + /* Check the status of the specified CAN flag */ + if ((CANx->TSR & (CAN_FLAG & 0x000FFFFF)) != (uint32_t)RESET) + { + /* CAN_FLAG is set */ + bitstatus = SET; + } + else + { + /* CAN_FLAG is reset */ + bitstatus = RESET; + } + } + else if((CAN_FLAG & CAN_FLAGS_RF0R) != (uint32_t)RESET) + { + /* Check the status of the specified CAN flag */ + if ((CANx->RF0R & (CAN_FLAG & 0x000FFFFF)) != (uint32_t)RESET) + { + /* CAN_FLAG is set */ + bitstatus = SET; + } + else + { + /* CAN_FLAG is reset */ + bitstatus = RESET; + } + } + else /* If(CAN_FLAG & CAN_FLAGS_RF1R != (uint32_t)RESET) */ + { + /* Check the status of the specified CAN flag */ + if ((uint32_t)(CANx->RF1R & (CAN_FLAG & 0x000FFFFF)) != (uint32_t)RESET) + { + /* CAN_FLAG is set */ + bitstatus = SET; + } + else + { + /* CAN_FLAG is reset */ + bitstatus = RESET; + } + } + /* Return the CAN_FLAG status */ + return bitstatus; +} + +/** + * @brief Clears the CAN's pending flags. + * @param CANx: where x can be 1 or 2 to select the CAN peripheral. + * @param CAN_FLAG: specifies the flag to clear. + * This parameter can be one of the following values: + * @arg CAN_FLAG_RQCP0: Request MailBox0 Flag + * @arg CAN_FLAG_RQCP1: Request MailBox1 Flag + * @arg CAN_FLAG_RQCP2: Request MailBox2 Flag + * @arg CAN_FLAG_FF0: FIFO 0 Full Flag + * @arg CAN_FLAG_FOV0: FIFO 0 Overrun Flag + * @arg CAN_FLAG_FF1: FIFO 1 Full Flag + * @arg CAN_FLAG_FOV1: FIFO 1 Overrun Flag + * @arg CAN_FLAG_WKU: Wake up Flag + * @arg CAN_FLAG_SLAK: Sleep acknowledge Flag + * @arg CAN_FLAG_LEC: Last error code Flag + * @retval None + */ +void CAN_ClearFlag(CAN_TypeDef* CANx, uint32_t CAN_FLAG) +{ + uint32_t flagtmp=0; + /* Check the parameters */ + assert_param(IS_CAN_ALL_PERIPH(CANx)); + assert_param(IS_CAN_CLEAR_FLAG(CAN_FLAG)); + + if (CAN_FLAG == CAN_FLAG_LEC) /* ESR register */ + { + /* Clear the selected CAN flags */ + CANx->ESR = (uint32_t)RESET; + } + else /* MSR or TSR or RF0R or RF1R */ + { + flagtmp = CAN_FLAG & 0x000FFFFF; + + if ((CAN_FLAG & CAN_FLAGS_RF0R)!=(uint32_t)RESET) + { + /* Receive Flags */ + CANx->RF0R = (uint32_t)(flagtmp); + } + else if ((CAN_FLAG & CAN_FLAGS_RF1R)!=(uint32_t)RESET) + { + /* Receive Flags */ + CANx->RF1R = (uint32_t)(flagtmp); + } + else if ((CAN_FLAG & CAN_FLAGS_TSR)!=(uint32_t)RESET) + { + /* Transmit Flags */ + CANx->TSR = (uint32_t)(flagtmp); + } + else /* If((CAN_FLAG & CAN_FLAGS_MSR)!=(uint32_t)RESET) */ + { + /* Operating mode Flags */ + CANx->MSR = (uint32_t)(flagtmp); + } + } +} + +/** + * @brief Checks whether the specified CANx interrupt has occurred or not. + * @param CANx: where x can be 1 or 2 to select the CAN peripheral. + * @param CAN_IT: specifies the CAN interrupt source to check. + * This parameter can be one of the following values: + * @arg CAN_IT_TME: Transmit mailbox empty Interrupt + * @arg CAN_IT_FMP0: FIFO 0 message pending Interrupt + * @arg CAN_IT_FF0: FIFO 0 full Interrupt + * @arg CAN_IT_FOV0: FIFO 0 overrun Interrupt + * @arg CAN_IT_FMP1: FIFO 1 message pending Interrupt + * @arg CAN_IT_FF1: FIFO 1 full Interrupt + * @arg CAN_IT_FOV1: FIFO 1 overrun Interrupt + * @arg CAN_IT_WKU: Wake-up Interrupt + * @arg CAN_IT_SLK: Sleep acknowledge Interrupt + * @arg CAN_IT_EWG: Error warning Interrupt + * @arg CAN_IT_EPV: Error passive Interrupt + * @arg CAN_IT_BOF: Bus-off Interrupt + * @arg CAN_IT_LEC: Last error code Interrupt + * @arg CAN_IT_ERR: Error Interrupt + * @retval The current state of CAN_IT (SET or RESET). + */ +ITStatus CAN_GetITStatus(CAN_TypeDef* CANx, uint32_t CAN_IT) +{ + ITStatus itstatus = RESET; + /* Check the parameters */ + assert_param(IS_CAN_ALL_PERIPH(CANx)); + assert_param(IS_CAN_IT(CAN_IT)); + + /* check the interrupt enable bit */ + if((CANx->IER & CAN_IT) != RESET) + { + /* in case the Interrupt is enabled, .... */ + switch (CAN_IT) + { + case CAN_IT_TME: + /* Check CAN_TSR_RQCPx bits */ + itstatus = CheckITStatus(CANx->TSR, CAN_TSR_RQCP0|CAN_TSR_RQCP1|CAN_TSR_RQCP2); + break; + case CAN_IT_FMP0: + /* Check CAN_RF0R_FMP0 bit */ + itstatus = CheckITStatus(CANx->RF0R, CAN_RF0R_FMP0); + break; + case CAN_IT_FF0: + /* Check CAN_RF0R_FULL0 bit */ + itstatus = CheckITStatus(CANx->RF0R, CAN_RF0R_FULL0); + break; + case CAN_IT_FOV0: + /* Check CAN_RF0R_FOVR0 bit */ + itstatus = CheckITStatus(CANx->RF0R, CAN_RF0R_FOVR0); + break; + case CAN_IT_FMP1: + /* Check CAN_RF1R_FMP1 bit */ + itstatus = CheckITStatus(CANx->RF1R, CAN_RF1R_FMP1); + break; + case CAN_IT_FF1: + /* Check CAN_RF1R_FULL1 bit */ + itstatus = CheckITStatus(CANx->RF1R, CAN_RF1R_FULL1); + break; + case CAN_IT_FOV1: + /* Check CAN_RF1R_FOVR1 bit */ + itstatus = CheckITStatus(CANx->RF1R, CAN_RF1R_FOVR1); + break; + case CAN_IT_WKU: + /* Check CAN_MSR_WKUI bit */ + itstatus = CheckITStatus(CANx->MSR, CAN_MSR_WKUI); + break; + case CAN_IT_SLK: + /* Check CAN_MSR_SLAKI bit */ + itstatus = CheckITStatus(CANx->MSR, CAN_MSR_SLAKI); + break; + case CAN_IT_EWG: + /* Check CAN_ESR_EWGF bit */ + itstatus = CheckITStatus(CANx->ESR, CAN_ESR_EWGF); + break; + case CAN_IT_EPV: + /* Check CAN_ESR_EPVF bit */ + itstatus = CheckITStatus(CANx->ESR, CAN_ESR_EPVF); + break; + case CAN_IT_BOF: + /* Check CAN_ESR_BOFF bit */ + itstatus = CheckITStatus(CANx->ESR, CAN_ESR_BOFF); + break; + case CAN_IT_LEC: + /* Check CAN_ESR_LEC bit */ + itstatus = CheckITStatus(CANx->ESR, CAN_ESR_LEC); + break; + case CAN_IT_ERR: + /* Check CAN_MSR_ERRI bit */ + itstatus = CheckITStatus(CANx->MSR, CAN_MSR_ERRI); + break; + default: + /* in case of error, return RESET */ + itstatus = RESET; + break; + } + } + else + { + /* in case the Interrupt is not enabled, return RESET */ + itstatus = RESET; + } + + /* Return the CAN_IT status */ + return itstatus; +} + +/** + * @brief Clears the CANx's interrupt pending bits. + * @param CANx: where x can be 1 or 2 to select the CAN peripheral. + * @param CAN_IT: specifies the interrupt pending bit to clear. + * This parameter can be one of the following values: + * @arg CAN_IT_TME: Transmit mailbox empty Interrupt + * @arg CAN_IT_FF0: FIFO 0 full Interrupt + * @arg CAN_IT_FOV0: FIFO 0 overrun Interrupt + * @arg CAN_IT_FF1: FIFO 1 full Interrupt + * @arg CAN_IT_FOV1: FIFO 1 overrun Interrupt + * @arg CAN_IT_WKU: Wake-up Interrupt + * @arg CAN_IT_SLK: Sleep acknowledge Interrupt + * @arg CAN_IT_EWG: Error warning Interrupt + * @arg CAN_IT_EPV: Error passive Interrupt + * @arg CAN_IT_BOF: Bus-off Interrupt + * @arg CAN_IT_LEC: Last error code Interrupt + * @arg CAN_IT_ERR: Error Interrupt + * @retval None + */ +void CAN_ClearITPendingBit(CAN_TypeDef* CANx, uint32_t CAN_IT) +{ + /* Check the parameters */ + assert_param(IS_CAN_ALL_PERIPH(CANx)); + assert_param(IS_CAN_CLEAR_IT(CAN_IT)); + + switch (CAN_IT) + { + case CAN_IT_TME: + /* Clear CAN_TSR_RQCPx (rc_w1)*/ + CANx->TSR = CAN_TSR_RQCP0|CAN_TSR_RQCP1|CAN_TSR_RQCP2; + break; + case CAN_IT_FF0: + /* Clear CAN_RF0R_FULL0 (rc_w1)*/ + CANx->RF0R = CAN_RF0R_FULL0; + break; + case CAN_IT_FOV0: + /* Clear CAN_RF0R_FOVR0 (rc_w1)*/ + CANx->RF0R = CAN_RF0R_FOVR0; + break; + case CAN_IT_FF1: + /* Clear CAN_RF1R_FULL1 (rc_w1)*/ + CANx->RF1R = CAN_RF1R_FULL1; + break; + case CAN_IT_FOV1: + /* Clear CAN_RF1R_FOVR1 (rc_w1)*/ + CANx->RF1R = CAN_RF1R_FOVR1; + break; + case CAN_IT_WKU: + /* Clear CAN_MSR_WKUI (rc_w1)*/ + CANx->MSR = CAN_MSR_WKUI; + break; + case CAN_IT_SLK: + /* Clear CAN_MSR_SLAKI (rc_w1)*/ + CANx->MSR = CAN_MSR_SLAKI; + break; + case CAN_IT_EWG: + /* Clear CAN_MSR_ERRI (rc_w1) */ + CANx->MSR = CAN_MSR_ERRI; + /* @note the corresponding Flag is cleared by hardware depending on the CAN Bus status*/ + break; + case CAN_IT_EPV: + /* Clear CAN_MSR_ERRI (rc_w1) */ + CANx->MSR = CAN_MSR_ERRI; + /* @note the corresponding Flag is cleared by hardware depending on the CAN Bus status*/ + break; + case CAN_IT_BOF: + /* Clear CAN_MSR_ERRI (rc_w1) */ + CANx->MSR = CAN_MSR_ERRI; + /* @note the corresponding Flag is cleared by hardware depending on the CAN Bus status*/ + break; + case CAN_IT_LEC: + /* Clear LEC bits */ + CANx->ESR = RESET; + /* Clear CAN_MSR_ERRI (rc_w1) */ + CANx->MSR = CAN_MSR_ERRI; + break; + case CAN_IT_ERR: + /*Clear LEC bits */ + CANx->ESR = RESET; + /* Clear CAN_MSR_ERRI (rc_w1) */ + CANx->MSR = CAN_MSR_ERRI; + /* @note BOFF, EPVF and EWGF Flags are cleared by hardware depending on the CAN Bus status*/ + break; + default: + break; + } +} + /** + * @} + */ + +/** + * @brief Checks whether the CAN interrupt has occurred or not. + * @param CAN_Reg: specifies the CAN interrupt register to check. + * @param It_Bit: specifies the interrupt source bit to check. + * @retval The new state of the CAN Interrupt (SET or RESET). + */ +static ITStatus CheckITStatus(uint32_t CAN_Reg, uint32_t It_Bit) +{ + ITStatus pendingbitstatus = RESET; + + if ((CAN_Reg & It_Bit) != (uint32_t)RESET) + { + /* CAN_IT is set */ + pendingbitstatus = SET; + } + else + { + /* CAN_IT is reset */ + pendingbitstatus = RESET; + } + return pendingbitstatus; +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_comp.c b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_comp.c new file mode 100755 index 0000000000..847a05f2bd --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_comp.c @@ -0,0 +1,507 @@ +/** + ****************************************************************************** + * @file stm32f30x_comp.c + * @author MCD Application Team + * @version V1.2.3 + * @date 10-July-2015 + * @brief This file provides firmware functions to manage the following + * functionalities of the 7 analog comparators (COMP1, COMP2...COMP7) peripheral: + * + Comparators configuration + * + Window mode control + * + @verbatim + + ============================================================================== + ##### COMP Peripheral features ##### + ============================================================================== + [..] + The device integrates 7 analog comparators COMP1, COMP2...COMP7: + (#) The non inverting input and inverting input can be set to GPIO pins + as shown in table1. COMP Inputs below. + + (#) The COMP output is internally is available using COMP_GetOutputLevel() + and can be set on GPIO pins. Refer to table 2. COMP Outputs below. + + (#) The COMP output can be redirected to embedded timers (TIM1, TIM2, TIM3...) + Refer to table 3. COMP Outputs redirection to embedded timers below. + + (#) The comparators COMP1 and COMP2, COMP3 and COMP4, COMP5 and COMP6 can be combined in window + mode and only COMP1, COMP3 and COMP5 non inverting input can be used as non-inverting input. + + (#) The seven comparators have interrupt capability with wake-up + from Sleep and Stop modes (through the EXTI controller): + (++) COMP1 is internally connected to EXTI Line 21 + (++) COMP2 is internally connected to EXTI Line 22 + (++) COMP3 is internally connected to EXTI Line 29 + (++) COMP4 is internally connected to EXTI Line 30 + (++) COMP5 is internally connected to EXTI Line 31 + (++) COMP6 is internally connected to EXTI Line 32 + (++) COMP7 is internally connected to EXTI Line 33 + + [..] Table 1. COMP Inputs + +------------------------------------------------------------------------------------------+ + | | | COMP1 | COMP2 | COMP3 | COMP4 | COMP5 | COMP6 | COMP7 | + |-----------------|----------------|---------------|---------------------------------------| + | | 1/4 VREFINT | OK | OK | OK | OK | OK | OK | OK | + | | 1/2 VREFINT | OK | OK | OK | OK | OK | OK | OK | + | | 3/4 VREFINT | OK | OK | OK | OK | OK | OK | OK | + | Inverting Input | VREFINT | OK | OK | OK | OK | OK | OK | OK | + | | DAC1 OUT1(PA4) | OK | OK | OK | OK | OK | OK | OK | + | | DAC1 OUT2(PA5) | OK | OK | OK | OK | OK | OK | OK | + | | IO1 | PA0 | PA2 | PD15 | PE8 | PD13 | PD10 | PC0 | + | | IO2 | --- | --- | PB12 | PB2 | PB10 | PB15 | --- | + | | DAC2 OUT1(PA6) | --- | OK | --- | OK | --- | OK | --- | + |-----------------|----------------|-------|-------|-------|-------|-------|-------|-------| + | Non Inverting | IO1 | PA1 | PA7 | PB14 | PB0 | PD12 | PD11 | PA0 | + | Input | IO2 | --- | PA3 | PD14 | PE7 | PB13 | PB11 | PC1 | + +------------------------------------------------------------------------------------------+ + + [..] Table 2. COMP Outputs + +-------------------------------------------------------+ + | COMP1 | COMP2 | COMP3 | COMP4 | COMP5 | COMP6 | COMP7 | + |-------|-------|-------|-------|-------|-------|-------| + | PA0 | PA2 | PB1 | PC8 | PC7 | PA10 | PC2 | + | PF4 | PA7 | --- | PA8 | PA9 | PC6 | --- | + | PA6 | PA12 | --- | --- | --- | --- | --- | + | PA11 | PB9 | --- | --- | --- | --- | --- | + | PB8 | --- | --- | --- | --- | --- | --- | + +-------------------------------------------------------+ + + [..] Table 3. COMP Outputs redirection to embedded timers + +----------------------------------------------------------------------------------------------------------------------+ + | COMP1 | COMP2 | COMP3 | COMP4 | COMP5 | COMP6 | COMP7 | + |----------------|----------------|----------------|----------------|----------------|----------------|----------------| + | TIM1 BKIN | TIM1 BKIN | TIM1 BKIN | TIM1 BKIN | TIM1 BKIN | TIM1 BKIN | TIM1 BKIN | + | | | | | | | | + | TIM1 BKIN2 | TIM1 BKIN2 | TIM1 BKIN2 | TIM1 BKIN2 | TIM1 BKIN2 | TIM1 BKIN2 | TIM1 BKIN2 | + | | | | | | | | + | TIM8 BKIN | TIM8 BKIN | TIM8 BKIN | TIM8 BKIN | TIM8 BKIN | TIM8 BKIN | TIM8 BKIN | + | | | | | | | | + | TIM8 BKIN2 | TIM8 BKIN2 | TIM8 BKIN2 | TIM8 BKIN2 | TIM8 BKIN2 | TIM8 BKIN2 | TIM8 BKIN2 | + | | | | | | | | + | TIM1 BKIN2 | TIM1 BKIN2 | TIM1 BKIN2 | TIM1 BKIN2 | TIM1 BKIN2 | TIM1 BKIN2 | TIM1 BKIN2 | + | + | + | + | + | + | + | + | + | TIM8BKIN2 | TIM8BKIN2 | TIM8BKIN2 | TIM8BKIN2 | TIM8BKIN2 | TIM8BKIN2 | TIM8BKIN2 | + | | | | | | | | + | TIM1 OCREFCLR | TIM1 OCREFCLR | TIM1 OCREFCLR | TIM8 OCREFCLR | TIM8 OCREFCLR | TIM8 OCREFCLR | TIM1 OCREFCLR | + | | | | | | | | + | TIM1 IC1 | TIM1 IC1 | TIM2 OCREFCLR | TIM3 IC3 | TIM2 IC1 | TIM2 IC2 | TIM8 OCREFCLR | + | | | | | | | | + | TIM2 IC4 | TIM2 IC4 | TIM3 IC2 | TIM3 OCREFCLR | TIM3 OCREFCLR | TIM2 OCREFCLR | TIM2 IC3 | + | | | | | | | | + | TIM2 OCREFCLR | TIM2 OCREFCLR | TIM4 IC1 | TIM4 IC2 | TIM4 IC3 | TIM16 OCREFCLR| TIM1 IC2 | + | | | | | | | | + | TIM3 IC1 | TIM3 IC1 | TIM15 IC1 | TIM15 OCREFCLR| TIM16 BKIN | TIM16 IC1 | TIM17 OCREFCLR| + | | | | | | | | + | TIM3 OCREFCLR | TIM3 OCREFCLR | TIM15 BKIN | TIM15 IC2 | TIM17 IC1 | TIM4 IC4 | TIM17 BKIN | + +----------------------------------------------------------------------------------------------------------------------+ + + [..] Table 4. COMP Outputs blanking sources + +----------------------------------------------------------------------------------------------------------------------+ + | COMP1 | COMP2 | COMP3 | COMP4 | COMP5 | COMP6 | COMP7 | + |----------------|----------------|----------------|----------------|----------------|----------------|----------------| + | TIM1 OC5 | TIM1 OC5 | TIM1 OC5 | TIM3 OC4 | TIM3 OC3 | TIM2 OC4 | TIM1 OC5 | + | | | | | | | | + | TIM2 OC3 | TIM2 OC3 | -------- | TIM8 OC5 | TIM8 OC5 | TIM8 OC5 | TIM8 OC5 | + | | | | | | | | + | TIM3 OC3 | TIM3 OC3 | TIM2 OC4 | TIM15 OC1 | TIM8 BKIN | TIM15 OC2 | TIM15 OC2 | + | | | | | | | | + +----------------------------------------------------------------------------------------------------------------------+ + + + ##### How to use this driver ##### + ============================================================================== + [..] + This driver provides functions to configure and program the Comparators + of all STM32F30x devices. + + To use the comparator, perform the following steps: + + (#) Enable the SYSCFG APB clock to get write access to comparator + register using RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); + + (#) Configure the comparator input in analog mode using GPIO_Init() + + (#) Configure the comparator output in alternate function mode + using GPIO_Init() and use GPIO_PinAFConfig() function to map the + comparator output to the GPIO pin + + (#) Configure the comparator using COMP_Init() function: + (++) Select the inverting input + (++) Select the non-inverting input + (++) Select the output polarity + (++) Select the output redirection + (++) Select the hysteresis level + (++) Select the power mode + + (#) Enable the comparator using COMP_Cmd() function + + (#) If required enable the COMP interrupt by configuring and enabling + EXTI line in Interrupt mode and selecting the desired sensitivity + level using EXTI_Init() function. After that enable the comparator + interrupt vector using NVIC_Init() function. + + @endverbatim + * + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f30x_comp.h" + +/** @addtogroup STM32F30x_StdPeriph_Driver + * @{ + */ + +/** @defgroup COMP + * @brief COMP driver modules + * @{ + */ + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +/* CSR register Mask */ +#define COMP_CSR_CLEAR_MASK ((uint32_t)0x00000003) + +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/* Private function prototypes -----------------------------------------------*/ +/* Private functions ---------------------------------------------------------*/ + +/** @defgroup COMP_Private_Functions + * @{ + */ + +/** @defgroup COMP_Group1 Initialization and Configuration functions + * @brief Initialization and Configuration functions + * +@verbatim + =============================================================================== + ##### Initialization and Configuration functions ##### + =============================================================================== + +@endverbatim + * @{ + */ + +/** + * @brief Deinitializes COMP peripheral registers to their default reset values. + * @note Deinitialization can't be performed if the COMP configuration is locked. + * To unlock the configuration, perform a system reset. + * @param COMP_Selection: the selected comparator. + * This parameter can be COMP_Selection_COMPx where x can be 1 to 7 + * to select the COMP peripheral. + * @param None + * @retval None + */ +void COMP_DeInit(uint32_t COMP_Selection) +{ + /*!< Set COMP_CSR register to reset value */ + *(__IO uint32_t *) (COMP_BASE + COMP_Selection) = ((uint32_t)0x00000000); +} + +/** + * @brief Initializes the COMP peripheral according to the specified parameters + * in COMP_InitStruct + * @note If the selected comparator is locked, initialization can't be performed. + * To unlock the configuration, perform a system reset. + * @note By default, PA1 is selected as COMP1 non inverting input. + * To use PA4 as COMP1 non inverting input call COMP_SwitchCmd() after COMP_Init() + * @param COMP_Selection: the selected comparator. + * This parameter can be COMP_Selection_COMPx where x can be 1 to 7 + * to select the COMP peripheral. + * @param COMP_InitStruct: pointer to an COMP_InitTypeDef structure that contains + * the configuration information for the specified COMP peripheral. + * - COMP_InvertingInput specifies the inverting input of COMP + * - COMP_NonInvertingInput specifies the non inverting input of COMP + * - COMP_Output connect COMP output to selected timer + * input (Input capture / Output Compare Reference Clear / Break Input) + * - COMP_BlankingSrce specifies the blanking source of COMP + * - COMP_OutputPol select output polarity + * - COMP_Hysteresis configures COMP hysteresis value + * - COMP_Mode configures COMP power mode + * @note COMP_Hysteresis must be configured only for STM32F303xC. Otherwise, COMP_Hysteresis + * must be kept at reset value(COMP_Hysteresis_No). + * @note COMP_Mode field is only applicable for STM32F303xC devices. + * @retval None + */ +void COMP_Init(uint32_t COMP_Selection, COMP_InitTypeDef* COMP_InitStruct) +{ + uint32_t tmpreg = 0; + + /* Check the parameters */ + assert_param(IS_COMP_ALL_PERIPH(COMP_Selection)); + assert_param(IS_COMP_INVERTING_INPUT(COMP_InitStruct->COMP_InvertingInput)); + assert_param(IS_COMP_NONINVERTING_INPUT(COMP_InitStruct->COMP_NonInvertingInput)); + assert_param(IS_COMP_OUTPUT(COMP_InitStruct->COMP_Output)); + assert_param(IS_COMP_BLANKING_SOURCE(COMP_InitStruct->COMP_BlankingSrce)); + assert_param(IS_COMP_OUTPUT_POL(COMP_InitStruct->COMP_OutputPol)); + assert_param(IS_COMP_HYSTERESIS(COMP_InitStruct->COMP_Hysteresis)); + assert_param(IS_COMP_MODE(COMP_InitStruct->COMP_Mode)); + + /*!< Get the COMPx_CSR register value */ + tmpreg = *(__IO uint32_t *) (COMP_BASE + COMP_Selection); + + /*!< Clear the COMP1SW1, COMPxINSEL, COMPxOUTSEL, COMPxPOL, COMPxHYST and COMPxMODE bits */ + tmpreg &= (uint32_t) (COMP_CSR_CLEAR_MASK); + + /*!< Configure COMP: inverting input, output redirection, hysteresis value and power mode */ + /*!< Set COMPxINSEL bits according to COMP_InitStruct->COMP_InvertingInput value */ + /*!< Set COMPxNONINSEL bits according to COMP_InitStruct->COMP_NonInvertingInput value */ + /*!< Set COMPxBLANKING bits according to COMP_InitStruct->COMP_BlankingSrce value */ + /*!< Set COMPxOUTSEL bits according to COMP_InitStruct->COMP_Output value */ + /*!< Set COMPxPOL bit according to COMP_InitStruct->COMP_OutputPol value */ + /*!< Set COMPxHYST bits according to COMP_InitStruct->COMP_Hysteresis value */ + /*!< Set COMPxMODE bits according to COMP_InitStruct->COMP_Mode value */ + tmpreg |= (uint32_t)(COMP_InitStruct->COMP_InvertingInput | COMP_InitStruct->COMP_NonInvertingInput | + COMP_InitStruct->COMP_Output | COMP_InitStruct->COMP_OutputPol | COMP_InitStruct->COMP_BlankingSrce | + COMP_InitStruct->COMP_Hysteresis | COMP_InitStruct->COMP_Mode); + + /*!< Write to COMPx_CSR register */ + *(__IO uint32_t *) (COMP_BASE + COMP_Selection) = tmpreg; +} + +/** + * @brief Fills each COMP_InitStruct member with its default value. + * @param COMP_InitStruct: pointer to an COMP_InitTypeDef structure which will + * be initialized. + * @retval None + */ +void COMP_StructInit(COMP_InitTypeDef* COMP_InitStruct) +{ + COMP_InitStruct->COMP_InvertingInput = COMP_InvertingInput_1_4VREFINT; + COMP_InitStruct->COMP_NonInvertingInput = COMP_NonInvertingInput_IO1; + COMP_InitStruct->COMP_Output = COMP_Output_None; + COMP_InitStruct->COMP_BlankingSrce = COMP_BlankingSrce_None; + COMP_InitStruct->COMP_OutputPol = COMP_OutputPol_NonInverted; + COMP_InitStruct->COMP_Hysteresis = COMP_Hysteresis_No; + COMP_InitStruct->COMP_Mode = COMP_Mode_UltraLowPower; +} + +/** + * @brief Enable or disable the COMP peripheral. + * @note If the selected comparator is locked, enable/disable can't be performed. + * To unlock the configuration, perform a system reset. + * @param COMP_Selection: the selected comparator. + * This parameter can be COMP_Selection_COMPx where x can be 1 to 7 + * to select the COMP peripheral. + * @param NewState: new state of the COMP peripheral. + * This parameter can be: ENABLE or DISABLE. + * When enabled, the comparator compares the non inverting input with + * the inverting input and the comparison result is available + * on comparator output. + * When disabled, the comparator doesn't perform comparison and the + * output level is low. + * @retval None + */ +void COMP_Cmd(uint32_t COMP_Selection, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_COMP_ALL_PERIPH(COMP_Selection)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable the selected COMPx peripheral */ + *(__IO uint32_t *) (COMP_BASE + COMP_Selection) |= (uint32_t) (COMP_CSR_COMPxEN); + } + else + { + /* Disable the selected COMP peripheral */ + *(__IO uint32_t *) (COMP_BASE + COMP_Selection) &= (uint32_t)(~COMP_CSR_COMPxEN); + } +} + +/** + * @brief Close or Open the SW1 switch. + * @note If the COMP1 is locked, Close/Open the SW1 switch can't be performed. + * To unlock the configuration, perform a system reset. + * @note This switch is solely intended to redirect signals onto high + * impedance input, such as COMP1 non-inverting input (highly resistive switch) + * @param NewState: New state of the analog switch. + * This parameter can be + * ENABLE so the SW1 is closed; PA1 is connected to PA4 + * or DISABLE so the SW1 switch is open; PA1 is disconnected from PA4 + * @retval None + */ +void COMP_SwitchCmd(uint32_t COMP_Selection, FunctionalState NewState) +{ + /* Check the parameter */ + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Close SW1 switch */ + *(__IO uint32_t *) (COMP_BASE + COMP_Selection) |= (uint32_t) (COMP_CSR_COMP1SW1); + } + else + { + /* Open SW1 switch */ + *(__IO uint32_t *) (COMP_BASE + COMP_Selection) &= (uint32_t)(~COMP_CSR_COMP1SW1); + } +} + +/** + * @brief Return the output level (high or low) of the selected comparator. + * The output level depends on the selected polarity. + * If the polarity is not inverted: + * - Comparator output is low when the non-inverting input is at a lower + * voltage than the inverting input + * - Comparator output is high when the non-inverting input is at a higher + * voltage than the inverting input + * If the polarity is inverted: + * - Comparator output is high when the non-inverting input is at a lower + * voltage than the inverting input + * - Comparator output is low when the non-inverting input is at a higher + * voltage than the inverting input + * @param COMP_Selection: the selected comparator. + * This parameter can be COMP_Selection_COMPx where x can be 1 to 7 + * to select the COMP peripheral. + * @retval Returns the selected comparator output level: low or high. + * + */ +uint32_t COMP_GetOutputLevel(uint32_t COMP_Selection) +{ + uint32_t compout = 0x0; + + /* Check the parameters */ + assert_param(IS_COMP_ALL_PERIPH(COMP_Selection)); + + /* Check if selected comparator output is high */ + if ((*(__IO uint32_t *) (COMP_BASE + COMP_Selection) & (COMP_CSR_COMPxOUT)) != 0) + { + compout = COMP_OutputLevel_High; + } + else + { + compout = COMP_OutputLevel_Low; + } + + /* Return the comparator output level */ + return (uint32_t)(compout); +} + +/** + * @} + */ + +/** @defgroup COMP_Group2 Window mode control function + * @brief Window mode control function + * +@verbatim + =============================================================================== + ##### Window mode control function ##### + =============================================================================== + +@endverbatim + * @{ + */ + +/** + * @brief Enables or disables the window mode. + * Window mode for comparators makes use of two comparators: + * COMP1 and COM2, COMP3 and COMP4, COMP5 and COMP6. + * In window mode, COMPx and COMPx-1 (where x can be 2, 4 or 6) + * non inverting inputs are connected together and only COMPx-1 non + * inverting input can be used. + * e.g When window mode enabled for COMP4, COMP3 non inverting input (PB14 or PD14) + * is to be used. + * @note If the COMPx is locked, ENABLE/DISABLE the window mode can't be performed. + * To unlock the configuration, perform a system reset. + * @param COMP_Selection: the selected comparator. + * This parameter can be COMP_Selection_COMPx where x can be 2, 4 or 6 + * to select the COMP peripheral. + * param NewState: new state of the window mode. + * This parameter can be ENABLE or DISABLE. + * When enbaled, COMPx and COMPx-1 non inverting inputs are connected together. + * When disabled, COMPx and COMPx-1 non inverting inputs are disconnected. + * @retval None + */ +void COMP_WindowCmd(uint32_t COMP_Selection, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_FUNCTIONAL_STATE(NewState)); + assert_param(IS_COMP_WINDOW(COMP_Selection)); + + if (NewState != DISABLE) + { + /* Enable the window mode */ + *(__IO uint32_t *) (COMP_BASE + COMP_Selection) |= (uint32_t) COMP_CSR_COMPxWNDWEN; + } + else + { + /* Disable the window mode */ + *(__IO uint32_t *) (COMP_BASE + COMP_Selection) &= (uint32_t)(~COMP_CSR_COMPxWNDWEN); + } +} + +/** + * @} + */ + +/** @defgroup COMP_Group3 COMP configuration locking function + * @brief COMP1, COMP2,...COMP7 configuration locking function + * COMP1, COMP2,...COMP7 configuration can be locked each separately. + * Unlocking is performed by system reset. + * +@verbatim + =============================================================================== + ##### Configuration Lock function ##### + =============================================================================== + +@endverbatim + * @{ + */ + +/** + * @brief Lock the selected comparator (COMP1/COMP2) configuration. + * @note Locking the configuration means that all control bits are read-only. + * To unlock the comparator configuration, perform a system reset. + * @param COMP_Selection: the selected comparator. + * This parameter can be COMP_Selection_COMPx where x can be 1 to 7 + * to select the COMP peripheral. + * @retval None + */ +void COMP_LockConfig(uint32_t COMP_Selection) +{ + /* Check the parameter */ + assert_param(IS_COMP_ALL_PERIPH(COMP_Selection)); + + /* Set the lock bit corresponding to selected comparator */ + *(__IO uint32_t *) (COMP_BASE + COMP_Selection) |= (uint32_t) (COMP_CSR_COMPxLOCK); +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_crc.c b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_crc.c new file mode 100755 index 0000000000..ea9d5e9d87 --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_crc.c @@ -0,0 +1,354 @@ +/** + ****************************************************************************** + * @file stm32f30x_crc.c + * @author MCD Application Team + * @version V1.2.3 + * @date 10-July-2015 + * @brief This file provides firmware functions to manage the following + * functionalities of CRC computation unit peripheral: + * + Configuration of the CRC computation unit + * + CRC computation of one/many 32-bit data + * + CRC Independent register (IDR) access + * + @verbatim + + =============================================================================== + ##### How to use this driver ##### + =============================================================================== + [..] + (#) Enable CRC AHB clock using RCC_AHBPeriphClockCmd(RCC_AHBPeriph_CRC, ENABLE) + function. + (#) Select the polynomial size: 7-bit, 8-bit, 16-bit or 32-bit. + (#) Set the polynomial coefficients using CRC_SetPolynomial(); + (#) If required, select the reverse operation on input data + using CRC_ReverseInputDataSelect(); + (#) If required, enable the reverse operation on output data + using CRC_ReverseOutputDataCmd(Enable); + (#) If required, set the initialization remainder value using + CRC_SetInitRegister(); + (#) use CRC_CalcCRC() function to compute the CRC of a 32-bit data + or use CRC_CalcBlockCRC() function to compute the CRC if a 32-bit + data buffer. + + @endverbatim + + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2014 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f30x_crc.h" + +/** @addtogroup STM32F30x_StdPeriph_Driver + * @{ + */ + +/** @defgroup CRC + * @brief CRC driver modules + * @{ + */ + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/* Private function prototypes -----------------------------------------------*/ +/* Private functions ---------------------------------------------------------*/ + +/** @defgroup CRC_Private_Functions + * @{ + */ + +/** @defgroup CRC_Group1 Configuration of the CRC computation unit functions + * @brief Configuration of the CRC computation unit functions + * +@verbatim + =============================================================================== + ##### CRC configuration functions ##### + =============================================================================== + +@endverbatim + * @{ + */ + +/** + * @brief Deinitializes CRC peripheral registers to their default reset values. + * @param None + * @retval None + */ +void CRC_DeInit(void) +{ + /* Set DR register to reset value */ + CRC->DR = 0xFFFFFFFF; + /* Set the POL register to the reset value: 0x04C11DB7 */ + CRC->POL = 0x04C11DB7; + /* Reset IDR register */ + CRC->IDR = 0x00; + /* Set INIT register to reset value */ + CRC->INIT = 0xFFFFFFFF; + /* Reset the CRC calculation unit */ + CRC->CR = CRC_CR_RESET; +} + +/** + * @brief Resets the CRC calculation unit and sets INIT register content in DR register. + * @param None + * @retval None + */ +void CRC_ResetDR(void) +{ + /* Reset CRC generator */ + CRC->CR |= CRC_CR_RESET; +} + +/** + * @brief Selects the polynomial size. + * @param CRC_PolSize: Specifies the polynomial size. + * This parameter can be: + * @arg CRC_PolSize_7: 7-bit polynomial for CRC calculation + * @arg CRC_PolSize_8: 8-bit polynomial for CRC calculation + * @arg CRC_PolSize_16: 16-bit polynomial for CRC calculation + * @arg CRC_PolSize_32: 32-bit polynomial for CRC calculation + * @retval None + */ +void CRC_PolynomialSizeSelect(uint32_t CRC_PolSize) +{ + uint32_t tmpcr = 0; + + /* Check the parameter */ + assert_param(IS_CRC_POL_SIZE(CRC_PolSize)); + + /* Get CR register value */ + tmpcr = CRC->CR; + + /* Reset POL_SIZE bits */ + tmpcr &= (uint32_t)~((uint32_t)CRC_CR_POLSIZE); + /* Set the polynomial size */ + tmpcr |= (uint32_t)CRC_PolSize; + + /* Write to CR register */ + CRC->CR = (uint32_t)tmpcr; +} + +/** + * @brief Selects the reverse operation to be performed on input data. + * @param CRC_ReverseInputData: Specifies the reverse operation on input data. + * This parameter can be: + * @arg CRC_ReverseInputData_No: No reverse operation is performed + * @arg CRC_ReverseInputData_8bits: reverse operation performed on 8 bits + * @arg CRC_ReverseInputData_16bits: reverse operation performed on 16 bits + * @arg CRC_ReverseInputData_32bits: reverse operation performed on 32 bits + * @retval None + */ +void CRC_ReverseInputDataSelect(uint32_t CRC_ReverseInputData) +{ + uint32_t tmpcr = 0; + + /* Check the parameter */ + assert_param(IS_CRC_REVERSE_INPUT_DATA(CRC_ReverseInputData)); + + /* Get CR register value */ + tmpcr = CRC->CR; + + /* Reset REV_IN bits */ + tmpcr &= (uint32_t)~((uint32_t)CRC_CR_REV_IN); + /* Set the reverse operation */ + tmpcr |= (uint32_t)CRC_ReverseInputData; + + /* Write to CR register */ + CRC->CR = (uint32_t)tmpcr; +} + +/** + * @brief Enables or disable the reverse operation on output data. + * The reverse operation on output data is performed on 32-bit. + * @param NewState: new state of the reverse operation on output data. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void CRC_ReverseOutputDataCmd(FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable reverse operation on output data */ + CRC->CR |= CRC_CR_REV_OUT; + } + else + { + /* Disable reverse operation on output data */ + CRC->CR &= (uint32_t)~((uint32_t)CRC_CR_REV_OUT); + } +} + +/** + * @brief Initializes the INIT register. + * @note After resetting CRC calculation unit, CRC_InitValue is stored in DR register + * @param CRC_InitValue: Programmable initial CRC value + * @retval None + */ +void CRC_SetInitRegister(uint32_t CRC_InitValue) +{ + CRC->INIT = CRC_InitValue; +} + +/** + * @brief Initializes the polynomial coefficients. + * @param CRC_Pol: Polynomial to be used for CRC calculation. + * @retval None + */ +void CRC_SetPolynomial(uint32_t CRC_Pol) +{ + CRC->POL = CRC_Pol; +} + +/** + * @} + */ + +/** @defgroup CRC_Group2 CRC computation of one/many 32-bit data functions + * @brief CRC computation of one/many 32-bit data functions + * +@verbatim + =============================================================================== + ##### CRC computation functions ##### + =============================================================================== + +@endverbatim + * @{ + */ + +/** + * @brief Computes the 32-bit CRC of a given data word(32-bit). + * @param CRC_Data: data word(32-bit) to compute its CRC + * @retval 32-bit CRC + */ +uint32_t CRC_CalcCRC(uint32_t CRC_Data) +{ + CRC->DR = CRC_Data; + + return (CRC->DR); +} + +/** + * @brief Computes the 16-bit CRC of a given 16-bit data. + * @param CRC_Data: data half-word(16-bit) to compute its CRC + * @retval 16-bit CRC + */ +uint32_t CRC_CalcCRC16bits(uint16_t CRC_Data) +{ + *(uint16_t*)(CRC_BASE) = (uint16_t) CRC_Data; + + return (CRC->DR); +} + +/** + * @brief Computes the 8-bit CRC of a given 8-bit data. + * @param CRC_Data: 8-bit data to compute its CRC + * @retval 8-bit CRC + */ +uint32_t CRC_CalcCRC8bits(uint8_t CRC_Data) +{ + *(uint8_t*)(CRC_BASE) = (uint8_t) CRC_Data; + + return (CRC->DR); +} + +/** + * @brief Computes the 32-bit CRC of a given buffer of data word(32-bit). + * @param pBuffer: pointer to the buffer containing the data to be computed + * @param BufferLength: length of the buffer to be computed + * @retval 32-bit CRC + */ +uint32_t CRC_CalcBlockCRC(uint32_t pBuffer[], uint32_t BufferLength) +{ + uint32_t index = 0; + + for(index = 0; index < BufferLength; index++) + { + CRC->DR = pBuffer[index]; + } + return (CRC->DR); +} + +/** + * @brief Returns the current CRC value. + * @param None + * @retval 32-bit CRC + */ +uint32_t CRC_GetCRC(void) +{ + return (CRC->DR); +} + +/** + * @} + */ + +/** @defgroup CRC_Group3 CRC Independent Register (IDR) access functions + * @brief CRC Independent Register (IDR) access (write/read) functions + * +@verbatim + =============================================================================== + ##### CRC Independent Register (IDR) access functions ##### + =============================================================================== + +@endverbatim + * @{ + */ + +/** + * @brief Stores an 8-bit data in the Independent Data(ID) register. + * @param CRC_IDValue: 8-bit value to be stored in the ID register + * @retval None + */ +void CRC_SetIDRegister(uint8_t CRC_IDValue) +{ + CRC->IDR = CRC_IDValue; +} + +/** + * @brief Returns the 8-bit data stored in the Independent Data(ID) register + * @param None + * @retval 8-bit value of the ID register + */ +uint8_t CRC_GetIDRegister(void) +{ + return (CRC->IDR); +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_dac.c b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_dac.c new file mode 100755 index 0000000000..971ee88b95 --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_dac.c @@ -0,0 +1,754 @@ +/** + ****************************************************************************** + * @file stm32f30x_dac.c + * @author MCD Application Team + * @version V1.2.3 + * @date 10-July-2015 + * @brief This file provides firmware functions to manage the following + * functionalities of the Digital-to-Analog Converter (DAC) peripheral: + * + DAC channels configuration: trigger, output buffer, data format + * + DMA management + * + Interrupts and flags management + * + @verbatim + + =============================================================================== + ##### DAC Peripheral features ##### + =============================================================================== + [..] The device integrates two 12-bit Digital Analog Converters that can + be used independently or simultaneously (dual mode): + (#) DAC1 integrates two DAC channels: + (++) DAC1 channel 1 with DAC1_OUT1 as output + (++) DAC1 channel 2 with DAC1_OUT2 as output + (++) The two channels can be used independently or simultaneously (dual mode) + + (#) DAC2 integrates only one channel DAC2 channel 1 with DAC2_OUT1 as output + + [..] Digital to Analog conversion can be non-triggered using DAC_Trigger_None + and DAC_OUT1/DAC_OUT2 is available once writing to DHRx register using + DAC_SetChannel1Data()/DAC_SetChannel2Data. + + [..] Digital to Analog conversion can be triggered by: + (#) External event: EXTI Line 9 (any GPIOx_Pin9) using DAC_Trigger_Ext_IT9. + The used pin (GPIOx_Pin9) must be configured in input mode. + + (#) Timers TRGO: TIM2, TIM8/TIM3, TIM4, TIM6, TIM7, and TIM15 + (DAC_Trigger_T2_TRGO, DAC_Trigger_T4_TRGO...) + The timer TRGO event should be selected using TIM_SelectOutputTrigger() + (++) To trigger DAC conversions by TIM3 instead of TIM8 follow + this sequence: + (+++) Enable SYSCFG APB clock by calling + RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); + (+++) Select DAC_Trigger_T3_TRGO when calling DAC_Init() + (+++) Remap the DAC trigger from TIM8 to TIM3 by calling + SYSCFG_TriggerRemapConfig(SYSCFG_TriggerRemap_DACTIM3, ENABLE) + (#) Software using DAC_Trigger_Software + + [..] Each DAC channel integrates an output buffer that can be used to + reduce the output impedance, and to drive external loads directly + without having to add an external operational amplifier. + To enable, the output buffer use + DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable; + + [..] Refer to the device datasheet for more details about output impedance + value with and without output buffer. + + [..] Both DAC channels can be used to generate: + (+) Noise wave using DAC_WaveGeneration_Noise + (+) Triangle wave using DAC_WaveGeneration_Triangle + + [..] Wave generation can be disabled using DAC_WaveGeneration_None + + [..] The DAC data format can be: + (+) 8-bit right alignment using DAC_Align_8b_R + (+) 12-bit left alignment using DAC_Align_12b_L + (+) 12-bit right alignment using DAC_Align_12b_R + + [..] The analog output voltage on each DAC channel pin is determined + by the following equation: + (+) DAC_OUTx = VREF+ * DOR / 4095 with DOR is the Data Output Register. + VREF+ is the input voltage reference (refer to the device datasheet) + e.g. To set DAC_OUT1 to 0.7V, use DAC_SetChannel1Data(DAC_Align_12b_R, 868); + Assuming that VREF+ = 3.3, DAC_OUT1 = (3.3 * 868) / 4095 = 0.7V + + [..] A DMA1 request can be generated when an external trigger (but not + a software trigger) occurs if DMA1 requests are enabled using + DAC_DMACmd() + DMA1 requests are mapped as following: + (+) DAC channel1 is mapped on DMA1 channel3 which must be already + configured + (+) DAC channel2 is mapped on DMA1 channel4 which must be already + configured + + ##### How to use this driver ##### + =============================================================================== + [..] + (+) Enable DAC APB1 clock to get write access to DAC registers + using RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE) + + (+) Configure DACx_OUTy (DAC1_OUT1: PA4, DAC1_OUT2: PA5, DAC2_OUT1: PA6) + in analog mode. + + (+) Configure the DAC channel using DAC_Init() + + (+) Enable the DAC channel using DAC_Cmd() + + @endverbatim + + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f30x_dac.h" +#include "stm32f30x_rcc.h" + +/** @addtogroup STM32F30x_StdPeriph_Driver + * @{ + */ + +/** @defgroup DAC + * @brief DAC driver modules + * @{ + */ + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ + +/* CR register Mask */ +#define CR_CLEAR_MASK ((uint32_t)0x00000FFE) + +/* DAC Dual Channels SWTRIG masks */ +#define DUAL_SWTRIG_SET ((uint32_t)0x00000003) +#define DUAL_SWTRIG_RESET ((uint32_t)0xFFFFFFFC) + +/* DHR registers offsets */ +#define DHR12R1_OFFSET ((uint32_t)0x00000008) +#define DHR12R2_OFFSET ((uint32_t)0x00000014) +#define DHR12RD_OFFSET ((uint32_t)0x00000020) + +/* DOR register offset */ +#define DOR_OFFSET ((uint32_t)0x0000002C) + +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/* Private function prototypes -----------------------------------------------*/ +/* Private functions ---------------------------------------------------------*/ + +/** @defgroup DAC_Private_Functions + * @{ + */ + +/** @defgroup DAC_Group1 DAC channels configuration + * @brief DAC channels configuration: trigger, output buffer, data format + * +@verbatim + =============================================================================== + ##### DAC channels configuration: trigger, output buffer, data format ##### + =============================================================================== + +@endverbatim + * @{ + */ + +/** + * @brief Deinitializes the DAC peripheral registers to their default reset values. + * @param DACx: where x can be 1 or 2 to select the DAC peripheral. + * @retval None + */ +void DAC_DeInit(DAC_TypeDef* DACx) +{ + /* Check the parameters */ + assert_param(IS_DAC_ALL_PERIPH(DACx)); + + if (DACx == DAC1) + { + /* Enable DAC1 reset state */ + RCC_APB1PeriphResetCmd(RCC_APB1Periph_DAC1, ENABLE); + /* Release DAC1 from reset state */ + RCC_APB1PeriphResetCmd(RCC_APB1Periph_DAC1, DISABLE); + } + else + { + /* Enable DAC2 reset state */ + RCC_APB1PeriphResetCmd(RCC_APB1Periph_DAC2, ENABLE); + /* Release DAC2 from reset state */ + RCC_APB1PeriphResetCmd(RCC_APB1Periph_DAC2, DISABLE); + } +} + +/** + * @brief Initializes the DAC peripheral according to the specified + * parameters in the DAC_InitStruct. + * @param DACx: where x can be 1 or 2 to select the DAC peripheral. + * @param DAC_Channel: the selected DAC channel. + * This parameter can be one of the following values: + * @arg DAC_Channel_1: DAC Channel1 selected + * @arg DAC_Channel_2: DAC Channel2 selected + * @param DAC_InitStruct: pointer to a DAC_InitTypeDef structure that + * contains the configuration information for the specified DAC channel. + * @retval None + */ +void DAC_Init(DAC_TypeDef* DACx, uint32_t DAC_Channel, DAC_InitTypeDef* DAC_InitStruct) +{ + uint32_t tmpreg1 = 0, tmpreg2 = 0; + + /* Check the DAC parameters */ + assert_param(IS_DAC_ALL_PERIPH(DACx)); + assert_param(IS_DAC_TRIGGER(DAC_InitStruct->DAC_Trigger)); + assert_param(IS_DAC_GENERATE_WAVE(DAC_InitStruct->DAC_WaveGeneration)); + assert_param(IS_DAC_LFSR_UNMASK_TRIANGLE_AMPLITUDE(DAC_InitStruct->DAC_LFSRUnmask_TriangleAmplitude)); + assert_param(IS_DAC_BUFFER_SWITCH_STATE(DAC_InitStruct->DAC_Buffer_Switch)); + +/*---------------------------- DAC CR Configuration --------------------------*/ + /* Get the DAC CR value */ + tmpreg1 = DACx->CR; + /* Clear BOFFx, TENx, TSELx, WAVEx and MAMPx bits */ + tmpreg1 &= ~(CR_CLEAR_MASK << DAC_Channel); + /* Configure for the selected DAC channel: buffer output, trigger, wave generation, + mask/amplitude for wave generation */ + + /* Set TSELx and TENx bits according to DAC_Trigger value */ + /* Set WAVEx bits according to DAC_WaveGeneration value */ + /* Set MAMPx bits according to DAC_LFSRUnmask_TriangleAmplitude value */ + /* Set BOFFx OUTENx bit according to DAC_Buffer_Switch value */ + tmpreg2 = (DAC_InitStruct->DAC_Trigger | DAC_InitStruct->DAC_WaveGeneration | + DAC_InitStruct->DAC_LFSRUnmask_TriangleAmplitude | DAC_InitStruct->DAC_Buffer_Switch); + + /* Calculate CR register value depending on DAC_Channel */ + tmpreg1 |= tmpreg2 << DAC_Channel; + /* Write to DAC CR */ + DACx->CR = tmpreg1; +} + +/** + * @brief Fills each DAC_InitStruct member with its default value. + * @param DAC_InitStruct: pointer to a DAC_InitTypeDef structure which will + * be initialized. + * @retval None + */ +void DAC_StructInit(DAC_InitTypeDef* DAC_InitStruct) +{ +/*--------------- Reset DAC init structure parameters values -----------------*/ + /* Initialize the DAC_Trigger member */ + DAC_InitStruct->DAC_Trigger = DAC_Trigger_None; + /* Initialize the DAC_WaveGeneration member */ + DAC_InitStruct->DAC_WaveGeneration = DAC_WaveGeneration_None; + /* Initialize the DAC_LFSRUnmask_TriangleAmplitude member */ + DAC_InitStruct->DAC_LFSRUnmask_TriangleAmplitude = DAC_LFSRUnmask_Bit0; + /* Initialize the DAC_Buffer_Switch member */ + DAC_InitStruct->DAC_Buffer_Switch = DAC_BufferSwitch_Enable; +} + +/** + * @brief Enables or disables the specified DAC channel. + * @param DACx: where x can be 1 or 2 to select the DAC peripheral. + * @param DAC_Channel: The selected DAC channel. + * This parameter can be one of the following values: + * @arg DAC_Channel_1: DAC Channel1 selected + * @arg DAC_Channel_2: DAC Channel2 selected + * @param NewState: new state of the DAC channel. + * This parameter can be: ENABLE or DISABLE. + * @note When the DAC channel is enabled the trigger source can no more + * be modified. + * @retval None + */ +void DAC_Cmd(DAC_TypeDef* DACx, uint32_t DAC_Channel, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_DAC_ALL_PERIPH(DACx)); + assert_param(IS_DAC_CHANNEL(DAC_Channel)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable the selected DAC channel */ + DACx->CR |= (DAC_CR_EN1 << DAC_Channel); + } + else + { + /* Disable the selected DAC channel */ + DACx->CR &= (~(DAC_CR_EN1 << DAC_Channel)); + } +} + +/** + * @brief Enables or disables the selected DAC channel software trigger. + * @param DACx: where x can be 1 or 2 to select the DAC peripheral. + * @param DAC_Channel: the selected DAC channel. + * This parameter can be one of the following values: + * @arg DAC_Channel_1: DAC Channel1 selected + * @arg DAC_Channel_2: DAC Channel2 selected + * @param NewState: new state of the selected DAC channel software trigger. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void DAC_SoftwareTriggerCmd(DAC_TypeDef* DACx, uint32_t DAC_Channel, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_DAC_ALL_PERIPH(DACx)); + assert_param(IS_DAC_CHANNEL(DAC_Channel)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable software trigger for the selected DAC channel */ + DACx->SWTRIGR |= (uint32_t)DAC_SWTRIGR_SWTRIG1 << (DAC_Channel >> 4); + } + else + { + /* Disable software trigger for the selected DAC channel */ + DACx->SWTRIGR &= ~((uint32_t)DAC_SWTRIGR_SWTRIG1 << (DAC_Channel >> 4)); + } +} + +/** + * @brief Enables or disables simultaneously the two DAC channels software + * triggers. + * @param DACx: where x can be 1 to select the DAC1 peripheral. + * @note Dual trigger is not applicable for DAC2 (DAC2 integrates one channel). + * @param NewState: new state of the DAC channels software triggers. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void DAC_DualSoftwareTriggerCmd(DAC_TypeDef* DACx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_DAC_LIST1_PERIPH(DACx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable software trigger for both DAC channels */ + DACx->SWTRIGR |= DUAL_SWTRIG_SET; + } + else + { + /* Disable software trigger for both DAC channels */ + DACx->SWTRIGR &= DUAL_SWTRIG_RESET; + } +} + +/** + * @brief Enables or disables the selected DAC channel wave generation. + * @param DACx: where x can be 1 to select the DAC1 peripheral. + * @note Wave generation is not available in DAC2. + * @param DAC_Channel: the selected DAC channel. + * This parameter can be one of the following values: + * @arg DAC_Channel_1: DAC Channel1 selected + * @arg DAC_Channel_2: DAC Channel2 selected + * @param DAC_Wave: Specifies the wave type to enable or disable. + * This parameter can be one of the following values: + * @arg DAC_Wave_Noise: noise wave generation + * @arg DAC_Wave_Triangle: triangle wave generation + * @param NewState: new state of the selected DAC channel wave generation. + * This parameter can be: ENABLE or DISABLE. + * @note + * @retval None + */ +void DAC_WaveGenerationCmd(DAC_TypeDef* DACx, uint32_t DAC_Channel, uint32_t DAC_Wave, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_DAC_LIST1_PERIPH(DACx)); + assert_param(IS_DAC_CHANNEL(DAC_Channel)); + assert_param(IS_DAC_WAVE(DAC_Wave)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable the selected wave generation for the selected DAC channel */ + DACx->CR |= DAC_Wave << DAC_Channel; + } + else + { + /* Disable the selected wave generation for the selected DAC channel */ + DACx->CR &= ~(DAC_Wave << DAC_Channel); + } +} + +/** + * @brief Set the specified data holding register value for DAC channel1. + * @param DACx: where x can be 1 or 2 to select the DAC peripheral. + * @param DAC_Align: Specifies the data alignment for DAC channel1. + * This parameter can be one of the following values: + * @arg DAC_Align_8b_R: 8bit right data alignment selected + * @arg DAC_Align_12b_L: 12bit left data alignment selected + * @arg DAC_Align_12b_R: 12bit right data alignment selected + * @param Data: Data to be loaded in the selected data holding register. + * @retval None + */ +void DAC_SetChannel1Data(DAC_TypeDef* DACx, uint32_t DAC_Align, uint16_t Data) +{ + __IO uint32_t tmp = 0; + + /* Check the parameters */ + assert_param(IS_DAC_ALL_PERIPH(DACx)); + assert_param(IS_DAC_ALIGN(DAC_Align)); + assert_param(IS_DAC_DATA(Data)); + + tmp = (uint32_t)DACx; + tmp += DHR12R1_OFFSET + DAC_Align; + + /* Set the DAC channel1 selected data holding register */ + *(__IO uint32_t *) tmp = Data; +} + +/** + * @brief Set the specified data holding register value for DAC channel2. + * @param DACx: where x can be 1 to select the DAC peripheral. + * @note This function is available only for DAC1. + * @param DAC_Align: Specifies the data alignment for DAC channel2. + * This parameter can be one of the following values: + * @arg DAC_Align_8b_R: 8bit right data alignment selected + * @arg DAC_Align_12b_L: 12bit left data alignment selected + * @arg DAC_Align_12b_R: 12bit right data alignment selected + * @param Data : Data to be loaded in the selected data holding register. + * @retval None + */ +void DAC_SetChannel2Data(DAC_TypeDef* DACx, uint32_t DAC_Align, uint16_t Data) +{ + __IO uint32_t tmp = 0; + + /* Check the parameters */ + assert_param(IS_DAC_LIST1_PERIPH(DACx)); + assert_param(IS_DAC_ALIGN(DAC_Align)); + assert_param(IS_DAC_DATA(Data)); + + tmp = (uint32_t)DACx; + tmp += DHR12R2_OFFSET + DAC_Align; + + /* Set the DAC channel2 selected data holding register */ + *(__IO uint32_t *)tmp = Data; +} + +/** + * @brief Set the specified data holding register value for dual channel DAC. + * @param DACx: where x can be 1 to select the DAC peripheral. + * @note This function isn't applicable for DAC2. + * @param DAC_Align: Specifies the data alignment for dual channel DAC. + * This parameter can be one of the following values: + * @arg DAC_Align_8b_R: 8bit right data alignment selected + * @arg DAC_Align_12b_L: 12bit left data alignment selected + * @arg DAC_Align_12b_R: 12bit right data alignment selected + * @param Data2: Data for DAC Channel2 to be loaded in the selected data + * holding register. + * @param Data1: Data for DAC Channel1 to be loaded in the selected data + * holding register. + * @note In dual mode, a unique register access is required to write in both + * DAC channels at the same time. + * @retval None + */ +void DAC_SetDualChannelData(DAC_TypeDef* DACx, uint32_t DAC_Align, uint16_t Data2, uint16_t Data1) +{ + uint32_t data = 0, tmp = 0; + + /* Check the parameters */ + assert_param(IS_DAC_LIST1_PERIPH(DACx)); + assert_param(IS_DAC_ALIGN(DAC_Align)); + assert_param(IS_DAC_DATA(Data1)); + assert_param(IS_DAC_DATA(Data2)); + + /* Calculate and set dual DAC data holding register value */ + if (DAC_Align == DAC_Align_8b_R) + { + data = ((uint32_t)Data2 << 8) | Data1; + } + else + { + data = ((uint32_t)Data2 << 16) | Data1; + } + + tmp = (uint32_t)DACx; + tmp += DHR12RD_OFFSET + DAC_Align; + + /* Set the dual DAC selected data holding register */ + *(__IO uint32_t *)tmp = data; +} + +/** + * @brief Returns the last data output value of the selected DAC channel. + * @param DACx: where x can be 1 or 2 to select the DAC peripheral. + * @param DAC_Channel: the selected DAC channel. + * This parameter can be one of the following values: + * @arg DAC_Channel_1: DAC Channel1 selected + * @arg DAC_Channel_2: DAC Channel2 selected + * @retval The selected DAC channel data output value. + */ +uint16_t DAC_GetDataOutputValue(DAC_TypeDef* DACx, uint32_t DAC_Channel) +{ + __IO uint32_t tmp = 0; + + /* Check the parameters */ + assert_param(IS_DAC_ALL_PERIPH(DACx)); + assert_param(IS_DAC_CHANNEL(DAC_Channel)); + + tmp = (uint32_t) DACx; + tmp += DOR_OFFSET + ((uint32_t)DAC_Channel >> 2); + + /* Returns the DAC channel data output register value */ + return (uint16_t) (*(__IO uint32_t*) tmp); +} + +/** + * @} + */ + +/** @defgroup DAC_Group2 DMA management functions + * @brief DMA management functions + * +@verbatim + =============================================================================== + ##### DMA management functions ##### + =============================================================================== + +@endverbatim + * @{ + */ + +/** + * @brief Enables or disables the specified DAC channel DMA request. + * When enabled DMA1 is generated when an external trigger (EXTI Line9, + * TIM2, TIM4, TIM6, TIM7 or TIM9 but not a software trigger) occurs + * @param DACx: where x can be 1 or 2 to select the DAC peripheral. + * @param DAC_Channel: the selected DAC channel. + * This parameter can be one of the following values: + * @arg DAC_Channel_1: DAC Channel1 selected + * @arg DAC_Channel_2: DAC Channel2 selected + * @param NewState: new state of the selected DAC channel DMA request. + * This parameter can be: ENABLE or DISABLE. + * @note The DAC channel1 (channel2) is mapped on DMA1 channel3 (channel4) which + * must be already configured. + * @retval None + */ +void DAC_DMACmd(DAC_TypeDef* DACx, uint32_t DAC_Channel, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_DAC_ALL_PERIPH(DACx)); + assert_param(IS_DAC_CHANNEL(DAC_Channel)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable the selected DAC channel DMA request */ + DACx->CR |= (DAC_CR_DMAEN1 << DAC_Channel); + } + else + { + /* Disable the selected DAC channel DMA request */ + DACx->CR &= (~(DAC_CR_DMAEN1 << DAC_Channel)); + } +} + +/** + * @} + */ + +/** @defgroup DAC_Group3 Interrupts and flags management functions + * @brief Interrupts and flags management functions + * +@verbatim + =============================================================================== + ##### Interrupts and flags management functions ##### + =============================================================================== + +@endverbatim + * @{ + */ + +/** + * @brief Enables or disables the specified DAC interrupts. + * @param DACx: where x can be 1 or 2 to select the DAC peripheral. + * @param DAC_Channel: the selected DAC channel. + * This parameter can be one of the following values: + * @arg DAC_Channel_1: DAC Channel1 selected + * @arg DAC_Channel_2: DAC Channel2 selected + * @param DAC_IT: specifies the DAC interrupt sources to be enabled or disabled. + * This parameter can be: + * @arg DAC_IT_DMAUDR: DMA underrun interrupt mask + * @note The DMA underrun occurs when a second external trigger arrives before + * the acknowledgement for the first external trigger is received (first request). + * @param NewState: new state of the specified DAC interrupts. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void DAC_ITConfig(DAC_TypeDef* DACx, uint32_t DAC_Channel, uint32_t DAC_IT, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_DAC_ALL_PERIPH(DACx)); + assert_param(IS_DAC_CHANNEL(DAC_Channel)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + assert_param(IS_DAC_IT(DAC_IT)); + + if (NewState != DISABLE) + { + /* Enable the selected DAC interrupts */ + DACx->CR |= (DAC_IT << DAC_Channel); + } + else + { + /* Disable the selected DAC interrupts */ + DACx->CR &= (~(uint32_t)(DAC_IT << DAC_Channel)); + } +} + +/** + * @brief Checks whether the specified DAC flag is set or not. + * @param DACx: where x can be 1 or 2 to select the DAC peripheral. + * @param DAC_Channel: thee selected DAC channel. + * This parameter can be one of the following values: + * @arg DAC_Channel_1: DAC Channel1 selected + * @arg DAC_Channel_2: DAC Channel2 selected + * @param DAC_FLAG: specifies the flag to check. + * This parameter can be: + * @arg DAC_FLAG_DMAUDR: DMA underrun flag + * @note The DMA underrun occurs when a second external trigger arrives before + * the acknowledgement for the first external trigger is received (first request). + * @retval The new state of DAC_FLAG (SET or RESET). + */ +FlagStatus DAC_GetFlagStatus(DAC_TypeDef* DACx, uint32_t DAC_Channel, uint32_t DAC_FLAG) +{ + FlagStatus bitstatus = RESET; + + /* Check the parameters */ + assert_param(IS_DAC_ALL_PERIPH(DACx)); + assert_param(IS_DAC_CHANNEL(DAC_Channel)); + assert_param(IS_DAC_FLAG(DAC_FLAG)); + + /* Check the status of the specified DAC flag */ + if ((DACx->SR & (DAC_FLAG << DAC_Channel)) != (uint8_t)RESET) + { + /* DAC_FLAG is set */ + bitstatus = SET; + } + else + { + /* DAC_FLAG is reset */ + bitstatus = RESET; + } + /* Return the DAC_FLAG status */ + return bitstatus; +} + +/** + * @brief Clears the DAC channel's pending flags. + * @param DACx: where x can be 1 or 2 to select the DAC peripheral. + * @param DAC_Channel: the selected DAC channel. + * This parameter can be one of the following values: + * @arg DAC_Channel_1: DAC Channel1 selected + * @arg DAC_Channel_2: DAC Channel2 selected + * @param DAC_FLAG: specifies the flag to clear. + * This parameter can be: + * @arg DAC_FLAG_DMAUDR: DMA underrun flag + * @retval None + */ +void DAC_ClearFlag(DAC_TypeDef* DACx, uint32_t DAC_Channel, uint32_t DAC_FLAG) +{ + /* Check the parameters */ + assert_param(IS_DAC_ALL_PERIPH(DACx)); + assert_param(IS_DAC_CHANNEL(DAC_Channel)); + assert_param(IS_DAC_FLAG(DAC_FLAG)); + + /* Clear the selected DAC flags */ + DACx->SR = (DAC_FLAG << DAC_Channel); +} + +/** + * @brief Checks whether the specified DAC interrupt has occurred or not. + * @param DACx: where x can be 1 or 2 to select the DAC peripheral. + * @param DAC_Channel: the selected DAC channel. + * This parameter can be one of the following values: + * @arg DAC_Channel_1: DAC Channel1 selected + * @arg DAC_Channel_2: DAC Channel2 selected + * @param DAC_IT: specifies the DAC interrupt source to check. + * This parameter can be: + * @arg DAC_IT_DMAUDR: DMA underrun interrupt mask + * @note The DMA underrun occurs when a second external trigger arrives before + * the acknowledgement for the first external trigger is received (first request). + * @retval The new state of DAC_IT (SET or RESET). + */ +ITStatus DAC_GetITStatus(DAC_TypeDef* DACx, uint32_t DAC_Channel, uint32_t DAC_IT) +{ + ITStatus bitstatus = RESET; + uint32_t enablestatus = 0; + + /* Check the parameters */ + assert_param(IS_DAC_ALL_PERIPH(DACx)); + assert_param(IS_DAC_CHANNEL(DAC_Channel)); + assert_param(IS_DAC_IT(DAC_IT)); + + /* Get the DAC_IT enable bit status */ + enablestatus = (DACx->CR & (DAC_IT << DAC_Channel)) ; + + /* Check the status of the specified DAC interrupt */ + if (((DACx->SR & (DAC_IT << DAC_Channel)) != (uint32_t)RESET) && enablestatus) + { + /* DAC_IT is set */ + bitstatus = SET; + } + else + { + /* DAC_IT is reset */ + bitstatus = RESET; + } + /* Return the DAC_IT status */ + return bitstatus; +} + +/** + * @brief Clears the DAC channel's interrupt pending bits. + * @param DACx: where x can be 1 or 2 to select the DAC peripheral. + * @param DAC_Channel: the selected DAC channel. + * This parameter can be one of the following values: + * @arg DAC_Channel_1: DAC Channel1 selected + * @arg DAC_Channel_2: DAC Channel2 selected + * @param DAC_IT: specifies the DAC interrupt pending bit to clear. + * This parameter can be the following values: + * @arg DAC_IT_DMAUDR: DMA underrun interrupt mask + * @retval None + */ +void DAC_ClearITPendingBit(DAC_TypeDef* DACx, uint32_t DAC_Channel, uint32_t DAC_IT) +{ + /* Check the parameters */ + assert_param(IS_DAC_ALL_PERIPH(DACx)); + assert_param(IS_DAC_CHANNEL(DAC_Channel)); + assert_param(IS_DAC_IT(DAC_IT)); + + /* Clear the selected DAC interrupt pending bits */ + DACx->SR = (DAC_IT << DAC_Channel); +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + diff --git a/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_dbgmcu.c b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_dbgmcu.c new file mode 100755 index 0000000000..7887905b20 --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_dbgmcu.c @@ -0,0 +1,216 @@ +/** + ****************************************************************************** + * @file stm32f30x_dbgmcu.c + * @author MCD Application Team + * @version V1.2.3 + * @date 10-July-2015 + * @brief This file provides firmware functions to manage the following + * functionalities of the Debug MCU (DBGMCU) peripheral: + * + Device and Revision ID management + * + Peripherals Configuration + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f30x_dbgmcu.h" + +/** @addtogroup STM32F30x_StdPeriph_Driver + * @{ + */ + +/** @defgroup DBGMCU + * @brief DBGMCU driver modules + * @{ + */ + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +#define IDCODE_DEVID_MASK ((uint32_t)0x00000FFF) + +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/* Private function prototypes -----------------------------------------------*/ +/* Private functions ---------------------------------------------------------*/ + +/** @defgroup DBGMCU_Private_Functions + * @{ + */ + +/** @defgroup DBGMCU_Group1 Device and Revision ID management functions + * @brief Device and Revision ID management functions + * +@verbatim + ============================================================================== + ##### Device and Revision ID management functions ##### + ============================================================================== + +@endverbatim + * @{ + */ + +/** + * @brief Returns the device revision identifier. + * @param None + * @retval Device revision identifier + */ +uint32_t DBGMCU_GetREVID(void) +{ + return(DBGMCU->IDCODE >> 16); +} + +/** + * @brief Returns the device identifier. + * @param None + * @retval Device identifier + */ +uint32_t DBGMCU_GetDEVID(void) +{ + return(DBGMCU->IDCODE & IDCODE_DEVID_MASK); +} + +/** + * @} + */ + +/** @defgroup DBGMCU_Group2 Peripherals Configuration functions + * @brief Peripherals Configuration + * +@verbatim + ============================================================================== + ##### Peripherals Configuration functions ##### + ============================================================================== + +@endverbatim + * @{ + */ + +/** + * @brief Configures low power mode behavior when the MCU is in Debug mode. + * @param DBGMCU_Periph: specifies the low power mode. + * This parameter can be any combination of the following values: + * @arg DBGMCU_SLEEP: Keep debugger connection during SLEEP mode. + * @arg DBGMCU_STOP: Keep debugger connection during STOP mode. + * @arg DBGMCU_STANDBY: Keep debugger connection during STANDBY mode. + * @param NewState: new state of the specified low power mode in Debug mode. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void DBGMCU_Config(uint32_t DBGMCU_Periph, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_DBGMCU_PERIPH(DBGMCU_Periph)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + if (NewState != DISABLE) + { + DBGMCU->CR |= DBGMCU_Periph; + } + else + { + DBGMCU->CR &= ~DBGMCU_Periph; + } +} + +/** + * @brief Configures APB1 peripheral behavior when the MCU is in Debug mode. + * @param DBGMCU_Periph: specifies the APB1 peripheral. + * This parameter can be any combination of the following values: + * @arg DBGMCU_TIM2_STOP: TIM2 counter stopped when Core is halted. + * @arg DBGMCU_TIM3_STOP: TIM3 counter stopped when Core is halted. + * @arg DBGMCU_TIM4_STOP: TIM4 counter stopped when Core is halted. + * @arg DBGMCU_TIM6_STOP: TIM6 counter stopped when Core is halted. + * @arg DBGMCU_TIM7_STOP: TIM7 counter stopped when Core is halted. + * @arg DBGMCU_RTC_STOP: RTC Calendar and Wakeup counter are stopped when + * Core is halted. + * @arg DBGMCU_WWDG_STOP: Debug WWDG stopped when Core is halted. + * @arg DBGMCU_IWDG_STOP: Debug IWDG stopped when Core is halted. + * @arg DBGMCU_I2C1_SMBUS_TIMEOUT: I2C1 SMBUS timeout mode stopped when + * Core is halted. + * @arg DBGMCU_I2C2_SMBUS_TIMEOUT: I2C2 SMBUS timeout mode stopped when + * Core is halted. + * @arg DBGMCU_CAN1_STOP: Debug CAN2 stopped when Core is halted. + * @arg DBGMCU_I2C3_SMBUS_TIMEOUT: I2C3 SMBUS timeout mode stopped when + * Core is halted. + * @param NewState: new state of the specified APB1 peripheral in Debug mode. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void DBGMCU_APB1PeriphConfig(uint32_t DBGMCU_Periph, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_DBGMCU_APB1PERIPH(DBGMCU_Periph)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + DBGMCU->APB1FZ |= DBGMCU_Periph; + } + else + { + DBGMCU->APB1FZ &= ~DBGMCU_Periph; + } +} + +/** + * @brief Configures APB2 peripheral behavior when the MCU is in Debug mode. + * @param DBGMCU_Periph: specifies the APB2 peripheral. + * This parameter can be any combination of the following values: + * @arg DBGMCU_TIM1_STOP: TIM1 counter stopped when Core is halted. + * @arg DBGMCU_TIM8_STOP: TIM8 counter stopped when Core is halted. + * @arg DBGMCU_TIM15_STOP: TIM15 counter stopped when Core is halted. + * @arg DBGMCU_TIM16_STOP: TIM16 counter stopped when Core is halted. + * @arg DBGMCU_TIM17_STOP: TIM17 counter stopped when Core is halted. + * @arg DBGMCU_TIM20_STOP: TIM20 counter stopped when Core is halted. + * @param NewState: new state of the specified APB2 peripheral in Debug mode. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void DBGMCU_APB2PeriphConfig(uint32_t DBGMCU_Periph, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_DBGMCU_APB2PERIPH(DBGMCU_Periph)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + DBGMCU->APB2FZ |= DBGMCU_Periph; + } + else + { + DBGMCU->APB2FZ &= ~DBGMCU_Periph; + } +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_dma.c b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_dma.c new file mode 100755 index 0000000000..11bf7252a3 --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_dma.c @@ -0,0 +1,866 @@ +/** + ****************************************************************************** + * @file stm32f30x_dma.c + * @author MCD Application Team + * @version V1.2.3 + * @date 10-July-2015 + * @brief This file provides firmware functions to manage the following + * functionalities of the Direct Memory Access controller (DMA): + * + Initialization and Configuration + * + Data Counter + * + Interrupts and flags management + * + @verbatim + + =============================================================================== + ##### How to use this driver ##### + =============================================================================== + [..] + (#) Enable The DMA controller clock using + RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE) function for DMA1 or + using RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE) function for DMA2. + (#) Enable and configure the peripheral to be connected to the DMA channel + (except for internal SRAM / FLASH memories: no initialization is necessary). + (#) For a given Channel, program the Source and Destination addresses, + the transfer Direction, the Buffer Size, the Peripheral and Memory + Incrementation mode and Data Size, the Circular or Normal mode, + the channel transfer Priority and the Memory-to-Memory transfer + mode (if needed) using the DMA_Init() function. + (#) Enable the NVIC and the corresponding interrupt(s) using the function + DMA_ITConfig() if you need to use DMA interrupts. + (#) Enable the DMA channel using the DMA_Cmd() function. + (#) Activate the needed channel Request using PPP_DMACmd() function for + any PPP peripheral except internal SRAM and FLASH (ie. SPI, USART ...) + The function allowing this operation is provided in each PPP peripheral + driver (ie. SPI_DMACmd for SPI peripheral). + (#) Optionally, you can configure the number of data to be transferred + when the channel is disabled (ie. after each Transfer Complete event + or when a Transfer Error occurs) using the function DMA_SetCurrDataCounter(). + And you can get the number of remaining data to be transferred using + the function DMA_GetCurrDataCounter() at run time (when the DMA channel is + enabled and running). + (#) To control DMA events you can use one of the following two methods: + (##) Check on DMA channel flags using the function DMA_GetFlagStatus(). + (##) Use DMA interrupts through the function DMA_ITConfig() at initialization + phase and DMA_GetITStatus() function into interrupt routines in + communication phase. + After checking on a flag you should clear it using DMA_ClearFlag() + function. And after checking on an interrupt event you should + clear it using DMA_ClearITPendingBit() function. + + @endverbatim + + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f30x_dma.h" + +/** @addtogroup STM32F30x_StdPeriph_Driver + * @{ + */ + +/** @defgroup DMA + * @brief DMA driver modules + * @{ + */ + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +#define CCR_CLEAR_MASK ((uint32_t)0xFFFF800F) /* DMA Channel config registers Masks */ +#define FLAG_Mask ((uint32_t)0x10000000) /* DMA2 FLAG mask */ + + +/* DMA1 Channelx interrupt pending bit masks */ +#define DMA1_CHANNEL1_IT_MASK ((uint32_t)(DMA_ISR_GIF1 | DMA_ISR_TCIF1 | DMA_ISR_HTIF1 | DMA_ISR_TEIF1)) +#define DMA1_CHANNEL2_IT_MASK ((uint32_t)(DMA_ISR_GIF2 | DMA_ISR_TCIF2 | DMA_ISR_HTIF2 | DMA_ISR_TEIF2)) +#define DMA1_CHANNEL3_IT_MASK ((uint32_t)(DMA_ISR_GIF3 | DMA_ISR_TCIF3 | DMA_ISR_HTIF3 | DMA_ISR_TEIF3)) +#define DMA1_CHANNEL4_IT_MASK ((uint32_t)(DMA_ISR_GIF4 | DMA_ISR_TCIF4 | DMA_ISR_HTIF4 | DMA_ISR_TEIF4)) +#define DMA1_CHANNEL5_IT_MASK ((uint32_t)(DMA_ISR_GIF5 | DMA_ISR_TCIF5 | DMA_ISR_HTIF5 | DMA_ISR_TEIF5)) +#define DMA1_CHANNEL6_IT_MASK ((uint32_t)(DMA_ISR_GIF6 | DMA_ISR_TCIF6 | DMA_ISR_HTIF6 | DMA_ISR_TEIF6)) +#define DMA1_CHANNEL7_IT_MASK ((uint32_t)(DMA_ISR_GIF7 | DMA_ISR_TCIF7 | DMA_ISR_HTIF7 | DMA_ISR_TEIF7)) + +/* DMA2 Channelx interrupt pending bit masks */ +#define DMA2_CHANNEL1_IT_MASK ((uint32_t)(DMA_ISR_GIF1 | DMA_ISR_TCIF1 | DMA_ISR_HTIF1 | DMA_ISR_TEIF1)) +#define DMA2_CHANNEL2_IT_MASK ((uint32_t)(DMA_ISR_GIF2 | DMA_ISR_TCIF2 | DMA_ISR_HTIF2 | DMA_ISR_TEIF2)) +#define DMA2_CHANNEL3_IT_MASK ((uint32_t)(DMA_ISR_GIF3 | DMA_ISR_TCIF3 | DMA_ISR_HTIF3 | DMA_ISR_TEIF3)) +#define DMA2_CHANNEL4_IT_MASK ((uint32_t)(DMA_ISR_GIF4 | DMA_ISR_TCIF4 | DMA_ISR_HTIF4 | DMA_ISR_TEIF4)) +#define DMA2_CHANNEL5_IT_MASK ((uint32_t)(DMA_ISR_GIF5 | DMA_ISR_TCIF5 | DMA_ISR_HTIF5 | DMA_ISR_TEIF5)) + +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/* Private function prototypes -----------------------------------------------*/ +/* Private functions ---------------------------------------------------------*/ + +/** @defgroup DMA_Private_Functions + * @{ + */ + +/** @defgroup DMA_Group1 Initialization and Configuration functions + * @brief Initialization and Configuration functions + * +@verbatim + =============================================================================== + ##### Initialization and Configuration functions ##### + =============================================================================== + [..] This subsection provides functions allowing to initialize the DMA channel + source and destination addresses, incrementation and data sizes, transfer + direction, buffer size, circular/normal mode selection, memory-to-memory + mode selection and channel priority value. + [..] The DMA_Init() function follows the DMA configuration procedures as described + in reference manual (RM00316). + +@endverbatim + * @{ + */ + +/** + * @brief Deinitializes the DMAy Channelx registers to their default reset + * values. + * @param DMAy_Channelx: where y can be 1 or 2 to select the DMA and + * x can be 1 to 7 for DMA1 and 1 to 5 for DMA2 to select the DMA Channel. + * @retval None + */ +void DMA_DeInit(DMA_Channel_TypeDef* DMAy_Channelx) +{ + /* Check the parameters */ + assert_param(IS_DMA_ALL_PERIPH(DMAy_Channelx)); + + /* Disable the selected DMAy Channelx */ + DMAy_Channelx->CCR &= (uint16_t)(~DMA_CCR_EN); + + /* Reset DMAy Channelx control register */ + DMAy_Channelx->CCR = 0; + + /* Reset DMAy Channelx remaining bytes register */ + DMAy_Channelx->CNDTR = 0; + + /* Reset DMAy Channelx peripheral address register */ + DMAy_Channelx->CPAR = 0; + + /* Reset DMAy Channelx memory address register */ + DMAy_Channelx->CMAR = 0; + + if (DMAy_Channelx == DMA1_Channel1) + { + /* Reset interrupt pending bits for DMA1 Channel1 */ + DMA1->IFCR |= DMA1_CHANNEL1_IT_MASK; + } + else if (DMAy_Channelx == DMA1_Channel2) + { + /* Reset interrupt pending bits for DMA1 Channel2 */ + DMA1->IFCR |= DMA1_CHANNEL2_IT_MASK; + } + else if (DMAy_Channelx == DMA1_Channel3) + { + /* Reset interrupt pending bits for DMA1 Channel3 */ + DMA1->IFCR |= DMA1_CHANNEL3_IT_MASK; + } + else if (DMAy_Channelx == DMA1_Channel4) + { + /* Reset interrupt pending bits for DMA1 Channel4 */ + DMA1->IFCR |= DMA1_CHANNEL4_IT_MASK; + } + else if (DMAy_Channelx == DMA1_Channel5) + { + /* Reset interrupt pending bits for DMA1 Channel5 */ + DMA1->IFCR |= DMA1_CHANNEL5_IT_MASK; + } + else if (DMAy_Channelx == DMA1_Channel6) + { + /* Reset interrupt pending bits for DMA1 Channel6 */ + DMA1->IFCR |= DMA1_CHANNEL6_IT_MASK; + } + else if (DMAy_Channelx == DMA1_Channel7) + { + /* Reset interrupt pending bits for DMA1 Channel7 */ + DMA1->IFCR |= DMA1_CHANNEL7_IT_MASK; + } + else if (DMAy_Channelx == DMA2_Channel1) + { + /* Reset interrupt pending bits for DMA2 Channel1 */ + DMA2->IFCR |= DMA2_CHANNEL1_IT_MASK; + } + else if (DMAy_Channelx == DMA2_Channel2) + { + /* Reset interrupt pending bits for DMA2 Channel2 */ + DMA2->IFCR |= DMA2_CHANNEL2_IT_MASK; + } + else if (DMAy_Channelx == DMA2_Channel3) + { + /* Reset interrupt pending bits for DMA2 Channel3 */ + DMA2->IFCR |= DMA2_CHANNEL3_IT_MASK; + } + else if (DMAy_Channelx == DMA2_Channel4) + { + /* Reset interrupt pending bits for DMA2 Channel4 */ + DMA2->IFCR |= DMA2_CHANNEL4_IT_MASK; + } + else + { + if (DMAy_Channelx == DMA2_Channel5) + { + /* Reset interrupt pending bits for DMA2 Channel5 */ + DMA2->IFCR |= DMA2_CHANNEL5_IT_MASK; + } + } +} + +/** + * @brief Initializes the DMAy Channelx according to the specified parameters + * in the DMA_InitStruct. + * @param DMAy_Channelx: where y can be 1 or 2 to select the DMA and + * x can be 1 to 7 for DMA1 and 1 to 5 for DMA2 to select the DMA Channel. + * @param DMA_InitStruct: pointer to a DMA_InitTypeDef structure that contains + * the configuration information for the specified DMA Channel. + * @retval None + */ +void DMA_Init(DMA_Channel_TypeDef* DMAy_Channelx, DMA_InitTypeDef* DMA_InitStruct) +{ + uint32_t tmpreg = 0; + + /* Check the parameters */ + assert_param(IS_DMA_ALL_PERIPH(DMAy_Channelx)); + assert_param(IS_DMA_DIR(DMA_InitStruct->DMA_DIR)); + assert_param(IS_DMA_PERIPHERAL_INC_STATE(DMA_InitStruct->DMA_PeripheralInc)); + assert_param(IS_DMA_MEMORY_INC_STATE(DMA_InitStruct->DMA_MemoryInc)); + assert_param(IS_DMA_PERIPHERAL_DATA_SIZE(DMA_InitStruct->DMA_PeripheralDataSize)); + assert_param(IS_DMA_MEMORY_DATA_SIZE(DMA_InitStruct->DMA_MemoryDataSize)); + assert_param(IS_DMA_MODE(DMA_InitStruct->DMA_Mode)); + assert_param(IS_DMA_PRIORITY(DMA_InitStruct->DMA_Priority)); + assert_param(IS_DMA_M2M_STATE(DMA_InitStruct->DMA_M2M)); + +/*--------------------------- DMAy Channelx CCR Configuration ----------------*/ + /* Get the DMAy_Channelx CCR value */ + tmpreg = DMAy_Channelx->CCR; + + /* Clear MEM2MEM, PL, MSIZE, PSIZE, MINC, PINC, CIRC and DIR bits */ + tmpreg &= CCR_CLEAR_MASK; + + /* Configure DMAy Channelx: data transfer, data size, priority level and mode */ + /* Set DIR bit according to DMA_DIR value */ + /* Set CIRC bit according to DMA_Mode value */ + /* Set PINC bit according to DMA_PeripheralInc value */ + /* Set MINC bit according to DMA_MemoryInc value */ + /* Set PSIZE bits according to DMA_PeripheralDataSize value */ + /* Set MSIZE bits according to DMA_MemoryDataSize value */ + /* Set PL bits according to DMA_Priority value */ + /* Set the MEM2MEM bit according to DMA_M2M value */ + tmpreg |= DMA_InitStruct->DMA_DIR | DMA_InitStruct->DMA_Mode | + DMA_InitStruct->DMA_PeripheralInc | DMA_InitStruct->DMA_MemoryInc | + DMA_InitStruct->DMA_PeripheralDataSize | DMA_InitStruct->DMA_MemoryDataSize | + DMA_InitStruct->DMA_Priority | DMA_InitStruct->DMA_M2M; + + /* Write to DMAy Channelx CCR */ + DMAy_Channelx->CCR = tmpreg; + +/*--------------------------- DMAy Channelx CNDTR Configuration --------------*/ + /* Write to DMAy Channelx CNDTR */ + DMAy_Channelx->CNDTR = DMA_InitStruct->DMA_BufferSize; + +/*--------------------------- DMAy Channelx CPAR Configuration ---------------*/ + /* Write to DMAy Channelx CPAR */ + DMAy_Channelx->CPAR = DMA_InitStruct->DMA_PeripheralBaseAddr; + +/*--------------------------- DMAy Channelx CMAR Configuration ---------------*/ + /* Write to DMAy Channelx CMAR */ + DMAy_Channelx->CMAR = DMA_InitStruct->DMA_MemoryBaseAddr; +} + +/** + * @brief Fills each DMA_InitStruct member with its default value. + * @param DMA_InitStruct: pointer to a DMA_InitTypeDef structure which will + * be initialized. + * @retval None + */ +void DMA_StructInit(DMA_InitTypeDef* DMA_InitStruct) +{ +/*-------------- Reset DMA init structure parameters values ------------------*/ + /* Initialize the DMA_PeripheralBaseAddr member */ + DMA_InitStruct->DMA_PeripheralBaseAddr = 0; + /* Initialize the DMA_MemoryBaseAddr member */ + DMA_InitStruct->DMA_MemoryBaseAddr = 0; + /* Initialize the DMA_DIR member */ + DMA_InitStruct->DMA_DIR = DMA_DIR_PeripheralSRC; + /* Initialize the DMA_BufferSize member */ + DMA_InitStruct->DMA_BufferSize = 0; + /* Initialize the DMA_PeripheralInc member */ + DMA_InitStruct->DMA_PeripheralInc = DMA_PeripheralInc_Disable; + /* Initialize the DMA_MemoryInc member */ + DMA_InitStruct->DMA_MemoryInc = DMA_MemoryInc_Disable; + /* Initialize the DMA_PeripheralDataSize member */ + DMA_InitStruct->DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; + /* Initialize the DMA_MemoryDataSize member */ + DMA_InitStruct->DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; + /* Initialize the DMA_Mode member */ + DMA_InitStruct->DMA_Mode = DMA_Mode_Normal; + /* Initialize the DMA_Priority member */ + DMA_InitStruct->DMA_Priority = DMA_Priority_Low; + /* Initialize the DMA_M2M member */ + DMA_InitStruct->DMA_M2M = DMA_M2M_Disable; +} + +/** + * @brief Enables or disables the specified DMAy Channelx. + * @param DMAy_Channelx: where y can be 1 or 2 to select the DMA and + * x can be 1 to 7 for DMA1 and 1 to 5 for DMA2 to select the DMA Channel. + * @param NewState: new state of the DMAy Channelx. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void DMA_Cmd(DMA_Channel_TypeDef* DMAy_Channelx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_DMA_ALL_PERIPH(DMAy_Channelx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable the selected DMAy Channelx */ + DMAy_Channelx->CCR |= DMA_CCR_EN; + } + else + { + /* Disable the selected DMAy Channelx */ + DMAy_Channelx->CCR &= (uint16_t)(~DMA_CCR_EN); + } +} + +/** + * @} + */ + +/** @defgroup DMA_Group2 Data Counter functions + * @brief Data Counter functions + * +@verbatim + =============================================================================== + ##### Data Counter functions ##### + =============================================================================== + [..] This subsection provides function allowing to configure and read the buffer + size (number of data to be transferred).The DMA data counter can be written + only when the DMA channel is disabled (ie. after transfer complete event). + [..] The following function can be used to write the Channel data counter value: + (+) void DMA_SetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx, uint16_t DataNumber). + [..] + (@) It is advised to use this function rather than DMA_Init() in situations + where only the Data buffer needs to be reloaded. + [..] The DMA data counter can be read to indicate the number of remaining transfers + for the relative DMA channel. This counter is decremented at the end of each + data transfer and when the transfer is complete: + (+) If Normal mode is selected: the counter is set to 0. + (+) If Circular mode is selected: the counter is reloaded with the initial + value(configured before enabling the DMA channel). + [..] The following function can be used to read the Channel data counter value: + (+) uint16_t DMA_GetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx). + +@endverbatim + * @{ + */ + +/** + * @brief Sets the number of data units in the current DMAy Channelx transfer. + * @param DMAy_Channelx: where y can be 1 or 2 to select the DMA and + * x can be 1 to 7 for DMA1 and 1 to 5 for DMA2 to select the DMA Channel. + * @param DataNumber: The number of data units in the current DMAy Channelx + * transfer. + * @note This function can only be used when the DMAy_Channelx is disabled. + * @retval None. + */ +void DMA_SetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx, uint16_t DataNumber) +{ + /* Check the parameters */ + assert_param(IS_DMA_ALL_PERIPH(DMAy_Channelx)); + +/*--------------------------- DMAy Channelx CNDTR Configuration --------------*/ + /* Write to DMAy Channelx CNDTR */ + DMAy_Channelx->CNDTR = DataNumber; +} + +/** + * @brief Returns the number of remaining data units in the current + * DMAy Channelx transfer. + * @param DMAy_Channelx: where y can be 1 or 2 to select the DMA and + * x can be 1 to 7 for DMA1 and 1 to 5 for DMA2 to select the DMA Channel. + * @retval The number of remaining data units in the current DMAy Channelx + * transfer. + */ +uint16_t DMA_GetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx) +{ + /* Check the parameters */ + assert_param(IS_DMA_ALL_PERIPH(DMAy_Channelx)); + /* Return the number of remaining data units for DMAy Channelx */ + return ((uint16_t)(DMAy_Channelx->CNDTR)); +} + +/** + * @} + */ + +/** @defgroup DMA_Group3 Interrupts and flags management functions + * @brief Interrupts and flags management functions + * +@verbatim + =============================================================================== + ##### Interrupts and flags management functions ##### + =============================================================================== + [..] This subsection provides functions allowing to configure the DMA Interrupt + sources and check or clear the flags or pending bits status. + The user should identify which mode will be used in his application to manage + the DMA controller events: Polling mode or Interrupt mode. + + *** Polling Mode *** + ==================== + [..] Each DMA channel can be managed through 4 event Flags (y : DMA Controller + number, x : DMA channel number): + (#) DMAy_FLAG_TCx : to indicate that a Transfer Complete event occurred. + (#) DMAy_FLAG_HTx : to indicate that a Half-Transfer Complete event occurred. + (#) DMAy_FLAG_TEx : to indicate that a Transfer Error occurred. + (#) DMAy_FLAG_GLx : to indicate that at least one of the events described + above occurred. + [..] + (@) Clearing DMAy_FLAG_GLx results in clearing all other pending flags of the + same channel (DMAy_FLAG_TCx, DMAy_FLAG_HTx and DMAy_FLAG_TEx). + [..] In this Mode it is advised to use the following functions: + (+) FlagStatus DMA_GetFlagStatus(uint32_t DMA_FLAG); + (+) void DMA_ClearFlag(uint32_t DMA_FLAG); + + *** Interrupt Mode *** + ====================== + [..] Each DMA channel can be managed through 4 Interrupts: + (+) Interrupt Source + (##) DMA_IT_TC: specifies the interrupt source for the Transfer Complete + event. + (##) DMA_IT_HT: specifies the interrupt source for the Half-transfer Complete + event. + (##) DMA_IT_TE: specifies the interrupt source for the transfer errors event. + (##) DMA_IT_GL: to indicate that at least one of the interrupts described + above occurred. + -@@- Clearing DMA_IT_GL interrupt results in clearing all other interrupts of + the same channel (DMA_IT_TCx, DMA_IT_HT and DMA_IT_TE). + [..] In this Mode it is advised to use the following functions: + (+) void DMA_ITConfig(DMA_Channel_TypeDef* DMAy_Channelx, uint32_t DMA_IT, FunctionalState NewState); + (+) ITStatus DMA_GetITStatus(uint32_t DMA_IT); + (+) void DMA_ClearITPendingBit(uint32_t DMA_IT); + +@endverbatim + * @{ + */ + +/** + * @brief Enables or disables the specified DMAy Channelx interrupts. + * @param DMAy_Channelx: where y can be 1 or 2 to select the DMA and + * x can be 1 to 7 for DMA1 and 1 to 5 for DMA2 to select the DMA Channel. + * @param DMA_IT: specifies the DMA interrupts sources to be enabled + * or disabled. + * This parameter can be any combination of the following values: + * @arg DMA_IT_TC: Transfer complete interrupt mask + * @arg DMA_IT_HT: Half transfer interrupt mask + * @arg DMA_IT_TE: Transfer error interrupt mask + * @param NewState: new state of the specified DMA interrupts. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void DMA_ITConfig(DMA_Channel_TypeDef* DMAy_Channelx, uint32_t DMA_IT, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_DMA_ALL_PERIPH(DMAy_Channelx)); + assert_param(IS_DMA_CONFIG_IT(DMA_IT)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable the selected DMA interrupts */ + DMAy_Channelx->CCR |= DMA_IT; + } + else + { + /* Disable the selected DMA interrupts */ + DMAy_Channelx->CCR &= ~DMA_IT; + } +} + +/** + * @brief Checks whether the specified DMAy Channelx flag is set or not. + * @param DMAy_FLAG: specifies the flag to check. + * This parameter can be one of the following values: + * @arg DMA1_FLAG_GL1: DMA1 Channel1 global flag. + * @arg DMA1_FLAG_TC1: DMA1 Channel1 transfer complete flag. + * @arg DMA1_FLAG_HT1: DMA1 Channel1 half transfer flag. + * @arg DMA1_FLAG_TE1: DMA1 Channel1 transfer error flag. + * @arg DMA1_FLAG_GL2: DMA1 Channel2 global flag. + * @arg DMA1_FLAG_TC2: DMA1 Channel2 transfer complete flag. + * @arg DMA1_FLAG_HT2: DMA1 Channel2 half transfer flag. + * @arg DMA1_FLAG_TE2: DMA1 Channel2 transfer error flag. + * @arg DMA1_FLAG_GL3: DMA1 Channel3 global flag. + * @arg DMA1_FLAG_TC3: DMA1 Channel3 transfer complete flag. + * @arg DMA1_FLAG_HT3: DMA1 Channel3 half transfer flag. + * @arg DMA1_FLAG_TE3: DMA1 Channel3 transfer error flag. + * @arg DMA1_FLAG_GL4: DMA1 Channel4 global flag. + * @arg DMA1_FLAG_TC4: DMA1 Channel4 transfer complete flag. + * @arg DMA1_FLAG_HT4: DMA1 Channel4 half transfer flag. + * @arg DMA1_FLAG_TE4: DMA1 Channel4 transfer error flag. + * @arg DMA1_FLAG_GL5: DMA1 Channel5 global flag. + * @arg DMA1_FLAG_TC5: DMA1 Channel5 transfer complete flag. + * @arg DMA1_FLAG_HT5: DMA1 Channel5 half transfer flag. + * @arg DMA1_FLAG_TE5: DMA1 Channel5 transfer error flag. + * @arg DMA1_FLAG_GL6: DMA1 Channel6 global flag. + * @arg DMA1_FLAG_TC6: DMA1 Channel6 transfer complete flag. + * @arg DMA1_FLAG_HT6: DMA1 Channel6 half transfer flag. + * @arg DMA1_FLAG_TE6: DMA1 Channel6 transfer error flag. + * @arg DMA1_FLAG_GL7: DMA1 Channel7 global flag. + * @arg DMA1_FLAG_TC7: DMA1 Channel7 transfer complete flag. + * @arg DMA1_FLAG_HT7: DMA1 Channel7 half transfer flag. + * @arg DMA1_FLAG_TE7: DMA1 Channel7 transfer error flag. + * @arg DMA2_FLAG_GL1: DMA2 Channel1 global flag. + * @arg DMA2_FLAG_TC1: DMA2 Channel1 transfer complete flag. + * @arg DMA2_FLAG_HT1: DMA2 Channel1 half transfer flag. + * @arg DMA2_FLAG_TE1: DMA2 Channel1 transfer error flag. + * @arg DMA2_FLAG_GL2: DMA2 Channel2 global flag. + * @arg DMA2_FLAG_TC2: DMA2 Channel2 transfer complete flag. + * @arg DMA2_FLAG_HT2: DMA2 Channel2 half transfer flag. + * @arg DMA2_FLAG_TE2: DMA2 Channel2 transfer error flag. + * @arg DMA2_FLAG_GL3: DMA2 Channel3 global flag. + * @arg DMA2_FLAG_TC3: DMA2 Channel3 transfer complete flag. + * @arg DMA2_FLAG_HT3: DMA2 Channel3 half transfer flag. + * @arg DMA2_FLAG_TE3: DMA2 Channel3 transfer error flag. + * @arg DMA2_FLAG_GL4: DMA2 Channel4 global flag. + * @arg DMA2_FLAG_TC4: DMA2 Channel4 transfer complete flag. + * @arg DMA2_FLAG_HT4: DMA2 Channel4 half transfer flag. + * @arg DMA2_FLAG_TE4: DMA2 Channel4 transfer error flag. + * @arg DMA2_FLAG_GL5: DMA2 Channel5 global flag. + * @arg DMA2_FLAG_TC5: DMA2 Channel5 transfer complete flag. + * @arg DMA2_FLAG_HT5: DMA2 Channel5 half transfer flag. + * @arg DMA2_FLAG_TE5: DMA2 Channel5 transfer error flag. + * + * @note + * The Global flag (DMAy_FLAG_GLx) is set whenever any of the other flags + * relative to the same channel is set (Transfer Complete, Half-transfer + * Complete or Transfer Error flags: DMAy_FLAG_TCx, DMAy_FLAG_HTx or + * DMAy_FLAG_TEx). + * + * @retval The new state of DMAy_FLAG (SET or RESET). + */ +FlagStatus DMA_GetFlagStatus(uint32_t DMAy_FLAG) +{ + FlagStatus bitstatus = RESET; + uint32_t tmpreg = 0; + + /* Check the parameters */ + assert_param(IS_DMA_GET_FLAG(DMAy_FLAG)); + + /* Calculate the used DMAy */ + if ((DMAy_FLAG & FLAG_Mask) != (uint32_t)RESET) + { + /* Get DMA2 ISR register value */ + tmpreg = DMA2->ISR ; + } + else + { + /* Get DMA1 ISR register value */ + tmpreg = DMA1->ISR ; + } + + /* Check the status of the specified DMAy flag */ + if ((tmpreg & DMAy_FLAG) != (uint32_t)RESET) + { + /* DMAy_FLAG is set */ + bitstatus = SET; + } + else + { + /* DMAy_FLAG is reset */ + bitstatus = RESET; + } + + /* Return the DMAy_FLAG status */ + return bitstatus; +} + +/** + * @brief Clears the DMAy Channelx's pending flags. + * @param DMAy_FLAG: specifies the flag to clear. + * This parameter can be any combination (for the same DMA) of the following values: + * @arg DMA1_FLAG_GL1: DMA1 Channel1 global flag. + * @arg DMA1_FLAG_TC1: DMA1 Channel1 transfer complete flag. + * @arg DMA1_FLAG_HT1: DMA1 Channel1 half transfer flag. + * @arg DMA1_FLAG_TE1: DMA1 Channel1 transfer error flag. + * @arg DMA1_FLAG_GL2: DMA1 Channel2 global flag. + * @arg DMA1_FLAG_TC2: DMA1 Channel2 transfer complete flag. + * @arg DMA1_FLAG_HT2: DMA1 Channel2 half transfer flag. + * @arg DMA1_FLAG_TE2: DMA1 Channel2 transfer error flag. + * @arg DMA1_FLAG_GL3: DMA1 Channel3 global flag. + * @arg DMA1_FLAG_TC3: DMA1 Channel3 transfer complete flag. + * @arg DMA1_FLAG_HT3: DMA1 Channel3 half transfer flag. + * @arg DMA1_FLAG_TE3: DMA1 Channel3 transfer error flag. + * @arg DMA1_FLAG_GL4: DMA1 Channel4 global flag. + * @arg DMA1_FLAG_TC4: DMA1 Channel4 transfer complete flag. + * @arg DMA1_FLAG_HT4: DMA1 Channel4 half transfer flag. + * @arg DMA1_FLAG_TE4: DMA1 Channel4 transfer error flag. + * @arg DMA1_FLAG_GL5: DMA1 Channel5 global flag. + * @arg DMA1_FLAG_TC5: DMA1 Channel5 transfer complete flag. + * @arg DMA1_FLAG_HT5: DMA1 Channel5 half transfer flag. + * @arg DMA1_FLAG_TE5: DMA1 Channel5 transfer error flag. + * @arg DMA1_FLAG_GL6: DMA1 Channel6 global flag. + * @arg DMA1_FLAG_TC6: DMA1 Channel6 transfer complete flag. + * @arg DMA1_FLAG_HT6: DMA1 Channel6 half transfer flag. + * @arg DMA1_FLAG_TE6: DMA1 Channel6 transfer error flag. + * @arg DMA1_FLAG_GL7: DMA1 Channel7 global flag. + * @arg DMA1_FLAG_TC7: DMA1 Channel7 transfer complete flag. + * @arg DMA1_FLAG_HT7: DMA1 Channel7 half transfer flag. + * @arg DMA1_FLAG_TE7: DMA1 Channel7 transfer error flag. + * @arg DMA2_FLAG_GL1: DMA2 Channel1 global flag. + * @arg DMA2_FLAG_TC1: DMA2 Channel1 transfer complete flag. + * @arg DMA2_FLAG_HT1: DMA2 Channel1 half transfer flag. + * @arg DMA2_FLAG_TE1: DMA2 Channel1 transfer error flag. + * @arg DMA2_FLAG_GL2: DMA2 Channel2 global flag. + * @arg DMA2_FLAG_TC2: DMA2 Channel2 transfer complete flag. + * @arg DMA2_FLAG_HT2: DMA2 Channel2 half transfer flag. + * @arg DMA2_FLAG_TE2: DMA2 Channel2 transfer error flag. + * @arg DMA2_FLAG_GL3: DMA2 Channel3 global flag. + * @arg DMA2_FLAG_TC3: DMA2 Channel3 transfer complete flag. + * @arg DMA2_FLAG_HT3: DMA2 Channel3 half transfer flag. + * @arg DMA2_FLAG_TE3: DMA2 Channel3 transfer error flag. + * @arg DMA2_FLAG_GL4: DMA2 Channel4 global flag. + * @arg DMA2_FLAG_TC4: DMA2 Channel4 transfer complete flag. + * @arg DMA2_FLAG_HT4: DMA2 Channel4 half transfer flag. + * @arg DMA2_FLAG_TE4: DMA2 Channel4 transfer error flag. + * @arg DMA2_FLAG_GL5: DMA2 Channel5 global flag. + * @arg DMA2_FLAG_TC5: DMA2 Channel5 transfer complete flag. + * @arg DMA2_FLAG_HT5: DMA2 Channel5 half transfer flag. + * @arg DMA2_FLAG_TE5: DMA2 Channel5 transfer error flag. + * + * @note + * Clearing the Global flag (DMAy_FLAG_GLx) results in clearing all other flags + * relative to the same channel (Transfer Complete, Half-transfer Complete and + * Transfer Error flags: DMAy_FLAG_TCx, DMAy_FLAG_HTx and DMAy_FLAG_TEx). + * + * @retval None + */ +void DMA_ClearFlag(uint32_t DMAy_FLAG) +{ + /* Check the parameters */ + assert_param(IS_DMA_CLEAR_FLAG(DMAy_FLAG)); + +/* Calculate the used DMAy */ + if ((DMAy_FLAG & FLAG_Mask) != (uint32_t)RESET) + { + /* Clear the selected DMAy flags */ + DMA2->IFCR = DMAy_FLAG; + } + else + { + /* Clear the selected DMAy flags */ + DMA1->IFCR = DMAy_FLAG; + } +} + +/** + * @brief Checks whether the specified DMAy Channelx interrupt has occurred or not. + * @param DMAy_IT: specifies the DMAy interrupt source to check. + * This parameter can be one of the following values: + * @arg DMA1_IT_GL1: DMA1 Channel1 global interrupt. + * @arg DMA1_IT_TC1: DMA1 Channel1 transfer complete interrupt. + * @arg DMA1_IT_HT1: DMA1 Channel1 half transfer interrupt. + * @arg DMA1_IT_TE1: DMA1 Channel1 transfer error interrupt. + * @arg DMA1_IT_GL2: DMA1 Channel2 global interrupt. + * @arg DMA1_IT_TC2: DMA1 Channel2 transfer complete interrupt. + * @arg DMA1_IT_HT2: DMA1 Channel2 half transfer interrupt. + * @arg DMA1_IT_TE2: DMA1 Channel2 transfer error interrupt. + * @arg DMA1_IT_GL3: DMA1 Channel3 global interrupt. + * @arg DMA1_IT_TC3: DMA1 Channel3 transfer complete interrupt. + * @arg DMA1_IT_HT3: DMA1 Channel3 half transfer interrupt. + * @arg DMA1_IT_TE3: DMA1 Channel3 transfer error interrupt. + * @arg DMA1_IT_GL4: DMA1 Channel4 global interrupt. + * @arg DMA1_IT_TC4: DMA1 Channel4 transfer complete interrupt. + * @arg DMA1_IT_HT4: DMA1 Channel4 half transfer interrupt. + * @arg DMA1_IT_TE4: DMA1 Channel4 transfer error interrupt. + * @arg DMA1_IT_GL5: DMA1 Channel5 global interrupt. + * @arg DMA1_IT_TC5: DMA1 Channel5 transfer complete interrupt. + * @arg DMA1_IT_HT5: DMA1 Channel5 half transfer interrupt. + * @arg DMA1_IT_TE5: DMA1 Channel5 transfer error interrupt. + * @arg DMA1_IT_GL6: DMA1 Channel6 global interrupt. + * @arg DMA1_IT_TC6: DMA1 Channel6 transfer complete interrupt. + * @arg DMA1_IT_HT6: DMA1 Channel6 half transfer interrupt. + * @arg DMA1_IT_TE6: DMA1 Channel6 transfer error interrupt. + * @arg DMA1_IT_GL7: DMA1 Channel7 global interrupt. + * @arg DMA1_IT_TC7: DMA1 Channel7 transfer complete interrupt. + * @arg DMA1_IT_HT7: DMA1 Channel7 half transfer interrupt. + * @arg DMA1_IT_TE7: DMA1 Channel7 transfer error interrupt. + * @arg DMA2_IT_GL1: DMA2 Channel1 global interrupt. + * @arg DMA2_IT_TC1: DMA2 Channel1 transfer complete interrupt. + * @arg DMA2_IT_HT1: DMA2 Channel1 half transfer interrupt. + * @arg DMA2_IT_TE1: DMA2 Channel1 transfer error interrupt. + * @arg DMA2_IT_GL2: DMA2 Channel2 global interrupt. + * @arg DMA2_IT_TC2: DMA2 Channel2 transfer complete interrupt. + * @arg DMA2_IT_HT2: DMA2 Channel2 half transfer interrupt. + * @arg DMA2_IT_TE2: DMA2 Channel2 transfer error interrupt. + * @arg DMA2_IT_GL3: DMA2 Channel3 global interrupt. + * @arg DMA2_IT_TC3: DMA2 Channel3 transfer complete interrupt. + * @arg DMA2_IT_HT3: DMA2 Channel3 half transfer interrupt. + * @arg DMA2_IT_TE3: DMA2 Channel3 transfer error interrupt. + * @arg DMA2_IT_GL4: DMA2 Channel4 global interrupt. + * @arg DMA2_IT_TC4: DMA2 Channel4 transfer complete interrupt. + * @arg DMA2_IT_HT4: DMA2 Channel4 half transfer interrupt. + * @arg DMA2_IT_TE4: DMA2 Channel4 transfer error interrupt. + * @arg DMA2_IT_GL5: DMA2 Channel5 global interrupt. + * @arg DMA2_IT_TC5: DMA2 Channel5 transfer complete interrupt. + * @arg DMA2_IT_HT5: DMA2 Channel5 half transfer interrupt. + * @arg DMA2_IT_TE5: DMA2 Channel5 transfer error interrupt. + * + * @note + * The Global interrupt (DMAy_FLAG_GLx) is set whenever any of the other + * interrupts relative to the same channel is set (Transfer Complete, + * Half-transfer Complete or Transfer Error interrupts: DMAy_IT_TCx, + * DMAy_IT_HTx or DMAy_IT_TEx). + * + * @retval The new state of DMAy_IT (SET or RESET). + */ +ITStatus DMA_GetITStatus(uint32_t DMAy_IT) +{ + ITStatus bitstatus = RESET; + uint32_t tmpreg = 0; + + /* Check the parameters */ + assert_param(IS_DMA_GET_IT(DMAy_IT)); + + /* Calculate the used DMA */ + if ((DMAy_IT & FLAG_Mask) != (uint32_t)RESET) + { + /* Get DMA2 ISR register value */ + tmpreg = DMA2->ISR; + } + else + { + /* Get DMA1 ISR register value */ + tmpreg = DMA1->ISR; + } + + /* Check the status of the specified DMAy interrupt */ + if ((tmpreg & DMAy_IT) != (uint32_t)RESET) + { + /* DMAy_IT is set */ + bitstatus = SET; + } + else + { + /* DMAy_IT is reset */ + bitstatus = RESET; + } + /* Return the DMAy_IT status */ + return bitstatus; +} + +/** + * @brief Clears the DMAy Channelx's interrupt pending bits. + * @param DMAy_IT: specifies the DMAy interrupt pending bit to clear. + * This parameter can be any combination (for the same DMA) of the following values: + * @arg DMA1_IT_GL1: DMA1 Channel1 global interrupt. + * @arg DMA1_IT_TC1: DMA1 Channel1 transfer complete interrupt. + * @arg DMA1_IT_HT1: DMA1 Channel1 half transfer interrupt. + * @arg DMA1_IT_TE1: DMA1 Channel1 transfer error interrupt. + * @arg DMA1_IT_GL2: DMA1 Channel2 global interrupt. + * @arg DMA1_IT_TC2: DMA1 Channel2 transfer complete interrupt. + * @arg DMA1_IT_HT2: DMA1 Channel2 half transfer interrupt. + * @arg DMA1_IT_TE2: DMA1 Channel2 transfer error interrupt. + * @arg DMA1_IT_GL3: DMA1 Channel3 global interrupt. + * @arg DMA1_IT_TC3: DMA1 Channel3 transfer complete interrupt. + * @arg DMA1_IT_HT3: DMA1 Channel3 half transfer interrupt. + * @arg DMA1_IT_TE3: DMA1 Channel3 transfer error interrupt. + * @arg DMA1_IT_GL4: DMA1 Channel4 global interrupt. + * @arg DMA1_IT_TC4: DMA1 Channel4 transfer complete interrupt. + * @arg DMA1_IT_HT4: DMA1 Channel4 half transfer interrupt. + * @arg DMA1_IT_TE4: DMA1 Channel4 transfer error interrupt. + * @arg DMA1_IT_GL5: DMA1 Channel5 global interrupt. + * @arg DMA1_IT_TC5: DMA1 Channel5 transfer complete interrupt. + * @arg DMA1_IT_HT5: DMA1 Channel5 half transfer interrupt. + * @arg DMA1_IT_TE5: DMA1 Channel5 transfer error interrupt. + * @arg DMA1_IT_GL6: DMA1 Channel6 global interrupt. + * @arg DMA1_IT_TC6: DMA1 Channel6 transfer complete interrupt. + * @arg DMA1_IT_HT6: DMA1 Channel6 half transfer interrupt. + * @arg DMA1_IT_TE6: DMA1 Channel6 transfer error interrupt. + * @arg DMA1_IT_GL7: DMA1 Channel7 global interrupt. + * @arg DMA1_IT_TC7: DMA1 Channel7 transfer complete interrupt. + * @arg DMA1_IT_HT7: DMA1 Channel7 half transfer interrupt. + * @arg DMA1_IT_TE7: DMA1 Channel7 transfer error interrupt. + * @arg DMA2_IT_GL1: DMA2 Channel1 global interrupt. + * @arg DMA2_IT_TC1: DMA2 Channel1 transfer complete interrupt. + * @arg DMA2_IT_HT1: DMA2 Channel1 half transfer interrupt. + * @arg DMA2_IT_TE1: DMA2 Channel1 transfer error interrupt. + * @arg DMA2_IT_GL2: DMA2 Channel2 global interrupt. + * @arg DMA2_IT_TC2: DMA2 Channel2 transfer complete interrupt. + * @arg DMA2_IT_HT2: DMA2 Channel2 half transfer interrupt. + * @arg DMA2_IT_TE2: DMA2 Channel2 transfer error interrupt. + * @arg DMA2_IT_GL3: DMA2 Channel3 global interrupt. + * @arg DMA2_IT_TC3: DMA2 Channel3 transfer complete interrupt. + * @arg DMA2_IT_HT3: DMA2 Channel3 half transfer interrupt. + * @arg DMA2_IT_TE3: DMA2 Channel3 transfer error interrupt. + * @arg DMA2_IT_GL4: DMA2 Channel4 global interrupt. + * @arg DMA2_IT_TC4: DMA2 Channel4 transfer complete interrupt. + * @arg DMA2_IT_HT4: DMA2 Channel4 half transfer interrupt. + * @arg DMA2_IT_TE4: DMA2 Channel4 transfer error interrupt. + * @arg DMA2_IT_GL5: DMA2 Channel5 global interrupt. + * @arg DMA2_IT_TC5: DMA2 Channel5 transfer complete interrupt. + * @arg DMA2_IT_HT5: DMA2 Channel5 half transfer interrupt. + * @arg DMA2_IT_TE5: DMA2 Channel5 transfer error interrupt. + * + * @note + * Clearing the Global interrupt (DMAy_IT_GLx) results in clearing all other + * interrupts relative to the same channel (Transfer Complete, Half-transfer + * Complete and Transfer Error interrupts: DMAy_IT_TCx, DMAy_IT_HTx and + * DMAy_IT_TEx). + * + * @retval None + */ +void DMA_ClearITPendingBit(uint32_t DMAy_IT) +{ + /* Check the parameters */ + assert_param(IS_DMA_CLEAR_IT(DMAy_IT)); + + /* Calculate the used DMAy */ + if ((DMAy_IT & FLAG_Mask) != (uint32_t)RESET) + { + /* Clear the selected DMAy interrupt pending bits */ + DMA2->IFCR = DMAy_IT; + } + else + { + /* Clear the selected DMAy interrupt pending bits */ + DMA1->IFCR = DMAy_IT; + } +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_exti.c b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_exti.c new file mode 100755 index 0000000000..b9976c08d4 --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_exti.c @@ -0,0 +1,349 @@ +/** + ****************************************************************************** + * @file stm32f30x_exti.c + * @author MCD Application Team + * @version V1.2.3 + * @date 10-July-2015 + * @brief This file provides firmware functions to manage the following + * functionalities of the EXTI peripheral: + * + Initialization and Configuration + * + Interrupts and flags management + * + @verbatim + =============================================================================== + ##### EXTI features ##### + =============================================================================== + [..] External interrupt/event lines are mapped as following: + (#) All available GPIO pins are connected to the 16 external + interrupt/event lines from EXTI0 to EXTI15. + (#) EXTI line 16 is connected to the PVD output + (#) EXTI line 17 is connected to the RTC Alarm event + (#) EXTI line 18 is connected to USB Device wakeup event + (#) EXTI line 19 is connected to the RTC Tamper and TimeStamp events + (#) EXTI line 20 is connected to the RTC wakeup event + (#) EXTI line 21 is connected to the Comparator 1 wakeup event + (#) EXTI line 22 is connected to the Comparator 2 wakeup event + (#) EXTI line 23 is connected to the I2C1 wakeup event + (#) EXTI line 24 is connected to the I2C2 wakeup event + (#) EXTI line 25 is connected to the USART1 wakeup event + (#) EXTI line 26 is connected to the USART2 wakeup event + (#) EXTI line 27 is reserved + (#) EXTI line 28 is connected to the USART3 wakeup event + (#) EXTI line 29 is connected to the Comparator 3 event + (#) EXTI line 30 is connected to the Comparator 4 event + (#) EXTI line 31 is connected to the Comparator 5 event + (#) EXTI line 32 is connected to the Comparator 6 event + (#) EXTI line 33 is connected to the Comparator 7 event + (#) EXTI line 34 is connected for thr UART4 wakeup event + (#) EXTI line 35 is connected for the UART5 wakeup event + + ##### How to use this driver ##### + =============================================================================== + [..] In order to use an I/O pin as an external interrupt source, + follow steps below: + (#) Configure the I/O in input mode using GPIO_Init(). + (#) Select the input source pin for the EXTI line using + SYSCFG_EXTILineConfig(). + (#) Select the mode(interrupt, event) and configure the trigger + selection (Rising, falling or both) using EXTI_Init(). For the + internal interrupt, the trigger selection is not needed + (the active edge is always the rising one). + (#) Configure NVIC IRQ channel mapped to the EXTI line using NVIC_Init(). + (#) Optionally, you can generate a software interrupt using the function + EXTI_GenerateSWInterrupt(). + [..] + (@) SYSCFG APB clock must be enabled to get write access to SYSCFG_EXTICRx + registers using RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); + + @endverbatim + + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f30x_exti.h" + +/** @addtogroup STM32F30x_StdPeriph_Driver + * @{ + */ + +/** @defgroup EXTI + * @brief EXTI driver modules + * @{ + */ + + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +#define EXTI_LINENONE ((uint32_t)0x00000) /* No interrupt selected */ + +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/* Private function prototypes -----------------------------------------------*/ +/* Private functions ---------------------------------------------------------*/ + +/** @defgroup EXTI_Private_Functions + * @{ + */ + +/** @defgroup EXTI_Group1 Initialization and Configuration functions + * @brief Initialization and Configuration functions + * +@verbatim + =============================================================================== + ##### Initialization and Configuration functions ##### + =============================================================================== + +@endverbatim + * @{ + */ + +/** + * @brief Deinitializes the EXTI peripheral registers to their default reset + * values. + * @param None + * @retval None + */ +void EXTI_DeInit(void) +{ + EXTI->IMR = 0x1F800000; + EXTI->EMR = 0x00000000; + EXTI->RTSR = 0x00000000; + EXTI->FTSR = 0x00000000; + EXTI->SWIER = 0x00000000; + EXTI->PR = 0xE07FFFFF; + EXTI->IMR2 = 0x0000000C; + EXTI->EMR2 = 0x00000000; + EXTI->RTSR2 = 0x00000000; + EXTI->FTSR2 = 0x00000000; + EXTI->SWIER2 = 0x00000000; + EXTI->PR2 = 0x00000003; +} + +/** + * @brief Initializes the EXTI peripheral according to the specified + * parameters in the EXTI_InitStruct. + * EXTI_Line specifies the EXTI line (EXTI0....EXTI35). + * EXTI_Mode specifies which EXTI line is used as interrupt or an event. + * EXTI_Trigger selects the trigger. When the trigger occurs, interrupt + * pending bit will be set. + * EXTI_LineCmd controls (Enable/Disable) the EXTI line. + * @param EXTI_InitStruct: pointer to a EXTI_InitTypeDef structure that + * contains the configuration information for the EXTI peripheral. + * @retval None + */ + + +void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct) +{ + uint32_t tmp = 0; + + /* Check the parameters */ + assert_param(IS_EXTI_MODE(EXTI_InitStruct->EXTI_Mode)); + assert_param(IS_EXTI_TRIGGER(EXTI_InitStruct->EXTI_Trigger)); + assert_param(IS_EXTI_LINE_ALL(EXTI_InitStruct->EXTI_Line)); + assert_param(IS_FUNCTIONAL_STATE(EXTI_InitStruct->EXTI_LineCmd)); + + tmp = (uint32_t)EXTI_BASE; + + if (EXTI_InitStruct->EXTI_LineCmd != DISABLE) + { + /* Clear EXTI line configuration */ + *(__IO uint32_t *) (((uint32_t) &(EXTI->IMR)) + ((EXTI_InitStruct->EXTI_Line) >> 5 ) * 0x20) &= ~(uint32_t)(1 << (EXTI_InitStruct->EXTI_Line & 0x1F)); + *(__IO uint32_t *) (((uint32_t) &(EXTI->EMR)) + ((EXTI_InitStruct->EXTI_Line) >> 5 ) * 0x20) &= ~(uint32_t)(1 << (EXTI_InitStruct->EXTI_Line & 0x1F)); + + tmp += EXTI_InitStruct->EXTI_Mode + (((EXTI_InitStruct->EXTI_Line) >> 5 ) * 0x20); + + *(__IO uint32_t *) tmp |= (uint32_t)(1 << (EXTI_InitStruct->EXTI_Line & 0x1F)); + + tmp = (uint32_t)EXTI_BASE; + + /* Clear Rising Falling edge configuration */ + *(__IO uint32_t *) (((uint32_t) &(EXTI->RTSR)) + ((EXTI_InitStruct->EXTI_Line) >> 5 ) * 0x20) &= ~(uint32_t)(1 << (EXTI_InitStruct->EXTI_Line & 0x1F)); + *(__IO uint32_t *) (((uint32_t) &(EXTI->FTSR)) + ((EXTI_InitStruct->EXTI_Line) >> 5 ) * 0x20) &= ~(uint32_t)(1 << (EXTI_InitStruct->EXTI_Line & 0x1F)); + + /* Select the trigger for the selected interrupts */ + if (EXTI_InitStruct->EXTI_Trigger == EXTI_Trigger_Rising_Falling) + { + /* Rising Falling edge */ + *(__IO uint32_t *) (((uint32_t) &(EXTI->RTSR)) + ((EXTI_InitStruct->EXTI_Line) >> 5 ) * 0x20) |= (uint32_t)(1 << (EXTI_InitStruct->EXTI_Line & 0x1F)); + *(__IO uint32_t *) (((uint32_t) &(EXTI->FTSR)) + ((EXTI_InitStruct->EXTI_Line) >> 5 ) * 0x20) |= (uint32_t)(1 << (EXTI_InitStruct->EXTI_Line & 0x1F)); + } + else + { + tmp += EXTI_InitStruct->EXTI_Trigger + (((EXTI_InitStruct->EXTI_Line) >> 5 ) * 0x20); + + *(__IO uint32_t *) tmp |= (uint32_t)(1 << (EXTI_InitStruct->EXTI_Line & 0x1F)); + } + } + + else + { + tmp += EXTI_InitStruct->EXTI_Mode + (((EXTI_InitStruct->EXTI_Line) >> 5 ) * 0x20); + + /* Disable the selected external lines */ + *(__IO uint32_t *) tmp &= ~(uint32_t)(1 << (EXTI_InitStruct->EXTI_Line & 0x1F)); + } + +} + +/** + * @brief Fills each EXTI_InitStruct member with its reset value. + * @param EXTI_InitStruct: pointer to a EXTI_InitTypeDef structure which will + * be initialized. + * @retval None + */ +void EXTI_StructInit(EXTI_InitTypeDef* EXTI_InitStruct) +{ + EXTI_InitStruct->EXTI_Line = EXTI_LINENONE; + EXTI_InitStruct->EXTI_Mode = EXTI_Mode_Interrupt; + EXTI_InitStruct->EXTI_Trigger = EXTI_Trigger_Rising_Falling; + EXTI_InitStruct->EXTI_LineCmd = DISABLE; +} + +/** + * @brief Generates a Software interrupt on selected EXTI line. + * @param EXTI_Line: specifies the EXTI line on which the software interrupt + * will be generated. + * This parameter can be any combination of EXTI_Linex where x can be (0..20). + * @retval None + */ +void EXTI_GenerateSWInterrupt(uint32_t EXTI_Line) +{ + /* Check the parameters */ + assert_param(IS_EXTI_LINE_EXT(EXTI_Line)); + + *(__IO uint32_t *) (((uint32_t) &(EXTI->SWIER)) + ((EXTI_Line) >> 5 ) * 0x20) |= (uint32_t)(1 << (EXTI_Line & 0x1F)); + +} + +/** + * @} + */ + +/** @defgroup EXTI_Group2 Interrupts and flags management functions + * @brief EXTI Interrupts and flags management functions + * +@verbatim + =============================================================================== + ##### Interrupts and flags management functions ##### + =============================================================================== + [..] + This section provides functions allowing to configure the EXTI Interrupts + sources and check or clear the flags or pending bits status. + +@endverbatim + * @{ + */ + +/** + * @brief Checks whether the specified EXTI line flag is set or not. + * @param EXTI_Line: specifies the EXTI line flag to check. + * This parameter can be any combination of EXTI_Linex where x can be (0..20). + * @retval The new state of EXTI_Line (SET or RESET). + */ +FlagStatus EXTI_GetFlagStatus(uint32_t EXTI_Line) +{ + FlagStatus bitstatus = RESET; + + /* Check the parameters */ + assert_param(IS_GET_EXTI_LINE(EXTI_Line)); + + if ((*(__IO uint32_t *) (((uint32_t) &(EXTI->PR)) + ((EXTI_Line) >> 5 ) * 0x20)& (uint32_t)(1 << (EXTI_Line & 0x1F))) != (uint32_t)RESET) + { + bitstatus = SET; + } + else + { + bitstatus = RESET; + } + return bitstatus; +} + +/** + * @brief Clears the EXTI's line pending flags. + * @param EXTI_Line: specifies the EXTI lines flags to clear. + * This parameter can be any combination of EXTI_Linex where x can be (0..20). + * @retval None + */ +void EXTI_ClearFlag(uint32_t EXTI_Line) +{ + /* Check the parameters */ + assert_param(IS_EXTI_LINE_EXT(EXTI_Line)); + + *(__IO uint32_t *) (((uint32_t) &(EXTI->PR)) + ((EXTI_Line) >> 5 ) * 0x20) = (1 << (EXTI_Line & 0x1F)); +} + +/** + * @brief Checks whether the specified EXTI line is asserted or not. + * @param EXTI_Line: specifies the EXTI line to check. + * This parameter can be any combination of EXTI_Linex where x can be (0..20). + * @retval The new state of EXTI_Line (SET or RESET). + */ +ITStatus EXTI_GetITStatus(uint32_t EXTI_Line) +{ + ITStatus bitstatus = RESET; + + /* Check the parameters */ + assert_param(IS_GET_EXTI_LINE(EXTI_Line)); + + if ((*(__IO uint32_t *) (((uint32_t) &(EXTI->PR)) + ((EXTI_Line) >> 5 ) * 0x20)& (uint32_t)(1 << (EXTI_Line & 0x1F))) != (uint32_t)RESET) + { + bitstatus = SET; + } + else + { + bitstatus = RESET; + } + return bitstatus; + +} + +/** + * @brief Clears the EXTI's line pending bits. + * @param EXTI_Line: specifies the EXTI lines to clear. + * This parameter can be any combination of EXTI_Linex where x can be (0..20). + * @retval None + */ +void EXTI_ClearITPendingBit(uint32_t EXTI_Line) +{ + /* Check the parameters */ + assert_param(IS_EXTI_LINE_EXT(EXTI_Line)); + + *(__IO uint32_t *) (((uint32_t) &(EXTI->PR)) + ((EXTI_Line) >> 5 ) * 0x20) = (1 << (EXTI_Line & 0x1F)); +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_flash.c b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_flash.c new file mode 100755 index 0000000000..de327143a3 --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_flash.c @@ -0,0 +1,1186 @@ +/** + ****************************************************************************** + * @file stm32f30x_flash.c + * @author MCD Application Team + * @version V1.2.3 + * @date 10-July-2015 + * @brief This file provides firmware functions to manage the following + * functionalities of the FLASH peripheral: + * + FLASH Interface configuration + * + FLASH Memory Programming + * + Option Bytes Programming + * + Interrupts and flags management + * + @verbatim + + =============================================================================== + ##### How to use this driver ##### + =============================================================================== + [..] This driver provides functions to configure and program the FLASH + memory of all STM32F30x devices. These functions are split in 4 groups: + (#) FLASH Interface configuration functions: this group includes the + management of following features: + (++) Set the latency. + (++) Enable/Disable the Half Cycle Access. + (++) Enable/Disable the prefetch buffer. + (#) FLASH Memory Programming functions: this group includes all needed + functions to erase and program the main memory: + (++) Lock and Unlock the FLASH interface. + (++) Erase function: Erase page, erase all pages. + (++) Program functions: Half Word and Word write. + (#) FLASH Option Bytes Programming functions: this group includes all + needed functions to manage the Option Bytes: + (++) Lock and Unlock the Flash Option bytes. + (++) Launch the Option Bytes loader + (++) Erase the Option Bytes + (++) Set/Reset the write protection + (++) Set the Read protection Level + (++) Program the user option Bytes + (++) Set/Reset the BOOT1 bit + (++) Enable/Disable the VDDA Analog Monitoring + (++) Enable/Disable the SRAM parity + (++) Get the user option bytes + (++) Get the Write protection + (++) Get the read protection status + (#) FLASH Interrupts and flags management functions: this group includes + all needed functions to: + (++) Enable/Disable the FLASH interrupt sources. + (++) Get flags status. + (++) Clear flags. + (++) Get FLASH operation status. + (++) Wait for last FLASH operation. + + @endverbatim + + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f30x_flash.h" + +/** @addtogroup STM32F30x_StdPeriph_Driver + * @{ + */ + +/** @defgroup FLASH + * @brief FLASH driver modules + * @{ + */ + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ + +/* FLASH Mask */ +#define RDPRT_MASK ((uint32_t)0x00000002) +#define WRP01_MASK ((uint32_t)0x0000FFFF) +#define WRP23_MASK ((uint32_t)0xFFFF0000) +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/* Private function prototypes -----------------------------------------------*/ +/* Private functions ---------------------------------------------------------*/ + +/** @defgroup FLASH_Private_Functions + * @{ + */ + +/** @defgroup FLASH_Group1 FLASH Interface configuration functions + * @brief FLASH Interface configuration functions + * + +@verbatim + =============================================================================== + ##### FLASH Interface configuration functions ##### + =============================================================================== + [..] This group includes the following functions: + (+) void FLASH_SetLatency(uint32_t FLASH_Latency); + (+) void FLASH_HalfCycleAccessCmd(uint32_t FLASH_HalfCycleAccess); + (+) void FLASH_PrefetchBufferCmd(FunctionalState NewState); + [..] The unlock sequence is not needed for these functions. + +@endverbatim + * @{ + */ + +/** + * @brief Sets the code latency value. + * @param FLASH_Latency: specifies the FLASH Latency value. + * This parameter can be one of the following values: + * @arg FLASH_Latency_0: FLASH Zero Latency cycle + * @arg FLASH_Latency_1: FLASH One Latency cycle + * @arg FLASH_Latency_2: FLASH Two Latency cycles + * @retval None + */ +void FLASH_SetLatency(uint32_t FLASH_Latency) +{ + uint32_t tmpreg = 0; + + /* Check the parameters */ + assert_param(IS_FLASH_LATENCY(FLASH_Latency)); + + /* Read the ACR register */ + tmpreg = FLASH->ACR; + + /* Sets the Latency value */ + tmpreg &= (uint32_t) (~((uint32_t)FLASH_ACR_LATENCY)); + tmpreg |= FLASH_Latency; + + /* Write the ACR register */ + FLASH->ACR = tmpreg; +} + +/** + * @brief Enables or disables the Half cycle flash access. + * @param FLASH_HalfCycleAccess: specifies the FLASH Half cycle Access mode. + * This parameter can be one of the following values: + * @arg FLASH_HalfCycleAccess_Enable: FLASH Half Cycle Enable + * @arg FLASH_HalfCycleAccess_Disable: FLASH Half Cycle Disable + * @retval None + */ +void FLASH_HalfCycleAccessCmd(FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if(NewState != DISABLE) + { + FLASH->ACR |= FLASH_ACR_HLFCYA; + } + else + { + FLASH->ACR &= (uint32_t)(~((uint32_t)FLASH_ACR_HLFCYA)); + } +} + +/** + * @brief Enables or disables the Prefetch Buffer. + * @param NewState: new state of the Prefetch Buffer. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void FLASH_PrefetchBufferCmd(FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if(NewState != DISABLE) + { + FLASH->ACR |= FLASH_ACR_PRFTBE; + } + else + { + FLASH->ACR &= (uint32_t)(~((uint32_t)FLASH_ACR_PRFTBE)); + } +} + +/** + * @} + */ + +/** @defgroup FLASH_Group2 FLASH Memory Programming functions + * @brief FLASH Memory Programming functions + * +@verbatim + =============================================================================== + ##### FLASH Memory Programming functions ##### + =============================================================================== + [..] This group includes the following functions: + (+) void FLASH_Unlock(void); + (+) void FLASH_Lock(void); + (+) FLASH_Status FLASH_ErasePage(uint32_t Page_Address); + (+) FLASH_Status FLASH_EraseAllPages(void); + (+) FLASH_Status FLASH_ProgramWord(uint32_t Address, uint32_t Data); + (+) FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data); + [..] Any operation of erase or program should follow these steps: + (#) Call the FLASH_Unlock() function to enable the FLASH control register + program memory access. + (#) Call the desired function to erase page or program data. + (#) Call the FLASH_Lock() function to disable the FLASH control register + access (recommended to protect the FLASH memory against possible + unwanted operation). + +@endverbatim + * @{ + */ + +/** + * @brief Unlocks the FLASH control register access + * @param None + * @retval None + */ +void FLASH_Unlock(void) +{ + if((FLASH->CR & FLASH_CR_LOCK) != RESET) + { + /* Authorize the FLASH Registers access */ + FLASH->KEYR = FLASH_KEY1; + FLASH->KEYR = FLASH_KEY2; + } +} + +/** + * @brief Locks the FLASH control register access + * @param None + * @retval None + */ +void FLASH_Lock(void) +{ + /* Set the LOCK Bit to lock the FLASH Registers access */ + FLASH->CR |= FLASH_CR_LOCK; +} + +/** + * @brief Erases a specified page in program memory. + * @note To correctly run this function, the FLASH_Unlock() function + * must be called before. + * @note Call the FLASH_Lock() to disable the flash memory access + * (recommended to protect the FLASH memory against possible unwanted operation) + * @param Page_Address: The page address in program memory to be erased. + * @note A Page is erased in the Program memory only if the address to load + * is the start address of a page (multiple of 1024 bytes). + * @retval FLASH Status: The returned value can be: + * FLASH_ERROR_PROGRAM, FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT. + */ +FLASH_Status FLASH_ErasePage(uint32_t Page_Address) +{ + FLASH_Status status = FLASH_COMPLETE; + + /* Check the parameters */ + assert_param(IS_FLASH_PROGRAM_ADDRESS(Page_Address)); + + /* Wait for last operation to be completed */ + status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT); + + if(status == FLASH_COMPLETE) + { + /* If the previous operation is completed, proceed to erase the page */ + FLASH->CR |= FLASH_CR_PER; + FLASH->AR = Page_Address; + FLASH->CR |= FLASH_CR_STRT; + + /* Wait for last operation to be completed */ + status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT); + + /* Disable the PER Bit */ + FLASH->CR &= ~FLASH_CR_PER; + } + + /* Return the Erase Status */ + return status; +} + +/** + * @brief Erases all FLASH pages. + * @note To correctly run this function, the FLASH_Unlock() function + * must be called before. + * all the FLASH_Lock() to disable the flash memory access + * (recommended to protect the FLASH memory against possible unwanted operation) + * @param None + * @retval FLASH Status: The returned value can be: FLASH_ERROR_PG, + * FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT. + */ +FLASH_Status FLASH_EraseAllPages(void) +{ + FLASH_Status status = FLASH_COMPLETE; + + /* Wait for last operation to be completed */ + status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT); + + if(status == FLASH_COMPLETE) + { + /* if the previous operation is completed, proceed to erase all pages */ + FLASH->CR |= FLASH_CR_MER; + FLASH->CR |= FLASH_CR_STRT; + + /* Wait for last operation to be completed */ + status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT); + + /* Disable the MER Bit */ + FLASH->CR &= ~FLASH_CR_MER; + } + + /* Return the Erase Status */ + return status; +} + +/** + * @brief Programs a word at a specified address. + * @note To correctly run this function, the FLASH_Unlock() function + * must be called before. + * Call the FLASH_Lock() to disable the flash memory access + * (recommended to protect the FLASH memory against possible unwanted operation) + * @param Address: specifies the address to be programmed. + * @param Data: specifies the data to be programmed. + * @retval FLASH Status: The returned value can be: FLASH_ERROR_PG, + * FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT. + */ +FLASH_Status FLASH_ProgramWord(uint32_t Address, uint32_t Data) +{ + FLASH_Status status = FLASH_COMPLETE; + __IO uint32_t tmp = 0; + + /* Check the parameters */ + assert_param(IS_FLASH_PROGRAM_ADDRESS(Address)); + + /* Wait for last operation to be completed */ + status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT); + + if(status == FLASH_COMPLETE) + { + /* If the previous operation is completed, proceed to program the new first + half word */ + FLASH->CR |= FLASH_CR_PG; + + *(__IO uint16_t*)Address = (uint16_t)Data; + + /* Wait for last operation to be completed */ + status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT); + + if(status == FLASH_COMPLETE) + { + /* If the previous operation is completed, proceed to program the new second + half word */ + tmp = Address + 2; + + *(__IO uint16_t*) tmp = Data >> 16; + + /* Wait for last operation to be completed */ + status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT); + + /* Disable the PG Bit */ + FLASH->CR &= ~FLASH_CR_PG; + } + else + { + /* Disable the PG Bit */ + FLASH->CR &= ~FLASH_CR_PG; + } + } + + /* Return the Program Status */ + return status; +} + +/** + * @brief Programs a half word at a specified address. + * @note To correctly run this function, the FLASH_Unlock() function + * must be called before. + * Call the FLASH_Lock() to disable the flash memory access + * (recommended to protect the FLASH memory against possible unwanted operation) + * @param Address: specifies the address to be programmed. + * @param Data: specifies the data to be programmed. + * @retval FLASH Status: The returned value can be: FLASH_ERROR_PG, + * FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT. + */ +FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data) +{ + FLASH_Status status = FLASH_COMPLETE; + + /* Check the parameters */ + assert_param(IS_FLASH_PROGRAM_ADDRESS(Address)); + + /* Wait for last operation to be completed */ + status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT); + + if(status == FLASH_COMPLETE) + { + /* If the previous operation is completed, proceed to program the new data */ + FLASH->CR |= FLASH_CR_PG; + + *(__IO uint16_t*)Address = Data; + + /* Wait for last operation to be completed */ + status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT); + + /* Disable the PG Bit */ + FLASH->CR &= ~FLASH_CR_PG; + } + + /* Return the Program Status */ + return status; +} + +/** + * @} + */ + +/** @defgroup FLASH_Group3 Option Bytes Programming functions + * @brief Option Bytes Programming functions + * +@verbatim + =============================================================================== + ##### Option Bytes Programming functions ##### + =============================================================================== + [..] This group includes the following functions: + (+) void FLASH_OB_Unlock(void); + (+) void FLASH_OB_Lock(void); + (+) void FLASH_OB_Erase(void); + (+) FLASH_Status FLASH_OB_WRPConfig(uint32_t OB_WRP, FunctionalState NewState); + (+) FLASH_Status FLASH_OB_RDPConfig(uint8_t OB_RDP); + (+) FLASH_Status FLASH_OB_UserConfig(uint8_t OB_IWDG, uint8_t OB_STOP, uint8_t OB_STDBY); + (+) FLASH_Status FLASH_OB_BOOTConfig(uint8_t OB_BOOT1); + (+) FLASH_Status FLASH_OB_VDDAConfig(uint8_t OB_VDDA_ANALOG); + (+) FLASH_Status FLASH_OB_SRMParityConfig(uint8_t OB_SRAM_Parity); + (+) FLASH_Status FLASH_OB_WriteUser(uint8_t OB_USER); + (+) FLASH_Status FLASH_OB_Launch(void); + (+) uint32_t FLASH_OB_GetUser(void); + (+) uint8_t FLASH_OB_GetWRP(void); + (+) uint8_t FLASH_OB_GetRDP(void); + [..] Any operation of erase or program should follow these steps: + (#) Call the FLASH_OB_Unlock() function to enable the FLASH option control + register access. + (#) Call one or several functions to program the desired Option Bytes: + (++) void FLASH_OB_WRPConfig(uint32_t OB_WRP, FunctionalState NewState); + => to Enable/Disable the desired sector write protection. + (++) FLASH_Status FLASH_OB_RDPConfig(uint8_t OB_RDP) => to set the + desired read Protection Level. + (++) FLASH_Status FLASH_OB_UserConfig(uint8_t OB_IWDG, uint8_t OB_STOP, uint8_t OB_STDBY); + => to configure the user Option Bytes. + (++) FLASH_Status FLASH_OB_BOOTConfig(uint8_t OB_BOOT1); + => to set the boot1 mode + (++) FLASH_Status FLASH_OB_VDDAConfig(uint8_t OB_VDDA_ANALOG); + => to Enable/Disable the VDDA monitoring. + (++) FLASH_Status FLASH_OB_SRMParityConfig(uint8_t OB_SRAM_Parity); + => to Enable/Disable the SRAM Parity check. + (++) FLASH_Status FLASH_OB_WriteUser(uint8_t OB_USER); + => to write all user option bytes: OB_IWDG, OB_STOP, OB_STDBY, + OB_BOOT1, OB_VDDA_ANALOG and OB_VDD_SD12. + (#) Once all needed Option Bytes to be programmed are correctly written, + call the FLASH_OB_Launch() function to launch the Option Bytes + programming process. + (#@) When changing the IWDG mode from HW to SW or from SW to HW, a system + reset is needed to make the change effective. + (#) Call the FLASH_OB_Lock() function to disable the FLASH option control + register access (recommended to protect the Option Bytes against + possible unwanted operations). + +@endverbatim + * @{ + */ + +/** + * @brief Unlocks the option bytes block access. + * @param None + * @retval None + */ +void FLASH_OB_Unlock(void) +{ + if((FLASH->CR & FLASH_CR_OPTWRE) == RESET) + { + /* Unlocking the option bytes block access */ + FLASH->OPTKEYR = FLASH_OPTKEY1; + FLASH->OPTKEYR = FLASH_OPTKEY2; + } +} + +/** + * @brief Locks the option bytes block access. + * @param None + * @retval None + */ +void FLASH_OB_Lock(void) +{ + /* Set the OPTWREN Bit to lock the option bytes block access */ + FLASH->CR &= ~FLASH_CR_OPTWRE; +} + +/** + * @brief Launch the option byte loading. + * @param None + * @retval None + */ +void FLASH_OB_Launch(void) +{ + /* Set the OBL_Launch bit to launch the option byte loading */ + FLASH->CR |= FLASH_CR_OBL_LAUNCH; +} + +/** + * @brief Erases the FLASH option bytes. + * @note This functions erases all option bytes except the Read protection (RDP). + * @param None + * @retval FLASH Status: The returned value can be: FLASH_ERROR_PG, + * FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT. + */ +FLASH_Status FLASH_OB_Erase(void) +{ + uint16_t rdptmp = OB_RDP_Level_0; + + FLASH_Status status = FLASH_COMPLETE; + + /* Get the actual read protection Option Byte value */ + if(FLASH_OB_GetRDP() != RESET) + { + rdptmp = 0x00; + } + + /* Wait for last operation to be completed */ + status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT); + + if(status == FLASH_COMPLETE) + { + /* If the previous operation is completed, proceed to erase the option bytes */ + FLASH->CR |= FLASH_CR_OPTER; + FLASH->CR |= FLASH_CR_STRT; + + /* Wait for last operation to be completed */ + status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT); + + if(status == FLASH_COMPLETE) + { + /* If the erase operation is completed, disable the OPTER Bit */ + FLASH->CR &= ~FLASH_CR_OPTER; + + /* Enable the Option Bytes Programming operation */ + FLASH->CR |= FLASH_CR_OPTPG; + + /* Restore the last read protection Option Byte value */ + OB->RDP = (uint16_t)rdptmp; + + /* Wait for last operation to be completed */ + status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT); + + if(status != FLASH_TIMEOUT) + { + /* if the program operation is completed, disable the OPTPG Bit */ + FLASH->CR &= ~FLASH_CR_OPTPG; + } + } + else + { + if (status != FLASH_TIMEOUT) + { + /* Disable the OPTPG Bit */ + FLASH->CR &= ~FLASH_CR_OPTPG; + } + } + } + /* Return the erase status */ + return status; +} + +/** + * @brief Write protects the desired pages + * @note To correctly run this function, the FLASH_OB_Unlock() function + * must be called before. + * @note Call the FLASH_OB_Lock() to disable the flash control register access and the option bytes + * (recommended to protect the FLASH memory against possible unwanted operation) + * @param OB_WRP: specifies the address of the pages to be write protected. + * This parameter can be: + * @arg value between OB_WRP_Pages0to35 and OB_WRP_Pages60to63 + * @arg OB_WRP_AllPages + * @retval FLASH Status: The returned value can be: + * FLASH_ERROR_PROGRAM, FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT. + */ +FLASH_Status FLASH_OB_EnableWRP(uint32_t OB_WRP) +{ + uint16_t WRP0_Data = 0xFFFF, WRP1_Data = 0xFFFF, WRP2_Data = 0xFFFF, WRP3_Data = 0xFFFF; + + FLASH_Status status = FLASH_COMPLETE; + + /* Check the parameters */ + assert_param(IS_OB_WRP(OB_WRP)); + + OB_WRP = (uint32_t)(~OB_WRP); + WRP0_Data = (uint16_t)(OB_WRP & OB_WRP0_WRP0); + WRP1_Data = (uint16_t)((OB_WRP >> 8) & OB_WRP0_WRP0); + WRP2_Data = (uint16_t)((OB_WRP >> 16) & OB_WRP0_WRP0) ; + WRP3_Data = (uint16_t)((OB_WRP >> 24) & OB_WRP0_WRP0) ; + + /* Wait for last operation to be completed */ + status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT); + + if(status == FLASH_COMPLETE) + { + FLASH->CR |= FLASH_CR_OPTPG; + + if(WRP0_Data != 0xFF) + { + OB->WRP0 = WRP0_Data; + + /* Wait for last operation to be completed */ + status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT); + } + if((status == FLASH_COMPLETE) && (WRP1_Data != 0xFF)) + { + OB->WRP1 = WRP1_Data; + + /* Wait for last operation to be completed */ + status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT); + } + if((status == FLASH_COMPLETE) && (WRP2_Data != 0xFF)) + { + OB->WRP2 = WRP2_Data; + + /* Wait for last operation to be completed */ + status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT); + } + if((status == FLASH_COMPLETE) && (WRP3_Data != 0xFF)) + { + OB->WRP3 = WRP3_Data; + + /* Wait for last operation to be completed */ + status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT); + } + if(status != FLASH_TIMEOUT) + { + /* if the program operation is completed, disable the OPTPG Bit */ + FLASH->CR &= ~FLASH_CR_OPTPG; + } + } + /* Return the write protection operation Status */ + return status; +} + +/** + * @brief Enables or disables the read out protection. + * @note To correctly run this function, the FLASH_OB_Unlock() function + * must be called before. + * @note Call the FLASH_OB_Lock() to disable the flash control register access and the option bytes + * (recommended to protect the FLASH memory against possible unwanted operation) + * @param FLASH_ReadProtection_Level: specifies the read protection level. + * This parameter can be: + * @arg OB_RDP_Level_0: No protection + * @arg OB_RDP_Level_1: Read protection of the memory + * @arg OB_RDP_Level_2: Chip protection + * @retval FLASH Status: The returned value can be: + * FLASH_ERROR_PROGRAM, FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT. + */ +FLASH_Status FLASH_OB_RDPConfig(uint8_t OB_RDP) +{ + FLASH_Status status = FLASH_COMPLETE; + + /* Check the parameters */ + assert_param(IS_OB_RDP(OB_RDP)); + status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT); + + if(status == FLASH_COMPLETE) + { + FLASH->CR |= FLASH_CR_OPTER; + FLASH->CR |= FLASH_CR_STRT; + + /* Wait for last operation to be completed */ + status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT); + + if(status == FLASH_COMPLETE) + { + /* If the erase operation is completed, disable the OPTER Bit */ + FLASH->CR &= ~FLASH_CR_OPTER; + + /* Enable the Option Bytes Programming operation */ + FLASH->CR |= FLASH_CR_OPTPG; + + OB->RDP = OB_RDP; + + /* Wait for last operation to be completed */ + status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT); + + if(status != FLASH_TIMEOUT) + { + /* if the program operation is completed, disable the OPTPG Bit */ + FLASH->CR &= ~FLASH_CR_OPTPG; + } + } + else + { + if(status != FLASH_TIMEOUT) + { + /* Disable the OPTER Bit */ + FLASH->CR &= ~FLASH_CR_OPTER; + } + } + } + /* Return the protection operation Status */ + return status; +} + +/** + * @brief Programs the FLASH User Option Byte: IWDG_SW / RST_STOP / RST_STDBY. + * @param OB_IWDG: Selects the IWDG mode + * This parameter can be one of the following values: + * @arg OB_IWDG_SW: Software IWDG selected + * @arg OB_IWDG_HW: Hardware IWDG selected + * @param OB_STOP: Reset event when entering STOP mode. + * This parameter can be one of the following values: + * @arg OB_STOP_NoRST: No reset generated when entering in STOP + * @arg OB_STOP_RST: Reset generated when entering in STOP + * @param OB_STDBY: Reset event when entering Standby mode. + * This parameter can be one of the following values: + * @arg OB_STDBY_NoRST: No reset generated when entering in STANDBY + * @arg OB_STDBY_RST: Reset generated when entering in STANDBY + * @retval FLASH Status: The returned value can be: FLASH_ERROR_PG, + * FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT. + */ +FLASH_Status FLASH_OB_UserConfig(uint8_t OB_IWDG, uint8_t OB_STOP, uint8_t OB_STDBY) +{ + FLASH_Status status = FLASH_COMPLETE; + + /* Check the parameters */ + assert_param(IS_OB_IWDG_SOURCE(OB_IWDG)); + assert_param(IS_OB_STOP_SOURCE(OB_STOP)); + assert_param(IS_OB_STDBY_SOURCE(OB_STDBY)); + + /* Authorize the small information block programming */ + FLASH->OPTKEYR = FLASH_KEY1; + FLASH->OPTKEYR = FLASH_KEY2; + + /* Wait for last operation to be completed */ + status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT); + + if(status == FLASH_COMPLETE) + { + /* Enable the Option Bytes Programming operation */ + FLASH->CR |= FLASH_CR_OPTPG; + + OB->USER = (uint8_t)((uint8_t)(OB_IWDG | OB_STOP) | (uint8_t)(OB_STDBY |0xF8)); + + /* Wait for last operation to be completed */ + status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT); + + if(status != FLASH_TIMEOUT) + { + /* if the program operation is completed, disable the OPTPG Bit */ + FLASH->CR &= ~FLASH_CR_OPTPG; + } + } + /* Return the Option Byte program Status */ + return status; +} + +/** + * @brief Sets or resets the BOOT1. + * @param OB_BOOT1: Set or Reset the BOOT1. + * This parameter can be one of the following values: + * @arg OB_BOOT1_RESET: BOOT1 Reset + * @arg OB_BOOT1_SET: BOOT1 Set + * @retval None + */ +FLASH_Status FLASH_OB_BOOTConfig(uint8_t OB_BOOT1) +{ + FLASH_Status status = FLASH_COMPLETE; + + /* Check the parameters */ + assert_param(IS_OB_BOOT1(OB_BOOT1)); + + /* Authorize the small information block programming */ + FLASH->OPTKEYR = FLASH_KEY1; + FLASH->OPTKEYR = FLASH_KEY2; + + /* Wait for last operation to be completed */ + status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT); + + if(status == FLASH_COMPLETE) + { + /* Enable the Option Bytes Programming operation */ + FLASH->CR |= FLASH_CR_OPTPG; + + OB->USER = OB_BOOT1|0xEF; + + /* Wait for last operation to be completed */ + status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT); + + if(status != FLASH_TIMEOUT) + { + /* if the program operation is completed, disable the OPTPG Bit */ + FLASH->CR &= ~FLASH_CR_OPTPG; + } + } + /* Return the Option Byte program Status */ + return status; +} + +/** + * @brief Sets or resets the analogue monitoring on VDDA Power source. + * @param OB_VDDA_ANALOG: Selects the analog monitoring on VDDA Power source. + * This parameter can be one of the following values: + * @arg OB_VDDA_ANALOG_ON: Analog monitoring on VDDA Power source ON + * @arg OB_VDDA_ANALOG_OFF: Analog monitoring on VDDA Power source OFF + * @retval None + */ +FLASH_Status FLASH_OB_VDDAConfig(uint8_t OB_VDDA_ANALOG) +{ + FLASH_Status status = FLASH_COMPLETE; + + /* Check the parameters */ + assert_param(IS_OB_VDDA_ANALOG(OB_VDDA_ANALOG)); + + /* Authorize the small information block programming */ + FLASH->OPTKEYR = FLASH_KEY1; + FLASH->OPTKEYR = FLASH_KEY2; + + /* Wait for last operation to be completed */ + status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT); + + if(status == FLASH_COMPLETE) + { + /* Enable the Option Bytes Programming operation */ + FLASH->CR |= FLASH_CR_OPTPG; + + OB->USER = OB_VDDA_ANALOG |0xDF; + + /* Wait for last operation to be completed */ + status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT); + + if(status != FLASH_TIMEOUT) + { + /* if the program operation is completed, disable the OPTPG Bit */ + FLASH->CR &= ~FLASH_CR_OPTPG; + } + } + /* Return the Option Byte program Status */ + return status; +} + +/** + * @brief Sets or resets the SRAM parity. + * @param OB_SRAM_Parity: Set or Reset the SRAM parity enable bit. + * This parameter can be one of the following values: + * @arg OB_SRAM_PARITY_SET: Set SRAM parity. + * @arg OB_SRAM_PARITY_RESET: Reset SRAM parity. + * @retval None + */ +FLASH_Status FLASH_OB_SRAMParityConfig(uint8_t OB_SRAM_Parity) +{ + FLASH_Status status = FLASH_COMPLETE; + + /* Check the parameters */ + assert_param(IS_OB_SRAM_PARITY(OB_SRAM_Parity)); + + /* Wait for last operation to be completed */ + status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT); + + if(status == FLASH_COMPLETE) + { + /* Enable the Option Bytes Programming operation */ + FLASH->CR |= FLASH_CR_OPTPG; + + OB->USER = OB_SRAM_Parity | 0xBF; + + /* Wait for last operation to be completed */ + status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT); + + if(status != FLASH_TIMEOUT) + { + /* if the program operation is completed, disable the OPTPG Bit */ + FLASH->CR &= ~FLASH_CR_OPTPG; + } + } + /* Return the Option Byte program Status */ + return status; +} + +/** + * @brief Programs the FLASH User Option Byte: IWDG_SW / RST_STOP / RST_STDBY/ BOOT1 and OB_VDDA_ANALOG. + * @note To correctly run this function, the FLASH_OB_Unlock() function + * must be called before. + * @note Call the FLASH_OB_Lock() to disable the flash control register access and the option bytes + * (recommended to protect the FLASH memory against possible unwanted operation) + * @param OB_USER: Selects all user option bytes + * This parameter is a combination of the following values: + * @arg OB_IWDG_SW / OB_IWDG_HW: Software / Hardware WDG selected + * @arg OB_STOP_NoRST / OB_STOP_RST: No reset / Reset generated when entering in STOP + * @arg OB_STDBY_NoRST / OB_STDBY_RST: No reset / Reset generated when entering in STANDBY + * @arg OB_BOOT1_RESET / OB_BOOT1_SET: BOOT1 Reset / Set + * @arg OB_VDDA_ANALOG_ON / OB_VDDA_ANALOG_OFF: Analog monitoring on VDDA Power source ON / OFF + * @retval FLASH Status: The returned value can be: + * FLASH_ERROR_PROGRAM, FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT. + */ +FLASH_Status FLASH_OB_WriteUser(uint8_t OB_USER) +{ + FLASH_Status status = FLASH_COMPLETE; + + /* Authorize the small information block programming */ + FLASH->OPTKEYR = FLASH_KEY1; + FLASH->OPTKEYR = FLASH_KEY2; + + /* Wait for last operation to be completed */ + status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT); + + if(status == FLASH_COMPLETE) + { + /* Enable the Option Bytes Programming operation */ + FLASH->CR |= FLASH_CR_OPTPG; + + OB->USER = OB_USER | 0x88; + + /* Wait for last operation to be completed */ + status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT); + + if(status != FLASH_TIMEOUT) + { + /* if the program operation is completed, disable the OPTPG Bit */ + FLASH->CR &= ~FLASH_CR_OPTPG; + } + } + /* Return the Option Byte program Status */ + return status; + +} + +/** + * @brief Programs a half word at a specified Option Byte Data address. + * @note To correctly run this function, the FLASH_OB_Unlock() function + * must be called before. + * Call the FLASH_OB_Lock() to disable the flash control register access and the option bytes + * (recommended to protect the FLASH memory against possible unwanted operation) + * @param Address: specifies the address to be programmed. + * This parameter can be 0x1FFFF804 or 0x1FFFF806. + * @param Data: specifies the data to be programmed. + * @retval FLASH Status: The returned value can be: FLASH_ERROR_PG, + * FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT. + */ +FLASH_Status FLASH_ProgramOptionByteData(uint32_t Address, uint8_t Data) +{ + FLASH_Status status = FLASH_COMPLETE; + /* Check the parameters */ + assert_param(IS_OB_DATA_ADDRESS(Address)); + status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT); + + if(status == FLASH_COMPLETE) + { + /* Enables the Option Bytes Programming operation */ + FLASH->CR |= FLASH_CR_OPTPG; + *(__IO uint16_t*)Address = Data; + + /* Wait for last operation to be completed */ + status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT); + + if(status != FLASH_TIMEOUT) + { + /* If the program operation is completed, disable the OPTPG Bit */ + FLASH->CR &= ~FLASH_CR_OPTPG; + } + } + /* Return the Option Byte Data Program Status */ + return status; +} + +/** + * @brief Returns the FLASH User Option Bytes values. + * @param None + * @retval The FLASH User Option Bytes . + */ +uint8_t FLASH_OB_GetUser(void) +{ + /* Return the User Option Byte */ + return (uint8_t)(FLASH->OBR >> 8); +} + +/** + * @brief Returns the FLASH Write Protection Option Bytes value. + * @param None + * @retval The FLASH Write Protection Option Bytes value + */ +uint32_t FLASH_OB_GetWRP(void) +{ + /* Return the FLASH write protection Register value */ + return (uint32_t)(FLASH->WRPR); +} + +/** + * @brief Checks whether the FLASH Read out Protection Status is set or not. + * @param None + * @retval FLASH ReadOut Protection Status(SET or RESET) + */ +FlagStatus FLASH_OB_GetRDP(void) +{ + FlagStatus readstatus = RESET; + + if ((uint8_t)(FLASH->OBR & (FLASH_OBR_RDPRT1 | FLASH_OBR_RDPRT2)) != RESET) + { + readstatus = SET; + } + else + { + readstatus = RESET; + } + return readstatus; +} + +/** + * @} + */ + +/** @defgroup FLASH_Group4 Interrupts and flags management functions + * @brief Interrupts and flags management functions + * +@verbatim + =============================================================================== + ##### Interrupts and flags management functions ##### + =============================================================================== + +@endverbatim + * @{ + */ + +/** + * @brief Enables or disables the specified FLASH interrupts. + * @param FLASH_IT: specifies the FLASH interrupt sources to be enabled or + * disabled. + * This parameter can be any combination of the following values: + * @arg FLASH_IT_EOP: FLASH end of programming Interrupt + * @arg FLASH_IT_ERR: FLASH Error Interrupt + * @retval None + */ +void FLASH_ITConfig(uint32_t FLASH_IT, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_FLASH_IT(FLASH_IT)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if(NewState != DISABLE) + { + /* Enable the interrupt sources */ + FLASH->CR |= FLASH_IT; + } + else + { + /* Disable the interrupt sources */ + FLASH->CR &= ~(uint32_t)FLASH_IT; + } +} + +/** + * @brief Checks whether the specified FLASH flag is set or not. + * @param FLASH_FLAG: specifies the FLASH flag to check. + * This parameter can be one of the following values: + * @arg FLASH_FLAG_BSY: FLASH write/erase operations in progress flag + * @arg FLASH_FLAG_PGERR: FLASH Programming error flag + * @arg FLASH_FLAG_WRPERR: FLASH Write protected error flag + * @arg FLASH_FLAG_EOP: FLASH End of Programming flag + * @retval The new state of FLASH_FLAG (SET or RESET). + */ +FlagStatus FLASH_GetFlagStatus(uint32_t FLASH_FLAG) +{ + FlagStatus bitstatus = RESET; + + /* Check the parameters */ + assert_param(IS_FLASH_GET_FLAG(FLASH_FLAG)); + + if((FLASH->SR & FLASH_FLAG) != (uint32_t)RESET) + { + bitstatus = SET; + } + else + { + bitstatus = RESET; + } + /* Return the new state of FLASH_FLAG (SET or RESET) */ + return bitstatus; +} + +/** + * @brief Clears the FLASH's pending flags. + * @param FLASH_FLAG: specifies the FLASH flags to clear. + * This parameter can be any combination of the following values: + * @arg FLASH_FLAG_PGERR: FLASH Programming error flag + * @arg FLASH_FLAG_WRPERR: FLASH Write protected error flag + * @arg FLASH_FLAG_EOP: FLASH End of Programming flag + * @retval None + */ +void FLASH_ClearFlag(uint32_t FLASH_FLAG) +{ + /* Check the parameters */ + assert_param(IS_FLASH_CLEAR_FLAG(FLASH_FLAG)); + + /* Clear the flags */ + FLASH->SR = FLASH_FLAG; +} + +/** + * @brief Returns the FLASH Status. + * @param None + * @retval FLASH Status: The returned value can be: + * FLASH_BUSY, FLASH_ERROR_PROGRAM, FLASH_ERROR_WRP or FLASH_COMPLETE. + */ +FLASH_Status FLASH_GetStatus(void) +{ + FLASH_Status FLASHstatus = FLASH_COMPLETE; + + if((FLASH->SR & FLASH_FLAG_BSY) == FLASH_FLAG_BSY) + { + FLASHstatus = FLASH_BUSY; + } + else + { + if((FLASH->SR & (uint32_t)FLASH_FLAG_WRPERR)!= (uint32_t)0x00) + { + FLASHstatus = FLASH_ERROR_WRP; + } + else + { + if((FLASH->SR & (uint32_t)(FLASH_SR_PGERR)) != (uint32_t)0x00) + { + FLASHstatus = FLASH_ERROR_PROGRAM; + } + else + { + FLASHstatus = FLASH_COMPLETE; + } + } + } + /* Return the FLASH Status */ + return FLASHstatus; +} + +/** + * @brief Waits for a FLASH operation to complete or a TIMEOUT to occur. + * @param Timeout: FLASH programming Timeout + * @retval FLASH Status: The returned value can be: FLASH_BUSY, + * FLASH_ERROR_PROGRAM, FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT. + */ +FLASH_Status FLASH_WaitForLastOperation(uint32_t Timeout) +{ + FLASH_Status status = FLASH_COMPLETE; + + /* Check for the FLASH Status */ + status = FLASH_GetStatus(); + + /* Wait for a FLASH operation to complete or a TIMEOUT to occur */ + while((status == FLASH_BUSY) && (Timeout != 0x00)) + { + status = FLASH_GetStatus(); + Timeout--; + } + + if(Timeout == 0x00 ) + { + status = FLASH_TIMEOUT; + } + /* Return the operation status */ + return status; +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_fmc.c b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_fmc.c new file mode 100755 index 0000000000..4c55198f64 --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_fmc.c @@ -0,0 +1,1001 @@ +/** + ****************************************************************************** + * @file stm32f30x_fmc.c + * @author MCD Application Team + * @version V1.2.3 + * @date 10-July-2015 + * @brief This file provides firmware functions to manage the following + * functionalities of the FMC peripheral: + * + Interface with SRAM, PSRAM, NOR and OneNAND memories + * + Interface with NAND memories + * + Interface with 16-bit PC Card compatible memories + * + Interrupts and flags management + * + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f30x_fmc.h" +#include "stm32f30x_rcc.h" + +/** @addtogroup STM32F30x_StdPeriph_Driver + * @{ + */ + +/** @defgroup FMC + * @brief FMC driver modules + * @{ + */ + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ + +/* --------------------- FMC registers bit mask ---------------------------- */ +/* FMC BCRx Mask */ +#define BCR_MBKEN_SET ((uint32_t)0x00000001) +#define BCR_MBKEN_RESET ((uint32_t)0x000FFFFE) +#define BCR_FACCEN_SET ((uint32_t)0x00000040) + +/* FMC PCRx Mask */ +#define PCR_PBKEN_SET ((uint32_t)0x00000004) +#define PCR_PBKEN_RESET ((uint32_t)0x000FFFFB) +#define PCR_ECCEN_SET ((uint32_t)0x00000040) +#define PCR_ECCEN_RESET ((uint32_t)0x000FFFBF) +#define PCR_MEMORYTYPE_NAND ((uint32_t)0x00000008) + +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/* Private function prototypes -----------------------------------------------*/ +/* Private functions ---------------------------------------------------------*/ + +/** @defgroup FMC_Private_Functions + * @{ + */ + +/** @defgroup FMC_Group1 NOR/SRAM Controller functions + * @brief NOR/SRAM Controller functions + * +@verbatim + =============================================================================== + ##### NOR and SRAM Controller functions ##### + =============================================================================== + + [..] The following sequence should be followed to configure the FMC to interface + with SRAM, PSRAM, NOR or OneNAND memory connected to the NOR/SRAM Bank: + + (#) Enable the clock for the FMC and associated GPIOs using the following functions: + RCC_AHB3PeriphClockCmd(RCC_AHB3Periph_FMC, ENABLE); + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOx, ENABLE); + + (#) FMC pins configuration + (++) Connect the involved FMC pins to AF12 using the following function + GPIO_PinAFConfig(GPIOx, GPIO_PinSourcex, GPIO_AF_FMC); + (++) Configure these FMC pins in alternate function mode by calling the function + GPIO_Init(); + + (#) Declare a FMC_NORSRAMInitTypeDef structure, for example: + FMC_NORSRAMInitTypeDef FMC_NORSRAMInitStructure; + and fill the FMC_NORSRAMInitStructure variable with the allowed values of + the structure member. + + (#) Initialize the NOR/SRAM Controller by calling the function + FMC_NORSRAMInit(&FMC_NORSRAMInitStructure); + + (#) Then enable the NOR/SRAM Bank, for example: + FMC_NORSRAMCmd(FMC_Bank1_NORSRAM2, ENABLE); + + (#) At this stage you can read/write from/to the memory connected to the NOR/SRAM Bank. + +@endverbatim + * @{ + */ + +/** + * @brief De-initializes the FMC NOR/SRAM Banks registers to their default + * reset values. + * @param FMC_Bank: specifies the FMC Bank to be used + * This parameter can be one of the following values: + * @arg FMC_Bank1_NORSRAM1: FMC Bank1 NOR/SRAM1 + * @arg FMC_Bank1_NORSRAM2: FMC Bank1 NOR/SRAM2 + * @arg FMC_Bank1_NORSRAM3: FMC Bank1 NOR/SRAM3 + * @arg FMC_Bank1_NORSRAM4: FMC Bank1 NOR/SRAM4 + * @retval None + */ +void FMC_NORSRAMDeInit(uint32_t FMC_Bank) +{ + /* Check the parameter */ + assert_param(IS_FMC_NORSRAM_BANK(FMC_Bank)); + + /* FMC_Bank1_NORSRAM1 */ + if(FMC_Bank == FMC_Bank1_NORSRAM1) + { + FMC_Bank1->BTCR[FMC_Bank] = 0x000030DB; + } + /* FMC_Bank1_NORSRAM2, FMC_Bank1_NORSRAM3 or FMC_Bank1_NORSRAM4 */ + else + { + FMC_Bank1->BTCR[FMC_Bank] = 0x000030D2; + } + FMC_Bank1->BTCR[FMC_Bank + 1] = 0x0FFFFFFF; + FMC_Bank1E->BWTR[FMC_Bank] = 0x0FFFFFFF; +} + +/** + * @brief Initializes the FMC NOR/SRAM Banks according to the specified + * parameters in the FMC_NORSRAMInitStruct. + * @param FMC_NORSRAMInitStruct : pointer to a FMC_NORSRAMInitTypeDef structure + * that contains the configuration information for the FMC NOR/SRAM + * specified Banks. + * @retval None + */ +void FMC_NORSRAMInit(FMC_NORSRAMInitTypeDef* FMC_NORSRAMInitStruct) +{ + /* Check the parameters */ + assert_param(IS_FMC_NORSRAM_BANK(FMC_NORSRAMInitStruct->FMC_Bank)); + assert_param(IS_FMC_MUX(FMC_NORSRAMInitStruct->FMC_DataAddressMux)); + assert_param(IS_FMC_MEMORY(FMC_NORSRAMInitStruct->FMC_MemoryType)); + assert_param(IS_FMC_NORSRAM_MEMORY_WIDTH(FMC_NORSRAMInitStruct->FMC_MemoryDataWidth)); + assert_param(IS_FMC_BURSTMODE(FMC_NORSRAMInitStruct->FMC_BurstAccessMode)); + assert_param(IS_FMC_WAIT_POLARITY(FMC_NORSRAMInitStruct->FMC_WaitSignalPolarity)); + assert_param(IS_FMC_WRAP_MODE(FMC_NORSRAMInitStruct->FMC_WrapMode)); + assert_param(IS_FMC_WAIT_SIGNAL_ACTIVE(FMC_NORSRAMInitStruct->FMC_WaitSignalActive)); + assert_param(IS_FMC_WRITE_OPERATION(FMC_NORSRAMInitStruct->FMC_WriteOperation)); + assert_param(IS_FMC_WAITE_SIGNAL(FMC_NORSRAMInitStruct->FMC_WaitSignal)); + assert_param(IS_FMC_EXTENDED_MODE(FMC_NORSRAMInitStruct->FMC_ExtendedMode)); + assert_param(IS_FMC_ASYNWAIT(FMC_NORSRAMInitStruct->FMC_AsynchronousWait)); + assert_param(IS_FMC_WRITE_BURST(FMC_NORSRAMInitStruct->FMC_WriteBurst)); + assert_param(IS_FMC_ADDRESS_SETUP_TIME(FMC_NORSRAMInitStruct->FMC_ReadWriteTimingStruct->FMC_AddressSetupTime)); + assert_param(IS_FMC_ADDRESS_HOLD_TIME(FMC_NORSRAMInitStruct->FMC_ReadWriteTimingStruct->FMC_AddressHoldTime)); + assert_param(IS_FMC_DATASETUP_TIME(FMC_NORSRAMInitStruct->FMC_ReadWriteTimingStruct->FMC_DataSetupTime)); + assert_param(IS_FMC_TURNAROUND_TIME(FMC_NORSRAMInitStruct->FMC_ReadWriteTimingStruct->FMC_BusTurnAroundDuration)); + assert_param(IS_FMC_CLK_DIV(FMC_NORSRAMInitStruct->FMC_ReadWriteTimingStruct->FMC_CLKDivision)); + assert_param(IS_FMC_DATA_LATENCY(FMC_NORSRAMInitStruct->FMC_ReadWriteTimingStruct->FMC_DataLatency)); + assert_param(IS_FMC_ACCESS_MODE(FMC_NORSRAMInitStruct->FMC_ReadWriteTimingStruct->FMC_AccessMode)); + + /* NOR/SRAM Bank control register configuration */ + FMC_Bank1->BTCR[FMC_NORSRAMInitStruct->FMC_Bank] = + (uint32_t)FMC_NORSRAMInitStruct->FMC_DataAddressMux | + FMC_NORSRAMInitStruct->FMC_MemoryType | + FMC_NORSRAMInitStruct->FMC_MemoryDataWidth | + FMC_NORSRAMInitStruct->FMC_BurstAccessMode | + FMC_NORSRAMInitStruct->FMC_WaitSignalPolarity | + FMC_NORSRAMInitStruct->FMC_WrapMode | + FMC_NORSRAMInitStruct->FMC_WaitSignalActive | + FMC_NORSRAMInitStruct->FMC_WriteOperation | + FMC_NORSRAMInitStruct->FMC_WaitSignal | + FMC_NORSRAMInitStruct->FMC_ExtendedMode | + FMC_NORSRAMInitStruct->FMC_AsynchronousWait | + FMC_NORSRAMInitStruct->FMC_WriteBurst; + + + if(FMC_NORSRAMInitStruct->FMC_MemoryType == FMC_MemoryType_NOR) + { + FMC_Bank1->BTCR[FMC_NORSRAMInitStruct->FMC_Bank] |= (uint32_t)BCR_FACCEN_SET; + } + + /* NOR/SRAM Bank timing register configuration */ + FMC_Bank1->BTCR[FMC_NORSRAMInitStruct->FMC_Bank+1] = + (uint32_t)FMC_NORSRAMInitStruct->FMC_ReadWriteTimingStruct->FMC_AddressSetupTime | + (FMC_NORSRAMInitStruct->FMC_ReadWriteTimingStruct->FMC_AddressHoldTime << 4) | + (FMC_NORSRAMInitStruct->FMC_ReadWriteTimingStruct->FMC_DataSetupTime << 8) | + (FMC_NORSRAMInitStruct->FMC_ReadWriteTimingStruct->FMC_BusTurnAroundDuration << 16) | + (((FMC_NORSRAMInitStruct->FMC_ReadWriteTimingStruct->FMC_CLKDivision)-1) << 20) | + (((FMC_NORSRAMInitStruct->FMC_ReadWriteTimingStruct->FMC_DataLatency)-2) << 24) | + FMC_NORSRAMInitStruct->FMC_ReadWriteTimingStruct->FMC_AccessMode; + + /* NOR/SRAM Bank timing register for write configuration, if extended mode is used */ + if(FMC_NORSRAMInitStruct->FMC_ExtendedMode == FMC_ExtendedMode_Enable) + { + assert_param(IS_FMC_ADDRESS_SETUP_TIME(FMC_NORSRAMInitStruct->FMC_WriteTimingStruct->FMC_AddressSetupTime)); + assert_param(IS_FMC_ADDRESS_HOLD_TIME(FMC_NORSRAMInitStruct->FMC_WriteTimingStruct->FMC_AddressHoldTime)); + assert_param(IS_FMC_DATASETUP_TIME(FMC_NORSRAMInitStruct->FMC_WriteTimingStruct->FMC_DataSetupTime)); + assert_param(IS_FMC_CLK_DIV(FMC_NORSRAMInitStruct->FMC_WriteTimingStruct->FMC_CLKDivision)); + assert_param(IS_FMC_DATA_LATENCY(FMC_NORSRAMInitStruct->FMC_WriteTimingStruct->FMC_DataLatency)); + assert_param(IS_FMC_ACCESS_MODE(FMC_NORSRAMInitStruct->FMC_WriteTimingStruct->FMC_AccessMode)); + + FMC_Bank1E->BWTR[FMC_NORSRAMInitStruct->FMC_Bank] = + (uint32_t)FMC_NORSRAMInitStruct->FMC_WriteTimingStruct->FMC_AddressSetupTime | + (FMC_NORSRAMInitStruct->FMC_WriteTimingStruct->FMC_AddressHoldTime << 4 )| + (FMC_NORSRAMInitStruct->FMC_WriteTimingStruct->FMC_DataSetupTime << 8) | + (((FMC_NORSRAMInitStruct->FMC_WriteTimingStruct->FMC_CLKDivision)-1) << 20) | + (((FMC_NORSRAMInitStruct->FMC_WriteTimingStruct->FMC_DataLatency)-2) << 24) | + FMC_NORSRAMInitStruct->FMC_WriteTimingStruct->FMC_AccessMode; + } + else + { + FMC_Bank1E->BWTR[FMC_NORSRAMInitStruct->FMC_Bank] = 0x0FFFFFFF; + } + +} + +/** + * @brief Fills each FMC_NORSRAMInitStruct member with its default value. + * @param FMC_NORSRAMInitStruct: pointer to a FMC_NORSRAMInitTypeDef structure + * which will be initialized. + * @retval None + */ +void FMC_NORSRAMStructInit(FMC_NORSRAMInitTypeDef* FMC_NORSRAMInitStruct) +{ + /* Reset NOR/SRAM Init structure parameters values */ + FMC_NORSRAMInitStruct->FMC_Bank = FMC_Bank1_NORSRAM1; + FMC_NORSRAMInitStruct->FMC_DataAddressMux = FMC_DataAddressMux_Enable; + FMC_NORSRAMInitStruct->FMC_MemoryType = FMC_MemoryType_SRAM; + FMC_NORSRAMInitStruct->FMC_MemoryDataWidth = FMC_NORSRAM_MemoryDataWidth_16b; + FMC_NORSRAMInitStruct->FMC_BurstAccessMode = FMC_BurstAccessMode_Disable; + FMC_NORSRAMInitStruct->FMC_AsynchronousWait = FMC_AsynchronousWait_Disable; + FMC_NORSRAMInitStruct->FMC_WaitSignalPolarity = FMC_WaitSignalPolarity_Low; + FMC_NORSRAMInitStruct->FMC_WrapMode = FMC_WrapMode_Disable; + FMC_NORSRAMInitStruct->FMC_WaitSignalActive = FMC_WaitSignalActive_BeforeWaitState; + FMC_NORSRAMInitStruct->FMC_WriteOperation = FMC_WriteOperation_Enable; + FMC_NORSRAMInitStruct->FMC_WaitSignal = FMC_WaitSignal_Enable; + FMC_NORSRAMInitStruct->FMC_ExtendedMode = FMC_ExtendedMode_Disable; + FMC_NORSRAMInitStruct->FMC_WriteBurst = FMC_WriteBurst_Disable; + + FMC_NORSRAMInitStruct->FMC_ReadWriteTimingStruct->FMC_AddressSetupTime = 15; + FMC_NORSRAMInitStruct->FMC_ReadWriteTimingStruct->FMC_AddressHoldTime = 15; + FMC_NORSRAMInitStruct->FMC_ReadWriteTimingStruct->FMC_DataSetupTime = 255; + FMC_NORSRAMInitStruct->FMC_ReadWriteTimingStruct->FMC_BusTurnAroundDuration = 15; + FMC_NORSRAMInitStruct->FMC_ReadWriteTimingStruct->FMC_CLKDivision = 15; + FMC_NORSRAMInitStruct->FMC_ReadWriteTimingStruct->FMC_DataLatency = 15; + FMC_NORSRAMInitStruct->FMC_ReadWriteTimingStruct->FMC_AccessMode = FMC_AccessMode_A; + FMC_NORSRAMInitStruct->FMC_WriteTimingStruct->FMC_AddressSetupTime = 15; + FMC_NORSRAMInitStruct->FMC_WriteTimingStruct->FMC_AddressHoldTime = 15; + FMC_NORSRAMInitStruct->FMC_WriteTimingStruct->FMC_DataSetupTime = 255; + FMC_NORSRAMInitStruct->FMC_WriteTimingStruct->FMC_BusTurnAroundDuration = 15; + FMC_NORSRAMInitStruct->FMC_WriteTimingStruct->FMC_CLKDivision = 16; + FMC_NORSRAMInitStruct->FMC_WriteTimingStruct->FMC_DataLatency = 17; + FMC_NORSRAMInitStruct->FMC_WriteTimingStruct->FMC_AccessMode = FMC_AccessMode_A; +} + +/** + * @brief Enables or disables the specified NOR/SRAM Memory Bank. + * @param FMC_Bank: specifies the FMC Bank to be used + * This parameter can be one of the following values: + * @arg FMC_Bank1_NORSRAM1: FMC Bank1 NOR/SRAM1 + * @arg FMC_Bank1_NORSRAM2: FMC Bank1 NOR/SRAM2 + * @arg FMC_Bank1_NORSRAM3: FMC Bank1 NOR/SRAM3 + * @arg FMC_Bank1_NORSRAM4: FMC Bank1 NOR/SRAM4 + * @param NewState: new state of the FMC_Bank. This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void FMC_NORSRAMCmd(uint32_t FMC_Bank, FunctionalState NewState) +{ + assert_param(IS_FMC_NORSRAM_BANK(FMC_Bank)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable the selected NOR/SRAM Bank by setting the PBKEN bit in the BCRx register */ + FMC_Bank1->BTCR[FMC_Bank] |= BCR_MBKEN_SET; + } + else + { + /* Disable the selected NOR/SRAM Bank by clearing the PBKEN bit in the BCRx register */ + FMC_Bank1->BTCR[FMC_Bank] &= BCR_MBKEN_RESET; + } +} +/** + * @} + */ + +/** @defgroup FMC_Group2 NAND Controller functions + * @brief NAND Controller functions + * +@verbatim + =============================================================================== + ##### NAND Controller functions ##### + =============================================================================== + + [..] The following sequence should be followed to configure the FMC to interface + with 8-bit or 16-bit NAND memory connected to the NAND Bank: + + (#) Enable the clock for the FMC and associated GPIOs using the following functions: + (++) RCC_AHB3PeriphClockCmd(RCC_AHB3Periph_FMC, ENABLE); + (++) RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOx, ENABLE); + + (#) FMC pins configuration + (++) Connect the involved FMC pins to AF12 using the following function + GPIO_PinAFConfig(GPIOx, GPIO_PinSourcex, GPIO_AF_FMC); + (++) Configure these FMC pins in alternate function mode by calling the function + GPIO_Init(); + + (#) Declare a FMC_NANDInitTypeDef structure, for example: + FMC_NANDInitTypeDef FMC_NANDInitStructure; + and fill the FMC_NANDInitStructure variable with the allowed values of + the structure member. + + (#) Initialize the NAND Controller by calling the function + FMC_NANDInit(&FMC_NANDInitStructure); + + (#) Then enable the NAND Bank, for example: + FMC_NANDCmd(FMC_Bank3_NAND, ENABLE); + + (#) At this stage you can read/write from/to the memory connected to the NAND Bank. + + [..] + (@) To enable the Error Correction Code (ECC), you have to use the function + FMC_NANDECCCmd(FMC_Bank3_NAND, ENABLE); + [..] + (@) and to get the current ECC value you have to use the function + ECCval = FMC_GetECC(FMC_Bank3_NAND); + +@endverbatim + * @{ + */ + +/** + * @brief De-initializes the FMC NAND Banks registers to their default reset values. + * @param FMC_Bank: specifies the FMC Bank to be used + * This parameter can be one of the following values: + * @arg FMC_Bank2_NAND: FMC Bank2 NAND + * @arg FMC_Bank3_NAND: FMC Bank3 NAND + * @retval None + */ +void FMC_NANDDeInit(uint32_t FMC_Bank) +{ + /* Check the parameter */ + assert_param(IS_FMC_NAND_BANK(FMC_Bank)); + + if(FMC_Bank == FMC_Bank2_NAND) + { + /* Set the FMC_Bank2 registers to their reset values */ + FMC_Bank2->PCR2 = 0x00000018; + FMC_Bank2->SR2 = 0x00000040; + FMC_Bank2->PMEM2 = 0xFCFCFCFC; + FMC_Bank2->PATT2 = 0xFCFCFCFC; + } + /* FMC_Bank3_NAND */ + else + { + /* Set the FMC_Bank3 registers to their reset values */ + FMC_Bank3->PCR3 = 0x00000018; + FMC_Bank3->SR3 = 0x00000040; + FMC_Bank3->PMEM3 = 0xFCFCFCFC; + FMC_Bank3->PATT3 = 0xFCFCFCFC; + } +} + +/** + * @brief Initializes the FMC NAND Banks according to the specified parameters + * in the FMC_NANDInitStruct. + * @param FMC_NANDInitStruct : pointer to a FMC_NANDInitTypeDef structure that + * contains the configuration information for the FMC NAND specified Banks. + * @retval None + */ +void FMC_NANDInit(FMC_NANDInitTypeDef* FMC_NANDInitStruct) +{ + uint32_t tmppcr = 0x00000000, tmppmem = 0x00000000, tmppatt = 0x00000000; + + /* Check the parameters */ + assert_param(IS_FMC_NAND_BANK(FMC_NANDInitStruct->FMC_Bank)); + assert_param(IS_FMC_WAIT_FEATURE(FMC_NANDInitStruct->FMC_Waitfeature)); + assert_param(IS_FMC_NAND_MEMORY_WIDTH(FMC_NANDInitStruct->FMC_MemoryDataWidth)); + assert_param(IS_FMC_ECC_STATE(FMC_NANDInitStruct->FMC_ECC)); + assert_param(IS_FMC_ECCPAGE_SIZE(FMC_NANDInitStruct->FMC_ECCPageSize)); + assert_param(IS_FMC_TCLR_TIME(FMC_NANDInitStruct->FMC_TCLRSetupTime)); + assert_param(IS_FMC_TAR_TIME(FMC_NANDInitStruct->FMC_TARSetupTime)); + assert_param(IS_FMC_SETUP_TIME(FMC_NANDInitStruct->FMC_CommonSpaceTimingStruct->FMC_SetupTime)); + assert_param(IS_FMC_WAIT_TIME(FMC_NANDInitStruct->FMC_CommonSpaceTimingStruct->FMC_WaitSetupTime)); + assert_param(IS_FMC_HOLD_TIME(FMC_NANDInitStruct->FMC_CommonSpaceTimingStruct->FMC_HoldSetupTime)); + assert_param(IS_FMC_HIZ_TIME(FMC_NANDInitStruct->FMC_CommonSpaceTimingStruct->FMC_HiZSetupTime)); + assert_param(IS_FMC_SETUP_TIME(FMC_NANDInitStruct->FMC_AttributeSpaceTimingStruct->FMC_SetupTime)); + assert_param(IS_FMC_WAIT_TIME(FMC_NANDInitStruct->FMC_AttributeSpaceTimingStruct->FMC_WaitSetupTime)); + assert_param(IS_FMC_HOLD_TIME(FMC_NANDInitStruct->FMC_AttributeSpaceTimingStruct->FMC_HoldSetupTime)); + assert_param(IS_FMC_HIZ_TIME(FMC_NANDInitStruct->FMC_AttributeSpaceTimingStruct->FMC_HiZSetupTime)); + + /* Set the tmppcr value according to FMC_NANDInitStruct parameters */ + tmppcr = (uint32_t)FMC_NANDInitStruct->FMC_Waitfeature | + PCR_MEMORYTYPE_NAND | + FMC_NANDInitStruct->FMC_MemoryDataWidth | + FMC_NANDInitStruct->FMC_ECC | + FMC_NANDInitStruct->FMC_ECCPageSize | + (FMC_NANDInitStruct->FMC_TCLRSetupTime << 9 )| + (FMC_NANDInitStruct->FMC_TARSetupTime << 13); + + /* Set tmppmem value according to FMC_CommonSpaceTimingStructure parameters */ + tmppmem = (uint32_t)FMC_NANDInitStruct->FMC_CommonSpaceTimingStruct->FMC_SetupTime | + (FMC_NANDInitStruct->FMC_CommonSpaceTimingStruct->FMC_WaitSetupTime << 8) | + (FMC_NANDInitStruct->FMC_CommonSpaceTimingStruct->FMC_HoldSetupTime << 16)| + (FMC_NANDInitStruct->FMC_CommonSpaceTimingStruct->FMC_HiZSetupTime << 24); + + /* Set tmppatt value according to FMC_AttributeSpaceTimingStructure parameters */ + tmppatt = (uint32_t)FMC_NANDInitStruct->FMC_AttributeSpaceTimingStruct->FMC_SetupTime | + (FMC_NANDInitStruct->FMC_AttributeSpaceTimingStruct->FMC_WaitSetupTime << 8) | + (FMC_NANDInitStruct->FMC_AttributeSpaceTimingStruct->FMC_HoldSetupTime << 16)| + (FMC_NANDInitStruct->FMC_AttributeSpaceTimingStruct->FMC_HiZSetupTime << 24); + + if(FMC_NANDInitStruct->FMC_Bank == FMC_Bank2_NAND) + { + /* FMC_Bank2_NAND registers configuration */ + FMC_Bank2->PCR2 = tmppcr; + FMC_Bank2->PMEM2 = tmppmem; + FMC_Bank2->PATT2 = tmppatt; + } + else + { + /* FMC_Bank3_NAND registers configuration */ + FMC_Bank3->PCR3 = tmppcr; + FMC_Bank3->PMEM3 = tmppmem; + FMC_Bank3->PATT3 = tmppatt; + } +} + + +/** + * @brief Fills each FMC_NANDInitStruct member with its default value. + * @param FMC_NANDInitStruct: pointer to a FMC_NANDInitTypeDef structure which + * will be initialized. + * @retval None + */ +void FMC_NANDStructInit(FMC_NANDInitTypeDef* FMC_NANDInitStruct) +{ + /* Reset NAND Init structure parameters values */ + FMC_NANDInitStruct->FMC_Bank = FMC_Bank2_NAND; + FMC_NANDInitStruct->FMC_Waitfeature = FMC_Waitfeature_Disable; + FMC_NANDInitStruct->FMC_MemoryDataWidth = FMC_NAND_MemoryDataWidth_16b; + FMC_NANDInitStruct->FMC_ECC = FMC_ECC_Disable; + FMC_NANDInitStruct->FMC_ECCPageSize = FMC_ECCPageSize_256Bytes; + FMC_NANDInitStruct->FMC_TCLRSetupTime = 0x0; + FMC_NANDInitStruct->FMC_TARSetupTime = 0x0; + FMC_NANDInitStruct->FMC_CommonSpaceTimingStruct->FMC_SetupTime = 252; + FMC_NANDInitStruct->FMC_CommonSpaceTimingStruct->FMC_WaitSetupTime = 252; + FMC_NANDInitStruct->FMC_CommonSpaceTimingStruct->FMC_HoldSetupTime = 252; + FMC_NANDInitStruct->FMC_CommonSpaceTimingStruct->FMC_HiZSetupTime = 252; + FMC_NANDInitStruct->FMC_AttributeSpaceTimingStruct->FMC_SetupTime = 252; + FMC_NANDInitStruct->FMC_AttributeSpaceTimingStruct->FMC_WaitSetupTime = 252; + FMC_NANDInitStruct->FMC_AttributeSpaceTimingStruct->FMC_HoldSetupTime = 252; + FMC_NANDInitStruct->FMC_AttributeSpaceTimingStruct->FMC_HiZSetupTime = 252; +} + +/** + * @brief Enables or disables the specified NAND Memory Bank. + * @param FMC_Bank: specifies the FMC Bank to be used + * This parameter can be one of the following values: + * @arg FMC_Bank2_NAND: FMC Bank2 NAND + * @arg FMC_Bank3_NAND: FMC Bank3 NAND + * @param NewState: new state of the FMC_Bank. This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void FMC_NANDCmd(uint32_t FMC_Bank, FunctionalState NewState) +{ + assert_param(IS_FMC_NAND_BANK(FMC_Bank)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable the selected NAND Bank by setting the PBKEN bit in the PCRx register */ + if(FMC_Bank == FMC_Bank2_NAND) + { + FMC_Bank2->PCR2 |= PCR_PBKEN_SET; + } + else + { + FMC_Bank3->PCR3 |= PCR_PBKEN_SET; + } + } + else + { + /* Disable the selected NAND Bank by clearing the PBKEN bit in the PCRx register */ + if(FMC_Bank == FMC_Bank2_NAND) + { + FMC_Bank2->PCR2 &= PCR_PBKEN_RESET; + } + else + { + FMC_Bank3->PCR3 &= PCR_PBKEN_RESET; + } + } +} +/** + * @brief Enables or disables the FMC NAND ECC feature. + * @param FMC_Bank: specifies the FMC Bank to be used + * This parameter can be one of the following values: + * @arg FMC_Bank2_NAND: FMC Bank2 NAND + * @arg FMC_Bank3_NAND: FMC Bank3 NAND + * @param NewState: new state of the FMC NAND ECC feature. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void FMC_NANDECCCmd(uint32_t FMC_Bank, FunctionalState NewState) +{ + assert_param(IS_FMC_NAND_BANK(FMC_Bank)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable the selected NAND Bank ECC function by setting the ECCEN bit in the PCRx register */ + if(FMC_Bank == FMC_Bank2_NAND) + { + FMC_Bank2->PCR2 |= PCR_ECCEN_SET; + } + else + { + FMC_Bank3->PCR3 |= PCR_ECCEN_SET; + } + } + else + { + /* Disable the selected NAND Bank ECC function by clearing the ECCEN bit in the PCRx register */ + if(FMC_Bank == FMC_Bank2_NAND) + { + FMC_Bank2->PCR2 &= PCR_ECCEN_RESET; + } + else + { + FMC_Bank3->PCR3 &= PCR_ECCEN_RESET; + } + } +} + +/** + * @brief Returns the error correction code register value. + * @param FMC_Bank: specifies the FMC Bank to be used + * This parameter can be one of the following values: + * @arg FMC_Bank2_NAND: FMC Bank2 NAND + * @arg FMC_Bank3_NAND: FMC Bank3 NAND + * @retval The Error Correction Code (ECC) value. + */ +uint32_t FMC_GetECC(uint32_t FMC_Bank) +{ + uint32_t eccval = 0x00000000; + + if(FMC_Bank == FMC_Bank2_NAND) + { + /* Get the ECCR2 register value */ + eccval = FMC_Bank2->ECCR2; + } + else + { + /* Get the ECCR3 register value */ + eccval = FMC_Bank3->ECCR3; + } + /* Return the error correction code value */ + return(eccval); +} +/** + * @} + */ + +/** @defgroup FMC_Group3 PCCARD Controller functions + * @brief PCCARD Controller functions + * +@verbatim + =============================================================================== + ##### PCCARD Controller functions ##### + =============================================================================== + + [..] he following sequence should be followed to configure the FMC to interface + with 16-bit PC Card compatible memory connected to the PCCARD Bank: + + (#) Enable the clock for the FMC and associated GPIOs using the following functions: + (++) RCC_AHB3PeriphClockCmd(RCC_AHB3Periph_FMC, ENABLE); + (++) RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOx, ENABLE); + + (#) FMC pins configuration + (++) Connect the involved FMC pins to AF12 using the following function + GPIO_PinAFConfig(GPIOx, GPIO_PinSourcex, GPIO_AF_FMC); + (++) Configure these FMC pins in alternate function mode by calling the function + GPIO_Init(); + + (#) Declare a FMC_PCCARDInitTypeDef structure, for example: + FMC_PCCARDInitTypeDef FMC_PCCARDInitStructure; + and fill the FMC_PCCARDInitStructure variable with the allowed values of + the structure member. + + (#) Initialize the PCCARD Controller by calling the function + FMC_PCCARDInit(&FMC_PCCARDInitStructure); + + (#) Then enable the PCCARD Bank: + FMC_PCCARDCmd(ENABLE); + + (#) At this stage you can read/write from/to the memory connected to the PCCARD Bank. + +@endverbatim + * @{ + */ + +/** + * @brief De-initializes the FMC PCCARD Bank registers to their default reset values. + * @param None + * @retval None + */ +void FMC_PCCARDDeInit(void) +{ + /* Set the FMC_Bank4 registers to their reset values */ + FMC_Bank4->PCR4 = 0x00000018; + FMC_Bank4->SR4 = 0x00000000; + FMC_Bank4->PMEM4 = 0xFCFCFCFC; + FMC_Bank4->PATT4 = 0xFCFCFCFC; + FMC_Bank4->PIO4 = 0xFCFCFCFC; +} + +/** + * @brief Initializes the FMC PCCARD Bank according to the specified parameters + * in the FMC_PCCARDInitStruct. + * @param FMC_PCCARDInitStruct : pointer to a FMC_PCCARDInitTypeDef structure + * that contains the configuration information for the FMC PCCARD Bank. + * @retval None + */ +void FMC_PCCARDInit(FMC_PCCARDInitTypeDef* FMC_PCCARDInitStruct) +{ + /* Check the parameters */ + assert_param(IS_FMC_WAIT_FEATURE(FMC_PCCARDInitStruct->FMC_Waitfeature)); + assert_param(IS_FMC_TCLR_TIME(FMC_PCCARDInitStruct->FMC_TCLRSetupTime)); + assert_param(IS_FMC_TAR_TIME(FMC_PCCARDInitStruct->FMC_TARSetupTime)); + + assert_param(IS_FMC_SETUP_TIME(FMC_PCCARDInitStruct->FMC_CommonSpaceTimingStruct->FMC_SetupTime)); + assert_param(IS_FMC_WAIT_TIME(FMC_PCCARDInitStruct->FMC_CommonSpaceTimingStruct->FMC_WaitSetupTime)); + assert_param(IS_FMC_HOLD_TIME(FMC_PCCARDInitStruct->FMC_CommonSpaceTimingStruct->FMC_HoldSetupTime)); + assert_param(IS_FMC_HIZ_TIME(FMC_PCCARDInitStruct->FMC_CommonSpaceTimingStruct->FMC_HiZSetupTime)); + + assert_param(IS_FMC_SETUP_TIME(FMC_PCCARDInitStruct->FMC_AttributeSpaceTimingStruct->FMC_SetupTime)); + assert_param(IS_FMC_WAIT_TIME(FMC_PCCARDInitStruct->FMC_AttributeSpaceTimingStruct->FMC_WaitSetupTime)); + assert_param(IS_FMC_HOLD_TIME(FMC_PCCARDInitStruct->FMC_AttributeSpaceTimingStruct->FMC_HoldSetupTime)); + assert_param(IS_FMC_HIZ_TIME(FMC_PCCARDInitStruct->FMC_AttributeSpaceTimingStruct->FMC_HiZSetupTime)); + assert_param(IS_FMC_SETUP_TIME(FMC_PCCARDInitStruct->FMC_IOSpaceTimingStruct->FMC_SetupTime)); + assert_param(IS_FMC_WAIT_TIME(FMC_PCCARDInitStruct->FMC_IOSpaceTimingStruct->FMC_WaitSetupTime)); + assert_param(IS_FMC_HOLD_TIME(FMC_PCCARDInitStruct->FMC_IOSpaceTimingStruct->FMC_HoldSetupTime)); + assert_param(IS_FMC_HIZ_TIME(FMC_PCCARDInitStruct->FMC_IOSpaceTimingStruct->FMC_HiZSetupTime)); + + /* Set the PCR4 register value according to FMC_PCCARDInitStruct parameters */ + FMC_Bank4->PCR4 = (uint32_t)FMC_PCCARDInitStruct->FMC_Waitfeature | + FMC_NAND_MemoryDataWidth_16b | + (FMC_PCCARDInitStruct->FMC_TCLRSetupTime << 9) | + (FMC_PCCARDInitStruct->FMC_TARSetupTime << 13); + + /* Set PMEM4 register value according to FMC_CommonSpaceTimingStructure parameters */ + FMC_Bank4->PMEM4 = (uint32_t)FMC_PCCARDInitStruct->FMC_CommonSpaceTimingStruct->FMC_SetupTime | + (FMC_PCCARDInitStruct->FMC_CommonSpaceTimingStruct->FMC_WaitSetupTime << 8) | + (FMC_PCCARDInitStruct->FMC_CommonSpaceTimingStruct->FMC_HoldSetupTime << 16)| + (FMC_PCCARDInitStruct->FMC_CommonSpaceTimingStruct->FMC_HiZSetupTime << 24); + + /* Set PATT4 register value according to FMC_AttributeSpaceTimingStructure parameters */ + FMC_Bank4->PATT4 = (uint32_t)FMC_PCCARDInitStruct->FMC_AttributeSpaceTimingStruct->FMC_SetupTime | + (FMC_PCCARDInitStruct->FMC_AttributeSpaceTimingStruct->FMC_WaitSetupTime << 8) | + (FMC_PCCARDInitStruct->FMC_AttributeSpaceTimingStruct->FMC_HoldSetupTime << 16)| + (FMC_PCCARDInitStruct->FMC_AttributeSpaceTimingStruct->FMC_HiZSetupTime << 24); + + /* Set PIO4 register value according to FMC_IOSpaceTimingStructure parameters */ + FMC_Bank4->PIO4 = (uint32_t)FMC_PCCARDInitStruct->FMC_IOSpaceTimingStruct->FMC_SetupTime | + (FMC_PCCARDInitStruct->FMC_IOSpaceTimingStruct->FMC_WaitSetupTime << 8) | + (FMC_PCCARDInitStruct->FMC_IOSpaceTimingStruct->FMC_HoldSetupTime << 16)| + (FMC_PCCARDInitStruct->FMC_IOSpaceTimingStruct->FMC_HiZSetupTime << 24); +} + +/** + * @brief Fills each FMC_PCCARDInitStruct member with its default value. + * @param FMC_PCCARDInitStruct: pointer to a FMC_PCCARDInitTypeDef structure + * which will be initialized. + * @retval None + */ +void FMC_PCCARDStructInit(FMC_PCCARDInitTypeDef* FMC_PCCARDInitStruct) +{ + /* Reset PCCARD Init structure parameters values */ + FMC_PCCARDInitStruct->FMC_Waitfeature = FMC_Waitfeature_Disable; + FMC_PCCARDInitStruct->FMC_TCLRSetupTime = 0; + FMC_PCCARDInitStruct->FMC_TARSetupTime = 0; + FMC_PCCARDInitStruct->FMC_CommonSpaceTimingStruct->FMC_SetupTime = 252; + FMC_PCCARDInitStruct->FMC_CommonSpaceTimingStruct->FMC_WaitSetupTime = 252; + FMC_PCCARDInitStruct->FMC_CommonSpaceTimingStruct->FMC_HoldSetupTime = 252; + FMC_PCCARDInitStruct->FMC_CommonSpaceTimingStruct->FMC_HiZSetupTime = 252; + FMC_PCCARDInitStruct->FMC_AttributeSpaceTimingStruct->FMC_SetupTime = 252; + FMC_PCCARDInitStruct->FMC_AttributeSpaceTimingStruct->FMC_WaitSetupTime = 252; + FMC_PCCARDInitStruct->FMC_AttributeSpaceTimingStruct->FMC_HoldSetupTime = 252; + FMC_PCCARDInitStruct->FMC_AttributeSpaceTimingStruct->FMC_HiZSetupTime = 252; + FMC_PCCARDInitStruct->FMC_IOSpaceTimingStruct->FMC_SetupTime = 252; + FMC_PCCARDInitStruct->FMC_IOSpaceTimingStruct->FMC_WaitSetupTime = 252; + FMC_PCCARDInitStruct->FMC_IOSpaceTimingStruct->FMC_HoldSetupTime = 252; + FMC_PCCARDInitStruct->FMC_IOSpaceTimingStruct->FMC_HiZSetupTime = 252; +} + +/** + * @brief Enables or disables the PCCARD Memory Bank. + * @param NewState: new state of the PCCARD Memory Bank. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void FMC_PCCARDCmd(FunctionalState NewState) +{ + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable the PCCARD Bank by setting the PBKEN bit in the PCR4 register */ + FMC_Bank4->PCR4 |= PCR_PBKEN_SET; + } + else + { + /* Disable the PCCARD Bank by clearing the PBKEN bit in the PCR4 register */ + FMC_Bank4->PCR4 &= PCR_PBKEN_RESET; + } +} + +/** + * @} + */ + +/** @defgroup FMC_Group4 Interrupts and flags management functions + * @brief Interrupts and flags management functions + * +@verbatim + =============================================================================== + ##### Interrupts and flags management functions ##### + =============================================================================== + +@endverbatim + * @{ + */ + +/** + * @brief Enables or disables the specified FMC interrupts. + * @param FMC_Bank: specifies the FMC Bank to be used + * This parameter can be one of the following values: + * @arg FMC_Bank2_NAND: FMC Bank2 NAND + * @arg FMC_Bank3_NAND: FMC Bank3 NAND + * @arg FMC_Bank4_PCCARD: FMC Bank4 PCCARD + * @arg FMC_Bank1_SDRAM: FMC Bank1 SDRAM + * @arg FMC_Bank2_SDRAM: FMC Bank2 SDRAM + * @param FMC_IT: specifies the FMC interrupt sources to be enabled or disabled. + * This parameter can be any combination of the following values: + * @arg FMC_IT_RisingEdge: Rising edge detection interrupt. + * @arg FMC_IT_Level: Level edge detection interrupt. + * @arg FMC_IT_FallingEdge: Falling edge detection interrupt. + * @param NewState: new state of the specified FMC interrupts. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void FMC_ITConfig(uint32_t FMC_Bank, uint32_t FMC_IT, FunctionalState NewState) +{ + assert_param(IS_FMC_IT_BANK(FMC_Bank)); + assert_param(IS_FMC_IT(FMC_IT)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable the selected FMC_Bank2 interrupts */ + if(FMC_Bank == FMC_Bank2_NAND) + { + FMC_Bank2->SR2 |= FMC_IT; + } + /* Enable the selected FMC_Bank3 interrupts */ + else if (FMC_Bank == FMC_Bank3_NAND) + { + FMC_Bank3->SR3 |= FMC_IT; + } + /* Enable the selected FMC_Bank4 interrupts */ + else + { + FMC_Bank4->SR4 |= FMC_IT; + } + } + else + { + /* Disable the selected FMC_Bank2 interrupts */ + if(FMC_Bank == FMC_Bank2_NAND) + { + FMC_Bank2->SR2 &= (uint32_t)~FMC_IT; + } + /* Disable the selected FMC_Bank3 interrupts */ + else if (FMC_Bank == FMC_Bank3_NAND) + { + FMC_Bank3->SR3 &= (uint32_t)~FMC_IT; + } + /* Disable the selected FMC_Bank4 interrupts */ + else + { + FMC_Bank4->SR4 &= (uint32_t)~FMC_IT; + } + } +} + +/** + * @brief Checks whether the specified FMC flag is set or not. + * @param FMC_Bank: specifies the FMC Bank to be used + * This parameter can be one of the following values: + * @arg FMC_Bank2_NAND: FMC Bank2 NAND + * @arg FMC_Bank3_NAND: FMC Bank3 NAND + * @arg FMC_Bank4_PCCARD: FMC Bank4 PCCARD + * @param FMC_FLAG: specifies the flag to check. + * This parameter can be one of the following values: + * @arg FMC_FLAG_RisingEdge: Rising edge detection Flag. + * @arg FMC_FLAG_Level: Level detection Flag. + * @arg FMC_FLAG_FallingEdge: Falling edge detection Flag. + * @arg FMC_FLAG_FEMPT: Fifo empty Flag. + * @retval The new state of FMC_FLAG (SET or RESET). + */ +FlagStatus FMC_GetFlagStatus(uint32_t FMC_Bank, uint32_t FMC_FLAG) +{ + FlagStatus bitstatus = RESET; + uint32_t tmpsr = 0x00000000; + + /* Check the parameters */ + assert_param(IS_FMC_GETFLAG_BANK(FMC_Bank)); + assert_param(IS_FMC_GET_FLAG(FMC_FLAG)); + + if(FMC_Bank == FMC_Bank2_NAND) + { + tmpsr = FMC_Bank2->SR2; + } + else if(FMC_Bank == FMC_Bank3_NAND) + { + tmpsr = FMC_Bank3->SR3; + } + else + { + tmpsr = FMC_Bank4->SR4; + } + + /* Get the flag status */ + if ((tmpsr & FMC_FLAG) != FMC_FLAG ) + { + bitstatus = RESET; + } + else + { + bitstatus = SET; + } + /* Return the flag status */ + return bitstatus; +} + +/** + * @brief Clears the FMC's pending flags. + * @param FMC_Bank: specifies the FMC Bank to be used + * This parameter can be one of the following values: + * @arg FMC_Bank2_NAND: FMC Bank2 NAND + * @arg FMC_Bank3_NAND: FMC Bank3 NAND + * @arg FMC_Bank4_PCCARD: FMC Bank4 PCCARD + * @param FMC_FLAG: specifies the flag to clear. + * This parameter can be any combination of the following values: + * @arg FMC_FLAG_RisingEdge: Rising edge detection Flag. + * @arg FMC_FLAG_Level: Level detection Flag. + * @arg FMC_FLAG_FallingEdge: Falling edge detection Flag. + * @retval None + */ +void FMC_ClearFlag(uint32_t FMC_Bank, uint32_t FMC_FLAG) +{ + /* Check the parameters */ + assert_param(IS_FMC_GETFLAG_BANK(FMC_Bank)); + assert_param(IS_FMC_CLEAR_FLAG(FMC_FLAG)) ; + + if(FMC_Bank == FMC_Bank2_NAND) + { + FMC_Bank2->SR2 &= (~FMC_FLAG); + } + else if(FMC_Bank == FMC_Bank3_NAND) + { + FMC_Bank3->SR3 &= (~FMC_FLAG); + } + /* FMC_Bank4 PCCARD */ + else + { + FMC_Bank4->SR4 &= (~FMC_FLAG); + } + +} + +/** + * @brief Checks whether the specified FMC interrupt has occurred or not. + * @param FMC_Bank: specifies the FMC Bank to be used + * This parameter can be one of the following values: + * @arg FMC_Bank2_NAND: FMC Bank2 NAND + * @arg FMC_Bank3_NAND: FMC Bank3 NAND + * @arg FMC_Bank4_PCCARD: FMC Bank4 PCCARD + * @param FMC_IT: specifies the FMC interrupt source to check. + * This parameter can be one of the following values: + * @arg FMC_IT_RisingEdge: Rising edge detection interrupt. + * @arg FMC_IT_Level: Level edge detection interrupt. + * @arg FMC_IT_FallingEdge: Falling edge detection interrupt. + * @retval The new state of FMC_IT (SET or RESET). + */ +ITStatus FMC_GetITStatus(uint32_t FMC_Bank, uint32_t FMC_IT) +{ + ITStatus bitstatus = RESET; + uint32_t tmpsr = 0; + uint32_t itstatus = 0; + uint32_t itenable = 0; + + /* Check the parameters */ + assert_param(IS_FMC_IT_BANK(FMC_Bank)); + assert_param(IS_FMC_GET_IT(FMC_IT)); + + if(FMC_Bank == FMC_Bank2_NAND) + { + tmpsr = FMC_Bank2->SR2; + } + else if(FMC_Bank == FMC_Bank3_NAND) + { + tmpsr = FMC_Bank3->SR3; + } + /* FMC_Bank4 PCCARD */ + else + { + tmpsr = FMC_Bank4->SR4; + } + + /* get the IT enable bit status*/ + itenable = tmpsr & FMC_IT; + + /* get the corresponding IT Flag status*/ + itstatus = tmpsr & (FMC_IT >> 3); + + if ((itstatus != (uint32_t)RESET) && (itenable != (uint32_t)RESET)) + { + bitstatus = SET; + } + else + { + bitstatus = RESET; + } + return bitstatus; +} + +/** + * @brief Clears the FMC's interrupt pending bits. + * @param FMC_Bank: specifies the FMC Bank to be used + * This parameter can be one of the following values: + * @arg FMC_Bank2_NAND: FMC Bank2 NAND + * @arg FMC_Bank3_NAND: FMC Bank3 NAND + * @arg FMC_Bank4_PCCARD: FMC Bank4 PCCARD + * @param FMC_IT: specifies the interrupt pending bit to clear. + * This parameter can be any combination of the following values: + * @arg FMC_IT_RisingEdge: Rising edge detection interrupt. + * @arg FMC_IT_Level: Level edge detection interrupt. + * @arg FMC_IT_FallingEdge: Falling edge detection interrupt. + * @retval None + */ +void FMC_ClearITPendingBit(uint32_t FMC_Bank, uint32_t FMC_IT) +{ + /* Check the parameters */ + assert_param(IS_FMC_IT_BANK(FMC_Bank)); + assert_param(IS_FMC_IT(FMC_IT)); + + if(FMC_Bank == FMC_Bank2_NAND) + { + FMC_Bank2->SR2 &= ~(FMC_IT >> 3); + } + else if(FMC_Bank == FMC_Bank3_NAND) + { + FMC_Bank3->SR3 &= ~(FMC_IT >> 3); + } + /* FMC_Bank4 PCCARD */ + else + { + FMC_Bank4->SR4 &= ~(FMC_IT >> 3); + } +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_gpio.c b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_gpio.c new file mode 100755 index 0000000000..c8d8eabb21 --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_gpio.c @@ -0,0 +1,545 @@ +/** + ****************************************************************************** + * @file stm32f30x_gpio.c + * @author MCD Application Team + * @version V1.2.3 + * @date 10-July-2015 + * @brief This file provides firmware functions to manage the following + * functionalities of the GPIO peripheral: + * + Initialization and Configuration functions + * + GPIO Read and Write functions + * + GPIO Alternate functions configuration functions + * + * @verbatim + + + =============================================================================== + ##### How to use this driver ##### + =============================================================================== + [..] + (#) Enable the GPIO AHB clock using RCC_AHBPeriphClockCmd() + (#) Configure the GPIO pin(s) using GPIO_Init() + Four possible configuration are available for each pin: + (++) Input: Floating, Pull-up, Pull-down. + (++) Output: Push-Pull (Pull-up, Pull-down or no Pull), + Open Drain (Pull-up, Pull-down or no Pull). + In output mode, the speed is configurable: Low, Medium, Fast or High. + (++) Alternate Function: Push-Pull (Pull-up, Pull-down or no Pull), + Open Drain (Pull-up, Pull-down or no Pull). + (++) Analog: required mode when a pin is to be used as ADC channel, + DAC output or comparator input. + (#) Peripherals alternate function: + (++) For ADC, DAC and comparators, configure the desired pin in + analog mode using GPIO_InitStruct->GPIO_Mode = GPIO_Mode_AN + (++) For other peripherals (TIM, USART...): + (+++) Connect the pin to the desired peripherals' Alternate + Function (AF) using GPIO_PinAFConfig() function. + (+++) Configure the desired pin in alternate function mode using + GPIO_InitStruct->GPIO_Mode = GPIO_Mode_AF + (+++) Select the type, pull-up/pull-down and output speed via + GPIO_PuPd, GPIO_OType and GPIO_Speed members. + (+++) Call GPIO_Init() function. + (#) To get the level of a pin configured in input mode use GPIO_ReadInputDataBit() + (#) To set/reset the level of a pin configured in output mode use + GPIO_SetBits()/GPIO_ResetBits() + (#) During and just after reset, the alternate functions are not active + and the GPIO pins are configured in input floating mode (except JTAG pins). + (#) The LSE oscillator pins OSC32_IN and OSC32_OUT can be used as + general-purpose (PC14 and PC15, respectively) when the LSE + oscillator is off. The LSE has priority over the GPIO function. + (#) The HSE oscillator pins OSC_IN/OSC_OUT can be used as general-purpose + (PF0 and PF1 respectively) when the HSE oscillator is off. The HSE has + the priority over the GPIO function. + + @endverbatim + + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f30x_gpio.h" +#include "stm32f30x_rcc.h" + +/** @addtogroup STM32F30x_StdPeriph_Driver + * @{ + */ + +/** @defgroup GPIO + * @brief GPIO driver modules + * @{ + */ + + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ + + +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/* Private function prototypes -----------------------------------------------*/ +/* Private functions ---------------------------------------------------------*/ + +/** @defgroup GPIO_Private_Functions + * @{ + */ + +/** @defgroup GPIO_Group1 Initialization and Configuration + * @brief Initialization and Configuration + * +@verbatim + =============================================================================== + ##### Initialization and Configuration ##### + =============================================================================== + +@endverbatim + * @{ + */ + +/** + * @brief Deinitializes the GPIOx peripheral registers to their default reset + * values. + * @param GPIOx: where x can be (A, B, C, D, E or F) to select the GPIO peripheral. + * @retval None + */ +void GPIO_DeInit(GPIO_TypeDef* GPIOx) +{ + /* Check the parameters */ + assert_param(IS_GPIO_ALL_PERIPH(GPIOx)); + + if(GPIOx == GPIOA) + { + RCC_AHBPeriphResetCmd(RCC_AHBPeriph_GPIOA, ENABLE); + RCC_AHBPeriphResetCmd(RCC_AHBPeriph_GPIOA, DISABLE); + } + else if(GPIOx == GPIOB) + { + RCC_AHBPeriphResetCmd(RCC_AHBPeriph_GPIOB, ENABLE); + RCC_AHBPeriphResetCmd(RCC_AHBPeriph_GPIOB, DISABLE); + } + else if(GPIOx == GPIOC) + { + RCC_AHBPeriphResetCmd(RCC_AHBPeriph_GPIOC, ENABLE); + RCC_AHBPeriphResetCmd(RCC_AHBPeriph_GPIOC, DISABLE); + } + else if(GPIOx == GPIOD) + { + RCC_AHBPeriphResetCmd(RCC_AHBPeriph_GPIOD, ENABLE); + RCC_AHBPeriphResetCmd(RCC_AHBPeriph_GPIOD, DISABLE); + } + else if(GPIOx == GPIOE) + { + RCC_AHBPeriphResetCmd(RCC_AHBPeriph_GPIOE, ENABLE); + RCC_AHBPeriphResetCmd(RCC_AHBPeriph_GPIOE, DISABLE); + } + else if(GPIOx == GPIOF) + { + RCC_AHBPeriphResetCmd(RCC_AHBPeriph_GPIOF, ENABLE); + RCC_AHBPeriphResetCmd(RCC_AHBPeriph_GPIOF, DISABLE); + } + else if(GPIOx == GPIOG) + { + RCC_AHBPeriphResetCmd(RCC_AHBPeriph_GPIOG, ENABLE); + RCC_AHBPeriphResetCmd(RCC_AHBPeriph_GPIOG, DISABLE); + } + else + { + if(GPIOx == GPIOH) + { + RCC_AHBPeriphResetCmd(RCC_AHBPeriph_GPIOH, ENABLE); + RCC_AHBPeriphResetCmd(RCC_AHBPeriph_GPIOH, DISABLE); + } + } +} + +/** + * @brief Initializes the GPIOx peripheral according to the specified + * parameters in the GPIO_InitStruct. + * @param GPIOx: where x can be (A, B, C, D, E, F, G or H) to select the GPIO peripheral. + * @param GPIO_InitStruct: pointer to a GPIO_InitTypeDef structure that + * contains the configuration information for the specified GPIO + * peripheral. + * @note GPIO_Pin: selects the pin to be configured: + * GPIO_Pin_0->GPIO_Pin_15 for GPIOA, GPIOB, GPIOC, GPIOD and GPIOE; + * GPIO_Pin_0->GPIO_Pin_2, GPIO_Pin_4, GPIO_Pin_6, GPIO_Pin_9 + * and GPIO_Pin_10 for GPIOF. + * @retval None + */ +void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct) +{ + uint32_t pinpos = 0x00, pos = 0x00 , currentpin = 0x00; + uint32_t tmpreg = 0x00; + + /* Check the parameters */ + assert_param(IS_GPIO_ALL_PERIPH(GPIOx)); + assert_param(IS_GPIO_PIN(GPIO_InitStruct->GPIO_Pin)); + assert_param(IS_GPIO_MODE(GPIO_InitStruct->GPIO_Mode)); + assert_param(IS_GPIO_PUPD(GPIO_InitStruct->GPIO_PuPd)); + + /*-------------------------- Configure the port pins -----------------------*/ + /*-- GPIO Mode Configuration --*/ + for (pinpos = 0x00; pinpos < 0x10; pinpos++) + { + pos = ((uint32_t)0x01) << pinpos; + + /* Get the port pins position */ + currentpin = (GPIO_InitStruct->GPIO_Pin) & pos; + + if (currentpin == pos) + { + if ((GPIO_InitStruct->GPIO_Mode == GPIO_Mode_OUT) || (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_AF)) + { + /* Check Speed mode parameters */ + assert_param(IS_GPIO_SPEED(GPIO_InitStruct->GPIO_Speed)); + + /* Speed mode configuration */ + GPIOx->OSPEEDR &= ~(GPIO_OSPEEDER_OSPEEDR0 << (pinpos * 2)); + GPIOx->OSPEEDR |= ((uint32_t)(GPIO_InitStruct->GPIO_Speed) << (pinpos * 2)); + + /* Check Output mode parameters */ + assert_param(IS_GPIO_OTYPE(GPIO_InitStruct->GPIO_OType)); + + /* Output mode configuration */ + GPIOx->OTYPER &= ~((GPIO_OTYPER_OT_0) << ((uint16_t)pinpos)); + GPIOx->OTYPER |= (uint16_t)(((uint16_t)GPIO_InitStruct->GPIO_OType) << ((uint16_t)pinpos)); + } + + GPIOx->MODER &= ~(GPIO_MODER_MODER0 << (pinpos * 2)); + + GPIOx->MODER |= (((uint32_t)GPIO_InitStruct->GPIO_Mode) << (pinpos * 2)); + + /* Use temporary variable to update PUPDR register configuration, to avoid + unexpected transition in the GPIO pin configuration. */ + tmpreg = GPIOx->PUPDR; + tmpreg &= ~(GPIO_PUPDR_PUPDR0 << ((uint16_t)pinpos * 2)); + tmpreg |= (((uint32_t)GPIO_InitStruct->GPIO_PuPd) << (pinpos * 2)); + GPIOx->PUPDR = tmpreg; + } + } +} + +/** + * @brief Fills each GPIO_InitStruct member with its default value. + * @param GPIO_InitStruct: pointer to a GPIO_InitTypeDef structure which will + * be initialized. + * @retval None + */ +void GPIO_StructInit(GPIO_InitTypeDef* GPIO_InitStruct) +{ + /* Reset GPIO init structure parameters values */ + GPIO_InitStruct->GPIO_Pin = GPIO_Pin_All; + GPIO_InitStruct->GPIO_Mode = GPIO_Mode_IN; + GPIO_InitStruct->GPIO_Speed = GPIO_Speed_2MHz; + GPIO_InitStruct->GPIO_OType = GPIO_OType_PP; + GPIO_InitStruct->GPIO_PuPd = GPIO_PuPd_NOPULL; +} + +/** + * @brief Locks GPIO Pins configuration registers. + * The locked registers are GPIOx_MODER, GPIOx_OTYPER, GPIOx_OSPEEDR, + * GPIOx_PUPDR, GPIOx_AFRL and GPIOx_AFRH. + * @note The configuration of the locked GPIO pins can no longer be modified + * until the next reset. + * @param GPIOx: where x can be (A or B or D) to select the GPIO peripheral. + * @param GPIO_Pin: specifies the port bit to be written. + * This parameter can be any combination of GPIO_Pin_x where x can be (0..15). + * @retval None + */ +void GPIO_PinLockConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) +{ + uint32_t tmp = 0x00010000; + + /* Check the parameters */ + assert_param(IS_GPIO_LIST_PERIPH(GPIOx)); + assert_param(IS_GPIO_PIN(GPIO_Pin)); + + tmp |= GPIO_Pin; + /* Set LCKK bit */ + GPIOx->LCKR = tmp; + /* Reset LCKK bit */ + GPIOx->LCKR = GPIO_Pin; + /* Set LCKK bit */ + GPIOx->LCKR = tmp; + /* Read LCKK bit */ + tmp = GPIOx->LCKR; + /* Read LCKK bit */ + tmp = GPIOx->LCKR; +} + +/** + * @} + */ + +/** @defgroup GPIO_Group2 GPIO Read and Write + * @brief GPIO Read and Write + * +@verbatim + =============================================================================== + ##### GPIO Read and Write ##### + =============================================================================== + +@endverbatim + * @{ + */ + +/** + * @brief Reads the specified input port pin. + * @param GPIOx: where x can be (A, B, C, D, E, F, G or H) to select the GPIO peripheral. + * @param GPIO_Pin: specifies the port bit to read. + * @note This parameter can be GPIO_Pin_x where x can be : + * (0..15) for GPIOA, GPIOB, GPIOC, GPIOD or GPIOE; + * (0..2, 4, 6, 9..10) for GPIOF. + * @retval The input port pin value. + */ +uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) +{ + uint8_t bitstatus = 0x00; + + /* Check the parameters */ + assert_param(IS_GPIO_ALL_PERIPH(GPIOx)); + assert_param(IS_GET_GPIO_PIN(GPIO_Pin)); + + if ((GPIOx->IDR & GPIO_Pin) != (uint32_t)Bit_RESET) + { + bitstatus = (uint8_t)Bit_SET; + } + else + { + bitstatus = (uint8_t)Bit_RESET; + } + return bitstatus; +} + +/** + * @brief Reads the specified input port pin. + * @param GPIOx: where x can be (A, B, C, D, E, F, G or H) to select the GPIO peripheral. + * @retval The input port pin value. + */ +uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx) +{ + /* Check the parameters */ + assert_param(IS_GPIO_ALL_PERIPH(GPIOx)); + + return ((uint16_t)GPIOx->IDR); +} + +/** + * @brief Reads the specified output data port bit. + * @param GPIOx: where x can be (A, B, C, D, E, F, G or H) to select the GPIO peripheral. + * @param GPIO_Pin: Specifies the port bit to read. + * @note This parameter can be GPIO_Pin_x where x can be : + * (0..15) for GPIOA, GPIOB, GPIOC, GPIOD or GPIOE; + * (0..2, 4, 6, 9..10) for GPIOF. + * @retval The output port pin value. + */ +uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) +{ + uint8_t bitstatus = 0x00; + + /* Check the parameters */ + assert_param(IS_GPIO_ALL_PERIPH(GPIOx)); + assert_param(IS_GET_GPIO_PIN(GPIO_Pin)); + + if ((GPIOx->ODR & GPIO_Pin) != (uint32_t)Bit_RESET) + { + bitstatus = (uint8_t)Bit_SET; + } + else + { + bitstatus = (uint8_t)Bit_RESET; + } + return bitstatus; +} + +/** + * @brief Reads the specified GPIO output data port. + * @param GPIOx: where x can be (A, B, C, D, E, F, G or H) to select the GPIO peripheral. + * @retval GPIO output data port value. + */ +uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx) +{ + /* Check the parameters */ + assert_param(IS_GPIO_ALL_PERIPH(GPIOx)); + + return ((uint16_t)GPIOx->ODR); +} + +/** + * @brief Sets the selected data port bits. + * @param GPIOx: where x can be (A, B, C, D, E, F, G or H) to select the GPIO peripheral. + * @param GPIO_Pin: specifies the port bits to be written. + * @note This parameter can be GPIO_Pin_x where x can be : + * (0..15) for GPIOA, GPIOB, GPIOC, GPIOD or GPIOE; + * (0..2, 4, 6, 9..10) for GPIOF. + * @retval None + */ +void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) +{ + /* Check the parameters */ + assert_param(IS_GPIO_ALL_PERIPH(GPIOx)); + assert_param(IS_GPIO_PIN(GPIO_Pin)); + + GPIOx->BSRR = GPIO_Pin; +} + +/** + * @brief Clears the selected data port bits. + * @param GPIOx: where x can be (A, B, C, D, E, F, G or H) to select the GPIO peripheral. + * @param GPIO_Pin: specifies the port bits to be written. + * @note This parameter can be GPIO_Pin_x where x can be : + * (0..15) for GPIOA, GPIOB, GPIOC, GPIOD or GPIOE; + * (0..2, 4, 6, 9..10) for GPIOF. + * @retval None + */ +void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) +{ + /* Check the parameters */ + assert_param(IS_GPIO_ALL_PERIPH(GPIOx)); + assert_param(IS_GPIO_PIN(GPIO_Pin)); + + GPIOx->BRR = GPIO_Pin; +} + +/** + * @brief Sets or clears the selected data port bit. + * @param GPIOx: where x can be (A, B, C, D, E, F, G or H) to select the GPIO peripheral. + * @param GPIO_Pin: specifies the port bit to be written. + * @note This parameter can be GPIO_Pin_x where x can be : + * (0..15) for GPIOA, GPIOB, GPIOC, GPIOD or GPIOE; + * (0..2, 4, 6, 9..10) for GPIOF. + * @param BitVal: specifies the value to be written to the selected bit. + * This parameter can be one of the BitAction enumeration values: + * @arg Bit_RESET: to clear the port pin + * @arg Bit_SET: to set the port pin + * @retval None + */ +void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal) +{ + /* Check the parameters */ + assert_param(IS_GPIO_ALL_PERIPH(GPIOx)); + assert_param(IS_GET_GPIO_PIN(GPIO_Pin)); + assert_param(IS_GPIO_BIT_ACTION(BitVal)); + + if (BitVal != Bit_RESET) + { + GPIOx->BSRR = GPIO_Pin; + } + else + { + GPIOx->BRR = GPIO_Pin ; + } +} + +/** + * @brief Writes data to the specified GPIO data port. + * @param GPIOx: where x can be (A, B, C, D, E, F, G or H) to select the GPIO peripheral. + * @param PortVal: specifies the value to be written to the port output data + * register. + * @retval None + */ +void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal) +{ + /* Check the parameters */ + assert_param(IS_GPIO_ALL_PERIPH(GPIOx)); + + GPIOx->ODR = PortVal; +} + +/** + * @} + */ + +/** @defgroup GPIO_Group3 GPIO Alternate functions configuration functions + * @brief GPIO Alternate functions configuration functions + * +@verbatim + =============================================================================== + ##### GPIO Alternate functions configuration functions ##### + =============================================================================== + +@endverbatim + * @{ + */ + +/** + * @brief Writes data to the specified GPIO data port. + * @param GPIOx: where x can be (A, B, C, D, E, F, G or H) to select the GPIO peripheral. + * @param GPIO_PinSource: specifies the pin for the Alternate function. + * This parameter can be GPIO_PinSourcex where x can be (0..15). + * @param GPIO_AF: selects the pin to be used as Alternate function. + * This parameter can be one of the following value: + * @arg GPIO_AF_0: JTCK-SWCLK, JTDI, JTDO/TRACESW0, JTMS-SWDAT, MCO, NJTRST, + * TRACED, TRACECK. + * @arg GPIO_AF_1: OUT, TIM2, TIM15, TIM16, TIM17. + * @arg GPIO_AF_2: COMP1_OUT, TIM1, TIM2, TIM3, TIM4, TIM8, TIM15, TIM16. + * @arg GPIO_AF_3: COMP7_OUT, TIM8, TIM15, Touch, HRTIM. + * @arg GPIO_AF_4: I2C1, I2C2, TIM1, TIM8, TIM16, TIM17. + * @arg GPIO_AF_5: IR_OUT, I2S2, I2S3, SPI1, SPI2, TIM8, USART4, USART5 + * @arg GPIO_AF_6: IR_OUT, I2S2, I2S3, SPI2, SPI3, TIM1, TIM8 + * @arg GPIO_AF_7: AOP2_OUT, CAN, COMP3_OUT, COMP5_OUT, COMP6_OUT, USART1, + * USART2, USART3. + * @arg GPIO_AF_8: COMP1_OUT, COMP2_OUT, COMP3_OUT, COMP4_OUT, COMP5_OUT, + * COMP6_OUT. + * @arg GPIO_AF_9: AOP4_OUT, CAN, TIM1, TIM8, TIM15. + * @arg GPIO_AF_10: AOP1_OUT, AOP3_OUT, TIM2, TIM3, TIM4, TIM8, TIM17. + * @arg GPIO_AF_11: TIM1, TIM8. + * @arg GPIO_AF_12: TIM1, HRTIM. + * @arg GPIO_AF_13: HRTIM, AOP2_OUT. + * @arg GPIO_AF_14: USBDM, USBDP. + * @arg GPIO_AF_15: OUT. + * @note The pin should already been configured in Alternate Function mode(AF) + * using GPIO_InitStruct->GPIO_Mode = GPIO_Mode_AF + * @note Refer to the Alternate function mapping table in the device datasheet + * for the detailed mapping of the system and peripherals alternate + * function I/O pins. + * @retval None + */ +void GPIO_PinAFConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_PinSource, uint8_t GPIO_AF) +{ + uint32_t temp = 0x00; + uint32_t temp_2 = 0x00; + + /* Check the parameters */ + assert_param(IS_GPIO_ALL_PERIPH(GPIOx)); + assert_param(IS_GPIO_PIN_SOURCE(GPIO_PinSource)); + assert_param(IS_GPIO_AF(GPIO_AF)); + + temp = ((uint32_t)(GPIO_AF) << ((uint32_t)((uint32_t)GPIO_PinSource & (uint32_t)0x07) * 4)); + GPIOx->AFR[GPIO_PinSource >> 0x03] &= ~((uint32_t)0xF << ((uint32_t)((uint32_t)GPIO_PinSource & (uint32_t)0x07) * 4)); + temp_2 = GPIOx->AFR[GPIO_PinSource >> 0x03] | temp; + GPIOx->AFR[GPIO_PinSource >> 0x03] = temp_2; +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_hrtim.c b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_hrtim.c new file mode 100755 index 0000000000..4e2cd3e7d9 --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_hrtim.c @@ -0,0 +1,4103 @@ +/** + ****************************************************************************** + * @file stm32f30x_hrtim.c + * @author MCD Application Team + * @version V1.2.3 + * @date 10-July-2015 + * @brief HRTIMx module driver. + * + * This file provides firmware functions to manage the following + * functionalities of the HRTIMx peripheral: + * + Initialization/de-initialization methods + * + I/O operation methods + * + Peripheral Control methods + * + @verbatim +================================================================================ + ##### ##### +================================================================================ + + [..] < HRTIM introduction: + (#) The high-resolution timer can generate up to 10 digital signals with + highly accurate timings. + It is primarily intended to drive power conversion systems such as + switch mode power supplies or lighting systems, + but can be of general purpose usage, whenever a very fine timing + resolution is expected. + + (#) Its modular architecture allows to generate either independent or + coupled waveforms. + The wave-shape is defined by self-contained timings + (using counters and compare units) and a broad range of external events, + such as analog or digital feedbacks and synchronisation signals. + This allows to produce a large variety of control signal (PWM, phase-shifted, + constant Ton,...) and address most of conversion topologies. + + (#) For control and monitoring purposes, the timer has also timing measure + capabilities and links to built-in ADC and DAC converters. + Last, it features light-load management mode and is able to handle + various fault schemes for safe shut-down purposes. + + + ##### How to use this driver ##### +================================================================================ + [..] This driver provides functions to configure and program the HRTIM + of all stm32f33x devices. + These functions are split in 9 groups: + + (#) HRTIM Simple TimeBase management: this group includes all needed functions + to configure the HRTIM Timebase unit: + (++) Initializes the HRTIMx timer in simple time base mode + (++) Start/Stop the time base generation + (++) Deinitialize the HRTIM peripheral + + + (#) HRTIM simple Output Compare management: this group includes all needed + functions to configure the Compare unit used in Output compare mode: + (++) Initializes the HRTIMx timer time base unit + (++) Configure the compare unit in simple Output Compare mode + (++) Start/Stop the Output compare generation + + (#) HRTIM simple PWM management: this group includes all needed + functions to configure the Compare unit used in PWM mode: + (++) Initializes the HRTIMx timer time base unit + (++) Configure the compare unit in simple PWM mode + (++) Start/Stop the PWM generation + + (#) HRTIM simple Capture management: this group includes all needed + functions to configure the Capture unit used in Capture mode: + (++) Initializes the HRTIMx timer time base unit + (++) Configure the compare unit in simple Capture mode + (++) Start/Stop the Capture mode + + (#) HRTIM simple One Pulse management: this group includes all needed + functions to configure the Capture unit and Compare unit used in One Pulse mode: + (++) Initializes the HRTIMx timer time base unit + (++) Configure the compare unit and the capture unit in simple One Pulse mode + (++) Start/Stop the One Pulse mode generation + + (#) HRTIM Waveform management: this group includes all needed + functions to configure the HRTIM possible waveform mode: + (++) Initializes the HRTIMx timer Master time base unit + (++) Initializes the HRTIMx timer Slaves time base unit + (++) Configures the HRTIMx timer Compare unit + (++) Configures the HRTIMx Slave timer Capture unit + (++) Configures the HRTIMx timer Output unit + (++) Configures the HRTIMx timer DeadTime / Chopper / Burst features + (++) Configures the HRTIMx timer Fault / External event features + (++) Configures the HRTIMx timer Synchronization features: Internal/External connection, DACs,... + (++) Configures the HRTIMx timer Synchronization features: ADCs Triggers + (++) HRTIMx timer Outputs Start/Stop + (++) Start/Stop the HRTIMx Timer counters + + (#) HRTIM interrupts, DMA and flags management + (++) Enable/Disable interrupt sources + (++) Get flags status + (++) Clear flags/ Pending bits + (++) Enable/Disable DMA requests + (++) Configure DMA burst mode + + (#) TIM specific interface management, this group includes all + needed functions to use the specific TIM interface: + (++) HRTIMx timer DLL calibration + + @endverbatim + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ +/* Includes ------------------------------------------------------------------*/ +#include "stm32f30x_hrtim.h" + +/** @addtogroup STM32F30x_StdPeriph_Driver + * @{ + */ + +/** @defgroup HRTIM + * @brief HRTIM driver module + * @{ + */ + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +#define HRTIM_FLTR_FLTxEN (HRTIM_FLTR_FLT1EN |\ + HRTIM_FLTR_FLT2EN |\ + HRTIM_FLTR_FLT3EN |\ + HRTIM_FLTR_FLT4EN | \ + HRTIM_FLTR_FLT5EN) + +#define HRTIM_TIMCR_TIMUPDATETRIGGER (HRTIM_TIMUPDATETRIGGER_MASTER |\ + HRTIM_TIMUPDATETRIGGER_TIMER_A |\ + HRTIM_TIMUPDATETRIGGER_TIMER_B |\ + HRTIM_TIMUPDATETRIGGER_TIMER_C |\ + HRTIM_TIMUPDATETRIGGER_TIMER_D |\ + HRTIM_TIMUPDATETRIGGER_TIMER_E) + +#define HRTIM_TIM_OFFSET (uint32_t)0x00000080 +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +static uint32_t TimerIdxToTimerId[] = +{ + HRTIM_TIMERID_TIMER_A, + HRTIM_TIMERID_TIMER_B, + HRTIM_TIMERID_TIMER_C, + HRTIM_TIMERID_TIMER_D, + HRTIM_TIMERID_TIMER_E, + HRTIM_TIMERID_MASTER, +}; + +/* Private function prototypes -----------------------------------------------*/ +/* Private functions ---------------------------------------------------------*/ +static void HRTIM_MasterBase_Config(HRTIM_TypeDef* HRTIMx, HRTIM_BaseInitTypeDef* HRTIM_BaseInitStruc); +static void HRTIM_TimingUnitBase_Config(HRTIM_TypeDef * HRTIMx, uint32_t TimerIdx, HRTIM_BaseInitTypeDef* HRTIM_BaseInitStruct); +static void HRTIM_MasterWaveform_Config(HRTIM_TypeDef * HRTIMx, HRTIM_TimerInitTypeDef * TimerInit); +static void HRTIM_TimingUnitWaveform_Config(HRTIM_TypeDef * HRTIMx, + uint32_t TimerIdx, + HRTIM_TimerInitTypeDef * TimerInit); +static void HRTIM_CompareUnitConfig(HRTIM_TypeDef * HRTIMx, + uint32_t TimerIdx, + uint32_t CompareUnit, + HRTIM_CompareCfgTypeDef * CompareCfg); +static void HRTIM_CaptureUnitConfig(HRTIM_TypeDef * HRTIMx, + uint32_t TimerIdx, + uint32_t CaptureUnit, + uint32_t Event); +static void HRTIM_OutputConfig(HRTIM_TypeDef * HRTIMx, + uint32_t TimerIdx, + uint32_t Output, + HRTIM_OutputCfgTypeDef * OutputCfg); +static void HRTIM_ExternalEventConfig(HRTIM_TypeDef * HRTIMx, + uint32_t Event, + HRTIM_EventCfgTypeDef * EventCfg); +static void HRTIM_TIM_ResetConfig(HRTIM_TypeDef * HRTIMx, + uint32_t TimerIdx, + uint32_t Event); + /** @defgroup HRTIM_Private_Functions + * @{ + */ + +/** @defgroup HRTIM_Group1 Initialization/de-initialization methods + * @brief Initialization and Configuration functions + * +@verbatim + =============================================================================== + ##### Initialization/de-initialization methods ##### + =============================================================================== + [..] This section provides functions allowing to: + (+)Initializes timer in basic time base mode + (+)Initializes timer in basic OC mode + (+)Initializes timer in basic PWM mode + (+)Initializes timer in basic Capture mode + (+)Initializes timer in One Pulse mode + (+)Initializes a timer operating in waveform mode + (+)De-initializes the HRTIMx timer + +@endverbatim + * @{ + */ + +/** + * @brief Initializes the HRTIMx timer in basic time base mode + * @param HRTIMx: pointer to HRTIMx peripheral + * @param TimerIdx: Timer index + * This parameter can be one of the following values: + * @arg 0x0 for master timer + * @arg 0x1 to 0x5 for timers A to E + * @note The time-base unit initialization parameters specify: + * The timer counter operating mode (continuous, one shot) + * The timer clock prescaler + * The timer period + * The timer repetition counter. + * @retval None + */ +void HRTIM_SimpleBase_Init(HRTIM_TypeDef* HRTIMx, uint32_t TimerIdx, HRTIM_BaseInitTypeDef* HRTIM_BaseInitStruct) +{ + /* Check the parameters */ + assert_param(IS_HRTIM_TIMERINDEX(TimerIdx)); + assert_param(IS_HRTIM_MODE(HRTIM_BaseInitStruct->Mode)); + + if (TimerIdx == HRTIM_TIMERINDEX_MASTER) + { + /* Configure master timer */ + HRTIM_MasterBase_Config(HRTIMx, HRTIM_BaseInitStruct); + } + else + { + /* Configure timing unit */ + HRTIM_TimingUnitBase_Config(HRTIMx, TimerIdx, HRTIM_BaseInitStruct); + } +} + +/** + * @brief De-initializes a timer operating in all mode + * @param HRTIMx: pointer to HRTIMx peripheral + * @retval None + */ +void HRTIM_DeInit(HRTIM_TypeDef* HRTIMx) +{ + /* Check the parameters */ + RCC_APB2PeriphResetCmd(RCC_APB2Periph_HRTIM1, ENABLE); + RCC_APB2PeriphResetCmd(RCC_APB2Periph_HRTIM1, DISABLE); + } + +/** + * @brief Initializes the HRTIMx timer in basic output compare mode + * @param HRTIMx: pointer to HRTIMx peripheral + * @param TimerIdx: Timer index + * This parameter can be one of the following values: + * @arg 0x1 to 0x5 for timers A to E + * @note Initializes the time-base unit of the timer and prepare it to + * operate in output compare mode + * @retval None + */ +void HRTIM_SimpleOC_Init(HRTIM_TypeDef * HRTIMx, uint32_t TimerIdx, HRTIM_BaseInitTypeDef* HRTIM_BaseInitStruct) +{ + /* Check the parameters */ + assert_param(IS_HRTIM_TIMERINDEX(TimerIdx)); + assert_param(IS_HRTIM_MODE(HRTIM_BaseInitStruct->Mode)); + + /* Configure timing unit */ + HRTIM_TimingUnitBase_Config(HRTIMx, TimerIdx, HRTIM_BaseInitStruct); +} + +/** + * @brief Initializes the HRTIMx timer in basic PWM mode + * @param HRTIMx: pointer to HRTIMx peripheral + * @param TimerIdx: Timer index + * This parameter can be one of the following values: + * @arg 0x1 to 0x5 for timers A to E + * @note Initializes the time-base unit of the timer and prepare it to + * operate in capture mode + * @retval None + */ +void HRTIM_SimplePWM_Init(HRTIM_TypeDef * HRTIMx, uint32_t TimerIdx, HRTIM_BaseInitTypeDef* HRTIM_BaseInitStruct) +{ + /* Check the parameters */ + assert_param(IS_HRTIM_TIMERINDEX(TimerIdx)); + assert_param(IS_HRTIM_MODE(HRTIM_BaseInitStruct->Mode)); + + /* Configure timing unit */ + HRTIM_TimingUnitBase_Config(HRTIMx, TimerIdx, HRTIM_BaseInitStruct); +} + +/** + * @brief Initializes a timer operating in basic capture mode + * @param HRTIMx: pointer to HRTIMx peripheral + * @param TimerIdx: Timer index + * This parameter can be one of the following values: + * @arg 0x1 to 0x5 for timers A to E + * @retval None + */ +void HRTIM_SimpleCapture_Init(HRTIM_TypeDef * HRTIMx, uint32_t TimerIdx, HRTIM_BaseInitTypeDef* HRTIM_BaseInitStruct) +{ + /* Check the parameters */ + assert_param(IS_HRTIM_TIMERINDEX(TimerIdx)); + assert_param(IS_HRTIM_MODE(HRTIM_BaseInitStruct->Mode)); + + /* Configure timing unit */ + HRTIM_TimingUnitBase_Config(HRTIMx, TimerIdx, HRTIM_BaseInitStruct); +} + +/** + * @brief Initializes the HRTIMx timer in basic one pulse mode + * @param HRTIMx: pointer to HRTIMx peripheral + * @param TimerIdx: Timer index + * This parameter can be one of the following values: + * @arg 0x1 to 0x5 for timers A to E + * @note Initializes the time-base unit of the timer and prepare it to + * operate in one pulse mode. In this mode the counter operates + * in single shot mode (retriggerable or not) + * @retval None + */ +void HRTIM_SimpleOnePulse_Init(HRTIM_TypeDef * HRTIMx, uint32_t TimerIdx, HRTIM_BaseInitTypeDef* HRTIM_BaseInitStruct) +{ + /* Check the parameters */ + assert_param(IS_HRTIM_TIMERINDEX(TimerIdx)); + assert_param(IS_HRTIM_MODE(HRTIM_BaseInitStruct->Mode)); + + /* Configure timing unit */ + HRTIM_TimingUnitBase_Config(HRTIMx, TimerIdx, HRTIM_BaseInitStruct); +} + +/** + * @brief Initializes a timer operating in waveform mode + * @param HRTIMx: pointer to HRTIMx peripheral + * @param TimerIdx: Timer index + * This parameter can be one of the following values: + * @arg 0x0 for master timer + * @arg 0x1 to 0x5 for timers A to E + * @param pTimerInit: pointer to the timer initialization data structure + * @retval None + */ +void HRTIM_Waveform_Init(HRTIM_TypeDef * HRTIMx, + uint32_t TimerIdx, + HRTIM_BaseInitTypeDef* HRTIM_BaseInitStruct, + HRTIM_TimerInitTypeDef* HRTIM_TimerInitStruct) +{ + /* Check the parameters */ + assert_param(IS_HRTIM_HALFMODE(HRTIM_TimerInitStruct->HalfModeEnable)); + assert_param(IS_HRTIM_SYNCSTART(HRTIM_TimerInitStruct->StartOnSync)); + assert_param(IS_HRTIM_SYNCRESET(HRTIM_TimerInitStruct->ResetOnSync)); + assert_param(IS_HRTIM_DACSYNC(HRTIM_TimerInitStruct->DACSynchro)); + assert_param(IS_HRTIM_PRELOAD(HRTIM_TimerInitStruct->PreloadEnable)); + assert_param(IS_HRTIM_TIMERBURSTMODE(HRTIM_TimerInitStruct->BurstMode)); + assert_param(IS_HRTIM_UPDATEONREPETITION(HRTIM_TimerInitStruct->RepetitionUpdate)); + + if (TimerIdx == HRTIM_TIMERINDEX_MASTER) + { + /* Check parameters */ + assert_param(IS_HRTIM_UPDATEGATING_MASTER(HRTIM_TimerInitStruct->UpdateGating)); + + /* Configure master timer */ + HRTIM_MasterBase_Config(HRTIMx, HRTIM_BaseInitStruct); + HRTIM_MasterWaveform_Config(HRTIMx, HRTIM_TimerInitStruct); + } + else + { + /* Check parameters */ + assert_param(IS_HRTIM_UPDATEGATING_TIM(HRTIM_TimerInitStruct->UpdateGating)); + + /* Configure timing unit */ + HRTIM_TimingUnitBase_Config(HRTIMx, TimerIdx, HRTIM_BaseInitStruct); + HRTIM_TimingUnitWaveform_Config(HRTIMx, TimerIdx, HRTIM_TimerInitStruct); + } +} + +/** + * @} + */ + +/** @defgroup HRTIM_Group2 I/O operation methods + * @brief Data transfers functions + * +@verbatim + =============================================================================== + ##### IO operation methods ##### + =============================================================================== + [..] + This subsection provides a set of functions allowing to manage the HRTIMx data + transfers. + (+) Starts the DLL calibration. + (+) Starts / stops the counter of a timer operating in basic time base mode + (+) Starts / stops the output compare signal generation on the designed timer output + (+) Starts / stops the PWM output signal generation on the designed timer output + (+) Enables / disables a basic capture on the designed capture unit + +@endverbatim + * @{ + */ + +/** + * @brief Starts the DLL calibration + * @param HRTIMx: pointer to HRTIMx peripheral + * @param CalibrationRate: DLL calibration period + * This parameter can be one of the following values: + * @arg HRTIM_SINGLE_CALIBRATION: One shot DLL calibration + * @arg HRTIM_CALIBRATIONRATE_7300: 7.3 ms + * @arg HRTIM_CALIBRATIONRATE_910: 910 us + * @arg HRTIM_CALIBRATIONRATE_114: 114 us + * @arg HRTIM_CALIBRATIONRATE_14: 14 us + * @retval None + */ +void HRTIM_DLLCalibrationStart(HRTIM_TypeDef * HRTIMx, uint32_t CalibrationRate) +{ + uint32_t HRTIM_dllcr; + + /* Check the parameters */ + assert_param(IS_HRTIM_CALIBRATIONRATE(CalibrationRate)); + + /* Configure DLL Calibration */ + HRTIM_dllcr = (HRTIMx->HRTIM_COMMON).DLLCR; + + if (CalibrationRate == HRTIM_SINGLE_CALIBRATION) + { + /* One shot DLL calibration */ + HRTIM_dllcr &= ~(HRTIM_DLLCR_CALEN); + HRTIM_dllcr |= HRTIM_DLLCR_CAL; + } + else + { + /* Periodic DLL calibration */ + HRTIM_dllcr &= ~(HRTIM_DLLCR_CALRTE | HRTIM_DLLCR_CAL); + HRTIM_dllcr |= (CalibrationRate | HRTIM_DLLCR_CALEN); + } + + /* Update HRTIMx register */ + HRTIMx->HRTIM_COMMON.DLLCR = HRTIM_dllcr; + +} +/** + * @brief Starts the counter of a timer operating in basic time base mode + * @param HRTIMx: pointer to HRTIM peripheral + * @param TimerIdx: Timer index + * This parameter can be one of the following values: + * @arg 0x5 for master timer + * @arg 0x0 to 0x4 for timers A to E + * @retval None + */ +void HRTIM_SimpleBaseStart(HRTIM_TypeDef * HRTIMx, uint32_t TimerIdx) +{ + /* Check the parameters */ + assert_param(IS_HRTIM_TIMERINDEX(TimerIdx)); + + /* Enable the timer counter */ + __HRTIM_ENABLE(HRTIMx, TimerIdxToTimerId[TimerIdx]); +} + +/** + * @brief Stops the counter of a timer operating in basic time base mode + * @param HRTIMx: pointer to HRTIM peripheral + * @param TimerIdx: Timer index + * This parameter can be one of the following values: + * @arg 0x5 for master timer + * @arg 0x0 to 0x4 for timers A to E + * @retval None + */ +void HRTIM_SimpleBaseStop(HRTIM_TypeDef * HRTIMx, uint32_t TimerIdx) +{ + /* Check the parameters */ + assert_param(IS_HRTIM_TIMERINDEX(TimerIdx)); + + /* Disable the timer counter */ + __HRTIM_DISABLE(HRTIMx, TimerIdxToTimerId[TimerIdx]); +} + +/** + * @brief Starts the output compare signal generation on the designed timer output + * @param HRTIMx: pointer to HRTIM peripheral + * @param TimerIdx: Timer index + * This parameter can be one of the following values: + * @arg 0x0 to 0x4 for timers A to E + * @param OCChannel: Timer output + * This parameter can be one of the following values: + * @arg HRTIM_OUTPUT_TA1: Timer A - Output 1 + * @arg HRTIM_OUTPUT_TA2: Timer A - Output 2 + * @arg HRTIM_OUTPUT_TB1: Timer B - Output 1 + * @arg HRTIM_OUTPUT_TB2: Timer B - Output 2 + * @arg HRTIM_OUTPUT_TC1: Timer C - Output 1 + * @arg HRTIM_OUTPUT_TC2: Timer C - Output 2 + * @arg HRTIM_OUTPUT_TD1: Timer D - Output 1 + * @arg HRTIM_OUTPUT_TD2: Timer D - Output 2 + * @arg HRTIM_OUTPUT_TE1: Timer E - Output 1 + * @arg HRTIM_OUTPUT_TE2: Timer E - Output 2 + * @retval None + */ +void HRTIM_SimpleOCStart(HRTIM_TypeDef * HRTIMx, + uint32_t TimerIdx, + uint32_t OCChannel) +{ + /* Check the parameters */ + assert_param(IS_HRTIM_TIMER_OUTPUT(TimerIdx, OCChannel)); + + /* Enable the timer output */ + (HRTIMx->HRTIM_COMMON).OENR |= OCChannel; + + /* Enable the timer counter */ + __HRTIM_ENABLE(HRTIMx, TimerIdxToTimerId[TimerIdx]); + +} + +/** + * @brief Stops the output compare signal generation on the designed timer output + * @param HRTIMx: pointer to HRTIM peripheral + * @param TimerIdx: Timer index + * This parameter can be one of the following values: + * @arg 0x0 to 0x4 for timers A to E + * @param OCChannel: Timer output + * This parameter can be one of the following values: + * @arg HRTIM_OUTPUT_TA1: Timer A - Output 1 + * @arg HRTIM_OUTPUT_TA2: Timer A - Output 2 + * @arg HRTIM_OUTPUT_TB1: Timer B - Output 1 + * @arg HRTIM_OUTPUT_TB2: Timer B - Output 2 + * @arg HRTIM_OUTPUT_TC1: Timer C - Output 1 + * @arg HRTIM_OUTPUT_TC2: Timer C - Output 2 + * @arg HRTIM_OUTPUT_TD1: Timer D - Output 1 + * @arg HRTIM_OUTPUT_TD2: Timer D - Output 2 + * @arg HRTIM_OUTPUT_TE1: Timer E - Output 1 + * @arg HRTIM_OUTPUT_TE2: Timer E - Output 2 + * @retval None + */ +void HRTIM_SimpleOCStop(HRTIM_TypeDef * HRTIMx, + uint32_t TimerIdx, + uint32_t OCChannel) +{ + /* Check the parameters */ + assert_param(IS_HRTIM_TIMER_OUTPUT(TimerIdx, OCChannel)); + + /* Disable the timer output */ + HRTIMx->HRTIM_COMMON.DISR |= OCChannel; + + /* Disable the timer counter */ + __HRTIM_DISABLE(HRTIMx, TimerIdxToTimerId[TimerIdx]); +} + +/** + * @brief Starts the PWM output signal generation on the designed timer output + * @param HRTIMx: pointer to HRTIM peripheral + * @param TimerIdx: Timer index + * This parameter can be one of the following values: + * @arg 0x0 to 0x4 for timers A to E + * @param PWMChannel: Timer output + * This parameter can be one of the following values: + * @arg HRTIM_OUTPUT_TA1: Timer A - Output 1 + * @arg HRTIM_OUTPUT_TA2: Timer A - Output 2 + * @arg HRTIM_OUTPUT_TB1: Timer B - Output 1 + * @arg HRTIM_OUTPUT_TB2: Timer B - Output 2 + * @arg HRTIM_OUTPUT_TC1: Timer C - Output 1 + * @arg HRTIM_OUTPUT_TC2: Timer C - Output 2 + * @arg HRTIM_OUTPUT_TD1: Timer D - Output 1 + * @arg HRTIM_OUTPUT_TD2: Timer D - Output 2 + * @arg HRTIM_OUTPUT_TE1: Timer E - Output 1 + * @arg HRTIM_OUTPUT_TE2: Timer E - Output 2 + * @retval None + */ +void HRTIM_SimplePWMStart(HRTIM_TypeDef * HRTIMx, + uint32_t TimerIdx, + uint32_t PWMChannel) +{ + /* Check the parameters */ + assert_param(IS_HRTIM_TIMER_OUTPUT(TimerIdx, PWMChannel)); + + /* Enable the timer output */ + HRTIMx->HRTIM_COMMON.OENR |= PWMChannel; + + /* Enable the timer counter */ + __HRTIM_ENABLE(HRTIMx, TimerIdxToTimerId[TimerIdx]); +} + +/** + * @brief Stops the PWM output signal generation on the designed timer output + * @param HRTIMx: pointer to HRTIM peripheral + * @param TimerIdx: Timer index + * This parameter can be one of the following values: + * @arg 0x0 to 0x4 for timers A to E + * @param PWMChannel: Timer output + * This parameter can be one of the following values: + * @arg HRTIM_OUTPUT_TA1: Timer A - Output 1 + * @arg HRTIM_OUTPUT_TA2: Timer A - Output 2 + * @arg HRTIM_OUTPUT_TB1: Timer B - Output 1 + * @arg HRTIM_OUTPUT_TB2: Timer B - Output 2 + * @arg HRTIM_OUTPUT_TC1: Timer C - Output 1 + * @arg HRTIM_OUTPUT_TC2: Timer C - Output 2 + * @arg HRTIM_OUTPUT_TD1: Timer D - Output 1 + * @arg HRTIM_OUTPUT_TD2: Timer D - Output 2 + * @arg HRTIM_OUTPUT_TE1: Timer E - Output 1 + * @arg HRTIM_OUTPUT_TE2: Timer E - Output 2 + * @retval None + */ +void HRTIM_SimplePWMStop(HRTIM_TypeDef * HRTIMx, + uint32_t TimerIdx, + uint32_t PWMChannel) +{ + /* Check the parameters */ + assert_param(IS_HRTIM_TIMER_OUTPUT(TimerIdx, PWMChannel)); + + /* Disable the timer output */ + HRTIMx->HRTIM_COMMON.DISR |= PWMChannel; + + /* Disable the timer counter */ + __HRTIM_DISABLE(HRTIMx, TimerIdxToTimerId[TimerIdx]); +} + +/** + * @brief Enables a basic capture on the designed capture unit + * @param HRTIMx: pointer to HRTIM peripheral + * @param TimerIdx: Timer index + * This parameter can be one of the following values: + * @arg 0x0 to 0x4 for timers A to E + * @param CaptureChannel: Timer output + * This parameter can be one of the following values: + * @arg HRTIM_CAPTUREUNIT_1: Capture unit 1 + * @arg HRTIM_CAPTUREUNIT_2: Capture unit 2 + * @retval None + * @note The external event triggering the capture is available for all timing + * units. It can be used directly and is active as soon as the timing + * unit counter is enabled. + */ +void HRTIM_SimpleCaptureStart(HRTIM_TypeDef * HRTIMx, + uint32_t TimerIdx, + uint32_t CaptureChannel) +{ + /* Enable the timer counter */ + __HRTIM_ENABLE(HRTIMx, TimerIdxToTimerId[TimerIdx]); + +} + +/** + * @brief Disables a basic capture on the designed capture unit + * @param HRTIMx: pointer to HRTIMx peripheral + * @param TimerIdx: Timer index + * This parameter can be one of the following values: + * @arg 0x0 to 0x4 for timers A to E + * @param CaptureChannel: Timer output + * This parameter can be one of the following values: + * @arg HRTIM_CAPTUREUNIT_1: Capture unit 1 + * @arg HRTIM_CAPTUREUNIT_2: Capture unit 2 + * @retval None + */ +void HRTIM_SimpleCaptureStop(HRTIM_TypeDef * HRTIMx, + uint32_t TimerIdx, + uint32_t CaptureChannel) +{ + /* Check the parameters */ + assert_param(IS_HRTIM_TIMING_UNIT(TimerIdx)); + assert_param(IS_HRTIM_CAPTUREUNIT(CaptureChannel)); + + /* Set the capture unit trigger */ + switch (CaptureChannel) + { + case HRTIM_CAPTUREUNIT_1: + { + HRTIMx->HRTIM_TIMERx[TimerIdx].CPT1xCR = HRTIM_CAPTURETRIGGER_NONE; + } + break; + case HRTIM_CAPTUREUNIT_2: + { + HRTIMx->HRTIM_TIMERx[TimerIdx].CPT2xCR = HRTIM_CAPTURETRIGGER_NONE; + } + break; + default: + break; + } + + /* Disable the timer counter */ + if ((HRTIMx->HRTIM_TIMERx[TimerIdx].CPT1xCR == HRTIM_CAPTURETRIGGER_NONE) && + (HRTIMx->HRTIM_TIMERx[TimerIdx].CPT2xCR == HRTIM_CAPTURETRIGGER_NONE)) + { + __HRTIM_DISABLE(HRTIMx, TimerIdxToTimerId[TimerIdx]); + } + +} + +/** + * @brief Enables the basic one pulse signal generation on the designed output + * @param HRTIMx: pointer to HRTIMx peripheral + * @param TimerIdx: Timer index + * This parameter can be one of the following values: + * @arg 0x0 to 0x4 for timers A to E + * @param OnePulseChannel: Timer output + * This parameter can be one of the following values: + * @arg HRTIM_OUTPUT_TA1: Timer A - Output 1 + * @arg HRTIM_OUTPUT_TA2: Timer A - Output 2 + * @arg HRTIM_OUTPUT_TB1: Timer B - Output 1 + * @arg HRTIM_OUTPUT_TB2: Timer B - Output 2 + * @arg HRTIM_OUTPUT_TC1: Timer C - Output 1 + * @arg HRTIM_OUTPUT_TC2: Timer C - Output 2 + * @arg HRTIM_OUTPUT_TD1: Timer D - Output 1 + * @arg HRTIM_OUTPUT_TD2: Timer D - Output 2 + * @arg HRTIM_OUTPUT_TE1: Timer E - Output 1 + * @arg HRTIM_OUTPUT_TE2: Timer E - Output 2 + * @retval None + */ +void HRTIM_SimpleOnePulseStart(HRTIM_TypeDef * HRTIMx, + uint32_t TimerIdx, + uint32_t OnePulseChannel) +{ + /* Check the parameters */ + assert_param(IS_HRTIM_TIMER_OUTPUT(TimerIdx, OnePulseChannel)); + + /* Enable the timer output */ + HRTIMx->HRTIM_COMMON.OENR |= OnePulseChannel; + + /* Enable the timer counter */ + __HRTIM_ENABLE(HRTIMx, TimerIdxToTimerId[TimerIdx]); +} + +/** + * @brief Disables the basic one pulse signal generation on the designed output + * @param HRTIMx: pointer to HRTIMx peripheral + * @param TimerIdx: Timer index + * This parameter can be one of the following values: + * @arg 0x0 to 0x4 for timers A to E + * @param OnePulseChannel: Timer output + * This parameter can be one of the following values: + * @arg HRTIM_OUTPUT_TA1: Timer A - Output 1 + * @arg HRTIM_OUTPUT_TA2: Timer A - Output 2 + * @arg HRTIM_OUTPUT_TB1: Timer B - Output 1 + * @arg HRTIM_OUTPUT_TB2: Timer B - Output 2 + * @arg HRTIM_OUTPUT_TC1: Timer C - Output 1 + * @arg HRTIM_OUTPUT_TC2: Timer C - Output 2 + * @arg HRTIM_OUTPUT_TD1: Timer D - Output 1 + * @arg HRTIM_OUTPUT_TD2: Timer D - Output 2 + * @arg HRTIM_OUTPUT_TE1: Timer E - Output 1 + * @arg HRTIM_OUTPUT_TE2: Timer E - Output 2 + * @retval None + */ +void HRTIM_SimpleOnePulseStop(HRTIM_TypeDef * HRTIMx, + uint32_t TimerIdx, + uint32_t OnePulseChannel) +{ + /* Check the parameters */ + assert_param(IS_HRTIM_TIMER_OUTPUT(TimerIdx, OnePulseChannel)); + + /* Disable the timer output */ + HRTIMx->HRTIM_COMMON.DISR |= OnePulseChannel; + + /* Disable the timer counter */ + __HRTIM_DISABLE(HRTIMx, TimerIdxToTimerId[TimerIdx]); +} + +/** + * @brief Starts the counter of the designated timer(s) operating in waveform mode + * Timers can be combined (ORed) to allow for simultaneous counter start + * @param HRTIMx: pointer to HRTIMx peripheral + * @param TimersToStart: Timer counter(s) to start + * This parameter can be any combination of the following values: + * @arg HRTIM_TIMERID_MASTER + * @arg HRTIM_TIMERID_TIMER_A + * @arg HRTIM_TIMERID_TIMER_B + * @arg HRTIM_TIMERID_TIMER_C + * @arg HRTIM_TIMERID_TIMER_D + * @arg HRTIM_TIMERID_TIMER_E + * @retval None + */ +void HRTIM_WaveformCounterStart(HRTIM_TypeDef * HRTIMx, + uint32_t TimersToStart) +{ + /* Enable timer(s) counter */ + HRTIMx->HRTIM_MASTER.MCR |= TimersToStart; +} + +/** + * @brief Stops the counter of the designated timer(s) operating in waveform mode + * Timers can be combined (ORed) to allow for simultaneous counter stop + * @param HRTIMx: pointer to HRTIMx peripheral + * @param TimersToStop: Timer counter(s) to stop + * This parameter can be any combination of the following values: + * @arg HRTIM_TIMERID_MASTER + * @arg HRTIM_TIMERID_TIMER_A + * @arg HRTIM_TIMERID_TIMER_B + * @arg HRTIM_TIMERID_TIMER_C + * @arg HRTIM_TIMERID_TIMER_D + * @arg HRTIM_TIMERID_TIMER_E + * @retval None + */ +void HRTIM_WaveformCounterStop(HRTIM_TypeDef * HRTIMx, + uint32_t TimersToStop) +{ + /* Disable timer(s) counter */ + HRTIMx->HRTIM_MASTER.MCR &= ~TimersToStop; +} + +/** + * @brief Enables the generation of the waveform signal on the designated output(s) + * Outputs can be combined (ORed) to allow for simultaneous output enabling + * @param HRTIMx: pointer to HRTIMx peripheral + * @param OutputsToStart: Timer output(s) to enable + * This parameter can be any combination of the following values: + * @arg HRTIM_OUTPUT_TA1: Timer A - Output 1 + * @arg HRTIM_OUTPUT_TA2: Timer A - Output 2 + * @arg HRTIM_OUTPUT_TB1: Timer B - Output 1 + * @arg HRTIM_OUTPUT_TB2: Timer B - Output 2 + * @arg HRTIM_OUTPUT_TC1: Timer C - Output 1 + * @arg HRTIM_OUTPUT_TC2: Timer C - Output 2 + * @arg HRTIM_OUTPUT_TD1: Timer D - Output 1 + * @arg HRTIM_OUTPUT_TD2: Timer D - Output 2 + * @arg HRTIM_OUTPUT_TE1: Timer E - Output 1 + * @arg HRTIM_OUTPUT_TE2: Timer E - Output 2 + * @retval None + */ +void HRTIM_WaveformOutputStart(HRTIM_TypeDef * HRTIMx, + uint32_t OutputsToStart) +{ + /* Enable the HRTIM outputs */ + HRTIMx->HRTIM_COMMON.OENR = OutputsToStart; +} + +/** + * @brief Disables the generation of the waveform signal on the designated output(s) + * Outputs can be combined (ORed) to allow for simultaneous output disabling + * @param HRTIMx: pointer to HRTIMx peripheral + * @param OutputsToStop: Timer output(s) to disable + * This parameter can be any combination of the following values: + * @arg HRTIM_OUTPUT_TA1: Timer A - Output 1 + * @arg HRTIM_OUTPUT_TA2: Timer A - Output 2 + * @arg HRTIM_OUTPUT_TB1: Timer B - Output 1 + * @arg HRTIM_OUTPUT_TB2: Timer B - Output 2 + * @arg HRTIM_OUTPUT_TC1: Timer C - Output 1 + * @arg HRTIM_OUTPUT_TC2: Timer C - Output 2 + * @arg HRTIM_OUTPUT_TD1: Timer D - Output 1 + * @arg HRTIM_OUTPUT_TD2: Timer D - Output 2 + * @arg HRTIM_OUTPUT_TE1: Timer E - Output 1 + * @arg HRTIM_OUTPUT_TE2: Timer E - Output 2 + * @retval None + */ +void HRTIM_WaveformOutputStop(HRTIM_TypeDef * HRTIMx, + uint32_t OutputsToStop) +{ + /* Disable the HRTIM outputs */ + HRTIMx->HRTIM_COMMON.DISR = OutputsToStop; +} + +/** + * @brief Enables or disables the Master and slaves interrupt request + * @param HRTIMx: pointer to HRTIMx peripheral + * @param TimerIdx: Timer index + * This parameter can be one of the following values: + * @arg 0x0 to 0x4 for timers A to E + * @param HRTIM_IT: specifies the HRTIM interrupts sources to be enabled or disabled. + * This parameter can be any combination of the following values: + * @arg HRTIM_MASTER_IT_MCMP1: Master compare 1 interrupt source + * @arg HRTIM_MASTER_IT_MCMP2: Master compare 2 interrupt source + * @arg HRTIM_MASTER_IT_MCMP3: Master compare 3 interrupt Interrupt source + * @arg HRTIM_MASTER_IT_MCMP4: Master compare 4 Interrupt source + * @arg HRTIM_MASTER_IT_MREP: Master Repetition Interrupt source + * @arg HRTIM_MASTER_IT_SYNC: Synchronization input Interrupt source + * @arg HRTIM_MASTER_IT_MUPD: Master update Interrupt source + * @arg HRTIM_TIM_IT_CMP1: Timer compare 1 Interrupt source + * @arg HRTIM_TIM_IT_CMP2: Timer compare 2 Interrupt source + * @arg HRTIM_TIM_IT_CMP3: Timer compare 3 Interrupt source + * @arg HRTIM_TIM_IT_CMP4: Timer compare 4 Interrupt source + * @arg HRTIM_TIM_IT_REP: Timer repetition Interrupt source + * @arg HRTIM_TIM_IT_UPD: Timer update Interrupt source + * @arg HRTIM_TIM_IT_CPT1: Timer capture 1 Interrupt source + * @arg HRTIM_TIM_IT_CPT2: Timer capture 2 Interrupt source + * @arg HRTIM_TIM_IT_SET1: Timer output 1 set Interrupt source + * @arg HRTIM_TIM_IT_RST1: Timer output 1 reset Interrupt source + * @arg HRTIM_TIM_IT_SET2: Timer output 2 set Interrupt source + * @arg HRTIM_TIM_IT_RST2: Timer output 2 reset Interrupt source + * @arg HRTIM_TIM_IT_RST: Timer reset Interrupt source + * @arg HRTIM_TIM_IT_DLYPRT1: Timer delay protection Interrupt source + * @param NewState: new state of the TIM interrupts. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void HRTIM_ITConfig(HRTIM_TypeDef * HRTIMx, uint32_t TimerIdx, uint32_t HRTIM_IT, FunctionalState NewState) +{ + assert_param(IS_HRTIM_TIMERINDEX(TimerIdx)); + + switch(TimerIdx) + { + case HRTIM_TIMERINDEX_MASTER: + { + if(NewState != DISABLE) + { + HRTIMx->HRTIM_MASTER.MDIER |= HRTIM_IT; + } + else + { + HRTIMx->HRTIM_MASTER.MDIER &= ~HRTIM_IT; + } + } + break; + case HRTIM_TIMERINDEX_TIMER_A: + case HRTIM_TIMERINDEX_TIMER_B: + case HRTIM_TIMERINDEX_TIMER_C: + case HRTIM_TIMERINDEX_TIMER_D: + case HRTIM_TIMERINDEX_TIMER_E: + { + if(NewState != DISABLE) + { + HRTIMx->HRTIM_TIMERx[TimerIdx].TIMxDIER |= HRTIM_IT; + } + else + { + HRTIMx->HRTIM_TIMERx[TimerIdx].TIMxDIER &= ~HRTIM_IT; + } + } + break; + + default: + break; + } +} + +/** + * @brief Enables or disables the common interrupt request + * @param HRTIMx: pointer to HRTIMx peripheral + * @param HRTIM_IT: specifies the HRTIM interrupts sources to be enabled or disabled. + * This parameter can be any combination of the following values: + * @arg HRTIM_IT_FLT1: Fault 1 interrupt source + * @arg HRTIM_IT_FLT2: Fault 2 interrupt source + * @arg HRTIM_IT_FLT3: Fault 3 interrupt Interrupt source + * @arg HRTIM_IT_FLT4: Fault 4 Interrupt source + * @arg HRTIM_IT_FLT5: Fault 5 Interrupt source + * @arg HRTIM_IT_SYSFLT: System Fault Interrupt source + * @arg HRTIM_IT_DLLRDY: DLL ready Interrupt source + * @arg HRTIM_IT_BMPER: Burst mode period Interrupt source + * @param NewState: new state of the TIM interrupts. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void HRTIM_ITCommonConfig(HRTIM_TypeDef * HRTIMx, uint32_t HRTIM_CommonIT, FunctionalState NewState) +{ + if(NewState != DISABLE) + { + HRTIMx->HRTIM_COMMON.IER |= HRTIM_CommonIT; + } + else + { + HRTIMx->HRTIM_COMMON.IER &= ~HRTIM_CommonIT; + } +} + +/** + * @brief Clears the Master and slaves interrupt flags + * @param HRTIMx: pointer to HRTIMx peripheral + * @param TimerIdx: Timer index + * This parameter can be one of the following values: + * @arg 0x0 to 0x4 for timers A to E + * @param HRTIM_FLAG: specifies the HRTIM flags sources to be cleared. + * This parameter can be any combination of the following values: + * @arg HRTIM_MASTER_FLAG_MCMP1: Master compare 1 interrupt flag + * @arg HRTIM_MASTER_FLAG_MCMP2: Master compare 2 interrupt flag + * @arg HRTIM_MASTER_FLAG_MCMP3: Master compare 3 interrupt Interrupt flag + * @arg HRTIM_MASTER_FLAG_MCMP4: Master compare 4 Interrupt flag + * @arg HRTIM_MASTER_FLAG_MREP: Master Repetition Interrupt flag + * @arg HRTIM_MASTER_FLAG_SYNC: Synchronization input Interrupt flag + * @arg HRTIM_MASTER_FLAG_MUPD: Master update Interrupt flag + * @arg HRTIM_TIM_FLAG_CMP1: Timer compare 1 Interrupt flag + * @arg HRTIM_TIM_FLAG_CMP2: Timer compare 2 Interrupt flag + * @arg HRTIM_TIM_FLAG_CMP3: Timer compare 3 Interrupt flag + * @arg HRTIM_TIM_FLAG_CMP4: Timer compare 4 Interrupt flag + * @arg HRTIM_TIM_FLAG_REP: Timer repetition Interrupt flag + * @arg HRTIM_TIM_FLAG_UPD: Timer update Interrupt flag + * @arg HRTIM_TIM_FLAG_CPT1: Timer capture 1 Interrupt flag + * @arg HRTIM_TIM_FLAG_CPT2: Timer capture 2 Interrupt flag + * @arg HRTIM_TIM_FLAG_SET1: Timer output 1 set Interrupt flag + * @arg HRTIM_TIM_FLAG_RST1: Timer output 1 reset Interrupt flag + * @arg HRTIM_TIM_FLAG_SET2: Timer output 2 set Interrupt flag + * @arg HRTIM_TIM_FLAG_RST2: Timer output 2 reset Interrupt flag + * @arg HRTIM_TIM_FLAG_RST: Timer reset Interrupt flag + * @arg HRTIM_TIM_FLAG_DLYPRT1: Timer delay protection Interrupt flag + * @retval None + */ +void HRTIM_ClearFlag(HRTIM_TypeDef * HRTIMx, uint32_t TimerIdx, uint32_t HRTIM_FLAG) +{ + assert_param(IS_HRTIM_TIMERINDEX(TimerIdx)); + + switch(TimerIdx) + { + case HRTIM_TIMERINDEX_MASTER: + { + HRTIMx->HRTIM_MASTER.MICR |= HRTIM_FLAG; + } + break; + case HRTIM_TIMERINDEX_TIMER_A: + case HRTIM_TIMERINDEX_TIMER_B: + case HRTIM_TIMERINDEX_TIMER_C: + case HRTIM_TIMERINDEX_TIMER_D: + case HRTIM_TIMERINDEX_TIMER_E: + { + HRTIMx->HRTIM_TIMERx[TimerIdx].TIMxICR |= HRTIM_FLAG; + } + break; + + default: + break; + } +} + +/** + * @brief Clears the common interrupt flags + * @param HRTIMx: pointer to HRTIMx peripheral + * @param HRTIM_FLAG: specifies the HRTIM flags to be cleared. + * This parameter can be any combination of the following values: + * @arg HRTIM_FLAG_FLT1: Fault 1 interrupt flag + * @arg HRTIM_FLAG_FLT2: Fault 2 interrupt flag + * @arg HRTIM_FLAG_FLT3: Fault 3 interrupt Interrupt flag + * @arg HRTIM_FLAG_FLT4: Fault 4 Interrupt flag + * @arg HRTIM_FLAG_FLT5: Fault 5 Interrupt flag + * @arg HRTIM_FLAG_SYSFLT: System Fault Interrupt flag + * @arg HRTIM_FLAG_DLLRDY: DLL ready Interrupt flag + * @arg HRTIM_FLAG_BMPER: Burst mode period Interrupt flag + * @retval None + */ +void HRTIM_ClearCommonFlag(HRTIM_TypeDef * HRTIMx, uint32_t HRTIM_CommonFLAG) +{ + HRTIMx->HRTIM_COMMON.ICR |= HRTIM_CommonFLAG; +} + +/** + * @brief Clears the Master and slaves interrupt request pending bits + * @param HRTIMx: pointer to HRTIMx peripheral + * @param TimerIdx: Timer index + * This parameter can be one of the following values: + * @arg 0x0 to 0x4 for timers A to E + * @param HRTIM_IT: specifies the HRTIM interrupts sources to be enabled or disabled. + * This parameter can be any combination of the following values: + * @arg HRTIM_MASTER_IT_MCMP1: Master compare 1 interrupt source + * @arg HRTIM_MASTER_IT_MCMP2: Master compare 2 interrupt source + * @arg HRTIM_MASTER_IT_MCMP3: Master compare 3 interrupt Interrupt source + * @arg HRTIM_MASTER_IT_MCMP4: Master compare 4 Interrupt source + * @arg HRTIM_MASTER_IT_MREP: Master Repetition Interrupt source + * @arg HRTIM_MASTER_IT_SYNC: Synchronization input Interrupt source + * @arg HRTIM_MASTER_IT_MUPD: Master update Interrupt source + * @arg HRTIM_TIM_IT_CMP1: Timer compare 1 Interrupt source + * @arg HRTIM_TIM_IT_CMP2: Timer compare 2 Interrupt source + * @arg HRTIM_TIM_IT_CMP3: Timer compare 3 Interrupt source + * @arg HRTIM_TIM_IT_CMP4: Timer compare 4 Interrupt source + * @arg HRTIM_TIM_IT_REP: Timer repetition Interrupt source + * @arg HRTIM_TIM_IT_UPD: Timer update Interrupt source + * @arg HRTIM_TIM_IT_CPT1: Timer capture 1 Interrupt source + * @arg HRTIM_TIM_IT_CPT2: Timer capture 2 Interrupt source + * @arg HRTIM_TIM_IT_SET1: Timer output 1 set Interrupt source + * @arg HRTIM_TIM_IT_RST1: Timer output 1 reset Interrupt source + * @arg HRTIM_TIM_IT_SET2: Timer output 2 set Interrupt source + * @arg HRTIM_TIM_IT_RST2: Timer output 2 reset Interrupt source + * @arg HRTIM_TIM_IT_RST: Timer reset Interrupt source + * @arg HRTIM_TIM_IT_DLYPRT: Timer delay protection Interrupt source + * @retval None + */ +void HRTIM_ClearITPendingBit(HRTIM_TypeDef * HRTIMx, uint32_t TimerIdx, uint32_t HRTIM_IT) +{ + assert_param(IS_HRTIM_TIMERINDEX(TimerIdx)); + + switch(TimerIdx) + { + case HRTIM_TIMERINDEX_MASTER: + { + HRTIMx->HRTIM_MASTER.MICR |= HRTIM_IT; + } + break; + case HRTIM_TIMERINDEX_TIMER_A: + case HRTIM_TIMERINDEX_TIMER_B: + case HRTIM_TIMERINDEX_TIMER_C: + case HRTIM_TIMERINDEX_TIMER_D: + case HRTIM_TIMERINDEX_TIMER_E: + { + HRTIMx->HRTIM_TIMERx[TimerIdx].TIMxICR |= HRTIM_IT; + } + break; + + default: + break; + } +} + +/** + * @brief Clears the common interrupt pending bits + * @param HRTIMx: pointer to HRTIMx peripheral + * @param HRTIM_IT: specifies the HRTIM interrupts sources to be cleared. + * This parameter can be any combination of the following values: + * @arg HRTIM_IT_FLT1: Fault 1 interrupt source + * @arg HRTIM_IT_FLT2: Fault 2 interrupt source + * @arg HRTIM_IT_FLT3: Fault 3 interrupt Interrupt source + * @arg HRTIM_IT_FLT4: Fault 4 Interrupt source + * @arg HRTIM_IT_FLT5: Fault 5 Interrupt source + * @arg HRTIM_IT_SYSFLT: System Fault Interrupt source + * @arg HRTIM_IT_DLLRDY: DLL ready Interrupt source + * @arg HRTIM_IT_BMPER: Burst mode period Interrupt source + * @retval None + */ +void HRTIM_ClearCommonITPendingBit(HRTIM_TypeDef * HRTIMx, uint32_t HRTIM_CommonIT) +{ + HRTIMx->HRTIM_COMMON.ICR |= HRTIM_CommonIT; +} + + +/** + * @brief Checks whether the specified HRTIM flag is set or not. + * @param HRTIMx: pointer to HRTIMx peripheral + * @param TimerIdx: Timer index + * This parameter can be one of the following values: + * @arg 0x0 to 0x4 for timers A to E + * @param HRTIM_FLAG: specifies the HRTIM flags to check. + * This parameter can be any combination of the following values: + * @arg HRTIM_MASTER_FLAG_MCMP1: Master compare 1 interrupt flag + * @arg HRTIM_MASTER_FLAG_MCMP2: Master compare 2 interrupt flag + * @arg HRTIM_MASTER_FLAG_MCMP3: Master compare 3 interrupt Interrupt flag + * @arg HRTIM_MASTER_FLAG_MCMP4: Master compare 4 Interrupt flag + * @arg HRTIM_MASTER_FLAG_MREP: Master Repetition Interrupt flag + * @arg HRTIM_MASTER_FLAG_SYNC: Synchronization input Interrupt flag + * @arg HRTIM_MASTER_FLAG_MUPD: Master update Interrupt flag + * @arg HRTIM_TIM_FLAG_CMP1: Timer compare 1 Interrupt flag + * @arg HRTIM_TIM_FLAG_CMP2: Timer compare 2 Interrupt flag + * @arg HRTIM_TIM_FLAG_CMP3: Timer compare 3 Interrupt flag + * @arg HRTIM_TIM_FLAG_CMP4: Timer compare 4 Interrupt flag + * @arg HRTIM_TIM_FLAG_REP: Timer repetition Interrupt flag + * @arg HRTIM_TIM_FLAG_UPD: Timer update Interrupt flag + * @arg HRTIM_TIM_FLAG_CPT1: Timer capture 1 Interrupt flag + * @arg HRTIM_TIM_FLAG_CPT2: Timer capture 2 Interrupt flag + * @arg HRTIM_TIM_FLAG_SET1: Timer output 1 set Interrupt flag + * @arg HRTIM_TIM_FLAG_RST1: Timer output 1 reset Interrupt flag + * @arg HRTIM_TIM_FLAG_SET2: Timer output 2 set Interrupt flag + * @arg HRTIM_TIM_FLAG_RST2: Timer output 2 reset Interrupt flag + * @arg HRTIM_TIM_FLAG_RST: Timer reset Interrupt flag + * @arg HRTIM_TIM_FLAG_DLYPRT: Timer delay protection Interrupt flag + * @retval The new state of HRTIM_FLAG (SET or RESET). + */ +FlagStatus HRTIM_GetFlagStatus(HRTIM_TypeDef * HRTIMx, uint32_t TimerIdx, uint32_t HRTIM_FLAG) +{ + assert_param(IS_HRTIM_TIMERINDEX(TimerIdx)); + + FlagStatus bitstatus = RESET; + + switch(TimerIdx) + { + case HRTIM_TIMERINDEX_MASTER: + { + if ((HRTIMx->HRTIM_MASTER.MISR & HRTIM_FLAG) != RESET) + { + bitstatus = SET; + } + else + { + bitstatus = RESET; + } + } + break; + + case HRTIM_TIMERINDEX_TIMER_A: + case HRTIM_TIMERINDEX_TIMER_B: + case HRTIM_TIMERINDEX_TIMER_C: + case HRTIM_TIMERINDEX_TIMER_D: + case HRTIM_TIMERINDEX_TIMER_E: + { + if ((HRTIMx->HRTIM_TIMERx[TimerIdx].TIMxISR & HRTIM_FLAG) != RESET) + { + bitstatus = SET; + } + else + { + bitstatus = RESET; + } + } + break; + + default: + break; + } + return bitstatus; +} + +/** + * @brief Checks whether the specified HRTIM common flag is set or not. + * @param HRTIMx: pointer to HRTIMx peripheral + * @param HRTIM_FLAG: specifies the HRTIM flags to check. + * This parameter can be any combination of the following values: + * @arg HRTIM_FLAG_FLT1: Fault 1 interrupt flag + * @arg HRTIM_FLAG_FLT2: Fault 2 interrupt flag + * @arg HRTIM_FLAG_FLT3: Fault 3 interrupt Interrupt flag + * @arg HRTIM_FLAG_FLT4: Fault 4 Interrupt flag + * @arg HRTIM_FLAG_FLT5: Fault 5 Interrupt flag + * @arg HRTIM_FLAG_SYSFLT: System Fault Interrupt flag + * @arg HRTIM_FLAG_DLLRDY: DLL ready Interrupt flag + * @arg HRTIM_FLAG_BMPER: Burst mode period Interrupt flag + * @retval The new state of HRTIM_FLAG (SET or RESET). + */ +FlagStatus HRTIM_GetCommonFlagStatus(HRTIM_TypeDef * HRTIMx, uint32_t HRTIM_CommonFLAG) +{ + FlagStatus bitstatus = RESET; + + if((HRTIMx->HRTIM_COMMON.ISR & HRTIM_CommonFLAG) != RESET) + { + bitstatus = SET; + } + else + { + bitstatus = RESET; + } + return bitstatus; +} + +/** + * @brief Checks whether the specified HRTIM interrupt has occurred or not. + * @param HRTIMx: pointer to HRTIMx peripheral + * @param TimerIdx: Timer index + * This parameter can be one of the following values: + * @arg 0x0 to 0x4 for timers A to E + * @param HRTIM_IT: specifies the HRTIM flags sources to be cleared. + * This parameter can be any combination of the following values: + * @arg HRTIM_MASTER_IT_MCMP1: Master compare 1 interrupt + * @arg HRTIM_MASTER_IT_MCMP2: Master compare 2 interrupt + * @arg HRTIM_MASTER_IT_MCMP3: Master compare 3 interrupt Interrupt + * @arg HRTIM_MASTER_IT_MCMP4: Master compare 4 Interrupt + * @arg HRTIM_MASTER_IT_MREP: Master Repetition Interrupt + * @arg HRTIM_MASTER_IT_SYNC: Synchronization input Interrupt + * @arg HRTIM_MASTER_IT_MUPD: Master update Interrupt + * @arg HRTIM_TIM_IT_CMP1: Timer compare 1 Interrupt + * @arg HRTIM_TIM_IT_CMP2: Timer compare 2 Interrupt + * @arg HRTIM_TIM_IT_CMP3: Timer compare 3 Interrupt + * @arg HRTIM_TIM_IT_CMP4: Timer compare 4 Interrupt + * @arg HRTIM_TIM_IT_REP: Timer repetition Interrupt + * @arg HRTIM_TIM_IT_UPD: Timer update Interrupt + * @arg HRTIM_TIM_IT_CPT1: Timer capture 1 Interrupt + * @arg HRTIM_TIM_IT_CPT2: Timer capture 2 Interrupt + * @arg HRTIM_TIM_IT_SET1: Timer output 1 set Interrupt + * @arg HRTIM_TIM_IT_RST1: Timer output 1 reset Interrupt + * @arg HRTIM_TIM_IT_SET2: Timer output 2 set Interrupt + * @arg HRTIM_TIM_IT_RST2: Timer output 2 reset Interrupt + * @arg HRTIM_TIM_IT_RST: Timer reset Interrupt + * @arg HRTIM_TIM_IT_DLYPRT: Timer delay protection Interrupt + * @retval The new state of the HRTIM_IT(SET or RESET). + */ +ITStatus HRTIM_GetITStatus(HRTIM_TypeDef * HRTIMx, uint32_t TimerIdx, uint32_t HRTIM_IT) +{ + ITStatus bitstatus = RESET; + uint16_t itstatus = 0x0, itenable = 0x0; + + assert_param(IS_HRTIM_TIMERINDEX(TimerIdx)); + + switch(TimerIdx) + { + case HRTIM_TIMERINDEX_MASTER: + { + itstatus = HRTIMx->HRTIM_MASTER.MISR & HRTIM_IT; + + itenable = HRTIMx->HRTIM_MASTER.MDIER & HRTIM_IT; + if ((itstatus != (uint16_t)RESET) && (itenable != (uint16_t)RESET)) + { + bitstatus = SET; + } + else + { + bitstatus = RESET; + } + } + break; + + case HRTIM_TIMERINDEX_TIMER_A: + case HRTIM_TIMERINDEX_TIMER_B: + case HRTIM_TIMERINDEX_TIMER_C: + case HRTIM_TIMERINDEX_TIMER_D: + case HRTIM_TIMERINDEX_TIMER_E: + { + itstatus = HRTIMx->HRTIM_TIMERx[TimerIdx].TIMxISR & HRTIM_IT; + + itenable = HRTIMx->HRTIM_TIMERx[TimerIdx].TIMxDIER & HRTIM_IT; + if ((itstatus != (uint16_t)RESET) && (itenable != (uint16_t)RESET)) + { + bitstatus = SET; + } + else + { + bitstatus = RESET; + } + } + break; + + default: + break; + } + return bitstatus; +} + +/** + * @brief Checks whether the specified HRTIM common interrupt has occurred or not. + * @param HRTIMx: pointer to HRTIMx peripheral + * @param HRTIM_IT: specifies the HRTIM interrupt source to check. + * This parameter can be any combination of the following values: + * @arg HRTIM_IT_FLT1: Fault 1 interrupt + * @arg HRTIM_IT_FLT2: Fault 2 interrupt + * @arg HRTIM_IT_FLT3: Fault 3 interrupt Interrupt + * @arg HRTIM_IT_FLT4: Fault 4 Interrupt + * @arg HRTIM_IT_FLT5: Fault 5 Interrupt + * @arg HRTIM_IT_SYSFLT: System Fault Interrupt + * @arg HRTIM_IT_DLLRDY: DLL ready Interrupt flag + * @arg HRTIM_IT_BMPER: Burst mode period Interrupt + * @retval The new state of HRTIM_FLAG (SET or RESET). + */ +ITStatus HRTIM_GetCommonITStatus(HRTIM_TypeDef * HRTIMx, uint32_t HRTIM_CommonIT) +{ + ITStatus bitstatus = RESET; + uint16_t itstatus = 0x0, itenable = 0x0; + + itstatus = HRTIMx->HRTIM_COMMON.ISR & HRTIM_CommonIT; + itenable = HRTIMx->HRTIM_COMMON.IER & HRTIM_CommonIT; + + if ((itstatus != (uint16_t)RESET) && (itenable != (uint16_t)RESET)) + { + bitstatus = SET; + } + else + { + bitstatus = RESET; + } + + return bitstatus; +} + +/** + * @brief Enables or disables the HRTIMx's DMA Requests. + * @param HRTIMx: pointer to HRTIMx peripheral + * @param TimerIdx: Timer index + * This parameter can be one of the following values: + * @arg 0x0 to 0x4 for timers A to E + * @param HRTIM_DMA: specifies the DMA Request sources. + * This parameter can be any combination of the following values: + * @arg HRTIM_MASTER_DMA_MCMP1: Master compare 1 DMA request source + * @arg HRTIM_MASTER_DMA_MCMP2: Master compare 2 DMA request source + * @arg HRTIM_MASTER_DMA_MCMP3: Master compare 3 DMA request source + * @arg HRTIM_MASTER_DMA_MCMP4: Master compare 4 DMA request source + * @arg HRTIM_MASTER_DMA_MREP: Master Repetition DMA request source + * @arg HRTIM_MASTER_DMA_SYNC: Synchronization input DMA request source + * @arg HRTIM_MASTER_DMA_MUPD:Master update DMA request source + * @arg HRTIM_TIM_DMA_CMP1: Timer compare 1 DMA request source + * @arg HRTIM_TIM_DMA_CMP2: Timer compare 2 DMA request source + * @arg HRTIM_TIM_DMA_CMP3: Timer compare 3 DMA request source + * @arg HRTIM_TIM_DMA_CMP4: Timer compare 4 DMA request source + * @arg HRTIM_TIM_DMA_REP: Timer repetition DMA request source + * @arg HRTIM_TIM_DMA_UPD: Timer update DMA request source + * @arg HRTIM_TIM_DMA_CPT1: Timer capture 1 DMA request source + * @arg HRTIM_TIM_DMA_CPT2: Timer capture 2 DMA request source + * @arg HRTIM_TIM_DMA_SET1: Timer output 1 set DMA request source + * @arg HRTIM_TIM_DMA_RST1: Timer output 1 reset DMA request source + * @arg HRTIM_TIM_DMA_SET2: Timer output 2 set DMA request source + * @arg HRTIM_TIM_DMA_RST2: Timer output 2 reset DMA request source + * @arg HRTIM_TIM_DMA_RST: Timer reset DMA request source + * @arg HRTIM_TIM_DMA_DLYPRT: Timer delay protection DMA request source + * @param NewState: new state of the DMA Request sources. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void HRTIM_DMACmd(HRTIM_TypeDef* HRTIMx, uint32_t TimerIdx, uint32_t HRTIM_DMA, FunctionalState NewState) +{ + assert_param(IS_HRTIM_TIMERINDEX(TimerIdx)); + + switch(TimerIdx) + { + case HRTIM_TIMERINDEX_MASTER: + { + if(NewState != DISABLE) + { + HRTIMx->HRTIM_MASTER.MDIER |= HRTIM_DMA; + } + else + { + HRTIMx->HRTIM_MASTER.MDIER &= ~HRTIM_DMA; + } + } + break; + case HRTIM_TIMERINDEX_TIMER_A: + case HRTIM_TIMERINDEX_TIMER_B: + case HRTIM_TIMERINDEX_TIMER_C: + case HRTIM_TIMERINDEX_TIMER_D: + case HRTIM_TIMERINDEX_TIMER_E: + { + if(NewState != DISABLE) + { + HRTIMx->HRTIM_TIMERx[TimerIdx].TIMxDIER |= HRTIM_DMA; + } + else + { + HRTIMx->HRTIM_TIMERx[TimerIdx].TIMxDIER &= ~HRTIM_DMA; + } + } + break; + + default: + break; + } +} + +/** + * @} + */ + +/** @defgroup HRTIM_Group3 Peripheral Control methods + * @brief management functions + * +@verbatim + =============================================================================== + ##### Peripheral Control methods ##### + =============================================================================== + [..] + This subsection provides a set of functions allowing to control the HRTIMx data + transfers. + +@endverbatim + * @{ + */ + +/** + * @brief Configures an output in basic output compare mode + * @param HRTIMx: pointer to HRTIMx peripheral + * @param TimerIdx: Timer index + * This parameter can be one of the following values: + * @arg 0x0 to 0x4 for timers A to E + * @param OCChannel: Timer output + * This parameter can be one of the following values: + * @arg HRTIM_OUTPUT_TA1: Timer A - Output 1 + * @arg HRTIM_OUTPUT_TA2: Timer A - Output 2 + * @arg HRTIM_OUTPUT_TB1: Timer B - Output 1 + * @arg HRTIM_OUTPUT_TB2: Timer B - Output 2 + * @arg HRTIM_OUTPUT_TC1: Timer C - Output 1 + * @arg HRTIM_OUTPUT_TC2: Timer C - Output 2 + * @arg HRTIM_OUTPUT_TD1: Timer D - Output 1 + * @arg HRTIM_OUTPUT_TD2: Timer D - Output 2 + * @arg HRTIM_OUTPUT_TE1: Timer E - Output 1 + * @arg HRTIM_OUTPUT_TE2: Timer E - Output 2 + * @param pBasicOCChannelCfg: pointer to the basic output compare output configuration structure + * @note When the timer operates in basic output compare mode: + * Output 1 is implicitly controlled by the compare unit 1 + * Output 2 is implicitly controlled by the compare unit 2 + * Output Set/Reset crossbar is set according to the selected output compare mode: + * Toggle: SETxyR = RSTxyR = CMPy + * Active: SETxyR = CMPy, RSTxyR = 0 + * Inactive: SETxy =0, RSTxy = CMPy + * @retval None + */ +void HRTIM_SimpleOCChannelConfig(HRTIM_TypeDef * HRTIMx, + uint32_t TimerIdx, + uint32_t OCChannel, + HRTIM_BasicOCChannelCfgTypeDef* pBasicOCChannelCfg) +{ + uint32_t CompareUnit = HRTIM_COMPAREUNIT_1; + HRTIM_CompareCfgTypeDef CompareCfg; + HRTIM_OutputCfgTypeDef OutputCfg; + + /* Check parameters */ + assert_param(IS_HRTIM_TIMER_OUTPUT(TimerIdx, OCChannel)); + assert_param(IS_HRTIM_BASICOCMODE(pBasicOCChannelCfg->Mode)); + assert_param(IS_HRTIM_OUTPUTPOLARITY(pBasicOCChannelCfg->Polarity)); + assert_param(IS_HRTIM_OUTPUTIDLESTATE(pBasicOCChannelCfg->IdleState)); + + /* Configure timer compare unit */ + switch (OCChannel) + { + case HRTIM_OUTPUT_TA1: + case HRTIM_OUTPUT_TB1: + case HRTIM_OUTPUT_TC1: + case HRTIM_OUTPUT_TD1: + case HRTIM_OUTPUT_TE1: + { + CompareUnit = HRTIM_COMPAREUNIT_1; + } + break; + case HRTIM_OUTPUT_TA2: + case HRTIM_OUTPUT_TB2: + case HRTIM_OUTPUT_TC2: + case HRTIM_OUTPUT_TD2: + case HRTIM_OUTPUT_TE2: + { + CompareUnit = HRTIM_COMPAREUNIT_2; + } + break; + default: + break; + } + + CompareCfg.CompareValue = pBasicOCChannelCfg->Pulse; + CompareCfg.AutoDelayedMode = HRTIM_AUTODELAYEDMODE_REGULAR; + CompareCfg.AutoDelayedTimeout = 0; + + HRTIM_CompareUnitConfig(HRTIMx, + TimerIdx, + CompareUnit, + &CompareCfg); + + /* Configure timer output */ + OutputCfg.Polarity = pBasicOCChannelCfg->Polarity; + OutputCfg.IdleState = pBasicOCChannelCfg->IdleState; + OutputCfg.FaultState = HRTIM_OUTPUTFAULTSTATE_NONE; + OutputCfg.IdleMode = HRTIM_OUTPUTIDLEMODE_NONE; + OutputCfg.ChopperModeEnable = HRTIM_OUTPUTCHOPPERMODE_DISABLED; + OutputCfg.BurstModeEntryDelayed = HRTIM_OUTPUTBURSTMODEENTRY_REGULAR; + + switch (pBasicOCChannelCfg->Mode) + { + case HRTIM_BASICOCMODE_TOGGLE: + { + if (CompareUnit == HRTIM_COMPAREUNIT_1) + { + OutputCfg.SetSource = HRTIM_OUTPUTSET_TIMCMP1; + } + else + { + OutputCfg.SetSource = HRTIM_OUTPUTSET_TIMCMP2; + } + OutputCfg.ResetSource = OutputCfg.SetSource; + } + break; + case HRTIM_BASICOCMODE_ACTIVE: + { + if (CompareUnit == HRTIM_COMPAREUNIT_1) + { + OutputCfg.SetSource = HRTIM_OUTPUTSET_TIMCMP1; + } + else + { + OutputCfg.SetSource = HRTIM_OUTPUTSET_TIMCMP2; + } + OutputCfg.ResetSource = HRTIM_OUTPUTRESET_NONE; + } + break; + case HRTIM_BASICOCMODE_INACTIVE: + { + if (CompareUnit == HRTIM_COMPAREUNIT_1) + { + OutputCfg.ResetSource = HRTIM_OUTPUTRESET_TIMCMP1; + } + else + { + OutputCfg.ResetSource = HRTIM_OUTPUTRESET_TIMCMP2; + } + OutputCfg.SetSource = HRTIM_OUTPUTSET_NONE; + } + break; + default: + break; + } + + HRTIM_OutputConfig(HRTIMx, TimerIdx, OCChannel, &OutputCfg); +} + +/** + * @brief Configures an output in basic PWM mode + * @param HRTIMx: pointer to HRTIMx peripheral + * @param TimerIdx: Timer index + * This parameter can be one of the following values: + * @arg 0x0 to 0x4 for timers A to E + * @param PWMChannel: Timer output + * This parameter can be one of the following values: + * @arg HRTIM_OUTPUT_TA1: Timer A - Output 1 + * @arg HRTIM_OUTPUT_TA2: Timer A - Output 2 + * @arg HRTIM_OUTPUT_TB1: Timer B - Output 1 + * @arg HRTIM_OUTPUT_TB2: Timer B - Output 2 + * @arg HRTIM_OUTPUT_TC1: Timer C - Output 1 + * @arg HRTIM_OUTPUT_TC2: Timer C - Output 2 + * @arg HRTIM_OUTPUT_TD1: Timer D - Output 1 + * @arg HRTIM_OUTPUT_TD2: Timer D - Output 2 + * @arg HRTIM_OUTPUT_TE1: Timer E - Output 1 + * @arg HRTIM_OUTPUT_TE2: Timer E - Output 2 + * @param pBasicPWMChannelCfg: pointer to the basic PWM output configuration structure + * @note When the timer operates in basic PWM output mode: + * Output 1 is implicitly controlled by the compare unit 1 + * Output 2 is implicitly controlled by the compare unit 2 + * Output Set/Reset crossbar is set as follows: + * Output 1: SETx1R = CMP1, RSTx1R = PER + * Output 2: SETx2R = CMP2, RST2R = PER + * @retval None + */ +void HRTIM_SimplePWMChannelConfig(HRTIM_TypeDef * HRTIMx, + uint32_t TimerIdx, + uint32_t PWMChannel, + HRTIM_BasicPWMChannelCfgTypeDef* pBasicPWMChannelCfg) +{ + uint32_t CompareUnit = HRTIM_COMPAREUNIT_1; + HRTIM_CompareCfgTypeDef CompareCfg; + HRTIM_OutputCfgTypeDef OutputCfg; + + /* Check parameters */ + assert_param(IS_HRTIM_TIMER_OUTPUT(TimerIdx, PWMChannel)); + assert_param(IS_HRTIM_OUTPUTPOLARITY(pBasicPWMChannelCfg->Polarity)); + assert_param(IS_HRTIM_OUTPUTIDLESTATE(pBasicPWMChannelCfg->IdleState)); + + /* Configure timer compare unit */ + switch (PWMChannel) + { + case HRTIM_OUTPUT_TA1: + case HRTIM_OUTPUT_TB1: + case HRTIM_OUTPUT_TC1: + case HRTIM_OUTPUT_TD1: + case HRTIM_OUTPUT_TE1: + { + CompareUnit = HRTIM_COMPAREUNIT_1; + } + break; + case HRTIM_OUTPUT_TA2: + case HRTIM_OUTPUT_TB2: + case HRTIM_OUTPUT_TC2: + case HRTIM_OUTPUT_TD2: + case HRTIM_OUTPUT_TE2: + { + CompareUnit = HRTIM_COMPAREUNIT_2; + } + break; + default: + break; + } + + CompareCfg.CompareValue = pBasicPWMChannelCfg->Pulse; + CompareCfg.AutoDelayedMode = HRTIM_AUTODELAYEDMODE_REGULAR; + CompareCfg.AutoDelayedTimeout = 0; + + HRTIM_CompareUnitConfig(HRTIMx, + TimerIdx, + CompareUnit, + &CompareCfg); + + /* Configure timer output */ + OutputCfg.Polarity = pBasicPWMChannelCfg->Polarity; + OutputCfg.IdleState = pBasicPWMChannelCfg->IdleState; + OutputCfg.FaultState = HRTIM_OUTPUTFAULTSTATE_NONE; + OutputCfg.IdleMode = HRTIM_OUTPUTIDLEMODE_NONE; + OutputCfg.ChopperModeEnable = HRTIM_OUTPUTCHOPPERMODE_DISABLED; + OutputCfg.BurstModeEntryDelayed = HRTIM_OUTPUTBURSTMODEENTRY_REGULAR; + + if (CompareUnit == HRTIM_COMPAREUNIT_1) + { + OutputCfg.SetSource = HRTIM_OUTPUTSET_TIMCMP1; + } + else + { + OutputCfg.SetSource = HRTIM_OUTPUTSET_TIMCMP2; + } + OutputCfg.ResetSource = HRTIM_OUTPUTSET_TIMPER; + + HRTIM_OutputConfig(HRTIMx, TimerIdx, PWMChannel, &OutputCfg); +} + +/** + * @brief Configures a basic capture + * @param HRTIMx: pointer to HRTIMx peripheral + * @param TimerIdx: Timer index + * This parameter can be one of the following values: + * @arg 0x0 to 0x4 for timers A to E + * @param CaptureChannel: Capture unit + * This parameter can be one of the following values: + * @arg HRTIM_CAPTUREUNIT_1: Capture unit 1 + * @arg HRTIM_CAPTUREUNIT_2: Capture unit 2 + * @param pBasicCaptureChannelCfg: pointer to the basic capture configuration structure + * @note When the timer operates in basic capture mode the capture is triggered + * by the designated external event and GPIO input is implicitly used as event source. + * The capture can be triggered by a rising edge, a falling edge or both + * edges on event channel. + * @retval None + */ +void HRTIM_SimpleCaptureChannelConfig(HRTIM_TypeDef * HRTIMx, + uint32_t TimerIdx, + uint32_t CaptureChannel, + HRTIM_BasicCaptureChannelCfgTypeDef* pBasicCaptureChannelCfg) +{ + HRTIM_EventCfgTypeDef EventCfg; + + /* Check parameters */ + assert_param(IS_HRTIM_TIMING_UNIT(TimerIdx)); + assert_param(IS_HRTIM_CAPTUREUNIT(CaptureChannel)); + assert_param(IS_HRTIM_EVENT(pBasicCaptureChannelCfg->Event)); + assert_param(IS_HRTIM_EVENTPOLARITY(pBasicCaptureChannelCfg->EventPolarity)); + assert_param(IS_HRTIM_EVENTSENSITIVITY(pBasicCaptureChannelCfg->EventSensitivity)); + assert_param(IS_HRTIM_EVENTFILTER(pBasicCaptureChannelCfg->EventFilter)); + + /* Configure external event channel */ + EventCfg.FastMode = HRTIM_EVENTFASTMODE_DISABLE; + EventCfg.Filter = pBasicCaptureChannelCfg->EventFilter; + EventCfg.Polarity = pBasicCaptureChannelCfg->EventPolarity; + EventCfg.Sensitivity = pBasicCaptureChannelCfg->EventSensitivity; + EventCfg.Source = HRTIM_EVENTSRC_1; + + HRTIM_ExternalEventConfig(HRTIMx, + pBasicCaptureChannelCfg->Event, + &EventCfg); + + /* Memorize capture trigger (will be configured when the capture is started */ + HRTIM_CaptureUnitConfig(HRTIMx, + TimerIdx, + CaptureChannel, + pBasicCaptureChannelCfg->Event); +} + +/** + * @brief Configures an output basic one pulse mode + * @param HRTIMx: pointer to HRTIMx peripheral + * @param TimerIdx: Timer index + * This parameter can be one of the following values: + * @arg 0x0 to 0x4 for timers A to E + * @param OnePulseChannel: Timer output + * This parameter can be one of the following values: + * @arg HRTIM_OUTPUT_TA1: Timer A - Output 1 + * @arg HRTIM_OUTPUT_TA2: Timer A - Output 2 + * @arg HRTIM_OUTPUT_TB1: Timer B - Output 1 + * @arg HRTIM_OUTPUT_TB2: Timer B - Output 2 + * @arg HRTIM_OUTPUT_TC1: Timer C - Output 1 + * @arg HRTIM_OUTPUT_TC2: Timer C - Output 2 + * @arg HRTIM_OUTPUT_TD1: Timer D - Output 1 + * @arg HRTIM_OUTPUT_TD2: Timer D - Output 2 + * @arg HRTIM_OUTPUT_TE1: Timer E - Output 1 + * @arg HRTIM_OUTPUT_TE2: Timer E - Output 2 + * @param pBasicOnePulseChannelCfg: pointer to the basic one pulse output configuration structure + * @note When the timer operates in basic one pulse mode: + * the timer counter is implicitly started by the reset event, + * the reset of the timer counter is triggered by the designated external event + * GPIO input is implicitly used as event source, + * Output 1 is implicitly controlled by the compare unit 1, + * Output 2 is implicitly controlled by the compare unit 2. + * Output Set/Reset crossbar is set as follows: + * Output 1: SETx1R = CMP1, RSTx1R = PER + * Output 2: SETx2R = CMP2, RST2R = PER + * The counter mode should be HRTIM_MODE_SINGLESHOT_RETRIGGERABLE + * @retval None + */ +void HRTIM_SimpleOnePulseChannelConfig(HRTIM_TypeDef * HRTIMx, + uint32_t TimerIdx, + uint32_t OnePulseChannel, + HRTIM_BasicOnePulseChannelCfgTypeDef* pBasicOnePulseChannelCfg) +{ + uint32_t CompareUnit = HRTIM_COMPAREUNIT_1; + HRTIM_CompareCfgTypeDef CompareCfg; + HRTIM_OutputCfgTypeDef OutputCfg; + HRTIM_EventCfgTypeDef EventCfg; + + /* Check parameters */ + assert_param(IS_HRTIM_TIMER_OUTPUT(TimerIdx, OnePulseChannel)); + assert_param(IS_HRTIM_OUTPUTPOLARITY(pBasicOnePulseChannelCfg->OutputPolarity)); + assert_param(IS_HRTIM_OUTPUTIDLESTATE(pBasicOnePulseChannelCfg->OutputIdleState)); + assert_param(IS_HRTIM_EVENT(pBasicOnePulseChannelCfg->Event)); + assert_param(IS_HRTIM_EVENTPOLARITY(pBasicOnePulseChannelCfg->EventPolarity)); + assert_param(IS_HRTIM_EVENTSENSITIVITY(pBasicOnePulseChannelCfg->EventSensitivity)); + assert_param(IS_HRTIM_EVENTFILTER(pBasicOnePulseChannelCfg->EventFilter)); + + /* Configure timer compare unit */ + switch (OnePulseChannel) + { + case HRTIM_OUTPUT_TA1: + case HRTIM_OUTPUT_TB1: + case HRTIM_OUTPUT_TC1: + case HRTIM_OUTPUT_TD1: + case HRTIM_OUTPUT_TE1: + { + CompareUnit = HRTIM_COMPAREUNIT_1; + } + break; + case HRTIM_OUTPUT_TA2: + case HRTIM_OUTPUT_TB2: + case HRTIM_OUTPUT_TC2: + case HRTIM_OUTPUT_TD2: + case HRTIM_OUTPUT_TE2: + { + CompareUnit = HRTIM_COMPAREUNIT_2; + } + break; + default: + break; + } + + CompareCfg.CompareValue = pBasicOnePulseChannelCfg->Pulse; + CompareCfg.AutoDelayedMode = HRTIM_AUTODELAYEDMODE_REGULAR; + CompareCfg.AutoDelayedTimeout = 0; + + HRTIM_CompareUnitConfig(HRTIMx, + TimerIdx, + CompareUnit, + &CompareCfg); + + /* Configure timer output */ + OutputCfg.Polarity = pBasicOnePulseChannelCfg->OutputPolarity; + OutputCfg.IdleState = pBasicOnePulseChannelCfg->OutputIdleState; + OutputCfg.FaultState = HRTIM_OUTPUTFAULTSTATE_NONE; + OutputCfg.IdleMode = HRTIM_OUTPUTIDLEMODE_NONE; + OutputCfg.ChopperModeEnable = HRTIM_OUTPUTCHOPPERMODE_DISABLED; + OutputCfg.BurstModeEntryDelayed = HRTIM_OUTPUTBURSTMODEENTRY_REGULAR; + + if (CompareUnit == HRTIM_COMPAREUNIT_1) + { + OutputCfg.SetSource = HRTIM_OUTPUTSET_TIMCMP1; + } + else + { + OutputCfg.SetSource = HRTIM_OUTPUTSET_TIMCMP2; + } + OutputCfg.ResetSource = HRTIM_OUTPUTSET_TIMPER; + + HRTIM_OutputConfig(HRTIMx, + TimerIdx, + OnePulseChannel, + &OutputCfg); + + /* Configure external event channel */ + EventCfg.FastMode = HRTIM_EVENTFASTMODE_DISABLE; + EventCfg.Filter = pBasicOnePulseChannelCfg->EventFilter; + EventCfg.Polarity = pBasicOnePulseChannelCfg->EventPolarity; + EventCfg.Sensitivity = pBasicOnePulseChannelCfg->EventSensitivity; + EventCfg.Source = HRTIM_EVENTSRC_1; + + HRTIM_ExternalEventConfig(HRTIMx, + pBasicOnePulseChannelCfg->Event, + &EventCfg); + + /* Configure the timer reset register */ + HRTIM_TIM_ResetConfig(HRTIMx, + TimerIdx, + pBasicOnePulseChannelCfg->Event); +} + +/** + * @brief Configures the general behavior of a timer operating in waveform mode + * @param HRTIMx: pointer to HRTIMx peripheral + * @param TimerIdx: Timer index + * This parameter can be one of the following values: + * @arg 0x0 to 0x4 for timers A to E + * @param pTimerCfg: pointer to the timer configuration structure + * @note When the timer operates in waveform mode, all the features supported by + * the HRTIMx are available without any limitation. + * @retval None + */ +void HRTIM_WaveformTimerConfig(HRTIM_TypeDef * HRTIMx, + uint32_t TimerIdx, + HRTIM_TimerCfgTypeDef * pTimerCfg) +{ + uint32_t HRTIM_timcr; + uint32_t HRTIM_timfltr; + uint32_t HRTIM_timoutr; + uint32_t HRTIM_timrstr; + + /* Check parameters */ + assert_param(IS_HRTIM_TIMING_UNIT(TimerIdx)); + assert_param(IS_HRTIM_TIMPUSHPULLMODE(pTimerCfg->PushPull)); + assert_param(IS_HRTIM_TIMFAULTENABLE(pTimerCfg->FaultEnable)); + assert_param(IS_HRTIM_TIMFAULTLOCK(pTimerCfg->FaultLock)); + assert_param(IS_HRTIM_TIMDEADTIMEINSERTION(pTimerCfg->DeadTimeInsertion)); + assert_param(IS_HRTIM_TIMDELAYEDPROTECTION(pTimerCfg->DelayedProtectionMode)); + assert_param(IS_HRTIM_TIMUPDATETRIGGER(pTimerCfg->UpdateTrigger)); + assert_param(IS_HRTIM_TIMRESETTRIGGER(pTimerCfg->ResetTrigger)); + assert_param(IS_HRTIM_TIMUPDATEONRESET(pTimerCfg->ResetUpdate)); + + /* Configure timing unit (Timer A to Timer E) */ + HRTIM_timcr = HRTIMx->HRTIM_TIMERx[TimerIdx].TIMxCR; + HRTIM_timfltr = HRTIMx->HRTIM_TIMERx[TimerIdx].FLTxR; + HRTIM_timoutr = HRTIMx->HRTIM_TIMERx[TimerIdx].OUTxR; + HRTIM_timrstr = HRTIMx->HRTIM_TIMERx[TimerIdx].RSTxR; + + /* Set the push-pull mode */ + HRTIM_timcr &= ~(HRTIM_TIMCR_PSHPLL); + HRTIM_timcr |= pTimerCfg->PushPull; + + /* Enable/Disable registers update on timer counter reset */ + HRTIM_timcr &= ~(HRTIM_TIMCR_TRSTU); + HRTIM_timcr |= pTimerCfg->ResetUpdate; + + /* Set the timer update trigger */ + HRTIM_timcr &= ~(HRTIM_TIMCR_TIMUPDATETRIGGER); + HRTIM_timcr |= pTimerCfg->UpdateTrigger; + + /* Enable/Disable the fault channel at timer level */ + HRTIM_timfltr &= ~(HRTIM_FLTR_FLTxEN); + HRTIM_timfltr |= (pTimerCfg->FaultEnable & HRTIM_FLTR_FLTxEN); + + /* Lock/Unlock fault sources at timer level */ + HRTIM_timfltr &= ~(HRTIM_FLTR_FLTCLK); + HRTIM_timfltr |= pTimerCfg->FaultLock; + + /* Enable/Disable dead time insertion at timer level */ + HRTIM_timoutr &= ~(HRTIM_OUTR_DTEN); + HRTIM_timoutr |= pTimerCfg->DeadTimeInsertion; + + /* Enable/Disable delayed protection at timer level */ + HRTIM_timoutr &= ~(HRTIM_OUTR_DLYPRT| HRTIM_OUTR_DLYPRTEN); + HRTIM_timoutr |= pTimerCfg->DelayedProtectionMode; + + /* Set the timer counter reset trigger */ + HRTIM_timrstr = pTimerCfg->ResetTrigger; + + /* Update the HRTIMx registers */ + HRTIMx->HRTIM_TIMERx[TimerIdx].TIMxCR = HRTIM_timcr; + HRTIMx->HRTIM_TIMERx[TimerIdx].FLTxR = HRTIM_timfltr; + HRTIMx->HRTIM_TIMERx[TimerIdx].OUTxR = HRTIM_timoutr; + HRTIMx->HRTIM_TIMERx[TimerIdx].RSTxR = HRTIM_timrstr; + } + +/** + * @brief Configures the compare unit of a timer operating in waveform mode + * @param HRTIMx: pointer to HRTIMx peripheral + * @param TimerIdx: Timer index + * 0xFF for master timer + * This parameter can be one of the following values: + * @arg 0x0 to 0x4 for timers A to E + * @param CompareUnit: Compare unit to configure + * This parameter can be one of the following values: + * @arg HRTIM_COMPAREUNIT_1: Compare unit 1 + * @arg HRTIM_COMPAREUNIT_2: Compare unit 2 + * @arg HRTIM_COMPAREUNIT_3: Compare unit 3 + * @arg HRTIM_COMPAREUNIT_4: Compare unit 4 + * @param pCompareCfg: pointer to the compare unit configuration structure + * @note When auto delayed mode is required for compare unit 2 or compare unit 4, + * application has to configure separately the capture unit. Capture unit + * to configure in that case depends on the compare unit auto delayed mode + * is applied to (see below): + * Auto delayed on output compare 2: capture unit 1 must be configured + * Auto delayed on output compare 4: capture unit 2 must be configured + * @retval None + */ + void HRTIM_WaveformCompareConfig(HRTIM_TypeDef * HRTIMx, + uint32_t TimerIdx, + uint32_t CompareUnit, + HRTIM_CompareCfgTypeDef* pCompareCfg) +{ + uint32_t HRTIM_timcr; + + /* Check parameters */ + assert_param(IS_HRTIM_TIMING_UNIT(TimerIdx)); + assert_param(IS_HRTIM_COMPAREUNIT_AUTODELAYEDMODE(CompareUnit, pCompareCfg->AutoDelayedMode)); + + /* Configure the compare unit */ + switch (CompareUnit) + { + case HRTIM_COMPAREUNIT_1: + { + /* Set the compare value */ + HRTIMx->HRTIM_TIMERx[TimerIdx].CMP1xR = pCompareCfg->CompareValue; + } + break; + case HRTIM_COMPAREUNIT_2: + { + /* Set the compare value */ + HRTIMx->HRTIM_TIMERx[TimerIdx].CMP2xR = pCompareCfg->CompareValue; + + if (pCompareCfg->AutoDelayedMode != HRTIM_AUTODELAYEDMODE_REGULAR) + { + /* Configure auto-delayed mode */ + HRTIM_timcr = HRTIMx->HRTIM_TIMERx[TimerIdx].TIMxCR; + HRTIM_timcr &= ~HRTIM_TIMCR_DELCMP2; + HRTIM_timcr |= pCompareCfg->AutoDelayedMode; + HRTIMx->HRTIM_TIMERx[TimerIdx].TIMxCR = HRTIM_timcr; + + /* Set the compare value for timeout compare unit (if any) */ + if (pCompareCfg->AutoDelayedMode == HRTIM_AUTODELAYEDMODE_AUTODELAYED_TIMEOUTCMP1) + { + HRTIMx->HRTIM_TIMERx[TimerIdx].CMP1xR = pCompareCfg->AutoDelayedTimeout; + } + else if (pCompareCfg->AutoDelayedMode == HRTIM_AUTODELAYEDMODE_AUTODELAYED_TIMEOUTCMP3) + { + HRTIMx->HRTIM_TIMERx[TimerIdx].CMP3xR = pCompareCfg->AutoDelayedTimeout; + } + } + } + break; + case HRTIM_COMPAREUNIT_3: + { + /* Set the compare value */ + HRTIMx->HRTIM_TIMERx[TimerIdx].CMP3xR = pCompareCfg->CompareValue; + } + break; + case HRTIM_COMPAREUNIT_4: + { + /* Set the compare value */ + HRTIMx->HRTIM_TIMERx[TimerIdx].CMP4xR = pCompareCfg->CompareValue; + + if (pCompareCfg->AutoDelayedMode != HRTIM_AUTODELAYEDMODE_REGULAR) + { + /* Configure auto-delayed mode */ + HRTIM_timcr = HRTIMx->HRTIM_TIMERx[TimerIdx].TIMxCR; + HRTIM_timcr &= ~HRTIM_TIMCR_DELCMP4; + HRTIM_timcr |= (pCompareCfg->AutoDelayedMode << 2); + HRTIMx->HRTIM_TIMERx[TimerIdx].TIMxCR = HRTIM_timcr; + + /* Set the compare value for timeout compare unit (if any) */ + if (pCompareCfg->AutoDelayedMode == HRTIM_AUTODELAYEDMODE_AUTODELAYED_TIMEOUTCMP1) + { + HRTIMx->HRTIM_TIMERx[TimerIdx].CMP1xR = pCompareCfg->AutoDelayedTimeout; + } + else if (pCompareCfg->AutoDelayedMode == HRTIM_AUTODELAYEDMODE_AUTODELAYED_TIMEOUTCMP3) + { + HRTIMx->HRTIM_TIMERx[TimerIdx].CMP3xR = pCompareCfg->AutoDelayedTimeout; + } + } + } + break; + default: + break; + } +} + +/** + * @brief Sets the HRTIMx Master Comparex Register value + * @param HRTIMx: pointer to HRTIMx peripheral + * @param CompareUnit: Compare unit to configure + * This parameter can be one of the following values: + * @arg HRTIM_COMPAREUNIT_1: Compare unit 1 + * @arg HRTIM_COMPAREUNIT_2: Compare unit 2 + * @arg HRTIM_COMPAREUNIT_3: Compare unit 3 + * @arg HRTIM_COMPAREUNIT_4: Compare unit 4 + * @param Compare: specifies the Comparex register new value + * @retval None + */ +void HRTIM_MasterSetCompare(HRTIM_TypeDef * HRTIMx, + uint32_t CompareUnit, + uint32_t Compare) +{ + /* Check parameters */ + assert_param(IS_HRTIM_COMPAREUNIT(CompareUnit)); + + /* Configure the compare unit */ + switch (CompareUnit) + { + case HRTIM_COMPAREUNIT_1: + { + /* Set the compare value */ + HRTIMx->HRTIM_MASTER.MCMP1R = Compare; + } + break; + case HRTIM_COMPAREUNIT_2: + { + /* Set the compare value */ + HRTIMx->HRTIM_MASTER.MCMP2R = Compare; + } + break; + case HRTIM_COMPAREUNIT_3: + { + /* Set the compare value */ + HRTIMx->HRTIM_MASTER.MCMP3R = Compare; + } + break; + case HRTIM_COMPAREUNIT_4: + { + /* Set the compare value */ + HRTIMx->HRTIM_MASTER.MCMP4R = Compare; + } + break; + default: + break; + } +} + +/** + * @brief Sets the HRTIMx Slave Comparex Register value + * @param HRTIMx: pointer to HRTIMx peripheral + * @param CompareUnit: Compare unit to configure + * This parameter can be one of the following values: + * @arg HRTIM_COMPAREUNIT_1: Compare unit 1 + * @arg HRTIM_COMPAREUNIT_2: Compare unit 2 + * @arg HRTIM_COMPAREUNIT_3: Compare unit 3 + * @arg HRTIM_COMPAREUNIT_4: Compare unit 4 + * @param Compare: specifies the Comparex register new value + * @retval None + */ +void HRTIM_SlaveSetCompare(HRTIM_TypeDef * HRTIMx, + uint32_t TimerIdx, + uint32_t CompareUnit, + uint32_t Compare) +{ + /* Check parameters */ + assert_param(IS_HRTIM_COMPAREUNIT(CompareUnit)); + + /* Configure the compare unit */ + switch (CompareUnit) + { + case HRTIM_COMPAREUNIT_1: + { + /* Set the compare value */ + HRTIMx->HRTIM_TIMERx[TimerIdx].CMP1xR = Compare; + } + break; + case HRTIM_COMPAREUNIT_2: + { + /* Set the compare value */ + HRTIMx->HRTIM_TIMERx[TimerIdx].CMP2xR = Compare; + } + break; + case HRTIM_COMPAREUNIT_3: + { + /* Set the compare value */ + HRTIMx->HRTIM_TIMERx[TimerIdx].CMP3xR = Compare; + } + break; + case HRTIM_COMPAREUNIT_4: + { + /* Set the compare value */ + HRTIMx->HRTIM_TIMERx[TimerIdx].CMP4xR = Compare; + } + break; + default: + break; + } +} +/** + * @brief Configures the capture unit of a timer operating in waveform mode + * @param HRTIMx: pointer to HRTIMx peripheral + * @param TimerIdx: Timer index + * This parameter can be one of the following values: + * @arg 0x0 to 0x4 for timers A to E + * @param CaptureChannel: Capture unit to configure + * This parameter can be one of the following values: + * @arg HRTIM_CAPTUREUNIT_1: Capture unit 1 + * @arg HRTIM_CAPTUREUNIT_2: Capture unit 2 + * @param pCaptureCfg: pointer to the compare unit configuration structure + * @retval None + */ +void HRTIM_WaveformCaptureConfig(HRTIM_TypeDef * HRTIMx, + uint32_t TimerIdx, + uint32_t CaptureUnit, + HRTIM_CaptureCfgTypeDef* pCaptureCfg) +{ + /* Configure the capture unit */ + switch (CaptureUnit) + { + case HRTIM_CAPTUREUNIT_1: + { + HRTIMx->HRTIM_TIMERx[TimerIdx].CPT1xCR = pCaptureCfg->Trigger; + } + break; + case HRTIM_CAPTUREUNIT_2: + { + HRTIMx->HRTIM_TIMERx[TimerIdx].CPT2xCR = pCaptureCfg->Trigger; + } + break; + default: + break; + } +} + +/** + * @brief Configures the output of a timer operating in waveform mode + * @param HRTIMx: pointer to HRTIMx peripheral + * @param TimerIdx: Timer index + * This parameter can be one of the following values: + * @arg 0x0 to 0x4 for timers A to E + * @param Output: Timer output + * This parameter can be one of the following values: + * @arg HRTIM_OUTPUT_TA1: Timer A - Output 1 + * @arg HRTIM_OUTPUT_TA2: Timer A - Output 2 + * @arg HRTIM_OUTPUT_TB1: Timer B - Output 1 + * @arg HRTIM_OUTPUT_TB2: Timer B - Output 2 + * @arg HRTIM_OUTPUT_TC1: Timer C - Output 1 + * @arg HRTIM_OUTPUT_TC2: Timer C - Output 2 + * @arg HRTIM_OUTPUT_TD1: Timer D - Output 1 + * @arg HRTIM_OUTPUT_TD2: Timer D - Output 2 + * @arg HRTIM_OUTPUT_TE1: Timer E - Output 1 + * @arg HRTIM_OUTPUT_TE2: Timer E - Output 2 + * @param pOutputCfg: pointer to the timer output configuration structure + * @retval None + */ +void HRTIM_WaveformOutputConfig(HRTIM_TypeDef * HRTIMx, + uint32_t TimerIdx, + uint32_t Output, + HRTIM_OutputCfgTypeDef * pOutputCfg) +{ + /* Check parameters */ + assert_param(IS_HRTIM_TIMER_OUTPUT(TimerIdx, Output)); + assert_param(IS_HRTIM_OUTPUTPOLARITY(pOutputCfg->Polarity)); + assert_param(IS_HRTIM_OUTPUTIDLESTATE(pOutputCfg->IdleState)); + assert_param(IS_HRTIM_OUTPUTIDLEMODE(pOutputCfg->IdleMode)); + assert_param(IS_HRTIM_OUTPUTFAULTSTATE(pOutputCfg->FaultState)); + assert_param(IS_HRTIM_OUTPUTCHOPPERMODE(pOutputCfg->ChopperModeEnable)); + assert_param(IS_HRTIM_OUTPUTBURSTMODEENTRY(pOutputCfg->BurstModeEntryDelayed)); + + /* Configure the timer output */ + HRTIM_OutputConfig(HRTIMx, TimerIdx, Output, pOutputCfg); +} + +/** + * @brief Configures the event filtering capabilities of a timer (blanking, windowing) + * @param HRTIMx: pointer to HRTIMx peripheral + * @param TimerIdx: Timer index + * This parameter can be one of the following values: + * @arg 0x0 to 0x4 for timers A to E + * @param Event: external event for which timer event filtering must be configured + * This parameter can be one of the following values: + * @arg HRTIM_EVENT_1: External event 1 + * @arg HRTIM_EVENT_2: External event 2 + * @arg HRTIM_EVENT_3: External event 3 + * @arg HRTIM_EVENT_4: External event 4 + * @arg HRTIM_EVENT_5: External event 5 + * @arg HRTIM_EVENT_6: External event 6 + * @arg HRTIM_EVENT_7: External event 7 + * @arg HRTIM_EVENT_8: External event 8 + * @arg HRTIM_EVENT_9: External event 9 + * @arg HRTIM_EVENT_10: External event 10 + * @param pTimerEventFilteringCfg: pointer to the timer event filtering configuration structure + * @retval None + */ +void HRTIM_TimerEventFilteringConfig(HRTIM_TypeDef * HRTIMx, + uint32_t TimerIdx, + uint32_t Event, + HRTIM_TimerEventFilteringCfgTypeDef* pTimerEventFilteringCfg) +{ + uint32_t HRTIM_eefr; + + /* Check parameters */ + assert_param(IS_HRTIM_TIMING_UNIT(TimerIdx)); + assert_param(IS_HRTIM_EVENT(Event)); + assert_param(IS_HRTIM_TIMEVENTFILTER(pTimerEventFilteringCfg->Filter)); + assert_param(IS_HRTIM_TIMEVENTLATCH(pTimerEventFilteringCfg->Latch)); + + /* Configure timer event filtering capabilities */ + switch (Event) + { + case HRTIM_TIMEVENTFILTER_NONE: + { + HRTIMx->HRTIM_TIMERx[TimerIdx].EEFxR1 = 0; + HRTIMx->HRTIM_TIMERx[TimerIdx].EEFxR2 = 0; + } + break; + case HRTIM_EVENT_1: + { + HRTIM_eefr = HRTIMx->HRTIM_TIMERx[TimerIdx].EEFxR1; + HRTIM_eefr &= ~(HRTIM_EEFR1_EE1FLTR | HRTIM_EEFR1_EE1LTCH); + HRTIM_eefr |= (pTimerEventFilteringCfg->Filter | pTimerEventFilteringCfg->Latch); + HRTIMx->HRTIM_TIMERx[TimerIdx].EEFxR1 = HRTIM_eefr; + } + break; + case HRTIM_EVENT_2: + { + HRTIM_eefr = HRTIMx->HRTIM_TIMERx[TimerIdx].EEFxR1; + HRTIM_eefr &= ~(HRTIM_EEFR1_EE2FLTR | HRTIM_EEFR1_EE2LTCH); + HRTIM_eefr |= ((pTimerEventFilteringCfg->Filter | pTimerEventFilteringCfg->Latch) << 6); + HRTIMx->HRTIM_TIMERx[TimerIdx].EEFxR1 = HRTIM_eefr; + } + break; + case HRTIM_EVENT_3: + { + HRTIM_eefr = HRTIMx->HRTIM_TIMERx[TimerIdx].EEFxR1; + HRTIM_eefr &= ~(HRTIM_EEFR1_EE3FLTR | HRTIM_EEFR1_EE3LTCH); + HRTIM_eefr |= ((pTimerEventFilteringCfg->Filter | pTimerEventFilteringCfg->Latch) << 12); + HRTIMx->HRTIM_TIMERx[TimerIdx].EEFxR1 = HRTIM_eefr; + } + break; + case HRTIM_EVENT_4: + { + HRTIM_eefr = HRTIMx->HRTIM_TIMERx[TimerIdx].EEFxR1; + HRTIM_eefr &= ~(HRTIM_EEFR1_EE4FLTR | HRTIM_EEFR1_EE4LTCH); + HRTIM_eefr |= ((pTimerEventFilteringCfg->Filter | pTimerEventFilteringCfg->Latch) << 18); + HRTIMx->HRTIM_TIMERx[TimerIdx].EEFxR1 = HRTIM_eefr; + } + break; + case HRTIM_EVENT_5: + { + HRTIM_eefr = HRTIMx->HRTIM_TIMERx[TimerIdx].EEFxR1; + HRTIM_eefr &= ~(HRTIM_EEFR1_EE5FLTR | HRTIM_EEFR1_EE5LTCH); + HRTIM_eefr |= ((pTimerEventFilteringCfg->Filter | pTimerEventFilteringCfg->Latch) << 24); + HRTIMx->HRTIM_TIMERx[TimerIdx].EEFxR1 = HRTIM_eefr; + } + break; + case HRTIM_EVENT_6: + { + HRTIM_eefr = HRTIMx->HRTIM_TIMERx[TimerIdx].EEFxR2; + HRTIM_eefr &= ~(HRTIM_EEFR2_EE6FLTR | HRTIM_EEFR2_EE6LTCH); + HRTIM_eefr |= (pTimerEventFilteringCfg->Filter | pTimerEventFilteringCfg->Latch); + HRTIMx->HRTIM_TIMERx[TimerIdx].EEFxR2 = HRTIM_eefr; + } + break; + case HRTIM_EVENT_7: + { + HRTIM_eefr = HRTIMx->HRTIM_TIMERx[TimerIdx].EEFxR2; + HRTIM_eefr &= ~(HRTIM_EEFR2_EE7FLTR | HRTIM_EEFR2_EE7LTCH); + HRTIM_eefr |= ((pTimerEventFilteringCfg->Filter | pTimerEventFilteringCfg->Latch) << 6); + HRTIMx->HRTIM_TIMERx[TimerIdx].EEFxR2 = HRTIM_eefr; + } + break; + case HRTIM_EVENT_8: + { + HRTIM_eefr = HRTIMx->HRTIM_TIMERx[TimerIdx].EEFxR2; + HRTIM_eefr &= ~(HRTIM_EEFR2_EE8FLTR | HRTIM_EEFR2_EE8LTCH); + HRTIM_eefr |= ((pTimerEventFilteringCfg->Filter | pTimerEventFilteringCfg->Latch) << 12); + HRTIMx->HRTIM_TIMERx[TimerIdx].EEFxR2 = HRTIM_eefr; + } + break; + case HRTIM_EVENT_9: + { + HRTIM_eefr = HRTIMx->HRTIM_TIMERx[TimerIdx].EEFxR2; + HRTIM_eefr &= ~(HRTIM_EEFR2_EE9FLTR | HRTIM_EEFR2_EE9LTCH); + HRTIM_eefr |= ((pTimerEventFilteringCfg->Filter | pTimerEventFilteringCfg->Latch) << 18); + HRTIMx->HRTIM_TIMERx[TimerIdx].EEFxR2 = HRTIM_eefr; + } + break; + case HRTIM_EVENT_10: + { + HRTIM_eefr = HRTIMx->HRTIM_TIMERx[TimerIdx].EEFxR2; + HRTIM_eefr &= ~(HRTIM_EEFR2_EE10FLTR | HRTIM_EEFR2_EE10LTCH); + HRTIM_eefr |= ((pTimerEventFilteringCfg->Filter | pTimerEventFilteringCfg->Latch) << 24); + HRTIMx->HRTIM_TIMERx[TimerIdx].EEFxR2 = HRTIM_eefr; + } + break; + default: + break; + } +} + +/** + * @brief Configures the dead time insertion feature for a timer + * @param HRTIMx: pointer to HRTIMx peripheral + * @param TimerIdx: Timer index + * This parameter can be one of the following values: + * @arg 0x0 to 0x4 for timers A to E + * @param pDeadTimeCfg: pointer to the dead time insertion configuration structure + * @retval None + */ +void HRTIM_DeadTimeConfig(HRTIM_TypeDef * HRTIMx, + uint32_t TimerIdx, + HRTIM_DeadTimeCfgTypeDef* pDeadTimeCfg) +{ + uint32_t HRTIM_dtr; + + /* Check parameters */ + assert_param(IS_HRTIM_TIMING_UNIT(TimerIdx)); + assert_param(IS_HRTIM_TIMDEADTIME_RISINGSIGN(pDeadTimeCfg->RisingSign)); + assert_param(IS_HRTIM_TIMDEADTIME_RISINGLOCK(pDeadTimeCfg->RisingLock)); + assert_param(IS_HRTIM_TIMDEADTIME_RISINGSIGNLOCK(pDeadTimeCfg->RisingSignLock)); + assert_param(IS_HRTIM_TIMDEADTIME_FALLINGSIGN(pDeadTimeCfg->FallingSign)); + assert_param(IS_HRTIM_TIMDEADTIME_FALLINGLOCK(pDeadTimeCfg->FallingLock)); + assert_param(IS_HRTIM_TIMDEADTIME_FALLINGSIGNLOCK(pDeadTimeCfg->FallingSignLock)); + + HRTIM_dtr = HRTIMx->HRTIM_TIMERx[TimerIdx].DTxR; + + /* Clear timer dead times configuration */ + HRTIM_dtr &= ~(HRTIM_DTR_DTR | HRTIM_DTR_SDTR | HRTIM_DTR_DTPRSC | + HRTIM_DTR_DTRSLK | HRTIM_DTR_DTRLK | HRTIM_DTR_SDTF | + HRTIM_DTR_SDTR | HRTIM_DTR_DTFSLK | HRTIM_DTR_DTFLK); + + /* Set timer dead times configuration */ + HRTIM_dtr |= (pDeadTimeCfg->Prescaler << 10); + HRTIM_dtr |= pDeadTimeCfg->RisingValue; + HRTIM_dtr |= pDeadTimeCfg->RisingSign; + HRTIM_dtr |= pDeadTimeCfg->RisingSignLock; + HRTIM_dtr |= pDeadTimeCfg->RisingLock; + HRTIM_dtr |= (pDeadTimeCfg->FallingValue << 16); + HRTIM_dtr |= pDeadTimeCfg->FallingSign; + HRTIM_dtr |= pDeadTimeCfg->FallingSignLock; + HRTIM_dtr |= pDeadTimeCfg->FallingLock; + + /* Update the HRTIMx registers */ + HRTIMx->HRTIM_TIMERx[TimerIdx].DTxR = HRTIM_dtr; +} + +/** + * @brief Configures the chopper mode feature for a timer + * @param HRTIMx: pointer to HRTIMx peripheral + * @param TimerIdx: Timer index + * This parameter can be one of the following values: + * @arg 0x0 to 0x4 for timers A to E + * @param pChopperModeCfg: pointer to the chopper mode configuration structure + * @retval None + */ +void HRTIM_ChopperModeConfig(HRTIM_TypeDef * HRTIMx, + uint32_t TimerIdx, + HRTIM_ChopperModeCfgTypeDef* pChopperModeCfg) +{ + uint32_t HRTIM_chpr; + + /* Check parameters */ + assert_param(IS_HRTIM_TIMING_UNIT(TimerIdx)); + + HRTIM_chpr = HRTIMx->HRTIM_TIMERx[TimerIdx].CHPxR; + + /* Clear timer chopper mode configuration */ + HRTIM_chpr &= ~(HRTIM_CHPR_CARFRQ | HRTIM_CHPR_CARDTY | HRTIM_CHPR_STRPW); + + /* Set timer chopper mode configuration */ + HRTIM_chpr |= pChopperModeCfg->CarrierFreq; + HRTIM_chpr |= (pChopperModeCfg->DutyCycle << 4); + HRTIM_chpr |= (pChopperModeCfg->StartPulse << 7); + + /* Update the HRTIMx registers */ + HRTIMx->HRTIM_TIMERx[TimerIdx].CHPxR = HRTIM_chpr; +} + +/** + * @brief Configures the burst DMA controller for a timer + * @param HRTIMx: pointer to HRTIMx peripheral + * @param TimerIdx: Timer index + * This parameter can be one of the following values: + * @arg 0x5 for master timer + * @arg 0x0 to 0x4 for timers A to E + * @param RegistersToUpdate: registers to be written by DMA + * This parameter can be any combination of the following values: + * @arg HRTIM_BURSTDMA_CR: HRTIM_MCR or HRTIM_TIMxCR + * @arg HRTIM_BURSTDMA_ICR: HRTIM_MICR or HRTIM_TIMxICR + * @arg HRTIM_BURSTDMA_DIER: HRTIM_MDIER or HRTIM_TIMxDIER + * @arg HRTIM_BURSTDMA_CNT: HRTIM_MCNT or HRTIM_TIMxCNT + * @arg HRTIM_BURSTDMA_PER: HRTIM_MPER or HRTIM_TIMxPER + * @arg HRTIM_BURSTDMA_REP: HRTIM_MREP or HRTIM_TIMxREP + * @arg HRTIM_BURSTDMA_CMP1: HRTIM_MCMP1 or HRTIM_TIMxCMP1 + * @arg HRTIM_BURSTDMA_CMP2: HRTIM_MCMP2 or HRTIM_TIMxCMP2 + * @arg HRTIM_BURSTDMA_CMP3: HRTIM_MCMP3 or HRTIM_TIMxCMP3 + * @arg HRTIM_BURSTDMA_CMP4: HRTIM_MCMP4 or HRTIM_TIMxCMP4 + * @arg HRTIM_BURSTDMA_DTR: HRTIM_TIMxDTR + * @arg HRTIM_BURSTDMA_SET1R: HRTIM_TIMxSET1R + * @arg HRTIM_BURSTDMA_RST1R: HRTIM_TIMxRST1R + * @arg HRTIM_BURSTDMA_SET2R: HRTIM_TIMxSET2R + * @arg HRTIM_BURSTDMA_RST2R: HRTIM_TIMxRST2R + * @arg HRTIM_BURSTDMA_EEFR1: HRTIM_TIMxEEFR1 + * @arg HRTIM_BURSTDMA_EEFR2: HRTIM_TIMxEEFR2 + * @arg HRTIM_BURSTDMA_RSTR: HRTIM_TIMxRSTR + * @arg HRTIM_BURSTDMA_CHPR: HRTIM_TIMxCHPR + * @arg HRTIM_BURSTDMA_OUTR: HRTIM_TIMxOUTR + * @arg HRTIM_BURSTDMA_FLTR: HRTIM_TIMxFLTR + * @retval None + */ +void HRTIM_BurstDMAConfig(HRTIM_TypeDef * HRTIMx, + uint32_t TimerIdx, + uint32_t RegistersToUpdate) +{ + /* Check parameters */ + assert_param(IS_HRTIM_TIMER_BURSTDMA(TimerIdx, RegistersToUpdate)); + + /* Set the burst DMA timer update register */ + switch (TimerIdx) + { + case HRTIM_TIMERINDEX_TIMER_A: + { + HRTIMx->HRTIM_COMMON.BDTAUPR = RegistersToUpdate; + } + break; + case HRTIM_TIMERINDEX_TIMER_B: + { + HRTIMx->HRTIM_COMMON.BDTBUPR = RegistersToUpdate; + } + break; + case HRTIM_TIMERINDEX_TIMER_C: + { + HRTIMx->HRTIM_COMMON.BDTCUPR = RegistersToUpdate; + } + break; + case HRTIM_TIMERINDEX_TIMER_D: + { + HRTIMx->HRTIM_COMMON.BDTDUPR = RegistersToUpdate; + } + break; + case HRTIM_TIMERINDEX_TIMER_E: + { + HRTIMx->HRTIM_COMMON.BDTEUPR = RegistersToUpdate; + } + break; + case HRTIM_TIMERINDEX_MASTER: + { + HRTIMx->HRTIM_COMMON.BDMUPDR = RegistersToUpdate; + } + break; + default: + break; + } +} + +/** + * @brief Configures the external input/output synchronization of the HRTIMx + * @param HRTIMx: pointer to HRTIMx peripheral + * @param pSynchroCfg: pointer to the input/output synchronization configuration structure + * @retval None + */ +void HRTIM_SynchronizationConfig(HRTIM_TypeDef *HRTIMx, HRTIM_SynchroCfgTypeDef * pSynchroCfg) +{ + uint32_t HRTIM_mcr; + + /* Check parameters */ + assert_param(IS_HRTIM_SYNCINPUTSOURCE(pSynchroCfg->SyncInputSource)); + assert_param(IS_HRTIM_SYNCOUTPUTSOURCE(pSynchroCfg->SyncOutputSource)); + assert_param(IS_HRTIM_SYNCOUTPUTPOLARITY(pSynchroCfg->SyncOutputPolarity)); + + HRTIM_mcr = HRTIMx->HRTIM_MASTER.MCR; + + /* Set the synchronization input source */ + HRTIM_mcr &= ~(HRTIM_MCR_SYNC_IN); + HRTIM_mcr |= pSynchroCfg->SyncInputSource; + + /* Set the event to be sent on the synchronization output */ + HRTIM_mcr &= ~(HRTIM_MCR_SYNC_SRC); + HRTIM_mcr |= pSynchroCfg->SyncOutputSource; + + /* Set the polarity of the synchronization output */ + HRTIM_mcr &= ~(HRTIM_MCR_SYNC_OUT); + HRTIM_mcr |= pSynchroCfg->SyncOutputPolarity; + + /* Update the HRTIMx registers */ + HRTIMx->HRTIM_MASTER.MCR = HRTIM_mcr; +} + +/** + * @brief Configures the burst mode feature of the HRTIMx + * @param HRTIMx: pointer to HRTIMx peripheral + * @param pBurstModeCfg: pointer to the burst mode configuration structure + * @retval None + */ +void HRTIM_BurstModeConfig(HRTIM_TypeDef * HRTIMx, + HRTIM_BurstModeCfgTypeDef* pBurstModeCfg) +{ + uint32_t HRTIM_bmcr; + + /* Check parameters */ + assert_param(IS_HRTIM_BURSTMODE(pBurstModeCfg->Mode)); + assert_param(IS_HRTIM_BURSTMODECLOCKSOURCE(pBurstModeCfg->ClockSource)); + assert_param(IS_HRTIM_HRTIM_BURSTMODEPRESCALER(pBurstModeCfg->Prescaler)); + assert_param(IS_HRTIM_BURSTMODEPRELOAD(pBurstModeCfg->PreloadEnable)); + + HRTIM_bmcr = HRTIMx->HRTIM_COMMON.BMCR; + + /* Set the burst mode operating mode */ + HRTIM_bmcr &= ~(HRTIM_BMCR_BMOM); + HRTIM_bmcr |= pBurstModeCfg->Mode; + + /* Set the burst mode clock source */ + HRTIM_bmcr &= ~(HRTIM_BMCR_BMCLK); + HRTIM_bmcr |= pBurstModeCfg->ClockSource; + + /* Set the burst mode prescaler */ + HRTIM_bmcr &= ~(HRTIM_BMCR_BMPSC); + HRTIM_bmcr |= pBurstModeCfg->Prescaler; + + /* Enable/disable burst mode registers preload */ + HRTIM_bmcr &= ~(HRTIM_BMCR_BMPREN); + HRTIM_bmcr |= pBurstModeCfg->PreloadEnable; + + /* Set the burst mode trigger */ + HRTIMx->HRTIM_COMMON.BMTRGR = pBurstModeCfg->Trigger; + + /* Set the burst mode compare value */ + HRTIMx->HRTIM_COMMON.BMCMPR = pBurstModeCfg->IdleDuration; + + /* Set the burst mode period */ + HRTIMx->HRTIM_COMMON.BMPER = pBurstModeCfg->Period; + + /* Update the HRTIMx registers */ + HRTIMx->HRTIM_COMMON.BMCR = HRTIM_bmcr; +} + +/** + * @brief Configures the conditioning of an external event + * @param HRTIMx: pointer to HRTIMx peripheral + * @param Event: external event to configure + * This parameter can be one of the following values: + * @arg HRTIM_EVENT_1: External event 1 + * @arg HRTIM_EVENT_2: External event 2 + * @arg HRTIM_EVENT_3: External event 3 + * @arg HRTIM_EVENT_4: External event 4 + * @arg HRTIM_EVENT_5: External event 5 + * @arg HRTIM_EVENT_6: External event 6 + * @arg HRTIM_EVENT_7: External event 7 + * @arg HRTIM_EVENT_8: External event 8 + * @arg HRTIM_EVENT_9: External event 9 + * @arg HRTIM_EVENT_10: External event 10 + * @param pEventCfg: pointer to the event conditioning configuration structure + * @retval None + */ +void HRTIM_EventConfig(HRTIM_TypeDef * HRTIMx, + uint32_t Event, + HRTIM_EventCfgTypeDef* pEventCfg) +{ + /* Check parameters */ + assert_param(IS_HRTIM_EVENTSRC(pEventCfg->Source)); + assert_param(IS_HRTIM_EVENTPOLARITY(pEventCfg->Polarity)); + assert_param(IS_HRTIM_EVENTSENSITIVITY(pEventCfg->Sensitivity)); + assert_param(IS_HRTIM_EVENTFASTMODE(pEventCfg->FastMode)); + assert_param(IS_HRTIM_EVENTFILTER(pEventCfg->Filter)); + + /* Configure the event channel */ + HRTIM_ExternalEventConfig(HRTIMx, Event, pEventCfg); + +} + +/** + * @brief Configures the external event conditioning block prescaler + * @param HRTIMx: pointer to HRTIMx peripheral + * @param Prescaler: Prescaler value + * This parameter can be one of the following values: + * @arg HRTIM_EVENTPRESCALER_DIV1: fEEVS=fHRTIMx + * @arg HRTIM_EVENTPRESCALER_DIV2: fEEVS=fHRTIMx / 2 + * @arg HRTIM_EVENTPRESCALER_DIV4: fEEVS=fHRTIMx / 4 + * @arg HRTIM_EVENTPRESCALER_DIV8: fEEVS=fHRTIMx / 8 + * @retval None + */ +void HRTIM_EventPrescalerConfig(HRTIM_TypeDef * HRTIMx, + uint32_t Prescaler) +{ + uint32_t HRTIM_eecr3; + + /* Check parameters */ + assert_param(IS_HRTIM_EVENTPRESCALER(Prescaler)); + + /* Set the external event prescaler */ + HRTIM_eecr3 = HRTIMx->HRTIM_COMMON.EECR3; + HRTIM_eecr3 &= ~(HRTIM_EECR3_EEVSD); + HRTIM_eecr3 |= Prescaler; + + /* Update the HRTIMx registers */ + HRTIMx->HRTIM_COMMON.EECR3 = HRTIM_eecr3; +} + +/** + * @brief Configures the conditioning of fault input + * @param HRTIMx: pointer to HRTIMx peripheral + * @param Fault: fault input to configure + * This parameter can be one of the following values: + * @arg HRTIM_FAULT_1: Fault input 1 + * @arg HRTIM_FAULT_2: Fault input 2 + * @arg HRTIM_FAULT_3: Fault input 3 + * @arg HRTIM_FAULT_4: Fault input 4 + * @arg HRTIM_FAULT_5: Fault input 5 + * @param pFaultCfg: pointer to the fault conditioning configuration structure + * @retval None + */ +void HRTIM_FaultConfig(HRTIM_TypeDef * HRTIMx, + HRTIM_FaultCfgTypeDef* pFaultCfg, + uint32_t Fault) +{ + uint32_t HRTIM_fltinr1; + uint32_t HRTIM_fltinr2; + + /* Check parameters */ + assert_param(IS_HRTIM_FAULT(Fault)); + assert_param(IS_HRTIM_FAULTSOURCE(pFaultCfg->Source)); + assert_param(IS_HRTIM_FAULTPOLARITY(pFaultCfg->Polarity)); + assert_param(IS_HRTIM_FAULTFILTER(pFaultCfg->Filter)); + assert_param(IS_HRTIM_FAULTLOCK(pFaultCfg->Lock)); + + /* Configure fault channel */ + HRTIM_fltinr1 = HRTIMx->HRTIM_COMMON.FLTINxR1; + HRTIM_fltinr2 = HRTIMx->HRTIM_COMMON.FLTINxR2; + + switch (Fault) + { + case HRTIM_FAULT_1: + { + HRTIM_fltinr1 &= ~(HRTIM_FLTINR1_FLT1P | HRTIM_FLTINR1_FLT1SRC | HRTIM_FLTINR1_FLT1F | HRTIM_FLTINR1_FLT1LCK); + HRTIM_fltinr1 |= pFaultCfg->Polarity; + HRTIM_fltinr1 |= pFaultCfg->Source; + HRTIM_fltinr1 |= pFaultCfg->Filter; + HRTIM_fltinr1 |= pFaultCfg->Lock; + } + break; + case HRTIM_FAULT_2: + { + HRTIM_fltinr1 &= ~(HRTIM_FLTINR1_FLT2P | HRTIM_FLTINR1_FLT2SRC | HRTIM_FLTINR1_FLT2F | HRTIM_FLTINR1_FLT2LCK); + HRTIM_fltinr1 |= (pFaultCfg->Polarity << 8); + HRTIM_fltinr1 |= (pFaultCfg->Source << 8); + HRTIM_fltinr1 |= (pFaultCfg->Filter << 8); + HRTIM_fltinr1 |= (pFaultCfg->Lock << 8); + } + break; + case HRTIM_FAULT_3: + { + HRTIM_fltinr1 &= ~(HRTIM_FLTINR1_FLT3P | HRTIM_FLTINR1_FLT3SRC | HRTIM_FLTINR1_FLT3F | HRTIM_FLTINR1_FLT3LCK); + HRTIM_fltinr1 |= (pFaultCfg->Polarity << 16); + HRTIM_fltinr1 |= (pFaultCfg->Source << 16); + HRTIM_fltinr1 |= (pFaultCfg->Filter << 16); + HRTIM_fltinr1 |= (pFaultCfg->Lock << 16); + } + break; + case HRTIM_FAULT_4: + { + HRTIM_fltinr1 &= ~(HRTIM_FLTINR1_FLT4P | HRTIM_FLTINR1_FLT4SRC | HRTIM_FLTINR1_FLT4F | HRTIM_FLTINR1_FLT4LCK); + HRTIM_fltinr1 |= (pFaultCfg->Polarity << 24); + HRTIM_fltinr1 |= (pFaultCfg->Source << 24); + HRTIM_fltinr1 |= (pFaultCfg->Filter << 24); + HRTIM_fltinr1 |= (pFaultCfg->Lock << 24); + } + break; + case HRTIM_FAULT_5: + { + HRTIM_fltinr2 &= ~(HRTIM_FLTINR2_FLT5P | HRTIM_FLTINR2_FLT5SRC | HRTIM_FLTINR2_FLT5F | HRTIM_FLTINR2_FLT5LCK); + HRTIM_fltinr2 |= pFaultCfg->Polarity; + HRTIM_fltinr2 |= pFaultCfg->Source; + HRTIM_fltinr2 |= pFaultCfg->Filter; + HRTIM_fltinr2 |= pFaultCfg->Lock; + } + break; + default: + break; + } + + /* Update the HRTIMx registers */ + HRTIMx->HRTIM_COMMON.FLTINxR1 = HRTIM_fltinr1; + HRTIMx->HRTIM_COMMON.FLTINxR2 = HRTIM_fltinr2; +} + +/** + * @brief Configures the fault conditioning block prescaler + * @param HRTIMx: pointer to HRTIMx peripheral + * @param Prescaler: Prescaler value + * This parameter can be one of the following values: + * @arg HRTIM_FAULTPRESCALER_DIV1: fFLTS=fHRTIMx + * @arg HRTIM_FAULTPRESCALER_DIV2: fFLTS=fHRTIMx / 2 + * @arg HRTIM_FAULTPRESCALER_DIV4: fFLTS=fHRTIMx / 4 + * @arg HRTIM_FAULTPRESCALER_DIV8: fFLTS=fHRTIMx / 8 + * @retval None + */ +void HRTIM_FaultPrescalerConfig(HRTIM_TypeDef * HRTIMx, + uint32_t Prescaler) +{ + uint32_t HRTIM_fltinr2; + + /* Check parameters */ + assert_param(IS_HRTIM_FAULTPRESCALER(Prescaler)); + + /* Set the external event prescaler */ + HRTIM_fltinr2 = HRTIMx->HRTIM_COMMON.FLTINxR2; + HRTIM_fltinr2 &= ~(HRTIM_FLTINR2_FLTSD); + HRTIM_fltinr2 |= Prescaler; + + /* Update the HRTIMx registers */ + HRTIMx->HRTIM_COMMON.FLTINxR2 = HRTIM_fltinr2; +} + +/** + * @brief Enables or disables the HRTIMx Fault mode. + * @param HRTIMx: pointer to HRTIMx peripheral + * @param Fault: fault input to configure + * This parameter can be one of the following values: + * @arg HRTIM_FAULT_1: Fault input 1 + * @arg HRTIM_FAULT_2: Fault input 2 + * @arg HRTIM_FAULT_3: Fault input 3 + * @arg HRTIM_FAULT_4: Fault input 4 + * @arg HRTIM_FAULT_5: Fault input 5 + * @param Enable: Fault mode controller enabling + * This parameter can be one of the following values: + * @arg HRTIM_FAULT_ENABLED: Fault mode enabled + * @arg HRTIM_FAULT_DISABLED: Fault mode disabled + * @retval None + */ +void HRTIM_FaultModeCtl(HRTIM_TypeDef * HRTIMx, uint32_t Fault, uint32_t Enable) +{ + uint32_t HRTIM_fltinr1; + uint32_t HRTIM_fltinr2; + + /* Check parameters */ + assert_param(IS_HRTIM_FAULT(Fault)); + assert_param(IS_HRTIM_FAULTCTL(Enable)); + + /* Configure fault channel */ + HRTIM_fltinr1 = HRTIMx->HRTIM_COMMON.FLTINxR1; + HRTIM_fltinr2 = HRTIMx->HRTIM_COMMON.FLTINxR2; + + switch (Fault) + { + case HRTIM_FAULT_1: + { + HRTIM_fltinr1 &= ~HRTIM_FLTINR1_FLT1E; + HRTIM_fltinr1 |= Enable; + } + break; + case HRTIM_FAULT_2: + { + HRTIM_fltinr1 &= ~HRTIM_FLTINR1_FLT2E; + HRTIM_fltinr1 |= (Enable<< 8); + } + break; + case HRTIM_FAULT_3: + { + HRTIM_fltinr1 &= ~HRTIM_FLTINR1_FLT3E; + HRTIM_fltinr1 |= (Enable << 16); + } + break; + case HRTIM_FAULT_4: + { + HRTIM_fltinr1 &= ~HRTIM_FLTINR1_FLT4E; + HRTIM_fltinr1 |= (Enable << 24); + } + break; + case HRTIM_FAULT_5: + { + HRTIM_fltinr2 &= ~HRTIM_FLTINR2_FLT5E; + HRTIM_fltinr2 |= Enable; + } + break; + default: + break; + } + + /* Update the HRTIMx registers */ + HRTIMx->HRTIM_COMMON.FLTINxR1 = HRTIM_fltinr1; + HRTIMx->HRTIM_COMMON.FLTINxR2 = HRTIM_fltinr2; +} + +/** + * @brief Configures both the ADC trigger register update source and the ADC + * trigger source. + * @param HRTIMx: pointer to HRTIMx peripheral + * @param ADC trigger: ADC trigger to configure + * This parameter can be one of the following values: + * @arg HRTIM_ADCTRIGGER_1: ADC trigger 1 + * @arg HRTIM_ADCTRIGGER_2: ADC trigger 2 + * @arg HRTIM_ADCTRIGGER_3: ADC trigger 3 + * @arg HRTIM_ADCTRIGGER_4: ADC trigger 4 + * @param pADCTriggerCfg: pointer to the ADC trigger configuration structure + * @retval None + */ +void HRTIM_ADCTriggerConfig(HRTIM_TypeDef * HRTIMx, + uint32_t ADCTrigger, + HRTIM_ADCTriggerCfgTypeDef* pADCTriggerCfg) +{ + uint32_t HRTIM_cr1; + + /* Check parameters */ + assert_param(IS_HRTIM_ADCTRIGGER(ADCTrigger)); + assert_param(IS_HRTIM_ADCTRIGGERUPDATE(pADCTriggerCfg->UpdateSource)); + + /* Set the ADC trigger update source */ + HRTIM_cr1 = HRTIMx->HRTIM_COMMON.CR1; + + switch (ADCTrigger) + { + case HRTIM_ADCTRIGGER_1: + { + HRTIM_cr1 &= ~(HRTIM_CR1_ADC1USRC); + HRTIM_cr1 |= pADCTriggerCfg->UpdateSource; + + /* Set the ADC trigger 1 source */ + HRTIMx->HRTIM_COMMON.ADC1R = pADCTriggerCfg->Trigger; + } + break; + case HRTIM_ADCTRIGGER_2: + { + HRTIM_cr1 &= ~(HRTIM_CR1_ADC2USRC); + HRTIM_cr1 |= (pADCTriggerCfg->UpdateSource << 3); + + /* Set the ADC trigger 2 source */ + HRTIMx->HRTIM_COMMON.ADC2R = pADCTriggerCfg->Trigger; + } + break; + case HRTIM_ADCTRIGGER_3: + { + HRTIM_cr1 &= ~(HRTIM_CR1_ADC3USRC); + HRTIM_cr1 |= (pADCTriggerCfg->UpdateSource << 6); + + /* Set the ADC trigger 3 source */ + HRTIMx->HRTIM_COMMON.ADC3R = pADCTriggerCfg->Trigger; + } + case HRTIM_ADCTRIGGER_4: + { + HRTIM_cr1 &= ~(HRTIM_CR1_ADC4USRC); + HRTIM_cr1 |= (pADCTriggerCfg->UpdateSource << 9); + + /* Set the ADC trigger 4 source */ + HRTIMx->HRTIM_COMMON.ADC4R = pADCTriggerCfg->Trigger; + } + break; + default: + break; + } + + /* Update the HRTIMx registers */ + HRTIMx->HRTIM_COMMON.CR1 = HRTIM_cr1; +} + + +/** + * @brief Enables or disables the HRTIMx burst mode controller. + * @param HRTIMx: pointer to HRTIMx peripheral + * @param Enable: Burst mode controller enabling + * This parameter can be one of the following values: + * @arg HRTIM_BURSTMODECTL_ENABLED: Burst mode enabled + * @arg HRTIM_BURSTMODECTL_DISABLED: Burst mode disabled + * @retval None + */ +void HRTIM_BurstModeCtl(HRTIM_TypeDef * HRTIMx, uint32_t Enable) +{ + uint32_t HRTIM_bmcr; + + /* Check parameters */ + assert_param(IS_HRTIM_BURSTMODECTL(Enable)); + + /* Enable/Disable the burst mode controller */ + HRTIM_bmcr = HRTIMx->HRTIM_COMMON.BMCR; + HRTIM_bmcr &= ~(HRTIM_BMCR_BME); + HRTIM_bmcr |= Enable; + + /* Update the HRTIMx registers */ + HRTIMx->HRTIM_COMMON.BMCR = HRTIM_bmcr; +} + +/** + * @brief Triggers a software capture on the designed capture unit + * @param HRTIMx: pointer to HRTIMx peripheral + * @param TimerIdx: Timer index + * This parameter can be one of the following values: + * @arg 0x0 to 0x4 for timers A to E + * @param CaptureUnit: Capture unit to trig + * This parameter can be one of the following values: + * @arg HRTIM_CAPTUREUNIT_1: Capture unit 1 + * @arg HRTIM_CAPTUREUNIT_2: Capture unit 2 + * @retval None + * @note The 'software capture' bit in the capture configuration register is + * automatically reset by hardware + */ +void HRTIM_SoftwareCapture(HRTIM_TypeDef * HRTIMx, + uint32_t TimerIdx, + uint32_t CaptureUnit) +{ + /* Check parameters */ + assert_param(IS_HRTIM_TIMING_UNIT(TimerIdx)); + assert_param(IS_HRTIM_CAPTUREUNIT(CaptureUnit)); + + /* Force a software capture on concerned capture unit */ + switch (CaptureUnit) + { + case HRTIM_CAPTUREUNIT_1: + { + HRTIMx->HRTIM_TIMERx[TimerIdx].CPT1xCR |= HRTIM_CPT1CR_SWCPT; + } + break; + case HRTIM_CAPTUREUNIT_2: + { + HRTIMx->HRTIM_TIMERx[TimerIdx].CPT2xCR |= HRTIM_CPT2CR_SWCPT; + } + break; + default: + break; + } +} + +/** + * @brief Triggers the update of the registers of one or several timers + * @param HRTIMx: pointer to HRTIMx peripheral + * @param TimersToUpdate: timers concerned with the software register update + * This parameter can be any combination of the following values: + * @arg HRTIM_TIMERUPDATE_MASTER + * @arg HRTIM_TIMERUPDATE_A + * @arg HRTIM_TIMERUPDATE_B + * @arg HRTIM_TIMERUPDATE_C + * @arg HRTIM_TIMERUPDATE_D + * @arg HRTIM_TIMERUPDATE_E + * @retval None + * @note The 'software update' bits in the HRTIMx control register 2 register are + * automatically reset by hardware + */ +void HRTIM_SoftwareUpdate(HRTIM_TypeDef * HRTIMx, + uint32_t TimersToUpdate) +{ + /* Check parameters */ + assert_param(IS_HRTIM_TIMERUPDATE(TimersToUpdate)); + + /* Force timer(s) registers update */ + HRTIMx->HRTIM_COMMON.CR2 |= TimersToUpdate; + +} + +/** + * @brief Triggers the reset of one or several timers + * @param HRTIMx: pointer to HRTIMx peripheral + * @param TimersToUpdate: timers concerned with the software counter reset + * This parameter can be any combination of the following values: + * @arg HRTIM_TIMER_MASTER + * @arg HRTIM_TIMER_A + * @arg HRTIM_TIMER_B + * @arg HRTIM_TIMER_C + * @arg HRTIM_TIMER_D + * @arg HRTIM_TIMER_E + * @retval None + * @note The 'software reset' bits in the HRTIMx control register 2 are + * automatically reset by hardware + */ +void HRTIM_SoftwareReset(HRTIM_TypeDef * HRTIMx, + uint32_t TimersToReset) +{ + /* Check parameters */ + assert_param(IS_HRTIM_TIMERRESET(TimersToReset)); + + /* Force timer(s) registers update */ + HRTIMx->HRTIM_COMMON.CR2 |= TimersToReset; + +} + +/** + * @brief Forces the timer output to its active or inactive state + * @param HRTIMx: pointer to HRTIMx peripheral + * @param TimerIdx: Timer index + * This parameter can be one of the following values: + * @arg 0x0 to 0x4 for timers A to E + * @param Output: Timer output + * This parameter can be one of the following values: + * @arg HRTIM_OUTPUT_TA1: Timer A - Output 1 + * @arg HRTIM_OUTPUT_TA2: Timer A - Output 2 + * @arg HRTIM_OUTPUT_TB1: Timer B - Output 1 + * @arg HRTIM_OUTPUT_TB2: Timer B - Output 2 + * @arg HRTIM_OUTPUT_TC1: Timer C - Output 1 + * @arg HRTIM_OUTPUT_TC2: Timer C - Output 2 + * @arg HRTIM_OUTPUT_TD1: Timer D - Output 1 + * @arg HRTIM_OUTPUT_TD2: Timer D - Output 2 + * @arg HRTIM_OUTPUT_TE1: Timer E - Output 1 + * @arg HRTIM_OUTPUT_TE2: Timer E - Output 2 + * @param OutputLevel: indicates whether the output is forced to its active or inactive state + * This parameter can be one of the following values: + * @arg HRTIM_OUTPUTLEVEL_ACTIVE: output is forced to its active state + * @arg HRTIM_OUTPUTLEVEL_INACTIVE: output is forced to its inactive state + * @retval None + * @note The 'software set/reset trigger' bit in the output set/reset registers + * is automatically reset by hardware + */ +void HRTIM_WaveformSetOutputLevel(HRTIM_TypeDef * HRTIMx, + uint32_t TimerIdx, + uint32_t Output, + uint32_t OutputLevel) +{ + /* Check parameters */ + assert_param(IS_HRTIM_TIMER_OUTPUT(TimerIdx, Output)); + assert_param(IS_HRTIM_OUTPUTLEVEL(OutputLevel)); + + /* Force timer output level */ + switch (Output) + { + case HRTIM_OUTPUT_TA1: + case HRTIM_OUTPUT_TB1: + case HRTIM_OUTPUT_TC1: + case HRTIM_OUTPUT_TD1: + case HRTIM_OUTPUT_TE1: + { + if (OutputLevel == HRTIM_OUTPUTLEVEL_ACTIVE) + { + /* Force output to its active state */ + HRTIMx->HRTIM_TIMERx[TimerIdx].SETx1R |= HRTIM_SET1R_SST; + } + else + { + /* Force output to its inactive state */ + HRTIMx->HRTIM_TIMERx[TimerIdx].RSTx1R |= HRTIM_RST1R_SRT; + } + } + break; + case HRTIM_OUTPUT_TA2: + case HRTIM_OUTPUT_TB2: + case HRTIM_OUTPUT_TC2: + case HRTIM_OUTPUT_TD2: + case HRTIM_OUTPUT_TE2: + { + if (OutputLevel == HRTIM_OUTPUTLEVEL_ACTIVE) + { + /* Force output to its active state */ + HRTIMx->HRTIM_TIMERx[TimerIdx].SETx2R |= HRTIM_SET2R_SST; + } + else + { + /* Force output to its inactive state */ + HRTIMx->HRTIM_TIMERx[TimerIdx].RSTx2R |= HRTIM_RST2R_SRT; + } + } + break; + default: + break; + } +} + + +/** + * @} + */ + +/** @defgroup HRTIM_Group4 Peripheral State methods + * @brief Peripheral State functions + * +@verbatim + =============================================================================== + ##### Peripheral State methods ##### + =============================================================================== + [..] + This subsection permit to get in run-time the status of the peripheral + and the data flow. + +@endverbatim + * @{ + */ + +/** + * @brief Returns actual value of the capture register of the designated capture unit + * @param HRTIMx: pointer to HRTIMx peripheral + * @param TimerIdx: Timer index + * This parameter can be one of the following values: + * @arg 0x0 to 0x4 for timers A to E + * @param CaptureUnit: Capture unit to trig + * This parameter can be one of the following values: + * @arg HRTIM_CAPTUREUNIT_1: Capture unit 1 + * @arg HRTIM_CAPTUREUNIT_2: Capture unit 2 + * @retval Captured value + */ +uint32_t HRTIM_GetCapturedValue(HRTIM_TypeDef * HRTIMx, + uint32_t TimerIdx, + uint32_t CaptureUnit) +{ + uint32_t captured_value = 0; + + /* Check parameters */ + assert_param(IS_HRTIM_TIMING_UNIT(TimerIdx)); + assert_param(IS_HRTIM_CAPTUREUNIT(CaptureUnit)); + + /* Read captured value */ + switch (CaptureUnit) + { + case HRTIM_CAPTUREUNIT_1: + { + captured_value = HRTIMx->HRTIM_TIMERx[TimerIdx].CPT1xR; + } + break; + case HRTIM_CAPTUREUNIT_2: + { + captured_value = HRTIMx->HRTIM_TIMERx[TimerIdx].CPT2xR; + } + break; + default: + break; + } + + return captured_value; +} + +/** + * @brief Returns actual level (active or inactive) of the designated output + * @param HRTIMx: pointer to HRTIMx peripheral + * @param TimerIdx: Timer index + * This parameter can be one of the following values: + * @arg 0x0 to 0x4 for timers A to E + * @param Output: Timer output + * This parameter can be one of the following values: + * @arg HRTIM_OUTPUT_TA1: Timer A - Output 1 + * @arg HRTIM_OUTPUT_TA2: Timer A - Output 2 + * @arg HRTIM_OUTPUT_TB1: Timer B - Output 1 + * @arg HRTIM_OUTPUT_TB2: Timer B - Output 2 + * @arg HRTIM_OUTPUT_TC1: Timer C - Output 1 + * @arg HRTIM_OUTPUT_TC2: Timer C - Output 2 + * @arg HRTIM_OUTPUT_TD1: Timer D - Output 1 + * @arg HRTIM_OUTPUT_TD2: Timer D - Output 2 + * @arg HRTIM_OUTPUT_TE1: Timer E - Output 1 + * @arg HRTIM_OUTPUT_TE2: Timer E - Output 2 + * @retval Output level + * @note Returned output level is taken before the output stage (chopper, + * polarity). + */ +uint32_t HRTIM_WaveformGetOutputLevel(HRTIM_TypeDef * HRTIMx, + uint32_t TimerIdx, + uint32_t Output) +{ + uint32_t output_level = HRTIM_OUTPUTLEVEL_INACTIVE; + + /* Check parameters */ + assert_param(IS_HRTIM_TIMER_OUTPUT(TimerIdx, Output)); + + /* Read the output level */ + switch (Output) + { + case HRTIM_OUTPUT_TA1: + case HRTIM_OUTPUT_TB1: + case HRTIM_OUTPUT_TC1: + case HRTIM_OUTPUT_TD1: + case HRTIM_OUTPUT_TE1: + { + if ((HRTIMx->HRTIM_TIMERx[TimerIdx].TIMxISR & HRTIM_TIMISR_O1CPY) != RESET) + { + output_level = HRTIM_OUTPUTLEVEL_ACTIVE; + } + else + { + output_level = HRTIM_OUTPUTLEVEL_INACTIVE; + } + } + break; + case HRTIM_OUTPUT_TA2: + case HRTIM_OUTPUT_TB2: + case HRTIM_OUTPUT_TC2: + case HRTIM_OUTPUT_TD2: + case HRTIM_OUTPUT_TE2: + { + if ((HRTIMx->HRTIM_TIMERx[TimerIdx].TIMxISR & HRTIM_TIMISR_O2CPY) != RESET) + { + output_level = HRTIM_OUTPUTLEVEL_ACTIVE; + } + else + { + output_level = HRTIM_OUTPUTLEVEL_INACTIVE; + } + } + break; + default: + break; + } + + return output_level; +} + +/** + * @brief Returns actual state (RUN, IDLE, FAULT) of the designated output + * @param HRTIMx: pointer to HRTIMx peripheral + * @param TimerIdx: Timer index + * This parameter can be one of the following values: + * @arg 0x0 to 0x4 for timers A to E + * @param Output: Timer output + * This parameter can be one of the following values: + * @arg HRTIM_OUTPUT_TA1: Timer A - Output 1 + * @arg HRTIM_OUTPUT_TA2: Timer A - Output 2 + * @arg HRTIM_OUTPUT_TB1: Timer B - Output 1 + * @arg HRTIM_OUTPUT_TB2: Timer B - Output 2 + * @arg HRTIM_OUTPUT_TC1: Timer C - Output 1 + * @arg HRTIM_OUTPUT_TC2: Timer C - Output 2 + * @arg HRTIM_OUTPUT_TD1: Timer D - Output 1 + * @arg HRTIM_OUTPUT_TD2: Timer D - Output 2 + * @arg HRTIM_OUTPUT_TE1: Timer E - Output 1 + * @arg HRTIM_OUTPUT_TE2: Timer E - Output 2 + * @retval Output state + */ +uint32_t HRTIM_WaveformGetOutputState(HRTIM_TypeDef * HRTIMx, + uint32_t TimerIdx, + uint32_t Output) +{ + uint32_t output_bit = 0; + uint32_t output_state = HRTIM_OUTPUTSTATE_IDLE; + + /* Check parameters */ + assert_param(IS_HRTIM_TIMER_OUTPUT(TimerIdx, Output)); + + /* Set output state according to output control status and output disable status */ + switch (Output) + { + case HRTIM_OUTPUT_TA1: + { + output_bit = HRTIM_OENR_TA1OEN; + } + break; + case HRTIM_OUTPUT_TA2: + { + output_bit = HRTIM_OENR_TA2OEN; + } + break; + case HRTIM_OUTPUT_TB1: + { + output_bit = HRTIM_OENR_TB1OEN; + } + break; + case HRTIM_OUTPUT_TB2: + { + output_bit = HRTIM_OENR_TB2OEN; + } + break; + case HRTIM_OUTPUT_TC1: + { + output_bit = HRTIM_OENR_TC1OEN; + } + break; + case HRTIM_OUTPUT_TC2: + { + output_bit = HRTIM_OENR_TC2OEN; + } + break; + case HRTIM_OUTPUT_TD1: + { + output_bit = HRTIM_OENR_TD1OEN; + } + break; + case HRTIM_OUTPUT_TD2: + { + output_bit = HRTIM_OENR_TD2OEN; + } + break; + case HRTIM_OUTPUT_TE1: + { + output_bit = HRTIM_OENR_TE1OEN; + } + break; + case HRTIM_OUTPUT_TE2: + { + output_bit = HRTIM_OENR_TE2OEN; + } + break; + default: + break; + } + + if ((HRTIMx->HRTIM_COMMON.OENR & output_bit) != RESET) + { + /* Output is enabled: output in RUN state (whatever output disable status is)*/ + output_state = HRTIM_OUTPUTSTATE_RUN; + } + else + { + if ((HRTIMx->HRTIM_COMMON.ODSR & output_bit) != RESET) + { + /* Output is disabled: output in FAULT state */ + output_state = HRTIM_OUTPUTSTATE_FAULT; + } + else + { + /* Output is disabled: output in IDLE state */ + output_state = HRTIM_OUTPUTSTATE_IDLE; + } + } + + return(output_state); +} + +/** + * @brief Returns the level (active or inactive) of the designated output + * when the delayed protection was triggered + * @param HRTIMx: pointer to HRTIMx peripheral + * @param TimerIdx: Timer index + * This parameter can be one of the following values: + * @arg 0x0 to 0x4 for timers A to E + * @param Output: Timer output + * This parameter can be one of the following values: + * @arg HRTIM_OUTPUT_TA1: Timer A - Output 1 + * @arg HRTIM_OUTPUT_TA2: Timer A - Output 2 + * @arg HRTIM_OUTPUT_TB1: Timer B - Output 1 + * @arg HRTIM_OUTPUT_TB2: Timer B - Output 2 + * @arg HRTIM_OUTPUT_TC1: Timer C - Output 1 + * @arg HRTIM_OUTPUT_TC2: Timer C - Output 2 + * @arg HRTIM_OUTPUT_TD1: Timer D - Output 1 + * @arg HRTIM_OUTPUT_TD2: Timer D - Output 2 + * @arg HRTIM_OUTPUT_TD1: Timer E - Output 1 + * @arg HRTIM_OUTPUT_TD2: Timer E - Output 2 + * @retval Delayed protection status + */ +uint32_t HRTIM_GetDelayedProtectionStatus(HRTIM_TypeDef * HRTIMx, + uint32_t TimerIdx, + uint32_t Output) +{ + uint32_t delayed_protection_status = HRTIM_OUTPUTLEVEL_INACTIVE; + + /* Check parameters */ + assert_param(IS_HRTIM_TIMER_OUTPUT(TimerIdx, Output)); + + /* Read the delayed protection status */ + switch (Output) + { + case HRTIM_OUTPUT_TA1: + case HRTIM_OUTPUT_TB1: + case HRTIM_OUTPUT_TC1: + case HRTIM_OUTPUT_TD1: + case HRTIM_OUTPUT_TE1: + { + if ((HRTIMx->HRTIM_TIMERx[TimerIdx].TIMxISR & HRTIM_TIMISR_O1STAT) != RESET) + { + /* Output 1 was active when the delayed idle protection was triggered */ + delayed_protection_status = HRTIM_OUTPUTLEVEL_ACTIVE; + } + else + { + /* Output 1 was inactive when the delayed idle protection was triggered */ + delayed_protection_status = HRTIM_OUTPUTLEVEL_INACTIVE; + } + } + break; + case HRTIM_OUTPUT_TA2: + case HRTIM_OUTPUT_TB2: + case HRTIM_OUTPUT_TC2: + case HRTIM_OUTPUT_TD2: + case HRTIM_OUTPUT_TE2: + { + if ((HRTIMx->HRTIM_TIMERx[TimerIdx].TIMxISR & HRTIM_TIMISR_O2STAT) != RESET) + { + /* Output 2 was active when the delayed idle protection was triggered */ + delayed_protection_status = HRTIM_OUTPUTLEVEL_ACTIVE; + } + else + { + /* Output 2 was inactive when the delayed idle protection was triggered */ + delayed_protection_status = HRTIM_OUTPUTLEVEL_INACTIVE; + } + } + break; + default: + break; + } + + return delayed_protection_status; +} + +/** + * @brief Returns the actual status (active or inactive) of the burst mode controller + * @param HRTIMx: pointer to HRTIMx peripheral + * @retval Burst mode controller status + */ +uint32_t HRTIM_GetBurstStatus(HRTIM_TypeDef * HRTIMx) +{ + uint32_t burst_mode_status; + + /* Read burst mode status */ + burst_mode_status = (HRTIMx->HRTIM_COMMON.BMCR & HRTIM_BMCR_BMSTAT); + + return burst_mode_status; +} + +/** + * @brief Indicates on which output the signal is currently active (when the + * push pull mode is enabled) + * @param HRTIMx: pointer to HRTIMx peripheral + * @param TimerIdx: Timer index + * This parameter can be one of the following values: + * @arg 0x0 to 0x4 for timers A to E + * @retval Burst mode controller status + */ +uint32_t HRTIM_GetCurrentPushPullStatus(HRTIM_TypeDef * HRTIMx, + uint32_t TimerIdx) +{ + uint32_t current_pushpull_status; + + /* Check the parameters */ + assert_param(IS_HRTIM_TIMING_UNIT(TimerIdx)); + + /* Read current push pull status */ + current_pushpull_status = (HRTIMx->HRTIM_TIMERx[TimerIdx].TIMxISR & HRTIM_TIMISR_CPPSTAT); + + return current_pushpull_status; +} + + +/** + * @brief Indicates on which output the signal was applied, in push-pull mode + balanced fault mode or delayed idle mode, when the protection was triggered + * @param HRTIMx: pointer to HRTIMx peripheral + * @param TimerIdx: Timer index + * This parameter can be one of the following values: + * @arg 0x0 to 0x4 for timers A to E + * @retval Idle Push Pull Status + */ +uint32_t HRTIM_GetIdlePushPullStatus(HRTIM_TypeDef * HRTIMx, + uint32_t TimerIdx) +{ + uint32_t idle_pushpull_status; + + /* Check the parameters */ + assert_param(IS_HRTIM_TIMING_UNIT(TimerIdx)); + + /* Read current push pull status */ + idle_pushpull_status = (HRTIMx->HRTIM_TIMERx[TimerIdx].TIMxISR & HRTIM_TIMISR_IPPSTAT); + + return idle_pushpull_status; +} + +/** + * @brief Configures the master timer time base + * @param HRTIMx: pointer to HRTIMx peripheral + * @retval None + */ +void HRTIM_MasterBase_Config(HRTIM_TypeDef * HRTIMx, HRTIM_BaseInitTypeDef* HRTIM_BaseInitStruct) +{ + /* Set the prescaler ratio */ + HRTIMx->HRTIM_MASTER.MCR &= (uint32_t) ~(HRTIM_MCR_CK_PSC); + HRTIMx->HRTIM_MASTER.MCR |= (uint32_t)HRTIM_BaseInitStruct->PrescalerRatio; + + /* Set the operating mode */ + HRTIMx->HRTIM_MASTER.MCR &= (uint32_t) ~(HRTIM_MCR_CONT | HRTIM_MCR_RETRIG); + HRTIMx->HRTIM_MASTER.MCR |= (uint32_t)HRTIM_BaseInitStruct->Mode; + + /* Update the HRTIMx registers */ + HRTIMx->HRTIM_MASTER.MPER = HRTIM_BaseInitStruct->Period; + HRTIMx->HRTIM_MASTER.MREP = HRTIM_BaseInitStruct->RepetitionCounter; +} + +/** + * @brief Configures timing unit (timer A to timer E) time base + * @param HRTIMx: pointer to HRTIMx peripheral + * @param TimerIdx: Timer index + * @retval None + */ +void HRTIM_TimingUnitBase_Config(HRTIM_TypeDef * HRTIMx, uint32_t TimerIdx, HRTIM_BaseInitTypeDef* HRTIM_BaseInitStruct) +{ + /* Set the prescaler ratio */ + HRTIMx->HRTIM_TIMERx[TimerIdx].TIMxCR &= (uint32_t) ~(HRTIM_TIMCR_CK_PSC); + HRTIMx->HRTIM_TIMERx[TimerIdx].TIMxCR |= (uint32_t)HRTIM_BaseInitStruct->PrescalerRatio; + + /* Set the operating mode */ + HRTIMx->HRTIM_TIMERx[TimerIdx].TIMxCR &= (uint32_t) ~(HRTIM_TIMCR_CONT | HRTIM_TIMCR_RETRIG); + HRTIMx->HRTIM_TIMERx[TimerIdx].TIMxCR |= (uint32_t)HRTIM_BaseInitStruct->Mode; + + /* Update the HRTIMx registers */ + HRTIMx->HRTIM_TIMERx[TimerIdx].PERxR = HRTIM_BaseInitStruct->Period; + HRTIMx->HRTIM_TIMERx[TimerIdx].REPxR = HRTIM_BaseInitStruct->RepetitionCounter; +} + +/** + * @brief Configures the master timer in waveform mode + * @param HRTIMx: pointer to HRTIMx peripheral + * @param TimerIdx: Timer index + * @param pTimerInit: pointer to the timer initialization data structure + * @retval None + */ +void HRTIM_MasterWaveform_Config(HRTIM_TypeDef * HRTIMx, + HRTIM_TimerInitTypeDef * pTimerInit) +{ + uint32_t HRTIM_mcr; + uint32_t HRTIM_bmcr; + + /* Configure master timer */ + HRTIM_mcr = HRTIMx->HRTIM_MASTER.MCR; + HRTIM_bmcr = HRTIMx->HRTIM_COMMON.BMCR; + + /* Enable/Disable the half mode */ + HRTIM_mcr &= ~(HRTIM_MCR_HALF); + HRTIM_mcr |= pTimerInit->HalfModeEnable; + + /* Enable/Disable the timer start upon synchronization event reception */ + HRTIM_mcr &= ~(HRTIM_MCR_SYNCSTRTM); + HRTIM_mcr |= pTimerInit->StartOnSync; + + /* Enable/Disable the timer reset upon synchronization event reception */ + HRTIM_mcr &= ~(HRTIM_MCR_SYNCRSTM); + HRTIM_mcr |= pTimerInit->ResetOnSync; + + /* Enable/Disable the DAC synchronization event generation */ + HRTIM_mcr &= ~(HRTIM_MCR_DACSYNC); + HRTIM_mcr |= pTimerInit->DACSynchro; + + /* Enable/Disable preload mechanism for timer registers */ + HRTIM_mcr &= ~(HRTIM_MCR_PREEN); + HRTIM_mcr |= pTimerInit->PreloadEnable; + + /* Master timer registers update handling */ + HRTIM_mcr &= ~(HRTIM_MCR_BRSTDMA); + HRTIM_mcr |= (pTimerInit->UpdateGating << 2); + + /* Enable/Disable registers update on repetition */ + HRTIM_mcr &= ~(HRTIM_MCR_MREPU); + HRTIM_mcr |= pTimerInit->RepetitionUpdate; + + /* Set the timer burst mode */ + HRTIM_bmcr &= ~(HRTIM_BMCR_MTBM); + HRTIM_bmcr |= pTimerInit->BurstMode; + + /* Update the HRTIMx registers */ + HRTIMx->HRTIM_MASTER.MCR = HRTIM_mcr; + HRTIMx->HRTIM_COMMON.BMCR = HRTIM_bmcr; + +} + +/** + * @brief Configures timing unit (timer A to timer E) in waveform mode + * @param HRTIMx: pointer to HRTIMx peripheral + * @param TimerIdx: Timer index + * @param pTimerInit: pointer to the timer initialization data structure + * @retval None + */ +void HRTIM_TimingUnitWaveform_Config(HRTIM_TypeDef * HRTIMx, + uint32_t TimerIdx, + HRTIM_TimerInitTypeDef * pTimerInit) +{ + uint32_t HRTIM_timcr; + uint32_t HRTIM_bmcr; + + /* Configure timing unit */ + HRTIM_timcr = HRTIMx->HRTIM_TIMERx[TimerIdx].TIMxCR; + HRTIM_bmcr = HRTIMx->HRTIM_COMMON.BMCR; + + /* Enable/Disable the half mode */ + HRTIM_timcr &= ~(HRTIM_TIMCR_HALF); + HRTIM_timcr |= pTimerInit->HalfModeEnable; + + /* Enable/Disable the timer start upon synchronization event reception */ + HRTIM_timcr &= ~(HRTIM_TIMCR_SYNCSTRT); + HRTIM_timcr |= pTimerInit->StartOnSync; + + /* Enable/Disable the timer reset upon synchronization event reception */ + HRTIM_timcr &= ~(HRTIM_TIMCR_SYNCRST); + HRTIM_timcr |= pTimerInit->ResetOnSync; + + /* Enable/Disable the DAC synchronization event generation */ + HRTIM_timcr &= ~(HRTIM_TIMCR_DACSYNC); + HRTIM_timcr |= pTimerInit->DACSynchro; + + /* Enable/Disable preload mechanism for timer registers */ + HRTIM_timcr &= ~(HRTIM_TIMCR_PREEN); + HRTIM_timcr |= pTimerInit->PreloadEnable; + + /* Timing unit registers update handling */ + HRTIM_timcr &= ~(HRTIM_TIMCR_UPDGAT); + HRTIM_timcr |= pTimerInit->UpdateGating; + + /* Enable/Disable registers update on repetition */ + HRTIM_timcr &= ~(HRTIM_TIMCR_TREPU); + if (pTimerInit->RepetitionUpdate == HRTIM_UPDATEONREPETITION_ENABLED) + { + HRTIM_timcr |= HRTIM_TIMCR_TREPU; + } + + /* Set the timer burst mode */ + switch (TimerIdx) + { + case HRTIM_TIMERINDEX_TIMER_A: + { + HRTIM_bmcr &= ~(HRTIM_BMCR_TABM); + HRTIM_bmcr |= ( pTimerInit->BurstMode << 1); + } + break; + case HRTIM_TIMERINDEX_TIMER_B: + { + HRTIM_bmcr &= ~(HRTIM_BMCR_TBBM); + HRTIM_bmcr |= ( pTimerInit->BurstMode << 2); + } + break; + case HRTIM_TIMERINDEX_TIMER_C: + { + HRTIM_bmcr &= ~(HRTIM_BMCR_TCBM); + HRTIM_bmcr |= ( pTimerInit->BurstMode << 3); + } + break; + case HRTIM_TIMERINDEX_TIMER_D: + { + HRTIM_bmcr &= ~(HRTIM_BMCR_TDBM); + HRTIM_bmcr |= ( pTimerInit->BurstMode << 4); + } + break; + case HRTIM_TIMERINDEX_TIMER_E: + { + HRTIM_bmcr &= ~(HRTIM_BMCR_TEBM); + HRTIM_bmcr |= ( pTimerInit->BurstMode << 5); + } + break; + default: + break; + } + + /* Update the HRTIMx registers */ + HRTIMx->HRTIM_TIMERx[TimerIdx].TIMxCR = HRTIM_timcr; + HRTIMx->HRTIM_COMMON.BMCR = HRTIM_bmcr; +} + +/** + * @brief Configures a compare unit + * @param HRTIMx: pointer to HRTIMx peripheral + * @param TimerIdx: Timer index + * @param CompareUnit: Compare unit identifier + * @param pCompareCfg: pointer to the compare unit configuration data structure + * @retval None + */ +void HRTIM_CompareUnitConfig(HRTIM_TypeDef * HRTIMx, + uint32_t TimerIdx, + uint32_t CompareUnit, + HRTIM_CompareCfgTypeDef * pCompareCfg) +{ + if (TimerIdx == HRTIM_TIMERINDEX_MASTER) + { + /* Configure the compare unit of the master timer */ + switch (CompareUnit) + { + case HRTIM_COMPAREUNIT_1: + { + HRTIMx->HRTIM_MASTER.MCMP1R = pCompareCfg->CompareValue; + } + break; + case HRTIM_COMPAREUNIT_2: + { + HRTIMx->HRTIM_MASTER.MCMP2R = pCompareCfg->CompareValue; + } + break; + case HRTIM_COMPAREUNIT_3: + { + HRTIMx->HRTIM_MASTER.MCMP3R = pCompareCfg->CompareValue; + } + break; + case HRTIM_COMPAREUNIT_4: + { + HRTIMx->HRTIM_MASTER.MCMP4R = pCompareCfg->CompareValue; + } + break; + default: + break; + } + } + else + { + /* Configure the compare unit of the timing unit */ + switch (CompareUnit) + { + case HRTIM_COMPAREUNIT_1: + { + HRTIMx->HRTIM_TIMERx[TimerIdx].CMP1xR = pCompareCfg->CompareValue; + } + break; + case HRTIM_COMPAREUNIT_2: + { + HRTIMx->HRTIM_TIMERx[TimerIdx].CMP2xR = pCompareCfg->CompareValue; + } + break; + case HRTIM_COMPAREUNIT_3: + { + HRTIMx->HRTIM_TIMERx[TimerIdx].CMP3xR = pCompareCfg->CompareValue; + } + break; + case HRTIM_COMPAREUNIT_4: + { + HRTIMx->HRTIM_TIMERx[TimerIdx].CMP4xR = pCompareCfg->CompareValue; + } + break; + default: + break; + } + } +} + +/** + * @brief Configures a capture unit + * @param HRTIMx: pointer to HRTIMx peripheral + * @param TimerIdx: Timer index + * @param CaptureUnit: Capture unit identifier + * @param pCaptureCfg: pointer to the compare unit configuration data structure + * @retval None + */ +void HRTIM_CaptureUnitConfig(HRTIM_TypeDef * HRTIMx, + uint32_t TimerIdx, + uint32_t CaptureUnit, + uint32_t Event) +{ + uint32_t CaptureTrigger = HRTIM_CAPTURETRIGGER_EEV_1; + + switch (Event) + { + case HRTIM_EVENT_1: + { + CaptureTrigger = HRTIM_CAPTURETRIGGER_EEV_1; + } + break; + case HRTIM_EVENT_2: + { + CaptureTrigger = HRTIM_CAPTURETRIGGER_EEV_2; + } + break; + case HRTIM_EVENT_3: + { + CaptureTrigger = HRTIM_CAPTURETRIGGER_EEV_3; + } + break; + case HRTIM_EVENT_4: + { + CaptureTrigger = HRTIM_CAPTURETRIGGER_EEV_4; + } + break; + case HRTIM_EVENT_5: + { + CaptureTrigger = HRTIM_CAPTURETRIGGER_EEV_5; + } + break; + case HRTIM_EVENT_6: + { + CaptureTrigger = HRTIM_CAPTURETRIGGER_EEV_6; + } + break; + case HRTIM_EVENT_7: + { + CaptureTrigger = HRTIM_CAPTURETRIGGER_EEV_7; + } + break; + case HRTIM_EVENT_8: + { + CaptureTrigger = HRTIM_CAPTURETRIGGER_EEV_8; + } + break; + case HRTIM_EVENT_9: + { + CaptureTrigger = HRTIM_CAPTURETRIGGER_EEV_9; + } + break; + case HRTIM_EVENT_10: + { + CaptureTrigger = HRTIM_CAPTURETRIGGER_EEV_10; + } + break; + default: + break; + + } + switch (CaptureUnit) + { + case HRTIM_CAPTUREUNIT_1: + { + HRTIMx->HRTIM_TIMERx[TimerIdx].CPT1xCR = CaptureTrigger; + } + break; + case HRTIM_CAPTUREUNIT_2: + { + HRTIMx->HRTIM_TIMERx[TimerIdx].CPT2xCR = CaptureTrigger; + } + break; + default: + break; + } +} + +/** + * @brief Configures the output of a timing unit + * @param HRTIMx: pointer to HRTIMx peripheral + * @param TimerIdx: Timer index + * @param Output: timing unit output identifier + * @param pOutputCfg: pointer to the output configuration data structure + * @retval None + */ +void HRTIM_OutputConfig(HRTIM_TypeDef * HRTIMx, + uint32_t TimerIdx, + uint32_t Output, + HRTIM_OutputCfgTypeDef * pOutputCfg) +{ + uint32_t HRTIM_outr; + uint32_t shift = 0; + + HRTIM_outr = HRTIMx->HRTIM_TIMERx[TimerIdx].OUTxR; + + switch (Output) + { + case HRTIM_OUTPUT_TA1: + case HRTIM_OUTPUT_TB1: + case HRTIM_OUTPUT_TC1: + case HRTIM_OUTPUT_TD1: + case HRTIM_OUTPUT_TE1: + { + /* Set the output set/reset crossbar */ + HRTIMx->HRTIM_TIMERx[TimerIdx].SETx1R = pOutputCfg->SetSource; + HRTIMx->HRTIM_TIMERx[TimerIdx].RSTx1R = pOutputCfg->ResetSource; + + shift = 0; + } + break; + case HRTIM_OUTPUT_TA2: + case HRTIM_OUTPUT_TB2: + case HRTIM_OUTPUT_TC2: + case HRTIM_OUTPUT_TD2: + case HRTIM_OUTPUT_TE2: + { + /* Set the output set/reset crossbar */ + HRTIMx->HRTIM_TIMERx[TimerIdx].SETx2R = pOutputCfg->SetSource; + HRTIMx->HRTIM_TIMERx[TimerIdx].RSTx2R = pOutputCfg->ResetSource; + + shift = 16; + } + break; + default: + break; + } + + /* Clear output config */ + HRTIM_outr &= ~((HRTIM_OUTR_POL1 | + HRTIM_OUTR_IDLM1 | + HRTIM_OUTR_IDLES1| + HRTIM_OUTR_FAULT1| + HRTIM_OUTR_CHP1 | + HRTIM_OUTR_DIDL1) << shift); + + /* Set the polarity */ + HRTIM_outr |= (pOutputCfg->Polarity << shift); + + /* Set the IDLE mode */ + HRTIM_outr |= (pOutputCfg->IdleMode << shift); + + /* Set the IDLE state */ + HRTIM_outr |= (pOutputCfg->IdleState << shift); + + /* Set the FAULT state */ + HRTIM_outr |= (pOutputCfg->FaultState << shift); + + /* Set the chopper mode */ + HRTIM_outr |= (pOutputCfg->ChopperModeEnable << shift); + + /* Set the burst mode entry mode */ + HRTIM_outr |= (pOutputCfg->BurstModeEntryDelayed << shift); + + /* Update HRTIMx register */ + HRTIMx->HRTIM_TIMERx[TimerIdx].OUTxR = HRTIM_outr; +} + +/** + * @brief Configures an external event channel + * @param HRTIMx: pointer to HRTIMx peripheral + * @param Event: Event channel identifier + * @param pEventCfg: pointer to the event channel configuration data structure + * @retval None + */ +static void HRTIM_ExternalEventConfig(HRTIM_TypeDef * HRTIMx, + uint32_t Event, + HRTIM_EventCfgTypeDef *pEventCfg) +{ + uint32_t hrtim_eecr1; + uint32_t hrtim_eecr2; + uint32_t hrtim_eecr3; + + /* Configure external event channel */ + hrtim_eecr1 = HRTIMx->HRTIM_COMMON.EECR1; + hrtim_eecr2 = HRTIMx->HRTIM_COMMON.EECR2; + hrtim_eecr3 = HRTIMx->HRTIM_COMMON.EECR3; + + switch (Event) + { + case HRTIM_EVENT_1: + { + hrtim_eecr1 &= ~(HRTIM_EECR1_EE1SRC | HRTIM_EECR1_EE1POL | HRTIM_EECR1_EE1SNS | HRTIM_EECR1_EE1FAST); + hrtim_eecr1 |= pEventCfg->Source; + hrtim_eecr1 |= pEventCfg->Polarity; + hrtim_eecr1 |= pEventCfg->Sensitivity; + /* Update the HRTIM registers (all bit fields but EE1FAST bit) */ + HRTIMx->HRTIM_COMMON.EECR1 = hrtim_eecr1; + /* Update the HRTIM registers (EE1FAST bit) */ + hrtim_eecr1 |= pEventCfg->FastMode; + HRTIMx->HRTIM_COMMON.EECR1 = hrtim_eecr1; + } + break; + case HRTIM_EVENT_2: + { + hrtim_eecr1 &= ~(HRTIM_EECR1_EE2SRC | HRTIM_EECR1_EE2POL | HRTIM_EECR1_EE2SNS | HRTIM_EECR1_EE2FAST); + hrtim_eecr1 |= (pEventCfg->Source << 6); + hrtim_eecr1 |= (pEventCfg->Polarity << 6); + hrtim_eecr1 |= (pEventCfg->Sensitivity << 6); + /* Update the HRTIM registers (all bit fields but EE2FAST bit) */ + HRTIMx->HRTIM_COMMON.EECR1 = hrtim_eecr1; + /* Update the HRTIM registers (EE2FAST bit) */ + hrtim_eecr1 |= (pEventCfg->FastMode << 6); + HRTIMx->HRTIM_COMMON.EECR1 = hrtim_eecr1; + } + break; + case HRTIM_EVENT_3: + { + hrtim_eecr1 &= ~(HRTIM_EECR1_EE3SRC | HRTIM_EECR1_EE3POL | HRTIM_EECR1_EE3SNS | HRTIM_EECR1_EE3FAST); + hrtim_eecr1 |= (pEventCfg->Source << 12); + hrtim_eecr1 |= (pEventCfg->Polarity << 12); + hrtim_eecr1 |= (pEventCfg->Sensitivity << 12); + /* Update the HRTIM registers (all bit fields but EE3FAST bit) */ + HRTIMx->HRTIM_COMMON.EECR1 = hrtim_eecr1; + /* Update the HRTIM registers (EE3FAST bit) */ + hrtim_eecr1 |= (pEventCfg->FastMode << 12); + HRTIMx->HRTIM_COMMON.EECR1 = hrtim_eecr1; + } + break; + case HRTIM_EVENT_4: + { + hrtim_eecr1 &= ~(HRTIM_EECR1_EE4SRC | HRTIM_EECR1_EE4POL | HRTIM_EECR1_EE4SNS | HRTIM_EECR1_EE4FAST); + hrtim_eecr1 |= (pEventCfg->Source << 18); + hrtim_eecr1 |= (pEventCfg->Polarity << 18); + hrtim_eecr1 |= (pEventCfg->Sensitivity << 18); + /* Update the HRTIM registers (all bit fields but EE4FAST bit) */ + HRTIMx->HRTIM_COMMON.EECR1 = hrtim_eecr1; + /* Update the HRTIM registers (EE4FAST bit) */ + hrtim_eecr1 |= (pEventCfg->FastMode << 18); + HRTIMx->HRTIM_COMMON.EECR1 = hrtim_eecr1; + } + break; + case HRTIM_EVENT_5: + { + hrtim_eecr1 &= ~(HRTIM_EECR1_EE5SRC | HRTIM_EECR1_EE5POL | HRTIM_EECR1_EE5SNS | HRTIM_EECR1_EE5FAST); + hrtim_eecr1 |= (pEventCfg->Source << 24); + hrtim_eecr1 |= (pEventCfg->Polarity << 24); + hrtim_eecr1 |= (pEventCfg->Sensitivity << 24); + /* Update the HRTIM registers (all bit fields but EE5FAST bit) */ + HRTIMx->HRTIM_COMMON.EECR1 = hrtim_eecr1; + /* Update the HRTIM registers (EE5FAST bit) */ + hrtim_eecr1 |= (pEventCfg->FastMode << 24); + HRTIMx->HRTIM_COMMON.EECR1 = hrtim_eecr1; + } + break; + case HRTIM_EVENT_6: + { + hrtim_eecr2 &= ~(HRTIM_EECR2_EE6SRC | HRTIM_EECR2_EE6POL | HRTIM_EECR2_EE6SNS); + hrtim_eecr2 |= pEventCfg->Source; + hrtim_eecr2 |= pEventCfg->Polarity; + hrtim_eecr2 |= pEventCfg->Sensitivity; + hrtim_eecr3 &= ~(HRTIM_EECR3_EE6F); + hrtim_eecr3 |= pEventCfg->Filter; + /* Update the HRTIM registers */ + HRTIMx->HRTIM_COMMON.EECR2 = hrtim_eecr2; + HRTIMx->HRTIM_COMMON.EECR3 = hrtim_eecr3; + } + break; + case HRTIM_EVENT_7: + { + hrtim_eecr2 &= ~(HRTIM_EECR2_EE7SRC | HRTIM_EECR2_EE7POL | HRTIM_EECR2_EE7SNS); + hrtim_eecr2 |= (pEventCfg->Source << 6); + hrtim_eecr2 |= (pEventCfg->Polarity << 6); + hrtim_eecr2 |= (pEventCfg->Sensitivity << 6); + hrtim_eecr3 &= ~(HRTIM_EECR3_EE7F); + hrtim_eecr3 |= (pEventCfg->Filter << 6); + /* Update the HRTIM registers */ + HRTIMx->HRTIM_COMMON.EECR2 = hrtim_eecr2; + HRTIMx->HRTIM_COMMON.EECR3 = hrtim_eecr3; + } + break; + case HRTIM_EVENT_8: + { + hrtim_eecr2 &= ~(HRTIM_EECR2_EE8SRC | HRTIM_EECR2_EE8POL | HRTIM_EECR2_EE8SNS); + hrtim_eecr2 |= (pEventCfg->Source << 12); + hrtim_eecr2 |= (pEventCfg->Polarity << 12); + hrtim_eecr2 |= (pEventCfg->Sensitivity << 12); + hrtim_eecr3 &= ~(HRTIM_EECR3_EE8F); + hrtim_eecr3 |= (pEventCfg->Filter << 12); + /* Update the HRTIM registers */ + HRTIMx->HRTIM_COMMON.EECR2 = hrtim_eecr2; + HRTIMx->HRTIM_COMMON.EECR3 = hrtim_eecr3; + } + break; + case HRTIM_EVENT_9: + { + hrtim_eecr2 &= ~(HRTIM_EECR2_EE9SRC | HRTIM_EECR2_EE9POL | HRTIM_EECR2_EE9SNS); + hrtim_eecr2 |= (pEventCfg->Source << 18); + hrtim_eecr2 |= (pEventCfg->Polarity << 18); + hrtim_eecr2 |= (pEventCfg->Sensitivity << 18); + hrtim_eecr3 &= ~(HRTIM_EECR3_EE9F); + hrtim_eecr3 |= (pEventCfg->Filter << 18); + /* Update the HRTIM registers */ + HRTIMx->HRTIM_COMMON.EECR2 = hrtim_eecr2; + HRTIMx->HRTIM_COMMON.EECR3 = hrtim_eecr3; + } + break; + case HRTIM_EVENT_10: + { + hrtim_eecr2 &= ~(HRTIM_EECR2_EE10SRC | HRTIM_EECR2_EE10POL | HRTIM_EECR2_EE10SNS); + hrtim_eecr2 |= (pEventCfg->Source << 24); + hrtim_eecr2 |= (pEventCfg->Polarity << 24); + hrtim_eecr2 |= (pEventCfg->Sensitivity << 24); + hrtim_eecr3 &= ~(HRTIM_EECR3_EE10F); + hrtim_eecr3 |= (pEventCfg->Filter << 24); + /* Update the HRTIM registers */ + HRTIMx->HRTIM_COMMON.EECR2 = hrtim_eecr2; + HRTIMx->HRTIM_COMMON.EECR3 = hrtim_eecr3; + } + break; + default: + break; + } +} + +/** + * @brief Configures the timer counter reset + * @param HRTIMx: pointer to HRTIMx peripheral + * @param TimerIdx: Timer index + * @param Event: Event channel identifier + * @retval None + */ +void HRTIM_TIM_ResetConfig(HRTIM_TypeDef * HRTIMx, + uint32_t TimerIdx, + uint32_t Event) +{ + switch (Event) + { + case HRTIM_EVENT_1: + { + HRTIMx->HRTIM_TIMERx[TimerIdx].RSTxR = HRTIM_TIMRESETTRIGGER_EEV_1; + } + break; + case HRTIM_EVENT_2: + { + HRTIMx->HRTIM_TIMERx[TimerIdx].RSTxR = HRTIM_TIMRESETTRIGGER_EEV_2; + } + break; + case HRTIM_EVENT_3: + { + HRTIMx->HRTIM_TIMERx[TimerIdx].RSTxR = HRTIM_TIMRESETTRIGGER_EEV_3; + } + break; + case HRTIM_EVENT_4: + { + HRTIMx->HRTIM_TIMERx[TimerIdx].RSTxR = HRTIM_TIMRESETTRIGGER_EEV_4; + } + break; + case HRTIM_EVENT_5: + { + HRTIMx->HRTIM_TIMERx[TimerIdx].RSTxR = HRTIM_TIMRESETTRIGGER_EEV_5; + } + break; + case HRTIM_EVENT_6: + { + HRTIMx->HRTIM_TIMERx[TimerIdx].RSTxR = HRTIM_TIMRESETTRIGGER_EEV_6; + } + break; + case HRTIM_EVENT_7: + { + HRTIMx->HRTIM_TIMERx[TimerIdx].RSTxR = HRTIM_TIMRESETTRIGGER_EEV_7; + } + break; + case HRTIM_EVENT_8: + { + HRTIMx->HRTIM_TIMERx[TimerIdx].RSTxR = HRTIM_TIMRESETTRIGGER_EEV_8; + } + break; + case HRTIM_EVENT_9: + { + HRTIMx->HRTIM_TIMERx[TimerIdx].RSTxR = HRTIM_TIMRESETTRIGGER_EEV_9; + } + break; + case HRTIM_EVENT_10: + { + HRTIMx->HRTIM_TIMERx[TimerIdx].RSTxR = HRTIM_TIMRESETTRIGGER_EEV_10; + } + break; + default: + break; + } +} +/** + * @} + */ +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + + + diff --git a/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_i2c.c b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_i2c.c new file mode 100755 index 0000000000..f2f30eb7a4 --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_i2c.c @@ -0,0 +1,1585 @@ +/** + ****************************************************************************** + * @file stm32f30x_i2c.c + * @author MCD Application Team + * @version V1.2.3 + * @date 10-July-2015 + * @brief This file provides firmware functions to manage the following + * functionalities of the Inter-Integrated circuit (I2C): + * + Initialization and Configuration + * + Communications handling + * + SMBUS management + * + I2C registers management + * + Data transfers management + * + DMA transfers management + * + Interrupts and flags management + * + * @verbatim + ============================================================================ + ##### How to use this driver ##### + ============================================================================ + [..] + (#) Enable peripheral clock using RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2Cx, ENABLE) + function for I2C1 or I2C2. + (#) Enable SDA, SCL and SMBA (when used) GPIO clocks using + RCC_AHBPeriphClockCmd() function. + (#) Peripherals alternate function: + (++) Connect the pin to the desired peripherals' Alternate + Function (AF) using GPIO_PinAFConfig() function. + (++) Configure the desired pin in alternate function by: + GPIO_InitStruct->GPIO_Mode = GPIO_Mode_AF + (++) Select the type, OpenDrain and speed via + GPIO_PuPd, GPIO_OType and GPIO_Speed members + (++) Call GPIO_Init() function. + (#) Program the Mode, Timing , Own address, Ack and Acknowledged Address + using the I2C_Init() function. + (#) Optionally you can enable/configure the following parameters without + re-initialization (i.e there is no need to call again I2C_Init() function): + (++) Enable the acknowledge feature using I2C_AcknowledgeConfig() function. + (++) Enable the dual addressing mode using I2C_DualAddressCmd() function. + (++) Enable the general call using the I2C_GeneralCallCmd() function. + (++) Enable the clock stretching using I2C_StretchClockCmd() function. + (++) Enable the PEC Calculation using I2C_CalculatePEC() function. + (++) For SMBus Mode: + (+++) Enable the SMBusAlert pin using I2C_SMBusAlertCmd() function. + (#) Enable the NVIC and the corresponding interrupt using the function + I2C_ITConfig() if you need to use interrupt mode. + (#) When using the DMA mode + (++) Configure the DMA using DMA_Init() function. + (++) Active the needed channel Request using I2C_DMACmd() function. + (#) Enable the I2C using the I2C_Cmd() function. + (#) Enable the DMA using the DMA_Cmd() function when using DMA mode in the + transfers. + [..] + (@) When using I2C in Fast Mode Plus, SCL and SDA pin 20mA current drive capability + must be enabled by setting the driving capability control bit in SYSCFG. + + @endverbatim + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f30x_i2c.h" +#include "stm32f30x_rcc.h" + +/** @addtogroup STM32F30x_StdPeriph_Driver + * @{ + */ + +/** @defgroup I2C + * @brief I2C driver modules + * @{ + */ + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ + +#define CR1_CLEAR_MASK ((uint32_t)0x00CFE0FF) /*I2C_AnalogFilter)); + assert_param(IS_I2C_DIGITAL_FILTER(I2C_InitStruct->I2C_DigitalFilter)); + assert_param(IS_I2C_MODE(I2C_InitStruct->I2C_Mode)); + assert_param(IS_I2C_OWN_ADDRESS1(I2C_InitStruct->I2C_OwnAddress1)); + assert_param(IS_I2C_ACK(I2C_InitStruct->I2C_Ack)); + assert_param(IS_I2C_ACKNOWLEDGE_ADDRESS(I2C_InitStruct->I2C_AcknowledgedAddress)); + + /* Disable I2Cx Peripheral */ + I2Cx->CR1 &= (uint32_t)~((uint32_t)I2C_CR1_PE); + + /*---------------------------- I2Cx FILTERS Configuration ------------------*/ + /* Get the I2Cx CR1 value */ + tmpreg = I2Cx->CR1; + /* Clear I2Cx CR1 register */ + tmpreg &= CR1_CLEAR_MASK; + /* Configure I2Cx: analog and digital filter */ + /* Set ANFOFF bit according to I2C_AnalogFilter value */ + /* Set DFN bits according to I2C_DigitalFilter value */ + tmpreg |= (uint32_t)I2C_InitStruct->I2C_AnalogFilter |(I2C_InitStruct->I2C_DigitalFilter << 8); + + /* Write to I2Cx CR1 */ + I2Cx->CR1 = tmpreg; + + /*---------------------------- I2Cx TIMING Configuration -------------------*/ + /* Configure I2Cx: Timing */ + /* Set TIMINGR bits according to I2C_Timing */ + /* Write to I2Cx TIMING */ + I2Cx->TIMINGR = I2C_InitStruct->I2C_Timing & TIMING_CLEAR_MASK; + + /* Enable I2Cx Peripheral */ + I2Cx->CR1 |= I2C_CR1_PE; + + /*---------------------------- I2Cx OAR1 Configuration ---------------------*/ + /* Clear tmpreg local variable */ + tmpreg = 0; + /* Clear OAR1 register */ + I2Cx->OAR1 = (uint32_t)tmpreg; + /* Clear OAR2 register */ + I2Cx->OAR2 = (uint32_t)tmpreg; + /* Configure I2Cx: Own Address1 and acknowledged address */ + /* Set OA1MODE bit according to I2C_AcknowledgedAddress value */ + /* Set OA1 bits according to I2C_OwnAddress1 value */ + tmpreg = (uint32_t)((uint32_t)I2C_InitStruct->I2C_AcknowledgedAddress | \ + (uint32_t)I2C_InitStruct->I2C_OwnAddress1); + /* Write to I2Cx OAR1 */ + I2Cx->OAR1 = tmpreg; + /* Enable Own Address1 acknowledgement */ + I2Cx->OAR1 |= I2C_OAR1_OA1EN; + + /*---------------------------- I2Cx MODE Configuration ---------------------*/ + /* Configure I2Cx: mode */ + /* Set SMBDEN and SMBHEN bits according to I2C_Mode value */ + tmpreg = I2C_InitStruct->I2C_Mode; + /* Write to I2Cx CR1 */ + I2Cx->CR1 |= tmpreg; + + /*---------------------------- I2Cx ACK Configuration ----------------------*/ + /* Get the I2Cx CR2 value */ + tmpreg = I2Cx->CR2; + /* Clear I2Cx CR2 register */ + tmpreg &= CR2_CLEAR_MASK; + /* Configure I2Cx: acknowledgement */ + /* Set NACK bit according to I2C_Ack value */ + tmpreg |= I2C_InitStruct->I2C_Ack; + /* Write to I2Cx CR2 */ + I2Cx->CR2 = tmpreg; +} + +/** + * @brief Fills each I2C_InitStruct member with its default value. + * @param I2C_InitStruct: pointer to an I2C_InitTypeDef structure which will be initialized. + * @retval None + */ +void I2C_StructInit(I2C_InitTypeDef* I2C_InitStruct) +{ + /*---------------- Reset I2C init structure parameters values --------------*/ + /* Initialize the I2C_Timing member */ + I2C_InitStruct->I2C_Timing = 0; + /* Initialize the I2C_AnalogFilter member */ + I2C_InitStruct->I2C_AnalogFilter = I2C_AnalogFilter_Enable; + /* Initialize the I2C_DigitalFilter member */ + I2C_InitStruct->I2C_DigitalFilter = 0; + /* Initialize the I2C_Mode member */ + I2C_InitStruct->I2C_Mode = I2C_Mode_I2C; + /* Initialize the I2C_OwnAddress1 member */ + I2C_InitStruct->I2C_OwnAddress1 = 0; + /* Initialize the I2C_Ack member */ + I2C_InitStruct->I2C_Ack = I2C_Ack_Disable; + /* Initialize the I2C_AcknowledgedAddress member */ + I2C_InitStruct->I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; +} + +/** + * @brief Enables or disables the specified I2C peripheral. + * @param I2Cx: where x can be 1 or 2 to select the I2C peripheral. + * @param NewState: new state of the I2Cx peripheral. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void I2C_Cmd(I2C_TypeDef* I2Cx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_I2C_ALL_PERIPH(I2Cx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + if (NewState != DISABLE) + { + /* Enable the selected I2C peripheral */ + I2Cx->CR1 |= I2C_CR1_PE; + } + else + { + /* Disable the selected I2C peripheral */ + I2Cx->CR1 &= (uint32_t)~((uint32_t)I2C_CR1_PE); + } +} + + +/** + * @brief Enables or disables the specified I2C software reset. + * @param I2Cx: where x can be 1 or 2 to select the I2C peripheral. + * @retval None + */ +void I2C_SoftwareResetCmd(I2C_TypeDef* I2Cx) +{ + /* Check the parameters */ + assert_param(IS_I2C_ALL_PERIPH(I2Cx)); + + /* Disable peripheral */ + I2Cx->CR1 &= (uint32_t)~((uint32_t)I2C_CR1_PE); + + /* Perform a dummy read to delay the disable of peripheral for minimum + 3 APB clock cycles to perform the software reset functionality */ + *(__IO uint32_t *)(uint32_t)I2Cx; + + /* Enable peripheral */ + I2Cx->CR1 |= I2C_CR1_PE; +} + +/** + * @brief Enables or disables the specified I2C interrupts. + * @param I2Cx: where x can be 1 or 2 to select the I2C peripheral. + * @param I2C_IT: specifies the I2C interrupts sources to be enabled or disabled. + * This parameter can be any combination of the following values: + * @arg I2C_IT_ERRI: Error interrupt mask + * @arg I2C_IT_TCI: Transfer Complete interrupt mask + * @arg I2C_IT_STOPI: Stop Detection interrupt mask + * @arg I2C_IT_NACKI: Not Acknowledge received interrupt mask + * @arg I2C_IT_ADDRI: Address Match interrupt mask + * @arg I2C_IT_RXI: RX interrupt mask + * @arg I2C_IT_TXI: TX interrupt mask + * @param NewState: new state of the specified I2C interrupts. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void I2C_ITConfig(I2C_TypeDef* I2Cx, uint32_t I2C_IT, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_I2C_ALL_PERIPH(I2Cx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + assert_param(IS_I2C_CONFIG_IT(I2C_IT)); + + if (NewState != DISABLE) + { + /* Enable the selected I2C interrupts */ + I2Cx->CR1 |= I2C_IT; + } + else + { + /* Disable the selected I2C interrupts */ + I2Cx->CR1 &= (uint32_t)~((uint32_t)I2C_IT); + } +} + +/** + * @brief Enables or disables the I2C Clock stretching. + * @param I2Cx: where x can be 1 or 2 to select the I2C peripheral. + * @param NewState: new state of the I2Cx Clock stretching. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void I2C_StretchClockCmd(I2C_TypeDef* I2Cx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_I2C_ALL_PERIPH(I2Cx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable clock stretching */ + I2Cx->CR1 &= (uint32_t)~((uint32_t)I2C_CR1_NOSTRETCH); + } + else + { + /* Disable clock stretching */ + I2Cx->CR1 |= I2C_CR1_NOSTRETCH; + } +} + +/** + * @brief Enables or disables I2C wakeup from stop mode. + * @param I2Cx: where x can be 1 or 2 to select the I2C peripheral. + * @param NewState: new state of the I2Cx stop mode. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void I2C_StopModeCmd(I2C_TypeDef* I2Cx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_I2C_ALL_PERIPH(I2Cx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable wakeup from stop mode */ + I2Cx->CR1 |= I2C_CR1_WUPEN; + } + else + { + /* Disable wakeup from stop mode */ + I2Cx->CR1 &= (uint32_t)~((uint32_t)I2C_CR1_WUPEN); + } +} + +/** + * @brief Enables or disables the I2C own address 2. + * @param I2Cx: where x can be 1 or 2 to select the I2C peripheral. + * @param NewState: new state of the I2C own address 2. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void I2C_DualAddressCmd(I2C_TypeDef* I2Cx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_I2C_ALL_PERIPH(I2Cx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable own address 2 */ + I2Cx->OAR2 |= I2C_OAR2_OA2EN; + } + else + { + /* Disable own address 2 */ + I2Cx->OAR2 &= (uint32_t)~((uint32_t)I2C_OAR2_OA2EN); + } +} + +/** + * @brief Configures the I2C slave own address 2 and mask. + * @param I2Cx: where x can be 1 or 2 to select the I2C peripheral. + * @param Address: specifies the slave address to be programmed. + * @param Mask: specifies own address 2 mask to be programmed. + * This parameter can be one of the following values: + * @arg I2C_OA2_NoMask: no mask. + * @arg I2C_OA2_Mask01: OA2[1] is masked and don't care. + * @arg I2C_OA2_Mask02: OA2[2:1] are masked and don't care. + * @arg I2C_OA2_Mask03: OA2[3:1] are masked and don't care. + * @arg I2C_OA2_Mask04: OA2[4:1] are masked and don't care. + * @arg I2C_OA2_Mask05: OA2[5:1] are masked and don't care. + * @arg I2C_OA2_Mask06: OA2[6:1] are masked and don't care. + * @arg I2C_OA2_Mask07: OA2[7:1] are masked and don't care. + * @retval None + */ +void I2C_OwnAddress2Config(I2C_TypeDef* I2Cx, uint16_t Address, uint8_t Mask) +{ + uint32_t tmpreg = 0; + + /* Check the parameters */ + assert_param(IS_I2C_ALL_PERIPH(I2Cx)); + assert_param(IS_I2C_OWN_ADDRESS2(Address)); + assert_param(IS_I2C_OWN_ADDRESS2_MASK(Mask)); + + /* Get the old register value */ + tmpreg = I2Cx->OAR2; + + /* Reset I2Cx OA2 bit [7:1] and OA2MSK bit [1:0] */ + tmpreg &= (uint32_t)~((uint32_t)(I2C_OAR2_OA2 | I2C_OAR2_OA2MSK)); + + /* Set I2Cx SADD */ + tmpreg |= (uint32_t)(((uint32_t)Address & I2C_OAR2_OA2) | \ + (((uint32_t)Mask << 8) & I2C_OAR2_OA2MSK)) ; + + /* Store the new register value */ + I2Cx->OAR2 = tmpreg; +} + +/** + * @brief Enables or disables the I2C general call mode. + * @param I2Cx: where x can be 1 or 2 to select the I2C peripheral. + * @param NewState: new state of the I2C general call mode. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void I2C_GeneralCallCmd(I2C_TypeDef* I2Cx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_I2C_ALL_PERIPH(I2Cx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable general call mode */ + I2Cx->CR1 |= I2C_CR1_GCEN; + } + else + { + /* Disable general call mode */ + I2Cx->CR1 &= (uint32_t)~((uint32_t)I2C_CR1_GCEN); + } +} + +/** + * @brief Enables or disables the I2C slave byte control. + * @param I2Cx: where x can be 1 or 2 to select the I2C peripheral. + * @param NewState: new state of the I2C slave byte control. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void I2C_SlaveByteControlCmd(I2C_TypeDef* I2Cx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_I2C_ALL_PERIPH(I2Cx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable slave byte control */ + I2Cx->CR1 |= I2C_CR1_SBC; + } + else + { + /* Disable slave byte control */ + I2Cx->CR1 &= (uint32_t)~((uint32_t)I2C_CR1_SBC); + } +} + +/** + * @brief Configures the slave address to be transmitted after start generation. + * @param I2Cx: where x can be 1 or 2 to select the I2C peripheral. + * @param Address: specifies the slave address to be programmed. + * @note This function should be called before generating start condition. + * @retval None + */ +void I2C_SlaveAddressConfig(I2C_TypeDef* I2Cx, uint16_t Address) +{ + uint32_t tmpreg = 0; + + /* Check the parameters */ + assert_param(IS_I2C_ALL_PERIPH(I2Cx)); + assert_param(IS_I2C_SLAVE_ADDRESS(Address)); + + /* Get the old register value */ + tmpreg = I2Cx->CR2; + + /* Reset I2Cx SADD bit [9:0] */ + tmpreg &= (uint32_t)~((uint32_t)I2C_CR2_SADD); + + /* Set I2Cx SADD */ + tmpreg |= (uint32_t)((uint32_t)Address & I2C_CR2_SADD); + + /* Store the new register value */ + I2Cx->CR2 = tmpreg; +} + +/** + * @brief Enables or disables the I2C 10-bit addressing mode for the master. + * @param I2Cx: where x can be 1 or 2 to select the I2C peripheral. + * @param NewState: new state of the I2C 10-bit addressing mode. + * This parameter can be: ENABLE or DISABLE. + * @note This function should be called before generating start condition. + * @retval None + */ +void I2C_10BitAddressingModeCmd(I2C_TypeDef* I2Cx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_I2C_ALL_PERIPH(I2Cx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable 10-bit addressing mode */ + I2Cx->CR2 |= I2C_CR2_ADD10; + } + else + { + /* Disable 10-bit addressing mode */ + I2Cx->CR2 &= (uint32_t)~((uint32_t)I2C_CR2_ADD10); + } +} + +/** + * @} + */ + + +/** @defgroup I2C_Group2 Communications handling functions + * @brief Communications handling functions + * +@verbatim + =============================================================================== + ##### Communications handling functions ##### + =============================================================================== + [..] This section provides a set of functions that handles I2C communication. + + [..] Automatic End mode is enabled using I2C_AutoEndCmd() function. When Reload + mode is enabled via I2C_ReloadCmd() AutoEnd bit has no effect. + + [..] I2C_NumberOfBytesConfig() function set the number of bytes to be transferred, + this configuration should be done before generating start condition in master + mode. + + [..] When switching from master write operation to read operation in 10Bit addressing + mode, master can only sends the 1st 7 bits of the 10 bit address, followed by + Read direction by enabling HEADR bit using I2C_10BitAddressHeader() function. + + [..] In master mode, when transferring more than 255 bytes Reload mode should be used + to handle communication. In the first phase of transfer, Nbytes should be set to + 255. After transferring these bytes TCR flag is set and I2C_TransferHandling() + function should be called to handle remaining communication. + + [..] In master mode, when software end mode is selected when all data is transferred + TC flag is set I2C_TransferHandling() function should be called to generate STOP + or generate ReStart. + +@endverbatim + * @{ + */ + +/** + * @brief Enables or disables the I2C automatic end mode (stop condition is + * automatically sent when nbytes data are transferred). + * @param I2Cx: where x can be 1 or 2 to select the I2C peripheral. + * @param NewState: new state of the I2C automatic end mode. + * This parameter can be: ENABLE or DISABLE. + * @note This function has effect if Reload mode is disabled. + * @retval None + */ +void I2C_AutoEndCmd(I2C_TypeDef* I2Cx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_I2C_ALL_PERIPH(I2Cx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable Auto end mode */ + I2Cx->CR2 |= I2C_CR2_AUTOEND; + } + else + { + /* Disable Auto end mode */ + I2Cx->CR2 &= (uint32_t)~((uint32_t)I2C_CR2_AUTOEND); + } +} + +/** + * @brief Enables or disables the I2C nbytes reload mode. + * @param I2Cx: where x can be 1 or 2 to select the I2C peripheral. + * @param NewState: new state of the nbytes reload mode. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void I2C_ReloadCmd(I2C_TypeDef* I2Cx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_I2C_ALL_PERIPH(I2Cx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable Auto Reload mode */ + I2Cx->CR2 |= I2C_CR2_RELOAD; + } + else + { + /* Disable Auto Reload mode */ + I2Cx->CR2 &= (uint32_t)~((uint32_t)I2C_CR2_RELOAD); + } +} + +/** + * @brief Configures the number of bytes to be transmitted/received. + * @param I2Cx: where x can be 1 or 2 to select the I2C peripheral. + * @param Number_Bytes: specifies the number of bytes to be programmed. + * @retval None + */ +void I2C_NumberOfBytesConfig(I2C_TypeDef* I2Cx, uint8_t Number_Bytes) +{ + uint32_t tmpreg = 0; + + /* Check the parameters */ + assert_param(IS_I2C_ALL_PERIPH(I2Cx)); + + /* Get the old register value */ + tmpreg = I2Cx->CR2; + + /* Reset I2Cx Nbytes bit [7:0] */ + tmpreg &= (uint32_t)~((uint32_t)I2C_CR2_NBYTES); + + /* Set I2Cx Nbytes */ + tmpreg |= (uint32_t)(((uint32_t)Number_Bytes << 16 ) & I2C_CR2_NBYTES); + + /* Store the new register value */ + I2Cx->CR2 = tmpreg; +} + +/** + * @brief Configures the type of transfer request for the master. + * @param I2Cx: where x can be 1 or 2 to select the I2C peripheral. + * @param I2C_Direction: specifies the transfer request direction to be programmed. + * This parameter can be one of the following values: + * @arg I2C_Direction_Transmitter: Master request a write transfer + * @arg I2C_Direction_Receiver: Master request a read transfer + * @retval None + */ +void I2C_MasterRequestConfig(I2C_TypeDef* I2Cx, uint16_t I2C_Direction) +{ +/* Check the parameters */ + assert_param(IS_I2C_ALL_PERIPH(I2Cx)); + assert_param(IS_I2C_DIRECTION(I2C_Direction)); + + /* Test on the direction to set/reset the read/write bit */ + if (I2C_Direction == I2C_Direction_Transmitter) + { + /* Request a write Transfer */ + I2Cx->CR2 &= (uint32_t)~((uint32_t)I2C_CR2_RD_WRN); + } + else + { + /* Request a read Transfer */ + I2Cx->CR2 |= I2C_CR2_RD_WRN; + } +} + +/** + * @brief Generates I2Cx communication START condition. + * @param I2Cx: where x can be 1 or 2 to select the I2C peripheral. + * @param NewState: new state of the I2C START condition generation. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void I2C_GenerateSTART(I2C_TypeDef* I2Cx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_I2C_ALL_PERIPH(I2Cx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Generate a START condition */ + I2Cx->CR2 |= I2C_CR2_START; + } + else + { + /* Disable the START condition generation */ + I2Cx->CR2 &= (uint32_t)~((uint32_t)I2C_CR2_START); + } +} + +/** + * @brief Generates I2Cx communication STOP condition. + * @param I2Cx: where x can be 1 or 2 to select the I2C peripheral. + * @param NewState: new state of the I2C STOP condition generation. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void I2C_GenerateSTOP(I2C_TypeDef* I2Cx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_I2C_ALL_PERIPH(I2Cx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Generate a STOP condition */ + I2Cx->CR2 |= I2C_CR2_STOP; + } + else + { + /* Disable the STOP condition generation */ + I2Cx->CR2 &= (uint32_t)~((uint32_t)I2C_CR2_STOP); + } +} + +/** + * @brief Enables or disables the I2C 10-bit header only mode with read direction. + * @param I2Cx: where x can be 1 or 2 to select the I2C peripheral. + * @param NewState: new state of the I2C 10-bit header only mode. + * This parameter can be: ENABLE or DISABLE. + * @note This mode can be used only when switching from master transmitter mode + * to master receiver mode. + * @retval None + */ +void I2C_10BitAddressHeaderCmd(I2C_TypeDef* I2Cx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_I2C_ALL_PERIPH(I2Cx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable 10-bit header only mode */ + I2Cx->CR2 |= I2C_CR2_HEAD10R; + } + else + { + /* Disable 10-bit header only mode */ + I2Cx->CR2 &= (uint32_t)~((uint32_t)I2C_CR2_HEAD10R); + } +} + +/** + * @brief Generates I2C communication Acknowledge. + * @param I2Cx: where x can be 1 or 2 to select the I2C peripheral. + * @param NewState: new state of the Acknowledge. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void I2C_AcknowledgeConfig(I2C_TypeDef* I2Cx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_I2C_ALL_PERIPH(I2Cx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable ACK generation */ + I2Cx->CR2 &= (uint32_t)~((uint32_t)I2C_CR2_NACK); + } + else + { + /* Enable NACK generation */ + I2Cx->CR2 |= I2C_CR2_NACK; + } +} + +/** + * @brief Returns the I2C slave matched address . + * @param I2Cx: where x can be 1 or 2 to select the I2C peripheral. + * @retval The value of the slave matched address . + */ +uint8_t I2C_GetAddressMatched(I2C_TypeDef* I2Cx) +{ + /* Check the parameters */ + assert_param(IS_I2C_ALL_PERIPH(I2Cx)); + + /* Return the slave matched address in the SR1 register */ + return (uint8_t)(((uint32_t)I2Cx->ISR & I2C_ISR_ADDCODE) >> 16) ; +} + +/** + * @brief Returns the I2C slave received request. + * @param I2Cx: where x can be 1 or 2 to select the I2C peripheral. + * @retval The value of the received request. + */ +uint16_t I2C_GetTransferDirection(I2C_TypeDef* I2Cx) +{ + uint32_t tmpreg = 0; + uint16_t direction = 0; + + /* Check the parameters */ + assert_param(IS_I2C_ALL_PERIPH(I2Cx)); + + /* Return the slave matched address in the SR1 register */ + tmpreg = (uint32_t)(I2Cx->ISR & I2C_ISR_DIR); + + /* If write transfer is requested */ + if (tmpreg == 0) + { + /* write transfer is requested */ + direction = I2C_Direction_Transmitter; + } + else + { + /* Read transfer is requested */ + direction = I2C_Direction_Receiver; + } + return direction; +} + +/** + * @brief Handles I2Cx communication when starting transfer or during transfer (TC or TCR flag are set). + * @param I2Cx: where x can be 1 or 2 to select the I2C peripheral. + * @param Address: specifies the slave address to be programmed. + * @param Number_Bytes: specifies the number of bytes to be programmed. + * This parameter must be a value between 0 and 255. + * @param ReloadEndMode: new state of the I2C START condition generation. + * This parameter can be one of the following values: + * @arg I2C_Reload_Mode: Enable Reload mode . + * @arg I2C_AutoEnd_Mode: Enable Automatic end mode. + * @arg I2C_SoftEnd_Mode: Enable Software end mode. + * @param StartStopMode: new state of the I2C START condition generation. + * This parameter can be one of the following values: + * @arg I2C_No_StartStop: Don't Generate stop and start condition. + * @arg I2C_Generate_Stop: Generate stop condition (Number_Bytes should be set to 0). + * @arg I2C_Generate_Start_Read: Generate Restart for read request. + * @arg I2C_Generate_Start_Write: Generate Restart for write request. + * @retval None + */ +void I2C_TransferHandling(I2C_TypeDef* I2Cx, uint16_t Address, uint8_t Number_Bytes, uint32_t ReloadEndMode, uint32_t StartStopMode) +{ + uint32_t tmpreg = 0; + + /* Check the parameters */ + assert_param(IS_I2C_ALL_PERIPH(I2Cx)); + assert_param(IS_I2C_SLAVE_ADDRESS(Address)); + assert_param(IS_RELOAD_END_MODE(ReloadEndMode)); + assert_param(IS_START_STOP_MODE(StartStopMode)); + + /* Get the CR2 register value */ + tmpreg = I2Cx->CR2; + + /* clear tmpreg specific bits */ + tmpreg &= (uint32_t)~((uint32_t)(I2C_CR2_SADD | I2C_CR2_NBYTES | I2C_CR2_RELOAD | I2C_CR2_AUTOEND | I2C_CR2_RD_WRN | I2C_CR2_START | I2C_CR2_STOP)); + + /* update tmpreg */ + tmpreg |= (uint32_t)(((uint32_t)Address & I2C_CR2_SADD) | (((uint32_t)Number_Bytes << 16 ) & I2C_CR2_NBYTES) | \ + (uint32_t)ReloadEndMode | (uint32_t)StartStopMode); + + /* update CR2 register */ + I2Cx->CR2 = tmpreg; +} + +/** + * @} + */ + + +/** @defgroup I2C_Group3 SMBUS management functions + * @brief SMBUS management functions + * +@verbatim + =============================================================================== + ##### SMBUS management functions ##### + =============================================================================== + [..] This section provides a set of functions that handles SMBus communication + and timeouts detection. + + [..] The SMBus Device default address (0b1100 001) is enabled by calling I2C_Init() + function and setting I2C_Mode member of I2C_InitTypeDef() structure to + I2C_Mode_SMBusDevice. + + [..] The SMBus Host address (0b0001 000) is enabled by calling I2C_Init() + function and setting I2C_Mode member of I2C_InitTypeDef() structure to + I2C_Mode_SMBusHost. + + [..] The Alert Response Address (0b0001 100) is enabled using I2C_SMBusAlertCmd() + function. + + [..] To detect cumulative SCL stretch in master and slave mode, TIMEOUTB should be + configured (in accordance to SMBus specification) using I2C_TimeoutBConfig() + function then I2C_ExtendedClockTimeoutCmd() function should be called to enable + the detection. + + [..] SCL low timeout is detected by configuring TIMEOUTB using I2C_TimeoutBConfig() + function followed by the call of I2C_ClockTimeoutCmd(). When adding to this + procedure the call of I2C_IdleClockTimeoutCmd() function, Bus Idle condition + (both SCL and SDA high) is detected also. + +@endverbatim + * @{ + */ + +/** + * @brief Enables or disables I2C SMBus alert. + * @param I2Cx: where x can be 1 or 2 to select the I2C peripheral. + * @param NewState: new state of the I2Cx SMBus alert. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void I2C_SMBusAlertCmd(I2C_TypeDef* I2Cx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_I2C_ALL_PERIPH(I2Cx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable SMBus alert */ + I2Cx->CR1 |= I2C_CR1_ALERTEN; + } + else + { + /* Disable SMBus alert */ + I2Cx->CR1 &= (uint32_t)~((uint32_t)I2C_CR1_ALERTEN); + } +} + +/** + * @brief Enables or disables I2C Clock Timeout (SCL Timeout detection). + * @param I2Cx: where x can be 1 or 2 to select the I2C peripheral. + * @param NewState: new state of the I2Cx clock Timeout. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void I2C_ClockTimeoutCmd(I2C_TypeDef* I2Cx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_I2C_ALL_PERIPH(I2Cx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable Clock Timeout */ + I2Cx->TIMEOUTR |= I2C_TIMEOUTR_TIMOUTEN; + } + else + { + /* Disable Clock Timeout */ + I2Cx->TIMEOUTR &= (uint32_t)~((uint32_t)I2C_TIMEOUTR_TIMOUTEN); + } +} + +/** + * @brief Enables or disables I2C Extended Clock Timeout (SCL cumulative Timeout detection). + * @param I2Cx: where x can be 1 or 2 to select the I2C peripheral. + * @param NewState: new state of the I2Cx Extended clock Timeout. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void I2C_ExtendedClockTimeoutCmd(I2C_TypeDef* I2Cx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_I2C_ALL_PERIPH(I2Cx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable Clock Timeout */ + I2Cx->TIMEOUTR |= I2C_TIMEOUTR_TEXTEN; + } + else + { + /* Disable Clock Timeout */ + I2Cx->TIMEOUTR &= (uint32_t)~((uint32_t)I2C_TIMEOUTR_TEXTEN); + } +} + +/** + * @brief Enables or disables I2C Idle Clock Timeout (Bus idle SCL and SDA + * high detection). + * @param I2Cx: where x can be 1 or 2 to select the I2C peripheral. + * @param NewState: new state of the I2Cx Idle clock Timeout. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void I2C_IdleClockTimeoutCmd(I2C_TypeDef* I2Cx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_I2C_ALL_PERIPH(I2Cx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable Clock Timeout */ + I2Cx->TIMEOUTR |= I2C_TIMEOUTR_TIDLE; + } + else + { + /* Disable Clock Timeout */ + I2Cx->TIMEOUTR &= (uint32_t)~((uint32_t)I2C_TIMEOUTR_TIDLE); + } +} + +/** + * @brief Configures the I2C Bus Timeout A (SCL Timeout when TIDLE = 0 or Bus + * idle SCL and SDA high when TIDLE = 1). + * @param I2Cx: where x can be 1 or 2 to select the I2C peripheral. + * @param Timeout: specifies the TimeoutA to be programmed. + * @retval None + */ +void I2C_TimeoutAConfig(I2C_TypeDef* I2Cx, uint16_t Timeout) +{ + uint32_t tmpreg = 0; + + /* Check the parameters */ + assert_param(IS_I2C_ALL_PERIPH(I2Cx)); + assert_param(IS_I2C_TIMEOUT(Timeout)); + + /* Get the old register value */ + tmpreg = I2Cx->TIMEOUTR; + + /* Reset I2Cx TIMEOUTA bit [11:0] */ + tmpreg &= (uint32_t)~((uint32_t)I2C_TIMEOUTR_TIMEOUTA); + + /* Set I2Cx TIMEOUTA */ + tmpreg |= (uint32_t)((uint32_t)Timeout & I2C_TIMEOUTR_TIMEOUTA) ; + + /* Store the new register value */ + I2Cx->TIMEOUTR = tmpreg; +} + +/** + * @brief Configures the I2C Bus Timeout B (SCL cumulative Timeout). + * @param I2Cx: where x can be 1 or 2 to select the I2C peripheral. + * @param Timeout: specifies the TimeoutB to be programmed. + * @retval None + */ +void I2C_TimeoutBConfig(I2C_TypeDef* I2Cx, uint16_t Timeout) +{ + uint32_t tmpreg = 0; + + /* Check the parameters */ + assert_param(IS_I2C_ALL_PERIPH(I2Cx)); + assert_param(IS_I2C_TIMEOUT(Timeout)); + + /* Get the old register value */ + tmpreg = I2Cx->TIMEOUTR; + + /* Reset I2Cx TIMEOUTB bit [11:0] */ + tmpreg &= (uint32_t)~((uint32_t)I2C_TIMEOUTR_TIMEOUTB); + + /* Set I2Cx TIMEOUTB */ + tmpreg |= (uint32_t)(((uint32_t)Timeout << 16) & I2C_TIMEOUTR_TIMEOUTB) ; + + /* Store the new register value */ + I2Cx->TIMEOUTR = tmpreg; +} + +/** + * @brief Enables or disables I2C PEC calculation. + * @param I2Cx: where x can be 1 or 2 to select the I2C peripheral. + * @param NewState: new state of the I2Cx PEC calculation. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void I2C_CalculatePEC(I2C_TypeDef* I2Cx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_I2C_ALL_PERIPH(I2Cx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable PEC calculation */ + I2Cx->CR1 |= I2C_CR1_PECEN; + } + else + { + /* Disable PEC calculation */ + I2Cx->CR1 &= (uint32_t)~((uint32_t)I2C_CR1_PECEN); + } +} + +/** + * @brief Enables or disables I2C PEC transmission/reception request. + * @param I2Cx: where x can be 1 or 2 to select the I2C peripheral. + * @param NewState: new state of the I2Cx PEC request. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void I2C_PECRequestCmd(I2C_TypeDef* I2Cx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_I2C_ALL_PERIPH(I2Cx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable PEC transmission/reception request */ + I2Cx->CR1 |= I2C_CR2_PECBYTE; + } + else + { + /* Disable PEC transmission/reception request */ + I2Cx->CR1 &= (uint32_t)~((uint32_t)I2C_CR2_PECBYTE); + } +} + +/** + * @brief Returns the I2C PEC. + * @param I2Cx: where x can be 1 or 2 to select the I2C peripheral. + * @retval The value of the PEC . + */ +uint8_t I2C_GetPEC(I2C_TypeDef* I2Cx) +{ + /* Check the parameters */ + assert_param(IS_I2C_ALL_PERIPH(I2Cx)); + + /* Return the slave matched address in the SR1 register */ + return (uint8_t)((uint32_t)I2Cx->PECR & I2C_PECR_PEC); +} + +/** + * @} + */ + + +/** @defgroup I2C_Group4 I2C registers management functions + * @brief I2C registers management functions + * +@verbatim + =============================================================================== + ##### I2C registers management functions ##### + =============================================================================== + [..] This section provides a functions that allow user the management of + I2C registers. + +@endverbatim + * @{ + */ + + /** + * @brief Reads the specified I2C register and returns its value. + * @param I2Cx: where x can be 1 or 2 to select the I2C peripheral. + * @param I2C_Register: specifies the register to read. + * This parameter can be one of the following values: + * @arg I2C_Register_CR1: CR1 register. + * @arg I2C_Register_CR2: CR2 register. + * @arg I2C_Register_OAR1: OAR1 register. + * @arg I2C_Register_OAR2: OAR2 register. + * @arg I2C_Register_TIMINGR: TIMING register. + * @arg I2C_Register_TIMEOUTR: TIMEOUTR register. + * @arg I2C_Register_ISR: ISR register. + * @arg I2C_Register_ICR: ICR register. + * @arg I2C_Register_PECR: PECR register. + * @arg I2C_Register_RXDR: RXDR register. + * @arg I2C_Register_TXDR: TXDR register. + * @retval The value of the read register. + */ +uint32_t I2C_ReadRegister(I2C_TypeDef* I2Cx, uint8_t I2C_Register) +{ + __IO uint32_t tmp = 0; + + /* Check the parameters */ + assert_param(IS_I2C_ALL_PERIPH(I2Cx)); + assert_param(IS_I2C_REGISTER(I2C_Register)); + + tmp = (uint32_t)I2Cx; + tmp += I2C_Register; + + /* Return the selected register value */ + return (*(__IO uint32_t *) tmp); +} + +/** + * @} + */ + +/** @defgroup I2C_Group5 Data transfers management functions + * @brief Data transfers management functions + * +@verbatim + =============================================================================== + ##### Data transfers management functions ##### + =============================================================================== + [..] This subsection provides a set of functions allowing to manage + the I2C data transfers. + + [..] The read access of the I2C_RXDR register can be done using + the I2C_ReceiveData() function and returns the received value. + Whereas a write access to the I2C_TXDR can be done using I2C_SendData() + function and stores the written data into TXDR. +@endverbatim + * @{ + */ + +/** + * @brief Sends a data byte through the I2Cx peripheral. + * @param I2Cx: where x can be 1 or 2 to select the I2C peripheral. + * @param Data: Byte to be transmitted.. + * @retval None + */ +void I2C_SendData(I2C_TypeDef* I2Cx, uint8_t Data) +{ + /* Check the parameters */ + assert_param(IS_I2C_ALL_PERIPH(I2Cx)); + + /* Write in the DR register the data to be sent */ + I2Cx->TXDR = (uint8_t)Data; +} + +/** + * @brief Returns the most recent received data by the I2Cx peripheral. + * @param I2Cx: where x can be 1 or 2 to select the I2C peripheral. + * @retval The value of the received data. + */ +uint8_t I2C_ReceiveData(I2C_TypeDef* I2Cx) +{ + /* Check the parameters */ + assert_param(IS_I2C_ALL_PERIPH(I2Cx)); + + /* Return the data in the DR register */ + return (uint8_t)I2Cx->RXDR; +} + +/** + * @} + */ + + +/** @defgroup I2C_Group6 DMA transfers management functions + * @brief DMA transfers management functions + * +@verbatim + =============================================================================== + ##### DMA transfers management functions ##### + =============================================================================== + [..] This section provides two functions that can be used only in DMA mode. + [..] In DMA Mode, the I2C communication can be managed by 2 DMA Channel + requests: + (#) I2C_DMAReq_Tx: specifies the Tx buffer DMA transfer request. + (#) I2C_DMAReq_Rx: specifies the Rx buffer DMA transfer request. + [..] In this Mode it is advised to use the following function: + (+) I2C_DMACmd(I2C_TypeDef* I2Cx, uint32_t I2C_DMAReq, FunctionalState NewState); +@endverbatim + * @{ + */ + +/** + * @brief Enables or disables the I2C DMA interface. + * @param I2Cx: where x can be 1 or 2 to select the I2C peripheral. + * @param I2C_DMAReq: specifies the I2C DMA transfer request to be enabled or disabled. + * This parameter can be any combination of the following values: + * @arg I2C_DMAReq_Tx: Tx DMA transfer request + * @arg I2C_DMAReq_Rx: Rx DMA transfer request + * @param NewState: new state of the selected I2C DMA transfer request. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void I2C_DMACmd(I2C_TypeDef* I2Cx, uint32_t I2C_DMAReq, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_I2C_ALL_PERIPH(I2Cx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + assert_param(IS_I2C_DMA_REQ(I2C_DMAReq)); + + if (NewState != DISABLE) + { + /* Enable the selected I2C DMA requests */ + I2Cx->CR1 |= I2C_DMAReq; + } + else + { + /* Disable the selected I2C DMA requests */ + I2Cx->CR1 &= (uint32_t)~I2C_DMAReq; + } +} +/** + * @} + */ + + +/** @defgroup I2C_Group7 Interrupts and flags management functions + * @brief Interrupts and flags management functions + * +@verbatim + =============================================================================== + ##### Interrupts and flags management functions ##### + =============================================================================== + [..] This section provides functions allowing to configure the I2C Interrupts + sources and check or clear the flags or pending bits status. + The user should identify which mode will be used in his application to manage + the communication: Polling mode, Interrupt mode or DMA mode(refer I2C_Group6) . + + *** Polling Mode *** + ==================== + [..] In Polling Mode, the I2C communication can be managed by 15 flags: + (#) I2C_FLAG_TXE: to indicate the status of Transmit data register empty flag. + (#) I2C_FLAG_TXIS: to indicate the status of Transmit interrupt status flag . + (#) I2C_FLAG_RXNE: to indicate the status of Receive data register not empty flag. + (#) I2C_FLAG_ADDR: to indicate the status of Address matched flag (slave mode). + (#) I2C_FLAG_NACKF: to indicate the status of NACK received flag. + (#) I2C_FLAG_STOPF: to indicate the status of STOP detection flag. + (#) I2C_FLAG_TC: to indicate the status of Transfer complete flag(master mode). + (#) I2C_FLAG_TCR: to indicate the status of Transfer complete reload flag. + (#) I2C_FLAG_BERR: to indicate the status of Bus error flag. + (#) I2C_FLAG_ARLO: to indicate the status of Arbitration lost flag. + (#) I2C_FLAG_OVR: to indicate the status of Overrun/Underrun flag. + (#) I2C_FLAG_PECERR: to indicate the status of PEC error in reception flag. + (#) I2C_FLAG_TIMEOUT: to indicate the status of Timeout or Tlow detection flag. + (#) I2C_FLAG_ALERT: to indicate the status of SMBus Alert flag. + (#) I2C_FLAG_BUSY: to indicate the status of Bus busy flag. + + [..] In this Mode it is advised to use the following functions: + (+) FlagStatus I2C_GetFlagStatus(I2C_TypeDef* I2Cx, uint32_t I2C_FLAG); + (+) void I2C_ClearFlag(I2C_TypeDef* I2Cx, uint32_t I2C_FLAG); + + [..] + (@)Do not use the BUSY flag to handle each data transmission or reception.It is + better to use the TXIS and RXNE flags instead. + + *** Interrupt Mode *** + ====================== + [..] In Interrupt Mode, the I2C communication can be managed by 7 interrupt sources + and 15 pending bits: + [..] Interrupt Source: + (#) I2C_IT_ERRI: specifies the interrupt source for the Error interrupt. + (#) I2C_IT_TCI: specifies the interrupt source for the Transfer Complete interrupt. + (#) I2C_IT_STOPI: specifies the interrupt source for the Stop Detection interrupt. + (#) I2C_IT_NACKI: specifies the interrupt source for the Not Acknowledge received interrupt. + (#) I2C_IT_ADDRI: specifies the interrupt source for the Address Match interrupt. + (#) I2C_IT_RXI: specifies the interrupt source for the RX interrupt. + (#) I2C_IT_TXI: specifies the interrupt source for the TX interrupt. + + [..] Pending Bits: + (#) I2C_IT_TXIS: to indicate the status of Transmit interrupt status flag. + (#) I2C_IT_RXNE: to indicate the status of Receive data register not empty flag. + (#) I2C_IT_ADDR: to indicate the status of Address matched flag (slave mode). + (#) I2C_IT_NACKF: to indicate the status of NACK received flag. + (#) I2C_IT_STOPF: to indicate the status of STOP detection flag. + (#) I2C_IT_TC: to indicate the status of Transfer complete flag (master mode). + (#) I2C_IT_TCR: to indicate the status of Transfer complete reload flag. + (#) I2C_IT_BERR: to indicate the status of Bus error flag. + (#) I2C_IT_ARLO: to indicate the status of Arbitration lost flag. + (#) I2C_IT_OVR: to indicate the status of Overrun/Underrun flag. + (#) I2C_IT_PECERR: to indicate the status of PEC error in reception flag. + (#) I2C_IT_TIMEOUT: to indicate the status of Timeout or Tlow detection flag. + (#) I2C_IT_ALERT: to indicate the status of SMBus Alert flag. + + [..] In this Mode it is advised to use the following functions: + (+) void I2C_ClearITPendingBit(I2C_TypeDef* I2Cx, uint32_t I2C_IT); + (+) ITStatus I2C_GetITStatus(I2C_TypeDef* I2Cx, uint32_t I2C_IT); + +@endverbatim + * @{ + */ + +/** + * @brief Checks whether the specified I2C flag is set or not. + * @param I2Cx: where x can be 1 or 2 to select the I2C peripheral. + * @param I2C_FLAG: specifies the flag to check. + * This parameter can be one of the following values: + * @arg I2C_FLAG_TXE: Transmit data register empty + * @arg I2C_FLAG_TXIS: Transmit interrupt status + * @arg I2C_FLAG_RXNE: Receive data register not empty + * @arg I2C_FLAG_ADDR: Address matched (slave mode) + * @arg I2C_FLAG_NACKF: NACK received flag + * @arg I2C_FLAG_STOPF: STOP detection flag + * @arg I2C_FLAG_TC: Transfer complete (master mode) + * @arg I2C_FLAG_TCR: Transfer complete reload + * @arg I2C_FLAG_BERR: Bus error + * @arg I2C_FLAG_ARLO: Arbitration lost + * @arg I2C_FLAG_OVR: Overrun/Underrun + * @arg I2C_FLAG_PECERR: PEC error in reception + * @arg I2C_FLAG_TIMEOUT: Timeout or Tlow detection flag + * @arg I2C_FLAG_ALERT: SMBus Alert + * @arg I2C_FLAG_BUSY: Bus busy + * @retval The new state of I2C_FLAG (SET or RESET). + */ +FlagStatus I2C_GetFlagStatus(I2C_TypeDef* I2Cx, uint32_t I2C_FLAG) +{ + uint32_t tmpreg = 0; + FlagStatus bitstatus = RESET; + + /* Check the parameters */ + assert_param(IS_I2C_ALL_PERIPH(I2Cx)); + assert_param(IS_I2C_GET_FLAG(I2C_FLAG)); + + /* Get the ISR register value */ + tmpreg = I2Cx->ISR; + + /* Get flag status */ + tmpreg &= I2C_FLAG; + + if(tmpreg != 0) + { + /* I2C_FLAG is set */ + bitstatus = SET; + } + else + { + /* I2C_FLAG is reset */ + bitstatus = RESET; + } + return bitstatus; +} + +/** + * @brief Clears the I2Cx's pending flags. + * @param I2Cx: where x can be 1 or 2 to select the I2C peripheral. + * @param I2C_FLAG: specifies the flag to clear. + * This parameter can be any combination of the following values: + * @arg I2C_FLAG_ADDR: Address matched (slave mode) + * @arg I2C_FLAG_NACKF: NACK received flag + * @arg I2C_FLAG_STOPF: STOP detection flag + * @arg I2C_FLAG_BERR: Bus error + * @arg I2C_FLAG_ARLO: Arbitration lost + * @arg I2C_FLAG_OVR: Overrun/Underrun + * @arg I2C_FLAG_PECERR: PEC error in reception + * @arg I2C_FLAG_TIMEOUT: Timeout or Tlow detection flag + * @arg I2C_FLAG_ALERT: SMBus Alert + * @retval The new state of I2C_FLAG (SET or RESET). + */ +void I2C_ClearFlag(I2C_TypeDef* I2Cx, uint32_t I2C_FLAG) +{ + /* Check the parameters */ + assert_param(IS_I2C_ALL_PERIPH(I2Cx)); + assert_param(IS_I2C_CLEAR_FLAG(I2C_FLAG)); + + /* Clear the selected flag */ + I2Cx->ICR = I2C_FLAG; + } + +/** + * @brief Checks whether the specified I2C interrupt has occurred or not. + * @param I2Cx: where x can be 1 or 2 to select the I2C peripheral. + * @param I2C_IT: specifies the interrupt source to check. + * This parameter can be one of the following values: + * @arg I2C_IT_TXIS: Transmit interrupt status + * @arg I2C_IT_RXNE: Receive data register not empty + * @arg I2C_IT_ADDR: Address matched (slave mode) + * @arg I2C_IT_NACKF: NACK received flag + * @arg I2C_IT_STOPF: STOP detection flag + * @arg I2C_IT_TC: Transfer complete (master mode) + * @arg I2C_IT_TCR: Transfer complete reload + * @arg I2C_IT_BERR: Bus error + * @arg I2C_IT_ARLO: Arbitration lost + * @arg I2C_IT_OVR: Overrun/Underrun + * @arg I2C_IT_PECERR: PEC error in reception + * @arg I2C_IT_TIMEOUT: Timeout or Tlow detection flag + * @arg I2C_IT_ALERT: SMBus Alert + * @retval The new state of I2C_IT (SET or RESET). + */ +ITStatus I2C_GetITStatus(I2C_TypeDef* I2Cx, uint32_t I2C_IT) +{ + uint32_t tmpreg = 0; + ITStatus bitstatus = RESET; + uint32_t enablestatus = 0; + + /* Check the parameters */ + assert_param(IS_I2C_ALL_PERIPH(I2Cx)); + assert_param(IS_I2C_GET_IT(I2C_IT)); + + /* Check if the interrupt source is enabled or not */ + /* If Error interrupt */ + if((uint32_t)(I2C_IT & ERROR_IT_MASK)) + { + enablestatus = (uint32_t)((I2C_CR1_ERRIE) & (I2Cx->CR1)); + } + /* If TC interrupt */ + else if((uint32_t)(I2C_IT & TC_IT_MASK)) + { + enablestatus = (uint32_t)((I2C_CR1_TCIE) & (I2Cx->CR1)); + } + else + { + enablestatus = (uint32_t)((I2C_IT) & (I2Cx->CR1)); + } + + /* Get the ISR register value */ + tmpreg = I2Cx->ISR; + + /* Get flag status */ + tmpreg &= I2C_IT; + + /* Check the status of the specified I2C flag */ + if((tmpreg != RESET) && enablestatus) + { + /* I2C_IT is set */ + bitstatus = SET; + } + else + { + /* I2C_IT is reset */ + bitstatus = RESET; + } + + /* Return the I2C_IT status */ + return bitstatus; +} + +/** + * @brief Clears the I2Cx's interrupt pending bits. + * @param I2Cx: where x can be 1 or 2 to select the I2C peripheral. + * @param I2C_IT: specifies the interrupt pending bit to clear. + * This parameter can be any combination of the following values: + * @arg I2C_IT_ADDR: Address matched (slave mode) + * @arg I2C_IT_NACKF: NACK received flag + * @arg I2C_IT_STOPF: STOP detection flag + * @arg I2C_IT_BERR: Bus error + * @arg I2C_IT_ARLO: Arbitration lost + * @arg I2C_IT_OVR: Overrun/Underrun + * @arg I2C_IT_PECERR: PEC error in reception + * @arg I2C_IT_TIMEOUT: Timeout or Tlow detection flag + * @arg I2C_IT_ALERT: SMBus Alert + * @retval The new state of I2C_IT (SET or RESET). + */ +void I2C_ClearITPendingBit(I2C_TypeDef* I2Cx, uint32_t I2C_IT) +{ + /* Check the parameters */ + assert_param(IS_I2C_ALL_PERIPH(I2Cx)); + assert_param(IS_I2C_CLEAR_IT(I2C_IT)); + + /* Clear the selected flag */ + I2Cx->ICR = I2C_IT; +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_iwdg.c b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_iwdg.c new file mode 100755 index 0000000000..885b2f98d2 --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_iwdg.c @@ -0,0 +1,288 @@ +/** + ****************************************************************************** + * @file stm32f30x_iwdg.c + * @author MCD Application Team + * @version V1.2.3 + * @date 10-July-2015 + * @brief This file provides firmware functions to manage the following + * functionalities of the Independent watchdog (IWDG) peripheral: + * + Prescaler and Counter configuration + * + IWDG activation + * + Flag management + * + @verbatim + + =============================================================================== + ##### IWDG features ##### + =============================================================================== + [..] The IWDG can be started by either software or hardware (configurable + through option byte). + [..] The IWDG is clocked by its own dedicated low-speed clock (LSI) and + thus stays active even if the main clock fails. + Once the IWDG is started, the LSI is forced ON and cannot be disabled + (LSI cannot be disabled too), and the counter starts counting down from + the reset value of 0xFFF. When it reaches the end of count value (0x000) + a system reset is generated. + The IWDG counter should be reloaded at regular intervals to prevent + an MCU reset. + [..] The IWDG is implemented in the VDD voltage domain that is still functional + in STOP and STANDBY mode (IWDG reset can wake-up from STANDBY). + [..] IWDGRST flag in RCC_CSR register can be used to inform when a IWDG + reset occurs. + [..] Min-max timeout value @41KHz (LSI): ~0.1ms / ~25.5s + The IWDG timeout may vary due to LSI frequency dispersion. STM32F30x + devices provide the capability to measure the LSI frequency (LSI clock + connected internally to TIM16 CH1 input capture). The measured value + can be used to have an IWDG timeout with an acceptable accuracy. + For more information, please refer to the STM32F30x Reference manual. + + ##### How to use this driver ##### + =============================================================================== + [..] This driver allows to use IWDG peripheral with either window option enabled + or disabled. To do so follow one of the two procedures below. + (#) Window option is enabled: + (++) Start the IWDG using IWDG_Enable() function, when the IWDG is used + in software mode (no need to enable the LSI, it will be enabled + by hardware). + (++) Enable write access to IWDG_PR and IWDG_RLR registers using + IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable) function. + (++) Configure the IWDG prescaler using IWDG_SetPrescaler() function. + (++) Configure the IWDG counter value using IWDG_SetReload() function. + This value will be loaded in the IWDG counter each time the counter + is reloaded, then the IWDG will start counting down from this value. + (++) Wait for the IWDG registers to be updated using IWDG_GetFlagStatus() function. + (++) Configure the IWDG refresh window using IWDG_SetWindowValue() function. + + (#) Window option is disabled: + (++) Enable write access to IWDG_PR and IWDG_RLR registers using + IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable) function. + (++) Configure the IWDG prescaler using IWDG_SetPrescaler() function. + (++) Configure the IWDG counter value using IWDG_SetReload() function. + This value will be loaded in the IWDG counter each time the counter + is reloaded, then the IWDG will start counting down from this value. + (++) Wait for the IWDG registers to be updated using IWDG_GetFlagStatus() function. + (++) reload the IWDG counter at regular intervals during normal operation + to prevent an MCU reset, using IWDG_ReloadCounter() function. + (++) Start the IWDG using IWDG_Enable() function, when the IWDG is used + in software mode (no need to enable the LSI, it will be enabled + by hardware). + + @endverbatim + + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f30x_iwdg.h" + +/** @addtogroup STM32F30x_StdPeriph_Driver + * @{ + */ + +/** @defgroup IWDG + * @brief IWDG driver modules + * @{ + */ + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +/* ---------------------- IWDG registers bit mask ----------------------------*/ +/* KR register bit mask */ +#define KR_KEY_RELOAD ((uint16_t)0xAAAA) +#define KR_KEY_ENABLE ((uint16_t)0xCCCC) + +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/* Private function prototypes -----------------------------------------------*/ +/* Private functions ---------------------------------------------------------*/ + +/** @defgroup IWDG_Private_Functions + * @{ + */ + +/** @defgroup IWDG_Group1 Prescaler and Counter configuration functions + * @brief Prescaler and Counter configuration functions + * +@verbatim + =============================================================================== + ##### Prescaler and Counter configuration functions ##### + =============================================================================== + +@endverbatim + * @{ + */ + +/** + * @brief Enables or disables write access to IWDG_PR and IWDG_RLR registers. + * @param IWDG_WriteAccess: new state of write access to IWDG_PR and IWDG_RLR registers. + * This parameter can be one of the following values: + * @arg IWDG_WriteAccess_Enable: Enable write access to IWDG_PR and IWDG_RLR registers + * @arg IWDG_WriteAccess_Disable: Disable write access to IWDG_PR and IWDG_RLR registers + * @retval None + */ +void IWDG_WriteAccessCmd(uint16_t IWDG_WriteAccess) +{ + /* Check the parameters */ + assert_param(IS_IWDG_WRITE_ACCESS(IWDG_WriteAccess)); + IWDG->KR = IWDG_WriteAccess; +} + +/** + * @brief Sets IWDG Prescaler value. + * @param IWDG_Prescaler: specifies the IWDG Prescaler value. + * This parameter can be one of the following values: + * @arg IWDG_Prescaler_4: IWDG prescaler set to 4 + * @arg IWDG_Prescaler_8: IWDG prescaler set to 8 + * @arg IWDG_Prescaler_16: IWDG prescaler set to 16 + * @arg IWDG_Prescaler_32: IWDG prescaler set to 32 + * @arg IWDG_Prescaler_64: IWDG prescaler set to 64 + * @arg IWDG_Prescaler_128: IWDG prescaler set to 128 + * @arg IWDG_Prescaler_256: IWDG prescaler set to 256 + * @retval None + */ +void IWDG_SetPrescaler(uint8_t IWDG_Prescaler) +{ + /* Check the parameters */ + assert_param(IS_IWDG_PRESCALER(IWDG_Prescaler)); + IWDG->PR = IWDG_Prescaler; +} + +/** + * @brief Sets IWDG Reload value. + * @param Reload: specifies the IWDG Reload value. + * This parameter must be a number between 0 and 0x0FFF. + * @retval None + */ +void IWDG_SetReload(uint16_t Reload) +{ + /* Check the parameters */ + assert_param(IS_IWDG_RELOAD(Reload)); + IWDG->RLR = Reload; +} + +/** + * @brief Reloads IWDG counter with value defined in the reload register + * (write access to IWDG_PR and IWDG_RLR registers disabled). + * @param None + * @retval None + */ +void IWDG_ReloadCounter(void) +{ + IWDG->KR = KR_KEY_RELOAD; +} + + +/** + * @brief Sets the IWDG window value. + * @param WindowValue: specifies the window value to be compared to the downcounter. + * @retval None + */ +void IWDG_SetWindowValue(uint16_t WindowValue) +{ + /* Check the parameters */ + assert_param(IS_IWDG_WINDOW_VALUE(WindowValue)); + IWDG->WINR = WindowValue; +} + +/** + * @} + */ + +/** @defgroup IWDG_Group2 IWDG activation function + * @brief IWDG activation function + * +@verbatim + =============================================================================== + ##### IWDG activation function ##### + =============================================================================== + +@endverbatim + * @{ + */ + +/** + * @brief Enables IWDG (write access to IWDG_PR and IWDG_RLR registers disabled). + * @param None + * @retval None + */ +void IWDG_Enable(void) +{ + IWDG->KR = KR_KEY_ENABLE; +} + +/** + * @} + */ + +/** @defgroup IWDG_Group3 Flag management function + * @brief Flag management function + * +@verbatim + =============================================================================== + ##### Flag management function ##### + =============================================================================== + +@endverbatim + * @{ + */ + +/** + * @brief Checks whether the specified IWDG flag is set or not. + * @param IWDG_FLAG: specifies the flag to check. + * This parameter can be one of the following values: + * @arg IWDG_FLAG_PVU: Prescaler Value Update on going + * @arg IWDG_FLAG_RVU: Reload Value Update on going + * @arg IWDG_FLAG_WVU: Counter Window Value Update on going + * @retval The new state of IWDG_FLAG (SET or RESET). + */ +FlagStatus IWDG_GetFlagStatus(uint16_t IWDG_FLAG) +{ + FlagStatus bitstatus = RESET; + /* Check the parameters */ + assert_param(IS_IWDG_FLAG(IWDG_FLAG)); + if ((IWDG->SR & IWDG_FLAG) != (uint32_t)RESET) + { + bitstatus = SET; + } + else + { + bitstatus = RESET; + } + /* Return the flag status */ + return bitstatus; +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_misc.c b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_misc.c new file mode 100755 index 0000000000..43e647dea1 --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_misc.c @@ -0,0 +1,230 @@ +/** + ****************************************************************************** + * @file stm32f30x_misc.c + * @author MCD Application Team + * @version V1.2.3 + * @date 10-July-2015 + * @brief This file provides all the miscellaneous firmware functions (add-on + * to CMSIS functions). + * + @verbatim + + =============================================================================== + ##### How to configure Interrupts using driver ##### + =============================================================================== + [..] This section provide functions allowing to configure the NVIC interrupts + (IRQ). The Cortex-M4 exceptions are managed by CMSIS functions. + (#) Configure the NVIC Priority Grouping using NVIC_PriorityGroupConfig() + function according to the following table. + The table below gives the allowed values of the pre-emption priority + and subpriority according to the Priority Grouping configuration + performed by NVIC_PriorityGroupConfig function. + + (#) Enable and Configure the priority of the selected IRQ Channels. + [..] + (@) When the NVIC_PriorityGroup_0 is selected, it will no any nested interrupt, + the IRQ priority will be managed only by subpriority. + The sub-priority is only used to sort pending exception priorities, + and does not affect active exceptions. + (@) Lower priority values gives higher priority. + (@) Priority Order: + (#@) Lowest Preemption priority. + (#@) Lowest Subpriority. + (#@) Lowest hardware priority (IRQn position). + + @endverbatim + + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f30x_misc.h" + +/** @addtogroup STM32F30x_StdPeriph_Driver + * @{ + */ + +/** @defgroup MISC + * @brief MISC driver modules + * @{ + */ + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +#define AIRCR_VECTKEY_MASK ((uint32_t)0x05FA0000) + +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/* Private function prototypes -----------------------------------------------*/ +/* Private functions ---------------------------------------------------------*/ + +/** @defgroup MISC_Private_Functions + * @{ + */ + +/** + * @brief Configures the priority grouping: pre-emption priority and subpriority. + * @param NVIC_PriorityGroup: specifies the priority grouping bits length. + * This parameter can be one of the following values: + * @arg NVIC_PriorityGroup_0: 0 bits for pre-emption priority. + * 4 bits for subpriority. + * @arg NVIC_PriorityGroup_1: 1 bits for pre-emption priority. + * 3 bits for subpriority. + * @arg NVIC_PriorityGroup_2: 2 bits for pre-emption priority. + * 2 bits for subpriority. + * @arg NVIC_PriorityGroup_3: 3 bits for pre-emption priority. + * 1 bits for subpriority. + * @arg NVIC_PriorityGroup_4: 4 bits for pre-emption priority. + * 0 bits for subpriority. + * @note When NVIC_PriorityGroup_0 is selected, it will no be any nested + * interrupt. This interrupts priority is managed only with subpriority. + * @retval None + */ +void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup) +{ + /* Check the parameters */ + assert_param(IS_NVIC_PRIORITY_GROUP(NVIC_PriorityGroup)); + + /* Set the PRIGROUP[10:8] bits according to NVIC_PriorityGroup value */ + SCB->AIRCR = AIRCR_VECTKEY_MASK | NVIC_PriorityGroup; +} + +/** + * @brief Initializes the NVIC peripheral according to the specified + * parameters in the NVIC_InitStruct. + * @note To configure interrupts priority correctly, the NVIC_PriorityGroupConfig() + * function should be called before. + * @param NVIC_InitStruct: pointer to a NVIC_InitTypeDef structure that contains + * the configuration information for the specified NVIC peripheral. + * @retval None + */ +void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct) +{ + uint32_t tmppriority = 0x00, tmppre = 0x00, tmpsub = 0x0F; + + /* Check the parameters */ + assert_param(IS_FUNCTIONAL_STATE(NVIC_InitStruct->NVIC_IRQChannelCmd)); + assert_param(IS_NVIC_PREEMPTION_PRIORITY(NVIC_InitStruct->NVIC_IRQChannelPreemptionPriority)); + assert_param(IS_NVIC_SUB_PRIORITY(NVIC_InitStruct->NVIC_IRQChannelSubPriority)); + + if (NVIC_InitStruct->NVIC_IRQChannelCmd != DISABLE) + { + /* Compute the Corresponding IRQ Priority --------------------------------*/ + tmppriority = (0x700 - ((SCB->AIRCR) & (uint32_t)0x700))>> 0x08; + tmppre = (0x4 - tmppriority); + tmpsub = tmpsub >> tmppriority; + + tmppriority = (uint32_t)NVIC_InitStruct->NVIC_IRQChannelPreemptionPriority << tmppre; + tmppriority |= NVIC_InitStruct->NVIC_IRQChannelSubPriority & tmpsub; + tmppriority = tmppriority << 0x04; + + NVIC->IP[NVIC_InitStruct->NVIC_IRQChannel] = tmppriority; + + /* Enable the Selected IRQ Channels --------------------------------------*/ + NVIC->ISER[NVIC_InitStruct->NVIC_IRQChannel >> 0x05] = + (uint32_t)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (uint8_t)0x1F); + } + else + { + /* Disable the Selected IRQ Channels -------------------------------------*/ + NVIC->ICER[NVIC_InitStruct->NVIC_IRQChannel >> 0x05] = + (uint32_t)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (uint8_t)0x1F); + } +} + +/** + * @brief Sets the vector table location and Offset. + * @param NVIC_VectTab: specifies if the vector table is in RAM or FLASH memory. + * This parameter can be one of the following values: + * @arg NVIC_VectTab_RAM + * @arg NVIC_VectTab_FLASH + * @param Offset: Vector Table base offset field. This value must be a multiple of 0x200. + * @retval None + */ +void NVIC_SetVectorTable(uint32_t NVIC_VectTab, uint32_t Offset) +{ + /* Check the parameters */ + assert_param(IS_NVIC_VECTTAB(NVIC_VectTab)); + assert_param(IS_NVIC_OFFSET(Offset)); + + SCB->VTOR = NVIC_VectTab | (Offset & (uint32_t)0x1FFFFF80); +} + +/** + * @brief Selects the condition for the system to enter low power mode. + * @param LowPowerMode: Specifies the new mode for the system to enter low power mode. + * This parameter can be one of the following values: + * @arg NVIC_LP_SEVONPEND + * @arg NVIC_LP_SLEEPDEEP + * @arg NVIC_LP_SLEEPONEXIT + * @param NewState: new state of LP condition. This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void NVIC_SystemLPConfig(uint8_t LowPowerMode, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_NVIC_LP(LowPowerMode)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + SCB->SCR |= LowPowerMode; + } + else + { + SCB->SCR &= (uint32_t)(~(uint32_t)LowPowerMode); + } +} + +/** + * @brief Configures the SysTick clock source. + * @param SysTick_CLKSource: specifies the SysTick clock source. + * This parameter can be one of the following values: + * @arg SysTick_CLKSource_HCLK_Div8: AHB clock divided by 8 selected as SysTick clock source. + * @arg SysTick_CLKSource_HCLK: AHB clock selected as SysTick clock source. + * @retval None + */ +void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource) +{ + /* Check the parameters */ + assert_param(IS_SYSTICK_CLK_SOURCE(SysTick_CLKSource)); + if (SysTick_CLKSource == SysTick_CLKSource_HCLK) + { + SysTick->CTRL |= SysTick_CLKSource_HCLK; + } + else + { + SysTick->CTRL &= SysTick_CLKSource_HCLK_Div8; + } +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_opamp.c b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_opamp.c new file mode 100755 index 0000000000..f215d58889 --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_opamp.c @@ -0,0 +1,575 @@ +/** + ****************************************************************************** + * @file stm32f30x_opamp.c + * @author MCD Application Team + * @version V1.2.3 + * @date 10-July-2015 + * @brief This file provides firmware functions to manage the following + * functionalities of the operational amplifiers (OPAMP1,...OPAMP4) peripheral: + * + OPAMP Configuration + * + OPAMP calibration + * + @verbatim + + ============================================================================== + ##### OPAMP Peripheral Features ##### + ============================================================================== + + [..] + The device integrates 4 operational amplifiers OPAMP1, OPAMP2, OPAMP3 and OPAMP4: + + (+) The OPAMPs non inverting input can be selected among the list shown by + table below. + + (+) The OPAMPs inverting input can be selected among the list shown by + table below. + + (+) The OPAMPs outputs can be internally connected to the inverting input + (follower mode) + (+) The OPAMPs outputs can be internally connected to resistor feedback + output (Programmable Gain Amplifier mode) + + (+) The OPAMPs outputs can be internally connected to ADC + + (+) The OPAMPs can be calibrated to compensate the offset compensation + + (+) Timer-controlled Mux for automatic switch of inverting and + non-inverting input + + OPAMPs inverting/non-inverting inputs: + +--------------------------------------------------------------+ + | | | OPAMP1 | OPAMP2 | OPAMP3 | OPAMP4 | + |-----------------|--------|--------|--------|--------|--------| + | | PGA | OK | OK | OK | OK | + | Inverting Input | Vout | OK | OK | OK | OK | + | | IO1 | PC5 | PC5 | PB10 | PB10 | + | | IO2 | PA3 | PA5 | PB2 | PD8 | + |-----------------|--------|--------|--------|--------|--------| + | | IO1 | PA7 | PD14 | PB13 | PD11 | + | Non Inverting | IO2 | PA5 | PB14 | PA5 | PB11 | + | Input | IO3 | PA3 | PB0 | PA1 | PA4 | + | | IO4 | PA1 | PA7 | PB0 | PB13 | + +--------------------------------------------------------------+ + + ##### How to use this driver ##### + ============================================================================== + [..] + This driver provides functions to configure and program the OPAMP + of all STM32F30x devices. + + To use the OPAMP, perform the following steps: + + (#) Enable the SYSCFG APB clock to get write access to OPAMP + register using RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); + + (#) Configure the OPAMP input in analog mode using GPIO_Init() + + (#) Configure the OPAMP using OPAMP_Init() function: + (++) Select the inverting input + (++) Select the non-inverting inverting input + + (#) Enable the OPAMP using OPAMP_Cmd() function + + @endverbatim + + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f30x_opamp.h" + +/** @addtogroup STM32F30x_StdPeriph_Driver + * @{ + */ + +/** @defgroup OPAMP + * @brief OPAMP driver modules + * @{ + */ + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +#define OPAMP_CSR_DEFAULT_MASK ((uint32_t)0xFFFFFF93) +#define OPAMP_CSR_TIMERMUX_MASK ((uint32_t)0xFFFFF8FF) +#define OPAMP_CSR_TRIMMING_MASK ((uint32_t)0x0000001F) + +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/* Private function prototypes -----------------------------------------------*/ +/* Private functions ---------------------------------------------------------*/ + +/** @defgroup OPAMP_Private_Functions + * @{ + */ + +/** @defgroup OPAMP_Group1 Initialization and Configuration functions + * @brief Initialization and Configuration functions + * +@verbatim + =============================================================================== + ##### Initialization and Configuration functions ##### + =============================================================================== + +@endverbatim + * @{ + */ + +/** + * @brief Deinitializes OPAMP peripheral registers to their default reset values. + * @note Deinitialization can't be performed if the OPAMP configuration is locked. + * To unlock the configuration, perform a system reset. + * @param OPAMP_Selection: the selected OPAMP. + * This parameter can be OPAMP_Selection_OPAMPx where x can be 1 to 4 + * to select the OPAMP peripheral. + * @param None + * @retval None + */ +void OPAMP_DeInit(uint32_t OPAMP_Selection) +{ + /*!< Set OPAMP_CSR register to reset value */ + *(__IO uint32_t *) (OPAMP_BASE + OPAMP_Selection) = ((uint32_t)0x00000000); +} + +/** + * @brief Initializes the OPAMP peripheral according to the specified parameters + * in OPAMP_InitStruct + * @note If the selected OPAMP is locked, initialization can't be performed. + * To unlock the configuration, perform a system reset. + * @param OPAMP_Selection: the selected OPAMP. + * This parameter can be OPAMP_Selection_OPAMPx where x can be 1 to 4 + * to select the OPAMP peripheral. + * @param OPAMP_InitStruct: pointer to an OPAMP_InitTypeDef structure that contains + * the configuration information for the specified OPAMP peripheral. + * - OPAMP_InvertingInput specifies the inverting input of OPAMP + * - OPAMP_NonInvertingInput specifies the non inverting input of OPAMP + * @retval None + */ +void OPAMP_Init(uint32_t OPAMP_Selection, OPAMP_InitTypeDef* OPAMP_InitStruct) +{ + uint32_t tmpreg = 0; + + /* Check the parameters */ + assert_param(IS_OPAMP_ALL_PERIPH(OPAMP_Selection)); + assert_param(IS_OPAMP_INVERTING_INPUT(OPAMP_InitStruct->OPAMP_InvertingInput)); + assert_param(IS_OPAMP_NONINVERTING_INPUT(OPAMP_InitStruct->OPAMP_NonInvertingInput)); + + /*!< Get the OPAMPx_CSR register value */ + tmpreg = *(__IO uint32_t *) (OPAMP_BASE + OPAMP_Selection); + + /*!< Clear the inverting and non inverting bits selection bits */ + tmpreg &= (uint32_t) (OPAMP_CSR_DEFAULT_MASK); + + /*!< Configure OPAMP: inverting and non inverting inputs */ + tmpreg |= (uint32_t)(OPAMP_InitStruct->OPAMP_InvertingInput | OPAMP_InitStruct->OPAMP_NonInvertingInput); + + /*!< Write to OPAMPx_CSR register */ + *(__IO uint32_t *) (OPAMP_BASE + OPAMP_Selection) = tmpreg; +} + +/** + * @brief Fills each OPAMP_InitStruct member with its default value. + * @param OPAMP_InitStruct: pointer to an OPAMP_InitTypeDef structure which will + * be initialized. + * @retval None + */ +void OPAMP_StructInit(OPAMP_InitTypeDef* OPAMP_InitStruct) +{ + OPAMP_InitStruct->OPAMP_NonInvertingInput = OPAMP_NonInvertingInput_IO1; + OPAMP_InitStruct->OPAMP_InvertingInput = OPAMP_InvertingInput_IO1; +} + +/** + * @brief Configure the feedback resistor gain. + * @note If the selected OPAMP is locked, gain configuration can't be performed. + * To unlock the configuration, perform a system reset. + * @param OPAMP_Selection: the selected OPAMP. + * This parameter can be OPAMP_Selection_OPAMPx where x can be 1 to 4 + * to select the OPAMP peripheral. + * @param NewState: new state of the OPAMP peripheral. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void OPAMP_PGAConfig(uint32_t OPAMP_Selection, uint32_t OPAMP_PGAGain, uint32_t OPAMP_PGAConnect) +{ + /* Check the parameters */ + assert_param(IS_OPAMP_ALL_PERIPH(OPAMP_Selection)); + assert_param(IS_OPAMP_PGAGAIN(OPAMP_PGAGain)); + assert_param(IS_OPAMP_PGACONNECT(OPAMP_PGAConnect)); + + /* Reset the configuration bits */ + *(__IO uint32_t *) (OPAMP_BASE + OPAMP_Selection) &= (uint32_t)(~OPAMP_CSR_PGGAIN); + + /* Set the new configuration */ + *(__IO uint32_t *) (OPAMP_BASE + OPAMP_Selection) |= (uint32_t) (OPAMP_PGAGain | OPAMP_PGAConnect); +} + +/** + * @brief Configure the OPAMP's internal reference. + * @note This feature is used when calibration enabled or OPAMP's reference + * connected to the non inverting input. + * @note If the selected OPAMP is locked, Vref configuration can't be performed. + * To unlock the configuration, perform a system reset. + * @param OPAMP_Selection: the selected OPAMP. + * This parameter can be OPAMP_Selection_OPAMPx where x can be 1 to 4 + * to select the OPAMP peripheral. + * @param OPAMP_Vref: This parameter can be: + * OPAMP_Vref_3VDDA: OPMAP Vref = 3.3% VDDA + * OPAMP_Vref_10VDDA: OPMAP Vref = 10% VDDA + * OPAMP_Vref_50VDDA: OPMAP Vref = 50% VDDA + * OPAMP_Vref_90VDDA: OPMAP Vref = 90% VDDA + * @retval None + */ +void OPAMP_VrefConfig(uint32_t OPAMP_Selection, uint32_t OPAMP_Vref) +{ + uint32_t tmpreg = 0; + + /* Check the parameters */ + assert_param(IS_OPAMP_ALL_PERIPH(OPAMP_Selection)); + assert_param(IS_OPAMP_VREF(OPAMP_Vref)); + + /*!< Get the OPAMPx_CSR register value */ + tmpreg = *(__IO uint32_t *) (OPAMP_BASE + OPAMP_Selection); + + /*!< Clear the CALSEL bits */ + tmpreg &= (uint32_t) (~OPAMP_CSR_CALSEL); + + /*!< Configure OPAMP reference */ + tmpreg |= (uint32_t)(OPAMP_Vref); + + /*!< Write to OPAMPx_CSR register */ + *(__IO uint32_t *) (OPAMP_BASE + OPAMP_Selection) = tmpreg; +} + +/** + * @brief Connect the internal reference to the OPAMP's non inverting input. + * @note If the selected OPAMP is locked, Vref configuration can't be performed. + * To unlock the configuration, perform a system reset. + * @param OPAMP_Selection: the selected OPAMP. + * This parameter can be OPAMP_Selection_OPAMPx where x can be 1 to 4 + * to select the OPAMP peripheral. + * @param NewState: new state of the OPAMP peripheral. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void OPAMP_VrefConnectNonInvertingInput(uint32_t OPAMP_Selection, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_OPAMP_ALL_PERIPH(OPAMP_Selection)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Connect the internal reference to the OPAMP's non inverting input */ + *(__IO uint32_t *) (OPAMP_BASE + OPAMP_Selection) |= (uint32_t) (OPAMP_CSR_FORCEVP); + } + else + { + /* Disconnect the internal reference to the OPAMP's non inverting input */ + *(__IO uint32_t *) (OPAMP_BASE + OPAMP_Selection) &= (uint32_t)(~OPAMP_CSR_FORCEVP); + } +} + +/** + * @brief Enables or disables connecting the OPAMP's internal reference to ADC. + * @note If the selected OPAMP is locked, Vref connection can't be performed. + * To unlock the configuration, perform a system reset. + * @param NewState: new state of the Vrefint output. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void OPAMP_VrefConnectADCCmd(uint32_t OPAMP_Selection, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_OPAMP_ALL_PERIPH(OPAMP_Selection)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable output internal reference */ + *(__IO uint32_t *) (OPAMP_BASE + OPAMP_Selection) |= (uint32_t) (OPAMP_CSR_TSTREF); + } + else + { + /* Disable output internal reference */ + *(__IO uint32_t *) (OPAMP_BASE + OPAMP_Selection) &= (uint32_t)(~OPAMP_CSR_TSTREF); + } +} + +/** + * @brief Configure the OPAMP peripheral (secondary inputs) for timer-controlled + * mux mode according to the specified parameters in OPAMP_InitStruct. + * @note If the selected OPAMP is locked, timer-controlled mux configuration + * can't be performed. + * To unlock the configuration, perform a system reset. + * @param OPAMP_Selection: the selected OPAMP. + * This parameter can be OPAMP_Selection_OPAMPx where x can be 1 to 4 + * to select the OPAMP peripheral. + * @param OPAMP_InitStruct: pointer to an OPAMP_InitTypeDef structure that contains + * the configuration information for the specified OPAMP peripheral. + * - OPAMP_InvertingInput specifies the inverting input of OPAMP + * - OPAMP_NonInvertingInput specifies the non inverting input of OPAMP + * @note PGA and Vout can't be selected as secondary inverting input. + * @retval None + */ +void OPAMP_TimerControlledMuxConfig(uint32_t OPAMP_Selection, OPAMP_InitTypeDef* OPAMP_InitStruct) +{ + uint32_t tmpreg = 0; + + /* Check the parameters */ + assert_param(IS_OPAMP_ALL_PERIPH(OPAMP_Selection)); + assert_param(IS_OPAMP_SECONDARY_INVINPUT(OPAMP_InitStruct->OPAMP_InvertingInput)); + assert_param(IS_OPAMP_NONINVERTING_INPUT(OPAMP_InitStruct->OPAMP_NonInvertingInput)); + + /*!< Get the OPAMPx_CSR register value */ + tmpreg = *(__IO uint32_t *) (OPAMP_BASE + OPAMP_Selection); + + /*!< Clear the secondary inverting bit, secondary non inverting bit and TCMEN bits */ + tmpreg &= (uint32_t) (OPAMP_CSR_TIMERMUX_MASK); + + /*!< Configure OPAMP: secondary inverting and non inverting inputs */ + tmpreg |= (uint32_t)((uint32_t)(OPAMP_InitStruct->OPAMP_InvertingInput<<3) | (uint32_t)(OPAMP_InitStruct->OPAMP_NonInvertingInput<<7)); + + /*!< Write to OPAMPx_CSR register */ + *(__IO uint32_t *) (OPAMP_BASE + OPAMP_Selection) = tmpreg; +} + +/** + * @brief Enable or disable the timer-controlled mux mode. + * @note If the selected OPAMP is locked, enable/disable can't be performed. + * To unlock the configuration, perform a system reset. + * @param OPAMP_Selection: the selected OPAMP. + * This parameter can be OPAMP_Selection_OPAMPx where x can be 1 to 4 + * to select the OPAMP peripheral. + * @param NewState: new state of the OPAMP peripheral. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void OPAMP_TimerControlledMuxCmd(uint32_t OPAMP_Selection, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_OPAMP_ALL_PERIPH(OPAMP_Selection)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable the timer-controlled Mux mode */ + *(__IO uint32_t *) (OPAMP_BASE + OPAMP_Selection) |= (uint32_t) (OPAMP_CSR_TCMEN); + } + else + { + /* Disable the timer-controlled Mux mode */ + *(__IO uint32_t *) (OPAMP_BASE + OPAMP_Selection) &= (uint32_t)(~OPAMP_CSR_TCMEN); + } +} + +/** + * @brief Enable or disable the OPAMP peripheral. + * @note If the selected OPAMP is locked, enable/disable can't be performed. + * To unlock the configuration, perform a system reset. + * @param OPAMP_Selection: the selected OPAMP. + * This parameter can be OPAMP_Selection_OPAMPx where x can be 1 to 4 + * to select the OPAMP peripheral. + * @param NewState: new state of the OPAMP peripheral. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void OPAMP_Cmd(uint32_t OPAMP_Selection, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_OPAMP_ALL_PERIPH(OPAMP_Selection)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable the selected OPAMPx peripheral */ + *(__IO uint32_t *) (OPAMP_BASE + OPAMP_Selection) |= (uint32_t) (OPAMP_CSR_OPAMPxEN); + } + else + { + /* Disable the selected OPAMPx peripheral */ + *(__IO uint32_t *) (OPAMP_BASE + OPAMP_Selection) &= (uint32_t)(~OPAMP_CSR_OPAMPxEN); + } +} + +/** + * @brief Return the output level (high or low) during calibration of the selected OPAMP. + * @param OPAMP_Selection: the selected OPAMP. + * This parameter can be OPAMP_Selection_OPAMPx where x can be 1 to 4 + * to select the OPAMP peripheral. + * - OPAMP output is low when the non-inverting input is at a lower + * voltage than the inverting input + * - OPAMP output is high when the non-inverting input is at a higher + * voltage than the inverting input + * @note OPAMP output level is provided only during calibration phase. + * @retval Returns the selected OPAMP output level: low or high. + * + */ +uint32_t OPAMP_GetOutputLevel(uint32_t OPAMP_Selection) +{ + uint32_t opampout = 0x0; + + /* Check the parameters */ + assert_param(IS_OPAMP_ALL_PERIPH(OPAMP_Selection)); + + /* Check if selected OPAMP output is high */ + if ((*(__IO uint32_t *) (OPAMP_BASE + OPAMP_Selection) & (OPAMP_CSR_OUTCAL)) != 0) + { + opampout = OPAMP_OutputLevel_High; + } + else + { + opampout = OPAMP_OutputLevel_Low; + } + + /* Return the OPAMP output level */ + return (uint32_t)(opampout); +} + +/** + * @brief Select the trimming mode. + * @param OffsetTrimming: the selected offset trimming mode. + * This parameter can be one of the following values: + * @arg OPAMP_Trimming_Factory: factory trimming values are used for offset + * calibration + * @arg OPAMP_Trimming_User: user trimming values are used for offset + * calibration + * @note When OffsetTrimming_User is selected, use OPAMP_OffsetTrimConfig() + * function or OPAMP_OffsetTrimLowPowerConfig() function to adjust + * trimming value. + * @retval None + */ +void OPAMP_OffsetTrimModeSelect(uint32_t OPAMP_Selection, uint32_t OPAMP_Trimming) +{ + /* Check the parameters */ + assert_param(IS_OPAMP_ALL_PERIPH(OPAMP_Selection)); + assert_param(IS_OPAMP_TRIMMING(OPAMP_Trimming)); + + /* Reset USERTRIM bit */ + *(__IO uint32_t *) (OPAMP_BASE + OPAMP_Selection) &= (~(uint32_t) (OPAMP_CSR_USERTRIM)); + + /* Select trimming mode */ + *(__IO uint32_t *) (OPAMP_BASE + OPAMP_Selection) |= OPAMP_Trimming; +} + +/** + * @brief Configure the trimming value of the OPAMP. + * @param OPAMP_Selection: the selected OPAMP. + * This parameter can be OPAMP_Selection_OPAMPx where x can be 1 to 4 + * to select the OPAMP peripheral. + * @param OPAMP_Input: the selected OPAMP input. + * This parameter can be one of the following values: + * @arg OPAMP_Input_Inverting: Inverting input is selected to configure the trimming value + * @arg OPAMP_Input_NonInverting: Non inverting input is selected to configure the trimming value + * @param OPAMP_TrimValue: the trimming value. This parameter can be any value lower + * or equal to 0x0000001F. + * @retval None + */ +void OPAMP_OffsetTrimConfig(uint32_t OPAMP_Selection, uint32_t OPAMP_Input, uint32_t OPAMP_TrimValue) +{ + uint32_t tmpreg = 0; + + /* Check the parameters */ + assert_param(IS_OPAMP_ALL_PERIPH(OPAMP_Selection)); + assert_param(IS_OPAMP_INPUT(OPAMP_Input)); + assert_param(IS_OPAMP_TRIMMINGVALUE(OPAMP_TrimValue)); + + /*!< Get the OPAMPx_CSR register value */ + tmpreg = *(__IO uint32_t *) (OPAMP_BASE + OPAMP_Selection); + + /*!< Clear the trimming bits */ + tmpreg &= ((uint32_t)~(OPAMP_CSR_TRIMMING_MASK<
© COPYRIGHT 2015 STMicroelectronics
+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f30x_pwr.h" +#include "stm32f30x_rcc.h" + +/** @addtogroup STM32F30x_StdPeriph_Driver + * @{ + */ + +/** @defgroup PWR + * @brief PWR driver modules + * @{ + */ + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +/* --------- PWR registers bit address in the alias region ---------- */ +#define PWR_OFFSET (PWR_BASE - PERIPH_BASE) + +/* --- CR Register ---*/ + +/* Alias word address of DBP bit */ +#define CR_OFFSET (PWR_OFFSET + 0x00) +#define DBP_BitNumber 0x08 +#define CR_DBP_BB (PERIPH_BB_BASE + (CR_OFFSET * 32) + (DBP_BitNumber * 4)) + +/* Alias word address of PVDE bit */ +#define PVDE_BitNumber 0x04 +#define CR_PVDE_BB (PERIPH_BB_BASE + (CR_OFFSET * 32) + (PVDE_BitNumber * 4)) + +/* ------------------ PWR registers bit mask ------------------------ */ + +/* CR register bit mask */ +#define CR_DS_MASK ((uint32_t)0xFFFFFFFC) +#define CR_PLS_MASK ((uint32_t)0xFFFFFF1F) + +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/* Private function prototypes -----------------------------------------------*/ +/* Private functions ---------------------------------------------------------*/ + +/** @defgroup PWR_Private_Functions + * @{ + */ + +/** @defgroup PWR_Group1 Backup Domain Access function + * @brief Backup Domain Access function + * +@verbatim + ============================================================================== + ##### Backup Domain Access function ##### + ============================================================================== + + [..] After reset, the Backup Domain Registers (RCC BDCR Register, RTC registers + and RTC backup registers) are protected against possible stray write accesses. + [..] To enable access to Backup domain use the PWR_BackupAccessCmd(ENABLE) function. + +@endverbatim + * @{ + */ + +/** + * @brief Deinitializes the PWR peripheral registers to their default reset values. + * @param None + * @retval None + */ +void PWR_DeInit(void) +{ + RCC_APB1PeriphResetCmd(RCC_APB1Periph_PWR, ENABLE); + RCC_APB1PeriphResetCmd(RCC_APB1Periph_PWR, DISABLE); +} + +/** + * @brief Enables or disables access to the RTC and backup registers. + * @note If the HSE divided by 32 is used as the RTC clock, the + * Backup Domain Access should be kept enabled. + * @param NewState: new state of the access to the RTC and backup registers. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void PWR_BackupAccessCmd(FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_FUNCTIONAL_STATE(NewState)); + *(__IO uint32_t *) CR_DBP_BB = (uint32_t)NewState; +} + +/** + * @} + */ + +/** @defgroup PWR_Group2 PVD configuration functions + * @brief PVD configuration functions + * +@verbatim + =============================================================================== + ##### PVD configuration functions ##### + ============================================================================== + [..] + (+) The PVD is used to monitor the VDD power supply by comparing it to a threshold + selected by the PVD Level (PLS[2:0] bits in the PWR_CR). + (+) A PVDO flag is available to indicate if VDD/VDDA is higher or lower than the + PVD threshold. This event is internally connected to the EXTI line16 + and can generate an interrupt if enabled through the EXTI registers. + (+) The PVD is stopped in Standby mode. + +@endverbatim + * @{ + */ + +/** + * @brief Configures the voltage threshold detected by the Power Voltage Detector(PVD). + * @param PWR_PVDLevel: specifies the PVD detection level + * This parameter can be one of the following values: + * @arg PWR_PVDLevel_0: PVD detection level set to 2.18V + * @arg PWR_PVDLevel_1: PVD detection level set to 2.28V + * @arg PWR_PVDLevel_2: PVD detection level set to 2.38V + * @arg PWR_PVDLevel_3: PVD detection level set to 2.48V + * @arg PWR_PVDLevel_4: PVD detection level set to 2.58V + * @arg PWR_PVDLevel_5: PVD detection level set to 2.68V + * @arg PWR_PVDLevel_6: PVD detection level set to 2.78V + * @arg PWR_PVDLevel_7: PVD detection level set to 2.88V + * @retval None + */ +void PWR_PVDLevelConfig(uint32_t PWR_PVDLevel) +{ + uint32_t tmpreg = 0; + + /* Check the parameters */ + assert_param(IS_PWR_PVD_LEVEL(PWR_PVDLevel)); + + tmpreg = PWR->CR; + + /* Clear PLS[7:5] bits */ + tmpreg &= CR_PLS_MASK; + + /* Set PLS[7:5] bits according to PWR_PVDLevel value */ + tmpreg |= PWR_PVDLevel; + + /* Store the new value */ + PWR->CR = tmpreg; +} + +/** + * @brief Enables or disables the Power Voltage Detector(PVD). + * @param NewState: new state of the PVD. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void PWR_PVDCmd(FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_FUNCTIONAL_STATE(NewState)); + *(__IO uint32_t *) CR_PVDE_BB = (uint32_t)NewState; +} + +/** + * @} + */ + +/** @defgroup PWR_Group3 WakeUp pins configuration functions + * @brief WakeUp pins configuration functions + * +@verbatim + =============================================================================== + ##### WakeUp pins configuration functions ##### + =============================================================================== + [..] + (+) WakeUp pins are used to wakeup the system from Standby mode. These pins are + forced in input pull down configuration and are active on rising edges. + (+) There are three WakeUp pins: WakeUp Pin 1 on PA.00, WakeUp Pin 2 on PC.13 and + WakeUp Pin 3 on PE.06. + +@endverbatim + * @{ + */ + +/** + * @brief Enables or disables the WakeUp Pin functionality. + * @param PWR_WakeUpPin: specifies the WakeUpPin. + * This parameter can be: PWR_WakeUpPin_1, PWR_WakeUpPin_2 or PWR_WakeUpPin_3. + * @param NewState: new state of the WakeUp Pin functionality. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void PWR_WakeUpPinCmd(uint32_t PWR_WakeUpPin, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_PWR_WAKEUP_PIN(PWR_WakeUpPin)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable the EWUPx pin */ + PWR->CSR |= PWR_WakeUpPin; + } + else + { + /* Disable the EWUPx pin */ + PWR->CSR &= ~PWR_WakeUpPin; + } +} + +/** + * @} + */ + + +/** @defgroup PWR_Group4 Low Power modes configuration functions + * @brief Low Power modes configuration functions + * +@verbatim + =============================================================================== + ##### Low Power modes configuration functions ##### + ============================================================================== + + [..] The devices feature three low-power modes: + (+) Sleep mode: Cortex-M4 core stopped, peripherals kept running. + (+) Stop mode: all clocks are stopped, regulator running, regulator in low power mode + (+) Standby mode: VCORE domain powered off + + *** Sleep mode *** + ================== + [..] + (+) Entry: + (++) The Sleep mode is entered by executing the WFE() or WFI() instructions. + (+) Exit: + (++) Any peripheral interrupt acknowledged by the nested vectored interrupt + controller (NVIC) can wake up the device from Sleep mode. + + *** Stop mode *** + ================= + [..] In Stop mode, all clocks in the VCORE domain are stopped, the PLL, the HSI, + and the HSE RC oscillators are disabled. Internal SRAM and register + contents are preserved. + The voltage regulator can be configured either in normal or low-power mode. + + (+) Entry: + (++) The Stop mode is entered using the PWR_EnterSTOPMode(PWR_Regulator_LowPower,) + function with regulator in LowPower or with Regulator ON. + (+) Exit: + (++) Any EXTI Line (Internal or External) configured in Interrupt/Event mode + or any internal IPs (I2C or UASRT) wakeup event. + + *** Standby mode *** + ==================== + [..] The Standby mode allows to achieve the lowest power consumption. It is based + on the Cortex-M4 deepsleep mode, with the voltage regulator disabled. + The VCORE domain is consequently powered off. The PLL, the HSI, and the HSE + oscillator are also switched off. SRAM and register + contents are lost except for the Backup domain (RTC registers, RTC backup + registers and Standby circuitry). + + [..] The voltage regulator is OFF. + + (+) Entry: + (++) The Standby mode is entered using the PWR_EnterSTANDBYMode() function. + (+) Exit: + (++) WKUP pin rising edge, RTC alarm (Alarm A and Alarm B), RTC wakeup, + tamper event, time-stamp event, external reset in NRST pin, IWDG reset. + + *** Auto-wakeup (AWU) from low-power mode *** + ============================================= + [..] The MCU can be woken up from low-power mode by an RTC Alarm event, a tamper + event, a time-stamp event, or a comparator event, without depending on an + external interrupt (Auto-wakeup mode). + + (+) RTC auto-wakeup (AWU) from the Stop mode + (++) To wake up from the Stop mode with an RTC alarm event, it is necessary to: + (+++) Configure the EXTI Line 17 to be sensitive to rising edges (Interrupt + or Event modes) using the EXTI_Init() function. + (+++) Enable the RTC Alarm Interrupt using the RTC_ITConfig() function + (+++) Configure the RTC to generate the RTC alarm using the RTC_SetAlarm() + and RTC_AlarmCmd() functions. + (++) To wake up from the Stop mode with an RTC Tamper or time stamp event, it + is necessary to: + (+++) Configure the EXTI Line 19 to be sensitive to rising edges (Interrupt + or Event modes) using the EXTI_Init() function. + (+++) Enable the RTC Tamper or time stamp Interrupt using the RTC_ITConfig() + function. + (+++) Configure the RTC to detect the tamper or time stamp event using the + RTC_TimeStampConfig(), RTC_TamperTriggerConfig() and RTC_TamperCmd() + functions. + + (+) RTC auto-wakeup (AWU) from the Standby mode + (++) To wake up from the Standby mode with an RTC alarm event, it is necessary to: + (+++) Enable the RTC Alarm Interrupt using the RTC_ITConfig() function. + (+++) Configure the RTC to generate the RTC alarm using the RTC_SetAlarm() + and RTC_AlarmCmd() functions. + (++) To wake up from the Standby mode with an RTC Tamper or time stamp event, it + is necessary to: + (+++) Enable the RTC Tamper or time stamp Interrupt using the RTC_ITConfig() + function. + (+++) Configure the RTC to detect the tamper or time stamp event using the + RTC_TimeStampConfig(), RTC_TamperTriggerConfig() and RTC_TamperCmd() + functions. + + (+) Comparator auto-wakeup (AWU) from the Stop mode + (++) To wake up from the Stop mode with a comparator wakeup event, it is necessary to: + (+++) Configure the correspondent comparator EXTI Line to be sensitive to + the selected edges (falling, rising or falling and rising) + (Interrupt or Event modes) using the EXTI_Init() function. + (+++) Configure the comparator to generate the event. + +@endverbatim + * @{ + */ + +/** + * @brief Enters Sleep mode. + * @note In Sleep mode, all I/O pins keep the same state as in Run mode. + * @param PWR_SLEEPEntry: specifies if SLEEP mode in entered with WFI or WFE instruction. + * This parameter can be one of the following values: + * @arg PWR_SLEEPEntry_WFI: enter SLEEP mode with WFI instruction + * @arg PWR_SLEEPEntry_WFE: enter SLEEP mode with WFE instruction + * @retval None + */ +void PWR_EnterSleepMode(uint8_t PWR_SLEEPEntry) +{ + /* Check the parameters */ + assert_param(IS_PWR_SLEEP_ENTRY(PWR_SLEEPEntry)); + + /* Clear SLEEPDEEP bit of Cortex System Control Register */ + SCB->SCR &= (uint32_t)~((uint32_t)SCB_SCR_SLEEPDEEP_Msk); + + /* Select SLEEP mode entry -------------------------------------------------*/ + if(PWR_SLEEPEntry == PWR_SLEEPEntry_WFI) + { + /* Request Wait For Interrupt */ + __WFI(); + } + else + { + /* Request Wait For Event */ + __SEV(); + __WFE(); + __WFE(); + } +} + +/** + * @brief Enters STOP mode. + * @note In Stop mode, all I/O pins keep the same state as in Run mode. + * @note When exiting Stop mode by issuing an interrupt or a wakeup event, + * the HSI RC oscillator is selected as system clock. + * @note When the voltage regulator operates in low power mode, an additional + * startup delay is incurred when waking up from Stop mode. + * By keeping the internal regulator ON during Stop mode, the consumption + * is higher although the startup time is reduced. + * @param PWR_Regulator: specifies the regulator state in STOP mode. + * This parameter can be one of the following values: + * @arg PWR_Regulator_ON: STOP mode with regulator ON + * @arg PWR_Regulator_LowPower: STOP mode with regulator in low power mode + * @param PWR_STOPEntry: specifies if STOP mode in entered with WFI or WFE instruction. + * This parameter can be one of the following values: + * @arg PWR_STOPEntry_WFI: enter STOP mode with WFI instruction + * @arg PWR_STOPEntry_WFE: enter STOP mode with WFE instruction + * @retval None + */ +void PWR_EnterSTOPMode(uint32_t PWR_Regulator, uint8_t PWR_STOPEntry) +{ + uint32_t tmpreg = 0; + + /* Check the parameters */ + assert_param(IS_PWR_REGULATOR(PWR_Regulator)); + assert_param(IS_PWR_STOP_ENTRY(PWR_STOPEntry)); + + /* Select the regulator state in STOP mode ---------------------------------*/ + tmpreg = PWR->CR; + /* Clear PDDS and LPDSR bits */ + tmpreg &= CR_DS_MASK; + + /* Set LPDSR bit according to PWR_Regulator value */ + tmpreg |= PWR_Regulator; + + /* Store the new value */ + PWR->CR = tmpreg; + + /* Set SLEEPDEEP bit of Cortex System Control Register */ + SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; + + /* Select STOP mode entry --------------------------------------------------*/ + if(PWR_STOPEntry == PWR_STOPEntry_WFI) + { + /* Request Wait For Interrupt */ + __WFI(); + } + else + { + /* Request Wait For Event */ + __WFE(); + } + /* Reset SLEEPDEEP bit of Cortex System Control Register */ + SCB->SCR &= (uint32_t)~((uint32_t)SCB_SCR_SLEEPDEEP_Msk); +} + +/** + * @brief Enters STANDBY mode. + * @note In Standby mode, all I/O pins are high impedance except for: + * @note Reset pad (still available) + * @note RTC_AF1 pin (PC13) if configured for Wakeup pin 2 (WKUP2), tamper, + * time-stamp, RTC Alarm out, or RTC clock calibration out. + * @note WKUP pin 1 (PA0) and WKUP pin 3 (PE6), if enabled. + * @note The Wakeup flag (WUF) need to be cleared at application level before to call this function. + * @param None + * @retval None + */ +void PWR_EnterSTANDBYMode(void) +{ + /* Select STANDBY mode */ + PWR->CR |= PWR_CR_PDDS; + + /* Set SLEEPDEEP bit of Cortex System Control Register */ + SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; + +/* This option is used to ensure that store operations are completed */ +#if defined ( __CC_ARM ) + __force_stores(); +#endif + /* Request Wait For Interrupt */ + __WFI(); +} + +/** + * @} + */ + +/** @defgroup PWR_Group5 Flags management functions + * @brief Flags management functions + * +@verbatim + =============================================================================== + ##### Flags management functions ##### + =============================================================================== + +@endverbatim + * @{ + */ + +/** + * @brief Checks whether the specified PWR flag is set or not. + * @param PWR_FLAG: specifies the flag to check. + * This parameter can be one of the following values: + * @arg PWR_FLAG_WU: Wake Up flag. This flag indicates that a wakeup event + * was received from the WKUP pin or from the RTC alarm (Alarm A or Alarm B), + * RTC Tamper event, RTC TimeStamp event or RTC Wakeup. + * @arg PWR_FLAG_SB: StandBy flag. This flag indicates that the system was + * resumed from StandBy mode. + * @arg PWR_FLAG_PVDO: PVD Output. This flag is valid only if PVD is enabled + * by the PWR_PVDCmd() function. + * @arg PWR_FLAG_VREFINTRDY: Internal Voltage Reference Ready flag. This + * flag indicates the state of the internal voltage reference, VREFINT. + * @retval The new state of PWR_FLAG (SET or RESET). + */ +FlagStatus PWR_GetFlagStatus(uint32_t PWR_FLAG) +{ + FlagStatus bitstatus = RESET; + /* Check the parameters */ + assert_param(IS_PWR_GET_FLAG(PWR_FLAG)); + + if ((PWR->CSR & PWR_FLAG) != (uint32_t)RESET) + { + bitstatus = SET; + } + else + { + bitstatus = RESET; + } + /* Return the flag status */ + return bitstatus; +} + +/** + * @brief Clears the PWR's pending flags. + * @param PWR_FLAG: specifies the flag to clear. + * This parameter can be one of the following values: + * @arg PWR_FLAG_WU: Wake Up flag + * @arg PWR_FLAG_SB: StandBy flag + * @retval None + */ +void PWR_ClearFlag(uint32_t PWR_FLAG) +{ + /* Check the parameters */ + assert_param(IS_PWR_CLEAR_FLAG(PWR_FLAG)); + + PWR->CR |= PWR_FLAG << 2; +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_rcc.c b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_rcc.c new file mode 100755 index 0000000000..f8568fa301 --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_rcc.c @@ -0,0 +1,2017 @@ +/** + ****************************************************************************** + * @file stm32f30x_rcc.c + * @author MCD Application Team + * @version V1.2.3 + * @date 10-July-2015 + * @brief This file provides firmware functions to manage the following + * functionalities of the Reset and clock control (RCC) peripheral: + * + Internal/external clocks, PLL, CSS and MCO configuration + * + System, AHB and APB busses clocks configuration + * + Peripheral clocks configuration + * + Interrupts and flags management + * + @verbatim + + =============================================================================== + ##### RCC specific features ##### + =============================================================================== + [..] After reset the device is running from HSI (8 MHz) with Flash 0 WS, + all peripherals are off except internal SRAM, Flash and SWD. + (+) There is no prescaler on High speed (AHB) and Low speed (APB) busses; + all peripherals mapped on these busses are running at HSI speed. + (+) The clock for all peripherals is switched off, except the SRAM and FLASH. + (+) All GPIOs are in input floating state, except the SWD pins which + are assigned to be used for debug purpose. + [..] Once the device starts from reset, the user application has to: + (+) Configure the clock source to be used to drive the System clock + (if the application needs higher frequency/performance). + (+) Configure the System clock frequency and Flash settings. + (+) Configure the AHB and APB busses prescalers. + (+) Enable the clock for the peripheral(s) to be used. + (+) Configure the clock source(s) for peripherals which clocks are not + derived from the System clock (ADC, TIM, I2C, USART, RTC and IWDG). + + @endverbatim + + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f30x_rcc.h" + +/** @addtogroup STM32F30x_StdPeriph_Driver + * @{ + */ + +/** @defgroup RCC + * @brief RCC driver modules + * @{ + */ + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +/* ------------ RCC registers bit address in the alias region ----------- */ +#define RCC_OFFSET (RCC_BASE - PERIPH_BASE) + +/* --- CR Register ---*/ + +/* Alias word address of HSION bit */ +#define CR_OFFSET (RCC_OFFSET + 0x00) +#define HSION_BitNumber 0x00 +#define CR_HSION_BB (PERIPH_BB_BASE + (CR_OFFSET * 32) + (HSION_BitNumber * 4)) + +/* Alias word address of PLLON bit */ +#define PLLON_BitNumber 0x18 +#define CR_PLLON_BB (PERIPH_BB_BASE + (CR_OFFSET * 32) + (PLLON_BitNumber * 4)) + +/* Alias word address of CSSON bit */ +#define CSSON_BitNumber 0x13 +#define CR_CSSON_BB (PERIPH_BB_BASE + (CR_OFFSET * 32) + (CSSON_BitNumber * 4)) + +/* --- CFGR Register ---*/ +/* Alias word address of USBPRE bit */ +#define CFGR_OFFSET (RCC_OFFSET + 0x04) +#define USBPRE_BitNumber 0x16 +#define CFGR_USBPRE_BB (PERIPH_BB_BASE + (CFGR_OFFSET * 32) + (USBPRE_BitNumber * 4)) +/* Alias word address of I2SSRC bit */ +#define I2SSRC_BitNumber 0x17 +#define CFGR_I2SSRC_BB (PERIPH_BB_BASE + (CFGR_OFFSET * 32) + (I2SSRC_BitNumber * 4)) + +/* --- BDCR Register ---*/ + +/* Alias word address of RTCEN bit */ +#define BDCR_OFFSET (RCC_OFFSET + 0x20) +#define RTCEN_BitNumber 0x0F +#define BDCR_RTCEN_BB (PERIPH_BB_BASE + (BDCR_OFFSET * 32) + (RTCEN_BitNumber * 4)) + +/* Alias word address of BDRST bit */ +#define BDRST_BitNumber 0x10 +#define BDCR_BDRST_BB (PERIPH_BB_BASE + (BDCR_OFFSET * 32) + (BDRST_BitNumber * 4)) + +/* --- CSR Register ---*/ + +/* Alias word address of LSION bit */ +#define CSR_OFFSET (RCC_OFFSET + 0x24) +#define LSION_BitNumber 0x00 +#define CSR_LSION_BB (PERIPH_BB_BASE + (CSR_OFFSET * 32) + (LSION_BitNumber * 4)) + +/* ---------------------- RCC registers bit mask ------------------------ */ +/* RCC Flag Mask */ +#define FLAG_MASK ((uint8_t)0x1F) + +/* CFGR register byte 3 (Bits[31:23]) base address */ +#define CFGR_BYTE3_ADDRESS ((uint32_t)0x40021007) + +/* CIR register byte 2 (Bits[15:8]) base address */ +#define CIR_BYTE2_ADDRESS ((uint32_t)0x40021009) + +/* CIR register byte 3 (Bits[23:16]) base address */ +#define CIR_BYTE3_ADDRESS ((uint32_t)0x4002100A) + +/* CR register byte 2 (Bits[23:16]) base address */ +#define CR_BYTE2_ADDRESS ((uint32_t)0x40021002) + +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +static __I uint8_t APBAHBPrescTable[16] = {0, 0, 0, 0, 1, 2, 3, 4, 1, 2, 3, 4, 6, 7, 8, 9}; +static __I uint16_t ADCPrescTable[16] = {1, 2, 4, 6, 8, 10, 12, 16, 32, 64, 128, 256, 0, 0, 0, 0 }; + +/* Private function prototypes -----------------------------------------------*/ +/* Private functions ---------------------------------------------------------*/ + +/** @defgroup RCC_Private_Functions + * @{ + */ + +/** @defgroup RCC_Group1 Internal and external clocks, PLL, CSS and MCO configuration functions + * @brief Internal and external clocks, PLL, CSS and MCO configuration functions + * +@verbatim + =============================================================================== + ##### Internal-external clocks, PLL, CSS and MCO configuration functions ##### + =============================================================================== + [..] This section provides functions allowing to configure the internal/external + clocks, PLL, CSS and MCO. + (#) HSI (high-speed internal), 8 MHz factory-trimmed RC used directly + or through the PLL as System clock source. + The HSI clock can be used also to clock the USART and I2C peripherals. + (#) LSI (low-speed internal), 40 KHz low consumption RC used as IWDG and/or RTC + clock source. + (#) HSE (high-speed external), 4 to 32 MHz crystal oscillator used directly or + through the PLL as System clock source. Can be used also as RTC clock source. + (#) LSE (low-speed external), 32 KHz oscillator used as RTC clock source. + LSE can be used also to clock the USART peripherals. + (#) PLL (clocked by HSI or HSE), for System clock. + (#) CSS (Clock security system), once enabled and if a HSE clock failure occurs + (HSE used directly or through PLL as System clock source), the System clock + is automatically switched to HSI and an interrupt is generated if enabled. + The interrupt is linked to the Cortex-M4 NMI (Non-Maskable Interrupt) + exception vector. + (#) MCO (microcontroller clock output), used to output SYSCLK, HSI, HSE, LSI, LSE, + PLL clock on PA8 pin. + +@endverbatim + * @{ + */ + +/** + * @brief Resets the RCC clock configuration to the default reset state. + * @note The default reset state of the clock configuration is given below: + * - HSI ON and used as system clock source + * - HSE, PLL and PLLI2S OFF + * - AHB, APB1 and APB2 prescaler set to 1. + * - CSS and MCO OFF + * - All interrupts disabled + * @note However, This function doesn't modify the configuration of the + * - Peripheral clocks + * - LSI, LSE and RTC clocks + * @param None + * @retval None + */ +void RCC_DeInit(void) +{ + /* Set HSION bit */ + RCC->CR |= (uint32_t)0x00000001; + + /* Reset SW[1:0], HPRE[3:0], PPRE[2:0] and MCOSEL[2:0] bits */ + RCC->CFGR &= (uint32_t)0xF8FFC000; + + /* Reset HSEON, CSSON and PLLON bits */ + RCC->CR &= (uint32_t)0xFEF6FFFF; + + /* Reset HSEBYP bit */ + RCC->CR &= (uint32_t)0xFFFBFFFF; + + /* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE bits */ + RCC->CFGR &= (uint32_t)0xFF80FFFF; + + /* Reset PREDIV1[3:0] and ADCPRE[13:4] bits */ + RCC->CFGR2 &= (uint32_t)0xFFFFC000; + + /* Reset USARTSW[1:0], I2CSW and TIMSW bits */ + RCC->CFGR3 &= (uint32_t)0xF00ECCC; + + /* Disable all interrupts */ + RCC->CIR = 0x00000000; +} + +/** + * @brief Configures the External High Speed oscillator (HSE). + * @note After enabling the HSE (RCC_HSE_ON or RCC_HSE_Bypass), the application + * software should wait on HSERDY flag to be set indicating that HSE clock + * is stable and can be used to clock the PLL and/or system clock. + * @note HSE state can not be changed if it is used directly or through the + * PLL as system clock. In this case, you have to select another source + * of the system clock then change the HSE state (ex. disable it). + * @note The HSE is stopped by hardware when entering STOP and STANDBY modes. + * @note This function resets the CSSON bit, so if the Clock security system(CSS) + * was previously enabled you have to enable it again after calling this + * function. + * @param RCC_HSE: specifies the new state of the HSE. + * This parameter can be one of the following values: + * @arg RCC_HSE_OFF: turn OFF the HSE oscillator, HSERDY flag goes low after + * 6 HSE oscillator clock cycles. + * @arg RCC_HSE_ON: turn ON the HSE oscillator + * @arg RCC_HSE_Bypass: HSE oscillator bypassed with external clock + * @retval None + */ +void RCC_HSEConfig(uint8_t RCC_HSE) +{ + /* Check the parameters */ + assert_param(IS_RCC_HSE(RCC_HSE)); + + /* Reset HSEON and HSEBYP bits before configuring the HSE ------------------*/ + *(__IO uint8_t *) CR_BYTE2_ADDRESS = RCC_HSE_OFF; + + /* Set the new HSE configuration -------------------------------------------*/ + *(__IO uint8_t *) CR_BYTE2_ADDRESS = RCC_HSE; + +} + +/** + * @brief Waits for HSE start-up. + * @note This function waits on HSERDY flag to be set and return SUCCESS if + * this flag is set, otherwise returns ERROR if the timeout is reached + * and this flag is not set. The timeout value is defined by the constant + * HSE_STARTUP_TIMEOUT in stm32f30x.h file. You can tailor it depending + * on the HSE crystal used in your application. + * @param None + * @retval An ErrorStatus enumeration value: + * - SUCCESS: HSE oscillator is stable and ready to use + * - ERROR: HSE oscillator not yet ready + */ +ErrorStatus RCC_WaitForHSEStartUp(void) +{ + __IO uint32_t StartUpCounter = 0; + ErrorStatus status = ERROR; + FlagStatus HSEStatus = RESET; + + /* Wait till HSE is ready and if timeout is reached exit */ + do + { + HSEStatus = RCC_GetFlagStatus(RCC_FLAG_HSERDY); + StartUpCounter++; + } while((StartUpCounter != HSE_STARTUP_TIMEOUT) && (HSEStatus == RESET)); + + if (RCC_GetFlagStatus(RCC_FLAG_HSERDY) != RESET) + { + status = SUCCESS; + } + else + { + status = ERROR; + } + return (status); +} + +/** + * @brief Adjusts the Internal High Speed oscillator (HSI) calibration value. + * @note The calibration is used to compensate for the variations in voltage + * and temperature that influence the frequency of the internal HSI RC. + * Refer to the Application Note AN3300 for more details on how to + * calibrate the HSI. + * @param HSICalibrationValue: specifies the HSI calibration trimming value. + * This parameter must be a number between 0 and 0x1F. + * @retval None + */ +void RCC_AdjustHSICalibrationValue(uint8_t HSICalibrationValue) +{ + uint32_t tmpreg = 0; + + /* Check the parameters */ + assert_param(IS_RCC_HSI_CALIBRATION_VALUE(HSICalibrationValue)); + + tmpreg = RCC->CR; + + /* Clear HSITRIM[4:0] bits */ + tmpreg &= ~RCC_CR_HSITRIM; + + /* Set the HSITRIM[4:0] bits according to HSICalibrationValue value */ + tmpreg |= (uint32_t)HSICalibrationValue << 3; + + /* Store the new value */ + RCC->CR = tmpreg; +} + +/** + * @brief Enables or disables the Internal High Speed oscillator (HSI). + * @note After enabling the HSI, the application software should wait on + * HSIRDY flag to be set indicating that HSI clock is stable and can + * be used to clock the PLL and/or system clock. + * @note HSI can not be stopped if it is used directly or through the PLL + * as system clock. In this case, you have to select another source + * of the system clock then stop the HSI. + * @note The HSI is stopped by hardware when entering STOP and STANDBY modes. + * @note When the HSI is stopped, HSIRDY flag goes low after 6 HSI oscillator + * clock cycles. + * @param NewState: new state of the HSI. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void RCC_HSICmd(FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + *(__IO uint32_t *) CR_HSION_BB = (uint32_t)NewState; +} + +/** + * @brief Configures the External Low Speed oscillator (LSE). + * @note As the LSE is in the Backup domain and write access is denied to this + * domain after reset, you have to enable write access using + * PWR_BackupAccessCmd(ENABLE) function before to configure the LSE + * (to be done once after reset). + * @note Care must be taken when using this function to configure LSE mode + * as it clears systematically the LSEON bit before any new configuration. + * @note After enabling the LSE (RCC_LSE_ON or RCC_LSE_Bypass), the application + * software should wait on LSERDY flag to be set indicating that LSE clock + * is stable and can be used to clock the RTC. + * @param RCC_LSE: specifies the new state of the LSE. + * This parameter can be one of the following values: + * @arg RCC_LSE_OFF: turn OFF the LSE oscillator, LSERDY flag goes low after + * 6 LSE oscillator clock cycles. + * @arg RCC_LSE_ON: turn ON the LSE oscillator + * @arg RCC_LSE_Bypass: LSE oscillator bypassed with external clock + * @retval None + */ +void RCC_LSEConfig(uint32_t RCC_LSE) +{ + /* Check the parameters */ + assert_param(IS_RCC_LSE(RCC_LSE)); + + /* Reset LSEON and LSEBYP bits before configuring the LSE ------------------*/ + /* Reset LSEON bit */ + RCC->BDCR &= ~(RCC_BDCR_LSEON); + + /* Reset LSEBYP bit */ + RCC->BDCR &= ~(RCC_BDCR_LSEBYP); + + /* Configure LSE */ + RCC->BDCR |= RCC_LSE; +} + +/** + * @brief Configures the External Low Speed oscillator (LSE) drive capability. + * @param RCC_LSEDrive: specifies the new state of the LSE drive capability. + * This parameter can be one of the following values: + * @arg RCC_LSEDrive_Low: LSE oscillator low drive capability. + * @arg RCC_LSEDrive_MediumLow: LSE oscillator medium low drive capability. + * @arg RCC_LSEDrive_MediumHigh: LSE oscillator medium high drive capability. + * @arg RCC_LSEDrive_High: LSE oscillator high drive capability. + * @retval None + */ +void RCC_LSEDriveConfig(uint32_t RCC_LSEDrive) +{ + /* Check the parameters */ + assert_param(IS_RCC_LSE_DRIVE(RCC_LSEDrive)); + + /* Clear LSEDRV[1:0] bits */ + RCC->BDCR &= ~(RCC_BDCR_LSEDRV); + + /* Set the LSE Drive */ + RCC->BDCR |= RCC_LSEDrive; +} + +/** + * @brief Enables or disables the Internal Low Speed oscillator (LSI). + * @note After enabling the LSI, the application software should wait on + * LSIRDY flag to be set indicating that LSI clock is stable and can + * be used to clock the IWDG and/or the RTC. + * @note LSI can not be disabled if the IWDG is running. + * @note When the LSI is stopped, LSIRDY flag goes low after 6 LSI oscillator + * clock cycles. + * @param NewState: new state of the LSI. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void RCC_LSICmd(FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + *(__IO uint32_t *) CSR_LSION_BB = (uint32_t)NewState; +} + +/** + * @brief Configures the PLL clock source and multiplication factor. + * @note This function must be used only when the PLL is disabled. + * @note The minimum input clock frequency for PLL is 2 MHz (when using HSE as + * PLL source). + * @param RCC_PLLSource: specifies the PLL entry clock source. + * This parameter can be one of the following values: + * @arg RCC_PLLSource_HSI: HSI oscillator clockselected as PLL clock entry + * @arg RCC_PLLSource_HSI_Div2: HSI oscillator clock divided by 2 selected as + * PLL clock entry + * @arg RCC_PLLSource_PREDIV1: PREDIV1 clock selected as PLL clock source + * @param RCC_PLLMul: specifies the PLL multiplication factor, which drive the PLLVCO clock + * This parameter can be RCC_PLLMul_x where x:[2,16] + * + * @retval None + */ +void RCC_PLLConfig(uint32_t RCC_PLLSource, uint32_t RCC_PLLMul) +{ + /* Check the parameters */ + assert_param(IS_RCC_PLL_SOURCE(RCC_PLLSource)); + assert_param(IS_RCC_PLL_MUL(RCC_PLLMul)); + + /* Clear PLL Source [16] and Multiplier [21:18] bits */ + RCC->CFGR &= ~(RCC_CFGR_PLLMULL | RCC_CFGR_PLLSRC); + + /* Set the PLL Source and Multiplier */ + RCC->CFGR |= (uint32_t)(RCC_PLLSource | RCC_PLLMul); +} + +/** + * @brief Enables or disables the PLL. + * @note After enabling the PLL, the application software should wait on + * PLLRDY flag to be set indicating that PLL clock is stable and can + * be used as system clock source. + * @note The PLL can not be disabled if it is used as system clock source + * @note The PLL is disabled by hardware when entering STOP and STANDBY modes. + * @param NewState: new state of the PLL. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void RCC_PLLCmd(FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + *(__IO uint32_t *) CR_PLLON_BB = (uint32_t)NewState; +} + +/** + * @brief Configures the PREDIV1 division factor. + * @note This function must be used only when the PLL is disabled. + * @param RCC_PREDIV1_Div: specifies the PREDIV1 clock division factor. + * This parameter can be RCC_PREDIV1_Divx where x:[1,16] + * @retval None + */ +void RCC_PREDIV1Config(uint32_t RCC_PREDIV1_Div) +{ + uint32_t tmpreg = 0; + + /* Check the parameters */ + assert_param(IS_RCC_PREDIV1(RCC_PREDIV1_Div)); + + tmpreg = RCC->CFGR2; + /* Clear PREDIV1[3:0] bits */ + tmpreg &= ~(RCC_CFGR2_PREDIV1); + + /* Set the PREDIV1 division factor */ + tmpreg |= RCC_PREDIV1_Div; + + /* Store the new value */ + RCC->CFGR2 = tmpreg; +} + +/** + * @brief Enables or disables the Clock Security System. + * @note If a failure is detected on the HSE oscillator clock, this oscillator + * is automatically disabled and an interrupt is generated to inform the + * software about the failure (Clock Security System Interrupt, CSSI), + * allowing the MCU to perform rescue operations. The CSSI is linked to + * the Cortex-M4 NMI (Non-Maskable Interrupt) exception vector. + * @param NewState: new state of the Clock Security System. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void RCC_ClockSecuritySystemCmd(FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + *(__IO uint32_t *) CR_CSSON_BB = (uint32_t)NewState; +} + +#ifdef STM32F303xC +/** + * @brief Selects the clock source to output on MCO pin (PA8). + * @note PA8 should be configured in alternate function mode. + * @param RCC_MCOSource: specifies the clock source to output. + * This parameter can be one of the following values: + * @arg RCC_MCOSource_NoClock: No clock selected. + * @arg RCC_MCOSource_LSI: LSI oscillator clock selected. + * @arg RCC_MCOSource_LSE: LSE oscillator clock selected. + * @arg RCC_MCOSource_SYSCLK: System clock selected. + * @arg RCC_MCOSource_HSI: HSI oscillator clock selected. + * @arg RCC_MCOSource_HSE: HSE oscillator clock selected. + * @arg RCC_MCOSource_PLLCLK_Div2: PLL clock divided by 2 selected. + * @retval None + */ +void RCC_MCOConfig(uint8_t RCC_MCOSource) +{ + uint32_t tmpreg = 0; + + /* Check the parameters */ + assert_param(IS_RCC_MCO_SOURCE(RCC_MCOSource)); + + /* Get CFGR value */ + tmpreg = RCC->CFGR; + /* Clear MCO[3:0] bits */ + tmpreg &= ~(RCC_CFGR_MCO | RCC_CFGR_PLLNODIV); + /* Set the RCC_MCOSource */ + tmpreg |= RCC_MCOSource<<24; + /* Store the new value */ + RCC->CFGR = tmpreg; +} +#else + +/** + * @brief Selects the clock source to output on MCO pin (PA8) and the corresponding + * prescsaler. + * @note PA8 should be configured in alternate function mode. + * @param RCC_MCOSource: specifies the clock source to output. + * This parameter can be one of the following values: + * @arg RCC_MCOSource_NoClock: No clock selected. + * @arg RCC_MCOSource_LSI: LSI oscillator clock selected. + * @arg RCC_MCOSource_LSE: LSE oscillator clock selected. + * @arg RCC_MCOSource_SYSCLK: System clock selected. + * @arg RCC_MCOSource_HSI: HSI oscillator clock selected. + * @arg RCC_MCOSource_HSE: HSE oscillator clock selected. + * @arg RCC_MCOSource_PLLCLK_Div2: PLL clock divided by 2 selected. + * @arg RCC_MCOSource_PLLCLK: PLL clock selected. + * @param RCC_MCOPrescaler: specifies the prescaler on MCO pin. + * This parameter can be one of the following values: + * @arg RCC_MCOPrescaler_1: MCO clock is divided by 1. + * @arg RCC_MCOPrescaler_2: MCO clock is divided by 2. + * @arg RCC_MCOPrescaler_4: MCO clock is divided by 4. + * @arg RCC_MCOPrescaler_8: MCO clock is divided by 8. + * @arg RCC_MCOPrescaler_16: MCO clock is divided by 16. + * @arg RCC_MCOPrescaler_32: MCO clock is divided by 32. + * @arg RCC_MCOPrescaler_64: MCO clock is divided by 64. + * @arg RCC_MCOPrescaler_128: MCO clock is divided by 128. + * @retval None + */ +void RCC_MCOConfig(uint8_t RCC_MCOSource, uint32_t RCC_MCOPrescaler) +{ + uint32_t tmpreg = 0; + + /* Check the parameters */ + assert_param(IS_RCC_MCO_SOURCE(RCC_MCOSource)); + assert_param(IS_RCC_MCO_PRESCALER(RCC_MCOPrescaler)); + + /* Get CFGR value */ + tmpreg = RCC->CFGR; + /* Clear MCOPRE[2:0] bits */ + tmpreg &= ~(RCC_CFGR_MCO_PRE | RCC_CFGR_MCO | RCC_CFGR_PLLNODIV); + /* Set the RCC_MCOSource and RCC_MCOPrescaler */ + tmpreg |= (RCC_MCOPrescaler | RCC_MCOSource<<24); + /* Store the new value */ + RCC->CFGR = tmpreg; +} +#endif /* STM32F303xC */ + +/** + * @} + */ + +/** @defgroup RCC_Group2 System AHB, APB1 and APB2 busses clocks configuration functions + * @brief System, AHB and APB busses clocks configuration functions + * +@verbatim + =============================================================================== + ##### System, AHB, APB1 and APB2 busses clocks configuration functions ##### + =============================================================================== + [..] This section provide functions allowing to configure the System, AHB, APB1 and + APB2 busses clocks. + (#) Several clock sources can be used to drive the System clock (SYSCLK): HSI, + HSE and PLL. + The AHB clock (HCLK) is derived from System clock through configurable prescaler + and used to clock the CPU, memory and peripherals mapped on AHB bus (DMA and GPIO). + APB1 (PCLK1) and APB2 (PCLK2) clocks are derived from AHB clock through + configurable prescalers and used to clock the peripherals mapped on these busses. + You can use "RCC_GetClocksFreq()" function to retrieve the frequencies of these clocks. + + (#) The maximum frequency of the SYSCLK, HCLK, PCLK1 and PCLK2 is 72 MHz. + Depending on the maximum frequency, the FLASH wait states (WS) should be + adapted accordingly: + +---------------------------------+ + | Wait states | HCLK clock | + | (Latency) | frequency (MHz) | + |-------------- |-----------------| + |0WS(1CPU cycle)| 0 < HCLK <= 24 | + |---------------|-----------------| + |1WS(2CPU cycle)|24 < HCLK <=48 | + |---------------|-----------------| + |2WS(3CPU cycle)|48 < HCLK <= 72 | + +---------------------------------+ + + (#) After reset, the System clock source is the HSI (8 MHz) with 0 WS and + prefetch is disabled. + [..] + (@) All the peripheral clocks are derived from the System clock (SYSCLK) + except: + (+@) The FLASH program/erase clock which is always HSI 8MHz clock. + (+@) The USB 48 MHz clock which is derived from the PLL VCO clock. + (+@) The USART clock which can be derived as well from HSI 8MHz, LSI or LSE. + (+@) The I2C clock which can be derived as well from HSI 8MHz clock. + (+@) The ADC clock which is derived from PLL output. + (+@) The RTC clock which is derived from the LSE, LSI or 1 MHz HSE_RTC + (HSE divided by a programmable prescaler). The System clock (SYSCLK) + frequency must be higher or equal to the RTC clock frequency. + (+@) IWDG clock which is always the LSI clock. + [..] It is recommended to use the following software sequences to tune the number + of wait states needed to access the Flash memory with the CPU frequency (HCLK). + (+) Increasing the CPU frequency + (++) Program the Flash Prefetch buffer, using "FLASH_PrefetchBufferCmd(ENABLE)" + function + (++) Check that Flash Prefetch buffer activation is taken into account by + reading FLASH_ACR using the FLASH_GetPrefetchBufferStatus() function + (++) Program Flash WS to 1 or 2, using "FLASH_SetLatency()" function + (++) Check that the new number of WS is taken into account by reading FLASH_ACR + (++) Modify the CPU clock source, using "RCC_SYSCLKConfig()" function + (++) If needed, modify the CPU clock prescaler by using "RCC_HCLKConfig()" function + (++) Check that the new CPU clock source is taken into account by reading + the clock source status, using "RCC_GetSYSCLKSource()" function + (+) Decreasing the CPU frequency + (++) Modify the CPU clock source, using "RCC_SYSCLKConfig()" function + (++) If needed, modify the CPU clock prescaler by using "RCC_HCLKConfig()" function + (++) Check that the new CPU clock source is taken into account by reading + the clock source status, using "RCC_GetSYSCLKSource()" function + (++) Program the new number of WS, using "FLASH_SetLatency()" function + (++) Check that the new number of WS is taken into account by reading FLASH_ACR + (++) Disable the Flash Prefetch buffer using "FLASH_PrefetchBufferCmd(DISABLE)" + function + (++) Check that Flash Prefetch buffer deactivation is taken into account by reading FLASH_ACR + using the FLASH_GetPrefetchBufferStatus() function. + +@endverbatim + * @{ + */ + +/** + * @brief Configures the system clock (SYSCLK). + * @note The HSI is used (enabled by hardware) as system clock source after + * startup from Reset, wake-up from STOP and STANDBY mode, or in case + * of failure of the HSE used directly or indirectly as system clock + * (if the Clock Security System CSS is enabled). + * @note A switch from one clock source to another occurs only if the target + * clock source is ready (clock stable after startup delay or PLL locked). + * If a clock source which is not yet ready is selected, the switch will + * occur when the clock source will be ready. + * You can use RCC_GetSYSCLKSource() function to know which clock is + * currently used as system clock source. + * @param RCC_SYSCLKSource: specifies the clock source used as system clock source + * This parameter can be one of the following values: + * @arg RCC_SYSCLKSource_HSI: HSI selected as system clock source + * @arg RCC_SYSCLKSource_HSE: HSE selected as system clock source + * @arg RCC_SYSCLKSource_PLLCLK: PLL selected as system clock source + * @retval None + */ +void RCC_SYSCLKConfig(uint32_t RCC_SYSCLKSource) +{ + uint32_t tmpreg = 0; + + /* Check the parameters */ + assert_param(IS_RCC_SYSCLK_SOURCE(RCC_SYSCLKSource)); + + tmpreg = RCC->CFGR; + + /* Clear SW[1:0] bits */ + tmpreg &= ~RCC_CFGR_SW; + + /* Set SW[1:0] bits according to RCC_SYSCLKSource value */ + tmpreg |= RCC_SYSCLKSource; + + /* Store the new value */ + RCC->CFGR = tmpreg; +} + +/** + * @brief Returns the clock source used as system clock. + * @param None + * @retval The clock source used as system clock. The returned value can be one + * of the following values: + * - 0x00: HSI used as system clock + * - 0x04: HSE used as system clock + * - 0x08: PLL used as system clock + */ +uint8_t RCC_GetSYSCLKSource(void) +{ + return ((uint8_t)(RCC->CFGR & RCC_CFGR_SWS)); +} + +/** + * @brief Configures the AHB clock (HCLK). + * @note Depending on the device voltage range, the software has to set correctly + * these bits to ensure that the system frequency does not exceed the + * maximum allowed frequency (for more details refer to section above + * "CPU, AHB and APB busses clocks configuration functions"). + * @param RCC_SYSCLK: defines the AHB clock divider. This clock is derived from + * the system clock (SYSCLK). + * This parameter can be one of the following values: + * @arg RCC_SYSCLK_Div1: AHB clock = SYSCLK + * @arg RCC_SYSCLK_Div2: AHB clock = SYSCLK/2 + * @arg RCC_SYSCLK_Div4: AHB clock = SYSCLK/4 + * @arg RCC_SYSCLK_Div8: AHB clock = SYSCLK/8 + * @arg RCC_SYSCLK_Div16: AHB clock = SYSCLK/16 + * @arg RCC_SYSCLK_Div64: AHB clock = SYSCLK/64 + * @arg RCC_SYSCLK_Div128: AHB clock = SYSCLK/128 + * @arg RCC_SYSCLK_Div256: AHB clock = SYSCLK/256 + * @arg RCC_SYSCLK_Div512: AHB clock = SYSCLK/512 + * @retval None + */ +void RCC_HCLKConfig(uint32_t RCC_SYSCLK) +{ + uint32_t tmpreg = 0; + + /* Check the parameters */ + assert_param(IS_RCC_HCLK(RCC_SYSCLK)); + + tmpreg = RCC->CFGR; + + /* Clear HPRE[3:0] bits */ + tmpreg &= ~RCC_CFGR_HPRE; + + /* Set HPRE[3:0] bits according to RCC_SYSCLK value */ + tmpreg |= RCC_SYSCLK; + + /* Store the new value */ + RCC->CFGR = tmpreg; +} + +/** + * @brief Configures the Low Speed APB clock (PCLK1). + * @param RCC_HCLK: defines the APB1 clock divider. This clock is derived from + * the AHB clock (HCLK). + * This parameter can be one of the following values: + * @arg RCC_HCLK_Div1: APB1 clock = HCLK + * @arg RCC_HCLK_Div2: APB1 clock = HCLK/2 + * @arg RCC_HCLK_Div4: APB1 clock = HCLK/4 + * @arg RCC_HCLK_Div8: APB1 clock = HCLK/8 + * @arg RCC_HCLK_Div16: APB1 clock = HCLK/16 + * @retval None + */ +void RCC_PCLK1Config(uint32_t RCC_HCLK) +{ + uint32_t tmpreg = 0; + + /* Check the parameters */ + assert_param(IS_RCC_PCLK(RCC_HCLK)); + + tmpreg = RCC->CFGR; + /* Clear PPRE1[2:0] bits */ + tmpreg &= ~RCC_CFGR_PPRE1; + + /* Set PPRE1[2:0] bits according to RCC_HCLK value */ + tmpreg |= RCC_HCLK; + + /* Store the new value */ + RCC->CFGR = tmpreg; +} + +/** + * @brief Configures the High Speed APB clock (PCLK2). + * @param RCC_HCLK: defines the APB2 clock divider. This clock is derived from + * the AHB clock (HCLK). + * This parameter can be one of the following values: + * @arg RCC_HCLK_Div1: APB2 clock = HCLK + * @arg RCC_HCLK_Div2: APB2 clock = HCLK/2 + * @arg RCC_HCLK_Div4: APB2 clock = HCLK/4 + * @arg RCC_HCLK_Div8: APB2 clock = HCLK/8 + * @arg RCC_HCLK_Div16: APB2 clock = HCLK/16 + * @retval None + */ +void RCC_PCLK2Config(uint32_t RCC_HCLK) +{ + uint32_t tmpreg = 0; + + /* Check the parameters */ + assert_param(IS_RCC_PCLK(RCC_HCLK)); + + tmpreg = RCC->CFGR; + /* Clear PPRE2[2:0] bits */ + tmpreg &= ~RCC_CFGR_PPRE2; + /* Set PPRE2[2:0] bits according to RCC_HCLK value */ + tmpreg |= RCC_HCLK << 3; + /* Store the new value */ + RCC->CFGR = tmpreg; +} + +/** + * @brief Returns the frequencies of the System, AHB, APB2 and APB1 busses clocks. + * + * @note This function returns the frequencies of : + * System, AHB, APB2 and APB1 busses clocks, ADC1/2/3/4 clocks, + * USART1/2/3/4/5 clocks, I2C1/2 clocks and TIM1/8 Clocks. + * + * @note The frequency returned by this function is not the real frequency + * in the chip. It is calculated based on the predefined constant and + * the source selected by RCC_SYSCLKConfig(). + * + * @note If SYSCLK source is HSI, function returns constant HSI_VALUE(*) + * + * @note If SYSCLK source is HSE, function returns constant HSE_VALUE(**) + * + * @note If SYSCLK source is PLL, function returns constant HSE_VALUE(**) + * or HSI_VALUE(*) multiplied by the PLL factors. + * + * @note (*) HSI_VALUE is a constant defined in stm32f30x.h file (default value + * 8 MHz) but the real value may vary depending on the variations + * in voltage and temperature, refer to RCC_AdjustHSICalibrationValue(). + * + * @note (**) HSE_VALUE is a constant defined in stm32f30x.h file (default value + * 8 MHz), user has to ensure that HSE_VALUE is same as the real + * frequency of the crystal used. Otherwise, this function may + * return wrong result. + * + * @note The result of this function could be not correct when using fractional + * value for HSE crystal. + * + * @param RCC_Clocks: pointer to a RCC_ClocksTypeDef structure which will hold + * the clocks frequencies. + * + * @note This function can be used by the user application to compute the + * baudrate for the communication peripherals or configure other parameters. + * @note Each time SYSCLK, HCLK, PCLK1 and/or PCLK2 clock changes, this function + * must be called to update the structure's field. Otherwise, any + * configuration based on this function will be incorrect. + * + * @retval None + */ +void RCC_GetClocksFreq(RCC_ClocksTypeDef* RCC_Clocks) +{ + uint32_t tmp = 0, pllmull = 0, pllsource = 0, prediv1factor = 0, presc = 0, pllclk = 0; + uint32_t apb2presc = 0, ahbpresc = 0; + + /* Get SYSCLK source -------------------------------------------------------*/ + tmp = RCC->CFGR & RCC_CFGR_SWS; + + switch (tmp) + { + case 0x00: /* HSI used as system clock */ + RCC_Clocks->SYSCLK_Frequency = HSI_VALUE; + break; + case 0x04: /* HSE used as system clock */ + RCC_Clocks->SYSCLK_Frequency = HSE_VALUE; + break; + case 0x08: /* PLL used as system clock */ + /* Get PLL clock source and multiplication factor ----------------------*/ + pllmull = RCC->CFGR & RCC_CFGR_PLLMULL; + pllsource = RCC->CFGR & RCC_CFGR_PLLSRC; + pllmull = ( pllmull >> 18) + 2; + + if (pllsource == 0x00) + { + /* HSI oscillator clock divided by 2 selected as PLL clock entry */ + pllclk = (HSI_VALUE >> 1) * pllmull; + } + else + { + prediv1factor = (RCC->CFGR2 & RCC_CFGR2_PREDIV1) + 1; + /* HSE oscillator clock selected as PREDIV1 clock entry */ + pllclk = (HSE_VALUE / prediv1factor) * pllmull; + } + RCC_Clocks->SYSCLK_Frequency = pllclk; + break; + default: /* HSI used as system clock */ + RCC_Clocks->SYSCLK_Frequency = HSI_VALUE; + break; + } + /* Compute HCLK, PCLK clocks frequencies -----------------------------------*/ + /* Get HCLK prescaler */ + tmp = RCC->CFGR & RCC_CFGR_HPRE; + tmp = tmp >> 4; + ahbpresc = APBAHBPrescTable[tmp]; + /* HCLK clock frequency */ + RCC_Clocks->HCLK_Frequency = RCC_Clocks->SYSCLK_Frequency >> ahbpresc; + + /* Get PCLK1 prescaler */ + tmp = RCC->CFGR & RCC_CFGR_PPRE1; + tmp = tmp >> 8; + presc = APBAHBPrescTable[tmp]; + /* PCLK1 clock frequency */ + RCC_Clocks->PCLK1_Frequency = RCC_Clocks->HCLK_Frequency >> presc; + + /* Get PCLK2 prescaler */ + tmp = RCC->CFGR & RCC_CFGR_PPRE2; + tmp = tmp >> 11; + apb2presc = APBAHBPrescTable[tmp]; + + /* PCLK2 clock frequency */ + RCC_Clocks->PCLK2_Frequency = RCC_Clocks->HCLK_Frequency >> apb2presc; + + /* Get ADC12CLK prescaler */ + tmp = RCC->CFGR2 & RCC_CFGR2_ADCPRE12; + tmp = tmp >> 4; + presc = ADCPrescTable[tmp & 0x0F]; + if (((tmp & 0x10) != 0) && (presc != 0)) + { + /* ADC12CLK clock frequency is derived from PLL clock */ + RCC_Clocks->ADC12CLK_Frequency = pllclk / presc; + } + else + { + /* ADC12CLK clock frequency is AHB clock */ + RCC_Clocks->ADC12CLK_Frequency = RCC_Clocks->SYSCLK_Frequency; + } + + /* Get ADC34CLK prescaler */ + tmp = RCC->CFGR2 & RCC_CFGR2_ADCPRE34; + tmp = tmp >> 9; + presc = ADCPrescTable[tmp & 0x0F]; + if (((tmp & 0x10) != 0) && (presc != 0)) + { + /* ADC34CLK clock frequency is derived from PLL clock */ + RCC_Clocks->ADC34CLK_Frequency = pllclk / presc; + } + else + { + /* ADC34CLK clock frequency is AHB clock */ + RCC_Clocks->ADC34CLK_Frequency = RCC_Clocks->SYSCLK_Frequency; + } + + /* I2C1CLK clock frequency */ + if((RCC->CFGR3 & RCC_CFGR3_I2C1SW) != RCC_CFGR3_I2C1SW) + { + /* I2C1 Clock is HSI Osc. */ + RCC_Clocks->I2C1CLK_Frequency = HSI_VALUE; + } + else + { + /* I2C1 Clock is System Clock */ + RCC_Clocks->I2C1CLK_Frequency = RCC_Clocks->SYSCLK_Frequency; + } + + /* I2C2CLK clock frequency */ + if((RCC->CFGR3 & RCC_CFGR3_I2C2SW) != RCC_CFGR3_I2C2SW) + { + /* I2C2 Clock is HSI Osc. */ + RCC_Clocks->I2C2CLK_Frequency = HSI_VALUE; + } + else + { + /* I2C2 Clock is System Clock */ + RCC_Clocks->I2C2CLK_Frequency = RCC_Clocks->SYSCLK_Frequency; + } + + /* I2C3CLK clock frequency */ + if((RCC->CFGR3 & RCC_CFGR3_I2C3SW) != RCC_CFGR3_I2C3SW) + { + /* I2C3 Clock is HSI Osc. */ + RCC_Clocks->I2C3CLK_Frequency = HSI_VALUE; + } + else + { + /* I2C3 Clock is System Clock */ + RCC_Clocks->I2C3CLK_Frequency = RCC_Clocks->SYSCLK_Frequency; + } + + /* TIM1CLK clock frequency */ + if(((RCC->CFGR3 & RCC_CFGR3_TIM1SW) == RCC_CFGR3_TIM1SW)&& (RCC_Clocks->SYSCLK_Frequency == pllclk) \ + && (apb2presc == ahbpresc)) + { + /* TIM1 Clock is 2 * pllclk */ + RCC_Clocks->TIM1CLK_Frequency = pllclk * 2; + } + else + { + /* TIM1 Clock is APB2 clock. */ + RCC_Clocks->TIM1CLK_Frequency = RCC_Clocks->PCLK2_Frequency; + } + +#ifdef STM32F303xE + uint32_t apb1presc = 0; + apb1presc = APBAHBPrescTable[tmp]; + /* TIM2CLK clock frequency */ + if(((RCC->CFGR3 & RCC_CFGR3_TIM2SW) == RCC_CFGR3_TIM2SW)&& (RCC_Clocks->SYSCLK_Frequency == pllclk) \ + && (apb1presc == ahbpresc)) + { + /* TIM2 Clock is pllclk */ + RCC_Clocks->TIM2CLK_Frequency = pllclk * 2 ; + } + else + { + /* TIM2 Clock is APB2 clock. */ + RCC_Clocks->TIM2CLK_Frequency = RCC_Clocks->PCLK1_Frequency; + } + + /* TIM3CLK clock frequency */ + if(((RCC->CFGR3 & RCC_CFGR3_TIM3SW) == RCC_CFGR3_TIM3SW)&& (RCC_Clocks->SYSCLK_Frequency == pllclk) \ + && (apb1presc == ahbpresc)) + { + /* TIM3 Clock is pllclk */ + RCC_Clocks->TIM3CLK_Frequency = pllclk * 2; + } + else + { + /* TIM3 Clock is APB2 clock. */ + RCC_Clocks->TIM3CLK_Frequency = RCC_Clocks->PCLK1_Frequency; + } +#endif /* STM32F303xE */ + + /* TIM1CLK clock frequency */ + if(((RCC->CFGR3 & RCC_CFGR3_HRTIM1SW) == RCC_CFGR3_HRTIM1SW)&& (RCC_Clocks->SYSCLK_Frequency == pllclk) \ + && (apb2presc == ahbpresc)) + { + /* HRTIM1 Clock is 2 * pllclk */ + RCC_Clocks->HRTIM1CLK_Frequency = pllclk * 2; + } + else + { + /* HRTIM1 Clock is APB2 clock. */ + RCC_Clocks->HRTIM1CLK_Frequency = RCC_Clocks->PCLK2_Frequency; + } + + /* TIM8CLK clock frequency */ + if(((RCC->CFGR3 & RCC_CFGR3_TIM8SW) == RCC_CFGR3_TIM8SW)&& (RCC_Clocks->SYSCLK_Frequency == pllclk) \ + && (apb2presc == ahbpresc)) + { + /* TIM8 Clock is 2 * pllclk */ + RCC_Clocks->TIM8CLK_Frequency = pllclk * 2; + } + else + { + /* TIM8 Clock is APB2 clock. */ + RCC_Clocks->TIM8CLK_Frequency = RCC_Clocks->PCLK2_Frequency; + } + + /* TIM15CLK clock frequency */ + if(((RCC->CFGR3 & RCC_CFGR3_TIM15SW) == RCC_CFGR3_TIM15SW)&& (RCC_Clocks->SYSCLK_Frequency == pllclk) \ + && (apb2presc == ahbpresc)) + { + /* TIM15 Clock is 2 * pllclk */ + RCC_Clocks->TIM15CLK_Frequency = pllclk * 2; + } + else + { + /* TIM15 Clock is APB2 clock. */ + RCC_Clocks->TIM15CLK_Frequency = RCC_Clocks->PCLK2_Frequency; + } + + /* TIM16CLK clock frequency */ + if(((RCC->CFGR3 & RCC_CFGR3_TIM16SW) == RCC_CFGR3_TIM16SW)&& (RCC_Clocks->SYSCLK_Frequency == pllclk) \ + && (apb2presc == ahbpresc)) + { + /* TIM16 Clock is 2 * pllclk */ + RCC_Clocks->TIM16CLK_Frequency = pllclk * 2; + } + else + { + /* TIM16 Clock is APB2 clock. */ + RCC_Clocks->TIM16CLK_Frequency = RCC_Clocks->PCLK2_Frequency; + } + + /* TIM17CLK clock frequency */ + if(((RCC->CFGR3 & RCC_CFGR3_TIM17SW) == RCC_CFGR3_TIM17SW)&& (RCC_Clocks->SYSCLK_Frequency == pllclk) \ + && (apb2presc == ahbpresc)) + { + /* TIM17 Clock is 2 * pllclk */ + RCC_Clocks->TIM17CLK_Frequency = pllclk * 2; + } + else + { + /* TIM17 Clock is APB2 clock. */ + RCC_Clocks->TIM16CLK_Frequency = RCC_Clocks->PCLK2_Frequency; + } + + /* TIM20CLK clock frequency */ + if(((RCC->CFGR3 & RCC_CFGR3_TIM20SW) == RCC_CFGR3_TIM20SW)&& (RCC_Clocks->SYSCLK_Frequency == pllclk) \ + && (apb2presc == ahbpresc)) + { + /* TIM20 Clock is 2 * pllclk */ + RCC_Clocks->TIM20CLK_Frequency = pllclk * 2; + } + else + { + /* TIM20 Clock is APB2 clock. */ + RCC_Clocks->TIM20CLK_Frequency = RCC_Clocks->PCLK2_Frequency; + } + + /* USART1CLK clock frequency */ + if((RCC->CFGR3 & RCC_CFGR3_USART1SW) == 0x0) + { +#if defined(STM32F303x8) || defined(STM32F334x8) || defined(STM32F301x8) || defined(STM32F302x8) + /* USART1 Clock is PCLK1 instead of PCLK2 (limitation described in the + STM32F302/01/34 x4/x6/x8 respective erratasheets) */ + RCC_Clocks->USART1CLK_Frequency = RCC_Clocks->PCLK1_Frequency; +#else + /* USART Clock is PCLK2 */ + RCC_Clocks->USART1CLK_Frequency = RCC_Clocks->PCLK2_Frequency; +#endif + } + else if((RCC->CFGR3 & RCC_CFGR3_USART1SW) == RCC_CFGR3_USART1SW_0) + { + /* USART Clock is System Clock */ + RCC_Clocks->USART1CLK_Frequency = RCC_Clocks->SYSCLK_Frequency; + } + else if((RCC->CFGR3 & RCC_CFGR3_USART1SW) == RCC_CFGR3_USART1SW_1) + { + /* USART Clock is LSE Osc. */ + RCC_Clocks->USART1CLK_Frequency = LSE_VALUE; + } + else if((RCC->CFGR3 & RCC_CFGR3_USART1SW) == RCC_CFGR3_USART1SW) + { + /* USART Clock is HSI Osc. */ + RCC_Clocks->USART1CLK_Frequency = HSI_VALUE; + } + + /* USART2CLK clock frequency */ + if((RCC->CFGR3 & RCC_CFGR3_USART2SW) == 0x0) + { + /* USART Clock is PCLK */ + RCC_Clocks->USART2CLK_Frequency = RCC_Clocks->PCLK1_Frequency; + } + else if((RCC->CFGR3 & RCC_CFGR3_USART2SW) == RCC_CFGR3_USART2SW_0) + { + /* USART Clock is System Clock */ + RCC_Clocks->USART2CLK_Frequency = RCC_Clocks->SYSCLK_Frequency; + } + else if((RCC->CFGR3 & RCC_CFGR3_USART2SW) == RCC_CFGR3_USART2SW_1) + { + /* USART Clock is LSE Osc. */ + RCC_Clocks->USART2CLK_Frequency = LSE_VALUE; + } + else if((RCC->CFGR3 & RCC_CFGR3_USART2SW) == RCC_CFGR3_USART2SW) + { + /* USART Clock is HSI Osc. */ + RCC_Clocks->USART2CLK_Frequency = HSI_VALUE; + } + + /* USART3CLK clock frequency */ + if((RCC->CFGR3 & RCC_CFGR3_USART3SW) == 0x0) + { + /* USART Clock is PCLK */ + RCC_Clocks->USART3CLK_Frequency = RCC_Clocks->PCLK1_Frequency; + } + else if((RCC->CFGR3 & RCC_CFGR3_USART3SW) == RCC_CFGR3_USART3SW_0) + { + /* USART Clock is System Clock */ + RCC_Clocks->USART3CLK_Frequency = RCC_Clocks->SYSCLK_Frequency; + } + else if((RCC->CFGR3 & RCC_CFGR3_USART3SW) == RCC_CFGR3_USART3SW_1) + { + /* USART Clock is LSE Osc. */ + RCC_Clocks->USART3CLK_Frequency = LSE_VALUE; + } + else if((RCC->CFGR3 & RCC_CFGR3_USART3SW) == RCC_CFGR3_USART3SW) + { + /* USART Clock is HSI Osc. */ + RCC_Clocks->USART3CLK_Frequency = HSI_VALUE; + } + + /* UART4CLK clock frequency */ + if((RCC->CFGR3 & RCC_CFGR3_UART4SW) == 0x0) + { + /* USART Clock is PCLK */ + RCC_Clocks->UART4CLK_Frequency = RCC_Clocks->PCLK1_Frequency; + } + else if((RCC->CFGR3 & RCC_CFGR3_UART4SW) == RCC_CFGR3_UART4SW_0) + { + /* USART Clock is System Clock */ + RCC_Clocks->UART4CLK_Frequency = RCC_Clocks->SYSCLK_Frequency; + } + else if((RCC->CFGR3 & RCC_CFGR3_UART4SW) == RCC_CFGR3_UART4SW_1) + { + /* USART Clock is LSE Osc. */ + RCC_Clocks->UART4CLK_Frequency = LSE_VALUE; + } + else if((RCC->CFGR3 & RCC_CFGR3_UART4SW) == RCC_CFGR3_UART4SW) + { + /* USART Clock is HSI Osc. */ + RCC_Clocks->UART4CLK_Frequency = HSI_VALUE; + } + + /* UART5CLK clock frequency */ + if((RCC->CFGR3 & RCC_CFGR3_UART5SW) == 0x0) + { + /* USART Clock is PCLK */ + RCC_Clocks->UART5CLK_Frequency = RCC_Clocks->PCLK1_Frequency; + } + else if((RCC->CFGR3 & RCC_CFGR3_UART5SW) == RCC_CFGR3_UART5SW_0) + { + /* USART Clock is System Clock */ + RCC_Clocks->UART5CLK_Frequency = RCC_Clocks->SYSCLK_Frequency; + } + else if((RCC->CFGR3 & RCC_CFGR3_UART5SW) == RCC_CFGR3_UART5SW_1) + { + /* USART Clock is LSE Osc. */ + RCC_Clocks->UART5CLK_Frequency = LSE_VALUE; + } + else if((RCC->CFGR3 & RCC_CFGR3_UART5SW) == RCC_CFGR3_UART5SW) + { + /* USART Clock is HSI Osc. */ + RCC_Clocks->UART5CLK_Frequency = HSI_VALUE; + } +} + +/** + * @} + */ + +/** @defgroup RCC_Group3 Peripheral clocks configuration functions + * @brief Peripheral clocks configuration functions + * +@verbatim + =============================================================================== + ##### Peripheral clocks configuration functions ##### + =============================================================================== + [..] This section provide functions allowing to configure the Peripheral clocks. + (#) The RTC clock which is derived from the LSE, LSI or HSE_Div32 + (HSE divided by 32). + (#) After restart from Reset or wakeup from STANDBY, all peripherals are + off except internal SRAM, Flash and SWD. Before to start using + a peripheral you have to enable its interface clock. You can do this + using RCC_AHBPeriphClockCmd(), RCC_APB2PeriphClockCmd() + and RCC_APB1PeriphClockCmd() functions. + (#) To reset the peripherals configuration (to the default state after + device reset) you can use RCC_AHBPeriphResetCmd(), RCC_APB2PeriphResetCmd() + and RCC_APB1PeriphResetCmd() functions. +@endverbatim + * @{ + */ + +/** + * @brief Configures the ADC clock (ADCCLK). + * @param RCC_PLLCLK: defines the ADC clock divider. This clock is derived from + * the PLL Clock. + * This parameter can be one of the following values: + * @arg RCC_ADC12PLLCLK_OFF: ADC12 clock disabled + * @arg RCC_ADC12PLLCLK_Div1: ADC12 clock = PLLCLK/1 + * @arg RCC_ADC12PLLCLK_Div2: ADC12 clock = PLLCLK/2 + * @arg RCC_ADC12PLLCLK_Div4: ADC12 clock = PLLCLK/4 + * @arg RCC_ADC12PLLCLK_Div6: ADC12 clock = PLLCLK/6 + * @arg RCC_ADC12PLLCLK_Div8: ADC12 clock = PLLCLK/8 + * @arg RCC_ADC12PLLCLK_Div10: ADC12 clock = PLLCLK/10 + * @arg RCC_ADC12PLLCLK_Div12: ADC12 clock = PLLCLK/12 + * @arg RCC_ADC12PLLCLK_Div16: ADC12 clock = PLLCLK/16 + * @arg RCC_ADC12PLLCLK_Div32: ADC12 clock = PLLCLK/32 + * @arg RCC_ADC12PLLCLK_Div64: ADC12 clock = PLLCLK/64 + * @arg RCC_ADC12PLLCLK_Div128: ADC12 clock = PLLCLK/128 + * @arg RCC_ADC12PLLCLK_Div256: ADC12 clock = PLLCLK/256 + * @arg RCC_ADC34PLLCLK_OFF: ADC34 clock disabled + * @arg RCC_ADC34PLLCLK_Div1: ADC34 clock = PLLCLK/1 + * @arg RCC_ADC34PLLCLK_Div2: ADC34 clock = PLLCLK/2 + * @arg RCC_ADC34PLLCLK_Div4: ADC34 clock = PLLCLK/4 + * @arg RCC_ADC34PLLCLK_Div6: ADC34 clock = PLLCLK/6 + * @arg RCC_ADC34PLLCLK_Div8: ADC34 clock = PLLCLK/8 + * @arg RCC_ADC34PLLCLK_Div10: ADC34 clock = PLLCLK/10 + * @arg RCC_ADC34PLLCLK_Div12: ADC34 clock = PLLCLK/12 + * @arg RCC_ADC34PLLCLK_Div16: ADC34 clock = PLLCLK/16 + * @arg RCC_ADC34PLLCLK_Div32: ADC34 clock = PLLCLK/32 + * @arg RCC_ADC34PLLCLK_Div64: ADC34 clock = PLLCLK/64 + * @arg RCC_ADC34PLLCLK_Div128: ADC34 clock = PLLCLK/128 + * @arg RCC_ADC34PLLCLK_Div256: ADC34 clock = PLLCLK/256 + * @retval None + */ +void RCC_ADCCLKConfig(uint32_t RCC_PLLCLK) +{ + uint32_t tmp = 0; + + /* Check the parameters */ + assert_param(IS_RCC_ADCCLK(RCC_PLLCLK)); + + tmp = (RCC_PLLCLK >> 28); + + /* Clears ADCPRE34 bits */ + if (tmp != 0) + { + RCC->CFGR2 &= ~RCC_CFGR2_ADCPRE34; + } + /* Clears ADCPRE12 bits */ + else + { + RCC->CFGR2 &= ~RCC_CFGR2_ADCPRE12; + } + /* Set ADCPRE bits according to RCC_PLLCLK value */ + RCC->CFGR2 |= RCC_PLLCLK; +} + +/** + * @brief Configures the I2C clock (I2CCLK). + * @param RCC_I2CCLK: defines the I2C clock source. This clock is derived + * from the HSI or System clock. + * This parameter can be one of the following values: + * @arg RCC_I2CxCLK_HSI: I2Cx clock = HSI + * @arg RCC_I2CxCLK_SYSCLK: I2Cx clock = System Clock + * (x can be 1 or 2 or 3). + * @retval None + */ +void RCC_I2CCLKConfig(uint32_t RCC_I2CCLK) +{ + uint32_t tmp = 0; + + /* Check the parameters */ + assert_param(IS_RCC_I2CCLK(RCC_I2CCLK)); + + tmp = (RCC_I2CCLK >> 28); + + /* Clear I2CSW bit */ + switch (tmp) + { + case 0x00: + RCC->CFGR3 &= ~RCC_CFGR3_I2C1SW; + break; + case 0x01: + RCC->CFGR3 &= ~RCC_CFGR3_I2C2SW; + break; + case 0x02: + RCC->CFGR3 &= ~RCC_CFGR3_I2C3SW; + break; + default: + break; + } + + /* Set I2CSW bits according to RCC_I2CCLK value */ + RCC->CFGR3 |= RCC_I2CCLK; +} + +/** + * @brief Configures the TIMx clock sources(TIMCLK). + * @note For STM32F303xC devices, TIMx can be clocked from the PLL running at 144 MHz + * when the system clock source is the PLL and HCLK & PCLK2 clocks are not divided in respect to SYSCLK. + * For the devices STM32F334x8, STM32F302x8 and STM32F303xE, TIMx can be clocked from the PLL running at + * 144 MHz when the system clock source is the PLL and AHB or APB2 subsystem clocks are not divided by + * more than 2 cumulatively. + * @note If one of the previous conditions is missed, the TIM clock source + * configuration is lost and calling again this function becomes mandatory. + * @param RCC_TIMCLK: defines the TIMx clock source. + * This parameter can be one of the following values: + * @arg RCC_TIMxCLK_PCLK: TIMx clock = APB clock (doubled frequency when prescaled) + * @arg RCC_TIMxCLK_PLLCLK: TIMx clock = PLL output (running up to 144 MHz) + * (x can be 1, 8, 15, 16, 17, 20, 2, 3,4). + * @note For STM32F303xC devices, TIM1 and TIM8 can be clocked at 144MHz. + * For STM32F303xE devices, TIM1/8/20/2/3/4/15/16/17 can be clocked at 144MHz. + * For STM32F334x8 devices , only TIM1 can be clocked at 144MHz. + * For STM32F302x8 devices, TIM1/15/16/17 can be clocked at 144MHz + * @retval None + */ +void RCC_TIMCLKConfig(uint32_t RCC_TIMCLK) +{ + uint32_t tmp = 0; + + /* Check the parameters */ + assert_param(IS_RCC_TIMCLK(RCC_TIMCLK)); + + tmp = (RCC_TIMCLK >> 28); + + /* Clear TIMSW bit */ + + switch (tmp) + { + case 0x00: + RCC->CFGR3 &= ~RCC_CFGR3_TIM1SW; + break; + case 0x01: + RCC->CFGR3 &= ~RCC_CFGR3_TIM8SW; + break; + case 0x02: + RCC->CFGR3 &= ~RCC_CFGR3_TIM15SW; + break; + case 0x03: + RCC->CFGR3 &= ~RCC_CFGR3_TIM16SW; + break; + case 0x04: + RCC->CFGR3 &= ~RCC_CFGR3_TIM17SW; + break; + case 0x05: + RCC->CFGR3 &= ~RCC_CFGR3_TIM20SW; + case 0x06: + RCC->CFGR3 &= ~RCC_CFGR3_TIM2SW; + case 0x07: + RCC->CFGR3 &= ~RCC_CFGR3_TIM3SW; + break; + default: + break; + } + + /* Set I2CSW bits according to RCC_TIMCLK value */ + RCC->CFGR3 |= RCC_TIMCLK; +} + +/** + * @brief Configures the HRTIM1 clock sources(HRTIM1CLK). + * @note The configuration of the HRTIM1 clock source is only possible when the + * SYSCLK = PLL and HCLK and PCLK2 clocks are not divided in respect to SYSCLK + * @note If one of the previous conditions is missed, the TIM clock source + * configuration is lost and calling again this function becomes mandatory. + * @param RCC_HRTIMCLK: defines the TIMx clock source. + * This parameter can be one of the following values: + * @arg RCC_HRTIM1CLK_HCLK: TIMx clock = APB high speed clock (doubled frequency + * when prescaled) + * @arg RCC_HRTIM1CLK_PLLCLK: TIMx clock = PLL output (running up to 144 MHz) + * (x can be 1 or 8). + * @retval None + */ +void RCC_HRTIM1CLKConfig(uint32_t RCC_HRTIMCLK) +{ + /* Check the parameters */ + assert_param(IS_RCC_HRTIMCLK(RCC_HRTIMCLK)); + + /* Clear HRTIMSW bit */ + RCC->CFGR3 &= ~RCC_CFGR3_HRTIM1SW; + + /* Set HRTIMSW bits according to RCC_HRTIMCLK value */ + RCC->CFGR3 |= RCC_HRTIMCLK; +} + +/** + * @brief Configures the USART clock (USARTCLK). + * @param RCC_USARTCLK: defines the USART clock source. This clock is derived + * from the HSI or System clock. + * This parameter can be one of the following values: + * @arg RCC_USARTxCLK_PCLK: USART clock = APB Clock (PCLK) + * @arg RCC_USARTxCLK_SYSCLK: USART clock = System Clock + * @arg RCC_USARTxCLK_LSE: USART clock = LSE Clock + * @arg RCC_USARTxCLK_HSI: USART clock = HSI Clock + * (x can be 1, 2, 3, 4 or 5). + * @retval None + */ +void RCC_USARTCLKConfig(uint32_t RCC_USARTCLK) +{ + uint32_t tmp = 0; + + /* Check the parameters */ + assert_param(IS_RCC_USARTCLK(RCC_USARTCLK)); + + tmp = (RCC_USARTCLK >> 28); + + /* Clear USARTSW[1:0] bit */ + switch (tmp) + { + case 0x01: /* clear USART1SW */ + RCC->CFGR3 &= ~RCC_CFGR3_USART1SW; + break; + case 0x02: /* clear USART2SW */ + RCC->CFGR3 &= ~RCC_CFGR3_USART2SW; + break; + case 0x03: /* clear USART3SW */ + RCC->CFGR3 &= ~RCC_CFGR3_USART3SW; + break; + case 0x04: /* clear UART4SW */ + RCC->CFGR3 &= ~RCC_CFGR3_UART4SW; + break; + case 0x05: /* clear UART5SW */ + RCC->CFGR3 &= ~RCC_CFGR3_UART5SW; + break; + default: + break; + } + + /* Set USARTSW bits according to RCC_USARTCLK value */ + RCC->CFGR3 |= RCC_USARTCLK; +} + +/** + * @brief Configures the USB clock (USBCLK). + * @param RCC_USBCLKSource: specifies the USB clock source. This clock is + * derived from the PLL output. + * This parameter can be one of the following values: + * @arg RCC_USBCLKSource_PLLCLK_1Div5: PLL clock divided by 1,5 selected as USB + * clock source + * @arg RCC_USBCLKSource_PLLCLK_Div1: PLL clock selected as USB clock source + * @retval None + */ +void RCC_USBCLKConfig(uint32_t RCC_USBCLKSource) +{ + /* Check the parameters */ + assert_param(IS_RCC_USBCLK_SOURCE(RCC_USBCLKSource)); + + *(__IO uint32_t *) CFGR_USBPRE_BB = RCC_USBCLKSource; +} + +/** + * @brief Configures the RTC clock (RTCCLK). + * @note As the RTC clock configuration bits are in the Backup domain and write + * access is denied to this domain after reset, you have to enable write + * access using PWR_BackupAccessCmd(ENABLE) function before to configure + * the RTC clock source (to be done once after reset). + * @note Once the RTC clock is configured it can't be changed unless the RTC + * is reset using RCC_BackupResetCmd function, or by a Power On Reset (POR) + * + * @param RCC_RTCCLKSource: specifies the RTC clock source. + * This parameter can be one of the following values: + * @arg RCC_RTCCLKSource_LSE: LSE selected as RTC clock + * @arg RCC_RTCCLKSource_LSI: LSI selected as RTC clock + * @arg RCC_RTCCLKSource_HSE_Div32: HSE divided by 32 selected as RTC clock + * + * @note If the LSE or LSI is used as RTC clock source, the RTC continues to + * work in STOP and STANDBY modes, and can be used as wakeup source. + * However, when the HSE clock is used as RTC clock source, the RTC + * cannot be used in STOP and STANDBY modes. + * @note The maximum input clock frequency for RTC is 2MHz (when using HSE as + * RTC clock source). + * @retval None + */ +void RCC_RTCCLKConfig(uint32_t RCC_RTCCLKSource) +{ + /* Check the parameters */ + assert_param(IS_RCC_RTCCLK_SOURCE(RCC_RTCCLKSource)); + + /* Select the RTC clock source */ + RCC->BDCR |= RCC_RTCCLKSource; +} + +/** + * @brief Configures the I2S clock source (I2SCLK). + * @note This function must be called before enabling the SPI2 and SPI3 clocks. + * @param RCC_I2SCLKSource: specifies the I2S clock source. + * This parameter can be one of the following values: + * @arg RCC_I2S2CLKSource_SYSCLK: SYSCLK clock used as I2S clock source + * @arg RCC_I2S2CLKSource_Ext: External clock mapped on the I2S_CKIN pin + * used as I2S clock source + * @retval None + */ +void RCC_I2SCLKConfig(uint32_t RCC_I2SCLKSource) +{ + /* Check the parameters */ + assert_param(IS_RCC_I2SCLK_SOURCE(RCC_I2SCLKSource)); + + *(__IO uint32_t *) CFGR_I2SSRC_BB = RCC_I2SCLKSource; +} + +/** + * @brief Enables or disables the RTC clock. + * @note This function must be used only after the RTC clock source was selected + * using the RCC_RTCCLKConfig function. + * @param NewState: new state of the RTC clock. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void RCC_RTCCLKCmd(FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + *(__IO uint32_t *) BDCR_RTCEN_BB = (uint32_t)NewState; +} + +/** + * @brief Forces or releases the Backup domain reset. + * @note This function resets the RTC peripheral (including the backup registers) + * and the RTC clock source selection in RCC_BDCR register. + * @param NewState: new state of the Backup domain reset. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void RCC_BackupResetCmd(FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + *(__IO uint32_t *) BDCR_BDRST_BB = (uint32_t)NewState; +} + +/** + * @brief Enables or disables the AHB peripheral clock. + * @note After reset, the peripheral clock (used for registers read/write access) + * is disabled and the application software has to enable this clock before + * using it. + * @param RCC_AHBPeriph: specifies the AHB peripheral to gates its clock. + * This parameter can be any combination of the following values: + * @arg RCC_AHBPeriph_GPIOA + * @arg RCC_AHBPeriph_GPIOB + * @arg RCC_AHBPeriph_GPIOC + * @arg RCC_AHBPeriph_GPIOD + * @arg RCC_AHBPeriph_GPIOE + * @arg RCC_AHBPeriph_GPIOF + * @arg RCC_AHBPeriph_GPIOG + * @arg RCC_AHBPeriph_GPIOH + * @arg RCC_AHBPeriph_TS + * @arg RCC_AHBPeriph_CRC + * @arg RCC_AHBPeriph_FMC + * @arg RCC_AHBPeriph_FLITF (has effect only when the Flash memory is in power down mode) + * @arg RCC_AHBPeriph_SRAM + * @arg RCC_AHBPeriph_DMA2 + * @arg RCC_AHBPeriph_DMA1 + * @arg RCC_AHBPeriph_ADC34 + * @arg RCC_AHBPeriph_ADC12 + * @param NewState: new state of the specified peripheral clock. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void RCC_AHBPeriphClockCmd(uint32_t RCC_AHBPeriph, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_RCC_AHB_PERIPH(RCC_AHBPeriph)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + RCC->AHBENR |= RCC_AHBPeriph; + } + else + { + RCC->AHBENR &= ~RCC_AHBPeriph; + } +} + +/** + * @brief Enables or disables the High Speed APB (APB2) peripheral clock. + * @note After reset, the peripheral clock (used for registers read/write access) + * is disabled and the application software has to enable this clock before + * using it. + * @param RCC_APB2Periph: specifies the APB2 peripheral to gates its clock. + * This parameter can be any combination of the following values: + * @arg RCC_APB2Periph_SYSCFG + * @arg RCC_APB2Periph_SPI1 + * @arg RCC_APB2Periph_USART1 + * @arg RCC_APB2Periph_SPI4 + * @arg RCC_APB2Periph_TIM15 + * @arg RCC_APB2Periph_TIM16 + * @arg RCC_APB2Periph_TIM17 + * @arg RCC_APB2Periph_TIM1 + * @arg RCC_APB2Periph_TIM8 + * @arg RCC_APB2Periph_HRTIM1 + * @arg RCC_APB2Periph_TIM20 + * @param NewState: new state of the specified peripheral clock. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_RCC_APB2_PERIPH(RCC_APB2Periph)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + RCC->APB2ENR |= RCC_APB2Periph; + } + else + { + RCC->APB2ENR &= ~RCC_APB2Periph; + } +} + +/** + * @brief Enables or disables the Low Speed APB (APB1) peripheral clock. + * @note After reset, the peripheral clock (used for registers read/write access) + * is disabled and the application software has to enable this clock before + * using it. + * @param RCC_APB1Periph: specifies the APB1 peripheral to gates its clock. + * This parameter can be any combination of the following values: + * @arg RCC_APB1Periph_TIM2 + * @arg RCC_APB1Periph_TIM3 + * @arg RCC_APB1Periph_TIM4 + * @arg RCC_APB1Periph_TIM6 + * @arg RCC_APB1Periph_TIM7 + * @arg RCC_APB1Periph_WWDG + * @arg RCC_APB1Periph_SPI2 + * @arg RCC_APB1Periph_SPI3 + * @arg RCC_APB1Periph_USART2 + * @arg RCC_APB1Periph_USART3 + * @arg RCC_APB1Periph_UART4 + * @arg RCC_APB1Periph_UART5 + * @arg RCC_APB1Periph_I2C1 + * @arg RCC_APB1Periph_I2C2 + * @arg RCC_APB1Periph_USB + * @arg RCC_APB1Periph_CAN1 + * @arg RCC_APB1Periph_PWR + * @arg RCC_APB1Periph_DAC1 + * @arg RCC_APB1Periph_DAC2 + * @arg RCC_APB1Periph_I2C3 + * @param NewState: new state of the specified peripheral clock. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void RCC_APB1PeriphClockCmd(uint32_t RCC_APB1Periph, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_RCC_APB1_PERIPH(RCC_APB1Periph)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + RCC->APB1ENR |= RCC_APB1Periph; + } + else + { + RCC->APB1ENR &= ~RCC_APB1Periph; + } +} + +/** + * @brief Forces or releases AHB peripheral reset. + * @param RCC_AHBPeriph: specifies the AHB peripheral to reset. + * This parameter can be any combination of the following values: + * @arg RCC_AHBPeriph_FMC + * @arg RCC_AHBPeriph_GPIOH + * @arg RCC_AHBPeriph_GPIOA + * @arg RCC_AHBPeriph_GPIOB + * @arg RCC_AHBPeriph_GPIOC + * @arg RCC_AHBPeriph_GPIOD + * @arg RCC_AHBPeriph_GPIOE + * @arg RCC_AHBPeriph_GPIOF + * @arg RCC_AHBPeriph_GPIOG + * @arg RCC_AHBPeriph_TS + * @arg RCC_AHBPeriph_ADC34 + * @arg RCC_AHBPeriph_ADC12 + * @param NewState: new state of the specified peripheral reset. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void RCC_AHBPeriphResetCmd(uint32_t RCC_AHBPeriph, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_RCC_AHB_RST_PERIPH(RCC_AHBPeriph)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + RCC->AHBRSTR |= RCC_AHBPeriph; + } + else + { + RCC->AHBRSTR &= ~RCC_AHBPeriph; + } +} + +/** + * @brief Forces or releases High Speed APB (APB2) peripheral reset. + * @param RCC_APB2Periph: specifies the APB2 peripheral to reset. + * This parameter can be any combination of the following values: + * @arg RCC_APB2Periph_SYSCFG + * @arg RCC_APB2Periph_SPI1 + * @arg RCC_APB2Periph_USART1 + * @arg RCC_APB2Periph_SPI4 + * @arg RCC_APB2Periph_TIM15 + * @arg RCC_APB2Periph_TIM16 + * @arg RCC_APB2Periph_TIM17 + * @arg RCC_APB2Periph_TIM1 + * @arg RCC_APB2Periph_TIM8 + * @arg RCC_APB2Periph_TIM20 + * @arg RCC_APB2Periph_HRTIM1 + * @param NewState: new state of the specified peripheral reset. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void RCC_APB2PeriphResetCmd(uint32_t RCC_APB2Periph, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_RCC_APB2_PERIPH(RCC_APB2Periph)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + RCC->APB2RSTR |= RCC_APB2Periph; + } + else + { + RCC->APB2RSTR &= ~RCC_APB2Periph; + } +} + +/** + * @brief Forces or releases Low Speed APB (APB1) peripheral reset. + * @param RCC_APB1Periph: specifies the APB1 peripheral to reset. + * This parameter can be any combination of the following values: + * @arg RCC_APB1Periph_TIM2 + * @arg RCC_APB1Periph_TIM3 + * @arg RCC_APB1Periph_TIM4 + * @arg RCC_APB1Periph_TIM6 + * @arg RCC_APB1Periph_TIM7 + * @arg RCC_APB1Periph_WWDG + * @arg RCC_APB1Periph_SPI2 + * @arg RCC_APB1Periph_SPI3 + * @arg RCC_APB1Periph_USART2 + * @arg RCC_APB1Periph_USART3 + * @arg RCC_APB1Periph_UART4 + * @arg RCC_APB1Periph_UART5 + * @arg RCC_APB1Periph_I2C1 + * @arg RCC_APB1Periph_I2C2 + * @arg RCC_APB1Periph_I2C3 + * @arg RCC_APB1Periph_USB + * @arg RCC_APB1Periph_CAN1 + * @arg RCC_APB1Periph_PWR + * @arg RCC_APB1Periph_DAC + * @param NewState: new state of the specified peripheral clock. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void RCC_APB1PeriphResetCmd(uint32_t RCC_APB1Periph, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_RCC_APB1_PERIPH(RCC_APB1Periph)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + RCC->APB1RSTR |= RCC_APB1Periph; + } + else + { + RCC->APB1RSTR &= ~RCC_APB1Periph; + } +} + +/** + * @} + */ + +/** @defgroup RCC_Group4 Interrupts and flags management functions + * @brief Interrupts and flags management functions + * +@verbatim + =============================================================================== + ##### Interrupts and flags management functions ##### + =============================================================================== + +@endverbatim + * @{ + */ + +/** + * @brief Enables or disables the specified RCC interrupts. + * @note The CSS interrupt doesn't have an enable bit; once the CSS is enabled + * and if the HSE clock fails, the CSS interrupt occurs and an NMI is + * automatically generated. The NMI will be executed indefinitely, and + * since NMI has higher priority than any other IRQ (and main program) + * the application will be stacked in the NMI ISR unless the CSS interrupt + * pending bit is cleared. + * @param RCC_IT: specifies the RCC interrupt sources to be enabled or disabled. + * This parameter can be any combination of the following values: + * @arg RCC_IT_LSIRDY: LSI ready interrupt + * @arg RCC_IT_LSERDY: LSE ready interrupt + * @arg RCC_IT_HSIRDY: HSI ready interrupt + * @arg RCC_IT_HSERDY: HSE ready interrupt + * @arg RCC_IT_PLLRDY: PLL ready interrupt + * @param NewState: new state of the specified RCC interrupts. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void RCC_ITConfig(uint8_t RCC_IT, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_RCC_IT(RCC_IT)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Perform Byte access to RCC_CIR[13:8] bits to enable the selected interrupts */ + *(__IO uint8_t *) CIR_BYTE2_ADDRESS |= RCC_IT; + } + else + { + /* Perform Byte access to RCC_CIR[13:8] bits to disable the selected interrupts */ + *(__IO uint8_t *) CIR_BYTE2_ADDRESS &= (uint8_t)~RCC_IT; + } +} + +/** + * @brief Checks whether the specified RCC flag is set or not. + * @param RCC_FLAG: specifies the flag to check. + * This parameter can be one of the following values: + * @arg RCC_FLAG_HSIRDY: HSI oscillator clock ready + * @arg RCC_FLAG_HSERDY: HSE oscillator clock ready + * @arg RCC_FLAG_PLLRDY: PLL clock ready + * @arg RCC_FLAG_MCOF: MCO Flag + * @arg RCC_FLAG_LSERDY: LSE oscillator clock ready + * @arg RCC_FLAG_LSIRDY: LSI oscillator clock ready + * @arg RCC_FLAG_OBLRST: Option Byte Loader (OBL) reset + * @arg RCC_FLAG_PINRST: Pin reset + * @arg RCC_FLAG_PORRST: POR/PDR reset + * @arg RCC_FLAG_SFTRST: Software reset + * @arg RCC_FLAG_IWDGRST: Independent Watchdog reset + * @arg RCC_FLAG_WWDGRST: Window Watchdog reset + * @arg RCC_FLAG_LPWRRST: Low Power reset + * @retval The new state of RCC_FLAG (SET or RESET). + */ +FlagStatus RCC_GetFlagStatus(uint8_t RCC_FLAG) +{ + uint32_t tmp = 0; + uint32_t statusreg = 0; + FlagStatus bitstatus = RESET; + + /* Check the parameters */ + assert_param(IS_RCC_FLAG(RCC_FLAG)); + + /* Get the RCC register index */ + tmp = RCC_FLAG >> 5; + + if (tmp == 0) /* The flag to check is in CR register */ + { + statusreg = RCC->CR; + } + else if (tmp == 1) /* The flag to check is in BDCR register */ + { + statusreg = RCC->BDCR; + } + else if (tmp == 4) /* The flag to check is in CFGR register */ + { + statusreg = RCC->CFGR; + } + else /* The flag to check is in CSR register */ + { + statusreg = RCC->CSR; + } + + /* Get the flag position */ + tmp = RCC_FLAG & FLAG_MASK; + + if ((statusreg & ((uint32_t)1 << tmp)) != (uint32_t)RESET) + { + bitstatus = SET; + } + else + { + bitstatus = RESET; + } + /* Return the flag status */ + return bitstatus; +} + +/** + * @brief Clears the RCC reset flags. + * The reset flags are: RCC_FLAG_OBLRST, RCC_FLAG_PINRST, RCC_FLAG_PORRST, + * RCC_FLAG_SFTRST, RCC_FLAG_IWDGRST, RCC_FLAG_WWDGRST, RCC_FLAG_LPWRRST. + * @param None + * @retval None + */ +void RCC_ClearFlag(void) +{ + /* Set RMVF bit to clear the reset flags */ + RCC->CSR |= RCC_CSR_RMVF; +} + +/** + * @brief Checks whether the specified RCC interrupt has occurred or not. + * @param RCC_IT: specifies the RCC interrupt source to check. + * This parameter can be one of the following values: + * @arg RCC_IT_LSIRDY: LSI ready interrupt + * @arg RCC_IT_LSERDY: LSE ready interrupt + * @arg RCC_IT_HSIRDY: HSI ready interrupt + * @arg RCC_IT_HSERDY: HSE ready interrupt + * @arg RCC_IT_PLLRDY: PLL ready interrupt + * @arg RCC_IT_CSS: Clock Security System interrupt + * @retval The new state of RCC_IT (SET or RESET). + */ +ITStatus RCC_GetITStatus(uint8_t RCC_IT) +{ + ITStatus bitstatus = RESET; + + /* Check the parameters */ + assert_param(IS_RCC_GET_IT(RCC_IT)); + + /* Check the status of the specified RCC interrupt */ + if ((RCC->CIR & RCC_IT) != (uint32_t)RESET) + { + bitstatus = SET; + } + else + { + bitstatus = RESET; + } + /* Return the RCC_IT status */ + return bitstatus; +} + +/** + * @brief Clears the RCC's interrupt pending bits. + * @param RCC_IT: specifies the interrupt pending bit to clear. + * This parameter can be any combination of the following values: + * @arg RCC_IT_LSIRDY: LSI ready interrupt + * @arg RCC_IT_LSERDY: LSE ready interrupt + * @arg RCC_IT_HSIRDY: HSI ready interrupt + * @arg RCC_IT_HSERDY: HSE ready interrupt + * @arg RCC_IT_PLLRDY: PLL ready interrupt + * @arg RCC_IT_CSS: Clock Security System interrupt + * @retval None + */ +void RCC_ClearITPendingBit(uint8_t RCC_IT) +{ + /* Check the parameters */ + assert_param(IS_RCC_CLEAR_IT(RCC_IT)); + + /* Perform Byte access to RCC_CIR[23:16] bits to clear the selected interrupt + pending bits */ + *(__IO uint8_t *) CIR_BYTE3_ADDRESS = RCC_IT; +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_rtc.c b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_rtc.c new file mode 100755 index 0000000000..daf87f26d1 --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_rtc.c @@ -0,0 +1,2598 @@ +/** + ****************************************************************************** + * @file stm32f30x_rtc.c + * @author MCD Application Team + * @version V1.2.3 + * @date 10-July-2015 + * @brief This file provides firmware functions to manage the following + * functionalities of the Real-Time Clock (RTC) peripheral: + * + Initialization + * + Calendar (Time and Date) configuration + * + Alarms (Alarm A and Alarm B) configuration + * + WakeUp Timer configuration + * + Daylight Saving configuration + * + Output pin Configuration + * + Smooth digital Calibration configuration + * + TimeStamp configuration + * + Tampers configuration + * + Backup Data Registers configuration + * + Output Type Config configuration + * + Shift control synchronisation + * + Interrupts and flags management + * + @verbatim + + =============================================================================== + ##### RTC Operating Condition ##### + =============================================================================== + [..] The real-time clock (RTC) and the RTC backup registers can be powered + from the VBAT voltage when the main VDD supply is powered off. + To retain the content of the RTC backup registers and supply the RTC + when VDD is turned off, VBAT pin can be connected to an optional + standby voltage supplied by a battery or by another source. + + [..] To allow the RTC to operate even when the main digital supply (VDD) + is turned off, the VBAT pin powers the following blocks: + (#) The RTC + (#) The LSE oscillator + (#) PC13 to PC15 I/Os (when available) + + [..] When the backup domain is supplied by VDD (analog switch connected + to VDD), the following functions are available: + (#) PC14 and PC15 can be used as either GPIO or LSE pins + (#) PC13 can be used as a GPIO or as the RTC_AF pin + + [..] When the backup domain is supplied by VBAT (analog switch connected + to VBAT because VDD is not present), the following functions are available: + (#) PC14 and PC15 can be used as LSE pins only + (#) PC13 can be used as the RTC_AF pin + + ##### Backup Domain Reset ##### + =============================================================================== + [..] The backup domain reset sets all RTC registers and the RCC_BDCR + register to their reset values. + A backup domain reset is generated when one of the following events + occurs: + (#) Software reset, triggered by setting the BDRST bit in the + RCC Backup domain control register (RCC_BDCR). You can use the + RCC_BackupResetCmd(). + (#) VDD or VBAT power on, if both supplies have previously been + powered off. + + ##### Backup Domain Access ##### + =============================================================================== + [..] After reset, the backup domain (RTC registers and RTC backup data + registers) is protected against possible unwanted write accesses. + [..] To enable access to the Backup Domain and RTC registers, proceed as follows: + (#) Enable the Power Controller (PWR) APB1 interface clock using the + RCC_APB1PeriphClockCmd() function. + (#) Enable access to Backup domain using the PWR_BackupAccessCmd() function. + (#) Select the RTC clock source using the RCC_RTCCLKConfig() function. + (#) Enable RTC Clock using the RCC_RTCCLKCmd() function. + + ##### How to use this driver ##### + =============================================================================== + [..] + (+) Enable the backup domain access (see description in the section above) + (+) Configure the RTC Prescaler (Asynchronous and Synchronous) and + RTC hour format using the RTC_Init() function. + + *** Time and Date configuration *** + =================================== + [..] + (+) To configure the RTC Calendar (Time and Date) use the RTC_SetTime() + and RTC_SetDate() functions. + (+) To read the RTC Calendar, use the RTC_GetTime() and RTC_GetDate() + functions. + (+) To read the RTC subsecond, use the RTC_GetSubSecond() function. + (+) Use the RTC_DayLightSavingConfig() function to add or sub one + hour to the RTC Calendar. + + *** Alarm configuration *** + =========================== + [..] + (+) To configure the RTC Alarm use the RTC_SetAlarm() function. + (+) Enable the selected RTC Alarm using the RTC_AlarmCmd() function. + (+) To read the RTC Alarm, use the RTC_GetAlarm() function. + (+) To read the RTC alarm SubSecond, use the RTC_GetAlarmSubSecond() function. + + *** RTC Wakeup configuration *** + ================================ + [..] + (+) Configure the RTC Wakeup Clock source use the RTC_WakeUpClockConfig() + function. + (+) Configure the RTC WakeUp Counter using the RTC_SetWakeUpCounter() + function + (+) Enable the RTC WakeUp using the RTC_WakeUpCmd() function + (+) To read the RTC WakeUp Counter register, use the RTC_GetWakeUpCounter() + function. + + *** Outputs configuration *** + ============================= + [..] The RTC has 2 different outputs: + (+) AFO_ALARM: this output is used to manage the RTC Alarm A, Alarm B + and WaKeUp signals. + To output the selected RTC signal on RTC_AF pin, use the + RTC_OutputConfig() function. + (+) AFO_CALIB: this output is 512Hz signal or 1Hz . + To output the RTC Clock on RTC_AF pin, use the RTC_CalibOutputCmd() + function. + + *** Smooth digital Calibration configuration *** + ================================================ + [..] + (+) Configure the RTC Original Digital Calibration Value and the corresponding + calibration cycle period (32s,16s and 8s) using the RTC_SmoothCalibConfig() + function. + + *** TimeStamp configuration *** + =============================== + [..] + (+) Configure the RTC_AF trigger and enables the RTC TimeStamp + using the RTC_TimeStampCmd() function. + (+) To read the RTC TimeStamp Time and Date register, use the + RTC_GetTimeStamp() function. + (+) To read the RTC TimeStamp SubSecond register, use the + RTC_GetTimeStampSubSecond() function. + + *** Tamper configuration *** + ============================ + [..] + (+) Configure the Tamper filter count using RTC_TamperFilterConfig() + function. + (+) Configure the RTC Tamper trigger Edge or Level according to the Tamper + filter (if equal to 0 Edge else Level) value using the RTC_TamperConfig() function. + (+) Configure the Tamper sampling frequency using RTC_TamperSamplingFreqConfig() + function. + (+) Configure the Tamper precharge or discharge duration using + RTC_TamperPinsPrechargeDuration() function. + (+) Enable the Tamper Pull-UP using RTC_TamperPullUpDisableCmd() function. + (+) Enable the RTC Tamper using the RTC_TamperCmd() function. + (+) Enable the Time stamp on Tamper detection event using + RTC_TSOnTamperDetecCmd() function. + + *** Backup Data Registers configuration *** + =========================================== + [..] + (+) To write to the RTC Backup Data registers, use the RTC_WriteBackupRegister() + function. + (+) To read the RTC Backup Data registers, use the RTC_ReadBackupRegister() + function. + + ##### RTC and low power modes ##### + =============================================================================== + [..] The MCU can be woken up from a low power mode by an RTC alternate + function. + [..] The RTC alternate functions are the RTC alarms (Alarm A and Alarm B), + RTC wakeup, RTC tamper event detection and RTC time stamp event detection. + These RTC alternate functions can wake up the system from the Stop + and Standby lowpower modes. + The system can also wake up from low power modes without depending + on an external interrupt (Auto-wakeup mode), by using the RTC alarm + or the RTC wakeup events. + [..] The RTC provides a programmable time base for waking up from the + Stop or Standby mode at regular intervals. + Wakeup from STOP and Standby modes is possible only when the RTC + clock source is LSE or LSI. + + ##### Selection of RTC_AF alternate functions ##### + =============================================================================== + [..] The RTC_AF pin (PC13) can be used for the following purposes: + (+) Wakeup pin 2 (WKUP2) using the PWR_WakeUpPinCmd() function. + (+) AFO_ALARM output + (+) AFO_CALIB output + (+) AFI_TAMPER + (+) AFI_TIMESTAMP + + +------------------------------------------------------------------------------------------+ + | Pin |RTC ALARM |RTC CALIB |RTC TAMPER |RTC TIMESTAMP |PC13MODE| PC13VALUE | + | configuration | OUTPUT | OUTPUT | INPUT | INPUT | bit | bit | + | and function | ENABLED | ENABLED | ENABLED | ENABLED | | | + |-----------------|----------|----------|-----------|--------------|--------|--------------| + | Alarm out | | | | | Don't | | + | output OD | 1 |Don't care|Don't care | Don't care | care | 0 | + |-----------------|----------|----------|-----------|--------------|--------|--------------| + | Alarm out | | | | | Don't | | + | output PP | 1 |Don't care|Don't care | Don't care | care | 1 | + |-----------------|----------|----------|-----------|--------------|--------|--------------| + | Calibration out | | | | | Don't | | + | output PP | 0 | 1 |Don't care | Don't care | care | Don't care | + |-----------------|----------|----------|-----------|--------------|--------|--------------| + | TAMPER input | | | | | Don't | | + | floating | 0 | 0 | 1 | 0 | care | Don't care | + |-----------------|----------|----------|-----------|--------------|--------|--------------| + | TIMESTAMP and | | | | | Don't | | + | TAMPER input | 0 | 0 | 1 | 1 | care | Don't care | + | floating | | | | | | | + |-----------------|----------|----------|-----------|--------------|--------|--------------| + | TIMESTAMP input | | | | | Don't | | + | floating | 0 | 0 | 0 | 1 | care | Don't care | + |-----------------|----------|----------|-----------|--------------|--------|--------------| + | Output PP | 0 | 0 | 0 | 0 | 1 | PC13 output | + | Forced | | | | | | | + |-----------------|----------|----------|-----------|--------------|--------|--------------| + | Wakeup Pin or | 0 | 0 | 0 | 0 | 0 | Don't care | + | Standard GPIO | | | | | | | + +------------------------------------------------------------------------------------------+ + + @endverbatim + + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f30x_rtc.h" +#include "stm32f30x_rcc.h" + +/** @addtogroup STM32F30x_StdPeriph_Driver + * @{ + */ + +/** @defgroup RTC + * @brief RTC driver modules + * @{ + */ + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ + +/* Masks Definition */ +#define RTC_TR_RESERVED_MASK ((uint32_t)0x007F7F7F) +#define RTC_DR_RESERVED_MASK ((uint32_t)0x00FFFF3F) +#define RTC_INIT_MASK ((uint32_t)0xFFFFFFFF) +#define RTC_RSF_MASK ((uint32_t)0xFFFFFF5F) +#define RTC_FLAGS_MASK ((uint32_t)(RTC_FLAG_TSOVF | RTC_FLAG_TSF | RTC_FLAG_WUTF | \ + RTC_FLAG_ALRBF | RTC_FLAG_ALRAF | RTC_FLAG_INITF | \ + RTC_FLAG_RSF | RTC_FLAG_INITS | RTC_FLAG_WUTWF | \ + RTC_FLAG_ALRBWF | RTC_FLAG_ALRAWF | RTC_FLAG_TAMP1F | \ + RTC_FLAG_TAMP2F | RTC_FLAG_TAMP3F | RTC_FLAG_RECALPF | \ + RTC_FLAG_SHPF)) + +#define INITMODE_TIMEOUT ((uint32_t) 0x00002000) +#define SYNCHRO_TIMEOUT ((uint32_t) 0x00008000) +#define RECALPF_TIMEOUT ((uint32_t) 0x00001000) +#define SHPF_TIMEOUT ((uint32_t) 0x00002000) + +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/* Private function prototypes -----------------------------------------------*/ +static uint8_t RTC_ByteToBcd2(uint8_t Value); +static uint8_t RTC_Bcd2ToByte(uint8_t Value); + +/* Private functions ---------------------------------------------------------*/ + +/** @defgroup RTC_Private_Functions + * @{ + */ + +/** @defgroup RTC_Group1 Initialization and Configuration functions + * @brief Initialization and Configuration functions + * +@verbatim + =============================================================================== + ##### Initialization and Configuration functions ##### + =============================================================================== + [..] This section provide functions allowing to initialize and configure the RTC + Prescaler (Synchronous and Asynchronous), RTC Hour format, disable RTC registers + Write protection, enter and exit the RTC initialization mode, RTC registers + synchronization check and reference clock detection enable. + (#) The RTC Prescaler is programmed to generate the RTC 1Hz time base. It is + split into 2 programmable prescalers to minimize power consumption. + (++) A 7-bit asynchronous prescaler and A 13-bit synchronous prescaler. + (++) When both prescalers are used, it is recommended to configure the + asynchronous prescaler to a high value to minimize consumption. + (#) All RTC registers are Write protected. Writing to the RTC registers + is enabled by writing a key into the Write Protection register, RTC_WPR. + (#) To Configure the RTC Calendar, user application should enter initialization + mode. In this mode, the calendar counter is stopped and its value + can be updated. When the initialization sequence is complete, the + calendar restarts counting after 4 RTCCLK cycles. + (#) To read the calendar through the shadow registers after Calendar + initialization, calendar update or after wakeup from low power modes + the software must first clear the RSF flag. The software must then + wait until it is set again before reading the calendar, which means + that the calendar registers have been correctly copied into the RTC_TR + and RTC_DR shadow registers. The RTC_WaitForSynchro() function + implements the above software sequence (RSF clear and RSF check). + +@endverbatim + * @{ + */ + +/** + * @brief Deinitializes the RTC registers to their default reset values. + * @note This function doesn't reset the RTC Clock source and RTC Backup Data + * registers. + * @param None + * @retval An ErrorStatus enumeration value: + * - SUCCESS: RTC registers are deinitialized + * - ERROR: RTC registers are not deinitialized + */ +ErrorStatus RTC_DeInit(void) +{ + __IO uint32_t wutcounter = 0x00; + uint32_t wutwfstatus = 0x00; + ErrorStatus status = ERROR; + + /* Disable the write protection for RTC registers */ + RTC->WPR = 0xCA; + RTC->WPR = 0x53; + + /* Set Initialization mode */ + if (RTC_EnterInitMode() == ERROR) + { + status = ERROR; + } + else + { + /* Reset TR, DR and CR registers */ + RTC->TR = (uint32_t)0x00000000; + RTC->DR = (uint32_t)0x00002101; + + /* Reset All CR bits except CR[2:0] */ + RTC->CR &= (uint32_t)0x00000007; + + /* Wait till RTC WUTWF flag is set and if Time out is reached exit */ + do + { + wutwfstatus = RTC->ISR & RTC_ISR_WUTWF; + wutcounter++; + } while((wutcounter != INITMODE_TIMEOUT) && (wutwfstatus == 0x00)); + + if ((RTC->ISR & RTC_ISR_WUTWF) == RESET) + { + status = ERROR; + } + else + { + /* Reset all RTC CR register bits */ + RTC->CR &= (uint32_t)0x00000000; + RTC->WUTR = (uint32_t)0x0000FFFF; + RTC->PRER = (uint32_t)0x007F00FF; + RTC->ALRMAR = (uint32_t)0x00000000; + RTC->ALRMBR = (uint32_t)0x00000000; + RTC->SHIFTR = (uint32_t)0x00000000; + RTC->CALR = (uint32_t)0x00000000; + RTC->ALRMASSR = (uint32_t)0x00000000; + RTC->ALRMBSSR = (uint32_t)0x00000000; + + /* Reset ISR register and exit initialization mode */ + RTC->ISR = (uint32_t)0x00000000; + + /* Reset Tamper and alternate functions configuration register */ + RTC->TAFCR = 0x00000000; + + /* Wait till the RTC RSF flag is set */ + if (RTC_WaitForSynchro() == ERROR) + { + status = ERROR; + } + else + { + status = SUCCESS; + } + } + } + + /* Enable the write protection for RTC registers */ + RTC->WPR = 0xFF; + + return status; +} + +/** + * @brief Initializes the RTC registers according to the specified parameters + * in RTC_InitStruct. + * @param RTC_InitStruct: pointer to a RTC_InitTypeDef structure that contains + * the configuration information for the RTC peripheral. + * @note The RTC Prescaler register is write protected and can be written in + * initialization mode only. + * @retval An ErrorStatus enumeration value: + * - SUCCESS: RTC registers are initialized + * - ERROR: RTC registers are not initialized + */ +ErrorStatus RTC_Init(RTC_InitTypeDef* RTC_InitStruct) +{ + ErrorStatus status = ERROR; + + /* Check the parameters */ + assert_param(IS_RTC_HOUR_FORMAT(RTC_InitStruct->RTC_HourFormat)); + assert_param(IS_RTC_ASYNCH_PREDIV(RTC_InitStruct->RTC_AsynchPrediv)); + assert_param(IS_RTC_SYNCH_PREDIV(RTC_InitStruct->RTC_SynchPrediv)); + + /* Disable the write protection for RTC registers */ + RTC->WPR = 0xCA; + RTC->WPR = 0x53; + + /* Set Initialization mode */ + if (RTC_EnterInitMode() == ERROR) + { + status = ERROR; + } + else + { + /* Clear RTC CR FMT Bit */ + RTC->CR &= ((uint32_t)~(RTC_CR_FMT)); + /* Set RTC_CR register */ + RTC->CR |= ((uint32_t)(RTC_InitStruct->RTC_HourFormat)); + + /* Configure the RTC PRER */ + RTC->PRER = (uint32_t)(RTC_InitStruct->RTC_SynchPrediv); + RTC->PRER |= (uint32_t)(RTC_InitStruct->RTC_AsynchPrediv << 16); + + /* Exit Initialization mode */ + RTC_ExitInitMode(); + + status = SUCCESS; + } + /* Enable the write protection for RTC registers */ + RTC->WPR = 0xFF; + + return status; +} + +/** + * @brief Fills each RTC_InitStruct member with its default value. + * @param RTC_InitStruct: pointer to a RTC_InitTypeDef structure which will be + * initialized. + * @retval None + */ +void RTC_StructInit(RTC_InitTypeDef* RTC_InitStruct) +{ + /* Initialize the RTC_HourFormat member */ + RTC_InitStruct->RTC_HourFormat = RTC_HourFormat_24; + + /* Initialize the RTC_AsynchPrediv member */ + RTC_InitStruct->RTC_AsynchPrediv = (uint32_t)0x7F; + + /* Initialize the RTC_SynchPrediv member */ + RTC_InitStruct->RTC_SynchPrediv = (uint32_t)0xFF; +} + +/** + * @brief Enables or disables the RTC registers write protection. + * @note All the RTC registers are write protected except for RTC_ISR[13:8], + * RTC_TAFCR and RTC_BKPxR. + * @note Writing a wrong key reactivates the write protection. + * @note The protection mechanism is not affected by system reset. + * @param NewState: new state of the write protection. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void RTC_WriteProtectionCmd(FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable the write protection for RTC registers */ + RTC->WPR = 0xFF; + } + else + { + /* Disable the write protection for RTC registers */ + RTC->WPR = 0xCA; + RTC->WPR = 0x53; + } +} + +/** + * @brief Enters the RTC Initialization mode. + * @note The RTC Initialization mode is write protected, use the + * RTC_WriteProtectionCmd(DISABLE) before calling this function. + * @param None + * @retval An ErrorStatus enumeration value: + * - SUCCESS: RTC is in Init mode + * - ERROR: RTC is not in Init mode + */ +ErrorStatus RTC_EnterInitMode(void) +{ + __IO uint32_t initcounter = 0x00; + ErrorStatus status = ERROR; + uint32_t initstatus = 0x00; + + /* Check if the Initialization mode is set */ + if ((RTC->ISR & RTC_ISR_INITF) == (uint32_t)RESET) + { + /* Set the Initialization mode */ + RTC->ISR = (uint32_t)RTC_INIT_MASK; + + /* Wait till RTC is in INIT state and if Time out is reached exit */ + do + { + initstatus = RTC->ISR & RTC_ISR_INITF; + initcounter++; + } while((initcounter != INITMODE_TIMEOUT) && (initstatus == 0x00)); + + if ((RTC->ISR & RTC_ISR_INITF) != RESET) + { + status = SUCCESS; + } + else + { + status = ERROR; + } + } + else + { + status = SUCCESS; + } + + return (status); +} + +/** + * @brief Exits the RTC Initialization mode. + * @note When the initialization sequence is complete, the calendar restarts + * counting after 4 RTCCLK cycles. + * @note The RTC Initialization mode is write protected, use the + * RTC_WriteProtectionCmd(DISABLE) before calling this function. + * @param None + * @retval None + */ +void RTC_ExitInitMode(void) +{ + /* Exit Initialization mode */ + RTC->ISR &= (uint32_t)~RTC_ISR_INIT; +} + +/** + * @brief Waits until the RTC Time and Date registers (RTC_TR and RTC_DR) are + * synchronized with RTC APB clock. + * @note The RTC Resynchronization mode is write protected, use the + * RTC_WriteProtectionCmd(DISABLE) before calling this function. + * @note To read the calendar through the shadow registers after Calendar + * initialization, calendar update or after wakeup from low power modes + * the software must first clear the RSF flag. + * The software must then wait until it is set again before reading + * the calendar, which means that the calendar registers have been + * correctly copied into the RTC_TR and RTC_DR shadow registers. + * @param None + * @retval An ErrorStatus enumeration value: + * - SUCCESS: RTC registers are synchronised + * - ERROR: RTC registers are not synchronised + */ +ErrorStatus RTC_WaitForSynchro(void) +{ + __IO uint32_t synchrocounter = 0; + ErrorStatus status = ERROR; + uint32_t synchrostatus = 0x00; + + if ((RTC->CR & RTC_CR_BYPSHAD) != RESET) + { + /* Bypass shadow mode */ + status = SUCCESS; + } + else + { + /* Disable the write protection for RTC registers */ + RTC->WPR = 0xCA; + RTC->WPR = 0x53; + + /* Clear RSF flag */ + RTC->ISR &= (uint32_t)RTC_RSF_MASK; + + /* Wait the registers to be synchronised */ + do + { + synchrostatus = RTC->ISR & RTC_ISR_RSF; + synchrocounter++; + } while((synchrocounter != SYNCHRO_TIMEOUT) && (synchrostatus == 0x00)); + + if ((RTC->ISR & RTC_ISR_RSF) != RESET) + { + status = SUCCESS; + } + else + { + status = ERROR; + } + + /* Enable the write protection for RTC registers */ + RTC->WPR = 0xFF; + } + + return (status); +} + +/** + * @brief Enables or disables the RTC reference clock detection. + * @param NewState: new state of the RTC reference clock. + * This parameter can be: ENABLE or DISABLE. + * @retval An ErrorStatus enumeration value: + * - SUCCESS: RTC reference clock detection is enabled + * - ERROR: RTC reference clock detection is disabled + */ +ErrorStatus RTC_RefClockCmd(FunctionalState NewState) +{ + ErrorStatus status = ERROR; + + /* Check the parameters */ + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + /* Disable the write protection for RTC registers */ + RTC->WPR = 0xCA; + RTC->WPR = 0x53; + + /* Set Initialization mode */ + if (RTC_EnterInitMode() == ERROR) + { + status = ERROR; + } + else + { + if (NewState != DISABLE) + { + /* Enable the RTC reference clock detection */ + RTC->CR |= RTC_CR_REFCKON; + } + else + { + /* Disable the RTC reference clock detection */ + RTC->CR &= ~RTC_CR_REFCKON; + } + /* Exit Initialization mode */ + RTC_ExitInitMode(); + + status = SUCCESS; + } + + /* Enable the write protection for RTC registers */ + RTC->WPR = 0xFF; + + return status; +} + +/** + * @brief Enables or Disables the Bypass Shadow feature. + * @note When the Bypass Shadow is enabled the calendar value are taken + * directly from the Calendar counter. + * @param NewState: new state of the Bypass Shadow feature. + * This parameter can be: ENABLE or DISABLE. + * @retval None +*/ +void RTC_BypassShadowCmd(FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + /* Disable the write protection for RTC registers */ + RTC->WPR = 0xCA; + RTC->WPR = 0x53; + + if (NewState != DISABLE) + { + /* Set the BYPSHAD bit */ + RTC->CR |= (uint8_t)RTC_CR_BYPSHAD; + } + else + { + /* Reset the BYPSHAD bit */ + RTC->CR &= (uint8_t)~RTC_CR_BYPSHAD; + } + + /* Enable the write protection for RTC registers */ + RTC->WPR = 0xFF; +} + +/** + * @} + */ + +/** @defgroup RTC_Group2 Time and Date configuration functions + * @brief Time and Date configuration functions + * +@verbatim + =============================================================================== + ##### Time and Date configuration functions ##### + =============================================================================== + [..] This section provide functions allowing to program and read the RTC Calendar + (Time and Date). + +@endverbatim + * @{ + */ + +/** + * @brief Set the RTC current time. + * @param RTC_Format: specifies the format of the entered parameters. + * This parameter can be one of the following values: + * @arg RTC_Format_BIN: Binary data format + * @arg RTC_Format_BCD: BCD data format + * @param RTC_TimeStruct: pointer to a RTC_TimeTypeDef structure that contains + * the time configuration information for the RTC. + * @retval An ErrorStatus enumeration value: + * - SUCCESS: RTC Time register is configured + * - ERROR: RTC Time register is not configured + */ +ErrorStatus RTC_SetTime(uint32_t RTC_Format, RTC_TimeTypeDef* RTC_TimeStruct) +{ + uint32_t tmpreg = 0; + ErrorStatus status = ERROR; + + /* Check the parameters */ + assert_param(IS_RTC_FORMAT(RTC_Format)); + + if (RTC_Format == RTC_Format_BIN) + { + if ((RTC->CR & RTC_CR_FMT) != (uint32_t)RESET) + { + assert_param(IS_RTC_HOUR12(RTC_TimeStruct->RTC_Hours)); + assert_param(IS_RTC_H12(RTC_TimeStruct->RTC_H12)); + } + else + { + RTC_TimeStruct->RTC_H12 = 0x00; + assert_param(IS_RTC_HOUR24(RTC_TimeStruct->RTC_Hours)); + } + assert_param(IS_RTC_MINUTES(RTC_TimeStruct->RTC_Minutes)); + assert_param(IS_RTC_SECONDS(RTC_TimeStruct->RTC_Seconds)); + } + else + { + if ((RTC->CR & RTC_CR_FMT) != (uint32_t)RESET) + { + tmpreg = RTC_Bcd2ToByte(RTC_TimeStruct->RTC_Hours); + assert_param(IS_RTC_HOUR12(tmpreg)); + assert_param(IS_RTC_H12(RTC_TimeStruct->RTC_H12)); + } + else + { + RTC_TimeStruct->RTC_H12 = 0x00; + assert_param(IS_RTC_HOUR24(RTC_Bcd2ToByte(RTC_TimeStruct->RTC_Hours))); + } + assert_param(IS_RTC_MINUTES(RTC_Bcd2ToByte(RTC_TimeStruct->RTC_Minutes))); + assert_param(IS_RTC_SECONDS(RTC_Bcd2ToByte(RTC_TimeStruct->RTC_Seconds))); + } + + /* Check the input parameters format */ + if (RTC_Format != RTC_Format_BIN) + { + tmpreg = (((uint32_t)(RTC_TimeStruct->RTC_Hours) << 16) | \ + ((uint32_t)(RTC_TimeStruct->RTC_Minutes) << 8) | \ + ((uint32_t)RTC_TimeStruct->RTC_Seconds) | \ + ((uint32_t)(RTC_TimeStruct->RTC_H12) << 16)); + } + else + { + tmpreg = (uint32_t)(((uint32_t)RTC_ByteToBcd2(RTC_TimeStruct->RTC_Hours) << 16) | \ + ((uint32_t)RTC_ByteToBcd2(RTC_TimeStruct->RTC_Minutes) << 8) | \ + ((uint32_t)RTC_ByteToBcd2(RTC_TimeStruct->RTC_Seconds)) | \ + (((uint32_t)RTC_TimeStruct->RTC_H12) << 16)); + } + + /* Disable the write protection for RTC registers */ + RTC->WPR = 0xCA; + RTC->WPR = 0x53; + + /* Set Initialization mode */ + if (RTC_EnterInitMode() == ERROR) + { + status = ERROR; + } + else + { + /* Set the RTC_TR register */ + RTC->TR = (uint32_t)(tmpreg & RTC_TR_RESERVED_MASK); + + /* Exit Initialization mode */ + RTC_ExitInitMode(); + + /* If RTC_CR_BYPSHAD bit = 0, wait for synchro else this check is not needed */ + if ((RTC->CR & RTC_CR_BYPSHAD) == RESET) + { + if (RTC_WaitForSynchro() == ERROR) + { + status = ERROR; + } + else + { + status = SUCCESS; + } + } + else + { + status = SUCCESS; + } + + } + /* Enable the write protection for RTC registers */ + RTC->WPR = 0xFF; + + return status; +} + +/** + * @brief Fills each RTC_TimeStruct member with its default value + * (Time = 00h:00min:00sec). + * @param RTC_TimeStruct: pointer to a RTC_TimeTypeDef structure which will be + * initialized. + * @retval None + */ +void RTC_TimeStructInit(RTC_TimeTypeDef* RTC_TimeStruct) +{ + /* Time = 00h:00min:00sec */ + RTC_TimeStruct->RTC_H12 = RTC_H12_AM; + RTC_TimeStruct->RTC_Hours = 0; + RTC_TimeStruct->RTC_Minutes = 0; + RTC_TimeStruct->RTC_Seconds = 0; +} + +/** + * @brief Get the RTC current Time. + * @param RTC_Format: specifies the format of the returned parameters. + * This parameter can be one of the following values: + * @arg RTC_Format_BIN: Binary data format + * @arg RTC_Format_BCD: BCD data format + * @param RTC_TimeStruct: pointer to a RTC_TimeTypeDef structure that will + * contain the returned current time configuration. + * @retval None + */ +void RTC_GetTime(uint32_t RTC_Format, RTC_TimeTypeDef* RTC_TimeStruct) +{ + uint32_t tmpreg = 0; + + /* Check the parameters */ + assert_param(IS_RTC_FORMAT(RTC_Format)); + + /* Get the RTC_TR register */ + tmpreg = (uint32_t)(RTC->TR & RTC_TR_RESERVED_MASK); + + /* Fill the structure fields with the read parameters */ + RTC_TimeStruct->RTC_Hours = (uint8_t)((tmpreg & (RTC_TR_HT | RTC_TR_HU)) >> 16); + RTC_TimeStruct->RTC_Minutes = (uint8_t)((tmpreg & (RTC_TR_MNT | RTC_TR_MNU)) >>8); + RTC_TimeStruct->RTC_Seconds = (uint8_t)(tmpreg & (RTC_TR_ST | RTC_TR_SU)); + RTC_TimeStruct->RTC_H12 = (uint8_t)((tmpreg & (RTC_TR_PM)) >> 16); + + /* Check the input parameters format */ + if (RTC_Format == RTC_Format_BIN) + { + /* Convert the structure parameters to Binary format */ + RTC_TimeStruct->RTC_Hours = (uint8_t)RTC_Bcd2ToByte(RTC_TimeStruct->RTC_Hours); + RTC_TimeStruct->RTC_Minutes = (uint8_t)RTC_Bcd2ToByte(RTC_TimeStruct->RTC_Minutes); + RTC_TimeStruct->RTC_Seconds = (uint8_t)RTC_Bcd2ToByte(RTC_TimeStruct->RTC_Seconds); + } +} + +/** + * @brief Gets the RTC current Calendar Subseconds value. + * @note This function freeze the Time and Date registers after reading the + * SSR register. + * @param None + * @retval RTC current Calendar Subseconds value. + */ +uint32_t RTC_GetSubSecond(void) +{ + uint32_t tmpreg = 0; + + /* Get subseconds values from the correspondent registers*/ + tmpreg = (uint32_t)(RTC->SSR); + + /* Read DR register to unfroze calendar registers */ + (void) (RTC->DR); + + return (tmpreg); +} + +/** + * @brief Set the RTC current date. + * @param RTC_Format: specifies the format of the entered parameters. + * This parameter can be one of the following values: + * @arg RTC_Format_BIN: Binary data format + * @arg RTC_Format_BCD: BCD data format + * @param RTC_DateStruct: pointer to a RTC_DateTypeDef structure that contains + * the date configuration information for the RTC. + * @retval An ErrorStatus enumeration value: + * - SUCCESS: RTC Date register is configured + * - ERROR: RTC Date register is not configured + */ +ErrorStatus RTC_SetDate(uint32_t RTC_Format, RTC_DateTypeDef* RTC_DateStruct) +{ + uint32_t tmpreg = 0; + ErrorStatus status = ERROR; + + /* Check the parameters */ + assert_param(IS_RTC_FORMAT(RTC_Format)); + + if ((RTC_Format == RTC_Format_BIN) && ((RTC_DateStruct->RTC_Month & 0x10) == 0x10)) + { + RTC_DateStruct->RTC_Month = (RTC_DateStruct->RTC_Month & (uint32_t)~(0x10)) + 0x0A; + } + if (RTC_Format == RTC_Format_BIN) + { + assert_param(IS_RTC_YEAR(RTC_DateStruct->RTC_Year)); + assert_param(IS_RTC_MONTH(RTC_DateStruct->RTC_Month)); + assert_param(IS_RTC_DATE(RTC_DateStruct->RTC_Date)); + } + else + { + assert_param(IS_RTC_YEAR(RTC_Bcd2ToByte(RTC_DateStruct->RTC_Year))); + tmpreg = RTC_Bcd2ToByte(RTC_DateStruct->RTC_Month); + assert_param(IS_RTC_MONTH(tmpreg)); + tmpreg = RTC_Bcd2ToByte(RTC_DateStruct->RTC_Date); + assert_param(IS_RTC_DATE(tmpreg)); + } + assert_param(IS_RTC_WEEKDAY(RTC_DateStruct->RTC_WeekDay)); + + /* Check the input parameters format */ + if (RTC_Format != RTC_Format_BIN) + { + tmpreg = ((((uint32_t)RTC_DateStruct->RTC_Year) << 16) | \ + (((uint32_t)RTC_DateStruct->RTC_Month) << 8) | \ + ((uint32_t)RTC_DateStruct->RTC_Date) | \ + (((uint32_t)RTC_DateStruct->RTC_WeekDay) << 13)); + } + else + { + tmpreg = (((uint32_t)RTC_ByteToBcd2(RTC_DateStruct->RTC_Year) << 16) | \ + ((uint32_t)RTC_ByteToBcd2(RTC_DateStruct->RTC_Month) << 8) | \ + ((uint32_t)RTC_ByteToBcd2(RTC_DateStruct->RTC_Date)) | \ + ((uint32_t)RTC_DateStruct->RTC_WeekDay << 13)); + } + + /* Disable the write protection for RTC registers */ + RTC->WPR = 0xCA; + RTC->WPR = 0x53; + + /* Set Initialization mode */ + if (RTC_EnterInitMode() == ERROR) + { + status = ERROR; + } + else + { + /* Set the RTC_DR register */ + RTC->DR = (uint32_t)(tmpreg & RTC_DR_RESERVED_MASK); + + /* Exit Initialization mode */ + RTC_ExitInitMode(); + + /* If RTC_CR_BYPSHAD bit = 0, wait for synchro else this check is not needed */ + if ((RTC->CR & RTC_CR_BYPSHAD) == RESET) + { + if (RTC_WaitForSynchro() == ERROR) + { + status = ERROR; + } + else + { + status = SUCCESS; + } + } + else + { + status = SUCCESS; + } + } + /* Enable the write protection for RTC registers */ + RTC->WPR = 0xFF; + + return status; +} + +/** + * @brief Fills each RTC_DateStruct member with its default value + * (Monday, January 01 xx00). + * @param RTC_DateStruct: pointer to a RTC_DateTypeDef structure which will be + * initialized. + * @retval None + */ +void RTC_DateStructInit(RTC_DateTypeDef* RTC_DateStruct) +{ + /* Monday, January 01 xx00 */ + RTC_DateStruct->RTC_WeekDay = RTC_Weekday_Monday; + RTC_DateStruct->RTC_Date = 1; + RTC_DateStruct->RTC_Month = RTC_Month_January; + RTC_DateStruct->RTC_Year = 0; +} + +/** + * @brief Get the RTC current date. + * @param RTC_Format: specifies the format of the returned parameters. + * This parameter can be one of the following values: + * @arg RTC_Format_BIN: Binary data format + * @arg RTC_Format_BCD: BCD data format + * @param RTC_DateStruct: pointer to a RTC_DateTypeDef structure that will + * contain the returned current date configuration. + * @retval None + */ +void RTC_GetDate(uint32_t RTC_Format, RTC_DateTypeDef* RTC_DateStruct) +{ + uint32_t tmpreg = 0; + + /* Check the parameters */ + assert_param(IS_RTC_FORMAT(RTC_Format)); + + /* Get the RTC_TR register */ + tmpreg = (uint32_t)(RTC->DR & RTC_DR_RESERVED_MASK); + + /* Fill the structure fields with the read parameters */ + RTC_DateStruct->RTC_Year = (uint8_t)((tmpreg & (RTC_DR_YT | RTC_DR_YU)) >> 16); + RTC_DateStruct->RTC_Month = (uint8_t)((tmpreg & (RTC_DR_MT | RTC_DR_MU)) >> 8); + RTC_DateStruct->RTC_Date = (uint8_t)(tmpreg & (RTC_DR_DT | RTC_DR_DU)); + RTC_DateStruct->RTC_WeekDay = (uint8_t)((tmpreg & (RTC_DR_WDU)) >> 13); + + /* Check the input parameters format */ + if (RTC_Format == RTC_Format_BIN) + { + /* Convert the structure parameters to Binary format */ + RTC_DateStruct->RTC_Year = (uint8_t)RTC_Bcd2ToByte(RTC_DateStruct->RTC_Year); + RTC_DateStruct->RTC_Month = (uint8_t)RTC_Bcd2ToByte(RTC_DateStruct->RTC_Month); + RTC_DateStruct->RTC_Date = (uint8_t)RTC_Bcd2ToByte(RTC_DateStruct->RTC_Date); + RTC_DateStruct->RTC_WeekDay = (uint8_t)(RTC_DateStruct->RTC_WeekDay); + } +} + +/** + * @} + */ + +/** @defgroup RTC_Group3 Alarms configuration functions + * @brief Alarms (Alarm A and Alarm B) configuration functions + * +@verbatim + =============================================================================== + ##### Alarms (Alarm A and Alarm B) configuration functions ##### + =============================================================================== + [..] This section provides functions allowing to program and read the RTC Alarms. + +@endverbatim + * @{ + */ + +/** + * @brief Set the specified RTC Alarm. + * @note The Alarm register can only be written when the corresponding Alarm + * is disabled (Use the RTC_AlarmCmd(DISABLE)). + * @param RTC_Format: specifies the format of the returned parameters. + * This parameter can be one of the following values: + * @arg RTC_Format_BIN: Binary data format + * @arg RTC_Format_BCD: BCD data format + * @param RTC_Alarm: specifies the alarm to be configured. + * This parameter can be one of the following values: + * @arg RTC_Alarm_A: to select Alarm A + * @arg RTC_Alarm_B: to select Alarm B + * @param RTC_AlarmStruct: pointer to a RTC_AlarmTypeDef structure that + * contains the alarm configuration parameters. + * @retval None + */ +void RTC_SetAlarm(uint32_t RTC_Format, uint32_t RTC_Alarm, RTC_AlarmTypeDef* RTC_AlarmStruct) +{ + uint32_t tmpreg = 0; + + /* Check the parameters */ + assert_param(IS_RTC_FORMAT(RTC_Format)); + assert_param(IS_RTC_ALARM(RTC_Alarm)); + assert_param(IS_ALARM_MASK(RTC_AlarmStruct->RTC_AlarmMask)); + assert_param(IS_RTC_ALARM_DATE_WEEKDAY_SEL(RTC_AlarmStruct->RTC_AlarmDateWeekDaySel)); + + if (RTC_Format == RTC_Format_BIN) + { + if ((RTC->CR & RTC_CR_FMT) != (uint32_t)RESET) + { + assert_param(IS_RTC_HOUR12(RTC_AlarmStruct->RTC_AlarmTime.RTC_Hours)); + assert_param(IS_RTC_H12(RTC_AlarmStruct->RTC_AlarmTime.RTC_H12)); + } + else + { + RTC_AlarmStruct->RTC_AlarmTime.RTC_H12 = 0x00; + assert_param(IS_RTC_HOUR24(RTC_AlarmStruct->RTC_AlarmTime.RTC_Hours)); + } + assert_param(IS_RTC_MINUTES(RTC_AlarmStruct->RTC_AlarmTime.RTC_Minutes)); + assert_param(IS_RTC_SECONDS(RTC_AlarmStruct->RTC_AlarmTime.RTC_Seconds)); + + if(RTC_AlarmStruct->RTC_AlarmDateWeekDaySel == RTC_AlarmDateWeekDaySel_Date) + { + assert_param(IS_RTC_ALARM_DATE_WEEKDAY_DATE(RTC_AlarmStruct->RTC_AlarmDateWeekDay)); + } + else + { + assert_param(IS_RTC_ALARM_DATE_WEEKDAY_WEEKDAY(RTC_AlarmStruct->RTC_AlarmDateWeekDay)); + } + } + else + { + if ((RTC->CR & RTC_CR_FMT) != (uint32_t)RESET) + { + tmpreg = RTC_Bcd2ToByte(RTC_AlarmStruct->RTC_AlarmTime.RTC_Hours); + assert_param(IS_RTC_HOUR12(tmpreg)); + assert_param(IS_RTC_H12(RTC_AlarmStruct->RTC_AlarmTime.RTC_H12)); + } + else + { + RTC_AlarmStruct->RTC_AlarmTime.RTC_H12 = 0x00; + assert_param(IS_RTC_HOUR24(RTC_Bcd2ToByte(RTC_AlarmStruct->RTC_AlarmTime.RTC_Hours))); + } + + assert_param(IS_RTC_MINUTES(RTC_Bcd2ToByte(RTC_AlarmStruct->RTC_AlarmTime.RTC_Minutes))); + assert_param(IS_RTC_SECONDS(RTC_Bcd2ToByte(RTC_AlarmStruct->RTC_AlarmTime.RTC_Seconds))); + + if(RTC_AlarmStruct->RTC_AlarmDateWeekDaySel == RTC_AlarmDateWeekDaySel_Date) + { + tmpreg = RTC_Bcd2ToByte(RTC_AlarmStruct->RTC_AlarmDateWeekDay); + assert_param(IS_RTC_ALARM_DATE_WEEKDAY_DATE(tmpreg)); + } + else + { + tmpreg = RTC_Bcd2ToByte(RTC_AlarmStruct->RTC_AlarmDateWeekDay); + assert_param(IS_RTC_ALARM_DATE_WEEKDAY_WEEKDAY(tmpreg)); + } + } + + /* Check the input parameters format */ + if (RTC_Format != RTC_Format_BIN) + { + tmpreg = (((uint32_t)(RTC_AlarmStruct->RTC_AlarmTime.RTC_Hours) << 16) | \ + ((uint32_t)(RTC_AlarmStruct->RTC_AlarmTime.RTC_Minutes) << 8) | \ + ((uint32_t)RTC_AlarmStruct->RTC_AlarmTime.RTC_Seconds) | \ + ((uint32_t)(RTC_AlarmStruct->RTC_AlarmTime.RTC_H12) << 16) | \ + ((uint32_t)(RTC_AlarmStruct->RTC_AlarmDateWeekDay) << 24) | \ + ((uint32_t)RTC_AlarmStruct->RTC_AlarmDateWeekDaySel) | \ + ((uint32_t)RTC_AlarmStruct->RTC_AlarmMask)); + } + else + { + tmpreg = (((uint32_t)RTC_ByteToBcd2(RTC_AlarmStruct->RTC_AlarmTime.RTC_Hours) << 16) | \ + ((uint32_t)RTC_ByteToBcd2(RTC_AlarmStruct->RTC_AlarmTime.RTC_Minutes) << 8) | \ + ((uint32_t)RTC_ByteToBcd2(RTC_AlarmStruct->RTC_AlarmTime.RTC_Seconds)) | \ + ((uint32_t)(RTC_AlarmStruct->RTC_AlarmTime.RTC_H12) << 16) | \ + ((uint32_t)RTC_ByteToBcd2(RTC_AlarmStruct->RTC_AlarmDateWeekDay) << 24) | \ + ((uint32_t)RTC_AlarmStruct->RTC_AlarmDateWeekDaySel) | \ + ((uint32_t)RTC_AlarmStruct->RTC_AlarmMask)); + } + + /* Disable the write protection for RTC registers */ + RTC->WPR = 0xCA; + RTC->WPR = 0x53; + + /* Configure the Alarm register */ + if (RTC_Alarm == RTC_Alarm_A) + { + RTC->ALRMAR = (uint32_t)tmpreg; + } + else + { + RTC->ALRMBR = (uint32_t)tmpreg; + } + + /* Enable the write protection for RTC registers */ + RTC->WPR = 0xFF; +} + +/** + * @brief Fills each RTC_AlarmStruct member with its default value + * (Time = 00h:00mn:00sec / Date = 1st day of the month/Mask = + * all fields are masked). + * @param RTC_AlarmStruct: pointer to a @ref RTC_AlarmTypeDef structure which + * will be initialized. + * @retval None + */ +void RTC_AlarmStructInit(RTC_AlarmTypeDef* RTC_AlarmStruct) +{ + /* Alarm Time Settings : Time = 00h:00mn:00sec */ + RTC_AlarmStruct->RTC_AlarmTime.RTC_H12 = RTC_H12_AM; + RTC_AlarmStruct->RTC_AlarmTime.RTC_Hours = 0; + RTC_AlarmStruct->RTC_AlarmTime.RTC_Minutes = 0; + RTC_AlarmStruct->RTC_AlarmTime.RTC_Seconds = 0; + + /* Alarm Date Settings : Date = 1st day of the month */ + RTC_AlarmStruct->RTC_AlarmDateWeekDaySel = RTC_AlarmDateWeekDaySel_Date; + RTC_AlarmStruct->RTC_AlarmDateWeekDay = 1; + + /* Alarm Masks Settings : Mask = all fields are not masked */ + RTC_AlarmStruct->RTC_AlarmMask = RTC_AlarmMask_None; +} + +/** + * @brief Get the RTC Alarm value and masks. + * @param RTC_Format: specifies the format of the output parameters. + * This parameter can be one of the following values: + * @arg RTC_Format_BIN: Binary data format + * @arg RTC_Format_BCD: BCD data format + * @param RTC_Alarm: specifies the alarm to be read. + * This parameter can be one of the following values: + * @arg RTC_Alarm_A: to select Alarm A + * @arg RTC_Alarm_B: to select Alarm B + * @param RTC_AlarmStruct: pointer to a RTC_AlarmTypeDef structure that will + * contains the output alarm configuration values. + * @retval None + */ +void RTC_GetAlarm(uint32_t RTC_Format, uint32_t RTC_Alarm, RTC_AlarmTypeDef* RTC_AlarmStruct) +{ + uint32_t tmpreg = 0; + + /* Check the parameters */ + assert_param(IS_RTC_FORMAT(RTC_Format)); + assert_param(IS_RTC_ALARM(RTC_Alarm)); + + /* Get the RTC_ALRMxR register */ + if (RTC_Alarm == RTC_Alarm_A) + { + tmpreg = (uint32_t)(RTC->ALRMAR); + } + else + { + tmpreg = (uint32_t)(RTC->ALRMBR); + } + + /* Fill the structure with the read parameters */ + RTC_AlarmStruct->RTC_AlarmTime.RTC_Hours = (uint32_t)((tmpreg & (RTC_ALRMAR_HT | \ + RTC_ALRMAR_HU)) >> 16); + RTC_AlarmStruct->RTC_AlarmTime.RTC_Minutes = (uint32_t)((tmpreg & (RTC_ALRMAR_MNT | \ + RTC_ALRMAR_MNU)) >> 8); + RTC_AlarmStruct->RTC_AlarmTime.RTC_Seconds = (uint32_t)(tmpreg & (RTC_ALRMAR_ST | \ + RTC_ALRMAR_SU)); + RTC_AlarmStruct->RTC_AlarmTime.RTC_H12 = (uint32_t)((tmpreg & RTC_ALRMAR_PM) >> 16); + RTC_AlarmStruct->RTC_AlarmDateWeekDay = (uint32_t)((tmpreg & (RTC_ALRMAR_DT | RTC_ALRMAR_DU)) >> 24); + RTC_AlarmStruct->RTC_AlarmDateWeekDaySel = (uint32_t)(tmpreg & RTC_ALRMAR_WDSEL); + RTC_AlarmStruct->RTC_AlarmMask = (uint32_t)(tmpreg & RTC_AlarmMask_All); + + if (RTC_Format == RTC_Format_BIN) + { + RTC_AlarmStruct->RTC_AlarmTime.RTC_Hours = RTC_Bcd2ToByte(RTC_AlarmStruct-> \ + RTC_AlarmTime.RTC_Hours); + RTC_AlarmStruct->RTC_AlarmTime.RTC_Minutes = RTC_Bcd2ToByte(RTC_AlarmStruct-> \ + RTC_AlarmTime.RTC_Minutes); + RTC_AlarmStruct->RTC_AlarmTime.RTC_Seconds = RTC_Bcd2ToByte(RTC_AlarmStruct-> \ + RTC_AlarmTime.RTC_Seconds); + RTC_AlarmStruct->RTC_AlarmDateWeekDay = RTC_Bcd2ToByte(RTC_AlarmStruct->RTC_AlarmDateWeekDay); + } +} + +/** + * @brief Enables or disables the specified RTC Alarm. + * @param RTC_Alarm: specifies the alarm to be configured. + * This parameter can be any combination of the following values: + * @arg RTC_Alarm_A: to select Alarm A + * @arg RTC_Alarm_B: to select Alarm B + * @param NewState: new state of the specified alarm. + * This parameter can be: ENABLE or DISABLE. + * @retval An ErrorStatus enumeration value: + * - SUCCESS: RTC Alarm is enabled/disabled + * - ERROR: RTC Alarm is not enabled/disabled + */ +ErrorStatus RTC_AlarmCmd(uint32_t RTC_Alarm, FunctionalState NewState) +{ + __IO uint32_t alarmcounter = 0x00; + uint32_t alarmstatus = 0x00; + ErrorStatus status = ERROR; + + /* Check the parameters */ + assert_param(IS_RTC_CMD_ALARM(RTC_Alarm)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + /* Disable the write protection for RTC registers */ + RTC->WPR = 0xCA; + RTC->WPR = 0x53; + + /* Configure the Alarm state */ + if (NewState != DISABLE) + { + RTC->CR |= (uint32_t)RTC_Alarm; + + status = SUCCESS; + } + else + { + /* Disable the Alarm in RTC_CR register */ + RTC->CR &= (uint32_t)~RTC_Alarm; + + /* Wait till RTC ALRxWF flag is set and if Time out is reached exit */ + do + { + alarmstatus = RTC->ISR & (RTC_Alarm >> 8); + alarmcounter++; + } while((alarmcounter != INITMODE_TIMEOUT) && (alarmstatus == 0x00)); + + if ((RTC->ISR & (RTC_Alarm >> 8)) == RESET) + { + status = ERROR; + } + else + { + status = SUCCESS; + } + } + + /* Enable the write protection for RTC registers */ + RTC->WPR = 0xFF; + + return status; +} + +/** + * @brief Configures the RTC AlarmA/B Subseconds value and mask. + * @note This function is performed only when the Alarm is disabled. + * @param RTC_Alarm: specifies the alarm to be configured. + * This parameter can be one of the following values: + * @arg RTC_Alarm_A: to select Alarm A + * @arg RTC_Alarm_B: to select Alarm B + * @param RTC_AlarmSubSecondValue: specifies the Subseconds value. + * This parameter can be a value from 0 to 0x00007FFF. + * @param RTC_AlarmSubSecondMask: specifies the Subseconds Mask. + * This parameter can be any combination of the following values: + * @arg RTC_AlarmSubSecondMask_All : All Alarm SS fields are masked. + * There is no comparison on sub seconds for Alarm. + * @arg RTC_AlarmSubSecondMask_SS14_1 : SS[14:1] are don't care in Alarm comparison. + * Only SS[0] is compared + * @arg RTC_AlarmSubSecondMask_SS14_2 : SS[14:2] are don't care in Alarm comparison. + * Only SS[1:0] are compared + * @arg RTC_AlarmSubSecondMask_SS14_3 : SS[14:3] are don't care in Alarm comparison. + * Only SS[2:0] are compared + * @arg RTC_AlarmSubSecondMask_SS14_4 : SS[14:4] are don't care in Alarm comparison. + * Only SS[3:0] are compared + * @arg RTC_AlarmSubSecondMask_SS14_5 : SS[14:5] are don't care in Alarm comparison. + * Only SS[4:0] are compared + * @arg RTC_AlarmSubSecondMask_SS14_6 : SS[14:6] are don't care in Alarm comparison. + * Only SS[5:0] are compared + * @arg RTC_AlarmSubSecondMask_SS14_7 : SS[14:7] are don't care in Alarm comparison. + * Only SS[6:0] are compared + * @arg RTC_AlarmSubSecondMask_SS14_8 : SS[14:8] are don't care in Alarm comparison. + * Only SS[7:0] are compared + * @arg RTC_AlarmSubSecondMask_SS14_9 : SS[14:9] are don't care in Alarm comparison. + * Only SS[8:0] are compared + * @arg RTC_AlarmSubSecondMask_SS14_10: SS[14:10] are don't care in Alarm comparison. + * Only SS[9:0] are compared + * @arg RTC_AlarmSubSecondMask_SS14_11: SS[14:11] are don't care in Alarm comparison. + * Only SS[10:0] are compared + * @arg RTC_AlarmSubSecondMask_SS14_12: SS[14:12] are don't care in Alarm comparison. + * Only SS[11:0] are compared + * @arg RTC_AlarmSubSecondMask_SS14_13: SS[14:13] are don't care in Alarm comparison. + * Only SS[12:0] are compared + * @arg RTC_AlarmSubSecondMask_SS14 : SS[14] is don't care in Alarm comparison. + * Only SS[13:0] are compared + * @arg RTC_AlarmSubSecondMask_None : SS[14:0] are compared and must match + * to activate alarm + * @retval None + */ +void RTC_AlarmSubSecondConfig(uint32_t RTC_Alarm, uint32_t RTC_AlarmSubSecondValue, uint32_t RTC_AlarmSubSecondMask) +{ + uint32_t tmpreg = 0; + + /* Check the parameters */ + assert_param(IS_RTC_ALARM(RTC_Alarm)); + assert_param(IS_RTC_ALARM_SUB_SECOND_VALUE(RTC_AlarmSubSecondValue)); + assert_param(IS_RTC_ALARM_SUB_SECOND_MASK(RTC_AlarmSubSecondMask)); + + /* Disable the write protection for RTC registers */ + RTC->WPR = 0xCA; + RTC->WPR = 0x53; + + /* Configure the Alarm A or Alarm B SubSecond registers */ + tmpreg = (uint32_t) (uint32_t)(RTC_AlarmSubSecondValue) | (uint32_t)(RTC_AlarmSubSecondMask); + + if (RTC_Alarm == RTC_Alarm_A) + { + /* Configure the AlarmA SubSecond register */ + RTC->ALRMASSR = tmpreg; + } + else + { + /* Configure the Alarm B SubSecond register */ + RTC->ALRMBSSR = tmpreg; + } + + /* Enable the write protection for RTC registers */ + RTC->WPR = 0xFF; + +} + +/** + * @brief Gets the RTC Alarm Subseconds value. + * @param RTC_Alarm: specifies the alarm to be read. + * This parameter can be one of the following values: + * @arg RTC_Alarm_A: to select Alarm A + * @arg RTC_Alarm_B: to select Alarm B + * @param None + * @retval RTC Alarm Subseconds value. + */ +uint32_t RTC_GetAlarmSubSecond(uint32_t RTC_Alarm) +{ + uint32_t tmpreg = 0; + + /* Get the RTC_ALRMxR register */ + if (RTC_Alarm == RTC_Alarm_A) + { + tmpreg = (uint32_t)((RTC->ALRMASSR) & RTC_ALRMASSR_SS); + } + else + { + tmpreg = (uint32_t)((RTC->ALRMBSSR) & RTC_ALRMBSSR_SS); + } + + return (tmpreg); +} + +/** + * @} + */ + +/** @defgroup RTC_Group4 WakeUp Timer configuration functions + * @brief WakeUp Timer configuration functions + * +@verbatim + =============================================================================== + ##### WakeUp Timer configuration functions ##### + =============================================================================== + [..] This section provide functions allowing to program and read the RTC WakeUp. + +@endverbatim + * @{ + */ + +/** + * @brief Configures the RTC Wakeup clock source. + * @note The WakeUp Clock source can only be changed when the RTC WakeUp + * is disabled (Use the RTC_WakeUpCmd(DISABLE)). + * @param RTC_WakeUpClock: Wakeup Clock source. + * This parameter can be one of the following values: + * @arg RTC_WakeUpClock_RTCCLK_Div16: RTC Wakeup Counter Clock = RTCCLK/16 + * @arg RTC_WakeUpClock_RTCCLK_Div8: RTC Wakeup Counter Clock = RTCCLK/8 + * @arg RTC_WakeUpClock_RTCCLK_Div4: RTC Wakeup Counter Clock = RTCCLK/4 + * @arg RTC_WakeUpClock_RTCCLK_Div2: RTC Wakeup Counter Clock = RTCCLK/2 + * @arg RTC_WakeUpClock_CK_SPRE_16bits: RTC Wakeup Counter Clock = CK_SPRE + * @arg RTC_WakeUpClock_CK_SPRE_17bits: RTC Wakeup Counter Clock = CK_SPRE + * @retval None + */ +void RTC_WakeUpClockConfig(uint32_t RTC_WakeUpClock) +{ + /* Check the parameters */ + assert_param(IS_RTC_WAKEUP_CLOCK(RTC_WakeUpClock)); + + /* Disable the write protection for RTC registers */ + RTC->WPR = 0xCA; + RTC->WPR = 0x53; + + /* Clear the Wakeup Timer clock source bits in CR register */ + RTC->CR &= (uint32_t)~RTC_CR_WUCKSEL; + + /* Configure the clock source */ + RTC->CR |= (uint32_t)RTC_WakeUpClock; + + /* Enable the write protection for RTC registers */ + RTC->WPR = 0xFF; +} + +/** + * @brief Configures the RTC Wakeup counter. + * @note The RTC WakeUp counter can only be written when the RTC WakeUp + * is disabled (Use the RTC_WakeUpCmd(DISABLE)). + * @param RTC_WakeUpCounter: specifies the WakeUp counter. + * This parameter can be a value from 0x0000 to 0xFFFF. + * @retval None + */ +void RTC_SetWakeUpCounter(uint32_t RTC_WakeUpCounter) +{ + /* Check the parameters */ + assert_param(IS_RTC_WAKEUP_COUNTER(RTC_WakeUpCounter)); + + /* Disable the write protection for RTC registers */ + RTC->WPR = 0xCA; + RTC->WPR = 0x53; + + /* Configure the Wakeup Timer counter */ + RTC->WUTR = (uint32_t)RTC_WakeUpCounter; + + /* Enable the write protection for RTC registers */ + RTC->WPR = 0xFF; +} + +/** + * @brief Returns the RTC WakeUp timer counter value. + * @param None + * @retval The RTC WakeUp Counter value. + */ +uint32_t RTC_GetWakeUpCounter(void) +{ + /* Get the counter value */ + return ((uint32_t)(RTC->WUTR & RTC_WUTR_WUT)); +} + +/** + * @brief Enables or Disables the RTC WakeUp timer. + * @param NewState: new state of the WakeUp timer. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +ErrorStatus RTC_WakeUpCmd(FunctionalState NewState) +{ + __IO uint32_t wutcounter = 0x00; + uint32_t wutwfstatus = 0x00; + ErrorStatus status = ERROR; + + /* Check the parameters */ + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + /* Disable the write protection for RTC registers */ + RTC->WPR = 0xCA; + RTC->WPR = 0x53; + + if (NewState != DISABLE) + { + /* Enable the Wakeup Timer */ + RTC->CR |= (uint32_t)RTC_CR_WUTE; + status = SUCCESS; + } + else + { + /* Disable the Wakeup Timer */ + RTC->CR &= (uint32_t)~RTC_CR_WUTE; + /* Wait till RTC WUTWF flag is set and if Time out is reached exit */ + do + { + wutwfstatus = RTC->ISR & RTC_ISR_WUTWF; + wutcounter++; + } while((wutcounter != INITMODE_TIMEOUT) && (wutwfstatus == 0x00)); + + if ((RTC->ISR & RTC_ISR_WUTWF) == RESET) + { + status = ERROR; + } + else + { + status = SUCCESS; + } + } + + /* Enable the write protection for RTC registers */ + RTC->WPR = 0xFF; + + return status; +} + +/** + * @} + */ + +/** @defgroup RTC_Group5 Daylight Saving configuration functions + * @brief Daylight Saving configuration functions + * +@verbatim + =============================================================================== + ##### Daylight Saving configuration functions ##### + =============================================================================== + [..] This section provide functions allowing to configure the RTC DayLight Saving. + +@endverbatim + * @{ + */ + +/** + * @brief Adds or substract one hour from the current time. + * @param RTC_DayLightSaveOperation: the value of hour adjustment. + * This parameter can be one of the following values: + * @arg RTC_DayLightSaving_SUB1H: Substract one hour (winter time) + * @arg RTC_DayLightSaving_ADD1H: Add one hour (summer time) + * @param RTC_StoreOperation: Specifies the value to be written in the BCK bit + * in CR register to store the operation. + * This parameter can be one of the following values: + * @arg RTC_StoreOperation_Reset: BCK Bit Reset + * @arg RTC_StoreOperation_Set: BCK Bit Set + * @retval None + */ +void RTC_DayLightSavingConfig(uint32_t RTC_DayLightSaving, uint32_t RTC_StoreOperation) +{ + /* Check the parameters */ + assert_param(IS_RTC_DAYLIGHT_SAVING(RTC_DayLightSaving)); + assert_param(IS_RTC_STORE_OPERATION(RTC_StoreOperation)); + + /* Disable the write protection for RTC registers */ + RTC->WPR = 0xCA; + RTC->WPR = 0x53; + + /* Clear the bits to be configured */ + RTC->CR &= (uint32_t)~(RTC_CR_BCK); + + /* Configure the RTC_CR register */ + RTC->CR |= (uint32_t)(RTC_DayLightSaving | RTC_StoreOperation); + + /* Enable the write protection for RTC registers */ + RTC->WPR = 0xFF; +} + +/** + * @brief Returns the RTC Day Light Saving stored operation. + * @param None + * @retval RTC Day Light Saving stored operation. + * - RTC_StoreOperation_Reset + * - RTC_StoreOperation_Set + */ +uint32_t RTC_GetStoreOperation(void) +{ + return (RTC->CR & RTC_CR_BCK); +} + +/** + * @} + */ + +/** @defgroup RTC_Group6 Output pin Configuration function + * @brief Output pin Configuration function + * +@verbatim + =============================================================================== + ##### Output pin Configuration function ##### + =============================================================================== + [..] This section provide functions allowing to configure the RTC Output source. + +@endverbatim + * @{ + */ + +/** + * @brief Configures the RTC output source (AFO_ALARM). + * @param RTC_Output: Specifies which signal will be routed to the RTC output. + * This parameter can be one of the following values: + * @arg RTC_Output_Disable: No output selected + * @arg RTC_Output_AlarmA: signal of AlarmA mapped to output + * @arg RTC_Output_AlarmB: signal of AlarmB mapped to output + * @arg RTC_Output_WakeUp: signal of WakeUp mapped to output + * @param RTC_OutputPolarity: Specifies the polarity of the output signal. + * This parameter can be one of the following: + * @arg RTC_OutputPolarity_High: The output pin is high when the + * ALRAF/ALRBF/WUTF is high (depending on OSEL) + * @arg RTC_OutputPolarity_Low: The output pin is low when the + * ALRAF/ALRBF/WUTF is high (depending on OSEL) + * @retval None + */ +void RTC_OutputConfig(uint32_t RTC_Output, uint32_t RTC_OutputPolarity) +{ + /* Check the parameters */ + assert_param(IS_RTC_OUTPUT(RTC_Output)); + assert_param(IS_RTC_OUTPUT_POL(RTC_OutputPolarity)); + + /* Disable the write protection for RTC registers */ + RTC->WPR = 0xCA; + RTC->WPR = 0x53; + + /* Clear the bits to be configured */ + RTC->CR &= (uint32_t)~(RTC_CR_OSEL | RTC_CR_POL); + + /* Configure the output selection and polarity */ + RTC->CR |= (uint32_t)(RTC_Output | RTC_OutputPolarity); + + /* Enable the write protection for RTC registers */ + RTC->WPR = 0xFF; +} + +/** + * @} + */ + +/** @defgroup RTC_Group7 Digital Calibration configuration functions + * @brief Digital Calibration configuration functions + * +@verbatim + =============================================================================== + ##### Digital Calibration configuration functions ##### + =============================================================================== + +@endverbatim + * @{ + */ + +/** + * @brief Enables or disables the RTC clock to be output through the relative + * pin. + * @param NewState: new state of the digital calibration Output. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void RTC_CalibOutputCmd(FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + /* Disable the write protection for RTC registers */ + RTC->WPR = 0xCA; + RTC->WPR = 0x53; + + if (NewState != DISABLE) + { + /* Enable the RTC clock output */ + RTC->CR |= (uint32_t)RTC_CR_COE; + } + else + { + /* Disable the RTC clock output */ + RTC->CR &= (uint32_t)~RTC_CR_COE; + } + + /* Enable the write protection for RTC registers */ + RTC->WPR = 0xFF; +} + +/** + * @brief Configures the Calibration Pinout (RTC_CALIB) Selection (1Hz or 512Hz). + * @param RTC_CalibOutput : Select the Calibration output Selection . + * This parameter can be one of the following values: + * @arg RTC_CalibOutput_512Hz: A signal has a regular waveform at 512Hz. + * @arg RTC_CalibOutput_1Hz : A signal has a regular waveform at 1Hz. + * @retval None +*/ +void RTC_CalibOutputConfig(uint32_t RTC_CalibOutput) +{ + /* Check the parameters */ + assert_param(IS_RTC_CALIB_OUTPUT(RTC_CalibOutput)); + + /* Disable the write protection for RTC registers */ + RTC->WPR = 0xCA; + RTC->WPR = 0x53; + + /*clear flags before config*/ + RTC->CR &= (uint32_t)~(RTC_CR_COSEL); + + /* Configure the RTC_CR register */ + RTC->CR |= (uint32_t)RTC_CalibOutput; + + /* Enable the write protection for RTC registers */ + RTC->WPR = 0xFF; +} + +/** + * @brief Configures the Smooth Calibration Settings. + * @param RTC_SmoothCalibPeriod : Select the Smooth Calibration Period. + * This parameter can be can be one of the following values: + * @arg RTC_SmoothCalibPeriod_32sec : The smooth calibration periode is 32s. + * @arg RTC_SmoothCalibPeriod_16sec : The smooth calibration periode is 16s. + * @arg RTC_SmoothCalibPeriod_8sec : The smooth calibration periode is 8s. + * @param RTC_SmoothCalibPlusPulses : Select to Set or reset the CALP bit. + * This parameter can be one of the following values: + * @arg RTC_SmoothCalibPlusPulses_Set : Add one RTCCLK puls every 2**11 pulses. + * @arg RTC_SmoothCalibPlusPulses_Reset: No RTCCLK pulses are added. + * @param RTC_SmouthCalibMinusPulsesValue: Select the value of CALM[8:0] bits. + * This parameter can be one any value from 0 to 0x000001FF. + * @retval An ErrorStatus enumeration value: + * - SUCCESS: RTC Calib registers are configured + * - ERROR: RTC Calib registers are not configured +*/ +ErrorStatus RTC_SmoothCalibConfig(uint32_t RTC_SmoothCalibPeriod, + uint32_t RTC_SmoothCalibPlusPulses, + uint32_t RTC_SmouthCalibMinusPulsesValue) +{ + ErrorStatus status = ERROR; + uint32_t recalpfcount = 0; + + /* Check the parameters */ + assert_param(IS_RTC_SMOOTH_CALIB_PERIOD(RTC_SmoothCalibPeriod)); + assert_param(IS_RTC_SMOOTH_CALIB_PLUS(RTC_SmoothCalibPlusPulses)); + assert_param(IS_RTC_SMOOTH_CALIB_MINUS(RTC_SmouthCalibMinusPulsesValue)); + + /* Disable the write protection for RTC registers */ + RTC->WPR = 0xCA; + RTC->WPR = 0x53; + + /* check if a calibration is pending*/ + if ((RTC->ISR & RTC_ISR_RECALPF) != RESET) + { + /* wait until the Calibration is completed*/ + while (((RTC->ISR & RTC_ISR_RECALPF) != RESET) && (recalpfcount != RECALPF_TIMEOUT)) + { + recalpfcount++; + } + } + + /* check if the calibration pending is completed or if there is no calibration operation at all*/ + if ((RTC->ISR & RTC_ISR_RECALPF) == RESET) + { + /* Configure the Smooth calibration settings */ + RTC->CALR = (uint32_t)((uint32_t)RTC_SmoothCalibPeriod | (uint32_t)RTC_SmoothCalibPlusPulses | (uint32_t)RTC_SmouthCalibMinusPulsesValue); + + status = SUCCESS; + } + else + { + status = ERROR; + } + + /* Enable the write protection for RTC registers */ + RTC->WPR = 0xFF; + + return (ErrorStatus)(status); +} + +/** + * @} + */ + + +/** @defgroup RTC_Group8 TimeStamp configuration functions + * @brief TimeStamp configuration functions + * +@verbatim + =============================================================================== + ##### TimeStamp configuration functions ##### + =============================================================================== + +@endverbatim + * @{ + */ + +/** + * @brief Enables or Disables the RTC TimeStamp functionality with the + * specified time stamp pin stimulating edge. + * @param RTC_TimeStampEdge: Specifies the pin edge on which the TimeStamp is + * activated. + * This parameter can be one of the following: + * @arg RTC_TimeStampEdge_Rising: the Time stamp event occurs on the rising + * edge of the related pin. + * @arg RTC_TimeStampEdge_Falling: the Time stamp event occurs on the + * falling edge of the related pin. + * @param NewState: new state of the TimeStamp. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void RTC_TimeStampCmd(uint32_t RTC_TimeStampEdge, FunctionalState NewState) +{ + uint32_t tmpreg = 0; + + /* Check the parameters */ + assert_param(IS_RTC_TIMESTAMP_EDGE(RTC_TimeStampEdge)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + /* Get the RTC_CR register and clear the bits to be configured */ + tmpreg = (uint32_t)(RTC->CR & (uint32_t)~(RTC_CR_TSEDGE | RTC_CR_TSE)); + + /* Get the new configuration */ + if (NewState != DISABLE) + { + tmpreg |= (uint32_t)(RTC_TimeStampEdge | RTC_CR_TSE); + } + else + { + tmpreg |= (uint32_t)(RTC_TimeStampEdge); + } + + /* Disable the write protection for RTC registers */ + RTC->WPR = 0xCA; + RTC->WPR = 0x53; + + /* Configure the Time Stamp TSEDGE and Enable bits */ + RTC->CR = (uint32_t)tmpreg; + + /* Enable the write protection for RTC registers */ + RTC->WPR = 0xFF; +} + +/** + * @brief Gets the RTC TimeStamp value and masks. + * @param RTC_Format: specifies the format of the output parameters. + * This parameter can be one of the following values: + * @arg RTC_Format_BIN: Binary data format + * @arg RTC_Format_BCD: BCD data format + * @param RTC_StampTimeStruct: pointer to a RTC_TimeTypeDef structure that will + * contains the TimeStamp time values. + * @param RTC_StampDateStruct: pointer to a RTC_DateTypeDef structure that will + * contains the TimeStamp date values. + * @retval None + */ +void RTC_GetTimeStamp(uint32_t RTC_Format, RTC_TimeTypeDef* RTC_StampTimeStruct, + RTC_DateTypeDef* RTC_StampDateStruct) +{ + uint32_t tmptime = 0, tmpdate = 0; + + /* Check the parameters */ + assert_param(IS_RTC_FORMAT(RTC_Format)); + + /* Get the TimeStamp time and date registers values */ + tmptime = (uint32_t)(RTC->TSTR & RTC_TR_RESERVED_MASK); + tmpdate = (uint32_t)(RTC->TSDR & RTC_DR_RESERVED_MASK); + + /* Fill the Time structure fields with the read parameters */ + RTC_StampTimeStruct->RTC_Hours = (uint8_t)((tmptime & (RTC_TR_HT | RTC_TR_HU)) >> 16); + RTC_StampTimeStruct->RTC_Minutes = (uint8_t)((tmptime & (RTC_TR_MNT | RTC_TR_MNU)) >> 8); + RTC_StampTimeStruct->RTC_Seconds = (uint8_t)(tmptime & (RTC_TR_ST | RTC_TR_SU)); + RTC_StampTimeStruct->RTC_H12 = (uint8_t)((tmptime & (RTC_TR_PM)) >> 16); + + /* Fill the Date structure fields with the read parameters */ + RTC_StampDateStruct->RTC_Year = 0; + RTC_StampDateStruct->RTC_Month = (uint8_t)((tmpdate & (RTC_DR_MT | RTC_DR_MU)) >> 8); + RTC_StampDateStruct->RTC_Date = (uint8_t)(tmpdate & (RTC_DR_DT | RTC_DR_DU)); + RTC_StampDateStruct->RTC_WeekDay = (uint8_t)((tmpdate & (RTC_DR_WDU)) >> 13); + + /* Check the input parameters format */ + if (RTC_Format == RTC_Format_BIN) + { + /* Convert the Time structure parameters to Binary format */ + RTC_StampTimeStruct->RTC_Hours = (uint8_t)RTC_Bcd2ToByte(RTC_StampTimeStruct->RTC_Hours); + RTC_StampTimeStruct->RTC_Minutes = (uint8_t)RTC_Bcd2ToByte(RTC_StampTimeStruct->RTC_Minutes); + RTC_StampTimeStruct->RTC_Seconds = (uint8_t)RTC_Bcd2ToByte(RTC_StampTimeStruct->RTC_Seconds); + + /* Convert the Date structure parameters to Binary format */ + RTC_StampDateStruct->RTC_Month = (uint8_t)RTC_Bcd2ToByte(RTC_StampDateStruct->RTC_Month); + RTC_StampDateStruct->RTC_Date = (uint8_t)RTC_Bcd2ToByte(RTC_StampDateStruct->RTC_Date); + RTC_StampDateStruct->RTC_WeekDay = (uint8_t)RTC_Bcd2ToByte(RTC_StampDateStruct->RTC_WeekDay); + } +} + +/** + * @brief Gets the RTC timestamp Subseconds value. + * @param None + * @retval RTC current timestamp Subseconds value. + */ +uint32_t RTC_GetTimeStampSubSecond(void) +{ + /* Get timestamp subseconds values from the correspondent registers */ + return (uint32_t)(RTC->TSSSR); +} + +/** + * @} + */ + +/** @defgroup RTC_Group9 Tampers configuration functions + * @brief Tampers configuration functions + * +@verbatim + =============================================================================== + ##### Tampers configuration functions ##### + =============================================================================== + +@endverbatim + * @{ + */ + +/** + * @brief Configures the select Tamper pin edge. + * @param RTC_Tamper: Selected tamper pin. + * This parameter can be any combination of the following values: + * @arg RTC_Tamper_1: Select Tamper 1. + * @arg RTC_Tamper_2: Select Tamper 2. + * @arg RTC_Tamper_3: Select Tamper 3. + * @param RTC_TamperTrigger: Specifies the trigger on the tamper pin that + * stimulates tamper event. + * This parameter can be one of the following values: + * @arg RTC_TamperTrigger_RisingEdge: Rising Edge of the tamper pin causes tamper event. + * @arg RTC_TamperTrigger_FallingEdge: Falling Edge of the tamper pin causes tamper event. + * @arg RTC_TamperTrigger_LowLevel: Low Level of the tamper pin causes tamper event. + * @arg RTC_TamperTrigger_HighLevel: High Level of the tamper pin causes tamper event. + * @retval None + */ +void RTC_TamperTriggerConfig(uint32_t RTC_Tamper, uint32_t RTC_TamperTrigger) +{ + /* Check the parameters */ + assert_param(IS_RTC_TAMPER(RTC_Tamper)); + assert_param(IS_RTC_TAMPER_TRIGGER(RTC_TamperTrigger)); + + /* Check if the active level for Tamper is rising edge (Low level)*/ + if (RTC_TamperTrigger == RTC_TamperTrigger_RisingEdge) + { + /* Configure the RTC_TAFCR register */ + RTC->TAFCR &= (uint32_t)((uint32_t)~(RTC_Tamper << 1)); + } + else + { + /* Configure the RTC_TAFCR register */ + RTC->TAFCR |= (uint32_t)(RTC_Tamper << 1); + } +} + +/** + * @brief Enables or Disables the Tamper detection. + * @param RTC_Tamper: Selected tamper pin. + * This parameter can be any combination of the following values: + * @arg RTC_Tamper_1: Select Tamper 1. + * @arg RTC_Tamper_2: Select Tamper 2. + * @arg RTC_Tamper_3: Select Tamper 3. + * @param NewState: new state of the tamper pin. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void RTC_TamperCmd(uint32_t RTC_Tamper, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_RTC_TAMPER(RTC_Tamper)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable the selected Tamper pin */ + RTC->TAFCR |= (uint32_t)RTC_Tamper; + } + else + { + /* Disable the selected Tamper pin */ + RTC->TAFCR &= (uint32_t)~RTC_Tamper; + } +} + +/** + * @brief Configures the Tampers Filter. + * @param RTC_TamperFilter: Specifies the tampers filter. + * This parameter can be one of the following values: + * @arg RTC_TamperFilter_Disable: Tamper filter is disabled. + * @arg RTC_TamperFilter_2Sample: Tamper is activated after 2 consecutive + * samples at the active level + * @arg RTC_TamperFilter_4Sample: Tamper is activated after 4 consecutive + * samples at the active level + * @arg RTC_TamperFilter_8Sample: Tamper is activated after 8 consecutive + * samples at the active level + * @retval None + */ +void RTC_TamperFilterConfig(uint32_t RTC_TamperFilter) +{ + /* Check the parameters */ + assert_param(IS_RTC_TAMPER_FILTER(RTC_TamperFilter)); + + /* Clear TAMPFLT[1:0] bits in the RTC_TAFCR register */ + RTC->TAFCR &= (uint32_t)~(RTC_TAFCR_TAMPFLT); + + /* Configure the RTC_TAFCR register */ + RTC->TAFCR |= (uint32_t)RTC_TamperFilter; +} + +/** + * @brief Configures the Tampers Sampling Frequency. + * @param RTC_TamperSamplingFreq: Specifies the tampers Sampling Frequency. + * This parameter can be one of the following values: + * @arg RTC_TamperSamplingFreq_RTCCLK_Div32768: Each of the tamper inputs are sampled + * with a frequency = RTCCLK / 32768 + * @arg RTC_TamperSamplingFreq_RTCCLK_Div16384: Each of the tamper inputs are sampled + * with a frequency = RTCCLK / 16384 + * @arg RTC_TamperSamplingFreq_RTCCLK_Div8192: Each of the tamper inputs are sampled + * with a frequency = RTCCLK / 8192 + * @arg RTC_TamperSamplingFreq_RTCCLK_Div4096: Each of the tamper inputs are sampled + * with a frequency = RTCCLK / 4096 + * @arg RTC_TamperSamplingFreq_RTCCLK_Div2048: Each of the tamper inputs are sampled + * with a frequency = RTCCLK / 2048 + * @arg RTC_TamperSamplingFreq_RTCCLK_Div1024: Each of the tamper inputs are sampled + * with a frequency = RTCCLK / 1024 + * @arg RTC_TamperSamplingFreq_RTCCLK_Div512: Each of the tamper inputs are sampled + * with a frequency = RTCCLK / 512 + * @arg RTC_TamperSamplingFreq_RTCCLK_Div256: Each of the tamper inputs are sampled + * with a frequency = RTCCLK / 256 + * @retval None + */ +void RTC_TamperSamplingFreqConfig(uint32_t RTC_TamperSamplingFreq) +{ + /* Check the parameters */ + assert_param(IS_RTC_TAMPER_SAMPLING_FREQ(RTC_TamperSamplingFreq)); + + /* Clear TAMPFREQ[2:0] bits in the RTC_TAFCR register */ + RTC->TAFCR &= (uint32_t)~(RTC_TAFCR_TAMPFREQ); + + /* Configure the RTC_TAFCR register */ + RTC->TAFCR |= (uint32_t)RTC_TamperSamplingFreq; +} + +/** + * @brief Configures the Tampers Pins input Precharge Duration. + * @param RTC_TamperPrechargeDuration: Specifies the Tampers Pins input + * Precharge Duration. + * This parameter can be one of the following values: + * @arg RTC_TamperPrechargeDuration_1RTCCLK: Tamper pins are pre-charged before sampling during 1 RTCCLK cycle + * @arg RTC_TamperPrechargeDuration_2RTCCLK: Tamper pins are pre-charged before sampling during 2 RTCCLK cycle + * @arg RTC_TamperPrechargeDuration_4RTCCLK: Tamper pins are pre-charged before sampling during 4 RTCCLK cycle + * @arg RTC_TamperPrechargeDuration_8RTCCLK: Tamper pins are pre-charged before sampling during 8 RTCCLK cycle + * @retval None + */ +void RTC_TamperPinsPrechargeDuration(uint32_t RTC_TamperPrechargeDuration) +{ + /* Check the parameters */ + assert_param(IS_RTC_TAMPER_PRECHARGE_DURATION(RTC_TamperPrechargeDuration)); + + /* Clear TAMPPRCH[1:0] bits in the RTC_TAFCR register */ + RTC->TAFCR &= (uint32_t)~(RTC_TAFCR_TAMPPRCH); + + /* Configure the RTC_TAFCR register */ + RTC->TAFCR |= (uint32_t)RTC_TamperPrechargeDuration; +} + +/** + * @brief Enables or Disables the TimeStamp on Tamper Detection Event. + * @note The timestamp is valid even the TSE bit in tamper control register + * is reset. + * @param NewState: new state of the timestamp on tamper event. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void RTC_TimeStampOnTamperDetectionCmd(FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Save timestamp on tamper detection event */ + RTC->TAFCR |= (uint32_t)RTC_TAFCR_TAMPTS; + } + else + { + /* Tamper detection does not cause a timestamp to be saved */ + RTC->TAFCR &= (uint32_t)~RTC_TAFCR_TAMPTS; + } +} + +/** + * @brief Enables or Disables the Precharge of Tamper pin. + * @param NewState: new state of tamper pull up. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void RTC_TamperPullUpCmd(FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable precharge of the selected Tamper pin */ + RTC->TAFCR &= (uint32_t)~RTC_TAFCR_TAMPPUDIS; + } + else + { + /* Disable precharge of the selected Tamper pin */ + RTC->TAFCR |= (uint32_t)RTC_TAFCR_TAMPPUDIS; + } +} + +/** + * @} + */ + +/** @defgroup RTC_Group10 Backup Data Registers configuration functions + * @brief Backup Data Registers configuration functions + * +@verbatim + =============================================================================== + ##### Backup Data Registers configuration functions ##### + =============================================================================== + +@endverbatim + * @{ + */ + +/** + * @brief Writes a data in a specified RTC Backup data register. + * @param RTC_BKP_DR: RTC Backup data Register number. + * This parameter can be: RTC_BKP_DRx where x can be from 0 to 15 to + * specify the register. + * @param Data: Data to be written in the specified RTC Backup data register. + * @retval None + */ +void RTC_WriteBackupRegister(uint32_t RTC_BKP_DR, uint32_t Data) +{ + __IO uint32_t tmp = 0; + + /* Check the parameters */ + assert_param(IS_RTC_BKP(RTC_BKP_DR)); + + tmp = RTC_BASE + 0x50; + tmp += (RTC_BKP_DR * 4); + + /* Write the specified register */ + *(__IO uint32_t *)tmp = (uint32_t)Data; +} + +/** + * @brief Reads data from the specified RTC Backup data Register. + * @param RTC_BKP_DR: RTC Backup data Register number. + * This parameter can be: RTC_BKP_DRx where x can be from 0 to 15 to + * specify the register. + * @retval None + */ +uint32_t RTC_ReadBackupRegister(uint32_t RTC_BKP_DR) +{ + __IO uint32_t tmp = 0; + + /* Check the parameters */ + assert_param(IS_RTC_BKP(RTC_BKP_DR)); + + tmp = RTC_BASE + 0x50; + tmp += (RTC_BKP_DR * 4); + + /* Read the specified register */ + return (*(__IO uint32_t *)tmp); +} + +/** + * @} + */ + +/** @defgroup RTC_Group11 Output Type Config configuration functions + * @brief Output Type Config configuration functions + * +@verbatim + =============================================================================== + ##### Output Type Config configuration functions ##### + =============================================================================== + +@endverbatim + * @{ + */ + +/** + * @brief Configures the RTC Output Pin mode. + * @param RTC_OutputType: specifies the RTC Output (PC13) pin mode. + * This parameter can be one of the following values: + * @arg RTC_OutputType_OpenDrain: RTC Output (PC13) is configured in + * Open Drain mode. + * @arg RTC_OutputType_PushPull: RTC Output (PC13) is configured in + * Push Pull mode. + * @retval None + */ +void RTC_OutputTypeConfig(uint32_t RTC_OutputType) +{ + /* Check the parameters */ + assert_param(IS_RTC_OUTPUT_TYPE(RTC_OutputType)); + + RTC->TAFCR &= (uint32_t)~(RTC_TAFCR_ALARMOUTTYPE); + RTC->TAFCR |= (uint32_t)(RTC_OutputType); +} + +/** + * @} + */ + +/** @defgroup RTC_Group12 Shift control synchronisation functions + * @brief Shift control synchronisation functions + * +@verbatim + =============================================================================== + ##### Shift control synchronisation functions ##### + =============================================================================== + +@endverbatim + * @{ + */ + +/** + * @brief Configures the Synchronization Shift Control Settings. + * @note When REFCKON is set, firmware must not write to Shift control register + * @param RTC_ShiftAdd1S : Select to add or not 1 second to the time Calendar. + * This parameter can be one of the following values : + * @arg RTC_ShiftAdd1S_Set : Add one second to the clock calendar. + * @arg RTC_ShiftAdd1S_Reset: No effect. + * @param RTC_ShiftSubFS: Select the number of Second Fractions to Substitute. + * This parameter can be one any value from 0 to 0x7FFF. + * @retval An ErrorStatus enumeration value: + * - SUCCESS: RTC Shift registers are configured + * - ERROR: RTC Shift registers are not configured +*/ +ErrorStatus RTC_SynchroShiftConfig(uint32_t RTC_ShiftAdd1S, uint32_t RTC_ShiftSubFS) +{ + ErrorStatus status = ERROR; + uint32_t shpfcount = 0; + + /* Check the parameters */ + assert_param(IS_RTC_SHIFT_ADD1S(RTC_ShiftAdd1S)); + assert_param(IS_RTC_SHIFT_SUBFS(RTC_ShiftSubFS)); + + /* Disable the write protection for RTC registers */ + RTC->WPR = 0xCA; + RTC->WPR = 0x53; + + /* Check if a Shift is pending*/ + if ((RTC->ISR & RTC_ISR_SHPF) != RESET) + { + /* Wait until the shift is completed*/ + while (((RTC->ISR & RTC_ISR_SHPF) != RESET) && (shpfcount != SHPF_TIMEOUT)) + { + shpfcount++; + } + } + + /* Check if the Shift pending is completed or if there is no Shift operation at all*/ + if ((RTC->ISR & RTC_ISR_SHPF) == RESET) + { + /* check if the reference clock detection is disabled */ + if((RTC->CR & RTC_CR_REFCKON) == RESET) + { + /* Configure the Shift settings */ + RTC->SHIFTR = (uint32_t)(uint32_t)(RTC_ShiftSubFS) | (uint32_t)(RTC_ShiftAdd1S); + + if(RTC_WaitForSynchro() == ERROR) + { + status = ERROR; + } + else + { + status = SUCCESS; + } + } + else + { + status = ERROR; + } + } + else + { + status = ERROR; + } + + /* Enable the write protection for RTC registers */ + RTC->WPR = 0xFF; + + return (ErrorStatus)(status); +} + +/** + * @} + */ + +/** @defgroup RTC_Group13 Interrupts and flags management functions + * @brief Interrupts and flags management functions + * +@verbatim + =============================================================================== + ##### Interrupts and flags management functions ##### + =============================================================================== + [..] All RTC interrupts are connected to the EXTI controller. + (+) To enable the RTC Alarm interrupt, the following sequence is required: + (++) Configure and enable the EXTI Line 17 in interrupt mode and select + the rising edge sensitivity using the EXTI_Init() function. + (++) Configure and enable the RTC_Alarm IRQ channel in the NVIC using + the NVIC_Init() function. + (++) Configure the RTC to generate RTC alarms (Alarm A and/or Alarm B) + using the RTC_SetAlarm() and RTC_AlarmCmd() functions. + (+) To enable the RTC Wakeup interrupt, the following sequence is required: + (++) Configure and enable the EXTI Line 20 in interrupt mode and select + the rising edge sensitivity using the EXTI_Init() function. + (++) Configure and enable the RTC_WKUP IRQ channel in the NVIC using + the NVIC_Init() function. + (++) Configure the RTC to generate the RTC wakeup timer event using the + RTC_WakeUpClockConfig(), RTC_SetWakeUpCounter() and RTC_WakeUpCmd() + functions. + (+) To enable the RTC Tamper interrupt, the following sequence is required: + (++) Configure and enable the EXTI Line 19 in interrupt mode and select + the rising edge sensitivity using the EXTI_Init() function. + (++) Configure and enable the TAMP_STAMP IRQ channel in the NVIC using + the NVIC_Init() function. + (++) Configure the RTC to detect the RTC tamper event using the + RTC_TamperTriggerConfig() and RTC_TamperCmd() functions. + (+) To enable the RTC TimeStamp interrupt, the following sequence is required: + (++) Configure and enable the EXTI Line 19 in interrupt mode and select + the rising edge sensitivity using the EXTI_Init() function. + (++) Configure and enable the TAMP_STAMP IRQ channel in the NVIC using + the NVIC_Init() function. + (++) Configure the RTC to detect the RTC time-stamp event using the + RTC_TimeStampCmd() functions. + +@endverbatim + * @{ + */ + +/** + * @brief Enables or disables the specified RTC interrupts. + * @param RTC_IT: specifies the RTC interrupt sources to be enabled or disabled. + * This parameter can be any combination of the following values: + * @arg RTC_IT_TS: Time Stamp interrupt mask + * @arg RTC_IT_WUT: WakeUp Timer interrupt mask + * @arg RTC_IT_ALRB: Alarm B interrupt mask + * @arg RTC_IT_ALRA: Alarm A interrupt mask + * @arg RTC_IT_TAMP: Tamper event interrupt mask + * @param NewState: new state of the specified RTC interrupts. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void RTC_ITConfig(uint32_t RTC_IT, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_RTC_CONFIG_IT(RTC_IT)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + /* Disable the write protection for RTC registers */ + RTC->WPR = 0xCA; + RTC->WPR = 0x53; + + if (NewState != DISABLE) + { + /* Configure the Interrupts in the RTC_CR register */ + RTC->CR |= (uint32_t)(RTC_IT & ~RTC_TAFCR_TAMPIE); + /* Configure the Tamper Interrupt in the RTC_TAFCR */ + RTC->TAFCR |= (uint32_t)(RTC_IT & RTC_TAFCR_TAMPIE); + } + else + { + /* Configure the Interrupts in the RTC_CR register */ + RTC->CR &= (uint32_t)~(RTC_IT & (uint32_t)~RTC_TAFCR_TAMPIE); + /* Configure the Tamper Interrupt in the RTC_TAFCR */ + RTC->TAFCR &= (uint32_t)~(RTC_IT & RTC_TAFCR_TAMPIE); + } + /* Enable the write protection for RTC registers */ + RTC->WPR = 0xFF; +} + +/** + * @brief Checks whether the specified RTC flag is set or not. + * @param RTC_FLAG: specifies the flag to check. + * This parameter can be one of the following values: + * @arg RTC_FLAG_RECALPF: RECALPF event flag + * @arg RTC_FLAG_TAMP3F: Tamper 3 event flag + * @arg RTC_FLAG_TAMP2F: Tamper 2 event flag + * @arg RTC_FLAG_TAMP1F: Tamper 1 event flag + * @arg RTC_FLAG_TSOVF: Time Stamp OverFlow flag + * @arg RTC_FLAG_TSF: Time Stamp event flag + * @arg RTC_FLAG_WUTF: WakeUp Timer flag + * @arg RTC_FLAG_ALRBF: Alarm B flag + * @arg RTC_FLAG_ALRAF: Alarm A flag + * @arg RTC_FLAG_INITF: Initialization mode flag + * @arg RTC_FLAG_RSF: Registers Synchronized flag + * @arg RTC_FLAG_INITS: Registers Configured flag + * @argRTC_FLAG_SHPF : Shift operation pending flag. + * @arg RTC_FLAG_WUTWF: WakeUp Timer Write flag + * @arg RTC_FLAG_ALRBWF: Alarm B Write flag + * @arg RTC_FLAG_ALRAWF: Alarm A write flag + * @retval The new state of RTC_FLAG (SET or RESET). + */ +FlagStatus RTC_GetFlagStatus(uint32_t RTC_FLAG) +{ + FlagStatus bitstatus = RESET; + uint32_t tmpreg = 0; + + /* Check the parameters */ + assert_param(IS_RTC_GET_FLAG(RTC_FLAG)); + + /* Get all the flags */ + tmpreg = (uint32_t)(RTC->ISR & RTC_FLAGS_MASK); + + /* Return the status of the flag */ + if ((tmpreg & RTC_FLAG) != (uint32_t)RESET) + { + bitstatus = SET; + } + else + { + bitstatus = RESET; + } + return bitstatus; +} + +/** + * @brief Clears the RTC's pending flags. + * @param RTC_FLAG: specifies the RTC flag to clear. + * This parameter can be any combination of the following values: + * @arg RTC_FLAG_TAMP3F: Tamper 3 event flag + * @arg RTC_FLAG_TAMP2F: Tamper 2 event flag + * @arg RTC_FLAG_TAMP1F: Tamper 1 event flag + * @arg RTC_FLAG_TSOVF: Time Stamp Overflow flag + * @arg RTC_FLAG_TSF: Time Stamp event flag + * @arg RTC_FLAG_WUTF: WakeUp Timer flag + * @arg RTC_FLAG_ALRBF: Alarm B flag + * @arg RTC_FLAG_ALRAF: Alarm A flag + * @arg RTC_FLAG_RSF: Registers Synchronized flag + * @retval None + */ +void RTC_ClearFlag(uint32_t RTC_FLAG) +{ + /* Check the parameters */ + assert_param(IS_RTC_CLEAR_FLAG(RTC_FLAG)); + + /* Clear the Flags in the RTC_ISR register */ + RTC->ISR = (uint32_t)((uint32_t)(~((RTC_FLAG | RTC_ISR_INIT)& 0x0001FFFF) | (uint32_t)(RTC->ISR & RTC_ISR_INIT))); +} + +/** + * @brief Checks whether the specified RTC interrupt has occurred or not. + * @param RTC_IT: specifies the RTC interrupt source to check. + * This parameter can be one of the following values: + * @arg RTC_IT_TS: Time Stamp interrupt + * @arg RTC_IT_WUT: WakeUp Timer interrupt + * @arg RTC_IT_ALRB: Alarm B interrupt + * @arg RTC_IT_ALRA: Alarm A interrupt + * @arg RTC_IT_TAMP1: Tamper1 event interrupt + * @arg RTC_IT_TAMP2: Tamper2 event interrupt + * @arg RTC_IT_TAMP3: Tamper3 event interrupt + * @retval The new state of RTC_IT (SET or RESET). + */ +ITStatus RTC_GetITStatus(uint32_t RTC_IT) +{ + ITStatus bitstatus = RESET; + uint32_t tmpreg = 0, enablestatus = 0; + + /* Check the parameters */ + assert_param(IS_RTC_GET_IT(RTC_IT)); + + /* Get the TAMPER Interrupt enable bit and pending bit */ + tmpreg = (uint32_t)(RTC->TAFCR & (RTC_TAFCR_TAMPIE)); + + /* Get the Interrupt enable Status */ + enablestatus = (uint32_t)((RTC->CR & RTC_IT) | (tmpreg & ((RTC_IT >> (RTC_IT >> 18)) >> 15))); + + /* Get the Interrupt pending bit */ + tmpreg = (uint32_t)((RTC->ISR & (uint32_t)(RTC_IT >> 4))); + + /* Get the status of the Interrupt */ + if ((enablestatus != (uint32_t)RESET) && ((tmpreg & 0x0000FFFF) != (uint32_t)RESET)) + { + bitstatus = SET; + } + else + { + bitstatus = RESET; + } + return bitstatus; +} + +/** + * @brief Clears the RTC's interrupt pending bits. + * @param RTC_IT: specifies the RTC interrupt pending bit to clear. + * This parameter can be any combination of the following values: + * @arg RTC_IT_TS: Time Stamp interrupt + * @arg RTC_IT_WUT: WakeUp Timer interrupt + * @arg RTC_IT_ALRB: Alarm B interrupt + * @arg RTC_IT_ALRA: Alarm A interrupt + * @arg RTC_IT_TAMP1: Tamper1 event interrupt + * @arg RTC_IT_TAMP2: Tamper2 event interrupt + * @arg RTC_IT_TAMP3: Tamper3 event interrupt + * @retval None + */ +void RTC_ClearITPendingBit(uint32_t RTC_IT) +{ + uint32_t tmpreg = 0; + + /* Check the parameters */ + assert_param(IS_RTC_CLEAR_IT(RTC_IT)); + + /* Get the RTC_ISR Interrupt pending bits mask */ + tmpreg = (uint32_t)(RTC_IT >> 4); + + /* Clear the interrupt pending bits in the RTC_ISR register */ + RTC->ISR = (uint32_t)((uint32_t)(~((tmpreg | RTC_ISR_INIT)& 0x0000FFFF) | (uint32_t)(RTC->ISR & RTC_ISR_INIT))); +} + +/** + * @} + */ + +/** + * @brief Converts a 2 digit decimal to BCD format. + * @param Value: Byte to be converted. + * @retval Converted byte + */ +static uint8_t RTC_ByteToBcd2(uint8_t Value) +{ + uint8_t bcdhigh = 0; + + while (Value >= 10) + { + bcdhigh++; + Value -= 10; + } + + return ((uint8_t)(bcdhigh << 4) | Value); +} + +/** + * @brief Convert from 2 digit BCD to Binary. + * @param Value: BCD value to be converted. + * @retval Converted word + */ +static uint8_t RTC_Bcd2ToByte(uint8_t Value) +{ + uint8_t tmp = 0; + tmp = ((uint8_t)(Value & (uint8_t)0xF0) >> (uint8_t)0x4) * 10; + return (tmp + (Value & (uint8_t)0x0F)); +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_spi.c b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_spi.c new file mode 100755 index 0000000000..279324dc23 --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_spi.c @@ -0,0 +1,1417 @@ +/** + ****************************************************************************** + * @file stm32f30x_spi.c + * @author MCD Application Team + * @version V1.2.3 + * @date 10-July-2015 + * @brief This file provides firmware functions to manage the following + * functionalities of the Serial peripheral interface (SPI): + * + Initialization and Configuration + * + Data transfers functions + * + Hardware CRC Calculation + * + DMA transfers management + * + Interrupts and flags management + * + * @verbatim + + + =============================================================================== + ##### How to use this driver ##### + =============================================================================== + [..] + (#) Enable peripheral clock using RCC_APBPeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE) + function for SPI1 or using RCC_APBPeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE) + function for SPI2. + (#) Enable SCK, MOSI, MISO and NSS GPIO clocks using RCC_AHBPeriphClockCmd() + function. + (#) Peripherals alternate function: + (++) Connect the pin to the desired peripherals' Alternate + Function (AF) using GPIO_PinAFConfig() function. + (++) Configure the desired pin in alternate function by: + GPIO_InitStruct->GPIO_Mode = GPIO_Mode_AF. + (++) Select the type, pull-up/pull-down and output speed via + GPIO_PuPd, GPIO_OType and GPIO_Speed members. + (++) Call GPIO_Init() function. + (#) Program the Polarity, Phase, First Data, Baud Rate Prescaler, Slave + Management, Peripheral Mode and CRC Polynomial values using the SPI_Init() + function in SPI mode. In I2S mode, program the Mode, Standard, Data Format, + MCLK Output, Audio frequency and Polarity using I2S_Init() function. + (#) Configure the FIFO threshold using SPI_RxFIFOThresholdConfig() to select + at which threshold the RXNE event is generated. + (#) Enable the NVIC and the corresponding interrupt using the function + SPI_I2S_ITConfig() if you need to use interrupt mode. + (#) When using the DMA mode + (++) Configure the DMA using DMA_Init() function. + (++) Active the needed channel Request using SPI_I2S_DMACmd() function. + (#) Enable the SPI using the SPI_Cmd() function or enable the I2S using + I2S_Cmd(). + (#) Enable the DMA using the DMA_Cmd() function when using DMA mode. + (#) Optionally you can enable/configure the following parameters without + re-initialization (i.e there is no need to call again SPI_Init() function): + (++) When bidirectional mode (SPI_Direction_1Line_Rx or SPI_Direction_1Line_Tx) + is programmed as Data direction parameter using the SPI_Init() function + it can be possible to switch between SPI_Direction_Tx or SPI_Direction_Rx + using the SPI_BiDirectionalLineConfig() function. + (++) When SPI_NSS_Soft is selected as Slave Select Management parameter + using the SPI_Init() function it can be possible to manage the + NSS internal signal using the SPI_NSSInternalSoftwareConfig() function. + (++) Reconfigure the data size using the SPI_DataSizeConfig() function. + (++) Enable or disable the SS output using the SPI_SSOutputCmd() function. + (#) To use the CRC Hardware calculation feature refer to the Peripheral + CRC hardware Calculation subsection. + [..] It is possible to use SPI in I2S full duplex mode, in this case, each SPI + peripheral is able to manage sending and receiving data simultaneously + using two data lines. Each SPI peripheral has an extended block called I2Sxext + (ie. I2S2ext for SPI2 and I2S3ext for SPI3). + The extension block is not a full SPI IP, it is used only as I2S slave to + implement full duplex mode. The extension block uses the same clock sources + as its master. + To configure I2S full duplex you have to: + (#) Configure SPIx in I2S mode (I2S_Init() function) as described above. + (#) Call the I2S_FullDuplexConfig() function using the same strucutre passed to + I2S_Init() function. + (#) Call I2S_Cmd() for SPIx then for its extended block. + (#) Configure interrupts or DMA requests and to get/clear flag status, + use I2Sxext instance for the extension block. + [..] Functions that can be called with I2Sxext instances are: + I2S_Cmd(), I2S_FullDuplexConfig(), SPI_I2S_ReceiveData16(), SPI_I2S_SendData16(), + SPI_I2S_DMACmd(), SPI_I2S_ITConfig(), SPI_I2S_GetFlagStatus(), SPI_I2S_ClearFlag(), + SPI_I2S_GetITStatus() and SPI_I2S_ClearITPendingBit(). + [..] Example: To use SPI3 in Full duplex mode (SPI3 is Master Tx, I2S3ext is Slave Rx): + [..] RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI3, ENABLE); + I2S_StructInit(&I2SInitStruct); + I2SInitStruct.Mode = I2S_Mode_MasterTx; + I2S_Init(SPI3, &I2SInitStruct); + I2S_FullDuplexConfig(SPI3ext, &I2SInitStruct) + I2S_Cmd(SPI3, ENABLE); + I2S_Cmd(SPI3ext, ENABLE); + ... + while (SPI_I2S_GetFlagStatus(SPI2, SPI_FLAG_TXE) == RESET) + {} + SPI_I2S_SendData16(SPI3, txdata[i]); + ... + while (SPI_I2S_GetFlagStatus(I2S3ext, SPI_FLAG_RXNE) == RESET) + {} + rxdata[i] = SPI_I2S_ReceiveData16(I2S3ext); + ... + [..] + (@) In SPI mode: To use the SPI TI mode, call the function SPI_TIModeCmd() + just after calling the function SPI_Init(). + + @endverbatim + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f30x_spi.h" +#include "stm32f30x_rcc.h" + +/** @addtogroup STM32F30x_StdPeriph_Driver + * @{ + */ + +/** @defgroup SPI + * @brief SPI driver modules + * @{ + */ + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +/* SPI registers Masks */ +#define CR1_CLEAR_MASK ((uint16_t)0x3040) +#define CR2_LDMA_MASK ((uint16_t)0x9FFF) + +#define I2SCFGR_CLEAR_MASK ((uint16_t)0xF040) + +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/* Private function prototypes -----------------------------------------------*/ +/* Private functions ---------------------------------------------------------*/ + +/** @defgroup SPI_Private_Functions + * @{ + */ + +/** @defgroup SPI_Group1 Initialization and Configuration functions + * @brief Initialization and Configuration functions + * +@verbatim + =============================================================================== + ##### Initialization and Configuration functions ##### + =============================================================================== + [..] This section provides a set of functions allowing to initialize the SPI Direction, + SPI Mode, SPI Data Size, SPI Polarity, SPI Phase, SPI NSS Management, SPI Baud + Rate Prescaler, SPI First Bit and SPI CRC Polynomial. + [..] The SPI_Init() function follows the SPI configuration procedures for Master mode + and Slave mode (details for these procedures are available in reference manual). + [..] When the Software NSS management (SPI_InitStruct->SPI_NSS = SPI_NSS_Soft) is selected, + use the following function to manage the NSS bit: + void SPI_NSSInternalSoftwareConfig(SPI_TypeDef* SPIx, uint16_t SPI_NSSInternalSoft); + [..] In Master mode, when the Hardware NSS management (SPI_InitStruct->SPI_NSS = SPI_NSS_Hard) + is selected, use the following function to enable the NSS output feature. + void SPI_SSOutputCmd(SPI_TypeDef* SPIx, FunctionalState NewState); + [..] The NSS pulse mode can be managed by the SPI TI mode when enabling it using the + following function: void SPI_TIModeCmd(SPI_TypeDef* SPIx, FunctionalState NewState); + And it can be managed by software in the SPI Motorola mode using this function: + void SPI_NSSPulseModeCmd(SPI_TypeDef* SPIx, FunctionalState NewState); + [..] This section provides also functions to initialize the I2S Mode, Standard, + Data Format, MCLK Output, Audio frequency and Polarity. + [..] The I2S_Init() function follows the I2S configuration procedures for Master mode + and Slave mode. + +@endverbatim + * @{ + */ + +/** + * @brief Deinitializes the SPIx peripheral registers to their default + * reset values. + * @param SPIx: To select the SPIx peripheral, where x can be: 1, 2 or 3 + * in SPI mode. + * @retval None + */ +void SPI_I2S_DeInit(SPI_TypeDef* SPIx) +{ + /* Check the parameters */ + assert_param(IS_SPI_ALL_PERIPH(SPIx)); + + if (SPIx == SPI1) + { + /* Enable SPI1 reset state */ + RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI1, ENABLE); + /* Release SPI1 from reset state */ + RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI1, DISABLE); + } + else if (SPIx == SPI2) + { + /* Enable SPI2 reset state */ + RCC_APB1PeriphResetCmd(RCC_APB1Periph_SPI2, ENABLE); + /* Release SPI2 from reset state */ + RCC_APB1PeriphResetCmd(RCC_APB1Periph_SPI2, DISABLE); + } + else if (SPIx == SPI3) + { + /* Enable SPI3 reset state */ + RCC_APB1PeriphResetCmd(RCC_APB1Periph_SPI3, ENABLE); + /* Release SPI3 from reset state */ + RCC_APB1PeriphResetCmd(RCC_APB1Periph_SPI3, DISABLE); + } + else + { + if (SPIx == SPI4) + { + /* Enable SPI4 reset state */ + RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI4, ENABLE); + /* Release SPI4 from reset state */ + RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI4, DISABLE); + } + } +} + +/** + * @brief Fills each SPI_InitStruct member with its default value. + * @param SPI_InitStruct: pointer to a SPI_InitTypeDef structure which will be initialized. + * @retval None + */ +void SPI_StructInit(SPI_InitTypeDef* SPI_InitStruct) +{ +/*--------------- Reset SPI init structure parameters values -----------------*/ + /* Initialize the SPI_Direction member */ + SPI_InitStruct->SPI_Direction = SPI_Direction_2Lines_FullDuplex; + /* Initialize the SPI_Mode member */ + SPI_InitStruct->SPI_Mode = SPI_Mode_Slave; + /* Initialize the SPI_DataSize member */ + SPI_InitStruct->SPI_DataSize = SPI_DataSize_8b; + /* Initialize the SPI_CPOL member */ + SPI_InitStruct->SPI_CPOL = SPI_CPOL_Low; + /* Initialize the SPI_CPHA member */ + SPI_InitStruct->SPI_CPHA = SPI_CPHA_1Edge; + /* Initialize the SPI_NSS member */ + SPI_InitStruct->SPI_NSS = SPI_NSS_Hard; + /* Initialize the SPI_BaudRatePrescaler member */ + SPI_InitStruct->SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2; + /* Initialize the SPI_FirstBit member */ + SPI_InitStruct->SPI_FirstBit = SPI_FirstBit_MSB; + /* Initialize the SPI_CRCPolynomial member */ + SPI_InitStruct->SPI_CRCPolynomial = 7; +} + +/** + * @brief Initializes the SPIx peripheral according to the specified + * parameters in the SPI_InitStruct. + * @param SPIx: where x can be 1, 2, 3 or 4 to select the SPI peripheral. + * @param SPI_InitStruct: pointer to a SPI_InitTypeDef structure that + * contains the configuration information for the specified SPI peripheral. + * @retval None + */ +void SPI_Init(SPI_TypeDef* SPIx, SPI_InitTypeDef* SPI_InitStruct) +{ + uint16_t tmpreg = 0; + + /* check the parameters */ + assert_param(IS_SPI_ALL_PERIPH(SPIx)); + + /* Check the SPI parameters */ + assert_param(IS_SPI_DIRECTION_MODE(SPI_InitStruct->SPI_Direction)); + assert_param(IS_SPI_MODE(SPI_InitStruct->SPI_Mode)); + assert_param(IS_SPI_DATA_SIZE(SPI_InitStruct->SPI_DataSize)); + assert_param(IS_SPI_CPOL(SPI_InitStruct->SPI_CPOL)); + assert_param(IS_SPI_CPHA(SPI_InitStruct->SPI_CPHA)); + assert_param(IS_SPI_NSS(SPI_InitStruct->SPI_NSS)); + assert_param(IS_SPI_BAUDRATE_PRESCALER(SPI_InitStruct->SPI_BaudRatePrescaler)); + assert_param(IS_SPI_FIRST_BIT(SPI_InitStruct->SPI_FirstBit)); + assert_param(IS_SPI_CRC_POLYNOMIAL(SPI_InitStruct->SPI_CRCPolynomial)); + + /* Configuring the SPI in master mode */ + if(SPI_InitStruct->SPI_Mode == SPI_Mode_Master) + { +/*---------------------------- SPIx CR1 Configuration ------------------------*/ + /* Get the SPIx CR1 value */ + tmpreg = SPIx->CR1; + /* Clear BIDIMode, BIDIOE, RxONLY, SSM, SSI, LSBFirst, BR, MSTR, CPOL and CPHA bits */ + tmpreg &= CR1_CLEAR_MASK; + /* Configure SPIx: direction, NSS management, first transmitted bit, BaudRate prescaler + master/slave mode, CPOL and CPHA */ + /* Set BIDImode, BIDIOE and RxONLY bits according to SPI_Direction value */ + /* Set SSM, SSI and MSTR bits according to SPI_Mode and SPI_NSS values */ + /* Set LSBFirst bit according to SPI_FirstBit value */ + /* Set BR bits according to SPI_BaudRatePrescaler value */ + /* Set CPOL bit according to SPI_CPOL value */ + /* Set CPHA bit according to SPI_CPHA value */ + tmpreg |= (uint16_t)((uint16_t)(SPI_InitStruct->SPI_Direction | SPI_InitStruct->SPI_Mode) | + (uint16_t)((uint16_t)(SPI_InitStruct->SPI_CPOL | SPI_InitStruct->SPI_CPHA) | + (uint16_t)((uint16_t)(SPI_InitStruct->SPI_NSS | SPI_InitStruct->SPI_BaudRatePrescaler) | + SPI_InitStruct->SPI_FirstBit))); + /* Write to SPIx CR1 */ + SPIx->CR1 = tmpreg; + /*-------------------------Data Size Configuration -----------------------*/ + /* Get the SPIx CR2 value */ + tmpreg = SPIx->CR2; + /* Clear DS[3:0] bits */ + tmpreg &= (uint16_t)~SPI_CR2_DS; + /* Configure SPIx: Data Size */ + tmpreg |= (uint16_t)(SPI_InitStruct->SPI_DataSize); + /* Write to SPIx CR2 */ + SPIx->CR2 = tmpreg; + } + /* Configuring the SPI in slave mode */ + else + { +/*---------------------------- Data size Configuration -----------------------*/ + /* Get the SPIx CR2 value */ + tmpreg = SPIx->CR2; + /* Clear DS[3:0] bits */ + tmpreg &= (uint16_t)~SPI_CR2_DS; + /* Configure SPIx: Data Size */ + tmpreg |= (uint16_t)(SPI_InitStruct->SPI_DataSize); + /* Write to SPIx CR2 */ + SPIx->CR2 = tmpreg; +/*---------------------------- SPIx CR1 Configuration ------------------------*/ + /* Get the SPIx CR1 value */ + tmpreg = SPIx->CR1; + /* Clear BIDIMode, BIDIOE, RxONLY, SSM, SSI, LSBFirst, BR, MSTR, CPOL and CPHA bits */ + tmpreg &= CR1_CLEAR_MASK; + /* Configure SPIx: direction, NSS management, first transmitted bit, BaudRate prescaler + master/salve mode, CPOL and CPHA */ + /* Set BIDImode, BIDIOE and RxONLY bits according to SPI_Direction value */ + /* Set SSM, SSI and MSTR bits according to SPI_Mode and SPI_NSS values */ + /* Set LSBFirst bit according to SPI_FirstBit value */ + /* Set BR bits according to SPI_BaudRatePrescaler value */ + /* Set CPOL bit according to SPI_CPOL value */ + /* Set CPHA bit according to SPI_CPHA value */ + tmpreg |= (uint16_t)((uint16_t)(SPI_InitStruct->SPI_Direction | SPI_InitStruct->SPI_Mode) | + (uint16_t)((uint16_t)(SPI_InitStruct->SPI_CPOL | SPI_InitStruct->SPI_CPHA) | + (uint16_t)((uint16_t)(SPI_InitStruct->SPI_NSS | SPI_InitStruct->SPI_BaudRatePrescaler) | + SPI_InitStruct->SPI_FirstBit))); + + /* Write to SPIx CR1 */ + SPIx->CR1 = tmpreg; + } + + /* Activate the SPI mode (Reset I2SMOD bit in I2SCFGR register) */ + SPIx->I2SCFGR &= (uint16_t)~((uint16_t)SPI_I2SCFGR_I2SMOD); + +/*---------------------------- SPIx CRCPOLY Configuration --------------------*/ + /* Write to SPIx CRCPOLY */ + SPIx->CRCPR = SPI_InitStruct->SPI_CRCPolynomial; +} + +/** + * @brief Fills each I2S_InitStruct member with its default value. + * @param I2S_InitStruct : pointer to a I2S_InitTypeDef structure which will be initialized. + * @retval None + */ +void I2S_StructInit(I2S_InitTypeDef* I2S_InitStruct) +{ +/*--------------- Reset I2S init structure parameters values -----------------*/ + /* Initialize the I2S_Mode member */ + I2S_InitStruct->I2S_Mode = I2S_Mode_SlaveTx; + + /* Initialize the I2S_Standard member */ + I2S_InitStruct->I2S_Standard = I2S_Standard_Phillips; + + /* Initialize the I2S_DataFormat member */ + I2S_InitStruct->I2S_DataFormat = I2S_DataFormat_16b; + + /* Initialize the I2S_MCLKOutput member */ + I2S_InitStruct->I2S_MCLKOutput = I2S_MCLKOutput_Disable; + + /* Initialize the I2S_AudioFreq member */ + I2S_InitStruct->I2S_AudioFreq = I2S_AudioFreq_Default; + + /* Initialize the I2S_CPOL member */ + I2S_InitStruct->I2S_CPOL = I2S_CPOL_Low; +} + +/** + * @brief Initializes the SPIx peripheral according to the specified + * parameters in the I2S_InitStruct. + * @param SPIx:To select the SPIx peripheral, where x can be: 2 or 3 + * in I2S mode. + * @param I2S_InitStruct: pointer to an I2S_InitTypeDef structure that + * contains the configuration information for the specified SPI peripheral + * configured in I2S mode. + * @note + * The function calculates the optimal prescaler needed to obtain the most + * accurate audio frequency (depending on the I2S clock source, the PLL values + * and the product configuration). But in case the prescaler value is greater + * than 511, the default value (0x02) will be configured instead. + * @retval None + */ +void I2S_Init(SPI_TypeDef* SPIx, I2S_InitTypeDef* I2S_InitStruct) +{ + uint16_t tmpreg = 0, i2sdiv = 2, i2sodd = 0, packetlength = 1; + uint32_t tmp = 0; + RCC_ClocksTypeDef RCC_Clocks; + uint32_t sourceclock = 0; + + /* Check the I2S parameters */ + assert_param(IS_SPI_23_PERIPH(SPIx)); + assert_param(IS_I2S_MODE(I2S_InitStruct->I2S_Mode)); + assert_param(IS_I2S_STANDARD(I2S_InitStruct->I2S_Standard)); + assert_param(IS_I2S_DATA_FORMAT(I2S_InitStruct->I2S_DataFormat)); + assert_param(IS_I2S_MCLK_OUTPUT(I2S_InitStruct->I2S_MCLKOutput)); + assert_param(IS_I2S_AUDIO_FREQ(I2S_InitStruct->I2S_AudioFreq)); + assert_param(IS_I2S_CPOL(I2S_InitStruct->I2S_CPOL)); + +/*----------------------- SPIx I2SCFGR & I2SPR Configuration -----------------*/ + /* Clear I2SMOD, I2SE, I2SCFG, PCMSYNC, I2SSTD, CKPOL, DATLEN and CHLEN bits */ + SPIx->I2SCFGR &= I2SCFGR_CLEAR_MASK; + SPIx->I2SPR = 0x0002; + + /* Get the I2SCFGR register value */ + tmpreg = SPIx->I2SCFGR; + + /* If the default value has to be written, reinitialize i2sdiv and i2sodd*/ + if(I2S_InitStruct->I2S_AudioFreq == I2S_AudioFreq_Default) + { + i2sodd = (uint16_t)0; + i2sdiv = (uint16_t)2; + } + /* If the requested audio frequency is not the default, compute the prescaler */ + else + { + /* Check the frame length (For the Prescaler computing) */ + if(I2S_InitStruct->I2S_DataFormat == I2S_DataFormat_16b) + { + /* Packet length is 16 bits */ + packetlength = 1; + } + else + { + /* Packet length is 32 bits */ + packetlength = 2; + } + + /* I2S Clock source is System clock: Get System Clock frequency */ + RCC_GetClocksFreq(&RCC_Clocks); + + /* Get the source clock value: based on System Clock value */ + sourceclock = RCC_Clocks.SYSCLK_Frequency; + + /* Compute the Real divider depending on the MCLK output state with a floating point */ + if(I2S_InitStruct->I2S_MCLKOutput == I2S_MCLKOutput_Enable) + { + /* MCLK output is enabled */ + tmp = (uint16_t)(((((sourceclock / 256) * 10) / I2S_InitStruct->I2S_AudioFreq)) + 5); + } + else + { + /* MCLK output is disabled */ + tmp = (uint16_t)(((((sourceclock / (32 * packetlength)) *10 ) / I2S_InitStruct->I2S_AudioFreq)) + 5); + } + + /* Remove the floating point */ + tmp = tmp / 10; + + /* Check the parity of the divider */ + i2sodd = (uint16_t)(tmp & (uint16_t)0x0001); + + /* Compute the i2sdiv prescaler */ + i2sdiv = (uint16_t)((tmp - i2sodd) / 2); + + /* Get the Mask for the Odd bit (SPI_I2SPR[8]) register */ + i2sodd = (uint16_t) (i2sodd << 8); + } + + /* Test if the divider is 1 or 0 or greater than 0xFF */ + if ((i2sdiv < 2) || (i2sdiv > 0xFF)) + { + /* Set the default values */ + i2sdiv = 2; + i2sodd = 0; + } + + /* Write to SPIx I2SPR register the computed value */ + SPIx->I2SPR = (uint16_t)(i2sdiv | (uint16_t)(i2sodd | (uint16_t)I2S_InitStruct->I2S_MCLKOutput)); + + /* Configure the I2S with the SPI_InitStruct values */ + tmpreg |= (uint16_t)((uint16_t)(SPI_I2SCFGR_I2SMOD | I2S_InitStruct->I2S_Mode) | \ + (uint16_t)((uint16_t)((uint16_t)(I2S_InitStruct->I2S_Standard |I2S_InitStruct->I2S_DataFormat) |\ + I2S_InitStruct->I2S_CPOL))); + + /* Write to SPIx I2SCFGR */ + SPIx->I2SCFGR = tmpreg; +} + +/** + * @brief Enables or disables the specified SPI peripheral. + * @param SPIx: where x can be 1, 2, 3 or 4 to select the SPI peripheral. + * @param NewState: new state of the SPIx peripheral. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void SPI_Cmd(SPI_TypeDef* SPIx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_SPI_ALL_PERIPH(SPIx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable the selected SPI peripheral */ + SPIx->CR1 |= SPI_CR1_SPE; + } + else + { + /* Disable the selected SPI peripheral */ + SPIx->CR1 &= (uint16_t)~((uint16_t)SPI_CR1_SPE); + } +} + +/** + * @brief Enables or disables the TI Mode. + * @note This function can be called only after the SPI_Init() function has + * been called. + * @note When TI mode is selected, the control bits SSM, SSI, CPOL and CPHA + * are not taken into consideration and are configured by hardware + * respectively to the TI mode requirements. + * @param SPIx: where x can be 1, 2, 3 or 4 to select the SPI peripheral. + * @param NewState: new state of the selected SPI TI communication mode. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void SPI_TIModeCmd(SPI_TypeDef* SPIx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_SPI_ALL_PERIPH(SPIx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable the TI mode for the selected SPI peripheral */ + SPIx->CR2 |= SPI_CR2_FRF; + } + else + { + /* Disable the TI mode for the selected SPI peripheral */ + SPIx->CR2 &= (uint16_t)~((uint16_t)SPI_CR2_FRF); + } +} + +/** + * @brief Enables or disables the specified SPI peripheral (in I2S mode). + * @param SPIx:To select the SPIx peripheral, where x can be: 2 or 3 in + * I2S mode or I2Sxext for I2S full duplex mode. + * @param NewState: new state of the SPIx peripheral. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void I2S_Cmd(SPI_TypeDef* SPIx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_SPI_23_PERIPH_EXT(SPIx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + if (NewState != DISABLE) + { + /* Enable the selected SPI peripheral in I2S mode */ + SPIx->I2SCFGR |= SPI_I2SCFGR_I2SE; + } + else + { + /* Disable the selected SPI peripheral in I2S mode */ + SPIx->I2SCFGR &= (uint16_t)~((uint16_t)SPI_I2SCFGR_I2SE); + } +} + +/** + * @brief Configures the data size for the selected SPI. + * @param SPIx: where x can be 1, 2, 3 or 4 to select the SPI peripheral. + * @param SPI_DataSize: specifies the SPI data size. + * For the SPIx peripheral this parameter can be one of the following values: + * @arg SPI_DataSize_4b: Set data size to 4 bits + * @arg SPI_DataSize_5b: Set data size to 5 bits + * @arg SPI_DataSize_6b: Set data size to 6 bits + * @arg SPI_DataSize_7b: Set data size to 7 bits + * @arg SPI_DataSize_8b: Set data size to 8 bits + * @arg SPI_DataSize_9b: Set data size to 9 bits + * @arg SPI_DataSize_10b: Set data size to 10 bits + * @arg SPI_DataSize_11b: Set data size to 11 bits + * @arg SPI_DataSize_12b: Set data size to 12 bits + * @arg SPI_DataSize_13b: Set data size to 13 bits + * @arg SPI_DataSize_14b: Set data size to 14 bits + * @arg SPI_DataSize_15b: Set data size to 15 bits + * @arg SPI_DataSize_16b: Set data size to 16 bits + * @retval None + */ +void SPI_DataSizeConfig(SPI_TypeDef* SPIx, uint16_t SPI_DataSize) +{ + uint16_t tmpreg = 0; + + /* Check the parameters */ + assert_param(IS_SPI_ALL_PERIPH(SPIx)); + assert_param(IS_SPI_DATA_SIZE(SPI_DataSize)); + /* Read the CR2 register */ + tmpreg = SPIx->CR2; + /* Clear DS[3:0] bits */ + tmpreg &= (uint16_t)~SPI_CR2_DS; + /* Set new DS[3:0] bits value */ + tmpreg |= SPI_DataSize; + SPIx->CR2 = tmpreg; +} + +/** + * @brief Configures the FIFO reception threshold for the selected SPI. + * @param SPIx: where x can be 1, 2, 3 or 4 to select the SPI peripheral. + * @param SPI_RxFIFOThreshold: specifies the FIFO reception threshold. + * This parameter can be one of the following values: + * @arg SPI_RxFIFOThreshold_HF: RXNE event is generated if the FIFO + * level is greater or equal to 1/2. + * @arg SPI_RxFIFOThreshold_QF: RXNE event is generated if the FIFO + * level is greater or equal to 1/4. + * @retval None + */ +void SPI_RxFIFOThresholdConfig(SPI_TypeDef* SPIx, uint16_t SPI_RxFIFOThreshold) +{ + /* Check the parameters */ + assert_param(IS_SPI_ALL_PERIPH(SPIx)); + assert_param(IS_SPI_RX_FIFO_THRESHOLD(SPI_RxFIFOThreshold)); + + /* Clear FRXTH bit */ + SPIx->CR2 &= (uint16_t)~((uint16_t)SPI_CR2_FRXTH); + + /* Set new FRXTH bit value */ + SPIx->CR2 |= SPI_RxFIFOThreshold; +} + +/** + * @brief Selects the data transfer direction in bidirectional mode for the specified SPI. + * @param SPIx: where x can be 1, 2, 3 or 4 to select the SPI peripheral. + * @param SPI_Direction: specifies the data transfer direction in bidirectional mode. + * This parameter can be one of the following values: + * @arg SPI_Direction_Tx: Selects Tx transmission direction + * @arg SPI_Direction_Rx: Selects Rx receive direction + * @retval None + */ +void SPI_BiDirectionalLineConfig(SPI_TypeDef* SPIx, uint16_t SPI_Direction) +{ + /* Check the parameters */ + assert_param(IS_SPI_ALL_PERIPH(SPIx)); + assert_param(IS_SPI_DIRECTION(SPI_Direction)); + if (SPI_Direction == SPI_Direction_Tx) + { + /* Set the Tx only mode */ + SPIx->CR1 |= SPI_Direction_Tx; + } + else + { + /* Set the Rx only mode */ + SPIx->CR1 &= SPI_Direction_Rx; + } +} + +/** + * @brief Configures internally by software the NSS pin for the selected SPI. + * @note This function can be called only after the SPI_Init() function has + * been called. + * @param SPIx: where x can be 1, 2, 3 or 4 to select the SPI peripheral. + * @param SPI_NSSInternalSoft: specifies the SPI NSS internal state. + * This parameter can be one of the following values: + * @arg SPI_NSSInternalSoft_Set: Set NSS pin internally + * @arg SPI_NSSInternalSoft_Reset: Reset NSS pin internally + * @retval None + */ +void SPI_NSSInternalSoftwareConfig(SPI_TypeDef* SPIx, uint16_t SPI_NSSInternalSoft) +{ + /* Check the parameters */ + assert_param(IS_SPI_ALL_PERIPH(SPIx)); + assert_param(IS_SPI_NSS_INTERNAL(SPI_NSSInternalSoft)); + + if (SPI_NSSInternalSoft != SPI_NSSInternalSoft_Reset) + { + /* Set NSS pin internally by software */ + SPIx->CR1 |= SPI_NSSInternalSoft_Set; + } + else + { + /* Reset NSS pin internally by software */ + SPIx->CR1 &= SPI_NSSInternalSoft_Reset; + } +} + +/** + * @brief Configures the full duplex mode for the I2Sx peripheral using its + * extension I2Sxext according to the specified parameters in the + * I2S_InitStruct. + * @param I2Sxext: where x can be 2 or 3 to select the I2S peripheral extension block. + * @param I2S_InitStruct: pointer to an I2S_InitTypeDef structure that + * contains the configuration information for the specified I2S peripheral + * extension. + * + * @note The structure pointed by I2S_InitStruct parameter should be the same + * used for the master I2S peripheral. In this case, if the master is + * configured as transmitter, the slave will be receiver and vice versa. + * Or you can force a different mode by modifying the field I2S_Mode to the + * value I2S_SlaveRx or I2S_SlaveTx independently of the master configuration. + * + * @note The I2S full duplex extension can be configured in slave mode only. + * + * @retval None + */ +void I2S_FullDuplexConfig(SPI_TypeDef* I2Sxext, I2S_InitTypeDef* I2S_InitStruct) +{ + uint16_t tmpreg = 0, tmp = 0; + + /* Check the I2S parameters */ + assert_param(IS_I2S_EXT_PERIPH(I2Sxext)); + assert_param(IS_I2S_MODE(I2S_InitStruct->I2S_Mode)); + assert_param(IS_I2S_STANDARD(I2S_InitStruct->I2S_Standard)); + assert_param(IS_I2S_DATA_FORMAT(I2S_InitStruct->I2S_DataFormat)); + assert_param(IS_I2S_CPOL(I2S_InitStruct->I2S_CPOL)); + +/*----------------------- SPIx I2SCFGR & I2SPR Configuration -----------------*/ + /* Clear I2SMOD, I2SE, I2SCFG, PCMSYNC, I2SSTD, CKPOL, DATLEN and CHLEN bits */ + I2Sxext->I2SCFGR &= I2SCFGR_CLEAR_MASK; + I2Sxext->I2SPR = 0x0002; + + /* Get the I2SCFGR register value */ + tmpreg = I2Sxext->I2SCFGR; + + /* Get the mode to be configured for the extended I2S */ + if ((I2S_InitStruct->I2S_Mode == I2S_Mode_MasterTx) || (I2S_InitStruct->I2S_Mode == I2S_Mode_SlaveTx)) + { + tmp = I2S_Mode_SlaveRx; + } + else + { + if ((I2S_InitStruct->I2S_Mode == I2S_Mode_MasterRx) || (I2S_InitStruct->I2S_Mode == I2S_Mode_SlaveRx)) + { + tmp = I2S_Mode_SlaveTx; + } + } + + + /* Configure the I2S with the SPI_InitStruct values */ + tmpreg |= (uint16_t)((uint16_t)SPI_I2SCFGR_I2SMOD | (uint16_t)(tmp | \ + (uint16_t)(I2S_InitStruct->I2S_Standard | (uint16_t)(I2S_InitStruct->I2S_DataFormat | \ + (uint16_t)I2S_InitStruct->I2S_CPOL)))); + + /* Write to SPIx I2SCFGR */ + I2Sxext->I2SCFGR = tmpreg; +} + +/** + * @brief Enables or disables the SS output for the selected SPI. + * @note This function can be called only after the SPI_Init() function has + * been called and the NSS hardware management mode is selected. + * @param SPIx: where x can be 1, 2, 3 or 4 to select the SPI peripheral. + * @param NewState: new state of the SPIx SS output. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void SPI_SSOutputCmd(SPI_TypeDef* SPIx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_SPI_ALL_PERIPH(SPIx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + if (NewState != DISABLE) + { + /* Enable the selected SPI SS output */ + SPIx->CR2 |= (uint16_t)SPI_CR2_SSOE; + } + else + { + /* Disable the selected SPI SS output */ + SPIx->CR2 &= (uint16_t)~((uint16_t)SPI_CR2_SSOE); + } +} + +/** + * @brief Enables or disables the NSS pulse management mode. + * @note This function can be called only after the SPI_Init() function has + * been called. + * @note When TI mode is selected, the control bits NSSP is not taken into + * consideration and are configured by hardware respectively to the + * TI mode requirements. + * @param SPIx: where x can be 1, 2, 3 or 4 to select the SPI peripheral. + * @param NewState: new state of the NSS pulse management mode. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void SPI_NSSPulseModeCmd(SPI_TypeDef* SPIx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_SPI_ALL_PERIPH(SPIx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable the NSS pulse management mode */ + SPIx->CR2 |= SPI_CR2_NSSP; + } + else + { + /* Disable the NSS pulse management mode */ + SPIx->CR2 &= (uint16_t)~((uint16_t)SPI_CR2_NSSP); + } +} + +/** + * @} + */ + +/** @defgroup SPI_Group2 Data transfers functions + * @brief Data transfers functions + * +@verbatim + =============================================================================== + ##### Data transfers functions ##### + =============================================================================== + [..] This section provides a set of functions allowing to manage the SPI or I2S + data transfers. + [..] In reception, data are received and then stored into an internal Rx buffer while + In transmission, data are first stored into an internal Tx buffer before being + transmitted. + [..] The read access of the SPI_DR register can be done using the SPI_I2S_ReceiveData() + function and returns the Rx buffered value. Whereas a write access to the SPI_DR + can be done using SPI_I2S_SendData() function and stores the written data into + Tx buffer. + +@endverbatim + * @{ + */ + +/** + * @brief Transmits a Data through the SPIx peripheral. + * @param SPIx: where x can be 1, 2, 3 or 4 to select the SPI peripheral. + * @param Data: Data to be transmitted. + * @retval None + */ +void SPI_SendData8(SPI_TypeDef* SPIx, uint8_t Data) +{ + uint32_t spixbase = 0x00; + + /* Check the parameters */ + assert_param(IS_SPI_ALL_PERIPH(SPIx)); + + spixbase = (uint32_t)SPIx; + spixbase += 0x0C; + + *(__IO uint8_t *) spixbase = Data; +} + +/** + * @brief Transmits a Data through the SPIx/I2Sx peripheral. + * @param SPIx: To select the SPIx/I2Sx peripheral, where x can be: 1, 2 or 3 + * in SPI mode or 2 or 3 in I2S mode or I2Sxext for I2S full duplex mode. + * @param Data: Data to be transmitted. + * @retval None + */ +void SPI_I2S_SendData16(SPI_TypeDef* SPIx, uint16_t Data) +{ + /* Check the parameters */ + assert_param(IS_SPI_ALL_PERIPH_EXT(SPIx)); + + SPIx->DR = (uint16_t)Data; +} + +/** + * @brief Returns the most recent received data by the SPIx peripheral. + * @param SPIx: where x can be 1, 2, 3 or 4 to select the SPI peripheral. + * @retval The value of the received data. + */ +uint8_t SPI_ReceiveData8(SPI_TypeDef* SPIx) +{ + uint32_t spixbase = 0x00; + + /* Check the parameters */ + assert_param(IS_SPI_ALL_PERIPH_EXT(SPIx)); + + spixbase = (uint32_t)SPIx; + spixbase += 0x0C; + + return *(__IO uint8_t *) spixbase; +} + +/** + * @brief Returns the most recent received data by the SPIx peripheral. + * @param SPIx: To select the SPIx/I2Sx peripheral, where x can be: 1, 2, 3 or 4 + * in SPI mode or 2 or 3 in I2S mode or I2Sxext for I2S full duplex mode. + * @retval The value of the received data. + */ +uint16_t SPI_I2S_ReceiveData16(SPI_TypeDef* SPIx) +{ + /* Check the parameters */ + assert_param(IS_SPI_ALL_PERIPH_EXT(SPIx)); + + return SPIx->DR; +} +/** + * @} + */ + +/** @defgroup SPI_Group3 Hardware CRC Calculation functions + * @brief Hardware CRC Calculation functions + * +@verbatim + =============================================================================== + ##### Hardware CRC Calculation functions ##### + =============================================================================== + [..] This section provides a set of functions allowing to manage the SPI CRC hardware + calculation. + [..] SPI communication using CRC is possible through the following procedure: + (#) Program the Data direction, Polarity, Phase, First Data, Baud Rate Prescaler, + Slave Management, Peripheral Mode and CRC Polynomial values using the SPI_Init() + function. + (#) Enable the CRC calculation using the SPI_CalculateCRC() function. + (#) Enable the SPI using the SPI_Cmd() function + (#) Before writing the last data to the TX buffer, set the CRCNext bit using the + SPI_TransmitCRC() function to indicate that after transmission of the last + data, the CRC should be transmitted. + (#) After transmitting the last data, the SPI transmits the CRC. The SPI_CR1_CRCNEXT + bit is reset. The CRC is also received and compared against the SPI_RXCRCR + value. + If the value does not match, the SPI_FLAG_CRCERR flag is set and an interrupt + can be generated when the SPI_I2S_IT_ERR interrupt is enabled. + [..] + (@) + (+@) It is advised to don't read the calculate CRC values during the communication. + (+@) When the SPI is in slave mode, be careful to enable CRC calculation only + when the clock is stable, that is, when the clock is in the steady state. + If not, a wrong CRC calculation may be done. In fact, the CRC is sensitive + to the SCK slave input clock as soon as CRCEN is set, and this, whatever + the value of the SPE bit. + (+@) With high bitrate frequencies, be careful when transmitting the CRC. + As the number of used CPU cycles has to be as low as possible in the CRC + transfer phase, it is forbidden to call software functions in the CRC + transmission sequence to avoid errors in the last data and CRC reception. + In fact, CRCNEXT bit has to be written before the end of the transmission/reception + of the last data. + (+@) For high bit rate frequencies, it is advised to use the DMA mode to avoid the + degradation of the SPI speed performance due to CPU accesses impacting the + SPI bandwidth. + (+@) When the STM32F30x are configured as slaves and the NSS hardware mode is + used, the NSS pin needs to be kept low between the data phase and the CRC + phase. + (+@) When the SPI is configured in slave mode with the CRC feature enabled, CRC + calculation takes place even if a high level is applied on the NSS pin. + This may happen for example in case of a multislave environment where the + communication master addresses slaves alternately. + (+@) Between a slave deselection (high level on NSS) and a new slave selection + (low level on NSS), the CRC value should be cleared on both master and slave + sides in order to resynchronize the master and slave for their respective + CRC calculation. + [..] + (@) To clear the CRC, follow the procedure below: + (#@) Disable SPI using the SPI_Cmd() function. + (#@) Disable the CRC calculation using the SPI_CalculateCRC() function. + (#@) Enable the CRC calculation using the SPI_CalculateCRC() function. + (#@) Enable SPI using the SPI_Cmd() function. + +@endverbatim + * @{ + */ + +/** + * @brief Configures the CRC calculation length for the selected SPI. + * @param SPIx: where x can be 1, 2, 3 or 4 to select the SPI peripheral. + * @param SPI_CRCLength: specifies the SPI CRC calculation length. + * This parameter can be one of the following values: + * @arg SPI_CRCLength_8b: Set CRC Calculation to 8 bits + * @arg SPI_CRCLength_16b: Set CRC Calculation to 16 bits + * @retval None + */ +void SPI_CRCLengthConfig(SPI_TypeDef* SPIx, uint16_t SPI_CRCLength) +{ + /* Check the parameters */ + assert_param(IS_SPI_ALL_PERIPH(SPIx)); + assert_param(IS_SPI_CRC_LENGTH(SPI_CRCLength)); + + /* Clear CRCL bit */ + SPIx->CR1 &= (uint16_t)~((uint16_t)SPI_CR1_CRCL); + + /* Set new CRCL bit value */ + SPIx->CR1 |= SPI_CRCLength; +} + +/** + * @brief Enables or disables the CRC value calculation of the transferred bytes. + * @param SPIx: where x can be 1, 2, 3 or 4 to select the SPI peripheral. + * @param NewState: new state of the SPIx CRC value calculation. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void SPI_CalculateCRC(SPI_TypeDef* SPIx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_SPI_ALL_PERIPH(SPIx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable the selected SPI CRC calculation */ + SPIx->CR1 |= SPI_CR1_CRCEN; + } + else + { + /* Disable the selected SPI CRC calculation */ + SPIx->CR1 &= (uint16_t)~((uint16_t)SPI_CR1_CRCEN); + } +} + +/** + * @brief Transmits the SPIx CRC value. + * @param SPIx: where x can be 1, 2, 3 or 4 to select the SPI peripheral. + * @retval None + */ +void SPI_TransmitCRC(SPI_TypeDef* SPIx) +{ + /* Check the parameters */ + assert_param(IS_SPI_ALL_PERIPH(SPIx)); + + /* Enable the selected SPI CRC transmission */ + SPIx->CR1 |= SPI_CR1_CRCNEXT; +} + +/** + * @brief Returns the transmit or the receive CRC register value for the specified SPI. + * @param SPIx: where x can be 1, 2, 3 or 4 to select the SPI peripheral. + * @param SPI_CRC: specifies the CRC register to be read. + * This parameter can be one of the following values: + * @arg SPI_CRC_Tx: Selects Tx CRC register + * @arg SPI_CRC_Rx: Selects Rx CRC register + * @retval The selected CRC register value.. + */ +uint16_t SPI_GetCRC(SPI_TypeDef* SPIx, uint8_t SPI_CRC) +{ + uint16_t crcreg = 0; + /* Check the parameters */ + assert_param(IS_SPI_ALL_PERIPH(SPIx)); + assert_param(IS_SPI_CRC(SPI_CRC)); + + if (SPI_CRC != SPI_CRC_Rx) + { + /* Get the Tx CRC register */ + crcreg = SPIx->TXCRCR; + } + else + { + /* Get the Rx CRC register */ + crcreg = SPIx->RXCRCR; + } + /* Return the selected CRC register */ + return crcreg; +} + +/** + * @brief Returns the CRC Polynomial register value for the specified SPI. + * @param SPIx: where x can be 1, 2, 3 or 4 to select the SPI peripheral. + * @retval The CRC Polynomial register value. + */ +uint16_t SPI_GetCRCPolynomial(SPI_TypeDef* SPIx) +{ + /* Check the parameters */ + assert_param(IS_SPI_ALL_PERIPH(SPIx)); + + /* Return the CRC polynomial register */ + return SPIx->CRCPR; +} + +/** + * @} + */ + +/** @defgroup SPI_Group4 DMA transfers management functions + * @brief DMA transfers management functions + * +@verbatim + =============================================================================== + ##### DMA transfers management functions ##### + =============================================================================== + +@endverbatim + * @{ + */ + +/** + * @brief Enables or disables the SPIx/I2Sx DMA interface. + * @param SPIx:To select the SPIx/I2Sx peripheral, where x can be: 1, 2, 3 or 4 + * in SPI mode or 2 or 3 in I2S mode or I2Sxext for I2S full duplex mode. + * @param SPI_I2S_DMAReq: specifies the SPI DMA transfer request to be enabled or disabled. + * This parameter can be any combination of the following values: + * @arg SPI_I2S_DMAReq_Tx: Tx buffer DMA transfer request + * @arg SPI_I2S_DMAReq_Rx: Rx buffer DMA transfer request + * @param NewState: new state of the selected SPI DMA transfer request. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void SPI_I2S_DMACmd(SPI_TypeDef* SPIx, uint16_t SPI_I2S_DMAReq, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_SPI_ALL_PERIPH_EXT(SPIx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + assert_param(IS_SPI_I2S_DMA_REQ(SPI_I2S_DMAReq)); + + if (NewState != DISABLE) + { + /* Enable the selected SPI DMA requests */ + SPIx->CR2 |= SPI_I2S_DMAReq; + } + else + { + /* Disable the selected SPI DMA requests */ + SPIx->CR2 &= (uint16_t)~SPI_I2S_DMAReq; + } +} + +/** + * @brief Configures the number of data to transfer type(Even/Odd) for the DMA + * last transfers and for the selected SPI. + * @note This function have a meaning only if DMA mode is selected and if + * the packing mode is used (data length <= 8 and DMA transfer size halfword) + * @param SPIx: where x can be 1, 2, 3 or 4 to select the SPI peripheral. + * @param SPI_LastDMATransfer: specifies the SPI last DMA transfers state. + * This parameter can be one of the following values: + * @arg SPI_LastDMATransfer_TxEvenRxEven: Number of data for transmission Even + * and number of data for reception Even. + * @arg SPI_LastDMATransfer_TxOddRxEven: Number of data for transmission Odd + * and number of data for reception Even. + * @arg SPI_LastDMATransfer_TxEvenRxOdd: Number of data for transmission Even + * and number of data for reception Odd. + * @arg SPI_LastDMATransfer_TxOddRxOdd: RNumber of data for transmission Odd + * and number of data for reception Odd. + * @retval None + */ +void SPI_LastDMATransferCmd(SPI_TypeDef* SPIx, uint16_t SPI_LastDMATransfer) +{ + /* Check the parameters */ + assert_param(IS_SPI_ALL_PERIPH(SPIx)); + assert_param(IS_SPI_LAST_DMA_TRANSFER(SPI_LastDMATransfer)); + + /* Clear LDMA_TX and LDMA_RX bits */ + SPIx->CR2 &= CR2_LDMA_MASK; + + /* Set new LDMA_TX and LDMA_RX bits value */ + SPIx->CR2 |= SPI_LastDMATransfer; +} + +/** + * @} + */ + +/** @defgroup SPI_Group5 Interrupts and flags management functions + * @brief Interrupts and flags management functions + * +@verbatim + =============================================================================== + ##### Interrupts and flags management functions ##### + =============================================================================== + [..] This section provides a set of functions allowing to configure the SPI/I2S + Interrupts sources and check or clear the flags or pending bits status. + The user should identify which mode will be used in his application to manage + the communication: Polling mode, Interrupt mode or DMA mode. + + *** Polling Mode *** + ==================== + [..] In Polling Mode, the SPI/I2S communication can be managed by 9 flags: + (#) SPI_I2S_FLAG_TXE : to indicate the status of the transmit buffer register. + (#) SPI_I2S_FLAG_RXNE : to indicate the status of the receive buffer register. + (#) SPI_I2S_FLAG_BSY : to indicate the state of the communication layer of the SPI. + (#) SPI_FLAG_CRCERR : to indicate if a CRC Calculation error occur. + (#) SPI_FLAG_MODF : to indicate if a Mode Fault error occur. + (#) SPI_I2S_FLAG_OVR : to indicate if an Overrun error occur. + (#) SPI_I2S_FLAG_FRE: to indicate a Frame Format error occurs. + (#) I2S_FLAG_UDR: to indicate an Underrun error occurs. + (#) I2S_FLAG_CHSIDE: to indicate Channel Side. + [..] + (@) Do not use the BSY flag to handle each data transmission or reception. + It is better to use the TXE and RXNE flags instead. + [..] In this Mode it is advised to use the following functions: + (+) FlagStatus SPI_I2S_GetFlagStatus(SPI_TypeDef* SPIx, uint16_t SPI_I2S_FLAG); + (+) void SPI_I2S_ClearFlag(SPI_TypeDef* SPIx, uint16_t SPI_I2S_FLAG); + + *** Interrupt Mode *** + ====================== + [..] In Interrupt Mode, the SPI/I2S communication can be managed by 3 interrupt sources + and 5 pending bits: + [..] Pending Bits: + (#) SPI_I2S_IT_TXE : to indicate the status of the transmit buffer register. + (#) SPI_I2S_IT_RXNE : to indicate the status of the receive buffer register. + (#) SPI_I2S_IT_OVR : to indicate if an Overrun error occur. + (#) I2S_IT_UDR : to indicate an Underrun Error occurs. + (#) SPI_I2S_FLAG_FRE : to indicate a Frame Format error occurs. + [..] Interrupt Source: + (#) SPI_I2S_IT_TXE: specifies the interrupt source for the Tx buffer empty + interrupt. + (#) SPI_I2S_IT_RXNE : specifies the interrupt source for the Rx buffer not + empty interrupt. + (#) SPI_I2S_IT_ERR : specifies the interrupt source for the errors interrupt. + [..] In this Mode it is advised to use the following functions: + (+) void SPI_I2S_ITConfig(SPI_TypeDef* SPIx, uint8_t SPI_I2S_IT, FunctionalState NewState); + (+) ITStatus SPI_I2S_GetITStatus(SPI_TypeDef* SPIx, uint8_t SPI_I2S_IT); + + *** FIFO Status *** + =================== + [..] It is possible to monitor the FIFO status when a transfer is ongoing using the + following function: + (+) uint32_t SPI_GetFIFOStatus(uint8_t SPI_FIFO_Direction); + + *** DMA Mode *** + ================ + [..] In DMA Mode, the SPI communication can be managed by 2 DMA Channel requests: + (#) SPI_I2S_DMAReq_Tx: specifies the Tx buffer DMA transfer request. + (#) SPI_I2S_DMAReq_Rx: specifies the Rx buffer DMA transfer request. + [..] In this Mode it is advised to use the following function: + (+) void SPI_I2S_DMACmd(SPI_TypeDef* SPIx, uint16_t SPI_I2S_DMAReq, FunctionalState NewState); + +@endverbatim + * @{ + */ + +/** + * @brief Enables or disables the specified SPI/I2S interrupts. + * @param SPIx: To select the SPIx/I2Sx peripheral, where x can be: 1, 2, 3 or 4 + * in SPI mode or 2 or 3 in I2S mode or I2Sxext for I2S full duplex mode. + * @param SPI_I2S_IT: specifies the SPI interrupt source to be enabled or disabled. + * This parameter can be one of the following values: + * @arg SPI_I2S_IT_TXE: Tx buffer empty interrupt mask + * @arg SPI_I2S_IT_RXNE: Rx buffer not empty interrupt mask + * @arg SPI_I2S_IT_ERR: Error interrupt mask + * @param NewState: new state of the specified SPI interrupt. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void SPI_I2S_ITConfig(SPI_TypeDef* SPIx, uint8_t SPI_I2S_IT, FunctionalState NewState) +{ + uint16_t itpos = 0, itmask = 0 ; + + /* Check the parameters */ + assert_param(IS_SPI_ALL_PERIPH_EXT(SPIx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + assert_param(IS_SPI_I2S_CONFIG_IT(SPI_I2S_IT)); + + /* Get the SPI IT index */ + itpos = SPI_I2S_IT >> 4; + + /* Set the IT mask */ + itmask = (uint16_t)1 << (uint16_t)itpos; + + if (NewState != DISABLE) + { + /* Enable the selected SPI interrupt */ + SPIx->CR2 |= itmask; + } + else + { + /* Disable the selected SPI interrupt */ + SPIx->CR2 &= (uint16_t)~itmask; + } +} + +/** + * @brief Returns the current SPIx Transmission FIFO filled level. + * @param SPIx: where x can be 1, 2, 3 or 4 to select the SPI peripheral. + * @retval The Transmission FIFO filling state. + * - SPI_TransmissionFIFOStatus_Empty: when FIFO is empty + * - SPI_TransmissionFIFOStatus_1QuarterFull: if more than 1 quarter-full. + * - SPI_TransmissionFIFOStatus_HalfFull: if more than 1 half-full. + * - SPI_TransmissionFIFOStatus_Full: when FIFO is full. + */ +uint16_t SPI_GetTransmissionFIFOStatus(SPI_TypeDef* SPIx) +{ + /* Get the SPIx Transmission FIFO level bits */ + return (uint16_t)((SPIx->SR & SPI_SR_FTLVL)); +} + +/** + * @brief Returns the current SPIx Reception FIFO filled level. + * @param SPIx: where x can be 1, 2, 3 or 4 to select the SPI peripheral. + * @retval The Reception FIFO filling state. + * - SPI_ReceptionFIFOStatus_Empty: when FIFO is empty + * - SPI_ReceptionFIFOStatus_1QuarterFull: if more than 1 quarter-full. + * - SPI_ReceptionFIFOStatus_HalfFull: if more than 1 half-full. + * - SPI_ReceptionFIFOStatus_Full: when FIFO is full. + */ +uint16_t SPI_GetReceptionFIFOStatus(SPI_TypeDef* SPIx) +{ + /* Get the SPIx Reception FIFO level bits */ + return (uint16_t)((SPIx->SR & SPI_SR_FRLVL)); +} + +/** + * @brief Checks whether the specified SPI flag is set or not. + * @param SPIx: To select the SPIx/I2Sx peripheral, where x can be: 1, 2, 3 or 4 + * in SPI mode or 2 or 3 in I2S mode or I2Sxext for I2S full duplex mode. + * @param SPI_I2S_FLAG: specifies the SPI flag to check. + * This parameter can be one of the following values: + * @arg SPI_I2S_FLAG_TXE: Transmit buffer empty flag. + * @arg SPI_I2S_FLAG_RXNE: Receive buffer not empty flag. + * @arg SPI_I2S_FLAG_BSY: Busy flag. + * @arg SPI_I2S_FLAG_OVR: Overrun flag. + * @arg SPI_I2S_FLAG_MODF: Mode Fault flag. + * @arg SPI_I2S_FLAG_CRCERR: CRC Error flag. + * @arg SPI_I2S_FLAG_FRE: TI frame format error flag. + * @arg I2S_FLAG_UDR: Underrun Error flag. + * @arg I2S_FLAG_CHSIDE: Channel Side flag. + * @retval The new state of SPI_I2S_FLAG (SET or RESET). + */ +FlagStatus SPI_I2S_GetFlagStatus(SPI_TypeDef* SPIx, uint16_t SPI_I2S_FLAG) +{ + FlagStatus bitstatus = RESET; + /* Check the parameters */ + assert_param(IS_SPI_ALL_PERIPH_EXT(SPIx)); + assert_param(IS_SPI_I2S_GET_FLAG(SPI_I2S_FLAG)); + + /* Check the status of the specified SPI flag */ + if ((SPIx->SR & SPI_I2S_FLAG) != (uint16_t)RESET) + { + /* SPI_I2S_FLAG is set */ + bitstatus = SET; + } + else + { + /* SPI_I2S_FLAG is reset */ + bitstatus = RESET; + } + /* Return the SPI_I2S_FLAG status */ + return bitstatus; +} + +/** + * @brief Clears the SPIx CRC Error (CRCERR) flag. + * @param SPIx: To select the SPIx/I2Sx peripheral, where x can be: 1, 2, 3 or 4 + * in SPI mode or 2 or 3 in I2S mode or I2Sxext for I2S full duplex mode. + * @param SPI_I2S_FLAG: specifies the SPI flag to clear. + * This function clears only CRCERR flag. + * @note OVR (OverRun error) flag is cleared by software sequence: a read + * operation to SPI_DR register (SPI_I2S_ReceiveData()) followed by a read + * operation to SPI_SR register (SPI_I2S_GetFlagStatus()). + * @note MODF (Mode Fault) flag is cleared by software sequence: a read/write + * operation to SPI_SR register (SPI_I2S_GetFlagStatus()) followed by a + * write operation to SPI_CR1 register (SPI_Cmd() to enable the SPI). + * @retval None + */ +void SPI_I2S_ClearFlag(SPI_TypeDef* SPIx, uint16_t SPI_I2S_FLAG) +{ + /* Check the parameters */ + assert_param(IS_SPI_ALL_PERIPH_EXT(SPIx)); + assert_param(IS_SPI_CLEAR_FLAG(SPI_I2S_FLAG)); + + /* Clear the selected SPI CRC Error (CRCERR) flag */ + SPIx->SR = (uint16_t)~SPI_I2S_FLAG; +} + +/** + * @brief Checks whether the specified SPI/I2S interrupt has occurred or not. + * @param SPIx: To select the SPIx/I2Sx peripheral, where x can be: 1, 2, 3 or 4 + * in SPI mode or 2 or 3 in I2S mode or I2Sxext for I2S full duplex mode. + * @param SPI_I2S_IT: specifies the SPI interrupt source to check. + * This parameter can be one of the following values: + * @arg SPI_I2S_IT_TXE: Transmit buffer empty interrupt. + * @arg SPI_I2S_IT_RXNE: Receive buffer not empty interrupt. + * @arg SPI_IT_MODF: Mode Fault interrupt. + * @arg SPI_I2S_IT_OVR: Overrun interrupt. + * @arg I2S_IT_UDR: Underrun interrupt. + * @arg SPI_I2S_IT_FRE: Format Error interrupt. + * @retval The new state of SPI_I2S_IT (SET or RESET). + */ +ITStatus SPI_I2S_GetITStatus(SPI_TypeDef* SPIx, uint8_t SPI_I2S_IT) +{ + ITStatus bitstatus = RESET; + uint16_t itpos = 0, itmask = 0, enablestatus = 0; + + /* Check the parameters */ + assert_param(IS_SPI_ALL_PERIPH_EXT(SPIx)); + assert_param(IS_SPI_I2S_GET_IT(SPI_I2S_IT)); + + /* Get the SPI_I2S_IT index */ + itpos = 0x01 << (SPI_I2S_IT & 0x0F); + + /* Get the SPI_I2S_IT IT mask */ + itmask = SPI_I2S_IT >> 4; + + /* Set the IT mask */ + itmask = 0x01 << itmask; + + /* Get the SPI_I2S_IT enable bit status */ + enablestatus = (SPIx->CR2 & itmask) ; + + /* Check the status of the specified SPI interrupt */ + if (((SPIx->SR & itpos) != (uint16_t)RESET) && enablestatus) + { + /* SPI_I2S_IT is set */ + bitstatus = SET; + } + else + { + /* SPI_I2S_IT is reset */ + bitstatus = RESET; + } + /* Return the SPI_I2S_IT status */ + return bitstatus; +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_syscfg.c b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_syscfg.c new file mode 100755 index 0000000000..e644d16e3d --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_syscfg.c @@ -0,0 +1,569 @@ +/** + ****************************************************************************** + * @file stm32f30x_syscfg.c + * @author MCD Application Team + * @version V1.2.3 + * @date 10-July-2015 + * @brief This file provides firmware functions to manage the following + * functionalities of the SYSCFG peripheral: + * + Remapping the memory mapped at 0x00000000 + * + Remapping the DMA channels + * + Enabling I2C fast mode plus driving capability for I2C plus + * + Remapping USB interrupt line + * + Configuring the EXTI lines connection to the GPIO port + * + Configuring the CLASSB requirements + * + @verbatim + + =============================================================================== + ##### How to use this driver ##### + =============================================================================== + [..] The SYSCFG registers can be accessed only when the SYSCFG + interface APB clock is enabled. + [..] To enable SYSCFG APB clock use: + RCC_APBPeriphClockCmd(RCC_APBPeriph_SYSCFG, ENABLE); + + @endverbatim + + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f30x_syscfg.h" + +/** @addtogroup STM32F30x_StdPeriph_Driver + * @{ + */ + +/** @defgroup SYSCFG + * @brief SYSCFG driver modules + * @{ + */ + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +/* Reset value of SYSCFG_CFGR1 register */ +#define CFGR1_CLEAR_MASK ((uint32_t)0x7C000000) + +/* ------------ SYSCFG registers bit address in the alias region -------------*/ +#define SYSCFG_OFFSET (SYSCFG_BASE - PERIPH_BASE) + +/* --- CFGR1 Register ---*/ +/* Alias word address of USB_IT_RMP bit */ +#define CFGR1_OFFSET (SYSCFG_OFFSET + 0x00) +#define USBITRMP_BitNumber 0x05 +#define CFGR1_USBITRMP_BB (PERIPH_BB_BASE + (CFGR1_OFFSET * 32) + (USBITRMP_BitNumber * 4)) + +/* --- CFGR2 Register ---*/ +/* Alias word address of BYP_ADDR_PAR bit */ +#define CFGR2_OFFSET (SYSCFG_OFFSET + 0x18) +#define BYPADDRPAR_BitNumber 0x04 +#define CFGR1_BYPADDRPAR_BB (PERIPH_BB_BASE + (CFGR2_OFFSET * 32) + (BYPADDRPAR_BitNumber * 4)) + +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/* Private function prototypes -----------------------------------------------*/ +/* Private functions ---------------------------------------------------------*/ + +/** @defgroup SYSCFG_Private_Functions + * @{ + */ + +/** @defgroup SYSCFG_Group1 SYSCFG Initialization and Configuration functions + * @brief SYSCFG Initialization and Configuration functions + * +@verbatim + =============================================================================== + ##### SYSCFG Initialization and Configuration functions ##### + =============================================================================== + +@endverbatim + * @{ + */ + +/** + * @brief Deinitializes the SYSCFG registers to their default reset values. + * @param None + * @retval None + * @note MEM_MODE bits are not affected by APB reset. + * MEM_MODE bits took the value from the user option bytes. + */ +void SYSCFG_DeInit(void) +{ + /* Reset SYSCFG_CFGR1 register to reset value without affecting MEM_MODE bits */ + SYSCFG->CFGR1 &= SYSCFG_CFGR1_MEM_MODE; + /* Set FPU Interrupt Enable bits to default value */ + SYSCFG->CFGR1 |= 0x7C000000; + /* Reset RAM Write protection bits to default value */ + SYSCFG->RCR = 0x00000000; + /* Set EXTICRx registers to reset value */ + SYSCFG->EXTICR[0] = 0; + SYSCFG->EXTICR[1] = 0; + SYSCFG->EXTICR[2] = 0; + SYSCFG->EXTICR[3] = 0; + /* Set CFGR2 register to reset value */ + SYSCFG->CFGR2 = 0; + /* Set CFGR3 register to reset value */ + SYSCFG->CFGR3 = 0; + /* Set CFGR4 register to reset value */ + SYSCFG->CFGR4 = 0; +} + +/** + * @brief Configures the memory mapping at address 0x00000000. + * @param SYSCFG_MemoryRemap: selects the memory remapping. + * This parameter can be one of the following values: + * @arg SYSCFG_MemoryRemap_Flash: Main Flash memory mapped at 0x00000000 + * @arg SYSCFG_MemoryRemap_SystemMemory: System Flash memory mapped at 0x00000000 + * @arg SYSCFG_MemoryRemap_SRAM: Embedded SRAM mapped at 0x00000000 + * @arg SYSCFG_MemoryRemap_FMC: External memory through FMC + * @retval None + */ +void SYSCFG_MemoryRemapConfig(uint32_t SYSCFG_MemoryRemap) +{ + uint32_t tmpcfgr1 = 0; + + /* Check the parameter */ + assert_param(IS_SYSCFG_MEMORY_REMAP(SYSCFG_MemoryRemap)); + + /* Get CFGR1 register value */ + tmpcfgr1 = SYSCFG->CFGR1; + + /* Clear MEM_MODE bits */ + tmpcfgr1 &= (uint32_t) (~SYSCFG_CFGR1_MEM_MODE); + + /* Set the new MEM_MODE bits value */ + tmpcfgr1 |= (uint32_t) SYSCFG_MemoryRemap; + + /* Set CFGR1 register with the new memory remap configuration */ + SYSCFG->CFGR1 = tmpcfgr1; +} + +/** + * @brief Configures the DMA channels remapping. + * @param SYSCFG_DMARemap: selects the DMA channels remap. + * This parameter can be one of the following values: + * @arg SYSCFG_DMARemap_TIM17: Remap TIM17 DMA requests from DMA1 channel1 to channel2 + * @arg SYSCFG_DMARemap_TIM16: Remap TIM16 DMA requests from DMA1 channel3 to channel4 + * @arg SYSCFG_DMARemap_TIM6DAC1Ch1: Remap TIM6/DAC1 DMA requests from DMA2 channel 3 to DMA1 channel 3 + * @arg SYSCFG_DMARemap_TIM7DAC1Ch2: Remap TIM7/DAC2 DMA requests from DMA2 channel 4 to DMA1 channel 4 + * @arg SYSCFG_DMARemap_ADC2ADC4: Remap ADC2 and ADC4 DMA requests from DMA2 channel1/channel3 to channel3/channel4 + * @arg SYSCFG_DMARemap_DAC2Ch1: Remap DAC2 DMA requests to DMA1 channel5 + * @arg SYSCFG_DMARemapCh2_SPI1_RX: Remap SPI1 RX DMA1 CH2 requests + * @arg SYSCFG_DMARemapCh4_SPI1_RX: Remap SPI1 RX DMA CH4 requests + * @arg SYSCFG_DMARemapCh6_SPI1_RX: Remap SPI1 RX DMA CH6 requests + * @arg SYSCFG_DMARemapCh3_SPI1_TX: Remap SPI1 TX DMA CH2 requests + * @arg SYSCFG_DMARemapCh5_SPI1_TX: Remap SPI1 TX DMA CH5 requests + * @arg SYSCFG_DMARemapCh7_SPI1_TX: Remap SPI1 TX DMA CH7 requests + * @arg SYSCFG_DMARemapCh7_I2C1_RX: Remap I2C1 RX DMA CH7 requests + * @arg SYSCFG_DMARemapCh3_I2C1_RX: Remap I2C1 RX DMA CH3 requests + * @arg SYSCFG_DMARemapCh5_I2C1_RX: Remap I2C1 RX DMA CH5 requests + * @arg SYSCFG_DMARemapCh6_I2C1_TX: Remap I2C1 TX DMA CH6 requests + * @arg SYSCFG_DMARemapCh2_I2C1_TX: Remap I2C1 TX DMA CH2 requests + * @arg SYSCFG_DMARemapCh4_I2C1_TX: Remap I2C1 TX DMA CH4 requests + * @arg SYSCFG_DMARemapCh4_ADC2: Remap ADC2 DMA1 Ch4 requests + * @arg SYSCFG_DMARemapCh2_ADC2: Remap ADC2 DMA1 Ch2 requests + * @param NewState: new state of the DMA channel remapping. + * This parameter can be: Enable or Disable. + * @note When enabled, DMA channel of the selected peripheral is remapped + * @note When disabled, Default DMA channel is mapped to the selected peripheral + * @note + * By default TIM17 DMA requests is mapped to channel 1 + * use SYSCFG_DMAChannelRemapConfig(SYSCFG_DMARemap_TIM17, Enable) + * to remap TIM17 DMA requests to DMA1 channel 2 + * use SYSCFG_DMAChannelRemapConfig(SYSCFG_DMARemap_TIM17, Disable) + * to map TIM17 DMA requests to DMA1 channel 1 (default mapping) + * @retval None + */ +void SYSCFG_DMAChannelRemapConfig(uint32_t SYSCFG_DMARemap, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_SYSCFG_DMA_REMAP(SYSCFG_DMARemap)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if ((SYSCFG_DMARemap & 0x80000000)!= 0x80000000) + { + if (NewState != DISABLE) + { + /* Remap the DMA channel */ + SYSCFG->CFGR1 |= (uint32_t)SYSCFG_DMARemap; + } + else + { + /* use the default DMA channel mapping */ + SYSCFG->CFGR1 &= (uint32_t)(~SYSCFG_DMARemap); + } + } + else + { + if (NewState != DISABLE) + { + /* Remap the DMA channel */ + SYSCFG->CFGR3 |= (uint32_t)SYSCFG_DMARemap; + } + else + { + /* use the default DMA channel mapping */ + SYSCFG->CFGR3 &= (uint32_t)(~SYSCFG_DMARemap); + } + } +} + +/** + * @brief Configures the remapping capabilities of DAC/TIM triggers. + * @param SYSCFG_TriggerRemap: selects the trigger to be remapped. + * This parameter can be one of the following values: + * @arg SYSCFG_TriggerRemap_DACTIM3: Remap DAC trigger from TIM8 to TIM3 + * @arg SYSCFG_TriggerRemap_TIM1TIM17: Remap TIM1 ITR3 from TIM4 TRGO to TIM17 OC + * @arg SYSCFG_TriggerRemap_DACHRTIM1_TRIG1: Remap DAC trigger to HRTIM1 TRIG1 + * @arg SYSCFG_TriggerRemap_DACHRTIM1_TRIG2: Remap DAC trigger to HRTIM1 TRIG2 + * @param NewState: new state of the trigger mapping. + * This parameter can be: ENABLE or DISABLE. + * @note ENABLE: Enable fast mode plus driving capability for selected pin + * @note DISABLE: Disable fast mode plus driving capability for selected pin + * @retval None + */ +void SYSCFG_TriggerRemapConfig(uint32_t SYSCFG_TriggerRemap, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_SYSCFG_TRIGGER_REMAP(SYSCFG_TriggerRemap)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if ((SYSCFG_TriggerRemap & 0x80000000)!= 0x80000000) + { + if (NewState != DISABLE) + { + /* Remap the trigger */ + SYSCFG->CFGR1 |= (uint32_t)SYSCFG_TriggerRemap; + } + else + { + /* Use the default trigger mapping */ + SYSCFG->CFGR1 &= (uint32_t)(~SYSCFG_TriggerRemap); + } + } + else + { + if (NewState != DISABLE) + { + /* Remap the trigger */ + SYSCFG->CFGR3 |= (uint32_t)SYSCFG_TriggerRemap; + } + else + { + /* Use the default trigger mapping */ + SYSCFG->CFGR3 &= (uint32_t)(~SYSCFG_TriggerRemap); + } + } +} + +/** + * @brief Configures the remapping capabilities of encoder mode. + * @ note This feature implement the so-called M/T method for measuring speed + * and position using quadrature encoders. + * @param SYSCFG_EncoderRemap: selects the remap option for encoder mode. + * This parameter can be one of the following values: + * @arg SYSCFG_EncoderRemap_No: No remap + * @arg SYSCFG_EncoderRemap_TIM2: Timer 2 IC1 and IC2 connected to TIM15 IC1 and IC2 + * @arg SYSCFG_EncoderRemap_TIM3: Timer 3 IC1 and IC2 connected to TIM15 IC1 and IC2 + * @arg SYSCFG_EncoderRemap_TIM4: Timer 4 IC1 and IC2 connected to TIM15 IC1 and IC2 + * @retval None + */ +void SYSCFG_EncoderRemapConfig(uint32_t SYSCFG_EncoderRemap) +{ + /* Check the parameter */ + assert_param(IS_SYSCFG_ENCODER_REMAP(SYSCFG_EncoderRemap)); + + /* Reset the encoder mode remapping bits */ + SYSCFG->CFGR1 &= (uint32_t)(~SYSCFG_CFGR1_ENCODER_MODE); + + /* Set the selected configuration */ + SYSCFG->CFGR1 |= (uint32_t)(SYSCFG_EncoderRemap); +} + +/** + * @brief Remaps the USB interrupt lines. + * @param NewState: new state of the mapping of USB interrupt lines. + * This parameter can be: + * @param ENABLE: Remap the USB interrupt line as following: + * @arg USB Device High Priority (USB_HP) interrupt mapped to line 74. + * @arg USB Device Low Priority (USB_LP) interrupt mapped to line 75. + * @arg USB Wakeup Interrupt (USB_WKUP) interrupt mapped to line 76. + * @param DISABLE: Use the default USB interrupt line: + * @arg USB Device High Priority (USB_HP) interrupt mapped to line 19. + * @arg USB Device Low Priority (USB_LP) interrupt mapped to line 20. + * @arg USB Wakeup Interrupt (USB_WKUP) interrupt mapped to line 42. + * @retval None + */ +void SYSCFG_USBInterruptLineRemapCmd(FunctionalState NewState) +{ + /* Check the parameter */ + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + /* Remap the USB interrupt lines */ + *(__IO uint32_t *) CFGR1_USBITRMP_BB = (uint32_t)NewState; +} + +/** + * @brief Configures the I2C fast mode plus driving capability. + * @param SYSCFG_I2CFastModePlus: selects the pin. + * This parameter can be one of the following values: + * @arg SYSCFG_I2CFastModePlus_PB6: Configure fast mode plus driving capability for PB6 + * @arg SYSCFG_I2CFastModePlus_PB7: Configure fast mode plus driving capability for PB7 + * @arg SYSCFG_I2CFastModePlus_PB8: Configure fast mode plus driving capability for PB8 + * @arg SYSCFG_I2CFastModePlus_PB9: Configure fast mode plus driving capability for PB9 + * @arg SYSCFG_I2CFastModePlus_I2C1: Configure fast mode plus driving capability for I2C1 pins + * @arg SYSCFG_I2CFastModePlus_I2C2: Configure fast mode plus driving capability for I2C2 pins + * @arg SYSCFG_I2CFastModePlus_I2C3: Configure fast mode plus driving capability for I2C3 pins + * @param NewState: new state of the DMA channel remapping. + * This parameter can be: + * @arg ENABLE: Enable fast mode plus driving capability for selected I2C pin + * @arg DISABLE: Disable fast mode plus driving capability for selected I2C pin + * @note For I2C1, fast mode plus driving capability can be enabled on all selected + * I2C1 pins using SYSCFG_I2CFastModePlus_I2C1 parameter or independently + * on each one of the following pins PB6, PB7, PB8 and PB9. + * @note For remaining I2C1 pins (PA14, PA15...) fast mode plus driving capability + * can be enabled only by using SYSCFG_I2CFastModePlus_I2C1 parameter. + * @note For all I2C2 pins fast mode plus driving capability can be enabled + * only by using SYSCFG_I2CFastModePlus_I2C2 parameter. + * @retval None + */ +void SYSCFG_I2CFastModePlusConfig(uint32_t SYSCFG_I2CFastModePlus, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_SYSCFG_I2C_FMP(SYSCFG_I2CFastModePlus)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable fast mode plus driving capability for selected I2C pin */ + SYSCFG->CFGR1 |= (uint32_t)SYSCFG_I2CFastModePlus; + } + else + { + /* Disable fast mode plus driving capability for selected I2C pin */ + SYSCFG->CFGR1 &= (uint32_t)(~SYSCFG_I2CFastModePlus); + } +} + +/** + * @brief Enables or disables the selected SYSCFG interrupts. + * @param SYSCFG_IT: specifies the SYSCFG interrupt sources to be enabled or disabled. + * This parameter can be one of the following values: + * @arg SYSCFG_IT_IXC: Inexact Interrupt + * @arg SYSCFG_IT_IDC: Input denormal Interrupt + * @arg SYSCFG_IT_OFC: Overflow Interrupt + * @arg SYSCFG_IT_UFC: Underflow Interrupt + * @arg SYSCFG_IT_DZC: Divide-by-zero Interrupt + * @arg SYSCFG_IT_IOC: Invalid operation Interrupt + * @param NewState: new state of the specified SYSCFG interrupts. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void SYSCFG_ITConfig(uint32_t SYSCFG_IT, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_FUNCTIONAL_STATE(NewState)); + assert_param(IS_SYSCFG_IT(SYSCFG_IT)); + + if (NewState != DISABLE) + { + /* Enable the selected SYSCFG interrupts */ + SYSCFG->CFGR1 |= SYSCFG_IT; + } + else + { + /* Disable the selected SYSCFG interrupts */ + SYSCFG->CFGR1 &= ((uint32_t)~SYSCFG_IT); + } +} + +/** + * @brief Selects the GPIO pin used as EXTI Line. + * @param EXTI_PortSourceGPIOx : selects the GPIO port to be used as source + * for EXTI lines where x can be (A, B, C, D, E, F, G, H). + * @param EXTI_PinSourcex: specifies the EXTI line to be configured. + * This parameter can be EXTI_PinSourcex where x can be (0..15) + * @retval None + */ +void SYSCFG_EXTILineConfig(uint8_t EXTI_PortSourceGPIOx, uint8_t EXTI_PinSourcex) +{ + uint32_t tmp = 0x00; + + /* Check the parameters */ + assert_param(IS_EXTI_PORT_SOURCE(EXTI_PortSourceGPIOx)); + assert_param(IS_EXTI_PIN_SOURCE(EXTI_PinSourcex)); + + tmp = ((uint32_t)0x0F) << (0x04 * (EXTI_PinSourcex & (uint8_t)0x03)); + SYSCFG->EXTICR[EXTI_PinSourcex >> 0x02] &= ~tmp; + SYSCFG->EXTICR[EXTI_PinSourcex >> 0x02] |= (((uint32_t)EXTI_PortSourceGPIOx) << (0x04 * (EXTI_PinSourcex & (uint8_t)0x03))); +} + +/** + * @brief Connects the selected parameter to the break input of TIM1. + * @note The selected configuration is locked and can be unlocked by system reset + * @param SYSCFG_Break: selects the configuration to be connected to break + * input of TIM1 + * This parameter can be any combination of the following values: + * @arg SYSCFG_Break_PVD: PVD interrupt is connected to the break input of TIM1. + * @arg SYSCFG_Break_SRAMParity: SRAM Parity error is connected to the break input of TIM1. + * @arg SYSCFG_Break_HardFault: Lockup output of CortexM4 is connected to the break input of TIM1. + * @retval None + */ +void SYSCFG_BreakConfig(uint32_t SYSCFG_Break) +{ + /* Check the parameter */ + assert_param(IS_SYSCFG_LOCK_CONFIG(SYSCFG_Break)); + + SYSCFG->CFGR2 |= (uint32_t) SYSCFG_Break; +} + +/** + * @brief Disables the parity check on RAM. + * @note Disabling the parity check on RAM locks the configuration bit. + * To re-enable the parity check on RAM perform a system reset. + * @param None + * @retval None + */ +void SYSCFG_BypassParityCheckDisable(void) +{ + /* Disable the address parity check on RAM */ + *(__IO uint32_t *) CFGR1_BYPADDRPAR_BB = (uint32_t)0x00000001; +} + +/** + * @brief Configures the remapping capabilities of DAC/TIM triggers. + * @param SYSCFG_ADCTriggerRemap: selects the ADC trigger to be remapped. + * This parameter can be one of the following values: + * @arg REMAPADCTRIGGER_ADC12_EXT2: Input trigger of ADC12 regular channel EXT2 + * @arg REMAPADCTRIGGER_ADC12_EXT3: Input trigger of ADC12 regular channel EXT3 + * @arg REMAPADCTRIGGER_ADC12_EXT5: Input trigger of ADC12 regular channel EXT5 + * @arg REMAPADCTRIGGER_ADC12_EXT13: Input trigger of ADC12 regular channel EXT13 + * @arg REMAPADCTRIGGER_ADC12_EXT15: Input trigger of ADC12 regular channel EXT15 + * @arg REMAPADCTRIGGER_ADC12_JEXT3: Input trigger of ADC12 injected channel JEXT3 + * @arg REMAPADCTRIGGER_ADC12_JEXT6: Input trigger of ADC12 injected channel JEXT6 + * @arg REMAPADCTRIGGER_ADC12_JEXT13: Input trigger of ADC12 injected channel JEXT16 + * @arg REMAPADCTRIGGER_ADC34_EXT5: Input trigger of ADC34 regular channel EXT5 + * @arg REMAPADCTRIGGER_ADC34_EXT6: Input trigger of ADC34 regular channel EXT6 + * @arg REMAPADCTRIGGER_ADC34_EXT15: Input trigger of ADC34 regular channel EXT15 + * @arg REMAPADCTRIGGER_ADC34_JEXT5: Input trigger of ADC34 injected channel JEXT5 + * @arg REMAPADCTRIGGER_ADC34_JEXT11: Input trigger of ADC34 injected channel JEXT11 + * @arg REMAPADCTRIGGER_ADC34_JEXT14: Input trigger of ADC34 injected channel JEXT14 + * @param NewState: new state of the trigger mapping. + * This parameter can be: ENABLE or DISABLE. + * @note ENABLE: Enable fast mode plus driving capability for selected pin + * @note DISABLE: Disable fast mode plus driving capability for selected pin + * @retval None + */ +void SYSCFG_ADCTriggerRemapConfig(uint32_t SYSCFG_ADCTriggerRemap, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_SYSCFG_ADC_TRIGGER_REMAP(SYSCFG_ADCTriggerRemap)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Remap the trigger */ + SYSCFG->CFGR4 |= (uint32_t)SYSCFG_ADCTriggerRemap; + } + else + { + /* Use the default trigger mapping */ + SYSCFG->CFGR4 &= (uint32_t)(~SYSCFG_ADCTriggerRemap); + } +} + +/** + * @brief Enables the ICODE SRAM write protection. + * @note Enabling the ICODE SRAM write protection locks the configuration bit. + * To disable the ICODE SRAM write protection perform a system reset. + * @param None + * @retval None + */ +void SYSCFG_SRAMWRPEnable(uint32_t SYSCFG_SRAMWRP) +{ + /* Check the parameter */ + assert_param(IS_SYSCFG_PAGE(SYSCFG_SRAMWRP)); + + /* Enable the write-protection on the selected ICODE SRAM page */ + SYSCFG->RCR |= (uint32_t)SYSCFG_SRAMWRP; +} + +/** + * @brief Checks whether the specified SYSCFG flag is set or not. + * @param SYSCFG_Flag: specifies the SYSCFG flag to check. + * This parameter can be one of the following values: + * @arg SYSCFG_FLAG_PE: SRAM parity error flag. + * @retval The new state of SYSCFG_Flag (SET or RESET). + */ +FlagStatus SYSCFG_GetFlagStatus(uint32_t SYSCFG_Flag) +{ + FlagStatus bitstatus = RESET; + + /* Check the parameter */ + assert_param(IS_SYSCFG_FLAG(SYSCFG_Flag)); + + /* Check the status of the specified SPI flag */ + if ((SYSCFG->CFGR2 & SYSCFG_CFGR2_SRAM_PE) != (uint32_t)RESET) + { + /* SYSCFG_Flag is set */ + bitstatus = SET; + } + else + { + /* SYSCFG_Flag is reset */ + bitstatus = RESET; + } + /* Return the SYSCFG_Flag status */ + return bitstatus; +} + +/** + * @brief Clears the selected SYSCFG flag. + * @param SYSCFG_Flag: selects the flag to be cleared. + * This parameter can be any combination of the following values: + * @arg SYSCFG_FLAG_PE: SRAM parity error flag. + * @retval None + */ +void SYSCFG_ClearFlag(uint32_t SYSCFG_Flag) +{ + /* Check the parameter */ + assert_param(IS_SYSCFG_FLAG(SYSCFG_Flag)); + + SYSCFG->CFGR2 |= (uint32_t) SYSCFG_Flag; +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + diff --git a/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_tim.c b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_tim.c new file mode 100755 index 0000000000..3c6589df58 --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_tim.c @@ -0,0 +1,4006 @@ +/** + ****************************************************************************** + * @file stm32f30x_tim.c + * @author MCD Application Team + * @version V1.2.3 + * @date 10-July-2015 + * @brief This file provides firmware functions to manage the following + * functionalities of the TIM peripheral: + * + TimeBase management + * + Output Compare management + * + Input Capture management + * + Advanced-control timers (TIM1 and TIM8) specific features + * + Interrupts, DMA and flags management + * + Clocks management + * + Synchronization management + * + Specific interface management + * + Specific remapping management + * + @verbatim + + ============================================================================== + ##### How to use this driver ##### + ============================================================================== + [..] This driver provides functions to configure and program the TIM + of all stm32f30x devices. + These functions are split in 9 groups: + + (#) TIM TimeBase management: this group includes all needed functions + to configure the TM Timebase unit: + (++) Set/Get Prescaler + (++) Set/Get Autoreload + (++) Counter modes configuration + (++) Set Clock division + (++) Select the One Pulse mode + (++) Update Request Configuration + (++) Update Disable Configuration + (++) Auto-Preload Configuration + (++) Enable/Disable the counter + + (#) TIM Output Compare management: this group includes all needed + functions to configure the Capture/Compare unit used in Output + compare mode: + (++) Configure each channel, independently, in Output Compare mode + (++) Select the output compare modes + (++) Select the Polarities of each channel + (++) Set/Get the Capture/Compare register values + (++) Select the Output Compare Fast mode + (++) Select the Output Compare Forced mode + (++) Output Compare-Preload Configuration + (++) Clear Output Compare Reference + (++) Select the OCREF Clear signal + (++) Enable/Disable the Capture/Compare Channels + + (#) TIM Input Capture management: this group includes all needed + functions to configure the Capture/Compare unit used in + Input Capture mode: + (++) Configure each channel in input capture mode + (++) Configure Channel1/2 in PWM Input mode + (++) Set the Input Capture Prescaler + (++) Get the Capture/Compare values + + (#) Advanced-control timers (TIM1 and TIM8) specific features + (++) Configures the Break input, dead time, Lock level, the OSSI, + the OSSR State and the AOE(automatic output enable) + (++) Enable/Disable the TIM peripheral Main Outputs + (++) Select the Commutation event + (++) Set/Reset the Capture Compare Preload Control bit + + (#) TIM interrupts, DMA and flags management + (++) Enable/Disable interrupt sources + (++) Get flags status + (++) Clear flags/ Pending bits + (++) Enable/Disable DMA requests + (++) Configure DMA burst mode + (++) Select CaptureCompare DMA request + + (#) TIM clocks management: this group includes all needed functions + to configure the clock controller unit: + (++) Select internal/External clock + (++) Select the external clock mode: ETR(Mode1/Mode2), TIx or ITRx + + (#) TIM synchronization management: this group includes all needed + functions to configure the Synchronization unit: + (++) Select Input Trigger + (++) Select Output Trigger + (++) Select Master Slave Mode + (++) ETR Configuration when used as external trigger + + (#) TIM specific interface management, this group includes all + needed functions to use the specific TIM interface: + (++) Encoder Interface Configuration + (++) Select Hall Sensor + + (#) TIM specific remapping management includes the Remapping + configuration of specific timers + + @endverbatim + + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f30x_tim.h" +#include "stm32f30x_rcc.h" + +/** @addtogroup STM32F30x_StdPeriph_Driver + * @{ + */ + +/** @defgroup TIM + * @brief TIM driver modules + * @{ + */ + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ + +/* ---------------------- TIM registers bit mask ------------------------ */ +#define SMCR_ETR_MASK ((uint16_t)0x00FF) +#define CCMR_OFFSET ((uint16_t)0x0018) +#define CCER_CCE_SET ((uint16_t)0x0001) +#define CCER_CCNE_SET ((uint16_t)0x0004) +#define CCMR_OC13M_MASK ((uint32_t)0xFFFEFF8F) +#define CCMR_OC24M_MASK ((uint32_t)0xFEFF8FFF) + +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/* Private function prototypes -----------------------------------------------*/ +static void TI1_Config(TIM_TypeDef* TIMx, uint16_t TIM_ICPolarity, uint16_t TIM_ICSelection, + uint16_t TIM_ICFilter); +static void TI2_Config(TIM_TypeDef* TIMx, uint16_t TIM_ICPolarity, uint16_t TIM_ICSelection, + uint16_t TIM_ICFilter); +static void TI3_Config(TIM_TypeDef* TIMx, uint16_t TIM_ICPolarity, uint16_t TIM_ICSelection, + uint16_t TIM_ICFilter); +static void TI4_Config(TIM_TypeDef* TIMx, uint16_t TIM_ICPolarity, uint16_t TIM_ICSelection, + uint16_t TIM_ICFilter); + +/* Private functions ---------------------------------------------------------*/ + +/** @defgroup TIM_Private_Functions + * @{ + */ + +/** @defgroup TIM_Group1 TimeBase management functions + * @brief TimeBase management functions + * +@verbatim + =============================================================================== + ##### TimeBase management functions ##### + =============================================================================== + + + *** TIM Driver: how to use it in Timing(Time base) Mode *** + ============================================================ + [..] + To use the Timer in Timing(Time base) mode, the following steps are mandatory: + + (#) Enable TIM clock using + RCC_APBxPeriphClockCmd(RCC_APBxPeriph_TIMx, ENABLE) function + (#) Fill the TIM_TimeBaseInitStruct with the desired parameters. + (#) Call TIM_TimeBaseInit(TIMx, &TIM_TimeBaseInitStruct) to configure + the Time Base unit + with the corresponding configuration + (#) Enable the NVIC if you need to generate the update interrupt. + (#) Enable the corresponding interrupt using the function + TIM_ITConfig(TIMx, TIM_IT_Update) + (#) Call the TIM_Cmd(ENABLE) function to enable the TIM counter. + [..] + (@) All other functions can be used separately to modify, if needed, + a specific feature of the Timer. + +@endverbatim + * @{ + */ + +/** + * @brief Deinitializes the TIMx peripheral registers to their default reset values. + * @param TIMx: where x can be 1, 2, 3, 4, 6 ,7 ,8, 15, 16,17 or 20 to select the TIM peripheral. + * @retval None + + */ +void TIM_DeInit(TIM_TypeDef* TIMx) +{ + /* Check the parameters */ + assert_param(IS_TIM_ALL_PERIPH(TIMx)); + + if (TIMx == TIM1) + { + RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM1, ENABLE); + RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM1, DISABLE); + } + else if (TIMx == TIM2) + { + RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM2, ENABLE); + RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM2, DISABLE); + } + else if (TIMx == TIM3) + { + RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM3, ENABLE); + RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM3, DISABLE); + } + else if (TIMx == TIM4) + { + RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM4, ENABLE); + RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM4, DISABLE); + } + else if (TIMx == TIM6) + { + RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM6, ENABLE); + RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM6, DISABLE); + } + else if (TIMx == TIM7) + { + RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM7, ENABLE); + RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM7, DISABLE); + } + else if (TIMx == TIM8) + { + RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM8, ENABLE); + RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM8, DISABLE); + } + else if (TIMx == TIM15) + { + RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM15, ENABLE); + RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM15, DISABLE); + } + else if (TIMx == TIM16) + { + RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM16, ENABLE); + RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM16, DISABLE); + } + else if (TIMx == TIM17) + { + RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM17, ENABLE); + RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM17, DISABLE); + } + else + { + if (TIMx == TIM20) + { + RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM20, ENABLE); + RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM20, DISABLE); + } + } +} + +/** + * @brief Initializes the TIMx Time Base Unit peripheral according to + * the specified parameters in the TIM_TimeBaseInitStruct. + * @param TIMx: where x can be 1, 2, 3, 4, 6 ,7 ,8, 15, 16, 17 or 20 to select the TIM peripheral. + * @param TIM_TimeBaseInitStruct: pointer to a TIM_TimeBaseInitTypeDef structure + * that contains the configuration information for the specified TIM peripheral. + * @retval None + */ +void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct) +{ + uint16_t tmpcr1 = 0; + + /* Check the parameters */ + assert_param(IS_TIM_ALL_PERIPH(TIMx)); + assert_param(IS_TIM_COUNTER_MODE(TIM_TimeBaseInitStruct->TIM_CounterMode)); + assert_param(IS_TIM_CKD_DIV(TIM_TimeBaseInitStruct->TIM_ClockDivision)); + + tmpcr1 = TIMx->CR1; + + if((TIMx == TIM1) || (TIMx == TIM8)|| (TIMx == TIM2) || + (TIMx == TIM3) || (TIMx == TIM4) || (TIMx == TIM20)) + { + /* Select the Counter Mode */ + tmpcr1 &= (uint16_t)(~(TIM_CR1_DIR | TIM_CR1_CMS)); + tmpcr1 |= (uint32_t)TIM_TimeBaseInitStruct->TIM_CounterMode; + } + + if((TIMx != TIM6) && (TIMx != TIM7)) + { + /* Set the clock division */ + tmpcr1 &= (uint16_t)(~TIM_CR1_CKD); + tmpcr1 |= (uint32_t)TIM_TimeBaseInitStruct->TIM_ClockDivision; + } + + TIMx->CR1 = tmpcr1; + + /* Set the Autoreload value */ + TIMx->ARR = TIM_TimeBaseInitStruct->TIM_Period ; + + /* Set the Prescaler value */ + TIMx->PSC = TIM_TimeBaseInitStruct->TIM_Prescaler; + + if ((TIMx == TIM1) || (TIMx == TIM8)|| (TIMx == TIM15) || + (TIMx == TIM16) || (TIMx == TIM17)|| (TIMx == TIM20)) + { + /* Set the Repetition Counter value */ + TIMx->RCR = TIM_TimeBaseInitStruct->TIM_RepetitionCounter; + } + + /* Generate an update event to reload the Prescaler + and the repetition counter(only for TIM1 and TIM8) value immediately */ + TIMx->EGR = TIM_PSCReloadMode_Immediate; +} + +/** + * @brief Fills each TIM_TimeBaseInitStruct member with its default value. + * @param TIM_TimeBaseInitStruct : pointer to a TIM_TimeBaseInitTypeDef + * structure which will be initialized. + * @retval None + */ +void TIM_TimeBaseStructInit(TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct) +{ + /* Set the default configuration */ + TIM_TimeBaseInitStruct->TIM_Period = 0xFFFFFFFF; + TIM_TimeBaseInitStruct->TIM_Prescaler = 0x0000; + TIM_TimeBaseInitStruct->TIM_ClockDivision = TIM_CKD_DIV1; + TIM_TimeBaseInitStruct->TIM_CounterMode = TIM_CounterMode_Up; + TIM_TimeBaseInitStruct->TIM_RepetitionCounter = 0x0000; +} + +/** + * @brief Configures the TIMx Prescaler. + * @param TIMx: where x can be 1, 2, 3, 4, 8, 15, 16 or 17 to select the TIM peripheral. + * @param Prescaler: specifies the Prescaler Register value + * @param TIM_PSCReloadMode: specifies the TIM Prescaler Reload mode + * This parameter can be one of the following values: + * @arg TIM_PSCReloadMode_Update: The Prescaler is loaded at the update event. + * @arg TIM_PSCReloadMode_Immediate: The Prescaler is loaded immediately. + * @retval None + */ +void TIM_PrescalerConfig(TIM_TypeDef* TIMx, uint16_t Prescaler, uint16_t TIM_PSCReloadMode) +{ + /* Check the parameters */ + assert_param(IS_TIM_ALL_PERIPH(TIMx)); + assert_param(IS_TIM_PRESCALER_RELOAD(TIM_PSCReloadMode)); + /* Set the Prescaler value */ + TIMx->PSC = Prescaler; + /* Set or reset the UG Bit */ + TIMx->EGR = TIM_PSCReloadMode; +} + +/** + * @brief Specifies the TIMx Counter Mode to be used. + * @param TIMx: where x can be 1, 2, 3, 4, 20 or 8 to select the TIM peripheral. + * @param TIM_CounterMode: specifies the Counter Mode to be used + * This parameter can be one of the following values: + * @arg TIM_CounterMode_Up: TIM Up Counting Mode + * @arg TIM_CounterMode_Down: TIM Down Counting Mode + * @arg TIM_CounterMode_CenterAligned1: TIM Center Aligned Mode1 + * @arg TIM_CounterMode_CenterAligned2: TIM Center Aligned Mode2 + * @arg TIM_CounterMode_CenterAligned3: TIM Center Aligned Mode3 + * @retval None + */ +void TIM_CounterModeConfig(TIM_TypeDef* TIMx, uint16_t TIM_CounterMode) +{ + uint16_t tmpcr1 = 0; + + /* Check the parameters */ + assert_param(IS_TIM_LIST3_PERIPH(TIMx)); + assert_param(IS_TIM_COUNTER_MODE(TIM_CounterMode)); + + tmpcr1 = TIMx->CR1; + + /* Reset the CMS and DIR Bits */ + tmpcr1 &= (uint16_t)~(TIM_CR1_DIR | TIM_CR1_CMS); + + /* Set the Counter Mode */ + tmpcr1 |= TIM_CounterMode; + + /* Write to TIMx CR1 register */ + TIMx->CR1 = tmpcr1; +} + +/** + * @brief Sets the TIMx Counter Register value + * @param TIMx: where x can be 1, 2, 3, 4, 6 ,7 ,8, 15, 16, 17 or 20 to select the TIM peripheral. + * @param Counter: specifies the Counter register new value. + * @retval None + */ +void TIM_SetCounter(TIM_TypeDef* TIMx, uint32_t Counter) +{ + /* Check the parameters */ + assert_param(IS_TIM_ALL_PERIPH(TIMx)); + + /* Set the Counter Register value */ + TIMx->CNT = Counter; +} + +/** + * @brief Sets the TIMx Autoreload Register value + * @param TIMx: where x can be 1, 2, 3, 4, 6 ,7 ,8, 15, 16, 17 or 20 to select the TIM peripheral. + * @param Autoreload: specifies the Autoreload register new value. + * @retval None + */ +void TIM_SetAutoreload(TIM_TypeDef* TIMx, uint32_t Autoreload) +{ + /* Check the parameters */ + assert_param(IS_TIM_ALL_PERIPH(TIMx)); + + /* Set the Autoreload Register value */ + TIMx->ARR = Autoreload; +} + +/** + * @brief Gets the TIMx Counter value. + * @param TIMx: where x can be 1, 2, 3, 4, 6 ,7 ,8, 15, 16, 17 or 20 to select the TIM peripheral. + * @retval Counter Register value + */ +uint32_t TIM_GetCounter(TIM_TypeDef* TIMx) +{ + /* Check the parameters */ + assert_param(IS_TIM_ALL_PERIPH(TIMx)); + + /* Get the Counter Register value */ + return TIMx->CNT; +} + +/** + * @brief Gets the TIMx Prescaler value. + * @param TIMx: where x can be 1, 2, 3, 4, 6 ,7 ,8, 15, 16, 17 or 20 to select the TIM peripheral. + * @retval Prescaler Register value. + */ +uint16_t TIM_GetPrescaler(TIM_TypeDef* TIMx) +{ + /* Check the parameters */ + assert_param(IS_TIM_ALL_PERIPH(TIMx)); + + /* Get the Prescaler Register value */ + return TIMx->PSC; +} + +/** + * @brief Enables or Disables the TIMx Update event. + * @param TIMx: where x can be 1, 2, 3, 4, 6 ,7 ,8, 15, 16, 17 or 20 to select the TIM peripheral. + * @param NewState: new state of the TIMx UDIS bit + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void TIM_UpdateDisableConfig(TIM_TypeDef* TIMx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_TIM_ALL_PERIPH(TIMx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Set the Update Disable Bit */ + TIMx->CR1 |= TIM_CR1_UDIS; + } + else + { + /* Reset the Update Disable Bit */ + TIMx->CR1 &= (uint16_t)~TIM_CR1_UDIS; + } +} + +/** + * @brief Configures the TIMx Update Request Interrupt source. + * @param TIMx: where x can be 1, 2, 3, 4, 6 ,7 ,8, 15, 16, 17 or 20 to select the TIM peripheral. + * @param TIM_UpdateSource: specifies the Update source. + * This parameter can be one of the following values: + * @arg TIM_UpdateSource_Regular: Source of update is the counter + * overflow/underflow or the setting of UG bit, or an update + * generation through the slave mode controller. + * @arg TIM_UpdateSource_Global: Source of update is counter overflow/underflow. + * @retval None + */ +void TIM_UpdateRequestConfig(TIM_TypeDef* TIMx, uint16_t TIM_UpdateSource) +{ + /* Check the parameters */ + assert_param(IS_TIM_ALL_PERIPH(TIMx)); + assert_param(IS_TIM_UPDATE_SOURCE(TIM_UpdateSource)); + + if (TIM_UpdateSource != TIM_UpdateSource_Global) + { + /* Set the URS Bit */ + TIMx->CR1 |= TIM_CR1_URS; + } + else + { + /* Reset the URS Bit */ + TIMx->CR1 &= (uint16_t)~TIM_CR1_URS; + } +} + +/** + * @brief Sets or resets the update interrupt flag (UIF)status bit Remapping. + * when sets, reading TIMx_CNT register returns UIF bit instead of CNT[31] + * @param TIMx: where x can be 1, 2, 3, 4, 6 ,7 ,8, 15, 16, 17 or 20 to select the TIM peripheral. + * @param NewState: new state of the UIFREMAP bit. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void TIM_UIFRemap(TIM_TypeDef* TIMx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_TIM_ALL_PERIPH(TIMx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable the TIM Counter */ + TIMx->CR1 |= TIM_CR1_UIFREMAP; + } + else + { + /* Disable the TIM Counter */ + TIMx->CR1 &= (uint16_t)~TIM_CR1_UIFREMAP; + } +} + +/** + * @brief Enables or disables TIMx peripheral Preload register on ARR. + * @param TIMx: where x can be 1, 2, 3, 4, 6 ,7 ,8, 15, 16, 17 or 20 to select the TIM peripheral. + * @param NewState: new state of the TIMx peripheral Preload register + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_TIM_ALL_PERIPH(TIMx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Set the ARR Preload Bit */ + TIMx->CR1 |= TIM_CR1_ARPE; + } + else + { + /* Reset the ARR Preload Bit */ + TIMx->CR1 &= (uint16_t)~TIM_CR1_ARPE; + } +} + +/** + * @brief Selects the TIMx's One Pulse Mode. + * @param TIMx: where x can be 1, 2, 3, 4, 6 ,7 ,8, 15, 16, 17 or 20 to select the TIM peripheral. + * @param TIM_OPMode: specifies the OPM Mode to be used. + * This parameter can be one of the following values: + * @arg TIM_OPMode_Single + * @arg TIM_OPMode_Repetitive + * @retval None + */ +void TIM_SelectOnePulseMode(TIM_TypeDef* TIMx, uint16_t TIM_OPMode) +{ + /* Check the parameters */ + assert_param(IS_TIM_ALL_PERIPH(TIMx)); + assert_param(IS_TIM_OPM_MODE(TIM_OPMode)); + + /* Reset the OPM Bit */ + TIMx->CR1 &= (uint16_t)~TIM_CR1_OPM; + + /* Configure the OPM Mode */ + TIMx->CR1 |= TIM_OPMode; +} + +/** + * @brief Sets the TIMx Clock Division value. + * @param TIMx: where x can be 1, 2, 3, 4, 8, 15, 16 or 17, to select the TIM peripheral. + * @param TIM_CKD: specifies the clock division value. + * This parameter can be one of the following value: + * @arg TIM_CKD_DIV1: TDTS = Tck_tim + * @arg TIM_CKD_DIV2: TDTS = 2*Tck_tim + * @arg TIM_CKD_DIV4: TDTS = 4*Tck_tim + * @retval None + */ +void TIM_SetClockDivision(TIM_TypeDef* TIMx, uint16_t TIM_CKD) +{ + /* Check the parameters */ + assert_param(IS_TIM_LIST1_PERIPH(TIMx)); + assert_param(IS_TIM_CKD_DIV(TIM_CKD)); + + /* Reset the CKD Bits */ + TIMx->CR1 &= (uint16_t)(~TIM_CR1_CKD); + + /* Set the CKD value */ + TIMx->CR1 |= TIM_CKD; +} + +/** + * @brief Enables or disables the specified TIM peripheral. + * @param TIMx: where x can be 1, 2, 3, 4, 6, 7, 8, 15, 16, 17 and 20 to select + * the TIMx peripheral. + * @param NewState: new state of the TIMx peripheral. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_TIM_ALL_PERIPH(TIMx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable the TIM Counter */ + TIMx->CR1 |= TIM_CR1_CEN; + } + else + { + /* Disable the TIM Counter */ + TIMx->CR1 &= (uint16_t)~TIM_CR1_CEN; + } +} +/** + * @} + */ + +/** @defgroup TIM_Group2 Output Compare management functions + * @brief Output Compare management functions + * +@verbatim + =============================================================================== + ##### Output Compare management functions ##### + =============================================================================== + + *** TIM Driver: how to use it in Output Compare Mode *** + ======================================================== + [..] + To use the Timer in Output Compare mode, the following steps are mandatory: + + (#) Enable TIM clock using RCC_APBxPeriphClockCmd(RCC_APBxPeriph_TIMx, ENABLE) function + + (#) Configure the TIM pins by configuring the corresponding GPIO pins + + (#) Configure the Time base unit as described in the first part of this driver, + if needed, else the Timer will run with the default configuration: + (++) Autoreload value = 0xFFFF + (++) Prescaler value = 0x0000 + (++) Counter mode = Up counting + (++) Clock Division = TIM_CKD_DIV1 + (#) Fill the TIM_OCInitStruct with the desired parameters including: + (++) The TIM Output Compare mode: TIM_OCMode + (++) TIM Output State: TIM_OutputState + (++) TIM Pulse value: TIM_Pulse + (++) TIM Output Compare Polarity : TIM_OCPolarity + + (#) Call TIM_OCxInit(TIMx, &TIM_OCInitStruct) to configure the desired channel with the + corresponding configuration + + (#) Call the TIM_Cmd(ENABLE) function to enable the TIM counter. + [..] + (@) All other functions can be used separately to modify, if needed, + a specific feature of the Timer. + + (@) In case of PWM mode, this function is mandatory: + TIM_OCxPreloadConfig(TIMx, TIM_OCPreload_ENABLE); + + (@) If the corresponding interrupt or DMA request are needed, the user should: + (#@) Enable the NVIC (or the DMA) to use the TIM interrupts (or DMA requests). + (#@) Enable the corresponding interrupt (or DMA request) using the function + TIM_ITConfig(TIMx, TIM_IT_CCx) (or TIM_DMA_Cmd(TIMx, TIM_DMA_CCx)) + +@endverbatim + * @{ + */ + +/** + * @brief Initializes the TIMx Channel1 according to the specified parameters in + * the TIM_OCInitStruct. + * @param TIMx: where x can be 1, 2, 3, 4, 8, 15, 16, 20 or 17, to select the TIM peripheral. + * @param TIM_OCInitStruct: pointer to a TIM_OCInitTypeDef structure that contains + * the configuration information for the specified TIM peripheral. + * @retval None + */ +void TIM_OC1Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct) +{ + uint32_t tmpccmrx = 0, tmpccer = 0, tmpcr2 = 0; + + /* Check the parameters */ + assert_param(IS_TIM_LIST1_PERIPH(TIMx)); + assert_param(IS_TIM_OC_MODE(TIM_OCInitStruct->TIM_OCMode)); + assert_param(IS_TIM_OUTPUT_STATE(TIM_OCInitStruct->TIM_OutputState)); + assert_param(IS_TIM_OC_POLARITY(TIM_OCInitStruct->TIM_OCPolarity)); + + /* Disable the Channel 1: Reset the CC1E Bit */ + TIMx->CCER &= (uint32_t)~TIM_CCER_CC1E; + + /* Get the TIMx CCER register value */ + tmpccer = TIMx->CCER; + /* Get the TIMx CR2 register value */ + tmpcr2 = TIMx->CR2; + + /* Get the TIMx CCMR1 register value */ + tmpccmrx = TIMx->CCMR1; + + /* Reset the Output Compare Mode Bits */ + tmpccmrx &= (uint32_t)~TIM_CCMR1_OC1M; + tmpccmrx &= (uint32_t)~TIM_CCMR1_CC1S; + /* Select the Output Compare Mode */ + tmpccmrx |= TIM_OCInitStruct->TIM_OCMode; + + /* Reset the Output Polarity level */ + tmpccer &= (uint32_t)~TIM_CCER_CC1P; + /* Set the Output Compare Polarity */ + tmpccer |= TIM_OCInitStruct->TIM_OCPolarity; + + /* Set the Output State */ + tmpccer |= TIM_OCInitStruct->TIM_OutputState; + + if((TIMx == TIM1) || (TIMx == TIM8) || (TIMx == TIM15) || (TIMx == TIM16) || (TIMx == TIM17)) + { + assert_param(IS_TIM_OUTPUTN_STATE(TIM_OCInitStruct->TIM_OutputNState)); + assert_param(IS_TIM_OCN_POLARITY(TIM_OCInitStruct->TIM_OCNPolarity)); + assert_param(IS_TIM_OCNIDLE_STATE(TIM_OCInitStruct->TIM_OCNIdleState)); + assert_param(IS_TIM_OCIDLE_STATE(TIM_OCInitStruct->TIM_OCIdleState)); + + /* Reset the Output N Polarity level */ + tmpccer &= (uint32_t)~TIM_CCER_CC1NP; + /* Set the Output N Polarity */ + tmpccer |= TIM_OCInitStruct->TIM_OCNPolarity; + /* Reset the Output N State */ + tmpccer &= (uint32_t)~TIM_CCER_CC1NE; + + /* Set the Output N State */ + tmpccer |= TIM_OCInitStruct->TIM_OutputNState; + /* Reset the Output Compare and Output Compare N IDLE State */ + tmpcr2 &= (uint32_t)~TIM_CR2_OIS1; + tmpcr2 &= (uint32_t)~TIM_CR2_OIS1N; + /* Set the Output Idle state */ + tmpcr2 |= TIM_OCInitStruct->TIM_OCIdleState; + /* Set the Output N Idle state */ + tmpcr2 |= TIM_OCInitStruct->TIM_OCNIdleState; + } + /* Write to TIMx CR2 */ + TIMx->CR2 = tmpcr2; + + /* Write to TIMx CCMR1 */ + TIMx->CCMR1 = tmpccmrx; + + /* Set the Capture Compare Register value */ + TIMx->CCR1 = TIM_OCInitStruct->TIM_Pulse; + + /* Write to TIMx CCER */ + TIMx->CCER = tmpccer; +} + +/** + * @brief Initializes the TIMx Channel2 according to the specified parameters + * in the TIM_OCInitStruct. + * @param TIMx: where x can be 1, 2, 3, 4, 8, 20 or 15 to select the TIM peripheral. + * @param TIM_OCInitStruct: pointer to a TIM_OCInitTypeDef structure that contains + * the configuration information for the specified TIM peripheral. + * @retval None + */ +void TIM_OC2Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct) +{ + uint32_t tmpccmrx = 0, tmpccer = 0, tmpcr2 = 0; + + /* Check the parameters */ + assert_param(IS_TIM_LIST2_PERIPH(TIMx)); + assert_param(IS_TIM_OC_MODE(TIM_OCInitStruct->TIM_OCMode)); + assert_param(IS_TIM_OUTPUT_STATE(TIM_OCInitStruct->TIM_OutputState)); + assert_param(IS_TIM_OC_POLARITY(TIM_OCInitStruct->TIM_OCPolarity)); + + /* Disable the Channel 2: Reset the CC2E Bit */ + TIMx->CCER &= (uint32_t)~TIM_CCER_CC2E; + + /* Get the TIMx CCER register value */ + tmpccer = TIMx->CCER; + /* Get the TIMx CR2 register value */ + tmpcr2 = TIMx->CR2; + + /* Get the TIMx CCMR1 register value */ + tmpccmrx = TIMx->CCMR1; + + /* Reset the Output Compare mode and Capture/Compare selection Bits */ + tmpccmrx &= (uint32_t)~TIM_CCMR1_OC2M; + tmpccmrx &= (uint32_t)~TIM_CCMR1_CC2S; + + /* Select the Output Compare Mode */ + tmpccmrx |= (uint32_t)(TIM_OCInitStruct->TIM_OCMode << 8); + + /* Reset the Output Polarity level */ + tmpccer &= (uint32_t)~TIM_CCER_CC2P; + /* Set the Output Compare Polarity */ + tmpccer |= (uint32_t)((uint32_t)TIM_OCInitStruct->TIM_OCPolarity << 4); + + /* Set the Output State */ + tmpccer |= (uint32_t)((uint32_t)TIM_OCInitStruct->TIM_OutputState << 4); + + if((TIMx == TIM1) || (TIMx == TIM8)) + { + assert_param(IS_TIM_OUTPUTN_STATE(TIM_OCInitStruct->TIM_OutputNState)); + assert_param(IS_TIM_OCN_POLARITY(TIM_OCInitStruct->TIM_OCNPolarity)); + assert_param(IS_TIM_OCNIDLE_STATE(TIM_OCInitStruct->TIM_OCNIdleState)); + assert_param(IS_TIM_OCIDLE_STATE(TIM_OCInitStruct->TIM_OCIdleState)); + + /* Reset the Output N Polarity level */ + tmpccer &= (uint32_t)~TIM_CCER_CC2NP; + /* Set the Output N Polarity */ + tmpccer |= (uint32_t)((uint32_t)TIM_OCInitStruct->TIM_OCNPolarity << 4); + /* Reset the Output N State */ + tmpccer &= (uint32_t)~TIM_CCER_CC2NE; + + /* Set the Output N State */ + tmpccer |= (uint32_t)((uint32_t)TIM_OCInitStruct->TIM_OutputNState << 4); + /* Reset the Output Compare and Output Compare N IDLE State */ + tmpcr2 &= (uint32_t)~TIM_CR2_OIS2; + tmpcr2 &= (uint32_t)~TIM_CR2_OIS2N; + /* Set the Output Idle state */ + tmpcr2 |= (uint32_t)((uint32_t)TIM_OCInitStruct->TIM_OCIdleState << 2); + /* Set the Output N Idle state */ + tmpcr2 |= (uint32_t)((uint32_t)TIM_OCInitStruct->TIM_OCNIdleState << 2); + } + /* Write to TIMx CR2 */ + TIMx->CR2 = tmpcr2; + + /* Write to TIMx CCMR1 */ + TIMx->CCMR1 = tmpccmrx; + + /* Set the Capture Compare Register value */ + TIMx->CCR2 = TIM_OCInitStruct->TIM_Pulse; + + /* Write to TIMx CCER */ + TIMx->CCER = tmpccer; +} + +/** + * @brief Initializes the TIMx Channel3 according to the specified parameters + * in the TIM_OCInitStruct. + * @param TIMx: where x can be 1, 2, 3, 4, 20 or 8 to select the TIM peripheral. + * @param TIM_OCInitStruct: pointer to a TIM_OCInitTypeDef structure that contains + * the configuration information for the specified TIM peripheral. + * @retval None + */ +void TIM_OC3Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct) +{ + uint32_t tmpccmrx = 0, tmpccer = 0, tmpcr2 = 0; + + /* Check the parameters */ + assert_param(IS_TIM_LIST3_PERIPH(TIMx)); + assert_param(IS_TIM_OC_MODE(TIM_OCInitStruct->TIM_OCMode)); + assert_param(IS_TIM_OUTPUT_STATE(TIM_OCInitStruct->TIM_OutputState)); + assert_param(IS_TIM_OC_POLARITY(TIM_OCInitStruct->TIM_OCPolarity)); + + /* Disable the Channel 3: Reset the CC2E Bit */ + TIMx->CCER &= (uint32_t)~TIM_CCER_CC3E; + + /* Get the TIMx CCER register value */ + tmpccer = TIMx->CCER; + /* Get the TIMx CR2 register value */ + tmpcr2 = TIMx->CR2; + + /* Get the TIMx CCMR2 register value */ + tmpccmrx = TIMx->CCMR2; + + /* Reset the Output Compare mode and Capture/Compare selection Bits */ + tmpccmrx &= (uint32_t)~TIM_CCMR2_OC3M; + tmpccmrx &= (uint32_t)~TIM_CCMR2_CC3S; + /* Select the Output Compare Mode */ + tmpccmrx |= TIM_OCInitStruct->TIM_OCMode; + + /* Reset the Output Polarity level */ + tmpccer &= (uint32_t)~TIM_CCER_CC3P; + /* Set the Output Compare Polarity */ + tmpccer |= (uint32_t)((uint32_t)TIM_OCInitStruct->TIM_OCPolarity << 8); + + /* Set the Output State */ + tmpccer |= (uint32_t)((uint32_t)TIM_OCInitStruct->TIM_OutputState << 8); + + if((TIMx == TIM1) || (TIMx == TIM8)) + { + assert_param(IS_TIM_OUTPUTN_STATE(TIM_OCInitStruct->TIM_OutputNState)); + assert_param(IS_TIM_OCN_POLARITY(TIM_OCInitStruct->TIM_OCNPolarity)); + assert_param(IS_TIM_OCNIDLE_STATE(TIM_OCInitStruct->TIM_OCNIdleState)); + assert_param(IS_TIM_OCIDLE_STATE(TIM_OCInitStruct->TIM_OCIdleState)); + + /* Reset the Output N Polarity level */ + tmpccer &= (uint32_t)~TIM_CCER_CC3NP; + /* Set the Output N Polarity */ + tmpccer |= (uint32_t)((uint32_t)TIM_OCInitStruct->TIM_OCNPolarity << 8); + /* Reset the Output N State */ + tmpccer &= (uint32_t)~TIM_CCER_CC3NE; + + /* Set the Output N State */ + tmpccer |= (uint32_t)((uint32_t)TIM_OCInitStruct->TIM_OutputNState << 8); + /* Reset the Output Compare and Output Compare N IDLE State */ + tmpcr2 &= (uint32_t)~TIM_CR2_OIS3; + tmpcr2 &= (uint32_t)~TIM_CR2_OIS3N; + /* Set the Output Idle state */ + tmpcr2 |= (uint32_t)((uint32_t)TIM_OCInitStruct->TIM_OCIdleState << 4); + /* Set the Output N Idle state */ + tmpcr2 |= (uint32_t)((uint32_t)TIM_OCInitStruct->TIM_OCNIdleState << 4); + } + /* Write to TIMx CR2 */ + TIMx->CR2 = tmpcr2; + + /* Write to TIMx CCMR2 */ + TIMx->CCMR2 = tmpccmrx; + + /* Set the Capture Compare Register value */ + TIMx->CCR3 = TIM_OCInitStruct->TIM_Pulse; + + /* Write to TIMx CCER */ + TIMx->CCER = tmpccer; +} + +/** + * @brief Initializes the TIMx Channel4 according to the specified parameters + * in the TIM_OCInitStruct. + * @param TIMx: where x can be 1, 2, 3, 4, 20 or 8 to select the TIM peripheral. + * @param TIM_OCInitStruct: pointer to a TIM_OCInitTypeDef structure that contains + * the configuration information for the specified TIM peripheral. + * @retval None + */ +void TIM_OC4Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct) +{ + uint32_t tmpccmrx = 0, tmpccer = 0, tmpcr2 = 0; + + /* Check the parameters */ + assert_param(IS_TIM_LIST3_PERIPH(TIMx)); + assert_param(IS_TIM_OC_MODE(TIM_OCInitStruct->TIM_OCMode)); + assert_param(IS_TIM_OUTPUT_STATE(TIM_OCInitStruct->TIM_OutputState)); + assert_param(IS_TIM_OC_POLARITY(TIM_OCInitStruct->TIM_OCPolarity)); + + /* Disable the Channel 4: Reset the CC4E Bit */ + TIMx->CCER &= (uint32_t)~TIM_CCER_CC4E; + + /* Get the TIMx CCER register value */ + tmpccer = TIMx->CCER; + /* Get the TIMx CR2 register value */ + tmpcr2 = TIMx->CR2; + + /* Get the TIMx CCMR2 register value */ + tmpccmrx = TIMx->CCMR2; + + /* Reset the Output Compare mode and Capture/Compare selection Bits */ + tmpccmrx &= (uint32_t)~TIM_CCMR2_OC4M; + tmpccmrx &= (uint32_t)~TIM_CCMR2_CC4S; + + /* Select the Output Compare Mode */ + tmpccmrx |= (uint32_t)(TIM_OCInitStruct->TIM_OCMode << 8); + + /* Reset the Output Polarity level */ + tmpccer &= (uint32_t)~TIM_CCER_CC4P; + /* Set the Output Compare Polarity */ + tmpccer |= (uint32_t)((uint32_t)TIM_OCInitStruct->TIM_OCPolarity << 12); + + /* Set the Output State */ + tmpccer |= (uint32_t)((uint32_t)TIM_OCInitStruct->TIM_OutputState << 12); + + if((TIMx == TIM1) || (TIMx == TIM8)) + { + assert_param(IS_TIM_OCIDLE_STATE(TIM_OCInitStruct->TIM_OCIdleState)); + /* Reset the Output Compare IDLE State */ + tmpcr2 &=(uint32_t) ~TIM_CR2_OIS4; + /* Set the Output Idle state */ + tmpcr2 |= (uint32_t)((uint32_t)TIM_OCInitStruct->TIM_OCIdleState << 6); + } + /* Write to TIMx CR2 */ + TIMx->CR2 = tmpcr2; + + /* Write to TIMx CCMR2 */ + TIMx->CCMR2 = tmpccmrx; + + /* Set the Capture Compare Register value */ + TIMx->CCR4 = TIM_OCInitStruct->TIM_Pulse; + + /* Write to TIMx CCER */ + TIMx->CCER = tmpccer; +} + +/** + * @brief Initializes the TIMx Channel5 according to the specified parameters + * in the TIM_OCInitStruct. + * @param TIMx: where x can be 1 or 8 or 20 to select the TIM peripheral. + * @param TIM_OCInitStruct: pointer to a TIM_OCInitTypeDef structure that contains + * the configuration information for the specified TIM peripheral. + * @retval None + */ +void TIM_OC5Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct) +{ + uint32_t tmpccmrx = 0, tmpccer = 0, tmpcr2 = 0; + + /* Check the parameters */ + assert_param(IS_TIM_LIST4_PERIPH(TIMx)); + assert_param(IS_TIM_OC_MODE(TIM_OCInitStruct->TIM_OCMode)); + assert_param(IS_TIM_OUTPUT_STATE(TIM_OCInitStruct->TIM_OutputState)); + assert_param(IS_TIM_OC_POLARITY(TIM_OCInitStruct->TIM_OCPolarity)); + + /* Disable the Channel 5: Reset the CC5E Bit */ + TIMx->CCER &= (uint32_t)~TIM_CCER_CC5E; /* to be verified*/ + + /* Get the TIMx CCER register value */ + tmpccer = TIMx->CCER; + /* Get the TIMx CR2 register value */ + tmpcr2 = TIMx->CR2; + + /* Get the TIMx CCMR3 register value */ + tmpccmrx = TIMx->CCMR3; + + /* Reset the Output Compare mode and Capture/Compare selection Bits */ + tmpccmrx &= (uint32_t)~TIM_CCMR3_OC5M; + + /* Select the Output Compare Mode */ + tmpccmrx |= (uint32_t)(TIM_OCInitStruct->TIM_OCMode); + + /* Reset the Output Polarity level */ + tmpccer &= (uint32_t)~TIM_CCER_CC5P; + /* Set the Output Compare Polarity */ + tmpccer |= (uint32_t)((uint32_t)TIM_OCInitStruct->TIM_OCPolarity << 16); + + /* Set the Output State */ + tmpccer |= (uint32_t)((uint32_t)TIM_OCInitStruct->TIM_OutputState << 16); + + if((TIMx == TIM1) || (TIMx == TIM8)) + { + assert_param(IS_TIM_OCIDLE_STATE(TIM_OCInitStruct->TIM_OCIdleState)); + /* Reset the Output Compare IDLE State */ + tmpcr2 &=(uint32_t) ~TIM_CR2_OIS5; + /* Set the Output Idle state */ + tmpcr2 |= (uint32_t)((uint32_t)TIM_OCInitStruct->TIM_OCIdleState << 16); + } + /* Write to TIMx CR2 */ + TIMx->CR2 = tmpcr2; + + /* Write to TIMx CCMR2 */ + TIMx->CCMR3 = tmpccmrx; + + /* Set the Capture Compare Register value */ + TIMx->CCR5 = TIM_OCInitStruct->TIM_Pulse; + + /* Write to TIMx CCER */ + TIMx->CCER = tmpccer; +} + +/** + * @brief Initializes the TIMx Channel6 according to the specified parameters + * in the TIM_OCInitStruct. + * @param TIMx: where x can be 1 or 8 or 20 to select the TIM peripheral. + * @param TIM_OCInitStruct: pointer to a TIM_OCInitTypeDef structure that contains + * the configuration information for the specified TIM peripheral. + * @retval None + */ +void TIM_OC6Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct) +{ + uint32_t tmpccmrx = 0, tmpccer = 0, tmpcr2 = 0; + + /* Check the parameters */ + assert_param(IS_TIM_LIST4_PERIPH(TIMx)); + assert_param(IS_TIM_OC_MODE(TIM_OCInitStruct->TIM_OCMode)); + assert_param(IS_TIM_OUTPUT_STATE(TIM_OCInitStruct->TIM_OutputState)); + assert_param(IS_TIM_OC_POLARITY(TIM_OCInitStruct->TIM_OCPolarity)); + + /* Disable the Channel 5: Reset the CC5E Bit */ + TIMx->CCER &= (uint32_t)~TIM_CCER_CC6E; /* to be verified*/ + + /* Get the TIMx CCER register value */ + tmpccer = TIMx->CCER; + /* Get the TIMx CR2 register value */ + tmpcr2 = TIMx->CR2; + + /* Get the TIMx CCMR3 register value */ + tmpccmrx = TIMx->CCMR3; + + /* Reset the Output Compare mode and Capture/Compare selection Bits */ + tmpccmrx &= (uint32_t)~TIM_CCMR3_OC6M; + + /* Select the Output Compare Mode */ + tmpccmrx |= (uint32_t)(TIM_OCInitStruct->TIM_OCMode << 8); + + /* Reset the Output Polarity level */ + tmpccer &= (uint32_t)~TIM_CCER_CC6P; + /* Set the Output Compare Polarity */ + tmpccer |= (uint32_t)((uint32_t)TIM_OCInitStruct->TIM_OCPolarity << 20); + + /* Set the Output State */ + tmpccer |= (uint32_t)((uint32_t)TIM_OCInitStruct->TIM_OutputState << 20); + + if((TIMx == TIM1) || (TIMx == TIM8)) + { + assert_param(IS_TIM_OCIDLE_STATE(TIM_OCInitStruct->TIM_OCIdleState)); + /* Reset the Output Compare IDLE State */ + tmpcr2 &=(uint32_t) ~TIM_CR2_OIS6; + /* Set the Output Idle state */ + tmpcr2 |= (uint16_t)(TIM_OCInitStruct->TIM_OCIdleState << 18); + } + /* Write to TIMx CR2 */ + TIMx->CR2 = tmpcr2; + + /* Write to TIMx CCMR2 */ + TIMx->CCMR3 = tmpccmrx; + + /* Set the Capture Compare Register value */ + TIMx->CCR6 = TIM_OCInitStruct->TIM_Pulse; + + /* Write to TIMx CCER */ + TIMx->CCER = tmpccer; +} + +/** + * @brief Selects the TIM Group Channel 5 and Channel 1, + OC1REFC is the logical AND of OC1REFC and OC5REF. + * @param TIMx: where x can be 1 or 8 or 20 to select the TIMx peripheral + * @param NewState: new state of the Commutation event. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void TIM_SelectGC5C1(TIM_TypeDef* TIMx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_TIM_LIST4_PERIPH(TIMx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Set the GC5C1 Bit */ + TIMx->CCR5 |= TIM_CCR5_GC5C1; + } + else + { + /* Reset the GC5C1 Bit */ + TIMx->CCR5 &= (uint32_t)~TIM_CCR5_GC5C1; + } +} + +/** + * @brief Selects the TIM Group Channel 5 and Channel 2, + OC2REFC is the logical AND of OC2REFC and OC5REF. + * @param TIMx: where x can be 1 or 8 or 20 to select the TIMx peripheral + * @param NewState: new state of the Commutation event. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void TIM_SelectGC5C2(TIM_TypeDef* TIMx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_TIM_LIST4_PERIPH(TIMx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Set the GC5C2 Bit */ + TIMx->CCR5 |= TIM_CCR5_GC5C2; + } + else + { + /* Reset the GC5C2 Bit */ + TIMx->CCR5 &= (uint32_t)~TIM_CCR5_GC5C2; + } +} + + +/** + * @brief Selects the TIM Group Channel 5 and Channel 3, + OC3REFC is the logical AND of OC3REFC and OC5REF. + * @param TIMx: where x can be 1 or 8 or 20 to select the TIMx peripheral + * @param NewState: new state of the Commutation event. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void TIM_SelectGC5C3(TIM_TypeDef* TIMx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_TIM_LIST4_PERIPH(TIMx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Set the GC5C3 Bit */ + TIMx->CCR5 |= TIM_CCR5_GC5C3; + } + else + { + /* Reset the GC5C3 Bit */ + TIMx->CCR5 &= (uint32_t)~TIM_CCR5_GC5C3; + } +} + +/** + * @brief Fills each TIM_OCInitStruct member with its default value. + * @param TIM_OCInitStruct: pointer to a TIM_OCInitTypeDef structure which will + * be initialized. + * @retval None + */ +void TIM_OCStructInit(TIM_OCInitTypeDef* TIM_OCInitStruct) +{ + /* Set the default configuration */ + TIM_OCInitStruct->TIM_OCMode = TIM_OCMode_Timing; + TIM_OCInitStruct->TIM_OutputState = TIM_OutputState_Disable; + TIM_OCInitStruct->TIM_OutputNState = TIM_OutputNState_Disable; + TIM_OCInitStruct->TIM_Pulse = 0x00000000; + TIM_OCInitStruct->TIM_OCPolarity = TIM_OCPolarity_High; + TIM_OCInitStruct->TIM_OCNPolarity = TIM_OCPolarity_High; + TIM_OCInitStruct->TIM_OCIdleState = TIM_OCIdleState_Reset; + TIM_OCInitStruct->TIM_OCNIdleState = TIM_OCNIdleState_Reset; +} + +/** + * @brief Selects the TIM Output Compare Mode. + * @note This function disables the selected channel before changing the Output + * Compare Mode. If needed, user has to enable this channel using + * TIM_CCxCmd() and TIM_CCxNCmd() functions. + * @param TIMx: where x can be 1, 2, 3, 4, 8, 15, 16, 20 or 17 to select the TIM peripheral. + * @param TIM_Channel: specifies the TIM Channel + * This parameter can be one of the following values: + * @arg TIM_Channel_1: TIM Channel 1 + * @arg TIM_Channel_2: TIM Channel 2 + * @arg TIM_Channel_3: TIM Channel 3 + * @arg TIM_Channel_4: TIM Channel 4 + * @param TIM_OCMode: specifies the TIM Output Compare Mode. + * This parameter can be one of the following values: + * @arg TIM_OCMode_Timing + * @arg TIM_OCMode_Active + * @arg TIM_OCMode_Toggle + * @arg TIM_OCMode_PWM1 + * @arg TIM_OCMode_PWM2 + * @arg TIM_ForcedAction_Active + * @arg TIM_ForcedAction_InActive + * @arg TIM_OCMode_Retrigerrable_OPM1 + * @arg TIM_OCMode_Retrigerrable_OPM2 + * @arg TIM_OCMode_Combined_PWM1 + * @arg TIM_OCMode_Combined_PWM2 + * @arg TIM_OCMode_Asymmetric_PWM1 + * @arg TIM_OCMode_Asymmetric_PWM2 + * @retval None + */ +void TIM_SelectOCxM(TIM_TypeDef* TIMx, uint16_t TIM_Channel, uint32_t TIM_OCMode) +{ + uint32_t tmp = 0; + uint16_t tmp1 = 0; + + /* Check the parameters */ + assert_param(IS_TIM_LIST1_PERIPH(TIMx)); + assert_param(IS_TIM_CHANNEL(TIM_Channel)); + assert_param(IS_TIM_OCM(TIM_OCMode)); + + tmp = (uint32_t) TIMx; + tmp += CCMR_OFFSET; + + tmp1 = CCER_CCE_SET << (uint16_t)TIM_Channel; + + /* Disable the Channel: Reset the CCxE Bit */ + TIMx->CCER &= (uint16_t) ~tmp1; + + if((TIM_Channel == TIM_Channel_1) ||(TIM_Channel == TIM_Channel_3)) + { + tmp += (TIM_Channel>>1); + + /* Reset the OCxM bits in the CCMRx register */ + *(__IO uint32_t *) tmp &= CCMR_OC13M_MASK; + + /* Configure the OCxM bits in the CCMRx register */ + *(__IO uint32_t *) tmp |= TIM_OCMode; + } + else + { + tmp += (uint32_t)(TIM_Channel - (uint32_t)4)>> (uint32_t)1; + + /* Reset the OCxM bits in the CCMRx register */ + *(__IO uint32_t *) tmp &= CCMR_OC24M_MASK; + + /* Configure the OCxM bits in the CCMRx register */ + *(__IO uint32_t *) tmp |= (uint32_t)(TIM_OCMode << 8); + } +} + +/** + * @brief Sets the TIMx Capture Compare1 Register value + * @param TIMx: where x can be 1, 2, 3, 4, 8, 15, 16, 20 or 17 to select the TIM peripheral. + * @param Compare1: specifies the Capture Compare1 register new value. + * @retval None + */ +void TIM_SetCompare1(TIM_TypeDef* TIMx, uint32_t Compare1) +{ + /* Check the parameters */ + assert_param(IS_TIM_LIST1_PERIPH(TIMx)); + + /* Set the Capture Compare1 Register value */ + TIMx->CCR1 = Compare1; +} + +/** + * @brief Sets the TIMx Capture Compare2 Register value + * @param TIMx: where x can be 1, 2, 3, 4, 8, 20 or 15 to select the TIM + * peripheral. + * @param Compare2: specifies the Capture Compare2 register new value. + * @retval None + */ +void TIM_SetCompare2(TIM_TypeDef* TIMx, uint32_t Compare2) +{ + /* Check the parameters */ + assert_param(IS_TIM_LIST2_PERIPH(TIMx)); + + /* Set the Capture Compare2 Register value */ + TIMx->CCR2 = Compare2; +} + +/** + * @brief Sets the TIMx Capture Compare3 Register value + * @param TIMx: where x can be 1, 2, 3, 4, 5, 20 or 8 to select the TIM peripheral. + * @param Compare3: specifies the Capture Compare3 register new value. + * @retval None + */ +void TIM_SetCompare3(TIM_TypeDef* TIMx, uint32_t Compare3) +{ + /* Check the parameters */ + assert_param(IS_TIM_LIST3_PERIPH(TIMx)); + + /* Set the Capture Compare3 Register value */ + TIMx->CCR3 = Compare3; +} + +/** + * @brief Sets the TIMx Capture Compare4 Register value + * @param TIMx: where x can be 1, 2, 3, 4, 5, 20 or 8 to select the TIM peripheral. + * @param Compare4: specifies the Capture Compare4 register new value. + * @retval None + */ +void TIM_SetCompare4(TIM_TypeDef* TIMx, uint32_t Compare4) +{ + /* Check the parameters */ + assert_param(IS_TIM_LIST3_PERIPH(TIMx)); + + /* Set the Capture Compare4 Register value */ + TIMx->CCR4 = Compare4; +} + +/** + * @brief Sets the TIMx Capture Compare5 Register value + * @param TIMx: where x can be 1 or 8 or 20 to select the TIM peripheral. + * @param Compare5: specifies the Capture Compare5 register new value. + * @retval None + */ +void TIM_SetCompare5(TIM_TypeDef* TIMx, uint32_t Compare5) +{ + /* Check the parameters */ + assert_param(IS_TIM_LIST4_PERIPH(TIMx)); + + /* Set the Capture Compare5 Register value */ + TIMx->CCR5 = Compare5; +} + +/** + * @brief Sets the TIMx Capture Compare6 Register value + * @param TIMx: where x can be 1 or 8 or 20 to select the TIM peripheral. + * @param Compare6: specifies the Capture Compare5 register new value. + * @retval None + */ +void TIM_SetCompare6(TIM_TypeDef* TIMx, uint32_t Compare6) +{ + /* Check the parameters */ + assert_param(IS_TIM_LIST4_PERIPH(TIMx)); + + /* Set the Capture Compare6 Register value */ + TIMx->CCR6 = Compare6; +} + +/** + * @brief Forces the TIMx output 1 waveform to active or inactive level. + * @param TIMx: where x can be 1, 2, 3, 4, 8, 15, 16, 20 or 17 to select the TIM peripheral. + * @param TIM_ForcedAction: specifies the forced Action to be set to the output waveform. + * This parameter can be one of the following values: + * @arg TIM_ForcedAction_Active: Force active level on OC1REF + * @arg TIM_ForcedAction_InActive: Force inactive level on OC1REF. + * @retval None + */ +void TIM_ForcedOC1Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction) +{ + uint32_t tmpccmr1 = 0; + + /* Check the parameters */ + assert_param(IS_TIM_LIST1_PERIPH(TIMx)); + assert_param(IS_TIM_FORCED_ACTION(TIM_ForcedAction)); + tmpccmr1 = TIMx->CCMR1; + + /* Reset the OC1M Bits */ + tmpccmr1 &= (uint32_t)~TIM_CCMR1_OC1M; + + /* Configure The Forced output Mode */ + tmpccmr1 |= TIM_ForcedAction; + + /* Write to TIMx CCMR1 register */ + TIMx->CCMR1 = tmpccmr1; +} + +/** + * @brief Forces the TIMx output 2 waveform to active or inactive level. + * @param TIMx: where x can be 1, 2, 3, 4, 8, 20 or 15 to select the TIM + * peripheral. + * @param TIM_ForcedAction: specifies the forced Action to be set to the output waveform. + * This parameter can be one of the following values: + * @arg TIM_ForcedAction_Active: Force active level on OC2REF + * @arg TIM_ForcedAction_InActive: Force inactive level on OC2REF. + * @retval None + */ +void TIM_ForcedOC2Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction) +{ + uint32_t tmpccmr1 = 0; + + /* Check the parameters */ + assert_param(IS_TIM_LIST2_PERIPH(TIMx)); + assert_param(IS_TIM_FORCED_ACTION(TIM_ForcedAction)); + tmpccmr1 = TIMx->CCMR1; + + /* Reset the OC2M Bits */ + tmpccmr1 &= (uint32_t)~TIM_CCMR1_OC2M; + + /* Configure The Forced output Mode */ + tmpccmr1 |= ((uint32_t)TIM_ForcedAction << 8); + + /* Write to TIMx CCMR1 register */ + TIMx->CCMR1 = tmpccmr1; +} + +/** + * @brief Forces the TIMx output 3 waveform to active or inactive level. + * @param TIMx: where x can be 1, 2, 3, 4, 20 or 8 to select the TIM peripheral. + * @param TIM_ForcedAction: specifies the forced Action to be set to the output waveform. + * This parameter can be one of the following values: + * @arg TIM_ForcedAction_Active: Force active level on OC3REF + * @arg TIM_ForcedAction_InActive: Force inactive level on OC3REF. + * @retval None + */ +void TIM_ForcedOC3Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction) +{ + uint32_t tmpccmr2 = 0; + + /* Check the parameters */ + assert_param(IS_TIM_LIST3_PERIPH(TIMx)); + assert_param(IS_TIM_FORCED_ACTION(TIM_ForcedAction)); + + tmpccmr2 = TIMx->CCMR2; + + /* Reset the OC1M Bits */ + tmpccmr2 &= (uint32_t)~TIM_CCMR2_OC3M; + + /* Configure The Forced output Mode */ + tmpccmr2 |= TIM_ForcedAction; + + /* Write to TIMx CCMR2 register */ + TIMx->CCMR2 = tmpccmr2; +} + +/** + * @brief Forces the TIMx output 4 waveform to active or inactive level. + * @param TIMx: where x can be 1, 2, 3, 4, 20 or 8 to select the TIM peripheral. + * @param TIM_ForcedAction: specifies the forced Action to be set to the output waveform. + * This parameter can be one of the following values: + * @arg TIM_ForcedAction_Active: Force active level on OC4REF + * @arg TIM_ForcedAction_InActive: Force inactive level on OC4REF. + * @retval None + */ +void TIM_ForcedOC4Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction) +{ + uint32_t tmpccmr2 = 0; + + /* Check the parameters */ + assert_param(IS_TIM_LIST3_PERIPH(TIMx)); + assert_param(IS_TIM_FORCED_ACTION(TIM_ForcedAction)); + tmpccmr2 = TIMx->CCMR2; + + /* Reset the OC2M Bits */ + tmpccmr2 &= (uint32_t)~TIM_CCMR2_OC4M; + + /* Configure The Forced output Mode */ + tmpccmr2 |= ((uint32_t)TIM_ForcedAction << 8); + + /* Write to TIMx CCMR2 register */ + TIMx->CCMR2 = tmpccmr2; +} + +/** + * @brief Forces the TIMx output 5 waveform to active or inactive level. + * @param TIMx: where x can be 1 or 8 or 20 to select the TIM peripheral. + * @param TIM_ForcedAction: specifies the forced Action to be set to the output waveform. + * This parameter can be one of the following values: + * @arg TIM_ForcedAction_Active: Force active level on OC5REF + * @arg TIM_ForcedAction_InActive: Force inactive level on OC5REF. + * @retval None + */ +void TIM_ForcedOC5Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction) +{ + uint32_t tmpccmr3 = 0; + + /* Check the parameters */ + assert_param(IS_TIM_LIST4_PERIPH(TIMx)); + assert_param(IS_TIM_FORCED_ACTION(TIM_ForcedAction)); + tmpccmr3 = TIMx->CCMR3; + + /* Reset the OC5M Bits */ + tmpccmr3 &= (uint32_t)~TIM_CCMR3_OC5M; + + /* Configure The Forced output Mode */ + tmpccmr3 |= (uint32_t)(TIM_ForcedAction); + + /* Write to TIMx CCMR3 register */ + TIMx->CCMR3 = tmpccmr3; +} + +/** + * @brief Forces the TIMx output 6 waveform to active or inactive level. + * @param TIMx: where x can be 1 or 8 or 20 to select the TIM peripheral. + * @param TIM_ForcedAction: specifies the forced Action to be set to the output waveform. + * This parameter can be one of the following values: + * @arg TIM_ForcedAction_Active: Force active level on OC5REF + * @arg TIM_ForcedAction_InActive: Force inactive level on OC5REF. + * @retval None + */ +void TIM_ForcedOC6Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction) +{ + uint32_t tmpccmr3 = 0; + + /* Check the parameters */ + assert_param(IS_TIM_LIST4_PERIPH(TIMx)); + assert_param(IS_TIM_FORCED_ACTION(TIM_ForcedAction)); + tmpccmr3 = TIMx->CCMR3; + + /* Reset the OC6M Bits */ + tmpccmr3 &= (uint32_t)~TIM_CCMR3_OC6M; + + /* Configure The Forced output Mode */ + tmpccmr3 |= ((uint32_t)TIM_ForcedAction << 8); + + /* Write to TIMx CCMR3 register */ + TIMx->CCMR3 = tmpccmr3; +} + +/** + * @brief Enables or disables the TIMx peripheral Preload register on CCR1. + * @param TIMx: where x can be 1, 2, 3, 4, 8, 15, 16, 20 or 17 to select the TIM peripheral. + * @param TIM_OCPreload: new state of the TIMx peripheral Preload register + * This parameter can be one of the following values: + * @arg TIM_OCPreload_Enable + * @arg TIM_OCPreload_Disable + * @retval None + */ +void TIM_OC1PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload) +{ + uint32_t tmpccmr1 = 0; + + /* Check the parameters */ + assert_param(IS_TIM_LIST1_PERIPH(TIMx)); + assert_param(IS_TIM_OCPRELOAD_STATE(TIM_OCPreload)); + + tmpccmr1 = TIMx->CCMR1; + + /* Reset the OC1PE Bit */ + tmpccmr1 &= (uint32_t)(~TIM_CCMR1_OC1PE); + + /* Enable or Disable the Output Compare Preload feature */ + tmpccmr1 |= TIM_OCPreload; + + /* Write to TIMx CCMR1 register */ + TIMx->CCMR1 = tmpccmr1; +} + +/** + * @brief Enables or disables the TIMx peripheral Preload register on CCR2. + * @param TIMx: where x can be 1, 2, 3, 4, 8, 20 or 15 to select the TIM + * peripheral. + * @param TIM_OCPreload: new state of the TIMx peripheral Preload register + * This parameter can be one of the following values: + * @arg TIM_OCPreload_Enable + * @arg TIM_OCPreload_Disable + * @retval None + */ +void TIM_OC2PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload) +{ + uint32_t tmpccmr1 = 0; + + /* Check the parameters */ + assert_param(IS_TIM_LIST2_PERIPH(TIMx)); + assert_param(IS_TIM_OCPRELOAD_STATE(TIM_OCPreload)); + + tmpccmr1 = TIMx->CCMR1; + + /* Reset the OC2PE Bit */ + tmpccmr1 &= (uint32_t)(~TIM_CCMR1_OC2PE); + + /* Enable or Disable the Output Compare Preload feature */ + tmpccmr1 |= ((uint32_t)TIM_OCPreload << 8); + + /* Write to TIMx CCMR1 register */ + TIMx->CCMR1 = tmpccmr1; +} + +/** + * @brief Enables or disables the TIMx peripheral Preload register on CCR3. + * @param TIMx: where x can be 1, 2, 3, 4, 20 or 8 to select the TIM peripheral. + * @param TIM_OCPreload: new state of the TIMx peripheral Preload register + * This parameter can be one of the following values: + * @arg TIM_OCPreload_Enable + * @arg TIM_OCPreload_Disable + * @retval None + */ +void TIM_OC3PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload) +{ + uint32_t tmpccmr2 = 0; + + /* Check the parameters */ + assert_param(IS_TIM_LIST3_PERIPH(TIMx)); + assert_param(IS_TIM_OCPRELOAD_STATE(TIM_OCPreload)); + + tmpccmr2 = TIMx->CCMR2; + + /* Reset the OC3PE Bit */ + tmpccmr2 &= (uint32_t)(~TIM_CCMR2_OC3PE); + + /* Enable or Disable the Output Compare Preload feature */ + tmpccmr2 |= TIM_OCPreload; + + /* Write to TIMx CCMR2 register */ + TIMx->CCMR2 = tmpccmr2; +} + +/** + * @brief Enables or disables the TIMx peripheral Preload register on CCR4. + * @param TIMx: where x can be 1, 2, 3, 4, 20 or 8 to select the TIM peripheral. + * @param TIM_OCPreload: new state of the TIMx peripheral Preload register + * This parameter can be one of the following values: + * @arg TIM_OCPreload_Enable + * @arg TIM_OCPreload_Disable + * @retval None + */ +void TIM_OC4PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload) +{ + uint32_t tmpccmr2 = 0; + + /* Check the parameters */ + assert_param(IS_TIM_LIST3_PERIPH(TIMx)); + assert_param(IS_TIM_OCPRELOAD_STATE(TIM_OCPreload)); + + tmpccmr2 = TIMx->CCMR2; + + /* Reset the OC4PE Bit */ + tmpccmr2 &= (uint32_t)(~TIM_CCMR2_OC4PE); + + /* Enable or Disable the Output Compare Preload feature */ + tmpccmr2 |= ((uint32_t)TIM_OCPreload << 8); + + /* Write to TIMx CCMR2 register */ + TIMx->CCMR2 = tmpccmr2; +} + +/** + * @brief Enables or disables the TIMx peripheral Preload register on CCR5. + * @param TIMx: where x can be 1 or 8 or 20 to select the TIM peripheral. + * @param TIM_OCPreload: new state of the TIMx peripheral Preload register + * This parameter can be one of the following values: + * @arg TIM_OCPreload_Enable + * @arg TIM_OCPreload_Disable + * @retval None + */ +void TIM_OC5PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload) +{ + uint32_t tmpccmr3 = 0; + + /* Check the parameters */ + assert_param(IS_TIM_LIST4_PERIPH(TIMx)); + assert_param(IS_TIM_OCPRELOAD_STATE(TIM_OCPreload)); + + tmpccmr3 = TIMx->CCMR3; + + /* Reset the OC5PE Bit */ + tmpccmr3 &= (uint32_t)(~TIM_CCMR3_OC5PE); + + /* Enable or Disable the Output Compare Preload feature */ + tmpccmr3 |= (uint32_t)(TIM_OCPreload); + + /* Write to TIMx CCMR3 register */ + TIMx->CCMR3 = tmpccmr3; +} + +/** + * @brief Enables or disables the TIMx peripheral Preload register on CCR6. + * @param TIMx: where x can be 1 or 8 or 20 to select the TIM peripheral. + * @param TIM_OCPreload: new state of the TIMx peripheral Preload register + * This parameter can be one of the following values: + * @arg TIM_OCPreload_Enable + * @arg TIM_OCPreload_Disable + * @retval None + */ +void TIM_OC6PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload) +{ + uint32_t tmpccmr3 = 0; + + /* Check the parameters */ + assert_param(IS_TIM_LIST4_PERIPH(TIMx)); + assert_param(IS_TIM_OCPRELOAD_STATE(TIM_OCPreload)); + + tmpccmr3 = TIMx->CCMR3; + + /* Reset the OC5PE Bit */ + tmpccmr3 &= (uint32_t)(~TIM_CCMR3_OC6PE); + + /* Enable or Disable the Output Compare Preload feature */ + tmpccmr3 |= ((uint32_t)TIM_OCPreload << 8); + + /* Write to TIMx CCMR3 register */ + TIMx->CCMR3 = tmpccmr3; +} + +/** + * @brief Configures the TIMx Output Compare 1 Fast feature. + * @param TIMx: where x can be 1, 2, 3, 4, 8, 15, 16, 20 or 17 to select the TIM peripheral. + * @param TIM_OCFast: new state of the Output Compare Fast Enable Bit. + * This parameter can be one of the following values: + * @arg TIM_OCFast_Enable: TIM output compare fast enable + * @arg TIM_OCFast_Disable: TIM output compare fast disable + * @retval None + */ +void TIM_OC1FastConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCFast) +{ + uint32_t tmpccmr1 = 0; + + /* Check the parameters */ + assert_param(IS_TIM_LIST1_PERIPH(TIMx)); + assert_param(IS_TIM_OCFAST_STATE(TIM_OCFast)); + + /* Get the TIMx CCMR1 register value */ + tmpccmr1 = TIMx->CCMR1; + + /* Reset the OC1FE Bit */ + tmpccmr1 &= (uint32_t)~TIM_CCMR1_OC1FE; + + /* Enable or Disable the Output Compare Fast Bit */ + tmpccmr1 |= TIM_OCFast; + + /* Write to TIMx CCMR1 */ + TIMx->CCMR1 = tmpccmr1; +} + +/** + * @brief Configures the TIMx Output Compare 2 Fast feature. + * @param TIMx: where x can be 1, 2, 3, 4, 8, 20 or 15 to select the TIM + * peripheral. + * @param TIM_OCFast: new state of the Output Compare Fast Enable Bit. + * This parameter can be one of the following values: + * @arg TIM_OCFast_Enable: TIM output compare fast enable + * @arg TIM_OCFast_Disable: TIM output compare fast disable + * @retval None + */ +void TIM_OC2FastConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCFast) +{ + uint32_t tmpccmr1 = 0; + + /* Check the parameters */ + assert_param(IS_TIM_LIST2_PERIPH(TIMx)); + assert_param(IS_TIM_OCFAST_STATE(TIM_OCFast)); + + /* Get the TIMx CCMR1 register value */ + tmpccmr1 = TIMx->CCMR1; + + /* Reset the OC2FE Bit */ + tmpccmr1 &= (uint32_t)(~TIM_CCMR1_OC2FE); + + /* Enable or Disable the Output Compare Fast Bit */ + tmpccmr1 |= ((uint32_t)TIM_OCFast << 8); + + /* Write to TIMx CCMR1 */ + TIMx->CCMR1 = tmpccmr1; +} + +/** + * @brief Configures the TIMx Output Compare 3 Fast feature. + * @param TIMx: where x can be 1, 2, 3, 4, 20 or 8 to select the TIM peripheral. + * @param TIM_OCFast: new state of the Output Compare Fast Enable Bit. + * This parameter can be one of the following values: + * @arg TIM_OCFast_Enable: TIM output compare fast enable + * @arg TIM_OCFast_Disable: TIM output compare fast disable + * @retval None + */ +void TIM_OC3FastConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCFast) +{ + uint32_t tmpccmr2 = 0; + + /* Check the parameters */ + assert_param(IS_TIM_LIST3_PERIPH(TIMx)); + assert_param(IS_TIM_OCFAST_STATE(TIM_OCFast)); + + /* Get the TIMx CCMR2 register value */ + tmpccmr2 = TIMx->CCMR2; + + /* Reset the OC3FE Bit */ + tmpccmr2 &= (uint32_t)~TIM_CCMR2_OC3FE; + + /* Enable or Disable the Output Compare Fast Bit */ + tmpccmr2 |= TIM_OCFast; + + /* Write to TIMx CCMR2 */ + TIMx->CCMR2 = tmpccmr2; +} + +/** + * @brief Configures the TIMx Output Compare 4 Fast feature. + * @param TIMx: where x can be 1, 2, 3, 4, 20 or 8 to select the TIM peripheral. + * @param TIM_OCFast: new state of the Output Compare Fast Enable Bit. + * This parameter can be one of the following values: + * @arg TIM_OCFast_Enable: TIM output compare fast enable + * @arg TIM_OCFast_Disable: TIM output compare fast disable + * @retval None + */ +void TIM_OC4FastConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCFast) +{ + uint32_t tmpccmr2 = 0; + + /* Check the parameters */ + assert_param(IS_TIM_LIST3_PERIPH(TIMx)); + assert_param(IS_TIM_OCFAST_STATE(TIM_OCFast)); + + /* Get the TIMx CCMR2 register value */ + tmpccmr2 = TIMx->CCMR2; + + /* Reset the OC4FE Bit */ + tmpccmr2 &= (uint32_t)(~TIM_CCMR2_OC4FE); + + /* Enable or Disable the Output Compare Fast Bit */ + tmpccmr2 |= ((uint32_t)TIM_OCFast << 8); + + /* Write to TIMx CCMR2 */ + TIMx->CCMR2 = tmpccmr2; +} + +/** + * @brief Clears or safeguards the OCREF1 signal on an external event + * @param TIMx: where x can be 1, 2, 3, 4, 8, 15, 16, 20 or 17 to select the TIM peripheral. + * @param TIM_OCClear: new state of the Output Compare Clear Enable Bit. + * This parameter can be one of the following values: + * @arg TIM_OCClear_Enable: TIM Output clear enable + * @arg TIM_OCClear_Disable: TIM Output clear disable + * @retval None + */ +void TIM_ClearOC1Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear) +{ + uint32_t tmpccmr1 = 0; + + /* Check the parameters */ + assert_param(IS_TIM_LIST1_PERIPH(TIMx)); + assert_param(IS_TIM_OCCLEAR_STATE(TIM_OCClear)); + + tmpccmr1 = TIMx->CCMR1; + + /* Reset the OC1CE Bit */ + tmpccmr1 &= (uint32_t)~TIM_CCMR1_OC1CE; + + /* Enable or Disable the Output Compare Clear Bit */ + tmpccmr1 |= TIM_OCClear; + + /* Write to TIMx CCMR1 register */ + TIMx->CCMR1 = tmpccmr1; +} + +/** + * @brief Clears or safeguards the OCREF2 signal on an external event + * @param TIMx: where x can be 1, 2, 3, 4, 8, 20 or 15 to select the TIM + * peripheral. + * @param TIM_OCClear: new state of the Output Compare Clear Enable Bit. + * This parameter can be one of the following values: + * @arg TIM_OCClear_Enable: TIM Output clear enable + * @arg TIM_OCClear_Disable: TIM Output clear disable + * @retval None + */ +void TIM_ClearOC2Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear) +{ + uint32_t tmpccmr1 = 0; + + /* Check the parameters */ + assert_param(IS_TIM_LIST2_PERIPH(TIMx)); + assert_param(IS_TIM_OCCLEAR_STATE(TIM_OCClear)); + + tmpccmr1 = TIMx->CCMR1; + + /* Reset the OC2CE Bit */ + tmpccmr1 &= (uint32_t)~TIM_CCMR1_OC2CE; + + /* Enable or Disable the Output Compare Clear Bit */ + tmpccmr1 |= ((uint32_t)TIM_OCClear << 8); + + /* Write to TIMx CCMR1 register */ + TIMx->CCMR1 = tmpccmr1; +} + +/** + * @brief Clears or safeguards the OCREF3 signal on an external event + * @param TIMx: where x can be 1, 2, 3, 4, 20 or 8 to select the TIM peripheral. + * @param TIM_OCClear: new state of the Output Compare Clear Enable Bit. + * This parameter can be one of the following values: + * @arg TIM_OCClear_Enable: TIM Output clear enable + * @arg TIM_OCClear_Disable: TIM Output clear disable + * @retval None + */ +void TIM_ClearOC3Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear) +{ + uint32_t tmpccmr2 = 0; + + /* Check the parameters */ + assert_param(IS_TIM_LIST3_PERIPH(TIMx)); + assert_param(IS_TIM_OCCLEAR_STATE(TIM_OCClear)); + + tmpccmr2 = TIMx->CCMR2; + + /* Reset the OC3CE Bit */ + tmpccmr2 &= (uint32_t)~TIM_CCMR2_OC3CE; + + /* Enable or Disable the Output Compare Clear Bit */ + tmpccmr2 |= TIM_OCClear; + + /* Write to TIMx CCMR2 register */ + TIMx->CCMR2 = tmpccmr2; +} + +/** + * @brief Clears or safeguards the OCREF4 signal on an external event + * @param TIMx: where x can be 1, 2, 3, 4, 20 or 8 to select the TIM peripheral. + * @param TIM_OCClear: new state of the Output Compare Clear Enable Bit. + * This parameter can be one of the following values: + * @arg TIM_OCClear_Enable: TIM Output clear enable + * @arg TIM_OCClear_Disable: TIM Output clear disable + * @retval None + */ +void TIM_ClearOC4Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear) +{ + uint32_t tmpccmr2 = 0; + + /* Check the parameters */ + assert_param(IS_TIM_LIST3_PERIPH(TIMx)); + assert_param(IS_TIM_OCCLEAR_STATE(TIM_OCClear)); + + tmpccmr2 = TIMx->CCMR2; + + /* Reset the OC4CE Bit */ + tmpccmr2 &= (uint32_t)~TIM_CCMR2_OC4CE; + + /* Enable or Disable the Output Compare Clear Bit */ + tmpccmr2 |= ((uint32_t)TIM_OCClear << 8); + + /* Write to TIMx CCMR2 register */ + TIMx->CCMR2 = tmpccmr2; +} + +/** + * @brief Clears or safeguards the OCREF5 signal on an external event + * @param TIMx: where x can be 1 or 8 or 20 to select the TIM peripheral. + * @param TIM_OCClear: new state of the Output Compare Clear Enable Bit. + * This parameter can be one of the following values: + * @arg TIM_OCClear_Enable: TIM Output clear enable + * @arg TIM_OCClear_Disable: TIM Output clear disable + * @retval None + */ +void TIM_ClearOC5Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear) +{ + uint32_t tmpccmr3 = 0; + + /* Check the parameters */ + assert_param(IS_TIM_LIST4_PERIPH(TIMx)); + assert_param(IS_TIM_OCCLEAR_STATE(TIM_OCClear)); + + tmpccmr3 = TIMx->CCMR3; + + /* Reset the OC5CE Bit */ + tmpccmr3 &= (uint32_t)~TIM_CCMR3_OC5CE; + + /* Enable or Disable the Output Compare Clear Bit */ + tmpccmr3 |= (uint32_t)(TIM_OCClear); + + /* Write to TIMx CCMR3 register */ + TIMx->CCMR3 = tmpccmr3; +} + +/** + * @brief Clears or safeguards the OCREF6 signal on an external event + * @param TIMx: where x can be 1 or 8 or 20 to select the TIM peripheral. + * @param TIM_OCClear: new state of the Output Compare Clear Enable Bit. + * This parameter can be one of the following values: + * @arg TIM_OCClear_Enable: TIM Output clear enable + * @arg TIM_OCClear_Disable: TIM Output clear disable + * @retval None + */ +void TIM_ClearOC6Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear) +{ + uint32_t tmpccmr3 = 0; + + /* Check the parameters */ + assert_param(IS_TIM_LIST4_PERIPH(TIMx)); + assert_param(IS_TIM_OCCLEAR_STATE(TIM_OCClear)); + + tmpccmr3 = TIMx->CCMR3; + + /* Reset the OC5CE Bit */ + tmpccmr3 &= (uint32_t)~TIM_CCMR3_OC6CE; + + /* Enable or Disable the Output Compare Clear Bit */ + tmpccmr3 |= ((uint32_t)TIM_OCClear << 8); + + /* Write to TIMx CCMR3 register */ + TIMx->CCMR3 = tmpccmr3; +} + +/** + * @brief Selects the OCReference Clear source. + * @param TIMx: where x can be 1, 2, 3, 4, 8, 15, 16, 20 or 17 to select the TIM peripheral. + * @param TIM_OCReferenceClear: specifies the OCReference Clear source. + * This parameter can be one of the following values: + * @arg TIM_OCReferenceClear_ETRF: The internal OCreference clear input is connected to ETRF. + * @arg TIM_OCReferenceClear_OCREFCLR: The internal OCreference clear input is connected to OCREF_CLR input. + * @retval None + */ +void TIM_SelectOCREFClear(TIM_TypeDef* TIMx, uint16_t TIM_OCReferenceClear) +{ + /* Check the parameters */ + assert_param(IS_TIM_LIST2_PERIPH(TIMx)); + assert_param(TIM_OCREFERENCECECLEAR_SOURCE(TIM_OCReferenceClear)); + + /* Set the TIM_OCReferenceClear source */ + TIMx->SMCR &= (uint16_t)~((uint16_t)TIM_SMCR_OCCS); + TIMx->SMCR |= TIM_OCReferenceClear; +} + +/** + * @brief Configures the TIMx channel 1 polarity. + * @param TIMx: where x can be 1, 2, 3, 4, 8, 15, 16, 20 or 17 to select the TIM peripheral. + * @param TIM_OCPolarity: specifies the OC1 Polarity + * This parameter can be one of the following values: + * @arg TIM_OCPolarity_High: Output Compare active high + * @arg TIM_OCPolarity_Low: Output Compare active low + * @retval None + */ +void TIM_OC1PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity) +{ + uint32_t tmpccer = 0; + + /* Check the parameters */ + assert_param(IS_TIM_LIST1_PERIPH(TIMx)); + assert_param(IS_TIM_OC_POLARITY(TIM_OCPolarity)); + + tmpccer = TIMx->CCER; + + /* Set or Reset the CC1P Bit */ + tmpccer &= (uint32_t)(~TIM_CCER_CC1P); + tmpccer |= TIM_OCPolarity; + + /* Write to TIMx CCER register */ + TIMx->CCER = tmpccer; +} + +/** + * @brief Configures the TIMx Channel 1N polarity. + * @param TIMx: where x can be 1, 8, 15, 16, 20 or 17 to select the TIM peripheral. + * @param TIM_OCNPolarity: specifies the OC1N Polarity + * This parameter can be one of the following values: + * @arg TIM_OCNPolarity_High: Output Compare active high + * @arg TIM_OCNPolarity_Low: Output Compare active low + * @retval None + */ +void TIM_OC1NPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCNPolarity) +{ + uint32_t tmpccer = 0; + /* Check the parameters */ + assert_param(IS_TIM_LIST6_PERIPH(TIMx)); + assert_param(IS_TIM_OCN_POLARITY(TIM_OCNPolarity)); + + tmpccer = TIMx->CCER; + + /* Set or Reset the CC1NP Bit */ + tmpccer &= (uint32_t)~TIM_CCER_CC1NP; + tmpccer |= TIM_OCNPolarity; + + /* Write to TIMx CCER register */ + TIMx->CCER = tmpccer; +} + +/** + * @brief Configures the TIMx channel 2 polarity. + * @param TIMx: where x can be 1, 2, 3, 4, 8, 20 or 15 to select the TIM + * peripheral. + * @param TIM_OCPolarity: specifies the OC2 Polarity + * This parameter can be one of the following values: + * @arg TIM_OCPolarity_High: Output Compare active high + * @arg TIM_OCPolarity_Low: Output Compare active low + * @retval None + */ +void TIM_OC2PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity) +{ + uint32_t tmpccer = 0; + + /* Check the parameters */ + assert_param(IS_TIM_LIST2_PERIPH(TIMx)); + assert_param(IS_TIM_OC_POLARITY(TIM_OCPolarity)); + + tmpccer = TIMx->CCER; + + /* Set or Reset the CC2P Bit */ + tmpccer &= (uint32_t)(~TIM_CCER_CC2P); + tmpccer |= ((uint32_t)TIM_OCPolarity << 4); + + /* Write to TIMx CCER register */ + TIMx->CCER = tmpccer; +} + +/** + * @brief Configures the TIMx Channel 2N polarity. + * @param TIMx: where x can be 1 or 8 or 20 to select the TIM peripheral. + * @param TIM_OCNPolarity: specifies the OC2N Polarity + * This parameter can be one of the following values: + * @arg TIM_OCNPolarity_High: Output Compare active high + * @arg TIM_OCNPolarity_Low: Output Compare active low + * @retval None + */ +void TIM_OC2NPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCNPolarity) +{ + uint32_t tmpccer = 0; + + /* Check the parameters */ + assert_param(IS_TIM_LIST4_PERIPH(TIMx)); + assert_param(IS_TIM_OCN_POLARITY(TIM_OCNPolarity)); + + tmpccer = TIMx->CCER; + + /* Set or Reset the CC2NP Bit */ + tmpccer &= (uint32_t)~TIM_CCER_CC2NP; + tmpccer |= ((uint32_t)TIM_OCNPolarity << 4); + + /* Write to TIMx CCER register */ + TIMx->CCER = tmpccer; +} + +/** + * @brief Configures the TIMx channel 3 polarity. + * @param TIMx: where x can be 1, 2, 3, 4, 20 or 8 to select the TIM peripheral. + * @param TIM_OCPolarity: specifies the OC3 Polarity + * This parameter can be one of the following values: + * @arg TIM_OCPolarity_High: Output Compare active high + * @arg TIM_OCPolarity_Low: Output Compare active low + * @retval None + */ +void TIM_OC3PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity) +{ + uint32_t tmpccer = 0; + + /* Check the parameters */ + assert_param(IS_TIM_LIST3_PERIPH(TIMx)); + assert_param(IS_TIM_OC_POLARITY(TIM_OCPolarity)); + + tmpccer = TIMx->CCER; + + /* Set or Reset the CC3P Bit */ + tmpccer &= (uint32_t)~TIM_CCER_CC3P; + tmpccer |= ((uint32_t)TIM_OCPolarity << 8); + + /* Write to TIMx CCER register */ + TIMx->CCER = tmpccer; +} + +/** + * @brief Configures the TIMx Channel 3N polarity. + * @param TIMx: where x can be 1 or 8 or 20 to select the TIM peripheral. + * @param TIM_OCNPolarity: specifies the OC3N Polarity + * This parameter can be one of the following values: + * @arg TIM_OCNPolarity_High: Output Compare active high + * @arg TIM_OCNPolarity_Low: Output Compare active low + * @retval None + */ +void TIM_OC3NPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCNPolarity) +{ + uint32_t tmpccer = 0; + + /* Check the parameters */ + assert_param(IS_TIM_LIST4_PERIPH(TIMx)); + assert_param(IS_TIM_OCN_POLARITY(TIM_OCNPolarity)); + + tmpccer = TIMx->CCER; + + /* Set or Reset the CC3NP Bit */ + tmpccer &= (uint32_t)~TIM_CCER_CC3NP; + tmpccer |= ((uint32_t)TIM_OCNPolarity << 8); + + /* Write to TIMx CCER register */ + TIMx->CCER = tmpccer; +} + +/** + * @brief Configures the TIMx channel 4 polarity. + * @param TIMx: where x can be 1, 2, 3, 4, 20 or 8 to select the TIM peripheral. + * @param TIM_OCPolarity: specifies the OC4 Polarity + * This parameter can be one of the following values: + * @arg TIM_OCPolarity_High: Output Compare active high + * @arg TIM_OCPolarity_Low: Output Compare active low + * @retval None + */ +void TIM_OC4PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity) +{ + uint32_t tmpccer = 0; + + /* Check the parameters */ + assert_param(IS_TIM_LIST3_PERIPH(TIMx)); + assert_param(IS_TIM_OC_POLARITY(TIM_OCPolarity)); + + tmpccer = TIMx->CCER; + + /* Set or Reset the CC4P Bit */ + tmpccer &= (uint32_t)~TIM_CCER_CC4P; + tmpccer |= ((uint32_t)TIM_OCPolarity << 12); + + /* Write to TIMx CCER register */ + TIMx->CCER = tmpccer; +} + +/** + * @brief Configures the TIMx channel 5 polarity. + * @param TIMx: where x can be 1 or 8 or 20 to select the TIM peripheral. + * @param TIM_OCPolarity: specifies the OC5 Polarity + * This parameter can be one of the following values: + * @arg TIM_OCPolarity_High: Output Compare active high + * @arg TIM_OCPolarity_Low: Output Compare active low + * @retval None + */ +void TIM_OC5PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity) +{ + uint32_t tmpccer = 0; + + /* Check the parameters */ + assert_param(IS_TIM_LIST4_PERIPH(TIMx)); + assert_param(IS_TIM_OC_POLARITY(TIM_OCPolarity)); + + tmpccer = TIMx->CCER; + + /* Set or Reset the CC5P Bit */ + tmpccer &= (uint32_t)~TIM_CCER_CC5P; + tmpccer |= ((uint32_t)TIM_OCPolarity << 16); + + /* Write to TIMx CCER register */ + TIMx->CCER = tmpccer; +} + +/** + * @brief Configures the TIMx channel 6 polarity. + * @param TIMx: where x can be 1 or 8 or 20 to select the TIM peripheral. + * @param TIM_OCPolarity: specifies the OC6 Polarity + * This parameter can be one of the following values: + * @arg TIM_OCPolarity_High: Output Compare active high + * @arg TIM_OCPolarity_Low: Output Compare active low + * @retval None + */ +void TIM_OC6PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity) +{ + uint32_t tmpccer = 0; + + /* Check the parameters */ + assert_param(IS_TIM_LIST4_PERIPH(TIMx)); + assert_param(IS_TIM_OC_POLARITY(TIM_OCPolarity)); + + tmpccer = TIMx->CCER; + + /* Set or Reset the CC6P Bit */ + tmpccer &= (uint32_t)~TIM_CCER_CC6P; + tmpccer |= ((uint32_t)TIM_OCPolarity << 20); + + /* Write to TIMx CCER register */ + TIMx->CCER = tmpccer; +} + +/** + * @brief Enables or disables the TIM Capture Compare Channel x. + * @param TIMx: where x can be 1, 2, 3, 4, 8, 15, 16, 20 or 17 to select the TIM peripheral. + * @param TIM_Channel: specifies the TIM Channel + * This parameter can be one of the following values: + * @arg TIM_Channel_1: TIM Channel 1 + * @arg TIM_Channel_2: TIM Channel 2 + * @arg TIM_Channel_3: TIM Channel 3 + * @arg TIM_Channel_4: TIM Channel 4 + * @arg TIM_Channel_5: TIM Channel 5 + * @arg TIM_Channel_6: TIM Channel 6 + * @param TIM_CCx: specifies the TIM Channel CCxE bit new state. + * This parameter can be: TIM_CCx_Enable or TIM_CCx_Disable. + * @retval None + */ +void TIM_CCxCmd(TIM_TypeDef* TIMx, uint16_t TIM_Channel, uint16_t TIM_CCx) +{ + uint32_t tmp = 0; + + /* Check the parameters */ + assert_param(IS_TIM_LIST1_PERIPH(TIMx)); + assert_param(IS_TIM_CHANNEL(TIM_Channel)); + assert_param(IS_TIM_CCX(TIM_CCx)); + + tmp = (uint32_t)CCER_CCE_SET << (uint32_t)TIM_Channel; + + /* Reset the CCxE Bit */ + TIMx->CCER &= (uint32_t)(~tmp); + + /* Set or reset the CCxE Bit */ + TIMx->CCER |= ((uint32_t)TIM_CCx << (uint32_t)TIM_Channel); +} + +/** + * @brief Enables or disables the TIM Capture Compare Channel xN. + * @param TIMx: where x can be 1, 8, 15, 16, 20 or 17 to select the TIM peripheral. + * @param TIM_Channel: specifies the TIM Channel + * This parameter can be one of the following values: + * @arg TIM_Channel_1: TIM Channel 1 + * @arg TIM_Channel_2: TIM Channel 2 + * @arg TIM_Channel_3: TIM Channel 3 + * @param TIM_CCxN: specifies the TIM Channel CCxNE bit new state. + * This parameter can be: TIM_CCxN_Enable or TIM_CCxN_Disable. + * @retval None + */ +void TIM_CCxNCmd(TIM_TypeDef* TIMx, uint16_t TIM_Channel, uint16_t TIM_CCxN) +{ + uint32_t tmp = 0; + + /* Check the parameters */ + assert_param(IS_TIM_LIST6_PERIPH(TIMx)); + assert_param(IS_TIM_COMPLEMENTARY_CHANNEL(TIM_Channel)); + assert_param(IS_TIM_CCXN(TIM_CCxN)); + + tmp = (uint32_t)CCER_CCNE_SET << (uint32_t)TIM_Channel; + + /* Reset the CCxNE Bit */ + TIMx->CCER &= (uint32_t) ~tmp; + + /* Set or reset the CCxNE Bit */ + TIMx->CCER |= ((uint32_t)TIM_CCxN << (uint32_t)TIM_Channel); +} +/** + * @} + */ + +/** @defgroup TIM_Group3 Input Capture management functions + * @brief Input Capture management functions + * +@verbatim + =============================================================================== + ##### Input Capture management functions ##### + =============================================================================== + + *** TIM Driver: how to use it in Input Capture Mode *** + ======================================================= + [..] + To use the Timer in Input Capture mode, the following steps are mandatory: + + (#) Enable TIM clock using RCC_APBxPeriphClockCmd(RCC_APBxPeriph_TIMx, ENABLE) function + + (#) Configure the TIM pins by configuring the corresponding GPIO pins + + (#) Configure the Time base unit as described in the first part of this driver, + if needed, else the Timer will run with the default configuration: + (++) Autoreload value = 0xFFFF + (++) Prescaler value = 0x0000 + (++) Counter mode = Up counting + (++) Clock Division = TIM_CKD_DIV1 + + (#) Fill the TIM_ICInitStruct with the desired parameters including: + (++) TIM Channel: TIM_Channel + (++) TIM Input Capture polarity: TIM_ICPolarity + (++) TIM Input Capture selection: TIM_ICSelection + (++) TIM Input Capture Prescaler: TIM_ICPrescaler + (++) TIM Input CApture filter value: TIM_ICFilter + + (#) Call TIM_ICInit(TIMx, &TIM_ICInitStruct) to configure the desired channel with the + corresponding configuration and to measure only frequency or duty cycle of the input signal, + or, + Call TIM_PWMIConfig(TIMx, &TIM_ICInitStruct) to configure the desired channels with the + corresponding configuration and to measure the frequency and the duty cycle of the input signal + + (#) Enable the NVIC or the DMA to read the measured frequency. + + (#) Enable the corresponding interrupt (or DMA request) to read the Captured value, + using the function TIM_ITConfig(TIMx, TIM_IT_CCx) (or TIM_DMA_Cmd(TIMx, TIM_DMA_CCx)) + + (#) Call the TIM_Cmd(ENABLE) function to enable the TIM counter. + + (#) Use TIM_GetCapturex(TIMx); to read the captured value. + [..] + (@) All other functions can be used separately to modify, if needed, + a specific feature of the Timer. + +@endverbatim + * @{ + */ + +/** + * @brief Initializes the TIM peripheral according to the specified parameters + * in the TIM_ICInitStruct. + * @param TIMx: where x can be 1, 2, 3, 4, 8, 15, 16, 20 or 17 to select the TIM peripheral. + * @param TIM_ICInitStruct: pointer to a TIM_ICInitTypeDef structure that contains + * the configuration information for the specified TIM peripheral. + * @retval None + */ +void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct) +{ + /* Check the parameters */ + assert_param(IS_TIM_LIST1_PERIPH(TIMx)); + assert_param(IS_TIM_IC_POLARITY(TIM_ICInitStruct->TIM_ICPolarity)); + assert_param(IS_TIM_IC_SELECTION(TIM_ICInitStruct->TIM_ICSelection)); + assert_param(IS_TIM_IC_PRESCALER(TIM_ICInitStruct->TIM_ICPrescaler)); + assert_param(IS_TIM_IC_FILTER(TIM_ICInitStruct->TIM_ICFilter)); + + if (TIM_ICInitStruct->TIM_Channel == TIM_Channel_1) + { + /* TI1 Configuration */ + TI1_Config(TIMx, TIM_ICInitStruct->TIM_ICPolarity, + TIM_ICInitStruct->TIM_ICSelection, + TIM_ICInitStruct->TIM_ICFilter); + /* Set the Input Capture Prescaler value */ + TIM_SetIC1Prescaler(TIMx, TIM_ICInitStruct->TIM_ICPrescaler); + } + else if (TIM_ICInitStruct->TIM_Channel == TIM_Channel_2) + { + /* TI2 Configuration */ + TI2_Config(TIMx, TIM_ICInitStruct->TIM_ICPolarity, + TIM_ICInitStruct->TIM_ICSelection, + TIM_ICInitStruct->TIM_ICFilter); + /* Set the Input Capture Prescaler value */ + TIM_SetIC2Prescaler(TIMx, TIM_ICInitStruct->TIM_ICPrescaler); + } + else if (TIM_ICInitStruct->TIM_Channel == TIM_Channel_3) + { + /* TI3 Configuration */ + TI3_Config(TIMx, TIM_ICInitStruct->TIM_ICPolarity, + TIM_ICInitStruct->TIM_ICSelection, + TIM_ICInitStruct->TIM_ICFilter); + /* Set the Input Capture Prescaler value */ + TIM_SetIC3Prescaler(TIMx, TIM_ICInitStruct->TIM_ICPrescaler); + } + else + { + /* TI4 Configuration */ + TI4_Config(TIMx, TIM_ICInitStruct->TIM_ICPolarity, + TIM_ICInitStruct->TIM_ICSelection, + TIM_ICInitStruct->TIM_ICFilter); + /* Set the Input Capture Prescaler value */ + TIM_SetIC4Prescaler(TIMx, TIM_ICInitStruct->TIM_ICPrescaler); + } +} + +/** + * @brief Fills each TIM_ICInitStruct member with its default value. + * @param TIM_ICInitStruct: pointer to a TIM_ICInitTypeDef structure which will + * be initialized. + * @retval None + */ +void TIM_ICStructInit(TIM_ICInitTypeDef* TIM_ICInitStruct) +{ + /* Set the default configuration */ + TIM_ICInitStruct->TIM_Channel = TIM_Channel_1; + TIM_ICInitStruct->TIM_ICPolarity = TIM_ICPolarity_Rising; + TIM_ICInitStruct->TIM_ICSelection = TIM_ICSelection_DirectTI; + TIM_ICInitStruct->TIM_ICPrescaler = TIM_ICPSC_DIV1; + TIM_ICInitStruct->TIM_ICFilter = 0x00; +} + +/** + * @brief Configures the TIM peripheral according to the specified parameters + * in the TIM_ICInitStruct to measure an external PWM signal. + * @param TIMx: where x can be 1, 2, 3, 4, 8, 20 or 15 to select the TIM + * peripheral. + * @param TIM_ICInitStruct: pointer to a TIM_ICInitTypeDef structure that contains + * the configuration information for the specified TIM peripheral. + * @retval None + */ +void TIM_PWMIConfig(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct) +{ + uint16_t icoppositepolarity = TIM_ICPolarity_Rising; + uint16_t icoppositeselection = TIM_ICSelection_DirectTI; + + /* Check the parameters */ + assert_param(IS_TIM_LIST2_PERIPH(TIMx)); + + /* Select the Opposite Input Polarity */ + if (TIM_ICInitStruct->TIM_ICPolarity == TIM_ICPolarity_Rising) + { + icoppositepolarity = TIM_ICPolarity_Falling; + } + else + { + icoppositepolarity = TIM_ICPolarity_Rising; + } + /* Select the Opposite Input */ + if (TIM_ICInitStruct->TIM_ICSelection == TIM_ICSelection_DirectTI) + { + icoppositeselection = TIM_ICSelection_IndirectTI; + } + else + { + icoppositeselection = TIM_ICSelection_DirectTI; + } + if (TIM_ICInitStruct->TIM_Channel == TIM_Channel_1) + { + /* TI1 Configuration */ + TI1_Config(TIMx, TIM_ICInitStruct->TIM_ICPolarity, TIM_ICInitStruct->TIM_ICSelection, + TIM_ICInitStruct->TIM_ICFilter); + /* Set the Input Capture Prescaler value */ + TIM_SetIC1Prescaler(TIMx, TIM_ICInitStruct->TIM_ICPrescaler); + /* TI2 Configuration */ + TI2_Config(TIMx, icoppositepolarity, icoppositeselection, TIM_ICInitStruct->TIM_ICFilter); + /* Set the Input Capture Prescaler value */ + TIM_SetIC2Prescaler(TIMx, TIM_ICInitStruct->TIM_ICPrescaler); + } + else + { + /* TI2 Configuration */ + TI2_Config(TIMx, TIM_ICInitStruct->TIM_ICPolarity, TIM_ICInitStruct->TIM_ICSelection, + TIM_ICInitStruct->TIM_ICFilter); + /* Set the Input Capture Prescaler value */ + TIM_SetIC2Prescaler(TIMx, TIM_ICInitStruct->TIM_ICPrescaler); + /* TI1 Configuration */ + TI1_Config(TIMx, icoppositepolarity, icoppositeselection, TIM_ICInitStruct->TIM_ICFilter); + /* Set the Input Capture Prescaler value */ + TIM_SetIC1Prescaler(TIMx, TIM_ICInitStruct->TIM_ICPrescaler); + } +} + +/** + * @brief Gets the TIMx Input Capture 1 value. + * @param TIMx: where x can be 1, 2, 3, 4, 8, 15, 16, 20 or 17 to select the TIM peripheral. + * @retval Capture Compare 1 Register value. + */ +uint32_t TIM_GetCapture1(TIM_TypeDef* TIMx) +{ + /* Check the parameters */ + assert_param(IS_TIM_LIST1_PERIPH(TIMx)); + + /* Get the Capture 1 Register value */ + return TIMx->CCR1; +} + +/** + * @brief Gets the TIMx Input Capture 2 value. + * @param TIMx: where x can be 1, 2, 3, 4, 8, 20 or 15 to select the TIM + * peripheral. + * @retval Capture Compare 2 Register value. + */ +uint32_t TIM_GetCapture2(TIM_TypeDef* TIMx) +{ + /* Check the parameters */ + assert_param(IS_TIM_LIST2_PERIPH(TIMx)); + + /* Get the Capture 2 Register value */ + return TIMx->CCR2; +} + +/** + * @brief Gets the TIMx Input Capture 3 value. + * @param TIMx: where x can be 1, 2, 3, 4, 20 or 8 to select the TIM peripheral. + * @retval Capture Compare 3 Register value. + */ +uint32_t TIM_GetCapture3(TIM_TypeDef* TIMx) +{ + /* Check the parameters */ + assert_param(IS_TIM_LIST3_PERIPH(TIMx)); + + /* Get the Capture 3 Register value */ + return TIMx->CCR3; +} + +/** + * @brief Gets the TIMx Input Capture 4 value. + * @param TIMx: where x can be 1, 2, 3, 4, 20 or 8 to select the TIM peripheral. + * @retval Capture Compare 4 Register value. + */ +uint32_t TIM_GetCapture4(TIM_TypeDef* TIMx) +{ + /* Check the parameters */ + assert_param(IS_TIM_LIST3_PERIPH(TIMx)); + + /* Get the Capture 4 Register value */ + return TIMx->CCR4; +} + +/** + * @brief Sets the TIMx Input Capture 1 prescaler. + * @param TIMx: where x can be 1, 2, 3, 4, 8, 15, 16, 20 or 17 to select the TIM peripheral. + * @param TIM_ICPSC: specifies the Input Capture1 prescaler new value. + * This parameter can be one of the following values: + * @arg TIM_ICPSC_DIV1: no prescaler + * @arg TIM_ICPSC_DIV2: capture is done once every 2 events + * @arg TIM_ICPSC_DIV4: capture is done once every 4 events + * @arg TIM_ICPSC_DIV8: capture is done once every 8 events + * @retval None + */ +void TIM_SetIC1Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC) +{ + /* Check the parameters */ + assert_param(IS_TIM_LIST1_PERIPH(TIMx)); + assert_param(IS_TIM_IC_PRESCALER(TIM_ICPSC)); + + /* Reset the IC1PSC Bits */ + TIMx->CCMR1 &= (uint32_t)~TIM_CCMR1_IC1PSC; + + /* Set the IC1PSC value */ + TIMx->CCMR1 |= TIM_ICPSC; +} + +/** + * @brief Sets the TIMx Input Capture 2 prescaler. + * @param TIMx: where x can be 1, 2, 3, 4, 8, 20 or 15 to select the TIM + * peripheral. + * @param TIM_ICPSC: specifies the Input Capture2 prescaler new value. + * This parameter can be one of the following values: + * @arg TIM_ICPSC_DIV1: no prescaler + * @arg TIM_ICPSC_DIV2: capture is done once every 2 events + * @arg TIM_ICPSC_DIV4: capture is done once every 4 events + * @arg TIM_ICPSC_DIV8: capture is done once every 8 events + * @retval None + */ +void TIM_SetIC2Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC) +{ + /* Check the parameters */ + assert_param(IS_TIM_LIST2_PERIPH(TIMx)); + assert_param(IS_TIM_IC_PRESCALER(TIM_ICPSC)); + + /* Reset the IC2PSC Bits */ + TIMx->CCMR1 &= (uint32_t)~TIM_CCMR1_IC2PSC; + + /* Set the IC2PSC value */ + TIMx->CCMR1 |= (uint32_t)((uint32_t)TIM_ICPSC << 8); +} + +/** + * @brief Sets the TIMx Input Capture 3 prescaler. + * @param TIMx: where x can be 1, 2, 3, 4, 20 or 8 to select the TIM peripheral. + * @param TIM_ICPSC: specifies the Input Capture3 prescaler new value. + * This parameter can be one of the following values: + * @arg TIM_ICPSC_DIV1: no prescaler + * @arg TIM_ICPSC_DIV2: capture is done once every 2 events + * @arg TIM_ICPSC_DIV4: capture is done once every 4 events + * @arg TIM_ICPSC_DIV8: capture is done once every 8 events + * @retval None + */ +void TIM_SetIC3Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC) +{ + /* Check the parameters */ + assert_param(IS_TIM_LIST3_PERIPH(TIMx)); + assert_param(IS_TIM_IC_PRESCALER(TIM_ICPSC)); + + /* Reset the IC3PSC Bits */ + TIMx->CCMR2 &= (uint16_t)~TIM_CCMR2_IC3PSC; + + /* Set the IC3PSC value */ + TIMx->CCMR2 |= TIM_ICPSC; +} + +/** + * @brief Sets the TIMx Input Capture 4 prescaler. + * @param TIMx: where x can be 1, 2, 3, 4, 20 or 8 to select the TIM peripheral. + * @param TIM_ICPSC: specifies the Input Capture4 prescaler new value. + * This parameter can be one of the following values: + * @arg TIM_ICPSC_DIV1: no prescaler + * @arg TIM_ICPSC_DIV2: capture is done once every 2 events + * @arg TIM_ICPSC_DIV4: capture is done once every 4 events + * @arg TIM_ICPSC_DIV8: capture is done once every 8 events + * @retval None + */ +void TIM_SetIC4Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC) +{ + /* Check the parameters */ + assert_param(IS_TIM_LIST3_PERIPH(TIMx)); + assert_param(IS_TIM_IC_PRESCALER(TIM_ICPSC)); + + /* Reset the IC4PSC Bits */ + TIMx->CCMR2 &= (uint16_t)~TIM_CCMR2_IC4PSC; + + /* Set the IC4PSC value */ + TIMx->CCMR2 |= (uint16_t)(TIM_ICPSC << 8); +} +/** + * @} + */ + +/** @defgroup TIM_Group4 Advanced-control timers (TIM1 and TIM8) specific features + * @brief Advanced-control timers (TIM1 and TIM8) specific features + * +@verbatim + =============================================================================== + ##### Advanced-control timers (TIM1 and TIM8) specific features ##### + =============================================================================== + + *** TIM Driver: how to use the Break feature *** + ================================================ + [..] + After configuring the Timer channel(s) in the appropriate Output Compare mode: + + (#) Fill the TIM_BDTRInitStruct with the desired parameters for the Timer + Break Polarity, dead time, Lock level, the OSSI/OSSR State and the + AOE(automatic output enable). + + (#) Call TIM_BDTRConfig(TIMx, &TIM_BDTRInitStruct) to configure the Timer + + (#) Enable the Main Output using TIM_CtrlPWMOutputs(TIM1, ENABLE) + + (#) Once the break even occurs, the Timer's output signals are put in reset + state or in a known state (according to the configuration made in + TIM_BDTRConfig() function). + +@endverbatim + * @{ + */ + +/** + * @brief Configures the Break feature, dead time, Lock level, OSSI/OSSR State + * and the AOE(automatic output enable). + * @param TIMx: where x can be 1, 8, 15, 16, 20 or 17 to select the TIM + * @param TIM_BDTRInitStruct: pointer to a TIM_BDTRInitTypeDef structure that + * contains the BDTR Register configuration information for the TIM peripheral. + * @retval None + */ +void TIM_BDTRConfig(TIM_TypeDef* TIMx, TIM_BDTRInitTypeDef *TIM_BDTRInitStruct) +{ + /* Check the parameters */ + assert_param(IS_TIM_LIST6_PERIPH(TIMx)); + assert_param(IS_TIM_OSSR_STATE(TIM_BDTRInitStruct->TIM_OSSRState)); + assert_param(IS_TIM_OSSI_STATE(TIM_BDTRInitStruct->TIM_OSSIState)); + assert_param(IS_TIM_LOCK_LEVEL(TIM_BDTRInitStruct->TIM_LOCKLevel)); + assert_param(IS_TIM_BREAK_STATE(TIM_BDTRInitStruct->TIM_Break)); + assert_param(IS_TIM_BREAK_POLARITY(TIM_BDTRInitStruct->TIM_BreakPolarity)); + assert_param(IS_TIM_AUTOMATIC_OUTPUT_STATE(TIM_BDTRInitStruct->TIM_AutomaticOutput)); + + /* Set the Lock level, the Break enable Bit and the Polarity, the OSSR State, + the OSSI State, the dead time value and the Automatic Output Enable Bit */ + TIMx->BDTR = (uint32_t)TIM_BDTRInitStruct->TIM_OSSRState | TIM_BDTRInitStruct->TIM_OSSIState | + TIM_BDTRInitStruct->TIM_LOCKLevel | TIM_BDTRInitStruct->TIM_DeadTime | + TIM_BDTRInitStruct->TIM_Break | TIM_BDTRInitStruct->TIM_BreakPolarity | + TIM_BDTRInitStruct->TIM_AutomaticOutput; +} + +/** + * @brief Configures the Break1 feature. + * @param TIMx: where x can be 1 or 8 or 20 to select the TIM + * @param TIM_Break1Polarity: specifies the Break1 polarity. + * This parameter can be one of the following values: + * @arg TIM_Break1Polarity_Low: Break1 input is active low + * @arg TIM_Break1Polarity_High: Break1 input is active high + * @param TIM_Break1Filter: specifies the Break1 filter value. + * This parameter must be a value between 0x00 and 0x0F + * @retval None + */ +void TIM_Break1Config(TIM_TypeDef* TIMx, uint32_t TIM_Break1Polarity, uint8_t TIM_Break1Filter) +{ /* Check the parameters */ + assert_param(IS_TIM_LIST4_PERIPH(TIMx)); + assert_param(IS_TIM_BREAK1_FILTER(TIM_Break1Filter)); + + /* Reset the BKP and BKF Bits */ + TIMx->BDTR &= (uint32_t)~ (TIM_BDTR_BKP | TIM_BDTR_BKF); + /* Configure the Break1 polarity and filter */ + TIMx->BDTR |= TIM_Break1Polarity |((uint32_t)TIM_Break1Filter << 16); +} + +/** + * @brief Configures the Break2 feature. + * @param TIMx: where x can be 1 or 8 or 20 to select the TIM + * @param TIM_Break2Polarity: specifies the Break2 polarity. + * This parameter can be one of the following values: + * @arg TIM_Break2Polarity_Low: Break2 input is active low + * @arg TIM_Break2Polarity_High: Break2 input is active high + * @param TIM_Break2Filter: specifies the Break2 filter value. + * This parameter must be a value between 0x00 and 0x0F + * @retval None + */ +void TIM_Break2Config(TIM_TypeDef* TIMx, uint32_t TIM_Break2Polarity, uint8_t TIM_Break2Filter) +{ + /* Check the parameters */ + assert_param(IS_TIM_LIST4_PERIPH(TIMx)); + assert_param(IS_TIM_BREAK2_FILTER(TIM_Break2Filter)); + + /* Reset the BKP and BKF Bits */ + TIMx->BDTR &= (uint32_t)~ (TIM_BDTR_BK2P | TIM_BDTR_BK2F); + + /* Configure the Break1 polarity and filter */ + TIMx->BDTR |= TIM_Break2Polarity |((uint32_t)TIM_Break2Filter << 20); +} + +/** + * @brief Enables or disables the TIM Break1 input. + * @param TIMx: where x can be 1, 8, 20, 16 or 17 to select the TIMx peripheral. + * @param NewState: new state of the TIM Break1 input. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void TIM_Break1Cmd(TIM_TypeDef* TIMx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_TIM_LIST6_PERIPH(TIMx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable the Break1 */ + TIMx->BDTR |= TIM_BDTR_BKE; + } + else + { + /* Disable the Break1 */ + TIMx->BDTR &= (uint32_t)~TIM_BDTR_BKE; + } +} + +/** + * @brief Enables or disables the TIM Break2 input. + * @param TIMx: where x can be 1 or 8 or 20 to select the TIMx peripheral. + * @param NewState: new state of the TIM Break2 input. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void TIM_Break2Cmd(TIM_TypeDef* TIMx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_TIM_LIST4_PERIPH(TIMx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable the Break1 */ + TIMx->BDTR |= TIM_BDTR_BK2E; + } + else + { + /* Disable the Break1 */ + TIMx->BDTR &= (uint32_t)~TIM_BDTR_BK2E; + } +} + +/** + * @brief Fills each TIM_BDTRInitStruct member with its default value. + * @param TIM_BDTRInitStruct: pointer to a TIM_BDTRInitTypeDef structure which + * will be initialized. + * @retval None + */ +void TIM_BDTRStructInit(TIM_BDTRInitTypeDef* TIM_BDTRInitStruct) +{ + /* Set the default configuration */ + TIM_BDTRInitStruct->TIM_OSSRState = TIM_OSSRState_Disable; + TIM_BDTRInitStruct->TIM_OSSIState = TIM_OSSIState_Disable; + TIM_BDTRInitStruct->TIM_LOCKLevel = TIM_LOCKLevel_OFF; + TIM_BDTRInitStruct->TIM_DeadTime = 0x00; + TIM_BDTRInitStruct->TIM_Break = TIM_Break_Disable; + TIM_BDTRInitStruct->TIM_BreakPolarity = TIM_BreakPolarity_Low; + TIM_BDTRInitStruct->TIM_AutomaticOutput = TIM_AutomaticOutput_Disable; +} + +/** + * @brief Enables or disables the TIM peripheral Main Outputs. + * @param TIMx: where x can be 1, 8, 15, 16, 20 or 17 to select the TIMx peripheral. + * @param NewState: new state of the TIM peripheral Main Outputs. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void TIM_CtrlPWMOutputs(TIM_TypeDef* TIMx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_TIM_LIST6_PERIPH(TIMx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable the TIM Main Output */ + TIMx->BDTR |= TIM_BDTR_MOE; + } + else + { + /* Disable the TIM Main Output */ + TIMx->BDTR &= (uint16_t)~TIM_BDTR_MOE; + } +} + +/** + * @brief Selects the TIM peripheral Commutation event. + * @param TIMx: where x can be 1, 8, 15, 16, 20 or 17 to select the TIMx peripheral + * @param NewState: new state of the Commutation event. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void TIM_SelectCOM(TIM_TypeDef* TIMx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_TIM_LIST6_PERIPH(TIMx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Set the COM Bit */ + TIMx->CR2 |= TIM_CR2_CCUS; + } + else + { + /* Reset the COM Bit */ + TIMx->CR2 &= (uint16_t)~TIM_CR2_CCUS; + } +} + +/** + * @brief Sets or Resets the TIM peripheral Capture Compare Preload Control bit. + * @param TIMx: where x can be 1 or 8 or 20 to select the TIMx peripheral + * @param NewState: new state of the Capture Compare Preload Control bit + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void TIM_CCPreloadControl(TIM_TypeDef* TIMx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_TIM_LIST6_PERIPH(TIMx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + if (NewState != DISABLE) + { + /* Set the CCPC Bit */ + TIMx->CR2 |= TIM_CR2_CCPC; + } + else + { + /* Reset the CCPC Bit */ + TIMx->CR2 &= (uint16_t)~TIM_CR2_CCPC; + } +} +/** + * @} + */ + +/** @defgroup TIM_Group5 Interrupts DMA and flags management functions + * @brief Interrupts, DMA and flags management functions + * +@verbatim + =============================================================================== + ##### Interrupts, DMA and flags management functions ##### + =============================================================================== + +@endverbatim + * @{ + */ + +/** + * @brief Enables or disables the specified TIM interrupts. + * @param TIMx: where x can be 1, 2, 3, 4, 6, 7, 8, 15, 16, 20 or 17 to select the TIMx peripheral. + * @param TIM_IT: specifies the TIM interrupts sources to be enabled or disabled. + * This parameter can be any combination of the following values: + * @arg TIM_IT_Update: TIM update Interrupt source + * @arg TIM_IT_CC1: TIM Capture Compare 1 Interrupt source + * @arg TIM_IT_CC2: TIM Capture Compare 2 Interrupt source + * @arg TIM_IT_CC3: TIM Capture Compare 3 Interrupt source + * @arg TIM_IT_CC4: TIM Capture Compare 4 Interrupt source + * @arg TIM_IT_COM: TIM Commutation Interrupt source + * @arg TIM_IT_Trigger: TIM Trigger Interrupt source + * @arg TIM_IT_Break: TIM Break Interrupt source + * + * @note For TIM6 and TIM7 only the parameter TIM_IT_Update can be used + * @note For TIM9 and TIM12 only one of the following parameters can be used: TIM_IT_Update, + * TIM_IT_CC1, TIM_IT_CC2 or TIM_IT_Trigger. + * @note For TIM10, TIM11, TIM13 and TIM14 only one of the following parameters can + * be used: TIM_IT_Update or TIM_IT_CC1 + * @note TIM_IT_COM and TIM_IT_Break can be used only with TIM1 and TIM8 + * + * @param NewState: new state of the TIM interrupts. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_TIM_ALL_PERIPH(TIMx)); + assert_param(IS_TIM_IT(TIM_IT)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable the Interrupt sources */ + TIMx->DIER |= TIM_IT; + } + else + { + /* Disable the Interrupt sources */ + TIMx->DIER &= (uint16_t)~TIM_IT; + } +} + +/** + * @brief Configures the TIMx event to be generate by software. + * @param TIMx: where x can be 1, 2, 3, 4, 6, 7, 8, 15, 16, 20 or 17 to select the TIM peripheral. + * @param TIM_EventSource: specifies the event source. + * This parameter can be one or more of the following values: + * @arg TIM_EventSource_Update: Timer update Event source + * @arg TIM_EventSource_CC1: Timer Capture Compare 1 Event source + * @arg TIM_EventSource_CC2: Timer Capture Compare 2 Event source + * @arg TIM_EventSource_CC3: Timer Capture Compare 3 Event source + * @arg TIM_EventSource_CC4: Timer Capture Compare 4 Event source + * @arg TIM_EventSource_COM: Timer COM event source + * @arg TIM_EventSource_Trigger: Timer Trigger Event source + * @arg TIM_EventSource_Break: Timer Break event source + * + * @note TIM6 and TIM7 can only generate an update event. + * @note TIM_EventSource_COM and TIM_EventSource_Break are used only with TIM1 and TIM8. + * + * @retval None + */ +void TIM_GenerateEvent(TIM_TypeDef* TIMx, uint16_t TIM_EventSource) +{ + /* Check the parameters */ + assert_param(IS_TIM_ALL_PERIPH(TIMx)); + assert_param(IS_TIM_EVENT_SOURCE(TIM_EventSource)); + + /* Set the event sources */ + TIMx->EGR = TIM_EventSource; +} + +/** + * @brief Checks whether the specified TIM flag is set or not. + * @param TIMx: where x can be 1, 2, 3, 4, 6, 7, 8, 15, 16, 20 or 17 to select the TIM peripheral. + * @param TIM_FLAG: specifies the flag to check. + * This parameter can be one of the following values: + * @arg TIM_FLAG_Update: TIM update Flag + * @arg TIM_FLAG_CC1: TIM Capture Compare 1 Flag + * @arg TIM_FLAG_CC2: TIM Capture Compare 2 Flag + * @arg TIM_FLAG_CC3: TIM Capture Compare 3 Flag + * @arg TIM_FLAG_CC4: TIM Capture Compare 4 Flag + * @arg TIM_FLAG_CC5: TIM Capture Compare 5 Flag + * @arg TIM_FLAG_CC6: TIM Capture Compare 6 Flag + * @arg TIM_FLAG_COM: TIM Commutation Flag + * @arg TIM_FLAG_Trigger: TIM Trigger Flag + * @arg TIM_FLAG_Break: TIM Break Flag + * @arg TIM_FLAG_CC1OF: TIM Capture Compare 1 over capture Flag + * @arg TIM_FLAG_CC2OF: TIM Capture Compare 2 over capture Flag + * @arg TIM_FLAG_CC3OF: TIM Capture Compare 3 over capture Flag + * @arg TIM_FLAG_CC4OF: TIM Capture Compare 4 over capture Flag + * + * @note TIM6 and TIM7 can have only one update flag. + * @note TIM_FLAG_COM and TIM_FLAG_Break are used only with TIM1 and TIM8. + * + * @retval The new state of TIM_FLAG (SET or RESET). + */ +FlagStatus TIM_GetFlagStatus(TIM_TypeDef* TIMx, uint32_t TIM_FLAG) +{ + ITStatus bitstatus = RESET; + /* Check the parameters */ + assert_param(IS_TIM_ALL_PERIPH(TIMx)); + assert_param(IS_TIM_GET_FLAG(TIM_FLAG)); + + + if ((TIMx->SR & TIM_FLAG) != RESET) + { + bitstatus = SET; + } + else + { + bitstatus = RESET; + } + return bitstatus; +} + +/** + * @brief Clears the TIMx's pending flags. + * @param TIMx: where x can be 1, 2, 3, 4, 6, 7, 8, 15, 16, 20 or 17 to select the TIM peripheral. + * @param TIM_FLAG: specifies the flag bit to clear. + * This parameter can be any combination of the following values: + * @arg TIM_FLAG_Update: TIM update Flag + * @arg TIM_FLAG_CC1: TIM Capture Compare 1 Flag + * @arg TIM_FLAG_CC2: TIM Capture Compare 2 Flag + * @arg TIM_FLAG_CC3: TIM Capture Compare 3 Flag + * @arg TIM_FLAG_CC4: TIM Capture Compare 4 Flag + * @arg TIM_FLAG_CC5: TIM Capture Compare 5 Flag + * @arg TIM_FLAG_CC6: TIM Capture Compare 6 Flag + * @arg TIM_FLAG_COM: TIM Commutation Flag + * @arg TIM_FLAG_Trigger: TIM Trigger Flag + * @arg TIM_FLAG_Break: TIM Break Flag + * @arg TIM_FLAG_CC1OF: TIM Capture Compare 1 over capture Flag + * @arg TIM_FLAG_CC2OF: TIM Capture Compare 2 over capture Flag + * @arg TIM_FLAG_CC3OF: TIM Capture Compare 3 over capture Flag + * @arg TIM_FLAG_CC4OF: TIM Capture Compare 4 over capture Flag + * + * @note TIM6 and TIM7 can have only one update flag. + * @note TIM_FLAG_COM and TIM_FLAG_Break are used only with TIM1 and TIM8. + * + * @retval None + */ +void TIM_ClearFlag(TIM_TypeDef* TIMx, uint16_t TIM_FLAG) +{ + /* Check the parameters */ + assert_param(IS_TIM_ALL_PERIPH(TIMx)); + + /* Clear the flags */ + TIMx->SR = (uint16_t)~TIM_FLAG; +} + +/** + * @brief Checks whether the TIM interrupt has occurred or not. + * @param TIMx: where x can be 1, 2, 3, 4, 6, 7, 8, 15, 16, 20 or 17 to select the TIM peripheral. + * @param TIM_IT: specifies the TIM interrupt source to check. + * This parameter can be one of the following values: + * @arg TIM_IT_Update: TIM update Interrupt source + * @arg TIM_IT_CC1: TIM Capture Compare 1 Interrupt source + * @arg TIM_IT_CC2: TIM Capture Compare 2 Interrupt source + * @arg TIM_IT_CC3: TIM Capture Compare 3 Interrupt source + * @arg TIM_IT_CC4: TIM Capture Compare 4 Interrupt source + * @arg TIM_IT_COM: TIM Commutation Interrupt source + * @arg TIM_IT_Trigger: TIM Trigger Interrupt source + * @arg TIM_IT_Break: TIM Break Interrupt source + * + * @note TIM6 and TIM7 can generate only an update interrupt. + * @note TIM_IT_COM and TIM_IT_Break are used only with TIM1 and TIM8. + * + * @retval The new state of the TIM_IT(SET or RESET). + */ +ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t TIM_IT) +{ + ITStatus bitstatus = RESET; + uint16_t itstatus = 0x0, itenable = 0x0; + /* Check the parameters */ + assert_param(IS_TIM_ALL_PERIPH(TIMx)); + assert_param(IS_TIM_GET_IT(TIM_IT)); + + itstatus = TIMx->SR & TIM_IT; + + itenable = TIMx->DIER & TIM_IT; + if ((itstatus != (uint16_t)RESET) && (itenable != (uint16_t)RESET)) + { + bitstatus = SET; + } + else + { + bitstatus = RESET; + } + return bitstatus; +} + +/** + * @brief Clears the TIMx's interrupt pending bits. + * @param TIMx: where x can be 1, 2, 3, 4, 6, 7, 8, 15, 16, 20 or 17 to select the TIM peripheral. + * @param TIM_IT: specifies the pending bit to clear. + * This parameter can be any combination of the following values: + * @arg TIM_IT_Update: TIM1 update Interrupt source + * @arg TIM_IT_CC1: TIM Capture Compare 1 Interrupt source + * @arg TIM_IT_CC2: TIM Capture Compare 2 Interrupt source + * @arg TIM_IT_CC3: TIM Capture Compare 3 Interrupt source + * @arg TIM_IT_CC4: TIM Capture Compare 4 Interrupt source + * @arg TIM_IT_COM: TIM Commutation Interrupt source + * @arg TIM_IT_Trigger: TIM Trigger Interrupt source + * @arg TIM_IT_Break: TIM Break Interrupt source + * + * @note TIM6 and TIM7 can generate only an update interrupt. + * @note TIM_IT_COM and TIM_IT_Break are used only with TIM1 and TIM8. + * + * @retval None + */ +void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT) +{ + /* Check the parameters */ + assert_param(IS_TIM_ALL_PERIPH(TIMx)); + + /* Clear the IT pending Bit */ + TIMx->SR = (uint16_t)~TIM_IT; +} + +/** + * @brief Configures the TIMx's DMA interface. + * @param TIMx: where x can be 1, 2, 3, 4, 20 or 8 to select the TIM peripheral. + * @param TIM_DMABase: DMA Base address. + * This parameter can be one of the following values: + * @arg TIM_DMABase_CR1 + * @arg TIM_DMABase_CR2 + * @arg TIM_DMABase_SMCR + * @arg TIM_DMABase_DIER + * @arg TIM1_DMABase_SR + * @arg TIM_DMABase_EGR + * @arg TIM_DMABase_CCMR1 + * @arg TIM_DMABase_CCMR2 + * @arg TIM_DMABase_CCER + * @arg TIM_DMABase_CNT + * @arg TIM_DMABase_PSC + * @arg TIM_DMABase_ARR + * @arg TIM_DMABase_RCR + * @arg TIM_DMABase_CCR1 + * @arg TIM_DMABase_CCR2 + * @arg TIM_DMABase_CCR3 + * @arg TIM_DMABase_CCR4 + * @arg TIM_DMABase_BDTR + * @arg TIM_DMABase_DCR + * @param TIM_DMABurstLength: DMA Burst length. This parameter can be one value + * between: TIM_DMABurstLength_1Transfer and TIM_DMABurstLength_18Transfers. + * @retval None + */ +void TIM_DMAConfig(TIM_TypeDef* TIMx, uint16_t TIM_DMABase, uint16_t TIM_DMABurstLength) +{ + /* Check the parameters */ + assert_param(IS_TIM_LIST1_PERIPH(TIMx)); + assert_param(IS_TIM_DMA_BASE(TIM_DMABase)); + assert_param(IS_TIM_DMA_LENGTH(TIM_DMABurstLength)); + + /* Set the DMA Base and the DMA Burst Length */ + TIMx->DCR = TIM_DMABase | TIM_DMABurstLength; +} + +/** + * @brief Enables or disables the TIMx's DMA Requests. + * @param TIMx: where x can be 1, 2, 3, 4, 6, 7, 8, 15, 16, 20 or 17 to select the TIM peripheral. + * @param TIM_DMASource: specifies the DMA Request sources. + * This parameter can be any combination of the following values: + * @arg TIM_DMA_Update: TIM update Interrupt source + * @arg TIM_DMA_CC1: TIM Capture Compare 1 DMA source + * @arg TIM_DMA_CC2: TIM Capture Compare 2 DMA source + * @arg TIM_DMA_CC3: TIM Capture Compare 3 DMA source + * @arg TIM_DMA_CC4: TIM Capture Compare 4 DMA source + * @arg TIM_DMA_COM: TIM Commutation DMA source + * @arg TIM_DMA_Trigger: TIM Trigger DMA source + * @param NewState: new state of the DMA Request sources. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void TIM_DMACmd(TIM_TypeDef* TIMx, uint16_t TIM_DMASource, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_TIM_ALL_PERIPH(TIMx)); + assert_param(IS_TIM_DMA_SOURCE(TIM_DMASource)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable the DMA sources */ + TIMx->DIER |= TIM_DMASource; + } + else + { + /* Disable the DMA sources */ + TIMx->DIER &= (uint16_t)~TIM_DMASource; + } +} + +/** + * @brief Selects the TIMx peripheral Capture Compare DMA source. + * @param TIMx: where x can be 1, 2, 3, 4, 8, 15, 16, 20 or 17 to select the TIM peripheral. + * @param NewState: new state of the Capture Compare DMA source + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void TIM_SelectCCDMA(TIM_TypeDef* TIMx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_TIM_LIST1_PERIPH(TIMx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Set the CCDS Bit */ + TIMx->CR2 |= TIM_CR2_CCDS; + } + else + { + /* Reset the CCDS Bit */ + TIMx->CR2 &= (uint16_t)~TIM_CR2_CCDS; + } +} +/** + * @} + */ + +/** @defgroup TIM_Group6 Clocks management functions + * @brief Clocks management functions + * +@verbatim + =============================================================================== + ##### Clocks management functions ##### + =============================================================================== + +@endverbatim + * @{ + */ + +/** + * @brief Configures the TIMx internal Clock + * @param TIMx: where x can be 1, 2, 3, 4, 8, 20 or 15 to select the TIM + * peripheral. + * @retval None + */ +void TIM_InternalClockConfig(TIM_TypeDef* TIMx) +{ + /* Check the parameters */ + assert_param(IS_TIM_LIST2_PERIPH(TIMx)); + + /* Disable slave mode to clock the prescaler directly with the internal clock */ + TIMx->SMCR &= (uint16_t)~TIM_SMCR_SMS; +} + +/** + * @brief Configures the TIMx Internal Trigger as External Clock + * @param TIMx: where x can be 1, 2, 3, 4, 8, 20 or 15 to select the TIM + * peripheral. + * @param TIM_InputTriggerSource: Trigger source. + * This parameter can be one of the following values: + * @arg TIM_TS_ITR0: Internal Trigger 0 + * @arg TIM_TS_ITR1: Internal Trigger 1 + * @arg TIM_TS_ITR2: Internal Trigger 2 + * @arg TIM_TS_ITR3: Internal Trigger 3 + * @retval None + */ +void TIM_ITRxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource) +{ + /* Check the parameters */ + assert_param(IS_TIM_LIST2_PERIPH(TIMx)); + assert_param(IS_TIM_INTERNAL_TRIGGER_SELECTION(TIM_InputTriggerSource)); + + /* Select the Internal Trigger */ + TIM_SelectInputTrigger(TIMx, TIM_InputTriggerSource); + + /* Select the External clock mode1 */ + TIMx->SMCR |= TIM_SlaveMode_External1; +} + +/** + * @brief Configures the TIMx Trigger as External Clock + * @param TIMx: where x can be 1, 2, 3, 4, 8, 20 or 15 + * to select the TIM peripheral. + * @param TIM_TIxExternalCLKSource: Trigger source. + * This parameter can be one of the following values: + * @arg TIM_TIxExternalCLK1Source_TI1ED: TI1 Edge Detector + * @arg TIM_TIxExternalCLK1Source_TI1: Filtered Timer Input 1 + * @arg TIM_TIxExternalCLK1Source_TI2: Filtered Timer Input 2 + * @param TIM_ICPolarity: specifies the TIx Polarity. + * This parameter can be one of the following values: + * @arg TIM_ICPolarity_Rising + * @arg TIM_ICPolarity_Falling + * @param ICFilter: specifies the filter value. + * This parameter must be a value between 0x0 and 0xF. + * @retval None + */ +void TIM_TIxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_TIxExternalCLKSource, + uint16_t TIM_ICPolarity, uint16_t ICFilter) +{ + /* Check the parameters */ + assert_param(IS_TIM_LIST2_PERIPH(TIMx)); + assert_param(IS_TIM_IC_POLARITY(TIM_ICPolarity)); + assert_param(IS_TIM_IC_FILTER(ICFilter)); + + /* Configure the Timer Input Clock Source */ + if (TIM_TIxExternalCLKSource == TIM_TIxExternalCLK1Source_TI2) + { + TI2_Config(TIMx, TIM_ICPolarity, TIM_ICSelection_DirectTI, ICFilter); + } + else + { + TI1_Config(TIMx, TIM_ICPolarity, TIM_ICSelection_DirectTI, ICFilter); + } + /* Select the Trigger source */ + TIM_SelectInputTrigger(TIMx, TIM_TIxExternalCLKSource); + /* Select the External clock mode1 */ + TIMx->SMCR |= TIM_SlaveMode_External1; +} + +/** + * @brief Configures the External clock Mode1 + * @param TIMx: where x can be 1, 2, 3, 4, 20 or 8 to select the TIM peripheral. + * @param TIM_ExtTRGPrescaler: The external Trigger Prescaler. + * This parameter can be one of the following values: + * @arg TIM_ExtTRGPSC_OFF: ETRP Prescaler OFF. + * @arg TIM_ExtTRGPSC_DIV2: ETRP frequency divided by 2. + * @arg TIM_ExtTRGPSC_DIV4: ETRP frequency divided by 4. + * @arg TIM_ExtTRGPSC_DIV8: ETRP frequency divided by 8. + * @param TIM_ExtTRGPolarity: The external Trigger Polarity. + * This parameter can be one of the following values: + * @arg TIM_ExtTRGPolarity_Inverted: active low or falling edge active. + * @arg TIM_ExtTRGPolarity_NonInverted: active high or rising edge active. + * @param ExtTRGFilter: External Trigger Filter. + * This parameter must be a value between 0x00 and 0x0F + * @retval None + */ +void TIM_ETRClockMode1Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, + uint16_t TIM_ExtTRGPolarity, uint16_t ExtTRGFilter) +{ + uint16_t tmpsmcr = 0; + + /* Check the parameters */ + assert_param(IS_TIM_LIST3_PERIPH(TIMx)); + assert_param(IS_TIM_EXT_PRESCALER(TIM_ExtTRGPrescaler)); + assert_param(IS_TIM_EXT_POLARITY(TIM_ExtTRGPolarity)); + assert_param(IS_TIM_EXT_FILTER(ExtTRGFilter)); + /* Configure the ETR Clock source */ + TIM_ETRConfig(TIMx, TIM_ExtTRGPrescaler, TIM_ExtTRGPolarity, ExtTRGFilter); + + /* Get the TIMx SMCR register value */ + tmpsmcr = TIMx->SMCR; + + /* Reset the SMS Bits */ + tmpsmcr &= (uint16_t)~TIM_SMCR_SMS; + + /* Select the External clock mode1 */ + tmpsmcr |= TIM_SlaveMode_External1; + + /* Select the Trigger selection : ETRF */ + tmpsmcr &= (uint16_t)~TIM_SMCR_TS; + tmpsmcr |= TIM_TS_ETRF; + + /* Write to TIMx SMCR */ + TIMx->SMCR = tmpsmcr; +} + +/** + * @brief Configures the External clock Mode2 + * @param TIMx: where x can be 1, 2, 3, 4, 20 or 8 to select the TIM peripheral. + * @param TIM_ExtTRGPrescaler: The external Trigger Prescaler. + * This parameter can be one of the following values: + * @arg TIM_ExtTRGPSC_OFF: ETRP Prescaler OFF. + * @arg TIM_ExtTRGPSC_DIV2: ETRP frequency divided by 2. + * @arg TIM_ExtTRGPSC_DIV4: ETRP frequency divided by 4. + * @arg TIM_ExtTRGPSC_DIV8: ETRP frequency divided by 8. + * @param TIM_ExtTRGPolarity: The external Trigger Polarity. + * This parameter can be one of the following values: + * @arg TIM_ExtTRGPolarity_Inverted: active low or falling edge active. + * @arg TIM_ExtTRGPolarity_NonInverted: active high or rising edge active. + * @param ExtTRGFilter: External Trigger Filter. + * This parameter must be a value between 0x00 and 0x0F + * @retval None + */ +void TIM_ETRClockMode2Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, + uint16_t TIM_ExtTRGPolarity, uint16_t ExtTRGFilter) +{ + /* Check the parameters */ + assert_param(IS_TIM_LIST3_PERIPH(TIMx)); + assert_param(IS_TIM_EXT_PRESCALER(TIM_ExtTRGPrescaler)); + assert_param(IS_TIM_EXT_POLARITY(TIM_ExtTRGPolarity)); + assert_param(IS_TIM_EXT_FILTER(ExtTRGFilter)); + + /* Configure the ETR Clock source */ + TIM_ETRConfig(TIMx, TIM_ExtTRGPrescaler, TIM_ExtTRGPolarity, ExtTRGFilter); + + /* Enable the External clock mode2 */ + TIMx->SMCR |= TIM_SMCR_ECE; +} +/** + * @} + */ + +/** @defgroup TIM_Group7 Synchronization management functions + * @brief Synchronization management functions + * +@verbatim + =============================================================================== + ##### Synchronization management functions ##### + =============================================================================== + + *** TIM Driver: how to use it in synchronization Mode *** + ========================================================= + [..] Case of two/several Timers + + (#) Configure the Master Timers using the following functions: + (++) void TIM_SelectOutputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_TRGOSource); + (++) void TIM_SelectMasterSlaveMode(TIM_TypeDef* TIMx, uint16_t TIM_MasterSlaveMode); + (#) Configure the Slave Timers using the following functions: + (++) void TIM_SelectInputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource); + (++) void TIM_SelectSlaveMode(TIM_TypeDef* TIMx, uint16_t TIM_SlaveMode); + + [..] Case of Timers and external trigger(ETR pin) + + (#) Configure the External trigger using this function: + (++) void TIM_ETRConfig(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity, + uint16_t ExtTRGFilter); + (#) Configure the Slave Timers using the following functions: + (++) void TIM_SelectInputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource); + (++) void TIM_SelectSlaveMode(TIM_TypeDef* TIMx, uint16_t TIM_SlaveMode); + +@endverbatim + * @{ + */ + +/** + * @brief Selects the Input Trigger source + * @param TIMx: where x can be 1, 2, 3, 4, 8, 20 or 15 + * to select the TIM peripheral. + * @param TIM_InputTriggerSource: The Input Trigger source. + * This parameter can be one of the following values: + * @arg TIM_TS_ITR0: Internal Trigger 0 + * @arg TIM_TS_ITR1: Internal Trigger 1 + * @arg TIM_TS_ITR2: Internal Trigger 2 + * @arg TIM_TS_ITR3: Internal Trigger 3 + * @arg TIM_TS_TI1F_ED: TI1 Edge Detector + * @arg TIM_TS_TI1FP1: Filtered Timer Input 1 + * @arg TIM_TS_TI2FP2: Filtered Timer Input 2 + * @arg TIM_TS_ETRF: External Trigger input + * @retval None + */ +void TIM_SelectInputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource) +{ + uint16_t tmpsmcr = 0; + + /* Check the parameters */ + assert_param(IS_TIM_LIST2_PERIPH(TIMx)); + assert_param(IS_TIM_TRIGGER_SELECTION(TIM_InputTriggerSource)); + + /* Get the TIMx SMCR register value */ + tmpsmcr = TIMx->SMCR; + + /* Reset the TS Bits */ + tmpsmcr &= (uint16_t)~TIM_SMCR_TS; + + /* Set the Input Trigger source */ + tmpsmcr |= TIM_InputTriggerSource; + + /* Write to TIMx SMCR */ + TIMx->SMCR = tmpsmcr; +} + +/** + * @brief Selects the TIMx Trigger Output Mode. + * @param TIMx: where x can be 1, 2, 3, 4, 5, 6, 7, 8 or 15 to select the TIM peripheral. + * + * @param TIM_TRGOSource: specifies the Trigger Output source. + * This parameter can be one of the following values: + * + * - For all TIMx + * @arg TIM_TRGOSource_Reset: The UG bit in the TIM_EGR register is used as the trigger output(TRGO) + * @arg TIM_TRGOSource_Enable: The Counter Enable CEN is used as the trigger output(TRGO) + * @arg TIM_TRGOSource_Update: The update event is selected as the trigger output(TRGO) + * + * - For all TIMx except TIM6 and TIM7 + * @arg TIM_TRGOSource_OC1: The trigger output sends a positive pulse when the CC1IF flag + * is to be set, as soon as a capture or compare match occurs(TRGO) + * @arg TIM_TRGOSource_OC1Ref: OC1REF signal is used as the trigger output(TRGO) + * @arg TIM_TRGOSource_OC2Ref: OC2REF signal is used as the trigger output(TRGO) + * @arg TIM_TRGOSource_OC3Ref: OC3REF signal is used as the trigger output(TRGO) + * @arg TIM_TRGOSource_OC4Ref: OC4REF signal is used as the trigger output(TRGO) + * + * @retval None + */ +void TIM_SelectOutputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_TRGOSource) +{ + /* Check the parameters */ + assert_param(IS_TIM_LIST7_PERIPH(TIMx)); + assert_param(IS_TIM_TRGO_SOURCE(TIM_TRGOSource)); + + /* Reset the MMS Bits */ + TIMx->CR2 &= (uint16_t)~TIM_CR2_MMS; + /* Select the TRGO source */ + TIMx->CR2 |= TIM_TRGOSource; +} + +/** + * @brief Selects the TIMx Trigger Output Mode2 (TRGO2). + * @param TIMx: where x can be 1 or 8 or 20 to select the TIM peripheral. + * + * @param TIM_TRGO2Source: specifies the Trigger Output source. + * This parameter can be one of the following values: + * + * - For all TIMx + * @arg TIM_TRGOSource_Reset: The UG bit in the TIM_EGR register is used as the trigger output(TRGO2) + * @arg TIM_TRGOSource_Enable: The Counter Enable CEN is used as the trigger output(TRGO2) + * @arg TIM_TRGOSource_Update: The update event is selected as the trigger output(TRGO2) + * @arg TIM_TRGOSource_OC1: The trigger output sends a positive pulse when the CC1IF flag + * is to be set, as soon as a capture or compare match occurs(TRGO2) + * @arg TIM_TRGOSource_OC1Ref: OC1REF signal is used as the trigger output(TRGO2) + * @arg TIM_TRGOSource_OC2Ref: OC2REF signal is used as the trigger output(TRGO2) + * @arg TIM_TRGOSource_OC3Ref: OC3REF signal is used as the trigger output(TRGO2) + * @arg TIM_TRGOSource_OC4Ref: OC4REF signal is used as the trigger output(TRGO2) + * @arg TIM_TRGO2Source_OC4Ref_RisingFalling: OC4Ref Rising and Falling are used as the trigger output(TRGO2) + * @arg TIM_TRGO2Source_OC6Ref_RisingFalling: OC6Ref Rising and Falling are used as the trigger output(TRGO2) + * @arg TIM_TRGO2Source_OC4RefRising_OC6RefRising: OC4Ref Rising and OC6Ref Rising are used as the trigger output(TRGO2) + * @arg TIM_TRGO2Source_OC4RefRising_OC6RefFalling: OC4Ref Rising and OC6Ref Falling are used as the trigger output(TRGO2) + * @arg TIM_TRGO2Source_OC5RefRising_OC6RefRising: OC5Ref Rising and OC6Ref Rising are used as the trigger output(TRGO2) + * @arg TIM_TRGO2Source_OC5RefRising_OC6RefFalling: OC5Ref Rising and OC6Ref Falling are used as the trigger output(TRGO2) + * + * @retval None + */ +void TIM_SelectOutputTrigger2(TIM_TypeDef* TIMx, uint32_t TIM_TRGO2Source) +{ + /* Check the parameters */ + assert_param(IS_TIM_LIST4_PERIPH(TIMx)); + assert_param(IS_TIM_TRGO2_SOURCE(TIM_TRGO2Source)); + + /* Reset the MMS Bits */ + TIMx->CR2 &= (uint32_t)~TIM_CR2_MMS2; + /* Select the TRGO source */ + TIMx->CR2 |= TIM_TRGO2Source; +} + +/** + * @brief Selects the TIMx Slave Mode. + * @param TIMx: where x can be 1, 2, 3, 4, 8, 20 or 15 to select the TIM peripheral. + * @param TIM_SlaveMode: specifies the Timer Slave Mode. + * This parameter can be one of the following values: + * @arg TIM_SlaveMode_Reset: Rising edge of the selected trigger signal(TRGI) reinitialize + * the counter and triggers an update of the registers + * @arg TIM_SlaveMode_Gated: The counter clock is enabled when the trigger signal (TRGI) is high + * @arg TIM_SlaveMode_Trigger: The counter starts at a rising edge of the trigger TRGI + * @arg TIM_SlaveMode_External1: Rising edges of the selected trigger (TRGI) clock the counter + * @arg TIM_SlaveMode_Combined_ResetTrigger: Rising edge of the selected trigger input (TRGI) + * reinitializes the counter, generates an update + * of the registers and starts the counter. + * @retval None + */ +void TIM_SelectSlaveMode(TIM_TypeDef* TIMx, uint32_t TIM_SlaveMode) +{ + /* Check the parameters */ + assert_param(IS_TIM_LIST2_PERIPH(TIMx)); + assert_param(IS_TIM_SLAVE_MODE(TIM_SlaveMode)); + + /* Reset the SMS Bits */ + TIMx->SMCR &= (uint32_t)~TIM_SMCR_SMS; + + /* Select the Slave Mode */ + TIMx->SMCR |= (uint32_t)TIM_SlaveMode; +} + +/** + * @brief Sets or Resets the TIMx Master/Slave Mode. + * @param TIMx: where x can be 1, 2, 3, 4, 8, 20 or 15 to select the TIM peripheral. + * @param TIM_MasterSlaveMode: specifies the Timer Master Slave Mode. + * This parameter can be one of the following values: + * @arg TIM_MasterSlaveMode_Enable: synchronization between the current timer + * and its slaves (through TRGO) + * @arg TIM_MasterSlaveMode_Disable: No action + * @retval None + */ +void TIM_SelectMasterSlaveMode(TIM_TypeDef* TIMx, uint16_t TIM_MasterSlaveMode) +{ + /* Check the parameters */ + assert_param(IS_TIM_LIST2_PERIPH(TIMx)); + assert_param(IS_TIM_MSM_STATE(TIM_MasterSlaveMode)); + + /* Reset the MSM Bit */ + TIMx->SMCR &= (uint16_t)~TIM_SMCR_MSM; + + /* Set or Reset the MSM Bit */ + TIMx->SMCR |= TIM_MasterSlaveMode; +} + +/** + * @brief Configures the TIMx External Trigger (ETR). + * @param TIMx: where x can be 1, 2, 3, 4, 20 or 8 to select the TIM peripheral. + * @param TIM_ExtTRGPrescaler: The external Trigger Prescaler. + * This parameter can be one of the following values: + * @arg TIM_ExtTRGPSC_OFF: ETRP Prescaler OFF. + * @arg TIM_ExtTRGPSC_DIV2: ETRP frequency divided by 2. + * @arg TIM_ExtTRGPSC_DIV4: ETRP frequency divided by 4. + * @arg TIM_ExtTRGPSC_DIV8: ETRP frequency divided by 8. + * @param TIM_ExtTRGPolarity: The external Trigger Polarity. + * This parameter can be one of the following values: + * @arg TIM_ExtTRGPolarity_Inverted: active low or falling edge active. + * @arg TIM_ExtTRGPolarity_NonInverted: active high or rising edge active. + * @param ExtTRGFilter: External Trigger Filter. + * This parameter must be a value between 0x00 and 0x0F + * @retval None + */ +void TIM_ETRConfig(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, + uint16_t TIM_ExtTRGPolarity, uint16_t ExtTRGFilter) +{ + uint16_t tmpsmcr = 0; + + /* Check the parameters */ + assert_param(IS_TIM_LIST3_PERIPH(TIMx)); + assert_param(IS_TIM_EXT_PRESCALER(TIM_ExtTRGPrescaler)); + assert_param(IS_TIM_EXT_POLARITY(TIM_ExtTRGPolarity)); + assert_param(IS_TIM_EXT_FILTER(ExtTRGFilter)); + + tmpsmcr = TIMx->SMCR; + + /* Reset the ETR Bits */ + tmpsmcr &= SMCR_ETR_MASK; + + /* Set the Prescaler, the Filter value and the Polarity */ + tmpsmcr |= (uint16_t)(TIM_ExtTRGPrescaler | (uint16_t)(TIM_ExtTRGPolarity | (uint16_t)(ExtTRGFilter << (uint16_t)8))); + + /* Write to TIMx SMCR */ + TIMx->SMCR = tmpsmcr; +} +/** + * @} + */ + +/** @defgroup TIM_Group8 Specific interface management functions + * @brief Specific interface management functions + * +@verbatim + =============================================================================== + ##### Specific interface management functions ##### + =============================================================================== + +@endverbatim + * @{ + */ + +/** + * @brief Configures the TIMx Encoder Interface. + * @param TIMx: where x can be 1, 2, 3, 4, 20 or 8 to select the TIM + * peripheral. + * @param TIM_EncoderMode: specifies the TIMx Encoder Mode. + * This parameter can be one of the following values: + * @arg TIM_EncoderMode_TI1: Counter counts on TI1FP1 edge depending on TI2FP2 level. + * @arg TIM_EncoderMode_TI2: Counter counts on TI2FP2 edge depending on TI1FP1 level. + * @arg TIM_EncoderMode_TI12: Counter counts on both TI1FP1 and TI2FP2 edges depending + * on the level of the other input. + * @param TIM_IC1Polarity: specifies the IC1 Polarity + * This parameter can be one of the following values: + * @arg TIM_ICPolarity_Falling: IC Falling edge. + * @arg TIM_ICPolarity_Rising: IC Rising edge. + * @param TIM_IC2Polarity: specifies the IC2 Polarity + * This parameter can be one of the following values: + * @arg TIM_ICPolarity_Falling: IC Falling edge. + * @arg TIM_ICPolarity_Rising: IC Rising edge. + * @retval None + */ +void TIM_EncoderInterfaceConfig(TIM_TypeDef* TIMx, uint16_t TIM_EncoderMode, + uint16_t TIM_IC1Polarity, uint16_t TIM_IC2Polarity) +{ + uint16_t tmpsmcr = 0; + uint16_t tmpccmr1 = 0; + uint16_t tmpccer = 0; + + /* Check the parameters */ + assert_param(IS_TIM_LIST3_PERIPH(TIMx)); + assert_param(IS_TIM_ENCODER_MODE(TIM_EncoderMode)); + assert_param(IS_TIM_IC_POLARITY(TIM_IC1Polarity)); + assert_param(IS_TIM_IC_POLARITY(TIM_IC2Polarity)); + + /* Get the TIMx SMCR register value */ + tmpsmcr = TIMx->SMCR; + + /* Get the TIMx CCMR1 register value */ + tmpccmr1 = TIMx->CCMR1; + + /* Get the TIMx CCER register value */ + tmpccer = TIMx->CCER; + + /* Set the encoder Mode */ + tmpsmcr &= (uint16_t)~TIM_SMCR_SMS; + tmpsmcr |= TIM_EncoderMode; + + /* Select the Capture Compare 1 and the Capture Compare 2 as input */ + tmpccmr1 &= ((uint16_t)~TIM_CCMR1_CC1S) & ((uint16_t)~TIM_CCMR1_CC2S); + tmpccmr1 |= TIM_CCMR1_CC1S_0 | TIM_CCMR1_CC2S_0; + + /* Set the TI1 and the TI2 Polarities */ + tmpccer &= ((uint16_t)~TIM_CCER_CC1P) & ((uint16_t)~TIM_CCER_CC2P); + tmpccer |= (uint16_t)(TIM_IC1Polarity | (uint16_t)(TIM_IC2Polarity << (uint16_t)4)); + + /* Write to TIMx SMCR */ + TIMx->SMCR = tmpsmcr; + + /* Write to TIMx CCMR1 */ + TIMx->CCMR1 = tmpccmr1; + + /* Write to TIMx CCER */ + TIMx->CCER = tmpccer; +} + +/** + * @brief Enables or disables the TIMx's Hall sensor interface. + * @param TIMx: where x can be 1, 2, 3, 4, 8, 20 or 15 to select the TIM + * peripheral. + * @param NewState: new state of the TIMx Hall sensor interface. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void TIM_SelectHallSensor(TIM_TypeDef* TIMx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_TIM_LIST2_PERIPH(TIMx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Set the TI1S Bit */ + TIMx->CR2 |= TIM_CR2_TI1S; + } + else + { + /* Reset the TI1S Bit */ + TIMx->CR2 &= (uint16_t)~TIM_CR2_TI1S; + } +} +/** + * @} + */ + +/** @defgroup TIM_Group9 Specific remapping management function + * @brief Specific remapping management function + * +@verbatim + =============================================================================== + ##### Specific remapping management function ##### + =============================================================================== + +@endverbatim + * @{ + */ + +/** + * @brief Configures the TIM16 Remapping input Capabilities. + * @param TIMx: where x can be 1, 8, 20 or 16 to select the TIM peripheral. + * @param TIM_Remap: specifies the TIM input remapping source. + * This parameter can be one of the following values: + * @arg TIM16_GPIO: TIM16 Channel 1 is connected to GPIO. + * @arg TIM16_RTC_CLK: TIM16 Channel 1 is connected to RTC input clock. + * @arg TIM16_HSE_DIV32: TIM16 Channel 1 is connected to HSE/32 clock. + * @arg TIM16_MCO: TIM16 Channel 1 is connected to MCO clock. + * @arg TIM1_ADC1_AWDG1: TIM1 ETR is connected to ADC1 AWDG1. + * @arg TIM1_ADC1_AWDG2: TIM1 ETR is connected to ADC1 AWDG2. + * @arg TIM1_ADC1_AWDG3: TIM1 ETR is connected to ADC1 AWDG3. + * @arg TIM1_ADC4_AWDG1: TIM1 ETR is connected to ADC4 AWDG1. + * @arg TIM1_ADC4_AWDG2: TIM1 ETR is connected to ADC4 AWDG2. + * @arg TIM1_ADC4_AWDG3: TIM1 ETR is connected to ADC4 AWDG3. + * @arg TIM8_ADC2_AWDG1: TIM8 ETR is connected to ADC2 AWDG1. + * @arg TIM8_ADC2_AWDG2: TIM8 ETR is connected to ADC2 AWDG2. + * @arg TIM8_ADC2_AWDG3: TIM8 ETR is connected to ADC2 AWDG3. + * @arg TIM8_ADC4_AWDG1: TIM8 ETR is connected to ADC4 AWDG1. + * @arg TIM8_ADC4_AWDG2: TIM8 ETR is connected to ADC4 AWDG2. + * @arg TIM8_ADC4_AWDG3: TIM8 ETR is connected to ADC4 AWDG3. + * @arg TIM20_ADC3_AWDG1: TIM20 ETR is connected to ADC3 AWDG1. + * @arg TIM20_ADC3_AWDG2: TIM20 ETR is connected to ADC3 AWDG2. + * @arg TIM20_ADC3_AWDG3: TIM20 ETR is connected to ADC3 AWDG3. + * @arg TIM20_ADC4_AWDG1: TIM20 ETR is connected to ADC4 AWDG1. + * @arg TIM20_ADC4_AWDG2: TIM20 ETR is connected to ADC4 AWDG2. + * @arg TIM20_ADC4_AWDG3: TIM20 ETR is connected to ADC4 AWDG3. + * @retval : None + */ +void TIM_RemapConfig(TIM_TypeDef* TIMx, uint16_t TIM_Remap) +{ + /* Check the parameters */ + assert_param(IS_TIM_LIST8_PERIPH(TIMx)); + assert_param(IS_TIM_REMAP(TIM_Remap)); + + /* Set the Timer remapping configuration */ + TIMx->OR = TIM_Remap; +} +/** + * @} + */ + +/** + * @brief Configure the TI1 as Input. + * @param TIMx: where x can be 1, 2, 3, 4, 5, 8, 9, 10, 11, 12, 13 or 14 + * to select the TIM peripheral. + * @param TIM_ICPolarity : The Input Polarity. + * This parameter can be one of the following values: + * @arg TIM_ICPolarity_Rising + * @arg TIM_ICPolarity_Falling + * @arg TIM_ICPolarity_BothEdge + * @param TIM_ICSelection: specifies the input to be used. + * This parameter can be one of the following values: + * @arg TIM_ICSelection_DirectTI: TIM Input 1 is selected to be connected to IC1. + * @arg TIM_ICSelection_IndirectTI: TIM Input 1 is selected to be connected to IC2. + * @arg TIM_ICSelection_TRC: TIM Input 1 is selected to be connected to TRC. + * @param TIM_ICFilter: Specifies the Input Capture Filter. + * This parameter must be a value between 0x00 and 0x0F. + * @retval None + */ +static void TI1_Config(TIM_TypeDef* TIMx, uint16_t TIM_ICPolarity, uint16_t TIM_ICSelection, + uint16_t TIM_ICFilter) +{ + uint32_t tmpccmr1 = 0, tmpccer = 0; + + /* Disable the Channel 1: Reset the CC1E Bit */ + TIMx->CCER &= (uint32_t)~TIM_CCER_CC1E; + tmpccmr1 = TIMx->CCMR1; + tmpccer = TIMx->CCER; + + /* Select the Input and set the filter */ + tmpccmr1 &= ((uint32_t)~TIM_CCMR1_CC1S) & ((uint32_t)~TIM_CCMR1_IC1F); + tmpccmr1 |= (uint32_t)(TIM_ICSelection | (uint32_t)((uint32_t)TIM_ICFilter << 4)); + + /* Select the Polarity and set the CC1E Bit */ + tmpccer &= (uint32_t)~(TIM_CCER_CC1P | TIM_CCER_CC1NP); + tmpccer |= (uint32_t)(TIM_ICPolarity | (uint32_t)TIM_CCER_CC1E); + + /* Write to TIMx CCMR1 and CCER registers */ + TIMx->CCMR1 = tmpccmr1; + TIMx->CCER = tmpccer; +} + +/** + * @brief Configure the TI2 as Input. + * @param TIMx: where x can be 1, 2, 3, 4, 5, 8, 9 or 12 to select the TIM + * peripheral. + * @param TIM_ICPolarity : The Input Polarity. + * This parameter can be one of the following values: + * @arg TIM_ICPolarity_Rising + * @arg TIM_ICPolarity_Falling + * @arg TIM_ICPolarity_BothEdge + * @param TIM_ICSelection: specifies the input to be used. + * This parameter can be one of the following values: + * @arg TIM_ICSelection_DirectTI: TIM Input 2 is selected to be connected to IC2. + * @arg TIM_ICSelection_IndirectTI: TIM Input 2 is selected to be connected to IC1. + * @arg TIM_ICSelection_TRC: TIM Input 2 is selected to be connected to TRC. + * @param TIM_ICFilter: Specifies the Input Capture Filter. + * This parameter must be a value between 0x00 and 0x0F. + * @retval None + */ +static void TI2_Config(TIM_TypeDef* TIMx, uint16_t TIM_ICPolarity, uint16_t TIM_ICSelection, + uint16_t TIM_ICFilter) +{ + uint32_t tmpccmr1 = 0, tmpccer = 0, tmp = 0; + + /* Disable the Channel 2: Reset the CC2E Bit */ + TIMx->CCER &= (uint16_t)~TIM_CCER_CC2E; + tmpccmr1 = TIMx->CCMR1; + tmpccer = TIMx->CCER; + tmp = (uint16_t)(TIM_ICPolarity << 4); + + /* Select the Input and set the filter */ + tmpccmr1 &= ((uint32_t)~TIM_CCMR1_CC2S) & ((uint32_t)~TIM_CCMR1_IC2F); + tmpccmr1 |= (uint32_t)((uint32_t)TIM_ICFilter << 12); + tmpccmr1 |= (uint32_t)((uint32_t)TIM_ICSelection << 8); + + /* Select the Polarity and set the CC2E Bit */ + tmpccer &= (uint16_t)~(TIM_CCER_CC2P | TIM_CCER_CC2NP); + tmpccer |= (uint16_t)(tmp | (uint16_t)TIM_CCER_CC2E); + + /* Write to TIMx CCMR1 and CCER registers */ + TIMx->CCMR1 = tmpccmr1 ; + TIMx->CCER = tmpccer; +} + +/** + * @brief Configure the TI3 as Input. + * @param TIMx: where x can be 1, 2, 3, 4, 5 or 8 to select the TIM peripheral. + * @param TIM_ICPolarity : The Input Polarity. + * This parameter can be one of the following values: + * @arg TIM_ICPolarity_Rising + * @arg TIM_ICPolarity_Falling + * @arg TIM_ICPolarity_BothEdge + * @param TIM_ICSelection: specifies the input to be used. + * This parameter can be one of the following values: + * @arg TIM_ICSelection_DirectTI: TIM Input 3 is selected to be connected to IC3. + * @arg TIM_ICSelection_IndirectTI: TIM Input 3 is selected to be connected to IC4. + * @arg TIM_ICSelection_TRC: TIM Input 3 is selected to be connected to TRC. + * @param TIM_ICFilter: Specifies the Input Capture Filter. + * This parameter must be a value between 0x00 and 0x0F. + * @retval None + */ +static void TI3_Config(TIM_TypeDef* TIMx, uint16_t TIM_ICPolarity, uint16_t TIM_ICSelection, + uint16_t TIM_ICFilter) +{ + uint16_t tmpccmr2 = 0, tmpccer = 0, tmp = 0; + + /* Disable the Channel 3: Reset the CC3E Bit */ + TIMx->CCER &= (uint16_t)~TIM_CCER_CC3E; + tmpccmr2 = TIMx->CCMR2; + tmpccer = TIMx->CCER; + tmp = (uint16_t)(TIM_ICPolarity << 8); + + /* Select the Input and set the filter */ + tmpccmr2 &= ((uint16_t)~TIM_CCMR1_CC1S) & ((uint16_t)~TIM_CCMR2_IC3F); + tmpccmr2 |= (uint16_t)(TIM_ICSelection | (uint16_t)(TIM_ICFilter << (uint16_t)4)); + + /* Select the Polarity and set the CC3E Bit */ + tmpccer &= (uint16_t)~(TIM_CCER_CC3P | TIM_CCER_CC3NP); + tmpccer |= (uint16_t)(tmp | (uint16_t)TIM_CCER_CC3E); + + /* Write to TIMx CCMR2 and CCER registers */ + TIMx->CCMR2 = tmpccmr2; + TIMx->CCER = tmpccer; +} + +/** + * @brief Configure the TI4 as Input. + * @param TIMx: where x can be 1, 2, 3, 4, 5 or 8 to select the TIM peripheral. + * @param TIM_ICPolarity : The Input Polarity. + * This parameter can be one of the following values: + * @arg TIM_ICPolarity_Rising + * @arg TIM_ICPolarity_Falling + * @arg TIM_ICPolarity_BothEdge + * @param TIM_ICSelection: specifies the input to be used. + * This parameter can be one of the following values: + * @arg TIM_ICSelection_DirectTI: TIM Input 4 is selected to be connected to IC4. + * @arg TIM_ICSelection_IndirectTI: TIM Input 4 is selected to be connected to IC3. + * @arg TIM_ICSelection_TRC: TIM Input 4 is selected to be connected to TRC. + * @param TIM_ICFilter: Specifies the Input Capture Filter. + * This parameter must be a value between 0x00 and 0x0F. + * @retval None + */ +static void TI4_Config(TIM_TypeDef* TIMx, uint16_t TIM_ICPolarity, uint16_t TIM_ICSelection, + uint16_t TIM_ICFilter) +{ + uint16_t tmpccmr2 = 0, tmpccer = 0, tmp = 0; + + /* Disable the Channel 4: Reset the CC4E Bit */ + TIMx->CCER &= (uint16_t)~TIM_CCER_CC4E; + tmpccmr2 = TIMx->CCMR2; + tmpccer = TIMx->CCER; + tmp = (uint16_t)(TIM_ICPolarity << 12); + + /* Select the Input and set the filter */ + tmpccmr2 &= ((uint16_t)~TIM_CCMR1_CC2S) & ((uint16_t)~TIM_CCMR1_IC2F); + tmpccmr2 |= (uint16_t)(TIM_ICSelection << 8); + tmpccmr2 |= (uint16_t)(TIM_ICFilter << 12); + + /* Select the Polarity and set the CC4E Bit */ + tmpccer &= (uint16_t)~(TIM_CCER_CC4P | TIM_CCER_CC4NP); + tmpccer |= (uint16_t)(tmp | (uint16_t)TIM_CCER_CC4E); + + /* Write to TIMx CCMR2 and CCER registers */ + TIMx->CCMR2 = tmpccmr2; + TIMx->CCER = tmpccer ; +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_usart.c b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_usart.c new file mode 100755 index 0000000000..8955c8d157 --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_usart.c @@ -0,0 +1,2084 @@ +/** + ****************************************************************************** + * @file stm32f30x_usart.c + * @author MCD Application Team + * @version V1.2.3 + * @date 10-July-2015 + * @brief This file provides firmware functions to manage the following + * functionalities of the Universal synchronous asynchronous receiver + * transmitter (USART): + * + Initialization and Configuration + * + STOP Mode + * + AutoBaudRate + * + Data transfers + * + Multi-Processor Communication + * + LIN mode + * + Half-duplex mode + * + Smartcard mode + * + IrDA mode + * + RS485 mode + * + DMA transfers management + * + Interrupts and flags management + * + * @verbatim + =============================================================================== + ##### How to use this driver ##### + =============================================================================== + [..] + (#) Enable peripheral clock using RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE) + function for USART1 or using RCC_APB1PeriphClockCmd(RCC_APB1Periph_USARTx, ENABLE) + function for USART2, USART3, UART4 and UART5. + (#) According to the USART mode, enable the GPIO clocks using + RCC_AHBPeriphClockCmd() function. (The I/O can be TX, RX, CTS, + or and SCLK). + (#) Peripheral's alternate function: + (++) Connect the pin to the desired peripherals' Alternate + Function (AF) using GPIO_PinAFConfig() function. + (++) Configure the desired pin in alternate function by: + GPIO_InitStruct->GPIO_Mode = GPIO_Mode_AF. + (++) Select the type, pull-up/pull-down and output speed via + GPIO_PuPd, GPIO_OType and GPIO_Speed members. + (++) Call GPIO_Init() function. + (#) Program the Baud Rate, Word Length , Stop Bit, Parity, Hardware + flow control and Mode(Receiver/Transmitter) using the SPI_Init() + function. + (#) For synchronous mode, enable the clock and program the polarity, + phase and last bit using the USART_ClockInit() function. + (#) Enable the USART using the USART_Cmd() function. + (#) Enable the NVIC and the corresponding interrupt using the function + USART_ITConfig() if you need to use interrupt mode. + (#) When using the DMA mode: + (++) Configure the DMA using DMA_Init() function. + (++) Activate the needed channel Request using USART_DMACmd() function. + (#) Enable the DMA using the DMA_Cmd() function, when using DMA mode. + [..] + Refer to Multi-Processor, LIN, half-duplex, Smartcard, IrDA sub-sections + for more details. + + @endverbatim + + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f30x_usart.h" +#include "stm32f30x_rcc.h" + +/** @addtogroup STM32F30x_StdPeriph_Driver + * @{ + */ + +/** @defgroup USART + * @brief USART driver modules + * @{ + */ + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ + +/*!< USART CR1 register clear Mask ((~(uint32_t)0xFFFFE6F3)) */ +#define CR1_CLEAR_MASK ((uint32_t)(USART_CR1_M | USART_CR1_PCE | \ + USART_CR1_PS | USART_CR1_TE | \ + USART_CR1_RE)) + +/*!< USART CR2 register clock bits clear Mask ((~(uint32_t)0xFFFFF0FF)) */ +#define CR2_CLOCK_CLEAR_MASK ((uint32_t)(USART_CR2_CLKEN | USART_CR2_CPOL | \ + USART_CR2_CPHA | USART_CR2_LBCL)) + +/*!< USART CR3 register clear Mask ((~(uint32_t)0xFFFFFCFF)) */ +#define CR3_CLEAR_MASK ((uint32_t)(USART_CR3_RTSE | USART_CR3_CTSE)) + +/*!< USART Interrupts mask */ +#define IT_MASK ((uint32_t)0x000000FF) + +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/* Private function prototypes -----------------------------------------------*/ +/* Private functions ---------------------------------------------------------*/ + +/** @defgroup USART_Private_Functions + * @{ + */ + +/** @defgroup USART_Group1 Initialization and Configuration functions + * @brief Initialization and Configuration functions + * +@verbatim + =============================================================================== + ##### Initialization and Configuration functions ##### + =============================================================================== + [..] + This subsection provides a set of functions allowing to initialize the USART + in asynchronous and in synchronous modes. + (+) For the asynchronous mode only these parameters can be configured: + (++) Baud Rate. + (++) Word Length. + (++) Stop Bit. + (++) Parity: If the parity is enabled, then the MSB bit of the data written + in the data register is transmitted but is changed by the parity bit. + Depending on the frame length defined by the M bit (8-bits or 9-bits), + the possible USART frame formats are as listed in the following table: + [..] + +-------------------------------------------------------------+ + | M bit | PCE bit | USART frame | + |---------------------|---------------------------------------| + | 0 | 0 | | SB | 8 bit data | STB | | + |---------|-----------|---------------------------------------| + | 0 | 1 | | SB | 7 bit data | PB | STB | | + |---------|-----------|---------------------------------------| + | 1 | 0 | | SB | 9 bit data | STB | | + |---------|-----------|---------------------------------------| + | 1 | 1 | | SB | 8 bit data | PB | STB | | + +-------------------------------------------------------------+ + [..] + (++) Hardware flow control. + (++) Receiver/transmitter modes. + [..] The USART_Init() function follows the USART asynchronous configuration + procedure(details for the procedure are available in reference manual. + (+) For the synchronous mode in addition to the asynchronous mode parameters + these parameters should be also configured: + (++) USART Clock Enabled. + (++) USART polarity. + (++) USART phase. + (++) USART LastBit. + [..] These parameters can be configured using the USART_ClockInit() function. + +@endverbatim + * @{ + */ + +/** + * @brief Deinitializes the USARTx peripheral registers to their default reset values. + * @param USARTx: Select the USART peripheral. This parameter can be one of the + * following values: USART1 or USART2 or USART3 or UART4 or UART5. + * @retval None + */ +void USART_DeInit(USART_TypeDef* USARTx) +{ + /* Check the parameters */ + assert_param(IS_USART_ALL_PERIPH(USARTx)); + + if (USARTx == USART1) + { + RCC_APB2PeriphResetCmd(RCC_APB2Periph_USART1, ENABLE); + RCC_APB2PeriphResetCmd(RCC_APB2Periph_USART1, DISABLE); + } + else if (USARTx == USART2) + { + RCC_APB1PeriphResetCmd(RCC_APB1Periph_USART2, ENABLE); + RCC_APB1PeriphResetCmd(RCC_APB1Periph_USART2, DISABLE); + } + else if (USARTx == USART3) + { + RCC_APB1PeriphResetCmd(RCC_APB1Periph_USART3, ENABLE); + RCC_APB1PeriphResetCmd(RCC_APB1Periph_USART3, DISABLE); + } + else if (USARTx == UART4) + { + RCC_APB1PeriphResetCmd(RCC_APB1Periph_UART4, ENABLE); + RCC_APB1PeriphResetCmd(RCC_APB1Periph_UART4, DISABLE); + } + else + { + if (USARTx == UART5) + { + RCC_APB1PeriphResetCmd(RCC_APB1Periph_UART5, ENABLE); + RCC_APB1PeriphResetCmd(RCC_APB1Periph_UART5, DISABLE); + } + } +} + +/** + * @brief Initializes the USARTx peripheral according to the specified + * parameters in the USART_InitStruct . + * @param USARTx: Select the USART peripheral. This parameter can be one of the + * following values: USART1 or USART2 or USART3 or UART4 or UART5. + * @param USART_InitStruct: pointer to a USART_InitTypeDef structure + * that contains the configuration information for the specified USART peripheral. + * @retval None + */ +void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct) +{ + uint32_t divider = 0, apbclock = 0, tmpreg = 0; + RCC_ClocksTypeDef RCC_ClocksStatus; + + /* Check the parameters */ + assert_param(IS_USART_ALL_PERIPH(USARTx)); + assert_param(IS_USART_BAUDRATE(USART_InitStruct->USART_BaudRate)); + assert_param(IS_USART_WORD_LENGTH(USART_InitStruct->USART_WordLength)); + assert_param(IS_USART_STOPBITS(USART_InitStruct->USART_StopBits)); + assert_param(IS_USART_PARITY(USART_InitStruct->USART_Parity)); + assert_param(IS_USART_MODE(USART_InitStruct->USART_Mode)); + assert_param(IS_USART_HARDWARE_FLOW_CONTROL(USART_InitStruct->USART_HardwareFlowControl)); + + /* Disable USART */ + USARTx->CR1 &= (uint32_t)~((uint32_t)USART_CR1_UE); + + /*---------------------------- USART CR2 Configuration -----------------------*/ + tmpreg = USARTx->CR2; + /* Clear STOP[13:12] bits */ + tmpreg &= (uint32_t)~((uint32_t)USART_CR2_STOP); + + /* Configure the USART Stop Bits, Clock, CPOL, CPHA and LastBit ------------*/ + /* Set STOP[13:12] bits according to USART_StopBits value */ + tmpreg |= (uint32_t)USART_InitStruct->USART_StopBits; + + /* Write to USART CR2 */ + USARTx->CR2 = tmpreg; + + /*---------------------------- USART CR1 Configuration -----------------------*/ + tmpreg = USARTx->CR1; + /* Clear M, PCE, PS, TE and RE bits */ + tmpreg &= (uint32_t)~((uint32_t)CR1_CLEAR_MASK); + + /* Configure the USART Word Length, Parity and mode ----------------------- */ + /* Set the M bits according to USART_WordLength value */ + /* Set PCE and PS bits according to USART_Parity value */ + /* Set TE and RE bits according to USART_Mode value */ + tmpreg |= (uint32_t)USART_InitStruct->USART_WordLength | USART_InitStruct->USART_Parity | + USART_InitStruct->USART_Mode; + + /* Write to USART CR1 */ + USARTx->CR1 = tmpreg; + + /*---------------------------- USART CR3 Configuration -----------------------*/ + tmpreg = USARTx->CR3; + /* Clear CTSE and RTSE bits */ + tmpreg &= (uint32_t)~((uint32_t)CR3_CLEAR_MASK); + + /* Configure the USART HFC -------------------------------------------------*/ + /* Set CTSE and RTSE bits according to USART_HardwareFlowControl value */ + tmpreg |= USART_InitStruct->USART_HardwareFlowControl; + + /* Write to USART CR3 */ + USARTx->CR3 = tmpreg; + + /*---------------------------- USART BRR Configuration -----------------------*/ + /* Configure the USART Baud Rate -------------------------------------------*/ + RCC_GetClocksFreq(&RCC_ClocksStatus); + + if (USARTx == USART1) + { + apbclock = RCC_ClocksStatus.USART1CLK_Frequency; + } + else if (USARTx == USART2) + { + apbclock = RCC_ClocksStatus.USART2CLK_Frequency; + } + else if (USARTx == USART3) + { + apbclock = RCC_ClocksStatus.USART3CLK_Frequency; + } + else if (USARTx == UART4) + { + apbclock = RCC_ClocksStatus.UART4CLK_Frequency; + } + else + { + apbclock = RCC_ClocksStatus.UART5CLK_Frequency; + } + + /* Determine the integer part */ + if ((USARTx->CR1 & USART_CR1_OVER8) != 0) + { + /* (divider * 10) computing in case Oversampling mode is 8 Samples */ + divider = (uint32_t)((2 * apbclock) / (USART_InitStruct->USART_BaudRate)); + tmpreg = (uint32_t)((2 * apbclock) % (USART_InitStruct->USART_BaudRate)); + } + else /* if ((USARTx->CR1 & CR1_OVER8_Set) == 0) */ + { + /* (divider * 10) computing in case Oversampling mode is 16 Samples */ + divider = (uint32_t)((apbclock) / (USART_InitStruct->USART_BaudRate)); + tmpreg = (uint32_t)((apbclock) % (USART_InitStruct->USART_BaudRate)); + } + + /* round the divider : if fractional part i greater than 0.5 increment divider */ + if (tmpreg >= (USART_InitStruct->USART_BaudRate) / 2) + { + divider++; + } + + /* Implement the divider in case Oversampling mode is 8 Samples */ + if ((USARTx->CR1 & USART_CR1_OVER8) != 0) + { + /* get the LSB of divider and shift it to the right by 1 bit */ + tmpreg = (divider & (uint16_t)0x000F) >> 1; + + /* update the divider value */ + divider = (divider & (uint16_t)0xFFF0) | tmpreg; + } + + /* Write to USART BRR */ + USARTx->BRR = (uint16_t)divider; +} + +/** + * @brief Fills each USART_InitStruct member with its default value. + * @param USART_InitStruct: pointer to a USART_InitTypeDef structure + * which will be initialized. + * @retval None + */ +void USART_StructInit(USART_InitTypeDef* USART_InitStruct) +{ + /* USART_InitStruct members default value */ + USART_InitStruct->USART_BaudRate = 9600; + USART_InitStruct->USART_WordLength = USART_WordLength_8b; + USART_InitStruct->USART_StopBits = USART_StopBits_1; + USART_InitStruct->USART_Parity = USART_Parity_No ; + USART_InitStruct->USART_Mode = USART_Mode_Rx | USART_Mode_Tx; + USART_InitStruct->USART_HardwareFlowControl = USART_HardwareFlowControl_None; +} + +/** + * @brief Initializes the USARTx peripheral Clock according to the + * specified parameters in the USART_ClockInitStruct. + * @param USARTx: Select the USART peripheral. This parameter can be one of the + * following values: USART1 or USART2 or USART3. + * @param USART_ClockInitStruct: pointer to a USART_ClockInitTypeDef + * structure that contains the configuration information for the specified + * USART peripheral. + * @retval None + */ +void USART_ClockInit(USART_TypeDef* USARTx, USART_ClockInitTypeDef* USART_ClockInitStruct) +{ + uint32_t tmpreg = 0; + /* Check the parameters */ + assert_param(IS_USART_123_PERIPH(USARTx)); + assert_param(IS_USART_CLOCK(USART_ClockInitStruct->USART_Clock)); + assert_param(IS_USART_CPOL(USART_ClockInitStruct->USART_CPOL)); + assert_param(IS_USART_CPHA(USART_ClockInitStruct->USART_CPHA)); + assert_param(IS_USART_LASTBIT(USART_ClockInitStruct->USART_LastBit)); +/*---------------------------- USART CR2 Configuration -----------------------*/ + tmpreg = USARTx->CR2; + /* Clear CLKEN, CPOL, CPHA, LBCL and SSM bits */ + tmpreg &= (uint32_t)~((uint32_t)CR2_CLOCK_CLEAR_MASK); + /* Configure the USART Clock, CPOL, CPHA, LastBit and SSM ------------*/ + /* Set CLKEN bit according to USART_Clock value */ + /* Set CPOL bit according to USART_CPOL value */ + /* Set CPHA bit according to USART_CPHA value */ + /* Set LBCL bit according to USART_LastBit value */ + tmpreg |= (uint32_t)(USART_ClockInitStruct->USART_Clock | USART_ClockInitStruct->USART_CPOL | + USART_ClockInitStruct->USART_CPHA | USART_ClockInitStruct->USART_LastBit); + /* Write to USART CR2 */ + USARTx->CR2 = tmpreg; +} + +/** + * @brief Fills each USART_ClockInitStruct member with its default value. + * @param USART_ClockInitStruct: pointer to a USART_ClockInitTypeDef + * structure which will be initialized. + * @retval None + */ +void USART_ClockStructInit(USART_ClockInitTypeDef* USART_ClockInitStruct) +{ + /* USART_ClockInitStruct members default value */ + USART_ClockInitStruct->USART_Clock = USART_Clock_Disable; + USART_ClockInitStruct->USART_CPOL = USART_CPOL_Low; + USART_ClockInitStruct->USART_CPHA = USART_CPHA_1Edge; + USART_ClockInitStruct->USART_LastBit = USART_LastBit_Disable; +} + +/** + * @brief Enables or disables the specified USART peripheral. + * @param USARTx: Select the USART peripheral. This parameter can be one of the + * following values: USART1 or USART2 or USART3 or UART4 or UART5. + * @param NewState: new state of the USARTx peripheral. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void USART_Cmd(USART_TypeDef* USARTx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_USART_ALL_PERIPH(USARTx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable the selected USART by setting the UE bit in the CR1 register */ + USARTx->CR1 |= USART_CR1_UE; + } + else + { + /* Disable the selected USART by clearing the UE bit in the CR1 register */ + USARTx->CR1 &= (uint32_t)~((uint32_t)USART_CR1_UE); + } +} + +/** + * @brief Enables or disables the USART's transmitter or receiver. + * @param USARTx: Select the USART peripheral. This parameter can be one of the + * following values: USART1 or USART2 or USART3 or UART4 or UART5. + * @param USART_Direction: specifies the USART direction. + * This parameter can be any combination of the following values: + * @arg USART_Mode_Tx: USART Transmitter + * @arg USART_Mode_Rx: USART Receiver + * @param NewState: new state of the USART transfer direction. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void USART_DirectionModeCmd(USART_TypeDef* USARTx, uint32_t USART_DirectionMode, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_USART_ALL_PERIPH(USARTx)); + assert_param(IS_USART_MODE(USART_DirectionMode)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable the USART's transfer interface by setting the TE and/or RE bits + in the USART CR1 register */ + USARTx->CR1 |= USART_DirectionMode; + } + else + { + /* Disable the USART's transfer interface by clearing the TE and/or RE bits + in the USART CR3 register */ + USARTx->CR1 &= (uint32_t)~USART_DirectionMode; + } +} + +/** + * @brief Enables or disables the USART's 8x oversampling mode. + * @param USARTx: Select the USART peripheral. This parameter can be one of the + * following values: USART1 or USART2 or USART3 or UART4 or UART5. + * @param NewState: new state of the USART 8x oversampling mode. + * This parameter can be: ENABLE or DISABLE. + * @note + * This function has to be called before calling USART_Init() + * function in order to have correct baudrate Divider value. + * @retval None + */ +void USART_OverSampling8Cmd(USART_TypeDef* USARTx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_USART_ALL_PERIPH(USARTx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable the 8x Oversampling mode by setting the OVER8 bit in the CR1 register */ + USARTx->CR1 |= USART_CR1_OVER8; + } + else + { + /* Disable the 8x Oversampling mode by clearing the OVER8 bit in the CR1 register */ + USARTx->CR1 &= (uint32_t)~((uint32_t)USART_CR1_OVER8); + } +} + +/** + * @brief Enables or disables the USART's one bit sampling method. + * @param USARTx: Select the USART peripheral. This parameter can be one of the + * following values: USART1 or USART2 or USART3 or UART4 or UART5. + * @param NewState: new state of the USART one bit sampling method. + * This parameter can be: ENABLE or DISABLE. + * @note + * This function has to be called before calling USART_Cmd() function. + * @retval None + */ +void USART_OneBitMethodCmd(USART_TypeDef* USARTx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_USART_ALL_PERIPH(USARTx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable the one bit method by setting the ONEBIT bit in the CR3 register */ + USARTx->CR3 |= USART_CR3_ONEBIT; + } + else + { + /* Disable the one bit method by clearing the ONEBIT bit in the CR3 register */ + USARTx->CR3 &= (uint32_t)~((uint32_t)USART_CR3_ONEBIT); + } +} + +/** + * @brief Enables or disables the USART's most significant bit first + * transmitted/received following the start bit. + * @param USARTx: Select the USART peripheral. This parameter can be one of the + * following values: USART1 or USART2 or USART3 or UART4 or UART5. + * @param NewState: new state of the USART most significant bit first + * transmitted/received following the start bit. + * This parameter can be: ENABLE or DISABLE. + * @note + * This function has to be called before calling USART_Cmd() function. + * @retval None + */ +void USART_MSBFirstCmd(USART_TypeDef* USARTx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_USART_ALL_PERIPH(USARTx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable the most significant bit first transmitted/received following the + start bit by setting the MSBFIRST bit in the CR2 register */ + USARTx->CR2 |= USART_CR2_MSBFIRST; + } + else + { + /* Disable the most significant bit first transmitted/received following the + start bit by clearing the MSBFIRST bit in the CR2 register */ + USARTx->CR2 &= (uint32_t)~((uint32_t)USART_CR2_MSBFIRST); + } +} + +/** + * @brief Enables or disables the binary data inversion. + * @param USARTx: Select the USART peripheral. This parameter can be one of the + * following values: USART1 or USART2 or USART3 or UART4 or UART5. + * @param NewState: new defined levels for the USART data. + * This parameter can be: ENABLE or DISABLE. + * @arg ENABLE: Logical data from the data register are send/received in negative + * logic. (1=L, 0=H). The parity bit is also inverted. + * @arg DISABLE: Logical data from the data register are send/received in positive + * logic. (1=H, 0=L) + * @note + * This function has to be called before calling USART_Cmd() function. + * @retval None + */ +void USART_DataInvCmd(USART_TypeDef* USARTx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_USART_ALL_PERIPH(USARTx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable the binary data inversion feature by setting the DATAINV bit in + the CR2 register */ + USARTx->CR2 |= USART_CR2_DATAINV; + } + else + { + /* Disable the binary data inversion feature by clearing the DATAINV bit in + the CR2 register */ + USARTx->CR2 &= (uint32_t)~((uint32_t)USART_CR2_DATAINV); + } +} + +/** + * @brief Enables or disables the Pin(s) active level inversion. + * @param USARTx: Select the USART peripheral. This parameter can be one of the + * following values: USART1 or USART2 or USART3 or UART4 or UART5. + * @param USART_InvPin: specifies the USART pin(s) to invert. + * This parameter can be any combination of the following values: + * @arg USART_InvPin_Tx: USART Tx pin active level inversion. + * @arg USART_InvPin_Rx: USART Rx pin active level inversion. + * @param NewState: new active level status for the USART pin(s). + * This parameter can be: ENABLE or DISABLE. + * - ENABLE: pin(s) signal values are inverted (Vdd =0, Gnd =1). + * - DISABLE: pin(s) signal works using the standard logic levels (Vdd =1, Gnd =0). + * @note + * This function has to be called before calling USART_Cmd() function. + * @retval None + */ +void USART_InvPinCmd(USART_TypeDef* USARTx, uint32_t USART_InvPin, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_USART_ALL_PERIPH(USARTx)); + assert_param(IS_USART_INVERSTION_PIN(USART_InvPin)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable the active level inversion for selected pins by setting the TXINV + and/or RXINV bits in the USART CR2 register */ + USARTx->CR2 |= USART_InvPin; + } + else + { + /* Disable the active level inversion for selected requests by clearing the + TXINV and/or RXINV bits in the USART CR2 register */ + USARTx->CR2 &= (uint32_t)~USART_InvPin; + } +} + +/** + * @brief Enables or disables the swap Tx/Rx pins. + * @param USARTx: Select the USART peripheral. This parameter can be one of the + * following values: USART1 or USART2 or USART3 or UART4 or UART5. + * @param NewState: new state of the USARTx TX/RX pins pinout. + * This parameter can be: ENABLE or DISABLE. + * @arg ENABLE: The TX and RX pins functions are swapped. + * @arg DISABLE: TX/RX pins are used as defined in standard pinout + * @note + * This function has to be called before calling USART_Cmd() function. + * @retval None + */ +void USART_SWAPPinCmd(USART_TypeDef* USARTx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_USART_ALL_PERIPH(USARTx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable the SWAP feature by setting the SWAP bit in the CR2 register */ + USARTx->CR2 |= USART_CR2_SWAP; + } + else + { + /* Disable the SWAP feature by clearing the SWAP bit in the CR2 register */ + USARTx->CR2 &= (uint32_t)~((uint32_t)USART_CR2_SWAP); + } +} + +/** + * @brief Enables or disables the receiver Time Out feature. + * @param USARTx: Select the USART peripheral. This parameter can be one of the + * following values: USART1 or USART2 or USART3 or UART4 or UART5. + * @param NewState: new state of the USARTx receiver Time Out. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void USART_ReceiverTimeOutCmd(USART_TypeDef* USARTx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_USART_ALL_PERIPH(USARTx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable the receiver time out feature by setting the RTOEN bit in the CR2 + register */ + USARTx->CR2 |= USART_CR2_RTOEN; + } + else + { + /* Disable the receiver time out feature by clearing the RTOEN bit in the CR2 + register */ + USARTx->CR2 &= (uint32_t)~((uint32_t)USART_CR2_RTOEN); + } +} + +/** + * @brief Sets the receiver Time Out value. + * @param USARTx: Select the USART peripheral. This parameter can be one of the + * following values: USART1 or USART2 or USART3 or UART4 or UART5. + * @param USART_ReceiverTimeOut: specifies the Receiver Time Out value. + * @retval None + */ +void USART_SetReceiverTimeOut(USART_TypeDef* USARTx, uint32_t USART_ReceiverTimeOut) +{ + /* Check the parameters */ + assert_param(IS_USART_ALL_PERIPH(USARTx)); + assert_param(IS_USART_TIMEOUT(USART_ReceiverTimeOut)); + + /* Clear the receiver Time Out value by clearing the RTO[23:0] bits in the RTOR + register */ + USARTx->RTOR &= (uint32_t)~((uint32_t)USART_RTOR_RTO); + /* Set the receiver Time Out value by setting the RTO[23:0] bits in the RTOR + register */ + USARTx->RTOR |= USART_ReceiverTimeOut; +} + +/** + * @brief Sets the system clock prescaler. + * @param USARTx: Select the USART peripheral. This parameter can be one of the + * following values: USART1 or USART2 or USART3 or UART4 or UART5. + * @param USART_Prescaler: specifies the prescaler clock. + * @note + * This function has to be called before calling USART_Cmd() function. + * @retval None + */ +void USART_SetPrescaler(USART_TypeDef* USARTx, uint8_t USART_Prescaler) +{ + /* Check the parameters */ + assert_param(IS_USART_ALL_PERIPH(USARTx)); + + /* Clear the USART prescaler */ + USARTx->GTPR &= USART_GTPR_GT; + /* Set the USART prescaler */ + USARTx->GTPR |= USART_Prescaler; +} + +/** + * @} + */ + + +/** @defgroup USART_Group2 STOP Mode functions + * @brief STOP Mode functions + * +@verbatim + =============================================================================== + ##### STOP Mode functions ##### + =============================================================================== + [..] This subsection provides a set of functions allowing to manage + WakeUp from STOP mode. + + [..] The USART is able to WakeUp from Stop Mode if USART clock is set to HSI + or LSI. + + [..] The WakeUp source is configured by calling USART_StopModeWakeUpSourceConfig() + function. + + [..] After configuring the source of WakeUp and before entering in Stop Mode + USART_STOPModeCmd() function should be called to allow USART WakeUp. + +@endverbatim + * @{ + */ + +/** + * @brief Enables or disables the specified USART peripheral in STOP Mode. + * @param USARTx: Select the USART peripheral. This parameter can be one of the + * following values: USART1 or USART2 or USART3 or UART4 or UART5. + * @param NewState: new state of the USARTx peripheral state in stop mode. + * This parameter can be: ENABLE or DISABLE. + * @note + * This function has to be called when USART clock is set to HSI or LSE. + * @retval None + */ +void USART_STOPModeCmd(USART_TypeDef* USARTx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_USART_ALL_PERIPH(USARTx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable the selected USART in STOP mode by setting the UESM bit in the CR1 + register */ + USARTx->CR1 |= USART_CR1_UESM; + } + else + { + /* Disable the selected USART in STOP mode by clearing the UE bit in the CR1 + register */ + USARTx->CR1 &= (uint32_t)~((uint32_t)USART_CR1_UESM); + } +} + +/** + * @brief Selects the USART WakeUp method form stop mode. + * @param USARTx: Select the USART peripheral. This parameter can be one of the + * following values: USART1 or USART2 or USART3 or UART4 or UART5. + * @param USART_WakeUp: specifies the selected USART wakeup method. + * This parameter can be one of the following values: + * @arg USART_WakeUpSource_AddressMatch: WUF active on address match. + * @arg USART_WakeUpSource_StartBit: WUF active on Start bit detection. + * @arg USART_WakeUpSource_RXNE: WUF active on RXNE. + * @note + * This function has to be called before calling USART_Cmd() function. + * @retval None + */ +void USART_StopModeWakeUpSourceConfig(USART_TypeDef* USARTx, uint32_t USART_WakeUpSource) +{ + /* Check the parameters */ + assert_param(IS_USART_ALL_PERIPH(USARTx)); + assert_param(IS_USART_STOPMODE_WAKEUPSOURCE(USART_WakeUpSource)); + + USARTx->CR3 &= (uint32_t)~((uint32_t)USART_CR3_WUS); + USARTx->CR3 |= USART_WakeUpSource; +} + +/** + * @} + */ + + +/** @defgroup USART_Group3 AutoBaudRate functions + * @brief AutoBaudRate functions + * +@verbatim + =============================================================================== + ##### AutoBaudRate functions ##### + =============================================================================== + [..] This subsection provides a set of functions allowing to manage + the AutoBaudRate detections. + + [..] Before Enabling AutoBaudRate detection using USART_AutoBaudRateCmd () + The character patterns used to calculate baudrate must be chosen by calling + USART_AutoBaudRateConfig() function. These function take as parameter : + (#)USART_AutoBaudRate_StartBit : any character starting with a bit 1. + (#)USART_AutoBaudRate_FallingEdge : any character starting with a 10xx bit pattern. + + [..] At any later time, another request for AutoBaudRate detection can be performed + using USART_RequestCmd() function. + + [..] The AutoBaudRate detection is monitored by the status of ABRF flag which indicate + that the AutoBaudRate detection is completed. In addition to ABRF flag, the ABRE flag + indicate that this procedure is completed without success. USART_GetFlagStatus () + function should be used to monitor the status of these flags. + +@endverbatim + * @{ + */ + +/** + * @brief Enables or disables the Auto Baud Rate. + * @param USARTx: Select the USART peripheral. This parameter can be one of the + * following values: USART1 or USART2 or USART3 or UART4 or UART5. + * @param NewState: new state of the USARTx auto baud rate. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void USART_AutoBaudRateCmd(USART_TypeDef* USARTx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_USART_ALL_PERIPH(USARTx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable the auto baud rate feature by setting the ABREN bit in the CR2 + register */ + USARTx->CR2 |= USART_CR2_ABREN; + } + else + { + /* Disable the auto baud rate feature by clearing the ABREN bit in the CR2 + register */ + USARTx->CR2 &= (uint32_t)~((uint32_t)USART_CR2_ABREN); + } +} + +/** + * @brief Selects the USART auto baud rate method. + * @param USARTx: Select the USART peripheral. This parameter can be one of the + * following values: USART1 or USART2 or USART3 or UART4 or UART5. + * @param USART_AutoBaudRate: specifies the selected USART auto baud rate method. + * This parameter can be one of the following values: + * @arg USART_AutoBaudRate_StartBit: Start Bit duration measurement. + * @arg USART_AutoBaudRate_FallingEdge: Falling edge to falling edge measurement. + * @arg USART_AutoBaudRate_0x7FFrame: 0x7F frame. + * @arg USART_AutoBaudRate_0x55Frame: 0x55 frame. + * @note + * This function has to be called before calling USART_Cmd() function. + * @retval None + */ +void USART_AutoBaudRateConfig(USART_TypeDef* USARTx, uint32_t USART_AutoBaudRate) +{ + /* Check the parameters */ + assert_param(IS_USART_ALL_PERIPH(USARTx)); + assert_param(IS_USART_AUTOBAUDRATE_MODE(USART_AutoBaudRate)); + + USARTx->CR2 &= (uint32_t)~((uint32_t)USART_CR2_ABRMODE); + USARTx->CR2 |= USART_AutoBaudRate; +} + +/** + * @} + */ + + +/** @defgroup USART_Group4 Data transfers functions + * @brief Data transfers functions + * +@verbatim + =============================================================================== + ##### Data transfers functions ##### + =============================================================================== + [..] This subsection provides a set of functions allowing to manage + the USART data transfers. + [..] During an USART reception, data shifts in least significant bit first + through the RX pin. When a transmission is taking place, a write instruction to + the USART_TDR register stores the data in the shift register. + [..] The read access of the USART_RDR register can be done using + the USART_ReceiveData() function and returns the RDR value. + Whereas a write access to the USART_TDR can be done using USART_SendData() + function and stores the written data into TDR. + +@endverbatim + * @{ + */ + +/** + * @brief Transmits single data through the USARTx peripheral. + * @param USARTx: Select the USART peripheral. This parameter can be one of the + * following values: USART1 or USART2 or USART3 or UART4 or UART5. + * @param Data: the data to transmit. + * @retval None + */ +void USART_SendData(USART_TypeDef* USARTx, uint16_t Data) +{ + /* Check the parameters */ + assert_param(IS_USART_ALL_PERIPH(USARTx)); + assert_param(IS_USART_DATA(Data)); + + /* Transmit Data */ + USARTx->TDR = (Data & (uint16_t)0x01FF); +} + +/** + * @brief Returns the most recent received data by the USARTx peripheral. + * @param USARTx: Select the USART peripheral. This parameter can be one of the + * following values: USART1 or USART2 or USART3 or UART4 or UART5. + * @retval The received data. + */ +uint16_t USART_ReceiveData(USART_TypeDef* USARTx) +{ + /* Check the parameters */ + assert_param(IS_USART_ALL_PERIPH(USARTx)); + + /* Receive Data */ + return (uint16_t)(USARTx->RDR & (uint16_t)0x01FF); +} + +/** + * @} + */ + +/** @defgroup USART_Group5 MultiProcessor Communication functions + * @brief Multi-Processor Communication functions + * +@verbatim + =============================================================================== + ##### Multi-Processor Communication functions ##### + =============================================================================== + [..] This subsection provides a set of functions allowing to manage the USART + multiprocessor communication. + [..] For instance one of the USARTs can be the master, its TX output is + connected to the RX input of the other USART. The others are slaves, + their respective TX outputs are logically ANDed together and connected + to the RX input of the master. USART multiprocessor communication is + possible through the following procedure: + (#) Program the Baud rate, Word length = 9 bits, Stop bits, Parity, + Mode transmitter or Mode receiver and hardware flow control values + using the USART_Init() function. + (#) Configures the USART address using the USART_SetAddress() function. + (#) Configures the wake up methode (USART_WakeUp_IdleLine or + USART_WakeUp_AddressMark) using USART_WakeUpConfig() function only + for the slaves. + (#) Enable the USART using the USART_Cmd() function. + (#) Enter the USART slaves in mute mode using USART_ReceiverWakeUpCmd() + function. + [..] The USART Slave exit from mute mode when receive the wake up condition. + +@endverbatim + * @{ + */ + +/** + * @brief Sets the address of the USART node. + * @param USARTx: Select the USART peripheral. This parameter can be one of the + * following values: USART1 or USART2 or USART3 or UART4 or UART5. + * @param USART_Address: Indicates the address of the USART node. + * @retval None + */ +void USART_SetAddress(USART_TypeDef* USARTx, uint8_t USART_Address) +{ + /* Check the parameters */ + assert_param(IS_USART_ALL_PERIPH(USARTx)); + + /* Clear the USART address */ + USARTx->CR2 &= (uint32_t)~((uint32_t)USART_CR2_ADD); + /* Set the USART address node */ + USARTx->CR2 |=((uint32_t)USART_Address << (uint32_t)0x18); +} + +/** + * @brief Enables or disables the USART's mute mode. + * @param USARTx: Select the USART peripheral. This parameter can be one of the + * following values: USART1 or USART2 or USART3 or UART4 or UART5. + * @param NewState: new state of the USART mute mode. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void USART_MuteModeCmd(USART_TypeDef* USARTx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_USART_ALL_PERIPH(USARTx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable the USART mute mode by setting the MME bit in the CR1 register */ + USARTx->CR1 |= USART_CR1_MME; + } + else + { + /* Disable the USART mute mode by clearing the MME bit in the CR1 register */ + USARTx->CR1 &= (uint32_t)~((uint32_t)USART_CR1_MME); + } +} + +/** + * @brief Selects the USART WakeUp method from mute mode. + * @param USARTx: Select the USART peripheral. This parameter can be one of the + * following values: USART1 or USART2 or USART3 or UART4 or UART5. + * @param USART_WakeUp: specifies the USART wakeup method. + * This parameter can be one of the following values: + * @arg USART_WakeUp_IdleLine: WakeUp by an idle line detection + * @arg USART_WakeUp_AddressMark: WakeUp by an address mark + * @retval None + */ +void USART_MuteModeWakeUpConfig(USART_TypeDef* USARTx, uint32_t USART_WakeUp) +{ + /* Check the parameters */ + assert_param(IS_USART_ALL_PERIPH(USARTx)); + assert_param(IS_USART_MUTEMODE_WAKEUP(USART_WakeUp)); + + USARTx->CR1 &= (uint32_t)~((uint32_t)USART_CR1_WAKE); + USARTx->CR1 |= USART_WakeUp; +} + +/** + * @brief Configure the USART Address detection length. + * @param USARTx: Select the USART peripheral. This parameter can be one of the + * following values: USART1 or USART2 or USART3 or UART4 or UART5. + * @param USART_AddressLength: specifies the USART address length detection. + * This parameter can be one of the following values: + * @arg USART_AddressLength_4b: 4-bit address length detection + * @arg USART_AddressLength_7b: 7-bit address length detection + * @retval None + */ +void USART_AddressDetectionConfig(USART_TypeDef* USARTx, uint32_t USART_AddressLength) +{ + /* Check the parameters */ + assert_param(IS_USART_ALL_PERIPH(USARTx)); + assert_param(IS_USART_ADDRESS_DETECTION(USART_AddressLength)); + + USARTx->CR2 &= (uint32_t)~((uint32_t)USART_CR2_ADDM7); + USARTx->CR2 |= USART_AddressLength; +} + +/** + * @} + */ + +/** @defgroup USART_Group6 LIN mode functions + * @brief LIN mode functions + * +@verbatim + =============================================================================== + ##### LIN mode functions ##### + =============================================================================== + [..] This subsection provides a set of functions allowing to manage the USART + LIN Mode communication. + [..] In LIN mode, 8-bit data format with 1 stop bit is required in accordance + with the LIN standard. + [..] Only this LIN Feature is supported by the USART IP: + (+) LIN Master Synchronous Break send capability and LIN slave break + detection capability : 13-bit break generation and 10/11 bit break + detection. + [..] USART LIN Master transmitter communication is possible through the + following procedure: + (#) Program the Baud rate, Word length = 8bits, Stop bits = 1bit, Parity, + Mode transmitter or Mode receiver and hardware flow control values + using the USART_Init() function. + (#) Enable the LIN mode using the USART_LINCmd() function. + (#) Enable the USART using the USART_Cmd() function. + (#) Send the break character using USART_SendBreak() function. + [..] USART LIN Master receiver communication is possible through the + following procedure: + (#) Program the Baud rate, Word length = 8bits, Stop bits = 1bit, Parity, + Mode transmitter or Mode receiver and hardware flow control values + using the USART_Init() function. + (#) Configures the break detection length + using the USART_LINBreakDetectLengthConfig() function. + (#) Enable the LIN mode using the USART_LINCmd() function. + (#) Enable the USART using the USART_Cmd() function. + [..] + (@) In LIN mode, the following bits must be kept cleared: + (+@) CLKEN in the USART_CR2 register. + (+@) STOP[1:0], SCEN, HDSEL and IREN in the USART_CR3 register. + +@endverbatim + * @{ + */ + +/** + * @brief Sets the USART LIN Break detection length. + * @param USARTx: Select the USART peripheral. This parameter can be one of the + * following values: USART1 or USART2 or USART3 or UART4 or UART5. + * @param USART_LINBreakDetectLength: specifies the LIN break detection length. + * This parameter can be one of the following values: + * @arg USART_LINBreakDetectLength_10b: 10-bit break detection + * @arg USART_LINBreakDetectLength_11b: 11-bit break detection + * @retval None + */ +void USART_LINBreakDetectLengthConfig(USART_TypeDef* USARTx, uint32_t USART_LINBreakDetectLength) +{ + /* Check the parameters */ + assert_param(IS_USART_ALL_PERIPH(USARTx)); + assert_param(IS_USART_LIN_BREAK_DETECT_LENGTH(USART_LINBreakDetectLength)); + + USARTx->CR2 &= (uint32_t)~((uint32_t)USART_CR2_LBDL); + USARTx->CR2 |= USART_LINBreakDetectLength; +} + +/** + * @brief Enables or disables the USART's LIN mode. + * @param USARTx: Select the USART peripheral. This parameter can be one of the + * following values: USART1 or USART2 or USART3 or UART4 or UART5. + * @param NewState: new state of the USART LIN mode. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void USART_LINCmd(USART_TypeDef* USARTx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_USART_ALL_PERIPH(USARTx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable the LIN mode by setting the LINEN bit in the CR2 register */ + USARTx->CR2 |= USART_CR2_LINEN; + } + else + { + /* Disable the LIN mode by clearing the LINEN bit in the CR2 register */ + USARTx->CR2 &= (uint32_t)~((uint32_t)USART_CR2_LINEN); + } +} + +/** + * @} + */ + +/** @defgroup USART_Group7 Halfduplex mode function + * @brief Half-duplex mode function + * +@verbatim + =============================================================================== + ##### Half-duplex mode function ##### + =============================================================================== + [..] This subsection provides a set of functions allowing to manage the USART + Half-duplex communication. + [..] The USART can be configured to follow a single-wire half-duplex protocol + where the TX and RX lines are internally connected. + [..] USART Half duplex communication is possible through the following procedure: + (#) Program the Baud rate, Word length, Stop bits, Parity, Mode transmitter + or Mode receiver and hardware flow control values using the USART_Init() + function. + (#) Configures the USART address using the USART_SetAddress() function. + (#) Enable the half duplex mode using USART_HalfDuplexCmd() function. + (#) Enable the USART using the USART_Cmd() function. + [..] + (@) The RX pin is no longer used. + (@) In Half-duplex mode the following bits must be kept cleared: + (+@) LINEN and CLKEN bits in the USART_CR2 register. + (+@) SCEN and IREN bits in the USART_CR3 register. + +@endverbatim + * @{ + */ + +/** + * @brief Enables or disables the USART's Half Duplex communication. + * @param USARTx: Select the USART peripheral. This parameter can be one of the + * following values: USART1 or USART2 or USART3 or UART4 or UART5. + * @param NewState: new state of the USART Communication. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void USART_HalfDuplexCmd(USART_TypeDef* USARTx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_USART_ALL_PERIPH(USARTx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable the Half-Duplex mode by setting the HDSEL bit in the CR3 register */ + USARTx->CR3 |= USART_CR3_HDSEL; + } + else + { + /* Disable the Half-Duplex mode by clearing the HDSEL bit in the CR3 register */ + USARTx->CR3 &= (uint32_t)~((uint32_t)USART_CR3_HDSEL); + } +} + +/** + * @} + */ + + +/** @defgroup USART_Group8 Smartcard mode functions + * @brief Smartcard mode functions + * +@verbatim + =============================================================================== + ##### Smartcard mode functions ##### + =============================================================================== + [..] This subsection provides a set of functions allowing to manage the USART + Smartcard communication. + [..] The Smartcard interface is designed to support asynchronous protocol + Smartcards as defined in the ISO 7816-3 standard. The USART can provide + a clock to the smartcard through the SCLK output. In smartcard mode, + SCLK is not associated to the communication but is simply derived from + the internal peripheral input clock through a 5-bit prescaler. + [..] Smartcard communication is possible through the following procedure: + (#) Configures the Smartcard Prescaler using the USART_SetPrescaler() + function. + (#) Configures the Smartcard Guard Time using the USART_SetGuardTime() + function. + (#) Program the USART clock using the USART_ClockInit() function as following: + (++) USART Clock enabled. + (++) USART CPOL Low. + (++) USART CPHA on first edge. + (++) USART Last Bit Clock Enabled. + (#) Program the Smartcard interface using the USART_Init() function as + following: + (++) Word Length = 9 Bits. + (++) 1.5 Stop Bit. + (++) Even parity. + (++) BaudRate = 12096 baud. + (++) Hardware flow control disabled (RTS and CTS signals). + (++) Tx and Rx enabled + (#) Optionally you can enable the parity error interrupt using + the USART_ITConfig() function. + (#) Enable the Smartcard NACK using the USART_SmartCardNACKCmd() function. + (#) Enable the Smartcard interface using the USART_SmartCardCmd() function. + (#) Enable the USART using the USART_Cmd() function. + [..] + Please refer to the ISO 7816-3 specification for more details. + [..] + (@) It is also possible to choose 0.5 stop bit for receiving but it is + recommended to use 1.5 stop bits for both transmitting and receiving + to avoid switching between the two configurations. + (@) In smartcard mode, the following bits must be kept cleared: + (+@) LINEN bit in the USART_CR2 register. + (+@) HDSEL and IREN bits in the USART_CR3 register. + +@endverbatim + * @{ + */ + +/** + * @brief Sets the specified USART guard time. + * @param USARTx: Select the USART peripheral. This parameter can be one of the + * following values: USART1 or USART2 or USART3. + * @param USART_GuardTime: specifies the guard time. + * @retval None + */ +void USART_SetGuardTime(USART_TypeDef* USARTx, uint8_t USART_GuardTime) +{ + /* Check the parameters */ + assert_param(IS_USART_123_PERIPH(USARTx)); + + /* Clear the USART Guard time */ + USARTx->GTPR &= USART_GTPR_PSC; + /* Set the USART guard time */ + USARTx->GTPR |= (uint16_t)((uint16_t)USART_GuardTime << 0x08); +} + +/** + * @brief Enables or disables the USART's Smart Card mode. + * @param USARTx: Select the USART peripheral. This parameter can be one of the + * following values: USART1 or USART2 or USART3. + * @param NewState: new state of the Smart Card mode. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void USART_SmartCardCmd(USART_TypeDef* USARTx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_USART_123_PERIPH(USARTx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + if (NewState != DISABLE) + { + /* Enable the SC mode by setting the SCEN bit in the CR3 register */ + USARTx->CR3 |= USART_CR3_SCEN; + } + else + { + /* Disable the SC mode by clearing the SCEN bit in the CR3 register */ + USARTx->CR3 &= (uint32_t)~((uint32_t)USART_CR3_SCEN); + } +} + +/** + * @brief Enables or disables NACK transmission. + * @param USARTx: Select the USART peripheral. This parameter can be one of the + * following values: USART1 or USART2 or USART3. + * @param NewState: new state of the NACK transmission. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void USART_SmartCardNACKCmd(USART_TypeDef* USARTx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_USART_123_PERIPH(USARTx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + if (NewState != DISABLE) + { + /* Enable the NACK transmission by setting the NACK bit in the CR3 register */ + USARTx->CR3 |= USART_CR3_NACK; + } + else + { + /* Disable the NACK transmission by clearing the NACK bit in the CR3 register */ + USARTx->CR3 &= (uint32_t)~((uint32_t)USART_CR3_NACK); + } +} + +/** + * @brief Sets the Smart Card number of retries in transmit and receive. + * @param USARTx: Select the USART peripheral. This parameter can be one of the + * following values: USART1 or USART2 or USART3. + * @param USART_AutoCount: specifies the Smart Card auto retry count. + * @retval None + */ +void USART_SetAutoRetryCount(USART_TypeDef* USARTx, uint8_t USART_AutoCount) +{ + /* Check the parameters */ + assert_param(IS_USART_123_PERIPH(USARTx)); + assert_param(IS_USART_AUTO_RETRY_COUNTER(USART_AutoCount)); + /* Clear the USART auto retry count */ + USARTx->CR3 &= (uint32_t)~((uint32_t)USART_CR3_SCARCNT); + /* Set the USART auto retry count*/ + USARTx->CR3 |= (uint32_t)((uint32_t)USART_AutoCount << 0x11); +} + +/** + * @brief Sets the Smart Card Block length. + * @param USARTx: Select the USART peripheral. This parameter can be one of the + * following values: USART1 or USART2 or USART3. + * @param USART_BlockLength: specifies the Smart Card block length. + * @retval None + */ +void USART_SetBlockLength(USART_TypeDef* USARTx, uint8_t USART_BlockLength) +{ + /* Check the parameters */ + assert_param(IS_USART_123_PERIPH(USARTx)); + + /* Clear the Smart card block length */ + USARTx->RTOR &= (uint32_t)~((uint32_t)USART_RTOR_BLEN); + /* Set the Smart Card block length */ + USARTx->RTOR |= (uint32_t)((uint32_t)USART_BlockLength << 0x18); +} + +/** + * @} + */ + +/** @defgroup USART_Group9 IrDA mode functions + * @brief IrDA mode functions + * +@verbatim + =============================================================================== + ##### IrDA mode functions ##### + =============================================================================== + [..] This subsection provides a set of functions allowing to manage the USART + IrDA communication. + [..] IrDA is a half duplex communication protocol. If the Transmitter is busy, + any data on the IrDA receive line will be ignored by the IrDA decoder + and if the Receiver is busy, data on the TX from the USART to IrDA will + not be encoded by IrDA. While receiving data, transmission should be + avoided as the data to be transmitted could be corrupted. + [..] IrDA communication is possible through the following procedure: + (#) Program the Baud rate, Word length = 8 bits, Stop bits, Parity, + Transmitter/Receiver modes and hardware flow control values using + the USART_Init() function. + (#) Configures the IrDA pulse width by configuring the prescaler using + the USART_SetPrescaler() function. + (#) Configures the IrDA USART_IrDAMode_LowPower or USART_IrDAMode_Normal + mode using the USART_IrDAConfig() function. + (#) Enable the IrDA using the USART_IrDACmd() function. + (#) Enable the USART using the USART_Cmd() function. + [..] + (@) A pulse of width less than two and greater than one PSC period(s) may or + may not be rejected. + (@) The receiver set up time should be managed by software. The IrDA physical + layer specification specifies a minimum of 10 ms delay between + transmission and reception (IrDA is a half duplex protocol). + (@) In IrDA mode, the following bits must be kept cleared: + (+@) LINEN, STOP and CLKEN bits in the USART_CR2 register. + (+@) SCEN and HDSEL bits in the USART_CR3 register. + +@endverbatim + * @{ + */ + +/** + * @brief Configures the USART's IrDA interface. + * @param USARTx: Select the USART peripheral. This parameter can be one of the + * following values: USART1 or USART2 or USART3 or UART4 or UART5. + * @param USART_IrDAMode: specifies the IrDA mode. + * This parameter can be one of the following values: + * @arg USART_IrDAMode_LowPower + * @arg USART_IrDAMode_Normal + * @retval None + */ +void USART_IrDAConfig(USART_TypeDef* USARTx, uint32_t USART_IrDAMode) +{ + /* Check the parameters */ + assert_param(IS_USART_ALL_PERIPH(USARTx)); + assert_param(IS_USART_IRDA_MODE(USART_IrDAMode)); + + USARTx->CR3 &= (uint32_t)~((uint32_t)USART_CR3_IRLP); + USARTx->CR3 |= USART_IrDAMode; +} + +/** + * @brief Enables or disables the USART's IrDA interface. + * @param USARTx: Select the USART peripheral. This parameter can be one of the + * following values: USART1 or USART2 or USART3 or UART4 or UART5. + * @param NewState: new state of the IrDA mode. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void USART_IrDACmd(USART_TypeDef* USARTx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_USART_ALL_PERIPH(USARTx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable the IrDA mode by setting the IREN bit in the CR3 register */ + USARTx->CR3 |= USART_CR3_IREN; + } + else + { + /* Disable the IrDA mode by clearing the IREN bit in the CR3 register */ + USARTx->CR3 &= (uint32_t)~((uint32_t)USART_CR3_IREN); + } +} +/** + * @} + */ + +/** @defgroup USART_Group10 RS485 mode function + * @brief RS485 mode function + * +@verbatim + =============================================================================== + ##### RS485 mode functions ##### + =============================================================================== + [..] This subsection provides a set of functions allowing to manage the USART + RS485 flow control. + [..] RS485 flow control (Driver enable feature) handling is possible through + the following procedure: + (#) Program the Baud rate, Word length = 8 bits, Stop bits, Parity, + Transmitter/Receiver modes and hardware flow control values using + the USART_Init() function. + (#) Enable the Driver Enable using the USART_DECmd() function. + (#) Configures the Driver Enable polarity using the USART_DEPolarityConfig() + function. + (#) Configures the Driver Enable assertion time using USART_SetDEAssertionTime() + function and deassertion time using the USART_SetDEDeassertionTime() + function. + (#) Enable the USART using the USART_Cmd() function. + [..] + (@) The assertion and dessertion times are expressed in sample time units (1/8 or + 1/16 bit time, depending on the oversampling rate). + +@endverbatim + * @{ + */ + +/** + * @brief Enables or disables the USART's DE functionality. + * @param USARTx: Select the USART peripheral. This parameter can be one of the + * following values: USART1 or USART2 or USART3 or UART4 or UART5. + * @param NewState: new state of the driver enable mode. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void USART_DECmd(USART_TypeDef* USARTx, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_USART_ALL_PERIPH(USARTx)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + if (NewState != DISABLE) + { + /* Enable the DE functionality by setting the DEM bit in the CR3 register */ + USARTx->CR3 |= USART_CR3_DEM; + } + else + { + /* Disable the DE functionality by clearing the DEM bit in the CR3 register */ + USARTx->CR3 &= (uint32_t)~((uint32_t)USART_CR3_DEM); + } +} + +/** + * @brief Configures the USART's DE polarity + * @param USARTx: Select the USART peripheral. This parameter can be one of the + * following values: USART1 or USART2 or USART3 or UART4 or UART5. + * @param USART_DEPolarity: specifies the DE polarity. + * This parameter can be one of the following values: + * @arg USART_DEPolarity_Low + * @arg USART_DEPolarity_High + * @retval None + */ +void USART_DEPolarityConfig(USART_TypeDef* USARTx, uint32_t USART_DEPolarity) +{ + /* Check the parameters */ + assert_param(IS_USART_ALL_PERIPH(USARTx)); + assert_param(IS_USART_DE_POLARITY(USART_DEPolarity)); + + USARTx->CR3 &= (uint32_t)~((uint32_t)USART_CR3_DEP); + USARTx->CR3 |= USART_DEPolarity; +} + +/** + * @brief Sets the specified RS485 DE assertion time + * @param USARTx: Select the USART peripheral. This parameter can be one of the + * following values: USART1 or USART2 or USART3 or UART4 or UART5. + * @param USART_AssertionTime: specifies the time between the activation of the DE + * signal and the beginning of the start bit + * @retval None + */ +void USART_SetDEAssertionTime(USART_TypeDef* USARTx, uint32_t USART_DEAssertionTime) +{ + /* Check the parameters */ + assert_param(IS_USART_ALL_PERIPH(USARTx)); + assert_param(IS_USART_DE_ASSERTION_DEASSERTION_TIME(USART_DEAssertionTime)); + + /* Clear the DE assertion time */ + USARTx->CR1 &= (uint32_t)~((uint32_t)USART_CR1_DEAT); + /* Set the new value for the DE assertion time */ + USARTx->CR1 |=((uint32_t)USART_DEAssertionTime << (uint32_t)0x15); +} + +/** + * @brief Sets the specified RS485 DE deassertion time + * @param USARTx: Select the USART peripheral. This parameter can be one of the + * following values: USART1 or USART2 or USART3 or UART4 or UART5. + * @param USART_DeassertionTime: specifies the time between the middle of the last + * stop bit in a transmitted message and the de-activation of the DE signal + * @retval None + */ +void USART_SetDEDeassertionTime(USART_TypeDef* USARTx, uint32_t USART_DEDeassertionTime) +{ + /* Check the parameters */ + assert_param(IS_USART_ALL_PERIPH(USARTx)); + assert_param(IS_USART_DE_ASSERTION_DEASSERTION_TIME(USART_DEDeassertionTime)); + + /* Clear the DE deassertion time */ + USARTx->CR1 &= (uint32_t)~((uint32_t)USART_CR1_DEDT); + /* Set the new value for the DE deassertion time */ + USARTx->CR1 |=((uint32_t)USART_DEDeassertionTime << (uint32_t)0x10); +} + +/** + * @} + */ + +/** @defgroup USART_Group11 DMA transfers management functions + * @brief DMA transfers management functions + * +@verbatim + =============================================================================== + ##### DMA transfers management functions ##### + =============================================================================== + [..] This section provides two functions that can be used only in DMA mode. + [..] In DMA Mode, the USART communication can be managed by 2 DMA Channel + requests: + (#) USART_DMAReq_Tx: specifies the Tx buffer DMA transfer request. + (#) USART_DMAReq_Rx: specifies the Rx buffer DMA transfer request. + [..] In this Mode it is advised to use the following function: + (+) void USART_DMACmd(USART_TypeDef* USARTx, uint16_t USART_DMAReq, + FunctionalState NewState). +@endverbatim + * @{ + */ + +/** + * @brief Enables or disables the USART's DMA interface. + * @param USARTx: Select the USART peripheral. This parameter can be one of the + * following values: USART1 or USART2 or USART3 or UART4. + * @param USART_DMAReq: specifies the DMA request. + * This parameter can be any combination of the following values: + * @arg USART_DMAReq_Tx: USART DMA transmit request + * @arg USART_DMAReq_Rx: USART DMA receive request + * @param NewState: new state of the DMA Request sources. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void USART_DMACmd(USART_TypeDef* USARTx, uint32_t USART_DMAReq, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_USART_1234_PERIPH(USARTx)); + assert_param(IS_USART_DMAREQ(USART_DMAReq)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable the DMA transfer for selected requests by setting the DMAT and/or + DMAR bits in the USART CR3 register */ + USARTx->CR3 |= USART_DMAReq; + } + else + { + /* Disable the DMA transfer for selected requests by clearing the DMAT and/or + DMAR bits in the USART CR3 register */ + USARTx->CR3 &= (uint32_t)~USART_DMAReq; + } +} + +/** + * @brief Enables or disables the USART's DMA interface when reception error occurs. + * @param USARTx: Select the USART peripheral. This parameter can be one of the + * following values: USART1 or USART2 or USART3 or UART4. + * @param USART_DMAOnError: specifies the DMA status in case of reception error. + * This parameter can be any combination of the following values: + * @arg USART_DMAOnError_Enable: DMA receive request enabled when the USART DMA + * reception error is asserted. + * @arg USART_DMAOnError_Disable: DMA receive request disabled when the USART DMA + * reception error is asserted. + * @retval None + */ +void USART_DMAReceptionErrorConfig(USART_TypeDef* USARTx, uint32_t USART_DMAOnError) +{ + /* Check the parameters */ + assert_param(IS_USART_1234_PERIPH(USARTx)); + assert_param(IS_USART_DMAONERROR(USART_DMAOnError)); + + /* Clear the DMA Reception error detection bit */ + USARTx->CR3 &= (uint32_t)~((uint32_t)USART_CR3_DDRE); + /* Set the new value for the DMA Reception error detection bit */ + USARTx->CR3 |= USART_DMAOnError; +} + +/** + * @} + */ + +/** @defgroup USART_Group12 Interrupts and flags management functions + * @brief Interrupts and flags management functions + * +@verbatim + =============================================================================== + ##### Interrupts and flags management functions ##### + =============================================================================== + [..] This subsection provides a set of functions allowing to configure the + USART Interrupts sources, Requests and check or clear the flags or pending bits status. + The user should identify which mode will be used in his application to + manage the communication: Polling mode, Interrupt mode. + + *** Polling Mode *** + ==================== + [..] In Polling Mode, the SPI communication can be managed by these flags: + (#) USART_FLAG_REACK: to indicate the status of the Receive Enable + acknowledge flag + (#) USART_FLAG_TEACK: to indicate the status of the Transmit Enable + acknowledge flag. + (#) USART_FLAG_WUF: to indicate the status of the Wake up flag. + (#) USART_FLAG_RWU: to indicate the status of the Receive Wake up flag. + (#) USART_FLAG_SBK: to indicate the status of the Send Break flag. + (#) USART_FLAG_CMF: to indicate the status of the Character match flag. + (#) USART_FLAG_BUSY: to indicate the status of the Busy flag. + (#) USART_FLAG_ABRF: to indicate the status of the Auto baud rate flag. + (#) USART_FLAG_ABRE: to indicate the status of the Auto baud rate error flag. + (#) USART_FLAG_EOBF: to indicate the status of the End of block flag. + (#) USART_FLAG_RTOF: to indicate the status of the Receive time out flag. + (#) USART_FLAG_nCTSS: to indicate the status of the Inverted nCTS input + bit status. + (#) USART_FLAG_TXE: to indicate the status of the transmit buffer register. + (#) USART_FLAG_RXNE: to indicate the status of the receive buffer register. + (#) USART_FLAG_TC: to indicate the status of the transmit operation. + (#) USART_FLAG_IDLE: to indicate the status of the Idle Line. + (#) USART_FLAG_CTS: to indicate the status of the nCTS input. + (#) USART_FLAG_LBD: to indicate the status of the LIN break detection. + (#) USART_FLAG_NE: to indicate if a noise error occur. + (#) USART_FLAG_FE: to indicate if a frame error occur. + (#) USART_FLAG_PE: to indicate if a parity error occur. + (#) USART_FLAG_ORE: to indicate if an Overrun error occur. + [..] In this Mode it is advised to use the following functions: + (+) FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG). + (+) void USART_ClearFlag(USART_TypeDef* USARTx, uint16_t USART_FLAG). + + *** Interrupt Mode *** + ====================== + [..] In Interrupt Mode, the USART communication can be managed by 8 interrupt + sources and 10 pending bits: + (+) Pending Bits: + (##) USART_IT_WU: to indicate the status of the Wake up interrupt. + (##) USART_IT_CM: to indicate the status of Character match interrupt. + (##) USART_IT_EOB: to indicate the status of End of block interrupt. + (##) USART_IT_RTO: to indicate the status of Receive time out interrupt. + (##) USART_IT_CTS: to indicate the status of CTS change interrupt. + (##) USART_IT_LBD: to indicate the status of LIN Break detection interrupt. + (##) USART_IT_TC: to indicate the status of Transmission complete interrupt. + (##) USART_IT_IDLE: to indicate the status of IDLE line detected interrupt. + (##) USART_IT_ORE: to indicate the status of OverRun Error interrupt. + (##) USART_IT_NE: to indicate the status of Noise Error interrupt. + (##) USART_IT_FE: to indicate the status of Framing Error interrupt. + (##) USART_IT_PE: to indicate the status of Parity Error interrupt. + + (+) Interrupt Source: + (##) USART_IT_WU: specifies the interrupt source for Wake up interrupt. + (##) USART_IT_CM: specifies the interrupt source for Character match + interrupt. + (##) USART_IT_EOB: specifies the interrupt source for End of block + interrupt. + (##) USART_IT_RTO: specifies the interrupt source for Receive time-out + interrupt. + (##) USART_IT_CTS: specifies the interrupt source for CTS change interrupt. + (##) USART_IT_LBD: specifies the interrupt source for LIN Break + detection interrupt. + (##) USART_IT_TXE: specifies the interrupt source for Transmit Data + Register empty interrupt. + (##) USART_IT_TC: specifies the interrupt source for Transmission + complete interrupt. + (##) USART_IT_RXNE: specifies the interrupt source for Receive Data + register not empty interrupt. + (##) USART_IT_IDLE: specifies the interrupt source for Idle line + detection interrupt. + (##) USART_IT_PE: specifies the interrupt source for Parity Error interrupt. + (##) USART_IT_ERR: specifies the interrupt source for Error interrupt + (Frame error, noise error, overrun error) + -@@- Some parameters are coded in order to use them as interrupt + source or as pending bits. + [..] In this Mode it is advised to use the following functions: + (+) void USART_ITConfig(USART_TypeDef* USARTx, uint16_t USART_IT, FunctionalState NewState). + (+) ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT). + (+) void USART_ClearITPendingBit(USART_TypeDef* USARTx, uint16_t USART_IT). + +@endverbatim + * @{ + */ + +/** + * @brief Enables or disables the specified USART interrupts. + * @param USARTx: Select the USART peripheral. This parameter can be one of the + * following values: USART1 or USART2 or USART3 or UART4 or UART5. + * @param USART_IT: specifies the USART interrupt sources to be enabled or disabled. + * This parameter can be one of the following values: + * @arg USART_IT_WU: Wake up interrupt. + * @arg USART_IT_CM: Character match interrupt. + * @arg USART_IT_EOB: End of block interrupt. + * @arg USART_IT_RTO: Receive time out interrupt. + * @arg USART_IT_CTS: CTS change interrupt. + * @arg USART_IT_LBD: LIN Break detection interrupt. + * @arg USART_IT_TXE: Transmit Data Register empty interrupt. + * @arg USART_IT_TC: Transmission complete interrupt. + * @arg USART_IT_RXNE: Receive Data register not empty interrupt. + * @arg USART_IT_IDLE: Idle line detection interrupt. + * @arg USART_IT_PE: Parity Error interrupt. + * @arg USART_IT_ERR: Error interrupt(Frame error, noise error, overrun error) + * @param NewState: new state of the specified USARTx interrupts. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void USART_ITConfig(USART_TypeDef* USARTx, uint32_t USART_IT, FunctionalState NewState) +{ + uint32_t usartreg = 0, itpos = 0, itmask = 0; + uint32_t usartxbase = 0; + /* Check the parameters */ + assert_param(IS_USART_ALL_PERIPH(USARTx)); + assert_param(IS_USART_CONFIG_IT(USART_IT)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + usartxbase = (uint32_t)USARTx; + + /* Get the USART register index */ + usartreg = (((uint16_t)USART_IT) >> 0x08); + + /* Get the interrupt position */ + itpos = USART_IT & IT_MASK; + itmask = (((uint32_t)0x01) << itpos); + + if (usartreg == 0x02) /* The IT is in CR2 register */ + { + usartxbase += 0x04; + } + else if (usartreg == 0x03) /* The IT is in CR3 register */ + { + usartxbase += 0x08; + } + else /* The IT is in CR1 register */ + { + } + if (NewState != DISABLE) + { + *(__IO uint32_t*)usartxbase |= itmask; + } + else + { + *(__IO uint32_t*)usartxbase &= ~itmask; + } +} + +/** + * @brief Enables the specified USART's Request. + * @param USARTx: Select the USART peripheral. This parameter can be one of the + * following values: USART1 or USART2 or USART3 or UART4 or UART5. + * @param USART_Request: specifies the USART request. + * This parameter can be any combination of the following values: + * @arg USART_Request_TXFRQ: Transmit data flush ReQuest + * @arg USART_Request_RXFRQ: Receive data flush ReQuest + * @arg USART_Request_MMRQ: Mute Mode ReQuest + * @arg USART_Request_SBKRQ: Send Break ReQuest + * @arg USART_Request_ABRRQ: Auto Baud Rate ReQuest + * @param NewState: new state of the DMA interface when reception error occurs. + * This parameter can be: ENABLE or DISABLE. + * @retval None + */ +void USART_RequestCmd(USART_TypeDef* USARTx, uint32_t USART_Request, FunctionalState NewState) +{ + /* Check the parameters */ + assert_param(IS_USART_ALL_PERIPH(USARTx)); + assert_param(IS_USART_REQUEST(USART_Request)); + assert_param(IS_FUNCTIONAL_STATE(NewState)); + + if (NewState != DISABLE) + { + /* Enable the USART ReQuest by setting the dedicated request bit in the RQR + register.*/ + USARTx->RQR |= USART_Request; + } + else + { + /* Disable the USART ReQuest by clearing the dedicated request bit in the RQR + register.*/ + USARTx->RQR &= (uint32_t)~USART_Request; + } +} + +/** + * @brief Enables or disables the USART's Overrun detection. + * @param USARTx: Select the USART peripheral. This parameter can be one of the + * following values: USART1 or USART2 or USART3 or UART4 or UART5. + * @param USART_OVRDetection: specifies the OVR detection status in case of OVR error. + * This parameter can be any combination of the following values: + * @arg USART_OVRDetection_Enable: OVR error detection enabled when the USART OVR error + * is asserted. + * @arg USART_OVRDetection_Disable: OVR error detection disabled when the USART OVR error + * is asserted. + * @retval None + */ +void USART_OverrunDetectionConfig(USART_TypeDef* USARTx, uint32_t USART_OVRDetection) +{ + /* Check the parameters */ + assert_param(IS_USART_ALL_PERIPH(USARTx)); + assert_param(IS_USART_OVRDETECTION(USART_OVRDetection)); + + /* Clear the OVR detection bit */ + USARTx->CR3 &= (uint32_t)~((uint32_t)USART_CR3_OVRDIS); + /* Set the new value for the OVR detection bit */ + USARTx->CR3 |= USART_OVRDetection; +} + +/** + * @brief Checks whether the specified USART flag is set or not. + * @param USARTx: Select the USART peripheral. This parameter can be one of the + * following values: USART1 or USART2 or USART3 or UART4 or UART5. + * @param USART_FLAG: specifies the flag to check. + * This parameter can be one of the following values: + * @arg USART_FLAG_REACK: Receive Enable acknowledge flag. + * @arg USART_FLAG_TEACK: Transmit Enable acknowledge flag. + * @arg USART_FLAG_WUF: Wake up flag. + * @arg USART_FLAG_RWU: Receive Wake up flag. + * @arg USART_FLAG_SBK: Send Break flag. + * @arg USART_FLAG_CMF: Character match flag. + * @arg USART_FLAG_BUSY: Busy flag. + * @arg USART_FLAG_ABRF: Auto baud rate flag. + * @arg USART_FLAG_ABRE: Auto baud rate error flag. + * @arg USART_FLAG_EOBF: End of block flag. + * @arg USART_FLAG_RTOF: Receive time out flag. + * @arg USART_FLAG_nCTSS: Inverted nCTS input bit status. + * @arg USART_FLAG_CTS: CTS Change flag. + * @arg USART_FLAG_LBD: LIN Break detection flag. + * @arg USART_FLAG_TXE: Transmit data register empty flag. + * @arg USART_FLAG_TC: Transmission Complete flag. + * @arg USART_FLAG_RXNE: Receive data register not empty flag. + * @arg USART_FLAG_IDLE: Idle Line detection flag. + * @arg USART_FLAG_ORE: OverRun Error flag. + * @arg USART_FLAG_NE: Noise Error flag. + * @arg USART_FLAG_FE: Framing Error flag. + * @arg USART_FLAG_PE: Parity Error flag. + * @retval The new state of USART_FLAG (SET or RESET). + */ +FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint32_t USART_FLAG) +{ + FlagStatus bitstatus = RESET; + /* Check the parameters */ + assert_param(IS_USART_ALL_PERIPH(USARTx)); + assert_param(IS_USART_FLAG(USART_FLAG)); + + if ((USARTx->ISR & USART_FLAG) != (uint16_t)RESET) + { + bitstatus = SET; + } + else + { + bitstatus = RESET; + } + return bitstatus; +} + +/** + * @brief Clears the USARTx's pending flags. + * @param USARTx: Select the USART peripheral. This parameter can be one of the + * following values: USART1 or USART2 or USART3 or UART4 or UART5. + * @param USART_FLAG: specifies the flag to clear. + * This parameter can be any combination of the following values: + * @arg USART_FLAG_WUF: Wake up flag. + * @arg USART_FLAG_CMF: Character match flag. + * @arg USART_FLAG_EOBF: End of block flag. + * @arg USART_FLAG_RTOF: Receive time out flag. + * @arg USART_FLAG_CTS: CTS Change flag. + * @arg USART_FLAG_LBD: LIN Break detection flag. + * @arg USART_FLAG_TC: Transmission Complete flag. + * @arg USART_FLAG_IDLE: IDLE line detected flag. + * @arg USART_FLAG_ORE: OverRun Error flag. + * @arg USART_FLAG_NE: Noise Error flag. + * @arg USART_FLAG_FE: Framing Error flag. + * @arg USART_FLAG_PE: Parity Errorflag. + * + * @note + * - RXNE pending bit is cleared by a read to the USART_RDR register + * (USART_ReceiveData()) or by writing 1 to the RXFRQ in the register USART_RQR + * (USART_RequestCmd()). + * - TC flag can be also cleared by software sequence: a read operation to + * USART_SR register (USART_GetFlagStatus()) followed by a write operation + * to USART_TDR register (USART_SendData()). + * - TXE flag is cleared by a write to the USART_TDR register + * (USART_SendData()) or by writing 1 to the TXFRQ in the register USART_RQR + * (USART_RequestCmd()). + * - SBKF flag is cleared by 1 to the SBKRQ in the register USART_RQR + * (USART_RequestCmd()). + * @retval None + */ +void USART_ClearFlag(USART_TypeDef* USARTx, uint32_t USART_FLAG) +{ + /* Check the parameters */ + assert_param(IS_USART_ALL_PERIPH(USARTx)); + assert_param(IS_USART_CLEAR_FLAG(USART_FLAG)); + + USARTx->ICR = USART_FLAG; +} + +/** + * @brief Checks whether the specified USART interrupt has occurred or not. + * @param USARTx: Select the USART peripheral. This parameter can be one of the + * following values: USART1 or USART2 or USART3 or UART4 or UART5. + * @param USART_IT: specifies the USART interrupt source to check. + * This parameter can be one of the following values: + * @arg USART_IT_WU: Wake up interrupt. + * @arg USART_IT_CM: Character match interrupt. + * @arg USART_IT_EOB: End of block interrupt. + * @arg USART_IT_RTO: Receive time out interrupt. + * @arg USART_IT_CTS: CTS change interrupt. + * @arg USART_IT_LBD: LIN Break detection interrupt. + * @arg USART_IT_TXE: Transmit Data Register empty interrupt. + * @arg USART_IT_TC: Transmission complete interrupt. + * @arg USART_IT_RXNE: Receive Data register not empty interrupt. + * @arg USART_IT_IDLE: Idle line detection interrupt. + * @arg USART_IT_ORE: OverRun Error interrupt. + * @arg USART_IT_NE: Noise Error interrupt. + * @arg USART_IT_FE: Framing Error interrupt. + * @arg USART_IT_PE: Parity Error interrupt. + * @retval The new state of USART_IT (SET or RESET). + */ +ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint32_t USART_IT) +{ + uint32_t bitpos = 0, itmask = 0, usartreg = 0; + ITStatus bitstatus = RESET; + /* Check the parameters */ + assert_param(IS_USART_ALL_PERIPH(USARTx)); + assert_param(IS_USART_GET_IT(USART_IT)); + + /* Get the USART register index */ + usartreg = (((uint16_t)USART_IT) >> 0x08); + /* Get the interrupt position */ + itmask = USART_IT & IT_MASK; + itmask = (uint32_t)0x01 << itmask; + + if (usartreg == 0x01) /* The IT is in CR1 register */ + { + itmask &= USARTx->CR1; + } + else if (usartreg == 0x02) /* The IT is in CR2 register */ + { + itmask &= USARTx->CR2; + } + else /* The IT is in CR3 register */ + { + itmask &= USARTx->CR3; + } + + bitpos = USART_IT >> 0x10; + bitpos = (uint32_t)0x01 << bitpos; + bitpos &= USARTx->ISR; + if ((itmask != (uint16_t)RESET)&&(bitpos != (uint16_t)RESET)) + { + bitstatus = SET; + } + else + { + bitstatus = RESET; + } + + return bitstatus; +} + +/** + * @brief Clears the USARTx's interrupt pending bits. + * @param USARTx: Select the USART peripheral. This parameter can be one of the + * following values: USART1 or USART2 or USART3 or UART4 or UART5. + * @param USART_IT: specifies the interrupt pending bit to clear. + * This parameter can be one of the following values: + * @arg USART_IT_WU: Wake up interrupt. + * @arg USART_IT_CM: Character match interrupt. + * @arg USART_IT_EOB: End of block interrupt. + * @arg USART_IT_RTO: Receive time out interrupt. + * @arg USART_IT_CTS: CTS change interrupt. + * @arg USART_IT_LBD: LIN Break detection interrupt. + * @arg USART_IT_TC: Transmission complete interrupt. + * @arg USART_IT_IDLE: IDLE line detected interrupt. + * @arg USART_IT_ORE: OverRun Error interrupt. + * @arg USART_IT_NE: Noise Error interrupt. + * @arg USART_IT_FE: Framing Error interrupt. + * @arg USART_IT_PE: Parity Error interrupt. + * @note + * - RXNE pending bit is cleared by a read to the USART_RDR register + * (USART_ReceiveData()) or by writing 1 to the RXFRQ in the register USART_RQR + * (USART_RequestCmd()). + * - TC pending bit can be also cleared by software sequence: a read + * operation to USART_SR register (USART_GetITStatus()) followed by a write + * operation to USART_TDR register (USART_SendData()). + * - TXE pending bit is cleared by a write to the USART_TDR register + * (USART_SendData()) or by writing 1 to the TXFRQ in the register USART_RQR + * (USART_RequestCmd()). + * @retval None + */ +void USART_ClearITPendingBit(USART_TypeDef* USARTx, uint32_t USART_IT) +{ + uint32_t bitpos = 0, itmask = 0; + /* Check the parameters */ + assert_param(IS_USART_ALL_PERIPH(USARTx)); + assert_param(IS_USART_CLEAR_IT(USART_IT)); + + bitpos = USART_IT >> 0x10; + itmask = ((uint32_t)0x01 << (uint32_t)bitpos); + USARTx->ICR = (uint32_t)itmask; +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_wwdg.c b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_wwdg.c new file mode 100755 index 0000000000..f51e887e63 --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_wwdg.c @@ -0,0 +1,304 @@ +/** + ****************************************************************************** + * @file stm32f30x_wwdg.c + * @author MCD Application Team + * @version V1.2.3 + * @date 10-July-2015 + * @brief This file provides firmware functions to manage the following + * functionalities of the Window watchdog (WWDG) peripheral: + * + Prescaler, Refresh window and Counter configuration + * + WWDG activation + * + Interrupts and flags management + * + * @verbatim + * + ============================================================================== + ##### WWDG features ##### + ============================================================================== + + [..] Once enabled the WWDG generates a system reset on expiry of a programmed + time period, unless the program refreshes the counter (downcounter) + before to reach 0x3F value (i.e. a reset is generated when the counter + value rolls over from 0x40 to 0x3F). + [..] An MCU reset is also generated if the counter value is refreshed + before the counter has reached the refresh window value. This + implies that the counter must be refreshed in a limited window. + + [..] Once enabled the WWDG cannot be disabled except by a system reset. + + [..] WWDGRST flag in RCC_CSR register can be used to inform when a WWDG + reset occurs. + + [..] The WWDG counter input clock is derived from the APB clock divided + by a programmable prescaler. + + [..] WWDG counter clock = PCLK1 / Prescaler. + [..] WWDG timeout = (WWDG counter clock) * (counter value). + + [..] Min-max timeout value @36MHz (PCLK1): ~114us / ~58.3ms. + + ##### How to use this driver ##### + ============================================================================== + [..] + (#) Enable WWDG clock using RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE) + function. + + (#) Configure the WWDG prescaler using WWDG_SetPrescaler() function. + + (#) Configure the WWDG refresh window using WWDG_SetWindowValue() function. + + (#) Set the WWDG counter value and start it using WWDG_Enable() function. + When the WWDG is enabled the counter value should be configured to + a value greater than 0x40 to prevent generating an immediate reset. + + (#) Optionally you can enable the Early wakeup interrupt which is + generated when the counter reach 0x40. + Once enabled this interrupt cannot be disabled except by a system reset. + + (#) Then the application program must refresh the WWDG counter at regular + intervals during normal operation to prevent an MCU reset, using + WWDG_SetCounter() function. This operation must occur only when + the counter value is lower than the refresh window value, + programmed using WWDG_SetWindowValue(). + + @endverbatim + + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f30x_wwdg.h" +#include "stm32f30x_rcc.h" + +/** @addtogroup STM32F30x_StdPeriph_Driver + * @{ + */ + +/** @defgroup WWDG + * @brief WWDG driver modules + * @{ + */ + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +/* --------------------- WWDG registers bit mask ---------------------------- */ +/* CFR register bit mask */ +#define CFR_WDGTB_MASK ((uint32_t)0xFFFFFE7F) +#define CFR_W_MASK ((uint32_t)0xFFFFFF80) +#define BIT_MASK ((uint8_t)0x7F) + +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/* Private function prototypes -----------------------------------------------*/ +/* Private functions ---------------------------------------------------------*/ + +/** @defgroup WWDG_Private_Functions + * @{ + */ + +/** @defgroup WWDG_Group1 Prescaler, Refresh window and Counter configuration functions + * @brief Prescaler, Refresh window and Counter configuration functions + * +@verbatim + ============================================================================== + ##### Prescaler, Refresh window and Counter configuration functions ##### + ============================================================================== + +@endverbatim + * @{ + */ + +/** + * @brief Deinitializes the WWDG peripheral registers to their default reset values. + * @param None + * @retval None + */ +void WWDG_DeInit(void) +{ + RCC_APB1PeriphResetCmd(RCC_APB1Periph_WWDG, ENABLE); + RCC_APB1PeriphResetCmd(RCC_APB1Periph_WWDG, DISABLE); +} + +/** + * @brief Sets the WWDG Prescaler. + * @param WWDG_Prescaler: specifies the WWDG Prescaler. + * This parameter can be one of the following values: + * @arg WWDG_Prescaler_1: WWDG counter clock = (PCLK1/4096)/1 + * @arg WWDG_Prescaler_2: WWDG counter clock = (PCLK1/4096)/2 + * @arg WWDG_Prescaler_4: WWDG counter clock = (PCLK1/4096)/4 + * @arg WWDG_Prescaler_8: WWDG counter clock = (PCLK1/4096)/8 + * @retval None + */ +void WWDG_SetPrescaler(uint32_t WWDG_Prescaler) +{ + uint32_t tmpreg = 0; + /* Check the parameters */ + assert_param(IS_WWDG_PRESCALER(WWDG_Prescaler)); + /* Clear WDGTB[1:0] bits */ + tmpreg = WWDG->CFR & CFR_WDGTB_MASK; + /* Set WDGTB[1:0] bits according to WWDG_Prescaler value */ + tmpreg |= WWDG_Prescaler; + /* Store the new value */ + WWDG->CFR = tmpreg; +} + +/** + * @brief Sets the WWDG window value. + * @param WindowValue: specifies the window value to be compared to the downcounter. + * This parameter value must be lower than 0x80. + * @retval None + */ +void WWDG_SetWindowValue(uint8_t WindowValue) +{ + __IO uint32_t tmpreg = 0; + + /* Check the parameters */ + assert_param(IS_WWDG_WINDOW_VALUE(WindowValue)); + /* Clear W[6:0] bits */ + + tmpreg = WWDG->CFR & CFR_W_MASK; + + /* Set W[6:0] bits according to WindowValue value */ + tmpreg |= WindowValue & (uint32_t) BIT_MASK; + + /* Store the new value */ + WWDG->CFR = tmpreg; +} + +/** + * @brief Enables the WWDG Early Wakeup interrupt(EWI). + * @note Once enabled this interrupt cannot be disabled except by a system reset. + * @param None + * @retval None + */ +void WWDG_EnableIT(void) +{ + WWDG->CFR |= WWDG_CFR_EWI; +} + +/** + * @brief Sets the WWDG counter value. + * @param Counter: specifies the watchdog counter value. + * This parameter must be a number between 0x40 and 0x7F (to prevent generating + * an immediate reset). + * @retval None + */ +void WWDG_SetCounter(uint8_t Counter) +{ + /* Check the parameters */ + assert_param(IS_WWDG_COUNTER(Counter)); + /* Write to T[6:0] bits to configure the counter value, no need to do + a read-modify-write; writing a 0 to WDGA bit does nothing */ + WWDG->CR = Counter & BIT_MASK; +} + +/** + * @} + */ + +/** @defgroup WWDG_Group2 WWDG activation functions + * @brief WWDG activation functions + * +@verbatim + ============================================================================== + ##### WWDG activation function ##### + ============================================================================== + +@endverbatim + * @{ + */ + +/** + * @brief Enables WWDG and load the counter value. + * @param Counter: specifies the watchdog counter value. + * This parameter must be a number between 0x40 and 0x7F (to prevent generating + * an immediate reset). + * @retval None + */ +void WWDG_Enable(uint8_t Counter) +{ + /* Check the parameters */ + assert_param(IS_WWDG_COUNTER(Counter)); + WWDG->CR = WWDG_CR_WDGA | Counter; +} + +/** + * @} + */ + +/** @defgroup WWDG_Group3 Interrupts and flags management functions + * @brief Interrupts and flags management functions + * +@verbatim + ============================================================================== + ##### Interrupts and flags management functions ##### + ============================================================================== + +@endverbatim + * @{ + */ + +/** + * @brief Checks whether the Early Wakeup interrupt flag is set or not. + * @param None + * @retval The new state of the Early Wakeup interrupt flag (SET or RESET). + */ +FlagStatus WWDG_GetFlagStatus(void) +{ + FlagStatus bitstatus = RESET; + + if ((WWDG->SR) != (uint32_t)RESET) + { + bitstatus = SET; + } + else + { + bitstatus = RESET; + } + return bitstatus; +} + +/** + * @brief Clears Early Wakeup interrupt flag. + * @param None + * @retval None + */ +void WWDG_ClearFlag(void) +{ + WWDG->SR = (uint32_t)RESET; +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/inc/usb_core.h b/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/inc/usb_core.h new file mode 100755 index 0000000000..bf303f79e6 --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/inc/usb_core.h @@ -0,0 +1,259 @@ +/** + ****************************************************************************** + * @file usb_core.h + * @author MCD Application Team + * @version V4.0.0 + * @date 28-August-2012 + * @brief Standard protocol processing functions prototypes + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2012 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USB_CORE_H +#define __USB_CORE_H + +/* Includes ------------------------------------------------------------------*/ +/* Exported types ------------------------------------------------------------*/ +typedef enum _CONTROL_STATE +{ + WAIT_SETUP, /* 0 */ + SETTING_UP, /* 1 */ + IN_DATA, /* 2 */ + OUT_DATA, /* 3 */ + LAST_IN_DATA, /* 4 */ + LAST_OUT_DATA, /* 5 */ + WAIT_STATUS_IN, /* 7 */ + WAIT_STATUS_OUT, /* 8 */ + STALLED, /* 9 */ + PAUSE /* 10 */ +} CONTROL_STATE; /* The state machine states of a control pipe */ + +typedef struct OneDescriptor +{ + uint8_t *Descriptor; + uint16_t Descriptor_Size; +} +ONE_DESCRIPTOR, *PONE_DESCRIPTOR; +/* All the request process routines return a value of this type + If the return value is not SUCCESS or NOT_READY, + the software will STALL the correspond endpoint */ +typedef enum _RESULT +{ + USB_SUCCESS = 0, /* Process successfully */ + USB_ERROR, + USB_UNSUPPORT, + USB_NOT_READY /* The process has not been finished, endpoint will be + NAK to further request */ +} RESULT; + + +/*-*-*-*-*-*-*-*-*-*-* Definitions for endpoint level -*-*-*-*-*-*-*-*-*-*-*-*/ +typedef struct _ENDPOINT_INFO +{ + /* When send data out of the device, + CopyData() is used to get data buffer 'Length' bytes data + if Length is 0, + CopyData() returns the total length of the data + if the request is not supported, returns 0 + (NEW Feature ) + if CopyData() returns -1, the calling routine should not proceed + further and will resume the SETUP process by the class device + if Length is not 0, + CopyData() returns a pointer to indicate the data location + Usb_wLength is the data remain to be sent, + Usb_wOffset is the Offset of original data + When receive data from the host, + CopyData() is used to get user data buffer which is capable + of Length bytes data to copy data from the endpoint buffer. + if Length is 0, + CopyData() returns the available data length, + if Length is not 0, + CopyData() returns user buffer address + Usb_rLength is the data remain to be received, + Usb_rPointer is the Offset of data buffer + */ + uint16_t Usb_wLength; + uint16_t Usb_wOffset; + uint16_t PacketSize; + uint8_t *(*CopyData)(uint16_t Length); +}ENDPOINT_INFO; + +/*-*-*-*-*-*-*-*-*-*-*-* Definitions for device level -*-*-*-*-*-*-*-*-*-*-*-*/ + +typedef struct _DEVICE +{ + uint8_t Total_Endpoint; /* Number of endpoints that are used */ + uint8_t Total_Configuration;/* Number of configuration available */ +} +DEVICE; + +typedef union +{ + uint16_t w; + struct BW + { + uint8_t bb1; + uint8_t bb0; + } + bw; +} uint16_t_uint8_t; + +typedef struct _DEVICE_INFO +{ + uint8_t USBbmRequestType; /* bmRequestType */ + uint8_t USBbRequest; /* bRequest */ + uint16_t_uint8_t USBwValues; /* wValue */ + uint16_t_uint8_t USBwIndexs; /* wIndex */ + uint16_t_uint8_t USBwLengths; /* wLength */ + + uint8_t ControlState; /* of type CONTROL_STATE */ + uint8_t Current_Feature; + uint8_t Current_Configuration; /* Selected configuration */ + uint8_t Current_Interface; /* Selected interface of current configuration */ + uint8_t Current_AlternateSetting;/* Selected Alternate Setting of current + interface*/ + + ENDPOINT_INFO Ctrl_Info; +}DEVICE_INFO; + +typedef struct _DEVICE_PROP +{ + void (*Init)(void); /* Initialize the device */ + void (*Reset)(void); /* Reset routine of this device */ + + /* Device dependent process after the status stage */ + void (*Process_Status_IN)(void); + void (*Process_Status_OUT)(void); + + /* Procedure of process on setup stage of a class specified request with data stage */ + /* All class specified requests with data stage are processed in Class_Data_Setup + Class_Data_Setup() + responses to check all special requests and fills ENDPOINT_INFO + according to the request + If IN tokens are expected, then wLength & wOffset will be filled + with the total transferring bytes and the starting position + If OUT tokens are expected, then rLength & rOffset will be filled + with the total expected bytes and the starting position in the buffer + + If the request is valid, Class_Data_Setup returns SUCCESS, else UNSUPPORT + + CAUTION: + Since GET_CONFIGURATION & GET_INTERFACE are highly related to + the individual classes, they will be checked and processed here. + */ + RESULT (*Class_Data_Setup)(uint8_t RequestNo); + + /* Procedure of process on setup stage of a class specified request without data stage */ + /* All class specified requests without data stage are processed in Class_NoData_Setup + Class_NoData_Setup + responses to check all special requests and perform the request + + CAUTION: + Since SET_CONFIGURATION & SET_INTERFACE are highly related to + the individual classes, they will be checked and processed here. + */ + RESULT (*Class_NoData_Setup)(uint8_t RequestNo); + + /*Class_Get_Interface_Setting + This function is used by the file usb_core.c to test if the selected Interface + and Alternate Setting (uint8_t Interface, uint8_t AlternateSetting) are supported by + the application. + This function is writing by user. It should return "SUCCESS" if the Interface + and Alternate Setting are supported by the application or "UNSUPPORT" if they + are not supported. */ + + RESULT (*Class_Get_Interface_Setting)(uint8_t Interface, uint8_t AlternateSetting); + + uint8_t* (*GetDeviceDescriptor)(uint16_t Length); + uint8_t* (*GetConfigDescriptor)(uint16_t Length); + uint8_t* (*GetStringDescriptor)(uint16_t Length); + + /* This field is not used in current library version. It is kept only for + compatibility with previous versions */ + void* RxEP_buffer; + + uint8_t MaxPacketSize; + +}DEVICE_PROP; + +typedef struct _USER_STANDARD_REQUESTS +{ + void (*User_GetConfiguration)(void); /* Get Configuration */ + void (*User_SetConfiguration)(void); /* Set Configuration */ + void (*User_GetInterface)(void); /* Get Interface */ + void (*User_SetInterface)(void); /* Set Interface */ + void (*User_GetStatus)(void); /* Get Status */ + void (*User_ClearFeature)(void); /* Clear Feature */ + void (*User_SetEndPointFeature)(void); /* Set Endpoint Feature */ + void (*User_SetDeviceFeature)(void); /* Set Device Feature */ + void (*User_SetDeviceAddress)(void); /* Set Device Address */ +} +USER_STANDARD_REQUESTS; + +/* Exported constants --------------------------------------------------------*/ +#define Type_Recipient (pInformation->USBbmRequestType & (REQUEST_TYPE | RECIPIENT)) + +#define Usb_rLength Usb_wLength +#define Usb_rOffset Usb_wOffset + +#define USBwValue USBwValues.w +#define USBwValue0 USBwValues.bw.bb0 +#define USBwValue1 USBwValues.bw.bb1 +#define USBwIndex USBwIndexs.w +#define USBwIndex0 USBwIndexs.bw.bb0 +#define USBwIndex1 USBwIndexs.bw.bb1 +#define USBwLength USBwLengths.w +#define USBwLength0 USBwLengths.bw.bb0 +#define USBwLength1 USBwLengths.bw.bb1 + +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions ------------------------------------------------------- */ +uint8_t Setup0_Process(void); +uint8_t Post0_Process(void); +uint8_t Out0_Process(void); +uint8_t In0_Process(void); + +RESULT Standard_SetEndPointFeature(void); +RESULT Standard_SetDeviceFeature(void); + +uint8_t *Standard_GetConfiguration(uint16_t Length); +RESULT Standard_SetConfiguration(void); +uint8_t *Standard_GetInterface(uint16_t Length); +RESULT Standard_SetInterface(void); +uint8_t *Standard_GetDescriptorData(uint16_t Length, PONE_DESCRIPTOR pDesc); + +uint8_t *Standard_GetStatus(uint16_t Length); +RESULT Standard_ClearFeature(void); +void SetDeviceAddress(uint8_t); +void NOP_Process(void); + +extern DEVICE_PROP Device_Property; +extern USER_STANDARD_REQUESTS User_Standard_Requests; +extern DEVICE Device_Table; +extern DEVICE_INFO Device_Info; + +/* cells saving status during interrupt servicing */ +extern __IO uint16_t SaveRState; +extern __IO uint16_t SaveTState; + +#endif /* __USB_CORE_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/inc/usb_def.h b/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/inc/usb_def.h new file mode 100755 index 0000000000..7f6e1b508b --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/inc/usb_def.h @@ -0,0 +1,92 @@ +/** + ****************************************************************************** + * @file usb_def.h + * @author MCD Application Team + * @version V4.0.0 + * @date 28-August-2012 + * @brief Definitions related to USB Core + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2012 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USB_DEF_H +#define __USB_DEF_H + +/* Includes ------------------------------------------------------------------*/ +/* Exported types ------------------------------------------------------------*/ +typedef enum _RECIPIENT_TYPE +{ + DEVICE_RECIPIENT, /* Recipient device */ + INTERFACE_RECIPIENT, /* Recipient interface */ + ENDPOINT_RECIPIENT, /* Recipient endpoint */ + OTHER_RECIPIENT +} RECIPIENT_TYPE; + + +typedef enum _STANDARD_REQUESTS +{ + GET_STATUS = 0, + CLEAR_FEATURE, + RESERVED1, + SET_FEATURE, + RESERVED2, + SET_ADDRESS, + GET_DESCRIPTOR, + SET_DESCRIPTOR, + GET_CONFIGURATION, + SET_CONFIGURATION, + GET_INTERFACE, + SET_INTERFACE, + TOTAL_sREQUEST, /* Total number of Standard request */ + SYNCH_FRAME = 12 +} STANDARD_REQUESTS; + +/* Definition of "USBwValue" */ +typedef enum _DESCRIPTOR_TYPE +{ + DEVICE_DESCRIPTOR = 1, + CONFIG_DESCRIPTOR, + STRING_DESCRIPTOR, + INTERFACE_DESCRIPTOR, + ENDPOINT_DESCRIPTOR +} DESCRIPTOR_TYPE; + +/* Feature selector of a SET_FEATURE or CLEAR_FEATURE */ +typedef enum _FEATURE_SELECTOR +{ + ENDPOINT_STALL, + DEVICE_REMOTE_WAKEUP +} FEATURE_SELECTOR; + +/* Exported constants --------------------------------------------------------*/ +/* Definition of "USBbmRequestType" */ +#define REQUEST_TYPE 0x60 /* Mask to get request type */ +#define STANDARD_REQUEST 0x00 /* Standard request */ +#define CLASS_REQUEST 0x20 /* Class request */ +#define VENDOR_REQUEST 0x40 /* Vendor request */ + +#define RECIPIENT 0x1F /* Mask to get recipient */ + +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions ------------------------------------------------------- */ + +#endif /* __USB_DEF_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/inc/usb_init.h b/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/inc/usb_init.h new file mode 100755 index 0000000000..44b528cbd4 --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/inc/usb_init.h @@ -0,0 +1,62 @@ +/** + ****************************************************************************** + * @file usb_init.h + * @author MCD Application Team + * @version V4.0.0 + * @date 28-August-2012 + * @brief Initialization routines & global variables + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2012 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USB_INIT_H +#define __USB_INIT_H + +/* Includes ------------------------------------------------------------------*/ +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions ------------------------------------------------------- */ +void USB_Init(void); + +/* External variables --------------------------------------------------------*/ +/* The number of current endpoint, it will be used to specify an endpoint */ +extern uint8_t EPindex; +/* The number of current device, it is an index to the Device_Table */ +/*extern uint8_t Device_no; */ +/* Points to the DEVICE_INFO structure of current device */ +/* The purpose of this register is to speed up the execution */ +extern DEVICE_INFO* pInformation; +/* Points to the DEVICE_PROP structure of current device */ +/* The purpose of this register is to speed up the execution */ +extern DEVICE_PROP* pProperty; +/* Temporary save the state of Rx & Tx status. */ +/* Whenever the Rx or Tx state is changed, its value is saved */ +/* in this variable first and will be set to the EPRB or EPRA */ +/* at the end of interrupt process */ +extern USER_STANDARD_REQUESTS *pUser_Standard_Requests; + +extern uint16_t SaveState ; +extern uint16_t wInterrupt_Mask; + +#endif /* __USB_INIT_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/inc/usb_int.h b/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/inc/usb_int.h new file mode 100755 index 0000000000..307ab14ea7 --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/inc/usb_int.h @@ -0,0 +1,45 @@ +/** + ****************************************************************************** + * @file usb_int.h + * @author MCD Application Team + * @version V4.0.0 + * @date 28-August-2012 + * @brief Endpoint CTR (Low and High) interrupt's service routines prototypes + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2012 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USB_INT_H +#define __USB_INT_H + +/* Includes ------------------------------------------------------------------*/ +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions ------------------------------------------------------- */ +void CTR_LP(void); +void CTR_HP(void); + +/* External variables --------------------------------------------------------*/ + +#endif /* __USB_INT_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/inc/usb_lib.h b/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/inc/usb_lib.h new file mode 100755 index 0000000000..b0e519bcc5 --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/inc/usb_lib.h @@ -0,0 +1,52 @@ +/** + ****************************************************************************** + * @file usb_lib.h + * @author MCD Application Team + * @version V4.0.0 + * @date 28-August-2012 + * @brief USB library include files + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2012 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USB_LIB_H +#define __USB_LIB_H + +/* Includes ------------------------------------------------------------------*/ +#include "hw_config.h" +#include "usb_type.h" +#include "usb_regs.h" +#include "usb_def.h" +#include "usb_core.h" +#include "usb_init.h" +#include "usb_sil.h" +#include "usb_mem.h" +#include "usb_int.h" + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions ------------------------------------------------------- */ +/* External variables --------------------------------------------------------*/ + +#endif /* __USB_LIB_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/inc/usb_mem.h b/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/inc/usb_mem.h new file mode 100755 index 0000000000..0b2910060a --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/inc/usb_mem.h @@ -0,0 +1,45 @@ +/** + ****************************************************************************** + * @file usb_mem.h + * @author MCD Application Team + * @version V4.0.0 + * @date 28-August-2012 + * @brief Utility prototypes functions for memory/PMA transfers + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2012 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USB_MEM_H +#define __USB_MEM_H + +/* Includes ------------------------------------------------------------------*/ +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions ------------------------------------------------------- */ +void UserToPMABufferCopy(uint8_t *pbUsrBuf, uint16_t wPMABufAddr, uint16_t wNBytes); +void PMAToUserBufferCopy(uint8_t *pbUsrBuf, uint16_t wPMABufAddr, uint16_t wNBytes); + +/* External variables --------------------------------------------------------*/ + +#endif /*__USB_MEM_H*/ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/inc/usb_regs.h b/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/inc/usb_regs.h new file mode 100755 index 0000000000..87e0a008a8 --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/inc/usb_regs.h @@ -0,0 +1,680 @@ +/** + ****************************************************************************** + * @file usb_regs.h + * @author MCD Application Team + * @version V4.0.0 + * @date 28-August-2012 + * @brief Interface prototype functions to USB cell registers + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2012 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USB_REGS_H +#define __USB_REGS_H + +/* Includes ------------------------------------------------------------------*/ +/* Exported types ------------------------------------------------------------*/ +typedef enum _EP_DBUF_DIR +{ + /* double buffered endpoint direction */ + EP_DBUF_ERR, + EP_DBUF_OUT, + EP_DBUF_IN +}EP_DBUF_DIR; + +/* endpoint buffer number */ +enum EP_BUF_NUM +{ + EP_NOBUF, + EP_BUF0, + EP_BUF1 +}; + +/* Exported constants --------------------------------------------------------*/ +#define RegBase (0x40005C00L) /* USB_IP Peripheral Registers base address */ +#define PMAAddr (0x40006000L) /* USB_IP Packet Memory Area base address */ + +/******************************************************************************/ +/* General registers */ +/******************************************************************************/ + +/* Control register */ +#define CNTR ((__IO unsigned *)(RegBase + 0x40)) +/* Interrupt status register */ +#define ISTR ((__IO unsigned *)(RegBase + 0x44)) +/* Frame number register */ +#define FNR ((__IO unsigned *)(RegBase + 0x48)) +/* Device address register */ +#define DADDR ((__IO unsigned *)(RegBase + 0x4C)) +/* Buffer Table address register */ +#define BTABLE ((__IO unsigned *)(RegBase + 0x50)) +/******************************************************************************/ +/* Endpoint registers */ +/******************************************************************************/ +#define EP0REG ((__IO unsigned *)(RegBase)) /* endpoint 0 register address */ + +/* Endpoint Addresses (w/direction) */ +#define EP0_OUT ((uint8_t)0x00) +#define EP0_IN ((uint8_t)0x80) +#define EP1_OUT ((uint8_t)0x01) +#define EP1_IN ((uint8_t)0x81) +#define EP2_OUT ((uint8_t)0x02) +#define EP2_IN ((uint8_t)0x82) +#define EP3_OUT ((uint8_t)0x03) +#define EP3_IN ((uint8_t)0x83) +#define EP4_OUT ((uint8_t)0x04) +#define EP4_IN ((uint8_t)0x84) +#define EP5_OUT ((uint8_t)0x05) +#define EP5_IN ((uint8_t)0x85) +#define EP6_OUT ((uint8_t)0x06) +#define EP6_IN ((uint8_t)0x86) +#define EP7_OUT ((uint8_t)0x07) +#define EP7_IN ((uint8_t)0x87) + +/* endpoints enumeration */ +#define ENDP0 ((uint8_t)0) +#define ENDP1 ((uint8_t)1) +#define ENDP2 ((uint8_t)2) +#define ENDP3 ((uint8_t)3) +#define ENDP4 ((uint8_t)4) +#define ENDP5 ((uint8_t)5) +#define ENDP6 ((uint8_t)6) +#define ENDP7 ((uint8_t)7) + +/******************************************************************************/ +/* ISTR interrupt events */ +/******************************************************************************/ +#define ISTR_CTR (0x8000) /* Correct TRansfer (clear-only bit) */ +#define ISTR_DOVR (0x4000) /* DMA OVeR/underrun (clear-only bit) */ +#define ISTR_ERR (0x2000) /* ERRor (clear-only bit) */ +#define ISTR_WKUP (0x1000) /* WaKe UP (clear-only bit) */ +#define ISTR_SUSP (0x0800) /* SUSPend (clear-only bit) */ +#define ISTR_RESET (0x0400) /* RESET (clear-only bit) */ +#define ISTR_SOF (0x0200) /* Start Of Frame (clear-only bit) */ +#define ISTR_ESOF (0x0100) /* Expected Start Of Frame (clear-only bit) */ + + +#define ISTR_DIR (0x0010) /* DIRection of transaction (read-only bit) */ +#define ISTR_EP_ID (0x000F) /* EndPoint IDentifier (read-only bit) */ + +#define CLR_CTR (~ISTR_CTR) /* clear Correct TRansfer bit */ +#define CLR_DOVR (~ISTR_DOVR) /* clear DMA OVeR/underrun bit*/ +#define CLR_ERR (~ISTR_ERR) /* clear ERRor bit */ +#define CLR_WKUP (~ISTR_WKUP) /* clear WaKe UP bit */ +#define CLR_SUSP (~ISTR_SUSP) /* clear SUSPend bit */ +#define CLR_RESET (~ISTR_RESET) /* clear RESET bit */ +#define CLR_SOF (~ISTR_SOF) /* clear Start Of Frame bit */ +#define CLR_ESOF (~ISTR_ESOF) /* clear Expected Start Of Frame bit */ + +/******************************************************************************/ +/* CNTR control register bits definitions */ +/******************************************************************************/ +#define CNTR_CTRM (0x8000) /* Correct TRansfer Mask */ +#define CNTR_DOVRM (0x4000) /* DMA OVeR/underrun Mask */ +#define CNTR_ERRM (0x2000) /* ERRor Mask */ +#define CNTR_WKUPM (0x1000) /* WaKe UP Mask */ +#define CNTR_SUSPM (0x0800) /* SUSPend Mask */ +#define CNTR_RESETM (0x0400) /* RESET Mask */ +#define CNTR_SOFM (0x0200) /* Start Of Frame Mask */ +#define CNTR_ESOFM (0x0100) /* Expected Start Of Frame Mask */ + + +#define CNTR_RESUME (0x0010) /* RESUME request */ +#define CNTR_FSUSP (0x0008) /* Force SUSPend */ +#define CNTR_LPMODE (0x0004) /* Low-power MODE */ +#define CNTR_PDWN (0x0002) /* Power DoWN */ +#define CNTR_FRES (0x0001) /* Force USB RESet */ + +/******************************************************************************/ +/* FNR Frame Number Register bit definitions */ +/******************************************************************************/ +#define FNR_RXDP (0x8000) /* status of D+ data line */ +#define FNR_RXDM (0x4000) /* status of D- data line */ +#define FNR_LCK (0x2000) /* LoCKed */ +#define FNR_LSOF (0x1800) /* Lost SOF */ +#define FNR_FN (0x07FF) /* Frame Number */ +/******************************************************************************/ +/* DADDR Device ADDRess bit definitions */ +/******************************************************************************/ +#define DADDR_EF (0x80) +#define DADDR_ADD (0x7F) +/******************************************************************************/ +/* Endpoint register */ +/******************************************************************************/ +/* bit positions */ +#define EP_CTR_RX (0x8000) /* EndPoint Correct TRansfer RX */ +#define EP_DTOG_RX (0x4000) /* EndPoint Data TOGGLE RX */ +#define EPRX_STAT (0x3000) /* EndPoint RX STATus bit field */ +#define EP_SETUP (0x0800) /* EndPoint SETUP */ +#define EP_T_FIELD (0x0600) /* EndPoint TYPE */ +#define EP_KIND (0x0100) /* EndPoint KIND */ +#define EP_CTR_TX (0x0080) /* EndPoint Correct TRansfer TX */ +#define EP_DTOG_TX (0x0040) /* EndPoint Data TOGGLE TX */ +#define EPTX_STAT (0x0030) /* EndPoint TX STATus bit field */ +#define EPADDR_FIELD (0x000F) /* EndPoint ADDRess FIELD */ + +/* EndPoint REGister MASK (no toggle fields) */ +#define EPREG_MASK (EP_CTR_RX|EP_SETUP|EP_T_FIELD|EP_KIND|EP_CTR_TX|EPADDR_FIELD) + +/* EP_TYPE[1:0] EndPoint TYPE */ +#define EP_TYPE_MASK (0x0600) /* EndPoint TYPE Mask */ +#define EP_BULK (0x0000) /* EndPoint BULK */ +#define EP_CONTROL (0x0200) /* EndPoint CONTROL */ +#define EP_ISOCHRONOUS (0x0400) /* EndPoint ISOCHRONOUS */ +#define EP_INTERRUPT (0x0600) /* EndPoint INTERRUPT */ +#define EP_T_MASK (~EP_T_FIELD & EPREG_MASK) + + +/* EP_KIND EndPoint KIND */ +#define EPKIND_MASK (~EP_KIND & EPREG_MASK) + +/* STAT_TX[1:0] STATus for TX transfer */ +#define EP_TX_DIS (0x0000) /* EndPoint TX DISabled */ +#define EP_TX_STALL (0x0010) /* EndPoint TX STALLed */ +#define EP_TX_NAK (0x0020) /* EndPoint TX NAKed */ +#define EP_TX_VALID (0x0030) /* EndPoint TX VALID */ +#define EPTX_DTOG1 (0x0010) /* EndPoint TX Data TOGgle bit1 */ +#define EPTX_DTOG2 (0x0020) /* EndPoint TX Data TOGgle bit2 */ +#define EPTX_DTOGMASK (EPTX_STAT|EPREG_MASK) + +/* STAT_RX[1:0] STATus for RX transfer */ +#define EP_RX_DIS (0x0000) /* EndPoint RX DISabled */ +#define EP_RX_STALL (0x1000) /* EndPoint RX STALLed */ +#define EP_RX_NAK (0x2000) /* EndPoint RX NAKed */ +#define EP_RX_VALID (0x3000) /* EndPoint RX VALID */ +#define EPRX_DTOG1 (0x1000) /* EndPoint RX Data TOGgle bit1 */ +#define EPRX_DTOG2 (0x2000) /* EndPoint RX Data TOGgle bit1 */ +#define EPRX_DTOGMASK (EPRX_STAT|EPREG_MASK) +/* Exported macro ------------------------------------------------------------*/ +/* SetCNTR */ +#define _SetCNTR(wRegValue) (*CNTR = (uint16_t)wRegValue) + +/* SetISTR */ +#define _SetISTR(wRegValue) (*ISTR = (uint16_t)wRegValue) + +/* SetDADDR */ +#define _SetDADDR(wRegValue) (*DADDR = (uint16_t)wRegValue) + +/* SetBTABLE */ +#define _SetBTABLE(wRegValue)(*BTABLE = (uint16_t)(wRegValue & 0xFFF8)) + +/* GetCNTR */ +#define _GetCNTR() ((uint16_t) *CNTR) + +/* GetISTR */ +#define _GetISTR() ((uint16_t) *ISTR) + +/* GetFNR */ +#define _GetFNR() ((uint16_t) *FNR) + +/* GetDADDR */ +#define _GetDADDR() ((uint16_t) *DADDR) + +/* GetBTABLE */ +#define _GetBTABLE() ((uint16_t) *BTABLE) + +/* SetENDPOINT */ +#define _SetENDPOINT(bEpNum,wRegValue) (*(EP0REG + bEpNum)= \ + (uint16_t)wRegValue) + +/* GetENDPOINT */ +#define _GetENDPOINT(bEpNum) ((uint16_t)(*(EP0REG + bEpNum))) + +/******************************************************************************* +* Macro Name : SetEPType +* Description : sets the type in the endpoint register(bits EP_TYPE[1:0]) +* Input : bEpNum: Endpoint Number. +* wType +* Output : None. +* Return : None. +*******************************************************************************/ +#define _SetEPType(bEpNum,wType) (_SetENDPOINT(bEpNum,\ + ((_GetENDPOINT(bEpNum) & EP_T_MASK) | wType ))) + +/******************************************************************************* +* Macro Name : GetEPType +* Description : gets the type in the endpoint register(bits EP_TYPE[1:0]) +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : Endpoint Type +*******************************************************************************/ +#define _GetEPType(bEpNum) (_GetENDPOINT(bEpNum) & EP_T_FIELD) + +/******************************************************************************* +* Macro Name : SetEPTxStatus +* Description : sets the status for tx transfer (bits STAT_TX[1:0]). +* Input : bEpNum: Endpoint Number. +* wState: new state +* Output : None. +* Return : None. +*******************************************************************************/ +#define _SetEPTxStatus(bEpNum,wState) {\ + register uint16_t _wRegVal; \ + _wRegVal = _GetENDPOINT(bEpNum) & EPTX_DTOGMASK;\ + /* toggle first bit ? */ \ + if((EPTX_DTOG1 & wState)!= 0) \ + _wRegVal ^= EPTX_DTOG1; \ + /* toggle second bit ? */ \ + if((EPTX_DTOG2 & wState)!= 0) \ + _wRegVal ^= EPTX_DTOG2; \ + _SetENDPOINT(bEpNum, (_wRegVal | EP_CTR_RX|EP_CTR_TX)); \ + } /* _SetEPTxStatus */ + +/******************************************************************************* +* Macro Name : SetEPRxStatus +* Description : sets the status for rx transfer (bits STAT_TX[1:0]) +* Input : bEpNum: Endpoint Number. +* wState: new state. +* Output : None. +* Return : None. +*******************************************************************************/ +#define _SetEPRxStatus(bEpNum,wState) {\ + register uint16_t _wRegVal; \ + \ + _wRegVal = _GetENDPOINT(bEpNum) & EPRX_DTOGMASK;\ + /* toggle first bit ? */ \ + if((EPRX_DTOG1 & wState)!= 0) \ + _wRegVal ^= EPRX_DTOG1; \ + /* toggle second bit ? */ \ + if((EPRX_DTOG2 & wState)!= 0) \ + _wRegVal ^= EPRX_DTOG2; \ + _SetENDPOINT(bEpNum, (_wRegVal | EP_CTR_RX|EP_CTR_TX)); \ + } /* _SetEPRxStatus */ + +/******************************************************************************* +* Macro Name : SetEPRxTxStatus +* Description : sets the status for rx & tx (bits STAT_TX[1:0] & STAT_RX[1:0]) +* Input : bEpNum: Endpoint Number. +* wStaterx: new state. +* wStatetx: new state. +* Output : None. +* Return : None. +*******************************************************************************/ +#define _SetEPRxTxStatus(bEpNum,wStaterx,wStatetx) {\ + register uint32_t _wRegVal; \ + \ + _wRegVal = _GetENDPOINT(bEpNum) & (EPRX_DTOGMASK |EPTX_STAT) ;\ + /* toggle first bit ? */ \ + if((EPRX_DTOG1 & wStaterx)!= 0) \ + _wRegVal ^= EPRX_DTOG1; \ + /* toggle second bit ? */ \ + if((EPRX_DTOG2 & wStaterx)!= 0) \ + _wRegVal ^= EPRX_DTOG2; \ + /* toggle first bit ? */ \ + if((EPTX_DTOG1 & wStatetx)!= 0) \ + _wRegVal ^= EPTX_DTOG1; \ + /* toggle second bit ? */ \ + if((EPTX_DTOG2 & wStatetx)!= 0) \ + _wRegVal ^= EPTX_DTOG2; \ + _SetENDPOINT(bEpNum, _wRegVal | EP_CTR_RX|EP_CTR_TX); \ + } /* _SetEPRxTxStatus */ +/******************************************************************************* +* Macro Name : GetEPTxStatus / GetEPRxStatus +* Description : gets the status for tx/rx transfer (bits STAT_TX[1:0] +* /STAT_RX[1:0]) +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : status . +*******************************************************************************/ +#define _GetEPTxStatus(bEpNum) ((uint16_t)_GetENDPOINT(bEpNum) & EPTX_STAT) + +#define _GetEPRxStatus(bEpNum) ((uint16_t)_GetENDPOINT(bEpNum) & EPRX_STAT) + +/******************************************************************************* +* Macro Name : SetEPTxValid / SetEPRxValid +* Description : sets directly the VALID tx/rx-status into the enpoint register +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : None. +*******************************************************************************/ +#define _SetEPTxValid(bEpNum) (_SetEPTxStatus(bEpNum, EP_TX_VALID)) + +#define _SetEPRxValid(bEpNum) (_SetEPRxStatus(bEpNum, EP_RX_VALID)) + +/******************************************************************************* +* Macro Name : GetTxStallStatus / GetRxStallStatus. +* Description : checks stall condition in an endpoint. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : TRUE = endpoint in stall condition. +*******************************************************************************/ +#define _GetTxStallStatus(bEpNum) (_GetEPTxStatus(bEpNum) \ + == EP_TX_STALL) +#define _GetRxStallStatus(bEpNum) (_GetEPRxStatus(bEpNum) \ + == EP_RX_STALL) + +/******************************************************************************* +* Macro Name : SetEP_KIND / ClearEP_KIND. +* Description : set & clear EP_KIND bit. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : None. +*******************************************************************************/ +#define _SetEP_KIND(bEpNum) (_SetENDPOINT(bEpNum, \ + (EP_CTR_RX|EP_CTR_TX|((_GetENDPOINT(bEpNum) | EP_KIND) & EPREG_MASK)))) +#define _ClearEP_KIND(bEpNum) (_SetENDPOINT(bEpNum, \ + (EP_CTR_RX|EP_CTR_TX|(_GetENDPOINT(bEpNum) & EPKIND_MASK)))) + +/******************************************************************************* +* Macro Name : Set_Status_Out / Clear_Status_Out. +* Description : Sets/clears directly STATUS_OUT bit in the endpoint register. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : None. +*******************************************************************************/ +#define _Set_Status_Out(bEpNum) _SetEP_KIND(bEpNum) +#define _Clear_Status_Out(bEpNum) _ClearEP_KIND(bEpNum) + +/******************************************************************************* +* Macro Name : SetEPDoubleBuff / ClearEPDoubleBuff. +* Description : Sets/clears directly EP_KIND bit in the endpoint register. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : None. +*******************************************************************************/ +#define _SetEPDoubleBuff(bEpNum) _SetEP_KIND(bEpNum) +#define _ClearEPDoubleBuff(bEpNum) _ClearEP_KIND(bEpNum) + +/******************************************************************************* +* Macro Name : ClearEP_CTR_RX / ClearEP_CTR_TX. +* Description : Clears bit CTR_RX / CTR_TX in the endpoint register. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : None. +*******************************************************************************/ +#define _ClearEP_CTR_RX(bEpNum) (_SetENDPOINT(bEpNum,\ + _GetENDPOINT(bEpNum) & 0x7FFF & EPREG_MASK)) +#define _ClearEP_CTR_TX(bEpNum) (_SetENDPOINT(bEpNum,\ + _GetENDPOINT(bEpNum) & 0xFF7F & EPREG_MASK)) + +/******************************************************************************* +* Macro Name : ToggleDTOG_RX / ToggleDTOG_TX . +* Description : Toggles DTOG_RX / DTOG_TX bit in the endpoint register. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : None. +*******************************************************************************/ +#define _ToggleDTOG_RX(bEpNum) (_SetENDPOINT(bEpNum, \ + EP_CTR_RX|EP_CTR_TX|EP_DTOG_RX | (_GetENDPOINT(bEpNum) & EPREG_MASK))) +#define _ToggleDTOG_TX(bEpNum) (_SetENDPOINT(bEpNum, \ + EP_CTR_RX|EP_CTR_TX|EP_DTOG_TX | (_GetENDPOINT(bEpNum) & EPREG_MASK))) + +/******************************************************************************* +* Macro Name : ClearDTOG_RX / ClearDTOG_TX. +* Description : Clears DTOG_RX / DTOG_TX bit in the endpoint register. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : None. +*******************************************************************************/ +#define _ClearDTOG_RX(bEpNum) if((_GetENDPOINT(bEpNum) & EP_DTOG_RX) != 0)\ + _ToggleDTOG_RX(bEpNum) +#define _ClearDTOG_TX(bEpNum) if((_GetENDPOINT(bEpNum) & EP_DTOG_TX) != 0)\ + _ToggleDTOG_TX(bEpNum) +/******************************************************************************* +* Macro Name : SetEPAddress. +* Description : Sets address in an endpoint register. +* Input : bEpNum: Endpoint Number. +* bAddr: Address. +* Output : None. +* Return : None. +*******************************************************************************/ +#define _SetEPAddress(bEpNum,bAddr) _SetENDPOINT(bEpNum,\ + EP_CTR_RX|EP_CTR_TX|(_GetENDPOINT(bEpNum) & EPREG_MASK) | bAddr) + +/******************************************************************************* +* Macro Name : GetEPAddress. +* Description : Gets address in an endpoint register. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : None. +*******************************************************************************/ +#define _GetEPAddress(bEpNum) ((uint8_t)(_GetENDPOINT(bEpNum) & EPADDR_FIELD)) + +#define _pEPTxAddr(bEpNum) ((uint32_t *)((_GetBTABLE()+bEpNum*8 )*2 + PMAAddr)) +#define _pEPTxCount(bEpNum) ((uint32_t *)((_GetBTABLE()+bEpNum*8+2)*2 + PMAAddr)) +#define _pEPRxAddr(bEpNum) ((uint32_t *)((_GetBTABLE()+bEpNum*8+4)*2 + PMAAddr)) +#define _pEPRxCount(bEpNum) ((uint32_t *)((_GetBTABLE()+bEpNum*8+6)*2 + PMAAddr)) + +/******************************************************************************* +* Macro Name : SetEPTxAddr / SetEPRxAddr. +* Description : sets address of the tx/rx buffer. +* Input : bEpNum: Endpoint Number. +* wAddr: address to be set (must be word aligned). +* Output : None. +* Return : None. +*******************************************************************************/ +#define _SetEPTxAddr(bEpNum,wAddr) (*_pEPTxAddr(bEpNum) = ((wAddr >> 1) << 1)) +#define _SetEPRxAddr(bEpNum,wAddr) (*_pEPRxAddr(bEpNum) = ((wAddr >> 1) << 1)) + +/******************************************************************************* +* Macro Name : GetEPTxAddr / GetEPRxAddr. +* Description : Gets address of the tx/rx buffer. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : address of the buffer. +*******************************************************************************/ +#define _GetEPTxAddr(bEpNum) ((uint16_t)*_pEPTxAddr(bEpNum)) +#define _GetEPRxAddr(bEpNum) ((uint16_t)*_pEPRxAddr(bEpNum)) + +/******************************************************************************* +* Macro Name : SetEPCountRxReg. +* Description : Sets counter of rx buffer with no. of blocks. +* Input : pdwReg: pointer to counter. +* wCount: Counter. +* Output : None. +* Return : None. +*******************************************************************************/ +#define _BlocksOf32(dwReg,wCount,wNBlocks) {\ + wNBlocks = wCount >> 5;\ + if((wCount & 0x1f) == 0)\ + wNBlocks--;\ + *pdwReg = (uint32_t)((wNBlocks << 10) | 0x8000);\ + }/* _BlocksOf32 */ + +#define _BlocksOf2(dwReg,wCount,wNBlocks) {\ + wNBlocks = wCount >> 1;\ + if((wCount & 0x1) != 0)\ + wNBlocks++;\ + *pdwReg = (uint32_t)(wNBlocks << 10);\ + }/* _BlocksOf2 */ + +#define _SetEPCountRxReg(dwReg,wCount) {\ + uint16_t wNBlocks;\ + if(wCount > 62){_BlocksOf32(dwReg,wCount,wNBlocks);}\ + else {_BlocksOf2(dwReg,wCount,wNBlocks);}\ + }/* _SetEPCountRxReg */ + + + +#define _SetEPRxDblBuf0Count(bEpNum,wCount) {\ + uint32_t *pdwReg = _pEPTxCount(bEpNum); \ + _SetEPCountRxReg(pdwReg, wCount);\ + } +/******************************************************************************* +* Macro Name : SetEPTxCount / SetEPRxCount. +* Description : sets counter for the tx/rx buffer. +* Input : bEpNum: endpoint number. +* wCount: Counter value. +* Output : None. +* Return : None. +*******************************************************************************/ +#define _SetEPTxCount(bEpNum,wCount) (*_pEPTxCount(bEpNum) = wCount) +#define _SetEPRxCount(bEpNum,wCount) {\ + uint32_t *pdwReg = _pEPRxCount(bEpNum); \ + _SetEPCountRxReg(pdwReg, wCount);\ + } +/******************************************************************************* +* Macro Name : GetEPTxCount / GetEPRxCount. +* Description : gets counter of the tx buffer. +* Input : bEpNum: endpoint number. +* Output : None. +* Return : Counter value. +*******************************************************************************/ +#define _GetEPTxCount(bEpNum)((uint16_t)(*_pEPTxCount(bEpNum)) & 0x3ff) +#define _GetEPRxCount(bEpNum)((uint16_t)(*_pEPRxCount(bEpNum)) & 0x3ff) + +/******************************************************************************* +* Macro Name : SetEPDblBuf0Addr / SetEPDblBuf1Addr. +* Description : Sets buffer 0/1 address in a double buffer endpoint. +* Input : bEpNum: endpoint number. +* : wBuf0Addr: buffer 0 address. +* Output : None. +* Return : None. +*******************************************************************************/ +#define _SetEPDblBuf0Addr(bEpNum,wBuf0Addr) {_SetEPTxAddr(bEpNum, wBuf0Addr);} +#define _SetEPDblBuf1Addr(bEpNum,wBuf1Addr) {_SetEPRxAddr(bEpNum, wBuf1Addr);} + +/******************************************************************************* +* Macro Name : SetEPDblBuffAddr. +* Description : Sets addresses in a double buffer endpoint. +* Input : bEpNum: endpoint number. +* : wBuf0Addr: buffer 0 address. +* : wBuf1Addr = buffer 1 address. +* Output : None. +* Return : None. +*******************************************************************************/ +#define _SetEPDblBuffAddr(bEpNum,wBuf0Addr,wBuf1Addr) { \ + _SetEPDblBuf0Addr(bEpNum, wBuf0Addr);\ + _SetEPDblBuf1Addr(bEpNum, wBuf1Addr);\ + } /* _SetEPDblBuffAddr */ + +/******************************************************************************* +* Macro Name : GetEPDblBuf0Addr / GetEPDblBuf1Addr. +* Description : Gets buffer 0/1 address of a double buffer endpoint. +* Input : bEpNum: endpoint number. +* Output : None. +* Return : None. +*******************************************************************************/ +#define _GetEPDblBuf0Addr(bEpNum) (_GetEPTxAddr(bEpNum)) +#define _GetEPDblBuf1Addr(bEpNum) (_GetEPRxAddr(bEpNum)) + +/******************************************************************************* +* Macro Name : SetEPDblBuffCount / SetEPDblBuf0Count / SetEPDblBuf1Count. +* Description : Gets buffer 0/1 address of a double buffer endpoint. +* Input : bEpNum: endpoint number. +* : bDir: endpoint dir EP_DBUF_OUT = OUT +* EP_DBUF_IN = IN +* : wCount: Counter value +* Output : None. +* Return : None. +*******************************************************************************/ +#define _SetEPDblBuf0Count(bEpNum, bDir, wCount) { \ + if(bDir == EP_DBUF_OUT)\ + /* OUT endpoint */ \ + {_SetEPRxDblBuf0Count(bEpNum,wCount);} \ + else if(bDir == EP_DBUF_IN)\ + /* IN endpoint */ \ + *_pEPTxCount(bEpNum) = (uint32_t)wCount; \ + } /* SetEPDblBuf0Count*/ + +#define _SetEPDblBuf1Count(bEpNum, bDir, wCount) { \ + if(bDir == EP_DBUF_OUT)\ + /* OUT endpoint */ \ + {_SetEPRxCount(bEpNum,wCount);}\ + else if(bDir == EP_DBUF_IN)\ + /* IN endpoint */\ + *_pEPRxCount(bEpNum) = (uint32_t)wCount; \ + } /* SetEPDblBuf1Count */ + +#define _SetEPDblBuffCount(bEpNum, bDir, wCount) {\ + _SetEPDblBuf0Count(bEpNum, bDir, wCount); \ + _SetEPDblBuf1Count(bEpNum, bDir, wCount); \ + } /* _SetEPDblBuffCount */ + +/******************************************************************************* +* Macro Name : GetEPDblBuf0Count / GetEPDblBuf1Count. +* Description : Gets buffer 0/1 rx/tx counter for double buffering. +* Input : bEpNum: endpoint number. +* Output : None. +* Return : None. +*******************************************************************************/ +#define _GetEPDblBuf0Count(bEpNum) (_GetEPTxCount(bEpNum)) +#define _GetEPDblBuf1Count(bEpNum) (_GetEPRxCount(bEpNum)) + + +/* External variables --------------------------------------------------------*/ +extern __IO uint16_t wIstr; /* ISTR register last read value */ + +/* Exported functions ------------------------------------------------------- */ +void SetCNTR(uint16_t /*wRegValue*/); +void SetISTR(uint16_t /*wRegValue*/); +void SetDADDR(uint16_t /*wRegValue*/); +void SetBTABLE(uint16_t /*wRegValue*/); +void SetBTABLE(uint16_t /*wRegValue*/); +uint16_t GetCNTR(void); +uint16_t GetISTR(void); +uint16_t GetFNR(void); +uint16_t GetDADDR(void); +uint16_t GetBTABLE(void); +void SetENDPOINT(uint8_t /*bEpNum*/, uint16_t /*wRegValue*/); +uint16_t GetENDPOINT(uint8_t /*bEpNum*/); +void SetEPType(uint8_t /*bEpNum*/, uint16_t /*wType*/); +uint16_t GetEPType(uint8_t /*bEpNum*/); +void SetEPTxStatus(uint8_t /*bEpNum*/, uint16_t /*wState*/); +void SetEPRxStatus(uint8_t /*bEpNum*/, uint16_t /*wState*/); +void SetDouBleBuffEPStall(uint8_t /*bEpNum*/, uint8_t bDir); +uint16_t GetEPTxStatus(uint8_t /*bEpNum*/); +uint16_t GetEPRxStatus(uint8_t /*bEpNum*/); +void SetEPTxValid(uint8_t /*bEpNum*/); +void SetEPRxValid(uint8_t /*bEpNum*/); +uint16_t GetTxStallStatus(uint8_t /*bEpNum*/); +uint16_t GetRxStallStatus(uint8_t /*bEpNum*/); +void SetEP_KIND(uint8_t /*bEpNum*/); +void ClearEP_KIND(uint8_t /*bEpNum*/); +void Set_Status_Out(uint8_t /*bEpNum*/); +void Clear_Status_Out(uint8_t /*bEpNum*/); +void SetEPDoubleBuff(uint8_t /*bEpNum*/); +void ClearEPDoubleBuff(uint8_t /*bEpNum*/); +void ClearEP_CTR_RX(uint8_t /*bEpNum*/); +void ClearEP_CTR_TX(uint8_t /*bEpNum*/); +void ToggleDTOG_RX(uint8_t /*bEpNum*/); +void ToggleDTOG_TX(uint8_t /*bEpNum*/); +void ClearDTOG_RX(uint8_t /*bEpNum*/); +void ClearDTOG_TX(uint8_t /*bEpNum*/); +void SetEPAddress(uint8_t /*bEpNum*/, uint8_t /*bAddr*/); +uint8_t GetEPAddress(uint8_t /*bEpNum*/); +void SetEPTxAddr(uint8_t /*bEpNum*/, uint16_t /*wAddr*/); +void SetEPRxAddr(uint8_t /*bEpNum*/, uint16_t /*wAddr*/); +uint16_t GetEPTxAddr(uint8_t /*bEpNum*/); +uint16_t GetEPRxAddr(uint8_t /*bEpNum*/); +void SetEPCountRxReg(uint32_t * /*pdwReg*/, uint16_t /*wCount*/); +void SetEPTxCount(uint8_t /*bEpNum*/, uint16_t /*wCount*/); +void SetEPRxCount(uint8_t /*bEpNum*/, uint16_t /*wCount*/); +uint16_t GetEPTxCount(uint8_t /*bEpNum*/); +uint16_t GetEPRxCount(uint8_t /*bEpNum*/); +void SetEPDblBuf0Addr(uint8_t /*bEpNum*/, uint16_t /*wBuf0Addr*/); +void SetEPDblBuf1Addr(uint8_t /*bEpNum*/, uint16_t /*wBuf1Addr*/); +void SetEPDblBuffAddr(uint8_t /*bEpNum*/, uint16_t /*wBuf0Addr*/, uint16_t /*wBuf1Addr*/); +uint16_t GetEPDblBuf0Addr(uint8_t /*bEpNum*/); +uint16_t GetEPDblBuf1Addr(uint8_t /*bEpNum*/); +void SetEPDblBuffCount(uint8_t /*bEpNum*/, uint8_t /*bDir*/, uint16_t /*wCount*/); +void SetEPDblBuf0Count(uint8_t /*bEpNum*/, uint8_t /*bDir*/, uint16_t /*wCount*/); +void SetEPDblBuf1Count(uint8_t /*bEpNum*/, uint8_t /*bDir*/, uint16_t /*wCount*/); +uint16_t GetEPDblBuf0Count(uint8_t /*bEpNum*/); +uint16_t GetEPDblBuf1Count(uint8_t /*bEpNum*/); +EP_DBUF_DIR GetEPDblBufDir(uint8_t /*bEpNum*/); +void FreeUserBuffer(uint8_t bEpNum/*bEpNum*/, uint8_t bDir); +uint16_t ToWord(uint8_t, uint8_t); +uint16_t ByteSwap(uint16_t); + +#endif /* __USB_REGS_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/inc/usb_sil.h b/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/inc/usb_sil.h new file mode 100755 index 0000000000..5548175290 --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/inc/usb_sil.h @@ -0,0 +1,47 @@ +/** + ****************************************************************************** + * @file usb_sil.h + * @author MCD Application Team + * @version V4.0.0 + * @date 28-August-2012 + * @brief Simplified Interface Layer function prototypes. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2012 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USB_SIL_H +#define __USB_SIL_H + +/* Includes ------------------------------------------------------------------*/ +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions ------------------------------------------------------- */ + +uint32_t USB_SIL_Init(void); +uint32_t USB_SIL_Write(uint8_t bEpAddr, uint8_t* pBufferPointer, uint32_t wBufferSize); +uint32_t USB_SIL_Read(uint8_t bEpAddr, uint8_t* pBufferPointer); + +/* External variables --------------------------------------------------------*/ + +#endif /* __USB_SIL_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/inc/usb_type.h b/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/inc/usb_type.h new file mode 100755 index 0000000000..21e16700c8 --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/inc/usb_type.h @@ -0,0 +1,54 @@ +/** + ****************************************************************************** + * @file usb_type.h + * @author MCD Application Team + * @version V4.0.0 + * @date 28-August-2012 + * @brief Type definitions used by the USB Library + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2012 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USB_TYPE_H +#define __USB_TYPE_H + +/* Includes ------------------------------------------------------------------*/ +#include "usb_conf.h" + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ +#ifndef NULL +#define NULL ((void *)0) +#endif + +typedef enum +{ + FALSE = 0, TRUE = !FALSE +} +bool; + +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions ------------------------------------------------------- */ +/* External variables --------------------------------------------------------*/ + +#endif /* __USB_TYPE_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/src/usb_core.c b/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/src/usb_core.c new file mode 100755 index 0000000000..3231a96221 --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/src/usb_core.c @@ -0,0 +1,1033 @@ +/** + ****************************************************************************** + * @file usb_core.c + * @author MCD Application Team + * @version V4.0.0 + * @date 28-August-2012 + * @brief Standard protocol processing (USB v2.0) + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2012 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + + +/* Includes ------------------------------------------------------------------*/ +#include "usb_lib.h" +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +#define ValBit(VAR,Place) (VAR & (1 << Place)) +#define SetBit(VAR,Place) (VAR |= (1 << Place)) +#define ClrBit(VAR,Place) (VAR &= ((1 << Place) ^ 255)) +#define Send0LengthData() { _SetEPTxCount(ENDP0, 0); \ + vSetEPTxStatus(EP_TX_VALID); \ + } + +#define vSetEPRxStatus(st) (SaveRState = st) +#define vSetEPTxStatus(st) (SaveTState = st) + +#define USB_StatusIn() Send0LengthData() +#define USB_StatusOut() vSetEPRxStatus(EP_RX_VALID) + +#define StatusInfo0 StatusInfo.bw.bb1 /* Reverse bb0 & bb1 */ +#define StatusInfo1 StatusInfo.bw.bb0 + +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +uint16_t_uint8_t StatusInfo; + +bool Data_Mul_MaxPacketSize = FALSE; +/* Private function prototypes -----------------------------------------------*/ +static void DataStageOut(void); +static void DataStageIn(void); +static void NoData_Setup0(void); +static void Data_Setup0(void); +/* Private functions ---------------------------------------------------------*/ + +/******************************************************************************* +* Function Name : Standard_GetConfiguration. +* Description : Return the current configuration variable address. +* Input : Length - How many bytes are needed. +* Output : None. +* Return : Return 1 , if the request is invalid when "Length" is 0. +* Return "Buffer" if the "Length" is not 0. +*******************************************************************************/ +uint8_t *Standard_GetConfiguration(uint16_t Length) +{ + if (Length == 0) + { + pInformation->Ctrl_Info.Usb_wLength = + sizeof(pInformation->Current_Configuration); + return 0; + } + pUser_Standard_Requests->User_GetConfiguration(); + return (uint8_t *)&pInformation->Current_Configuration; +} + +/******************************************************************************* +* Function Name : Standard_SetConfiguration. +* Description : This routine is called to set the configuration value +* Then each class should configure device itself. +* Input : None. +* Output : None. +* Return : Return USB_SUCCESS, if the request is performed. +* Return USB_UNSUPPORT, if the request is invalid. +*******************************************************************************/ +RESULT Standard_SetConfiguration(void) +{ + + if ((pInformation->USBwValue0 <= + Device_Table.Total_Configuration) && (pInformation->USBwValue1 == 0) + && (pInformation->USBwIndex == 0)) /*call Back usb spec 2.0*/ + { + pInformation->Current_Configuration = pInformation->USBwValue0; + pUser_Standard_Requests->User_SetConfiguration(); + return USB_SUCCESS; + } + else + { + return USB_UNSUPPORT; + } +} + +/******************************************************************************* +* Function Name : Standard_GetInterface. +* Description : Return the Alternate Setting of the current interface. +* Input : Length - How many bytes are needed. +* Output : None. +* Return : Return 0, if the request is invalid when "Length" is 0. +* Return "Buffer" if the "Length" is not 0. +*******************************************************************************/ +uint8_t *Standard_GetInterface(uint16_t Length) +{ + if (Length == 0) + { + pInformation->Ctrl_Info.Usb_wLength = + sizeof(pInformation->Current_AlternateSetting); + return 0; + } + pUser_Standard_Requests->User_GetInterface(); + return (uint8_t *)&pInformation->Current_AlternateSetting; +} + +/******************************************************************************* +* Function Name : Standard_SetInterface. +* Description : This routine is called to set the interface. +* Then each class should configure the interface them self. +* Input : None. +* Output : None. +* Return : - Return USB_SUCCESS, if the request is performed. +* - Return USB_UNSUPPORT, if the request is invalid. +*******************************************************************************/ +RESULT Standard_SetInterface(void) +{ + RESULT Re; + /*Test if the specified Interface and Alternate Setting are supported by + the application Firmware*/ + Re = (*pProperty->Class_Get_Interface_Setting)(pInformation->USBwIndex0, pInformation->USBwValue0); + + if (pInformation->Current_Configuration != 0) + { + if ((Re != USB_SUCCESS) || (pInformation->USBwIndex1 != 0) + || (pInformation->USBwValue1 != 0)) + { + return USB_UNSUPPORT; + } + else if (Re == USB_SUCCESS) + { + pUser_Standard_Requests->User_SetInterface(); + pInformation->Current_Interface = pInformation->USBwIndex0; + pInformation->Current_AlternateSetting = pInformation->USBwValue0; + return USB_SUCCESS; + } + + } + + return USB_UNSUPPORT; +} + +/******************************************************************************* +* Function Name : Standard_GetStatus. +* Description : Copy the device request data to "StatusInfo buffer". +* Input : - Length - How many bytes are needed. +* Output : None. +* Return : Return 0, if the request is at end of data block, +* or is invalid when "Length" is 0. +*******************************************************************************/ +uint8_t *Standard_GetStatus(uint16_t Length) +{ + if (Length == 0) + { + pInformation->Ctrl_Info.Usb_wLength = 2; + return 0; + } + + /* Reset Status Information */ + StatusInfo.w = 0; + + if (Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT)) + { + /*Get Device Status */ + uint8_t Feature = pInformation->Current_Feature; + + /* Remote Wakeup enabled */ + if (ValBit(Feature, 5)) + { + SetBit(StatusInfo0, 1); + } + else + { + ClrBit(StatusInfo0, 1); + } + + /* Bus-powered */ + if (ValBit(Feature, 6)) + { + SetBit(StatusInfo0, 0); + } + else /* Self-powered */ + { + ClrBit(StatusInfo0, 0); + } + } + /*Interface Status*/ + else if (Type_Recipient == (STANDARD_REQUEST | INTERFACE_RECIPIENT)) + { + return (uint8_t *)&StatusInfo; + } + /*Get EndPoint Status*/ + else if (Type_Recipient == (STANDARD_REQUEST | ENDPOINT_RECIPIENT)) + { + uint8_t Related_Endpoint; + uint8_t wIndex0 = pInformation->USBwIndex0; + + Related_Endpoint = (wIndex0 & 0x0f); + if (ValBit(wIndex0, 7)) + { + /* IN endpoint */ + if (_GetTxStallStatus(Related_Endpoint)) + { + SetBit(StatusInfo0, 0); /* IN Endpoint stalled */ + } + } + else + { + /* OUT endpoint */ + if (_GetRxStallStatus(Related_Endpoint)) + { + SetBit(StatusInfo0, 0); /* OUT Endpoint stalled */ + } + } + + } + else + { + return NULL; + } + pUser_Standard_Requests->User_GetStatus(); + return (uint8_t *)&StatusInfo; +} + +/******************************************************************************* +* Function Name : Standard_ClearFeature. +* Description : Clear or disable a specific feature. +* Input : None. +* Output : None. +* Return : - Return USB_SUCCESS, if the request is performed. +* - Return USB_UNSUPPORT, if the request is invalid. +*******************************************************************************/ +RESULT Standard_ClearFeature(void) +{ + uint32_t Type_Rec = Type_Recipient; + uint32_t Status; + + + if (Type_Rec == (STANDARD_REQUEST | DEVICE_RECIPIENT)) + {/*Device Clear Feature*/ + ClrBit(pInformation->Current_Feature, 5); + return USB_SUCCESS; + } + else if (Type_Rec == (STANDARD_REQUEST | ENDPOINT_RECIPIENT)) + {/*EndPoint Clear Feature*/ + DEVICE* pDev; + uint32_t Related_Endpoint; + uint32_t wIndex0; + uint32_t rEP; + + if ((pInformation->USBwValue != ENDPOINT_STALL) + || (pInformation->USBwIndex1 != 0)) + { + return USB_UNSUPPORT; + } + + pDev = &Device_Table; + wIndex0 = pInformation->USBwIndex0; + rEP = wIndex0 & ~0x80; + Related_Endpoint = ENDP0 + rEP; + + if (ValBit(pInformation->USBwIndex0, 7)) + { + /*Get Status of endpoint & stall the request if the related_ENdpoint + is Disabled*/ + Status = _GetEPTxStatus(Related_Endpoint); + } + else + { + Status = _GetEPRxStatus(Related_Endpoint); + } + + if ((rEP >= pDev->Total_Endpoint) || (Status == 0) + || (pInformation->Current_Configuration == 0)) + { + return USB_UNSUPPORT; + } + + + if (wIndex0 & 0x80) + { + /* IN endpoint */ + if (_GetTxStallStatus(Related_Endpoint )) + { + ClearDTOG_TX(Related_Endpoint); + SetEPTxStatus(Related_Endpoint, EP_TX_VALID); + } + } + else + { + /* OUT endpoint */ + if (_GetRxStallStatus(Related_Endpoint)) + { + if (Related_Endpoint == ENDP0) + { + /* After clear the STALL, enable the default endpoint receiver */ + SetEPRxCount(Related_Endpoint, Device_Property.MaxPacketSize); + _SetEPRxStatus(Related_Endpoint, EP_RX_VALID); + } + else + { + ClearDTOG_RX(Related_Endpoint); + _SetEPRxStatus(Related_Endpoint, EP_RX_VALID); + } + } + } + pUser_Standard_Requests->User_ClearFeature(); + return USB_SUCCESS; + } + + return USB_UNSUPPORT; +} + +/******************************************************************************* +* Function Name : Standard_SetEndPointFeature +* Description : Set or enable a specific feature of EndPoint +* Input : None. +* Output : None. +* Return : - Return USB_SUCCESS, if the request is performed. +* - Return USB_UNSUPPORT, if the request is invalid. +*******************************************************************************/ +RESULT Standard_SetEndPointFeature(void) +{ + uint32_t wIndex0; + uint32_t Related_Endpoint; + uint32_t rEP; + uint32_t Status; + + wIndex0 = pInformation->USBwIndex0; + rEP = wIndex0 & ~0x80; + Related_Endpoint = ENDP0 + rEP; + + if (ValBit(pInformation->USBwIndex0, 7)) + { + /* get Status of endpoint & stall the request if the related_ENdpoint + is Disabled*/ + Status = _GetEPTxStatus(Related_Endpoint); + } + else + { + Status = _GetEPRxStatus(Related_Endpoint); + } + + if (Related_Endpoint >= Device_Table.Total_Endpoint + || pInformation->USBwValue != 0 || Status == 0 + || pInformation->Current_Configuration == 0) + { + return USB_UNSUPPORT; + } + else + { + if (wIndex0 & 0x80) + { + /* IN endpoint */ + _SetEPTxStatus(Related_Endpoint, EP_TX_STALL); + } + + else + { + /* OUT endpoint */ + _SetEPRxStatus(Related_Endpoint, EP_RX_STALL); + } + } + pUser_Standard_Requests->User_SetEndPointFeature(); + return USB_SUCCESS; +} + +/******************************************************************************* +* Function Name : Standard_SetDeviceFeature. +* Description : Set or enable a specific feature of Device. +* Input : None. +* Output : None. +* Return : - Return USB_SUCCESS, if the request is performed. +* - Return USB_UNSUPPORT, if the request is invalid. +*******************************************************************************/ +RESULT Standard_SetDeviceFeature(void) +{ + SetBit(pInformation->Current_Feature, 5); + pUser_Standard_Requests->User_SetDeviceFeature(); + return USB_SUCCESS; +} + +/******************************************************************************* +* Function Name : Standard_GetDescriptorData. +* Description : Standard_GetDescriptorData is used for descriptors transfer. +* : This routine is used for the descriptors resident in Flash +* or RAM +* pDesc can be in either Flash or RAM +* The purpose of this routine is to have a versatile way to +* response descriptors request. It allows user to generate +* certain descriptors with software or read descriptors from +* external storage part by part. +* Input : - Length - Length of the data in this transfer. +* - pDesc - A pointer points to descriptor struct. +* The structure gives the initial address of the descriptor and +* its original size. +* Output : None. +* Return : Address of a part of the descriptor pointed by the Usb_ +* wOffset The buffer pointed by this address contains at least +* Length bytes. +*******************************************************************************/ +uint8_t *Standard_GetDescriptorData(uint16_t Length, ONE_DESCRIPTOR *pDesc) +{ + uint32_t wOffset; + + wOffset = pInformation->Ctrl_Info.Usb_wOffset; + if (Length == 0) + { + pInformation->Ctrl_Info.Usb_wLength = pDesc->Descriptor_Size - wOffset; + return 0; + } + + return pDesc->Descriptor + wOffset; +} + +/******************************************************************************* +* Function Name : DataStageOut. +* Description : Data stage of a Control Write Transfer. +* Input : None. +* Output : None. +* Return : None. +*******************************************************************************/ +void DataStageOut(void) +{ + ENDPOINT_INFO *pEPinfo = &pInformation->Ctrl_Info; + uint32_t save_rLength; + + save_rLength = pEPinfo->Usb_rLength; + + if (pEPinfo->CopyData && save_rLength) + { + uint8_t *Buffer; + uint32_t Length; + + Length = pEPinfo->PacketSize; + if (Length > save_rLength) + { + Length = save_rLength; + } + + Buffer = (*pEPinfo->CopyData)(Length); + pEPinfo->Usb_rLength -= Length; + pEPinfo->Usb_rOffset += Length; + PMAToUserBufferCopy(Buffer, GetEPRxAddr(ENDP0), Length); + + } + + if (pEPinfo->Usb_rLength != 0) + { + vSetEPRxStatus(EP_RX_VALID);/* re-enable for next data reception */ + SetEPTxCount(ENDP0, 0); + vSetEPTxStatus(EP_TX_VALID);/* Expect the host to abort the data OUT stage */ + } + /* Set the next State*/ + if (pEPinfo->Usb_rLength >= pEPinfo->PacketSize) + { + pInformation->ControlState = OUT_DATA; + } + else + { + if (pEPinfo->Usb_rLength > 0) + { + pInformation->ControlState = LAST_OUT_DATA; + } + else if (pEPinfo->Usb_rLength == 0) + { + pInformation->ControlState = WAIT_STATUS_IN; + USB_StatusIn(); + } + } +} + +/******************************************************************************* +* Function Name : DataStageIn. +* Description : Data stage of a Control Read Transfer. +* Input : None. +* Output : None. +* Return : None. +*******************************************************************************/ +void DataStageIn(void) +{ + ENDPOINT_INFO *pEPinfo = &pInformation->Ctrl_Info; + uint32_t save_wLength = pEPinfo->Usb_wLength; + uint32_t ControlState = pInformation->ControlState; + + uint8_t *DataBuffer; + uint32_t Length; + + if ((save_wLength == 0) && (ControlState == LAST_IN_DATA)) + { + if(Data_Mul_MaxPacketSize == TRUE) + { + /* No more data to send and empty packet */ + Send0LengthData(); + ControlState = LAST_IN_DATA; + Data_Mul_MaxPacketSize = FALSE; + } + else + { + /* No more data to send so STALL the TX Status*/ + ControlState = WAIT_STATUS_OUT; + vSetEPTxStatus(EP_TX_STALL); + + } + + goto Expect_Status_Out; + } + + Length = pEPinfo->PacketSize; + ControlState = (save_wLength <= Length) ? LAST_IN_DATA : IN_DATA; + + if (Length > save_wLength) + { + Length = save_wLength; + } + + DataBuffer = (*pEPinfo->CopyData)(Length); + + UserToPMABufferCopy(DataBuffer, GetEPTxAddr(ENDP0), Length); + + SetEPTxCount(ENDP0, Length); + + pEPinfo->Usb_wLength -= Length; + pEPinfo->Usb_wOffset += Length; + vSetEPTxStatus(EP_TX_VALID); + + USB_StatusOut();/* Expect the host to abort the data IN stage */ + +Expect_Status_Out: + pInformation->ControlState = ControlState; +} + +/******************************************************************************* +* Function Name : NoData_Setup0. +* Description : Proceed the processing of setup request without data stage. +* Input : None. +* Output : None. +* Return : None. +*******************************************************************************/ +void NoData_Setup0(void) +{ + RESULT Result = USB_UNSUPPORT; + uint32_t RequestNo = pInformation->USBbRequest; + uint32_t ControlState; + + if (Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT)) + { + /* Device Request*/ + /* SET_CONFIGURATION*/ + if (RequestNo == SET_CONFIGURATION) + { + Result = Standard_SetConfiguration(); + } + + /*SET ADDRESS*/ + else if (RequestNo == SET_ADDRESS) + { + if ((pInformation->USBwValue0 > 127) || (pInformation->USBwValue1 != 0) + || (pInformation->USBwIndex != 0) + || (pInformation->Current_Configuration != 0)) + /* Device Address should be 127 or less*/ + { + ControlState = STALLED; + goto exit_NoData_Setup0; + } + else + { + Result = USB_SUCCESS; + } + } + /*SET FEATURE for Device*/ + else if (RequestNo == SET_FEATURE) + { + if ((pInformation->USBwValue0 == DEVICE_REMOTE_WAKEUP) \ + && (pInformation->USBwIndex == 0)) + { + Result = Standard_SetDeviceFeature(); + } + else + { + Result = USB_UNSUPPORT; + } + } + /*Clear FEATURE for Device */ + else if (RequestNo == CLEAR_FEATURE) + { + if (pInformation->USBwValue0 == DEVICE_REMOTE_WAKEUP + && pInformation->USBwIndex == 0 + && ValBit(pInformation->Current_Feature, 5)) + { + Result = Standard_ClearFeature(); + } + else + { + Result = USB_UNSUPPORT; + } + } + + } + + /* Interface Request*/ + else if (Type_Recipient == (STANDARD_REQUEST | INTERFACE_RECIPIENT)) + { + /*SET INTERFACE*/ + if (RequestNo == SET_INTERFACE) + { + Result = Standard_SetInterface(); + } + } + + /* EndPoint Request*/ + else if (Type_Recipient == (STANDARD_REQUEST | ENDPOINT_RECIPIENT)) + { + /*CLEAR FEATURE for EndPoint*/ + if (RequestNo == CLEAR_FEATURE) + { + Result = Standard_ClearFeature(); + } + /* SET FEATURE for EndPoint*/ + else if (RequestNo == SET_FEATURE) + { + Result = Standard_SetEndPointFeature(); + } + } + else + { + Result = USB_UNSUPPORT; + } + + + if (Result != USB_SUCCESS) + { + Result = (*pProperty->Class_NoData_Setup)(RequestNo); + if (Result == USB_NOT_READY) + { + ControlState = PAUSE; + goto exit_NoData_Setup0; + } + } + + if (Result != USB_SUCCESS) + { + ControlState = STALLED; + goto exit_NoData_Setup0; + } + + ControlState = WAIT_STATUS_IN;/* After no data stage SETUP */ + + USB_StatusIn(); + +exit_NoData_Setup0: + pInformation->ControlState = ControlState; + return; +} + +/******************************************************************************* +* Function Name : Data_Setup0. +* Description : Proceed the processing of setup request with data stage. +* Input : None. +* Output : None. +* Return : None. +*******************************************************************************/ +void Data_Setup0(void) +{ + uint8_t *(*CopyRoutine)(uint16_t); + RESULT Result; + uint32_t Request_No = pInformation->USBbRequest; + + uint32_t Related_Endpoint, Reserved; + uint32_t wOffset, Status; + + + + CopyRoutine = NULL; + wOffset = 0; + + /*GET DESCRIPTOR*/ + if (Request_No == GET_DESCRIPTOR) + { + if (Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT)) + { + uint8_t wValue1 = pInformation->USBwValue1; + if (wValue1 == DEVICE_DESCRIPTOR) + { + CopyRoutine = pProperty->GetDeviceDescriptor; + } + else if (wValue1 == CONFIG_DESCRIPTOR) + { + CopyRoutine = pProperty->GetConfigDescriptor; + } + else if (wValue1 == STRING_DESCRIPTOR) + { + CopyRoutine = pProperty->GetStringDescriptor; + } /* End of GET_DESCRIPTOR */ + } + } + + /*GET STATUS*/ + else if ((Request_No == GET_STATUS) && (pInformation->USBwValue == 0) + && (pInformation->USBwLength == 0x0002) + && (pInformation->USBwIndex1 == 0)) + { + /* GET STATUS for Device*/ + if ((Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT)) + && (pInformation->USBwIndex == 0)) + { + CopyRoutine = Standard_GetStatus; + } + + /* GET STATUS for Interface*/ + else if (Type_Recipient == (STANDARD_REQUEST | INTERFACE_RECIPIENT)) + { + if (((*pProperty->Class_Get_Interface_Setting)(pInformation->USBwIndex0, 0) == USB_SUCCESS) + && (pInformation->Current_Configuration != 0)) + { + CopyRoutine = Standard_GetStatus; + } + } + + /* GET STATUS for EndPoint*/ + else if (Type_Recipient == (STANDARD_REQUEST | ENDPOINT_RECIPIENT)) + { + Related_Endpoint = (pInformation->USBwIndex0 & 0x0f); + Reserved = pInformation->USBwIndex0 & 0x70; + + if (ValBit(pInformation->USBwIndex0, 7)) + { + /*Get Status of endpoint & stall the request if the related_ENdpoint + is Disabled*/ + Status = _GetEPTxStatus(Related_Endpoint); + } + else + { + Status = _GetEPRxStatus(Related_Endpoint); + } + + if ((Related_Endpoint < Device_Table.Total_Endpoint) && (Reserved == 0) + && (Status != 0)) + { + CopyRoutine = Standard_GetStatus; + } + } + + } + + /*GET CONFIGURATION*/ + else if (Request_No == GET_CONFIGURATION) + { + if (Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT)) + { + CopyRoutine = Standard_GetConfiguration; + } + } + /*GET INTERFACE*/ + else if (Request_No == GET_INTERFACE) + { + if ((Type_Recipient == (STANDARD_REQUEST | INTERFACE_RECIPIENT)) + && (pInformation->Current_Configuration != 0) && (pInformation->USBwValue == 0) + && (pInformation->USBwIndex1 == 0) && (pInformation->USBwLength == 0x0001) + && ((*pProperty->Class_Get_Interface_Setting)(pInformation->USBwIndex0, 0) == USB_SUCCESS)) + { + CopyRoutine = Standard_GetInterface; + } + + } + + if (CopyRoutine) + { + pInformation->Ctrl_Info.Usb_wOffset = wOffset; + pInformation->Ctrl_Info.CopyData = CopyRoutine; + /* sb in the original the cast to word was directly */ + /* now the cast is made step by step */ + (*CopyRoutine)(0); + Result = USB_SUCCESS; + } + else + { + Result = (*pProperty->Class_Data_Setup)(pInformation->USBbRequest); + if (Result == USB_NOT_READY) + { + pInformation->ControlState = PAUSE; + return; + } + } + + if (pInformation->Ctrl_Info.Usb_wLength == 0xFFFF) + { + /* Data is not ready, wait it */ + pInformation->ControlState = PAUSE; + return; + } + if ((Result == USB_UNSUPPORT) || (pInformation->Ctrl_Info.Usb_wLength == 0)) + { + /* Unsupported request */ + pInformation->ControlState = STALLED; + return; + } + + + if (ValBit(pInformation->USBbmRequestType, 7)) + { + /* Device ==> Host */ + __IO uint32_t wLength = pInformation->USBwLength; + + /* Restrict the data length to be the one host asks for */ + if (pInformation->Ctrl_Info.Usb_wLength > wLength) + { + pInformation->Ctrl_Info.Usb_wLength = wLength; + } + + else if (pInformation->Ctrl_Info.Usb_wLength < pInformation->USBwLength) + { + if (pInformation->Ctrl_Info.Usb_wLength < pProperty->MaxPacketSize) + { + Data_Mul_MaxPacketSize = FALSE; + } + else if ((pInformation->Ctrl_Info.Usb_wLength % pProperty->MaxPacketSize) == 0) + { + Data_Mul_MaxPacketSize = TRUE; + } + } + + pInformation->Ctrl_Info.PacketSize = pProperty->MaxPacketSize; + DataStageIn(); + } + else + { + pInformation->ControlState = OUT_DATA; + vSetEPRxStatus(EP_RX_VALID); /* enable for next data reception */ + } + + return; +} + +/******************************************************************************* +* Function Name : Setup0_Process +* Description : Get the device request data and dispatch to individual process. +* Input : None. +* Output : None. +* Return : Post0_Process. +*******************************************************************************/ +uint8_t Setup0_Process(void) +{ + + union + { + uint8_t* b; + uint16_t* w; + } pBuf; + uint16_t offset = 1; + + pBuf.b = PMAAddr + (uint8_t *)(_GetEPRxAddr(ENDP0) * 2); /* *2 for 32 bits addr */ + + if (pInformation->ControlState != PAUSE) + { + pInformation->USBbmRequestType = *pBuf.b++; /* bmRequestType */ + pInformation->USBbRequest = *pBuf.b++; /* bRequest */ + pBuf.w += offset; /* word not accessed because of 32 bits addressing */ + pInformation->USBwValue = ByteSwap(*pBuf.w++); /* wValue */ + pBuf.w += offset; /* word not accessed because of 32 bits addressing */ + pInformation->USBwIndex = ByteSwap(*pBuf.w++); /* wIndex */ + pBuf.w += offset; /* word not accessed because of 32 bits addressing */ + pInformation->USBwLength = *pBuf.w; /* wLength */ + } + + pInformation->ControlState = SETTING_UP; + if (pInformation->USBwLength == 0) + { + /* Setup with no data stage */ + NoData_Setup0(); + } + else + { + /* Setup with data stage */ + Data_Setup0(); + } + return Post0_Process(); +} + +/******************************************************************************* +* Function Name : In0_Process +* Description : Process the IN token on all default endpoint. +* Input : None. +* Output : None. +* Return : Post0_Process. +*******************************************************************************/ +uint8_t In0_Process(void) +{ + uint32_t ControlState = pInformation->ControlState; + + if ((ControlState == IN_DATA) || (ControlState == LAST_IN_DATA)) + { + DataStageIn(); + /* ControlState may be changed outside the function */ + ControlState = pInformation->ControlState; + } + + else if (ControlState == WAIT_STATUS_IN) + { + if ((pInformation->USBbRequest == SET_ADDRESS) && + (Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT))) + { + SetDeviceAddress(pInformation->USBwValue0); + pUser_Standard_Requests->User_SetDeviceAddress(); + } + (*pProperty->Process_Status_IN)(); + ControlState = STALLED; + } + + else + { + ControlState = STALLED; + } + + pInformation->ControlState = ControlState; + + return Post0_Process(); +} + +/******************************************************************************* +* Function Name : Out0_Process +* Description : Process the OUT token on all default endpoint. +* Input : None. +* Output : None. +* Return : Post0_Process. +*******************************************************************************/ +uint8_t Out0_Process(void) +{ + uint32_t ControlState = pInformation->ControlState; + + if ((ControlState == IN_DATA) || (ControlState == LAST_IN_DATA)) + { + /* host aborts the transfer before finish */ + ControlState = STALLED; + } + else if ((ControlState == OUT_DATA) || (ControlState == LAST_OUT_DATA)) + { + DataStageOut(); + ControlState = pInformation->ControlState; /* may be changed outside the function */ + } + + else if (ControlState == WAIT_STATUS_OUT) + { + (*pProperty->Process_Status_OUT)(); + ControlState = STALLED; + } + + + /* Unexpect state, STALL the endpoint */ + else + { + ControlState = STALLED; + } + + pInformation->ControlState = ControlState; + + return Post0_Process(); +} + +/******************************************************************************* +* Function Name : Post0_Process +* Description : Stall the Endpoint 0 in case of error. +* Input : None. +* Output : None. +* Return : - 0 if the control State is in PAUSE +* - 1 if not. +*******************************************************************************/ +uint8_t Post0_Process(void) +{ + + SetEPRxCount(ENDP0, Device_Property.MaxPacketSize); + + if (pInformation->ControlState == STALLED) + { + vSetEPRxStatus(EP_RX_STALL); + vSetEPTxStatus(EP_TX_STALL); + } + + return (pInformation->ControlState == PAUSE); +} + +/******************************************************************************* +* Function Name : SetDeviceAddress. +* Description : Set the device and all the used Endpoints addresses. +* Input : - Val: device address. +* Output : None. +* Return : None. +*******************************************************************************/ +void SetDeviceAddress(uint8_t Val) +{ + uint32_t i; + uint32_t nEP = Device_Table.Total_Endpoint; + + /* set address in every used endpoint */ + for (i = 0; i < nEP; i++) + { + _SetEPAddress((uint8_t)i, (uint8_t)i); + } /* for */ + _SetDADDR(Val | DADDR_EF); /* set device address and enable function */ +} + +/******************************************************************************* +* Function Name : NOP_Process +* Description : No operation function. +* Input : None. +* Output : None. +* Return : None. +*******************************************************************************/ +void NOP_Process(void) +{ +} + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/src/usb_init.c b/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/src/usb_init.c new file mode 100755 index 0000000000..0949620ad5 --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/src/usb_init.c @@ -0,0 +1,76 @@ +/** + ****************************************************************************** + * @file usb_init.c + * @author MCD Application Team + * @version V4.0.0 + * @date 28-August-2012 + * @brief Initialization routines & global variables + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2012 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + + +/* Includes ------------------------------------------------------------------*/ +#include "usb_lib.h" + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/* The number of current endpoint, it will be used to specify an endpoint */ + uint8_t EPindex; +/* The number of current device, it is an index to the Device_Table */ +/* uint8_t Device_no; */ +/* Points to the DEVICE_INFO structure of current device */ +/* The purpose of this register is to speed up the execution */ +DEVICE_INFO *pInformation; +/* Points to the DEVICE_PROP structure of current device */ +/* The purpose of this register is to speed up the execution */ +DEVICE_PROP *pProperty; +/* Temporary save the state of Rx & Tx status. */ +/* Whenever the Rx or Tx state is changed, its value is saved */ +/* in this variable first and will be set to the EPRB or EPRA */ +/* at the end of interrupt process */ +uint16_t SaveState ; +uint16_t wInterrupt_Mask; +DEVICE_INFO Device_Info; +USER_STANDARD_REQUESTS *pUser_Standard_Requests; + +/* Extern variables ----------------------------------------------------------*/ +/* Private function prototypes -----------------------------------------------*/ +/* Private functions ---------------------------------------------------------*/ + +/******************************************************************************* +* Function Name : USB_Init +* Description : USB system initialization +* Input : None. +* Output : None. +* Return : None. +*******************************************************************************/ +void USB_Init(void) +{ + pInformation = &Device_Info; + pInformation->ControlState = 2; + pProperty = &Device_Property; + pUser_Standard_Requests = &User_Standard_Requests; + /* Initialize devices one by one */ + pProperty->Init(); +} + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/src/usb_int.c b/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/src/usb_int.c new file mode 100755 index 0000000000..dbaa33102d --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/src/usb_int.c @@ -0,0 +1,195 @@ +/** + ****************************************************************************** + * @file usb_int.c + * @author MCD Application Team + * @version V4.0.0 + * @date 28-August-2012 + * @brief Endpoint CTR (Low and High) interrupt's service routines + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2012 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "usb_lib.h" + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +__IO uint16_t SaveRState; +__IO uint16_t SaveTState; + +/* Extern variables ----------------------------------------------------------*/ +extern void (*pEpInt_IN[7])(void); /* Handles IN interrupts */ +extern void (*pEpInt_OUT[7])(void); /* Handles OUT interrupts */ + +/* Private function prototypes -----------------------------------------------*/ +/* Private functions ---------------------------------------------------------*/ + +/******************************************************************************* +* Function Name : CTR_LP. +* Description : Low priority Endpoint Correct Transfer interrupt's service +* routine. +* Input : None. +* Output : None. +* Return : None. +*******************************************************************************/ +void CTR_LP(void) +{ + __IO uint16_t wEPVal = 0; + /* stay in loop while pending interrupts */ + while (((wIstr = _GetISTR()) & ISTR_CTR) != 0) + { + /* extract highest priority endpoint number */ + EPindex = (uint8_t)(wIstr & ISTR_EP_ID); + if (EPindex == 0) + { + /* Decode and service control endpoint interrupt */ + /* calling related service routine */ + /* (Setup0_Process, In0_Process, Out0_Process) */ + + /* save RX & TX status */ + /* and set both to NAK */ + + SaveRState = _GetENDPOINT(ENDP0); + SaveTState = SaveRState & EPTX_STAT; + SaveRState &= EPRX_STAT; + + _SetEPRxTxStatus(ENDP0,EP_RX_NAK,EP_TX_NAK); + + /* DIR bit = origin of the interrupt */ + + if ((wIstr & ISTR_DIR) == 0) + { + /* DIR = 0 */ + + /* DIR = 0 => IN int */ + /* DIR = 0 implies that (EP_CTR_TX = 1) always */ + + _ClearEP_CTR_TX(ENDP0); + In0_Process(); + + /* before terminate set Tx & Rx status */ + + _SetEPRxTxStatus(ENDP0,SaveRState,SaveTState); + return; + } + else + { + /* DIR = 1 */ + + /* DIR = 1 & CTR_RX => SETUP or OUT int */ + /* DIR = 1 & (CTR_TX | CTR_RX) => 2 int pending */ + + wEPVal = _GetENDPOINT(ENDP0); + + if ((wEPVal &EP_SETUP) != 0) + { + _ClearEP_CTR_RX(ENDP0); /* SETUP bit kept frozen while CTR_RX = 1 */ + Setup0_Process(); + /* before terminate set Tx & Rx status */ + + _SetEPRxTxStatus(ENDP0,SaveRState,SaveTState); + return; + } + + else if ((wEPVal & EP_CTR_RX) != 0) + { + _ClearEP_CTR_RX(ENDP0); + Out0_Process(); + /* before terminate set Tx & Rx status */ + + _SetEPRxTxStatus(ENDP0,SaveRState,SaveTState); + return; + } + } + }/* if(EPindex == 0) */ + else + { + /* Decode and service non control endpoints interrupt */ + + /* process related endpoint register */ + wEPVal = _GetENDPOINT(EPindex); + if ((wEPVal & EP_CTR_RX) != 0) + { + /* clear int flag */ + _ClearEP_CTR_RX(EPindex); + + /* call OUT service function */ + (*pEpInt_OUT[EPindex-1])(); + + } /* if((wEPVal & EP_CTR_RX) */ + + if ((wEPVal & EP_CTR_TX) != 0) + { + /* clear int flag */ + _ClearEP_CTR_TX(EPindex); + + /* call IN service function */ + (*pEpInt_IN[EPindex-1])(); + } /* if((wEPVal & EP_CTR_TX) != 0) */ + + }/* if(EPindex == 0) else */ + + }/* while(...) */ +} + +/******************************************************************************* +* Function Name : CTR_HP. +* Description : High Priority Endpoint Correct Transfer interrupt's service +* routine. +* Input : None. +* Output : None. +* Return : None. +*******************************************************************************/ +void CTR_HP(void) +{ + uint32_t wEPVal = 0; + + while (((wIstr = _GetISTR()) & ISTR_CTR) != 0) + { + _SetISTR((uint16_t)CLR_CTR); /* clear CTR flag */ + /* extract highest priority endpoint number */ + EPindex = (uint8_t)(wIstr & ISTR_EP_ID); + /* process related endpoint register */ + wEPVal = _GetENDPOINT(EPindex); + if ((wEPVal & EP_CTR_RX) != 0) + { + /* clear int flag */ + _ClearEP_CTR_RX(EPindex); + + /* call OUT service function */ + (*pEpInt_OUT[EPindex-1])(); + + } /* if((wEPVal & EP_CTR_RX) */ + else if ((wEPVal & EP_CTR_TX) != 0) + { + /* clear int flag */ + _ClearEP_CTR_TX(EPindex); + + /* call IN service function */ + (*pEpInt_IN[EPindex-1])(); + + + } /* if((wEPVal & EP_CTR_TX) != 0) */ + + }/* while(...) */ +} + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/src/usb_mem.c b/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/src/usb_mem.c new file mode 100755 index 0000000000..4e0748ac39 --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/src/usb_mem.c @@ -0,0 +1,87 @@ +/** + ****************************************************************************** + * @file usb_mem.c + * @author MCD Application Team + * @version V4.0.0 + * @date 28-August-2012 + * @brief Utility functions for memory transfers to/from PMA + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2012 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "usb_lib.h" + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/* Extern variables ----------------------------------------------------------*/ +/* Private function prototypes -----------------------------------------------*/ +/* Private functions ---------------------------------------------------------*/ + +/******************************************************************************* +* Function Name : UserToPMABufferCopy +* Description : Copy a buffer from user memory area to packet memory area (PMA) +* Input : - pbUsrBuf: pointer to user memory area. +* - wPMABufAddr: address into PMA. +* - wNBytes: no. of bytes to be copied. +* Output : None. +* Return : None . +*******************************************************************************/ +void UserToPMABufferCopy(uint8_t *pbUsrBuf, uint16_t wPMABufAddr, uint16_t wNBytes) +{ + uint32_t n = (wNBytes + 1) >> 1; /* n = (wNBytes + 1) / 2 */ + uint32_t i, temp1, temp2; + uint16_t *pdwVal; + pdwVal = (uint16_t *)(wPMABufAddr * 2 + PMAAddr); + for (i = n; i != 0; i--) + { + temp1 = (uint16_t) * pbUsrBuf; + pbUsrBuf++; + temp2 = temp1 | (uint16_t) * pbUsrBuf << 8; + *pdwVal++ = temp2; + pdwVal++; + pbUsrBuf++; + } +} + +/******************************************************************************* +* Function Name : PMAToUserBufferCopy +* Description : Copy a buffer from user memory area to packet memory area (PMA) +* Input : - pbUsrBuf = pointer to user memory area. +* - wPMABufAddr = address into PMA. +* - wNBytes = no. of bytes to be copied. +* Output : None. +* Return : None. +*******************************************************************************/ +void PMAToUserBufferCopy(uint8_t *pbUsrBuf, uint16_t wPMABufAddr, uint16_t wNBytes) +{ + uint32_t n = (wNBytes + 1) >> 1;/* /2*/ + uint32_t i; + uint32_t *pdwVal; + pdwVal = (uint32_t *)(wPMABufAddr * 2 + PMAAddr); + for (i = n; i != 0; i--) + { + *(uint16_t*)pbUsrBuf++ = *pdwVal++; + pbUsrBuf++; + } +} + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/src/usb_regs.c b/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/src/usb_regs.c new file mode 100755 index 0000000000..b1e22fe6e3 --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/src/usb_regs.c @@ -0,0 +1,760 @@ +/** + ****************************************************************************** + * @file usb_regs.c + * @author MCD Application Team + * @version V4.0.0 + * @date 28-August-2012 + * @brief Interface functions to USB cell registers + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2012 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "usb_lib.h" + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/* Extern variables ----------------------------------------------------------*/ +/* Private function prototypes -----------------------------------------------*/ +/* Private functions ---------------------------------------------------------*/ + +/******************************************************************************* +* Function Name : SetCNTR. +* Description : Set the CNTR register value. +* Input : wRegValue: new register value. +* Output : None. +* Return : None. +*******************************************************************************/ +void SetCNTR(uint16_t wRegValue) +{ + _SetCNTR(wRegValue); +} + +/******************************************************************************* +* Function Name : GetCNTR. +* Description : returns the CNTR register value. +* Input : None. +* Output : None. +* Return : CNTR register Value. +*******************************************************************************/ +uint16_t GetCNTR(void) +{ + return(_GetCNTR()); +} + +/******************************************************************************* +* Function Name : SetISTR. +* Description : Set the ISTR register value. +* Input : wRegValue: new register value. +* Output : None. +* Return : None. +*******************************************************************************/ +void SetISTR(uint16_t wRegValue) +{ + _SetISTR(wRegValue); +} + +/******************************************************************************* +* Function Name : GetISTR +* Description : Returns the ISTR register value. +* Input : None. +* Output : None. +* Return : ISTR register Value +*******************************************************************************/ +uint16_t GetISTR(void) +{ + return(_GetISTR()); +} + +/******************************************************************************* +* Function Name : GetFNR +* Description : Returns the FNR register value. +* Input : None. +* Output : None. +* Return : FNR register Value +*******************************************************************************/ +uint16_t GetFNR(void) +{ + return(_GetFNR()); +} + +/******************************************************************************* +* Function Name : SetDADDR +* Description : Set the DADDR register value. +* Input : wRegValue: new register value. +* Output : None. +* Return : None. +*******************************************************************************/ +void SetDADDR(uint16_t wRegValue) +{ + _SetDADDR(wRegValue); +} + +/******************************************************************************* +* Function Name : GetDADDR +* Description : Returns the DADDR register value. +* Input : None. +* Output : None. +* Return : DADDR register Value +*******************************************************************************/ +uint16_t GetDADDR(void) +{ + return(_GetDADDR()); +} + +/******************************************************************************* +* Function Name : SetBTABLE +* Description : Set the BTABLE. +* Input : wRegValue: New register value. +* Output : None. +* Return : None. +*******************************************************************************/ +void SetBTABLE(uint16_t wRegValue) +{ + _SetBTABLE(wRegValue); +} + +/******************************************************************************* +* Function Name : GetBTABLE. +* Description : Returns the BTABLE register value. +* Input : None. +* Output : None. +* Return : BTABLE address. +*******************************************************************************/ +uint16_t GetBTABLE(void) +{ + return(_GetBTABLE()); +} + +/******************************************************************************* +* Function Name : SetENDPOINT +* Description : Set the Endpoint register value. +* Input : bEpNum: Endpoint Number. +* wRegValue. +* Output : None. +* Return : None. +*******************************************************************************/ +void SetENDPOINT(uint8_t bEpNum, uint16_t wRegValue) +{ + _SetENDPOINT(bEpNum, wRegValue); +} + +/******************************************************************************* +* Function Name : GetENDPOINT +* Description : Return the Endpoint register value. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : Endpoint register value. +*******************************************************************************/ +uint16_t GetENDPOINT(uint8_t bEpNum) +{ + return(_GetENDPOINT(bEpNum)); +} + +/******************************************************************************* +* Function Name : SetEPType +* Description : sets the type in the endpoint register. +* Input : bEpNum: Endpoint Number. +* wType: type definition. +* Output : None. +* Return : None. +*******************************************************************************/ +void SetEPType(uint8_t bEpNum, uint16_t wType) +{ + _SetEPType(bEpNum, wType); +} + +/******************************************************************************* +* Function Name : GetEPType +* Description : Returns the endpoint type. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : Endpoint Type +*******************************************************************************/ +uint16_t GetEPType(uint8_t bEpNum) +{ + return(_GetEPType(bEpNum)); +} + +/******************************************************************************* +* Function Name : SetEPTxStatus +* Description : Set the status of Tx endpoint. +* Input : bEpNum: Endpoint Number. +* wState: new state. +* Output : None. +* Return : None. +*******************************************************************************/ +void SetEPTxStatus(uint8_t bEpNum, uint16_t wState) +{ + _SetEPTxStatus(bEpNum, wState); +} + +/******************************************************************************* +* Function Name : SetEPRxStatus +* Description : Set the status of Rx endpoint. +* Input : bEpNum: Endpoint Number. +* wState: new state. +* Output : None. +* Return : None. +*******************************************************************************/ +void SetEPRxStatus(uint8_t bEpNum, uint16_t wState) +{ + _SetEPRxStatus(bEpNum, wState); +} + +/******************************************************************************* +* Function Name : SetDouBleBuffEPStall +* Description : sets the status for Double Buffer Endpoint to STALL +* Input : bEpNum: Endpoint Number. +* bDir: Endpoint direction. +* Output : None. +* Return : None. +*******************************************************************************/ +void SetDouBleBuffEPStall(uint8_t bEpNum, uint8_t bDir) +{ + uint16_t Endpoint_DTOG_Status; + Endpoint_DTOG_Status = GetENDPOINT(bEpNum); + if (bDir == EP_DBUF_OUT) + { /* OUT double buffered endpoint */ + _SetENDPOINT(bEpNum, Endpoint_DTOG_Status & ~EPRX_DTOG1); + } + else if (bDir == EP_DBUF_IN) + { /* IN double buffered endpoint */ + _SetENDPOINT(bEpNum, Endpoint_DTOG_Status & ~EPTX_DTOG1); + } +} + +/******************************************************************************* +* Function Name : GetEPTxStatus +* Description : Returns the endpoint Tx status. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : Endpoint TX Status +*******************************************************************************/ +uint16_t GetEPTxStatus(uint8_t bEpNum) +{ + return(_GetEPTxStatus(bEpNum)); +} + +/******************************************************************************* +* Function Name : GetEPRxStatus +* Description : Returns the endpoint Rx status. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : Endpoint RX Status +*******************************************************************************/ +uint16_t GetEPRxStatus(uint8_t bEpNum) +{ + return(_GetEPRxStatus(bEpNum)); +} + +/******************************************************************************* +* Function Name : SetEPTxValid +* Description : Valid the endpoint Tx Status. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : None. +*******************************************************************************/ +void SetEPTxValid(uint8_t bEpNum) +{ + _SetEPTxStatus(bEpNum, EP_TX_VALID); +} + +/******************************************************************************* +* Function Name : SetEPRxValid +* Description : Valid the endpoint Rx Status. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : None. +*******************************************************************************/ +void SetEPRxValid(uint8_t bEpNum) +{ + _SetEPRxStatus(bEpNum, EP_RX_VALID); +} + +/******************************************************************************* +* Function Name : SetEP_KIND +* Description : Clear the EP_KIND bit. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : None. +*******************************************************************************/ +void SetEP_KIND(uint8_t bEpNum) +{ + _SetEP_KIND(bEpNum); +} + +/******************************************************************************* +* Function Name : ClearEP_KIND +* Description : set the EP_KIND bit. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : None. +*******************************************************************************/ +void ClearEP_KIND(uint8_t bEpNum) +{ + _ClearEP_KIND(bEpNum); +} +/******************************************************************************* +* Function Name : Clear_Status_Out +* Description : Clear the Status Out of the related Endpoint +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : None. +*******************************************************************************/ +void Clear_Status_Out(uint8_t bEpNum) +{ + _ClearEP_KIND(bEpNum); +} +/******************************************************************************* +* Function Name : Set_Status_Out +* Description : Set the Status Out of the related Endpoint +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : None. +*******************************************************************************/ +void Set_Status_Out(uint8_t bEpNum) +{ + _SetEP_KIND(bEpNum); +} +/******************************************************************************* +* Function Name : SetEPDoubleBuff +* Description : Enable the double buffer feature for the endpoint. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : None. +*******************************************************************************/ +void SetEPDoubleBuff(uint8_t bEpNum) +{ + _SetEP_KIND(bEpNum); +} +/******************************************************************************* +* Function Name : ClearEPDoubleBuff +* Description : Disable the double buffer feature for the endpoint. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : None. +*******************************************************************************/ +void ClearEPDoubleBuff(uint8_t bEpNum) +{ + _ClearEP_KIND(bEpNum); +} +/******************************************************************************* +* Function Name : GetTxStallStatus +* Description : Returns the Stall status of the Tx endpoint. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : Tx Stall status. +*******************************************************************************/ +uint16_t GetTxStallStatus(uint8_t bEpNum) +{ + return(_GetTxStallStatus(bEpNum)); +} +/******************************************************************************* +* Function Name : GetRxStallStatus +* Description : Returns the Stall status of the Rx endpoint. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : Rx Stall status. +*******************************************************************************/ +uint16_t GetRxStallStatus(uint8_t bEpNum) +{ + return(_GetRxStallStatus(bEpNum)); +} +/******************************************************************************* +* Function Name : ClearEP_CTR_RX +* Description : Clear the CTR_RX bit. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : None. +*******************************************************************************/ +void ClearEP_CTR_RX(uint8_t bEpNum) +{ + _ClearEP_CTR_RX(bEpNum); +} +/******************************************************************************* +* Function Name : ClearEP_CTR_TX +* Description : Clear the CTR_TX bit. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : None. +*******************************************************************************/ +void ClearEP_CTR_TX(uint8_t bEpNum) +{ + _ClearEP_CTR_TX(bEpNum); +} +/******************************************************************************* +* Function Name : ToggleDTOG_RX +* Description : Toggle the DTOG_RX bit. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : None. +*******************************************************************************/ +void ToggleDTOG_RX(uint8_t bEpNum) +{ + _ToggleDTOG_RX(bEpNum); +} +/******************************************************************************* +* Function Name : ToggleDTOG_TX +* Description : Toggle the DTOG_TX bit. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : None. +*******************************************************************************/ +void ToggleDTOG_TX(uint8_t bEpNum) +{ + _ToggleDTOG_TX(bEpNum); +} +/******************************************************************************* +* Function Name : ClearDTOG_RX. +* Description : Clear the DTOG_RX bit. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : None. +*******************************************************************************/ +void ClearDTOG_RX(uint8_t bEpNum) +{ + _ClearDTOG_RX(bEpNum); +} +/******************************************************************************* +* Function Name : ClearDTOG_TX. +* Description : Clear the DTOG_TX bit. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : None. +*******************************************************************************/ +void ClearDTOG_TX(uint8_t bEpNum) +{ + _ClearDTOG_TX(bEpNum); +} +/******************************************************************************* +* Function Name : SetEPAddress +* Description : Set the endpoint address. +* Input : bEpNum: Endpoint Number. +* bAddr: New endpoint address. +* Output : None. +* Return : None. +*******************************************************************************/ +void SetEPAddress(uint8_t bEpNum, uint8_t bAddr) +{ + _SetEPAddress(bEpNum, bAddr); +} +/******************************************************************************* +* Function Name : GetEPAddress +* Description : Get the endpoint address. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : Endpoint address. +*******************************************************************************/ +uint8_t GetEPAddress(uint8_t bEpNum) +{ + return(_GetEPAddress(bEpNum)); +} +/******************************************************************************* +* Function Name : SetEPTxAddr +* Description : Set the endpoint Tx buffer address. +* Input : bEpNum: Endpoint Number. +* wAddr: new address. +* Output : None. +* Return : None. +*******************************************************************************/ +void SetEPTxAddr(uint8_t bEpNum, uint16_t wAddr) +{ + _SetEPTxAddr(bEpNum, wAddr); +} +/******************************************************************************* +* Function Name : SetEPRxAddr +* Description : Set the endpoint Rx buffer address. +* Input : bEpNum: Endpoint Number. +* wAddr: new address. +* Output : None. +* Return : None. +*******************************************************************************/ +void SetEPRxAddr(uint8_t bEpNum, uint16_t wAddr) +{ + _SetEPRxAddr(bEpNum, wAddr); +} +/******************************************************************************* +* Function Name : GetEPTxAddr +* Description : Returns the endpoint Tx buffer address. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : Rx buffer address. +*******************************************************************************/ +uint16_t GetEPTxAddr(uint8_t bEpNum) +{ + return(_GetEPTxAddr(bEpNum)); +} +/******************************************************************************* +* Function Name : GetEPRxAddr. +* Description : Returns the endpoint Rx buffer address. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : Rx buffer address. +*******************************************************************************/ +uint16_t GetEPRxAddr(uint8_t bEpNum) +{ + return(_GetEPRxAddr(bEpNum)); +} +/******************************************************************************* +* Function Name : SetEPTxCount. +* Description : Set the Tx count. +* Input : bEpNum: Endpoint Number. +* wCount: new count value. +* Output : None. +* Return : None. +*******************************************************************************/ +void SetEPTxCount(uint8_t bEpNum, uint16_t wCount) +{ + _SetEPTxCount(bEpNum, wCount); +} +/******************************************************************************* +* Function Name : SetEPCountRxReg. +* Description : Set the Count Rx Register value. +* Input : *pdwReg: point to the register. +* wCount: the new register value. +* Output : None. +* Return : None. +*******************************************************************************/ +void SetEPCountRxReg(uint32_t *pdwReg, uint16_t wCount) +{ + _SetEPCountRxReg(dwReg, wCount); +} +/******************************************************************************* +* Function Name : SetEPRxCount +* Description : Set the Rx count. +* Input : bEpNum: Endpoint Number. +* wCount: the new count value. +* Output : None. +* Return : None. +*******************************************************************************/ +void SetEPRxCount(uint8_t bEpNum, uint16_t wCount) +{ + _SetEPRxCount(bEpNum, wCount); +} +/******************************************************************************* +* Function Name : GetEPTxCount +* Description : Get the Tx count. +* Input : bEpNum: Endpoint Number. +* Output : None +* Return : Tx count value. +*******************************************************************************/ +uint16_t GetEPTxCount(uint8_t bEpNum) +{ + return(_GetEPTxCount(bEpNum)); +} +/******************************************************************************* +* Function Name : GetEPRxCount +* Description : Get the Rx count. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : Rx count value. +*******************************************************************************/ +uint16_t GetEPRxCount(uint8_t bEpNum) +{ + return(_GetEPRxCount(bEpNum)); +} +/******************************************************************************* +* Function Name : SetEPDblBuffAddr +* Description : Set the addresses of the buffer 0 and 1. +* Input : bEpNum: Endpoint Number. +* wBuf0Addr: new address of buffer 0. +* wBuf1Addr: new address of buffer 1. +* Output : None. +* Return : None. +*******************************************************************************/ +void SetEPDblBuffAddr(uint8_t bEpNum, uint16_t wBuf0Addr, uint16_t wBuf1Addr) +{ + _SetEPDblBuffAddr(bEpNum, wBuf0Addr, wBuf1Addr); +} +/******************************************************************************* +* Function Name : SetEPDblBuf0Addr +* Description : Set the Buffer 1 address. +* Input : bEpNum: Endpoint Number +* wBuf0Addr: new address. +* Output : None. +* Return : None. +*******************************************************************************/ +void SetEPDblBuf0Addr(uint8_t bEpNum, uint16_t wBuf0Addr) +{ + _SetEPDblBuf0Addr(bEpNum, wBuf0Addr); +} +/******************************************************************************* +* Function Name : SetEPDblBuf1Addr +* Description : Set the Buffer 1 address. +* Input : bEpNum: Endpoint Number +* wBuf1Addr: new address. +* Output : None. +* Return : None. +*******************************************************************************/ +void SetEPDblBuf1Addr(uint8_t bEpNum, uint16_t wBuf1Addr) +{ + _SetEPDblBuf1Addr(bEpNum, wBuf1Addr); +} +/******************************************************************************* +* Function Name : GetEPDblBuf0Addr +* Description : Returns the address of the Buffer 0. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : None. +*******************************************************************************/ +uint16_t GetEPDblBuf0Addr(uint8_t bEpNum) +{ + return(_GetEPDblBuf0Addr(bEpNum)); +} +/******************************************************************************* +* Function Name : GetEPDblBuf1Addr +* Description : Returns the address of the Buffer 1. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : Address of the Buffer 1. +*******************************************************************************/ +uint16_t GetEPDblBuf1Addr(uint8_t bEpNum) +{ + return(_GetEPDblBuf1Addr(bEpNum)); +} +/******************************************************************************* +* Function Name : SetEPDblBuffCount +* Description : Set the number of bytes for a double Buffer +* endpoint. +* Input : bEpNum,bDir, wCount +* Output : None. +* Return : None. +*******************************************************************************/ +void SetEPDblBuffCount(uint8_t bEpNum, uint8_t bDir, uint16_t wCount) +{ + _SetEPDblBuffCount(bEpNum, bDir, wCount); +} +/******************************************************************************* +* Function Name : SetEPDblBuf0Count +* Description : Set the number of bytes in the buffer 0 of a double Buffer +* endpoint. +* Input : bEpNum, bDir, wCount +* Output : None. +* Return : None. +*******************************************************************************/ +void SetEPDblBuf0Count(uint8_t bEpNum, uint8_t bDir, uint16_t wCount) +{ + _SetEPDblBuf0Count(bEpNum, bDir, wCount); +} +/******************************************************************************* +* Function Name : SetEPDblBuf1Count +* Description : Set the number of bytes in the buffer 0 of a double Buffer +* endpoint. +* Input : bEpNum, bDir, wCount +* Output : None. +* Return : None. +*******************************************************************************/ +void SetEPDblBuf1Count(uint8_t bEpNum, uint8_t bDir, uint16_t wCount) +{ + _SetEPDblBuf1Count(bEpNum, bDir, wCount); +} +/******************************************************************************* +* Function Name : GetEPDblBuf0Count +* Description : Returns the number of byte received in the buffer 0 of a double +* Buffer endpoint. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : Endpoint Buffer 0 count +*******************************************************************************/ +uint16_t GetEPDblBuf0Count(uint8_t bEpNum) +{ + return(_GetEPDblBuf0Count(bEpNum)); +} +/******************************************************************************* +* Function Name : GetEPDblBuf1Count +* Description : Returns the number of data received in the buffer 1 of a double +* Buffer endpoint. +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : Endpoint Buffer 1 count. +*******************************************************************************/ +uint16_t GetEPDblBuf1Count(uint8_t bEpNum) +{ + return(_GetEPDblBuf1Count(bEpNum)); +} +/******************************************************************************* +* Function Name : GetEPDblBufDir +* Description : gets direction of the double buffered endpoint +* Input : bEpNum: Endpoint Number. +* Output : None. +* Return : EP_DBUF_OUT, EP_DBUF_IN, +* EP_DBUF_ERR if the endpoint counter not yet programmed. +*******************************************************************************/ +EP_DBUF_DIR GetEPDblBufDir(uint8_t bEpNum) +{ + if ((uint16_t)(*_pEPRxCount(bEpNum) & 0xFC00) != 0) + return(EP_DBUF_OUT); + else if (((uint16_t)(*_pEPTxCount(bEpNum)) & 0x03FF) != 0) + return(EP_DBUF_IN); + else + return(EP_DBUF_ERR); +} +/******************************************************************************* +* Function Name : FreeUserBuffer +* Description : free buffer used from the application realizing it to the line + toggles bit SW_BUF in the double buffered endpoint register +* Input : bEpNum, bDir +* Output : None. +* Return : None. +*******************************************************************************/ +void FreeUserBuffer(uint8_t bEpNum, uint8_t bDir) +{ + if (bDir == EP_DBUF_OUT) + { /* OUT double buffered endpoint */ + _ToggleDTOG_TX(bEpNum); + } + else if (bDir == EP_DBUF_IN) + { /* IN double buffered endpoint */ + _ToggleDTOG_RX(bEpNum); + } +} + +/******************************************************************************* +* Function Name : ToWord +* Description : merge two byte in a word. +* Input : bh: byte high, bl: bytes low. +* Output : None. +* Return : resulted word. +*******************************************************************************/ +uint16_t ToWord(uint8_t bh, uint8_t bl) +{ + uint16_t wRet; + wRet = (uint16_t)bl | ((uint16_t)bh << 8); + return(wRet); +} +/******************************************************************************* +* Function Name : ByteSwap +* Description : Swap two byte in a word. +* Input : wSwW: word to Swap. +* Output : None. +* Return : resulted word. +*******************************************************************************/ +uint16_t ByteSwap(uint16_t wSwW) +{ + uint8_t bTemp; + uint16_t wRet; + bTemp = (uint8_t)(wSwW & 0xff); + wRet = (wSwW >> 8) | ((uint16_t)bTemp << 8); + return(wRet); +} + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/src/usb_sil.c b/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/src/usb_sil.c new file mode 100755 index 0000000000..5f2e4db007 --- /dev/null +++ b/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/src/usb_sil.c @@ -0,0 +1,103 @@ +/** + ****************************************************************************** + * @file usb_sil.c + * @author MCD Application Team + * @version V4.0.0 + * @date 28-August-2012 + * @brief Simplified Interface Layer for Global Initialization and Endpoint + * Rea/Write operations. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2012 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + + +/* Includes ------------------------------------------------------------------*/ +#include "usb_lib.h" + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/* Extern variables ----------------------------------------------------------*/ +/* Private function prototypes -----------------------------------------------*/ +/* Private functions ---------------------------------------------------------*/ + +/******************************************************************************* +* Function Name : USB_SIL_Init +* Description : Initialize the USB Device IP and the Endpoint 0. +* Input : None. +* Output : None. +* Return : Status. +*******************************************************************************/ +uint32_t USB_SIL_Init(void) +{ + /* USB interrupts initialization */ + /* clear pending interrupts */ + _SetISTR(0); + wInterrupt_Mask = IMR_MSK; + /* set interrupts mask */ + _SetCNTR(wInterrupt_Mask); + return 0; +} + +/******************************************************************************* +* Function Name : USB_SIL_Write +* Description : Write a buffer of data to a selected endpoint. +* Input : - bEpAddr: The address of the non control endpoint. +* - pBufferPointer: The pointer to the buffer of data to be written +* to the endpoint. +* - wBufferSize: Number of data to be written (in bytes). +* Output : None. +* Return : Status. +*******************************************************************************/ +uint32_t USB_SIL_Write(uint8_t bEpAddr, uint8_t* pBufferPointer, uint32_t wBufferSize) +{ + /* Use the memory interface function to write to the selected endpoint */ + UserToPMABufferCopy(pBufferPointer, GetEPTxAddr(bEpAddr & 0x7F), wBufferSize); + + /* Update the data length in the control register */ + SetEPTxCount((bEpAddr & 0x7F), wBufferSize); + + return 0; +} + +/******************************************************************************* +* Function Name : USB_SIL_Read +* Description : Write a buffer of data to a selected endpoint. +* Input : - bEpAddr: The address of the non control endpoint. +* - pBufferPointer: The pointer to which will be saved the +* received data buffer. +* Output : None. +* Return : Number of received data (in Bytes). +*******************************************************************************/ +uint32_t USB_SIL_Read(uint8_t bEpAddr, uint8_t* pBufferPointer) +{ + uint32_t DataLength = 0; + + /* Get the number of received data on the selected Endpoint */ + DataLength = GetEPRxCount(bEpAddr & 0x7F); + + /* Use the memory interface function to write to the selected endpoint */ + PMAToUserBufferCopy(pBufferPointer, GetEPRxAddr(bEpAddr & 0x7F), DataLength); + + /* Return the number of received data */ + return DataLength; +} + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ From f1bfc717272b55500ff9546e2a8321f9d7ea532d Mon Sep 17 00:00:00 2001 From: Vladimir Zidar Date: Thu, 25 May 2017 13:45:03 +0200 Subject: [PATCH 263/624] LP-512 StdPeriph driver: add __attribute__((unused)) where required. --- .../STM32F30x_StdPeriph_Driver/src/stm32f30x_adc.c | 4 ++-- .../STM32F30x_StdPeriph_Driver/src/stm32f30x_hrtim.c | 6 +++--- .../STM32F30x_StdPeriph_Driver/src/stm32f30x_syscfg.c | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_adc.c b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_adc.c index 44da04dbcd..af90b23c9c 100755 --- a/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_adc.c +++ b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_adc.c @@ -945,7 +945,7 @@ void ADC_AnalogWatchdog3SingleChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Chann * This parameter can be: ENABLE or DISABLE. * @retval None */ -void ADC_TempSensorCmd(ADC_TypeDef* ADCx, FunctionalState NewState) +void ADC_TempSensorCmd(__attribute__((unused)) ADC_TypeDef* ADCx, FunctionalState NewState) { /* Check the parameters */ assert_param(IS_FUNCTIONAL_STATE(NewState)); @@ -1010,7 +1010,7 @@ void ADC_VrefintCmd(ADC_TypeDef* ADCx, FunctionalState NewState) * This parameter can be: ENABLE or DISABLE. * @retval None */ -void ADC_VbatCmd(ADC_TypeDef* ADCx, FunctionalState NewState) +void ADC_VbatCmd(__attribute__((unused)) ADC_TypeDef* ADCx, FunctionalState NewState) { /* Check the parameters */ assert_param(IS_FUNCTIONAL_STATE(NewState)); diff --git a/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_hrtim.c b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_hrtim.c index 4e2cd3e7d9..40e3bd7a6f 100755 --- a/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_hrtim.c +++ b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_hrtim.c @@ -248,7 +248,7 @@ void HRTIM_SimpleBase_Init(HRTIM_TypeDef* HRTIMx, uint32_t TimerIdx, HRTIM_BaseI * @param HRTIMx: pointer to HRTIMx peripheral * @retval None */ -void HRTIM_DeInit(HRTIM_TypeDef* HRTIMx) +void HRTIM_DeInit(__attribute__((unused)) HRTIM_TypeDef* HRTIMx) { /* Check the parameters */ RCC_APB2PeriphResetCmd(RCC_APB2Periph_HRTIM1, ENABLE); @@ -631,7 +631,7 @@ void HRTIM_SimplePWMStop(HRTIM_TypeDef * HRTIMx, */ void HRTIM_SimpleCaptureStart(HRTIM_TypeDef * HRTIMx, uint32_t TimerIdx, - uint32_t CaptureChannel) + __attribute__((unused)) uint32_t CaptureChannel) { /* Enable the timer counter */ __HRTIM_ENABLE(HRTIMx, TimerIdxToTimerId[TimerIdx]); @@ -3208,7 +3208,7 @@ uint32_t HRTIM_WaveformGetOutputLevel(HRTIM_TypeDef * HRTIMx, * @retval Output state */ uint32_t HRTIM_WaveformGetOutputState(HRTIM_TypeDef * HRTIMx, - uint32_t TimerIdx, + __attribute__((unused)) uint32_t TimerIdx, uint32_t Output) { uint32_t output_bit = 0; diff --git a/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_syscfg.c b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_syscfg.c index e644d16e3d..6787719782 100755 --- a/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_syscfg.c +++ b/flight/pios/stm32f30x/libraries/STM32F30x_StdPeriph_Driver/src/stm32f30x_syscfg.c @@ -513,7 +513,7 @@ void SYSCFG_SRAMWRPEnable(uint32_t SYSCFG_SRAMWRP) * @arg SYSCFG_FLAG_PE: SRAM parity error flag. * @retval The new state of SYSCFG_Flag (SET or RESET). */ -FlagStatus SYSCFG_GetFlagStatus(uint32_t SYSCFG_Flag) +FlagStatus SYSCFG_GetFlagStatus(__attribute__((unused)) uint32_t SYSCFG_Flag) { FlagStatus bitstatus = RESET; From b87c8f4e3a0f60001f357381b05347bb117f9eb1 Mon Sep 17 00:00:00 2001 From: Vladimir Zidar Date: Thu, 25 May 2017 13:45:48 +0200 Subject: [PATCH 264/624] LP-512 F3 USB-FS Device: Add support for new usb peripheral in STM32F303xD and STM32F303xE --- .../STM32_USB-FS-Device_Driver/inc/usb_core.h | 14 ++--- .../STM32_USB-FS-Device_Driver/inc/usb_lib.h | 2 +- .../STM32_USB-FS-Device_Driver/inc/usb_regs.h | 45 ++++++++++---- .../STM32_USB-FS-Device_Driver/inc/usb_type.h | 4 +- .../STM32_USB-FS-Device_Driver/src/usb_core.c | 28 ++++++--- .../STM32_USB-FS-Device_Driver/src/usb_mem.c | 60 ++++++++++++++++++- 6 files changed, 124 insertions(+), 29 deletions(-) diff --git a/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/inc/usb_core.h b/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/inc/usb_core.h index bf303f79e6..4184a9c084 100755 --- a/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/inc/usb_core.h +++ b/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/inc/usb_core.h @@ -48,7 +48,7 @@ typedef enum _CONTROL_STATE typedef struct OneDescriptor { - uint8_t *Descriptor; + const uint8_t *Descriptor; uint16_t Descriptor_Size; } ONE_DESCRIPTOR, *PONE_DESCRIPTOR; @@ -182,9 +182,9 @@ typedef struct _DEVICE_PROP RESULT (*Class_Get_Interface_Setting)(uint8_t Interface, uint8_t AlternateSetting); - uint8_t* (*GetDeviceDescriptor)(uint16_t Length); - uint8_t* (*GetConfigDescriptor)(uint16_t Length); - uint8_t* (*GetStringDescriptor)(uint16_t Length); + const uint8_t* (*GetDeviceDescriptor)(uint16_t Length); + const uint8_t* (*GetConfigDescriptor)(uint16_t Length); + const uint8_t* (*GetStringDescriptor)(uint16_t Length); /* This field is not used in current library version. It is kept only for compatibility with previous versions */ @@ -234,13 +234,13 @@ uint8_t In0_Process(void); RESULT Standard_SetEndPointFeature(void); RESULT Standard_SetDeviceFeature(void); -uint8_t *Standard_GetConfiguration(uint16_t Length); +const uint8_t *Standard_GetConfiguration(uint16_t Length); RESULT Standard_SetConfiguration(void); -uint8_t *Standard_GetInterface(uint16_t Length); +const uint8_t *Standard_GetInterface(uint16_t Length); RESULT Standard_SetInterface(void); uint8_t *Standard_GetDescriptorData(uint16_t Length, PONE_DESCRIPTOR pDesc); -uint8_t *Standard_GetStatus(uint16_t Length); +const uint8_t *Standard_GetStatus(uint16_t Length); RESULT Standard_ClearFeature(void); void SetDeviceAddress(uint8_t); void NOP_Process(void); diff --git a/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/inc/usb_lib.h b/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/inc/usb_lib.h index b0e519bcc5..d40336d196 100755 --- a/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/inc/usb_lib.h +++ b/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/inc/usb_lib.h @@ -31,7 +31,7 @@ #define __USB_LIB_H /* Includes ------------------------------------------------------------------*/ -#include "hw_config.h" +#include "stm32f30x.h" #include "usb_type.h" #include "usb_regs.h" #include "usb_def.h" diff --git a/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/inc/usb_regs.h b/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/inc/usb_regs.h index 87e0a008a8..3c2bcb0189 100755 --- a/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/inc/usb_regs.h +++ b/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/inc/usb_regs.h @@ -30,6 +30,22 @@ #ifndef __USB_REGS_H #define __USB_REGS_H +#if defined(STM32F303xC) || \ + defined(STM32F303x8) || defined(STM32F334x8) || \ + defined(STM32F301x8) || \ + defined(STM32F373xC) || defined(STM32F378xx) || \ + defined(STM32F302xC) +#define __USB_PMA_1x16 +typedef uint32_t usb_pma_t; +#endif /* STM32F303xC || */ + /* STM32F303x8 || STM32F334x8 || */ + /* STM32F301x8 || */ + /* STM32F373xC || STM32F378xx */ +#if defined(STM32F302xE) || defined(STM32F303xD) || defined(STM32F303xE) +#define __USB_PMA_2x16 +typedef uint16_t usb_pma_t; +#endif /* STM32F302xE || STM32F303xD || STM32F303xE */ + /* Includes ------------------------------------------------------------------*/ /* Exported types ------------------------------------------------------------*/ typedef enum _EP_DBUF_DIR @@ -448,11 +464,18 @@ enum EP_BUF_NUM *******************************************************************************/ #define _GetEPAddress(bEpNum) ((uint8_t)(_GetENDPOINT(bEpNum) & EPADDR_FIELD)) -#define _pEPTxAddr(bEpNum) ((uint32_t *)((_GetBTABLE()+bEpNum*8 )*2 + PMAAddr)) -#define _pEPTxCount(bEpNum) ((uint32_t *)((_GetBTABLE()+bEpNum*8+2)*2 + PMAAddr)) -#define _pEPRxAddr(bEpNum) ((uint32_t *)((_GetBTABLE()+bEpNum*8+4)*2 + PMAAddr)) -#define _pEPRxCount(bEpNum) ((uint32_t *)((_GetBTABLE()+bEpNum*8+6)*2 + PMAAddr)) - +#ifdef __USB_PMA_1x16 +#define _pEPTxAddr(bEpNum) ((usb_pma_t *)((_GetBTABLE()+bEpNum*8 )*2 + PMAAddr)) +#define _pEPTxCount(bEpNum) ((usb_pma_t *)((_GetBTABLE()+bEpNum*8+2)*2 + PMAAddr)) +#define _pEPRxAddr(bEpNum) ((usb_pma_t *)((_GetBTABLE()+bEpNum*8+4)*2 + PMAAddr)) +#define _pEPRxCount(bEpNum) ((usb_pma_t *)((_GetBTABLE()+bEpNum*8+6)*2 + PMAAddr)) +#endif /* __USB_PMA_1x16 */ +#ifdef __USB_PMA_2x16 +#define _pEPTxAddr(bEpNum) ((usb_pma_t *)((_GetBTABLE()+bEpNum*8 ) + PMAAddr)) +#define _pEPTxCount(bEpNum) ((usb_pma_t *)((_GetBTABLE()+bEpNum*8+2) + PMAAddr)) +#define _pEPRxAddr(bEpNum) ((usb_pma_t *)((_GetBTABLE()+bEpNum*8+4) + PMAAddr)) +#define _pEPRxCount(bEpNum) ((usb_pma_t *)((_GetBTABLE()+bEpNum*8+6) + PMAAddr)) +#endif /* __USB_PMA_2x16 */ /******************************************************************************* * Macro Name : SetEPTxAddr / SetEPRxAddr. * Description : sets address of the tx/rx buffer. @@ -486,14 +509,14 @@ enum EP_BUF_NUM wNBlocks = wCount >> 5;\ if((wCount & 0x1f) == 0)\ wNBlocks--;\ - *pdwReg = (uint32_t)((wNBlocks << 10) | 0x8000);\ + *pdwReg = (usb_pma_t)((wNBlocks << 10) | 0x8000);\ }/* _BlocksOf32 */ #define _BlocksOf2(dwReg,wCount,wNBlocks) {\ wNBlocks = wCount >> 1;\ if((wCount & 0x1) != 0)\ wNBlocks++;\ - *pdwReg = (uint32_t)(wNBlocks << 10);\ + *pdwReg = (usb_pma_t)(wNBlocks << 10);\ }/* _BlocksOf2 */ #define _SetEPCountRxReg(dwReg,wCount) {\ @@ -505,7 +528,7 @@ enum EP_BUF_NUM #define _SetEPRxDblBuf0Count(bEpNum,wCount) {\ - uint32_t *pdwReg = _pEPTxCount(bEpNum); \ + usb_pma_t *pdwReg = _pEPTxCount(bEpNum); \ _SetEPCountRxReg(pdwReg, wCount);\ } /******************************************************************************* @@ -518,7 +541,7 @@ enum EP_BUF_NUM *******************************************************************************/ #define _SetEPTxCount(bEpNum,wCount) (*_pEPTxCount(bEpNum) = wCount) #define _SetEPRxCount(bEpNum,wCount) {\ - uint32_t *pdwReg = _pEPRxCount(bEpNum); \ + usb_pma_t *pdwReg = _pEPRxCount(bEpNum); \ _SetEPCountRxReg(pdwReg, wCount);\ } /******************************************************************************* @@ -582,7 +605,7 @@ enum EP_BUF_NUM {_SetEPRxDblBuf0Count(bEpNum,wCount);} \ else if(bDir == EP_DBUF_IN)\ /* IN endpoint */ \ - *_pEPTxCount(bEpNum) = (uint32_t)wCount; \ + *_pEPTxCount(bEpNum) = (usb_pma_t)wCount; \ } /* SetEPDblBuf0Count*/ #define _SetEPDblBuf1Count(bEpNum, bDir, wCount) { \ @@ -591,7 +614,7 @@ enum EP_BUF_NUM {_SetEPRxCount(bEpNum,wCount);}\ else if(bDir == EP_DBUF_IN)\ /* IN endpoint */\ - *_pEPRxCount(bEpNum) = (uint32_t)wCount; \ + *_pEPRxCount(bEpNum) = (usb_pma_t)wCount; \ } /* SetEPDblBuf1Count */ #define _SetEPDblBuffCount(bEpNum, bDir, wCount) {\ diff --git a/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/inc/usb_type.h b/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/inc/usb_type.h index 21e16700c8..cdce618704 100755 --- a/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/inc/usb_type.h +++ b/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/inc/usb_type.h @@ -39,11 +39,13 @@ #define NULL ((void *)0) #endif +#if !defined(FALSE) && !defined(TRUE) typedef enum { FALSE = 0, TRUE = !FALSE } -bool; +usb_fs_device_driver_bool; +#endif /* Exported macro ------------------------------------------------------------*/ /* Exported functions ------------------------------------------------------- */ diff --git a/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/src/usb_core.c b/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/src/usb_core.c index 3231a96221..f79a10f36b 100755 --- a/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/src/usb_core.c +++ b/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/src/usb_core.c @@ -50,7 +50,7 @@ /* Private variables ---------------------------------------------------------*/ uint16_t_uint8_t StatusInfo; -bool Data_Mul_MaxPacketSize = FALSE; +uint8_t Data_Mul_MaxPacketSize = FALSE; /* Private function prototypes -----------------------------------------------*/ static void DataStageOut(void); static void DataStageIn(void); @@ -66,7 +66,7 @@ static void Data_Setup0(void); * Return : Return 1 , if the request is invalid when "Length" is 0. * Return "Buffer" if the "Length" is not 0. *******************************************************************************/ -uint8_t *Standard_GetConfiguration(uint16_t Length) +const uint8_t *Standard_GetConfiguration(uint16_t Length) { if (Length == 0) { @@ -112,7 +112,7 @@ RESULT Standard_SetConfiguration(void) * Return : Return 0, if the request is invalid when "Length" is 0. * Return "Buffer" if the "Length" is not 0. *******************************************************************************/ -uint8_t *Standard_GetInterface(uint16_t Length) +const uint8_t *Standard_GetInterface(uint16_t Length) { if (Length == 0) { @@ -168,7 +168,7 @@ RESULT Standard_SetInterface(void) * Return : Return 0, if the request is at end of data block, * or is invalid when "Length" is 0. *******************************************************************************/ -uint8_t *Standard_GetStatus(uint16_t Length) +const uint8_t *Standard_GetStatus(uint16_t Length) { if (Length == 0) { @@ -430,7 +430,7 @@ uint8_t *Standard_GetDescriptorData(uint16_t Length, ONE_DESCRIPTOR *pDesc) return 0; } - return pDesc->Descriptor + wOffset; + return (uint8_t *)(pDesc->Descriptor + wOffset); } /******************************************************************************* @@ -682,7 +682,7 @@ void NoData_Setup0(void) *******************************************************************************/ void Data_Setup0(void) { - uint8_t *(*CopyRoutine)(uint16_t); + const uint8_t *(*CopyRoutine)(uint16_t); RESULT Result; uint32_t Request_No = pInformation->USBbRequest; @@ -787,7 +787,7 @@ void Data_Setup0(void) if (CopyRoutine) { pInformation->Ctrl_Info.Usb_wOffset = wOffset; - pInformation->Ctrl_Info.CopyData = CopyRoutine; + pInformation->Ctrl_Info.CopyData = (typeof(pInformation->Ctrl_Info.CopyData))CopyRoutine; /* sb in the original the cast to word was directly */ /* now the cast is made step by step */ (*CopyRoutine)(0); @@ -859,7 +859,7 @@ void Data_Setup0(void) * Output : None. * Return : Post0_Process. *******************************************************************************/ -uint8_t Setup0_Process(void) +uint8_t __attribute__((optimize("O0"))) Setup0_Process(void) { union @@ -867,9 +867,21 @@ uint8_t Setup0_Process(void) uint8_t* b; uint16_t* w; } pBuf; + +#ifdef STM32F10X_CL + USB_OTG_EP *ep; + uint16_t offset = 0; + + ep = PCD_GetOutEP(ENDP0); + pBuf.b = ep->xfer_buff; +#elif defined(STM32F303xD) || defined(STM32F303xE) + uint16_t offset = 0; + pBuf.b = (uint8_t *)(PMAAddr + _GetEPRxAddr(ENDP0)); +#else uint16_t offset = 1; pBuf.b = PMAAddr + (uint8_t *)(_GetEPRxAddr(ENDP0) * 2); /* *2 for 32 bits addr */ +#endif /* STM32F10X_CL */ if (pInformation->ControlState != PAUSE) { diff --git a/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/src/usb_mem.c b/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/src/usb_mem.c index 4e0748ac39..0d00951aba 100755 --- a/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/src/usb_mem.c +++ b/flight/pios/stm32f30x/libraries/STM32_USB-FS-Device_Driver/src/usb_mem.c @@ -36,6 +36,11 @@ /* Private function prototypes -----------------------------------------------*/ /* Private functions ---------------------------------------------------------*/ +#if defined(STM32F303xC) || \ + defined(STM32F303x8) || defined(STM32F334x8) || \ + defined(STM32F301x8) || \ + defined(STM32F373xC) || defined(STM32F378xx) || \ + defined(STM32F302xC) /******************************************************************************* * Function Name : UserToPMABufferCopy * Description : Copy a buffer from user memory area to packet memory area (PMA) @@ -64,7 +69,7 @@ void UserToPMABufferCopy(uint8_t *pbUsrBuf, uint16_t wPMABufAddr, uint16_t wNByt /******************************************************************************* * Function Name : PMAToUserBufferCopy -* Description : Copy a buffer from user memory area to packet memory area (PMA) +* Description : Copy a buffer from packet memory area (PMA) to user memory area * Input : - pbUsrBuf = pointer to user memory area. * - wPMABufAddr = address into PMA. * - wNBytes = no. of bytes to be copied. @@ -83,5 +88,58 @@ void PMAToUserBufferCopy(uint8_t *pbUsrBuf, uint16_t wPMABufAddr, uint16_t wNByt pbUsrBuf++; } } +#endif /* STM32F303xC || */ + /* STM32F303x8 || STM32F334x8 || */ + /* STM32F301x8 || */ + /* STM32F373xC || STM32F378xx */ +#if defined(STM32F302xE) || defined(STM32F303xD) || defined(STM32F303xE) +/******************************************************************************* +* Function Name : UserToPMABufferCopy +* Description : Copy a buffer from user memory area to packet memory area (PMA) +* Input : - pbUsrBuf: pointer to user memory area. +* - wPMABufAddr: address into PMA. +* - wNBytes: no. of bytes to be copied. +* Output : None. +* Return : None . +*******************************************************************************/ +void UserToPMABufferCopy(uint8_t *pbUsrBuf, uint16_t wPMABufAddr, uint16_t wNBytes) +{ + uint32_t n = ((uint32_t)((uint32_t)wNBytes + 1U)) >> 1U; + uint32_t i; + uint16_t temp1, temp2; + uint16_t *pdwVal; + pdwVal = (uint16_t *)((uint32_t)(wPMABufAddr + PMAAddr)); + for (i = n; i != 0U; i--) + { + temp1 = (uint16_t) * pbUsrBuf; + pbUsrBuf++; + temp2 = temp1 | ((uint16_t)((uint16_t) * pbUsrBuf << 8U)) ; + *pdwVal++ = temp2; + pbUsrBuf++; + } +} + +/******************************************************************************* +* Function Name : PMAToUserBufferCopy +* Description : Copy a buffer from packet memory area (PMA) to user memory area +* Input : - pbUsrBuf = pointer to user memory area. +* - wPMABufAddr = address into PMA. +* - wNBytes = no. of bytes to be copied. +* Output : None. +* Return : None. +*******************************************************************************/ +void PMAToUserBufferCopy(uint8_t *pbUsrBuf, uint16_t wPMABufAddr, uint16_t wNBytes) +{ + uint32_t n = ((uint32_t)((uint32_t)wNBytes + 1U)) >> 1U; + uint32_t i; + uint16_t *pdwVal; + pdwVal = (uint16_t *)((uint32_t)(wPMABufAddr + PMAAddr)); + for (i = n; i != 0U; i--) + { + *(uint16_t*)((uint32_t)pbUsrBuf++) = *pdwVal++; + pbUsrBuf++; + } +} +#endif /* STM32F302xE || STM32F303xD || STM32F303xE */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ From 5435dbd4645f48b9c352a80de6653b197b5630b9 Mon Sep 17 00:00:00 2001 From: Vladimir Zidar Date: Mon, 22 May 2017 15:08:04 +0200 Subject: [PATCH 265/624] LP-512 Initial F3 support --- Makefile | 1 + flight/Makefile | 4 + flight/make/apps-defs.mk | 10 +- flight/make/boot-defs.mk | 10 +- flight/modules/Battery/battery.c | 18 +- flight/modules/Sensors/sensors.c | 3 +- .../modules/StateEstimation/stateestimation.c | 9 + flight/modules/System/systemmod.c | 6 +- .../libraries/FreeRTOS/Source/openocd.c | 20 + .../common/libraries/msheap/pios_msheap.c | 3 + flight/pios/common/pios_board_io.c | 3 +- flight/pios/common/pios_board_sensors.c | 21 + flight/pios/common/pios_mpu6000.c | 233 ++++- flight/pios/common/pios_mpu9250.c | 19 +- flight/pios/common/pios_sbus.c | 9 +- flight/pios/common/pios_servo.c | 19 +- flight/pios/inc/pios_board_hw.h | 3 + flight/pios/inc/pios_com.h | 7 - flight/pios/inc/pios_flash_jedec_catalog.h | 9 + flight/pios/inc/pios_i2c.h | 6 +- flight/pios/inc/pios_i2c_priv.h | 2 +- flight/pios/inc/pios_mpu6000.h | 3 +- flight/pios/inc/pios_mpu9250.h | 1 + flight/pios/inc/pios_sbus_priv.h | 5 - .../{stm32f10x => }/inc/pios_usb_hid_istr.h | 0 .../{stm32f10x => }/inc/pios_usb_hid_pwr.h | 0 flight/pios/pios.h | 2 + flight/pios/stm32f0x/pios_usart.c | 2 - flight/pios/stm32f10x/library.mk | 2 +- flight/pios/stm32f10x/pios_usbhook.c | 3 + flight/pios/stm32f30x/inc/pios_architecture.h | 39 + flight/pios/stm32f30x/inc/pios_delay_raw.h | 43 + flight/pios/stm32f30x/inc/pios_servo_config.h | 52 + flight/pios/stm32f30x/inc/pios_usart_config.h | 39 + flight/pios/stm32f30x/inc/stm32f30x_conf.h | 82 ++ flight/pios/stm32f30x/inc/usb_conf.h | 197 ++++ flight/pios/stm32f30x/library.mk | 69 ++ .../link_STM32F303CCT_CC_Rev1_bl_memory.ld | 7 + .../link_STM32F303CCT_CC_Rev1_fw_memory.ld | 8 + .../link_STM32F303CCT_CC_Rev1_sections.ld | 197 ++++ flight/pios/stm32f30x/pios_bkp.c | 111 ++ flight/pios/stm32f30x/pios_bl_helper.c | 127 +++ flight/pios/stm32f30x/pios_can.c | 429 ++++++++ flight/pios/stm32f30x/pios_debug.c | 178 ++++ flight/pios/stm32f30x/pios_delay.c | 184 ++++ flight/pios/stm32f30x/pios_exti.c | 326 ++++++ flight/pios/stm32f30x/pios_flash_internal.c | 304 ++++++ flight/pios/stm32f30x/pios_gpio.c | 170 +++ flight/pios/stm32f30x/pios_i2c.c | 924 ++++++++++++++++ flight/pios/stm32f30x/pios_irq.c | 97 ++ flight/pios/stm32f30x/pios_ppm.c | 401 +++++++ flight/pios/stm32f30x/pios_pwm.c | 283 +++++ flight/pios/stm32f30x/pios_rtc.c | 148 +++ flight/pios/stm32f30x/pios_spi.c | 738 +++++++++++++ flight/pios/stm32f30x/pios_sys.c | 283 +++++ flight/pios/stm32f30x/pios_tim.c | 371 +++++++ flight/pios/stm32f30x/pios_usart.c | 528 ++++++++++ flight/pios/stm32f30x/pios_usb.c | 290 +++++ flight/pios/stm32f30x/pios_usb_cdc.c | 491 +++++++++ flight/pios/stm32f30x/pios_usb_hid.c | 372 +++++++ flight/pios/stm32f30x/pios_usb_hid_istr.c | 336 ++++++ flight/pios/stm32f30x/pios_usb_hid_pwr.c | 292 ++++++ flight/pios/stm32f30x/pios_usbhook.c | 572 ++++++++++ flight/pios/stm32f30x/pios_wdg.c | 186 ++++ flight/pios/stm32f30x/startup.c | 189 ++++ flight/pios/stm32f30x/vectors_stm32f30x.c | 309 ++++++ flight/pios/stm32f4xx/library.mk | 2 +- flight/pios/stm32f4xx/pios_i2c.c | 130 ++- flight/targets/boards/ccf3d/board-info.mk | 24 + flight/targets/boards/ccf3d/board_hw_defs.c | 861 +++++++++++++++ .../targets/boards/ccf3d/bootloader/Makefile | 29 + .../boards/ccf3d/bootloader/inc/common.h | 115 ++ .../boards/ccf3d/bootloader/inc/pios_config.h | 53 + .../bootloader/inc/pios_usb_board_data.h | 53 + flight/targets/boards/ccf3d/bootloader/main.c | 228 ++++ .../boards/ccf3d/bootloader/pios_board.c | 102 ++ flight/targets/boards/ccf3d/firmware/Makefile | 117 +++ .../boards/ccf3d/firmware/UAVObjects.inc | 135 +++ .../ccf3d/firmware/cm3_fault_handlers.c | 93 ++ .../boards/ccf3d/firmware/coptercontrol.cpp | 98 ++ .../targets/boards/ccf3d/firmware/dcc_stdio.c | 149 +++ .../ccf3d/firmware/inc/FreeRTOSConfig.h | 99 ++ .../boards/ccf3d/firmware/inc/dcc_stdio.h | 36 + .../boards/ccf3d/firmware/inc/openpilot.h | 52 + .../ccf3d/firmware/inc/pios_board_posix.h | 81 ++ .../boards/ccf3d/firmware/inc/pios_config.h | 189 ++++ .../ccf3d/firmware/inc/pios_config_posix.h | 48 + .../ccf3d/firmware/inc/pios_usb_board_data.h | 47 + .../boards/ccf3d/firmware/pios_board.c | 343 ++++++ .../boards/ccf3d/firmware/pios_board_posix.c | 145 +++ flight/targets/boards/ccf3d/pios_board.h | 312 ++++++ .../boards/ccf3d/pios_usb_board_data.c | 102 ++ flight/targets/boards/revoproto/pios_board.h | 20 - .../targets/boards/spracingf3/board-info.mk | 24 + .../targets/boards/spracingf3/board_hw_defs.c | 832 +++++++++++++++ .../boards/spracingf3/bootloader/Makefile | 39 + .../boards/spracingf3/bootloader/inc/common.h | 115 ++ .../spracingf3/bootloader/inc/pios_config.h | 52 + .../boards/spracingf3/bootloader/main.c | 276 +++++ .../boards/spracingf3/bootloader/memory.ld | 7 + .../boards/spracingf3/bootloader/pios_board.c | 84 ++ .../boards/spracingf3/common/sections.ld | 197 ++++ .../targets/boards/spracingf3/common/system.c | 354 +++++++ .../boards/spracingf3/firmware/Makefile | 118 +++ .../boards/spracingf3/firmware/UAVObjects.inc | 136 +++ .../spracingf3/firmware/cm3_fault_handlers.c | 93 ++ .../boards/spracingf3/firmware/dcc_stdio.c | 149 +++ .../spracingf3/firmware/inc/FreeRTOSConfig.h | 99 ++ .../spracingf3/firmware/inc/dcc_stdio.h | 36 + .../spracingf3/firmware/inc/openpilot.h | 52 + .../firmware/inc/pios_board_posix.h | 81 ++ .../spracingf3/firmware/inc/pios_config.h | 193 ++++ .../firmware/inc/pios_config_posix.h | 48 + .../boards/spracingf3/firmware/main.cpp | 100 ++ .../boards/spracingf3/firmware/memory.ld | 7 + .../boards/spracingf3/firmware/pios_board.c | 280 +++++ .../spracingf3/firmware/pios_board_posix.c | 145 +++ flight/targets/boards/spracingf3/pios_board.h | 242 +++++ .../boards/spracingf3evo/board-info.mk | 29 + .../boards/spracingf3evo/board_hw_defs.c | 902 ++++++++++++++++ .../boards/spracingf3evo/bootloader/Makefile | 29 + .../spracingf3evo/bootloader/inc/common.h | 115 ++ .../bootloader/inc/pios_config.h | 53 + .../bootloader/inc/pios_usb_board_data.h | 53 + .../boards/spracingf3evo/bootloader/main.c | 229 ++++ .../boards/spracingf3evo/bootloader/memory.ld | 7 + .../spracingf3evo/bootloader/pios_board.c | 100 ++ .../boards/spracingf3evo/common/sections.ld | 198 ++++ .../boards/spracingf3evo/common/system.c | 354 +++++++ .../boards/spracingf3evo/firmware/Makefile | 117 +++ .../spracingf3evo/firmware/UAVObjects.inc | 136 +++ .../firmware/cm3_fault_handlers.c | 93 ++ .../boards/spracingf3evo/firmware/dcc_stdio.c | 149 +++ .../firmware/inc/FreeRTOSConfig.h | 99 ++ .../spracingf3evo/firmware/inc/dcc_stdio.h | 36 + .../spracingf3evo/firmware/inc/openpilot.h | 52 + .../firmware/inc/pios_board_posix.h | 81 ++ .../spracingf3evo/firmware/inc/pios_config.h | 192 ++++ .../firmware/inc/pios_config_posix.h | 48 + .../firmware/inc/pios_usb_board_data.h | 47 + .../boards/spracingf3evo/firmware/main.cpp | 98 ++ .../boards/spracingf3evo/firmware/memory.ld | 8 + .../spracingf3evo/firmware/pios_board.c | 264 +++++ .../spracingf3evo/firmware/pios_board_posix.c | 145 +++ .../targets/boards/spracingf3evo/pios_board.h | 248 +++++ .../spracingf3evo/pios_usb_board_data.c | 103 ++ .../common/bootloader_updater/Makefile | 14 +- ground/gcs/src/plugins/config/config.pro | 3 + .../gcs/src/plugins/config/configgadget.qrc | 1 + .../src/plugins/config/configgadgetwidget.cpp | 29 +- .../src/plugins/config/configoutputwidget.cpp | 8 + .../config/configspracingf3hwwidget.cpp | 467 +++++++++ .../plugins/config/configspracingf3hwwidget.h | 60 ++ .../config/configspracingf3hwwidget.ui | 989 ++++++++++++++++++ .../plugins/config/images/spracingf3_top.png | Bin 0 -> 128896 bytes .../setupwizard/pages/controllerpage.cpp | 19 + .../setupwizard/vehicleconfigurationsource.h | 2 +- .../gcs/src/plugins/uavobjects/uavobjects.pro | 2 + .../uavobjectutil/devicedescriptorstruct.h | 6 + .../hwspracingf3evosettings.xml | 15 + .../hwspracingf3settings.xml | 16 + shared/uavobjectdefinition/revosettings.xml | 2 +- 162 files changed, 22657 insertions(+), 188 deletions(-) create mode 100644 flight/pios/common/libraries/FreeRTOS/Source/openocd.c rename flight/pios/{stm32f10x => }/inc/pios_usb_hid_istr.h (100%) rename flight/pios/{stm32f10x => }/inc/pios_usb_hid_pwr.h (100%) create mode 100644 flight/pios/stm32f30x/inc/pios_architecture.h create mode 100644 flight/pios/stm32f30x/inc/pios_delay_raw.h create mode 100644 flight/pios/stm32f30x/inc/pios_servo_config.h create mode 100644 flight/pios/stm32f30x/inc/pios_usart_config.h create mode 100644 flight/pios/stm32f30x/inc/stm32f30x_conf.h create mode 100644 flight/pios/stm32f30x/inc/usb_conf.h create mode 100644 flight/pios/stm32f30x/library.mk create mode 100644 flight/pios/stm32f30x/link_STM32F303CCT_CC_Rev1_bl_memory.ld create mode 100644 flight/pios/stm32f30x/link_STM32F303CCT_CC_Rev1_fw_memory.ld create mode 100644 flight/pios/stm32f30x/link_STM32F303CCT_CC_Rev1_sections.ld create mode 100644 flight/pios/stm32f30x/pios_bkp.c create mode 100644 flight/pios/stm32f30x/pios_bl_helper.c create mode 100644 flight/pios/stm32f30x/pios_can.c create mode 100644 flight/pios/stm32f30x/pios_debug.c create mode 100644 flight/pios/stm32f30x/pios_delay.c create mode 100644 flight/pios/stm32f30x/pios_exti.c create mode 100644 flight/pios/stm32f30x/pios_flash_internal.c create mode 100644 flight/pios/stm32f30x/pios_gpio.c create mode 100644 flight/pios/stm32f30x/pios_i2c.c create mode 100644 flight/pios/stm32f30x/pios_irq.c create mode 100644 flight/pios/stm32f30x/pios_ppm.c create mode 100644 flight/pios/stm32f30x/pios_pwm.c create mode 100644 flight/pios/stm32f30x/pios_rtc.c create mode 100644 flight/pios/stm32f30x/pios_spi.c create mode 100644 flight/pios/stm32f30x/pios_sys.c create mode 100644 flight/pios/stm32f30x/pios_tim.c create mode 100644 flight/pios/stm32f30x/pios_usart.c create mode 100644 flight/pios/stm32f30x/pios_usb.c create mode 100644 flight/pios/stm32f30x/pios_usb_cdc.c create mode 100644 flight/pios/stm32f30x/pios_usb_hid.c create mode 100644 flight/pios/stm32f30x/pios_usb_hid_istr.c create mode 100644 flight/pios/stm32f30x/pios_usb_hid_pwr.c create mode 100644 flight/pios/stm32f30x/pios_usbhook.c create mode 100644 flight/pios/stm32f30x/pios_wdg.c create mode 100644 flight/pios/stm32f30x/startup.c create mode 100644 flight/pios/stm32f30x/vectors_stm32f30x.c create mode 100644 flight/targets/boards/ccf3d/board-info.mk create mode 100644 flight/targets/boards/ccf3d/board_hw_defs.c create mode 100644 flight/targets/boards/ccf3d/bootloader/Makefile create mode 100644 flight/targets/boards/ccf3d/bootloader/inc/common.h create mode 100644 flight/targets/boards/ccf3d/bootloader/inc/pios_config.h create mode 100644 flight/targets/boards/ccf3d/bootloader/inc/pios_usb_board_data.h create mode 100644 flight/targets/boards/ccf3d/bootloader/main.c create mode 100644 flight/targets/boards/ccf3d/bootloader/pios_board.c create mode 100644 flight/targets/boards/ccf3d/firmware/Makefile create mode 100644 flight/targets/boards/ccf3d/firmware/UAVObjects.inc create mode 100644 flight/targets/boards/ccf3d/firmware/cm3_fault_handlers.c create mode 100644 flight/targets/boards/ccf3d/firmware/coptercontrol.cpp create mode 100644 flight/targets/boards/ccf3d/firmware/dcc_stdio.c create mode 100644 flight/targets/boards/ccf3d/firmware/inc/FreeRTOSConfig.h create mode 100644 flight/targets/boards/ccf3d/firmware/inc/dcc_stdio.h create mode 100644 flight/targets/boards/ccf3d/firmware/inc/openpilot.h create mode 100644 flight/targets/boards/ccf3d/firmware/inc/pios_board_posix.h create mode 100644 flight/targets/boards/ccf3d/firmware/inc/pios_config.h create mode 100644 flight/targets/boards/ccf3d/firmware/inc/pios_config_posix.h create mode 100644 flight/targets/boards/ccf3d/firmware/inc/pios_usb_board_data.h create mode 100644 flight/targets/boards/ccf3d/firmware/pios_board.c create mode 100644 flight/targets/boards/ccf3d/firmware/pios_board_posix.c create mode 100644 flight/targets/boards/ccf3d/pios_board.h create mode 100644 flight/targets/boards/ccf3d/pios_usb_board_data.c create mode 100644 flight/targets/boards/spracingf3/board-info.mk create mode 100644 flight/targets/boards/spracingf3/board_hw_defs.c create mode 100644 flight/targets/boards/spracingf3/bootloader/Makefile create mode 100644 flight/targets/boards/spracingf3/bootloader/inc/common.h create mode 100644 flight/targets/boards/spracingf3/bootloader/inc/pios_config.h create mode 100644 flight/targets/boards/spracingf3/bootloader/main.c create mode 100644 flight/targets/boards/spracingf3/bootloader/memory.ld create mode 100644 flight/targets/boards/spracingf3/bootloader/pios_board.c create mode 100644 flight/targets/boards/spracingf3/common/sections.ld create mode 100644 flight/targets/boards/spracingf3/common/system.c create mode 100644 flight/targets/boards/spracingf3/firmware/Makefile create mode 100644 flight/targets/boards/spracingf3/firmware/UAVObjects.inc create mode 100644 flight/targets/boards/spracingf3/firmware/cm3_fault_handlers.c create mode 100644 flight/targets/boards/spracingf3/firmware/dcc_stdio.c create mode 100644 flight/targets/boards/spracingf3/firmware/inc/FreeRTOSConfig.h create mode 100644 flight/targets/boards/spracingf3/firmware/inc/dcc_stdio.h create mode 100644 flight/targets/boards/spracingf3/firmware/inc/openpilot.h create mode 100644 flight/targets/boards/spracingf3/firmware/inc/pios_board_posix.h create mode 100644 flight/targets/boards/spracingf3/firmware/inc/pios_config.h create mode 100644 flight/targets/boards/spracingf3/firmware/inc/pios_config_posix.h create mode 100644 flight/targets/boards/spracingf3/firmware/main.cpp create mode 100644 flight/targets/boards/spracingf3/firmware/memory.ld create mode 100644 flight/targets/boards/spracingf3/firmware/pios_board.c create mode 100644 flight/targets/boards/spracingf3/firmware/pios_board_posix.c create mode 100644 flight/targets/boards/spracingf3/pios_board.h create mode 100644 flight/targets/boards/spracingf3evo/board-info.mk create mode 100644 flight/targets/boards/spracingf3evo/board_hw_defs.c create mode 100644 flight/targets/boards/spracingf3evo/bootloader/Makefile create mode 100644 flight/targets/boards/spracingf3evo/bootloader/inc/common.h create mode 100644 flight/targets/boards/spracingf3evo/bootloader/inc/pios_config.h create mode 100644 flight/targets/boards/spracingf3evo/bootloader/inc/pios_usb_board_data.h create mode 100644 flight/targets/boards/spracingf3evo/bootloader/main.c create mode 100644 flight/targets/boards/spracingf3evo/bootloader/memory.ld create mode 100644 flight/targets/boards/spracingf3evo/bootloader/pios_board.c create mode 100644 flight/targets/boards/spracingf3evo/common/sections.ld create mode 100644 flight/targets/boards/spracingf3evo/common/system.c create mode 100644 flight/targets/boards/spracingf3evo/firmware/Makefile create mode 100644 flight/targets/boards/spracingf3evo/firmware/UAVObjects.inc create mode 100644 flight/targets/boards/spracingf3evo/firmware/cm3_fault_handlers.c create mode 100644 flight/targets/boards/spracingf3evo/firmware/dcc_stdio.c create mode 100644 flight/targets/boards/spracingf3evo/firmware/inc/FreeRTOSConfig.h create mode 100644 flight/targets/boards/spracingf3evo/firmware/inc/dcc_stdio.h create mode 100644 flight/targets/boards/spracingf3evo/firmware/inc/openpilot.h create mode 100644 flight/targets/boards/spracingf3evo/firmware/inc/pios_board_posix.h create mode 100644 flight/targets/boards/spracingf3evo/firmware/inc/pios_config.h create mode 100644 flight/targets/boards/spracingf3evo/firmware/inc/pios_config_posix.h create mode 100644 flight/targets/boards/spracingf3evo/firmware/inc/pios_usb_board_data.h create mode 100644 flight/targets/boards/spracingf3evo/firmware/main.cpp create mode 100644 flight/targets/boards/spracingf3evo/firmware/memory.ld create mode 100644 flight/targets/boards/spracingf3evo/firmware/pios_board.c create mode 100644 flight/targets/boards/spracingf3evo/firmware/pios_board_posix.c create mode 100644 flight/targets/boards/spracingf3evo/pios_board.h create mode 100644 flight/targets/boards/spracingf3evo/pios_usb_board_data.c create mode 100644 ground/gcs/src/plugins/config/configspracingf3hwwidget.cpp create mode 100644 ground/gcs/src/plugins/config/configspracingf3hwwidget.h create mode 100644 ground/gcs/src/plugins/config/configspracingf3hwwidget.ui create mode 100644 ground/gcs/src/plugins/config/images/spracingf3_top.png create mode 100644 shared/uavobjectdefinition/hwspracingf3evosettings.xml create mode 100644 shared/uavobjectdefinition/hwspracingf3settings.xml diff --git a/Makefile b/Makefile index 92a13b3758..f5bce619da 100644 --- a/Makefile +++ b/Makefile @@ -340,6 +340,7 @@ PACKAGE_FW_TARGETS += fw_oplinkmini PACKAGE_FW_TARGETS += fw_gpsplatinum PACKAGE_FW_TARGETS += fw_osd PACKAGE_FW_TARGETS += fw_revoproto +PACKAGE_FW_TARGETS += fw_spracingf3evo fw_spracingf3 # Rules to generate GCS resources used to embed firmware binaries into the GCS. # They are used later by the vehicle setup wizard to update board firmware. diff --git a/flight/Makefile b/flight/Makefile index 3dca7b524a..afd76c2d72 100644 --- a/flight/Makefile +++ b/flight/Makefile @@ -14,12 +14,16 @@ ALL_BOARDS += oplinkmini ALL_BOARDS += gpsplatinum ALL_BOARDS += osd ALL_BOARDS += discoveryf4bare +ALL_BOARDS += ccf3d spracingf3 spracingf3evo # SimPosix only builds on Linux ifeq ($(UNAME), Linux) ALL_BOARDS += simposix endif # Short names of each board (used to display board name in parallel builds) +spracingf3_short := 'srf3' +spracingf3evo_short := 'spev' +ccf3d_short := 'cf3d' coptercontrol_short := 'cc ' oplinkmini_short := 'oplm' revolution_short := 'revo' diff --git a/flight/make/apps-defs.mk b/flight/make/apps-defs.mk index 7b661bb8e2..030b71d2b5 100644 --- a/flight/make/apps-defs.mk +++ b/flight/make/apps-defs.mk @@ -54,14 +54,16 @@ include $(FREERTOS_DIR)/library.mk OPTESTS = $(TOPDIR)/Tests ## PIOS Hardware -ifeq ($(MCU),cortex-m3) +ifneq (,$(findstring STM32F10,$(CHIP))) include $(PIOS)/stm32f10x/library.mk -else ifeq ($(MCU),cortex-m4) +else ifneq (,$(findstring STM32F4,$(CHIP))) include $(PIOS)/stm32f4xx/library.mk -else ifeq ($(MCU),cortex-m0) +else ifneq (,$(findstring STM32F30,$(CHIP))) + include $(PIOS)/stm32f30x/library.mk +else ifneq (,$(findstring STM32F0,$(CHIP))) include $(PIOS)/stm32f0x/library.mk else - $(error Unsupported MCU: $(MCU)) + $(error Unsupported CHIP: $(CHIP)) endif # List C source files here (C dependencies are automatically generated). diff --git a/flight/make/boot-defs.mk b/flight/make/boot-defs.mk index 42629af9c4..588f6e2436 100644 --- a/flight/make/boot-defs.mk +++ b/flight/make/boot-defs.mk @@ -34,14 +34,16 @@ FLIGHTLIBINC = $(FLIGHTLIB)/inc override USE_DSP_LIB := NO ## PIOS Hardware -ifeq ($(MCU),cortex-m3) +ifneq (,$(findstring STM32F10,$(CHIP))) include $(PIOS)/stm32f10x/library.mk -else ifeq ($(MCU),cortex-m4) +else ifneq (,$(findstring STM32F4,$(CHIP))) include $(PIOS)/stm32f4xx/library.mk -else ifeq ($(MCU),cortex-m0) +else ifneq (,$(findstring STM32F30,$(CHIP))) + include $(PIOS)/stm32f30x/library.mk +else ifneq (,$(findstring STM32F0,$(CHIP))) include $(PIOS)/stm32f0x/library.mk else - $(error Unsupported MCU: $(MCU)) + $(error Unsupported CHIP: $(CHIP)) endif # List C source files here (C dependencies are automatically generated). diff --git a/flight/modules/Battery/battery.c b/flight/modules/Battery/battery.c index ec17815c58..88ad581862 100644 --- a/flight/modules/Battery/battery.c +++ b/flight/modules/Battery/battery.c @@ -87,11 +87,10 @@ int32_t BatteryInitialize(void) batteryEnabled = true; #else HwSettingsInitialize(); - uint8_t optionalModules[HWSETTINGS_OPTIONALMODULES_NUMELEM]; + HwSettingsOptionalModulesData optionalModules; + HwSettingsOptionalModulesGet(&optionalModules); - HwSettingsOptionalModulesGet(optionalModules); - - if ((optionalModules[HWSETTINGS_OPTIONALMODULES_BATTERY] == HWSETTINGS_OPTIONALMODULES_ENABLED)) { + if (optionalModules.Battery == HWSETTINGS_OPTIONALMODULES_ENABLED) { batteryEnabled = true; } else { batteryEnabled = false; @@ -149,17 +148,19 @@ static void onTimer(__attribute__((unused)) UAVObjEvent *ev) batterySettings.ResetConsumedEnergy = false; FlightBatterySettingsSet(&batterySettings); } - +#ifdef PIOS_INCLUDE_ADC // calculate the battery parameters if (voltageADCPin >= 0) { flightBatteryData.Voltage = (PIOS_ADC_PinGetVolt(voltageADCPin) - batterySettings.SensorCalibrations.VoltageZero) * batterySettings.SensorCalibrations.VoltageFactor; // in Volts } else { flightBatteryData.Voltage = 0; // Dummy placeholder value. This is in case we get another source of battery current which is not from the ADC } - +#else + flightBatteryData.Voltage = 0; +#endif /* PIOS_INCLUDE_ADC */ // voltage available: get the number of cells if possible, desired and not armed GetNbCells(&batterySettings, &flightBatteryData); - +#ifdef PIOS_INCLUDE_ADC // ad a plausibility check: zero voltage => zero current if (currentADCPin >= 0 && flightBatteryData.Voltage > 0.f) { flightBatteryData.Current = (PIOS_ADC_PinGetVolt(currentADCPin) - batterySettings.SensorCalibrations.CurrentZero) * batterySettings.SensorCalibrations.CurrentFactor; // in Amps @@ -169,6 +170,9 @@ static void onTimer(__attribute__((unused)) UAVObjEvent *ev) } else { // If there's no current measurement, we still need to assign one. Make it negative, so it can never trigger an alarm flightBatteryData.Current = -0; // Dummy placeholder value. This is in case we get another source of battery current which is not from the ADC } +#else + flightBatteryData.Current = -0; +#endif /* PIOS_INCLUDE_ADC */ // For safety reasons consider only positive currents in energy comsumption, i.e. no charging up. // necesary when sensor are not perfectly calibrated diff --git a/flight/modules/Sensors/sensors.c b/flight/modules/Sensors/sensors.c index a08e74b64f..3f9cfffd68 100644 --- a/flight/modules/Sensors/sensors.c +++ b/flight/modules/Sensors/sensors.c @@ -63,7 +63,6 @@ #include #include #include -#include #include #include @@ -284,7 +283,7 @@ static void SensorsTask(__attribute__((unused)) void *parameters) count++; } - PIOS_Assert(count); +// PIOS_Assert(count); RELOAD_WDG(); if (!sensors_test) { AlarmsSet(SYSTEMALARMS_ALARM_SENSORS, SYSTEMALARMS_ALARM_CRITICAL); diff --git a/flight/modules/StateEstimation/stateestimation.c b/flight/modules/StateEstimation/stateestimation.c index ad06cba0e4..5088b364ac 100644 --- a/flight/modules/StateEstimation/stateestimation.c +++ b/flight/modules/StateEstimation/stateestimation.c @@ -165,6 +165,12 @@ static float gyroRaw[3]; static float gyroDelta[3]; // preconfigured filter chains selectable via revoSettings.FusionAlgorithm + +static const filterPipeline *acroQueue = &(filterPipeline) { + .filter = &cfFilter, + .next = NULL, +}; + static const filterPipeline *cfQueue = &(filterPipeline) { .filter = &airFilter, .next = &(filterPipeline) { @@ -434,6 +440,9 @@ static void StateEstimationCb(void) if (fsarmed == FLIGHTSTATUS_ARMED_DISARMED || fusionAlgorithm == FILTER_INIT_FORCE) { const filterPipeline *newFilterChain; switch ((RevoSettingsFusionAlgorithmOptions)revoSettings.FusionAlgorithm) { + case REVOSETTINGS_FUSIONALGORITHM_ACRONOSENSORS: + newFilterChain = acroQueue; + break; case REVOSETTINGS_FUSIONALGORITHM_BASICCOMPLEMENTARY: newFilterChain = cfQueue; // reinit Mag alarm diff --git a/flight/modules/System/systemmod.c b/flight/modules/System/systemmod.c index fb59876be5..9f1aa728fb 100644 --- a/flight/modules/System/systemmod.c +++ b/flight/modules/System/systemmod.c @@ -579,7 +579,11 @@ static uint16_t GetFreeIrqStackSize(void) #if !defined(ARCH_POSIX) && !defined(ARCH_WIN32) && defined(CHECK_IRQ_STACK) extern uint32_t _irq_stack_top; extern uint32_t _irq_stack_end; - uint32_t pattern = 0x0000A5A5; +#ifdef STM32F3 + uint32_t pattern = 0xA5A5A5A5; +#else + uint32_t pattern = 0xA5A5; +#endif uint32_t *ptr = &_irq_stack_end; #if 1 /* the ugly way accurate but takes more time, useful for debugging */ diff --git a/flight/pios/common/libraries/FreeRTOS/Source/openocd.c b/flight/pios/common/libraries/FreeRTOS/Source/openocd.c new file mode 100644 index 0000000000..a595d1d3ff --- /dev/null +++ b/flight/pios/common/libraries/FreeRTOS/Source/openocd.c @@ -0,0 +1,20 @@ +/* + * Since at least FreeRTOS V7.5.3 uxTopUsedPriority is no longer + * present in the kernel, so it has to be supplied by other means for + * OpenOCD's threads awareness. + * + * Add this file to your project, and, if you're using --gc-sections, + * ``--undefined=uxTopUsedPriority'' (or + * ``-Wl,--undefined=uxTopUsedPriority'' when using gcc for final + * linking) to your LDFLAGS; same with all the other symbols you need. + */ + +#include "FreeRTOS.h" + +#ifdef __GNUC__ +#define USED __attribute__((section(".keep"))) +#else +#define USED +#endif + +const int USED uxTopUsedPriority = configMAX_PRIORITIES; diff --git a/flight/pios/common/libraries/msheap/pios_msheap.c b/flight/pios/common/libraries/msheap/pios_msheap.c index e7e03f8c65..f28d2f644b 100644 --- a/flight/pios/common/libraries/msheap/pios_msheap.c +++ b/flight/pios/common/libraries/msheap/pios_msheap.c @@ -81,6 +81,9 @@ pios_general_malloc(void *ptr, size_t s, bool use_fast_heap) vPortEnterCritical(); if(use_fast_heap){ p = msheap_alloc(&fast_heap, ptr, s); + if(!p) { + p = msheap_alloc(&sram_heap, ptr, s); + } } else { p = msheap_alloc(&sram_heap, ptr, s); } diff --git a/flight/pios/common/pios_board_io.c b/flight/pios/common/pios_board_io.c index d2b236fb8a..407ca862f3 100644 --- a/flight/pios/common/pios_board_io.c +++ b/flight/pios/common/pios_board_io.c @@ -233,7 +233,7 @@ void PIOS_BOARD_IO_Configure_USB_Function(PIOS_BOARD_IO_USB_HID_Function hid_fun #endif /* PIOS_INCLUDE_USB_HID */ -#ifndef STM32F10X +#if !defined(STM32F1) && !defined(STM32F3) PIOS_USBHOOK_Activate(); #endif } @@ -672,7 +672,6 @@ void PIOS_BOARD_IO_Configure_RFM22B() OPLinkStatusSet(&oplinkStatus); } - void PIOS_BOARD_IO_Configure_RadioAuxStream(HwSettingsRadioAuxStreamOptions radioaux) { switch (radioaux) { diff --git a/flight/pios/common/pios_board_sensors.c b/flight/pios/common/pios_board_sensors.c index 4abfe1e021..4c6adee5ac 100644 --- a/flight/pios/common/pios_board_sensors.c +++ b/flight/pios/common/pios_board_sensors.c @@ -42,6 +42,10 @@ # include #endif +#ifdef PIOS_INCLUDE_BMP280 +# include +#endif + #ifdef PIOS_INCLUDE_ADXL345 # include #endif @@ -75,7 +79,13 @@ void PIOS_BOARD_Sensors_Configure() #ifdef PIOS_INCLUDE_MPU6000 const struct pios_mpu6000_cfg *mpu6000_cfg = PIOS_BOARD_HW_DEFS_GetMPU6000Cfg(pios_board_info_blob.board_rev); if (mpu6000_cfg) { +#ifdef PIOS_SPI_MPU6000_ADAPTER PIOS_MPU6000_Init(PIOS_SPI_MPU6000_ADAPTER, 0, mpu6000_cfg); +#elif defined(PIOS_I2C_MPU6000_ADAPTER) + PIOS_MPU6000_Init(PIOS_I2C_MPU6000_ADAPTER, 0, mpu6000_cfg); +#else +#error PIOS_INCLUDE_MPU6000 requires one of PIOS_SPI_MPU6000_ADAPTER or PIOS_I2C_MPU6000_ADAPTER +#endif PIOS_MPU6000_CONFIG_Configure(); #ifndef PIOS_EXCLUDE_ADVANCED_FEATURES PIOS_MPU6000_Register(); @@ -151,10 +161,14 @@ void PIOS_BOARD_Sensors_Configure() if (option == AUXMAGSETTINGS_TYPE_FLEXI) { // i2c_external +#ifdef PIOS_I2C_EXTERNAL_ADAPTER i2c_id = PIOS_I2C_EXTERNAL_ADAPTER; +#endif } else if (option == AUXMAGSETTINGS_TYPE_I2C) { // i2c_internal (or Sparky2/F3 dedicated I2C port) +#ifdef PIOS_I2C_FLEXI_ADAPTER i2c_id = PIOS_I2C_FLEXI_ADAPTER; +#endif } if (i2c_id) { @@ -184,6 +198,13 @@ void PIOS_BOARD_Sensors_Configure() } #endif +#ifdef PIOS_INCLUDE_BMP280 + const struct pios_bmp280_cfg *bmp280_cfg = PIOS_BOARD_HW_DEFS_GetBMP280Cfg(pios_board_info_blob.board_rev); + if(bmp280_cfg) { + PIOS_BMP280_Init(bmp280_cfg, PIOS_I2C_BMP280_INTERNAL_ADAPTER); + } +#endif + #ifdef PIOS_INCLUDE_ADC const struct pios_adc_cfg *adc_cfg = PIOS_BOARD_HW_DEFS_GetAdcCfg(pios_board_info_blob.board_rev); if (adc_cfg) { diff --git a/flight/pios/common/pios_mpu6000.c b/flight/pios/common/pios_mpu6000.c index 97daddd68c..0164eda40d 100644 --- a/flight/pios/common/pios_mpu6000.c +++ b/flight/pios/common/pios_mpu6000.c @@ -35,6 +35,7 @@ #include #include #include +#include /* Global Variables */ @@ -42,6 +43,9 @@ enum pios_mpu6000_dev_magic { PIOS_MPU6000_DEV_MAGIC = 0x9da9b3ed, }; +#define CALLBACK_TASK_STACKSIZE 256 + + // sensor driver interface bool PIOS_MPU6000_driver_Test(uintptr_t context); void PIOS_MPU6000_driver_Reset(uintptr_t context); @@ -58,13 +62,18 @@ const PIOS_SENSORS_Driver PIOS_MPU6000_Driver = { .is_polled = false, }; // - +struct pios_mpu6000_io_driver { + int32_t (*SetReg)(uint8_t address, uint8_t buffer); + int32_t (*GetReg)(uint8_t address); + bool (*ReadSensor)(bool *woken); +}; struct mpu6000_dev { - uint32_t spi_id; + uint32_t port_id; uint32_t slave_num; QueueHandle_t queue; const struct pios_mpu6000_cfg *cfg; + struct pios_mpu6000_io_driver *driver; enum pios_mpu6000_range gyro_range; enum pios_mpu6000_accel_range accel_range; enum pios_mpu6000_filter filter; @@ -101,6 +110,7 @@ typedef union { static struct mpu6000_dev *dev; volatile bool mpu6000_configured = false; static mpu6000_data_t mpu6000_data; +static uint32_t gyro_read_timestamp; static PIOS_SENSORS_3Axis_SensorsWithTemp *queue_data = 0; #define SENSOR_COUNT 2 #define SENSOR_DATA_SIZE (sizeof(PIOS_SENSORS_3Axis_SensorsWithTemp) + sizeof(Vector3i16) * SENSOR_COUNT) @@ -109,11 +119,27 @@ static PIOS_SENSORS_3Axis_SensorsWithTemp *queue_data = 0; static struct mpu6000_dev *PIOS_MPU6000_alloc(const struct pios_mpu6000_cfg *cfg); static int32_t PIOS_MPU6000_Validate(struct mpu6000_dev *dev); static void PIOS_MPU6000_Config(struct pios_mpu6000_cfg const *cfg); -static int32_t PIOS_MPU6000_SetReg(uint8_t address, uint8_t buffer); -static int32_t PIOS_MPU6000_GetReg(uint8_t address); +static int32_t PIOS_MPU6000_SPI_SetReg(uint8_t address, uint8_t buffer); +static int32_t PIOS_MPU6000_SPI_GetReg(uint8_t address); static void PIOS_MPU6000_SetSpeed(const bool fast); static bool PIOS_MPU6000_HandleData(uint32_t gyro_read_timestamp); -static bool PIOS_MPU6000_ReadSensor(bool *woken); +static bool PIOS_MPU6000_SPI_ReadSensor(bool *woken); +struct pios_mpu6000_io_driver spi_io_driver = { + .SetReg = PIOS_MPU6000_SPI_SetReg, + .GetReg = PIOS_MPU6000_SPI_GetReg, + .ReadSensor = PIOS_MPU6000_SPI_ReadSensor, +}; + +#ifdef PIOS_INCLUDE_I2C +static int32_t PIOS_MPU6000_I2C_SetReg(uint8_t address, uint8_t buffer); +static int32_t PIOS_MPU6000_I2C_GetReg(uint8_t address); +static bool PIOS_MPU6000_I2C_ReadSensor(bool *woken); +struct pios_mpu6000_io_driver i2c_io_driver = { + .SetReg = PIOS_MPU6000_I2C_SetReg, + .GetReg = PIOS_MPU6000_I2C_GetReg, + .ReadSensor = PIOS_MPU6000_I2C_ReadSensor, +}; +#endif /* PIOS_INCLUDE_I2C */ static int32_t PIOS_MPU6000_Test(void); @@ -133,6 +159,16 @@ static struct mpu6000_dev *PIOS_MPU6000_alloc(const struct pios_mpu6000_cfg *cfg mpu6000_dev->magic = PIOS_MPU6000_DEV_MAGIC; + if (cfg->i2c_addr == 0) { + mpu6000_dev->driver = &spi_io_driver; + } else { +#ifdef PIOS_INCLUDE_I2C + mpu6000_dev->driver = &i2c_io_driver; +#else + PIOS_Assert(0); +#endif + } + mpu6000_dev->queue = xQueueCreate(cfg->max_downsample + 1, SENSOR_DATA_SIZE); PIOS_Assert(mpu6000_dev->queue); @@ -154,7 +190,7 @@ static int32_t PIOS_MPU6000_Validate(struct mpu6000_dev *vdev) if (vdev->magic != PIOS_MPU6000_DEV_MAGIC) { return -2; } - if (vdev->spi_id == 0) { + if (vdev->port_id == 0) { return -3; } return 0; @@ -164,14 +200,14 @@ static int32_t PIOS_MPU6000_Validate(struct mpu6000_dev *vdev) * @brief Initialize the MPU6000 3-axis gyro sensor. * @return 0 for success, -1 for failure */ -int32_t PIOS_MPU6000_Init(uint32_t spi_id, uint32_t slave_num, const struct pios_mpu6000_cfg *cfg) +int32_t PIOS_MPU6000_Init(uint32_t port_id, uint32_t slave_num, const struct pios_mpu6000_cfg *cfg) { dev = PIOS_MPU6000_alloc(cfg); if (dev == NULL) { return -1; } - dev->spi_id = spi_id; + dev->port_id = port_id; dev->slave_num = slave_num; dev->cfg = cfg; @@ -194,13 +230,13 @@ static void PIOS_MPU6000_Config(struct pios_mpu6000_cfg const *cfg) PIOS_MPU6000_Test(); // Reset chip - while (PIOS_MPU6000_SetReg(PIOS_MPU6000_PWR_MGMT_REG, PIOS_MPU6000_PWRMGMT_IMU_RST) != 0) { + while (dev->driver->SetReg(PIOS_MPU6000_PWR_MGMT_REG, PIOS_MPU6000_PWRMGMT_IMU_RST) != 0) { ; } PIOS_DELAY_WaitmS(50); // Reset chip and fifo - while (PIOS_MPU6000_SetReg(PIOS_MPU6000_USER_CTRL_REG, + while (dev->driver->SetReg(PIOS_MPU6000_USER_CTRL_REG, PIOS_MPU6000_USERCTL_GYRO_RST | PIOS_MPU6000_USERCTL_SIG_COND | PIOS_MPU6000_USERCTL_FIFO_RST) != 0) { @@ -208,7 +244,7 @@ static void PIOS_MPU6000_Config(struct pios_mpu6000_cfg const *cfg) } // Wait for reset to finish - while (PIOS_MPU6000_GetReg(PIOS_MPU6000_USER_CTRL_REG) & + while (dev->driver->GetReg(PIOS_MPU6000_USER_CTRL_REG) & (PIOS_MPU6000_USERCTL_GYRO_RST | PIOS_MPU6000_USERCTL_SIG_COND | PIOS_MPU6000_USERCTL_FIFO_RST)) { @@ -216,45 +252,45 @@ static void PIOS_MPU6000_Config(struct pios_mpu6000_cfg const *cfg) } PIOS_DELAY_WaitmS(10); // Power management configuration - while (PIOS_MPU6000_SetReg(PIOS_MPU6000_PWR_MGMT_REG, cfg->Pwr_mgmt_clk) != 0) { + while (dev->driver->SetReg(PIOS_MPU6000_PWR_MGMT_REG, cfg->Pwr_mgmt_clk) != 0) { ; } // Interrupt configuration - while (PIOS_MPU6000_SetReg(PIOS_MPU6000_INT_CFG_REG, cfg->interrupt_cfg) != 0) { + while (dev->driver->SetReg(PIOS_MPU6000_INT_CFG_REG, cfg->interrupt_cfg) != 0) { ; } // Interrupt configuration - while (PIOS_MPU6000_SetReg(PIOS_MPU6000_INT_EN_REG, cfg->interrupt_en) != 0) { + while (dev->driver->SetReg(PIOS_MPU6000_INT_EN_REG, cfg->interrupt_en) != 0) { ; } // FIFO storage - while (PIOS_MPU6000_SetReg(PIOS_MPU6000_FIFO_EN_REG, cfg->Fifo_store) != 0) { + while (dev->driver->SetReg(PIOS_MPU6000_FIFO_EN_REG, cfg->Fifo_store) != 0) { ; } PIOS_MPU6000_ConfigureRanges(cfg->gyro_range, cfg->accel_range, cfg->filter); // Interrupt configuration - while (PIOS_MPU6000_SetReg(PIOS_MPU6000_USER_CTRL_REG, cfg->User_ctl) != 0) { + while (dev->driver->SetReg(PIOS_MPU6000_USER_CTRL_REG, cfg->User_ctl) != 0) { ; } // Interrupt configuration - while (PIOS_MPU6000_SetReg(PIOS_MPU6000_PWR_MGMT_REG, cfg->Pwr_mgmt_clk) != 0) { + while (dev->driver->SetReg(PIOS_MPU6000_PWR_MGMT_REG, cfg->Pwr_mgmt_clk) != 0) { ; } // Interrupt configuration - while (PIOS_MPU6000_SetReg(PIOS_MPU6000_INT_CFG_REG, cfg->interrupt_cfg) != 0) { + while (dev->driver->SetReg(PIOS_MPU6000_INT_CFG_REG, cfg->interrupt_cfg) != 0) { ; } // Interrupt configuration - while (PIOS_MPU6000_SetReg(PIOS_MPU6000_INT_EN_REG, cfg->interrupt_en) != 0) { + while (dev->driver->SetReg(PIOS_MPU6000_INT_EN_REG, cfg->interrupt_en) != 0) { ; } - if ((PIOS_MPU6000_GetReg(PIOS_MPU6000_INT_EN_REG)) != cfg->interrupt_en) { + if ((dev->driver->GetReg(PIOS_MPU6000_INT_EN_REG)) != cfg->interrupt_en) { return; } @@ -274,12 +310,12 @@ int32_t PIOS_MPU6000_ConfigureRanges( } // update filter settings - while (PIOS_MPU6000_SetReg(PIOS_MPU6000_DLPF_CFG_REG, filterSetting) != 0) { + while (dev->driver->SetReg(PIOS_MPU6000_DLPF_CFG_REG, filterSetting) != 0) { ; } // Sample rate divider, chosen upon digital filtering settings - while (PIOS_MPU6000_SetReg(PIOS_MPU6000_SMPLRT_DIV_REG, + while (dev->driver->SetReg(PIOS_MPU6000_SMPLRT_DIV_REG, filterSetting == PIOS_MPU6000_LOWPASS_256_HZ ? dev->cfg->Smpl_rate_div_no_dlp : dev->cfg->Smpl_rate_div_dlp) != 0) { ; @@ -288,13 +324,13 @@ int32_t PIOS_MPU6000_ConfigureRanges( dev->filter = filterSetting; // Gyro range - while (PIOS_MPU6000_SetReg(PIOS_MPU6000_GYRO_CFG_REG, gyroRange) != 0) { + while (dev->driver->SetReg(PIOS_MPU6000_GYRO_CFG_REG, gyroRange) != 0) { ; } dev->gyro_range = gyroRange; // Set the accel range - while (PIOS_MPU6000_SetReg(PIOS_MPU6000_ACCEL_CFG_REG, accelRange) != 0) { + while (dev->driver->SetReg(PIOS_MPU6000_ACCEL_CFG_REG, accelRange) != 0) { ; } @@ -311,11 +347,11 @@ static int32_t PIOS_MPU6000_ClaimBus(bool fast_spi) if (PIOS_MPU6000_Validate(dev) != 0) { return -1; } - if (PIOS_SPI_ClaimBus(dev->spi_id) != 0) { + if (PIOS_SPI_ClaimBus(dev->port_id) != 0) { return -2; } PIOS_MPU6000_SetSpeed(fast_spi); - PIOS_SPI_RC_PinSet(dev->spi_id, dev->slave_num, 0); + PIOS_SPI_RC_PinSet(dev->port_id, dev->slave_num, 0); return 0; } @@ -323,9 +359,9 @@ static int32_t PIOS_MPU6000_ClaimBus(bool fast_spi) static void PIOS_MPU6000_SetSpeed(const bool fast) { if (fast) { - PIOS_SPI_SetClockSpeed(dev->spi_id, dev->cfg->fast_prescaler); + PIOS_SPI_SetClockSpeed(dev->port_id, dev->cfg->fast_prescaler); } else { - PIOS_SPI_SetClockSpeed(dev->spi_id, dev->cfg->std_prescaler); + PIOS_SPI_SetClockSpeed(dev->port_id, dev->cfg->std_prescaler); } } @@ -340,11 +376,11 @@ static int32_t PIOS_MPU6000_ClaimBusISR(bool *woken, bool fast_spi) if (PIOS_MPU6000_Validate(dev) != 0) { return -1; } - if (PIOS_SPI_ClaimBusISR(dev->spi_id, woken) != 0) { + if (PIOS_SPI_ClaimBusISR(dev->port_id, woken) != 0) { return -2; } PIOS_MPU6000_SetSpeed(fast_spi); - PIOS_SPI_RC_PinSet(dev->spi_id, dev->slave_num, 0); + PIOS_SPI_RC_PinSet(dev->port_id, dev->slave_num, 0); return 0; } @@ -357,8 +393,8 @@ static int32_t PIOS_MPU6000_ReleaseBus() if (PIOS_MPU6000_Validate(dev) != 0) { return -1; } - PIOS_SPI_RC_PinSet(dev->spi_id, dev->slave_num, 1); - return PIOS_SPI_ReleaseBus(dev->spi_id); + PIOS_SPI_RC_PinSet(dev->port_id, dev->slave_num, 1); + return PIOS_SPI_ReleaseBus(dev->port_id); } /** @@ -372,8 +408,8 @@ static int32_t PIOS_MPU6000_ReleaseBusISR(bool *woken) if (PIOS_MPU6000_Validate(dev) != 0) { return -1; } - PIOS_SPI_RC_PinSet(dev->spi_id, dev->slave_num, 1); - return PIOS_SPI_ReleaseBusISR(dev->spi_id, woken); + PIOS_SPI_RC_PinSet(dev->port_id, dev->slave_num, 1); + return PIOS_SPI_ReleaseBusISR(dev->port_id, woken); } /** @@ -381,7 +417,7 @@ static int32_t PIOS_MPU6000_ReleaseBusISR(bool *woken) * @returns The register value or -1 if failure to get bus * @param reg[in] Register address to be read */ -static int32_t PIOS_MPU6000_GetReg(uint8_t reg) +static int32_t PIOS_MPU6000_SPI_GetReg(uint8_t reg) { uint8_t data; @@ -389,8 +425,8 @@ static int32_t PIOS_MPU6000_GetReg(uint8_t reg) return -1; } - PIOS_SPI_TransferByte(dev->spi_id, (0x80 | reg)); // request byte - data = PIOS_SPI_TransferByte(dev->spi_id, 0); // receive response + PIOS_SPI_TransferByte(dev->port_id, (0x80 | reg)); // request byte + data = PIOS_SPI_TransferByte(dev->port_id, 0); // receive response PIOS_MPU6000_ReleaseBus(); return data; @@ -404,18 +440,18 @@ static int32_t PIOS_MPU6000_GetReg(uint8_t reg) * \return -1 if unable to claim SPI bus * \return -2 if unable to claim i2c device */ -static int32_t PIOS_MPU6000_SetReg(uint8_t reg, uint8_t data) +static int32_t PIOS_MPU6000_SPI_SetReg(uint8_t reg, uint8_t data) { if (PIOS_MPU6000_ClaimBus(false) != 0) { return -1; } - if (PIOS_SPI_TransferByte(dev->spi_id, 0x7f & reg) != 0) { + if (PIOS_SPI_TransferByte(dev->port_id, 0x7f & reg) != 0) { PIOS_MPU6000_ReleaseBus(); return -2; } - if (PIOS_SPI_TransferByte(dev->spi_id, data) != 0) { + if (PIOS_SPI_TransferByte(dev->port_id, data) != 0) { PIOS_MPU6000_ReleaseBus(); return -3; } @@ -439,7 +475,7 @@ int32_t PIOS_MPU6000_DummyReadGyros() return -1; } - if (PIOS_SPI_TransferBlock(dev->spi_id, &buf[0], &rec[0], sizeof(buf), NULL) < 0) { + if (PIOS_SPI_TransferBlock(dev->port_id, &buf[0], &rec[0], sizeof(buf), NULL) < 0) { return -2; } @@ -448,13 +484,111 @@ int32_t PIOS_MPU6000_DummyReadGyros() return 0; } +#ifdef PIOS_INCLUDE_I2C +static int32_t PIOS_MPU6000_I2C_SetReg(uint8_t address, uint8_t buffer) +{ + uint8_t data[] = { + address, + buffer, + }; + + const struct pios_i2c_txn txn_list[] = { + { + .info = __func__, + .addr = dev->cfg->i2c_addr, + .rw = PIOS_I2C_TXN_WRITE, + .len = sizeof(data), + .buf = data, + } + , + }; + + return PIOS_I2C_Transfer(dev->port_id, txn_list, NELEMENTS(txn_list)); +} + +static int32_t PIOS_MPU6000_I2C_Read(uint8_t address, uint8_t *buffer, uint8_t len) +{ + uint8_t addr_buffer[] = { + address, + }; + + const struct pios_i2c_txn txn_list[] = { + { + .info = __func__, + .addr = dev->cfg->i2c_addr, + .rw = PIOS_I2C_TXN_WRITE, + .len = sizeof(addr_buffer), + .buf = addr_buffer, + } + , + { + .info = __func__, + .addr = dev->cfg->i2c_addr, + .rw = PIOS_I2C_TXN_READ, + .len = len, + .buf = buffer, + } + }; + + return PIOS_I2C_Transfer(dev->port_id, txn_list, NELEMENTS(txn_list)); +} + +static int32_t PIOS_MPU6000_I2C_GetReg(uint8_t address) +{ + uint8_t data; + + if (PIOS_MPU6000_I2C_Read(address, &data, sizeof(data)) < 0) { + return -1; + } + + return data; +} + +static bool PIOS_MPU6000_I2C_Read_Completed() +{ + return PIOS_MPU6000_HandleData(gyro_read_timestamp); +} + +static bool PIOS_MPU6000_I2C_ReadSensor(bool *woken) +{ + static uint8_t addr_buffer[] = { + PIOS_MPU6000_SENSOR_FIRST_REG, + }; + + static struct pios_i2c_txn txn_list[] = { + { + .info = __func__, +// .addr = dev->cfg->i2c_addr, + .rw = PIOS_I2C_TXN_WRITE, + .len = sizeof(addr_buffer), + .buf = addr_buffer, + } + , + { + .info = __func__, +// .addr = dev->cfg->i2c_addr, + .rw = PIOS_I2C_TXN_READ, + .len = sizeof(mpu6000_data_t) - 1, + .buf = &mpu6000_data.buffer[1], + } + }; + + txn_list[0].addr = dev->cfg->i2c_addr; + txn_list[1].addr = dev->cfg->i2c_addr; + + PIOS_I2C_Transfer_CallbackFromISR(dev->port_id, txn_list, NELEMENTS(txn_list), PIOS_MPU6000_I2C_Read_Completed, woken); + + return false; /* we did not read anything now */ +} +#endif /* PIOS_INCLUDE_I2C */ + /* * @brief Read the identification bytes from the MPU6000 sensor * \return ID read from MPU6000 or -1 if failure */ int32_t PIOS_MPU6000_ReadID() { - int32_t mpu6000_id = PIOS_MPU6000_GetReg(PIOS_MPU6000_WHOAMI); + int32_t mpu6000_id = dev->driver->GetReg(PIOS_MPU6000_WHOAMI); if (mpu6000_id < 0) { return -1; @@ -541,21 +675,21 @@ static int32_t PIOS_MPU6000_Test(void) bool PIOS_MPU6000_IRQHandler(void) { - uint32_t gyro_read_timestamp = PIOS_DELAY_GetRaw(); + gyro_read_timestamp = PIOS_DELAY_GetRaw(); bool woken = false; if (!mpu6000_configured) { return false; } - if (PIOS_MPU6000_ReadSensor(&woken)) { + if (dev->driver->ReadSensor(&woken)) { woken |= PIOS_MPU6000_HandleData(gyro_read_timestamp); } return woken; } -static bool PIOS_MPU6000_HandleData(uint32_t gyro_read_timestamp) +static bool PIOS_MPU6000_HandleData(uint32_t gyro_read_timestamp_p) { if (!queue_data) { return false; @@ -598,21 +732,22 @@ static bool PIOS_MPU6000_HandleData(uint32_t gyro_read_timestamp) const int16_t temp = GET_SENSOR_DATA(mpu6000_data, Temperature); // Temperature in degrees C = (TEMP_OUT Register Value as a signed quantity)/340 + 36.53 queue_data->temperature = 3653 + (temp * 100) / 340; - queue_data->timestamp = gyro_read_timestamp; + queue_data->timestamp = gyro_read_timestamp_p; + BaseType_t higherPriorityTaskWoken; xQueueSendToBackFromISR(dev->queue, (void *)queue_data, &higherPriorityTaskWoken); return higherPriorityTaskWoken == pdTRUE; } -static bool PIOS_MPU6000_ReadSensor(bool *woken) +static bool PIOS_MPU6000_SPI_ReadSensor(bool *woken) { const uint8_t mpu6000_send_buf[1 + PIOS_MPU6000_SAMPLES_BYTES] = { PIOS_MPU6000_SENSOR_FIRST_REG | 0x80 }; if (PIOS_MPU6000_ClaimBusISR(woken, true) != 0) { return false; } - if (PIOS_SPI_TransferBlock(dev->spi_id, &mpu6000_send_buf[0], &mpu6000_data.buffer[0], sizeof(mpu6000_data_t), NULL) < 0) { + if (PIOS_SPI_TransferBlock(dev->port_id, &mpu6000_send_buf[0], &mpu6000_data.buffer[0], sizeof(mpu6000_data_t), NULL) < 0) { PIOS_MPU6000_ReleaseBusISR(woken); return false; } @@ -628,7 +763,7 @@ bool PIOS_MPU6000_driver_Test(__attribute__((unused)) uintptr_t context) void PIOS_MPU6000_driver_Reset(__attribute__((unused)) uintptr_t context) { - PIOS_MPU6000_DummyReadGyros(); +// PIOS_MPU6000_DummyReadGyros(); } void PIOS_MPU6000_driver_get_scale(float *scales, uint8_t size, __attribute__((unused)) uintptr_t contet) diff --git a/flight/pios/common/pios_mpu9250.c b/flight/pios/common/pios_mpu9250.c index 887f0e0856..b9da3f30d0 100644 --- a/flight/pios/common/pios_mpu9250.c +++ b/flight/pios/common/pios_mpu9250.c @@ -129,6 +129,7 @@ static volatile bool mag_ready = false; static struct mpu9250_dev *dev; volatile bool mpu9250_configured = false; static mpu9250_data_t mpu9250_data; +static int32_t mpu9250_id; // ! Private functions static struct mpu9250_dev *PIOS_MPU9250_alloc(const struct pios_mpu9250_cfg *cfg); @@ -186,7 +187,9 @@ void PIOS_MPU9250_MainRegister() void PIOS_MPU9250_MagRegister() { - PIOS_SENSORS_Register(&PIOS_MPU9250_Mag_Driver, PIOS_SENSORS_TYPE_3AXIS_MAG, 0); + if (mpu9250_id == PIOS_MPU9250_GYRO_ACC_ID) { + PIOS_SENSORS_Register(&PIOS_MPU9250_Mag_Driver, PIOS_SENSORS_TYPE_3AXIS_MAG, 0); + } } /** * @brief Allocate a new device @@ -320,7 +323,9 @@ static void PIOS_MPU9250_Config(struct pios_mpu9250_cfg const *cfg) } #ifdef PIOS_MPU9250_MAG - PIOS_MPU9250_Mag_Init(); + if (mpu9250_id == PIOS_MPU9250_GYRO_ACC_ID) { + PIOS_MPU9250_Mag_Init(); + } #endif // Interrupt enable @@ -514,12 +519,12 @@ static int32_t PIOS_MPU9250_SetReg(uint8_t reg, uint8_t data) */ int32_t PIOS_MPU9250_ReadID() { - int32_t mpu9250_id = PIOS_MPU9250_GetReg(PIOS_MPU9250_WHOAMI); + int32_t id = PIOS_MPU9250_GetReg(PIOS_MPU9250_WHOAMI); - if (mpu9250_id < 0) { + if (id < 0) { return -1; } - return mpu9250_id; + return id; } static float PIOS_MPU9250_GetScale() @@ -566,13 +571,13 @@ static float PIOS_MPU9250_GetAccelScale() static int32_t PIOS_MPU9250_Test(void) { /* Verify that ID matches */ - int32_t mpu9250_id = PIOS_MPU9250_ReadID(); + mpu9250_id = PIOS_MPU9250_ReadID(); if (mpu9250_id < 0) { return -1; } - if (mpu9250_id != PIOS_MPU9250_GYRO_ACC_ID) { + if ((mpu9250_id != PIOS_MPU9250_GYRO_ACC_ID) && (mpu9250_id != PIOS_MPU6500_GYRO_ACC_ID)) { return -2; } diff --git a/flight/pios/common/pios_sbus.c b/flight/pios/common/pios_sbus.c index e424aa8f6e..44c3235f7a 100644 --- a/flight/pios/common/pios_sbus.c +++ b/flight/pios/common/pios_sbus.c @@ -81,9 +81,8 @@ struct pios_sbus_state { #define SBUS_FL_WEIGHTED_AVE 26 struct pios_sbus_dev { - enum pios_sbus_dev_magic magic; - const struct pios_sbus_cfg *cfg; - struct pios_sbus_state state; + enum pios_sbus_dev_magic magic; + struct pios_sbus_state state; }; /* Allocate S.Bus device descriptor */ @@ -153,7 +152,6 @@ int32_t PIOS_SBus_Init(uint32_t *sbus_id, uint32_t lower_id) { PIOS_DEBUG_Assert(sbus_id); - PIOS_DEBUG_Assert(cfg); PIOS_DEBUG_Assert(driver); struct pios_sbus_dev *sbus_dev; @@ -163,9 +161,6 @@ int32_t PIOS_SBus_Init(uint32_t *sbus_id, goto out_fail; } - /* Bind the configuration to the device instance */ - sbus_dev->cfg = cfg; - PIOS_SBus_ResetState(&(sbus_dev->state)); *sbus_id = (uint32_t)sbus_dev; diff --git a/flight/pios/common/pios_servo.c b/flight/pios/common/pios_servo.c index d0ca5f6b91..bcd5130326 100644 --- a/flight/pios/common/pios_servo.c +++ b/flight/pios/common/pios_servo.c @@ -100,7 +100,7 @@ extern void PIOS_Servo_Disable() GPIO_InitTypeDef init = chan->pin.init; -#if defined(STM32F40_41xxx) || defined(STM32F446xx) || defined(STM32F411xE) +#if defined(STM32F40_41xxx) || defined(STM32F446xx) || defined(STM32F411xE) || defined(STM32F3) init.GPIO_Mode = GPIO_Mode_OUT; #elif defined(STM32F10X_MD) init.GPIO_Mode = GPIO_Mode_Out_PP; @@ -147,7 +147,7 @@ static void PIOS_Servo_SetupBank(uint8_t bank_nr) switch (bank->mode) { case PIOS_SERVO_BANK_MODE_PWM: case PIOS_SERVO_BANK_MODE_SINGLE_PULSE: -#if defined(STM32F40_41xxx) || defined(STM32F446xx) || defined(STM32F411xE) +#if defined(STM32F40_41xxx) || defined(STM32F446xx) || defined(STM32F411xE) || defined(STM32F3) GPIO_PinAFConfig(chan->pin.gpio, chan->pin.pin_source, chan->remap); #elif defined(STM32F10X_MD) init.GPIO_Mode = GPIO_Mode_AF_PP; @@ -162,28 +162,27 @@ static void PIOS_Servo_SetupBank(uint8_t bank_nr) /* Set up for output compare function */ switch (chan->timer_chan) { case TIM_Channel_1: - TIM_OC1Init(chan->timer, &servo_cfg->tim_oc_init); + TIM_OC1Init(chan->timer, (TIM_OCInitTypeDef *)&servo_cfg->tim_oc_init); TIM_OC1PreloadConfig(chan->timer, TIM_OCPreload_Enable); break; case TIM_Channel_2: - TIM_OC2Init(chan->timer, &servo_cfg->tim_oc_init); + TIM_OC2Init(chan->timer, (TIM_OCInitTypeDef *)&servo_cfg->tim_oc_init); TIM_OC2PreloadConfig(chan->timer, TIM_OCPreload_Enable); break; case TIM_Channel_3: - TIM_OC3Init(chan->timer, &servo_cfg->tim_oc_init); + TIM_OC3Init(chan->timer, (TIM_OCInitTypeDef *)&servo_cfg->tim_oc_init); TIM_OC3PreloadConfig(chan->timer, TIM_OCPreload_Enable); break; case TIM_Channel_4: - TIM_OC4Init(chan->timer, &servo_cfg->tim_oc_init); + TIM_OC4Init(chan->timer, (TIM_OCInitTypeDef *)&servo_cfg->tim_oc_init); TIM_OC4PreloadConfig(chan->timer, TIM_OCPreload_Enable); break; } - break; case PIOS_SERVO_BANK_MODE_DSHOT: { -#if defined(STM32F40_41xxx) || defined(STM32F446xx) || defined(STM32F411xE) +#if defined(STM32F40_41xxx) || defined(STM32F446xx) || defined(STM32F411xE) || defined(STM32F3) init.GPIO_Mode = GPIO_Mode_OUT; #elif defined(STM32F10X_MD) init.GPIO_Mode = GPIO_Mode_Out_PP; @@ -504,8 +503,8 @@ void PIOS_Servo_SetHz(const uint16_t *speeds, const uint32_t *clock, uint8_t ban // Choose the correct prescaler value for the APB the timer is attached -#if defined(STM32F10X_MD) - // F1 has both timer clock domains running at master clock speed +#if defined(STM32F10X_MD) || defined(STM32F3) + // F1 & F3 have both timer clock domains running at master clock speed timer_clock = PIOS_MASTER_CLOCK; #elif defined(STM32F40_41xxx) || defined(STM32F446xx) || defined(STM32F411xE) if (timer == TIM1 || timer == TIM8 || timer == TIM9 || timer == TIM10 || timer == TIM11) { diff --git a/flight/pios/inc/pios_board_hw.h b/flight/pios/inc/pios_board_hw.h index 53d3054f87..19015f6ed2 100644 --- a/flight/pios/inc/pios_board_hw.h +++ b/flight/pios/inc/pios_board_hw.h @@ -68,4 +68,7 @@ const struct pios_l3gd20_cfg *PIOS_BOARD_HW_DEFS_GetL3GD20Cfg(uint32_t board_rev #ifdef PIOS_INCLUDE_BMA180 const struct pios_bma180_cfg *PIOS_BOARD_HW_DEFS_GetBMA180Cfg(uint32_t board_revision); #endif +#ifdef PIOS_INCLUDE_BMP280 +const struct pios_bmp280_cfg *PIOS_BOARD_HW_DEFS_GetBMP280Cfg(uint32_t board_revision); +#endif #endif /* PIOS_BOARD_HW_H */ diff --git a/flight/pios/inc/pios_com.h b/flight/pios/inc/pios_com.h index 4b827ad8de..3e33775da0 100644 --- a/flight/pios/inc/pios_com.h +++ b/flight/pios/inc/pios_com.h @@ -62,13 +62,6 @@ enum PIOS_COM_Parity { PIOS_COM_Parity_Odd, }; -enum PIOS_COM_Mode { - PIOS_COM_Mode_Unchanged = 0, - PIOS_COM_Mode_Rx = (1 << 0), - PIOS_COM_Mode_Tx = (1 << 1), - PIOS_COM_Mode_RxTx = (PIOS_COM_Mode_Rx | PIOS_COM_Mode_Tx), -}; - struct pios_com_driver { void (*set_baud)(uint32_t id, uint32_t baud); void (*set_config)(uint32_t usart_id, enum PIOS_COM_Word_Length word_len, enum PIOS_COM_Parity parity, enum PIOS_COM_StopBits stop_bits, uint32_t baud_rate); diff --git a/flight/pios/inc/pios_flash_jedec_catalog.h b/flight/pios/inc/pios_flash_jedec_catalog.h index eae55063d9..bc932a2098 100644 --- a/flight/pios/inc/pios_flash_jedec_catalog.h +++ b/flight/pios/inc/pios_flash_jedec_catalog.h @@ -72,6 +72,15 @@ const struct pios_flash_jedec_cfg pios_flash_jedec_catalog[] = .fast_read = 0x0B, .fast_read_dummy_bytes = 1, }, + { // 25q64 + .expect_manufacturer = JEDEC_MANUFACTURER_WINBOND, + .expect_memorytype = 0x40, + .expect_capacity = 0x17, + .sector_erase = 0x20, + .chip_erase = 0x60, + .fast_read = 0x0B, + .fast_read_dummy_bytes = 1, + }, { // 25q512 .expect_manufacturer = JEDEC_MANUFACTURER_MICRON, .expect_memorytype = 0xBA, diff --git a/flight/pios/inc/pios_i2c.h b/flight/pios/inc/pios_i2c.h index 0c4c714318..546a51e2fb 100644 --- a/flight/pios/inc/pios_i2c.h +++ b/flight/pios/inc/pios_i2c.h @@ -73,9 +73,13 @@ enum pios_i2c_error_count { PIOS_I2C_ERROR_COUNT_NUMELEM, }; +typedef bool (*pios_i2c_callback)(); + /* Public Functions */ extern int32_t PIOS_I2C_Transfer(uint32_t i2c_id, const struct pios_i2c_txn txn_list[], uint32_t num_txns); -extern int32_t PIOS_I2C_Transfer_Callback(uint32_t i2c_id, const struct pios_i2c_txn txn_list[], uint32_t num_txns, void *callback); +extern int32_t PIOS_I2C_Transfer_Callback(uint32_t i2c_id, const struct pios_i2c_txn txn_list[], uint32_t num_txns, pios_i2c_callback callback); +extern int32_t PIOS_I2C_Transfer_CallbackFromISR(uint32_t i2c_id, const struct pios_i2c_txn txn_list[], uint32_t num_txns, pios_i2c_callback callback, bool *woken); + extern void PIOS_I2C_EV_IRQ_Handler(uint32_t i2c_id); extern void PIOS_I2C_ER_IRQ_Handler(uint32_t i2c_id); extern void PIOS_I2C_IRQ_Handler(uint32_t i2c_id); diff --git a/flight/pios/inc/pios_i2c_priv.h b/flight/pios/inc/pios_i2c_priv.h index 8086f50743..20fec3e5dc 100644 --- a/flight/pios/inc/pios_i2c_priv.h +++ b/flight/pios/inc/pios_i2c_priv.h @@ -69,7 +69,7 @@ struct pios_i2c_adapter { const struct pios_i2c_txn *active_txn; const struct pios_i2c_txn *last_txn; - void (*callback)(); + pios_i2c_callback callback; uint8_t *active_byte; uint8_t *last_byte; diff --git a/flight/pios/inc/pios_mpu6000.h b/flight/pios/inc/pios_mpu6000.h index fc95380521..7b1262ea30 100644 --- a/flight/pios/inc/pios_mpu6000.h +++ b/flight/pios/inc/pios_mpu6000.h @@ -134,6 +134,7 @@ enum pios_mpu6000_orientation { // clockwise rotation from board forward struct pios_mpu6000_cfg { const struct pios_exti_cfg *exti_cfg; /* Pointer to the EXTI configuration */ + uint8_t i2c_addr; uint8_t Fifo_store; /* FIFO storage of different readings (See datasheet page 31 for more details) */ @@ -154,7 +155,7 @@ struct pios_mpu6000_cfg { }; /* Public Functions */ -extern int32_t PIOS_MPU6000_Init(uint32_t spi_id, uint32_t slave_num, const struct pios_mpu6000_cfg *new_cfg); +extern int32_t PIOS_MPU6000_Init(uint32_t port_id, uint32_t slave_num, const struct pios_mpu6000_cfg *new_cfg); extern int32_t PIOS_MPU6000_ConfigureRanges(enum pios_mpu6000_range gyroRange, enum pios_mpu6000_accel_range accelRange, enum pios_mpu6000_filter filterSetting); extern int32_t PIOS_MPU6000_ReadID(); extern void PIOS_MPU6000_Register(); diff --git a/flight/pios/inc/pios_mpu9250.h b/flight/pios/inc/pios_mpu9250.h index 8215bc91ba..b05badba4d 100644 --- a/flight/pios/inc/pios_mpu9250.h +++ b/flight/pios/inc/pios_mpu9250.h @@ -153,6 +153,7 @@ #define PIOS_MPU9250_ASAZ 0X12 /* IDs */ +#define PIOS_MPU6500_GYRO_ACC_ID 0x70 #define PIOS_MPU9250_GYRO_ACC_ID 0x71 #define PIOS_MPU9250_MAG_ID 0x48 diff --git a/flight/pios/inc/pios_sbus_priv.h b/flight/pios/inc/pios_sbus_priv.h index e99a4adca5..f260e6b31d 100644 --- a/flight/pios/inc/pios_sbus_priv.h +++ b/flight/pios/inc/pios_sbus_priv.h @@ -85,11 +85,6 @@ */ struct pios_sbus_cfg { bool non_inverted; -// struct stm32_gpio inv; -// void (*gpio_clk_func)(uint32_t periph, FunctionalState state); -// uint32_t gpio_clk_periph; -// BitAction gpio_inv_enable; -// BitAction gpio_inv_disable; }; extern const struct pios_rcvr_driver pios_sbus_rcvr_driver; diff --git a/flight/pios/stm32f10x/inc/pios_usb_hid_istr.h b/flight/pios/inc/pios_usb_hid_istr.h similarity index 100% rename from flight/pios/stm32f10x/inc/pios_usb_hid_istr.h rename to flight/pios/inc/pios_usb_hid_istr.h diff --git a/flight/pios/stm32f10x/inc/pios_usb_hid_pwr.h b/flight/pios/inc/pios_usb_hid_pwr.h similarity index 100% rename from flight/pios/stm32f10x/inc/pios_usb_hid_pwr.h rename to flight/pios/inc/pios_usb_hid_pwr.h diff --git a/flight/pios/pios.h b/flight/pios/pios.h index 1baab4ac05..8d37b08528 100644 --- a/flight/pios/pios.h +++ b/flight/pios/pios.h @@ -64,6 +64,8 @@ extern "C" { #include #elif defined(STM32F0) #include +#elif defined(STM32F3) +#include #else #error "No Architecture defined" #endif diff --git a/flight/pios/stm32f0x/pios_usart.c b/flight/pios/stm32f0x/pios_usart.c index 7666bc8df6..91bbd284d2 100644 --- a/flight/pios/stm32f0x/pios_usart.c +++ b/flight/pios/stm32f0x/pios_usart.c @@ -289,8 +289,6 @@ static void PIOS_USART_ChangeBaud(uint32_t usart_id, uint32_t baud) * \param[in] word_len Requested word length * \param[in] stop_bits Requested stop bits * \param[in] parity Requested parity - * \param[in] baud_rate Requested baud rate - * \param[in] mode Requested mode * */ static void PIOS_USART_ChangeConfig(uint32_t usart_id, diff --git a/flight/pios/stm32f10x/library.mk b/flight/pios/stm32f10x/library.mk index 592b95801a..318681ffad 100644 --- a/flight/pios/stm32f10x/library.mk +++ b/flight/pios/stm32f10x/library.mk @@ -9,7 +9,7 @@ PIOS_DEVLIB := $(dir $(lastword $(MAKEFILE_LIST))) LINKER_SCRIPTS_PATH = $(PIOS_DEVLIB) # Compiler options implied by the F10x -CDEFS += -DSTM32F10X -DSTM32F10X_$(MODEL) +CDEFS += -DSTM32F10X -DSTM32F10X_$(MODEL) -DSTM32F1 CDEFS += -DUSE_STDPERIPH_DRIVER CDEFS += -DARM_MATH_CM3 CDEFS += -DHSE_VALUE=$(OSCILLATOR_FREQ) diff --git a/flight/pios/stm32f10x/pios_usbhook.c b/flight/pios/stm32f10x/pios_usbhook.c index 55e0e40e58..210256f73f 100644 --- a/flight/pios/stm32f10x/pios_usbhook.c +++ b/flight/pios/stm32f10x/pios_usbhook.c @@ -86,6 +86,9 @@ void PIOS_USB_HID_RegisterHidReport(const uint8_t *desc, uint16_t desc_size) Hid_Report_Descriptor.Descriptor_Size = desc_size; } +void PIOS_USBHOOK_Deactivate(void) +{} + #include "stm32f10x.h" /* __IO */ __IO uint8_t EXTI_Enable; diff --git a/flight/pios/stm32f30x/inc/pios_architecture.h b/flight/pios/stm32f30x/inc/pios_architecture.h new file mode 100644 index 0000000000..dddc4df639 --- /dev/null +++ b/flight/pios/stm32f30x/inc/pios_architecture.h @@ -0,0 +1,39 @@ +/** + ****************************************************************************** + * + * @file pios_architecture.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2013. + * @brief Architecture specific macros and 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_ARCHITECTURE_H +#define PIOS_ARCHITECTURE_H + +// defines for adc +#define PIOS_ADC_VOLTAGE_SCALE 3.30f / 4096.0f + +// defines for Temp measurements +#define PIOS_ADC_STM32_TEMP_V25 0.76f /* V */ +#define PIOS_ADC_STM32_TEMP_AVG_SLOPE 2.5f /* mV/C */ +#define PIOS_CONVERT_VOLT_TO_CPU_TEMP(x) ((x - PIOS_ADC_STM32_TEMP_V25) * 1000.0f / PIOS_ADC_STM32_TEMP_AVG_SLOPE + 25.0f) + + +#endif /* PIOS_ARCHITECTURE_H */ diff --git a/flight/pios/stm32f30x/inc/pios_delay_raw.h b/flight/pios/stm32f30x/inc/pios_delay_raw.h new file mode 100644 index 0000000000..6a49415633 --- /dev/null +++ b/flight/pios/stm32f30x/inc/pios_delay_raw.h @@ -0,0 +1,43 @@ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_DELAY Delay Functions + * @brief PiOS Delay functionality + * @{ + * + * @file pios_delay_raw.h + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016-2017. + * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief Settings functions 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 PIOS_DELAY_RAW_H +#define PIOS_DELAY_RAW_H + +/* these should be defined by CMSIS, but they aren't */ +#define DWT_CTRL (*(volatile uint32_t *)0xe0001000) +#define CYCCNTENA (1 << 0) +#define DWT_CYCCNT (*(volatile uint32_t *)0xe0001004) + +#define PIOS_DELAY_GetRaw() (DWT_CYCCNT) + +extern uint32_t PIOS_DELAY_GetRawHz(); + +#endif /* PIOS_DELAY_RAW_H */ diff --git a/flight/pios/stm32f30x/inc/pios_servo_config.h b/flight/pios/stm32f30x/inc/pios_servo_config.h new file mode 100644 index 0000000000..0167bd0c9d --- /dev/null +++ b/flight/pios/stm32f30x/inc/pios_servo_config.h @@ -0,0 +1,52 @@ +/** + ****************************************************************************** + * + * @file pios_servp_config.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2013. + * @brief Architecture specific macros and 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_SERVO_CONFIG_H_ +#define PIOS_SERVO_CONFIG_H_ + + +/** + * Generic servo pin configuration structure for an STM32F4xx + */ +#define TIM_SERVO_CHANNEL_CONFIG(_timer, _channel, _gpio, _pin) \ + { \ + .timer = _timer, \ + .timer_chan = TIM_Channel_##_channel, \ + .pin = { \ + .gpio = GPIO##_gpio, \ + .init = { \ + .GPIO_Pin = GPIO_Pin_##_pin, \ + .GPIO_Speed = GPIO_Speed_2MHz, \ + .GPIO_Mode = GPIO_Mode_AF, \ + .GPIO_OType = GPIO_OType_PP, \ + .GPIO_PuPd = GPIO_PuPd_UP \ + }, \ + .pin_source = GPIO_PinSource##_pin, \ + }, \ + .remap = GPIO_AF_P##_gpio##_pin##_##_timer, \ + } + + +#endif /* PIOS_SERVO_CONFIG_H_ */ diff --git a/flight/pios/stm32f30x/inc/pios_usart_config.h b/flight/pios/stm32f30x/inc/pios_usart_config.h new file mode 100644 index 0000000000..1ca0ce8d23 --- /dev/null +++ b/flight/pios/stm32f30x/inc/pios_usart_config.h @@ -0,0 +1,39 @@ +/* + * pios_usart_config.h + */ + +#ifndef PIOS_USART_CONFIG_H_ +#define PIOS_USART_CONFIG_H_ + +/** + * Generic USART configuration structure for an STM32F30x port. + */ +#define USART_CONFIG(_usart, _rx_gpio, _rx_pin, _tx_gpio, _tx_pin) \ + { \ + .regs = _usart, \ + .remap = GPIO_AF_##_usart, \ + .rx = { \ + .gpio = GPIO##_rx_gpio, \ + .init = { \ + .GPIO_Pin = GPIO_Pin_##_rx_pin, \ + .GPIO_Mode = GPIO_Mode_AF, \ + .GPIO_Speed = GPIO_Speed_50MHz, \ + .GPIO_OType = GPIO_OType_PP, \ + .GPIO_PuPd = GPIO_PuPd_UP, \ + }, \ + .pin_source = GPIO_PinSource##_rx_pin, \ + }, \ + .tx = { \ + .gpio = GPIO##_tx_gpio, \ + .init = { \ + .GPIO_Pin = GPIO_Pin_##_tx_pin, \ + .GPIO_Mode = GPIO_Mode_AF, \ + .GPIO_Speed = GPIO_Speed_50MHz, \ + .GPIO_OType = GPIO_OType_PP, \ + .GPIO_PuPd = GPIO_PuPd_UP, \ + }, \ + .pin_source = GPIO_PinSource##_tx_pin, \ + }, \ + } + +#endif /* PIOS_USART_CONFIG_H_ */ diff --git a/flight/pios/stm32f30x/inc/stm32f30x_conf.h b/flight/pios/stm32f30x/inc/stm32f30x_conf.h new file mode 100644 index 0000000000..781f7fa3fd --- /dev/null +++ b/flight/pios/stm32f30x/inc/stm32f30x_conf.h @@ -0,0 +1,82 @@ +/** + ****************************************************************************** + * @file stm32f30x_conf.h + * @author MCD Application Team + * @version V1.0.0 + * @date 04-September-2012 + * @brief Library configuration file. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2012 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F30X_CONF_H +#define __STM32F30X_CONF_H + +/* Includes ------------------------------------------------------------------*/ +/* Comment the line below to disable peripheral header file inclusion */ +#include "stm32f30x_adc.h" +#include "stm32f30x_can.h" +#include "stm32f30x_crc.h" +#include "stm32f30x_comp.h" +#include "stm32f30x_dac.h" +#include "stm32f30x_dbgmcu.h" +#include "stm32f30x_dma.h" +#include "stm32f30x_exti.h" +#include "stm32f30x_flash.h" +#include "stm32f30x_gpio.h" +#include "stm32f30x_syscfg.h" +#include "stm32f30x_i2c.h" +#include "stm32f30x_iwdg.h" +#include "stm32f30x_opamp.h" +#include "stm32f30x_pwr.h" +#include "stm32f30x_rcc.h" +#include "stm32f30x_rtc.h" +#include "stm32f30x_spi.h" +#include "stm32f30x_tim.h" +#include "stm32f30x_usart.h" +#include "stm32f30x_wwdg.h" +#include "stm32f30x_misc.h" /* High level functions for NVIC and SysTick (add-on to CMSIS functions) */ + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ +/* Uncomment the line below to expanse the "assert_param" macro in the + Standard Peripheral Library drivers code */ +/* #define USE_FULL_ASSERT 1 */ + +/* Exported macro ------------------------------------------------------------*/ +#ifdef USE_FULL_ASSERT + +/** + * @brief The assert_param macro is used for function's parameters check. + * @param expr: If expr is false, it calls assert_failed function which reports + * the name of the source file and the source line number of the call + * that failed. If expr is true, it returns no value. + * @retval None + */ + #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__)) +/* Exported functions ------------------------------------------------------- */ +void assert_failed(uint8_t *file, uint32_t line); +#else + #define assert_param(expr) ((void)0) +#endif /* USE_FULL_ASSERT */ + +#endif /* __STM32F30X_CONF_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/inc/usb_conf.h b/flight/pios/stm32f30x/inc/usb_conf.h new file mode 100644 index 0000000000..97ea79b836 --- /dev/null +++ b/flight/pios/stm32f30x/inc/usb_conf.h @@ -0,0 +1,197 @@ +/******************** (C) COPYRIGHT 2010 STMicroelectronics ******************** +* File Name : usb_conf.h +* Author : MCD Application Team +* Version : V3.2.1 +* Date : 07/05/2010 +* Description : Custom HID demo configuration file +******************************************************************************** +* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS +* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. +* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, +* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE +* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING +* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. +*******************************************************************************/ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __USB_CONF_H +#define __USB_CONF_H + +/* Includes ------------------------------------------------------------------*/ +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions ------------------------------------------------------- */ +/* External variables --------------------------------------------------------*/ + +#ifndef STM32F10X_CL +/*-------------------------------------------------------------*/ +/* -------------- Buffer Description Table -----------------*/ +/*-------------------------------------------------------------*/ +/* buffer table base address */ +/* buffer table base address */ +#define BTABLE_ADDRESS (0x00) + +/* EP0 */ +/* rx/tx buffer base address */ +#define ENDP0_RXADDR (0x20) +#define ENDP0_TXADDR (0x40) + +/* EP1 */ +/* rx/tx buffer base address */ +#define ENDP1_TXADDR (0x60) +#define ENDP1_RXADDR (0x80) + +/* EP2 */ +/* rx/tx buffer base address */ +#define ENDP2_TXADDR (0x100) +#define ENDP2_RXADDR (0x140) + +/* EP3 */ +/* rx/tx buffer base address */ +#define ENDP3_TXADDR (0x180) +#define ENDP3_RXADDR (0x1C0) + +/*-------------------------------------------------------------*/ +/* ------------------- ISTR events -------------------------*/ +/*-------------------------------------------------------------*/ +/* IMR_MSK */ +/* mask defining which events has to be handled */ +/* by the device application software */ +#define IMR_MSK \ + (CNTR_CTRM | CNTR_WKUPM | CNTR_SUSPM | CNTR_ERRM | CNTR_SOFM \ + | CNTR_ESOFM | CNTR_RESETM) + +/* Provide a callback function for SOF so we can do early USB detection */ +#define SOF_CALLBACK + +/* Provide a callback function for SUSPend so we can notice a cable removal event */ +#define SUSP_CALLBACK + +#endif /* STM32F10X_CL */ + +#ifdef STM32F10X_CL + +/******************************************************************************* +* FIFO Size Configuration +* +* (i) Dedicated data FIFO SPRAM of 1.25 Kbytes = 1280 bytes = 320 32-bits words +* available for the endpoints IN and OUT. +* Device mode features: +* -1 bidirectional CTRL EP 0 +* -3 IN EPs to support any kind of Bulk, Interrupt or Isochronous transfer +* -3 OUT EPs to support any kind of Bulk, Interrupt or Isochronous transfer +* +* ii) Receive data FIFO size = RAM for setup packets + +* OUT endpoint control information + +* data OUT packets + miscellaneous +* Space = ONE 32-bits words +* --> RAM for setup packets = 4 * n + 6 space +* (n is the nbr of CTRL EPs the device core supports) +* --> OUT EP CTRL info = 1 space +* (one space for status information written to the FIFO along with each +* received packet) +* --> data OUT packets = (Largest Packet Size / 4) + 1 spaces +* (MINIMUM to receive packets) +* --> OR data OUT packets = at least 2*(Largest Packet Size / 4) + 1 spaces +* (if high-bandwidth EP is enabled or multiple isochronous EPs) +* --> miscellaneous = 1 space per OUT EP +* (one space for transfer complete status information also pushed to the +* FIFO with each endpoint's last packet) +* +* (iii)MINIMUM RAM space required for each IN EP Tx FIFO = MAX packet size for +* that particular IN EP. More space allocated in the IN EP Tx FIFO results +* in a better performance on the USB and can hide latencies on the AHB. +* +* (iv) TXn min size = 16 words. (n : Transmit FIFO index) +* (v) When a TxFIFO is not used, the Configuration should be as follows: +* case 1 : n > m and Txn is not used (n,m : Transmit FIFO indexes) +* --> Txm can use the space allocated for Txn. +* case2 : n < m and Txn is not used (n,m : Transmit FIFO indexes) +* --> Txn should be configured with the minimum space of 16 words +* (vi) The FIFO is used optimally when used TxFIFOs are allocated in the top +* of the FIFO.Ex: use EP1 and EP2 as IN instead of EP1 and EP3 as IN ones. +*******************************************************************************/ + +#define RX_FIFO_SIZE 128 +#define TX0_FIFO_SIZE 64 +#define TX1_FIFO_SIZE 64 +#define TX2_FIFO_SIZE 16 +#define TX3_FIFO_SIZE 16 + +/* OTGD-FS-DEVICE IP interrupts Enable definitions */ +/* Uncomment the define to enable the selected interrupt */ +// #define INTR_MODEMISMATCH +#define INTR_SOFINTR +#define INTR_RXSTSQLVL /* Mandatory */ +// #define INTR_NPTXFEMPTY +// #define INTR_GINNAKEFF +// #define INTR_GOUTNAKEFF +// #define INTR_ERLYSUSPEND +#define INTR_USBSUSPEND /* Mandatory */ +#define INTR_USBRESET /* Mandatory */ +#define INTR_ENUMDONE /* Mandatory */ +// #define INTR_ISOOUTDROP +// #define INTR_EOPFRAME +// #define INTR_EPMISMATCH +#define INTR_INEPINTR /* Mandatory */ +#define INTR_OUTEPINTR /* Mandatory */ +// #define INTR_INCOMPLISOIN +// #define INTR_INCOMPLISOOUT +#define INTR_WKUPINTR /* Mandatory */ + +/* OTGD-FS-DEVICE IP interrupts subroutines */ +/* Comment the define to enable the selected interrupt subroutine and replace it + by user code */ +#define INTR_MODEMISMATCH_Callback NOP_Process +#define INTR_SOFINTR_Callback NOP_Process +#define INTR_RXSTSQLVL_Callback NOP_Process +#define INTR_NPTXFEMPTY_Callback NOP_Process +#define INTR_NPTXFEMPTY_Callback NOP_Process +#define INTR_GINNAKEFF_Callback NOP_Process +#define INTR_GOUTNAKEFF_Callback NOP_Process +#define INTR_ERLYSUSPEND_Callback NOP_Process +#define INTR_USBSUSPEND_Callback NOP_Process +#define INTR_USBRESET_Callback NOP_Process +#define INTR_ENUMDONE_Callback NOP_Process +#define INTR_ISOOUTDROP_Callback NOP_Process +#define INTR_EOPFRAME_Callback NOP_Process +#define INTR_EPMISMATCH_Callback NOP_Process +#define INTR_INEPINTR_Callback NOP_Process +#define INTR_OUTEPINTR_Callback NOP_Process +#define INTR_INCOMPLISOIN_Callback NOP_Process +#define INTR_INCOMPLISOOUT_Callback NOP_Process +#define INTR_WKUPINTR_Callback NOP_Process + +/* Isochronous data update */ +#define INTR_RXSTSQLVL_ISODU_Callback NOP_Process + +/* Isochronous transfer parameters */ +/* Size of a single Isochronous buffer (size of a single transfer) */ +#define ISOC_BUFFER_SZE 1 +/* Number of sub-buffers (number of single buffers/transfers), should be even */ +#define NUM_SUB_BUFFERS 2 + +#endif /* STM32F10X_CL */ + +/* CTR service routines */ +/* associated to defined endpoints */ +#define EP1_IN_Callback NOP_Process +#define EP2_IN_Callback NOP_Process +#define EP3_IN_Callback NOP_Process +#define EP4_IN_Callback NOP_Process +#define EP5_IN_Callback NOP_Process +#define EP6_IN_Callback NOP_Process +#define EP7_IN_Callback NOP_Process + +#define EP1_OUT_Callback NOP_Process +#define EP2_OUT_Callback NOP_Process +#define EP3_OUT_Callback NOP_Process +#define EP4_OUT_Callback NOP_Process +#define EP5_OUT_Callback NOP_Process +#define EP6_OUT_Callback NOP_Process +#define EP7_OUT_Callback NOP_Process + +#endif /*__USB_CONF_H*/ + +/******************* (C) COPYRIGHT 2010 STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/library.mk b/flight/pios/stm32f30x/library.mk new file mode 100644 index 0000000000..45e22d443d --- /dev/null +++ b/flight/pios/stm32f30x/library.mk @@ -0,0 +1,69 @@ +# +# Rules to (help) build the F30x device support. +# + +# Directory containing this makefile +PIOS_DEVLIB := $(dir $(lastword $(MAKEFILE_LIST))) + +USE_USB ?= YES + +# Hardcoded linker script names for now +LINKER_SCRIPTS_APP = $(OPSYSTEM)/memory.ld \ + $(OPSYSTEM)/../common/sections.ld +LINKER_SCRIPTS_BL = $(OPSYSTEM)/memory.ld \ + $(OPSYSTEM)/../common/sections.ld +# _compat linker script are aimed at bootloader updater to guarantee to be compatible with earlier bootloaders. +LINKER_SCRIPTS_COMPAT = $(PIOS_DEVLIB)link_$(BOARD)_fw_memory.ld \ + $(PIOS_DEVLIB)link_$(BOARD)_sections_compat.ld + +CDEFS += -D$(CHIP) -DSTM32F3 +CDEFS += -DHSE_VALUE=$(OSCILLATOR_FREQ) +CDEFS += -DUSE_STDPERIPH_DRIVER +CDEFS += -DARM_MATH_CM4 -D__FPU_PRESENT=1 +CDEFS += -DPIOS_TARGET_PROVIDES_FAST_HEAP + +ARCHFLAGS += -mcpu=cortex-m4 -march=armv7e-m -mfpu=fpv4-sp-d16 -mfloat-abi=hard + +# PIOS device library source and includes +PIOS_DEVLIB_SRC = $(sort $(wildcard $(PIOS_DEVLIB)*.c)) + +ifeq ($(PIOS_OMITS_USB),YES) + SRC += $(filter-out $(wildcard $(PIOS_DEVLIB)pios_usb*.c), $(PIOS_DEVLIB_SRC)) +else + SRC += $(PIOS_DEVLIB_SRC) +endif + +EXTRAINCDIRS += $(PIOS_DEVLIB)inc + +# CMSIS for the F3 +include $(PIOSCOMMON)/libraries/CMSIS/library.mk +CMSIS_DEVICEDIR := $(PIOS_DEVLIB)libraries/CMSIS3/Device/ST/STM32F30x +SRC += $(OPSYSTEM)/../common/system.c +EXTRAINCDIRS += $(CMSIS_DEVICEDIR)/Include + +# ST Peripheral library +PERIPHLIB = $(PIOS_DEVLIB)libraries/STM32F30x_StdPeriph_Driver +ALL_SPL_SOURCES = $(sort $(wildcard $(PERIPHLIB)/src/*.c)) +SPL_SOURCES = $(filter-out %stm32f30x_can.c, $(ALL_SPL_SOURCES)) +SRC += $(SPL_SOURCES) +EXTRAINCDIRS += $(PERIPHLIB)/inc + +ifneq ($(PIOS_OMITS_USB),YES) + # ST USB Device library + USBDEVLIB = $(PIOS_DEVLIB)/libraries/STM32_USB-FS-Device_Driver + SRC += $(sort $(wildcard $(USBDEVLIB)/src/*.c)) + EXTRAINCDIRS += $(USBDEVLIB)/inc +endif + +# +# FreeRTOS +# +# If the application has included the generic FreeRTOS support, then add in +# the device-specific pieces of the code. +# +ifneq ($(FREERTOS_DIR),) + FREERTOS_PORTDIR := $(FREERTOS_DIR) + SRC += $(sort $(wildcard $(FREERTOS_PORTDIR)/portable/GCC/ARM_CM4F/*.c)) + EXTRAINCDIRS += $(FREERTOS_PORTDIR)/portable/GCC/ARM_CM4F + include $(PIOSCOMMON)/libraries/msheap/library.mk +endif diff --git a/flight/pios/stm32f30x/link_STM32F303CCT_CC_Rev1_bl_memory.ld b/flight/pios/stm32f30x/link_STM32F303CCT_CC_Rev1_bl_memory.ld new file mode 100644 index 0000000000..f4a1713f82 --- /dev/null +++ b/flight/pios/stm32f30x/link_STM32F303CCT_CC_Rev1_bl_memory.ld @@ -0,0 +1,7 @@ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 0x004000 - 0x000080 + BD_INFO (r) : ORIGIN = 0x08004000 - 0x80, LENGTH = 0x000080 + SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x009000 + CCSRAM (rw) : ORIGIN = 0x10000000, LENGTH = 0x002000 +} diff --git a/flight/pios/stm32f30x/link_STM32F303CCT_CC_Rev1_fw_memory.ld b/flight/pios/stm32f30x/link_STM32F303CCT_CC_Rev1_fw_memory.ld new file mode 100644 index 0000000000..c84c8ac8dd --- /dev/null +++ b/flight/pios/stm32f30x/link_STM32F303CCT_CC_Rev1_fw_memory.ld @@ -0,0 +1,8 @@ +MEMORY +{ + BD_INFO (r) : ORIGIN = 0x08004000 - 0x80, LENGTH = 0x000080 + RSVD (rx) : ORIGIN = 0x08004000, LENGTH = 0x00C000 - 0x004000 + FLASH (rx) : ORIGIN = 0x0800C000, LENGTH = 0x034000 + SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00A000 + CCSRAM (rw) : ORIGIN = 0x10000000, LENGTH = 0x002000 +} diff --git a/flight/pios/stm32f30x/link_STM32F303CCT_CC_Rev1_sections.ld b/flight/pios/stm32f30x/link_STM32F303CCT_CC_Rev1_sections.ld new file mode 100644 index 0000000000..b3eada5843 --- /dev/null +++ b/flight/pios/stm32f30x/link_STM32F303CCT_CC_Rev1_sections.ld @@ -0,0 +1,197 @@ + +/* Section Definitions */ +SECTIONS +{ + /* + * Vectors, code and constant data. + */ + .text : + { + PROVIDE (pios_isr_vector_table_base = .); + KEEP(*(.cpu_vectors)) /* CPU exception vectors */ + KEEP(*(.io_vectors)) /* I/O interrupt vectors */ + *(.text .text.* .gnu.linkonce.t.*) + *(.glue_7t) *(.glue_7) + *(.rodata .rodata* .gnu.linkonce.r.*) + } > FLASH + + /* + * Init section for UAVObjects. + */ + .initcalluavobj.init : + { + . = ALIGN(4); + __uavobj_initcall_start = .; + KEEP(*(.initcalluavobj.init)) + . = ALIGN(4); + __uavobj_initcall_end = .; + } >FLASH + + /* + * Module init section section + */ + .initcallmodule.init : + { + . = ALIGN(4); + __module_initcall_start = .; + KEEP(*(.initcallmodule.init)) + . = ALIGN(4); + __module_initcall_end = .; + } >FLASH + + + /* + * C++ exception handling. + */ + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > FLASH + .ARM.exidx : + { + __exidx_start = .; + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + __exidx_end = .; + } > FLASH + + /* + * Markers for the end of the 'text' section and the in-flash start of + * non-constant data + */ + . = ALIGN(4); + _etext = .; + _sidata = .; + + /* + * Board info structure, normally only generated by the bootloader but can + * be read by the application. + */ + PROVIDE(pios_board_info_blob = ORIGIN(BD_INFO)); + .boardinfo : + { + . = ALIGN(4); + KEEP(*(.boardinfo)) + . = ALIGN(ORIGIN(BD_INFO)+LENGTH(BD_INFO)); + } > BD_INFO + + /* + * Place the IRQ/bootstrap stack at the bottom of SRAM so that an overflow + * results in a hard fault. + */ + .istack (NOLOAD) : + { + . = ALIGN(4); + _irq_stack_end = . ; + *(.irqstack) + _irq_stack_top = . ; + } > CCSRAM + + + /* + * Non-const initialised data. + */ + .data : AT (_sidata) + { + . = ALIGN(4); + _sdata = .; + *(.data .data.*) + . = ALIGN(4); + _edata = . ; + } > SRAM + + /* + * Uninitialised data (BSS + commons). + */ + .bss (NOLOAD) : + { + _sbss = . ; + *(SORT_BY_ALIGNMENT(.bss*)) + *(COMMON) + _ebss = . ; + PROVIDE ( _end = _ebss ) ; + } > SRAM + + /* + * The heap consumes the remainder of the SRAM. + */ + .heap (NOLOAD) : + { + . = ALIGN(4); + _sheap = . ; + + /* + * This allows us to declare an object or objects up to the minimum acceptable + * heap size and receive a linker error if the space available for the heap is + * not sufficient. + */ + *(.heap) + + /* extend the heap up to the top of SRAM */ + . = ORIGIN(SRAM) + LENGTH(SRAM) - ABSOLUTE(_sheap); + _eheap = .; + } > SRAM + + /* + * 'Fast' memory goes in the CCM SRAM + */ + .fast (NOLOAD) : + { + _sfast = . ; + *(.fast) + _efast = . ; + } > CCSRAM + + /* + * The fastheap consumes the remainder of the CCSRAM. + */ + .fastheap (NOLOAD) : + { + . = ALIGN(4); + _sfastheap = . ; + + /* + * This allows us to declare an object or objects up to the minimum acceptable + * heap size and receive a linker error if the space available for the heap is + * not sufficient. + */ + *(.fastheap) + + /* extend the heap up to the top of SRAM */ + . = ORIGIN(CCSRAM) + LENGTH(CCSRAM) - ABSOLUTE(_sfastheap); + _efastheap = .; + } > CCSRAM + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } +} diff --git a/flight/pios/stm32f30x/pios_bkp.c b/flight/pios/stm32f30x/pios_bkp.c new file mode 100644 index 0000000000..4475445a2c --- /dev/null +++ b/flight/pios/stm32f30x/pios_bkp.c @@ -0,0 +1,111 @@ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_BKP Backup SRAM functions + * @brief Hardware abstraction layer for backup sram + * @{ + * + * @file pios_bkp.c + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2013. + * @brief IAP 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 +#include +#include + +/**************************************************************************************** +* Header files +****************************************************************************************/ + +/***************************************************************************************** + * Public Definitions/Macros + ****************************************************************************************/ + +/**************************************************************************************** +* Public Functions +****************************************************************************************/ +const uint32_t pios_bkp_registers_map[] = { + RTC_BKP_DR0, + RTC_BKP_DR1, + RTC_BKP_DR2, + RTC_BKP_DR3, + RTC_BKP_DR4, + RTC_BKP_DR5, + RTC_BKP_DR6, + RTC_BKP_DR7, + RTC_BKP_DR8, + RTC_BKP_DR9, + RTC_BKP_DR10, + RTC_BKP_DR11, + RTC_BKP_DR12, + RTC_BKP_DR13, + RTC_BKP_DR14, + RTC_BKP_DR15, +}; +#define PIOS_BKP_REGISTERS_COUNT NELEMENTS(pios_bkp_registers_map) + +void PIOS_BKP_Init(void) +{ + /* Enable CRC clock */ + RCC_AHBPeriphClockCmd(RCC_AHBPeriph_CRC, ENABLE); + + /* Enable PWR and BKP clock */ + RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE); + + /* Clear Tamper pin Event(TE) pending flag */ + RTC_ClearFlag(RTC_FLAG_TAMP1F); +} + +uint16_t PIOS_BKP_ReadRegister(uint32_t regnumber) +{ + if (PIOS_BKP_REGISTERS_COUNT < regnumber) { + PIOS_Assert(0); + } else { + return (uint16_t)RTC_ReadBackupRegister(pios_bkp_registers_map[regnumber]); + } +} + +void PIOS_BKP_WriteRegister(uint32_t regnumber, uint16_t data) +{ + if (PIOS_BKP_REGISTERS_COUNT < regnumber) { + PIOS_Assert(0); + } else { + RTC_WriteBackupRegister(pios_bkp_registers_map[regnumber], (uint32_t)data); + } +} + +void PIOS_BKP_EnableWrite(void) +{ + /* Enable write access to Backup domain */ + PWR_BackupAccessCmd(ENABLE); +} + +void PIOS_BKP_DisableWrite(void) +{ + /* Enable write access to Backup domain */ + PWR_BackupAccessCmd(DISABLE); +} + + +/**************************************************************************************** +* Public Data +****************************************************************************************/ diff --git a/flight/pios/stm32f30x/pios_bl_helper.c b/flight/pios/stm32f30x/pios_bl_helper.c new file mode 100644 index 0000000000..43e89ee965 --- /dev/null +++ b/flight/pios/stm32f30x/pios_bl_helper.c @@ -0,0 +1,127 @@ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_BOOTLOADER Functions + * @brief HAL code to interface to the OpenPilot AHRS module + * @{ + * + * @file pios_bl_helper.c + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief Bootloader Helper 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 + +#ifdef PIOS_INCLUDE_BL_HELPER + +#include +#include +#include + +uint8_t *PIOS_BL_HELPER_FLASH_If_Read(uint32_t SectorAddress) +{ + return (uint8_t *)(SectorAddress); +} + +#if defined(PIOS_INCLUDE_BL_HELPER_WRITE_SUPPORT) + +static bool erase_flash(uint32_t startAddress, uint32_t endAddress); + +uint8_t PIOS_BL_HELPER_FLASH_Ini() +{ + FLASH_Unlock(); + return 1; +} + +uint8_t PIOS_BL_HELPER_FLASH_Start() +{ + const struct pios_board_info *bdinfo = &pios_board_info_blob; + uint32_t startAddress = bdinfo->fw_base; + uint32_t endAddress = bdinfo->fw_base + bdinfo->fw_size + bdinfo->desc_size; + + bool success = erase_flash(startAddress, endAddress); + + return (success) ? 1 : 0; +} + +uint8_t PIOS_BL_HELPER_FLASH_Erase_Bootloader() +{ +/// Bootloader memory space erase + uint32_t startAddress = BL_BANK_BASE; + uint32_t endAddress = BL_BANK_BASE + BL_BANK_SIZE; + + bool success = erase_flash(startAddress, endAddress); + + return (success) ? 1 : 0; +} + +static bool erase_flash(uint32_t startAddress, uint32_t endAddress) +{ + uint32_t pageAddress = startAddress; + uint8_t fail = false; + + while ((pageAddress < endAddress) && (fail == false)) { + for (int retry = 0; retry < MAX_DEL_RETRYS; ++retry) { + if (FLASH_ErasePage(pageAddress) == FLASH_COMPLETE) { + fail = false; + break; + } else { + fail = true; + } + } + + pageAddress += 2048; + } + return !fail; +} + +#endif /* if defined(PIOS_INCLUDE_BL_HELPER_WRITE_SUPPORT) */ + +uint32_t PIOS_BL_HELPER_CRC_Memory_Calc() +{ + const struct pios_board_info *bdinfo = &pios_board_info_blob; + + PIOS_BL_HELPER_CRC_Ini(); + CRC_ResetDR(); + CRC_CalcBlockCRC((uint32_t *)bdinfo->fw_base, (bdinfo->fw_size) >> 2); + return CRC_GetCRC(); +} + +void PIOS_BL_HELPER_FLASH_Read_Description(uint8_t *array, uint8_t size) +{ + const struct pios_board_info *bdinfo = &pios_board_info_blob; + uint8_t x = 0; + + if (size > bdinfo->desc_size) { + size = bdinfo->desc_size; + } + for (uint32_t i = bdinfo->fw_base + bdinfo->fw_size; i < bdinfo->fw_base + bdinfo->fw_size + size; ++i) { + array[x] = *PIOS_BL_HELPER_FLASH_If_Read(i); + ++x; + } +} + +void PIOS_BL_HELPER_CRC_Ini() +{ + RCC_AHBPeriphClockCmd(RCC_AHBPeriph_CRC, ENABLE); +} + +#endif /* PIOS_INCLUDE_BL_HELPER */ diff --git a/flight/pios/stm32f30x/pios_can.c b/flight/pios/stm32f30x/pios_can.c new file mode 100644 index 0000000000..dc5e8e33fc --- /dev/null +++ b/flight/pios/stm32f30x/pios_can.c @@ -0,0 +1,429 @@ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_CAN PiOS CAN interface layer + * @brief CAN interface for PiOS + * @{ + * + * @file pios_can.c + * @author Tau Labs, http://taulabs.org, Copyright (C) 2013-2014 + * @author dRonin, http://dronin.org, Copyright (C) 2016 + * @brief PiOS CAN interface 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 + */ + + +#include "pios.h" + +#if defined(PIOS_INCLUDE_CAN) + +#include "pios_can_priv.h" + +/* Provide a COM driver */ +static void PIOS_CAN_RegisterRxCallback(uintptr_t can_id, pios_com_callback rx_in_cb, uintptr_t context); +static void PIOS_CAN_RegisterTxCallback(uintptr_t can_id, pios_com_callback tx_out_cb, uintptr_t context); +static void PIOS_CAN_TxStart(uintptr_t can_id, uint16_t tx_bytes_avail); +static void PIOS_CAN_RxStart(uintptr_t can_id, uint16_t rx_bytes_avail); + +const struct pios_com_driver pios_can_com_driver = { + .tx_start = PIOS_CAN_TxStart, + .rx_start = PIOS_CAN_RxStart, + .bind_tx_cb = PIOS_CAN_RegisterTxCallback, + .bind_rx_cb = PIOS_CAN_RegisterRxCallback, +}; + +enum pios_can_dev_magic { + PIOS_CAN_DEV_MAGIC = 0x41fa834A, +}; + +// ! Structure for an initialized CAN handle +struct pios_can_dev { + enum pios_can_dev_magic magic; + const struct pios_can_cfg *cfg; + pios_com_callback rx_in_cb; + uintptr_t rx_in_context; + pios_com_callback tx_out_cb; + uintptr_t tx_out_context; +}; + +// Local constants +#define CAN_COM_ID 0x11 +#define MAX_SEND_LEN 8 + +void USB_HP_CAN1_TX_IRQHandler(void); + +static bool PIOS_CAN_validate(struct pios_can_dev *can_dev) +{ + return can_dev->magic == PIOS_CAN_DEV_MAGIC; +} + +static struct pios_can_dev *PIOS_CAN_alloc(void) +{ + struct pios_can_dev *can_dev; + + can_dev = (struct pios_can_dev *)PIOS_malloc(sizeof(*can_dev)); + if (!can_dev) { + return NULL; + } + + memset(can_dev, 0, sizeof(*can_dev)); + can_dev->magic = PIOS_CAN_DEV_MAGIC; + + return can_dev; +} + +// ! The local handle for the CAN device +static struct pios_can_dev *can_dev; + +/** + * Initialize the CAN driver and return an opaque id + * @param[out] id the CAN interface handle + * @param[in] cfg the configuration structure + * @return 0 if successful, negative otherwise + */ +int32_t PIOS_CAN_Init(uintptr_t *can_id, const struct pios_can_cfg *cfg) +{ + PIOS_DEBUG_Assert(can_id); + PIOS_DEBUG_Assert(cfg); + + can_dev = (struct pios_can_dev *)PIOS_CAN_alloc(); + if (!can_dev) { + goto out_fail; + } + + /* Bind the configuration to the device instance */ + can_dev->cfg = cfg; + + /* Configure the CAN device */ + RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE); + + /* Map pins to CAN function */ + if (can_dev->cfg->remap) { + if (can_dev->cfg->rx.gpio != 0) { + GPIO_PinAFConfig(can_dev->cfg->rx.gpio, + can_dev->cfg->rx.pin_source, + can_dev->cfg->remap); + } + if (can_dev->cfg->tx.gpio != 0) { + GPIO_PinAFConfig(can_dev->cfg->tx.gpio, + can_dev->cfg->tx.pin_source, + can_dev->cfg->remap); + } + } + + /* Initialize the CAN Rx and Tx pins */ + if (can_dev->cfg->rx.gpio != 0) { + GPIO_Init(can_dev->cfg->rx.gpio, (GPIO_InitTypeDef *)&can_dev->cfg->rx.init); + } + if (can_dev->cfg->tx.gpio != 0) { + GPIO_Init(can_dev->cfg->tx.gpio, (GPIO_InitTypeDef *)&can_dev->cfg->tx.init); + } + + *can_id = (uintptr_t)can_dev; + + CAN_DeInit(can_dev->cfg->regs); + CAN_Init(can_dev->cfg->regs, (CAN_InitTypeDef *)&can_dev->cfg->init); + + /* CAN filter init */ + CAN_FilterInitTypeDef CAN_FilterInitStructure; + CAN_FilterInitStructure.CAN_FilterNumber = 0; + CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask; + CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit; + CAN_FilterInitStructure.CAN_FilterIdHigh = 0x0000; + CAN_FilterInitStructure.CAN_FilterIdLow = 0x0000; + CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0x0000; + CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0x0000; + CAN_FilterInitStructure.CAN_FilterFIFOAssignment = 1; + + CAN_FilterInitStructure.CAN_FilterActivation = ENABLE; + CAN_FilterInit(&CAN_FilterInitStructure); + + // Enable the receiver IRQ + NVIC_Init((NVIC_InitTypeDef *)&can_dev->cfg->rx_irq.init); + NVIC_Init((NVIC_InitTypeDef *)&can_dev->cfg->tx_irq.init); + + return 0; + +out_fail: + return -1; +} + +static void PIOS_CAN_RxStart(uintptr_t can_id, uint16_t rx_bytes_avail) +{ + struct pios_can_dev *can_dev = (struct pios_can_dev *)can_id; + + bool valid = PIOS_CAN_validate(can_dev); + + PIOS_Assert(valid); + + CAN_ITConfig(can_dev->cfg->regs, CAN_IT_FMP1, ENABLE); +} + +static void PIOS_CAN_TxStart(uintptr_t can_id, uint16_t tx_bytes_avail) +{ + struct pios_can_dev *can_dev = (struct pios_can_dev *)can_id; + + bool valid = PIOS_CAN_validate(can_dev); + + PIOS_Assert(valid); + + CAN_ITConfig(can_dev->cfg->regs, CAN_IT_TME, ENABLE); + + USB_HP_CAN1_TX_IRQHandler(); +} + +static void PIOS_CAN_RegisterRxCallback(uintptr_t can_id, pios_com_callback rx_in_cb, uintptr_t context) +{ + struct pios_can_dev *can_dev = (struct pios_can_dev *)can_id; + + bool valid = PIOS_CAN_validate(can_dev); + + PIOS_Assert(valid); + + /* + * Order is important in these assignments since ISR uses _cb + * field to determine if it's ok to dereference _cb and _context + */ + can_dev->rx_in_context = context; + can_dev->rx_in_cb = rx_in_cb; +} + +static void PIOS_CAN_RegisterTxCallback(uintptr_t can_id, pios_com_callback tx_out_cb, uintptr_t context) +{ + struct pios_can_dev *can_dev = (struct pios_can_dev *)can_id; + + bool valid = PIOS_CAN_validate(can_dev); + + PIOS_Assert(valid); + + /* + * Order is important in these assignments since ISR uses _cb + * field to determine if it's ok to dereference _cb and _context + */ + can_dev->tx_out_context = context; + can_dev->tx_out_cb = tx_out_cb; +} + +// ! The mapping of message types to CAN BUS StdID +static uint32_t pios_can_message_stdid[PIOS_CAN_LAST] = { + [PIOS_CAN_GIMBAL] = 0x130, +}; + +// ! The mapping of message types to CAN BUS StdID +static struct pios_queue *pios_can_queues[PIOS_CAN_LAST]; + +/** + * Process received CAN messages and push them out any corresponding + * queues. Called from ISR. + */ +static bool process_received_message(CanRxMsg message) +{ + // Look for a known message that matches this CAN StdId + uint32_t msg_id; + + for (msg_id = 0; msg_id < PIOS_CAN_LAST && pios_can_message_stdid[msg_id] != message.StdId; msg_id++) { + ; + } + + // If StdId is not one of the known messages, bail out + if (msg_id == PIOS_CAN_LAST) { + return false; + } + + // Get the queue for this message and send the data + struct pios_queue *queue = pios_can_queues[msg_id]; + if (queue == NULL) { + return false; + } + + bool woken = false; + PIOS_Queue_Send_FromISR(queue, message.Data, &woken); + + return woken; +} + +/** + * Create a queue to receive messages for a particular message + * and return it + * @param[in] id the CAN device ID + * @param[in] msg_id The message ID (std ID < 0x7FF) + */ +struct pios_queue *PIOS_CAN_RegisterMessageQueue(uintptr_t id, enum pios_can_messages msg_id) +{ + // Fetch the size of this message type or error if unknown + uint32_t bytes; + + switch (msg_id) { + case PIOS_CAN_GIMBAL: + bytes = sizeof(struct pios_can_gimbal_message); + break; + default: + return NULL; + } + + // Return existing queue if created + if (pios_can_queues[msg_id] != NULL) { + return pios_can_queues[msg_id]; + } + + // Create a queue that can manage the data message size + struct pios_queue *queue; + queue = PIOS_Queue_Create(2, bytes); + if (queue == NULL) { + return NULL; + } + + // Store the queue handle for the driver + pios_can_queues[msg_id] = queue; + + return queue; +} + +// Map the specific IRQ handlers to the device handle + +static void PIOS_CAN_RxGeneric(void); +static void PIOS_CAN_TxGeneric(void); + +void CAN1_RX1_IRQHandler(void) +{ +#if defined(PIOS_INCLUDE_CHIBIOS) + CH_IRQ_PROLOGUE(); +#endif /* defined(PIOS_INCLUDE_CHIBIOS) */ + + PIOS_CAN_RxGeneric(); + +#if defined(PIOS_INCLUDE_CHIBIOS) + CH_IRQ_EPILOGUE(); +#endif /* defined(PIOS_INCLUDE_CHIBIOS) */ +} + +void USB_HP_CAN1_TX_IRQHandler(void) +{ +#if defined(PIOS_INCLUDE_CHIBIOS) + CH_IRQ_PROLOGUE(); +#endif /* defined(PIOS_INCLUDE_CHIBIOS) */ + + PIOS_CAN_TxGeneric(); + +#if defined(PIOS_INCLUDE_CHIBIOS) + CH_IRQ_EPILOGUE(); +#endif /* defined(PIOS_INCLUDE_CHIBIOS) */ +} + +/** + * @brief This function handles CAN1 RX1 request. + * @note We are using RX1 instead of RX0 to avoid conflicts with the + * USB IRQ handler. + */ +static void PIOS_CAN_RxGeneric(void) +{ + CAN_ClearITPendingBit(can_dev->cfg->regs, CAN_IT_FMP1); + + bool valid = PIOS_CAN_validate(can_dev); + PIOS_Assert(valid); + + CanRxMsg RxMessage; + CAN_Receive(CAN1, CAN_FIFO1, &RxMessage); + + bool rx_need_yield = false; + if (RxMessage.StdId == CAN_COM_ID) { + if (can_dev->rx_in_cb) { + (void)(can_dev->rx_in_cb)(can_dev->rx_in_context, RxMessage.Data, RxMessage.DLC, NULL, &rx_need_yield); + } + } else { + rx_need_yield = process_received_message(RxMessage); + } +} + +/** + * @brief This function handles CAN1 TX irq and sends more data if available + */ +static void PIOS_CAN_TxGeneric(void) +{ + CAN_ClearITPendingBit(can_dev->cfg->regs, CAN_IT_TME); + + bool valid = PIOS_CAN_validate(can_dev); + PIOS_Assert(valid); + + bool tx_need_yield = false; + + if (can_dev->tx_out_cb) { + // Prepare CAN message structure + CanTxMsg msg; + msg.StdId = CAN_COM_ID; + msg.ExtId = 0; + msg.IDE = CAN_ID_STD; + msg.RTR = CAN_RTR_DATA; + msg.DLC = (can_dev->tx_out_cb)(can_dev->tx_out_context, msg.Data, MAX_SEND_LEN, NULL, &tx_need_yield); + + // Send message and get mailbox number + if (msg.DLC > 0) { + CAN_Transmit(can_dev->cfg->regs, &msg); + } else { + CAN_ITConfig(can_dev->cfg->regs, CAN_IT_TME, DISABLE); + } + + // TODO: deal with failure to send and keep the message to retransmit + } +} + + +/** + * PIOS_CAN_TxData transmits a data message with a specified ID + * @param[in] id the CAN device ID + * @param[in] msg_id The message ID (std ID < 0x7FF) + * @param[in] data Pointer to data message + * @returns number of bytes sent if successful, -1 if not + */ +int32_t PIOS_CAN_TxData(uintptr_t id, enum pios_can_messages msg_id, uint8_t *data) +{ + // Fetch the size of this message type or error if unknown + uint32_t bytes; + + switch (msg_id) { + case PIOS_CAN_GIMBAL: + bytes = sizeof(struct pios_can_gimbal_message); + break; + default: + return -1; + } + + // Look up the CAN BUS Standard ID for this message type + uint32_t std_id = pios_can_message_stdid[msg_id]; + + // Format and send the message + CanTxMsg msg; + msg.StdId = std_id & 0x7FF; + msg.ExtId = 0; + msg.IDE = CAN_ID_STD; + msg.RTR = CAN_RTR_DATA; + msg.DLC = (bytes > 8) ? 8 : bytes; + memcpy(msg.Data, data, msg.DLC); + CAN_Transmit(can_dev->cfg->regs, &msg); + + return msg.DLC; +} + + +#endif /* PIOS_INCLUDE_CAN */ +/** + * @} + * @} + */ diff --git a/flight/pios/stm32f30x/pios_debug.c b/flight/pios/stm32f30x/pios_debug.c new file mode 100644 index 0000000000..a7c9bf53a3 --- /dev/null +++ b/flight/pios/stm32f30x/pios_debug.c @@ -0,0 +1,178 @@ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @defgroup PIOS_DEBUG Debugging Functions + * @brief Debugging functionality + * @{ + * + * @file pios_debug.c + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2013. + * @brief Debugging 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.h" + +// Global variables +const char *PIOS_DEBUG_AssertMsg = "ASSERT FAILED"; + +#ifdef PIOS_ENABLE_DEBUG_PINS +static const struct pios_tim_channel *debug_channels; +static uint8_t debug_num_channels; +#endif /* PIOS_ENABLE_DEBUG_PINS */ + +/** + * Initialise Debug-features + */ +void PIOS_DEBUG_Init(__attribute__((unused)) const struct pios_tim_channel *channels, __attribute__((unused)) uint8_t num_channels) +{ +#ifdef PIOS_ENABLE_DEBUG_PINS + PIOS_Assert(channels); + PIOS_Assert(num_channels); + + /* Store away the GPIOs we've been given */ + debug_channels = channels; + debug_num_channels = num_channels; + + /* Configure the GPIOs we've been given */ + for (uint8_t i = 0; i < num_channels; i++) { + const struct pios_tim_channel *chan = &channels[i]; + + // Initialise pins as standard output pins + GPIO_InitTypeDef GPIO_InitStructure; + GPIO_StructInit(&GPIO_InitStructure); + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStructure.GPIO_Pin = chan->pin.init.GPIO_Pin; + + /* Initialize the GPIO */ + GPIO_Init(chan->pin.gpio, &GPIO_InitStructure); + + /* Set the pin low */ + GPIO_WriteBit(chan->pin.gpio, chan->pin.init.GPIO_Pin, Bit_RESET); + } +#endif // PIOS_ENABLE_DEBUG_PINS +} + +/** + * Set debug-pin high + * \param pin 0 for S1 output + */ +void PIOS_DEBUG_PinHigh(__attribute__((unused)) uint8_t pin) +{ +#ifdef PIOS_ENABLE_DEBUG_PINS + if (!debug_channels || pin >= debug_num_channels) { + return; + } + + const struct pios_tim_channel *chan = &debug_channels[pin]; + + GPIO_WriteBit(chan->pin.gpio, chan->pin.init.GPIO_Pin, Bit_SET); + +#endif // PIOS_ENABLE_DEBUG_PINS +} + +/** + * Set debug-pin low + * \param pin 0 for S1 output + */ +void PIOS_DEBUG_PinLow(__attribute__((unused)) uint8_t pin) +{ +#ifdef PIOS_ENABLE_DEBUG_PINS + if (!debug_channels || pin >= debug_num_channels) { + return; + } + + const struct pios_tim_channel *chan = &debug_channels[pin]; + + GPIO_WriteBit(chan->pin.gpio, chan->pin.init.GPIO_Pin, Bit_RESET); + +#endif // PIOS_ENABLE_DEBUG_PINS +} + + +void PIOS_DEBUG_PinValue8Bit(__attribute__((unused)) uint8_t value) +{ +#ifdef PIOS_ENABLE_DEBUG_PINS + if (!debug_channels) { + return; + } + +#pragma message("This code is not portable and should be revised") + PIOS_Assert(0); + + uint32_t bsrr_l = (((~value) & 0x0F) << (16 + 6)) | ((value & 0x0F) << 6); + uint32_t bsrr_h = (((~value) & 0xF0) << (16 + 6 - 4)) | ((value & 0xF0) << (6 - 4)); + + PIOS_IRQ_Disable(); + + /* + * This is sketchy since it assumes a particular ordering + * and bitwise layout of the channels provided to the debug code. + */ + // debug_channels[0].pin.gpio->BSRR = bsrr_l; + // debug_channels[4].pin.gpio->BSRR = bsrr_h; + + PIOS_IRQ_Enable(); +#endif // PIOS_ENABLE_DEBUG_PINS +} + +void PIOS_DEBUG_PinValue4BitL(__attribute__((unused)) uint8_t value) +{ +#ifdef PIOS_ENABLE_DEBUG_PINS + if (!debug_channels) { + return; + } + +#pragma message("This code is not portable and should be revised") + PIOS_Assert(0); + + /* + * This is sketchy since it assumes a particular ordering + * and bitwise layout of the channels provided to the debug code. + */ + uint32_t bsrr_l = ((~(value & 0x0F) << (16 + 6))) | ((value & 0x0F) << 6); + // debug_channels[0].pin.gpio->BSRR = bsrr_l; +#endif // PIOS_ENABLE_DEBUG_PINS +} + + +/** + * Report a serious error and halt + */ +void PIOS_DEBUG_Panic(__attribute__((unused)) const char *msg) +{ +#ifdef PIOS_INCLUDE_DEBUG_CONSOLE + register int *lr asm ("lr"); // Link-register holds the PC of the caller + DEBUG_PRINTF(0, "\r%s @0x%x\r", msg, lr); +#endif + + // Stay put + while (1) { + ; + } +} + +/** + * @} + * @} + */ diff --git a/flight/pios/stm32f30x/pios_delay.c b/flight/pios/stm32f30x/pios_delay.c new file mode 100644 index 0000000000..272afc3f2b --- /dev/null +++ b/flight/pios/stm32f30x/pios_delay.c @@ -0,0 +1,184 @@ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_DELAY Delay Functions + * @brief PiOS Delay functionality + * @{ + * + * @file pios_delay.c + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. + * Michael Smith Copyright (C) 2012 + * @brief Delay Functions + * - Provides a micro-second granular delay using the CPU + * cycle counter. + * @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 + +#ifdef PIOS_INCLUDE_DELAY + +/* cycles per microsecond */ +static uint32_t us_ticks; +static uint32_t raw_hz; + +/** + * Initialises the Timer used by PIOS_DELAY functions. + * + * \return always zero (success) + */ + +int32_t PIOS_DELAY_Init(void) +{ + RCC_ClocksTypeDef clocks; + + /* compute the number of system clocks per microsecond */ + RCC_GetClocksFreq(&clocks); + us_ticks = clocks.SYSCLK_Frequency / 1000000; + PIOS_DEBUG_Assert(us_ticks > 1); + raw_hz = clocks.SYSCLK_Frequency; + + /* turn on access to the DWT registers */ + CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; + + /* enable the CPU cycle counter */ + DWT_CTRL |= CYCCNTENA; + + return 0; +} + +/** + * Waits for a specific number of uS + * + * Example:
+ * \code + * // Wait for 500 uS + * PIOS_DELAY_Wait_uS(500); + * \endcode + * \param[in] uS delay + * \return < 0 on errors + */ +int32_t PIOS_DELAY_WaituS(uint32_t uS) +{ + uint32_t elapsed = 0; + uint32_t last_count = PIOS_DELAY_GetRaw(); + + for (;;) { + uint32_t current_count = PIOS_DELAY_GetRaw(); + uint32_t elapsed_uS; + + /* measure the time elapsed since the last time we checked */ + elapsed += current_count - last_count; + last_count = current_count; + + /* convert to microseconds */ + elapsed_uS = elapsed / us_ticks; + if (elapsed_uS >= uS) { + break; + } + + /* reduce the delay by the elapsed time */ + uS -= elapsed_uS; + + /* keep fractional microseconds for the next iteration */ + elapsed %= us_ticks; + } + + /* No error */ + return 0; +} + +/** + * Waits for a specific number of mS + * + * Example:
+ * \code + * // Wait for 500 mS + * PIOS_DELAY_Wait_mS(500); + * \endcode + * \param[in] mS delay (1..65535 milliseconds) + * \return < 0 on errors + */ +int32_t PIOS_DELAY_WaitmS(uint32_t mS) +{ + while (mS--) { + PIOS_DELAY_WaituS(1000); + } + + /* No error */ + return 0; +} + +/** + * @brief Query the Delay timer for the current uS + * @return A microsecond value + */ +uint32_t PIOS_DELAY_GetuS() +{ + return PIOS_DELAY_GetRaw() / us_ticks; +} + +/** + * @brief Calculate time in microseconds since a previous time + * @param[in] t previous time + * @return time in us since previous time t. + */ +uint32_t PIOS_DELAY_GetuSSince(uint32_t t) +{ + return PIOS_DELAY_GetuS() - t; +} + +/** + * @brief Get the raw delay timer frequency + * @return raw delay timer frequency in Hz + */ +uint32_t PIOS_DELAY_GetRawHz() +{ + return raw_hz; +} + +/** + * @brief Compare to raw times to and convert to us + * @return A microsecond value + */ +uint32_t PIOS_DELAY_DiffuS(uint32_t raw) +{ + uint32_t diff = PIOS_DELAY_GetRaw() - raw; + + return diff / us_ticks; +} + +#if !defined(PIOS_EXCLUDE_ADVANCED_FEATURES) +/** + * @brief Subtract two raw times and convert to us. + * @return Interval between raw times in microseconds + */ +uint32_t PIOS_DELAY_DiffuS2(uint32_t raw, uint32_t later) +{ + return (later - raw) / us_ticks; +} +#endif /* !defined(PIOS_EXCLUDE_ADVANCED_FEATURES) */ + +#endif /* PIOS_INCLUDE_DELAY */ + +/** + * @} + * @} + */ diff --git a/flight/pios/stm32f30x/pios_exti.c b/flight/pios/stm32f30x/pios_exti.c new file mode 100644 index 0000000000..8f2d785402 --- /dev/null +++ b/flight/pios/stm32f30x/pios_exti.c @@ -0,0 +1,326 @@ +/** + ****************************************************************************** + * + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_EXTI External Interrupt Handlers + * @brief External interrupt handler functions + * @{ + * + * @file pios_exti.c + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief External Interrupt Handlers + * @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.h" + +#ifdef PIOS_INCLUDE_EXTI + +#define EXTI_MAX_LINES 16 + +static pios_exti_vector_t pios_exti_vector[EXTI_MAX_LINES]; + +static uint8_t PIOS_EXTI_line_to_index(uint32_t line) +{ + switch (line) { + case EXTI_Line0: return 0; + + case EXTI_Line1: return 1; + + case EXTI_Line2: return 2; + + case EXTI_Line3: return 3; + + case EXTI_Line4: return 4; + + case EXTI_Line5: return 5; + + case EXTI_Line6: return 6; + + case EXTI_Line7: return 7; + + case EXTI_Line8: return 8; + + case EXTI_Line9: return 9; + + case EXTI_Line10: return 10; + + case EXTI_Line11: return 11; + + case EXTI_Line12: return 12; + + case EXTI_Line13: return 13; + + case EXTI_Line14: return 14; + + case EXTI_Line15: return 15; + } + + PIOS_Assert(0); + return 0xFF; +} + +uint8_t PIOS_EXTI_gpio_port_to_exti_source_port(GPIO_TypeDef *gpio_port) +{ + switch ((uint32_t)gpio_port) { + case (uint32_t)GPIOA: return EXTI_PortSourceGPIOA; + + case (uint32_t)GPIOB: return EXTI_PortSourceGPIOB; + + case (uint32_t)GPIOC: return EXTI_PortSourceGPIOC; + + case (uint32_t)GPIOD: return EXTI_PortSourceGPIOD; + + case (uint32_t)GPIOE: return EXTI_PortSourceGPIOE; + + case (uint32_t)GPIOF: return EXTI_PortSourceGPIOF; + } + + PIOS_Assert(0); + return 0xFF; +} + +uint8_t PIOS_EXTI_gpio_pin_to_exti_source_pin(uint32_t gpio_pin) +{ + switch ((uint32_t)gpio_pin) { + case GPIO_Pin_0: return GPIO_PinSource0; + + case GPIO_Pin_1: return GPIO_PinSource1; + + case GPIO_Pin_2: return GPIO_PinSource2; + + case GPIO_Pin_3: return GPIO_PinSource3; + + case GPIO_Pin_4: return GPIO_PinSource4; + + case GPIO_Pin_5: return GPIO_PinSource5; + + case GPIO_Pin_6: return GPIO_PinSource6; + + case GPIO_Pin_7: return GPIO_PinSource7; + + case GPIO_Pin_8: return GPIO_PinSource8; + + case GPIO_Pin_9: return GPIO_PinSource9; + + case GPIO_Pin_10: return GPIO_PinSource10; + + case GPIO_Pin_11: return GPIO_PinSource11; + + case GPIO_Pin_12: return GPIO_PinSource12; + + case GPIO_Pin_13: return GPIO_PinSource13; + + case GPIO_Pin_14: return GPIO_PinSource14; + + case GPIO_Pin_15: return GPIO_PinSource15; + } + + PIOS_Assert(0); + return 0xFF; +} + +int32_t PIOS_EXTI_Init(const struct pios_exti_cfg *cfg) +{ + PIOS_Assert(cfg); + + /* Connect this config to the requested vector */ + uint8_t line_index = PIOS_EXTI_line_to_index(cfg->line); + + if (pios_exti_vector[line_index]) { + /* Someone else already has this mapped */ + return -1; + } + + /* Bind the vector to the exti line */ + pios_exti_vector[line_index] = cfg->vector; + + /* Initialize the GPIO pin */ + GPIO_Init(cfg->pin.gpio, (GPIO_InitTypeDef *)&cfg->pin.init); + + /* Set up the EXTI interrupt source */ + uint8_t exti_source_port = PIOS_EXTI_gpio_port_to_exti_source_port(cfg->pin.gpio); + /* Following is not entirely correct! There is cfg->pin.pin_source to serve this purpose, and GPIO_Pin can also contain more than one bit set */ + uint8_t exti_source_pin = PIOS_EXTI_gpio_pin_to_exti_source_pin(cfg->pin.init.GPIO_Pin); + SYSCFG_EXTILineConfig(exti_source_port, exti_source_pin); + EXTI_Init((EXTI_InitTypeDef *)&cfg->exti.init); + + /* Enable the interrupt channel */ + NVIC_Init((NVIC_InitTypeDef *)&cfg->irq.init); + + return 0; +} + +int32_t PIOS_EXTI_DeInit(const struct pios_exti_cfg *cfg) +{ + uint8_t line_index = PIOS_EXTI_line_to_index(cfg->line); + + if (pios_exti_vector[line_index] == cfg->vector) { + EXTI_InitTypeDef disable = cfg->exti.init; + disable.EXTI_LineCmd = DISABLE; + + EXTI_Init(&disable); + pios_exti_vector[line_index] = 0; + + return 0; + } + + return -1; +} + +static bool PIOS_EXTI_generic_irq_handler(uint8_t line_index) +{ + if (pios_exti_vector[line_index]) { + return pios_exti_vector[line_index](); + } + + /* Unconfigured interrupt just fired! */ + return false; +} + +/* Bind Interrupt Handlers */ + +#ifdef PIOS_INCLUDE_FREERTOS +#define PIOS_EXTI_HANDLE_LINE(line, woken) \ + if (EXTI_GetITStatus(EXTI_Line##line) != RESET) { \ + EXTI_ClearITPendingBit(EXTI_Line##line); \ + woken = PIOS_EXTI_generic_irq_handler(line) ? pdTRUE : woken; \ + } +#else +#define PIOS_EXTI_HANDLE_LINE(line, woken) \ + if (EXTI_GetITStatus(EXTI_Line##line) != RESET) { \ + EXTI_ClearITPendingBit(EXTI_Line##line); \ + PIOS_EXTI_generic_irq_handler(line); \ + } +#endif + +static void PIOS_EXTI_0_irq_handler(void) +{ +#ifdef PIOS_INCLUDE_FREERTOS + portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; +#else + bool xHigherPriorityTaskWoken; +#endif + PIOS_EXTI_HANDLE_LINE(0, xHigherPriorityTaskWoken); +#ifdef PIOS_INCLUDE_FREERTOS + portEND_SWITCHING_ISR(xHigherPriorityTaskWoken); +#endif +} +void EXTI0_IRQHandler(void) __attribute__((alias("PIOS_EXTI_0_irq_handler"))); + +static void PIOS_EXTI_1_irq_handler(void) +{ +#ifdef PIOS_INCLUDE_FREERTOS + portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; +#else + bool xHigherPriorityTaskWoken; +#endif + PIOS_EXTI_HANDLE_LINE(1, xHigherPriorityTaskWoken); +#ifdef PIOS_INCLUDE_FREERTOS + portEND_SWITCHING_ISR(xHigherPriorityTaskWoken); +#endif +} +void EXTI1_IRQHandler(void) __attribute__((alias("PIOS_EXTI_1_irq_handler"))); + +static void PIOS_EXTI_2_irq_handler(void) +{ +#ifdef PIOS_INCLUDE_FREERTOS + portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; +#else + bool xHigherPriorityTaskWoken; +#endif + PIOS_EXTI_HANDLE_LINE(2, xHigherPriorityTaskWoken); +#ifdef PIOS_INCLUDE_FREERTOS + portEND_SWITCHING_ISR(xHigherPriorityTaskWoken); +#endif +} +void EXTI2_IRQHandler(void) __attribute__((alias("PIOS_EXTI_2_irq_handler"))); + +static void PIOS_EXTI_3_irq_handler(void) +{ +#ifdef PIOS_INCLUDE_FREERTOS + portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; +#else + bool xHigherPriorityTaskWoken; +#endif + PIOS_EXTI_HANDLE_LINE(3, xHigherPriorityTaskWoken); +#ifdef PIOS_INCLUDE_FREERTOS + portEND_SWITCHING_ISR(xHigherPriorityTaskWoken); +#endif +} +void EXTI3_IRQHandler(void) __attribute__((alias("PIOS_EXTI_3_irq_handler"))); + +static void PIOS_EXTI_4_irq_handler(void) +{ +#ifdef PIOS_INCLUDE_FREERTOS + portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; +#else + bool xHigherPriorityTaskWoken; +#endif + PIOS_EXTI_HANDLE_LINE(4, xHigherPriorityTaskWoken); +#ifdef PIOS_INCLUDE_FREERTOS + portEND_SWITCHING_ISR(xHigherPriorityTaskWoken); +#endif +} +void EXTI4_IRQHandler(void) __attribute__((alias("PIOS_EXTI_4_irq_handler"))); + +static void PIOS_EXTI_9_5_irq_handler(void) +{ +#ifdef PIOS_INCLUDE_FREERTOS + portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; +#else + bool xHigherPriorityTaskWoken; +#endif + PIOS_EXTI_HANDLE_LINE(5, xHigherPriorityTaskWoken); + PIOS_EXTI_HANDLE_LINE(6, xHigherPriorityTaskWoken); + PIOS_EXTI_HANDLE_LINE(7, xHigherPriorityTaskWoken); + PIOS_EXTI_HANDLE_LINE(8, xHigherPriorityTaskWoken); + PIOS_EXTI_HANDLE_LINE(9, xHigherPriorityTaskWoken); +#ifdef PIOS_INCLUDE_FREERTOS + portEND_SWITCHING_ISR(xHigherPriorityTaskWoken); +#endif +} +void EXTI9_5_IRQHandler(void) __attribute__((alias("PIOS_EXTI_9_5_irq_handler"))); + +static void PIOS_EXTI_15_10_irq_handler(void) +{ +#ifdef PIOS_INCLUDE_FREERTOS + portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; +#else + bool xHigherPriorityTaskWoken; +#endif + PIOS_EXTI_HANDLE_LINE(10, xHigherPriorityTaskWoken); + PIOS_EXTI_HANDLE_LINE(11, xHigherPriorityTaskWoken); + PIOS_EXTI_HANDLE_LINE(12, xHigherPriorityTaskWoken); + PIOS_EXTI_HANDLE_LINE(13, xHigherPriorityTaskWoken); + PIOS_EXTI_HANDLE_LINE(14, xHigherPriorityTaskWoken); + PIOS_EXTI_HANDLE_LINE(15, xHigherPriorityTaskWoken); +#ifdef PIOS_INCLUDE_FREERTOS + portEND_SWITCHING_ISR(xHigherPriorityTaskWoken); +#endif +} +void EXTI15_10_IRQHandler(void) __attribute__((alias("PIOS_EXTI_15_10_irq_handler"))); + +#endif /* PIOS_INCLUDE_EXTI */ + +/** + * @} + * @} + */ diff --git a/flight/pios/stm32f30x/pios_flash_internal.c b/flight/pios/stm32f30x/pios_flash_internal.c new file mode 100644 index 0000000000..9c1132664a --- /dev/null +++ b/flight/pios/stm32f30x/pios_flash_internal.c @@ -0,0 +1,304 @@ +/** + ****************************************************************************** + * + * @file pios_flash_internal.c + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2013. + * @brief brief goes here. + * -- + * @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.h" + +#ifdef PIOS_INCLUDE_FLASH_INTERNAL + +#include "stm32f30x_flash.h" +#include "pios_flash_internal_priv.h" +#include "pios_flash.h" +#include + +struct device_flash_sector { + uint32_t start; + uint32_t size; + uint16_t st_sector; +}; + +static bool PIOS_Flash_Internal_GetSectorInfo(uint32_t address, uint8_t *sector_number, uint32_t *sector_start, uint32_t *sector_size) +{ + uint16_t sector = (address - 0x08000000) / 2048; + + if (sector <= 127) { + /* address lies within this sector */ + *sector_number = sector; + *sector_start = sector * 2048 + 0x08000000; + *sector_size = 2048; + return true; + } + + return false; +} + +enum pios_internal_flash_dev_magic { + PIOS_INTERNAL_FLASH_DEV_MAGIC = 0x33445902, +}; + +struct pios_internal_flash_dev { + enum pios_internal_flash_dev_magic magic; + +#if defined(PIOS_INCLUDE_FREERTOS) + xSemaphoreHandle transaction_lock; +#endif /* defined(PIOS_INCLUDE_FREERTOS) */ +}; + +static bool PIOS_Flash_Internal_Validate(struct pios_internal_flash_dev *flash_dev) +{ + return flash_dev && (flash_dev->magic == PIOS_INTERNAL_FLASH_DEV_MAGIC); +} + +#if defined(PIOS_INCLUDE_FREERTOS) +static struct pios_internal_flash_dev *PIOS_Flash_Internal_alloc(void) +{ + struct pios_internal_flash_dev *flash_dev; + + flash_dev = (struct pios_internal_flash_dev *)pios_malloc(sizeof(*flash_dev)); + if (!flash_dev) { + return NULL; + } + + flash_dev->magic = PIOS_INTERNAL_FLASH_DEV_MAGIC; + + return flash_dev; +} +#else +static struct pios_internal_flash_dev pios_internal_flash_devs[PIOS_INTERNAL_FLASH_MAX_DEVS]; +static uint8_t pios_internal_flash_num_devs; +static struct pios_internal_flash_dev *PIOS_Flash_Internal_alloc(void) +{ + struct pios_internal_flash_dev *flash_dev; + + if (pios_internal_flash_num_devs >= PIOS_INTERNAL_FLASH_MAX_DEVS) { + return NULL; + } + + flash_dev = &pios_internal_flash_devs[pios_internal_flash_num_devs++]; + flash_dev->magic = PIOS_INTERNAL_FLASH_DEV_MAGIC; + + return flash_dev; +} + +#endif /* defined(PIOS_INCLUDE_FREERTOS) */ + +int32_t PIOS_Flash_Internal_Init(uintptr_t *flash_id, __attribute__((unused)) const struct pios_flash_internal_cfg *cfg) +{ + struct pios_internal_flash_dev *flash_dev; + + flash_dev = PIOS_Flash_Internal_alloc(); + if (flash_dev == NULL) { + return -1; + } + +#if defined(PIOS_INCLUDE_FREERTOS) + flash_dev->transaction_lock = xSemaphoreCreateMutex(); +#endif /* defined(PIOS_INCLUDE_FREERTOS) */ + + *flash_id = (uintptr_t)flash_dev; + + return 0; +} + +/********************************** + * + * Provide a PIOS flash driver API + * + *********************************/ +#include "pios_flash.h" + +static int32_t PIOS_Flash_Internal_StartTransaction(uintptr_t flash_id) +{ + struct pios_internal_flash_dev *flash_dev = (struct pios_internal_flash_dev *)flash_id; + + if (!PIOS_Flash_Internal_Validate(flash_dev)) { + return -1; + } + +#if defined(PIOS_INCLUDE_FREERTOS) + if (xSemaphoreTake(flash_dev->transaction_lock, portMAX_DELAY) != pdTRUE) { + return -2; + } +#endif /* defined(PIOS_INCLUDE_FREERTOS) */ + + /* Unlock the internal flash so we can write to it */ + FLASH_Unlock(); + return 0; +} + +static int32_t PIOS_Flash_Internal_EndTransaction(uintptr_t flash_id) +{ + struct pios_internal_flash_dev *flash_dev = (struct pios_internal_flash_dev *)flash_id; + + if (!PIOS_Flash_Internal_Validate(flash_dev)) { + return -1; + } + +#if defined(PIOS_INCLUDE_FREERTOS) + if (xSemaphoreGive(flash_dev->transaction_lock) != pdTRUE) { + return -2; + } +#endif /* defined(PIOS_INCLUDE_FREERTOS) */ + + /* Lock the internal flash again so we can no longer write to it */ + FLASH_Lock(); + + return 0; +} + +static int32_t PIOS_Flash_Internal_EraseSector(uintptr_t flash_id, uint32_t addr) +{ + struct pios_internal_flash_dev *flash_dev = (struct pios_internal_flash_dev *)flash_id; + + if (!PIOS_Flash_Internal_Validate(flash_dev)) { + return -1; + } + + uint8_t sector_number; + uint32_t sector_start; + uint32_t sector_size; + if (!PIOS_Flash_Internal_GetSectorInfo(addr, + §or_number, + §or_start, + §or_size)) { + /* We're asking for an invalid flash address */ + return -2; + } + + if (FLASH_ErasePage(sector_start) != FLASH_COMPLETE) { + return -3; + } + + return 0; +} + +static int32_t PIOS_Flash_Internal_WriteData(uintptr_t flash_id, uint32_t addr, uint8_t *data, uint16_t len) +{ + PIOS_Assert(data); + + struct pios_internal_flash_dev *flash_dev = (struct pios_internal_flash_dev *)flash_id; + + if (!PIOS_Flash_Internal_Validate(flash_dev)) { + return -1; + } + + uint8_t sector_number; + uint32_t sector_start; + uint32_t sector_size; + uint32_t hword_data; + uint32_t offset; + + /* Ensure that the base address is in a valid sector */ + if (!PIOS_Flash_Internal_GetSectorInfo(addr, + §or_number, + §or_start, + §or_size)) { + /* We're asking for an invalid flash address */ + return -2; + } + + /* Ensure that the entire write occurs within the same sector */ + if ((uintptr_t)addr + len > sector_start + sector_size) { + /* Write crosses the end of the sector */ + return -3; + } + + /* Write the data */ + uint32_t temp_addr = addr; + uint16_t numberOfhWords = len / 2; + uint16_t x = 0; + FLASH_Status status; + for (x = 0; x < numberOfhWords; ++x) { + offset = 2 * x; + hword_data = (data[offset + 1] << 8) | data[offset]; + + if (hword_data != *(uint16_t *)(temp_addr + offset)) { + status = FLASH_ProgramHalfWord(temp_addr + offset, hword_data); + } else { + status = FLASH_COMPLETE; + } + PIOS_Assert(status == FLASH_COMPLETE); + } + + uint16_t mod = len % 2; + if (mod == 1) { + offset = 2 * x; + hword_data = 0xFF00 | data[offset]; + if (hword_data != *(uint16_t *)(temp_addr + offset)) { + status = FLASH_ProgramHalfWord(temp_addr + offset, hword_data); + } else { + status = FLASH_COMPLETE; + } + PIOS_Assert(status == FLASH_COMPLETE); + } + + return 0; +} + +static int32_t PIOS_Flash_Internal_ReadData(uintptr_t flash_id, uint32_t addr, uint8_t *data, uint16_t len) +{ + PIOS_Assert(data); + + struct pios_internal_flash_dev *flash_dev = (struct pios_internal_flash_dev *)flash_id; + + if (!PIOS_Flash_Internal_Validate(flash_dev)) { + return -1; + } + + uint8_t sector_number; + uint32_t sector_start; + uint32_t sector_size; + + /* Ensure that the base address is in a valid sector */ + if (!PIOS_Flash_Internal_GetSectorInfo(addr, + §or_number, + §or_start, + §or_size)) { + /* We're asking for an invalid flash address */ + return -2; + } + + /* Ensure that the entire read occurs within the same sector */ + if ((uintptr_t)addr + len > sector_start + sector_size) { + /* Read crosses the end of the sector */ + return -3; + } + + /* Read the data into the buffer directly */ + memcpy(data, (void *)addr, len); + + return 0; +} + +/* Provide a flash driver to external drivers */ +const struct pios_flash_driver pios_internal_flash_driver = { + .start_transaction = PIOS_Flash_Internal_StartTransaction, + .end_transaction = PIOS_Flash_Internal_EndTransaction, + .erase_sector = PIOS_Flash_Internal_EraseSector, + .write_data = PIOS_Flash_Internal_WriteData, + .read_data = PIOS_Flash_Internal_ReadData, +}; + +#endif /* PIOS_INCLUDE_FLASH_INTERNAL */ diff --git a/flight/pios/stm32f30x/pios_gpio.c b/flight/pios/stm32f30x/pios_gpio.c new file mode 100644 index 0000000000..b87ed6e0a4 --- /dev/null +++ b/flight/pios/stm32f30x/pios_gpio.c @@ -0,0 +1,170 @@ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_GPIO GPIO Functions + * @brief STM32 Hardware GPIO handling code + * @{ + * + * @file pios_gpio.c + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012. + * @brief GPIO functions, init, toggle, on & off. + * @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.h" + +#ifdef PIOS_INCLUDE_GPIO + +#include + +/** + * Initialises all the GPIO's + */ +int32_t PIOS_GPIO_Init(uint32_t *gpios_dev_id, const struct pios_gpio_cfg *cfg) +{ + PIOS_Assert(cfg); + *gpios_dev_id = (uint32_t)cfg; + + for (uint8_t i = 0; i < cfg->num_gpios; i++) { + const struct pios_gpio *gpio = &(cfg->gpios[i]); + + /* Enable the peripheral clock for the GPIO */ + switch ((uint32_t)gpio->pin.gpio) { + case (uint32_t)GPIOA: + RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE); + break; + case (uint32_t)GPIOB: + RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE); + break; + case (uint32_t)GPIOC: + RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE); + break; + case (uint32_t)GPIOD: + RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOD, ENABLE); + break; + case (uint32_t)GPIOE: + RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOE, ENABLE); + break; + case (uint32_t)GPIOF: + RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOF, ENABLE); + break; + default: + PIOS_Assert(0); + break; + } + + if (gpio->remap) { + GPIO_PinAFConfig(gpio->pin.gpio, gpio->pin.init.GPIO_Pin, gpio->remap); + } + + GPIO_Init(gpio->pin.gpio, &((struct pios_gpio *)gpio)->pin.init); + + PIOS_GPIO_Off(*gpios_dev_id, i); + } + + return 0; +} + +/** + * Turn on GPIO + * \param[in] GPIO GPIO id + */ +void PIOS_GPIO_On(uint32_t gpios_dev_id, uint8_t gpio_id) +{ + const struct pios_gpio_cfg *gpio_cfg = (const struct pios_gpio_cfg *)gpios_dev_id; + + PIOS_Assert(gpio_cfg); + + if (gpio_id >= gpio_cfg->num_gpios) { + /* GPIO index out of range */ + return; + } + + const struct pios_gpio *gpio = &(gpio_cfg->gpios[gpio_id]); + + if (gpio->active_low) { + GPIO_ResetBits(gpio->pin.gpio, gpio->pin.init.GPIO_Pin); + } else { + GPIO_SetBits(gpio->pin.gpio, gpio->pin.init.GPIO_Pin); + } +} + +/** + * Turn off GPIO + * \param[in] GPIO GPIO id + */ +void PIOS_GPIO_Off(uint32_t gpios_dev_id, uint8_t gpio_id) +{ + const struct pios_gpio_cfg *gpio_cfg = (const struct pios_gpio_cfg *)gpios_dev_id; + + PIOS_Assert(gpio_cfg); + + if (gpio_id >= gpio_cfg->num_gpios) { + /* GPIO index out of range */ + return; + } + + const struct pios_gpio *gpio = &(gpio_cfg->gpios[gpio_id]); + + if (gpio->active_low) { + GPIO_SetBits(gpio->pin.gpio, gpio->pin.init.GPIO_Pin); + } else { + GPIO_ResetBits(gpio->pin.gpio, gpio->pin.init.GPIO_Pin); + } +} + +/** + * Toggle GPIO on/off + * \param[in] GPIO GPIO id + */ +void PIOS_GPIO_Toggle(uint32_t gpios_dev_id, uint8_t gpio_id) +{ + const struct pios_gpio_cfg *gpio_cfg = (const struct pios_gpio_cfg *)gpios_dev_id; + + PIOS_Assert(gpio_cfg); + + if (gpio_id >= gpio_cfg->num_gpios) { + /* GPIO index out of range */ + return; + } + + const struct pios_gpio *gpio = &(gpio_cfg->gpios[gpio_id]); + + if (GPIO_ReadOutputDataBit(gpio->pin.gpio, gpio->pin.init.GPIO_Pin) == Bit_SET) { + if (gpio->active_low) { + PIOS_GPIO_On(gpios_dev_id, gpio_id); + } else { + PIOS_GPIO_Off(gpios_dev_id, gpio_id); + } + } else { + if (gpio->active_low) { + PIOS_GPIO_Off(gpios_dev_id, gpio_id); + } else { + PIOS_GPIO_On(gpios_dev_id, gpio_id); + } + } +} + +#endif /* PIOS_INCLUDE_GPIO */ + +/** + * @} + * @} + */ diff --git a/flight/pios/stm32f30x/pios_i2c.c b/flight/pios/stm32f30x/pios_i2c.c new file mode 100644 index 0000000000..583ddb4562 --- /dev/null +++ b/flight/pios/stm32f30x/pios_i2c.c @@ -0,0 +1,924 @@ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_I2C I2C Functions + * @brief STM32F4xx Hardware dependent I2C functionality + * @{ + * + * @file pios_i2c.c + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012. + * @author Tau Labs, http://taulabs.org, Copyright (C) 2012-2014 + * @author dRonin, http://dronin.org, Copyright (C) 2016 + * @brief I2C Enable/Disable routines + * @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 + */ + +/* Project Includes */ +#include "pios.h" + +#if defined(PIOS_INCLUDE_I2C) + +#if defined(PIOS_INCLUDE_FREERTOS) +#define USE_FREERTOS +#endif + +#include + +enum i2c_adapter_state { + I2C_STATE_FSM_FAULT = 0, /* Must be zero so undefined transitions land here */ + + I2C_STATE_BUS_ERROR, + + I2C_STATE_STOPPED, + I2C_STATE_STOPPING, + I2C_STATE_STARTING, + + I2C_STATE_R_MORE_TXN_ADDR, + I2C_STATE_R_MORE_TXN_PRE_ONE, + I2C_STATE_R_MORE_TXN_PRE_FIRST, + I2C_STATE_R_MORE_TXN_PRE_MIDDLE, + I2C_STATE_R_MORE_TXN_PRE_LAST, + I2C_STATE_R_MORE_TXN_POST_LAST, + + I2C_STATE_R_LAST_TXN_ADDR, + I2C_STATE_R_LAST_TXN_PRE_ONE, + I2C_STATE_R_LAST_TXN_PRE_FIRST, + I2C_STATE_R_LAST_TXN_PRE_MIDDLE, + I2C_STATE_R_LAST_TXN_PRE_LAST, + I2C_STATE_R_LAST_TXN_POST_LAST, + + I2C_STATE_W_MORE_TXN_ADDR, + I2C_STATE_W_MORE_TXN_MIDDLE, + I2C_STATE_W_MORE_TXN_LAST, + + I2C_STATE_W_LAST_TXN_ADDR, + I2C_STATE_W_LAST_TXN_MIDDLE, + I2C_STATE_W_LAST_TXN_LAST, + + I2C_STATE_NACK, + + I2C_STATE_NUM_STATES /* Must be last */ +}; + +enum i2c_adapter_event { + I2C_EVENT_START, + I2C_EVENT_RECEIVER_BUFFER_NOT_EMPTY, + I2C_EVENT_TRANSMIT_BUFFER_EMPTY, + I2C_EVENT_TRANSFER_COMPLETE, + I2C_EVENT_STOP, + I2C_EVENT_NACK, + I2C_EVENT_BUS_ERROR, + I2C_EVENT_STOPPED, + I2C_EVENT_AUTO, + + I2C_EVENT_NUM_EVENTS /* Must be last */ +}; + +/* dirty hack to keep compatible with enum in pios_i2c_priv.h */ +#define I2C_STATE_WRITE_BYTE I2C_STATE_W_MORE_TXN_ADDR +#define I2C_STATE_READ_BYTE I2C_STATE_W_MORE_TXN_MIDDLE +#define I2C_STATE_TRANSFER_COMPLETE I2C_STATE_W_MORE_TXN_LAST + +// #define I2C_HALT_ON_ERRORS + +#if defined(PIOS_I2C_DIAGNOSTICS) +static struct pios_i2c_fault_history i2c_adapter_fault_history; + +static volatile uint32_t i2c_evirq_history[I2C_LOG_DEPTH]; +static volatile uint8_t i2c_evirq_history_pointer; + +static volatile uint32_t i2c_erirq_history[I2C_LOG_DEPTH]; +static volatile uint8_t i2c_erirq_history_pointer; + +static volatile uint8_t i2c_state_history[I2C_LOG_DEPTH]; +static volatile uint8_t i2c_state_history_pointer; + +static volatile uint8_t i2c_state_event_history[I2C_LOG_DEPTH]; +static volatile uint8_t i2c_state_event_history_pointer; + +static uint32_t i2c_fsm_fault_count; +static uint32_t i2c_bad_event_counter; +static uint32_t i2c_error_interrupt_counter; +static uint32_t i2c_nack_counter; +static uint32_t i2c_timeout_counter; +#endif + +static void go_fsm_fault(struct pios_i2c_adapter *i2c_adapter, bool *woken); +static void go_bus_error(struct pios_i2c_adapter *i2c_adapter, bool *woken); +static void go_stopped(struct pios_i2c_adapter *i2c_adapter, bool *woken); +static void go_starting(struct pios_i2c_adapter *i2c_adapter, bool *woken); +static void go_write_byte(struct pios_i2c_adapter *i2c_adapter, bool *woken); +static void go_read_byte(struct pios_i2c_adapter *i2c_adapter, bool *woken); +static void go_transfer_complete(struct pios_i2c_adapter *i2c_adapter, bool *woken); +static void go_nack(struct pios_i2c_adapter *i2c_adapter, bool *woken); + +struct i2c_adapter_transition { + void (*entry_fn)(struct pios_i2c_adapter *i2c_adapter, bool *woken); + enum i2c_adapter_state next_state[I2C_EVENT_NUM_EVENTS]; +}; + +static void i2c_adapter_process_auto(struct pios_i2c_adapter *i2c_adapter, bool *woken); +static void i2c_adapter_inject_event(struct pios_i2c_adapter *i2c_adapter, enum i2c_adapter_event event, bool *woken); +static void i2c_adapter_fsm_init(struct pios_i2c_adapter *i2c_adapter); +static void i2c_adapter_reset_bus(struct pios_i2c_adapter *i2c_adapter); +static bool i2c_adapter_callback_handler(struct pios_i2c_adapter *i2c_adapter, bool *woken); + +#if defined(PIOS_I2C_DIAGNOSTICS) +static void i2c_adapter_log_fault(struct pios_i2c_adapter *i2c_adapter, enum pios_i2c_error_type type); +#endif + +static const struct i2c_adapter_transition i2c_adapter_transitions[I2C_STATE_NUM_STATES] = { + [I2C_STATE_FSM_FAULT] = { + .entry_fn = go_fsm_fault, + .next_state = { + [I2C_EVENT_AUTO] = I2C_STATE_STOPPED, + }, + }, + [I2C_STATE_BUS_ERROR] = { + .entry_fn = go_bus_error, + .next_state = { + [I2C_EVENT_AUTO] = I2C_STATE_STOPPED, + }, + }, + + [I2C_STATE_STOPPED] = { + .entry_fn = go_stopped, + .next_state = { + [I2C_EVENT_START] = I2C_STATE_STARTING, + [I2C_EVENT_BUS_ERROR] = I2C_STATE_BUS_ERROR, + }, + }, + + [I2C_STATE_STARTING] = { + .entry_fn = go_starting, + .next_state = { + [I2C_EVENT_TRANSMIT_BUFFER_EMPTY] = I2C_STATE_WRITE_BYTE, + [I2C_EVENT_RECEIVER_BUFFER_NOT_EMPTY] = I2C_STATE_READ_BYTE, + [I2C_EVENT_NACK] = I2C_STATE_NACK, + [I2C_EVENT_BUS_ERROR] = I2C_STATE_BUS_ERROR, + }, + }, + + [I2C_STATE_WRITE_BYTE] = { + .entry_fn = go_write_byte, + .next_state = { + [I2C_EVENT_TRANSMIT_BUFFER_EMPTY] = I2C_STATE_WRITE_BYTE, + [I2C_EVENT_RECEIVER_BUFFER_NOT_EMPTY] = I2C_STATE_READ_BYTE, + [I2C_EVENT_TRANSFER_COMPLETE] = I2C_STATE_TRANSFER_COMPLETE, + [I2C_EVENT_STOP] = I2C_STATE_STOPPED, + [I2C_EVENT_BUS_ERROR] = I2C_STATE_BUS_ERROR, + }, + }, + + [I2C_STATE_READ_BYTE] = { + .entry_fn = go_read_byte, + .next_state = { + [I2C_EVENT_TRANSMIT_BUFFER_EMPTY] = I2C_STATE_WRITE_BYTE, + [I2C_EVENT_RECEIVER_BUFFER_NOT_EMPTY] = I2C_STATE_READ_BYTE, + [I2C_EVENT_TRANSFER_COMPLETE] = I2C_STATE_TRANSFER_COMPLETE, + [I2C_EVENT_STOP] = I2C_STATE_STOPPED, + [I2C_EVENT_BUS_ERROR] = I2C_STATE_BUS_ERROR, + }, + }, + + [I2C_STATE_TRANSFER_COMPLETE] = { + .entry_fn = go_transfer_complete, + .next_state = { + [I2C_EVENT_AUTO] = I2C_STATE_STARTING, + [I2C_EVENT_BUS_ERROR] = I2C_STATE_BUS_ERROR, + }, + }, + + [I2C_STATE_NACK] = { + .entry_fn = go_nack, + .next_state = { + [I2C_EVENT_AUTO] = I2C_STATE_STOPPED, + }, + }, +}; + +static void go_fsm_fault(struct pios_i2c_adapter *i2c_adapter, __attribute__((unused)) bool *woken) +{ +#if defined(I2C_HALT_ON_ERRORS) + PIOS_DEBUG_Assert(0); +#endif + /* Note that this transfer has hit a bus error */ + i2c_adapter->bus_error = true; + + i2c_adapter_reset_bus(i2c_adapter); +} + +static void go_bus_error(struct pios_i2c_adapter *i2c_adapter, __attribute__((unused)) bool *woken) +{ + /* Note that this transfer has hit a bus error */ + i2c_adapter->bus_error = true; + + i2c_adapter_reset_bus(i2c_adapter); +} + +static void go_stopped(struct pios_i2c_adapter *i2c_adapter, bool *woken) +{ + I2C_ITConfig(i2c_adapter->cfg->regs, I2C_IT_ERRI | I2C_IT_TCI | I2C_IT_NACKI | I2C_IT_RXI | I2C_IT_STOPI | I2C_IT_TXI, DISABLE); + + if (i2c_adapter->callback) { + i2c_adapter_callback_handler(i2c_adapter, woken); + } else { +#ifdef USE_FREERTOS + signed portBASE_TYPE pxHigherPriorityTaskWoken = pdFALSE; + if (xSemaphoreGiveFromISR(i2c_adapter->sem_ready, &pxHigherPriorityTaskWoken) != pdTRUE) { +#if defined(I2C_HALT_ON_ERRORS) + PIOS_DEBUG_Assert(0); +#endif + } + if (pxHigherPriorityTaskWoken == pdTRUE) { + *woken = true; + } +#endif /* USE_FREERTOS */ + } +} + +static void go_starting(struct pios_i2c_adapter *i2c_adapter, __attribute__((unused)) bool *woken) +{ + PIOS_DEBUG_Assert(i2c_adapter->active_txn); + PIOS_DEBUG_Assert(i2c_adapter->active_txn <= i2c_adapter->last_txn); + PIOS_DEBUG_Assert(i2c_adapter->active_txn->len <= 255); // FIXME: implement this using TCR + + i2c_adapter->active_byte = &(i2c_adapter->active_txn->buf[0]); + i2c_adapter->last_byte = &(i2c_adapter->active_txn->buf[i2c_adapter->active_txn->len - 1]); + + I2C_ITConfig(i2c_adapter->cfg->regs, I2C_IT_ERRI | I2C_IT_TCI | I2C_IT_NACKI | I2C_IT_RXI | I2C_IT_STOPI | I2C_IT_TXI, ENABLE); + + I2C_TransferHandling( + i2c_adapter->cfg->regs, + (i2c_adapter->active_txn->addr << 1), + i2c_adapter->active_txn->len, + i2c_adapter->active_txn == i2c_adapter->last_txn ? I2C_AutoEnd_Mode : I2C_SoftEnd_Mode, + i2c_adapter->active_txn->rw == PIOS_I2C_TXN_WRITE ? I2C_Generate_Start_Write : I2C_Generate_Start_Read); +} + +static void go_write_byte(struct pios_i2c_adapter *i2c_adapter, __attribute__((unused)) bool *woken) +{ + PIOS_DEBUG_Assert(i2c_adapter->active_txn); + PIOS_DEBUG_Assert(i2c_adapter->active_txn <= i2c_adapter->last_txn); + + I2C_SendData(i2c_adapter->cfg->regs, *(i2c_adapter->active_byte)); + + /* Move to the next byte */ + i2c_adapter->active_byte++; + PIOS_DEBUG_Assert(i2c_adapter->active_byte <= i2c_adapter->last_byte); +} + +static void go_read_byte(struct pios_i2c_adapter *i2c_adapter, __attribute__((unused)) bool *woken) +{ + PIOS_DEBUG_Assert(i2c_adapter->active_txn); + PIOS_DEBUG_Assert(i2c_adapter->active_txn <= i2c_adapter->last_txn); + + *(i2c_adapter->active_byte) = I2C_ReceiveData(i2c_adapter->cfg->regs); + + /* Move to the next byte */ + i2c_adapter->active_byte++; + PIOS_DEBUG_Assert(i2c_adapter->active_byte <= i2c_adapter->last_byte); +} + +static void go_transfer_complete(struct pios_i2c_adapter *i2c_adapter, __attribute__((unused)) bool *woken) +{ + /* Move to the next transaction */ + i2c_adapter->active_txn++; + PIOS_DEBUG_Assert(i2c_adapter->active_txn <= i2c_adapter->last_txn); +} + +static void go_nack(struct pios_i2c_adapter *i2c_adapter, __attribute__((unused)) bool *woken) +{ + i2c_adapter->nack = true; + I2C_ITConfig(i2c_adapter->cfg->regs, I2C_IT_ERRI | I2C_IT_TCI | I2C_IT_NACKI | I2C_IT_RXI | I2C_IT_STOPI | I2C_IT_TXI, DISABLE); + I2C_AcknowledgeConfig(i2c_adapter->cfg->regs, DISABLE); + I2C_GenerateSTOP(i2c_adapter->cfg->regs, ENABLE); +} + +static void i2c_adapter_inject_event(struct pios_i2c_adapter *i2c_adapter, enum i2c_adapter_event event, bool *woken) +{ +#if defined(PIOS_I2C_DIAGNOSTICS) + i2c_state_event_history[i2c_state_event_history_pointer] = event; + i2c_state_event_history_pointer = (i2c_state_event_history_pointer + 1) % I2C_LOG_DEPTH; + + i2c_state_history[i2c_state_history_pointer] = i2c_adapter->curr_state; + i2c_state_history_pointer = (i2c_state_history_pointer + 1) % I2C_LOG_DEPTH; + + if (i2c_adapter_transitions[i2c_adapter->curr_state].next_state[event] == I2C_STATE_FSM_FAULT) { + i2c_adapter_log_fault(i2c_adapter, PIOS_I2C_ERROR_FSM); + } +#endif + /* + * Move to the next state + * + * This is done prior to calling the new state's entry function to + * guarantee that the entry function never depends on the previous + * state. This way, it cannot ever know what the previous state was. + */ + enum i2c_adapter_state prev_state = i2c_adapter->curr_state; + if (prev_state) { + ; + } + + i2c_adapter->curr_state = i2c_adapter_transitions[i2c_adapter->curr_state].next_state[event]; + + /* Call the entry function (if any) for the next state. */ + if (i2c_adapter_transitions[i2c_adapter->curr_state].entry_fn) { + i2c_adapter_transitions[i2c_adapter->curr_state].entry_fn(i2c_adapter, woken); + } + + /* Process any AUTO transitions in the FSM */ + i2c_adapter_process_auto(i2c_adapter, woken); +} + +static void i2c_adapter_process_auto(struct pios_i2c_adapter *i2c_adapter, bool *woken) +{ + enum i2c_adapter_state prev_state = i2c_adapter->curr_state; + + if (prev_state) { + ; + } + + while (i2c_adapter_transitions[i2c_adapter->curr_state].next_state[I2C_EVENT_AUTO]) { + i2c_adapter->curr_state = i2c_adapter_transitions[i2c_adapter->curr_state].next_state[I2C_EVENT_AUTO]; + + /* Call the entry function (if any) for the next state. */ + if (i2c_adapter_transitions[i2c_adapter->curr_state].entry_fn) { + i2c_adapter_transitions[i2c_adapter->curr_state].entry_fn(i2c_adapter, woken); + } + } +} + +static void i2c_adapter_fsm_init(struct pios_i2c_adapter *i2c_adapter) +{ + i2c_adapter_reset_bus(i2c_adapter); + i2c_adapter->curr_state = I2C_STATE_STOPPED; +} + +static void i2c_adapter_reset_bus(struct pios_i2c_adapter *i2c_adapter) +{ + uint8_t retry_count = 0; + uint8_t retry_count_clk = 0; + static const uint8_t MAX_I2C_RETRY_COUNT = 10; + + /* Reset the I2C block */ + I2C_DeInit(i2c_adapter->cfg->regs); + + /* Make sure the bus is free by clocking it until any slaves release the bus. */ + GPIO_InitTypeDef scl_gpio_init; + scl_gpio_init = i2c_adapter->cfg->scl.init; + scl_gpio_init.GPIO_Mode = GPIO_Mode_OUT; + GPIO_SetBits(i2c_adapter->cfg->scl.gpio, i2c_adapter->cfg->scl.init.GPIO_Pin); + GPIO_Init(i2c_adapter->cfg->scl.gpio, &scl_gpio_init); + + GPIO_InitTypeDef sda_gpio_init; + sda_gpio_init = i2c_adapter->cfg->sda.init; + sda_gpio_init.GPIO_Mode = GPIO_Mode_OUT; + GPIO_SetBits(i2c_adapter->cfg->sda.gpio, i2c_adapter->cfg->sda.init.GPIO_Pin); + GPIO_Init(i2c_adapter->cfg->sda.gpio, &sda_gpio_init); + + /* Check SDA line to determine if slave is asserting bus and clock out if so, this may */ + /* have to be repeated (due to further bus errors) but better than clocking 0xFF into an */ + /* ESC */ + + retry_count_clk = 0; + while (GPIO_ReadInputDataBit(i2c_adapter->cfg->sda.gpio, i2c_adapter->cfg->sda.init.GPIO_Pin) == Bit_RESET && (retry_count_clk++ < MAX_I2C_RETRY_COUNT)) { + retry_count = 0; + /* Set clock high and wait for any clock stretching to finish. */ + GPIO_SetBits(i2c_adapter->cfg->scl.gpio, i2c_adapter->cfg->scl.init.GPIO_Pin); + while (GPIO_ReadInputDataBit(i2c_adapter->cfg->scl.gpio, i2c_adapter->cfg->scl.init.GPIO_Pin) == Bit_RESET && (retry_count++ < MAX_I2C_RETRY_COUNT)) { + PIOS_DELAY_WaituS(1); + } + + PIOS_DELAY_WaituS(2); + + /* Set clock low */ + GPIO_ResetBits(i2c_adapter->cfg->scl.gpio, i2c_adapter->cfg->scl.init.GPIO_Pin); + PIOS_DELAY_WaituS(2); + + /* Clock high again */ + GPIO_SetBits(i2c_adapter->cfg->scl.gpio, i2c_adapter->cfg->scl.init.GPIO_Pin); + PIOS_DELAY_WaituS(2); + } + + /* Generate a start then stop condition */ + GPIO_SetBits(i2c_adapter->cfg->scl.gpio, i2c_adapter->cfg->scl.init.GPIO_Pin); + PIOS_DELAY_WaituS(2); + GPIO_ResetBits(i2c_adapter->cfg->sda.gpio, i2c_adapter->cfg->sda.init.GPIO_Pin); + PIOS_DELAY_WaituS(2); + GPIO_ResetBits(i2c_adapter->cfg->sda.gpio, i2c_adapter->cfg->sda.init.GPIO_Pin); + PIOS_DELAY_WaituS(2); + + /* Set data and clock high and wait for any clock stretching to finish. */ + GPIO_SetBits(i2c_adapter->cfg->sda.gpio, i2c_adapter->cfg->sda.init.GPIO_Pin); + GPIO_SetBits(i2c_adapter->cfg->scl.gpio, i2c_adapter->cfg->scl.init.GPIO_Pin); + + retry_count = 0; + while (GPIO_ReadInputDataBit(i2c_adapter->cfg->scl.gpio, i2c_adapter->cfg->scl.init.GPIO_Pin) == Bit_RESET && (retry_count++ < MAX_I2C_RETRY_COUNT)) { + PIOS_DELAY_WaituS(1); + } + + /* Wait for data to be high */ + retry_count = 0; + while (GPIO_ReadInputDataBit(i2c_adapter->cfg->sda.gpio, i2c_adapter->cfg->sda.init.GPIO_Pin) != Bit_SET && (retry_count++ < MAX_I2C_RETRY_COUNT)) { + PIOS_DELAY_WaituS(1); + } + + /* Bus signals are guaranteed to be high (ie. free) after this point */ + /* Initialize the GPIO pins to the peripheral function */ + if (i2c_adapter->cfg->remapSCL) { + GPIO_PinAFConfig(i2c_adapter->cfg->scl.gpio, + __builtin_ctz(i2c_adapter->cfg->scl.init.GPIO_Pin), + i2c_adapter->cfg->remapSCL); + } + if (i2c_adapter->cfg->remapSDA) { + GPIO_PinAFConfig(i2c_adapter->cfg->sda.gpio, + __builtin_ctz(i2c_adapter->cfg->sda.init.GPIO_Pin), + i2c_adapter->cfg->remapSDA); + } + GPIO_Init(i2c_adapter->cfg->scl.gpio, (GPIO_InitTypeDef *)&(i2c_adapter->cfg->scl.init)); // Struct is const, function signature not + GPIO_Init(i2c_adapter->cfg->sda.gpio, (GPIO_InitTypeDef *)&(i2c_adapter->cfg->sda.init)); + + RCC_I2CCLKConfig(i2c_adapter->cfg->regs == I2C2 ? RCC_I2C2CLK_SYSCLK : RCC_I2C1CLK_SYSCLK); + + /* Reset the I2C block */ + I2C_DeInit(i2c_adapter->cfg->regs); + + /* Initialize the I2C block */ + I2C_Init(i2c_adapter->cfg->regs, (I2C_InitTypeDef *)&(i2c_adapter->cfg->init)); + + /* Enable the I2C block */ + I2C_Cmd(i2c_adapter->cfg->regs, ENABLE); + + if (I2C_GetFlagStatus(i2c_adapter->cfg->regs, I2C_FLAG_BUSY)) { + I2C_SoftwareResetCmd(i2c_adapter->cfg->regs); + } +} + +/** + * Logs the last N state transitions and N IRQ events due to + * an error condition + * \param[in] i2c the adapter number to log an event for + */ +#if defined(PIOS_I2C_DIAGNOSTICS) +void i2c_adapter_log_fault(__attribute__((unused)) struct pios_i2c_adapter *i2c_adapter, enum pios_i2c_error_type type) +{ + i2c_adapter_fault_history.type = type; + for (uint8_t i = 0; i < I2C_LOG_DEPTH; i++) { + i2c_adapter_fault_history.evirq[i] = + i2c_evirq_history[(I2C_LOG_DEPTH + i2c_evirq_history_pointer - 1 - i) % I2C_LOG_DEPTH]; + i2c_adapter_fault_history.erirq[i] = + i2c_erirq_history[(I2C_LOG_DEPTH + i2c_erirq_history_pointer - 1 - i) % I2C_LOG_DEPTH]; + i2c_adapter_fault_history.event[i] = + i2c_state_event_history[(I2C_LOG_DEPTH + i2c_state_event_history_pointer - 1 - i) % I2C_LOG_DEPTH]; + i2c_adapter_fault_history.state[i] = + i2c_state_history[(I2C_LOG_DEPTH + i2c_state_history_pointer - 1 - i) % I2C_LOG_DEPTH]; + } + switch (type) { + case PIOS_I2C_ERROR_EVENT: + i2c_bad_event_counter++; + break; + case PIOS_I2C_ERROR_FSM: + i2c_fsm_fault_count++; + break; + case PIOS_I2C_ERROR_INTERRUPT: + i2c_error_interrupt_counter++; + break; + } +} +#endif /* if defined(PIOS_I2C_DIAGNOSTICS) */ + +/** + * Logs the last N state transitions and N IRQ events due to + * an error condition + * \param[out] data address where to copy the pios_i2c_fault_history structure to + * \param[out] counts three uint16 that receive the bad event, fsm, and error irq + * counts + */ +void PIOS_I2C_GetDiagnostics(struct pios_i2c_fault_history *data, uint8_t *counts) +{ +#if defined(PIOS_I2C_DIAGNOSTICS) + memcpy(data, &i2c_adapter_fault_history, sizeof(i2c_adapter_fault_history)); + counts[PIOS_I2C_BAD_EVENT_COUNTER] = i2c_bad_event_counter; + counts[PIOS_I2C_FSM_FAULT_COUNT] = i2c_fsm_fault_count; + counts[PIOS_I2C_ERROR_INTERRUPT_COUNTER] = i2c_error_interrupt_counter; + counts[PIOS_I2C_NACK_COUNTER] = i2c_nack_counter; + counts[PIOS_I2C_TIMEOUT_COUNTER] = i2c_timeout_counter; +#else + struct pios_i2c_fault_history i2c_adapter_fault_history; + i2c_adapter_fault_history.type = PIOS_I2C_ERROR_EVENT; + + memcpy(data, &i2c_adapter_fault_history, sizeof(i2c_adapter_fault_history)); + memset(counts, 0, sizeof(*counts) * PIOS_I2C_ERROR_COUNT_NUMELEM); +#endif +} + +static bool PIOS_I2C_validate(struct pios_i2c_adapter *i2c_adapter) +{ + return i2c_adapter->magic == PIOS_I2C_DEV_MAGIC; +} + +#if defined(PIOS_INCLUDE_CHIBIOS) && 0 +static struct pios_i2c_dev *PIOS_I2C_alloc(void) +{ + struct pios_i2c_dev *i2c_adapter; + + i2c_adapter = (struct pios_i2c_adapter *)PIOS_malloc(sizeof(*i2c_adapter)); + if (!i2c_adapter) { + return NULL; + } + + i2c_adapter->magic = PIOS_I2C_DEV_MAGIC; + return i2c_adapter; +} +#else +static struct pios_i2c_adapter pios_i2c_adapters[PIOS_I2C_MAX_DEVS]; +static uint8_t pios_i2c_num_adapters; +static struct pios_i2c_adapter *PIOS_I2C_alloc(void) +{ + struct pios_i2c_adapter *i2c_adapter; + + if (pios_i2c_num_adapters >= PIOS_I2C_MAX_DEVS) { + return NULL; + } + + i2c_adapter = &pios_i2c_adapters[pios_i2c_num_adapters++]; + i2c_adapter->magic = PIOS_I2C_DEV_MAGIC; + + return i2c_adapter; +} +#endif /* if defined(PIOS_INCLUDE_CHIBIOS) && 0 */ + + +/** + * Initializes IIC driver + * \param[in] mode currently only mode 0 supported + * \return < 0 if initialisation failed + */ +int32_t PIOS_I2C_Init(uint32_t *i2c_id, const struct pios_i2c_adapter_cfg *cfg) +{ + PIOS_DEBUG_Assert(i2c_id); + PIOS_DEBUG_Assert(cfg); + + struct pios_i2c_adapter *i2c_adapter; + + i2c_adapter = (struct pios_i2c_adapter *)PIOS_I2C_alloc(); + if (!i2c_adapter) { + goto out_fail; + } + + /* Bind the configuration to the device instance */ + i2c_adapter->cfg = cfg; + + vSemaphoreCreateBinary(i2c_adapter->sem_ready); + i2c_adapter->sem_busy = xSemaphoreCreateMutex(); + + /* Initialize the state machine */ + i2c_adapter_fsm_init(i2c_adapter); + + *i2c_id = (uint32_t)i2c_adapter; + + /* Configure and enable I2C interrupts */ + NVIC_Init((NVIC_InitTypeDef *)&(i2c_adapter->cfg->event.init)); + NVIC_Init((NVIC_InitTypeDef *)&(i2c_adapter->cfg->error.init)); + + /* No error */ + return 0; + +out_fail: + return -1; +} + +int32_t PIOS_I2C_Transfer(uint32_t i2c_id, const struct pios_i2c_txn txn_list[], uint32_t num_txns) +{ + // FIXME: only supports transfer sizes up to 255 bytes + struct pios_i2c_adapter *i2c_adapter = (struct pios_i2c_adapter *)i2c_id; + + bool valid = PIOS_I2C_validate(i2c_adapter); + + PIOS_Assert(valid) + + PIOS_DEBUG_Assert(txn_list); + PIOS_DEBUG_Assert(num_txns); + + bool semaphore_success = true; + +#ifdef USE_FREERTOS + /* Lock the bus */ + portTickType timeout; + timeout = i2c_adapter->cfg->transfer_timeout_ms / portTICK_RATE_MS; + if (xSemaphoreTake(i2c_adapter->sem_busy, timeout) == pdFALSE) { + return -2; + } +#else + PIOS_IRQ_Disable(); + if (i2c_adapter->busy) { + PIOS_IRQ_Enable(); + return -2; + } + i2c_adapter->busy = 1; + PIOS_IRQ_Enable(); +#endif /* USE_FREERTOS */ + + PIOS_DEBUG_Assert(i2c_adapter->curr_state == I2C_STATE_STOPPED); + + i2c_adapter->last_txn = &txn_list[num_txns - 1]; + i2c_adapter->active_txn = &txn_list[0]; + i2c_adapter->bus_error = false; + i2c_adapter->nack = false; + +#ifdef USE_FREERTOS + /* Make sure the done/ready semaphore is consumed before we start */ + semaphore_success &= (xSemaphoreTake(i2c_adapter->sem_ready, timeout) == pdTRUE); +#endif + + i2c_adapter->callback = NULL; + + bool dummy = false; + i2c_adapter_inject_event(i2c_adapter, I2C_EVENT_START, &dummy); + + /* Wait for the transfer to complete */ +#ifdef USE_FREERTOS + semaphore_success &= (xSemaphoreTake(i2c_adapter->sem_ready, timeout) == pdTRUE); + xSemaphoreGive(i2c_adapter->sem_ready); +#endif /* USE_FREERTOS */ + +#ifdef USE_FREERTOS + /* Unlock the bus */ + xSemaphoreGive(i2c_adapter->sem_busy); +#if defined(PIOS_I2C_DIAGNOSTICS) + if (!semaphore_success) { + i2c_timeout_counter++; + } +#endif +#else + PIOS_IRQ_Disable(); + i2c_adapter->busy = 0; + PIOS_IRQ_Enable(); +#endif /* USE_FREERTOS */ + + return !semaphore_success ? -2 : + i2c_adapter->bus_error ? -1 : + i2c_adapter->nack ? -3 : + 0; +} + +static int32_t PIOS_I2C_Transfer_Callback_Internal(struct pios_i2c_adapter *i2c_adapter, const struct pios_i2c_txn txn_list[], uint32_t num_txns, pios_i2c_callback callback) +{ + PIOS_DEBUG_Assert(i2c_adapter->curr_state == I2C_STATE_STOPPED); + + i2c_adapter->last_txn = &txn_list[num_txns - 1]; + i2c_adapter->active_txn = &txn_list[0]; + i2c_adapter->bus_error = false; + i2c_adapter->nack = false; + i2c_adapter->callback = callback; + + // Estimate bytes of transmission. Per txns: 1 adress byte + length + i2c_adapter->transfer_timeout_ticks = num_txns; + for (uint32_t i = 0; i < num_txns; i++) { + i2c_adapter->transfer_timeout_ticks += txn_list[i].len; + } + // timeout if it takes eight times the expected time + i2c_adapter->transfer_timeout_ticks <<= 3; + + bool dummy = false; + i2c_adapter_inject_event(i2c_adapter, I2C_EVENT_START, &dummy); + + return 0; +} + +int32_t PIOS_I2C_Transfer_Callback(uint32_t i2c_id, const struct pios_i2c_txn txn_list[], uint32_t num_txns, pios_i2c_callback callback) +{ + // FIXME: only supports transfer sizes up to 255 bytes + struct pios_i2c_adapter *i2c_adapter = (struct pios_i2c_adapter *)i2c_id; + + bool valid = PIOS_I2C_validate(i2c_adapter); + + PIOS_Assert(valid) + + PIOS_DEBUG_Assert(txn_list); + PIOS_DEBUG_Assert(num_txns); + +#ifdef USE_FREERTOS + /* Lock the bus */ + portTickType timeout; + timeout = i2c_adapter->cfg->transfer_timeout_ms / portTICK_RATE_MS; + if (xSemaphoreTake(i2c_adapter->sem_busy, timeout) == pdFALSE) { + return -2; + } +#else + PIOS_IRQ_Disable(); + if (i2c_adapter->busy) { + PIOS_IRQ_Enable(); + return -2; + } + i2c_adapter->busy = 1; + PIOS_IRQ_Enable(); +#endif /* USE_FREERTOS */ + + return PIOS_I2C_Transfer_Callback_Internal(i2c_adapter, txn_list, num_txns, callback); +} + +int32_t PIOS_I2C_Transfer_CallbackFromISR(uint32_t i2c_id, const struct pios_i2c_txn txn_list[], uint32_t num_txns, pios_i2c_callback callback, bool *woken) +{ + // FIXME: only supports transfer sizes up to 255 bytes + struct pios_i2c_adapter *i2c_adapter = (struct pios_i2c_adapter *)i2c_id; + + bool valid = PIOS_I2C_validate(i2c_adapter); + + PIOS_Assert(valid) + + PIOS_DEBUG_Assert(txn_list); + PIOS_DEBUG_Assert(num_txns); + +#ifdef USE_FREERTOS + signed portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; + + /* Lock the bus */ + bool locked = xSemaphoreTakeFromISR(i2c_adapter->sem_busy, &xHigherPriorityTaskWoken) == pdTRUE; + + if (xHigherPriorityTaskWoken == pdTRUE) { + *woken = true; + } + + if (!locked) { + return -2; + } +#else + PIOS_IRQ_Disable(); + if (i2c_adapter->busy) { + PIOS_IRQ_Enable(); + return -2; + } + i2c_adapter->busy = 1; + PIOS_IRQ_Enable(); +#endif /* USE_FREERTOS */ + + return PIOS_I2C_Transfer_Callback_Internal(i2c_adapter, txn_list, num_txns, callback); +} + + +static bool i2c_adapter_callback_handler(struct pios_i2c_adapter *i2c_adapter, bool *woken) +{ +#ifdef USE_FREERTOS + /* Unlock the bus */ + signed portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; + xSemaphoreGiveFromISR(i2c_adapter->sem_busy, &xHigherPriorityTaskWoken); + if (xHigherPriorityTaskWoken == pdTRUE) { + *woken = true; + } +#else + PIOS_IRQ_Disable(); + i2c_adapter->busy = 0; + PIOS_IRQ_Enable(); +#endif /* USE_FREERTOS */ + + + // Execute user supplied function + + if (i2c_adapter->callback()) { + *woken = true; + } + + return !i2c_adapter->bus_error; +} + + +void PIOS_I2C_EV_IRQ_Handler(uint32_t i2c_id) +{ + struct pios_i2c_adapter *i2c_adapter = (struct pios_i2c_adapter *)i2c_id; + + bool valid = PIOS_I2C_validate(i2c_adapter); + + PIOS_Assert(valid) + + bool woken = false; + + if (I2C_GetFlagStatus(i2c_adapter->cfg->regs, I2C_FLAG_RXNE)) { + // flag will be cleared by event +#if defined(PIOS_I2C_DIAGNOSTICS) + i2c_evirq_history[i2c_evirq_history_pointer] = I2C_FLAG_RXNE; + i2c_evirq_history_pointer = (i2c_evirq_history_pointer + 1) % I2C_LOG_DEPTH; +#endif + i2c_adapter_inject_event(i2c_adapter, I2C_EVENT_RECEIVER_BUFFER_NOT_EMPTY, &woken); + } else if (I2C_GetFlagStatus(i2c_adapter->cfg->regs, I2C_FLAG_TXIS)) { + // flag will be cleared by event +#if defined(PIOS_I2C_DIAGNOSTICS) + i2c_evirq_history[i2c_evirq_history_pointer] = I2C_FLAG_TXIS; + i2c_evirq_history_pointer = (i2c_evirq_history_pointer + 1) % I2C_LOG_DEPTH; +#endif + i2c_adapter_inject_event(i2c_adapter, I2C_EVENT_TRANSMIT_BUFFER_EMPTY, &woken); + } else if (I2C_GetFlagStatus(i2c_adapter->cfg->regs, I2C_FLAG_NACKF)) { + I2C_ClearFlag(i2c_adapter->cfg->regs, I2C_FLAG_NACKF); +#if defined(PIOS_I2C_DIAGNOSTICS) + i2c_evirq_history[i2c_evirq_history_pointer] = I2C_FLAG_NACKF; + i2c_evirq_history_pointer = (i2c_evirq_history_pointer + 1) % I2C_LOG_DEPTH; + ++i2c_nack_counter; +#endif + i2c_adapter_inject_event(i2c_adapter, I2C_EVENT_NACK, &woken); + } else if (I2C_GetFlagStatus(i2c_adapter->cfg->regs, I2C_FLAG_TC)) { + I2C_ClearFlag(i2c_adapter->cfg->regs, I2C_FLAG_TC); +#if defined(PIOS_I2C_DIAGNOSTICS) + i2c_evirq_history[i2c_evirq_history_pointer] = I2C_FLAG_TC; + i2c_evirq_history_pointer = (i2c_evirq_history_pointer + 1) % I2C_LOG_DEPTH; +#endif + i2c_adapter_inject_event(i2c_adapter, I2C_EVENT_TRANSFER_COMPLETE, &woken); + } else if (I2C_GetFlagStatus(i2c_adapter->cfg->regs, I2C_FLAG_STOPF)) { + I2C_ClearFlag(i2c_adapter->cfg->regs, I2C_FLAG_STOPF); +#if defined(PIOS_I2C_DIAGNOSTICS) + i2c_evirq_history[i2c_evirq_history_pointer] = I2C_FLAG_STOPF; + i2c_evirq_history_pointer = (i2c_evirq_history_pointer + 1) % I2C_LOG_DEPTH; +#endif + i2c_adapter_inject_event(i2c_adapter, I2C_EVENT_STOP, &woken); + } + + portEND_SWITCHING_ISR(woken ? pdTRUE : pdFALSE); +} + + +void PIOS_I2C_ER_IRQ_Handler(uint32_t i2c_id) +{ + struct pios_i2c_adapter *i2c_adapter = (struct pios_i2c_adapter *)i2c_id; + + bool valid = PIOS_I2C_validate(i2c_adapter); + + PIOS_Assert(valid) + + else if (I2C_GetFlagStatus(i2c_adapter->cfg->regs, I2C_FLAG_BERR)) { + I2C_ClearFlag(i2c_adapter->cfg->regs, I2C_FLAG_BERR); +#if defined(PIOS_I2C_DIAGNOSTICS) + i2c_erirq_history[i2c_erirq_history_pointer] = I2C_FLAG_BERR; + i2c_erirq_history_pointer = (i2c_erirq_history_pointer + 1) % I2C_LOG_DEPTH; +#endif + } else if (I2C_GetFlagStatus(i2c_adapter->cfg->regs, I2C_FLAG_ARLO)) { + I2C_ClearFlag(i2c_adapter->cfg->regs, I2C_FLAG_ARLO); +#if defined(PIOS_I2C_DIAGNOSTICS) + i2c_erirq_history[i2c_erirq_history_pointer] = I2C_FLAG_ARLO; + i2c_erirq_history_pointer = (i2c_erirq_history_pointer + 1) % I2C_LOG_DEPTH; +#endif + } else if (I2C_GetFlagStatus(i2c_adapter->cfg->regs, I2C_FLAG_OVR)) { + I2C_ClearFlag(i2c_adapter->cfg->regs, I2C_FLAG_OVR); +#if defined(PIOS_I2C_DIAGNOSTICS) + i2c_erirq_history[i2c_erirq_history_pointer] = I2C_FLAG_OVR; + i2c_erirq_history_pointer = (i2c_erirq_history_pointer + 1) % I2C_LOG_DEPTH; +#endif + } else if (I2C_GetFlagStatus(i2c_adapter->cfg->regs, I2C_FLAG_PECERR)) { + I2C_ClearFlag(i2c_adapter->cfg->regs, I2C_FLAG_PECERR); +#if defined(PIOS_I2C_DIAGNOSTICS) + i2c_erirq_history[i2c_erirq_history_pointer] = I2C_FLAG_PECERR; + i2c_erirq_history_pointer = (i2c_erirq_history_pointer + 1) % I2C_LOG_DEPTH; +#endif + } else if (I2C_GetFlagStatus(i2c_adapter->cfg->regs, I2C_FLAG_TIMEOUT)) { + I2C_ClearFlag(i2c_adapter->cfg->regs, I2C_FLAG_TIMEOUT); +#if defined(PIOS_I2C_DIAGNOSTICS) + i2c_erirq_history[i2c_erirq_history_pointer] = I2C_FLAG_TIMEOUT; + i2c_erirq_history_pointer = (i2c_erirq_history_pointer + 1) % I2C_LOG_DEPTH; +#endif + } else if (I2C_GetFlagStatus(i2c_adapter->cfg->regs, I2C_FLAG_ALERT)) { + I2C_ClearFlag(i2c_adapter->cfg->regs, I2C_FLAG_ALERT); +#if defined(PIOS_I2C_DIAGNOSTICS) + i2c_erirq_history[i2c_erirq_history_pointer] = I2C_FLAG_ALERT; + i2c_erirq_history_pointer = (i2c_erirq_history_pointer + 1) % I2C_LOG_DEPTH; +#endif + } else if (I2C_GetFlagStatus(i2c_adapter->cfg->regs, I2C_FLAG_BUSY)) { + I2C_ClearFlag(i2c_adapter->cfg->regs, I2C_FLAG_BUSY); +#if defined(PIOS_I2C_DIAGNOSTICS) + i2c_erirq_history[i2c_erirq_history_pointer] = I2C_FLAG_BUSY; + i2c_erirq_history_pointer = (i2c_erirq_history_pointer + 1) % I2C_LOG_DEPTH; +#endif + } + +#if defined(PIOS_I2C_DIAGNOSTICS) + i2c_adapter_log_fault(i2c_adapter, PIOS_I2C_ERROR_INTERRUPT); +#endif + + /* Fail hard on any errors for now */ + bool woken = false; + i2c_adapter_inject_event(i2c_adapter, I2C_EVENT_BUS_ERROR, &woken); + + portEND_SWITCHING_ISR(woken ? pdTRUE : pdFALSE); +} + +#endif /* if defined(PIOS_INCLUDE_I2C) */ + +/** + * @} + * @} + */ diff --git a/flight/pios/stm32f30x/pios_irq.c b/flight/pios/stm32f30x/pios_irq.c new file mode 100644 index 0000000000..3a2a79b5d5 --- /dev/null +++ b/flight/pios/stm32f30x/pios_irq.c @@ -0,0 +1,97 @@ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_IRQ IRQ Setup Functions + * @brief STM32 Hardware code to enable and disable interrupts + * @{ + * + * @file pios_irq.c + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * Parts by Thorsten Klose (tk@midibox.org) (tk@midibox.org) + * @brief IRQ Enable/Disable routines + * @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.h" + +#ifdef PIOS_INCLUDE_IRQ + +/* Private Function Prototypes */ + +/* Local Variables */ +/* The nesting counter ensures, that interrupts won't be enabled so long nested functions disable them */ +static uint32_t nested_ctr; + +/* Stored priority level before IRQ has been disabled (important for co-existence with vPortEnterCritical) */ +static uint32_t prev_primask; + +/** + * Disables all interrupts (nested) + * \return < 0 On errors + */ +int32_t PIOS_IRQ_Disable(void) +{ + /* Get current priority if nested level == 0 */ + if (!nested_ctr) { + __asm volatile (" mrs %0, primask\n" : "=r" (prev_primask) + ); + } + + /* Disable interrupts */ + __asm volatile (" mov r0, #1 \n" " msr primask, r0\n" ::: "r0"); + + ++nested_ctr; + + /* No error */ + return 0; +} + +/** + * Enables all interrupts (nested) + * \return < 0 on errors + * \return -1 on nesting errors (PIOS_IRQ_Disable() hasn't been called before) + */ +int32_t PIOS_IRQ_Enable(void) +{ + /* Check for nesting error */ + if (nested_ctr == 0) { + /* Nesting error */ + return -1; + } + + /* Decrease nesting level */ + --nested_ctr; + + /* Set back previous priority once nested level reached 0 again */ + if (nested_ctr == 0) { + __asm volatile (" msr primask, %0\n" ::"r" (prev_primask) + ); + } + + /* No error */ + return 0; +} + +#endif /* PIOS_INCLUDE_IRQ */ + +/** + * @} + * @} + */ diff --git a/flight/pios/stm32f30x/pios_ppm.c b/flight/pios/stm32f30x/pios_ppm.c new file mode 100644 index 0000000000..9f1875a02c --- /dev/null +++ b/flight/pios/stm32f30x/pios_ppm.c @@ -0,0 +1,401 @@ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_PPM PPM Input Functions + * @brief Code to measure PPM input and seperate into channels + * @{ + * + * @file pios_ppm.c + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. + * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012. + * @brief PPM Input functions (STM32 dependent) + * @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.h" + +#ifdef PIOS_INCLUDE_PPM + +#include "pios_ppm_priv.h" + +/* Provide a RCVR driver */ +static int32_t PIOS_PPM_Get(uint32_t rcvr_id, uint8_t channel); +static xSemaphoreHandle PIOS_PPM_Get_Semaphore(uint32_t rcvr_id, uint8_t channel); + +const struct pios_rcvr_driver pios_ppm_rcvr_driver = { + .read = PIOS_PPM_Get, +#if defined(PIOS_INCLUDE_FREERTOS) + .get_semaphore = PIOS_PPM_Get_Semaphore +#endif +}; + +#define PIOS_PPM_IN_MIN_NUM_CHANNELS 4 +#define PIOS_PPM_IN_MAX_NUM_CHANNELS PIOS_PPM_NUM_INPUTS +#define PIOS_PPM_STABLE_CHANNEL_COUNT 25 // frames +#define PIOS_PPM_IN_MIN_SYNC_PULSE_US 2700 // microseconds +#define PIOS_PPM_IN_MIN_CHANNEL_PULSE_US 750 // microseconds +#define PIOS_PPM_IN_MAX_CHANNEL_PULSE_US 2250 // microseconds + +static void PIOS_PPM_Supervisor(uint32_t ppm_id); + +enum pios_ppm_dev_magic { + PIOS_PPM_DEV_MAGIC = 0xee014d8b, +}; + +struct pios_ppm_dev { + enum pios_ppm_dev_magic magic; + const struct pios_ppm_cfg *cfg; + + uint8_t PulseIndex; + uint32_t PreviousTime; + uint32_t CurrentTime; + uint32_t DeltaTime; + uint32_t CaptureValue[PIOS_PPM_IN_MAX_NUM_CHANNELS]; + uint32_t CaptureValueNewFrame[PIOS_PPM_IN_MAX_NUM_CHANNELS]; + uint32_t LargeCounter; + int8_t NumChannels; + int8_t NumChannelsPrevFrame; + uint8_t NumChannelCounter; + + uint8_t supv_timer; + bool Tracking; + bool Fresh; + +#ifdef PIOS_INCLUDE_FREERTOS + xSemaphoreHandle new_sample_semaphores[PIOS_PPM_IN_MIN_NUM_CHANNELS]; +#endif /* PIOS_INCLUDE_FREERTOS */ +}; + +static bool PIOS_PPM_validate(struct pios_ppm_dev *ppm_dev) +{ + return ppm_dev->magic == PIOS_PPM_DEV_MAGIC; +} + +#if defined(PIOS_INCLUDE_FREERTOS) +static struct pios_ppm_dev *PIOS_PPM_alloc(void) +{ + struct pios_ppm_dev *ppm_dev; + + ppm_dev = (struct pios_ppm_dev *)pios_malloc(sizeof(*ppm_dev)); + if (!ppm_dev) { + return NULL; + } + + // Initialize the semaphores to 0. + for (uint8_t i = 0; i < PIOS_PPM_IN_MIN_NUM_CHANNELS; ++i) { + ppm_dev->new_sample_semaphores[i] = 0; + } + + ppm_dev->magic = PIOS_PPM_DEV_MAGIC; + return ppm_dev; +} +#else +static struct pios_ppm_dev pios_ppm_devs[PIOS_PPM_MAX_DEVS]; +static uint8_t pios_ppm_num_devs; +static struct pios_ppm_dev *PIOS_PPM_alloc(void) +{ + struct pios_ppm_dev *ppm_dev; + + if (pios_ppm_num_devs >= PIOS_PPM_MAX_DEVS) { + return NULL; + } + + ppm_dev = &pios_ppm_devs[pios_ppm_num_devs++]; + ppm_dev->magic = PIOS_PPM_DEV_MAGIC; + + return ppm_dev; +} +#endif /* if defined(PIOS_INCLUDE_FREERTOS) */ + +static void PIOS_PPM_tim_overflow_cb(uint32_t id, uint32_t context, uint8_t channel, uint16_t count); +static void PIOS_PPM_tim_edge_cb(uint32_t id, uint32_t context, uint8_t channel, uint16_t count); +static const struct pios_tim_callbacks tim_callbacks = { + .overflow = PIOS_PPM_tim_overflow_cb, + .edge = PIOS_PPM_tim_edge_cb, +}; + +extern int32_t PIOS_PPM_Init(uint32_t *ppm_id, const struct pios_ppm_cfg *cfg) +{ + PIOS_DEBUG_Assert(ppm_id); + PIOS_DEBUG_Assert(cfg); + + struct pios_ppm_dev *ppm_dev; + + ppm_dev = (struct pios_ppm_dev *)PIOS_PPM_alloc(); + if (!ppm_dev) { + goto out_fail; + } + + /* Bind the configuration to the device instance */ + ppm_dev->cfg = cfg; + + /* Set up the state variables */ + ppm_dev->PulseIndex = 0; + ppm_dev->PreviousTime = 0; + ppm_dev->CurrentTime = 0; + ppm_dev->DeltaTime = 0; + ppm_dev->LargeCounter = 0; + ppm_dev->NumChannels = -1; + ppm_dev->NumChannelsPrevFrame = -1; + ppm_dev->NumChannelCounter = 0; + ppm_dev->Tracking = false; + ppm_dev->Fresh = false; + + for (uint8_t i = 0; i < PIOS_PPM_IN_MAX_NUM_CHANNELS; i++) { + /* Flush counter variables */ + ppm_dev->CaptureValue[i] = PIOS_RCVR_TIMEOUT; + ppm_dev->CaptureValueNewFrame[i] = PIOS_RCVR_TIMEOUT; + } + + uint32_t tim_id; + if (PIOS_TIM_InitChannels(&tim_id, cfg->channels, cfg->num_channels, &tim_callbacks, (uint32_t)ppm_dev)) { + return -1; + } + + TIM_ICInitTypeDef TIM_ICInitStructure = cfg->tim_ic_init; + + /* Configure the channels to be in capture/compare mode */ + for (uint8_t i = 0; i < cfg->num_channels; i++) { + const struct pios_tim_channel *chan = &cfg->channels[i]; + + /* Configure timer for input capture */ + TIM_ICInitStructure.TIM_Channel = chan->timer_chan; + TIM_ICInit(chan->timer, &TIM_ICInitStructure); + + /* Enable the Capture Compare Interrupt Request */ + switch (chan->timer_chan) { + case TIM_Channel_1: + TIM_ITConfig(chan->timer, TIM_IT_CC1 | TIM_IT_Update, ENABLE); + break; + case TIM_Channel_2: + TIM_ITConfig(chan->timer, TIM_IT_CC2 | TIM_IT_Update, ENABLE); + break; + case TIM_Channel_3: + TIM_ITConfig(chan->timer, TIM_IT_CC3 | TIM_IT_Update, ENABLE); + break; + case TIM_Channel_4: + TIM_ITConfig(chan->timer, TIM_IT_CC4 | TIM_IT_Update, ENABLE); + break; + } + } + + if (!PIOS_RTC_RegisterTickCallback(PIOS_PPM_Supervisor, (uint32_t)ppm_dev)) { + PIOS_DEBUG_Assert(0); + } + + *ppm_id = (uint32_t)ppm_dev; + + return 0; + +out_fail: + return -1; +} + +#if defined(PIOS_INCLUDE_FREERTOS) +static xSemaphoreHandle PIOS_PPM_Get_Semaphore(uint32_t rcvr_id, uint8_t channel) +{ + struct pios_ppm_dev *ppm_dev = (struct pios_ppm_dev *)rcvr_id; + + if (!PIOS_PPM_validate(ppm_dev)) { + /* Invalid device specified */ + return 0; + } + + if (channel >= PIOS_PPM_IN_MAX_NUM_CHANNELS) { + /* Channel out of range */ + return 0; + } + + if (ppm_dev->new_sample_semaphores[channel] == 0) { + vSemaphoreCreateBinary(ppm_dev->new_sample_semaphores[channel]); + } + return ppm_dev->new_sample_semaphores[channel]; +} +#endif /* if defined(PIOS_INCLUDE_FREERTOS) */ + +/** + * Get the value of an input channel + * \param[in] channel Number of the channel desired (zero based) + * \output PIOS_RCVR_INVALID channel not available + * \output PIOS_RCVR_TIMEOUT failsafe condition or missing receiver + * \output >=0 channel value + */ +static int32_t PIOS_PPM_Get(uint32_t rcvr_id, uint8_t channel) +{ + struct pios_ppm_dev *ppm_dev = (struct pios_ppm_dev *)rcvr_id; + + if (!PIOS_PPM_validate(ppm_dev)) { + /* Invalid device specified */ + return PIOS_RCVR_INVALID; + } + + if (channel >= PIOS_PPM_IN_MAX_NUM_CHANNELS) { + /* Channel out of range */ + return PIOS_RCVR_INVALID; + } + return ppm_dev->CaptureValue[channel]; +} + +static void PIOS_PPM_tim_overflow_cb(__attribute__((unused)) uint32_t tim_id, uint32_t context, + __attribute__((unused)) uint8_t channel, uint16_t count) +{ + struct pios_ppm_dev *ppm_dev = (struct pios_ppm_dev *)context; + + if (!PIOS_PPM_validate(ppm_dev)) { + /* Invalid device specified */ + return; + } + + ppm_dev->LargeCounter += count; +} + + +static void PIOS_PPM_tim_edge_cb(__attribute__((unused)) uint32_t tim_id, uint32_t context, uint8_t chan_idx, uint16_t count) +{ + /* Recover our device context */ + struct pios_ppm_dev *ppm_dev = (struct pios_ppm_dev *)context; + + if (!PIOS_PPM_validate(ppm_dev)) { + /* Invalid device specified */ + return; + } + + if (chan_idx >= ppm_dev->cfg->num_channels) { + /* Channel out of range */ + return; + } + + /* Shift the last measurement out */ + ppm_dev->PreviousTime = ppm_dev->CurrentTime; + + /* Grab the new count */ + ppm_dev->CurrentTime = count; + + /* Convert to 32-bit timer result */ + ppm_dev->CurrentTime += ppm_dev->LargeCounter; + + /* Capture computation */ + ppm_dev->DeltaTime = ppm_dev->CurrentTime - ppm_dev->PreviousTime; + + ppm_dev->PreviousTime = ppm_dev->CurrentTime; + + /* Sync pulse detection */ + if (ppm_dev->DeltaTime > PIOS_PPM_IN_MIN_SYNC_PULSE_US) { + if (ppm_dev->PulseIndex == ppm_dev->NumChannelsPrevFrame + && ppm_dev->PulseIndex >= PIOS_PPM_IN_MIN_NUM_CHANNELS + && ppm_dev->PulseIndex <= PIOS_PPM_IN_MAX_NUM_CHANNELS) { + /* If we see n simultaneous frames of the same + number of channels we save it as our frame size */ + if (ppm_dev->NumChannelCounter < PIOS_PPM_STABLE_CHANNEL_COUNT) { + ppm_dev->NumChannelCounter++; + } else { + ppm_dev->NumChannels = ppm_dev->PulseIndex; + } + } else { + ppm_dev->NumChannelCounter = 0; + } + + /* Check if the last frame was well formed */ + if (ppm_dev->PulseIndex == ppm_dev->NumChannels && ppm_dev->Tracking) { + /* The last frame was well formed */ + for (int32_t i = 0; i < ppm_dev->NumChannels; i++) { + ppm_dev->CaptureValue[i] = ppm_dev->CaptureValueNewFrame[i]; + } + for (uint32_t i = ppm_dev->NumChannels; + i < PIOS_PPM_IN_MAX_NUM_CHANNELS; i++) { + ppm_dev->CaptureValue[i] = PIOS_RCVR_TIMEOUT; + } +#if defined(PIOS_INCLUDE_FREERTOS) + /* Signal that a new sample is ready on this channel. */ + if (ppm_dev->new_sample_semaphores[chan_idx] != 0) { + signed portBASE_TYPE pxHigherPriorityTaskWoken = pdFALSE; + if (xSemaphoreGiveFromISR(ppm_dev->new_sample_semaphores[chan_idx], &pxHigherPriorityTaskWoken) == pdTRUE) { + portEND_SWITCHING_ISR(pxHigherPriorityTaskWoken); /* FIXME: is this the right place for his? */ + } + } +#endif /* USE_FREERTOS */ + } else { + for (uint32_t i = 0; + i < PIOS_PPM_IN_MAX_NUM_CHANNELS; i++) { + ppm_dev->CaptureValue[i] = PIOS_RCVR_TIMEOUT; + } + } + + ppm_dev->Fresh = true; + ppm_dev->Tracking = true; + ppm_dev->NumChannelsPrevFrame = ppm_dev->PulseIndex; + ppm_dev->PulseIndex = 0; + + /* We rely on the supervisor to set CaptureValue to invalid + if no valid frame is found otherwise we ride over it */ + } else if (ppm_dev->Tracking) { + /* Valid pulse duration 0.75 to 2.5 ms*/ + if (ppm_dev->DeltaTime > PIOS_PPM_IN_MIN_CHANNEL_PULSE_US + && ppm_dev->DeltaTime < PIOS_PPM_IN_MAX_CHANNEL_PULSE_US + && ppm_dev->PulseIndex < PIOS_PPM_IN_MAX_NUM_CHANNELS) { + ppm_dev->CaptureValueNewFrame[ppm_dev->PulseIndex] = ppm_dev->DeltaTime; + ppm_dev->PulseIndex++; + } else { + /* Not a valid pulse duration */ + ppm_dev->Tracking = false; + for (uint32_t i = 0; i < PIOS_PPM_IN_MAX_NUM_CHANNELS; i++) { + ppm_dev->CaptureValueNewFrame[i] = PIOS_RCVR_TIMEOUT; + } + } + } +} + +static void PIOS_PPM_Supervisor(uint32_t ppm_id) +{ + /* Recover our device context */ + struct pios_ppm_dev *ppm_dev = (struct pios_ppm_dev *)ppm_id; + + if (!PIOS_PPM_validate(ppm_dev)) { + /* Invalid device specified */ + return; + } + + /* + * RTC runs at 625Hz so divide down the base rate so + * that this loop runs at 25Hz. + */ + if (++(ppm_dev->supv_timer) < 25) { + return; + } + ppm_dev->supv_timer = 0; + + if (!ppm_dev->Fresh) { + ppm_dev->Tracking = false; + + for (int32_t i = 0; i < PIOS_PPM_IN_MAX_NUM_CHANNELS; i++) { + ppm_dev->CaptureValue[i] = PIOS_RCVR_TIMEOUT; + ppm_dev->CaptureValueNewFrame[i] = PIOS_RCVR_TIMEOUT; + } + } + + ppm_dev->Fresh = false; +} + +#endif /* PIOS_INCLUDE_PPM */ + +/** + * @} + * @} + */ diff --git a/flight/pios/stm32f30x/pios_pwm.c b/flight/pios/stm32f30x/pios_pwm.c new file mode 100644 index 0000000000..d0a6fcdda8 --- /dev/null +++ b/flight/pios/stm32f30x/pios_pwm.c @@ -0,0 +1,283 @@ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_PWM PWM Input Functions + * @brief Code to measure with PWM input + * @{ + * + * @file pios_pwm.c + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012. + * @brief PWM Input functions (STM32 dependent) + * @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.h" + +#ifdef PIOS_INCLUDE_PWM + +#include "pios_pwm_priv.h" + +/* Provide a RCVR driver */ +static int32_t PIOS_PWM_Get(uint32_t rcvr_id, uint8_t channel); + +const struct pios_rcvr_driver pios_pwm_rcvr_driver = { + .read = PIOS_PWM_Get, +}; + +/* Local Variables */ +/* 100 ms timeout without updates on channels */ +static const uint32_t PWM_SUPERVISOR_TIMEOUT = 100000; + +enum pios_pwm_dev_magic { + PIOS_PWM_DEV_MAGIC = 0xab30293c, +}; + +struct pios_pwm_dev { + enum pios_pwm_dev_magic magic; + const struct pios_pwm_cfg *cfg; + + uint8_t CaptureState[PIOS_PWM_NUM_INPUTS]; + uint16_t RiseValue[PIOS_PWM_NUM_INPUTS]; + uint16_t FallValue[PIOS_PWM_NUM_INPUTS]; + uint32_t CaptureValue[PIOS_PWM_NUM_INPUTS]; + uint32_t CapCounter[PIOS_PWM_NUM_INPUTS]; + uint32_t us_since_update[PIOS_PWM_NUM_INPUTS]; +}; + +static bool PIOS_PWM_validate(struct pios_pwm_dev *pwm_dev) +{ + return pwm_dev->magic == PIOS_PWM_DEV_MAGIC; +} + +#if defined(PIOS_INCLUDE_FREERTOS) +static struct pios_pwm_dev *PIOS_PWM_alloc(void) +{ + struct pios_pwm_dev *pwm_dev; + + pwm_dev = (struct pios_pwm_dev *)pios_malloc(sizeof(*pwm_dev)); + if (!pwm_dev) { + return NULL; + } + + pwm_dev->magic = PIOS_PWM_DEV_MAGIC; + return pwm_dev; +} +#else +static struct pios_pwm_dev pios_pwm_devs[PIOS_PWM_MAX_DEVS]; +static uint8_t pios_pwm_num_devs; +static struct pios_pwm_dev *PIOS_PWM_alloc(void) +{ + struct pios_pwm_dev *pwm_dev; + + if (pios_pwm_num_devs >= PIOS_PWM_MAX_DEVS) { + return NULL; + } + + pwm_dev = &pios_pwm_devs[pios_pwm_num_devs++]; + pwm_dev->magic = PIOS_PWM_DEV_MAGIC; + + return pwm_dev; +} +#endif /* if defined(PIOS_INCLUDE_FREERTOS) */ + +static void PIOS_PWM_tim_overflow_cb(uint32_t id, uint32_t context, uint8_t channel, uint16_t count); +static void PIOS_PWM_tim_edge_cb(uint32_t id, uint32_t context, uint8_t channel, uint16_t count); +static const struct pios_tim_callbacks tim_callbacks = { + .overflow = PIOS_PWM_tim_overflow_cb, + .edge = PIOS_PWM_tim_edge_cb, +}; + +/** + * Initialises all the pins + */ +int32_t PIOS_PWM_Init(uint32_t *pwm_id, const struct pios_pwm_cfg *cfg) +{ + PIOS_DEBUG_Assert(pwm_id); + PIOS_DEBUG_Assert(cfg); + + struct pios_pwm_dev *pwm_dev; + + pwm_dev = (struct pios_pwm_dev *)PIOS_PWM_alloc(); + if (!pwm_dev) { + goto out_fail; + } + + /* Bind the configuration to the device instance */ + pwm_dev->cfg = cfg; + + for (uint8_t i = 0; i < PIOS_PWM_NUM_INPUTS; i++) { + /* Flush counter variables */ + pwm_dev->CaptureState[i] = 0; + pwm_dev->RiseValue[i] = 0; + pwm_dev->FallValue[i] = 0; + pwm_dev->CaptureValue[i] = PIOS_RCVR_TIMEOUT; + } + + uint32_t tim_id; + if (PIOS_TIM_InitChannels(&tim_id, cfg->channels, cfg->num_channels, &tim_callbacks, (uint32_t)pwm_dev)) { + return -1; + } + + /* Configure the channels to be in capture/compare mode */ + for (uint8_t i = 0; i < cfg->num_channels; i++) { + const struct pios_tim_channel *chan = &cfg->channels[i]; + + /* Configure timer for input capture */ + TIM_ICInitTypeDef TIM_ICInitStructure = cfg->tim_ic_init; + TIM_ICInitStructure.TIM_Channel = chan->timer_chan; + TIM_ICInit(chan->timer, &TIM_ICInitStructure); + + /* Enable the Capture Compare Interrupt Request */ + switch (chan->timer_chan) { + case TIM_Channel_1: + TIM_ITConfig(chan->timer, TIM_IT_CC1, ENABLE); + break; + case TIM_Channel_2: + TIM_ITConfig(chan->timer, TIM_IT_CC2, ENABLE); + break; + case TIM_Channel_3: + TIM_ITConfig(chan->timer, TIM_IT_CC3, ENABLE); + break; + case TIM_Channel_4: + TIM_ITConfig(chan->timer, TIM_IT_CC4, ENABLE); + break; + } + + // Need the update event for that timer to detect timeouts + TIM_ITConfig(chan->timer, TIM_IT_Update, ENABLE); + } + + *pwm_id = (uint32_t)pwm_dev; + + return 0; + +out_fail: + return -1; +} + +/** + * Get the value of an input channel + * \param[in] channel Number of the channel desired (zero based) + * \output PIOS_RCVR_INVALID channel not available + * \output PIOS_RCVR_TIMEOUT failsafe condition or missing receiver + * \output >=0 channel value + */ +static int32_t PIOS_PWM_Get(uint32_t rcvr_id, uint8_t channel) +{ + struct pios_pwm_dev *pwm_dev = (struct pios_pwm_dev *)rcvr_id; + + if (!PIOS_PWM_validate(pwm_dev)) { + /* Invalid device specified */ + return PIOS_RCVR_INVALID; + } + + if (channel >= PIOS_PWM_NUM_INPUTS) { + /* Channel out of range */ + return PIOS_RCVR_INVALID; + } + return pwm_dev->CaptureValue[channel]; +} + +static void PIOS_PWM_tim_overflow_cb(__attribute__((unused)) uint32_t tim_id, uint32_t context, uint8_t channel, uint16_t count) +{ + struct pios_pwm_dev *pwm_dev = (struct pios_pwm_dev *)context; + + if (!PIOS_PWM_validate(pwm_dev)) { + /* Invalid device specified */ + return; + } + + if (channel >= pwm_dev->cfg->num_channels) { + /* Channel out of range */ + return; + } + + pwm_dev->us_since_update[channel] += count; + if (pwm_dev->us_since_update[channel] >= PWM_SUPERVISOR_TIMEOUT) { + pwm_dev->CaptureState[channel] = 0; + pwm_dev->RiseValue[channel] = 0; + pwm_dev->FallValue[channel] = 0; + pwm_dev->CaptureValue[channel] = PIOS_RCVR_TIMEOUT; + pwm_dev->us_since_update[channel] = 0; + } +} + +static void PIOS_PWM_tim_edge_cb(__attribute__((unused)) uint32_t tim_id, uint32_t context, uint8_t chan_idx, uint16_t count) +{ + /* Recover our device context */ + struct pios_pwm_dev *pwm_dev = (struct pios_pwm_dev *)context; + + if (!PIOS_PWM_validate(pwm_dev)) { + /* Invalid device specified */ + return; + } + + if (chan_idx >= pwm_dev->cfg->num_channels) { + /* Channel out of range */ + return; + } + + const struct pios_tim_channel *chan = &pwm_dev->cfg->channels[chan_idx]; + + if (pwm_dev->CaptureState[chan_idx] == 0) { + pwm_dev->RiseValue[chan_idx] = count; + pwm_dev->us_since_update[chan_idx] = 0; + } else { + pwm_dev->FallValue[chan_idx] = count; + } + + // flip state machine and capture value here + /* Simple rise or fall state machine */ + TIM_ICInitTypeDef TIM_ICInitStructure = pwm_dev->cfg->tim_ic_init; + if (pwm_dev->CaptureState[chan_idx] == 0) { + /* Switch states */ + pwm_dev->CaptureState[chan_idx] = 1; + + /* Switch polarity of input capture */ + TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Falling; + TIM_ICInitStructure.TIM_Channel = chan->timer_chan; + TIM_ICInit(chan->timer, &TIM_ICInitStructure); + } else { + /* Capture computation */ + if (pwm_dev->FallValue[chan_idx] > pwm_dev->RiseValue[chan_idx]) { + pwm_dev->CaptureValue[chan_idx] = (pwm_dev->FallValue[chan_idx] - pwm_dev->RiseValue[chan_idx]); + } else { + pwm_dev->CaptureValue[chan_idx] = ((chan->timer->ARR - pwm_dev->RiseValue[chan_idx]) + pwm_dev->FallValue[chan_idx]); + } + + /* Switch states */ + pwm_dev->CaptureState[chan_idx] = 0; + + /* Increase supervisor counter */ + pwm_dev->CapCounter[chan_idx]++; + + /* Switch polarity of input capture */ + TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; + TIM_ICInitStructure.TIM_Channel = chan->timer_chan; + TIM_ICInit(chan->timer, &TIM_ICInitStructure); + } +} + +#endif /* PIOS_INCLUDE_PWM */ + +/** + * @} + * @} + */ diff --git a/flight/pios/stm32f30x/pios_rtc.c b/flight/pios/stm32f30x/pios_rtc.c new file mode 100644 index 0000000000..0ea7fbbf48 --- /dev/null +++ b/flight/pios/stm32f30x/pios_rtc.c @@ -0,0 +1,148 @@ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_PWM PWM Input Functions + * @brief Code to measure with PWM input + * @{ + * + * @file pios_pwm.c + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012. + * @author Tau Labs, http://taulabs.org, Copyright (C) 2012-2013 + * @brief PWM Input functions (STM32 dependent) + * @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 + */ + +/* Project Includes */ +#include "pios.h" + +#if defined(PIOS_INCLUDE_RTC) +#include + +#ifndef PIOS_RTC_PRESCALER +#define PIOS_RTC_PRESCALER 100 +#endif + +struct rtc_callback_entry { + void (*fn)(uint32_t); + uint32_t data; +}; + +#define PIOS_RTC_MAX_CALLBACKS 3 +struct rtc_callback_entry rtc_callback_list[PIOS_RTC_MAX_CALLBACKS]; +static uint8_t rtc_callback_next = 0; + +void PIOS_RTC_Init(const struct pios_rtc_cfg *cfg) +{ + RCC_BackupResetCmd(ENABLE); + RCC_BackupResetCmd(DISABLE); + RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE); + PWR_BackupAccessCmd(ENABLE); + // Divide external 8 MHz clock by 32 to 250kHz + RCC_RTCCLKConfig(cfg->clksrc); + RCC_RTCCLKCmd(ENABLE); + + RTC_WakeUpCmd(DISABLE); + // Divide 250kHz Mhz clock by 16 to 15625Hz + RTC_WakeUpClockConfig(RTC_WakeUpClock_RTCCLK_Div16); + // Divide 15625Hz by 25 to get 625 Hz + RTC_SetWakeUpCounter(cfg->prescaler); // cfg->prescaler); + RTC_WakeUpCmd(ENABLE); + + /* Configure and enable the RTC Second interrupt */ + EXTI_InitTypeDef ExtiInit = { + .EXTI_Line = EXTI_Line20, // matches above GPIO pin + .EXTI_Mode = EXTI_Mode_Interrupt, + .EXTI_Trigger = EXTI_Trigger_Rising, + .EXTI_LineCmd = ENABLE, + }; + EXTI_Init((EXTI_InitTypeDef *)&ExtiInit); + NVIC_Init((NVIC_InitTypeDef *)&cfg->irq.init); + RTC_ITConfig(RTC_IT_WUT, ENABLE); + + RTC_ClearFlag(RTC_FLAG_WUTF); +} + +uint32_t PIOS_RTC_Counter() +{ + return RTC_GetWakeUpCounter(); +} + +/* FIXME: This shouldn't use hard-coded clock rates, dividers or prescalers. + * Should get these from the cfg struct passed to init. + */ +float PIOS_RTC_Rate() +{ + return (float)(8e6f / 128.0f) / (1 + PIOS_RTC_PRESCALER); +} + +float PIOS_RTC_MsPerTick() +{ + return 1000.0f / PIOS_RTC_Rate(); +} + +/* TODO: This needs a mutex around rtc_callbacks[] */ +bool PIOS_RTC_RegisterTickCallback(void (*fn)(uint32_t id), uint32_t data) +{ + struct rtc_callback_entry *cb; + + if (rtc_callback_next >= PIOS_RTC_MAX_CALLBACKS) { + return false; + } + + cb = &rtc_callback_list[rtc_callback_next++]; + + cb->fn = fn; + cb->data = data; + return true; +} + +void PIOS_RTC_irq_handler(void) +{ +#if defined(PIOS_INCLUDE_CHIBIOS) + CH_IRQ_PROLOGUE(); +#endif /* defined(PIOS_INCLUDE_CHIBIOS) */ + + if (RTC_GetITStatus(RTC_IT_WUT)) { + /* Call all registered callbacks */ + for (uint8_t i = 0; i < rtc_callback_next; i++) { + struct rtc_callback_entry *cb = &rtc_callback_list[i]; + if (cb->fn) { + (cb->fn)(cb->data); + } + } + + /* Clear the RTC Second interrupt */ + RTC_ClearITPendingBit(RTC_IT_WUT); + } + + if (EXTI_GetITStatus(EXTI_Line20) != RESET) { + EXTI_ClearITPendingBit(EXTI_Line20); + } + +#if defined(PIOS_INCLUDE_CHIBIOS) + CH_IRQ_EPILOGUE(); +#endif /* defined(PIOS_INCLUDE_CHIBIOS) */ +} +#endif /* if defined(PIOS_INCLUDE_RTC) */ + +/** + * @} + * @} + */ diff --git a/flight/pios/stm32f30x/pios_spi.c b/flight/pios/stm32f30x/pios_spi.c new file mode 100644 index 0000000000..87f119e971 --- /dev/null +++ b/flight/pios/stm32f30x/pios_spi.c @@ -0,0 +1,738 @@ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_SPI SPI Functions + * @brief PIOS interface to read and write from SPI ports + * @{ + * + * @file pios_spi.c + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012. + * @brief Hardware Abstraction Layer for SPI ports of STM32 + * @see The GNU Public License (GPL) Version 3 + * @notes + * + * Note that additional chip select lines can be easily added by using + * the remaining free GPIOs of the core module. Shared SPI ports should be + * arbitrated with (FreeRTOS based) Mutexes to avoid collisions! + * + *****************************************************************************/ +/* + * 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 + +#ifdef PIOS_INCLUDE_SPI + +#include + +static bool PIOS_SPI_validate(__attribute__((unused)) struct pios_spi_dev *com_dev) +{ + /* Should check device magic here */ + return true; +} + +#if defined(PIOS_INCLUDE_FREERTOS) +static struct pios_spi_dev *PIOS_SPI_alloc(void) +{ + return pios_malloc(sizeof(struct pios_spi_dev)); +} +#else +static struct pios_spi_dev pios_spi_devs[PIOS_SPI_MAX_DEVS]; +static uint8_t pios_spi_num_devs; +static struct pios_spi_dev *PIOS_SPI_alloc(void) +{ + if (pios_spi_num_devs >= PIOS_SPI_MAX_DEVS) { + return NULL; + } + + return &pios_spi_devs[pios_spi_num_devs++]; +} +#endif + +/** + * Initialises SPI pins + * \param[in] mode currently only mode 0 supported + * \return < 0 if initialisation failed + */ +int32_t PIOS_SPI_Init(uint32_t *spi_id, const struct pios_spi_cfg *cfg) +{ + uint32_t init_ssel = 0; + + PIOS_Assert(spi_id); + PIOS_Assert(cfg); + + struct pios_spi_dev *spi_dev; + + spi_dev = (struct pios_spi_dev *)PIOS_SPI_alloc(); + if (!spi_dev) { + goto out_fail; + } + + /* Bind the configuration to the device instance */ + spi_dev->cfg = cfg; + +#if defined(PIOS_INCLUDE_FREERTOS) + vSemaphoreCreateBinary(spi_dev->busy); + xSemaphoreGive(spi_dev->busy); +#else + spi_dev->busy = 0; +#endif + + /* Disable callback function */ + spi_dev->callback = NULL; + + /* Set rx/tx dummy bytes to a known value */ + spi_dev->rx_dummy_byte = 0xFF; + spi_dev->tx_dummy_byte = 0xFF; + + switch (spi_dev->cfg->init.SPI_NSS) { + case SPI_NSS_Soft: + if (spi_dev->cfg->init.SPI_Mode == SPI_Mode_Master) { + /* We're a master in soft NSS mode, make sure we see NSS high at all times. */ + SPI_NSSInternalSoftwareConfig(spi_dev->cfg->regs, SPI_NSSInternalSoft_Set); + /* Init as many slave selects as the config advertises. */ + init_ssel = spi_dev->cfg->slave_count; + } else { + /* We're a slave in soft NSS mode, make sure we see NSS low at all times. */ + SPI_NSSInternalSoftwareConfig(spi_dev->cfg->regs, SPI_NSSInternalSoft_Reset); + } + break; + case SPI_NSS_Hard: + /* only legal for single-slave config */ + PIOS_Assert(spi_dev->cfg->slave_count == 1); + init_ssel = 1; + /* FIXME: Should this also call SPI_SSOutputCmd()? */ + break; + + default: + PIOS_Assert(0); + } + + /* Initialize the GPIO pins */ + /* note __builtin_ctz() due to the difference between GPIO_PinX and GPIO_PinSourceX */ + if (spi_dev->cfg->remap) { + GPIO_PinAFConfig(spi_dev->cfg->sclk.gpio, + __builtin_ctz(spi_dev->cfg->sclk.init.GPIO_Pin), + spi_dev->cfg->remap); + GPIO_PinAFConfig(spi_dev->cfg->mosi.gpio, + __builtin_ctz(spi_dev->cfg->mosi.init.GPIO_Pin), + spi_dev->cfg->remap); + GPIO_PinAFConfig(spi_dev->cfg->miso.gpio, + __builtin_ctz(spi_dev->cfg->miso.init.GPIO_Pin), + spi_dev->cfg->remap); + for (uint32_t i = 0; i < init_ssel; i++) { + GPIO_PinAFConfig(spi_dev->cfg->ssel[i].gpio, + __builtin_ctz(spi_dev->cfg->ssel[i].init.GPIO_Pin), + spi_dev->cfg->remap); + } + } + + /* Initialize the GPIO pins */ + GPIO_Init(spi_dev->cfg->sclk.gpio, (GPIO_InitTypeDef *)&(spi_dev->cfg->sclk.init)); + GPIO_Init(spi_dev->cfg->mosi.gpio, (GPIO_InitTypeDef *)&(spi_dev->cfg->mosi.init)); + GPIO_Init(spi_dev->cfg->miso.gpio, (GPIO_InitTypeDef *)&(spi_dev->cfg->miso.init)); + for (uint32_t i = 0; i < init_ssel; i++) { + /* Since we're driving the SSEL pin in software, ensure that the slave is deselected */ + /* XXX multi-slave support - maybe have another SPI_NSS_ mode? */ + GPIO_SetBits(spi_dev->cfg->ssel[i].gpio, spi_dev->cfg->ssel[i].init.GPIO_Pin); + GPIO_Init(spi_dev->cfg->ssel[i].gpio, (GPIO_InitTypeDef *)&(spi_dev->cfg->ssel[i].init)); + } + + /* Enable the associated peripheral clock */ + switch ((uint32_t)spi_dev->cfg->regs) { + case (uint32_t)SPI1: + /* Enable SPI peripheral clock (APB2 == high speed) */ + RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE); + break; + case (uint32_t)SPI2: + /* Enable SPI peripheral clock (APB1 == slow speed) */ + RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE); + break; + case (uint32_t)SPI3: + /* Enable SPI peripheral clock (APB1 == slow speed) */ + RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI3, ENABLE); + break; + } + + /* Enable DMA clock */ + RCC_AHBPeriphClockCmd(spi_dev->cfg->dma.ahb_clk, ENABLE); + + /* Configure DMA for SPI Rx */ + DMA_Cmd(spi_dev->cfg->dma.rx.channel, DISABLE); + DMA_Init(spi_dev->cfg->dma.rx.channel, (DMA_InitTypeDef *)&(spi_dev->cfg->dma.rx.init)); + + /* Configure DMA for SPI Tx */ + DMA_Cmd(spi_dev->cfg->dma.tx.channel, DISABLE); + DMA_Init(spi_dev->cfg->dma.tx.channel, (DMA_InitTypeDef *)&(spi_dev->cfg->dma.tx.init)); + + /* Initialize the SPI block */ + SPI_I2S_DeInit(spi_dev->cfg->regs); + SPI_Init(spi_dev->cfg->regs, (SPI_InitTypeDef *)&(spi_dev->cfg->init)); + + /* Configure CRC calculation */ + if (spi_dev->cfg->use_crc) { + SPI_CalculateCRC(spi_dev->cfg->regs, ENABLE); + } else { + SPI_CalculateCRC(spi_dev->cfg->regs, DISABLE); + } + + /* Configure the RX FIFO Threshold -- 8 bits */ + SPI_RxFIFOThresholdConfig(spi_dev->cfg->regs, SPI_RxFIFOThreshold_QF); + + /* Enable SPI */ + SPI_Cmd(spi_dev->cfg->regs, ENABLE); + + /* Enable SPI interrupts to DMA */ + SPI_I2S_DMACmd(spi_dev->cfg->regs, SPI_I2S_DMAReq_Tx | SPI_I2S_DMAReq_Rx, ENABLE); + + /* Configure DMA interrupt */ + NVIC_Init((NVIC_InitTypeDef *)&(spi_dev->cfg->dma.irq.init)); + + *spi_id = (uint32_t)spi_dev; + return 0; + +out_fail: + return -1; +} + +/** + * (Re-)initialises SPI peripheral clock rate + * + * \param[in] spi SPI number (0 or 1) + * \param[in] spi_prescaler configures the SPI speed: + *
    + *
  • PIOS_SPI_PRESCALER_2: sets clock rate 27.7~ nS @ 72 MHz (36 MBit/s) (only supported for spi==0, spi1 uses 4 instead) + *
  • PIOS_SPI_PRESCALER_4: sets clock rate 55.5~ nS @ 72 MHz (18 MBit/s) + *
  • PIOS_SPI_PRESCALER_8: sets clock rate 111.1~ nS @ 72 MHz (9 MBit/s) + *
  • PIOS_SPI_PRESCALER_16: sets clock rate 222.2~ nS @ 72 MHz (4.5 MBit/s) + *
  • PIOS_SPI_PRESCALER_32: sets clock rate 444.4~ nS @ 72 MHz (2.25 MBit/s) + *
  • PIOS_SPI_PRESCALER_64: sets clock rate 888.8~ nS @ 72 MHz (1.125 MBit/s) + *
  • PIOS_SPI_PRESCALER_128: sets clock rate 1.7~ nS @ 72 MHz (0.562 MBit/s) + *
  • PIOS_SPI_PRESCALER_256: sets clock rate 3.5~ nS @ 72 MHz (0.281 MBit/s) + *
+ * \return 0 if no error + * \return -1 if disabled SPI port selected + * \return -3 if invalid spi_prescaler selected + */ +int32_t PIOS_SPI_SetClockSpeed(uint32_t spi_id, SPIPrescalerTypeDef spi_prescaler) +{ + struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id; + + bool valid = PIOS_SPI_validate(spi_dev); + + PIOS_Assert(valid) + + SPI_InitTypeDef SPI_InitStructure; + + if (spi_prescaler >= 8) { + /* Invalid prescaler selected */ + return -3; + } + + /* Start with a copy of the default configuration for the peripheral */ + SPI_InitStructure = spi_dev->cfg->init; + + /* Adjust the prescaler for the peripheral's clock */ + SPI_InitStructure.SPI_BaudRatePrescaler = ((uint16_t)spi_prescaler & 7) << 3; + + /* Write back the new configuration */ + SPI_Init(spi_dev->cfg->regs, &SPI_InitStructure); + + PIOS_SPI_TransferByte(spi_id, 0xFF); + return 0; +} + +/** + * Claim the SPI bus semaphore. Calling the SPI functions does not require this + * \param[in] spi SPI number (0 or 1) + * \return 0 if no error + * \return -1 if timeout before claiming semaphore + */ +int32_t PIOS_SPI_ClaimBus(uint32_t spi_id) +{ +#if defined(PIOS_INCLUDE_FREERTOS) + struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id; + + bool valid = PIOS_SPI_validate(spi_dev); + PIOS_Assert(valid) + + if (xSemaphoreTake(spi_dev->busy, 0xffff) != pdTRUE) { + return -1; + } +#else + struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id; + uint32_t timeout = 0xffff; + while ((PIOS_SPI_Busy(spi_id) || spi_dev->busy) && --timeout) { + ; + } + if (timeout == 0) { // timed out + return -1; + } + + PIOS_IRQ_Disable(); + if (spi_dev->busy) { + return -1; + } + spi_dev->busy = 1; + PIOS_IRQ_Enable(); +#endif /* if defined(PIOS_INCLUDE_FREERTOS) */ + return 0; +} + +/** + * Claim the SPI bus semaphore from an ISR. Has no timeout. + * \param[in] spi SPI number (0 or 1) + * \param woken[in,out] If non-NULL, will be set to true if woken was false and a higher priority + * task has is now eligible to run, else unchanged + * \return 0 if no error + * \return -1 if timeout before claiming semaphore + */ +int32_t PIOS_SPI_ClaimBusISR(uint32_t spi_id, bool *woken) +{ +#if defined(PIOS_INCLUDE_FREERTOS) + struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id; + signed portBASE_TYPE higherPriorityTaskWoken = pdFALSE; + + bool valid = PIOS_SPI_validate(spi_dev); + PIOS_Assert(valid) + + if (xSemaphoreTakeFromISR(spi_dev->busy, &higherPriorityTaskWoken) != pdTRUE) { + return -1; + } + if (woken) { + *woken = *woken || (higherPriorityTaskWoken == pdTRUE); + } + return 0; + +#else + if (woken) { + *woken = false; + } + return PIOS_SPI_ClaimBus(spi_id); + +#endif +} + +/** + * Release the SPI bus semaphore. Calling the SPI functions does not require this + * \param[in] spi SPI number (0 or 1) + * \return 0 if no error + */ +int32_t PIOS_SPI_ReleaseBus(uint32_t spi_id) +{ +#if defined(PIOS_INCLUDE_FREERTOS) + struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id; + + bool valid = PIOS_SPI_validate(spi_dev); + PIOS_Assert(valid) + + xSemaphoreGive(spi_dev->busy); +#else + struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id; + PIOS_IRQ_Disable(); + spi_dev->busy = 0; + PIOS_IRQ_Enable(); +#endif + return 0; +} + +/** + * Release the SPI bus semaphore from ISR. Calling the SPI functions does not require this + * \param[in] spi SPI number (0 or 1) + * \param woken[in,out] If non-NULL, will be set to true if woken was false and a higher priority + * task has is now eligible to run, else unchanged + * \return 0 if no error + */ +int32_t PIOS_SPI_ReleaseBusISR(uint32_t spi_id, bool *woken) +{ +#if defined(PIOS_INCLUDE_FREERTOS) + struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id; + signed portBASE_TYPE higherPriorityTaskWoken = pdFALSE; + + bool valid = PIOS_SPI_validate(spi_dev); + PIOS_Assert(valid) + + xSemaphoreGiveFromISR(spi_dev->busy, &higherPriorityTaskWoken); + if (woken) { + *woken = *woken || (higherPriorityTaskWoken == pdTRUE); + } + return 0; + +#else + if (woken) { + *woken = false; + } + return PIOS_SPI_ReleaseBus(spi_id); + +#endif +} + + +/** + * Controls the RC (Register Clock alias Chip Select) pin of a SPI port + * \param[in] spi SPI number (0 or 1) + * \param[in] pin_value 0 or 1 + * \return 0 if no error + */ +int32_t PIOS_SPI_RC_PinSet(uint32_t spi_id, uint32_t slave_id, uint8_t pin_value) +{ + struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id; + + bool valid = PIOS_SPI_validate(spi_dev); + + PIOS_Assert(valid) + PIOS_Assert(slave_id <= spi_dev->cfg->slave_count) + + /* XXX multi-slave support? */ + if (pin_value) { + GPIO_SetBits(spi_dev->cfg->ssel[slave_id].gpio, spi_dev->cfg->ssel[slave_id].init.GPIO_Pin); + } else { + GPIO_ResetBits(spi_dev->cfg->ssel[slave_id].gpio, spi_dev->cfg->ssel[slave_id].init.GPIO_Pin); + } + + return 0; +} + +/** + * Transfers a byte to SPI output and reads back the return value from SPI input + * \param[in] spi SPI number (0 or 1) + * \param[in] b the byte which should be transfered + */ +int32_t PIOS_SPI_TransferByte(uint32_t spi_id, uint8_t b) +{ + struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id; + + bool valid = PIOS_SPI_validate(spi_dev); + + PIOS_Assert(valid) + + uint8_t rx_byte; + + /* Make sure the RXNE flag is cleared by reading the DR register */ + SPI_ReceiveData8(spi_dev->cfg->regs); + + /* Wait until the TXE goes high */ + while (SPI_I2S_GetFlagStatus(spi_dev->cfg->regs, SPI_I2S_FLAG_TXE) == RESET) { + ; + } + + /* Start the transfer */ + SPI_SendData8(spi_dev->cfg->regs, b); + + /* Wait until there is a byte to read */ + while (SPI_I2S_GetFlagStatus(spi_dev->cfg->regs, SPI_I2S_FLAG_RXNE) == RESET) { + ; + } + + /* Read the rx'd byte */ + rx_byte = SPI_ReceiveData8(spi_dev->cfg->regs); + + /* Wait until the TXE goes high */ + while (!(spi_dev->cfg->regs->SR & SPI_I2S_FLAG_TXE)) { + ; + } + + /* Wait for SPI transfer to have fully completed */ + while (spi_dev->cfg->regs->SR & SPI_I2S_FLAG_BSY) { + ; + } + + /* Return received byte */ + return rx_byte; +} + +/** + * Transfers a block of bytes via PIO. + * + * \param[in] spi_id SPI device handle + * \param[in] send_buffer pointer to buffer which should be sent.
+ * If NULL, 0xff (all-one) will be sent. + * \param[in] receive_buffer pointer to buffer which should get the received values.
+ * If NULL, received bytes will be discarded. + * \param[in] len number of bytes which should be transfered + * \return >= 0 if no error during transfer + * \return -1 if disabled SPI port selected + */ +int32_t PIOS_SPI_TransferBlock(uint32_t spi_id, const uint8_t *send_buffer, uint8_t *receive_buffer, uint16_t len, __attribute__((unused)) void *callback) +{ + struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id; + uint8_t b; + + bool valid = PIOS_SPI_validate(spi_dev); + + PIOS_Assert(valid) + + while (len--) { + /* get the byte to send */ + b = send_buffer ? *(send_buffer++) : 0xff; + + /* Wait until the TXE goes high */ + while (SPI_I2S_GetFlagStatus(spi_dev->cfg->regs, SPI_I2S_FLAG_TXE) == RESET) { + ; + } + + /* Start the transfer */ + SPI_SendData8(spi_dev->cfg->regs, b); + + /* Wait until there is a byte to read */ + while (SPI_I2S_GetFlagStatus(spi_dev->cfg->regs, SPI_I2S_FLAG_RXNE) == RESET) { + ; + } + + /* Read the rx'd byte */ + b = SPI_ReceiveData8(spi_dev->cfg->regs); + + /* save the received byte */ + if (receive_buffer) { + *(receive_buffer++) = b; + } + } + + /* Wait for SPI transfer to have fully completed */ + while (spi_dev->cfg->regs->SR & SPI_I2S_FLAG_BSY) { + ; + } + + return 0; +} + + +/** + * Transfers a block of bytes via DMA. + * \param[in] spi SPI number (0 or 1) + * \param[in] send_buffer pointer to buffer which should be sent.
+ * If NULL, 0xff (all-one) will be sent. + * \param[in] receive_buffer pointer to buffer which should get the received values.
+ * If NULL, received bytes will be discarded. + * \param[in] len number of bytes which should be transfered + * \param[in] callback pointer to callback function which will be executed + * from DMA channel interrupt once the transfer is finished. + * If NULL, no callback function will be used, and PIOS_SPI_TransferBlock() will + * block until the transfer is finished. + * \return >= 0 if no error during transfer + * \return -1 if disabled SPI port selected + * \return -3 if function has been called during an ongoing DMA transfer + */ +int32_t _PIOS_SPI_TransferBlock(uint32_t spi_id, const uint8_t *send_buffer, uint8_t *receive_buffer, uint16_t len, void *callback) +{ + struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id; + + bool valid = PIOS_SPI_validate(spi_dev); + + PIOS_Assert(valid) + + DMA_InitTypeDef dma_init; + + /* Exit if ongoing transfer */ + if (DMA_GetCurrDataCounter(spi_dev->cfg->dma.rx.channel)) { + return -3; + } + + /* Disable the SPI peripheral */ + SPI_Cmd(spi_dev->cfg->regs, DISABLE); + + /* Disable the DMA channels */ + DMA_Cmd(spi_dev->cfg->dma.rx.channel, DISABLE); + DMA_Cmd(spi_dev->cfg->dma.tx.channel, DISABLE); + + /* Set callback function */ + spi_dev->callback = callback; + + /* + * Configure Rx channel + */ + + /* Start with the default configuration for this peripheral */ + dma_init = spi_dev->cfg->dma.rx.init; + + if (receive_buffer != NULL) { + /* Enable memory addr. increment - bytes written into receive buffer */ + dma_init.DMA_MemoryBaseAddr = (uint32_t)receive_buffer; + dma_init.DMA_MemoryInc = DMA_MemoryInc_Enable; + } else { + /* Disable memory addr. increment - bytes written into dummy buffer */ + spi_dev->rx_dummy_byte = 0xFF; + dma_init.DMA_MemoryBaseAddr = (uint32_t)&spi_dev->rx_dummy_byte; + dma_init.DMA_MemoryInc = DMA_MemoryInc_Disable; + } + if (spi_dev->cfg->use_crc) { + /* Make sure the CRC error flag is cleared before we start */ + SPI_I2S_ClearFlag(spi_dev->cfg->regs, SPI_FLAG_CRCERR); + } + + dma_init.DMA_BufferSize = len; + DMA_Init(spi_dev->cfg->dma.rx.channel, &(dma_init)); + + /* + * Configure Tx channel + */ + + /* Start with the default configuration for this peripheral */ + dma_init = spi_dev->cfg->dma.tx.init; + + if (send_buffer != NULL) { + /* Enable memory addr. increment - bytes written into receive buffer */ + dma_init.DMA_MemoryBaseAddr = (uint32_t)send_buffer; + dma_init.DMA_MemoryInc = DMA_MemoryInc_Enable; + } else { + /* Disable memory addr. increment - bytes written into dummy buffer */ + spi_dev->tx_dummy_byte = 0xFF; + dma_init.DMA_MemoryBaseAddr = (uint32_t)&spi_dev->tx_dummy_byte; + dma_init.DMA_MemoryInc = DMA_MemoryInc_Disable; + } + + if (spi_dev->cfg->use_crc) { + /* The last byte of the payload will be replaced with the CRC8 */ + dma_init.DMA_BufferSize = len - 1; + } else { + dma_init.DMA_BufferSize = len; + } + + DMA_Init(spi_dev->cfg->dma.tx.channel, &(dma_init)); + + /* Enable DMA interrupt if callback function active */ + DMA_ITConfig(spi_dev->cfg->dma.rx.channel, DMA_IT_TC, (callback != NULL) ? ENABLE : DISABLE); + + /* Flush out the CRC registers */ + SPI_CalculateCRC(spi_dev->cfg->regs, DISABLE); + (void)SPI_GetCRC(spi_dev->cfg->regs, SPI_CRC_Rx); + SPI_I2S_ClearFlag(spi_dev->cfg->regs, SPI_FLAG_CRCERR); + + /* Make sure to flush out the receive buffer */ + (void)SPI_I2S_ReceiveData16(spi_dev->cfg->regs); + + if (spi_dev->cfg->use_crc) { + /* Need a 0->1 transition to reset the CRC logic */ + SPI_CalculateCRC(spi_dev->cfg->regs, ENABLE); + } + + /* Start DMA transfers */ + DMA_Cmd(spi_dev->cfg->dma.rx.channel, ENABLE); + DMA_Cmd(spi_dev->cfg->dma.tx.channel, ENABLE); + + /* Reenable the SPI device */ + SPI_Cmd(spi_dev->cfg->regs, ENABLE); + + if (callback) { + /* User has requested a callback, don't wait for the transfer to complete. */ + return 0; + } + + /* Wait until all bytes have been transmitted/received */ + while (DMA_GetCurrDataCounter(spi_dev->cfg->dma.rx.channel)) { + ; + } + + /* Wait for the final bytes of the transfer to complete, including CRC byte(s). */ + while (!(SPI_I2S_GetFlagStatus(spi_dev->cfg->regs, SPI_I2S_FLAG_TXE))) { + ; + } + + /* Wait for the final bytes of the transfer to complete, including CRC byte(s). */ + while (SPI_I2S_GetFlagStatus(spi_dev->cfg->regs, SPI_I2S_FLAG_BSY)) { + ; + } + + /* Check the CRC on the transfer if enabled. */ + if (spi_dev->cfg->use_crc) { + /* Check the SPI CRC error flag */ + if (SPI_I2S_GetFlagStatus(spi_dev->cfg->regs, SPI_FLAG_CRCERR)) { + return -4; + } + } + + /* No error */ + return 0; +} + +/** + * Check if a transfer is in progress + * \param[in] spi SPI number (0 or 1) + * \return >= 0 if no transfer is in progress + * \return -1 if disabled SPI port selected + * \return -2 if unsupported SPI port selected + * \return -3 if function has been called during an ongoing DMA transfer + */ +int32_t PIOS_SPI_Busy(uint32_t spi_id) +{ + struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id; + + bool valid = PIOS_SPI_validate(spi_dev); + + PIOS_Assert(valid) + + /* DMA buffer has data or SPI transmit register not empty or SPI is busy*/ + if (DMA_GetCurrDataCounter(spi_dev->cfg->dma.rx.channel) || + !SPI_I2S_GetFlagStatus(spi_dev->cfg->regs, SPI_I2S_FLAG_TXE) || + SPI_I2S_GetFlagStatus(spi_dev->cfg->regs, SPI_I2S_FLAG_BSY)) { + return -3; + } + + return 0; +} + +void PIOS_SPI_SetPrescalar(uint32_t spi_id, uint32_t prescaler) +{ + struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id; + + bool valid = PIOS_SPI_validate(spi_dev); + + PIOS_Assert(valid); + PIOS_Assert(IS_SPI_BAUDRATE_PRESCALER(prescaler)); + + spi_dev->cfg->regs->CR1 = (spi_dev->cfg->regs->CR1 & ~0x0038) | prescaler; +} + +void PIOS_SPI_IRQ_Handler(uint32_t spi_id) +{ + struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id; + + bool valid = PIOS_SPI_validate(spi_dev); + + PIOS_Assert(valid) + + DMA_ClearFlag(spi_dev->cfg->dma.irq.flags); + + /* Wait for the final bytes of the transfer to complete, including CRC byte(s). */ + while (!(SPI_I2S_GetFlagStatus(spi_dev->cfg->regs, SPI_I2S_FLAG_TXE))) { + ; + } + + /* Wait for the final bytes of the transfer to complete, including CRC byte(s). */ + while (SPI_I2S_GetFlagStatus(spi_dev->cfg->regs, SPI_I2S_FLAG_BSY)) { + ; + } + + if (spi_dev->callback != NULL) { + bool crc_ok = true; + uint8_t crc_val; + + if (SPI_I2S_GetFlagStatus(spi_dev->cfg->regs, SPI_FLAG_CRCERR)) { + crc_ok = false; + SPI_I2S_ClearFlag(spi_dev->cfg->regs, SPI_FLAG_CRCERR); + } + crc_val = SPI_GetCRC(spi_dev->cfg->regs, SPI_CRC_Rx); + spi_dev->callback(crc_ok, crc_val); + } +} + +#endif /* PIOS_INCLUDE_SPI */ + +/** + * @} + * @} + */ diff --git a/flight/pios/stm32f30x/pios_sys.c b/flight/pios/stm32f30x/pios_sys.c new file mode 100644 index 0000000000..45640400e0 --- /dev/null +++ b/flight/pios/stm32f30x/pios_sys.c @@ -0,0 +1,283 @@ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_SYS System Functions + * @brief PIOS System Initialization code + * @{ + * + * @file pios_sys.c + * @author Michael Smith Copyright (C) 2011 + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012. + * @author Tau Labs, http://taulabs.org, Copyright (C) 2012-2014 + * @brief Sets up basic STM32 system hardware, functions are called from Main. + * @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 + */ + +/* Project Includes */ +#include "pios.h" + +#if defined(PIOS_INCLUDE_SYS) + +#define MEM8(addr) (*((volatile uint8_t *)(addr))) + +/* Private Function Prototypes */ +static void NVIC_Configuration(void); + +/** + * Initialises all system peripherals + */ +void PIOS_SYS_Init(void) +{ + /* Setup STM32 system (RCC, clock, PLL and Flash configuration) - CMSIS Function */ + SystemInit(); + SystemCoreClockUpdate(); /* update SystemCoreClock for use elsewhere */ + + /* + * @todo might make sense to fetch the bus clocks and save them somewhere to avoid + * having to use the clunky get-all-clocks API everytime we need one. + */ + + /* Initialise Basic NVIC */ + /* do this early to ensure that we take exceptions in the right place */ + NVIC_Configuration(); + + /* Init the delay system */ + PIOS_DELAY_Init(); + + /* + * Turn on all the peripheral clocks. + * Micromanaging clocks makes no sense given the power situation in the system, so + * light up everything we might reasonably use here and just leave it on. + */ + RCC_AHBPeriphClockCmd( + RCC_AHBPeriph_GPIOA | + RCC_AHBPeriph_GPIOB | + RCC_AHBPeriph_GPIOC | + RCC_AHBPeriph_GPIOD | + RCC_AHBPeriph_GPIOE | + RCC_AHBPeriph_GPIOF | + RCC_AHBPeriph_TS | + RCC_AHBPeriph_CRC | + RCC_AHBPeriph_FLITF | + RCC_AHBPeriph_SRAM | + RCC_AHBPeriph_DMA2 | + RCC_AHBPeriph_DMA1 | + RCC_AHBPeriph_ADC34 | + RCC_AHBPeriph_ADC12 | + 0, ENABLE); + + RCC_APB1PeriphClockCmd( + RCC_APB1Periph_TIM2 | + RCC_APB1Periph_TIM3 | + RCC_APB1Periph_TIM4 | + RCC_APB1Periph_TIM6 | + RCC_APB1Periph_TIM7 | + RCC_APB1Periph_WWDG | + RCC_APB1Periph_SPI2 | + RCC_APB1Periph_SPI3 | + RCC_APB1Periph_USART2 | + RCC_APB1Periph_USART3 | + RCC_APB1Periph_UART4 | + RCC_APB1Periph_UART5 | + RCC_APB1Periph_I2C1 | + RCC_APB1Periph_I2C2 | + RCC_APB1Periph_USB | + RCC_APB1Periph_CAN1 | + RCC_APB1Periph_PWR | + RCC_APB1Periph_DAC | + 0, ENABLE); + + RCC_APB2PeriphClockCmd( + RCC_APB2Periph_TIM1 | + RCC_APB2Periph_TIM8 | + RCC_APB2Periph_TIM15 | + RCC_APB2Periph_TIM16 | + RCC_APB2Periph_TIM17 | + RCC_APB2Periph_USART1 | + RCC_APB2Periph_SPI1 | + RCC_APB2Periph_SYSCFG | + 0, ENABLE); + + /* + * Configure all pins as input / pullup to avoid issues with + * uncommitted pins, excepting special-function pins that we need to + * remain as-is. + */ + GPIO_InitTypeDef GPIO_InitStructure; + GPIO_StructInit(&GPIO_InitStructure); + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; // default is un-pulled input + + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All; +#if (PIOS_USB_ENABLED) + GPIO_InitStructure.GPIO_Pin &= ~(GPIO_Pin_11 | GPIO_Pin_12); // leave USB D+/D- alone +#endif + GPIO_InitStructure.GPIO_Pin &= ~(GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15); // leave JTAG pins alone + GPIO_Init(GPIOA, &GPIO_InitStructure); + + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All; + GPIO_Init(GPIOB, &GPIO_InitStructure); + GPIO_Init(GPIOC, &GPIO_InitStructure); + GPIO_Init(GPIOD, &GPIO_InitStructure); + GPIO_Init(GPIOE, &GPIO_InitStructure); + GPIO_Init(GPIOF, &GPIO_InitStructure); +} + +/** + * Shutdown PIOS and reset the microcontroller:
+ *
    + *
  • Disable all RTOS tasks + *
  • Disable all interrupts + *
  • Turn off all board LEDs + *
  • Reset STM32 + *
+ * \return < 0 if reset failed + */ +int32_t PIOS_SYS_Reset(void) +{ + // disable all interrupts + PIOS_IRQ_Disable(); + + // turn off all board LEDs +#if defined(PIOS_INCLUDE_LED) && defined(PIOS_LED_HEARTBEAT) + PIOS_LED_Off(PIOS_LED_HEARTBEAT); +#endif /* PIOS_LED_HEARTBEAT */ +#if defined(PIOS_INCLUDE_LED) && defined(PIOS_LED_ALARM) + PIOS_LED_Off(PIOS_LED_ALARM); +#endif /* PIOS_LED_ALARM */ + + /* XXX F10x port resets most (but not all) peripherals ... do we care? */ + + /* Reset STM32 */ + NVIC_SystemReset(); + + while (1) { + ; + } + + /* We will never reach this point */ + return -1; +} + +/** + * Returns the serial number as byte array + * param[out] pointer to a byte array which can store at least 12 bytes + * (12 bytes returned for STM32) + * return < 0 if feature not supported + */ +int32_t PIOS_SYS_SerialNumberGetBinary(uint8_t *array) +{ + int i; + + /* Stored in the so called "electronic signature" */ + for (i = 0; i < PIOS_SYS_SERIAL_NUM_BINARY_LEN; ++i) { + uint8_t b = MEM8(0x1ffff7ac + i); + + array[i] = b; + } + + /* No error */ + return 0; +} + +/** + * Returns the serial number as a string + * param[out] str pointer to a string which can store at least 32 digits + zero terminator! + * (24 digits returned for STM32) + * return < 0 if feature not supported + */ +int32_t PIOS_SYS_SerialNumberGet(char *str) +{ + int i; + + /* Stored in the so called "electronic signature" */ + for (i = 0; i < PIOS_SYS_SERIAL_NUM_ASCII_LEN; ++i) { + uint8_t b = MEM8(0x1ffff7ac + (i / 2)); + if (!(i & 1)) { + b >>= 4; + } + b &= 0x0f; + + str[i] = ((b > 9) ? ('A' - 10) : '0') + b; + } + str[i] = '\0'; + + /* No error */ + return 0; +} + +/** + * Configures Vector Table base location and SysTick + */ +static void NVIC_Configuration(void) +{ + /* Set the Vector Table base address as specified in .ld file */ + extern void *pios_isr_vector_table_base; + + NVIC_SetVectorTable((uint32_t)&pios_isr_vector_table_base, 0x0); + + /* 4 bits for Interrupt priorities so no sub priorities */ + NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4); + + /* Configure HCLK clock as SysTick clock source. */ + SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK); +} + +#ifdef USE_FULL_ASSERT +/** + * Reports the name of the source file and the source line number + * where the assert_param error has occurred. + * \param[in] file pointer to the source file name + * \param[in] line assert_param error line source number + * \retval None + */ +void assert_failed(uint8_t *file, uint32_t line) +{ + /* When serial debugging is implemented, use something like this. */ + /* printf("Wrong parameters value: file %s on line %d\r\n", file, line); */ + + /* Setup the LEDs to Alternate */ +#if defined(PIOS_LED_HEARTBEAT) + PIOS_LED_On(PIOS_LED_HEARTBEAT); +#endif /* PIOS_LED_HEARTBEAT */ +#if defined(PIOS_LED_ALARM) + PIOS_LED_Off(PIOS_LED_ALARM); +#endif /* PIOS_LED_ALARM */ + + /* Infinite loop */ + while (1) { +#if defined(PIOS_LED_HEARTBEAT) + PIOS_LED_Toggle(PIOS_LED_HEARTBEAT); +#endif /* PIOS_LED_HEARTBEAT */ +#if defined(PIOS_LED_ALARM) + PIOS_LED_Toggle(PIOS_LED_ALARM); +#endif /* PIOS_LED_ALARM */ + for (int i = 0; i < 1000000; i++) { + ; + } + } +} +#endif /* ifdef USE_FULL_ASSERT */ + +#endif /* if defined(PIOS_INCLUDE_SYS) */ + +/** + * @} + * @} + */ diff --git a/flight/pios/stm32f30x/pios_tim.c b/flight/pios/stm32f30x/pios_tim.c new file mode 100644 index 0000000000..93f4e2a6ad --- /dev/null +++ b/flight/pios/stm32f30x/pios_tim.c @@ -0,0 +1,371 @@ +#include "pios.h" + +#ifdef PIOS_INCLUDE_TIM + +#include "pios_tim_priv.h" + +enum pios_tim_dev_magic { + PIOS_TIM_DEV_MAGIC = 0x87654098, +}; + +struct pios_tim_dev { + enum pios_tim_dev_magic magic; + + const struct pios_tim_channel *channels; + uint8_t num_channels; + + const struct pios_tim_callbacks *callbacks; + uint32_t context; +}; + +#if 0 +static bool PIOS_TIM_validate(struct pios_tim_dev *tim_dev) +{ + return tim_dev->magic == PIOS_TIM_DEV_MAGIC; +} +#endif + +#if defined(PIOS_INCLUDE_FREERTOS) && 0 +static struct pios_tim_dev *PIOS_TIM_alloc(void) +{ + struct pios_tim_dev *tim_dev; + + tim_dev = (struct pios_tim_dev *)pios_malloc(sizeof(*tim_dev)); + if (!tim_dev) { + return NULL; + } + + tim_dev->magic = PIOS_TIM_DEV_MAGIC; + return tim_dev; +} +#else +static struct pios_tim_dev pios_tim_devs[PIOS_TIM_MAX_DEVS]; +static uint8_t pios_tim_num_devs; +static struct pios_tim_dev *PIOS_TIM_alloc(void) +{ + struct pios_tim_dev *tim_dev; + + if (pios_tim_num_devs >= PIOS_TIM_MAX_DEVS) { + return NULL; + } + + tim_dev = &pios_tim_devs[pios_tim_num_devs++]; + tim_dev->magic = PIOS_TIM_DEV_MAGIC; + + return tim_dev; +} +#endif /* if defined(PIOS_INCLUDE_FREERTOS) && 0 */ + + +int32_t PIOS_TIM_InitClock(const struct pios_tim_clock_cfg *cfg) +{ + PIOS_DEBUG_Assert(cfg); + + /* Configure the dividers for this timer */ + TIM_TimeBaseInit(cfg->timer, (TIM_TimeBaseInitTypeDef *)cfg->time_base_init); + + /* Configure internal timer clocks */ + TIM_InternalClockConfig(cfg->timer); + + /* Enable timers */ + TIM_Cmd(cfg->timer, ENABLE); + + /* Enable Interrupts */ + NVIC_Init((NVIC_InitTypeDef *)&cfg->irq.init); + + // Advanced timers TIM1 & TIM8 need special handling: + // There are up to 4 separate interrupts handlers for each advanced timer, but + // pios_tim_clock_cfg has provision for only one irq init, so we take care here + // to enable additional irq channels that we intend to use. + + if (cfg->timer == TIM1) { + NVIC_InitTypeDef init = cfg->irq.init; + init.NVIC_IRQChannel = TIM1_UP_TIM16_IRQn; + NVIC_Init(&init); + } else if (cfg->timer == TIM8) { + NVIC_InitTypeDef init = cfg->irq.init; + init.NVIC_IRQChannel = TIM8_UP_IRQn; + NVIC_Init(&init); + } + + return 0; +} + +int32_t PIOS_TIM_InitChannels(uint32_t *tim_id, const struct pios_tim_channel *channels, uint8_t num_channels, const struct pios_tim_callbacks *callbacks, uint32_t context) +{ + PIOS_Assert(channels); + PIOS_Assert(num_channels); + + struct pios_tim_dev *tim_dev; + tim_dev = (struct pios_tim_dev *)PIOS_TIM_alloc(); + if (!tim_dev) { + goto out_fail; + } + + /* Bind the configuration to the device instance */ + tim_dev->channels = channels; + tim_dev->num_channels = num_channels; + tim_dev->callbacks = callbacks; + tim_dev->context = context; + + /* Configure the pins */ + for (uint8_t i = 0; i < num_channels; i++) { + const struct pios_tim_channel *chan = &(channels[i]); + + GPIO_Init(chan->pin.gpio, (GPIO_InitTypeDef *)&chan->pin.init); + + if (chan->remap) { + GPIO_PinAFConfig(chan->pin.gpio, chan->pin.pin_source, chan->remap); + } + } + + *tim_id = (uint32_t)tim_dev; + + return 0; + +out_fail: + return -1; +} + +static void PIOS_TIM_generic_irq_handler(TIM_TypeDef *timer) +{ + /* Check for an overflow event on this timer */ + bool overflow_event = 0; + uint16_t overflow_count = false; + + if (TIM_GetITStatus(timer, TIM_IT_Update) == SET) { + TIM_ClearITPendingBit(timer, TIM_IT_Update); + overflow_count = timer->ARR; + overflow_event = true; + } + + /* Iterate over all registered clients of the TIM layer to find channels on this timer */ + for (uint8_t i = 0; i < pios_tim_num_devs; i++) { + const struct pios_tim_dev *tim_dev = &pios_tim_devs[i]; + + if (!tim_dev->channels || tim_dev->num_channels == 0) { + /* No channels to process on this client */ + continue; + } + + for (uint8_t j = 0; j < tim_dev->num_channels; j++) { + const struct pios_tim_channel *chan = &tim_dev->channels[j]; + + if (chan->timer != timer) { + /* channel is not on this timer */ + continue; + } + + /* Figure out which interrupt bit we should be looking at */ + uint16_t timer_it; + switch (chan->timer_chan) { + case TIM_Channel_1: + timer_it = TIM_IT_CC1; + break; + case TIM_Channel_2: + timer_it = TIM_IT_CC2; + break; + case TIM_Channel_3: + timer_it = TIM_IT_CC3; + break; + case TIM_Channel_4: + timer_it = TIM_IT_CC4; + break; + default: + PIOS_Assert(0); + break; + } + + bool edge_event; + uint16_t edge_count; + if (TIM_GetITStatus(chan->timer, timer_it) == SET) { + TIM_ClearITPendingBit(chan->timer, timer_it); + + /* Read the current counter */ + switch (chan->timer_chan) { + case TIM_Channel_1: + edge_count = TIM_GetCapture1(chan->timer); + break; + case TIM_Channel_2: + edge_count = TIM_GetCapture2(chan->timer); + break; + case TIM_Channel_3: + edge_count = TIM_GetCapture3(chan->timer); + break; + case TIM_Channel_4: + edge_count = TIM_GetCapture4(chan->timer); + break; + default: + PIOS_Assert(0); + break; + } + edge_event = true; + } else { + edge_event = false; + edge_count = 0; + } + + if (!tim_dev->callbacks) { + /* No callbacks registered, we're done with this channel */ + continue; + } + + /* Generate the appropriate callbacks */ + if (overflow_event & edge_event) { + /* + * When both edge and overflow happen in the same interrupt, we + * need a heuristic to determine the order of the edge and overflow + * events so that the callbacks happen in the right order. If we + * get the order wrong, our pulse width calculations could be off by up + * to ARR ticks. That could be bad. + * + * Heuristic: If the edge_count is < 32 ticks above zero then we assume the + * edge happened just after the overflow. + */ + + if (edge_count < 32) { + /* Call the overflow callback first */ + if (tim_dev->callbacks->overflow) { + (*tim_dev->callbacks->overflow)((uint32_t)tim_dev, + tim_dev->context, + j, + overflow_count); + } + /* Call the edge callback second */ + if (tim_dev->callbacks->edge) { + (*tim_dev->callbacks->edge)((uint32_t)tim_dev, + tim_dev->context, + j, + edge_count); + } + } else { + /* Call the edge callback first */ + if (tim_dev->callbacks->edge) { + (*tim_dev->callbacks->edge)((uint32_t)tim_dev, + tim_dev->context, + j, + edge_count); + } + /* Call the overflow callback second */ + if (tim_dev->callbacks->overflow) { + (*tim_dev->callbacks->overflow)((uint32_t)tim_dev, + tim_dev->context, + j, + overflow_count); + } + } + } else if (overflow_event && tim_dev->callbacks->overflow) { + (*tim_dev->callbacks->overflow)((uint32_t)tim_dev, + tim_dev->context, + j, + overflow_count); + } else if (edge_event && tim_dev->callbacks->edge) { + (*tim_dev->callbacks->edge)((uint32_t)tim_dev, + tim_dev->context, + j, + edge_count); + } + } + } +} + +/* Bind Interrupt Handlers + * + * Map all valid TIM IRQs to the common interrupt handler + * and give it enough context to properly demux the various timers + */ +void TIM1_CC_IRQHandler(void) __attribute__((alias("PIOS_TIM_1_CC_irq_handler"))); +static void PIOS_TIM_1_CC_irq_handler(void) +{ + PIOS_TIM_generic_irq_handler(TIM1); +} + +// The rest of TIM1 interrupts are overlapped +void TIM1_BRK_TIM15_IRQHandler(void) __attribute__((alias("PIOS_TIM_1_BRK_TIM_15_irq_handler"))); +static void PIOS_TIM_1_BRK_TIM_15_irq_handler(void) +{ + if (TIM_GetITStatus(TIM1, TIM_IT_Break)) { + PIOS_TIM_generic_irq_handler(TIM1); + } else if (TIM_GetITStatus(TIM15, TIM_IT_Update | TIM_IT_CC1 | TIM_IT_CC2 | TIM_IT_CC3 | TIM_IT_CC4 | TIM_IT_COM | TIM_IT_Trigger | TIM_IT_Break)) { + PIOS_TIM_generic_irq_handler(TIM15); + } +} + +void TIM1_UP_TIM16_IRQHandler(void) __attribute__((alias("PIOS_TIM_1_UP_TIM_16_irq_handler"))); +static void PIOS_TIM_1_UP_TIM_16_irq_handler(void) +{ + if (TIM_GetITStatus(TIM1, TIM_IT_Update)) { + PIOS_TIM_generic_irq_handler(TIM1); + } else if (TIM_GetITStatus(TIM16, TIM_IT_Update | TIM_IT_CC1 | TIM_IT_CC2 | TIM_IT_CC3 | TIM_IT_CC4 | TIM_IT_COM | TIM_IT_Trigger | TIM_IT_Break)) { + PIOS_TIM_generic_irq_handler(TIM16); + } +} +void TIM1_TRG_COM_TIM17_IRQHandler(void) __attribute__((alias("PIOS_TIM_1_TRG_COM_TIM_17_irq_handler"))); +static void PIOS_TIM_1_TRG_COM_TIM_17_irq_handler(void) +{ + if (TIM_GetITStatus(TIM1, TIM_IT_Trigger | TIM_IT_COM)) { + PIOS_TIM_generic_irq_handler(TIM1); + } else if (TIM_GetITStatus(TIM17, TIM_IT_Update | TIM_IT_CC1 | TIM_IT_CC2 | TIM_IT_CC3 | TIM_IT_CC4 | TIM_IT_COM | TIM_IT_Trigger | TIM_IT_Break)) { + PIOS_TIM_generic_irq_handler(TIM17); + } +} + +void TIM2_IRQHandler(void) __attribute__((alias("PIOS_TIM_2_irq_handler"))); +static void PIOS_TIM_2_irq_handler(void) +{ + PIOS_TIM_generic_irq_handler(TIM2); +} + +void TIM3_IRQHandler(void) __attribute__((alias("PIOS_TIM_3_irq_handler"))); +static void PIOS_TIM_3_irq_handler(void) +{ + PIOS_TIM_generic_irq_handler(TIM3); +} + +void TIM4_IRQHandler(void) __attribute__((alias("PIOS_TIM_4_irq_handler"))); +static void PIOS_TIM_4_irq_handler(void) +{ + PIOS_TIM_generic_irq_handler(TIM4); +} + +void TIM6_DAC_IRQHandler(void) __attribute__((alias("PIOS_TIM_6_DAC_irq_handler"))); +static void PIOS_TIM_6_DAC_irq_handler(void) +{ + // What about DAC irq? + if (TIM_GetITStatus(TIM6, TIM_IT_Update | TIM_IT_CC1 | TIM_IT_CC2 | TIM_IT_CC3 | TIM_IT_CC4 | TIM_IT_COM | TIM_IT_Trigger | TIM_IT_Break)) { + PIOS_TIM_generic_irq_handler(TIM6); + } +} + +void TIM7_IRQHandler(void) __attribute__((alias("PIOS_TIM_7_irq_handler"))); +static void PIOS_TIM_7_irq_handler(void) +{ + PIOS_TIM_generic_irq_handler(TIM7); +} + +void TIM8_CC_IRQHandler(void) __attribute__((alias("PIOS_TIM_8_CC_irq_handler"))); +static void PIOS_TIM_8_CC_irq_handler(void) +{ + PIOS_TIM_generic_irq_handler(TIM8); +} + +void TIM8_BRK_IRQHandler(void) __attribute__((alias("PIOS_TIM_8_BRK_irq_handler"))); +static void PIOS_TIM_8_BRK_irq_handler(void) +{ + PIOS_TIM_generic_irq_handler(TIM8); +} + +void TIM8_UP_IRQHandler(void) __attribute__((alias("PIOS_TIM_8_UP_irq_handler"))); +static void PIOS_TIM_8_UP_irq_handler(void) +{ + PIOS_TIM_generic_irq_handler(TIM8); +} + +void TIM8_TRG_COM_IRQHandler(void) __attribute__((alias("PIOS_TIM_8_TRG_COM_irq_handler"))); +static void PIOS_TIM_8_TRG_COM_irq_handler(void) +{ + PIOS_TIM_generic_irq_handler(TIM8); +} + + +#endif /* PIOS_INCLUDE_TIM */ diff --git a/flight/pios/stm32f30x/pios_usart.c b/flight/pios/stm32f30x/pios_usart.c new file mode 100644 index 0000000000..fb4d75329d --- /dev/null +++ b/flight/pios/stm32f30x/pios_usart.c @@ -0,0 +1,528 @@ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_USART USART Functions + * @brief PIOS interface for USART port + * @{ + * + * @file pios_usart.c + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief USART commands. Inits USARTs, controls USARTs & Interupt handlers. (STM32 dependent) + * @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.h" + +#ifdef PIOS_INCLUDE_USART + +#include + +/* Provide a COM driver */ +static void PIOS_USART_ChangeBaud(uint32_t usart_id, uint32_t baud); +static void PIOS_USART_ChangeConfig(uint32_t usart_id, enum PIOS_COM_Word_Length word_len, enum PIOS_COM_Parity parity, enum PIOS_COM_StopBits stop_bits, uint32_t baud_rate); +static void PIOS_USART_RegisterRxCallback(uint32_t usart_id, pios_com_callback rx_in_cb, uint32_t context); +static void PIOS_USART_RegisterTxCallback(uint32_t usart_id, pios_com_callback tx_out_cb, uint32_t context); +static void PIOS_USART_TxStart(uint32_t usart_id, uint16_t tx_bytes_avail); +static void PIOS_USART_RxStart(uint32_t usart_id, uint16_t rx_bytes_avail); +static int32_t PIOS_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param); + +const struct pios_com_driver pios_usart_com_driver = { + .set_baud = PIOS_USART_ChangeBaud, + .set_config = PIOS_USART_ChangeConfig, + .tx_start = PIOS_USART_TxStart, + .rx_start = PIOS_USART_RxStart, + .bind_tx_cb = PIOS_USART_RegisterTxCallback, + .bind_rx_cb = PIOS_USART_RegisterRxCallback, + .ioctl = PIOS_USART_Ioctl, +}; + +enum pios_usart_dev_magic { + PIOS_USART_DEV_MAGIC = 0x11223344, +}; + +struct pios_usart_dev { + enum pios_usart_dev_magic magic; + const struct pios_usart_cfg *cfg; + USART_InitTypeDef init; + pios_com_callback rx_in_cb; + uint32_t rx_in_context; + pios_com_callback tx_out_cb; + uint32_t tx_out_context; + + uint32_t rx_dropped; + uint8_t irq_channel; +}; + +static bool PIOS_USART_validate(struct pios_usart_dev *usart_dev) +{ + return usart_dev->magic == PIOS_USART_DEV_MAGIC; +} + +static int32_t PIOS_USART_SetIrqPrio(struct pios_usart_dev *usart_dev, uint8_t irq_prio) +{ + NVIC_InitTypeDef init = { + .NVIC_IRQChannel = usart_dev->irq_channel, + .NVIC_IRQChannelPreemptionPriority = irq_prio, + .NVIC_IRQChannelCmd = ENABLE, + }; + + NVIC_Init(&init); + + return 0; +} + +#if defined(PIOS_INCLUDE_FREERTOS) +static struct pios_usart_dev *PIOS_USART_alloc(void) +{ + struct pios_usart_dev *usart_dev; + + usart_dev = (struct pios_usart_dev *)pios_malloc(sizeof(struct pios_usart_dev)); + if (!usart_dev) { + return NULL; + } + + memset(usart_dev, 0, sizeof(struct pios_usart_dev)); + usart_dev->magic = PIOS_USART_DEV_MAGIC; + return usart_dev; +} +#else +static struct pios_usart_dev pios_usart_devs[PIOS_USART_MAX_DEVS]; +static uint8_t pios_usart_num_devs; +static struct pios_usart_dev *PIOS_USART_alloc(void) +{ + struct pios_usart_dev *usart_dev; + + if (pios_usart_num_devs >= PIOS_USART_MAX_DEVS) { + return NULL; + } + + usart_dev = &pios_usart_devs[pios_usart_num_devs++]; + + memset(usart_dev, 0, sizeof(struct pios_usart_dev)); + usart_dev->magic = PIOS_USART_DEV_MAGIC; + + return usart_dev; +} +#endif /* if defined(PIOS_INCLUDE_FREERTOS) */ + +/* Bind Interrupt Handlers + * + * Map all valid USART IRQs to the common interrupt handler + * and provide storage for a 32-bit device id IRQ to map + * each physical IRQ to a specific registered device instance. + */ +static void PIOS_USART_generic_irq_handler(uint32_t usart_id); + +static uint32_t PIOS_USART_1_id; +void USART1_EXTI25_IRQHandler(void) __attribute__((alias("PIOS_USART_1_irq_handler"))); +static void PIOS_USART_1_irq_handler(void) +{ + PIOS_USART_generic_irq_handler(PIOS_USART_1_id); +} + +static uint32_t PIOS_USART_2_id; +void USART2_EXTI26_IRQHandler(void) __attribute__((alias("PIOS_USART_2_irq_handler"))); +static void PIOS_USART_2_irq_handler(void) +{ + PIOS_USART_generic_irq_handler(PIOS_USART_2_id); +} + +static uint32_t PIOS_USART_3_id; +void USART3_EXTI28_IRQHandler(void) __attribute__((alias("PIOS_USART_3_irq_handler"))); +static void PIOS_USART_3_irq_handler(void) +{ + PIOS_USART_generic_irq_handler(PIOS_USART_3_id); +} + + +static uint32_t PIOS_UART_4_id; +void UART4_EXTI34_IRQHandler(void) __attribute__((alias("PIOS_UART_4_irq_handler"))); +static void PIOS_UART_4_irq_handler(void) +{ + PIOS_USART_generic_irq_handler(PIOS_UART_4_id); +} + +static uint32_t PIOS_UART_5_id; +void UART5_EXTI35_IRQHandler(void) __attribute__((alias("PIOS_UART_5_irq_handler"))); +static void PIOS_UART_5_irq_handler(void) +{ + PIOS_USART_generic_irq_handler(PIOS_UART_5_id); +} + +/** + * Initialise a single USART device + */ +int32_t PIOS_USART_Init(uint32_t *usart_id, const struct pios_usart_cfg *cfg) +{ + PIOS_DEBUG_Assert(usart_id); + PIOS_DEBUG_Assert(cfg); + + struct pios_usart_dev *usart_dev; + + usart_dev = (struct pios_usart_dev *)PIOS_USART_alloc(); + if (!usart_dev) { + goto out_fail; + } + + /* Bind the configuration to the device instance */ + usart_dev->cfg = cfg; + + /* Set some sane defaults */ + USART_StructInit(&usart_dev->init); + + /* We will set modes later, depending on installed callbacks */ + usart_dev->init.USART_Mode = 0; + + *usart_id = (uint32_t)usart_dev; + + /* Configure USART Interrupts */ + switch ((uint32_t)usart_dev->cfg->regs) { + case (uint32_t)USART1: + PIOS_USART_1_id = (uint32_t)usart_dev; + usart_dev->irq_channel = USART1_IRQn; + break; + case (uint32_t)USART2: + PIOS_USART_2_id = (uint32_t)usart_dev; + usart_dev->irq_channel = USART2_IRQn; + break; + case (uint32_t)USART3: + PIOS_USART_3_id = (uint32_t)usart_dev; + usart_dev->irq_channel = USART3_IRQn; + break; + case (uint32_t)UART4: + PIOS_UART_4_id = (uint32_t)usart_dev; + usart_dev->irq_channel = UART4_IRQn; + break; + case (uint32_t)UART5: + PIOS_UART_5_id = (uint32_t)usart_dev; + usart_dev->irq_channel = UART5_IRQn; + break; + } + + PIOS_USART_SetIrqPrio(usart_dev, PIOS_IRQ_PRIO_MID); + + /* Disable overrun detection */ + USART_OverrunDetectionConfig(usart_dev->cfg->regs, USART_OVRDetection_Disable); + + return 0; + +out_fail: + return -1; +} + +static void PIOS_USART_Setup(struct pios_usart_dev *usart_dev) +{ + /* Configure RX GPIO */ + if ((usart_dev->init.USART_Mode & USART_Mode_Rx) && (usart_dev->cfg->rx.gpio)) { + if (usart_dev->cfg->remap) { + GPIO_PinAFConfig(usart_dev->cfg->rx.gpio, + usart_dev->cfg->rx.pin_source, + usart_dev->cfg->remap); + } + + GPIO_Init(usart_dev->cfg->rx.gpio, (GPIO_InitTypeDef *)&usart_dev->cfg->rx.init); + + USART_ITConfig(usart_dev->cfg->regs, USART_IT_RXNE, ENABLE); + } + + /* Configure TX GPIO */ + if ((usart_dev->init.USART_Mode & USART_Mode_Tx) && usart_dev->cfg->tx.gpio) { + if (usart_dev->cfg->remap) { + GPIO_PinAFConfig(usart_dev->cfg->tx.gpio, + usart_dev->cfg->tx.pin_source, + usart_dev->cfg->remap); + } + + GPIO_Init(usart_dev->cfg->tx.gpio, (GPIO_InitTypeDef *)&usart_dev->cfg->tx.init); + } + + /* Write new configuration */ + USART_Init(usart_dev->cfg->regs, &usart_dev->init); + + /* + * Re enable USART. + */ + USART_Cmd(usart_dev->cfg->regs, ENABLE); +} + +static void PIOS_USART_RxStart(uint32_t usart_id, __attribute__((unused)) uint16_t rx_bytes_avail) +{ + struct pios_usart_dev *usart_dev = (struct pios_usart_dev *)usart_id; + + bool valid = PIOS_USART_validate(usart_dev); + + PIOS_Assert(valid); + + USART_ITConfig(usart_dev->cfg->regs, USART_IT_RXNE, ENABLE); +} +static void PIOS_USART_TxStart(uint32_t usart_id, __attribute__((unused)) uint16_t tx_bytes_avail) +{ + struct pios_usart_dev *usart_dev = (struct pios_usart_dev *)usart_id; + + bool valid = PIOS_USART_validate(usart_dev); + + PIOS_Assert(valid); + + USART_ITConfig(usart_dev->cfg->regs, USART_IT_TXE, ENABLE); +} + +/** + * Changes the baud rate of the USART peripheral without re-initialising. + * \param[in] usart_id USART name (GPS, TELEM, AUX) + * \param[in] baud Requested baud rate + */ +static void PIOS_USART_ChangeBaud(uint32_t usart_id, uint32_t baud) +{ + struct pios_usart_dev *usart_dev = (struct pios_usart_dev *)usart_id; + + bool valid = PIOS_USART_validate(usart_dev); + + PIOS_Assert(valid); + + usart_dev->init.USART_BaudRate = baud; + + PIOS_USART_Setup(usart_dev); +} + +/** + * Changes configuration of the USART peripheral without re-initialising. + * \param[in] usart_id USART name (GPS, TELEM, AUX) + * \param[in] word_len Requested word length + * \param[in] stop_bits Requested stop bits + * \param[in] parity Requested parity + * + */ +static void PIOS_USART_ChangeConfig(uint32_t usart_id, + enum PIOS_COM_Word_Length word_len, + enum PIOS_COM_Parity parity, + enum PIOS_COM_StopBits stop_bits, + uint32_t baud_rate) +{ + struct pios_usart_dev *usart_dev = (struct pios_usart_dev *)usart_id; + + bool valid = PIOS_USART_validate(usart_dev); + + PIOS_Assert(valid); + + switch (word_len) { + case PIOS_COM_Word_length_8b: + usart_dev->init.USART_WordLength = USART_WordLength_8b; + break; + case PIOS_COM_Word_length_9b: + usart_dev->init.USART_WordLength = USART_WordLength_9b; + break; + default: + break; + } + + switch (stop_bits) { + case PIOS_COM_StopBits_1: + usart_dev->init.USART_StopBits = USART_StopBits_1; + break; + case PIOS_COM_StopBits_1_5: + usart_dev->init.USART_StopBits = USART_StopBits_1_5; + break; + case PIOS_COM_StopBits_2: + usart_dev->init.USART_StopBits = USART_StopBits_2; + break; + default: + break; + } + + switch (parity) { + case PIOS_COM_Parity_No: + usart_dev->init.USART_Parity = USART_Parity_No; + break; + case PIOS_COM_Parity_Even: + usart_dev->init.USART_Parity = USART_Parity_Even; + break; + case PIOS_COM_Parity_Odd: + usart_dev->init.USART_Parity = USART_Parity_Odd; + break; + default: + break; + } + + if (baud_rate) { + usart_dev->init.USART_BaudRate = baud_rate; + } + + PIOS_USART_Setup(usart_dev); +} + + +static void PIOS_USART_RegisterRxCallback(uint32_t usart_id, pios_com_callback rx_in_cb, uint32_t context) +{ + struct pios_usart_dev *usart_dev = (struct pios_usart_dev *)usart_id; + + bool valid = PIOS_USART_validate(usart_dev); + + PIOS_Assert(valid); + + /* + * Order is important in these assignments since ISR uses _cb + * field to determine if it's ok to dereference _cb and _context + */ + usart_dev->rx_in_context = context; + usart_dev->rx_in_cb = rx_in_cb; + + usart_dev->init.USART_Mode |= USART_Mode_Rx; + + PIOS_USART_Setup(usart_dev); +} + +static void PIOS_USART_RegisterTxCallback(uint32_t usart_id, pios_com_callback tx_out_cb, uint32_t context) +{ + struct pios_usart_dev *usart_dev = (struct pios_usart_dev *)usart_id; + + bool valid = PIOS_USART_validate(usart_dev); + + PIOS_Assert(valid); + + /* + * Order is important in these assignments since ISR uses _cb + * field to determine if it's ok to dereference _cb and _context + */ + usart_dev->tx_out_context = context; + usart_dev->tx_out_cb = tx_out_cb; + + usart_dev->init.USART_Mode |= USART_Mode_Tx; + + PIOS_USART_Setup(usart_dev); +} + +static void PIOS_USART_generic_irq_handler(uint32_t usart_id) +{ + struct pios_usart_dev *usart_dev = (struct pios_usart_dev *)usart_id; + + bool valid = PIOS_USART_validate(usart_dev); + + PIOS_Assert(valid); + + /* Force read of dr after sr to make sure to clear error flags */ + volatile uint16_t sr = usart_dev->cfg->regs->ISR; + volatile uint8_t dr = usart_dev->cfg->regs->RDR; + + /* Check if RXNE flag is set */ + bool rx_need_yield = false; + if (sr & USART_ISR_RXNE) { + uint8_t byte = dr; + if (usart_dev->rx_in_cb) { + uint16_t rc; + rc = (usart_dev->rx_in_cb)(usart_dev->rx_in_context, &byte, 1, NULL, &rx_need_yield); + if (rc < 1) { + /* Lost bytes on rx */ + usart_dev->rx_dropped += 1; + } + } + } + + /* Check if TXE flag is set */ + bool tx_need_yield = false; + if (sr & USART_ISR_TXE) { + if (usart_dev->tx_out_cb) { + uint8_t b; + uint16_t bytes_to_send; + + bytes_to_send = (usart_dev->tx_out_cb)(usart_dev->tx_out_context, &b, 1, NULL, &tx_need_yield); + + if (bytes_to_send > 0) { + /* Send the byte we've been given */ + usart_dev->cfg->regs->TDR = b; + } else { + /* No bytes to send, disable TXE interrupt */ + USART_ITConfig(usart_dev->cfg->regs, USART_IT_TXE, DISABLE); + } + } else { + /* No bytes to send, disable TXE interrupt */ + USART_ITConfig(usart_dev->cfg->regs, USART_IT_TXE, DISABLE); + } + } + +#if defined(PIOS_INCLUDE_FREERTOS) + if (rx_need_yield || tx_need_yield) { + vPortYield(); + } +#endif /* PIOS_INCLUDE_FREERTOS */ +} + +static int32_t PIOS_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param) +{ + struct pios_usart_dev *usart_dev = (struct pios_usart_dev *)usart_id; + + bool valid = PIOS_USART_validate(usart_dev); + + PIOS_Assert(valid); + + /* some sort of locking would be great to have */ + + uint32_t cr1_ue = usart_dev->cfg->regs->CR1 & USART_CR1_UE; + + switch (ctl) { + case PIOS_IOCTL_USART_SET_INVERTED: + { + enum PIOS_USART_Inverted inverted = *(enum PIOS_USART_Inverted *)param; + + usart_dev->cfg->regs->CR1 &= ~((uint32_t)USART_CR1_UE); + + if (usart_dev->cfg->rx.gpio != 0) { + GPIO_InitTypeDef gpioInit = usart_dev->cfg->rx.init; + + gpioInit.GPIO_PuPd = (inverted & PIOS_USART_Inverted_Rx) ? GPIO_PuPd_DOWN : GPIO_PuPd_UP; + + GPIO_Init(usart_dev->cfg->rx.gpio, &gpioInit); + + USART_InvPinCmd(usart_dev->cfg->regs, USART_InvPin_Rx, (inverted & PIOS_USART_Inverted_Rx) ? ENABLE : DISABLE); + } + + if (usart_dev->cfg->tx.gpio != 0) { + USART_InvPinCmd(usart_dev->cfg->regs, USART_InvPin_Tx, (inverted & PIOS_USART_Inverted_Tx) ? ENABLE : DISABLE); + } + } + break; + case PIOS_IOCTL_USART_SET_SWAPPIN: + usart_dev->cfg->regs->CR1 &= ~((uint32_t)USART_CR1_UE); + USART_SWAPPinCmd(usart_dev->cfg->regs, *(bool *)param ? ENABLE : DISABLE); + break; + case PIOS_IOCTL_USART_SET_HALFDUPLEX: + usart_dev->cfg->regs->CR1 &= ~((uint32_t)USART_CR1_UE); + USART_HalfDuplexCmd(usart_dev->cfg->regs, *(bool *)param ? ENABLE : DISABLE); + break; + case PIOS_IOCTL_USART_GET_RXGPIO: + *(struct stm32_gpio *)param = usart_dev->cfg->rx; + break; + case PIOS_IOCTL_USART_GET_TXGPIO: + *(struct stm32_gpio *)param = usart_dev->cfg->tx; + break; + default: + return -1; + } + + usart_dev->cfg->regs->CR1 |= cr1_ue; + + return 0; +} + +#endif /* PIOS_INCLUDE_USART */ + +/** + * @} + * @} + */ diff --git a/flight/pios/stm32f30x/pios_usb.c b/flight/pios/stm32f30x/pios_usb.c new file mode 100644 index 0000000000..63b5c5db2b --- /dev/null +++ b/flight/pios/stm32f30x/pios_usb.c @@ -0,0 +1,290 @@ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_USB USB Setup Functions + * @brief PIOS USB device implementation + * @{ + * + * @file pios_usb.c + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @author Tau Labs, http://taulabs.org, Copyright (C) 2012-2013 + * @brief USB device functions (STM32 dependent code) + * @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 + */ + +/* Project Includes */ +#include "pios.h" + +#if defined(PIOS_INCLUDE_USB) + +#include "usb_lib.h" +#include "pios_usb_board_data.h" + +#include "pios_usb.h" +#include "pios_usb_priv.h" + + +/* Rx/Tx status */ +static bool transfer_possible = false; + +/* USB activity detection */ +static volatile bool sof_seen_since_reset = false; + +enum pios_usb_dev_magic { + PIOS_USB_DEV_MAGIC = 0x17365904, +}; + +struct pios_usb_dev { + enum pios_usb_dev_magic magic; + const struct pios_usb_cfg *cfg; +}; + +/** + * @brief Validate the usb device structure + * @returns 0 if valid device or -1 otherwise + */ +static int32_t PIOS_USB_validate(struct pios_usb_dev *usb_dev) +{ + if (usb_dev == NULL) { + return -1; + } + + if (usb_dev->magic != PIOS_USB_DEV_MAGIC) { + return -1; + } + + return 0; +} + +#ifdef PIOS_INCLUDE_FREERTOS +static struct pios_usb_dev *PIOS_USB_alloc(void) +{ + struct pios_usb_dev *usb_dev; + + usb_dev = (struct pios_usb_dev *)pios_malloc(sizeof(*usb_dev)); + if (!usb_dev) { + return NULL; + } + + usb_dev->magic = PIOS_USB_DEV_MAGIC; + return usb_dev; +} +#else +static struct pios_usb_dev pios_usb_devs[PIOS_USB_MAX_DEVS]; +static uint8_t pios_usb_num_devs; +static struct pios_usb_dev *PIOS_USB_alloc(void) +{ + struct pios_usb_dev *usb_dev; + + if (pios_usb_num_devs >= PIOS_USB_MAX_DEVS) { + return NULL; + } + + usb_dev = &pios_usb_devs[pios_usb_num_devs++]; + usb_dev->magic = PIOS_USB_DEV_MAGIC; + + return usb_dev; +} +#endif /* ifdef PIOS_INCLUDE_FREERTOS */ + +/** + * Initialises USB COM layer + * \return < 0 if initialisation failed + * \note Applications shouldn't call this function directly, instead please use \ref PIOS_COM layer functions + */ +static uint32_t pios_usb_com_id; +int32_t PIOS_USB_Init(uint32_t *usb_id, const struct pios_usb_cfg *cfg) +{ + PIOS_Assert(usb_id); + PIOS_Assert(cfg); + + struct pios_usb_dev *usb_dev; + + usb_dev = (struct pios_usb_dev *)PIOS_USB_alloc(); + if (!usb_dev) { + goto out_fail; + } + + /* Bind the configuration to the device instance */ + usb_dev->cfg = cfg; + + PIOS_USB_Reenumerate(); + + /* + * This is a horrible hack to make this available to + * the interrupt callbacks. This should go away ASAP. + */ + pios_usb_com_id = (uintptr_t)usb_dev; + + /* Enable the USB Interrupts */ + NVIC_Init((NVIC_InitTypeDef *)&usb_dev->cfg->irq.init); + + /* Configure USB D-/D+ (DM/DP) pins */ + GPIO_InitTypeDef GPIO_InitStructure; + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; + GPIO_Init(GPIOA, &GPIO_InitStructure); + + GPIO_PinAFConfig(GPIOA, GPIO_PinSource11, GPIO_AF_14); + GPIO_PinAFConfig(GPIOA, GPIO_PinSource12, GPIO_AF_14); + + /* Configure VBUS sense pin */ + if (usb_dev->cfg->vsense.gpio) { + GPIO_Init(usb_dev->cfg->vsense.gpio, (GPIO_InitTypeDef *)&usb_dev->cfg->vsense.init); + } + + /* Select USBCLK source */ + RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_1Div5); + /* Enable the USB clock */ + RCC_APB1PeriphClockCmd(RCC_APB1Periph_USB, ENABLE); + + USB_Init(); + USB_SIL_Init(); + + *usb_id = (uintptr_t)usb_dev; + + return 0; /* No error */ + +out_fail: + return -1; +} + +/** + * This function is called by the USB driver on cable connection/disconnection + * \param[in] connected connection status (1 if connected) + * \return < 0 on errors + * \note Applications shouldn't call this function directly, instead please use \ref PIOS_COM layer functions + */ +int32_t PIOS_USB_ChangeConnectionState(bool Connected) +{ + // In all cases: re-initialise USB HID driver + if (Connected) { + transfer_possible = true; + + // TODO: Check SetEPRxValid(ENDP1); + +#if defined(USB_LED_ON) + USB_LED_ON; // turn the USB led on +#endif + } else { + // Cable disconnected: disable transfers + transfer_possible = false; + +#if defined(USB_LED_OFF) + USB_LED_OFF; // turn the USB led off +#endif + } + + return 0; +} + +int32_t PIOS_USB_Reenumerate() +{ + /* Force USB reset and power-down (this will also release the USB pins for direct GPIO control) */ + _SetCNTR(CNTR_FRES | CNTR_PDWN); + + /* Using a "dirty" method to force a re-enumeration: */ + /* Force DPM (Pin PA12) low for ca. 10 mS before USB Tranceiver will be enabled */ + /* This overrules the external Pull-Up at PA12, and at least Windows & MacOS will enumerate again */ + GPIO_InitTypeDef GPIO_InitStructure; + GPIO_StructInit(&GPIO_InitStructure); + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_Init(GPIOA, &GPIO_InitStructure); + + PIOS_DELAY_WaitmS(50); + + /* Release power-down, still hold reset */ + _SetCNTR(CNTR_PDWN); + PIOS_DELAY_WaituS(5); + + /* CNTR_FRES = 0 */ + _SetCNTR(0); + + /* Clear pending interrupts */ + _SetISTR(0); + + /* set back to alternate function */ + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; + GPIO_Init(GPIOA, &GPIO_InitStructure); + + /* Configure USB clock */ + /* USBCLK = PLLCLK / 1.5 */ + RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_1Div5); + /* Enable USB clock */ + RCC_APB1PeriphClockCmd(RCC_APB1Periph_USB, ENABLE); + + return 0; +} + +bool PIOS_USB_CableConnected(__attribute__((unused)) uint8_t id) +{ + struct pios_usb_dev *usb_dev = (struct pios_usb_dev *)pios_usb_com_id; + + if (PIOS_USB_validate(usb_dev) != 0) { + return false; + } + + // If board is configured to have a VSENSE pin, use that + if (usb_dev->cfg->vsense.gpio != NULL) { + return GPIO_ReadInputDataBit(usb_dev->cfg->vsense.gpio, usb_dev->cfg->vsense.init.GPIO_Pin) == Bit_SET; + } + + return sof_seen_since_reset; +} + +/** + * This function returns the connection status of the USB HID interface + * \return 1: interface available + * \return 0: interface not available + * \note Applications shouldn't call this function directly, instead please use \ref PIOS_COM layer functions + */ +bool PIOS_USB_CheckAvailable(uint32_t id) +{ + struct pios_usb_dev *usb_dev = (struct pios_usb_dev *)pios_usb_com_id; + + if (PIOS_USB_validate(usb_dev) != 0) { + return false; + } + + return PIOS_USB_CableConnected(id) && transfer_possible; +} + +void SOF_Callback(void) +{ + sof_seen_since_reset = true; +} + +void SUSP_Callback(void) +{ + sof_seen_since_reset = false; +} + +#endif /* if defined(PIOS_INCLUDE_USB) */ + +/** + * @} + * @} + */ diff --git a/flight/pios/stm32f30x/pios_usb_cdc.c b/flight/pios/stm32f30x/pios_usb_cdc.c new file mode 100644 index 0000000000..84255191f7 --- /dev/null +++ b/flight/pios/stm32f30x/pios_usb_cdc.c @@ -0,0 +1,491 @@ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_USB_COM USB COM Functions + * @brief PIOS USB COM implementation for CDC interfaces + * @notes This implements a CDC Serial Port + * @{ + * + * @file pios_usb_com_cdc.c + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief USB COM functions (STM32 dependent code) + * @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.h" + +#ifdef PIOS_INCLUDE_USB_CDC + +#include "pios_usb_cdc_priv.h" +#include "pios_usb_board_data.h" /* PIOS_BOARD_*_DATA_LENGTH */ + +/* STM32 USB Library Definitions */ +#include "usb_lib.h" + +static void PIOS_USB_CDC_RegisterTxCallback(uint32_t usbcdc_id, pios_com_callback tx_out_cb, uint32_t context); +static void PIOS_USB_CDC_RegisterRxCallback(uint32_t usbcdc_id, pios_com_callback rx_in_cb, uint32_t context); +static void PIOS_USB_CDC_RegisterBaudRateCallback(uint32_t usbcdc_id, pios_com_callback_baud_rate baud_rate_cb, uint32_t context); +static void PIOS_USB_CDC_TxStart(uint32_t usbcdc_id, uint16_t tx_bytes_avail); +static void PIOS_USB_CDC_RxStart(uint32_t usbcdc_id, uint16_t rx_bytes_avail); +static uint32_t PIOS_USB_CDC_Available(uint32_t usbcdc_id); + +const struct pios_com_driver pios_usb_cdc_com_driver = { + .tx_start = PIOS_USB_CDC_TxStart, + .rx_start = PIOS_USB_CDC_RxStart, + .bind_tx_cb = PIOS_USB_CDC_RegisterTxCallback, + .bind_rx_cb = PIOS_USB_CDC_RegisterRxCallback, + .bind_baud_rate_cb = PIOS_USB_CDC_RegisterBaudRateCallback, + .available = PIOS_USB_CDC_Available, +}; + +enum pios_usb_cdc_dev_magic { + PIOS_USB_CDC_DEV_MAGIC = 0xAABBCCDD, +}; + +struct pios_usb_cdc_dev { + enum pios_usb_cdc_dev_magic magic; + const struct pios_usb_cdc_cfg *cfg; + + uint32_t lower_id; + + pios_com_callback rx_in_cb; + uint32_t rx_in_context; + pios_com_callback tx_out_cb; + uint32_t tx_out_context; + + pios_com_callback_baud_rate baud_rate_cb; + uint32_t baud_rate_context; + + uint8_t rx_packet_buffer[PIOS_USB_BOARD_CDC_DATA_LENGTH]; + /* + * NOTE: This is -1 as somewhat of a hack. It ensures that we always send packets + * that are strictly < maxPacketSize for this interface which means we never have + * to bother with zero length packets (ZLP). + */ + uint8_t tx_packet_buffer[PIOS_USB_BOARD_CDC_DATA_LENGTH - 1]; + + uint32_t rx_dropped; + uint32_t rx_oversize; +}; + +static bool PIOS_USB_CDC_validate(struct pios_usb_cdc_dev *usb_cdc_dev) +{ + return usb_cdc_dev->magic == PIOS_USB_CDC_DEV_MAGIC; +} + +#if defined(PIOS_INCLUDE_FREERTOS) +static struct pios_usb_cdc_dev *PIOS_USB_CDC_alloc(void) +{ + struct pios_usb_cdc_dev *usb_cdc_dev; + + usb_cdc_dev = (struct pios_usb_cdc_dev *)pios_malloc(sizeof(struct pios_usb_cdc_dev)); + if (!usb_cdc_dev) { + return NULL; + } + + memset(usb_cdc_dev, 0, sizeof(struct pios_usb_cdc_dev)); + usb_cdc_dev->magic = PIOS_USB_CDC_DEV_MAGIC; + return usb_cdc_dev; +} +#else +static struct pios_usb_cdc_dev pios_usb_cdc_devs[PIOS_USB_CDC_MAX_DEVS]; +static uint8_t pios_usb_cdc_num_devs; +static struct pios_usb_cdc_dev *PIOS_USB_CDC_alloc(void) +{ + struct pios_usb_cdc_dev *usb_cdc_dev; + + if (pios_usb_cdc_num_devs >= PIOS_USB_CDC_MAX_DEVS) { + return NULL; + } + + usb_cdc_dev = &pios_usb_cdc_devs[pios_usb_cdc_num_devs++]; + + memset(usb_cdc_dev, 0, sizeof(struct pios_usb_cdc_dev)); + usb_cdc_dev->magic = PIOS_USB_CDC_DEV_MAGIC; + + return usb_cdc_dev; +} +#endif /* if defined(PIOS_INCLUDE_FREERTOS) */ + +static void PIOS_USB_CDC_DATA_EP_IN_Callback(void); +static void PIOS_USB_CDC_DATA_EP_OUT_Callback(void); +static void PIOS_USB_CDC_CTRL_EP_IN_Callback(void); + +static uint32_t pios_usb_cdc_id; + +/* Need a better way to pull these in */ +extern void(*pEpInt_IN[7]) (void); +extern void(*pEpInt_OUT[7]) (void); + +int32_t PIOS_USB_CDC_Init(uint32_t *usbcdc_id, const struct pios_usb_cdc_cfg *cfg, uint32_t lower_id) +{ + PIOS_Assert(usbcdc_id); + PIOS_Assert(cfg); + + struct pios_usb_cdc_dev *usb_cdc_dev; + + usb_cdc_dev = (struct pios_usb_cdc_dev *)PIOS_USB_CDC_alloc(); + if (!usb_cdc_dev) { + goto out_fail; + } + + /* Bind the configuration to the device instance */ + usb_cdc_dev->cfg = cfg; + usb_cdc_dev->lower_id = lower_id; + + pios_usb_cdc_id = (uint32_t)usb_cdc_dev; + + /* Bind lower level callbacks into the USB infrastructure */ + pEpInt_OUT[cfg->ctrl_tx_ep - 1] = PIOS_USB_CDC_CTRL_EP_IN_Callback; + pEpInt_IN[cfg->data_tx_ep - 1] = PIOS_USB_CDC_DATA_EP_IN_Callback; + pEpInt_OUT[cfg->data_rx_ep - 1] = PIOS_USB_CDC_DATA_EP_OUT_Callback; + + *usbcdc_id = (uint32_t)usb_cdc_dev; + + return 0; + +out_fail: + return -1; +} + + +static void PIOS_USB_CDC_RegisterRxCallback(uint32_t usbcdc_id, pios_com_callback rx_in_cb, uint32_t context) +{ + struct pios_usb_cdc_dev *usb_cdc_dev = (struct pios_usb_cdc_dev *)usbcdc_id; + + bool valid = PIOS_USB_CDC_validate(usb_cdc_dev); + + PIOS_Assert(valid); + + /* + * Order is important in these assignments since ISR uses _cb + * field to determine if it's ok to dereference _cb and _context + */ + usb_cdc_dev->rx_in_context = context; + usb_cdc_dev->rx_in_cb = rx_in_cb; +} + +static void PIOS_USB_CDC_RegisterTxCallback(uint32_t usbcdc_id, pios_com_callback tx_out_cb, uint32_t context) +{ + struct pios_usb_cdc_dev *usb_cdc_dev = (struct pios_usb_cdc_dev *)usbcdc_id; + + bool valid = PIOS_USB_CDC_validate(usb_cdc_dev); + + PIOS_Assert(valid); + + /* + * Order is important in these assignments since ISR uses _cb + * field to determine if it's ok to dereference _cb and _context + */ + usb_cdc_dev->tx_out_context = context; + usb_cdc_dev->tx_out_cb = tx_out_cb; +} + +static void PIOS_USB_CDC_RxStart(uint32_t usbcdc_id, uint16_t rx_bytes_avail) +{ + struct pios_usb_cdc_dev *usb_cdc_dev = (struct pios_usb_cdc_dev *)usbcdc_id; + + bool valid = PIOS_USB_CDC_validate(usb_cdc_dev); + + PIOS_Assert(valid); + + if (!PIOS_USB_CheckAvailable(usb_cdc_dev->lower_id)) { + return; + } + + // If endpoint was stalled and there is now space make it valid + PIOS_IRQ_Disable(); + if ((GetEPRxStatus(usb_cdc_dev->cfg->data_rx_ep) != EP_RX_VALID) && + (rx_bytes_avail >= sizeof(usb_cdc_dev->rx_packet_buffer))) { + SetEPRxStatus(usb_cdc_dev->cfg->data_rx_ep, EP_RX_VALID); + } + PIOS_IRQ_Enable(); +} + +static void PIOS_USB_CDC_SendData(struct pios_usb_cdc_dev *usb_cdc_dev) +{ + uint16_t bytes_to_tx; + + if (!usb_cdc_dev->tx_out_cb) { + return; + } + + bool need_yield = false; + bytes_to_tx = (usb_cdc_dev->tx_out_cb)(usb_cdc_dev->tx_out_context, + usb_cdc_dev->tx_packet_buffer, + sizeof(usb_cdc_dev->tx_packet_buffer), + NULL, + &need_yield); + if (bytes_to_tx == 0) { + return; + } + + UserToPMABufferCopy(usb_cdc_dev->tx_packet_buffer, + GetEPTxAddr(usb_cdc_dev->cfg->data_tx_ep), + bytes_to_tx); + SetEPTxCount(usb_cdc_dev->cfg->data_tx_ep, bytes_to_tx); + SetEPTxValid(usb_cdc_dev->cfg->data_tx_ep); + +#if defined(PIOS_INCLUDE_FREERTOS) + if (need_yield) { + vPortYield(); + } +#endif /* PIOS_INCLUDE_FREERTOS */ +} + +static void PIOS_USB_CDC_TxStart(uint32_t usbcdc_id, __attribute__((unused)) uint16_t tx_bytes_avail) +{ + struct pios_usb_cdc_dev *usb_cdc_dev = (struct pios_usb_cdc_dev *)usbcdc_id; + + bool valid = PIOS_USB_CDC_validate(usb_cdc_dev); + + PIOS_Assert(valid); + + if (!PIOS_USB_CheckAvailable(usb_cdc_dev->lower_id)) { + return; + } + + if (GetEPTxStatus(usb_cdc_dev->cfg->data_tx_ep) == EP_TX_VALID) { + /* Endpoint is already transmitting */ + return; + } + + PIOS_USB_CDC_SendData(usb_cdc_dev); +} + +static void PIOS_USB_CDC_DATA_EP_IN_Callback(void) +{ + struct pios_usb_cdc_dev *usb_cdc_dev = (struct pios_usb_cdc_dev *)pios_usb_cdc_id; + + bool valid = PIOS_USB_CDC_validate(usb_cdc_dev); + + PIOS_Assert(valid); + + PIOS_USB_CDC_SendData(usb_cdc_dev); +} + +static void PIOS_USB_CDC_DATA_EP_OUT_Callback(void) +{ + struct pios_usb_cdc_dev *usb_cdc_dev = (struct pios_usb_cdc_dev *)pios_usb_cdc_id; + + bool valid = PIOS_USB_CDC_validate(usb_cdc_dev); + + PIOS_Assert(valid); + + uint32_t DataLength; + + /* Get the number of received data on the selected Endpoint */ + DataLength = GetEPRxCount(usb_cdc_dev->cfg->data_rx_ep); + if (DataLength > sizeof(usb_cdc_dev->rx_packet_buffer)) { + usb_cdc_dev->rx_oversize++; + DataLength = sizeof(usb_cdc_dev->rx_packet_buffer); + } + + /* Use the memory interface function to read from the selected endpoint */ + PMAToUserBufferCopy((uint8_t *)usb_cdc_dev->rx_packet_buffer, + GetEPRxAddr(usb_cdc_dev->cfg->data_rx_ep), + DataLength); + + if (!usb_cdc_dev->rx_in_cb) { + /* No Rx call back registered, disable the receiver */ + SetEPRxStatus(usb_cdc_dev->cfg->data_rx_ep, EP_RX_NAK); + return; + } + + uint16_t headroom; + bool need_yield = false; + uint16_t rc; + rc = (usb_cdc_dev->rx_in_cb)(usb_cdc_dev->rx_in_context, + usb_cdc_dev->rx_packet_buffer, + DataLength, + &headroom, + &need_yield); + + if (rc < DataLength) { + /* Lost bytes on rx */ + usb_cdc_dev->rx_dropped += (DataLength - rc); + } + + if (headroom >= sizeof(usb_cdc_dev->rx_packet_buffer)) { + /* We have room for a maximum length message */ + SetEPRxStatus(usb_cdc_dev->cfg->data_rx_ep, EP_RX_VALID); + } else { + /* Not enough room left for a message, apply backpressure */ + SetEPRxStatus(usb_cdc_dev->cfg->data_rx_ep, EP_RX_NAK); + } + +#if defined(PIOS_INCLUDE_FREERTOS) + if (need_yield) { + vPortYield(); + } +#endif /* PIOS_INCLUDE_FREERTOS */ +} + +static uint16_t control_line_state; +RESULT PIOS_USB_CDC_SetControlLineState(void) +{ + struct pios_usb_cdc_dev *usb_cdc_dev = (struct pios_usb_cdc_dev *)pios_usb_cdc_id; + + bool valid = PIOS_USB_CDC_validate(usb_cdc_dev); + + if (!valid) { + /* No CDC interface is configured */ + return USB_UNSUPPORT; + } + + uint8_t wValue0 = pInformation->USBwValue0; + uint8_t wValue1 = pInformation->USBwValue1; + + control_line_state = wValue1 << 8 | wValue0; + + return USB_SUCCESS; +} + +static uint32_t PIOS_USB_CDC_Available(uint32_t usbcdc_id) +{ + struct pios_usb_cdc_dev *usb_cdc_dev = (struct pios_usb_cdc_dev *)usbcdc_id; + + bool valid = PIOS_USB_CDC_validate(usb_cdc_dev); + + PIOS_Assert(valid); + + return (PIOS_USB_CheckAvailable(usb_cdc_dev->lower_id) && + (control_line_state & USB_CDC_CONTROL_LINE_STATE_DTE_PRESENT)) ? COM_AVAILABLE_RXTX : COM_AVAILABLE_NONE; +} + +static struct usb_cdc_line_coding line_coding = { + .dwDTERate = htousbl(57600), + .bCharFormat = USB_CDC_LINE_CODING_STOP_1, + .bParityType = USB_CDC_LINE_CODING_PARITY_NONE, + .bDataBits = 8, +}; + +uint8_t *PIOS_USB_CDC_SetLineCoding(uint16_t Length) +{ + struct pios_usb_cdc_dev *usb_cdc_dev = (struct pios_usb_cdc_dev *)pios_usb_cdc_id; + + bool valid = PIOS_USB_CDC_validate(usb_cdc_dev); + + if (!valid) { + /* No CDC interface is configured */ + return NULL; + } + + if (Length == 0) { + /* Report the number of bytes we're prepared to consume */ + pInformation->Ctrl_Info.Usb_wLength = sizeof(line_coding); + pInformation->Ctrl_Info.Usb_rLength = sizeof(line_coding); + return NULL; + } else { + /* Give out a pointer to the data struct */ + return (uint8_t *)&line_coding; + } +} + +const uint8_t *PIOS_USB_CDC_GetLineCoding(uint16_t Length) +{ + struct pios_usb_cdc_dev *usb_cdc_dev = (struct pios_usb_cdc_dev *)pios_usb_cdc_id; + + bool valid = PIOS_USB_CDC_validate(usb_cdc_dev); + + if (!valid) { + /* No CDC interface is configured */ + return NULL; + } + + if (Length == 0) { + pInformation->Ctrl_Info.Usb_wLength = sizeof(line_coding); + return NULL; + } else { + return (uint8_t *)&line_coding; + } +} + +struct usb_cdc_serial_state_report uart_state = { + .bmRequestType = 0xA1, + .bNotification = USB_CDC_NOTIFICATION_SERIAL_STATE, + .wValue = 0, + .wIndex = htousbs(1), + .wLength = htousbs(2), + .bmUartState = htousbs(0), +}; + +static void PIOS_USB_CDC_CTRL_EP_IN_Callback(void) +{ + struct pios_usb_cdc_dev *usb_cdc_dev = (struct pios_usb_cdc_dev *)pios_usb_cdc_id; + + bool valid = PIOS_USB_CDC_validate(usb_cdc_dev); + + PIOS_Assert(valid); + + /* Give back UART State Bitmap */ + /* UART State Bitmap + * 15-7: reserved + * 6: bOverRun overrun error + * 5: bParity parity error + * 4: bFraming framing error + * 3: bRingSignal RI + * 2: bBreak break reception + * 1: bTxCarrier DSR + * 0: bRxCarrier DCD + */ + uart_state.bmUartState = htousbs(0x0003); + + UserToPMABufferCopy((uint8_t *)&uart_state, + GetEPTxAddr(usb_cdc_dev->cfg->ctrl_tx_ep), + sizeof(uart_state)); + SetEPTxCount(usb_cdc_dev->cfg->ctrl_tx_ep, PIOS_USB_BOARD_CDC_MGMT_LENGTH); + SetEPTxValid(usb_cdc_dev->cfg->ctrl_tx_ep); +} + +static void PIOS_USB_CDC_RegisterBaudRateCallback(uint32_t usbcdc_id, pios_com_callback_baud_rate baud_rate_cb, uint32_t context) +{ + struct pios_usb_cdc_dev *usb_cdc_dev = (struct pios_usb_cdc_dev *)usbcdc_id; + + bool valid = PIOS_USB_CDC_validate(usb_cdc_dev); + + PIOS_Assert(valid); + + /* + * Order is important in these assignments since ISR uses _cb + * field to determine if it's ok to dereference _cb and _context + */ + usb_cdc_dev->baud_rate_context = context; + usb_cdc_dev->baud_rate_cb = baud_rate_cb; +} + +void PIOS_USB_CDC_SetLineCoding_Completed() +{ + struct pios_usb_cdc_dev *usb_cdc_dev = (struct pios_usb_cdc_dev *)pios_usb_cdc_id; + + bool valid = PIOS_USB_CDC_validate(usb_cdc_dev); + + if (!valid) { + /* No CDC interface is configured */ + return; + } + + if (usb_cdc_dev->baud_rate_cb) { + usb_cdc_dev->baud_rate_cb(usb_cdc_dev->baud_rate_context, usbltoh(line_coding.dwDTERate)); + } +} + + +#endif /* PIOS_INCLUDE_USB_CDC */ diff --git a/flight/pios/stm32f30x/pios_usb_hid.c b/flight/pios/stm32f30x/pios_usb_hid.c new file mode 100644 index 0000000000..af74d5cc66 --- /dev/null +++ b/flight/pios/stm32f30x/pios_usb_hid.c @@ -0,0 +1,372 @@ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_USB_HID USB COM Functions + * @brief PIOS USB COM implementation for HID interfaces + * @notes This implements serial emulation over HID reports + * @{ + * + * @file pios_usb_hid.c + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @author Tau Labs, http://taulabs.org, Copyright (C) 2012-2014 + * @author dRonin, http://dronin.org, Copyright (C) 2016 + * @brief USB COM functions (STM32 dependent code) + * @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 + */ + +/* Project Includes */ +#include "pios.h" + +#if defined(PIOS_INCLUDE_USB_HID) + +#include "pios_usb.h" +#include "pios_usb_hid_priv.h" +#include "pios_usb_board_data.h" /* PIOS_BOARD_*_DATA_LENGTH */ + +/* STM32 USB Library Definitions */ +#include "usb_lib.h" + +static void PIOS_USB_HID_RegisterTxCallback(uint32_t usbhid_id, pios_com_callback tx_out_cb, uint32_t context); +static void PIOS_USB_HID_RegisterRxCallback(uint32_t usbhid_id, pios_com_callback rx_in_cb, uint32_t context); +static void PIOS_USB_HID_TxStart(uint32_t usbhid_id, uint16_t tx_bytes_avail); +static void PIOS_USB_HID_RxStart(uint32_t usbhid_id, uint16_t rx_bytes_avail); +static uint32_t PIOS_USB_HID_Available(uint32_t usbhid_id); + +const struct pios_com_driver pios_usb_hid_com_driver = { + .tx_start = PIOS_USB_HID_TxStart, + .rx_start = PIOS_USB_HID_RxStart, + .bind_tx_cb = PIOS_USB_HID_RegisterTxCallback, + .bind_rx_cb = PIOS_USB_HID_RegisterRxCallback, + .available = PIOS_USB_HID_Available, +}; + +enum pios_usb_hid_dev_magic { + PIOS_USB_HID_DEV_MAGIC = 0xAA00BB00, +}; + +struct pios_usb_hid_dev { + enum pios_usb_hid_dev_magic magic; + const struct pios_usb_hid_cfg *cfg; + + uint32_t lower_id; + + pios_com_callback rx_in_cb; + uint32_t rx_in_context; + pios_com_callback tx_out_cb; + uint32_t tx_out_context; + + uint8_t rx_packet_buffer[PIOS_USB_BOARD_HID_DATA_LENGTH]; + uint8_t tx_packet_buffer[PIOS_USB_BOARD_HID_DATA_LENGTH]; + + uint32_t rx_dropped; + uint32_t rx_oversize; +}; + +static bool PIOS_USB_HID_validate(struct pios_usb_hid_dev *usb_hid_dev) +{ + return usb_hid_dev->magic == PIOS_USB_HID_DEV_MAGIC; +} + +#ifdef PIOS_INCLUDE_FREERTOS +static struct pios_usb_hid_dev *PIOS_USB_HID_alloc(void) +{ + struct pios_usb_hid_dev *usb_hid_dev; + + usb_hid_dev = (struct pios_usb_hid_dev *)pios_malloc(sizeof(struct pios_usb_hid_dev)); + if (!usb_hid_dev) { + return NULL; + } + + memset(usb_hid_dev, 0, sizeof(struct pios_usb_hid_dev)); + usb_hid_dev->magic = PIOS_USB_HID_DEV_MAGIC; + return usb_hid_dev; +} +#else +static struct pios_usb_hid_dev pios_usb_hid_devs[PIOS_USB_HID_MAX_DEVS]; +static uint8_t pios_usb_hid_num_devs; +static struct pios_usb_hid_dev *PIOS_USB_HID_alloc(void) +{ + struct pios_usb_hid_dev *usb_hid_dev; + + if (pios_usb_hid_num_devs >= PIOS_USB_HID_MAX_DEVS) { + return NULL; + } + + usb_hid_dev = &pios_usb_hid_devs[pios_usb_hid_num_devs++]; + + memset(usb_hid_dev, 0, sizeof(struct pios_usb_hid_dev)); + usb_hid_dev->magic = PIOS_USB_HID_DEV_MAGIC; + + return usb_hid_dev; +} +#endif /* ifdef PIOS_INCLUDE_FREERTOS */ + +static void PIOS_USB_HID_EP_IN_Callback(void); +static void PIOS_USB_HID_EP_OUT_Callback(void); + +static uint32_t pios_usb_hid_id; + +/* Need a better way to pull these in */ +extern void(*pEpInt_IN[7]) (void); +extern void(*pEpInt_OUT[7]) (void); + +int32_t PIOS_USB_HID_Init(uint32_t *usbhid_id, const struct pios_usb_hid_cfg *cfg, uint32_t lower_id) +{ + PIOS_Assert(usbhid_id); + PIOS_Assert(cfg); + + struct pios_usb_hid_dev *usb_hid_dev; + + usb_hid_dev = (struct pios_usb_hid_dev *)PIOS_USB_HID_alloc(); + if (!usb_hid_dev) { + goto out_fail; + } + + /* Bind the configuration to the device instance */ + usb_hid_dev->cfg = cfg; + usb_hid_dev->lower_id = lower_id; + + pios_usb_hid_id = (uint32_t)usb_hid_dev; + + /* Bind lower level callbacks into the USB infrastructure */ + pEpInt_IN[cfg->data_tx_ep - 1] = PIOS_USB_HID_EP_IN_Callback; + pEpInt_OUT[cfg->data_rx_ep - 1] = PIOS_USB_HID_EP_OUT_Callback; + + *usbhid_id = (uint32_t)usb_hid_dev; + + return 0; + +out_fail: + return -1; +} + + +static void PIOS_USB_HID_SendReport(struct pios_usb_hid_dev *usb_hid_dev) +{ + uint16_t bytes_to_tx; + + if (!usb_hid_dev->tx_out_cb) { + return; + } + + bool need_yield = false; +#ifdef PIOS_USB_BOARD_BL_HID_HAS_NO_LENGTH_BYTE + bytes_to_tx = (usb_hid_dev->tx_out_cb)(usb_hid_dev->tx_out_context, + &usb_hid_dev->tx_packet_buffer[1], + sizeof(usb_hid_dev->tx_packet_buffer) - 1, + NULL, + &need_yield); +#else + bytes_to_tx = (usb_hid_dev->tx_out_cb)(usb_hid_dev->tx_out_context, + &usb_hid_dev->tx_packet_buffer[2], + sizeof(usb_hid_dev->tx_packet_buffer) - 2, + NULL, + &need_yield); +#endif + if (bytes_to_tx == 0) { + return; + } + + /* Always set type as report ID */ + usb_hid_dev->tx_packet_buffer[0] = 1; + +#ifdef PIOS_USB_BOARD_BL_HID_HAS_NO_LENGTH_BYTE + UserToPMABufferCopy(usb_hid_dev->tx_packet_buffer, + GetEPTxAddr(usb_hid_dev->cfg->data_tx_ep), + bytes_to_tx + 1); +#else + usb_hid_dev->tx_packet_buffer[1] = bytes_to_tx; + UserToPMABufferCopy(usb_hid_dev->tx_packet_buffer, + GetEPTxAddr(usb_hid_dev->cfg->data_tx_ep), + bytes_to_tx + 2); +#endif + /* Is this correct? Why do we always send the whole buffer? */ + SetEPTxCount(usb_hid_dev->cfg->data_tx_ep, sizeof(usb_hid_dev->tx_packet_buffer)); + SetEPTxValid(usb_hid_dev->cfg->data_tx_ep); +} + +static void PIOS_USB_HID_RxStart(uint32_t usbhid_id, uint16_t rx_bytes_avail) +{ + struct pios_usb_hid_dev *usb_hid_dev = (struct pios_usb_hid_dev *)usbhid_id; + + bool valid = PIOS_USB_HID_validate(usb_hid_dev); + + PIOS_Assert(valid); + + if (!PIOS_USB_CheckAvailable(usb_hid_dev->lower_id)) { + return; + } + + // If endpoint was stalled and there is now space make it valid +#ifdef PIOS_USB_BOARD_BL_HID_HAS_NO_LENGTH_BYTE + uint16_t max_payload_length = PIOS_USB_BOARD_HID_DATA_LENGTH - 1; +#else + uint16_t max_payload_length = PIOS_USB_BOARD_HID_DATA_LENGTH - 2; +#endif + + PIOS_IRQ_Disable(); + if ((GetEPRxStatus(usb_hid_dev->cfg->data_rx_ep) != EP_RX_VALID) && + (rx_bytes_avail >= max_payload_length)) { + SetEPRxStatus(usb_hid_dev->cfg->data_rx_ep, EP_RX_VALID); + } + PIOS_IRQ_Enable(); +} + +static void PIOS_USB_HID_TxStart(uint32_t usbhid_id, __attribute__((unused)) uint16_t tx_bytes_avail) +{ + struct pios_usb_hid_dev *usb_hid_dev = (struct pios_usb_hid_dev *)usbhid_id; + + bool valid = PIOS_USB_HID_validate(usb_hid_dev); + + PIOS_Assert(valid); + + if (!PIOS_USB_CheckAvailable(usb_hid_dev->lower_id)) { + return; + } + + if (GetEPTxStatus(usb_hid_dev->cfg->data_tx_ep) == EP_TX_VALID) { + /* Endpoint is already transmitting */ + return; + } + + PIOS_USB_HID_SendReport(usb_hid_dev); +} + +static void PIOS_USB_HID_RegisterRxCallback(uint32_t usbhid_id, pios_com_callback rx_in_cb, uint32_t context) +{ + struct pios_usb_hid_dev *usb_hid_dev = (struct pios_usb_hid_dev *)usbhid_id; + + bool valid = PIOS_USB_HID_validate(usb_hid_dev); + + PIOS_Assert(valid); + + /* + * Order is important in these assignments since ISR uses _cb + * field to determine if it's ok to dereference _cb and _context + */ + usb_hid_dev->rx_in_context = context; + usb_hid_dev->rx_in_cb = rx_in_cb; +} + +static void PIOS_USB_HID_RegisterTxCallback(uint32_t usbhid_id, pios_com_callback tx_out_cb, uint32_t context) +{ + struct pios_usb_hid_dev *usb_hid_dev = (struct pios_usb_hid_dev *)usbhid_id; + + bool valid = PIOS_USB_HID_validate(usb_hid_dev); + + PIOS_Assert(valid); + + /* + * Order is important in these assignments since ISR uses _cb + * field to determine if it's ok to dereference _cb and _context + */ + usb_hid_dev->tx_out_context = context; + usb_hid_dev->tx_out_cb = tx_out_cb; +} + +/** + * @brief Callback used to indicate a transmission from device INto host completed + * Checks if any data remains, pads it into HID packet and sends. + */ +static void PIOS_USB_HID_EP_IN_Callback(void) +{ + struct pios_usb_hid_dev *usb_hid_dev = (struct pios_usb_hid_dev *)pios_usb_hid_id; + + bool valid = PIOS_USB_HID_validate(usb_hid_dev); + + PIOS_Assert(valid); + + if (!PIOS_USB_CheckAvailable(usb_hid_dev->lower_id)) { + return; + } + + PIOS_USB_HID_SendReport(usb_hid_dev); +} + +/** + * EP1 OUT Callback Routine + */ +static void PIOS_USB_HID_EP_OUT_Callback(void) +{ + struct pios_usb_hid_dev *usb_hid_dev = (struct pios_usb_hid_dev *)pios_usb_hid_id; + + bool valid = PIOS_USB_HID_validate(usb_hid_dev); + + PIOS_Assert(valid); + + uint32_t DataLength; + + /* Read received data (63 bytes) */ + /* Get the number of received data on the selected Endpoint */ + DataLength = GetEPRxCount(usb_hid_dev->cfg->data_rx_ep); + if (DataLength > sizeof(usb_hid_dev->rx_packet_buffer)) { + DataLength = sizeof(usb_hid_dev->rx_packet_buffer); + } + + /* Use the memory interface function to read from the selected endpoint */ + PMAToUserBufferCopy((uint8_t *)usb_hid_dev->rx_packet_buffer, + GetEPRxAddr(usb_hid_dev->cfg->data_rx_ep), + DataLength); + + if (!usb_hid_dev->rx_in_cb) { + /* No Rx call back registered, disable the receiver */ + SetEPRxStatus(usb_hid_dev->cfg->data_rx_ep, EP_RX_NAK); + return; + } + + /* The first byte is report ID (not checked), the second byte is the valid data length */ + uint16_t headroom; + bool need_yield = false; +#ifdef PIOS_USB_BOARD_BL_HID_HAS_NO_LENGTH_BYTE + (usb_hid_dev->rx_in_cb)(usb_hid_dev->rx_in_context, + &usb_hid_dev->rx_packet_buffer[1], + sizeof(usb_hid_dev->rx_packet_buffer) - 1, + &headroom, + &need_yield); +#else + (usb_hid_dev->rx_in_cb)(usb_hid_dev->rx_in_context, + &usb_hid_dev->rx_packet_buffer[2], + usb_hid_dev->rx_packet_buffer[1], + &headroom, + &need_yield); +#endif + +#ifdef PIOS_USB_BOARD_BL_HID_HAS_NO_LENGTH_BYTE + uint16_t max_payload_length = PIOS_USB_BOARD_HID_DATA_LENGTH - 1; +#else + uint16_t max_payload_length = PIOS_USB_BOARD_HID_DATA_LENGTH - 2; +#endif + + if (headroom >= max_payload_length) { + /* We have room for a maximum length message */ + SetEPRxStatus(usb_hid_dev->cfg->data_rx_ep, EP_RX_VALID); + } else { + /* Not enough room left for a message, apply backpressure */ + SetEPRxStatus(usb_hid_dev->cfg->data_rx_ep, EP_RX_NAK); + } +} + +static uint32_t PIOS_USB_HID_Available(uint32_t usbhid_id) +{ + return PIOS_USB_CheckAvailable(usbhid_id) ? COM_AVAILABLE_RXTX : COM_AVAILABLE_NONE; +} + + +#endif /* PIOS_INCLUDE_USB_HID */ diff --git a/flight/pios/stm32f30x/pios_usb_hid_istr.c b/flight/pios/stm32f30x/pios_usb_hid_istr.c new file mode 100644 index 0000000000..99965333ff --- /dev/null +++ b/flight/pios/stm32f30x/pios_usb_hid_istr.c @@ -0,0 +1,336 @@ +/******************** (C) COPYRIGHT 2010 STMicroelectronics ******************** +* File Name : usb_istr.c +* Author : MCD Application Team +* Version : V3.2.1 +* Date : 07/05/2010 +* Description : ISTR events interrupt service routines +******************************************************************************** +* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS +* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. +* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, +* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE +* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING +* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. +*******************************************************************************/ + +/* Includes ------------------------------------------------------------------*/ +#include "pios.h" + +#ifdef PIOS_INCLUDE_USB + +#include "usb_lib.h" +#include "pios_usb_hid_pwr.h" +#include "pios_usb_hid_istr.h" +#include "pios_usb_hid.h" + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +__IO uint16_t wIstr; /* ISTR register last read value */ +__IO uint8_t bIntPackSOF = 0; /* SOFs received between 2 consecutive packets */ + +/* Extern variables ----------------------------------------------------------*/ +/* Private function prototypes -----------------------------------------------*/ +/* Private functions ---------------------------------------------------------*/ +/* function pointers to non-control endpoints service routines */ +void(*pEpInt_IN[7]) (void) = { + EP1_IN_Callback, EP2_IN_Callback, EP3_IN_Callback, EP4_IN_Callback, EP5_IN_Callback, EP6_IN_Callback, EP7_IN_Callback, +}; + +void(*pEpInt_OUT[7]) (void) = { + EP1_OUT_Callback, EP2_OUT_Callback, EP3_OUT_Callback, EP4_OUT_Callback, EP5_OUT_Callback, EP6_OUT_Callback, EP7_OUT_Callback, +}; + +#ifndef STM32F10X_CL + +/******************************************************************************* +* Function Name : USB_Istr +* Description : STR events interrupt service routine +* Input : +* Output : +* Return : +*******************************************************************************/ +void USB_LP_CAN1_RX0_IRQHandler(void) // USB_Istr(void) +{ + wIstr = _GetISTR(); + +#if (IMR_MSK & ISTR_CTR) + if (wIstr & ISTR_CTR & wInterrupt_Mask) { + /* servicing of the endpoint correct transfer interrupt */ + /* clear of the CTR flag into the sub */ + CTR_LP(); +#ifdef CTR_CALLBACK + CTR_Callback(); +#endif + } +#endif + /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ +#if (IMR_MSK & ISTR_RESET) + if (wIstr & ISTR_RESET & wInterrupt_Mask) { + _SetISTR((uint16_t)CLR_RESET); + Device_Property.Reset(); +#ifdef RESET_CALLBACK + RESET_Callback(); +#endif + } +#endif + /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ +#if (IMR_MSK & ISTR_DOVR) + if (wIstr & ISTR_DOVR & wInterrupt_Mask) { + _SetISTR((uint16_t)CLR_DOVR); +#ifdef DOVR_CALLBACK + DOVR_Callback(); +#endif + } +#endif + /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ +#if (IMR_MSK & ISTR_ERR) + if (wIstr & ISTR_ERR & wInterrupt_Mask) { + _SetISTR((uint16_t)CLR_ERR); +#ifdef ERR_CALLBACK + ERR_Callback(); +#endif + } +#endif + /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ +#if (IMR_MSK & ISTR_WKUP) + if (wIstr & ISTR_WKUP & wInterrupt_Mask) { + _SetISTR((uint16_t)CLR_WKUP); + Resume(RESUME_EXTERNAL); +#ifdef WKUP_CALLBACK + WKUP_Callback(); +#endif + } +#endif + /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ +#if (IMR_MSK & ISTR_SUSP) + if (wIstr & ISTR_SUSP & wInterrupt_Mask) { + /* check if SUSPEND is possible */ + if (fSuspendEnabled) { + Suspend(); + } else { + /* if not possible then resume after xx ms */ + Resume(RESUME_LATER); + } + /* clear of the ISTR bit must be done after setting of CNTR_FSUSP */ + _SetISTR((uint16_t)CLR_SUSP); +#ifdef SUSP_CALLBACK + SUSP_Callback(); +#endif + } +#endif + /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ +#if (IMR_MSK & ISTR_SOF) + if (wIstr & ISTR_SOF & wInterrupt_Mask) { + _SetISTR((uint16_t)CLR_SOF); + bIntPackSOF++; + +#ifdef SOF_CALLBACK + SOF_Callback(); +#endif + } +#endif + /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ +#if (IMR_MSK & ISTR_ESOF) + if (wIstr & ISTR_ESOF & wInterrupt_Mask) { + _SetISTR((uint16_t)CLR_ESOF); + /* resume handling timing is made with ESOFs */ + Resume(RESUME_ESOF); /* request without change of the machine state */ + +#ifdef ESOF_CALLBACK + ESOF_Callback(); +#endif + } +#endif +} /* USB_Istr */ + +/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ +#else /* STM32F10X_CL */ + +/******************************************************************************* +* Function Name : STM32_PCD_OTG_ISR_Handler +* Description : Handles all USB Device Interrupts +* Input : None +* Output : None +* Return : status +*******************************************************************************/ +u32 STM32_PCD_OTG_ISR_Handler(void) +{ + USB_OTG_GINTSTS_TypeDef gintr_status; + u32 retval = 0; + + if (USBD_FS_IsDeviceMode()) { /* ensure that we are in device mode */ + gintr_status.d32 = OTGD_FS_ReadCoreItr(); + + /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ + + /* If there is no interrupt pending exit the interrupt routine */ + if (!gintr_status.d32) { + return 0; + } + + /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ + /* Early Suspend interrupt */ +#ifdef INTR_ERLYSUSPEND + if (gintr_status.b.erlysuspend) { + retval |= OTGD_FS_Handle_EarlySuspend_ISR(); + } +#endif /* INTR_ERLYSUSPEND */ + + /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ + /* End of Periodic Frame interrupt */ +#ifdef INTR_EOPFRAME + if (gintr_status.b.eopframe) { + retval |= OTGD_FS_Handle_EOPF_ISR(); + } +#endif /* INTR_EOPFRAME */ + + /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ + /* Non Periodic Tx FIFO Emty interrupt */ +#ifdef INTR_NPTXFEMPTY + if (gintr_status.b.nptxfempty) { + retval |= OTGD_FS_Handle_NPTxFE_ISR(); + } +#endif /* INTR_NPTXFEMPTY */ + + /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ + /* Wakeup or RemoteWakeup interrupt */ +#ifdef INTR_WKUPINTR + if (gintr_status.b.wkupintr) { + retval |= OTGD_FS_Handle_Wakeup_ISR(); + } +#endif /* INTR_WKUPINTR */ + + /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ + /* Suspend interrupt */ +#ifdef INTR_USBSUSPEND + if (gintr_status.b.usbsuspend) { + /* check if SUSPEND is possible */ + if (fSuspendEnabled) { + Suspend(); + } else { + /* if not possible then resume after xx ms */ + Resume(RESUME_LATER); /* This case shouldn't happen in OTG Device mode because + there's no ESOF interrupt to increment the ResumeS.bESOFcnt in the Resume state machine */ + } + + retval |= OTGD_FS_Handle_USBSuspend_ISR(); + } +#endif /* INTR_USBSUSPEND */ + + /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ + /* Start of Frame interrupt */ +#ifdef INTR_SOFINTR + if (gintr_status.b.sofintr) { + /* Update the frame number variable */ + bIntPackSOF++; + + retval |= OTGD_FS_Handle_Sof_ISR(); + } +#endif /* INTR_SOFINTR */ + + /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ + /* Receive FIFO Queue Status Level interrupt */ +#ifdef INTR_RXSTSQLVL + if (gintr_status.b.rxstsqlvl) { + retval |= OTGD_FS_Handle_RxStatusQueueLevel_ISR(); + } +#endif /* INTR_RXSTSQLVL */ + + /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ + /* Enumeration Done interrupt */ +#ifdef INTR_ENUMDONE + if (gintr_status.b.enumdone) { + retval |= OTGD_FS_Handle_EnumDone_ISR(); + } +#endif /* INTR_ENUMDONE */ + + /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ + /* Reset interrutp */ +#ifdef INTR_USBRESET + if (gintr_status.b.usbreset) { + retval |= OTGD_FS_Handle_UsbReset_ISR(); + } +#endif /* INTR_USBRESET */ + + /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ + /* IN Endpoint interrupt */ +#ifdef INTR_INEPINTR + if (gintr_status.b.inepint) { + retval |= OTGD_FS_Handle_InEP_ISR(); + } +#endif /* INTR_INEPINTR */ + + /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ + /* OUT Endpoint interrupt */ +#ifdef INTR_OUTEPINTR + if (gintr_status.b.outepintr) { + retval |= OTGD_FS_Handle_OutEP_ISR(); + } +#endif /* INTR_OUTEPINTR */ + + /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ + /* Mode Mismatch interrupt */ +#ifdef INTR_MODEMISMATCH + if (gintr_status.b.modemismatch) { + retval |= OTGD_FS_Handle_ModeMismatch_ISR(); + } +#endif /* INTR_MODEMISMATCH */ + + /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ + /* Global IN Endpoints NAK Effective interrupt */ +#ifdef INTR_GINNAKEFF + if (gintr_status.b.ginnakeff) { + retval |= OTGD_FS_Handle_GInNakEff_ISR(); + } +#endif /* INTR_GINNAKEFF */ + + /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ + /* Global OUT Endpoints NAK effective interrupt */ +#ifdef INTR_GOUTNAKEFF + if (gintr_status.b.goutnakeff) { + retval |= OTGD_FS_Handle_GOutNakEff_ISR(); + } +#endif /* INTR_GOUTNAKEFF */ + + /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ + /* Isochrounous Out packet Dropped interrupt */ +#ifdef INTR_ISOOUTDROP + if (gintr_status.b.isooutdrop) { + retval |= OTGD_FS_Handle_IsoOutDrop_ISR(); + } +#endif /* INTR_ISOOUTDROP */ + + /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ + /* Endpoint Mismatch error interrupt */ +#ifdef INTR_EPMISMATCH + if (gintr_status.b.epmismatch) { + retval |= OTGD_FS_Handle_EPMismatch_ISR(); + } +#endif /* INTR_EPMISMATCH */ + + /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ + /* Incomplete Isochrous IN tranfer error interrupt */ +#ifdef INTR_INCOMPLISOIN + if (gintr_status.b.incomplisoin) { + retval |= OTGD_FS_Handle_IncomplIsoIn_ISR(); + } +#endif /* INTR_INCOMPLISOIN */ + + /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ + /* Incomplete Isochrous OUT tranfer error interrupt */ +#ifdef INTR_INCOMPLISOOUT + if (gintr_status.b.outepintr) { + retval |= OTGD_FS_Handle_IncomplIsoOut_ISR(); + } +#endif /* INTR_INCOMPLISOOUT */ + } + return retval; +} + +#endif /* STM32F10X_CL */ + +#endif /* PIOS_INCLUDE_USB */ + +/******************* (C) COPYRIGHT 2010 STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/pios_usb_hid_pwr.c b/flight/pios/stm32f30x/pios_usb_hid_pwr.c new file mode 100644 index 0000000000..7a028a91de --- /dev/null +++ b/flight/pios/stm32f30x/pios_usb_hid_pwr.c @@ -0,0 +1,292 @@ +/******************** (C) COPYRIGHT 2010 STMicroelectronics ******************** +* File Name : usb_pwr.c +* Author : MCD Application Team +* Version : V3.2.1 +* Date : 07/05/2010 +* Description : Connection/disconnection & power management +******************************************************************************** +* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS +* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. +* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, +* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE +* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING +* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. +*******************************************************************************/ + +/* Includes ------------------------------------------------------------------*/ +#include "pios.h" +#include "stm32f30x.h" +#include "usb_lib.h" +#include "usb_conf.h" +#include "pios_usb_hid_pwr.h" +#include "pios_usb_hid.h" + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +__IO uint32_t bDeviceState = UNCONNECTED; /* USB device status */ +__IO bool fSuspendEnabled = true; /* true when suspend is possible */ + +struct { + __IO RESUME_STATE eState; + __IO uint8_t bESOFcnt; +} ResumeS; + +/* Extern variables ----------------------------------------------------------*/ +/* Private function prototypes -----------------------------------------------*/ +/* Extern function prototypes ------------------------------------------------*/ +/* Private functions ---------------------------------------------------------*/ + +/******************************************************************************* +* Function Name : USB_Cable_Config. +* Description : Software Connection/Disconnection of USB Cable. +* Input : NewState: new state. +* Output : None. +* Return : None +*******************************************************************************/ +void USB_Cable_Config(FunctionalState __attribute__((unused)) NewState) +{} + +/******************************************************************************* +* Function Name : PowerOn +* Description : +* Input : None. +* Output : None. +* Return : USB_SUCCESS. +*******************************************************************************/ +RESULT PowerOn(void) +{ +#ifndef STM32F10X_CL + uint16_t wRegVal; + + /*** cable plugged-in ? ***/ + USB_Cable_Config(ENABLE); + + /*** CNTR_PWDN = 0 ***/ + wRegVal = CNTR_FRES; + _SetCNTR(wRegVal); + + /*** CNTR_FRES = 0 ***/ + wInterrupt_Mask = 0; + _SetCNTR(wInterrupt_Mask); + /*** Clear pending interrupts ***/ + _SetISTR(0); + /*** Set interrupt mask ***/ + wInterrupt_Mask = CNTR_RESETM | CNTR_SUSPM | CNTR_WKUPM; + _SetCNTR(wInterrupt_Mask); +#endif /* STM32F10X_CL */ + + return USB_SUCCESS; +} + +/******************************************************************************* +* Function Name : PowerOff +* Description : handles switch-off conditions +* Input : None. +* Output : None. +* Return : USB_SUCCESS. +*******************************************************************************/ +RESULT PowerOff() +{ +#ifndef STM32F10X_CL + /* disable all ints and force USB reset */ + _SetCNTR(CNTR_FRES); + /* clear interrupt status register */ + _SetISTR(0); + /* Disable the Pull-Up */ + USB_Cable_Config(DISABLE); + /* switch-off device */ + _SetCNTR(CNTR_FRES + CNTR_PDWN); +#endif /* STM32F10X_CL */ + + /* sw variables reset */ + /* ... */ + + return USB_SUCCESS; +} + +/******************************************************************************* +* Function Name : Enter_LowPowerMode. +* Description : Power-off system clocks and power while entering suspend mode. +* Input : None. +* Output : None. +* Return : None. +*******************************************************************************/ +void Enter_LowPowerMode(void) +{ + /* Set the device state to suspend */ + bDeviceState = SUSPENDED; +} + +/******************************************************************************* +* Function Name : Suspend +* Description : sets suspend mode operating conditions +* Input : None. +* Output : None. +* Return : USB_SUCCESS. +*******************************************************************************/ +void Suspend(void) +{ +#ifndef STM32F10X_CL + uint16_t wCNTR; + /* suspend preparation */ + /* ... */ + + /* macrocell enters suspend mode */ + wCNTR = _GetCNTR(); + wCNTR |= CNTR_FSUSP; + _SetCNTR(wCNTR); +#endif /* STM32F10X_CL */ + + /* ------------------ ONLY WITH BUS-POWERED DEVICES ---------------------- */ + /* power reduction */ + /* ... on connected devices */ + +#ifndef STM32F10X_CL + /* force low-power mode in the macrocell */ + wCNTR = _GetCNTR(); + wCNTR |= CNTR_LPMODE; + _SetCNTR(wCNTR); +#endif /* STM32F10X_CL */ + + /* switch-off the clocks */ + /* ... */ + Enter_LowPowerMode(); +} + +/******************************************************************************* +* Function Name : Leave_LowPowerMode. +* Description : Restores system clocks and power while exiting suspend mode. +* Input : None. +* Output : None. +* Return : None. +*******************************************************************************/ +void Leave_LowPowerMode(void) +{ + DEVICE_INFO *pInfo = &Device_Info; + + /* Set the device state to the correct state */ + if (pInfo->Current_Configuration != 0) { + /* Device configured */ + bDeviceState = CONFIGURED; + } else { + bDeviceState = ATTACHED; + } +} + +/******************************************************************************* +* Function Name : Resume_Init +* Description : Handles wake-up restoring normal operations +* Input : None. +* Output : None. +* Return : USB_SUCCESS. +*******************************************************************************/ +void Resume_Init(void) +{ +#ifndef STM32F10X_CL + uint16_t wCNTR; +#endif /* STM32F10X_CL */ + + /* ------------------ ONLY WITH BUS-POWERED DEVICES ---------------------- */ + /* restart the clocks */ + /* ... */ + +#ifndef STM32F10X_CL + /* CNTR_LPMODE = 0 */ + wCNTR = _GetCNTR(); + wCNTR &= (~CNTR_LPMODE); + _SetCNTR(wCNTR); +#endif /* STM32F10X_CL */ + + /* restore full power */ + /* ... on connected devices */ + Leave_LowPowerMode(); + +#ifndef STM32F10X_CL + /* reset FSUSP bit */ + _SetCNTR(IMR_MSK); +#endif /* STM32F10X_CL */ + + /* reverse suspend preparation */ + /* ... */ +} + +/******************************************************************************* +* Function Name : Resume +* Description : This is the state machine handling resume operations and +* timing sequence. The control is based on the Resume structure +* variables and on the ESOF interrupt calling this subroutine +* without changing machine state. +* Input : a state machine value (RESUME_STATE) +* RESUME_ESOF doesn't change ResumeS.eState allowing +* decrementing of the ESOF counter in different states. +* Output : None. +* Return : None. +*******************************************************************************/ +void Resume(RESUME_STATE eResumeSetVal) +{ +#ifndef STM32F10X_CL + uint16_t wCNTR; +#endif /* STM32F10X_CL */ + + if (eResumeSetVal != RESUME_ESOF) { + ResumeS.eState = eResumeSetVal; + } + + switch (ResumeS.eState) { + case RESUME_EXTERNAL: + Resume_Init(); + ResumeS.eState = RESUME_OFF; + break; + case RESUME_INTERNAL: + Resume_Init(); + ResumeS.eState = RESUME_START; + break; + case RESUME_LATER: + ResumeS.bESOFcnt = 2; + ResumeS.eState = RESUME_WAIT; + break; + case RESUME_WAIT: + ResumeS.bESOFcnt--; + if (ResumeS.bESOFcnt == 0) { + ResumeS.eState = RESUME_START; + } + break; + case RESUME_START: +#ifdef STM32F10X_CL + OTGD_FS_SetRemoteWakeup(); +#else + wCNTR = _GetCNTR(); + wCNTR |= CNTR_RESUME; + _SetCNTR(wCNTR); +#endif /* STM32F10X_CL */ + ResumeS.eState = RESUME_ON; + ResumeS.bESOFcnt = 10; + break; + case RESUME_ON: +#ifndef STM32F10X_CL + ResumeS.bESOFcnt--; + if (ResumeS.bESOFcnt == 0) { +#endif /* STM32F10X_CL */ +#ifdef STM32F10X_CL + OTGD_FS_ResetRemoteWakeup(); +#else + wCNTR = _GetCNTR(); + wCNTR &= (~CNTR_RESUME); + _SetCNTR(wCNTR); +#endif /* STM32F10X_CL */ + ResumeS.eState = RESUME_OFF; +#ifndef STM32F10X_CL + } +#endif /* STM32F10X_CL */ + break; + case RESUME_OFF: + case RESUME_ESOF: + default: + ResumeS.eState = RESUME_OFF; + break; + } +} + +/******************* (C) COPYRIGHT 2010 STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/pios_usbhook.c b/flight/pios/stm32f30x/pios_usbhook.c new file mode 100644 index 0000000000..738eacd91f --- /dev/null +++ b/flight/pios/stm32f30x/pios_usbhook.c @@ -0,0 +1,572 @@ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_USBHOOK USB glue code + * @brief Glue between PiOS and STM32 libs + * @{ + * + * @file pios_usbhook.c + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief Glue between PiOS and STM32 libs + * @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.h" + +#ifdef PIOS_INCLUDE_USB + +#include "pios_usb.h" /* PIOS_USB_* */ +#include "pios_usbhook.h" +#include "pios_usb_defs.h" /* struct usb_* */ +#include "pios_usb_hid_pwr.h" +#include "pios_usb_cdc_priv.h" /* PIOS_USB_CDC_* */ +#include "pios_usb_board_data.h" /* PIOS_USB_BOARD_* */ + +/* STM32 USB Library Definitions */ +#include "usb_lib.h" + +static void (*ep0_rxready_cb)(void) = 0; + +static ONE_DESCRIPTOR Device_Descriptor; + +void PIOS_USBHOOK_RegisterDevice(const uint8_t *desc, uint16_t desc_size) +{ + Device_Descriptor.Descriptor = desc; + Device_Descriptor.Descriptor_Size = desc_size; +} + +static ONE_DESCRIPTOR Config_Descriptor; + +void PIOS_USBHOOK_RegisterConfig(__attribute__((unused)) uint8_t config_id, const uint8_t *desc, uint16_t desc_size) +{ + Config_Descriptor.Descriptor = desc; + Config_Descriptor.Descriptor_Size = desc_size; +} + +static ONE_DESCRIPTOR String_Descriptor[4]; + +void PIOS_USBHOOK_RegisterString(enum usb_string_desc string_id, const uint8_t *desc, uint16_t desc_size) +{ + if (string_id < NELEMENTS(String_Descriptor)) { + String_Descriptor[string_id].Descriptor = desc; + String_Descriptor[string_id].Descriptor_Size = desc_size; + } +} + +static ONE_DESCRIPTOR Hid_Descriptor; + +void PIOS_USB_HID_RegisterHidDescriptor(const uint8_t *desc, uint16_t desc_size) +{ + Hid_Descriptor.Descriptor = desc; + Hid_Descriptor.Descriptor_Size = desc_size; +} + +static ONE_DESCRIPTOR Hid_Report_Descriptor; + +void PIOS_USB_HID_RegisterHidReport(const uint8_t *desc, uint16_t desc_size) +{ + Hid_Report_Descriptor.Descriptor = desc; + Hid_Report_Descriptor.Descriptor_Size = desc_size; +} + +void PIOS_USBHOOK_Deactivate(void) +{} + +#include "stm32f30x.h" /* __IO */ +__IO uint8_t EXTI_Enable; + +uint32_t ProtocolValue; + +DEVICE Device_Table = { + PIOS_USB_BOARD_EP_NUM, + 1 +}; + +static void PIOS_USBHOOK_Init(void); +static void PIOS_USBHOOK_Reset(void); +static void PIOS_USBHOOK_Status_In(void); +static void PIOS_USBHOOK_Status_Out(void); +static RESULT PIOS_USBHOOK_Data_Setup(uint8_t RequestNo); +static RESULT PIOS_USBHOOK_NoData_Setup(uint8_t RequestNo); +static RESULT PIOS_USBHOOK_Get_Interface_Setting(uint8_t Interface, uint8_t AlternateSetting); +static const uint8_t *PIOS_USBHOOK_GetDeviceDescriptor(uint16_t Length); +static const uint8_t *PIOS_USBHOOK_GetConfigDescriptor(uint16_t Length); +static const uint8_t *PIOS_USBHOOK_GetStringDescriptor(uint16_t Length); + +DEVICE_PROP Device_Property = { + .Init = PIOS_USBHOOK_Init, + .Reset = PIOS_USBHOOK_Reset, + .Process_Status_IN = PIOS_USBHOOK_Status_In, + .Process_Status_OUT = PIOS_USBHOOK_Status_Out, + .Class_Data_Setup = PIOS_USBHOOK_Data_Setup, + .Class_NoData_Setup = PIOS_USBHOOK_NoData_Setup, + .Class_Get_Interface_Setting = PIOS_USBHOOK_Get_Interface_Setting, + .GetDeviceDescriptor = PIOS_USBHOOK_GetDeviceDescriptor, + .GetConfigDescriptor = PIOS_USBHOOK_GetConfigDescriptor, + .GetStringDescriptor = PIOS_USBHOOK_GetStringDescriptor, + .RxEP_buffer = 0, + .MaxPacketSize = 0x40, +}; + +static void PIOS_USBHOOK_SetConfiguration(void); +static void PIOS_USBHOOK_SetDeviceAddress(void); + +USER_STANDARD_REQUESTS User_Standard_Requests = { + .User_GetConfiguration = NOP_Process, + .User_SetConfiguration = PIOS_USBHOOK_SetConfiguration, + .User_GetInterface = NOP_Process, + .User_SetInterface = NOP_Process, + .User_GetStatus = NOP_Process, + .User_ClearFeature = NOP_Process, + .User_SetEndPointFeature = NOP_Process, + .User_SetDeviceFeature = NOP_Process, + .User_SetDeviceAddress = PIOS_USBHOOK_SetDeviceAddress +}; + +static RESULT PIOS_USBHOOK_SetProtocol(void); +static const uint8_t *PIOS_USBHOOK_GetProtocolValue(uint16_t Length); +static const uint8_t *PIOS_USBHOOK_GetReportDescriptor(uint16_t Length); +static const uint8_t *PIOS_USBHOOK_GetHIDDescriptor(uint16_t Length); + +/******************************************************************************* +* Function Name : PIOS_USBHOOK_Init. +* Description : Custom HID init routine. +* Input : None. +* Output : None. +* Return : None. +*******************************************************************************/ +static void PIOS_USBHOOK_Init(void) +{ + pInformation->Current_Configuration = 0; + + /* Connect the device */ + PowerOn(); + + /* Perform basic device initialization operations */ + USB_SIL_Init(); + + bDeviceState = UNCONNECTED; +} + +/******************************************************************************* +* Function Name : PIOS_USBHOOK_Reset. +* Description : Custom HID reset routine. +* Input : None. +* Output : None. +* Return : None. +*******************************************************************************/ +static void PIOS_USBHOOK_Reset(void) +{ + /* Set DEVICE as not configured */ + pInformation->Current_Configuration = 0; + pInformation->Current_Interface = 0; /*the default Interface */ + + /* Current Feature initialization */ + pInformation->Current_Feature = 0; + +#ifdef STM32F10X_CL + /* EP0 is already configured in DFU_Init() by USB_SIL_Init() function */ + + /* Init EP1 IN as Interrupt endpoint */ + OTG_DEV_EP_Init(EP1_IN, OTG_DEV_EP_TYPE_INT, 2); + + /* Init EP1 OUT as Interrupt endpoint */ + OTG_DEV_EP_Init(EP1_OUT, OTG_DEV_EP_TYPE_INT, 2); +#else + SetBTABLE(BTABLE_ADDRESS); + + /* Initialize Endpoint 0 (Control) */ + SetEPType(ENDP0, EP_CONTROL); + SetEPTxAddr(ENDP0, ENDP0_TXADDR); + SetEPTxStatus(ENDP0, EP_TX_STALL); + Clear_Status_Out(ENDP0); + + SetEPRxAddr(ENDP0, ENDP0_RXADDR); + SetEPRxCount(ENDP0, Device_Property.MaxPacketSize); + SetEPRxValid(ENDP0); + +#if defined(PIOS_INCLUDE_USB_HID) + /* Initialize Endpoint 1 (HID) */ + SetEPType(ENDP1, EP_INTERRUPT); + SetEPTxAddr(ENDP1, ENDP1_TXADDR); + SetEPTxCount(ENDP1, PIOS_USB_BOARD_HID_DATA_LENGTH); + SetEPTxStatus(ENDP1, EP_TX_NAK); + + SetEPRxAddr(ENDP1, ENDP1_RXADDR); + SetEPRxCount(ENDP1, PIOS_USB_BOARD_HID_DATA_LENGTH); + SetEPRxStatus(ENDP1, EP_RX_VALID); +#endif /* PIOS_INCLUDE_USB_HID */ + +#if defined(PIOS_INCLUDE_USB_CDC) + /* Initialize Endpoint 2 (CDC Call Control) */ + SetEPType(ENDP2, EP_INTERRUPT); + SetEPTxAddr(ENDP2, ENDP2_TXADDR); + SetEPTxStatus(ENDP2, EP_TX_NAK); + + SetEPRxAddr(ENDP2, ENDP2_RXADDR); + SetEPRxCount(ENDP2, PIOS_USB_BOARD_CDC_MGMT_LENGTH); + SetEPRxStatus(ENDP2, EP_RX_DIS); + + /* Initialize Endpoint 3 (CDC Data) */ + SetEPType(ENDP3, EP_BULK); + SetEPTxAddr(ENDP3, ENDP3_TXADDR); + SetEPTxStatus(ENDP3, EP_TX_NAK); + + SetEPRxAddr(ENDP3, ENDP3_RXADDR); + SetEPRxCount(ENDP3, PIOS_USB_BOARD_CDC_DATA_LENGTH); + SetEPRxStatus(ENDP3, EP_RX_VALID); + +#endif /* PIOS_INCLUDE_USB_CDC */ + + /* Set this device to response on default address */ + SetDeviceAddress(0); +#endif /* STM32F10X_CL */ + + bDeviceState = ATTACHED; +} + +/******************************************************************************* +* Function Name : PIOS_USBHOOK_SetConfiguration. +* Description : Update the device state to configured +* Input : None. +* Output : None. +* Return : None. +*******************************************************************************/ +static void PIOS_USBHOOK_SetConfiguration(void) +{ + if (pInformation->Current_Configuration != 0) { + /* Device configured */ + bDeviceState = CONFIGURED; + } + + /* Enable transfers */ + PIOS_USB_ChangeConnectionState(pInformation->Current_Configuration != 0); +} + +/******************************************************************************* +* Function Name : PIOS_USBHOOK_SetConfiguration. +* Description : Update the device state to addressed. +* Input : None. +* Output : None. +* Return : None. +*******************************************************************************/ +static void PIOS_USBHOOK_SetDeviceAddress(void) +{ + bDeviceState = ADDRESSED; +} + +/******************************************************************************* +* Function Name : PIOS_USBHOOK_Status_In. +* Description : status IN routine. +* Input : None. +* Output : None. +* Return : None. +*******************************************************************************/ +static void PIOS_USBHOOK_Status_In(void) +{ + /* this callback gets executed after sending ZLP and doing In0_Process(), to ack */ + if (ep0_rxready_cb) { + ep0_rxready_cb(); + ep0_rxready_cb = 0; + } +} + +/******************************************************************************* +* Function Name : PIOS_USBHOOK_Status_Out +* Description : status OUT routine. +* Input : None. +* Output : None. +* Return : None. +*******************************************************************************/ +static void PIOS_USBHOOK_Status_Out(void) +{} + +/******************************************************************************* +* Function Name : PIOS_USBHOOK_Data_Setup +* Description : Handle the data class specific requests. +* Input : Request Nb. +* Output : None. +* Return : USB_UNSUPPORT or USB_SUCCESS. +*******************************************************************************/ +extern uint8_t *PIOS_USB_CDC_SetLineCoding(uint16_t Length); +extern const uint8_t *PIOS_USB_CDC_GetLineCoding(uint16_t Length); +extern void PIOS_USB_CDC_SetLineCoding_Completed(); + +static RESULT PIOS_USBHOOK_Data_Setup(uint8_t RequestNo) +{ + uint8_t *(*CopyOutRoutine)(uint16_t); + const uint8_t *(*CopyInRoutine)(uint16_t); + + CopyInRoutine = NULL; + CopyOutRoutine = NULL; + + switch (Type_Recipient) { + case (STANDARD_REQUEST | INTERFACE_RECIPIENT): + switch (pInformation->USBwIndex0) { +#if defined(PIOS_INCLUDE_USB_CDC) + case 2: /* HID Interface */ +#else + case 0: /* HID Interface */ +#endif + switch (RequestNo) { + case GET_DESCRIPTOR: + switch (pInformation->USBwValue1) { + case USB_DESC_TYPE_REPORT: + CopyInRoutine = PIOS_USBHOOK_GetReportDescriptor; + break; + case USB_DESC_TYPE_HID: + CopyInRoutine = PIOS_USBHOOK_GetHIDDescriptor; + break; + } + } + } + break; + + case (CLASS_REQUEST | INTERFACE_RECIPIENT): + switch (pInformation->USBwIndex0) { +#if defined(PIOS_INCLUDE_USB_CDC) + case 2: /* HID Interface */ +#else + case 0: /* HID Interface */ +#endif + switch (RequestNo) { + case USB_HID_REQ_GET_PROTOCOL: + CopyInRoutine = PIOS_USBHOOK_GetProtocolValue; + break; + } + + break; +#if defined(PIOS_INCLUDE_USB_CDC) + case 0: /* CDC Call Control Interface */ + switch (RequestNo) { + case USB_CDC_REQ_SET_LINE_CODING: + CopyOutRoutine = PIOS_USB_CDC_SetLineCoding; + ep0_rxready_cb = PIOS_USB_CDC_SetLineCoding_Completed; + break; + case USB_CDC_REQ_GET_LINE_CODING: + CopyInRoutine = PIOS_USB_CDC_GetLineCoding; + break; + } + + break; + + case 1: /* CDC Data Interface */ + switch (RequestNo) { + case 0: + break; + } + + break; +#endif /* PIOS_INCLUDE_USB_CDC */ + } + break; + } + + /* No registered copy routine */ + if ((CopyInRoutine == NULL) && (CopyOutRoutine == NULL)) { + return USB_UNSUPPORT; + } + + /* Registered copy in AND copy out routine */ + if ((CopyInRoutine != NULL) && (CopyOutRoutine != NULL)) { + /* This should never happen */ + return USB_UNSUPPORT; + } + + if (CopyInRoutine != NULL) { + pInformation->Ctrl_Info.CopyData = (typeof(pInformation->Ctrl_Info.CopyData))CopyInRoutine; + pInformation->Ctrl_Info.Usb_wOffset = 0; + (*CopyInRoutine)(0); + } else if (CopyOutRoutine != NULL) { + pInformation->Ctrl_Info.CopyData = CopyOutRoutine; + pInformation->Ctrl_Info.Usb_rOffset = 0; + (*CopyOutRoutine)(0); + } + + return USB_SUCCESS; +} + +/******************************************************************************* +* Function Name : PIOS_USBHOOK_NoData_Setup +* Description : handle the no data class specific requests +* Input : Request Nb. +* Output : None. +* Return : USB_UNSUPPORT or USB_SUCCESS. +*******************************************************************************/ +extern RESULT PIOS_USB_CDC_SetControlLineState(void); + +static RESULT PIOS_USBHOOK_NoData_Setup(uint8_t RequestNo) +{ + switch (Type_Recipient) { + case (CLASS_REQUEST | INTERFACE_RECIPIENT): + switch (pInformation->USBwIndex0) { +#if defined(PIOS_INCLUDE_USB_CDC) + case 2: /* HID */ +#else + case 0: /* HID */ +#endif + switch (RequestNo) { + case USB_HID_REQ_SET_PROTOCOL: + return PIOS_USBHOOK_SetProtocol(); + + break; + } + + break; + +#if defined(PIOS_INCLUDE_USB_CDC) + case 0: /* CDC Call Control Interface */ + switch (RequestNo) { + case USB_CDC_REQ_SET_CONTROL_LINE_STATE: + return PIOS_USB_CDC_SetControlLineState(); + + break; + } + + break; +#endif /* PIOS_INCLUDE_USB_CDC */ + } + + break; + } + + return USB_UNSUPPORT; +} + +/******************************************************************************* +* Function Name : PIOS_USBHOOK_GetDeviceDescriptor. +* Description : Gets the device descriptor. +* Input : Length +* Output : None. +* Return : The address of the device descriptor. +*******************************************************************************/ +static const uint8_t *PIOS_USBHOOK_GetDeviceDescriptor(uint16_t Length) +{ + return Standard_GetDescriptorData(Length, &Device_Descriptor); +} + +/******************************************************************************* +* Function Name : PIOS_USBHOOK_GetConfigDescriptor. +* Description : Gets the configuration descriptor. +* Input : Length +* Output : None. +* Return : The address of the configuration descriptor. +*******************************************************************************/ +static const uint8_t *PIOS_USBHOOK_GetConfigDescriptor(uint16_t Length) +{ + return Standard_GetDescriptorData(Length, &Config_Descriptor); +} + +/******************************************************************************* +* Function Name : PIOS_USBHOOK_GetStringDescriptor +* Description : Gets the string descriptors according to the needed index +* Input : Length +* Output : None. +* Return : The address of the string descriptors. +*******************************************************************************/ +static const uint8_t *PIOS_USBHOOK_GetStringDescriptor(uint16_t Length) +{ + uint8_t wValue0 = pInformation->USBwValue0; + + if (wValue0 > 4) { + return NULL; + } else { + return Standard_GetDescriptorData(Length, &String_Descriptor[wValue0]); + } +} + +/******************************************************************************* +* Function Name : PIOS_USBHOOK_GetReportDescriptor. +* Description : Gets the HID report descriptor. +* Input : Length +* Output : None. +* Return : The address of the configuration descriptor. +*******************************************************************************/ +static const uint8_t *PIOS_USBHOOK_GetReportDescriptor(uint16_t Length) +{ + return Standard_GetDescriptorData(Length, &Hid_Report_Descriptor); +} + +/******************************************************************************* +* Function Name : PIOS_USBHOOK_GetHIDDescriptor. +* Description : Gets the HID descriptor. +* Input : Length +* Output : None. +* Return : The address of the configuration descriptor. +*******************************************************************************/ +static const uint8_t *PIOS_USBHOOK_GetHIDDescriptor(uint16_t Length) +{ + return Standard_GetDescriptorData(Length, &Hid_Descriptor); +} + +/******************************************************************************* +* Function Name : PIOS_USBHOOK_Get_Interface_Setting. +* Description : tests the interface and the alternate setting according to the +* supported one. +* Input : - Interface : interface number. +* - AlternateSetting : Alternate Setting number. +* Output : None. +* Return : USB_SUCCESS or USB_UNSUPPORT. +*******************************************************************************/ +static RESULT PIOS_USBHOOK_Get_Interface_Setting(uint8_t Interface, uint8_t AlternateSetting) +{ + if (AlternateSetting > 0) { + return USB_UNSUPPORT; + } else if (Interface > 0) { + return USB_UNSUPPORT; + } + return USB_SUCCESS; +} + +/******************************************************************************* +* Function Name : PIOS_USBHOOK_SetProtocol +* Description : Set Protocol request routine. +* Input : None. +* Output : None. +* Return : USB SUCCESS. +*******************************************************************************/ +static RESULT PIOS_USBHOOK_SetProtocol(void) +{ + uint8_t wValue0 = pInformation->USBwValue0; + + ProtocolValue = wValue0; + return USB_SUCCESS; +} + +/******************************************************************************* +* Function Name : PIOS_USBHOOK_GetProtocolValue +* Description : get the protocol value +* Input : Length. +* Output : None. +* Return : address of the protcol value. +*******************************************************************************/ +static const uint8_t *PIOS_USBHOOK_GetProtocolValue(uint16_t Length) +{ + if (Length == 0) { + pInformation->Ctrl_Info.Usb_wLength = 1; + return NULL; + } else { + return (uint8_t *)(&ProtocolValue); + } +} + +#endif /* PIOS_INCLUDE_USB */ + +/******************* (C) COPYRIGHT 2010 STMicroelectronics *****END OF FILE****/ diff --git a/flight/pios/stm32f30x/pios_wdg.c b/flight/pios/stm32f30x/pios_wdg.c new file mode 100644 index 0000000000..5e41b229cd --- /dev/null +++ b/flight/pios/stm32f30x/pios_wdg.c @@ -0,0 +1,186 @@ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_WDG Watchdog Functions + * @brief PIOS Comamnds to initialize and clear watchdog timer + * @{ + * + * @file pios_spi.c + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012. + * Parts by Thorsten Klose (tk@midibox.org) (tk@midibox.org) + * @brief Hardware Abstraction Layer for SPI ports of STM32 + * @see The GNU Public License (GPL) Version 3 + * @notes + * + * The PIOS Watchdog provides a HAL to initialize a watchdog + * + *****************************************************************************/ +/* + * 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 + */ + +/* + * @todo This is virtually identical to the F1xx code and should be merged. + */ + +#include "pios.h" + +#ifdef PIOS_INCLUDE_WDG + +#include "stm32f30x_iwdg.h" +#include "stm32f30x_dbgmcu.h" +#include "stm32f30x_rtc.h" + +static struct wdg_configuration { + uint16_t used_flags; + uint16_t bootup_flags; +} wdg_configuration; + +/** + * @brief Initialize the watchdog timer for a specified timeout + * + * It is important to note that this function returns the achieved timeout + * for this hardware. For hardware independence this should be checked when + * scheduling updates. Other hardware dependent details may need to be + * considered such as a window time which sets a minimum update time, + * and this function should return a recommended delay for clearing. + * + * For the STM32 nominal clock rate is 32 khz, but for the maximum clock rate of + * 60 khz and a prescaler of 4 yields a clock rate of 15 khz. The delay that is + * set in the watchdog assumes the nominal clock rate, but the delay for FreeRTOS + * to use is 75% of the minimal delay. + * + * @returns Maximum recommended delay between updates based on PIOS_WATCHDOG_TIMEOUT constant + */ +uint16_t PIOS_WDG_Init() +{ + uint16_t delay = ((uint32_t)PIOS_WATCHDOG_TIMEOUT * 60) / 16; + + if (delay > 0x0fff) { + delay = 0x0fff; + } +#if defined(PIOS_INCLUDE_WDG) + DBGMCU_APB1PeriphConfig(DBGMCU_IWDG_STOP, ENABLE); // OP-1272 : write in APB1 register + IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable); + IWDG_SetPrescaler(IWDG_Prescaler_16); + IWDG_SetReload(delay); + IWDG_ReloadCounter(); + IWDG_Enable(); + + // watchdog flags now stored in backup registers + PWR_BackupAccessCmd(ENABLE); + + wdg_configuration.bootup_flags = RTC_ReadBackupRegister(PIOS_WDG_REGISTER); +#endif + return delay; +} + +/** + * @brief Register a module against the watchdog + * + * There are two ways to use PIOS WDG: this is for when + * multiple modules must be monitored. In this case they + * must first register against the watchdog system and + * only when all of the modules have been updated with the + * watchdog be cleared. Each module must have its own + * bit in the 16 bit + * + * @param[in] flag the bit this module wants to use + * @returns True if that bit is unregistered + */ +bool PIOS_WDG_RegisterFlag(uint16_t flag_requested) +{ + // flag are being registered so we are in module initialization phase + // clear the WDG to prevent timeout while initializing modules. (OP-815) + PIOS_WDG_Clear(); + + /* Fail if flag already registered */ + if (wdg_configuration.used_flags & flag_requested) { + return false; + } + + // FIXME: Protect with semaphore + wdg_configuration.used_flags |= flag_requested; + + return true; +} + +/** + * @brief Function called by modules to indicate they are still running + * + * This function will set this flag in the active flags register (which is + * a backup regsiter) and if all the registered flags are set will clear + * the watchdog and set only this flag in the backup register + * + * @param[in] flag the flag to set + * @return true if the watchdog cleared, false if flags are pending + */ +bool PIOS_WDG_UpdateFlag(uint16_t flag) +{ + // we can probably avoid using a semaphore here which will be good for + // efficiency and not blocking critical tasks. race condition could + // overwrite their flag update, but unlikely to block _all_ of them + // for the timeout window + uint16_t cur_flags = RTC_ReadBackupRegister(PIOS_WDG_REGISTER); + + if ((cur_flags | flag) == wdg_configuration.used_flags) { + PIOS_WDG_Clear(); + RTC_WriteBackupRegister(PIOS_WDG_REGISTER, flag); + return true; + } else { + RTC_WriteBackupRegister(PIOS_WDG_REGISTER, cur_flags | flag); + return false; + } +} + +/** + * @brief Returns the flags that were set at bootup + * + * This is used for diagnostics, if only one flag not set this + * was likely the module that wasn't running before reset + * + * @return The active flags register from bootup + */ +uint16_t PIOS_WDG_GetBootupFlags() +{ + return wdg_configuration.bootup_flags; +} + +/** + * @brief Returns the currently active flags + * + * For external monitoring + * + * @return The active flags register + */ +uint16_t PIOS_WDG_GetActiveFlags() +{ + return RTC_ReadBackupRegister(PIOS_WDG_REGISTER); +} + +/** + * @brief Clear the watchdog timer + * + * This function must be called at the appropriate delay to prevent a reset event occuring + */ +void PIOS_WDG_Clear(void) +{ +#if defined(PIOS_INCLUDE_WDG) + IWDG_ReloadCounter(); +#endif +} + +#endif /* PIOS_INCLUDE_WDG */ diff --git a/flight/pios/stm32f30x/startup.c b/flight/pios/stm32f30x/startup.c new file mode 100644 index 0000000000..e4299b60f8 --- /dev/null +++ b/flight/pios/stm32f30x/startup.c @@ -0,0 +1,189 @@ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * + * @file startup.c + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012. + * @author Tau Labs, http://taulabs.org, Copyright (C) 2012-2013 + * @brief C based startup of F3 + * @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 +#include + +/* prototype for main() that tells us not to worry about it possibly returning */ +extern int main(void) __attribute__((noreturn)); + +/* prototype our _main() to avoid prolog/epilog insertion and other related junk */ +void _main(void) __attribute__((noreturn, naked, no_instrument_function)); + +/** default handler for CPU exceptions */ +static void default_cpu_handler(void) __attribute__((noreturn, naked, no_instrument_function)); + +/** BSS symbols XXX should have a header that defines all of these */ +extern char _sbss, _ebss; + +/** DATA symbols XXX should have a header that defines all of these */ +extern char _sidata, _sdata, _edata, _sfast, _efast; + +/** The bootstrap/IRQ stack XXX should define size somewhere else */ +char irq_stack[1024] __attribute__((section(".irqstack"))); + +/** exception handler */ +typedef void (vector)(void); + +/** CortexM3 CPU vectors */ +struct cm3_vectors { + void *initial_stack; + vector *entry; + vector *vectors[14]; +}; + +/** + * Initial startup code. + */ +void _main(void) +{ + // load the stack base for the current stack before we attempt to branch to any function + // that might bounds-check the stack + asm volatile ("mov r10, %0" : : "r" (&irq_stack[0]) :); + + /* enable usage, bus and memory faults */ + SCB->SHCSR |= SCB_SHCSR_USGFAULTENA_Msk | SCB_SHCSR_BUSFAULTENA_Msk | SCB_SHCSR_MEMFAULTENA_Msk; + + /* configure FP state save behaviour - automatic, lazy save */ + FPU->FPCCR |= FPU_FPCCR_ASPEN_Msk | FPU_FPCCR_LSPEN_Msk; + + /* configure default FPU state */ + FPU->FPDSCR |= FPU_FPDSCR_DN_Msk; /* enable Default NaN */ + FPU->FPDSCR |= FPU_FPDSCR_FZ_Msk; /* Use flush to zero for very + * small values. */ + + /* enable the FPU */ + SCB->CPACR |= (0xf << 20); // turn on CP10/11 for FP support on cores that implement it + + /* copy initialised data from flash to RAM */ + memcpy(&_sdata, &_sidata, &_edata - &_sdata); + + /* zero the BSS */ + memset(&_sbss, 0, &_ebss - &_sbss); + + /* zero any 'fast' RAM that's been used */ + memset(&_sfast, 0, &_efast - &_sfast); + + /* fill most of the IRQ/bootstrap stack with a watermark pattern so we can measure how much is used */ + /* leave a little space at the top in case memset() isn't a leaf with no locals */ + memset(&irq_stack, 0xa5, sizeof(irq_stack) - 64); + + /* call main */ + (void)main(); +} + +/** + * Default handler for CPU exceptions. + */ +static void default_cpu_handler(void) +{ + for (;;) { + ; + } +} + +static void default_NMI_Handler() +{ + default_cpu_handler(); +} +static void default_HardFault_Handler() +{ + default_cpu_handler(); +} +static void default_MemManage_Handler() +{ + default_cpu_handler(); +} +static void default_BusFault_Handler() +{ + default_cpu_handler(); +} +static void default_UsageFault_Handler() +{ + default_cpu_handler(); +} +static void default_DebugMon_Handler() +{ + default_cpu_handler(); +} +static void default_vPortSVCHandler() +{ + default_cpu_handler(); +} +static void default_xPortPendSVHandler() +{ + default_cpu_handler(); +} +static void default_xPortSysTickHandler() +{ + default_cpu_handler(); +} + + +/** Prototype for optional exception vector handlers */ +#define HANDLER(_name) extern vector _name __attribute__((weak, alias("default_" #_name))) + +/* standard CMSIS vector names */ +HANDLER(NMI_Handler); +HANDLER(HardFault_Handler); +HANDLER(MemManage_Handler); +HANDLER(BusFault_Handler); +HANDLER(UsageFault_Handler); +HANDLER(DebugMon_Handler); +/* these vectors point directly to the relevant FreeRTOS functions if they are defined */ +HANDLER(vPortSVCHandler); +HANDLER(xPortPendSVHandler); +HANDLER(xPortSysTickHandler); + +/** CortexM3 vector table */ +struct cm3_vectors cpu_vectors __attribute((section(".cpu_vectors"))) = +{ + .initial_stack = &irq_stack[sizeof(irq_stack)], + .entry = (vector *)_main, + .vectors = { + NMI_Handler, + HardFault_Handler, + MemManage_Handler, + BusFault_Handler, + UsageFault_Handler, + 0, + 0, + 0, + 0, + vPortSVCHandler, + DebugMon_Handler, // Maybe + 0, + xPortPendSVHandler, + xPortSysTickHandler, + } +}; + +/** + * @} + */ diff --git a/flight/pios/stm32f30x/vectors_stm32f30x.c b/flight/pios/stm32f30x/vectors_stm32f30x.c new file mode 100644 index 0000000000..713366c74a --- /dev/null +++ b/flight/pios/stm32f30x/vectors_stm32f30x.c @@ -0,0 +1,309 @@ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * + * @file vector_stm32f4xx.c + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012. + * @author Tau Labs, http://taulabs.org, Copyright (C) 2012-2013 + * @brief C based vectors for F4 + * @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 + */ + +/** interrupt handler */ +typedef void (vector)(void); + +/** default interrupt handler */ +static void default_io_handler(void) +{ + for (;;) { + ; + } +} + +/** prototypes an interrupt handler */ +#define HANDLER(_name) extern vector _name __attribute__((weak, alias("default_io_handler"))) + +HANDLER(Reserved_IRQHandler); // Reserved +HANDLER(WWDG_IRQHandler); // Window WatchDog +HANDLER(PVD_IRQHandler); // PVD through EXTI Line detection +HANDLER(TAMP_STAMP_IRQHandler); // Tamper and TimeStamps through the EXTI line +HANDLER(RTC_WKUP_IRQHandler); // RTC Wakeup through the EXTI line +HANDLER(FLASH_IRQHandler); // FLASH +HANDLER(RCC_IRQHandler); // RCC +HANDLER(EXTI0_IRQHandler); // EXTI Line0 +HANDLER(EXTI1_IRQHandler); // EXTI Line1 +HANDLER(EXTI2_TS_IRQHandler); // EXTI Line2 and Touch Sense Interrupt +HANDLER(EXTI3_IRQHandler); // EXTI Line3 +HANDLER(EXTI4_IRQHandler); // EXTI Line4 +HANDLER(DMA1_Channel1_IRQHandler); // DMA1 Channel 1 +HANDLER(DMA1_Channel2_IRQHandler); // DMA1 Channel 2 +HANDLER(DMA1_Channel3_IRQHandler); // DMA1 Channel 3 +HANDLER(DMA1_Channel4_IRQHandler); // DMA1 Channel 4 +HANDLER(DMA1_Channel5_IRQHandler); // DMA1 Channel 5 +HANDLER(DMA1_Channel6_IRQHandler); // DMA1 Channel 6 +HANDLER(DMA1_Channel7_IRQHandler); // DMA1 Channel 7 +HANDLER(ADC1_2_IRQHandler); // ADC1 and ADC2 +HANDLER(USB_HP_CAN1_TX_IRQHandler); // USB Device High Priority or CAN1 TX +HANDLER(USB_LP_CAN1_RX0_IRQHandler); // USB Device Low Priority or CAN1 RX0 +HANDLER(CAN1_RX1_IRQHandler); // CAN1 RX1 +HANDLER(CAN1_SCE_IRQHandler); // CAN1 SCE +HANDLER(EXTI9_5_IRQHandler); // External Line[9:5]s +HANDLER(TIM1_BRK_TIM15_IRQHandler); // TIM1 Break and TIM15 +HANDLER(TIM1_UP_TIM16_IRQHandler); // TIM1 Update and TIM16 +HANDLER(TIM1_TRG_COM_TIM17_IRQHandler); // TIM1 Trigger and Commutation and TIM17 +HANDLER(TIM1_CC_IRQHandler); // TIM1 Capture Compare +HANDLER(TIM2_IRQHandler); // TIM2 +HANDLER(TIM3_IRQHandler); // TIM3 +HANDLER(TIM4_IRQHandler); // TIM4 +HANDLER(I2C1_EV_EXTI23_IRQHandler); // I2C1 Event and EXTI23 +HANDLER(I2C1_ER_IRQHandler); // I2C1 Error +HANDLER(I2C2_EV_EXTI24_IRQHandler); // I2C2 Event and EXTI24 +HANDLER(I2C2_ER_IRQHandler); // I2C2 Error +HANDLER(SPI1_IRQHandler); // SPI1 +HANDLER(SPI2_IRQHandler); // SPI2 +HANDLER(USART1_EXTI25_IRQHandler); // USART1 and EXTI25 +HANDLER(USART2_EXTI26_IRQHandler); // USART2 and EXTI26 +HANDLER(USART3_EXTI28_IRQHandler); // USART3 and EXTI28 +HANDLER(EXTI15_10_IRQHandler); // External Line[15:10]s +HANDLER(RTC_Alarm_IRQHandler); // RTC Alarm (A and B) through EXTI Line +HANDLER(USB_WKUP_IRQHandler); // USB FS Wakeup through EXTI line +HANDLER(TIM8_BRK_IRQHandler); // TIM8 Break +HANDLER(TIM8_UP_IRQHandler); // TIM8 Update +HANDLER(TIM8_TRG_COM_IRQHandler); // TIM8 Trigger and Commutation +HANDLER(TIM8_CC_IRQHandler); // TIM8 Capture Compare +HANDLER(ADC3_IRQHandler); // ADC3 +HANDLER(SPI3_IRQHandler); // SPI3 +HANDLER(UART4_EXTI34_IRQHandler); // UART4 and EXTI34 +HANDLER(UART5_EXTI35_IRQHandler); // UART5 and EXTI35 +HANDLER(TIM6_DAC_IRQHandler); // TIM6 and DAC1&2 underrun errors +HANDLER(TIM7_IRQHandler); // TIM7 +HANDLER(DMA2_Channel1_IRQHandler); // DMA2 Channel 1 +HANDLER(DMA2_Channel2_IRQHandler); // DMA2 Channel 2 +HANDLER(DMA2_Channel3_IRQHandler); // DMA2 Channel 3 +HANDLER(DMA2_Channel4_IRQHandler); // DMA2 Channel 4 +HANDLER(DMA2_Channel5_IRQHandler); // DMA2 Channel 5 +HANDLER(ADC4_IRQHandler); // ADC4 +HANDLER(COMP1_2_3_IRQHandler); // COMP1, COMP2 and COMP3 +HANDLER(COMP4_5_6_IRQHandler); // COMP4, COMP5 and COMP6 +HANDLER(COMP7_IRQHandler); // COMP7 +HANDLER(USB_HP_IRQHandler); // USB High Priority remap +HANDLER(USB_LP_IRQHandler); // USB Low Priority remap +HANDLER(USB_WKUP_RMP_IRQHandler); // USB Wakup remap +HANDLER(FPU_IRQHandler); // FPU + +/* STM32F303xE */ +HANDLER(TAMPER_STAMP_IRQHandler); +HANDLER(I2C1_EV_IRQHandler); +HANDLER(USART1_IRQHandler); +HANDLER(USART2_IRQHandler); +HANDLER(USART3_IRQHandler); +HANDLER(USBWakeUp_IRQHandler); +HANDLER(FMC_IRQHandler); +HANDLER(UART4_IRQHandler); +HANDLER(UART5_IRQHandler); +HANDLER(I2C3_EV_IRQHandler); +HANDLER(I2C3_ER_IRQHandler); +HANDLER(USBWakeUp_RMP_IRQHandler); +HANDLER(TIM20_BRK_IRQHandler); +HANDLER(TIM20_UP_IRQHandler); +HANDLER(TIM20_TRG_COM_IRQHandler); +HANDLER(TIM20_CC_IRQHandler); +HANDLER(SPI4_IRQHandler); +HANDLER(I2C2_EV_IRQHandler); + + +/** stm32f30x interrupt vector table */ +vector *io_vectors[] __attribute__((section(".io_vectors"))) = { +#ifdef STM32F303xC + WWDG_IRQHandler, // Window WatchDog + PVD_IRQHandler, // PVD through EXTI Line detection + TAMP_STAMP_IRQHandler, // Tamper and TimeStamps through the EXTI line + RTC_WKUP_IRQHandler, // RTC Wakeup through the EXTI line + FLASH_IRQHandler, // FLASH + RCC_IRQHandler, // RCC + EXTI0_IRQHandler, // EXTI Line0 + EXTI1_IRQHandler, // EXTI Line1 + EXTI2_TS_IRQHandler, // EXTI Line2 and Touch Sense Interrupt + EXTI3_IRQHandler, // EXTI Line3 + EXTI4_IRQHandler, // EXTI Line4 + DMA1_Channel1_IRQHandler, // DMA1 Channel 1 + DMA1_Channel2_IRQHandler, // DMA1 Channel 2 + DMA1_Channel3_IRQHandler, // DMA1 Channel 3 + DMA1_Channel4_IRQHandler, // DMA1 Channel 4 + DMA1_Channel5_IRQHandler, // DMA1 Channel 5 + DMA1_Channel6_IRQHandler, // DMA1 Channel 6 + DMA1_Channel7_IRQHandler, // DMA1 Channel 7 + ADC1_2_IRQHandler, // ADC1 and ADC2 + USB_HP_CAN1_TX_IRQHandler, // USB Device High Priority or CAN1 TX + USB_LP_CAN1_RX0_IRQHandler, // USB Device Low Priority or CAN1 RX0 + CAN1_RX1_IRQHandler, // CAN1 RX1 + CAN1_SCE_IRQHandler, // CAN1 SCE + EXTI9_5_IRQHandler, // External Line[9:5]s + TIM1_BRK_TIM15_IRQHandler, // TIM1 Break and TIM15 + TIM1_UP_TIM16_IRQHandler, // TIM1 Update and TIM16 + TIM1_TRG_COM_TIM17_IRQHandler, // TIM1 Trigger and Commutation and TIM17 + TIM1_CC_IRQHandler, // TIM1 Capture Compare + TIM2_IRQHandler, // TIM2 + TIM3_IRQHandler, // TIM3 + TIM4_IRQHandler, // TIM4 + I2C1_EV_EXTI23_IRQHandler, // I2C1 Event and EXTI23 + I2C1_ER_IRQHandler, // I2C1 Error + I2C2_EV_EXTI24_IRQHandler, // I2C2 Event and EXTI24 + I2C2_ER_IRQHandler, // I2C2 Error + SPI1_IRQHandler, // SPI1 + SPI2_IRQHandler, // SPI2 + USART1_EXTI25_IRQHandler, // USART1 and EXTI25 + USART2_EXTI26_IRQHandler, // USART2 and EXTI26 + USART3_EXTI28_IRQHandler, // USART3 and EXTI28 + EXTI15_10_IRQHandler, // External Line[15:10]s + RTC_Alarm_IRQHandler, // RTC Alarm (A and B) through EXTI Line + USB_WKUP_IRQHandler, // USB FS Wakeup through EXTI line + TIM8_BRK_IRQHandler, // TIM8 Break + TIM8_UP_IRQHandler, // TIM8 Update + TIM8_TRG_COM_IRQHandler, // TIM8 Trigger and Commutation + TIM8_CC_IRQHandler, // TIM8 Capture Compare + ADC3_IRQHandler, // ADC3 + Reserved_IRQHandler, // reserved + Reserved_IRQHandler, // reserved + Reserved_IRQHandler, // reserved + SPI3_IRQHandler, // SPI3 + UART4_EXTI34_IRQHandler, // UART4 and EXTI34 + UART5_EXTI35_IRQHandler, // UART5 and EXTI35 + TIM6_DAC_IRQHandler, // TIM6 and DAC1&2 underrun errors + TIM7_IRQHandler, // TIM7 + DMA2_Channel1_IRQHandler, // DMA2 Channel 1 + DMA2_Channel2_IRQHandler, // DMA2 Channel 2 + DMA2_Channel3_IRQHandler, // DMA2 Channel 3 + DMA2_Channel4_IRQHandler, // DMA2 Channel 4 + DMA2_Channel5_IRQHandler, // DMA2 Channel 5 + ADC4_IRQHandler, // ADC4 + Reserved_IRQHandler, // reserved + Reserved_IRQHandler, // reserved + COMP1_2_3_IRQHandler, // COMP1, COMP2 and COMP3 + COMP4_5_6_IRQHandler, // COMP4, COMP5 and COMP6 + COMP7_IRQHandler, // COMP7 + Reserved_IRQHandler, // reserved + Reserved_IRQHandler, // reserved + Reserved_IRQHandler, // reserved + Reserved_IRQHandler, // reserved + Reserved_IRQHandler, // reserved + Reserved_IRQHandler, // reserved + Reserved_IRQHandler, // reserved + USB_HP_IRQHandler, // USB High Priority remap + USB_LP_IRQHandler, // USB Low Priority remap + USB_WKUP_RMP_IRQHandler, // USB Wakup remap + Reserved_IRQHandler, // reserved + Reserved_IRQHandler, // reserved + Reserved_IRQHandler, // reserved + Reserved_IRQHandler, // reserved + FPU_IRQHandler, // FPU +#endif /* ifdef STM32F303xC */ +#ifdef STM32F303xE + WWDG_IRQHandler, /*!< Window WatchDog Interrupt */ + PVD_IRQHandler, /*!< PVD through EXTI Line detection Interrupt */ + TAMPER_STAMP_IRQHandler, /*!< Tamper and TimeStamp interrupts */ + RTC_WKUP_IRQHandler, /*!< RTC Wakeup interrupt through the EXTI lines 17, 19 & 20 */ + FLASH_IRQHandler, /*!< FLASH global Interrupt */ + RCC_IRQHandler, /*!< RCC global Interrupt */ + EXTI0_IRQHandler, /*!< EXTI Line0 Interrupt */ + EXTI1_IRQHandler, /*!< EXTI Line1 Interrupt */ + EXTI2_TS_IRQHandler, /*!< EXTI Line2 Interrupt and Touch Sense Interrupt */ + EXTI3_IRQHandler, /*!< EXTI Line3 Interrupt */ + EXTI4_IRQHandler, /*!< EXTI Line4 Interrupt */ + DMA1_Channel1_IRQHandler, /*!< DMA1 Channel 1 Interrupt */ + DMA1_Channel2_IRQHandler, /*!< DMA1 Channel 2 Interrupt */ + DMA1_Channel3_IRQHandler, /*!< DMA1 Channel 3 Interrupt */ + DMA1_Channel4_IRQHandler, /*!< DMA1 Channel 4 Interrupt */ + DMA1_Channel5_IRQHandler, /*!< DMA1 Channel 5 Interrupt */ + DMA1_Channel6_IRQHandler, /*!< DMA1 Channel 6 Interrupt */ + DMA1_Channel7_IRQHandler, /*!< DMA1 Channel 7 Interrupt */ + ADC1_2_IRQHandler, /*!< ADC1 & ADC2 Interrupts */ + USB_HP_CAN1_TX_IRQHandler, /*!< USB Device High Priority or CAN1 TX Interrupts */ + USB_LP_CAN1_RX0_IRQHandler, /*!< USB Device Low Priority or CAN1 RX0 Interrupts */ + CAN1_RX1_IRQHandler, /*!< CAN1 RX1 Interrupt */ + CAN1_SCE_IRQHandler, /*!< CAN1 SCE Interrupt */ + EXTI9_5_IRQHandler, /*!< External Line[9:5] Interrupts */ + TIM1_BRK_TIM15_IRQHandler, /*!< TIM1 Break and TIM15 Interrupts */ + TIM1_UP_TIM16_IRQHandler, /*!< TIM1 Update and TIM16 Interrupts */ + TIM1_TRG_COM_TIM17_IRQHandler, /*!< TIM1 Trigger and Commutation and TIM17 Interrupt */ + TIM1_CC_IRQHandler, /*!< TIM1 Capture Compare Interrupt */ + TIM2_IRQHandler, /*!< TIM2 global Interrupt */ + TIM3_IRQHandler, /*!< TIM3 global Interrupt */ + TIM4_IRQHandler, /*!< TIM4 global Interrupt */ + I2C1_EV_IRQHandler, /*!< I2C1 Event Interrupt */ + I2C1_ER_IRQHandler, /*!< I2C1 Error Interrupt */ + I2C2_EV_IRQHandler, /*!< I2C2 Event Interrupt */ + I2C2_ER_IRQHandler, /*!< I2C2 Error Interrupt */ + SPI1_IRQHandler, /*!< SPI1 global Interrupt */ + SPI2_IRQHandler, /*!< SPI2 global Interrupt */ + USART1_IRQHandler, /*!< USART1 global Interrupt */ + USART2_IRQHandler, /*!< USART2 global Interrupt */ + USART3_IRQHandler, /*!< USART3 global Interrupt */ + EXTI15_10_IRQHandler, /*!< External Line[15:10] Interrupts */ + RTC_Alarm_IRQHandler, /*!< RTC Alarm (A and B) through EXTI Line Interrupt */ + USBWakeUp_IRQHandler, /*!< USB Wakeup Interrupt */ + TIM8_BRK_IRQHandler, /*!< TIM8 Break Interrupt */ + TIM8_UP_IRQHandler, /*!< TIM8 Update Interrupt */ + TIM8_TRG_COM_IRQHandler, /*!< TIM8 Trigger and Commutation Interrupt */ + TIM8_CC_IRQHandler, /*!< TIM8 Capture Compare Interrupt */ + ADC3_IRQHandler, /*!< ADC3 global Interrupt */ + FMC_IRQHandler, /*!< FMC global Interrupt */ + Reserved_IRQHandler, + Reserved_IRQHandler, + SPI3_IRQHandler, /*!< SPI3 global Interrupt */ + UART4_IRQHandler, /*!< UART4 global Interrupt */ + UART5_IRQHandler, /*!< UART5 global Interrupt */ + TIM6_DAC_IRQHandler, /*!< TIM6 global and DAC1&2 underrun error interrupts */ + TIM7_IRQHandler, /*!< TIM7 global Interrupt */ + DMA2_Channel1_IRQHandler, /*!< DMA2 Channel 1 global Interrupt */ + DMA2_Channel2_IRQHandler, /*!< DMA2 Channel 2 global Interrupt */ + DMA2_Channel3_IRQHandler, /*!< DMA2 Channel 3 global Interrupt */ + DMA2_Channel4_IRQHandler, /*!< DMA2 Channel 4 global Interrupt */ + DMA2_Channel5_IRQHandler, /*!< DMA2 Channel 5 global Interrupt */ + ADC4_IRQHandler, /*!< ADC4 global Interrupt */ + Reserved_IRQHandler, + Reserved_IRQHandler, + COMP1_2_3_IRQHandler, /*!< COMP1, COMP2 and COMP3 global Interrupt */ + COMP4_5_6_IRQHandler, /*!< COMP5, COMP6 and COMP4 global Interrupt */ + COMP7_IRQHandler, /*!< COMP7 global Interrupt */ + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + I2C3_EV_IRQHandler, /*!< I2C3 event interrupt */ + I2C3_ER_IRQHandler, /*!< I2C3 error interrupt */ + USB_HP_IRQHandler, /*!< USB High Priority global Interrupt remap */ + USB_LP_IRQHandler, /*!< USB Low Priority global Interrupt remap */ + USBWakeUp_RMP_IRQHandler, /*!< USB Wakeup Interrupt remap */ + TIM20_BRK_IRQHandler, /*!< TIM20 Break Interrupt */ + TIM20_UP_IRQHandler, /*!< TIM20 Update Interrupt */ + TIM20_TRG_COM_IRQHandler, /*!< TIM20 Trigger and Commutation Interrupt */ + TIM20_CC_IRQHandler, /*!< TIM20 Capture Compare Interrupt */ + FPU_IRQHandler, /*!< Floating point Interrupt */ + Reserved_IRQHandler, + Reserved_IRQHandler, + SPI4_IRQHandler /*!< SPI4 global Interrupt */ +#endif /* ifdef STM32F303xE */ +}; + +/** + * @} + */ diff --git a/flight/pios/stm32f4xx/library.mk b/flight/pios/stm32f4xx/library.mk index 669c8c08a4..bd515456ca 100644 --- a/flight/pios/stm32f4xx/library.mk +++ b/flight/pios/stm32f4xx/library.mk @@ -15,7 +15,7 @@ LINKER_SCRIPTS_COMPAT = $(PIOS_DEVLIB)link_$(BOARD)_fw_memory.ld \ $(PIOS_DEVLIB)link_$(BOARD)_sections_compat.ld # Compiler options implied by the F4xx -CDEFS += -DSTM32F4XX +CDEFS += -DSTM32F4XX -DSTM32F4 ifeq ($(CHIPFAMILY),STM32F427_437xx) CDEFS += -DPIOS_TARGET_PROVIDES_FAST_HEAP #large heap support must be enabled if SRAM > 128K diff --git a/flight/pios/stm32f4xx/pios_i2c.c b/flight/pios/stm32f4xx/pios_i2c.c index 2821f79bee..308ed82367 100644 --- a/flight/pios/stm32f4xx/pios_i2c.c +++ b/flight/pios/stm32f4xx/pios_i2c.c @@ -159,7 +159,7 @@ static bool i2c_adapter_wait_for_stopped(struct pios_i2c_adapter *i2c_adapter); static void i2c_adapter_reset_bus(struct pios_i2c_adapter *i2c_adapter); static void i2c_adapter_log_fault(enum pios_i2c_error_type type); -static bool i2c_adapter_callback_handler(struct pios_i2c_adapter *i2c_adapter); +static bool i2c_adapter_callback_handler(struct pios_i2c_adapter *i2c_adapter, signed portBASE_TYPE *pxHigherPriorityTaskWoken); static const struct i2c_adapter_transition i2c_adapter_transitions[I2C_STATE_NUM_STATES] = { [I2C_STATE_FSM_FAULT] = { @@ -420,18 +420,19 @@ static void go_stopping(struct pios_i2c_adapter *i2c_adapter) I2C_ITConfig(i2c_adapter->cfg->regs, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR, DISABLE); + if (i2c_adapter->callback) { + i2c_adapter_callback_handler(i2c_adapter, &pxHigherPriorityTaskWoken); + } else { #ifdef USE_FREERTOS - if (xSemaphoreGiveFromISR(i2c_adapter->sem_ready, &pxHigherPriorityTaskWoken) != pdTRUE) { + if (xSemaphoreGiveFromISR(i2c_adapter->sem_ready, &pxHigherPriorityTaskWoken) != pdTRUE) { #if defined(I2C_HALT_ON_ERRORS) - PIOS_DEBUG_Assert(0); + PIOS_DEBUG_Assert(0); #endif - } - portEND_SWITCHING_ISR(pxHigherPriorityTaskWoken); /* FIXME: is this the right place for this? */ + } #endif /* USE_FREERTOS */ - - if (i2c_adapter->callback) { - i2c_adapter_callback_handler(i2c_adapter); } + + portEND_SWITCHING_ISR(pxHigherPriorityTaskWoken); /* FIXME: is this the right place for this? */ } @@ -853,18 +854,8 @@ static bool i2c_adapter_fsm_terminated(struct pios_i2c_adapter *i2c_adapter) uint32_t i2c_cb_count = 0; -static bool i2c_adapter_callback_handler(struct pios_i2c_adapter *i2c_adapter) +static bool i2c_adapter_callback_handler(struct pios_i2c_adapter *i2c_adapter, signed portBASE_TYPE *pxHigherPriorityTaskWoken) { - bool semaphore_success = true; - - /* Wait for the transfer to complete */ -#ifdef USE_FREERTOS - portTickType timeout; - timeout = i2c_adapter->cfg->transfer_timeout_ms / portTICK_RATE_MS; - semaphore_success &= (xSemaphoreTake(i2c_adapter->sem_ready, timeout) == pdTRUE); - xSemaphoreGive(i2c_adapter->sem_ready); -#endif /* USE_FREERTOS */ - /* transfer_timeout_ticks is set by PIOS_I2C_Transfer_Callback */ /* Spin waiting for the transfer to finish */ while (!i2c_adapter_fsm_terminated(i2c_adapter)) { @@ -885,17 +876,10 @@ static bool i2c_adapter_callback_handler(struct pios_i2c_adapter *i2c_adapter) i2c_adapter_fsm_init(i2c_adapter); } - // Execute user supplied function - i2c_adapter->callback(); - - i2c_cb_count++; - #ifdef USE_FREERTOS /* Unlock the bus */ - xSemaphoreGive(i2c_adapter->sem_busy); - if (!semaphore_success) { - i2c_timeout_counter++; - } + xSemaphoreGiveFromISR(i2c_adapter->sem_busy, pxHigherPriorityTaskWoken); + #else PIOS_IRQ_Disable(); i2c_adapter->busy = 0; @@ -903,7 +887,14 @@ static bool i2c_adapter_callback_handler(struct pios_i2c_adapter *i2c_adapter) #endif /* USE_FREERTOS */ - return (!i2c_adapter->bus_error) && semaphore_success; + // Execute user supplied function + if (i2c_adapter->callback()) { + *pxHigherPriorityTaskWoken = pdTRUE; + } + + i2c_cb_count++; + + return !i2c_adapter->bus_error; } @@ -1149,7 +1140,31 @@ int32_t PIOS_I2C_Transfer(uint32_t i2c_id, const struct pios_i2c_txn txn_list[], 0; } -int32_t PIOS_I2C_Transfer_Callback(uint32_t i2c_id, const struct pios_i2c_txn txn_list[], uint32_t num_txns, void *callback) +static int32_t PIOS_I2C_Transfer_Callback_Internal(struct pios_i2c_adapter *i2c_adapter, const struct pios_i2c_txn txn_list[], uint32_t num_txns, pios_i2c_callback callback) +{ + PIOS_DEBUG_Assert(i2c_adapter->curr_state == I2C_STATE_STOPPED); + + i2c_adapter->first_txn = &txn_list[0]; + i2c_adapter->last_txn = &txn_list[num_txns - 1]; + i2c_adapter->active_txn = i2c_adapter->first_txn; + i2c_adapter->bus_error = false; + i2c_adapter->nack = false; + i2c_adapter->callback = callback; + + // Estimate bytes of transmission. Per txns: 1 adress byte + length + i2c_adapter->transfer_timeout_ticks = num_txns; + for (uint32_t i = 0; i < num_txns; i++) { + i2c_adapter->transfer_timeout_ticks += txn_list[i].len; + } + // timeout if it takes eight times the expected time + i2c_adapter->transfer_timeout_ticks <<= 3; + + i2c_adapter_inject_event(i2c_adapter, I2C_EVENT_START); + + return 0; +} + +int32_t PIOS_I2C_Transfer_Callback(uint32_t i2c_id, const struct pios_i2c_txn txn_list[], uint32_t num_txns, pios_i2c_callback callback) { struct pios_i2c_adapter *i2c_adapter = (struct pios_i2c_adapter *)i2c_id; @@ -1162,8 +1177,6 @@ int32_t PIOS_I2C_Transfer_Callback(uint32_t i2c_id, const struct pios_i2c_txn tx PIOS_DEBUG_Assert(txn_list); PIOS_DEBUG_Assert(num_txns); - bool semaphore_success = true; - #ifdef USE_FREERTOS /* Lock the bus */ portTickType timeout; @@ -1172,37 +1185,54 @@ int32_t PIOS_I2C_Transfer_Callback(uint32_t i2c_id, const struct pios_i2c_txn tx return -2; } #else + PIOS_IRQ_Disable(); if (i2c_adapter->busy) { PIOS_IRQ_Enable(); return -2; } + i2c_adapter->busy = 1; + PIOS_IRQ_Enable(); #endif /* USE_FREERTOS */ - PIOS_DEBUG_Assert(i2c_adapter->curr_state == I2C_STATE_STOPPED); + return PIOS_I2C_Transfer_Callback_Internal(i2c_adapter, txn_list, num_txns, callback); +} - i2c_adapter->first_txn = &txn_list[0]; - i2c_adapter->last_txn = &txn_list[num_txns - 1]; - i2c_adapter->active_txn = i2c_adapter->first_txn; +int32_t PIOS_I2C_Transfer_CallbackFromISR(uint32_t i2c_id, const struct pios_i2c_txn txn_list[], uint32_t num_txns, pios_i2c_callback callback, bool *woken) +{ + // FIXME: only supports transfer sizes up to 255 bytes + struct pios_i2c_adapter *i2c_adapter = (struct pios_i2c_adapter *)i2c_id; + + bool valid = PIOS_I2C_validate(i2c_adapter); + + PIOS_Assert(valid) + + PIOS_DEBUG_Assert(txn_list); + PIOS_DEBUG_Assert(num_txns); #ifdef USE_FREERTOS - /* Make sure the done/ready semaphore is consumed before we start */ - semaphore_success &= (xSemaphoreTake(i2c_adapter->sem_ready, timeout) == pdTRUE); -#endif + signed portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; - // used in the i2c_adapter_callback_handler function - // Estimate bytes of transmission. Per txns: 1 adress byte + length - i2c_adapter->transfer_timeout_ticks = num_txns; - for (uint32_t i = 0; i < num_txns; i++) { - i2c_adapter->transfer_timeout_ticks += txn_list[i].len; + /* Lock the bus */ + bool locked = xSemaphoreTakeFromISR(i2c_adapter->sem_busy, &xHigherPriorityTaskWoken) == pdTRUE; + + if (xHigherPriorityTaskWoken == pdTRUE) { + *woken = true; } - // timeout if it takes eight times the expected time - i2c_adapter->transfer_timeout_ticks <<= 3; - i2c_adapter->callback = callback; - i2c_adapter->bus_error = false; - i2c_adapter_inject_event(i2c_adapter, I2C_EVENT_START); + if (!locked) { + return -2; + } +#else + PIOS_IRQ_Disable(); + if (i2c_adapter->busy) { + PIOS_IRQ_Enable(); + return -2; + } + i2c_adapter->busy = 1; + PIOS_IRQ_Enable(); +#endif /* USE_FREERTOS */ - return !semaphore_success ? -2 : 0; + return PIOS_I2C_Transfer_Callback_Internal(i2c_adapter, txn_list, num_txns, callback); } void PIOS_I2C_EV_IRQ_Handler(uint32_t i2c_id) diff --git a/flight/targets/boards/ccf3d/board-info.mk b/flight/targets/boards/ccf3d/board-info.mk new file mode 100644 index 0000000000..6689cf5a14 --- /dev/null +++ b/flight/targets/boards/ccf3d/board-info.mk @@ -0,0 +1,24 @@ +BOARD_TYPE := 0x04 +BOARD_REVISION := 0x03 +BOOTLOADER_VERSION := 0x04 +HW_TYPE := 0x01 + +MCU := cortex-m4 +PIOS_DEVLIB := $(PIOS)/stm32f30x +CHIP := STM32F303xC +BOARD := STM32F303CCT_CC_Rev1 +MODEL := HD +MODEL_SUFFIX := _CC + +OPENOCD_JTAG_CONFIG := foss-jtag.revb.cfg +OPENOCD_CONFIG := stm32f1x.cfg + +# Note: These must match the values in link_$(BOARD)_memory.ld +BL_BANK_BASE := 0x08000000 # Start of bootloader flash +BL_BANK_SIZE := 0x00004000 # Should include BD_INFO region +FW_BANK_BASE := 0x0800C000 # Start of firmware flash +FW_BANK_SIZE := 0x00034000 # Should include FW_DESC_SIZE (208kB) + +FW_DESC_SIZE := 0x00000064 + +OSCILLATOR_FREQ := 8000000 diff --git a/flight/targets/boards/ccf3d/board_hw_defs.c b/flight/targets/boards/ccf3d/board_hw_defs.c new file mode 100644 index 0000000000..9bf269d49c --- /dev/null +++ b/flight/targets/boards/ccf3d/board_hw_defs.c @@ -0,0 +1,861 @@ +/** + ****************************************************************************** + * @file board_hw_defs.c + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015. + * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012. + * PhoenixPilot, http://github.com/PhoenixPilot, Copyright (C) 2012 + * + * @addtogroup OpenPilotSystem OpenPilot System + * @{ + * @addtogroup OpenPilotCore OpenPilot Core + * @{ + * @brief Defines board specific static initializers for hardware for the CopterControl board. + *****************************************************************************/ +/* + * 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 + */ + +#if defined(PIOS_INCLUDE_LED) + +#include + +static const struct pios_gpio pios_leds_cc3d[] = { + [PIOS_LED_HEARTBEAT] = { + .pin = { + .gpio = GPIOB, + .init = { + .GPIO_Pin = GPIO_Pin_3, + .GPIO_Mode = GPIO_Mode_OUT, + .GPIO_OType = GPIO_OType_PP, + .GPIO_Speed = GPIO_Speed_50MHz, + .GPIO_PuPd = GPIO_PuPd_NOPULL, + }, + }, +// .remap = GPIO_Remap_SWJ_JTAGDisable, + .active_low = true + }, +}; + +static const struct pios_gpio_cfg pios_led_cfg_cc3d = { + .gpios = pios_leds_cc3d, + .num_gpios = NELEMENTS(pios_leds_cc3d), +}; + +const struct pios_gpio_cfg *PIOS_BOARD_HW_DEFS_GetLedCfg(__attribute__((unused)) uint32_t board_revision) +{ + return &pios_led_cfg_cc3d; +} + +#endif /* PIOS_INCLUDE_LED */ + +#if defined(PIOS_INCLUDE_SPI) + +#include + +/* Gyro interface */ +void PIOS_SPI_gyro_irq_handler(void); +void DMA1_Channel2_IRQHandler() __attribute__((alias("PIOS_SPI_gyro_irq_handler"))); +void DMA1_Channel3_IRQHandler() __attribute__((alias("PIOS_SPI_gyro_irq_handler"))); +static const struct pios_spi_cfg pios_spi_gyro_cfg = { + .regs = SPI1, + .init = { + .SPI_Mode = SPI_Mode_Master, + .SPI_Direction = SPI_Direction_2Lines_FullDuplex, + .SPI_DataSize = SPI_DataSize_8b, + .SPI_NSS = SPI_NSS_Soft, + .SPI_FirstBit = SPI_FirstBit_MSB, + .SPI_CRCPolynomial = 7, + .SPI_CPOL = SPI_CPOL_High, + .SPI_CPHA = SPI_CPHA_2Edge, + .SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16, /* 10 Mhz */ + }, + .use_crc = false, + .dma = { + .ahb_clk = RCC_AHBPeriph_DMA1, + + .irq = { + .flags = (DMA1_FLAG_TC2 | DMA1_FLAG_TE2 | DMA1_FLAG_HT2 | DMA1_FLAG_GL2), + .init = { + .NVIC_IRQChannel = DMA1_Channel2_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, + + .rx = { + .channel = DMA1_Channel2, + .init = { + .DMA_PeripheralBaseAddr = (uint32_t)&(SPI1->DR), + .DMA_DIR = DMA_DIR_PeripheralSRC, + .DMA_PeripheralInc = DMA_PeripheralInc_Disable, + .DMA_MemoryInc = DMA_MemoryInc_Enable, + .DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte, + .DMA_MemoryDataSize = DMA_MemoryDataSize_Byte, + .DMA_Mode = DMA_Mode_Normal, + .DMA_Priority = DMA_Priority_Medium, + .DMA_M2M = DMA_M2M_Disable, + }, + }, + .tx = { + .channel = DMA1_Channel3, + .init = { + .DMA_PeripheralBaseAddr = (uint32_t)&(SPI1->DR), + .DMA_DIR = DMA_DIR_PeripheralDST, + .DMA_PeripheralInc = DMA_PeripheralInc_Disable, + .DMA_MemoryInc = DMA_MemoryInc_Enable, + .DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte, + .DMA_MemoryDataSize = DMA_MemoryDataSize_Byte, + .DMA_Mode = DMA_Mode_Normal, + .DMA_Priority = DMA_Priority_Medium, + .DMA_M2M = DMA_M2M_Disable, + }, + }, + }, + .remap = GPIO_AF_5, + .sclk = { + .gpio = GPIOA, + .init = { + .GPIO_Pin = GPIO_Pin_5, + .GPIO_Speed = GPIO_Speed_50MHz, + .GPIO_Mode = GPIO_Mode_AF, + .GPIO_OType = GPIO_OType_PP, + .GPIO_PuPd = GPIO_PuPd_NOPULL, + }, + }, + .miso = { + .gpio = GPIOA, + .init = { + .GPIO_Pin = GPIO_Pin_6, + .GPIO_Speed = GPIO_Speed_50MHz, + .GPIO_Mode = GPIO_Mode_AF, + .GPIO_OType = GPIO_OType_PP, + .GPIO_PuPd = GPIO_PuPd_NOPULL, + }, + }, + .mosi = { + .gpio = GPIOA, + .init = { + .GPIO_Pin = GPIO_Pin_7, + .GPIO_Speed = GPIO_Speed_50MHz, + .GPIO_Mode = GPIO_Mode_AF, + .GPIO_OType = GPIO_OType_PP, + .GPIO_PuPd = GPIO_PuPd_NOPULL, + }, + }, + .slave_count = 1, + .ssel = { + { + .gpio = GPIOA, + .init = { + .GPIO_Pin = GPIO_Pin_4, + .GPIO_Speed = GPIO_Speed_50MHz, + .GPIO_Mode = GPIO_Mode_OUT, + .GPIO_OType = GPIO_OType_PP, + .GPIO_PuPd = GPIO_PuPd_UP + }, + } + }, +}; + +uint32_t pios_spi_gyro_id; +void PIOS_SPI_gyro_irq_handler(void) +{ + /* Call into the generic code to handle the IRQ for this specific device */ + PIOS_SPI_IRQ_Handler(pios_spi_gyro_id); +} + + +/* Flash/Accel Interface + * + * NOTE: Leave this declared as const data so that it ends up in the + * .rodata section (ie. Flash) rather than in the .bss section (RAM). + */ +void PIOS_SPI_flash_accel_irq_handler(void); +void DMA1_Channel4_IRQHandler() __attribute__((alias("PIOS_SPI_flash_accel_irq_handler"))); +void DMA1_Channel5_IRQHandler() __attribute__((alias("PIOS_SPI_flash_accel_irq_handler"))); +static const struct pios_spi_cfg pios_spi_flash_accel_cfg_cc3d = { + .regs = SPI2, + .init = { + .SPI_Mode = SPI_Mode_Master, + .SPI_Direction = SPI_Direction_2Lines_FullDuplex, + .SPI_DataSize = SPI_DataSize_8b, + .SPI_NSS = SPI_NSS_Soft, + .SPI_FirstBit = SPI_FirstBit_MSB, + .SPI_CRCPolynomial = 7, + .SPI_CPOL = SPI_CPOL_High, + .SPI_CPHA = SPI_CPHA_2Edge, + .SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8, + }, + .use_crc = false, + .dma = { + .ahb_clk = RCC_AHBPeriph_DMA1, + + .irq = { + .flags = (DMA1_FLAG_TC4 | DMA1_FLAG_TE4 | DMA1_FLAG_HT4 | DMA1_FLAG_GL4), + .init = { + .NVIC_IRQChannel = DMA1_Channel4_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, + + .rx = { + .channel = DMA1_Channel4, + .init = { + .DMA_PeripheralBaseAddr = (uint32_t)&(SPI2->DR), + .DMA_DIR = DMA_DIR_PeripheralSRC, + .DMA_PeripheralInc = DMA_PeripheralInc_Disable, + .DMA_MemoryInc = DMA_MemoryInc_Enable, + .DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte, + .DMA_MemoryDataSize = DMA_MemoryDataSize_Byte, + .DMA_Mode = DMA_Mode_Normal, + .DMA_Priority = DMA_Priority_High, + .DMA_M2M = DMA_M2M_Disable, + }, + }, + .tx = { + .channel = DMA1_Channel5, + .init = { + .DMA_PeripheralBaseAddr = (uint32_t)&(SPI2->DR), + .DMA_DIR = DMA_DIR_PeripheralDST, + .DMA_PeripheralInc = DMA_PeripheralInc_Disable, + .DMA_MemoryInc = DMA_MemoryInc_Enable, + .DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte, + .DMA_MemoryDataSize = DMA_MemoryDataSize_Byte, + .DMA_Mode = DMA_Mode_Normal, + .DMA_Priority = DMA_Priority_High, + .DMA_M2M = DMA_M2M_Disable, + }, + }, + }, + .remap = GPIO_AF_5, + .sclk = { + .gpio = GPIOB, + .init = { + .GPIO_Pin = GPIO_Pin_13, + .GPIO_Speed = GPIO_Speed_50MHz, + .GPIO_Mode = GPIO_Mode_AF, + .GPIO_OType = GPIO_OType_PP, + .GPIO_PuPd = GPIO_PuPd_NOPULL, + }, + }, + .miso = { + .gpio = GPIOB, + .init = { + .GPIO_Pin = GPIO_Pin_14, + .GPIO_Speed = GPIO_Speed_50MHz, + .GPIO_Mode = GPIO_Mode_AF, /* NOTE: was GPIO_Mode_IN_FLOATING */ + .GPIO_OType = GPIO_OType_PP, + .GPIO_PuPd = GPIO_PuPd_NOPULL, + }, + }, + .mosi = { + .gpio = GPIOB, + .init = { + .GPIO_Pin = GPIO_Pin_15, + .GPIO_Speed = GPIO_Speed_50MHz, + .GPIO_Mode = GPIO_Mode_AF, + .GPIO_OType = GPIO_OType_PP, + .GPIO_PuPd = GPIO_PuPd_NOPULL, + }, + }, + .slave_count = 2, + .ssel = { + { + .gpio = GPIOB, + .init = { + .GPIO_Pin = GPIO_Pin_12, + .GPIO_Speed = GPIO_Speed_50MHz, + .GPIO_Mode = GPIO_Mode_OUT, + .GPIO_OType = GPIO_OType_PP, + .GPIO_PuPd = GPIO_PuPd_UP, + } + },{ + .gpio = GPIOC, + .init = { + .GPIO_Pin = GPIO_Pin_15, + .GPIO_Speed = GPIO_Speed_50MHz, + .GPIO_Mode = GPIO_Mode_OUT, + .GPIO_OType = GPIO_OType_PP, + .GPIO_PuPd = GPIO_PuPd_UP, + }, + } + }, +}; + +static uint32_t pios_spi_flash_accel_id; +void PIOS_SPI_flash_accel_irq_handler(void) +{ + /* Call into the generic code to handle the IRQ for this specific device */ + PIOS_SPI_IRQ_Handler(pios_spi_flash_accel_id); +} + +#endif /* PIOS_INCLUDE_SPI */ + +#if defined(PIOS_INCLUDE_FLASH) +#include "pios_flashfs_logfs_priv.h" +#include "pios_flash_jedec_priv.h" + +static const struct flashfs_logfs_cfg flashfs_m25p_cfg = { + .fs_magic = 0x99abceef, + .total_fs_size = 0x00200000, /* 2M bytes (32 sectors = entire chip) */ + .arena_size = 0x00010000, /* 256 * slot size */ + .slot_size = 0x00000100, /* 256 bytes */ + + .start_offset = 0, /* start at the beginning of the chip */ + .sector_size = 0x00010000, /* 64K bytes */ + .page_size = 0x00000100, /* 256 bytes */ +}; + +#include "pios_flash.h" + +#endif /* PIOS_INCLUDE_FLASH */ + +/* + * ADC system + */ +#if defined(PIOS_INCLUDE_ADC) +#include "pios_adc_priv.h" +extern void PIOS_ADC_handler(void); +void DMA1_Channel1_IRQHandler() __attribute__((alias("PIOS_ADC_handler"))); +// Remap the ADC DMA handler to this one +static const struct pios_adc_cfg pios_adc_cfg = { + .dma = { + .ahb_clk = RCC_AHBPeriph_DMA1, + .irq = { + .flags = (DMA1_FLAG_TC1 | DMA1_FLAG_TE1 | DMA1_FLAG_HT1 | DMA1_FLAG_GL1), + .init = { + .NVIC_IRQChannel = DMA1_Channel1_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, + .rx = { + .channel = DMA1_Channel1, + .init = { + .DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR, + .DMA_DIR = DMA_DIR_PeripheralSRC, + .DMA_PeripheralInc = DMA_PeripheralInc_Disable, + .DMA_MemoryInc = DMA_MemoryInc_Enable, + .DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word, + .DMA_MemoryDataSize = DMA_MemoryDataSize_Word, + .DMA_Mode = DMA_Mode_Circular, + .DMA_Priority = DMA_Priority_High, + .DMA_M2M = DMA_M2M_Disable, + }, + } + }, + .half_flag = DMA1_IT_HT1, + .full_flag = DMA1_IT_TC1, +}; + +void PIOS_ADC_handler() +{ + PIOS_ADC_DMA_Handler(); +} +#endif /* if defined(PIOS_INCLUDE_ADC) */ + +#include "pios_tim_priv.h" + +static const TIM_TimeBaseInitTypeDef tim_1_2_3_4_time_base = { + .TIM_Prescaler = (PIOS_MASTER_CLOCK / 1000000) - 1, + .TIM_ClockDivision = TIM_CKD_DIV1, + .TIM_CounterMode = TIM_CounterMode_Up, + .TIM_Period = ((1000000 / PIOS_SERVO_UPDATE_HZ) - 1), + .TIM_RepetitionCounter = 0x0000, +}; + +static const struct pios_tim_clock_cfg tim_1_cfg = { + .timer = TIM1, + .time_base_init = &tim_1_2_3_4_time_base, + .irq = { + .init = { + .NVIC_IRQChannel = TIM1_CC_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, +}; + +static const struct pios_tim_clock_cfg tim_2_cfg = { + .timer = TIM2, + .time_base_init = &tim_1_2_3_4_time_base, + .irq = { + .init = { + .NVIC_IRQChannel = TIM2_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, +}; + +static const struct pios_tim_clock_cfg tim_3_cfg = { + .timer = TIM3, + .time_base_init = &tim_1_2_3_4_time_base, + .irq = { + .init = { + .NVIC_IRQChannel = TIM3_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, +}; + +static const struct pios_tim_clock_cfg tim_4_cfg = { + .timer = TIM4, + .time_base_init = &tim_1_2_3_4_time_base, + .irq = { + .init = { + .NVIC_IRQChannel = TIM4_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, +}; + +#include + +#define GPIO_AF_PA1_TIM2 GPIO_AF_1 +#define GPIO_AF_PA0_TIM2 GPIO_AF_1 +#define GPIO_AF_PA8_TIM1 GPIO_AF_6 +#define GPIO_AF_PA2_TIM2 GPIO_AF_1 +#define GPIO_AF_PB6_TIM4 GPIO_AF_2 +#define GPIO_AF_PB5_TIM3 GPIO_AF_2 +#define GPIO_AF_PB0_TIM3 GPIO_AF_2 +#define GPIO_AF_PB1_TIM3 GPIO_AF_2 +#define GPIO_AF_PB9_TIM4 GPIO_AF_2 +#define GPIO_AF_PB8_TIM4 GPIO_AF_2 +#define GPIO_AF_PB7_TIM4 GPIO_AF_2 +#define GPIO_AF_PB4_TIM3 GPIO_AF_2 +#define GPIO_AF_PB11_TIM2 GPIO_AF_1 + +static const struct pios_tim_channel pios_tim_rcvrport_all_channels[] = { + TIM_SERVO_CHANNEL_CONFIG(TIM4, 1, B, 6), + TIM_SERVO_CHANNEL_CONFIG(TIM3, 2, B, 5), + TIM_SERVO_CHANNEL_CONFIG(TIM3, 3, B, 0), + TIM_SERVO_CHANNEL_CONFIG(TIM3, 4, B, 1), + TIM_SERVO_CHANNEL_CONFIG(TIM2, 1, A, 0), + TIM_SERVO_CHANNEL_CONFIG(TIM2, 2, A, 1), +}; + +static const struct pios_tim_channel pios_tim_servoport_rcvrport_pins[] = { + TIM_SERVO_CHANNEL_CONFIG(TIM4, 4, B, 9), + TIM_SERVO_CHANNEL_CONFIG(TIM4, 3, B, 8), + TIM_SERVO_CHANNEL_CONFIG(TIM4, 2, B, 7), + TIM_SERVO_CHANNEL_CONFIG(TIM1, 1, A, 8), + TIM_SERVO_CHANNEL_CONFIG(TIM3, 1, B, 4), + TIM_SERVO_CHANNEL_CONFIG(TIM2, 3, A, 2), + + // Receiver port pins + // S3-S6 inputs are used as outputs in this case + + TIM_SERVO_CHANNEL_CONFIG(TIM3, 3, B, 0), + TIM_SERVO_CHANNEL_CONFIG(TIM3, 4, B, 1), + TIM_SERVO_CHANNEL_CONFIG(TIM2, 1, A, 0), + TIM_SERVO_CHANNEL_CONFIG(TIM2, 2, A, 1), +}; + +static const struct pios_tim_channel pios_tim_ppm_flexi_port = TIM_SERVO_CHANNEL_CONFIG(TIM2, 4, B, 11); + + +#if defined(PIOS_INCLUDE_USART) + +#define GPIO_AF_USART1 GPIO_AF_7 +#define GPIO_AF_USART3 GPIO_AF_7 + + +#include "pios_usart_priv.h" +#include "pios_usart_config.h" + +static const struct pios_usart_cfg pios_usart_main_cfg = USART_CONFIG(USART1, A, 10, A, 9); +static const struct pios_usart_cfg pios_usart_flexi_cfg = USART_CONFIG(USART3, B, 11, B, 10); +#endif /* PIOS_INCLUDE_USART */ + +#if defined(PIOS_INCLUDE_RTC) +/* + * Realtime Clock (RTC) + */ +#include + +void PIOS_RTC_IRQ_Handler(void); +void RTC_WKUP_IRQHandler() __attribute__((alias("PIOS_RTC_IRQ_Handler"))); +static const struct pios_rtc_cfg pios_rtc_main_cfg = { + .clksrc = RCC_RTCCLKSource_HSE_Div32, + .prescaler = 25 - 1, // 8Mhz / 32 / 16 / 25 => 625Hz + .irq = { + .init = { + .NVIC_IRQChannel = RTC_WKUP_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, +}; + +void PIOS_RTC_IRQ_Handler(void) +{ + PIOS_RTC_irq_handler(); +} + +#endif /* if defined(PIOS_INCLUDE_RTC) */ + +#if defined(PIOS_INCLUDE_SERVO) && defined(PIOS_INCLUDE_TIM) +/* + * Servo outputs + */ +#include + +const struct pios_servo_cfg pios_servo_cfg = { + .tim_oc_init = { + .TIM_OCMode = TIM_OCMode_PWM1, + .TIM_OutputState = TIM_OutputState_Enable, + .TIM_OutputNState = TIM_OutputNState_Disable, + .TIM_Pulse = PIOS_SERVOS_INITIAL_POSITION, + .TIM_OCPolarity = TIM_OCPolarity_High, + .TIM_OCNPolarity = TIM_OCPolarity_High, + .TIM_OCIdleState = TIM_OCIdleState_Reset, + .TIM_OCNIdleState = TIM_OCNIdleState_Reset, + }, + .channels = pios_tim_servoport_rcvrport_pins, + .num_channels = 6, +}; + +const struct pios_servo_cfg pios_servo_rcvr_cfg = { + .tim_oc_init = { + .TIM_OCMode = TIM_OCMode_PWM1, + .TIM_OutputState = TIM_OutputState_Enable, + .TIM_OutputNState = TIM_OutputNState_Disable, + .TIM_Pulse = PIOS_SERVOS_INITIAL_POSITION, + .TIM_OCPolarity = TIM_OCPolarity_High, + .TIM_OCNPolarity = TIM_OCPolarity_High, + .TIM_OCIdleState = TIM_OCIdleState_Reset, + .TIM_OCNIdleState = TIM_OCNIdleState_Reset, + }, + .channels = pios_tim_servoport_rcvrport_pins, + .num_channels = NELEMENTS(pios_tim_servoport_rcvrport_pins), +}; + +#endif /* PIOS_INCLUDE_SERVO && PIOS_INCLUDE_TIM */ + +/* + * PPM Inputs + */ +#if defined(PIOS_INCLUDE_PPM) +#include + +const struct pios_ppm_cfg pios_ppm_cfg = { + .tim_ic_init = { + .TIM_ICPolarity = TIM_ICPolarity_Rising, + .TIM_ICSelection = TIM_ICSelection_DirectTI, + .TIM_ICPrescaler = TIM_ICPSC_DIV1, + .TIM_ICFilter = 0x0, + }, + /* Use only the first channel for ppm */ + .channels = &pios_tim_rcvrport_all_channels[0], + .num_channels = 1, +}; + +const struct pios_ppm_cfg pios_ppm_pin8_cfg = { + .tim_ic_init = { + .TIM_ICPolarity = TIM_ICPolarity_Rising, + .TIM_ICSelection = TIM_ICSelection_DirectTI, + .TIM_ICPrescaler = TIM_ICPSC_DIV1, + .TIM_ICFilter = 0x0, + }, + /* Use only the first channel for ppm */ + .channels = &pios_tim_rcvrport_all_channels[5], + .num_channels = 1, +}; + +#endif /* PIOS_INCLUDE_PPM */ + +#if defined(PIOS_INCLUDE_PPM_FLEXI) +#include + +const struct pios_ppm_cfg pios_ppm_flexi_cfg = { + .tim_ic_init = { + .TIM_ICPolarity = TIM_ICPolarity_Rising, + .TIM_ICSelection = TIM_ICSelection_DirectTI, + .TIM_ICPrescaler = TIM_ICPSC_DIV1, + .TIM_ICFilter = 0x0, + }, + .channels = &pios_tim_ppm_flexi_port, + .num_channels = 1, +}; + +#endif /* PIOS_INCLUDE_PPM_FLEXI */ + +/* + * PWM Inputs + */ +#if defined(PIOS_INCLUDE_PWM) +#include + +const struct pios_pwm_cfg pios_pwm_cfg = { + .tim_ic_init = { + .TIM_ICPolarity = TIM_ICPolarity_Rising, + .TIM_ICSelection = TIM_ICSelection_DirectTI, + .TIM_ICPrescaler = TIM_ICPSC_DIV1, + .TIM_ICFilter = 0x0, + }, + .channels = pios_tim_rcvrport_all_channels, + .num_channels = NELEMENTS(pios_tim_rcvrport_all_channels), +}; + +const struct pios_pwm_cfg pios_pwm_with_ppm_cfg = { + .tim_ic_init = { + .TIM_ICPolarity = TIM_ICPolarity_Rising, + .TIM_ICSelection = TIM_ICSelection_DirectTI, + .TIM_ICPrescaler = TIM_ICPSC_DIV1, + .TIM_ICFilter = 0x0, + }, + /* Leave the first channel for PPM use and use the rest for PWM */ + .channels = &pios_tim_rcvrport_all_channels[1], + .num_channels = NELEMENTS(pios_tim_rcvrport_all_channels) - 1, +}; + +#endif /* if defined(PIOS_INCLUDE_PWM) */ + + +/* + * SONAR Inputs + */ +#if defined(PIOS_INCLUDE_HCSR04) +#include + +static const struct pios_tim_channel pios_tim_hcsr04_port_all_channels[] = { + { + .timer = TIM3, + .timer_chan = TIM_Channel_2, + .pin = { + .gpio = GPIOB, + .init = { + .GPIO_Pin = GPIO_Pin_5, + .GPIO_Mode = GPIO_Mode_IPD, + .GPIO_Speed = GPIO_Speed_2MHz, + }, + }, + .remap = GPIO_PartialRemap_TIM3, + }, +}; + +const struct pios_hcsr04_cfg pios_hcsr04_cfg = { + .tim_ic_init = { + .TIM_ICPolarity = TIM_ICPolarity_Rising, + .TIM_ICSelection = TIM_ICSelection_DirectTI, + .TIM_ICPrescaler = TIM_ICPSC_DIV1, + .TIM_ICFilter = 0x0, + }, + .channels = pios_tim_hcsr04_port_all_channels, + .num_channels = NELEMENTS(pios_tim_hcsr04_port_all_channels), + .trigger = { + .gpio = GPIOB, + .init = { + .GPIO_Pin = GPIO_Pin_6, + .GPIO_Mode = GPIO_Mode_Out_PP, + .GPIO_Speed = GPIO_Speed_2MHz, + }, + }, +}; +#endif /* if defined(PIOS_INCLUDE_HCSR04) */ + +#if defined(PIOS_INCLUDE_I2C) + +#include + +/* + * I2C Adapters + */ + +void PIOS_I2C_flexi_adapter_ev_irq_handler(void); +void PIOS_I2C_flexi_adapter_er_irq_handler(void); +void I2C2_EV_EXTI24_IRQHandler() __attribute__((alias("PIOS_I2C_flexi_adapter_ev_irq_handler"))); +void I2C2_ER_IRQHandler() __attribute__((alias("PIOS_I2C_flexi_adapter_er_irq_handler"))); + +static const struct pios_i2c_adapter_cfg pios_i2c_flexi_adapter_cfg = { + .regs = I2C2, + .init = { + .I2C_Mode = I2C_Mode_I2C, + .I2C_OwnAddress1 = 0, + .I2C_Ack = I2C_Ack_Enable, + .I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit, + .I2C_DigitalFilter = 0x00, + .I2C_AnalogFilter = I2C_AnalogFilter_Enable, + .I2C_Timing = 0x70310309, // 50kHz I2C @ 8MHz input -> PRESC=0x7, SCLDEL=0x3, SDADEL=0x1, SCLH=0x03, SCLL=0x09 + }, + .remapSDA = GPIO_AF_4, /* I2C1, I2C2 */ + .remapSCL = GPIO_AF_4, /* I2C1, I2C2 */ + .transfer_timeout_ms = 50, + .scl = { + .gpio = GPIOB, + .init = { + .GPIO_Pin = GPIO_Pin_10, + .GPIO_Mode = GPIO_Mode_AF, + .GPIO_Speed = GPIO_Speed_50MHz, + .GPIO_OType = GPIO_OType_OD, + .GPIO_PuPd = GPIO_PuPd_UP, + }, + }, + .sda = { + .gpio = GPIOB, + .init = { + .GPIO_Pin = GPIO_Pin_11, + .GPIO_Mode = GPIO_Mode_AF, + .GPIO_Speed = GPIO_Speed_50MHz, + .GPIO_OType = GPIO_OType_OD, + .GPIO_PuPd = GPIO_PuPd_UP, + }, + }, + .event = { + .flags = 0, /* FIXME: check this */ + .init = { + .NVIC_IRQChannel = I2C2_EV_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGHEST, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, + .error = { + .flags = 0, /* FIXME: check this */ + .init = { + .NVIC_IRQChannel = I2C2_ER_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGHEST, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, +}; + +uint32_t pios_i2c_flexi_adapter_id; +void PIOS_I2C_flexi_adapter_ev_irq_handler(void) +{ + /* Call into the generic code to handle the IRQ for this specific device */ + PIOS_I2C_EV_IRQ_Handler(pios_i2c_flexi_adapter_id); +} + +void PIOS_I2C_flexi_adapter_er_irq_handler(void) +{ + /* Call into the generic code to handle the IRQ for this specific device */ + PIOS_I2C_ER_IRQ_Handler(pios_i2c_flexi_adapter_id); +} + +#endif /* PIOS_INCLUDE_I2C */ + +#if defined(PIOS_INCLUDE_RCVR) +#include "pios_rcvr_priv.h" + +#endif /* PIOS_INCLUDE_RCVR */ + +#if defined(PIOS_INCLUDE_USB) +#include "pios_usb_priv.h" + +static const struct pios_usb_cfg pios_usb_main_cfg_cc3d = { + .irq = { + .init = { + .NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_LOW, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, + .vsense = { + .gpio = GPIOC, + .init = { + .GPIO_Pin = GPIO_Pin_14, + .GPIO_Speed = GPIO_Speed_2MHz, + .GPIO_Mode = GPIO_Mode_IN, + .GPIO_OType = GPIO_OType_OD, + .GPIO_PuPd = GPIO_PuPd_DOWN, + }, + }, + .vsense_active_low = false +}; + +const struct pios_usb_cfg *PIOS_BOARD_HW_DEFS_GetUsbCfg(__attribute__((unused)) uint32_t board_revision) +{ + return &pios_usb_main_cfg_cc3d; +} + +#endif /* PIOS_INCLUDE_USB */ + +/** + * Configuration for MPU6000 chip + */ +#if defined(PIOS_INCLUDE_MPU6000) +#include "pios_mpu6000.h" +static const struct pios_exti_cfg pios_exti_mpu6000_cfg __exti_config = { + .vector = PIOS_MPU6000_IRQHandler, + .line = EXTI_Line3, + .pin = { + .gpio = GPIOA, + .init = { + .GPIO_Pin = GPIO_Pin_3, + .GPIO_Speed = GPIO_Speed_10MHz, + .GPIO_Mode = GPIO_Mode_IN, + .GPIO_OType = GPIO_OType_OD, + .GPIO_PuPd = GPIO_PuPd_NOPULL, + }, + }, + .irq = { + .init = { + .NVIC_IRQChannel = EXTI3_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, + .exti = { + .init = { + .EXTI_Line = EXTI_Line3, // matches above GPIO pin + .EXTI_Mode = EXTI_Mode_Interrupt, + .EXTI_Trigger = EXTI_Trigger_Rising, + .EXTI_LineCmd = ENABLE, + }, + }, +}; + +static const struct pios_mpu6000_cfg pios_mpu6000_cfg = { + .exti_cfg = &pios_exti_mpu6000_cfg, + .Fifo_store = PIOS_MPU6000_FIFO_TEMP_OUT | PIOS_MPU6000_FIFO_GYRO_X_OUT | PIOS_MPU6000_FIFO_GYRO_Y_OUT | PIOS_MPU6000_FIFO_GYRO_Z_OUT, + // Clock at 8 khz, downsampled by 8 for 1000 Hz + .Smpl_rate_div_no_dlp = 7, + // Clock at 1 khz, downsampled by 1 for 1000 Hz + .Smpl_rate_div_dlp = 0, + .interrupt_cfg = PIOS_MPU6000_INT_CLR_ANYRD, + .interrupt_en = PIOS_MPU6000_INTEN_DATA_RDY, + .User_ctl = PIOS_MPU6000_USERCTL_DIS_I2C, + .Pwr_mgmt_clk = PIOS_MPU6000_PWRMGMT_PLL_X_CLK, + .accel_range = PIOS_MPU6000_ACCEL_8G, + .gyro_range = PIOS_MPU6000_SCALE_2000_DEG, + .filter = PIOS_MPU6000_LOWPASS_256_HZ, + .orientation = PIOS_MPU6000_TOP_180DEG, + .fast_prescaler = PIOS_SPI_PRESCALER_4, + .std_prescaler = PIOS_SPI_PRESCALER_64, + .max_downsample = 2 +}; + +const struct pios_mpu6000_cfg *PIOS_BOARD_HW_DEFS_GetMPU6000Cfg(__attribute__((unused)) uint32_t board_revision) +{ + return &pios_mpu6000_cfg; +} +#endif /* PIOS_INCLUDE_MPU6000 */ + diff --git a/flight/targets/boards/ccf3d/bootloader/Makefile b/flight/targets/boards/ccf3d/bootloader/Makefile new file mode 100644 index 0000000000..152ac0a87c --- /dev/null +++ b/flight/targets/boards/ccf3d/bootloader/Makefile @@ -0,0 +1,29 @@ +# +# Copyright (c) 2015, The LibrePilot Project, http://www.librepilot.org +# Copyright (c) 2009-2013, The OpenPilot Team, http://www.openpilot.org +# +# 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 FLIGHT_MAKEFILE + $(error Top level Makefile must be used to build this target) +endif + +include ../board-info.mk +include $(FLIGHT_ROOT_DIR)/make/firmware-defs.mk +include $(FLIGHT_ROOT_DIR)/make/boot-defs.mk +include $(FLIGHT_ROOT_DIR)/make/common-defs.mk + +$(info Making bootloader for CCF3D, board revision $(BOARD_REVISION)) diff --git a/flight/targets/boards/ccf3d/bootloader/inc/common.h b/flight/targets/boards/ccf3d/bootloader/inc/common.h new file mode 100644 index 0000000000..e64b89014c --- /dev/null +++ b/flight/targets/boards/ccf3d/bootloader/inc/common.h @@ -0,0 +1,115 @@ +/** + ****************************************************************************** + * @addtogroup CopterControlBL CopterControl BootLoader + * @brief These files contain the code to the CopterControl Bootloader. + * + * @{ + * @file common.c + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief This file contains various common defines for the BootLoader + * @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 COMMON_H_ +#define COMMON_H_ + +// #include "board.h" + +typedef enum { + start, keepgoing, +} DownloadAction; + +/**************************************************/ +/* OP_DFU states */ +/**************************************************/ + +typedef enum { + DFUidle, // 0 + uploading, // 1 + wrong_packet_received, // 2 + too_many_packets, // 3 + too_few_packets, // 4 + Last_operation_Success, // 5 + downloading, // 6 + BLidle, // 7 + Last_operation_failed, // 8 + uploadingStarting, // 9 + outsideDevCapabilities, // 10 + CRC_Fail, // 11 + failed_jump, +// 12 +} DFUStates; +/**************************************************/ +/* OP_DFU commands */ +/**************************************************/ +typedef enum { + Reserved, // 0 + Req_Capabilities, // 1 + Rep_Capabilities, // 2 + EnterDFU, // 3 + JumpFW, // 4 + Reset, // 5 + Abort_Operation, // 6 + Upload, // 7 + Op_END, // 8 + Download_Req, // 9 + Download, // 10 + Status_Request, // 11 + Status_Rep +// 12 +} DFUCommands; + +typedef enum { + High_Density, Medium_Density +} DeviceType; +/**************************************************/ +/* OP_DFU transfer types */ +/**************************************************/ +typedef enum { + FW, // 0 + Descript +// 2 +} DFUTransfer; +/**************************************************/ +/* OP_DFU transfer port */ +/**************************************************/ +typedef enum { + Usb, // 0 + Serial +// 2 +} DFUPort; +/**************************************************/ +/* OP_DFU programable programable HW types */ +/**************************************************/ +typedef enum { + Self_flash, // 0 + Remote_flash_via_spi +// 1 +} DFUProgType; +/**************************************************/ +/* OP_DFU programable sources */ +/**************************************************/ +#define USB 0 +#define SPI 1 + +#define DownloadDelay 100000 + +#define MAX_DEL_RETRYS 3 +#define MAX_WRI_RETRYS 3 + +#endif /* COMMON_H_ */ diff --git a/flight/targets/boards/ccf3d/bootloader/inc/pios_config.h b/flight/targets/boards/ccf3d/bootloader/inc/pios_config.h new file mode 100644 index 0000000000..43182e4354 --- /dev/null +++ b/flight/targets/boards/ccf3d/bootloader/inc/pios_config.h @@ -0,0 +1,53 @@ +/** + ****************************************************************************** + * @addtogroup CopterControlBL CopterControl BootLoader + * @brief These files contain the code to the CopterControl Bootloader. + * @{ + * @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. + * In particular, pios_config.h is where you define which PiOS libraries + * and features are included in the firmware. + * @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_SYS +#define PIOS_INCLUDE_IRQ +#define PIOS_INCLUDE_GPIO +#define PIOS_INCLUDE_USB +#define PIOS_INCLUDE_USB_HID +#define PIOS_INCLUDE_LED +#define PIOS_INCLUDE_IAP +#define PIOS_INCLUDE_COM +#define PIOS_INCLUDE_COM_MSG +#define PIOS_INCLUDE_BL_HELPER +#define PIOS_INCLUDE_BL_HELPER_WRITE_SUPPORT + +#endif /* PIOS_CONFIG_H */ + +/** + * @} + * @} + */ diff --git a/flight/targets/boards/ccf3d/bootloader/inc/pios_usb_board_data.h b/flight/targets/boards/ccf3d/bootloader/inc/pios_usb_board_data.h new file mode 100644 index 0000000000..5a40bf4cf2 --- /dev/null +++ b/flight/targets/boards/ccf3d/bootloader/inc/pios_usb_board_data.h @@ -0,0 +1,53 @@ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_USB_BOARD Board specific USB definitions + * @brief Board specific USB definitions + * @{ + * + * @file pios_usb_board_data.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief Board specific USB 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_USB_BOARD_DATA_H +#define PIOS_USB_BOARD_DATA_H + +// Note : changing below length will require changes to the USB buffer setup +#define PIOS_USB_BOARD_HID_DATA_LENGTH 64 + +#define PIOS_USB_BOARD_EP_NUM 2 + +#include /* struct usb_* */ + +#define PIOS_USB_BOARD_PRODUCT_ID USB_PRODUCT_ID_COPTERCONTROL +#define PIOS_USB_BOARD_DEVICE_VER USB_OP_DEVICE_VER(USB_OP_BOARD_ID_COPTERCONTROL, USB_OP_BOARD_MODE_BL) +#define PIOS_USB_BOARD_SN_SUFFIX "+BL" + +/* + * The bootloader uses a simplified report structure + * BL: ... + * FW: ... + * This define changes the behaviour in pios_usb_hid.c + */ +#define PIOS_USB_BOARD_BL_HID_HAS_NO_LENGTH_BYTE + +#endif /* PIOS_USB_BOARD_DATA_H */ diff --git a/flight/targets/boards/ccf3d/bootloader/main.c b/flight/targets/boards/ccf3d/bootloader/main.c new file mode 100644 index 0000000000..a392775f4a --- /dev/null +++ b/flight/targets/boards/ccf3d/bootloader/main.c @@ -0,0 +1,228 @@ +/** + ****************************************************************************** + * @addtogroup CopterControlBL CopterControl BootLoader + * @brief These files contain the code to the CopterControl Bootloader. + * + * @{ + * @file main.c + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief This is the file with the main function of the OpenPilot BootLoader + * @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 +#include +#include +#include +#include +#include +#include +#include + +extern void FLASH_Download(); +#define BSL_HOLD_STATE ((PIOS_USB_DETECT_GPIO_PORT->IDR & PIOS_USB_DETECT_GPIO_PIN) ? 0 : 1) + +/* Private typedef -----------------------------------------------------------*/ +typedef void (*pFunction)(void); +/* Private define ------------------------------------------------------------*/ +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +pFunction Jump_To_Application; +uint32_t JumpAddress; + +/// LEDs PWM +uint32_t period1 = 5000; // 5 mS +uint32_t sweep_steps1 = 100; // * 5 mS -> 500 mS +uint32_t period2 = 5000; // 5 mS +uint32_t sweep_steps2 = 100; // * 5 mS -> 500 mS + + +//////////////////////////////////////// +uint8_t tempcount = 0; + +/* Extern variables ----------------------------------------------------------*/ +DFUStates DeviceState; +int16_t status = 0; +uint8_t JumpToApp = FALSE; +uint8_t GO_dfu = FALSE; +uint8_t USB_connected = FALSE; +uint8_t User_DFU_request = FALSE; +static uint8_t mReceive_Buffer[63]; +/* Private function prototypes -----------------------------------------------*/ +uint32_t LedPWM(uint32_t pwm_period, uint32_t pwm_sweep_steps, uint32_t count); +uint8_t processRX(); +void jump_to_app(); + +int main() +{ + PIOS_SYS_Init(); + PIOS_Board_Init(); + PIOS_IAP_Init(); + + USB_connected = PIOS_USB_CableConnected(0); + + if (PIOS_IAP_CheckRequest() == TRUE) { + PIOS_DELAY_WaitmS(1000); + User_DFU_request = TRUE; + PIOS_IAP_ClearRequest(); + } + + GO_dfu = (USB_connected == TRUE) || (User_DFU_request == TRUE); + + if (GO_dfu == TRUE) { + PIOS_Board_Init(); + if (User_DFU_request == TRUE) { + DeviceState = DFUidle; + } else { + DeviceState = BLidle; + } + } else { + JumpToApp = TRUE; + } + + uint32_t stopwatch = 0; + uint32_t prev_ticks = PIOS_DELAY_GetuS(); + while (TRUE) { + /* Update the stopwatch */ + uint32_t elapsed_ticks = PIOS_DELAY_GetuSSince(prev_ticks); + prev_ticks += elapsed_ticks; + stopwatch += elapsed_ticks; + + if (JumpToApp == TRUE) { + jump_to_app(); + } + + switch (DeviceState) { + case Last_operation_Success: + case uploadingStarting: + case DFUidle: + period1 = 5000; + sweep_steps1 = 100; + PIOS_LED_Off(PIOS_LED_HEARTBEAT); + period2 = 0; + break; + case uploading: + period1 = 5000; + sweep_steps1 = 100; + period2 = 2500; + sweep_steps2 = 50; + break; + case downloading: + period1 = 2500; + sweep_steps1 = 50; + PIOS_LED_Off(PIOS_LED_HEARTBEAT); + period2 = 0; + break; + case BLidle: + period1 = 0; + PIOS_LED_On(PIOS_LED_HEARTBEAT); + period2 = 0; + break; + default: // error + period1 = 5000; + sweep_steps1 = 100; + period2 = 5000; + sweep_steps2 = 100; + } + + if (period1 != 0) { + if (LedPWM(period1, sweep_steps1, stopwatch)) { + PIOS_LED_On(PIOS_LED_HEARTBEAT); + } else { + PIOS_LED_Off(PIOS_LED_HEARTBEAT); + } + } else { + PIOS_LED_On(PIOS_LED_HEARTBEAT); + } + + if (period2 != 0) { + if (LedPWM(period2, sweep_steps2, stopwatch)) { + PIOS_LED_On(PIOS_LED_HEARTBEAT); + } else { + PIOS_LED_Off(PIOS_LED_HEARTBEAT); + } + } else { + PIOS_LED_Off(PIOS_LED_HEARTBEAT); + } + + if (stopwatch > 50 * 1000 * 1000) { + stopwatch = 0; + } + if ((stopwatch > 6 * 1000 * 1000) && ((DeviceState == BLidle) || (DeviceState == DFUidle && !USB_connected))) { + JumpToApp = TRUE; + } + + processRX(); + DataDownload(start); + } +} + +void jump_to_app() +{ + const struct pios_board_info *bdinfo = &pios_board_info_blob; + + uint32_t fwIrqStackBase = (*(__IO uint32_t *)bdinfo->fw_base) & 0xFFFE0000; + + // Check for the two possible irqstack locations (sram or core coupled sram) + if (fwIrqStackBase == 0x20000000 || fwIrqStackBase == 0x10000000) { + /* Jump to user application */ + FLASH_Lock(); + RCC_APB2PeriphResetCmd(0xffffffff, ENABLE); + RCC_APB1PeriphResetCmd(0xffffffff, ENABLE); + RCC_APB2PeriphResetCmd(0xffffffff, DISABLE); + RCC_APB1PeriphResetCmd(0xffffffff, DISABLE); + + _SetCNTR(0); // clear interrupt mask + _SetISTR(0); // clear all requests + + JumpAddress = *(__IO uint32_t *)(bdinfo->fw_base + 4); + Jump_To_Application = (pFunction)JumpAddress; + /* Initialize user application's Stack Pointer */ + __set_MSP(*(__IO uint32_t *)bdinfo->fw_base); + Jump_To_Application(); + } else { + DeviceState = failed_jump; + return; + } +} +uint32_t LedPWM(uint32_t pwm_period, uint32_t pwm_sweep_steps, uint32_t count) +{ + uint32_t curr_step = (count / pwm_period) % pwm_sweep_steps; /* 0 - pwm_sweep_steps */ + uint32_t pwm_duty = pwm_period * curr_step / pwm_sweep_steps; /* fraction of pwm_period */ + + uint32_t curr_sweep = (count / (pwm_period * pwm_sweep_steps)); /* ticks once per full sweep */ + + if (curr_sweep & 1) { + pwm_duty = pwm_period - pwm_duty; /* reverse direction in odd sweeps */ + } + return ((count % pwm_period) > pwm_duty) ? 1 : 0; +} + +uint8_t processRX() +{ + if (PIOS_COM_MSG_Receive(PIOS_COM_TELEM_USB, mReceive_Buffer, sizeof(mReceive_Buffer))) { + processComand(mReceive_Buffer); + } + return TRUE; +} + +int32_t platform_senddata(const uint8_t *msg, uint16_t msg_len) +{ + return PIOS_COM_MSG_Send(PIOS_COM_TELEM_USB, msg, msg_len); +} diff --git a/flight/targets/boards/ccf3d/bootloader/pios_board.c b/flight/targets/boards/ccf3d/bootloader/pios_board.c new file mode 100644 index 0000000000..8187bed913 --- /dev/null +++ b/flight/targets/boards/ccf3d/bootloader/pios_board.c @@ -0,0 +1,102 @@ +/** + ****************************************************************************** + * + * @file pios_board.c + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief Defines board specific static initializers for hardware for the CopterControl board. + * @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 +#include + +#include "pios_usb_board_data_priv.h" +#include "pios_usb_desc_hid_cdc_priv.h" +#include "pios_usb_desc_hid_only_priv.h" +#include "pios_usbhook.h" + +#include + +/* + * Pull in the board-specific static HW definitions. + * Including .c files is a bit ugly but this allows all of + * the HW definitions to be const and static to limit their + * scope. + * + * NOTE: THIS IS THE ONLY PLACE THAT SHOULD EVER INCLUDE THIS FILE + */ +#include "../board_hw_defs.c" + +uint32_t pios_com_telem_usb_id; + +/** + * PIOS_Board_Init() + * initializes all the core subsystems on this specific hardware + * called from System/openpilot.c + */ +static bool board_init_complete = false; +void PIOS_Board_Init(void) +{ + if (board_init_complete) { + return; + } + + /* Enable Prefetch Buffer */ + FLASH_PrefetchBufferCmd(ENABLE); + + /* Flash 2 wait state */ + FLASH_SetLatency(FLASH_Latency_2); + + const struct pios_board_info *bdinfo = &pios_board_info_blob; + +#if defined(PIOS_INCLUDE_LED) + const struct pios_gpio_cfg *led_cfg = PIOS_BOARD_HW_DEFS_GetLedCfg(bdinfo->board_rev); + PIOS_Assert(led_cfg); + PIOS_LED_Init(led_cfg); +#endif /* PIOS_INCLUDE_LED */ + +#if defined(PIOS_INCLUDE_USB) + /* Initialize board specific USB data */ + PIOS_USB_BOARD_DATA_Init(); + + /* Activate the HID-only USB configuration */ + PIOS_USB_DESC_HID_ONLY_Init(); + + uint32_t pios_usb_id; + PIOS_USB_Init(&pios_usb_id, &pios_usb_main_cfg_cc3d); + +#if defined(PIOS_INCLUDE_USB_HID) && defined(PIOS_INCLUDE_COM_MSG) + uint32_t pios_usb_hid_id; + if (PIOS_USB_HID_Init(&pios_usb_hid_id, &pios_usb_hid_only_cfg, pios_usb_id)) { + PIOS_Assert(0); + } + if (PIOS_COM_MSG_Init(&pios_com_telem_usb_id, &pios_usb_hid_com_driver, pios_usb_hid_id)) { + PIOS_Assert(0); + } +#endif /* PIOS_INCLUDE_USB_HID && PIOS_INCLUDE_COM_MSG */ + +#endif /* PIOS_INCLUDE_USB */ + + RCC_AHBPeriphClockCmd(RCC_AHBPeriph_CRC, ENABLE); // TODO Tirar + + board_init_complete = true; +} + +void PIOS_ADC_DMA_Handler() +{} diff --git a/flight/targets/boards/ccf3d/firmware/Makefile b/flight/targets/boards/ccf3d/firmware/Makefile new file mode 100644 index 0000000000..8af46bb3bd --- /dev/null +++ b/flight/targets/boards/ccf3d/firmware/Makefile @@ -0,0 +1,117 @@ +# +# Copyright (C) 2015-2016, The LibrePilot Project, http://www.librepilot.org +# Copyright (C) 2009-2013, The OpenPilot Team, http://www.openpilot.org +# Copyright (C) 2012, PhoenixPilot, http://github.com/PhoenixPilot +# +# 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 FLIGHT_MAKEFILE + $(error Top level Makefile must be used to build this target) +endif + +include ../board-info.mk +include $(FLIGHT_ROOT_DIR)/make/firmware-defs.mk + +# REVO C++ support +USE_CXX = YES + +# ARM DSP library +USE_DSP_LIB ?= NO + +DEBUG = NO + +# List of mandatory modules to include +MODULES += Sensors +MODULES += StateEstimation +MODULES += Stabilization +MODULES += ManualControl +MODULES += Receiver +MODULES += Actuator +MODULES += FirmwareIAP +#MODULES += PathPlanner +#MODULES += PathFollower +#MODULES += Osd/osdoutout +#MODULES += Logging +MODULES += Telemetry +#MODULES += Notify + +OPTMODULES += Airspeed +OPTMODULES += AutoTune +OPTMODULES += GPS +OPTMODULES += TxPID +OPTMODULES += CameraStab +OPTMODULES += CameraControl +OPTMODULES += Battery +OPTMODULES += ComUsbBridge +OPTMODULES += UAVOMSPBridge +OPTMODULES += UAVOMavlinkBridge + +SRC += $(FLIGHTLIB)/notification.c + +# Include all camera options +CDEFS += -DUSE_INPUT_LPF -DUSE_GIMBAL_LPF -DUSE_GIMBAL_FF + +# Some diagnostics +CDEFS += -DDIAG_TASKS + +# Misc options +CFLAGS += -ffast-math + +# List C source files here (C dependencies are automatically generated). +# Use file-extension c for "c-only"-files +ifndef TESTAPP + ## Application Core + SRC += ../pios_usb_board_data.c + SRC += $(OPMODULEDIR)/System/systemmod.c + CPPSRC += $(OPSYSTEM)/coptercontrol.cpp + SRC += $(OPSYSTEM)/pios_board.c + SRC += $(FLIGHTLIB)/alarms.c + SRC += $(OPUAVTALK)/uavtalk.c + SRC += $(OPUAVOBJ)/uavobjectmanager.c + SRC += $(OPUAVOBJ)/uavobjectpersistence.c + SRC += $(OPUAVOBJ)/eventdispatcher.c + SRC += $(PIOSCOMMON)/pios_flashfs_logfs.c + SRC += $(PIOSCOMMON)/pios_flash_jedec.c + + #ifeq ($(DEBUG), YES) + SRC += $(OPSYSTEM)/dcc_stdio.c + SRC += $(OPSYSTEM)/cm3_fault_handlers.c + #endif + + ## Misc library functions + SRC += $(FLIGHTLIB)/instrumentation.c + SRC += $(FLIGHTLIB)/paths.c + SRC += $(FLIGHTLIB)/plans.c + SRC += $(FLIGHTLIB)/WorldMagModel.c + SRC += $(FLIGHTLIB)/insgps13state.c + SRC += $(FLIGHTLIB)/auxmagsupport.c + SRC += $(FLIGHTLIB)/lednotification.c + + ## UAVObjects + include ./UAVObjects.inc + SRC += $(UAVOBJSRC) +else + ## Test Code + SRC += $(OPTESTS)/test_common.c + SRC += $(OPTESTS)/$(TESTAPP).c +endif + +# Optional component libraries +#include $(FLIGHTLIB)/rscode/library.mk +#include $(FLIGHTLIB)/PyMite/pymite.mk + +include $(FLIGHT_ROOT_DIR)/make/apps-defs.mk +include $(FLIGHT_ROOT_DIR)/make/common-defs.mk diff --git a/flight/targets/boards/ccf3d/firmware/UAVObjects.inc b/flight/targets/boards/ccf3d/firmware/UAVObjects.inc new file mode 100644 index 0000000000..22e9cb2a71 --- /dev/null +++ b/flight/targets/boards/ccf3d/firmware/UAVObjects.inc @@ -0,0 +1,135 @@ +# +# Copyright (C) 2016, The LibrePilot Project, http://www.librepilot.org +# Copyright (C) 2009-2013, The OpenPilot Team, http://www.openpilot.org +# +# 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 +# + +# These are the UAVObjects supposed to be build as part of the OpenPilot target +# (all architectures) +UAVOBJSRCFILENAMES = +UAVOBJSRCFILENAMES += statusgrounddrive +UAVOBJSRCFILENAMES += pidstatus +UAVOBJSRCFILENAMES += statusvtolland +UAVOBJSRCFILENAMES += statusvtolautotakeoff +UAVOBJSRCFILENAMES += vtolselftuningstats +UAVOBJSRCFILENAMES += accelgyrosettings +UAVOBJSRCFILENAMES += accessorydesired +UAVOBJSRCFILENAMES += actuatorcommand +UAVOBJSRCFILENAMES += actuatordesired +UAVOBJSRCFILENAMES += actuatorsettings +UAVOBJSRCFILENAMES += attitudesettings +UAVOBJSRCFILENAMES += attitudestate +UAVOBJSRCFILENAMES += gyrostate +UAVOBJSRCFILENAMES += gyrosensor +UAVOBJSRCFILENAMES += accelstate +UAVOBJSRCFILENAMES += accelsensor +UAVOBJSRCFILENAMES += magsensor +UAVOBJSRCFILENAMES += auxmagsensor +UAVOBJSRCFILENAMES += auxmagsettings +UAVOBJSRCFILENAMES += magstate +UAVOBJSRCFILENAMES += barosensor +UAVOBJSRCFILENAMES += airspeedsensor +UAVOBJSRCFILENAMES += airspeedsettings +UAVOBJSRCFILENAMES += airspeedstate +UAVOBJSRCFILENAMES += debuglogsettings +UAVOBJSRCFILENAMES += debuglogcontrol +UAVOBJSRCFILENAMES += debuglogstatus +UAVOBJSRCFILENAMES += debuglogentry +UAVOBJSRCFILENAMES += flightbatterysettings +UAVOBJSRCFILENAMES += firmwareiapobj +UAVOBJSRCFILENAMES += flightbatterystate +UAVOBJSRCFILENAMES += flightplancontrol +UAVOBJSRCFILENAMES += flightplansettings +UAVOBJSRCFILENAMES += flightplanstatus +UAVOBJSRCFILENAMES += flighttelemetrystats +UAVOBJSRCFILENAMES += gcstelemetrystats +UAVOBJSRCFILENAMES += gcsreceiver +UAVOBJSRCFILENAMES += gpspositionsensor +UAVOBJSRCFILENAMES += gpssatellites +UAVOBJSRCFILENAMES += gpstime +UAVOBJSRCFILENAMES += gpsvelocitysensor +UAVOBJSRCFILENAMES += gpssettings +UAVOBJSRCFILENAMES += gpsextendedstatus +UAVOBJSRCFILENAMES += fixedwingpathfollowersettings +UAVOBJSRCFILENAMES += fixedwingpathfollowerstatus +UAVOBJSRCFILENAMES += vtolpathfollowersettings +UAVOBJSRCFILENAMES += groundpathfollowersettings +UAVOBJSRCFILENAMES += homelocation +UAVOBJSRCFILENAMES += i2cstats +UAVOBJSRCFILENAMES += manualcontrolcommand +UAVOBJSRCFILENAMES += manualcontrolsettings +UAVOBJSRCFILENAMES += flightmodesettings +UAVOBJSRCFILENAMES += mixersettings +UAVOBJSRCFILENAMES += mixerstatus +UAVOBJSRCFILENAMES += nedaccel +UAVOBJSRCFILENAMES += objectpersistence +UAVOBJSRCFILENAMES += oplinkreceiver +UAVOBJSRCFILENAMES += overosyncstats +UAVOBJSRCFILENAMES += overosyncsettings +UAVOBJSRCFILENAMES += pathaction +UAVOBJSRCFILENAMES += pathdesired +UAVOBJSRCFILENAMES += pathplan +UAVOBJSRCFILENAMES += pathstatus +UAVOBJSRCFILENAMES += pathsummary +UAVOBJSRCFILENAMES += positionstate +UAVOBJSRCFILENAMES += ratedesired +UAVOBJSRCFILENAMES += ekfconfiguration +UAVOBJSRCFILENAMES += ekfstatevariance +UAVOBJSRCFILENAMES += revocalibration +UAVOBJSRCFILENAMES += revosettings +UAVOBJSRCFILENAMES += sonaraltitude +UAVOBJSRCFILENAMES += stabilizationdesired +UAVOBJSRCFILENAMES += stabilizationsettings +UAVOBJSRCFILENAMES += stabilizationsettingsbank1 +UAVOBJSRCFILENAMES += stabilizationsettingsbank2 +UAVOBJSRCFILENAMES += stabilizationsettingsbank3 +UAVOBJSRCFILENAMES += stabilizationstatus +UAVOBJSRCFILENAMES += stabilizationbank +UAVOBJSRCFILENAMES += systemalarms +UAVOBJSRCFILENAMES += systemsettings +UAVOBJSRCFILENAMES += systemstats +UAVOBJSRCFILENAMES += taskinfo +UAVOBJSRCFILENAMES += callbackinfo +UAVOBJSRCFILENAMES += velocitystate +UAVOBJSRCFILENAMES += velocitydesired +UAVOBJSRCFILENAMES += watchdogstatus +UAVOBJSRCFILENAMES += flightstatus +UAVOBJSRCFILENAMES += hwsettings +UAVOBJSRCFILENAMES += receiveractivity +UAVOBJSRCFILENAMES += receiverstatus +UAVOBJSRCFILENAMES += cameradesired +UAVOBJSRCFILENAMES += camerastabsettings +UAVOBJSRCFILENAMES += altitudeholdsettings +UAVOBJSRCFILENAMES += oplinksettings +UAVOBJSRCFILENAMES += oplinkstatus +UAVOBJSRCFILENAMES += altitudefiltersettings +UAVOBJSRCFILENAMES += altitudeholdstatus +UAVOBJSRCFILENAMES += waypoint +UAVOBJSRCFILENAMES += waypointactive +UAVOBJSRCFILENAMES += poilocation +UAVOBJSRCFILENAMES += poilearnsettings +UAVOBJSRCFILENAMES += mpugyroaccelsettings +UAVOBJSRCFILENAMES += txpidsettings +UAVOBJSRCFILENAMES += txpidstatus +UAVOBJSRCFILENAMES += takeofflocation +UAVOBJSRCFILENAMES += perfcounter +UAVOBJSRCFILENAMES += systemidentsettings +UAVOBJSRCFILENAMES += systemidentstate +UAVOBJSRCFILENAMES += cameracontrolsettings +UAVOBJSRCFILENAMES += cameracontrolactivity + +UAVOBJSRC = $(foreach UAVOBJSRCFILE,$(UAVOBJSRCFILENAMES),$(FLIGHT_UAVOBJ_DIR)/$(UAVOBJSRCFILE).c ) +UAVOBJDEFINE = $(foreach UAVOBJSRCFILE,$(UAVOBJSRCFILENAMES),-DUAVOBJ_INIT_$(UAVOBJSRCFILE) ) diff --git a/flight/targets/boards/ccf3d/firmware/cm3_fault_handlers.c b/flight/targets/boards/ccf3d/firmware/cm3_fault_handlers.c new file mode 100644 index 0000000000..cf91428579 --- /dev/null +++ b/flight/targets/boards/ccf3d/firmware/cm3_fault_handlers.c @@ -0,0 +1,93 @@ +/* + * cm3_fault_handlers.c + * + * Created on: Apr 24, 2011 + * Author: msmith + */ + +#include +#include "inc/dcc_stdio.h" +#ifdef STM32F4XX +# include +#endif +#ifdef STM32F3 +# include +#endif +#ifdef STM32F2XX +# include +#endif + +#define FAULT_TRAMPOLINE(_vec) \ + __attribute__((naked, no_instrument_function)) \ + void \ + _vec##_Handler(void) \ + { \ + __asm(".syntax unified\n" \ + "MOVS R0, #4 \n" \ + "MOV R1, LR \n" \ + "TST R0, R1 \n" \ + "BEQ 1f \n" \ + "MRS R0, PSP \n" \ + "B " #_vec "_Handler2 \n" \ + "1: \n" \ + "MRS R0, MSP \n" \ + "B " #_vec "_Handler2 \n" \ + ".syntax divided\n"); \ + } \ + struct hack + +struct cm3_frame { + uint32_t r0; + uint32_t r1; + uint32_t r2; + uint32_t r3; + uint32_t r12; + uint32_t lr; + uint32_t pc; + uint32_t psr; +}; + +FAULT_TRAMPOLINE(HardFault); +FAULT_TRAMPOLINE(BusFault); +FAULT_TRAMPOLINE(UsageFault); + +/* this is a hackaround to avoid an issue where dereferencing SCB seems to result in bad codegen and a link error */ +#define SCB_REG(_reg) (*(uint32_t *)&(SCB->_reg)) + +void HardFault_Handler2(struct cm3_frame *frame) +{ + dbg_write_str("\nHARD FAULT"); + dbg_write_hex32(frame->pc); + dbg_write_char('\n'); + dbg_write_hex32(SCB_REG(HFSR)); + dbg_write_char('\n'); + for (;;) { + ; + } +} + +void BusFault_Handler2(struct cm3_frame *frame) +{ + dbg_write_str("\nBUS FAULT"); + dbg_write_hex32(frame->pc); + dbg_write_char('\n'); + dbg_write_hex32(SCB_REG(CFSR)); + dbg_write_char('\n'); + dbg_write_hex32(SCB_REG(BFAR)); + dbg_write_char('\n'); + for (;;) { + ; + } +} + +void UsageFault_Handler2(struct cm3_frame *frame) +{ + dbg_write_str("\nUSAGE FAULT"); + dbg_write_hex32(frame->pc); + dbg_write_char('\n'); + dbg_write_hex32(SCB_REG(CFSR)); + dbg_write_char('\n'); + for (;;) { + ; + } +} diff --git a/flight/targets/boards/ccf3d/firmware/coptercontrol.cpp b/flight/targets/boards/ccf3d/firmware/coptercontrol.cpp new file mode 100644 index 0000000000..ec093c995e --- /dev/null +++ b/flight/targets/boards/ccf3d/firmware/coptercontrol.cpp @@ -0,0 +1,98 @@ +/** + ****************************************************************************** + * @addtogroup LibrePilotSystem LibrePilot System + * @brief These files are the core system files for CopterControl. + * They are the ground layer just above PiOS. In practice, CopterControl actually starts + * in the main() function of coptercontrol.c + * @{ + * @addtogroup LibrePilotCore LibrePilot Core + * @brief This is where the LP firmware starts. Those files also define the compile-time + * options of the firmware. + * @{ + * @file coptercontrol.c + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015. + * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010-2015 + * @brief Sets up and runs main tasks. + * @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 + */ + +extern "C" { +#include "inc/openpilot.h" +#include +/* Task Priorities */ + +/* Global Variables */ +extern void Stack_Change(void); +} /* extern "C" */ + +/** + * OpenPilot Main function: + * + * Initialize PiOS
+ * Create the "System" task (SystemModInitializein Modules/System/systemmod.c)
+ * Start FreeRTOS Scheduler (vTaskStartScheduler) (Now handled by caller) + * If something goes wrong, blink LED1 and LED2 every 100ms + * + */ +int main() +{ + /* NOTE: Do NOT modify the following start-up sequence */ + /* Any new initialization functions should be added in OpenPilotInit() */ + + vPortInitialiseBlocks(); + + /* Brings up System using CMSIS functions, enables the LEDs. */ + PIOS_SYS_Init(); + + + SystemModStart(); + + /* Start the FreeRTOS scheduler, which should never return. + * + * NOTE: OpenPilot runs an operating system (FreeRTOS), which constantly calls + * (schedules) function files (modules). These functions never return from their + * while loops, which explains why each module has a while(1){} segment. Thus, + * the OpenPilot software actually starts at the vTaskStartScheduler() function, + * even though this is somewhat obscure. + * + * In addition, there are many main() functions in the OpenPilot firmware source tree + * This is because each main() refers to a separate hardware platform. Of course, + * C only allows one main(), so only the relevant main() function is compiled when + * making a specific firmware. + * + */ + vTaskStartScheduler(); + + /* If all is well we will never reach here as the scheduler will now be running. */ + + /* Do some indication to user that something bad just happened */ + while (1) { +#if defined(PIOS_LED_HEARTBEAT) + PIOS_LED_Toggle(PIOS_LED_HEARTBEAT); +#endif /* PIOS_LED_HEARTBEAT */ + PIOS_DELAY_WaitmS(100); + } + + return 0; +} + +/** + * @} + * @} + */ diff --git a/flight/targets/boards/ccf3d/firmware/dcc_stdio.c b/flight/targets/boards/ccf3d/firmware/dcc_stdio.c new file mode 100644 index 0000000000..1a522e9a0d --- /dev/null +++ b/flight/targets/boards/ccf3d/firmware/dcc_stdio.c @@ -0,0 +1,149 @@ +/*************************************************************************** +* Copyright (C) 2008 by Dominic Rath * +* Dominic.Rath@gmx.de * +* Copyright (C) 2008 by Spencer Oliver * +* spen@spen-soft.co.uk * +* Copyright (C) 2008 by Frederik Kriewtz * +* frederik@kriewitz.eu * +* * +* 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 2 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 "inc/dcc_stdio.h" + +#define TARGET_REQ_TRACEMSG 0x00 +#define TARGET_REQ_DEBUGMSG_ASCII 0x01 +#define TARGET_REQ_DEBUGMSG_HEXMSG(size) (0x01 | ((size & 0xff) << 8)) +#define TARGET_REQ_DEBUGCHAR 0x02 + +/* we use the cortex_m3 DCRDR reg to simulate a arm7_9 dcc channel + * DCRDR[7:0] is used by target for status + * DCRDR[15:8] is used by target for write buffer + * DCRDR[23:16] is used for by host for status + * DCRDR[31:24] is used for by host for write buffer */ + +#define NVIC_DBG_DATA_R (*((volatile unsigned short *)0xE000EDF8)) + +#define BUSY 1 + +void dbg_write(unsigned long dcc_data) +{ + int len = 4; + + while (len--) { + /* wait for data ready */ + while (NVIC_DBG_DATA_R & BUSY) { + ; + } + + /* write our data and set write flag - tell host there is data*/ + NVIC_DBG_DATA_R = (unsigned short)(((dcc_data & 0xff) << 8) | BUSY); + dcc_data >>= 8; + } +} + +void dbg_trace_point(unsigned long number) +{ + dbg_write(TARGET_REQ_TRACEMSG | (number << 8)); +} + +void dbg_write_u32(const unsigned long *val, long len) +{ + dbg_write(TARGET_REQ_DEBUGMSG_HEXMSG(4) | ((len & 0xffff) << 16)); + + while (len > 0) { + dbg_write(*val); + + val++; + len--; + } +} + +void dbg_write_u16(const unsigned short *val, long len) +{ + unsigned long dcc_data; + + dbg_write(TARGET_REQ_DEBUGMSG_HEXMSG(2) | ((len & 0xffff) << 16)); + + while (len > 0) { + dcc_data = val[0] + | ((len > 1) ? val[1] << 16 : 0x0000); + + dbg_write(dcc_data); + + val += 2; + len -= 2; + } +} + +void dbg_write_u8(const unsigned char *val, long len) +{ + unsigned long dcc_data; + + dbg_write(TARGET_REQ_DEBUGMSG_HEXMSG(1) | ((len & 0xffff) << 16)); + + while (len > 0) { + dcc_data = val[0] + | ((len > 1) ? val[1] << 8 : 0x00) + | ((len > 2) ? val[2] << 16 : 0x00) + | ((len > 3) ? val[3] << 24 : 0x00); + + dbg_write(dcc_data); + + val += 4; + len -= 4; + } +} + +void dbg_write_str(const char *msg) +{ + long len; + unsigned long dcc_data; + + for (len = 0; msg[len] && (len < 65536); len++) { + ; + } + + dbg_write(TARGET_REQ_DEBUGMSG_ASCII | ((len & 0xffff) << 16)); + + while (len > 0) { + dcc_data = msg[0] + | ((len > 1) ? msg[1] << 8 : 0x00) + | ((len > 2) ? msg[2] << 16 : 0x00) + | ((len > 3) ? msg[3] << 24 : 0x00); + dbg_write(dcc_data); + + msg += 4; + len -= 4; + } +} + +void dbg_write_char(char msg) +{ + dbg_write(TARGET_REQ_DEBUGCHAR | ((msg & 0xff) << 16)); +} + +void dbg_write_hex32(const unsigned long val) +{ + static const char hextab[] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' + }; + + for (int shift = 28; shift >= 0; shift -= 4) { + dbg_write_char(hextab[(val >> shift) & 0xf]); + } +} diff --git a/flight/targets/boards/ccf3d/firmware/inc/FreeRTOSConfig.h b/flight/targets/boards/ccf3d/firmware/inc/FreeRTOSConfig.h new file mode 100644 index 0000000000..5fea013d7a --- /dev/null +++ b/flight/targets/boards/ccf3d/firmware/inc/FreeRTOSConfig.h @@ -0,0 +1,99 @@ +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +/*----------------------------------------------------------- +* Application specific definitions. +* +* These definitions should be adjusted for your particular hardware and +* application requirements. +* +* THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE +* FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. +* +* See http://www.freertos.org/a00110.html. +*----------------------------------------------------------*/ + +/** + * @addtogroup PIOS PIOS + * @{ + * @addtogroup FreeRTOS FreeRTOS + * @{ + */ + +/* Notes: We use 5 task priorities */ + +#define configUSE_PREEMPTION 1 +#define configUSE_IDLE_HOOK 1 +#define configUSE_TICK_HOOK 0 +#define configUSE_MALLOC_FAILED_HOOK 1 +#define configCPU_CLOCK_HZ ((unsigned long)72000000) +#define configTICK_RATE_HZ ((portTickType)1000) +#define configMAX_PRIORITIES ((unsigned portBASE_TYPE)5) +#define configMINIMAL_STACK_SIZE ((unsigned short)512) +#define configTOTAL_HEAP_SIZE ((size_t)(53 * 256)) +#define configMAX_TASK_NAME_LEN (6) +#define configUSE_TRACE_FACILITY 0 +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 0 +#define configUSE_MUTEXES 1 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configUSE_COUNTING_SEMAPHORES 0 +#define configUSE_ALTERNATIVE_API 0 +#define configQUEUE_REGISTRY_SIZE 0 + +/* Co-routine definitions. */ +#define configUSE_CO_ROUTINES 0 +#define configMAX_CO_ROUTINE_PRIORITIES (2) + +/* Set the following definitions to 1 to include the API function, or zero + to exclude the API function. */ + +#define INCLUDE_vTaskPrioritySet 1 +#define INCLUDE_uxTaskPriorityGet 1 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskCleanUpResources 0 +#define INCLUDE_vTaskSuspend 1 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_xTaskGetSchedulerState 0 +#define INCLUDE_xTaskGetCurrentTaskHandle 1 +#define INCLUDE_uxTaskGetStackHighWaterMark 1 + +/* This is the raw value as per the Cortex-M3 NVIC. Values can be 255 + (lowest) to 1 (highest maskable) to 0 (highest non-maskable). */ +#define configKERNEL_INTERRUPT_PRIORITY 15 << 4 /* equivalent to NVIC priority 15 */ + #define configMAX_SYSCALL_INTERRUPT_PRIORITY 3 << 4 /* equivalent to NVIC priority 3 */ + +/* This is the value being used as per the ST library which permits 16 + priority values, 0 to 15. This must correspond to the + configKERNEL_INTERRUPT_PRIORITY setting. Here 15 corresponds to the lowest + NVIC value of 255. */ +#define configLIBRARY_KERNEL_INTERRUPT_PRIORITY 15 + +#if !defined(ARCH_POSIX) && !defined(ARCH_WIN32) +#define CHECK_IRQ_STACK +#endif + +/* Enable run time stats collection */ +#define configGENERATE_RUN_TIME_STATS 1 +#define INCLUDE_uxTaskGetRunTime 1 +#define INCLUDE_xTaskGetIdleTaskHandle 1 +#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() \ + do { \ + (*(unsigned long *)0xe000edfc) |= (1 << 24); /* DEMCR |= DEMCR_TRCENA */ \ + (*(unsigned long *)0xe0001000) |= 1; /* DWT_CTRL |= DWT_CYCCNT_ENA */ \ + } \ + while (0) +#define portGET_RUN_TIME_COUNTER_VALUE() (*(unsigned long *)0xe0001004) /* DWT_CYCCNT */ + +#ifdef DIAG_TASKS +#define configCHECK_FOR_STACK_OVERFLOW 2 +#else +#define configCHECK_FOR_STACK_OVERFLOW 1 +#endif + +/** + * @} + */ + +#endif /* FREERTOS_CONFIG_H */ diff --git a/flight/targets/boards/ccf3d/firmware/inc/dcc_stdio.h b/flight/targets/boards/ccf3d/firmware/inc/dcc_stdio.h new file mode 100644 index 0000000000..3d73549182 --- /dev/null +++ b/flight/targets/boards/ccf3d/firmware/inc/dcc_stdio.h @@ -0,0 +1,36 @@ +/*************************************************************************** +* Copyright (C) 2008 by Dominic Rath * +* Dominic.Rath@gmx.de * +* Copyright (C) 2008 by Spencer Oliver * +* spen@spen-soft.co.uk * +* * +* 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 2 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 DCC_STDIO_H +#define DCC_STDIO_H + +void dbg_trace_point(unsigned long number); + +void dbg_write_u32(const unsigned long *val, long len); +void dbg_write_u16(const unsigned short *val, long len); +void dbg_write_u8(const unsigned char *val, long len); + +void dbg_write_str(const char *msg); +void dbg_write_char(char msg); +void dbg_write_hex32(const unsigned long val); + +#endif /* DCC_STDIO_H */ diff --git a/flight/targets/boards/ccf3d/firmware/inc/openpilot.h b/flight/targets/boards/ccf3d/firmware/inc/openpilot.h new file mode 100644 index 0000000000..5576baca66 --- /dev/null +++ b/flight/targets/boards/ccf3d/firmware/inc/openpilot.h @@ -0,0 +1,52 @@ +/** + ****************************************************************************** + * @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 + +/* OpenPilot Libraries */ +#include +#include +#include +#include + +#include "alarms.h" +#include + +/* Global Functions */ +void OpenPilotInit(void); + +#endif /* OPENPILOT_H */ + +/** + * @} + * @} + */ diff --git a/flight/targets/boards/ccf3d/firmware/inc/pios_board_posix.h b/flight/targets/boards/ccf3d/firmware/inc/pios_board_posix.h new file mode 100644 index 0000000000..16364d7fa0 --- /dev/null +++ b/flight/targets/boards/ccf3d/firmware/inc/pios_board_posix.h @@ -0,0 +1,81 @@ +/** + ****************************************************************************** + * + * @file pios_board.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief Defines board hardware for the OpenPilot Version 1.1 hardware. + * @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_BOARD_H +#define PIOS_BOARD_H + + +// ------------------------ +// PIOS_LED +// ------------------------ +// #define PIOS_LED_LED1_GPIO_PORT GPIOC +// #define PIOS_LED_LED1_GPIO_PIN GPIO_Pin_12 +// #define PIOS_LED_LED1_GPIO_CLK RCC_APB2Periph_GPIOC +// #define PIOS_LED_LED2_GPIO_PORT GPIOC +// #define PIOS_LED_LED2_GPIO_PIN GPIO_Pin_13 +// #define PIOS_LED_LED2_GPIO_CLK RCC_APB2Periph_GPIOC +#define PIOS_LED_NUM 2 +// #define PIOS_LED_PORTS { PIOS_LED_LED1_GPIO_PORT, PIOS_LED_LED2_GPIO_PORT } +// #define PIOS_LED_PINS { PIOS_LED_LED1_GPIO_PIN, PIOS_LED_LED2_GPIO_PIN } +// #define PIOS_LED_CLKS { PIOS_LED_LED1_GPIO_CLK, PIOS_LED_LED2_GPIO_CLK } + + +// ------------------------- +// COM +// +// See also pios_board_posix.c +// ------------------------- +// #define PIOS_USART_TX_BUFFER_SIZE 256 +#define PIOS_COM_BUFFER_SIZE 1024 +#define PIOS_UDP_RX_BUFFER_SIZE PIOS_COM_BUFFER_SIZE + +#define PIOS_COM_TELEM_RF 0 +#define PIOS_COM_GPS 1 +#define PIOS_COM_TELEM_USB 2 + +#ifdef PIOS_ENABLE_AUX_UART +#define PIOS_COM_AUX 3 +#define PIOS_COM_DEBUG PIOS_COM_AUX +#endif + +/** + * glue macros for file IO + * STM32 uses DOSFS for file IO + */ +#define PIOS_FOPEN_READ(filename, file) (file = fopen((char *)filename, "r")) == NULL + +#define PIOS_FOPEN_WRITE(filename, file) (file = fopen((char *)filename, "w")) == NULL + +#define PIOS_FREAD(file, bufferadr, length, resultadr) (*resultadr = fread((uint8_t *)bufferadr, 1, length, *file)) != length + +#define PIOS_FWRITE(file, bufferadr, length, resultadr) *resultadr = fwrite((uint8_t *)bufferadr, 1, length, *file) + + +#define PIOS_FCLOSE(file) fclose(file) + +#define PIOS_FUNLINK(file) unlink((char *)filename) + +#endif /* PIOS_BOARD_H */ diff --git a/flight/targets/boards/ccf3d/firmware/inc/pios_config.h b/flight/targets/boards/ccf3d/firmware/inc/pios_config.h new file mode 100644 index 0000000000..b3f3f1b795 --- /dev/null +++ b/flight/targets/boards/ccf3d/firmware/inc/pios_config.h @@ -0,0 +1,189 @@ +/** + ****************************************************************************** + * @addtogroup OpenPilotSystem OpenPilot System + * @{ + * @addtogroup OpenPilotCore OpenPilot Core + * @{ + * @file pios_config.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010-2013. + * @author LibrePilot, https://bitbucket.org/librepilot, Copyright (C) 2015 + * @brief PiOS configuration header, the compile time config file for the PIOS. + * Defines which PiOS libraries and features are included in the firmware. + * @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 + +/* + * Below is a complete list of PIOS configurable options. + * Please do not remove or rearrange them. Only comment out + * unused options in the list. See main pios.h header for more + * details. + */ + +/* #define PIOS_INCLUDE_DEBUG_CONSOLE */ +/* #define DEBUG_LEVEL 0 */ +/* #define PIOS_ENABLE_DEBUG_PINS */ + +/* PIOS FreeRTOS support */ +#define PIOS_INCLUDE_FREERTOS + + +/* PIOS CallbackScheduler support */ +#define PIOS_INCLUDE_CALLBACKSCHEDULER + +/* PIOS bootloader helper */ +#define PIOS_INCLUDE_BL_HELPER +/* #define PIOS_INCLUDE_BL_HELPER_WRITE_SUPPORT */ + +/* PIOS system functions */ +#define PIOS_INCLUDE_DELAY +#define PIOS_INCLUDE_INITCALL +#define PIOS_INCLUDE_SYS +#define PIOS_INCLUDE_TASK_MONITOR +// #define PIOS_INCLUDE_INSTRUMENTATION +#define PIOS_INSTRUMENTATION_MAX_COUNTERS 5 + +/* PIOS hardware peripherals */ +#define PIOS_INCLUDE_IRQ +#define PIOS_INCLUDE_RTC +#define PIOS_INCLUDE_TIM +#define PIOS_INCLUDE_USART +/* #define PIOS_INCLUDE_ADC */ +#define PIOS_INCLUDE_I2C +#define PIOS_INCLUDE_SPI +#define PIOS_INCLUDE_GPIO +#define PIOS_INCLUDE_EXTI +#define PIOS_INCLUDE_WDG + +/* PIOS USB functions */ +#define PIOS_INCLUDE_USB +#define PIOS_INCLUDE_USB_HID +#define PIOS_INCLUDE_USB_CDC +/* #define PIOS_INCLUDE_USB_RCTX */ + +/* PIOS sensor interfaces */ +/* #define PIOS_INCLUDE_ADXL345 */ +/* #define PIOS_INCLUDE_BMA180 */ +/* #define PIOS_INCLUDE_L3GD20 */ +#define PIOS_INCLUDE_MPU6000 +#define PIOS_MPU6000_ACCEL +/* #define PIOS_INCLUDE_HMC5843 */ +/* #define PIOS_INCLUDE_HMC5X83 */ +/* #define PIOS_HMC5883_HAS_GPIOS */ +/* #define PIOS_INCLUDE_BMP085 */ +/* #define PIOS_INCLUDE_MS5611 */ +/* #define PIOS_INCLUDE_MPXV */ +/* #define PIOS_INCLUDE_ETASV3 */ +/* #define PIOS_INCLUDE_HCSR04 */ + +#define PIOS_SENSOR_RATE 500.0f + +/* PIOS receiver drivers */ +#define PIOS_INCLUDE_PWM +#define PIOS_INCLUDE_PPM +#define PIOS_INCLUDE_PPM_FLEXI +#define PIOS_INCLUDE_DSM +#define PIOS_INCLUDE_SBUS +#define PIOS_INCLUDE_EXBUS +#define PIOS_INCLUDE_SRXL +#define PIOS_INCLUDE_HOTT +#define PIOS_INCLUDE_IBUS +/* #define PIOS_INCLUDE_GCSRCVR */ +/* #define PIOS_INCLUDE_OPLINKRCVR */ + +/* PIOS abstract receiver interface */ +#define PIOS_INCLUDE_RCVR + +/* PIOS common peripherals */ +#define PIOS_INCLUDE_LED +#define PIOS_INCLUDE_IAP +#define PIOS_INCLUDE_SERVO +/* #define PIOS_INCLUDE_I2C_ESC */ +/* #define PIOS_INCLUDE_OVERO */ +/* #define PIOS_OVERO_SPI */ +/* #define PIOS_INCLUDE_SDCARD */ +/* #define LOG_FILENAME "startup.log" */ +#define PIOS_INCLUDE_FLASH +#define PIOS_INCLUDE_FLASH_LOGFS_SETTINGS +/* #define FLASH_FREERTOS */ +/* #define PIOS_INCLUDE_FLASH_EEPROM */ +/* #define PIOS_INCLUDE_FLASH_INTERNAL */ + +/* PIOS radio modules */ +/* #define PIOS_INCLUDE_RFM22B */ +/* #define PIOS_INCLUDE_RFM22B_COM */ +/* #define PIOS_INCLUDE_PPM_OUT */ +/* #define PIOS_RFM22B_DEBUG_ON_TELEM */ + +/* PIOS misc peripherals */ +/* #define PIOS_INCLUDE_VIDEO */ +/* #define PIOS_INCLUDE_WAVE */ +/* #define PIOS_INCLUDE_UDP */ + +/* PIOS abstract comms interface with options */ +#define PIOS_INCLUDE_COM +/* #define PIOS_INCLUDE_COM_MSG */ +#define PIOS_INCLUDE_TELEMETRY_RF +/* #define PIOS_INCLUDE_COM_TELEM */ +/* #define PIOS_INCLUDE_COM_FLEXI */ +/* #define PIOS_INCLUDE_COM_AUX */ +/* #define PIOS_TELEM_PRIORITY_QUEUE */ +#define PIOS_INCLUDE_GPS +/* #define PIOS_GPS_MINIMAL */ +#define PIOS_INCLUDE_GPS_NMEA_PARSER +#define PIOS_INCLUDE_GPS_UBX_PARSER +#define PIOS_INCLUDE_GPS_DJI_PARSER +#define PIOS_GPS_SETS_HOMELOCATION + +/* Stabilization options */ +#define PIOS_QUATERNION_STABILIZATION +/* #define PIOS_EXCLUDE_ADVANCED_FEATURES */ +/* Performance counters */ +#define IDLE_COUNTS_PER_SEC_AT_NO_LOAD 1995998 + +/* Alarm Thresholds */ +#define HEAP_LIMIT_WARNING 220 +#define HEAP_LIMIT_CRITICAL 40 +#define IRQSTACK_LIMIT_WARNING 100 +#define IRQSTACK_LIMIT_CRITICAL 60 +#define CPULOAD_LIMIT_WARNING 85 +#define CPULOAD_LIMIT_CRITICAL 95 + +/* Task stack sizes */ +#define PIOS_ACTUATOR_STACK_SIZE 800 +#define PIOS_MANUAL_STACK_SIZE 935 +#define PIOS_RECEIVER_STACK_SIZE 840 +#define PIOS_SYSTEM_STACK_SIZE 1536 +/* #define PIOS_STABILIZATION_STACK_SIZE 400 */ + +#define PIOS_TELEM_STACK_SIZE 800 +#define PIOS_EVENTDISPATCHER_STACK_SIZE 256 + +/* This can't be too high to stop eventdispatcher thread overflowing */ +#define PIOS_EVENTDISAPTCHER_QUEUE 10 + +/* Revolution series */ +#define REVOLUTION + +#endif /* PIOS_CONFIG_H */ +/** + * @} + * @} + */ diff --git a/flight/targets/boards/ccf3d/firmware/inc/pios_config_posix.h b/flight/targets/boards/ccf3d/firmware/inc/pios_config_posix.h new file mode 100644 index 0000000000..4e8aa47c66 --- /dev/null +++ b/flight/targets/boards/ccf3d/firmware/inc/pios_config_posix.h @@ -0,0 +1,48 @@ +/** + ****************************************************************************** + * + * @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_POSIX_H +#define PIOS_CONFIG_POSIX_H + + +/* Enable/Disable PiOS Modules */ +#define PIOS_INCLUDE_SYS +#define PIOS_INCLUDE_DELAY +#define PIOS_INCLUDE_LED +#define PIOS_INCLUDE_FREERTOS +#define PIOS_INCLUDE_CALLBACKSCHEDULER +#define PIOS_INCLUDE_TASK_MONITOR +#define PIOS_INCLUDE_COM +#define PIOS_INCLUDE_UDP +#define PIOS_INCLUDE_SERVO + + +/* Defaults for Logging */ +#define LOG_FILENAME "PIOS.LOG" +#define STARTUP_LOG_ENABLED 1 + +#endif /* PIOS_CONFIG_POSIX_H */ diff --git a/flight/targets/boards/ccf3d/firmware/inc/pios_usb_board_data.h b/flight/targets/boards/ccf3d/firmware/inc/pios_usb_board_data.h new file mode 100644 index 0000000000..1fac7c659e --- /dev/null +++ b/flight/targets/boards/ccf3d/firmware/inc/pios_usb_board_data.h @@ -0,0 +1,47 @@ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_USB_BOARD Board specific USB definitions + * @brief Board specific USB definitions + * @{ + * + * @file pios_usb_board_data.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief Board specific USB 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_USB_BOARD_DATA_H +#define PIOS_USB_BOARD_DATA_H + +// Note : changing below length will require changes to the USB buffer setup +#define PIOS_USB_BOARD_CDC_DATA_LENGTH 64 +#define PIOS_USB_BOARD_CDC_MGMT_LENGTH 32 +#define PIOS_USB_BOARD_HID_DATA_LENGTH 64 + +#define PIOS_USB_BOARD_EP_NUM 4 + +#include /* USB_* macros */ + +#define PIOS_USB_BOARD_PRODUCT_ID USB_PRODUCT_ID_COPTERCONTROL +#define PIOS_USB_BOARD_DEVICE_VER USB_OP_DEVICE_VER(USB_OP_BOARD_ID_COPTERCONTROL, USB_OP_BOARD_MODE_FW) +#define PIOS_USB_BOARD_SN_SUFFIX "+FW" + +#endif /* PIOS_USB_BOARD_DATA_H */ diff --git a/flight/targets/boards/ccf3d/firmware/pios_board.c b/flight/targets/boards/ccf3d/firmware/pios_board.c new file mode 100644 index 0000000000..dfc7536a52 --- /dev/null +++ b/flight/targets/boards/ccf3d/firmware/pios_board.c @@ -0,0 +1,343 @@ +/** + ***************************************************************************** + * @file pios_board.c + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015. + * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * PhoenixPilot, http://github.com/PhoenixPilot, Copyright (C) 2012 + * @addtogroup LibrePilotSystem LibrePilot System + * @{ + * @addtogroup LibrePilotCore LibrePilot Core + * @{ + * @brief Defines board specific static initializers for hardware for the CopterControl board. + *****************************************************************************/ +/* + * 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 "inc/openpilot.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef PIOS_INCLUDE_INSTRUMENTATION +#include +#endif + +#include +#include + +/* + * Pull in the board-specific static HW definitions. + * Including .c files is a bit ugly but this allows all of + * the HW definitions to be const and static to limit their + * scope. + * + * NOTE: THIS IS THE ONLY PLACE THAT SHOULD EVER INCLUDE THIS FILE + */ +#include "../board_hw_defs.c" + + +static SystemAlarmsExtendedAlarmStatusOptions CopterControlConfigHook(); +static void ActuatorSettingsUpdatedCb(__attribute__((unused)) UAVObjEvent *ev); + +uintptr_t pios_uavo_settings_fs_id; +uintptr_t pios_user_fs_id = 0; + +/** + * PIOS_Board_Init() + * initializes all the core subsystems on this specific hardware + * called from System/openpilot.c + */ +int32_t init_test; +void PIOS_Board_Init(void) +{ + const struct pios_board_info *bdinfo = &pios_board_info_blob; + +#if defined(PIOS_INCLUDE_LED) + const struct pios_gpio_cfg *led_cfg = PIOS_BOARD_HW_DEFS_GetLedCfg(bdinfo->board_rev); + PIOS_Assert(led_cfg); + PIOS_LED_Init(led_cfg); +#endif /* PIOS_INCLUDE_LED */ + +#ifdef PIOS_INCLUDE_INSTRUMENTATION + PIOS_Instrumentation_Init(PIOS_INSTRUMENTATION_MAX_COUNTERS); +#endif + +#if defined(PIOS_INCLUDE_SPI) + /* Set up the SPI interface to the serial flash */ + if (PIOS_SPI_Init(&pios_spi_flash_accel_id, &pios_spi_flash_accel_cfg_cc3d)) { + PIOS_Assert(0); + } +#endif + + uintptr_t flash_id; + if (PIOS_Flash_Jedec_Init(&flash_id, pios_spi_flash_accel_id, 0)) { + PIOS_DEBUG_Assert(0); + } + if (PIOS_FLASHFS_Logfs_Init(&pios_uavo_settings_fs_id, &flashfs_m25p_cfg, &pios_jedec_flash_driver, flash_id)) { + PIOS_DEBUG_Assert(0); + } + + /* Initialize the task monitor */ + if (PIOS_TASK_MONITOR_Initialize(TASKINFO_RUNNING_NUMELEM)) { + PIOS_Assert(0); + } + + /* Initialize the delayed callback library */ + PIOS_CALLBACKSCHEDULER_Initialize(); + + /* Initialize UAVObject libraries */ + EventDispatcherInitialize(); + UAVObjInitialize(); + +#if defined(PIOS_INCLUDE_RTC) + /* Initialize the real-time clock and its associated tick */ + PIOS_RTC_Init(&pios_rtc_main_cfg); +#endif + PIOS_IAP_Init(); + // check for safe mode commands from gcs + if (PIOS_IAP_ReadBootCmd(0) == PIOS_IAP_CLEAR_FLASH_CMD_0 && + PIOS_IAP_ReadBootCmd(1) == PIOS_IAP_CLEAR_FLASH_CMD_1 && + PIOS_IAP_ReadBootCmd(2) == PIOS_IAP_CLEAR_FLASH_CMD_2) { + PIOS_FLASHFS_Format(pios_uavo_settings_fs_id); + PIOS_IAP_WriteBootCmd(0, 0); + PIOS_IAP_WriteBootCmd(1, 0); + PIOS_IAP_WriteBootCmd(2, 0); + } + + HwSettingsInitialize(); + +#ifndef ERASE_FLASH +#ifdef PIOS_INCLUDE_WDG + /* Initialize watchdog as early as possible to catch faults during init */ + PIOS_WDG_Init(); +#endif +#endif + + /* Initialize the alarms library */ + AlarmsInitialize(); + + /* Check for repeated boot failures */ + uint16_t boot_count = PIOS_IAP_ReadBootCount(); + if (boot_count < 3) { + PIOS_IAP_WriteBootCount(++boot_count); + AlarmsClear(SYSTEMALARMS_ALARM_BOOTFAULT); + } else { + /* Too many failed boot attempts, force hwsettings to defaults */ + HwSettingsSetDefaults(HwSettingsHandle(), 0); + AlarmsSet(SYSTEMALARMS_ALARM_BOOTFAULT, SYSTEMALARMS_ALARM_CRITICAL); + } + + /* Set up pulse timers */ + PIOS_TIM_InitClock(&tim_1_cfg); + PIOS_TIM_InitClock(&tim_2_cfg); + PIOS_TIM_InitClock(&tim_3_cfg); + PIOS_TIM_InitClock(&tim_4_cfg); + +#if defined(PIOS_INCLUDE_USB) + PIOS_BOARD_IO_Configure_USB(); +#endif + + /* Configure the main IO port */ + static const PIOS_BOARD_IO_UART_Function usart_main_function_map[] = { + [HWSETTINGS_CC_MAINPORT_TELEMETRY] = PIOS_BOARD_IO_UART_TELEMETRY, + [HWSETTINGS_CC_MAINPORT_GPS] = PIOS_BOARD_IO_UART_GPS, + [HWSETTINGS_CC_MAINPORT_SBUS] = PIOS_BOARD_IO_UART_SBUS, + [HWSETTINGS_CC_MAINPORT_DSM] = PIOS_BOARD_IO_UART_DSM_MAIN, + [HWSETTINGS_CC_MAINPORT_DEBUGCONSOLE] = PIOS_BOARD_IO_UART_DEBUGCONSOLE, + [HWSETTINGS_CC_MAINPORT_COMBRIDGE] = PIOS_BOARD_IO_UART_COMBRIDGE, + [HWSETTINGS_CC_MAINPORT_OSDHK] = PIOS_BOARD_IO_UART_OSDHK, + [HWSETTINGS_CC_MAINPORT_MSP] = PIOS_BOARD_IO_UART_MSP, + [HWSETTINGS_CC_MAINPORT_MAVLINK] = PIOS_BOARD_IO_UART_MAVLINK, + }; + + uint8_t hwsettings_cc_mainport; + HwSettingsCC_MainPortGet(&hwsettings_cc_mainport); + + if(hwsettings_cc_mainport < NELEMENTS(usart_main_function_map)) { + PIOS_BOARD_IO_Configure_UART(&pios_usart_main_cfg, usart_main_function_map[hwsettings_cc_mainport]); + } + + + /* Configure the flexi port */ + static const PIOS_BOARD_IO_UART_Function usart_flexi_function_map[] = { + [HWSETTINGS_CC_FLEXIPORT_TELEMETRY] = PIOS_BOARD_IO_UART_TELEMETRY, + [HWSETTINGS_CC_FLEXIPORT_GPS] = PIOS_BOARD_IO_UART_GPS, + [HWSETTINGS_CC_FLEXIPORT_DSM] = PIOS_BOARD_IO_UART_DSM_FLEXI, + [HWSETTINGS_CC_FLEXIPORT_EXBUS] = PIOS_BOARD_IO_UART_EXBUS, + [HWSETTINGS_CC_FLEXIPORT_HOTTSUMD] = PIOS_BOARD_IO_UART_HOTT_SUMD, + [HWSETTINGS_CC_FLEXIPORT_HOTTSUMH] = PIOS_BOARD_IO_UART_HOTT_SUMH, + [HWSETTINGS_CC_FLEXIPORT_SRXL] = PIOS_BOARD_IO_UART_SRXL, + [HWSETTINGS_CC_FLEXIPORT_IBUS] = PIOS_BOARD_IO_UART_IBUS, + [HWSETTINGS_CC_FLEXIPORT_DEBUGCONSOLE] = PIOS_BOARD_IO_UART_DEBUGCONSOLE, + [HWSETTINGS_CC_FLEXIPORT_COMBRIDGE] = PIOS_BOARD_IO_UART_COMBRIDGE, + [HWSETTINGS_CC_FLEXIPORT_OSDHK] = PIOS_BOARD_IO_UART_OSDHK, + [HWSETTINGS_CC_FLEXIPORT_MSP] = PIOS_BOARD_IO_UART_MSP, + [HWSETTINGS_CC_FLEXIPORT_MAVLINK] = PIOS_BOARD_IO_UART_MAVLINK, + }; + + uint8_t hwsettings_cc_flexiport; + HwSettingsCC_FlexiPortGet(&hwsettings_cc_flexiport); + + if(hwsettings_cc_flexiport < NELEMENTS(usart_flexi_function_map)) { + PIOS_BOARD_IO_Configure_UART(&pios_usart_flexi_cfg, usart_flexi_function_map[hwsettings_cc_flexiport]); + } + + if(hwsettings_cc_flexiport == HWSETTINGS_CC_FLEXIPORT_PPM) { +#if defined(PIOS_INCLUDE_PPM_FLEXI) + PIOS_BOARD_IO_Configure_PPM_RCVR(&pios_ppm_flexi_cfg); +#endif /* PIOS_INCLUDE_PPM_FLEXI */ + } else if(hwsettings_cc_flexiport == HWSETTINGS_CC_FLEXIPORT_I2C) { + // F303CC has no I2C on CC3D flexi. + } + + /* Configure the rcvr port */ + uint8_t hwsettings_rcvrport; + HwSettingsCC_RcvrPortGet(&hwsettings_rcvrport); + + switch ((HwSettingsCC_RcvrPortOptions)hwsettings_rcvrport) { + case HWSETTINGS_CC_RCVRPORT_DISABLEDONESHOT: +#if defined(PIOS_INCLUDE_HCSR04) + { + uint32_t pios_hcsr04_id; + PIOS_HCSR04_Init(&pios_hcsr04_id, &pios_hcsr04_cfg); + } +#endif + break; + case HWSETTINGS_CC_RCVRPORT_PWMNOONESHOT: +#if defined(PIOS_INCLUDE_PWM) + PIOS_BOARD_IO_Configure_PWM_RCVR(&pios_pwm_cfg); +#endif /* PIOS_INCLUDE_PWM */ + break; + case HWSETTINGS_CC_RCVRPORT_PPM_PIN8ONESHOT: +#if defined(PIOS_INCLUDE_PPM) + PIOS_BOARD_IO_Configure_PPM_RCVR(&pios_ppm_pin8_cfg); +#endif /* PIOS_INCLUDE_PPM */ + break; + case HWSETTINGS_CC_RCVRPORT_PPMNOONESHOT: + case HWSETTINGS_CC_RCVRPORT_PPMOUTPUTSNOONESHOT: +#if defined(PIOS_INCLUDE_PPM) + PIOS_BOARD_IO_Configure_PPM_RCVR(&pios_ppm_cfg); +#endif /* PIOS_INCLUDE_PPM */ + break; + case HWSETTINGS_CC_RCVRPORT_PPMPWMNOONESHOT: + /* This is a combination of PPM and PWM inputs */ +#if defined(PIOS_INCLUDE_PPM) + PIOS_BOARD_IO_Configure_PPM_RCVR(&pios_ppm_cfg); +#endif /* PIOS_INCLUDE_PPM */ +#if defined(PIOS_INCLUDE_PWM) + PIOS_BOARD_IO_Configure_PWM_RCVR(&pios_pwm_with_ppm_cfg); +#endif /* PIOS_INCLUDE_PWM */ + break; + case HWSETTINGS_CC_RCVRPORT_OUTPUTSONESHOT: + break; + } + + + +#if defined(PIOS_INCLUDE_GCSRCVR) + PIOS_BOARD_IO_Configure_GCSRCVR(); +#endif /* PIOS_INCLUDE_GCSRCVR */ + +#ifndef PIOS_ENABLE_DEBUG_PINS + switch ((HwSettingsCC_RcvrPortOptions)hwsettings_rcvrport) { + case HWSETTINGS_CC_RCVRPORT_DISABLEDONESHOT: + case HWSETTINGS_CC_RCVRPORT_PWMNOONESHOT: + case HWSETTINGS_CC_RCVRPORT_PPMNOONESHOT: + case HWSETTINGS_CC_RCVRPORT_PPMPWMNOONESHOT: + case HWSETTINGS_CC_RCVRPORT_PPM_PIN8ONESHOT: + PIOS_Servo_Init(&pios_servo_cfg); + break; + case HWSETTINGS_CC_RCVRPORT_PPMOUTPUTSNOONESHOT: + case HWSETTINGS_CC_RCVRPORT_OUTPUTSONESHOT: + PIOS_Servo_Init(&pios_servo_rcvr_cfg); + break; + } +#else + PIOS_DEBUG_Init(pios_tim_servoport_all_pins, NELEMENTS(pios_tim_servoport_all_pins)); +#endif /* PIOS_ENABLE_DEBUG_PINS */ + + PIOS_BOARD_Sensors_Configure(); + + /* Make sure we have at least one telemetry link configured or else fail initialization */ + PIOS_Assert(pios_com_telem_rf_id || pios_com_telem_usb_id); + + // Attach the board config check hook + SANITYCHECK_AttachHook(&CopterControlConfigHook); + // trigger a config check if actuatorsettings are updated + ActuatorSettingsInitialize(); + ActuatorSettingsConnectCallback(ActuatorSettingsUpdatedCb); +} + +SystemAlarmsExtendedAlarmStatusOptions CopterControlConfigHook() +{ + // inhibit usage of oneshot for non supported RECEIVER port modes + uint8_t recmode; + + HwSettingsCC_RcvrPortGet(&recmode); + uint8_t flexiMode; + uint8_t modes[ACTUATORSETTINGS_BANKMODE_NUMELEM]; + ActuatorSettingsBankModeGet(modes); + HwSettingsCC_FlexiPortGet(&flexiMode); + + switch ((HwSettingsCC_RcvrPortOptions)recmode) { + // Those modes allows oneshot usage + case HWSETTINGS_CC_RCVRPORT_DISABLEDONESHOT: + case HWSETTINGS_CC_RCVRPORT_OUTPUTSONESHOT: + case HWSETTINGS_CC_RCVRPORT_PPM_PIN8ONESHOT: + if ((recmode == HWSETTINGS_CC_RCVRPORT_PPM_PIN8ONESHOT || + flexiMode == HWSETTINGS_CC_FLEXIPORT_PPM) && + (modes[3] == ACTUATORSETTINGS_BANKMODE_PWMSYNC || + modes[3] == ACTUATORSETTINGS_BANKMODE_ONESHOT125 || + modes[3] == ACTUATORSETTINGS_BANKMODE_ONESHOT42 || + modes[3] == ACTUATORSETTINGS_BANKMODE_MULTISHOT)) { + return SYSTEMALARMS_EXTENDEDALARMSTATUS_UNSUPPORTEDCONFIG_ONESHOT; + } else { + return SYSTEMALARMS_EXTENDEDALARMSTATUS_NONE; + } + + // inhibit oneshot for the following modes + case HWSETTINGS_CC_RCVRPORT_PPMNOONESHOT: + case HWSETTINGS_CC_RCVRPORT_PPMOUTPUTSNOONESHOT: + case HWSETTINGS_CC_RCVRPORT_PPMPWMNOONESHOT: + case HWSETTINGS_CC_RCVRPORT_PWMNOONESHOT: + for (uint8_t i = 0; i < ACTUATORSETTINGS_BANKMODE_NUMELEM; i++) { + if (modes[i] == ACTUATORSETTINGS_BANKMODE_PWMSYNC || + modes[i] == ACTUATORSETTINGS_BANKMODE_ONESHOT125 || + modes[i] == ACTUATORSETTINGS_BANKMODE_ONESHOT42 || + modes[i] == ACTUATORSETTINGS_BANKMODE_MULTISHOT) { + return SYSTEMALARMS_EXTENDEDALARMSTATUS_UNSUPPORTEDCONFIG_ONESHOT;; + } + + return SYSTEMALARMS_EXTENDEDALARMSTATUS_NONE; + } + } + return SYSTEMALARMS_EXTENDEDALARMSTATUS_UNSUPPORTEDCONFIG_ONESHOT;; +} +// trigger a configuration check if ActuatorSettings are changed. +void ActuatorSettingsUpdatedCb(__attribute__((unused)) UAVObjEvent *ev) +{ + configuration_check(); +} + +/** + * @} + */ diff --git a/flight/targets/boards/ccf3d/firmware/pios_board_posix.c b/flight/targets/boards/ccf3d/firmware/pios_board_posix.c new file mode 100644 index 0000000000..7fa958a38e --- /dev/null +++ b/flight/targets/boards/ccf3d/firmware/pios_board_posix.c @@ -0,0 +1,145 @@ +/** + ****************************************************************************** + * + * @file pios_board.c + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief Defines board specific static initializers for hardware for the OpenPilot board. + * @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 "inc/openpilot.h" +#include +#include +#include + +/** + * PIOS_Board_Init() + * initializes all the core systems on this specific hardware + * called from System/openpilot.c + */ +void PIOS_Board_Init(void) +{ + /* Delay system */ + PIOS_DELAY_Init(); + + /* Initialize the delayed callback library */ + PIOS_CALLBACKSCHEDULER_Initialize(); + + /* Initialize UAVObject libraries */ + EventDispatcherInitialize(); + UAVObjInitialize(); + + /* Initialize the alarms library */ + AlarmsInitialize(); + + /* Initialize the task monitor */ + if (PIOS_TASK_MONITOR_Initialize(TASKINFO_RUNNING_NUMELEM)) { + PIOS_Assert(0); + } + + /* Initialize the PiOS library */ + PIOS_COM_Init(); +} + + +const struct pios_udp_cfg pios_udp0_cfg = { + .ip = "0.0.0.0", + .port = 9000, +}; +const struct pios_udp_cfg pios_udp1_cfg = { + .ip = "0.0.0.0", + .port = 9001, +}; +const struct pios_udp_cfg pios_udp2_cfg = { + .ip = "0.0.0.0", + .port = 9002, +}; + +#ifdef PIOS_COM_AUX +/* + * AUX USART + */ +const struct pios_udp_cfg pios_udp3_cfg = { + .ip = "0.0.0.0", + .port = 9003, +}; +#endif + +/* + * Board specific number of devices. + */ +struct pios_udp_dev pios_udp_devs[] = { +#define PIOS_UDP_TELEM 0 + { + .cfg = &pios_udp0_cfg, + }, +#define PIOS_UDP_GPS 1 + { + .cfg = &pios_udp1_cfg, + }, +#define PIOS_UDP_LOCAL 2 + { + .cfg = &pios_udp2_cfg, + }, +#ifdef PIOS_COM_AUX +#define PIOS_UDP_AUX 3 + { + .cfg = &pios_udp3_cfg, + }, +#endif +}; + +uint8_t pios_udp_num_devices = NELEMENTS(pios_udp_devs); + +/* + * COM devices + */ + +/* + * Board specific number of devices. + */ +extern const struct pios_com_driver pios_serial_com_driver; +extern const struct pios_com_driver pios_udp_com_driver; + +struct pios_com_dev pios_com_devs[] = { + { + .id = PIOS_UDP_TELEM, + .driver = &pios_udp_com_driver, + }, + { + .id = PIOS_UDP_GPS, + .driver = &pios_udp_com_driver, + }, + { + .id = PIOS_UDP_LOCAL, + .driver = &pios_udp_com_driver, + }, +#ifdef PIOS_COM_AUX + { + .id = PIOS_UDP_AUX, + .driver = &pios_udp_com_driver, + }, +#endif +}; + +const uint8_t pios_com_num_devices = NELEMENTS(pios_com_devs); + +/** + * @} + */ diff --git a/flight/targets/boards/ccf3d/pios_board.h b/flight/targets/boards/ccf3d/pios_board.h new file mode 100644 index 0000000000..75b29db177 --- /dev/null +++ b/flight/targets/boards/ccf3d/pios_board.h @@ -0,0 +1,312 @@ +/** + ****************************************************************************** + * + * @file pios_board.h + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015. + * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * + * @brief Defines board hardware for the OpenPilot Version 1.1 hardware. + * @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_BOARD_H +#define PIOS_BOARD_H +// ------------------------ +// Timers and Channels Used +// ------------------------ +/* + Timer | Channel 1 | Channel 2 | Channel 3 | Channel 4 + ------+-----------+-----------+-----------+---------- + TIM1 | Servo 4 | | | + TIM2 | RC In 5 | RC In 6 | Servo 6 | + TIM3 | Servo 5 | RC In 2 | RC In 3 | RC In 4 + TIM4 | RC In 1 | Servo 3 | Servo 2 | Servo 1 + ------+-----------+-----------+-----------+---------- + */ + +// ------------------------ +// DMA Channels Used +// ------------------------ +/* Channel 1 - */ +/* Channel 2 - */ +/* Channel 3 - */ +/* Channel 4 - */ +/* Channel 5 - */ +/* Channel 6 - */ +/* Channel 7 - */ +/* Channel 8 - */ +/* Channel 9 - */ +/* Channel 10 - */ +/* Channel 11 - */ +/* Channel 12 - */ + +// ------------------------ +// BOOTLOADER_SETTINGS +// ------------------------ +#define BOARD_READABLE true +#define BOARD_WRITABLE true +#define MAX_DEL_RETRYS 3 + +// ------------------------ +// WATCHDOG_SETTINGS +// ------------------------ +#define PIOS_WATCHDOG_TIMEOUT 250 +#define PIOS_WDG_REGISTER RTC_BKP_DR4 +#define PIOS_WDG_ACTUATOR 0x0001 +#define PIOS_WDG_STABILIZATION 0x0002 +#define PIOS_WDG_ATTITUDE 0x0004 +#define PIOS_WDG_MANUAL 0x0008 +#define PIOS_WDG_AUTOTUNE 0x0010 +#define PIOS_WDG_SENSORS 0x0020 + + +// ------------------------ +// TELEMETRY +// ------------------------ +#define TELEM_QUEUE_SIZE 10 + +// ------------------------ +// PIOS_LED +// ------------------------ +#define PIOS_LED_HEARTBEAT 0 + +// ------------------------- +// System Settings +// ------------------------- +#define PIOS_MASTER_CLOCK 72000000 +#define PIOS_PERIPHERAL_CLOCK (PIOS_MASTER_CLOCK / 2) + +// ------------------------- +// Interrupt Priorities +// ------------------------- +#define PIOS_IRQ_PRIO_LOW 12 // lower than RTOS +#define PIOS_IRQ_PRIO_MID 8 // higher than RTOS +#define PIOS_IRQ_PRIO_HIGH 5 // for SPI, ADC, I2C etc... +#define PIOS_IRQ_PRIO_HIGHEST 4 // for USART etc... +// ------------------------ +// PIOS_I2C +// See also pios_board.c +// ------------------------ +#define PIOS_I2C_MAX_DEVS 1 +#define PIOS_I2C_EXTERNAL_ADAPTER (0) +#define PIOS_I2C_FLEXI_ADAPTER (0) + +// ------------------------ +// PIOS_BMP085 +// ------------------------ +#define PIOS_BMP085_OVERSAMPLING 3 + +// ------------------------- +// SPI +// +// See also pios_board.c +// ------------------------- +#define PIOS_SPI_MAX_DEVS 2 +extern uint32_t pios_spi_gyro_id; +#define PIOS_SPI_MPU6000_ADAPTER (pios_spi_gyro_id) +// ------------------------- +// PIOS_USART +// ------------------------- +#define PIOS_USART_MAX_DEVS 2 + +// ------------------------- +// PIOS_COM +// +// See also pios_board.c +// ------------------------- +#define PIOS_COM_MAX_DEVS 3 + +extern uint32_t pios_com_telem_rf_id; +#define PIOS_COM_TELEM_RF (pios_com_telem_rf_id) + +#if defined(PIOS_INCLUDE_GPS) +extern uint32_t pios_com_gps_id; +#define PIOS_COM_GPS (pios_com_gps_id) +#endif /* PIOS_INCLUDE_GPS */ + +extern uint32_t pios_com_bridge_id; +#define PIOS_COM_BRIDGE (pios_com_bridge_id) + +extern uint32_t pios_com_vcp_id; +#define PIOS_COM_VCP (pios_com_vcp_id) + +extern uint32_t pios_com_telem_usb_id; +#define PIOS_COM_TELEM_USB (pios_com_telem_usb_id) + +#if defined(PIOS_INCLUDE_DEBUG_CONSOLE) +extern uint32_t pios_com_debug_id; +#define PIOS_COM_DEBUG (pios_com_debug_id) +#endif /* PIOS_INCLUDE_DEBUG_CONSOLE */ + +extern uint32_t pios_com_hkosd_id; +#define PIOS_COM_OSDHK (pios_com_hkosd_id) + +extern uint32_t pios_com_msp_id; +#define PIOS_COM_MSP (pios_com_msp_id) + +extern uint32_t pios_com_mavlink_id; +#define PIOS_COM_MAVLINK (pios_com_mavlink_id) + +// ------------------------- +// ADC +// PIOS_ADC_PinGet(0) = Gyro Z +// PIOS_ADC_PinGet(1) = Gyro Y +// PIOS_ADC_PinGet(2) = Gyro X +// ------------------------- +// #define PIOS_ADC_OVERSAMPLING_RATE 1 +#define PIOS_ADC_USE_TEMP_SENSOR 1 +#define PIOS_ADC_TEMP_SENSOR_ADC ADC1 +#define PIOS_ADC_TEMP_SENSOR_ADC_CHANNEL 1 + +#define PIOS_ADC_PIN1_GPIO_PORT GPIOA // PA4 (Gyro X) +#define PIOS_ADC_PIN1_GPIO_PIN GPIO_Pin_4 // ADC12_IN4 +#define PIOS_ADC_PIN1_GPIO_CHANNEL ADC_Channel_4 +#define PIOS_ADC_PIN1_ADC ADC2 +#define PIOS_ADC_PIN1_ADC_NUMBER 1 + +#define PIOS_ADC_PIN2_GPIO_PORT GPIOA // PA5 (Gyro Y) +#define PIOS_ADC_PIN2_GPIO_PIN GPIO_Pin_5 // ADC123_IN5 +#define PIOS_ADC_PIN2_GPIO_CHANNEL ADC_Channel_5 +#define PIOS_ADC_PIN2_ADC ADC1 +#define PIOS_ADC_PIN2_ADC_NUMBER 2 + +#define PIOS_ADC_PIN3_GPIO_PORT GPIOA // PA3 (Gyro Z) +#define PIOS_ADC_PIN3_GPIO_PIN GPIO_Pin_3 // ADC12_IN3 +#define PIOS_ADC_PIN3_GPIO_CHANNEL ADC_Channel_3 +#define PIOS_ADC_PIN3_ADC ADC2 +#define PIOS_ADC_PIN3_ADC_NUMBER 2 + +#define PIOS_ADC_NUM_PINS 3 + +#define PIOS_ADC_PORTS { PIOS_ADC_PIN1_GPIO_PORT, PIOS_ADC_PIN2_GPIO_PORT, PIOS_ADC_PIN3_GPIO_PORT } +#define PIOS_ADC_PINS { PIOS_ADC_PIN1_GPIO_PIN, PIOS_ADC_PIN2_GPIO_PIN, PIOS_ADC_PIN3_GPIO_PIN } +#define PIOS_ADC_CHANNELS { PIOS_ADC_PIN1_GPIO_CHANNEL, PIOS_ADC_PIN2_GPIO_CHANNEL, PIOS_ADC_PIN3_GPIO_CHANNEL } +#define PIOS_ADC_MAPPING { PIOS_ADC_PIN1_ADC, PIOS_ADC_PIN2_ADC, PIOS_ADC_PIN3_ADC } +#define PIOS_ADC_CHANNEL_MAPPING { PIOS_ADC_PIN1_ADC_NUMBER, PIOS_ADC_PIN2_ADC_NUMBER, PIOS_ADC_PIN3_ADC_NUMBER } +#define PIOS_ADC_NUM_CHANNELS (PIOS_ADC_NUM_PINS + PIOS_ADC_USE_TEMP_SENSOR) +#define PIOS_ADC_NUM_ADC_CHANNELS 2 +#define PIOS_ADC_USE_ADC2 1 +#define PIOS_ADC_CLOCK_FUNCTION RCC_AHBPeriphClockCmd(RCC_AHBPeriph_ADC12, ENABLE) +#define PIOS_ADC_ADCCLK RCC_ADC12PLLCLK_Div32 +/* RCC_PCLK2_Div2: ADC clock = PCLK2/2 */ +/* RCC_PCLK2_Div4: ADC clock = PCLK2/4 */ +/* RCC_PCLK2_Div6: ADC clock = PCLK2/6 */ +/* RCC_PCLK2_Div8: ADC clock = PCLK2/8 */ +#define PIOS_ADC_SAMPLE_TIME ADC_SampleTime_181Cycles5 +/* Sample time: */ +/* With an ADCCLK = 14 MHz and a sampling time of 239.5 cycles: */ +/* Tconv = 239.5 + 12.5 = 252 cycles = 18�s */ +/* (1 / (ADCCLK / CYCLES)) = Sample Time (�S) */ +#define PIOS_ADC_IRQ_PRIO PIOS_IRQ_PRIO_LOW + +// Currently analog acquistion hard coded at 480 Hz +// PCKL2 = HCLK / 16 +// ADCCLK = PCLK2 / 2 +#define PIOS_ADC_RATE (72.0e6f / 1.0f / 8.0f / 252.0f / (PIOS_ADC_NUM_CHANNELS >> PIOS_ADC_USE_ADC2)) +#define PIOS_ADC_MAX_OVERSAMPLING 48 + +#define PIOS_ADC_TEMPERATURE_PIN 0 + +// ------------------------ +// PIOS_RCVR +// See also pios_board.c +// ------------------------ +#define PIOS_RCVR_MAX_DEVS 3 +#define PIOS_RCVR_MAX_CHANNELS 12 +#define PIOS_GCSRCVR_TIMEOUT_MS 100 + +// ------------------------- +// Receiver PPM input +// ------------------------- +#define PIOS_PPM_MAX_DEVS 1 +#define PIOS_PPM_NUM_INPUTS 16 + +// ------------------------- +// Receiver PWM input +// ------------------------- +#define PIOS_PWM_MAX_DEVS 1 +#define PIOS_PWM_NUM_INPUTS 6 + +// ------------------------- +// Receiver DSM input +// ------------------------- +#define PIOS_DSM_MAX_DEVS 2 +#define PIOS_DSM_NUM_INPUTS 12 + +// ------------------------- +// Receiver S.Bus input +// ------------------------- +#define PIOS_SBUS_MAX_DEVS 1 +#define PIOS_SBUS_NUM_INPUTS (16 + 2) + +// ------------------------- +// Receiver HOTT input +// ------------------------- +#define PIOS_HOTT_MAX_DEVS 1 +#define PIOS_HOTT_NUM_INPUTS 32 + +// ------------------------- +// Receiver EX.Bus input +// ------------------------- +#define PIOS_EXBUS_MAX_DEVS 1 +#define PIOS_EXBUS_NUM_INPUTS 16 + +// ------------------------- +// Receiver Multiplex SRXL input +// ------------------------- +#define PIOS_SRXL_MAX_DEVS 1 +#define PIOS_SRXL_NUM_INPUTS 16 + +// ------------------------- +// Receiver FlySky IBus input +// ------------------------- +#define PIOS_IBUS_MAX_DEVS 1 +#define PIOS_IBUS_NUM_INPUTS 10 + +// ------------------------- +// Servo outputs +// ------------------------- +#define PIOS_SERVO_UPDATE_HZ 50 +#define PIOS_SERVOS_INITIAL_POSITION 0 /* dont want to start motors, have no pulse till settings loaded */ +#define PIOS_SERVO_BANKS 6 + +// -------------------------- +// Timer controller settings +// -------------------------- +#define PIOS_TIM_MAX_DEVS 3 + +// ------------------------- +// GPIO +// ------------------------- +#define PIOS_GPIO_PORTS {} +#define PIOS_GPIO_PINS {} +#define PIOS_GPIO_CLKS {} +#define PIOS_GPIO_NUM 0 + +// ------------------------- +// USB +// ------------------------- +#define PIOS_USB_HID_MAX_DEVS 1 + +#define PIOS_USB_ENABLED 1 +#define PIOS_USB_DETECT_GPIO_PORT GPIOC +#define PIOS_USB_MAX_DEVS 1 +#define PIOS_USB_DETECT_GPIO_PIN GPIO_Pin_15 + +#endif /* PIOS_BOARD_H */ diff --git a/flight/targets/boards/ccf3d/pios_usb_board_data.c b/flight/targets/boards/ccf3d/pios_usb_board_data.c new file mode 100644 index 0000000000..20c49fdcfb --- /dev/null +++ b/flight/targets/boards/ccf3d/pios_usb_board_data.c @@ -0,0 +1,102 @@ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_USB_BOARD Board specific USB definitions + * @brief Board specific USB definitions + * @{ + * + * @file pios_usb_board_data.c + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief Board specific USB 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 + */ + +#include "inc/pios_usb_board_data.h" /* struct usb_*, USB_* */ +#include /* PIOS_SYS_SerialNumberGet */ +#include /* PIOS_USBHOOK_* */ +#include /* PIOS_USB_UTIL_AsciiToUtf8 */ + +static const uint8_t usb_product_id[28] = { + sizeof(usb_product_id), + USB_DESC_TYPE_STRING, + 'C', 0, + 'o', 0, + 'p', 0, + 't', 0, + 'e', 0, + 'r', 0, + 'C', 0, + 'o', 0, + 'n', 0, + 't', 0, + 'r', 0, + 'o', 0, + 'l', 0, +}; + +static uint8_t usb_serial_number[2 + PIOS_SYS_SERIAL_NUM_ASCII_LEN * 2 + (sizeof(PIOS_USB_BOARD_SN_SUFFIX) - 1) * 2] = { + sizeof(usb_serial_number), + USB_DESC_TYPE_STRING, +}; + +static const struct usb_string_langid usb_lang_id = { + .bLength = sizeof(usb_lang_id), + .bDescriptorType = USB_DESC_TYPE_STRING, + .bLangID = htousbs(USB_LANGID_ENGLISH_US), +}; + +static const uint8_t usb_vendor_id[28] = { + sizeof(usb_vendor_id), + USB_DESC_TYPE_STRING, + 'o', 0, + 'p', 0, + 'e', 0, + 'n', 0, + 'p', 0, + 'i', 0, + 'l', 0, + 'o', 0, + 't', 0, + '.', 0, + 'o', 0, + 'r', 0, + 'g', 0 +}; + +int32_t PIOS_USB_BOARD_DATA_Init(void) +{ + /* Load device serial number into serial number string */ + uint8_t sn[PIOS_SYS_SERIAL_NUM_ASCII_LEN + 1]; + + PIOS_SYS_SerialNumberGet((char *)sn); + + /* Concatenate the device serial number and the appropriate suffix ("+BL" or "+FW") into the USB serial number */ + uint8_t *utf8 = &(usb_serial_number[2]); + utf8 = PIOS_USB_UTIL_AsciiToUtf8(utf8, sn, PIOS_SYS_SERIAL_NUM_ASCII_LEN); + utf8 = PIOS_USB_UTIL_AsciiToUtf8(utf8, (uint8_t *)PIOS_USB_BOARD_SN_SUFFIX, sizeof(PIOS_USB_BOARD_SN_SUFFIX) - 1); + + PIOS_USBHOOK_RegisterString(USB_STRING_DESC_PRODUCT, (uint8_t *)&usb_product_id, sizeof(usb_product_id)); + PIOS_USBHOOK_RegisterString(USB_STRING_DESC_SERIAL, (uint8_t *)&usb_serial_number, sizeof(usb_serial_number)); + + PIOS_USBHOOK_RegisterString(USB_STRING_DESC_LANG, (uint8_t *)&usb_lang_id, sizeof(usb_lang_id)); + PIOS_USBHOOK_RegisterString(USB_STRING_DESC_VENDOR, (uint8_t *)&usb_vendor_id, sizeof(usb_vendor_id)); + + return 0; +} diff --git a/flight/targets/boards/revoproto/pios_board.h b/flight/targets/boards/revoproto/pios_board.h index 71a562dbf7..3e778e780f 100644 --- a/flight/targets/boards/revoproto/pios_board.h +++ b/flight/targets/boards/revoproto/pios_board.h @@ -136,26 +136,6 @@ extern uint32_t pios_i2c_flexiport_adapter_id; // See also pios_board.c // ------------------------- #define PIOS_COM_MAX_DEVS 4 -// extern uint32_t pios_com_telem_rf_id; -// extern uint32_t pios_com_gps_id; -// extern uint32_t pios_com_aux_id; -// extern uint32_t pios_com_telem_usb_id; -// extern uint32_t pios_com_bridge_id; -// extern uint32_t pios_com_vcp_id; -// extern uint32_t pios_com_hkosd_id; -// extern uint32_t pios_com_msp_id; -// extern uint32_t pios_com_mavlink_id; -// -// #define PIOS_COM_AUX (pios_com_aux_id) -// #define PIOS_COM_GPS (pios_com_gps_id) -// #define PIOS_COM_TELEM_USB (pios_com_telem_usb_id) -// #define PIOS_COM_TELEM_RF (pios_com_telem_rf_id) -// #define PIOS_COM_BRIDGE (pios_com_bridge_id) -// #define PIOS_COM_VCP (pios_com_vcp_id) -// #define PIOS_COM_DEBUG PIOS_COM_AUX -// #define PIOS_COM_OSDHK (pios_com_hkosd_id) -// #define PIOS_COM_MSP (pios_com_msp_id) -// #define PIOS_COM_MAVLINK (pios_com_mavlink_id) // ------------------------ // TELEMETRY diff --git a/flight/targets/boards/spracingf3/board-info.mk b/flight/targets/boards/spracingf3/board-info.mk new file mode 100644 index 0000000000..b64fd5e527 --- /dev/null +++ b/flight/targets/boards/spracingf3/board-info.mk @@ -0,0 +1,24 @@ +BOARD_TYPE := 0x10 +BOARD_REVISION := 0x01 +BOOTLOADER_VERSION := 0x00 +HW_TYPE := 0x01 + +MCU := cortex-m4 +PIOS_DEVLIB := $(PIOS)/stm32f30x +CHIP := STM32F303xC +BOARD := STM32F303CCT_SRF3_Rev1 +MODEL := HD + +OPENOCD_JTAG_CONFIG := jlink.cfg +OPENOCD_CONFIG := stm32f3x.cfg + +# Note: These must match the values in link_$(BOARD)_memory.ld +BL_BANK_BASE := 0x08000000 # Start of bootloader flash +BL_BANK_SIZE := 0x00004000 # Should include BD_INFO region + +FW_BANK_BASE := 0x08004000 # Start of firmware flash +FW_BANK_SIZE := 0x0003C000 # Should include FW_DESC_SIZE + +FW_DESC_SIZE := 0x00000064 + +OSCILLATOR_FREQ := 8000000 diff --git a/flight/targets/boards/spracingf3/board_hw_defs.c b/flight/targets/boards/spracingf3/board_hw_defs.c new file mode 100644 index 0000000000..5d633f5a71 --- /dev/null +++ b/flight/targets/boards/spracingf3/board_hw_defs.c @@ -0,0 +1,832 @@ +/** + ****************************************************************************** + * @file board_hw_defs.c + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015. + * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012. + * PhoenixPilot, http://github.com/PhoenixPilot, Copyright (C) 2012 + * + * @addtogroup OpenPilotSystem OpenPilot System + * @{ + * @addtogroup OpenPilotCore OpenPilot Core + * @{ + * @brief Defines board specific static initializers for hardware for the CopterControl board. + *****************************************************************************/ +/* + * 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 + */ + +#if defined(PIOS_INCLUDE_LED) + +#include + + +static const struct pios_gpio pios_leds[] = { + [PIOS_LED_HEARTBEAT] = { + .pin = { + .gpio = GPIOB, + .init = { + .GPIO_Pin = GPIO_Pin_3, + .GPIO_Mode = GPIO_Mode_OUT, + .GPIO_OType = GPIO_OType_PP, + .GPIO_Speed = GPIO_Speed_50MHz, + .GPIO_PuPd = GPIO_PuPd_NOPULL, + }, + }, +// .remap = GPIO_Remap_SWJ_JTAGDisable, + .active_low = false + }, +}; + +static const struct pios_gpio_cfg pios_led_cfg = { + .gpios = pios_leds, + .num_gpios = NELEMENTS(pios_leds), +}; + +const struct pios_gpio_cfg *PIOS_BOARD_HW_DEFS_GetLedCfg(__attribute__((unused)) uint32_t board_revision) +{ + return &pios_led_cfg; +} + +#endif /* PIOS_INCLUDE_LED */ + +#if defined(PIOS_INCLUDE_HMC5X83) +#include "pios_hmc5x83.h" + +#ifdef PIOS_HMC5X83_HAS_GPIOS +bool pios_board_internal_mag_handler() +{ + return PIOS_HMC5x83_IRQHandler(onboard_mag); +} + +static const struct pios_exti_cfg pios_exti_hmc5x83_cfg = { + .vector = pios_board_internal_mag_handler, + .line = EXTI_Line14, + .pin = { + .gpio = GPIOC, + .init = { + .GPIO_Pin = GPIO_Pin_14, + .GPIO_Speed = GPIO_Speed_100MHz, + .GPIO_Mode = GPIO_Mode_IN, + .GPIO_OType = GPIO_OType_OD, + .GPIO_PuPd = GPIO_PuPd_NOPULL, + }, + }, + .irq = { + .init = { + .NVIC_IRQChannel = EXTI15_10_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_LOW, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, + .exti = { + .init = { + .EXTI_Line = EXTI_Line14, // matches above GPIO pin + .EXTI_Mode = EXTI_Mode_Interrupt, + .EXTI_Trigger = EXTI_Trigger_Rising, + .EXTI_LineCmd = ENABLE, + }, + }, +}; +#endif /* PIOS_HMC5X83_HAS_GPIOS */ + +static const struct pios_hmc5x83_cfg pios_hmc5x83_internal_cfg = { +#ifdef PIOS_HMC5X83_HAS_GPIOS + .exti_cfg = &pios_exti_hmc5x83_cfg, +#endif + .M_ODR = PIOS_HMC5x83_ODR_75, + .Meas_Conf = PIOS_HMC5x83_MEASCONF_NORMAL, + .Gain = PIOS_HMC5x83_GAIN_1_9, + .Mode = PIOS_HMC5x83_MODE_CONTINUOUS, + .TempCompensation = false, + .Driver = &PIOS_HMC5x83_I2C_DRIVER, + .Orientation = PIOS_HMC5X83_ORIENTATION_EAST_NORTH_UP, +}; + +static const struct pios_hmc5x83_cfg pios_hmc5x83_external_cfg = { +#ifdef PIOS_HMC5X83_HAS_GPIOS + .exti_cfg = NULL, +#endif + .M_ODR = PIOS_HMC5x83_ODR_75, // if you change this for auxmag, change AUX_MAG_SKIP in sensors.c + .Meas_Conf = PIOS_HMC5x83_MEASCONF_NORMAL, + .Gain = PIOS_HMC5x83_GAIN_1_9, + .Mode = PIOS_HMC5x83_MODE_CONTINUOUS, + .TempCompensation = false, + .Driver = &PIOS_HMC5x83_I2C_DRIVER, + .Orientation = PIOS_HMC5X83_ORIENTATION_EAST_NORTH_UP, // ENU for GPSV9, WND for typical I2C mag +}; +const struct pios_hmc5x83_cfg *PIOS_BOARD_HW_DEFS_GetExternalHMC5x83Cfg(__attribute__((unused)) uint32_t board_revision) +{ + return 0; // external HMC5883 will conflict with internal one. +} +const struct pios_hmc5x83_cfg *PIOS_BOARD_HW_DEFS_GetInternalHMC5x83Cfg(__attribute__((unused)) uint32_t board_revision) +{ + return &pios_hmc5x83_internal_cfg; +} +#endif /* PIOS_INCLUDE_HMC5X83 */ + +/** + * Configuration for the MS5611 chip + */ +#if defined(PIOS_INCLUDE_MS5611) +#include "pios_ms5611.h" +static const struct pios_ms5611_cfg pios_ms5611_cfg = { + .oversampling = MS5611_OSR_4096, +}; +const struct pios_ms5611_cfg *PIOS_BOARD_HW_DEFS_GetMS5611Cfg(__attribute__((unused)) uint32_t board_revision) +{ + return &pios_ms5611_cfg; +} +#endif /* PIOS_INCLUDE_MS5611 */ + + +/** + * Configuration for MPU6000 chip + */ +#if defined(PIOS_INCLUDE_MPU6000) +#include "pios_mpu6000.h" +static const struct pios_exti_cfg pios_exti_mpu6000_cfg __exti_config = { + .vector = PIOS_MPU6000_IRQHandler, + .line = EXTI_Line13, + .pin = { + .gpio = GPIOC, + .init = { + .GPIO_Pin = GPIO_Pin_13, + .GPIO_Speed = GPIO_Speed_10MHz, + .GPIO_Mode = GPIO_Mode_IN, + .GPIO_OType = GPIO_OType_OD, + .GPIO_PuPd = GPIO_PuPd_NOPULL, + }, + }, + .irq = { + .init = { + .NVIC_IRQChannel = EXTI15_10_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, + .exti = { + .init = { + .EXTI_Line = EXTI_Line13, // matches above GPIO pin + .EXTI_Mode = EXTI_Mode_Interrupt, + .EXTI_Trigger = EXTI_Trigger_Rising, + .EXTI_LineCmd = ENABLE, + }, + }, +}; + +static const struct pios_mpu6000_cfg pios_mpu6000_cfg = { + .exti_cfg = &pios_exti_mpu6000_cfg, +#ifdef PIOS_MPU6000_I2C_ADDR + .i2c_addr = PIOS_MPU6000_I2C_ADDR, +#endif + .Fifo_store = PIOS_MPU6000_FIFO_TEMP_OUT | PIOS_MPU6000_FIFO_GYRO_X_OUT | PIOS_MPU6000_FIFO_GYRO_Y_OUT | PIOS_MPU6000_FIFO_GYRO_Z_OUT, + // Clock at 8 khz, downsampled by 12 for 666Hz + .Smpl_rate_div_no_dlp = 11, + // Clock at 1 khz, downsampled by 1 for 1000 Hz + .Smpl_rate_div_dlp = 0, + .interrupt_cfg = PIOS_MPU6000_INT_CLR_ANYRD, + .interrupt_en = PIOS_MPU6000_INTEN_DATA_RDY, + .User_ctl = PIOS_MPU6000_USERCTL_FIFO_EN, + .Pwr_mgmt_clk = PIOS_MPU6000_PWRMGMT_PLL_X_CLK, + .accel_range = PIOS_MPU6000_ACCEL_8G, + .gyro_range = PIOS_MPU6000_SCALE_2000_DEG, + .filter = PIOS_MPU6000_LOWPASS_256_HZ, + .orientation = PIOS_MPU6000_TOP_180DEG, +}; + +const struct pios_mpu6000_cfg *PIOS_BOARD_HW_DEFS_GetMPU6000Cfg(__attribute__((unused)) uint32_t board_revision) +{ + return &pios_mpu6000_cfg; +} +#endif /* PIOS_INCLUDE_MPU6000 */ + + +#if defined(PIOS_INCLUDE_SPI) + +#include + +/* Flash/Accel Interface + * + * NOTE: Leave this declared as const data so that it ends up in the + * .rodata section (ie. Flash) rather than in the .bss section (RAM). + */ +void PIOS_SPI_flash_accel_irq_handler(void); +void DMA1_Channel4_IRQHandler() __attribute__((alias("PIOS_SPI_flash_accel_irq_handler"))); +void DMA1_Channel5_IRQHandler() __attribute__((alias("PIOS_SPI_flash_accel_irq_handler"))); +static const struct pios_spi_cfg pios_spi_flash_accel_cfg = { + .regs = SPI2, + .init = { + .SPI_Mode = SPI_Mode_Master, + .SPI_Direction = SPI_Direction_2Lines_FullDuplex, + .SPI_DataSize = SPI_DataSize_8b, + .SPI_NSS = SPI_NSS_Soft, + .SPI_FirstBit = SPI_FirstBit_MSB, + .SPI_CRCPolynomial = 7, + .SPI_CPOL = SPI_CPOL_High, + .SPI_CPHA = SPI_CPHA_2Edge, + .SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_32, + }, + .use_crc = false, + .dma = { + .ahb_clk = RCC_AHBPeriph_DMA1, + + .irq = { + .flags = (DMA1_FLAG_TC4 | DMA1_FLAG_TE4 | DMA1_FLAG_HT4 | DMA1_FLAG_GL4), + .init = { + .NVIC_IRQChannel = DMA1_Channel4_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, + + .rx = { + .channel = DMA1_Channel4, + .init = { + .DMA_PeripheralBaseAddr = (uint32_t)&(SPI2->DR), + .DMA_DIR = DMA_DIR_PeripheralSRC, + .DMA_PeripheralInc = DMA_PeripheralInc_Disable, + .DMA_MemoryInc = DMA_MemoryInc_Enable, + .DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte, + .DMA_MemoryDataSize = DMA_MemoryDataSize_Byte, + .DMA_Mode = DMA_Mode_Normal, + .DMA_Priority = DMA_Priority_High, + .DMA_M2M = DMA_M2M_Disable, + }, + }, + .tx = { + .channel = DMA1_Channel5, + .init = { + .DMA_PeripheralBaseAddr = (uint32_t)&(SPI2->DR), + .DMA_DIR = DMA_DIR_PeripheralDST, + .DMA_PeripheralInc = DMA_PeripheralInc_Disable, + .DMA_MemoryInc = DMA_MemoryInc_Enable, + .DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte, + .DMA_MemoryDataSize = DMA_MemoryDataSize_Byte, + .DMA_Mode = DMA_Mode_Normal, + .DMA_Priority = DMA_Priority_High, + .DMA_M2M = DMA_M2M_Disable, + }, + }, + }, + .remap = GPIO_AF_5, + .sclk = { + .gpio = GPIOB, + .init = { + .GPIO_Pin = GPIO_Pin_13, + .GPIO_Speed = GPIO_Speed_50MHz, + .GPIO_Mode = GPIO_Mode_AF, + .GPIO_OType = GPIO_OType_PP, + .GPIO_PuPd = GPIO_PuPd_NOPULL, + }, + }, + .miso = { + .gpio = GPIOB, + .init = { + .GPIO_Pin = GPIO_Pin_14, + .GPIO_Speed = GPIO_Speed_50MHz, + .GPIO_Mode = GPIO_Mode_AF, /* NOTE: was GPIO_Mode_IN_FLOATING */ + .GPIO_OType = GPIO_OType_PP, + .GPIO_PuPd = GPIO_PuPd_NOPULL, + }, + }, + .mosi = { + .gpio = GPIOB, + .init = { + .GPIO_Pin = GPIO_Pin_15, + .GPIO_Speed = GPIO_Speed_50MHz, + .GPIO_Mode = GPIO_Mode_AF, + .GPIO_OType = GPIO_OType_PP, + .GPIO_PuPd = GPIO_PuPd_NOPULL, + }, + }, + .slave_count = 1, + .ssel = { + { + .gpio = GPIOB, + .init = { + .GPIO_Pin = GPIO_Pin_12, + .GPIO_Speed = GPIO_Speed_50MHz, + .GPIO_Mode = GPIO_Mode_OUT, + .GPIO_OType = GPIO_OType_PP, + .GPIO_PuPd = GPIO_PuPd_UP, + } + }, /*{ + .gpio = GPIOC, + .init = { + .GPIO_Pin = GPIO_Pin_15, + .GPIO_Speed = GPIO_Speed_50MHz, + .GPIO_Mode = GPIO_Mode_OUT, + .GPIO_OType = GPIO_OType_PP, + .GPIO_PuPd = GPIO_PuPd_UP, + }, + }*/ + }, +}; + +static uint32_t pios_spi_flash_accel_id; +void PIOS_SPI_flash_accel_irq_handler(void) +{ + /* Call into the generic code to handle the IRQ for this specific device */ + PIOS_SPI_IRQ_Handler(pios_spi_flash_accel_id); +} + +#endif /* PIOS_INCLUDE_SPI */ + +#if defined(PIOS_INCLUDE_FLASH) +#include "pios_flashfs_logfs_priv.h" +#include "pios_flash_jedec_priv.h" + +static const struct flashfs_logfs_cfg flashfs_w25x_cfg = { + .fs_magic = 0x99abcdef, + .total_fs_size = 0x00080000, /* 512K bytes (128 sectors = entire chip) */ + .arena_size = 0x00010000, /* 256 * slot size */ + .slot_size = 0x00000100, /* 256 bytes */ + + .start_offset = 0, /* start at the beginning of the chip */ + .sector_size = 0x00001000, /* 4K bytes */ + .page_size = 0x00000100, /* 256 bytes */ +}; + + +static const struct flashfs_logfs_cfg flashfs_m25p_cfg = { + .fs_magic = 0x99abceef, + .total_fs_size = 0x00200000, /* 2M bytes (32 sectors = entire chip) */ + .arena_size = 0x00010000, /* 256 * slot size */ + .slot_size = 0x00000100, /* 256 bytes */ + + .start_offset = 0, /* start at the beginning of the chip */ + .sector_size = 0x00010000, /* 64K bytes */ + .page_size = 0x00000100, /* 256 bytes */ +}; + +#include "pios_flash.h" + +#endif /* PIOS_INCLUDE_FLASH */ + +#include "pios_tim_priv.h" + +static const TIM_TimeBaseInitTypeDef tim_1_2_3_4_15_16_17_time_base = { + .TIM_Prescaler = (PIOS_MASTER_CLOCK / 1000000) - 1, + .TIM_ClockDivision = TIM_CKD_DIV1, + .TIM_CounterMode = TIM_CounterMode_Up, + .TIM_Period = ((1000000 / PIOS_SERVO_UPDATE_HZ) - 1), + .TIM_RepetitionCounter = 0x0000, +}; + +static const struct pios_tim_clock_cfg tim_1_cfg = { + .timer = TIM1, + .time_base_init = &tim_1_2_3_4_15_16_17_time_base, + .irq = { + .init = { + .NVIC_IRQChannel = TIM1_CC_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, +}; + +static const struct pios_tim_clock_cfg tim_2_cfg = { + .timer = TIM2, + .time_base_init = &tim_1_2_3_4_15_16_17_time_base, + .irq = { + .init = { + .NVIC_IRQChannel = TIM2_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, +}; + +static const struct pios_tim_clock_cfg tim_3_cfg = { + .timer = TIM3, + .time_base_init = &tim_1_2_3_4_15_16_17_time_base, + .irq = { + .init = { + .NVIC_IRQChannel = TIM3_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, +}; + +static const struct pios_tim_clock_cfg tim_4_cfg = { + .timer = TIM4, + .time_base_init = &tim_1_2_3_4_15_16_17_time_base, + .irq = { + .init = { + .NVIC_IRQChannel = TIM4_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, +}; + +static const struct pios_tim_clock_cfg tim_15_cfg = { + .timer = TIM4, + .time_base_init = &tim_1_2_3_4_15_16_17_time_base, + .irq = { + .init = { + .NVIC_IRQChannel = TIM1_BRK_TIM15_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, +}; + +static const struct pios_tim_clock_cfg tim_16_cfg = { + .timer = TIM4, + .time_base_init = &tim_1_2_3_4_15_16_17_time_base, + .irq = { + .init = { + .NVIC_IRQChannel = TIM1_UP_TIM16_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, +}; + +static const struct pios_tim_clock_cfg tim_17_cfg = { + .timer = TIM4, + .time_base_init = &tim_1_2_3_4_15_16_17_time_base, + .irq = { + .init = { + .NVIC_IRQChannel = TIM1_TRG_COM_TIM17_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, +}; + +#include + +#define GPIO_AF_PA1_TIM2 GPIO_AF_1 +#define GPIO_AF_PA0_TIM2 GPIO_AF_1 +#define GPIO_AF_PA8_TIM1 GPIO_AF_6 +#define GPIO_AF_PA2_TIM2 GPIO_AF_1 +#define GPIO_AF_PB6_TIM4 GPIO_AF_2 +#define GPIO_AF_PB5_TIM3 GPIO_AF_2 +#define GPIO_AF_PB0_TIM3 GPIO_AF_2 +#define GPIO_AF_PB1_TIM3 GPIO_AF_2 +#define GPIO_AF_PB9_TIM4 GPIO_AF_2 +#define GPIO_AF_PB8_TIM4 GPIO_AF_2 +#define GPIO_AF_PB7_TIM4 GPIO_AF_2 +#define GPIO_AF_PB4_TIM3 GPIO_AF_2 +#define GPIO_AF_PB11_TIM2 GPIO_AF_1 +#define GPIO_AF_PB10_TIM2 GPIO_AF_1 +#define GPIO_AF_PA6_TIM16 GPIO_AF_1 +#define GPIO_AF_PA7_TIM17 GPIO_AF_1 +#define GPIO_AF_PA11_TIM4 GPIO_AF_10 +#define GPIO_AF_PA12_TIM4 GPIO_AF_10 +#define GPIO_AF_PA2_TIM15 GPIO_AF_9 +#define GPIO_AF_PA3_TIM15 GPIO_AF_9 + + +static const struct pios_tim_channel pios_tim_servoport_io1_io2_pins[] = { + TIM_SERVO_CHANNEL_CONFIG(TIM16, 1, A, 6), // bank 1 + TIM_SERVO_CHANNEL_CONFIG(TIM17, 1, A, 7), // bank 1 + TIM_SERVO_CHANNEL_CONFIG(TIM4, 1, A, 11), // bank 1 + TIM_SERVO_CHANNEL_CONFIG(TIM4, 2, A, 12), // bank 2 + TIM_SERVO_CHANNEL_CONFIG(TIM4, 3, B, 8), // bank 3 + TIM_SERVO_CHANNEL_CONFIG(TIM4, 4, B, 9), // bank 4 + TIM_SERVO_CHANNEL_CONFIG(TIM15, 1, A, 2), // bank 1 + TIM_SERVO_CHANNEL_CONFIG(TIM15, 2, A, 3), // bank 2 + + // Receiver port pins + // S3-S6 inputs are used as outputs in this case + + TIM_SERVO_CHANNEL_CONFIG(TIM2, 1, A, 0), + TIM_SERVO_CHANNEL_CONFIG(TIM2, 2, A, 1), + TIM_SERVO_CHANNEL_CONFIG(TIM2, 4, B, 11), + TIM_SERVO_CHANNEL_CONFIG(TIM2, 3, B, 10), + TIM_SERVO_CHANNEL_CONFIG(TIM3, 1, B, 4), + TIM_SERVO_CHANNEL_CONFIG(TIM3, 2, B, 5), + TIM_SERVO_CHANNEL_CONFIG(TIM3, 3, B, 0), + TIM_SERVO_CHANNEL_CONFIG(TIM3, 4, B, 1), +}; + +#if defined(PIOS_INCLUDE_USART) + +#define GPIO_AF_USART1 GPIO_AF_7 +#define GPIO_AF_USART2 GPIO_AF_7 +#define GPIO_AF_USART3 GPIO_AF_7 + + +#include "pios_usart_priv.h" +#include "pios_usart_config.h" + +static const struct pios_usart_cfg pios_usart_cfg[] = { + USART_CONFIG(USART1, A, 10, A, 9), + USART_CONFIG(USART2, A, 15, A, 14), + USART_CONFIG(USART3, B, 11, B, 10), +}; + +#endif /* PIOS_INCLUDE_USART */ + +#if defined(PIOS_INCLUDE_COM) + +#include "pios_com_priv.h" + +#endif /* PIOS_INCLUDE_COM */ + +#if defined(PIOS_INCLUDE_RTC) +/* + * Realtime Clock (RTC) + */ +#include + +void PIOS_RTC_IRQ_Handler(void); +void RTC_WKUP_IRQHandler() __attribute__((alias("PIOS_RTC_IRQ_Handler"))); +static const struct pios_rtc_cfg pios_rtc_main_cfg = { + .clksrc = RCC_RTCCLKSource_HSE_Div32, + .prescaler = 25 - 1, // 8Mhz / 32 / 16 / 25 => 625Hz + .irq = { + .init = { + .NVIC_IRQChannel = RTC_WKUP_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, +}; + +void PIOS_RTC_IRQ_Handler(void) +{ + PIOS_RTC_irq_handler(); +} + +#endif /* if defined(PIOS_INCLUDE_RTC) */ + +#if defined(PIOS_INCLUDE_SERVO) && defined(PIOS_INCLUDE_TIM) +/* + * Servo outputs + */ +#include + +const struct pios_servo_cfg pios_servo_cfg = { + .tim_oc_init = { + .TIM_OCMode = TIM_OCMode_PWM1, + .TIM_OutputState = TIM_OutputState_Enable, + .TIM_OutputNState = TIM_OutputNState_Disable, + .TIM_Pulse = PIOS_SERVOS_INITIAL_POSITION, + .TIM_OCPolarity = TIM_OCPolarity_High, + .TIM_OCNPolarity = TIM_OCPolarity_High, + .TIM_OCIdleState = TIM_OCIdleState_Reset, + .TIM_OCNIdleState = TIM_OCNIdleState_Reset, + }, + .channels = pios_tim_servoport_io1_io2_pins, + .num_channels = 8, +}; + +// const struct pios_servo_cfg pios_servo_rcvr_cfg = { +// .tim_oc_init = { +// .TIM_OCMode = TIM_OCMode_PWM1, +// .TIM_OutputState = TIM_OutputState_Enable, +// .TIM_OutputNState = TIM_OutputNState_Disable, +// .TIM_Pulse = PIOS_SERVOS_INITIAL_POSITION, +// .TIM_OCPolarity = TIM_OCPolarity_High, +// .TIM_OCNPolarity = TIM_OCPolarity_High, +// .TIM_OCIdleState = TIM_OCIdleState_Reset, +// .TIM_OCNIdleState = TIM_OCNIdleState_Reset, +// }, +// .channels = pios_tim_servoport_io1_io2_pins, +// .num_channels = NELEMENTS(pios_tim_servoport_io1_io2_pins), +// }; + +#endif /* PIOS_INCLUDE_SERVO && PIOS_INCLUDE_TIM */ + +/* + * PPM Inputs + */ +#if defined(PIOS_INCLUDE_PPM) +#include + +const struct pios_ppm_cfg pios_ppm_cfg = { + .tim_ic_init = { + .TIM_ICPolarity = TIM_ICPolarity_Rising, + .TIM_ICSelection = TIM_ICSelection_DirectTI, + .TIM_ICPrescaler = TIM_ICPSC_DIV1, + .TIM_ICFilter = 0x0, + }, + /* Use only the first channel for ppm */ + .channels = &pios_tim_servoport_io1_io2_pins[8], + .num_channels = 1, +}; + +#endif /* PIOS_INCLUDE_PPM */ + +/* + * PWM Inputs + */ +#if defined(PIOS_INCLUDE_PWM) +#include + +const struct pios_pwm_cfg pios_pwm_cfg = { + .tim_ic_init = { + .TIM_ICPolarity = TIM_ICPolarity_Rising, + .TIM_ICSelection = TIM_ICSelection_DirectTI, + .TIM_ICPrescaler = TIM_ICPSC_DIV1, + .TIM_ICFilter = 0x0, + }, + .channels = &pios_tim_servoport_io1_io2_pins[8], + .num_channels = 8, +}; + +#endif /* if defined(PIOS_INCLUDE_PWM) */ + + +/* + * SONAR Inputs + */ +#if defined(PIOS_INCLUDE_HCSR04) +#include + +static const struct pios_tim_channel pios_tim_hcsr04_port_all_channels[] = { + { + .timer = TIM3, + .timer_chan = TIM_Channel_2, + .pin = { + .gpio = GPIOB, + .init = { + .GPIO_Pin = GPIO_Pin_5, + .GPIO_Mode = GPIO_Mode_IPD, + .GPIO_Speed = GPIO_Speed_2MHz, + }, + }, + .remap = GPIO_PartialRemap_TIM3, + }, +}; + +const struct pios_hcsr04_cfg pios_hcsr04_cfg = { + .tim_ic_init = { + .TIM_ICPolarity = TIM_ICPolarity_Rising, + .TIM_ICSelection = TIM_ICSelection_DirectTI, + .TIM_ICPrescaler = TIM_ICPSC_DIV1, + .TIM_ICFilter = 0x0, + }, + .channels = pios_tim_hcsr04_port_all_channels, + .num_channels = NELEMENTS(pios_tim_hcsr04_port_all_channels), + .trigger = { + .gpio = GPIOB, + .init = { + .GPIO_Pin = GPIO_Pin_6, + .GPIO_Mode = GPIO_Mode_Out_PP, + .GPIO_Speed = GPIO_Speed_2MHz, + }, + }, +}; +#endif /* if defined(PIOS_INCLUDE_HCSR04) */ + +#if defined(PIOS_INCLUDE_I2C) + +#include + +/* + * I2C Adapters + */ + +void PIOS_I2C_ev_irq_handler(void); +void PIOS_I2C_er_irq_handler(void); +void I2C1_EV_EXTI23_IRQHandler() __attribute__((alias("PIOS_I2C_ev_irq_handler"))); +void I2C1_ER_IRQHandler() __attribute__((alias("PIOS_I2C_er_irq_handler"))); + +static const struct pios_i2c_adapter_cfg pios_i2c_cfg = { + .regs = I2C1, + .remapSCL = GPIO_AF_4, + .remapSDA = GPIO_AF_4, + .init = { + .I2C_Mode = I2C_Mode_I2C, + .I2C_OwnAddress1 = 0, + .I2C_Ack = I2C_Ack_Enable, + .I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit, + .I2C_DigitalFilter = 0x00, + .I2C_AnalogFilter = I2C_AnalogFilter_Enable, +// .I2C_Timing = 0x70310309, // 50kHz I2C @ 8MHz input -> PRESC=0x7, SCLDEL=0x3, SDADEL=0x1, SCLH=0x03, SCLL=0x09 + .I2C_Timing = 0x00E0257A, // 400 Khz, 72Mhz Clock, Analog Filter Delay ON, Rise 100, Fall 10. + }, + .transfer_timeout_ms = 50, + .scl = { + .gpio = GPIOB, + .init = { + .GPIO_Pin = GPIO_Pin_6, + .GPIO_Mode = GPIO_Mode_AF, + .GPIO_Speed = GPIO_Speed_50MHz, + .GPIO_OType = GPIO_OType_PP, + .GPIO_PuPd = GPIO_PuPd_UP, + }, + .pin_source = GPIO_PinSource6, + }, + .sda = { + .gpio = GPIOB, + .init = { + .GPIO_Pin = GPIO_Pin_7, + .GPIO_Mode = GPIO_Mode_AF, + .GPIO_Speed = GPIO_Speed_50MHz, + .GPIO_OType = GPIO_OType_PP, + .GPIO_PuPd = GPIO_PuPd_UP, + }, + .pin_source = GPIO_PinSource7, + }, + .event = { + .flags = 0, /* FIXME: check this */ + .init = { + .NVIC_IRQChannel = I2C1_EV_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGHEST, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, + .error = { + .flags = 0, /* FIXME: check this */ + .init = { + .NVIC_IRQChannel = I2C1_ER_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGHEST, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, +}; + +uint32_t pios_i2c_id; +void PIOS_I2C_ev_irq_handler(void) +{ + /* Call into the generic code to handle the IRQ for this specific device */ + PIOS_I2C_EV_IRQ_Handler(pios_i2c_id); +} + +void PIOS_I2C_er_irq_handler(void) +{ + /* Call into the generic code to handle the IRQ for this specific device */ + PIOS_I2C_ER_IRQ_Handler(pios_i2c_id); +} + + +#endif /* PIOS_INCLUDE_I2C */ + +#if defined(PIOS_INCLUDE_GCSRCVR) +#include "pios_gcsrcvr_priv.h" +#endif /* PIOS_INCLUDE_GCSRCVR */ + +#if defined(PIOS_INCLUDE_RCVR) +#include "pios_rcvr_priv.h" + +#endif /* PIOS_INCLUDE_RCVR */ + + +#if defined(PIOS_INCLUDE_ADC) +#include "pios_adc_priv.h" +void PIOS_ADC_DMC_irq_handler(void); +void DMA2_Channel1_IRQHandler(void) __attribute__((alias("PIOS_ADC_DMC_irq_handler"))); + +struct pios_adc_cfg pios_adc_cfg = { + .adc_dev = ADC2, + .dma = { + .irq = { + .flags = (DMA2_FLAG_TC1 | DMA2_FLAG_TE1 | DMA2_FLAG_HT1), + .init = { + .NVIC_IRQChannel = DMA2_Channel1_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_LOW, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, + .rx = { + .channel = DMA2_Channel1, + } + }, + .half_flag = DMA2_FLAG_HT1, + .full_flag = DMA2_FLAG_TC1, +}; + +void PIOS_ADC_DMC_irq_handler(void) +{ + /* Call into the generic code to handle the IRQ for this specific device */ + PIOS_ADC_DMA_Handler(); +} + +const struct pios_adc_cfg *PIOS_BOARD_HW_DEFS_GetAdcCfg(__attribute__((unused)) uint32_t board_revision) +{ + return &pios_adc_cfg; +} +#endif /* if defined(PIOS_INCLUDE_ADC) */ diff --git a/flight/targets/boards/spracingf3/bootloader/Makefile b/flight/targets/boards/spracingf3/bootloader/Makefile new file mode 100644 index 0000000000..3cd53ef127 --- /dev/null +++ b/flight/targets/boards/spracingf3/bootloader/Makefile @@ -0,0 +1,39 @@ +# +# Copyright (c) 2015, The LibrePilot Project, http://www.librepilot.org +# Copyright (c) 2009-2013, The OpenPilot Team, http://www.openpilot.org +# +# 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 FLIGHT_MAKEFILE + $(error Top level Makefile must be used to build this target) +endif + +PIOS_OMITS_USB = YES +PIOS_APPS_MINIMAL = YES + +include ../board-info.mk +include $(FLIGHT_ROOT_DIR)/make/firmware-defs.mk + +## The standard CMSIS startup +SRC += $(FLIGHTLIB)/ssp.c +SRC += $(PIOSCOMMON)/pios_com.c +SRC += $(FLIGHTLIB)/fifo_buffer.c + + + +include $(FLIGHT_ROOT_DIR)/make/boot-defs.mk +include $(FLIGHT_ROOT_DIR)/make/common-defs.mk + diff --git a/flight/targets/boards/spracingf3/bootloader/inc/common.h b/flight/targets/boards/spracingf3/bootloader/inc/common.h new file mode 100644 index 0000000000..93bccceeab --- /dev/null +++ b/flight/targets/boards/spracingf3/bootloader/inc/common.h @@ -0,0 +1,115 @@ +/** + ****************************************************************************** + * @addtogroup SPRacingF3 serial BootLoader + * @brief These files contain the code to the SPRacingF3 serial Bootloader. + * + * @{ + * @file common.c + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief This file contains various common defines for the BootLoader + * @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 COMMON_H_ +#define COMMON_H_ + +// #include "board.h" + +typedef enum { + start, keepgoing, +} DownloadAction; + +/**************************************************/ +/* OP_DFU states */ +/**************************************************/ + +typedef enum { + DFUidle, // 0 + uploading, // 1 + wrong_packet_received, // 2 + too_many_packets, // 3 + too_few_packets, // 4 + Last_operation_Success, // 5 + downloading, // 6 + BLidle, // 7 + Last_operation_failed, // 8 + uploadingStarting, // 9 + outsideDevCapabilities, // 10 + CRC_Fail, // 11 + failed_jump, +// 12 +} DFUStates; +/**************************************************/ +/* OP_DFU commands */ +/**************************************************/ +typedef enum { + Reserved, // 0 + Req_Capabilities, // 1 + Rep_Capabilities, // 2 + EnterDFU, // 3 + JumpFW, // 4 + Reset, // 5 + Abort_Operation, // 6 + Upload, // 7 + Op_END, // 8 + Download_Req, // 9 + Download, // 10 + Status_Request, // 11 + Status_Rep +// 12 +} DFUCommands; + +typedef enum { + High_Density, Medium_Density +} DeviceType; +/**************************************************/ +/* OP_DFU transfer types */ +/**************************************************/ +typedef enum { + FW, // 0 + Descript +// 2 +} DFUTransfer; +/**************************************************/ +/* OP_DFU transfer port */ +/**************************************************/ +typedef enum { + Usb, // 0 + Serial +// 2 +} DFUPort; +/**************************************************/ +/* OP_DFU programable programable HW types */ +/**************************************************/ +typedef enum { + Self_flash, // 0 + Remote_flash_via_spi +// 1 +} DFUProgType; +/**************************************************/ +/* OP_DFU programable sources */ +/**************************************************/ +#define USB 0 +#define SPI 1 + +#define DownloadDelay 100000 + +#define MAX_DEL_RETRYS 3 +#define MAX_WRI_RETRYS 3 + +#endif /* COMMON_H_ */ diff --git a/flight/targets/boards/spracingf3/bootloader/inc/pios_config.h b/flight/targets/boards/spracingf3/bootloader/inc/pios_config.h new file mode 100644 index 0000000000..d56538d7e0 --- /dev/null +++ b/flight/targets/boards/spracingf3/bootloader/inc/pios_config.h @@ -0,0 +1,52 @@ +/** + ****************************************************************************** + * @addtogroup CopterControlBL CopterControl BootLoader + * @brief These files contain the code to the CopterControl Bootloader. + * @{ + * @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. + * In particular, pios_config.h is where you define which PiOS libraries + * and features are included in the firmware. + * @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_SYS +#define PIOS_INCLUDE_IRQ +#define PIOS_INCLUDE_GPIO +#define PIOS_INCLUDE_LED +#define PIOS_INCLUDE_IAP +#define PIOS_INCLUDE_COM +#define PIOS_INCLUDE_USART +#define PIOS_INCLUDE_COM_MSG +#define PIOS_INCLUDE_BL_HELPER +#define PIOS_INCLUDE_BL_HELPER_WRITE_SUPPORT + +#endif /* PIOS_CONFIG_H */ + +/** + * @} + * @} + */ diff --git a/flight/targets/boards/spracingf3/bootloader/main.c b/flight/targets/boards/spracingf3/bootloader/main.c new file mode 100644 index 0000000000..72b08d065f --- /dev/null +++ b/flight/targets/boards/spracingf3/bootloader/main.c @@ -0,0 +1,276 @@ +/** + ****************************************************************************** + * @addtogroup SPRacingF3 serial BootLoader + * @brief These files contain the code to the SPRacingF3 serial Bootloader. + * + * @{ + * @file main.c + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief This is the file with the main function of the OpenPilot BootLoader + * @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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern void FLASH_Download(); +int32_t platform_senddata(const uint8_t *msg, uint16_t msg_len); +/* Private typedef -----------------------------------------------------------*/ +typedef void (*pFunction)(void); +/* Private define ------------------------------------------------------------*/ +#define MAX_PACKET_DATA_LEN 255 +#define MAX_PACKET_BUF_SIZE (1 + 1 + MAX_PACKET_DATA_LEN + 2) +#define UART_BUFFER_SIZE 256 +#define BL_WAIT_TIME 6 * 1000 * 1000 +#define DFU_BUFFER_SIZE 63 + +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +pFunction Jump_To_Application; +static uint32_t JumpAddress; + +/// LEDs PWM +uint32_t period1 = 5000; // 5 mS +uint32_t sweep_steps1 = 100; // * 5 mS -> 500 mS +uint32_t period2 = 5000; // 5 mS +uint32_t sweep_steps2 = 100; // * 5 mS -> 500 mS + +static uint8_t process_buffer[DFU_BUFFER_SIZE]; +static uint8_t rx_buffer[UART_BUFFER_SIZE]; +static uint8_t txBuf[MAX_PACKET_BUF_SIZE]; +static uint8_t rxBuf[MAX_PACKET_BUF_SIZE]; + +/* Extern variables ----------------------------------------------------------*/ +DFUStates DeviceState = DFUidle; +int16_t status = 0; +bool JumpToApp = false; +bool ssp_dfu = false; // signal that ssp data has been received +bool User_DFU_request = true; + + +/* Private function prototypes -----------------------------------------------*/ +static void led_pwm_step(uint16_t pwm_period, uint16_t pwm_sweep_steps, uint32_t stopwatch, bool default_state); +static uint32_t LedPWM(uint16_t pwm_period, uint16_t pwm_sweep_steps, uint32_t count); +static void processRX(); +static void jump_to_app(); + + +static void SSP_CallBack(uint8_t *buf, uint16_t len); +static int16_t SSP_SerialRead(void); +static void SSP_SerialWrite(uint8_t); + + +static const PortConfig_t ssp_portConfig = { + .rxBuf = rxBuf, + .rxBufSize = MAX_PACKET_DATA_LEN, + .txBuf = txBuf, + .txBufSize = MAX_PACKET_DATA_LEN, + .max_retry = 1, + .timeoutLen = 5000, + .pfCallBack = SSP_CallBack, + .pfSerialRead = SSP_SerialRead, + .pfSerialWrite = SSP_SerialWrite, + .pfGetTime = PIOS_DELAY_GetuS, +}; + +static Port_t ssp_port; +static t_fifo_buffer ssp_buffer; + +int main() +{ + PIOS_SYS_Init(); + PIOS_Board_Init(); + PIOS_IAP_Init(); + + if (PIOS_IAP_CheckRequest() == false) { + PIOS_DELAY_WaitmS(500); + User_DFU_request = false; + DeviceState = BLidle; + PIOS_IAP_ClearRequest(); + } + + // Initialize the SSP layer between serial port and DFU + fifoBuf_init(&ssp_buffer, rx_buffer, UART_BUFFER_SIZE); + ssp_Init(&ssp_port, &ssp_portConfig); + + uint32_t stopwatch = 0; + const uint32_t start_time = PIOS_DELAY_GetuS(); + while (true) { + /* Update the stopwatch */ + stopwatch = PIOS_DELAY_GetuSSince(start_time); + + processRX(); + + switch (DeviceState) { + case Last_operation_Success: + case uploadingStarting: + case DFUidle: + period1 = 5000; + sweep_steps1 = 100; + // PIOS_LED_Off(PIOS_LED_HEARTBEAT); + period2 = 0; + break; + case uploading: + period1 = 5000; + sweep_steps1 = 100; + period2 = 2500; + sweep_steps2 = 50; + break; + case downloading: + period1 = 2500; + sweep_steps1 = 50; + // PIOS_LED_Off(PIOS_LED_HEARTBEAT); + period2 = 0; + break; + case BLidle: + period1 = 0; + sweep_steps1 = 100; + PIOS_LED_On(PIOS_LED_HEARTBEAT); + period2 = 0; + break; + default: // error + period1 = 5000; + sweep_steps1 = 100; + period2 = 5000; + sweep_steps2 = 100; + } + led_pwm_step(period1, sweep_steps1, stopwatch, false); + led_pwm_step(period2, sweep_steps2, stopwatch, true); + JumpToApp |= (stopwatch > BL_WAIT_TIME) && ((DeviceState == BLidle) || (DeviceState == DFUidle)); + DataDownload(start); + + if (JumpToApp == true && !ssp_dfu) { + jump_to_app(); + } + } +} + +void led_pwm_step(uint16_t pwm_period, uint16_t pwm_sweep_steps, uint32_t stopwatch, bool default_state) +{ + if (pwm_period != 0) { + if (LedPWM(pwm_period, pwm_sweep_steps, stopwatch)) { + PIOS_LED_On(PIOS_LED_HEARTBEAT); + } else { + PIOS_LED_Off(PIOS_LED_HEARTBEAT); + } + } else { + if (default_state) { + PIOS_LED_On(PIOS_LED_HEARTBEAT); + } else { + PIOS_LED_Off(PIOS_LED_HEARTBEAT); + } + } +} +void jump_to_app() +{ + const struct pios_board_info *bdinfo = &pios_board_info_blob; + + uint32_t fwIrqStackBase = (*(__IO uint32_t *)bdinfo->fw_base) & 0xFFFE0000; + + // Check for the two possible irqstack locations (sram or core coupled sram) + if (fwIrqStackBase == 0x20000000 || fwIrqStackBase == 0x10000000) { + FLASH_Lock(); + RCC_APB2PeriphResetCmd(0xffffffff, ENABLE); + RCC_APB1PeriphResetCmd(0xffffffff, ENABLE); + RCC_APB2PeriphResetCmd(0xffffffff, DISABLE); + RCC_APB1PeriphResetCmd(0xffffffff, DISABLE); + + JumpAddress = *(__IO uint32_t *)(bdinfo->fw_base + 4); + Jump_To_Application = (pFunction)JumpAddress; + /* Initialize user application's Stack Pointer */ + __set_MSP(*(__IO uint32_t *)bdinfo->fw_base); + Jump_To_Application(); + } else { + DeviceState = failed_jump; + return; + } +} + +uint32_t LedPWM(uint16_t pwm_period, uint16_t pwm_sweep_steps, uint32_t count) +{ + const uint32_t curr_step = (count / pwm_period) % pwm_sweep_steps; /* 0 - pwm_sweep_steps */ + uint32_t pwm_duty = pwm_period * curr_step / pwm_sweep_steps; /* fraction of pwm_period */ + + const uint32_t curr_sweep = (count / (pwm_period * pwm_sweep_steps)); /* ticks once per full sweep */ + + if (curr_sweep & 1) { + pwm_duty = pwm_period - pwm_duty; /* reverse direction in odd sweeps */ + } + return ((count % pwm_period) > pwm_duty) ? 1 : 0; +} +uint32_t process_count = 0; +void processRX() +{ + do { + ssp_ReceiveProcess(&ssp_port); + status = ssp_SendProcess(&ssp_port); + } while ((status != SSP_TX_IDLE) && (status != SSP_TX_ACKED)); + + if (fifoBuf_getUsed(&ssp_buffer) >= DFU_BUFFER_SIZE) { + for (int32_t x = 0; x < DFU_BUFFER_SIZE; ++x) { + process_buffer[x] = fifoBuf_getByte(&ssp_buffer); + } + process_count++; + processComand(process_buffer); + } +} +uint32_t callback_cnt = 0; +uint32_t read_cnt = 0; +uint32_t write_cnt = 0; +uint32_t rx_check_cnt = 0; +void SSP_CallBack(uint8_t *buf, uint16_t len) +{ + ssp_dfu = true; + callback_cnt++; + fifoBuf_putData(&ssp_buffer, buf, len); +} + +int16_t SSP_SerialRead(void) +{ + uint8_t byte; + + rx_check_cnt++; + if (PIOS_COM_ReceiveBuffer(PIOS_COM_TELEM_USB, &byte, 1, 0) == 1) { + read_cnt++; + return byte; + } else { + return -1; + } +} + +int32_t platform_senddata(const uint8_t *msg, uint16_t msg_len) +{ + return ssp_SendData(&ssp_port, msg, msg_len); +} + +void SSP_SerialWrite(uint8_t value) +{ + write_cnt++; + PIOS_COM_SendChar(PIOS_COM_TELEM_USB, value); +} diff --git a/flight/targets/boards/spracingf3/bootloader/memory.ld b/flight/targets/boards/spracingf3/bootloader/memory.ld new file mode 100644 index 0000000000..f4a1713f82 --- /dev/null +++ b/flight/targets/boards/spracingf3/bootloader/memory.ld @@ -0,0 +1,7 @@ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 0x004000 - 0x000080 + BD_INFO (r) : ORIGIN = 0x08004000 - 0x80, LENGTH = 0x000080 + SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x009000 + CCSRAM (rw) : ORIGIN = 0x10000000, LENGTH = 0x002000 +} diff --git a/flight/targets/boards/spracingf3/bootloader/pios_board.c b/flight/targets/boards/spracingf3/bootloader/pios_board.c new file mode 100644 index 0000000000..c8604bfa78 --- /dev/null +++ b/flight/targets/boards/spracingf3/bootloader/pios_board.c @@ -0,0 +1,84 @@ +/** + ****************************************************************************** + * + * @file pios_board.c + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2014. + * @brief Defines board specific static initializers for hardware for the GPS board. + * @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 +#include +#include + +/* + * Pull in the board-specific static HW definitions. + * Including .c files is a bit ugly but this allows all of + * the HW definitions to be const and static to limit their + * scope. + * + * NOTE: THIS IS THE ONLY PLACE THAT SHOULD EVER INCLUDE THIS FILE + */ +#include "../board_hw_defs.c" +#include + +uint32_t pios_com_telem_usb_id; + +#define PIOS_COM_MAIN_RX_BUF_LEN 256 +#define PIOS_COM_MAIN_TX_BUF_LEN 256 +uint8_t rx_buffer[PIOS_COM_MAIN_RX_BUF_LEN]; +uint8_t tx_buffer[PIOS_COM_MAIN_TX_BUF_LEN]; + + +static void setupCom(); +/** + * PIOS_Board_Init() + * initializes all the core subsystems on this specific hardware + * called from System/openpilot.c + */ +void PIOS_Board_Init(void) +{ + const struct pios_board_info *bdinfo = &pios_board_info_blob; + + FLASH_PrefetchBufferCmd(ENABLE); + +#if defined(PIOS_INCLUDE_LED) + const struct pios_gpio_cfg *led_cfg = PIOS_BOARD_HW_DEFS_GetLedCfg(bdinfo->board_rev); + PIOS_Assert(led_cfg); + PIOS_LED_Init(led_cfg); +#endif /* PIOS_INCLUDE_LED */ + setupCom(); +} + +void setupCom() +{ + uint32_t pios_usart_generic_id; + + if (PIOS_USART_Init(&pios_usart_generic_id, &pios_usart_cfg[0])) { + PIOS_Assert(0); + } + + if (PIOS_COM_Init(&PIOS_COM_TELEM_USB, &pios_usart_com_driver, pios_usart_generic_id, + rx_buffer, PIOS_COM_MAIN_RX_BUF_LEN, + tx_buffer, PIOS_COM_MAIN_TX_BUF_LEN)) { + PIOS_Assert(0); + } + + PIOS_COM_ChangeConfig(PIOS_COM_TELEM_USB, PIOS_COM_Word_length_8b, PIOS_COM_Parity_No, PIOS_COM_StopBits_1, 57600); +} diff --git a/flight/targets/boards/spracingf3/common/sections.ld b/flight/targets/boards/spracingf3/common/sections.ld new file mode 100644 index 0000000000..b3eada5843 --- /dev/null +++ b/flight/targets/boards/spracingf3/common/sections.ld @@ -0,0 +1,197 @@ + +/* Section Definitions */ +SECTIONS +{ + /* + * Vectors, code and constant data. + */ + .text : + { + PROVIDE (pios_isr_vector_table_base = .); + KEEP(*(.cpu_vectors)) /* CPU exception vectors */ + KEEP(*(.io_vectors)) /* I/O interrupt vectors */ + *(.text .text.* .gnu.linkonce.t.*) + *(.glue_7t) *(.glue_7) + *(.rodata .rodata* .gnu.linkonce.r.*) + } > FLASH + + /* + * Init section for UAVObjects. + */ + .initcalluavobj.init : + { + . = ALIGN(4); + __uavobj_initcall_start = .; + KEEP(*(.initcalluavobj.init)) + . = ALIGN(4); + __uavobj_initcall_end = .; + } >FLASH + + /* + * Module init section section + */ + .initcallmodule.init : + { + . = ALIGN(4); + __module_initcall_start = .; + KEEP(*(.initcallmodule.init)) + . = ALIGN(4); + __module_initcall_end = .; + } >FLASH + + + /* + * C++ exception handling. + */ + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > FLASH + .ARM.exidx : + { + __exidx_start = .; + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + __exidx_end = .; + } > FLASH + + /* + * Markers for the end of the 'text' section and the in-flash start of + * non-constant data + */ + . = ALIGN(4); + _etext = .; + _sidata = .; + + /* + * Board info structure, normally only generated by the bootloader but can + * be read by the application. + */ + PROVIDE(pios_board_info_blob = ORIGIN(BD_INFO)); + .boardinfo : + { + . = ALIGN(4); + KEEP(*(.boardinfo)) + . = ALIGN(ORIGIN(BD_INFO)+LENGTH(BD_INFO)); + } > BD_INFO + + /* + * Place the IRQ/bootstrap stack at the bottom of SRAM so that an overflow + * results in a hard fault. + */ + .istack (NOLOAD) : + { + . = ALIGN(4); + _irq_stack_end = . ; + *(.irqstack) + _irq_stack_top = . ; + } > CCSRAM + + + /* + * Non-const initialised data. + */ + .data : AT (_sidata) + { + . = ALIGN(4); + _sdata = .; + *(.data .data.*) + . = ALIGN(4); + _edata = . ; + } > SRAM + + /* + * Uninitialised data (BSS + commons). + */ + .bss (NOLOAD) : + { + _sbss = . ; + *(SORT_BY_ALIGNMENT(.bss*)) + *(COMMON) + _ebss = . ; + PROVIDE ( _end = _ebss ) ; + } > SRAM + + /* + * The heap consumes the remainder of the SRAM. + */ + .heap (NOLOAD) : + { + . = ALIGN(4); + _sheap = . ; + + /* + * This allows us to declare an object or objects up to the minimum acceptable + * heap size and receive a linker error if the space available for the heap is + * not sufficient. + */ + *(.heap) + + /* extend the heap up to the top of SRAM */ + . = ORIGIN(SRAM) + LENGTH(SRAM) - ABSOLUTE(_sheap); + _eheap = .; + } > SRAM + + /* + * 'Fast' memory goes in the CCM SRAM + */ + .fast (NOLOAD) : + { + _sfast = . ; + *(.fast) + _efast = . ; + } > CCSRAM + + /* + * The fastheap consumes the remainder of the CCSRAM. + */ + .fastheap (NOLOAD) : + { + . = ALIGN(4); + _sfastheap = . ; + + /* + * This allows us to declare an object or objects up to the minimum acceptable + * heap size and receive a linker error if the space available for the heap is + * not sufficient. + */ + *(.fastheap) + + /* extend the heap up to the top of SRAM */ + . = ORIGIN(CCSRAM) + LENGTH(CCSRAM) - ABSOLUTE(_sfastheap); + _efastheap = .; + } > CCSRAM + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } +} diff --git a/flight/targets/boards/spracingf3/common/system.c b/flight/targets/boards/spracingf3/common/system.c new file mode 100644 index 0000000000..d26ba3ad62 --- /dev/null +++ b/flight/targets/boards/spracingf3/common/system.c @@ -0,0 +1,354 @@ +/** + ****************************************************************************** + * @file system_stm32f30x.c + * @author MCD Application Team + * @version V1.2.2 + * @date 27-February-2015 + * @brief CMSIS Cortex-M4 Device Peripheral Access Layer System Source File. + * This file contains the system clock configuration for STM32F30x devices, + * and is generated by the clock configuration tool + * stm32f30x_Clock_Configuration_V1.0.0.xls + * + * 1. This file provides two functions and one global variable to be called from + * user application: + * - SystemInit(): Setups the system clock (System clock source, PLL Multiplier + * and Divider factors, AHB/APBx prescalers and Flash settings), + * depending on the configuration made in the clock xls tool. + * This function is called at startup just after reset and + * before branch to main program. This call is made inside + * the "startup_stm32f30x.s" file. + * + * - SystemCoreClock variable: Contains the core clock (HCLK), it can be used + * by the user application to setup the SysTick + * timer or configure other parameters. + * + * - SystemCoreClockUpdate(): Updates the variable SystemCoreClock and must + * be called whenever the core clock is changed + * during program execution. + * + * 2. After each device reset the HSI (8 MHz) is used as system clock source. + * Then SystemInit() function is called, in "startup_stm32f30x.s" file, to + * configure the system clock before to branch to main program. + * + * 3. If the system clock source selected by user fails to startup, the SystemInit() + * function will do nothing and HSI still used as system clock source. User can + * add some code to deal with this issue inside the SetSysClock() function. + * + * 4. The default value of HSE crystal is set to 8MHz, refer to "HSE_VALUE" define + * in "stm32f30x.h" file. When HSE is used as system clock source, directly or + * through PLL, and you are using different crystal you have to adapt the HSE + * value to your own configuration. + * + * 5. This file configures the system clock as follows: + *============================================================================= + * Supported STM32F30x device + *----------------------------------------------------------------------------- + * System Clock source | PLL (HSE) + *----------------------------------------------------------------------------- + * SYSCLK(Hz) | 72000000 + *----------------------------------------------------------------------------- + * HCLK(Hz) | 72000000 + *----------------------------------------------------------------------------- + * AHB Prescaler | 1 + *----------------------------------------------------------------------------- + * APB2 Prescaler | 1 + *----------------------------------------------------------------------------- + * APB1 Prescaler | 2 + *----------------------------------------------------------------------------- + * HSE Frequency(Hz) | 8000000 + *---------------------------------------------------------------------------- + * PLLMUL | 9 + *----------------------------------------------------------------------------- + * PREDIV | 1 + *----------------------------------------------------------------------------- + * USB Clock | DISABLE + *----------------------------------------------------------------------------- + * Flash Latency(WS) | 2 + *----------------------------------------------------------------------------- + * Prefetch Buffer | ON + *----------------------------------------------------------------------------- + *============================================================================= + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ +/** @addtogroup CMSIS + * @{ + */ + +/** @addtogroup stm32f30x_system + * @{ + */ + +/** @addtogroup STM32F30x_System_Private_Includes + * @{ + */ + +#include "stm32f30x.h" + +/** + * @} + */ + +/* Private typedef -----------------------------------------------------------*/ + +/** @addtogroup STM32F30x_System_Private_Defines + * @{ + */ +/*!< Uncomment the following line if you need to relocate your vector Table in + Internal SRAM. */ +/* #define VECT_TAB_SRAM */ +#define VECT_TAB_OFFSET 0x0 /*!< Vector Table base offset field. + This value must be a multiple of 0x200. */ +/** + * @} + */ + +/* Private macro -------------------------------------------------------------*/ + +/** @addtogroup STM32F30x_System_Private_Variables + * @{ + */ + +uint32_t SystemCoreClock = 72000000; + +__I uint8_t AHBPrescTable[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9 }; + +/** + * @} + */ + +/** @addtogroup STM32F30x_System_Private_FunctionPrototypes + * @{ + */ + +static void SetSysClock(void); + +/** + * @} + */ + +/** @addtogroup STM32F30x_System_Private_Functions + * @{ + */ + +/** + * @brief Setup the microcontroller system + * Initialize the Embedded Flash Interface, the PLL and update the + * SystemFrequency variable. + * @param None + * @retval None + */ +void SystemInit(void) +{ + /* FPU settings ------------------------------------------------------------*/ + #if (__FPU_PRESENT == 1) && (__FPU_USED == 1) + SCB->CPACR |= ((3UL << 10 * 2) | (3UL << 11 * 2)); /* set CP10 and CP11 Full Access */ + #endif + + /* Reset the RCC clock configuration to the default reset state ------------*/ + /* Set HSION bit */ + RCC->CR |= (uint32_t)0x00000001; + + /* Reset CFGR register */ + RCC->CFGR &= 0xF87FC00C; + + /* Reset HSEON, CSSON and PLLON bits */ + RCC->CR &= (uint32_t)0xFEF6FFFF; + + /* Reset HSEBYP bit */ + RCC->CR &= (uint32_t)0xFFFBFFFF; + + /* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE bits */ + RCC->CFGR &= (uint32_t)0xFF80FFFF; + + /* Reset PREDIV1[3:0] bits */ + RCC->CFGR2 &= (uint32_t)0xFFFFFFF0; + + /* Reset USARTSW[1:0], I2CSW and TIMs bits */ + RCC->CFGR3 &= (uint32_t)0xFF00FCCC; + + /* Disable all interrupts */ + RCC->CIR = 0x00000000; + + /* Configure the System clock source, PLL Multiplier and Divider factors, + AHB/APBx prescalers and Flash settings ----------------------------------*/ + SetSysClock(); + +#ifdef VECT_TAB_SRAM + SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */ +#else + SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */ +#endif +} + +/** + * @brief Update SystemCoreClock variable according to Clock Register Values. + * The SystemCoreClock variable contains the core clock (HCLK), it can + * be used by the user application to setup the SysTick timer or configure + * other parameters. + * + * @note Each time the core clock (HCLK) changes, this function must be called + * to update SystemCoreClock variable value. Otherwise, any configuration + * based on this variable will be incorrect. + * + * @note - The system frequency computed by this function is not the real + * frequency in the chip. It is calculated based on the predefined + * constant and the selected clock source: + * + * - If SYSCLK source is HSI, SystemCoreClock will contain the HSI_VALUE(*) + * + * - If SYSCLK source is HSE, SystemCoreClock will contain the HSE_VALUE(**) + * + * - If SYSCLK source is PLL, SystemCoreClock will contain the HSE_VALUE(**) + * or HSI_VALUE(*) multiplied/divided by the PLL factors. + * + * (*) HSI_VALUE is a constant defined in stm32f30x.h file (default value + * 8 MHz) but the real value may vary depending on the variations + * in voltage and temperature. + * + * (**) HSE_VALUE is a constant defined in stm32f30x.h file (default value + * 8 MHz), user has to ensure that HSE_VALUE is same as the real + * frequency of the crystal used. Otherwise, this function may + * have wrong result. + * + * - The result of this function could be not correct when using fractional + * value for HSE crystal. + * + * @param None + * @retval None + */ +void SystemCoreClockUpdate(void) +{ + uint32_t tmp = 0, pllmull = 0, pllsource = 0, prediv1factor = 0; + + /* Get SYSCLK source -------------------------------------------------------*/ + tmp = RCC->CFGR & RCC_CFGR_SWS; + + switch (tmp) { + case 0x00: /* HSI used as system clock */ + SystemCoreClock = HSI_VALUE; + break; + case 0x04: /* HSE used as system clock */ + SystemCoreClock = HSE_VALUE; + break; + case 0x08: /* PLL used as system clock */ + /* Get PLL clock source and multiplication factor ----------------------*/ + pllmull = RCC->CFGR & RCC_CFGR_PLLMULL; + pllsource = RCC->CFGR & RCC_CFGR_PLLSRC; + pllmull = (pllmull >> 18) + 2; + + if (pllsource == 0x00) { + /* HSI oscillator clock divided by 2 selected as PLL clock entry */ + SystemCoreClock = (HSI_VALUE >> 1) * pllmull; + } else { + prediv1factor = (RCC->CFGR2 & RCC_CFGR2_PREDIV1) + 1; + /* HSE oscillator clock selected as PREDIV1 clock entry */ + SystemCoreClock = (HSE_VALUE / prediv1factor) * pllmull; + } + break; + default: /* HSI used as system clock */ + SystemCoreClock = HSI_VALUE; + break; + } + /* Compute HCLK clock frequency ----------------*/ + /* Get HCLK prescaler */ + tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> 4)]; + /* HCLK clock frequency */ + SystemCoreClock >>= tmp; +} + +/** + * @brief Configures the System clock source, PLL Multiplier and Divider factors, + * AHB/APBx prescalers and Flash settings + * @note This function should be called only once the RCC clock configuration + * is reset to the default reset state (done in SystemInit() function). + * @param None + * @retval None + */ +static void SetSysClock(void) +{ + __IO uint32_t StartUpCounter = 0, HSEStatus = 0; + +/******************************************************************************/ +/* PLL (clocked by HSE) used as System clock source */ +/******************************************************************************/ + + /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration -----------*/ + /* Enable HSE */ + RCC->CR |= ((uint32_t)RCC_CR_HSEON); + + /* Wait till HSE is ready and if Time out is reached exit */ + do { + HSEStatus = RCC->CR & RCC_CR_HSERDY; + StartUpCounter++; + } while ((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT)); + + if ((RCC->CR & RCC_CR_HSERDY) != RESET) { + HSEStatus = (uint32_t)0x01; + } else { + HSEStatus = (uint32_t)0x00; + } + + if (HSEStatus == (uint32_t)0x01) { + /* Enable Prefetch Buffer and set Flash Latency */ + FLASH->ACR = FLASH_ACR_PRFTBE | (uint32_t)FLASH_ACR_LATENCY_1; + + /* HCLK = SYSCLK / 1 */ + RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1; + + /* PCLK2 = HCLK / 1 */ + RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1; + + /* PCLK1 = HCLK / 2 */ + RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2; + + /* PLL configuration */ + RCC->CFGR &= (uint32_t)((uint32_t) ~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL)); + RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_PREDIV1 | RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLMULL9); + + /* Enable PLL */ + RCC->CR |= RCC_CR_PLLON; + + /* Wait till PLL is ready */ + while ((RCC->CR & RCC_CR_PLLRDY) == 0) {} + + /* Select PLL as system clock source */ + RCC->CFGR &= (uint32_t)((uint32_t) ~(RCC_CFGR_SW)); + RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL; + + /* Wait till PLL is used as system clock source */ + while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)RCC_CFGR_SWS_PLL) {} + } else { /* If HSE fails to start-up, the application will have wrong clock + configuration. User can add here some code to deal with this error */ + } +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/targets/boards/spracingf3/firmware/Makefile b/flight/targets/boards/spracingf3/firmware/Makefile new file mode 100644 index 0000000000..05a2a78177 --- /dev/null +++ b/flight/targets/boards/spracingf3/firmware/Makefile @@ -0,0 +1,118 @@ +# +# Copyright (C) 2015-2016, The LibrePilot Project, http://www.librepilot.org +# Copyright (C) 2009-2013, The OpenPilot Team, http://www.openpilot.org +# Copyright (C) 2012, PhoenixPilot, http://github.com/PhoenixPilot +# +# 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 FLIGHT_MAKEFILE + $(error Top level Makefile must be used to build this target) +endif + +include ../board-info.mk +include $(FLIGHT_ROOT_DIR)/make/firmware-defs.mk + +# REVO C++ support +USE_CXX = YES + +# ARM DSP library +USE_DSP_LIB ?= NO + +DEBUG = NO + +PIOS_OMITS_USB = YES + +# List of mandatory modules to include +MODULES += Sensors +MODULES += StateEstimation +MODULES += Stabilization +MODULES += ManualControl +MODULES += Receiver +MODULES += Actuator +MODULES += FirmwareIAP +#MODULES += PathPlanner +#MODULES += PathFollower +#MODULES += Osd/osdoutout +#MODULES += Logging +MODULES += Telemetry +#MODULES += Notify + +OPTMODULES += Airspeed +OPTMODULES += AutoTune +OPTMODULES += GPS +OPTMODULES += TxPID +OPTMODULES += CameraStab +OPTMODULES += CameraControl +OPTMODULES += Battery +OPTMODULES += ComUsbBridge +OPTMODULES += UAVOMSPBridge +OPTMODULES += UAVOMavlinkBridge + +SRC += $(FLIGHTLIB)/notification.c + +# Include all camera options +CDEFS += -DUSE_INPUT_LPF -DUSE_GIMBAL_LPF -DUSE_GIMBAL_FF + +# Some diagnostics +CDEFS += -DDIAG_TASKS + +# Misc options +CFLAGS += -ffast-math + +# List C source files here (C dependencies are automatically generated). +# Use file-extension c for "c-only"-files +ifndef TESTAPP + ## Application Core + SRC += $(OPMODULEDIR)/System/systemmod.c + CPPSRC += $(OPSYSTEM)/main.cpp + SRC += $(OPSYSTEM)/pios_board.c + SRC += $(FLIGHTLIB)/alarms.c + SRC += $(OPUAVTALK)/uavtalk.c + SRC += $(OPUAVOBJ)/uavobjectmanager.c + SRC += $(OPUAVOBJ)/uavobjectpersistence.c + SRC += $(OPUAVOBJ)/eventdispatcher.c + SRC += $(PIOSCOMMON)/pios_flashfs_logfs.c + SRC += $(PIOSCOMMON)/pios_flash_jedec.c + + #ifeq ($(DEBUG), YES) + SRC += $(OPSYSTEM)/dcc_stdio.c + SRC += $(OPSYSTEM)/cm3_fault_handlers.c + #endif + + ## Misc library functions + SRC += $(FLIGHTLIB)/instrumentation.c + SRC += $(FLIGHTLIB)/paths.c + SRC += $(FLIGHTLIB)/plans.c + SRC += $(FLIGHTLIB)/WorldMagModel.c + SRC += $(FLIGHTLIB)/insgps13state.c + SRC += $(FLIGHTLIB)/auxmagsupport.c + SRC += $(FLIGHTLIB)/lednotification.c + + ## UAVObjects + include ./UAVObjects.inc + SRC += $(UAVOBJSRC) +else + ## Test Code + SRC += $(OPTESTS)/test_common.c + SRC += $(OPTESTS)/$(TESTAPP).c +endif + +# Optional component libraries +#include $(FLIGHTLIB)/rscode/library.mk +#include $(FLIGHTLIB)/PyMite/pymite.mk + +include $(FLIGHT_ROOT_DIR)/make/apps-defs.mk +include $(FLIGHT_ROOT_DIR)/make/common-defs.mk diff --git a/flight/targets/boards/spracingf3/firmware/UAVObjects.inc b/flight/targets/boards/spracingf3/firmware/UAVObjects.inc new file mode 100644 index 0000000000..c81d7a6dfd --- /dev/null +++ b/flight/targets/boards/spracingf3/firmware/UAVObjects.inc @@ -0,0 +1,136 @@ +# +# Copyright (C) 2016, The LibrePilot Project, http://www.librepilot.org +# Copyright (C) 2009-2013, The OpenPilot Team, http://www.openpilot.org +# +# 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 +# + +# These are the UAVObjects supposed to be build as part of the OpenPilot target +# (all architectures) +UAVOBJSRCFILENAMES = +UAVOBJSRCFILENAMES += statusgrounddrive +UAVOBJSRCFILENAMES += pidstatus +UAVOBJSRCFILENAMES += statusvtolland +UAVOBJSRCFILENAMES += statusvtolautotakeoff +UAVOBJSRCFILENAMES += vtolselftuningstats +UAVOBJSRCFILENAMES += accelgyrosettings +UAVOBJSRCFILENAMES += accessorydesired +UAVOBJSRCFILENAMES += actuatorcommand +UAVOBJSRCFILENAMES += actuatordesired +UAVOBJSRCFILENAMES += actuatorsettings +UAVOBJSRCFILENAMES += attitudesettings +UAVOBJSRCFILENAMES += attitudestate +UAVOBJSRCFILENAMES += gyrostate +UAVOBJSRCFILENAMES += gyrosensor +UAVOBJSRCFILENAMES += accelstate +UAVOBJSRCFILENAMES += accelsensor +UAVOBJSRCFILENAMES += magsensor +UAVOBJSRCFILENAMES += auxmagsensor +UAVOBJSRCFILENAMES += auxmagsettings +UAVOBJSRCFILENAMES += magstate +UAVOBJSRCFILENAMES += barosensor +UAVOBJSRCFILENAMES += airspeedsensor +UAVOBJSRCFILENAMES += airspeedsettings +UAVOBJSRCFILENAMES += airspeedstate +UAVOBJSRCFILENAMES += debuglogsettings +UAVOBJSRCFILENAMES += debuglogcontrol +UAVOBJSRCFILENAMES += debuglogstatus +UAVOBJSRCFILENAMES += debuglogentry +UAVOBJSRCFILENAMES += flightbatterysettings +UAVOBJSRCFILENAMES += firmwareiapobj +UAVOBJSRCFILENAMES += flightbatterystate +UAVOBJSRCFILENAMES += flightplancontrol +UAVOBJSRCFILENAMES += flightplansettings +UAVOBJSRCFILENAMES += flightplanstatus +UAVOBJSRCFILENAMES += flighttelemetrystats +UAVOBJSRCFILENAMES += gcstelemetrystats +UAVOBJSRCFILENAMES += gcsreceiver +UAVOBJSRCFILENAMES += gpspositionsensor +UAVOBJSRCFILENAMES += gpssatellites +UAVOBJSRCFILENAMES += gpstime +UAVOBJSRCFILENAMES += gpsvelocitysensor +UAVOBJSRCFILENAMES += gpssettings +UAVOBJSRCFILENAMES += gpsextendedstatus +UAVOBJSRCFILENAMES += fixedwingpathfollowersettings +UAVOBJSRCFILENAMES += fixedwingpathfollowerstatus +UAVOBJSRCFILENAMES += vtolpathfollowersettings +UAVOBJSRCFILENAMES += groundpathfollowersettings +UAVOBJSRCFILENAMES += homelocation +UAVOBJSRCFILENAMES += i2cstats +UAVOBJSRCFILENAMES += manualcontrolcommand +UAVOBJSRCFILENAMES += manualcontrolsettings +UAVOBJSRCFILENAMES += flightmodesettings +UAVOBJSRCFILENAMES += mixersettings +UAVOBJSRCFILENAMES += mixerstatus +UAVOBJSRCFILENAMES += nedaccel +UAVOBJSRCFILENAMES += objectpersistence +UAVOBJSRCFILENAMES += oplinkreceiver +UAVOBJSRCFILENAMES += overosyncstats +UAVOBJSRCFILENAMES += overosyncsettings +UAVOBJSRCFILENAMES += pathaction +UAVOBJSRCFILENAMES += pathdesired +UAVOBJSRCFILENAMES += pathplan +UAVOBJSRCFILENAMES += pathstatus +UAVOBJSRCFILENAMES += pathsummary +UAVOBJSRCFILENAMES += positionstate +UAVOBJSRCFILENAMES += ratedesired +UAVOBJSRCFILENAMES += ekfconfiguration +UAVOBJSRCFILENAMES += ekfstatevariance +UAVOBJSRCFILENAMES += revocalibration +UAVOBJSRCFILENAMES += revosettings +UAVOBJSRCFILENAMES += sonaraltitude +UAVOBJSRCFILENAMES += stabilizationdesired +UAVOBJSRCFILENAMES += stabilizationsettings +UAVOBJSRCFILENAMES += stabilizationsettingsbank1 +UAVOBJSRCFILENAMES += stabilizationsettingsbank2 +UAVOBJSRCFILENAMES += stabilizationsettingsbank3 +UAVOBJSRCFILENAMES += stabilizationstatus +UAVOBJSRCFILENAMES += stabilizationbank +UAVOBJSRCFILENAMES += systemalarms +UAVOBJSRCFILENAMES += systemsettings +UAVOBJSRCFILENAMES += systemstats +UAVOBJSRCFILENAMES += taskinfo +UAVOBJSRCFILENAMES += callbackinfo +UAVOBJSRCFILENAMES += velocitystate +UAVOBJSRCFILENAMES += velocitydesired +UAVOBJSRCFILENAMES += watchdogstatus +UAVOBJSRCFILENAMES += flightstatus +UAVOBJSRCFILENAMES += hwsettings +UAVOBJSRCFILENAMES += hwspracingf3settings +UAVOBJSRCFILENAMES += receiveractivity +UAVOBJSRCFILENAMES += receiverstatus +UAVOBJSRCFILENAMES += cameradesired +UAVOBJSRCFILENAMES += camerastabsettings +UAVOBJSRCFILENAMES += altitudeholdsettings +UAVOBJSRCFILENAMES += oplinksettings +UAVOBJSRCFILENAMES += oplinkstatus +UAVOBJSRCFILENAMES += altitudefiltersettings +UAVOBJSRCFILENAMES += altitudeholdstatus +UAVOBJSRCFILENAMES += waypoint +UAVOBJSRCFILENAMES += waypointactive +UAVOBJSRCFILENAMES += poilocation +UAVOBJSRCFILENAMES += poilearnsettings +UAVOBJSRCFILENAMES += mpugyroaccelsettings +UAVOBJSRCFILENAMES += txpidsettings +UAVOBJSRCFILENAMES += txpidstatus +UAVOBJSRCFILENAMES += takeofflocation +UAVOBJSRCFILENAMES += perfcounter +UAVOBJSRCFILENAMES += systemidentsettings +UAVOBJSRCFILENAMES += systemidentstate +UAVOBJSRCFILENAMES += cameracontrolsettings +UAVOBJSRCFILENAMES += cameracontrolactivity + +UAVOBJSRC = $(foreach UAVOBJSRCFILE,$(UAVOBJSRCFILENAMES),$(FLIGHT_UAVOBJ_DIR)/$(UAVOBJSRCFILE).c ) +UAVOBJDEFINE = $(foreach UAVOBJSRCFILE,$(UAVOBJSRCFILENAMES),-DUAVOBJ_INIT_$(UAVOBJSRCFILE) ) diff --git a/flight/targets/boards/spracingf3/firmware/cm3_fault_handlers.c b/flight/targets/boards/spracingf3/firmware/cm3_fault_handlers.c new file mode 100644 index 0000000000..cf91428579 --- /dev/null +++ b/flight/targets/boards/spracingf3/firmware/cm3_fault_handlers.c @@ -0,0 +1,93 @@ +/* + * cm3_fault_handlers.c + * + * Created on: Apr 24, 2011 + * Author: msmith + */ + +#include +#include "inc/dcc_stdio.h" +#ifdef STM32F4XX +# include +#endif +#ifdef STM32F3 +# include +#endif +#ifdef STM32F2XX +# include +#endif + +#define FAULT_TRAMPOLINE(_vec) \ + __attribute__((naked, no_instrument_function)) \ + void \ + _vec##_Handler(void) \ + { \ + __asm(".syntax unified\n" \ + "MOVS R0, #4 \n" \ + "MOV R1, LR \n" \ + "TST R0, R1 \n" \ + "BEQ 1f \n" \ + "MRS R0, PSP \n" \ + "B " #_vec "_Handler2 \n" \ + "1: \n" \ + "MRS R0, MSP \n" \ + "B " #_vec "_Handler2 \n" \ + ".syntax divided\n"); \ + } \ + struct hack + +struct cm3_frame { + uint32_t r0; + uint32_t r1; + uint32_t r2; + uint32_t r3; + uint32_t r12; + uint32_t lr; + uint32_t pc; + uint32_t psr; +}; + +FAULT_TRAMPOLINE(HardFault); +FAULT_TRAMPOLINE(BusFault); +FAULT_TRAMPOLINE(UsageFault); + +/* this is a hackaround to avoid an issue where dereferencing SCB seems to result in bad codegen and a link error */ +#define SCB_REG(_reg) (*(uint32_t *)&(SCB->_reg)) + +void HardFault_Handler2(struct cm3_frame *frame) +{ + dbg_write_str("\nHARD FAULT"); + dbg_write_hex32(frame->pc); + dbg_write_char('\n'); + dbg_write_hex32(SCB_REG(HFSR)); + dbg_write_char('\n'); + for (;;) { + ; + } +} + +void BusFault_Handler2(struct cm3_frame *frame) +{ + dbg_write_str("\nBUS FAULT"); + dbg_write_hex32(frame->pc); + dbg_write_char('\n'); + dbg_write_hex32(SCB_REG(CFSR)); + dbg_write_char('\n'); + dbg_write_hex32(SCB_REG(BFAR)); + dbg_write_char('\n'); + for (;;) { + ; + } +} + +void UsageFault_Handler2(struct cm3_frame *frame) +{ + dbg_write_str("\nUSAGE FAULT"); + dbg_write_hex32(frame->pc); + dbg_write_char('\n'); + dbg_write_hex32(SCB_REG(CFSR)); + dbg_write_char('\n'); + for (;;) { + ; + } +} diff --git a/flight/targets/boards/spracingf3/firmware/dcc_stdio.c b/flight/targets/boards/spracingf3/firmware/dcc_stdio.c new file mode 100644 index 0000000000..1a522e9a0d --- /dev/null +++ b/flight/targets/boards/spracingf3/firmware/dcc_stdio.c @@ -0,0 +1,149 @@ +/*************************************************************************** +* Copyright (C) 2008 by Dominic Rath * +* Dominic.Rath@gmx.de * +* Copyright (C) 2008 by Spencer Oliver * +* spen@spen-soft.co.uk * +* Copyright (C) 2008 by Frederik Kriewtz * +* frederik@kriewitz.eu * +* * +* 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 2 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 "inc/dcc_stdio.h" + +#define TARGET_REQ_TRACEMSG 0x00 +#define TARGET_REQ_DEBUGMSG_ASCII 0x01 +#define TARGET_REQ_DEBUGMSG_HEXMSG(size) (0x01 | ((size & 0xff) << 8)) +#define TARGET_REQ_DEBUGCHAR 0x02 + +/* we use the cortex_m3 DCRDR reg to simulate a arm7_9 dcc channel + * DCRDR[7:0] is used by target for status + * DCRDR[15:8] is used by target for write buffer + * DCRDR[23:16] is used for by host for status + * DCRDR[31:24] is used for by host for write buffer */ + +#define NVIC_DBG_DATA_R (*((volatile unsigned short *)0xE000EDF8)) + +#define BUSY 1 + +void dbg_write(unsigned long dcc_data) +{ + int len = 4; + + while (len--) { + /* wait for data ready */ + while (NVIC_DBG_DATA_R & BUSY) { + ; + } + + /* write our data and set write flag - tell host there is data*/ + NVIC_DBG_DATA_R = (unsigned short)(((dcc_data & 0xff) << 8) | BUSY); + dcc_data >>= 8; + } +} + +void dbg_trace_point(unsigned long number) +{ + dbg_write(TARGET_REQ_TRACEMSG | (number << 8)); +} + +void dbg_write_u32(const unsigned long *val, long len) +{ + dbg_write(TARGET_REQ_DEBUGMSG_HEXMSG(4) | ((len & 0xffff) << 16)); + + while (len > 0) { + dbg_write(*val); + + val++; + len--; + } +} + +void dbg_write_u16(const unsigned short *val, long len) +{ + unsigned long dcc_data; + + dbg_write(TARGET_REQ_DEBUGMSG_HEXMSG(2) | ((len & 0xffff) << 16)); + + while (len > 0) { + dcc_data = val[0] + | ((len > 1) ? val[1] << 16 : 0x0000); + + dbg_write(dcc_data); + + val += 2; + len -= 2; + } +} + +void dbg_write_u8(const unsigned char *val, long len) +{ + unsigned long dcc_data; + + dbg_write(TARGET_REQ_DEBUGMSG_HEXMSG(1) | ((len & 0xffff) << 16)); + + while (len > 0) { + dcc_data = val[0] + | ((len > 1) ? val[1] << 8 : 0x00) + | ((len > 2) ? val[2] << 16 : 0x00) + | ((len > 3) ? val[3] << 24 : 0x00); + + dbg_write(dcc_data); + + val += 4; + len -= 4; + } +} + +void dbg_write_str(const char *msg) +{ + long len; + unsigned long dcc_data; + + for (len = 0; msg[len] && (len < 65536); len++) { + ; + } + + dbg_write(TARGET_REQ_DEBUGMSG_ASCII | ((len & 0xffff) << 16)); + + while (len > 0) { + dcc_data = msg[0] + | ((len > 1) ? msg[1] << 8 : 0x00) + | ((len > 2) ? msg[2] << 16 : 0x00) + | ((len > 3) ? msg[3] << 24 : 0x00); + dbg_write(dcc_data); + + msg += 4; + len -= 4; + } +} + +void dbg_write_char(char msg) +{ + dbg_write(TARGET_REQ_DEBUGCHAR | ((msg & 0xff) << 16)); +} + +void dbg_write_hex32(const unsigned long val) +{ + static const char hextab[] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' + }; + + for (int shift = 28; shift >= 0; shift -= 4) { + dbg_write_char(hextab[(val >> shift) & 0xf]); + } +} diff --git a/flight/targets/boards/spracingf3/firmware/inc/FreeRTOSConfig.h b/flight/targets/boards/spracingf3/firmware/inc/FreeRTOSConfig.h new file mode 100644 index 0000000000..5fea013d7a --- /dev/null +++ b/flight/targets/boards/spracingf3/firmware/inc/FreeRTOSConfig.h @@ -0,0 +1,99 @@ +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +/*----------------------------------------------------------- +* Application specific definitions. +* +* These definitions should be adjusted for your particular hardware and +* application requirements. +* +* THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE +* FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. +* +* See http://www.freertos.org/a00110.html. +*----------------------------------------------------------*/ + +/** + * @addtogroup PIOS PIOS + * @{ + * @addtogroup FreeRTOS FreeRTOS + * @{ + */ + +/* Notes: We use 5 task priorities */ + +#define configUSE_PREEMPTION 1 +#define configUSE_IDLE_HOOK 1 +#define configUSE_TICK_HOOK 0 +#define configUSE_MALLOC_FAILED_HOOK 1 +#define configCPU_CLOCK_HZ ((unsigned long)72000000) +#define configTICK_RATE_HZ ((portTickType)1000) +#define configMAX_PRIORITIES ((unsigned portBASE_TYPE)5) +#define configMINIMAL_STACK_SIZE ((unsigned short)512) +#define configTOTAL_HEAP_SIZE ((size_t)(53 * 256)) +#define configMAX_TASK_NAME_LEN (6) +#define configUSE_TRACE_FACILITY 0 +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 0 +#define configUSE_MUTEXES 1 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configUSE_COUNTING_SEMAPHORES 0 +#define configUSE_ALTERNATIVE_API 0 +#define configQUEUE_REGISTRY_SIZE 0 + +/* Co-routine definitions. */ +#define configUSE_CO_ROUTINES 0 +#define configMAX_CO_ROUTINE_PRIORITIES (2) + +/* Set the following definitions to 1 to include the API function, or zero + to exclude the API function. */ + +#define INCLUDE_vTaskPrioritySet 1 +#define INCLUDE_uxTaskPriorityGet 1 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskCleanUpResources 0 +#define INCLUDE_vTaskSuspend 1 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_xTaskGetSchedulerState 0 +#define INCLUDE_xTaskGetCurrentTaskHandle 1 +#define INCLUDE_uxTaskGetStackHighWaterMark 1 + +/* This is the raw value as per the Cortex-M3 NVIC. Values can be 255 + (lowest) to 1 (highest maskable) to 0 (highest non-maskable). */ +#define configKERNEL_INTERRUPT_PRIORITY 15 << 4 /* equivalent to NVIC priority 15 */ + #define configMAX_SYSCALL_INTERRUPT_PRIORITY 3 << 4 /* equivalent to NVIC priority 3 */ + +/* This is the value being used as per the ST library which permits 16 + priority values, 0 to 15. This must correspond to the + configKERNEL_INTERRUPT_PRIORITY setting. Here 15 corresponds to the lowest + NVIC value of 255. */ +#define configLIBRARY_KERNEL_INTERRUPT_PRIORITY 15 + +#if !defined(ARCH_POSIX) && !defined(ARCH_WIN32) +#define CHECK_IRQ_STACK +#endif + +/* Enable run time stats collection */ +#define configGENERATE_RUN_TIME_STATS 1 +#define INCLUDE_uxTaskGetRunTime 1 +#define INCLUDE_xTaskGetIdleTaskHandle 1 +#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() \ + do { \ + (*(unsigned long *)0xe000edfc) |= (1 << 24); /* DEMCR |= DEMCR_TRCENA */ \ + (*(unsigned long *)0xe0001000) |= 1; /* DWT_CTRL |= DWT_CYCCNT_ENA */ \ + } \ + while (0) +#define portGET_RUN_TIME_COUNTER_VALUE() (*(unsigned long *)0xe0001004) /* DWT_CYCCNT */ + +#ifdef DIAG_TASKS +#define configCHECK_FOR_STACK_OVERFLOW 2 +#else +#define configCHECK_FOR_STACK_OVERFLOW 1 +#endif + +/** + * @} + */ + +#endif /* FREERTOS_CONFIG_H */ diff --git a/flight/targets/boards/spracingf3/firmware/inc/dcc_stdio.h b/flight/targets/boards/spracingf3/firmware/inc/dcc_stdio.h new file mode 100644 index 0000000000..3d73549182 --- /dev/null +++ b/flight/targets/boards/spracingf3/firmware/inc/dcc_stdio.h @@ -0,0 +1,36 @@ +/*************************************************************************** +* Copyright (C) 2008 by Dominic Rath * +* Dominic.Rath@gmx.de * +* Copyright (C) 2008 by Spencer Oliver * +* spen@spen-soft.co.uk * +* * +* 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 2 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 DCC_STDIO_H +#define DCC_STDIO_H + +void dbg_trace_point(unsigned long number); + +void dbg_write_u32(const unsigned long *val, long len); +void dbg_write_u16(const unsigned short *val, long len); +void dbg_write_u8(const unsigned char *val, long len); + +void dbg_write_str(const char *msg); +void dbg_write_char(char msg); +void dbg_write_hex32(const unsigned long val); + +#endif /* DCC_STDIO_H */ diff --git a/flight/targets/boards/spracingf3/firmware/inc/openpilot.h b/flight/targets/boards/spracingf3/firmware/inc/openpilot.h new file mode 100644 index 0000000000..5576baca66 --- /dev/null +++ b/flight/targets/boards/spracingf3/firmware/inc/openpilot.h @@ -0,0 +1,52 @@ +/** + ****************************************************************************** + * @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 + +/* OpenPilot Libraries */ +#include +#include +#include +#include + +#include "alarms.h" +#include + +/* Global Functions */ +void OpenPilotInit(void); + +#endif /* OPENPILOT_H */ + +/** + * @} + * @} + */ diff --git a/flight/targets/boards/spracingf3/firmware/inc/pios_board_posix.h b/flight/targets/boards/spracingf3/firmware/inc/pios_board_posix.h new file mode 100644 index 0000000000..16364d7fa0 --- /dev/null +++ b/flight/targets/boards/spracingf3/firmware/inc/pios_board_posix.h @@ -0,0 +1,81 @@ +/** + ****************************************************************************** + * + * @file pios_board.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief Defines board hardware for the OpenPilot Version 1.1 hardware. + * @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_BOARD_H +#define PIOS_BOARD_H + + +// ------------------------ +// PIOS_LED +// ------------------------ +// #define PIOS_LED_LED1_GPIO_PORT GPIOC +// #define PIOS_LED_LED1_GPIO_PIN GPIO_Pin_12 +// #define PIOS_LED_LED1_GPIO_CLK RCC_APB2Periph_GPIOC +// #define PIOS_LED_LED2_GPIO_PORT GPIOC +// #define PIOS_LED_LED2_GPIO_PIN GPIO_Pin_13 +// #define PIOS_LED_LED2_GPIO_CLK RCC_APB2Periph_GPIOC +#define PIOS_LED_NUM 2 +// #define PIOS_LED_PORTS { PIOS_LED_LED1_GPIO_PORT, PIOS_LED_LED2_GPIO_PORT } +// #define PIOS_LED_PINS { PIOS_LED_LED1_GPIO_PIN, PIOS_LED_LED2_GPIO_PIN } +// #define PIOS_LED_CLKS { PIOS_LED_LED1_GPIO_CLK, PIOS_LED_LED2_GPIO_CLK } + + +// ------------------------- +// COM +// +// See also pios_board_posix.c +// ------------------------- +// #define PIOS_USART_TX_BUFFER_SIZE 256 +#define PIOS_COM_BUFFER_SIZE 1024 +#define PIOS_UDP_RX_BUFFER_SIZE PIOS_COM_BUFFER_SIZE + +#define PIOS_COM_TELEM_RF 0 +#define PIOS_COM_GPS 1 +#define PIOS_COM_TELEM_USB 2 + +#ifdef PIOS_ENABLE_AUX_UART +#define PIOS_COM_AUX 3 +#define PIOS_COM_DEBUG PIOS_COM_AUX +#endif + +/** + * glue macros for file IO + * STM32 uses DOSFS for file IO + */ +#define PIOS_FOPEN_READ(filename, file) (file = fopen((char *)filename, "r")) == NULL + +#define PIOS_FOPEN_WRITE(filename, file) (file = fopen((char *)filename, "w")) == NULL + +#define PIOS_FREAD(file, bufferadr, length, resultadr) (*resultadr = fread((uint8_t *)bufferadr, 1, length, *file)) != length + +#define PIOS_FWRITE(file, bufferadr, length, resultadr) *resultadr = fwrite((uint8_t *)bufferadr, 1, length, *file) + + +#define PIOS_FCLOSE(file) fclose(file) + +#define PIOS_FUNLINK(file) unlink((char *)filename) + +#endif /* PIOS_BOARD_H */ diff --git a/flight/targets/boards/spracingf3/firmware/inc/pios_config.h b/flight/targets/boards/spracingf3/firmware/inc/pios_config.h new file mode 100644 index 0000000000..9064b34e23 --- /dev/null +++ b/flight/targets/boards/spracingf3/firmware/inc/pios_config.h @@ -0,0 +1,193 @@ +/** + ****************************************************************************** + * @addtogroup OpenPilotSystem OpenPilot System + * @{ + * @addtogroup OpenPilotCore OpenPilot Core + * @{ + * @file pios_config.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010-2013. + * @author LibrePilot, https://bitbucket.org/librepilot, Copyright (C) 2015 + * @brief PiOS configuration header, the compile time config file for the PIOS. + * Defines which PiOS libraries and features are included in the firmware. + * @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 + +/* + * Below is a complete list of PIOS configurable options. + * Please do not remove or rearrange them. Only comment out + * unused options in the list. See main pios.h header for more + * details. + */ + +/* #define PIOS_INCLUDE_DEBUG_CONSOLE */ +/* #define DEBUG_LEVEL 0 */ +/* #define PIOS_ENABLE_DEBUG_PINS */ + +/* PIOS FreeRTOS support */ +#define PIOS_INCLUDE_FREERTOS + + +/* PIOS CallbackScheduler support */ +#define PIOS_INCLUDE_CALLBACKSCHEDULER + +/* PIOS bootloader helper */ +#define PIOS_INCLUDE_BL_HELPER +/* #define PIOS_INCLUDE_BL_HELPER_WRITE_SUPPORT */ + +/* PIOS system functions */ +#define PIOS_INCLUDE_DELAY +#define PIOS_INCLUDE_INITCALL +#define PIOS_INCLUDE_SYS +#define PIOS_INCLUDE_TASK_MONITOR +// #define PIOS_INCLUDE_INSTRUMENTATION +#define PIOS_INSTRUMENTATION_MAX_COUNTERS 5 + +/* PIOS hardware peripherals */ +#define PIOS_INCLUDE_IRQ +#define PIOS_INCLUDE_RTC +#define PIOS_INCLUDE_TIM +#define PIOS_INCLUDE_USART +/* #define PIOS_INCLUDE_ADC */ +#define PIOS_INCLUDE_I2C +#define PIOS_INCLUDE_SPI +#define PIOS_INCLUDE_GPIO +#define PIOS_INCLUDE_EXTI +// #define PIOS_INCLUDE_WDG + +/* PIOS USB functions */ +/* #define PIOS_INCLUDE_USB */ +/* #define PIOS_INCLUDE_USB_HID */ +/* #define PIOS_INCLUDE_USB_CDC */ +/* #define PIOS_INCLUDE_USB_RCTX */ + +/* PIOS sensor interfaces */ +/* #define PIOS_INCLUDE_ADXL345 */ +/* #define PIOS_INCLUDE_BMA180 */ +/* #define PIOS_INCLUDE_L3GD20 */ +#define PIOS_INCLUDE_MPU6000 +#define PIOS_MPU6000_ACCEL +/* #define PIOS_INCLUDE_HMC5843 */ +#define PIOS_INCLUDE_HMC5X83 +#define PIOS_INCLUDE_HMC5X83_INTERNAL +#define PIOS_HMC5883_HAS_GPIOS +/* #define PIOS_INCLUDE_BMP085 */ +#define PIOS_INCLUDE_MS5611 +/* #define PIOS_INCLUDE_MPXV */ +/* #define PIOS_INCLUDE_ETASV3 */ +/* #define PIOS_INCLUDE_HCSR04 */ + +#define PIOS_SENSOR_RATE 500.0f + +/* PIOS receiver drivers */ +#define PIOS_INCLUDE_PWM +#define PIOS_INCLUDE_PPM +#define PIOS_INCLUDE_PPM_FLEXI +#define PIOS_INCLUDE_DSM +#define PIOS_INCLUDE_SBUS +#define PIOS_INCLUDE_EXBUS +#define PIOS_INCLUDE_SRXL +#define PIOS_INCLUDE_HOTT +#define PIOS_INCLUDE_IBUS +/* #define PIOS_INCLUDE_GCSRCVR */ +/* #define PIOS_INCLUDE_OPLINKRCVR */ + +/* PIOS abstract receiver interface */ +#define PIOS_INCLUDE_RCVR + +/* PIOS common peripherals */ +#define PIOS_INCLUDE_LED +#define PIOS_INCLUDE_IAP +#define PIOS_INCLUDE_SERVO +/* #define PIOS_INCLUDE_I2C_ESC */ +/* #define PIOS_INCLUDE_OVERO */ +/* #define PIOS_OVERO_SPI */ +/* #define PIOS_INCLUDE_SDCARD */ +/* #define LOG_FILENAME "startup.log" */ +#define PIOS_INCLUDE_FLASH +#define PIOS_INCLUDE_FLASH_LOGFS_SETTINGS +#define FLASH_FREERTOS +/* #define PIOS_INCLUDE_FLASH_EEPROM */ +/* #define PIOS_INCLUDE_FLASH_INTERNAL */ + +/* #define PIOS_INCLUDE_DEBUGLOG */ + +/* PIOS radio modules */ +/* #define PIOS_INCLUDE_RFM22B */ +/* #define PIOS_INCLUDE_RFM22B_COM */ +/* #define PIOS_INCLUDE_PPM_OUT */ +/* #define PIOS_RFM22B_DEBUG_ON_TELEM */ + +/* PIOS misc peripherals */ +/* #define PIOS_INCLUDE_VIDEO */ +/* #define PIOS_INCLUDE_WAVE */ +/* #define PIOS_INCLUDE_UDP */ + +/* PIOS abstract comms interface with options */ +#define PIOS_INCLUDE_COM +/* #define PIOS_INCLUDE_COM_MSG */ +#define PIOS_INCLUDE_TELEMETRY_RF +/* #define PIOS_INCLUDE_COM_TELEM */ +/* #define PIOS_INCLUDE_COM_FLEXI */ +/* #define PIOS_INCLUDE_COM_AUX */ +/* #define PIOS_TELEM_PRIORITY_QUEUE */ +#define PIOS_INCLUDE_GPS +//#define PIOS_GPS_MINIMAL +#define PIOS_INCLUDE_GPS_NMEA_PARSER +#define PIOS_INCLUDE_GPS_UBX_PARSER +#define PIOS_INCLUDE_GPS_DJI_PARSER +#define PIOS_GPS_SETS_HOMELOCATION + +/* Stabilization options */ +#define PIOS_QUATERNION_STABILIZATION +/* #define PIOS_EXCLUDE_ADVANCED_FEATURES */ +/* Performance counters */ +#define IDLE_COUNTS_PER_SEC_AT_NO_LOAD 1995998 + +/* Alarm Thresholds */ +#define HEAP_LIMIT_WARNING 220 +#define HEAP_LIMIT_CRITICAL 40 +#define IRQSTACK_LIMIT_WARNING 100 +#define IRQSTACK_LIMIT_CRITICAL 60 +#define CPULOAD_LIMIT_WARNING 85 +#define CPULOAD_LIMIT_CRITICAL 95 + +/* Task stack sizes */ +#define PIOS_ACTUATOR_STACK_SIZE 800 +#define PIOS_MANUAL_STACK_SIZE 935 +#define PIOS_RECEIVER_STACK_SIZE 840 +#define PIOS_SYSTEM_STACK_SIZE 1536 +/* #define PIOS_STABILIZATION_STACK_SIZE 400 */ + + +#define PIOS_TELEM_STACK_SIZE 800 +#define PIOS_EVENTDISPATCHER_STACK_SIZE 256 + +/* This can't be too high to stop eventdispatcher thread overflowing */ +#define PIOS_EVENTDISAPTCHER_QUEUE 10 + +/* Revolution series */ +#define REVOLUTION + +#endif /* PIOS_CONFIG_H */ +/** + * @} + * @} + */ diff --git a/flight/targets/boards/spracingf3/firmware/inc/pios_config_posix.h b/flight/targets/boards/spracingf3/firmware/inc/pios_config_posix.h new file mode 100644 index 0000000000..4e8aa47c66 --- /dev/null +++ b/flight/targets/boards/spracingf3/firmware/inc/pios_config_posix.h @@ -0,0 +1,48 @@ +/** + ****************************************************************************** + * + * @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_POSIX_H +#define PIOS_CONFIG_POSIX_H + + +/* Enable/Disable PiOS Modules */ +#define PIOS_INCLUDE_SYS +#define PIOS_INCLUDE_DELAY +#define PIOS_INCLUDE_LED +#define PIOS_INCLUDE_FREERTOS +#define PIOS_INCLUDE_CALLBACKSCHEDULER +#define PIOS_INCLUDE_TASK_MONITOR +#define PIOS_INCLUDE_COM +#define PIOS_INCLUDE_UDP +#define PIOS_INCLUDE_SERVO + + +/* Defaults for Logging */ +#define LOG_FILENAME "PIOS.LOG" +#define STARTUP_LOG_ENABLED 1 + +#endif /* PIOS_CONFIG_POSIX_H */ diff --git a/flight/targets/boards/spracingf3/firmware/main.cpp b/flight/targets/boards/spracingf3/firmware/main.cpp new file mode 100644 index 0000000000..ab405d4fc0 --- /dev/null +++ b/flight/targets/boards/spracingf3/firmware/main.cpp @@ -0,0 +1,100 @@ +/** + ****************************************************************************** + * @addtogroup LibrePilotSystem LibrePilot System + * @brief These files are the core system files for CopterControl. + * They are the ground layer just above PiOS. In practice, CopterControl actually starts + * in the main() function of coptercontrol.c + * @{ + * @addtogroup LibrePilotCore LibrePilot Core + * @brief This is where the LP firmware starts. Those files also define the compile-time + * options of the firmware. + * @{ + * @file coptercontrol.c + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015. + * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010-2015 + * @brief Sets up and runs main tasks. + * @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 + */ + +extern "C" { +#include "inc/openpilot.h" +#include +#include + + +/* Global Variables */ + +/* Local Variables */ +} +extern void Stack_Change(void); +/** + * OpenPilot Main function: + * + * Initialize PiOS
+ * Create the "System" task (SystemModInitializein Modules/System/systemmod.c)
+ * Start FreeRTOS Scheduler (vTaskStartScheduler) (Now handled by caller) + * If something goes wrong, blink LED1 and LED2 every 100ms + * + */ +int main() +{ + /* NOTE: Do NOT modify the following start-up sequence */ + /* Any new initialization functions should be added in OpenPilotInit() */ + + vPortInitialiseBlocks(); + + /* Brings up System using CMSIS functions, enables the LEDs. */ + PIOS_SYS_Init(); + + + SystemModStart(); + + /* Start the FreeRTOS scheduler, which should never return. + * + * NOTE: OpenPilot runs an operating system (FreeRTOS), which constantly calls + * (schedules) function files (modules). These functions never return from their + * while loops, which explains why each module has a while(1){} segment. Thus, + * the OpenPilot software actually starts at the vTaskStartScheduler() function, + * even though this is somewhat obscure. + * + * In addition, there are many main() functions in the OpenPilot firmware source tree + * This is because each main() refers to a separate hardware platform. Of course, + * C only allows one main(), so only the relevant main() function is compiled when + * making a specific firmware. + * + */ + vTaskStartScheduler(); + + /* If all is well we will never reach here as the scheduler will now be running. */ + + /* Do some indication to user that something bad just happened */ + while (1) { +#if defined(PIOS_LED_HEARTBEAT) + PIOS_LED_Toggle(PIOS_LED_HEARTBEAT); +#endif /* PIOS_LED_HEARTBEAT */ + PIOS_DELAY_WaitmS(100); + } + + return 0; +} + +/** + * @} + * @} + */ diff --git a/flight/targets/boards/spracingf3/firmware/memory.ld b/flight/targets/boards/spracingf3/firmware/memory.ld new file mode 100644 index 0000000000..951620e437 --- /dev/null +++ b/flight/targets/boards/spracingf3/firmware/memory.ld @@ -0,0 +1,7 @@ +MEMORY +{ + BD_INFO (r) : ORIGIN = 0x08004000 - 0x80, LENGTH = 0x000080 + FLASH (rx) : ORIGIN = 0x08004000, LENGTH = 0x03C000 + SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00A000 + CCSRAM (rw) : ORIGIN = 0x10000000, LENGTH = 0x002000 +} diff --git a/flight/targets/boards/spracingf3/firmware/pios_board.c b/flight/targets/boards/spracingf3/firmware/pios_board.c new file mode 100644 index 0000000000..b916110995 --- /dev/null +++ b/flight/targets/boards/spracingf3/firmware/pios_board.c @@ -0,0 +1,280 @@ +/** + ***************************************************************************** + * @file pios_board.c + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015. + * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * PhoenixPilot, http://github.com/PhoenixPilot, Copyright (C) 2012 + * @addtogroup LibrePilotSystem LibrePilot System + * @{ + * @addtogroup LibrePilotCore LibrePilot Core + * @{ + * @brief Defines board specific static initializers for hardware for the CopterControl board. + *****************************************************************************/ +/* + * 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 "inc/openpilot.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef PIOS_INCLUDE_INSTRUMENTATION +#include +#endif + +#include +#include + +/* + * Pull in the board-specific static HW definitions. + * Including .c files is a bit ugly but this allows all of + * the HW definitions to be const and static to limit their + * scope. + * + * NOTE: THIS IS THE ONLY PLACE THAT SHOULD EVER INCLUDE THIS FILE + */ +#include "../board_hw_defs.c" + +static HwSPRacingF3SettingsData boardHwSettings; + +static void hwSPRacingF3SettingsUpdatedCb(__attribute__((unused)) UAVObjEvent *ev) +{ + HwSPRacingF3SettingsData currentBoardHwSettings; + + HwSPRacingF3SettingsGet(¤tBoardHwSettings); + + if (memcmp(¤tBoardHwSettings, &boardHwSettings, sizeof(HwSPRacingF3SettingsData)) != 0) { + ExtendedAlarmsSet(SYSTEMALARMS_ALARM_BOOTFAULT, SYSTEMALARMS_ALARM_CRITICAL, SYSTEMALARMS_EXTENDEDALARMSTATUS_REBOOTREQUIRED, 0); + } +} + +uintptr_t pios_uavo_settings_fs_id; +uintptr_t pios_user_fs_id = 0; + +/** + * PIOS_Board_Init() + * initializes all the core subsystems on this specific hardware + * called from System/openpilot.c + */ + +void PIOS_Board_Init(void) +{ + const struct pios_board_info *bdinfo = &pios_board_info_blob; + +#if defined(PIOS_INCLUDE_LED) + const struct pios_gpio_cfg *led_cfg = PIOS_BOARD_HW_DEFS_GetLedCfg(bdinfo->board_rev); + PIOS_Assert(led_cfg); + PIOS_LED_Init(led_cfg); +#endif /* PIOS_INCLUDE_LED */ + +#ifdef PIOS_INCLUDE_INSTRUMENTATION + PIOS_Instrumentation_Init(PIOS_INSTRUMENTATION_MAX_COUNTERS); +#endif + +#if defined(PIOS_INCLUDE_SPI) + /* Set up the SPI interface to the serial flash */ + + + if (PIOS_SPI_Init(&pios_spi_flash_accel_id, &pios_spi_flash_accel_cfg)) { + PIOS_Assert(0); + } + +#endif + + uintptr_t flash_id; + + if (PIOS_Flash_Jedec_Init(&flash_id, pios_spi_flash_accel_id, 0)) { + PIOS_DEBUG_Assert(0); + } + if (PIOS_FLASHFS_Logfs_Init(&pios_uavo_settings_fs_id, &flashfs_m25p_cfg, &pios_jedec_flash_driver, flash_id)) { + PIOS_DEBUG_Assert(0); + } + + /* Initialize the task monitor */ + if (PIOS_TASK_MONITOR_Initialize(TASKINFO_RUNNING_NUMELEM)) { + PIOS_Assert(0); + } + + /* Initialize the delayed callback library */ + PIOS_CALLBACKSCHEDULER_Initialize(); + + /* Initialize UAVObject libraries */ + EventDispatcherInitialize(); + UAVObjInitialize(); + +#if defined(PIOS_INCLUDE_RTC) + /* Initialize the real-time clock and its associated tick */ + PIOS_RTC_Init(&pios_rtc_main_cfg); +#endif + PIOS_IAP_Init(); + // check for safe mode commands from gcs + if (PIOS_IAP_ReadBootCmd(0) == PIOS_IAP_CLEAR_FLASH_CMD_0 && + PIOS_IAP_ReadBootCmd(1) == PIOS_IAP_CLEAR_FLASH_CMD_1 && + PIOS_IAP_ReadBootCmd(2) == PIOS_IAP_CLEAR_FLASH_CMD_2) { + PIOS_FLASHFS_Format(pios_uavo_settings_fs_id); + PIOS_IAP_WriteBootCmd(0, 0); + PIOS_IAP_WriteBootCmd(1, 0); + PIOS_IAP_WriteBootCmd(2, 0); + } + + HwSettingsInitialize(); + HwSPRacingF3SettingsInitialize(); + +#ifndef ERASE_FLASH +#ifdef PIOS_INCLUDE_WDG + /* Initialize watchdog as early as possible to catch faults during init */ + PIOS_WDG_Init(); +#endif +#endif + + /* Initialize the alarms library */ + AlarmsInitialize(); + + /* Check for repeated boot failures */ + uint16_t boot_count = PIOS_IAP_ReadBootCount(); + if (boot_count < 3) { + PIOS_IAP_WriteBootCount(++boot_count); + AlarmsClear(SYSTEMALARMS_ALARM_BOOTFAULT); + } else { + /* Too many failed boot attempts, force hwsettings to defaults */ + HwSettingsSetDefaults(HwSettingsHandle(), 0); + HwSPRacingF3SettingsSetDefaults(HwSPRacingF3SettingsHandle(), 0); + + AlarmsSet(SYSTEMALARMS_ALARM_BOOTFAULT, SYSTEMALARMS_ALARM_CRITICAL); + } + + /* Set up pulse timers */ + PIOS_TIM_InitClock(&tim_1_cfg); + PIOS_TIM_InitClock(&tim_2_cfg); + PIOS_TIM_InitClock(&tim_3_cfg); + PIOS_TIM_InitClock(&tim_4_cfg); + PIOS_TIM_InitClock(&tim_15_cfg); + PIOS_TIM_InitClock(&tim_16_cfg); + PIOS_TIM_InitClock(&tim_17_cfg); + + HwSPRacingF3SettingsConnectCallback(hwSPRacingF3SettingsUpdatedCb); + + HwSPRacingF3SettingsGet(&boardHwSettings); + + boardHwSettings.UARTPort[0] = HWSPRACINGF3SETTINGS_UARTPORT_TELEMETRY; /* UART1 should always be telemetry */ + boardHwSettings.UARTPort[2] = HWSPRACINGF3SETTINGS_UARTPORT_DISABLED; /* UART3 has conflict with SWD, so we will let it be disabled for a moment */ + + static const PIOS_BOARD_IO_UART_Function uart_function_map[] = { + [HWSPRACINGF3SETTINGS_UARTPORT_TELEMETRY] = PIOS_BOARD_IO_UART_TELEMETRY, + [HWSPRACINGF3SETTINGS_UARTPORT_GPS] = PIOS_BOARD_IO_UART_GPS, + [HWSPRACINGF3SETTINGS_UARTPORT_SBUS] = PIOS_BOARD_IO_UART_SBUS, + [HWSPRACINGF3SETTINGS_UARTPORT_DSM] = PIOS_BOARD_IO_UART_DSM_MAIN, // single DSM instance? ok. + [HWSPRACINGF3SETTINGS_UARTPORT_EXBUS] = PIOS_BOARD_IO_UART_EXBUS, + [HWSPRACINGF3SETTINGS_UARTPORT_HOTTSUMD] = PIOS_BOARD_IO_UART_HOTT_SUMD, + [HWSPRACINGF3SETTINGS_UARTPORT_HOTTSUMH] = PIOS_BOARD_IO_UART_HOTT_SUMH, + [HWSPRACINGF3SETTINGS_UARTPORT_SRXL] = PIOS_BOARD_IO_UART_SRXL, + [HWSPRACINGF3SETTINGS_UARTPORT_IBUS] = PIOS_BOARD_IO_UART_IBUS, + [HWSPRACINGF3SETTINGS_UARTPORT_DEBUGCONSOLE] = PIOS_BOARD_IO_UART_DEBUGCONSOLE, + [HWSPRACINGF3SETTINGS_UARTPORT_COMBRIDGE] = PIOS_BOARD_IO_UART_COMBRIDGE, + [HWSPRACINGF3SETTINGS_UARTPORT_MSP] = PIOS_BOARD_IO_UART_MSP, + [HWSPRACINGF3SETTINGS_UARTPORT_MAVLINK] = PIOS_BOARD_IO_UART_MAVLINK, + }; + + for (unsigned int i = 0; i < HWSPRACINGF3SETTINGS_UARTPORT_NUMELEM; ++i) { + if(boardHwSettings.UARTPort[i] < NELEMENTS(uart_function_map)) { + PIOS_BOARD_IO_Configure_UART(&pios_usart_cfg[i], uart_function_map[boardHwSettings.UARTPort[i]]); + } + } + + /* Configure IO ports (IO-1 & IO-2) */ + + bool use_ppm = false; + + /* then do PPM */ + if ((boardHwSettings.IOPorts == HWSPRACINGF3SETTINGS_IOPORTS_PPMPWM) + || (boardHwSettings.IOPorts == HWSPRACINGF3SETTINGS_IOPORTS_PPM) + || (boardHwSettings.IOPorts == HWSPRACINGF3SETTINGS_IOPORTS_PPMOUTPUTS)) { +#if defined(PIOS_INCLUDE_PPM) + use_ppm = true; + PIOS_BOARD_IO_Configure_PPM_RCVR(&pios_ppm_cfg); +#endif /* PIOS_INCLUDE_PPM */ + } + + if ((boardHwSettings.IOPorts == HWSPRACINGF3SETTINGS_IOPORTS_OUTPUTS) + || (boardHwSettings.IOPorts == HWSPRACINGF3SETTINGS_IOPORTS_PPMOUTPUTS)) { + /* configure remaining inputs as additional outputs */ + } else if ((boardHwSettings.IOPorts == HWSPRACINGF3SETTINGS_IOPORTS_PPMPWM) + || (boardHwSettings.IOPorts == HWSPRACINGF3SETTINGS_IOPORTS_PWM)) { +#if defined(PIOS_INCLUDE_PWM) + /* configure remaining inputs as pwm input */ + + struct pios_pwm_cfg pwm_cfg = pios_pwm_cfg; + + if (use_ppm) { + ++(pwm_cfg.channels); + --(pwm_cfg.num_channels); + } + + PIOS_BOARD_IO_Configure_PWM_RCVR(&pwm_cfg); // is this ok? pwm_cfg is on stack +#endif /* if defined(PIOS_INCLUDE_PWM) */ + } + +#ifndef PIOS_ENABLE_DEBUG_PINS + // TODO: make use of HWSPRACINGF3SETTINGS_IOPORTS_[PPM]OUTPUTS + PIOS_Servo_Init(&pios_servo_cfg); +#else + PIOS_DEBUG_Init(&pios_servo_cfg.channels, pios_servo_cfg.num_channels); +#endif + + switch (boardHwSettings.LEDPort) { + case HWSPRACINGF3SETTINGS_LEDPORT_WS2811: + break; + case HWSPRACINGF3SETTINGS_LEDPORT_OUTPUT: + break; + default:; + } + + if (boardHwSettings.BuzzerPort == HWSPRACINGF3SETTINGS_BUZZERPORT_OUTPUT) { + // enable buzzer somehow + } + + switch (boardHwSettings.SonarPort) { + case HWSPRACINGF3SETTINGS_SONARPORT_HCSR04: + /* enable hcsr04 sonar on this port */ + break; + default:; + } + +#if defined(PIOS_INCLUDE_I2C) + // init I2C1 for use with the internal mag and baro + if (PIOS_I2C_Init(&pios_i2c_id, &pios_i2c_cfg)) { + PIOS_DEBUG_Assert(0); + } +#endif + + PIOS_DELAY_WaitmS(50); + + PIOS_BOARD_Sensors_Configure(); + + /* Make sure we have at least one telemetry link configured or else fail initialization */ + PIOS_Assert(pios_com_telem_rf_id); +} + + +/** + * @} + */ diff --git a/flight/targets/boards/spracingf3/firmware/pios_board_posix.c b/flight/targets/boards/spracingf3/firmware/pios_board_posix.c new file mode 100644 index 0000000000..7fa958a38e --- /dev/null +++ b/flight/targets/boards/spracingf3/firmware/pios_board_posix.c @@ -0,0 +1,145 @@ +/** + ****************************************************************************** + * + * @file pios_board.c + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief Defines board specific static initializers for hardware for the OpenPilot board. + * @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 "inc/openpilot.h" +#include +#include +#include + +/** + * PIOS_Board_Init() + * initializes all the core systems on this specific hardware + * called from System/openpilot.c + */ +void PIOS_Board_Init(void) +{ + /* Delay system */ + PIOS_DELAY_Init(); + + /* Initialize the delayed callback library */ + PIOS_CALLBACKSCHEDULER_Initialize(); + + /* Initialize UAVObject libraries */ + EventDispatcherInitialize(); + UAVObjInitialize(); + + /* Initialize the alarms library */ + AlarmsInitialize(); + + /* Initialize the task monitor */ + if (PIOS_TASK_MONITOR_Initialize(TASKINFO_RUNNING_NUMELEM)) { + PIOS_Assert(0); + } + + /* Initialize the PiOS library */ + PIOS_COM_Init(); +} + + +const struct pios_udp_cfg pios_udp0_cfg = { + .ip = "0.0.0.0", + .port = 9000, +}; +const struct pios_udp_cfg pios_udp1_cfg = { + .ip = "0.0.0.0", + .port = 9001, +}; +const struct pios_udp_cfg pios_udp2_cfg = { + .ip = "0.0.0.0", + .port = 9002, +}; + +#ifdef PIOS_COM_AUX +/* + * AUX USART + */ +const struct pios_udp_cfg pios_udp3_cfg = { + .ip = "0.0.0.0", + .port = 9003, +}; +#endif + +/* + * Board specific number of devices. + */ +struct pios_udp_dev pios_udp_devs[] = { +#define PIOS_UDP_TELEM 0 + { + .cfg = &pios_udp0_cfg, + }, +#define PIOS_UDP_GPS 1 + { + .cfg = &pios_udp1_cfg, + }, +#define PIOS_UDP_LOCAL 2 + { + .cfg = &pios_udp2_cfg, + }, +#ifdef PIOS_COM_AUX +#define PIOS_UDP_AUX 3 + { + .cfg = &pios_udp3_cfg, + }, +#endif +}; + +uint8_t pios_udp_num_devices = NELEMENTS(pios_udp_devs); + +/* + * COM devices + */ + +/* + * Board specific number of devices. + */ +extern const struct pios_com_driver pios_serial_com_driver; +extern const struct pios_com_driver pios_udp_com_driver; + +struct pios_com_dev pios_com_devs[] = { + { + .id = PIOS_UDP_TELEM, + .driver = &pios_udp_com_driver, + }, + { + .id = PIOS_UDP_GPS, + .driver = &pios_udp_com_driver, + }, + { + .id = PIOS_UDP_LOCAL, + .driver = &pios_udp_com_driver, + }, +#ifdef PIOS_COM_AUX + { + .id = PIOS_UDP_AUX, + .driver = &pios_udp_com_driver, + }, +#endif +}; + +const uint8_t pios_com_num_devices = NELEMENTS(pios_com_devs); + +/** + * @} + */ diff --git a/flight/targets/boards/spracingf3/pios_board.h b/flight/targets/boards/spracingf3/pios_board.h new file mode 100644 index 0000000000..828d99d018 --- /dev/null +++ b/flight/targets/boards/spracingf3/pios_board.h @@ -0,0 +1,242 @@ +/** + ****************************************************************************** + * + * @file pios_board.h + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015. + * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * + * @brief Defines board hardware for the OpenPilot Version 1.1 hardware. + * @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_BOARD_H +#define PIOS_BOARD_H +// ------------------------ +// Timers and Channels Used +// ------------------------ +/* + Timer | Channel 1 | Channel 2 | Channel 3 | Channel 4 + ------+-----------+-----------+-----------+---------- + TIM1 | Servo 4 | | | + TIM2 | RC In 5 | RC In 6 | Servo 6 | + TIM3 | Servo 5 | RC In 2 | RC In 3 | RC In 4 + TIM4 | RC In 1 | Servo 3 | Servo 2 | Servo 1 + ------+-----------+-----------+-----------+---------- + */ + +// ------------------------ +// DMA Channels Used +// ------------------------ +/* Channel 1 - */ +/* Channel 2 - */ +/* Channel 3 - */ +/* Channel 4 - */ +/* Channel 5 - */ +/* Channel 6 - */ +/* Channel 7 - */ +/* Channel 8 - */ +/* Channel 9 - */ +/* Channel 10 - */ +/* Channel 11 - */ +/* Channel 12 - */ + +// ------------------------ +// BOOTLOADER_SETTINGS +// ------------------------ +#define BOARD_READABLE true +#define BOARD_WRITABLE true +#define MAX_DEL_RETRYS 3 + +// ------------------------ +// WATCHDOG_SETTINGS +// ------------------------ +#define PIOS_WATCHDOG_TIMEOUT 250 +#define PIOS_WDG_REGISTER RTC_BKP_DR4 +#define PIOS_WDG_ACTUATOR 0x0001 +#define PIOS_WDG_STABILIZATION 0x0002 +#define PIOS_WDG_ATTITUDE 0x0004 +#define PIOS_WDG_MANUAL 0x0008 +#define PIOS_WDG_AUTOTUNE 0x0010 +#define PIOS_WDG_SENSORS 0x0020 + +// ------------------------ +// TELEMETRY +// ------------------------ +#define TELEM_QUEUE_SIZE 10 + +// ------------------------ +// PIOS_LED +// ------------------------ +#define PIOS_LED_HEARTBEAT 0 + +// ------------------------- +// System Settings +// ------------------------- +#define PIOS_MASTER_CLOCK 72000000 + +// ------------------------- +// Interrupt Priorities +// ------------------------- +#define PIOS_IRQ_PRIO_LOW 12 // lower than RTOS +#define PIOS_IRQ_PRIO_MID 8 // higher than RTOS +#define PIOS_IRQ_PRIO_HIGH 5 // for SPI, ADC, I2C etc... +#define PIOS_IRQ_PRIO_HIGHEST 4 // for USART etc... +// ------------------------ +// PIOS_I2C +// See also pios_board.c +// ------------------------ +#define PIOS_I2C_MAX_DEVS 1 +extern uint32_t pios_i2c_id; +#define PIOS_I2C_MAIN_ADAPTER (pios_i2c_id) +#define PIOS_I2C_ESC_ADAPTER (pios_i2c_id) +#define PIOS_I2C_MS5611_INTERNAL_ADAPTER (pios_i2c_id) +#define PIOS_I2C_HMC5X83_INTERNAL_ADAPTER (pios_i2c_id) +#define PIOS_I2C_MPU6000_ADAPTER (pios_i2c_id) +#define PIOS_I2C_EXTERNAL_ADAPTER (pios_i2c_id) + +// ------------------------ +// PIOS_BMP085 +// ------------------------ +#define PIOS_BMP085_OVERSAMPLING 3 + +// ------------------------- +// SPI +// +// See also pios_board.c +// ------------------------- +#define PIOS_SPI_MAX_DEVS 2 + +// ------------------------- +// PIOS_USART +// ------------------------- +#define PIOS_USART_MAX_DEVS 2 + +// ------------------------- +// PIOS_COM +// +// See also pios_board.c +// ------------------------- +#define PIOS_COM_MAX_DEVS 3 + +// ------------------------- +// ADC +// PIOS_ADC_PinGet(0) = Current sensor +// PIOS_ADC_PinGet(1) = RSSI sensor +// PIOS_ADC_PinGet(2) = Battery voltage +// ------------------------- +#define PIOS_DMA_PIN_CONFIG \ + { \ + { GPIOA, GPIO_Pin_5, ADC_Channel_2, false }, /* ADC_1 / Current */ \ + { GPIOB, GPIO_Pin_2, ADC_Channel_12, false }, /* ADC_2 / RSSI */ \ + { GPIOA, GPIO_Pin_4, ADC_Channel_1, false }, /* Battery voltage */ \ + } + +/* we have to do all this to satisfy the PIOS_ADC_MAX_SAMPLES define in pios_adc.h */ +/* which is annoying because this then determines the rate at which we generate buffer turnover events */ +/* the objective here is to get enough buffer space to support 100Hz averaging rate */ +#define PIOS_ADC_NUM_CHANNELS 3 +#define PIOS_ADC_MAX_OVERSAMPLING 32 +#define PIOS_ADC_USE_ADC2 0 + +// ------------------------ +// PIOS_RCVR +// See also pios_board.c +// ------------------------ +#define PIOS_RCVR_MAX_DEVS 3 +#define PIOS_RCVR_MAX_CHANNELS 12 +#define PIOS_GCSRCVR_TIMEOUT_MS 100 + +// ------------------------- +// Receiver PPM input +// ------------------------- +#define PIOS_PPM_MAX_DEVS 1 +#define PIOS_PPM_NUM_INPUTS 16 + +// ------------------------- +// Receiver PWM input +// ------------------------- +#define PIOS_PWM_MAX_DEVS 1 +#define PIOS_PWM_NUM_INPUTS 6 + +// ------------------------- +// Receiver DSM input +// ------------------------- +#define PIOS_DSM_MAX_DEVS 2 +#define PIOS_DSM_NUM_INPUTS 12 + +// ------------------------- +// Receiver S.Bus input +// ------------------------- +#define PIOS_SBUS_MAX_DEVS 1 +#define PIOS_SBUS_NUM_INPUTS (16 + 2) + +// ------------------------- +// Receiver HOTT input +// ------------------------- +#define PIOS_HOTT_MAX_DEVS 1 +#define PIOS_HOTT_NUM_INPUTS 32 + +// ------------------------- +// Receiver EX.Bus input +// ------------------------- +#define PIOS_EXBUS_MAX_DEVS 1 +#define PIOS_EXBUS_NUM_INPUTS 16 + +// ------------------------- +// Receiver Multiplex SRXL input +// ------------------------- +#define PIOS_SRXL_MAX_DEVS 1 +#define PIOS_SRXL_NUM_INPUTS 16 + +// ------------------------- +// Receiver FlySky IBus input +// ------------------------- +#define PIOS_IBUS_MAX_DEVS 1 +#define PIOS_IBUS_NUM_INPUTS 10 + +// ------------------------- +// Servo outputs +// ------------------------- +#define PIOS_SERVO_UPDATE_HZ 50 +#define PIOS_SERVOS_INITIAL_POSITION 0 /* dont want to start motors, have no pulse till settings loaded */ +#define PIOS_SERVO_BANKS 6 + +// -------------------------- +// Timer controller settings +// -------------------------- +#define PIOS_TIM_MAX_DEVS 3 + +// ------------------------- +// GPIO +// ------------------------- +#define PIOS_GPIO_PORTS {} +#define PIOS_GPIO_PINS {} +#define PIOS_GPIO_CLKS {} +#define PIOS_GPIO_NUM 0 + +// ------------------------- +// MPU6000 +// ------------------------- + +#define PIOS_MPU6050_I2C_ADDR_AD0_LOW 0x68 +#define PIOS_MPU6050_I2C_ADDR_AD0_HIGH 0x69 + +#define PIOS_MPU6000_I2C_ADDR PIOS_MPU6050_I2C_ADDR_AD0_LOW + +#endif /* PIOS_BOARD_H */ diff --git a/flight/targets/boards/spracingf3evo/board-info.mk b/flight/targets/boards/spracingf3evo/board-info.mk new file mode 100644 index 0000000000..6f1ac61425 --- /dev/null +++ b/flight/targets/boards/spracingf3evo/board-info.mk @@ -0,0 +1,29 @@ +BOARD_TYPE := 0x10 +BOARD_REVISION := 0x02 +BOOTLOADER_VERSION := 0x04 +HW_TYPE := 0x01 + +MCU := cortex-m4 +PIOS_DEVLIB := $(PIOS)/stm32f30x +CHIP := STM32F303xC +BOARD := STM32F303CCT_SPEV_Rev1 +MODEL := HD +MODEL_SUFFIX := _CC + +OPENOCD_JTAG_CONFIG := foss-jtag.revb.cfg +OPENOCD_CONFIG := stm32f1x.cfg + +# Note: These must match the values in link_$(BOARD)_memory.ld +BL_BANK_BASE := 0x08000000 # Start of bootloader flash +BL_BANK_SIZE := 0x00004000 # Should include BD_INFO region + +# Some KB for settings storage (32kb) +EE_BANK_BASE := 0x08004000 # EEPROM storage area +EE_BANK_SIZE := 0x00008000 # EEPROM storage size + +FW_BANK_BASE := 0x0800C000 # Start of firmware flash +FW_BANK_SIZE := 0x00034000 # Should include FW_DESC_SIZE (208kB) + +FW_DESC_SIZE := 0x00000064 + +OSCILLATOR_FREQ := 8000000 diff --git a/flight/targets/boards/spracingf3evo/board_hw_defs.c b/flight/targets/boards/spracingf3evo/board_hw_defs.c new file mode 100644 index 0000000000..2ada94e07c --- /dev/null +++ b/flight/targets/boards/spracingf3evo/board_hw_defs.c @@ -0,0 +1,902 @@ +/** + ****************************************************************************** + * @file board_hw_defs.c + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015. + * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012. + * PhoenixPilot, http://github.com/PhoenixPilot, Copyright (C) 2012 + * + * @addtogroup OpenPilotSystem OpenPilot System + * @{ + * @addtogroup OpenPilotCore OpenPilot Core + * @{ + * @brief Defines board specific static initializers for hardware for the CopterControl board. + *****************************************************************************/ +/* + * 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 + */ + +#if defined(PIOS_INCLUDE_LED) + +#include +static const struct pios_gpio pios_leds[] = { + [PIOS_LED_HEARTBEAT] = { + .pin = { + .gpio = GPIOB, + .init = { + .GPIO_Pin = GPIO_Pin_8, + .GPIO_Mode = GPIO_Mode_OUT, + .GPIO_OType = GPIO_OType_PP, + .GPIO_Speed = GPIO_Speed_50MHz, + .GPIO_PuPd = GPIO_PuPd_NOPULL, + }, + }, + .active_low = false + }, +}; + +static const struct pios_gpio_cfg pios_led_cfg = { + .gpios = pios_leds, + .num_gpios = NELEMENTS(pios_leds), +}; + +const struct pios_gpio_cfg *PIOS_BOARD_HW_DEFS_GetLedCfg(__attribute__((unused)) uint32_t board_revision) +{ + return &pios_led_cfg; +} + +#endif /* PIOS_INCLUDE_LED */ + +#if defined(PIOS_INCLUDE_SPI) + +#include + +/* Gyro interface */ + +void PIOS_SPI_MPU9250_irq_handler(void); +void DMA1_Channel2_IRQHandler() __attribute__((alias("PIOS_SPI_MPU9250_irq_handler"))); +void DMA1_Channel3_IRQHandler() __attribute__((alias("PIOS_SPI_MPU9250_irq_handler"))); + +static const struct pios_spi_cfg pios_spi_mpu9250_cfg = { + .regs = SPI1, + .init = { + .SPI_Mode = SPI_Mode_Master, + .SPI_Direction = SPI_Direction_2Lines_FullDuplex, + .SPI_DataSize = SPI_DataSize_8b, + .SPI_NSS = SPI_NSS_Soft, + .SPI_FirstBit = SPI_FirstBit_MSB, + .SPI_CRCPolynomial = 7, + .SPI_CPOL = SPI_CPOL_High, + .SPI_CPHA = SPI_CPHA_2Edge, + .SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16, /* 10 Mhz */ + }, + .use_crc = false, + .dma = { + .ahb_clk = RCC_AHBPeriph_DMA1, + + .irq = { + .flags = (DMA1_FLAG_TC2 | DMA1_FLAG_TE2 | DMA1_FLAG_HT2 | DMA1_FLAG_GL2), + .init = { + .NVIC_IRQChannel = DMA1_Channel2_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, + + .rx = { + .channel = DMA1_Channel2, + .init = { + .DMA_PeripheralBaseAddr = (uint32_t)&(SPI1->DR), + .DMA_DIR = DMA_DIR_PeripheralSRC, + .DMA_PeripheralInc = DMA_PeripheralInc_Disable, + .DMA_MemoryInc = DMA_MemoryInc_Enable, + .DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte, + .DMA_MemoryDataSize = DMA_MemoryDataSize_Byte, + .DMA_Mode = DMA_Mode_Normal, + .DMA_Priority = DMA_Priority_Medium, + .DMA_M2M = DMA_M2M_Disable, + }, + }, + .tx = { + .channel = DMA1_Channel3, + .init = { + .DMA_PeripheralBaseAddr = (uint32_t)&(SPI1->DR), + .DMA_DIR = DMA_DIR_PeripheralDST, + .DMA_PeripheralInc = DMA_PeripheralInc_Disable, + .DMA_MemoryInc = DMA_MemoryInc_Enable, + .DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte, + .DMA_MemoryDataSize = DMA_MemoryDataSize_Byte, + .DMA_Mode = DMA_Mode_Normal, + .DMA_Priority = DMA_Priority_Medium, + .DMA_M2M = DMA_M2M_Disable, + }, + }, + }, + .remap = GPIO_AF_5, + .sclk = { + .gpio = GPIOB, + .init = { + .GPIO_Pin = GPIO_Pin_3, + .GPIO_Speed = GPIO_Speed_50MHz, + .GPIO_Mode = GPIO_Mode_AF, + .GPIO_OType = GPIO_OType_PP, + .GPIO_PuPd = GPIO_PuPd_NOPULL, + }, + }, + .miso = { + .gpio = GPIOB, + .init = { + .GPIO_Pin = GPIO_Pin_4, + .GPIO_Speed = GPIO_Speed_50MHz, + .GPIO_Mode = GPIO_Mode_AF, + .GPIO_OType = GPIO_OType_PP, + .GPIO_PuPd = GPIO_PuPd_NOPULL, + }, + }, + .mosi = { + .gpio = GPIOB, + .init = { + .GPIO_Pin = GPIO_Pin_5, + .GPIO_Speed = GPIO_Speed_50MHz, + .GPIO_Mode = GPIO_Mode_AF, + .GPIO_OType = GPIO_OType_PP, + .GPIO_PuPd = GPIO_PuPd_NOPULL, + }, + }, + .slave_count = 1, + .ssel = { + { + .gpio = GPIOB, + .init = { + .GPIO_Pin = GPIO_Pin_9, + .GPIO_Speed = GPIO_Speed_50MHz, + .GPIO_Mode = GPIO_Mode_OUT, + .GPIO_OType = GPIO_OType_PP, + .GPIO_PuPd = GPIO_PuPd_UP + }, + } + }, +}; + +uint32_t pios_spi_mpu9250_id; +void PIOS_SPI_MPU9250_irq_handler(void) +{ + /* Call into the generic code to handle the IRQ for this specific device */ + PIOS_SPI_IRQ_Handler(pios_spi_mpu9250_id); +} + +/* SDCARD Interface + * + * NOTE: Leave this declared as const data so that it ends up in the + * .rodata section (ie. Flash) rather than in the .bss section (RAM). + */ +void PIOS_SPI_SDCARD_irq_handler(void); +void DMA1_Channel4_IRQHandler() __attribute__((alias("PIOS_SPI_SDCARD_irq_handler"))); +void DMA1_Channel5_IRQHandler() __attribute__((alias("PIOS_SPI_SDCARD_irq_handler"))); +static const struct pios_spi_cfg pios_spi_sdcard_cfg = { + .regs = SPI2, + .init = { + .SPI_Mode = SPI_Mode_Master, + .SPI_Direction = SPI_Direction_2Lines_FullDuplex, + .SPI_DataSize = SPI_DataSize_8b, + .SPI_NSS = SPI_NSS_Soft, + .SPI_FirstBit = SPI_FirstBit_MSB, + .SPI_CRCPolynomial = 7, + .SPI_CPOL = SPI_CPOL_High, + .SPI_CPHA = SPI_CPHA_2Edge, + .SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8, + }, + .use_crc = false, + .dma = { + .ahb_clk = RCC_AHBPeriph_DMA1, + + .irq = { + .flags = (DMA1_FLAG_TC4 | DMA1_FLAG_TE4 | DMA1_FLAG_HT4 | DMA1_FLAG_GL4), + .init = { + .NVIC_IRQChannel = DMA1_Channel4_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, + + .rx = { + .channel = DMA1_Channel4, + .init = { + .DMA_PeripheralBaseAddr = (uint32_t)&(SPI2->DR), + .DMA_DIR = DMA_DIR_PeripheralSRC, + .DMA_PeripheralInc = DMA_PeripheralInc_Disable, + .DMA_MemoryInc = DMA_MemoryInc_Enable, + .DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte, + .DMA_MemoryDataSize = DMA_MemoryDataSize_Byte, + .DMA_Mode = DMA_Mode_Normal, + .DMA_Priority = DMA_Priority_High, + .DMA_M2M = DMA_M2M_Disable, + }, + }, + .tx = { + .channel = DMA1_Channel5, + .init = { + .DMA_PeripheralBaseAddr = (uint32_t)&(SPI2->DR), + .DMA_DIR = DMA_DIR_PeripheralDST, + .DMA_PeripheralInc = DMA_PeripheralInc_Disable, + .DMA_MemoryInc = DMA_MemoryInc_Enable, + .DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte, + .DMA_MemoryDataSize = DMA_MemoryDataSize_Byte, + .DMA_Mode = DMA_Mode_Normal, + .DMA_Priority = DMA_Priority_High, + .DMA_M2M = DMA_M2M_Disable, + }, + }, + }, + .remap = GPIO_AF_5, + .sclk = { + .gpio = GPIOB, + .init = { + .GPIO_Pin = GPIO_Pin_13, + .GPIO_Speed = GPIO_Speed_50MHz, + .GPIO_Mode = GPIO_Mode_AF, + .GPIO_OType = GPIO_OType_PP, + .GPIO_PuPd = GPIO_PuPd_NOPULL, + }, + }, + .miso = { + .gpio = GPIOB, + .init = { + .GPIO_Pin = GPIO_Pin_14, + .GPIO_Speed = GPIO_Speed_50MHz, + .GPIO_Mode = GPIO_Mode_AF, /* NOTE: was GPIO_Mode_IN_FLOATING */ + .GPIO_OType = GPIO_OType_PP, + .GPIO_PuPd = GPIO_PuPd_NOPULL, + }, + }, + .mosi = { + .gpio = GPIOB, + .init = { + .GPIO_Pin = GPIO_Pin_15, + .GPIO_Speed = GPIO_Speed_50MHz, + .GPIO_Mode = GPIO_Mode_AF, + .GPIO_OType = GPIO_OType_PP, + .GPIO_PuPd = GPIO_PuPd_NOPULL, + }, + }, + .slave_count = 1, + .ssel = { + { + .gpio = GPIOB, + .init = { + .GPIO_Pin = GPIO_Pin_12, + .GPIO_Speed = GPIO_Speed_50MHz, + .GPIO_Mode = GPIO_Mode_OUT, + .GPIO_OType = GPIO_OType_PP, + .GPIO_PuPd = GPIO_PuPd_UP, + } + }, + }, +}; + +static uint32_t pios_spi_sdcard_id; +void PIOS_SPI_SDCARD_irq_handler(void) +{ + /* Call into the generic code to handle the IRQ for this specific device */ + PIOS_SPI_IRQ_Handler(pios_spi_sdcard_id); +} + +#endif /* PIOS_INCLUDE_SPI */ + +#if defined(PIOS_INCLUDE_FLASH) +#include "pios_flashfs_logfs_priv.h" +#include "pios_flash_jedec_priv.h" +#include "pios_flash_internal_priv.h" + +static const struct pios_flash_internal_cfg flash_internal_system_cfg = {}; + +static const struct flashfs_logfs_cfg flashfs_internal_cfg = { + .fs_magic = 0x99abcfef, + .total_fs_size = EE_BANK_SIZE, /* 32K bytes (2x16KB sectors) */ + .arena_size = 0x00004000, /* 64 * slot size = 16K bytes = 1 sector */ + .slot_size = 0x00000100, /* 256 bytes */ + + .start_offset = EE_BANK_BASE, /* start after the bootloader */ + .sector_size = 0x00004000, /* 16K bytes */ + .page_size = 0x00004000, /* 16K bytes */ +}; + +//static const struct flashfs_logfs_cfg flashfs_internal_user_cfg = { +// .fs_magic = 0x99abcfef, +// .total_fs_size = USER_EE_BANK_SIZE, /* 128K bytes (2x16KB sectors) */ +// .arena_size = 0x00020000, /* 64 * slot size = 16K bytes = 1 sector */ +// .slot_size = 0x00000100, /* 256 bytes */ +// +// .start_offset = USER_EE_BANK_BASE, /* start after the bootloader */ +// .sector_size = 0x00020000, /* 128K bytes */ +// .page_size = 0x00020000, /* 128K bytes */ +//}; +#endif /* PIOS_INCLUDE_FLASH */ + + +/* + * ADC system + */ +#if defined(PIOS_INCLUDE_ADC) +#include "pios_adc_priv.h" +extern void PIOS_ADC_handler(void); +void DMA1_Channel1_IRQHandler() __attribute__((alias("PIOS_ADC_handler"))); +// Remap the ADC DMA handler to this one +static const struct pios_adc_cfg pios_adc_cfg = { + .dma = { + .ahb_clk = RCC_AHBPeriph_DMA1, + .irq = { + .flags = (DMA1_FLAG_TC1 | DMA1_FLAG_TE1 | DMA1_FLAG_HT1 | DMA1_FLAG_GL1), + .init = { + .NVIC_IRQChannel = DMA1_Channel1_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, + .rx = { + .channel = DMA1_Channel1, + .init = { + .DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR, + .DMA_DIR = DMA_DIR_PeripheralSRC, + .DMA_PeripheralInc = DMA_PeripheralInc_Disable, + .DMA_MemoryInc = DMA_MemoryInc_Enable, + .DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word, + .DMA_MemoryDataSize = DMA_MemoryDataSize_Word, + .DMA_Mode = DMA_Mode_Circular, + .DMA_Priority = DMA_Priority_High, + .DMA_M2M = DMA_M2M_Disable, + }, + } + }, + .half_flag = DMA1_IT_HT1, + .full_flag = DMA1_IT_TC1, +}; + +void PIOS_ADC_handler() +{ + PIOS_ADC_DMA_Handler(); +} +#endif /* if defined(PIOS_INCLUDE_ADC) */ + +#include "pios_tim_priv.h" + +static const TIM_TimeBaseInitTypeDef tim_time_base = { + .TIM_Prescaler = (PIOS_MASTER_CLOCK / 1000000) - 1, + .TIM_ClockDivision = TIM_CKD_DIV1, + .TIM_CounterMode = TIM_CounterMode_Up, + .TIM_Period = ((1000000 / PIOS_SERVO_UPDATE_HZ) - 1), + .TIM_RepetitionCounter = 0x0000, +}; + +static const struct pios_tim_clock_cfg tim_1_cfg = { + .timer = TIM1, + .time_base_init = &tim_time_base, + .irq = { + .init = { + .NVIC_IRQChannel = TIM1_CC_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, +}; + +static const struct pios_tim_clock_cfg tim_2_cfg = { + .timer = TIM2, + .time_base_init = &tim_time_base, + .irq = { + .init = { + .NVIC_IRQChannel = TIM2_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, +}; + +static const struct pios_tim_clock_cfg tim_3_cfg = { + .timer = TIM3, + .time_base_init = &tim_time_base, + .irq = { + .init = { + .NVIC_IRQChannel = TIM3_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, +}; + +static const struct pios_tim_clock_cfg tim_4_cfg = { + .timer = TIM4, + .time_base_init = &tim_time_base, + .irq = { + .init = { + .NVIC_IRQChannel = TIM4_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, +}; + +static const struct pios_tim_clock_cfg tim_8_cfg = { + .timer = TIM8, + .time_base_init = &tim_time_base, + .irq = { + .init = { + .NVIC_IRQChannel = TIM8_CC_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, +}; + +static const struct pios_tim_clock_cfg tim_15_cfg = { + .timer = TIM4, + .time_base_init = &tim_time_base, + .irq = { + .init = { + .NVIC_IRQChannel = TIM1_BRK_TIM15_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, +}; + +static const struct pios_tim_clock_cfg tim_16_cfg = { + .timer = TIM4, + .time_base_init = &tim_time_base, + .irq = { + .init = { + .NVIC_IRQChannel = TIM1_UP_TIM16_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, +}; + +static const struct pios_tim_clock_cfg tim_17_cfg = { + .timer = TIM4, + .time_base_init = &tim_time_base, + .irq = { + .init = { + .NVIC_IRQChannel = TIM1_TRG_COM_TIM17_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, +}; + +#include + +#define GPIO_AF_PA1_TIM2 GPIO_AF_1 +#define GPIO_AF_PA0_TIM2 GPIO_AF_1 +#define GPIO_AF_PA8_TIM1 GPIO_AF_6 +#define GPIO_AF_PA2_TIM2 GPIO_AF_1 +#define GPIO_AF_PB6_TIM4 GPIO_AF_2 +#define GPIO_AF_PB5_TIM3 GPIO_AF_2 +#define GPIO_AF_PB0_TIM3 GPIO_AF_2 +#define GPIO_AF_PB1_TIM3 GPIO_AF_2 +#define GPIO_AF_PB9_TIM4 GPIO_AF_2 +#define GPIO_AF_PB8_TIM4 GPIO_AF_2 +#define GPIO_AF_PB7_TIM4 GPIO_AF_2 +#define GPIO_AF_PB4_TIM3 GPIO_AF_2 +#define GPIO_AF_PB11_TIM2 GPIO_AF_1 +#define GPIO_AF_PA15_TIM8 GPIO_AF_2 +#define GPIO_AF_PA3_TIM15 GPIO_AF_9 +#define GPIO_AF_PA6_TIM3 GPIO_AF_2 +#define GPIO_AF_PA7_TIM3 GPIO_AF_2 + +static const struct pios_tim_channel pios_tim_servoport_pins[] = { + TIM_SERVO_CHANNEL_CONFIG(TIM2, 1, A, 0), // bank 1 + TIM_SERVO_CHANNEL_CONFIG(TIM2, 2, A, 1), // bank 1 + TIM_SERVO_CHANNEL_CONFIG(TIM2, 3, A, 2), // bank 1 + TIM_SERVO_CHANNEL_CONFIG(TIM15, 2, A, 3), // bank 2 + TIM_SERVO_CHANNEL_CONFIG(TIM3, 1, A, 6), // bank 3 + TIM_SERVO_CHANNEL_CONFIG(TIM3, 2, A, 7), // bank 3 + TIM_SERVO_CHANNEL_CONFIG(TIM3, 3, B, 0), // bank 3 + TIM_SERVO_CHANNEL_CONFIG(TIM3, 4, B, 1), // bank 3 +}; + +static const struct pios_tim_channel pios_tim_ppm_flexi_port = TIM_SERVO_CHANNEL_CONFIG(TIM2, 4, B, 11); + + +#if defined(PIOS_INCLUDE_USART) + +#define GPIO_AF_USART1 GPIO_AF_7 +#define GPIO_AF_USART2 GPIO_AF_7 +#define GPIO_AF_USART3 GPIO_AF_7 + + +#include "pios_usart_priv.h" +#include "pios_usart_config.h" + +static const struct pios_usart_cfg pios_usart_cfg[] = { + USART_CONFIG(USART1, A, 10, A, 9), + USART_CONFIG(USART2, A, 15, A, 14), + USART_CONFIG(USART3, B, 11, B, 10), +}; + + +#endif /* PIOS_INCLUDE_USART */ + +#if defined(PIOS_INCLUDE_COM) + +#include "pios_com_priv.h" + +#endif /* PIOS_INCLUDE_COM */ + +#if defined(PIOS_INCLUDE_RTC) +/* + * Realtime Clock (RTC) + */ +#include + +void PIOS_RTC_IRQ_Handler(void); +void RTC_WKUP_IRQHandler() __attribute__((alias("PIOS_RTC_IRQ_Handler"))); +static const struct pios_rtc_cfg pios_rtc_main_cfg = { + .clksrc = RCC_RTCCLKSource_HSE_Div32, + .prescaler = 25 - 1, // 8Mhz / 32 / 16 / 25 => 625Hz + .irq = { + .init = { + .NVIC_IRQChannel = RTC_WKUP_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, +}; + +void PIOS_RTC_IRQ_Handler(void) +{ + PIOS_RTC_irq_handler(); +} + +#endif /* if defined(PIOS_INCLUDE_RTC) */ + +#if defined(PIOS_INCLUDE_SERVO) && defined(PIOS_INCLUDE_TIM) +/* + * Servo outputs + */ +#include + +const struct pios_servo_cfg pios_servo_cfg = { + .tim_oc_init = { + .TIM_OCMode = TIM_OCMode_PWM1, + .TIM_OutputState = TIM_OutputState_Enable, + .TIM_OutputNState = TIM_OutputNState_Disable, + .TIM_Pulse = PIOS_SERVOS_INITIAL_POSITION, + .TIM_OCPolarity = TIM_OCPolarity_High, + .TIM_OCNPolarity = TIM_OCPolarity_High, + .TIM_OCIdleState = TIM_OCIdleState_Reset, + .TIM_OCNIdleState = TIM_OCNIdleState_Reset, + }, + .channels = pios_tim_servoport_pins, + .num_channels = NELEMENTS(pios_tim_servoport_pins), +}; + +#endif /* PIOS_INCLUDE_SERVO && PIOS_INCLUDE_TIM */ + +/* + * PPM Inputs + */ +#if defined(PIOS_INCLUDE_PPM) +#include + +static const struct pios_tim_channel pios_tim_ppm_channel = TIM_SERVO_CHANNEL_CONFIG(TIM8, 1, A, 15); + +const struct pios_ppm_cfg pios_ppm_cfg = { + .tim_ic_init = { + .TIM_ICPolarity = TIM_ICPolarity_Rising, + .TIM_ICSelection = TIM_ICSelection_DirectTI, + .TIM_ICPrescaler = TIM_ICPSC_DIV1, + .TIM_ICFilter = 0x0, + }, + /* Use only the first channel for ppm */ + .channels = &pios_tim_ppm_channel, + .num_channels = 1, +}; +#endif /* PIOS_INCLUDE_PPM */ + +/* + * SONAR Inputs + */ +#if defined(PIOS_INCLUDE_HCSR04) +#include + +static const struct pios_tim_channel pios_tim_hcsr04_port_all_channels[] = { + { + .timer = TIM3, + .timer_chan = TIM_Channel_2, + .pin = { + .gpio = GPIOB, + .init = { + .GPIO_Pin = GPIO_Pin_5, + .GPIO_Mode = GPIO_Mode_IPD, + .GPIO_Speed = GPIO_Speed_2MHz, + }, + }, + .remap = GPIO_PartialRemap_TIM3, + }, +}; + +const struct pios_hcsr04_cfg pios_hcsr04_cfg = { + .tim_ic_init = { + .TIM_ICPolarity = TIM_ICPolarity_Rising, + .TIM_ICSelection = TIM_ICSelection_DirectTI, + .TIM_ICPrescaler = TIM_ICPSC_DIV1, + .TIM_ICFilter = 0x0, + }, + .channels = pios_tim_hcsr04_port_all_channels, + .num_channels = NELEMENTS(pios_tim_hcsr04_port_all_channels), + .trigger = { + .gpio = GPIOB, + .init = { + .GPIO_Pin = GPIO_Pin_6, + .GPIO_Mode = GPIO_Mode_Out_PP, + .GPIO_Speed = GPIO_Speed_2MHz, + }, + }, +}; +#endif /* if defined(PIOS_INCLUDE_HCSR04) */ + +#if defined(PIOS_INCLUDE_I2C) + +#include + +/* + * I2C Adapters + */ + +void PIOS_I2C_ev_irq_handler(void); +void PIOS_I2C_er_irq_handler(void); +void I2C1_EV_EXTI23_IRQHandler() __attribute__((alias("PIOS_I2C_ev_irq_handler"))); +void I2C1_ER_IRQHandler() __attribute__((alias("PIOS_I2C_er_irq_handler"))); + +static const struct pios_i2c_adapter_cfg pios_i2c_cfg = { + .regs = I2C1, + .remapSCL = GPIO_AF_4, + .remapSDA = GPIO_AF_4, + .init = { + .I2C_Mode = I2C_Mode_I2C, + .I2C_OwnAddress1 = 0, + .I2C_Ack = I2C_Ack_Enable, + .I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit, + .I2C_DigitalFilter = 0x00, + .I2C_AnalogFilter = I2C_AnalogFilter_Enable, +// .I2C_Timing = 0x70310309, // 50kHz I2C @ 8MHz input -> PRESC=0x7, SCLDEL=0x3, SDADEL=0x1, SCLH=0x03, SCLL=0x09 + .I2C_Timing = 0x00E0257A, // 400 Khz, 72Mhz Clock, Analog Filter Delay ON, Rise 100, Fall 10. + }, + .transfer_timeout_ms = 50, + .scl = { + .gpio = GPIOB, + .init = { + .GPIO_Pin = GPIO_Pin_6, + .GPIO_Mode = GPIO_Mode_AF, + .GPIO_Speed = GPIO_Speed_50MHz, + .GPIO_OType = GPIO_OType_PP, + .GPIO_PuPd = GPIO_PuPd_UP, + }, + .pin_source = GPIO_PinSource6, + }, + .sda = { + .gpio = GPIOB, + .init = { + .GPIO_Pin = GPIO_Pin_7, + .GPIO_Mode = GPIO_Mode_AF, + .GPIO_Speed = GPIO_Speed_50MHz, + .GPIO_OType = GPIO_OType_PP, + .GPIO_PuPd = GPIO_PuPd_UP, + }, + .pin_source = GPIO_PinSource7, + }, + .event = { + .flags = 0, /* FIXME: check this */ + .init = { + .NVIC_IRQChannel = I2C1_EV_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGHEST, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, + .error = { + .flags = 0, /* FIXME: check this */ + .init = { + .NVIC_IRQChannel = I2C1_ER_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGHEST, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, +}; + +uint32_t pios_i2c_id; +void PIOS_I2C_ev_irq_handler(void) +{ + /* Call into the generic code to handle the IRQ for this specific device */ + PIOS_I2C_EV_IRQ_Handler(pios_i2c_id); +} + +void PIOS_I2C_er_irq_handler(void) +{ + /* Call into the generic code to handle the IRQ for this specific device */ + PIOS_I2C_ER_IRQ_Handler(pios_i2c_id); +} + + +#endif /* PIOS_INCLUDE_I2C */ + +#if defined(PIOS_INCLUDE_RCVR) +#include "pios_rcvr_priv.h" + +#endif /* PIOS_INCLUDE_RCVR */ + +#if defined(PIOS_INCLUDE_USB) +#include "pios_usb_priv.h" + +static const struct pios_usb_cfg pios_usb_main_cfg = { + .irq = { + .init = { + .NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_LOW, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, +}; + +const struct pios_usb_cfg *PIOS_BOARD_HW_DEFS_GetUsbCfg(__attribute__((unused)) uint32_t board_revision) +{ + return &pios_usb_main_cfg; +} +#endif /* PIOS_INCLUDE_USB */ + + +#if defined(PIOS_INCLUDE_ADC) +#include "pios_adc_priv.h" +void PIOS_ADC_DMC_irq_handler(void); +void DMA2_Channel1_IRQHandler(void) __attribute__((alias("PIOS_ADC_DMC_irq_handler"))); + +struct pios_adc_cfg pios_adc_cfg = { + .adc_dev = ADC2, + .dma = { + .irq = { + .flags = (DMA2_FLAG_TC1 | DMA2_FLAG_TE1 | DMA2_FLAG_HT1), + .init = { + .NVIC_IRQChannel = DMA2_Channel1_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_LOW, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, + .rx = { + .channel = DMA2_Channel1, + } + }, + .half_flag = DMA2_FLAG_HT1, + .full_flag = DMA2_FLAG_TC1, +}; + +void PIOS_ADC_DMC_irq_handler(void) +{ + /* Call into the generic code to handle the IRQ for this specific device */ + PIOS_ADC_DMA_Handler(); +} +const struct pios_adc_cfg *PIOS_BOARD_HW_DEFS_GetAdcCfg(__attribute__((unused)) uint32_t board_revision) +{ + return &pios_adc_cfg; +} +#endif /* if defined(PIOS_INCLUDE_ADC) */ + +#if defined(PIOS_INCLUDE_HMC5X83) +#include "pios_hmc5x83.h" +pios_hmc5x83_dev_t external_mag = 0; + +static const struct pios_hmc5x83_cfg pios_hmc5x83_external_cfg = { +#ifdef PIOS_HMC5X83_HAS_GPIOS + .exti_cfg = NULL, +#endif + .M_ODR = PIOS_HMC5x83_ODR_75, // if you change this for auxmag, change AUX_MAG_SKIP in sensors.c + .Meas_Conf = PIOS_HMC5x83_MEASCONF_NORMAL, + .Gain = PIOS_HMC5x83_GAIN_1_9, + .Mode = PIOS_HMC5x83_MODE_CONTINUOUS, + .TempCompensation = false, + .Driver = &PIOS_HMC5x83_I2C_DRIVER, + .Orientation = PIOS_HMC5X83_ORIENTATION_EAST_NORTH_UP, // ENU for GPSV9, WND for typical I2C mag +}; +const struct pios_hmc5x83_cfg *PIOS_BOARD_HW_DEFS_GetExternalHMC5x83Cfg(__attribute__((unused)) uint32_t board_revision) +{ + return &pios_hmc5x83_external_cfg; +} +#endif /* PIOS_INCLUDE_HMC5X83 */ + +#ifdef PIOS_INCLUDE_BMP280 +#include "pios_bmp280.h" +static const struct pios_bmp280_cfg bmp280_config = { + .oversampling = BMP280_ULTRA_HIGH_RESOLUTION +}; +const struct pios_bmp280_cfg *PIOS_BOARD_HW_DEFS_GetBMP280Cfg(__attribute__((unused)) uint32_t board_revision) +{ + return &bmp280_config; +} +#endif + +/** + * Configuration for the MPU9250 chip + */ +#if defined(PIOS_INCLUDE_MPU9250) +#include "pios_mpu9250.h" +static const struct pios_exti_cfg pios_exti_mpu9250_cfg __exti_config = { + .vector = PIOS_MPU9250_IRQHandler, + .line = EXTI_Line13, + .pin = { + .gpio = GPIOC, + .init = { + .GPIO_Pin = GPIO_Pin_13, + .GPIO_Speed = GPIO_Speed_50MHz, + .GPIO_Mode = GPIO_Mode_IN, + .GPIO_OType = GPIO_OType_OD, + .GPIO_PuPd = GPIO_PuPd_NOPULL, + }, + }, + .irq = { + .init = { + .NVIC_IRQChannel = EXTI15_10_IRQn, + .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH, + .NVIC_IRQChannelSubPriority = 0, + .NVIC_IRQChannelCmd = ENABLE, + }, + }, + .exti = { + .init = { + .EXTI_Line = EXTI_Line13, // matches above GPIO pin + .EXTI_Mode = EXTI_Mode_Interrupt, + .EXTI_Trigger = EXTI_Trigger_Rising, + .EXTI_LineCmd = ENABLE, + }, + }, +}; + +static const struct pios_mpu9250_cfg pios_mpu9250_cfg = { + .exti_cfg = &pios_exti_mpu9250_cfg, + .Fifo_store = 0, + // Clock at 8 khz + .Smpl_rate_div_no_dlp = 0, + // with dlp on output rate is 1000Hz + .Smpl_rate_div_dlp = 0, + .interrupt_cfg = PIOS_MPU9250_INT_CLR_ANYRD, // | PIOS_MPU9250_INT_LATCH_EN, + .interrupt_en = PIOS_MPU9250_INTEN_DATA_RDY, + .User_ctl = PIOS_MPU9250_USERCTL_DIS_I2C | PIOS_MPU9250_USERCTL_I2C_MST_EN, + .Pwr_mgmt_clk = PIOS_MPU9250_PWRMGMT_PLL_Z_CLK, + .accel_range = PIOS_MPU9250_ACCEL_8G, + .gyro_range = PIOS_MPU9250_SCALE_2000_DEG, + .filter = PIOS_MPU9250_LOWPASS_256_HZ, + .orientation = PIOS_MPU9250_TOP_270DEG, + .fast_prescaler = PIOS_SPI_PRESCALER_4, + .std_prescaler = PIOS_SPI_PRESCALER_64, + .max_downsample = 26, +}; +const struct pios_mpu9250_cfg *PIOS_BOARD_HW_DEFS_GetMPU9250Cfg(__attribute__((unused)) uint32_t board_revision) +{ + return &pios_mpu9250_cfg; +} +#endif /* PIOS_INCLUDE_MPU9250 */ diff --git a/flight/targets/boards/spracingf3evo/bootloader/Makefile b/flight/targets/boards/spracingf3evo/bootloader/Makefile new file mode 100644 index 0000000000..d9f8aa112e --- /dev/null +++ b/flight/targets/boards/spracingf3evo/bootloader/Makefile @@ -0,0 +1,29 @@ +# +# Copyright (c) 2015, The LibrePilot Project, http://www.librepilot.org +# Copyright (c) 2009-2013, The OpenPilot Team, http://www.openpilot.org +# +# 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 FLIGHT_MAKEFILE + $(error Top level Makefile must be used to build this target) +endif + +include ../board-info.mk +include $(FLIGHT_ROOT_DIR)/make/firmware-defs.mk +include $(FLIGHT_ROOT_DIR)/make/boot-defs.mk +include $(FLIGHT_ROOT_DIR)/make/common-defs.mk + +$(info Making bootloader for SPRacingF3_EVO, board revision $(BOARD_REVISION)) diff --git a/flight/targets/boards/spracingf3evo/bootloader/inc/common.h b/flight/targets/boards/spracingf3evo/bootloader/inc/common.h new file mode 100644 index 0000000000..e64b89014c --- /dev/null +++ b/flight/targets/boards/spracingf3evo/bootloader/inc/common.h @@ -0,0 +1,115 @@ +/** + ****************************************************************************** + * @addtogroup CopterControlBL CopterControl BootLoader + * @brief These files contain the code to the CopterControl Bootloader. + * + * @{ + * @file common.c + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief This file contains various common defines for the BootLoader + * @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 COMMON_H_ +#define COMMON_H_ + +// #include "board.h" + +typedef enum { + start, keepgoing, +} DownloadAction; + +/**************************************************/ +/* OP_DFU states */ +/**************************************************/ + +typedef enum { + DFUidle, // 0 + uploading, // 1 + wrong_packet_received, // 2 + too_many_packets, // 3 + too_few_packets, // 4 + Last_operation_Success, // 5 + downloading, // 6 + BLidle, // 7 + Last_operation_failed, // 8 + uploadingStarting, // 9 + outsideDevCapabilities, // 10 + CRC_Fail, // 11 + failed_jump, +// 12 +} DFUStates; +/**************************************************/ +/* OP_DFU commands */ +/**************************************************/ +typedef enum { + Reserved, // 0 + Req_Capabilities, // 1 + Rep_Capabilities, // 2 + EnterDFU, // 3 + JumpFW, // 4 + Reset, // 5 + Abort_Operation, // 6 + Upload, // 7 + Op_END, // 8 + Download_Req, // 9 + Download, // 10 + Status_Request, // 11 + Status_Rep +// 12 +} DFUCommands; + +typedef enum { + High_Density, Medium_Density +} DeviceType; +/**************************************************/ +/* OP_DFU transfer types */ +/**************************************************/ +typedef enum { + FW, // 0 + Descript +// 2 +} DFUTransfer; +/**************************************************/ +/* OP_DFU transfer port */ +/**************************************************/ +typedef enum { + Usb, // 0 + Serial +// 2 +} DFUPort; +/**************************************************/ +/* OP_DFU programable programable HW types */ +/**************************************************/ +typedef enum { + Self_flash, // 0 + Remote_flash_via_spi +// 1 +} DFUProgType; +/**************************************************/ +/* OP_DFU programable sources */ +/**************************************************/ +#define USB 0 +#define SPI 1 + +#define DownloadDelay 100000 + +#define MAX_DEL_RETRYS 3 +#define MAX_WRI_RETRYS 3 + +#endif /* COMMON_H_ */ diff --git a/flight/targets/boards/spracingf3evo/bootloader/inc/pios_config.h b/flight/targets/boards/spracingf3evo/bootloader/inc/pios_config.h new file mode 100644 index 0000000000..43182e4354 --- /dev/null +++ b/flight/targets/boards/spracingf3evo/bootloader/inc/pios_config.h @@ -0,0 +1,53 @@ +/** + ****************************************************************************** + * @addtogroup CopterControlBL CopterControl BootLoader + * @brief These files contain the code to the CopterControl Bootloader. + * @{ + * @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. + * In particular, pios_config.h is where you define which PiOS libraries + * and features are included in the firmware. + * @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_SYS +#define PIOS_INCLUDE_IRQ +#define PIOS_INCLUDE_GPIO +#define PIOS_INCLUDE_USB +#define PIOS_INCLUDE_USB_HID +#define PIOS_INCLUDE_LED +#define PIOS_INCLUDE_IAP +#define PIOS_INCLUDE_COM +#define PIOS_INCLUDE_COM_MSG +#define PIOS_INCLUDE_BL_HELPER +#define PIOS_INCLUDE_BL_HELPER_WRITE_SUPPORT + +#endif /* PIOS_CONFIG_H */ + +/** + * @} + * @} + */ diff --git a/flight/targets/boards/spracingf3evo/bootloader/inc/pios_usb_board_data.h b/flight/targets/boards/spracingf3evo/bootloader/inc/pios_usb_board_data.h new file mode 100644 index 0000000000..5a40bf4cf2 --- /dev/null +++ b/flight/targets/boards/spracingf3evo/bootloader/inc/pios_usb_board_data.h @@ -0,0 +1,53 @@ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_USB_BOARD Board specific USB definitions + * @brief Board specific USB definitions + * @{ + * + * @file pios_usb_board_data.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief Board specific USB 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_USB_BOARD_DATA_H +#define PIOS_USB_BOARD_DATA_H + +// Note : changing below length will require changes to the USB buffer setup +#define PIOS_USB_BOARD_HID_DATA_LENGTH 64 + +#define PIOS_USB_BOARD_EP_NUM 2 + +#include /* struct usb_* */ + +#define PIOS_USB_BOARD_PRODUCT_ID USB_PRODUCT_ID_COPTERCONTROL +#define PIOS_USB_BOARD_DEVICE_VER USB_OP_DEVICE_VER(USB_OP_BOARD_ID_COPTERCONTROL, USB_OP_BOARD_MODE_BL) +#define PIOS_USB_BOARD_SN_SUFFIX "+BL" + +/* + * The bootloader uses a simplified report structure + * BL: ... + * FW: ... + * This define changes the behaviour in pios_usb_hid.c + */ +#define PIOS_USB_BOARD_BL_HID_HAS_NO_LENGTH_BYTE + +#endif /* PIOS_USB_BOARD_DATA_H */ diff --git a/flight/targets/boards/spracingf3evo/bootloader/main.c b/flight/targets/boards/spracingf3evo/bootloader/main.c new file mode 100644 index 0000000000..c21f408ebf --- /dev/null +++ b/flight/targets/boards/spracingf3evo/bootloader/main.c @@ -0,0 +1,229 @@ +/** + ****************************************************************************** + * @addtogroup CopterControlBL CopterControl BootLoader + * @brief These files contain the code to the CopterControl Bootloader. + * + * @{ + * @file main.c + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief This is the file with the main function of the OpenPilot BootLoader + * @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 +#include +#include +#include +#include +#include +#include +#include +#include + +extern void FLASH_Download(); +#define BSL_HOLD_STATE ((PIOS_USB_DETECT_GPIO_PORT->IDR & PIOS_USB_DETECT_GPIO_PIN) ? 0 : 1) + +/* Private typedef -----------------------------------------------------------*/ +typedef void (*pFunction)(void); +/* Private define ------------------------------------------------------------*/ +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +pFunction Jump_To_Application; +uint32_t JumpAddress; + +/// LEDs PWM +uint32_t period1 = 5000; // 5 mS +uint32_t sweep_steps1 = 100; // * 5 mS -> 500 mS +uint32_t period2 = 5000; // 5 mS +uint32_t sweep_steps2 = 100; // * 5 mS -> 500 mS + + +//////////////////////////////////////// +uint8_t tempcount = 0; + +/* Extern variables ----------------------------------------------------------*/ +DFUStates DeviceState; +int16_t status = 0; +uint8_t JumpToApp = FALSE; +uint8_t GO_dfu = FALSE; +uint8_t USB_connected = FALSE; +uint8_t User_DFU_request = FALSE; +static uint8_t mReceive_Buffer[63]; +/* Private function prototypes -----------------------------------------------*/ +uint32_t LedPWM(uint32_t pwm_period, uint32_t pwm_sweep_steps, uint32_t count); +uint8_t processRX(); +void jump_to_app(); + +int main() +{ + PIOS_SYS_Init(); + PIOS_Board_Init(); + PIOS_IAP_Init(); + + USB_connected = PIOS_USB_CableConnected(0); + + if (PIOS_IAP_CheckRequest() == TRUE) { + PIOS_DELAY_WaitmS(1000); + User_DFU_request = TRUE; + PIOS_IAP_ClearRequest(); + } + + GO_dfu = (USB_connected == TRUE) || (User_DFU_request == TRUE); + + if (GO_dfu == TRUE) { + PIOS_Board_Init(); + if (User_DFU_request == TRUE) { + DeviceState = DFUidle; + } else { + DeviceState = BLidle; + } + } else { + JumpToApp = TRUE; + } + + uint32_t stopwatch = 0; + uint32_t prev_ticks = PIOS_DELAY_GetuS(); + while (TRUE) { + /* Update the stopwatch */ + uint32_t elapsed_ticks = PIOS_DELAY_GetuSSince(prev_ticks); + prev_ticks += elapsed_ticks; + stopwatch += elapsed_ticks; + + if (JumpToApp == TRUE) { + jump_to_app(); + } + + switch (DeviceState) { + case Last_operation_Success: + case uploadingStarting: + case DFUidle: + period1 = 5000; + sweep_steps1 = 100; + PIOS_LED_Off(PIOS_LED_HEARTBEAT); + period2 = 0; + break; + case uploading: + period1 = 5000; + sweep_steps1 = 100; + period2 = 2500; + sweep_steps2 = 50; + break; + case downloading: + period1 = 2500; + sweep_steps1 = 50; + PIOS_LED_Off(PIOS_LED_HEARTBEAT); + period2 = 0; + break; + case BLidle: + period1 = 0; + PIOS_LED_On(PIOS_LED_HEARTBEAT); + period2 = 0; + break; + default: // error + period1 = 5000; + sweep_steps1 = 100; + period2 = 5000; + sweep_steps2 = 100; + } + + if (period1 != 0) { + if (LedPWM(period1, sweep_steps1, stopwatch)) { + PIOS_LED_On(PIOS_LED_HEARTBEAT); + } else { + PIOS_LED_Off(PIOS_LED_HEARTBEAT); + } + } else { + PIOS_LED_On(PIOS_LED_HEARTBEAT); + } + + if (period2 != 0) { + if (LedPWM(period2, sweep_steps2, stopwatch)) { + PIOS_LED_On(PIOS_LED_HEARTBEAT); + } else { + PIOS_LED_Off(PIOS_LED_HEARTBEAT); + } + } else { + PIOS_LED_Off(PIOS_LED_HEARTBEAT); + } + + if (stopwatch > 50 * 1000 * 1000) { + stopwatch = 0; + } + if ((stopwatch > 6 * 1000 * 1000) && ((DeviceState == BLidle) /*|| (DeviceState == DFUidle && !USB_connected)*/)) { + JumpToApp = TRUE; + } + + processRX(); + DataDownload(start); + } +} + +void jump_to_app() +{ + const struct pios_board_info *bdinfo = &pios_board_info_blob; + + uint32_t fwIrqStackBase = (*(__IO uint32_t *)bdinfo->fw_base) & 0xFFFE0000; + + // Check for the two possible irqstack locations (sram or core coupled sram) + if (fwIrqStackBase == 0x20000000 || fwIrqStackBase == 0x10000000) { + /* Jump to user application */ + FLASH_Lock(); + RCC_APB2PeriphResetCmd(0xffffffff, ENABLE); + RCC_APB1PeriphResetCmd(0xffffffff, ENABLE); + RCC_APB2PeriphResetCmd(0xffffffff, DISABLE); + RCC_APB1PeriphResetCmd(0xffffffff, DISABLE); + + _SetCNTR(0); // clear interrupt mask + _SetISTR(0); // clear all requests + + JumpAddress = *(__IO uint32_t *)(bdinfo->fw_base + 4); + Jump_To_Application = (pFunction)JumpAddress; + /* Initialize user application's Stack Pointer */ + __set_MSP(*(__IO uint32_t *)bdinfo->fw_base); + Jump_To_Application(); + } else { + DeviceState = failed_jump; + return; + } +} +uint32_t LedPWM(uint32_t pwm_period, uint32_t pwm_sweep_steps, uint32_t count) +{ + uint32_t curr_step = (count / pwm_period) % pwm_sweep_steps; /* 0 - pwm_sweep_steps */ + uint32_t pwm_duty = pwm_period * curr_step / pwm_sweep_steps; /* fraction of pwm_period */ + + uint32_t curr_sweep = (count / (pwm_period * pwm_sweep_steps)); /* ticks once per full sweep */ + + if (curr_sweep & 1) { + pwm_duty = pwm_period - pwm_duty; /* reverse direction in odd sweeps */ + } + return ((count % pwm_period) > pwm_duty) ? 1 : 0; +} + +uint8_t processRX() +{ + if (PIOS_COM_MSG_Receive(PIOS_COM_TELEM_USB, mReceive_Buffer, sizeof(mReceive_Buffer))) { + processComand(mReceive_Buffer); + } + return TRUE; +} + +int32_t platform_senddata(const uint8_t *msg, uint16_t msg_len) +{ + return PIOS_COM_MSG_Send(PIOS_COM_TELEM_USB, msg, msg_len); +} diff --git a/flight/targets/boards/spracingf3evo/bootloader/memory.ld b/flight/targets/boards/spracingf3evo/bootloader/memory.ld new file mode 100644 index 0000000000..f4a1713f82 --- /dev/null +++ b/flight/targets/boards/spracingf3evo/bootloader/memory.ld @@ -0,0 +1,7 @@ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 0x004000 - 0x000080 + BD_INFO (r) : ORIGIN = 0x08004000 - 0x80, LENGTH = 0x000080 + SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x009000 + CCSRAM (rw) : ORIGIN = 0x10000000, LENGTH = 0x002000 +} diff --git a/flight/targets/boards/spracingf3evo/bootloader/pios_board.c b/flight/targets/boards/spracingf3evo/bootloader/pios_board.c new file mode 100644 index 0000000000..f0476cb8ec --- /dev/null +++ b/flight/targets/boards/spracingf3evo/bootloader/pios_board.c @@ -0,0 +1,100 @@ +/** + ****************************************************************************** + * + * @file pios_board.c + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief Defines board specific static initializers for hardware for the CopterControl board. + * @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 +#include +#include + + +#include "pios_usb_board_data_priv.h" +#include "pios_usb_desc_hid_cdc_priv.h" +#include "pios_usb_desc_hid_only_priv.h" +#include "pios_usbhook.h" + +#include + +/* + * Pull in the board-specific static HW definitions. + * Including .c files is a bit ugly but this allows all of + * the HW definitions to be const and static to limit their + * scope. + * + * NOTE: THIS IS THE ONLY PLACE THAT SHOULD EVER INCLUDE THIS FILE + */ +#include "../board_hw_defs.c" + +uint32_t pios_com_telem_usb_id; + +/** + * PIOS_Board_Init() + * initializes all the core subsystems on this specific hardware + * called from System/openpilot.c + */ +static bool board_init_complete = false; +void PIOS_Board_Init(void) +{ + if (board_init_complete) { + return; + } + + /* Enable Prefetch Buffer */ + FLASH_PrefetchBufferCmd(ENABLE); + + /* Flash 2 wait state */ + FLASH_SetLatency(FLASH_Latency_2); + +#if defined(PIOS_INCLUDE_LED) + PIOS_LED_Init(&pios_led_cfg); +#endif /* PIOS_INCLUDE_LED */ + +#if defined(PIOS_INCLUDE_USB) + /* Initialize board specific USB data */ + PIOS_USB_BOARD_DATA_Init(); + + /* Activate the HID-only USB configuration */ + PIOS_USB_DESC_HID_ONLY_Init(); + + uint32_t pios_usb_id; + PIOS_USB_Init(&pios_usb_id, &pios_usb_main_cfg); + +#if defined(PIOS_INCLUDE_USB_HID) && defined(PIOS_INCLUDE_COM_MSG) + uint32_t pios_usb_hid_id; + if (PIOS_USB_HID_Init(&pios_usb_hid_id, &pios_usb_hid_only_cfg, pios_usb_id)) { + PIOS_Assert(0); + } + if (PIOS_COM_MSG_Init(&pios_com_telem_usb_id, &pios_usb_hid_com_driver, pios_usb_hid_id)) { + PIOS_Assert(0); + } +#endif /* PIOS_INCLUDE_USB_HID && PIOS_INCLUDE_COM_MSG */ + +#endif /* PIOS_INCLUDE_USB */ + + RCC_AHBPeriphClockCmd(RCC_AHBPeriph_CRC, ENABLE); // TODO Tirar + + board_init_complete = true; +} + +void PIOS_ADC_DMA_Handler() +{} diff --git a/flight/targets/boards/spracingf3evo/common/sections.ld b/flight/targets/boards/spracingf3evo/common/sections.ld new file mode 100644 index 0000000000..d2901a96e5 --- /dev/null +++ b/flight/targets/boards/spracingf3evo/common/sections.ld @@ -0,0 +1,198 @@ + +/* Section Definitions */ +SECTIONS +{ + /* + * Vectors, code and constant data. + */ + .text : + { + PROVIDE (pios_isr_vector_table_base = .); + KEEP(*(.cpu_vectors)) /* CPU exception vectors */ + KEEP(*(.io_vectors)) /* I/O interrupt vectors */ + *(.text .text.* .gnu.linkonce.t.*) + *(.glue_7t) *(.glue_7) + *(.rodata .rodata* .gnu.linkonce.r.*) + KEEP(*(.keep)) + } > FLASH + + /* + * Init section for UAVObjects. + */ + .initcalluavobj.init : + { + . = ALIGN(4); + __uavobj_initcall_start = .; + KEEP(*(.initcalluavobj.init)) + . = ALIGN(4); + __uavobj_initcall_end = .; + } >FLASH + + /* + * Module init section section + */ + .initcallmodule.init : + { + . = ALIGN(4); + __module_initcall_start = .; + KEEP(*(.initcallmodule.init)) + . = ALIGN(4); + __module_initcall_end = .; + } >FLASH + + + /* + * C++ exception handling. + */ + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > FLASH + .ARM.exidx : + { + __exidx_start = .; + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + __exidx_end = .; + } > FLASH + + /* + * Markers for the end of the 'text' section and the in-flash start of + * non-constant data + */ + . = ALIGN(4); + _etext = .; + _sidata = .; + + /* + * Board info structure, normally only generated by the bootloader but can + * be read by the application. + */ + PROVIDE(pios_board_info_blob = ORIGIN(BD_INFO)); + .boardinfo : + { + . = ALIGN(4); + KEEP(*(.boardinfo)) + . = ALIGN(ORIGIN(BD_INFO)+LENGTH(BD_INFO)); + } > BD_INFO + + /* + * Place the IRQ/bootstrap stack at the bottom of SRAM so that an overflow + * results in a hard fault. + */ + .istack (NOLOAD) : + { + . = ALIGN(4); + _irq_stack_end = . ; + *(.irqstack) + _irq_stack_top = . ; + } > CCSRAM + + + /* + * Non-const initialised data. + */ + .data : AT (_sidata) + { + . = ALIGN(4); + _sdata = .; + *(.data .data.*) + . = ALIGN(4); + _edata = . ; + } > SRAM + + /* + * Uninitialised data (BSS + commons). + */ + .bss (NOLOAD) : + { + _sbss = . ; + *(SORT_BY_ALIGNMENT(.bss*)) + *(COMMON) + _ebss = . ; + PROVIDE ( _end = _ebss ) ; + } > SRAM + + /* + * The heap consumes the remainder of the SRAM. + */ + .heap (NOLOAD) : + { + . = ALIGN(4); + _sheap = . ; + + /* + * This allows us to declare an object or objects up to the minimum acceptable + * heap size and receive a linker error if the space available for the heap is + * not sufficient. + */ + *(.heap) + + /* extend the heap up to the top of SRAM */ + . = ORIGIN(SRAM) + LENGTH(SRAM) - ABSOLUTE(_sheap); + _eheap = .; + } > SRAM + + /* + * 'Fast' memory goes in the CCM SRAM + */ + .fast (NOLOAD) : + { + _sfast = . ; + *(.fast) + _efast = . ; + } > CCSRAM + + /* + * The fastheap consumes the remainder of the CCSRAM. + */ + .fastheap (NOLOAD) : + { + . = ALIGN(4); + _sfastheap = . ; + + /* + * This allows us to declare an object or objects up to the minimum acceptable + * heap size and receive a linker error if the space available for the heap is + * not sufficient. + */ + *(.fastheap) + + /* extend the heap up to the top of SRAM */ + . = ORIGIN(CCSRAM) + LENGTH(CCSRAM) - ABSOLUTE(_sfastheap); + _efastheap = .; + } > CCSRAM + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } +} diff --git a/flight/targets/boards/spracingf3evo/common/system.c b/flight/targets/boards/spracingf3evo/common/system.c new file mode 100644 index 0000000000..d26ba3ad62 --- /dev/null +++ b/flight/targets/boards/spracingf3evo/common/system.c @@ -0,0 +1,354 @@ +/** + ****************************************************************************** + * @file system_stm32f30x.c + * @author MCD Application Team + * @version V1.2.2 + * @date 27-February-2015 + * @brief CMSIS Cortex-M4 Device Peripheral Access Layer System Source File. + * This file contains the system clock configuration for STM32F30x devices, + * and is generated by the clock configuration tool + * stm32f30x_Clock_Configuration_V1.0.0.xls + * + * 1. This file provides two functions and one global variable to be called from + * user application: + * - SystemInit(): Setups the system clock (System clock source, PLL Multiplier + * and Divider factors, AHB/APBx prescalers and Flash settings), + * depending on the configuration made in the clock xls tool. + * This function is called at startup just after reset and + * before branch to main program. This call is made inside + * the "startup_stm32f30x.s" file. + * + * - SystemCoreClock variable: Contains the core clock (HCLK), it can be used + * by the user application to setup the SysTick + * timer or configure other parameters. + * + * - SystemCoreClockUpdate(): Updates the variable SystemCoreClock and must + * be called whenever the core clock is changed + * during program execution. + * + * 2. After each device reset the HSI (8 MHz) is used as system clock source. + * Then SystemInit() function is called, in "startup_stm32f30x.s" file, to + * configure the system clock before to branch to main program. + * + * 3. If the system clock source selected by user fails to startup, the SystemInit() + * function will do nothing and HSI still used as system clock source. User can + * add some code to deal with this issue inside the SetSysClock() function. + * + * 4. The default value of HSE crystal is set to 8MHz, refer to "HSE_VALUE" define + * in "stm32f30x.h" file. When HSE is used as system clock source, directly or + * through PLL, and you are using different crystal you have to adapt the HSE + * value to your own configuration. + * + * 5. This file configures the system clock as follows: + *============================================================================= + * Supported STM32F30x device + *----------------------------------------------------------------------------- + * System Clock source | PLL (HSE) + *----------------------------------------------------------------------------- + * SYSCLK(Hz) | 72000000 + *----------------------------------------------------------------------------- + * HCLK(Hz) | 72000000 + *----------------------------------------------------------------------------- + * AHB Prescaler | 1 + *----------------------------------------------------------------------------- + * APB2 Prescaler | 1 + *----------------------------------------------------------------------------- + * APB1 Prescaler | 2 + *----------------------------------------------------------------------------- + * HSE Frequency(Hz) | 8000000 + *---------------------------------------------------------------------------- + * PLLMUL | 9 + *----------------------------------------------------------------------------- + * PREDIV | 1 + *----------------------------------------------------------------------------- + * USB Clock | DISABLE + *----------------------------------------------------------------------------- + * Flash Latency(WS) | 2 + *----------------------------------------------------------------------------- + * Prefetch Buffer | ON + *----------------------------------------------------------------------------- + *============================================================================= + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2015 STMicroelectronics

+ * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ +/** @addtogroup CMSIS + * @{ + */ + +/** @addtogroup stm32f30x_system + * @{ + */ + +/** @addtogroup STM32F30x_System_Private_Includes + * @{ + */ + +#include "stm32f30x.h" + +/** + * @} + */ + +/* Private typedef -----------------------------------------------------------*/ + +/** @addtogroup STM32F30x_System_Private_Defines + * @{ + */ +/*!< Uncomment the following line if you need to relocate your vector Table in + Internal SRAM. */ +/* #define VECT_TAB_SRAM */ +#define VECT_TAB_OFFSET 0x0 /*!< Vector Table base offset field. + This value must be a multiple of 0x200. */ +/** + * @} + */ + +/* Private macro -------------------------------------------------------------*/ + +/** @addtogroup STM32F30x_System_Private_Variables + * @{ + */ + +uint32_t SystemCoreClock = 72000000; + +__I uint8_t AHBPrescTable[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9 }; + +/** + * @} + */ + +/** @addtogroup STM32F30x_System_Private_FunctionPrototypes + * @{ + */ + +static void SetSysClock(void); + +/** + * @} + */ + +/** @addtogroup STM32F30x_System_Private_Functions + * @{ + */ + +/** + * @brief Setup the microcontroller system + * Initialize the Embedded Flash Interface, the PLL and update the + * SystemFrequency variable. + * @param None + * @retval None + */ +void SystemInit(void) +{ + /* FPU settings ------------------------------------------------------------*/ + #if (__FPU_PRESENT == 1) && (__FPU_USED == 1) + SCB->CPACR |= ((3UL << 10 * 2) | (3UL << 11 * 2)); /* set CP10 and CP11 Full Access */ + #endif + + /* Reset the RCC clock configuration to the default reset state ------------*/ + /* Set HSION bit */ + RCC->CR |= (uint32_t)0x00000001; + + /* Reset CFGR register */ + RCC->CFGR &= 0xF87FC00C; + + /* Reset HSEON, CSSON and PLLON bits */ + RCC->CR &= (uint32_t)0xFEF6FFFF; + + /* Reset HSEBYP bit */ + RCC->CR &= (uint32_t)0xFFFBFFFF; + + /* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE bits */ + RCC->CFGR &= (uint32_t)0xFF80FFFF; + + /* Reset PREDIV1[3:0] bits */ + RCC->CFGR2 &= (uint32_t)0xFFFFFFF0; + + /* Reset USARTSW[1:0], I2CSW and TIMs bits */ + RCC->CFGR3 &= (uint32_t)0xFF00FCCC; + + /* Disable all interrupts */ + RCC->CIR = 0x00000000; + + /* Configure the System clock source, PLL Multiplier and Divider factors, + AHB/APBx prescalers and Flash settings ----------------------------------*/ + SetSysClock(); + +#ifdef VECT_TAB_SRAM + SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */ +#else + SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */ +#endif +} + +/** + * @brief Update SystemCoreClock variable according to Clock Register Values. + * The SystemCoreClock variable contains the core clock (HCLK), it can + * be used by the user application to setup the SysTick timer or configure + * other parameters. + * + * @note Each time the core clock (HCLK) changes, this function must be called + * to update SystemCoreClock variable value. Otherwise, any configuration + * based on this variable will be incorrect. + * + * @note - The system frequency computed by this function is not the real + * frequency in the chip. It is calculated based on the predefined + * constant and the selected clock source: + * + * - If SYSCLK source is HSI, SystemCoreClock will contain the HSI_VALUE(*) + * + * - If SYSCLK source is HSE, SystemCoreClock will contain the HSE_VALUE(**) + * + * - If SYSCLK source is PLL, SystemCoreClock will contain the HSE_VALUE(**) + * or HSI_VALUE(*) multiplied/divided by the PLL factors. + * + * (*) HSI_VALUE is a constant defined in stm32f30x.h file (default value + * 8 MHz) but the real value may vary depending on the variations + * in voltage and temperature. + * + * (**) HSE_VALUE is a constant defined in stm32f30x.h file (default value + * 8 MHz), user has to ensure that HSE_VALUE is same as the real + * frequency of the crystal used. Otherwise, this function may + * have wrong result. + * + * - The result of this function could be not correct when using fractional + * value for HSE crystal. + * + * @param None + * @retval None + */ +void SystemCoreClockUpdate(void) +{ + uint32_t tmp = 0, pllmull = 0, pllsource = 0, prediv1factor = 0; + + /* Get SYSCLK source -------------------------------------------------------*/ + tmp = RCC->CFGR & RCC_CFGR_SWS; + + switch (tmp) { + case 0x00: /* HSI used as system clock */ + SystemCoreClock = HSI_VALUE; + break; + case 0x04: /* HSE used as system clock */ + SystemCoreClock = HSE_VALUE; + break; + case 0x08: /* PLL used as system clock */ + /* Get PLL clock source and multiplication factor ----------------------*/ + pllmull = RCC->CFGR & RCC_CFGR_PLLMULL; + pllsource = RCC->CFGR & RCC_CFGR_PLLSRC; + pllmull = (pllmull >> 18) + 2; + + if (pllsource == 0x00) { + /* HSI oscillator clock divided by 2 selected as PLL clock entry */ + SystemCoreClock = (HSI_VALUE >> 1) * pllmull; + } else { + prediv1factor = (RCC->CFGR2 & RCC_CFGR2_PREDIV1) + 1; + /* HSE oscillator clock selected as PREDIV1 clock entry */ + SystemCoreClock = (HSE_VALUE / prediv1factor) * pllmull; + } + break; + default: /* HSI used as system clock */ + SystemCoreClock = HSI_VALUE; + break; + } + /* Compute HCLK clock frequency ----------------*/ + /* Get HCLK prescaler */ + tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> 4)]; + /* HCLK clock frequency */ + SystemCoreClock >>= tmp; +} + +/** + * @brief Configures the System clock source, PLL Multiplier and Divider factors, + * AHB/APBx prescalers and Flash settings + * @note This function should be called only once the RCC clock configuration + * is reset to the default reset state (done in SystemInit() function). + * @param None + * @retval None + */ +static void SetSysClock(void) +{ + __IO uint32_t StartUpCounter = 0, HSEStatus = 0; + +/******************************************************************************/ +/* PLL (clocked by HSE) used as System clock source */ +/******************************************************************************/ + + /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration -----------*/ + /* Enable HSE */ + RCC->CR |= ((uint32_t)RCC_CR_HSEON); + + /* Wait till HSE is ready and if Time out is reached exit */ + do { + HSEStatus = RCC->CR & RCC_CR_HSERDY; + StartUpCounter++; + } while ((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT)); + + if ((RCC->CR & RCC_CR_HSERDY) != RESET) { + HSEStatus = (uint32_t)0x01; + } else { + HSEStatus = (uint32_t)0x00; + } + + if (HSEStatus == (uint32_t)0x01) { + /* Enable Prefetch Buffer and set Flash Latency */ + FLASH->ACR = FLASH_ACR_PRFTBE | (uint32_t)FLASH_ACR_LATENCY_1; + + /* HCLK = SYSCLK / 1 */ + RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1; + + /* PCLK2 = HCLK / 1 */ + RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1; + + /* PCLK1 = HCLK / 2 */ + RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2; + + /* PLL configuration */ + RCC->CFGR &= (uint32_t)((uint32_t) ~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL)); + RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_PREDIV1 | RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLMULL9); + + /* Enable PLL */ + RCC->CR |= RCC_CR_PLLON; + + /* Wait till PLL is ready */ + while ((RCC->CR & RCC_CR_PLLRDY) == 0) {} + + /* Select PLL as system clock source */ + RCC->CFGR &= (uint32_t)((uint32_t) ~(RCC_CFGR_SW)); + RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL; + + /* Wait till PLL is used as system clock source */ + while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)RCC_CFGR_SWS_PLL) {} + } else { /* If HSE fails to start-up, the application will have wrong clock + configuration. User can add here some code to deal with this error */ + } +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/flight/targets/boards/spracingf3evo/firmware/Makefile b/flight/targets/boards/spracingf3evo/firmware/Makefile new file mode 100644 index 0000000000..30686b69af --- /dev/null +++ b/flight/targets/boards/spracingf3evo/firmware/Makefile @@ -0,0 +1,117 @@ +# +# Copyright (C) 2015-2016, The LibrePilot Project, http://www.librepilot.org +# Copyright (C) 2009-2013, The OpenPilot Team, http://www.openpilot.org +# Copyright (C) 2012, PhoenixPilot, http://github.com/PhoenixPilot +# +# 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 FLIGHT_MAKEFILE + $(error Top level Makefile must be used to build this target) +endif + +include ../board-info.mk +include $(FLIGHT_ROOT_DIR)/make/firmware-defs.mk + +# REVO C++ support +USE_CXX = YES + +# ARM DSP library +USE_DSP_LIB ?= NO + +DEBUG = NO + +# List of mandatory modules to include +MODULES += Sensors +MODULES += StateEstimation +MODULES += Stabilization +MODULES += ManualControl +MODULES += Receiver +MODULES += Actuator +MODULES += FirmwareIAP +#MODULES += PathPlanner +#MODULES += PathFollower +#MODULES += Osd/osdoutout +#MODULES += Logging +MODULES += Telemetry +#MODULES += Notify + +OPTMODULES += Airspeed +OPTMODULES += AutoTune +OPTMODULES += GPS +OPTMODULES += TxPID +OPTMODULES += CameraStab +OPTMODULES += CameraControl +OPTMODULES += Battery +OPTMODULES += ComUsbBridge +OPTMODULES += UAVOMSPBridge +OPTMODULES += UAVOMavlinkBridge + +SRC += $(FLIGHTLIB)/notification.c + +# Include all camera options +CDEFS += -DUSE_INPUT_LPF -DUSE_GIMBAL_LPF -DUSE_GIMBAL_FF + +# Some diagnostics +CDEFS += -DDIAG_TASKS + +# Misc options +CFLAGS += -ffast-math + +# List C source files here (C dependencies are automatically generated). +# Use file-extension c for "c-only"-files +ifndef TESTAPP + ## Application Core + SRC += ../pios_usb_board_data.c + SRC += $(OPMODULEDIR)/System/systemmod.c + CPPSRC += $(OPSYSTEM)/main.cpp + SRC += $(OPSYSTEM)/pios_board.c + SRC += $(FLIGHTLIB)/alarms.c + SRC += $(OPUAVTALK)/uavtalk.c + SRC += $(OPUAVOBJ)/uavobjectmanager.c + SRC += $(OPUAVOBJ)/uavobjectpersistence.c + SRC += $(OPUAVOBJ)/eventdispatcher.c + SRC += $(PIOSCOMMON)/pios_flashfs_logfs.c + SRC += $(PIOSCOMMON)/pios_flash_jedec.c + + #ifeq ($(DEBUG), YES) + SRC += $(OPSYSTEM)/dcc_stdio.c + SRC += $(OPSYSTEM)/cm3_fault_handlers.c + #endif + + ## Misc library functions + SRC += $(FLIGHTLIB)/instrumentation.c + SRC += $(FLIGHTLIB)/paths.c + SRC += $(FLIGHTLIB)/plans.c + SRC += $(FLIGHTLIB)/WorldMagModel.c + SRC += $(FLIGHTLIB)/insgps13state.c + SRC += $(FLIGHTLIB)/auxmagsupport.c + SRC += $(FLIGHTLIB)/lednotification.c + + ## UAVObjects + include ./UAVObjects.inc + SRC += $(UAVOBJSRC) +else + ## Test Code + SRC += $(OPTESTS)/test_common.c + SRC += $(OPTESTS)/$(TESTAPP).c +endif + +# Optional component libraries +#include $(FLIGHTLIB)/rscode/library.mk +#include $(FLIGHTLIB)/PyMite/pymite.mk + +include $(FLIGHT_ROOT_DIR)/make/apps-defs.mk +include $(FLIGHT_ROOT_DIR)/make/common-defs.mk diff --git a/flight/targets/boards/spracingf3evo/firmware/UAVObjects.inc b/flight/targets/boards/spracingf3evo/firmware/UAVObjects.inc new file mode 100644 index 0000000000..00a3fb1180 --- /dev/null +++ b/flight/targets/boards/spracingf3evo/firmware/UAVObjects.inc @@ -0,0 +1,136 @@ +# +# Copyright (C) 2016, The LibrePilot Project, http://www.librepilot.org +# Copyright (C) 2009-2013, The OpenPilot Team, http://www.openpilot.org +# +# 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 +# + +# These are the UAVObjects supposed to be build as part of the OpenPilot target +# (all architectures) +UAVOBJSRCFILENAMES = +UAVOBJSRCFILENAMES += statusgrounddrive +UAVOBJSRCFILENAMES += pidstatus +UAVOBJSRCFILENAMES += statusvtolland +UAVOBJSRCFILENAMES += statusvtolautotakeoff +UAVOBJSRCFILENAMES += vtolselftuningstats +UAVOBJSRCFILENAMES += accelgyrosettings +UAVOBJSRCFILENAMES += accessorydesired +UAVOBJSRCFILENAMES += actuatorcommand +UAVOBJSRCFILENAMES += actuatordesired +UAVOBJSRCFILENAMES += actuatorsettings +UAVOBJSRCFILENAMES += attitudesettings +UAVOBJSRCFILENAMES += attitudestate +UAVOBJSRCFILENAMES += gyrostate +UAVOBJSRCFILENAMES += gyrosensor +UAVOBJSRCFILENAMES += accelstate +UAVOBJSRCFILENAMES += accelsensor +UAVOBJSRCFILENAMES += magsensor +UAVOBJSRCFILENAMES += auxmagsensor +UAVOBJSRCFILENAMES += auxmagsettings +UAVOBJSRCFILENAMES += magstate +UAVOBJSRCFILENAMES += barosensor +UAVOBJSRCFILENAMES += airspeedsensor +UAVOBJSRCFILENAMES += airspeedsettings +UAVOBJSRCFILENAMES += airspeedstate +UAVOBJSRCFILENAMES += debuglogsettings +UAVOBJSRCFILENAMES += debuglogcontrol +UAVOBJSRCFILENAMES += debuglogstatus +UAVOBJSRCFILENAMES += debuglogentry +UAVOBJSRCFILENAMES += flightbatterysettings +UAVOBJSRCFILENAMES += firmwareiapobj +UAVOBJSRCFILENAMES += flightbatterystate +UAVOBJSRCFILENAMES += flightplancontrol +UAVOBJSRCFILENAMES += flightplansettings +UAVOBJSRCFILENAMES += flightplanstatus +UAVOBJSRCFILENAMES += flighttelemetrystats +UAVOBJSRCFILENAMES += gcstelemetrystats +UAVOBJSRCFILENAMES += gcsreceiver +UAVOBJSRCFILENAMES += gpspositionsensor +UAVOBJSRCFILENAMES += gpssatellites +UAVOBJSRCFILENAMES += gpstime +UAVOBJSRCFILENAMES += gpsvelocitysensor +UAVOBJSRCFILENAMES += gpssettings +UAVOBJSRCFILENAMES += gpsextendedstatus +UAVOBJSRCFILENAMES += fixedwingpathfollowersettings +UAVOBJSRCFILENAMES += fixedwingpathfollowerstatus +UAVOBJSRCFILENAMES += vtolpathfollowersettings +UAVOBJSRCFILENAMES += groundpathfollowersettings +UAVOBJSRCFILENAMES += homelocation +UAVOBJSRCFILENAMES += i2cstats +UAVOBJSRCFILENAMES += manualcontrolcommand +UAVOBJSRCFILENAMES += manualcontrolsettings +UAVOBJSRCFILENAMES += flightmodesettings +UAVOBJSRCFILENAMES += mixersettings +UAVOBJSRCFILENAMES += mixerstatus +UAVOBJSRCFILENAMES += nedaccel +UAVOBJSRCFILENAMES += objectpersistence +UAVOBJSRCFILENAMES += oplinkreceiver +UAVOBJSRCFILENAMES += overosyncstats +UAVOBJSRCFILENAMES += overosyncsettings +UAVOBJSRCFILENAMES += pathaction +UAVOBJSRCFILENAMES += pathdesired +UAVOBJSRCFILENAMES += pathplan +UAVOBJSRCFILENAMES += pathstatus +UAVOBJSRCFILENAMES += pathsummary +UAVOBJSRCFILENAMES += positionstate +UAVOBJSRCFILENAMES += ratedesired +UAVOBJSRCFILENAMES += ekfconfiguration +UAVOBJSRCFILENAMES += ekfstatevariance +UAVOBJSRCFILENAMES += revocalibration +UAVOBJSRCFILENAMES += revosettings +UAVOBJSRCFILENAMES += sonaraltitude +UAVOBJSRCFILENAMES += stabilizationdesired +UAVOBJSRCFILENAMES += stabilizationsettings +UAVOBJSRCFILENAMES += stabilizationsettingsbank1 +UAVOBJSRCFILENAMES += stabilizationsettingsbank2 +UAVOBJSRCFILENAMES += stabilizationsettingsbank3 +UAVOBJSRCFILENAMES += stabilizationstatus +UAVOBJSRCFILENAMES += stabilizationbank +UAVOBJSRCFILENAMES += systemalarms +UAVOBJSRCFILENAMES += systemsettings +UAVOBJSRCFILENAMES += systemstats +UAVOBJSRCFILENAMES += taskinfo +UAVOBJSRCFILENAMES += callbackinfo +UAVOBJSRCFILENAMES += velocitystate +UAVOBJSRCFILENAMES += velocitydesired +UAVOBJSRCFILENAMES += watchdogstatus +UAVOBJSRCFILENAMES += flightstatus +UAVOBJSRCFILENAMES += hwsettings +UAVOBJSRCFILENAMES += hwspracingf3evosettings +UAVOBJSRCFILENAMES += receiveractivity +UAVOBJSRCFILENAMES += receiverstatus +UAVOBJSRCFILENAMES += cameradesired +UAVOBJSRCFILENAMES += camerastabsettings +UAVOBJSRCFILENAMES += altitudeholdsettings +UAVOBJSRCFILENAMES += oplinksettings +UAVOBJSRCFILENAMES += oplinkstatus +UAVOBJSRCFILENAMES += altitudefiltersettings +UAVOBJSRCFILENAMES += altitudeholdstatus +UAVOBJSRCFILENAMES += waypoint +UAVOBJSRCFILENAMES += waypointactive +UAVOBJSRCFILENAMES += poilocation +UAVOBJSRCFILENAMES += poilearnsettings +UAVOBJSRCFILENAMES += mpugyroaccelsettings +UAVOBJSRCFILENAMES += txpidsettings +UAVOBJSRCFILENAMES += txpidstatus +UAVOBJSRCFILENAMES += takeofflocation +UAVOBJSRCFILENAMES += perfcounter +UAVOBJSRCFILENAMES += systemidentsettings +UAVOBJSRCFILENAMES += systemidentstate +UAVOBJSRCFILENAMES += cameracontrolsettings +UAVOBJSRCFILENAMES += cameracontrolactivity + +UAVOBJSRC = $(foreach UAVOBJSRCFILE,$(UAVOBJSRCFILENAMES),$(FLIGHT_UAVOBJ_DIR)/$(UAVOBJSRCFILE).c ) +UAVOBJDEFINE = $(foreach UAVOBJSRCFILE,$(UAVOBJSRCFILENAMES),-DUAVOBJ_INIT_$(UAVOBJSRCFILE) ) diff --git a/flight/targets/boards/spracingf3evo/firmware/cm3_fault_handlers.c b/flight/targets/boards/spracingf3evo/firmware/cm3_fault_handlers.c new file mode 100644 index 0000000000..cf91428579 --- /dev/null +++ b/flight/targets/boards/spracingf3evo/firmware/cm3_fault_handlers.c @@ -0,0 +1,93 @@ +/* + * cm3_fault_handlers.c + * + * Created on: Apr 24, 2011 + * Author: msmith + */ + +#include +#include "inc/dcc_stdio.h" +#ifdef STM32F4XX +# include +#endif +#ifdef STM32F3 +# include +#endif +#ifdef STM32F2XX +# include +#endif + +#define FAULT_TRAMPOLINE(_vec) \ + __attribute__((naked, no_instrument_function)) \ + void \ + _vec##_Handler(void) \ + { \ + __asm(".syntax unified\n" \ + "MOVS R0, #4 \n" \ + "MOV R1, LR \n" \ + "TST R0, R1 \n" \ + "BEQ 1f \n" \ + "MRS R0, PSP \n" \ + "B " #_vec "_Handler2 \n" \ + "1: \n" \ + "MRS R0, MSP \n" \ + "B " #_vec "_Handler2 \n" \ + ".syntax divided\n"); \ + } \ + struct hack + +struct cm3_frame { + uint32_t r0; + uint32_t r1; + uint32_t r2; + uint32_t r3; + uint32_t r12; + uint32_t lr; + uint32_t pc; + uint32_t psr; +}; + +FAULT_TRAMPOLINE(HardFault); +FAULT_TRAMPOLINE(BusFault); +FAULT_TRAMPOLINE(UsageFault); + +/* this is a hackaround to avoid an issue where dereferencing SCB seems to result in bad codegen and a link error */ +#define SCB_REG(_reg) (*(uint32_t *)&(SCB->_reg)) + +void HardFault_Handler2(struct cm3_frame *frame) +{ + dbg_write_str("\nHARD FAULT"); + dbg_write_hex32(frame->pc); + dbg_write_char('\n'); + dbg_write_hex32(SCB_REG(HFSR)); + dbg_write_char('\n'); + for (;;) { + ; + } +} + +void BusFault_Handler2(struct cm3_frame *frame) +{ + dbg_write_str("\nBUS FAULT"); + dbg_write_hex32(frame->pc); + dbg_write_char('\n'); + dbg_write_hex32(SCB_REG(CFSR)); + dbg_write_char('\n'); + dbg_write_hex32(SCB_REG(BFAR)); + dbg_write_char('\n'); + for (;;) { + ; + } +} + +void UsageFault_Handler2(struct cm3_frame *frame) +{ + dbg_write_str("\nUSAGE FAULT"); + dbg_write_hex32(frame->pc); + dbg_write_char('\n'); + dbg_write_hex32(SCB_REG(CFSR)); + dbg_write_char('\n'); + for (;;) { + ; + } +} diff --git a/flight/targets/boards/spracingf3evo/firmware/dcc_stdio.c b/flight/targets/boards/spracingf3evo/firmware/dcc_stdio.c new file mode 100644 index 0000000000..1a522e9a0d --- /dev/null +++ b/flight/targets/boards/spracingf3evo/firmware/dcc_stdio.c @@ -0,0 +1,149 @@ +/*************************************************************************** +* Copyright (C) 2008 by Dominic Rath * +* Dominic.Rath@gmx.de * +* Copyright (C) 2008 by Spencer Oliver * +* spen@spen-soft.co.uk * +* Copyright (C) 2008 by Frederik Kriewtz * +* frederik@kriewitz.eu * +* * +* 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 2 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 "inc/dcc_stdio.h" + +#define TARGET_REQ_TRACEMSG 0x00 +#define TARGET_REQ_DEBUGMSG_ASCII 0x01 +#define TARGET_REQ_DEBUGMSG_HEXMSG(size) (0x01 | ((size & 0xff) << 8)) +#define TARGET_REQ_DEBUGCHAR 0x02 + +/* we use the cortex_m3 DCRDR reg to simulate a arm7_9 dcc channel + * DCRDR[7:0] is used by target for status + * DCRDR[15:8] is used by target for write buffer + * DCRDR[23:16] is used for by host for status + * DCRDR[31:24] is used for by host for write buffer */ + +#define NVIC_DBG_DATA_R (*((volatile unsigned short *)0xE000EDF8)) + +#define BUSY 1 + +void dbg_write(unsigned long dcc_data) +{ + int len = 4; + + while (len--) { + /* wait for data ready */ + while (NVIC_DBG_DATA_R & BUSY) { + ; + } + + /* write our data and set write flag - tell host there is data*/ + NVIC_DBG_DATA_R = (unsigned short)(((dcc_data & 0xff) << 8) | BUSY); + dcc_data >>= 8; + } +} + +void dbg_trace_point(unsigned long number) +{ + dbg_write(TARGET_REQ_TRACEMSG | (number << 8)); +} + +void dbg_write_u32(const unsigned long *val, long len) +{ + dbg_write(TARGET_REQ_DEBUGMSG_HEXMSG(4) | ((len & 0xffff) << 16)); + + while (len > 0) { + dbg_write(*val); + + val++; + len--; + } +} + +void dbg_write_u16(const unsigned short *val, long len) +{ + unsigned long dcc_data; + + dbg_write(TARGET_REQ_DEBUGMSG_HEXMSG(2) | ((len & 0xffff) << 16)); + + while (len > 0) { + dcc_data = val[0] + | ((len > 1) ? val[1] << 16 : 0x0000); + + dbg_write(dcc_data); + + val += 2; + len -= 2; + } +} + +void dbg_write_u8(const unsigned char *val, long len) +{ + unsigned long dcc_data; + + dbg_write(TARGET_REQ_DEBUGMSG_HEXMSG(1) | ((len & 0xffff) << 16)); + + while (len > 0) { + dcc_data = val[0] + | ((len > 1) ? val[1] << 8 : 0x00) + | ((len > 2) ? val[2] << 16 : 0x00) + | ((len > 3) ? val[3] << 24 : 0x00); + + dbg_write(dcc_data); + + val += 4; + len -= 4; + } +} + +void dbg_write_str(const char *msg) +{ + long len; + unsigned long dcc_data; + + for (len = 0; msg[len] && (len < 65536); len++) { + ; + } + + dbg_write(TARGET_REQ_DEBUGMSG_ASCII | ((len & 0xffff) << 16)); + + while (len > 0) { + dcc_data = msg[0] + | ((len > 1) ? msg[1] << 8 : 0x00) + | ((len > 2) ? msg[2] << 16 : 0x00) + | ((len > 3) ? msg[3] << 24 : 0x00); + dbg_write(dcc_data); + + msg += 4; + len -= 4; + } +} + +void dbg_write_char(char msg) +{ + dbg_write(TARGET_REQ_DEBUGCHAR | ((msg & 0xff) << 16)); +} + +void dbg_write_hex32(const unsigned long val) +{ + static const char hextab[] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' + }; + + for (int shift = 28; shift >= 0; shift -= 4) { + dbg_write_char(hextab[(val >> shift) & 0xf]); + } +} diff --git a/flight/targets/boards/spracingf3evo/firmware/inc/FreeRTOSConfig.h b/flight/targets/boards/spracingf3evo/firmware/inc/FreeRTOSConfig.h new file mode 100644 index 0000000000..5fea013d7a --- /dev/null +++ b/flight/targets/boards/spracingf3evo/firmware/inc/FreeRTOSConfig.h @@ -0,0 +1,99 @@ +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +/*----------------------------------------------------------- +* Application specific definitions. +* +* These definitions should be adjusted for your particular hardware and +* application requirements. +* +* THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE +* FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. +* +* See http://www.freertos.org/a00110.html. +*----------------------------------------------------------*/ + +/** + * @addtogroup PIOS PIOS + * @{ + * @addtogroup FreeRTOS FreeRTOS + * @{ + */ + +/* Notes: We use 5 task priorities */ + +#define configUSE_PREEMPTION 1 +#define configUSE_IDLE_HOOK 1 +#define configUSE_TICK_HOOK 0 +#define configUSE_MALLOC_FAILED_HOOK 1 +#define configCPU_CLOCK_HZ ((unsigned long)72000000) +#define configTICK_RATE_HZ ((portTickType)1000) +#define configMAX_PRIORITIES ((unsigned portBASE_TYPE)5) +#define configMINIMAL_STACK_SIZE ((unsigned short)512) +#define configTOTAL_HEAP_SIZE ((size_t)(53 * 256)) +#define configMAX_TASK_NAME_LEN (6) +#define configUSE_TRACE_FACILITY 0 +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 0 +#define configUSE_MUTEXES 1 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configUSE_COUNTING_SEMAPHORES 0 +#define configUSE_ALTERNATIVE_API 0 +#define configQUEUE_REGISTRY_SIZE 0 + +/* Co-routine definitions. */ +#define configUSE_CO_ROUTINES 0 +#define configMAX_CO_ROUTINE_PRIORITIES (2) + +/* Set the following definitions to 1 to include the API function, or zero + to exclude the API function. */ + +#define INCLUDE_vTaskPrioritySet 1 +#define INCLUDE_uxTaskPriorityGet 1 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskCleanUpResources 0 +#define INCLUDE_vTaskSuspend 1 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_xTaskGetSchedulerState 0 +#define INCLUDE_xTaskGetCurrentTaskHandle 1 +#define INCLUDE_uxTaskGetStackHighWaterMark 1 + +/* This is the raw value as per the Cortex-M3 NVIC. Values can be 255 + (lowest) to 1 (highest maskable) to 0 (highest non-maskable). */ +#define configKERNEL_INTERRUPT_PRIORITY 15 << 4 /* equivalent to NVIC priority 15 */ + #define configMAX_SYSCALL_INTERRUPT_PRIORITY 3 << 4 /* equivalent to NVIC priority 3 */ + +/* This is the value being used as per the ST library which permits 16 + priority values, 0 to 15. This must correspond to the + configKERNEL_INTERRUPT_PRIORITY setting. Here 15 corresponds to the lowest + NVIC value of 255. */ +#define configLIBRARY_KERNEL_INTERRUPT_PRIORITY 15 + +#if !defined(ARCH_POSIX) && !defined(ARCH_WIN32) +#define CHECK_IRQ_STACK +#endif + +/* Enable run time stats collection */ +#define configGENERATE_RUN_TIME_STATS 1 +#define INCLUDE_uxTaskGetRunTime 1 +#define INCLUDE_xTaskGetIdleTaskHandle 1 +#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() \ + do { \ + (*(unsigned long *)0xe000edfc) |= (1 << 24); /* DEMCR |= DEMCR_TRCENA */ \ + (*(unsigned long *)0xe0001000) |= 1; /* DWT_CTRL |= DWT_CYCCNT_ENA */ \ + } \ + while (0) +#define portGET_RUN_TIME_COUNTER_VALUE() (*(unsigned long *)0xe0001004) /* DWT_CYCCNT */ + +#ifdef DIAG_TASKS +#define configCHECK_FOR_STACK_OVERFLOW 2 +#else +#define configCHECK_FOR_STACK_OVERFLOW 1 +#endif + +/** + * @} + */ + +#endif /* FREERTOS_CONFIG_H */ diff --git a/flight/targets/boards/spracingf3evo/firmware/inc/dcc_stdio.h b/flight/targets/boards/spracingf3evo/firmware/inc/dcc_stdio.h new file mode 100644 index 0000000000..3d73549182 --- /dev/null +++ b/flight/targets/boards/spracingf3evo/firmware/inc/dcc_stdio.h @@ -0,0 +1,36 @@ +/*************************************************************************** +* Copyright (C) 2008 by Dominic Rath * +* Dominic.Rath@gmx.de * +* Copyright (C) 2008 by Spencer Oliver * +* spen@spen-soft.co.uk * +* * +* 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 2 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 DCC_STDIO_H +#define DCC_STDIO_H + +void dbg_trace_point(unsigned long number); + +void dbg_write_u32(const unsigned long *val, long len); +void dbg_write_u16(const unsigned short *val, long len); +void dbg_write_u8(const unsigned char *val, long len); + +void dbg_write_str(const char *msg); +void dbg_write_char(char msg); +void dbg_write_hex32(const unsigned long val); + +#endif /* DCC_STDIO_H */ diff --git a/flight/targets/boards/spracingf3evo/firmware/inc/openpilot.h b/flight/targets/boards/spracingf3evo/firmware/inc/openpilot.h new file mode 100644 index 0000000000..5576baca66 --- /dev/null +++ b/flight/targets/boards/spracingf3evo/firmware/inc/openpilot.h @@ -0,0 +1,52 @@ +/** + ****************************************************************************** + * @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 + +/* OpenPilot Libraries */ +#include +#include +#include +#include + +#include "alarms.h" +#include + +/* Global Functions */ +void OpenPilotInit(void); + +#endif /* OPENPILOT_H */ + +/** + * @} + * @} + */ diff --git a/flight/targets/boards/spracingf3evo/firmware/inc/pios_board_posix.h b/flight/targets/boards/spracingf3evo/firmware/inc/pios_board_posix.h new file mode 100644 index 0000000000..16364d7fa0 --- /dev/null +++ b/flight/targets/boards/spracingf3evo/firmware/inc/pios_board_posix.h @@ -0,0 +1,81 @@ +/** + ****************************************************************************** + * + * @file pios_board.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief Defines board hardware for the OpenPilot Version 1.1 hardware. + * @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_BOARD_H +#define PIOS_BOARD_H + + +// ------------------------ +// PIOS_LED +// ------------------------ +// #define PIOS_LED_LED1_GPIO_PORT GPIOC +// #define PIOS_LED_LED1_GPIO_PIN GPIO_Pin_12 +// #define PIOS_LED_LED1_GPIO_CLK RCC_APB2Periph_GPIOC +// #define PIOS_LED_LED2_GPIO_PORT GPIOC +// #define PIOS_LED_LED2_GPIO_PIN GPIO_Pin_13 +// #define PIOS_LED_LED2_GPIO_CLK RCC_APB2Periph_GPIOC +#define PIOS_LED_NUM 2 +// #define PIOS_LED_PORTS { PIOS_LED_LED1_GPIO_PORT, PIOS_LED_LED2_GPIO_PORT } +// #define PIOS_LED_PINS { PIOS_LED_LED1_GPIO_PIN, PIOS_LED_LED2_GPIO_PIN } +// #define PIOS_LED_CLKS { PIOS_LED_LED1_GPIO_CLK, PIOS_LED_LED2_GPIO_CLK } + + +// ------------------------- +// COM +// +// See also pios_board_posix.c +// ------------------------- +// #define PIOS_USART_TX_BUFFER_SIZE 256 +#define PIOS_COM_BUFFER_SIZE 1024 +#define PIOS_UDP_RX_BUFFER_SIZE PIOS_COM_BUFFER_SIZE + +#define PIOS_COM_TELEM_RF 0 +#define PIOS_COM_GPS 1 +#define PIOS_COM_TELEM_USB 2 + +#ifdef PIOS_ENABLE_AUX_UART +#define PIOS_COM_AUX 3 +#define PIOS_COM_DEBUG PIOS_COM_AUX +#endif + +/** + * glue macros for file IO + * STM32 uses DOSFS for file IO + */ +#define PIOS_FOPEN_READ(filename, file) (file = fopen((char *)filename, "r")) == NULL + +#define PIOS_FOPEN_WRITE(filename, file) (file = fopen((char *)filename, "w")) == NULL + +#define PIOS_FREAD(file, bufferadr, length, resultadr) (*resultadr = fread((uint8_t *)bufferadr, 1, length, *file)) != length + +#define PIOS_FWRITE(file, bufferadr, length, resultadr) *resultadr = fwrite((uint8_t *)bufferadr, 1, length, *file) + + +#define PIOS_FCLOSE(file) fclose(file) + +#define PIOS_FUNLINK(file) unlink((char *)filename) + +#endif /* PIOS_BOARD_H */ diff --git a/flight/targets/boards/spracingf3evo/firmware/inc/pios_config.h b/flight/targets/boards/spracingf3evo/firmware/inc/pios_config.h new file mode 100644 index 0000000000..7cfe4ea046 --- /dev/null +++ b/flight/targets/boards/spracingf3evo/firmware/inc/pios_config.h @@ -0,0 +1,192 @@ +/** + ****************************************************************************** + * @addtogroup OpenPilotSystem OpenPilot System + * @{ + * @addtogroup OpenPilotCore OpenPilot Core + * @{ + * @file pios_config.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010-2013. + * @author LibrePilot, https://bitbucket.org/librepilot, Copyright (C) 2015 + * @brief PiOS configuration header, the compile time config file for the PIOS. + * Defines which PiOS libraries and features are included in the firmware. + * @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 + +/* + * Below is a complete list of PIOS configurable options. + * Please do not remove or rearrange them. Only comment out + * unused options in the list. See main pios.h header for more + * details. + */ + +/* #define PIOS_INCLUDE_DEBUG_CONSOLE */ +/* #define DEBUG_LEVEL 0 */ +/* #define PIOS_ENABLE_DEBUG_PINS */ + +/* PIOS FreeRTOS support */ +#define PIOS_INCLUDE_FREERTOS + + +/* PIOS CallbackScheduler support */ +#define PIOS_INCLUDE_CALLBACKSCHEDULER + +/* PIOS bootloader helper */ +#define PIOS_INCLUDE_BL_HELPER +/* #define PIOS_INCLUDE_BL_HELPER_WRITE_SUPPORT */ + +/* PIOS system functions */ +#define PIOS_INCLUDE_DELAY +#define PIOS_INCLUDE_INITCALL +#define PIOS_INCLUDE_SYS +#define PIOS_INCLUDE_TASK_MONITOR +// #define PIOS_INCLUDE_INSTRUMENTATION +#define PIOS_INSTRUMENTATION_MAX_COUNTERS 5 + +/* PIOS hardware peripherals */ +#define PIOS_INCLUDE_IRQ +#define PIOS_INCLUDE_RTC +#define PIOS_INCLUDE_TIM +#define PIOS_INCLUDE_USART +/* #define PIOS_INCLUDE_ADC */ +#define PIOS_INCLUDE_I2C +#define PIOS_INCLUDE_SPI +#define PIOS_INCLUDE_GPIO +#define PIOS_INCLUDE_EXTI +#define PIOS_INCLUDE_WDG + +/* PIOS USB functions */ +#define PIOS_INCLUDE_USB +#define PIOS_INCLUDE_USB_HID +#define PIOS_INCLUDE_USB_CDC +/* #define PIOS_INCLUDE_USB_RCTX */ + +/* PIOS sensor interfaces */ +/* #define PIOS_INCLUDE_ADXL345 */ +/* #define PIOS_INCLUDE_BMA180 */ +/* #define PIOS_INCLUDE_L3GD20 */ +/* #define PIOS_INCLUDE_MPU6000 */ +/* #define PIOS_MPU6000_ACCEL */ +/* #define PIOS_INCLUDE_HMC5843 */ +#define PIOS_INCLUDE_HMC5X83 +/* #define PIOS_HMC5883_HAS_GPIOS */ +#define PIOS_INCLUDE_MPU9250 +#define PIOS_MPU9250_ACCEL +/* #define PIOS_MPU9250_MAG */ +/* #define PIOS_INCLUDE_BMP085 */ +/* #define PIOS_INCLUDE_MS5611 */ +/* #define PIOS_INCLUDE_MPXV */ +/* #define PIOS_INCLUDE_ETASV3 */ +/* #define PIOS_INCLUDE_HCSR04 */ + +#define PIOS_SENSOR_RATE 500.0f + +/* PIOS receiver drivers */ +#define PIOS_INCLUDE_PWM +#define PIOS_INCLUDE_PPM +#define PIOS_INCLUDE_PPM_FLEXI +#define PIOS_INCLUDE_DSM +#define PIOS_INCLUDE_SBUS +#define PIOS_INCLUDE_EXBUS +#define PIOS_INCLUDE_SRXL +#define PIOS_INCLUDE_HOTT +#define PIOS_INCLUDE_IBUS +/* #define PIOS_INCLUDE_GCSRCVR */ +/* #define PIOS_INCLUDE_OPLINKRCVR */ + +/* PIOS abstract receiver interface */ +#define PIOS_INCLUDE_RCVR + +/* PIOS common peripherals */ +#define PIOS_INCLUDE_LED +#define PIOS_INCLUDE_IAP +#define PIOS_INCLUDE_SERVO +/* #define PIOS_INCLUDE_I2C_ESC */ +/* #define PIOS_INCLUDE_OVERO */ +/* #define PIOS_OVERO_SPI */ +/* #define PIOS_INCLUDE_SDCARD */ +/* #define LOG_FILENAME "startup.log" */ +#define PIOS_INCLUDE_FLASH +#define PIOS_INCLUDE_FLASH_LOGFS_SETTINGS +#define FLASH_FREERTOS +/* #define PIOS_INCLUDE_FLASH_EEPROM */ +#define PIOS_INCLUDE_FLASH_INTERNAL + +/* PIOS radio modules */ +/* #define PIOS_INCLUDE_RFM22B */ +/* #define PIOS_INCLUDE_RFM22B_COM */ +/* #define PIOS_INCLUDE_PPM_OUT */ +/* #define PIOS_RFM22B_DEBUG_ON_TELEM */ + +/* PIOS misc peripherals */ +/* #define PIOS_INCLUDE_VIDEO */ +/* #define PIOS_INCLUDE_WAVE */ +/* #define PIOS_INCLUDE_UDP */ + +/* PIOS abstract comms interface with options */ +#define PIOS_INCLUDE_COM +/* #define PIOS_INCLUDE_COM_MSG */ +#define PIOS_INCLUDE_TELEMETRY_RF +/* #define PIOS_INCLUDE_COM_TELEM */ +/* #define PIOS_INCLUDE_COM_FLEXI */ +/* #define PIOS_INCLUDE_COM_AUX */ +/* #define PIOS_TELEM_PRIORITY_QUEUE */ +#define PIOS_INCLUDE_GPS +/* #define PIOS_GPS_MINIMAL */ +#define PIOS_INCLUDE_GPS_NMEA_PARSER +#define PIOS_INCLUDE_GPS_UBX_PARSER +#define PIOS_INCLUDE_GPS_DJI_PARSER +#define PIOS_GPS_SETS_HOMELOCATION + +/* Stabilization options */ +#define PIOS_QUATERNION_STABILIZATION +/* #define PIOS_EXCLUDE_ADVANCED_FEATURES */ +/* Performance counters */ +#define IDLE_COUNTS_PER_SEC_AT_NO_LOAD 1995998 + +/* Alarm Thresholds */ +#define HEAP_LIMIT_WARNING 220 +#define HEAP_LIMIT_CRITICAL 40 +#define IRQSTACK_LIMIT_WARNING 100 +#define IRQSTACK_LIMIT_CRITICAL 60 +#define CPULOAD_LIMIT_WARNING 85 +#define CPULOAD_LIMIT_CRITICAL 95 + +/* Task stack sizes */ +#define PIOS_ACTUATOR_STACK_SIZE 800 +#define PIOS_MANUAL_STACK_SIZE 935 +#define PIOS_RECEIVER_STACK_SIZE 840 +#define PIOS_SYSTEM_STACK_SIZE 1536 +/* #define PIOS_STABILIZATION_STACK_SIZE 400 */ + +#define PIOS_TELEM_STACK_SIZE 800 +#define PIOS_EVENTDISPATCHER_STACK_SIZE 256 + +/* This can't be too high to stop eventdispatcher thread overflowing */ +#define PIOS_EVENTDISAPTCHER_QUEUE 10 + +/* Revolution series */ +#define REVOLUTION + +#endif /* PIOS_CONFIG_H */ +/** + * @} + * @} + */ diff --git a/flight/targets/boards/spracingf3evo/firmware/inc/pios_config_posix.h b/flight/targets/boards/spracingf3evo/firmware/inc/pios_config_posix.h new file mode 100644 index 0000000000..4e8aa47c66 --- /dev/null +++ b/flight/targets/boards/spracingf3evo/firmware/inc/pios_config_posix.h @@ -0,0 +1,48 @@ +/** + ****************************************************************************** + * + * @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_POSIX_H +#define PIOS_CONFIG_POSIX_H + + +/* Enable/Disable PiOS Modules */ +#define PIOS_INCLUDE_SYS +#define PIOS_INCLUDE_DELAY +#define PIOS_INCLUDE_LED +#define PIOS_INCLUDE_FREERTOS +#define PIOS_INCLUDE_CALLBACKSCHEDULER +#define PIOS_INCLUDE_TASK_MONITOR +#define PIOS_INCLUDE_COM +#define PIOS_INCLUDE_UDP +#define PIOS_INCLUDE_SERVO + + +/* Defaults for Logging */ +#define LOG_FILENAME "PIOS.LOG" +#define STARTUP_LOG_ENABLED 1 + +#endif /* PIOS_CONFIG_POSIX_H */ diff --git a/flight/targets/boards/spracingf3evo/firmware/inc/pios_usb_board_data.h b/flight/targets/boards/spracingf3evo/firmware/inc/pios_usb_board_data.h new file mode 100644 index 0000000000..1fac7c659e --- /dev/null +++ b/flight/targets/boards/spracingf3evo/firmware/inc/pios_usb_board_data.h @@ -0,0 +1,47 @@ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_USB_BOARD Board specific USB definitions + * @brief Board specific USB definitions + * @{ + * + * @file pios_usb_board_data.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief Board specific USB 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_USB_BOARD_DATA_H +#define PIOS_USB_BOARD_DATA_H + +// Note : changing below length will require changes to the USB buffer setup +#define PIOS_USB_BOARD_CDC_DATA_LENGTH 64 +#define PIOS_USB_BOARD_CDC_MGMT_LENGTH 32 +#define PIOS_USB_BOARD_HID_DATA_LENGTH 64 + +#define PIOS_USB_BOARD_EP_NUM 4 + +#include /* USB_* macros */ + +#define PIOS_USB_BOARD_PRODUCT_ID USB_PRODUCT_ID_COPTERCONTROL +#define PIOS_USB_BOARD_DEVICE_VER USB_OP_DEVICE_VER(USB_OP_BOARD_ID_COPTERCONTROL, USB_OP_BOARD_MODE_FW) +#define PIOS_USB_BOARD_SN_SUFFIX "+FW" + +#endif /* PIOS_USB_BOARD_DATA_H */ diff --git a/flight/targets/boards/spracingf3evo/firmware/main.cpp b/flight/targets/boards/spracingf3evo/firmware/main.cpp new file mode 100644 index 0000000000..ec093c995e --- /dev/null +++ b/flight/targets/boards/spracingf3evo/firmware/main.cpp @@ -0,0 +1,98 @@ +/** + ****************************************************************************** + * @addtogroup LibrePilotSystem LibrePilot System + * @brief These files are the core system files for CopterControl. + * They are the ground layer just above PiOS. In practice, CopterControl actually starts + * in the main() function of coptercontrol.c + * @{ + * @addtogroup LibrePilotCore LibrePilot Core + * @brief This is where the LP firmware starts. Those files also define the compile-time + * options of the firmware. + * @{ + * @file coptercontrol.c + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015. + * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010-2015 + * @brief Sets up and runs main tasks. + * @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 + */ + +extern "C" { +#include "inc/openpilot.h" +#include +/* Task Priorities */ + +/* Global Variables */ +extern void Stack_Change(void); +} /* extern "C" */ + +/** + * OpenPilot Main function: + * + * Initialize PiOS
+ * Create the "System" task (SystemModInitializein Modules/System/systemmod.c)
+ * Start FreeRTOS Scheduler (vTaskStartScheduler) (Now handled by caller) + * If something goes wrong, blink LED1 and LED2 every 100ms + * + */ +int main() +{ + /* NOTE: Do NOT modify the following start-up sequence */ + /* Any new initialization functions should be added in OpenPilotInit() */ + + vPortInitialiseBlocks(); + + /* Brings up System using CMSIS functions, enables the LEDs. */ + PIOS_SYS_Init(); + + + SystemModStart(); + + /* Start the FreeRTOS scheduler, which should never return. + * + * NOTE: OpenPilot runs an operating system (FreeRTOS), which constantly calls + * (schedules) function files (modules). These functions never return from their + * while loops, which explains why each module has a while(1){} segment. Thus, + * the OpenPilot software actually starts at the vTaskStartScheduler() function, + * even though this is somewhat obscure. + * + * In addition, there are many main() functions in the OpenPilot firmware source tree + * This is because each main() refers to a separate hardware platform. Of course, + * C only allows one main(), so only the relevant main() function is compiled when + * making a specific firmware. + * + */ + vTaskStartScheduler(); + + /* If all is well we will never reach here as the scheduler will now be running. */ + + /* Do some indication to user that something bad just happened */ + while (1) { +#if defined(PIOS_LED_HEARTBEAT) + PIOS_LED_Toggle(PIOS_LED_HEARTBEAT); +#endif /* PIOS_LED_HEARTBEAT */ + PIOS_DELAY_WaitmS(100); + } + + return 0; +} + +/** + * @} + * @} + */ diff --git a/flight/targets/boards/spracingf3evo/firmware/memory.ld b/flight/targets/boards/spracingf3evo/firmware/memory.ld new file mode 100644 index 0000000000..61e49d1244 --- /dev/null +++ b/flight/targets/boards/spracingf3evo/firmware/memory.ld @@ -0,0 +1,8 @@ +MEMORY +{ + BD_INFO (r) : ORIGIN = 0x08004000 - 0x80, LENGTH = 0x000080 + EE_BANK (rx) : ORIGIN = 0x08004000, LENGTH = 0x008000 + FLASH (rx) : ORIGIN = 0x0800C000, LENGTH = 0x034000 + SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00A000 + CCSRAM (rw) : ORIGIN = 0x10000000, LENGTH = 0x002000 +} diff --git a/flight/targets/boards/spracingf3evo/firmware/pios_board.c b/flight/targets/boards/spracingf3evo/firmware/pios_board.c new file mode 100644 index 0000000000..c7719cb67b --- /dev/null +++ b/flight/targets/boards/spracingf3evo/firmware/pios_board.c @@ -0,0 +1,264 @@ +/** + ***************************************************************************** + * @file pios_board.c + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015. + * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * PhoenixPilot, http://github.com/PhoenixPilot, Copyright (C) 2012 + * @addtogroup LibrePilotSystem LibrePilot System + * @{ + * @addtogroup LibrePilotCore LibrePilot Core + * @{ + * @brief Defines board specific static initializers for hardware for the CopterControl board. + *****************************************************************************/ +/* + * 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 "inc/openpilot.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef PIOS_INCLUDE_INSTRUMENTATION +#include +#endif + +#include +#include + +/* + * Pull in the board-specific static HW definitions. + * Including .c files is a bit ugly but this allows all of + * the HW definitions to be const and static to limit their + * scope. + * + * NOTE: THIS IS THE ONLY PLACE THAT SHOULD EVER INCLUDE THIS FILE + */ +#include "../board_hw_defs.c" + +uintptr_t pios_uavo_settings_fs_id; +uintptr_t pios_user_fs_id = 0; + +static HwSPRacingF3EVOSettingsData boardHwSettings; + +static void hwSPRacingF3EVOSettingsUpdatedCb(__attribute__((unused)) UAVObjEvent *ev) +{ + HwSPRacingF3EVOSettingsData currentBoardHwSettings; + + HwSPRacingF3EVOSettingsGet(¤tBoardHwSettings); + + if (memcmp(¤tBoardHwSettings, &boardHwSettings, sizeof(HwSPRacingF3EVOSettingsData)) != 0) { + ExtendedAlarmsSet(SYSTEMALARMS_ALARM_BOOTFAULT, SYSTEMALARMS_ALARM_CRITICAL, SYSTEMALARMS_EXTENDEDALARMSTATUS_REBOOTREQUIRED, 0); + } +} + +/** + * PIOS_Board_Init() + * initializes all the core subsystems on this specific hardware + * called from System/openpilot.c + */ + +void PIOS_Board_Init(void) +{ +#if defined(PIOS_INCLUDE_LED) + PIOS_LED_Init(&pios_led_cfg); +#endif /* PIOS_INCLUDE_LED */ + +#ifdef PIOS_INCLUDE_INSTRUMENTATION + PIOS_Instrumentation_Init(PIOS_INSTRUMENTATION_MAX_COUNTERS); +#endif + +#if defined(PIOS_INCLUDE_SPI) + /* Set up the SPI interface to the mpu9250 */ + + if (PIOS_SPI_Init(&pios_spi_mpu9250_id, &pios_spi_mpu9250_cfg)) { + PIOS_DEBUG_Assert(0); + } + + /* Set up the SPI interface to the sdcard */ + if (PIOS_SPI_Init(&pios_spi_sdcard_id, &pios_spi_sdcard_cfg)) { + PIOS_DEBUG_Assert(0); + } +#endif + +#if defined(PIOS_INCLUDE_FLASH) + /* Connect flash to the appropriate interface and configure it */ + uintptr_t flash_id; + + // initialize the internal settings storage flash + if (PIOS_Flash_Internal_Init(&flash_id, &flash_internal_system_cfg)) { + PIOS_DEBUG_Assert(0); + } + + if (PIOS_FLASHFS_Logfs_Init(&pios_uavo_settings_fs_id, &flashfs_internal_cfg, &pios_internal_flash_driver, flash_id)) { + PIOS_DEBUG_Assert(0); + } + +// if (PIOS_FLASHFS_Logfs_Init(&pios_user_fs_id, &flashfs_internal_user_cfg, &pios_internal_flash_driver, flash_id)) { +// PIOS_DEBUG_Assert(0); +// } + +#endif /* if defined(PIOS_INCLUDE_FLASH) */ + + /* Initialize the task monitor */ + if (PIOS_TASK_MONITOR_Initialize(TASKINFO_RUNNING_NUMELEM)) { + PIOS_Assert(0); + } + + /* Initialize the delayed callback library */ + PIOS_CALLBACKSCHEDULER_Initialize(); + + /* Initialize UAVObject libraries */ + EventDispatcherInitialize(); + UAVObjInitialize(); + +#if defined(PIOS_INCLUDE_RTC) + /* Initialize the real-time clock and its associated tick */ + PIOS_RTC_Init(&pios_rtc_main_cfg); +#endif + PIOS_IAP_Init(); + // check for safe mode commands from gcs + if (PIOS_IAP_ReadBootCmd(0) == PIOS_IAP_CLEAR_FLASH_CMD_0 && + PIOS_IAP_ReadBootCmd(1) == PIOS_IAP_CLEAR_FLASH_CMD_1 && + PIOS_IAP_ReadBootCmd(2) == PIOS_IAP_CLEAR_FLASH_CMD_2) { + PIOS_FLASHFS_Format(pios_uavo_settings_fs_id); + PIOS_IAP_WriteBootCmd(0, 0); + PIOS_IAP_WriteBootCmd(1, 0); + PIOS_IAP_WriteBootCmd(2, 0); + } + + HwSettingsInitialize(); + HwSPRacingF3EVOSettingsInitialize(); + +#ifndef ERASE_FLASH +#ifdef PIOS_INCLUDE_WDG + /* Initialize watchdog as early as possible to catch faults during init */ + PIOS_WDG_Init(); +#endif +#endif + + /* Initialize the alarms library */ + AlarmsInitialize(); + + /* Check for repeated boot failures */ + uint16_t boot_count = PIOS_IAP_ReadBootCount(); + if (boot_count < 3) { + PIOS_IAP_WriteBootCount(++boot_count); + AlarmsClear(SYSTEMALARMS_ALARM_BOOTFAULT); + } else { + /* Too many failed boot attempts, force hwsettings to defaults */ + HwSettingsSetDefaults(HwSettingsHandle(), 0); + HwSPRacingF3EVOSettingsSetDefaults(HwSPRacingF3EVOSettingsHandle(), 0); + + AlarmsSet(SYSTEMALARMS_ALARM_BOOTFAULT, SYSTEMALARMS_ALARM_CRITICAL); + } + + + /* Set up pulse timers: 2, 3, 8, 15 */ + // PIOS_TIM_InitClock(&tim_1_cfg); + PIOS_TIM_InitClock(&tim_2_cfg); + PIOS_TIM_InitClock(&tim_3_cfg); + // PIOS_TIM_InitClock(&tim_4_cfg); + PIOS_TIM_InitClock(&tim_8_cfg); + PIOS_TIM_InitClock(&tim_15_cfg); + // PIOS_TIM_InitClock(&tim_16_cfg); + // PIOS_TIM_InitClock(&tim_17_cfg); + + +#if defined(PIOS_INCLUDE_USB) + PIOS_BOARD_IO_Configure_USB(); +#endif + + + HwSPRacingF3EVOSettingsConnectCallback(hwSPRacingF3EVOSettingsUpdatedCb); + + HwSPRacingF3EVOSettingsGet(&boardHwSettings); + + static const PIOS_BOARD_IO_UART_Function uart_function_map[] = { + [HWSPRACINGF3EVOSETTINGS_UARTPORT_TELEMETRY] = PIOS_BOARD_IO_UART_TELEMETRY, + [HWSPRACINGF3EVOSETTINGS_UARTPORT_GPS] = PIOS_BOARD_IO_UART_GPS, + [HWSPRACINGF3EVOSETTINGS_UARTPORT_SBUS] = PIOS_BOARD_IO_UART_SBUS, + [HWSPRACINGF3EVOSETTINGS_UARTPORT_DSM] = PIOS_BOARD_IO_UART_DSM_MAIN, // single DSM instance? ok. + [HWSPRACINGF3EVOSETTINGS_UARTPORT_EXBUS] = PIOS_BOARD_IO_UART_EXBUS, + [HWSPRACINGF3EVOSETTINGS_UARTPORT_HOTTSUMD] = PIOS_BOARD_IO_UART_HOTT_SUMD, + [HWSPRACINGF3EVOSETTINGS_UARTPORT_HOTTSUMH] = PIOS_BOARD_IO_UART_HOTT_SUMH, + [HWSPRACINGF3EVOSETTINGS_UARTPORT_SRXL] = PIOS_BOARD_IO_UART_SRXL, + [HWSPRACINGF3EVOSETTINGS_UARTPORT_IBUS] = PIOS_BOARD_IO_UART_IBUS, + [HWSPRACINGF3EVOSETTINGS_UARTPORT_DEBUGCONSOLE] = PIOS_BOARD_IO_UART_DEBUGCONSOLE, + [HWSPRACINGF3EVOSETTINGS_UARTPORT_COMBRIDGE] = PIOS_BOARD_IO_UART_COMBRIDGE, + [HWSPRACINGF3EVOSETTINGS_UARTPORT_MSP] = PIOS_BOARD_IO_UART_MSP, + [HWSPRACINGF3EVOSETTINGS_UARTPORT_MAVLINK] = PIOS_BOARD_IO_UART_MAVLINK, + }; + + for (unsigned int i = 0; i < HWSPRACINGF3EVOSETTINGS_UARTPORT_NUMELEM; ++i) { + if(boardHwSettings.UARTPort[i] < NELEMENTS(uart_function_map)) { + PIOS_BOARD_IO_Configure_UART(&pios_usart_cfg[i], uart_function_map[boardHwSettings.UARTPort[i]]); + } + } + +#ifndef PIOS_ENABLE_DEBUG_PINS + PIOS_Servo_Init(&pios_servo_cfg); +#else + PIOS_DEBUG_Init(&pios_servo_cfg.channels, pios_servo_cfg.num_channels); +#endif + + switch (boardHwSettings.LEDPort) { + case HWSPRACINGF3EVOSETTINGS_LEDPORT_WS2811: + break; + case HWSPRACINGF3EVOSETTINGS_LEDPORT_OUTPUT: + break; + default:; + } + + if (boardHwSettings.BuzzerPort == HWSPRACINGF3EVOSETTINGS_BUZZERPORT_OUTPUT) { + // enable buzzer somehow + } + + switch (boardHwSettings.SonarPort) { + case HWSPRACINGF3EVOSETTINGS_SONARPORT_HCSR04: + /* enable hcsr04 sonar on this port */ + break; + default:; + } + +#if defined(PIOS_INCLUDE_I2C) + + // init I2C1 for use with the internal baro + if (PIOS_I2C_Init(&pios_i2c_id, &pios_i2c_cfg)) { + PIOS_DEBUG_Assert(0); + } + PIOS_DELAY_WaitmS(50); + +#endif + + PIOS_BOARD_Sensors_Configure(); + + PIOS_LED_On(PIOS_LED_HEARTBEAT); + + /* Make sure we have at least one telemetry link configured or else fail initialization */ + PIOS_Assert(pios_com_telem_rf_id || pios_com_telem_usb_id); +} + + +/** + * @} + */ diff --git a/flight/targets/boards/spracingf3evo/firmware/pios_board_posix.c b/flight/targets/boards/spracingf3evo/firmware/pios_board_posix.c new file mode 100644 index 0000000000..7fa958a38e --- /dev/null +++ b/flight/targets/boards/spracingf3evo/firmware/pios_board_posix.c @@ -0,0 +1,145 @@ +/** + ****************************************************************************** + * + * @file pios_board.c + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief Defines board specific static initializers for hardware for the OpenPilot board. + * @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 "inc/openpilot.h" +#include +#include +#include + +/** + * PIOS_Board_Init() + * initializes all the core systems on this specific hardware + * called from System/openpilot.c + */ +void PIOS_Board_Init(void) +{ + /* Delay system */ + PIOS_DELAY_Init(); + + /* Initialize the delayed callback library */ + PIOS_CALLBACKSCHEDULER_Initialize(); + + /* Initialize UAVObject libraries */ + EventDispatcherInitialize(); + UAVObjInitialize(); + + /* Initialize the alarms library */ + AlarmsInitialize(); + + /* Initialize the task monitor */ + if (PIOS_TASK_MONITOR_Initialize(TASKINFO_RUNNING_NUMELEM)) { + PIOS_Assert(0); + } + + /* Initialize the PiOS library */ + PIOS_COM_Init(); +} + + +const struct pios_udp_cfg pios_udp0_cfg = { + .ip = "0.0.0.0", + .port = 9000, +}; +const struct pios_udp_cfg pios_udp1_cfg = { + .ip = "0.0.0.0", + .port = 9001, +}; +const struct pios_udp_cfg pios_udp2_cfg = { + .ip = "0.0.0.0", + .port = 9002, +}; + +#ifdef PIOS_COM_AUX +/* + * AUX USART + */ +const struct pios_udp_cfg pios_udp3_cfg = { + .ip = "0.0.0.0", + .port = 9003, +}; +#endif + +/* + * Board specific number of devices. + */ +struct pios_udp_dev pios_udp_devs[] = { +#define PIOS_UDP_TELEM 0 + { + .cfg = &pios_udp0_cfg, + }, +#define PIOS_UDP_GPS 1 + { + .cfg = &pios_udp1_cfg, + }, +#define PIOS_UDP_LOCAL 2 + { + .cfg = &pios_udp2_cfg, + }, +#ifdef PIOS_COM_AUX +#define PIOS_UDP_AUX 3 + { + .cfg = &pios_udp3_cfg, + }, +#endif +}; + +uint8_t pios_udp_num_devices = NELEMENTS(pios_udp_devs); + +/* + * COM devices + */ + +/* + * Board specific number of devices. + */ +extern const struct pios_com_driver pios_serial_com_driver; +extern const struct pios_com_driver pios_udp_com_driver; + +struct pios_com_dev pios_com_devs[] = { + { + .id = PIOS_UDP_TELEM, + .driver = &pios_udp_com_driver, + }, + { + .id = PIOS_UDP_GPS, + .driver = &pios_udp_com_driver, + }, + { + .id = PIOS_UDP_LOCAL, + .driver = &pios_udp_com_driver, + }, +#ifdef PIOS_COM_AUX + { + .id = PIOS_UDP_AUX, + .driver = &pios_udp_com_driver, + }, +#endif +}; + +const uint8_t pios_com_num_devices = NELEMENTS(pios_com_devs); + +/** + * @} + */ diff --git a/flight/targets/boards/spracingf3evo/pios_board.h b/flight/targets/boards/spracingf3evo/pios_board.h new file mode 100644 index 0000000000..fcb8092ba1 --- /dev/null +++ b/flight/targets/boards/spracingf3evo/pios_board.h @@ -0,0 +1,248 @@ +/** + ****************************************************************************** + * + * @file pios_board.h + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015. + * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * + * @brief Defines board hardware for the OpenPilot Version 1.1 hardware. + * @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_BOARD_H +#define PIOS_BOARD_H +// ------------------------ +// Timers and Channels Used +// ------------------------ +/* + Timer | Channel 1 | Channel 2 | Channel 3 | Channel 4 + ------+-----------+-----------+-----------+---------- + TIM1 | Servo 4 | | | + TIM2 | RC In 5 | RC In 6 | Servo 6 | + TIM3 | Servo 5 | RC In 2 | RC In 3 | RC In 4 + TIM4 | RC In 1 | Servo 3 | Servo 2 | Servo 1 + ------+-----------+-----------+-----------+---------- + */ + +// ------------------------ +// DMA Channels Used +// ------------------------ +/* Channel 1 - */ +/* Channel 2 - */ +/* Channel 3 - */ +/* Channel 4 - */ +/* Channel 5 - */ +/* Channel 6 - */ +/* Channel 7 - */ +/* Channel 8 - */ +/* Channel 9 - */ +/* Channel 10 - */ +/* Channel 11 - */ +/* Channel 12 - */ + +// ------------------------ +// BOOTLOADER_SETTINGS +// ------------------------ +#define BOARD_READABLE true +#define BOARD_WRITABLE true +#define MAX_DEL_RETRYS 3 + +// ------------------------ +// WATCHDOG_SETTINGS +// ------------------------ +#define PIOS_WATCHDOG_TIMEOUT 250 +#define PIOS_WDG_REGISTER RTC_BKP_DR4 +#define PIOS_WDG_ACTUATOR 0x0001 +#define PIOS_WDG_STABILIZATION 0x0002 +#define PIOS_WDG_ATTITUDE 0x0004 +#define PIOS_WDG_MANUAL 0x0008 +#define PIOS_WDG_AUTOTUNE 0x0010 +#define PIOS_WDG_SENSORS 0x0020 + + +// ------------------------ +// TELEMETRY +// ------------------------ +#define TELEM_QUEUE_SIZE 10 + +// ------------------------ +// PIOS_LED +// ------------------------ +#define PIOS_LED_HEARTBEAT 0 + +// ------------------------- +// System Settings +// ------------------------- +#define PIOS_MASTER_CLOCK 72000000 + +// ------------------------- +// Interrupt Priorities +// ------------------------- +#define PIOS_IRQ_PRIO_LOW 12 // lower than RTOS +#define PIOS_IRQ_PRIO_MID 8 // higher than RTOS +#define PIOS_IRQ_PRIO_HIGH 5 // for SPI, ADC, I2C etc... +#define PIOS_IRQ_PRIO_HIGHEST 4 // for USART etc... +// ------------------------ +// PIOS_I2C +// See also pios_board.c +// ------------------------ +#define PIOS_I2C_MAX_DEVS 1 +extern uint32_t pios_i2c_id; +#define PIOS_I2C_MAIN_ADAPTER (pios_i2c_id) +#define PIOS_I2C_ESC_ADAPTER (pios_i2c_id) +#define PIOS_I2C_EXTERNAL_ADAPTER (pios_i2c_id) +#define PIOS_I2C_BMP280_INTERNAL_ADAPTER (pios_i2c_id) + +// ------------------------ +// PIOS_BMP085 +// ------------------------ +#define PIOS_BMP085_OVERSAMPLING 3 + +// ------------------------- +// SPI +// +// See also pios_board.c +// ------------------------- +#define PIOS_SPI_MAX_DEVS 2 +extern uint32_t pios_spi_mpu9250_id; +#define PIOS_SPI_MPU9250_ADAPTER (pios_spi_mpu9250_id) + +// ------------------------- +// PIOS_USART +// ------------------------- +#define PIOS_USART_MAX_DEVS 2 + +// ------------------------- +// PIOS_COM +// +// See also pios_board.c +// ------------------------- +#define PIOS_COM_MAX_DEVS 3 + + +// ------------------------- +// ADC +// PIOS_ADC_PinGet(0) = Current sensor +// PIOS_ADC_PinGet(1) = RSSI sensor +// PIOS_ADC_PinGet(2) = Battery voltage +// ------------------------- +#define PIOS_DMA_PIN_CONFIG \ + { \ + { GPIOA, GPIO_Pin_5, ADC_Channel_2, false }, /* ADC_1 / Current */ \ + { GPIOB, GPIO_Pin_2, ADC_Channel_12, false }, /* ADC_2 / RSSI */ \ + { GPIOA, GPIO_Pin_4, ADC_Channel_1, false }, /* Battery voltage */ \ + } + +/* we have to do all this to satisfy the PIOS_ADC_MAX_SAMPLES define in pios_adc.h */ +/* which is annoying because this then determines the rate at which we generate buffer turnover events */ +/* the objective here is to get enough buffer space to support 100Hz averaging rate */ +#define PIOS_ADC_NUM_CHANNELS 3 +#define PIOS_ADC_MAX_OVERSAMPLING 32 +#define PIOS_ADC_USE_ADC2 0 + +// #define PIOS_ADC_USE_TEMP_SENSOR +// #define PIOS_ADC_TEMPERATURE_PIN 4 + +// ------------------------ +// PIOS_RCVR +// See also pios_board.c +// ------------------------ +#define PIOS_RCVR_MAX_DEVS 3 +#define PIOS_RCVR_MAX_CHANNELS 12 +#define PIOS_GCSRCVR_TIMEOUT_MS 100 + +// ------------------------- +// Receiver PPM input +// ------------------------- +#define PIOS_PPM_MAX_DEVS 1 +#define PIOS_PPM_NUM_INPUTS 16 + +// ------------------------- +// Receiver PWM input +// ------------------------- +#define PIOS_PWM_MAX_DEVS 1 +#define PIOS_PWM_NUM_INPUTS 6 + +// ------------------------- +// Receiver DSM input +// ------------------------- +#define PIOS_DSM_MAX_DEVS 2 +#define PIOS_DSM_NUM_INPUTS 12 + +// ------------------------- +// Receiver S.Bus input +// ------------------------- +#define PIOS_SBUS_MAX_DEVS 1 +#define PIOS_SBUS_NUM_INPUTS (16 + 2) + +// ------------------------- +// Receiver HOTT input +// ------------------------- +#define PIOS_HOTT_MAX_DEVS 1 +#define PIOS_HOTT_NUM_INPUTS 32 + +// ------------------------- +// Receiver EX.Bus input +// ------------------------- +#define PIOS_EXBUS_MAX_DEVS 1 +#define PIOS_EXBUS_NUM_INPUTS 16 + +// ------------------------- +// Receiver Multiplex SRXL input +// ------------------------- +#define PIOS_SRXL_MAX_DEVS 1 +#define PIOS_SRXL_NUM_INPUTS 16 + +// ------------------------- +// Receiver FlySky IBus input +// ------------------------- +#define PIOS_IBUS_MAX_DEVS 1 +#define PIOS_IBUS_NUM_INPUTS 10 + +// ------------------------- +// Servo outputs +// ------------------------- +#define PIOS_SERVO_UPDATE_HZ 50 +#define PIOS_SERVOS_INITIAL_POSITION 0 /* dont want to start motors, have no pulse till settings loaded */ +#define PIOS_SERVO_BANKS 6 + +// -------------------------- +// Timer controller settings +// -------------------------- +#define PIOS_TIM_MAX_DEVS 3 + +// ------------------------- +// GPIO +// ------------------------- +#define PIOS_GPIO_PORTS {} +#define PIOS_GPIO_PINS {} +#define PIOS_GPIO_CLKS {} +#define PIOS_GPIO_NUM 0 + +// ------------------------- +// USB +// ------------------------- +#define PIOS_USB_HID_MAX_DEVS 1 + +#define PIOS_USB_ENABLED 1 +#define PIOS_USB_DETECT_GPIO_PORT GPIOC +#define PIOS_USB_MAX_DEVS 1 +#define PIOS_USB_DETECT_GPIO_PIN GPIO_Pin_15 + +#endif /* PIOS_BOARD_H */ diff --git a/flight/targets/boards/spracingf3evo/pios_usb_board_data.c b/flight/targets/boards/spracingf3evo/pios_usb_board_data.c new file mode 100644 index 0000000000..1885deb5be --- /dev/null +++ b/flight/targets/boards/spracingf3evo/pios_usb_board_data.c @@ -0,0 +1,103 @@ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @addtogroup PIOS_USB_BOARD Board specific USB definitions + * @brief Board specific USB definitions + * @{ + * + * @file pios_usb_board_data.c + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief Board specific USB 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 + */ + +#include "inc/pios_usb_board_data.h" /* struct usb_*, USB_* */ +#include /* PIOS_SYS_SerialNumberGet */ +#include /* PIOS_USBHOOK_* */ +#include /* PIOS_USB_UTIL_AsciiToUtf8 */ + +static const uint8_t usb_product_id[30] = { + sizeof(usb_product_id), + USB_DESC_TYPE_STRING, + 'S', 0, + 'P', 0, + 'R', 0, + 'a', 0, + 'c', 0, + 'i', 0, + 'n', 0, + 'g', 0, + 'F', 0, + '3', 0, + '_', 0, + 'E', 0, + 'V', 0, + 'O', 0, +}; + +static uint8_t usb_serial_number[2 + PIOS_SYS_SERIAL_NUM_ASCII_LEN * 2 + (sizeof(PIOS_USB_BOARD_SN_SUFFIX) - 1) * 2] = { + sizeof(usb_serial_number), + USB_DESC_TYPE_STRING, +}; + +static const struct usb_string_langid usb_lang_id = { + .bLength = sizeof(usb_lang_id), + .bDescriptorType = USB_DESC_TYPE_STRING, + .bLangID = htousbs(USB_LANGID_ENGLISH_US), +}; + +static const uint8_t usb_vendor_id[28] = { + sizeof(usb_vendor_id), + USB_DESC_TYPE_STRING, + 'o', 0, + 'p', 0, + 'e', 0, + 'n', 0, + 'p', 0, + 'i', 0, + 'l', 0, + 'o', 0, + 't', 0, + '.', 0, + 'o', 0, + 'r', 0, + 'g', 0 +}; + +int32_t PIOS_USB_BOARD_DATA_Init(void) +{ + /* Load device serial number into serial number string */ + uint8_t sn[PIOS_SYS_SERIAL_NUM_ASCII_LEN + 1]; + + PIOS_SYS_SerialNumberGet((char *)sn); + + /* Concatenate the device serial number and the appropriate suffix ("+BL" or "+FW") into the USB serial number */ + uint8_t *utf8 = &(usb_serial_number[2]); + utf8 = PIOS_USB_UTIL_AsciiToUtf8(utf8, sn, PIOS_SYS_SERIAL_NUM_ASCII_LEN); + utf8 = PIOS_USB_UTIL_AsciiToUtf8(utf8, (uint8_t *)PIOS_USB_BOARD_SN_SUFFIX, sizeof(PIOS_USB_BOARD_SN_SUFFIX) - 1); + + PIOS_USBHOOK_RegisterString(USB_STRING_DESC_PRODUCT, (uint8_t *)&usb_product_id, sizeof(usb_product_id)); + PIOS_USBHOOK_RegisterString(USB_STRING_DESC_SERIAL, (uint8_t *)&usb_serial_number, sizeof(usb_serial_number)); + + PIOS_USBHOOK_RegisterString(USB_STRING_DESC_LANG, (uint8_t *)&usb_lang_id, sizeof(usb_lang_id)); + PIOS_USBHOOK_RegisterString(USB_STRING_DESC_VENDOR, (uint8_t *)&usb_vendor_id, sizeof(usb_vendor_id)); + + return 0; +} diff --git a/flight/targets/common/bootloader_updater/Makefile b/flight/targets/common/bootloader_updater/Makefile index fae84250fe..a05464959f 100644 --- a/flight/targets/common/bootloader_updater/Makefile +++ b/flight/targets/common/bootloader_updater/Makefile @@ -41,7 +41,7 @@ SRC += $(OPSYSTEM)/main.c SRC += $(OPSYSTEM)/pios_board.c SRC += $(PIOSCOMMON)/pios_led.c ## PIOS Hardware -ifeq ($(MCU),cortex-m3) +ifneq (,$(findstring STM32F10,$(CHIP))) include $(PIOS)/stm32f10x/library.mk ## The standard CMSIS startup @@ -50,7 +50,7 @@ ifeq ($(MCU),cortex-m3) # Set linker-script name depending on selected submodel name LDFLAGS += -T$(LINKER_SCRIPTS_PATH)/link_$(BOARD)_memory.ld LDFLAGS += -T$(LINKER_SCRIPTS_PATH)/link_$(BOARD)_sections.ld -else ifeq ($(MCU),cortex-m4) +else ifneq (,$(findstring STM32F4,$(CHIP))) include $(PIOS)/stm32f4xx/library.mk # Set linker-script name depending on selected submodel name # Using the _compat ld script ensure that the bootloader updated is compiled with irqstack in sram @@ -58,8 +58,16 @@ else ifeq ($(MCU),cortex-m4) LDFLAGS += $(addprefix -T,$(LINKER_SCRIPTS_APP)) SRC += $(HWDEFSINC)/firmware/cm3_fault_handlers.c SRC += $(HWDEFSINC)/firmware/dcc_stdio.c +else ifneq (,$(findstring STM32F30,$(CHIP))) + include $(PIOS)/stm32f30x/library.mk + # Set linker-script name depending on selected submodel name + # Using the _compat ld script ensure that the bootloader updated is compiled with irqstack in sram + # This allow to be used with bootloader earlier than rel5 +# LDFLAGS += $(addprefix -T,$(LINKER_SCRIPTS_APP)) + SRC += $(HWDEFSINC)/firmware/cm3_fault_handlers.c + SRC += $(HWDEFSINC)/firmware/dcc_stdio.c else - $(error Unsupported MCU for BootloaderUpdater: $(MCU)) + $(error Unsupported MCU for BootloaderUpdater: $(CHIP)) endif # List any extra directories to look for include files here. diff --git a/ground/gcs/src/plugins/config/config.pro b/ground/gcs/src/plugins/config/config.pro index 5865e0da4a..913a0c14d2 100644 --- a/ground/gcs/src/plugins/config/config.pro +++ b/ground/gcs/src/plugins/config/config.pro @@ -43,6 +43,7 @@ HEADERS += \ mixercurve.h \ dblspindelegate.h \ configrevohwwidget.h \ + configspracingf3hwwidget.h \ calibration/calibrationutils.h \ calibration/wizardstate.h \ calibration/wizardmodel.h \ @@ -89,6 +90,7 @@ SOURCES += \ mixercurve.cpp \ dblspindelegate.cpp \ configrevohwwidget.cpp \ + configspracingf3hwwidget.cpp \ calibration/calibrationutils.cpp \ calibration/wizardstate.cpp \ calibration/wizardmodel.cpp \ @@ -124,6 +126,7 @@ FORMS += \ txpid.ui \ mixercurve.ui \ configrevohwwidget.ui \ + configspracingf3hwwidget.ui \ oplink.ui \ configrevonanohwwidget.ui \ configsparky2hwwidget.ui \ diff --git a/ground/gcs/src/plugins/config/configgadget.qrc b/ground/gcs/src/plugins/config/configgadget.qrc index b7e9b3ec75..918a0a1602 100644 --- a/ground/gcs/src/plugins/config/configgadget.qrc +++ b/ground/gcs/src/plugins/config/configgadget.qrc @@ -58,5 +58,6 @@ images/nano_top.png images/cc3d_top.png images/sparky2_top.png + images/spracingf3_top.png diff --git a/ground/gcs/src/plugins/config/configgadgetwidget.cpp b/ground/gcs/src/plugins/config/configgadgetwidget.cpp index ec891265fe..92294a74e2 100644 --- a/ground/gcs/src/plugins/config/configgadgetwidget.cpp +++ b/ground/gcs/src/plugins/config/configgadgetwidget.cpp @@ -41,6 +41,7 @@ #include "configrevowidget.h" #include "configrevonanohwwidget.h" #include "configsparky2hwwidget.h" +#include "configspracingf3hwwidget.h" #include "defaultconfigwidget.h" #include @@ -201,10 +202,18 @@ void ConfigGadgetWidget::onAutopilotConnect() int board = utilMngr->getBoardModel(); if ((board & 0xff00) == 0x0400) { // CopterControl family + ConfigTaskWidget *widget; - widget = new ConfigCCAttitudeWidget(this); + + if((board & 0x00ff) == 0x03) { + widget = new ConfigRevoWidget(this); + } else { + widget = new ConfigCCAttitudeWidget(this); + } + widget->bind(); stackWidget->replaceTab(ConfigGadgetWidget::Sensors, widget); + widget = new ConfigCCHWWidget(this); widget->bind(); stackWidget->replaceTab(ConfigGadgetWidget::Hardware, widget); @@ -230,6 +239,24 @@ void ConfigGadgetWidget::onAutopilotConnect() widget = new ConfigSparky2HWWidget(this); widget->bind(); stackWidget->replaceTab(ConfigGadgetWidget::Hardware, widget); + } else if(( board & 0xff00) == 0x1000) { + // SPRacingF3 + ConfigTaskWidget *widget; + widget = new ConfigRevoWidget(this); + widget->bind(); + stackWidget->replaceTab(ConfigGadgetWidget::Sensors, widget); + + widget = 0; + + if (board == 0x1001) { + widget = new ConfigSPRacingF3HWWidget(this); + } else if (board == 0x1002) { + //widget = new ConfigSPRacingF3EVOHWWidget(this); + } + if(widget) { + widget->bind(); + stackWidget->replaceTab(ConfigGadgetWidget::Hardware, widget); + } } else { // Unknown board qWarning() << "Unknown board " << board; diff --git a/ground/gcs/src/plugins/config/configoutputwidget.cpp b/ground/gcs/src/plugins/config/configoutputwidget.cpp index c4887c2925..e66095cf45 100644 --- a/ground/gcs/src/plugins/config/configoutputwidget.cpp +++ b/ground/gcs/src/plugins/config/configoutputwidget.cpp @@ -373,6 +373,14 @@ void ConfigOutputWidget::refreshWidgetsValuesImpl(UAVObject *obj) // Sparky2 bankLabels << "1 (1-2)" << "2 (3)" << "3 (4)" << "4 (5-6)" << "5 (7-8)" << "6 (9-10)"; channelBanks << 1 << 1 << 2 << 3 << 4 << 4 << 5 << 5 << 6 << 6; + } else if (board == 0x1001) { + // SPRacingF3 + bankLabels << "1 (1-3,7)" << "2 (4,8)" << "3 (5)" << "4 (6)"; + channelBanks << 1 << 1 << 1 << 2 << 3 << 4 << 1 << 2; + } else if (board == 0x1002) { + // SPRacingF3_EVO + bankLabels << "1 (1-3)" << "2 (4)" << "3 (5-8)"; + channelBanks << 1 << 1 << 1 << 2 << 3 << 3 << 3 << 3; } } diff --git a/ground/gcs/src/plugins/config/configspracingf3hwwidget.cpp b/ground/gcs/src/plugins/config/configspracingf3hwwidget.cpp new file mode 100644 index 0000000000..7cf6adfd3c --- /dev/null +++ b/ground/gcs/src/plugins/config/configspracingf3hwwidget.cpp @@ -0,0 +1,467 @@ +/** + ****************************************************************************** + * + * @file configSPRacingF3HWWidget.cpp + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. + * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @addtogroup GCSPlugins GCS Plugins + * @{ + * @addtogroup ConfigPlugin Config Plugin + * @{ + * @brief SPRacingF3 hardware 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 + */ +#include "configspracingf3hwwidget.h" + +#include "ui_configspracingf3hwwidget.h" + +#include "hwsettings.h" +#include "hwspracingf3settings.h" + +#include + +ConfigSPRacingF3HWWidget::ConfigSPRacingF3HWWidget(QWidget *parent) : ConfigTaskWidget(parent) +{ + m_ui = new Ui_SPRacingF3HWWidget(); + m_ui->setupUi(this); + + // must be done before auto binding ! + setWikiURL("SPRacingF3+Configuration"); + + addAutoBindings(); + + addUAVObject("HwSettings"); + +// addWidgetBinding("HwSettings", "RM_FlexiPort", m_ui->cbFlexi); +// addWidgetBinding("HwSettings", "RM_MainPort", m_ui->cbMain); +// addWidgetBinding("HwSettings", "RM_RcvrPort", m_ui->cbRcvr); +// +// addWidgetBinding("HwSettings", "USB_HIDPort", m_ui->cbUSBHIDFunction); +// addWidgetBinding("HwSettings", "USB_VCPPort", m_ui->cbUSBVCPFunction); +// +// addWidgetBinding("HwSettings", "TelemetrySpeed", m_ui->cbFlexiTelemSpeed); +// addWidgetBinding("HwSettings", "GPSSpeed", m_ui->cbFlexiGPSSpeed); +// +// addWidgetBinding("HwSettings", "TelemetrySpeed", m_ui->cbMainTelemSpeed); +// addWidgetBinding("HwSettings", "GPSSpeed", m_ui->cbMainGPSSpeed); +// +// addWidgetBinding("HwSettings", "TelemetrySpeed", m_ui->cbRcvrTelemSpeed); +// addWidgetBinding("HwSettings", "GPSSpeed", m_ui->cbRcvrGPSSpeed); +// +// // Add Gps protocol configuration +// addWidgetBinding("GPSSettings", "DataProtocol", m_ui->cbMainGPSProtocol); +// addWidgetBinding("GPSSettings", "DataProtocol", m_ui->cbFlexiGPSProtocol); +// addWidgetBinding("GPSSettings", "DataProtocol", m_ui->cbRcvrGPSProtocol); + + setupCustomCombos(); +} + +ConfigSPRacingF3HWWidget::~ConfigSPRacingF3HWWidget() +{ + // Do nothing +} + +void ConfigSPRacingF3HWWidget::setupCustomCombos() +{ +// connect(m_ui->cbUSBHIDFunction, SIGNAL(currentIndexChanged(int)), this, SLOT(usbHIDPortChanged(int))); +// connect(m_ui->cbUSBVCPFunction, SIGNAL(currentIndexChanged(int)), this, SLOT(usbVCPPortChanged(int))); +// +// m_ui->cbSonar->addItem(tr("Disabled")); +// m_ui->cbSonar->setCurrentIndex(0); +// m_ui->cbSonar->setEnabled(false); +// +// connect(m_ui->cbFlexi, SIGNAL(currentIndexChanged(int)), this, SLOT(flexiPortChanged(int))); +// connect(m_ui->cbMain, SIGNAL(currentIndexChanged(int)), this, SLOT(mainPortChanged(int))); +// connect(m_ui->cbRcvr, SIGNAL(currentIndexChanged(int)), this, SLOT(rcvrPortChanged(int))); +} + +void ConfigSPRacingF3HWWidget::refreshWidgetsValuesImpl(UAVObject *obj) +{ + Q_UNUSED(obj); + +// usbVCPPortChanged(0); +// mainPortChanged(0); +// flexiPortChanged(0); +// rcvrPortChanged(0); +} + +void ConfigSPRacingF3HWWidget::updateObjectsFromWidgetsImpl() +{ + // If any port is configured to be GPS port, enable GPS module if it is not enabled. + // Otherwise disable GPS module. +// quint8 enableModule = HwSettings::OPTIONALMODULES_DISABLED; +// +// if (isComboboxOptionSelected(m_ui->cbFlexi, HwSettings::RM_FLEXIPORT_GPS) +// || isComboboxOptionSelected(m_ui->cbMain, HwSettings::RM_MAINPORT_GPS)) { +// enableModule = HwSettings::OPTIONALMODULES_ENABLED; +// } +// +// HwSettings *hwSettings = HwSettings::GetInstance(getObjectManager()); +// hwSettings->setOptionalModules(HwSettings::OPTIONALMODULES_GPS, enableModule); +} + +void ConfigSPRacingF3HWWidget::usbVCPPortChanged(int index) +{ + Q_UNUSED(index); + +// bool vcpComBridgeEnabled = isComboboxOptionSelected(m_ui->cbUSBVCPFunction, HwSettings::USB_VCPPORT_COMBRIDGE); +// +// if (!vcpComBridgeEnabled && isComboboxOptionSelected(m_ui->cbFlexi, HwSettings::RM_FLEXIPORT_COMBRIDGE)) { +// setComboboxSelectedOption(m_ui->cbFlexi, HwSettings::RM_FLEXIPORT_DISABLED); +// } +// enableComboBoxOptionItem(m_ui->cbFlexi, HwSettings::RM_FLEXIPORT_COMBRIDGE, vcpComBridgeEnabled); +// +// if (!vcpComBridgeEnabled && isComboboxOptionSelected(m_ui->cbMain, HwSettings::RM_MAINPORT_COMBRIDGE)) { +// setComboboxSelectedOption(m_ui->cbMain, HwSettings::RM_MAINPORT_DISABLED); +// } +// enableComboBoxOptionItem(m_ui->cbMain, HwSettings::RM_MAINPORT_COMBRIDGE, vcpComBridgeEnabled); +// +// if (!vcpComBridgeEnabled && isComboboxOptionSelected(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_COMBRIDGE)) { +// setComboboxSelectedOption(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_DISABLED); +// } +// if (!vcpComBridgeEnabled && isComboboxOptionSelected(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_PPMCOMBRIDGE)) { +// setComboboxSelectedOption(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_PPM); +// } +// +// enableComboBoxOptionItem(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_COMBRIDGE, vcpComBridgeEnabled); +// enableComboBoxOptionItem(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_PPMCOMBRIDGE, vcpComBridgeEnabled); +// +// // _DEBUGCONSOLE modes are mutual exclusive +// if (isComboboxOptionSelected(m_ui->cbUSBVCPFunction, HwSettings::USB_VCPPORT_DEBUGCONSOLE)) { +// if (isComboboxOptionSelected(m_ui->cbMain, HwSettings::RM_MAINPORT_DEBUGCONSOLE)) { +// setComboboxSelectedOption(m_ui->cbMain, HwSettings::RM_MAINPORT_DISABLED); +// } +// if (isComboboxOptionSelected(m_ui->cbFlexi, HwSettings::RM_FLEXIPORT_DEBUGCONSOLE)) { +// setComboboxSelectedOption(m_ui->cbFlexi, HwSettings::RM_FLEXIPORT_DISABLED); +// } +// if (isComboboxOptionSelected(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_DEBUGCONSOLE)) { +// setComboboxSelectedOption(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_DISABLED); +// } +// if (isComboboxOptionSelected(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_PPMDEBUGCONSOLE)) { +// setComboboxSelectedOption(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_PPM); +// } +// } +// +// // _USBTELEMETRY modes are mutual exclusive +// if (isComboboxOptionSelected(m_ui->cbUSBVCPFunction, HwSettings::USB_VCPPORT_USBTELEMETRY) +// && isComboboxOptionSelected(m_ui->cbUSBHIDFunction, HwSettings::USB_HIDPORT_USBTELEMETRY)) { +// setComboboxSelectedOption(m_ui->cbUSBHIDFunction, HwSettings::USB_HIDPORT_DISABLED); +// } +} + +void ConfigSPRacingF3HWWidget::usbHIDPortChanged(int index) +{ + Q_UNUSED(index); + +// // _USBTELEMETRY modes are mutual exclusive +// if (isComboboxOptionSelected(m_ui->cbUSBHIDFunction, HwSettings::USB_HIDPORT_USBTELEMETRY) +// && isComboboxOptionSelected(m_ui->cbUSBVCPFunction, HwSettings::USB_VCPPORT_USBTELEMETRY)) { +// setComboboxSelectedOption(m_ui->cbUSBVCPFunction, HwSettings::USB_VCPPORT_DISABLED); +// } +} + +//void ConfigSPRacingF3HWWidget::flexiPortChanged(int index) +//{ +// Q_UNUSED(index); +// +// m_ui->cbFlexiTelemSpeed->setVisible(false); +// m_ui->cbFlexiGPSSpeed->setVisible(false); +// m_ui->lblFlexiSpeed->setVisible(true); +// +// // Add Gps protocol configuration +// m_ui->cbFlexiGPSProtocol->setVisible(false); +// m_ui->lbFlexiGPSProtocol->setVisible(false); +// +// switch (getComboboxSelectedOption(m_ui->cbFlexi)) { +// case HwSettings::RM_FLEXIPORT_TELEMETRY: +// m_ui->cbFlexiTelemSpeed->setVisible(true); +// if (isComboboxOptionSelected(m_ui->cbMain, HwSettings::RM_MAINPORT_TELEMETRY)) { +// setComboboxSelectedOption(m_ui->cbMain, HwSettings::RM_MAINPORT_DISABLED); +// } +// if (isComboboxOptionSelected(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_PPMTELEMETRY)) { +// setComboboxSelectedOption(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_PPM); +// } +// if (isComboboxOptionSelected(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_TELEMETRY)) { +// setComboboxSelectedOption(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_DISABLED); +// } +// break; +// case HwSettings::RM_FLEXIPORT_GPS: +// // Add Gps protocol configuration +// m_ui->cbFlexiGPSProtocol->setVisible(true); +// m_ui->lbFlexiGPSProtocol->setVisible(true); +// +// m_ui->cbFlexiGPSSpeed->setVisible(true); +// if (isComboboxOptionSelected(m_ui->cbMain, HwSettings::RM_MAINPORT_GPS)) { +// setComboboxSelectedOption(m_ui->cbMain, HwSettings::RM_MAINPORT_DISABLED); +// } +// if (isComboboxOptionSelected(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_PPMGPS)) { +// setComboboxSelectedOption(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_PPM); +// } +// if (isComboboxOptionSelected(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_GPS)) { +// setComboboxSelectedOption(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_DISABLED); +// } +// +// break; +// case HwSettings::RM_FLEXIPORT_COMBRIDGE: +// m_ui->lblFlexiSpeed->setVisible(false); +// if (isComboboxOptionSelected(m_ui->cbMain, HwSettings::RM_MAINPORT_COMBRIDGE)) { +// setComboboxSelectedOption(m_ui->cbMain, HwSettings::RM_MAINPORT_DISABLED); +// } +// if (isComboboxOptionSelected(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_COMBRIDGE)) { +// setComboboxSelectedOption(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_DISABLED); +// } +// if (isComboboxOptionSelected(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_PPMCOMBRIDGE)) { +// setComboboxSelectedOption(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_PPM); +// } +// break; +// case HwSettings::RM_FLEXIPORT_DEBUGCONSOLE: +// m_ui->lblFlexiSpeed->setVisible(false); +// if (isComboboxOptionSelected(m_ui->cbMain, HwSettings::RM_MAINPORT_DEBUGCONSOLE)) { +// setComboboxSelectedOption(m_ui->cbMain, HwSettings::RM_MAINPORT_DISABLED); +// } +// if (isComboboxOptionSelected(m_ui->cbUSBVCPFunction, HwSettings::USB_VCPPORT_DEBUGCONSOLE)) { +// setComboboxSelectedOption(m_ui->cbUSBVCPFunction, HwSettings::USB_VCPPORT_DISABLED); +// } +// if (isComboboxOptionSelected(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_PPMDEBUGCONSOLE)) { +// setComboboxSelectedOption(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_PPM); +// } +// if (isComboboxOptionSelected(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_DEBUGCONSOLE)) { +// setComboboxSelectedOption(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_DISABLED); +// } +// break; +// case HwSettings::RM_FLEXIPORT_OSDHK: +// m_ui->lblFlexiSpeed->setVisible(false); +// if (isComboboxOptionSelected(m_ui->cbMain, HwSettings::RM_MAINPORT_OSDHK)) { +// setComboboxSelectedOption(m_ui->cbMain, HwSettings::RM_MAINPORT_DISABLED); +// } +// break; +// case HwSettings::RM_FLEXIPORT_MSP: +// m_ui->lblFlexiSpeed->setVisible(false); +// if (isComboboxOptionSelected(m_ui->cbMain, HwSettings::RM_MAINPORT_MSP)) { +// setComboboxSelectedOption(m_ui->cbMain, HwSettings::RM_MAINPORT_DISABLED); +// } +// if (isComboboxOptionSelected(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_MSP)) { +// setComboboxSelectedOption(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_DISABLED); +// } +// if (isComboboxOptionSelected(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_PPMMSP)) { +// setComboboxSelectedOption(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_PPM); +// } +// break; +// case HwSettings::RM_FLEXIPORT_MAVLINK: +// m_ui->lblFlexiSpeed->setVisible(false); +// if (isComboboxOptionSelected(m_ui->cbMain, HwSettings::RM_MAINPORT_MAVLINK)) { +// setComboboxSelectedOption(m_ui->cbMain, HwSettings::RM_MAINPORT_DISABLED); +// } +// if (isComboboxOptionSelected(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_MAVLINK)) { +// setComboboxSelectedOption(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_DISABLED); +// } +// if (isComboboxOptionSelected(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_PPMMAVLINK)) { +// setComboboxSelectedOption(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_PPM); +// } +// break; +// default: +// m_ui->lblFlexiSpeed->setVisible(false); +// break; +// } +//} +// +//void ConfigSPRacingF3HWWidget::mainPortChanged(int index) +//{ +// Q_UNUSED(index); +// +// m_ui->cbMainTelemSpeed->setVisible(false); +// m_ui->cbMainGPSSpeed->setVisible(false); +// m_ui->lblMainSpeed->setVisible(true); +// +// // Add Gps protocol configuration +// m_ui->cbMainGPSProtocol->setVisible(false); +// m_ui->lbMainGPSProtocol->setVisible(false); +// +// switch (getComboboxSelectedOption(m_ui->cbMain)) { +// case HwSettings::RM_MAINPORT_TELEMETRY: +// m_ui->cbMainTelemSpeed->setVisible(true); +// if (isComboboxOptionSelected(m_ui->cbFlexi, HwSettings::RM_FLEXIPORT_TELEMETRY)) { +// setComboboxSelectedOption(m_ui->cbFlexi, HwSettings::RM_FLEXIPORT_DISABLED); +// } +// if (isComboboxOptionSelected(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_PPMTELEMETRY)) { +// setComboboxSelectedOption(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_PPM); +// } +// if (isComboboxOptionSelected(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_TELEMETRY)) { +// setComboboxSelectedOption(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_DISABLED); +// } +// break; +// case HwSettings::RM_MAINPORT_GPS: +// // Add Gps protocol configuration +// m_ui->cbMainGPSProtocol->setVisible(true); +// m_ui->lbMainGPSProtocol->setVisible(true); +// +// m_ui->cbMainGPSSpeed->setVisible(true); +// if (isComboboxOptionSelected(m_ui->cbFlexi, HwSettings::RM_FLEXIPORT_GPS)) { +// setComboboxSelectedOption(m_ui->cbFlexi, HwSettings::RM_FLEXIPORT_DISABLED); +// } +// if (isComboboxOptionSelected(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_PPMGPS)) { +// setComboboxSelectedOption(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_PPM); +// } +// if (isComboboxOptionSelected(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_GPS)) { +// setComboboxSelectedOption(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_DISABLED); +// } +// break; +// case HwSettings::RM_MAINPORT_COMBRIDGE: +// m_ui->lblMainSpeed->setVisible(false); +// if (isComboboxOptionSelected(m_ui->cbFlexi, HwSettings::RM_FLEXIPORT_COMBRIDGE)) { +// setComboboxSelectedOption(m_ui->cbFlexi, HwSettings::RM_FLEXIPORT_DISABLED); +// } +// if (isComboboxOptionSelected(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_COMBRIDGE)) { +// setComboboxSelectedOption(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_DISABLED); +// } +// if (isComboboxOptionSelected(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_PPMCOMBRIDGE)) { +// setComboboxSelectedOption(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_PPM); +// } +// break; +// case HwSettings::RM_MAINPORT_DEBUGCONSOLE: +// m_ui->lblMainSpeed->setVisible(false); +// if (isComboboxOptionSelected(m_ui->cbFlexi, HwSettings::RM_FLEXIPORT_DEBUGCONSOLE)) { +// setComboboxSelectedOption(m_ui->cbFlexi, HwSettings::RM_FLEXIPORT_DISABLED); +// } +// if (isComboboxOptionSelected(m_ui->cbUSBVCPFunction, HwSettings::USB_VCPPORT_DEBUGCONSOLE)) { +// setComboboxSelectedOption(m_ui->cbUSBVCPFunction, HwSettings::USB_VCPPORT_DISABLED); +// } +// if (isComboboxOptionSelected(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_PPMDEBUGCONSOLE)) { +// setComboboxSelectedOption(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_PPM); +// } +// if (isComboboxOptionSelected(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_DEBUGCONSOLE)) { +// setComboboxSelectedOption(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_DISABLED); +// } +// break; +// case HwSettings::RM_MAINPORT_OSDHK: +// m_ui->lblMainSpeed->setVisible(false); +// if (isComboboxOptionSelected(m_ui->cbFlexi, HwSettings::RM_FLEXIPORT_OSDHK)) { +// setComboboxSelectedOption(m_ui->cbFlexi, HwSettings::RM_FLEXIPORT_DISABLED); +// } +// break; +// case HwSettings::RM_MAINPORT_MSP: +// m_ui->lblMainSpeed->setVisible(false); +// if (isComboboxOptionSelected(m_ui->cbFlexi, HwSettings::RM_FLEXIPORT_MSP)) { +// setComboboxSelectedOption(m_ui->cbFlexi, HwSettings::RM_FLEXIPORT_DISABLED); +// } +// if (isComboboxOptionSelected(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_MSP)) { +// setComboboxSelectedOption(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_DISABLED); +// } +// if (isComboboxOptionSelected(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_PPMMSP)) { +// setComboboxSelectedOption(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_PPM); +// } +// break; +// case HwSettings::RM_MAINPORT_MAVLINK: +// m_ui->lblMainSpeed->setVisible(false); +// if (isComboboxOptionSelected(m_ui->cbFlexi, HwSettings::RM_FLEXIPORT_MAVLINK)) { +// setComboboxSelectedOption(m_ui->cbFlexi, HwSettings::RM_FLEXIPORT_DISABLED); +// } +// if (isComboboxOptionSelected(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_MAVLINK)) { +// setComboboxSelectedOption(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_DISABLED); +// } +// if (isComboboxOptionSelected(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_PPMMAVLINK)) { +// setComboboxSelectedOption(m_ui->cbRcvr, HwSettings::RM_RCVRPORT_PPM); +// } +// break; +// default: +// m_ui->lblMainSpeed->setVisible(false); +// break; +// } +//} +// +//void ConfigSPRacingF3HWWidget::rcvrPortChanged(int index) +//{ +// Q_UNUSED(index); +// m_ui->lblRcvrSpeed->setVisible(true); +// m_ui->cbRcvrTelemSpeed->setVisible(false); +// m_ui->cbRcvrGPSSpeed->setVisible(false); +// +// // Add Gps protocol configuration +// m_ui->cbRcvrGPSProtocol->setVisible(false); +// m_ui->lblRcvrGPSProtocol->setVisible(false); +// +// switch (getComboboxSelectedOption(m_ui->cbRcvr)) { +// case HwSettings::RM_RCVRPORT_TELEMETRY: +// case HwSettings::RM_RCVRPORT_PPMTELEMETRY: +// m_ui->cbRcvrTelemSpeed->setVisible(true); +// +// if (isComboboxOptionSelected(m_ui->cbFlexi, HwSettings::RM_FLEXIPORT_TELEMETRY)) { +// setComboboxSelectedOption(m_ui->cbFlexi, HwSettings::RM_FLEXIPORT_DISABLED); +// } +// if (isComboboxOptionSelected(m_ui->cbMain, HwSettings::RM_MAINPORT_TELEMETRY)) { +// setComboboxSelectedOption(m_ui->cbMain, HwSettings::RM_MAINPORT_DISABLED); +// } +// break; +// case HwSettings::RM_RCVRPORT_COMBRIDGE: +// case HwSettings::RM_RCVRPORT_PPMCOMBRIDGE: +// m_ui->lblRcvrSpeed->setVisible(false); +// if (isComboboxOptionSelected(m_ui->cbFlexi, HwSettings::RM_FLEXIPORT_COMBRIDGE)) { +// setComboboxSelectedOption(m_ui->cbFlexi, HwSettings::RM_FLEXIPORT_DISABLED); +// } +// if (isComboboxOptionSelected(m_ui->cbMain, HwSettings::RM_MAINPORT_COMBRIDGE)) { +// setComboboxSelectedOption(m_ui->cbMain, HwSettings::RM_MAINPORT_DISABLED); +// } +// break; +// case HwSettings::RM_RCVRPORT_DEBUGCONSOLE: +// case HwSettings::RM_RCVRPORT_PPMDEBUGCONSOLE: +// if (isComboboxOptionSelected(m_ui->cbFlexi, HwSettings::RM_FLEXIPORT_DEBUGCONSOLE)) { +// setComboboxSelectedOption(m_ui->cbFlexi, HwSettings::RM_FLEXIPORT_DISABLED); +// } +// if (isComboboxOptionSelected(m_ui->cbMain, HwSettings::RM_MAINPORT_DEBUGCONSOLE)) { +// setComboboxSelectedOption(m_ui->cbMain, HwSettings::RM_MAINPORT_DISABLED); +// } +// break; +// case HwSettings::RM_RCVRPORT_GPS: +// case HwSettings::RM_RCVRPORT_PPMGPS: +// // Add Gps protocol configuration +// m_ui->cbRcvrGPSProtocol->setVisible(true); +// m_ui->lblRcvrGPSProtocol->setVisible(true); +// +// m_ui->cbRcvrGPSSpeed->setVisible(true); +// +// if (isComboboxOptionSelected(m_ui->cbFlexi, HwSettings::RM_FLEXIPORT_GPS)) { +// setComboboxSelectedOption(m_ui->cbFlexi, HwSettings::RM_FLEXIPORT_DISABLED); +// } +// if (isComboboxOptionSelected(m_ui->cbMain, HwSettings::RM_MAINPORT_GPS)) { +// setComboboxSelectedOption(m_ui->cbMain, HwSettings::RM_MAINPORT_DISABLED); +// } +// break; +// case HwSettings::RM_RCVRPORT_MSP: +// case HwSettings::RM_RCVRPORT_PPMMSP: +// m_ui->lblRcvrSpeed->setVisible(false); +// if (isComboboxOptionSelected(m_ui->cbFlexi, HwSettings::RM_FLEXIPORT_MSP)) { +// setComboboxSelectedOption(m_ui->cbFlexi, HwSettings::RM_FLEXIPORT_DISABLED); +// } +// if (isComboboxOptionSelected(m_ui->cbMain, HwSettings::RM_MAINPORT_MSP)) { +// setComboboxSelectedOption(m_ui->cbMain, HwSettings::RM_MAINPORT_DISABLED); +// } +// break; +// case HwSettings::RM_RCVRPORT_MAVLINK: +// case HwSettings::RM_RCVRPORT_PPMMAVLINK: +// m_ui->lblRcvrSpeed->setVisible(false); +// if (isComboboxOptionSelected(m_ui->cbFlexi, HwSettings::RM_FLEXIPORT_MAVLINK)) { +// setComboboxSelectedOption(m_ui->cbFlexi, HwSettings::RM_FLEXIPORT_DISABLED); +// } +// if (isComboboxOptionSelected(m_ui->cbMain, HwSettings::RM_MAINPORT_MAVLINK)) { +// setComboboxSelectedOption(m_ui->cbMain, HwSettings::RM_MAINPORT_DISABLED); +// } +// break; +// default: +// m_ui->lblRcvrSpeed->setVisible(false); +// break; +// } +//} diff --git a/ground/gcs/src/plugins/config/configspracingf3hwwidget.h b/ground/gcs/src/plugins/config/configspracingf3hwwidget.h new file mode 100644 index 0000000000..ab4cd6f2af --- /dev/null +++ b/ground/gcs/src/plugins/config/configspracingf3hwwidget.h @@ -0,0 +1,60 @@ +/** + ****************************************************************************** + * + * @file configSPRacingF3HWWidget.h + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016. + * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @addtogroup GCSPlugins GCS Plugins + * @{ + * @addtogroup ConfigPlugin Config Plugin + * @{ + * @brief Revolution hardware 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 CONFIGSPRACINGF3HWWIDGET_H +#define CONFIGSPRACINGF3HWWIDGET_H + +#include "../uavobjectwidgetutils/configtaskwidget.h" + +class Ui_SPRacingF3HWWidget; + +class UAVObject; + +class QWidget; + +class ConfigSPRacingF3HWWidget : public ConfigTaskWidget { + Q_OBJECT + +public: + ConfigSPRacingF3HWWidget(QWidget *parent = 0); + ~ConfigSPRacingF3HWWidget(); + +protected: + virtual void refreshWidgetsValuesImpl(UAVObject *obj); + virtual void updateObjectsFromWidgetsImpl(); + +private: + Ui_SPRacingF3HWWidget *m_ui; + + void setupCustomCombos(); + +private slots: + void usbVCPPortChanged(int index); + void usbHIDPortChanged(int index); +}; + +#endif // CONFIGSPRACINGF3HWWIDGET_H diff --git a/ground/gcs/src/plugins/config/configspracingf3hwwidget.ui b/ground/gcs/src/plugins/config/configspracingf3hwwidget.ui new file mode 100644 index 0000000000..cb1f7afb39 --- /dev/null +++ b/ground/gcs/src/plugins/config/configspracingf3hwwidget.ui @@ -0,0 +1,989 @@ + + + SPRacingF3HWWidget + + + + 0 + 0 + 969 + 886 + + + + Form + + + + + + 0 + + + + true + + + HW settings + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + + 255 + 255 + 255 + + + + + + + 232 + 232 + 232 + + + + + + + + + 255 + 255 + 255 + + + + + + + 232 + 232 + 232 + + + + + + + + + 232 + 232 + 232 + + + + + + + 232 + 232 + 232 + + + + + + + + border-color: rgb(255, 0, 0); + + + QFrame::NoFrame + + + QFrame::Plain + + + true + + + + + 0 + 0 + 939 + 786 + + + + + 12 + + + 12 + + + 12 + + + 12 + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 10 + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + + 75 + true + + + + Changes on this page only take effect after board reset or power cycle + + + Qt::AlignCenter + + + true + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + UART3 +(bottom) + + + Qt::AlignBottom|Qt::AlignHCenter + + + + + + + Qt::Horizontal + + + QSizePolicy::Minimum + + + + 120 + 10 + + + + + + + + + + + UART2 + + + Qt::AlignBottom|Qt::AlignHCenter + + + + + + + + + + + + + + + UART1 +(bottom) + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Maximum + + + + 20 + 20 + + + + + + + + Qt::Horizontal + + + QSizePolicy::Maximum + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + QSizePolicy::Minimum + + + + 120 + 10 + + + + + + + + + + + + + I2C1 +(bottom) + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Qt::Vertical + + + QSizePolicy::Maximum + + + + 20 + 90 + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Minimum + + + + 10 + 20 + + + + + + + + + + + + + + + + + + + + + + IO-2 + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + Sonar + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + ADC2 + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + ADC1 + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 10 + + + + + + + + + + + 0 + 0 + + + + + 350 + 350 + + + + + + + :/configgadget/images/spracingf3_top.png + + + false + + + Qt::AlignCenter + + + Qt::NoTextInteraction + + + + + + + + + + + + IO-1 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Maximum + + + + 20 + 50 + + + + + + + + Qt::Vertical + + + + 20 + 10 + + + + + + + + LED Strip + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + + + VBAT + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Qt::Vertical + + + QSizePolicy::Maximum + + + + 20 + 70 + + + + + + + + + + + + Buzzer + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Maximum + + + + 20 + 70 + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + SBUS Inverted + + + + + + + GPS Protocol + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + + GPS Speed + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Telemetry Speed + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + DebugConsole Speed + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + DSMx Bind + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + Qt::Horizontal + + + + + + + Options + + + Qt::AlignCenter + + + + + + + + + Qt::Vertical + + + + 20 + 20 + + + + + + + + + + + + + + + + + + 4 + + + + + Qt::Horizontal + + + + 369 + 20 + + + + + + + + + 0 + 0 + + + + + 25 + 25 + + + + + 25 + 25 + + + + Takes you to the wiki page + + + + + + + :/core/images/helpicon.svg:/core/images/helpicon.svg + + + + 25 + 25 + + + + true + + + button:help + + + + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + + + + + + 255 + 255 + 255 + + + + + + + 232 + 232 + 232 + + + + + + + + + 255 + 255 + 255 + + + + + + + 232 + 232 + 232 + + + + + + + + + 232 + 232 + 232 + + + + + + + 232 + 232 + 232 + + + + + + + + Send to board but don't write in SD. +Beware of not locking yourself out! + + + false + + + + + + Apply + + + + 16 + 16 + + + + false + + + button:apply + + + + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + Applies and Saves all settings to SD. +Beware of not locking yourself out! + + + false + + + + + + Save + + + button:save + + + + + + + + + + + + + diff --git a/ground/gcs/src/plugins/config/images/spracingf3_top.png b/ground/gcs/src/plugins/config/images/spracingf3_top.png new file mode 100644 index 0000000000000000000000000000000000000000..80182d9cc7c11aabb608e6e22656990a75dff3d3 GIT binary patch literal 128896 zcmb??1yCJLv*D;O=h0-3jgvkMH~bd++=2 zyY;GG)tjoV-RF(+2+Uf2IQ&NyYMIu51005}6A0$-(04R&UE(G{Di2IJ=@3$M2 zlZuQupmL1l;Ozy`{)3hi0AS_&*98S_TJ#2lxwll)bk>xY6EL>3VKp?dGcsib+t|Nh z0{|efz}usZsk0#k*v8t{NdPQF^*4sV+w)&wHY$q0QJk%Ws5Ir3C?xD0O)1{9aSXL_Y42=lXG`%{zlKJ3F3v(!RDTWhpY0z$O^p9@9D5f> z>%T`aF=jKhHnlOeb#`LoVC7)@pXlDC{ZB$$r+;bVO)qRQ~I#`QM@c#lv3{DPV1AYc50uW-&1} zGjy?brV^HrV5d-WF|xKarjWF=F|@R$kTf;1G&cNus{S?Ke~WDCYWk*48@o3x{WbCS zf76)!O~U4G>S*`3vi@(v{X1)a3-^DB@t17Qmd@6u|1QMe>iu{6e@)0gy8NF-Q&r+p zF*LTcHUEF)>c2ApdNVBniGQYD&CbqR_%Hjnw6$_FHncbWOBo=x|Bmrra|`;*kOUMR zE#HjyZ>0)zfY|;I*uU`qVf24nEPt!vAL!ds6h?X*=|7gWFw!njoFD)o3Xqi)Qv*XC zc>xVbdaqwj^psCqwUc&Mqmb*N@KK6*sl{RDPdZg6-wD9%3l7U=!@xMtN*O#Wvqs;0q| zQb{j@neAld`}aQ=y6Z&$a6^JcLIFspILai?g~jM;AxFD@)X?|(oX{@=NhJTG72>Xo zy7L6&-p|$X2vJ&}94C!~#x)++*Wl<^VwVZa;wNZSWVr zDq(&=Y~JpOVY^xF0vSL_H`0n*4E1&oF!BPqU2z)+@U@d+VSPJrZN^=GEO22Ek<`NR zt(}^hQt>^6{918c!oOX18b?Slm9n?DC(8Oo`AXiY@6b=`h65-1pj0`U8}}=B?jstN z{-o$6-e>P@;IyQDIC==9kV)fs{1-1Z?7|-osU#iRdFeq0sR;4f4reuOF{OaI)+X6euv4~ z`Fu}k%w_f9eDzLfUA=G^2>L|^&2I)HQXq&lkMny@&tsJ9-WX|~vZLw6)Nj2Sa%q-S zF)r$L{aa%x3%nVoZt;yCx`h>%?*P^ufYh1l>c?y`{Yp3f=kPF--AZ$6dOCz=z6xb$ zX9q7~5-}F7@54GvG!|gYR;S|bxUaeX?Ch+%Vb#B84e(ME#s8?OnqmK0NraWr>0(jF z9VnDGB657ifPXn{zCawCXP%0xzLsMBLp>$6gWN?7={X7JPXx=49bHl)>**w=T7Ih!=Yv!4lh;xk`cyh2}GyO%CHP7(d7tcHos=YX8+3ePuVdfl|=D}nl& z&SUc@?hKWfM~+a)om=dq6iH!yeLW(#bga2TvFax|IW_4hqQZoP1ct`O#&_ISq}p`= z^Rqa^gj{YhhC^siRTWj$M5zco#xnJaDZs42FeVO8fkFnKvNPwJ*KOv<3L?X;Tv{@C z7KhVu@0;3*-CeV}#h+G|?Md5Bt*kl?u{Cqf!z{l>fb05D?s$xfk)dnCra!*qW$Jx& zFWB*73pii!n>t6^@?x_bC@UCWD+oh7(n{%Bl^{m0C@*)mTWiyW7n;{F!d?PXdkTS; z0(+P)GExTDguXH%%(3xm0^}!5bGMb)pl($+=)3ni=sRV)mNo_hy^+Z+t`@{nO3oQA zD9T}XA>7twvYvfzR}u@keglqjz!Wm{SXK#$Z@w!WYVlH@7_~YQ5|T66weH=W_;J@~ z4Gms29y5hJOIU`B{i<#>>?^>>Kjm7runkZHa9+EH3<4MQtgH%9zVFt&A1j*d-lSTr zv;64nT-W6RsPCJE8X|0U*y<}*>Z?Z=c~Zi`Ez=I{^UA4-?~fJg)R)YF^Q~vs{dy*` z634q=&WK-ITT|24#}IKm+-0u9gJwj?m~e$N1rM%|SUJ;4ttD&2&@)O=;{mG00*P`M zm6?5y{LuQJjqXy<2G3wkkf@MZJPM&$*ryI=WzS5h#k*@osU34BwQ`{vbMG71f2(uj z5mtUN67pi~93sBEmwP$+(%{L!8MUFVi;oBPl52DV;CAJ_#WB7?OXEh=|a|*LQRnh~i!4y9huR zX3%^&xTw#_AgL&-R~K?T(Q(-fL=2BlGcY#1F!f5Q?@@_A`gQB#98D;v5)-1^y1 z=EJ;KJ1)%BY_TBqsG_1$9uyQLEGP?Lg<6Cot~LFWP#R~OoPPZwG5xw;pTwV=m^9O^ z`>-yw32oKZhEQj5EfWiii*I)2U_8A{Cy$~upTUn=njAN@?AU~ygi|KB z?6XVkqZrV|z`*t4oJNJ-&qcU4pu|>PhUaG3M-`QC`#5MWS&-zYr&=+z@88Q3-PU~c z8F(2KnOyao$iQcQM=W3JXEJUgro#Y_%&nF{Ygeq}$$bNyqCaR9Sh=!i2I~ZMr=3;S9&hzs4SNKE^g)c$n($?0N#KwXHR&D7@$!a{9 zlk_rm*IBTX^y5UL3u6GJ5*Aa|oB=Al7_cj^0ii#`$Y^%N8>QNP$0vp)YGhn|Z|p%%m(cMFj=4 z{{1LAxR$B;n|<{6{UB9L%OLZYqRwf_N3ti0GwvXaVGGpQoam*OW4};%SfR+!iUYc6dxlNKH0oe|K195tZMSsF_lUKOMIVq-jE*V8U-SAJw_mkf9(t|u zQ+%Z3?#p8TT4GS>@K*YRD2FdP?JD=e9?7?iN{Ru+6a?;{AO#8y>=AGc2y=tr79!7uh<}Z7|Uk^q zbxKQ3+~hf%&-9?%W?z3G5q- z1*HWG!)f&f&cJ%zL4C#T0O#(fNwV=o27RCBpZ#jx?t7tM|ICyc6^7T9J<_I|U7Gdx zW2PfTi4Kt+7+X+(i>o5r<0{#s|gQ4%`B z-Cr@PO=51b>O4ekI|A6*MzF2>KpGMoO|}C5Jk~`+x^63lk%U}k9T&`E6%u0dIfrM~ z2+!;Wiv#wG()uCb$xy@|p2`~p|90}MXbKkG&*wQJK2LBHBN&|!*eB{UowL$+=4eV0yAKwX@k#O4p3*)HeznXLmy+^4TwJOfc(wvBbnMtAUj8MKBn=PS z0I|g{OMW*;QA@&GB%A1AxxvS>$|s#dKmYtbQ!(tdS<6)Ge^lsHILL1f7MshbY z)A;6OzUlFK213SjVdqr1p1pC&&OLUZ`RL|x4FZy9CSb7umTbW!>o*jL=;uKV;uLg! z7)~X}>Ydn%2(vu|w$g?KiwWuLgwdz&e>6cw-QeMMk$^ojR^e0R^;;sjxafXNlGN1h z^}P-!4Ffx<`11uP2lyhKEadj~;59_W-8f~~eTzHmJFPRPjoNj@DP~VQL0HLy^h4~B z$E2C{zCXI1?)dKZpEyfOF*9H)-AE|<1p=-B>HMJ_unPoW*869Kta$L!=o(fI;#lgL z4wWa)lLh!)DD0nA1C(woWcm)(cyD0V!6#F^UqWuJvh(ThAR~JICp2JaW~iUMS1E=! z+OP|+0k8C)h%IdWnF50ABEEa>#i|=Vh~(&Oqwg{gNq<1w0^W9BwSzOhyUQL27qlQ4 zi%p6?jC6#lSM(R!I}lhu`YsW@9qWbh4tw2_kN{0_7?7x_ztF$+oN?3`76ogu8{n|x zw0tvit-h70W@-dGyl|!xm3)fsY#O{^d>q`4@L~w|=em@LHIM1`IJi$AzfX^($;k$` z<7F-WJYu#d{@3o$7a)};#n1UR6dBn6(vLk@Q=;PD<*s&PEhxsHzTpPPAS|Y*C+sYL z{UF8mhi*0%CGJ8zJIuk^h@7G&W`@>!)LFa#D_NFYF8#!XkOye>)A*X_*cysV60z52F40#1^31cU>+r2l|c{bY4nNAW?3pX(UJcn_{cdpDm;qHEsOBW0N2nw*zd_ z^<%^G7ukncyu_(^Xex53TkH+d4)~SF@Ds$Q>#VOK1U*0nSoIElm~3>#a)T+MUV=?R zj$jITH~c4`4SwxYL{#yh9!Vn_(yePE@du;{xeQjI-f9GJ<%u#t)4>0a&>2?7eKTA1 zIn9SxvfJ`lgS)Iw^Fe!`C77?oyAf`mkCNU@rx~?wHNt3&* z8x)j&L!d|A?=ur4{Z2yVAY)H|Z?dO|vm^f0Uu|medC!u%r#(gEEwt+n_+)MvXo;DD z2?(hgki=$k#91h}4-TS6BYOk54#CkBOXT!oX%Uz&@QTYu^!7Qfq8kP}tR^|TEA(^t z*HRy8J+Po{6#;45EKsdPFWF}=&fk>nd@Y1qU@d)$C@lv4A2ZJ;sOHUiFedK!>9dSG z$E_wWJ02x)_vdrj?LY==8d-(GLUrFy*LP==&wOLr$ZmP^d!YQyiJykeOy1dHk&noD zH4P}=14Bm}xlZn5$D61II5|)pzTH?g=_SX*?N`KyVb}+(dvpQJ5`rF3yoo_8en=L9 z0%!WJ807>+SM7l!=vlQ@UI(5Sqs7>!N3vpGeZn*3H$Zo3OrDv$^=9xIF2__Hwj;}*;xN##kvTg0_66Ev zDn7H1XgM2B@!`0}m;BlJo43f|6GPr@8a}KbnY5x3HG!L}C%xjY!>1F2=Ojqc&4{O) zYlu;n;GP4+(+xIXZHe_MZ1?F#sno5u0%oxwyVwcAIWUy)QSgax)1u51tyI*=*IF0B@F;d#}52OJbE&3vz7(hEC zBS~=ei1H1#5MkK)D*CRGBf?Ydki*CiwnDKEE5ZKEP1%F0?DLKz7v-j=s2#-y0lNm( zRnRvx*yRG~i%?69bK$$I_2!$e-G2A^T?`=^5y>fXUWqzDpL+EB0rWlke~4PJq1|DT zIs3PfdG!7{XBjPmiQ?$t*c<`eyg%L{W%f0LQ~I)3uqi5##gn$BZzWN!gYE~p5$_mL_1j)9bU9ntagra%fg)ifnF@Y zJiz`SyWN9N)`#MPEQfHtLoo@)yGAVDM+LFK227FB131x45=7dm_4}YWK_cf{WG2|h z9M=9`Ww0bJM+5_4V-`q#b7yv7E~pq4<2#>9A?f>>1j~!2z<# zmp;=ilR~9hxEVfOM{8fnfd}P$I2F-&(STk_gKHFc+|d!%V!GM_`G5O#cd;@BghArg;H>MxhP8Aw8wUU zku$xq*L6wZq27{%VGlr41TSnec$GC_dPsT#cOngZR?V}(!lH$xo>Fv?TdnTd(doS~C+ zqUd-jTl4~s5v;` zgNlZ3EE4FY)FG$#?9Krfs3m)G#a*li|K=f5M0cv#H0e2lJ)Td4_6D6{_uD4K>sFh^ zJ`Icz5%xm&b%?;Ti4px0Pe0M|@jN-c)8qW&e;E(v!OB|XT0;#LRO*ALnFLG%fY2oS zEWl7ptOW87q2tLX`JGtm8<_W|VH`bJMkwep_gqiTcLLxk0&d=Uz^H$4QVVx~xQ408Fpwfe)Hc*-bQ)4tvun#Gv%!=eia;QV3ahNL^w@UL$sgKNkN6uUv@f4k z^R3h+4!R&-+qrsQG(ybPv({%1^9K1^+)u;`b-#JY*UVuG46|NRE~)IfedAMvrNKAJ z+Hry;Vh5qjk<(v_5t(VrC22bet&a93KC;)Zd$T;@4V();9;eUe9y}fxTJ+|q1W?Yq5AWh45v|=efpntbTSq{2Z(*a&bG+Q zQAUdV(%aVqE0HtEi#GZGXQ>upW)|M_XgIF%@qS&~LJNO^{iz<*3n}As zoj0cQ{iyia_{H_b4nHN|naIGw6qZD{cxM^Mdh_D0a})XNp+2&{_x10jgdRy7w(U|T z;CYavfv3(d=QZI@{V8+Zk9(i8?ka!Oyt#N-zO?>#W#1)3*xJO6cNHR;BinRePnu8X zvp)M)NfX*w*-X2guCgR>*SSTJdx#3s`9_!n^iTn1+{S?+Ja!hS-xwSGqu&b%Xp0fF zQ450K$F3?pF)Qs_-zm^-sh)4qP;_fyjQ5RKS5s5GqT_uaM*^UFBgizy-c!bFYE7M! z(yGw1=U+H;UcV(+6h;VBv88v#oLtwPK0bQiZG_Yl+qG~wF5fvAChIuM@_THg{UN#? z35`m*3 zAwdUa?JwH*M!2JzkAfESkApnq6ivkyXYlvexC-2ovWceR^UqzmpKd3NH1#bnAba+n zbfny{=PaT~YcGrhxdpAMi?U|!?vfu>zO@z>O69^U#P0R$Q%iIoIVexMP7SlXQ*rH7 z-HAPTlKk-<`N@zzNyu6gj6ejT?tpKv;9pq4+{Oh+g@uLZWgNHyz#7qxdCk3kH{!v1 zK9};@q7LjP-_yAT2b$d$7>F3!(R_L2K=1-(wm4WD%&(q1*^J~~SIVQv#k+k|HBfj&GLi6r&?z zkU5v?>IHq=wxrsdLWQzlw&NB16jRtKu{aN1`ABW+Aq1QlP`8S}T3E8h2+{d13rOxPYV#XA5ZlFlVAd}0naE>B}NolMjT(h&gF)o7XgGZ|E_9pW)#(p+51>T))ZEQxktPt5jKMmPw9DaC2Najz1g^Qb z(!f_N!)W8E_-gJMK-XD{$3+_w)Yno|V7C++r)5gGD5wTsw@s-@REaKOXjk6~t`3I? z9F5wbg)Ar%SE5P2!F^$yi|GquB#SS4yxWkECue9 zv!8w**22QQBONLQex2d~nF)f|mUmM?=ulOg$yX6AF}~pAqn7S-8S< z=cMo<_7I>tndqJW@OfrBZrF!P|1qt7C6UUuj=wO*_%{Zm36GbCZ~ys(!g&-Z*a9kSy3Xj6@PjoN{hW7Nz( z<(!-Euk)Qw*to#wX|P`k|K&pbrfTt$4U}DFGWcx-NamUIkd$t>fq}p>G5`&S*y;`^ z;L8BY9SpPssl2)RsoA1pdU~sVHcbO#7#z`v@FI$nvJ(6D>rNmJkuyTn1BnG37oB1~ z)DZ|Z^_0hEX;-Js{U;X{h-5av%2#4RV$~HZpy?DjN55TAe#YK!uPAt&7V`tD0c*-_&y9TC8m+`>}LG zB}f>q0uCX-qVA}n-1>c*MRJcJDZ^JrzNBeY^@~pCUj|8o_%%^wx&urX@$Joy1%0fzr~7nM^g+lc^vY7`ze!^aT>czl zzO+`fz>__(Ac0w=B|OxCBL|Y#ZS6RTVXXWlT8ibt06i?+yycgAYsR31IAqvZRAaRP zWy1Fcgc%wG?Ftq6zZM-+A_4W7KiVF?4l2u#Ci?S;I8OD*ekoCl6M4NK_d)v6bn)(M zThgyJh@i{M)BT{^ikHT-EPa+*s5x!2uD2F~^upH5ZTl;(E~GaxgG6caL?XAP(ChK| z7p@E&NFaNB)$?*x4d6YL+1_0Ha?*TK8MH71jg6p(+D5Dbkk1X6Hq6Q))n3x5k0}Fb z4knqlYuBUuPCqP`{dm868}iu2u#IEjod4AnPMX8)r-U)L9HO{-U|va{kyVV)jV39N z1zksM)+~%@vGy`T?tFA^DOkZUP!ln?N9prIjZ4{Ma9Jf%lva%iPKe?W3ITlgm!EBw zl?Q%6vUz^Urld`Gk^ETdxKJ_yIdOU?JoS{A=zNpfuWse@Vi|IlR1TXomle0Q#xcH) zz@xy128*wT;(~cN0lQgwd0ipo?j>j}N{ox&i`p0*faAAuLI1!v`Dkw%30tQ^_Gihe+>bBdu0djzL_OilCQe09Hp0F&>mKWw z7W_KFpwp+3!|U}m&R1q1Hl003zcpwKS$|XW`@mDU(J`@6?z*?cX@b~RnH16Y{c^&I z^6s8HFfQj#%JZ@lV{9omqiSebH+P}9F`LI#jL)(lWQt}uIEr|snAB|&~`V5 z6mEpW9g}FRJ4SfuH_{(j`V0d>^TBVElgi5CVI5qqyYGg6-}D{+u(RuEkrXq`J&d_s z!N=8L)mm4h2TeE7hD?Id)*M?X{~ zpPnR1Tq`?`8l{_tN!W)b9YLAxIpA3a$RUjXB zhYO%W`LPHWdVO@Qi@t~cj4?##_*)>*x#;BkBwl)Y`XLfprx6wx4lytKT*_zn+5hr;-B6xzJE2h<{;TlJBeFKya+c1T2(-GheQ@ zg-u1pyMqZ2A~rp&a4^LGJT(j;;_= zWxvl;ChxJ6s4?~O=9M(Mcxe0f#8qNb5L<$M!94{+_`xap^(zWU1;o2J>TRo2%zzne zjK#o)SHoevo&0eTUb@K=jta~Juw>I&)*YBh?w!9KnC%A&%pT>iI>H`=O)nNNJ7wc8>nbJM^OQ**U74JBm3zPk zP*`#aFV_}LB&@^C1j7&>y(n{4Nfs9QjYrUf&rM9vuXwDL`gml87U}u8FY5a*xpPYC zl%d;n9*!*5?h5T@b(W6rK=y~PO63w{2_M^}*LT!0A z7zN3koaxN)ZhvHV*3cs(cTpngfq4=Gj@2zkT}O%E-037FDn>ElPUUEgvXA>w?=!QX zbw@JJ#tSay6cFT5$`O~#wgt2bI81HJZm^ra+vE+!j2qZtV4DiLlk-rMOh~-9`)WB!5ZxtBVPw|G z&H9e6&;9Obfrpy{mB_yWp2(3)RP^iDf)Ktx8%}%kLzv_@mdNIVr~(vSM*(^t>_cme zc92kOXLu(0MnGdkpd<)f#l zr8ku`_(9lAn4__e3Y@Wy+{Iq*Jc4dHWRKGA;hZv1d7c0=;8O;gNd{Bfb7b6?EJci< z!ytA@EPoy7C?AYZ%qVA8E+WJHlMs&7`>k%YW{G2sYL_ZS!><1Zuv8Tu#fHbI>N#$& zh8AicGA_JKhDT%uB}7_pTmhZWm`mbIyA5}VpPgcn86YbV@mUpn3)@;#uasMy@Y?|g zY4ni--wT-7LX#*hO~()uQ{B4fe1_OkIr@vPLevG~G1+G$%!|>c#5#t-PO;9RvE@t) zu0ftzY`=JFwWcIGjtguI?WP|I$5;?G!zSdKqm|}ghO^~bUohn?n%923dPDE2j7*k9 zD}VVQDJg01?%ssTvsHgNCS-S*_TFldu1gpl?vn+(f0pH?nfoB);9G$gQ+s9eOVgz3 z;}8*M7V%ET0(DJAv)ggfX7_r)NidG6gopaaPoJ)uLtR~bVgia zRq5mrH|&x8w|5_8%Z=-D@S`AaKR~yRefaD6$Y#9Cp_;M{HBz;CKerV5$cEK9_<^1A z?>qWBtKK%ICLaxz4YB-mky25%8pZi0^KdkDg={6gh>o!iEL=SX?uS`37|4wy5r0Ev zHc28G0lR~O`}7@--=DYi3rg8ptK_V@hhPt8x-YWT#6qAJQ4Xbzry3n3r@Fb!o{lcZ ziDd+A66|$;%dI}CLq(p4OA#oYlY~piV@;pHmcuqrBoy=EvK#o!jRQjSddteus_^y5t_gm#l9oGZg)At5X{y({f)qR1a} z4G&E;Q%qBe=$$-+Z>i*`PR7EXI(UfD;?v7(?R`f|j;uR@{%LY$f�j7SK7}1L#`H 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%0A}Ejc#ahx1a)ESW;nDj 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

9l-+TW(J1FULm}Xny|09m; z5ssGxBb)U|t626Jb^w(Jb924Hg0z#0hYr66=W9Oj=IA(d_;59Kv0)`i%Rz7CLv~Hn z$Gjaeba(_UCyhW(2s44*c`OvWF!@<7yST_>E(%jXgJi}Mz_n50K?0;KzrJspVMExW z!*_$;qepk^jvYH4K=|##8jJlQg-Z&h7y_>=$6uL^K5)@^mwM3J5aT4qYY<#qLS4!N z>o?CJ{`v;I4dXaoa?ZgAwseY%)7Ed;aKwh*7ELfuemXQ5v@=GJ?h0)N|E|zwpSNg{ zWk0lzXhllFwgI87Zh?UH5~$RD@YY+2K_MZDzd|mvV)^p4-+%wT3@1tpwSF23>3h;C zV7J_V-~IW?os+ZAIrp6Si!Z)7QKlzVy>;u>qHC_XhT13^k+^9%C7S<_yYAY@(;Nw? z-&e1;-!XY|z_f=S>Ipee8B|l#`t|Ci_~IsW=%IIq0L3pD@+CPhvX1ul-Qcd)goZZG z@oz!_?L7$>7XA2=YUKwzu0YPPI1vIi8IPkC74e-gPF+wQr%Z~#Mz31zD{dYp)A6Xr zDn!l{XfS;F{`+xDzMR|p+qrW)lP^xhC{}@Zdwl*7sOeCLCkprgQP=$RQ;%Q1{k98R zQvoW7en31JR0?2$oLd8{9&Aplic)jn)*S#W%P&w!$#l_=5z4QhrG>-6F|8v_mednG% zj!K+-1!6YG#}j{xXA=MOq*(2ldtJZtZ1r=FI!^v9*y5F}d9JnKx{7*-gJCIf`Xmj4xhNu zpazoVB7tE54EU0>CtNup8~3|eaf7gAo74dk@XG{c3SpAto%i2QAAS1iL3`8F;gQuR z0>J2GvDC?QEPr4@V2pH{4wDL7^1}~@V3bp^Y{iNiXk5^=+@q~AdG|ylM@1$g0p^22 zE_^<7PThaIr)emiYrdwYVLBOD_wfo)0cF4G3`>7^_Ut|QurZF%$jF`($Bhdm(sb`% zYud`bl67$9_1Eu1IW$%gH@)Lqqu{);fOd$1qTrcprlhn)xD!Agfw+rHilNqQcM>sTmkwU!V)nNbn6QRKkZCFYJ_4P9cIe3NzYMU)DB{ z6RQOah?EKVjrujW+``3J1%9S45kXrvfcIXA+e{Qc6#*EpO*5b^9o#Y zYdv}J$x&Q4>({NPBw7qQg@N*9Ir7v~qkE*L29O6%Z;X30GnEg&oT~@;`}s_~^wM~^ z3lKtoo^rEr$L7I;f}_q|Q~KMMX&Q&D#%u1-2wHaCWJRcO9jDmJ%EeM7Kv@kx5i*$= zN0ZeoZZn3|S(`CqMkzi!kVuZRSkO?&C(y~f^?uWU0F<=j@{2C=9X)bnSmwTc{@*WO z?(xM`Z{_R^>1UwBu>2K5?}iFp8es6%DSyv6(DT7vXmQ0D{B+G zl`vG9e)rw6zA(dn=hIIsxBT(PHVV7h7H$d+1+EDQ3ALAAdZ`qff7+dQ-I+RK#E1w< zuWVOa=5mgCIW zjvrbB6df8t3nUB*5sqKfvvFA_3`O+$ix$Cwzun3^*doHhy-w=g+YX<)!jh1bBpk{U z`mkPAajSM%M3`1xSuOlkAYKQXgtzo6xcRtIkbuJ%stk$s|IpN_Dd0l~Zv694W#RYV zqgjT4PHqN`7Su*BMH|50;KHVB$Lp@TDiMv1S-)}Pw$MK$yfRkrpam!l!lG&YdDI0*i~F) z?3zz3Zm4&OxZsEgwF}r*@D!+IfhuE2PD!DYDrJ*PKB}=vWP&83acmbh15utc?&zEv zR^hP#C4QySpq4dm{FD)pWk>yN0jwUYNdUjtxWRg$EJ6s^8$-(ORm1;`!h1=dfByNB zs_Lqpxcwvu`N>OGaTB?1%9JU*IYOiTfqS`x2X4IV69XP_{~%Z*;?am=eSG!*L+G#w zniEKkiB7a6JpFXvE6zJl+==&}d+t$|tzKBXcw(25Sh&jVlRd3+qXeJ{e#Uk*CRe>I;t7o_{`OK;OOr z>o#sIzH{o-yp#I%^Pd0FN1cF}tP2(`%6;*TH;Qk*_S(SlmtGnRs><>F%P;R=_S z=c{kOEuV$o1N!v~Si50E=|7PVjjB)j%l0y!{x@pO{2ny)aD`;cx!JHgR zRA{IT-t3~nVq$!O6*^p@U)C!`t|7e{reB78{oVG$bZ%|Iu{ z6<>dD-fZvNt5@KNks||eO&JYBa{U7Wyax>&7zJO5L$ z%>DAq{rBE?Ur=n=3KkIK*gU2oeDl3YeRGY} zQmR0l6xy-e-UA1C{rvM!2Nr(yRRtU#c|kVOEVcqE>G;HWEhr#JXh4xNCdG_+oxExj z>C!8|bL0Sz7FzY9eHvJA3fC-6!O?%giens!2ePbKUPlid8bNdNxTpve5dATT`S*^KxvsNH`{Q7cC-2B6a9p z;sG6Ba(r1f97U1jvaesi-gPq)$PMuZhBh`TK8rLDO`o1~@%r_pFTL<0g|lA2u3YJO z?8zth#K*;ZJ@(Agq{e(6n=zvtw`=SLg0_FTV1a1&Sr=Wj|Bjn)E_mhbw>j2c8#Zoq zJpR;Ed!Rz-J$=RuB72|bUVgbUDIsAm;o(j2+Zi|Z^2-n0`S-sUz4X>w%xA?WfiDr* z9@#F}ZwDL#@twW8rkbZBBXwjOme=7_!x(A5O-Xf`IHL0r~W?F6`Jc4$P0~V2U88OlX4l_L!O$zUJ~4Bq*fg-H>y?Ikpz09*zxrzA1A^k^qn|DLwwPs1nl#Cm6flsi{%1yd^_3GRdU-d&`4IaE-w-PN zOjx1!>&1RHA9Wqk^#&tA_0x~C9d2*^Pe1+iI3@%I>WGes*827Dr-J2HeF*BLu(HDi zJr*Tn-#*))J9bnL?%&@hJ~mcZ{%yv^4G_NB2leac3;BXj+53IvN^0#`dUx**qS>mz zkjR#j+7+kDP&FkbMG1pzg32mGQwdeJ7|*zDV4{zNJ=Z|BR;~xO;kw&yBa2DObM50N zP6&MC_1D9}GO2_-BHhfV-Errgfw$2uLlEiXejGZ)!5| zSO*Vfjbo2yKmu>*hBq)mqBdsa$hhu(`vT{|Srh6dfD&1_18Osh_efG6bxA?-p2Cv{ z3%-fWFvW~{SSqIDFyuz)VXkc^t*;v`G?+CXDdPd|bLOPoa??$r_e`FgNWu4eAAejB6cb%NpkMzGo-m3E zi)vt4!ix#O@@n~w@NzC(`{e%2G+dM5vujw38uXmiZQHl2;US?GvNUXVA=9x$U|oep zhHLbJ?aqpHFS8^3?(hhj2nfPH9YQ<19Se!aJ}fFNFepd^^++p1ojW)HgqN8L{T)wC zEY;KqM5Lhqw{&SXj$ZSWXrKIoCiJT%(~) zO9BO}2cBx1?KMG(*+Av;F+xOUw{S~7<2d8nF(psilDx&pV+ z*ywbK><%DR4Z>&pk3ala016{I11f9O?$~$mAonE4LCj$p;5{EaT+B6z1qTEnymCs( zHq(HGpyMVV1rCUmJizQ-_urp|baH2A9?B0ixXHz1+XilKROMqWxL=cBT$^?H7l$Ei z$43xV!u2Fmb>Prp5j5dZS`vP`aAD>8wQG0Njp6eDeQ*2sQ%^?W`ueyxUU@Zb=eBKC zq2b{cs`5bFLL9AV=il1EV=s`iaCHjJ02--~8An5v-ULLnPXK>w>uG6zwgHGl2eqOW zm6Yh`UV7;sltl*K=_QHqVc`YqI@_lof0{9O?%c|2uf0~8zhnvh-7D~AE>uO=Z`tA~ zfd3A`hsFsJftnePKcKQm1kc-i;P}Y##W&xGO9yaQB?%O6sN%Q-SG)#~8VKHmS(f4P zK%pSmFJei2H*X#^^b!N92TeXXE{WBaEdEx3yVHQ57ccI?TfKQ2f*Od=&ns7w9p-WN zq{lnhiUK<B$F(sE9ud}e>!tjXN?XdHF--FF}U`RAWYhn_Ojf8&OY6<>b&WhD@) z&ksNRkO#I}K2JrsY?X-Cy7IT*_Ce=72bWQB<0PExzphxZ3u|RSOETX z3D*gn@(TpbwZVWZ-UNK`*`O!*%P~7*fW#pRSQ!Z1J=AhI-QP6tcO)(XfDS2Z z((b(V)|6g-`}+L>$@s@`woYItYr)e;;pVlFu&)VyXBw(pdHLlOKE?dJV#Vg=zx`Gd z8y&4d`=q%=I@5D;lLBKu$!6lMEkex1AvecgtSmfpqW~+UHr`oE(;u7^e?8@Mqo%B( zO#LVqvZ%UYJA$b?wQfAGIvm7$$^_#zAXAYH?s_g`gTIG66?mLDK1& zfF~qXscLs31lRsGx4mrywaslt+oUH@Q}{=z_2m~|?86=TyU#we*laak)PwF69piKM z$dL-H(=<>IG^KSc`SHgZ0x4V68mhtcaVv`1n~_l*3?mEjDuJ*B>#Q|pdvdfWXdxAy zjbkx*oyF_dtrKjXidHUC_K&`P8R$|Hd`~f^_(^z`&*GFrIRLa2n6yO!)T7Q}`z(zJie9CXRsD#x%?CJHu(9&Fsx=}p zBB>KSfHgreULC@W{c`Uc1>y*G(z!d^=NOuT-F7i7oL7E`q~)_%Drl!`9N%$`o(Q2e zt?aM}T1*@!l}Bs{2UQ0UFog~QrXqeNj^GsP&@nxAfoVwy-Wz$*atCkq+*2}c27Tq) zwZshep)l8NFTvO&NK84DEjxCweWad+T9YT*$Qzz%;yz}~7%Ohjh{AYVp@%FG2H67C zCnnNdvwBT2{Wc`QCkiPGaeY(|2Pji50Q zT*!h43cXGOwOGKIYU-{cUL5=Q9z0AHs(5v%jb@DF5lJb)FxdzC$8WzKI|SFyL9zDagUQ;d$)X zu_5EekLyfzF>VI5ax=$YY@qPX9RroI-H$%{Xkm{YJ*@E6A+$*9LqakRzPJ_m;^u~; zeemH2$-F_D?-=;ax=0yv;{|KUK5y>4&A)-S9ugX&9t)K*(U3O$BRAJJtm2pz?aK3p zE_N0!$?)RZtf{JYghWR8T{do9=Yt0il*95f8!Coeqgql*N+M)DSZ3ZBiaMHj$E@8= zt*A9frNblW1_#kx%p5#1fIwKD3{?DwE-?$$1`iq(mD;P94-tl-4pA3X*^c)jBO)Wh zB(m(Dn#!AEd~vZr?oZ2?R|9Fc8bRmg=Cc2mnKNgWz&CLIfB^%-F$VhT)vNPxOfSdn z1zLDmxbN`c!=rDx^_Ff}Y`Y(P@WFgugpie$B@nDc$ebJboC@!C@X_s{R>ODSeU~zD z(7@1LX}ii{PJRftY(s6Z$Ubnuz_65*ln@Fle_HxeHjy(HzLtNOE;;@R?P&yfpCW=V z8hhdO*XeSAaKqi!HgVF`H8c?mb%cta{I@^;@p_5QIaSoA9^t2+;h$i=p#Vlg}3?e+_0w7YpSbl6cQGLq5@LV{KG=&vCKvtX|OkR9Eq)^CE|J>VG8aE0R*iH;p;$y zV;_1+JBUvx3{}F>u683NQ!UY;B*Quzisy%%IF4}u&O$$3L zg64t-gG$^<_|g3Nl|L_Cnnnfuc?%cX-+OOP^r%sz;+_C9LCwB<=Gk4pFI!$2pOk1J z{~3#zV=4Huo|yDdsDJVLDELG0ITJn+_GM@LuiUt?7Pvf7Nh``A0ww<)7MJSOfBh>W z8#k(a^!evDAZZmyx)miGSvd!+1ISsINP5)BQG0O(lFnN;9-00~DpKwulD_`B>kqu~ z<{OSHuDBveAXp!7ZSw7t>-c7dwuS?q+1zKK-+k8$zB(v3QfWyDZ7kkCj%jTTjoQA(!o4*e7D2P4oH!nv;Ov~2 zqSnA1iP1JVMY8c$??VOo)oVBZ!4I`J1ahYEjz|C22GfdA6!d?OKAO_6ckiH0xKU;4 z@4pKq0ZT5A)YH;-5>Zh{meeV|+1-Bg%}I!h*$NkJ@SSXn!d;56ENp4<&U~zgD+oy1 zNlA|xJtqC9pMN4HEs!+YunXqO6}R4UYcAMLI*@eo`0?YDAxu<(XbYj^Y$+=*bA-br zfAZwX$-R2@3fKr|{x{xm%(Ksg!(&|+vamp%XF8EH)CFnaL0Dj0{tE4H z1Y9i%fq?xI6B2xdB_Y-*tp#l<#p|7%T)oL5uHF}XJ**&?7@1$|#)S!?MVgLn(B#zJL&#wkth)s|A zTN+@MD81R~lm7nq^b5z1rO+!7>T5~R;2`zP!dtVswzO#?AG=6umClmDqj$VMd-lGK zn>H0}*|yEW>yE&hX;t~|nb}>|DUftBc+%+^jxlG9ak4ued;GCfjK(fd%oX4%AA);H z$Ju{7yA!E=IS&-{f~`?{^G!GJGm*37+2@`OCvqm`3@W^qt??IfcAtW#pCDQe_D9s& z+z7&mx%`X=zzqoqZqf+O^HFv5^o$i+tpZ!{>=m9hCaz=!X&jqJg)Z@Px%c!zsEaV0}bPG9Sy8^}#}wa8)NC ze{&poJrvc}$TkSVX@e9esZd-!1>ZAuZbgyE?g(^@@lk30NdfP%4xAezV`^yd<5Wk* znh|k)hyDSJ8=qs{z++rrhegnG968z4RKT}|RF>ddVS=e z1!18Y9uZ;Lvv;osDqg2$BYERM9>(2#06tng5@Et>N~h)t+fC|`s|de&&5uYUdDm3r zXCG;7LZIgTauoRS4mwG7G9S~(vYChF$iT%fKMAm<<1jlN@(mGu*b1mZTGV6hH?4I7aHg9G+^7$2FzaI*>5If^)+#a{ z{f`DSeT|#eu?&PyS`PA?Zbi9aN*Lt$FpeM2#s3eX!y{-;u9$QKfswbWb0_BQDSYN+ z^F5H6K#pxO>7=6Qa~Wl;%a<<~$T=ZCL8S*bwvR~l5GYpozSW~~%}_Y5@gYT(18;H! zO59AY^7^cN2)meuMkLX=@r3Qpfxa?%cCl~>1z{g==T>sy^qhV`7)RucOH`FY)X%c1 zS;D||O(5q2q*Egz3Q*Gmd&>nO61Kq~me2ZKkhD%p`lp{DI2=AKf|N8&!PDsHxKE!x zR;beHP_a{JnF!=u^X#+FMmPn6P^D{3AefwNn1i2n)>+;s4?fwOw~@FmZr+_pdX0SV zFHm1jcD5J;>W7o^bPYra=JqBKv&%c@ZK2ZhncbO&zt}F$sSKo~B_+?e z`tmWJ@M9W#@TbuAmy|qy>KH@qw%czD4-N{p!mFSl3PeKpKWGF`6o5;0-I{f!FTVI< zIe7jmPb4n=a?jQ3-=)S$gkzzhGcw--o zlh}SOB{elkSQ7g9plR*flCU)c)Zr1d92^tCIGG}f2!esXMT{9QB0c{{2ViNqu%z^{SQz@f>ezF%*i+39DLE3F}~mdSArj0GJNo0uS+htAcR-WfA_-=MGKZK ztG?yB>jKXkHOdd3=W1rW@Ir9_3~Q#|dv6Go`z@>1t}TV(M#Z>`FZR3o!V3dIMcQAP zHLDo6W!R_Qbysj=e7yG-7>3N6Ge?TOi3vpA=bn467mnLuq`;3=;JCXWX%)!YF?#gq zbh10BC;h~ePjo|D1d{IEyElzYbSRkAKp+_D6bR0RK=9_j9}uc^*l64Zf<1foiR|=U(=eh>?i!>T%;rd@v@9{vUha0a#U${eAC!FTICALPAJF z=v7crQ53NktZPRFR9siwwXCjd|GU;t*Y2vQpeS}x5gQ-^QUnyFLwX@VAfyn|-+TA_ z{m#4dc!>}o?S#sYnz4_*C$U}egrI)&l8aXodlNmGe?*Gq!N>Y=P{iaQxoD2eM zyYs&LvKQg(zdI*Q3Y#!?Y|^?78%nO6FoEgJ$uGXx<&=|7iktb(H~Duz^iT=f#F+KT zCkcu1@nNu<%fUgz6>wD>I&s2;$?9Mid8dFGjzvra!f{>xdjw%q;TgT)RI zs4u2ZPe|?2BjSIPC+ECAb!z#|+Irh41ofB~;V|8tf<9~0z ztwdh7+wZu;3B1>+jn$DuhbPb+j9kWZ*-wr{i8RQeQuINe86+0;4}ssUwr+x%u?+;e z3O*?+AcqbfGiHoGIab2J(<7n-1C6Av@!HZAD=I*s(?*?qa^y|p$43xez_)$wf(1L_ zv$@ykQKN!3Zr)r20-brx@Zq)_uDfnf9MsT2Oo~4Q!MfnQ^AfMT^wQAng@vwPR;#n-0Ke#CWg^L!IgFt88eDlPxnlSC1Y6 zSQ${JM1V}_0Ed9khJcHt>ZdEFQzv_$o;`zML`5OB#6dZ#Ji^Jqbis@V_yh*5ux!XX z7&2(*%rC#(I-pI0ktCwBY1@Bj4wN05K(hlW!^5)Q1w?fa(YT!V!@vm( z53|9lu#TD=HgBjes4rN&Scge=4F;9}=8Oyue7`i@ zi&00^t9towzp+f))@|FWF@VE!a&wuEM8gjRD;O4g2A90#VBqnsCO12mW$WBnV!$|& zdu#q-8SEzzXR6@oxVtFskd4FR-5ZCcC8cSjM~@B$;Sg;N9R1Yjh9G@)q@|@fpsE)H z?T|j;9Q~%fJ1zV6+i$1giyALNIIX(zxei>YUv=M_2<%U=;w0iao}D!y=)@xi_9I<( z0%w#gf==aK^e>LPO2^GYQbO5JU|vW^`LZ~omyGZZaa>&9*UJkknatl3udrOxD;?q7 zTOPzRDlcq^yBN>HGrbm^Fn=R&E{n`3pM0v^ird(Yb+TV|)m2IiLhpZ=6;v^eC2g5+ z5bu$Zf=Ev`f+4%m4RZAmd9m(BFeXjv?Nf9o1iB4yw7E5FPV0480?mO>OTw)`>Vd}(w{cK%qlHMIcGR2OG2ZF( z^78o8cH@mV7Nw-5hz=VFp$YCxPfJgCbpc{xU<6KwRUP8_eKBiR9SC?jIp}F0eI&&9 zhDnol!HA?1gqOd`O_=xn-~VN&BqiCgG^_#_$|xfmoO%ju?70dpK$O?x1$Z%dfoL2Vw?4 zu5xh1Q!do(3bFAgdd>|u1iN?dP9F}=>#n~p_>o5*>5Y|v-;}qfWZiYwT}8cm_40?i zQw^FTDAGM_C<~6oId>~puQpMJL9Q9xBR`tlu=PionE$}n8S;+b2nX(LAjyQ!@(x6U z?-;-Y(9a7u0~yB!f+Fci@EC^|pD{~|)`ogVe=vLpcc~HwdnMj+*q@TFAq<3@=`7e? zkb9f_9pElc1BcHH)kMR*y(cIwASggj+mz-)dxP?MCNY_$Tbon$wj})I-FLfV)e?>g z#{t-NSP~kuzM6?Xs|#5?XHGw!RK$HFv~R$Vixz2RnBZC)KD3q3LWd>LY*BU`JF^-a zU`v)Scf@v$<7)>LIvhms-SEY+qo&I7>zdW(?vhd>Ez@|Gzx>@&fdqleNQzprv$KV( zLEdVR=sQYF%@<#Lja%jh2Cj~!o&FIvtyn(Px(x2xlRJ84@??p_@7#R);m04z_1BQF zLXATlKD{w@D&@>N(_!;dTfJ_b6PKhT(Lg21;hAvj>Aef4lMvxOi){12_F;cvlJIcS zO56c&cb&*p(zk{p&QyhKDAs^uCJhsz3lm+?Lk~UF3mygircRkE#2Fs){NN$ag$c<8 z%R~d>9kxB$WI5P@&*|COBGb$(C?KWP;jl;lecd_|J-xEJT9((auGE+O`m44nBSU^O zU1m;>wrKfsEi*S)-bG=k`re@lG#irxpPkId!fm40sR%Kbn|vm5CTAjn z1XL|&)w`CuQr;Oi}$MMK2xBe?KPD)I);S^;0F%Zz{RWB+s(#A6esSZX$2sxgdTSu5UaqwP* zvV9rq5ou-2a_Z>ZufP7w48z8u|HmJFoR33RcVe^9 zpYBP~&Ialo2aN!#vh1Y_Oa(lcbmyG`?njL?d8bvs|E^zh_0^OQv%gYtxgLM!89OdK zYLU45@!`&Y|J$vXsA*mCGiK@Xc*HrHvz3TB&f%Wn= zF;=iNynBc=j9D;|8E7jL8>&+2E^%G#dv@;;LlSmT!~Rjfc|a}Y=y~~hT!F}@6DL84 za#B$5NSKgo0|pL|jVH=iB^|n&>3|1h$Nt7veyniYO52O#G%}Y;w}=DiC&F{DTz;+QJld zQZf1(ED4VY3~Gf+k}$IWIFV5gmyY?#;e+#)O<#UvoW=qNG%N>&ONKvTXO}KrVsL;! z>AIhoO& zqP1(UyVjib^(+H*j|a1|8_WVDTCB4>1@lmeeQ{@>uSroH#;*+F}53 zKL7-pdlmJ$Xf!k0w|>F(plID6>@zuo5I|6yiha$oOM;DOdB-@?7M#F3c<`Y{?x)W0Vue?B3tA=^Czy;NM-A`ts0IPlYBv(EgDz9e7vNXL@q=GpWY&1G@6NJ zNhopNfYUDMe#?rfy0X$4o0t%E*_BuI*tT_B#q%$}oClY)jA!)d)hh}6FxYkoyOpt9?8o2sB%dh^j6@Knz&*8`CjAcGymCHSB4}8I!0hqRM_|;Hn9IFPn)Z)Rv6) zpliXjhg)FXDcYkRHVkq+D-qU3wF~Q{p7~zd&fR7rT7i?LR;{)*0qfM}nEcK=R0U;+ zv9W1MXx`kZ6MT(SINzK$P3dymZol(R7mSCrAUKI?@1Z$Z)8Pp;5snB-E{bY7+$bbM zaMJ|ul_jB0wLARYE8+mM{230f7H~Uj!|ojj5l_$I9f5koo-sl~gmtnVh@>QWl%yPo}x)q$%^8cetmXZVZDYdPR9a=tnzgQ_OP6ln1`}gi`!r;uH^Ds-xqpd(|ayiXGw+>67iHuOOGq>*8 zp-=nlv+9{&e32Fw5vI*wxX3Z>y=if$o_cD+fBx^$jLC1lS##2e5k?JE*yuJAz0hK3 z5;nO<|4i7V7NFJ#WUa=lufAG|D+`&Be_>!{rR+v?S>q~v6RjPu)dIw>MS=D>Ak<>qKx z3$`j`ZO(+p{3WO*B^|{_MMjCdTYYQFo%zA3l4+TYHzkWk)6i!!O}@RxX`}J?_mObY z**p9%?=MQLy@z2B4R&1DTz+}rzwWpr#UCOoYOrx5_=#tq4cJjCy5P;OW2;r56*E@& z2z>~aVqSFax%N9IP3ryA(xt&e`uBGX=+nofivut(`vTJ1hsS8inEt z%VN-#o0G%WE;uNnZv?HfMhLVE#F?Ee1R9-gSdMBKx5t92;L728_vlGjwpj|Ln8Qi;X zXyb?y0I#F#q_Ga9UM^ zThH?8)2COrHIarKm2esJe*U?(`r(H+!dHnjBBH`C#7gc~ph_iLb=+U9j<_joRpE--*V zt9JzGNa?~3OQ6|-;GFetuoOIR^yq*wr=Q-3OQP){%-{d?lm69=FElLkdc?!Q4rgZQ zQyN*>*<~Qm>0rHN0IOq#4i!V`TN%XJ96EHU{mG}EOif8i3E?uasYt~EMvniCGtY2> z2&TRI%BvOdFJXhfV2tAs< zHVvnA*I={Gpx$v?1g?C-;czGy4wG=v2t!R9Bsg`{>YxV45gSl-GA#%?L_y}KUw)|! zRaB!8@A+(itF||EJ-~#m9l$Az6EKVw_%w676s5y2u`a|na?&{7-3`VOFwb^a0<92< z80WDf1c8QsW!b^zGKp$-$|IJzneZv zY7c?McbcMEzX`f0a1y}=nC;9n&x{6vE(2lJgF}M#$_n?vrJjff`2h22I)}Y8&8lnDB2c`s*Ci zsE-Fv+X%cS71JCbJ3N7Ai;5m4EeV03ywG59l<&4Aw7#{DB_Rp|!7?H97Fh*+{L+Km zK8bY0p66gf@FtEXiQkA3Bf89)JI8$K#h13h%Uc~?RKnTKjF0C-+QlD z6_vVW?>Ly31ll!p@Zg~F*Id(+y3icpgbl7ewH52uqF#r`pl;cg+1pp-L=nt^I7SR7 z@1)FLw8(bM;KAC^fdlEgMoty~b=9ge5a=}eK%v(_ZXUK~;K2e2f~zmQ`f5Jp;RQs% z^0M8o9=&@8T|0h!YC*x)%Ktp|RBoqE(I)*i^cyfBrL3X?+IT@gwT|1TM+AXp?~`Dt zi!=w=ptvjfjE{S%4&SsyaFaQ*nq2zp+1c6U%a<=N0#eb#+CEDlvLV2ayy*wR5{f(5 zb3Cz|^5P)Kw*5hP;x4}U;&5nm>|DKiwG*5*iS!>h^L-Tnf==$5_Pq4Yq~)I31_(NiqjD@+wyY3N-Nlm~-kCT}COj-8BnVYw!?%22v*g1daI!+s zx8Rg>Xf|yx*aBq@!*G>@5R+TRK8=x{nMvQ_I{m2A4Q^`(3*BU;JN?s7y_Y%8>&9KL zM?hq_dr!IZ<1fFE4hB5No&Wr&3;ihuNv#cEbMxQ#NI$q-J3N6VM@QK+H;gFGpeO^( zG*s5AglJL`A3+Yr#CKsYr0Lw8#=*7X{$lMV117~O+qZ46oOJ6XI;C#Rc9udy0+ou3 zzJtB{mpQ86v~f+srCGjy`FOy9WuwGdym&F)Px4viM}NZ77!tuv#JHQEg-iJlR&lK; zawAN2Z^8dCIPtv)&+e_ecidKe#^x3`g$9zt3K8(U@rrdMJQCex0pY<3wuA>KyqlmcIA>KJ zamnf%^Q03_u;C;i5kcl>Wx1koc4%#_oF=3X?A6O2->sWw$2g)N4vMdkP-W90?;Vyv zv%_ggxD96#zKdnkw5d}!ck0qb`)%b)$Gg+sjXUkM)4Dxy{{xxtyz@@=kimnE-B{w0 zP$IPWnS_8vNCL?N@^}66%P);#6~Flp8#;^*>rHQ>N#MK)vOCWMBdEk$))`BdA-~uFf9aySvD!U`1(UW@lI4 zdEb4-JW(4i66B-O#Xm!E$@<|O2ux8LrM z)5^JDL}tS8hXo6?l0AD+H9_gt1kq=CcUS@~Eo#lo?9iMoTg-rvAig%i1wvB?+8l0n z)K$J`w+^)|Axf>$6F?v#v={)c%g2lfzWpEnNZ^5_EQ=s4TeV8hhcAR-0|%OYQd7;z zQ>O-h@ZERx-P>x%Zyl(f#CmQH4H+=N{`^x^@^wHv6ha5cywC&T+ zKHCZn374-2N(8iL=y#)cuU>xVoN-1x4^8F7L-o6bOO|L$fB&6xWXB!N2k2C`1^p@` zm^kI#IQ68H5)2sg4C>ogI~p5>+$7{41vUxkHEtIPCv}h=c;A}Af=P;iHLE{132pR^ zLrX&V%h7h=paxDHIL+H18<%cfZqx;04i7`on(+BD?~YBN(Xw0ymAhwW=jP4nY-U>V1L7dr0#+tQjYd`$tlWZ)7al(jjTP|#bc8-pS2*dsZD72eOwOxz0 zpOV;T2s#d-b$<2jw^^_Y@ZSM7$aOdzm)bY9!pzCfms8_+mzT@r)|Su%J{QLy)$MF` zbvogt)gy^97#tBt5>76K)T*y7;cM%%Iy8Z1M|Q%Dd-Acz`ky>(SORwSHJGuQP~Qn% zhf|lwUVKU1gv%}$-7tTf&DgSSTh*<1-BrvDJ$8g3LJRhY5NYT$bEyr&>sCnv0&?Sy z9=qrQ6}rf3Q23nF;{-x3nLa?sU2zFaIH}idePbOAh=yExU;xD*J`LoyFmdSf7cX|; z@;pr9wB5aou)+N20}t?&;D&n#T-h0r1KZkqlaPQh z5b+iAtGm4SnpeHw^ILlk&4IPU5@-@boaU{=0z-qIrysB`UN#BAt$sRdmNswBTXTtlk+8{!u+Zcr)dgC^Ki(g^iOUm1z5%yOE27$$O zig=A})GZ;wZ%aV|SCaLD_bDg!KD6==rEO)@)EHdl62Hh85XT^v6i!-!(4O#4!L+Zt zYV3V|JJ36CBtB5w!|pprB}D|5mIU0IImJ5`I~_h{bz0|%V-_r(@Xi1t2zwzFMLHEA z7ZZI;oa^RkYskcOY~t`!^;O74|-M+6F)u6c!(oRI2ke%6BCX6{CrQk#vWL% zzkh(vjTnee1SBFGcB`TK=P%CDY5hh{zdZyF91bd49>P}%<&y#{28_lF16S%oLRf>i zz7B*B!Ng{gkq{RbhD|0h73Mw!y|r!3$q^9Q4@Y9~t~d3Z(MBOO%je1V-1p#0l1`Ig zJxFy^llBAR6u*g$rN$bFzIb+YxExw(ajA&(ytA|p4v_H)x3Kw<5fKF#u!vji8gSH6 zK{x&N=APTO7F6E<$RpX9G&CDLP7WD5v`1x4O(4b#s?`oB-4?>J4o{#t6v?rI*tku- z@l3?watYt?(#_3sHfB5($TjewO*%coJM;6;KacO%zh4vxD>Xo9xmWkb>u==0{r1}x z-Me?U!>Uj6^&SK&FW&jy&+ezErERWVwR&|ih=$0Zsc)K{*a zKPF^lI_=zVrNFSpf;NF}wKL0#n=m{r8V-LzLTWUr*hjY?8 zh~^OVCBOXQcVLf!Xv_Aj8*3RX7+5JSIA)eGaA;}XsT7aR63)<~|JyYoL4&2C^Z6H^j~O*;R2(?m+K)c^D0j{3HB~?^|=R{}aEev<(gj+kZZ*5yEnDhd znLN3YV}hJ+Q~H)0eD3XJ&HUiQ58~nXB>^r8TxXwicG36WeP0Wgy!1mZXrgcp<(Q|A z9BBtPuVaT$-_AB7i>EfhIsa4ygjZppO|gEa-1H z-PDWnd~OU=2E7g1J9C#Trm(W@8`QhCeE7^hg-1m~V8VNy9UlKu<}O}rJ9^L{w>LXz zz;NYAZ+0NiX^;gs*_&N*af6OTueIFtB;$T|YB2h*?#)Wpj7|9Rkn?#arM z5EJay!b1Iv&pzj;kpI2-V!s$z5|S~1_{#pn{P|k(VPHw<8Pu%BA%+f3pxG8AbfNHP zfejB^YR{e;o!sM)I>X^`YMmk@h^_Y2)Kp^&Hu|XBtDN*Bjx^^}Aw?aNRer|gF z_WSQ1{~Hp)2Y)y*P!1o1o&3A+xFZT&zH{y7&GeIC_Q&~kJg<&~51WPh^mpFbP1(FJ zCKKME8)i6EB zoeJ3CwPQoqfF_4O)mpIvmQ%$6myXq?UnHzWSqGVH4iihly|q)dJotNuC(x=XNNgxp za0eN-kjJ@kg#){x^&sWR*x|O{amO9IdiLrWGIHd|*zx1Wr;Z&vR){{e8lZMp_slcT zxUoeaCvtIsZz>0=bYpAX6Ho^TC)w?Vcx(e_a@p}hAJ2v8pee2{`>D&;mX;xc@y}gV1Mr8G!`&UO~wJ2Oy3}a{}i==W9C>f zIgZJV1K0kvBy6l9+xs^X3oNPht}s+N<+$Slt{gMQedHBn(5p6Y@|!z*jy7@Z*dF)& z;~y^TBnew?e*W&WF1|RQgPaGcLhkIk=9+7QfN1o~tQD6O*MP{^!Iy^tZ+JmKI6uhL zB0m23<7yIrid2X^`wW1G69TwyTbItA{VgPu&=a& zh8MYKyrUx`oq8~+UUL`)sc%dCp=y|=A>b`W;@<7IGA zpOKcP4Iel#*kefuc_n6UH+zA`wuq$b%(Kpn=-01b2psK~fP>D3?3shz_3VG2jT$#@ zTq-&1sRC{H7?=ADGa;vU)+UXrMJ2;1Igyt3Z6 z6PnivYLUCJ5p@>5*ED5j8a5f8GdY5)7?|ky8djU0^%Yi~ z(*9&fR1j?@>qkXZm6PhNuo!gGMgW6M4+{^6vYjsPDlo}1Elmr#dOI9CvpMWQhbGVp z0Z0(hk@(}r6A~IrA6DKm9%aPJYKrkWYa{5`_+ss=-dU0k3qC zkx`NQ(j`lG!<(Cv8;6H-vI#Ty1d7w}gXPN2^TD?dY$vt}4GSm(|7f+Y>>@2iuZDJbLE&b%AhTAQImRz6C~RnV~A$koa9ZOqltGe8aSy; z)#fgLKlaQsd2kyGjMBATJ9j#d8h&i>-)_CN7tSQCxaZz`v!T{W{4<6gb4)52ufX6C z+DElROF~t-X5Nn&0xiS^oz9Mz5es=R38Er8yyLe}NXEhTHXY{Mo_OL39`}?s;f4u4 zh72AO$=RFHh`95An!n?`bI;p?@6@A~-R8#ngH#xVP7G$GY!-;Tu$0rWv=qX}I}fz= zc>u69@V!+_}1fLqi3Zd`YKE;mr<5Ug`4}Epp&0 zwAzq;O3_u&S!bOUrnGZ>-oCy70G*?}*{xZ>-h>!~YNH-P=>?Jw)i;|(IK5sU{38v* z3SbO#)Ucy$uh#=7HKq7%$cxIP!>Far?zFCOE_>^@}k=`QG zWm(x-n@>35gb)%e%;3~_c0Byh!(x>JZ4Uz`(L%TtvM~?u!14n8{fwD2zNmz{UmkwT zv`;brAEd#-m@H^4X&Epf*G#_N6@3x z-AxPKf6*pjM(pfsG=su5xm%p}A-4_*CbNTOtwvjctFO8`a^l2^Da?=8xN+kWlarEz zL7=lB8idPd_r41YBL2W=#vqdt77?zm->?x*%7UO0i?nqPqLvYhO>`V0YvV*r97JJ< z4CCRHpu-YqA_;US%|cke&6+#68k>T7DAnnux4fw>Es^C_K!aNs2Z2j(_Lm#XbcNvUC$NdfVS`xg~Y+Z@&fOtUpKZo;^jq z4P(Z(IX%7fit*#OL956hhf5j$!3LJWz~j;oY(LHWsRCLYTS9_EY*g{1sBGcS3(45% z^dw0F?H%9;M1Cf?Ck)yw$o_}gaKw1lYQfxaY)Dz{0PnovZ|Ub|6KFP)TY}2T%-uOH z4dkKZC-5KvAt8am@>~0T<3{I;&p)qhupMV!I3}j&Lg9!EO=w9qx@TiC2YXX_!9XJK9i%@oj=aad_xF}~ zCh!EjvCuFM;ZZO(maegH%_h*&;h4o#>o-eU8?X!;rK~&^}xWh@4 z;R*?*FJ+01Wt|QeilS8l*)A*4?B+ZOFb)_+)hik2*U|q01}rBiQ>-9yhw}yv?jH#& z)KT`?GzToBB_mkem$78&(we89e}1EE5(1|nOLxtgJ2yTtAt4HFPL8Zyv~Nq+{eXE{ zHLk65Z+#x(Bo!`opE6oVVjIn_#u5Pz(+eVhzAmiXAGCE)p-VxZuuqG5D z4X==PrL{rgO3t}4byV+s4(3@l_fej7E5^HG81Z8NG^Md`4GU#l1W&#VzpLMbLD4Wi zTUT>NMzaaDf{lZ@S$MB1rZQ~G-8&DjXCmGfI5UDMgSkq3k#GZPF5&FOU#v9s+ zBXDS}MZ}w1{-LHv`-mms@kbx+_vXtl_u2v1lRqwAtV0t*JN1MU#N8;CnI^ba`zN1% zmP1QI57%?3g|$$8iv!d*rlq-XQB_O@&V(`DQc^H~H@`1cria^|cxDjrt=KtP$ zizeOsVv!AKQrLKeSW|-b!%2>KojjmXkn-+cF-A912R zaQgdc^0s_!#zN#X^28HEa6}lLfw{uq1BP5K@ep1Mo!`!$UB^k9?Z>M*p(XP0E}w8h zyD#?>Kpbcx zr*rj$6##%_FC3YHgp&P+U>&2!!7i$9ds=x3APu<4ktUv^y$}x<2s}% zZFtZG`jbyS5tot}l=+}{GjYEh1-eN1$f+=Zz;Kq}lq)831ju_dG^B|9rrxP%@Ayp5 zz&PqVf2%m^J>PlfBQc=uLxP9P*s^5{yb|tl;v#nPXcZ=bDqWK%HA&mlKa`iT^AOl% zo+_w1k$!ldn_5UqrrQgvf?IM2_b;k;tcz8jmMpbNd2zx((7`ykN{Wjs?eNS-_D?3i z+FHGwzFg7TP$YTZcO9TU=O@{jc2wM7(*St zc5HwFj6oflS<#L`jISPfx%%o4w#6 z&L)pKbyR1pPL9k?LaQ;j5<<}D{PdF(S7zUyJ#7?KmO@VK9k}Ym-i-GvpF9)SDAK^{ z+_?Vw>%rg$;}zbS&QhrDRnu`9CT5=_Ac3l^s&sWv>>hCOB^P(g&&#ivFkwP|LPCPk zr%#{zr%ah5POU8(deHD5G=XOC00wi^s8RO$^XEHWdF7QASZ=TfT{y}nASETmc=(Zr zyWRi5{lZ!Kq&N3bC>sQ?F>c*7k25Z~erUN1m1$E#NIJ&VMqq$H#RKe9%>j;DoH&6C zpd5{Q)z&g}AGK-QS0um~r-Vza9|<416$K~1QNCu!S&MZCjdHD92QGWz$AQr7b@t$X zHaQ`y)l=(2(Qb1WnX(sj&P^E^{MoSgc#^h=H@xDu>7yF2{sI1+E9km36#m!;s`nN! zZW|kp;)XR)&^Go>#c6nNMjDP8dcv%#ta9b#`)OVU{8H?|>?Q&(#%pI`Z};H|#CcC) zVPVaZB}>Hkf;yY69VnZkO!T{1vnny8=2P8^WpWw0AuUa(L5&T|q3oT&DsuiELVD3no+oIo9Ti~nuM7m1^QILnT_QaUpqF6 z$mz>KcdgXOISm8h+AFT;jLAgyMgW&Nb^7$+-Fv_#qBVUDr?1+G?EnHH_%v+LAY=Ts z*LK;EnHkhAF3y>fm?--U=vQiZRNwdLqh++#s{zLiTxfHUsri9m{J!e)!Ez#oeI-#!cc@6Cx6~FlE5FO^50tiHfaj*RBTC48t~V+~}d5hXV5<6KG^E zjk0FV8qNefLr;Ha>O0lAat@{7b`sYH0lrREpw9}sb{dW3n;7$>DYW4-U>j3LO6u*iIifdj7HX5Q2UfgipK(S~Ak^sw z_wB14Gh~S9C&QJn5a<%DG;JCjCaF_~+Oh^@n&_+J=bwLej5=jh7Ro+kV%(PS z?xQRYc{_Z{o46F$e8_cZ3V~Lz$YjQu4lKQn8O{y_;NVq+M#VdryGr9-fkVwp<-zj2 zpS{cXyeFvGJQS@7MUcEBw)C^RV4-b#a&oe*w6sKX;n*z(s5%KZ3WCUkXEmG*;&V$v z?>509v2>inW4dIyiRG`TFVf%uenoU}IPK!l*kZRurh!9uYd)VjGf%16p)M}K*eNkC zF7!_sv|9!ZZ+5Ql=gi5?fhA!vRKYUR(`6!qh)p=MX_3aaQHVVG>1TYmWsPzACF5lpt>IlKq`&8tF#S&tM~i5d&l*D z_Kv&H_wIScJ6h{L<6Je}AF^C27hLil=xbBsBnTWIwPJX5Q(MF2U1OH*T|Q-MJZZTc zYL##;DhG>FE=cvjFmO5EX?^+3O)W0Ve_XJ@fy;elw0pAVOc*$7)G47yvNt;}@44ZI zps!xH&UM>8_t5c$Xg2YsS7^33JFmQ&^~gzrYHDCyM1D@j;cy6~hu&kTsW3N-KsU9} zBQYHjiD+ zM#7N~^dtj00OTDw8aR~^3q4vA!gVRRRe{Qv+ycv{!Axjipbkevfh2si8YFCVJmhUj z7#$rAOF~Pz+=mPfCy(trce*aS@WOye6DKCvuqjK51X;cb^ZC#X&{*(go3;_E?Y9^b zXPeDEZ=HPNiMBf@O-fp^W=%-XJ`1S zwA8OpYN~eBph3c=auT*Cv2FAYC^Bf^=AXegE$}CSZsT^ZXG!Q)whRhVa9r(zIxE=R zFaf;!7K8i^kp{IQ)PPnge0JY~LlY2;Met_#?8`52Qk#T;(Yf&FpX2)`B}HPA@u-^l z3{W2wEck_TEwgQX)tWWV*QZQL!^W!L>Q$?_VW>8$^@6QiNs$e@(&Z}Z&)~Zj@CkvY zu>%bn8n)|3^4iw?wXi11?A;`QV$X_orc^`pTzgTcx0GRLO52p_`fv_G*aOtj0 z{iJRE3vzI7VCuiGTj#{(Z3agw)9K`sN2*=*wg#=;l*dg%sM_h-d3h!dF`#~_lGS^| zs6(gR-X1Ioy@B%8GkyB7-MDgW>(J%|ngl8&G{n8s!bq>Is1y$DNLY5Vj^ygt;o#)Z z6mY15j;Cdwvd-f&otA|RBz`_?7r;u{Esl)QDJq}=gIE&!*=1K9KCQJnINqV=iJ#4G z)LJHbZdxwjxA`CHZNs^b*%LaxII%huZ7uDGc6NR9{rCRWH5g!OMrm{Cd|x1^Q{o&| z4Z9~K=qI0aQpncALjO*YkuHclOzty~cteiw{Nn4cYk3$jy%_oo2YugUg6q^GVY^XW zMloMohBhbA95iL6Wy&;3r)~X_z)2IydE^xw$yfC2+c(eKl5qK|-}UVLJPlq|%$)3O z8VYpj-LGE|($H*PF|2Kd7lajb%!E&1J#F1O$CqD!y&cZmoxl9@3;aQM5;y~CNr=gX zmV_Tnn^tz^EjNoLA@JB|p{wQ14jW)WkNo@J{V;imJ~_D`KfwF;=bvdKPddqm5c;fX zq+rgWoWu~!5yu~IzxU2NQ|A2qbHGq|vK!LBKgAznJqi`PVi4#|y2hnXXkT!SzHKRY z>6RBd6B;CHS{FMfj*qqqZAPG}f<-^VFoSeWo;>N0-*o6ZvbhMudqGZFlj&v@jV?*2RV_8xhS$|-jt-+Or91uP0n_1lZzE2+%?Na2VxnhxaMV#pMGqQ0C=91$?*M_Wh0`TFxM;dM^bn+ufDSgh zdx;JDAkNUCY##tZ7T_UbRwdoU&MnRm%>xXg*Is?ieD&2=8KVtJ+#g&0z6b8Jf!m6v zhKULd;Rm(WNF2EV$2cVL7LngeuvOw#yz{s+z-D~<<(IX%GQ5f+RZ0fF!JA#%E>XQ; zXcv#wZhd0?o7uA+xH92G+qM<$)-a&|jFNWX&8{I_ZSkA?WAO>`ItaAu{PWNEA2w`Q zXAo!#ptqAw!EuwGlatdX`x&iHpgEX%<>uyckZ=H-HMKPk%-mXWNijJ|C;WQgrs`)qQn)7m-Z>je* zL+7a~$WP%LfhJXEU$j{}wp4vuIv<>eEk0o^-DU@fvy90G<=}wi&}JQZ)gZsa<|ow* zc}mNM^&5ykE;u=IV$3=*F8SLDx@Bf%Wf7+gn#H%a_@`9~v~o>}O1a*A^UW^(2lS6% zW#Qo|gu-_COHH`?>Z{{Ggj}z`{`$7hKKrbubC=G>&K;sI)vh{qe*|VtG z%(KqiK4i#{&KMYO?h-C94<_`7Ob`yqA?M}MScb-d#h{*f!h||-Kt1#B9n^RAPQ_Ed z8@sa{auS?SK%7Z<1^)e|QSedDo{^DJ`tnOJ(;b-&UIQCVx4-RGPdUYY zBRsWn0FfeNqsx4I+O*L8!a^?{l%|w$c&8z*qJL<3VxD;1amMx6Toboq_3FUhJ$g7( zlaoyzq>PPVBP%DT>YoohPzrB`VyL1Rj>Eh52ZmmWHNcqI9(wqpZdmd1h$#93;fYNC z^B2rdMf>Pm^0!o8am5vdAkJoM@1eCSf#v|`jDx1pDb^S~WN;WAppZCY(3?Gb^^EZM z^OsGC0RsjUgFsjFsCE$OHXGCj>Nav+6wg?*rHPe*9HkW(9|y)3r=#E>XIyx!@?^!; z0X=c?{e>4?xaHDIFWng$779~ikW7f5l_tmC|4J59}x*Rxp?$dJr)`;is;7A-w!8A*yLM9WrgeW z&psD@B=%)vo&s4W>&nd->_ccE<{mNFq1Q;$a6}Ucw5w0gp8n^ZeRd)>Ovw4uf^*q# zziG4Q%`?wD{j_>@Xi7PUYZ|t-r6FYYfWxj+Pd+(`_W8%aNM$H4I=>2`H@j72ur7mhbh)z~2fsRX+ul6pFyHa;;e`; z-q#E2JrSG}0NPH{lSA>Ach^gFfFDJ0+J#^&UbLv@o%i0$!2rX&AqU60aBf|6pZ@(q z9gg}wwn?-O_rM8N^ltW35$`%eyvSI3T1JNRhq-fe)3UPs%S%dJY3b?ozhOel!}xv8 z8lLtoM>Ua|I#L1|1O(&#_usDp5#9t>%C?Be2>Vr6U6l-4R)<4M@_?TjPD`l;adwfm z?Q|PQwOSK3g_}?VvMZqa5LYxV_PQF_c&r~d2tlwo0C|~Xk?2uRF3?z|%eN7?wHQ|exP@x?v;`uDS6_Ls|oQ7;2rt-fs8vZ~KM z{j3^Z-)!{k$H3JCmp~BN=r>HbAsFAFVrtXUGt+Ca0a%HRQG?4PwhaThZur2JlZxTG zm2KfBcYt8^>eVK=aC=HhivP4}(<;doVmDb24ha^rPh!W(kh4DtBMwgxSupc;)Hx(y z4pPQr;KY*$Lj@pS05(5d-+ue8^xwpZ69X46Tv)ql({rBIi-+S-9O5_uK{PD*JZQZuD?&+tV=0vL|W)Xnv!`(Ds!ar-M*escxkjS3yHA9ht1oiFOJV8`9MN}d zFLXf@XET81*i+7u6zt~bGiD@~m+y9ryMA0DaM4DK!Xrh@!M3vMO1yM{YYzPOyKjep z*{JE)x8GX4<9nC~_!|dUSrF$GO&pKs)l7%$ke0x$%0UAd3FIcpVM3;3gI``JPaWU@ zBymFoKQw}kMCbq&wsLEmTO4$1K`dM^yzoM&zg+g06w1y)Q0)T;4a_avURZnMO*i&} zs!}Zox$WYMFLrk8)-Cge=U=EG;UxiLdJsVuzJ>hl*1z?F7{P>i!(@CAhwQuVxQiz) zu>PvU4D1{m6oFu4f@}*rn1OLzT@$(nL7v?iE0J9MHZAwADlOv~*j<*g0ry^&3wL@V zh6GML7<7Dgq7Jc06M-Xn)<5?6V-Xiza6xj-gEbo;fBf;N<4-s~9+O7hB>|V%Fd1ZY zOYG*4x+J5{bwpqws15Cr*Cn=#{kGd~>%|N~SdBr01{I9GX6$xMJi-aHpGhPr--8&4 z$W8y@2H^m4Cj92tv%c;Q!r2MsZT#Sa4{Bn&#_9$6?$rq6A8Y`}BLsTH2`7Y}ckVf{ z*_jy?Ake#x8-A>@Z21bKx~f`4MiqN1WI|*;4u(JR?6L&wF&+Hq2j4YFo43X}T!4I5o(JKKm6Cv?R`$BCA5RuQ$e<}&_3u(#!R zH4$MCh_p(_IHqV)9Bu&)8<+|k+Y!uKn}F3S1e(Z2xh)1EERk?XCp3Y%NoFlwbu1ya zC8s18&-`j;6_11|D=#zg8>#RQdcz2~?Y%c_3Hc6v;SxB#FWFThgN#I=r2@H7a&pK| z2T_b)w{~68*=L`f0WnNGDssJZvvd(#&$T3iRtuh*4VUKtMpO|C>{O~dY< zJfowc4HDdI_X))562*8W6$P>MKl$X7Lm>YZ<@ulH{ZvjFKE4}|KKf`BxJf@E z(w41TYMy%HDGoN_Ovyc~exTeK2}l^#Bb?gx*Iyq5t5PF5DLD*h&)EWl0zugTr_nUD zWPKTU0yLQd5F(inigt;%Q0=N!t2ETjOzo9Qv6arYAl`_00Ik~a&b$;}{o&4Tke=8_ zoPB-U$Gdv@@BNOV0*oD0bb{DN{4S zmW+=;DjQFTC)=WDL4$zUN^3dBM*c!6nzRPKYBS4wjDz)Bw>c1!q|Yafuz9 zdI4dfVRn>VxAM1@Y}A^Jw2boTUW*l#4Punu7yw%ydGwL2XP$Yc zFAg7W4lV$ky+QEMLOnclw&aQ>cE;y3?3ip#^eGM;a1(S)kZwYV;VR@B3ODuMVW6Y_ z5{HAHLH%YtH?2g-#6u(^hWf3_V>(PkR+)?=8Hsf# z<1(-fT!>SLdfKpb#|lLZ!tlNrWl{9wSy>SWRp2t8X%Q?4)tAHP&bH+KQPIvK7cW5G zWZZh_p@-aZOSD%;dPc)WU>kAI#lTo=_^sK$Ta-YvV;O)T<{fw35en|uA3*b2MMrY6S?#BW#PO@f1R+##FymdSu`>f96tc&fGZ_^M0J?IFPmg6CX+-w?Tgyl-E7@ z;Dfo~d{fRm^UMSiJZPSTVDhOXFFPY;20?vHvaqH z|E7X?)j(7bilx46!mu5{(bRHEqh;kq7hMzsLLUSfY1xPqMr4i{F@nU>!~vAG0|pJ) zg2^GCb!GMtA=of$?-_d3&`r>QvCsHoM!(zsep_d7#Gz}~tlfFmS!ZQF|NQe^&L4Ar zBDhp{2cRF=+*W^3HmO(FR69|(^lPrUCj5a1ALz;UW&R-8>`WWw!K@3~#6>Rq)X}HL zhlPjj0D-QAv5|qYsIlR9_E~4gL0l4^o0D6%V#Nv>5Nfl}5?$HAi4?u|`fG77y!b+N zRAiJNRKAQ`|8{HfO%rblB47%C2xD_Y1Ds=Bs=%dZVMUS%F^apBnp;RaNY8rmQbd^` zk=Rmm#od*17N%%p;1kCpkNTke$URt@z$}U(7uVX%lN7*-ix&skZwG)w!L=s<&@W^lxl@LWi z$oz^5$3q{Ay()<#7V#c(BToci@(F3peC9 z+m-?8Ymq<2Xv8TYK74<;1vQa-PfFf(U^{`4A%S**X^F=Mb`0ByZKrVGJAPB2Sw71G z!&S3x-MUQ>LDoV0!)Qsj6)idvNE{H%$cRV-h-xE&*t~gjDTx?}0qRm;=EKOSA23CT zhV>mWfmVW9h>swMWTl0F0EY`&3IX6aao|HJ3*`qj{0?ls#Da5oV1n9#&6uF;uD>oJHa6Dp=9_L#{Bh2Y z+2BZA)MT;JxHD+}Um~ClIO4)Z@tP+jCM0P21qIHjuf7_4+_A^Td^%&smWQ8ustjh( z_7A5_=??2e+rJ)uICtK{g*E@a^Um?^9sdU3enjslPBlCF?H&mTP92hx#gytlCrY1%P+e6>H?e{X`oE{ z+aS&~8q}C;G*TOWM865%Qdgc@PfC=4@g}OAWX^!6GI5a^V0>%R;z>n3%v#&Dc~dEv z95`TvF@a=PpB}l1jC(L4I5_)hXtA8~g;CKS`RZ{KjmC9p$UGO!+& zT-!MB-17?Fo%U`m5P&LZ)KDnA?DES3z%_26Rth@DMzIFCOG!gmn4Ty4B0zg!Sq;Pv zIY2HQChfIPKJjEaX7rG^-h8V96Ic3$7hl+kTsFi4+d;TXu+dmfLOr1W032_03iga|hG_E8d^}KGpZ^fGr$%ikYNi zI1!R7#KgcP#>}s0?!c;#-|WBr_FL_&uV>|h%dLQZdc|XpJ=O&)6Tff1`KDyzO%n@m zx#gBnSO_wq5!ERQj+C}g3}hQScI zsC763GIMhya<^>p!|%fKiV9g3;8_S5?<%NqtA4kqyBbg2#{lk_z$0&3K~N1aF7%Bd z%LL-2BH;W8<^O3d=Gt07?h`D0Tg&YOKq2{j#$nL;Cdy z3kVCb!!@#LZY`>=o%d^L^}3Dab$VowF(}^8D662cu8ZgO=^!LD0Fg#!ISBGcmEBTz z?reitkRvv)zwUYtPBy)crIY>BPd=^1MUjGy9J4p)u8xxhbB2LLlxgq2`)xLf6cI=d)m1cxSZm;p{Vch=w?zcC$GEYOmm+=1Eyk~i{VV1uf3R5f)G+Klt#2ZonJk(n~Ha zz<1aux#=+Rj#qT2Xuhxw9z56%+yY;sX`w;7URiCLuxxi~Ap!OYXGaD0NC*xH^f!#^ zT9+%Upt5Gl+>&aotj3v?9Apa()b;Wz(+q~T5ttPhR`HM~xrq>%EE#((-B_(cpn(no ztm%4r5Frnz3fZ(tZ3tX;7-ookm$EGq zD-IA9mLxJ$jr*DfVRc%Nw-cC!pY?z^HFj*5^1C{2sf97 zoQz0pt!FJdCfbjKm33kn_+|iBDVybBa+3NoAHWM9Q+85xidpy$q8<6pb|9@{doobA z&vN<9x&j_rXL|6ECiCQg6r6-lrDd8!2{esIU|;Egkw!owGxOvDETw!N9Iw6$6aSC_ z1N2i*IYry%wrZ5s#>nH2(|J%Xj5nkL-LaHD@AT8PP`F=J`5>Kk-kE1=I|~ct9r0$= zh!Hw;jm?ig`9#un#p>bgQKPgK5fPqrgZuZ_&pqP|Z8r>zR9?pp9jZe_qQUpJ#N$D@ zX91>FQBnLY@dotiqg{aV%HSr{lkTXa^nQ51YUN5#x-*e(Q(79+n0@>7F+l2-Y+5Dr z+yepwr0=+*Av$_K`1pZ3`@l&Pwi5Q|o_{VC<0lmO&sC-lmC%^i{`Z<4I8}Adx#x6U zFn@up-gqF0_r43Opfq;CIGG$j2{DGYAr~qx2v6T}RLt>%<6=5T1qNfQMXWPOVQOog z&hca7E0?a>UUbiMtH^}7kj~gr8XEH4qY}*{jijd`Rp_sHkfRqY*73F#&9pY!YhRnB{ax zB1ric#RyR8bK)Y`uS3H`2sdFMCqlR^_{H}H>&f?oAG*N;GYKp%cLnf&I~~8tZ;P4Pw0X1Qz&-iwJB0sa9H3>!#LmF+oAMT{Ey3Cd>5KKh4-PEJ1G_c)bASzy?txu`(e;q5;YPbaD{G4=2ec@qsq&+t7w;oYky_Zp^(jz!I4YaA6y2xZ4gFb zA5o8emCZ7lUgt(A?gBqo3*MpyA}xum1wZ3Z-e+WIXE!$3B_2gQxCBnLfsGS{B}e2t z1-}7qhR^#7%!k2-$xY{^aiBnW8K{|ppkZS*2C9G|0saAo=npr{fF&Ra4R&xoUm>We zMt7yqEtHIyA5LPi@nU`q>{E#Acy|}ZcOVL0?}Vt~JJVt1Yo)_Vfh!QK4BRh}j?YY| z%47cEx(zycVmS=t`sKHGI+X2I9;1m)dxLax92p4~z8mkp`!1dT_`zsOwLQ~$0*4=G zHEv7?2L;??%98~dhwhqHf5u>HUHoRFFv9~N3!T_++BRGkAs>dmwu)@Bvx6onW4dPGG&_pcND zZvD@~^wsG#GNwo?T068V!2^Oz4H7zm5bWCRc=_MQ#vMDbOJ`IXB4zprkgZZQ38x^o z3+8Iv@GL_O1l$!7=5L>HN#EqTOR_d)?i3jxBQj>AZNnVMZ89iMgM*A5?Y<0K7@rM} zP9|}7LRRGm6`dGp7X&iBHGeQWIduYe9b9KMH|juu>_5)^aTm<6%Rz(;%33)Xfl$IB zy*=gaIB=l>Kqkq^lNXA_K;$5`Z``o49M*Sb<0p&5e(w4#Jmdf`0Wor{BQ)8oZ&2! z?SX&HUc@w*r0fuh!1kre1q;DIa6fhbzW3jS;8I;^7uUm&JRAX^7|~@VWwof!j=$dW z*YKl{J~|Q{Aa`?^8xcU-1!5T+tW9^k^wLXvFfoYuh4tNEPy+^>ejWQ58Y0o)uJ#vQ z`kQS>0+gMbQ;8Ess^K5mi9s%tB)L++Ux~K1!_mD!21`39u$4aS5R4>NHI*3axCRph=oU!NxT(yA1 zlMeA6IChr`kuIIw~FnS|&<0*;r}o-N?DK z-?93T@`%SAGrkIHoU?DyS0-ie2&%ofk}$vg>Pv2lxF9l8es8tV zssvg=U9d}YojN=|aOBZl<0#JHG6EHs24Vf7-33!{d55JP#T{g~(KwhkE2|wQIqCcV zdR*-I2fZCMNW-Zj>fOn;k~o8avdRAt*nu2;DsYez0g{uGH4qXfoFj!zxM4z4Vz)#( z2U5}GPUPlNAL?-1=-(Qq&tX6e$K*FBQ=}k-jdzL#s4jN*J$HxWRE9)yqD;%ONboI$ z!z!Xu`*r!RMMQ`Li4q^-!6e^BnP^!VB0qHx``9Bz~O4} z{>F;hUU~iXJvgIrE&Wd8w{XJ`J^uL4mtK3V2n1NtL3_d+cgroAHnhpcv^04)dCHW^ zZ)eY5N70Uz&V2aECyQQreptN#K2|C)QKh5(F|lv#6x|6M@lKEU zjDUCt>Vwl~IL8OnHA$7F-F-oziBH5Wa?T9wC*ZdZ|1rr|U40dlTTC4|=*PVi*eIml z`>%Ul*yGvFO+v0@8Q(jwQ4sWutP1D9CiIH{N8G6jv_&_BB?K{n**3(hu$}^O7v|9t zdEf`I8z`z(R5`T1DUqG-pE#iS@yWlJL;u>>D?nD!~Feg zAnQ=XnUyB%wIQ>lWMf8gS!6_j-%)*IVxnNqQ466ozM-2a_cOHtJ)@(J8B)CC*VS4L zXFFt$FMkXqQk?ZcoMkrsV+>7vf^hJXurUx3xcmk&FrjH-zwyQ!lTuPrf*?+CLUpVZ z2r8#>uqGfL`qa0lZs$(%BmehEESFT^^76j;{EI4>X;Y6_!~!5d1kkwbvdg*>9_R;G zq-{>yZS%vDH6X}<2|ucDXtU?cE_(KvXDiolSl=%>IXSRkO95RO?j~mt5f$N=)IBL2 ztze)&72_w2j|L|hM9~ZM%S$M)B>aFG^glcR6NgF86-)a#63Y#1Hk83NVg(4i0Uc-V zY#Yee1r3nxab4qVPd)im90&fl-+Y_@;fEhqP|E~JE(3w900bRg^tzHbLq)KR2P?p& zJf4IN#xdpCys6}1X8W%UtB+0LhSGXn-Q=*1;(l6Cp^t zB5VNj;tSTB7l^6LBB+v%GVnCFcRxm>xI^ECiGUY>t8{tT#Ka}#@#JkHdIpFv;~;Qz zlH9rW``WdhcaYtZ^^|-h)`9!sbN)z zaUj}M>}5`DFFdRl*^@9et?1$yCN455fN0>D{w)*cr6sKD2hl` zKoF4t3L*p{q}NT^Y{~Y1%K!77_nounoISgHHp$}u-peFs-!}8iGwqpYo_U^U>T3(~ z4w_q5Nw>t8jxXJ2mGb z;(X_wcW%1oE7xfE)}6-P3{81fzPj=NmW+M~Ocz8+gha3vLps2c>6iIdl zLF#7XuD!aZI`o6@|Db2vwrz$pBz~AfDe<4)kjuNl%f5Kox`!WrSZr1d%e-1#9G0-$ zjo`4U`-FF&P%RD<_omIbJKd(t2wCW2F4Bf3Tybl4Wp&n!h8cPIp^jn@(y?*F#(pNP z0K`rN%Pt!n3`>{_EBwUiLC0BT)NZ)o8T`RFe9Nu3REqesypC#uK|7>E5#Wkkc8aIA>fQ0AS|sguh` zwbIF&P$#~qUJ!|xRa60KFd&Ji6RdLftC$FUh)B#PpNMT46Qs@(6keJf3*Z{TGbtU1 z6&O8dn@%vw>EB9+C`2ndV`Z929jdPF=B{x1X9jQY!Qlw1FpNa2r(P;TYzcs_(Nj)6 zCAX%kM&nePD)CKLi#tV9h#hutVOC8=UcQ(<`;PKDBEt7Rwqf%%x4otfNcEk_wVybs z`-AVDI|nkQ)xM!4A}1&@-mJ^PwtFwoPsB*OQs4maJNiqQ-E*$e@2Cg_~ z4So@43`=Tp7*r2O)(cl@OrSOULEHjxaszTVsi1~buySXNF7gh0+hJ8&9^vb_4dUE> z*kOldiTEq7#2pZq@Ev#DAvc}*+6a5_fd@s^Vu(5fJJ!(9;D@`6B0k7^_lfVW)j-jp zIQH0MYY->Y;8wL6`F1~QY`&E*uZ(=|3!f|Hxk3XMQAsailPt~wtQOacC%szb`TX8Xa$YJ8h=0Jl%3`3eBLO}?B^w;{Um)9$7)a_U}*Hl$+2($5d~I}?#d7*Bak z5XWAKSBMEEj6V!b9EBeDEV)1g{Db1aDVKU*^MLV6c=vUCNWoOVvI@$j;VO29`LG3Au*lm z@_%ArY)a=i{E>4$Qgr^u&Yy?Ft~KBM#y7j!{0(+?bjH-z;G(05IO-5<=KS=hKV7Bv zFDx!hBoT39d_Y592<2k9J!6Od$1-CzqY>ZqC<({I-eKQEOyzx8CLWx``#8fJ1k?_iOJ<-wv zbPIR)$EwTGKPPTSmlhjt1;)$G7o-F6O7|u-^I3#ha$0FP+Fnz*WmA!Eq2F)Iyko=qUH0KP*EH5oA&EI1C)GWXbWn(qRCyn~gQI42Phb z4I8P#5uzy6!?e`qK=g)rhap#Q1l)Gt^UHh0cA1%8aN#7Y5lrc1ZO>P$|#nTQG1jD+G%_a1|mq-FVYRG95~b-os4I_5unagtQGUo-y}2(ow?5a|*&6nB!`4_F^j-0JMg>o) z+yJ4s;OwjYc6~Dlv_r``!671xEK@)k!{hqFhfF%>!hfBU`{VmIcA=XXdSf#dJp}X; z**J1%H>FVax6wlu#ww*kX{Ix)YJp=Ue{c7R%X&AaYVeqGl!6Giq;f&J3>5 z$8tWxMne%!jLNh*)zR581Q82WR#)ce3_wi=5F!6JzW$9~HV~^IO4$&n2+OV>OTbG(;FT3z?zU&J| zqi~dd$&|S|e}C!kt=h~(Y!Z;%_miLeq!qbD;rOd~FS&OggmehbyGBGD7oNMAV9d&d zsxXEiDnD}Z@b%YUZzm4n-+ewl8>ERsI_2xg*d6i0qQ$~mP-vPiTRs1Z|?uW_kPd@k)5rH63edkV~;&{qtYupv*MY##LENE zUJgLegciH*y6cMZDP67&C`~%JL>;s;e3R&{KX27QLJi2Zsu&kfb0~Vl4L6i7J!EOo z_19gGb-WBL;yz~#9Y{!;cTCrm#>VR#9UEn44iNep=d)HQ7mkchIQ>ijtIo7)HaXV(`LdFUDk z{%BG8&p&O!3@l!^-tpj;{>tKD;D#@}t!6<(aXAE?s46w?MVTGhagD6s)+f%(Xn&X* z^MHw{LTDY9anWym=Uba^_{I$jk>Ae4kHuPy6s)Y*i|y7k1j~2tNrZq%p;K~k%Bka+d^pM1CS{I97UDoX8LjXB2ktlG2&IR>mEixP zQhDI&v2?bJK|=O&*D$K zKFX#u7A4LY;Mb36#^fVk(JC|LHGNg()dY&Szov7~J-3*8%SW~!x&8Lrg{SG$@|}(N zq*TjJjt**Kk{Lv#lZ}=~Efa%p)$6NzK5>bWfd^P^2(`DuTQv}`f%r<$SJ}9z%$*$Up#kk5cSCH>Ep}ls>*V5aijtzr=!#Fkpzg_9(?lezM+b$kP*xBUSml8 zeZPk{gFqX^|GuiV^N@w5)yUh;z!hJtg4a~$<^S8q4q5oI(--#TW(9-gB{?}vP?TAE zwfHiiVY1jL+S1n7^Rov#&C*!hv^)OY`VdIT*f;^f|I537*hg%3XT;K6J% z3`l!Hn}s4u#Oubd@)kr0F`eD#(i)$RU+TtJb0I9OnO1>m@aB7rcfl85e6eN0yaoA! zA+d$HO(CK5B5uHoN{;&K%2#{O`{;QywMi(8ESzzT8G<#4j%<0O$+53%eeq*lEJp0_Ua?7f%fB%v1I5LDBT1Qz4&$g?syh^ep zKW877!1?FX7GY%g5{^csJ%g-K{)*#m!uz+v|Ir#y*GwEQVg?v{I@qENMkEW_bUxo> zsJB+`Zr(kFs6)H_al+ts?UBke13^S%s6Vn{YiH-o+QI@GnX8Dj@4&gGE~dy94r(FNFl>HRmbw>ldBP-L{U?V;IzMoxQ!5Kvl0+-)}|&t2zF4m9oqDxb2^ylc0+h| z0PL_f5G`@m&F(}nj zlEe@X>X^BtS`;Tj09KCw=MS%MTe`5a3K454uJ+4E-Q%<^RKlTl@GIt7Gzt;|4MD|@ zO|U(kgTuf4{Z{$6@%KZQraDXwfp$eZs$^3yHN{xnb;hE%-?w`El@~3`FU-rrGAjZB zqxAfj%1b1|5{1}$R)vt(Jm=*GeSdkSsrg&CukJW_@%-RFR>f7t;&me;r09eggra2b zyt#Q0i^%4!oBOb&6JbV^*v!asOK5y;Di;Wj-HbCE4CphDXENp7_nZ61`|fMN$&oZT z_?bN72u^TA=aQbYQ4eE7Pd&>JJ+6*62)*P|%r~aw(onePo_pf&z3(Os#qvw0ZG$EP zl~t;66XA~rhq%}nKa0N(`t?8m-1EcF`<}NrSvrz-r9OV~(FZ^*u z>wE0c)cP#?002M$NklZd9@UXde}u571Lr$vVV3`oFYX+8?AdLNXTN9eY^nMp>M$nm zqCLo$W8$VogY+z_BH}DPX#srv*=^e&dv>enfWK!z-VXJ4>cZ3z=oEaLa4a%+Mrq*g zM;rTUD)Kje^z;RDiVF;pb_ubKPi+|PjzWjnYGtp?_wuUN)-x}AMmke|>e0qbx=IyI zA`6zyewOj|QVC~{BIUOV0aOA1+B!)m(-=S?Z>!VCh%*d*AzBH7cfASgP)#UzstJuJ*e6qp_M&fACAUtZah@ zh2H&+`ud#gAVw;3X*@z-JburpdvcyJdeSl9W6w4=UU|#P)`sbofh{{)rkpqne_OzG zW!dL<4B&W)ckLOD)mH`sH~#mUuBJVGYtKJ@QT>dXf+BPhA!deSHu-7LD|B`b4ZrY@ z-McUR+FvD8bxQMmh&n_zMuqr0Er;Z{LORUH9edm+WTDmQBG>=uzkam-YhU|XCubPW zVhLZ2pNmmIwAt3QOIeK_M2sd1f&jljK))k-_}&I46JsP`(|ZXCP;cW9BMzA_VqCcxAnqOadu;jJ1Ns|G{|)X(uJBcC@> z^!RhxTsB%iS6qHY5ocPizxLW|JC8o*=+HBNekO{#X*qjJIl$Y+STIIt>0pb;YsXzl zNxnbu$#1;abj?M5gQpw|$z?N8u4U-{1d$Z{*+Yt8sC~_Q2Ks;h%+?*!i!Q~A9N$U? zbRv_MNbAhU{q$!_2{aWPXGf!On2lJ-)>k-zyMMQ>kKej0v57xyab&k+IxMma?TaC1zQu?{(^7wh66W*-qTgLulMSz)q~&($JC(yq&Cn5yT5|13#}m7 z*z(~&c%K{(2_CCMAMOHJcaO$Wdg^ACqT0s{5 zyZHF_%AsdOcQH;PT93w64Jw}VS#hqF-xc!VFp$9rZ5J1Dq~X~s|gKmazNv#vqNe17#y_;SAt`4Un zJ8A9b6J39(sqqSZOTki0BY7dNE$q;>EQCPRo4k^!>fj9;t6$X~Sl zOG7jhhpB@CwER?L3~Q{2(j8}&AlPyE@}qwi@j`ltNnL#2%Z3Oo8_C!#1UB_V*2cW67fJt{9y8W%R8^ti= zS@kn&TtgRxzJplP!7mMQOypSoOefUX7KvScQwws&*0#Et*@2ppfYa0wiEZC1Mh_Ld zX|n>$4i1F6`eL!7N}rD-SDZ$;NthHb%aL)gzw2mf2sG1`iq8zA${I${KdQpKg6MrL zhS>C_)_5WH4oena^yPnyxD`}<3@!8xmyI19zcvC=15X=Mon4&~TxfQqNm2gbgAdNd zs;yLp6X$>I{DvbBKeG6s0}rYMmk#ufjgqy*32$}~-Ws?bk<&ns&awP5NB5NosVof* z#v`ABi_@f_&i;dVI_N4#Aa+sm@{3rgX9A}XREywM0EaHvu2qMGOb+HhBADDc=;ZC z>@gi?Ec0h4QzC8g^<=%KLmYqn@n|u)-UTsAin381roZY`_r0E6GALr&D3E|gS&^Wj;s%q@GX5I6vd+N;Wrq1Nmi%M-vW8^q2 zrI1#ez9Jcr`_0A}DU&)P%baNKwAwr^FYGc;1e(0$gTXodw9~iz_Ws}cjyUp&8VFL) z_rL%B#`nDEJvBH^s@<@0L&rzY{pe;O>UbxIMjHYCX53M5wIf7QTuKCvC5T$w9C_pU z;MpJCfG&2FPUh_Ga$ZEA2`K!bk9;Wavdb=;Syfq;$3QbjJ;8bPp}x2I(MKO0gopS`0!k^j-( zKiYWVg%>u{KF0SnuPum-t{yC(S5KNGW2kTD;nA={@>BLec6|JTkMEv6dv*|JBjZWT z_7{jz!Dm1F*|}P+i1|@|`X_yRjWN_R_i)1cHWfNQ_&hx-gljJUTefQ%~9i$vCDte_TZ-e@H(k)3D&!H?EZWZ5Ch z*1r78%k#f^!#5YJ9N?yvZOo+aH;It1^;-;a9$(f_S%$#Z9CjPOsNI9zU^vBYy zq<9FY1TXU$tjZ6wd(gK-G z9f-q%I7ctP;__n5&FAV6&fQJBk<>+_5Q7l)UH;qO{xKC&Yi^E`^BysXsk6Q=4t{$0*!-7y{&n8OotQ&4V~^mW3+y zXZp=#ai2^%71zRtSuwcbDRF>RTGO3(-D#G+Z#(>L{=dEWw=k|2*5fv}j zs(io5t!_L^!ICvB;~)+<{&62}M1!<~1V=dx+XqNvC!G=k9UcyArt{O#L-MmA%?dlO zC6a0?j(+WGdW>~%QCD9Ur>RpzF!RjEfWy`6B7&Bz8eIHz{LSo!Sq(*S+D4Ku4pJP) zGtWG;`-1Z?*ezXOj93g14us%pl}8KEcs@I>=fU%G1Nn$>G!7})qRU2nk2QSs?#oL&L}ZGvbR?|Yflf$CR! z>pTeB`q z-Q+Nt%wt86qm3_}3Ip+x4!ddN$<&SF+B&74*{hBi|J`t+%@EUUapiEcmZcIgm^An7 z)nUvMXSn@rPS=^sN+6F(GxFqXLHC;_Mv2CC3<9fbRu#Y-+QYTwk(z( zzg!+Gbi6-$!T!OW@ z#8qe$zCSvzyz)xH*TDgD_ZVR*-zNf1Sxj4r5N1OB4H}eOVgZ(|My!F^_&hlL9Jr=- zWVa>q#R5??JM@UMjM2>`(2tKqO)|nsep2L;md&P0an6Wkx=%gz)JDn~+nbG4^*?0u z;+!KQ&Ntt3^E?h($b~6rJ%0J|+rU+-A;HP6S`y1hf0kB`$}U49O(^Owvi7XUEo>D! z>tWm+n9j8~W#FWF<1G$?IEXKG>1?VUBM;pFK6Q?)q;V0)O{tnRcOYxX*sa;WV3X$A-&imSxmxm*(O4Xg?Coe}~K`bPF6 z84VbO8X6kd#LMAaJ$y#Y4EfPPL`F?1Cm{wswsqVwOMuMS!d2>sl4Hg)6Xc^X&}G6=a(@|z;_YfXmg18 zyqQ6AK_(4{lUgG9ux*DhOh>GNuWU2p?=>poG{m+3_{Tq%9Ilu9AmRZ(nqCadep5%gTyn5&s}u znFPr|B|gFZXzo>CzG@EjlLMzVgj(8=Z;mg<01!c~fot!83muZkfPtO~Xg7{UgMKOT z7_L+6JkHTLl0ug@=dUmPH5VEECYjwMo{{N$#_)wdS~F2N&7AA5ziv)FN2QT|nBO2v z@(R_-SHJpIO=w1?QY*d51`!#xA7jbSsv-tKj=?$4WJ9l74yx$u8*aYo<}R%esmqMP zd!hhMQo?tL&DkPk<#Qm!IxWY4@REbeBz8mm)+^!+;K@&rB+@ER6CiEt*Q!=x714*W z`n{dpxr&DP@^kYgwur4*v7!kvObs0MeEQs4h_fau8%eVxn4HW!nS!&zjo$m%+QwUcvD;W~A)KR;fHwY=@;Pf}ns)$R?@@ zQyt^~kq)e6znZ}4{4o({y!ut(wQja1FigF->KG|j7J<#1H;)f2<*UYt;5W=}@YhYN z^K&NS5c>;dh$Ct>>4@kc!)&_z^2=KxA|W{56bR`b)n?*~2vP8?M9h(^Nq`hu}odJ@4F#S+i#4iQ8ooG5ar)P0AvZ728HuHG8BD!BRVY zWsLFG<^yN!qh3W$j95d&nS8_eJ6X?uMz?%@vkI}((HPK@U$c=ekBb5Pl=tF*Yu8z4 zo;6b^=P+(e`9(k__Fx}JRNoxvpb5a@lngEXlQ?I!F_V1s=Xd|SfiV|hGjl5RkInF>gf}2Pm^{t#%%N?D0K+e)`WH95=U!Q;p_hkhY$_Flg{GN@MXPNjJtU z9Q>Phx5akuXpH^hTko8PU!YPLU+lVFYQhi{BBMs4dCv#5d;Og~g9A6-wRYR%&-Dxz z6t!{)k3oG@nxxG4;o;37(7v7_vmEmsvZ$(j=Cs0GPU~hy%?xYRIfqXB-f_tE;#+>P zNlxHR@ai;vuMP!w6kEQ0d2rU8S)tXdRtK>x($XV(%KJ_!VwpCbfim=!uYP4CiDKI9 zklN5cBM4Uo3;<|e)4=-;4G}cB=a@FCZoKKn3J#f_Eh31=ysa00{KDN3sG#CZM0`>a zQhW%%kHZY2{KU2RAA01WJ#Fo6!z}0Xa4A}`rOQ4UDxfXfX` zhRYR9$!;O0>MY`%>mklHcySAV@0Rav5OGfQUO1V$VM6!OSE7gvbKZXB+bcxqIHY0^ zE4&^}h=_rRQjv}3PBoMAcCDmDa3{mqsK0YCuW*+xejdbEJ9uH#UB~MD0Z*Jm4SG?y zXtJoAQ5U-A>TB9KSYth#)${)J^q=N0U9xl)V?W~UlbC!`>%h{BojW42;|?tg9<-pm zvJ98&gP2`pLW^hu(;^GE*QM+|ZP z?R~%9CgLoPMO?5rxXExp%3oX}oNbgH{ap0RbH8}$7u)an=^cIiw5uL_^sz@ZIaV^r zi*E7V(ycbhG{}F4#4~r@b=Lqtv6tdVBwx(IZ%U0+z0N!LJoBFN1;q7DCV2I2mcDrE z3wvT3KOAEKZp@teV&IwHIvL2xam5L$4IpHDzI@e}HT!F8Kk|!T{9+g%F?IOwF6O!2 z)=j2uz@CcTWAKSMQ_t0iBf?CC>-ibZ*?KQb#%SUv?Zp7g5a?NGxv;Y8IrbQH*n(;! zddVj)>ALpXYZtM9QO2rfmsScGSUDJ2O$ts=gr^H2k#}BSyWZggRy^U|lym`jY z4~#)9+K*weu8=8{CLTG>jiElo0v|N<-3VIB2=l27Q$wJW1rQd0Qxb`#RqG1&1BFbW zOUYj(&2+^)Be8Xtm|Su+aWBlUF}SSVXclzv&Ztm%q7Mg8S6z6k6W8Py_oB`)mi#L@ zr~UtwUzl%*9YzdN^fDQ+G&M_CI%S4yi)6f19?3#k0*7z@55yWD{NQYHrz|NqU;6n= zb-GHB4Gqly76;FssHmZ1vpU`2(!QB0%dLdne$))b(_ncgfUx(eN zzVFm+BF@AJh;WLqdfb{exF>{}7$LDQDlJ^62(ghla}B}m8Ooy7Tw=OR@6l)X(N}cp zPw`Pl9aT*|3`3YVAb0MjjzYBSUQ-EMkK%CEU$kNU&Ud{t>)930ipzDR>7u$3?h-u+ z=a^xZGR5AFXD3PENDiHY)OAG6#*JtY#ZV_ipJ{|cQ*q=doh*;W=Z(*ycH2~wjpEX-t8bo+_>A_2j z;pj><^=kryn{Hy$u$SF&zfNzFj5HP3)I3#J#{UC-`l+X$YFn^yK^f|Hb zMk>lGa^&Kbfz^*FMU>w^*gt6Y1k%+-DttYw9GWyB0y5+gA)ptKFM9~UkT}W^2gx!s zU0w^O>d=etm;4f0b2-cTYHbQ4e-7hxCyTv+0tny`hX-hYo53wYYh>3ZS7A6h2)^pZ z+f(p!VodvzLzYxZ=k|pcU&!V#hA^j@XCWIdplybJ_sH)Ie97#`>L*FLF!nWpQ+z`O zii(T;nkdm;=%Ssw79X@Y3sIgq&dv6Nr1Tj)NM26xBggK8Xm;Rhxr9@2=5q*fKW=*c z(xMS;)YLS|8%tERk@`(yP#iHzWA!Dp3McH z@i5~2r(KPIXx`dSZalr1T9T|BM#7X5XjT45R_X5C3hC(|4)563*NxwJ|MaSS+-1wX zpPlDMryB*ATr^PBY3L;4-BO2@@EBTt?D8^pr7O`1?qEkchI~*KRHHMPwS1O#v(XmN2ASuhVB9QpaKSJhX298x--8Y~!p&!$b=GY3 zP>WUX3@oWa^?l{)uWWqip@#+$fdtVkh)KS=H^Jl9RZkJ=vqR7{V6|`Hh?^I2n@kV^ z<+Stw8^zriaBRl7VUAP+4erzlDu{#M{?@lQ+O;54h~;gZDqU z>$>Z%(*}4*Mr-4RIOd`X9);3HQj)gLfx(ux{vPaJvXM6zKuI`sL(4cDb3DlV|J&qx z`XuwG!4e5&;yvYdiSzE({=S=k_Ufiz{b9Qr%y-#&3yaTv|AJZhxxrA_ZHQ61roc6I zr%tL(LN)_~aEC!Uo-{y|4;9a83+vVfQP2oIGGb)owyiogzIKz#^_>JzJ z39wkEnJ1R3?JVP8udb;Mh)a^sjQ{%Ke@O){wsFHoPi&u%aDrQJqKTdO?h_k7^{G#_ ziiqh{35+~IFJ_3Eh&CH#W^)Wb0u!_6DS5)h>W%aH&wajS#WO2q}P*aDmy(6ku*^rt_)x_NiA>NGXh^n2Js=xc|vb+ab=qbEaqExi0Ga?p6O#Jopss$9kldS|NLih4VkF_8fO9-8uviVCxXG-@cjEgn%l6BFN9vn#+!NuCz;SEb zEp=jyk$b_{E;t+FFbAs37)BNHuxR{ej6~$l!nH3|LJQk|OSlSG^%*vQCH5Jq4;yC$ z&PZJ*eoKUJyNBOQgSz?=7xLn0CYwrZjkM2t@xui|FiDA;p zP(k0t`J-d)#}z;u<0SWvJMO4aVU@3f+IP*`HT{S(w8GPY4(0%7Z3t@vnT_2+e(O!- ziymD=uxW-`r zVANNTD+{G?aLvY!zM~JF#`1*@V_Pr*Mk-u&1O|ZFrGM=4$C}tQ>A>7PY6+w|Om|Or z1b-0~EYEU8yaBi0DpaRaL!cuky!(Wr}mU-epw(nD~lYu{3+?7`%d=Z@S!al*LXG-=y zRuJs5+HkBidT()>C~aanExd8d%P10eD=`e}mW2xzE$CRgdTj)zCCQiw(StTRr3F-o zznJ;5=1gFsjQsgM?|qLCJB1ybp3-E9es-27XtRM_T3+fD7ZwL3ViArC^3gJ_cACR^ zor4@Q(Tk;HKCk0yk|xr4e_Sve^5JmS;K0D&R&|Ew&ww~L4#pPF%=NF?+8^DqyQlYn zIVG~4_@{&^CD3D)2>R@ZJC=LqxigEi9{)>oe`RSlI?INhha2h&a3c0XkjXoY}?d zq8K8CITru+N1z61`+o560-{`T7DI@#_bdK^Kp*%^4__8-C9D*Zcggm#9Kh~nBeol2 zmxEYJ`0snWTAUCIpoZ2-9Sw4tP_Ei{f56x9p)bZbhRTNzmLe^wyuBB-YaD+z<1IHG zV`IEdn|@!v{_AVxCRF;)nlxD1M$w_4hL+8Abj5qw>*$2z4nWk!LHpX<+GG4QnBs6% zJWfH1Ej?su&g?m}i@iM@b7-u_VTJ)(gpPk-F?dWWwZ{P5337d`FF#)u_RTaeR!@l&cwgcMl>XcF{F5su# z4?UOhlU1b(VA=5TU=qy)3tJC~@TCSOb3VJfq8&03(?tBof}i+)Ecoi=DucXKX=6yc zhnfr|D70zP!Lc~nI7E-*t$PKHL~%}nt2$R%1YeW1zS*=Ee(IGdCXUTZ&xt`WRQIZ9 z39_{tTggxGM-dF(S@_(Jy4SnZd<4J9iz`iuIxmi`D;|^J=s7hc=BaOq&%#mdDHD9b zpUF?}q-|q2=@R4H`@}0z4c>|GY&ir=nnMz6#3af{4bt(~{tWNs231z3oj2Wdlj={C zoO#bR%;xYesfgk!QFO_`mtH?&jwq^hxu5yWXJ$a`rFv=e);NzMgU-`9Mc=%UbjJ0t zIPI~55H=B<%5W%6)$}l^F#XR zlYBd+1e!{VS0s2Pl?2+!L5%^@DUp$h4qdjaZ%;>OVDlzzIxtNqjhl3k%sT-wc>Bt-0t>5xxR{LLt0SBj z2$*9bqT2lP`va|r&Uy#JvB0*?7XFwp?S~QAyveG{4$LkIMDf#<8;ynQ@j7U@LIXb# z6#RZpwDE7>#^!+A4oT@P(DYZwS5li5s3`<~Bw7%SMy3H@{VfRmXuuzAMuTp+yFcRW zYLxD@Y3H%vr+M%ADyC-zD)J3{G$ta|sKo^#Jy~%75r{%F-6_1MFXA+BkHb$yH4V(9 z&rVH!R-hy=5JqIpXphPKIS7*|_+jAh=0xb&ZuYx6cB%f|CQF3CeQF*F&yF*FMs}be z*9oJtubtcy;LEqL+Mov}p^5qltzE1A1aD6v1$g>L4FuI?(3w9!D}bmSg{Vj#@MONO z&2wG541B*YYwbGirsYWI<+cas@jWHh5$MuM;kx|1zOK;TZ zO4`_#I7^q9U2+{26`y2n9IlS^Hf7{8QSesoft^jw!CgDI2QEElesM)9j=kx48V2J9 z4K3lri1j`FLSye!FLey&29eRbo6@QhTP^DG`UNjPZ$WWsNp_Icrs?kEWg+-FF$_!U z*yGP_>3!}WJ%d=R23_Z@aoFl@0ip&uhb?gB`3nnJ0tN&>6Z{3AF%*07sf|6atm_}j za(n^I4TQJ-X>81T;VjKk+$ zkaw{KGlId3FIrH*nU@B>$iZ0kqr}2c`1kgQqrdpw>Yg=gnV{3a&t{Ruwn=0ub{y}& zcy56XKNkL(z?b*k?w;YuPw!jZyLOv7XfvQ0%Bvssyl@^g9 z`x@^V2cp`k3B|8ieRV+rOk;sSu-6NRt~+7~WZH_?hp7uwL!cRFLOEqt8KWf9=7_*0 zx`k9_i8$*?f5u4UMxMl9$(^+`tQi^+L{dsMsCQ~b6!T(PDAi+*8q%z-6CHHL(a>)6 zXnW`!<}{2%01(u)XztoM9Qo=c2bP?3>Vml%^l)F4%oHs#dD6WA2_M8iz9SBQP;gE_mPMkeUa5IC?SRfO@KV)%L+o_*^YJ*H) zWwEK#iVYkhG}LDKHt!k=f8~>hRlWbXh8dQrF|Ct?aq@#kn&9UE|G@d>EoWT%=Z*L} z@^$ycoCG^Mr?w*K+tD%{`SK@@s5$wl`Z`U_YH+&>NrpP|WZ`FXOx2=UWlbNtV#Su~ zijZ%6%dm$#)CWz9ijqKV*Pd|X>PwECe$3lyYvEESgzq+@`xnm1H@CiI=f|#jerru- zmah>lJll4PQBf9*?Pvx6i;t*3Vo6Pv2D9z8%k$w7hws|u! zoLDLK#mUprLl+ijUHZ{wvui4HbETM*&Z5=;OZX#tqW0|S84C9g#Mb`e(QQ3dB>`V^ z$B2KC@?ykrossB?M^=R{J#XpUijthHA?klJ@Y_2FhdTRKt$pB+J$>3QvUQVyO8gcA zY)`89%abJD^0JW|S08xLfjYX*h#^_g`cbVLz!*gbKEzM`k--&&-N3s4f%|71d+f2b z5;?y2l=nuybk&#o5os2X*2e~8Kf3Ij&}HuzL1)ay^H06e3>XhyV|l|8j$E^>4Z_Zl zA=7v4+k^W*&*O_;-uhNSK79{_~h$@{Uj(3n}w{* zQs5`nhax5h;26Ew%2IcO$R%EGKU6%qsO)hMjQ5qRjMSO@%w$?Wf-hsN3auImnw)U6 z1S6m)9YA54E;e^YVGw(OEKM%rGPM=%#?bf~-NxRx7;WWX&k?Mz%{MY$X-x4g&gC+9 zD#Q>c2J^5tkoB%w%)%cBwn@iige*A_s;|y9@KJ&=0LS{HW`+0~)ig1xhgTZ{$AGc!0 zFRTH*|NgwG1RAcyPsgM~#yFXK;zFoSR7K+U=+9G9G3q2fXRq66K+?uU->2{j06m8HHJ(` zjgtu9jlo}~Qm*{uCRXoNIuC>%O|Y;aY})*H-|25c#3cA0ToaK$NZS5j zkS0(%{7EkGCO3CVbK~2;`XXg%`;)n*2O$zRcq*Xm)i}dgf zFvzLabVi1uc;roafKLva_80P5Jemap-*XV;>#-!4H10<%hTZu-Cd} zMRsj!ucEvnpj9w#3)(r5qG#RObzPMem3a{84h)0(*`(~iMS?cEb!410IlLZ_9xYVs zP$rNHr&0eVl2`aq(cQ+=SCw1nXf>>mq9tqI?e9Nv>a@QBC&H`9=VaVoUv%x3j*g15 zoLsuSVTtV^N{pL$ujWT{&ez>L99y}j6%{A9u@py*x<3Neg%WwhYN~1i_)IA2>g@7i z(YJ+;B9$uf8Znkm-RM{Q@KaEU&k1pby^?!nlE1h^4QBlVV|QE&s7hdXE*e{_36K90 zOt)xCH*pT)bmQ;^%1a{XuE0WXlHt3EDBalb0c$EaF;3#W0dF99@P&m3PiqA4e#{(f zTqP6IifAHxDaM0u@wZ9RmqLKN8sJt>HcwM9TRlq5{RsA6!4u*u${4|vS#ZWe|oUN&6a!p8}$Roj|<kS<3anhKuKd!K z3pmzp4TQI!4L|E|nLQI`GvdfHmRz`XCm+tmw9nGE62aGVJY6bA)20WVCtlnc-ngx+ zL;j#y)kP>oCgtE%8OPt%JvjL4ns#GZDccQYr%FoAXMa6U4S_baXaq%nex zC=pxg;V4!~l8F1YDcIfHEgj4#r*1c%_AjS3bL5lMl>*+;RZ6oL!8LPNLiMvCg>*M0 zG!8NbH(pGvCYj9WHezyuO#4z5(ojo;Z-?O+IgSfoDw2XX9{e%jrhTm*t_-~^Dwshj zd7BrYpBDc#fX2hwL>GMKOzJ0yL4%$Q6W|PKDWb8a7w&7_r48d{B9sM$Q`O{N*F0#B zHpY2w5!1pqA(r7!C5yeFLf!>99<5Sl`Zd)xxta()m`M|&@-RkgT+2%eoSp5}u@8QA z^|lk274D>M%xX+=;z8Jqsx5G!AFgZc3%|BYd%AR^V4m`cC!30!DIw5W^Qo@9SuWb# zEcH=${5|$;YkKA5iA(3KTxl9Pil;Z|8f>^bz{n|0ZB7i&#Ly12Fhe^diuOi7M7j9O zU;gs+*H*sPn46R9NJ$><+K<28VTiMKE7WO{v_LYg-@d!2=PxUpn{mGzS-P;i^nkggIAhm@kO^oLXB2!d zrIF8W-PzOq{K}@5VdOB&4yYv zL>Yl#Pgit_La=X;9=|bEv33h&XJ`>CWA*&VYpdQ+iDUinzz;svfJ%M36QKNEt-kuLRo8Cd_=M64-ppdG@(y=Se-)6v;H=#G7R4@ixl{X7g|q>m#;N z(4(UB6W8S#(kGhmt#*i!C(9{J6lXNszWL2>&exGYFaG^SQ6 zyT5|a1T^ZrYOjh3~D@$cQJ?xFmO52X02tmKes~ zJ_{F>C8{8GfRUg=n4*rn^6uO(l5dIbj-;{AssPQ7(z1Z#mAOz1LYA&I7uxKT zBbR%BeeVGF{F^Vn=wfpMI28}t99u*={`HK1ohbss$-*rV^nkp_C6{R|=z6bm@S|{Q zzn53Hw2C+{ou8jIh#YJ6*8a$C_pEANc0gs7OindONT907IH;~n=O7z6&lVA9Ojbi8 zm#a4RMgIH2bu9;T%nw=tLCCg&4=y7WJUXZNH*>=u!53!F{@om>5jkj1o_6tluWjrL z-~0H+<^$%GmLpmTMBUA=N#d`W%5|Xi)C)W0HZQtlUVaGCqwkH)ec^|m-r9^4t#XMw z)GVXX9si9IFjS2i)nhBRX-O9od~yBYKm3R18e8Vn7nO+!LW3p`pA?7%98L_1-v8uA zvt(R6D^Du-zLo2GhyVQdoh>t`7Zy{8Y5mKLk3GmjgfzKt-qFP8d}A$Jna7LNN;Px0^Kie&(%cX!=+*LIH2T5!v)w=9N6;4NPx z!uW!ggCyV6Pe0v+$H6XM`|)C^G)zpccRaiTilG@VIN7<`j$EW-J#6BkJu)PEAuTKn zTjFEZ(i0b$K_LO|*v~ed(ALDG04*3oy)OP(AVOSBeTZ;N zvBKaGCyE)sO^hP^!P!)JRaq9g&XL%(DrNuzO=2o4G5%!k-DFVXjFE13~#g9io=TC~c+q`LWKPy;m z&O73itxBv2p*9*Z>6UmgEe3k8)i6w(`Hnb5S3lnIc5*;NJ9)V3HtCb6g*nknjWzIh zHf-E5{K5+_M8MgfYGW}GjETPQR{|}BHG_z4&@L>Q+jgG_kG=iwPi)A&1p*AYLyW!m zz3&ZS>!0<&{SORa@g&iMj#_eX6uuh{JNJYWPN?B3Ee9d6D=>V z>(P=-fQCPK%Di&SOLMgG16i1KH*$%;WQYL=nYP%6J+E!(GZTT}|H}!pN(=KtIHVH% zi6#_Mq!K4EqJ52s;LydDg5Unemi{>W_Z~f?qA)KjXgIjc;G0Ym|3Dv&h~vnm)y22| za$N_Uv+6;=@bV+373X7ZC=tpSV>A)e=zE}u0Asl3Kl-rR;yWMO(zSYvYXBkm?_5?> zoWsW6pmab-r=Iu?WrnoHa8nR?_dBK+Klt>{og20f3Y5k`t^JwBnxc938&anw|;83j`YV#;Lt?MrHEamF6`%^xAUs zZ+~rl+u-6kWqBWd-@NIiMcLWXbQuf2+qaTXPI`dR@o6mK%`We%FI_bs*)ztmF&|7( zFLK-*+yDo{XM}z4I{IBZ&OYnxCeZ{Lh^1~CCIKDiL48#mxaX!c$-&Y%$?PYWZjI5C z1)HB%sMH5yv%$fbqz6+Gri4JN;ypDq(-UQ`iAX?Y8dV0p6M@9Z(YU>KRKkQ8drO=J zLL9$b9!fK0SJSTEg$FFGy!?vGXU&^GZ-=~aF)K!oKIZ5$bfC-R9&yEr74jnI-#tLZ6^iJDNvbho1_)51rbh?#g*&Ek2b6&ND0 zfdPDCn++b|XGlZi@Dmya+*mz;t&qxRXhh{F}Jt_PXaZuloTLg}U%m37e7cc1R zUpS0OeNcWz5PgimPM^aBWig+DAB|ywSoryK4_Y`d7#YgR3WiYm$Hl7A;7AXdLMijH zf(Wg*KNY*^!i(xzr3P4)zJAEEL-H=T;2rkOoB#ko07*naRD#)T1oocu|IXQP^;fR0 z<#2=P*IaW=?{(K*7k4*07TodPTbh81tZ`L3UfeX_bg->2TSlT(tEF3NKHYQVm`*~s zMYh*8VD|mhlo04dw4|UeYdp@ZOJ1`iMuOl$B+Wso$*-sWNd#J|bP#9<-OO#zJ@;Jj z(8CTbz4X#c=c|$RQwL+h8NT_Zn>YOIuAlWK%AY5Tp(T%~r^PU$4&-t~r5U_%iW-0; z@b<3V1wm3uX=|Wwj+%>n_L`L=02ASl#0k8;%*l&!8xZ;uYRZP?A3*(l7#6 ziB0&H5G50g$IKM`vA$%JON3Lgq#5BsjMu+?kx5R;aa?g0>2@&uD>2k6-u+PHFA;+b;vWIx%l2^Kr{_W_P(#bcv&_xA-Y$kZE`cnEPZ6z)s zA&gfral@hkM0a$iAdF5oE7Ts2(i%GLw9~>HH*V|_JQX61)S^r&fwsh%13LX2(^HI0C?Ky{w5|FoomM)* zA?NkiU+>4qML&enK@OFQ`FrctS6@9`R9J+|Q*&&UbZT@O_U`}u z&;Ly8ENMIhH3M7z!nU;A?@*bd^P4?=ckJ5FUY8ho90R@p%j7p6YznVmd)f|gZmIBX z3d7Iahf!A-zWK{H3tYGE{h07=RN|S`T0V~xOq`S`=8*-3C2UHb62;(Qv9sV4o)ul> zG2xYsxSwJh`MLu9vL*62HgqlZl)~&%)P0vG<9^XY80s zl4*we0dxX%5*SNDcPnuuwS{f2-fIC*$RHj?@Ky5?`J}=(k-%RdNIOObaZvFa5orZh z7z#=k711UbRXIH)mzK4lIsIF4{~1BV8KzD9QCamf>jM!vz_ING*6i{4-dOWSc*UPr zgeBv)8<|su>y#2`oyg1V7&-gwvx_+VbFKo4j>j)xl<&41BGfiyZ1Kz;UzNDN1*`VQx|7P<@3~{t34JR6=8}TE+JpdMe z9u0h)omkNBGx%D4a_Re6_)Z%9El3MMR|_BUqTu01)V0El#~FcdNTY!-mOL$dQ|^(% zC%~7eNHD3aZ==Jiw1WYW;kP>e^r1sH+_V9J6^4qj6BhbR892vxjn z5j|~mo5*kSAA2|eC)VfO@U0sbA{P&e7MVr{7nMn?X~eO89L~H}TsE2|QY)S^OsAAU zd&i&qvAgfb$LlVs)JV6OZfP1oO%Fl#uX=rz%Qn;QZ#HpO&8p(n2-+pqS!y&wKq@<$ z^`(%GzW_6HVr@9dhA3ot8$gs1lA4f69qA|Tdm@gx*-U1wQv1w{Vef;8n$E!x(wNg` zQ(mrC|1A!#v2|h**lua%LvV7&`1x^s+63o?Rt;~`mzTAA7zBeNt@dH1L z_qf;72u=xllRBsw?+#wl7?h&QL0@fkvDy4%x)Nu`FX}5S3gH5?1w!hN=I3U^_Jv32 z$pm>=_>r(n5sOO8eZ&5+X(Q8?U{shFaC)}4va#kE_8#<6;o80pC#F|>07C7 znOZ-p8+B#;Sz~c%@OS(&MDqe;$8-`l+kK#pijq+PFq&QRWQRp=2V80Z<}F|C0b|rF zf{dOrKA2-ZM4@toWKIgw_>=y$;l61x9m!%6o_WKnZfgkqm+TCX1$FEeg?ww!#{$;EY zhA_hL<21)2Z$ORwv1Re#OJpLk?!$jtZ&;U&Tg`?|9JZoKHC_Pj`Q0nK2L={IFzC>1 zF@k>rOj8aMn*=O)ARJO@i~i;hZwS7#aa*f^DTe*|I$ivIzxw^FySjVl48iQO0Xb47 z#7!Fn0GcTGv(aBY@(&rbIGY=jHk@K8Cn=iq=!)K5Ygb+eJ8mrtg8I} z?Yp}BzW>Wr#;MQd?Me0T>+tISmyd23IP`$LE%RoS6i7>(Tm@+)Bt8iv1*TVgyZAS5 z@94e#{?|nF!u&Q6otZL@XJTrDtMHj>k!)fUBqA{0y)^H&rqmAjFZq@6 z6RW4fBn8co8q=t#nV;0}^v(v27HLXI)WPg(U;mH0&YCsL*}Qpk_-kMLS_ubV&U@jn zFGSdlUQI#NfmJW@HTWb8XX{k#Y(2j%`~+(@KXr670KIoyCLIJ{olR~Ur}5juPoaUI z+^rf;hU>oIFZlWVs`+i^C#GNqKTX)yUfx~*@?w%f_$zG@ze;`^`N_v}9lx#oEZ+MH zUwYr_=Yp@Y*t)WC?UhfH3U(~%%s?F(C88kQ^?o})S!${bs>8hr7JdVXWdI_=sC(h7 z0VnujetQ!%kOe=yaN)vPkN@HEO1Q~^d2{Ej(K~*&Z*jX{g7OpIBGOWA+b=-V0YS{d zie*SAil?o2iD5*`Ccr^yRR;L|py$ym-kjqE> z{s$Hc4w`>iN${0{u-J=`1V0d11PC@4BPgN;=5cSzwzv3uD4BU4oMG$&i{oVp1Wa8i zzkPk9s3f58`A!ojK=F){o!DeN`wq_s_kd^swZ#k6U)`jIM( zdrdg|4qw2KlWEln{#pNc?H}`%wWOHtCo)OACr8?7+$JHuw^VbZNzABK0qS^N?>psv z+aZjxsU*_c_>+AEiURCkB+tFnn^bQnBFh1@;a;M_5YM;~=U9D<*`0 zv3-S);$t)iKiE}lfC#>pc6Ho0k@w(!fgg?Lu}Z1{|3=E9o$+aKT)UXibgrvhl8heF znb!}}(`W&8Ukdzf+-E1&)xN@~jyYgHTm|dbT~i$}A_BX}PpqO$>V`P-R@vR%9j&ga4&cat z9(^Y!?io*_-fHpVK?Zx3vYHI)o>SzvN@$JX7%(d@Bp( zHlvW3x4jn($+azfTNc6ByHxynHK`yuyyV*AZndYNXSK1dD{kY#;uL?8a+CPo-V1;I zRM)BS_1?zgHtAl^nS?N>49VHPiMx5r=E27wf86%VMA-VC`kV-VtZ&iMlG5N6S6-p9 zB~jl*a1vqukH3G5KuFB;pjMH>*9%b5`H z)lLujtBM0oKmN)2Ss|SWr&QA<_mqC90Svb&AGcDw(sLYs4wA+^w46AkHMVVA5`1TR zeU?*E=y&>HKn4Wg)c?5no@Ug9IY>UL& zo0H+sos;FyBk$gUDDdMO6RLl$kWBqc$W7Y{o~mc0ZFzylno|gVaue{z7GN8{(jrzw zFA6z}r%8>|$6>aT*v45*!PlOJ=`X;v@Rh-6_^9_ue|+_3;LD22%oBcJuq5bTR2!0E zlCNg~Y(4mLRJLZ#npi_agWH>UUszCR;HvMVl|?;D=8TY)9N()TNB zLjLJxI`t>!>-GA+azRzk!D*Sp3E)~Kx9vD#9f)7T#8e*N!#XJvN7v?96O#le10`2IgN4(-}uxF`Sg za-V-kn*nFiD!q9cxq6T0z4T8STBO}(ht2_MgGrNYiy6^)k>n=|X&88P1f-R5xl<+M4 z*KLc#51zifCTChzu~8k|va>7v`)7BFqc?e{z_)M{ul7EkA9d>`sqjnle9i!e*l!7&{^1<4xFGAm`4yr3+>qc$o_}S>&}*yR z!yl-dz#gm?hQNmdISl?-0Gg}*Fd3M9M4Y|8?~umV*b(oW{u7TV%bGo-IOLuz)EmC{ ziN>MUrqO+0{xAr*pY7A8BP82ak6!=Z2yYSSG1^(GHYm|s7LGk+*J=0|(bK+G8ig5E zSm5V&m7&0{ zHb#u68$4duoKY3>ZEGHm%$k-Ry!`wnm5b+hHOR*@*Q=BTe82C%(6@)(Z;R7ph%wNJ0OZd@2O@%mu5B~kHuWM`n z`j1{|+u1rCo)A88#aYR{b9H&px1(h^@{WT_vMxO9fQkhT#U+IWSsbon@Q>kZB6`II zL;bI=ZQb+v@BF=OS9>fnqXzt&#=+l%pM^b7c~QW(qb(dc;fTuYb3QP?VjkWE3k#64 zt9~FfgZNUuqHCc4l~pZ!zIfxydmzqH;QKRyFRr*CKj7O5{8Nvv$vOKyb1UY~D8@Bv zNT*$KT8In3t)sv1rB%&)uDE&S9*A?4`ths&Rlll-)L`G&mIodBfnr22J8w}jZdWUC zIhrpgMqrPj5=Tf4hKCw=_jEu0?Dp0l-n+p#^J4CCS~{iHIzIgA6(MIwt5!q4*q1L{ zT#6H{it6%QY=`i(!tQ{aZT0jYJlxpS)AjJvTU+mZa7!;B{iUpyur6}Z=0$3V_x+kI z-?k>mIbG?yUp%yuLj}q!igR+ag+1`4Z+_`{!-E{()$!jCt#AFqUz-OhbD*_74Bz9z z7c7Xga!FHDsX71edVY&Qr?jV*WU_*iZ`!Ya{p%%#MTNo7efD#E5CIr#C^lJAQjGlw zcL{M0ia3YQKdmAE#*mf`T#7cDM5{e;;waGRNJ;KPWK zh2UfU@Aos|6mqU#;USAED}H+4>aF;5?uCd3Jt8VJl7istM6}{O#|MFnT>q(q%W&yB zqr4>Bc&;<%(}E9?;9zNgNl{T~Ha?XPhaMI=w;v6~sgz34T{qR9E8>SZ&YJ4U2{TzP)r&4*Gt(bS< zyz(4y%%vr~u zaJ)95VyF;}imw-}^3(NE%z*=Np5gFkJ~Y4Z3+FAF4}r|rnR@!k^`}eZ46%!8Dcpx| zoCRCw>Op`E zeC46M^iJQZ%ky$BIqQJ=U%B|e5)nqh7z=)Vb;!4)H5~rxB?p#WbmpRYN-G?NtKeHg zod|zgbza`5KXl-N%g$X`tchbrwF{p-RHsQ{8r+-8`0dXvtz>eUS5};z9f!~CmI&Y0 z8b0@2pFEr6a&;mkQ&EOOgdj;J~F#5uF%wp8#r1x9u6;t!#QAc@P3 z$qU_rhLWP|Kl8Tvr!SwLEBKmVMJ!W;xPB&F@4%Yw;neWcrg*@LXHRZz{hjZjrKce|LFV~xq;iie%!oeiz_PV$FV-} zOoUGx7`&CQCdw0!s;j&A#-nElKBn*nW*l%rA>+R~}Z?*5iw?Uz1wxHivXs+He1>u5S_O|F6CC0I;j5_y0Nf-tE2jmQE_2 z(2I1XiJ*uDM0n39h$udv4Tb+x(1)UcSP-SDD5!|=5R?*XLQMkc$?hhb?S1d=-FD0W z`tvU{y8VAT~tj5w_0q}-N{!ty@ zW%$I#DA=VZJAFS@fwA9OHyS>jnFFUU$y+Im|sl;)S5?OI>z}hMSb=L94DHokNrzSPU@8di?aByHcIu`gQ zjpq5_P$a5-ChQANn^|+gspY9)psB?t0HUN_Sq-hDk&Dl)O#6_+avmPvLL&}zXm{uz z#}6ru>fZZ4cJ`c_(~m4n-X@G9vwLJ*0(7gcwME*lIDcmP*(cRh>C8{<9}%5^KNbDp z!^=;dKd32Va@FFlmPg-8eBDj27Kf8&aUIVUeIub?4hTh7V&4v(}ag?Pr$ zAjfSL<)$X-kk@KK`PINiv)Fqh&XF2=7jm(?zkOWAoSN*c0dtI&MiX5ekM}OVDLX2v zF&#%1<8WOaLR_NnBib@lsWMn&f0EQ@1~r(-gCBhPsLB}?nd#uelF9g9>ESsIvG$0L z9lofj@b<49R@ki3)-ljYH|ts=(eeUc;NLD1M#HYQw ztG@V&xmoKsn-ho3&V7^MC#7i8+y6yBCzg!=MG4!Jq);f(oOPa9RHMeDnzI|x(sS(= z$u4FwYx(l!46a31uU;L-E=?KpY;44%FgqzQL$S|Yyr{S^HzjEZ;igHiCcM7T=_%}Q zVSFOe$p|}D5bZ59DnX)dpYNhGXO}9x-PC?jHYXz~aOt`8z_$j6be5p8hVx6pLEZi#=PW?$6KBsU%}!7B8{x*z zH^#+c(CpDqT;uq*Pn9^DpPiieFBi^7NYGm_n9jFmL|?+q*gfqJpE;{c`!Z|8`IzYU z@GXN6{n|cQJ7y!Ylo4{I5nj^ezWQT}i}Wa(n#{xjF-n2BYPN&D-OQq}d}`>**ceK) z6SN!9IKE5;qCdf;0nL-fK;Iku0cnf$1it>6gAIOqs)G+UE<4R<)i;mC^f?>zm&rs$ zei-3t2oN0(zC*v@9ehO~N#qMjh*p(mr2q6AN6;mUWTeGquD&fVNYo%=B=V(84#-+0 zvxXWa5e9iixaqhxt<87ymSei0TaFnMMjMx1SEt4l6@TRPid6N0qSBUm?*^0hoTJ8e zG#2^Rzb?w2KO-kk_>z)_HwvRhU>EpEakTei4=pJ@=cEdzA8J{pM*`6pXNP-2QJu_E zSYDi#iuO&uK>&P)-wyo=npI=cZZa1>v3E8bRq2SfQtjRa;W}n*2Ye@%{{w&B3inT! zQp)*czu$<&bfHn_=x49|Z0a-5J~Pw!XP%j%fkKuf+rR$JudAMV`l*>Oy!gVbU)=SJ zLJ4FQIG5&}s!N_T86T|P{^8-5R<*Uh z_-1Qsckl3UJU+C5uXF6OE;+k8Ro(Px&bSt8wDV4x1}^{LjP%Nq^sFI`@o2cqtKd4g z)o*w94h;*t<>l3Ft-bvtBk}lzMZnLj%F3ZD53M<7_Lak>!fcJr$;5ok$LFS(7p7$n z4s*Ebm;h0Q^x17)gG2D9G7{nF^wq1iVbha5U1W z2E8&%3)0et*l=F>?t6pZ(lHoX_Ih*6t8cfrOCX0G`W<`{DyxCDa8_=vPDW2uFF;!Q zxR4e;K_cJy%#v(1z9~j?)+6wFL4(rV78+RgT66Q8YdhMNz6gz&*9Z^}^UZS9R{;w%%Sn;;j+R2x*O} z>Xe%V{|An*Vwy!%Tdsp`G7#Y#95C9m@90BH@@ZQUx+a7xJTYIrwW+HM{JO?qpW=iZ zgQ2+0sV*852%LLT1w<{V!_$U%!-^r(Y#5*N+R%R`YcPk1VP_yE6O6W^bEt*N9NQ*yTKYFHFK3UHNaFq*DTB}P9wPs#-2O}Yo+s0kTYbirhJzYm3Wcr= zcX{0@p6%0yg&7+2*5gAxCw@;&53lIc15gEVE&4 zLz!hywcViVih`(+F3Cw_@K2RpX>znE3TQ{q(9pMk_WI_BpJ`^{fHl7+wdIa)95<6e z6uNl|s>-GVPNf}bP)wWXXxBE?Zo=Y>LMeQmt(WF#pZdndN3(6|2!+0W+pC+OTG7s8 z3hU?tb6URpg{8ANDhXjiCD!14OoL0l!xj~$bAYN_2??%BW-hVA78a&!D^m$WO%+L$d`m_crWw-4PH{_cm|s?K$O&ztxI#dPdf# z&YjWzxr-Oh%GAsbgquh)Jrw;;I^(#i)YY5UYVQX}@-WX?bD7Bt`v9H8%b7Bq{sR5T z7)(KLZ|?5=z-OPTR~SRkXFoE#Q@x2<>JbDqc#EcOwqKRaHRXa+Yf^6e?WU;C9A$pI zm8*uJwI>o=su?ZC`6+3bPTcg2rTZ_>Y~6b857-6Jd3E>yJF4{9LrTin-PI7L7YyJ^ zOIO*k{EhA57<1$`|J_nUW48-md6uaBN@KvzNf{crPp7p+V}JPDmfEl1wt8&*?>FB) zwqmI?as#}fvcp~UghO&tndu{q7~W8PO|P+UU}WS+_pRRi zt3TI!>!_Qb{MpGfbhcu4eA!PDqZiE1hW<{{vX30>0gY?Ci~*j!ate^c*L^Buh+uEr zKLZgk%goQ!l?0Y*Vt4)GuDb7i_j?;}zWL_O-@WO(bp(#zYEW{;EuOp?bFtEVofap1 zf!-TxUBPWV^Gaj0g!6#3vxEgTsR=s0dgP(MZE4g&$8@nBRZO2y=nHa^NxK~!)IPq_ zgowzKFh zCMYCVo`wV(!S|fr+Jj1qoGsgA{5zu^O7o6A`1qDagfp}g$M2rpKJeV@O)Vte^(F=m z*)1(_@QDw{$UnT2v-7f2l6mZAj_F#0{!O&><$G?87N#8`_|GcV{gdab! zsppL~?QNzk049v>!3W}kM}+GV{aUrfFp3!1Z% z?aAknsRE4^D!rF8Kee)rEz2E;*g`llLcXo3A1uErv!(7kf&H}&eVXqdktP_>;t$mt zp318dnX(xgifJ{LS}Xy&8ig%oZLHjak8o#RX+ulU;P(y4unUKT-_YDYtWDn|s^osO zIIkK=<1=YuhzMG#BBMsH#MUi|Ws(9Z+R$G=L+Y+?Z4OeX1MNK{I``02N&ohi{$a%( zQ<`DM7`_C)BN1F2(acIoXtLe7xgWzH7>tCsXkmvQ`5W7Yv>CqnT=)Y+*jDu!WE%3h z3pn%}GXO7Xuq2>~z?Q)BdFh0Hk|X&lCb_D9N{`E)+YUI>ooHelRRE)3EHlW(ubhSRZM85Ia7& z@Wr{Bi|{oGoa{A85uo$fYU?yR;`{X8URysHol%}>K7Vq(%U&&O+K>4Fwy(Paweyx0qytgbJnKDEE5Z5#Qpd~*>N&JV&$?*avO5S5f zR?tGG%0DjuY57a!e=Pr$JdE5Z|F--x`Mc!*RsNImzm=!vQXpM%qPx9x)JTLhOIPR5 zpC6F0_Lr8G2DFrcO>2CM7cC}({7aTB3F!Fv9S)0BA@|C+LxEe%WKN(zZX6|)x<(gx zZcR364y!`PvNFsxwD96Nc{)$iuhXBYjV_!n*e?NKnJlJkikd4j%mNGE;i$xjT?G2v zYOM_uKEg0L$<)m7ycyX#7zN=BMGiiHhh&rBbA>gn42Og=x0h!K^l?&*tum&QUi@09 z!cKi*O#$=5hG$o2r83|{8c8bvIQ0q){jPk#91u%$v^l0+jcF*PnY3%bFJbZAJjzA5 zAV+ouhnL~mRl=7>20Upc0wU6sHW%Na8I4f0BFt-P;~LOaIED4_(JGfNDNfR}aB+T; z?7fB|5$I>I&mrGQ01*wVMb+nH2{INO_q7_-arzYz?=sU8l1@3YBvDJ=!wBb|J~J2^ znOT{YimV@}-%&=z1A}jefccxLdKi_fiaH3csT;T)M=nG(?S&lIO@ znxG~FH253c)NjdjF~%O}rT%KRiiyf(gyJLJ^bW)a@FOZ0n)2zC{lgX&C6O;~56{Ig z{De1Z^xa2$e&KuSE>sM#B|yq1=H$98LrLl)@anBypva3aJ^8Iqs0slFxl~PWI-8 z;mGFg!{G~0El)f5eKqB#0vq|G@~@IjU25&naV{#P+9yKxL5EUL8)}j^LZviAEL2Q4 z-jk0kFa7ifYqB;sjzm!SMWXm2x z;1O7_%-MeQLf?OUb=k%5uS^Gjx&zee7M~gd2-kG?5*S3!gN~?t5PPUq9XcmLEnnG7fAntxcNnM*)D7dI_5lz=zE*D1zTi z?*#wUrG+V8LF5=m89dkTnA&~kY%u-U1BY;?p(nxLmj9IeGI^6GU3Vs9 zh<~g6_vJ5YW3e~J8U z@=N3q_U}492x$!(n$vnech%?W)6>#zoud}Ttf6Umieg8nBIuNU_mxwjEZ;M)bq;9H zjghR3q(llUg_}yODRc?{df|dOXPr>hr=QVM&17IO(F>z8sevS)<{gKln&}Y~?1Z_X zbQR@%&%V;wf7&q>;k1;1P9QgfTN=TS#IjYHuKDX7d*P9uvF(-@ziVGX1&$3^9vpIOeVWm-39-q`9Lq9ZXwO`7AeEOidT3pgc z<=0FM4fX~6oMLV8)lz5~n5_Y!@G~nK!B6ZDjhAm7noKnIiq)-sTKOgo%;<`ibrUBE2 zOO!+Ft&N?12Op4MM84{$p`9rldFez*z1SSKW#kqdpTbl<)8(IhY3vyD>_KoR@5H!NaA68oS!o6o?^~frw zyhzn5!W1)r=d`6pR6>zVMcOsPij?ICtnC^ogvidmXsjUH?|b(3&XMN!P=8)_PL2i! zMU@eZCJm$|~chR>cl z3L7?M%%)$KUnY<9WXyPBbe>QCi;TgolfP8{7Wwzd_sG9%86%9{c6*-m-G-hrAdI0^ z>z4nVJi?iQ01=KKpDK z(+7fkXHJ#IEw*k5WT48`-(Tt(UcIralfjblgfR^&5=)f8k*Onl!OWao1gtmv0R+w1 z)vN)(CA)ObFCVTO&_WM?bC)BPdEc(t5L#T~drZrP*VlG;Y39ZlJ^~UUs_*?WYvdd- zGh0;diV#4!){bOtw{P?UwG2CthwJF3An}dbGoygRV^L4zmQ?|Feg- z4AgB8_DHxhsO7y^PazUZlPwn z?>XUv<@d%L%(eW0JgJNDdg-+R;0618+WZ&rm4<&<>tgtNk^@pVG3c&oKtci{@{ z%i#`e(vWDHo)h4&&o#6&0r^!M5ww_wPy&bI?;Yp*dM4duk|_9}qi9Y;nXM4`zO&iqE!d9p*dyL1#FJTit}0$p_Encx%J-933yes^K z++_dPZhfUyLL!u=>1wK2&}K9_1QHYYH8f?GO&iTqFA0Oj+SxrkdgnuHoAk)&XGT1^ zk#TSA(c=j7am*mY9rQy7(^r;On_blZP)8zOS(@G8W+Xn;MZ;M>-)@qu0VkLJA20KB%!qB zre=2-{OE&!t=%q+D9fM)Y2pWq21~=5W{EdKbqrquhy^lg9DBZa^Ba`iK)3eIAOsG4 zv|X*V^#Ams&B0gRYHu+Oq@F_@?+MJ(eXV*l%kIr*damfrVi_8MXI5-){OikYLt3uy zqd|{%tzGH`W%~W!zjuA#o9jATRURDX>3gvF!_-IcJ>e-xgRi#2Xv=?nVO!%1Z?s~g z^{IW(WrB+pmZtfy{LZWGwGF{O@=M63?2|(Hq28h4kJl^WYw`!hrC<4Vzw(U~>#;4} ze}@Pr#5VqeaCpq8Kb2o5k4%68CKq(w6X(eo3c%OpsgI1mOk}7Y>@W9T3TP6QDgSr* zN9D=$@sh6}d*NUpHT_Nb2jnrG>~3Z%=&l{xg>usGJ2|6(>=-CEr@*Xe3*U0jo3*W- zp<$i8Eq)t2G8#pQ^0dKZcJK(9|*Ex2Qq-ue;u;W!JotTn%`| zY3D9J`%J_t3v55Tul@e7o9c$Ox>1dSW_7suBvROTQsDB;CXX~DC3M42U#ZuNC|i%Z zvqA`{kmjNt+D0vHG3vkVw;O|h{CjP^dM%a)P{jeqQ3?(3C*W&Vg=SCGHTL!Y#}8iG z3Q|#)1im>W#KHCOyUj!v%m0b5zR>i>+V&3hSTrlhXYA;P;llOsi4pp>(UE4x_^ju( zKt{X%wQHMF|Mpg@h;c6Ej5BCix-@4w--XvM+pa|^-LjqA2w%eo;ZZvcz5+S;8i1A= z2<={)_x7*ex~j9P%vqv1RgKF_Gxa-m!yPN?QBasQf}Za3c?_TQf{#nlq)r;12b5pG ze7L@U-b~Yqvst!Dz;65@AU$d1!7tqKJR3{9`)p4xFc2ZH2E+QfJf;(J_1$3V^WAeq z{9ZT`LtNMi?r|eTu)bRX?LwK$Z}j&A@^nK?%Wj_jDV z{$sN$W>#d-WjEbaPw_xVsB)NR+gd{X_dHVDaOZ;^{e0UUibl)IW70Y_N7_uhvdt;z ztZ+mVT`p$A>DO zG03*2HrVsS`!;QR{Q1ZT{OKBS@x>o_f(g{)75MXK`vTYhw6VKqAh7YG)2k~>3R1NF z(A4;JrB`q2?fUke8ya4GBQQE2{)3<9@E?4NlgleZ)4UvC;H$T8?d%H$!sorOyt0IO z-wGv7e~kao&!?J$ExUMc$8~qC-@bBvdU*cqJn}bEmOh4WXjc?ENXuuJC2C*ozNmH1 z=ic6W_kS)JK73I@Nrv`-rrdy!gCNpF9(M<2^M9qe@#-7bw^vk@`7tG=OT1`XF0brR zj`#$8t2o8y+t@f7IpZ^H>h8a3-q4{7@{6_4sPboO{LY?{(Z4Nk+Ww`R*LTdQuJ9)% zYig0zKDMG3ddOq&t%MBgfZ65#r(YW$x%QTIo4)$#xfR+*R_44N%Rcl|R#{;6z~fsR zZn?Ly?|@n539$t9ttLB3Q((b<2M0r(xGn2`-6LC&Ir~D!crC=k!uzoNYHV!dlfJRj>`EJlNzxU}Jm*Vw^_atEmfY7$D~|(zyF8=lUO4c5-~4n!_F-CCS&*ZS zYl3!_64b~@INa9NA6mZh&F=5qZ3a?2e9}$cQ`3s&x5#6bs*>L(AK#D~{Qvw+M$Wuw{!*vUVLq3*Ui5+gTeZAj4tS>XI3D;S)MLvg?zm{aeMR=E^yP8 zIXO!Xn3a>KS%(3MFs!aaT6)~v(HB~_d{yVI4_XXNK{p=9cQpExbMQ$^seHY>;km9j z!X?~%O<~R=EsM*^6u!^@WB;HrKcH-Sz9*&J}eg&rH7SdmMCC%VW=N zaqpoUjWAK3yuwE>INnM-=ahMQRb_eUsVNMFy7>Kr!yD^c`)<9pzH?o_sp}K)7c5*b z-mDbOn0=-0pY^$mC4c_%!Cc5q26@x`wCkd=AD(#5$Yg;|t+y=QK8IHJ9>hgPrO z((~opy0B@JXYu&a%JRyDXPG^;A2>8_IxjU}CwW6IS<@=O|lkHoz% z9O;3!t6blsYdoF$Il+;3FOM(P{VI9FL+5V0_yVxoAMIs8h+84=5x%b&2RU9wysZ24 zh}38>0gcZHR>qEDHp*e*`uIO9N<;HO*5GE`=rguTIZ9_szYP-hYe+zWBj`{ z(f)_l#s(H?3!l6UpUGdD0K#uKriKS2r^L=U!RXHET>K=Mro%pc zn*U7&RUj?m(jP|ZhegxfE2F^&*Tni4lq4kNraK$xYi{p6KsU(PB!xS+(Jpd+-@fSEzj@T#WNaKJu2 z_JI%hWT=>cFBug{&{=gp@m+gKN5^=jw3#ESJbWGZ6}$DNXm8=0cHaTQ&rI{_D6v?q zttT2;DgLJhO02Wa@@eUf!ylLfe}tK!6{UXgbxjoi{p5w-kvC)X2Zv(O?=6e;RJ>;Q z&DCDjnHmUX{7(4c*PGJ9IfwjJ6(B-^qw`J9d&TAfuwj5OK4^-s&IkQ#!X2hbkZKsstXL5f*VHAV;j{D9SX zka%C1%{m!dGkv0wbuFpk)=+Nr)YJV5I%NZ1 zC4b@tLB^zqvB`0Ef)k zBW=}uwevroLRqgM9rEN4mVo%=ZwHDJr5vY9F@A5Vf>+iN3Oj}|-x%d1#^9E;ZJ%Z+>z_1U#lx9EOzxUc zK*r({zV`xT2YzB4ar8id^c-7Dpjj~(HTZmHXo#bm-#F4KP&bls`pr8xym_f4%NhC& zzP>{v6>p@EJM_eV5~rb^2)_`c;NA!UrwB+wK6Eq z6OWeh5If-Om{mjbguH+Tc@xI}6Nke)W^oq1lUs|&qy(3_~ z{N$PE;JrhqcmsGGf8x_?LMeo_e)!F*M0x}70)L!44h6(*@;5OvGgBI|kMjdHfh9s* zWSSwFu<_}DetqSVN2B6|Bd~{S_@i(hhPGTt<~#SdlT3p?_J^JfCWzLtC;RrsBNFos zW3|HWyok#uOM8Ofz7z^39deQ%^m0i_9E@ zng!x@g~lk!)8G#ughVO1&XzG4BigZ8JCDqb{tyf;fUaA){8smOjjq@e8FbwNKVQcn zQRWBXgj|X&jXD8tSNL?hOXR`FRm)?eqyX-KUm$!`AP+wkOQtQg!pU8)AnT!_pM1w| zTO?m6PnoNfZ;;3SYD@&Wdd@BoHBo&v$XmHorJnS3>R?mn$=F}TYRVPbERAxle6oBz zucpKg3x7!Xyi5UK`cdcTPVv#4bL7Ei3YW(#eYGR~g|dWlgsV2uGcQw>9^&hs8lP0= z$zy}wA`k75)g%wECZt)B>xe5=B;^e2iL}3w#gfesJfcxhDHgZm`XqQK2<=UM*h5v_r9gzaqnH@pO2+ea=}(Tib+sT zz*j>+c*6Oq;FIt@OuZf(Q1S4+IC+O;GT*lE0^g&-eBk_wCO$F6~Aac6bd3O;8m-Hzkh?Y--iZQmqtlie7bf@{Q z`e;Sw{Fzy);KKywJ+H6p3;pQ+1}(qok5pIW`q^Sg^KWh8s{`OneeHg1utRib(O;)NldP<41}x!Z48v_M?2Lz4P#$) z@xe4gDh{7T4tA#Y{$QqbV^gQPAUXbPKU$hGw>mRbbCSW2b@h&nzP-6;;HSTDP+Kz` znN^h=&{T147G-Sr4AhAaW*Q&(Oc{)$KW1~JlmA`NG3z~E~srOx&>`JlMQrjtRxPFP{EE2gag zBGu(ZfsdY1tOH^*QZ#2fAlVh`5dNF%x(75TTRT46u{kwa{=R_-i-FjE&rG4DQHSRe zcBU*#Tf{_QdMbGtetToxpgI+O(X&seNk00Z{Pfa79gMA^GnPv?XeYj>UuhqBdc{_? z|GB=|)rr0it#(x2;tX%37*l@0HxI!Vx;Q_rq<}d_KAnye z)$WD;gHOKPI`HBf+lMWGo_|(Fg7Cw!oXiYnFKI7poy_Yx2KI<^#*7(uixx_zXy29e zWWT+sp4C1+`?B+@(hfWzJ1tj>_eFvo90+Uo!eHp`zcdcCv~`3F#hvw298VvuaSaj( z?jg9lLx2DwcnA<6*cW#Q&Mxlm?!kgP1b5fP9Ts0IN%Cv=&*1miHGe%t+p5BqJx|-uV`#3Ca%@ou9}?7d# zrl%$M|9-og)7?B<(e0HwzUo^JQ)Qu;`52Vy2;Z}}v+Av)-Wu9f{WqPkIzMx~ zZS?9G^?S3WvGV7$tW{!KkeV?j!RbIh)_jYli-g@sOD*&LaxiauejgRevz73c_p5WU z%_la|Znx*iR24nJ!b=#=`6s}HO6(|%bKK)LA}qmGL#frQyczu=CRk=ZAt7BGUvb!I)MW^_9z0ZJt!Ut@Zyxq+Gz2 zcW?cag@xnm63Ul}gkgHAu=B%({2G&*SDf?b`0Q-u`}u+gJv388w1Cvo>sOYk%`n z=^&$zalLvDaTBUS@RB10k#3dTGY*NDJ6Of$q!a$3+7~G zd6KXG@6M+|MJjt)+$v__@>DDP`_sX$R+$AGphMTVSEq4ItyRyz2pJQB$)k6+GJoQH zII90SNgu3}iLBN9^Y!9;_A0{AWlLn*_C~E>7Bg;v2%{grJT4MeG!eyw)kEr;!6)zTu2w(Wupm-9YM-6ql^h7#+gO(|1{ixRiCHs5~XM28Hw@^#CRn66qC}m~3h3iOaZEaf0 zSsp&Z&I#X?RXug1bvIcDPoKR6uq}XS0TL1I-t`_+QFvrSo`~NtEY@;FxD2b?*_b?f zJ|Y56I>JrRHtB&n!UOcT>F;N5*Zl#6&>zk{pNcRJl1%r>J}v7k2d)Cr*f~_l4foQ7 zD0RKZ68874?1ENzdxWnikMJk-XC)Z40erSw(N<^S400iUPhiZHNZn_m^rRo|v`9%o zsq(ktzh7g9lXLRVB|&CXK)w>jdwe2iN_gS6y;Vq|%5$FRc_U4%b6l2TJs%6pkpD9s+5ElaM)Vj>haepcvg{Dg-~ z{63A)Qefv~-~Pwayd6wpthyJcdsSfYV3+gsOXKDCG&S`u^uGi(F{+H7IG>N8rhWXtvG52YI95>TvH6cXtBH~>08?*h4 z*;P%Kr^5lm;Y3bOPDVUF7N(JFdAG?J&O?3R!0vGQIPYAy+rCLd?9cR+@RdPs%Sb7* zOcy#ZrMz&Sn~Ylugtbml3W(oIIL4@LYrk3qAEp;g5a)u{NJ$jS$2V&iB+iztqvWMa@|*2@2-L z|NU((MS!1h`eJTUJr%_UIuLYSpaNR>V7@RiUW1}Fno3TP+AiX!rNE+@VZWl`ai#`)q)!&)i)nid^!S9CgwX%rQ$}Z%?fNmex zh*WONV^>N(#|b(9{Fzg56wuVM#PV~$%Tt|J3XNpd$0oz)kG231&lAg6QH)*(t3%p# z|JT{u18wsnriT@8?TQATcSqf0u|v4Eghy$@YPvhEXz8+r8un6|cY{i)>Lk&jH4AHP zR30M7eM{2q=u?Vn{~nMV${Q`_Qmecux31*PhdC0$t*#<)fcANrH}`%LMZdIGlb<7w z7^$DD?qw5{rpvxro_;qc>m&wY3*|2-`*_D-*0jL{gw|jfmSan~h&F28k4RPBzCK%)M;@RLdmv(^P7E5B8ddFA% zf68ksRERjZ;M%{r9Dd2-dY7>RI(X2YYl#eX`d39SJyu?`8eTaU4i22Vfwvg=k1;VZ zpwZmJ$;rveJx#E;!eWFP;|bqI9UR-OM`uyJ(5kfWn*10J=@ZT9RpI zm2Z`{WDz!68$U08Cq|%z$^3lLj4fAJSVWIy*+VlbLnnkIGo%B`LvL|`!7VW*`s~pN zrP_Qm#Q;KdBpK(S?*!*P*I{Wyw;U-G80e^UMZF|~=}FgQq(LQfaa9OgOeTb;+vvbw zsf}uw;me6D#}UJn-+#SpE{GY!?(#%r>>%qu4A}_`yGq=++VlfzMNqHxzSQ#DZm?kZ z34`^S%oS9{+28)%LPF#&URJz!!KX!J9R0FcyO_{6B*&}wjCSH~FD!foM(s%Qjh)A& zkJ`?$xKk%iE-*HQ=J{ zKeT&F%31sIO`flw3&Bz=Uix#nj#O%1ylN&(OqOBz=So*0FM)o{&!;HZid9cIltY(d z*OEm;gX)WIxKNo+dbDd0P3Osu+~X=hY^4{965C+F!id%AHiWcXgb54}^d#x*pC4fF7H>_Xp~QS?=0VHSli6AV@T zA-~|Bc6(LDC8Hnja*KwcI&4S0bwnpTPGDR#UDYciUJgIXjYOTzoM_ZRyl=ta67mH6gl^IFwaIuVA1~r>;LvcwNfz zqQlIwQQwm_s1aW^HP#7G4*!BO8#`r-&IJ7GMy`QuaKhh4SXUNxd1c`K;KX`%Y8FOCOWHkdfw`c)B4`yQdaNfTzZm*q3Y78Q!7f>g++~+%I;(;wSB!16#Yv{W#n%;hgJqKw(CFKv;Rv&Sr|C!-OaCPa?*z zh5q-p2drH$Zl>tH$(M`$CWlhjTJpKCO|ZDVnnX)V|KO`mO=Q;wY=vK*!J^TxUE)DO z0FG>dvRr#PQ(oJLM$kBA6`aZuU_9Be`v8FjJoakE#LLDthyR<8qO{!u|g&| z@HS&9FIYUT_9L|yVO2|7#5)<-t1Y2RKL4nKE~xo-w_Yv@QBg=d<^LfFSuoW?O3@ZP zU+PH@)vNTiww8Ah&{}`wE|D(f7mTvJG)%Fj-voJTSD&51? z0&Fa--qOUf|HwI9RZ|XrN0ZS0?&yrWdggt?N5m?L9z~n^ zG4;!@ny^2XG&+fYlbjP7DwH|<)PmDvGsruyron>F_Fgef=kh6a@M8t%Mv-47jq0m-%~L9*byw%oEb!0%z;(li<3jHdDd0q@8hK^H1Q@X>JZfPsqxTK_f5yY7Q@PJw$JVLia10b zX_MqDn~L2&_j%X0R{%cSzA`<>PklObv~}D?*3Wu5;tg@Zwsn_B5{nfX?ERoA_!yx# zT|F}(EMXwd#*rT+0uED~YZqN1%%C!3enHdnpiCk)PNn4@Y_Y{+B z{Ahl2iew#2b&!BJ4rzN$O?+!6ASYqeIhX;-VZC+MF833MZUbzAf`(F1*V^*m!w1nqwUI5x?zdL81X0A-@+~9^>`K0a*_LMXTsR;pm3` zT=v~+NEf+bLaqcqI-pSs{5POCM%0beo`5)tbUVH74~rL?kra+3Ea5ZK%;M-8;T4aN zt5OgAsHl7=`n3W6F5X5O<1pD5FT1L zTa;UJgvdQ5s0QOp)`O|FW-Dj#?VpUYh|GO(l11J_j@Z&&v+FxZ#r2XP!Y7$`b8^o{ z=;e0fmlJ=SkD#n38r4(t?{iJE`VyUH>;KbY^P&jhY8a&1c)onR4OJzlo;>GEKFu(3 z&zwizSUod32j4gdQT|KU9N)W4mXgbriHQ!#%o!!gB_uK_+kL!|N_1-_Y2|O=?9Jg zClxOEIH@IRMb~CJ5c8D85jII*{j@KbL5teVHf3>$eA ze@EUy@w}_iYG36MBd8`OovG%5*pBn#>5LQ+X`eIJVPm0K7rv6R@|C%n@PEaYB4qje zQBbi^kNuYiY@v5{3@~B(99mwIplSb-60G0fyn0TK=6-yV<3{Ze#GnYvbrm9BH)+@0 zo9uZ zePs2r8^O4!<3IM*!F~F^w-rA;5t#LnY%0nCzR@3Q{SFJM!;xk|VuOyf?{>p27%DHz zwFGzE@22-_h5^0MtbXrf?;nokG5Y1ekZ+6M>^c41tJN>Te&Zz=udj zA!n|4#Q&XC>RYw`U@o*eTJgVn(^vm&%$rcKgumUGz1leQn@!AYXkb=1A;;J-*{C<>Q5nsz&)50~*%Bn-ZqWsCT_UBO= zrY8fsMW|%|c%rO|-ld>&8;n>C#r?t%6qWH^SqeB5&E83~G0RUt1P|@bTu6)>V!tUc zI>PNz9dh@yn~_U?*gdPam-b5^K0pT3TQz=Vc$}ljOvCI_#s;NOp!c-kW$MI7)w+U- z^ek{et5oyeUq#d$ympk(+d}KivmDn+xfLeZr$_XJ={YojWFY>|<<+NNaGaIkThgbE zsJly&VLz=)kF=S-i_~L3r0EO&Q%rU(g}$tbMRGcI#M+f?e@D5UC(X|$YvT{F)q{it zwyC@f?aFHuOZL8=bWhhF=^|~V7W2_rS@bQhiiA4DP9kbxFy+J84hhbShC4eri*U_N z%o}{%zlJIya1NA||mjVr!e?IrAnWQ;47E2Wf^ zcw{kBow@?avqXxu@}3OIq&Sz7PRp6Efp-a%{pC*@bx5{$T*3AMe`L! zC0{D?c}p6bScDPY+f7ruFW9Fs15AA!kJ4qo{XH8{lQ0%davKQ@+yQjCxZbI$ExOZj zHzDMk9q;rJY_{%C{808i-Lss#mG=KWNJ}Lho>(CLH=v({WC$#V6v^W1Vc=K9(4d^Q zn7yJ$m+CRo(ed$0IV6}s1Px1Q9_n8cz&As6=#ea$)EsoMpEY*Tp%EuzEeW2fug?R* zF-}3|_ms@G6-XrP*(v%6xk*3xut{OdnH&b&&mC?QGc~9(XsSy2==?LO(_H?E6VGrxOV+R7ScsRcjqF`vNK^n^j-z$64P8!aOTl`?jh-5jnT znlixV(F{uc*vCYIcZ~ADAH#H$LGJ&Rol8vQad=DE{UAuq!FvAZP&nE$?=)a5`o?vo zK}1R&=5eG$QCv7IV{0Q@xJm*%o6+asVIu45X167MNyD37+IISkyo2EmRx-Ao5xFlj z$`-x#P_wfx-&hnXcTQlRH03;0{q)ZlOED5zZSI!@fKuq#! z+h7ZeMj*`yXgyJW*le)h2m z-4Dut<7q`O3B_1$--~ndqu@OC^`M$XP-8K+=fp4>h%l+nQ3Jr#{F@e|8d2kE`wa8zymVN5Hc8Lc}V=#I@ycko~A`wy=#TJUaSD9#9^^XJyM>Az6rvAOhAzuD6>*^kv5r6=X^f#d0^!w$u;2f56jE}H3oZKc1G!5+4*5CSY)_n=83L?NC z-MHwj2n|vdht%t2dB^_xvygSr^V2dESx;1{cv_;hpIq;leWpH0dj7Y5eJIa{JWLRb5(I$xO9BARJ5&EN54o{&!M{ zeQ2XhS4ka%+k6e;Ztq)Rk+wQyTk@by7Cu$0&;ZwbO4N4K{(#1hCpz)MB{AC(Wm@hP z%4yI8`p{X)1q3>mKprt{@AEPS!!SoM{4^pS<-nD1v9Ui6FNFxg}rS|R0zYY4PZ zj9zEP=4_O-(JRg!iy?*~l5QFzKNKIf+2V0ZE$*Zou;dm;72HK(+2)AkDfdF>)utf6 zMsdg!gAy1}%NXD}hci#a*sY(5dYvl_$Tt;+P23C-2Xpm#DSs}Ppwcq>)qoHCVZj=r zU#r+&_V*oaXL*?&SM>>XHH+$<8-(Y%&smgiaQ3J}e!U+|V(93w&r(m*`&G`A8%^0- z!Pg5f&)7Q(5`^DU^*_$uVOdaEuPiBVBS3&qp@r2&Me&d0{lQDZe#Po4sfNc#p`B5T zuOw3Os!oKro9Rr)iAgmz+sqjfDZHnwplyf4^_KcJL78N zI8xDZWOWyZGW1}cBwfG9x0>@?==vBKMQmFT&xeoJ21%W{xu}Qvzvgz^;V1@OnlZ*e zzVq_SFvyT2D)uXx_D>N12?3b?*LrnOLg4?B7Pr(Gx;&j?l}DKA=)|Whq&=&7@5h&b1`KfDJCPBO7J!5emI@qH%UmWItF5$IeMsiLV}|efenIO z2VaYAyIpP_Q~Z1^#VHHfB7rr{J^Yf^WjWr$*u8qxQb1zpe`n6Vkp0L zVTZspvk8{wbGyHY<0jF$opo{Uj<2}@P)Vw4TlP3Dhi-2#ZQ0U z$WI*^f8^}G2su~{?V^2%KdJ5M;YmLcjF$1Zj$qO4$LFfDv2T0Kz3(I#VBh1}-lX|H zf!MI^cMH*>Fh8XFj7@U;i`djc-QMjQ^v;A`M!kMae%D7;6YdL{Iml1-eijK>?`H&C zwex4zRG(9MT}7*aD56tlQ4ub?1P$JC-};N}@!eZ#vmfzL(aa9M#ITsflFYunG8ZN5+-iPMgt#bbOveEZ78Gj7CbG z%ZD!W|1%mV#S#g6Q>XpYpbmp&jsR~xp|5AyXzEt9!PUJ>d)7_IsVeLX-dBE;tw}*Z z5}@-6L`S=&xo*T?T08}JjDG5avrD1n>?eCIZor%VC-~OI?J5e#>uG_*?F-g^)hr(w7MG4@K#xZ#?o4`ajJX6R znH};dk9Iqmf|l4&(}^#WNp_eP^xtSz+0#5i51WJHe6&05`)QmEo?<4o`bJA#aOsVn zL6NJIYfpiC$sfVO0$q{71v1P_-o^4ppb#$e-K*yACkL zg{OVg1RZi2!R(CX?*%8TY^jr-;o9BVIZ*Pz5Szo#%}P{(mnnxi&zS4Mui_yl#eY+4 z(U-}tdYJ?r$!6EB?wKFf7vv)lY_cnjb(@=o?%iyiE~=#}w?3Zxe(q#{h2Yw!4k*O( zL4gbN#IY#{Ob<2B*C$g7xz!aqL50*&^4H1Y=ox*AU;j8y;BI@2vAYi=+X}v39}o44 z@a5cJ$S`fA9A;(!?K1DzPbVk8waPteJfGm7rTW||`HhgUkaeww8edgN{nA)lA&Ht` z)3ONn$Lx8{mf|)s-U?kj-Di2egFsgs3mjwk1lFIgIjix}q^*F;rXpIBa@2f-U6Hct zui2bTOv4w)#}T=nI}xKwX`GX$lJ`E)jirR_M9C98=%cxBEc_*+sO(%)L#JeuuT0}`s zeMwUC$XEjTK7Q|4)20nRw(tF`Sp2$z8~%-dcvcmI{`Qqf+zmwOw-`Oeq`h}&wz_qL zPyn&GVgw(4h|bO~Ns-2Uu+;a36#j#9>9^tiRg60@XJ9f-&4{kivv2Xh!;yTl^XVrN zsGJEZ8r|lkOb%%n~^oFhkjE0~k7N1}*-ES{t=h*L?F%*aUzM28A*Bp{3 zVZBVvcJQ4^$42b_Qpq4SFLX)dA4P~jwDNe*USsAHw$Wx_ocK~X;k=AbJqgo@Vcr+| z(|xv%;b2~rFFXoJqG`drq9r{*Yp2H)x;UXm^ z6&Y^ohav`>R3(B6AqikLKij*9s?}wXSAU$&JRE#{&|422-;#*WPcjJoPfJTnyWLcgEuiT(;@B--JbbjS98tVh1Vx2q%|2HJn&GD*QG~wUMeB_bdxn% z#Z0lLhekiBo604eX@?VvHi1-+&G|3izhuXw``G|sYirBS!7)j!8T^9h(O8>|xflr4 zeCgh2*}c>g#_q?^s($X1W)9p#eViVDO%o@2FGkdtB?I;AYb6gc`1#Y=gNad>K~c}B z*yiD~rO|`3-ZLNCL5Rg`p;c0RXhl}P{HODiyh4j$7+S7ptHi?|c4vRe0v}wLr8y4g z+0rHvxlh(z)Qym3Y+1O;_174#cY?B~cES~pi{WkOVskM%6q@Y`O>!8&W^&HnO?|xXW#gOl0uEvni_yv#KVLz)FbbG)B$u7=o7hC2_Yn*&E>X`a{() zRhLstrJxND+t=3(s&*n zL$=@CQ3}x~GTt1+jFl!eFIRTsqT*CEZ#@kRS#Aayn!61w-i*dHwp<) zvonW6;me=e0166%b~upNgHg!#kV+636@6k>{yCk8RE!&@0OErsXbkKURR;P3B969J z$zpt96>c$yd8=#AeFa__=5hoY7ol)bCu2_^pW0WQ*Nx3?pHpKq5KI@bHe&!o@(u|N zzQ=LweA_23Roj>51T_k6EQ1em==gQep7*q_kfFAYj-ELE4a1M&Z^6UuY-?unJiKgb zZ%J{W`Nu4jKg1%)w>B@L>7GxdJSh`+en36`uYQzM>4pIY!;?jpdhHLLTr$*4?{adt zkT+4~rQ*#iX_L!bMMKx=SRjNg#H`T0|GcQy)_(cAW_-1yiOqYUWm$4)mLc~`FZ~0xy%lCiu6GmP!-%GYY=}7@ zY*1IS8%@bHB;(lKQXy*+q?4=xo?V7D2wO=X6p;Q+&S2?@?x)L!lI4^jU^p3x2J=@9 z%RF9=aK$U|ZIfL>6tV;1!>wd|7C)Psni3ohUaQV*t6MD~N?ctZM0TV37Q;VUkj7i^ zPACaM4Nu8mmE%+n5_^R&DR}dU+rD*a=Wg-sXYFaw^~8AqBJnt^oXl^wcP&O7)1dMN z5_+BrFwgai89d46*8d(kZul1$Zr1iPT6c-8@N9J+uJ?xvBfbTGRA=s1q_)Q*DP5E z+2UdK%P)CfL*GQ-!Z9yYExp2$u{IVRFFw_8)y|~IMdC3ba!KD4%&nNE$3e*T`esVt z2%88m8Ctsdf(HVAn`!07I!E_dE?PNmqAqTN{z4NDxJrIc-JOAgI|{FT#sm?x{f`k` zhb1H-`KxeZe#qyQ+0XDo`oe(}mZuDB0YoF>Uy%I|L{p8TM=L~rJ!z0UQF3Zjsj$Y+ z-JU7MQwJ2$M@T}cYpu%+I`r-5h^EW#58 zx8&}1)5=T&DN02`-#@N9zxJ!9Xu}@|Xl8lo9JToE?lgHuX0XNO!nSrQGJ+~;9V!P< zxz0yMuEG!c9tv6cy!w{hmEC{9M&EDo*NancCQ}7n&WMp2X_F_&M^ZA`HH(FR4U(V9 zx^bHT4V!&P`|$i`X9Dkw!^X+E3a#kJ?gDRq`2A3m!7YAE*_jVc05kuzdW~dbrM_N$ zm+TGREM&t$&Fxd9pS-WR*-9y`E0o@W2lF36+kZdHewM|TAr0hl{KfPt^f)rBz&DSPU z?5=aC9Ku6nA>QTDE%tEz^BQW{LB06n7?SH{(&5M`1wGn^?=^ZmdoOubj(Wa9SxY%S zgfy|-Nyj%`^pp-a&ku*2K0sl-Eui@E^p8vNXiw^au&C}l6w5IU;M>YEPg%;Oq;H;2 zneyQ+tI7EUWY*~ONbwl#KJl5!!1QeF8uu|6KMy7@IU(8Z$A#Lc!0+tcm-(fO3G@DA zUYDwiaVGK{boardTypeCombo->addItem(tr("OpenPilot DiscoveryF4"), SetupWizard::CONTROLLER_DISCOVERYF4); ui->boardTypeCombo->addItem(tr("OpenPilot Nano"), SetupWizard::CONTROLLER_NANO); ui->boardTypeCombo->addItem(tr("TauLabs Sparky 2.0"), SetupWizard::CONTROLLER_SPARKY2); + ui->boardTypeCombo->addItem(tr("SPRacing F3"), SetupWizard::CONTROLLER_SPRACINGF3); + ui->boardTypeCombo->addItem(tr("SPRacing F3 EVO"), SetupWizard::CONTROLLER_SPRACINGF3EVO); } void ControllerPage::setControllerType(SetupWizard::CONTROLLER_TYPE type) @@ -231,6 +239,17 @@ void ControllerPage::connectionStatusChanged() ui->boardImg->setPixmap(boardPic.scaled(picSize, Qt::KeepAspectRatio)); break; + case SetupWizard::CONTROLLER_SPRACINGF3: + boardPic.load(":/configgadget/images/spracingf3_top.png"); + ui->boardImg->setPixmap(boardPic.scaled(picSize, Qt::KeepAspectRatio)); + break; + + case SetupWizard::CONTROLLER_SPRACINGF3EVO: + boardPic.load(":/configgadget/images/spracingf3evo_top.png"); + ui->boardImg->setPixmap(boardPic.scaled(picSize, Qt::KeepAspectRatio)); + break; + + default: ui->boardImg->setPixmap(QPixmap()); break; diff --git a/ground/gcs/src/plugins/setupwizard/vehicleconfigurationsource.h b/ground/gcs/src/plugins/setupwizard/vehicleconfigurationsource.h index c9e10f5317..5784342943 100644 --- a/ground/gcs/src/plugins/setupwizard/vehicleconfigurationsource.h +++ b/ground/gcs/src/plugins/setupwizard/vehicleconfigurationsource.h @@ -58,7 +58,7 @@ class VehicleConfigurationSource { public: VehicleConfigurationSource(); - enum CONTROLLER_TYPE { CONTROLLER_UNKNOWN, CONTROLLER_CC, CONTROLLER_CC3D, CONTROLLER_REVO, CONTROLLER_NANO, CONTROLLER_SPARKY2, CONTROLLER_OPLINK, CONTROLLER_DISCOVERYF4 }; + enum CONTROLLER_TYPE { CONTROLLER_UNKNOWN, CONTROLLER_CC, CONTROLLER_CC3D, CONTROLLER_REVO, CONTROLLER_NANO, CONTROLLER_SPARKY2, CONTROLLER_OPLINK, CONTROLLER_DISCOVERYF4, CONTROLLER_SPRACINGF3, CONTROLLER_SPRACINGF3EVO }; enum VEHICLE_TYPE { VEHICLE_UNKNOWN, VEHICLE_MULTI, VEHICLE_FIXEDWING, VEHICLE_HELI, VEHICLE_SURFACE }; enum VEHICLE_SUB_TYPE { MULTI_ROTOR_UNKNOWN, MULTI_ROTOR_TRI_Y, MULTI_ROTOR_QUAD_X, MULTI_ROTOR_QUAD_PLUS, MULTI_ROTOR_QUAD_H, MULTI_ROTOR_HEXA, MULTI_ROTOR_HEXA_H, MULTI_ROTOR_HEXA_X, MULTI_ROTOR_HEXA_COAX_Y, MULTI_ROTOR_OCTO, diff --git a/ground/gcs/src/plugins/uavobjects/uavobjects.pro b/ground/gcs/src/plugins/uavobjects/uavobjects.pro index 46236e484e..a881aee656 100644 --- a/ground/gcs/src/plugins/uavobjects/uavobjects.pro +++ b/ground/gcs/src/plugins/uavobjects/uavobjects.pro @@ -97,6 +97,8 @@ UAVOBJS = \ $${UAVOBJ_XML_DIR}/hottbridgesettings.xml \ $${UAVOBJ_XML_DIR}/hottbridgestatus.xml \ $${UAVOBJ_XML_DIR}/hwsettings.xml \ + $${UAVOBJ_XML_DIR}/hwspracingf3settings.xml \ + $${UAVOBJ_XML_DIR}/hwspracingf3evosettings.xml \ $${UAVOBJ_XML_DIR}/i2cstats.xml \ $${UAVOBJ_XML_DIR}/magsensor.xml \ $${UAVOBJ_XML_DIR}/magstate.xml \ diff --git a/ground/gcs/src/plugins/uavobjectutil/devicedescriptorstruct.h b/ground/gcs/src/plugins/uavobjectutil/devicedescriptorstruct.h index bc118a8df7..be0ebb14ae 100644 --- a/ground/gcs/src/plugins/uavobjectutil/devicedescriptorstruct.h +++ b/ground/gcs/src/plugins/uavobjectutil/devicedescriptorstruct.h @@ -63,6 +63,12 @@ struct deviceDescriptorStruct { // Sparky 2.0 return QString("Sparky2"); + case 0x1001: + return QString("SPRacingF3"); + + case 0x1002: + return QString("SPRacingF3EVO"); + default: return QString(""); diff --git a/shared/uavobjectdefinition/hwspracingf3evosettings.xml b/shared/uavobjectdefinition/hwspracingf3evosettings.xml new file mode 100644 index 0000000000..0d3ec63019 --- /dev/null +++ b/shared/uavobjectdefinition/hwspracingf3evosettings.xml @@ -0,0 +1,15 @@ + + + Seriously Pro SPRacingF3 EVO hardware configuration. + + + + + + + + + + + + diff --git a/shared/uavobjectdefinition/hwspracingf3settings.xml b/shared/uavobjectdefinition/hwspracingf3settings.xml new file mode 100644 index 0000000000..669793439a --- /dev/null +++ b/shared/uavobjectdefinition/hwspracingf3settings.xml @@ -0,0 +1,16 @@ + + + Seriously Pro SPRacingF3 hardware configuration. + + + + + + + + + + + + + diff --git a/shared/uavobjectdefinition/revosettings.xml b/shared/uavobjectdefinition/revosettings.xml index 2cddb0f9d7..bb258e20b6 100644 --- a/shared/uavobjectdefinition/revosettings.xml +++ b/shared/uavobjectdefinition/revosettings.xml @@ -2,7 +2,7 @@ Settings for the revo to control the algorithm and what is updated J2$M@T}cYpu%+I`r-5h^EW#58 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

OZE0o*~v#MuJfE*c%KcuTsQmW$( zK_<|&F0N-Ge!5E$Sj6cdh9!&UXDDDLR$OE33D+@IN=2yNx*Qt1=jKj9{HzmXW|GZ= z9q=k|6%f}_qLFB~5EztP)L>%BMc%rUjP^VC9#(89QT7{Q0~t1)5Ne|OkZ0L2Sed1! zO6Lgp-rvgHJ?v$5u+6i}*5MZSEyyK19IXmK+CKzQk(A*W+Ytr=po}X#$=F4nU^CFe zq~w#T<2x1b!BE6J!_Ifs?q?(epVx}A(oX#FFfMF`g;ioBL!`GG5@%QJ$RuA6mBS4PTD&@9He=hR6}(&+T*UbDs>!CDs}r!SYA6i-)2_L?t~ zewtdJ&dT&6K{NK$Y+uoO1{%2Usd3?LZYSan^>*&oGlcI(it74UxoBu+cL$>*)Nml& z|L#+ia#r9Wz~27wx~GIq9U5}D6l;xMg@U~AUwhVOKH&{zI3UM#R7*|>(-l>{yu1vj z5m_gJOixYF>SwL2r0GwupSrFuFukxw zQ_IRrcL$xHH!0L%{7DPQWV0vvtDRP8{ZMZ=VwC{PZ2iN!b`MOMgB=zciz3~RN`S*T zDK}_A%!rW$`Rn5)ZuU>jenQ}DN`?;qUn&h_@(}BId3kwCn*%wcK~q>~AoPD;y)LP! zZh*QSU1wScQpv!hsJDg0T2P7nF<`qh!h#&t9$FF1Q-Hyaup&Ut1ti$y9|pvaH-GmI z{I-jX=>-OF6hFH){*u%N*B zsNz*jzQ$IZU+ZL!0W*A^iuE}VF^bh4`uYCcnIof6RRkBFIP72{H-71bwSLt2L(7%+x**`h)gC-`A9f)2|X^$iS!U z)V>DJB27|XpX7(^d%?#;`lr7xB`>wWY?r#Q6Va*Tdk3}j`XKk3mS2i&iN9kdDD?6` ze}msInKQb2{1Koyot zCZ?%lkiA1%(M7e!DInQYS*c*87!+4Fb@(G~pIxi{@pPpzXs4p=zc?l!aXY^q&B&%j zq*rf6)h_DV%krJPvoD4Q#gGtkR2(^|RXeTiRU1*j*)Z!vAWEIcpe8E!o{f#*2u_st7n@pqSjWa!{b6dY{vz zk?{F*+|RVZ!>I#j5CsO8JX9O5rmaw8vw#V%DQ5U~s*+rVx5`(i>c0$y8EKY#LtM(A zp&;>O$!;004xc305*E0uzc%P5Y;Q}~u@K?THw}IPZI5^Bz1;TR&c;KnHDFP&Tfv-y z8V5Hi5nn;yhk!D~>G}EPO9v|}L<&-YNqeQn2>Bvfjmh{-wpek38<#Za((}>N0TzB5 zMW!xat|A(*NYLP9Pg#O|T4GDx*+RfnpC2{s;=R4lkpFZ6T)4PIypGV2^__!oD01?!=vXOHV0<>5 zZx1+kaO=y#q5*RTc;R5Pb@oOZJZ>4k(yO{s3)~WQV*RR;L%WJC(;@#z-vz$RmB)$2DatOEB)N8)?}kcPw247H{C{|yX*8|q zQlYJmGZHG;*s%e^z#f4axrYQn{(L(IG-CckrhUJrYEWfOuUTrryqy$g4^}En1jQ`F zS9rLaqqnt^d0gWHK|vTGW}~~H092I0(zN2zz#XTjn$I;J^mrRuAB(p6S>>FY5miuM ze}AQ!3pANmaGnmYFF@i>1h{>6g*>rl*Z-a&3Kne%AYnIzfIAk5)?jKSgT9jppyQ$Y zgL)o3Guna*@kOn+7GK8O(`-I~y$%Zxm?DEA-rNczzxD^LLm$|>J&wXT|ZT}?n zWXP&t_T8T$>d*f2x1{Gj6ab}I9$5DGGb@MKGXtd?Gq{nz1I;j)y+FxS?cTbB4mnJ^ zV6)zp=jU=oE@5J0L$VgqHaKB%!ewaxgFy)e!K}pNLjEBR4wsxmb)Fpl%NO$?)_G(F zML83k9pDg=R#cd|#h?n`o>rahEm36*6{nk-<1eH|9QghFfs_`~kBzvE^DeM--vsjC zznVCdT^-xF4p&V)g+<&G93oZpPje-2#qsP$=>eJb~T^#Oo@k6Lq?pB)T5z_XvJ z)zm7BBmW!OTe9l=R&jLnzs>}R(M(=feNy=R1X~wt5CBR*Ap(^KC!JS>XHH(rU~~3E zx!!GyK!$mR*j?P-X%0S?D_Q{5a*{bB4GFr8p&(to2A>V`gPwD_!4<{Bqmg>^&;7ke z_OFopd8+82s+c(V;rsiv>KiUP`BmJ!h6JlK&DI)VQF^M(G&jb=|Qn*~`VloBGNT){ENQwEJ+i&!mArRnTzbsVji4pL+ zGSPm#%hpjscYS$w^LX23c#|)q`Pzf~z>?4#Bk@<{D*WQf8Ruk>#=j^W7=Ddj{x&|` zRJ6Uu_@R+<^11fV4>1pC|LCB}vK2RmkvRFXT@q)I8<0%c{53N&?9f1kR6e(sl z7Q2ecpwkL5e1(t!q)$27{{B5?IJ5J-LwDZ{$-lYp0PZiDvHCSb_mkg|$k-8KchtbY zLoAenjS?oEs|u&?R-aa6EC#xPN2`^mXp;GEOB18GZ*(h8|yF6(L5jdKJnmo=Ho5usoG8_^WeeF`&Qw}x+H!C)|ETwEnGn1+y7OsP2NA; z4Z*2s3AuqHKA*Z(z#TB+fN9y>F-6z7D*>WaWs|!!&El?PKd`P!tU7!xRTt5Vl^j~{ z^F#WcWS!h@WyKyYC1QC~^?>)`t?+f_E=Qb(QhP*N+~60mp3M}EfINC^>~~e)5^v;2hD4UHcEt!vn5mqt%mZKDvyS zE0BKw@$7&2AVoov zz5vU7Y_ofzy0o=NvP!l0atNr2{Z{{!68UG)i0Kw~HI?ybK6xV{ACQ;U8LGsIM`jes zInZdE{nOql%x?5aAAI0b2p{PYnG^R7hs&}VlTgxmdv&%M=GyAbjU@A9!14>O75Y1R zDfgey&TNhbVaTqvghB0!8R+QfVPLi!`=QG*f4Xj)2U48!#Di<4CUV8Q-D*lSBJOXW zi;9b{aj@T|5#Q$bC$jqrYKEE2$+7%Nr{t}5^iRinQ;;U2UkQh{iPJ#*K1kboRg&Km zFJN=in8C}Gr}gfbZF_gup9~%uBqNMPlg5JSN2vnkl@{u7P4V-p?~OkbQj7O#FE_ei zAxdm%utY|9f3s+gkI0Y&DlrjilM2z2k~fq|(rMEp2>_Vr?P(H{pvOimeO&h`)ojG{ zJDv~7&7}YWIv~3IPo&0I$Ke}oCze(a;7iayHYO$G$buIl;_U1k6w-;KUaA<6iAm<$ z8F=7&%x|4fMPqWUW8bmV_jYx46{uUJKgpS#7_sBH!aT#C>phdfXBtgt#%QDbyi1w^ zfJb;$6)OnXFX-5#2G#rKX6NA+Z~ZqicYO{iFpn=8g`b|!H4Uwiho`@`sxTK|0#LfG z=qHPAr9NbaoYsQ_0|*@*9YB!aZhB#iygw!Nx){ypcJ3vCDWNc&$&0hqr)qlI)7!T- zMCuDk9^%kSbZYblb%3w|Vh!VXj4wK0r9JZ3Uy$wD1Af;`y~E2EFKtU8uI(dVKkbAH zg_a$39+6!gM31NH*t?vVoJuG-%=rFO*OoJZ9PHGkTc9p-=l|T&Ti97}$?eRVa2Q=Z zQ{>6TuFHrkngegl!Dt6KH8O~dxQMEw%t;U-`X?r)zc0IV&L^`d5)u;gjXs2+m5BhO zqum_`RDdGCRy#QCEt&(sK!CAJ%W1cBsgDqn{hj_l9G0rPkL%#?QG`_FyK{Eh#9}47 zxU@|DBS*&3(evw@+4@@Tver|X_kdODEOuKBmdxu&CKQs|#rh$-t^})_K?_eTE&YX8 zI={*4lENm@%sl%Mj)$Tqi>;}~G#PKWUt{Y*3}11Lg$d5`2s=5+xLzc!G{@CI!NQq$ z)-lHAdyOZ72iN@CyQ! z#AbV2bk;eWSvUM&?s~c&K5`y>`@b5^DxZLj?)=7Djbo+<69GV*y##DF-O}8A$x>V> z1pKg%H^-8C2kU)Z`Q+vM`1_Ez`f8fG%D++T^YXbp6`;dQJ?6sz_7IFprJuDEo*A%< z^1Tfg?XveD`r;VE+VMx`^iA6#hYyH$`uY!bMw=1}=&%7vaDBgL#$2D=Lj8r^-94cp zaL5GH`EX4N>74WRZn5E;s3PdJ{bPNLx3dshra_LcR~An#)-;gyiVQx-i%t(v8kH^8 zf%e77lLaB3YD8U`@>*?f(4g7-fKrtJONb9d!s+gpZ(#eczF?-7_}mjR#&;*c9AEiCWm8& z21bjOmvJGW<3I0ciX8_;7}&3Kt>^6A{YI?viwZVo5-UuuQdkVz*8$sdw^Nig?zb-N z&_HxoZx?;QW+qxP)48@rs^j;F(-%V|GH2JJdHM3_;OHW8_sk3n>)MS37aVg44MjF( zcv&iMmYS1C8{zV^bGTLBT@z2=ppuBU43#x?M;VJsWPL=7WPh!8cMJzYLBTFUKMgi9nRF>NaJAm%HKU(>-L+9@G3&hEn8V!0YIC${S zIzCz5$jTmp5LL%N)e^mpn1PTNw%>2!tJOG?zO7%lgA-onwCf~hbP3lKL`oVIc=TfW z6-PORe>%9}&~`{%z!y0K_#|ua2i%;fKtfjMOv!_*CswjpDVknTP+V4WY$^56qdaK#k5M-1T`zN6?O9;kS#bKOUDJM4GI+!X)~>Dk*XLXzMgaj7{DXrO zeis7p*8$5viNJ^y1ezFPF(90aPl#u>7x56OI~DL;KTc)y>^V4pEad7c9hP5i@Fj*Y z+sr#~0|hzQT?hrWL$7Ms|C^c9A|`tHDv1vlghCM$!Qd@A`D>gA?c+=FfTXwZAz77r{96!rHb!9TXa;q~O` zrE~5tmFN~6@BjX+R6Kk}3{OPFY`M%0Y0r4Pz0Pgib+?oI*F@~>P(czMuv`+s?zot+ zvawwN4Z#1S=^KFKYTvgvPGj3P8{3T=+i7fDjoG-dlg74fG;VC$&i}l>Z@x@2v$K=k zJ$v@q=iK*oUl1-?IDw~CbGpC5)a`H}k|}}%NH_h!81TEMWhX9R<*9eoF}UKV1ZdRi;_hvsuN;$)6f|--Us!-K|`ak%jay6Kct0tw7(B~&6EwL;u4#R%Z3@4aME* zYS_Xf4I7$HSE=&YZ+34iQLp+vM%3#o)UM|#pHk@{5*FVfx&P`Vr@H#>#eArn+gp_T zBh-}!JBUUZs8U={b|6SGrs?gq)qdIz8201UA5IN!0*T4D@)@;&&?5Bo$k_LL>`2KRE2_Gmor2ZJ=3*73v`I$MRm~P14USu3~92-Z;e9)kRnIJ3+hU8fUq}06)rxc>u)H4f>wC>Qi=}8{H(4f2F{*C zooLJB*+2I1$jGnWYbBq}U~%*=XdHNmf-hST4lTNcMa4V&MY6yY81>pQZhQMUVj>!W zCRwJ!!xNVm2I@a*pdb?xFuUBed4_XJL-;zmWfa0`Vk7qzz~0+*rFAL#%!&PhWO$!w zB0eku?*}%%oD*RG`=+1(zFaHDLw>wj?Pnvn29LLRO1wq0;F z0VECR^gLXPulsR^$?msfP3pkNVtf$)Ul%-haGE_tKNk@Uh<7!H#;e%T)lsC|?;V5$ zGZraz!=%?E2Df)-$5+_e5rB*P1Pv@{Z@E6 zl}+7js;+cO?_?QZd;=g}i#hFRMarYfkl;Nxhq4s=CO_D46B5UN6am_@>z9mj;RFgm znFbX5^=%y-fJ_3Y2buKR47Yj$U3r^0V+r|&yf$4!ICpy~M1G$Mx22ZSa=<3Gw@)2G zhCo4a`-YVw(pmX7#V_Vkw@NH7J$@Ir)VW3K&foY7TeP6)VK0=80%1x-3pSXjiD3$x-q>kL5M z4M;?1aBRLw@Owc<#P?2&n6}GBvYY(sQNp`VL(Z^9I$Q6=r&i1i2n&M&zJ&O4H49iY z7#SZ!Sp=iMmeEy$eo_(q6>1BIm)$^vqd|wzqbT)LV@Q;VPfD_AoOjN+5;<+qPOJ+_ z26&d~!OJ|n-=_v;$VgAF8m6BJ>T(O^9?QzZzqVFlCt1X+Sh(9S(?N>lN&&JWzpSGp zixGq*<=8BKqn%T?t=qqSgYuhHDseqpQ?YC$@E#zB^6m5U-JjV4-nDPT@$qrLlG7qc z`$I)27!2fR5Mlt}{g@sl-2_PZba1PRR0h_3usE4W2B)oNnGEV}(rXEDHlO;hN_{lm|21OK0{hP`V3_oY zA4w1rgdOjR@5rZZHs|VN(d?fYp>MZ6gI7u6*5F~bm?scPo_jSz z$}o~17m-+!IafA+7TMc;eT$PihDh@lf~rvG3XoU3$5PP2k4#s1l(|U5ta( zd{*yNSp+=$L+r#keWP^`?^~E3Pj@Hl_<#cb=0mFiw)13mwHk*9jw%s1LR$K1@Ah9y zMSMymbGGlcgwORP*VDl(Fy*1TiEg{81h;tGMx(>*tP>#ckTYLwo(fbQ%6RzzLb@-x-7H2J)AP5K<4FrRRO|k5+g|>q$6sy zD@CYFS!Dk5QBwY~4hq@j*5$GzPzXV>g8|WVYSmC~hSsL0vE()r5gMy)!3Ihha(j)% zOnO&n*3WtAYb^E7Fd=*;g|s|AZgD%)L?GlO2qM{vnijG*&OPOETZvIj@pA82paai_ z$h_Dh=A6FuIQuI_F$|b)*Hisd_z8_PaA!t)gcSvaEcBu|^QdY;jL>dFlaP=edYqh` zOwN3H=HWbyAnciCV=2H?3ob0u^GM6gZ2t?flA5QLx(b&a+Q63;e_>(a%3}>|(t^u= zB{<0Jg&~@?Lc0~bdCiUQ&Pzc5V<`$0kic&4kl%vCwdqBl{dp*~?ZS(Sj~@jDj~XAw zo`XGhXa9tPqOl|$6d(X{e`)B;dnwW3fX{XFT{q&=??L9*35V{td`p7iJh3owRSga4 z*}K*BTdUmNogIe-j-{=1VAzU{9e1|gezk~iZ#aG+@9_NX**03r(4smv`X(|m6mEDi zosK)}W`lw{AW||!k1?gkZ5g*fzN);m6#CW?8K0VyXGz=pBFbP4I5@{Wf?!`YH8qhr znmOBfOmb6|PJH~M;I5@ygL+kaMLVJ^oh@i>q(0Q>&JV9>JOMoQ49tiKX^%(7Pq?3- zJ|7{WkX2$(FxMyk9i_wFmHIJ!7j5|7j~A8+6*qrjE_Vl04TcU4d}DTpWAijFHvrx1 z(?NN4&_z87?4kH_8KWqOR$^v|2Z%;rio-_+Op^t?ZyY}jh{WaO5D1W9Hat(|Z8V#i z&ff0^J=td<09yul=1v4rSak-SP@YZy&0k>mQd^_`{BvjF)f5QySL2By&6n4(K<4Jb z(sP>>&y~v6qlN669oJMQ4@A`9?5{T4=2hRw(OZ6GU%f^gy2zSlmc)q2Nbn*I0@9lK zkR)7$Kv|{GpTruK!K0=r1kC&{u!?WzO3`?}l#snY34zdBX09c3K42+mwvfPwN?M){ z#}QgTwKq0l<@nxwiHs$-cG7#eSob)K@7`IdHHn`g1*1=4?B9`q*P-11k||#;1a15wpR>**ZJHGX zGan!RDc8rw9s#hM;iS&IDTk<&C`a05@jeU0u`W93D@aI09j52!8*-+7KP4wMId5}K z7-Pf4OqLh4e|mSv_{yIDD4YcJV{pI83ZjP~O z+%dBdpaA4|5$BTxur7)hy!*^Baej%4ioDuC`}g!R&K&=*TSzjt3r(-x&DI&B(&6Ku z`xc1oL>HUUwr5_ul3Vw%VC~TSAuTIoH5Z1_d-@$F;GGd$d}MUe`g-%T;>lU!$d&iE zy!qU$t=lUU?jjd3C5`SnvBDuIbJ$eWca9P&R4$jOGoBIa-iB9Ks31`1_Ou>gPSsnks#$M2_YVSFxHftS zXs>;4{)UB@qF>PQyQmX2Ud{C8mRE+!w6o20c^v*#I6@(3KDva5-g?a`uQ68fDC5jz z{_nbZ6i;qcy_f~)-1GD0Mm9RfO9sqYa1fyH>{X}!Z1sTUxUOMM<-jD;wxCG>&Y4n9 zY)Bk)=txNiJKu2A(pV(D>Zc;3BGYX;LPT|a_?bFgV8_PBYD`|6YX0P+in2J&7+ScR zlPftnJAKDD+;=wso?2JPjvqkzYhRWO`fm`pMZd3%U>3p)Q}YtMy%$3weEXvR>Afn* zw~@Z;lF6jk!L7Rvmj>S_Je>CPk_znChKheL-VsgW7v{H9%KsSl%z}@)Kbai3TaFJh z9B(U|!LC9%1zxViNb!#+KHje<>Zdt;^nY^@*9*PMJ?H|O`&p7GhYhFI^WU5%&{P`^ zozvgqgr()=`shC&H$$hrZ*H&lcH_e4sX#6lYq<7Zw{}0bKOau3Sq@(>#q7BHEC%YC zJ3y`lWn#o#pG4{miJJrnkg>a0IZGeN>r8F13MJ?!)!kr^o6hbdjw67}6qf=wJ-x%t zouv<&a#UbEFdShH%Fcpdmh=^DAwh7lj+b#Z;0D?(;G)pK?I2u zz1?IFxWWLxIKB%D%N>p;BYA)BSr1LB+L3@xJUk*MWD?H{JaN)a%CbPqV;7P(Wb1kE zKi8oc+&PMu^*rmjldKT6~UJ_}}+7#q5?$IkyADh`@&( zT|=}t`^PW^P0e&fd_=)Rb=`2Yy~teL<$!Yu5XA6w_0-ET+uhIMTGxS?k^lVqNSh0` ziuAa_q9w`we&>Yj?PY@*h~Yv)zYs~aysm>I+IButn*!aQ$5mb!tN(>=QYH_23MX;P zp`Ba~8}5Hso_WhTF}rGSAT$M7$^XG5&og}op|4dk;~-g+3Vsw2zA_bI9paav&QOQ$Ad;72u~99y&CH_ z7*bK>4@^I?l8aBP(H&udrV4iv9A55JHHF`bA#BODz-G4)6Nj8IW6w9q5A6S#Hb;<~ zto0jRVlFih^Q$u-E#$$&Y^{~&dw~Hg5vhS7a~=l$29!;o`yZMs1iUslu){{Xp@=lh z%*e7QcG_ONfLTXXw~=mtEew$tiu*cN$CjeWf4-h%cm4|Q?FmifE z(Fbc57k4Jo=4MV@NE`qCr$l2lsRlS-jhSjVG(auG4WM!q58b^R@x z_M*pN%KP?)970XjXC|aySc0~J@dc7%<#RiS#6?=ehe5!O{BuxDY0Z0WhYCqBQRhBa zj1t-=S3+rEI7ge{JIwpiA0$z4Cwa)EcXhsG5Vp2d6otLpY~T+CE8^tDrvH9<>T%WeDr(0yX4?1e z?}?(J=Zgq(cAxo?ySM!G3ccoYY74ZDkZmsKL7VE;NUf7zp>a51LpY1oh;i1o zKz@|RR$kcETGXfLj~`G~t!@Z{uY0?|+a*GgIJjUpa!f=?PXdUR8{Iy$!~CRRtDWOv zND{$+|KJ?u8p@$z=;2dZsfl1*6(<>wtAFMJ5vN&wqs|1G8^6`))xYWEDqfZ!#^-{k4)e~}1SjIfFW zqa8fXJvd^UUGFv4he*Jx3#(~>2LaUlr@P&_ek^4Fy%D31hcSN^qa6yDqZu%*+XExD zEVp}NaD@%uaZhpwW}KCfz^X>g8vjkf%r7(8WlHgdzOp58M|?&fp)V%+=+6BZAqz}f zu)w&S1Ifl9fXS?9#Me`S2jhj2Ay?yBUE8R9X?7l|#5UV(i7Ck!R^4`^3T#Z8c#(kgY{1wn6~R>TQc zjF4UFe+@8c!%k7cU)eZma=Dh4C@kFqB$XkDnvsx@)3SJf?x%kZ+7b?vTi>E_(L$cg zzIYERJR)FUmmDEs*NP`R>sdGKgPR+fKq=`?#loCx?$2 z(~#{Yt@dhCvaZ=w3$63895hzUdBP*t))$S6D=Chb&S_N}p_ytsShs1t;#zbnyv+?L z-x4Ac)#z-n_)UW&rCy#dRB9TYR}00$km688jYXBp)7fU%_N3rI!2u2g($Flw55sLn zFK4a5@SRq|xP3`n&U1UC+^LL!6T%zg5>gBd?%Wr5#scGkg|O=q;!mEhj>^wMi^N_X zD=C)*H`xs>8W3#3A^E^X#+x8DMJgpM^fazQesyO{I3pkpfyw-CM}Ei8#>tY*I1s8-`kt4YUC@K zD79}FU3RWcKC}jMq_{*(_^$a|J32S`nuqJxi!78dkNUUU7>-hwuan^l*H)(3+$1la z7{MU)(2T3A1`mqCQc7F!0G@>5qIa^H`g*K(WM1&}=f{)$!6CYq z;*CDD7vGlV8Y>rzcbcmB|6G8Kq8wQ}9IJ#kGgweIIpLR)B7Q}*{VL}c8g<);EH)vZ z0ZgFq*PNU9F^mIYQc+e|SSU|_rC$Thi^4PCwOK|*2uT%~jdKV=uQd>Tl zMkEDGl#>=f`VNj>e)(4^>NgEhJ5mGx9DcmffSAf|uk%MYdSd)=t{}9{RCDis$yZ#` z9x;_2R{nLI@BZ!X^SLG+(5nys-m?EYb+zFuX zu(*Yvy$Oq^LL#2@-{~j!dQNv>jB>?dGZLefPF9I_&v)KU8~oLblCi zP7;VSI+k>ihE=FUzM4{~?$-SnCd%7oaTIqDy7MyAC){-&WOHq3RTEkP>qIUM^)!;{mKUM0pZ3!iwD%D!ZX_wF~0l~|xKCl=fe{igNZpC7zG zbPc}0la)cwZ&6c?eu9+XT$$r=TbA}l7zORfShD$U@hMO zJINWIz5hSWj6|8e#e8zlyVI(EYT~Xq&rScR|Nfwy4-JJsKR^LSmN(PQiz5D{NxGsE zd5M#>{IrpBb=kzT%%Tq=NwaFy)^`L7>a^i4fet?4`^(9kVIFnQJg8nsxY)7=I9cdl zTWF+T*3K3FQia=4Z9hRGt<7lj3CzC{G)5Xa7(6G(tvwkd{BaE@4(C5tpxrE3q#BEy zdiHWVkI{oULkVg?4H~I2$$9s2@03`Pz>spb>wKoNS?hq3iY0&o@qc%qy?DP1>}0x`w&-(0Ly7$O%oKKfxem=p2*Wf{+K`)1`t zfpGDX7j;q9I;sX%rdr#P5gN+E%A|SjT!ctiTxuq#DTVQRRP6$H#P21{-t`x|$Bouf z`h&@7NK$xDRHc@*dcM=f-s5+v%HInl**gyJweADAgfJO$*n*VX;;cCbFW1$gEb4Lj z+%81*{RA)CcHP7?CIv68Yv;%za=T)qr_1~ust=hm|IFU*B@Z1QHxjhD%xsN}7EhDy zlUZg&gK2Yc(f#P_dvRj0eyGgkS4Gjvi?mKBh@X{@tMtymgK0GfSfPw*Gwy3Una>m4OX)Q{>igyVFpbc@-2VMzA(uo;k|3Ow|Hzt7a?=-x_riZqVuMcJvqiq zpZ* z30lB*3;`hO^UaGWzu%Gq2g@hlutDv&y=uF9>=0O#Xmg}BG zWvln4X0$iW1Oxe28@Q}ll}J%6Nsaj(CYTTfw!LiBn9A>(bPh8zH}gqE)Wxsea^M!l zQ*P|e)|y6cby@jElZ(4CWGMnF)nd7HAP1qLrfHR(2X`rsFe;WXv2VqWra=}0F?Ss! z-o~0g$VZJN6^5`#O1eWApDC^ZthI(76FFiIh`@`doNl6h#3+w8VVSsRo>oL~#L2`u+uK$0NZgKuCc(3OYKXFHVScUjzx8 z>SAO9EJXZlH?bbidHuzbc@|he=WPkDb>#&YS;pj=czj+T8Da=s@|SM*lV=5QEcv$c zgwZH`GsR-Ixp6Cq_=-STx}v4=#xI}+&g=CozDq(5hpiGK5O;%(j1U(lrLrAmau-y@ z-U_D$kMl>qbX=i={u;_yQnSM>x))*mnXVq6TbssV8f#4(NfXRPI}9NoRbHVJq8zIH zIt(hb-AW*FNoOV-XE_M;FqKnWtGRA3fmc{B(P~cm=>PXm?zrrvCsI%MN!+>C*JGlX z&~FI-xzni*TftW2pP)4Z|Fa&z`}~Voicx4L$tF zqkw0hM>LTq6u%wv$NP!(pQIYGH3EQCyiE%C^;p?_%${qYU_fjX7@xy-ZoZ$Tw<|} zKdgB&jXRa~@9{Q2m*j~@1l2*83Ddtc+Xs;_8;me*`K}dC^PNg7%zxXc$7+%gLb=a8 zNvx*C33l0;bdR|WGQy%Rb4Dg?H)4!ovPhTdTtb4*5_>y`{&^$&yti=T)=vjHc9umjyMV;w2A-F3kl z$ApHCPEt41U8K%@T0fKD^P|B%eU1t7u6Z*|(e$9)z6()D=cC1DqzH%qPpQ7+M|P(l z;$55$LyMDeAw`x($uHIu@vSxjPRR$%9L?FxmrIM0@u@#{euXM z;Io}{qKRy3mf9ho+Js4;1G-Ckv7~$@S^Ckp52}WqGR7Neg#86@H=>$x$wqOhGA1a8 zQW5ISO^D$vZYP;^kcqo;#j5R~+Rwr~+hSNjOyRQX%QMwh7|)QKj7@qj9S6%z*wOKU z++DdD$H#Gf$m-Mc)bn$8w3G4b?k}=@(X2iX5*`%pt3ht3KR?(V%hrApH$xlbc^-oC zIU$XH(%?dLJ=d~XToVKR(UjHZewq4Z%@`iG|HO0SST)TYmyp`ao%3tovDwo>Ny<3g zf~JINW&GLCm;LXx@Ye3HDWvZohjh!}az@p|j4VElWA6U-i>l8)JTF0PhQK^7CoMQE zQtzn~leFa2O-JebykI`=M+FUZTh`S(bMmq$$<^d>)98QZQ5e>ejp20ZDg|~* z>2Mb2FqZdpnFQjm3P=$=8UL^_vWCl>J6O%N1mZFYhAG1e`Xs%ni!>AmhB@>;G}M+1 zr@J7)^rlgPN|1dBnf-ZUu>e66=rcCoH2)c^ikrN+E^TjoaXdoVT`h3EYrrRFq7!qJ zHcXa?_Ck7;k51IvSu$}}o_KGhqv?nBknp|8!C1<-lXNV_CuXerH9-ApGVzOMqGgsL zV*tWKgGlFbg~i)bqDS&3p91lNjR#4O@7r$7DUaSoFSRT^xH^Jdq}p!as3RJ-nh6~P znV^pLg)`;?0j46$?TJNn>sPdn=pM{1--x%C!JyV|H5f|URaV+B5fSG1;c!Sq;u6Vk zGI@%ZNufBdpyhgirr}aGjhUqUT?YAZe;-P}q#Bb3nm3x|FXD{ZxJuv8KR%xh`{C@R zEM#-x4W@)UlXMOQB1IAd+2lwzBegrGT37pNs{FnCrKmXb!vR2hCXVN!sslwJwA;HV zzM?RUy zye1Szs#lF|HR9^yKM3_&YlXtVe#|sUQ+*p@(FQmx4iUA=@b}@&g z`K5qf-@BufKY^ovf(EH}#7pt{9#(6AR0~)z+KYCq5Txp%1rlX7ut+%6@X#ozdDNT+ zKy)8!>l7Je;S>yo%aJo3=ZR&Gp3X6qW7Qmnqo3ASid4q_w{Bm+DRiN=MMUy^ovRS; zh&Qc(v?m(fT$=yx6Uob(W!lZf#K2ggmMlPh+;F9C(7rtQq2ou#T4r#l*8_ku$zDNsx2`Eq^zP3{Z?z_WIG?Z&q$ zjLQw4viNroeNwD5My3E%{I`5*P#$0!`4Nn#R3nsSEz=N@vysPdsDx=I!V!ScF_JwH zI)@Srva$>Y#5&U9Ao5$CV@N5s)|hk?0-YyQWP!OkV`vfX-}Vfwzmh}>$P!w~0cSsv zDyD1uutYJ2i+sshTB^bH(B@s=F_m<8dLMk6x~UzBjntcu!M{=M`< z6T6Lz`t3YV%0_Q{?Zyi1IjmDjG*H~J<9@??xx3r)=}#ne%Nd$|;rCrux3dQL)yFJC zlS{uVQc$kSaO~4v0dmmAXU>;F;js9p`ieLB^!iC&KAuLjLnhz&|oIXflhVaQ~#5<1hhXmv&`TsQqZ_Cge5}; zRD;_)W{xvvH(6AN}h1NGRmpMk?7n=bNSs|Xole#XY^{B1ACLYMk|HMgie zp`}OpDjHvk3)TZDC*E=Jvo8oufL%jMsh&5kYelt1IC4mz27%}+3P62U`@+b`*bgx5 z-}T2Gdra8T9Ts{9yj6ztUsFL;I8?Z8>xi$Ah z({ik)fK#L2##cIsrXJ87t@gPAEq=ta2mM>_KfFtE>SRmf=Q2jGiAN|ZuvQ!;C4n{8 zJ~U`NHj*Oih6?VY@ZID)F+|gOegAREjIC82(q~5_gz;>~h3NX5++FfkSKo<^1~?$}%n4Ms25zs9Hf?G%Z# zcFkf%>PEXm@>j4Mhk{=j!2zft;6Ns7l2z&kCmS_TY;c41z=1m#$ozY~#9xgO_RFP_ zF!?l{Xrsb|Q1LO}=b&y)ghrN6P7brn1s3;34$dLFbp;PEV%V@b70J}u>hd3tAZj}q z3s(AC9+NO}>G_wvqgj!du;KwI-P`X4WF9V(qQc2-)!qCxg7b+0lC#T2^$oHDFA>-l z3fR$1;h9GAcD{VDQR+8Us0jd{a`$Eus6eoWlSkBH7_s(fso)3CI)HrS8$9+P_(xgn<4Idi#EPPLd0l6tg7*E%QW)^qezBkxW#B$PCiC;* zqAXdBGLbh*Tl3 zEP1=dKi&N_bdSV}l7H(Mk}>DYRDFnXoHX2I-i_k3{?RCk7gvi%zs~4>{>u-wjLec34+aA+Fw%vyHZWUp%X??-v{r%M(5#CyWL!|Fz|HosY4LkGH<~FO@gD96HFMz zVR$P|w!7@JgU@=_T2jEX?3#ywbfjaMB!1-#rzFMIc3yLEvd}y%{vJ~ePD8G3fU?ep zW3%DA74WsLSf*euU)c<+b#6J@gx+kqJAawxfv0-!&n2(s6k@JVB`Rt5xEh7I6suI* zooc_de&T9{TLDg!Du1fmv3wLVXyZ`F*435`UripelW(vbz_e1rAI$YDQuVHvv(Aco zxtM(Ol>9Hbjz*+rKkz90cIQny&lon1(S`8&o&R;-=O8m=@CF7lS^9l`VB`Oqv+4gu zzJaajY@?u!SAeeEwq8>Q2YUGUdM>R~SwbQ@%|Tm~{C6BAx;I|;OkhIR?tC>-gxLGH z{ZP?k!D8$4?-PM&$F$*O)fVTkPa7Kcquc06>hNS*t1-v5Q{Q0*tKSRv8QDK#W}OvB z44AVb1~Q6?#IR|3otA-3+IGL1(5qHzI5XekN<9aGRa6xX=;*}6j?aMilY&X)a^q?8b(fa!#T+mC*XxUebR_yc~?7Ur{mwxp8qAvgPpV=2&j*f{F z$#NFpL?&?ZN(gtJk_A+C?5ve|32l7QKlj2e1ThK_a&kd$t5Zpu@WCnr?$_n?iQOz*xd&hswVpvE6w`VS&tn9);q!@Zlg()6j8GI^ z?3K~@QWt`t+yq?NU=#Dbsr&m*;H5Cq#7&aqrqKk*;4PwQze=#q9OAYoj=^j&Pw&r)B}T>7670FO&R%iE>EoW6a;-cCEr4x2O!o7*1{%JBz- z$7XzZSS34e9;cizye;9-GF#4cDc0TG%a&-A_nOGv-+8Rg{I&A5+?AZzE^)*iv7_Z$ zdFIZ^5?;!95zYv*J0nJ--noz;+1xOUH>uCyqiWKz^D{bGuFY2g>m7K)elSzi5$ z>r(ibr{=4&Qb=&CdfKmele^ zX(HB>hyjaKRk*s)>f8~^Qri-B$1?49Z|B~~QZ8$L(XK@5{tBiS+hB#4Y^Gn*f4Kct z5L3gX&Ajk99+Xjv&@dT+xoo+VvSK_VzjbU{bP-VFn4V67pk$E zWvGlgcPnFAKEMEwoua@FZzP>~o!`h&gW$kKICHIo>QUYbD-!#M>ix2j>!)gs&scv) zsQRL|L%Dj4KZpI&c7DPD9Eh7lB`X-EXP@L0E=9gWi`+P>C(#Ai|43(hWZ&drVr6&x zkg-OAZcf+cc%vxsg5~C7fhqs=M=ji@xWpA2OwHP@t0zuumZK~uB{||-A))hdH+CiY zCuK*d>dLxe2H6vSx`F>*;i`F)aj#}U_qS+#I$lo1VV%A<8z?G>p_@ug5V^a2cu!u=S(&Iz)?rHeuLP=%*E%oLgEjA z&2mZ8Ql`zl3ZAEFG*3kG-)wwyN_U^YVcDB>fR?nbBj z85M!N-}l5lV**;tzR*DvVnY}vmsG(!eG%n^k(eSaWn~0rYs;3+6bdW3yX2q=cM*6N zDo;t!7Aj8DD{Rc#Z|g)H3sF#_(me_k5xDqoABwaFjIQ6lGhpqBeYuIzwM_RWa!|s9 zvN6t<$pK=6k%13kJ3AIIHWQ7|na1nC@yf%KGxiI}Y!o6X@%QNcUQI4e=yKW!;1^Y! zWj>8G0y_tB6LkzVYpPtoz-w8TktA%{jKFcneE^`%Hv+0NZ;GmgPe$KCm5BqDYu%lx(XP8mn-USwu_#8UU@Ve80HgZ74BV%XF~uTc;aIIXK(t{Z-=IF>7d$zg<7z^kj! z?kSOdH@H20Si!nv9A4~f!lJidy6x>_Q-$2VHAQ%Gv6P4kwH1rSw048iVB|ae1tDa2 zt=B66+!*JCHot?5%+#z|d>rp%WO=&`Q*Pl8#22?0*DwN%>0RDs#_ryob%NnENbWc`Ns&oji>qu2xxYsfccdjm}$p5Kr7B+ zuKu;IYBh1qZkJhw^6Q`MX1*OP2qU@W`lOli55f%h1(O2_mCS-MuZw`So7VMcLS#T$ z3g0>c-{Y#Iblt|GQx{QO&(-K`B$giAy(w{nSP|K`;{%~r`*9-t4TJ9o8bUv&QK|XC z#kz@jyG{OkclMKvx8=CXwwSe_zu|$okZGbDo=I(l$9tGE0YVQ{FK~#&Yd9I5`LmZe z@G!3b{A__3AvLOPD5G53BEx7;nj!*FAC5CP_b84t`%ptPYb@)5QFJ_S->f^pSuglY zgX;A6^uERD&0}75smBV@AlElWexU74`#YRV^wKxKZ=BSFZF=ee5`!_U0CRwrhp}9{ z8M|w~_AOe8v`uS*<3~?dfr3v%3xSY*q9SHWLCZi4Mnn#XU=_=}9w{6V2+^D10>A{nhh z%mKazFhM`?!QaT%i1lU52ykNYKs@=_RT#)n3+K3&j|Q3aY$q~J=<7!e;#-kGKheNN z>W=X230Fvm1Y0yxVB9|8a&^6z!Z~YbKvh_2Dv=wmUua+P&#)?xe{n8vRC%kL3<9|B z4rTlfsXFgCd_Yr(#7Z|X5(5yO;%W^`+0&z0slLm2%Fsf62g^-jEjEj`Jc(|^2N6eR zace-g>0!tGhz?Xf0V4q)0k07+Qho=Lf~u&jd*DPH4D2gJ;ffc@i&w%>%*{71!m|4WkKvL<_{H zrZzMDI)z5SF+`KNrX5<|4MvIGZOJ8DnMw|{OEq$fW(5m?=qUum(wjl8oLpS)mC zm`f9XK_E=4|9k;vXZ6W~`THFSv`=qQBv1{evSS3Ey{{fivV%y;!2b(#ZL+_uzO2a2 zooQkjB8en}Vi~q;-c-@l#Bo^DU#ELZ18h`0fhlS}&5$EOiKYFk*7=mMij2gNCgt?4 znEU01-tvms&CN|VkbuQ4PWxUr^$lkITTYiR>t5YB2n2)(4PcT>ZRbf5^|m#p3S-dv zeH=?=^7y(LUt)oUsqjkD*cuqL1@#ewDPhnKJ2D^c?R6}#aMsn=JI~F|vhl>~4C9T`id-sYD9e2_rsb)AzX%BnW2>`yb7;GtRPhE3#HvL1 z_ShQ>mdaCBQX$i0a+!6PCU@10d)?BIV;}FsLj(2kDi$HG(URTkiwNKi{4FFoyP*X1 zg1Ylg*Fmq;gGPnOygT$9aI66zk_;bAYip~Jxv6PIagsjjnQ2v}g+^L%bnPMFF5X8J zmk9ho7+S6$nDhYF);Nm%_ZUsK>p`n_*&&W5!&}=hL;#Y$KW>E4OUCxSxLSjO=o<0dH=UV**eAEkm4AD0 z(vA`%M;*$u3Mq?FMKv8kqMC+)QU&Tm(OMuFMVhDfR>C`7WISc{3p>~k^2K_aQM9+0 z+i8!R(=EU4l#bPr<|MnP0viz;|z1_l`C`+%l;yqLEWcS)r^^ z^K8d*=!gQik2CDay*Ui3di>-kUDOr(K1(#Kmu0fVZ{k=^>vLnCAHRnJi+Ba@j8Ze8 zs-0I5+7q?K4MY*fWyd`g)Xsw2CEgbFct2qxnIA0gqgUU)8%y~r>(Jpgaq0vKS6^gw@_B6XNME&u(N3^TLI;1fZ&-J=G2{$^pQdVO{hPhEAT^*jNn@sbOe zqm#uZX<8FWLfnL2W(Hlo_h3*S}fJN`RT;?mC!xAT$lXEtY%q`=d^ zE1Y0G+l7moh@)qI{rNAfDLM6qv$TzP^m*M z4(!pYTwlNt@7x&m*Lp88G3fpZK|Ec2{yN2(fe4^-2|__A9X0X|()S{})4>4}c&e9B z>)**UnVQ;O3n}G07!O*GE^#ETRNi>`$GdH zv~30HfTJ!MDaBWgGM2ykW;6UI6^WnhVx5T62nT~LcIS9FWMmGLzgb((WBF>_6$KaH z9`HHeKlm!tkLjF`>-IIst0+ErtPWIVgsOY~|?u7e;onYk#(GVJ76n|fV1jRZyZMI_(kms!|v|Xxa zrKRDfW@Ry!QV>h>vJQziK)fy={I{+VduYl)y6Y+L-(+RSAyH6)oT!S50ryRx81IV~ zLVw>Q5y17H7_c@Oc)UH>1;7re)T)HGKSl*Zq6S*+Zl?X9(f8*R*wmkb=rS4c(0+FS zr{dnur=qU!-H9fOr!SCRK;>R{*92I2MH%F#P8&Z5Z1!LXwK*v3uWQq_&+CJ~xlT+c zB^mbS4~}TJz-qx`8v!@DJ#Uhxo6eE0TXz7}fG!K4`$lfu7jI$pgUaDsx~qJjCe3SqKGpM-|@wIHR)M8 zaLtb5B);t2Au;|=!zYmoeJ5m8B%Zyzs9&Yqpd0z7^-9i^v_^mI@%qfeLUGM|TDMBv z#HQvXe?<2Jo}HA4I_G@GuYer)?#)Dh_O_l!f{dy9F-*%7#-i;Sw861NcxR3o&h`um z-vaI`6NFX84^8c&O01aYIq%tQvAA*^eamKdI*nU}oVtR-ZQlM=u_%R0;D-ft)J)zx z$q_7}jAOmD$ag;G%y)fAI^C61y&S2w?UOz`Iy{tqcJb8&*=d}dhRc{jgrawM4{fW3 zNMAD6=U|g4f^cozf%^1SxJd8h$=LsMwywS?RQr_A2!yPj-fTIx)_d;b3)p5Klya z3Y;FN&YQ^>I9mOtM8uTTVUgM~Y0rO7uQy1h$IG z6J7saW(rn@4cE*N5ZPykt5kMT5{gqIoQ0&QTf`K-NLPz1Eo$RyH}1!B_<7k#bkFH{ zDVeJeJl-7Iq@d*T#T$Dq{I)T&3ALHed-w;*(1Azts<=NRSa6&8gy z6(jFK3rS}4d*tR5iRdg*bi2%qtLAVUWJ0>{wX?Hx2|tXJ+b$#$wBV6Ttvea`S*uhU5%kDb|<1VlUHe}5@?M)V= z414bDA94?VWP_u2@8@Cuysv*nS4mlw=cG2yuT-`>{EVKiEi z(Iea=Wx;D|?utst-C;E#w>J_(l?>G6+#d<+J##ScraW4mvQ{kKBP6nFZ+Qe3gmlyn z!oi!QCl+>LlSXj^!o2Ls2_w zZ8ei#cc^?;L=m*$C(ct=ZQI;L@{hwjz$6fk#f5EkmTMUyy{E^^>fv;$>;v$M-6o@h z9vi>=-jC(_S#%@uPB+ID5-<7|arH%{PKC1@^sXuH7AZTVjYMazOolJ@)@8N%iL5W1 z56g&dUNf2IU~^FvRx4(%qM@hVOSR zQ9<8njH{XO<0ww0$gR{D$sJYNQq^PPy9ezti3STP38sF%aIKMV0;iUm_<@z=B|bDJ zCm=9LQm0Rt8SidUcw=%wRW9J=<)miedQ(HZiv3uS)rBF5_>H2^c|fj(hJ>taKrcBw z2FsOB`ZPUv;HwccGBHFLhcSk<2Dz3e%@)dBqs*B2k&WdleBvLO7L?}-m*gs7932z# z5$hlcda6G!B&VRjkUZ0nz$0S|72}7&{v35ELMF0U$m-oWX-Rog3X63P(q58jOzBJ& zto5H^I2D|AYVc{~uF!qz$DD9D;)cn#dPQJp+nUrbI|q}cWB#i6Xtb5a9FQ`l<>jX4 z&_8O-pKag9>i=CBD8JAapB7NR3CDcZBZ=a*K5!7`q9!7hKY1ehe)IxaY%+^nS@H3E zl`(ZLfWeAKzjGvIDaBZL4&@Fwkh1RZ*g-_?q2Eb{f$ORL*GQclf_h5JYXT8XXI$3h z^rtEk-IsULTwUBilorwXXv0Du>SN8r(HYyy+ajjBl71NU1@n7vFdd&Q;US;Sp1UPsU@2y*p zd=)aH++DphRF4fUS5%FswWa}?PXW;h=<>ltM2fF<=F_Il>ZKkT*)$*{h@i_V1;6Bk z#rCg;0yUv*O|i5KI{rFniaf3K!o@Zs!qM_%gxF1^ee27U&KD46!$YBYx(rfNRB#c3 zA%Qkp&1)MRLKP&{OXIC-0(s4Crs&s0uh_^7Wkm+`4-5>1sFLDU0Fy8gxgd|cG5xl2m-`>fNsIz1>-?!xr-I%3%T6u0^ul#? zxN-~@Ef-hZlADWla=Ip4&yd@R7!9Uziclfl{h-HgIz1agpmXUW;HtE~CVqq7`;-!E z3cHoB`L2TVGka@5-YUeidF&pXP-xrUmQaZMeX(LVz-XI&Vf9^7LLwm8LtDQauF$uh zM+X-25OA81-#~DQWsEJa$MVA-s+TEr*=VVIo;$%XlTGfPNx{@G+Rc+zKdC)_ z(p-Houi$X=#`?Go^PO2#)Iac+An1SRd%HND$$-cNUX{$^;ec@40L>4eYbxf8sHNt# zWq5efQi(B+#`hX4O4?$swJ;kCy)RxYrh=t!=GV=g2+Y@yX8SsUJ*dyLu5Gu8!=>iE zFmt)A0<6mv1!FnkxcMG`)^haQu5M*GT-aLp@s2@ecLo6I->Rt;4#v~+3~4D4pPZx6 z8NlSn_AN;kNx#`85{d5A;hWmN-}o>ZC9pC>4R!TG!QDTZ<*UpDqh!@PQXD{_Ck}qC zF}jj&NdHvce+?w7fKo&DOO%hk!J6JfyJN^BtrEp!f@>yzkk9XBszdM|!(MCP_VA0pl-3@BjtMT%@Aj!p*+e zE&}M!4h4a038lHMylgmD606u<-CzPPDB`&H^E||ib_d=8ejp%G@5Dx`;_8qd^GP5r z1U!?5Z$JM1zKh}#aOufE>sIIKTy`%A#!Hjv`pXfF@>rvUhK7cX z9j3#P>NZW)xoRL5jj{Pcu$MFFmimages/gcs-board-nano.png images/gcs-board-sparky2.png images/gcs-board-tinyfish.png + images/gcs-board-pikoblx.png + images/gcs-board-spracingf3.png + images/gcs-board-spracingf3evo.png From aba9d56ccc065c9aa70574e884d00f6f49e726cb Mon Sep 17 00:00:00 2001 From: Vladimir Zidar Date: Thu, 1 Jun 2017 08:12:14 +0200 Subject: [PATCH 300/624] LP-512 Set default fusion algorithm for PikoBLX and tinyFISH --- flight/targets/boards/pikoblx/firmware/pios_board.c | 8 +++++++- flight/targets/boards/tinyfish/firmware/pios_board.c | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/flight/targets/boards/pikoblx/firmware/pios_board.c b/flight/targets/boards/pikoblx/firmware/pios_board.c index 021df1d156..b9b81f5f20 100644 --- a/flight/targets/boards/pikoblx/firmware/pios_board.c +++ b/flight/targets/boards/pikoblx/firmware/pios_board.c @@ -37,7 +37,7 @@ #include #include #include - +#include #ifdef PIOS_INCLUDE_INSTRUMENTATION #include #endif @@ -62,6 +62,12 @@ uintptr_t pios_user_fs_id = 0; uint32_t pios_ws2811_id; #endif +void RevoSettingsDataOverrideDefaults(RevoSettingsData * data) +{ + /* This board has no barometer, so adjust default fusion algorithm to one that does not depend on working baro */ + data->FusionAlgorithm = REVOSETTINGS_FUSIONALGORITHM_ACRONOSENSORS; +} + static HwPikoBLXSettingsData boardHwSettings; diff --git a/flight/targets/boards/tinyfish/firmware/pios_board.c b/flight/targets/boards/tinyfish/firmware/pios_board.c index 961fa703ff..b6fbd02e79 100644 --- a/flight/targets/boards/tinyfish/firmware/pios_board.c +++ b/flight/targets/boards/tinyfish/firmware/pios_board.c @@ -38,7 +38,7 @@ #include #include #include - +#include #ifdef PIOS_INCLUDE_INSTRUMENTATION #include #endif @@ -69,6 +69,12 @@ void FlightBatterySettingsDataOverrideDefaults(FlightBatterySettingsData * data) data->SensorCalibrations.CurrentFactor = 0.07f; } +void RevoSettingsDataOverrideDefaults(RevoSettingsData * data) +{ + /* This board has no barometer, so adjust default fusion algorithm to one that does not depend on working baro */ + data->FusionAlgorithm = REVOSETTINGS_FUSIONALGORITHM_ACRONOSENSORS; +} + static HwTinyFISHSettingsData boardHwSettings; static void hwTinyFISHSettingsUpdatedCb(__attribute__((unused)) UAVObjEvent *ev) From 5194f79784a9a94d181444317432261116f337b9 Mon Sep 17 00:00:00 2001 From: Vladimir Zidar Date: Thu, 1 Jun 2017 14:07:23 +0200 Subject: [PATCH 301/624] LP-522 GCS: DFUObject::CRCFromQBArray - allocate temp buffer on heap --- ground/gcs/src/plugins/uploader/dfu.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/ground/gcs/src/plugins/uploader/dfu.cpp b/ground/gcs/src/plugins/uploader/dfu.cpp index 26e0262f17..f6546f7f2d 100644 --- a/ground/gcs/src/plugins/uploader/dfu.cpp +++ b/ground/gcs/src/plugins/uploader/dfu.cpp @@ -1031,11 +1031,12 @@ quint32 DFUObject::CRC32WideFast(quint32 Crc, quint32 Size, quint32 *Buffer) */ quint32 DFUObject::CRCFromQBArray(QByteArray array, quint32 Size) { - quint32 pad = Size - array.length(); + quint32 pad = Size - array.length(); array.append(QByteArray(pad, 255)); - quint32 t[Size / 4]; - for (int x = 0; x < array.length() / 4; x++) { + int num_words = Size / 4; + quint32 *t = (quint32 *)malloc(Size); + for (int x = 0; x < num_words; x++) { quint32 aux = 0; aux = (char)array[x * 4 + 3] & 0xFF; aux = aux << 8; @@ -1046,7 +1047,10 @@ quint32 DFUObject::CRCFromQBArray(QByteArray array, quint32 Size) aux += (char)array[x * 4 + 0] & 0xFF; t[x] = aux; } - return DFUObject::CRC32WideFast(0xFFFFFFFF, Size / 4, (quint32 *)t); + quint32 ret = DFUObject::CRC32WideFast(0xFFFFFFFF, num_words, t); + free(t); + + return ret; } /** From e8b7aacd99bc4b71a7df09f677cecb2f5aff95d2 Mon Sep 17 00:00:00 2001 From: Vladimir Zidar Date: Wed, 31 May 2017 15:21:49 +0200 Subject: [PATCH 302/624] LP-512 update F3 pios_usb.c and pios_usb_cdc.c to include bind_available_cb(). --- flight/pios/stm32f30x/pios_usb.c | 49 ++++++++++++++++++++++++++-- flight/pios/stm32f30x/pios_usb_cdc.c | 38 +++++++++++++++++++-- 2 files changed, 83 insertions(+), 4 deletions(-) diff --git a/flight/pios/stm32f30x/pios_usb.c b/flight/pios/stm32f30x/pios_usb.c index 63b5c5db2b..f7a36e8251 100644 --- a/flight/pios/stm32f30x/pios_usb.c +++ b/flight/pios/stm32f30x/pios_usb.c @@ -7,8 +7,9 @@ * @{ * * @file pios_usb.c - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * @author Tau Labs, http://taulabs.org, Copyright (C) 2012-2013 + * @author The LibrePilot Project, http://www.librepilot.org (C) 2017. + * Tau Labs, http://taulabs.org, Copyright (C) 2012-2013 + * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. * @brief USB device functions (STM32 dependent code) * @see The GNU Public License (GPL) Version 3 * @@ -44,6 +45,13 @@ /* Rx/Tx status */ static bool transfer_possible = false; +#ifdef PIOS_INCLUDE_FREERTOS +struct { + void (*callback)(bool connected, uint32_t context); + uint32_t context; +} connectionState_cb_list[3]; +#endif + /* USB activity detection */ static volatile bool sof_seen_since_reset = false; @@ -55,6 +63,9 @@ struct pios_usb_dev { enum pios_usb_dev_magic magic; const struct pios_usb_cfg *cfg; }; +#ifdef PIOS_INCLUDE_FREERTOS +static void raiseConnectionStateCallback(bool connected); +#endif /** * @brief Validate the usb device structure @@ -195,6 +206,10 @@ int32_t PIOS_USB_ChangeConnectionState(bool Connected) #endif } +#ifdef PIOS_INCLUDE_FREERTOS + raiseConnectionStateCallback(Connected); +#endif + return 0; } @@ -282,6 +297,36 @@ void SUSP_Callback(void) sof_seen_since_reset = false; } +#ifdef PIOS_INCLUDE_FREERTOS +void PIOS_USB_RegisterConnectionStateCallback(void (*connectionStateCallback)(bool connected, uint32_t context), uint32_t context) +{ + PIOS_Assert(connectionStateCallback); + + for (uint32_t i = 0; i < NELEMENTS(connectionState_cb_list); i++) { + if (connectionState_cb_list[i].callback == NULL) { + connectionState_cb_list[i].callback = connectionStateCallback; + connectionState_cb_list[i].context = context; + return; + } + } + + PIOS_Assert(0); +} + +static void raiseConnectionStateCallback(bool connected) +{ + uint32_t i = 0; + + while (i < NELEMENTS(connectionState_cb_list) && connectionState_cb_list[i].callback != NULL) { + connectionState_cb_list[i].callback(connected, connectionState_cb_list[i].context); + i++; + } +} +#else /* PIOS_INCLUDE_FREERTOS */ +void PIOS_USB_RegisterConnectionStateCallback(__attribute__((unused)) void (*connectionStateCallback)(bool connected, uint32_t context), __attribute__((unused)) uint32_t context) +{} +#endif /* PIOS_INCLUDE_FREERTOS */ + #endif /* if defined(PIOS_INCLUDE_USB) */ /** diff --git a/flight/pios/stm32f30x/pios_usb_cdc.c b/flight/pios/stm32f30x/pios_usb_cdc.c index d96a67dc6f..186fb95b48 100644 --- a/flight/pios/stm32f30x/pios_usb_cdc.c +++ b/flight/pios/stm32f30x/pios_usb_cdc.c @@ -43,6 +43,8 @@ static void PIOS_USB_CDC_RegisterTxCallback(uint32_t usbcdc_id, pios_com_callback tx_out_cb, uint32_t context); static void PIOS_USB_CDC_RegisterRxCallback(uint32_t usbcdc_id, pios_com_callback rx_in_cb, uint32_t context); static void PIOS_USB_CDC_RegisterBaudRateCallback(uint32_t usbcdc_id, pios_com_callback_baud_rate baud_rate_cb, uint32_t context); +static void PIOS_USB_CDC_RegisterAvailableCallback(uint32_t usbcdc_id, pios_com_callback_available baud_rate_cb, uint32_t context); +static void PIOS_USB_CDC_ChangeConnectionState(bool connected, uint32_t usbcdc_id); static void PIOS_USB_CDC_TxStart(uint32_t usbcdc_id, uint16_t tx_bytes_avail); static void PIOS_USB_CDC_RxStart(uint32_t usbcdc_id, uint16_t rx_bytes_avail); static uint32_t PIOS_USB_CDC_Available(uint32_t usbcdc_id); @@ -54,6 +56,7 @@ const struct pios_com_driver pios_usb_cdc_com_driver = { .bind_rx_cb = PIOS_USB_CDC_RegisterRxCallback, .bind_baud_rate_cb = PIOS_USB_CDC_RegisterBaudRateCallback, .available = PIOS_USB_CDC_Available, + .bind_available_cb = PIOS_USB_CDC_RegisterAvailableCallback, }; enum pios_usb_cdc_dev_magic { @@ -73,6 +76,8 @@ struct pios_usb_cdc_dev { pios_com_callback_baud_rate baud_rate_cb; uint32_t baud_rate_context; + pios_com_callback_available available_cb; + uint32_t available_context; uint8_t rx_packet_buffer[PIOS_USB_BOARD_CDC_DATA_LENGTH]; /* @@ -158,6 +163,8 @@ int32_t PIOS_USB_CDC_Init(uint32_t *usbcdc_id, const struct pios_usb_cdc_cfg *cf pEpInt_IN[cfg->data_tx_ep - 1] = PIOS_USB_CDC_DATA_EP_IN_Callback; pEpInt_OUT[cfg->data_rx_ep - 1] = PIOS_USB_CDC_DATA_EP_OUT_Callback; + PIOS_USB_RegisterConnectionStateCallback(PIOS_USB_CDC_ChangeConnectionState, (uint32_t)usb_cdc_dev); + *usbcdc_id = (uint32_t)usb_cdc_dev; return 0; @@ -367,8 +374,7 @@ static uint32_t PIOS_USB_CDC_Available(uint32_t usbcdc_id) PIOS_Assert(valid); - return (PIOS_USB_CheckAvailable(usb_cdc_dev->lower_id) && - (control_line_state & USB_CDC_CONTROL_LINE_STATE_DTE_PRESENT)) ? COM_AVAILABLE_RXTX : COM_AVAILABLE_NONE; + return PIOS_USB_CheckAvailable(usb_cdc_dev->lower_id) ? COM_AVAILABLE_RXTX : COM_AVAILABLE_NONE; } static struct usb_cdc_line_coding line_coding = { @@ -488,5 +494,33 @@ void PIOS_USB_CDC_SetLineCoding_Completed() } } +static void PIOS_USB_CDC_ChangeConnectionState(__attribute__((unused)) bool connected, uint32_t usbcdc_id) +{ + struct pios_usb_cdc_dev *usb_cdc_dev = (struct pios_usb_cdc_dev *)usbcdc_id; + + bool valid = PIOS_USB_CDC_validate(usb_cdc_dev); + + PIOS_Assert(valid); + + if (usb_cdc_dev->available_cb) { + (usb_cdc_dev->available_cb)(usb_cdc_dev->available_context, PIOS_USB_CDC_Available(usbcdc_id)); + } +} + +static void PIOS_USB_CDC_RegisterAvailableCallback(uint32_t usbcdc_id, pios_com_callback_available available_cb, uint32_t context) +{ + struct pios_usb_cdc_dev *usb_cdc_dev = (struct pios_usb_cdc_dev *)usbcdc_id; + + bool valid = PIOS_USB_CDC_validate(usb_cdc_dev); + + PIOS_Assert(valid); + + /* + * Order is important in these assignments since ISR uses _cb + * field to determine if it's ok to dereference _cb and _context + */ + usb_cdc_dev->available_context = context; + usb_cdc_dev->available_cb = available_cb; +} #endif /* PIOS_INCLUDE_USB_CDC */ From 8ddd8a029efdffc4b6393a2e11e2ac3915150c9d Mon Sep 17 00:00:00 2001 From: Vladimir Zidar Date: Thu, 1 Jun 2017 18:10:08 +0200 Subject: [PATCH 303/624] LP-512 Cleaned up buzzer configuration and usage for boards with dedicated buzzer port. --- flight/libraries/notification.c | 33 ++++++++++++++++--- flight/pios/stm32f0x/pios_sys.c | 13 +++++--- flight/pios/stm32f10x/pios_sys.c | 13 +++++--- flight/pios/stm32f30x/pios_sys.c | 14 +++++--- flight/pios/stm32f4xx/pios_sys.c | 13 +++++--- flight/targets/boards/pikoblx/board_hw_defs.c | 2 +- flight/targets/boards/pikoblx/pios_board.h | 2 +- .../targets/boards/spracingf3/board_hw_defs.c | 14 +++++++- flight/targets/boards/spracingf3/pios_board.h | 1 + .../boards/spracingf3evo/board_hw_defs.c | 2 +- .../targets/boards/spracingf3evo/pios_board.h | 2 +- .../targets/boards/tinyfish/board_hw_defs.c | 2 +- .../boards/tinyfish/firmware/pios_board.c | 2 +- flight/targets/boards/tinyfish/pios_board.h | 2 +- 14 files changed, 85 insertions(+), 30 deletions(-) diff --git a/flight/libraries/notification.c b/flight/libraries/notification.c index f68504048e..b60fd4d8d0 100644 --- a/flight/libraries/notification.c +++ b/flight/libraries/notification.c @@ -42,6 +42,18 @@ #define ALARM_LED_OFF() #endif +#ifdef PIOS_BUZZER_ALARM +#define ALARM_BUZZER_ON() \ + { if (buzzer_enabled) { PIOS_LED_On(PIOS_BUZZER_ALARM); } \ + } +#define ALARM_BUZZER_OFF() \ + { if (buzzer_enabled) { PIOS_LED_Off(PIOS_BUZZER_ALARM); } \ + } +#else +#define ALARM_BUZZER_ON() +#define ALARM_BUZZER_OFF() +#endif + #ifdef PIOS_LED_HEARTBEAT #define HEARTBEAT_LED_ON() PIOS_LED_On(PIOS_LED_HEARTBEAT) #define HEARTBEAT_LED_OFF() PIOS_LED_Off(PIOS_LED_HEARTBEAT) @@ -135,9 +147,10 @@ static volatile FlightStatusData currentFlightStatus; static volatile bool started = false; static volatile pios_notify_notification nextNotification = NOTIFY_NONE; -#ifdef PIOS_LED_ALARM + +#if defined(PIOS_LED_ALARM) || defined(PIOS_BUZZER_ALARM) static bool handleAlarms(uint16_t *r_pattern, uint16_t *b_pattern); -#endif // PIOS_LED_ALARM +#endif // PIOS_LED_ALARM || PIOS_BUZZER_ALARM static bool handleNotifications(pios_notify_notification runningNotification, uint16_t *r_pattern, uint16_t *b_pattern); static void handleFlightMode(uint16_t *r_pattern, uint16_t *b_pattern); static void handleHeartbeat(uint16_t *r_pattern, uint16_t *b_pattern); @@ -163,6 +176,10 @@ void NotificationOnboardLedsRun() static uint8_t lastFlightMode = -1; static bool forceShowFlightMode = false; static pios_notify_notification runningNotification = NOTIFY_NONE; + +#ifdef PIOS_BUZZER_ALARM + static bool buzzer_enabled = false; +#endif static enum { STATUS_NOTIFY, STATUS_ALARM, @@ -206,6 +223,7 @@ void NotificationOnboardLedsRun() if (cycleCount & 0x10) { HEARTBEAT_LED_OFF(); ALARM_LED_OFF(); + ALARM_BUZZER_OFF(); cycleCount = 0x0; forceShowFlightMode = false; // Notification has been just shown, cleanup @@ -213,6 +231,9 @@ void NotificationOnboardLedsRun() runningNotification = NOTIFY_NONE; } status = (status + 1) % STATUS_LENGHT; +#ifdef PIOS_BUZZER_ALARM + buzzer_enabled = true; /* This is the place where we update buzzer_enabled status based on (not yet implemented) NotificationSettings.Buzzer config */ +#endif } if (status == STATUS_NOTIFY) { @@ -224,7 +245,7 @@ void NotificationOnboardLedsRun() // Handles Alarm display if (status == STATUS_ALARM) { -#ifdef PIOS_LED_ALARM +#if defined(PIOS_LED_ALARM) || defined(PIOS_BUZZER_ALARM) if (!cycleCount && !handleAlarms(&r_pattern, &b_pattern)) { // no alarms, advance status++; @@ -252,14 +273,16 @@ void NotificationOnboardLedsRun() } if (r_pattern & 0x1) { ALARM_LED_ON(); + ALARM_BUZZER_ON(); } else { ALARM_LED_OFF(); + ALARM_BUZZER_OFF(); } r_pattern >>= 1; b_pattern >>= 1; } -#if defined(PIOS_LED_ALARM) +#if defined(PIOS_LED_ALARM) || defined(PIOS_BUZZER_ALARM) static bool handleAlarms(uint16_t *r_pattern, uint16_t *b_pattern) { if (currentAlarmLevel == SYSTEMALARMS_ALARM_OK) { @@ -269,7 +292,7 @@ static bool handleAlarms(uint16_t *r_pattern, uint16_t *b_pattern) *r_pattern = BLINK_R_ALARM_PATTERN(currentAlarmLevel); return true; } -#endif /* PIOS_LED_ALARM */ +#endif /* PIOS_LED_ALARM || PIOS_BUZZER_ALARM */ static bool handleNotifications(pios_notify_notification runningNotification, uint16_t *r_pattern, uint16_t *b_pattern) diff --git a/flight/pios/stm32f0x/pios_sys.c b/flight/pios/stm32f0x/pios_sys.c index ab2aef92fc..aae1423025 100644 --- a/flight/pios/stm32f0x/pios_sys.c +++ b/flight/pios/stm32f0x/pios_sys.c @@ -124,12 +124,17 @@ int32_t PIOS_SYS_Reset(void) PIOS_IRQ_Disable(); // turn off all board LEDs -#if defined(PIOS_LED_HEARTBEAT) +#ifdef PIOS_INCLUDE_LED +# ifdef PIOS_LED_HEARTBEAT PIOS_LED_Off(PIOS_LED_HEARTBEAT); -#endif /* PIOS_LED_HEARTBEAT */ -#if defined(PIOS_LED_ALARM) +# endif /* PIOS_LED_HEARTBEAT */ +# ifdef PIOS_LED_ALARM PIOS_LED_Off(PIOS_LED_ALARM); -#endif /* PIOS_LED_ALARM */ +# endif /* PIOS_LED_ALARM */ +# ifdef PIOS_BUZZER_ALARM + PIOS_LED_Off(PIOS_BUZZER_ALARM); +# endif /* PIOS_BUZZER_ALARM */ +#endif /* PIOS_INCLUDE_LED */ /* Reset STM32 */ NVIC_SystemReset(); diff --git a/flight/pios/stm32f10x/pios_sys.c b/flight/pios/stm32f10x/pios_sys.c index 849bb83cdb..288fc0775b 100644 --- a/flight/pios/stm32f10x/pios_sys.c +++ b/flight/pios/stm32f10x/pios_sys.c @@ -97,12 +97,17 @@ int32_t PIOS_SYS_Reset(void) PIOS_IRQ_Disable(); // turn off all board LEDs -#if defined(PIOS_LED_HEARTBEAT) +#ifdef PIOS_INCLUDE_LED +# ifdef PIOS_LED_HEARTBEAT PIOS_LED_Off(PIOS_LED_HEARTBEAT); -#endif /* PIOS_LED_HEARTBEAT */ -#if defined(PIOS_LED_ALARM) +# endif /* PIOS_LED_HEARTBEAT */ +# ifdef PIOS_LED_ALARM PIOS_LED_Off(PIOS_LED_ALARM); -#endif /* PIOS_LED_ALARM */ +# endif /* PIOS_LED_ALARM */ +# ifdef PIOS_BUZZER_ALARM + PIOS_LED_Off(PIOS_BUZZER_ALARM); +# endif /* PIOS_BUZZER_ALARM */ +#endif /* PIOS_INCLUDE_LED */ RCC_APB2PeriphResetCmd(0xffffffff, DISABLE); RCC_APB1PeriphResetCmd(0xffffffff, DISABLE); diff --git a/flight/pios/stm32f30x/pios_sys.c b/flight/pios/stm32f30x/pios_sys.c index 45640400e0..6d849bc147 100644 --- a/flight/pios/stm32f30x/pios_sys.c +++ b/flight/pios/stm32f30x/pios_sys.c @@ -155,13 +155,17 @@ int32_t PIOS_SYS_Reset(void) PIOS_IRQ_Disable(); // turn off all board LEDs -#if defined(PIOS_INCLUDE_LED) && defined(PIOS_LED_HEARTBEAT) +#ifdef PIOS_INCLUDE_LED +# ifdef PIOS_LED_HEARTBEAT PIOS_LED_Off(PIOS_LED_HEARTBEAT); -#endif /* PIOS_LED_HEARTBEAT */ -#if defined(PIOS_INCLUDE_LED) && defined(PIOS_LED_ALARM) +# endif /* PIOS_LED_HEARTBEAT */ +# ifdef PIOS_LED_ALARM PIOS_LED_Off(PIOS_LED_ALARM); -#endif /* PIOS_LED_ALARM */ - +# endif /* PIOS_LED_ALARM */ +# ifdef PIOS_BUZZER_ALARM + PIOS_LED_Off(PIOS_BUZZER_ALARM); +# endif /* PIOS_BUZZER_ALARM */ +#endif /* PIOS_INCLUDE_LED */ /* XXX F10x port resets most (but not all) peripherals ... do we care? */ /* Reset STM32 */ diff --git a/flight/pios/stm32f4xx/pios_sys.c b/flight/pios/stm32f4xx/pios_sys.c index ab6759fe9e..c03297871c 100644 --- a/flight/pios/stm32f4xx/pios_sys.c +++ b/flight/pios/stm32f4xx/pios_sys.c @@ -204,12 +204,17 @@ int32_t PIOS_SYS_Reset(void) PIOS_IRQ_Disable(); // turn off all board LEDs -#if defined(PIOS_LED_HEARTBEAT) +#ifdef PIOS_INCLUDE_LED +# ifdef PIOS_LED_HEARTBEAT PIOS_LED_Off(PIOS_LED_HEARTBEAT); -#endif /* PIOS_LED_HEARTBEAT */ -#if defined(PIOS_LED_ALARM) +# endif /* PIOS_LED_HEARTBEAT */ +# ifdef PIOS_LED_ALARM PIOS_LED_Off(PIOS_LED_ALARM); -#endif /* PIOS_LED_ALARM */ +# endif /* PIOS_LED_ALARM */ +# ifdef PIOS_BUZZER_ALARM + PIOS_LED_Off(PIOS_BUZZER_ALARM); +# endif /* PIOS_BUZZER_ALARM */ +#endif /* PIOS_INCLUDE_LED */ /* XXX F10x port resets most (but not all) peripherals ... do we care? */ diff --git a/flight/targets/boards/pikoblx/board_hw_defs.c b/flight/targets/boards/pikoblx/board_hw_defs.c index 1330070fd3..159c930347 100644 --- a/flight/targets/boards/pikoblx/board_hw_defs.c +++ b/flight/targets/boards/pikoblx/board_hw_defs.c @@ -53,7 +53,7 @@ static const struct pios_gpio pios_leds[] = { }, .active_low = true }, - [PIOS_LED_BUZZER] = { /* not really LED, but buzzer! */ + [PIOS_BUZZER_ALARM] = { .pin = { .gpio = GPIOA, .init = { diff --git a/flight/targets/boards/pikoblx/pios_board.h b/flight/targets/boards/pikoblx/pios_board.h index dcc6a06a4c..f3654b0b08 100644 --- a/flight/targets/boards/pikoblx/pios_board.h +++ b/flight/targets/boards/pikoblx/pios_board.h @@ -86,7 +86,7 @@ // ------------------------ #define PIOS_LED_HEARTBEAT 0 #define PIOS_LED_ALARM 1 -#define PIOS_LED_BUZZER 2 +#define PIOS_BUZZER_ALARM 2 // ------------------------- // System Settings diff --git a/flight/targets/boards/spracingf3/board_hw_defs.c b/flight/targets/boards/spracingf3/board_hw_defs.c index b6d1fd39a9..5febf939df 100644 --- a/flight/targets/boards/spracingf3/board_hw_defs.c +++ b/flight/targets/boards/spracingf3/board_hw_defs.c @@ -44,7 +44,19 @@ static const struct pios_gpio pios_leds[] = { .GPIO_PuPd = GPIO_PuPd_NOPULL, }, }, -// .remap = GPIO_Remap_SWJ_JTAGDisable, + .active_low = false + }, + [PIOS_BUZZER_ALARM] = { + .pin = { + .gpio = GPIOC, + .init = { + .GPIO_Pin = GPIO_Pin_15, + .GPIO_Mode = GPIO_Mode_OUT, + .GPIO_OType = GPIO_OType_PP, + .GPIO_Speed = GPIO_Speed_50MHz, + .GPIO_PuPd = GPIO_PuPd_NOPULL, + }, + }, .active_low = false }, }; diff --git a/flight/targets/boards/spracingf3/pios_board.h b/flight/targets/boards/spracingf3/pios_board.h index 2e91027785..9f3fb62538 100644 --- a/flight/targets/boards/spracingf3/pios_board.h +++ b/flight/targets/boards/spracingf3/pios_board.h @@ -84,6 +84,7 @@ // PIOS_LED // ------------------------ #define PIOS_LED_HEARTBEAT 0 +#define PIOS_BUZZER_ALARM 1 // ------------------------- // System Settings diff --git a/flight/targets/boards/spracingf3evo/board_hw_defs.c b/flight/targets/boards/spracingf3evo/board_hw_defs.c index 1a31665182..2e4d75b4a4 100644 --- a/flight/targets/boards/spracingf3evo/board_hw_defs.c +++ b/flight/targets/boards/spracingf3evo/board_hw_defs.c @@ -44,7 +44,7 @@ static const struct pios_gpio pios_leds[] = { }, .active_low = true }, - [PIOS_LED_ALARM] = { /* not really LED, but buzzer! */ + [PIOS_BUZZER_ALARM] = { .pin = { .gpio = GPIOC, .init = { diff --git a/flight/targets/boards/spracingf3evo/pios_board.h b/flight/targets/boards/spracingf3evo/pios_board.h index 887ed20735..629b33783c 100644 --- a/flight/targets/boards/spracingf3evo/pios_board.h +++ b/flight/targets/boards/spracingf3evo/pios_board.h @@ -85,7 +85,7 @@ // PIOS_LED // ------------------------ #define PIOS_LED_HEARTBEAT 0 -#define PIOS_LED_ALARM 1 +#define PIOS_BUZZER_ALARM 1 // ------------------------- // System Settings diff --git a/flight/targets/boards/tinyfish/board_hw_defs.c b/flight/targets/boards/tinyfish/board_hw_defs.c index 197b153a9f..6f1ef54677 100644 --- a/flight/targets/boards/tinyfish/board_hw_defs.c +++ b/flight/targets/boards/tinyfish/board_hw_defs.c @@ -53,7 +53,7 @@ static const struct pios_gpio pios_leds[] = { }, .active_low = false }, - [PIOS_LED_BUZZER] = { /* not really LED, but buzzer! (or PB2 ??) */ + [PIOS_BUZZER_ALARM] = { /* (or PB2 ??) */ .pin = { .gpio = GPIOC, .init = { diff --git a/flight/targets/boards/tinyfish/firmware/pios_board.c b/flight/targets/boards/tinyfish/firmware/pios_board.c index b6fbd02e79..7ced0a9c10 100644 --- a/flight/targets/boards/tinyfish/firmware/pios_board.c +++ b/flight/targets/boards/tinyfish/firmware/pios_board.c @@ -63,7 +63,7 @@ uintptr_t pios_user_fs_id = 0; uint32_t pios_ws2811_id; #endif -void FlightBatterySettingsDataOverrideDefaults(FlightBatterySettingsData * data) +void FlightBatterySettingsDataOverrideDefaults(FlightBatterySettingsData *data) { data->SensorCalibrations.VoltageFactor = 8.8f; data->SensorCalibrations.CurrentFactor = 0.07f; diff --git a/flight/targets/boards/tinyfish/pios_board.h b/flight/targets/boards/tinyfish/pios_board.h index 2fe545f26e..45e4f69e4b 100644 --- a/flight/targets/boards/tinyfish/pios_board.h +++ b/flight/targets/boards/tinyfish/pios_board.h @@ -58,7 +58,7 @@ // ------------------------ #define PIOS_LED_HEARTBEAT 0 #define PIOS_LED_ALARM 1 -#define PIOS_LED_BUZZER 2 +#define PIOS_BUZZER_ALARM 2 // ------------------------- // System Settings From 61e036d6d3bd2c4ce6c932caa9f521b09201fe35 Mon Sep 17 00:00:00 2001 From: Vladimir Zidar Date: Thu, 1 Jun 2017 19:06:01 +0200 Subject: [PATCH 304/624] LP-512 Cleaned up Hw(board)Settings for F3 boards. Removed unneeded stuff. --- .../boards/nucleof303re/firmware/pios_board.c | 18 ++---------------- .../boards/pikoblx/firmware/pios_board.c | 13 ++----------- .../boards/spracingf3/firmware/pios_board.c | 16 ++-------------- .../boards/spracingf3evo/firmware/pios_board.c | 16 ++-------------- .../boards/tinyfish/firmware/pios_board.c | 6 +----- .../uavobjectdefinition/hwpikoblxsettings.xml | 4 +--- .../hwspracingf3evosettings.xml | 4 +--- .../hwspracingf3settings.xml | 4 +--- .../uavobjectdefinition/hwtinyfishsettings.xml | 3 +-- 9 files changed, 13 insertions(+), 71 deletions(-) diff --git a/flight/targets/boards/nucleof303re/firmware/pios_board.c b/flight/targets/boards/nucleof303re/firmware/pios_board.c index f155a5c11b..39a4787da1 100644 --- a/flight/targets/boards/nucleof303re/firmware/pios_board.c +++ b/flight/targets/boards/nucleof303re/firmware/pios_board.c @@ -227,35 +227,21 @@ void PIOS_Board_Init(void) #endif switch (boardHwSettings.LEDPort) { - case HWSPRACINGF3EVOSETTINGS_LEDPORT_WS2811: + case HWSPRACINGF3EVOSETTINGS_LEDPORT_WS281X: #if defined(PIOS_INCLUDE_WS2811) PIOS_WS2811_Init(&pios_ws2811_id, &pios_ws2811_cfg); #endif break; - case HWSPRACINGF3EVOSETTINGS_LEDPORT_OUTPUT: + default: break; - default:; - } - - if (boardHwSettings.BuzzerPort == HWSPRACINGF3EVOSETTINGS_BUZZERPORT_OUTPUT) { - // enable buzzer somehow - } - - switch (boardHwSettings.SonarPort) { - case HWSPRACINGF3EVOSETTINGS_SONARPORT_HCSR04: - /* enable hcsr04 sonar on this port */ - break; - default:; } #if defined(PIOS_INCLUDE_I2C) - // init I2C1 for use with the internal baro if (PIOS_I2C_Init(&pios_i2c_id, &pios_i2c_cfg)) { PIOS_DEBUG_Assert(0); } PIOS_DELAY_WaitmS(50); - #endif PIOS_BOARD_Sensors_Configure(); diff --git a/flight/targets/boards/pikoblx/firmware/pios_board.c b/flight/targets/boards/pikoblx/firmware/pios_board.c index b9b81f5f20..f52c3a1070 100644 --- a/flight/targets/boards/pikoblx/firmware/pios_board.c +++ b/flight/targets/boards/pikoblx/firmware/pios_board.c @@ -233,22 +233,13 @@ void PIOS_Board_Init(void) #endif switch (boardHwSettings.LEDPort) { - case HWPIKOBLXSETTINGS_LEDPORT_WS2811: + case HWPIKOBLXSETTINGS_LEDPORT_WS281X: #if defined(PIOS_INCLUDE_WS2811) PIOS_WS2811_Init(&pios_ws2811_id, &pios_ws2811_cfg); #endif break; - case HWPIKOBLXSETTINGS_LEDPORT_OUTPUT: + default: break; - default:; - } - - if (boardHwSettings.BuzzerPort == HWPIKOBLXSETTINGS_BUZZERPORT_ENABLED) { - // enable buzzer somehow - } - - if (boardHwSettings.TransponderPort == HWPIKOBLXSETTINGS_TRANSPONDERPORT_ENABLED) { - // enable transponder somethow } diff --git a/flight/targets/boards/spracingf3/firmware/pios_board.c b/flight/targets/boards/spracingf3/firmware/pios_board.c index 7c10710311..3833aa96c6 100644 --- a/flight/targets/boards/spracingf3/firmware/pios_board.c +++ b/flight/targets/boards/spracingf3/firmware/pios_board.c @@ -247,25 +247,13 @@ void PIOS_Board_Init(void) #endif switch (boardHwSettings.LEDPort) { - case HWSPRACINGF3SETTINGS_LEDPORT_WS2811: + case HWSPRACINGF3SETTINGS_LEDPORT_WS281X: #if defined(PIOS_INCLUDE_WS2811) PIOS_WS2811_Init(&pios_ws2811_id, &pios_ws2811_cfg); #endif break; - case HWSPRACINGF3SETTINGS_LEDPORT_OUTPUT: + default: break; - default:; - } - - if (boardHwSettings.BuzzerPort == HWSPRACINGF3SETTINGS_BUZZERPORT_OUTPUT) { - // enable buzzer somehow - } - - switch (boardHwSettings.SonarPort) { - case HWSPRACINGF3SETTINGS_SONARPORT_HCSR04: - /* enable hcsr04 sonar on this port */ - break; - default:; } #if defined(PIOS_INCLUDE_I2C) diff --git a/flight/targets/boards/spracingf3evo/firmware/pios_board.c b/flight/targets/boards/spracingf3evo/firmware/pios_board.c index b58dc341e8..a9e5a7cdb2 100644 --- a/flight/targets/boards/spracingf3evo/firmware/pios_board.c +++ b/flight/targets/boards/spracingf3evo/firmware/pios_board.c @@ -234,25 +234,13 @@ void PIOS_Board_Init(void) #endif switch (boardHwSettings.LEDPort) { - case HWSPRACINGF3EVOSETTINGS_LEDPORT_WS2811: + case HWSPRACINGF3EVOSETTINGS_LEDPORT_WS281X: #if defined(PIOS_INCLUDE_WS2811) PIOS_WS2811_Init(&pios_ws2811_id, &pios_ws2811_cfg); #endif break; - case HWSPRACINGF3EVOSETTINGS_LEDPORT_OUTPUT: + default: break; - default:; - } - - if (boardHwSettings.BuzzerPort == HWSPRACINGF3EVOSETTINGS_BUZZERPORT_OUTPUT) { - // enable buzzer somehow - } - - switch (boardHwSettings.SonarPort) { - case HWSPRACINGF3EVOSETTINGS_SONARPORT_HCSR04: - /* enable hcsr04 sonar on this port */ - break; - default:; } #if defined(PIOS_INCLUDE_I2C) diff --git a/flight/targets/boards/tinyfish/firmware/pios_board.c b/flight/targets/boards/tinyfish/firmware/pios_board.c index 7ced0a9c10..8e32b2a9b1 100644 --- a/flight/targets/boards/tinyfish/firmware/pios_board.c +++ b/flight/targets/boards/tinyfish/firmware/pios_board.c @@ -265,7 +265,7 @@ void PIOS_Board_Init(void) #endif /* PIOS_ENABLE_DEBUG_PINS */ switch (boardHwSettings.LEDPort) { - case HWTINYFISHSETTINGS_LEDPORT_WS2811: + case HWTINYFISHSETTINGS_LEDPORT_WS281X: #if defined(PIOS_INCLUDE_WS2811) PIOS_WS2811_Init(&pios_ws2811_id, &pios_ws2811_cfg); #endif @@ -274,10 +274,6 @@ void PIOS_Board_Init(void) break; } - if (boardHwSettings.BuzzerPort == HWTINYFISHSETTINGS_BUZZERPORT_ENABLED) { - // enable buzzer somehow - } - PIOS_BOARD_Sensors_Configure(); PIOS_LED_On(PIOS_LED_HEARTBEAT); diff --git a/shared/uavobjectdefinition/hwpikoblxsettings.xml b/shared/uavobjectdefinition/hwpikoblxsettings.xml index 0112cb1171..b5b8132961 100644 --- a/shared/uavobjectdefinition/hwpikoblxsettings.xml +++ b/shared/uavobjectdefinition/hwpikoblxsettings.xml @@ -2,9 +2,7 @@ Furious FPV Piko BLX Micro Flight Controller hardware configuration - - - + diff --git a/shared/uavobjectdefinition/hwspracingf3evosettings.xml b/shared/uavobjectdefinition/hwspracingf3evosettings.xml index dc48a077e1..9a90b452e6 100644 --- a/shared/uavobjectdefinition/hwspracingf3evosettings.xml +++ b/shared/uavobjectdefinition/hwspracingf3evosettings.xml @@ -3,9 +3,7 @@ Seriously Pro SPRacingF3 EVO hardware configuration. - - - + diff --git a/shared/uavobjectdefinition/hwspracingf3settings.xml b/shared/uavobjectdefinition/hwspracingf3settings.xml index 1c3d1b4cad..3e8871f4b3 100644 --- a/shared/uavobjectdefinition/hwspracingf3settings.xml +++ b/shared/uavobjectdefinition/hwspracingf3settings.xml @@ -3,9 +3,7 @@ Seriously Pro SPRacingF3 hardware configuration. - - - + diff --git a/shared/uavobjectdefinition/hwtinyfishsettings.xml b/shared/uavobjectdefinition/hwtinyfishsettings.xml index cc91c237da..0b620a52c7 100644 --- a/shared/uavobjectdefinition/hwtinyfishsettings.xml +++ b/shared/uavobjectdefinition/hwtinyfishsettings.xml @@ -3,8 +3,7 @@ fishpepper.de tinyFISH Flight Controller hardware configuration - - + From e44114d7940bcf985fbb1dd0ee4342bf1b767d14 Mon Sep 17 00:00:00 2001 From: Vladimir Zidar Date: Thu, 1 Jun 2017 22:12:31 +0200 Subject: [PATCH 305/624] LP-512 Uncrustify --- flight/targets/boards/pikoblx/firmware/pios_board.c | 2 +- flight/targets/boards/tinyfish/firmware/pios_board.c | 2 +- ground/gcs/src/plugins/setupwizard/pages/controllerpage.cpp | 2 +- ground/gcs/src/plugins/uavobjectutil/devicedescriptorstruct.h | 2 +- ground/gcs/src/plugins/uploader/devicewidget.cpp | 2 +- ground/gcs/src/plugins/uploader/runningdevicewidget.cpp | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/flight/targets/boards/pikoblx/firmware/pios_board.c b/flight/targets/boards/pikoblx/firmware/pios_board.c index f52c3a1070..9aa8b0c2f5 100644 --- a/flight/targets/boards/pikoblx/firmware/pios_board.c +++ b/flight/targets/boards/pikoblx/firmware/pios_board.c @@ -62,7 +62,7 @@ uintptr_t pios_user_fs_id = 0; uint32_t pios_ws2811_id; #endif -void RevoSettingsDataOverrideDefaults(RevoSettingsData * data) +void RevoSettingsDataOverrideDefaults(RevoSettingsData *data) { /* This board has no barometer, so adjust default fusion algorithm to one that does not depend on working baro */ data->FusionAlgorithm = REVOSETTINGS_FUSIONALGORITHM_ACRONOSENSORS; diff --git a/flight/targets/boards/tinyfish/firmware/pios_board.c b/flight/targets/boards/tinyfish/firmware/pios_board.c index 8e32b2a9b1..9abcb96245 100644 --- a/flight/targets/boards/tinyfish/firmware/pios_board.c +++ b/flight/targets/boards/tinyfish/firmware/pios_board.c @@ -69,7 +69,7 @@ void FlightBatterySettingsDataOverrideDefaults(FlightBatterySettingsData *data) data->SensorCalibrations.CurrentFactor = 0.07f; } -void RevoSettingsDataOverrideDefaults(RevoSettingsData * data) +void RevoSettingsDataOverrideDefaults(RevoSettingsData *data) { /* This board has no barometer, so adjust default fusion algorithm to one that does not depend on working baro */ data->FusionAlgorithm = REVOSETTINGS_FUSIONALGORITHM_ACRONOSENSORS; diff --git a/ground/gcs/src/plugins/setupwizard/pages/controllerpage.cpp b/ground/gcs/src/plugins/setupwizard/pages/controllerpage.cpp index 9a71ad593b..b9bd058ebb 100644 --- a/ground/gcs/src/plugins/setupwizard/pages/controllerpage.cpp +++ b/ground/gcs/src/plugins/setupwizard/pages/controllerpage.cpp @@ -128,7 +128,7 @@ SetupWizard::CONTROLLER_TYPE ControllerPage::getControllerType() case 0x1005: return SetupWizard::CONTROLLER_PIKOBLX; - + case 0x1006: return SetupWizard::CONTROLLER_TINYFISH; diff --git a/ground/gcs/src/plugins/uavobjectutil/devicedescriptorstruct.h b/ground/gcs/src/plugins/uavobjectutil/devicedescriptorstruct.h index b8d656b490..8dd9f8d9ce 100644 --- a/ground/gcs/src/plugins/uavobjectutil/devicedescriptorstruct.h +++ b/ground/gcs/src/plugins/uavobjectutil/devicedescriptorstruct.h @@ -74,7 +74,7 @@ struct deviceDescriptorStruct { case 0x1005: return QString("PikoBLX"); - + case 0x1006: return QString("tinyFISH"); diff --git a/ground/gcs/src/plugins/uploader/devicewidget.cpp b/ground/gcs/src/plugins/uploader/devicewidget.cpp index 4d531960e6..e207f49401 100644 --- a/ground/gcs/src/plugins/uploader/devicewidget.cpp +++ b/ground/gcs/src/plugins/uploader/devicewidget.cpp @@ -126,7 +126,7 @@ void DeviceWidget::populate() devicePic.load(":/uploader/images/gcs-board-spracingf3.png"); break; case 0x1003: - // Nucleo F303RE + // Nucleo F303RE case 0x1002: // SPRacingF3 EVO devicePic.load(":/uploader/images/gcs-board-spracingf3evo.png"); diff --git a/ground/gcs/src/plugins/uploader/runningdevicewidget.cpp b/ground/gcs/src/plugins/uploader/runningdevicewidget.cpp index cc34fcd0f9..58372ed183 100644 --- a/ground/gcs/src/plugins/uploader/runningdevicewidget.cpp +++ b/ground/gcs/src/plugins/uploader/runningdevicewidget.cpp @@ -106,7 +106,7 @@ void RunningDeviceWidget::populate() devicePic.load(":/uploader/images/gcs-board-spracingf3.png"); break; case 0x1003: - // Nucleo F303RE + // Nucleo F303RE case 0x1002: // SPRacingF3 EVO devicePic.load(":/uploader/images/gcs-board-spracingf3evo.png"); From d198b7c70a38c4f482092216265933260d870625 Mon Sep 17 00:00:00 2001 From: Vladimir Zidar Date: Fri, 2 Jun 2017 10:55:42 +0200 Subject: [PATCH 306/624] LP-512 Fixed PikoBLX mpu6000 orientation. --- flight/targets/boards/pikoblx/board_hw_defs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flight/targets/boards/pikoblx/board_hw_defs.c b/flight/targets/boards/pikoblx/board_hw_defs.c index 159c930347..84b330d11f 100644 --- a/flight/targets/boards/pikoblx/board_hw_defs.c +++ b/flight/targets/boards/pikoblx/board_hw_defs.c @@ -546,7 +546,7 @@ static const struct pios_mpu6000_cfg pios_mpu6000_cfg = { .accel_range = PIOS_MPU6000_ACCEL_8G, .gyro_range = PIOS_MPU6000_SCALE_2000_DEG, .filter = PIOS_MPU6000_LOWPASS_256_HZ, - .orientation = PIOS_MPU6000_TOP_180DEG, + .orientation = PIOS_MPU6000_TOP_270DEG, #ifdef PIOS_INCLUDE_SPI .fast_prescaler = PIOS_SPI_PRESCALER_4, .std_prescaler = PIOS_SPI_PRESCALER_64, From aadd17d1b47e07daa6406819a1afcafbcc66ef4c Mon Sep 17 00:00:00 2001 From: Vladimir Zidar Date: Sun, 4 Jun 2017 22:38:34 +0200 Subject: [PATCH 307/624] LP-527 Remove peripheral clock managing code --- flight/pios/stm32f0x/pios_adc.c | 3 -- flight/pios/stm32f0x/pios_bkp.c | 6 ---- flight/pios/stm32f0x/pios_bl_helper.c | 4 +-- flight/pios/stm32f0x/pios_delay.c | 4 +-- flight/pios/stm32f0x/pios_gpio.c | 16 ---------- flight/pios/stm32f0x/pios_i2c.c | 4 --- flight/pios/stm32f0x/pios_rtc.c | 1 - flight/pios/stm32f0x/pios_spi.c | 16 +--------- flight/pios/stm32f0x/pios_sys.c | 19 ++++++++++- flight/pios/stm32f0x/pios_tim.c | 45 --------------------------- flight/pios/stm32f0x/pios_usart.c | 3 -- flight/pios/stm32f0x/pios_wdg.c | 1 - 12 files changed, 22 insertions(+), 100 deletions(-) diff --git a/flight/pios/stm32f0x/pios_adc.c b/flight/pios/stm32f0x/pios_adc.c index 3f57014491..1c33422a1e 100644 --- a/flight/pios/stm32f0x/pios_adc.c +++ b/flight/pios/stm32f0x/pios_adc.c @@ -244,9 +244,6 @@ void PIOS_ADC_Config(uint32_t oversampling) pios_adc_dev->fir_coeffs[i] = 1; } pios_adc_dev->fir_coeffs[pios_adc_dev->adc_oversample] = pios_adc_dev->adc_oversample; - - /* Enable DMA1 clock */ - RCC_AHBPeriphClockCmd(pios_adc_dev->cfg->dma.ahb_clk, ENABLE); } /** diff --git a/flight/pios/stm32f0x/pios_bkp.c b/flight/pios/stm32f0x/pios_bkp.c index d15063ff89..a20a199bdc 100644 --- a/flight/pios/stm32f0x/pios_bkp.c +++ b/flight/pios/stm32f0x/pios_bkp.c @@ -57,12 +57,6 @@ const uint32_t pios_bkp_registers_map[] = { void PIOS_BKP_Init(void) { - /* Enable CRC clock */ - RCC_AHBPeriphClockCmd(RCC_AHBPeriph_CRC, ENABLE); - - /* Enable PWR and BKP clock */ - RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE); - /* Clear Tamper pin Event(TE) pending flag */ RTC_ClearFlag(RTC_FLAG_TAMP1F | RTC_FLAG_TAMP2F); } diff --git a/flight/pios/stm32f0x/pios_bl_helper.c b/flight/pios/stm32f0x/pios_bl_helper.c index af96880e4f..7552681911 100644 --- a/flight/pios/stm32f0x/pios_bl_helper.c +++ b/flight/pios/stm32f0x/pios_bl_helper.c @@ -119,8 +119,6 @@ void PIOS_BL_HELPER_FLASH_Read_Description(uint8_t *array, uint8_t size) } void PIOS_BL_HELPER_CRC_Ini() -{ - RCC_AHBPeriphClockCmd(RCC_AHBPeriph_CRC, ENABLE); -} +{} #endif /* PIOS_INCLUDE_BL_HELPER */ diff --git a/flight/pios/stm32f0x/pios_delay.c b/flight/pios/stm32f0x/pios_delay.c index 1a27f182da..90ae0975b4 100644 --- a/flight/pios/stm32f0x/pios_delay.c +++ b/flight/pios/stm32f0x/pios_delay.c @@ -47,8 +47,7 @@ int32_t PIOS_DELAY_Init(void) { // unfortunately F0 does not allow access to DWT and CoreDebug functionality from CPU side - // thus we are going to use timer3 for timing measurement - RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); + // thus we are going to use timer2 for timing measurement const TIM_TimeBaseInitTypeDef timerInit = { .TIM_Prescaler = (48000000 / 1000000), @@ -57,6 +56,7 @@ int32_t PIOS_DELAY_Init(void) .TIM_Period = 0xFFFFFFFF, .TIM_RepetitionCounter = 0x0000, }; + // Stop timer TIM_Cmd(TIM2, DISABLE); // Configure timebase and internal clock diff --git a/flight/pios/stm32f0x/pios_gpio.c b/flight/pios/stm32f0x/pios_gpio.c index 17830d2cdb..eb42c9711d 100644 --- a/flight/pios/stm32f0x/pios_gpio.c +++ b/flight/pios/stm32f0x/pios_gpio.c @@ -45,22 +45,6 @@ int32_t PIOS_GPIO_Init(uint32_t *gpios_dev_id, const struct pios_gpio_cfg *cfg) for (uint8_t i = 0; i < cfg->num_gpios; i++) { const struct pios_gpio *gpio = &(cfg->gpios[i]); - /* Enable the peripheral clock for the GPIO */ - switch ((uint32_t)gpio->pin.gpio) { - case (uint32_t)GPIOA: - RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE); - break; - case (uint32_t)GPIOB: - RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE); - break; - case (uint32_t)GPIOC: - RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE); - break; - default: - PIOS_Assert(0); - break; - } - if (gpio->remap) { GPIO_PinAFConfig(gpio->pin.gpio, gpio->pin.init.GPIO_Pin, gpio->remap); } diff --git a/flight/pios/stm32f0x/pios_i2c.c b/flight/pios/stm32f0x/pios_i2c.c index 385c5295e1..80299e32de 100644 --- a/flight/pios/stm32f0x/pios_i2c.c +++ b/flight/pios/stm32f0x/pios_i2c.c @@ -541,13 +541,9 @@ int32_t PIOS_I2C_Init(uint32_t *i2c_id, const struct pios_i2c_adapter_cfg *cfg) /* Enable the associated peripheral clock */ switch ((uint32_t)i2c_adapter->cfg->regs) { case (uint32_t)I2C1: - /* Enable I2C peripheral clock (APB1 == slow speed) */ - RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE); RCC_I2CCLKConfig(RCC_I2C1CLK_HSI); break; case (uint32_t)I2C2: - /* Enable I2C peripheral clock (APB1 == slow speed) */ - RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE); break; } diff --git a/flight/pios/stm32f0x/pios_rtc.c b/flight/pios/stm32f0x/pios_rtc.c index 8fe758145e..bfa5670216 100644 --- a/flight/pios/stm32f0x/pios_rtc.c +++ b/flight/pios/stm32f0x/pios_rtc.c @@ -51,7 +51,6 @@ void PIOS_RTC_Init(const struct pios_rtc_cfg *cfg) { RCC_BackupResetCmd(ENABLE); RCC_BackupResetCmd(DISABLE); - RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE); PWR_BackupAccessCmd(ENABLE); // Divide external 8 MHz clock to 1 MHz RCC_RTCCLKConfig(cfg->clksrc); diff --git a/flight/pios/stm32f0x/pios_spi.c b/flight/pios/stm32f0x/pios_spi.c index 5758ce7429..f408ab7980 100644 --- a/flight/pios/stm32f0x/pios_spi.c +++ b/flight/pios/stm32f0x/pios_spi.c @@ -91,22 +91,8 @@ int32_t PIOS_SPI_Init(uint32_t *spi_id, const struct pios_spi_cfg *cfg) vSemaphoreCreateBinary(spi_dev->busy); xSemaphoreGive(spi_dev->busy); #else - spi_dev->busy = 0; + spi_dev->busy = 0; #endif - /* Enable the associated peripheral clock */ - switch ((uint32_t)spi_dev->cfg->regs) { - case (uint32_t)SPI1: - /* Enable SPI peripheral clock (APB2 == high speed) */ - RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE); - break; - case (uint32_t)SPI2: - /* Enable SPI peripheral clock (APB1 == slow speed) */ - RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE); - break; - } - /* Enable DMA clock */ - RCC_AHBPeriphClockCmd(spi_dev->cfg->dma.ahb_clk, ENABLE); - /* Disable callback function */ spi_dev->callback = NULL; diff --git a/flight/pios/stm32f0x/pios_sys.c b/flight/pios/stm32f0x/pios_sys.c index aae1423025..275b6cc023 100644 --- a/flight/pios/stm32f0x/pios_sys.c +++ b/flight/pios/stm32f0x/pios_sys.c @@ -72,13 +72,30 @@ void PIOS_SYS_Init(void) RCC_AHBPeriphClockCmd( RCC_AHBPeriph_GPIOA | RCC_AHBPeriph_GPIOB | + RCC_AHBPeriph_GPIOC | RCC_AHBPeriph_FLITF | RCC_AHBPeriph_SRAM | - RCC_AHBPeriph_DMA1 + RCC_AHBPeriph_DMA1 | + RCC_AHBPeriph_CRC + , ENABLE); + + RCC_APB1PeriphClockCmd( + RCC_APB1Periph_USART2 | + RCC_APB1Periph_USART3 | + RCC_APB1Periph_WWDG | + RCC_APB1Periph_PWR | + RCC_APB1Periph_TIM2 | + RCC_APB1Periph_TIM3 | + RCC_APB1Periph_I2C1 | + RCC_APB1Periph_I2C2 | + RCC_APB1Periph_SPI2 , ENABLE); RCC_APB2PeriphClockCmd( RCC_APB2Periph_SYSCFG | + RCC_APB2Periph_USART1 | + RCC_APB2Periph_SPI1 | + RCC_APB2Periph_TIM1 | 0, ENABLE); /* diff --git a/flight/pios/stm32f0x/pios_tim.c b/flight/pios/stm32f0x/pios_tim.c index a519240ee0..7a9b649c84 100644 --- a/flight/pios/stm32f0x/pios_tim.c +++ b/flight/pios/stm32f0x/pios_tim.c @@ -61,36 +61,6 @@ int32_t PIOS_TIM_InitClock(const struct pios_tim_clock_cfg *cfg) { PIOS_DEBUG_Assert(cfg); - /* Enable appropriate clock to timer module */ - switch ((uint32_t)cfg->timer) { - case (uint32_t)TIM1: - RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE); - break; - case (uint32_t)TIM2: - RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); - break; - case (uint32_t)TIM3: - RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); - break; - case (uint32_t)TIM4: - RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); - break; -#ifdef STM32F10X_HD - case (uint32_t)TIM5: - RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE); - break; - case (uint32_t)TIM6: - RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE); - break; - case (uint32_t)TIM7: - RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7, ENABLE); - break; - case (uint32_t)TIM8: - RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8, ENABLE); - break; -#endif - } - /* Configure the dividers for this timer */ TIM_TimeBaseInit(cfg->timer, cfg->time_base_init); @@ -127,21 +97,6 @@ int32_t PIOS_TIM_InitChannels(uint32_t *tim_id, const struct pios_tim_channel *c for (uint8_t i = 0; i < num_channels; i++) { const struct pios_tim_channel *chan = &(channels[i]); - /* Enable the peripheral clock for the GPIO */ - switch ((uint32_t)chan->pin.gpio) { - case (uint32_t)GPIOA: - RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); - break; - case (uint32_t)GPIOB: - RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); - break; - case (uint32_t)GPIOC: - RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); - break; - default: - PIOS_Assert(0); - break; - } GPIO_Init(chan->pin.gpio, &chan->pin.init); if (chan->remap) { diff --git a/flight/pios/stm32f0x/pios_usart.c b/flight/pios/stm32f0x/pios_usart.c index 3547c29fce..6154341c39 100644 --- a/flight/pios/stm32f0x/pios_usart.c +++ b/flight/pios/stm32f0x/pios_usart.c @@ -179,18 +179,15 @@ int32_t PIOS_USART_Init(uint32_t *usart_id, const struct pios_usart_cfg *cfg) /* Enable USART clock */ switch ((uint32_t)cfg->regs) { case (uint32_t)USART1: - RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); local_id = &PIOS_USART_1_id; irq_channel = USART1_IRQn; break; case (uint32_t)USART2: - RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); local_id = &PIOS_USART_2_id; irq_channel = USART2_IRQn; break; #if defined(STM32F072) case (uint32_t)USART3: - RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE); local_id = &PIOS_USART_3_id; irq_channel = USART3_4_IRQn; break; diff --git a/flight/pios/stm32f0x/pios_wdg.c b/flight/pios/stm32f0x/pios_wdg.c index f87af420db..ef51e28e83 100644 --- a/flight/pios/stm32f0x/pios_wdg.c +++ b/flight/pios/stm32f0x/pios_wdg.c @@ -70,7 +70,6 @@ uint16_t PIOS_WDG_Init() delay = 0x0fff; } #if defined(PIOS_INCLUDE_WDG) - RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE); DBGMCU_APB1PeriphConfig(DBGMCU_IWDG_STOP, ENABLE); // make the watchdog stop counting in debug mode IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable); IWDG_SetPrescaler(IWDG_Prescaler_32); From d991607aa5f9539d7dd150316b65fa4797b0da5c Mon Sep 17 00:00:00 2001 From: Vladimir Zidar Date: Mon, 5 Jun 2017 01:09:52 +0200 Subject: [PATCH 308/624] LP-527 Move PIOS_DELAY_Init() after the peripheral clocks have been started. F0 uses TIM2 for delays. --- flight/pios/stm32f0x/pios_sys.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flight/pios/stm32f0x/pios_sys.c b/flight/pios/stm32f0x/pios_sys.c index 275b6cc023..c4a774e06c 100644 --- a/flight/pios/stm32f0x/pios_sys.c +++ b/flight/pios/stm32f0x/pios_sys.c @@ -61,9 +61,6 @@ void PIOS_SYS_Init(void) /* do this early to ensure that we take exceptions in the right place */ NVIC_Configuration(); - /* Init the delay system */ - PIOS_DELAY_Init(); - /* * Turn on all the peripheral clocks. * Micromanaging clocks makes no sense given the power situation in the system, so @@ -98,6 +95,9 @@ void PIOS_SYS_Init(void) RCC_APB2Periph_TIM1 | 0, ENABLE); + /* Init the delay system */ + PIOS_DELAY_Init(); + /* * Configure all pins as input / pullup to avoid issues with * uncommitted pins, excepting special-function pins that we need to From 27312c4895aff603d7f6845e63fcf0236e203397 Mon Sep 17 00:00:00 2001 From: Vladimir Zidar Date: Wed, 7 Jun 2017 00:33:39 +0200 Subject: [PATCH 309/624] LP-528 partially revert 9f16143ba76aff279b118a178f93504a8f5fbea0 (uavobjects cannot be in ccm - loading from external SPI flash optionally uses DMA) --- flight/uavobjects/uavobjectmanager.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flight/uavobjects/uavobjectmanager.c b/flight/uavobjects/uavobjectmanager.c index 84e6d1b50e..8368f87a3e 100644 --- a/flight/uavobjects/uavobjectmanager.c +++ b/flight/uavobjects/uavobjectmanager.c @@ -225,7 +225,7 @@ static struct UAVOData *UAVObjAllocSingle(uint32_t num_bytes) uint32_t object_size = sizeof(struct UAVOSingle) + num_bytes; /* Allocate the object from the heap */ - struct UAVOSingle *uavo_single = (struct UAVOSingle *)pios_fastheapmalloc(object_size); + struct UAVOSingle *uavo_single = (struct UAVOSingle *)pios_malloc(object_size); if (!uavo_single) { return NULL; @@ -250,7 +250,7 @@ static struct UAVOData *UAVObjAllocMulti(uint32_t num_bytes) uint32_t object_size = sizeof(struct UAVOMulti) + num_bytes; /* Allocate the object from the heap */ - struct UAVOMulti *uavo_multi = (struct UAVOMulti *)pios_fastheapmalloc(object_size); + struct UAVOMulti *uavo_multi = (struct UAVOMulti *)pios_malloc(object_size); if (!uavo_multi) { return NULL; @@ -1598,7 +1598,7 @@ static InstanceHandle createInstance(struct UAVOData *obj, uint16_t instId) /* Create the actual instance */ uint32_t size = sizeof(struct UAVOMultiInst) + obj->instance_size; - instEntry = (struct UAVOMultiInst *)pios_fastheapmalloc(size); + instEntry = (struct UAVOMultiInst *)pios_malloc(size); if (!instEntry) { return NULL; } From d52f5a02f8b14a3b57c879d141d17b36275739ee Mon Sep 17 00:00:00 2001 From: Vladimir Zidar Date: Tue, 30 May 2017 22:03:07 +0200 Subject: [PATCH 310/624] LP-523 uavobject.c.template: Invoke new method $(NAME)DataOverrideDefaults() from $(NAME)SetDefaults() --- flight/uavobjects/inc/uavobject.h.template | 2 ++ flight/uavobjects/uavobject.c.template | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/flight/uavobjects/inc/uavobject.h.template b/flight/uavobjects/inc/uavobject.h.template index 349a01c1d4..c9c70ed187 100644 --- a/flight/uavobjects/inc/uavobject.h.template +++ b/flight/uavobjects/inc/uavobject.h.template @@ -71,6 +71,8 @@ typedef struct { */ typedef $(NAME)DataPacked __attribute__((aligned(4))) $(NAME)Data; +void $(NAME)DataOverrideDefaults($(NAME)Data * data); + /* Typesafe Object access functions */ static inline int32_t $(NAME)Get($(NAME)Data * dataOut) { return UAVObjGetData($(NAME)Handle(), dataOut); diff --git a/flight/uavobjects/uavobject.c.template b/flight/uavobjects/uavobject.c.template index c25cb4abf2..e50906a6fd 100644 --- a/flight/uavobjects/uavobject.c.template +++ b/flight/uavobjects/uavobject.c.template @@ -71,6 +71,10 @@ int32_t $(NAME)Initialize(void) return handle ? 0 : -1; } +static inline void DataOverrideDefaults(__attribute__((unused)) $(NAME)Data * data) {} + +void $(NAME)DataOverrideDefaults($(NAME)Data * data) __attribute__((weak, alias("DataOverrideDefaults"))); + /** * Initialize object fields and metadata with the default values. * If a default value is not specified the object fields @@ -84,6 +88,7 @@ void $(NAME)SetDefaults(UAVObjHandle obj, uint16_t instId) UAVObjGetInstanceData(obj, instId, &data); memset(&data, 0, sizeof($(NAME)Data)); $(INITFIELDS) + $(NAME)DataOverrideDefaults(&data); UAVObjSetInstanceData(obj, instId, &data); // Initialize object metadata to their default values From 9f12a27f53420169f9bcb3ca1309ff8ca857cfd9 Mon Sep 17 00:00:00 2001 From: Vladimir Zidar Date: Wed, 31 May 2017 14:41:09 +0200 Subject: [PATCH 311/624] LP-523 Move object id and instance_size members from UAVOData structure into UAVObjType and keep only pointer to it. UAVObjType contains init_callback too to allow resetting data to default values. --- flight/uavobjects/inc/uavobject.h.template | 2 +- flight/uavobjects/inc/uavobjectmanager.h | 12 ++- flight/uavobjects/inc/uavobjectprivate.h | 5 +- flight/uavobjects/uavobject.c.template | 10 +- flight/uavobjects/uavobjectmanager.c | 100 ++++++++++++------ flight/uavobjects/uavobjectpersistence.c | 4 +- .../uavobjectbrowserwidget.cpp | 2 + 7 files changed, 94 insertions(+), 41 deletions(-) diff --git a/flight/uavobjects/inc/uavobject.h.template b/flight/uavobjects/inc/uavobject.h.template index c9c70ed187..1474786716 100644 --- a/flight/uavobjects/inc/uavobject.h.template +++ b/flight/uavobjects/inc/uavobject.h.template @@ -96,7 +96,7 @@ static inline int32_t $(NAME)ConnectFastCallback(UAVObjEventCallback cb) { return UAVObjConnectCallback($(NAME)Handle(), cb, EV_MASK_ALL_UPDATES, true); } static inline uint16_t $(NAME)CreateInstance() { - return UAVObjCreateInstance($(NAME)Handle(), &$(NAME)SetDefaults); + return UAVObjCreateInstance($(NAME)Handle()); } static inline void $(NAME)RequestUpdate() { UAVObjRequestUpdate($(NAME)Handle()); diff --git a/flight/uavobjects/inc/uavobjectmanager.h b/flight/uavobjects/inc/uavobjectmanager.h index 7317e99df1..e73ac86a6e 100644 --- a/flight/uavobjects/inc/uavobjectmanager.h +++ b/flight/uavobjects/inc/uavobjectmanager.h @@ -182,16 +182,22 @@ typedef struct { uint32_t lastQueueErrorID; } UAVObjStats; +typedef struct { + uint32_t id; + UAVObjInitializeCallback init_callback; + uint16_t instance_size; +} __attribute__((packed, aligned(4))) UAVObjType; + int32_t UAVObjInitialize(); void UAVObjGetStats(UAVObjStats *statsOut); void UAVObjClearStats(); -UAVObjHandle UAVObjRegister(uint32_t id, bool isSingleInstance, bool isSettings, bool isPriority, uint32_t num_bytes, UAVObjInitializeCallback initCb); +UAVObjHandle UAVObjRegister(const UAVObjType *type, bool isSingleInstance, bool isSettings, bool isPriority); UAVObjHandle UAVObjGetByID(uint32_t id); uint32_t UAVObjGetID(UAVObjHandle obj); uint32_t UAVObjGetNumBytes(UAVObjHandle obj); uint16_t UAVObjGetNumInstances(UAVObjHandle obj); UAVObjHandle UAVObjGetLinkedObj(UAVObjHandle obj); -uint16_t UAVObjCreateInstance(UAVObjHandle obj_handle, UAVObjInitializeCallback initCb); +uint16_t UAVObjCreateInstance(UAVObjHandle obj_handle); bool UAVObjIsSingleInstance(UAVObjHandle obj); bool UAVObjIsMetaobject(UAVObjHandle obj); bool UAVObjIsSettings(UAVObjHandle obj); @@ -208,10 +214,12 @@ int32_t UAVObjDeleteSettings(); int32_t UAVObjSaveMetaobjects(); int32_t UAVObjLoadMetaobjects(); int32_t UAVObjDeleteMetaobjects(); +int32_t UAVObjSetDefaults(UAVObjHandle obj_handle); int32_t UAVObjSetData(UAVObjHandle obj_handle, const void *dataIn); int32_t UAVObjSetDataField(UAVObjHandle obj_handle, const void *dataIn, uint32_t offset, uint32_t size); int32_t UAVObjGetData(UAVObjHandle obj_handle, void *dataOut); int32_t UAVObjGetDataField(UAVObjHandle obj_handle, void *dataOut, uint32_t offset, uint32_t size); +int32_t UAVObjSetInstanceDefaults(UAVObjHandle obj_handle, uint16_t instId); int32_t UAVObjSetInstanceData(UAVObjHandle obj_handle, uint16_t instId, const void *dataIn); int32_t UAVObjSetInstanceDataField(UAVObjHandle obj_handle, uint16_t instId, const void *dataIn, uint32_t offset, uint32_t size); int32_t UAVObjGetInstanceData(UAVObjHandle obj_handle, uint16_t instId, void *dataOut); diff --git a/flight/uavobjects/inc/uavobjectprivate.h b/flight/uavobjects/inc/uavobjectprivate.h index 88229f44ec..2177539fdd 100644 --- a/flight/uavobjects/inc/uavobjectprivate.h +++ b/flight/uavobjects/inc/uavobjectprivate.h @@ -112,14 +112,13 @@ struct UAVOMeta { /* Shared data structure for all data-carrying UAVObjects (UAVOSingle and UAVOMulti) */ struct UAVOData { - struct UAVOBase base; - uint32_t id; + struct UAVOBase base; + const UAVObjType *type; /* this contains id, instance_size and data initializer */ /* * Embed the Meta object as another complete UAVO * inside the payload for this UAVO. */ struct UAVOMeta metaObj; - uint16_t instance_size; } __attribute__((packed, aligned(4))); /* Augmented type for Single Instance Data UAVO */ diff --git a/flight/uavobjects/uavobject.c.template b/flight/uavobjects/uavobject.c.template index e50906a6fd..4ec89d540f 100644 --- a/flight/uavobjects/uavobject.c.template +++ b/flight/uavobjects/uavobject.c.template @@ -63,9 +63,15 @@ int32_t $(NAME)Initialize(void) return -2; } + static const UAVObjType objType = { + .id = $(NAMEUC)_OBJID, + .instance_size = $(NAMEUC)_NUMBYTES, + .init_callback = &$(NAME)SetDefaults, + }; + // Register object with the object manager - handle = UAVObjRegister($(NAMEUC)_OBJID, - $(NAMEUC)_ISSINGLEINST, $(NAMEUC)_ISSETTINGS, $(NAMEUC)_ISPRIORITY, $(NAMEUC)_NUMBYTES, &$(NAME)SetDefaults); + handle = UAVObjRegister(&objType, + $(NAMEUC)_ISSINGLEINST, $(NAMEUC)_ISSETTINGS, $(NAMEUC)_ISPRIORITY); // Done return handle ? 0 : -1; diff --git a/flight/uavobjects/uavobjectmanager.c b/flight/uavobjects/uavobjectmanager.c index 8368f87a3e..0d9de00ea8 100644 --- a/flight/uavobjects/uavobjectmanager.c +++ b/flight/uavobjects/uavobjectmanager.c @@ -278,33 +278,30 @@ static struct UAVOData *UAVObjAllocMulti(uint32_t num_bytes) /** * Register and new object in the object manager. - * \param[in] id Unique object ID + * \param[in] pointer to UAVObjType structure that holds Unique object ID, instance size, initialization function * \param[in] isSingleInstance Is this a single instance or multi-instance object * \param[in] isSettings Is this a settings object - * \param[in] numBytes Number of bytes of object data (for one instance) - * \param[in] initCb Default field and metadata initialization function + * \param[in] isPriority * \return Object handle, or NULL if failure. * \return */ -UAVObjHandle UAVObjRegister(uint32_t id, - bool isSingleInstance, bool isSettings, bool isPriority, - uint32_t num_bytes, - UAVObjInitializeCallback initCb) +UAVObjHandle UAVObjRegister(const UAVObjType *type, + bool isSingleInstance, bool isSettings, bool isPriority) { struct UAVOData *uavo_data = NULL; xSemaphoreTakeRecursive(mutex, portMAX_DELAY); /* Don't allow duplicate registrations */ - if (UAVObjGetByID(id)) { + if (UAVObjGetByID(type->id)) { goto unlock_exit; } /* Map the various flags to one of the UAVO types we understand */ if (isSingleInstance) { - uavo_data = UAVObjAllocSingle(num_bytes); + uavo_data = UAVObjAllocSingle(type->instance_size); } else { - uavo_data = UAVObjAllocMulti(num_bytes); + uavo_data = UAVObjAllocMulti(type->instance_size); } if (!uavo_data) { @@ -312,8 +309,7 @@ UAVObjHandle UAVObjRegister(uint32_t id, } /* Fill in the details about this UAVO */ - uavo_data->id = id; - uavo_data->instance_size = num_bytes; + uavo_data->type = type; if (isSettings) { uavo_data->base.flags.isSettings = true; // settings defaults to being sent with priority @@ -325,8 +321,8 @@ UAVObjHandle UAVObjRegister(uint32_t id, UAVObjInitMetaData(&uavo_data->metaObj); /* Initialize object fields and metadata to default values */ - if (initCb) { - initCb((UAVObjHandle)uavo_data, 0); + if (type->init_callback) { + type->init_callback((UAVObjHandle)uavo_data, 0); } /* Always try to load the meta object from flash */ @@ -360,11 +356,11 @@ UAVObjHandle UAVObjGetByID(uint32_t id) // Look for object UAVO_LIST_ITERATE(tmp_obj) - if (tmp_obj->id == id) { + if (tmp_obj->type->id == id) { found_obj = (UAVObjHandle *)tmp_obj; goto unlock_exit; } - if (MetaObjectId(tmp_obj->id) == id) { + if (MetaObjectId(tmp_obj->type->id) == id) { found_obj = (UAVObjHandle *)&(tmp_obj->metaObj); goto unlock_exit; } @@ -391,12 +387,12 @@ uint32_t UAVObjGetID(UAVObjHandle obj_handle) /* We have a meta object, find our containing UAVO */ struct UAVOData *uavo_data = container_of((struct UAVOMeta *)uavo_base, struct UAVOData, metaObj); - return MetaObjectId(uavo_data->id); + return MetaObjectId(uavo_data->type->id); } else { /* We have a data object, augment our pointer */ struct UAVOData *uavo_data = (struct UAVOData *)uavo_base; - return uavo_data->id; + return uavo_data->type->id; } } @@ -420,7 +416,7 @@ uint32_t UAVObjGetNumBytes(UAVObjHandle obj) /* We have a data object, augment our pointer */ struct UAVOData *uavo = (struct UAVOData *)uavo_base; - instance_size = uavo->instance_size; + instance_size = uavo->type->instance_size; } return instance_size; @@ -478,8 +474,7 @@ uint16_t UAVObjGetNumInstances(UAVObjHandle obj_handle) * \param[in] obj The object handle * \return The instance ID or 0 if an error */ -uint16_t UAVObjCreateInstance(UAVObjHandle obj_handle, - UAVObjInitializeCallback initCb) +uint16_t UAVObjCreateInstance(UAVObjHandle obj_handle) { PIOS_Assert(obj_handle); @@ -501,8 +496,8 @@ uint16_t UAVObjCreateInstance(UAVObjHandle obj_handle, } // Initialize instance data - if (initCb) { - initCb(obj_handle, instId); + if (((struct UAVOData *)obj_handle)->type->init_callback) { + ((struct UAVOData *)obj_handle)->type->init_callback(obj_handle, instId); } unlock_exit: @@ -550,7 +545,7 @@ int32_t UAVObjUnpack(UAVObjHandle obj_handle, uint16_t instId, const uint8_t *da } } // Set the data - memcpy(InstanceData(instEntry), dataIn, obj->instance_size); + memcpy(InstanceData(instEntry), dataIn, obj->type->instance_size); } // Fire event @@ -596,7 +591,7 @@ int32_t UAVObjPack(UAVObjHandle obj_handle, uint16_t instId, uint8_t *dataOut) goto unlock_exit; } // Pack data - memcpy(dataOut, InstanceData(instEntry), obj->instance_size); + memcpy(dataOut, InstanceData(instEntry), obj->type->instance_size); } rc = 0; @@ -638,7 +633,7 @@ uint8_t UAVObjUpdateCRC(UAVObjHandle obj_handle, uint16_t instId, uint8_t crc) goto unlock_exit; } // Update crc - crc = PIOS_CRC_updateCRC(crc, (uint8_t *)InstanceData(instEntry), (int32_t)obj->instance_size); + crc = PIOS_CRC_updateCRC(crc, (uint8_t *)InstanceData(instEntry), (int32_t)obj->type->instance_size); } unlock_exit: @@ -677,7 +672,7 @@ void UAVObjInstanceWriteToLog(UAVObjHandle obj_handle, uint16_t instId) goto unlock_exit; } // Pack data - PIOS_DEBUGLOG_UAVObject(UAVObjGetID(obj_handle), instId, obj->instance_size, (uint8_t *)InstanceData(instEntry)); + PIOS_DEBUGLOG_UAVObject(UAVObjGetID(obj_handle), instId, obj->type->instance_size, (uint8_t *)InstanceData(instEntry)); } unlock_exit: @@ -857,6 +852,11 @@ xSemaphoreGiveRecursive(mutex); return rc; } +int32_t UAVObjSetDefaults(UAVObjHandle obj_handle) +{ + return UAVObjSetInstanceDefaults(obj_handle, 0); +} + /** * Set the object data * \param[in] obj The object handle @@ -901,6 +901,42 @@ int32_t UAVObjGetDataField(UAVObjHandle obj_handle, void *dataOut, uint32_t offs return UAVObjGetInstanceDataField(obj_handle, 0, dataOut, offset, size); } +int32_t UAVObjSetInstanceDefaults(UAVObjHandle obj_handle, uint16_t instId) +{ + PIOS_Assert(obj_handle); + + // Lock + xSemaphoreTakeRecursive(mutex, portMAX_DELAY); + + int32_t rc = -1; + + if (IsMetaobject(obj_handle)) { + if (instId != 0) { + goto unlock_exit; + } +// How do we set meta data defaults? +// MetaDataPtr((struct UAVOMeta *)obj_handle), MetaNumBytes; + } else { + // Check access level + if (UAVObjReadOnly(obj_handle)) { + goto unlock_exit; + } + + // Set default data + if (((struct UAVOData *)obj_handle)->type->init_callback) { + ((struct UAVOData *)obj_handle)->type->init_callback(obj_handle, instId); + } + } + + // Fire event + sendEvent((struct UAVOBase *)obj_handle, instId, EV_UPDATED); + rc = 0; + +unlock_exit: + xSemaphoreGiveRecursive(mutex); + return rc; +} + /** * Set the data of a specific object instance * \param[in] obj The object handle @@ -940,7 +976,7 @@ int32_t UAVObjSetInstanceData(UAVObjHandle obj_handle, uint16_t instId, goto unlock_exit; } // Set data - memcpy(InstanceData(instEntry), dataIn, obj->instance_size); + memcpy(InstanceData(instEntry), dataIn, obj->type->instance_size); } // Fire event @@ -1000,7 +1036,7 @@ int32_t UAVObjSetInstanceDataField(UAVObjHandle obj_handle, uint16_t instId, con } // Check for overrun - if ((size + offset) > obj->instance_size) { + if ((size + offset) > obj->type->instance_size) { goto unlock_exit; } @@ -1055,7 +1091,7 @@ int32_t UAVObjGetInstanceData(UAVObjHandle obj_handle, uint16_t instId, goto unlock_exit; } // Set data - memcpy(dataOut, InstanceData(instEntry), obj->instance_size); + memcpy(dataOut, InstanceData(instEntry), obj->type->instance_size); } rc = 0; @@ -1108,7 +1144,7 @@ int32_t UAVObjGetInstanceDataField(UAVObjHandle obj_handle, uint16_t instId, voi } // Check for overrun - if ((size + offset) > obj->instance_size) { + if ((size + offset) > obj->type->instance_size) { goto unlock_exit; } @@ -1597,7 +1633,7 @@ static InstanceHandle createInstance(struct UAVOData *obj, uint16_t instId) } /* Create the actual instance */ - uint32_t size = sizeof(struct UAVOMultiInst) + obj->instance_size; + uint32_t size = sizeof(struct UAVOMultiInst) + obj->type->instance_size; instEntry = (struct UAVOMultiInst *)pios_malloc(size); if (!instEntry) { return NULL; diff --git a/flight/uavobjects/uavobjectpersistence.c b/flight/uavobjects/uavobjectpersistence.c index 4acbd41e5d..0f0395ce7b 100644 --- a/flight/uavobjects/uavobjectpersistence.c +++ b/flight/uavobjects/uavobjectpersistence.c @@ -121,6 +121,8 @@ int32_t UAVObjLoad(UAVObjHandle obj_handle, uint16_t instId) int32_t UAVObjDelete(UAVObjHandle obj_handle, uint16_t instId) { PIOS_Assert(obj_handle); - PIOS_FLASHFS_ObjDelete(pios_uavo_settings_fs_id, UAVObjGetID(obj_handle), instId); + if (PIOS_FLASHFS_ObjDelete(pios_uavo_settings_fs_id, UAVObjGetID(obj_handle), instId) == 0) { + UAVObjSetInstanceDefaults(obj_handle, instId); + } return 0; } diff --git a/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowserwidget.cpp b/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowserwidget.cpp index 93b1b76c51..b7ab69aefd 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowserwidget.cpp +++ b/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowserwidget.cpp @@ -212,6 +212,8 @@ void UAVObjectBrowserWidget::eraseObject() UAVObject *obj = objItem->object(); Q_ASSERT(obj); updateObjectPersistance(ObjectPersistence::OPERATION_DELETE, obj); + // Retrieve object so that correct default value is displayed + requestUpdate(); } } From 22071ba230742d96122884aba6e0bcc25be08003 Mon Sep 17 00:00:00 2001 From: Brian Webb Date: Sun, 4 Jun 2017 08:28:25 -0700 Subject: [PATCH 312/624] LP-526 Adds support for the MSP_SERVO command to the MSP module. --- flight/modules/UAVOMSPBridge/UAVOMSPBridge.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/flight/modules/UAVOMSPBridge/UAVOMSPBridge.c b/flight/modules/UAVOMSPBridge/UAVOMSPBridge.c index 6114a963c2..8412766234 100644 --- a/flight/modules/UAVOMSPBridge/UAVOMSPBridge.c +++ b/flight/modules/UAVOMSPBridge/UAVOMSPBridge.c @@ -49,6 +49,7 @@ #include "airspeedstate.h" #include "actuatorsettings.h" #include "actuatordesired.h" +#include "actuatorcommand.h" #include "flightstatus.h" #include "systemstats.h" #include "systemalarms.h" @@ -665,6 +666,20 @@ static void msp_send_channels(struct msp_bridge *m) msp_send(m, MSP_RC, data.buf, sizeof(data)); } +static void msp_send_servo(struct msp_bridge *m) +{ + ActuatorCommandData ac; + + ActuatorCommandGet(&ac); + + // Only the first 8 channels are supported. + // Channels are 16 bits (2 bytes). + uint8_t channels[16]; + memcpy(channels, (uint8_t *)ac.Channel, 16); + + msp_send(m, MSP_SERVO, channels, sizeof(channels)); +} + static void msp_send_boxids(struct msp_bridge *m) // This is actually sending a map of MSP_STATUS.flag bits to BOX ids. { msp_send(m, MSP_BOXIDS, msp_boxes, sizeof(msp_boxes)); @@ -871,6 +886,9 @@ static msp_state msp_state_checksum(struct msp_bridge *m, uint8_t b) case MSP_RC: msp_send_channels(m); break; + case MSP_SERVO: + msp_send_servo(m); + break; case MSP_BOXIDS: msp_send_boxids(m); break; From bd555623ddbd995132e71714663649437f16e7b1 Mon Sep 17 00:00:00 2001 From: Fredrik Arvidsson Date: Wed, 14 Jun 2017 00:18:33 +0200 Subject: [PATCH 313/624] LP-531 Adds support for Qt 5.9.0 SDK install script and Qt installer script updated with new version, paths and URL:s Explicit casts to char added to avoid clang compiler warnings (treated like errors) on MacOSX and XCode 8.3.2 --- .../uavobjectutil/uavobjectutilmanager.cpp | 2 +- ground/gcs/src/plugins/uploader/dfu.cpp | 8 ++++---- make/tool_install/qt-install.qs | 18 +++++++++--------- make/tools.mk | 10 +++++----- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/ground/gcs/src/plugins/uavobjectutil/uavobjectutilmanager.cpp b/ground/gcs/src/plugins/uavobjectutil/uavobjectutilmanager.cpp index b4e2f7f645..113f795ce0 100644 --- a/ground/gcs/src/plugins/uavobjectutil/uavobjectutilmanager.cpp +++ b/ground/gcs/src/plugins/uavobjectutil/uavobjectutilmanager.cpp @@ -313,7 +313,7 @@ QString UAVObjectUtilManager::getBoardDescriptionString() { QByteArray arr = getBoardDescription(); - int index = arr.indexOf(255); + int index = arr.indexOf((char)255); return QString((index == -1) ? arr : arr.left(index)); } diff --git a/ground/gcs/src/plugins/uploader/dfu.cpp b/ground/gcs/src/plugins/uploader/dfu.cpp index f6546f7f2d..5f923b800c 100644 --- a/ground/gcs/src/plugins/uploader/dfu.cpp +++ b/ground/gcs/src/plugins/uploader/dfu.cpp @@ -365,7 +365,7 @@ QString DFUObject::DownloadDescription(int const & numberOfChars) StartDownloadT(&arr, numberOfChars, DFU::Descript); - int index = arr.indexOf(255); + int index = arr.indexOf((char)255); return QString((index == -1) ? arr : arr.left(index)); } @@ -778,7 +778,7 @@ DFU::Status DFUObject::UploadFirmwareT(const QString &sfile, const bool &verify, ++pad; pad = pad * 4; pad = pad - arr.length(); - arr.append(QByteArray(pad, 255)); + arr.append(QByteArray(pad, (char)255)); } if (devices[device].SizeOfCode < (quint32)arr.length()) { if (debug) { @@ -884,7 +884,7 @@ DFU::Status DFUObject::CompareFirmware(const QString &sfile, const CompareType & ++pad; pad = pad * 4; pad = pad - arr.length(); - arr.append(QByteArray(pad, 255)); + arr.append(QByteArray(pad, (char)255)); } if (type == DFU::crccompare) { quint32 crc = DFUObject::CRCFromQBArray(arr, devices[device].SizeOfCode); @@ -1033,7 +1033,7 @@ quint32 DFUObject::CRCFromQBArray(QByteArray array, quint32 Size) { quint32 pad = Size - array.length(); - array.append(QByteArray(pad, 255)); + array.append(QByteArray(pad, (char)255)); int num_words = Size / 4; quint32 *t = (quint32 *)malloc(Size); for (int x = 0; x < num_words; x++) { diff --git a/make/tool_install/qt-install.qs b/make/tool_install/qt-install.qs index 441d7bbd97..dc1920c729 100644 --- a/make/tool_install/qt-install.qs +++ b/make/tool_install/qt-install.qs @@ -1,10 +1,10 @@ /* Silent installer script -Known to work with Qt 5.8.0 and QtIFW 2.0.5 +Known to work with Qt 5.9.0 and QtIFW 2.0.5 Test with: -$ ./qt-opensource-windows-x86-mingw530-5.8.0.exe --verbose --script ../librepilot/make/tool_install/qt-install.qs +$ ./qt-opensource-windows-x86-mingw530-5.9.0.exe --verbose --script ../librepilot/make/tool_install/qt-install.qs Known issues: - silent but not headless (QtIFW 2.1.0 should support gui.setSilent(true)) @@ -20,7 +20,7 @@ function Controller() var qtInstallTargetDir = installer.environmentVariable("QT_INSTALL_TARGET_DIR"); if (qtInstallTargetDir == "") { - qtInstallTargetDir = installer.environmentVariable("PWD") + "/tools/qt-5.8.0"; + qtInstallTargetDir = installer.environmentVariable("PWD") + "/tools/qt-5.9.0"; console.log("Environment variable QT_INSTALL_TARGET_DIR not set, using default " + qtInstallTargetDir); } installer.setValue("TargetDir", qtInstallTargetDir); @@ -107,18 +107,18 @@ Controller.prototype.ComponentSelectionPageCallback = function() var page = gui.currentPageWidget(); page.deselectAll() if (installer.value("os") == "win") { - selectComponent(page, "qt.58.win32_mingw53"); + selectComponent(page, "qt.59.win32_mingw53"); selectComponent(page, "qt.tools.win32_mingw530"); } else if (installer.value("os") == "x11") { - selectComponent(page, "qt.58.gcc"); - selectComponent(page, "qt.58.gcc_64"); + selectComponent(page, "qt.59.gcc"); + selectComponent(page, "qt.59.gcc_64"); } else if (installer.value("os") == "mac") { - selectComponent(page, "qt.58.clang_64"); + selectComponent(page, "qt.59.clang_64"); } - //selectComponent(page, "qt.58.qtquickcontrols"); - selectComponent(page, "qt.58.qtscript"); + //selectComponent(page, "qt.59.qtquickcontrols"); + selectComponent(page, "qt.59.qtscript"); gui.clickButton(buttons.NextButton); } diff --git a/make/tools.mk b/make/tools.mk index 902be7aaf5..1acd5c4017 100644 --- a/make/tools.mk +++ b/make/tools.mk @@ -90,8 +90,8 @@ TOOLS_URL := http://librepilot.github.io/tools # and are used only to install the tools on some OSes # don't assume actual versions to match -QT_SHORT_VERSION := 5.8 -QT_VERSION := 5.8.0 +QT_SHORT_VERSION := 5.9 +QT_VERSION := 5.9.0 OSG_VERSION := 3.5.5 OSGEARTH_VERSION := 2.8 @@ -110,10 +110,10 @@ ifeq ($(UNAME), Linux) DOXYGEN_URL := $(TOOLS_URL)/doxygen-1.8.3.1.src.tar.gz else ifeq ($(UNAME), Darwin) QT_SDK_ARCH := clang_64 - QT_SDK_URL := http://download.qt.io/official_releases/qt/$(QT_SHORT_VERSION)/$(QT_VERSION)/qt-opensource-mac-x64-clang-$(QT_VERSION).dmg + QT_SDK_URL := http://download.qt.io/official_releases/qt/$(QT_SHORT_VERSION)/$(QT_VERSION)/qt-opensource-mac-x64-$(QT_VERSION).dmg QT_SDK_MD5_URL := http://download.qt.io/official_releases/qt/$(QT_SHORT_VERSION)/$(QT_VERSION)/md5sums.txt - QT_SDK_MOUNT_DIR := /Volumes/qt-opensource-mac-x64-clang-$(QT_VERSION) - QT_SDK_MAINTENANCE_TOOL := /Volumes/qt-opensource-mac-x64-clang-$(QT_VERSION)/qt-opensource-mac-x64-clang-$(QT_VERSION).app/Contents/MacOS/qt-opensource-mac-x64-clang-$(QT_VERSION) + QT_SDK_MOUNT_DIR := /Volumes/qt-opensource-mac-x64-$(QT_VERSION) + QT_SDK_MAINTENANCE_TOOL := /Volumes/qt-opensource-mac-x64-$(QT_VERSION)/qt-opensource-mac-x64-$(QT_VERSION).app/Contents/MacOS/qt-opensource-mac-x64-$(QT_VERSION) UNCRUSTIFY_URL := $(TOOLS_URL)/uncrustify-0.60.tar.gz DOXYGEN_URL := $(TOOLS_URL)/doxygen-1.8.3.1.src.tar.gz OSG_URL := $(TOOLS_URL)/osg-$(OSG_VERSION)-clang_64.tar.gz From 8c60c28b513e6e6e0f47a50a5f60b67b4539796d Mon Sep 17 00:00:00 2001 From: Vladimir Zidar Date: Thu, 8 Jun 2017 15:03:48 +0200 Subject: [PATCH 314/624] LP-529 Fixed i2c port selection for aux mag. --- flight/pios/common/pios_board_sensors.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/flight/pios/common/pios_board_sensors.c b/flight/pios/common/pios_board_sensors.c index d878951e22..e07cfffd75 100644 --- a/flight/pios/common/pios_board_sensors.c +++ b/flight/pios/common/pios_board_sensors.c @@ -161,13 +161,13 @@ void PIOS_BOARD_Sensors_Configure() if (option == AUXMAGSETTINGS_TYPE_FLEXI) { // i2c_external -#ifdef PIOS_I2C_EXTERNAL_ADAPTER - i2c_id = PIOS_I2C_EXTERNAL_ADAPTER; +#ifdef PIOS_I2C_FLEXI_ADAPTER + i2c_id = PIOS_I2C_FLEXI_ADAPTER; #endif } else if (option == AUXMAGSETTINGS_TYPE_I2C) { // i2c_internal (or Sparky2/F3 dedicated I2C port) -#ifdef PIOS_I2C_FLEXI_ADAPTER - i2c_id = PIOS_I2C_FLEXI_ADAPTER; +#ifdef PIOS_I2C_EXTERNAL_ADAPTER + i2c_id = PIOS_I2C_EXTERNAL_ADAPTER; #endif } From a00af53710b75789da0edad8b6b0d66c026963e2 Mon Sep 17 00:00:00 2001 From: Vladimir Zidar Date: Fri, 9 Jun 2017 12:14:43 +0200 Subject: [PATCH 315/624] LP-529 [F3] [I2C] Fix nack handling. --- flight/pios/stm32f30x/pios_i2c.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/flight/pios/stm32f30x/pios_i2c.c b/flight/pios/stm32f30x/pios_i2c.c index 8644c6f079..2a8b835350 100644 --- a/flight/pios/stm32f30x/pios_i2c.c +++ b/flight/pios/stm32f30x/pios_i2c.c @@ -260,6 +260,7 @@ static void go_starting(struct pios_i2c_adapter *i2c_adapter, __attribute__((unu i2c_adapter->active_byte = &(i2c_adapter->active_txn->buf[0]); i2c_adapter->last_byte = &(i2c_adapter->active_txn->buf[i2c_adapter->active_txn->len - 1]); + I2C_ClearITPendingBit(i2c_adapter->cfg->regs, I2C_IT_STOPI | I2C_IT_NACKI | I2C_IT_ERRI); I2C_ITConfig(i2c_adapter->cfg->regs, I2C_IT_ERRI | I2C_IT_TCI | I2C_IT_NACKI | I2C_IT_RXI | I2C_IT_STOPI | I2C_IT_TXI, ENABLE); I2C_TransferHandling( @@ -305,8 +306,9 @@ static void go_nack(struct pios_i2c_adapter *i2c_adapter, __attribute__((unused) { i2c_adapter->nack = true; I2C_ITConfig(i2c_adapter->cfg->regs, I2C_IT_ERRI | I2C_IT_TCI | I2C_IT_NACKI | I2C_IT_RXI | I2C_IT_STOPI | I2C_IT_TXI, DISABLE); - I2C_AcknowledgeConfig(i2c_adapter->cfg->regs, DISABLE); - I2C_GenerateSTOP(i2c_adapter->cfg->regs, ENABLE); + /* It seems that we don't need this with F3 i2c peripheral */ + // I2C_AcknowledgeConfig(i2c_adapter->cfg->regs, DISABLE); + // I2C_GenerateSTOP(i2c_adapter->cfg->regs, ENABLE); } static void i2c_adapter_inject_event(struct pios_i2c_adapter *i2c_adapter, enum i2c_adapter_event event, bool *woken) From b0fa0edb6424b0eb849596b648f7ca9464e2dbb8 Mon Sep 17 00:00:00 2001 From: Vladimir Zidar Date: Wed, 14 Jun 2017 16:05:52 +0200 Subject: [PATCH 316/624] LP-529 [F3] [I2C] Move i2c bus unlocking down to irq, to save one context switch and make bus available for use by other drivers sooner. --- flight/pios/common/pios_mpu6000.c | 4 +- flight/pios/inc/pios_i2c.h | 12 ++++- flight/pios/inc/pios_i2c_priv.h | 2 + flight/pios/stm32f10x/pios_i2c.c | 11 ++-- flight/pios/stm32f30x/pios_i2c.c | 86 ++++++++++++++----------------- flight/pios/stm32f4xx/pios_i2c.c | 24 ++++----- 6 files changed, 72 insertions(+), 67 deletions(-) diff --git a/flight/pios/common/pios_mpu6000.c b/flight/pios/common/pios_mpu6000.c index a95dc846f6..ace15cac50 100644 --- a/flight/pios/common/pios_mpu6000.c +++ b/flight/pios/common/pios_mpu6000.c @@ -570,9 +570,9 @@ static int32_t PIOS_MPU6000_I2C_GetReg(uint8_t address) return data; } -static bool PIOS_MPU6000_I2C_Read_Completed() +static bool PIOS_MPU6000_I2C_Read_Completed(enum pios_i2c_transfer_result result) { - return PIOS_MPU6000_HandleData(gyro_read_timestamp); + return (result == PIOS_I2C_TRANSFER_OK) ? PIOS_MPU6000_HandleData(gyro_read_timestamp) : false; } static bool PIOS_MPU6000_I2C_ReadSensor(bool *woken) diff --git a/flight/pios/inc/pios_i2c.h b/flight/pios/inc/pios_i2c.h index 546a51e2fb..b37537bda9 100644 --- a/flight/pios/inc/pios_i2c.h +++ b/flight/pios/inc/pios_i2c.h @@ -73,7 +73,17 @@ enum pios_i2c_error_count { PIOS_I2C_ERROR_COUNT_NUMELEM, }; -typedef bool (*pios_i2c_callback)(); +enum pios_i2c_transfer_result { + PIOS_I2C_TRANSFER_OK = 0, + PIOS_I2C_TRANSFER_BUSY = -2, + PIOS_I2C_TRANSFER_BUS_ERROR = -1, + PIOS_I2C_TRANSFER_NACK = -3, + PIOS_I2C_TRANSFER_TIMEOUT = -4, + PIOS_I2C_TRANSFER_UNSPECIFIED_ERROR = -5, + PIOS_I2C_TRANSFER_DEVICE_ERROR = -6, +}; + +typedef bool (*pios_i2c_callback)(enum pios_i2c_transfer_result result); /* Public Functions */ extern int32_t PIOS_I2C_Transfer(uint32_t i2c_id, const struct pios_i2c_txn txn_list[], uint32_t num_txns); diff --git a/flight/pios/inc/pios_i2c_priv.h b/flight/pios/inc/pios_i2c_priv.h index 20fec3e5dc..7be45ba770 100644 --- a/flight/pios/inc/pios_i2c_priv.h +++ b/flight/pios/inc/pios_i2c_priv.h @@ -73,6 +73,8 @@ struct pios_i2c_adapter { uint8_t *active_byte; uint8_t *last_byte; + + enum pios_i2c_transfer_result *transfer_result; }; int32_t PIOS_I2C_Init(uint32_t *i2c_id, const struct pios_i2c_adapter_cfg *cfg); diff --git a/flight/pios/stm32f10x/pios_i2c.c b/flight/pios/stm32f10x/pios_i2c.c index e18edc2fe7..c411d7eac5 100644 --- a/flight/pios/stm32f10x/pios_i2c.c +++ b/flight/pios/stm32f10x/pios_i2c.c @@ -980,7 +980,7 @@ int32_t PIOS_I2C_Transfer(uint32_t i2c_id, const struct pios_i2c_txn txn_list[], struct pios_i2c_adapter *i2c_adapter = (struct pios_i2c_adapter *)i2c_id; if (!PIOS_I2C_validate(i2c_adapter)) { - return -1; + return PIOS_I2C_TRANSFER_DEVICE_ERROR; } PIOS_DEBUG_Assert(txn_list); @@ -993,9 +993,10 @@ int32_t PIOS_I2C_Transfer(uint32_t i2c_id, const struct pios_i2c_txn txn_list[], portTickType timeout; timeout = i2c_adapter->cfg->transfer_timeout_ms / portTICK_RATE_MS; if (xSemaphoreTake(i2c_adapter->sem_busy, timeout) == pdFALSE) { - return -2; + return PIOS_I2C_TRANSFER_BUSY; } #else +#error PIOS_I2C_Transfer is broken for use without FreeRTOS uint32_t timeout = 0xfff; while (i2c_adapter->busy && --timeout) { ; @@ -1071,9 +1072,9 @@ int32_t PIOS_I2C_Transfer(uint32_t i2c_id, const struct pios_i2c_txn txn_list[], } #endif /* USE_FREERTOS */ - return !semaphore_success ? -2 : - i2c_adapter->bus_error ? -1 : - 0; + return !semaphore_success ? PIOS_I2C_TRANSFER_TIMEOUT : + i2c_adapter->bus_error ? PIOS_I2C_TRANSFER_BUS_ERROR : + PIOS_I2C_TRANSFER_OK; } diff --git a/flight/pios/stm32f30x/pios_i2c.c b/flight/pios/stm32f30x/pios_i2c.c index 2a8b835350..831c5f30e6 100644 --- a/flight/pios/stm32f30x/pios_i2c.c +++ b/flight/pios/stm32f30x/pios_i2c.c @@ -135,7 +135,6 @@ static void i2c_adapter_process_auto(struct pios_i2c_adapter *i2c_adapter, bool static void i2c_adapter_inject_event(struct pios_i2c_adapter *i2c_adapter, enum i2c_adapter_event event, bool *woken); static void i2c_adapter_fsm_init(struct pios_i2c_adapter *i2c_adapter); static void i2c_adapter_reset_bus(struct pios_i2c_adapter *i2c_adapter); -static bool i2c_adapter_callback_handler(struct pios_i2c_adapter *i2c_adapter, bool *woken); #if defined(PIOS_I2C_DIAGNOSTICS) static void i2c_adapter_log_fault(struct pios_i2c_adapter *i2c_adapter, enum pios_i2c_error_type type); @@ -234,9 +233,18 @@ static void go_stopped(struct pios_i2c_adapter *i2c_adapter, bool *woken) { I2C_ITConfig(i2c_adapter->cfg->regs, I2C_IT_ERRI | I2C_IT_TCI | I2C_IT_NACKI | I2C_IT_RXI | I2C_IT_STOPI | I2C_IT_TXI, DISABLE); - if (i2c_adapter->callback) { - i2c_adapter_callback_handler(i2c_adapter, woken); - } else { + enum pios_i2c_transfer_result result = + i2c_adapter->bus_error ? PIOS_I2C_TRANSFER_BUS_ERROR : + i2c_adapter->nack ? PIOS_I2C_TRANSFER_NACK : + PIOS_I2C_TRANSFER_OK; + + if (i2c_adapter->transfer_result) { + *(i2c_adapter->transfer_result) = result; + } + + pios_i2c_callback cb = i2c_adapter->callback; + + if(!cb) { /* No callback? Signal that we are done */ #ifdef PIOS_INCLUDE_FREERTOS signed portBASE_TYPE pxHigherPriorityTaskWoken = pdFALSE; if (xSemaphoreGiveFromISR(i2c_adapter->sem_ready, &pxHigherPriorityTaskWoken) != pdTRUE) { @@ -249,6 +257,23 @@ static void go_stopped(struct pios_i2c_adapter *i2c_adapter, bool *woken) } #endif /* PIOS_INCLUDE_FREERTOS */ } + +#ifdef PIOS_INCLUDE_FREERTOS + /* Unlock the bus */ + signed portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; + xSemaphoreGiveFromISR(i2c_adapter->sem_busy, &xHigherPriorityTaskWoken); + if (xHigherPriorityTaskWoken == pdTRUE) { + *woken = true; + } +#else + PIOS_IRQ_Disable(); + i2c_adapter->busy = 0; + PIOS_IRQ_Enable(); +#endif /* PIOS_INCLUDE_FREERTOS */ + + if(cb && cb(result)) { /* User provided callback? Do it, but with bus unlocked */ + *woken = true; + } } static void go_starting(struct pios_i2c_adapter *i2c_adapter, __attribute__((unused)) bool *woken) @@ -609,7 +634,8 @@ int32_t PIOS_I2C_Transfer(uint32_t i2c_id, const struct pios_i2c_txn txn_list[], { // FIXME: only supports transfer sizes up to 255 bytes struct pios_i2c_adapter *i2c_adapter = (struct pios_i2c_adapter *)i2c_id; - + enum pios_i2c_transfer_result result = PIOS_I2C_TRANSFER_UNSPECIFIED_ERROR; + bool valid = PIOS_I2C_validate(i2c_adapter); PIOS_Assert(valid) @@ -624,13 +650,13 @@ int32_t PIOS_I2C_Transfer(uint32_t i2c_id, const struct pios_i2c_txn txn_list[], portTickType timeout; timeout = i2c_adapter->cfg->transfer_timeout_ms / portTICK_RATE_MS; if (xSemaphoreTake(i2c_adapter->sem_busy, timeout) == pdFALSE) { - return -2; + return PIOS_I2C_TRANSFER_BUSY; } #else PIOS_IRQ_Disable(); if (i2c_adapter->busy) { PIOS_IRQ_Enable(); - return -2; + return PIOS_I2C_TRANSFER_BUSY; } i2c_adapter->busy = 1; PIOS_IRQ_Enable(); @@ -638,6 +664,7 @@ int32_t PIOS_I2C_Transfer(uint32_t i2c_id, const struct pios_i2c_txn txn_list[], PIOS_DEBUG_Assert(i2c_adapter->curr_state == I2C_STATE_STOPPED); + i2c_adapter->transfer_result = &result; i2c_adapter->last_txn = &txn_list[num_txns - 1]; i2c_adapter->active_txn = &txn_list[0]; i2c_adapter->bus_error = false; @@ -659,30 +686,22 @@ int32_t PIOS_I2C_Transfer(uint32_t i2c_id, const struct pios_i2c_txn txn_list[], xSemaphoreGive(i2c_adapter->sem_ready); #endif /* PIOS_INCLUDE_FREERTOS */ -#ifdef PIOS_INCLUDE_FREERTOS - /* Unlock the bus */ - xSemaphoreGive(i2c_adapter->sem_busy); + /* After this point, the bus is already unlocked from ISR + * Touching i2c_adapter is not allowed */ #if defined(PIOS_I2C_DIAGNOSTICS) if (!semaphore_success) { i2c_timeout_counter++; + result = PIOS_I2C_TRANSFER_TIMEOUT; } #endif -#else - PIOS_IRQ_Disable(); - i2c_adapter->busy = 0; - PIOS_IRQ_Enable(); -#endif /* PIOS_INCLUDE_FREERTOS */ - - return !semaphore_success ? -2 : - i2c_adapter->bus_error ? -1 : - i2c_adapter->nack ? -3 : - 0; + return result; } static int32_t PIOS_I2C_Transfer_Callback_Internal(struct pios_i2c_adapter *i2c_adapter, const struct pios_i2c_txn txn_list[], uint32_t num_txns, pios_i2c_callback callback) { PIOS_DEBUG_Assert(i2c_adapter->curr_state == I2C_STATE_STOPPED); + i2c_adapter->transfer_result = 0; i2c_adapter->last_txn = &txn_list[num_txns - 1]; i2c_adapter->active_txn = &txn_list[0]; i2c_adapter->bus_error = false; @@ -773,33 +792,6 @@ int32_t PIOS_I2C_Transfer_CallbackFromISR(uint32_t i2c_id, const struct pios_i2c return PIOS_I2C_Transfer_Callback_Internal(i2c_adapter, txn_list, num_txns, callback); } - -static bool i2c_adapter_callback_handler(struct pios_i2c_adapter *i2c_adapter, bool *woken) -{ -#ifdef PIOS_INCLUDE_FREERTOS - /* Unlock the bus */ - signed portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; - xSemaphoreGiveFromISR(i2c_adapter->sem_busy, &xHigherPriorityTaskWoken); - if (xHigherPriorityTaskWoken == pdTRUE) { - *woken = true; - } -#else - PIOS_IRQ_Disable(); - i2c_adapter->busy = 0; - PIOS_IRQ_Enable(); -#endif /* PIOS_INCLUDE_FREERTOS */ - - - // Execute user supplied function - - if (i2c_adapter->callback()) { - *woken = true; - } - - return !i2c_adapter->bus_error; -} - - void PIOS_I2C_EV_IRQ_Handler(uint32_t i2c_id) { struct pios_i2c_adapter *i2c_adapter = (struct pios_i2c_adapter *)i2c_id; diff --git a/flight/pios/stm32f4xx/pios_i2c.c b/flight/pios/stm32f4xx/pios_i2c.c index 308ed82367..92bb65bc59 100644 --- a/flight/pios/stm32f4xx/pios_i2c.c +++ b/flight/pios/stm32f4xx/pios_i2c.c @@ -888,7 +888,7 @@ static bool i2c_adapter_callback_handler(struct pios_i2c_adapter *i2c_adapter, s // Execute user supplied function - if (i2c_adapter->callback()) { + if (i2c_adapter->callback(PIOS_I2C_TRANSFER_OK)) { *pxHigherPriorityTaskWoken = pdTRUE; } @@ -1048,7 +1048,7 @@ int32_t PIOS_I2C_Transfer(uint32_t i2c_id, const struct pios_i2c_txn txn_list[], struct pios_i2c_adapter *i2c_adapter = (struct pios_i2c_adapter *)i2c_id; if (!PIOS_I2C_validate(i2c_adapter)) { - return -1; + return PIOS_I2C_TRANSFER_DEVICE_ERROR; } PIOS_DEBUG_Assert(txn_list); @@ -1061,13 +1061,13 @@ int32_t PIOS_I2C_Transfer(uint32_t i2c_id, const struct pios_i2c_txn txn_list[], portTickType timeout; timeout = i2c_adapter->cfg->transfer_timeout_ms / portTICK_RATE_MS; if (xSemaphoreTake(i2c_adapter->sem_busy, timeout) == pdFALSE) { - return -2; + return PIOS_I2C_TRANSFER_BUSY; } #else PIOS_IRQ_Disable(); if (i2c_adapter->busy) { PIOS_IRQ_Enable(); - return -2; + return PIOS_I2C_TRANSFER_BUSY; } i2c_adapter->busy = 1; PIOS_IRQ_Enable(); @@ -1134,10 +1134,10 @@ int32_t PIOS_I2C_Transfer(uint32_t i2c_id, const struct pios_i2c_txn txn_list[], PIOS_IRQ_Enable(); #endif /* USE_FREERTOS */ - return !semaphore_success ? -2 : - i2c_adapter->bus_error ? -1 : - i2c_adapter->nack ? -3 : - 0; + return !semaphore_success ? PIOS_I2C_TRANSFER_TIMEOUT : + i2c_adapter->bus_error ? PIOS_I2C_TRANSFER_BUS_ERROR : + i2c_adapter->nack ? PIOS_I2C_TRANSFER_NACK : + PIOS_I2C_TRANSFER_OK; } static int32_t PIOS_I2C_Transfer_Callback_Internal(struct pios_i2c_adapter *i2c_adapter, const struct pios_i2c_txn txn_list[], uint32_t num_txns, pios_i2c_callback callback) @@ -1182,13 +1182,13 @@ int32_t PIOS_I2C_Transfer_Callback(uint32_t i2c_id, const struct pios_i2c_txn tx portTickType timeout; timeout = i2c_adapter->cfg->transfer_timeout_ms / portTICK_RATE_MS; if (xSemaphoreTake(i2c_adapter->sem_busy, timeout) == pdFALSE) { - return -2; + return PIOS_I2C_TRANSFER_BUSY; } #else PIOS_IRQ_Disable(); if (i2c_adapter->busy) { PIOS_IRQ_Enable(); - return -2; + return PIOS_I2C_TRANSFER_BUSY; } i2c_adapter->busy = 1; PIOS_IRQ_Enable(); @@ -1220,13 +1220,13 @@ int32_t PIOS_I2C_Transfer_CallbackFromISR(uint32_t i2c_id, const struct pios_i2c } if (!locked) { - return -2; + return PIOS_I2C_TRANSFER_BUSY; } #else PIOS_IRQ_Disable(); if (i2c_adapter->busy) { PIOS_IRQ_Enable(); - return -2; + return PIOS_I2C_TRANSFER_BUSY; } i2c_adapter->busy = 1; PIOS_IRQ_Enable(); From 429f8c41be21c03aef5802163daedec41ddd2c41 Mon Sep 17 00:00:00 2001 From: Vladimir Zidar Date: Wed, 14 Jun 2017 16:07:44 +0200 Subject: [PATCH 317/624] LP-529 [I2C] [MS5611] Remove PIOS_DELAY_WaitmS() and move (re)initialization into fsm. --- flight/pios/common/pios_ms5611.c | 217 ++++++++++++++----------------- flight/pios/inc/pios_i2c.h | 10 +- flight/pios/inc/pios_i2c_priv.h | 2 +- flight/pios/stm32f30x/pios_i2c.c | 14 +- 4 files changed, 108 insertions(+), 135 deletions(-) diff --git a/flight/pios/common/pios_ms5611.c b/flight/pios/common/pios_ms5611.c index d526750791..fdcdedaa4c 100644 --- a/flight/pios/common/pios_ms5611.c +++ b/flight/pios/common/pios_ms5611.c @@ -33,9 +33,6 @@ #include #define POW2(x) (1 << x) -// TODO: Clean this up. Getting around old constant. -#define PIOS_MS5611_OVERSAMPLING oversampling - // Option to change the interleave between Temp and Pressure conversions // Undef for normal operation #define PIOS_MS5611_SLOW_TEMP_RATE 20 @@ -44,9 +41,9 @@ #endif // Running moving average smoothing factor #define PIOS_MS5611_TEMP_SMOOTHING 10 -// -#define PIOS_MS5611_I2C_RETRIES 5 +#define PIOS_MS5611_INIT_DELAY_US 1000000 +#define PIOS_MS5611_RESET_DELAY_US 20000 /* Local Types */ typedef struct { @@ -61,16 +58,17 @@ typedef enum { typedef enum { MS5611_FSM_INIT = 0, + MS5611_FSM_CALIBRATION, MS5611_FSM_TEMPERATURE, MS5611_FSM_PRESSURE, MS5611_FSM_CALCULATE, } MS5611_FSM_State; -/* Glocal Variables */ -ConversionTypeTypeDef CurrentRead = MS5611_CONVERSION_TYPE_None; +static ConversionTypeTypeDef CurrentRead = MS5611_CONVERSION_TYPE_None; + +static MS5611CalibDataTypeDef CalibData; -/* Local Variables */ -MS5611CalibDataTypeDef CalibData; +static uint8_t temp_press_interleave_count = 1; /* Straight from the datasheet */ static uint32_t RawTemperature; @@ -78,15 +76,11 @@ static uint32_t RawPressure; static int64_t Pressure; static int64_t Temperature; static int64_t FilteredTemperature = INT32_MIN; -static int32_t lastConversionStart; -static uint32_t conversionDelayMs; -static uint32_t conversionDelayUs; +static uint32_t lastCommandTimeRaw; +static uint32_t commandDelayUs; -static int32_t PIOS_MS5611_Read(uint8_t address, uint8_t *buffer, uint8_t len); -static int32_t PIOS_MS5611_WriteCommand(uint8_t command); -static uint32_t PIOS_MS5611_GetDelay(); -static uint32_t PIOS_MS5611_GetDelayUs(); +static uint32_t conversionDelayUs; // Second order temperature compensation. Temperature offset static int64_t compensation_t2; @@ -96,8 +90,13 @@ static uint32_t oversampling; static const struct pios_ms5611_cfg *dev_cfg; static int32_t i2c_id; static PIOS_SENSORS_1Axis_SensorsWithTemp results; +static bool hw_error = false; -static bool sensorIsAlive = false; +// private functions +static int32_t PIOS_MS5611_Read(uint8_t address, uint8_t *buffer, uint8_t len); +static int32_t PIOS_MS5611_WriteCommand(uint8_t command, uint32_t delayuS); +static uint32_t PIOS_MS5611_GetDelayUs(void); +static void PIOS_MS5611_ReadCalibrationData(void); // sensor driver interface bool PIOS_MS5611_driver_Test(uintptr_t context); @@ -118,43 +117,15 @@ const PIOS_SENSORS_Driver PIOS_MS5611_Driver = { /** * Initialise the MS5611 sensor */ -int32_t ms5611_read_flag; void PIOS_MS5611_Init(const struct pios_ms5611_cfg *cfg, int32_t i2c_device) { - static uint32_t initTime; - - if (cfg) { - i2c_id = i2c_device; - - oversampling = cfg->oversampling; - conversionDelayMs = PIOS_MS5611_GetDelay(); - conversionDelayUs = PIOS_MS5611_GetDelayUs(); - - dev_cfg = cfg; // Store cfg before enabling interrupt - } else if (PIOS_DELAY_DiffuS(initTime) < 1000000) { // Do not reinitialize too often - return; - } - - initTime = PIOS_DELAY_GetRaw(); - - PIOS_MS5611_WriteCommand(MS5611_RESET); - PIOS_DELAY_WaitmS(20); - - uint8_t data[2]; + i2c_id = i2c_device; - // reset temperature compensation values - compensation_t2 = 0; - /* Calibration parameters */ - for (int i = 0; i < 6; i++) { - if (PIOS_MS5611_Read(MS5611_CALIB_ADDR + i * 2, data, 2) != 0) { - return; - } - CalibData.C[i] = (data[0] << 8) | data[1]; - } + oversampling = cfg->oversampling; + conversionDelayUs = PIOS_MS5611_GetDelayUs(); - sensorIsAlive = true; + dev_cfg = cfg; // Store cfg before enabling interrupt } - /** * Start the ADC conversion * \param[in] PresOrTemp BMP085_PRES_ADDR or BMP085_TEMP_ADDR @@ -162,54 +133,23 @@ void PIOS_MS5611_Init(const struct pios_ms5611_cfg *cfg, int32_t i2c_device) */ int32_t PIOS_MS5611_StartADC(ConversionTypeTypeDef Type) { - if (!sensorIsAlive) { /* if sensor is not alive, don't bother, wait for next poll to try to reinitialize */ - return -2; - } - /* Start the conversion */ if (Type == MS5611_CONVERSION_TYPE_TemperatureConv) { - if (PIOS_MS5611_WriteCommand(MS5611_TEMP_ADDR + oversampling) != 0) { + if (PIOS_MS5611_WriteCommand(MS5611_TEMP_ADDR + oversampling, conversionDelayUs) != 0) { return -2; } } else if (Type == MS5611_CONVERSION_TYPE_PressureConv) { - if (PIOS_MS5611_WriteCommand(MS5611_PRES_ADDR + oversampling) != 0) { + if (PIOS_MS5611_WriteCommand(MS5611_PRES_ADDR + oversampling, conversionDelayUs) != 0) { return -2; } } - lastConversionStart = PIOS_DELAY_GetRaw(); + CurrentRead = Type; return 0; } -/** - * @brief Return the delay for the current osr - */ -static uint32_t PIOS_MS5611_GetDelay() -{ - switch (oversampling) { - case MS5611_OSR_256: - return 1; - - case MS5611_OSR_512: - return 2; - - case MS5611_OSR_1024: - return 3; - - case MS5611_OSR_2048: - return 5; - - case MS5611_OSR_4096: - return 10; - - default: - break; - } - return 10; -} - /** * @brief Return the delay for the current osr in uS */ @@ -243,10 +183,6 @@ static uint32_t PIOS_MS5611_GetDelayUs() */ int32_t PIOS_MS5611_ReadADC(void) { - if (!sensorIsAlive) { /* if sensor is not alive, don't bother, wait for next poll to try to reinitialize */ - return -2; - } - uint8_t Data[3]; Data[0] = 0; @@ -256,18 +192,15 @@ int32_t PIOS_MS5611_ReadADC(void) if (CurrentRead == MS5611_CONVERSION_TYPE_None) { return -2; } - if (conversionDelayUs > PIOS_DELAY_DiffuS(lastConversionStart)) { - return -1; - } + static int64_t deltaTemp; + if (PIOS_MS5611_Read(MS5611_ADC_READ, Data, 3) != 0) { + return -2; + } + /* Read and store the 16bit result */ if (CurrentRead == MS5611_CONVERSION_TYPE_TemperatureConv) { - /* Read the temperature conversion */ - if (PIOS_MS5611_Read(MS5611_ADC_READ, Data, 3) != 0) { - return -2; - } - RawTemperature = (Data[0] << 16) | (Data[1] << 8) | Data[2]; // Difference between actual and reference temperature // dT = D2 - TREF = D2 - C5 * 2^8 @@ -288,10 +221,6 @@ int32_t PIOS_MS5611_ReadADC(void) int64_t Offset2 = 0; int64_t Sens2 = 0; - /* Read the pressure conversion */ - if (PIOS_MS5611_Read(MS5611_ADC_READ, Data, 3) != 0) { - return -2; - } // check if temperature is less than 20°C if (FilteredTemperature < 2000) { // Apply compensation @@ -327,6 +256,9 @@ int32_t PIOS_MS5611_ReadADC(void) // P = D1 * SENS - OFF = (D1 * SENS / 2^21 - OFF) / 2^15 Pressure = (((((int64_t)RawPressure) * Sens) / POW2(21)) - Offset) / POW2(15); } + + CurrentRead = MS5611_CONVERSION_TYPE_None; + return 0; } @@ -375,13 +307,15 @@ static int32_t PIOS_MS5611_Read(uint8_t address, uint8_t *buffer, uint8_t len) } }; - for (uint8_t retry = PIOS_MS5611_I2C_RETRIES; retry > 0; --retry) { - if (PIOS_I2C_Transfer(i2c_id, txn_list, NELEMENTS(txn_list)) == 0) { - return 0; - } + enum pios_i2c_transfer_result i2c_result = PIOS_I2C_Transfer(i2c_id, txn_list, NELEMENTS(txn_list)); + + if (i2c_result == PIOS_I2C_TRANSFER_OK) { + return 0; } - sensorIsAlive = false; + if (i2c_result != PIOS_I2C_TRANSFER_BUSY) { + hw_error = true; + } return -1; } @@ -393,7 +327,7 @@ static int32_t PIOS_MS5611_Read(uint8_t address, uint8_t *buffer, uint8_t len) * \return 0 if operation was successful * \return -1 if error during I2C transfer */ -static int32_t PIOS_MS5611_WriteCommand(uint8_t command) +static int32_t PIOS_MS5611_WriteCommand(uint8_t command, uint32_t delayuS) { const struct pios_i2c_txn txn_list[] = { { @@ -406,17 +340,46 @@ static int32_t PIOS_MS5611_WriteCommand(uint8_t command) , }; - for (uint8_t retry = PIOS_MS5611_I2C_RETRIES; retry > 0; --retry) { - if (PIOS_I2C_Transfer(i2c_id, txn_list, NELEMENTS(txn_list)) == 0) { - return 0; - } + lastCommandTimeRaw = PIOS_DELAY_GetRaw(); + commandDelayUs = delayuS; + + enum pios_i2c_transfer_result i2c_result = PIOS_I2C_Transfer(i2c_id, txn_list, NELEMENTS(txn_list)); + + if (i2c_result == PIOS_I2C_TRANSFER_OK) { + return 0; } - sensorIsAlive = false; + if (i2c_result != PIOS_I2C_TRANSFER_BUSY) { + hw_error = true; + } return -1; } +static void PIOS_MS5611_ReadCalibrationData() +{ + uint8_t data[2]; + + /* reset temperature compensation values */ + compensation_t2 = 0; + /* Calibration parameters */ + for (int i = 0; i < 6; i++) { + if (PIOS_MS5611_Read(MS5611_CALIB_ADDR + i * 2, data, 2) != 0) { + break; + } + CalibData.C[i] = (data[0] << 8) | data[1]; + } +} + +static void PIOS_MS5611_Reset() +{ + temp_press_interleave_count = 1; + hw_error = false; + + PIOS_MS5611_WriteCommand(MS5611_RESET, PIOS_MS5611_RESET_DELAY_US); +} + + /** * @brief Run self-test operation. * \return 0 if self-test succeed, -1 if failed @@ -473,32 +436,34 @@ void PIOS_MS5611_driver_fetch(void *data, __attribute__((unused)) uint8_t size, bool PIOS_MS5611_driver_poll(__attribute__((unused)) uintptr_t context) { - static uint8_t temp_press_interleave_count = 1; static MS5611_FSM_State next_state = MS5611_FSM_INIT; - if (!sensorIsAlive) { // try to reinit - PIOS_MS5611_Init(0, 0); + if (PIOS_DELAY_DiffuS(lastCommandTimeRaw) < commandDelayUs) { + return false; } - int32_t conversionResult = PIOS_MS5611_ReadADC(); + commandDelayUs = 0; + + PIOS_MS5611_ReadADC(); - if (__builtin_expect(conversionResult == -1, 1)) { - return false; // wait for conversion to complete - } else if (__builtin_expect(conversionResult == -2, 0)) { - temp_press_interleave_count = 1; - next_state = MS5611_FSM_INIT; - } switch (next_state) { case MS5611_FSM_INIT: + PIOS_MS5611_Reset(); + next_state = MS5611_FSM_CALIBRATION; + break; + case MS5611_FSM_CALIBRATION: + PIOS_MS5611_ReadCalibrationData(); + /* fall through to MS5611_FSM_TEMPERATURE */ + case MS5611_FSM_TEMPERATURE: PIOS_MS5611_StartADC(MS5611_CONVERSION_TYPE_TemperatureConv); next_state = MS5611_FSM_PRESSURE; - return false; + break; case MS5611_FSM_PRESSURE: PIOS_MS5611_StartADC(MS5611_CONVERSION_TYPE_PressureConv); next_state = MS5611_FSM_CALCULATE; - return false; + break; case MS5611_FSM_CALCULATE: temp_press_interleave_count--; @@ -519,6 +484,14 @@ bool PIOS_MS5611_driver_poll(__attribute__((unused)) uintptr_t context) // it should not be there PIOS_Assert(0); } + + if (hw_error) { + lastCommandTimeRaw = PIOS_DELAY_GetRaw(); + commandDelayUs = (next_state == MS5611_FSM_CALIBRATION) ? PIOS_MS5611_INIT_DELAY_US : 0; + CurrentRead = MS5611_CONVERSION_TYPE_None; + next_state = MS5611_FSM_INIT; + } + return false; } diff --git a/flight/pios/inc/pios_i2c.h b/flight/pios/inc/pios_i2c.h index b37537bda9..2f5a99e12a 100644 --- a/flight/pios/inc/pios_i2c.h +++ b/flight/pios/inc/pios_i2c.h @@ -74,11 +74,11 @@ enum pios_i2c_error_count { }; enum pios_i2c_transfer_result { - PIOS_I2C_TRANSFER_OK = 0, - PIOS_I2C_TRANSFER_BUSY = -2, - PIOS_I2C_TRANSFER_BUS_ERROR = -1, - PIOS_I2C_TRANSFER_NACK = -3, - PIOS_I2C_TRANSFER_TIMEOUT = -4, + PIOS_I2C_TRANSFER_OK = 0, + PIOS_I2C_TRANSFER_BUSY = -2, + PIOS_I2C_TRANSFER_BUS_ERROR = -1, + PIOS_I2C_TRANSFER_NACK = -3, + PIOS_I2C_TRANSFER_TIMEOUT = -4, PIOS_I2C_TRANSFER_UNSPECIFIED_ERROR = -5, PIOS_I2C_TRANSFER_DEVICE_ERROR = -6, }; diff --git a/flight/pios/inc/pios_i2c_priv.h b/flight/pios/inc/pios_i2c_priv.h index 7be45ba770..70e0840eb0 100644 --- a/flight/pios/inc/pios_i2c_priv.h +++ b/flight/pios/inc/pios_i2c_priv.h @@ -73,7 +73,7 @@ struct pios_i2c_adapter { uint8_t *active_byte; uint8_t *last_byte; - + enum pios_i2c_transfer_result *transfer_result; }; diff --git a/flight/pios/stm32f30x/pios_i2c.c b/flight/pios/stm32f30x/pios_i2c.c index 831c5f30e6..f269f96bb3 100644 --- a/flight/pios/stm32f30x/pios_i2c.c +++ b/flight/pios/stm32f30x/pios_i2c.c @@ -234,17 +234,17 @@ static void go_stopped(struct pios_i2c_adapter *i2c_adapter, bool *woken) I2C_ITConfig(i2c_adapter->cfg->regs, I2C_IT_ERRI | I2C_IT_TCI | I2C_IT_NACKI | I2C_IT_RXI | I2C_IT_STOPI | I2C_IT_TXI, DISABLE); enum pios_i2c_transfer_result result = - i2c_adapter->bus_error ? PIOS_I2C_TRANSFER_BUS_ERROR : - i2c_adapter->nack ? PIOS_I2C_TRANSFER_NACK : - PIOS_I2C_TRANSFER_OK; + i2c_adapter->bus_error ? PIOS_I2C_TRANSFER_BUS_ERROR : + i2c_adapter->nack ? PIOS_I2C_TRANSFER_NACK : + PIOS_I2C_TRANSFER_OK; if (i2c_adapter->transfer_result) { *(i2c_adapter->transfer_result) = result; } - + pios_i2c_callback cb = i2c_adapter->callback; - if(!cb) { /* No callback? Signal that we are done */ + if (!cb) { /* No callback? Signal that we are done */ #ifdef PIOS_INCLUDE_FREERTOS signed portBASE_TYPE pxHigherPriorityTaskWoken = pdFALSE; if (xSemaphoreGiveFromISR(i2c_adapter->sem_ready, &pxHigherPriorityTaskWoken) != pdTRUE) { @@ -271,7 +271,7 @@ static void go_stopped(struct pios_i2c_adapter *i2c_adapter, bool *woken) PIOS_IRQ_Enable(); #endif /* PIOS_INCLUDE_FREERTOS */ - if(cb && cb(result)) { /* User provided callback? Do it, but with bus unlocked */ + if (cb && cb(result)) { /* User provided callback? Do it, but with bus unlocked */ *woken = true; } } @@ -635,7 +635,7 @@ int32_t PIOS_I2C_Transfer(uint32_t i2c_id, const struct pios_i2c_txn txn_list[], // FIXME: only supports transfer sizes up to 255 bytes struct pios_i2c_adapter *i2c_adapter = (struct pios_i2c_adapter *)i2c_id; enum pios_i2c_transfer_result result = PIOS_I2C_TRANSFER_UNSPECIFIED_ERROR; - + bool valid = PIOS_I2C_validate(i2c_adapter); PIOS_Assert(valid) From ee7d630e3e6fcc38ad2653741e992806baae2f37 Mon Sep 17 00:00:00 2001 From: Laurent Lalanne Date: Sat, 17 Jun 2017 16:49:40 +0200 Subject: [PATCH 318/624] LP-482 Fix Complementary Mag integral sign --- flight/modules/StateEstimation/filtercf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flight/modules/StateEstimation/filtercf.c b/flight/modules/StateEstimation/filtercf.c index fae8d1f8c7..714f5d938c 100644 --- a/flight/modules/StateEstimation/filtercf.c +++ b/flight/modules/StateEstimation/filtercf.c @@ -423,7 +423,7 @@ static filterResult complementaryFilter(struct data *this, float gyro[3], float this->gyroBias[0] -= accel_err[0] * this->attitudeSettings.AccelKi - gyro[0] * this->rollPitchBiasRate; this->gyroBias[1] -= accel_err[1] * this->attitudeSettings.AccelKi - gyro[1] * this->rollPitchBiasRate; if (this->useMag) { - this->gyroBias[2] -= -mag_err[2] * this->attitudeSettings.MagKi - gyro[2] * this->rollPitchBiasRate; + this->gyroBias[2] -= mag_err[2] * this->attitudeSettings.MagKi - gyro[2] * this->rollPitchBiasRate; } else { this->gyroBias[2] -= -gyro[2] * this->rollPitchBiasRate; } From 684e0dc14f1e517fe88bce5c2213e270a3a03f15 Mon Sep 17 00:00:00 2001 From: Laurent Lalanne Date: Sat, 17 Jun 2017 16:50:58 +0200 Subject: [PATCH 319/624] LP-482 Increase temporary MagKp for initialisation --- flight/modules/StateEstimation/filtercf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/flight/modules/StateEstimation/filtercf.c b/flight/modules/StateEstimation/filtercf.c index 714f5d938c..62c15adcf0 100644 --- a/flight/modules/StateEstimation/filtercf.c +++ b/flight/modules/StateEstimation/filtercf.c @@ -315,7 +315,7 @@ static filterResult complementaryFilter(struct data *this, float gyro[3], float this->attitudeSettings.YawBiasRate = 0.23f; this->accel_filter_enabled = false; this->rollPitchBiasRate = 0.01f; - this->attitudeSettings.MagKp = this->magCalibrated ? 1.0f : 0.0f; + this->attitudeSettings.MagKp = this->magCalibrated ? 20.0f : 0.0f; PIOS_NOTIFY_StartNotification(NOTIFY_DRAW_ATTENTION, NOTIFY_PRIORITY_REGULAR); } else if ((this->attitudeSettings.ZeroDuringArming == ATTITUDESETTINGS_ZERODURINGARMING_TRUE) && (flightStatus.Armed == FLIGHTSTATUS_ARMED_ARMING)) { this->attitudeSettings.AccelKp = 1.0f; @@ -323,7 +323,7 @@ static filterResult complementaryFilter(struct data *this, float gyro[3], float this->attitudeSettings.YawBiasRate = 0.23f; this->accel_filter_enabled = false; this->rollPitchBiasRate = 0.01f; - this->attitudeSettings.MagKp = this->magCalibrated ? 1.0f : 0.0f; + this->attitudeSettings.MagKp = this->magCalibrated ? 20.0f : 0.0f; this->init = 0; PIOS_NOTIFY_StartNotification(NOTIFY_DRAW_ATTENTION, NOTIFY_PRIORITY_REGULAR); } else if (this->init == 0) { From ad23d188b5eb1241fe605221c851f380ddd74e2d Mon Sep 17 00:00:00 2001 From: Laurent Lalanne Date: Sat, 17 Jun 2017 17:03:09 +0200 Subject: [PATCH 320/624] LP-482 Complementary+Mag : Increase MagKp and MagKi values --- shared/uavobjectdefinition/attitudesettings.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shared/uavobjectdefinition/attitudesettings.xml b/shared/uavobjectdefinition/attitudesettings.xml index e45ec747d0..82540609a9 100644 --- a/shared/uavobjectdefinition/attitudesettings.xml +++ b/shared/uavobjectdefinition/attitudesettings.xml @@ -5,8 +5,8 @@ - - + + From ed28311841cf1600db5b125434d7f9229a374d79 Mon Sep 17 00:00:00 2001 From: Laurent Lalanne Date: Sat, 17 Jun 2017 19:21:55 +0200 Subject: [PATCH 321/624] LP-482 Complementary+Mag : Allow fast convergence for mag --- flight/modules/StateEstimation/filtercf.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/flight/modules/StateEstimation/filtercf.c b/flight/modules/StateEstimation/filtercf.c index 62c15adcf0..8850880ef6 100644 --- a/flight/modules/StateEstimation/filtercf.c +++ b/flight/modules/StateEstimation/filtercf.c @@ -7,7 +7,8 @@ * @{ * * @file filtercf.c - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2013. + * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017. + * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2013. * @brief Complementary filter to calculate Attitude from Accels and Gyros * and optionally magnetometers: * WARNING: Will drift if the mean acceleration force doesn't point @@ -49,7 +50,9 @@ #define CALIBRATION_DELAY_MS 4000 #define CALIBRATION_DURATION_MS 6000 +#define RELOADSETTINGS_DELAY_MS 1000 #define VARIANCE_WINDOW_SIZE 40 + // Private types struct data { AttitudeSettingsData attitudeSettings; @@ -68,6 +71,7 @@ struct data { float rollPitchBiasRate; int32_t timeval; int32_t starttime; + int32_t inittime; uint8_t init; bool magCalibrated; pw_variance_t gyro_var[3]; @@ -327,13 +331,17 @@ static filterResult complementaryFilter(struct data *this, float gyro[3], float this->init = 0; PIOS_NOTIFY_StartNotification(NOTIFY_DRAW_ATTENTION, NOTIFY_PRIORITY_REGULAR); } else if (this->init == 0) { - // Reload settings (all the rates) - AttitudeSettingsGet(&this->attitudeSettings); this->rollPitchBiasRate = 0.0f; if (this->accel_alpha > 0.0f) { this->accel_filter_enabled = true; } - this->init = 1; + this->inittime = xTaskGetTickCount(); + this->init = 1; + // Allow running filter with custom MagKp for some time before reload settings + } else if (this->init == 1 && (!this->magCalibrated || (xTaskGetTickCount() - this->inittime > RELOADSETTINGS_DELAY_MS / portTICK_RATE_MS))) { + // Reload settings (all the rates) + AttitudeSettingsGet(&this->attitudeSettings); + this->init = 2; } // Compute the dT using the cpu clock @@ -473,7 +481,7 @@ static filterResult complementaryFilter(struct data *this, float gyro[3], float return FILTERRESULT_WARNING; } - if (this->init) { + if (this->init > 0) { return FILTERRESULT_OK; } else { return FILTERRESULT_CRITICAL; // return "critical" for now, so users can see the zeroing period, switch to more graceful notification later From 4ba064b017cc63088f9cee7a9fa200299130415c Mon Sep 17 00:00:00 2001 From: Jan NIJS Date: Sun, 18 Jun 2017 12:26:00 +0200 Subject: [PATCH 322/624] LP-533 incorrect MCU pin used to toggle inverter for rcvr port on Sparky2 Bug introduced by LP-480. The wrong MCU pin is used for toggling the input inversion. This inverted the serial signal when it should not be inverted. ibus reception and possibly other serial receiver protocols where not working. PC4 was controlled, but according to the schematic, PC6 is connected to the xor port. PC4 is actually connected to the gyro interrupt. This bug explains another issue I saw from time to time. After a restart of the Sparky2 board, gyro and accelerometer graphs remained locked at 0. Making the board unusable for flight. --- flight/targets/boards/sparky2/pios_board.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flight/targets/boards/sparky2/pios_board.h b/flight/targets/boards/sparky2/pios_board.h index b4c17c0fea..9afe473936 100644 --- a/flight/targets/boards/sparky2/pios_board.h +++ b/flight/targets/boards/sparky2/pios_board.h @@ -145,7 +145,7 @@ extern uint32_t pios_i2c_flexiport_adapter_id; // Inverter for SBUS handling #define PIOS_USART_INVERTER_PORT USART6 #define PIOS_USART_INVERTER_GPIO GPIOC -#define PIOS_USART_INVERTER_PIN GPIO_Pin_4 +#define PIOS_USART_INVERTER_PIN GPIO_Pin_6 #define PIOS_USART_INVERTER_ENABLE Bit_SET #define PIOS_USART_INVERTER_DISABLE Bit_RESET From 20ac6ed1e39d9d0d618dab8b23c272f78492de3c Mon Sep 17 00:00:00 2001 From: Laurent Lalanne Date: Fri, 26 May 2017 12:39:47 +0200 Subject: [PATCH 323/624] LP-520 Oplink : Send RSSI value as PPM output channel --- flight/pios/stm32f10x/pios_ppm_out.c | 2 +- .../boards/oplinkmini/firmware/pios_board.c | 11 +++++++++ shared/uavobjectdefinition/oplinksettings.xml | 23 ++++++++++--------- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/flight/pios/stm32f10x/pios_ppm_out.c b/flight/pios/stm32f10x/pios_ppm_out.c index d479341775..9f4a7adbbf 100644 --- a/flight/pios/stm32f10x/pios_ppm_out.c +++ b/flight/pios/stm32f10x/pios_ppm_out.c @@ -35,7 +35,7 @@ #include "pios_ppm_out_priv.h" #define PIOS_PPM_OUT_MAX_DEVS 1 -#define PIOS_PPM_OUT_MAX_CHANNELS 8 +#define PIOS_PPM_OUT_MAX_CHANNELS 8 + 1 // 8 RC channels + Rssi #define PIOS_PPM_OUT_FRAME_PERIOD_US 22500 // microseconds #define PIOS_PPM_OUT_HIGH_PULSE_US 400 // microseconds #define PIOS_PPM_OUT_MIN_CHANNEL_PULSE_US 1000 // microseconds diff --git a/flight/targets/boards/oplinkmini/firmware/pios_board.c b/flight/targets/boards/oplinkmini/firmware/pios_board.c index 61730031e8..2e84df6b7e 100644 --- a/flight/targets/boards/oplinkmini/firmware/pios_board.c +++ b/flight/targets/boards/oplinkmini/firmware/pios_board.c @@ -57,6 +57,7 @@ uint32_t pios_com_gcs_id = 0; uint32_t pios_com_gcs_out_id = 0; #if defined(PIOS_INCLUDE_PPM_OUT) uint32_t pios_ppm_out_id = 0; +bool ppm_rssi = false; #endif #if defined(PIOS_INCLUDE_RFM22B) #include @@ -142,6 +143,7 @@ void PIOS_Board_Init(void) bool ppm_only = (oplinkSettings.LinkType == OPLINKSETTINGS_LINKTYPE_CONTROL); bool ppm_mode = ((oplinkSettings.LinkType == OPLINKSETTINGS_LINKTYPE_CONTROL) || (oplinkSettings.LinkType == OPLINKSETTINGS_LINKTYPE_DATAANDCONTROL)); + ppm_rssi = (oplinkSettings.PPMOutRSSI == OPLINKSETTINGS_PPMOUTRSSI_CH9); bool servo_main = false; bool servo_flexi = false; @@ -441,6 +443,15 @@ static void PIOS_Board_PPM_callback(__attribute__((unused)) uint32_t context, co PIOS_PPM_OUT_Set(PIOS_PPM_OUTPUT, i, channels[i]); } } + // Rssi channel output is added after RC channels + // Output Rssi from 1000µs to 2000µs (-127dBm to -16dBm range) + if (ppm_rssi) { + int8_t rssi; + int16_t ppm_value; + OPLinkStatusRSSIGet(&rssi); + ppm_value = 1000 + ((rssi + 127) * 9); + PIOS_PPM_OUT_Set(PIOS_PPM_OUTPUT, RFM22B_PPM_NUM_CHANNELS, ppm_value); + } } #if defined(PIOS_INCLUDE_SERVO) for (uint8_t i = 0; i < servo_count; ++i) { diff --git a/shared/uavobjectdefinition/oplinksettings.xml b/shared/uavobjectdefinition/oplinksettings.xml index 91a1adc731..bcf17f6265 100644 --- a/shared/uavobjectdefinition/oplinksettings.xml +++ b/shared/uavobjectdefinition/oplinksettings.xml @@ -1,22 +1,23 @@ OPLink configurations options. - - - + + + - + + - - - - - + + + + + - + @@ -24,7 +25,7 @@ - + From 673dbeee4086914986905b68a30fa86dfe13ea59 Mon Sep 17 00:00:00 2001 From: Laurent Lalanne Date: Fri, 26 May 2017 15:32:14 +0200 Subject: [PATCH 324/624] LP-520 Oplink : Add PPM Rssi option to Gui - Allow only one PPM port --- .../src/plugins/config/configoplinkwidget.cpp | 18 ++++++++++++++++-- ground/gcs/src/plugins/config/oplink.ui | 13 +++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/ground/gcs/src/plugins/config/configoplinkwidget.cpp b/ground/gcs/src/plugins/config/configoplinkwidget.cpp index cb53e3444c..37a01b7734 100644 --- a/ground/gcs/src/plugins/config/configoplinkwidget.cpp +++ b/ground/gcs/src/plugins/config/configoplinkwidget.cpp @@ -82,6 +82,7 @@ ConfigOPLinkWidget::ConfigOPLinkWidget(QWidget *parent) : ConfigTaskWidget(paren addWidgetBinding("OPLinkSettings", "MaxRFPower", m_oplink->MaxRFTxPower); addWidgetBinding("OPLinkSettings", "MainPort", m_oplink->MainPort); addWidgetBinding("OPLinkSettings", "FlexiPort", m_oplink->FlexiPort); + addWidgetBinding("OPLinkSettings", "PPMOutRSSI", m_oplink->PPMoutRssi); addWidgetBinding("OPLinkSettings", "RadioPriStream", m_oplink->RadioPriStream); addWidgetBinding("OPLinkSettings", "RadioAuxStream", m_oplink->RadioAuxStream); addWidgetBinding("OPLinkSettings", "VCPBridge", m_oplink->VCPBridge); @@ -263,6 +264,7 @@ void ConfigOPLinkWidget::updateSettings() bool is_receiver = isComboboxOptionSelected(m_oplink->Protocol, OPLinkSettings::PROTOCOL_OPLINKRECEIVER); bool is_oplink = (is_receiver || is_coordinator); bool is_ppm_only = isComboboxOptionSelected(m_oplink->LinkType, OPLinkSettings::LINKTYPE_CONTROL); + bool is_ppm = isComboboxOptionSelected(m_oplink->LinkType, OPLinkSettings::LINKTYPE_DATAANDCONTROL); bool is_main_serial = isComboboxOptionSelected(m_oplink->MainPort, OPLinkSettings::MAINPORT_SERIAL); bool is_main_telem = isComboboxOptionSelected(m_oplink->MainPort, OPLinkSettings::MAINPORT_TELEMETRY); bool is_flexi_serial = isComboboxOptionSelected(m_oplink->FlexiPort, OPLinkSettings::FLEXIPORT_SERIAL); @@ -277,6 +279,9 @@ void ConfigOPLinkWidget::updateSettings() bool is_stream_flexi = isComboboxOptionSelected(m_oplink->RadioPriStream, OPLinkSettings::RADIOPRISTREAM_FLEXI) || isComboboxOptionSelected(m_oplink->RadioAuxStream, OPLinkSettings::RADIOAUXSTREAM_FLEXI); + bool is_flexi_ppm = isComboboxOptionSelected(m_oplink->FlexiPort, OPLinkSettings::FLEXIPORT_PPM); + bool is_main_ppm = isComboboxOptionSelected(m_oplink->MainPort, OPLinkSettings::MAINPORT_PPM); + if (!is_stream_main && !is_vcp_main && (is_main_serial || is_main_telem)) { setComboboxSelectedOption(m_oplink->MainPort, OPLinkSettings::MAINPORT_DISABLED); is_main_serial = false; @@ -295,6 +300,9 @@ void ConfigOPLinkWidget::updateSettings() m_oplink->MainPort->setEnabled(is_oplink || is_vcp_main); m_oplink->FlexiPort->setEnabled(is_oplink || is_vcp_flexi); + + m_oplink->PPMoutRssi->setEnabled(is_receiver && (is_ppm || is_ppm_only) && (is_flexi_ppm || is_main_ppm)); + m_oplink->MainComSpeed->setEnabled(is_oplink && !is_ppm_only && !is_vcp_main && (is_main_serial || is_main_telem)); m_oplink->FlexiComSpeed->setEnabled(is_oplink && !is_ppm_only && !is_vcp_flexi && (is_flexi_serial || is_flexi_telem)); m_oplink->CoordID->setEnabled(is_receiver || is_openlrs); @@ -416,6 +424,9 @@ void ConfigOPLinkWidget::mainPortChanged() { switch (getComboboxSelectedOption(m_oplink->MainPort)) { case OPLinkSettings::MAINPORT_PPM: + if (isComboboxOptionSelected(m_oplink->FlexiPort, OPLinkSettings::FLEXIPORT_PPM)) { + setComboboxSelectedOption(m_oplink->FlexiPort, OPLinkSettings::FLEXIPORT_DISABLED); + } case OPLinkSettings::MAINPORT_PWM: case OPLinkSettings::MAINPORT_DISABLED: if (isComboboxOptionSelected(m_oplink->RadioPriStream, OPLinkSettings::RADIOPRISTREAM_MAIN)) { @@ -439,12 +450,16 @@ void ConfigOPLinkWidget::mainPortChanged() default: break; } + updateSettings(); } void ConfigOPLinkWidget::flexiPortChanged() { switch (getComboboxSelectedOption(m_oplink->FlexiPort)) { case OPLinkSettings::FLEXIPORT_PPM: + if (isComboboxOptionSelected(m_oplink->MainPort, OPLinkSettings::MAINPORT_PPM)) { + setComboboxSelectedOption(m_oplink->MainPort, OPLinkSettings::MAINPORT_DISABLED); + } case OPLinkSettings::FLEXIPORT_PWM: case OPLinkSettings::FLEXIPORT_DISABLED: if (isComboboxOptionSelected(m_oplink->RadioPriStream, OPLinkSettings::RADIOPRISTREAM_FLEXI)) { @@ -462,14 +477,13 @@ void ConfigOPLinkWidget::flexiPortChanged() if (isComboboxOptionSelected(m_oplink->MainPort, OPLinkSettings::MAINPORT_TELEMETRY)) { setComboboxSelectedOption(m_oplink->MainPort, OPLinkSettings::MAINPORT_SERIAL); } - m_oplink->FlexiComSpeed->setEnabled(true); - break; case OPLinkSettings::FLEXIPORT_SERIAL: m_oplink->FlexiComSpeed->setEnabled(true); break; default: break; } + updateSettings(); } void ConfigOPLinkWidget::radioPriStreamChanged() diff --git a/ground/gcs/src/plugins/config/oplink.ui b/ground/gcs/src/plugins/config/oplink.ui index dddcebb76b..f71ae04691 100644 --- a/ground/gcs/src/plugins/config/oplink.ui +++ b/ground/gcs/src/plugins/config/oplink.ui @@ -2143,6 +2143,19 @@ Leave blank to use autogenerated Device ID. + + + + + + + PPM RSSI Output + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + From d11b2bbd51e225b8b1065c400639423cd536632e Mon Sep 17 00:00:00 2001 From: Laurent Lalanne Date: Fri, 26 May 2017 19:30:28 +0200 Subject: [PATCH 325/624] LP-520 Oplink : Remove outdated comments --- flight/targets/boards/oplinkmini/firmware/pios_board.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/flight/targets/boards/oplinkmini/firmware/pios_board.c b/flight/targets/boards/oplinkmini/firmware/pios_board.c index 2e84df6b7e..053658d4e3 100644 --- a/flight/targets/boards/oplinkmini/firmware/pios_board.c +++ b/flight/targets/boards/oplinkmini/firmware/pios_board.c @@ -253,7 +253,6 @@ void PIOS_Board_Init(void) if (is_coordinator) { PIOS_BOARD_IO_Configure_PPM_RCVR(&pios_ppm_main_cfg); } - // For some reason, PPM output on the main port doesn't work. #if defined(PIOS_INCLUDE_PPM_OUT) else { PIOS_PPM_Out_Init(&pios_ppm_out_id, &pios_main_ppm_out_cfg); @@ -307,7 +306,6 @@ void PIOS_Board_Init(void) if (is_coordinator) { PIOS_BOARD_IO_Configure_PPM_RCVR(&pios_ppm_flexi_cfg); } - // For some reason, PPM output on the flexi port doesn't work. #if defined(PIOS_INCLUDE_PPM_OUT) else { PIOS_PPM_Out_Init(&pios_ppm_out_id, &pios_flexi_ppm_out_cfg); From 9bc63139c39a30ab5376279e8c4cb65f6db2dfc7 Mon Sep 17 00:00:00 2001 From: Laurent Lalanne Date: Sun, 11 Jun 2017 16:11:42 +0200 Subject: [PATCH 326/624] LP-520 Remove Ch9 from UAVO --- flight/targets/boards/oplinkmini/firmware/pios_board.c | 2 +- shared/uavobjectdefinition/oplinksettings.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/flight/targets/boards/oplinkmini/firmware/pios_board.c b/flight/targets/boards/oplinkmini/firmware/pios_board.c index 053658d4e3..e808edf7b1 100644 --- a/flight/targets/boards/oplinkmini/firmware/pios_board.c +++ b/flight/targets/boards/oplinkmini/firmware/pios_board.c @@ -143,7 +143,7 @@ void PIOS_Board_Init(void) bool ppm_only = (oplinkSettings.LinkType == OPLINKSETTINGS_LINKTYPE_CONTROL); bool ppm_mode = ((oplinkSettings.LinkType == OPLINKSETTINGS_LINKTYPE_CONTROL) || (oplinkSettings.LinkType == OPLINKSETTINGS_LINKTYPE_DATAANDCONTROL)); - ppm_rssi = (oplinkSettings.PPMOutRSSI == OPLINKSETTINGS_PPMOUTRSSI_CH9); + ppm_rssi = (oplinkSettings.PPMOutRSSI == OPLINKSETTINGS_PPMOUTRSSI_TRUE); bool servo_main = false; bool servo_flexi = false; diff --git a/shared/uavobjectdefinition/oplinksettings.xml b/shared/uavobjectdefinition/oplinksettings.xml index bcf17f6265..c4d5189e47 100644 --- a/shared/uavobjectdefinition/oplinksettings.xml +++ b/shared/uavobjectdefinition/oplinksettings.xml @@ -9,7 +9,7 @@ - + From 86a8eded5117b85e13f1c0bd05bd81c171132737 Mon Sep 17 00:00:00 2001 From: Laurent Lalanne Date: Sun, 11 Jun 2017 16:12:24 +0200 Subject: [PATCH 327/624] LP-520 Update UI using checkbox for Rssi PPM output --- ground/gcs/src/plugins/config/oplink.ui | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/ground/gcs/src/plugins/config/oplink.ui b/ground/gcs/src/plugins/config/oplink.ui index f71ae04691..21ea15a58a 100644 --- a/ground/gcs/src/plugins/config/oplink.ui +++ b/ground/gcs/src/plugins/config/oplink.ui @@ -2143,16 +2143,19 @@ Leave blank to use autogenerated Device ID. - - - - - + + + + Add RSSI to the PPM output stream (Ch9) + + + Qt::LeftToRight + - PPM RSSI Output + RSSI to PPM - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + false From 34d27dc854fb4e5e47091e8a22974bcb1090222b Mon Sep 17 00:00:00 2001 From: Laurent Lalanne Date: Sun, 18 Jun 2017 10:52:42 +0200 Subject: [PATCH 328/624] LP-520 Change checkbox name --- ground/gcs/src/plugins/config/oplink.ui | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ground/gcs/src/plugins/config/oplink.ui b/ground/gcs/src/plugins/config/oplink.ui index 21ea15a58a..ef31f76f5b 100644 --- a/ground/gcs/src/plugins/config/oplink.ui +++ b/ground/gcs/src/plugins/config/oplink.ui @@ -2143,7 +2143,7 @@ Leave blank to use autogenerated Device ID. - + Add RSSI to the PPM output stream (Ch9) @@ -2152,7 +2152,7 @@ Leave blank to use autogenerated Device ID. Qt::LeftToRight - RSSI to PPM + Send RSSI over PPM (Ch9) false From c2a7582bd9a40c6de69322ac2e3ce52ba64207c8 Mon Sep 17 00:00:00 2001 From: Laurent Lalanne Date: Mon, 19 Jun 2017 09:38:05 +0200 Subject: [PATCH 329/624] LP-482 Changes from review, add defines --- flight/modules/StateEstimation/filtercf.c | 29 +++++++++++++---------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/flight/modules/StateEstimation/filtercf.c b/flight/modules/StateEstimation/filtercf.c index 8850880ef6..e72243762b 100644 --- a/flight/modules/StateEstimation/filtercf.c +++ b/flight/modules/StateEstimation/filtercf.c @@ -51,8 +51,13 @@ #define CALIBRATION_DELAY_MS 4000 #define CALIBRATION_DURATION_MS 6000 #define RELOADSETTINGS_DELAY_MS 1000 +#define CONVERGENCE_MAGKP 20.0f #define VARIANCE_WINDOW_SIZE 40 +#define UNDONE 0 +#define DONE 1 +#define RUN 2 + // Private types struct data { AttitudeSettingsData attitudeSettings; @@ -252,7 +257,7 @@ static filterResult complementaryFilter(struct data *this, float gyro[3], float AttitudeStateData attitudeState; // base on previous state AttitudeStateGet(&attitudeState); - this->init = 0; + this->init = UNDONE; // Set initial attitude. Use accels to determine roll and pitch, rotate magnetic measurement accordingly, // so pseudo "north" vector can be estimated even if the board is not level @@ -292,7 +297,7 @@ static filterResult complementaryFilter(struct data *this, float gyro[3], float return FILTERRESULT_OK; // must return OK on initial initialization, so attitude will init with a valid quaternion } // check whether copter is steady - if (this->init == 0 && this->attitudeSettings.InitialZeroWhenBoardSteady == ATTITUDESETTINGS_INITIALZEROWHENBOARDSTEADY_TRUE) { + if (this->init == UNDONE && this->attitudeSettings.InitialZeroWhenBoardSteady == ATTITUDESETTINGS_INITIALZEROWHENBOARDSTEADY_TRUE) { pseudo_windowed_variance_push_sample(&this->gyro_var[0], gyro[0]); pseudo_windowed_variance_push_sample(&this->gyro_var[1], gyro[1]); pseudo_windowed_variance_push_sample(&this->gyro_var[2], gyro[2]); @@ -308,18 +313,18 @@ static filterResult complementaryFilter(struct data *this, float gyro[3], float } - if (this->init == 0 && xTaskGetTickCount() - this->starttime < CALIBRATION_DELAY_MS / portTICK_RATE_MS) { + if (this->init == UNDONE && xTaskGetTickCount() - this->starttime < CALIBRATION_DELAY_MS / portTICK_RATE_MS) { // wait 4 seconds for the user to get his hands off in case the board was just powered this->timeval = PIOS_DELAY_GetRaw(); return FILTERRESULT_ERROR; - } else if (this->init == 0 && xTaskGetTickCount() - this->starttime < (CALIBRATION_DELAY_MS + CALIBRATION_DURATION_MS) / portTICK_RATE_MS) { + } else if (this->init == UNDONE && xTaskGetTickCount() - this->starttime < (CALIBRATION_DELAY_MS + CALIBRATION_DURATION_MS) / portTICK_RATE_MS) { // For first 6 seconds use accels to get gyro bias this->attitudeSettings.AccelKp = 1.0f; this->attitudeSettings.AccelKi = 0.0f; this->attitudeSettings.YawBiasRate = 0.23f; this->accel_filter_enabled = false; this->rollPitchBiasRate = 0.01f; - this->attitudeSettings.MagKp = this->magCalibrated ? 20.0f : 0.0f; + this->attitudeSettings.MagKp = this->magCalibrated ? CONVERGENCE_MAGKP : 0.0f; PIOS_NOTIFY_StartNotification(NOTIFY_DRAW_ATTENTION, NOTIFY_PRIORITY_REGULAR); } else if ((this->attitudeSettings.ZeroDuringArming == ATTITUDESETTINGS_ZERODURINGARMING_TRUE) && (flightStatus.Armed == FLIGHTSTATUS_ARMED_ARMING)) { this->attitudeSettings.AccelKp = 1.0f; @@ -327,21 +332,21 @@ static filterResult complementaryFilter(struct data *this, float gyro[3], float this->attitudeSettings.YawBiasRate = 0.23f; this->accel_filter_enabled = false; this->rollPitchBiasRate = 0.01f; - this->attitudeSettings.MagKp = this->magCalibrated ? 20.0f : 0.0f; - this->init = 0; + this->attitudeSettings.MagKp = this->magCalibrated ? CONVERGENCE_MAGKP : 0.0f; + this->init = UNDONE; PIOS_NOTIFY_StartNotification(NOTIFY_DRAW_ATTENTION, NOTIFY_PRIORITY_REGULAR); - } else if (this->init == 0) { + } else if (this->init == UNDONE) { this->rollPitchBiasRate = 0.0f; if (this->accel_alpha > 0.0f) { this->accel_filter_enabled = true; } this->inittime = xTaskGetTickCount(); - this->init = 1; + this->init = DONE; // Allow running filter with custom MagKp for some time before reload settings - } else if (this->init == 1 && (!this->magCalibrated || (xTaskGetTickCount() - this->inittime > RELOADSETTINGS_DELAY_MS / portTICK_RATE_MS))) { + } else if (this->init == DONE && (!this->magCalibrated || (xTaskGetTickCount() - this->inittime > RELOADSETTINGS_DELAY_MS / portTICK_RATE_MS))) { // Reload settings (all the rates) AttitudeSettingsGet(&this->attitudeSettings); - this->init = 2; + this->init = RUN; } // Compute the dT using the cpu clock @@ -481,7 +486,7 @@ static filterResult complementaryFilter(struct data *this, float gyro[3], float return FILTERRESULT_WARNING; } - if (this->init > 0) { + if (this->init != UNDONE) { return FILTERRESULT_OK; } else { return FILTERRESULT_CRITICAL; // return "critical" for now, so users can see the zeroing period, switch to more graceful notification later From 1b624d7de3fb36293e171cdcb01155f22219a29b Mon Sep 17 00:00:00 2001 From: Laurent Lalanne Date: Mon, 19 Jun 2017 12:10:06 +0200 Subject: [PATCH 330/624] LP-534 MagStatus trouble: disable the corrected mag debug from EKF --- flight/modules/StateEstimation/filterekf.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/flight/modules/StateEstimation/filterekf.c b/flight/modules/StateEstimation/filterekf.c index 88943a2f42..25d4630130 100644 --- a/flight/modules/StateEstimation/filterekf.c +++ b/flight/modules/StateEstimation/filterekf.c @@ -223,7 +223,6 @@ static filterResult filter(stateFilter *self, stateEstimation *state) UNSET_MASK(state->updated, SENSORUPDATES_vel); UNSET_MASK(state->updated, SENSORUPDATES_attitude); UNSET_MASK(state->updated, SENSORUPDATES_gyro); - UNSET_MASK(state->updated, SENSORUPDATES_mag); return FILTERRESULT_OK; } @@ -387,15 +386,18 @@ static filterResult filter(stateFilter *self, stateEstimation *state) local_down[2] *= MagStrength; rot_mult(R, local_down, this->work.mag); } + // From Eric: "exporting it in MagState was meant for debugging, but I think it makes a + // lot of sense to have a "corrected" magnetometer reading available in the system." + // TODO: Should move above calc to filtermag, updating from here cause trouble with the state->MagStatus (LP-534) // debug rotated mags - state->mag[0] = this->work.mag[0]; - state->mag[1] = this->work.mag[1]; - state->mag[2] = this->work.mag[2]; - state->updated |= SENSORUPDATES_mag; - } else { - // mag state is delayed until EKF processed it, allows overriding/debugging magnetometer estimate - UNSET_MASK(state->updated, SENSORUPDATES_mag); - } + // state->mag[0] = this->work.mag[0]; + // state->mag[1] = this->work.mag[1]; + // state->mag[2] = this->work.mag[2]; + // state->updated |= SENSORUPDATES_mag; + } // else { + // mag state is delayed until EKF processed it, allows overriding/debugging magnetometer estimate + // UNSET_MASK(state->updated, SENSORUPDATES_mag); + // } if (IS_SET(this->work.updated, SENSORUPDATES_baro)) { sensors |= BARO_SENSOR; From ded673442c34b4cdb5067fd93ef7b10d4875a71d Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Thu, 22 Jun 2017 13:42:22 +0200 Subject: [PATCH 331/624] LP-496 config stabilization: copy banks from/to were reversed --- ground/gcs/src/plugins/config/configstabilizationwidget.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ground/gcs/src/plugins/config/configstabilizationwidget.cpp b/ground/gcs/src/plugins/config/configstabilizationwidget.cpp index 046c31f439..1ab5b96787 100644 --- a/ground/gcs/src/plugins/config/configstabilizationwidget.cpp +++ b/ground/gcs/src/plugins/config/configstabilizationwidget.cpp @@ -180,12 +180,12 @@ void ConfigStabilizationWidget::setupStabBanksGUI() if (j != i) { menuAction = new QAction(tr("from %1").arg(j + 1), this); connect(menuAction, SIGNAL(triggered()), &m_bankActionSignalMapper, SLOT(map())); - m_bankActionSignalMapper.setMapping(menuAction, QString("copy:%1:%2").arg(i).arg(j)); + m_bankActionSignalMapper.setMapping(menuAction, QString("copy:%1:%2").arg(j).arg(i)); copyMenu->addAction(menuAction); menuAction = new QAction(tr("to %1").arg(j + 1), this); connect(menuAction, SIGNAL(triggered()), &m_bankActionSignalMapper, SLOT(map())); - m_bankActionSignalMapper.setMapping(menuAction, QString("copy:%1:%2").arg(j).arg(i)); + m_bankActionSignalMapper.setMapping(menuAction, QString("copy:%1:%2").arg(i).arg(j)); copyMenu->addAction(menuAction); menuAction = new QAction(tr("with %1").arg(j + 1), this); From 6d7aa878207d0c567cdde4fcdbc97cfe2987b813 Mon Sep 17 00:00:00 2001 From: Laurent Lalanne Date: Sat, 24 Jun 2017 14:54:02 +0200 Subject: [PATCH 332/624] LP-520 Add PIOS_RCVR_TIMEOUT for failsafe state --- flight/targets/boards/oplinkmini/firmware/pios_board.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/flight/targets/boards/oplinkmini/firmware/pios_board.c b/flight/targets/boards/oplinkmini/firmware/pios_board.c index e808edf7b1..4cdbb83ad7 100644 --- a/flight/targets/boards/oplinkmini/firmware/pios_board.c +++ b/flight/targets/boards/oplinkmini/firmware/pios_board.c @@ -437,7 +437,7 @@ static void PIOS_Board_PPM_callback(__attribute__((unused)) uint32_t context, co #if defined(PIOS_INCLUDE_PPM) && defined(PIOS_INCLUDE_PPM_OUT) if (pios_ppm_out_id) { for (uint8_t i = 0; i < RFM22B_PPM_NUM_CHANNELS; ++i) { - if (channels[i] != PIOS_RCVR_INVALID) { + if ((channels[i] != PIOS_RCVR_INVALID) && (channels[i] != PIOS_RCVR_TIMEOUT)) { PIOS_PPM_OUT_Set(PIOS_PPM_OUTPUT, i, channels[i]); } } @@ -453,7 +453,7 @@ static void PIOS_Board_PPM_callback(__attribute__((unused)) uint32_t context, co } #if defined(PIOS_INCLUDE_SERVO) for (uint8_t i = 0; i < servo_count; ++i) { - uint16_t val = (channels[i] == PIOS_RCVR_INVALID) ? 0 : channels[i]; + uint16_t val = ((channels[i] == PIOS_RCVR_INVALID) || (channels[i] == PIOS_RCVR_TIMEOUT)) ? 0 : channels[i]; PIOS_Servo_Set(i, val); } #endif /* PIOS_INCLUDE_SERVO */ From 481d9abfd851277a76199c27f5d99bc08ec8d3da Mon Sep 17 00:00:00 2001 From: Brian Webb Date: Sat, 24 Jun 2017 14:48:58 -0700 Subject: [PATCH 333/624] LP-537 Remove requirement for left shifting I2C addresses on the F0 devices. This makes the I2C driver on F0 compatible with the other devices. --- flight/pios/common/pios_ubx_dcc.c | 2 +- flight/pios/stm32f0x/pios_i2c.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/flight/pios/common/pios_ubx_dcc.c b/flight/pios/common/pios_ubx_dcc.c index fce4e0fff3..2b9a974717 100644 --- a/flight/pios/common/pios_ubx_dcc.c +++ b/flight/pios/common/pios_ubx_dcc.c @@ -27,7 +27,7 @@ #include #include #include -#define GPS_I2C_ADDRESS (0x42 << 1) +#define GPS_I2C_ADDRESS 0x42 #define GPS_I2C_STREAM_REG 0xFF #define GPS_I2C_STREAM_SIZE_HIGH_REG 0xFD #define GPS_I2C_STREAM_SIZE_LOW_REG 0xFE diff --git a/flight/pios/stm32f0x/pios_i2c.c b/flight/pios/stm32f0x/pios_i2c.c index 80299e32de..87ec65782f 100644 --- a/flight/pios/stm32f0x/pios_i2c.c +++ b/flight/pios/stm32f0x/pios_i2c.c @@ -274,12 +274,12 @@ void go_txn_setup(struct pios_i2c_adapter *i2c_adapter) I2C_ITConfig(i2c_adapter->cfg->regs, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR, ENABLE); if (i2c_adapter->active_txn->rw == PIOS_I2C_TXN_READ) { - I2C_TransferHandling(i2c_adapter->cfg->regs, i2c_adapter->active_txn->addr, i2c_adapter->active_txn->len, + I2C_TransferHandling(i2c_adapter->cfg->regs, (i2c_adapter->active_txn->addr << 1), i2c_adapter->active_txn->len, /* Only last transaction generates Auto End */ i2c_adapter->active_txn == i2c_adapter->last_txn ? I2C_AutoEnd_Mode : I2C_SoftEnd_Mode, I2C_Generate_Start_Read); } else { - I2C_TransferHandling(i2c_adapter->cfg->regs, i2c_adapter->active_txn->addr, i2c_adapter->active_txn->len, + I2C_TransferHandling(i2c_adapter->cfg->regs, (i2c_adapter->active_txn->addr << 1), i2c_adapter->active_txn->len, /* Only last transaction generates Auto End */ i2c_adapter->active_txn == i2c_adapter->last_txn ? I2C_AutoEnd_Mode : I2C_SoftEnd_Mode, I2C_Generate_Start_Write); From b47a3ad39344db1d4db575857d9686ca04c3cde6 Mon Sep 17 00:00:00 2001 From: Brian Webb Date: Sat, 24 Jun 2017 15:11:41 -0700 Subject: [PATCH 334/624] LP-537 The LED should be configured active low on the GPSV9. --- flight/modules/gpsp/gpsdsysmod.c | 2 +- flight/targets/boards/gpsplatinum/board_hw_defs.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/flight/modules/gpsp/gpsdsysmod.c b/flight/modules/gpsp/gpsdsysmod.c index d7f009658e..1586f19642 100644 --- a/flight/modules/gpsp/gpsdsysmod.c +++ b/flight/modules/gpsp/gpsdsysmod.c @@ -143,7 +143,7 @@ static void gpspSystemTask(__attribute__((unused)) void *parameters) PIOS_WDG_UpdateFlag(PIOS_WDG_SYSTEM); #endif uint32_t ledPeriod = PIOS_DELAY_DiffuS(ledTimer) / 1000; - if (ledPeriod < HB_LED_BLINK_ON_PERIOD_MS) { + if (ledPeriod < HB_LED_BLINK_OFF_PERIOD_MS) { PIOS_LED_Off(PIOS_LED_HEARTBEAT); } else { PIOS_LED_On(PIOS_LED_HEARTBEAT); diff --git a/flight/targets/boards/gpsplatinum/board_hw_defs.c b/flight/targets/boards/gpsplatinum/board_hw_defs.c index 7b19737f42..95f43d2f0d 100644 --- a/flight/targets/boards/gpsplatinum/board_hw_defs.c +++ b/flight/targets/boards/gpsplatinum/board_hw_defs.c @@ -62,7 +62,7 @@ static const struct pios_gpio pios_leds_gpsp[] = { .GPIO_Speed = GPIO_Speed_Level_1, }, }, - .active_low = false + .active_low = true }, }; From 081fda25a16b71701646f76aaecdcf24dda5ca83 Mon Sep 17 00:00:00 2001 From: Brian Webb Date: Sat, 24 Jun 2017 15:28:04 -0700 Subject: [PATCH 335/624] LP-537 Changes startup code on GPSV9 to call PIOS_Board_Init after scheduler start. --- flight/modules/gpsp/gpsdsysmod.c | 10 +++++++ .../boards/gpsplatinum/firmware/gpsp.c | 26 +++++-------------- 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/flight/modules/gpsp/gpsdsysmod.c b/flight/modules/gpsp/gpsdsysmod.c index 1586f19642..bd7443bdca 100644 --- a/flight/modules/gpsp/gpsdsysmod.c +++ b/flight/modules/gpsp/gpsdsysmod.c @@ -44,6 +44,7 @@ #include "inc/gps9flashhandler.h" #include "inc/gps9protocol.h" #include "pios_board_info.h" +#include "pios_board_init.h" extern uint32_t pios_com_main_id; @@ -107,9 +108,17 @@ static void gpspSystemTask(__attribute__((unused)) void *parameters) #ifdef PIOS_INCLUDE_WDG PIOS_WDG_UpdateFlag(PIOS_WDG_SYSTEM); #endif + + /* board driver init */ + PIOS_Board_Init(); + + /* Initialize all modules */ + MODULE_INITIALISE_ALL; + while (!initTaskDone) { vTaskDelay(10); } + #ifndef PIOS_INCLUDE_WDG // if no watchdog is enabled, don't reset watchdog in MODULE_TASKCREATE_ALL loop #define PIOS_WDG_Clear() @@ -127,6 +136,7 @@ static void gpspSystemTask(__attribute__((unused)) void *parameters) #if defined(PIOS_INCLUDE_IAP) PIOS_IAP_WriteBootCount(0); #endif + /* Right now there is no configuration and uart speed is fixed at 57600. * TODO: * 1) add a tiny ubx parser on gps side to intercept CFG-RINV and use that for config storage; diff --git a/flight/targets/boards/gpsplatinum/firmware/gpsp.c b/flight/targets/boards/gpsplatinum/firmware/gpsp.c index 0768c2a55d..8bed9b50cd 100644 --- a/flight/targets/boards/gpsplatinum/firmware/gpsp.c +++ b/flight/targets/boards/gpsplatinum/firmware/gpsp.c @@ -42,6 +42,7 @@ /* Global Variables */ extern void Stack_Change(void); +extern void GPSPSystemModStart(void); /** * OpenPilot Main function: @@ -54,32 +55,19 @@ extern void Stack_Change(void); */ int main() { - /* NOTE: Do NOT modify the following start-up sequence */ - /* Any new initialization functions should be added in OpenPilotInit() */ - /* Brings up System using CMSIS functions, enables the LEDs. */ PIOS_SYS_Init(); - /* Architecture dependant Hardware and - * core subsystem initialisation - * (see pios_board.c for your arch) - * */ - PIOS_Board_Init(); + /* + * Initialize the system module, which configures the board and + * starts the other modules. + */ + GPSPSystemModStart(); - /* Initialize modules */ - MODULE_INITIALISE_ALL /* swap the stack to use the IRQ stack */ Stack_Change(); - /* Start the FreeRTOS scheduler, which should never return. - * - * NOTE: OpenPilot runs an operating system (FreeRTOS), which constantly calls - * (schedules) function files (modules). These functions never return from their - * while loops, which explains why each module has a while(1){} segment. Thus, - * the OpenPilot software actually starts at the vTaskStartScheduler() function, - * even though this is somewhat obscure. - * - */ + /* Start the FreeRTOS scheduler */ vTaskStartScheduler(); /* If all is well we will never reach here as the scheduler will now be running. */ From 95387e5df7fa7afbe5e9506f6ff34a3006371433 Mon Sep 17 00:00:00 2001 From: Laurent Lalanne Date: Sun, 25 Jun 2017 16:06:31 +0200 Subject: [PATCH 336/624] LP-538 Set correct reg.72 value for 256kbps and 150Khz Tx deviation - Cleanup --- flight/pios/common/pios_rfm22b.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flight/pios/common/pios_rfm22b.c b/flight/pios/common/pios_rfm22b.c index 0579c99a97..13ea929482 100644 --- a/flight/pios/common/pios_rfm22b.c +++ b/flight/pios/common/pios_rfm22b.c @@ -346,7 +346,7 @@ static const uint8_t channel_spacing[] = { 3, /* 100kps */ 4, /* 128kps */ 4, /* 192kps */ - 4 /* 256kps */ + 4, /* 256kps */ }; static const uint8_t reg_1C[] = { 0x01, 0x05, 0x06, 0x95, 0x95, 0x81, 0x88, 0x8B, 0x8D }; // rfm22_if_filter_bandwidth @@ -362,7 +362,7 @@ static const uint8_t reg_23[] = { 0xA5, 0x49, 0x25, 0x93, 0x86, 0x11, 0x86, 0x4A static const uint8_t reg_24[] = { 0x00, 0x00, 0x01, 0x03, 0x03, 0x03, 0x03, 0x06, 0x07 }; // rfm22_clk_recovery_timing_loop_gain1 static const uint8_t reg_25[] = { 0x34, 0x88, 0x77, 0x29, 0xE2, 0x90, 0xE2, 0x1A, 0xFF }; // rfm22_clk_recovery_timing_loop_gain0 -static const uint8_t reg_2A[] = { 0x1E, 0x24, 0x28, 0x3C, 0x3C, 0x50, 0x50, 0x50, 0x50 }; // rfm22_afc_limiter .. AFC_pull_in_range = �AFCLimiter[7:0] x (hbsel+1) x 625 Hz +static const uint8_t reg_2A[] = { 0x1E, 0x24, 0x28, 0x3C, 0x3C, 0x50, 0x50, 0x50, 0x50 }; // rfm22_afc_limiter .. AFC_pull_in_range = ±AFCLimiter[7:0] x (hbsel+1) x 625 Hz static const uint8_t reg_58[] = { 0x80, 0x80, 0x80, 0x80, 0x80, 0xC0, 0xC0, 0xC0, 0xED }; // rfm22_cpcuu static const uint8_t reg_69[] = { 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60 }; // rfm22_agc_override1 @@ -372,7 +372,7 @@ static const uint8_t reg_6F[] = { 0xA5, 0x49, 0x31, 0xBF, 0x62, 0x9A, 0xC5, 0x27 static const uint8_t reg_70[] = { 0x2C, 0x2C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C }; // rfm22_modulation_mode_control1 static const uint8_t reg_71[] = { 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23 }; // rfm22_modulation_mode_control2 -static const uint8_t reg_72[] = { 0x30, 0x48, 0x48, 0x48, 0x48, 0x60, 0x90, 0xCD, 0x0F }; // rfm22_frequency_deviation +static const uint8_t reg_72[] = { 0x30, 0x48, 0x48, 0x48, 0x48, 0x60, 0x90, 0xCD, 0xF0 }; // rfm22_frequency_deviation static const uint8_t packet_time[] = { 80, 40, 25, 15, 13, 10, 8, 6, 5 }; static const uint8_t packet_time_ppm[] = { 26, 25, 25, 15, 13, 10, 8, 6, 5 }; From c358d1741d28ce1d44fde1ce2736ddb08df0f98a Mon Sep 17 00:00:00 2001 From: Brian Webb Date: Sun, 25 Jun 2017 19:03:44 -0700 Subject: [PATCH 337/624] LP-537 GPSPSystemModStart gets called from main, so it should not be called from GPSPSystemModInitialize. --- flight/modules/gpsp/gpsdsysmod.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/flight/modules/gpsp/gpsdsysmod.c b/flight/modules/gpsp/gpsdsysmod.c index bd7443bdca..91480078ab 100644 --- a/flight/modules/gpsp/gpsdsysmod.c +++ b/flight/modules/gpsp/gpsdsysmod.c @@ -94,8 +94,7 @@ int32_t GPSPSystemModStart(void) */ int32_t GPSPSystemModInitialize(void) { - GPSPSystemModStart(); - + // Module started in main return 0; } From 53cf78e63f1ccf9e136d278d2f7a67d64488e745 Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Sat, 24 Jun 2017 16:10:16 +0200 Subject: [PATCH 338/624] LP-535 msys2: add python utility to find and copy library dependencies also add a new qmake addCopyDependenciesTarget function to invoke new utility --- ground/gcs/gcs.pri | 21 +++++++++ make/copy_dependencies.py | 92 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+) create mode 100644 make/copy_dependencies.py diff --git a/ground/gcs/gcs.pri b/ground/gcs/gcs.pri index cb25cd54f8..094a09deba 100644 --- a/ground/gcs/gcs.pri +++ b/ground/gcs/gcs.pri @@ -46,6 +46,27 @@ defineTest(addCopyFileTarget) { export($${file}.target) export($${file}.depends) export($${file}.commands) + +defineTest(addCopyDependenciesTarget) { + file = $$1 + src = $$2/$$1 + dest = $$3 + + target_file = $${OUT_PWD}/deps/$${file}.deps + + target = $${file}_deps + $${target}.target = $$target_file + $${target}.depends = $$src + + $${target}.commands = -@$(MKDIR) \"$$dirname(target_file)\" $$addNewline() + $${target}.commands += $$(PYTHON) $$(ROOT_DIR)/make/copy_dependencies.py --dest \"$$dest\" --files \"$$src\" --excludes OPENGL32.DLL > \"$$target_file\" + + QMAKE_EXTRA_TARGETS += $$target + POST_TARGETDEPS += $$eval($${target}.target) + + export($${target}.target) + export($${target}.depends) + export($${target}.commands) export(QMAKE_EXTRA_TARGETS) export(POST_TARGETDEPS) diff --git a/make/copy_dependencies.py b/make/copy_dependencies.py new file mode 100644 index 0000000000..413c16ab0d --- /dev/null +++ b/make/copy_dependencies.py @@ -0,0 +1,92 @@ +#!/usr/bin/python2 + + ############################################################################### + # + # The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017. + # Script to find and copy dependencies (msys2 only). + # ./copy_dependencies.py -h for usage. + # + ############################################################################### + +import argparse +import glob +import os +import re +import shutil +import subprocess +import sys + +def cygpath(file): + return subprocess.check_output(["cygpath", "-m", file]).strip() + +# ldd does not work well on Windows 10 and is not supported on mingw32 +# ntldd seems to be more reliable but is not recursive (so recursion needs to be done here) +def ldd(file): + ldd_output = subprocess.check_output(["ntldd", file]) + # sanitize output + ldd_output = ldd_output.strip() + ldd_output = ldd_output.replace('\\', '/') + # split output into lines + ldd_lines = ldd_output.split('\n') + # parse lines that match this format : ==> () + file_pattern = ".*/mingw../bin/.*" + pattern = "(.*) => (" + file_pattern + ") \((.*)\)"; + regex = re.compile(pattern) + dependencies = {m.group(2).strip() for m in [regex.match(line) for line in ldd_lines] if m} + return dependencies + +def find_dependencies(file, visited): + print "Analyzing " + file + visited.add(file) + dependencies = ldd(file) + # recurse + for f in dependencies.copy(): + if f in visited: + continue + if args.excludes and os.path.basename(f) in args.excludes: + print "Ignoring " + f + dependencies.remove(f) + continue + dependencies = dependencies | find_dependencies(f, visited) + return dependencies + +parser = argparse.ArgumentParser(description='Find and copy dependencies to a destination directory.') +parser.add_argument('-n', '--no-copy', action='store_true', help='don\'t copy dependencies to destination dir') +parser.add_argument('-v', '--verbose', action='store_true', help='enable verbose mode') +parser.add_argument('-d', '--dest', type=str, default='.', help='destination directory (defaults to current directory)') +parser.add_argument('-s', '--source', type=str, default='.', help='source directory (defaults to current directory)') +parser.add_argument('-f', '--files', metavar='FILE', nargs='+', required=True, help='a file') +parser.add_argument('-e', '--excludes', metavar='FILE', nargs='+', help='a file') + +args = parser.parse_args() + +# check that args.dest exists and is a directory +if not os.path.isdir(args.dest): + print "Error: destination " + str(args.dest) + " is not a directory." + exit(1) + +# find dependencies +dependencies = set() +visited = set() +for file in args.files: + file = os.path.join(args.source, file) + files = glob.glob(file) + for f in files: + dependencies = dependencies | find_dependencies(f, visited) +print "Found " + str(len(dependencies)) + " dependencies." + +# no copy, exit now +if args.no_copy: + exit(0) + +# copy dependencies to destination dir +copy_count = 0 +for file in dependencies: + dest_file = args.dest + "/" + os.path.basename(file) + if not os.path.isfile(dest_file): + print "Copying " + file + " to " + args.dest + shutil.copy2(file, args.dest) + copy_count += 1 +print "Copied " + str(copy_count) + " dependencies to '" + str(args.dest) + "'." + +exit(0) From 5e6b0e83b3a5bd2549704aeb9d8c948446c6cad7 Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Sat, 24 Jun 2017 16:11:29 +0200 Subject: [PATCH 339/624] LP-535 cosmetic renaming in addCopyFileTarget and addCopyDirTarget --- ground/gcs/gcs.pri | 47 ++++++++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/ground/gcs/gcs.pri b/ground/gcs/gcs.pri index 094a09deba..f36f6290ea 100644 --- a/ground/gcs/gcs.pri +++ b/ground/gcs/gcs.pri @@ -33,19 +33,25 @@ defineTest(addCopyFileTarget) { src = $$2/$$1 dest = $$3/$$1 - $${file}.target = $$dest - $${file}.depends = $$src + target = $${file} + $${target}.target = $$dest + $${target}.depends = $$src # create directory. Better would be an order only dependency - $${file}.commands = -@$(MKDIR) \"$$dirname(dest)\" $$addNewline() - $${file}.commands += $(COPY_FILE) \"$$src\" \"$$dest\" + $${target}.commands = -@$(MKDIR) \"$$dirname(dest)\" $$addNewline() + $${target}.commands += $(COPY_FILE) \"$$src\" \"$$dest\" - QMAKE_EXTRA_TARGETS += $$file - POST_TARGETDEPS += $$eval($${file}.target) + QMAKE_EXTRA_TARGETS += $$target + POST_TARGETDEPS += $$eval($${target}.target) - export($${file}.target) - export($${file}.depends) - export($${file}.commands) + export($${target}.target) + export($${target}.depends) + export($${target}.commands) + export(QMAKE_EXTRA_TARGETS) + export(POST_TARGETDEPS) + + return(true) +} defineTest(addCopyDependenciesTarget) { file = $$1 @@ -78,22 +84,23 @@ defineTest(addCopyDirTarget) { src = $$2/$$1 dest = $$3/$$1 - $${dir}.target = $$dest - $${dir}.depends = $$src + target = $${dir} + $${target}.target = $$dest + $${target}.depends = $$src # Windows does not update directory timestamp if files are modified - win32: $${dir}.depends += FORCE + win32:$${target}depends += FORCE - $${dir}.commands = @rm -rf \"$$dest\" $$addNewline() + $${target}.commands = @rm -rf \"$$dest\" $$addNewline() # create directory. Better would be an order only dependency - $${dir}.commands += -@$(MKDIR) \"$$dirname(dest)\" $$addNewline() - $${dir}.commands += $(COPY_DIR) \"$$src\" \"$$dest\" + $${target}.commands += -@$(MKDIR) \"$$dirname(dest)\" $$addNewline() + $${target}.commands += $(COPY_DIR) \"$$src\" \"$$dest\" - QMAKE_EXTRA_TARGETS += $$dir - POST_TARGETDEPS += $$eval($${dir}.target) + QMAKE_EXTRA_TARGETS += $$target + POST_TARGETDEPS += $$eval($${target}.target) - export($${dir}.target) - export($${dir}.depends) - export($${dir}.commands) + export($${target}.target) + export($${target}.depends) + export($${target}.commands) export(QMAKE_EXTRA_TARGETS) export(POST_TARGETDEPS) From bdd95f95f35c7b778df09e75ec54fe645d68e680 Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Sat, 24 Jun 2017 16:12:17 +0200 Subject: [PATCH 340/624] LP-535 msys2: use new addCopyDependenciesTarget to automatically find and copy library dependencies --- ground/gcs/copydata.pro | 29 ++----------- ground/gcs/src/libs/osgearth/copydata.pro | 50 ++++------------------- 2 files changed, 11 insertions(+), 68 deletions(-) diff --git a/ground/gcs/copydata.pro b/ground/gcs/copydata.pro index e2fc81a67d..c0133a7d84 100644 --- a/ground/gcs/copydata.pro +++ b/ground/gcs/copydata.pro @@ -87,35 +87,11 @@ win32 { Qt5MultimediaWidgets$${DS}.dll \ Qt5Quick$${DS}.dll \ Qt5QuickWidgets$${DS}.dll \ - Qt5Qml$${DS}.dll \ - libicuin57.dll \ - libicudt57.dll \ - libicuuc57.dll \ - libstdc++-6.dll \ - libwinpthread-1.dll \ - libpcre-1.dll \ - libpcre16-0.dll \ - zlib1.dll \ - libharfbuzz-0.dll \ - libgraphite2.dll \ - libfreetype-6.dll \ - libbz2-1.dll \ - libpng16-16.dll \ - libjpeg-8.dll \ - libglib-2.0-0.dll \ - libintl-8.dll \ - libiconv-2.dll - - contains(QT_ARCH, i386) { - QT_DLLS += \ - libgcc_s_dw2-1.dll - } else { - QT_DLLS += \ - libgcc_s_seh-1.dll - } + Qt5Qml$${DS}.dll for(dll, QT_DLLS) { addCopyFileTarget($${dll},$$[QT_INSTALL_BINS],$${GCS_APP_PATH}) + win32:addCopyDependenciesTarget($${dll},$$[QT_INSTALL_BINS],$${GCS_APP_PATH}) } # copy OpenSSL DLLs @@ -141,6 +117,7 @@ win32 { for(plugin, QT_PLUGINS) { addCopyFileTarget($${plugin},$$[QT_INSTALL_PLUGINS],$${GCS_QT_PLUGINS_PATH}) + win32:addCopyDependenciesTarget($${plugin},$$[QT_INSTALL_PLUGINS],$${GCS_APP_PATH}) } # Copy QtQuick2 complete directories diff --git a/ground/gcs/src/libs/osgearth/copydata.pro b/ground/gcs/src/libs/osgearth/copydata.pro index b4d89a4871..89e0187267 100644 --- a/ground/gcs/src/libs/osgearth/copydata.pro +++ b/ground/gcs/src/libs/osgearth/copydata.pro @@ -44,39 +44,7 @@ linux|macx { } osg:win32 { - # osg & osgearth dependencies - - # curl - OSG_LIBS = \ - libcurl-4.dll \ - libidn-11.dll \ - librtmp-1.dll \ - libgmp-10.dll \ - libgnutls-30.dll \ - libunistring-2.dll \ - libp11-kit-0.dll \ - libffi-6.dll \ - libtasn1-6.dll \ - libssh2-1.dll \ - libnghttp2-14.dll - - equals(OSG_VERSION, "3.5.1") { - OSG_LIBS += \ - libhogweed-4-2.dll \ - libnettle-6-2.dll - } else { - OSG_LIBS += \ - libhogweed-4.dll \ - libnettle-6.dll - } - - # other - OSG_LIBS += \ - libjpeg-8.dll \ - libfreetype-6.dll \ - libpng16-16.dll \ - libiconv-2.dll \ - zlib1.dll + # osg and osgearth dependencies # osg libraries OSG_LIBS += \ @@ -103,6 +71,7 @@ osg:win32 { for(lib, OSG_LIBS) { addCopyFileTarget($${lib},$${OSG_SDK_DIR}/bin,$${GCS_APP_PATH}) + win32:addCopyDependenciesTarget($${lib},$${OSG_SDK_DIR}/bin,$${GCS_APP_PATH}) } # osg plugins @@ -183,6 +152,7 @@ osg:win32 { for(lib, OSG_PLUGINS) { addCopyFileTarget($${lib},$${OSG_SDK_DIR}/bin/osgPlugins-$${OSG_VERSION},$${GCS_LIBRARY_PATH}/osg/osgPlugins-$${OSG_VERSION}) + win32:addCopyDependenciesTarget($${lib},$${OSG_SDK_DIR}/bin/osgPlugins-$${OSG_VERSION},$${GCS_APP_PATH}) } } @@ -193,23 +163,18 @@ osgearth:win32 { libosgEarthAnnotation$${DS}.dll \ libosgEarthFeatures$${DS}.dll \ libosgEarthSymbology$${DS}.dll \ - libosgEarthUtil$${DS}.dll \ - libprotobuf.dll + libosgEarthUtil$${DS}.dll - # gdal + # loaded dynamically (probably by an osg plugin, need to find by which) OSGEARTH_LIBS += \ - libgdal-20.dll \ - libgeos_c.dll \ - libgeos.dll \ - libopenjp2-7.dll \ - libtiff-5.dll \ - liblzma-5.dll + libopenjp2-7.dll osgearthQt:OSGEARTH_LIBS += \ libosgEarthQt$${DS}.dll for(lib, OSGEARTH_LIBS) { addCopyFileTarget($${lib},$${OSGEARTH_SDK_DIR}/bin,$${GCS_APP_PATH}) + win32:addCopyDependenciesTarget($${lib},$${OSGEARTH_SDK_DIR}/bin,$${GCS_APP_PATH}) } # osgearth plugins @@ -261,5 +226,6 @@ osgearth:win32 { for(lib, OSGEARTH_PLUGINS) { addCopyFileTarget($${lib},$${OSGEARTH_SDK_DIR}/bin/osgPlugins-$${OSG_VERSION},$${GCS_LIBRARY_PATH}/osg/osgPlugins-$${OSG_VERSION}) + win32:addCopyDependenciesTarget($${lib},$${OSGEARTH_SDK_DIR}/bin/osgPlugins-$${OSG_VERSION},$${GCS_APP_PATH}) } } From 9098517693230aae14971739341797c15b25f2e1 Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Sat, 24 Jun 2017 16:19:37 +0200 Subject: [PATCH 341/624] LP-535 add ntldd to list of required msys2 packages --- CONTRIBUTING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6f3f11e01d..b4fbef76fb 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -41,7 +41,7 @@ Add the following lines at the end of your /etc/pacman.conf file: Start a MinGW-w64 Win64 Shell or a MinGW-w64 Win32 Shell. pacman -Sy - pacman -S --needed git unzip tar mingw-w64-i686-toolchain mingw-w64-i686-ccache mingw-w64-i686-qt5 mingw-w64-i686-SDL mingw-w64-i686-mesa mingw-w64-i686-openssl mingw-w64-i686-gdal-minimal mingw-w64-i686-OpenSceneGraph mingw-w64-i686-osgearth + pacman -S --needed git unzip tar mingw-w64-i686-toolchain mingw-w64-i686-ccache mingw-w64-i686-ntldd mingw-w64-i686-qt5 mingw-w64-i686-SDL mingw-w64-i686-mesa mingw-w64-i686-openssl mingw-w64-i686-gdal-minimal mingw-w64-i686-OpenSceneGraph mingw-w64-i686-osgearth Optionally install debug packages: @@ -52,7 +52,7 @@ Optionally install debug packages: Start a MinGW-w64 Win64 Shell. pacman -Sy - pacman -S --needed git unzip tar mingw-w64-x86_64-toolchain mingw-w64-x86_64-ccache mingw-w64-x86_64-qt5 mingw-w64-x86_64-SDL mingw-w64-x86_64-mesa mingw-w64-x86_64-openssl mingw-w64-x86_64-gdal-minimal mingw-w64-x86_64-OpenSceneGraph mingw-w64-x86_64-osgearth + pacman -S --needed git unzip tar mingw-w64-x86_64-toolchain mingw-w64-x86_64-ccache mingw-w64-x86_64-ntldd mingw-w64-x86_64-qt5 mingw-w64-x86_64-SDL mingw-w64-x86_64-mesa mingw-w64-x86_64-openssl mingw-w64-x86_64-gdal-minimal mingw-w64-x86_64-OpenSceneGraph mingw-w64-x86_64-osgearth Optionally install debug packages: From d4f7f4af496b118e66e264f297b8b28e42b4c5bd Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Mon, 26 Jun 2017 10:02:00 +0200 Subject: [PATCH 342/624] LP-535 added ntldd package to .drone.yml (for tea ci) --- .drone.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.drone.yml b/.drone.yml index b8f8c67b21..6babff0515 100644 --- a/.drone.yml +++ b/.drone.yml @@ -6,7 +6,7 @@ build: - if [ $$arch = 32 ]; then target=i686; fi - if [ $$arch = 64 ]; then target=x86_64; fi - echo -e "[librepilot-mingw]\nSigLevel = Optional TrustAll\nServer = http://download.librepilot.org/repo/mingw" >> /etc/pacman.conf - - pacman -Syu --noconfirm --noprogressbar --needed git unzip tar mingw-w64-${target}-toolchain mingw-w64-${target}-ccache mingw-w64-${target}-qt5 mingw-w64-${target}-SDL mingw-w64-${target}-mesa mingw-w64-${target}-openssl mingw-w64-${target}-gdal-minimal mingw-w64-${target}-OpenSceneGraph mingw-w64-${target}-osgearth + - pacman -Syu --noconfirm --noprogressbar --needed git unzip tar mingw-w64-${target}-toolchain mingw-w64-${target}-ccache mingw-w64-${target}-ntldd mingw-w64-${target}-qt5 mingw-w64-${target}-SDL mingw-w64-${target}-mesa mingw-w64-${target}-openssl mingw-w64-${target}-gdal-minimal mingw-w64-${target}-OpenSceneGraph mingw-w64-${target}-osgearth - mingw32-make all_sdk_install - git config core.filemode false - mingw32-make build-info && cat build/build-info.txt From b15e5c010934b6f1ec85c005a5291e764196f3d8 Mon Sep 17 00:00:00 2001 From: Laurent Lalanne Date: Mon, 26 Jun 2017 19:48:49 +0200 Subject: [PATCH 343/624] LP-539 OPLink : Increase USB Telemetry buffers to previous default --- flight/targets/boards/oplinkmini/pios_board.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/flight/targets/boards/oplinkmini/pios_board.h b/flight/targets/boards/oplinkmini/pios_board.h index 15f07034b4..752ec3054d 100644 --- a/flight/targets/boards/oplinkmini/pios_board.h +++ b/flight/targets/boards/oplinkmini/pios_board.h @@ -174,9 +174,11 @@ extern uint32_t pios_i2c_flexi_adapter_id; // ------------------------- #define PIOS_COM_MAX_DEVS 5 -#define PIOS_COM_TELEM_USB_RX_BUF_LEN 128 -#define PIOS_COM_TELEM_USB_TX_BUF_LEN 128 +/* USB telemetry */ +#define PIOS_COM_TELEM_USB_RX_BUF_LEN 256 +#define PIOS_COM_TELEM_USB_TX_BUF_LEN 256 +/* VCP Bridge */ #define PIOS_COM_TELEM_VCP_RX_BUF_LEN 128 #define PIOS_COM_TELEM_VCP_TX_BUF_LEN 128 From 620aabc1fe723ef85cfb008fc25a4db21be54758 Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Tue, 27 Jun 2017 17:44:52 +0200 Subject: [PATCH 344/624] LP-535 simplified copy_dependencies.py use the fact that ntldd can find dependencies recursivly and on a bunch of files at once --- make/copy_dependencies.py | 45 +++++++++++---------------------------- 1 file changed, 13 insertions(+), 32 deletions(-) diff --git a/make/copy_dependencies.py b/make/copy_dependencies.py index 413c16ab0d..e89ebd4ca7 100644 --- a/make/copy_dependencies.py +++ b/make/copy_dependencies.py @@ -20,41 +20,25 @@ def cygpath(file): return subprocess.check_output(["cygpath", "-m", file]).strip() # ldd does not work well on Windows 10 and is not supported on mingw32 -# ntldd seems to be more reliable but is not recursive (so recursion needs to be done here) -def ldd(file): - ldd_output = subprocess.check_output(["ntldd", file]) +def ldd(files): + ldd_output = subprocess.check_output(["ntldd", "-R"] + files) # sanitize output ldd_output = ldd_output.strip() ldd_output = ldd_output.replace('\\', '/') # split output into lines - ldd_lines = ldd_output.split('\n') + ldd_lines = ldd_output.split(os.linesep) # parse lines that match this format : ==> () - file_pattern = ".*/mingw../bin/.*" + file_pattern = cygpath("/") + "mingw(32|64)/bin/.*" + print file_pattern pattern = "(.*) => (" + file_pattern + ") \((.*)\)"; regex = re.compile(pattern) - dependencies = {m.group(2).strip() for m in [regex.match(line) for line in ldd_lines] if m} - return dependencies - -def find_dependencies(file, visited): - print "Analyzing " + file - visited.add(file) - dependencies = ldd(file) - # recurse - for f in dependencies.copy(): - if f in visited: - continue - if args.excludes and os.path.basename(f) in args.excludes: - print "Ignoring " + f - dependencies.remove(f) - continue - dependencies = dependencies | find_dependencies(f, visited) + dependencies = {m.group(2) for m in [regex.match(line.strip()) for line in ldd_lines] if m} return dependencies parser = argparse.ArgumentParser(description='Find and copy dependencies to a destination directory.') parser.add_argument('-n', '--no-copy', action='store_true', help='don\'t copy dependencies to destination dir') parser.add_argument('-v', '--verbose', action='store_true', help='enable verbose mode') parser.add_argument('-d', '--dest', type=str, default='.', help='destination directory (defaults to current directory)') -parser.add_argument('-s', '--source', type=str, default='.', help='source directory (defaults to current directory)') parser.add_argument('-f', '--files', metavar='FILE', nargs='+', required=True, help='a file') parser.add_argument('-e', '--excludes', metavar='FILE', nargs='+', help='a file') @@ -62,18 +46,12 @@ def find_dependencies(file, visited): # check that args.dest exists and is a directory if not os.path.isdir(args.dest): - print "Error: destination " + str(args.dest) + " is not a directory." + print "Error: destination " + str(args.dest) + " is not a directory" exit(1) # find dependencies -dependencies = set() -visited = set() -for file in args.files: - file = os.path.join(args.source, file) - files = glob.glob(file) - for f in files: - dependencies = dependencies | find_dependencies(f, visited) -print "Found " + str(len(dependencies)) + " dependencies." +dependencies = ldd(args.files) +print "Found " + str(len(dependencies)) + " new dependencies" # no copy, exit now if args.no_copy: @@ -83,10 +61,13 @@ def find_dependencies(file, visited): copy_count = 0 for file in dependencies: dest_file = args.dest + "/" + os.path.basename(file) + if args.excludes and os.path.basename(file) in args.excludes: + print "Ignoring " + file + continue if not os.path.isfile(dest_file): print "Copying " + file + " to " + args.dest shutil.copy2(file, args.dest) copy_count += 1 -print "Copied " + str(copy_count) + " dependencies to '" + str(args.dest) + "'." +print "Copied " + str(copy_count) + " dependencies to " + str(args.dest) exit(0) From 4ca27d24133ce6831be30450419667a90f2230a8 Mon Sep 17 00:00:00 2001 From: Jan NIJS Date: Fri, 23 Jun 2017 18:29:08 +0200 Subject: [PATCH 345/624] LP-536 Display information for up to 24 satellites instead of only 16. Information for 24 satellites is fine when using 3 constellations. I think displaying more is overkill. --- .../gcs/src/plugins/gpsdisplay/gpsconstellationwidget.h | 2 +- ground/gcs/src/plugins/gpsdisplay/gpssnrwidget.h | 2 +- shared/uavobjectdefinition/gpssatellites.xml | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ground/gcs/src/plugins/gpsdisplay/gpsconstellationwidget.h b/ground/gcs/src/plugins/gpsdisplay/gpsconstellationwidget.h index b8b1424a5e..ab4ba26e88 100644 --- a/ground/gcs/src/plugins/gpsdisplay/gpsconstellationwidget.h +++ b/ground/gcs/src/plugins/gpsdisplay/gpsconstellationwidget.h @@ -47,7 +47,7 @@ public slots: private slots: private: - static const int MAX_SATTELITES = 16; + static const int MAX_SATTELITES = 24; int satellites[MAX_SATTELITES][4]; QGraphicsScene *scene; QSvgRenderer *renderer; diff --git a/ground/gcs/src/plugins/gpsdisplay/gpssnrwidget.h b/ground/gcs/src/plugins/gpsdisplay/gpssnrwidget.h index 1ff48b168f..1d1a183d64 100644 --- a/ground/gcs/src/plugins/gpsdisplay/gpssnrwidget.h +++ b/ground/gcs/src/plugins/gpsdisplay/gpssnrwidget.h @@ -16,7 +16,7 @@ public slots: void updateSat(int index, int prn, int elevation, int azimuth, int snr); private: - static const int MAX_SATTELITES = 16; + static const int MAX_SATTELITES = 24; int satellites[MAX_SATTELITES][4]; QGraphicsScene *scene; QGraphicsRectItem *boxes[MAX_SATTELITES]; diff --git a/shared/uavobjectdefinition/gpssatellites.xml b/shared/uavobjectdefinition/gpssatellites.xml index 5ad5fc7de4..9267c26177 100644 --- a/shared/uavobjectdefinition/gpssatellites.xml +++ b/shared/uavobjectdefinition/gpssatellites.xml @@ -2,10 +2,10 @@ Contains information about the GPS satellites in view from @ref GPSModule. - - - - + + + + From 93bf673f545bb2be3905d4d68a6e021a1a345f29 Mon Sep 17 00:00:00 2001 From: Jan NIJS Date: Fri, 23 Jun 2017 19:02:57 +0200 Subject: [PATCH 346/624] LP-536 brighten the Galileo satellite icons a bit for better readability of the SV number --- ground/gcs/src/plugins/gpsdisplay/images/gpsEarth.svg | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ground/gcs/src/plugins/gpsdisplay/images/gpsEarth.svg b/ground/gcs/src/plugins/gpsdisplay/images/gpsEarth.svg index 200160fb1b..7dbe6491ca 100644 --- a/ground/gcs/src/plugins/gpsdisplay/images/gpsEarth.svg +++ b/ground/gcs/src/plugins/gpsdisplay/images/gpsEarth.svg @@ -23,7 +23,7 @@ + style="stop-color:#ee2eff;stop-opacity:1" /> + style="fill:url(#linearGradient3859-7-2);fill-opacity:1;stroke:#b503c6;stroke-width:1.56471384;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> Date: Fri, 23 Jun 2017 19:09:06 +0200 Subject: [PATCH 347/624] LP-536 UTC is the more correct label for GNSS time + fix for the jumping number of satellites in gps widget. The number of satellites was jumping around the screen. This was due to an unnecessary resize being called. --- ground/gcs/src/plugins/gpsdisplay/gpsdisplaywidget.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ground/gcs/src/plugins/gpsdisplay/gpsdisplaywidget.cpp b/ground/gcs/src/plugins/gpsdisplay/gpsdisplaywidget.cpp index e8b5df611b..1a9be40537 100644 --- a/ground/gcs/src/plugins/gpsdisplay/gpsdisplaywidget.cpp +++ b/ground/gcs/src/plugins/gpsdisplay/gpsdisplaywidget.cpp @@ -81,7 +81,7 @@ void GpsDisplayWidget::setDateTime(double date, double time) dstring2.sprintf("%06.0f", time); dstring2.insert(dstring2.length() - 2, ":"); dstring2.insert(dstring2.length() - 5, ":"); - time_value->setText(dstring1 + " " + dstring2 + " GMT"); + time_value->setText(dstring1 + " " + dstring2 + " UTC"); } void GpsDisplayWidget::setFixType(const QString &fixtype) @@ -117,7 +117,6 @@ void GpsDisplayWidget::setSVs(int sv) temp.append(QString::number(sv)); status_value->setText(temp); - status_value->adjustSize(); } void GpsDisplayWidget::setDOP(double hdop, double vdop, double pdop) From b5a42dc48909eecd7ac614c3da73a9ecef6586a5 Mon Sep 17 00:00:00 2001 From: Jan NIJS Date: Fri, 23 Jun 2017 19:17:31 +0200 Subject: [PATCH 348/624] LP-536 Reorganize GPS display widget for a wider SNR widget. --- .../plugins/gpsdisplay/gpsdisplaywidget.ui | 500 ++++++++++-------- .../src/plugins/gpsdisplay/gpssnrwidget.cpp | 27 +- 2 files changed, 304 insertions(+), 223 deletions(-) diff --git a/ground/gcs/src/plugins/gpsdisplay/gpsdisplaywidget.ui b/ground/gcs/src/plugins/gpsdisplay/gpsdisplaywidget.ui index 6af532b91c..c64359ddc5 100644 --- a/ground/gcs/src/plugins/gpsdisplay/gpsdisplaywidget.ui +++ b/ground/gcs/src/plugins/gpsdisplay/gpsdisplaywidget.ui @@ -6,7 +6,7 @@ 0 0 - 609 + 664 606 @@ -47,164 +47,9 @@ true - - - - - - 0 - 0 - - - - - 400 - 140 - - - - - - - - - 236 - 236 - 236 - - - - - - - 237 - 237 - 237 - - - - - - - - - 236 - 236 - 236 - - - - - - - 237 - 237 - 237 - - - - - - - - - 236 - 236 - 236 - - - - - - - 236 - 236 - 236 - - - - - - - - <html><head/><body><p>Displays the SNR for each detected sat. GPS satellites are shown in green, GLONASS in cyan, BeiDou in red, Galileo in magenta and SBAS/QZSS in orange. Satellite number (PRN) is displayed inside the bar. Sat SNR is displayed above (in dBHz)</p></body></html> - - - false - - - QFrame::Panel - - - 0 - - - Qt::ScrollBarAlwaysOff - - - Qt::ScrollBarAlwaysOff - - - - - - - 0 - - - - - true - - - - 400 - 400 - - - - background-color: rgba(255, 255, 255, 0); - - - QFrame::Panel - - - Qt::ScrollBarAlwaysOff - - - Qt::ScrollBarAlwaysOff - - - - - 0 - 0 - 0 - - - - - - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 20 - 40 - - - - - - - - + + + 0 @@ -284,6 +129,22 @@ + + + + Qt::Vertical + + + QSizePolicy::Preferred + + + + 20 + 6 + + + + @@ -578,6 +439,18 @@ + + + 0 + 0 + + + + + 50 + 0 + + 100 @@ -659,6 +532,12 @@ + + + 100 + 0 + + Unknown @@ -755,71 +634,21 @@ - + 0 - - - Qt::Horizontal - - - QSizePolicy::Preferred - - - - 9 - 20 - - - - - - - - - - Connect - - - - - - - Disconnect - - - - - - - + Qt::Horizontal - QSizePolicy::Preferred - - - - 9 - 20 - - - - - - - - Qt::Horizontal - - - QSizePolicy::Expanding + QSizePolicy::Minimum - 0 + 18 20 @@ -875,7 +704,7 @@ - 20 + 40 20 @@ -885,6 +714,249 @@ + + + + 0 + + + + + true + + + + 400 + 400 + + + + background-color: rgba(255, 255, 255, 0); + + + QFrame::Panel + + + Qt::ScrollBarAlwaysOff + + + Qt::ScrollBarAlwaysOff + + + + + 0 + 0 + 0 + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 40 + + + + + + + + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 9 + 20 + + + + + + + + + + Connect + + + + + + + Disconnect + + + + + + + + + Qt::Horizontal + + + QSizePolicy::MinimumExpanding + + + + 9 + 20 + + + + + + + + + 1 + 0 + + + + + 850 + 110 + + + + + 0 + 0 + + + + + + + + + 236 + 236 + 236 + + + + + + + 237 + 237 + 237 + + + + + + + + + 236 + 236 + 236 + + + + + + + 237 + 237 + 237 + + + + + + + + + 236 + 236 + 236 + + + + + + + 236 + 236 + 236 + + + + + + + + <html><head/><body><p>Displays the SNR for each detected sat.</p> <ul><li> GPS satellites are shown in green</li><li> GLONASS in cyan</li><li> BeiDou in red</li><li> Galileo in magenta </li><li> SBAS/QZSS in orange <li></ul><p> Satellite number (PRN) is displayed inside the bar. <br/> Sat SNR is displayed above (in dBHz )</p></body></html> + + + false + + + QFrame::NoFrame + + + QFrame::Plain + + + 0 + + + Qt::ScrollBarAlwaysOff + + + Qt::ScrollBarAlwaysOff + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 9 + 20 + + + + + + diff --git a/ground/gcs/src/plugins/gpsdisplay/gpssnrwidget.cpp b/ground/gcs/src/plugins/gpsdisplay/gpssnrwidget.cpp index 10c5523345..e67ea113d1 100644 --- a/ground/gcs/src/plugins/gpsdisplay/gpssnrwidget.cpp +++ b/ground/gcs/src/plugins/gpsdisplay/gpssnrwidget.cpp @@ -18,13 +18,13 @@ GpsSnrWidget::GpsSnrWidget(QWidget *parent) : scene->addItem(boxes[i]); boxes[i]->hide(); - satTexts[i] = new QGraphicsSimpleTextItem("##", boxes[i]); + satTexts[i] = new QGraphicsSimpleTextItem("###", boxes[i]); satTexts[i]->setBrush(QColor("Black")); - satTexts[i]->setFont(QFont("Courier")); + satTexts[i]->setFont(QFont("Arial")); satSNRs[i] = new QGraphicsSimpleTextItem("##", boxes[i]); satSNRs[i]->setBrush(QColor("Black")); - satSNRs[i]->setFont(QFont("Courier")); + satSNRs[i]->setFont(QFont("Arial")); } } @@ -68,6 +68,8 @@ void GpsSnrWidget::updateSat(int index, int prn, int elevation, int azimuth, int drawSat(index); } +#define PRN_TEXTAREA_HEIGHT 20 + void GpsSnrWidget::drawSat(int index) { if (index >= MAX_SATTELITES) { @@ -93,11 +95,11 @@ void GpsSnrWidget::drawSat(int index) // 2 pixels, one on each side. qreal width = availableWidth - 2; // SNR = 1-99 (0 is special).. - qreal height = int((scene->height() / 99) * snr + 0.5); + qreal height = int(((scene->height() - PRN_TEXTAREA_HEIGHT) / 99) * snr + 0.5); // 1 for showing a pixel of white to the left. qreal x = availableWidth * index + 1; // Rember, 0 is at the top. - qreal y = scene->height() - height; + qreal y = scene->height() - height - PRN_TEXTAREA_HEIGHT; // Compensate for the extra pixel for the border. boxes[index]->setRect(0, 0, width - 1, height - 1); boxes[index]->setPos(x, y); @@ -122,6 +124,8 @@ void GpsSnrWidget::drawSat(int index) } else { boxes[index]->setBrush(QColor("Green")); } + + // Add leading 0 to PRN number QString prnString = QString().number(prn); if (prnString.length() == 1) { prnString = "0" + prnString; @@ -129,22 +133,27 @@ void GpsSnrWidget::drawSat(int index) satTexts[index]->setText(prnString); QRectF textRect = satTexts[index]->boundingRect(); + // Reposition PRN numbers below the bar and rescale QTransform matrix; - qreal scale = 0.85 * (boxRect.width() / textRect.width()); + // rescale based on the textRect height because it depends less on the number of digits: + qreal scale = 0.56 * (boxRect.width() / textRect.height()); matrix.translate(boxRect.width() / 2, boxRect.height()); matrix.scale(scale, scale); - matrix.translate(-textRect.width() / 2, -textRect.height()); + matrix.translate(-textRect.width() / 2, 0); satTexts[index]->setTransform(matrix, false); + // Add leading 0 to SNR values QString snrString = QString().number(snr); - if (snrString.length() == 1) { // Will probably never happen! + if (snrString.length() == 1) { snrString = "0" + snrString; } satSNRs[index]->setText(snrString); textRect = satSNRs[index]->boundingRect(); + // Reposition SNR levels above the bar and rescale matrix.reset(); - scale = 0.85 * (boxRect.width() / textRect.width()); + // rescale based on the textRect height because it depends less on the number of digits: + scale = 0.60 * (boxRect.width() / textRect.height()); matrix.translate(boxRect.width() / 2, 0); matrix.scale(scale, scale); matrix.translate(-textRect.width() / 2, -textRect.height()); From 6f3fefd65024fa614faa48e529fa01c80729d7c8 Mon Sep 17 00:00:00 2001 From: Jan NIJS Date: Fri, 23 Jun 2017 19:42:58 +0200 Subject: [PATCH 349/624] LP-536 add extra DGNSS state to indicate when SBAS information (any differential information in fact) is used for higher accuracy. --- flight/modules/GPS/GPS.c | 4 ++-- flight/modules/GPS/UBX.c | 16 ++++++++++++---- flight/modules/Osd/OsdEtStd/OsdEtStd.c | 2 +- flight/modules/StateEstimation/filterlla.c | 2 +- .../UAVOFrSKYSensorHubBridge.c | 4 +++- flight/modules/UAVOHottBridge/uavohottbridge.c | 1 + .../UAVOMavlinkBridge/UAVOMavlinkBridge.c | 1 + .../src/plugins/gpsdisplay/gpsdisplaywidget.cpp | 2 ++ ground/gcs/src/share/qml/js/uav.js | 2 +- shared/uavobjectdefinition/gpspositionsensor.xml | 2 +- 10 files changed, 25 insertions(+), 11 deletions(-) diff --git a/flight/modules/GPS/GPS.c b/flight/modules/GPS/GPS.c index b9ce967c4f..c894c59c41 100644 --- a/flight/modules/GPS/GPS.c +++ b/flight/modules/GPS/GPS.c @@ -416,7 +416,7 @@ static void gpsTask(__attribute__((unused)) void *parameters) // // if (the fix is good) { if ((gpspositionsensor.PDOP < gpsSettings.MaxPDOP) && (gpspositionsensor.Satellites >= gpsSettings.MinSatellites) && - (gpspositionsensor.Status == GPSPOSITIONSENSOR_STATUS_FIX3D) && + ((gpspositionsensor.Status == GPSPOSITIONSENSOR_STATUS_FIX3D) || (gpspositionsensor.Status == GPSPOSITIONSENSOR_STATUS_FIX3DDGNSS)) && (gpspositionsensor.Latitude != 0 || gpspositionsensor.Longitude != 0)) { AlarmsClear(SYSTEMALARMS_ALARM_GPS); #ifdef PIOS_GPS_SETS_HOMELOCATION @@ -436,7 +436,7 @@ static void gpsTask(__attribute__((unused)) void *parameters) } #endif // else if (we are at least getting what might be usable GPS data to finish a flight with) { - } else if ((gpspositionsensor.Status == GPSPOSITIONSENSOR_STATUS_FIX3D) && + } else if (((gpspositionsensor.Status == GPSPOSITIONSENSOR_STATUS_FIX3D) || (gpspositionsensor.Status == GPSPOSITIONSENSOR_STATUS_FIX3DDGNSS)) && (gpspositionsensor.Latitude != 0 || gpspositionsensor.Longitude != 0)) { AlarmsSet(SYSTEMALARMS_ALARM_GPS, SYSTEMALARMS_ALARM_WARNING); // else data is probably not good enough to fly diff --git a/flight/modules/GPS/UBX.c b/flight/modules/GPS/UBX.c index 11678ceb46..2ad5d42aa2 100644 --- a/flight/modules/GPS/UBX.c +++ b/flight/modules/GPS/UBX.c @@ -337,7 +337,7 @@ static void parse_ubx_nav_sol(struct UBXPacket *ubx, GPSPositionSensorData *GpsP GpsPosition->Status = GPSPOSITIONSENSOR_STATUS_FIX2D; break; case STATUS_GPSFIX_3DFIX: - GpsPosition->Status = GPSPOSITIONSENSOR_STATUS_FIX3D; + GpsPosition->Status = (sol->flags & STATUS_FLAGS_DIFFSOLN) ? GPSPOSITIONSENSOR_STATUS_FIX3DDGNSS : GPSPOSITIONSENSOR_STATUS_FIX3D; break; default: GpsPosition->Status = GPSPOSITIONSENSOR_STATUS_NOFIX; } @@ -399,10 +399,18 @@ static void parse_ubx_nav_pvt(struct UBXPacket *ubx, GPSPositionSensorData *GpsP GpsPosition->Longitude = pvt->lon; GpsPosition->Satellites = pvt->numSV; GpsPosition->PDOP = pvt->pDOP * 0.01f; + if (pvt->flags & PVT_FLAGS_GNSSFIX_OK) { - GpsPosition->Status = pvt->fixType == PVT_FIX_TYPE_3D ? - GPSPOSITIONSENSOR_STATUS_FIX3D : GPSPOSITIONSENSOR_STATUS_FIX2D; - } else { + switch (pvt->fixType) { + case PVT_FIX_TYPE_2D: + GpsPosition->Status = GPSPOSITIONSENSOR_STATUS_FIX2D; + break; + case PVT_FIX_TYPE_3D: + GpsPosition->Status = (pvt->flags & PVT_FLAGS_DIFFSOLN) ? GPSPOSITIONSENSOR_STATUS_FIX3DDGNSS : GPSPOSITIONSENSOR_STATUS_FIX3D; + break; + default: GpsPosition->Status = GPSPOSITIONSENSOR_STATUS_NOFIX; + } + } else { // fix is not valid so we make sure to treat is as NOFIX GpsPosition->Status = GPSPOSITIONSENSOR_STATUS_NOFIX; } diff --git a/flight/modules/Osd/OsdEtStd/OsdEtStd.c b/flight/modules/Osd/OsdEtStd/OsdEtStd.c index fdf74f072a..3aa0b822df 100644 --- a/flight/modules/Osd/OsdEtStd/OsdEtStd.c +++ b/flight/modules/Osd/OsdEtStd/OsdEtStd.c @@ -450,7 +450,7 @@ static void Run(void) // positionData.Status, positionData.Satellites, (uint32_t)positionData.Altitude); // GPS Status - if (positionData.Status == GPSPOSITIONSENSOR_STATUS_FIX3D) { + if ((positionData.Status == GPSPOSITIONSENSOR_STATUS_FIX3D) || (positionData.Status == GPSPOSITIONSENSOR_STATUS_FIX3DDGNSS)) { msg[OSDMSG_GPS_STAT] = OSDMSG_GPS_STAT_FIX; } else { msg[OSDMSG_GPS_STAT] = OSDMSG_GPS_STAT_NOFIX; diff --git a/flight/modules/StateEstimation/filterlla.c b/flight/modules/StateEstimation/filterlla.c index 1febace770..ebb6be449b 100644 --- a/flight/modules/StateEstimation/filterlla.c +++ b/flight/modules/StateEstimation/filterlla.c @@ -104,7 +104,7 @@ static filterResult filter(__attribute__((unused)) stateFilter *self, stateEstim // check if we have a valid GPS signal (not checked by StateEstimation istelf) if ((gpsdata.PDOP < this->settings.MaxPDOP) && (gpsdata.Satellites >= this->settings.MinSatellites) && - (gpsdata.Status == GPSPOSITIONSENSOR_STATUS_FIX3D) && + ((gpsdata.Status == GPSPOSITIONSENSOR_STATUS_FIX3D) || (gpsdata.Status == GPSPOSITIONSENSOR_STATUS_FIX3DDGNSS))&& (gpsdata.Latitude != 0 || gpsdata.Longitude != 0)) { int32_t LLAi[3] = { gpsdata.Latitude, diff --git a/flight/modules/UAVOFrSKYSensorHubBridge/UAVOFrSKYSensorHubBridge.c b/flight/modules/UAVOFrSKYSensorHubBridge/UAVOFrSKYSensorHubBridge.c index cc6385734b..964697d8c9 100644 --- a/flight/modules/UAVOFrSKYSensorHubBridge/UAVOFrSKYSensorHubBridge.c +++ b/flight/modules/UAVOFrSKYSensorHubBridge/UAVOFrSKYSensorHubBridge.c @@ -382,6 +382,7 @@ static void uavoFrSKYSensorHubBridgeTask(__attribute__((unused)) void *parameter status = 300; break; case GPSPOSITIONSENSOR_STATUS_FIX3D: + case GPSPOSITIONSENSOR_STATUS_FIX3DDGNSS: if (hl_set == HOMELOCATION_SET_TRUE) { status = 500; } else { @@ -419,7 +420,8 @@ static void uavoFrSKYSensorHubBridgeTask(__attribute__((unused)) void *parameter msg_length += frsky_pack_temperature_02((vdop * 256 + hdop), shub_global->serial_buf + msg_length); if (gpsPosData.Status == GPSPOSITIONSENSOR_STATUS_FIX2D || - gpsPosData.Status == GPSPOSITIONSENSOR_STATUS_FIX3D) { + gpsPosData.Status == GPSPOSITIONSENSOR_STATUS_FIX3D || + gpsPosData.Status == GPSPOSITIONSENSOR_STATUS_FIX3DDGNSS) { msg_length += frsky_pack_gps( gpsPosData.Heading, gpsPosData.Latitude, diff --git a/flight/modules/UAVOHottBridge/uavohottbridge.c b/flight/modules/UAVOHottBridge/uavohottbridge.c index 2fbab124e1..e5164217d7 100644 --- a/flight/modules/UAVOHottBridge/uavohottbridge.c +++ b/flight/modules/UAVOHottBridge/uavohottbridge.c @@ -357,6 +357,7 @@ uint16_t build_GPS_message(struct hott_gps_message *msg) msg->gps_fix_char = '2'; break; case GPSPOSITIONSENSOR_STATUS_FIX3D: + case GPSPOSITIONSENSOR_STATUS_FIX3DDGNSS: msg->gps_fix_char = '3'; break; default: diff --git a/flight/modules/UAVOMavlinkBridge/UAVOMavlinkBridge.c b/flight/modules/UAVOMavlinkBridge/UAVOMavlinkBridge.c index 03f97252df..ab834b7a3b 100644 --- a/flight/modules/UAVOMavlinkBridge/UAVOMavlinkBridge.c +++ b/flight/modules/UAVOMavlinkBridge/UAVOMavlinkBridge.c @@ -320,6 +320,7 @@ static void mavlink_send_position() gps_fix_type = 2; break; case GPSPOSITIONSENSOR_STATUS_FIX3D: + case GPSPOSITIONSENSOR_STATUS_FIX3DDGNSS: gps_fix_type = 3; break; } diff --git a/ground/gcs/src/plugins/gpsdisplay/gpsdisplaywidget.cpp b/ground/gcs/src/plugins/gpsdisplay/gpsdisplaywidget.cpp index 1a9be40537..7387a57db8 100644 --- a/ground/gcs/src/plugins/gpsdisplay/gpsdisplaywidget.cpp +++ b/ground/gcs/src/plugins/gpsdisplay/gpsdisplaywidget.cpp @@ -94,6 +94,8 @@ void GpsDisplayWidget::setFixType(const QString &fixtype) fix_value->setText("2D"); } else if (fixtype == "Fix3D") { fix_value->setText("3D"); + } else if (fixtype == "Fix3DDGNSS") { + fix_value->setText("3D/DGNSS"); } else { fix_value->setText("Unknown"); } diff --git a/ground/gcs/src/share/qml/js/uav.js b/ground/gcs/src/share/qml/js/uav.js index d01500e86c..ea89f76872 100644 --- a/ground/gcs/src/share/qml/js/uav.js +++ b/ground/gcs/src/share/qml/js/uav.js @@ -276,7 +276,7 @@ function gpsAltitude() { } function gpsStatus() { - var gpsStatusText = ["NO GPS", "NO FIX", "2D", "3D"]; + var gpsStatusText = ["NO GPS", "NO FIX", "2D", "3D", "3D"]; if (gpsStatusText.length != GPSPositionSensor.GPSPositionSensorConstants.StatusCount) { console.log("uav.js: gpsStatus() do not match gpsPositionSensor.status uavo"); diff --git a/shared/uavobjectdefinition/gpspositionsensor.xml b/shared/uavobjectdefinition/gpspositionsensor.xml index 566678a4b5..f548974be3 100644 --- a/shared/uavobjectdefinition/gpspositionsensor.xml +++ b/shared/uavobjectdefinition/gpspositionsensor.xml @@ -1,7 +1,7 @@ Raw GPS data from @ref GPSModule. - + From a6aeb11a56b7737f83c2bbbdcc8e835d5bd0a439 Mon Sep 17 00:00:00 2001 From: Jan NIJS Date: Sat, 10 Jun 2017 18:30:21 +0200 Subject: [PATCH 350/624] LP-536 Timeout parameter for PIOS_COM_ReceiveBuffer() should be in milliseconds. No need to convert to ticks. Changed the int xDelay to a define and put the define next to the other major delay in the GPS task. Increased the time we wait for PIOS_COM_ReceiveBuffer from 5 to 20 ms. --- flight/modules/GPS/GPS.c | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/flight/modules/GPS/GPS.c b/flight/modules/GPS/GPS.c index c894c59c41..5bd2c90613 100644 --- a/flight/modules/GPS/GPS.c +++ b/flight/modules/GPS/GPS.c @@ -105,7 +105,27 @@ void updateGpsSettings(__attribute__((unused)) UAVObjEvent *ev); // the new location with Set = true. #define GPS_HOMELOCATION_SET_DELAY 5000 -#define GPS_LOOP_DELAY_MS 6 +// PIOS serial port receive buffer for GPS is set to 32 bytes for the minimal and 128 bytes for the full version. +// GPS_READ_BUFFER is defined a few lines below in this file. +// +// 57600 bps = 5760 bytes per second +// For 32 bytes buffer: this is a maximum of 5760/32 = 180 buffers per second +// that is 1/180 = 0.0056 seconds per packet +// We must never wait more than 5ms since packet was last drained or it may overflow +// For 128 bytes buffer: this is a maximum of 5760/128 = 45 buffers per second +// that is 1/45 = 0.022 seconds per packet +// We must never wait more than 22ms since packet was last drained or it may overflow + +// There are two delays in play for the GPS task: +// - GPS_BLOCK_ON_NO_DATA_MS is the time to block while waiting to receive serial data from the GPS +// - GPS_LOOP_DELAY_MS is used for a context switch initiated by calling vTaskDelayUntil() to let other tasks run +// +// The delayMs time is not that critical. It should not be too high so that maintenance actions within this task +// are run often enough. +// GPS_LOOP_DELAY_MS on the other hand, should be less then 5.55 ms. A value set too high will cause data to be dropped. + +#define GPS_LOOP_DELAY_MS 5 +#define GPS_BLOCK_ON_NO_DATA_MS 20 #ifdef PIOS_GPS_SETS_HOMELOCATION // Unfortunately need a good size stack for the WMM calculation @@ -116,10 +136,10 @@ void updateGpsSettings(__attribute__((unused)) UAVObjEvent *ev); #ifdef PIOS_INCLUDE_GPS_NMEA_PARSER #define STACK_SIZE_BYTES 580 // NMEA -#else +#else // PIOS_INCLUDE_GPS_NMEA_PARSER #define STACK_SIZE_BYTES 440 // UBX #endif // PIOS_INCLUDE_GPS_NMEA_PARSER -#else +#else // PIOS_GPS_MINIMAL #define STACK_SIZE_BYTES 650 #endif // PIOS_GPS_MINIMAL #endif // PIOS_GPS_SETS_HOMELOCATION @@ -284,13 +304,7 @@ MODULE_INITCALL(GPSInitialize, GPSStart); static void gpsTask(__attribute__((unused)) void *parameters) { - // 57600 baud = 5760 bytes per second - // PIOS serial buffers appear to be 32 bytes long - // that is a maximum of 5760/32 = 180 buffers per second - // that is 1/180 = 0.005555556 seconds per packet - // we must never wait more than 5ms since packet was last drained or it may overflow - // 100ms is way slow too, considering we do everything possible to make the sensor data as contemporary as possible - portTickType xDelay = 5 / portTICK_RATE_MS; + uint32_t timeNowMs = xTaskGetTickCount() * portTICK_RATE_MS; #ifdef PIOS_GPS_SETS_HOMELOCATION @@ -353,8 +367,8 @@ static void gpsTask(__attribute__((unused)) void *parameters) uint16_t cnt; int res; - // This blocks the task until there is something on the buffer (or 100ms? passes) - cnt = PIOS_COM_ReceiveBuffer(gpsPort, c, GPS_READ_BUFFER, xDelay); + // This blocks the task until there is something in the buffer (or GPS_BLOCK_ON_NO_DATA_MS passes) + cnt = PIOS_COM_ReceiveBuffer(gpsPort, c, GPS_READ_BUFFER, GPS_BLOCK_ON_NO_DATA_MS); res = PARSER_INCOMPLETE; if (cnt > 0) { PERF_TIMED_SECTION_START(counterParse); From 1876d44c2e0bd7922bb149b8e8a4417d436e30ca Mon Sep 17 00:00:00 2001 From: Jan NIJS Date: Fri, 23 Jun 2017 21:52:43 +0200 Subject: [PATCH 351/624] LP-536 adapt SNR widget tooltip to the new location of the PRN number (under the bar instead of in the bar) --- ground/gcs/src/plugins/gpsdisplay/gpsdisplaywidget.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ground/gcs/src/plugins/gpsdisplay/gpsdisplaywidget.ui b/ground/gcs/src/plugins/gpsdisplay/gpsdisplaywidget.ui index c64359ddc5..3664fe44e8 100644 --- a/ground/gcs/src/plugins/gpsdisplay/gpsdisplaywidget.ui +++ b/ground/gcs/src/plugins/gpsdisplay/gpsdisplaywidget.ui @@ -917,7 +917,7 @@ - <html><head/><body><p>Displays the SNR for each detected sat.</p> <ul><li> GPS satellites are shown in green</li><li> GLONASS in cyan</li><li> BeiDou in red</li><li> Galileo in magenta </li><li> SBAS/QZSS in orange <li></ul><p> Satellite number (PRN) is displayed inside the bar. <br/> Sat SNR is displayed above (in dBHz )</p></body></html> + <html><head/><body><p>Displays the SNR for each detected sat.</p> <ul><li> GPS satellites are shown in green</li><li> GLONASS in cyan</li><li> BeiDou in red</li><li> Galileo in magenta </li><li> SBAS/QZSS in orange <li></ul><p> Satellite number (PRN) is displayed below the bar. <br/> Satellite SNR is displayed above (in dBHz )</p></body></html> false From 6cf16cc7277d033676797b3a1d5ec70eede353e7 Mon Sep 17 00:00:00 2001 From: Jan NIJS Date: Fri, 23 Jun 2017 00:31:59 +0200 Subject: [PATCH 352/624] LP-536 Second part of visual improvements for the GPS widget - Improve Alt label in the GPS display widget. The displayed altitude is Above Mean Sea Level (AMSL). AMSL label has been added to clarify the reference from which this altitude is measured. - Make values bold to draw more attention to them. The labels are less important. - Replaced an empty horizontal layout by a vertical spacer --- .../plugins/gpsdisplay/gpsdisplaywidget.ui | 118 ++++++++++++++---- 1 file changed, 94 insertions(+), 24 deletions(-) diff --git a/ground/gcs/src/plugins/gpsdisplay/gpsdisplaywidget.ui b/ground/gcs/src/plugins/gpsdisplay/gpsdisplaywidget.ui index 3664fe44e8..dd06b81291 100644 --- a/ground/gcs/src/plugins/gpsdisplay/gpsdisplaywidget.ui +++ b/ground/gcs/src/plugins/gpsdisplay/gpsdisplaywidget.ui @@ -83,6 +83,12 @@ + + + 75 + true + + Unknown @@ -106,6 +112,12 @@ + + + 75 + true + + Unknown @@ -153,7 +165,7 @@ - Alt : + Altitude (AMSL): @@ -175,6 +187,12 @@ + + + 75 + true + + Unknown @@ -241,6 +259,12 @@ + + + 75 + true + + Unknown @@ -290,6 +314,12 @@ + + + 75 + true + + Unknown @@ -363,6 +393,12 @@ + + + 75 + true + + 0 / 0 / 0 @@ -410,7 +446,7 @@ - + 0 @@ -457,6 +493,12 @@ 16777215 + + + 75 + true + + Unknown @@ -514,22 +556,6 @@ - - - - Qt::Horizontal - - - QSizePolicy::Expanding - - - - 6 - 0 - - - - @@ -538,6 +564,12 @@ 0 + + + 75 + true + + Unknown @@ -575,13 +607,36 @@ - + 0 0 + + + + Date & time: + + + + + + + Qt::Horizontal + + + QSizePolicy::Minimum + + + + 6 + 0 + + + + @@ -590,6 +645,12 @@ 16777215 + + + 75 + true + + Unknown @@ -611,11 +672,20 @@ - - - 0 + + + Qt::Vertical - + + QSizePolicy::Expanding + + + + 20 + 4 + + + @@ -917,7 +987,7 @@ - <html><head/><body><p>Displays the SNR for each detected sat.</p> <ul><li> GPS satellites are shown in green</li><li> GLONASS in cyan</li><li> BeiDou in red</li><li> Galileo in magenta </li><li> SBAS/QZSS in orange <li></ul><p> Satellite number (PRN) is displayed below the bar. <br/> Satellite SNR is displayed above (in dBHz )</p></body></html> + <html><head/><body><p>Displays the SNR for each detected satellite.</p> <ul><li> GPS satellites are shown in green</li><li> GLONASS in cyan</li><li> BeiDou in red</li><li> Galileo in magenta </li><li> SBAS/QZSS in orange <li></ul><p> Satellite SNR is displayed above (in dBHz ) <br/> Satellite number (PRN) is displayed below the bar. </p></body></html> false From 2d181994f00df50ed4051f0a8d16e83cf021bb91 Mon Sep 17 00:00:00 2001 From: Jan NIJS Date: Fri, 23 Jun 2017 16:05:59 +0200 Subject: [PATCH 353/624] LP-536 use the correct spelling for SATELLITES --- .../plugins/gpsdisplay/gpsconstellationwidget.cpp | 4 ++-- .../plugins/gpsdisplay/gpsconstellationwidget.h | 8 ++++---- ground/gcs/src/plugins/gpsdisplay/gpssnrwidget.cpp | 14 +++++++------- ground/gcs/src/plugins/gpsdisplay/gpssnrwidget.h | 10 +++++----- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/ground/gcs/src/plugins/gpsdisplay/gpsconstellationwidget.cpp b/ground/gcs/src/plugins/gpsdisplay/gpsconstellationwidget.cpp index 9c8f5ac160..67cd31687f 100644 --- a/ground/gcs/src/plugins/gpsdisplay/gpsconstellationwidget.cpp +++ b/ground/gcs/src/plugins/gpsdisplay/gpsconstellationwidget.cpp @@ -65,7 +65,7 @@ GpsConstellationWidget::GpsConstellationWidget(QWidget *parent) : QGraphicsView( QFontDatabase::addApplicationFont(":/gpsgadget/font/digital-7.ttf"); // Now create 'maxSatellites' satellite icons which we will move around on the map: - for (int i = 0; i < MAX_SATTELITES; i++) { + for (int i = 0; i < MAX_SATELLITES; i++) { satellites[i][0] = 0; satellites[i][1] = 0; satellites[i][2] = 0; @@ -112,7 +112,7 @@ void GpsConstellationWidget::resizeEvent(QResizeEvent *event) void GpsConstellationWidget::updateSat(int index, int prn, int elevation, int azimuth, int snr) { - if (index >= MAX_SATTELITES) { + if (index >= MAX_SATELLITES) { // A bit of error checking never hurts. return; } diff --git a/ground/gcs/src/plugins/gpsdisplay/gpsconstellationwidget.h b/ground/gcs/src/plugins/gpsdisplay/gpsconstellationwidget.h index ab4ba26e88..6a11058e4c 100644 --- a/ground/gcs/src/plugins/gpsdisplay/gpsconstellationwidget.h +++ b/ground/gcs/src/plugins/gpsdisplay/gpsconstellationwidget.h @@ -47,13 +47,13 @@ public slots: private slots: private: - static const int MAX_SATTELITES = 24; - int satellites[MAX_SATTELITES][4]; + static const int MAX_SATELLITES = 24; + int satellites[MAX_SATELLITES][4]; QGraphicsScene *scene; QSvgRenderer *renderer; QGraphicsSvgItem *world; - QGraphicsSvgItem *satIcons[MAX_SATTELITES]; - QGraphicsSimpleTextItem *satTexts[MAX_SATTELITES]; + QGraphicsSvgItem *satIcons[MAX_SATELLITES]; + QGraphicsSimpleTextItem *satTexts[MAX_SATELLITES]; QPointF polarToCoord(int elevation, int azimuth); diff --git a/ground/gcs/src/plugins/gpsdisplay/gpssnrwidget.cpp b/ground/gcs/src/plugins/gpsdisplay/gpssnrwidget.cpp index e67ea113d1..94c8ab694e 100644 --- a/ground/gcs/src/plugins/gpsdisplay/gpssnrwidget.cpp +++ b/ground/gcs/src/plugins/gpsdisplay/gpssnrwidget.cpp @@ -6,8 +6,8 @@ GpsSnrWidget::GpsSnrWidget(QWidget *parent) : scene = new QGraphicsScene(this); setScene(scene); - // Now create 'maxSatellites' satellite icons which we will move around on the map: - for (int i = 0; i < MAX_SATTELITES; i++) { + // Now create 'maxSatellites' signal to noise level bars: + for (int i = 0; i < MAX_SATELLITES; i++) { satellites[i][0] = 0; satellites[i][1] = 0; satellites[i][2] = 0; @@ -38,7 +38,7 @@ void GpsSnrWidget::showEvent(QShowEvent *event) { Q_UNUSED(event) scene->setSceneRect(0, 0, this->viewport()->width(), this->viewport()->height()); - for (int index = 0; index < MAX_SATTELITES; index++) { + for (int index = 0; index < MAX_SATELLITES; index++) { drawSat(index); } } @@ -47,14 +47,14 @@ void GpsSnrWidget::resizeEvent(QResizeEvent *event) { Q_UNUSED(event); scene->setSceneRect(0, 0, this->viewport()->width(), this->viewport()->height()); - for (int index = 0; index < MAX_SATTELITES; index++) { + for (int index = 0; index < MAX_SATELLITES; index++) { drawSat(index); } } void GpsSnrWidget::updateSat(int index, int prn, int elevation, int azimuth, int snr) { - if (index >= MAX_SATTELITES) { + if (index >= MAX_SATELLITES) { // A bit of error checking never hurts. return; } @@ -72,7 +72,7 @@ void GpsSnrWidget::updateSat(int index, int prn, int elevation, int azimuth, int void GpsSnrWidget::drawSat(int index) { - if (index >= MAX_SATTELITES) { + if (index >= MAX_SATELLITES) { // A bit of error checking never hurts. return; } @@ -90,7 +90,7 @@ void GpsSnrWidget::drawSat(int index) // Casting to int rounds down, which is what I want. // Minus 2 to allow a pixel of white left and right. - int availableWidth = (int)((scene->width() - 2) / MAX_SATTELITES); + int availableWidth = (int)((scene->width() - 2) / MAX_SATELLITES); // 2 pixels, one on each side. qreal width = availableWidth - 2; diff --git a/ground/gcs/src/plugins/gpsdisplay/gpssnrwidget.h b/ground/gcs/src/plugins/gpsdisplay/gpssnrwidget.h index 1d1a183d64..b05d0cb477 100644 --- a/ground/gcs/src/plugins/gpsdisplay/gpssnrwidget.h +++ b/ground/gcs/src/plugins/gpsdisplay/gpssnrwidget.h @@ -16,12 +16,12 @@ public slots: void updateSat(int index, int prn, int elevation, int azimuth, int snr); private: - static const int MAX_SATTELITES = 24; - int satellites[MAX_SATTELITES][4]; + static const int MAX_SATELLITES = 24; + int satellites[MAX_SATELLITES][4]; QGraphicsScene *scene; - QGraphicsRectItem *boxes[MAX_SATTELITES]; - QGraphicsSimpleTextItem *satTexts[MAX_SATTELITES]; - QGraphicsSimpleTextItem *satSNRs[MAX_SATTELITES]; + QGraphicsRectItem *boxes[MAX_SATELLITES]; + QGraphicsSimpleTextItem *satTexts[MAX_SATELLITES]; + QGraphicsSimpleTextItem *satSNRs[MAX_SATELLITES]; void drawSat(int index); From 5e53fb283c72d5b6c9b546ee87bb2ec19c5f3a34 Mon Sep 17 00:00:00 2001 From: Jan NIJS Date: Fri, 23 Jun 2017 16:26:32 +0200 Subject: [PATCH 354/624] LP-536 skip informational UBX packets that are too large to fit buffers UBX-NAV-SVINFO (id 30) and UBX-NAV-SAT (id 35) packets are NOT critical to the navigation. Their only use is to update the nice GPS constellation widget in the GCS. These packets become very large when a lot of SV (Space Vehicles) are tracked. (8 + 12 * ) bytes In the case of 3 simultaneously enabled GNSS, it is easy to reach the currently defined tracking limit of 32 SV. The memory taken up by this is 8 + 12 * 32 = 392 bytes The NEO-M8N has been seen to send out information for more than 32 SV. This causes overflow errors. We will ignore these informational packets if they become too large. The downside of this is no more constellation updates in the GCS when we reach the limit. An alternative fix could be to increment the maximum number of satellites: MAX_SVS and UBX_CFG_GNSS_NUMCH_VER8 in UBX.h This would use extra memory for little gain. Both fixes can be combined. Tests indicate that, once we reach this amount of tracked SV, the NEO-M8N module positioning output becomes jittery (in time) and therefore less accurate. The recommendation is to limit the maximum number of simultaneously used GNSS to a value of 2. This will help keep the number of tracked satellites in line. --- flight/modules/GPS/UBX.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/flight/modules/GPS/UBX.c b/flight/modules/GPS/UBX.c index 2ad5d42aa2..06170977f7 100644 --- a/flight/modules/GPS/UBX.c +++ b/flight/modules/GPS/UBX.c @@ -173,8 +173,35 @@ int parse_ubx_stream(uint8_t *rx, uint16_t len, char *gps_rx_buffer, GPSPosition #if defined(PIOS_GPS_MINIMAL) restart_state = RESTART_NO_ERROR; #else - restart_state = RESTART_WITH_ERROR; + /* UBX-NAV-SVINFO (id 30) and UBX-NAV-SAT (id 35) packets are NOT critical to the navigation. + Their only use is to update the nice GPS constellation widget in the GCS. + These packets become very large when a lot of SV (Space Vehicles) are tracked. (8 + 12 * ) bytes + + In the case of 3 simultaneously enabled GNSS, it is easy to reach the currently defined tracking limit of 32 SV. + The memory taken up by this is 8 + 12 * 32 = 392 bytes + + The NEO-M8N has been seen to send out information for more than 32 SV. This causes overflow errors. + We will ignore these informational packets if they become too large. + The downside of this is no more constellation updates in the GCS when we reach the limit. + + An alternative fix could be to increment the maximum number of satellites: MAX_SVS and UBX_CFG_GNSS_NUMCH_VER8 in UBX.h + This would use extra memory for little gain. Both fixes can be combined. + + Tests indicate that, once we reach this amount of tracked SV, the NEO-M8N module positioning output + becomes jittery (in time) and therefore less accurate. + + The recommendation is to limit the maximum number of simultaneously used GNSS to a value of 2. + This will help keep the number of tracked satellites in line. + */ + if ( (ubx->header.class == 0x01) && ( (ubx->header.id == 0x30) || (ubx->header.id == 0x35) ) ) { + restart_state = RESTART_NO_ERROR; + } else { + restart_state = RESTART_WITH_ERROR; + } #endif + // We won't see the end of the packet. Which means it is useless to do any further processing. + // Therefore scan for the start of the next packet. + proto_state = START; break; } else { if (ubx->header.len == 0) { From a61d87243ed2af72c58fcf5e828cb354aa57a22f Mon Sep 17 00:00:00 2001 From: Jan NIJS Date: Fri, 23 Jun 2017 17:05:10 +0200 Subject: [PATCH 355/624] LP-536 gpsextendedstatus: change update type from periodic (1s) to on-change. There is no need to transmit one telemetry update per second for this uavo on controllers where no OP-GPS is present. For the controllers where an OP-GPS is present, the FlightTime field updates will trigger a telemetry update. --- shared/uavobjectdefinition/gpsextendedstatus.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/uavobjectdefinition/gpsextendedstatus.xml b/shared/uavobjectdefinition/gpsextendedstatus.xml index f47e320756..2dfedc567c 100644 --- a/shared/uavobjectdefinition/gpsextendedstatus.xml +++ b/shared/uavobjectdefinition/gpsextendedstatus.xml @@ -9,7 +9,7 @@ - + From 12062a5c7de976e30da955b52bdbb3142dbf7e53 Mon Sep 17 00:00:00 2001 From: Jan NIJS Date: Fri, 23 Jun 2017 23:47:16 +0200 Subject: [PATCH 356/624] LP-536 make pretty --- flight/modules/GPS/GPS.c | 35 +++++++++++----------- flight/modules/GPS/UBX.c | 4 +-- flight/modules/StateEstimation/filterlla.c | 2 +- 3 files changed, 21 insertions(+), 20 deletions(-) diff --git a/flight/modules/GPS/GPS.c b/flight/modules/GPS/GPS.c index 5bd2c90613..71080f97da 100644 --- a/flight/modules/GPS/GPS.c +++ b/flight/modules/GPS/GPS.c @@ -109,12 +109,14 @@ void updateGpsSettings(__attribute__((unused)) UAVObjEvent *ev); // GPS_READ_BUFFER is defined a few lines below in this file. // // 57600 bps = 5760 bytes per second +// // For 32 bytes buffer: this is a maximum of 5760/32 = 180 buffers per second -// that is 1/180 = 0.0056 seconds per packet -// We must never wait more than 5ms since packet was last drained or it may overflow +// that is 1/180 = 0.0056 seconds per packet +// We must never wait more than 5ms since packet was last drained or it may overflow +// // For 128 bytes buffer: this is a maximum of 5760/128 = 45 buffers per second -// that is 1/45 = 0.022 seconds per packet -// We must never wait more than 22ms since packet was last drained or it may overflow +// that is 1/45 = 0.022 seconds per packet +// We must never wait more than 22ms since packet was last drained or it may overflow // There are two delays in play for the GPS task: // - GPS_BLOCK_ON_NO_DATA_MS is the time to block while waiting to receive serial data from the GPS @@ -124,31 +126,31 @@ void updateGpsSettings(__attribute__((unused)) UAVObjEvent *ev); // are run often enough. // GPS_LOOP_DELAY_MS on the other hand, should be less then 5.55 ms. A value set too high will cause data to be dropped. -#define GPS_LOOP_DELAY_MS 5 -#define GPS_BLOCK_ON_NO_DATA_MS 20 +#define GPS_LOOP_DELAY_MS 5 +#define GPS_BLOCK_ON_NO_DATA_MS 20 #ifdef PIOS_GPS_SETS_HOMELOCATION // Unfortunately need a good size stack for the WMM calculation - #define STACK_SIZE_BYTES 1024 + #define STACK_SIZE_BYTES 1024 #else #if defined(PIOS_GPS_MINIMAL) - #define GPS_READ_BUFFER 32 + #define GPS_READ_BUFFER 32 #ifdef PIOS_INCLUDE_GPS_NMEA_PARSER - #define STACK_SIZE_BYTES 580 // NMEA -#else // PIOS_INCLUDE_GPS_NMEA_PARSER - #define STACK_SIZE_BYTES 440 // UBX + #define STACK_SIZE_BYTES 580 // NMEA +#else // PIOS_INCLUDE_GPS_NMEA_PARSER + #define STACK_SIZE_BYTES 440 // UBX #endif // PIOS_INCLUDE_GPS_NMEA_PARSER -#else // PIOS_GPS_MINIMAL - #define STACK_SIZE_BYTES 650 +#else // PIOS_GPS_MINIMAL + #define STACK_SIZE_BYTES 650 #endif // PIOS_GPS_MINIMAL #endif // PIOS_GPS_SETS_HOMELOCATION #ifndef GPS_READ_BUFFER -#define GPS_READ_BUFFER 128 +#define GPS_READ_BUFFER 128 #endif -#define TASK_PRIORITY (tskIDLE_PRIORITY + 1) +#define TASK_PRIORITY (tskIDLE_PRIORITY + 1) // **************** // Private variables @@ -304,8 +306,7 @@ MODULE_INITCALL(GPSInitialize, GPSStart); static void gpsTask(__attribute__((unused)) void *parameters) { - - uint32_t timeNowMs = xTaskGetTickCount() * portTICK_RATE_MS; + uint32_t timeNowMs = xTaskGetTickCount() * portTICK_RATE_MS; #ifdef PIOS_GPS_SETS_HOMELOCATION portTickType homelocationSetDelay = 0; diff --git a/flight/modules/GPS/UBX.c b/flight/modules/GPS/UBX.c index 06170977f7..e8a79a3b51 100644 --- a/flight/modules/GPS/UBX.c +++ b/flight/modules/GPS/UBX.c @@ -192,8 +192,8 @@ int parse_ubx_stream(uint8_t *rx, uint16_t len, char *gps_rx_buffer, GPSPosition The recommendation is to limit the maximum number of simultaneously used GNSS to a value of 2. This will help keep the number of tracked satellites in line. - */ - if ( (ubx->header.class == 0x01) && ( (ubx->header.id == 0x30) || (ubx->header.id == 0x35) ) ) { + */ + if ((ubx->header.class == 0x01) && ((ubx->header.id == 0x30) || (ubx->header.id == 0x35))) { restart_state = RESTART_NO_ERROR; } else { restart_state = RESTART_WITH_ERROR; diff --git a/flight/modules/StateEstimation/filterlla.c b/flight/modules/StateEstimation/filterlla.c index ebb6be449b..e0f6c4c357 100644 --- a/flight/modules/StateEstimation/filterlla.c +++ b/flight/modules/StateEstimation/filterlla.c @@ -104,7 +104,7 @@ static filterResult filter(__attribute__((unused)) stateFilter *self, stateEstim // check if we have a valid GPS signal (not checked by StateEstimation istelf) if ((gpsdata.PDOP < this->settings.MaxPDOP) && (gpsdata.Satellites >= this->settings.MinSatellites) && - ((gpsdata.Status == GPSPOSITIONSENSOR_STATUS_FIX3D) || (gpsdata.Status == GPSPOSITIONSENSOR_STATUS_FIX3DDGNSS))&& + ((gpsdata.Status == GPSPOSITIONSENSOR_STATUS_FIX3D) || (gpsdata.Status == GPSPOSITIONSENSOR_STATUS_FIX3DDGNSS)) && (gpsdata.Latitude != 0 || gpsdata.Longitude != 0)) { int32_t LLAi[3] = { gpsdata.Latitude, From 9d6175e68e1c36782098c314b76f010b0468bc24 Mon Sep 17 00:00:00 2001 From: Jan NIJS Date: Sun, 25 Jun 2017 16:36:31 +0200 Subject: [PATCH 357/624] LP-536 Missed a few 3D conditions in uav.js --- ground/gcs/src/share/qml/js/uav.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ground/gcs/src/share/qml/js/uav.js b/ground/gcs/src/share/qml/js/uav.js index ea89f76872..95489ec28a 100644 --- a/ground/gcs/src/share/qml/js/uav.js +++ b/ground/gcs/src/share/qml/js/uav.js @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The LibrePilot Project + * Copyright (C) 2016-2017 The LibrePilot Project * Contact: http://www.librepilot.org * * This file is part of LibrePilot GCS. @@ -117,6 +117,7 @@ function position() { switch(gpsPositionSensor.status) { case GPSPositionSensor.Status.Fix2D: case GPSPositionSensor.Status.Fix3D: + case GPSPositionSensor.Status.Fix3DDGNSS: return gpsPosition(); case GPSPositionSensor.Status.NoFix: case GPSPositionSensor.Status.NoGPS: @@ -222,7 +223,7 @@ function isGpsNotInitialised() { } function isGpsStatusFix3D() { - return (gpsPositionSensor.status == GPSPositionSensor.Status.Fix3D); + return ((gpsPositionSensor.status == GPSPositionSensor.Status.Fix3D) || (gpsPositionSensor.status == GPSPositionSensor.Status.Fix3DDGNSS)); } function isOplmConnected() { From 557e728a00fc6c4f0679fdd8c9d6e79bad312f5c Mon Sep 17 00:00:00 2001 From: Jan NIJS Date: Tue, 27 Jun 2017 22:34:01 +0200 Subject: [PATCH 358/624] LP-536 auto-scaling world map as requested by Philippe + lay-out modifications Includes a nice feature which you will notice if you keep an eye on your cursor ;-) --- .../plugins/gpsdisplay/flatearthwidget.cpp | 149 ++ .../src/plugins/gpsdisplay/flatearthwidget.h | 57 + .../gcs/src/plugins/gpsdisplay/gpsdisplay.pro | 2 + .../plugins/gpsdisplay/gpsdisplaywidget.cpp | 21 +- .../src/plugins/gpsdisplay/gpsdisplaywidget.h | 2 +- .../plugins/gpsdisplay/gpsdisplaywidget.ui | 1346 +++++++++-------- .../gpsdisplay/images/flatEarth source.txt | 11 + .../plugins/gpsdisplay/images/flatEarth.png | Bin 28931 -> 1131136 bytes .../src/plugins/gpsdisplay/images/marker.svg | 64 +- 9 files changed, 969 insertions(+), 683 deletions(-) create mode 100644 ground/gcs/src/plugins/gpsdisplay/flatearthwidget.cpp create mode 100644 ground/gcs/src/plugins/gpsdisplay/flatearthwidget.h create mode 100644 ground/gcs/src/plugins/gpsdisplay/images/flatEarth source.txt diff --git a/ground/gcs/src/plugins/gpsdisplay/flatearthwidget.cpp b/ground/gcs/src/plugins/gpsdisplay/flatearthwidget.cpp new file mode 100644 index 0000000000..00659f2ec2 --- /dev/null +++ b/ground/gcs/src/plugins/gpsdisplay/flatearthwidget.cpp @@ -0,0 +1,149 @@ +/** + ****************************************************************************** + * + * @file flatearthwidget.cpp + * @author The LibrePilot Team, http://www.librepilot.org Copyright (C) 2017. + * @author Edouard Lafargue Copyright (C) 2010. + * @addtogroup GCSPlugins GCS Plugins + * @{ + * @addtogroup FlatEarthWidget FlatEarth Widget Plugin + * @{ + * @brief A widget for visualizing a location on a flat map of the world. + *****************************************************************************/ +/* + * 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, see . + */ + +#include "flatearthwidget.h" +#include /* fabs */ + +#define MARKER_SIZE 40.0 + +FlatEarthWidget::FlatEarthWidget(QWidget *parent) : QGraphicsView(parent) +{ + // Disable scrollbars to prevent an "always updated loop" + this->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + this->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + + // Show the whole world by default + zoomedin = false; + + // Set initial location + oldLat = oldLon = 0; + + // Draw the earth + earthScene = new QGraphicsScene(this); + QPixmap earthpix(":/gpsgadget/images/flatEarth.png"); + earthPixmapItem = earthScene->addPixmap(earthpix); + this->setScene(earthScene); + + // Draw the marker + marker = new QGraphicsSvgItem(); + QSvgRenderer *renderer = new QSvgRenderer(); + renderer->load(QString(":/gpsgadget/images/marker.svg")); + marker->setSharedRenderer(renderer); + earthScene->addItem(marker); +} + +FlatEarthWidget::~FlatEarthWidget() +{} + +/* + * Refresh the map on first showing + */ +void FlatEarthWidget::showEvent(QShowEvent *event) +{ + Q_UNUSED(event) + + refreshMap(); +} + +/* + * Refresh the map while resizing the widget + */ +void FlatEarthWidget::resizeEvent(QResizeEvent *event) +{ + Q_UNUSED(event) + + refreshMap(); +} + +/* + * Toggle zoom state on mouse click event + */ +void FlatEarthWidget::mousePressEvent(QMouseEvent *event) +{ + Q_UNUSED(event) + + // toggle zoom state + if (zoomedin) { + zoomedin = false; + } else { + zoomedin = true; + } + refreshMap(); +} + +/* + * Update the position of the marker on the map + */ +void FlatEarthWidget::setPosition(double lat, double lon) +{ + /* Only perform this expensive graphics operation if the position has changed enough + to be visible on the map. + */ + if (fabs(oldLat - lat) > 0.1 || fabs(oldLon - lon) > 0.1) { + double wscale = this->sceneRect().width() / 360; + double hscale = this->sceneRect().height() / 180; + QPointF opd = QPointF((lon + 180) * wscale - marker->boundingRect().width() * marker->scale() / 2, + (90 - lat) * hscale - marker->boundingRect().height() * marker->scale() / 2); + marker->setTransform(QTransform::fromTranslate(opd.x(), opd.y()), false); + + // Center the map on the uav position + if (zoomedin) { + this->centerOn(marker); + } + } + oldLat = lat; + oldLon = lon; +} + +/* + * Update the scale of the map + */ +void FlatEarthWidget::refreshMap(void) +{ + double markerScale; + + if (zoomedin) { + // Zoom the map to it's native resolution + this->resetTransform(); + + // Center the map on the uav position + this->centerOn(marker); + + // Rescale the marker dimensions to keep the same appearance in both zoom levels + markerScale = MARKER_SIZE / 100.0 * (double)this->rect().width() / (double)(earthPixmapItem->boundingRect().width()); + marker->setScale(markerScale); + } else { + // Fit the whole world + this->fitInView(earthPixmapItem, Qt::KeepAspectRatio); + + // Rescale the marker dimensions to keep the same appearance in both zoom levels + markerScale = MARKER_SIZE / 100.0; + marker->setScale(markerScale); + } + // force an update of the marker position by giving the position a nudge + this->setPosition(oldLat - 0.2, oldLon); +} diff --git a/ground/gcs/src/plugins/gpsdisplay/flatearthwidget.h b/ground/gcs/src/plugins/gpsdisplay/flatearthwidget.h new file mode 100644 index 0000000000..fd9a6c42da --- /dev/null +++ b/ground/gcs/src/plugins/gpsdisplay/flatearthwidget.h @@ -0,0 +1,57 @@ +/** + ****************************************************************************** + * + * @file flatearthwidget.h + * @author The LibrePilot Team, http://www.librepilot.org Copyright (C) 2017. + * @addtogroup GCSPlugins GCS Plugins + * @{ + * @addtogroup FlatEarthWidget FlatEarth Widget Plugin + * @{ + * @brief A widget for visualizing a location on a flat map of the world. + *****************************************************************************/ +/* + * 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, see . + */ + +#ifndef FLATEARTHWIDGET_H_ +#define FLATEARTHWIDGET_H_ + +#include +#include +#include + +class FlatEarthWidget : public QGraphicsView { + Q_OBJECT + +public: + explicit FlatEarthWidget(QWidget *parent = 0); + ~FlatEarthWidget(); + void setPosition(double, double); + +protected: + void showEvent(QShowEvent *event); + void resizeEvent(QResizeEvent *event); + void mousePressEvent(QMouseEvent *event); + +private: + bool zoomedin; + double oldLat, oldLon; + + QGraphicsScene *earthScene; + QGraphicsPixmapItem *earthPixmapItem; + QGraphicsSvgItem *marker; + + void refreshMap(void); +}; +#endif /* FLATEARTHWIDGET_H_ */ diff --git a/ground/gcs/src/plugins/gpsdisplay/gpsdisplay.pro b/ground/gcs/src/plugins/gpsdisplay/gpsdisplay.pro index 31b1218d52..1ed616f067 100644 --- a/ground/gcs/src/plugins/gpsdisplay/gpsdisplay.pro +++ b/ground/gcs/src/plugins/gpsdisplay/gpsdisplay.pro @@ -9,6 +9,7 @@ include(gpsdisplay_dependencies.pri) include(../../libs/qwt/qwt.pri) HEADERS += \ + flatearthwidget.h \ gpsdisplayplugin.h \ gpsconstellationwidget.h \ gpsparser.h \ @@ -23,6 +24,7 @@ HEADERS += \ gpsdisplaygadgetoptionspage.h SOURCES += \ + flatearthwidget.cpp \ gpsdisplayplugin.cpp \ gpsconstellationwidget.cpp \ gpsparser.cpp \ diff --git a/ground/gcs/src/plugins/gpsdisplay/gpsdisplaywidget.cpp b/ground/gcs/src/plugins/gpsdisplay/gpsdisplaywidget.cpp index 7387a57db8..2589c212c7 100644 --- a/ground/gcs/src/plugins/gpsdisplay/gpsdisplaywidget.cpp +++ b/ground/gcs/src/plugins/gpsdisplay/gpsdisplaywidget.cpp @@ -2,6 +2,7 @@ ****************************************************************************** * * @file gpsdisplaywidget.cpp + * @author The LibrePilot Team, http://www.librepilot.org Copyright (C) 2017. * @author Edouard Lafargue Copyright (C) 2010. * @addtogroup GCSPlugins GCS Plugins * @{ @@ -45,19 +46,6 @@ GpsDisplayWidget::GpsDisplayWidget(QWidget *parent) : QWidget(parent) { setupUi(this); - - // Not elegant, just load the image for now - QGraphicsScene *fescene = new QGraphicsScene(this); - QPixmap earthpix(":/gpsgadget/images/flatEarth.png"); - fescene->addPixmap(earthpix); - flatEarth->setScene(fescene); - marker = new QGraphicsSvgItem(); - QSvgRenderer *renderer = new QSvgRenderer(); - renderer->load(QString(":/gpsgadget/images/marker.svg")); - marker->setSharedRenderer(renderer); - fescene->addItem(marker); - double scale = earthpix.width() / (marker->boundingRect().width() * 20); - marker->setScale(scale); } GpsDisplayWidget::~GpsDisplayWidget() @@ -158,10 +146,5 @@ void GpsDisplayWidget::setPosition(double lat, double lon, double alt) str3.sprintf("%.2f m", alt); coord_value_3->setText(str3); - // Now place the marker: - double wscale = flatEarth->sceneRect().width() / 360; - double hscale = flatEarth->sceneRect().height() / 180; - QPointF opd = QPointF((lon + 180) * wscale - marker->boundingRect().width() * marker->scale() / 2, - (90 - lat) * hscale - marker->boundingRect().height() * marker->scale() / 2); - marker->setTransform(QTransform::fromTranslate(opd.x(), opd.y()), false); + flatEarth->setPosition(lat, lon); } diff --git a/ground/gcs/src/plugins/gpsdisplay/gpsdisplaywidget.h b/ground/gcs/src/plugins/gpsdisplay/gpsdisplaywidget.h index a7be008096..469e18310d 100644 --- a/ground/gcs/src/plugins/gpsdisplay/gpsdisplaywidget.h +++ b/ground/gcs/src/plugins/gpsdisplay/gpsdisplaywidget.h @@ -2,6 +2,7 @@ ****************************************************************************** * * @file gpsdisplaywidget.h + * @author The LibrePilot Team, http://www.librepilot.org Copyright (C) 2017. * @author Edouard Lafargue Copyright (C) 2010. * @addtogroup GCSPlugins GCS Plugins * @{ @@ -56,6 +57,5 @@ private slots: private: GpsConstellationWidget *gpsConstellation; - QGraphicsSvgItem *marker; }; #endif /* GPSDISPLAYWIDGET_H_ */ diff --git a/ground/gcs/src/plugins/gpsdisplay/gpsdisplaywidget.ui b/ground/gcs/src/plugins/gpsdisplay/gpsdisplaywidget.ui index dd06b81291..8139463ea1 100644 --- a/ground/gcs/src/plugins/gpsdisplay/gpsdisplaywidget.ui +++ b/ground/gcs/src/plugins/gpsdisplay/gpsdisplaywidget.ui @@ -47,257 +47,545 @@ true - + + + 6 + + + 0 + - - - 0 - - - + + + 0 - - - Coord: + + + 0 - + + + + Coord: + + + + + + + Qt::Horizontal + + + QSizePolicy::Minimum + + + + 6 + 0 + + + + + + + + + 80 + 0 + + + + + 100 + 16777215 + + + + + 75 + true + + + + Unknown + + + + + + + Qt::Horizontal + + + QSizePolicy::Preferred + + + + 6 + 20 + + + + + + + + + 80 + 0 + + + + + 100 + 16777215 + + + + + 75 + true + + + + Unknown + + + + + + + Qt::Horizontal + + + QSizePolicy::MinimumExpanding + + + + 6 + 20 + + + + + - + - Qt::Horizontal + Qt::Vertical - QSizePolicy::Minimum + QSizePolicy::Preferred - 6 - 0 + 20 + 6 - - - - 75 - true - - - - Unknown + + + 0 - + + + + Speed: + + + + + + + Qt::Horizontal + + + QSizePolicy::Minimum + + + + 6 + 0 + + + + + + + + + 40 + 0 + + + + + 75 + true + + + + Unknown + + + false + + + + + + + Qt::Horizontal + + + + 6 + 20 + + + + + + + + Qt::Horizontal + + + QSizePolicy::Minimum + + + + 6 + 0 + + + + + + + + Heading: + + + + + + + Qt::Horizontal + + + QSizePolicy::Minimum + + + + 6 + 0 + + + + + + + + + 50 + 0 + + + + + 75 + true + + + + Unknown + + + + - + - Qt::Horizontal + Qt::Vertical - QSizePolicy::Minimum + QSizePolicy::Preferred - 6 - 0 + 20 + 6 - - - - 75 - true - + + + 0 - - Unknown + + 0 - + + + + Altitude (AMSL): + + + + + + + Qt::Horizontal + + + QSizePolicy::Minimum + + + + 6 + 20 + + + + + + + + + 75 + true + + + + Unknown + + + + + + + Qt::Horizontal + + + + 6 + 20 + + + + + - + - Qt::Horizontal + Qt::Vertical - QSizePolicy::Minimum + QSizePolicy::Preferred - 6 - 0 + 20 + 4 - - - - - - Qt::Vertical - - - QSizePolicy::Preferred - - - - 20 - 6 - - - - - - - - 0 - - - - - Altitude (AMSL): - - - - + Qt::Horizontal - - QSizePolicy::Minimum - - - - 6 - 20 - - - - - - - - - 75 - true - - - - Unknown - - - - - Qt::Horizontal - - - - 40 - 20 - - - - + + + + + + true + + + + 400 + 400 + + + + background-color: rgba(255, 255, 255, 0); + + + QFrame::Panel + + + Qt::ScrollBarAlwaysOff + + + Qt::ScrollBarAlwaysOff + + + + + 0 + 0 + 0 + + + + + + + + + + 0 + 0 + + + + + 180 + 90 + + + + + 1440 + 720 + + + + + 0 + 0 + + + + + 0 + 0 + + + + + + + + + 170 + 255 + 0 + + + + + + + 240 + 34 + 223 + + + + + + + + + 170 + 255 + 0 + + + + + + + 240 + 34 + 223 + + + + + + + + + 240 + 34 + 223 + + + + + + + 240 + 34 + 223 + + + + + + + + PointingHandCursor + + + <html><head/><body><p>Location of the UAV on the Earth</p><p>Click to toggle zoomlevel.</p></body></html> + + + QFrame::NoFrame + + + 0 + + + Qt::ScrollBarAlwaysOff + + + Qt::ScrollBarAlwaysOff + + + QGraphicsView::DontAdjustForAntialiasing + + + + + + + 0 + - - - Qt::Vertical - - - QSizePolicy::Preferred - - - - 20 - 6 - - - - - - + 0 - - - Speed: - - - - - - - Qt::Horizontal - - - QSizePolicy::Minimum - - - - 6 - 0 - - - - - - - - - 75 - true - - - - Unknown - - - true - - - - - - - Qt::Horizontal - - - QSizePolicy::Minimum - - - - 6 - 0 - - - - - - + - Heading: + H / V / P DOP: - + Qt::Horizontal @@ -313,7 +601,7 @@ - + 75 @@ -321,113 +609,24 @@ - Unknown - - - - - - - - - Qt::Vertical - - - QSizePolicy::Preferred - - - - 20 - 4 - - - - - - - - Qt::Horizontal - - - - - - - Qt::Vertical - - - QSizePolicy::Preferred - - - - 20 - 4 - - - - - - - - - - H / V / P DOP: + 0 / 0 / 0 - + Qt::Horizontal - - QSizePolicy::Minimum - 6 - 0 + 20 - - - - - - - - 75 - true - - - - 0 / 0 / 0 - - - - - - - - - Qt::Vertical - - - QSizePolicy::Preferred - - - - 20 - 4 - - - - - - - - Qt::Horizontal - - + + + + @@ -440,13 +639,13 @@ 20 - 4 + 6 - + 0 @@ -483,13 +682,13 @@ - 50 + 30 0 - 100 + 16777215 16777215 @@ -511,7 +710,7 @@ - 40 + 6 20 @@ -560,7 +759,7 @@ - 100 + 80 0 @@ -575,19 +774,6 @@ - - - - Qt::Horizontal - - - - 40 - 20 - - - - @@ -616,6 +802,12 @@ + + + 0 + 0 + + Date & time: @@ -639,6 +831,12 @@ + + + 50 + 0 + + 16777215 @@ -663,7 +861,7 @@ - 40 + 6 20 @@ -672,12 +870,12 @@ - + Qt::Vertical - QSizePolicy::Expanding + QSizePolicy::Preferred @@ -688,188 +886,201 @@ - + - Qt::Vertical - - - QSizePolicy::Ignored - - - - 20 - 40 - - - - - - - - 0 - - - - - Qt::Horizontal - - - QSizePolicy::Minimum - - - - 18 - 20 - - - - - - - - - 0 - 0 - - - - - 191 - 95 - - - - - 191 - 95 - - - - false - - - <html><head/><body><p>Location of GCS on the Earth</p></body></html> - - - QFrame::NoFrame - - - 0 - - - Qt::ScrollBarAlwaysOff - - - Qt::ScrollBarAlwaysOff - - - QGraphicsView::DontAdjustForAntialiasing - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - 0 - - - - - true - - - - 400 - 400 - - - - background-color: rgba(255, 255, 255, 0); - - - QFrame::Panel - - - Qt::ScrollBarAlwaysOff - - - Qt::ScrollBarAlwaysOff - - - - - 0 - 0 - 0 - - + Qt::Horizontal - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 20 - 40 - - - - - - - - 0 + + + + + 1 + 0 + - - 0 + + + 0 + 0 + - - 0 + + + 16777215 + 16777215 + + + + Qt::NoFocus + + Signal to Noise Ratio + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 0 + 100 + + + + + 850 + 100 + + + + + 0 + 0 + + + + + + + + + 236 + 236 + 236 + + + + + + + 237 + 237 + 237 + + + + + + + + + 236 + 236 + 236 + + + + + + + 237 + 237 + 237 + + + + + + + + + 236 + 236 + 236 + + + + + + + 236 + 236 + 236 + + + + + + + + <html><head/><body><p>Displays the SNR for each detected satellite.</p> <ul><li> GPS satellites are shown in green</li><li> GLONASS in cyan</li><li> BeiDou in red</li><li> Galileo in magenta </li><li> SBAS/QZSS in orange <li></ul><p> Satellite SNR is displayed above (in dBHz ) <br/> Satellite number (PRN) is displayed below the bar. </p></body></html> + + + false + + + QFrame::NoFrame + + + QFrame::Plain + + + 0 + + + Qt::ScrollBarAlwaysOff + + + Qt::ScrollBarAlwaysOff + + + + + + + + + + + GPS Data Stream + + + + 0 + + + 0 + + + 0 + + + 0 + + + - - - Qt::Horizontal - - - QSizePolicy::Fixed + + + 9 - - - 9 - 20 - + + 9 - - - - @@ -887,195 +1098,37 @@ - - - Qt::Horizontal - - - QSizePolicy::MinimumExpanding - - - - 9 - 20 - - - - - - + - - 1 + + 0 0 - - - 850 - 110 - - - + 0 - 0 + 50 - - - - - - - 236 - 236 - 236 - - - - - - - 237 - 237 - 237 - - - - - - - - - 236 - 236 - 236 - - - - - - - 237 - 237 - 237 - - - - - - - - - 236 - 236 - 236 - - - - - - - 236 - 236 - 236 - - - - - - - - <html><head/><body><p>Displays the SNR for each detected satellite.</p> <ul><li> GPS satellites are shown in green</li><li> GLONASS in cyan</li><li> BeiDou in red</li><li> Galileo in magenta </li><li> SBAS/QZSS in orange <li></ul><p> Satellite SNR is displayed above (in dBHz ) <br/> Satellite number (PRN) is displayed below the bar. </p></body></html> - - - false - - - QFrame::NoFrame - - - QFrame::Plain - 0 - Qt::ScrollBarAlwaysOff + Qt::ScrollBarAlwaysOn - - Qt::ScrollBarAlwaysOff - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed + + QTextEdit::WidgetWidth - - - 9 - 20 - + + false - + - - - GPS Data Stream - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - 0 - - - - - 0 - 50 - - - - 0 - - - Qt::ScrollBarAlwaysOn - - - QTextEdit::WidgetWidth - - - false - - - - - @@ -1091,6 +1144,11 @@ QGraphicsView
gpssnrwidget.h
+ + FlatEarthWidget + QGraphicsView +
flatearthwidget.h
+
diff --git a/ground/gcs/src/plugins/gpsdisplay/images/flatEarth source.txt b/ground/gcs/src/plugins/gpsdisplay/images/flatEarth source.txt new file mode 100644 index 0000000000..64bbe92a09 --- /dev/null +++ b/ground/gcs/src/plugins/gpsdisplay/images/flatEarth source.txt @@ -0,0 +1,11 @@ +flatEarth.png image used from: http://www.shadedrelief.com/natural3/pages/textures.html + +Terms of Use + +All Natural Earth III data (and images) found on this website are in the public domain. You may use the data in any manner, including modifying the content and design, electronic dissemination, and offset printing. The author, Tom Patterson, renounces all financial claim to the data and invites you to use it for personal, educational, and commercial purposes. + +No permission is needed to use Natural Earth III. Crediting the author is unnecessary. However, if you wish to cite the data source, simply use: Tom Patterson, www.shadedrelief.com. + +The author provides Natural Earth III as a public service and is not responsible for any problems relating to accuracy, content, design, and how it is used. + + diff --git a/ground/gcs/src/plugins/gpsdisplay/images/flatEarth.png b/ground/gcs/src/plugins/gpsdisplay/images/flatEarth.png index a18d9e36812c6c8eab0e57ed8fe0399642e5427a..8501ec6aca8c46abafaeb832041a2bece61b78dd 100644 GIT binary patch literal 1131136 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 z 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
{m34TQ_3Z#$tlDvg3t`3zXl!kFMG3eH>zvd^PG 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
AgMFhX<2HGpt#VLe)9HC_J{RS{K52K* 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

lE`^?`VZ*WKJXgh?J=5GTSV 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�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 @@ -33,18 +33,20 @@ inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="1.4481878" - inkscape:cx="88.375982" + inkscape:cx="-13.475449" inkscape:cy="166.06585" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="false" - inkscape:window-width="1280" - inkscape:window-height="928" - inkscape:window-x="0" - inkscape:window-y="27" + inkscape:window-width="1920" + inkscape:window-height="1017" + inkscape:window-x="-8" + inkscape:window-y="-8" inkscape:window-maximized="1" inkscape:snap-page="true" - inkscape:snap-object-midpoints="true" /> + inkscape:snap-object-midpoints="true" + showguides="true" + inkscape:guide-bbox="true" /> @@ -64,23 +66,47 @@ transform="translate(-81.1701,-431.51432)"> - - + + + + + From f0f89fe2adfa0d111af4cfdea3002ca080bcbada Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Mon, 12 Jun 2017 09:57:32 +0200 Subject: [PATCH 359/624] LP-530 upgrade to eigen 3.3.3 fixes compilation warnings --- ground/gcs/src/libs/eigen/.hg_archival.txt | 6 +- ground/gcs/src/libs/eigen/.hgeol | 3 + ground/gcs/src/libs/eigen/.hgignore | 2 + ground/gcs/src/libs/eigen/.hgtags | 19 +- ground/gcs/src/libs/eigen/CMakeLists.txt | 218 +- ground/gcs/src/libs/eigen/CTestConfig.cmake | 4 +- ground/gcs/src/libs/eigen/Eigen/Array | 11 - .../gcs/src/libs/eigen/Eigen/CMakeLists.txt | 2 +- ground/gcs/src/libs/eigen/Eigen/Cholesky | 17 +- .../gcs/src/libs/eigen/Eigen/CholmodSupport | 11 +- ground/gcs/src/libs/eigen/Eigen/Core | 290 +- ground/gcs/src/libs/eigen/Eigen/Eigen | 2 +- ground/gcs/src/libs/eigen/Eigen/Eigen2Support | 95 - ground/gcs/src/libs/eigen/Eigen/Eigenvalues | 15 +- ground/gcs/src/libs/eigen/Eigen/Geometry | 61 +- ground/gcs/src/libs/eigen/Eigen/Householder | 7 + .../libs/eigen/Eigen/IterativeLinearSolvers | 24 +- ground/gcs/src/libs/eigen/Eigen/Jacobi | 7 + ground/gcs/src/libs/eigen/Eigen/LU | 21 +- ground/gcs/src/libs/eigen/Eigen/LeastSquares | 32 - ground/gcs/src/libs/eigen/Eigen/MetisSupport | 7 + .../gcs/src/libs/eigen/Eigen/OrderingMethods | 7 + ground/gcs/src/libs/eigen/Eigen/PaStiXSupport | 12 +- .../gcs/src/libs/eigen/Eigen/PardisoSupport | 9 +- ground/gcs/src/libs/eigen/Eigen/QR | 26 +- .../gcs/src/libs/eigen/Eigen/QtAlignedMalloc | 10 +- ground/gcs/src/libs/eigen/Eigen/SPQRSupport | 9 +- ground/gcs/src/libs/eigen/Eigen/SVD | 26 +- ground/gcs/src/libs/eigen/Eigen/Sparse | 15 +- .../gcs/src/libs/eigen/Eigen/SparseCholesky | 2 - ground/gcs/src/libs/eigen/Eigen/SparseCore | 33 +- ground/gcs/src/libs/eigen/Eigen/SparseLU | 3 - ground/gcs/src/libs/eigen/Eigen/SparseQR | 10 +- ground/gcs/src/libs/eigen/Eigen/StdDeque | 2 +- ground/gcs/src/libs/eigen/Eigen/StdList | 2 +- ground/gcs/src/libs/eigen/Eigen/StdVector | 2 +- .../gcs/src/libs/eigen/Eigen/SuperLUSupport | 13 +- .../gcs/src/libs/eigen/Eigen/UmfPackSupport | 10 +- .../src/libs/eigen/Eigen/src/CMakeLists.txt | 7 - .../eigen/Eigen/src/Cholesky/CMakeLists.txt | 6 - .../src/libs/eigen/Eigen/src/Cholesky/LDLT.h | 268 +- .../src/libs/eigen/Eigen/src/Cholesky/LLT.h | 168 +- .../src/Cholesky/{LLT_MKL.h => LLT_LAPACKE.h} | 45 +- .../Eigen/src/CholmodSupport/CMakeLists.txt | 6 - .../Eigen/src/CholmodSupport/CholmodSupport.h | 284 +- .../gcs/src/libs/eigen/Eigen/src/Core/Array.h | 144 +- .../src/libs/eigen/Eigen/src/Core/ArrayBase.h | 70 +- .../libs/eigen/Eigen/src/Core/ArrayWrapper.h | 145 +- .../src/libs/eigen/Eigen/src/Core/Assign.h | 540 +- .../eigen/Eigen/src/Core/AssignEvaluator.h | 935 + .../libs/eigen/Eigen/src/Core/Assign_MKL.h | 256 +- .../libs/eigen/Eigen/src/Core/BandMatrix.h | 61 +- .../gcs/src/libs/eigen/Eigen/src/Core/Block.h | 254 +- .../libs/eigen/Eigen/src/Core/BooleanRedux.h | 42 +- .../libs/eigen/Eigen/src/Core/CMakeLists.txt | 10 - .../eigen/Eigen/src/Core/CommaInitializer.h | 40 +- .../eigen/Eigen/src/Core/ConditionEstimator.h | 175 + .../eigen/Eigen/src/Core/CoreEvaluators.h | 1671 ++ .../libs/eigen/Eigen/src/Core/CoreIterators.h | 140 +- .../libs/eigen/Eigen/src/Core/CwiseBinaryOp.h | 166 +- .../eigen/Eigen/src/Core/CwiseNullaryOp.h | 252 +- .../eigen/Eigen/src/Core/CwiseTernaryOp.h | 197 + .../libs/eigen/Eigen/src/Core/CwiseUnaryOp.h | 111 +- .../eigen/Eigen/src/Core/CwiseUnaryView.h | 81 +- .../src/libs/eigen/Eigen/src/Core/DenseBase.h | 386 +- .../eigen/Eigen/src/Core/DenseCoeffsBase.h | 279 +- .../libs/eigen/Eigen/src/Core/DenseStorage.h | 442 +- .../src/libs/eigen/Eigen/src/Core/Diagonal.h | 66 +- .../eigen/Eigen/src/Core/DiagonalMatrix.h | 140 +- .../eigen/Eigen/src/Core/DiagonalProduct.h | 107 +- .../gcs/src/libs/eigen/Eigen/src/Core/Dot.h | 160 +- .../src/libs/eigen/Eigen/src/Core/EigenBase.h | 48 +- .../src/libs/eigen/Eigen/src/Core/Flagged.h | 140 - .../eigen/Eigen/src/Core/ForceAlignedAccess.h | 24 +- .../src/libs/eigen/Eigen/src/Core/Functors.h | 1026 - .../gcs/src/libs/eigen/Eigen/src/Core/Fuzzy.h | 13 +- .../eigen/Eigen/src/Core/GeneralProduct.h | 506 +- .../eigen/Eigen/src/Core/GenericPacketMath.h | 349 +- .../eigen/Eigen/src/Core/GlobalFunctions.h | 161 +- ground/gcs/src/libs/eigen/Eigen/src/Core/IO.h | 49 +- .../src/libs/eigen/Eigen/src/Core/Inverse.h | 118 + .../gcs/src/libs/eigen/Eigen/src/Core/Map.h | 110 +- .../src/libs/eigen/Eigen/src/Core/MapBase.h | 98 +- .../libs/eigen/Eigen/src/Core/MathFunctions.h | 856 +- .../eigen/Eigen/src/Core/MathFunctionsImpl.h | 78 + .../src/libs/eigen/Eigen/src/Core/Matrix.h | 241 +- .../libs/eigen/Eigen/src/Core/MatrixBase.h | 313 +- .../libs/eigen/Eigen/src/Core/NestByValue.h | 35 +- .../src/libs/eigen/Eigen/src/Core/NoAlias.h | 62 +- .../src/libs/eigen/Eigen/src/Core/NumTraits.h | 136 +- .../eigen/Eigen/src/Core/PermutationMatrix.h | 364 +- .../eigen/Eigen/src/Core/PlainObjectBase.h | 427 +- .../src/libs/eigen/Eigen/src/Core/Product.h | 186 + .../libs/eigen/Eigen/src/Core/ProductBase.h | 290 - .../eigen/Eigen/src/Core/ProductEvaluators.h | 1099 ++ .../src/libs/eigen/Eigen/src/Core/Random.h | 58 +- .../gcs/src/libs/eigen/Eigen/src/Core/Redux.h | 210 +- .../gcs/src/libs/eigen/Eigen/src/Core/Ref.h | 199 +- .../src/libs/eigen/Eigen/src/Core/Replicate.h | 95 +- .../libs/eigen/Eigen/src/Core/ReturnByValue.h | 50 +- .../src/libs/eigen/Eigen/src/Core/Reverse.h | 209 +- .../src/libs/eigen/Eigen/src/Core/Select.h | 22 +- .../eigen/Eigen/src/Core/SelfAdjointView.h | 292 +- .../eigen/Eigen/src/Core/SelfCwiseBinaryOp.h | 172 +- .../gcs/src/libs/eigen/Eigen/src/Core/Solve.h | 188 + .../eigen/Eigen/src/Core/SolveTriangular.h | 76 +- .../libs/eigen/Eigen/src/Core/SolverBase.h | 130 + .../libs/eigen/Eigen/src/Core/StableNorm.h | 53 +- .../src/libs/eigen/Eigen/src/Core/Stride.h | 25 +- .../gcs/src/libs/eigen/Eigen/src/Core/Swap.h | 149 +- .../src/libs/eigen/Eigen/src/Core/Transpose.h | 184 +- .../eigen/Eigen/src/Core/Transpositions.h | 245 +- .../eigen/Eigen/src/Core/TriangularMatrix.h | 1102 +- .../libs/eigen/Eigen/src/Core/VectorBlock.h | 27 +- .../libs/eigen/Eigen/src/Core/VectorwiseOp.h | 339 +- .../src/libs/eigen/Eigen/src/Core/Visitor.h | 77 +- .../eigen/Eigen/src/Core/arch/AVX/Complex.h | 483 + .../Eigen/src/Core/arch/AVX/MathFunctions.h | 439 + .../Eigen/src/Core/arch/AVX/PacketMath.h | 633 + .../Eigen/src/Core/arch/AVX/TypeCasting.h | 51 + .../src/Core/arch/AVX512/MathFunctions.h | 396 + .../Eigen/src/Core/arch/AVX512/PacketMath.h | 1316 ++ .../src/Core/arch/AltiVec/CMakeLists.txt | 6 - .../Eigen/src/Core/arch/AltiVec/Complex.h | 354 +- .../src/Core/arch/AltiVec/MathFunctions.h | 322 + .../Eigen/src/Core/arch/AltiVec/PacketMath.h | 796 +- .../eigen/Eigen/src/Core/arch/CMakeLists.txt | 4 - .../eigen/Eigen/src/Core/arch/CUDA/Complex.h | 103 + .../eigen/Eigen/src/Core/arch/CUDA/Half.h | 585 + .../Eigen/src/Core/arch/CUDA/MathFunctions.h | 91 + .../Eigen/src/Core/arch/CUDA/PacketMath.h | 333 + .../Eigen/src/Core/arch/CUDA/PacketMathHalf.h | 1123 ++ .../Eigen/src/Core/arch/CUDA/TypeCasting.h | 212 + .../src/Core/arch/Default/CMakeLists.txt | 6 - .../Eigen/src/Core/arch/NEON/CMakeLists.txt | 6 - .../eigen/Eigen/src/Core/arch/NEON/Complex.h | 251 +- .../Eigen/src/Core/arch/NEON/MathFunctions.h | 91 + .../Eigen/src/Core/arch/NEON/PacketMath.h | 404 +- .../Eigen/src/Core/arch/SSE/CMakeLists.txt | 6 - .../eigen/Eigen/src/Core/arch/SSE/Complex.h | 99 +- .../Eigen/src/Core/arch/SSE/MathFunctions.h | 113 +- .../Eigen/src/Core/arch/SSE/PacketMath.h | 416 +- .../Eigen/src/Core/arch/SSE/TypeCasting.h | 77 + .../Eigen/src/Core/arch/ZVector/Complex.h | 394 + .../src/Core/arch/ZVector/MathFunctions.h | 137 + .../Eigen/src/Core/arch/ZVector/PacketMath.h | 945 + .../src/Core/functors/AssignmentFunctors.h | 168 + .../Eigen/src/Core/functors/BinaryFunctors.h | 482 + .../Eigen/src/Core/functors/NullaryFunctors.h | 189 + .../Eigen/src/Core/functors/StlFunctors.h | 132 + .../Eigen/src/Core/functors/TernaryFunctors.h | 25 + .../Eigen/src/Core/functors/UnaryFunctors.h | 792 + .../Eigen/src/Core/products/CMakeLists.txt | 6 - .../src/Core/products/CoeffBasedProduct.h | 476 - .../Core/products/GeneralBlockPanelKernel.h | 2244 ++- .../src/Core/products/GeneralMatrixMatrix.h | 371 +- .../products/GeneralMatrixMatrixTriangular.h | 138 +- ...h => GeneralMatrixMatrixTriangular_BLAS.h} | 65 +- ...atrix_MKL.h => GeneralMatrixMatrix_BLAS.h} | 47 +- .../src/Core/products/GeneralMatrixVector.h | 305 +- ...ector_MKL.h => GeneralMatrixVector_BLAS.h} | 68 +- .../Eigen/src/Core/products/Parallelizer.h | 67 +- .../Core/products/SelfadjointMatrixMatrix.h | 335 +- ...x_MKL.h => SelfadjointMatrixMatrix_BLAS.h} | 136 +- .../Core/products/SelfadjointMatrixVector.h | 127 +- ...r_MKL.h => SelfadjointMatrixVector_BLAS.h} | 49 +- .../src/Core/products/SelfadjointProduct.h | 26 +- .../Core/products/SelfadjointRank2Update.h | 8 +- .../Core/products/TriangularMatrixMatrix.h | 138 +- ...ix_MKL.h => TriangularMatrixMatrix_BLAS.h} | 111 +- .../Core/products/TriangularMatrixVector.h | 182 +- ...or_MKL.h => TriangularMatrixVector_BLAS.h} | 96 +- .../Core/products/TriangularSolverMatrix.h | 73 +- ...ix_MKL.h => TriangularSolverMatrix_BLAS.h} | 56 +- .../Core/products/TriangularSolverVector.h | 24 +- .../libs/eigen/Eigen/src/Core/util/BlasUtil.h | 204 +- .../eigen/Eigen/src/Core/util/CMakeLists.txt | 6 - .../eigen/Eigen/src/Core/util/Constants.h | 174 +- .../src/Core/util/DisableStupidWarnings.h | 39 +- .../Eigen/src/Core/util/ForwardDeclarations.h | 134 +- .../eigen/Eigen/src/Core/util/MKL_support.h | 50 +- .../libs/eigen/Eigen/src/Core/util/Macros.h | 544 +- .../libs/eigen/Eigen/src/Core/util/Memory.h | 562 +- .../src/libs/eigen/Eigen/src/Core/util/Meta.h | 351 +- .../src/Core/util/ReenableStupidWarnings.h | 13 + .../eigen/Eigen/src/Core/util/StaticAssert.h | 40 +- .../eigen/Eigen/src/Core/util/XprHelper.h | 582 +- .../eigen/Eigen/src/Eigen2Support/Block.h | 126 - .../Eigen/src/Eigen2Support/CMakeLists.txt | 8 - .../eigen/Eigen/src/Eigen2Support/Cwise.h | 192 - .../Eigen/src/Eigen2Support/CwiseOperators.h | 298 - .../src/Eigen2Support/Geometry/AlignedBox.h | 159 - .../Eigen/src/Eigen2Support/Geometry/All.h | 115 - .../src/Eigen2Support/Geometry/AngleAxis.h | 214 - .../src/Eigen2Support/Geometry/CMakeLists.txt | 6 - .../src/Eigen2Support/Geometry/Hyperplane.h | 254 - .../Eigen2Support/Geometry/ParametrizedLine.h | 141 - .../src/Eigen2Support/Geometry/Quaternion.h | 495 - .../src/Eigen2Support/Geometry/Rotation2D.h | 145 - .../src/Eigen2Support/Geometry/RotationBase.h | 123 - .../src/Eigen2Support/Geometry/Scaling.h | 167 - .../src/Eigen2Support/Geometry/Transform.h | 786 - .../src/Eigen2Support/Geometry/Translation.h | 184 - .../libs/eigen/Eigen/src/Eigen2Support/LU.h | 120 - .../libs/eigen/Eigen/src/Eigen2Support/Lazy.h | 71 - .../Eigen/src/Eigen2Support/LeastSquares.h | 169 - .../eigen/Eigen/src/Eigen2Support/Macros.h | 20 - .../Eigen/src/Eigen2Support/MathFunctions.h | 57 - .../eigen/Eigen/src/Eigen2Support/Memory.h | 45 - .../libs/eigen/Eigen/src/Eigen2Support/Meta.h | 75 - .../eigen/Eigen/src/Eigen2Support/Minor.h | 117 - .../libs/eigen/Eigen/src/Eigen2Support/QR.h | 67 - .../libs/eigen/Eigen/src/Eigen2Support/SVD.h | 637 - .../src/Eigen2Support/TriangularSolver.h | 42 - .../Eigen/src/Eigen2Support/VectorBlock.h | 94 - .../Eigen/src/Eigenvalues/CMakeLists.txt | 6 - .../src/Eigenvalues/ComplexEigenSolver.h | 25 +- .../Eigen/src/Eigenvalues/ComplexSchur.h | 19 +- ...plexSchur_MKL.h => ComplexSchur_LAPACKE.h} | 40 +- .../eigen/Eigen/src/Eigenvalues/EigenSolver.h | 113 +- .../src/Eigenvalues/GeneralizedEigenSolver.h | 197 +- .../GeneralizedSelfAdjointEigenSolver.h | 3 +- .../src/Eigenvalues/HessenbergDecomposition.h | 15 +- .../libs/eigen/Eigen/src/Eigenvalues/RealQZ.h | 46 +- .../eigen/Eigen/src/Eigenvalues/RealSchur.h | 41 +- .../{RealSchur_MKL.h => RealSchur_LAPACKE.h} | 38 +- .../src/Eigenvalues/SelfAdjointEigenSolver.h | 273 +- ...MKL.h => SelfAdjointEigenSolver_LAPACKE.h} | 42 +- .../src/Eigenvalues/Tridiagonalization.h | 39 +- .../eigen/Eigen/src/Geometry/AlignedBox.h | 96 +- .../libs/eigen/Eigen/src/Geometry/AngleAxis.h | 85 +- .../eigen/Eigen/src/Geometry/CMakeLists.txt | 8 - .../eigen/Eigen/src/Geometry/EulerAngles.h | 22 +- .../eigen/Eigen/src/Geometry/Homogeneous.h | 290 +- .../eigen/Eigen/src/Geometry/Hyperplane.h | 64 +- .../eigen/Eigen/src/Geometry/OrthoMethods.h | 58 +- .../Eigen/src/Geometry/ParametrizedLine.h | 60 +- .../eigen/Eigen/src/Geometry/Quaternion.h | 225 +- .../eigen/Eigen/src/Geometry/Rotation2D.h | 85 +- .../eigen/Eigen/src/Geometry/RotationBase.h | 48 +- .../libs/eigen/Eigen/src/Geometry/Scaling.h | 38 +- .../libs/eigen/Eigen/src/Geometry/Transform.h | 262 +- .../eigen/Eigen/src/Geometry/Translation.h | 60 +- .../libs/eigen/Eigen/src/Geometry/Umeyama.h | 19 +- .../Eigen/src/Geometry/arch/CMakeLists.txt | 6 - .../Eigen/src/Geometry/arch/Geometry_SSE.h | 56 +- .../Eigen/src/Householder/BlockHouseholder.h | 77 +- .../Eigen/src/Householder/CMakeLists.txt | 6 - .../eigen/Eigen/src/Householder/Householder.h | 7 +- .../src/Householder/HouseholderSequence.h | 55 +- .../BasicPreconditioners.h | 114 +- .../src/IterativeLinearSolvers/BiCGSTAB.h | 97 +- .../src/IterativeLinearSolvers/CMakeLists.txt | 6 - .../ConjugateGradient.h | 137 +- .../IncompleteCholesky.h | 400 + .../IterativeLinearSolvers/IncompleteLUT.h | 138 +- .../IterativeSolverBase.h | 340 +- .../LeastSquareConjugateGradient.h | 216 + .../IterativeLinearSolvers/SolveWithGuess.h | 115 + .../eigen/Eigen/src/Jacobi/CMakeLists.txt | 6 - .../src/libs/eigen/Eigen/src/Jacobi/Jacobi.h | 34 +- .../libs/eigen/Eigen/src/LU/CMakeLists.txt | 8 - .../src/libs/eigen/Eigen/src/LU/Determinant.h | 2 +- .../src/libs/eigen/Eigen/src/LU/FullPivLU.h | 314 +- .../Eigen/src/LU/{Inverse.h => InverseImpl.h} | 79 +- .../libs/eigen/Eigen/src/LU/PartialPivLU.h | 252 +- ...tialPivLU_MKL.h => PartialPivLU_LAPACKE.h} | 26 +- .../eigen/Eigen/src/LU/arch/CMakeLists.txt | 6 - .../eigen/Eigen/src/LU/arch/Inverse_SSE.h | 47 +- .../Eigen/src/MetisSupport/CMakeLists.txt | 6 - .../Eigen/src/MetisSupport/MetisSupport.h | 18 +- .../eigen/Eigen/src/OrderingMethods/Amd.h | 83 +- .../Eigen/src/OrderingMethods/CMakeLists.txt | 6 - .../Eigen/src/OrderingMethods/Eigen_Colamd.h | 410 +- .../Eigen/src/OrderingMethods/Ordering.h | 51 +- .../Eigen/src/PaStiXSupport/CMakeLists.txt | 6 - .../Eigen/src/PaStiXSupport/PaStiXSupport.h | 155 +- .../Eigen/src/PardisoSupport/CMakeLists.txt | 6 - .../Eigen/src/PardisoSupport/PardisoSupport.h | 249 +- .../libs/eigen/Eigen/src/QR/CMakeLists.txt | 6 - .../eigen/Eigen/src/QR/ColPivHouseholderQR.h | 281 +- ...QR_MKL.h => ColPivHouseholderQR_LAPACKE.h} | 47 +- .../src/QR/CompleteOrthogonalDecomposition.h | 562 + .../eigen/Eigen/src/QR/FullPivHouseholderQR.h | 192 +- .../libs/eigen/Eigen/src/QR/HouseholderQR.h | 119 +- ...holderQR_MKL.h => HouseholderQR_LAPACKE.h} | 29 +- .../Eigen/src/SPQRSupport/CMakeLists.txt | 6 - .../src/SPQRSupport/SuiteSparseQRSupport.h | 123 +- .../gcs/src/libs/eigen/Eigen/src/SVD/BDCSVD.h | 1230 ++ .../libs/eigen/Eigen/src/SVD/CMakeLists.txt | 6 - .../src/libs/eigen/Eigen/src/SVD/JacobiSVD.h | 390 +- .../{JacobiSVD_MKL.h => JacobiSVD_LAPACKE.h} | 48 +- .../{unsupported => }/Eigen/src/SVD/SVDBase.h | 199 +- .../Eigen/src/SVD/UpperBidiagonalization.h | 326 +- .../Eigen/src/SparseCholesky/CMakeLists.txt | 6 - .../src/SparseCholesky/SimplicialCholesky.h | 272 +- .../SparseCholesky/SimplicialCholesky_impl.h | 34 +- .../eigen/Eigen/src/SparseCore/AmbiVector.h | 98 +- .../eigen/Eigen/src/SparseCore/CMakeLists.txt | 6 - .../Eigen/src/SparseCore/CompressedStorage.h | 139 +- .../ConservativeSparseSparseProduct.h | 216 +- .../Eigen/src/SparseCore/MappedSparseMatrix.h | 164 +- .../eigen/Eigen/src/SparseCore/SparseAssign.h | 216 + .../eigen/Eigen/src/SparseCore/SparseBlock.h | 682 +- .../Eigen/src/SparseCore/SparseColEtree.h | 44 +- .../src/SparseCore/SparseCompressedBase.h | 341 + .../src/SparseCore/SparseCwiseBinaryOp.h | 666 +- .../Eigen/src/SparseCore/SparseCwiseUnaryOp.h | 155 +- .../Eigen/src/SparseCore/SparseDenseProduct.h | 417 +- .../src/SparseCore/SparseDiagonalProduct.h | 228 +- .../eigen/Eigen/src/SparseCore/SparseDot.h | 17 +- .../eigen/Eigen/src/SparseCore/SparseFuzzy.h | 29 +- .../eigen/Eigen/src/SparseCore/SparseMap.h | 305 + .../eigen/Eigen/src/SparseCore/SparseMatrix.h | 641 +- .../Eigen/src/SparseCore/SparseMatrixBase.h | 268 +- .../Eigen/src/SparseCore/SparsePermutation.h | 170 +- .../Eigen/src/SparseCore/SparseProduct.h | 291 +- .../eigen/Eigen/src/SparseCore/SparseRedux.h | 12 +- .../eigen/Eigen/src/SparseCore/SparseRef.h | 397 + .../src/SparseCore/SparseSelfAdjointView.h | 556 +- .../Eigen/src/SparseCore/SparseSolverBase.h | 124 + .../SparseSparseProductWithPruning.h | 86 +- .../Eigen/src/SparseCore/SparseTranspose.h | 99 +- .../src/SparseCore/SparseTriangularView.h | 252 +- .../eigen/Eigen/src/SparseCore/SparseUtil.h | 106 +- .../eigen/Eigen/src/SparseCore/SparseVector.h | 212 +- .../eigen/Eigen/src/SparseCore/SparseView.h | 230 +- .../Eigen/src/SparseCore/TriangularSolver.h | 117 +- .../eigen/Eigen/src/SparseLU/CMakeLists.txt | 6 - .../libs/eigen/Eigen/src/SparseLU/SparseLU.h | 221 +- .../eigen/Eigen/src/SparseLU/SparseLUImpl.h | 10 +- .../Eigen/src/SparseLU/SparseLU_Memory.h | 15 +- .../Eigen/src/SparseLU/SparseLU_Structs.h | 3 +- .../src/SparseLU/SparseLU_SupernodalMatrix.h | 69 +- .../eigen/Eigen/src/SparseLU/SparseLU_Utils.h | 10 +- .../Eigen/src/SparseLU/SparseLU_column_bmod.h | 7 +- .../Eigen/src/SparseLU/SparseLU_column_dfs.h | 38 +- .../src/SparseLU/SparseLU_copy_to_ucol.h | 7 +- .../Eigen/src/SparseLU/SparseLU_gemm_kernel.h | 93 +- .../src/SparseLU/SparseLU_heap_relax_snode.h | 21 +- .../Eigen/src/SparseLU/SparseLU_kernel_bmod.h | 52 +- .../Eigen/src/SparseLU/SparseLU_panel_bmod.h | 6 +- .../Eigen/src/SparseLU/SparseLU_panel_dfs.h | 44 +- .../Eigen/src/SparseLU/SparseLU_pivotL.h | 12 +- .../Eigen/src/SparseLU/SparseLU_pruneL.h | 7 +- .../Eigen/src/SparseLU/SparseLU_relax_snode.h | 12 +- .../eigen/Eigen/src/SparseQR/CMakeLists.txt | 6 - .../libs/eigen/Eigen/src/SparseQR/SparseQR.h | 187 +- .../eigen/Eigen/src/StlSupport/CMakeLists.txt | 6 - .../eigen/Eigen/src/StlSupport/StdDeque.h | 2 +- .../libs/eigen/Eigen/src/StlSupport/StdList.h | 4 +- .../eigen/Eigen/src/StlSupport/StdVector.h | 5 + .../libs/eigen/Eigen/src/StlSupport/details.h | 16 +- .../Eigen/src/SuperLUSupport/CMakeLists.txt | 6 - .../Eigen/src/SuperLUSupport/SuperLUSupport.h | 209 +- .../Eigen/src/UmfPackSupport/CMakeLists.txt | 6 - .../Eigen/src/UmfPackSupport/UmfPackSupport.h | 251 +- .../libs/eigen/Eigen/src/misc/CMakeLists.txt | 6 - .../gcs/src/libs/eigen/Eigen/src/misc/Image.h | 2 - .../src/libs/eigen/Eigen/src/misc/Kernel.h | 4 +- .../libs/eigen/Eigen/src/misc/RealSvd2x2.h | 55 + .../gcs/src/libs/eigen/Eigen/src/misc/Solve.h | 76 - .../libs/eigen/Eigen/src/misc/SparseSolve.h | 128 - .../gcs/src/libs/eigen/Eigen/src/misc/blas.h | 418 +- .../src/libs/eigen/Eigen/src/misc/lapack.h | 152 + .../src/libs/eigen/Eigen/src/misc/lapacke.h | 16291 ++++++++++++++++ .../eigen/Eigen/src/misc/lapacke_mangling.h | 17 + .../Eigen/src/plugins/ArrayCwiseBinaryOps.h | 203 +- .../Eigen/src/plugins/ArrayCwiseUnaryOps.h | 467 +- .../eigen/Eigen/src/plugins/BlockMethods.h | 1269 +- .../eigen/Eigen/src/plugins/CMakeLists.txt | 6 - .../Eigen/src/plugins/CommonCwiseBinaryOps.h | 75 +- .../Eigen/src/plugins/CommonCwiseUnaryOps.h | 205 +- .../Eigen/src/plugins/MatrixCwiseBinaryOps.h | 29 +- .../Eigen/src/plugins/MatrixCwiseUnaryOps.h | 115 +- ...OpenpilotGCS.txt => README.LibrePilot.txt} | 5 +- ground/gcs/src/libs/eigen/README.md | 3 + ground/gcs/src/libs/eigen/bench/BenchTimer.h | 10 +- .../eigen/bench/analyze-blocking-sizes.cpp | 876 + .../src/libs/eigen/bench/benchCholesky.cpp | 16 +- .../gcs/src/libs/eigen/bench/bench_gemm.cpp | 117 +- .../gcs/src/libs/eigen/bench/bench_norm.cpp | 117 +- .../eigen/bench/benchmark-blocking-sizes.cpp | 677 + .../src/libs/eigen/bench/btl/CMakeLists.txt | 31 +- .../eigen/bench/btl/actions/action_axpby.hh | 2 +- .../eigen/bench/btl/actions/action_axpy.hh | 2 +- .../libs/eigen/bench/btl/cmake/FindACML.cmake | 2 + .../eigen/bench/btl/cmake/FindATLAS.cmake | 26 +- .../eigen/bench/btl/cmake/FindBLAZE.cmake | 31 + .../eigen/bench/btl/cmake/FindCBLAS.cmake | 1 + .../libs/eigen/bench/btl/cmake/FindGOTO.cmake | 15 - .../eigen/bench/btl/cmake/FindGOTO2.cmake | 25 - .../eigen/bench/btl/cmake/FindOPENBLAS.cmake | 17 + .../eigen/bench/btl/data/action_settings.txt | 34 +- .../bench/btl/data/perlib_plot_settings.txt | 4 +- .../eigen/bench/btl/generic_bench/bench.hh | 4 +- .../btl/generic_bench/bench_parameter.hh | 4 +- .../libs/eigen/bench/btl/generic_bench/btl.hh | 17 +- .../btl/generic_bench/init/init_function.hh | 8 +- .../btl/generic_bench/init/init_matrix.hh | 10 +- .../btl/generic_bench/init/init_vector.hh | 2 +- .../timers/portable_perf_analyzer.hh | 2 +- .../generic_bench/timers/portable_timer.hh | 46 +- .../btl/generic_bench/utils/size_lin_log.hh | 2 +- .../eigen/bench/btl/libs/BLAS/CMakeLists.txt | 29 +- .../btl/libs/BLAS/blas_interface_impl.hh | 6 +- .../bench/btl/libs/BLAS/c_interface_base.h | 6 +- .../libs/eigen/bench/btl/libs/BLAS/main.cpp | 10 +- .../eigen/bench/btl/libs/STL/STL_interface.hh | 4 +- .../eigen/bench/btl/libs/blaze/CMakeLists.txt | 13 + .../bench/btl/libs/blaze/blaze_interface.hh | 140 + .../libs/eigen/bench/btl/libs/blaze/main.cpp | 40 + .../bench/btl/libs/eigen2/eigen2_interface.hh | 2 +- .../bench/btl/libs/eigen3/eigen3_interface.hh | 58 +- .../eigen/bench/btl/libs/eigen3/main_adv.cpp | 14 +- .../bench/btl/libs/tensors/CMakeLists.txt | 44 + .../bench/btl/libs/tensors/main_linear.cpp | 23 + .../bench/btl/libs/tensors/main_matmat.cpp | 21 + .../bench/btl/libs/tensors/main_vecmat.cpp | 21 + .../btl/libs/tensors/tensor_interface.hh | 105 + .../src/libs/eigen/bench/dense_solvers.cpp | 186 + ground/gcs/src/libs/eigen/bench/eig33.cpp | 57 +- .../bench/perf_monitoring/gemm/changesets.txt | 61 + .../eigen/bench/perf_monitoring/gemm/gemm.cpp | 67 + .../perf_monitoring/gemm/gemm_settings.txt | 15 + .../bench/perf_monitoring/gemm/lazy_gemm.cpp | 98 + .../gemm/lazy_gemm_settings.txt | 15 + .../bench/perf_monitoring/gemm/make_plot.sh | 38 + .../eigen/bench/perf_monitoring/gemm/run.sh | 156 + .../libs/eigen/bench/spbench/CMakeLists.txt | 2 +- .../libs/eigen/bench/spbench/spbenchstyle.h | 3 +- .../gcs/src/libs/eigen/bench/tensors/README | 21 + .../src/libs/eigen/bench/tensors/benchmark.h | 49 + .../eigen/bench/tensors/benchmark_main.cc | 237 + .../tensors/contraction_benchmarks_cpu.cc | 39 + .../eigen/bench/tensors/tensor_benchmarks.h | 478 + .../bench/tensors/tensor_benchmarks_cpu.cc | 168 + .../tensors/tensor_benchmarks_fp16_gpu.cu | 77 + .../bench/tensors/tensor_benchmarks_gpu.cu | 75 + .../bench/tensors/tensor_benchmarks_sycl.cc | 37 + ground/gcs/src/libs/eigen/blas/CMakeLists.txt | 27 +- .../eigen/blas/PackedTriangularMatrixVector.h | 4 +- ground/gcs/src/libs/eigen/blas/chbmv.f | 310 - ground/gcs/src/libs/eigen/blas/chpmv.f | 272 - ground/gcs/src/libs/eigen/blas/common.h | 44 +- ground/gcs/src/libs/eigen/blas/ctbmv.f | 366 - ground/gcs/src/libs/eigen/blas/double.cpp | 11 +- ground/gcs/src/libs/eigen/blas/drotm.f | 147 - ground/gcs/src/libs/eigen/blas/drotmg.f | 206 - ground/gcs/src/libs/eigen/blas/dsbmv.f | 304 - ground/gcs/src/libs/eigen/blas/dspmv.f | 265 - ground/gcs/src/libs/eigen/blas/dtbmv.f | 335 - ground/gcs/src/libs/eigen/blas/f2c/chbmv.c | 487 + ground/gcs/src/libs/eigen/blas/f2c/chpmv.c | 438 + .../gcs/src/libs/eigen/blas/f2c/complexdots.c | 84 + ground/gcs/src/libs/eigen/blas/f2c/ctbmv.c | 647 + ground/gcs/src/libs/eigen/blas/f2c/d_cnjg.c | 6 + .../gcs/src/libs/eigen/blas/f2c/datatypes.h | 24 + ground/gcs/src/libs/eigen/blas/f2c/drotm.c | 215 + ground/gcs/src/libs/eigen/blas/f2c/drotmg.c | 293 + ground/gcs/src/libs/eigen/blas/f2c/dsbmv.c | 366 + ground/gcs/src/libs/eigen/blas/f2c/dspmv.c | 316 + ground/gcs/src/libs/eigen/blas/f2c/dtbmv.c | 428 + ground/gcs/src/libs/eigen/blas/f2c/lsame.c | 117 + ground/gcs/src/libs/eigen/blas/f2c/r_cnjg.c | 6 + ground/gcs/src/libs/eigen/blas/f2c/srotm.c | 216 + ground/gcs/src/libs/eigen/blas/f2c/srotmg.c | 295 + ground/gcs/src/libs/eigen/blas/f2c/ssbmv.c | 368 + ground/gcs/src/libs/eigen/blas/f2c/sspmv.c | 316 + ground/gcs/src/libs/eigen/blas/f2c/stbmv.c | 428 + ground/gcs/src/libs/eigen/blas/f2c/zhbmv.c | 488 + ground/gcs/src/libs/eigen/blas/f2c/zhpmv.c | 438 + ground/gcs/src/libs/eigen/blas/f2c/ztbmv.c | 647 + .../eigen/blas/{ => fortran}/complexdots.f | 0 .../src/libs/eigen/blas/level1_cplx_impl.h | 54 +- ground/gcs/src/libs/eigen/blas/level1_impl.h | 49 +- .../src/libs/eigen/blas/level1_real_impl.h | 22 +- .../src/libs/eigen/blas/level2_cplx_impl.h | 118 +- ground/gcs/src/libs/eigen/blas/level2_impl.h | 429 +- .../src/libs/eigen/blas/level2_real_impl.h | 174 +- ground/gcs/src/libs/eigen/blas/level3_impl.h | 468 +- ground/gcs/src/libs/eigen/blas/lsame.f | 85 - ground/gcs/src/libs/eigen/blas/single.cpp | 2 +- ground/gcs/src/libs/eigen/blas/srotm.f | 148 - ground/gcs/src/libs/eigen/blas/srotmg.f | 208 - ground/gcs/src/libs/eigen/blas/ssbmv.f | 306 - ground/gcs/src/libs/eigen/blas/sspmv.f | 265 - ground/gcs/src/libs/eigen/blas/stbmv.f | 335 - .../gcs/src/libs/eigen/blas/testing/cblat1.f | 83 +- .../gcs/src/libs/eigen/blas/testing/cblat2.f | 188 +- .../gcs/src/libs/eigen/blas/testing/cblat3.f | 185 +- .../gcs/src/libs/eigen/blas/testing/dblat2.f | 186 +- .../gcs/src/libs/eigen/blas/testing/dblat3.f | 168 +- .../gcs/src/libs/eigen/blas/testing/sblat2.f | 186 +- .../gcs/src/libs/eigen/blas/testing/sblat3.f | 168 +- .../gcs/src/libs/eigen/blas/testing/zblat1.f | 83 +- .../gcs/src/libs/eigen/blas/testing/zblat2.f | 188 +- .../gcs/src/libs/eigen/blas/testing/zblat3.f | 189 +- ground/gcs/src/libs/eigen/blas/xerbla.cpp | 4 +- ground/gcs/src/libs/eigen/blas/zhbmv.f | 310 - ground/gcs/src/libs/eigen/blas/zhpmv.f | 272 - ground/gcs/src/libs/eigen/blas/ztbmv.f | 366 - .../libs/eigen/cmake/Eigen3Config.cmake.in | 21 + .../eigen/cmake/Eigen3ConfigLegacy.cmake.in | 30 + .../eigen/cmake/EigenConfigureTesting.cmake | 29 +- .../eigen/cmake/EigenDetermineOSVersion.cmake | 2 +- .../cmake/EigenDetermineVSServicePack.cmake | 18 +- .../src/libs/eigen/cmake/EigenTesting.cmake | 344 +- .../src/libs/eigen/cmake/EigenUninstall.cmake | 40 + .../gcs/src/libs/eigen/cmake/FindAdolc.cmake | 2 +- .../src/libs/eigen/cmake/FindComputeCpp.cmake | 245 + .../gcs/src/libs/eigen/cmake/FindEigen3.cmake | 30 +- .../src/libs/eigen/cmake/FindSuperLU.cmake | 79 +- .../gcs/src/libs/eigen/cmake/UseEigen3.cmake | 6 + .../libs/eigen/cmake/language_support.cmake | 3 +- .../gcs/src/libs/eigen/debug/gdb/printers.py | 12 +- .../eigen/demos/opengl/quaternion_demo.cpp | 2 +- .../src/libs/eigen/demos/opengl/trackball.cpp | 2 +- .../libs/eigen/doc/A05_PortingFrom2To3.dox | 15 +- .../libs/eigen/doc/A10_Eigen2SupportModes.dox | 95 - .../libs/eigen/doc/AsciiQuickReference.txt | 116 +- .../src/libs/eigen/doc/B01_Experimental.dox | 6 +- ground/gcs/src/libs/eigen/doc/CMakeLists.txt | 12 + .../eigen/doc/CoeffwiseMathFunctionsTable.dox | 525 + .../src/libs/eigen/doc/CustomizingEigen.dox | 188 - .../doc/CustomizingEigen_CustomScalar.dox | 120 + .../doc/CustomizingEigen_InheritingMatrix.dox | 34 + .../doc/CustomizingEigen_NullaryExpr.dox | 86 + .../eigen/doc/CustomizingEigen_Plugins.dox | 69 + .../eigen/doc/DenseDecompositionBenchmark.dox | 42 + ground/gcs/src/libs/eigen/doc/Doxyfile.in | 52 +- .../libs/eigen/doc/FixedSizeVectorizable.dox | 4 +- .../libs/eigen/doc/InplaceDecomposition.dox | 115 + .../gcs/src/libs/eigen/doc/LeastSquares.dox | 70 + ground/gcs/src/libs/eigen/doc/Manual.dox | 31 +- .../eigen/doc/MatrixfreeSolverExample.dox | 9 +- .../src/libs/eigen/doc/NewExpressionType.dox | 143 + ground/gcs/src/libs/eigen/doc/Overview.dox | 4 +- .../libs/eigen/doc/PreprocessorDirectives.dox | 80 +- .../gcs/src/libs/eigen/doc/QuickReference.dox | 138 +- .../libs/eigen/doc/SparseLinearSystems.dox | 92 +- .../libs/eigen/doc/SparseQuickReference.dox | 16 +- .../gcs/src/libs/eigen/doc/StlContainers.dox | 4 +- .../eigen/doc/StructHavingEigenMembers.dox | 24 +- .../src/libs/eigen/doc/TemplateKeyword.dox | 17 +- .../gcs/src/libs/eigen/doc/TopicAliasing.dox | 30 +- .../src/libs/eigen/doc/TopicAssertions.dox | 2 +- .../src/libs/eigen/doc/TopicCMakeGuide.dox | 52 + .../libs/eigen/doc/TopicLazyEvaluation.dox | 4 +- .../doc/TopicLinearAlgebraDecompositions.dox | 8 +- .../libs/eigen/doc/TopicMultithreading.dox | 16 +- .../src/libs/eigen/doc/TutorialArrayClass.dox | 2 +- .../src/libs/eigen/doc/TutorialGeometry.dox | 9 +- .../libs/eigen/doc/TutorialLinearAlgebra.dox | 37 +- ...TutorialReductionsVisitorsBroadcasting.dox | 29 +- .../libs/eigen/doc/TutorialReshapeSlicing.dox | 65 + .../gcs/src/libs/eigen/doc/TutorialSparse.dox | 16 +- .../libs/eigen/doc/UnalignedArrayAssert.dox | 23 +- .../eigen/doc/UsingBlasLapackBackends.dox | 133 + .../gcs/src/libs/eigen/doc/UsingIntelMKL.dox | 96 +- ground/gcs/src/libs/eigen/doc/UsingNVCC.dox | 32 + ground/gcs/src/libs/eigen/doc/eigendoxy.css | 41 +- .../libs/eigen/doc/examples/CMakeLists.txt | 5 + .../examples/CustomizingEigen_Inheritance.cpp | 30 + .../src/libs/eigen/doc/examples/Cwise_erf.cpp | 9 + .../libs/eigen/doc/examples/Cwise_erfc.cpp | 9 + .../libs/eigen/doc/examples/Cwise_lgamma.cpp | 9 + .../doc/examples/MatrixBase_cwise_const.cpp | 18 - .../eigen/doc/examples/TutorialInplaceLU.cpp | 61 + .../TutorialLinAlgInverseDeterminant.cpp | 2 +- ...rsBroadcasting_reductions_operatornorm.cpp | 18 + .../eigen/doc/examples/make_circulant.cpp | 11 + .../doc/examples/make_circulant.cpp.entry | 5 + .../doc/examples/make_circulant.cpp.evaluator | 32 + .../examples/make_circulant.cpp.expression | 20 + .../doc/examples/make_circulant.cpp.main | 8 + .../doc/examples/make_circulant.cpp.preamble | 4 + .../doc/examples/make_circulant.cpp.traits | 19 + .../eigen/doc/examples/make_circulant2.cpp | 52 + .../libs/eigen/doc/examples/matrixfree_cg.cpp | 210 +- .../eigen/doc/examples/nullary_indexing.cpp | 66 + ground/gcs/src/libs/eigen/doc/ftv2node.png | Bin 0 -> 86 bytes ground/gcs/src/libs/eigen/doc/ftv2pnode.png | Bin 0 -> 229 bytes .../eigen/doc/snippets/BiCGSTAB_simple.cpp | 11 + .../doc/snippets/BiCGSTAB_step_by_step.cpp | 14 + .../libs/eigen/doc/snippets/CMakeLists.txt | 2 - .../src/libs/eigen/doc/snippets/Cwise_arg.cpp | 3 + .../doc/snippets/Cwise_array_power_array.cpp | 4 + .../libs/eigen/doc/snippets/Cwise_atan.cpp | 2 + .../eigen/doc/snippets/Cwise_boolean_not.cpp | 5 + .../eigen/doc/snippets/Cwise_boolean_xor.cpp | 2 + .../libs/eigen/doc/snippets/Cwise_ceil.cpp | 3 + .../libs/eigen/doc/snippets/Cwise_cosh.cpp | 2 + .../libs/eigen/doc/snippets/Cwise_floor.cpp | 3 + .../eigen/doc/snippets/Cwise_isFinite.cpp | 5 + .../libs/eigen/doc/snippets/Cwise_isInf.cpp | 5 + .../libs/eigen/doc/snippets/Cwise_isNaN.cpp | 5 + .../libs/eigen/doc/snippets/Cwise_log10.cpp | 2 + .../libs/eigen/doc/snippets/Cwise_round.cpp | 3 + .../doc/snippets/Cwise_scalar_power_array.cpp | 2 + .../libs/eigen/doc/snippets/Cwise_sign.cpp | 2 + .../libs/eigen/doc/snippets/Cwise_sinh.cpp | 2 + .../libs/eigen/doc/snippets/Cwise_tanh.cpp | 2 + .../doc/snippets/DenseBase_LinSpacedInt.cpp | 8 + .../snippets/DirectionWise_hnormalized.cpp | 7 + .../doc/snippets/EigenSolver_eigenvectors.cpp | 4 +- .../snippets/LeastSquaresNormalEquations.cpp | 4 + .../eigen/doc/snippets/LeastSquaresQR.cpp | 4 + .../doc/snippets/MatrixBase_cwiseSign.cpp | 4 + .../doc/snippets/MatrixBase_hnormalized.cpp | 6 + .../doc/snippets/MatrixBase_homogeneous.cpp | 6 + .../eigen/doc/snippets/MatrixBase_marked.cpp | 14 - .../eigen/doc/snippets/MatrixBase_part.cpp | 13 - .../snippets/MatrixBase_selfadjointView.cpp | 6 + ...ract.cpp => MatrixBase_triangularView.cpp} | 12 +- .../eigen/doc/snippets/PartialRedux_count.cpp | 4 +- .../doc/snippets/SparseMatrix_coeffs.cpp | 9 + .../doc/snippets/TopicAliasing_mult4.cpp | 5 + .../doc/snippets/TopicAliasing_mult5.cpp | 5 + .../eigen/doc/snippets/Triangular_solve.cpp | 11 + .../Tutorial_AdvancedInitialization_Join.cpp | 2 +- .../doc/snippets/Tutorial_ReshapeMat2Mat.cpp | 6 + .../doc/snippets/Tutorial_ReshapeMat2Vec.cpp | 11 + .../doc/snippets/Tutorial_SlicingCol.cpp | 11 + .../doc/snippets/Tutorial_SlicingVec.cpp | 4 + .../doc/snippets/VectorwiseOp_homogeneous.cpp | 7 + .../eigen/doc/snippets/compile_snippet.cpp.in | 10 +- .../eigen/doc/special_examples/CMakeLists.txt | 14 + .../Tutorial_sparse_example.cpp | 2 + .../Tutorial_sparse_example_details.cpp | 2 +- .../doc/special_examples/random_cpp11.cpp | 14 + .../src/libs/eigen/failtest/CMakeLists.txt | 21 + .../src/libs/eigen/failtest/bdcsvd_int.cpp | 14 + ...seunaryview_nonconst_ctor_on_const_xpr.cpp | 15 + ...unaryview_on_const_type_actually_const.cpp | 16 + ...adjointview_nonconst_ctor_on_const_xpr.cpp | 15 + ...jointview_on_const_type_actually_const.cpp | 16 + .../src/libs/eigen/failtest/sparse_ref_1.cpp | 18 + .../src/libs/eigen/failtest/sparse_ref_2.cpp | 15 + .../src/libs/eigen/failtest/sparse_ref_3.cpp | 15 + .../src/libs/eigen/failtest/sparse_ref_4.cpp | 15 + .../src/libs/eigen/failtest/sparse_ref_5.cpp | 16 + .../failtest/sparse_storage_mismatch.cpp | 16 + ground/gcs/src/libs/eigen/failtest/swap_1.cpp | 14 + ground/gcs/src/libs/eigen/failtest/swap_2.cpp | 14 + .../gcs/src/libs/eigen/failtest/ternary_1.cpp | 13 + .../gcs/src/libs/eigen/failtest/ternary_2.cpp | 13 + ...angularview_nonconst_ctor_on_const_xpr.cpp | 15 + ...gularview_on_const_type_actually_const.cpp | 16 + .../src/libs/eigen/lapack/complex_double.cpp | 3 +- .../src/libs/eigen/lapack/complex_single.cpp | 3 +- ground/gcs/src/libs/eigen/lapack/double.cpp | 3 +- .../gcs/src/libs/eigen/lapack/eigenvalues.cpp | 27 +- .../gcs/src/libs/eigen/lapack/lapack_common.h | 8 +- ground/gcs/src/libs/eigen/lapack/single.cpp | 3 +- ground/gcs/src/libs/eigen/lapack/svd.cpp | 138 + .../gcs/src/libs/eigen/scripts/buildtests.in | 6 +- ground/gcs/src/libs/eigen/scripts/check.in | 2 +- .../gcs/src/libs/eigen/scripts/eigen_gen_docs | 2 +- ground/gcs/src/libs/eigen/test/CMakeLists.txt | 213 +- ground/gcs/src/libs/eigen/test/adjoint.cpp | 42 +- ground/gcs/src/libs/eigen/test/array.cpp | 243 +- .../src/libs/eigen/test/array_for_matrix.cpp | 34 +- .../src/libs/eigen/test/array_of_string.cpp | 32 + .../src/libs/eigen/test/array_replicate.cpp | 13 + .../gcs/src/libs/eigen/test/array_reverse.cpp | 32 +- ground/gcs/src/libs/eigen/test/bandmatrix.cpp | 3 - ground/gcs/src/libs/eigen/test/basicstuff.cpp | 86 +- ground/gcs/src/libs/eigen/test/bdcsvd.cpp | 111 + ground/gcs/src/libs/eigen/test/bicgstab.cpp | 16 +- ground/gcs/src/libs/eigen/test/block.cpp | 31 +- .../src/libs/eigen/test/boostmultiprec.cpp | 201 + ground/gcs/src/libs/eigen/test/bug1213.cpp | 13 + ground/gcs/src/libs/eigen/test/bug1213.h | 8 + .../gcs/src/libs/eigen/test/bug1213_main.cpp | 18 + ground/gcs/src/libs/eigen/test/cholesky.cpp | 157 +- .../src/libs/eigen/test/cholmod_support.cpp | 15 +- .../src/libs/eigen/test/commainitializer.cpp | 60 + .../libs/eigen/test/conjugate_gradient.cpp | 18 +- .../gcs/src/libs/eigen/test/constructor.cpp | 84 + ground/gcs/src/libs/eigen/test/ctorleak.cpp | 69 + ground/gcs/src/libs/eigen/test/cuda_basic.cu | 173 + ground/gcs/src/libs/eigen/test/cuda_common.h | 101 + ground/gcs/src/libs/eigen/test/cwiseop.cpp | 184 - .../gcs/src/libs/eigen/test/dense_storage.cpp | 76 + ground/gcs/src/libs/eigen/test/diagonal.cpp | 24 + .../src/libs/eigen/test/diagonalmatrices.cpp | 27 + ground/gcs/src/libs/eigen/test/dynalloc.cpp | 66 +- .../src/libs/eigen/test/eigen2/CMakeLists.txt | 61 - .../libs/eigen/test/eigen2/eigen2_adjoint.cpp | 99 - .../eigen/test/eigen2/eigen2_alignedbox.cpp | 60 - .../libs/eigen/test/eigen2/eigen2_array.cpp | 142 - .../eigen/test/eigen2/eigen2_basicstuff.cpp | 105 - .../libs/eigen/test/eigen2/eigen2_bug_132.cpp | 26 - .../eigen/test/eigen2/eigen2_cholesky.cpp | 113 - .../test/eigen2/eigen2_commainitializer.cpp | 46 - .../libs/eigen/test/eigen2/eigen2_cwiseop.cpp | 155 - .../eigen/test/eigen2/eigen2_determinant.cpp | 61 - .../eigen/test/eigen2/eigen2_dynalloc.cpp | 131 - .../eigen/test/eigen2/eigen2_eigensolver.cpp | 146 - .../test/eigen2/eigen2_first_aligned.cpp | 49 - .../eigen/test/eigen2/eigen2_geometry.cpp | 432 - .../eigen2_geometry_with_eigen2_prefix.cpp | 435 - .../eigen/test/eigen2/eigen2_hyperplane.cpp | 126 - .../libs/eigen/test/eigen2/eigen2_inverse.cpp | 62 - .../test/eigen2/eigen2_linearstructure.cpp | 83 - .../src/libs/eigen/test/eigen2/eigen2_lu.cpp | 122 - .../src/libs/eigen/test/eigen2/eigen2_map.cpp | 114 - .../libs/eigen/test/eigen2/eigen2_meta.cpp | 60 - .../eigen/test/eigen2/eigen2_miscmatrices.cpp | 48 - .../eigen/test/eigen2/eigen2_mixingtypes.cpp | 77 - .../eigen/test/eigen2/eigen2_newstdvector.cpp | 149 - .../eigen/test/eigen2/eigen2_nomalloc.cpp | 53 - .../eigen/test/eigen2/eigen2_packetmath.cpp | 132 - .../test/eigen2/eigen2_parametrizedline.cpp | 62 - .../test/eigen2/eigen2_prec_inverse_4x4.cpp | 84 - .../test/eigen2/eigen2_product_large.cpp | 45 - .../test/eigen2/eigen2_product_small.cpp | 22 - .../src/libs/eigen/test/eigen2/eigen2_qr.cpp | 69 - .../eigen/test/eigen2/eigen2_qtvector.cpp | 158 - .../eigen/test/eigen2/eigen2_regression.cpp | 136 - .../libs/eigen/test/eigen2/eigen2_sizeof.cpp | 31 - .../eigen/test/eigen2/eigen2_smallvectors.cpp | 42 - .../eigen/test/eigen2/eigen2_sparse_basic.cpp | 317 - .../test/eigen2/eigen2_sparse_product.cpp | 115 - .../test/eigen2/eigen2_sparse_solvers.cpp | 200 - .../test/eigen2/eigen2_sparse_vector.cpp | 84 - .../eigen/test/eigen2/eigen2_stdvector.cpp | 148 - .../eigen/test/eigen2/eigen2_submatrices.cpp | 142 - .../src/libs/eigen/test/eigen2/eigen2_sum.cpp | 71 - .../src/libs/eigen/test/eigen2/eigen2_svd.cpp | 87 - .../libs/eigen/test/eigen2/eigen2_swap.cpp | 83 - .../eigen/test/eigen2/eigen2_triangular.cpp | 148 - .../test/eigen2/eigen2_unalignedassert.cpp | 116 - .../libs/eigen/test/eigen2/eigen2_visitor.cpp | 116 - .../src/libs/eigen/test/eigen2/gsl_helper.h | 175 - ground/gcs/src/libs/eigen/test/eigen2/main.h | 399 - .../gcs/src/libs/eigen/test/eigen2/product.h | 129 - .../gcs/src/libs/eigen/test/eigen2/runtest.sh | 28 - .../gcs/src/libs/eigen/test/eigen2/sparse.h | 154 - .../libs/eigen/test/eigen2/testsuite.cmake | 197 - .../gcs/src/libs/eigen/test/eigen2support.cpp | 1 - .../libs/eigen/test/eigensolver_complex.cpp | 71 +- .../test/eigensolver_generalized_real.cpp | 54 +- .../libs/eigen/test/eigensolver_generic.cpp | 49 +- .../eigen/test/eigensolver_selfadjoint.cpp | 180 +- .../src/libs/eigen/test/evaluator_common.h | 0 ground/gcs/src/libs/eigen/test/evaluators.cpp | 499 + ground/gcs/src/libs/eigen/test/fastmath.cpp | 99 + .../gcs/src/libs/eigen/test/first_aligned.cpp | 6 +- .../src/libs/eigen/test/geo_alignedbox.cpp | 11 +- .../src/libs/eigen/test/geo_eulerangles.cpp | 20 +- .../src/libs/eigen/test/geo_homogeneous.cpp | 26 +- .../src/libs/eigen/test/geo_hyperplane.cpp | 39 +- .../src/libs/eigen/test/geo_orthomethods.cpp | 14 +- .../libs/eigen/test/geo_parametrizedline.cpp | 10 +- .../src/libs/eigen/test/geo_quaternion.cpp | 51 +- .../libs/eigen/test/geo_transformations.cpp | 170 +- ground/gcs/src/libs/eigen/test/half_float.cpp | 252 + .../libs/eigen/test/incomplete_cholesky.cpp | 65 + .../libs/eigen/test/inplace_decomposition.cpp | 110 + .../gcs/src/libs/eigen/test/integer_types.cpp | 8 + ground/gcs/src/libs/eigen/test/inverse.cpp | 15 +- .../gcs/src/libs/eigen/test/is_same_dense.cpp | 33 + ground/gcs/src/libs/eigen/test/jacobisvd.cpp | 386 +- .../src/libs/eigen/test/linearstructure.cpp | 67 +- ground/gcs/src/libs/eigen/test/lscg.cpp | 29 + ground/gcs/src/libs/eigen/test/lu.cpp | 83 +- ground/gcs/src/libs/eigen/test/main.h | 284 +- .../gcs/src/libs/eigen/test/mapped_matrix.cpp | 86 +- .../src/libs/eigen/test/mapstaticmethods.cpp | 6 +- ground/gcs/src/libs/eigen/test/mapstride.cpp | 43 +- ground/gcs/src/libs/eigen/test/meta.cpp | 24 + .../gcs/src/libs/eigen/test/metis_support.cpp | 22 +- .../gcs/src/libs/eigen/test/mixingtypes.cpp | 202 +- ground/gcs/src/libs/eigen/test/mpl2only.cpp | 2 + .../gcs/src/libs/eigen/test/nesting_ops.cpp | 86 +- ground/gcs/src/libs/eigen/test/nomalloc.cpp | 59 +- ground/gcs/src/libs/eigen/test/nullary.cpp | 225 +- ground/gcs/src/libs/eigen/test/packetmath.cpp | 424 +- .../src/libs/eigen/test/pastix_support.cpp | 10 + .../libs/eigen/test/permutationmatrices.cpp | 62 +- .../src/libs/eigen/test/prec_inverse_4x4.cpp | 15 + ground/gcs/src/libs/eigen/test/product.h | 66 +- .../gcs/src/libs/eigen/test/product_extra.cpp | 146 +- .../gcs/src/libs/eigen/test/product_large.cpp | 32 +- .../gcs/src/libs/eigen/test/product_mmtr.cpp | 28 +- .../libs/eigen/test/product_notemporary.cpp | 59 +- .../libs/eigen/test/product_selfadjoint.cpp | 9 +- .../gcs/src/libs/eigen/test/product_small.cpp | 247 +- .../gcs/src/libs/eigen/test/product_symm.cpp | 18 + .../gcs/src/libs/eigen/test/product_syrk.cpp | 5 +- .../gcs/src/libs/eigen/test/product_trmm.cpp | 22 +- .../gcs/src/libs/eigen/test/product_trmv.cpp | 6 +- .../src/libs/eigen/test/product_trsolve.cpp | 18 +- ground/gcs/src/libs/eigen/test/qr.cpp | 9 +- .../src/libs/eigen/test/qr_colpivoting.cpp | 206 +- .../src/libs/eigen/test/qr_fullpivoting.cpp | 34 +- ground/gcs/src/libs/eigen/test/rand.cpp | 118 + ground/gcs/src/libs/eigen/test/real_qz.cpp | 16 +- ground/gcs/src/libs/eigen/test/redux.cpp | 13 +- ground/gcs/src/libs/eigen/test/ref.cpp | 27 +- ground/gcs/src/libs/eigen/test/runtest.sh | 20 - .../gcs/src/libs/eigen/test/rvalue_types.cpp | 14 +- .../gcs/src/libs/eigen/test/schur_complex.cpp | 4 +- ground/gcs/src/libs/eigen/test/schur_real.cpp | 4 +- .../gcs/src/libs/eigen/test/selfadjoint.cpp | 15 +- .../libs/eigen/test/simplicial_cholesky.cpp | 28 +- ground/gcs/src/libs/eigen/test/sizeof.cpp | 17 +- .../gcs/src/libs/eigen/test/sizeoverflow.cpp | 2 - ground/gcs/src/libs/eigen/test/sparse.h | 23 +- .../gcs/src/libs/eigen/test/sparse_basic.cpp | 662 +- .../gcs/src/libs/eigen/test/sparse_block.cpp | 317 + .../libs/eigen/test/sparse_permutations.cpp | 95 +- .../src/libs/eigen/test/sparse_product.cpp | 203 +- ground/gcs/src/libs/eigen/test/sparse_ref.cpp | 139 + .../gcs/src/libs/eigen/test/sparse_solver.h | 386 +- .../gcs/src/libs/eigen/test/sparse_vector.cpp | 75 +- ground/gcs/src/libs/eigen/test/sparselu.cpp | 28 +- ground/gcs/src/libs/eigen/test/sparseqr.cpp | 12 +- .../gcs/src/libs/eigen/test/spqr_support.cpp | 8 +- .../gcs/src/libs/eigen/test/stable_norm.cpp | 105 +- ground/gcs/src/libs/eigen/test/stdvector.cpp | 6 +- .../libs/eigen/test/stdvector_overload.cpp | 6 +- .../src/libs/eigen/test/superlu_support.cpp | 1 + ground/gcs/src/libs/eigen/test/svd_common.h | 483 + ground/gcs/src/libs/eigen/test/svd_fill.h | 119 + ground/gcs/src/libs/eigen/test/swap.cpp | 23 +- .../gcs/src/libs/eigen/test/testsuite.cmake | 229 - ground/gcs/src/libs/eigen/test/triangular.cpp | 19 +- .../src/libs/eigen/test/umfpack_support.cpp | 1 + .../src/libs/eigen/test/unalignedassert.cpp | 93 +- .../src/libs/eigen/test/unalignedcount.cpp | 9 +- .../eigen/test/upperbidiagonalization.cpp | 2 +- .../libs/eigen/test/vectorization_logic.cpp | 292 +- .../gcs/src/libs/eigen/test/vectorwiseop.cpp | 75 +- ground/gcs/src/libs/eigen/test/zerosized.cpp | 20 +- .../libs/eigen/unsupported/Eigen/AdolcForward | 2 +- .../eigen/unsupported/Eigen/AlignedVector3 | 38 +- .../eigen/unsupported/Eigen/CMakeLists.txt | 31 +- .../unsupported/Eigen/CXX11/CMakeLists.txt | 8 + .../libs/eigen/unsupported/Eigen/CXX11/Tensor | 152 + .../unsupported/Eigen/CXX11/TensorSymmetry | 42 + .../eigen/unsupported/Eigen/CXX11/ThreadPool | 65 + .../Eigen/CXX11/src/Tensor/README.md | 1757 ++ .../Eigen/CXX11/src/Tensor/Tensor.h | 527 + .../Eigen/CXX11/src/Tensor/TensorArgMax.h | 299 + .../Eigen/CXX11/src/Tensor/TensorAssign.h | 181 + .../Eigen/CXX11/src/Tensor/TensorBase.h | 1010 + .../CXX11/src/Tensor/TensorBroadcasting.h | 392 + .../Eigen/CXX11/src/Tensor/TensorChipping.h | 384 + .../CXX11/src/Tensor/TensorConcatenation.h | 361 + .../CXX11/src/Tensor/TensorContraction.h | 628 + .../src/Tensor/TensorContractionBlocking.h | 56 + .../CXX11/src/Tensor/TensorContractionCuda.h | 1391 ++ .../src/Tensor/TensorContractionMapper.h | 467 + .../src/Tensor/TensorContractionThreadPool.h | 1052 + .../Eigen/CXX11/src/Tensor/TensorConversion.h | 279 + .../CXX11/src/Tensor/TensorConvolution.h | 1104 ++ .../Eigen/CXX11/src/Tensor/TensorCostModel.h | 212 + .../Eigen/CXX11/src/Tensor/TensorCustomOp.h | 313 + .../Eigen/CXX11/src/Tensor/TensorDevice.h | 68 + .../Eigen/CXX11/src/Tensor/TensorDeviceCuda.h | 337 + .../CXX11/src/Tensor/TensorDeviceDefault.h | 81 + .../Eigen/CXX11/src/Tensor/TensorDeviceSycl.h | 122 + .../CXX11/src/Tensor/TensorDeviceThreadPool.h | 279 + .../CXX11/src/Tensor/TensorDimensionList.h | 236 + .../Eigen/CXX11/src/Tensor/TensorDimensions.h | 428 + .../Eigen/CXX11/src/Tensor/TensorEvalTo.h | 181 + .../Eigen/CXX11/src/Tensor/TensorEvaluator.h | 633 + .../Eigen/CXX11/src/Tensor/TensorExecutor.h | 288 + .../Eigen/CXX11/src/Tensor/TensorExpr.h | 371 + .../Eigen/CXX11/src/Tensor/TensorFFT.h | 651 + .../Eigen/CXX11/src/Tensor/TensorFixedSize.h | 389 + .../Eigen/CXX11/src/Tensor/TensorForcedEval.h | 167 + .../src/Tensor/TensorForwardDeclarations.h | 109 + .../Eigen/CXX11/src/Tensor/TensorFunctors.h | 489 + .../Eigen/CXX11/src/Tensor/TensorGenerator.h | 185 + .../CXX11/src/Tensor/TensorGlobalFunctions.h | 33 + .../Eigen/CXX11/src/Tensor/TensorIO.h | 79 + .../Eigen/CXX11/src/Tensor/TensorImagePatch.h | 509 + .../Eigen/CXX11/src/Tensor/TensorIndexList.h | 725 + .../Eigen/CXX11/src/Tensor/TensorInflation.h | 229 + .../CXX11/src/Tensor/TensorInitializer.h | 82 + .../Eigen/CXX11/src/Tensor/TensorIntDiv.h | 253 + .../Eigen/CXX11/src/Tensor/TensorLayoutSwap.h | 209 + .../Eigen/CXX11/src/Tensor/TensorMacros.h | 54 + .../Eigen/CXX11/src/Tensor/TensorMap.h | 321 + .../Eigen/CXX11/src/Tensor/TensorMeta.h | 218 + .../Eigen/CXX11/src/Tensor/TensorMorphing.h | 888 + .../Eigen/CXX11/src/Tensor/TensorPadding.h | 397 + .../Eigen/CXX11/src/Tensor/TensorPatch.h | 269 + .../Eigen/CXX11/src/Tensor/TensorRandom.h | 276 + .../Eigen/CXX11/src/Tensor/TensorReduction.h | 781 + .../CXX11/src/Tensor/TensorReductionCuda.h | 750 + .../CXX11/src/Tensor/TensorReductionSycl.h | 242 + .../Eigen/CXX11/src/Tensor/TensorRef.h | 429 + .../Eigen/CXX11/src/Tensor/TensorReverse.h | 288 + .../Eigen/CXX11/src/Tensor/TensorScan.h | 287 + .../Eigen/CXX11/src/Tensor/TensorShuffling.h | 264 + .../Eigen/CXX11/src/Tensor/TensorStorage.h | 146 + .../Eigen/CXX11/src/Tensor/TensorStriding.h | 338 + .../Eigen/CXX11/src/Tensor/TensorSycl.h | 82 + .../TensorSyclConvertToDeviceExpression.h | 121 + .../src/Tensor/TensorSyclExprConstructor.h | 239 + .../src/Tensor/TensorSyclExtractAccessor.h | 204 + .../src/Tensor/TensorSyclExtractFunctors.h | 177 + .../CXX11/src/Tensor/TensorSyclLeafCount.h | 114 + .../src/Tensor/TensorSyclPlaceHolderExpr.h | 181 + .../Eigen/CXX11/src/Tensor/TensorSyclRun.h | 70 + .../Eigen/CXX11/src/Tensor/TensorSyclTuple.h | 234 + .../Eigen/CXX11/src/Tensor/TensorTraits.h | 272 + .../Eigen/CXX11/src/Tensor/TensorUInt128.h | 248 + .../CXX11/src/Tensor/TensorVolumePatch.h | 608 + .../src/TensorSymmetry/DynamicSymmetry.h | 293 + .../CXX11/src/TensorSymmetry/StaticSymmetry.h | 236 + .../Eigen/CXX11/src/TensorSymmetry/Symmetry.h | 338 + .../TensorSymmetry/util/TemplateGroupTheory.h | 666 + .../Eigen/CXX11/src/ThreadPool/EventCount.h | 233 + .../src/ThreadPool/NonBlockingThreadPool.h | 274 + .../Eigen/CXX11/src/ThreadPool/RunQueue.h | 210 + .../CXX11/src/ThreadPool/SimpleThreadPool.h | 154 + .../CXX11/src/ThreadPool/ThreadEnvironment.h | 38 + .../Eigen/CXX11/src/ThreadPool/ThreadLocal.h | 22 + .../src/ThreadPool/ThreadPoolInterface.h | 33 + .../Eigen/CXX11/src/ThreadPool/ThreadYield.h | 20 + .../Eigen/CXX11/src/util/CXX11Meta.h | 542 + .../Eigen/CXX11/src/util/CXX11Workarounds.h | 88 + .../Eigen/CXX11/src/util/EmulateArray.h | 267 + .../Eigen/CXX11/src/util/EmulateCXX11Meta.h | 311 + .../Eigen/CXX11/src/util/MaxSizeVector.h | 141 + .../libs/eigen/unsupported/Eigen/EulerAngles | 43 + .../eigen/unsupported/Eigen/IterativeSolvers | 5 +- .../eigen/unsupported/Eigen/KroneckerProduct | 2 + .../eigen/unsupported/Eigen/MPRealSupport | 104 +- .../eigen/unsupported/Eigen/MatrixFunctions | 76 +- .../eigen/unsupported/Eigen/OpenGLSupport | 20 +- .../gcs/src/libs/eigen/unsupported/Eigen/SVD | 39 - .../libs/eigen/unsupported/Eigen/SparseExtra | 3 - .../eigen/unsupported/Eigen/SpecialFunctions | 63 + .../Eigen/src/AutoDiff/AutoDiffJacobian.h | 49 +- .../Eigen/src/AutoDiff/AutoDiffScalar.h | 222 +- .../Eigen/src/AutoDiff/CMakeLists.txt | 6 - .../unsupported/Eigen/src/BVH/CMakeLists.txt | 6 - .../unsupported/Eigen/src/CMakeLists.txt | 15 - .../ArpackSelfAdjointEigenSolver.h | 14 +- .../Eigen/src/Eigenvalues/CMakeLists.txt | 6 - .../Eigen/src/EulerAngles/CMakeLists.txt | 6 + .../Eigen/src/EulerAngles/EulerAngles.h | 386 + .../Eigen/src/EulerAngles/EulerSystem.h | 326 + .../unsupported/Eigen/src/FFT/CMakeLists.txt | 6 - .../Eigen/src/IterativeSolvers/CMakeLists.txt | 6 - .../Eigen/src/IterativeSolvers/DGMRES.h | 57 +- .../Eigen/src/IterativeSolvers/GMRES.h | 406 +- .../src/IterativeSolvers/IncompleteCholesky.h | 278 - .../Eigen/src/IterativeSolvers/IncompleteLU.h | 39 +- .../Eigen/src/IterativeSolvers/MINRES.h | 84 +- .../Eigen/src/IterativeSolvers/Scaling.h | 6 +- .../Eigen/src/KroneckerProduct/CMakeLists.txt | 6 - .../KroneckerProduct/KroneckerTensorProduct.h | 169 +- .../src/LevenbergMarquardt/CMakeLists.txt | 6 - .../Eigen/src/LevenbergMarquardt/LMcovar.h | 1 - .../Eigen/src/LevenbergMarquardt/LMpar.h | 2 +- .../Eigen/src/LevenbergMarquardt/LMqrsolv.h | 9 +- .../LevenbergMarquardt/LevenbergMarquardt.h | 31 +- .../Eigen/src/MatrixFunctions/CMakeLists.txt | 6 - .../src/MatrixFunctions/MatrixExponential.h | 665 +- .../src/MatrixFunctions/MatrixFunction.h | 708 +- .../MatrixFunctions/MatrixFunctionAtomic.h | 131 - .../src/MatrixFunctions/MatrixLogarithm.h | 507 +- .../Eigen/src/MatrixFunctions/MatrixPower.h | 397 +- .../src/MatrixFunctions/MatrixSquareRoot.h | 450 +- .../Eigen/src/MatrixFunctions/StemFunction.h | 172 +- .../src/MoreVectorization/CMakeLists.txt | 6 - .../src/NonLinearOptimization/CMakeLists.txt | 6 - .../HybridNonLinearSolver.h | 4 +- .../LevenbergMarquardt.h | 25 +- .../Eigen/src/NumericalDiff/CMakeLists.txt | 6 - .../Eigen/src/Polynomials/CMakeLists.txt | 6 - .../Eigen/src/Polynomials/PolynomialSolver.h | 33 +- .../Eigen/src/Polynomials/PolynomialUtils.h | 2 +- .../eigen/unsupported/Eigen/src/SVD/BDCSVD.h | 748 - .../unsupported/Eigen/src/SVD/CMakeLists.txt | 6 - .../unsupported/Eigen/src/SVD/JacobiSVD.h | 782 - .../unsupported/Eigen/src/SVD/TODOBdcsvd.txt | 29 - .../Eigen/src/SVD/doneInBDCSVD.txt | 21 - .../Eigen/src/Skyline/CMakeLists.txt | 6 - .../Eigen/src/Skyline/SkylineProduct.h | 6 +- .../Eigen/src/SparseExtra/BlockSparseMatrix.h | 1079 + .../Eigen/src/SparseExtra/CMakeLists.txt | 6 - .../src/SparseExtra/DynamicSparseMatrix.h | 71 +- .../Eigen/src/SparseExtra/MarketIO.h | 21 +- .../src/SparseExtra/MatrixMarketIterator.h | 43 +- .../Eigen/src/SparseExtra/RandomSetter.h | 10 +- .../SpecialFunctionsArrayAPI.h | 124 + .../SpecialFunctionsFunctors.h | 236 + .../SpecialFunctions/SpecialFunctionsHalf.h | 47 + .../SpecialFunctions/SpecialFunctionsImpl.h | 1565 ++ .../SpecialFunctionsPacketMath.h | 58 + .../arch/CUDA/CudaSpecialFunctions.h | 165 + .../Eigen/src/Splines/CMakeLists.txt | 6 - .../unsupported/Eigen/src/Splines/Spline.h | 74 +- .../Eigen/src/Splines/SplineFitting.h | 274 + .../unsupported/Eigen/src/Splines/SplineFwd.h | 11 +- .../libs/eigen/unsupported/doc/Overview.dox | 11 +- .../unsupported/doc/examples/BVH_Example.cpp | 4 +- .../unsupported/doc/examples/EulerAngles.cpp | 46 + .../eigen/unsupported/test/CMakeLists.txt | 177 +- .../eigen/unsupported/test/EulerAngles.cpp | 208 + .../src/libs/eigen/unsupported/test/FFTW.cpp | 32 +- .../test/NonLinearOptimization.cpp | 46 +- .../eigen/unsupported/test/alignedvector3.cpp | 29 +- .../libs/eigen/unsupported/test/autodiff.cpp | 206 +- .../unsupported/test/autodiff_scalar.cpp | 83 + .../libs/eigen/unsupported/test/bdcsvd.cpp | 213 - .../unsupported/test/cxx11_eventcount.cpp | 142 + .../eigen/unsupported/test/cxx11_meta.cpp | 357 + .../test/cxx11_non_blocking_thread_pool.cpp | 107 + .../eigen/unsupported/test/cxx11_runqueue.cpp | 235 + .../unsupported/test/cxx11_tensor_argmax.cpp | 294 + .../test/cxx11_tensor_argmax_cuda.cu | 254 + .../unsupported/test/cxx11_tensor_assign.cpp | 370 + .../test/cxx11_tensor_broadcast_sycl.cpp | 74 + .../test/cxx11_tensor_broadcasting.cpp | 194 + .../test/cxx11_tensor_cast_float16_cuda.cu | 82 + .../unsupported/test/cxx11_tensor_casts.cpp | 115 + .../test/cxx11_tensor_chipping.cpp | 425 + .../test/cxx11_tensor_comparisons.cpp | 84 + .../test/cxx11_tensor_complex_cuda.cu | 153 + .../cxx11_tensor_complex_cwise_ops_cuda.cu | 97 + .../test/cxx11_tensor_concatenation.cpp | 137 + .../unsupported/test/cxx11_tensor_const.cpp | 62 + .../test/cxx11_tensor_contract_cuda.cu | 216 + .../test/cxx11_tensor_contraction.cpp | 545 + .../test/cxx11_tensor_convolution.cpp | 149 + .../unsupported/test/cxx11_tensor_cuda.cu | 1287 ++ .../test/cxx11_tensor_custom_index.cpp | 100 + .../test/cxx11_tensor_custom_op.cpp | 111 + .../unsupported/test/cxx11_tensor_device.cu | 390 + .../test/cxx11_tensor_device_sycl.cpp | 31 + .../test/cxx11_tensor_dimension.cpp | 69 + .../unsupported/test/cxx11_tensor_empty.cpp | 40 + .../unsupported/test/cxx11_tensor_expr.cpp | 314 + .../unsupported/test/cxx11_tensor_fft.cpp | 273 + .../test/cxx11_tensor_fixed_size.cpp | 261 + .../test/cxx11_tensor_forced_eval.cpp | 79 + .../test/cxx11_tensor_forced_eval_sycl.cpp | 70 + .../test/cxx11_tensor_generator.cpp | 91 + .../unsupported/test/cxx11_tensor_ifft.cpp | 154 + .../test/cxx11_tensor_image_patch.cpp | 757 + .../test/cxx11_tensor_index_list.cpp | 386 + .../test/cxx11_tensor_inflation.cpp | 81 + .../unsupported/test/cxx11_tensor_intdiv.cpp | 147 + .../unsupported/test/cxx11_tensor_io.cpp | 136 + .../test/cxx11_tensor_layout_swap.cpp | 61 + .../unsupported/test/cxx11_tensor_lvalue.cpp | 42 + .../unsupported/test/cxx11_tensor_map.cpp | 277 + .../unsupported/test/cxx11_tensor_math.cpp | 46 + .../test/cxx11_tensor_mixed_indices.cpp | 53 + .../test/cxx11_tensor_morphing.cpp | 485 + .../test/cxx11_tensor_notification.cpp | 81 + .../test/cxx11_tensor_of_complex.cpp | 103 + .../test/cxx11_tensor_of_const_values.cpp | 105 + .../test/cxx11_tensor_of_float16_cuda.cu | 494 + .../test/cxx11_tensor_of_strings.cpp | 152 + .../unsupported/test/cxx11_tensor_padding.cpp | 93 + .../unsupported/test/cxx11_tensor_patch.cpp | 172 + .../unsupported/test/cxx11_tensor_random.cpp | 78 + .../test/cxx11_tensor_random_cuda.cu | 88 + .../test/cxx11_tensor_reduction.cpp | 508 + .../test/cxx11_tensor_reduction_cuda.cu | 157 + .../test/cxx11_tensor_reduction_sycl.cpp | 138 + .../unsupported/test/cxx11_tensor_ref.cpp | 248 + .../unsupported/test/cxx11_tensor_reverse.cpp | 190 + .../test/cxx11_tensor_roundings.cpp | 62 + .../unsupported/test/cxx11_tensor_scan.cpp | 110 + .../test/cxx11_tensor_scan_cuda.cu | 79 + .../test/cxx11_tensor_shuffling.cpp | 228 + .../unsupported/test/cxx11_tensor_simple.cpp | 327 + .../test/cxx11_tensor_striding.cpp | 119 + .../unsupported/test/cxx11_tensor_sugar.cpp | 81 + .../unsupported/test/cxx11_tensor_sycl.cpp | 159 + .../test/cxx11_tensor_symmetry.cpp | 818 + .../test/cxx11_tensor_thread_pool.cpp | 373 + .../unsupported/test/cxx11_tensor_uint128.cpp | 160 + .../test/cxx11_tensor_volume_patch.cpp | 112 + .../eigen/unsupported/test/forward_adolc.cpp | 4 +- .../libs/eigen/unsupported/test/jacobisvd.cpp | 198 - .../unsupported/test/kronecker_product.cpp | 89 +- .../unsupported/test/levenberg_marquardt.cpp | 93 +- .../unsupported/test/matrix_function.cpp | 6 +- .../eigen/unsupported/test/matrix_functions.h | 42 +- .../eigen/unsupported/test/matrix_power.cpp | 171 +- .../libs/eigen/unsupported/test/minres.cpp | 19 +- .../eigen/unsupported/test/mpreal/mpreal.h | 854 +- .../eigen/unsupported/test/mpreal_support.cpp | 10 +- .../unsupported/test/polynomialsolver.cpp | 7 +- .../eigen/unsupported/test/sparse_extra.cpp | 1 - .../unsupported/test/special_functions.cpp | 345 + .../libs/eigen/unsupported/test/splines.cpp | 73 +- .../libs/eigen/unsupported/test/svd_common.h | 261 - 1101 files changed, 137563 insertions(+), 44626 deletions(-) delete mode 100644 ground/gcs/src/libs/eigen/Eigen/Array delete mode 100644 ground/gcs/src/libs/eigen/Eigen/Eigen2Support delete mode 100644 ground/gcs/src/libs/eigen/Eigen/LeastSquares delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/CMakeLists.txt delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Cholesky/CMakeLists.txt rename ground/gcs/src/libs/eigen/Eigen/src/Cholesky/{LLT_MKL.h => LLT_LAPACKE.h} (71%) delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/CholmodSupport/CMakeLists.txt create mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Core/AssignEvaluator.h delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Core/CMakeLists.txt create mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Core/ConditionEstimator.h create mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Core/CoreEvaluators.h create mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Core/CwiseTernaryOp.h delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Core/Flagged.h delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Core/Functors.h create mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Core/Inverse.h create mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Core/MathFunctionsImpl.h create mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Core/Product.h delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Core/ProductBase.h create mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Core/ProductEvaluators.h create mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Core/Solve.h create mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Core/SolverBase.h create mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Core/arch/AVX/Complex.h create mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Core/arch/AVX/MathFunctions.h create mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Core/arch/AVX/PacketMath.h create mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Core/arch/AVX/TypeCasting.h create mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Core/arch/AVX512/MathFunctions.h create mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Core/arch/AVX512/PacketMath.h delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Core/arch/AltiVec/CMakeLists.txt create mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Core/arch/AltiVec/MathFunctions.h delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Core/arch/CMakeLists.txt create mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Core/arch/CUDA/Complex.h create mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Core/arch/CUDA/Half.h create mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Core/arch/CUDA/MathFunctions.h create mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Core/arch/CUDA/PacketMath.h create mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Core/arch/CUDA/PacketMathHalf.h create mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Core/arch/CUDA/TypeCasting.h delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Core/arch/Default/CMakeLists.txt delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Core/arch/NEON/CMakeLists.txt create mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Core/arch/NEON/MathFunctions.h delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Core/arch/SSE/CMakeLists.txt create mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Core/arch/SSE/TypeCasting.h create mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Core/arch/ZVector/Complex.h create mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Core/arch/ZVector/MathFunctions.h create mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Core/arch/ZVector/PacketMath.h create mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Core/functors/AssignmentFunctors.h create mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Core/functors/BinaryFunctors.h create mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Core/functors/NullaryFunctors.h create mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Core/functors/StlFunctors.h create mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Core/functors/TernaryFunctors.h create mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Core/functors/UnaryFunctors.h delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Core/products/CMakeLists.txt delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Core/products/CoeffBasedProduct.h rename ground/gcs/src/libs/eigen/Eigen/src/Core/products/{GeneralMatrixMatrixTriangular_MKL.h => GeneralMatrixMatrixTriangular_BLAS.h} (69%) rename ground/gcs/src/libs/eigen/Eigen/src/Core/products/{GeneralMatrixMatrix_MKL.h => GeneralMatrixMatrix_BLAS.h} (76%) rename ground/gcs/src/libs/eigen/Eigen/src/Core/products/{GeneralMatrixVector_MKL.h => GeneralMatrixVector_BLAS.h} (60%) rename ground/gcs/src/libs/eigen/Eigen/src/Core/products/{SelfadjointMatrixMatrix_MKL.h => SelfadjointMatrixMatrix_BLAS.h} (68%) rename ground/gcs/src/libs/eigen/Eigen/src/Core/products/{SelfadjointMatrixVector_MKL.h => SelfadjointMatrixVector_BLAS.h} (72%) rename ground/gcs/src/libs/eigen/Eigen/src/Core/products/{TriangularMatrixMatrix_MKL.h => TriangularMatrixMatrix_BLAS.h} (76%) rename ground/gcs/src/libs/eigen/Eigen/src/Core/products/{TriangularMatrixVector_MKL.h => TriangularMatrixVector_BLAS.h} (74%) rename ground/gcs/src/libs/eigen/Eigen/src/Core/products/{TriangularSolverMatrix_MKL.h => TriangularSolverMatrix_BLAS.h} (75%) delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Core/util/CMakeLists.txt delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Eigen2Support/Block.h delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Eigen2Support/CMakeLists.txt delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Eigen2Support/Cwise.h delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Eigen2Support/CwiseOperators.h delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Eigen2Support/Geometry/AlignedBox.h delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Eigen2Support/Geometry/All.h delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Eigen2Support/Geometry/AngleAxis.h delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Eigen2Support/Geometry/CMakeLists.txt delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Eigen2Support/Geometry/Hyperplane.h delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Eigen2Support/Geometry/ParametrizedLine.h delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Eigen2Support/Geometry/Quaternion.h delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Eigen2Support/Geometry/Rotation2D.h delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Eigen2Support/Geometry/RotationBase.h delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Eigen2Support/Geometry/Scaling.h delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Eigen2Support/Geometry/Transform.h delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Eigen2Support/Geometry/Translation.h delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Eigen2Support/LU.h delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Eigen2Support/Lazy.h delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Eigen2Support/LeastSquares.h delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Eigen2Support/Macros.h delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Eigen2Support/MathFunctions.h delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Eigen2Support/Memory.h delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Eigen2Support/Meta.h delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Eigen2Support/Minor.h delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Eigen2Support/QR.h delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Eigen2Support/SVD.h delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Eigen2Support/TriangularSolver.h delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Eigen2Support/VectorBlock.h delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Eigenvalues/CMakeLists.txt rename ground/gcs/src/libs/eigen/Eigen/src/Eigenvalues/{ComplexSchur_MKL.h => ComplexSchur_LAPACKE.h} (65%) rename ground/gcs/src/libs/eigen/Eigen/src/Eigenvalues/{RealSchur_MKL.h => RealSchur_LAPACKE.h} (64%) rename ground/gcs/src/libs/eigen/Eigen/src/Eigenvalues/{SelfAdjointEigenSolver_MKL.h => SelfAdjointEigenSolver_LAPACKE.h} (62%) delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Geometry/CMakeLists.txt delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Geometry/arch/CMakeLists.txt delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Householder/CMakeLists.txt delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/IterativeLinearSolvers/CMakeLists.txt create mode 100644 ground/gcs/src/libs/eigen/Eigen/src/IterativeLinearSolvers/IncompleteCholesky.h create mode 100644 ground/gcs/src/libs/eigen/Eigen/src/IterativeLinearSolvers/LeastSquareConjugateGradient.h create mode 100644 ground/gcs/src/libs/eigen/Eigen/src/IterativeLinearSolvers/SolveWithGuess.h delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/Jacobi/CMakeLists.txt delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/LU/CMakeLists.txt rename ground/gcs/src/libs/eigen/Eigen/src/LU/{Inverse.h => InverseImpl.h} (86%) rename ground/gcs/src/libs/eigen/Eigen/src/LU/{PartialPivLU_MKL.h => PartialPivLU_LAPACKE.h} (77%) delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/LU/arch/CMakeLists.txt delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/MetisSupport/CMakeLists.txt delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/OrderingMethods/CMakeLists.txt delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/PaStiXSupport/CMakeLists.txt delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/PardisoSupport/CMakeLists.txt delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/QR/CMakeLists.txt rename ground/gcs/src/libs/eigen/Eigen/src/QR/{ColPivHouseholderQR_MKL.h => ColPivHouseholderQR_LAPACKE.h} (64%) create mode 100644 ground/gcs/src/libs/eigen/Eigen/src/QR/CompleteOrthogonalDecomposition.h rename ground/gcs/src/libs/eigen/Eigen/src/QR/{HouseholderQR_MKL.h => HouseholderQR_LAPACKE.h} (77%) delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/SPQRSupport/CMakeLists.txt create mode 100644 ground/gcs/src/libs/eigen/Eigen/src/SVD/BDCSVD.h delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/SVD/CMakeLists.txt rename ground/gcs/src/libs/eigen/Eigen/src/SVD/{JacobiSVD_MKL.h => JacobiSVD_LAPACKE.h} (62%) rename ground/gcs/src/libs/eigen/{unsupported => }/Eigen/src/SVD/SVDBase.h (52%) delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/SparseCholesky/CMakeLists.txt delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/SparseCore/CMakeLists.txt create mode 100644 ground/gcs/src/libs/eigen/Eigen/src/SparseCore/SparseAssign.h create mode 100644 ground/gcs/src/libs/eigen/Eigen/src/SparseCore/SparseCompressedBase.h create mode 100644 ground/gcs/src/libs/eigen/Eigen/src/SparseCore/SparseMap.h create mode 100644 ground/gcs/src/libs/eigen/Eigen/src/SparseCore/SparseRef.h create mode 100644 ground/gcs/src/libs/eigen/Eigen/src/SparseCore/SparseSolverBase.h delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/SparseLU/CMakeLists.txt delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/SparseQR/CMakeLists.txt delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/StlSupport/CMakeLists.txt delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/SuperLUSupport/CMakeLists.txt delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/UmfPackSupport/CMakeLists.txt delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/misc/CMakeLists.txt create mode 100644 ground/gcs/src/libs/eigen/Eigen/src/misc/RealSvd2x2.h delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/misc/Solve.h delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/misc/SparseSolve.h create mode 100644 ground/gcs/src/libs/eigen/Eigen/src/misc/lapack.h create mode 100644 ground/gcs/src/libs/eigen/Eigen/src/misc/lapacke.h create mode 100644 ground/gcs/src/libs/eigen/Eigen/src/misc/lapacke_mangling.h delete mode 100644 ground/gcs/src/libs/eigen/Eigen/src/plugins/CMakeLists.txt rename ground/gcs/src/libs/eigen/{README.OpenpilotGCS.txt => README.LibrePilot.txt} (70%) create mode 100644 ground/gcs/src/libs/eigen/README.md create mode 100644 ground/gcs/src/libs/eigen/bench/analyze-blocking-sizes.cpp create mode 100644 ground/gcs/src/libs/eigen/bench/benchmark-blocking-sizes.cpp create mode 100644 ground/gcs/src/libs/eigen/bench/btl/cmake/FindBLAZE.cmake delete mode 100644 ground/gcs/src/libs/eigen/bench/btl/cmake/FindGOTO.cmake delete mode 100644 ground/gcs/src/libs/eigen/bench/btl/cmake/FindGOTO2.cmake create mode 100644 ground/gcs/src/libs/eigen/bench/btl/cmake/FindOPENBLAS.cmake create mode 100644 ground/gcs/src/libs/eigen/bench/btl/libs/blaze/CMakeLists.txt create mode 100644 ground/gcs/src/libs/eigen/bench/btl/libs/blaze/blaze_interface.hh create mode 100644 ground/gcs/src/libs/eigen/bench/btl/libs/blaze/main.cpp create mode 100644 ground/gcs/src/libs/eigen/bench/btl/libs/tensors/CMakeLists.txt create mode 100644 ground/gcs/src/libs/eigen/bench/btl/libs/tensors/main_linear.cpp create mode 100644 ground/gcs/src/libs/eigen/bench/btl/libs/tensors/main_matmat.cpp create mode 100644 ground/gcs/src/libs/eigen/bench/btl/libs/tensors/main_vecmat.cpp create mode 100644 ground/gcs/src/libs/eigen/bench/btl/libs/tensors/tensor_interface.hh create mode 100644 ground/gcs/src/libs/eigen/bench/dense_solvers.cpp create mode 100644 ground/gcs/src/libs/eigen/bench/perf_monitoring/gemm/changesets.txt create mode 100644 ground/gcs/src/libs/eigen/bench/perf_monitoring/gemm/gemm.cpp create mode 100644 ground/gcs/src/libs/eigen/bench/perf_monitoring/gemm/gemm_settings.txt create mode 100644 ground/gcs/src/libs/eigen/bench/perf_monitoring/gemm/lazy_gemm.cpp create mode 100644 ground/gcs/src/libs/eigen/bench/perf_monitoring/gemm/lazy_gemm_settings.txt create mode 100644 ground/gcs/src/libs/eigen/bench/perf_monitoring/gemm/make_plot.sh create mode 100644 ground/gcs/src/libs/eigen/bench/perf_monitoring/gemm/run.sh create mode 100644 ground/gcs/src/libs/eigen/bench/tensors/README create mode 100644 ground/gcs/src/libs/eigen/bench/tensors/benchmark.h create mode 100644 ground/gcs/src/libs/eigen/bench/tensors/benchmark_main.cc create mode 100644 ground/gcs/src/libs/eigen/bench/tensors/contraction_benchmarks_cpu.cc create mode 100644 ground/gcs/src/libs/eigen/bench/tensors/tensor_benchmarks.h create mode 100644 ground/gcs/src/libs/eigen/bench/tensors/tensor_benchmarks_cpu.cc create mode 100644 ground/gcs/src/libs/eigen/bench/tensors/tensor_benchmarks_fp16_gpu.cu create mode 100644 ground/gcs/src/libs/eigen/bench/tensors/tensor_benchmarks_gpu.cu create mode 100644 ground/gcs/src/libs/eigen/bench/tensors/tensor_benchmarks_sycl.cc delete mode 100644 ground/gcs/src/libs/eigen/blas/chbmv.f delete mode 100644 ground/gcs/src/libs/eigen/blas/chpmv.f delete mode 100644 ground/gcs/src/libs/eigen/blas/ctbmv.f delete mode 100644 ground/gcs/src/libs/eigen/blas/drotm.f delete mode 100644 ground/gcs/src/libs/eigen/blas/drotmg.f delete mode 100644 ground/gcs/src/libs/eigen/blas/dsbmv.f delete mode 100644 ground/gcs/src/libs/eigen/blas/dspmv.f delete mode 100644 ground/gcs/src/libs/eigen/blas/dtbmv.f create mode 100644 ground/gcs/src/libs/eigen/blas/f2c/chbmv.c create mode 100644 ground/gcs/src/libs/eigen/blas/f2c/chpmv.c create mode 100644 ground/gcs/src/libs/eigen/blas/f2c/complexdots.c create mode 100644 ground/gcs/src/libs/eigen/blas/f2c/ctbmv.c create mode 100644 ground/gcs/src/libs/eigen/blas/f2c/d_cnjg.c create mode 100644 ground/gcs/src/libs/eigen/blas/f2c/datatypes.h create mode 100644 ground/gcs/src/libs/eigen/blas/f2c/drotm.c create mode 100644 ground/gcs/src/libs/eigen/blas/f2c/drotmg.c create mode 100644 ground/gcs/src/libs/eigen/blas/f2c/dsbmv.c create mode 100644 ground/gcs/src/libs/eigen/blas/f2c/dspmv.c create mode 100644 ground/gcs/src/libs/eigen/blas/f2c/dtbmv.c create mode 100644 ground/gcs/src/libs/eigen/blas/f2c/lsame.c create mode 100644 ground/gcs/src/libs/eigen/blas/f2c/r_cnjg.c create mode 100644 ground/gcs/src/libs/eigen/blas/f2c/srotm.c create mode 100644 ground/gcs/src/libs/eigen/blas/f2c/srotmg.c create mode 100644 ground/gcs/src/libs/eigen/blas/f2c/ssbmv.c create mode 100644 ground/gcs/src/libs/eigen/blas/f2c/sspmv.c create mode 100644 ground/gcs/src/libs/eigen/blas/f2c/stbmv.c create mode 100644 ground/gcs/src/libs/eigen/blas/f2c/zhbmv.c create mode 100644 ground/gcs/src/libs/eigen/blas/f2c/zhpmv.c create mode 100644 ground/gcs/src/libs/eigen/blas/f2c/ztbmv.c rename ground/gcs/src/libs/eigen/blas/{ => fortran}/complexdots.f (100%) delete mode 100644 ground/gcs/src/libs/eigen/blas/lsame.f delete mode 100644 ground/gcs/src/libs/eigen/blas/srotm.f delete mode 100644 ground/gcs/src/libs/eigen/blas/srotmg.f delete mode 100644 ground/gcs/src/libs/eigen/blas/ssbmv.f delete mode 100644 ground/gcs/src/libs/eigen/blas/sspmv.f delete mode 100644 ground/gcs/src/libs/eigen/blas/stbmv.f delete mode 100644 ground/gcs/src/libs/eigen/blas/zhbmv.f delete mode 100644 ground/gcs/src/libs/eigen/blas/zhpmv.f delete mode 100644 ground/gcs/src/libs/eigen/blas/ztbmv.f create mode 100644 ground/gcs/src/libs/eigen/cmake/Eigen3Config.cmake.in create mode 100644 ground/gcs/src/libs/eigen/cmake/Eigen3ConfigLegacy.cmake.in create mode 100644 ground/gcs/src/libs/eigen/cmake/EigenUninstall.cmake create mode 100644 ground/gcs/src/libs/eigen/cmake/FindComputeCpp.cmake create mode 100644 ground/gcs/src/libs/eigen/cmake/UseEigen3.cmake delete mode 100644 ground/gcs/src/libs/eigen/doc/A10_Eigen2SupportModes.dox create mode 100644 ground/gcs/src/libs/eigen/doc/CoeffwiseMathFunctionsTable.dox delete mode 100644 ground/gcs/src/libs/eigen/doc/CustomizingEigen.dox create mode 100644 ground/gcs/src/libs/eigen/doc/CustomizingEigen_CustomScalar.dox create mode 100644 ground/gcs/src/libs/eigen/doc/CustomizingEigen_InheritingMatrix.dox create mode 100644 ground/gcs/src/libs/eigen/doc/CustomizingEigen_NullaryExpr.dox create mode 100644 ground/gcs/src/libs/eigen/doc/CustomizingEigen_Plugins.dox create mode 100644 ground/gcs/src/libs/eigen/doc/DenseDecompositionBenchmark.dox create mode 100644 ground/gcs/src/libs/eigen/doc/InplaceDecomposition.dox create mode 100644 ground/gcs/src/libs/eigen/doc/LeastSquares.dox create mode 100644 ground/gcs/src/libs/eigen/doc/NewExpressionType.dox create mode 100644 ground/gcs/src/libs/eigen/doc/TopicCMakeGuide.dox create mode 100644 ground/gcs/src/libs/eigen/doc/TutorialReshapeSlicing.dox create mode 100644 ground/gcs/src/libs/eigen/doc/UsingBlasLapackBackends.dox create mode 100644 ground/gcs/src/libs/eigen/doc/UsingNVCC.dox create mode 100644 ground/gcs/src/libs/eigen/doc/examples/CustomizingEigen_Inheritance.cpp create mode 100644 ground/gcs/src/libs/eigen/doc/examples/Cwise_erf.cpp create mode 100644 ground/gcs/src/libs/eigen/doc/examples/Cwise_erfc.cpp create mode 100644 ground/gcs/src/libs/eigen/doc/examples/Cwise_lgamma.cpp delete mode 100644 ground/gcs/src/libs/eigen/doc/examples/MatrixBase_cwise_const.cpp create mode 100644 ground/gcs/src/libs/eigen/doc/examples/TutorialInplaceLU.cpp create mode 100644 ground/gcs/src/libs/eigen/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_reductions_operatornorm.cpp create mode 100644 ground/gcs/src/libs/eigen/doc/examples/make_circulant.cpp create mode 100644 ground/gcs/src/libs/eigen/doc/examples/make_circulant.cpp.entry create mode 100644 ground/gcs/src/libs/eigen/doc/examples/make_circulant.cpp.evaluator create mode 100644 ground/gcs/src/libs/eigen/doc/examples/make_circulant.cpp.expression create mode 100644 ground/gcs/src/libs/eigen/doc/examples/make_circulant.cpp.main create mode 100644 ground/gcs/src/libs/eigen/doc/examples/make_circulant.cpp.preamble create mode 100644 ground/gcs/src/libs/eigen/doc/examples/make_circulant.cpp.traits create mode 100644 ground/gcs/src/libs/eigen/doc/examples/make_circulant2.cpp create mode 100644 ground/gcs/src/libs/eigen/doc/examples/nullary_indexing.cpp create mode 100644 ground/gcs/src/libs/eigen/doc/ftv2node.png create mode 100644 ground/gcs/src/libs/eigen/doc/ftv2pnode.png create mode 100644 ground/gcs/src/libs/eigen/doc/snippets/BiCGSTAB_simple.cpp create mode 100644 ground/gcs/src/libs/eigen/doc/snippets/BiCGSTAB_step_by_step.cpp create mode 100644 ground/gcs/src/libs/eigen/doc/snippets/Cwise_arg.cpp create mode 100644 ground/gcs/src/libs/eigen/doc/snippets/Cwise_array_power_array.cpp create mode 100644 ground/gcs/src/libs/eigen/doc/snippets/Cwise_atan.cpp create mode 100644 ground/gcs/src/libs/eigen/doc/snippets/Cwise_boolean_not.cpp create mode 100644 ground/gcs/src/libs/eigen/doc/snippets/Cwise_boolean_xor.cpp create mode 100644 ground/gcs/src/libs/eigen/doc/snippets/Cwise_ceil.cpp create mode 100644 ground/gcs/src/libs/eigen/doc/snippets/Cwise_cosh.cpp create mode 100644 ground/gcs/src/libs/eigen/doc/snippets/Cwise_floor.cpp create mode 100644 ground/gcs/src/libs/eigen/doc/snippets/Cwise_isFinite.cpp create mode 100644 ground/gcs/src/libs/eigen/doc/snippets/Cwise_isInf.cpp create mode 100644 ground/gcs/src/libs/eigen/doc/snippets/Cwise_isNaN.cpp create mode 100644 ground/gcs/src/libs/eigen/doc/snippets/Cwise_log10.cpp create mode 100644 ground/gcs/src/libs/eigen/doc/snippets/Cwise_round.cpp create mode 100644 ground/gcs/src/libs/eigen/doc/snippets/Cwise_scalar_power_array.cpp create mode 100644 ground/gcs/src/libs/eigen/doc/snippets/Cwise_sign.cpp create mode 100644 ground/gcs/src/libs/eigen/doc/snippets/Cwise_sinh.cpp create mode 100644 ground/gcs/src/libs/eigen/doc/snippets/Cwise_tanh.cpp create mode 100644 ground/gcs/src/libs/eigen/doc/snippets/DenseBase_LinSpacedInt.cpp create mode 100644 ground/gcs/src/libs/eigen/doc/snippets/DirectionWise_hnormalized.cpp create mode 100644 ground/gcs/src/libs/eigen/doc/snippets/LeastSquaresNormalEquations.cpp create mode 100644 ground/gcs/src/libs/eigen/doc/snippets/LeastSquaresQR.cpp create mode 100644 ground/gcs/src/libs/eigen/doc/snippets/MatrixBase_cwiseSign.cpp create mode 100644 ground/gcs/src/libs/eigen/doc/snippets/MatrixBase_hnormalized.cpp create mode 100644 ground/gcs/src/libs/eigen/doc/snippets/MatrixBase_homogeneous.cpp delete mode 100644 ground/gcs/src/libs/eigen/doc/snippets/MatrixBase_marked.cpp delete mode 100644 ground/gcs/src/libs/eigen/doc/snippets/MatrixBase_part.cpp create mode 100644 ground/gcs/src/libs/eigen/doc/snippets/MatrixBase_selfadjointView.cpp rename ground/gcs/src/libs/eigen/doc/snippets/{MatrixBase_extract.cpp => MatrixBase_triangularView.cpp} (55%) create mode 100644 ground/gcs/src/libs/eigen/doc/snippets/SparseMatrix_coeffs.cpp create mode 100644 ground/gcs/src/libs/eigen/doc/snippets/TopicAliasing_mult4.cpp create mode 100644 ground/gcs/src/libs/eigen/doc/snippets/TopicAliasing_mult5.cpp create mode 100644 ground/gcs/src/libs/eigen/doc/snippets/Triangular_solve.cpp create mode 100644 ground/gcs/src/libs/eigen/doc/snippets/Tutorial_ReshapeMat2Mat.cpp create mode 100644 ground/gcs/src/libs/eigen/doc/snippets/Tutorial_ReshapeMat2Vec.cpp create mode 100644 ground/gcs/src/libs/eigen/doc/snippets/Tutorial_SlicingCol.cpp create mode 100644 ground/gcs/src/libs/eigen/doc/snippets/Tutorial_SlicingVec.cpp create mode 100644 ground/gcs/src/libs/eigen/doc/snippets/VectorwiseOp_homogeneous.cpp create mode 100644 ground/gcs/src/libs/eigen/doc/special_examples/random_cpp11.cpp create mode 100644 ground/gcs/src/libs/eigen/failtest/bdcsvd_int.cpp create mode 100644 ground/gcs/src/libs/eigen/failtest/cwiseunaryview_nonconst_ctor_on_const_xpr.cpp create mode 100644 ground/gcs/src/libs/eigen/failtest/cwiseunaryview_on_const_type_actually_const.cpp create mode 100644 ground/gcs/src/libs/eigen/failtest/selfadjointview_nonconst_ctor_on_const_xpr.cpp create mode 100644 ground/gcs/src/libs/eigen/failtest/selfadjointview_on_const_type_actually_const.cpp create mode 100644 ground/gcs/src/libs/eigen/failtest/sparse_ref_1.cpp create mode 100644 ground/gcs/src/libs/eigen/failtest/sparse_ref_2.cpp create mode 100644 ground/gcs/src/libs/eigen/failtest/sparse_ref_3.cpp create mode 100644 ground/gcs/src/libs/eigen/failtest/sparse_ref_4.cpp create mode 100644 ground/gcs/src/libs/eigen/failtest/sparse_ref_5.cpp create mode 100644 ground/gcs/src/libs/eigen/failtest/sparse_storage_mismatch.cpp create mode 100644 ground/gcs/src/libs/eigen/failtest/swap_1.cpp create mode 100644 ground/gcs/src/libs/eigen/failtest/swap_2.cpp create mode 100644 ground/gcs/src/libs/eigen/failtest/ternary_1.cpp create mode 100644 ground/gcs/src/libs/eigen/failtest/ternary_2.cpp create mode 100644 ground/gcs/src/libs/eigen/failtest/triangularview_nonconst_ctor_on_const_xpr.cpp create mode 100644 ground/gcs/src/libs/eigen/failtest/triangularview_on_const_type_actually_const.cpp create mode 100644 ground/gcs/src/libs/eigen/lapack/svd.cpp create mode 100644 ground/gcs/src/libs/eigen/test/array_of_string.cpp create mode 100644 ground/gcs/src/libs/eigen/test/bdcsvd.cpp create mode 100644 ground/gcs/src/libs/eigen/test/boostmultiprec.cpp create mode 100644 ground/gcs/src/libs/eigen/test/bug1213.cpp create mode 100644 ground/gcs/src/libs/eigen/test/bug1213.h create mode 100644 ground/gcs/src/libs/eigen/test/bug1213_main.cpp create mode 100644 ground/gcs/src/libs/eigen/test/constructor.cpp create mode 100644 ground/gcs/src/libs/eigen/test/ctorleak.cpp create mode 100644 ground/gcs/src/libs/eigen/test/cuda_basic.cu create mode 100644 ground/gcs/src/libs/eigen/test/cuda_common.h delete mode 100644 ground/gcs/src/libs/eigen/test/cwiseop.cpp create mode 100644 ground/gcs/src/libs/eigen/test/dense_storage.cpp delete mode 100644 ground/gcs/src/libs/eigen/test/eigen2/CMakeLists.txt delete mode 100644 ground/gcs/src/libs/eigen/test/eigen2/eigen2_adjoint.cpp delete mode 100644 ground/gcs/src/libs/eigen/test/eigen2/eigen2_alignedbox.cpp delete mode 100644 ground/gcs/src/libs/eigen/test/eigen2/eigen2_array.cpp delete mode 100644 ground/gcs/src/libs/eigen/test/eigen2/eigen2_basicstuff.cpp delete mode 100644 ground/gcs/src/libs/eigen/test/eigen2/eigen2_bug_132.cpp delete mode 100644 ground/gcs/src/libs/eigen/test/eigen2/eigen2_cholesky.cpp delete mode 100644 ground/gcs/src/libs/eigen/test/eigen2/eigen2_commainitializer.cpp delete mode 100644 ground/gcs/src/libs/eigen/test/eigen2/eigen2_cwiseop.cpp delete mode 100644 ground/gcs/src/libs/eigen/test/eigen2/eigen2_determinant.cpp delete mode 100644 ground/gcs/src/libs/eigen/test/eigen2/eigen2_dynalloc.cpp delete mode 100644 ground/gcs/src/libs/eigen/test/eigen2/eigen2_eigensolver.cpp delete mode 100644 ground/gcs/src/libs/eigen/test/eigen2/eigen2_first_aligned.cpp delete mode 100644 ground/gcs/src/libs/eigen/test/eigen2/eigen2_geometry.cpp delete mode 100644 ground/gcs/src/libs/eigen/test/eigen2/eigen2_geometry_with_eigen2_prefix.cpp delete mode 100644 ground/gcs/src/libs/eigen/test/eigen2/eigen2_hyperplane.cpp delete mode 100644 ground/gcs/src/libs/eigen/test/eigen2/eigen2_inverse.cpp delete mode 100644 ground/gcs/src/libs/eigen/test/eigen2/eigen2_linearstructure.cpp delete mode 100644 ground/gcs/src/libs/eigen/test/eigen2/eigen2_lu.cpp delete mode 100644 ground/gcs/src/libs/eigen/test/eigen2/eigen2_map.cpp delete mode 100644 ground/gcs/src/libs/eigen/test/eigen2/eigen2_meta.cpp delete mode 100644 ground/gcs/src/libs/eigen/test/eigen2/eigen2_miscmatrices.cpp delete mode 100644 ground/gcs/src/libs/eigen/test/eigen2/eigen2_mixingtypes.cpp delete mode 100644 ground/gcs/src/libs/eigen/test/eigen2/eigen2_newstdvector.cpp delete mode 100644 ground/gcs/src/libs/eigen/test/eigen2/eigen2_nomalloc.cpp delete mode 100644 ground/gcs/src/libs/eigen/test/eigen2/eigen2_packetmath.cpp delete mode 100644 ground/gcs/src/libs/eigen/test/eigen2/eigen2_parametrizedline.cpp delete mode 100644 ground/gcs/src/libs/eigen/test/eigen2/eigen2_prec_inverse_4x4.cpp delete mode 100644 ground/gcs/src/libs/eigen/test/eigen2/eigen2_product_large.cpp delete mode 100644 ground/gcs/src/libs/eigen/test/eigen2/eigen2_product_small.cpp delete mode 100644 ground/gcs/src/libs/eigen/test/eigen2/eigen2_qr.cpp delete mode 100644 ground/gcs/src/libs/eigen/test/eigen2/eigen2_qtvector.cpp delete mode 100644 ground/gcs/src/libs/eigen/test/eigen2/eigen2_regression.cpp delete mode 100644 ground/gcs/src/libs/eigen/test/eigen2/eigen2_sizeof.cpp delete mode 100644 ground/gcs/src/libs/eigen/test/eigen2/eigen2_smallvectors.cpp delete mode 100644 ground/gcs/src/libs/eigen/test/eigen2/eigen2_sparse_basic.cpp delete mode 100644 ground/gcs/src/libs/eigen/test/eigen2/eigen2_sparse_product.cpp delete mode 100644 ground/gcs/src/libs/eigen/test/eigen2/eigen2_sparse_solvers.cpp delete mode 100644 ground/gcs/src/libs/eigen/test/eigen2/eigen2_sparse_vector.cpp delete mode 100644 ground/gcs/src/libs/eigen/test/eigen2/eigen2_stdvector.cpp delete mode 100644 ground/gcs/src/libs/eigen/test/eigen2/eigen2_submatrices.cpp delete mode 100644 ground/gcs/src/libs/eigen/test/eigen2/eigen2_sum.cpp delete mode 100644 ground/gcs/src/libs/eigen/test/eigen2/eigen2_svd.cpp delete mode 100644 ground/gcs/src/libs/eigen/test/eigen2/eigen2_swap.cpp delete mode 100644 ground/gcs/src/libs/eigen/test/eigen2/eigen2_triangular.cpp delete mode 100644 ground/gcs/src/libs/eigen/test/eigen2/eigen2_unalignedassert.cpp delete mode 100644 ground/gcs/src/libs/eigen/test/eigen2/eigen2_visitor.cpp delete mode 100644 ground/gcs/src/libs/eigen/test/eigen2/gsl_helper.h delete mode 100644 ground/gcs/src/libs/eigen/test/eigen2/main.h delete mode 100644 ground/gcs/src/libs/eigen/test/eigen2/product.h delete mode 100755 ground/gcs/src/libs/eigen/test/eigen2/runtest.sh delete mode 100644 ground/gcs/src/libs/eigen/test/eigen2/sparse.h delete mode 100644 ground/gcs/src/libs/eigen/test/eigen2/testsuite.cmake create mode 100644 ground/gcs/src/libs/eigen/test/evaluator_common.h create mode 100644 ground/gcs/src/libs/eigen/test/evaluators.cpp create mode 100644 ground/gcs/src/libs/eigen/test/fastmath.cpp create mode 100644 ground/gcs/src/libs/eigen/test/half_float.cpp create mode 100644 ground/gcs/src/libs/eigen/test/incomplete_cholesky.cpp create mode 100644 ground/gcs/src/libs/eigen/test/inplace_decomposition.cpp create mode 100644 ground/gcs/src/libs/eigen/test/is_same_dense.cpp create mode 100644 ground/gcs/src/libs/eigen/test/lscg.cpp create mode 100644 ground/gcs/src/libs/eigen/test/rand.cpp delete mode 100755 ground/gcs/src/libs/eigen/test/runtest.sh create mode 100644 ground/gcs/src/libs/eigen/test/sparse_block.cpp create mode 100644 ground/gcs/src/libs/eigen/test/sparse_ref.cpp create mode 100644 ground/gcs/src/libs/eigen/test/svd_common.h create mode 100644 ground/gcs/src/libs/eigen/test/svd_fill.h delete mode 100644 ground/gcs/src/libs/eigen/test/testsuite.cmake create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/CMakeLists.txt create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/Tensor create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/TensorSymmetry create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/ThreadPool create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/README.md create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/Tensor.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorArgMax.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorAssign.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorBase.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorBroadcasting.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorChipping.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorConcatenation.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorContraction.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorContractionBlocking.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorContractionCuda.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorContractionMapper.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorContractionThreadPool.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorConversion.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorConvolution.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorCostModel.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorCustomOp.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorDevice.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorDeviceCuda.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorDeviceDefault.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorDeviceSycl.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorDeviceThreadPool.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorDimensionList.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorDimensions.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorEvalTo.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorEvaluator.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorExecutor.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorExpr.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorFFT.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorFixedSize.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorForcedEval.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorForwardDeclarations.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorFunctors.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorGenerator.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorGlobalFunctions.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorIO.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorImagePatch.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorIndexList.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorInflation.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorInitializer.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorIntDiv.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorLayoutSwap.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorMacros.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorMap.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorMeta.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorMorphing.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorPadding.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorPatch.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorRandom.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorReduction.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorReductionCuda.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorReductionSycl.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorRef.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorReverse.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorScan.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorShuffling.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorStorage.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorStriding.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorSycl.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorSyclConvertToDeviceExpression.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorSyclExprConstructor.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorSyclExtractAccessor.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorSyclExtractFunctors.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorSyclLeafCount.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorSyclPlaceHolderExpr.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorSyclRun.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorSyclTuple.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorTraits.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorUInt128.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorVolumePatch.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/TensorSymmetry/DynamicSymmetry.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/TensorSymmetry/StaticSymmetry.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/TensorSymmetry/Symmetry.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/TensorSymmetry/util/TemplateGroupTheory.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/ThreadPool/EventCount.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/ThreadPool/NonBlockingThreadPool.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/ThreadPool/RunQueue.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/ThreadPool/SimpleThreadPool.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/ThreadPool/ThreadEnvironment.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/ThreadPool/ThreadLocal.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/ThreadPool/ThreadPoolInterface.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/ThreadPool/ThreadYield.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/util/CXX11Meta.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/util/CXX11Workarounds.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/util/EmulateArray.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/util/EmulateCXX11Meta.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/util/MaxSizeVector.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/EulerAngles delete mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/SVD create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/SpecialFunctions delete mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/src/AutoDiff/CMakeLists.txt delete mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/src/BVH/CMakeLists.txt delete mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/src/CMakeLists.txt delete mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/src/Eigenvalues/CMakeLists.txt create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/src/EulerAngles/CMakeLists.txt create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/src/EulerAngles/EulerAngles.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/src/EulerAngles/EulerSystem.h delete mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/src/FFT/CMakeLists.txt delete mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/src/IterativeSolvers/CMakeLists.txt delete mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/src/IterativeSolvers/IncompleteCholesky.h delete mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/src/KroneckerProduct/CMakeLists.txt delete mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/src/LevenbergMarquardt/CMakeLists.txt delete mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/src/MatrixFunctions/CMakeLists.txt delete mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/src/MatrixFunctions/MatrixFunctionAtomic.h delete mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/src/MoreVectorization/CMakeLists.txt delete mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/src/NonLinearOptimization/CMakeLists.txt delete mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/src/NumericalDiff/CMakeLists.txt delete mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/src/Polynomials/CMakeLists.txt delete mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/src/SVD/BDCSVD.h delete mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/src/SVD/CMakeLists.txt delete mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/src/SVD/JacobiSVD.h delete mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/src/SVD/TODOBdcsvd.txt delete mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/src/SVD/doneInBDCSVD.txt delete mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/src/Skyline/CMakeLists.txt create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/src/SparseExtra/BlockSparseMatrix.h delete mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/src/SparseExtra/CMakeLists.txt create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/src/SpecialFunctions/SpecialFunctionsArrayAPI.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/src/SpecialFunctions/SpecialFunctionsFunctors.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/src/SpecialFunctions/SpecialFunctionsHalf.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/src/SpecialFunctions/SpecialFunctionsImpl.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/src/SpecialFunctions/SpecialFunctionsPacketMath.h create mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/src/SpecialFunctions/arch/CUDA/CudaSpecialFunctions.h delete mode 100644 ground/gcs/src/libs/eigen/unsupported/Eigen/src/Splines/CMakeLists.txt create mode 100644 ground/gcs/src/libs/eigen/unsupported/doc/examples/EulerAngles.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/EulerAngles.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/autodiff_scalar.cpp delete mode 100644 ground/gcs/src/libs/eigen/unsupported/test/bdcsvd.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_eventcount.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_meta.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_non_blocking_thread_pool.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_runqueue.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_argmax.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_argmax_cuda.cu create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_assign.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_broadcast_sycl.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_broadcasting.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_cast_float16_cuda.cu create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_casts.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_chipping.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_comparisons.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_complex_cuda.cu create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_complex_cwise_ops_cuda.cu create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_concatenation.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_const.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_contract_cuda.cu create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_contraction.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_convolution.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_cuda.cu create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_custom_index.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_custom_op.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_device.cu create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_device_sycl.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_dimension.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_empty.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_expr.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_fft.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_fixed_size.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_forced_eval.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_forced_eval_sycl.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_generator.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_ifft.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_image_patch.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_index_list.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_inflation.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_intdiv.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_io.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_layout_swap.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_lvalue.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_map.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_math.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_mixed_indices.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_morphing.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_notification.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_of_complex.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_of_const_values.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_of_float16_cuda.cu create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_of_strings.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_padding.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_patch.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_random.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_random_cuda.cu create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_reduction.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_reduction_cuda.cu create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_reduction_sycl.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_ref.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_reverse.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_roundings.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_scan.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_scan_cuda.cu create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_shuffling.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_simple.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_striding.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_sugar.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_sycl.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_symmetry.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_thread_pool.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_uint128.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/cxx11_tensor_volume_patch.cpp delete mode 100644 ground/gcs/src/libs/eigen/unsupported/test/jacobisvd.cpp create mode 100644 ground/gcs/src/libs/eigen/unsupported/test/special_functions.cpp delete mode 100644 ground/gcs/src/libs/eigen/unsupported/test/svd_common.h diff --git a/ground/gcs/src/libs/eigen/.hg_archival.txt b/ground/gcs/src/libs/eigen/.hg_archival.txt index c4115d7f6b..0e10abfa21 100644 --- a/ground/gcs/src/libs/eigen/.hg_archival.txt +++ b/ground/gcs/src/libs/eigen/.hg_archival.txt @@ -1,4 +1,4 @@ repo: 8a21fd850624c931e448cbcfb38168cb2717c790 -node: 07105f7124f9aef00a68c85e0fc606e65d3d6c15 -branch: 3.2 -tag: 3.2.8 +node: 67e894c6cd8f5f1f604b27d37ed47fdf012674ff +branch: 3.3 +tag: 3.3.3 diff --git a/ground/gcs/src/libs/eigen/.hgeol b/ground/gcs/src/libs/eigen/.hgeol index 423676d31b..5327df1615 100644 --- a/ground/gcs/src/libs/eigen/.hgeol +++ b/ground/gcs/src/libs/eigen/.hgeol @@ -1,6 +1,9 @@ [patterns] +*.sh = LF +*.MINPACK = CRLF scripts/*.in = LF debug/msvc/*.dat = CRLF +debug/msvc/*.natvis = CRLF unsupported/test/mpreal/*.* = CRLF ** = native diff --git a/ground/gcs/src/libs/eigen/.hgignore b/ground/gcs/src/libs/eigen/.hgignore index e33ba2e9dc..769a47f1f4 100644 --- a/ground/gcs/src/libs/eigen/.hgignore +++ b/ground/gcs/src/libs/eigen/.hgignore @@ -30,3 +30,5 @@ log patch a a.* +lapack/testing +lapack/reference diff --git a/ground/gcs/src/libs/eigen/.hgtags b/ground/gcs/src/libs/eigen/.hgtags index 8f0097f20f..961b719a9d 100644 --- a/ground/gcs/src/libs/eigen/.hgtags +++ b/ground/gcs/src/libs/eigen/.hgtags @@ -21,13 +21,12 @@ a810d5dbab47acfe65b3350236efdd98f67d4d8a 3.1.0-alpha1 8383e883ebcc6f14695ff0b5e20bb631abab43fb 3.1.0-rc1 bf4cb8c934fa3a79f45f1e629610f0225e93e493 3.1.0-rc2 da195914abcc1d739027cbee7c52077aab30b336 3.2-beta1 -4b687cad1d23066f66863f4f87298447298443df 3.2-rc1 -1eeda7b1258bcd306018c0738e2b6a8543661141 3.2-rc2 -ffa86ffb557094721ca71dcea6aed2651b9fd610 3.2.0 -6b38706d90a9fe182e66ab88477b3dbde34b9f66 3.2.1 -1306d75b4a21891e59ff9bd96678882cf831e39f 3.2.2 -36fd1ba04c120cfdd90f3e4cede47f43b21d19ad 3.2.3 -10219c95fe653d4962aa9db4946f6fbea96dd740 3.2.4 -bdd17ee3b1b3a166cd5ec36dcad4fc1f3faf774a 3.2.5 -c58038c56923e0fd86de3ded18e03df442e66dfb 3.2.6 -b30b87236a1b1552af32ac34075ee5696a9b5a33 3.2.7 +a8e0d153fc5e239ef8b06e3665f1f9e8cb8d49c8 before-evaluators +09a8e21866106b49c5dec1d6d543e5794e82efa0 3.3-alpha1 +ce5a455b34c0a0ac3545a1497cb4a16c38ed90e8 3.3-beta1 +69d418c0699907bcd0bf9e0b3ba0a112ed091d85 3.3-beta2 +bef509908b9da05d0d07ffc0da105e2c8c6d3996 3.3-rc1 +04ab5fa4b241754afcf631117572276444c67239 3.3-rc2 +26667be4f70baf4f0d39e96f330714c87b399090 3.3.0 +f562a193118d4f40514e2f4a0ace6e974926ef06 3.3.1 +da9b4e14c2550e0d11078a3c39e6d56eba9905df 3.3.2 diff --git a/ground/gcs/src/libs/eigen/CMakeLists.txt b/ground/gcs/src/libs/eigen/CMakeLists.txt index 77e9f2d354..f5840025b8 100644 --- a/ground/gcs/src/libs/eigen/CMakeLists.txt +++ b/ground/gcs/src/libs/eigen/CMakeLists.txt @@ -1,4 +1,5 @@ -project(Eigen) +project(Eigen3) + cmake_minimum_required(VERSION 2.8.5) # guard against in-source builds @@ -7,6 +8,11 @@ if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR}) message(FATAL_ERROR "In-source builds not allowed. Please make a new directory (called a build directory) and run CMake from there. You may need to remove CMakeCache.txt. ") endif() +# Alias Eigen_*_DIR to Eigen3_*_DIR: + +set(Eigen_SOURCE_DIR ${Eigen3_SOURCE_DIR}) +set(Eigen_BINARY_DIR ${Eigen3_BINARY_DIR}) + # guard against bad build-type strings if (NOT CMAKE_BUILD_TYPE) @@ -92,9 +98,11 @@ else() endif() option(EIGEN_BUILD_BTL "Build benchmark suite" OFF) -if(NOT WIN32) + +# Disable pkgconfig only for native Windows builds +if(NOT WIN32 OR NOT CMAKE_HOST_SYSTEM_NAME MATCHES Windows) option(EIGEN_BUILD_PKGCONFIG "Build pkg-config .pc file for Eigen" ON) -endif(NOT WIN32) +endif() set(CMAKE_INCLUDE_CURRENT_DIR ON) @@ -108,7 +116,8 @@ endif() set(EIGEN_TEST_MAX_SIZE "320" CACHE STRING "Maximal matrix/vector size, default is 320") macro(ei_add_cxx_compiler_flag FLAG) - string(REGEX REPLACE "-" "" SFLAG ${FLAG}) + string(REGEX REPLACE "-" "" SFLAG1 ${FLAG}) + string(REGEX REPLACE "\\+" "p" SFLAG ${SFLAG1}) check_cxx_compiler_flag(${FLAG} COMPILER_SUPPORT_${SFLAG}) if(COMPILER_SUPPORT_${SFLAG}) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${FLAG}") @@ -117,18 +126,13 @@ endmacro(ei_add_cxx_compiler_flag) if(NOT MSVC) # We assume that other compilers are partly compatible with GNUCC - - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexceptions") - set(CMAKE_CXX_FLAGS_DEBUG "-g3") - set(CMAKE_CXX_FLAGS_RELEASE "-g0 -O2") - - # clang outputs some warnings for unknwon flags that are not caught by check_cxx_compiler_flag + + # clang outputs some warnings for unknown flags that are not caught by check_cxx_compiler_flag # adding -Werror turns such warnings into errors check_cxx_compiler_flag("-Werror" COMPILER_SUPPORT_WERROR) if(COMPILER_SUPPORT_WERROR) set(CMAKE_REQUIRED_FLAGS "-Werror") endif() - ei_add_cxx_compiler_flag("-pedantic") ei_add_cxx_compiler_flag("-Wall") ei_add_cxx_compiler_flag("-Wextra") @@ -142,6 +146,18 @@ if(NOT MSVC) ei_add_cxx_compiler_flag("-Wpointer-arith") ei_add_cxx_compiler_flag("-Wwrite-strings") ei_add_cxx_compiler_flag("-Wformat-security") + ei_add_cxx_compiler_flag("-Wshorten-64-to-32") + ei_add_cxx_compiler_flag("-Wlogical-op") + ei_add_cxx_compiler_flag("-Wenum-conversion") + ei_add_cxx_compiler_flag("-Wc++11-extensions") + ei_add_cxx_compiler_flag("-Wdouble-promotion") +# ei_add_cxx_compiler_flag("-Wconversion") + + # -Wshadow is insanely too strict with gcc, hopefully it will become usable with gcc 6 + # if(NOT CMAKE_COMPILER_IS_GNUCXX OR (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER "5.0.0")) + if(NOT CMAKE_COMPILER_IS_GNUCXX) + ei_add_cxx_compiler_flag("-Wshadow") + endif() ei_add_cxx_compiler_flag("-Wno-psabi") ei_add_cxx_compiler_flag("-Wno-variadic-macros") @@ -151,7 +167,8 @@ if(NOT MSVC) ei_add_cxx_compiler_flag("-fno-common") ei_add_cxx_compiler_flag("-fstrict-aliasing") ei_add_cxx_compiler_flag("-wd981") # disable ICC's "operands are evaluated in unspecified order" remark - ei_add_cxx_compiler_flag("-wd2304") # disbale ICC's "warning #2304: non-explicit constructor with single argument may cause implicit type conversion" produced by -Wnon-virtual-dtor + ei_add_cxx_compiler_flag("-wd2304") # disable ICC's "warning #2304: non-explicit constructor with single argument may cause implicit type conversion" produced by -Wnon-virtual-dtor + # The -ansi flag must be added last, otherwise it is also used as a linker flag by check_cxx_compiler_flag making it fails # Moreover we should not set both -strict-ansi and -ansi @@ -163,6 +180,11 @@ if(NOT MSVC) else() ei_add_cxx_compiler_flag("-ansi") endif() + + if(ANDROID_NDK) + ei_add_cxx_compiler_flag("-pie") + ei_add_cxx_compiler_flag("-fPIE") + endif() set(CMAKE_REQUIRED_FLAGS "") @@ -196,18 +218,65 @@ if(NOT MSVC) message(STATUS "Enabling SSE4.2 in tests/examples") endif() + option(EIGEN_TEST_AVX "Enable/Disable AVX in tests/examples" OFF) + if(EIGEN_TEST_AVX) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mavx") + message(STATUS "Enabling AVX in tests/examples") + endif() + + option(EIGEN_TEST_FMA "Enable/Disable FMA in tests/examples" OFF) + if(EIGEN_TEST_FMA AND NOT EIGEN_TEST_NEON) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfma") + message(STATUS "Enabling FMA in tests/examples") + endif() + + option(EIGEN_TEST_AVX512 "Enable/Disable AVX512 in tests/examples" OFF) + if(EIGEN_TEST_AVX512) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mavx512f -fabi-version=6 -DEIGEN_ENABLE_AVX512") + message(STATUS "Enabling AVX512 in tests/examples") + endif() + + option(EIGEN_TEST_F16C "Enable/Disable F16C in tests/examples" OFF) + if(EIGEN_TEST_F16C) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mf16c") + message(STATUS "Enabling F16C in tests/examples") + endif() + option(EIGEN_TEST_ALTIVEC "Enable/Disable AltiVec in tests/examples" OFF) if(EIGEN_TEST_ALTIVEC) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -maltivec -mabi=altivec") message(STATUS "Enabling AltiVec in tests/examples") endif() + option(EIGEN_TEST_VSX "Enable/Disable VSX in tests/examples" OFF) + if(EIGEN_TEST_VSX) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m64 -mvsx") + message(STATUS "Enabling VSX in tests/examples") + endif() + option(EIGEN_TEST_NEON "Enable/Disable Neon in tests/examples" OFF) if(EIGEN_TEST_NEON) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfpu=neon -mcpu=cortex-a8") + if(EIGEN_TEST_FMA) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfpu=neon-vfpv4") + else() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfpu=neon") + endif() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfloat-abi=hard") + message(STATUS "Enabling NEON in tests/examples") + endif() + + option(EIGEN_TEST_NEON64 "Enable/Disable Neon in tests/examples" OFF) + if(EIGEN_TEST_NEON64) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") message(STATUS "Enabling NEON in tests/examples") endif() + option(EIGEN_TEST_ZVECTOR "Enable/Disable S390X(zEC13) ZVECTOR in tests/examples" OFF) + if(EIGEN_TEST_ZVECTOR) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=z13 -mzvector") + message(STATUS "Enabling S390X(zEC13) ZVECTOR in tests/examples") + endif() + check_cxx_compiler_flag("-fopenmp" COMPILER_SUPPORT_OPENMP) if(COMPILER_SUPPORT_OPENMP) option(EIGEN_TEST_OPENMP "Enable/Disable OpenMP in tests/examples" OFF) @@ -284,11 +353,23 @@ if(EIGEN_TEST_NO_EXPLICIT_ALIGNMENT) message(STATUS "Disabling alignment in tests/examples") endif() -option(EIGEN_TEST_C++0x "Enables all C++0x features." OFF) +option(EIGEN_TEST_NO_EXCEPTIONS "Disables C++ exceptions" OFF) +if(EIGEN_TEST_NO_EXCEPTIONS) + ei_add_cxx_compiler_flag("-fno-exceptions") + message(STATUS "Disabling exceptions in tests/examples") +endif() + +option(EIGEN_TEST_CXX11 "Enable testing with C++11 and C++11 features (e.g. Tensor module)." OFF) + +set(EIGEN_CUDA_COMPUTE_ARCH 30 CACHE STRING "The CUDA compute architecture level to target when compiling CUDA code") include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) # Backward compatibility support for EIGEN_INCLUDE_INSTALL_DIR +if(EIGEN_INCLUDE_INSTALL_DIR) + message(WARNING "EIGEN_INCLUDE_INSTALL_DIR is deprecated. Use INCLUDE_INSTALL_DIR instead.") +endif() + if(EIGEN_INCLUDE_INSTALL_DIR AND NOT INCLUDE_INSTALL_DIR) set(INCLUDE_INSTALL_DIR ${EIGEN_INCLUDE_INSTALL_DIR} CACHE PATH "The directory relative to CMAKE_PREFIX_PATH where Eigen header files are installed") @@ -298,9 +379,8 @@ else() CACHE PATH "The directory relative to CMAKE_PREFIX_PATH where Eigen header files are installed" ) endif() - set(CMAKEPACKAGE_INSTALL_DIR - "${CMAKE_INSTALL_LIBDIR}/cmake/eigen3" + "${CMAKE_INSTALL_DATADIR}/eigen3/cmake" CACHE PATH "The directory relative to CMAKE_PREFIX_PATH where Eigen3Config.cmake is installed" ) set(PKGCONFIG_INSTALL_DIR @@ -308,6 +388,7 @@ set(PKGCONFIG_INSTALL_DIR CACHE PATH "The directory relative to CMAKE_PREFIX_PATH where eigen3.pc is installed" ) + # similar to set_target_properties but append the property instead of overwriting it macro(ei_add_target_property target prop value) @@ -329,7 +410,7 @@ if(EIGEN_BUILD_PKGCONFIG) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/eigen3.pc DESTINATION ${PKGCONFIG_INSTALL_DIR} ) -endif(EIGEN_BUILD_PKGCONFIG) +endif() add_subdirectory(Eigen) @@ -355,6 +436,13 @@ else() add_subdirectory(lapack EXCLUDE_FROM_ALL) endif() +# add SYCL +option(EIGEN_TEST_SYCL "Add Sycl support." OFF) +if(EIGEN_TEST_SYCL) + set (CMAKE_MODULE_PATH "${CMAKE_ROOT}/Modules" "cmake/Modules/" "${CMAKE_MODULE_PATH}") + include(FindComputeCpp) +endif() + add_subdirectory(unsupported) add_subdirectory(demos EXCLUDE_FROM_ALL) @@ -403,6 +491,7 @@ if(cmake_generator_tolower MATCHES "makefile") message(STATUS "make check | Build and run the unit-tests. Read this page:") message(STATUS " | http://eigen.tuxfamily.org/index.php?title=Tests") message(STATUS "make blas | Build BLAS library (not the same thing as Eigen)") + message(STATUS "make uninstall| Removes files installed by make install") message(STATUS "--------------+--------------------------------------------------------------") else() message(STATUS "To build/run the unit tests, read this page:") @@ -410,3 +499,98 @@ else() endif() message(STATUS "") + + +set ( EIGEN_VERSION_STRING ${EIGEN_VERSION_NUMBER} ) +set ( EIGEN_VERSION_MAJOR ${EIGEN_WORLD_VERSION} ) +set ( EIGEN_VERSION_MINOR ${EIGEN_MAJOR_VERSION} ) +set ( EIGEN_VERSION_PATCH ${EIGEN_MINOR_VERSION} ) +set ( EIGEN_DEFINITIONS "") +set ( EIGEN_INCLUDE_DIR "${CMAKE_INSTALL_PREFIX}/${INCLUDE_INSTALL_DIR}" ) +set ( EIGEN_ROOT_DIR ${CMAKE_INSTALL_PREFIX} ) + +# Interface libraries require at least CMake 3.0 +if (NOT CMAKE_VERSION VERSION_LESS 3.0) + include (CMakePackageConfigHelpers) + + # Imported target support + add_library (eigen INTERFACE) + + target_compile_definitions (eigen INTERFACE ${EIGEN_DEFINITIONS}) + target_include_directories (eigen INTERFACE + $ + $ + ) + + # Export as title case Eigen + set_target_properties (eigen PROPERTIES EXPORT_NAME Eigen) + + install (TARGETS eigen EXPORT Eigen3Targets) + + configure_package_config_file ( + ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Eigen3Config.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/Eigen3Config.cmake + PATH_VARS EIGEN_INCLUDE_DIR EIGEN_ROOT_DIR + INSTALL_DESTINATION ${CMAKEPACKAGE_INSTALL_DIR} + NO_CHECK_REQUIRED_COMPONENTS_MACRO # Eigen does not provide components + ) + # Remove CMAKE_SIZEOF_VOID_P from Eigen3ConfigVersion.cmake since Eigen does + # not depend on architecture specific settings or libraries. More + # specifically, an Eigen3Config.cmake generated from a 64 bit target can be + # used for 32 bit targets as well (and vice versa). + set (_Eigen3_CMAKE_SIZEOF_VOID_P ${CMAKE_SIZEOF_VOID_P}) + unset (CMAKE_SIZEOF_VOID_P) + write_basic_package_version_file (Eigen3ConfigVersion.cmake + VERSION ${EIGEN_VERSION_NUMBER} + COMPATIBILITY SameMajorVersion) + set (CMAKE_SIZEOF_VOID_P ${_Eigen3_CMAKE_SIZEOF_VOID_P}) + + # The Eigen target will be located in the Eigen3 namespace. Other CMake + # targets can refer to it using Eigen3::Eigen. + export (TARGETS eigen NAMESPACE Eigen3:: FILE Eigen3Targets.cmake) + # Export Eigen3 package to CMake registry such that it can be easily found by + # CMake even if it has not been installed to a standard directory. + export (PACKAGE Eigen3) + + install (EXPORT Eigen3Targets NAMESPACE Eigen3:: DESTINATION ${CMAKEPACKAGE_INSTALL_DIR}) + +else (NOT CMAKE_VERSION VERSION_LESS 3.0) + # Fallback to legacy Eigen3Config.cmake without the imported target + + # If CMakePackageConfigHelpers module is available (CMake >= 2.8.8) + # create a relocatable Config file, otherwise leave the hardcoded paths + include(CMakePackageConfigHelpers OPTIONAL RESULT_VARIABLE CPCH_PATH) + + if(CPCH_PATH) + configure_package_config_file ( + ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Eigen3ConfigLegacy.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/Eigen3Config.cmake + PATH_VARS EIGEN_INCLUDE_DIR EIGEN_ROOT_DIR + INSTALL_DESTINATION ${CMAKEPACKAGE_INSTALL_DIR} + NO_CHECK_REQUIRED_COMPONENTS_MACRO # Eigen does not provide components + ) + else() + # The PACKAGE_* variables are defined by the configure_package_config_file + # but without it we define them manually to the hardcoded paths + set(PACKAGE_INIT "") + set(PACKAGE_EIGEN_INCLUDE_DIR ${EIGEN_INCLUDE_DIR}) + set(PACKAGE_EIGEN_ROOT_DIR ${EIGEN_ROOT_DIR}) + configure_file ( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Eigen3ConfigLegacy.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/Eigen3Config.cmake + @ONLY ESCAPE_QUOTES ) + endif() + + write_basic_package_version_file( Eigen3ConfigVersion.cmake + VERSION ${EIGEN_VERSION_NUMBER} + COMPATIBILITY SameMajorVersion ) + +endif (NOT CMAKE_VERSION VERSION_LESS 3.0) + +install ( FILES ${CMAKE_CURRENT_SOURCE_DIR}/cmake/UseEigen3.cmake + ${CMAKE_CURRENT_BINARY_DIR}/Eigen3Config.cmake + ${CMAKE_CURRENT_BINARY_DIR}/Eigen3ConfigVersion.cmake + DESTINATION ${CMAKEPACKAGE_INSTALL_DIR} ) + +# Add uninstall target +add_custom_target ( uninstall + COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/EigenUninstall.cmake) diff --git a/ground/gcs/src/libs/eigen/CTestConfig.cmake b/ground/gcs/src/libs/eigen/CTestConfig.cmake index 0557c491a3..755b473237 100644 --- a/ground/gcs/src/libs/eigen/CTestConfig.cmake +++ b/ground/gcs/src/libs/eigen/CTestConfig.cmake @@ -4,10 +4,10 @@ ## # The following are required to uses Dart and the Cdash dashboard ## ENABLE_TESTING() ## INCLUDE(CTest) -set(CTEST_PROJECT_NAME "Eigen3.2") +set(CTEST_PROJECT_NAME "Eigen3.3") set(CTEST_NIGHTLY_START_TIME "00:00:00 UTC") set(CTEST_DROP_METHOD "http") set(CTEST_DROP_SITE "manao.inria.fr") -set(CTEST_DROP_LOCATION "/CDash/submit.php?project=Eigen3.2") +set(CTEST_DROP_LOCATION "/CDash/submit.php?project=Eigen3.3") set(CTEST_DROP_SITE_CDASH TRUE) diff --git a/ground/gcs/src/libs/eigen/Eigen/Array b/ground/gcs/src/libs/eigen/Eigen/Array deleted file mode 100644 index 3d004fb69e..0000000000 --- a/ground/gcs/src/libs/eigen/Eigen/Array +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef EIGEN_ARRAY_MODULE_H -#define EIGEN_ARRAY_MODULE_H - -// include Core first to handle Eigen2 support macros -#include "Core" - -#ifndef EIGEN2_SUPPORT - #error The Eigen/Array header does no longer exist in Eigen3. All that functionality has moved to Eigen/Core. -#endif - -#endif // EIGEN_ARRAY_MODULE_H diff --git a/ground/gcs/src/libs/eigen/Eigen/CMakeLists.txt b/ground/gcs/src/libs/eigen/Eigen/CMakeLists.txt index a92dd6f6ca..9eb502b792 100644 --- a/ground/gcs/src/libs/eigen/Eigen/CMakeLists.txt +++ b/ground/gcs/src/libs/eigen/Eigen/CMakeLists.txt @@ -16,4 +16,4 @@ install(FILES DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen COMPONENT Devel ) -add_subdirectory(src) +install(DIRECTORY src DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen COMPONENT Devel FILES_MATCHING PATTERN "*.h") diff --git a/ground/gcs/src/libs/eigen/Eigen/Cholesky b/ground/gcs/src/libs/eigen/Eigen/Cholesky index f727f5d89c..369d1f5ec9 100644 --- a/ground/gcs/src/libs/eigen/Eigen/Cholesky +++ b/ground/gcs/src/libs/eigen/Eigen/Cholesky @@ -1,3 +1,10 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + #ifndef EIGEN_CHOLESKY_MODULE_H #define EIGEN_CHOLESKY_MODULE_H @@ -10,20 +17,22 @@ * * * This module provides two variants of the Cholesky decomposition for selfadjoint (hermitian) matrices. - * Those decompositions are accessible via the following MatrixBase methods: - * - MatrixBase::llt(), + * Those decompositions are also accessible via the following methods: + * - MatrixBase::llt() * - MatrixBase::ldlt() + * - SelfAdjointView::llt() + * - SelfAdjointView::ldlt() * * \code * #include * \endcode */ -#include "src/misc/Solve.h" #include "src/Cholesky/LLT.h" #include "src/Cholesky/LDLT.h" #ifdef EIGEN_USE_LAPACKE -#include "src/Cholesky/LLT_MKL.h" +#include "src/misc/lapacke.h" +#include "src/Cholesky/LLT_LAPACKE.h" #endif #include "src/Core/util/ReenableStupidWarnings.h" diff --git a/ground/gcs/src/libs/eigen/Eigen/CholmodSupport b/ground/gcs/src/libs/eigen/Eigen/CholmodSupport index 88c29a6462..bed8924d31 100644 --- a/ground/gcs/src/libs/eigen/Eigen/CholmodSupport +++ b/ground/gcs/src/libs/eigen/Eigen/CholmodSupport @@ -1,3 +1,10 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + #ifndef EIGEN_CHOLMODSUPPORT_MODULE_H #define EIGEN_CHOLMODSUPPORT_MODULE_H @@ -33,12 +40,8 @@ extern "C" { * */ -#include "src/misc/Solve.h" -#include "src/misc/SparseSolve.h" - #include "src/CholmodSupport/CholmodSupport.h" - #include "src/Core/util/ReenableStupidWarnings.h" #endif // EIGEN_CHOLMODSUPPORT_MODULE_H diff --git a/ground/gcs/src/libs/eigen/Eigen/Core b/ground/gcs/src/libs/eigen/Eigen/Core index 509c529e13..0f7fa630dd 100644 --- a/ground/gcs/src/libs/eigen/Eigen/Core +++ b/ground/gcs/src/libs/eigen/Eigen/Core @@ -14,6 +14,58 @@ // first thing Eigen does: stop the compiler from committing suicide #include "src/Core/util/DisableStupidWarnings.h" +// Handle NVCC/CUDA/SYCL +#if defined(__CUDACC__) || defined(__SYCL_DEVICE_ONLY__) + // Do not try asserts on CUDA and SYCL! + #ifndef EIGEN_NO_DEBUG + #define EIGEN_NO_DEBUG + #endif + + #ifdef EIGEN_INTERNAL_DEBUGGING + #undef EIGEN_INTERNAL_DEBUGGING + #endif + + #ifdef EIGEN_EXCEPTIONS + #undef EIGEN_EXCEPTIONS + #endif + + // All functions callable from CUDA code must be qualified with __device__ + #ifdef __CUDACC__ + // Do not try to vectorize on CUDA and SYCL! + #ifndef EIGEN_DONT_VECTORIZE + #define EIGEN_DONT_VECTORIZE + #endif + + #define EIGEN_DEVICE_FUNC __host__ __device__ + // We need math_functions.hpp to ensure that that EIGEN_USING_STD_MATH macro + // works properly on the device side + #include + #else + #define EIGEN_DEVICE_FUNC + #endif + +#else + #define EIGEN_DEVICE_FUNC + +#endif + +// When compiling CUDA device code with NVCC, pull in math functions from the +// global namespace. In host mode, and when device doee with clang, use the +// std versions. +#if defined(__CUDA_ARCH__) && defined(__NVCC__) + #define EIGEN_USING_STD_MATH(FUNC) using ::FUNC; +#else + #define EIGEN_USING_STD_MATH(FUNC) using std::FUNC; +#endif + +#if (defined(_CPPUNWIND) || defined(__EXCEPTIONS)) && !defined(__CUDA_ARCH__) && !defined(EIGEN_EXCEPTIONS) && !defined(EIGEN_USE_SYCL) + #define EIGEN_EXCEPTIONS +#endif + +#ifdef EIGEN_EXCEPTIONS + #include +#endif + // then include this file where all our macros are defined. It's really important to do it first because // it's where we do all the alignment settings (platform detection and honoring the user's will if he // defined e.g. EIGEN_DONT_ALIGN) so it needs to be done before we do anything with vectorization. @@ -21,7 +73,7 @@ // Disable the ipa-cp-clone optimization flag with MinGW 6.x or newer (enabled by default with -O3) // See http://eigen.tuxfamily.org/bz/show_bug.cgi?id=556 for details. -#if defined(__MINGW32__) && EIGEN_GNUC_AT_LEAST(4,6) +#if EIGEN_COMP_MINGW && EIGEN_GNUC_AT_LEAST(4,6) #pragma GCC optimize ("-fno-ipa-cp-clone") #endif @@ -31,26 +83,26 @@ // and inclusion of their respective header files #include "src/Core/util/MKL_support.h" -// if alignment is disabled, then disable vectorization. Note: EIGEN_ALIGN is the proper check, it takes into -// account both the user's will (EIGEN_DONT_ALIGN) and our own platform checks -#if !EIGEN_ALIGN +// if alignment is disabled, then disable vectorization. Note: EIGEN_MAX_ALIGN_BYTES is the proper check, it takes into +// account both the user's will (EIGEN_MAX_ALIGN_BYTES,EIGEN_DONT_ALIGN) and our own platform checks +#if EIGEN_MAX_ALIGN_BYTES==0 #ifndef EIGEN_DONT_VECTORIZE #define EIGEN_DONT_VECTORIZE #endif #endif -#ifdef _MSC_VER +#if EIGEN_COMP_MSVC #include // for _aligned_malloc -- need it regardless of whether vectorization is enabled - #if (_MSC_VER >= 1500) // 2008 or later + #if (EIGEN_COMP_MSVC >= 1500) // 2008 or later // Remember that usage of defined() in a #define is undefined by the standard. // a user reported that in 64-bit mode, MSVC doesn't care to define _M_IX86_FP. - #if (defined(_M_IX86_FP) && (_M_IX86_FP >= 2)) || defined(_M_X64) + #if (defined(_M_IX86_FP) && (_M_IX86_FP >= 2)) || EIGEN_ARCH_x86_64 #define EIGEN_SSE2_ON_MSVC_2008_OR_LATER #endif #endif #else // Remember that usage of defined() in a #define is undefined by the standard - #if (defined __SSE2__) && ( (!defined __GNUC__) || (defined __INTEL_COMPILER) || EIGEN_GNUC_AT_LEAST(4,2) ) + #if (defined __SSE2__) && ( (!EIGEN_COMP_GNUC) || EIGEN_COMP_ICC || EIGEN_GNUC_AT_LEAST(4,2) ) #define EIGEN_SSE2_ON_NON_MSVC_BUT_NOT_OLD_GCC #endif #endif @@ -82,6 +134,28 @@ #ifdef __SSE4_2__ #define EIGEN_VECTORIZE_SSE4_2 #endif + #ifdef __AVX__ + #define EIGEN_VECTORIZE_AVX + #define EIGEN_VECTORIZE_SSE3 + #define EIGEN_VECTORIZE_SSSE3 + #define EIGEN_VECTORIZE_SSE4_1 + #define EIGEN_VECTORIZE_SSE4_2 + #endif + #ifdef __AVX2__ + #define EIGEN_VECTORIZE_AVX2 + #endif + #ifdef __FMA__ + #define EIGEN_VECTORIZE_FMA + #endif + #if defined(__AVX512F__) && defined(EIGEN_ENABLE_AVX512) + #define EIGEN_VECTORIZE_AVX512 + #define EIGEN_VECTORIZE_AVX2 + #define EIGEN_VECTORIZE_AVX + #define EIGEN_VECTORIZE_FMA + #ifdef __AVX512DQ__ + #define EIGEN_VECTORIZE_AVX512DQ + #endif + #endif // include files @@ -95,9 +169,10 @@ extern "C" { // In theory we should only include immintrin.h and not the other *mmintrin.h header files directly. // Doing so triggers some issues with ICC. However old gcc versions seems to not have this file, thus: - #if defined(__INTEL_COMPILER) && __INTEL_COMPILER >= 1110 + #if EIGEN_COMP_ICC >= 1110 #include #else + #include #include #include #ifdef EIGEN_VECTORIZE_SSE3 @@ -112,8 +187,20 @@ #ifdef EIGEN_VECTORIZE_SSE4_2 #include #endif + #if defined(EIGEN_VECTORIZE_AVX) || defined(EIGEN_VECTORIZE_AVX512) + #include + #endif #endif } // end extern "C" + #elif defined __VSX__ + #define EIGEN_VECTORIZE + #define EIGEN_VECTORIZE_VSX + #include + // We need to #undef all these ugly tokens defined in + // => use __vector instead of vector + #undef bool + #undef vector + #undef pixel #elif defined __ALTIVEC__ #define EIGEN_VECTORIZE #define EIGEN_VECTORIZE_ALTIVEC @@ -123,13 +210,35 @@ #undef bool #undef vector #undef pixel - #elif defined __ARM_NEON + #elif (defined __ARM_NEON) || (defined __ARM_NEON__) #define EIGEN_VECTORIZE #define EIGEN_VECTORIZE_NEON #include + #elif (defined __s390x__ && defined __VEC__) + #define EIGEN_VECTORIZE + #define EIGEN_VECTORIZE_ZVECTOR + #include #endif #endif +#if defined(__F16C__) && !defined(EIGEN_COMP_CLANG) + // We can use the optimized fp16 to float and float to fp16 conversion routines + #define EIGEN_HAS_FP16_C +#endif + +#if defined __CUDACC__ + #define EIGEN_VECTORIZE_CUDA + #include + #if defined __CUDACC_VER__ && __CUDACC_VER__ >= 70500 + #define EIGEN_HAS_CUDA_FP16 + #endif +#endif + +#if defined EIGEN_HAS_CUDA_FP16 + #include + #include +#endif + #if (defined _OPENMP) && (!defined EIGEN_DONT_PARALLELIZE) #define EIGEN_HAS_OPENMP #endif @@ -139,7 +248,7 @@ #endif // MSVC for windows mobile does not have the errno.h file -#if !(defined(_MSC_VER) && defined(_WIN32_WCE)) && !defined(__ARMCC_VERSION) +#if !(EIGEN_COMP_MSVC && EIGEN_OS_WINCE) && !EIGEN_COMP_ARM #define EIGEN_HAS_ERRNO #endif @@ -159,29 +268,30 @@ // for min/max: #include +// for std::is_nothrow_move_assignable +#ifdef EIGEN_INCLUDE_TYPE_TRAITS +#include +#endif + // for outputting debug info #ifdef EIGEN_DEBUG_ASSIGN #include #endif // required for __cpuid, needs to be included after cmath -#if defined(_MSC_VER) && (defined(_M_IX86)||defined(_M_X64)) && (!defined(_WIN32_WCE)) +#if EIGEN_COMP_MSVC && EIGEN_ARCH_i386_OR_x86_64 && !EIGEN_OS_WINCE #include #endif -#if defined(_CPPUNWIND) || defined(__EXCEPTIONS) - #define EIGEN_EXCEPTIONS -#endif - -#ifdef EIGEN_EXCEPTIONS - #include -#endif - /** \brief Namespace containing all symbols from the %Eigen library. */ namespace Eigen { inline static const char *SimdInstructionSetsInUse(void) { -#if defined(EIGEN_VECTORIZE_SSE4_2) +#if defined(EIGEN_VECTORIZE_AVX512) + return "AVX512, FMA, AVX2, AVX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2"; +#elif defined(EIGEN_VECTORIZE_AVX) + return "AVX SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2"; +#elif defined(EIGEN_VECTORIZE_SSE4_2) return "SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2"; #elif defined(EIGEN_VECTORIZE_SSE4_1) return "SSE, SSE2, SSE3, SSSE3, SSE4.1"; @@ -193,8 +303,12 @@ inline static const char *SimdInstructionSetsInUse(void) { return "SSE, SSE2"; #elif defined(EIGEN_VECTORIZE_ALTIVEC) return "AltiVec"; +#elif defined(EIGEN_VECTORIZE_VSX) + return "VSX"; #elif defined(EIGEN_VECTORIZE_NEON) return "ARM NEON"; +#elif defined(EIGEN_VECTORIZE_ZVECTOR) + return "S390X ZVECTOR"; #else return "None"; #endif @@ -202,42 +316,21 @@ inline static const char *SimdInstructionSetsInUse(void) { } // end namespace Eigen -#define STAGE10_FULL_EIGEN2_API 10 -#define STAGE20_RESOLVE_API_CONFLICTS 20 -#define STAGE30_FULL_EIGEN3_API 30 -#define STAGE40_FULL_EIGEN3_STRICTNESS 40 -#define STAGE99_NO_EIGEN2_SUPPORT 99 - -#if defined EIGEN2_SUPPORT_STAGE40_FULL_EIGEN3_STRICTNESS - #define EIGEN2_SUPPORT - #define EIGEN2_SUPPORT_STAGE STAGE40_FULL_EIGEN3_STRICTNESS -#elif defined EIGEN2_SUPPORT_STAGE30_FULL_EIGEN3_API - #define EIGEN2_SUPPORT - #define EIGEN2_SUPPORT_STAGE STAGE30_FULL_EIGEN3_API -#elif defined EIGEN2_SUPPORT_STAGE20_RESOLVE_API_CONFLICTS - #define EIGEN2_SUPPORT - #define EIGEN2_SUPPORT_STAGE STAGE20_RESOLVE_API_CONFLICTS -#elif defined EIGEN2_SUPPORT_STAGE10_FULL_EIGEN2_API - #define EIGEN2_SUPPORT - #define EIGEN2_SUPPORT_STAGE STAGE10_FULL_EIGEN2_API -#elif defined EIGEN2_SUPPORT - // default to stage 3, that's what it's always meant - #define EIGEN2_SUPPORT_STAGE30_FULL_EIGEN3_API - #define EIGEN2_SUPPORT_STAGE STAGE30_FULL_EIGEN3_API -#else - #define EIGEN2_SUPPORT_STAGE STAGE99_NO_EIGEN2_SUPPORT +#if defined EIGEN2_SUPPORT_STAGE40_FULL_EIGEN3_STRICTNESS || defined EIGEN2_SUPPORT_STAGE30_FULL_EIGEN3_API || defined EIGEN2_SUPPORT_STAGE20_RESOLVE_API_CONFLICTS || defined EIGEN2_SUPPORT_STAGE10_FULL_EIGEN2_API || defined EIGEN2_SUPPORT +// This will generate an error message: +#error Eigen2-support is only available up to version 3.2. Please go to "http://eigen.tuxfamily.org/index.php?title=Eigen2" for further information #endif -#ifdef EIGEN2_SUPPORT -#undef minor -#endif +namespace Eigen { // we use size_t frequently and we'll never remember to prepend it with std:: everytime just to // ensure QNX/QCC support using std::size_t; -// gcc 4.6.0 wants std:: for ptrdiff_t +// gcc 4.6.0 wants std:: for ptrdiff_t using std::ptrdiff_t; +} + /** \defgroup Core_Module Core module * This is the main module of Eigen providing dense matrix and vector support * (both fixed and dynamic size) with all the features corresponding to a BLAS library @@ -249,8 +342,8 @@ using std::ptrdiff_t; */ #include "src/Core/util/Constants.h" -#include "src/Core/util/ForwardDeclarations.h" #include "src/Core/util/Meta.h" +#include "src/Core/util/ForwardDeclarations.h" #include "src/Core/util/StaticAssert.h" #include "src/Core/util/XprHelper.h" #include "src/Core/util/Memory.h" @@ -258,41 +351,92 @@ using std::ptrdiff_t; #include "src/Core/NumTraits.h" #include "src/Core/MathFunctions.h" #include "src/Core/GenericPacketMath.h" +#include "src/Core/MathFunctionsImpl.h" -#if defined EIGEN_VECTORIZE_SSE +#if defined EIGEN_VECTORIZE_AVX512 + #include "src/Core/arch/SSE/PacketMath.h" + #include "src/Core/arch/AVX/PacketMath.h" + #include "src/Core/arch/AVX512/PacketMath.h" + #include "src/Core/arch/AVX512/MathFunctions.h" +#elif defined EIGEN_VECTORIZE_AVX + // Use AVX for floats and doubles, SSE for integers + #include "src/Core/arch/SSE/PacketMath.h" + #include "src/Core/arch/SSE/Complex.h" + #include "src/Core/arch/SSE/MathFunctions.h" + #include "src/Core/arch/AVX/PacketMath.h" + #include "src/Core/arch/AVX/MathFunctions.h" + #include "src/Core/arch/AVX/Complex.h" + #include "src/Core/arch/AVX/TypeCasting.h" +#elif defined EIGEN_VECTORIZE_SSE #include "src/Core/arch/SSE/PacketMath.h" #include "src/Core/arch/SSE/MathFunctions.h" #include "src/Core/arch/SSE/Complex.h" -#elif defined EIGEN_VECTORIZE_ALTIVEC + #include "src/Core/arch/SSE/TypeCasting.h" +#elif defined(EIGEN_VECTORIZE_ALTIVEC) || defined(EIGEN_VECTORIZE_VSX) #include "src/Core/arch/AltiVec/PacketMath.h" + #include "src/Core/arch/AltiVec/MathFunctions.h" #include "src/Core/arch/AltiVec/Complex.h" #elif defined EIGEN_VECTORIZE_NEON #include "src/Core/arch/NEON/PacketMath.h" + #include "src/Core/arch/NEON/MathFunctions.h" #include "src/Core/arch/NEON/Complex.h" +#elif defined EIGEN_VECTORIZE_ZVECTOR + #include "src/Core/arch/ZVector/PacketMath.h" + #include "src/Core/arch/ZVector/MathFunctions.h" + #include "src/Core/arch/ZVector/Complex.h" +#endif + +// Half float support +#include "src/Core/arch/CUDA/Half.h" +#include "src/Core/arch/CUDA/PacketMathHalf.h" +#include "src/Core/arch/CUDA/TypeCasting.h" + +#if defined EIGEN_VECTORIZE_CUDA + #include "src/Core/arch/CUDA/PacketMath.h" + #include "src/Core/arch/CUDA/MathFunctions.h" #endif #include "src/Core/arch/Default/Settings.h" -#include "src/Core/Functors.h" +#include "src/Core/functors/TernaryFunctors.h" +#include "src/Core/functors/BinaryFunctors.h" +#include "src/Core/functors/UnaryFunctors.h" +#include "src/Core/functors/NullaryFunctors.h" +#include "src/Core/functors/StlFunctors.h" +#include "src/Core/functors/AssignmentFunctors.h" + +// Specialized functors to enable the processing of complex numbers +// on CUDA devices +#include "src/Core/arch/CUDA/Complex.h" + +#include "src/Core/IO.h" #include "src/Core/DenseCoeffsBase.h" #include "src/Core/DenseBase.h" #include "src/Core/MatrixBase.h" #include "src/Core/EigenBase.h" +#include "src/Core/Product.h" +#include "src/Core/CoreEvaluators.h" +#include "src/Core/AssignEvaluator.h" + #ifndef EIGEN_PARSED_BY_DOXYGEN // work around Doxygen bug triggered by Assign.h r814874 // at least confirmed with Doxygen 1.5.5 and 1.5.6 #include "src/Core/Assign.h" #endif +#include "src/Core/ArrayBase.h" #include "src/Core/util/BlasUtil.h" #include "src/Core/DenseStorage.h" #include "src/Core/NestByValue.h" -#include "src/Core/ForceAlignedAccess.h" + +// #include "src/Core/ForceAlignedAccess.h" + #include "src/Core/ReturnByValue.h" #include "src/Core/NoAlias.h" #include "src/Core/PlainObjectBase.h" #include "src/Core/Matrix.h" #include "src/Core/Array.h" +#include "src/Core/CwiseTernaryOp.h" #include "src/Core/CwiseBinaryOp.h" #include "src/Core/CwiseUnaryOp.h" #include "src/Core/CwiseNullaryOp.h" @@ -300,32 +444,32 @@ using std::ptrdiff_t; #include "src/Core/SelfCwiseBinaryOp.h" #include "src/Core/Dot.h" #include "src/Core/StableNorm.h" -#include "src/Core/MapBase.h" #include "src/Core/Stride.h" +#include "src/Core/MapBase.h" #include "src/Core/Map.h" +#include "src/Core/Ref.h" #include "src/Core/Block.h" #include "src/Core/VectorBlock.h" -#include "src/Core/Ref.h" #include "src/Core/Transpose.h" #include "src/Core/DiagonalMatrix.h" #include "src/Core/Diagonal.h" #include "src/Core/DiagonalProduct.h" -#include "src/Core/PermutationMatrix.h" -#include "src/Core/Transpositions.h" #include "src/Core/Redux.h" #include "src/Core/Visitor.h" #include "src/Core/Fuzzy.h" -#include "src/Core/IO.h" #include "src/Core/Swap.h" #include "src/Core/CommaInitializer.h" -#include "src/Core/Flagged.h" -#include "src/Core/ProductBase.h" #include "src/Core/GeneralProduct.h" +#include "src/Core/Solve.h" +#include "src/Core/Inverse.h" +#include "src/Core/SolverBase.h" +#include "src/Core/PermutationMatrix.h" +#include "src/Core/Transpositions.h" #include "src/Core/TriangularMatrix.h" #include "src/Core/SelfAdjointView.h" #include "src/Core/products/GeneralBlockPanelKernel.h" #include "src/Core/products/Parallelizer.h" -#include "src/Core/products/CoeffBasedProduct.h" +#include "src/Core/ProductEvaluators.h" #include "src/Core/products/GeneralMatrixVector.h" #include "src/Core/products/GeneralMatrixMatrix.h" #include "src/Core/SolveTriangular.h" @@ -340,6 +484,7 @@ using std::ptrdiff_t; #include "src/Core/products/TriangularSolverVector.h" #include "src/Core/BandMatrix.h" #include "src/Core/CoreIterators.h" +#include "src/Core/ConditionEstimator.h" #include "src/Core/BooleanRedux.h" #include "src/Core/Select.h" @@ -347,18 +492,17 @@ using std::ptrdiff_t; #include "src/Core/Random.h" #include "src/Core/Replicate.h" #include "src/Core/Reverse.h" -#include "src/Core/ArrayBase.h" #include "src/Core/ArrayWrapper.h" #ifdef EIGEN_USE_BLAS -#include "src/Core/products/GeneralMatrixMatrix_MKL.h" -#include "src/Core/products/GeneralMatrixVector_MKL.h" -#include "src/Core/products/GeneralMatrixMatrixTriangular_MKL.h" -#include "src/Core/products/SelfadjointMatrixMatrix_MKL.h" -#include "src/Core/products/SelfadjointMatrixVector_MKL.h" -#include "src/Core/products/TriangularMatrixMatrix_MKL.h" -#include "src/Core/products/TriangularMatrixVector_MKL.h" -#include "src/Core/products/TriangularSolverMatrix_MKL.h" +#include "src/Core/products/GeneralMatrixMatrix_BLAS.h" +#include "src/Core/products/GeneralMatrixVector_BLAS.h" +#include "src/Core/products/GeneralMatrixMatrixTriangular_BLAS.h" +#include "src/Core/products/SelfadjointMatrixMatrix_BLAS.h" +#include "src/Core/products/SelfadjointMatrixVector_BLAS.h" +#include "src/Core/products/TriangularMatrixMatrix_BLAS.h" +#include "src/Core/products/TriangularMatrixVector_BLAS.h" +#include "src/Core/products/TriangularSolverMatrix_BLAS.h" #endif // EIGEN_USE_BLAS #ifdef EIGEN_USE_MKL_VML @@ -369,8 +513,4 @@ using std::ptrdiff_t; #include "src/Core/util/ReenableStupidWarnings.h" -#ifdef EIGEN2_SUPPORT -#include "Eigen2Support" -#endif - #endif // EIGEN_CORE_H diff --git a/ground/gcs/src/libs/eigen/Eigen/Eigen b/ground/gcs/src/libs/eigen/Eigen/Eigen index 19b40ea4e7..654c8dc638 100644 --- a/ground/gcs/src/libs/eigen/Eigen/Eigen +++ b/ground/gcs/src/libs/eigen/Eigen/Eigen @@ -1,2 +1,2 @@ #include "Dense" -//#include "Sparse" +#include "Sparse" diff --git a/ground/gcs/src/libs/eigen/Eigen/Eigen2Support b/ground/gcs/src/libs/eigen/Eigen/Eigen2Support deleted file mode 100644 index 6aa009d209..0000000000 --- a/ground/gcs/src/libs/eigen/Eigen/Eigen2Support +++ /dev/null @@ -1,95 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2009 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN2SUPPORT_H -#define EIGEN2SUPPORT_H - -#if (!defined(EIGEN2_SUPPORT)) || (!defined(EIGEN_CORE_H)) -#error Eigen2 support must be enabled by defining EIGEN2_SUPPORT before including any Eigen header -#endif - -#ifndef EIGEN_NO_EIGEN2_DEPRECATED_WARNING - -#if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__clang__) -#warning "Eigen2 support is deprecated in Eigen 3.2.x and it will be removed in Eigen 3.3. (Define EIGEN_NO_EIGEN2_DEPRECATED_WARNING to disable this warning)" -#else -#pragma message ("Eigen2 support is deprecated in Eigen 3.2.x and it will be removed in Eigen 3.3. (Define EIGEN_NO_EIGEN2_DEPRECATED_WARNING to disable this warning)") -#endif - -#endif // EIGEN_NO_EIGEN2_DEPRECATED_WARNING - -#include "src/Core/util/DisableStupidWarnings.h" - -/** \ingroup Support_modules - * \defgroup Eigen2Support_Module Eigen2 support module - * - * \warning Eigen2 support is deprecated in Eigen 3.2.x and it will be removed in Eigen 3.3. - * - * This module provides a couple of deprecated functions improving the compatibility with Eigen2. - * - * To use it, define EIGEN2_SUPPORT before including any Eigen header - * \code - * #define EIGEN2_SUPPORT - * \endcode - * - */ - -#include "src/Eigen2Support/Macros.h" -#include "src/Eigen2Support/Memory.h" -#include "src/Eigen2Support/Meta.h" -#include "src/Eigen2Support/Lazy.h" -#include "src/Eigen2Support/Cwise.h" -#include "src/Eigen2Support/CwiseOperators.h" -#include "src/Eigen2Support/TriangularSolver.h" -#include "src/Eigen2Support/Block.h" -#include "src/Eigen2Support/VectorBlock.h" -#include "src/Eigen2Support/Minor.h" -#include "src/Eigen2Support/MathFunctions.h" - - -#include "src/Core/util/ReenableStupidWarnings.h" - -// Eigen2 used to include iostream -#include - -#define EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, SizeSuffix) \ -using Eigen::Matrix##SizeSuffix##TypeSuffix; \ -using Eigen::Vector##SizeSuffix##TypeSuffix; \ -using Eigen::RowVector##SizeSuffix##TypeSuffix; - -#define EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE(TypeSuffix) \ -EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, 2) \ -EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, 3) \ -EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, 4) \ -EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE_AND_SIZE(TypeSuffix, X) \ - -#define EIGEN_USING_MATRIX_TYPEDEFS \ -EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE(i) \ -EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE(f) \ -EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE(d) \ -EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE(cf) \ -EIGEN_USING_MATRIX_TYPEDEFS_FOR_TYPE(cd) - -#define USING_PART_OF_NAMESPACE_EIGEN \ -EIGEN_USING_MATRIX_TYPEDEFS \ -using Eigen::Matrix; \ -using Eigen::MatrixBase; \ -using Eigen::ei_random; \ -using Eigen::ei_real; \ -using Eigen::ei_imag; \ -using Eigen::ei_conj; \ -using Eigen::ei_abs; \ -using Eigen::ei_abs2; \ -using Eigen::ei_sqrt; \ -using Eigen::ei_exp; \ -using Eigen::ei_log; \ -using Eigen::ei_sin; \ -using Eigen::ei_cos; - -#endif // EIGEN2SUPPORT_H diff --git a/ground/gcs/src/libs/eigen/Eigen/Eigenvalues b/ground/gcs/src/libs/eigen/Eigen/Eigenvalues index 53c5a73a27..009e529e19 100644 --- a/ground/gcs/src/libs/eigen/Eigen/Eigenvalues +++ b/ground/gcs/src/libs/eigen/Eigen/Eigenvalues @@ -1,3 +1,10 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + #ifndef EIGEN_EIGENVALUES_MODULE_H #define EIGEN_EIGENVALUES_MODULE_H @@ -25,6 +32,7 @@ * \endcode */ +#include "src/misc/RealSvd2x2.h" #include "src/Eigenvalues/Tridiagonalization.h" #include "src/Eigenvalues/RealSchur.h" #include "src/Eigenvalues/EigenSolver.h" @@ -37,9 +45,10 @@ #include "src/Eigenvalues/GeneralizedEigenSolver.h" #include "src/Eigenvalues/MatrixBaseEigenvalues.h" #ifdef EIGEN_USE_LAPACKE -#include "src/Eigenvalues/RealSchur_MKL.h" -#include "src/Eigenvalues/ComplexSchur_MKL.h" -#include "src/Eigenvalues/SelfAdjointEigenSolver_MKL.h" +#include "src/misc/lapacke.h" +#include "src/Eigenvalues/RealSchur_LAPACKE.h" +#include "src/Eigenvalues/ComplexSchur_LAPACKE.h" +#include "src/Eigenvalues/SelfAdjointEigenSolver_LAPACKE.h" #endif #include "src/Core/util/ReenableStupidWarnings.h" diff --git a/ground/gcs/src/libs/eigen/Eigen/Geometry b/ground/gcs/src/libs/eigen/Eigen/Geometry index efd9d4504c..716d529529 100644 --- a/ground/gcs/src/libs/eigen/Eigen/Geometry +++ b/ground/gcs/src/libs/eigen/Eigen/Geometry @@ -1,3 +1,10 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + #ifndef EIGEN_GEOMETRY_MODULE_H #define EIGEN_GEOMETRY_MODULE_H @@ -9,21 +16,17 @@ #include "LU" #include -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif - /** \defgroup Geometry_Module Geometry module - * - * * * This module provides support for: * - fixed-size homogeneous transformations * - translation, scaling, 2D and 3D rotations - * - quaternions - * - \ref MatrixBase::cross() "cross product" - * - \ref MatrixBase::unitOrthogonal() "orthognal vector generation" - * - some linear components: parametrized-lines and hyperplanes + * - \link Quaternion quaternions \endlink + * - cross products (\ref MatrixBase::cross, \ref MatrixBase::cross3) + * - orthognal vector generation (\ref MatrixBase::unitOrthogonal) + * - some linear components: \link ParametrizedLine parametrized-lines \endlink and \link Hyperplane hyperplanes \endlink + * - \link AlignedBox axis aligned bounding boxes \endlink + * - \link umeyama least-square transformation fitting \endlink * * \code * #include @@ -33,27 +36,23 @@ #include "src/Geometry/OrthoMethods.h" #include "src/Geometry/EulerAngles.h" -#if EIGEN2_SUPPORT_STAGE > STAGE20_RESOLVE_API_CONFLICTS - #include "src/Geometry/Homogeneous.h" - #include "src/Geometry/RotationBase.h" - #include "src/Geometry/Rotation2D.h" - #include "src/Geometry/Quaternion.h" - #include "src/Geometry/AngleAxis.h" - #include "src/Geometry/Transform.h" - #include "src/Geometry/Translation.h" - #include "src/Geometry/Scaling.h" - #include "src/Geometry/Hyperplane.h" - #include "src/Geometry/ParametrizedLine.h" - #include "src/Geometry/AlignedBox.h" - #include "src/Geometry/Umeyama.h" - - #if defined EIGEN_VECTORIZE_SSE - #include "src/Geometry/arch/Geometry_SSE.h" - #endif -#endif - -#ifdef EIGEN2_SUPPORT -#include "src/Eigen2Support/Geometry/All.h" +#include "src/Geometry/Homogeneous.h" +#include "src/Geometry/RotationBase.h" +#include "src/Geometry/Rotation2D.h" +#include "src/Geometry/Quaternion.h" +#include "src/Geometry/AngleAxis.h" +#include "src/Geometry/Transform.h" +#include "src/Geometry/Translation.h" +#include "src/Geometry/Scaling.h" +#include "src/Geometry/Hyperplane.h" +#include "src/Geometry/ParametrizedLine.h" +#include "src/Geometry/AlignedBox.h" +#include "src/Geometry/Umeyama.h" + +// Use the SSE optimized version whenever possible. At the moment the +// SSE version doesn't compile when AVX is enabled +#if defined EIGEN_VECTORIZE_SSE && !defined EIGEN_VECTORIZE_AVX +#include "src/Geometry/arch/Geometry_SSE.h" #endif #include "src/Core/util/ReenableStupidWarnings.h" diff --git a/ground/gcs/src/libs/eigen/Eigen/Householder b/ground/gcs/src/libs/eigen/Eigen/Householder index 6e348db5c4..89cd81b1af 100644 --- a/ground/gcs/src/libs/eigen/Eigen/Householder +++ b/ground/gcs/src/libs/eigen/Eigen/Householder @@ -1,3 +1,10 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + #ifndef EIGEN_HOUSEHOLDER_MODULE_H #define EIGEN_HOUSEHOLDER_MODULE_H diff --git a/ground/gcs/src/libs/eigen/Eigen/IterativeLinearSolvers b/ground/gcs/src/libs/eigen/Eigen/IterativeLinearSolvers index 0f4159dc19..957d5750b2 100644 --- a/ground/gcs/src/libs/eigen/Eigen/IterativeLinearSolvers +++ b/ground/gcs/src/libs/eigen/Eigen/IterativeLinearSolvers @@ -1,3 +1,10 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + #ifndef EIGEN_ITERATIVELINEARSOLVERS_MODULE_H #define EIGEN_ITERATIVELINEARSOLVERS_MODULE_H @@ -12,28 +19,29 @@ * This module currently provides iterative methods to solve problems of the form \c A \c x = \c b, where \c A is a squared matrix, usually very large and sparse. * Those solvers are accessible via the following classes: * - ConjugateGradient for selfadjoint (hermitian) matrices, + * - LeastSquaresConjugateGradient for rectangular least-square problems, * - BiCGSTAB for general square matrices. * * These iterative solvers are associated with some preconditioners: * - IdentityPreconditioner - not really useful - * - DiagonalPreconditioner - also called JAcobi preconditioner, work very well on diagonal dominant matrices. - * - IncompleteILUT - incomplete LU factorization with dual thresholding + * - DiagonalPreconditioner - also called Jacobi preconditioner, work very well on diagonal dominant matrices. + * - IncompleteLUT - incomplete LU factorization with dual thresholding * * Such problems can also be solved using the direct sparse decomposition modules: SparseCholesky, CholmodSupport, UmfPackSupport, SuperLUSupport. * - * \code - * #include - * \endcode + \code + #include + \endcode */ -#include "src/misc/Solve.h" -#include "src/misc/SparseSolve.h" - +#include "src/IterativeLinearSolvers/SolveWithGuess.h" #include "src/IterativeLinearSolvers/IterativeSolverBase.h" #include "src/IterativeLinearSolvers/BasicPreconditioners.h" #include "src/IterativeLinearSolvers/ConjugateGradient.h" +#include "src/IterativeLinearSolvers/LeastSquareConjugateGradient.h" #include "src/IterativeLinearSolvers/BiCGSTAB.h" #include "src/IterativeLinearSolvers/IncompleteLUT.h" +#include "src/IterativeLinearSolvers/IncompleteCholesky.h" #include "src/Core/util/ReenableStupidWarnings.h" diff --git a/ground/gcs/src/libs/eigen/Eigen/Jacobi b/ground/gcs/src/libs/eigen/Eigen/Jacobi index ba8a4dc36a..17c1d785a1 100644 --- a/ground/gcs/src/libs/eigen/Eigen/Jacobi +++ b/ground/gcs/src/libs/eigen/Eigen/Jacobi @@ -1,3 +1,10 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + #ifndef EIGEN_JACOBI_MODULE_H #define EIGEN_JACOBI_MODULE_H diff --git a/ground/gcs/src/libs/eigen/Eigen/LU b/ground/gcs/src/libs/eigen/Eigen/LU index db57955044..6f6c55629c 100644 --- a/ground/gcs/src/libs/eigen/Eigen/LU +++ b/ground/gcs/src/libs/eigen/Eigen/LU @@ -1,3 +1,10 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + #ifndef EIGEN_LU_MODULE_H #define EIGEN_LU_MODULE_H @@ -16,25 +23,23 @@ * \endcode */ -#include "src/misc/Solve.h" #include "src/misc/Kernel.h" #include "src/misc/Image.h" #include "src/LU/FullPivLU.h" #include "src/LU/PartialPivLU.h" #ifdef EIGEN_USE_LAPACKE -#include "src/LU/PartialPivLU_MKL.h" +#include "src/misc/lapacke.h" +#include "src/LU/PartialPivLU_LAPACKE.h" #endif #include "src/LU/Determinant.h" -#include "src/LU/Inverse.h" +#include "src/LU/InverseImpl.h" -#if defined EIGEN_VECTORIZE_SSE +// Use the SSE optimized version whenever possible. At the moment the +// SSE version doesn't compile when AVX is enabled +#if defined EIGEN_VECTORIZE_SSE && !defined EIGEN_VECTORIZE_AVX #include "src/LU/arch/Inverse_SSE.h" #endif -#ifdef EIGEN2_SUPPORT - #include "src/Eigen2Support/LU.h" -#endif - #include "src/Core/util/ReenableStupidWarnings.h" #endif // EIGEN_LU_MODULE_H diff --git a/ground/gcs/src/libs/eigen/Eigen/LeastSquares b/ground/gcs/src/libs/eigen/Eigen/LeastSquares deleted file mode 100644 index 35137c25db..0000000000 --- a/ground/gcs/src/libs/eigen/Eigen/LeastSquares +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef EIGEN_REGRESSION_MODULE_H -#define EIGEN_REGRESSION_MODULE_H - -#ifndef EIGEN2_SUPPORT -#error LeastSquares is only available in Eigen2 support mode (define EIGEN2_SUPPORT) -#endif - -// exclude from normal eigen3-only documentation -#ifdef EIGEN2_SUPPORT - -#include "Core" - -#include "src/Core/util/DisableStupidWarnings.h" - -#include "Eigenvalues" -#include "Geometry" - -/** \defgroup LeastSquares_Module LeastSquares module - * This module provides linear regression and related features. - * - * \code - * #include - * \endcode - */ - -#include "src/Eigen2Support/LeastSquares.h" - -#include "src/Core/util/ReenableStupidWarnings.h" - -#endif // EIGEN2_SUPPORT - -#endif // EIGEN_REGRESSION_MODULE_H diff --git a/ground/gcs/src/libs/eigen/Eigen/MetisSupport b/ground/gcs/src/libs/eigen/Eigen/MetisSupport index 6a113f7a87..85c41bf340 100644 --- a/ground/gcs/src/libs/eigen/Eigen/MetisSupport +++ b/ground/gcs/src/libs/eigen/Eigen/MetisSupport @@ -1,3 +1,10 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + #ifndef EIGEN_METISSUPPORT_MODULE_H #define EIGEN_METISSUPPORT_MODULE_H diff --git a/ground/gcs/src/libs/eigen/Eigen/OrderingMethods b/ground/gcs/src/libs/eigen/Eigen/OrderingMethods index 7c0f1fffff..d8ea361936 100644 --- a/ground/gcs/src/libs/eigen/Eigen/OrderingMethods +++ b/ground/gcs/src/libs/eigen/Eigen/OrderingMethods @@ -1,3 +1,10 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + #ifndef EIGEN_ORDERINGMETHODS_MODULE_H #define EIGEN_ORDERINGMETHODS_MODULE_H diff --git a/ground/gcs/src/libs/eigen/Eigen/PaStiXSupport b/ground/gcs/src/libs/eigen/Eigen/PaStiXSupport index 7c616ee5ea..de3a63b4d1 100644 --- a/ground/gcs/src/libs/eigen/Eigen/PaStiXSupport +++ b/ground/gcs/src/libs/eigen/Eigen/PaStiXSupport @@ -1,3 +1,10 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + #ifndef EIGEN_PASTIXSUPPORT_MODULE_H #define EIGEN_PASTIXSUPPORT_MODULE_H @@ -5,7 +12,6 @@ #include "src/Core/util/DisableStupidWarnings.h" -#include extern "C" { #include #include @@ -35,12 +41,8 @@ extern "C" { * */ -#include "src/misc/Solve.h" -#include "src/misc/SparseSolve.h" - #include "src/PaStiXSupport/PaStiXSupport.h" - #include "src/Core/util/ReenableStupidWarnings.h" #endif // EIGEN_PASTIXSUPPORT_MODULE_H diff --git a/ground/gcs/src/libs/eigen/Eigen/PardisoSupport b/ground/gcs/src/libs/eigen/Eigen/PardisoSupport index 99330ce7a7..340edf51fe 100644 --- a/ground/gcs/src/libs/eigen/Eigen/PardisoSupport +++ b/ground/gcs/src/libs/eigen/Eigen/PardisoSupport @@ -1,3 +1,10 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + #ifndef EIGEN_PARDISOSUPPORT_MODULE_H #define EIGEN_PARDISOSUPPORT_MODULE_H @@ -7,8 +14,6 @@ #include -#include - /** \ingroup Support_modules * \defgroup PardisoSupport_Module PardisoSupport module * diff --git a/ground/gcs/src/libs/eigen/Eigen/QR b/ground/gcs/src/libs/eigen/Eigen/QR index ac5b026935..80838e3bdd 100644 --- a/ground/gcs/src/libs/eigen/Eigen/QR +++ b/ground/gcs/src/libs/eigen/Eigen/QR @@ -1,3 +1,10 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + #ifndef EIGEN_QR_MODULE_H #define EIGEN_QR_MODULE_H @@ -15,31 +22,26 @@ * * This module provides various QR decompositions * This module also provides some MatrixBase methods, including: - * - MatrixBase::qr(), + * - MatrixBase::householderQr() + * - MatrixBase::colPivHouseholderQr() + * - MatrixBase::fullPivHouseholderQr() * * \code * #include * \endcode */ -#include "src/misc/Solve.h" #include "src/QR/HouseholderQR.h" #include "src/QR/FullPivHouseholderQR.h" #include "src/QR/ColPivHouseholderQR.h" +#include "src/QR/CompleteOrthogonalDecomposition.h" #ifdef EIGEN_USE_LAPACKE -#include "src/QR/HouseholderQR_MKL.h" -#include "src/QR/ColPivHouseholderQR_MKL.h" -#endif - -#ifdef EIGEN2_SUPPORT -#include "src/Eigen2Support/QR.h" +#include "src/misc/lapacke.h" +#include "src/QR/HouseholderQR_LAPACKE.h" +#include "src/QR/ColPivHouseholderQR_LAPACKE.h" #endif #include "src/Core/util/ReenableStupidWarnings.h" -#ifdef EIGEN2_SUPPORT -#include "Eigenvalues" -#endif - #endif // EIGEN_QR_MODULE_H /* vim: set filetype=cpp et sw=2 ts=2 ai: */ diff --git a/ground/gcs/src/libs/eigen/Eigen/QtAlignedMalloc b/ground/gcs/src/libs/eigen/Eigen/QtAlignedMalloc index 46f7d83b70..c6571f1291 100644 --- a/ground/gcs/src/libs/eigen/Eigen/QtAlignedMalloc +++ b/ground/gcs/src/libs/eigen/Eigen/QtAlignedMalloc @@ -1,3 +1,9 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_QTMALLOC_MODULE_H #define EIGEN_QTMALLOC_MODULE_H @@ -8,7 +14,7 @@ #include "src/Core/util/DisableStupidWarnings.h" -void *qMalloc(size_t size) +void *qMalloc(std::size_t size) { return Eigen::internal::aligned_malloc(size); } @@ -18,7 +24,7 @@ void qFree(void *ptr) Eigen::internal::aligned_free(ptr); } -void *qRealloc(void *ptr, size_t size) +void *qRealloc(void *ptr, std::size_t size) { void* newPtr = Eigen::internal::aligned_malloc(size); memcpy(newPtr, ptr, size); diff --git a/ground/gcs/src/libs/eigen/Eigen/SPQRSupport b/ground/gcs/src/libs/eigen/Eigen/SPQRSupport index 7f1eb4770b..f70390c176 100644 --- a/ground/gcs/src/libs/eigen/Eigen/SPQRSupport +++ b/ground/gcs/src/libs/eigen/Eigen/SPQRSupport @@ -1,3 +1,10 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + #ifndef EIGEN_SPQRSUPPORT_MODULE_H #define EIGEN_SPQRSUPPORT_MODULE_H @@ -21,8 +28,6 @@ * */ -#include "src/misc/Solve.h" -#include "src/misc/SparseSolve.h" #include "src/CholmodSupport/CholmodSupport.h" #include "src/SPQRSupport/SuiteSparseQRSupport.h" diff --git a/ground/gcs/src/libs/eigen/Eigen/SVD b/ground/gcs/src/libs/eigen/Eigen/SVD index fd310017ad..86143c23d7 100644 --- a/ground/gcs/src/libs/eigen/Eigen/SVD +++ b/ground/gcs/src/libs/eigen/Eigen/SVD @@ -1,3 +1,10 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + #ifndef EIGEN_SVD_MODULE_H #define EIGEN_SVD_MODULE_H @@ -12,23 +19,26 @@ * * * This module provides SVD decomposition for matrices (both real and complex). - * This decomposition is accessible via the following MatrixBase method: + * Two decomposition algorithms are provided: + * - JacobiSVD implementing two-sided Jacobi iterations is numerically very accurate, fast for small matrices, but very slow for larger ones. + * - BDCSVD implementing a recursive divide & conquer strategy on top of an upper-bidiagonalization which remains fast for large problems. + * These decompositions are accessible via the respective classes and following MatrixBase methods: * - MatrixBase::jacobiSvd() + * - MatrixBase::bdcSvd() * * \code * #include * \endcode */ -#include "src/misc/Solve.h" +#include "src/misc/RealSvd2x2.h" +#include "src/SVD/UpperBidiagonalization.h" +#include "src/SVD/SVDBase.h" #include "src/SVD/JacobiSVD.h" +#include "src/SVD/BDCSVD.h" #if defined(EIGEN_USE_LAPACKE) && !defined(EIGEN_USE_LAPACKE_STRICT) -#include "src/SVD/JacobiSVD_MKL.h" -#endif -#include "src/SVD/UpperBidiagonalization.h" - -#ifdef EIGEN2_SUPPORT -#include "src/Eigen2Support/SVD.h" +#include "src/misc/lapacke.h" +#include "src/SVD/JacobiSVD_LAPACKE.h" #endif #include "src/Core/util/ReenableStupidWarnings.h" diff --git a/ground/gcs/src/libs/eigen/Eigen/Sparse b/ground/gcs/src/libs/eigen/Eigen/Sparse index 7cc9c09133..136e681a1f 100644 --- a/ground/gcs/src/libs/eigen/Eigen/Sparse +++ b/ground/gcs/src/libs/eigen/Eigen/Sparse @@ -1,3 +1,10 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + #ifndef EIGEN_SPARSE_MODULE_H #define EIGEN_SPARSE_MODULE_H @@ -11,14 +18,16 @@ * - \ref SparseQR_Module * - \ref IterativeLinearSolvers_Module * - * \code - * #include - * \endcode + \code + #include + \endcode */ #include "SparseCore" #include "OrderingMethods" +#ifndef EIGEN_MPL2_ONLY #include "SparseCholesky" +#endif #include "SparseLU" #include "SparseQR" #include "IterativeLinearSolvers" diff --git a/ground/gcs/src/libs/eigen/Eigen/SparseCholesky b/ground/gcs/src/libs/eigen/Eigen/SparseCholesky index 9f5056aa1a..b6a320c402 100644 --- a/ground/gcs/src/libs/eigen/Eigen/SparseCholesky +++ b/ground/gcs/src/libs/eigen/Eigen/SparseCholesky @@ -34,8 +34,6 @@ #error The SparseCholesky module has nothing to offer in MPL2 only mode #endif -#include "src/misc/Solve.h" -#include "src/misc/SparseSolve.h" #include "src/SparseCholesky/SimplicialCholesky.h" #ifndef EIGEN_MPL2_ONLY diff --git a/ground/gcs/src/libs/eigen/Eigen/SparseCore b/ground/gcs/src/libs/eigen/Eigen/SparseCore index 24bcf0156b..76966c4c4c 100644 --- a/ground/gcs/src/libs/eigen/Eigen/SparseCore +++ b/ground/gcs/src/libs/eigen/Eigen/SparseCore @@ -1,3 +1,10 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + #ifndef EIGEN_SPARSECORE_MODULE_H #define EIGEN_SPARSECORE_MODULE_H @@ -26,37 +33,35 @@ * This module depends on: Core. */ -namespace Eigen { - -/** The type used to identify a general sparse storage. */ -struct Sparse {}; - -} - #include "src/SparseCore/SparseUtil.h" #include "src/SparseCore/SparseMatrixBase.h" +#include "src/SparseCore/SparseAssign.h" #include "src/SparseCore/CompressedStorage.h" #include "src/SparseCore/AmbiVector.h" +#include "src/SparseCore/SparseCompressedBase.h" #include "src/SparseCore/SparseMatrix.h" +#include "src/SparseCore/SparseMap.h" #include "src/SparseCore/MappedSparseMatrix.h" #include "src/SparseCore/SparseVector.h" -#include "src/SparseCore/SparseBlock.h" -#include "src/SparseCore/SparseTranspose.h" +#include "src/SparseCore/SparseRef.h" #include "src/SparseCore/SparseCwiseUnaryOp.h" #include "src/SparseCore/SparseCwiseBinaryOp.h" +#include "src/SparseCore/SparseTranspose.h" +#include "src/SparseCore/SparseBlock.h" #include "src/SparseCore/SparseDot.h" -#include "src/SparseCore/SparsePermutation.h" #include "src/SparseCore/SparseRedux.h" -#include "src/SparseCore/SparseFuzzy.h" +#include "src/SparseCore/SparseView.h" +#include "src/SparseCore/SparseDiagonalProduct.h" #include "src/SparseCore/ConservativeSparseSparseProduct.h" #include "src/SparseCore/SparseSparseProductWithPruning.h" #include "src/SparseCore/SparseProduct.h" #include "src/SparseCore/SparseDenseProduct.h" -#include "src/SparseCore/SparseDiagonalProduct.h" -#include "src/SparseCore/SparseTriangularView.h" #include "src/SparseCore/SparseSelfAdjointView.h" +#include "src/SparseCore/SparseTriangularView.h" #include "src/SparseCore/TriangularSolver.h" -#include "src/SparseCore/SparseView.h" +#include "src/SparseCore/SparsePermutation.h" +#include "src/SparseCore/SparseFuzzy.h" +#include "src/SparseCore/SparseSolverBase.h" #include "src/Core/util/ReenableStupidWarnings.h" diff --git a/ground/gcs/src/libs/eigen/Eigen/SparseLU b/ground/gcs/src/libs/eigen/Eigen/SparseLU index 8527a49bd8..38b38b531d 100644 --- a/ground/gcs/src/libs/eigen/Eigen/SparseLU +++ b/ground/gcs/src/libs/eigen/Eigen/SparseLU @@ -20,9 +20,6 @@ * Please, see the documentation of the SparseLU class for more details. */ -#include "src/misc/Solve.h" -#include "src/misc/SparseSolve.h" - // Ordering interface #include "OrderingMethods" diff --git a/ground/gcs/src/libs/eigen/Eigen/SparseQR b/ground/gcs/src/libs/eigen/Eigen/SparseQR index 4ee42065ee..a6f3b7f7d7 100644 --- a/ground/gcs/src/libs/eigen/Eigen/SparseQR +++ b/ground/gcs/src/libs/eigen/Eigen/SparseQR @@ -1,3 +1,10 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + #ifndef EIGEN_SPARSEQR_MODULE_H #define EIGEN_SPARSEQR_MODULE_H @@ -21,9 +28,6 @@ * */ -#include "src/misc/Solve.h" -#include "src/misc/SparseSolve.h" - #include "OrderingMethods" #include "src/SparseCore/SparseColEtree.h" #include "src/SparseQR/SparseQR.h" diff --git a/ground/gcs/src/libs/eigen/Eigen/StdDeque b/ground/gcs/src/libs/eigen/Eigen/StdDeque index f27234778f..bc68397be2 100644 --- a/ground/gcs/src/libs/eigen/Eigen/StdDeque +++ b/ground/gcs/src/libs/eigen/Eigen/StdDeque @@ -14,7 +14,7 @@ #include "Core" #include -#if (defined(_MSC_VER) && defined(_WIN64)) /* MSVC auto aligns in 64 bit builds */ +#if EIGEN_COMP_MSVC && EIGEN_OS_WIN64 && (EIGEN_MAX_STATIC_ALIGN_BYTES<=16) /* MSVC auto aligns up to 16 bytes in 64 bit builds */ #define EIGEN_DEFINE_STL_DEQUE_SPECIALIZATION(...) diff --git a/ground/gcs/src/libs/eigen/Eigen/StdList b/ground/gcs/src/libs/eigen/Eigen/StdList index 225c1e18f8..4c6262c08c 100644 --- a/ground/gcs/src/libs/eigen/Eigen/StdList +++ b/ground/gcs/src/libs/eigen/Eigen/StdList @@ -13,7 +13,7 @@ #include "Core" #include -#if (defined(_MSC_VER) && defined(_WIN64)) /* MSVC auto aligns in 64 bit builds */ +#if EIGEN_COMP_MSVC && EIGEN_OS_WIN64 && (EIGEN_MAX_STATIC_ALIGN_BYTES<=16) /* MSVC auto aligns up to 16 bytes in 64 bit builds */ #define EIGEN_DEFINE_STL_LIST_SPECIALIZATION(...) diff --git a/ground/gcs/src/libs/eigen/Eigen/StdVector b/ground/gcs/src/libs/eigen/Eigen/StdVector index 6b22627f6f..0c4697ad5b 100644 --- a/ground/gcs/src/libs/eigen/Eigen/StdVector +++ b/ground/gcs/src/libs/eigen/Eigen/StdVector @@ -14,7 +14,7 @@ #include "Core" #include -#if (defined(_MSC_VER) && defined(_WIN64)) /* MSVC auto aligns in 64 bit builds */ +#if EIGEN_COMP_MSVC && EIGEN_OS_WIN64 && (EIGEN_MAX_STATIC_ALIGN_BYTES<=16) /* MSVC auto aligns up to 16 bytes in 64 bit builds */ #define EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(...) diff --git a/ground/gcs/src/libs/eigen/Eigen/SuperLUSupport b/ground/gcs/src/libs/eigen/Eigen/SuperLUSupport index 575e14fbc2..59312a82db 100644 --- a/ground/gcs/src/libs/eigen/Eigen/SuperLUSupport +++ b/ground/gcs/src/libs/eigen/Eigen/SuperLUSupport @@ -1,3 +1,10 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + #ifndef EIGEN_SUPERLUSUPPORT_MODULE_H #define EIGEN_SUPERLUSUPPORT_MODULE_H @@ -36,6 +43,8 @@ namespace Eigen { struct SluMatrix; } * - class SuperLU: a supernodal sequential LU factorization. * - class SuperILU: a supernodal sequential incomplete LU factorization (to be used as a preconditioner for iterative methods). * + * \warning This wrapper requires at least versions 4.0 of SuperLU. The 3.x versions are not supported. + * * \warning When including this module, you have to use SUPERLU_EMPTY instead of EMPTY which is no longer defined because it is too polluting. * * \code @@ -48,12 +57,8 @@ namespace Eigen { struct SluMatrix; } * */ -#include "src/misc/Solve.h" -#include "src/misc/SparseSolve.h" - #include "src/SuperLUSupport/SuperLUSupport.h" - #include "src/Core/util/ReenableStupidWarnings.h" #endif // EIGEN_SUPERLUSUPPORT_MODULE_H diff --git a/ground/gcs/src/libs/eigen/Eigen/UmfPackSupport b/ground/gcs/src/libs/eigen/Eigen/UmfPackSupport index 7b1b660649..00eec80875 100644 --- a/ground/gcs/src/libs/eigen/Eigen/UmfPackSupport +++ b/ground/gcs/src/libs/eigen/Eigen/UmfPackSupport @@ -1,3 +1,10 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + #ifndef EIGEN_UMFPACKSUPPORT_MODULE_H #define EIGEN_UMFPACKSUPPORT_MODULE_H @@ -26,9 +33,6 @@ extern "C" { * */ -#include "src/misc/Solve.h" -#include "src/misc/SparseSolve.h" - #include "src/UmfPackSupport/UmfPackSupport.h" #include "src/Core/util/ReenableStupidWarnings.h" diff --git a/ground/gcs/src/libs/eigen/Eigen/src/CMakeLists.txt b/ground/gcs/src/libs/eigen/Eigen/src/CMakeLists.txt deleted file mode 100644 index c326f374d9..0000000000 --- a/ground/gcs/src/libs/eigen/Eigen/src/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -file(GLOB Eigen_src_subdirectories "*") -escape_string_as_regex(ESCAPED_CMAKE_CURRENT_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") -foreach(f ${Eigen_src_subdirectories}) - if(NOT f MATCHES "\\.txt" AND NOT f MATCHES "${ESCAPED_CMAKE_CURRENT_SOURCE_DIR}/[.].+" ) - add_subdirectory(${f}) - endif() -endforeach() diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Cholesky/CMakeLists.txt b/ground/gcs/src/libs/eigen/Eigen/src/Cholesky/CMakeLists.txt deleted file mode 100644 index d01488b41a..0000000000 --- a/ground/gcs/src/libs/eigen/Eigen/src/Cholesky/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -FILE(GLOB Eigen_Cholesky_SRCS "*.h") - -INSTALL(FILES - ${Eigen_Cholesky_SRCS} - DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/Cholesky COMPONENT Devel - ) diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Cholesky/LDLT.h b/ground/gcs/src/libs/eigen/Eigen/src/Cholesky/LDLT.h index abd30bd916..fcee7b2e3f 100644 --- a/ground/gcs/src/libs/eigen/Eigen/src/Cholesky/LDLT.h +++ b/ground/gcs/src/libs/eigen/Eigen/src/Cholesky/LDLT.h @@ -13,7 +13,7 @@ #ifndef EIGEN_LDLT_H #define EIGEN_LDLT_H -namespace Eigen { +namespace Eigen { namespace internal { template struct LDLT_Traits; @@ -28,8 +28,8 @@ namespace internal { * * \brief Robust Cholesky decomposition of a matrix with pivoting * - * \param MatrixType the type of the matrix of which to compute the LDL^T Cholesky decomposition - * \param UpLo the triangular part that will be used for the decompositon: Lower (default) or Upper. + * \tparam _MatrixType the type of the matrix of which to compute the LDL^T Cholesky decomposition + * \tparam _UpLo the triangular part that will be used for the decompositon: Lower (default) or Upper. * The other triangular part won't be read. * * Perform a robust Cholesky decomposition of a positive semidefinite or negative semidefinite @@ -43,7 +43,9 @@ namespace internal { * Remember that Cholesky decompositions are not rank-revealing. Also, do not use a Cholesky * decomposition to determine whether a system of equations has a solution. * - * \sa MatrixBase::ldlt(), class LLT + * This class supports the \link InplaceDecomposition inplace decomposition \endlink mechanism. + * + * \sa MatrixBase::ldlt(), SelfAdjointView::ldlt(), class LLT */ template class LDLT { @@ -52,15 +54,15 @@ template class LDLT enum { RowsAtCompileTime = MatrixType::RowsAtCompileTime, ColsAtCompileTime = MatrixType::ColsAtCompileTime, - Options = MatrixType::Options & ~RowMajorBit, // these are the options for the TmpMatrixType, we need a ColMajor matrix here! MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime, MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime, UpLo = _UpLo }; typedef typename MatrixType::Scalar Scalar; typedef typename NumTraits::Real RealScalar; - typedef typename MatrixType::Index Index; - typedef Matrix TmpMatrixType; + typedef Eigen::Index Index; ///< \deprecated since Eigen 3.3 + typedef typename MatrixType::StorageIndex StorageIndex; + typedef Matrix TmpMatrixType; typedef Transpositions TranspositionType; typedef PermutationMatrix PermutationType; @@ -72,11 +74,11 @@ template class LDLT * The default constructor is useful in cases in which the user intends to * perform decompositions via LDLT::compute(const MatrixType&). */ - LDLT() - : m_matrix(), - m_transpositions(), + LDLT() + : m_matrix(), + m_transpositions(), m_sign(internal::ZeroSign), - m_isInitialized(false) + m_isInitialized(false) {} /** \brief Default Constructor with memory preallocation @@ -85,7 +87,7 @@ template class LDLT * according to the specified problem \a size. * \sa LDLT() */ - LDLT(Index size) + explicit LDLT(Index size) : m_matrix(size, size), m_transpositions(size), m_temporary(size), @@ -96,16 +98,35 @@ template class LDLT /** \brief Constructor with decomposition * * This calculates the decomposition for the input \a matrix. + * * \sa LDLT(Index size) */ - LDLT(const MatrixType& matrix) + template + explicit LDLT(const EigenBase& matrix) : m_matrix(matrix.rows(), matrix.cols()), m_transpositions(matrix.rows()), m_temporary(matrix.rows()), m_sign(internal::ZeroSign), m_isInitialized(false) { - compute(matrix); + compute(matrix.derived()); + } + + /** \brief Constructs a LDLT factorization from a given matrix + * + * This overloaded constructor is provided for \link InplaceDecomposition inplace decomposition \endlink when \c MatrixType is a Eigen::Ref. + * + * \sa LDLT(const EigenBase&) + */ + template + explicit LDLT(EigenBase& matrix) + : m_matrix(matrix.derived()), + m_transpositions(matrix.rows()), + m_temporary(matrix.rows()), + m_sign(internal::ZeroSign), + m_isInitialized(false) + { + compute(matrix.derived()); } /** Clear any existing decomposition @@ -151,13 +172,6 @@ template class LDLT eigen_assert(m_isInitialized && "LDLT is not initialized."); return m_sign == internal::PositiveSemiDef || m_sign == internal::ZeroSign; } - - #ifdef EIGEN2_SUPPORT - inline bool isPositiveDefinite() const - { - return isPositive(); - } - #endif /** \returns true if the matrix is negative (semidefinite) */ inline bool isNegative(void) const @@ -173,37 +187,38 @@ template class LDLT * \note_about_checking_solutions * * More precisely, this method solves \f$ A x = b \f$ using the decomposition \f$ A = P^T L D L^* P \f$ - * by solving the systems \f$ P^T y_1 = b \f$, \f$ L y_2 = y_1 \f$, \f$ D y_3 = y_2 \f$, + * by solving the systems \f$ P^T y_1 = b \f$, \f$ L y_2 = y_1 \f$, \f$ D y_3 = y_2 \f$, * \f$ L^* y_4 = y_3 \f$ and \f$ P x = y_4 \f$ in succession. If the matrix \f$ A \f$ is singular, then * \f$ D \f$ will also be singular (all the other matrices are invertible). In that case, the * least-square solution of \f$ D y_3 = y_2 \f$ is computed. This does not mean that this function * computes the least-square solution of \f$ A x = b \f$ is \f$ A \f$ is singular. * - * \sa MatrixBase::ldlt() + * \sa MatrixBase::ldlt(), SelfAdjointView::ldlt() */ template - inline const internal::solve_retval + inline const Solve solve(const MatrixBase& b) const { eigen_assert(m_isInitialized && "LDLT is not initialized."); eigen_assert(m_matrix.rows()==b.rows() && "LDLT::solve(): invalid number of rows of the right hand side matrix b"); - return internal::solve_retval(*this, b.derived()); + return Solve(*this, b.derived()); } - #ifdef EIGEN2_SUPPORT - template - bool solve(const MatrixBase& b, ResultType *result) const - { - *result = this->solve(b); - return true; - } - #endif - template bool solveInPlace(MatrixBase &bAndX) const; - LDLT& compute(const MatrixType& matrix); + template + LDLT& compute(const EigenBase& matrix); + + /** \returns an estimate of the reciprocal condition number of the matrix of + * which \c *this is the LDLT decomposition. + */ + RealScalar rcond() const + { + eigen_assert(m_isInitialized && "LDLT is not initialized."); + return internal::rcond_estimate_helper(m_l1_norm, *this); + } template LDLT& rankUpdate(const MatrixBase& w, const RealScalar& alpha=1); @@ -220,6 +235,13 @@ template class LDLT MatrixType reconstructedMatrix() const; + /** \returns the adjoint of \c *this, that is, a const reference to the decomposition itself as the underlying matrix is self-adjoint. + * + * This method is provided for compatibility with other matrix decompositions, thus enabling generic code such as: + * \code x = decomposition.adjoint().solve(b) \endcode + */ + const LDLT& adjoint() const { return *this; }; + inline Index rows() const { return m_matrix.rows(); } inline Index cols() const { return m_matrix.cols(); } @@ -231,11 +253,17 @@ template class LDLT ComputationInfo info() const { eigen_assert(m_isInitialized && "LDLT is not initialized."); - return Success; + return m_info; } + #ifndef EIGEN_PARSED_BY_DOXYGEN + template + EIGEN_DEVICE_FUNC + void _solve_impl(const RhsType &rhs, DstType &dst) const; + #endif + protected: - + static void check_template_parameters() { EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar); @@ -248,10 +276,12 @@ template class LDLT * is not stored), and the diagonal entries correspond to D. */ MatrixType m_matrix; + RealScalar m_l1_norm; TranspositionType m_transpositions; TmpMatrixType m_temporary; internal::SignMatrix m_sign; bool m_isInitialized; + ComputationInfo m_info; }; namespace internal { @@ -266,15 +296,17 @@ template<> struct ldlt_inplace using std::abs; typedef typename MatrixType::Scalar Scalar; typedef typename MatrixType::RealScalar RealScalar; - typedef typename MatrixType::Index Index; + typedef typename TranspositionType::StorageIndex IndexType; eigen_assert(mat.rows()==mat.cols()); const Index size = mat.rows(); + bool found_zero_pivot = false; + bool ret = true; if (size <= 1) { transpositions.setIdentity(); - if (numext::real(mat.coeff(0,0)) > 0) sign = PositiveSemiDef; - else if (numext::real(mat.coeff(0,0)) < 0) sign = NegativeSemiDef; + if (numext::real(mat.coeff(0,0)) > static_cast(0) ) sign = PositiveSemiDef; + else if (numext::real(mat.coeff(0,0)) < static_cast(0)) sign = NegativeSemiDef; else sign = ZeroSign; return true; } @@ -286,7 +318,7 @@ template<> struct ldlt_inplace mat.diagonal().tail(size-k).cwiseAbs().maxCoeff(&index_of_biggest_in_corner); index_of_biggest_in_corner += k; - transpositions.coeffRef(k) = index_of_biggest_in_corner; + transpositions.coeffRef(k) = IndexType(index_of_biggest_in_corner); if(k != index_of_biggest_in_corner) { // apply the transposition while taking care to consider only @@ -295,7 +327,7 @@ template<> struct ldlt_inplace mat.row(k).head(k).swap(mat.row(index_of_biggest_in_corner).head(k)); mat.col(k).tail(s).swap(mat.col(index_of_biggest_in_corner).tail(s)); std::swap(mat.coeffRef(k,k),mat.coeffRef(index_of_biggest_in_corner,index_of_biggest_in_corner)); - for(int i=k+1;i struct ldlt_inplace if(rs>0) A21.noalias() -= A20 * temp.head(k); } - + // In some previous versions of Eigen (e.g., 3.2.1), the scaling was omitted if the pivot - // was smaller than the cutoff value. However, soince LDLT is not rank-revealing - // we should only make sure we do not introduce INF or NaN values. - // LAPACK also uses 0 as the cutoff value. + // was smaller than the cutoff value. However, since LDLT is not rank-revealing + // we should only make sure that we do not introduce INF or NaN values. + // Remark that LAPACK also uses 0 as the cutoff value. RealScalar realAkk = numext::real(mat.coeffRef(k,k)); - if((rs>0) && (abs(realAkk) > RealScalar(0))) + bool pivot_is_valid = (abs(realAkk) > RealScalar(0)); + + if(k==0 && !pivot_is_valid) + { + // The entire diagonal is zero, there is nothing more to do + // except filling the transpositions, and checking whether the matrix is zero. + sign = ZeroSign; + for(Index j = 0; j0) && pivot_is_valid) A21 /= realAkk; + if(found_zero_pivot && pivot_is_valid) ret = false; // factorization failed + else if(!pivot_is_valid) found_zero_pivot = true; + if (sign == PositiveSemiDef) { - if (realAkk < 0) sign = Indefinite; + if (realAkk < static_cast(0)) sign = Indefinite; } else if (sign == NegativeSemiDef) { - if (realAkk > 0) sign = Indefinite; + if (realAkk > static_cast(0)) sign = Indefinite; } else if (sign == ZeroSign) { - if (realAkk > 0) sign = PositiveSemiDef; - else if (realAkk < 0) sign = NegativeSemiDef; + if (realAkk > static_cast(0)) sign = PositiveSemiDef; + else if (realAkk < static_cast(0)) sign = NegativeSemiDef; } } - return true; + return ret; } // Reference for the algorithm: Davis and Hager, "Multiple Rank @@ -356,7 +406,6 @@ template<> struct ldlt_inplace using numext::isfinite; typedef typename MatrixType::Scalar Scalar; typedef typename MatrixType::RealScalar RealScalar; - typedef typename MatrixType::Index Index; const Index size = mat.rows(); eigen_assert(mat.cols() == size && w.size()==size); @@ -420,16 +469,16 @@ template struct LDLT_Traits { typedef const TriangularView MatrixL; typedef const TriangularView MatrixU; - static inline MatrixL getL(const MatrixType& m) { return m; } - static inline MatrixU getU(const MatrixType& m) { return m.adjoint(); } + static inline MatrixL getL(const MatrixType& m) { return MatrixL(m); } + static inline MatrixU getU(const MatrixType& m) { return MatrixU(m.adjoint()); } }; template struct LDLT_Traits { typedef const TriangularView MatrixL; typedef const TriangularView MatrixU; - static inline MatrixL getL(const MatrixType& m) { return m.adjoint(); } - static inline MatrixU getU(const MatrixType& m) { return m; } + static inline MatrixL getL(const MatrixType& m) { return MatrixL(m.adjoint()); } + static inline MatrixU getU(const MatrixType& m) { return MatrixU(m); } }; } // end namespace internal @@ -437,21 +486,35 @@ template struct LDLT_Traits /** Compute / recompute the LDLT decomposition A = L D L^* = U^* D U of \a matrix */ template -LDLT& LDLT::compute(const MatrixType& a) +template +LDLT& LDLT::compute(const EigenBase& a) { check_template_parameters(); - + eigen_assert(a.rows()==a.cols()); const Index size = a.rows(); - m_matrix = a; + m_matrix = a.derived(); + + // Compute matrix L1 norm = max abs column sum. + m_l1_norm = RealScalar(0); + // TODO move this code to SelfAdjointView + for (Index col = 0; col < size; ++col) { + RealScalar abs_col_sum; + if (_UpLo == Lower) + abs_col_sum = m_matrix.col(col).tail(size - col).template lpNorm<1>() + m_matrix.row(col).head(col).template lpNorm<1>(); + else + abs_col_sum = m_matrix.col(col).head(col).template lpNorm<1>() + m_matrix.row(col).tail(size - col).template lpNorm<1>(); + if (abs_col_sum > m_l1_norm) + m_l1_norm = abs_col_sum; + } m_transpositions.resize(size); m_isInitialized = false; m_temporary.resize(size); m_sign = internal::ZeroSign; - internal::ldlt_inplace::unblocked(m_matrix, m_transpositions, m_temporary, m_sign); + m_info = internal::ldlt_inplace::unblocked(m_matrix, m_transpositions, m_temporary, m_sign) ? Success : NumericalIssue; m_isInitialized = true; return *this; @@ -466,18 +529,19 @@ template template LDLT& LDLT::rankUpdate(const MatrixBase& w, const typename LDLT::RealScalar& sigma) { + typedef typename TranspositionType::StorageIndex IndexType; const Index size = w.rows(); if (m_isInitialized) { eigen_assert(m_matrix.rows()==size); } else - { + { m_matrix.resize(size,size); m_matrix.setZero(); m_transpositions.resize(size); for (Index i = 0; i < size; i++) - m_transpositions.coeffRef(i) = i; + m_transpositions.coeffRef(i) = IndexType(i); m_temporary.resize(size); m_sign = sigma>=0 ? internal::PositiveSemiDef : internal::NegativeSemiDef; m_isInitialized = true; @@ -488,53 +552,45 @@ LDLT& LDLT::rankUpdate(const MatrixBase -struct solve_retval, Rhs> - : solve_retval_base, Rhs> +#ifndef EIGEN_PARSED_BY_DOXYGEN +template +template +void LDLT<_MatrixType,_UpLo>::_solve_impl(const RhsType &rhs, DstType &dst) const { - typedef LDLT<_MatrixType,_UpLo> LDLTType; - EIGEN_MAKE_SOLVE_HELPERS(LDLTType,Rhs) - - template void evalTo(Dest& dst) const + eigen_assert(rhs.rows() == rows()); + // dst = P b + dst = m_transpositions * rhs; + + // dst = L^-1 (P b) + matrixL().solveInPlace(dst); + + // dst = D^-1 (L^-1 P b) + // more precisely, use pseudo-inverse of D (see bug 241) + using std::abs; + const typename Diagonal::RealReturnType vecD(vectorD()); + // In some previous versions, tolerance was set to the max of 1/highest and the maximal diagonal entry * epsilon + // as motivated by LAPACK's xGELSS: + // RealScalar tolerance = numext::maxi(vecD.array().abs().maxCoeff() * NumTraits::epsilon(),RealScalar(1) / NumTraits::highest()); + // However, LDLT is not rank revealing, and so adjusting the tolerance wrt to the highest + // diagonal element is not well justified and leads to numerical issues in some cases. + // Moreover, Lapack's xSYTRS routines use 0 for the tolerance. + RealScalar tolerance = RealScalar(1) / NumTraits::highest(); + + for (Index i = 0; i < vecD.size(); ++i) { - eigen_assert(rhs().rows() == dec().matrixLDLT().rows()); - // dst = P b - dst = dec().transpositionsP() * rhs(); - - // dst = L^-1 (P b) - dec().matrixL().solveInPlace(dst); - - // dst = D^-1 (L^-1 P b) - // more precisely, use pseudo-inverse of D (see bug 241) - using std::abs; - using std::max; - typedef typename LDLTType::MatrixType MatrixType; - typedef typename LDLTType::RealScalar RealScalar; - const typename Diagonal::RealReturnType vectorD(dec().vectorD()); - // In some previous versions, tolerance was set to the max of 1/highest and the maximal diagonal entry * epsilon - // as motivated by LAPACK's xGELSS: - // RealScalar tolerance = (max)(vectorD.array().abs().maxCoeff() *NumTraits::epsilon(),RealScalar(1) / NumTraits::highest()); - // However, LDLT is not rank revealing, and so adjusting the tolerance wrt to the highest - // diagonal element is not well justified and to numerical issues in some cases. - // Moreover, Lapack's xSYTRS routines use 0 for the tolerance. - RealScalar tolerance = RealScalar(1) / NumTraits::highest(); - - for (Index i = 0; i < vectorD.size(); ++i) { - if(abs(vectorD(i)) > tolerance) - dst.row(i) /= vectorD(i); - else - dst.row(i).setZero(); - } + if(abs(vecD(i)) > tolerance) + dst.row(i) /= vecD(i); + else + dst.row(i).setZero(); + } - // dst = L^-T (D^-1 L^-1 P b) - dec().matrixU().solveInPlace(dst); + // dst = L^-T (D^-1 L^-1 P b) + matrixU().solveInPlace(dst); - // dst = P^-1 (L^-T D^-1 L^-1 P b) = A^-1 b - dst = dec().transpositionsP().transpose() * dst; - } -}; + // dst = P^-1 (L^-T D^-1 L^-1 P b) = A^-1 b + dst = m_transpositions.transpose() * dst; } +#endif /** \internal use x = ldlt_object.solve(x); * @@ -588,6 +644,7 @@ MatrixType LDLT::reconstructedMatrix() const /** \cholesky_module * \returns the Cholesky decomposition with full pivoting without square root of \c *this + * \sa MatrixBase::ldlt() */ template inline const LDLT::PlainObject, UpLo> @@ -598,6 +655,7 @@ SelfAdjointView::ldlt() const /** \cholesky_module * \returns the Cholesky decomposition with full pivoting without square root of \c *this + * \sa SelfAdjointView::ldlt() */ template inline const LDLT::PlainObject> diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Cholesky/LLT.h b/ground/gcs/src/libs/eigen/Eigen/src/Cholesky/LLT.h index 7c11a2dc29..87ca8d4236 100644 --- a/ground/gcs/src/libs/eigen/Eigen/src/Cholesky/LLT.h +++ b/ground/gcs/src/libs/eigen/Eigen/src/Cholesky/LLT.h @@ -10,7 +10,7 @@ #ifndef EIGEN_LLT_H #define EIGEN_LLT_H -namespace Eigen { +namespace Eigen { namespace internal{ template struct LLT_Traits; @@ -22,8 +22,8 @@ template struct LLT_Traits; * * \brief Standard Cholesky decomposition (LL^T) of a matrix and associated features * - * \param MatrixType the type of the matrix of which we are computing the LL^T Cholesky decomposition - * \param UpLo the triangular part that will be used for the decompositon: Lower (default) or Upper. + * \tparam _MatrixType the type of the matrix of which we are computing the LL^T Cholesky decomposition + * \tparam _UpLo the triangular part that will be used for the decompositon: Lower (default) or Upper. * The other triangular part won't be read. * * This class performs a LL^T Cholesky decomposition of a symmetric, positive definite @@ -40,8 +40,10 @@ template struct LLT_Traits; * * Example: \include LLT_example.cpp * Output: \verbinclude LLT_example.out - * - * \sa MatrixBase::llt(), class LDLT + * + * This class supports the \link InplaceDecomposition inplace decomposition \endlink mechanism. + * + * \sa MatrixBase::llt(), SelfAdjointView::llt(), class LDLT */ /* HEY THIS DOX IS DISABLED BECAUSE THERE's A BUG EITHER HERE OR IN LDLT ABOUT THAT (OR BOTH) * Note that during the decomposition, only the upper triangular part of A is considered. Therefore, @@ -54,12 +56,12 @@ template class LLT enum { RowsAtCompileTime = MatrixType::RowsAtCompileTime, ColsAtCompileTime = MatrixType::ColsAtCompileTime, - Options = MatrixType::Options, MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime }; typedef typename MatrixType::Scalar Scalar; typedef typename NumTraits::Real RealScalar; - typedef typename MatrixType::Index Index; + typedef Eigen::Index Index; ///< \deprecated since Eigen 3.3 + typedef typename MatrixType::StorageIndex StorageIndex; enum { PacketSize = internal::packet_traits::size, @@ -83,14 +85,30 @@ template class LLT * according to the specified problem \a size. * \sa LLT() */ - LLT(Index size) : m_matrix(size, size), + explicit LLT(Index size) : m_matrix(size, size), m_isInitialized(false) {} - LLT(const MatrixType& matrix) + template + explicit LLT(const EigenBase& matrix) : m_matrix(matrix.rows(), matrix.cols()), m_isInitialized(false) { - compute(matrix); + compute(matrix.derived()); + } + + /** \brief Constructs a LDLT factorization from a given matrix + * + * This overloaded constructor is provided for \link InplaceDecomposition inplace decomposition \endlink when + * \c MatrixType is a Eigen::Ref. + * + * \sa LLT(const EigenBase&) + */ + template + explicit LLT(EigenBase& matrix) + : m_matrix(matrix.derived()), + m_isInitialized(false) + { + compute(matrix.derived()); } /** \returns a view of the upper triangular matrix U */ @@ -115,33 +133,33 @@ template class LLT * Example: \include LLT_solve.cpp * Output: \verbinclude LLT_solve.out * - * \sa solveInPlace(), MatrixBase::llt() + * \sa solveInPlace(), MatrixBase::llt(), SelfAdjointView::llt() */ template - inline const internal::solve_retval + inline const Solve solve(const MatrixBase& b) const { eigen_assert(m_isInitialized && "LLT is not initialized."); eigen_assert(m_matrix.rows()==b.rows() && "LLT::solve(): invalid number of rows of the right hand side matrix b"); - return internal::solve_retval(*this, b.derived()); + return Solve(*this, b.derived()); } - #ifdef EIGEN2_SUPPORT - template - bool solve(const MatrixBase& b, ResultType *result) const - { - *result = this->solve(b); - return true; - } - - bool isPositiveDefinite() const { return true; } - #endif - template void solveInPlace(MatrixBase &bAndX) const; - LLT& compute(const MatrixType& matrix); + template + LLT& compute(const EigenBase& matrix); + + /** \returns an estimate of the reciprocal condition number of the matrix of + * which \c *this is the Cholesky decomposition. + */ + RealScalar rcond() const + { + eigen_assert(m_isInitialized && "LLT is not initialized."); + eigen_assert(m_info == Success && "LLT failed because matrix appears to be negative"); + return internal::rcond_estimate_helper(m_l1_norm, *this); + } /** \returns the LLT decomposition matrix * @@ -167,24 +185,38 @@ template class LLT return m_info; } + /** \returns the adjoint of \c *this, that is, a const reference to the decomposition itself as the underlying matrix is self-adjoint. + * + * This method is provided for compatibility with other matrix decompositions, thus enabling generic code such as: + * \code x = decomposition.adjoint().solve(b) \endcode + */ + const LLT& adjoint() const { return *this; }; + inline Index rows() const { return m_matrix.rows(); } inline Index cols() const { return m_matrix.cols(); } template LLT rankUpdate(const VectorType& vec, const RealScalar& sigma = 1); + #ifndef EIGEN_PARSED_BY_DOXYGEN + template + EIGEN_DEVICE_FUNC + void _solve_impl(const RhsType &rhs, DstType &dst) const; + #endif + protected: - + static void check_template_parameters() { EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar); } - + /** \internal * Used to compute and store L * The strict upper part is not used and even not initialized. */ MatrixType m_matrix; + RealScalar m_l1_norm; bool m_isInitialized; ComputationInfo m_info; }; @@ -194,12 +226,11 @@ namespace internal { template struct llt_inplace; template -static typename MatrixType::Index llt_rank_update_lower(MatrixType& mat, const VectorType& vec, const typename MatrixType::RealScalar& sigma) +static Index llt_rank_update_lower(MatrixType& mat, const VectorType& vec, const typename MatrixType::RealScalar& sigma) { using std::sqrt; typedef typename MatrixType::Scalar Scalar; typedef typename MatrixType::RealScalar RealScalar; - typedef typename MatrixType::Index Index; typedef typename MatrixType::ColXpr ColXpr; typedef typename internal::remove_all::type ColXprCleaned; typedef typename ColXprCleaned::SegmentReturnType ColXprSegment; @@ -268,11 +299,10 @@ template struct llt_inplace { typedef typename NumTraits::Real RealScalar; template - static typename MatrixType::Index unblocked(MatrixType& mat) + static Index unblocked(MatrixType& mat) { using std::sqrt; - typedef typename MatrixType::Index Index; - + eigen_assert(mat.rows()==mat.cols()); const Index size = mat.rows(); for(Index k = 0; k < size; ++k) @@ -295,9 +325,8 @@ template struct llt_inplace } template - static typename MatrixType::Index blocked(MatrixType& m) + static Index blocked(MatrixType& m) { - typedef typename MatrixType::Index Index; eigen_assert(m.rows()==m.cols()); Index size = m.rows(); if(size<32) @@ -322,36 +351,36 @@ template struct llt_inplace Index ret; if((ret=unblocked(A11))>=0) return k+ret; if(rs>0) A11.adjoint().template triangularView().template solveInPlace(A21); - if(rs>0) A22.template selfadjointView().rankUpdate(A21,-1); // bottleneck + if(rs>0) A22.template selfadjointView().rankUpdate(A21,typename NumTraits::Literal(-1)); // bottleneck } return -1; } template - static typename MatrixType::Index rankUpdate(MatrixType& mat, const VectorType& vec, const RealScalar& sigma) + static Index rankUpdate(MatrixType& mat, const VectorType& vec, const RealScalar& sigma) { return Eigen::internal::llt_rank_update_lower(mat, vec, sigma); } }; - + template struct llt_inplace { typedef typename NumTraits::Real RealScalar; template - static EIGEN_STRONG_INLINE typename MatrixType::Index unblocked(MatrixType& mat) + static EIGEN_STRONG_INLINE Index unblocked(MatrixType& mat) { Transpose matt(mat); return llt_inplace::unblocked(matt); } template - static EIGEN_STRONG_INLINE typename MatrixType::Index blocked(MatrixType& mat) + static EIGEN_STRONG_INLINE Index blocked(MatrixType& mat) { Transpose matt(mat); return llt_inplace::blocked(matt); } template - static typename MatrixType::Index rankUpdate(MatrixType& mat, const VectorType& vec, const RealScalar& sigma) + static Index rankUpdate(MatrixType& mat, const VectorType& vec, const RealScalar& sigma) { Transpose matt(mat); return llt_inplace::rankUpdate(matt, vec.conjugate(), sigma); @@ -362,8 +391,8 @@ template struct LLT_Traits { typedef const TriangularView MatrixL; typedef const TriangularView MatrixU; - static inline MatrixL getL(const MatrixType& m) { return m; } - static inline MatrixU getU(const MatrixType& m) { return m.adjoint(); } + static inline MatrixL getL(const MatrixType& m) { return MatrixL(m); } + static inline MatrixU getU(const MatrixType& m) { return MatrixU(m.adjoint()); } static bool inplace_decomposition(MatrixType& m) { return llt_inplace::blocked(m)==-1; } }; @@ -372,8 +401,8 @@ template struct LLT_Traits { typedef const TriangularView MatrixL; typedef const TriangularView MatrixU; - static inline MatrixL getL(const MatrixType& m) { return m.adjoint(); } - static inline MatrixU getU(const MatrixType& m) { return m; } + static inline MatrixL getL(const MatrixType& m) { return MatrixL(m.adjoint()); } + static inline MatrixU getU(const MatrixType& m) { return MatrixU(m); } static bool inplace_decomposition(MatrixType& m) { return llt_inplace::blocked(m)==-1; } }; @@ -388,14 +417,28 @@ template struct LLT_Traits * Output: \verbinclude TutorialLinAlgComputeTwice.out */ template -LLT& LLT::compute(const MatrixType& a) +template +LLT& LLT::compute(const EigenBase& a) { check_template_parameters(); - + eigen_assert(a.rows()==a.cols()); const Index size = a.rows(); m_matrix.resize(size, size); - m_matrix = a; + m_matrix = a.derived(); + + // Compute matrix L1 norm = max abs column sum. + m_l1_norm = RealScalar(0); + // TODO move this code to SelfAdjointView + for (Index col = 0; col < size; ++col) { + RealScalar abs_col_sum; + if (_UpLo == Lower) + abs_col_sum = m_matrix.col(col).tail(size - col).template lpNorm<1>() + m_matrix.row(col).head(col).template lpNorm<1>(); + else + abs_col_sum = m_matrix.col(col).head(col).template lpNorm<1>() + m_matrix.row(col).tail(size - col).template lpNorm<1>(); + if (abs_col_sum > m_l1_norm) + m_l1_norm = abs_col_sum; + } m_isInitialized = true; bool ok = Traits::inplace_decomposition(m_matrix); @@ -423,33 +466,24 @@ LLT<_MatrixType,_UpLo> LLT<_MatrixType,_UpLo>::rankUpdate(const VectorType& v, c return *this; } - -namespace internal { -template -struct solve_retval, Rhs> - : solve_retval_base, Rhs> -{ - typedef LLT<_MatrixType,UpLo> LLTType; - EIGEN_MAKE_SOLVE_HELPERS(LLTType,Rhs) - template void evalTo(Dest& dst) const - { - dst = rhs(); - dec().solveInPlace(dst); - } -}; +#ifndef EIGEN_PARSED_BY_DOXYGEN +template +template +void LLT<_MatrixType,_UpLo>::_solve_impl(const RhsType &rhs, DstType &dst) const +{ + dst = rhs; + solveInPlace(dst); } +#endif /** \internal use x = llt_object.solve(x); - * + * * This is the \em in-place version of solve(). * * \param bAndX represents both the right-hand side matrix b and result x. * - * \returns true always! If you need to check for existence of solutions, use another decomposition like LU, QR, or SVD. - * - * This version avoids a copy when the right hand side matrix b is not - * needed anymore. + * This version avoids a copy when the right hand side matrix b is not needed anymore. * * \sa LLT::solve(), MatrixBase::llt() */ @@ -475,6 +509,7 @@ MatrixType LLT::reconstructedMatrix() const /** \cholesky_module * \returns the LLT decomposition of \c *this + * \sa SelfAdjointView::llt() */ template inline const LLT::PlainObject> @@ -485,6 +520,7 @@ MatrixBase::llt() const /** \cholesky_module * \returns the LLT decomposition of \c *this + * \sa SelfAdjointView::llt() */ template inline const LLT::PlainObject, UpLo> diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Cholesky/LLT_MKL.h b/ground/gcs/src/libs/eigen/Eigen/src/Cholesky/LLT_LAPACKE.h similarity index 71% rename from ground/gcs/src/libs/eigen/Eigen/src/Cholesky/LLT_MKL.h rename to ground/gcs/src/libs/eigen/Eigen/src/Cholesky/LLT_LAPACKE.h index 66675d7476..bc6489e69a 100644 --- a/ground/gcs/src/libs/eigen/Eigen/src/Cholesky/LLT_MKL.h +++ b/ground/gcs/src/libs/eigen/Eigen/src/Cholesky/LLT_LAPACKE.h @@ -25,41 +25,38 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ******************************************************************************** - * Content : Eigen bindings to Intel(R) MKL + * Content : Eigen bindings to LAPACKe * LLt decomposition based on LAPACKE_?potrf function. ******************************************************************************** */ -#ifndef EIGEN_LLT_MKL_H -#define EIGEN_LLT_MKL_H - -#include "Eigen/src/Core/util/MKL_support.h" -#include +#ifndef EIGEN_LLT_LAPACKE_H +#define EIGEN_LLT_LAPACKE_H namespace Eigen { namespace internal { -template struct mkl_llt; +template struct lapacke_llt; -#define EIGEN_MKL_LLT(EIGTYPE, MKLTYPE, MKLPREFIX) \ -template<> struct mkl_llt \ +#define EIGEN_LAPACKE_LLT(EIGTYPE, BLASTYPE, LAPACKE_PREFIX) \ +template<> struct lapacke_llt \ { \ template \ - static inline typename MatrixType::Index potrf(MatrixType& m, char uplo) \ + static inline Index potrf(MatrixType& m, char uplo) \ { \ lapack_int matrix_order; \ lapack_int size, lda, info, StorageOrder; \ EIGTYPE* a; \ eigen_assert(m.rows()==m.cols()); \ /* Set up parameters for ?potrf */ \ - size = m.rows(); \ + size = convert_index(m.rows()); \ StorageOrder = MatrixType::Flags&RowMajorBit?RowMajor:ColMajor; \ matrix_order = StorageOrder==RowMajor ? LAPACK_ROW_MAJOR : LAPACK_COL_MAJOR; \ a = &(m.coeffRef(0,0)); \ - lda = m.outerStride(); \ + lda = convert_index(m.outerStride()); \ \ - info = LAPACKE_##MKLPREFIX##potrf( matrix_order, uplo, size, (MKLTYPE*)a, lda ); \ + info = LAPACKE_##LAPACKE_PREFIX##potrf( matrix_order, uplo, size, (BLASTYPE*)a, lda ); \ info = (info==0) ? -1 : info>0 ? info-1 : size; \ return info; \ } \ @@ -67,36 +64,36 @@ template<> struct mkl_llt \ template<> struct llt_inplace \ { \ template \ - static typename MatrixType::Index blocked(MatrixType& m) \ + static Index blocked(MatrixType& m) \ { \ - return mkl_llt::potrf(m, 'L'); \ + return lapacke_llt::potrf(m, 'L'); \ } \ template \ - static typename MatrixType::Index rankUpdate(MatrixType& mat, const VectorType& vec, const typename MatrixType::RealScalar& sigma) \ + static Index rankUpdate(MatrixType& mat, const VectorType& vec, const typename MatrixType::RealScalar& sigma) \ { return Eigen::internal::llt_rank_update_lower(mat, vec, sigma); } \ }; \ template<> struct llt_inplace \ { \ template \ - static typename MatrixType::Index blocked(MatrixType& m) \ + static Index blocked(MatrixType& m) \ { \ - return mkl_llt::potrf(m, 'U'); \ + return lapacke_llt::potrf(m, 'U'); \ } \ template \ - static typename MatrixType::Index rankUpdate(MatrixType& mat, const VectorType& vec, const typename MatrixType::RealScalar& sigma) \ + static Index rankUpdate(MatrixType& mat, const VectorType& vec, const typename MatrixType::RealScalar& sigma) \ { \ Transpose matt(mat); \ return llt_inplace::rankUpdate(matt, vec.conjugate(), sigma); \ } \ }; -EIGEN_MKL_LLT(double, double, d) -EIGEN_MKL_LLT(float, float, s) -EIGEN_MKL_LLT(dcomplex, MKL_Complex16, z) -EIGEN_MKL_LLT(scomplex, MKL_Complex8, c) +EIGEN_LAPACKE_LLT(double, double, d) +EIGEN_LAPACKE_LLT(float, float, s) +EIGEN_LAPACKE_LLT(dcomplex, lapack_complex_double, z) +EIGEN_LAPACKE_LLT(scomplex, lapack_complex_float, c) } // end namespace internal } // end namespace Eigen -#endif // EIGEN_LLT_MKL_H +#endif // EIGEN_LLT_LAPACKE_H diff --git a/ground/gcs/src/libs/eigen/Eigen/src/CholmodSupport/CMakeLists.txt b/ground/gcs/src/libs/eigen/Eigen/src/CholmodSupport/CMakeLists.txt deleted file mode 100644 index 814dfa6131..0000000000 --- a/ground/gcs/src/libs/eigen/Eigen/src/CholmodSupport/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -FILE(GLOB Eigen_CholmodSupport_SRCS "*.h") - -INSTALL(FILES - ${Eigen_CholmodSupport_SRCS} - DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/CholmodSupport COMPONENT Devel - ) diff --git a/ground/gcs/src/libs/eigen/Eigen/src/CholmodSupport/CholmodSupport.h b/ground/gcs/src/libs/eigen/Eigen/src/CholmodSupport/CholmodSupport.h index 99dbe171c3..5719720238 100644 --- a/ground/gcs/src/libs/eigen/Eigen/src/CholmodSupport/CholmodSupport.h +++ b/ground/gcs/src/libs/eigen/Eigen/src/CholmodSupport/CholmodSupport.h @@ -14,46 +14,52 @@ namespace Eigen { namespace internal { -template -void cholmod_configure_matrix(CholmodType& mat) -{ - if (internal::is_same::value) - { - mat.xtype = CHOLMOD_REAL; - mat.dtype = CHOLMOD_SINGLE; - } - else if (internal::is_same::value) - { +template struct cholmod_configure_matrix; + +template<> struct cholmod_configure_matrix { + template + static void run(CholmodType& mat) { mat.xtype = CHOLMOD_REAL; mat.dtype = CHOLMOD_DOUBLE; } - else if (internal::is_same >::value) - { - mat.xtype = CHOLMOD_COMPLEX; - mat.dtype = CHOLMOD_SINGLE; - } - else if (internal::is_same >::value) - { +}; + +template<> struct cholmod_configure_matrix > { + template + static void run(CholmodType& mat) { mat.xtype = CHOLMOD_COMPLEX; mat.dtype = CHOLMOD_DOUBLE; } - else - { - eigen_assert(false && "Scalar type not supported by CHOLMOD"); - } -} +}; + +// Other scalar types are not yet suppotred by Cholmod +// template<> struct cholmod_configure_matrix { +// template +// static void run(CholmodType& mat) { +// mat.xtype = CHOLMOD_REAL; +// mat.dtype = CHOLMOD_SINGLE; +// } +// }; +// +// template<> struct cholmod_configure_matrix > { +// template +// static void run(CholmodType& mat) { +// mat.xtype = CHOLMOD_COMPLEX; +// mat.dtype = CHOLMOD_SINGLE; +// } +// }; } // namespace internal /** Wraps the Eigen sparse matrix \a mat into a Cholmod sparse matrix object. * Note that the data are shared. */ -template -cholmod_sparse viewAsCholmod(SparseMatrix<_Scalar,_Options,_Index>& mat) +template +cholmod_sparse viewAsCholmod(Ref > mat) { cholmod_sparse res; res.nzmax = mat.nonZeros(); - res.nrow = mat.rows();; + res.nrow = mat.rows(); res.ncol = mat.cols(); res.p = mat.outerIndexPtr(); res.i = mat.innerIndexPtr(); @@ -74,11 +80,11 @@ cholmod_sparse viewAsCholmod(SparseMatrix<_Scalar,_Options,_Index>& mat) res.dtype = 0; res.stype = -1; - if (internal::is_same<_Index,int>::value) + if (internal::is_same<_StorageIndex,int>::value) { res.itype = CHOLMOD_INT; } - else if (internal::is_same<_Index,SuiteSparse_long>::value) + else if (internal::is_same<_StorageIndex,long>::value) { res.itype = CHOLMOD_LONG; } @@ -88,7 +94,7 @@ cholmod_sparse viewAsCholmod(SparseMatrix<_Scalar,_Options,_Index>& mat) } // setup res.xtype - internal::cholmod_configure_matrix<_Scalar>(res); + internal::cholmod_configure_matrix<_Scalar>::run(res); res.stype = 0; @@ -98,16 +104,23 @@ cholmod_sparse viewAsCholmod(SparseMatrix<_Scalar,_Options,_Index>& mat) template const cholmod_sparse viewAsCholmod(const SparseMatrix<_Scalar,_Options,_Index>& mat) { - cholmod_sparse res = viewAsCholmod(mat.const_cast_derived()); + cholmod_sparse res = viewAsCholmod(Ref >(mat.const_cast_derived())); + return res; +} + +template +const cholmod_sparse viewAsCholmod(const SparseVector<_Scalar,_Options,_Index>& mat) +{ + cholmod_sparse res = viewAsCholmod(Ref >(mat.const_cast_derived())); return res; } /** Returns a view of the Eigen sparse matrix \a mat as Cholmod sparse matrix. * The data are not copied but shared. */ template -cholmod_sparse viewAsCholmod(const SparseSelfAdjointView, UpLo>& mat) +cholmod_sparse viewAsCholmod(const SparseSelfAdjointView, UpLo>& mat) { - cholmod_sparse res = viewAsCholmod(mat.matrix().const_cast_derived()); + cholmod_sparse res = viewAsCholmod(Ref >(mat.matrix().const_cast_derived())); if(UpLo==Upper) res.stype = 1; if(UpLo==Lower) res.stype = -1; @@ -131,19 +144,19 @@ cholmod_dense viewAsCholmod(MatrixBase& mat) res.x = (void*)(mat.derived().data()); res.z = 0; - internal::cholmod_configure_matrix(res); + internal::cholmod_configure_matrix::run(res); return res; } /** Returns a view of the Cholmod sparse matrix \a cm as an Eigen sparse matrix. * The data are not copied but shared. */ -template -MappedSparseMatrix viewAsEigen(cholmod_sparse& cm) +template +MappedSparseMatrix viewAsEigen(cholmod_sparse& cm) { - return MappedSparseMatrix - (cm.nrow, cm.ncol, static_cast(cm.p)[cm.ncol], - static_cast(cm.p), static_cast(cm.i),static_cast(cm.x) ); + return MappedSparseMatrix + (cm.nrow, cm.ncol, static_cast(cm.p)[cm.ncol], + static_cast(cm.p), static_cast(cm.i),static_cast(cm.x) ); } enum CholmodMode { @@ -157,29 +170,39 @@ enum CholmodMode { * \sa class CholmodSupernodalLLT, class CholmodSimplicialLDLT, class CholmodSimplicialLLT */ template -class CholmodBase : internal::noncopyable +class CholmodBase : public SparseSolverBase { + protected: + typedef SparseSolverBase Base; + using Base::derived; + using Base::m_isInitialized; public: typedef _MatrixType MatrixType; enum { UpLo = _UpLo }; typedef typename MatrixType::Scalar Scalar; typedef typename MatrixType::RealScalar RealScalar; typedef MatrixType CholMatrixType; - typedef typename MatrixType::Index Index; + typedef typename MatrixType::StorageIndex StorageIndex; + enum { + ColsAtCompileTime = MatrixType::ColsAtCompileTime, + MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime + }; public: CholmodBase() - : m_cholmodFactor(0), m_info(Success), m_isInitialized(false) + : m_cholmodFactor(0), m_info(Success), m_factorizationIsOk(false), m_analysisIsOk(false) { - m_shiftOffset[0] = m_shiftOffset[1] = RealScalar(0.0); + EIGEN_STATIC_ASSERT((internal::is_same::value), CHOLMOD_SUPPORTS_DOUBLE_PRECISION_ONLY); + m_shiftOffset[0] = m_shiftOffset[1] = 0.0; cholmod_start(&m_cholmod); } - CholmodBase(const MatrixType& matrix) - : m_cholmodFactor(0), m_info(Success), m_isInitialized(false) + explicit CholmodBase(const MatrixType& matrix) + : m_cholmodFactor(0), m_info(Success), m_factorizationIsOk(false), m_analysisIsOk(false) { - m_shiftOffset[0] = m_shiftOffset[1] = RealScalar(0.0); + EIGEN_STATIC_ASSERT((internal::is_same::value), CHOLMOD_SUPPORTS_DOUBLE_PRECISION_ONLY); + m_shiftOffset[0] = m_shiftOffset[1] = 0.0; cholmod_start(&m_cholmod); compute(matrix); } @@ -191,11 +214,8 @@ class CholmodBase : internal::noncopyable cholmod_finish(&m_cholmod); } - inline Index cols() const { return m_cholmodFactor->n; } - inline Index rows() const { return m_cholmodFactor->n; } - - Derived& derived() { return *static_cast(this); } - const Derived& derived() const { return *static_cast(this); } + inline StorageIndex cols() const { return internal::convert_index(m_cholmodFactor->n); } + inline StorageIndex rows() const { return internal::convert_index(m_cholmodFactor->n); } /** \brief Reports whether previous computation was successful. * @@ -216,34 +236,6 @@ class CholmodBase : internal::noncopyable return derived(); } - /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A. - * - * \sa compute() - */ - template - inline const internal::solve_retval - solve(const MatrixBase& b) const - { - eigen_assert(m_isInitialized && "LLT is not initialized."); - eigen_assert(rows()==b.rows() - && "CholmodDecomposition::solve(): invalid number of rows of the right hand side matrix b"); - return internal::solve_retval(*this, b.derived()); - } - - /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A. - * - * \sa compute() - */ - template - inline const internal::sparse_solve_retval - solve(const SparseMatrixBase& b) const - { - eigen_assert(m_isInitialized && "LLT is not initialized."); - eigen_assert(rows()==b.rows() - && "CholmodDecomposition::solve(): invalid number of rows of the right hand side matrix b"); - return internal::sparse_solve_retval(*this, b.derived()); - } - /** Performs a symbolic decomposition on the sparsity pattern of \a matrix. * * This function is particularly useful when solving for several problems having the same structure. @@ -277,7 +269,7 @@ class CholmodBase : internal::noncopyable eigen_assert(m_analysisIsOk && "You must first call analyzePattern()"); cholmod_sparse A = viewAsCholmod(matrix.template selfadjointView()); cholmod_factorize_p(&A, m_shiftOffset, 0, 0, m_cholmodFactor, &m_cholmod); - + // If the factorization failed, minor is the column at which it did. On success minor == n. this->m_info = (m_cholmodFactor->minor == m_cholmodFactor->n ? Success : NumericalIssue); m_factorizationIsOk = true; @@ -290,20 +282,22 @@ class CholmodBase : internal::noncopyable #ifndef EIGEN_PARSED_BY_DOXYGEN /** \internal */ template - void _solve(const MatrixBase &b, MatrixBase &dest) const + void _solve_impl(const MatrixBase &b, MatrixBase &dest) const { eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or symbolic()/numeric()"); const Index size = m_cholmodFactor->n; EIGEN_UNUSED_VARIABLE(size); eigen_assert(size==b.rows()); + + // Cholmod needs column-major stoarge without inner-stride, which corresponds to the default behavior of Ref. + Ref > b_ref(b.derived()); - // note: cd stands for Cholmod Dense - Rhs& b_ref(b.const_cast_derived()); cholmod_dense b_cd = viewAsCholmod(b_ref); cholmod_dense* x_cd = cholmod_solve(CHOLMOD_A, m_cholmodFactor, &b_cd, &m_cholmod); if(!x_cd) { this->m_info = NumericalIssue; + return; } // TODO optimize this copy by swapping when possible (be careful with alignment, etc.) dest = Matrix::Map(reinterpret_cast(x_cd->x),b.rows(),b.cols()); @@ -311,8 +305,8 @@ class CholmodBase : internal::noncopyable } /** \internal */ - template - void _solve(const SparseMatrix &b, SparseMatrix &dest) const + template + void _solve_impl(const SparseMatrixBase &b, SparseMatrixBase &dest) const { eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or symbolic()/numeric()"); const Index size = m_cholmodFactor->n; @@ -320,14 +314,16 @@ class CholmodBase : internal::noncopyable eigen_assert(size==b.rows()); // note: cs stands for Cholmod Sparse - cholmod_sparse b_cs = viewAsCholmod(b); + Ref > b_ref(b.const_cast_derived()); + cholmod_sparse b_cs = viewAsCholmod(b_ref); cholmod_sparse* x_cs = cholmod_spsolve(CHOLMOD_A, m_cholmodFactor, &b_cs, &m_cholmod); if(!x_cs) { this->m_info = NumericalIssue; + return; } // TODO optimize this copy by swapping when possible (be careful with alignment, etc.) - dest = viewAsEigen(*x_cs); + dest.derived() = viewAsEigen(*x_cs); cholmod_free_sparse(&x_cs, &m_cholmod); } #endif // EIGEN_PARSED_BY_DOXYGEN @@ -344,10 +340,61 @@ class CholmodBase : internal::noncopyable */ Derived& setShift(const RealScalar& offset) { - m_shiftOffset[0] = offset; + m_shiftOffset[0] = double(offset); return derived(); } + /** \returns the determinant of the underlying matrix from the current factorization */ + Scalar determinant() const + { + using std::exp; + return exp(logDeterminant()); + } + + /** \returns the log determinant of the underlying matrix from the current factorization */ + Scalar logDeterminant() const + { + using std::log; + using numext::real; + eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or symbolic()/numeric()"); + + RealScalar logDet = 0; + Scalar *x = static_cast(m_cholmodFactor->x); + if (m_cholmodFactor->is_super) + { + // Supernodal factorization stored as a packed list of dense column-major blocs, + // as described by the following structure: + + // super[k] == index of the first column of the j-th super node + StorageIndex *super = static_cast(m_cholmodFactor->super); + // pi[k] == offset to the description of row indices + StorageIndex *pi = static_cast(m_cholmodFactor->pi); + // px[k] == offset to the respective dense block + StorageIndex *px = static_cast(m_cholmodFactor->px); + + Index nb_super_nodes = m_cholmodFactor->nsuper; + for (Index k=0; k < nb_super_nodes; ++k) + { + StorageIndex ncols = super[k + 1] - super[k]; + StorageIndex nrows = pi[k + 1] - pi[k]; + + Map, 0, InnerStride<> > sk(x + px[k], ncols, InnerStride<>(nrows+1)); + logDet += sk.real().log().sum(); + } + } + else + { + // Simplicial factorization stored as standard CSC matrix. + StorageIndex *p = static_cast(m_cholmodFactor->p); + Index size = m_cholmodFactor->n; + for (Index k=0; kis_ll) + logDet *= 2.0; + return logDet; + }; + template void dumpMemory(Stream& /*s*/) {} @@ -355,9 +402,8 @@ class CholmodBase : internal::noncopyable protected: mutable cholmod_common m_cholmod; cholmod_factor* m_cholmodFactor; - RealScalar m_shiftOffset[2]; + double m_shiftOffset[2]; mutable ComputationInfo m_info; - bool m_isInitialized; int m_factorizationIsOk; int m_analysisIsOk; }; @@ -376,9 +422,13 @@ class CholmodBase : internal::noncopyable * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower * or Upper. Default is Lower. * + * \implsparsesolverconcept + * * This class supports all kind of SparseMatrix<>: row or column major; upper, lower, or both; compressed or non compressed. * - * \sa \ref TutorialSparseDirectSolvers, class CholmodSupernodalLLT, class SimplicialLLT + * \warning Only double precision real and complex scalar types are supported by Cholmod. + * + * \sa \ref TutorialSparseSolverConcept, class CholmodSupernodalLLT, class SimplicialLLT */ template class CholmodSimplicialLLT : public CholmodBase<_MatrixType, _UpLo, CholmodSimplicialLLT<_MatrixType, _UpLo> > @@ -395,7 +445,7 @@ class CholmodSimplicialLLT : public CholmodBase<_MatrixType, _UpLo, CholmodSimpl CholmodSimplicialLLT(const MatrixType& matrix) : Base() { init(); - Base::compute(matrix); + this->compute(matrix); } ~CholmodSimplicialLLT() {} @@ -423,9 +473,13 @@ class CholmodSimplicialLLT : public CholmodBase<_MatrixType, _UpLo, CholmodSimpl * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower * or Upper. Default is Lower. * + * \implsparsesolverconcept + * * This class supports all kind of SparseMatrix<>: row or column major; upper, lower, or both; compressed or non compressed. * - * \sa \ref TutorialSparseDirectSolvers, class CholmodSupernodalLLT, class SimplicialLDLT + * \warning Only double precision real and complex scalar types are supported by Cholmod. + * + * \sa \ref TutorialSparseSolverConcept, class CholmodSupernodalLLT, class SimplicialLDLT */ template class CholmodSimplicialLDLT : public CholmodBase<_MatrixType, _UpLo, CholmodSimplicialLDLT<_MatrixType, _UpLo> > @@ -442,7 +496,7 @@ class CholmodSimplicialLDLT : public CholmodBase<_MatrixType, _UpLo, CholmodSimp CholmodSimplicialLDLT(const MatrixType& matrix) : Base() { init(); - Base::compute(matrix); + this->compute(matrix); } ~CholmodSimplicialLDLT() {} @@ -468,9 +522,13 @@ class CholmodSimplicialLDLT : public CholmodBase<_MatrixType, _UpLo, CholmodSimp * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower * or Upper. Default is Lower. * + * \implsparsesolverconcept + * * This class supports all kind of SparseMatrix<>: row or column major; upper, lower, or both; compressed or non compressed. * - * \sa \ref TutorialSparseDirectSolvers + * \warning Only double precision real and complex scalar types are supported by Cholmod. + * + * \sa \ref TutorialSparseSolverConcept */ template class CholmodSupernodalLLT : public CholmodBase<_MatrixType, _UpLo, CholmodSupernodalLLT<_MatrixType, _UpLo> > @@ -487,7 +545,7 @@ class CholmodSupernodalLLT : public CholmodBase<_MatrixType, _UpLo, CholmodSuper CholmodSupernodalLLT(const MatrixType& matrix) : Base() { init(); - Base::compute(matrix); + this->compute(matrix); } ~CholmodSupernodalLLT() {} @@ -515,9 +573,13 @@ class CholmodSupernodalLLT : public CholmodBase<_MatrixType, _UpLo, CholmodSuper * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower * or Upper. Default is Lower. * + * \implsparsesolverconcept + * * This class supports all kind of SparseMatrix<>: row or column major; upper, lower, or both; compressed or non compressed. * - * \sa \ref TutorialSparseDirectSolvers + * \warning Only double precision real and complex scalar types are supported by Cholmod. + * + * \sa \ref TutorialSparseSolverConcept */ template class CholmodDecomposition : public CholmodBase<_MatrixType, _UpLo, CholmodDecomposition<_MatrixType, _UpLo> > @@ -534,7 +596,7 @@ class CholmodDecomposition : public CholmodBase<_MatrixType, _UpLo, CholmodDecom CholmodDecomposition(const MatrixType& matrix) : Base() { init(); - Base::compute(matrix); + this->compute(matrix); } ~CholmodDecomposition() {} @@ -572,36 +634,6 @@ class CholmodDecomposition : public CholmodBase<_MatrixType, _UpLo, CholmodDecom } }; -namespace internal { - -template -struct solve_retval, Rhs> - : solve_retval_base, Rhs> -{ - typedef CholmodBase<_MatrixType,_UpLo,Derived> Dec; - EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs) - - template void evalTo(Dest& dst) const - { - dec()._solve(rhs(),dst); - } -}; - -template -struct sparse_solve_retval, Rhs> - : sparse_solve_retval_base, Rhs> -{ - typedef CholmodBase<_MatrixType,_UpLo,Derived> Dec; - EIGEN_MAKE_SPARSE_SOLVE_HELPERS(Dec,Rhs) - - template void evalTo(Dest& dst) const - { - dec()._solve(rhs(),dst); - } -}; - -} // end namespace internal - } // end namespace Eigen #endif // EIGEN_CHOLMODSUPPORT_H diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Core/Array.h b/ground/gcs/src/libs/eigen/Eigen/src/Core/Array.h index 0b9c38c821..0d34269fd4 100644 --- a/ground/gcs/src/libs/eigen/Eigen/src/Core/Array.h +++ b/ground/gcs/src/libs/eigen/Eigen/src/Core/Array.h @@ -12,7 +12,16 @@ namespace Eigen { -/** \class Array +namespace internal { +template +struct traits > : traits > +{ + typedef ArrayXpr XprKind; + typedef ArrayBase > XprBase; +}; +} + +/** \class Array * \ingroup Core_Module * * \brief General-purpose arrays with easy API for coefficient-wise operations @@ -24,20 +33,14 @@ namespace Eigen { * API for the %Matrix class provides easy access to linear-algebra * operations. * + * See documentation of class Matrix for detailed information on the template parameters + * storage layout. + * * This class can be extended with the help of the plugin mechanism described on the page - * \ref TopicCustomizingEigen by defining the preprocessor symbol \c EIGEN_ARRAY_PLUGIN. + * \ref TopicCustomizing_Plugins by defining the preprocessor symbol \c EIGEN_ARRAY_PLUGIN. * - * \sa \ref TutorialArrayClass, \ref TopicClassHierarchy + * \sa \blank \ref TutorialArrayClass, \ref TopicClassHierarchy */ -namespace internal { -template -struct traits > : traits > -{ - typedef ArrayXpr XprKind; - typedef ArrayBase > XprBase; -}; -} - template class Array : public PlainObjectBase > @@ -69,11 +72,27 @@ class Array * the usage of 'using'. This should be done only for operator=. */ template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Array& operator=(const EigenBase &other) { return Base::operator=(other); } + /** Set all the entries to \a value. + * \sa DenseBase::setConstant(), DenseBase::fill() + */ + /* This overload is needed because the usage of + * using Base::operator=; + * fails on MSVC. Since the code below is working with GCC and MSVC, we skipped + * the usage of 'using'. This should be done only for operator=. + */ + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Array& operator=(const Scalar &value) + { + Base::setConstant(value); + return *this; + } + /** Copies the value of the expression \a other into \c *this with automatic resizing. * * *this might be resized to match the dimensions of \a other. If *this was a null matrix (not already initialized), @@ -84,7 +103,8 @@ class Array * remain row-vectors and vectors remain vectors. */ template - EIGEN_STRONG_INLINE Array& operator=(const ArrayBase& other) + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Array& operator=(const DenseBase& other) { return Base::_set(other); } @@ -92,11 +112,12 @@ class Array /** This is a special case of the templated operator=. Its purpose is to * prevent a default operator= from hiding the templated operator=. */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Array& operator=(const Array& other) { return Base::_set(other); } - + /** Default constructor. * * For fixed-size matrices, does nothing. @@ -107,6 +128,7 @@ class Array * * \sa resize(Index,Index) */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Array() : Base() { Base::_check_template_params(); @@ -116,6 +138,7 @@ class Array #ifndef EIGEN_PARSED_BY_DOXYGEN // FIXME is it still needed ?? /** \internal */ + EIGEN_DEVICE_FUNC Array(internal::constructor_without_unaligned_array_assert) : Base(internal::constructor_without_unaligned_array_assert()) { @@ -124,56 +147,64 @@ class Array } #endif -#ifdef EIGEN_HAVE_RVALUE_REFERENCES - Array(Array&& other) +#if EIGEN_HAS_RVALUE_REFERENCES + EIGEN_DEVICE_FUNC + Array(Array&& other) EIGEN_NOEXCEPT_IF(std::is_nothrow_move_constructible::value) : Base(std::move(other)) { Base::_check_template_params(); if (RowsAtCompileTime!=Dynamic && ColsAtCompileTime!=Dynamic) Base::_set_noalias(other); } - Array& operator=(Array&& other) + EIGEN_DEVICE_FUNC + Array& operator=(Array&& other) EIGEN_NOEXCEPT_IF(std::is_nothrow_move_assignable::value) { other.swap(*this); return *this; } #endif - /** Constructs a vector or row-vector with given dimension. \only_for_vectors - * - * Note that this is only useful for dynamic-size vectors. For fixed-size vectors, - * it is redundant to pass the dimension here, so it makes more sense to use the default - * constructor Matrix() instead. - */ - EIGEN_STRONG_INLINE explicit Array(Index dim) - : Base(dim, RowsAtCompileTime == 1 ? 1 : dim, ColsAtCompileTime == 1 ? 1 : dim) + #ifndef EIGEN_PARSED_BY_DOXYGEN + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE explicit Array(const T& x) { Base::_check_template_params(); - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Array) - eigen_assert(dim >= 0); - eigen_assert(SizeAtCompileTime == Dynamic || SizeAtCompileTime == dim); - EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED + Base::template _init1(x); } - #ifndef EIGEN_PARSED_BY_DOXYGEN template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Array(const T0& val0, const T1& val1) { Base::_check_template_params(); this->template _init2(val0, val1); } #else - /** constructs an uninitialized matrix with \a rows rows and \a cols columns. + /** \brief Constructs a fixed-sized array initialized with coefficients starting at \a data */ + EIGEN_DEVICE_FUNC explicit Array(const Scalar *data); + /** Constructs a vector or row-vector with given dimension. \only_for_vectors * - * This is useful for dynamic-size matrices. For fixed-size matrices, + * Note that this is only useful for dynamic-size vectors. For fixed-size vectors, + * it is redundant to pass the dimension here, so it makes more sense to use the default + * constructor Array() instead. + */ + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE explicit Array(Index dim); + /** constructs an initialized 1x1 Array with the given coefficient */ + Array(const Scalar& value); + /** constructs an uninitialized array with \a rows rows and \a cols columns. + * + * This is useful for dynamic-size arrays. For fixed-size arrays, * it is redundant to pass these parameters, so one should use the default constructor - * Matrix() instead. */ + * Array() instead. */ Array(Index rows, Index cols); /** constructs an initialized 2D vector with given coefficients */ Array(const Scalar& val0, const Scalar& val1); #endif /** constructs an initialized 3D vector with given coefficients */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Array(const Scalar& val0, const Scalar& val1, const Scalar& val2) { Base::_check_template_params(); @@ -183,6 +214,7 @@ class Array m_storage.data()[2] = val2; } /** constructs an initialized 4D vector with given coefficients */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Array(const Scalar& val0, const Scalar& val1, const Scalar& val2, const Scalar& val3) { Base::_check_template_params(); @@ -193,51 +225,21 @@ class Array m_storage.data()[3] = val3; } - explicit Array(const Scalar *data); - - /** Constructor copying the value of the expression \a other */ - template - EIGEN_STRONG_INLINE Array(const ArrayBase& other) - : Base(other.rows() * other.cols(), other.rows(), other.cols()) - { - Base::_check_template_params(); - Base::_set_noalias(other); - } /** Copy constructor */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Array(const Array& other) - : Base(other.rows() * other.cols(), other.rows(), other.cols()) - { - Base::_check_template_params(); - Base::_set_noalias(other); - } - /** Copy constructor with in-place evaluation */ - template - EIGEN_STRONG_INLINE Array(const ReturnByValue& other) - { - Base::_check_template_params(); - Base::resize(other.rows(), other.cols()); - other.evalTo(*this); - } + : Base(other) + { } /** \sa MatrixBase::operator=(const EigenBase&) */ template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Array(const EigenBase &other) - : Base(other.derived().rows() * other.derived().cols(), other.derived().rows(), other.derived().cols()) - { - Base::_check_template_params(); - Base::_resize_to_match(other); - *this = other; - } - - /** Override MatrixBase::swap() since for dynamic-sized matrices of same type it is enough to swap the - * data pointers. - */ - template - void swap(ArrayBase const & other) - { this->_swap(other.derived()); } + : Base(other.derived()) + { } - inline Index innerStride() const { return 1; } - inline Index outerStride() const { return this->innerSize(); } + EIGEN_DEVICE_FUNC inline Index innerStride() const { return 1; } + EIGEN_DEVICE_FUNC inline Index outerStride() const { return this->innerSize(); } #ifdef EIGEN_ARRAY_PLUGIN #include EIGEN_ARRAY_PLUGIN diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Core/ArrayBase.h b/ground/gcs/src/libs/eigen/Eigen/src/Core/ArrayBase.h index 33ff553712..f0232f65ef 100644 --- a/ground/gcs/src/libs/eigen/Eigen/src/Core/ArrayBase.h +++ b/ground/gcs/src/libs/eigen/Eigen/src/Core/ArrayBase.h @@ -32,7 +32,7 @@ template class MatrixWrapper; * \tparam Derived is the derived type, e.g., an array or an expression type. * * This class can be extended with the help of the plugin mechanism described on the page - * \ref TopicCustomizingEigen by defining the preprocessor symbol \c EIGEN_ARRAYBASE_PLUGIN. + * \ref TopicCustomizing_Plugins by defining the preprocessor symbol \c EIGEN_ARRAYBASE_PLUGIN. * * \sa class MatrixBase, \ref TopicClassHierarchy */ @@ -47,13 +47,11 @@ template class ArrayBase typedef ArrayBase Eigen_BaseClassForSpecializationOfGlobalMathFuncImpl; typedef typename internal::traits::StorageKind StorageKind; - typedef typename internal::traits::Index Index; typedef typename internal::traits::Scalar Scalar; typedef typename internal::packet_traits::type PacketScalar; typedef typename NumTraits::Real RealScalar; typedef DenseBase Base; - using Base::operator*; using Base::RowsAtCompileTime; using Base::ColsAtCompileTime; using Base::SizeAtCompileTime; @@ -62,8 +60,7 @@ template class ArrayBase using Base::MaxSizeAtCompileTime; using Base::IsVectorAtCompileTime; using Base::Flags; - using Base::CoeffReadCost; - + using Base::derived; using Base::const_cast_derived; using Base::rows; @@ -83,25 +80,14 @@ template class ArrayBase #endif // not EIGEN_PARSED_BY_DOXYGEN #ifndef EIGEN_PARSED_BY_DOXYGEN - /** \internal the plain matrix type corresponding to this expression. Note that is not necessarily - * exactly the return type of eval(): in the case of plain matrices, the return type of eval() is a const - * reference to a matrix, not a matrix! It is however guaranteed that the return type of eval() is either - * PlainObject or const PlainObject&. - */ - typedef Array::Scalar, - internal::traits::RowsAtCompileTime, - internal::traits::ColsAtCompileTime, - AutoAlign | (internal::traits::Flags&RowMajorBit ? RowMajor : ColMajor), - internal::traits::MaxRowsAtCompileTime, - internal::traits::MaxColsAtCompileTime - > PlainObject; - + typedef typename Base::PlainObject PlainObject; /** \internal Represents a matrix with all coefficients equal to one another*/ - typedef CwiseNullaryOp,Derived> ConstantReturnType; + typedef CwiseNullaryOp,PlainObject> ConstantReturnType; #endif // not EIGEN_PARSED_BY_DOXYGEN #define EIGEN_CURRENT_STORAGE_BASE_CLASS Eigen::ArrayBase +#define EIGEN_DOC_UNARY_ADDONS(X,Y) # include "../plugins/CommonCwiseUnaryOps.h" # include "../plugins/MatrixCwiseUnaryOps.h" # include "../plugins/ArrayCwiseUnaryOps.h" @@ -112,44 +98,62 @@ template class ArrayBase # include EIGEN_ARRAYBASE_PLUGIN # endif #undef EIGEN_CURRENT_STORAGE_BASE_CLASS +#undef EIGEN_DOC_UNARY_ADDONS /** Special case of the template operator=, in order to prevent the compiler * from generating a default operator= (issue hit with g++ 4.1) */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator=(const ArrayBase& other) { - return internal::assign_selector::run(derived(), other.derived()); + internal::call_assignment(derived(), other.derived()); + return derived(); } - - Derived& operator+=(const Scalar& scalar) - { return *this = derived() + scalar; } - Derived& operator-=(const Scalar& scalar) - { return *this = derived() - scalar; } + + /** Set all the entries to \a value. + * \sa DenseBase::setConstant(), DenseBase::fill() */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Derived& operator=(const Scalar &value) + { Base::setConstant(value); return derived(); } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Derived& operator+=(const Scalar& scalar); + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Derived& operator-=(const Scalar& scalar); template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator+=(const ArrayBase& other); template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator-=(const ArrayBase& other); template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator*=(const ArrayBase& other); template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator/=(const ArrayBase& other); public: + EIGEN_DEVICE_FUNC ArrayBase& array() { return *this; } + EIGEN_DEVICE_FUNC const ArrayBase& array() const { return *this; } /** \returns an \link Eigen::MatrixBase Matrix \endlink expression of this array * \sa MatrixBase::array() */ - MatrixWrapper matrix() { return derived(); } - const MatrixWrapper matrix() const { return derived(); } + EIGEN_DEVICE_FUNC + MatrixWrapper matrix() { return MatrixWrapper(derived()); } + EIGEN_DEVICE_FUNC + const MatrixWrapper matrix() const { return MatrixWrapper(derived()); } // template // inline void evalTo(Dest& dst) const { dst = matrix(); } protected: + EIGEN_DEVICE_FUNC ArrayBase() : Base() {} private: @@ -174,8 +178,7 @@ template EIGEN_STRONG_INLINE Derived & ArrayBase::operator-=(const ArrayBase &other) { - SelfCwiseBinaryOp, Derived, OtherDerived> tmp(derived()); - tmp = other.derived(); + call_assignment(derived(), other.derived(), internal::sub_assign_op()); return derived(); } @@ -188,8 +191,7 @@ template EIGEN_STRONG_INLINE Derived & ArrayBase::operator+=(const ArrayBase& other) { - SelfCwiseBinaryOp, Derived, OtherDerived> tmp(derived()); - tmp = other.derived(); + call_assignment(derived(), other.derived(), internal::add_assign_op()); return derived(); } @@ -202,8 +204,7 @@ template EIGEN_STRONG_INLINE Derived & ArrayBase::operator*=(const ArrayBase& other) { - SelfCwiseBinaryOp, Derived, OtherDerived> tmp(derived()); - tmp = other.derived(); + call_assignment(derived(), other.derived(), internal::mul_assign_op()); return derived(); } @@ -216,8 +217,7 @@ template EIGEN_STRONG_INLINE Derived & ArrayBase::operator/=(const ArrayBase& other) { - SelfCwiseBinaryOp, Derived, OtherDerived> tmp(derived()); - tmp = other.derived(); + call_assignment(derived(), other.derived(), internal::div_assign_op()); return derived(); } diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Core/ArrayWrapper.h b/ground/gcs/src/libs/eigen/Eigen/src/Core/ArrayWrapper.h index b4641e2a01..a04521a161 100644 --- a/ground/gcs/src/libs/eigen/Eigen/src/Core/ArrayWrapper.h +++ b/ground/gcs/src/libs/eigen/Eigen/src/Core/ArrayWrapper.h @@ -44,6 +44,7 @@ class ArrayWrapper : public ArrayBase > typedef ArrayBase Base; EIGEN_DENSE_PUBLIC_INTERFACE(ArrayWrapper) EIGEN_INHERIT_ASSIGNMENT_OPERATORS(ArrayWrapper) + typedef typename internal::remove_all::type NestedExpression; typedef typename internal::conditional< internal::is_lvalue::value, @@ -51,76 +52,45 @@ class ArrayWrapper : public ArrayBase > const Scalar >::type ScalarWithConstIfNotLvalue; - typedef typename internal::nested::type NestedExpressionType; + typedef typename internal::ref_selector::non_const_type NestedExpressionType; - inline ArrayWrapper(ExpressionType& matrix) : m_expression(matrix) {} + using Base::coeffRef; + EIGEN_DEVICE_FUNC + explicit EIGEN_STRONG_INLINE ArrayWrapper(ExpressionType& matrix) : m_expression(matrix) {} + + EIGEN_DEVICE_FUNC inline Index rows() const { return m_expression.rows(); } + EIGEN_DEVICE_FUNC inline Index cols() const { return m_expression.cols(); } + EIGEN_DEVICE_FUNC inline Index outerStride() const { return m_expression.outerStride(); } + EIGEN_DEVICE_FUNC inline Index innerStride() const { return m_expression.innerStride(); } - inline ScalarWithConstIfNotLvalue* data() { return m_expression.const_cast_derived().data(); } + EIGEN_DEVICE_FUNC + inline ScalarWithConstIfNotLvalue* data() { return m_expression.data(); } + EIGEN_DEVICE_FUNC inline const Scalar* data() const { return m_expression.data(); } - inline CoeffReturnType coeff(Index rowId, Index colId) const - { - return m_expression.coeff(rowId, colId); - } - - inline Scalar& coeffRef(Index rowId, Index colId) - { - return m_expression.const_cast_derived().coeffRef(rowId, colId); - } - + EIGEN_DEVICE_FUNC inline const Scalar& coeffRef(Index rowId, Index colId) const { - return m_expression.const_cast_derived().coeffRef(rowId, colId); - } - - inline CoeffReturnType coeff(Index index) const - { - return m_expression.coeff(index); - } - - inline Scalar& coeffRef(Index index) - { - return m_expression.const_cast_derived().coeffRef(index); + return m_expression.coeffRef(rowId, colId); } + EIGEN_DEVICE_FUNC inline const Scalar& coeffRef(Index index) const { - return m_expression.const_cast_derived().coeffRef(index); - } - - template - inline const PacketScalar packet(Index rowId, Index colId) const - { - return m_expression.template packet(rowId, colId); - } - - template - inline void writePacket(Index rowId, Index colId, const PacketScalar& val) - { - m_expression.const_cast_derived().template writePacket(rowId, colId, val); - } - - template - inline const PacketScalar packet(Index index) const - { - return m_expression.template packet(index); - } - - template - inline void writePacket(Index index, const PacketScalar& val) - { - m_expression.const_cast_derived().template writePacket(index, val); + return m_expression.coeffRef(index); } template + EIGEN_DEVICE_FUNC inline void evalTo(Dest& dst) const { dst = m_expression; } const typename internal::remove_all::type& + EIGEN_DEVICE_FUNC nestedExpression() const { return m_expression; @@ -128,10 +98,12 @@ class ArrayWrapper : public ArrayBase > /** Forwards the resizing request to the nested expression * \sa DenseBase::resize(Index) */ - void resize(Index newSize) { m_expression.const_cast_derived().resize(newSize); } + EIGEN_DEVICE_FUNC + void resize(Index newSize) { m_expression.resize(newSize); } /** Forwards the resizing request to the nested expression * \sa DenseBase::resize(Index,Index)*/ - void resize(Index nbRows, Index nbCols) { m_expression.const_cast_derived().resize(nbRows,nbCols); } + EIGEN_DEVICE_FUNC + void resize(Index rows, Index cols) { m_expression.resize(rows,cols); } protected: NestedExpressionType m_expression; @@ -169,6 +141,7 @@ class MatrixWrapper : public MatrixBase > typedef MatrixBase > Base; EIGEN_DENSE_PUBLIC_INTERFACE(MatrixWrapper) EIGEN_INHERIT_ASSIGNMENT_OPERATORS(MatrixWrapper) + typedef typename internal::remove_all::type NestedExpression; typedef typename internal::conditional< internal::is_lvalue::value, @@ -176,72 +149,40 @@ class MatrixWrapper : public MatrixBase > const Scalar >::type ScalarWithConstIfNotLvalue; - typedef typename internal::nested::type NestedExpressionType; + typedef typename internal::ref_selector::non_const_type NestedExpressionType; - inline MatrixWrapper(ExpressionType& a_matrix) : m_expression(a_matrix) {} + using Base::coeffRef; + EIGEN_DEVICE_FUNC + explicit inline MatrixWrapper(ExpressionType& matrix) : m_expression(matrix) {} + + EIGEN_DEVICE_FUNC inline Index rows() const { return m_expression.rows(); } + EIGEN_DEVICE_FUNC inline Index cols() const { return m_expression.cols(); } + EIGEN_DEVICE_FUNC inline Index outerStride() const { return m_expression.outerStride(); } + EIGEN_DEVICE_FUNC inline Index innerStride() const { return m_expression.innerStride(); } - inline ScalarWithConstIfNotLvalue* data() { return m_expression.const_cast_derived().data(); } + EIGEN_DEVICE_FUNC + inline ScalarWithConstIfNotLvalue* data() { return m_expression.data(); } + EIGEN_DEVICE_FUNC inline const Scalar* data() const { return m_expression.data(); } - inline CoeffReturnType coeff(Index rowId, Index colId) const - { - return m_expression.coeff(rowId, colId); - } - - inline Scalar& coeffRef(Index rowId, Index colId) - { - return m_expression.const_cast_derived().coeffRef(rowId, colId); - } - + EIGEN_DEVICE_FUNC inline const Scalar& coeffRef(Index rowId, Index colId) const { return m_expression.derived().coeffRef(rowId, colId); } - inline CoeffReturnType coeff(Index index) const - { - return m_expression.coeff(index); - } - - inline Scalar& coeffRef(Index index) - { - return m_expression.const_cast_derived().coeffRef(index); - } - + EIGEN_DEVICE_FUNC inline const Scalar& coeffRef(Index index) const { - return m_expression.const_cast_derived().coeffRef(index); - } - - template - inline const PacketScalar packet(Index rowId, Index colId) const - { - return m_expression.template packet(rowId, colId); - } - - template - inline void writePacket(Index rowId, Index colId, const PacketScalar& val) - { - m_expression.const_cast_derived().template writePacket(rowId, colId, val); - } - - template - inline const PacketScalar packet(Index index) const - { - return m_expression.template packet(index); - } - - template - inline void writePacket(Index index, const PacketScalar& val) - { - m_expression.const_cast_derived().template writePacket(index, val); + return m_expression.coeffRef(index); } + EIGEN_DEVICE_FUNC const typename internal::remove_all::type& nestedExpression() const { @@ -250,10 +191,12 @@ class MatrixWrapper : public MatrixBase > /** Forwards the resizing request to the nested expression * \sa DenseBase::resize(Index) */ - void resize(Index newSize) { m_expression.const_cast_derived().resize(newSize); } + EIGEN_DEVICE_FUNC + void resize(Index newSize) { m_expression.resize(newSize); } /** Forwards the resizing request to the nested expression * \sa DenseBase::resize(Index,Index)*/ - void resize(Index nbRows, Index nbCols) { m_expression.const_cast_derived().resize(nbRows,nbCols); } + EIGEN_DEVICE_FUNC + void resize(Index rows, Index cols) { m_expression.resize(rows,cols); } protected: NestedExpressionType m_expression; diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Core/Assign.h b/ground/gcs/src/libs/eigen/Eigen/src/Core/Assign.h index f481731727..53806ba33c 100644 --- a/ground/gcs/src/libs/eigen/Eigen/src/Core/Assign.h +++ b/ground/gcs/src/libs/eigen/Eigen/src/Core/Assign.h @@ -14,478 +14,6 @@ namespace Eigen { -namespace internal { - -/*************************************************************************** -* Part 1 : the logic deciding a strategy for traversal and unrolling * -***************************************************************************/ - -template -struct assign_traits -{ -public: - enum { - DstIsAligned = Derived::Flags & AlignedBit, - DstHasDirectAccess = Derived::Flags & DirectAccessBit, - SrcIsAligned = OtherDerived::Flags & AlignedBit, - JointAlignment = bool(DstIsAligned) && bool(SrcIsAligned) ? Aligned : Unaligned - }; - -private: - enum { - InnerSize = int(Derived::IsVectorAtCompileTime) ? int(Derived::SizeAtCompileTime) - : int(Derived::Flags)&RowMajorBit ? int(Derived::ColsAtCompileTime) - : int(Derived::RowsAtCompileTime), - InnerMaxSize = int(Derived::IsVectorAtCompileTime) ? int(Derived::MaxSizeAtCompileTime) - : int(Derived::Flags)&RowMajorBit ? int(Derived::MaxColsAtCompileTime) - : int(Derived::MaxRowsAtCompileTime), - MaxSizeAtCompileTime = Derived::SizeAtCompileTime, - PacketSize = packet_traits::size - }; - - enum { - StorageOrdersAgree = (int(Derived::IsRowMajor) == int(OtherDerived::IsRowMajor)), - MightVectorize = StorageOrdersAgree - && (int(Derived::Flags) & int(OtherDerived::Flags) & ActualPacketAccessBit), - MayInnerVectorize = MightVectorize && int(InnerSize)!=Dynamic && int(InnerSize)%int(PacketSize)==0 - && int(DstIsAligned) && int(SrcIsAligned), - MayLinearize = StorageOrdersAgree && (int(Derived::Flags) & int(OtherDerived::Flags) & LinearAccessBit), - MayLinearVectorize = MightVectorize && MayLinearize && DstHasDirectAccess - && (DstIsAligned || MaxSizeAtCompileTime == Dynamic), - /* If the destination isn't aligned, we have to do runtime checks and we don't unroll, - so it's only good for large enough sizes. */ - MaySliceVectorize = MightVectorize && DstHasDirectAccess - && (int(InnerMaxSize)==Dynamic || int(InnerMaxSize)>=3*PacketSize) - /* slice vectorization can be slow, so we only want it if the slices are big, which is - indicated by InnerMaxSize rather than InnerSize, think of the case of a dynamic block - in a fixed-size matrix */ - }; - -public: - enum { - Traversal = int(MayInnerVectorize) ? int(InnerVectorizedTraversal) - : int(MayLinearVectorize) ? int(LinearVectorizedTraversal) - : int(MaySliceVectorize) ? int(SliceVectorizedTraversal) - : int(MayLinearize) ? int(LinearTraversal) - : int(DefaultTraversal), - Vectorized = int(Traversal) == InnerVectorizedTraversal - || int(Traversal) == LinearVectorizedTraversal - || int(Traversal) == SliceVectorizedTraversal - }; - -private: - enum { - UnrollingLimit = EIGEN_UNROLLING_LIMIT * (Vectorized ? int(PacketSize) : 1), - MayUnrollCompletely = int(Derived::SizeAtCompileTime) != Dynamic - && int(OtherDerived::CoeffReadCost) != Dynamic - && int(Derived::SizeAtCompileTime) * int(OtherDerived::CoeffReadCost) <= int(UnrollingLimit), - MayUnrollInner = int(InnerSize) != Dynamic - && int(OtherDerived::CoeffReadCost) != Dynamic - && int(InnerSize) * int(OtherDerived::CoeffReadCost) <= int(UnrollingLimit) - }; - -public: - enum { - Unrolling = (int(Traversal) == int(InnerVectorizedTraversal) || int(Traversal) == int(DefaultTraversal)) - ? ( - int(MayUnrollCompletely) ? int(CompleteUnrolling) - : int(MayUnrollInner) ? int(InnerUnrolling) - : int(NoUnrolling) - ) - : int(Traversal) == int(LinearVectorizedTraversal) - ? ( bool(MayUnrollCompletely) && bool(DstIsAligned) ? int(CompleteUnrolling) : int(NoUnrolling) ) - : int(Traversal) == int(LinearTraversal) - ? ( bool(MayUnrollCompletely) ? int(CompleteUnrolling) : int(NoUnrolling) ) - : int(NoUnrolling) - }; - -#ifdef EIGEN_DEBUG_ASSIGN - static void debug() - { - EIGEN_DEBUG_VAR(DstIsAligned) - EIGEN_DEBUG_VAR(SrcIsAligned) - EIGEN_DEBUG_VAR(JointAlignment) - EIGEN_DEBUG_VAR(InnerSize) - EIGEN_DEBUG_VAR(InnerMaxSize) - EIGEN_DEBUG_VAR(PacketSize) - EIGEN_DEBUG_VAR(StorageOrdersAgree) - EIGEN_DEBUG_VAR(MightVectorize) - EIGEN_DEBUG_VAR(MayLinearize) - EIGEN_DEBUG_VAR(MayInnerVectorize) - EIGEN_DEBUG_VAR(MayLinearVectorize) - EIGEN_DEBUG_VAR(MaySliceVectorize) - EIGEN_DEBUG_VAR(Traversal) - EIGEN_DEBUG_VAR(UnrollingLimit) - EIGEN_DEBUG_VAR(MayUnrollCompletely) - EIGEN_DEBUG_VAR(MayUnrollInner) - EIGEN_DEBUG_VAR(Unrolling) - } -#endif -}; - -/*************************************************************************** -* Part 2 : meta-unrollers -***************************************************************************/ - -/************************ -*** Default traversal *** -************************/ - -template -struct assign_DefaultTraversal_CompleteUnrolling -{ - enum { - outer = Index / Derived1::InnerSizeAtCompileTime, - inner = Index % Derived1::InnerSizeAtCompileTime - }; - - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) - { - dst.copyCoeffByOuterInner(outer, inner, src); - assign_DefaultTraversal_CompleteUnrolling::run(dst, src); - } -}; - -template -struct assign_DefaultTraversal_CompleteUnrolling -{ - static EIGEN_STRONG_INLINE void run(Derived1 &, const Derived2 &) {} -}; - -template -struct assign_DefaultTraversal_InnerUnrolling -{ - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src, typename Derived1::Index outer) - { - dst.copyCoeffByOuterInner(outer, Index, src); - assign_DefaultTraversal_InnerUnrolling::run(dst, src, outer); - } -}; - -template -struct assign_DefaultTraversal_InnerUnrolling -{ - static EIGEN_STRONG_INLINE void run(Derived1 &, const Derived2 &, typename Derived1::Index) {} -}; - -/*********************** -*** Linear traversal *** -***********************/ - -template -struct assign_LinearTraversal_CompleteUnrolling -{ - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) - { - dst.copyCoeff(Index, src); - assign_LinearTraversal_CompleteUnrolling::run(dst, src); - } -}; - -template -struct assign_LinearTraversal_CompleteUnrolling -{ - static EIGEN_STRONG_INLINE void run(Derived1 &, const Derived2 &) {} -}; - -/************************** -*** Inner vectorization *** -**************************/ - -template -struct assign_innervec_CompleteUnrolling -{ - enum { - outer = Index / Derived1::InnerSizeAtCompileTime, - inner = Index % Derived1::InnerSizeAtCompileTime, - JointAlignment = assign_traits::JointAlignment - }; - - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) - { - dst.template copyPacketByOuterInner(outer, inner, src); - assign_innervec_CompleteUnrolling::size, Stop>::run(dst, src); - } -}; - -template -struct assign_innervec_CompleteUnrolling -{ - static EIGEN_STRONG_INLINE void run(Derived1 &, const Derived2 &) {} -}; - -template -struct assign_innervec_InnerUnrolling -{ - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src, typename Derived1::Index outer) - { - dst.template copyPacketByOuterInner(outer, Index, src); - assign_innervec_InnerUnrolling::size, Stop>::run(dst, src, outer); - } -}; - -template -struct assign_innervec_InnerUnrolling -{ - static EIGEN_STRONG_INLINE void run(Derived1 &, const Derived2 &, typename Derived1::Index) {} -}; - -/*************************************************************************** -* Part 3 : implementation of all cases -***************************************************************************/ - -template::Traversal, - int Unrolling = assign_traits::Unrolling, - int Version = Specialized> -struct assign_impl; - -/************************ -*** Default traversal *** -************************/ - -template -struct assign_impl -{ - static inline void run(Derived1 &, const Derived2 &) { } -}; - -template -struct assign_impl -{ - typedef typename Derived1::Index Index; - static inline void run(Derived1 &dst, const Derived2 &src) - { - const Index innerSize = dst.innerSize(); - const Index outerSize = dst.outerSize(); - for(Index outer = 0; outer < outerSize; ++outer) - for(Index inner = 0; inner < innerSize; ++inner) - dst.copyCoeffByOuterInner(outer, inner, src); - } -}; - -template -struct assign_impl -{ - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) - { - assign_DefaultTraversal_CompleteUnrolling - ::run(dst, src); - } -}; - -template -struct assign_impl -{ - typedef typename Derived1::Index Index; - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) - { - const Index outerSize = dst.outerSize(); - for(Index outer = 0; outer < outerSize; ++outer) - assign_DefaultTraversal_InnerUnrolling - ::run(dst, src, outer); - } -}; - -/*********************** -*** Linear traversal *** -***********************/ - -template -struct assign_impl -{ - typedef typename Derived1::Index Index; - static inline void run(Derived1 &dst, const Derived2 &src) - { - const Index size = dst.size(); - for(Index i = 0; i < size; ++i) - dst.copyCoeff(i, src); - } -}; - -template -struct assign_impl -{ - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) - { - assign_LinearTraversal_CompleteUnrolling - ::run(dst, src); - } -}; - -/************************** -*** Inner vectorization *** -**************************/ - -template -struct assign_impl -{ - typedef typename Derived1::Index Index; - static inline void run(Derived1 &dst, const Derived2 &src) - { - const Index innerSize = dst.innerSize(); - const Index outerSize = dst.outerSize(); - const Index packetSize = packet_traits::size; - for(Index outer = 0; outer < outerSize; ++outer) - for(Index inner = 0; inner < innerSize; inner+=packetSize) - dst.template copyPacketByOuterInner(outer, inner, src); - } -}; - -template -struct assign_impl -{ - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) - { - assign_innervec_CompleteUnrolling - ::run(dst, src); - } -}; - -template -struct assign_impl -{ - typedef typename Derived1::Index Index; - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) - { - const Index outerSize = dst.outerSize(); - for(Index outer = 0; outer < outerSize; ++outer) - assign_innervec_InnerUnrolling - ::run(dst, src, outer); - } -}; - -/*************************** -*** Linear vectorization *** -***************************/ - -template -struct unaligned_assign_impl -{ - template - static EIGEN_STRONG_INLINE void run(const Derived&, OtherDerived&, typename Derived::Index, typename Derived::Index) {} -}; - -template <> -struct unaligned_assign_impl -{ - // MSVC must not inline this functions. If it does, it fails to optimize the - // packet access path. -#ifdef _MSC_VER - template - static EIGEN_DONT_INLINE void run(const Derived& src, OtherDerived& dst, typename Derived::Index start, typename Derived::Index end) -#else - template - static EIGEN_STRONG_INLINE void run(const Derived& src, OtherDerived& dst, typename Derived::Index start, typename Derived::Index end) -#endif - { - for (typename Derived::Index index = start; index < end; ++index) - dst.copyCoeff(index, src); - } -}; - -template -struct assign_impl -{ - typedef typename Derived1::Index Index; - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) - { - const Index size = dst.size(); - typedef packet_traits PacketTraits; - enum { - packetSize = PacketTraits::size, - dstAlignment = PacketTraits::AlignedOnScalar ? Aligned : int(assign_traits::DstIsAligned) , - srcAlignment = assign_traits::JointAlignment - }; - const Index alignedStart = assign_traits::DstIsAligned ? 0 - : internal::first_aligned(&dst.coeffRef(0), size); - const Index alignedEnd = alignedStart + ((size-alignedStart)/packetSize)*packetSize; - - unaligned_assign_impl::DstIsAligned!=0>::run(src,dst,0,alignedStart); - - for(Index index = alignedStart; index < alignedEnd; index += packetSize) - { - dst.template copyPacket(index, src); - } - - unaligned_assign_impl<>::run(src,dst,alignedEnd,size); - } -}; - -template -struct assign_impl -{ - typedef typename Derived1::Index Index; - static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src) - { - enum { size = Derived1::SizeAtCompileTime, - packetSize = packet_traits::size, - alignedSize = (size/packetSize)*packetSize }; - - assign_innervec_CompleteUnrolling::run(dst, src); - assign_DefaultTraversal_CompleteUnrolling::run(dst, src); - } -}; - -/************************** -*** Slice vectorization *** -***************************/ - -template -struct assign_impl -{ - typedef typename Derived1::Index Index; - static inline void run(Derived1 &dst, const Derived2 &src) - { - typedef typename Derived1::Scalar Scalar; - typedef packet_traits PacketTraits; - enum { - packetSize = PacketTraits::size, - alignable = PacketTraits::AlignedOnScalar, - dstIsAligned = assign_traits::DstIsAligned, - dstAlignment = alignable ? Aligned : int(dstIsAligned), - srcAlignment = assign_traits::JointAlignment - }; - const Scalar *dst_ptr = &dst.coeffRef(0,0); - if((!bool(dstIsAligned)) && (size_t(dst_ptr) % sizeof(Scalar))>0) - { - // the pointer is not aligend-on scalar, so alignment is not possible - return assign_impl::run(dst, src); - } - const Index packetAlignedMask = packetSize - 1; - const Index innerSize = dst.innerSize(); - const Index outerSize = dst.outerSize(); - const Index alignedStep = alignable ? (packetSize - dst.outerStride() % packetSize) & packetAlignedMask : 0; - Index alignedStart = ((!alignable) || bool(dstIsAligned)) ? 0 : internal::first_aligned(dst_ptr, innerSize); - - for(Index outer = 0; outer < outerSize; ++outer) - { - const Index alignedEnd = alignedStart + ((innerSize-alignedStart) & ~packetAlignedMask); - // do the non-vectorizable part of the assignment - for(Index inner = 0; inner(outer, inner, src); - - // do the non-vectorizable part of the assignment - for(Index inner = alignedEnd; inner((alignedStart+alignedStep)%packetSize, innerSize); - } - } -}; - -} // end namespace internal - -/*************************************************************************** -* Part 4 : implementation of DenseBase methods -***************************************************************************/ - template template EIGEN_STRONG_INLINE Derived& DenseBase @@ -499,90 +27,62 @@ EIGEN_STRONG_INLINE Derived& DenseBase EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(Derived,OtherDerived) EIGEN_STATIC_ASSERT(SameType,YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) -#ifdef EIGEN_DEBUG_ASSIGN - internal::assign_traits::debug(); -#endif eigen_assert(rows() == other.rows() && cols() == other.cols()); - internal::assign_impl::Traversal) - : int(InvalidTraversal)>::run(derived(),other.derived()); -#ifndef EIGEN_NO_DEBUG - checkTransposeAliasing(other.derived()); -#endif + internal::call_assignment_no_alias(derived(),other.derived()); + return derived(); } -namespace internal { - -template::Flags) & EvalBeforeAssigningBit) != 0, - bool NeedToTranspose = ((int(Derived::RowsAtCompileTime) == 1 && int(OtherDerived::ColsAtCompileTime) == 1) - | // FIXME | instead of || to please GCC 4.4.0 stupid warning "suggest parentheses around &&". - // revert to || as soon as not needed anymore. - (int(Derived::ColsAtCompileTime) == 1 && int(OtherDerived::RowsAtCompileTime) == 1)) - && int(Derived::SizeAtCompileTime) != 1> -struct assign_selector; - -template -struct assign_selector { - static EIGEN_STRONG_INLINE Derived& run(Derived& dst, const OtherDerived& other) { return dst.lazyAssign(other.derived()); } - template - static EIGEN_STRONG_INLINE Derived& evalTo(ActualDerived& dst, const ActualOtherDerived& other) { other.evalTo(dst); return dst; } -}; -template -struct assign_selector { - static EIGEN_STRONG_INLINE Derived& run(Derived& dst, const OtherDerived& other) { return dst.lazyAssign(other.eval()); } -}; -template -struct assign_selector { - static EIGEN_STRONG_INLINE Derived& run(Derived& dst, const OtherDerived& other) { return dst.lazyAssign(other.transpose()); } - template - static EIGEN_STRONG_INLINE Derived& evalTo(ActualDerived& dst, const ActualOtherDerived& other) { Transpose dstTrans(dst); other.evalTo(dstTrans); return dst; } -}; -template -struct assign_selector { - static EIGEN_STRONG_INLINE Derived& run(Derived& dst, const OtherDerived& other) { return dst.lazyAssign(other.transpose().eval()); } -}; - -} // end namespace internal - template template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& DenseBase::operator=(const DenseBase& other) { - return internal::assign_selector::run(derived(), other.derived()); + internal::call_assignment(derived(), other.derived()); + return derived(); } template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& DenseBase::operator=(const DenseBase& other) { - return internal::assign_selector::run(derived(), other.derived()); + internal::call_assignment(derived(), other.derived()); + return derived(); } template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& MatrixBase::operator=(const MatrixBase& other) { - return internal::assign_selector::run(derived(), other.derived()); + internal::call_assignment(derived(), other.derived()); + return derived(); } template template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& MatrixBase::operator=(const DenseBase& other) { - return internal::assign_selector::run(derived(), other.derived()); + internal::call_assignment(derived(), other.derived()); + return derived(); } template template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& MatrixBase::operator=(const EigenBase& other) { - return internal::assign_selector::evalTo(derived(), other.derived()); + internal::call_assignment(derived(), other.derived()); + return derived(); } template template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& MatrixBase::operator=(const ReturnByValue& other) { - return internal::assign_selector::evalTo(derived(), other.derived()); + other.derived().evalTo(derived()); + return derived(); } } // end namespace Eigen diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Core/AssignEvaluator.h b/ground/gcs/src/libs/eigen/Eigen/src/Core/AssignEvaluator.h new file mode 100644 index 0000000000..b0ec7b7cad --- /dev/null +++ b/ground/gcs/src/libs/eigen/Eigen/src/Core/AssignEvaluator.h @@ -0,0 +1,935 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2011 Benoit Jacob +// Copyright (C) 2011-2014 Gael Guennebaud +// Copyright (C) 2011-2012 Jitse Niesen +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_ASSIGN_EVALUATOR_H +#define EIGEN_ASSIGN_EVALUATOR_H + +namespace Eigen { + +// This implementation is based on Assign.h + +namespace internal { + +/*************************************************************************** +* Part 1 : the logic deciding a strategy for traversal and unrolling * +***************************************************************************/ + +// copy_using_evaluator_traits is based on assign_traits + +template +struct copy_using_evaluator_traits +{ + typedef typename DstEvaluator::XprType Dst; + typedef typename Dst::Scalar DstScalar; + + enum { + DstFlags = DstEvaluator::Flags, + SrcFlags = SrcEvaluator::Flags + }; + +public: + enum { + DstAlignment = DstEvaluator::Alignment, + SrcAlignment = SrcEvaluator::Alignment, + DstHasDirectAccess = DstFlags & DirectAccessBit, + JointAlignment = EIGEN_PLAIN_ENUM_MIN(DstAlignment,SrcAlignment) + }; + +private: + enum { + InnerSize = int(Dst::IsVectorAtCompileTime) ? int(Dst::SizeAtCompileTime) + : int(DstFlags)&RowMajorBit ? int(Dst::ColsAtCompileTime) + : int(Dst::RowsAtCompileTime), + InnerMaxSize = int(Dst::IsVectorAtCompileTime) ? int(Dst::MaxSizeAtCompileTime) + : int(DstFlags)&RowMajorBit ? int(Dst::MaxColsAtCompileTime) + : int(Dst::MaxRowsAtCompileTime), + OuterStride = int(outer_stride_at_compile_time::ret), + MaxSizeAtCompileTime = Dst::SizeAtCompileTime + }; + + // TODO distinguish between linear traversal and inner-traversals + typedef typename find_best_packet::type LinearPacketType; + typedef typename find_best_packet::type InnerPacketType; + + enum { + LinearPacketSize = unpacket_traits::size, + InnerPacketSize = unpacket_traits::size + }; + +public: + enum { + LinearRequiredAlignment = unpacket_traits::alignment, + InnerRequiredAlignment = unpacket_traits::alignment + }; + +private: + enum { + DstIsRowMajor = DstFlags&RowMajorBit, + SrcIsRowMajor = SrcFlags&RowMajorBit, + StorageOrdersAgree = (int(DstIsRowMajor) == int(SrcIsRowMajor)), + MightVectorize = bool(StorageOrdersAgree) + && (int(DstFlags) & int(SrcFlags) & ActualPacketAccessBit) + && bool(functor_traits::PacketAccess), + MayInnerVectorize = MightVectorize + && int(InnerSize)!=Dynamic && int(InnerSize)%int(InnerPacketSize)==0 + && int(OuterStride)!=Dynamic && int(OuterStride)%int(InnerPacketSize)==0 + && (EIGEN_UNALIGNED_VECTORIZE || int(JointAlignment)>=int(InnerRequiredAlignment)), + MayLinearize = bool(StorageOrdersAgree) && (int(DstFlags) & int(SrcFlags) & LinearAccessBit), + MayLinearVectorize = bool(MightVectorize) && MayLinearize && DstHasDirectAccess + && (EIGEN_UNALIGNED_VECTORIZE || (int(DstAlignment)>=int(LinearRequiredAlignment)) || MaxSizeAtCompileTime == Dynamic), + /* If the destination isn't aligned, we have to do runtime checks and we don't unroll, + so it's only good for large enough sizes. */ + MaySliceVectorize = bool(MightVectorize) && bool(DstHasDirectAccess) + && (int(InnerMaxSize)==Dynamic || int(InnerMaxSize)>=(EIGEN_UNALIGNED_VECTORIZE?InnerPacketSize:(3*InnerPacketSize))) + /* slice vectorization can be slow, so we only want it if the slices are big, which is + indicated by InnerMaxSize rather than InnerSize, think of the case of a dynamic block + in a fixed-size matrix + However, with EIGEN_UNALIGNED_VECTORIZE and unrolling, slice vectorization is still worth it */ + }; + +public: + enum { + Traversal = int(MayLinearVectorize) && (LinearPacketSize>InnerPacketSize) ? int(LinearVectorizedTraversal) + : int(MayInnerVectorize) ? int(InnerVectorizedTraversal) + : int(MayLinearVectorize) ? int(LinearVectorizedTraversal) + : int(MaySliceVectorize) ? int(SliceVectorizedTraversal) + : int(MayLinearize) ? int(LinearTraversal) + : int(DefaultTraversal), + Vectorized = int(Traversal) == InnerVectorizedTraversal + || int(Traversal) == LinearVectorizedTraversal + || int(Traversal) == SliceVectorizedTraversal + }; + + typedef typename conditional::type PacketType; + +private: + enum { + ActualPacketSize = int(Traversal)==LinearVectorizedTraversal ? LinearPacketSize + : Vectorized ? InnerPacketSize + : 1, + UnrollingLimit = EIGEN_UNROLLING_LIMIT * ActualPacketSize, + MayUnrollCompletely = int(Dst::SizeAtCompileTime) != Dynamic + && int(Dst::SizeAtCompileTime) * (int(DstEvaluator::CoeffReadCost)+int(SrcEvaluator::CoeffReadCost)) <= int(UnrollingLimit), + MayUnrollInner = int(InnerSize) != Dynamic + && int(InnerSize) * (int(DstEvaluator::CoeffReadCost)+int(SrcEvaluator::CoeffReadCost)) <= int(UnrollingLimit) + }; + +public: + enum { + Unrolling = (int(Traversal) == int(InnerVectorizedTraversal) || int(Traversal) == int(DefaultTraversal)) + ? ( + int(MayUnrollCompletely) ? int(CompleteUnrolling) + : int(MayUnrollInner) ? int(InnerUnrolling) + : int(NoUnrolling) + ) + : int(Traversal) == int(LinearVectorizedTraversal) + ? ( bool(MayUnrollCompletely) && ( EIGEN_UNALIGNED_VECTORIZE || (int(DstAlignment)>=int(LinearRequiredAlignment))) + ? int(CompleteUnrolling) + : int(NoUnrolling) ) + : int(Traversal) == int(LinearTraversal) + ? ( bool(MayUnrollCompletely) ? int(CompleteUnrolling) + : int(NoUnrolling) ) +#if EIGEN_UNALIGNED_VECTORIZE + : int(Traversal) == int(SliceVectorizedTraversal) + ? ( bool(MayUnrollInner) ? int(InnerUnrolling) + : int(NoUnrolling) ) +#endif + : int(NoUnrolling) + }; + +#ifdef EIGEN_DEBUG_ASSIGN + static void debug() + { + std::cerr << "DstXpr: " << typeid(typename DstEvaluator::XprType).name() << std::endl; + std::cerr << "SrcXpr: " << typeid(typename SrcEvaluator::XprType).name() << std::endl; + std::cerr.setf(std::ios::hex, std::ios::basefield); + std::cerr << "DstFlags" << " = " << DstFlags << " (" << demangle_flags(DstFlags) << " )" << std::endl; + std::cerr << "SrcFlags" << " = " << SrcFlags << " (" << demangle_flags(SrcFlags) << " )" << std::endl; + std::cerr.unsetf(std::ios::hex); + EIGEN_DEBUG_VAR(DstAlignment) + EIGEN_DEBUG_VAR(SrcAlignment) + EIGEN_DEBUG_VAR(LinearRequiredAlignment) + EIGEN_DEBUG_VAR(InnerRequiredAlignment) + EIGEN_DEBUG_VAR(JointAlignment) + EIGEN_DEBUG_VAR(InnerSize) + EIGEN_DEBUG_VAR(InnerMaxSize) + EIGEN_DEBUG_VAR(LinearPacketSize) + EIGEN_DEBUG_VAR(InnerPacketSize) + EIGEN_DEBUG_VAR(ActualPacketSize) + EIGEN_DEBUG_VAR(StorageOrdersAgree) + EIGEN_DEBUG_VAR(MightVectorize) + EIGEN_DEBUG_VAR(MayLinearize) + EIGEN_DEBUG_VAR(MayInnerVectorize) + EIGEN_DEBUG_VAR(MayLinearVectorize) + EIGEN_DEBUG_VAR(MaySliceVectorize) + std::cerr << "Traversal" << " = " << Traversal << " (" << demangle_traversal(Traversal) << ")" << std::endl; + EIGEN_DEBUG_VAR(SrcEvaluator::CoeffReadCost) + EIGEN_DEBUG_VAR(UnrollingLimit) + EIGEN_DEBUG_VAR(MayUnrollCompletely) + EIGEN_DEBUG_VAR(MayUnrollInner) + std::cerr << "Unrolling" << " = " << Unrolling << " (" << demangle_unrolling(Unrolling) << ")" << std::endl; + std::cerr << std::endl; + } +#endif +}; + +/*************************************************************************** +* Part 2 : meta-unrollers +***************************************************************************/ + +/************************ +*** Default traversal *** +************************/ + +template +struct copy_using_evaluator_DefaultTraversal_CompleteUnrolling +{ + // FIXME: this is not very clean, perhaps this information should be provided by the kernel? + typedef typename Kernel::DstEvaluatorType DstEvaluatorType; + typedef typename DstEvaluatorType::XprType DstXprType; + + enum { + outer = Index / DstXprType::InnerSizeAtCompileTime, + inner = Index % DstXprType::InnerSizeAtCompileTime + }; + + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) + { + kernel.assignCoeffByOuterInner(outer, inner); + copy_using_evaluator_DefaultTraversal_CompleteUnrolling::run(kernel); + } +}; + +template +struct copy_using_evaluator_DefaultTraversal_CompleteUnrolling +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel&) { } +}; + +template +struct copy_using_evaluator_DefaultTraversal_InnerUnrolling +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel, Index outer) + { + kernel.assignCoeffByOuterInner(outer, Index_); + copy_using_evaluator_DefaultTraversal_InnerUnrolling::run(kernel, outer); + } +}; + +template +struct copy_using_evaluator_DefaultTraversal_InnerUnrolling +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel&, Index) { } +}; + +/*********************** +*** Linear traversal *** +***********************/ + +template +struct copy_using_evaluator_LinearTraversal_CompleteUnrolling +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel& kernel) + { + kernel.assignCoeff(Index); + copy_using_evaluator_LinearTraversal_CompleteUnrolling::run(kernel); + } +}; + +template +struct copy_using_evaluator_LinearTraversal_CompleteUnrolling +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel&) { } +}; + +/************************** +*** Inner vectorization *** +**************************/ + +template +struct copy_using_evaluator_innervec_CompleteUnrolling +{ + // FIXME: this is not very clean, perhaps this information should be provided by the kernel? + typedef typename Kernel::DstEvaluatorType DstEvaluatorType; + typedef typename DstEvaluatorType::XprType DstXprType; + typedef typename Kernel::PacketType PacketType; + + enum { + outer = Index / DstXprType::InnerSizeAtCompileTime, + inner = Index % DstXprType::InnerSizeAtCompileTime, + SrcAlignment = Kernel::AssignmentTraits::SrcAlignment, + DstAlignment = Kernel::AssignmentTraits::DstAlignment + }; + + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) + { + kernel.template assignPacketByOuterInner(outer, inner); + enum { NextIndex = Index + unpacket_traits::size }; + copy_using_evaluator_innervec_CompleteUnrolling::run(kernel); + } +}; + +template +struct copy_using_evaluator_innervec_CompleteUnrolling +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel&) { } +}; + +template +struct copy_using_evaluator_innervec_InnerUnrolling +{ + typedef typename Kernel::PacketType PacketType; + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel, Index outer) + { + kernel.template assignPacketByOuterInner(outer, Index_); + enum { NextIndex = Index_ + unpacket_traits::size }; + copy_using_evaluator_innervec_InnerUnrolling::run(kernel, outer); + } +}; + +template +struct copy_using_evaluator_innervec_InnerUnrolling +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &, Index) { } +}; + +/*************************************************************************** +* Part 3 : implementation of all cases +***************************************************************************/ + +// dense_assignment_loop is based on assign_impl + +template +struct dense_assignment_loop; + +/************************ +*** Default traversal *** +************************/ + +template +struct dense_assignment_loop +{ + EIGEN_DEVICE_FUNC static void EIGEN_STRONG_INLINE run(Kernel &kernel) + { + for(Index outer = 0; outer < kernel.outerSize(); ++outer) { + for(Index inner = 0; inner < kernel.innerSize(); ++inner) { + kernel.assignCoeffByOuterInner(outer, inner); + } + } + } +}; + +template +struct dense_assignment_loop +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) + { + typedef typename Kernel::DstEvaluatorType::XprType DstXprType; + copy_using_evaluator_DefaultTraversal_CompleteUnrolling::run(kernel); + } +}; + +template +struct dense_assignment_loop +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) + { + typedef typename Kernel::DstEvaluatorType::XprType DstXprType; + + const Index outerSize = kernel.outerSize(); + for(Index outer = 0; outer < outerSize; ++outer) + copy_using_evaluator_DefaultTraversal_InnerUnrolling::run(kernel, outer); + } +}; + +/*************************** +*** Linear vectorization *** +***************************/ + + +// The goal of unaligned_dense_assignment_loop is simply to factorize the handling +// of the non vectorizable beginning and ending parts + +template +struct unaligned_dense_assignment_loop +{ + // if IsAligned = true, then do nothing + template + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel&, Index, Index) {} +}; + +template <> +struct unaligned_dense_assignment_loop +{ + // MSVC must not inline this functions. If it does, it fails to optimize the + // packet access path. + // FIXME check which version exhibits this issue +#if EIGEN_COMP_MSVC + template + static EIGEN_DONT_INLINE void run(Kernel &kernel, + Index start, + Index end) +#else + template + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel, + Index start, + Index end) +#endif + { + for (Index index = start; index < end; ++index) + kernel.assignCoeff(index); + } +}; + +template +struct dense_assignment_loop +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) + { + const Index size = kernel.size(); + typedef typename Kernel::Scalar Scalar; + typedef typename Kernel::PacketType PacketType; + enum { + requestedAlignment = Kernel::AssignmentTraits::LinearRequiredAlignment, + packetSize = unpacket_traits::size, + dstIsAligned = int(Kernel::AssignmentTraits::DstAlignment)>=int(requestedAlignment), + dstAlignment = packet_traits::AlignedOnScalar ? int(requestedAlignment) + : int(Kernel::AssignmentTraits::DstAlignment), + srcAlignment = Kernel::AssignmentTraits::JointAlignment + }; + const Index alignedStart = dstIsAligned ? 0 : internal::first_aligned(kernel.dstDataPtr(), size); + const Index alignedEnd = alignedStart + ((size-alignedStart)/packetSize)*packetSize; + + unaligned_dense_assignment_loop::run(kernel, 0, alignedStart); + + for(Index index = alignedStart; index < alignedEnd; index += packetSize) + kernel.template assignPacket(index); + + unaligned_dense_assignment_loop<>::run(kernel, alignedEnd, size); + } +}; + +template +struct dense_assignment_loop +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) + { + typedef typename Kernel::DstEvaluatorType::XprType DstXprType; + typedef typename Kernel::PacketType PacketType; + + enum { size = DstXprType::SizeAtCompileTime, + packetSize =unpacket_traits::size, + alignedSize = (size/packetSize)*packetSize }; + + copy_using_evaluator_innervec_CompleteUnrolling::run(kernel); + copy_using_evaluator_DefaultTraversal_CompleteUnrolling::run(kernel); + } +}; + +/************************** +*** Inner vectorization *** +**************************/ + +template +struct dense_assignment_loop +{ + typedef typename Kernel::PacketType PacketType; + enum { + SrcAlignment = Kernel::AssignmentTraits::SrcAlignment, + DstAlignment = Kernel::AssignmentTraits::DstAlignment + }; + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) + { + const Index innerSize = kernel.innerSize(); + const Index outerSize = kernel.outerSize(); + const Index packetSize = unpacket_traits::size; + for(Index outer = 0; outer < outerSize; ++outer) + for(Index inner = 0; inner < innerSize; inner+=packetSize) + kernel.template assignPacketByOuterInner(outer, inner); + } +}; + +template +struct dense_assignment_loop +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) + { + typedef typename Kernel::DstEvaluatorType::XprType DstXprType; + copy_using_evaluator_innervec_CompleteUnrolling::run(kernel); + } +}; + +template +struct dense_assignment_loop +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) + { + typedef typename Kernel::DstEvaluatorType::XprType DstXprType; + typedef typename Kernel::AssignmentTraits Traits; + const Index outerSize = kernel.outerSize(); + for(Index outer = 0; outer < outerSize; ++outer) + copy_using_evaluator_innervec_InnerUnrolling::run(kernel, outer); + } +}; + +/*********************** +*** Linear traversal *** +***********************/ + +template +struct dense_assignment_loop +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) + { + const Index size = kernel.size(); + for(Index i = 0; i < size; ++i) + kernel.assignCoeff(i); + } +}; + +template +struct dense_assignment_loop +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) + { + typedef typename Kernel::DstEvaluatorType::XprType DstXprType; + copy_using_evaluator_LinearTraversal_CompleteUnrolling::run(kernel); + } +}; + +/************************** +*** Slice vectorization *** +***************************/ + +template +struct dense_assignment_loop +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) + { + typedef typename Kernel::Scalar Scalar; + typedef typename Kernel::PacketType PacketType; + enum { + packetSize = unpacket_traits::size, + requestedAlignment = int(Kernel::AssignmentTraits::InnerRequiredAlignment), + alignable = packet_traits::AlignedOnScalar || int(Kernel::AssignmentTraits::DstAlignment)>=sizeof(Scalar), + dstIsAligned = int(Kernel::AssignmentTraits::DstAlignment)>=int(requestedAlignment), + dstAlignment = alignable ? int(requestedAlignment) + : int(Kernel::AssignmentTraits::DstAlignment) + }; + const Scalar *dst_ptr = kernel.dstDataPtr(); + if((!bool(dstIsAligned)) && (UIntPtr(dst_ptr) % sizeof(Scalar))>0) + { + // the pointer is not aligend-on scalar, so alignment is not possible + return dense_assignment_loop::run(kernel); + } + const Index packetAlignedMask = packetSize - 1; + const Index innerSize = kernel.innerSize(); + const Index outerSize = kernel.outerSize(); + const Index alignedStep = alignable ? (packetSize - kernel.outerStride() % packetSize) & packetAlignedMask : 0; + Index alignedStart = ((!alignable) || bool(dstIsAligned)) ? 0 : internal::first_aligned(dst_ptr, innerSize); + + for(Index outer = 0; outer < outerSize; ++outer) + { + const Index alignedEnd = alignedStart + ((innerSize-alignedStart) & ~packetAlignedMask); + // do the non-vectorizable part of the assignment + for(Index inner = 0; inner(outer, inner); + + // do the non-vectorizable part of the assignment + for(Index inner = alignedEnd; inner +struct dense_assignment_loop +{ + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel) + { + typedef typename Kernel::DstEvaluatorType::XprType DstXprType; + typedef typename Kernel::PacketType PacketType; + + enum { size = DstXprType::InnerSizeAtCompileTime, + packetSize =unpacket_traits::size, + vectorizableSize = (size/packetSize)*packetSize }; + + for(Index outer = 0; outer < kernel.outerSize(); ++outer) + { + copy_using_evaluator_innervec_InnerUnrolling::run(kernel, outer); + copy_using_evaluator_DefaultTraversal_InnerUnrolling::run(kernel, outer); + } + } +}; +#endif + + +/*************************************************************************** +* Part 4 : Generic dense assignment kernel +***************************************************************************/ + +// This class generalize the assignment of a coefficient (or packet) from one dense evaluator +// to another dense writable evaluator. +// It is parametrized by the two evaluators, and the actual assignment functor. +// This abstraction level permits to keep the evaluation loops as simple and as generic as possible. +// One can customize the assignment using this generic dense_assignment_kernel with different +// functors, or by completely overloading it, by-passing a functor. +template +class generic_dense_assignment_kernel +{ +protected: + typedef typename DstEvaluatorTypeT::XprType DstXprType; + typedef typename SrcEvaluatorTypeT::XprType SrcXprType; +public: + + typedef DstEvaluatorTypeT DstEvaluatorType; + typedef SrcEvaluatorTypeT SrcEvaluatorType; + typedef typename DstEvaluatorType::Scalar Scalar; + typedef copy_using_evaluator_traits AssignmentTraits; + typedef typename AssignmentTraits::PacketType PacketType; + + + EIGEN_DEVICE_FUNC generic_dense_assignment_kernel(DstEvaluatorType &dst, const SrcEvaluatorType &src, const Functor &func, DstXprType& dstExpr) + : m_dst(dst), m_src(src), m_functor(func), m_dstExpr(dstExpr) + { + #ifdef EIGEN_DEBUG_ASSIGN + AssignmentTraits::debug(); + #endif + } + + EIGEN_DEVICE_FUNC Index size() const { return m_dstExpr.size(); } + EIGEN_DEVICE_FUNC Index innerSize() const { return m_dstExpr.innerSize(); } + EIGEN_DEVICE_FUNC Index outerSize() const { return m_dstExpr.outerSize(); } + EIGEN_DEVICE_FUNC Index rows() const { return m_dstExpr.rows(); } + EIGEN_DEVICE_FUNC Index cols() const { return m_dstExpr.cols(); } + EIGEN_DEVICE_FUNC Index outerStride() const { return m_dstExpr.outerStride(); } + + EIGEN_DEVICE_FUNC DstEvaluatorType& dstEvaluator() { return m_dst; } + EIGEN_DEVICE_FUNC const SrcEvaluatorType& srcEvaluator() const { return m_src; } + + /// Assign src(row,col) to dst(row,col) through the assignment functor. + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void assignCoeff(Index row, Index col) + { + m_functor.assignCoeff(m_dst.coeffRef(row,col), m_src.coeff(row,col)); + } + + /// \sa assignCoeff(Index,Index) + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void assignCoeff(Index index) + { + m_functor.assignCoeff(m_dst.coeffRef(index), m_src.coeff(index)); + } + + /// \sa assignCoeff(Index,Index) + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void assignCoeffByOuterInner(Index outer, Index inner) + { + Index row = rowIndexByOuterInner(outer, inner); + Index col = colIndexByOuterInner(outer, inner); + assignCoeff(row, col); + } + + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void assignPacket(Index row, Index col) + { + m_functor.template assignPacket(&m_dst.coeffRef(row,col), m_src.template packet(row,col)); + } + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void assignPacket(Index index) + { + m_functor.template assignPacket(&m_dst.coeffRef(index), m_src.template packet(index)); + } + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void assignPacketByOuterInner(Index outer, Index inner) + { + Index row = rowIndexByOuterInner(outer, inner); + Index col = colIndexByOuterInner(outer, inner); + assignPacket(row, col); + } + + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE Index rowIndexByOuterInner(Index outer, Index inner) + { + typedef typename DstEvaluatorType::ExpressionTraits Traits; + return int(Traits::RowsAtCompileTime) == 1 ? 0 + : int(Traits::ColsAtCompileTime) == 1 ? inner + : int(DstEvaluatorType::Flags)&RowMajorBit ? outer + : inner; + } + + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE Index colIndexByOuterInner(Index outer, Index inner) + { + typedef typename DstEvaluatorType::ExpressionTraits Traits; + return int(Traits::ColsAtCompileTime) == 1 ? 0 + : int(Traits::RowsAtCompileTime) == 1 ? inner + : int(DstEvaluatorType::Flags)&RowMajorBit ? inner + : outer; + } + + EIGEN_DEVICE_FUNC const Scalar* dstDataPtr() const + { + return m_dstExpr.data(); + } + +protected: + DstEvaluatorType& m_dst; + const SrcEvaluatorType& m_src; + const Functor &m_functor; + // TODO find a way to avoid the needs of the original expression + DstXprType& m_dstExpr; +}; + +/*************************************************************************** +* Part 5 : Entry point for dense rectangular assignment +***************************************************************************/ + +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +void resize_if_allowed(DstXprType &dst, const SrcXprType& src, const Functor &/*func*/) +{ + EIGEN_ONLY_USED_FOR_DEBUG(dst); + EIGEN_ONLY_USED_FOR_DEBUG(src); + eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); +} + +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +void resize_if_allowed(DstXprType &dst, const SrcXprType& src, const internal::assign_op &/*func*/) +{ + Index dstRows = src.rows(); + Index dstCols = src.cols(); + if(((dst.rows()!=dstRows) || (dst.cols()!=dstCols))) + dst.resize(dstRows, dstCols); + eigen_assert(dst.rows() == dstRows && dst.cols() == dstCols); +} + +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void call_dense_assignment_loop(DstXprType& dst, const SrcXprType& src, const Functor &func) +{ + typedef evaluator DstEvaluatorType; + typedef evaluator SrcEvaluatorType; + + SrcEvaluatorType srcEvaluator(src); + + // NOTE To properly handle A = (A*A.transpose())/s with A rectangular, + // we need to resize the destination after the source evaluator has been created. + resize_if_allowed(dst, src, func); + + DstEvaluatorType dstEvaluator(dst); + + typedef generic_dense_assignment_kernel Kernel; + Kernel kernel(dstEvaluator, srcEvaluator, func, dst.const_cast_derived()); + + dense_assignment_loop::run(kernel); +} + +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void call_dense_assignment_loop(DstXprType& dst, const SrcXprType& src) +{ + call_dense_assignment_loop(dst, src, internal::assign_op()); +} + +/*************************************************************************** +* Part 6 : Generic assignment +***************************************************************************/ + +// Based on the respective shapes of the destination and source, +// the class AssignmentKind determine the kind of assignment mechanism. +// AssignmentKind must define a Kind typedef. +template struct AssignmentKind; + +// Assignement kind defined in this file: +struct Dense2Dense {}; +struct EigenBase2EigenBase {}; + +template struct AssignmentKind { typedef EigenBase2EigenBase Kind; }; +template<> struct AssignmentKind { typedef Dense2Dense Kind; }; + +// This is the main assignment class +template< typename DstXprType, typename SrcXprType, typename Functor, + typename Kind = typename AssignmentKind< typename evaluator_traits::Shape , typename evaluator_traits::Shape >::Kind, + typename EnableIf = void> +struct Assignment; + + +// The only purpose of this call_assignment() function is to deal with noalias() / "assume-aliasing" and automatic transposition. +// Indeed, I (Gael) think that this concept of "assume-aliasing" was a mistake, and it makes thing quite complicated. +// So this intermediate function removes everything related to "assume-aliasing" such that Assignment +// does not has to bother about these annoying details. + +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +void call_assignment(Dst& dst, const Src& src) +{ + call_assignment(dst, src, internal::assign_op()); +} +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +void call_assignment(const Dst& dst, const Src& src) +{ + call_assignment(dst, src, internal::assign_op()); +} + +// Deal with "assume-aliasing" +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +void call_assignment(Dst& dst, const Src& src, const Func& func, typename enable_if< evaluator_assume_aliasing::value, void*>::type = 0) +{ + typename plain_matrix_type::type tmp(src); + call_assignment_no_alias(dst, tmp, func); +} + +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +void call_assignment(Dst& dst, const Src& src, const Func& func, typename enable_if::value, void*>::type = 0) +{ + call_assignment_no_alias(dst, src, func); +} + +// by-pass "assume-aliasing" +// When there is no aliasing, we require that 'dst' has been properly resized +template class StorageBase, typename Src, typename Func> +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +void call_assignment(NoAlias& dst, const Src& src, const Func& func) +{ + call_assignment_no_alias(dst.expression(), src, func); +} + + +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +void call_assignment_no_alias(Dst& dst, const Src& src, const Func& func) +{ + enum { + NeedToTranspose = ( (int(Dst::RowsAtCompileTime) == 1 && int(Src::ColsAtCompileTime) == 1) + || (int(Dst::ColsAtCompileTime) == 1 && int(Src::RowsAtCompileTime) == 1) + ) && int(Dst::SizeAtCompileTime) != 1 + }; + + typedef typename internal::conditional, Dst>::type ActualDstTypeCleaned; + typedef typename internal::conditional, Dst&>::type ActualDstType; + ActualDstType actualDst(dst); + + // TODO check whether this is the right place to perform these checks: + EIGEN_STATIC_ASSERT_LVALUE(Dst) + EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(ActualDstTypeCleaned,Src) + EIGEN_CHECK_BINARY_COMPATIBILIY(Func,typename ActualDstTypeCleaned::Scalar,typename Src::Scalar); + + Assignment::run(actualDst, src, func); +} +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +void call_assignment_no_alias(Dst& dst, const Src& src) +{ + call_assignment_no_alias(dst, src, internal::assign_op()); +} + +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +void call_assignment_no_alias_no_transpose(Dst& dst, const Src& src, const Func& func) +{ + // TODO check whether this is the right place to perform these checks: + EIGEN_STATIC_ASSERT_LVALUE(Dst) + EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(Dst,Src) + EIGEN_CHECK_BINARY_COMPATIBILIY(Func,typename Dst::Scalar,typename Src::Scalar); + + Assignment::run(dst, src, func); +} +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +void call_assignment_no_alias_no_transpose(Dst& dst, const Src& src) +{ + call_assignment_no_alias_no_transpose(dst, src, internal::assign_op()); +} + +// forward declaration +template void check_for_aliasing(const Dst &dst, const Src &src); + +// Generic Dense to Dense assignment +// Note that the last template argument "Weak" is needed to make it possible to perform +// both partial specialization+SFINAE without ambiguous specialization +template< typename DstXprType, typename SrcXprType, typename Functor, typename Weak> +struct Assignment +{ + EIGEN_DEVICE_FUNC + static EIGEN_STRONG_INLINE void run(DstXprType &dst, const SrcXprType &src, const Functor &func) + { +#ifndef EIGEN_NO_DEBUG + internal::check_for_aliasing(dst, src); +#endif + + call_dense_assignment_loop(dst, src, func); + } +}; + +// Generic assignment through evalTo. +// TODO: not sure we have to keep that one, but it helps porting current code to new evaluator mechanism. +// Note that the last template argument "Weak" is needed to make it possible to perform +// both partial specialization+SFINAE without ambiguous specialization +template< typename DstXprType, typename SrcXprType, typename Functor, typename Weak> +struct Assignment +{ + EIGEN_DEVICE_FUNC + static EIGEN_STRONG_INLINE void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op &/*func*/) + { + Index dstRows = src.rows(); + Index dstCols = src.cols(); + if((dst.rows()!=dstRows) || (dst.cols()!=dstCols)) + dst.resize(dstRows, dstCols); + + eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); + src.evalTo(dst); + } + + // NOTE The following two functions are templated to avoid their instanciation if not needed + // This is needed because some expressions supports evalTo only and/or have 'void' as scalar type. + template + EIGEN_DEVICE_FUNC + static EIGEN_STRONG_INLINE void run(DstXprType &dst, const SrcXprType &src, const internal::add_assign_op &/*func*/) + { + Index dstRows = src.rows(); + Index dstCols = src.cols(); + if((dst.rows()!=dstRows) || (dst.cols()!=dstCols)) + dst.resize(dstRows, dstCols); + + eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); + src.addTo(dst); + } + + template + EIGEN_DEVICE_FUNC + static EIGEN_STRONG_INLINE void run(DstXprType &dst, const SrcXprType &src, const internal::sub_assign_op &/*func*/) + { + Index dstRows = src.rows(); + Index dstCols = src.cols(); + if((dst.rows()!=dstRows) || (dst.cols()!=dstCols)) + dst.resize(dstRows, dstCols); + + eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); + src.subTo(dst); + } +}; + +} // namespace internal + +} // end namespace Eigen + +#endif // EIGEN_ASSIGN_EVALUATOR_H diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Core/Assign_MKL.h b/ground/gcs/src/libs/eigen/Eigen/src/Core/Assign_MKL.h index 7772951b91..6c2ab92648 100644 --- a/ground/gcs/src/libs/eigen/Eigen/src/Core/Assign_MKL.h +++ b/ground/gcs/src/libs/eigen/Eigen/src/Core/Assign_MKL.h @@ -1,6 +1,7 @@ /* Copyright (c) 2011, Intel Corporation. All rights reserved. - + Copyright (C) 2015 Gael Guennebaud + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -37,17 +38,13 @@ namespace Eigen { namespace internal { -template struct vml_call -{ enum { IsSupported = 0 }; }; - -template +template class vml_assign_traits { private: enum { DstHasDirectAccess = Dst::Flags & DirectAccessBit, SrcHasDirectAccess = Src::Flags & DirectAccessBit, - StorageOrdersAgree = (int(Dst::IsRowMajor) == int(Src::IsRowMajor)), InnerSize = int(Dst::IsVectorAtCompileTime) ? int(Dst::SizeAtCompileTime) : int(Dst::Flags)&RowMajorBit ? int(Dst::ColsAtCompileTime) @@ -57,165 +54,120 @@ class vml_assign_traits : int(Dst::MaxRowsAtCompileTime), MaxSizeAtCompileTime = Dst::SizeAtCompileTime, - MightEnableVml = vml_call::IsSupported && StorageOrdersAgree && DstHasDirectAccess && SrcHasDirectAccess - && Src::InnerStrideAtCompileTime==1 && Dst::InnerStrideAtCompileTime==1, + MightEnableVml = StorageOrdersAgree && DstHasDirectAccess && SrcHasDirectAccess && Src::InnerStrideAtCompileTime==1 && Dst::InnerStrideAtCompileTime==1, MightLinearize = MightEnableVml && (int(Dst::Flags) & int(Src::Flags) & LinearAccessBit), VmlSize = MightLinearize ? MaxSizeAtCompileTime : InnerMaxSize, - LargeEnough = VmlSize==Dynamic || VmlSize>=EIGEN_MKL_VML_THRESHOLD, - MayEnableVml = MightEnableVml && LargeEnough, - MayLinearize = MayEnableVml && MightLinearize + LargeEnough = VmlSize==Dynamic || VmlSize>=EIGEN_MKL_VML_THRESHOLD }; public: enum { - Traversal = MayLinearize ? LinearVectorizedTraversal - : MayEnableVml ? InnerVectorizedTraversal - : DefaultTraversal + EnableVml = MightEnableVml && LargeEnough, + Traversal = MightLinearize ? LinearTraversal : DefaultTraversal }; }; -template::Traversal > -struct vml_assign_impl - : assign_impl,Traversal,Unrolling,BuiltIn> -{ -}; - -template -struct vml_assign_impl -{ - typedef typename Derived1::Scalar Scalar; - typedef typename Derived1::Index Index; - static inline void run(Derived1& dst, const CwiseUnaryOp& src) - { - // in case we want to (or have to) skip VML at runtime we can call: - // assign_impl,Traversal,Unrolling,BuiltIn>::run(dst,src); - const Index innerSize = dst.innerSize(); - const Index outerSize = dst.outerSize(); - for(Index outer = 0; outer < outerSize; ++outer) { - const Scalar *src_ptr = src.IsRowMajor ? &(src.nestedExpression().coeffRef(outer,0)) : - &(src.nestedExpression().coeffRef(0, outer)); - Scalar *dst_ptr = dst.IsRowMajor ? &(dst.coeffRef(outer,0)) : &(dst.coeffRef(0, outer)); - vml_call::run(src.functor(), innerSize, src_ptr, dst_ptr ); - } - } -}; - -template -struct vml_assign_impl -{ - static inline void run(Derived1& dst, const CwiseUnaryOp& src) - { - // in case we want to (or have to) skip VML at runtime we can call: - // assign_impl,Traversal,Unrolling,BuiltIn>::run(dst,src); - vml_call::run(src.functor(), dst.size(), src.nestedExpression().data(), dst.data() ); - } -}; - -// Macroses - -#define EIGEN_MKL_VML_SPECIALIZE_ASSIGN(TRAVERSAL,UNROLLING) \ - template \ - struct assign_impl, TRAVERSAL, UNROLLING, Specialized> { \ - static inline void run(Derived1 &dst, const Eigen::CwiseUnaryOp &src) { \ - vml_assign_impl::run(dst, src); \ - } \ - }; - -EIGEN_MKL_VML_SPECIALIZE_ASSIGN(DefaultTraversal,NoUnrolling) -EIGEN_MKL_VML_SPECIALIZE_ASSIGN(DefaultTraversal,CompleteUnrolling) -EIGEN_MKL_VML_SPECIALIZE_ASSIGN(DefaultTraversal,InnerUnrolling) -EIGEN_MKL_VML_SPECIALIZE_ASSIGN(LinearTraversal,NoUnrolling) -EIGEN_MKL_VML_SPECIALIZE_ASSIGN(LinearTraversal,CompleteUnrolling) -EIGEN_MKL_VML_SPECIALIZE_ASSIGN(InnerVectorizedTraversal,NoUnrolling) -EIGEN_MKL_VML_SPECIALIZE_ASSIGN(InnerVectorizedTraversal,CompleteUnrolling) -EIGEN_MKL_VML_SPECIALIZE_ASSIGN(InnerVectorizedTraversal,InnerUnrolling) -EIGEN_MKL_VML_SPECIALIZE_ASSIGN(LinearVectorizedTraversal,CompleteUnrolling) -EIGEN_MKL_VML_SPECIALIZE_ASSIGN(LinearVectorizedTraversal,NoUnrolling) -EIGEN_MKL_VML_SPECIALIZE_ASSIGN(SliceVectorizedTraversal,NoUnrolling) - - +#define EIGEN_PP_EXPAND(ARG) ARG #if !defined (EIGEN_FAST_MATH) || (EIGEN_FAST_MATH != 1) -#define EIGEN_MKL_VML_MODE VML_HA +#define EIGEN_VMLMODE_EXPAND_LA , VML_HA #else -#define EIGEN_MKL_VML_MODE VML_LA +#define EIGEN_VMLMODE_EXPAND_LA , VML_LA #endif -#define EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, VMLOP, EIGENTYPE, VMLTYPE) \ - template<> struct vml_call< scalar_##EIGENOP##_op > { \ - enum { IsSupported = 1 }; \ - static inline void run( const scalar_##EIGENOP##_op& /*func*/, \ - int size, const EIGENTYPE* src, EIGENTYPE* dst) { \ - VMLOP(size, (const VMLTYPE*)src, (VMLTYPE*)dst); \ - } \ +#define EIGEN_VMLMODE_EXPAND__ + +#define EIGEN_VMLMODE_PREFIX_LA vm +#define EIGEN_VMLMODE_PREFIX__ v +#define EIGEN_VMLMODE_PREFIX(VMLMODE) EIGEN_CAT(EIGEN_VMLMODE_PREFIX_,VMLMODE) + +#define EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, VMLOP, EIGENTYPE, VMLTYPE, VMLMODE) \ + template< typename DstXprType, typename SrcXprNested> \ + struct Assignment, SrcXprNested>, assign_op, \ + Dense2Dense, typename enable_if::EnableVml>::type> { \ + typedef CwiseUnaryOp, SrcXprNested> SrcXprType; \ + static void run(DstXprType &dst, const SrcXprType &src, const assign_op &/*func*/) { \ + eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); \ + if(vml_assign_traits::Traversal==LinearTraversal) { \ + VMLOP(dst.size(), (const VMLTYPE*)src.nestedExpression().data(), \ + (VMLTYPE*)dst.data() EIGEN_PP_EXPAND(EIGEN_VMLMODE_EXPAND_##VMLMODE) ); \ + } else { \ + const Index outerSize = dst.outerSize(); \ + for(Index outer = 0; outer < outerSize; ++outer) { \ + const EIGENTYPE *src_ptr = src.IsRowMajor ? &(src.nestedExpression().coeffRef(outer,0)) : \ + &(src.nestedExpression().coeffRef(0, outer)); \ + EIGENTYPE *dst_ptr = dst.IsRowMajor ? &(dst.coeffRef(outer,0)) : &(dst.coeffRef(0, outer)); \ + VMLOP( dst.innerSize(), (const VMLTYPE*)src_ptr, \ + (VMLTYPE*)dst_ptr EIGEN_PP_EXPAND(EIGEN_VMLMODE_EXPAND_##VMLMODE)); \ + } \ + } \ + } \ + }; \ + + +#define EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(EIGENOP, VMLOP, VMLMODE) \ + EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, EIGEN_CAT(EIGEN_VMLMODE_PREFIX(VMLMODE),s##VMLOP), float, float, VMLMODE) \ + EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, EIGEN_CAT(EIGEN_VMLMODE_PREFIX(VMLMODE),d##VMLOP), double, double, VMLMODE) + +#define EIGEN_MKL_VML_DECLARE_UNARY_CALLS_CPLX(EIGENOP, VMLOP, VMLMODE) \ + EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, EIGEN_CAT(EIGEN_VMLMODE_PREFIX(VMLMODE),c##VMLOP), scomplex, MKL_Complex8, VMLMODE) \ + EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, EIGEN_CAT(EIGEN_VMLMODE_PREFIX(VMLMODE),z##VMLOP), dcomplex, MKL_Complex16, VMLMODE) + +#define EIGEN_MKL_VML_DECLARE_UNARY_CALLS(EIGENOP, VMLOP, VMLMODE) \ + EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(EIGENOP, VMLOP, VMLMODE) \ + EIGEN_MKL_VML_DECLARE_UNARY_CALLS_CPLX(EIGENOP, VMLOP, VMLMODE) + + +EIGEN_MKL_VML_DECLARE_UNARY_CALLS(sin, Sin, LA) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS(asin, Asin, LA) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS(sinh, Sinh, LA) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS(cos, Cos, LA) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS(acos, Acos, LA) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS(cosh, Cosh, LA) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS(tan, Tan, LA) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS(atan, Atan, LA) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS(tanh, Tanh, LA) +// EIGEN_MKL_VML_DECLARE_UNARY_CALLS(abs, Abs, _) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS(exp, Exp, LA) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS(log, Ln, LA) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS(log10, Log10, LA) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS(sqrt, Sqrt, _) + +EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(square, Sqr, _) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS_CPLX(arg, Arg, _) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(round, Round, _) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(floor, Floor, _) +EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(ceil, Ceil, _) + +#define EIGEN_MKL_VML_DECLARE_POW_CALL(EIGENOP, VMLOP, EIGENTYPE, VMLTYPE, VMLMODE) \ + template< typename DstXprType, typename SrcXprNested, typename Plain> \ + struct Assignment, SrcXprNested, \ + const CwiseNullaryOp,Plain> >, assign_op, \ + Dense2Dense, typename enable_if::EnableVml>::type> { \ + typedef CwiseBinaryOp, SrcXprNested, \ + const CwiseNullaryOp,Plain> > SrcXprType; \ + static void run(DstXprType &dst, const SrcXprType &src, const assign_op &/*func*/) { \ + eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); \ + VMLTYPE exponent = reinterpret_cast(src.rhs().functor().m_other); \ + if(vml_assign_traits::Traversal==LinearTraversal) \ + { \ + VMLOP( dst.size(), (const VMLTYPE*)src.lhs().data(), exponent, \ + (VMLTYPE*)dst.data() EIGEN_PP_EXPAND(EIGEN_VMLMODE_EXPAND_##VMLMODE) ); \ + } else { \ + const Index outerSize = dst.outerSize(); \ + for(Index outer = 0; outer < outerSize; ++outer) { \ + const EIGENTYPE *src_ptr = src.IsRowMajor ? &(src.lhs().coeffRef(outer,0)) : \ + &(src.lhs().coeffRef(0, outer)); \ + EIGENTYPE *dst_ptr = dst.IsRowMajor ? &(dst.coeffRef(outer,0)) : &(dst.coeffRef(0, outer)); \ + VMLOP( dst.innerSize(), (const VMLTYPE*)src_ptr, exponent, \ + (VMLTYPE*)dst_ptr EIGEN_PP_EXPAND(EIGEN_VMLMODE_EXPAND_##VMLMODE)); \ + } \ + } \ + } \ }; - -#define EIGEN_MKL_VML_DECLARE_UNARY_CALL_LA(EIGENOP, VMLOP, EIGENTYPE, VMLTYPE) \ - template<> struct vml_call< scalar_##EIGENOP##_op > { \ - enum { IsSupported = 1 }; \ - static inline void run( const scalar_##EIGENOP##_op& /*func*/, \ - int size, const EIGENTYPE* src, EIGENTYPE* dst) { \ - MKL_INT64 vmlMode = EIGEN_MKL_VML_MODE; \ - VMLOP(size, (const VMLTYPE*)src, (VMLTYPE*)dst, vmlMode); \ - } \ - }; - -#define EIGEN_MKL_VML_DECLARE_POW_CALL(EIGENOP, VMLOP, EIGENTYPE, VMLTYPE) \ - template<> struct vml_call< scalar_##EIGENOP##_op > { \ - enum { IsSupported = 1 }; \ - static inline void run( const scalar_##EIGENOP##_op& func, \ - int size, const EIGENTYPE* src, EIGENTYPE* dst) { \ - EIGENTYPE exponent = func.m_exponent; \ - MKL_INT64 vmlMode = EIGEN_MKL_VML_MODE; \ - VMLOP(&size, (const VMLTYPE*)src, (const VMLTYPE*)&exponent, \ - (VMLTYPE*)dst, &vmlMode); \ - } \ - }; - -#define EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(EIGENOP, VMLOP) \ - EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, vs##VMLOP, float, float) \ - EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, vd##VMLOP, double, double) - -#define EIGEN_MKL_VML_DECLARE_UNARY_CALLS_COMPLEX(EIGENOP, VMLOP) \ - EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, vc##VMLOP, scomplex, MKL_Complex8) \ - EIGEN_MKL_VML_DECLARE_UNARY_CALL(EIGENOP, vz##VMLOP, dcomplex, MKL_Complex16) - -#define EIGEN_MKL_VML_DECLARE_UNARY_CALLS(EIGENOP, VMLOP) \ - EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(EIGENOP, VMLOP) \ - EIGEN_MKL_VML_DECLARE_UNARY_CALLS_COMPLEX(EIGENOP, VMLOP) - - -#define EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL_LA(EIGENOP, VMLOP) \ - EIGEN_MKL_VML_DECLARE_UNARY_CALL_LA(EIGENOP, vms##VMLOP, float, float) \ - EIGEN_MKL_VML_DECLARE_UNARY_CALL_LA(EIGENOP, vmd##VMLOP, double, double) - -#define EIGEN_MKL_VML_DECLARE_UNARY_CALLS_COMPLEX_LA(EIGENOP, VMLOP) \ - EIGEN_MKL_VML_DECLARE_UNARY_CALL_LA(EIGENOP, vmc##VMLOP, scomplex, MKL_Complex8) \ - EIGEN_MKL_VML_DECLARE_UNARY_CALL_LA(EIGENOP, vmz##VMLOP, dcomplex, MKL_Complex16) - -#define EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(EIGENOP, VMLOP) \ - EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL_LA(EIGENOP, VMLOP) \ - EIGEN_MKL_VML_DECLARE_UNARY_CALLS_COMPLEX_LA(EIGENOP, VMLOP) - - -EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(sin, Sin) -EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(asin, Asin) -EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(cos, Cos) -EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(acos, Acos) -EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(tan, Tan) -//EIGEN_MKL_VML_DECLARE_UNARY_CALLS(abs, Abs) -EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(exp, Exp) -EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(log, Ln) -EIGEN_MKL_VML_DECLARE_UNARY_CALLS_LA(sqrt, Sqrt) - -EIGEN_MKL_VML_DECLARE_UNARY_CALLS_REAL(square, Sqr) - -// The vm*powx functions are not avaibale in the windows version of MKL. -#ifndef _WIN32 -EIGEN_MKL_VML_DECLARE_POW_CALL(pow, vmspowx_, float, float) -EIGEN_MKL_VML_DECLARE_POW_CALL(pow, vmdpowx_, double, double) -EIGEN_MKL_VML_DECLARE_POW_CALL(pow, vmcpowx_, scomplex, MKL_Complex8) -EIGEN_MKL_VML_DECLARE_POW_CALL(pow, vmzpowx_, dcomplex, MKL_Complex16) -#endif + +EIGEN_MKL_VML_DECLARE_POW_CALL(pow, vmsPowx, float, float, LA) +EIGEN_MKL_VML_DECLARE_POW_CALL(pow, vmdPowx, double, double, LA) +EIGEN_MKL_VML_DECLARE_POW_CALL(pow, vmcPowx, scomplex, MKL_Complex8, LA) +EIGEN_MKL_VML_DECLARE_POW_CALL(pow, vmzPowx, dcomplex, MKL_Complex16, LA) } // end namespace internal diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Core/BandMatrix.h b/ground/gcs/src/libs/eigen/Eigen/src/Core/BandMatrix.h index ffd7fe8b30..4978c91405 100644 --- a/ground/gcs/src/libs/eigen/Eigen/src/Core/BandMatrix.h +++ b/ground/gcs/src/libs/eigen/Eigen/src/Core/BandMatrix.h @@ -32,7 +32,7 @@ class BandMatrixBase : public EigenBase }; typedef typename internal::traits::Scalar Scalar; typedef Matrix DenseMatrixType; - typedef typename DenseMatrixType::Index Index; + typedef typename DenseMatrixType::StorageIndex StorageIndex; typedef typename internal::traits::CoefficientsType CoefficientsType; typedef EigenBase Base; @@ -161,15 +161,15 @@ class BandMatrixBase : public EigenBase * * \brief Represents a rectangular matrix with a banded storage * - * \param _Scalar Numeric type, i.e. float, double, int - * \param Rows Number of rows, or \b Dynamic - * \param Cols Number of columns, or \b Dynamic - * \param Supers Number of super diagonal - * \param Subs Number of sub diagonal - * \param _Options A combination of either \b #RowMajor or \b #ColMajor, and of \b #SelfAdjoint - * The former controls \ref TopicStorageOrders "storage order", and defaults to - * column-major. The latter controls whether the matrix represents a selfadjoint - * matrix in which case either Supers of Subs have to be null. + * \tparam _Scalar Numeric type, i.e. float, double, int + * \tparam _Rows Number of rows, or \b Dynamic + * \tparam _Cols Number of columns, or \b Dynamic + * \tparam _Supers Number of super diagonal + * \tparam _Subs Number of sub diagonal + * \tparam _Options A combination of either \b #RowMajor or \b #ColMajor, and of \b #SelfAdjoint + * The former controls \ref TopicStorageOrders "storage order", and defaults to + * column-major. The latter controls whether the matrix represents a selfadjoint + * matrix in which case either Supers of Subs have to be null. * * \sa class TridiagonalMatrix */ @@ -179,7 +179,7 @@ struct traits > { typedef _Scalar Scalar; typedef Dense StorageKind; - typedef DenseIndex Index; + typedef Eigen::Index StorageIndex; enum { CoeffReadCost = NumTraits::ReadCost, RowsAtCompileTime = _Rows, @@ -201,10 +201,10 @@ class BandMatrix : public BandMatrixBase::Scalar Scalar; - typedef typename internal::traits::Index Index; + typedef typename internal::traits::StorageIndex StorageIndex; typedef typename internal::traits::CoefficientsType CoefficientsType; - inline BandMatrix(Index rows=Rows, Index cols=Cols, Index supers=Supers, Index subs=Subs) + explicit inline BandMatrix(Index rows=Rows, Index cols=Cols, Index supers=Supers, Index subs=Subs) : m_coeffs(1+supers+subs,cols), m_rows(rows), m_supers(supers), m_subs(subs) { @@ -241,7 +241,7 @@ struct traits::CoeffReadCost, RowsAtCompileTime = _Rows, @@ -264,9 +264,9 @@ class BandMatrixWrapper : public BandMatrixBase::Scalar Scalar; typedef typename internal::traits::CoefficientsType CoefficientsType; - typedef typename internal::traits::Index Index; + typedef typename internal::traits::StorageIndex StorageIndex; - inline BandMatrixWrapper(const CoefficientsType& coeffs, Index rows=_Rows, Index cols=_Cols, Index supers=_Supers, Index subs=_Subs) + explicit inline BandMatrixWrapper(const CoefficientsType& coeffs, Index rows=_Rows, Index cols=_Cols, Index supers=_Supers, Index subs=_Subs) : m_coeffs(coeffs), m_rows(rows), m_supers(supers), m_subs(subs) { @@ -302,9 +302,9 @@ class BandMatrixWrapper : public BandMatrixBase class TridiagonalMatrix : public BandMatrix { typedef BandMatrix Base; - typedef typename Base::Index Index; + typedef typename Base::StorageIndex StorageIndex; public: - TridiagonalMatrix(Index size = Size) : Base(size,size,Options&SelfAdjoint?0:1,1) {} + explicit TridiagonalMatrix(Index size = Size) : Base(size,size,Options&SelfAdjoint?0:1,1) {} inline typename Base::template DiagonalIntReturnType<1>::Type super() { return Base::template diagonal<1>(); } @@ -327,6 +327,25 @@ class TridiagonalMatrix : public BandMatrix +struct evaluator_traits > + : public evaluator_traits_base > +{ + typedef BandShape Shape; +}; + +template +struct evaluator_traits > + : public evaluator_traits_base > +{ + typedef BandShape Shape; +}; + +template<> struct AssignmentKind { typedef EigenBase2EigenBase Kind; }; + } // end namespace internal } // end namespace Eigen diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Core/Block.h b/ground/gcs/src/libs/eigen/Eigen/src/Core/Block.h index 8278944432..11de45c2ec 100644 --- a/ground/gcs/src/libs/eigen/Eigen/src/Core/Block.h +++ b/ground/gcs/src/libs/eigen/Eigen/src/Core/Block.h @@ -13,38 +13,6 @@ namespace Eigen { -/** \class Block - * \ingroup Core_Module - * - * \brief Expression of a fixed-size or dynamic-size block - * - * \param XprType the type of the expression in which we are taking a block - * \param BlockRows the number of rows of the block we are taking at compile time (optional) - * \param BlockCols the number of columns of the block we are taking at compile time (optional) - * - * This class represents an expression of either a fixed-size or dynamic-size block. It is the return - * type of DenseBase::block(Index,Index,Index,Index) and DenseBase::block(Index,Index) and - * most of the time this is the only way it is used. - * - * However, if you want to directly maniputate block expressions, - * for instance if you want to write a function returning such an expression, you - * will need to use this class. - * - * Here is an example illustrating the dynamic case: - * \include class_Block.cpp - * Output: \verbinclude class_Block.out - * - * \note Even though this expression has dynamic size, in the case where \a XprType - * has fixed size, this expression inherits a fixed maximal size which means that evaluating - * it does not cause a dynamic memory allocation. - * - * Here is an example illustrating the fixed-size case: - * \include class_FixedBlock.cpp - * Output: \verbinclude class_FixedBlock.out - * - * \sa DenseBase::block(Index,Index,Index,Index), DenseBase::block(Index,Index), class VectorBlock - */ - namespace internal { template struct traits > : traits @@ -52,7 +20,7 @@ struct traits > : traits::Scalar Scalar; typedef typename traits::StorageKind StorageKind; typedef typename traits::XprKind XprKind; - typedef typename nested::type XprTypeNested; + typedef typename ref_selector::type XprTypeNested; typedef typename remove_reference::type _XprTypeNested; enum{ MatrixRows = traits::RowsAtCompileTime, @@ -65,10 +33,10 @@ struct traits > : traits::MaxColsAtCompileTime), + XprTypeIsRowMajor = (int(traits::Flags)&RowMajorBit) != 0, - IsDense = is_same::value, - IsRowMajor = (IsDense&&MaxRowsAtCompileTime==1&&MaxColsAtCompileTime!=1) ? 1 - : (IsDense&&MaxColsAtCompileTime==1&&MaxRowsAtCompileTime!=1) ? 0 + IsRowMajor = (MaxRowsAtCompileTime==1&&MaxColsAtCompileTime!=1) ? 1 + : (MaxColsAtCompileTime==1&&MaxRowsAtCompileTime!=1) ? 0 : XprTypeIsRowMajor, HasSameStorageOrderAsXprType = (IsRowMajor == XprTypeIsRowMajor), InnerSize = IsRowMajor ? int(ColsAtCompileTime) : int(RowsAtCompileTime), @@ -78,18 +46,16 @@ struct traits > : traits::ret) : int(inner_stride_at_compile_time::ret), - MaskPacketAccessBit = (InnerSize == Dynamic || (InnerSize % packet_traits::size) == 0) - && (InnerStrideAtCompileTime == 1) - ? PacketAccessBit : 0, - MaskAlignedBit = (InnerPanel && (OuterStrideAtCompileTime!=Dynamic) && (((OuterStrideAtCompileTime * int(sizeof(Scalar))) % 16) == 0)) ? AlignedBit : 0, - FlagsLinearAccessBit = (RowsAtCompileTime == 1 || ColsAtCompileTime == 1 || (InnerPanel && (traits::Flags&LinearAccessBit))) ? LinearAccessBit : 0, + + // FIXME, this traits is rather specialized for dense object and it needs to be cleaned further FlagsLvalueBit = is_lvalue::value ? LvalueBit : 0, FlagsRowMajorBit = IsRowMajor ? RowMajorBit : 0, - Flags0 = traits::Flags & ( (HereditaryBits & ~RowMajorBit) | - DirectAccessBit | - MaskPacketAccessBit | - MaskAlignedBit), - Flags = Flags0 | FlagsLinearAccessBit | FlagsLvalueBit | FlagsRowMajorBit + Flags = (traits::Flags & (DirectAccessBit | (InnerPanel?CompressedAccessBit:0))) | FlagsLvalueBit | FlagsRowMajorBit, + // FIXME DirectAccessBit should not be handled by expressions + // + // Alignment is needed by MapBase's assertions + // We can sefely set it to false here. Internal alignment errors will be detected by an eigen_internal_assert in the respective evaluator + Alignment = 0 }; }; @@ -100,6 +66,40 @@ template class BlockImpl; +/** \class Block + * \ingroup Core_Module + * + * \brief Expression of a fixed-size or dynamic-size block + * + * \tparam XprType the type of the expression in which we are taking a block + * \tparam BlockRows the number of rows of the block we are taking at compile time (optional) + * \tparam BlockCols the number of columns of the block we are taking at compile time (optional) + * \tparam InnerPanel is true, if the block maps to a set of rows of a row major matrix or + * to set of columns of a column major matrix (optional). The parameter allows to determine + * at compile time whether aligned access is possible on the block expression. + * + * This class represents an expression of either a fixed-size or dynamic-size block. It is the return + * type of DenseBase::block(Index,Index,Index,Index) and DenseBase::block(Index,Index) and + * most of the time this is the only way it is used. + * + * However, if you want to directly maniputate block expressions, + * for instance if you want to write a function returning such an expression, you + * will need to use this class. + * + * Here is an example illustrating the dynamic case: + * \include class_Block.cpp + * Output: \verbinclude class_Block.out + * + * \note Even though this expression has dynamic size, in the case where \a XprType + * has fixed size, this expression inherits a fixed maximal size which means that evaluating + * it does not cause a dynamic memory allocation. + * + * Here is an example illustrating the fixed-size case: + * \include class_FixedBlock.cpp + * Output: \verbinclude class_FixedBlock.out + * + * \sa DenseBase::block(Index,Index,Index,Index), DenseBase::block(Index,Index), class VectorBlock + */ template class Block : public BlockImpl::StorageKind> { @@ -109,9 +109,12 @@ template class typedef Impl Base; EIGEN_GENERIC_PUBLIC_INTERFACE(Block) EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Block) + + typedef typename internal::remove_all::type NestedExpression; /** Column or Row constructor */ + EIGEN_DEVICE_FUNC inline Block(XprType& xpr, Index i) : Impl(xpr,i) { eigen_assert( (i>=0) && ( @@ -121,25 +124,27 @@ template class /** Fixed-size constructor */ - inline Block(XprType& xpr, Index a_startRow, Index a_startCol) - : Impl(xpr, a_startRow, a_startCol) + EIGEN_DEVICE_FUNC + inline Block(XprType& xpr, Index startRow, Index startCol) + : Impl(xpr, startRow, startCol) { EIGEN_STATIC_ASSERT(RowsAtCompileTime!=Dynamic && ColsAtCompileTime!=Dynamic,THIS_METHOD_IS_ONLY_FOR_FIXED_SIZE) - eigen_assert(a_startRow >= 0 && BlockRows >= 1 && a_startRow + BlockRows <= xpr.rows() - && a_startCol >= 0 && BlockCols >= 1 && a_startCol + BlockCols <= xpr.cols()); + eigen_assert(startRow >= 0 && BlockRows >= 0 && startRow + BlockRows <= xpr.rows() + && startCol >= 0 && BlockCols >= 0 && startCol + BlockCols <= xpr.cols()); } /** Dynamic-size constructor */ + EIGEN_DEVICE_FUNC inline Block(XprType& xpr, - Index a_startRow, Index a_startCol, + Index startRow, Index startCol, Index blockRows, Index blockCols) - : Impl(xpr, a_startRow, a_startCol, blockRows, blockCols) + : Impl(xpr, startRow, startCol, blockRows, blockCols) { eigen_assert((RowsAtCompileTime==Dynamic || RowsAtCompileTime==blockRows) && (ColsAtCompileTime==Dynamic || ColsAtCompileTime==blockCols)); - eigen_assert(a_startRow >= 0 && blockRows >= 0 && a_startRow <= xpr.rows() - blockRows - && a_startCol >= 0 && blockCols >= 0 && a_startCol <= xpr.cols() - blockCols); + eigen_assert(startRow >= 0 && blockRows >= 0 && startRow <= xpr.rows() - blockRows + && startCol >= 0 && blockCols >= 0 && startCol <= xpr.cols() - blockCols); } }; @@ -150,14 +155,15 @@ class BlockImpl : public internal::BlockImpl_dense { typedef internal::BlockImpl_dense Impl; - typedef typename XprType::Index Index; + typedef typename XprType::StorageIndex StorageIndex; public: typedef Impl Base; EIGEN_INHERIT_ASSIGNMENT_OPERATORS(BlockImpl) - inline BlockImpl(XprType& xpr, Index i) : Impl(xpr,i) {} - inline BlockImpl(XprType& xpr, Index a_startRow, Index a_startCol) : Impl(xpr, a_startRow, a_startCol) {} - inline BlockImpl(XprType& xpr, Index a_startRow, Index a_startCol, Index blockRows, Index blockCols) - : Impl(xpr, a_startRow, a_startCol, blockRows, blockCols) {} + EIGEN_DEVICE_FUNC inline BlockImpl(XprType& xpr, Index i) : Impl(xpr,i) {} + EIGEN_DEVICE_FUNC inline BlockImpl(XprType& xpr, Index startRow, Index startCol) : Impl(xpr, startRow, startCol) {} + EIGEN_DEVICE_FUNC + inline BlockImpl(XprType& xpr, Index startRow, Index startCol, Index blockRows, Index blockCols) + : Impl(xpr, startRow, startCol, blockRows, blockCols) {} }; namespace internal { @@ -167,16 +173,18 @@ template >::type { typedef Block BlockType; + typedef typename internal::ref_selector::non_const_type XprTypeNested; public: typedef typename internal::dense_xpr_base::type Base; EIGEN_DENSE_PUBLIC_INTERFACE(BlockType) EIGEN_INHERIT_ASSIGNMENT_OPERATORS(BlockImpl_dense) - class InnerIterator; + // class InnerIterator; // FIXME apparently never used /** Column or Row constructor */ + EIGEN_DEVICE_FUNC inline BlockImpl_dense(XprType& xpr, Index i) : m_xpr(xpr), // It is a row if and only if BlockRows==1 and BlockCols==XprType::ColsAtCompileTime, @@ -191,75 +199,76 @@ template inline PacketScalar packet(Index rowId, Index colId) const { - return m_xpr.template packet - (rowId + m_startRow.value(), colId + m_startCol.value()); + return m_xpr.template packet(rowId + m_startRow.value(), colId + m_startCol.value()); } template inline void writePacket(Index rowId, Index colId, const PacketScalar& val) { - m_xpr.const_cast_derived().template writePacket - (rowId + m_startRow.value(), colId + m_startCol.value(), val); + m_xpr.template writePacket(rowId + m_startRow.value(), colId + m_startCol.value(), val); } template @@ -273,40 +282,46 @@ template inline void writePacket(Index index, const PacketScalar& val) { - m_xpr.const_cast_derived().template writePacket + m_xpr.template writePacket (m_startRow.value() + (RowsAtCompileTime == 1 ? 0 : index), m_startCol.value() + (RowsAtCompileTime == 1 ? index : 0), val); } #ifdef EIGEN_PARSED_BY_DOXYGEN /** \sa MapBase::data() */ - inline const Scalar* data() const; - inline Index innerStride() const; - inline Index outerStride() const; + EIGEN_DEVICE_FUNC inline const Scalar* data() const; + EIGEN_DEVICE_FUNC inline Index innerStride() const; + EIGEN_DEVICE_FUNC inline Index outerStride() const; #endif - const typename internal::remove_all::type& nestedExpression() const + EIGEN_DEVICE_FUNC + const typename internal::remove_all::type& nestedExpression() const { return m_xpr; } + + EIGEN_DEVICE_FUNC + XprType& nestedExpression() { return m_xpr; } - Index startRow() const + EIGEN_DEVICE_FUNC + StorageIndex startRow() const { return m_startRow.value(); } - Index startCol() const + EIGEN_DEVICE_FUNC + StorageIndex startCol() const { return m_startCol.value(); } protected: - const typename XprType::Nested m_xpr; - const internal::variable_if_dynamic m_startRow; - const internal::variable_if_dynamic m_startCol; - const internal::variable_if_dynamic m_blockRows; - const internal::variable_if_dynamic m_blockCols; + XprTypeNested m_xpr; + const internal::variable_if_dynamic m_startRow; + const internal::variable_if_dynamic m_startCol; + const internal::variable_if_dynamic m_blockRows; + const internal::variable_if_dynamic m_blockCols; }; /** \internal Internal implementation of dense Blocks in the direct access case.*/ @@ -315,6 +330,10 @@ class BlockImpl_dense : public MapBase > { typedef Block BlockType; + typedef typename internal::ref_selector::non_const_type XprTypeNested; + enum { + XprTypeIsRowMajor = (int(traits::Flags)&RowMajorBit) != 0 + }; public: typedef MapBase Base; @@ -323,42 +342,52 @@ class BlockImpl_dense /** Column or Row constructor */ + EIGEN_DEVICE_FUNC inline BlockImpl_dense(XprType& xpr, Index i) - : Base(internal::const_cast_ptr(&xpr.coeffRef( - (BlockRows==1) && (BlockCols==XprType::ColsAtCompileTime) ? i : 0, - (BlockRows==XprType::RowsAtCompileTime) && (BlockCols==1) ? i : 0)), + : Base(xpr.data() + i * ( ((BlockRows==1) && (BlockCols==XprType::ColsAtCompileTime) && (!XprTypeIsRowMajor)) + || ((BlockRows==XprType::RowsAtCompileTime) && (BlockCols==1) && ( XprTypeIsRowMajor)) ? xpr.innerStride() : xpr.outerStride()), BlockRows==1 ? 1 : xpr.rows(), BlockCols==1 ? 1 : xpr.cols()), - m_xpr(xpr) + m_xpr(xpr), + m_startRow( (BlockRows==1) && (BlockCols==XprType::ColsAtCompileTime) ? i : 0), + m_startCol( (BlockRows==XprType::RowsAtCompileTime) && (BlockCols==1) ? i : 0) { init(); } /** Fixed-size constructor */ + EIGEN_DEVICE_FUNC inline BlockImpl_dense(XprType& xpr, Index startRow, Index startCol) - : Base(internal::const_cast_ptr(&xpr.coeffRef(startRow,startCol))), m_xpr(xpr) + : Base(xpr.data()+xpr.innerStride()*(XprTypeIsRowMajor?startCol:startRow) + xpr.outerStride()*(XprTypeIsRowMajor?startRow:startCol)), + m_xpr(xpr), m_startRow(startRow), m_startCol(startCol) { init(); } /** Dynamic-size constructor */ + EIGEN_DEVICE_FUNC inline BlockImpl_dense(XprType& xpr, Index startRow, Index startCol, Index blockRows, Index blockCols) - : Base(internal::const_cast_ptr(&xpr.coeffRef(startRow,startCol)), blockRows, blockCols), - m_xpr(xpr) + : Base(xpr.data()+xpr.innerStride()*(XprTypeIsRowMajor?startCol:startRow) + xpr.outerStride()*(XprTypeIsRowMajor?startRow:startCol), blockRows, blockCols), + m_xpr(xpr), m_startRow(startRow), m_startCol(startCol) { init(); } - const typename internal::remove_all::type& nestedExpression() const + EIGEN_DEVICE_FUNC + const typename internal::remove_all::type& nestedExpression() const { return m_xpr; } + + EIGEN_DEVICE_FUNC + XprType& nestedExpression() { return m_xpr; } /** \sa MapBase::innerStride() */ + EIGEN_DEVICE_FUNC inline Index innerStride() const { return internal::traits::HasSameStorageOrderAsXprType @@ -367,11 +396,24 @@ class BlockImpl_dense } /** \sa MapBase::outerStride() */ + EIGEN_DEVICE_FUNC inline Index outerStride() const { return m_outerStride; } + EIGEN_DEVICE_FUNC + StorageIndex startRow() const + { + return m_startRow.value(); + } + + EIGEN_DEVICE_FUNC + StorageIndex startCol() const + { + return m_startCol.value(); + } + #ifndef __SUNPRO_CC // FIXME sunstudio is not friendly with the above friend... // META-FIXME there is no 'friend' keyword around here. Is this obsolete? @@ -380,6 +422,7 @@ class BlockImpl_dense #ifndef EIGEN_PARSED_BY_DOXYGEN /** \internal used by allowAligned() */ + EIGEN_DEVICE_FUNC inline BlockImpl_dense(XprType& xpr, const Scalar* data, Index blockRows, Index blockCols) : Base(data, blockRows, blockCols), m_xpr(xpr) { @@ -388,6 +431,7 @@ class BlockImpl_dense #endif protected: + EIGEN_DEVICE_FUNC void init() { m_outerStride = internal::traits::HasSameStorageOrderAsXprType @@ -395,7 +439,9 @@ class BlockImpl_dense : m_xpr.innerStride(); } - typename XprType::Nested m_xpr; + XprTypeNested m_xpr; + const internal::variable_if_dynamic m_startRow; + const internal::variable_if_dynamic m_startCol; Index m_outerStride; }; diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Core/BooleanRedux.h b/ground/gcs/src/libs/eigen/Eigen/src/Core/BooleanRedux.h index be9f48a8c7..8409d8749a 100644 --- a/ground/gcs/src/libs/eigen/Eigen/src/Core/BooleanRedux.h +++ b/ground/gcs/src/libs/eigen/Eigen/src/Core/BooleanRedux.h @@ -17,9 +17,10 @@ namespace internal { template struct all_unroller { + typedef typename Derived::ExpressionTraits Traits; enum { - col = (UnrollCount-1) / Derived::RowsAtCompileTime, - row = (UnrollCount-1) % Derived::RowsAtCompileTime + col = (UnrollCount-1) / Traits::RowsAtCompileTime, + row = (UnrollCount-1) % Traits::RowsAtCompileTime }; static inline bool run(const Derived &mat) @@ -43,11 +44,12 @@ struct all_unroller template struct any_unroller { + typedef typename Derived::ExpressionTraits Traits; enum { - col = (UnrollCount-1) / Derived::RowsAtCompileTime, - row = (UnrollCount-1) % Derived::RowsAtCompileTime + col = (UnrollCount-1) / Traits::RowsAtCompileTime, + row = (UnrollCount-1) % Traits::RowsAtCompileTime }; - + static inline bool run(const Derived &mat) { return any_unroller::run(mat) || mat.coeff(row, col); @@ -78,19 +80,19 @@ struct any_unroller template inline bool DenseBase::all() const { + typedef internal::evaluator Evaluator; enum { unroll = SizeAtCompileTime != Dynamic - && CoeffReadCost != Dynamic - && NumTraits::AddCost != Dynamic - && SizeAtCompileTime * (CoeffReadCost + NumTraits::AddCost) <= EIGEN_UNROLLING_LIMIT + && SizeAtCompileTime * (Evaluator::CoeffReadCost + NumTraits::AddCost) <= EIGEN_UNROLLING_LIMIT }; + Evaluator evaluator(derived()); if(unroll) - return internal::all_unroller::run(derived()); + return internal::all_unroller::run(evaluator); else { for(Index j = 0; j < cols(); ++j) for(Index i = 0; i < rows(); ++i) - if (!coeff(i, j)) return false; + if (!evaluator.coeff(i, j)) return false; return true; } } @@ -102,19 +104,19 @@ inline bool DenseBase::all() const template inline bool DenseBase::any() const { + typedef internal::evaluator Evaluator; enum { unroll = SizeAtCompileTime != Dynamic - && CoeffReadCost != Dynamic - && NumTraits::AddCost != Dynamic - && SizeAtCompileTime * (CoeffReadCost + NumTraits::AddCost) <= EIGEN_UNROLLING_LIMIT + && SizeAtCompileTime * (Evaluator::CoeffReadCost + NumTraits::AddCost) <= EIGEN_UNROLLING_LIMIT }; + Evaluator evaluator(derived()); if(unroll) - return internal::any_unroller::run(derived()); + return internal::any_unroller::run(evaluator); else { for(Index j = 0; j < cols(); ++j) for(Index i = 0; i < rows(); ++i) - if (coeff(i, j)) return true; + if (evaluator.coeff(i, j)) return true; return false; } } @@ -124,7 +126,7 @@ inline bool DenseBase::any() const * \sa all(), any() */ template -inline typename DenseBase::Index DenseBase::count() const +inline Eigen::Index DenseBase::count() const { return derived().template cast().template cast().sum(); } @@ -136,7 +138,11 @@ inline typename DenseBase::Index DenseBase::count() const template inline bool DenseBase::hasNaN() const { +#if EIGEN_COMP_MSVC || (defined __FAST_MATH__) + return derived().array().isNaN().any(); +#else return !((derived().array()==derived().array()).all()); +#endif } /** \returns true if \c *this contains only finite numbers, i.e., no NaN and no +/-INF values. @@ -146,7 +152,11 @@ inline bool DenseBase::hasNaN() const template inline bool DenseBase::allFinite() const { +#if EIGEN_COMP_MSVC || (defined __FAST_MATH__) + return derived().array().isFinite().all(); +#else return !((derived()-derived()).hasNaN()); +#endif } } // end namespace Eigen diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Core/CMakeLists.txt b/ground/gcs/src/libs/eigen/Eigen/src/Core/CMakeLists.txt deleted file mode 100644 index 2346fc2bbc..0000000000 --- a/ground/gcs/src/libs/eigen/Eigen/src/Core/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -FILE(GLOB Eigen_Core_SRCS "*.h") - -INSTALL(FILES - ${Eigen_Core_SRCS} - DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/Core COMPONENT Devel - ) - -ADD_SUBDIRECTORY(products) -ADD_SUBDIRECTORY(util) -ADD_SUBDIRECTORY(arch) diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Core/CommaInitializer.h b/ground/gcs/src/libs/eigen/Eigen/src/Core/CommaInitializer.h index a036d8c3bc..d218e98143 100644 --- a/ground/gcs/src/libs/eigen/Eigen/src/Core/CommaInitializer.h +++ b/ground/gcs/src/libs/eigen/Eigen/src/Core/CommaInitializer.h @@ -22,14 +22,14 @@ namespace Eigen { * the return type of MatrixBase::operator<<, and most of the time this is the only * way it is used. * - * \sa \ref MatrixBaseCommaInitRef "MatrixBase::operator<<", CommaInitializer::finished() + * \sa \blank \ref MatrixBaseCommaInitRef "MatrixBase::operator<<", CommaInitializer::finished() */ template struct CommaInitializer { typedef typename XprType::Scalar Scalar; - typedef typename XprType::Index Index; + EIGEN_DEVICE_FUNC inline CommaInitializer(XprType& xpr, const Scalar& s) : m_xpr(xpr), m_row(0), m_col(1), m_currentBlockRows(1) { @@ -37,6 +37,7 @@ struct CommaInitializer } template + EIGEN_DEVICE_FUNC inline CommaInitializer(XprType& xpr, const DenseBase& other) : m_xpr(xpr), m_row(0), m_col(other.cols()), m_currentBlockRows(other.rows()) { @@ -46,6 +47,7 @@ struct CommaInitializer /* Copy/Move constructor which transfers ownership. This is crucial in * absence of return value optimization to avoid assertions during destruction. */ // FIXME in C++11 mode this could be replaced by a proper RValue constructor + EIGEN_DEVICE_FUNC inline CommaInitializer(const CommaInitializer& o) : m_xpr(o.m_xpr), m_row(o.m_row), m_col(o.m_col), m_currentBlockRows(o.m_currentBlockRows) { // Mark original object as finished. In absence of R-value references we need to const_cast: @@ -55,6 +57,7 @@ struct CommaInitializer } /* inserts a scalar value in the target matrix */ + EIGEN_DEVICE_FUNC CommaInitializer& operator,(const Scalar& s) { if (m_col==m_xpr.cols()) @@ -74,11 +77,10 @@ struct CommaInitializer /* inserts a matrix expression in the target matrix */ template + EIGEN_DEVICE_FUNC CommaInitializer& operator,(const DenseBase& other) { - if(other.cols()==0 || other.rows()==0) - return *this; - if (m_col==m_xpr.cols()) + if (m_col==m_xpr.cols() && (other.cols()!=0 || other.rows()!=m_currentBlockRows)) { m_row+=m_currentBlockRows; m_col = 0; @@ -86,24 +88,22 @@ struct CommaInitializer eigen_assert(m_row+m_currentBlockRows<=m_xpr.rows() && "Too many rows passed to comma initializer (operator<<)"); } - eigen_assert(m_col - (m_row, m_col) = other; - else - m_xpr.block(m_row, m_col, other.rows(), other.cols()) = other; + m_xpr.template block + (m_row, m_col, other.rows(), other.cols()) = other; m_col += other.cols(); return *this; } + EIGEN_DEVICE_FUNC inline ~CommaInitializer() +#if defined VERIFY_RAISES_ASSERT && (!defined EIGEN_NO_ASSERTION_CHECKING) && defined EIGEN_EXCEPTIONS + EIGEN_EXCEPTION_SPEC(Eigen::eigen_assert_exception) +#endif { - eigen_assert((m_row+m_currentBlockRows) == m_xpr.rows() - && m_col == m_xpr.cols() - && "Too few coefficients passed to comma initializer (operator<<)"); + finished(); } /** \returns the built matrix once all its coefficients have been set. @@ -113,9 +113,15 @@ struct CommaInitializer * quaternion.fromRotationMatrix((Matrix3f() << axis0, axis1, axis2).finished()); * \endcode */ - inline XprType& finished() { return m_xpr; } + EIGEN_DEVICE_FUNC + inline XprType& finished() { + eigen_assert(((m_row+m_currentBlockRows) == m_xpr.rows() || m_xpr.cols() == 0) + && m_col == m_xpr.cols() + && "Too few coefficients passed to comma initializer (operator<<)"); + return m_xpr; + } - XprType& m_xpr; // target expression + XprType& m_xpr; // target expression Index m_row; // current row id Index m_col; // current col id Index m_currentBlockRows; // current block height diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Core/ConditionEstimator.h b/ground/gcs/src/libs/eigen/Eigen/src/Core/ConditionEstimator.h new file mode 100644 index 0000000000..aa7efdc765 --- /dev/null +++ b/ground/gcs/src/libs/eigen/Eigen/src/Core/ConditionEstimator.h @@ -0,0 +1,175 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2016 Rasmus Munk Larsen (rmlarsen@google.com) +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CONDITIONESTIMATOR_H +#define EIGEN_CONDITIONESTIMATOR_H + +namespace Eigen { + +namespace internal { + +template +struct rcond_compute_sign { + static inline Vector run(const Vector& v) { + const RealVector v_abs = v.cwiseAbs(); + return (v_abs.array() == static_cast(0)) + .select(Vector::Ones(v.size()), v.cwiseQuotient(v_abs)); + } +}; + +// Partial specialization to avoid elementwise division for real vectors. +template +struct rcond_compute_sign { + static inline Vector run(const Vector& v) { + return (v.array() < static_cast(0)) + .select(-Vector::Ones(v.size()), Vector::Ones(v.size())); + } +}; + +/** + * \returns an estimate of ||inv(matrix)||_1 given a decomposition of + * \a matrix that implements .solve() and .adjoint().solve() methods. + * + * This function implements Algorithms 4.1 and 5.1 from + * http://www.maths.manchester.ac.uk/~higham/narep/narep135.pdf + * which also forms the basis for the condition number estimators in + * LAPACK. Since at most 10 calls to the solve method of dec are + * performed, the total cost is O(dims^2), as opposed to O(dims^3) + * needed to compute the inverse matrix explicitly. + * + * The most common usage is in estimating the condition number + * ||matrix||_1 * ||inv(matrix)||_1. The first term ||matrix||_1 can be + * computed directly in O(n^2) operations. + * + * Supports the following decompositions: FullPivLU, PartialPivLU, LDLT, and + * LLT. + * + * \sa FullPivLU, PartialPivLU, LDLT, LLT. + */ +template +typename Decomposition::RealScalar rcond_invmatrix_L1_norm_estimate(const Decomposition& dec) +{ + typedef typename Decomposition::MatrixType MatrixType; + typedef typename Decomposition::Scalar Scalar; + typedef typename Decomposition::RealScalar RealScalar; + typedef typename internal::plain_col_type::type Vector; + typedef typename internal::plain_col_type::type RealVector; + const bool is_complex = (NumTraits::IsComplex != 0); + + eigen_assert(dec.rows() == dec.cols()); + const Index n = dec.rows(); + if (n == 0) + return 0; + + // Disable Index to float conversion warning +#ifdef __INTEL_COMPILER + #pragma warning push + #pragma warning ( disable : 2259 ) +#endif + Vector v = dec.solve(Vector::Ones(n) / Scalar(n)); +#ifdef __INTEL_COMPILER + #pragma warning pop +#endif + + // lower_bound is a lower bound on + // ||inv(matrix)||_1 = sup_v ||inv(matrix) v||_1 / ||v||_1 + // and is the objective maximized by the ("super-") gradient ascent + // algorithm below. + RealScalar lower_bound = v.template lpNorm<1>(); + if (n == 1) + return lower_bound; + + // Gradient ascent algorithm follows: We know that the optimum is achieved at + // one of the simplices v = e_i, so in each iteration we follow a + // super-gradient to move towards the optimal one. + RealScalar old_lower_bound = lower_bound; + Vector sign_vector(n); + Vector old_sign_vector; + Index v_max_abs_index = -1; + Index old_v_max_abs_index = v_max_abs_index; + for (int k = 0; k < 4; ++k) + { + sign_vector = internal::rcond_compute_sign::run(v); + if (k > 0 && !is_complex && sign_vector == old_sign_vector) { + // Break if the solution stagnated. + break; + } + // v_max_abs_index = argmax |real( inv(matrix)^T * sign_vector )| + v = dec.adjoint().solve(sign_vector); + v.real().cwiseAbs().maxCoeff(&v_max_abs_index); + if (v_max_abs_index == old_v_max_abs_index) { + // Break if the solution stagnated. + break; + } + // Move to the new simplex e_j, where j = v_max_abs_index. + v = dec.solve(Vector::Unit(n, v_max_abs_index)); // v = inv(matrix) * e_j. + lower_bound = v.template lpNorm<1>(); + if (lower_bound <= old_lower_bound) { + // Break if the gradient step did not increase the lower_bound. + break; + } + if (!is_complex) { + old_sign_vector = sign_vector; + } + old_v_max_abs_index = v_max_abs_index; + old_lower_bound = lower_bound; + } + // The following calculates an independent estimate of ||matrix||_1 by + // multiplying matrix by a vector with entries of slowly increasing + // magnitude and alternating sign: + // v_i = (-1)^{i} (1 + (i / (dim-1))), i = 0,...,dim-1. + // This improvement to Hager's algorithm above is due to Higham. It was + // added to make the algorithm more robust in certain corner cases where + // large elements in the matrix might otherwise escape detection due to + // exact cancellation (especially when op and op_adjoint correspond to a + // sequence of backsubstitutions and permutations), which could cause + // Hager's algorithm to vastly underestimate ||matrix||_1. + Scalar alternating_sign(RealScalar(1)); + for (Index i = 0; i < n; ++i) { + // The static_cast is needed when Scalar is a complex and RealScalar implements expression templates + v[i] = alternating_sign * static_cast(RealScalar(1) + (RealScalar(i) / (RealScalar(n - 1)))); + alternating_sign = -alternating_sign; + } + v = dec.solve(v); + const RealScalar alternate_lower_bound = (2 * v.template lpNorm<1>()) / (3 * RealScalar(n)); + return numext::maxi(lower_bound, alternate_lower_bound); +} + +/** \brief Reciprocal condition number estimator. + * + * Computing a decomposition of a dense matrix takes O(n^3) operations, while + * this method estimates the condition number quickly and reliably in O(n^2) + * operations. + * + * \returns an estimate of the reciprocal condition number + * (1 / (||matrix||_1 * ||inv(matrix)||_1)) of matrix, given ||matrix||_1 and + * its decomposition. Supports the following decompositions: FullPivLU, + * PartialPivLU, LDLT, and LLT. + * + * \sa FullPivLU, PartialPivLU, LDLT, LLT. + */ +template +typename Decomposition::RealScalar +rcond_estimate_helper(typename Decomposition::RealScalar matrix_norm, const Decomposition& dec) +{ + typedef typename Decomposition::RealScalar RealScalar; + eigen_assert(dec.rows() == dec.cols()); + if (dec.rows() == 0) return RealScalar(1); + if (matrix_norm == RealScalar(0)) return RealScalar(0); + if (dec.rows() == 1) return RealScalar(1); + const RealScalar inverse_matrix_norm = rcond_invmatrix_L1_norm_estimate(dec); + return (inverse_matrix_norm == RealScalar(0) ? RealScalar(0) + : (RealScalar(1) / inverse_matrix_norm) / matrix_norm); +} + +} // namespace internal + +} // namespace Eigen + +#endif diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Core/CoreEvaluators.h b/ground/gcs/src/libs/eigen/Eigen/src/Core/CoreEvaluators.h new file mode 100644 index 0000000000..f7c1effca7 --- /dev/null +++ b/ground/gcs/src/libs/eigen/Eigen/src/Core/CoreEvaluators.h @@ -0,0 +1,1671 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2011 Benoit Jacob +// Copyright (C) 2011-2014 Gael Guennebaud +// Copyright (C) 2011-2012 Jitse Niesen +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + + +#ifndef EIGEN_COREEVALUATORS_H +#define EIGEN_COREEVALUATORS_H + +namespace Eigen { + +namespace internal { + +// This class returns the evaluator kind from the expression storage kind. +// Default assumes index based accessors +template +struct storage_kind_to_evaluator_kind { + typedef IndexBased Kind; +}; + +// This class returns the evaluator shape from the expression storage kind. +// It can be Dense, Sparse, Triangular, Diagonal, SelfAdjoint, Band, etc. +template struct storage_kind_to_shape; + +template<> struct storage_kind_to_shape { typedef DenseShape Shape; }; +template<> struct storage_kind_to_shape { typedef SolverShape Shape; }; +template<> struct storage_kind_to_shape { typedef PermutationShape Shape; }; +template<> struct storage_kind_to_shape { typedef TranspositionsShape Shape; }; + +// Evaluators have to be specialized with respect to various criteria such as: +// - storage/structure/shape +// - scalar type +// - etc. +// Therefore, we need specialization of evaluator providing additional template arguments for each kind of evaluators. +// We currently distinguish the following kind of evaluators: +// - unary_evaluator for expressions taking only one arguments (CwiseUnaryOp, CwiseUnaryView, Transpose, MatrixWrapper, ArrayWrapper, Reverse, Replicate) +// - binary_evaluator for expression taking two arguments (CwiseBinaryOp) +// - ternary_evaluator for expression taking three arguments (CwiseTernaryOp) +// - product_evaluator for linear algebra products (Product); special case of binary_evaluator because it requires additional tags for dispatching. +// - mapbase_evaluator for Map, Block, Ref +// - block_evaluator for Block (special dispatching to a mapbase_evaluator or unary_evaluator) + +template< typename T, + typename Arg1Kind = typename evaluator_traits::Kind, + typename Arg2Kind = typename evaluator_traits::Kind, + typename Arg3Kind = typename evaluator_traits::Kind, + typename Arg1Scalar = typename traits::Scalar, + typename Arg2Scalar = typename traits::Scalar, + typename Arg3Scalar = typename traits::Scalar> struct ternary_evaluator; + +template< typename T, + typename LhsKind = typename evaluator_traits::Kind, + typename RhsKind = typename evaluator_traits::Kind, + typename LhsScalar = typename traits::Scalar, + typename RhsScalar = typename traits::Scalar> struct binary_evaluator; + +template< typename T, + typename Kind = typename evaluator_traits::Kind, + typename Scalar = typename T::Scalar> struct unary_evaluator; + +// evaluator_traits contains traits for evaluator + +template +struct evaluator_traits_base +{ + // by default, get evaluator kind and shape from storage + typedef typename storage_kind_to_evaluator_kind::StorageKind>::Kind Kind; + typedef typename storage_kind_to_shape::StorageKind>::Shape Shape; +}; + +// Default evaluator traits +template +struct evaluator_traits : public evaluator_traits_base +{ +}; + +template::Shape > +struct evaluator_assume_aliasing { + static const bool value = false; +}; + +// By default, we assume a unary expression: +template +struct evaluator : public unary_evaluator +{ + typedef unary_evaluator Base; + EIGEN_DEVICE_FUNC explicit evaluator(const T& xpr) : Base(xpr) {} +}; + + +// TODO: Think about const-correctness +template +struct evaluator + : evaluator +{ + EIGEN_DEVICE_FUNC + explicit evaluator(const T& xpr) : evaluator(xpr) {} +}; + +// ---------- base class for all evaluators ---------- + +template +struct evaluator_base : public noncopyable +{ + // TODO that's not very nice to have to propagate all these traits. They are currently only needed to handle outer,inner indices. + typedef traits ExpressionTraits; + + enum { + Alignment = 0 + }; +}; + +// -------------------- Matrix and Array -------------------- +// +// evaluator is a common base class for the +// Matrix and Array evaluators. +// Here we directly specialize evaluator. This is not really a unary expression, and it is, by definition, dense, +// so no need for more sophisticated dispatching. + +template +struct evaluator > + : evaluator_base +{ + typedef PlainObjectBase PlainObjectType; + typedef typename PlainObjectType::Scalar Scalar; + typedef typename PlainObjectType::CoeffReturnType CoeffReturnType; + + enum { + IsRowMajor = PlainObjectType::IsRowMajor, + IsVectorAtCompileTime = PlainObjectType::IsVectorAtCompileTime, + RowsAtCompileTime = PlainObjectType::RowsAtCompileTime, + ColsAtCompileTime = PlainObjectType::ColsAtCompileTime, + + CoeffReadCost = NumTraits::ReadCost, + Flags = traits::EvaluatorFlags, + Alignment = traits::Alignment + }; + + EIGEN_DEVICE_FUNC evaluator() + : m_data(0), + m_outerStride(IsVectorAtCompileTime ? 0 + : int(IsRowMajor) ? ColsAtCompileTime + : RowsAtCompileTime) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + + EIGEN_DEVICE_FUNC explicit evaluator(const PlainObjectType& m) + : m_data(m.data()), m_outerStride(IsVectorAtCompileTime ? 0 : m.outerStride()) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index row, Index col) const + { + if (IsRowMajor) + return m_data[row * m_outerStride.value() + col]; + else + return m_data[row + col * m_outerStride.value()]; + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index index) const + { + return m_data[index]; + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Scalar& coeffRef(Index row, Index col) + { + if (IsRowMajor) + return const_cast(m_data)[row * m_outerStride.value() + col]; + else + return const_cast(m_data)[row + col * m_outerStride.value()]; + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Scalar& coeffRef(Index index) + { + return const_cast(m_data)[index]; + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index row, Index col) const + { + if (IsRowMajor) + return ploadt(m_data + row * m_outerStride.value() + col); + else + return ploadt(m_data + row + col * m_outerStride.value()); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index index) const + { + return ploadt(m_data + index); + } + + template + EIGEN_STRONG_INLINE + void writePacket(Index row, Index col, const PacketType& x) + { + if (IsRowMajor) + return pstoret + (const_cast(m_data) + row * m_outerStride.value() + col, x); + else + return pstoret + (const_cast(m_data) + row + col * m_outerStride.value(), x); + } + + template + EIGEN_STRONG_INLINE + void writePacket(Index index, const PacketType& x) + { + return pstoret(const_cast(m_data) + index, x); + } + +protected: + const Scalar *m_data; + + // We do not need to know the outer stride for vectors + variable_if_dynamic m_outerStride; +}; + +template +struct evaluator > + : evaluator > > +{ + typedef Matrix XprType; + + EIGEN_DEVICE_FUNC evaluator() {} + + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& m) + : evaluator >(m) + { } +}; + +template +struct evaluator > + : evaluator > > +{ + typedef Array XprType; + + EIGEN_DEVICE_FUNC evaluator() {} + + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& m) + : evaluator >(m) + { } +}; + +// -------------------- Transpose -------------------- + +template +struct unary_evaluator, IndexBased> + : evaluator_base > +{ + typedef Transpose XprType; + + enum { + CoeffReadCost = evaluator::CoeffReadCost, + Flags = evaluator::Flags ^ RowMajorBit, + Alignment = evaluator::Alignment + }; + + EIGEN_DEVICE_FUNC explicit unary_evaluator(const XprType& t) : m_argImpl(t.nestedExpression()) {} + + typedef typename XprType::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index row, Index col) const + { + return m_argImpl.coeff(col, row); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index index) const + { + return m_argImpl.coeff(index); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Scalar& coeffRef(Index row, Index col) + { + return m_argImpl.coeffRef(col, row); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + typename XprType::Scalar& coeffRef(Index index) + { + return m_argImpl.coeffRef(index); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index row, Index col) const + { + return m_argImpl.template packet(col, row); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index index) const + { + return m_argImpl.template packet(index); + } + + template + EIGEN_STRONG_INLINE + void writePacket(Index row, Index col, const PacketType& x) + { + m_argImpl.template writePacket(col, row, x); + } + + template + EIGEN_STRONG_INLINE + void writePacket(Index index, const PacketType& x) + { + m_argImpl.template writePacket(index, x); + } + +protected: + evaluator m_argImpl; +}; + +// -------------------- CwiseNullaryOp -------------------- +// Like Matrix and Array, this is not really a unary expression, so we directly specialize evaluator. +// Likewise, there is not need to more sophisticated dispatching here. + +template::value, + bool has_unary = has_unary_operator::value, + bool has_binary = has_binary_operator::value> +struct nullary_wrapper +{ + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const NullaryOp& op, IndexType i, IndexType j) const { return op(i,j); } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const NullaryOp& op, IndexType i) const { return op(i); } + + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T packetOp(const NullaryOp& op, IndexType i, IndexType j) const { return op.template packetOp(i,j); } + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T packetOp(const NullaryOp& op, IndexType i) const { return op.template packetOp(i); } +}; + +template +struct nullary_wrapper +{ + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const NullaryOp& op, IndexType=0, IndexType=0) const { return op(); } + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T packetOp(const NullaryOp& op, IndexType=0, IndexType=0) const { return op.template packetOp(); } +}; + +template +struct nullary_wrapper +{ + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const NullaryOp& op, IndexType i, IndexType j=0) const { return op(i,j); } + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T packetOp(const NullaryOp& op, IndexType i, IndexType j=0) const { return op.template packetOp(i,j); } +}; + +// We need the following specialization for vector-only functors assigned to a runtime vector, +// for instance, using linspace and assigning a RowVectorXd to a MatrixXd or even a row of a MatrixXd. +// In this case, i==0 and j is used for the actual iteration. +template +struct nullary_wrapper +{ + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const NullaryOp& op, IndexType i, IndexType j) const { + eigen_assert(i==0 || j==0); + return op(i+j); + } + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T packetOp(const NullaryOp& op, IndexType i, IndexType j) const { + eigen_assert(i==0 || j==0); + return op.template packetOp(i+j); + } + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const NullaryOp& op, IndexType i) const { return op(i); } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T packetOp(const NullaryOp& op, IndexType i) const { return op.template packetOp(i); } +}; + +template +struct nullary_wrapper {}; + +#if 0 && EIGEN_COMP_MSVC>0 +// Disable this ugly workaround. This is now handled in traits::match, +// but this piece of code might still become handly if some other weird compilation +// erros pop up again. + +// MSVC exhibits a weird compilation error when +// compiling: +// Eigen::MatrixXf A = MatrixXf::Random(3,3); +// Ref R = 2.f*A; +// and that has_*ary_operator> have not been instantiated yet. +// The "problem" is that evaluator<2.f*A> is instantiated by traits::match<2.f*A> +// and at that time has_*ary_operator returns true regardless of T. +// Then nullary_wrapper is badly instantiated as nullary_wrapper<.,.,true,true,true>. +// The trick is thus to defer the proper instantiation of nullary_wrapper when coeff(), +// and packet() are really instantiated as implemented below: + +// This is a simple wrapper around Index to enforce the re-instantiation of +// has_*ary_operator when needed. +template struct nullary_wrapper_workaround_msvc { + nullary_wrapper_workaround_msvc(const T&); + operator T()const; +}; + +template +struct nullary_wrapper +{ + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const NullaryOp& op, IndexType i, IndexType j) const { + return nullary_wrapper >::value, + has_unary_operator >::value, + has_binary_operator >::value>().operator()(op,i,j); + } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const NullaryOp& op, IndexType i) const { + return nullary_wrapper >::value, + has_unary_operator >::value, + has_binary_operator >::value>().operator()(op,i); + } + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T packetOp(const NullaryOp& op, IndexType i, IndexType j) const { + return nullary_wrapper >::value, + has_unary_operator >::value, + has_binary_operator >::value>().template packetOp(op,i,j); + } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T packetOp(const NullaryOp& op, IndexType i) const { + return nullary_wrapper >::value, + has_unary_operator >::value, + has_binary_operator >::value>().template packetOp(op,i); + } +}; +#endif // MSVC workaround + +template +struct evaluator > + : evaluator_base > +{ + typedef CwiseNullaryOp XprType; + typedef typename internal::remove_all::type PlainObjectTypeCleaned; + + enum { + CoeffReadCost = internal::functor_traits::Cost, + + Flags = (evaluator::Flags + & ( HereditaryBits + | (functor_has_linear_access::ret ? LinearAccessBit : 0) + | (functor_traits::PacketAccess ? PacketAccessBit : 0))) + | (functor_traits::IsRepeatable ? 0 : EvalBeforeNestingBit), + Alignment = AlignedMax + }; + + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& n) + : m_functor(n.functor()), m_wrapper() + { + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + + typedef typename XprType::CoeffReturnType CoeffReturnType; + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(IndexType row, IndexType col) const + { + return m_wrapper(m_functor, row, col); + } + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(IndexType index) const + { + return m_wrapper(m_functor,index); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(IndexType row, IndexType col) const + { + return m_wrapper.template packetOp(m_functor, row, col); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(IndexType index) const + { + return m_wrapper.template packetOp(m_functor, index); + } + +protected: + const NullaryOp m_functor; + const internal::nullary_wrapper m_wrapper; +}; + +// -------------------- CwiseUnaryOp -------------------- + +template +struct unary_evaluator, IndexBased > + : evaluator_base > +{ + typedef CwiseUnaryOp XprType; + + enum { + CoeffReadCost = evaluator::CoeffReadCost + functor_traits::Cost, + + Flags = evaluator::Flags + & (HereditaryBits | LinearAccessBit | (functor_traits::PacketAccess ? PacketAccessBit : 0)), + Alignment = evaluator::Alignment + }; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + explicit unary_evaluator(const XprType& op) + : m_functor(op.functor()), + m_argImpl(op.nestedExpression()) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(functor_traits::Cost); + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + + typedef typename XprType::CoeffReturnType CoeffReturnType; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index row, Index col) const + { + return m_functor(m_argImpl.coeff(row, col)); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index index) const + { + return m_functor(m_argImpl.coeff(index)); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index row, Index col) const + { + return m_functor.packetOp(m_argImpl.template packet(row, col)); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index index) const + { + return m_functor.packetOp(m_argImpl.template packet(index)); + } + +protected: + const UnaryOp m_functor; + evaluator m_argImpl; +}; + +// -------------------- CwiseTernaryOp -------------------- + +// this is a ternary expression +template +struct evaluator > + : public ternary_evaluator > +{ + typedef CwiseTernaryOp XprType; + typedef ternary_evaluator > Base; + + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& xpr) : Base(xpr) {} +}; + +template +struct ternary_evaluator, IndexBased, IndexBased> + : evaluator_base > +{ + typedef CwiseTernaryOp XprType; + + enum { + CoeffReadCost = evaluator::CoeffReadCost + evaluator::CoeffReadCost + evaluator::CoeffReadCost + functor_traits::Cost, + + Arg1Flags = evaluator::Flags, + Arg2Flags = evaluator::Flags, + Arg3Flags = evaluator::Flags, + SameType = is_same::value && is_same::value, + StorageOrdersAgree = (int(Arg1Flags)&RowMajorBit)==(int(Arg2Flags)&RowMajorBit) && (int(Arg1Flags)&RowMajorBit)==(int(Arg3Flags)&RowMajorBit), + Flags0 = (int(Arg1Flags) | int(Arg2Flags) | int(Arg3Flags)) & ( + HereditaryBits + | (int(Arg1Flags) & int(Arg2Flags) & int(Arg3Flags) & + ( (StorageOrdersAgree ? LinearAccessBit : 0) + | (functor_traits::PacketAccess && StorageOrdersAgree && SameType ? PacketAccessBit : 0) + ) + ) + ), + Flags = (Flags0 & ~RowMajorBit) | (Arg1Flags & RowMajorBit), + Alignment = EIGEN_PLAIN_ENUM_MIN( + EIGEN_PLAIN_ENUM_MIN(evaluator::Alignment, evaluator::Alignment), + evaluator::Alignment) + }; + + EIGEN_DEVICE_FUNC explicit ternary_evaluator(const XprType& xpr) + : m_functor(xpr.functor()), + m_arg1Impl(xpr.arg1()), + m_arg2Impl(xpr.arg2()), + m_arg3Impl(xpr.arg3()) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(functor_traits::Cost); + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + + typedef typename XprType::CoeffReturnType CoeffReturnType; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index row, Index col) const + { + return m_functor(m_arg1Impl.coeff(row, col), m_arg2Impl.coeff(row, col), m_arg3Impl.coeff(row, col)); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index index) const + { + return m_functor(m_arg1Impl.coeff(index), m_arg2Impl.coeff(index), m_arg3Impl.coeff(index)); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index row, Index col) const + { + return m_functor.packetOp(m_arg1Impl.template packet(row, col), + m_arg2Impl.template packet(row, col), + m_arg3Impl.template packet(row, col)); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index index) const + { + return m_functor.packetOp(m_arg1Impl.template packet(index), + m_arg2Impl.template packet(index), + m_arg3Impl.template packet(index)); + } + +protected: + const TernaryOp m_functor; + evaluator m_arg1Impl; + evaluator m_arg2Impl; + evaluator m_arg3Impl; +}; + +// -------------------- CwiseBinaryOp -------------------- + +// this is a binary expression +template +struct evaluator > + : public binary_evaluator > +{ + typedef CwiseBinaryOp XprType; + typedef binary_evaluator > Base; + + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& xpr) : Base(xpr) {} +}; + +template +struct binary_evaluator, IndexBased, IndexBased> + : evaluator_base > +{ + typedef CwiseBinaryOp XprType; + + enum { + CoeffReadCost = evaluator::CoeffReadCost + evaluator::CoeffReadCost + functor_traits::Cost, + + LhsFlags = evaluator::Flags, + RhsFlags = evaluator::Flags, + SameType = is_same::value, + StorageOrdersAgree = (int(LhsFlags)&RowMajorBit)==(int(RhsFlags)&RowMajorBit), + Flags0 = (int(LhsFlags) | int(RhsFlags)) & ( + HereditaryBits + | (int(LhsFlags) & int(RhsFlags) & + ( (StorageOrdersAgree ? LinearAccessBit : 0) + | (functor_traits::PacketAccess && StorageOrdersAgree && SameType ? PacketAccessBit : 0) + ) + ) + ), + Flags = (Flags0 & ~RowMajorBit) | (LhsFlags & RowMajorBit), + Alignment = EIGEN_PLAIN_ENUM_MIN(evaluator::Alignment,evaluator::Alignment) + }; + + EIGEN_DEVICE_FUNC explicit binary_evaluator(const XprType& xpr) + : m_functor(xpr.functor()), + m_lhsImpl(xpr.lhs()), + m_rhsImpl(xpr.rhs()) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(functor_traits::Cost); + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + + typedef typename XprType::CoeffReturnType CoeffReturnType; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index row, Index col) const + { + return m_functor(m_lhsImpl.coeff(row, col), m_rhsImpl.coeff(row, col)); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index index) const + { + return m_functor(m_lhsImpl.coeff(index), m_rhsImpl.coeff(index)); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index row, Index col) const + { + return m_functor.packetOp(m_lhsImpl.template packet(row, col), + m_rhsImpl.template packet(row, col)); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index index) const + { + return m_functor.packetOp(m_lhsImpl.template packet(index), + m_rhsImpl.template packet(index)); + } + +protected: + const BinaryOp m_functor; + evaluator m_lhsImpl; + evaluator m_rhsImpl; +}; + +// -------------------- CwiseUnaryView -------------------- + +template +struct unary_evaluator, IndexBased> + : evaluator_base > +{ + typedef CwiseUnaryView XprType; + + enum { + CoeffReadCost = evaluator::CoeffReadCost + functor_traits::Cost, + + Flags = (evaluator::Flags & (HereditaryBits | LinearAccessBit | DirectAccessBit)), + + Alignment = 0 // FIXME it is not very clear why alignment is necessarily lost... + }; + + EIGEN_DEVICE_FUNC explicit unary_evaluator(const XprType& op) + : m_unaryOp(op.functor()), + m_argImpl(op.nestedExpression()) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(functor_traits::Cost); + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + + typedef typename XprType::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index row, Index col) const + { + return m_unaryOp(m_argImpl.coeff(row, col)); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index index) const + { + return m_unaryOp(m_argImpl.coeff(index)); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Scalar& coeffRef(Index row, Index col) + { + return m_unaryOp(m_argImpl.coeffRef(row, col)); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Scalar& coeffRef(Index index) + { + return m_unaryOp(m_argImpl.coeffRef(index)); + } + +protected: + const UnaryOp m_unaryOp; + evaluator m_argImpl; +}; + +// -------------------- Map -------------------- + +// FIXME perhaps the PlainObjectType could be provided by Derived::PlainObject ? +// but that might complicate template specialization +template +struct mapbase_evaluator; + +template +struct mapbase_evaluator : evaluator_base +{ + typedef Derived XprType; + typedef typename XprType::PointerType PointerType; + typedef typename XprType::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + + enum { + IsRowMajor = XprType::RowsAtCompileTime, + ColsAtCompileTime = XprType::ColsAtCompileTime, + CoeffReadCost = NumTraits::ReadCost + }; + + EIGEN_DEVICE_FUNC explicit mapbase_evaluator(const XprType& map) + : m_data(const_cast(map.data())), + m_innerStride(map.innerStride()), + m_outerStride(map.outerStride()) + { + EIGEN_STATIC_ASSERT(EIGEN_IMPLIES(evaluator::Flags&PacketAccessBit, internal::inner_stride_at_compile_time::ret==1), + PACKET_ACCESS_REQUIRES_TO_HAVE_INNER_STRIDE_FIXED_TO_1); + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index row, Index col) const + { + return m_data[col * colStride() + row * rowStride()]; + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index index) const + { + return m_data[index * m_innerStride.value()]; + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Scalar& coeffRef(Index row, Index col) + { + return m_data[col * colStride() + row * rowStride()]; + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Scalar& coeffRef(Index index) + { + return m_data[index * m_innerStride.value()]; + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index row, Index col) const + { + PointerType ptr = m_data + row * rowStride() + col * colStride(); + return internal::ploadt(ptr); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index index) const + { + return internal::ploadt(m_data + index * m_innerStride.value()); + } + + template + EIGEN_STRONG_INLINE + void writePacket(Index row, Index col, const PacketType& x) + { + PointerType ptr = m_data + row * rowStride() + col * colStride(); + return internal::pstoret(ptr, x); + } + + template + EIGEN_STRONG_INLINE + void writePacket(Index index, const PacketType& x) + { + internal::pstoret(m_data + index * m_innerStride.value(), x); + } +protected: + EIGEN_DEVICE_FUNC + inline Index rowStride() const { return XprType::IsRowMajor ? m_outerStride.value() : m_innerStride.value(); } + EIGEN_DEVICE_FUNC + inline Index colStride() const { return XprType::IsRowMajor ? m_innerStride.value() : m_outerStride.value(); } + + PointerType m_data; + const internal::variable_if_dynamic m_innerStride; + const internal::variable_if_dynamic m_outerStride; +}; + +template +struct evaluator > + : public mapbase_evaluator, PlainObjectType> +{ + typedef Map XprType; + typedef typename XprType::Scalar Scalar; + // TODO: should check for smaller packet types once we can handle multi-sized packet types + typedef typename packet_traits::type PacketScalar; + + enum { + InnerStrideAtCompileTime = StrideType::InnerStrideAtCompileTime == 0 + ? int(PlainObjectType::InnerStrideAtCompileTime) + : int(StrideType::InnerStrideAtCompileTime), + OuterStrideAtCompileTime = StrideType::OuterStrideAtCompileTime == 0 + ? int(PlainObjectType::OuterStrideAtCompileTime) + : int(StrideType::OuterStrideAtCompileTime), + HasNoInnerStride = InnerStrideAtCompileTime == 1, + HasNoOuterStride = StrideType::OuterStrideAtCompileTime == 0, + HasNoStride = HasNoInnerStride && HasNoOuterStride, + IsDynamicSize = PlainObjectType::SizeAtCompileTime==Dynamic, + + PacketAccessMask = bool(HasNoInnerStride) ? ~int(0) : ~int(PacketAccessBit), + LinearAccessMask = bool(HasNoStride) || bool(PlainObjectType::IsVectorAtCompileTime) ? ~int(0) : ~int(LinearAccessBit), + Flags = int( evaluator::Flags) & (LinearAccessMask&PacketAccessMask), + + Alignment = int(MapOptions)&int(AlignedMask) + }; + + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& map) + : mapbase_evaluator(map) + { } +}; + +// -------------------- Ref -------------------- + +template +struct evaluator > + : public mapbase_evaluator, PlainObjectType> +{ + typedef Ref XprType; + + enum { + Flags = evaluator >::Flags, + Alignment = evaluator >::Alignment + }; + + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& ref) + : mapbase_evaluator(ref) + { } +}; + +// -------------------- Block -------------------- + +template::ret> struct block_evaluator; + +template +struct evaluator > + : block_evaluator +{ + typedef Block XprType; + typedef typename XprType::Scalar Scalar; + // TODO: should check for smaller packet types once we can handle multi-sized packet types + typedef typename packet_traits::type PacketScalar; + + enum { + CoeffReadCost = evaluator::CoeffReadCost, + + RowsAtCompileTime = traits::RowsAtCompileTime, + ColsAtCompileTime = traits::ColsAtCompileTime, + MaxRowsAtCompileTime = traits::MaxRowsAtCompileTime, + MaxColsAtCompileTime = traits::MaxColsAtCompileTime, + + ArgTypeIsRowMajor = (int(evaluator::Flags)&RowMajorBit) != 0, + IsRowMajor = (MaxRowsAtCompileTime==1 && MaxColsAtCompileTime!=1) ? 1 + : (MaxColsAtCompileTime==1 && MaxRowsAtCompileTime!=1) ? 0 + : ArgTypeIsRowMajor, + HasSameStorageOrderAsArgType = (IsRowMajor == ArgTypeIsRowMajor), + InnerSize = IsRowMajor ? int(ColsAtCompileTime) : int(RowsAtCompileTime), + InnerStrideAtCompileTime = HasSameStorageOrderAsArgType + ? int(inner_stride_at_compile_time::ret) + : int(outer_stride_at_compile_time::ret), + OuterStrideAtCompileTime = HasSameStorageOrderAsArgType + ? int(outer_stride_at_compile_time::ret) + : int(inner_stride_at_compile_time::ret), + MaskPacketAccessBit = (InnerStrideAtCompileTime == 1) ? PacketAccessBit : 0, + + FlagsLinearAccessBit = (RowsAtCompileTime == 1 || ColsAtCompileTime == 1 || (InnerPanel && (evaluator::Flags&LinearAccessBit))) ? LinearAccessBit : 0, + FlagsRowMajorBit = XprType::Flags&RowMajorBit, + Flags0 = evaluator::Flags & ( (HereditaryBits & ~RowMajorBit) | + DirectAccessBit | + MaskPacketAccessBit), + Flags = Flags0 | FlagsLinearAccessBit | FlagsRowMajorBit, + + PacketAlignment = unpacket_traits::alignment, + Alignment0 = (InnerPanel && (OuterStrideAtCompileTime!=Dynamic) && (((OuterStrideAtCompileTime * int(sizeof(Scalar))) % int(PacketAlignment)) == 0)) ? int(PacketAlignment) : 0, + Alignment = EIGEN_PLAIN_ENUM_MIN(evaluator::Alignment, Alignment0) + }; + typedef block_evaluator block_evaluator_type; + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& block) : block_evaluator_type(block) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } +}; + +// no direct-access => dispatch to a unary evaluator +template +struct block_evaluator + : unary_evaluator > +{ + typedef Block XprType; + + EIGEN_DEVICE_FUNC explicit block_evaluator(const XprType& block) + : unary_evaluator(block) + {} +}; + +template +struct unary_evaluator, IndexBased> + : evaluator_base > +{ + typedef Block XprType; + + EIGEN_DEVICE_FUNC explicit unary_evaluator(const XprType& block) + : m_argImpl(block.nestedExpression()), + m_startRow(block.startRow()), + m_startCol(block.startCol()) + { } + + typedef typename XprType::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + + enum { + RowsAtCompileTime = XprType::RowsAtCompileTime + }; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index row, Index col) const + { + return m_argImpl.coeff(m_startRow.value() + row, m_startCol.value() + col); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index index) const + { + return coeff(RowsAtCompileTime == 1 ? 0 : index, RowsAtCompileTime == 1 ? index : 0); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Scalar& coeffRef(Index row, Index col) + { + return m_argImpl.coeffRef(m_startRow.value() + row, m_startCol.value() + col); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Scalar& coeffRef(Index index) + { + return coeffRef(RowsAtCompileTime == 1 ? 0 : index, RowsAtCompileTime == 1 ? index : 0); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index row, Index col) const + { + return m_argImpl.template packet(m_startRow.value() + row, m_startCol.value() + col); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index index) const + { + return packet(RowsAtCompileTime == 1 ? 0 : index, + RowsAtCompileTime == 1 ? index : 0); + } + + template + EIGEN_STRONG_INLINE + void writePacket(Index row, Index col, const PacketType& x) + { + return m_argImpl.template writePacket(m_startRow.value() + row, m_startCol.value() + col, x); + } + + template + EIGEN_STRONG_INLINE + void writePacket(Index index, const PacketType& x) + { + return writePacket(RowsAtCompileTime == 1 ? 0 : index, + RowsAtCompileTime == 1 ? index : 0, + x); + } + +protected: + evaluator m_argImpl; + const variable_if_dynamic m_startRow; + const variable_if_dynamic m_startCol; +}; + +// TODO: This evaluator does not actually use the child evaluator; +// all action is via the data() as returned by the Block expression. + +template +struct block_evaluator + : mapbase_evaluator, + typename Block::PlainObject> +{ + typedef Block XprType; + typedef typename XprType::Scalar Scalar; + + EIGEN_DEVICE_FUNC explicit block_evaluator(const XprType& block) + : mapbase_evaluator(block) + { + // TODO: for the 3.3 release, this should be turned to an internal assertion, but let's keep it as is for the beta lifetime + eigen_assert(((internal::UIntPtr(block.data()) % EIGEN_PLAIN_ENUM_MAX(1,evaluator::Alignment)) == 0) && "data is not aligned"); + } +}; + + +// -------------------- Select -------------------- +// NOTE shall we introduce a ternary_evaluator? + +// TODO enable vectorization for Select +template +struct evaluator > + : evaluator_base > +{ + typedef Select XprType; + enum { + CoeffReadCost = evaluator::CoeffReadCost + + EIGEN_PLAIN_ENUM_MAX(evaluator::CoeffReadCost, + evaluator::CoeffReadCost), + + Flags = (unsigned int)evaluator::Flags & evaluator::Flags & HereditaryBits, + + Alignment = EIGEN_PLAIN_ENUM_MIN(evaluator::Alignment, evaluator::Alignment) + }; + + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& select) + : m_conditionImpl(select.conditionMatrix()), + m_thenImpl(select.thenMatrix()), + m_elseImpl(select.elseMatrix()) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + + typedef typename XprType::CoeffReturnType CoeffReturnType; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index row, Index col) const + { + if (m_conditionImpl.coeff(row, col)) + return m_thenImpl.coeff(row, col); + else + return m_elseImpl.coeff(row, col); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index index) const + { + if (m_conditionImpl.coeff(index)) + return m_thenImpl.coeff(index); + else + return m_elseImpl.coeff(index); + } + +protected: + evaluator m_conditionImpl; + evaluator m_thenImpl; + evaluator m_elseImpl; +}; + + +// -------------------- Replicate -------------------- + +template +struct unary_evaluator > + : evaluator_base > +{ + typedef Replicate XprType; + typedef typename XprType::CoeffReturnType CoeffReturnType; + enum { + Factor = (RowFactor==Dynamic || ColFactor==Dynamic) ? Dynamic : RowFactor*ColFactor + }; + typedef typename internal::nested_eval::type ArgTypeNested; + typedef typename internal::remove_all::type ArgTypeNestedCleaned; + + enum { + CoeffReadCost = evaluator::CoeffReadCost, + LinearAccessMask = XprType::IsVectorAtCompileTime ? LinearAccessBit : 0, + Flags = (evaluator::Flags & (HereditaryBits|LinearAccessMask) & ~RowMajorBit) | (traits::Flags & RowMajorBit), + + Alignment = evaluator::Alignment + }; + + EIGEN_DEVICE_FUNC explicit unary_evaluator(const XprType& replicate) + : m_arg(replicate.nestedExpression()), + m_argImpl(m_arg), + m_rows(replicate.nestedExpression().rows()), + m_cols(replicate.nestedExpression().cols()) + {} + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index row, Index col) const + { + // try to avoid using modulo; this is a pure optimization strategy + const Index actual_row = internal::traits::RowsAtCompileTime==1 ? 0 + : RowFactor==1 ? row + : row % m_rows.value(); + const Index actual_col = internal::traits::ColsAtCompileTime==1 ? 0 + : ColFactor==1 ? col + : col % m_cols.value(); + + return m_argImpl.coeff(actual_row, actual_col); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index index) const + { + // try to avoid using modulo; this is a pure optimization strategy + const Index actual_index = internal::traits::RowsAtCompileTime==1 + ? (ColFactor==1 ? index : index%m_cols.value()) + : (RowFactor==1 ? index : index%m_rows.value()); + + return m_argImpl.coeff(actual_index); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index row, Index col) const + { + const Index actual_row = internal::traits::RowsAtCompileTime==1 ? 0 + : RowFactor==1 ? row + : row % m_rows.value(); + const Index actual_col = internal::traits::ColsAtCompileTime==1 ? 0 + : ColFactor==1 ? col + : col % m_cols.value(); + + return m_argImpl.template packet(actual_row, actual_col); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index index) const + { + const Index actual_index = internal::traits::RowsAtCompileTime==1 + ? (ColFactor==1 ? index : index%m_cols.value()) + : (RowFactor==1 ? index : index%m_rows.value()); + + return m_argImpl.template packet(actual_index); + } + +protected: + const ArgTypeNested m_arg; + evaluator m_argImpl; + const variable_if_dynamic m_rows; + const variable_if_dynamic m_cols; +}; + + +// -------------------- PartialReduxExpr -------------------- + +template< typename ArgType, typename MemberOp, int Direction> +struct evaluator > + : evaluator_base > +{ + typedef PartialReduxExpr XprType; + typedef typename internal::nested_eval::type ArgTypeNested; + typedef typename internal::remove_all::type ArgTypeNestedCleaned; + typedef typename ArgType::Scalar InputScalar; + typedef typename XprType::Scalar Scalar; + enum { + TraversalSize = Direction==int(Vertical) ? int(ArgType::RowsAtCompileTime) : int(ArgType::ColsAtCompileTime) + }; + typedef typename MemberOp::template Cost CostOpType; + enum { + CoeffReadCost = TraversalSize==Dynamic ? HugeCost + : TraversalSize * evaluator::CoeffReadCost + int(CostOpType::value), + + Flags = (traits::Flags&RowMajorBit) | (evaluator::Flags&(HereditaryBits&(~RowMajorBit))) | LinearAccessBit, + + Alignment = 0 // FIXME this will need to be improved once PartialReduxExpr is vectorized + }; + + EIGEN_DEVICE_FUNC explicit evaluator(const XprType xpr) + : m_arg(xpr.nestedExpression()), m_functor(xpr.functor()) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(TraversalSize==Dynamic ? HugeCost : int(CostOpType::value)); + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + + typedef typename XprType::CoeffReturnType CoeffReturnType; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const Scalar coeff(Index i, Index j) const + { + if (Direction==Vertical) + return m_functor(m_arg.col(j)); + else + return m_functor(m_arg.row(i)); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const Scalar coeff(Index index) const + { + if (Direction==Vertical) + return m_functor(m_arg.col(index)); + else + return m_functor(m_arg.row(index)); + } + +protected: + typename internal::add_const_on_value_type::type m_arg; + const MemberOp m_functor; +}; + + +// -------------------- MatrixWrapper and ArrayWrapper -------------------- +// +// evaluator_wrapper_base is a common base class for the +// MatrixWrapper and ArrayWrapper evaluators. + +template +struct evaluator_wrapper_base + : evaluator_base +{ + typedef typename remove_all::type ArgType; + enum { + CoeffReadCost = evaluator::CoeffReadCost, + Flags = evaluator::Flags, + Alignment = evaluator::Alignment + }; + + EIGEN_DEVICE_FUNC explicit evaluator_wrapper_base(const ArgType& arg) : m_argImpl(arg) {} + + typedef typename ArgType::Scalar Scalar; + typedef typename ArgType::CoeffReturnType CoeffReturnType; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index row, Index col) const + { + return m_argImpl.coeff(row, col); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index index) const + { + return m_argImpl.coeff(index); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Scalar& coeffRef(Index row, Index col) + { + return m_argImpl.coeffRef(row, col); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Scalar& coeffRef(Index index) + { + return m_argImpl.coeffRef(index); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index row, Index col) const + { + return m_argImpl.template packet(row, col); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index index) const + { + return m_argImpl.template packet(index); + } + + template + EIGEN_STRONG_INLINE + void writePacket(Index row, Index col, const PacketType& x) + { + m_argImpl.template writePacket(row, col, x); + } + + template + EIGEN_STRONG_INLINE + void writePacket(Index index, const PacketType& x) + { + m_argImpl.template writePacket(index, x); + } + +protected: + evaluator m_argImpl; +}; + +template +struct unary_evaluator > + : evaluator_wrapper_base > +{ + typedef MatrixWrapper XprType; + + EIGEN_DEVICE_FUNC explicit unary_evaluator(const XprType& wrapper) + : evaluator_wrapper_base >(wrapper.nestedExpression()) + { } +}; + +template +struct unary_evaluator > + : evaluator_wrapper_base > +{ + typedef ArrayWrapper XprType; + + EIGEN_DEVICE_FUNC explicit unary_evaluator(const XprType& wrapper) + : evaluator_wrapper_base >(wrapper.nestedExpression()) + { } +}; + + +// -------------------- Reverse -------------------- + +// defined in Reverse.h: +template struct reverse_packet_cond; + +template +struct unary_evaluator > + : evaluator_base > +{ + typedef Reverse XprType; + typedef typename XprType::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + + enum { + IsRowMajor = XprType::IsRowMajor, + IsColMajor = !IsRowMajor, + ReverseRow = (Direction == Vertical) || (Direction == BothDirections), + ReverseCol = (Direction == Horizontal) || (Direction == BothDirections), + ReversePacket = (Direction == BothDirections) + || ((Direction == Vertical) && IsColMajor) + || ((Direction == Horizontal) && IsRowMajor), + + CoeffReadCost = evaluator::CoeffReadCost, + + // let's enable LinearAccess only with vectorization because of the product overhead + // FIXME enable DirectAccess with negative strides? + Flags0 = evaluator::Flags, + LinearAccess = ( (Direction==BothDirections) && (int(Flags0)&PacketAccessBit) ) + || ((ReverseRow && XprType::ColsAtCompileTime==1) || (ReverseCol && XprType::RowsAtCompileTime==1)) + ? LinearAccessBit : 0, + + Flags = int(Flags0) & (HereditaryBits | PacketAccessBit | LinearAccess), + + Alignment = 0 // FIXME in some rare cases, Alignment could be preserved, like a Vector4f. + }; + + EIGEN_DEVICE_FUNC explicit unary_evaluator(const XprType& reverse) + : m_argImpl(reverse.nestedExpression()), + m_rows(ReverseRow ? reverse.nestedExpression().rows() : 1), + m_cols(ReverseCol ? reverse.nestedExpression().cols() : 1) + { } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index row, Index col) const + { + return m_argImpl.coeff(ReverseRow ? m_rows.value() - row - 1 : row, + ReverseCol ? m_cols.value() - col - 1 : col); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index index) const + { + return m_argImpl.coeff(m_rows.value() * m_cols.value() - index - 1); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Scalar& coeffRef(Index row, Index col) + { + return m_argImpl.coeffRef(ReverseRow ? m_rows.value() - row - 1 : row, + ReverseCol ? m_cols.value() - col - 1 : col); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Scalar& coeffRef(Index index) + { + return m_argImpl.coeffRef(m_rows.value() * m_cols.value() - index - 1); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index row, Index col) const + { + enum { + PacketSize = unpacket_traits::size, + OffsetRow = ReverseRow && IsColMajor ? PacketSize : 1, + OffsetCol = ReverseCol && IsRowMajor ? PacketSize : 1 + }; + typedef internal::reverse_packet_cond reverse_packet; + return reverse_packet::run(m_argImpl.template packet( + ReverseRow ? m_rows.value() - row - OffsetRow : row, + ReverseCol ? m_cols.value() - col - OffsetCol : col)); + } + + template + EIGEN_STRONG_INLINE + PacketType packet(Index index) const + { + enum { PacketSize = unpacket_traits::size }; + return preverse(m_argImpl.template packet(m_rows.value() * m_cols.value() - index - PacketSize)); + } + + template + EIGEN_STRONG_INLINE + void writePacket(Index row, Index col, const PacketType& x) + { + // FIXME we could factorize some code with packet(i,j) + enum { + PacketSize = unpacket_traits::size, + OffsetRow = ReverseRow && IsColMajor ? PacketSize : 1, + OffsetCol = ReverseCol && IsRowMajor ? PacketSize : 1 + }; + typedef internal::reverse_packet_cond reverse_packet; + m_argImpl.template writePacket( + ReverseRow ? m_rows.value() - row - OffsetRow : row, + ReverseCol ? m_cols.value() - col - OffsetCol : col, + reverse_packet::run(x)); + } + + template + EIGEN_STRONG_INLINE + void writePacket(Index index, const PacketType& x) + { + enum { PacketSize = unpacket_traits::size }; + m_argImpl.template writePacket + (m_rows.value() * m_cols.value() - index - PacketSize, preverse(x)); + } + +protected: + evaluator m_argImpl; + + // If we do not reverse rows, then we do not need to know the number of rows; same for columns + // Nonetheless, in this case it is important to set to 1 such that the coeff(index) method works fine for vectors. + const variable_if_dynamic m_rows; + const variable_if_dynamic m_cols; +}; + + +// -------------------- Diagonal -------------------- + +template +struct evaluator > + : evaluator_base > +{ + typedef Diagonal XprType; + + enum { + CoeffReadCost = evaluator::CoeffReadCost, + + Flags = (unsigned int)(evaluator::Flags & (HereditaryBits | DirectAccessBit) & ~RowMajorBit) | LinearAccessBit, + + Alignment = 0 + }; + + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& diagonal) + : m_argImpl(diagonal.nestedExpression()), + m_index(diagonal.index()) + { } + + typedef typename XprType::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index row, Index) const + { + return m_argImpl.coeff(row + rowOffset(), row + colOffset()); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + CoeffReturnType coeff(Index index) const + { + return m_argImpl.coeff(index + rowOffset(), index + colOffset()); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Scalar& coeffRef(Index row, Index) + { + return m_argImpl.coeffRef(row + rowOffset(), row + colOffset()); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Scalar& coeffRef(Index index) + { + return m_argImpl.coeffRef(index + rowOffset(), index + colOffset()); + } + +protected: + evaluator m_argImpl; + const internal::variable_if_dynamicindex m_index; + +private: + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index rowOffset() const { return m_index.value() > 0 ? 0 : -m_index.value(); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index colOffset() const { return m_index.value() > 0 ? m_index.value() : 0; } +}; + + +//---------------------------------------------------------------------- +// deprecated code +//---------------------------------------------------------------------- + +// -------------------- EvalToTemp -------------------- + +// expression class for evaluating nested expression to a temporary + +template class EvalToTemp; + +template +struct traits > + : public traits +{ }; + +template +class EvalToTemp + : public dense_xpr_base >::type +{ + public: + + typedef typename dense_xpr_base::type Base; + EIGEN_GENERIC_PUBLIC_INTERFACE(EvalToTemp) + + explicit EvalToTemp(const ArgType& arg) + : m_arg(arg) + { } + + const ArgType& arg() const + { + return m_arg; + } + + Index rows() const + { + return m_arg.rows(); + } + + Index cols() const + { + return m_arg.cols(); + } + + private: + const ArgType& m_arg; +}; + +template +struct evaluator > + : public evaluator +{ + typedef EvalToTemp XprType; + typedef typename ArgType::PlainObject PlainObject; + typedef evaluator Base; + + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& xpr) + : m_result(xpr.arg()) + { + ::new (static_cast(this)) Base(m_result); + } + + // This constructor is used when nesting an EvalTo evaluator in another evaluator + EIGEN_DEVICE_FUNC evaluator(const ArgType& arg) + : m_result(arg) + { + ::new (static_cast(this)) Base(m_result); + } + +protected: + PlainObject m_result; +}; + +} // namespace internal + +} // end namespace Eigen + +#endif // EIGEN_COREEVALUATORS_H diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Core/CoreIterators.h b/ground/gcs/src/libs/eigen/Eigen/src/Core/CoreIterators.h index 6da4683d2c..4eb42b93af 100644 --- a/ground/gcs/src/libs/eigen/Eigen/src/Core/CoreIterators.h +++ b/ground/gcs/src/libs/eigen/Eigen/src/Core/CoreIterators.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008-2010 Gael Guennebaud +// Copyright (C) 2008-2014 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -15,47 +15,113 @@ namespace Eigen { /* This file contains the respective InnerIterator definition of the expressions defined in Eigen/Core */ -/** \ingroup SparseCore_Module - * \class InnerIterator - * \brief An InnerIterator allows to loop over the element of a sparse (or dense) matrix or expression - * - * todo +namespace internal { + +template +class inner_iterator_selector; + +} + +/** \class InnerIterator + * \brief An InnerIterator allows to loop over the element of any matrix expression. + * + * \warning To be used with care because an evaluator is constructed every time an InnerIterator iterator is constructed. + * + * TODO: add a usage example */ +template +class InnerIterator +{ +protected: + typedef internal::inner_iterator_selector::Kind> IteratorType; + typedef internal::evaluator EvaluatorType; + typedef typename internal::traits::Scalar Scalar; +public: + /** Construct an iterator over the \a outerId -th row or column of \a xpr */ + InnerIterator(const XprType &xpr, const Index &outerId) + : m_eval(xpr), m_iter(m_eval, outerId, xpr.innerSize()) + {} + + /// \returns the value of the current coefficient. + EIGEN_STRONG_INLINE Scalar value() const { return m_iter.value(); } + /** Increment the iterator \c *this to the next non-zero coefficient. + * Explicit zeros are not skipped over. To skip explicit zeros, see class SparseView + */ + EIGEN_STRONG_INLINE InnerIterator& operator++() { m_iter.operator++(); return *this; } + /// \returns the column or row index of the current coefficient. + EIGEN_STRONG_INLINE Index index() const { return m_iter.index(); } + /// \returns the row index of the current coefficient. + EIGEN_STRONG_INLINE Index row() const { return m_iter.row(); } + /// \returns the column index of the current coefficient. + EIGEN_STRONG_INLINE Index col() const { return m_iter.col(); } + /// \returns \c true if the iterator \c *this still references a valid coefficient. + EIGEN_STRONG_INLINE operator bool() const { return m_iter; } + +protected: + EvaluatorType m_eval; + IteratorType m_iter; +private: + // If you get here, then you're not using the right InnerIterator type, e.g.: + // SparseMatrix A; + // SparseMatrix::InnerIterator it(A,0); + template InnerIterator(const EigenBase&,Index outer); +}; + +namespace internal { -// generic version for dense matrix and expressions -template class DenseBase::InnerIterator +// Generic inner iterator implementation for dense objects +template +class inner_iterator_selector { - protected: - typedef typename Derived::Scalar Scalar; - typedef typename Derived::Index Index; - - enum { IsRowMajor = (Derived::Flags&RowMajorBit)==RowMajorBit }; - public: - EIGEN_STRONG_INLINE InnerIterator(const Derived& expr, Index outer) - : m_expression(expr), m_inner(0), m_outer(outer), m_end(expr.innerSize()) - {} - - EIGEN_STRONG_INLINE Scalar value() const - { - return (IsRowMajor) ? m_expression.coeff(m_outer, m_inner) - : m_expression.coeff(m_inner, m_outer); - } - - EIGEN_STRONG_INLINE InnerIterator& operator++() { m_inner++; return *this; } - - EIGEN_STRONG_INLINE Index index() const { return m_inner; } - inline Index row() const { return IsRowMajor ? m_outer : index(); } - inline Index col() const { return IsRowMajor ? index() : m_outer; } - - EIGEN_STRONG_INLINE operator bool() const { return m_inner < m_end && m_inner>=0; } - - protected: - const Derived& m_expression; - Index m_inner; - const Index m_outer; - const Index m_end; +protected: + typedef evaluator EvaluatorType; + typedef typename traits::Scalar Scalar; + enum { IsRowMajor = (XprType::Flags&RowMajorBit)==RowMajorBit }; + +public: + EIGEN_STRONG_INLINE inner_iterator_selector(const EvaluatorType &eval, const Index &outerId, const Index &innerSize) + : m_eval(eval), m_inner(0), m_outer(outerId), m_end(innerSize) + {} + + EIGEN_STRONG_INLINE Scalar value() const + { + return (IsRowMajor) ? m_eval.coeff(m_outer, m_inner) + : m_eval.coeff(m_inner, m_outer); + } + + EIGEN_STRONG_INLINE inner_iterator_selector& operator++() { m_inner++; return *this; } + + EIGEN_STRONG_INLINE Index index() const { return m_inner; } + inline Index row() const { return IsRowMajor ? m_outer : index(); } + inline Index col() const { return IsRowMajor ? index() : m_outer; } + + EIGEN_STRONG_INLINE operator bool() const { return m_inner < m_end && m_inner>=0; } + +protected: + const EvaluatorType& m_eval; + Index m_inner; + const Index m_outer; + const Index m_end; }; +// For iterator-based evaluator, inner-iterator is already implemented as +// evaluator<>::InnerIterator +template +class inner_iterator_selector + : public evaluator::InnerIterator +{ +protected: + typedef typename evaluator::InnerIterator Base; + typedef evaluator EvaluatorType; + +public: + EIGEN_STRONG_INLINE inner_iterator_selector(const EvaluatorType &eval, const Index &outerId, const Index &/*innerSize*/) + : Base(eval, outerId) + {} +}; + +} // end namespace internal + } // end namespace Eigen #endif // EIGEN_COREITERATORS_H diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Core/CwiseBinaryOp.h b/ground/gcs/src/libs/eigen/Eigen/src/Core/CwiseBinaryOp.h index 519a866e60..a36765e396 100644 --- a/ground/gcs/src/libs/eigen/Eigen/src/Core/CwiseBinaryOp.h +++ b/ground/gcs/src/libs/eigen/Eigen/src/Core/CwiseBinaryOp.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008-2009 Gael Guennebaud +// Copyright (C) 2008-2014 Gael Guennebaud // Copyright (C) 2006-2008 Benoit Jacob // // This Source Code Form is subject to the terms of the Mozilla @@ -13,26 +13,6 @@ namespace Eigen { -/** \class CwiseBinaryOp - * \ingroup Core_Module - * - * \brief Generic expression where a coefficient-wise binary operator is applied to two expressions - * - * \param BinaryOp template functor implementing the operator - * \param Lhs the type of the left-hand side - * \param Rhs the type of the right-hand side - * - * This class represents an expression where a coefficient-wise binary operator is applied to two expressions. - * It is the return type of binary operators, by which we mean only those binary operators where - * both the left-hand side and the right-hand side are Eigen expressions. - * For example, the return type of matrix1+matrix2 is a CwiseBinaryOp. - * - * Most of the time, this is the only way that it is used, so you typically don't have to name - * CwiseBinaryOp types explicitly. - * - * \sa MatrixBase::binaryExpr(const MatrixBase &,const CustomBinaryOp &) const, class CwiseUnaryOp, class CwiseNullaryOp - */ - namespace internal { template struct traits > @@ -52,77 +32,75 @@ struct traits > // we still want to handle the case when the result type is different. typedef typename result_of< BinaryOp( - typename Lhs::Scalar, - typename Rhs::Scalar + const typename Lhs::Scalar&, + const typename Rhs::Scalar& ) >::type Scalar; - typedef typename promote_storage_type::StorageKind, - typename traits::StorageKind>::ret StorageKind; - typedef typename promote_index_type::Index, - typename traits::Index>::type Index; + typedef typename cwise_promote_storage_type::StorageKind, + typename traits::StorageKind, + BinaryOp>::ret StorageKind; + typedef typename promote_index_type::StorageIndex, + typename traits::StorageIndex>::type StorageIndex; typedef typename Lhs::Nested LhsNested; typedef typename Rhs::Nested RhsNested; typedef typename remove_reference::type _LhsNested; typedef typename remove_reference::type _RhsNested; enum { - LhsCoeffReadCost = _LhsNested::CoeffReadCost, - RhsCoeffReadCost = _RhsNested::CoeffReadCost, - LhsFlags = _LhsNested::Flags, - RhsFlags = _RhsNested::Flags, - SameType = is_same::value, - StorageOrdersAgree = (int(Lhs::Flags)&RowMajorBit)==(int(Rhs::Flags)&RowMajorBit), - Flags0 = (int(LhsFlags) | int(RhsFlags)) & ( - HereditaryBits - | (int(LhsFlags) & int(RhsFlags) & - ( AlignedBit - | (StorageOrdersAgree ? LinearAccessBit : 0) - | (functor_traits::PacketAccess && StorageOrdersAgree && SameType ? PacketAccessBit : 0) - ) - ) - ), - Flags = (Flags0 & ~RowMajorBit) | (LhsFlags & RowMajorBit), - Cost0 = EIGEN_ADD_COST(LhsCoeffReadCost,RhsCoeffReadCost), - CoeffReadCost = EIGEN_ADD_COST(Cost0,functor_traits::Cost) + Flags = cwise_promote_storage_order::StorageKind,typename traits::StorageKind,_LhsNested::Flags & RowMajorBit,_RhsNested::Flags & RowMajorBit>::value }; }; } // end namespace internal -// we require Lhs and Rhs to have the same scalar type. Currently there is no example of a binary functor -// that would take two operands of different types. If there were such an example, then this check should be -// moved to the BinaryOp functors, on a per-case basis. This would however require a change in the BinaryOp functors, as -// currently they take only one typename Scalar template parameter. -// It is tempting to always allow mixing different types but remember that this is often impossible in the vectorized paths. -// So allowing mixing different types gives very unexpected errors when enabling vectorization, when the user tries to -// add together a float matrix and a double matrix. -#define EIGEN_CHECK_BINARY_COMPATIBILIY(BINOP,LHS,RHS) \ - EIGEN_STATIC_ASSERT((internal::functor_is_product_like::ret \ - ? int(internal::scalar_product_traits::Defined) \ - : int(internal::is_same::value)), \ - YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) - template class CwiseBinaryOpImpl; -template -class CwiseBinaryOp : internal::no_assignment_operator, +/** \class CwiseBinaryOp + * \ingroup Core_Module + * + * \brief Generic expression where a coefficient-wise binary operator is applied to two expressions + * + * \tparam BinaryOp template functor implementing the operator + * \tparam LhsType the type of the left-hand side + * \tparam RhsType the type of the right-hand side + * + * This class represents an expression where a coefficient-wise binary operator is applied to two expressions. + * It is the return type of binary operators, by which we mean only those binary operators where + * both the left-hand side and the right-hand side are Eigen expressions. + * For example, the return type of matrix1+matrix2 is a CwiseBinaryOp. + * + * Most of the time, this is the only way that it is used, so you typically don't have to name + * CwiseBinaryOp types explicitly. + * + * \sa MatrixBase::binaryExpr(const MatrixBase &,const CustomBinaryOp &) const, class CwiseUnaryOp, class CwiseNullaryOp + */ +template +class CwiseBinaryOp : public CwiseBinaryOpImpl< - BinaryOp, Lhs, Rhs, - typename internal::promote_storage_type::StorageKind, - typename internal::traits::StorageKind>::ret> + BinaryOp, LhsType, RhsType, + typename internal::cwise_promote_storage_type::StorageKind, + typename internal::traits::StorageKind, + BinaryOp>::ret>, + internal::no_assignment_operator { public: + + typedef typename internal::remove_all::type Functor; + typedef typename internal::remove_all::type Lhs; + typedef typename internal::remove_all::type Rhs; typedef typename CwiseBinaryOpImpl< - BinaryOp, Lhs, Rhs, - typename internal::promote_storage_type::StorageKind, - typename internal::traits::StorageKind>::ret>::Base Base; + BinaryOp, LhsType, RhsType, + typename internal::cwise_promote_storage_type::StorageKind, + typename internal::traits::StorageKind, + BinaryOp>::ret>::Base Base; EIGEN_GENERIC_PUBLIC_INTERFACE(CwiseBinaryOp) - typedef typename internal::nested::type LhsNested; - typedef typename internal::nested::type RhsNested; + typedef typename internal::ref_selector::type LhsNested; + typedef typename internal::ref_selector::type RhsNested; typedef typename internal::remove_reference::type _LhsNested; typedef typename internal::remove_reference::type _RhsNested; + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CwiseBinaryOp(const Lhs& aLhs, const Rhs& aRhs, const BinaryOp& func = BinaryOp()) : m_lhs(aLhs), m_rhs(aRhs), m_functor(func) { @@ -132,6 +110,7 @@ class CwiseBinaryOp : internal::no_assignment_operator, eigen_assert(aLhs.rows() == aRhs.rows() && aLhs.cols() == aRhs.cols()); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index rows() const { // return the fixed size type if available to enable compile time optimizations if (internal::traits::type>::RowsAtCompileTime==Dynamic) @@ -139,6 +118,7 @@ class CwiseBinaryOp : internal::no_assignment_operator, else return m_lhs.rows(); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index cols() const { // return the fixed size type if available to enable compile time optimizations if (internal::traits::type>::ColsAtCompileTime==Dynamic) @@ -148,10 +128,13 @@ class CwiseBinaryOp : internal::no_assignment_operator, } /** \returns the left hand side nested expression */ + EIGEN_DEVICE_FUNC const _LhsNested& lhs() const { return m_lhs; } /** \returns the right hand side nested expression */ + EIGEN_DEVICE_FUNC const _RhsNested& rhs() const { return m_rhs; } /** \returns the functor representing the binary operation */ + EIGEN_DEVICE_FUNC const BinaryOp& functor() const { return m_functor; } protected: @@ -160,41 +143,13 @@ class CwiseBinaryOp : internal::no_assignment_operator, const BinaryOp m_functor; }; -template -class CwiseBinaryOpImpl - : public internal::dense_xpr_base >::type +// Generic API dispatcher +template +class CwiseBinaryOpImpl + : public internal::generic_xpr_base >::type { - typedef CwiseBinaryOp Derived; - public: - - typedef typename internal::dense_xpr_base >::type Base; - EIGEN_DENSE_PUBLIC_INTERFACE( Derived ) - - EIGEN_STRONG_INLINE const Scalar coeff(Index rowId, Index colId) const - { - return derived().functor()(derived().lhs().coeff(rowId, colId), - derived().rhs().coeff(rowId, colId)); - } - - template - EIGEN_STRONG_INLINE PacketScalar packet(Index rowId, Index colId) const - { - return derived().functor().packetOp(derived().lhs().template packet(rowId, colId), - derived().rhs().template packet(rowId, colId)); - } - - EIGEN_STRONG_INLINE const Scalar coeff(Index index) const - { - return derived().functor()(derived().lhs().coeff(index), - derived().rhs().coeff(index)); - } - - template - EIGEN_STRONG_INLINE PacketScalar packet(Index index) const - { - return derived().functor().packetOp(derived().lhs().template packet(index), - derived().rhs().template packet(index)); - } +public: + typedef typename internal::generic_xpr_base >::type Base; }; /** replaces \c *this by \c *this - \a other. @@ -206,8 +161,7 @@ template EIGEN_STRONG_INLINE Derived & MatrixBase::operator-=(const MatrixBase &other) { - SelfCwiseBinaryOp, Derived, OtherDerived> tmp(derived()); - tmp = other.derived(); + call_assignment(derived(), other.derived(), internal::sub_assign_op()); return derived(); } @@ -220,11 +174,11 @@ template EIGEN_STRONG_INLINE Derived & MatrixBase::operator+=(const MatrixBase& other) { - SelfCwiseBinaryOp, Derived, OtherDerived> tmp(derived()); - tmp = other.derived(); + call_assignment(derived(), other.derived(), internal::add_assign_op()); return derived(); } } // end namespace Eigen #endif // EIGEN_CWISE_BINARY_OP_H + diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Core/CwiseNullaryOp.h b/ground/gcs/src/libs/eigen/Eigen/src/Core/CwiseNullaryOp.h index a93bab2d0f..dd498f758d 100644 --- a/ground/gcs/src/libs/eigen/Eigen/src/Core/CwiseNullaryOp.h +++ b/ground/gcs/src/libs/eigen/Eigen/src/Core/CwiseNullaryOp.h @@ -12,13 +12,24 @@ namespace Eigen { +namespace internal { +template +struct traits > : traits +{ + enum { + Flags = traits::Flags & RowMajorBit + }; +}; + +} // namespace internal + /** \class CwiseNullaryOp * \ingroup Core_Module * * \brief Generic expression of a matrix where all coefficients are defined by a functor * - * \param NullaryOp template functor implementing the operator - * \param PlainObjectType the underlying plain matrix/array type + * \tparam NullaryOp template functor implementing the operator + * \tparam PlainObjectType the underlying plain matrix/array type * * This class represents an expression of a generic nullary operator. * It is the return type of the Ones(), Zero(), Constant(), Identity() and Random() methods, @@ -27,68 +38,49 @@ namespace Eigen { * However, if you want to write a function returning such an expression, you * will need to use this class. * - * \sa class CwiseUnaryOp, class CwiseBinaryOp, DenseBase::NullaryExpr() + * The functor NullaryOp must expose one of the following method: + + + + +
\c operator()() if the procedural generation does not depend on the coefficient entries (e.g., random numbers)
\c operator()(Index i)if the procedural generation makes sense for vectors only and that it depends on the coefficient index \c i (e.g., linspace)
\c operator()(Index i,Index j)if the procedural generation depends on the matrix coordinates \c i, \c j (e.g., to generate a checkerboard with 0 and 1)
+ * It is also possible to expose the last two operators if the generation makes sense for matrices but can be optimized for vectors. + * + * See DenseBase::NullaryExpr(Index,const CustomNullaryOp&) for an example binding + * C++11 random number generators. + * + * A nullary expression can also be used to implement custom sophisticated matrix manipulations + * that cannot be covered by the existing set of natively supported matrix manipulations. + * See this \ref TopicCustomizing_NullaryExpr "page" for some examples and additional explanations + * on the behavior of CwiseNullaryOp. + * + * \sa class CwiseUnaryOp, class CwiseBinaryOp, DenseBase::NullaryExpr */ - -namespace internal { template -struct traits > : traits -{ - enum { - Flags = (traits::Flags - & ( HereditaryBits - | (functor_has_linear_access::ret ? LinearAccessBit : 0) - | (functor_traits::PacketAccess ? PacketAccessBit : 0))) - | (functor_traits::IsRepeatable ? 0 : EvalBeforeNestingBit), - CoeffReadCost = functor_traits::Cost - }; -}; -} - -template -class CwiseNullaryOp : internal::no_assignment_operator, - public internal::dense_xpr_base< CwiseNullaryOp >::type +class CwiseNullaryOp : public internal::dense_xpr_base< CwiseNullaryOp >::type, internal::no_assignment_operator { public: typedef typename internal::dense_xpr_base::type Base; EIGEN_DENSE_PUBLIC_INTERFACE(CwiseNullaryOp) - CwiseNullaryOp(Index nbRows, Index nbCols, const NullaryOp& func = NullaryOp()) - : m_rows(nbRows), m_cols(nbCols), m_functor(func) + EIGEN_DEVICE_FUNC + CwiseNullaryOp(Index rows, Index cols, const NullaryOp& func = NullaryOp()) + : m_rows(rows), m_cols(cols), m_functor(func) { - eigen_assert(nbRows >= 0 - && (RowsAtCompileTime == Dynamic || RowsAtCompileTime == nbRows) - && nbCols >= 0 - && (ColsAtCompileTime == Dynamic || ColsAtCompileTime == nbCols)); + eigen_assert(rows >= 0 + && (RowsAtCompileTime == Dynamic || RowsAtCompileTime == rows) + && cols >= 0 + && (ColsAtCompileTime == Dynamic || ColsAtCompileTime == cols)); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index rows() const { return m_rows.value(); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index cols() const { return m_cols.value(); } - EIGEN_STRONG_INLINE const Scalar coeff(Index rowId, Index colId) const - { - return m_functor(rowId, colId); - } - - template - EIGEN_STRONG_INLINE PacketScalar packet(Index rowId, Index colId) const - { - return m_functor.packetOp(rowId, colId); - } - - EIGEN_STRONG_INLINE const Scalar coeff(Index index) const - { - return m_functor(index); - } - - template - EIGEN_STRONG_INLINE PacketScalar packet(Index index) const - { - return m_functor.packetOp(index); - } - /** \returns the functor representing the nullary operation */ + EIGEN_DEVICE_FUNC const NullaryOp& functor() const { return m_functor; } protected: @@ -113,10 +105,10 @@ class CwiseNullaryOp : internal::no_assignment_operator, */ template template -EIGEN_STRONG_INLINE const CwiseNullaryOp +EIGEN_STRONG_INLINE const CwiseNullaryOp::PlainObject> DenseBase::NullaryExpr(Index rows, Index cols, const CustomNullaryOp& func) { - return CwiseNullaryOp(rows, cols, func); + return CwiseNullaryOp(rows, cols, func); } /** \returns an expression of a matrix defined by a custom functor \a func @@ -132,16 +124,19 @@ DenseBase::NullaryExpr(Index rows, Index cols, const CustomNullaryOp& f * * The template parameter \a CustomNullaryOp is the type of the functor. * + * Here is an example with C++11 random generators: \include random_cpp11.cpp + * Output: \verbinclude random_cpp11.out + * * \sa class CwiseNullaryOp */ template template -EIGEN_STRONG_INLINE const CwiseNullaryOp +EIGEN_STRONG_INLINE const CwiseNullaryOp::PlainObject> DenseBase::NullaryExpr(Index size, const CustomNullaryOp& func) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - if(RowsAtCompileTime == 1) return CwiseNullaryOp(1, size, func); - else return CwiseNullaryOp(size, 1, func); + if(RowsAtCompileTime == 1) return CwiseNullaryOp(1, size, func); + else return CwiseNullaryOp(size, 1, func); } /** \returns an expression of a matrix defined by a custom functor \a func @@ -155,19 +150,19 @@ DenseBase::NullaryExpr(Index size, const CustomNullaryOp& func) */ template template -EIGEN_STRONG_INLINE const CwiseNullaryOp +EIGEN_STRONG_INLINE const CwiseNullaryOp::PlainObject> DenseBase::NullaryExpr(const CustomNullaryOp& func) { - return CwiseNullaryOp(RowsAtCompileTime, ColsAtCompileTime, func); + return CwiseNullaryOp(RowsAtCompileTime, ColsAtCompileTime, func); } /** \returns an expression of a constant matrix of value \a value * - * The parameters \a nbRows and \a nbCols are the number of rows and of columns of + * The parameters \a rows and \a cols are the number of rows and of columns of * the returned matrix. Must be compatible with this DenseBase type. * * This variant is meant to be used for dynamic-size matrix types. For fixed-size types, - * it is redundant to pass \a nbRows and \a nbCols as arguments, so Zero() should be used + * it is redundant to pass \a rows and \a cols as arguments, so Zero() should be used * instead. * * The template parameter \a CustomNullaryOp is the type of the functor. @@ -176,9 +171,9 @@ DenseBase::NullaryExpr(const CustomNullaryOp& func) */ template EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType -DenseBase::Constant(Index nbRows, Index nbCols, const Scalar& value) +DenseBase::Constant(Index rows, Index cols, const Scalar& value) { - return DenseBase::NullaryExpr(nbRows, nbCols, internal::scalar_constant_op(value)); + return DenseBase::NullaryExpr(rows, cols, internal::scalar_constant_op(value)); } /** \returns an expression of a constant matrix of value \a value @@ -220,46 +215,33 @@ DenseBase::Constant(const Scalar& value) return DenseBase::NullaryExpr(RowsAtCompileTime, ColsAtCompileTime, internal::scalar_constant_op(value)); } -/** - * \brief Sets a linearly space vector. - * - * The function generates 'size' equally spaced values in the closed interval [low,high]. - * This particular version of LinSpaced() uses sequential access, i.e. vector access is - * assumed to be a(0), a(1), ..., a(size). This assumption allows for better vectorization - * and yields faster code than the random access version. +/** \deprecated because of accuracy loss. In Eigen 3.3, it is an alias for LinSpaced(Index,const Scalar&,const Scalar&) * - * When size is set to 1, a vector of length 1 containing 'high' is returned. - * - * \only_for_vectors - * - * Example: \include DenseBase_LinSpaced_seq.cpp - * Output: \verbinclude DenseBase_LinSpaced_seq.out - * - * \sa setLinSpaced(Index,const Scalar&,const Scalar&), LinSpaced(Index,Scalar,Scalar), CwiseNullaryOp + * \sa LinSpaced(Index,Scalar,Scalar), setLinSpaced(Index,const Scalar&,const Scalar&) */ template -EIGEN_STRONG_INLINE const typename DenseBase::SequentialLinSpacedReturnType +EIGEN_STRONG_INLINE const typename DenseBase::RandomAccessLinSpacedReturnType DenseBase::LinSpaced(Sequential_t, Index size, const Scalar& low, const Scalar& high) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return DenseBase::NullaryExpr(size, internal::linspaced_op(low,high,size)); + return DenseBase::NullaryExpr(size, internal::linspaced_op(low,high,size)); } -/** - * \copydoc DenseBase::LinSpaced(Sequential_t, Index, const Scalar&, const Scalar&) - * Special version for fixed size types which does not require the size parameter. +/** \deprecated because of accuracy loss. In Eigen 3.3, it is an alias for LinSpaced(const Scalar&,const Scalar&) + * + * \sa LinSpaced(Scalar,Scalar) */ template -EIGEN_STRONG_INLINE const typename DenseBase::SequentialLinSpacedReturnType +EIGEN_STRONG_INLINE const typename DenseBase::RandomAccessLinSpacedReturnType DenseBase::LinSpaced(Sequential_t, const Scalar& low, const Scalar& high) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) EIGEN_STATIC_ASSERT_FIXED_SIZE(Derived) - return DenseBase::NullaryExpr(Derived::SizeAtCompileTime, internal::linspaced_op(low,high,Derived::SizeAtCompileTime)); + return DenseBase::NullaryExpr(Derived::SizeAtCompileTime, internal::linspaced_op(low,high,Derived::SizeAtCompileTime)); } /** - * \brief Sets a linearly space vector. + * \brief Sets a linearly spaced vector. * * The function generates 'size' equally spaced values in the closed interval [low,high]. * When size is set to 1, a vector of length 1 containing 'high' is returned. @@ -269,14 +251,24 @@ DenseBase::LinSpaced(Sequential_t, const Scalar& low, const Scalar& hig * Example: \include DenseBase_LinSpaced.cpp * Output: \verbinclude DenseBase_LinSpaced.out * - * \sa setLinSpaced(Index,const Scalar&,const Scalar&), LinSpaced(Sequential_t,Index,const Scalar&,const Scalar&,Index), CwiseNullaryOp + * For integer scalar types, an even spacing is possible if and only if the length of the range, + * i.e., \c high-low is a scalar multiple of \c size-1, or if \c size is a scalar multiple of the + * number of values \c high-low+1 (meaning each value can be repeated the same number of time). + * If one of these two considions is not satisfied, then \c high is lowered to the largest value + * satisfying one of this constraint. + * Here are some examples: + * + * Example: \include DenseBase_LinSpacedInt.cpp + * Output: \verbinclude DenseBase_LinSpacedInt.out + * + * \sa setLinSpaced(Index,const Scalar&,const Scalar&), CwiseNullaryOp */ template EIGEN_STRONG_INLINE const typename DenseBase::RandomAccessLinSpacedReturnType DenseBase::LinSpaced(Index size, const Scalar& low, const Scalar& high) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return DenseBase::NullaryExpr(size, internal::linspaced_op(low,high,size)); + return DenseBase::NullaryExpr(size, internal::linspaced_op(low,high,size)); } /** @@ -289,7 +281,7 @@ DenseBase::LinSpaced(const Scalar& low, const Scalar& high) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) EIGEN_STATIC_ASSERT_FIXED_SIZE(Derived) - return DenseBase::NullaryExpr(Derived::SizeAtCompileTime, internal::linspaced_op(low,high,Derived::SizeAtCompileTime)); + return DenseBase::NullaryExpr(Derived::SizeAtCompileTime, internal::linspaced_op(low,high,Derived::SizeAtCompileTime)); } /** \returns true if all coefficients in this matrix are approximately equal to \a val, to within precision \a prec */ @@ -297,9 +289,10 @@ template bool DenseBase::isApproxToConstant (const Scalar& val, const RealScalar& prec) const { + typename internal::nested_eval::type self(derived()); for(Index j = 0; j < cols(); ++j) for(Index i = 0; i < rows(); ++i) - if(!internal::isApprox(this->coeff(i, j), val, prec)) + if(!internal::isApprox(self.coeff(i, j), val, prec)) return false; return true; } @@ -324,7 +317,7 @@ EIGEN_STRONG_INLINE void DenseBase::fill(const Scalar& val) setConstant(val); } -/** Sets all coefficients in this expression to \a value. +/** Sets all coefficients in this expression to value \a val. * * \sa fill(), setConstant(Index,const Scalar&), setConstant(Index,Index,const Scalar&), setZero(), setOnes(), Constant(), class CwiseNullaryOp, setZero(), setOnes() */ @@ -334,7 +327,7 @@ EIGEN_STRONG_INLINE Derived& DenseBase::setConstant(const Scalar& val) return derived() = Constant(rows(), cols(), val); } -/** Resizes to the given \a size, and sets all coefficients in this expression to the given \a value. +/** Resizes to the given \a size, and sets all coefficients in this expression to the given value \a val. * * \only_for_vectors * @@ -351,10 +344,10 @@ PlainObjectBase::setConstant(Index size, const Scalar& val) return setConstant(val); } -/** Resizes to the given size, and sets all coefficients in this expression to the given \a value. +/** Resizes to the given size, and sets all coefficients in this expression to the given value \a val. * - * \param nbRows the new number of rows - * \param nbCols the new number of columns + * \param rows the new number of rows + * \param cols the new number of columns * \param val the value to which all coefficients are set * * Example: \include Matrix_setConstant_int_int.cpp @@ -364,14 +357,14 @@ PlainObjectBase::setConstant(Index size, const Scalar& val) */ template EIGEN_STRONG_INLINE Derived& -PlainObjectBase::setConstant(Index nbRows, Index nbCols, const Scalar& val) +PlainObjectBase::setConstant(Index rows, Index cols, const Scalar& val) { - resize(nbRows, nbCols); + resize(rows, cols); return setConstant(val); } /** - * \brief Sets a linearly space vector. + * \brief Sets a linearly spaced vector. * * The function generates 'size' equally spaced values in the closed interval [low,high]. * When size is set to 1, a vector of length 1 containing 'high' is returned. @@ -381,24 +374,30 @@ PlainObjectBase::setConstant(Index nbRows, Index nbCols, const Scalar& * Example: \include DenseBase_setLinSpaced.cpp * Output: \verbinclude DenseBase_setLinSpaced.out * - * \sa CwiseNullaryOp + * For integer scalar types, do not miss the explanations on the definition + * of \link LinSpaced(Index,const Scalar&,const Scalar&) even spacing \endlink. + * + * \sa LinSpaced(Index,const Scalar&,const Scalar&), CwiseNullaryOp */ template EIGEN_STRONG_INLINE Derived& DenseBase::setLinSpaced(Index newSize, const Scalar& low, const Scalar& high) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - return derived() = Derived::NullaryExpr(newSize, internal::linspaced_op(low,high,newSize)); + return derived() = Derived::NullaryExpr(newSize, internal::linspaced_op(low,high,newSize)); } /** - * \brief Sets a linearly space vector. + * \brief Sets a linearly spaced vector. * - * The function fill *this with equally spaced values in the closed interval [low,high]. + * The function fills \c *this with equally spaced values in the closed interval [low,high]. * When size is set to 1, a vector of length 1 containing 'high' is returned. * * \only_for_vectors * - * \sa setLinSpaced(Index, const Scalar&, const Scalar&), CwiseNullaryOp + * For integer scalar types, do not miss the explanations on the definition + * of \link LinSpaced(Index,const Scalar&,const Scalar&) even spacing \endlink. + * + * \sa LinSpaced(Index,const Scalar&,const Scalar&), setLinSpaced(Index, const Scalar&, const Scalar&), CwiseNullaryOp */ template EIGEN_STRONG_INLINE Derived& DenseBase::setLinSpaced(const Scalar& low, const Scalar& high) @@ -425,9 +424,9 @@ EIGEN_STRONG_INLINE Derived& DenseBase::setLinSpaced(const Scalar& low, */ template EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType -DenseBase::Zero(Index nbRows, Index nbCols) +DenseBase::Zero(Index rows, Index cols) { - return Constant(nbRows, nbCols, Scalar(0)); + return Constant(rows, cols, Scalar(0)); } /** \returns an expression of a zero vector. @@ -481,9 +480,10 @@ DenseBase::Zero() template bool DenseBase::isZero(const RealScalar& prec) const { + typename internal::nested_eval::type self(derived()); for(Index j = 0; j < cols(); ++j) for(Index i = 0; i < rows(); ++i) - if(!internal::isMuchSmallerThan(this->coeff(i, j), static_cast(1), prec)) + if(!internal::isMuchSmallerThan(self.coeff(i, j), static_cast(1), prec)) return false; return true; } @@ -520,8 +520,8 @@ PlainObjectBase::setZero(Index newSize) /** Resizes to the given size, and sets all coefficients in this expression to zero. * - * \param nbRows the new number of rows - * \param nbCols the new number of columns + * \param rows the new number of rows + * \param cols the new number of columns * * Example: \include Matrix_setZero_int_int.cpp * Output: \verbinclude Matrix_setZero_int_int.out @@ -530,9 +530,9 @@ PlainObjectBase::setZero(Index newSize) */ template EIGEN_STRONG_INLINE Derived& -PlainObjectBase::setZero(Index nbRows, Index nbCols) +PlainObjectBase::setZero(Index rows, Index cols) { - resize(nbRows, nbCols); + resize(rows, cols); return setConstant(Scalar(0)); } @@ -540,7 +540,7 @@ PlainObjectBase::setZero(Index nbRows, Index nbCols) /** \returns an expression of a matrix where all coefficients equal one. * - * The parameters \a nbRows and \a nbCols are the number of rows and of columns of + * The parameters \a rows and \a cols are the number of rows and of columns of * the returned matrix. Must be compatible with this MatrixBase type. * * This variant is meant to be used for dynamic-size matrix types. For fixed-size types, @@ -554,9 +554,9 @@ PlainObjectBase::setZero(Index nbRows, Index nbCols) */ template EIGEN_STRONG_INLINE const typename DenseBase::ConstantReturnType -DenseBase::Ones(Index nbRows, Index nbCols) +DenseBase::Ones(Index rows, Index cols) { - return Constant(nbRows, nbCols, Scalar(1)); + return Constant(rows, cols, Scalar(1)); } /** \returns an expression of a vector where all coefficients equal one. @@ -646,8 +646,8 @@ PlainObjectBase::setOnes(Index newSize) /** Resizes to the given size, and sets all coefficients in this expression to one. * - * \param nbRows the new number of rows - * \param nbCols the new number of columns + * \param rows the new number of rows + * \param cols the new number of columns * * Example: \include Matrix_setOnes_int_int.cpp * Output: \verbinclude Matrix_setOnes_int_int.out @@ -656,9 +656,9 @@ PlainObjectBase::setOnes(Index newSize) */ template EIGEN_STRONG_INLINE Derived& -PlainObjectBase::setOnes(Index nbRows, Index nbCols) +PlainObjectBase::setOnes(Index rows, Index cols) { - resize(nbRows, nbCols); + resize(rows, cols); return setConstant(Scalar(1)); } @@ -666,7 +666,7 @@ PlainObjectBase::setOnes(Index nbRows, Index nbCols) /** \returns an expression of the identity matrix (not necessarily square). * - * The parameters \a nbRows and \a nbCols are the number of rows and of columns of + * The parameters \a rows and \a cols are the number of rows and of columns of * the returned matrix. Must be compatible with this MatrixBase type. * * This variant is meant to be used for dynamic-size matrix types. For fixed-size types, @@ -680,9 +680,9 @@ PlainObjectBase::setOnes(Index nbRows, Index nbCols) */ template EIGEN_STRONG_INLINE const typename MatrixBase::IdentityReturnType -MatrixBase::Identity(Index nbRows, Index nbCols) +MatrixBase::Identity(Index rows, Index cols) { - return DenseBase::NullaryExpr(nbRows, nbCols, internal::scalar_identity_op()); + return DenseBase::NullaryExpr(rows, cols, internal::scalar_identity_op()); } /** \returns an expression of the identity matrix (not necessarily square). @@ -716,18 +716,19 @@ template bool MatrixBase::isIdentity (const RealScalar& prec) const { + typename internal::nested_eval::type self(derived()); for(Index j = 0; j < cols(); ++j) { for(Index i = 0; i < rows(); ++i) { if(i == j) { - if(!internal::isApprox(this->coeff(i, j), static_cast(1), prec)) + if(!internal::isApprox(self.coeff(i, j), static_cast(1), prec)) return false; } else { - if(!internal::isMuchSmallerThan(this->coeff(i, j), static_cast(1), prec)) + if(!internal::isMuchSmallerThan(self.coeff(i, j), static_cast(1), prec)) return false; } } @@ -740,6 +741,7 @@ namespace internal { template=16)> struct setIdentity_impl { + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE Derived& run(Derived& m) { return m = Derived::Identity(m.rows(), m.cols()); @@ -749,11 +751,11 @@ struct setIdentity_impl template struct setIdentity_impl { - typedef typename Derived::Index Index; + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE Derived& run(Derived& m) { m.setZero(); - const Index size = (std::min)(m.rows(), m.cols()); + const Index size = numext::mini(m.rows(), m.cols()); for(Index i = 0; i < size; ++i) m.coeffRef(i,i) = typename Derived::Scalar(1); return m; } @@ -776,8 +778,8 @@ EIGEN_STRONG_INLINE Derived& MatrixBase::setIdentity() /** \brief Resizes to the given size, and writes the identity expression (not necessarily square) into *this. * - * \param nbRows the new number of rows - * \param nbCols the new number of columns + * \param rows the new number of rows + * \param cols the new number of columns * * Example: \include Matrix_setIdentity_int_int.cpp * Output: \verbinclude Matrix_setIdentity_int_int.out @@ -785,9 +787,9 @@ EIGEN_STRONG_INLINE Derived& MatrixBase::setIdentity() * \sa MatrixBase::setIdentity(), class CwiseNullaryOp, MatrixBase::Identity() */ template -EIGEN_STRONG_INLINE Derived& MatrixBase::setIdentity(Index nbRows, Index nbCols) +EIGEN_STRONG_INLINE Derived& MatrixBase::setIdentity(Index rows, Index cols) { - derived().resize(nbRows, nbCols); + derived().resize(rows, cols); return setIdentity(); } diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Core/CwiseTernaryOp.h b/ground/gcs/src/libs/eigen/Eigen/src/Core/CwiseTernaryOp.h new file mode 100644 index 0000000000..9f3576fece --- /dev/null +++ b/ground/gcs/src/libs/eigen/Eigen/src/Core/CwiseTernaryOp.h @@ -0,0 +1,197 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2014 Gael Guennebaud +// Copyright (C) 2006-2008 Benoit Jacob +// Copyright (C) 2016 Eugene Brevdo +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CWISE_TERNARY_OP_H +#define EIGEN_CWISE_TERNARY_OP_H + +namespace Eigen { + +namespace internal { +template +struct traits > { + // we must not inherit from traits since it has + // the potential to cause problems with MSVC + typedef typename remove_all::type Ancestor; + typedef typename traits::XprKind XprKind; + enum { + RowsAtCompileTime = traits::RowsAtCompileTime, + ColsAtCompileTime = traits::ColsAtCompileTime, + MaxRowsAtCompileTime = traits::MaxRowsAtCompileTime, + MaxColsAtCompileTime = traits::MaxColsAtCompileTime + }; + + // even though we require Arg1, Arg2, and Arg3 to have the same scalar type + // (see CwiseTernaryOp constructor), + // we still want to handle the case when the result type is different. + typedef typename result_of::type Scalar; + + typedef typename internal::traits::StorageKind StorageKind; + typedef typename internal::traits::StorageIndex StorageIndex; + + typedef typename Arg1::Nested Arg1Nested; + typedef typename Arg2::Nested Arg2Nested; + typedef typename Arg3::Nested Arg3Nested; + typedef typename remove_reference::type _Arg1Nested; + typedef typename remove_reference::type _Arg2Nested; + typedef typename remove_reference::type _Arg3Nested; + enum { Flags = _Arg1Nested::Flags & RowMajorBit }; +}; +} // end namespace internal + +template +class CwiseTernaryOpImpl; + +/** \class CwiseTernaryOp + * \ingroup Core_Module + * + * \brief Generic expression where a coefficient-wise ternary operator is + * applied to two expressions + * + * \tparam TernaryOp template functor implementing the operator + * \tparam Arg1Type the type of the first argument + * \tparam Arg2Type the type of the second argument + * \tparam Arg3Type the type of the third argument + * + * This class represents an expression where a coefficient-wise ternary + * operator is applied to three expressions. + * It is the return type of ternary operators, by which we mean only those + * ternary operators where + * all three arguments are Eigen expressions. + * For example, the return type of betainc(matrix1, matrix2, matrix3) is a + * CwiseTernaryOp. + * + * Most of the time, this is the only way that it is used, so you typically + * don't have to name + * CwiseTernaryOp types explicitly. + * + * \sa MatrixBase::ternaryExpr(const MatrixBase &, const + * MatrixBase &, const CustomTernaryOp &) const, class CwiseBinaryOp, + * class CwiseUnaryOp, class CwiseNullaryOp + */ +template +class CwiseTernaryOp : public CwiseTernaryOpImpl< + TernaryOp, Arg1Type, Arg2Type, Arg3Type, + typename internal::traits::StorageKind>, + internal::no_assignment_operator +{ + public: + typedef typename internal::remove_all::type Arg1; + typedef typename internal::remove_all::type Arg2; + typedef typename internal::remove_all::type Arg3; + + typedef typename CwiseTernaryOpImpl< + TernaryOp, Arg1Type, Arg2Type, Arg3Type, + typename internal::traits::StorageKind>::Base Base; + EIGEN_GENERIC_PUBLIC_INTERFACE(CwiseTernaryOp) + + typedef typename internal::ref_selector::type Arg1Nested; + typedef typename internal::ref_selector::type Arg2Nested; + typedef typename internal::ref_selector::type Arg3Nested; + typedef typename internal::remove_reference::type _Arg1Nested; + typedef typename internal::remove_reference::type _Arg2Nested; + typedef typename internal::remove_reference::type _Arg3Nested; + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE CwiseTernaryOp(const Arg1& a1, const Arg2& a2, + const Arg3& a3, + const TernaryOp& func = TernaryOp()) + : m_arg1(a1), m_arg2(a2), m_arg3(a3), m_functor(func) { + // require the sizes to match + EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(Arg1, Arg2) + EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(Arg1, Arg3) + + // The index types should match + EIGEN_STATIC_ASSERT((internal::is_same< + typename internal::traits::StorageKind, + typename internal::traits::StorageKind>::value), + STORAGE_KIND_MUST_MATCH) + EIGEN_STATIC_ASSERT((internal::is_same< + typename internal::traits::StorageKind, + typename internal::traits::StorageKind>::value), + STORAGE_KIND_MUST_MATCH) + + eigen_assert(a1.rows() == a2.rows() && a1.cols() == a2.cols() && + a1.rows() == a3.rows() && a1.cols() == a3.cols()); + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Index rows() const { + // return the fixed size type if available to enable compile time + // optimizations + if (internal::traits::type>:: + RowsAtCompileTime == Dynamic && + internal::traits::type>:: + RowsAtCompileTime == Dynamic) + return m_arg3.rows(); + else if (internal::traits::type>:: + RowsAtCompileTime == Dynamic && + internal::traits::type>:: + RowsAtCompileTime == Dynamic) + return m_arg2.rows(); + else + return m_arg1.rows(); + } + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Index cols() const { + // return the fixed size type if available to enable compile time + // optimizations + if (internal::traits::type>:: + ColsAtCompileTime == Dynamic && + internal::traits::type>:: + ColsAtCompileTime == Dynamic) + return m_arg3.cols(); + else if (internal::traits::type>:: + ColsAtCompileTime == Dynamic && + internal::traits::type>:: + ColsAtCompileTime == Dynamic) + return m_arg2.cols(); + else + return m_arg1.cols(); + } + + /** \returns the first argument nested expression */ + EIGEN_DEVICE_FUNC + const _Arg1Nested& arg1() const { return m_arg1; } + /** \returns the first argument nested expression */ + EIGEN_DEVICE_FUNC + const _Arg2Nested& arg2() const { return m_arg2; } + /** \returns the third argument nested expression */ + EIGEN_DEVICE_FUNC + const _Arg3Nested& arg3() const { return m_arg3; } + /** \returns the functor representing the ternary operation */ + EIGEN_DEVICE_FUNC + const TernaryOp& functor() const { return m_functor; } + + protected: + Arg1Nested m_arg1; + Arg2Nested m_arg2; + Arg3Nested m_arg3; + const TernaryOp m_functor; +}; + +// Generic API dispatcher +template +class CwiseTernaryOpImpl + : public internal::generic_xpr_base< + CwiseTernaryOp >::type { + public: + typedef typename internal::generic_xpr_base< + CwiseTernaryOp >::type Base; +}; + +} // end namespace Eigen + +#endif // EIGEN_CWISE_TERNARY_OP_H diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Core/CwiseUnaryOp.h b/ground/gcs/src/libs/eigen/Eigen/src/Core/CwiseUnaryOp.h index f7ee60e987..1d2dd19f2b 100644 --- a/ground/gcs/src/libs/eigen/Eigen/src/Core/CwiseUnaryOp.h +++ b/ground/gcs/src/libs/eigen/Eigen/src/Core/CwiseUnaryOp.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008-2010 Gael Guennebaud +// Copyright (C) 2008-2014 Gael Guennebaud // Copyright (C) 2006-2008 Benoit Jacob // // This Source Code Form is subject to the terms of the Mozilla @@ -13,41 +13,18 @@ namespace Eigen { -/** \class CwiseUnaryOp - * \ingroup Core_Module - * - * \brief Generic expression where a coefficient-wise unary operator is applied to an expression - * - * \param UnaryOp template functor implementing the operator - * \param XprType the type of the expression to which we are applying the unary operator - * - * This class represents an expression where a unary operator is applied to an expression. - * It is the return type of all operations taking exactly 1 input expression, regardless of the - * presence of other inputs such as scalars. For example, the operator* in the expression 3*matrix - * is considered unary, because only the right-hand side is an expression, and its - * return type is a specialization of CwiseUnaryOp. - * - * Most of the time, this is the only way that it is used, so you typically don't have to name - * CwiseUnaryOp types explicitly. - * - * \sa MatrixBase::unaryExpr(const CustomUnaryOp &) const, class CwiseBinaryOp, class CwiseNullaryOp - */ - namespace internal { template struct traits > : traits { typedef typename result_of< - UnaryOp(typename XprType::Scalar) + UnaryOp(const typename XprType::Scalar&) >::type Scalar; typedef typename XprType::Nested XprTypeNested; typedef typename remove_reference::type _XprTypeNested; enum { - Flags = _XprTypeNested::Flags & ( - HereditaryBits | LinearAccessBit | AlignedBit - | (functor_traits::PacketAccess ? PacketAccessBit : 0)), - CoeffReadCost = EIGEN_ADD_COST(_XprTypeNested::CoeffReadCost, functor_traits::Cost) + Flags = _XprTypeNested::Flags & RowMajorBit }; }; } @@ -55,70 +32,70 @@ struct traits > template class CwiseUnaryOpImpl; +/** \class CwiseUnaryOp + * \ingroup Core_Module + * + * \brief Generic expression where a coefficient-wise unary operator is applied to an expression + * + * \tparam UnaryOp template functor implementing the operator + * \tparam XprType the type of the expression to which we are applying the unary operator + * + * This class represents an expression where a unary operator is applied to an expression. + * It is the return type of all operations taking exactly 1 input expression, regardless of the + * presence of other inputs such as scalars. For example, the operator* in the expression 3*matrix + * is considered unary, because only the right-hand side is an expression, and its + * return type is a specialization of CwiseUnaryOp. + * + * Most of the time, this is the only way that it is used, so you typically don't have to name + * CwiseUnaryOp types explicitly. + * + * \sa MatrixBase::unaryExpr(const CustomUnaryOp &) const, class CwiseBinaryOp, class CwiseNullaryOp + */ template -class CwiseUnaryOp : internal::no_assignment_operator, - public CwiseUnaryOpImpl::StorageKind> +class CwiseUnaryOp : public CwiseUnaryOpImpl::StorageKind>, internal::no_assignment_operator { public: typedef typename CwiseUnaryOpImpl::StorageKind>::Base Base; EIGEN_GENERIC_PUBLIC_INTERFACE(CwiseUnaryOp) + typedef typename internal::ref_selector::type XprTypeNested; + typedef typename internal::remove_all::type NestedExpression; - inline CwiseUnaryOp(const XprType& xpr, const UnaryOp& func = UnaryOp()) + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + explicit CwiseUnaryOp(const XprType& xpr, const UnaryOp& func = UnaryOp()) : m_xpr(xpr), m_functor(func) {} - EIGEN_STRONG_INLINE Index rows() const { return m_xpr.rows(); } - EIGEN_STRONG_INLINE Index cols() const { return m_xpr.cols(); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Index rows() const { return m_xpr.rows(); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Index cols() const { return m_xpr.cols(); } /** \returns the functor representing the unary operation */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const UnaryOp& functor() const { return m_functor; } /** \returns the nested expression */ - const typename internal::remove_all::type& + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const typename internal::remove_all::type& nestedExpression() const { return m_xpr; } /** \returns the nested expression */ - typename internal::remove_all::type& - nestedExpression() { return m_xpr.const_cast_derived(); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + typename internal::remove_all::type& + nestedExpression() { return m_xpr; } protected: - typename XprType::Nested m_xpr; + XprTypeNested m_xpr; const UnaryOp m_functor; }; -// This is the generic implementation for dense storage. -// It can be used for any expression types implementing the dense concept. -template -class CwiseUnaryOpImpl - : public internal::dense_xpr_base >::type +// Generic API dispatcher +template +class CwiseUnaryOpImpl + : public internal::generic_xpr_base >::type { - public: - - typedef CwiseUnaryOp Derived; - typedef typename internal::dense_xpr_base >::type Base; - EIGEN_DENSE_PUBLIC_INTERFACE(Derived) - - EIGEN_STRONG_INLINE const Scalar coeff(Index rowId, Index colId) const - { - return derived().functor()(derived().nestedExpression().coeff(rowId, colId)); - } - - template - EIGEN_STRONG_INLINE PacketScalar packet(Index rowId, Index colId) const - { - return derived().functor().packetOp(derived().nestedExpression().template packet(rowId, colId)); - } - - EIGEN_STRONG_INLINE const Scalar coeff(Index index) const - { - return derived().functor()(derived().nestedExpression().coeff(index)); - } - - template - EIGEN_STRONG_INLINE PacketScalar packet(Index index) const - { - return derived().functor().packetOp(derived().nestedExpression().template packet(index)); - } +public: + typedef typename internal::generic_xpr_base >::type Base; }; } // end namespace Eigen diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Core/CwiseUnaryView.h b/ground/gcs/src/libs/eigen/Eigen/src/Core/CwiseUnaryView.h index f3b2ffeb6f..2710330562 100644 --- a/ground/gcs/src/libs/eigen/Eigen/src/Core/CwiseUnaryView.h +++ b/ground/gcs/src/libs/eigen/Eigen/src/Core/CwiseUnaryView.h @@ -12,33 +12,19 @@ namespace Eigen { -/** \class CwiseUnaryView - * \ingroup Core_Module - * - * \brief Generic lvalue expression of a coefficient-wise unary operator of a matrix or a vector - * - * \param ViewOp template functor implementing the view - * \param MatrixType the type of the matrix we are applying the unary operator - * - * This class represents a lvalue expression of a generic unary view operator of a matrix or a vector. - * It is the return type of real() and imag(), and most of the time this is the only way it is used. - * - * \sa MatrixBase::unaryViewExpr(const CustomUnaryOp &) const, class CwiseUnaryOp - */ - namespace internal { template struct traits > : traits { typedef typename result_of< - ViewOp(typename traits::Scalar) + ViewOp(const typename traits::Scalar&) >::type Scalar; typedef typename MatrixType::Nested MatrixTypeNested; typedef typename remove_all::type _MatrixTypeNested; enum { - Flags = (traits<_MatrixTypeNested>::Flags & (HereditaryBits | LvalueBit | LinearAccessBit | DirectAccessBit)), - CoeffReadCost = EIGEN_ADD_COST(traits<_MatrixTypeNested>::CoeffReadCost, functor_traits::Cost), + FlagsLvalueBit = is_lvalue::value ? LvalueBit : 0, + Flags = traits<_MatrixTypeNested>::Flags & (RowMajorBit | FlagsLvalueBit | DirectAccessBit), // FIXME DirectAccessBit should not be handled by expressions MatrixTypeInnerStride = inner_stride_at_compile_time::ret, // need to cast the sizeof's from size_t to int explicitly, otherwise: // "error: no integral type can represent all of the enumerator values @@ -55,6 +41,19 @@ struct traits > template class CwiseUnaryViewImpl; +/** \class CwiseUnaryView + * \ingroup Core_Module + * + * \brief Generic lvalue expression of a coefficient-wise unary operator of a matrix or a vector + * + * \tparam ViewOp template functor implementing the view + * \tparam MatrixType the type of the matrix we are applying the unary operator + * + * This class represents a lvalue expression of a generic unary view operator of a matrix or a vector. + * It is the return type of real() and imag(), and most of the time this is the only way it is used. + * + * \sa MatrixBase::unaryViewExpr(const CustomUnaryOp &) const, class CwiseUnaryOp + */ template class CwiseUnaryView : public CwiseUnaryViewImpl::StorageKind> { @@ -62,8 +61,10 @@ class CwiseUnaryView : public CwiseUnaryViewImpl::StorageKind>::Base Base; EIGEN_GENERIC_PUBLIC_INTERFACE(CwiseUnaryView) + typedef typename internal::ref_selector::non_const_type MatrixTypeNested; + typedef typename internal::remove_all::type NestedExpression; - inline CwiseUnaryView(const MatrixType& mat, const ViewOp& func = ViewOp()) + explicit inline CwiseUnaryView(MatrixType& mat, const ViewOp& func = ViewOp()) : m_matrix(mat), m_functor(func) {} EIGEN_INHERIT_ASSIGNMENT_OPERATORS(CwiseUnaryView) @@ -75,19 +76,27 @@ class CwiseUnaryView : public CwiseUnaryViewImpl::type& + const typename internal::remove_all::type& nestedExpression() const { return m_matrix; } /** \returns the nested expression */ - typename internal::remove_all::type& + typename internal::remove_reference::type& nestedExpression() { return m_matrix.const_cast_derived(); } protected: - // FIXME changed from MatrixType::Nested because of a weird compilation error with sun CC - typename internal::nested::type m_matrix; + MatrixTypeNested m_matrix; ViewOp m_functor; }; +// Generic API dispatcher +template +class CwiseUnaryViewImpl + : public internal::generic_xpr_base >::type +{ +public: + typedef typename internal::generic_xpr_base >::type Base; +}; + template class CwiseUnaryViewImpl : public internal::dense_xpr_base< CwiseUnaryView >::type @@ -100,38 +109,18 @@ class CwiseUnaryViewImpl EIGEN_DENSE_PUBLIC_INTERFACE(Derived) EIGEN_INHERIT_ASSIGNMENT_OPERATORS(CwiseUnaryViewImpl) - inline Scalar* data() { return &coeffRef(0); } - inline const Scalar* data() const { return &coeff(0); } + EIGEN_DEVICE_FUNC inline Scalar* data() { return &(this->coeffRef(0)); } + EIGEN_DEVICE_FUNC inline const Scalar* data() const { return &(this->coeff(0)); } - inline Index innerStride() const + EIGEN_DEVICE_FUNC inline Index innerStride() const { return derived().nestedExpression().innerStride() * sizeof(typename internal::traits::Scalar) / sizeof(Scalar); } - inline Index outerStride() const + EIGEN_DEVICE_FUNC inline Index outerStride() const { return derived().nestedExpression().outerStride() * sizeof(typename internal::traits::Scalar) / sizeof(Scalar); } - - EIGEN_STRONG_INLINE CoeffReturnType coeff(Index row, Index col) const - { - return derived().functor()(derived().nestedExpression().coeff(row, col)); - } - - EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const - { - return derived().functor()(derived().nestedExpression().coeff(index)); - } - - EIGEN_STRONG_INLINE Scalar& coeffRef(Index row, Index col) - { - return derived().functor()(const_cast_derived().nestedExpression().coeffRef(row, col)); - } - - EIGEN_STRONG_INLINE Scalar& coeffRef(Index index) - { - return derived().functor()(const_cast_derived().nestedExpression().coeffRef(index)); - } }; } // end namespace Eigen diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Core/DenseBase.h b/ground/gcs/src/libs/eigen/Eigen/src/Core/DenseBase.h index 4b371b075b..46fe5193c2 100644 --- a/ground/gcs/src/libs/eigen/Eigen/src/Core/DenseBase.h +++ b/ground/gcs/src/libs/eigen/Eigen/src/Core/DenseBase.h @@ -34,37 +34,45 @@ static inline void check_DenseIndex_is_signed() { * \tparam Derived is the derived type, e.g., a matrix type or an expression. * * This class can be extended with the help of the plugin mechanism described on the page - * \ref TopicCustomizingEigen by defining the preprocessor symbol \c EIGEN_DENSEBASE_PLUGIN. + * \ref TopicCustomizing_Plugins by defining the preprocessor symbol \c EIGEN_DENSEBASE_PLUGIN. * - * \sa \ref TopicClassHierarchy + * \sa \blank \ref TopicClassHierarchy */ template class DenseBase #ifndef EIGEN_PARSED_BY_DOXYGEN - : public internal::special_scalar_op_base::Scalar, - typename NumTraits::Scalar>::Real, - DenseCoeffsBase > -#else : public DenseCoeffsBase +#else + : public DenseCoeffsBase #endif // not EIGEN_PARSED_BY_DOXYGEN { public: - class InnerIterator; + /** Inner iterator type to iterate over the coefficients of a row or column. + * \sa class InnerIterator + */ + typedef Eigen::InnerIterator InnerIterator; typedef typename internal::traits::StorageKind StorageKind; - /** \brief The type of indices - * \details To change this, \c \#define the preprocessor symbol \c EIGEN_DEFAULT_DENSE_INDEX_TYPE. - * \sa \ref TopicPreprocessorDirectives. - */ - typedef typename internal::traits::Index Index; + /** + * \brief The type used to store indices + * \details This typedef is relevant for types that store multiple indices such as + * PermutationMatrix or Transpositions, otherwise it defaults to Eigen::Index + * \sa \blank \ref TopicPreprocessorDirectives, Eigen::Index, SparseMatrixBase. + */ + typedef typename internal::traits::StorageIndex StorageIndex; + /** The numeric type of the expression' coefficients, e.g. float, double, int or std::complex, etc. */ typedef typename internal::traits::Scalar Scalar; - typedef typename internal::packet_traits::type PacketScalar; + + /** The numeric type of the expression' coefficients, e.g. float, double, int or std::complex, etc. + * + * It is an alias for the Scalar type */ + typedef Scalar value_type; + typedef typename NumTraits::Real RealScalar; - typedef internal::special_scalar_op_base > Base; + typedef DenseCoeffsBase Base; - using Base::operator*; using Base::derived; using Base::const_cast_derived; using Base::rows; @@ -74,16 +82,6 @@ template class DenseBase using Base::colIndexByOuterInner; using Base::coeff; using Base::coeffByOuterInner; - using Base::packet; - using Base::packetByOuterInner; - using Base::writePacket; - using Base::writePacketByOuterInner; - using Base::coeffRef; - using Base::coeffRefByOuterInner; - using Base::copyCoeff; - using Base::copyCoeffByOuterInner; - using Base::copyPacket; - using Base::copyPacketByOuterInner; using Base::operator(); using Base::operator[]; using Base::x; @@ -169,19 +167,46 @@ template class DenseBase InnerSizeAtCompileTime = int(IsVectorAtCompileTime) ? int(SizeAtCompileTime) : int(IsRowMajor) ? int(ColsAtCompileTime) : int(RowsAtCompileTime), - CoeffReadCost = internal::traits::CoeffReadCost, - /**< This is a rough measure of how expensive it is to read one coefficient from - * this expression. - */ - InnerStrideAtCompileTime = internal::inner_stride_at_compile_time::ret, OuterStrideAtCompileTime = internal::outer_stride_at_compile_time::ret }; + + typedef typename internal::find_best_packet::type PacketScalar; - enum { ThisConstantIsPrivateInPlainObjectBase }; + enum { IsPlainObjectBase = 0 }; + + /** The plain matrix type corresponding to this expression. + * \sa PlainObject */ + typedef Matrix::Scalar, + internal::traits::RowsAtCompileTime, + internal::traits::ColsAtCompileTime, + AutoAlign | (internal::traits::Flags&RowMajorBit ? RowMajor : ColMajor), + internal::traits::MaxRowsAtCompileTime, + internal::traits::MaxColsAtCompileTime + > PlainMatrix; + + /** The plain array type corresponding to this expression. + * \sa PlainObject */ + typedef Array::Scalar, + internal::traits::RowsAtCompileTime, + internal::traits::ColsAtCompileTime, + AutoAlign | (internal::traits::Flags&RowMajorBit ? RowMajor : ColMajor), + internal::traits::MaxRowsAtCompileTime, + internal::traits::MaxColsAtCompileTime + > PlainArray; + + /** \brief The plain matrix or array type corresponding to this expression. + * + * This is not necessarily exactly the return type of eval(). In the case of plain matrices, + * the return type of eval() is a const reference to a matrix, not a matrix! It is however guaranteed + * that the return type of eval() is either PlainObject or const PlainObject&. + */ + typedef typename internal::conditional::XprKind,MatrixXpr >::value, + PlainMatrix, PlainArray>::type PlainObject; /** \returns the number of nonzero coefficients which is in practice the number * of stored coefficients. */ + EIGEN_DEVICE_FUNC inline Index nonZeros() const { return size(); } /** \returns the outer size. @@ -189,6 +214,7 @@ template class DenseBase * \note For a vector, this returns just 1. For a matrix (non-vector), this is the major dimension * with respect to the \ref TopicStorageOrders "storage order", i.e., the number of columns for a * column-major matrix, and the number of rows for a row-major matrix. */ + EIGEN_DEVICE_FUNC Index outerSize() const { return IsVectorAtCompileTime ? 1 @@ -200,6 +226,7 @@ template class DenseBase * \note For a vector, this is just the size. For a matrix (non-vector), this is the minor dimension * with respect to the \ref TopicStorageOrders "storage order", i.e., the number of rows for a * column-major matrix, and the number of columns for a row-major matrix. */ + EIGEN_DEVICE_FUNC Index innerSize() const { return IsVectorAtCompileTime ? this->size() @@ -210,6 +237,7 @@ template class DenseBase * Matrix::resize() and Array::resize(). The present method only asserts that the new size equals the old size, and does * nothing else. */ + EIGEN_DEVICE_FUNC void resize(Index newSize) { EIGEN_ONLY_USED_FOR_DEBUG(newSize); @@ -220,22 +248,22 @@ template class DenseBase * Matrix::resize() and Array::resize(). The present method only asserts that the new size equals the old size, and does * nothing else. */ - void resize(Index nbRows, Index nbCols) + EIGEN_DEVICE_FUNC + void resize(Index rows, Index cols) { - EIGEN_ONLY_USED_FOR_DEBUG(nbRows); - EIGEN_ONLY_USED_FOR_DEBUG(nbCols); - eigen_assert(nbRows == this->rows() && nbCols == this->cols() + EIGEN_ONLY_USED_FOR_DEBUG(rows); + EIGEN_ONLY_USED_FOR_DEBUG(cols); + eigen_assert(rows == this->rows() && cols == this->cols() && "DenseBase::resize() does not actually allow to resize."); } #ifndef EIGEN_PARSED_BY_DOXYGEN - /** \internal Represents a matrix with all coefficients equal to one another*/ - typedef CwiseNullaryOp,Derived> ConstantReturnType; - /** \internal Represents a vector with linearly spaced coefficients that allows sequential access only. */ - typedef CwiseNullaryOp,Derived> SequentialLinSpacedReturnType; + typedef CwiseNullaryOp,PlainObject> ConstantReturnType; + /** \internal \deprecated Represents a vector with linearly spaced coefficients that allows sequential access only. */ + typedef CwiseNullaryOp,PlainObject> SequentialLinSpacedReturnType; /** \internal Represents a vector with linearly spaced coefficients that allows random access. */ - typedef CwiseNullaryOp,Derived> RandomAccessLinSpacedReturnType; + typedef CwiseNullaryOp,PlainObject> RandomAccessLinSpacedReturnType; /** \internal the return type of MatrixBase::eigenvalues() */ typedef Matrix::Scalar>::Real, internal::traits::ColsAtCompileTime, 1> EigenvaluesReturnType; @@ -243,120 +271,133 @@ template class DenseBase /** Copies \a other into *this. \returns a reference to *this. */ template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator=(const DenseBase& other); /** Special case of the template operator=, in order to prevent the compiler * from generating a default operator= (issue hit with g++ 4.1) */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator=(const DenseBase& other); template + EIGEN_DEVICE_FUNC Derived& operator=(const EigenBase &other); template + EIGEN_DEVICE_FUNC Derived& operator+=(const EigenBase &other); template + EIGEN_DEVICE_FUNC Derived& operator-=(const EigenBase &other); template + EIGEN_DEVICE_FUNC Derived& operator=(const ReturnByValue& func); - /** \internal Copies \a other into *this without evaluating other. \returns a reference to *this. */ + /** \ínternal + * Copies \a other into *this without evaluating other. \returns a reference to *this. + * \deprecated */ template + EIGEN_DEVICE_FUNC Derived& lazyAssign(const DenseBase& other); - /** \internal Evaluates \a other into *this. \returns a reference to *this. */ - template - Derived& lazyAssign(const ReturnByValue& other); - + EIGEN_DEVICE_FUNC CommaInitializer operator<< (const Scalar& s); + /** \deprecated it now returns \c *this */ template - const Flagged flagged() const; + EIGEN_DEPRECATED + const Derived& flagged() const + { return derived(); } template + EIGEN_DEVICE_FUNC CommaInitializer operator<< (const DenseBase& other); - Eigen::Transpose transpose(); - typedef typename internal::add_const >::type ConstTransposeReturnType; + typedef Transpose TransposeReturnType; + EIGEN_DEVICE_FUNC + TransposeReturnType transpose(); + typedef typename internal::add_const >::type ConstTransposeReturnType; + EIGEN_DEVICE_FUNC ConstTransposeReturnType transpose() const; + EIGEN_DEVICE_FUNC void transposeInPlace(); -#ifndef EIGEN_NO_DEBUG - protected: - template - void checkTransposeAliasing(const OtherDerived& other) const; - public: -#endif - - static const ConstantReturnType + EIGEN_DEVICE_FUNC static const ConstantReturnType Constant(Index rows, Index cols, const Scalar& value); - static const ConstantReturnType + EIGEN_DEVICE_FUNC static const ConstantReturnType Constant(Index size, const Scalar& value); - static const ConstantReturnType + EIGEN_DEVICE_FUNC static const ConstantReturnType Constant(const Scalar& value); - static const SequentialLinSpacedReturnType + EIGEN_DEVICE_FUNC static const SequentialLinSpacedReturnType LinSpaced(Sequential_t, Index size, const Scalar& low, const Scalar& high); - static const RandomAccessLinSpacedReturnType + EIGEN_DEVICE_FUNC static const RandomAccessLinSpacedReturnType LinSpaced(Index size, const Scalar& low, const Scalar& high); - static const SequentialLinSpacedReturnType + EIGEN_DEVICE_FUNC static const SequentialLinSpacedReturnType LinSpaced(Sequential_t, const Scalar& low, const Scalar& high); - static const RandomAccessLinSpacedReturnType + EIGEN_DEVICE_FUNC static const RandomAccessLinSpacedReturnType LinSpaced(const Scalar& low, const Scalar& high); - template - static const CwiseNullaryOp + template EIGEN_DEVICE_FUNC + static const CwiseNullaryOp NullaryExpr(Index rows, Index cols, const CustomNullaryOp& func); - template - static const CwiseNullaryOp + template EIGEN_DEVICE_FUNC + static const CwiseNullaryOp NullaryExpr(Index size, const CustomNullaryOp& func); - template - static const CwiseNullaryOp + template EIGEN_DEVICE_FUNC + static const CwiseNullaryOp NullaryExpr(const CustomNullaryOp& func); - static const ConstantReturnType Zero(Index rows, Index cols); - static const ConstantReturnType Zero(Index size); - static const ConstantReturnType Zero(); - static const ConstantReturnType Ones(Index rows, Index cols); - static const ConstantReturnType Ones(Index size); - static const ConstantReturnType Ones(); - - void fill(const Scalar& value); - Derived& setConstant(const Scalar& value); - Derived& setLinSpaced(Index size, const Scalar& low, const Scalar& high); - Derived& setLinSpaced(const Scalar& low, const Scalar& high); - Derived& setZero(); - Derived& setOnes(); - Derived& setRandom(); - - template + EIGEN_DEVICE_FUNC static const ConstantReturnType Zero(Index rows, Index cols); + EIGEN_DEVICE_FUNC static const ConstantReturnType Zero(Index size); + EIGEN_DEVICE_FUNC static const ConstantReturnType Zero(); + EIGEN_DEVICE_FUNC static const ConstantReturnType Ones(Index rows, Index cols); + EIGEN_DEVICE_FUNC static const ConstantReturnType Ones(Index size); + EIGEN_DEVICE_FUNC static const ConstantReturnType Ones(); + + EIGEN_DEVICE_FUNC void fill(const Scalar& value); + EIGEN_DEVICE_FUNC Derived& setConstant(const Scalar& value); + EIGEN_DEVICE_FUNC Derived& setLinSpaced(Index size, const Scalar& low, const Scalar& high); + EIGEN_DEVICE_FUNC Derived& setLinSpaced(const Scalar& low, const Scalar& high); + EIGEN_DEVICE_FUNC Derived& setZero(); + EIGEN_DEVICE_FUNC Derived& setOnes(); + EIGEN_DEVICE_FUNC Derived& setRandom(); + + template EIGEN_DEVICE_FUNC bool isApprox(const DenseBase& other, const RealScalar& prec = NumTraits::dummy_precision()) const; + EIGEN_DEVICE_FUNC bool isMuchSmallerThan(const RealScalar& other, const RealScalar& prec = NumTraits::dummy_precision()) const; - template + template EIGEN_DEVICE_FUNC bool isMuchSmallerThan(const DenseBase& other, const RealScalar& prec = NumTraits::dummy_precision()) const; - bool isApproxToConstant(const Scalar& value, const RealScalar& prec = NumTraits::dummy_precision()) const; - bool isConstant(const Scalar& value, const RealScalar& prec = NumTraits::dummy_precision()) const; - bool isZero(const RealScalar& prec = NumTraits::dummy_precision()) const; - bool isOnes(const RealScalar& prec = NumTraits::dummy_precision()) const; + EIGEN_DEVICE_FUNC bool isApproxToConstant(const Scalar& value, const RealScalar& prec = NumTraits::dummy_precision()) const; + EIGEN_DEVICE_FUNC bool isConstant(const Scalar& value, const RealScalar& prec = NumTraits::dummy_precision()) const; + EIGEN_DEVICE_FUNC bool isZero(const RealScalar& prec = NumTraits::dummy_precision()) const; + EIGEN_DEVICE_FUNC bool isOnes(const RealScalar& prec = NumTraits::dummy_precision()) const; inline bool hasNaN() const; inline bool allFinite() const; - inline Derived& operator*=(const Scalar& other); - inline Derived& operator/=(const Scalar& other); + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Derived& operator*=(const Scalar& other); + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Derived& operator/=(const Scalar& other); typedef typename internal::add_const_on_value_type::type>::type EvalReturnType; /** \returns the matrix or vector obtained by evaluating this expression. * * Notice that in the case of a plain matrix or vector (not an expression) this function just returns * a const reference, in order to avoid a useless copy. + * + * \warning Be carefull with eval() and the auto C++ keyword, as detailed in this \link TopicPitfalls_auto_keyword page \endlink. */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE EvalReturnType eval() const { // Even though MSVC does not honor strong inlining when the return type @@ -364,61 +405,78 @@ template class DenseBase // size types on MSVC. return typename internal::eval::type(derived()); } - + /** swaps *this with the expression \a other. * */ template - void swap(const DenseBase& other, - int = OtherDerived::ThisConstantIsPrivateInPlainObjectBase) + EIGEN_DEVICE_FUNC + void swap(const DenseBase& other) { - SwapWrapper(derived()).lazyAssign(other.derived()); + EIGEN_STATIC_ASSERT(!OtherDerived::IsPlainObjectBase,THIS_EXPRESSION_IS_NOT_A_LVALUE__IT_IS_READ_ONLY); + eigen_assert(rows()==other.rows() && cols()==other.cols()); + call_assignment(derived(), other.const_cast_derived(), internal::swap_assign_op()); } /** swaps *this with the matrix or array \a other. * */ template + EIGEN_DEVICE_FUNC void swap(PlainObjectBase& other) { - SwapWrapper(derived()).lazyAssign(other.derived()); + eigen_assert(rows()==other.rows() && cols()==other.cols()); + call_assignment(derived(), other.derived(), internal::swap_assign_op()); } + EIGEN_DEVICE_FUNC inline const NestByValue nestByValue() const; + EIGEN_DEVICE_FUNC inline const ForceAlignedAccess forceAlignedAccess() const; + EIGEN_DEVICE_FUNC inline ForceAlignedAccess forceAlignedAccess(); + template EIGEN_DEVICE_FUNC + inline const typename internal::conditional,Derived&>::type forceAlignedAccessIf() const; + template EIGEN_DEVICE_FUNC + inline typename internal::conditional,Derived&>::type forceAlignedAccessIf(); - inline const NestByValue nestByValue() const; - inline const ForceAlignedAccess forceAlignedAccess() const; - inline ForceAlignedAccess forceAlignedAccess(); - template inline const typename internal::conditional,Derived&>::type forceAlignedAccessIf() const; - template inline typename internal::conditional,Derived&>::type forceAlignedAccessIf(); - - Scalar sum() const; - Scalar mean() const; - Scalar trace() const; + EIGEN_DEVICE_FUNC Scalar sum() const; + EIGEN_DEVICE_FUNC Scalar mean() const; + EIGEN_DEVICE_FUNC Scalar trace() const; - Scalar prod() const; + EIGEN_DEVICE_FUNC Scalar prod() const; - typename internal::traits::Scalar minCoeff() const; - typename internal::traits::Scalar maxCoeff() const; + EIGEN_DEVICE_FUNC typename internal::traits::Scalar minCoeff() const; + EIGEN_DEVICE_FUNC typename internal::traits::Scalar maxCoeff() const; - template + template EIGEN_DEVICE_FUNC typename internal::traits::Scalar minCoeff(IndexType* row, IndexType* col) const; - template + template EIGEN_DEVICE_FUNC typename internal::traits::Scalar maxCoeff(IndexType* row, IndexType* col) const; - template + template EIGEN_DEVICE_FUNC typename internal::traits::Scalar minCoeff(IndexType* index) const; - template + template EIGEN_DEVICE_FUNC typename internal::traits::Scalar maxCoeff(IndexType* index) const; template - typename internal::result_of::Scalar)>::type - redux(const BinaryOp& func) const; + EIGEN_DEVICE_FUNC + Scalar redux(const BinaryOp& func) const; template + EIGEN_DEVICE_FUNC void visit(Visitor& func) const; - inline const WithFormat format(const IOFormat& fmt) const; + /** \returns a WithFormat proxy object allowing to print a matrix the with given + * format \a fmt. + * + * See class IOFormat for some examples. + * + * \sa class IOFormat, class WithFormat + */ + inline const WithFormat format(const IOFormat& fmt) const + { + return WithFormat(derived(), fmt); + } /** \returns the unique coefficient of a 1x1 expression */ + EIGEN_DEVICE_FUNC CoeffReturnType value() const { EIGEN_STATIC_ASSERT_SIZE_1x1(Derived) @@ -426,8 +484,8 @@ template class DenseBase return derived().coeff(0,0); } - bool all(void) const; - bool any(void) const; + bool all() const; + bool any() const; Index count() const; typedef VectorwiseOp RowwiseReturnType; @@ -435,14 +493,35 @@ template class DenseBase typedef VectorwiseOp ColwiseReturnType; typedef const VectorwiseOp ConstColwiseReturnType; - ConstRowwiseReturnType rowwise() const; - RowwiseReturnType rowwise(); - ConstColwiseReturnType colwise() const; - ColwiseReturnType colwise(); + /** \returns a VectorwiseOp wrapper of *this providing additional partial reduction operations + * + * Example: \include MatrixBase_rowwise.cpp + * Output: \verbinclude MatrixBase_rowwise.out + * + * \sa colwise(), class VectorwiseOp, \ref TutorialReductionsVisitorsBroadcasting + */ + //Code moved here due to a CUDA compiler bug + EIGEN_DEVICE_FUNC inline ConstRowwiseReturnType rowwise() const { + return ConstRowwiseReturnType(derived()); + } + EIGEN_DEVICE_FUNC RowwiseReturnType rowwise(); + + /** \returns a VectorwiseOp wrapper of *this providing additional partial reduction operations + * + * Example: \include MatrixBase_colwise.cpp + * Output: \verbinclude MatrixBase_colwise.out + * + * \sa rowwise(), class VectorwiseOp, \ref TutorialReductionsVisitorsBroadcasting + */ + EIGEN_DEVICE_FUNC inline ConstColwiseReturnType colwise() const { + return ConstColwiseReturnType(derived()); + } + EIGEN_DEVICE_FUNC ColwiseReturnType colwise(); - static const CwiseNullaryOp,Derived> Random(Index rows, Index cols); - static const CwiseNullaryOp,Derived> Random(Index size); - static const CwiseNullaryOp,Derived> Random(); + typedef CwiseNullaryOp,PlainObject> RandomReturnType; + static const RandomReturnType Random(Index rows, Index cols); + static const RandomReturnType Random(Index size); + static const RandomReturnType Random(); template const Select @@ -460,45 +539,56 @@ template class DenseBase template RealScalar lpNorm() const; template - inline const Replicate replicate() const; - - typedef Replicate ReplicateReturnType; - inline const ReplicateReturnType replicate(Index rowFacor,Index colFactor) const; + EIGEN_DEVICE_FUNC + const Replicate replicate() const; + /** + * \return an expression of the replication of \c *this + * + * Example: \include MatrixBase_replicate_int_int.cpp + * Output: \verbinclude MatrixBase_replicate_int_int.out + * + * \sa VectorwiseOp::replicate(), DenseBase::replicate(), class Replicate + */ + //Code moved here due to a CUDA compiler bug + EIGEN_DEVICE_FUNC + const Replicate replicate(Index rowFactor, Index colFactor) const + { + return Replicate(derived(), rowFactor, colFactor); + } typedef Reverse ReverseReturnType; typedef const Reverse ConstReverseReturnType; - ReverseReturnType reverse(); - ConstReverseReturnType reverse() const; - void reverseInPlace(); + EIGEN_DEVICE_FUNC ReverseReturnType reverse(); + /** This is the const version of reverse(). */ + //Code moved here due to a CUDA compiler bug + EIGEN_DEVICE_FUNC ConstReverseReturnType reverse() const + { + return ConstReverseReturnType(derived()); + } + EIGEN_DEVICE_FUNC void reverseInPlace(); #define EIGEN_CURRENT_STORAGE_BASE_CLASS Eigen::DenseBase +#define EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL +#define EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(COND) # include "../plugins/BlockMethods.h" # ifdef EIGEN_DENSEBASE_PLUGIN # include EIGEN_DENSEBASE_PLUGIN # endif #undef EIGEN_CURRENT_STORAGE_BASE_CLASS - -#ifdef EIGEN2_SUPPORT - - Block corner(CornerType type, Index cRows, Index cCols); - const Block corner(CornerType type, Index cRows, Index cCols) const; - template - Block corner(CornerType type); - template - const Block corner(CornerType type) const; - -#endif // EIGEN2_SUPPORT - +#undef EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL +#undef EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF // disable the use of evalTo for dense objects with a nice compilation error - template inline void evalTo(Dest& ) const + template + EIGEN_DEVICE_FUNC + inline void evalTo(Dest& ) const { EIGEN_STATIC_ASSERT((internal::is_same::value),THE_EVAL_EVALTO_FUNCTION_SHOULD_NEVER_BE_CALLED_FOR_DENSE_OBJECTS); } protected: /** Default constructor. Do nothing. */ - DenseBase() + EIGEN_DEVICE_FUNC DenseBase() { /* Just checks for self-consistency of the flags. * Only do it when debugging Eigen, as this borders on paranoiac and could slow compilation down @@ -511,9 +601,9 @@ template class DenseBase } private: - explicit DenseBase(int); - DenseBase(int,int); - template explicit DenseBase(const DenseBase&); + EIGEN_DEVICE_FUNC explicit DenseBase(int); + EIGEN_DEVICE_FUNC DenseBase(int,int); + template EIGEN_DEVICE_FUNC explicit DenseBase(const DenseBase&); }; } // end namespace Eigen diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Core/DenseCoeffsBase.h b/ground/gcs/src/libs/eigen/Eigen/src/Core/DenseCoeffsBase.h index 3c890f2159..c4af48ab69 100644 --- a/ground/gcs/src/libs/eigen/Eigen/src/Core/DenseCoeffsBase.h +++ b/ground/gcs/src/libs/eigen/Eigen/src/Core/DenseCoeffsBase.h @@ -35,7 +35,6 @@ class DenseCoeffsBase : public EigenBase { public: typedef typename internal::traits::StorageKind StorageKind; - typedef typename internal::traits::Index Index; typedef typename internal::traits::Scalar Scalar; typedef typename internal::packet_traits::type PacketScalar; @@ -61,6 +60,7 @@ class DenseCoeffsBase : public EigenBase using Base::size; using Base::derived; + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index rowIndexByOuterInner(Index outer, Index inner) const { return int(Derived::RowsAtCompileTime) == 1 ? 0 @@ -69,6 +69,7 @@ class DenseCoeffsBase : public EigenBase : inner; } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index colIndexByOuterInner(Index outer, Index inner) const { return int(Derived::ColsAtCompileTime) == 1 ? 0 @@ -91,13 +92,15 @@ class DenseCoeffsBase : public EigenBase * * \sa operator()(Index,Index) const, coeffRef(Index,Index), coeff(Index) const */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index row, Index col) const { eigen_internal_assert(row >= 0 && row < rows() - && col >= 0 && col < cols()); - return derived().coeff(row, col); + && col >= 0 && col < cols()); + return internal::evaluator(derived()).coeff(row,col); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeffByOuterInner(Index outer, Index inner) const { return coeff(rowIndexByOuterInner(outer, inner), @@ -108,11 +111,12 @@ class DenseCoeffsBase : public EigenBase * * \sa operator()(Index,Index), operator[](Index) */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType operator()(Index row, Index col) const { eigen_assert(row >= 0 && row < rows() && col >= 0 && col < cols()); - return derived().coeff(row, col); + return coeff(row, col); } /** Short version: don't use this function, use @@ -130,11 +134,14 @@ class DenseCoeffsBase : public EigenBase * \sa operator[](Index) const, coeffRef(Index), coeff(Index,Index) const */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const { + EIGEN_STATIC_ASSERT(internal::evaluator::Flags & LinearAccessBit, + THIS_COEFFICIENT_ACCESSOR_TAKING_ONE_ACCESS_IS_ONLY_FOR_EXPRESSIONS_ALLOWING_LINEAR_ACCESS) eigen_internal_assert(index >= 0 && index < size()); - return derived().coeff(index); + return internal::evaluator(derived()).coeff(index); } @@ -146,15 +153,14 @@ class DenseCoeffsBase : public EigenBase * z() const, w() const */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType operator[](Index index) const { - #ifndef EIGEN2_SUPPORT EIGEN_STATIC_ASSERT(Derived::IsVectorAtCompileTime, THE_BRACKET_OPERATOR_IS_ONLY_FOR_VECTORS__USE_THE_PARENTHESIS_OPERATOR_INSTEAD) - #endif eigen_assert(index >= 0 && index < size()); - return derived().coeff(index); + return coeff(index); } /** \returns the coefficient at given index. @@ -167,32 +173,49 @@ class DenseCoeffsBase : public EigenBase * z() const, w() const */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType operator()(Index index) const { eigen_assert(index >= 0 && index < size()); - return derived().coeff(index); + return coeff(index); } /** equivalent to operator[](0). */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType x() const { return (*this)[0]; } /** equivalent to operator[](1). */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType - y() const { return (*this)[1]; } + y() const + { + EIGEN_STATIC_ASSERT(Derived::SizeAtCompileTime==-1 || Derived::SizeAtCompileTime>=2, OUT_OF_RANGE_ACCESS); + return (*this)[1]; + } /** equivalent to operator[](2). */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType - z() const { return (*this)[2]; } + z() const + { + EIGEN_STATIC_ASSERT(Derived::SizeAtCompileTime==-1 || Derived::SizeAtCompileTime>=3, OUT_OF_RANGE_ACCESS); + return (*this)[2]; + } /** equivalent to operator[](3). */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType - w() const { return (*this)[3]; } + w() const + { + EIGEN_STATIC_ASSERT(Derived::SizeAtCompileTime==-1 || Derived::SizeAtCompileTime>=4, OUT_OF_RANGE_ACCESS); + return (*this)[3]; + } /** \internal * \returns the packet of coefficients starting at the given row and column. It is your responsibility @@ -207,9 +230,9 @@ class DenseCoeffsBase : public EigenBase template EIGEN_STRONG_INLINE PacketReturnType packet(Index row, Index col) const { - eigen_internal_assert(row >= 0 && row < rows() - && col >= 0 && col < cols()); - return derived().template packet(row,col); + typedef typename internal::packet_traits::type DefaultPacketType; + eigen_internal_assert(row >= 0 && row < rows() && col >= 0 && col < cols()); + return internal::evaluator(derived()).template packet(row,col); } @@ -234,8 +257,11 @@ class DenseCoeffsBase : public EigenBase template EIGEN_STRONG_INLINE PacketReturnType packet(Index index) const { + EIGEN_STATIC_ASSERT(internal::evaluator::Flags & LinearAccessBit, + THIS_COEFFICIENT_ACCESSOR_TAKING_ONE_ACCESS_IS_ONLY_FOR_EXPRESSIONS_ALLOWING_LINEAR_ACCESS) + typedef typename internal::packet_traits::type DefaultPacketType; eigen_internal_assert(index >= 0 && index < size()); - return derived().template packet(index); + return internal::evaluator(derived()).template packet(index); } protected: @@ -278,7 +304,6 @@ class DenseCoeffsBase : public DenseCoeffsBase Base; typedef typename internal::traits::StorageKind StorageKind; - typedef typename internal::traits::Index Index; typedef typename internal::traits::Scalar Scalar; typedef typename internal::packet_traits::type PacketScalar; typedef typename NumTraits::Real RealScalar; @@ -311,13 +336,15 @@ class DenseCoeffsBase : public DenseCoeffsBase= 0 && row < rows() - && col >= 0 && col < cols()); - return derived().coeffRef(row, col); + && col >= 0 && col < cols()); + return internal::evaluator(derived()).coeffRef(row,col); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRefByOuterInner(Index outer, Index inner) { @@ -330,12 +357,13 @@ class DenseCoeffsBase : public DenseCoeffsBase= 0 && row < rows() && col >= 0 && col < cols()); - return derived().coeffRef(row, col); + return coeffRef(row, col); } @@ -354,11 +382,14 @@ class DenseCoeffsBase : public DenseCoeffsBase::Flags & LinearAccessBit, + THIS_COEFFICIENT_ACCESSOR_TAKING_ONE_ACCESS_IS_ONLY_FOR_EXPRESSIONS_ALLOWING_LINEAR_ACCESS) eigen_internal_assert(index >= 0 && index < size()); - return derived().coeffRef(index); + return internal::evaluator(derived()).coeffRef(index); } /** \returns a reference to the coefficient at given index. @@ -368,15 +399,14 @@ class DenseCoeffsBase : public DenseCoeffsBase= 0 && index < size()); - return derived().coeffRef(index); + return coeffRef(index); } /** \returns a reference to the coefficient at given index. @@ -388,167 +418,49 @@ class DenseCoeffsBase : public DenseCoeffsBase= 0 && index < size()); - return derived().coeffRef(index); + return coeffRef(index); } /** equivalent to operator[](0). */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& x() { return (*this)[0]; } /** equivalent to operator[](1). */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& - y() { return (*this)[1]; } - - /** equivalent to operator[](2). */ - - EIGEN_STRONG_INLINE Scalar& - z() { return (*this)[2]; } - - /** equivalent to operator[](3). */ - - EIGEN_STRONG_INLINE Scalar& - w() { return (*this)[3]; } - - /** \internal - * Stores the given packet of coefficients, at the given row and column of this expression. It is your responsibility - * to ensure that a packet really starts there. This method is only available on expressions having the - * PacketAccessBit. - * - * The \a LoadMode parameter may have the value \a #Aligned or \a #Unaligned. Its effect is to select - * the appropriate vectorization instruction. Aligned access is faster, but is only possible for packets - * starting at an address which is a multiple of the packet size. - */ - - template - EIGEN_STRONG_INLINE void writePacket - (Index row, Index col, const typename internal::packet_traits::type& val) + y() { - eigen_internal_assert(row >= 0 && row < rows() - && col >= 0 && col < cols()); - derived().template writePacket(row,col,val); + EIGEN_STATIC_ASSERT(Derived::SizeAtCompileTime==-1 || Derived::SizeAtCompileTime>=2, OUT_OF_RANGE_ACCESS); + return (*this)[1]; } + /** equivalent to operator[](2). */ - /** \internal */ - template - EIGEN_STRONG_INLINE void writePacketByOuterInner - (Index outer, Index inner, const typename internal::packet_traits::type& val) - { - writePacket(rowIndexByOuterInner(outer, inner), - colIndexByOuterInner(outer, inner), - val); - } - - /** \internal - * Stores the given packet of coefficients, at the given index in this expression. It is your responsibility - * to ensure that a packet really starts there. This method is only available on expressions having the - * PacketAccessBit and the LinearAccessBit. - * - * The \a LoadMode parameter may have the value \a Aligned or \a Unaligned. Its effect is to select - * the appropriate vectorization instruction. Aligned access is faster, but is only possible for packets - * starting at an address which is a multiple of the packet size. - */ - template - EIGEN_STRONG_INLINE void writePacket - (Index index, const typename internal::packet_traits::type& val) - { - eigen_internal_assert(index >= 0 && index < size()); - derived().template writePacket(index,val); - } - -#ifndef EIGEN_PARSED_BY_DOXYGEN - - /** \internal Copies the coefficient at position (row,col) of other into *this. - * - * This method is overridden in SwapWrapper, allowing swap() assignments to share 99% of their code - * with usual assignments. - * - * Outside of this internal usage, this method has probably no usefulness. It is hidden in the public API dox. - */ - - template - EIGEN_STRONG_INLINE void copyCoeff(Index row, Index col, const DenseBase& other) - { - eigen_internal_assert(row >= 0 && row < rows() - && col >= 0 && col < cols()); - derived().coeffRef(row, col) = other.derived().coeff(row, col); - } - - /** \internal Copies the coefficient at the given index of other into *this. - * - * This method is overridden in SwapWrapper, allowing swap() assignments to share 99% of their code - * with usual assignments. - * - * Outside of this internal usage, this method has probably no usefulness. It is hidden in the public API dox. - */ - - template - EIGEN_STRONG_INLINE void copyCoeff(Index index, const DenseBase& other) - { - eigen_internal_assert(index >= 0 && index < size()); - derived().coeffRef(index) = other.derived().coeff(index); - } - - - template - EIGEN_STRONG_INLINE void copyCoeffByOuterInner(Index outer, Index inner, const DenseBase& other) - { - const Index row = rowIndexByOuterInner(outer,inner); - const Index col = colIndexByOuterInner(outer,inner); - // derived() is important here: copyCoeff() may be reimplemented in Derived! - derived().copyCoeff(row, col, other); - } - - /** \internal Copies the packet at position (row,col) of other into *this. - * - * This method is overridden in SwapWrapper, allowing swap() assignments to share 99% of their code - * with usual assignments. - * - * Outside of this internal usage, this method has probably no usefulness. It is hidden in the public API dox. - */ - - template - EIGEN_STRONG_INLINE void copyPacket(Index row, Index col, const DenseBase& other) + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Scalar& + z() { - eigen_internal_assert(row >= 0 && row < rows() - && col >= 0 && col < cols()); - derived().template writePacket(row, col, - other.derived().template packet(row, col)); + EIGEN_STATIC_ASSERT(Derived::SizeAtCompileTime==-1 || Derived::SizeAtCompileTime>=3, OUT_OF_RANGE_ACCESS); + return (*this)[2]; } - /** \internal Copies the packet at the given index of other into *this. - * - * This method is overridden in SwapWrapper, allowing swap() assignments to share 99% of their code - * with usual assignments. - * - * Outside of this internal usage, this method has probably no usefulness. It is hidden in the public API dox. - */ - - template - EIGEN_STRONG_INLINE void copyPacket(Index index, const DenseBase& other) - { - eigen_internal_assert(index >= 0 && index < size()); - derived().template writePacket(index, - other.derived().template packet(index)); - } + /** equivalent to operator[](3). */ - /** \internal */ - template - EIGEN_STRONG_INLINE void copyPacketByOuterInner(Index outer, Index inner, const DenseBase& other) + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Scalar& + w() { - const Index row = rowIndexByOuterInner(outer,inner); - const Index col = colIndexByOuterInner(outer,inner); - // derived() is important here: copyCoeff() may be reimplemented in Derived! - derived().template copyPacket< OtherDerived, StoreMode, LoadMode>(row, col, other); + EIGEN_STATIC_ASSERT(Derived::SizeAtCompileTime==-1 || Derived::SizeAtCompileTime>=4, OUT_OF_RANGE_ACCESS); + return (*this)[3]; } -#endif - }; /** \brief Base class providing direct read-only coefficient access to matrices and arrays. @@ -560,7 +472,7 @@ class DenseCoeffsBase : public DenseCoeffsBase which defines functions to access entries read-only using * \c operator() . * - * \sa \ref TopicClassHierarchy + * \sa \blank \ref TopicClassHierarchy */ template class DenseCoeffsBase : public DenseCoeffsBase @@ -568,7 +480,6 @@ class DenseCoeffsBase : public DenseCoeffsBase Base; - typedef typename internal::traits::Index Index; typedef typename internal::traits::Scalar Scalar; typedef typename NumTraits::Real RealScalar; @@ -581,6 +492,7 @@ class DenseCoeffsBase : public DenseCoeffsBase : public DenseCoeffsBase : public DenseCoeffsBase : public DenseCoeffsBase : public DenseCoeffsBase which defines functions to access entries read/write using * \c operator(). * - * \sa \ref TopicClassHierarchy + * \sa \blank \ref TopicClassHierarchy */ template class DenseCoeffsBase @@ -639,7 +554,6 @@ class DenseCoeffsBase public: typedef DenseCoeffsBase Base; - typedef typename internal::traits::Index Index; typedef typename internal::traits::Scalar Scalar; typedef typename NumTraits::Real RealScalar; @@ -652,6 +566,7 @@ class DenseCoeffsBase * * \sa outerStride(), rowStride(), colStride() */ + EIGEN_DEVICE_FUNC inline Index innerStride() const { return derived().innerStride(); @@ -662,6 +577,7 @@ class DenseCoeffsBase * * \sa innerStride(), rowStride(), colStride() */ + EIGEN_DEVICE_FUNC inline Index outerStride() const { return derived().outerStride(); @@ -677,6 +593,7 @@ class DenseCoeffsBase * * \sa innerStride(), outerStride(), colStride() */ + EIGEN_DEVICE_FUNC inline Index rowStride() const { return Derived::IsRowMajor ? outerStride() : innerStride(); @@ -686,6 +603,7 @@ class DenseCoeffsBase * * \sa innerStride(), outerStride(), rowStride() */ + EIGEN_DEVICE_FUNC inline Index colStride() const { return Derived::IsRowMajor ? innerStride() : outerStride(); @@ -694,33 +612,42 @@ class DenseCoeffsBase namespace internal { -template +template struct first_aligned_impl { - static inline typename Derived::Index run(const Derived&) + static inline Index run(const Derived&) { return 0; } }; -template -struct first_aligned_impl +template +struct first_aligned_impl { - static inline typename Derived::Index run(const Derived& m) + static inline Index run(const Derived& m) { - return internal::first_aligned(&m.const_cast_derived().coeffRef(0,0), m.size()); + return internal::first_aligned(m.data(), m.size()); } }; -/** \internal \returns the index of the first element of the array that is well aligned for vectorization. +/** \internal \returns the index of the first element of the array stored by \a m that is properly aligned with respect to \a Alignment for vectorization. + * + * \tparam Alignment requested alignment in Bytes. * * There is also the variant first_aligned(const Scalar*, Integer) defined in Memory.h. See it for more * documentation. */ +template +static inline Index first_aligned(const DenseBase& m) +{ + enum { ReturnZero = (int(evaluator::Alignment) >= Alignment) || !(Derived::Flags & DirectAccessBit) }; + return first_aligned_impl::run(m.derived()); +} + template -static inline typename Derived::Index first_aligned(const Derived& m) +static inline Index first_default_aligned(const DenseBase& m) { - return first_aligned_impl - - ::run(m); + typedef typename Derived::Scalar Scalar; + typedef typename packet_traits::type DefaultPacketType; + return internal::first_aligned::alignment),Derived>(m); } template::ret> diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Core/DenseStorage.h b/ground/gcs/src/libs/eigen/Eigen/src/Core/DenseStorage.h index 568493cbae..7958feeb9c 100644 --- a/ground/gcs/src/libs/eigen/Eigen/src/Core/DenseStorage.h +++ b/ground/gcs/src/libs/eigen/Eigen/src/Core/DenseStorage.h @@ -3,7 +3,7 @@ // // Copyright (C) 2008 Gael Guennebaud // Copyright (C) 2006-2009 Benoit Jacob -// Copyright (C) 2010 Hauke Heibel +// Copyright (C) 2010-2013 Hauke Heibel // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -13,9 +13,9 @@ #define EIGEN_MATRIXSTORAGE_H #ifdef EIGEN_DENSE_STORAGE_CTOR_PLUGIN - #define EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN EIGEN_DENSE_STORAGE_CTOR_PLUGIN; + #define EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN(X) X; EIGEN_DENSE_STORAGE_CTOR_PLUGIN; #else - #define EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN + #define EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN(X) #endif namespace Eigen { @@ -24,7 +24,9 @@ namespace internal { struct constructor_without_unaligned_array_assert {}; -template void check_static_allocation_size() +template +EIGEN_DEVICE_FUNC +void check_static_allocation_size() { // if EIGEN_STACK_ALLOCATION_LIMIT is defined to 0, then no limit #if EIGEN_STACK_ALLOCATION_LIMIT @@ -38,18 +40,19 @@ template void check_static_allocation_size() */ template + : compute_default_alignment::value > struct plain_array { T array[Size]; - plain_array() + EIGEN_DEVICE_FUNC + plain_array() { check_static_allocation_size(); } - plain_array(constructor_without_unaligned_array_assert) + EIGEN_DEVICE_FUNC + plain_array(constructor_without_unaligned_array_assert) { check_static_allocation_size(); } @@ -64,29 +67,88 @@ struct plain_array template EIGEN_ALWAYS_INLINE PtrType eigen_unaligned_array_assert_workaround_gcc47(PtrType array) { return array; } #define EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(sizemask) \ - eigen_assert((reinterpret_cast(eigen_unaligned_array_assert_workaround_gcc47(array)) & sizemask) == 0 \ + eigen_assert((internal::UIntPtr(eigen_unaligned_array_assert_workaround_gcc47(array)) & (sizemask)) == 0 \ && "this assertion is explained here: " \ "http://eigen.tuxfamily.org/dox-devel/group__TopicUnalignedArrayAssert.html" \ " **** READ THIS WEB PAGE !!! ****"); #else #define EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(sizemask) \ - eigen_assert((reinterpret_cast(array) & sizemask) == 0 \ + eigen_assert((internal::UIntPtr(array) & (sizemask)) == 0 \ && "this assertion is explained here: " \ "http://eigen.tuxfamily.org/dox-devel/group__TopicUnalignedArrayAssert.html" \ " **** READ THIS WEB PAGE !!! ****"); #endif +template +struct plain_array +{ + EIGEN_ALIGN_TO_BOUNDARY(8) T array[Size]; + + EIGEN_DEVICE_FUNC + plain_array() + { + EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(7); + check_static_allocation_size(); + } + + EIGEN_DEVICE_FUNC + plain_array(constructor_without_unaligned_array_assert) + { + check_static_allocation_size(); + } +}; + template struct plain_array { - EIGEN_USER_ALIGN16 T array[Size]; + EIGEN_ALIGN_TO_BOUNDARY(16) T array[Size]; + EIGEN_DEVICE_FUNC plain_array() { - EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(0xf); + EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(15); check_static_allocation_size(); } + EIGEN_DEVICE_FUNC + plain_array(constructor_without_unaligned_array_assert) + { + check_static_allocation_size(); + } +}; + +template +struct plain_array +{ + EIGEN_ALIGN_TO_BOUNDARY(32) T array[Size]; + + EIGEN_DEVICE_FUNC + plain_array() + { + EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(31); + check_static_allocation_size(); + } + + EIGEN_DEVICE_FUNC + plain_array(constructor_without_unaligned_array_assert) + { + check_static_allocation_size(); + } +}; + +template +struct plain_array +{ + EIGEN_ALIGN_TO_BOUNDARY(64) T array[Size]; + + EIGEN_DEVICE_FUNC + plain_array() + { + EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(63); + check_static_allocation_size(); + } + + EIGEN_DEVICE_FUNC plain_array(constructor_without_unaligned_array_assert) { check_static_allocation_size(); @@ -96,9 +158,9 @@ struct plain_array template struct plain_array { - EIGEN_USER_ALIGN16 T array[1]; - plain_array() {} - plain_array(constructor_without_unaligned_array_assert) {} + T array[1]; + EIGEN_DEVICE_FUNC plain_array() {} + EIGEN_DEVICE_FUNC plain_array(constructor_without_unaligned_array_assert) {} }; } // end namespace internal @@ -122,41 +184,54 @@ template class DenseSt { internal::plain_array m_data; public: - DenseStorage() {} - DenseStorage(internal::constructor_without_unaligned_array_assert) + EIGEN_DEVICE_FUNC DenseStorage() { + EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN(Index size = Size) + } + EIGEN_DEVICE_FUNC + explicit DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(internal::constructor_without_unaligned_array_assert()) {} - DenseStorage(const DenseStorage& other) : m_data(other.m_data) {} + EIGEN_DEVICE_FUNC + DenseStorage(const DenseStorage& other) : m_data(other.m_data) { + EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN(Index size = Size) + } + EIGEN_DEVICE_FUNC DenseStorage& operator=(const DenseStorage& other) - { + { if (this != &other) m_data = other.m_data; - return *this; + return *this; } - DenseStorage(DenseIndex,DenseIndex,DenseIndex) {} - void swap(DenseStorage& other) { std::swap(m_data,other.m_data); } - static DenseIndex rows(void) {return _Rows;} - static DenseIndex cols(void) {return _Cols;} - void conservativeResize(DenseIndex,DenseIndex,DenseIndex) {} - void resize(DenseIndex,DenseIndex,DenseIndex) {} - const T *data() const { return m_data.array; } - T *data() { return m_data.array; } + EIGEN_DEVICE_FUNC DenseStorage(Index size, Index rows, Index cols) { + EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN({}) + eigen_internal_assert(size==rows*cols && rows==_Rows && cols==_Cols); + EIGEN_UNUSED_VARIABLE(size); + EIGEN_UNUSED_VARIABLE(rows); + EIGEN_UNUSED_VARIABLE(cols); + } + EIGEN_DEVICE_FUNC void swap(DenseStorage& other) { std::swap(m_data,other.m_data); } + EIGEN_DEVICE_FUNC static Index rows(void) {return _Rows;} + EIGEN_DEVICE_FUNC static Index cols(void) {return _Cols;} + EIGEN_DEVICE_FUNC void conservativeResize(Index,Index,Index) {} + EIGEN_DEVICE_FUNC void resize(Index,Index,Index) {} + EIGEN_DEVICE_FUNC const T *data() const { return m_data.array; } + EIGEN_DEVICE_FUNC T *data() { return m_data.array; } }; // null matrix template class DenseStorage { public: - DenseStorage() {} - DenseStorage(internal::constructor_without_unaligned_array_assert) {} - DenseStorage(const DenseStorage&) {} - DenseStorage& operator=(const DenseStorage&) { return *this; } - DenseStorage(DenseIndex,DenseIndex,DenseIndex) {} - void swap(DenseStorage& ) {} - static DenseIndex rows(void) {return _Rows;} - static DenseIndex cols(void) {return _Cols;} - void conservativeResize(DenseIndex,DenseIndex,DenseIndex) {} - void resize(DenseIndex,DenseIndex,DenseIndex) {} - const T *data() const { return 0; } - T *data() { return 0; } + EIGEN_DEVICE_FUNC DenseStorage() {} + EIGEN_DEVICE_FUNC explicit DenseStorage(internal::constructor_without_unaligned_array_assert) {} + EIGEN_DEVICE_FUNC DenseStorage(const DenseStorage&) {} + EIGEN_DEVICE_FUNC DenseStorage& operator=(const DenseStorage&) { return *this; } + EIGEN_DEVICE_FUNC DenseStorage(Index,Index,Index) {} + EIGEN_DEVICE_FUNC void swap(DenseStorage& ) {} + EIGEN_DEVICE_FUNC static Index rows(void) {return _Rows;} + EIGEN_DEVICE_FUNC static Index cols(void) {return _Cols;} + EIGEN_DEVICE_FUNC void conservativeResize(Index,Index,Index) {} + EIGEN_DEVICE_FUNC void resize(Index,Index,Index) {} + EIGEN_DEVICE_FUNC const T *data() const { return 0; } + EIGEN_DEVICE_FUNC T *data() { return 0; } }; // more specializations for null matrices; these are necessary to resolve ambiguities @@ -173,74 +248,74 @@ template class DenseStorage class DenseStorage { internal::plain_array m_data; - DenseIndex m_rows; - DenseIndex m_cols; + Index m_rows; + Index m_cols; public: - DenseStorage() : m_rows(0), m_cols(0) {} - DenseStorage(internal::constructor_without_unaligned_array_assert) + EIGEN_DEVICE_FUNC DenseStorage() : m_rows(0), m_cols(0) {} + EIGEN_DEVICE_FUNC explicit DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(internal::constructor_without_unaligned_array_assert()), m_rows(0), m_cols(0) {} - DenseStorage(const DenseStorage& other) : m_data(other.m_data), m_rows(other.m_rows), m_cols(other.m_cols) {} - DenseStorage& operator=(const DenseStorage& other) - { + EIGEN_DEVICE_FUNC DenseStorage(const DenseStorage& other) : m_data(other.m_data), m_rows(other.m_rows), m_cols(other.m_cols) {} + EIGEN_DEVICE_FUNC DenseStorage& operator=(const DenseStorage& other) + { if (this != &other) { m_data = other.m_data; m_rows = other.m_rows; m_cols = other.m_cols; } - return *this; + return *this; } - DenseStorage(DenseIndex, DenseIndex nbRows, DenseIndex nbCols) : m_rows(nbRows), m_cols(nbCols) {} - void swap(DenseStorage& other) + EIGEN_DEVICE_FUNC DenseStorage(Index, Index rows, Index cols) : m_rows(rows), m_cols(cols) {} + EIGEN_DEVICE_FUNC void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); std::swap(m_cols,other.m_cols); } - DenseIndex rows() const {return m_rows;} - DenseIndex cols() const {return m_cols;} - void conservativeResize(DenseIndex, DenseIndex nbRows, DenseIndex nbCols) { m_rows = nbRows; m_cols = nbCols; } - void resize(DenseIndex, DenseIndex nbRows, DenseIndex nbCols) { m_rows = nbRows; m_cols = nbCols; } - const T *data() const { return m_data.array; } - T *data() { return m_data.array; } + EIGEN_DEVICE_FUNC Index rows() const {return m_rows;} + EIGEN_DEVICE_FUNC Index cols() const {return m_cols;} + EIGEN_DEVICE_FUNC void conservativeResize(Index, Index rows, Index cols) { m_rows = rows; m_cols = cols; } + EIGEN_DEVICE_FUNC void resize(Index, Index rows, Index cols) { m_rows = rows; m_cols = cols; } + EIGEN_DEVICE_FUNC const T *data() const { return m_data.array; } + EIGEN_DEVICE_FUNC T *data() { return m_data.array; } }; // dynamic-size matrix with fixed-size storage and fixed width template class DenseStorage { internal::plain_array m_data; - DenseIndex m_rows; + Index m_rows; public: - DenseStorage() : m_rows(0) {} - DenseStorage(internal::constructor_without_unaligned_array_assert) + EIGEN_DEVICE_FUNC DenseStorage() : m_rows(0) {} + EIGEN_DEVICE_FUNC explicit DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(internal::constructor_without_unaligned_array_assert()), m_rows(0) {} - DenseStorage(const DenseStorage& other) : m_data(other.m_data), m_rows(other.m_rows) {} - DenseStorage& operator=(const DenseStorage& other) + EIGEN_DEVICE_FUNC DenseStorage(const DenseStorage& other) : m_data(other.m_data), m_rows(other.m_rows) {} + EIGEN_DEVICE_FUNC DenseStorage& operator=(const DenseStorage& other) { if (this != &other) { m_data = other.m_data; m_rows = other.m_rows; } - return *this; + return *this; } - DenseStorage(DenseIndex, DenseIndex nbRows, DenseIndex) : m_rows(nbRows) {} - void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); } - DenseIndex rows(void) const {return m_rows;} - DenseIndex cols(void) const {return _Cols;} - void conservativeResize(DenseIndex, DenseIndex nbRows, DenseIndex) { m_rows = nbRows; } - void resize(DenseIndex, DenseIndex nbRows, DenseIndex) { m_rows = nbRows; } - const T *data() const { return m_data.array; } - T *data() { return m_data.array; } + EIGEN_DEVICE_FUNC DenseStorage(Index, Index rows, Index) : m_rows(rows) {} + EIGEN_DEVICE_FUNC void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); } + EIGEN_DEVICE_FUNC Index rows(void) const {return m_rows;} + EIGEN_DEVICE_FUNC Index cols(void) const {return _Cols;} + EIGEN_DEVICE_FUNC void conservativeResize(Index, Index rows, Index) { m_rows = rows; } + EIGEN_DEVICE_FUNC void resize(Index, Index rows, Index) { m_rows = rows; } + EIGEN_DEVICE_FUNC const T *data() const { return m_data.array; } + EIGEN_DEVICE_FUNC T *data() { return m_data.array; } }; // dynamic-size matrix with fixed-size storage and fixed height template class DenseStorage { internal::plain_array m_data; - DenseIndex m_cols; + Index m_cols; public: - DenseStorage() : m_cols(0) {} - DenseStorage(internal::constructor_without_unaligned_array_assert) + EIGEN_DEVICE_FUNC DenseStorage() : m_cols(0) {} + EIGEN_DEVICE_FUNC explicit DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(internal::constructor_without_unaligned_array_assert()), m_cols(0) {} - DenseStorage(const DenseStorage& other) : m_data(other.m_data), m_cols(other.m_cols) {} - DenseStorage& operator=(const DenseStorage& other) + EIGEN_DEVICE_FUNC DenseStorage(const DenseStorage& other) : m_data(other.m_data), m_cols(other.m_cols) {} + EIGEN_DEVICE_FUNC DenseStorage& operator=(const DenseStorage& other) { if (this != &other) { @@ -249,38 +324,62 @@ template class DenseStorage class DenseStorage { T *m_data; - DenseIndex m_rows; - DenseIndex m_cols; + Index m_rows; + Index m_cols; public: - DenseStorage() : m_data(0), m_rows(0), m_cols(0) {} - DenseStorage(internal::constructor_without_unaligned_array_assert) + EIGEN_DEVICE_FUNC DenseStorage() : m_data(0), m_rows(0), m_cols(0) {} + EIGEN_DEVICE_FUNC explicit DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(0), m_rows(0), m_cols(0) {} - DenseStorage(DenseIndex size, DenseIndex nbRows, DenseIndex nbCols) - : m_data(internal::conditional_aligned_new_auto(size)), m_rows(nbRows), m_cols(nbCols) - { EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN } -#ifdef EIGEN_HAVE_RVALUE_REFERENCES - DenseStorage(DenseStorage&& other) + EIGEN_DEVICE_FUNC DenseStorage(Index size, Index rows, Index cols) + : m_data(internal::conditional_aligned_new_auto(size)), m_rows(rows), m_cols(cols) + { + EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN({}) + eigen_internal_assert(size==rows*cols && rows>=0 && cols >=0); + } + EIGEN_DEVICE_FUNC DenseStorage(const DenseStorage& other) + : m_data(internal::conditional_aligned_new_auto(other.m_rows*other.m_cols)) + , m_rows(other.m_rows) + , m_cols(other.m_cols) + { + EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN(Index size = m_rows*m_cols) + internal::smart_copy(other.m_data, other.m_data+other.m_rows*other.m_cols, m_data); + } + EIGEN_DEVICE_FUNC DenseStorage& operator=(const DenseStorage& other) + { + if (this != &other) + { + DenseStorage tmp(other); + this->swap(tmp); + } + return *this; + } +#if EIGEN_HAS_RVALUE_REFERENCES + EIGEN_DEVICE_FUNC + DenseStorage(DenseStorage&& other) EIGEN_NOEXCEPT : m_data(std::move(other.m_data)) , m_rows(std::move(other.m_rows)) , m_cols(std::move(other.m_cols)) { other.m_data = nullptr; + other.m_rows = 0; + other.m_cols = 0; } - DenseStorage& operator=(DenseStorage&& other) + EIGEN_DEVICE_FUNC + DenseStorage& operator=(DenseStorage&& other) EIGEN_NOEXCEPT { using std::swap; swap(m_data, other.m_data); @@ -289,18 +388,18 @@ template class DenseStorage(m_data, m_rows*m_cols); } - void swap(DenseStorage& other) + EIGEN_DEVICE_FUNC ~DenseStorage() { internal::conditional_aligned_delete_auto(m_data, m_rows*m_cols); } + EIGEN_DEVICE_FUNC void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); std::swap(m_cols,other.m_cols); } - DenseIndex rows(void) const {return m_rows;} - DenseIndex cols(void) const {return m_cols;} - void conservativeResize(DenseIndex size, DenseIndex nbRows, DenseIndex nbCols) + EIGEN_DEVICE_FUNC Index rows(void) const {return m_rows;} + EIGEN_DEVICE_FUNC Index cols(void) const {return m_cols;} + void conservativeResize(Index size, Index rows, Index cols) { m_data = internal::conditional_aligned_realloc_new_auto(m_data, size, m_rows*m_cols); - m_rows = nbRows; - m_cols = nbCols; + m_rows = rows; + m_cols = cols; } - void resize(DenseIndex size, DenseIndex nbRows, DenseIndex nbCols) + EIGEN_DEVICE_FUNC void resize(Index size, Index rows, Index cols) { if(size != m_rows*m_cols) { @@ -309,36 +408,56 @@ template class DenseStorage(size); else m_data = 0; - EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN + EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN({}) } - m_rows = nbRows; - m_cols = nbCols; + m_rows = rows; + m_cols = cols; } - const T *data() const { return m_data; } - T *data() { return m_data; } - private: - DenseStorage(const DenseStorage&); - DenseStorage& operator=(const DenseStorage&); + EIGEN_DEVICE_FUNC const T *data() const { return m_data; } + EIGEN_DEVICE_FUNC T *data() { return m_data; } }; // matrix with dynamic width and fixed height (so that matrix has dynamic size). template class DenseStorage { T *m_data; - DenseIndex m_cols; + Index m_cols; public: - DenseStorage() : m_data(0), m_cols(0) {} - DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(0), m_cols(0) {} - DenseStorage(DenseIndex size, DenseIndex, DenseIndex nbCols) : m_data(internal::conditional_aligned_new_auto(size)), m_cols(nbCols) - { EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN } -#ifdef EIGEN_HAVE_RVALUE_REFERENCES - DenseStorage(DenseStorage&& other) + EIGEN_DEVICE_FUNC DenseStorage() : m_data(0), m_cols(0) {} + explicit DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(0), m_cols(0) {} + EIGEN_DEVICE_FUNC DenseStorage(Index size, Index rows, Index cols) : m_data(internal::conditional_aligned_new_auto(size)), m_cols(cols) + { + EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN({}) + eigen_internal_assert(size==rows*cols && rows==_Rows && cols >=0); + EIGEN_UNUSED_VARIABLE(rows); + } + EIGEN_DEVICE_FUNC DenseStorage(const DenseStorage& other) + : m_data(internal::conditional_aligned_new_auto(_Rows*other.m_cols)) + , m_cols(other.m_cols) + { + EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN(Index size = m_cols*_Rows) + internal::smart_copy(other.m_data, other.m_data+_Rows*m_cols, m_data); + } + EIGEN_DEVICE_FUNC DenseStorage& operator=(const DenseStorage& other) + { + if (this != &other) + { + DenseStorage tmp(other); + this->swap(tmp); + } + return *this; + } +#if EIGEN_HAS_RVALUE_REFERENCES + EIGEN_DEVICE_FUNC + DenseStorage(DenseStorage&& other) EIGEN_NOEXCEPT : m_data(std::move(other.m_data)) , m_cols(std::move(other.m_cols)) { other.m_data = nullptr; + other.m_cols = 0; } - DenseStorage& operator=(DenseStorage&& other) + EIGEN_DEVICE_FUNC + DenseStorage& operator=(DenseStorage&& other) EIGEN_NOEXCEPT { using std::swap; swap(m_data, other.m_data); @@ -346,16 +465,16 @@ template class DenseStorage(m_data, _Rows*m_cols); } - void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_cols,other.m_cols); } - static DenseIndex rows(void) {return _Rows;} - DenseIndex cols(void) const {return m_cols;} - void conservativeResize(DenseIndex size, DenseIndex, DenseIndex nbCols) + EIGEN_DEVICE_FUNC ~DenseStorage() { internal::conditional_aligned_delete_auto(m_data, _Rows*m_cols); } + EIGEN_DEVICE_FUNC void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_cols,other.m_cols); } + EIGEN_DEVICE_FUNC static Index rows(void) {return _Rows;} + EIGEN_DEVICE_FUNC Index cols(void) const {return m_cols;} + EIGEN_DEVICE_FUNC void conservativeResize(Index size, Index, Index cols) { m_data = internal::conditional_aligned_realloc_new_auto(m_data, size, _Rows*m_cols); - m_cols = nbCols; + m_cols = cols; } - EIGEN_STRONG_INLINE void resize(DenseIndex size, DenseIndex, DenseIndex nbCols) + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void resize(Index size, Index, Index cols) { if(size != _Rows*m_cols) { @@ -364,35 +483,55 @@ template class DenseStorage(size); else m_data = 0; - EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN + EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN({}) } - m_cols = nbCols; + m_cols = cols; } - const T *data() const { return m_data; } - T *data() { return m_data; } - private: - DenseStorage(const DenseStorage&); - DenseStorage& operator=(const DenseStorage&); + EIGEN_DEVICE_FUNC const T *data() const { return m_data; } + EIGEN_DEVICE_FUNC T *data() { return m_data; } }; // matrix with dynamic height and fixed width (so that matrix has dynamic size). template class DenseStorage { T *m_data; - DenseIndex m_rows; + Index m_rows; public: - DenseStorage() : m_data(0), m_rows(0) {} - DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(0), m_rows(0) {} - DenseStorage(DenseIndex size, DenseIndex nbRows, DenseIndex) : m_data(internal::conditional_aligned_new_auto(size)), m_rows(nbRows) - { EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN } -#ifdef EIGEN_HAVE_RVALUE_REFERENCES - DenseStorage(DenseStorage&& other) + EIGEN_DEVICE_FUNC DenseStorage() : m_data(0), m_rows(0) {} + explicit DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(0), m_rows(0) {} + EIGEN_DEVICE_FUNC DenseStorage(Index size, Index rows, Index cols) : m_data(internal::conditional_aligned_new_auto(size)), m_rows(rows) + { + EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN({}) + eigen_internal_assert(size==rows*cols && rows>=0 && cols == _Cols); + EIGEN_UNUSED_VARIABLE(cols); + } + EIGEN_DEVICE_FUNC DenseStorage(const DenseStorage& other) + : m_data(internal::conditional_aligned_new_auto(other.m_rows*_Cols)) + , m_rows(other.m_rows) + { + EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN(Index size = m_rows*_Cols) + internal::smart_copy(other.m_data, other.m_data+other.m_rows*_Cols, m_data); + } + EIGEN_DEVICE_FUNC DenseStorage& operator=(const DenseStorage& other) + { + if (this != &other) + { + DenseStorage tmp(other); + this->swap(tmp); + } + return *this; + } +#if EIGEN_HAS_RVALUE_REFERENCES + EIGEN_DEVICE_FUNC + DenseStorage(DenseStorage&& other) EIGEN_NOEXCEPT : m_data(std::move(other.m_data)) , m_rows(std::move(other.m_rows)) { other.m_data = nullptr; + other.m_rows = 0; } - DenseStorage& operator=(DenseStorage&& other) + EIGEN_DEVICE_FUNC + DenseStorage& operator=(DenseStorage&& other) EIGEN_NOEXCEPT { using std::swap; swap(m_data, other.m_data); @@ -400,16 +539,16 @@ template class DenseStorage(m_data, _Cols*m_rows); } - void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); } - DenseIndex rows(void) const {return m_rows;} - static DenseIndex cols(void) {return _Cols;} - void conservativeResize(DenseIndex size, DenseIndex nbRows, DenseIndex) + EIGEN_DEVICE_FUNC ~DenseStorage() { internal::conditional_aligned_delete_auto(m_data, _Cols*m_rows); } + EIGEN_DEVICE_FUNC void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); } + EIGEN_DEVICE_FUNC Index rows(void) const {return m_rows;} + EIGEN_DEVICE_FUNC static Index cols(void) {return _Cols;} + void conservativeResize(Index size, Index rows, Index) { m_data = internal::conditional_aligned_realloc_new_auto(m_data, size, m_rows*_Cols); - m_rows = nbRows; + m_rows = rows; } - EIGEN_STRONG_INLINE void resize(DenseIndex size, DenseIndex nbRows, DenseIndex) + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void resize(Index size, Index rows, Index) { if(size != m_rows*_Cols) { @@ -418,15 +557,12 @@ template class DenseStorage(size); else m_data = 0; - EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN + EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN({}) } - m_rows = nbRows; + m_rows = rows; } - const T *data() const { return m_data; } - T *data() { return m_data; } - private: - DenseStorage(const DenseStorage&); - DenseStorage& operator=(const DenseStorage&); + EIGEN_DEVICE_FUNC const T *data() const { return m_data; } + EIGEN_DEVICE_FUNC T *data() { return m_data; } }; } // end namespace Eigen diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Core/Diagonal.h b/ground/gcs/src/libs/eigen/Eigen/src/Core/Diagonal.h index 68cf6d4b04..49e7112571 100644 --- a/ground/gcs/src/libs/eigen/Eigen/src/Core/Diagonal.h +++ b/ground/gcs/src/libs/eigen/Eigen/src/Core/Diagonal.h @@ -21,7 +21,7 @@ namespace Eigen { * \param MatrixType the type of the object in which we are taking a sub/main/super diagonal * \param DiagIndex the index of the sub/super diagonal. The default is 0 and it means the main diagonal. * A positive value means a superdiagonal, a negative value means a subdiagonal. - * You can also use Dynamic so the index can be set at runtime. + * You can also use DynamicIndex so the index can be set at runtime. * * The matrix is not required to be square. * @@ -37,7 +37,7 @@ template struct traits > : traits { - typedef typename nested::type MatrixTypeNested; + typedef typename ref_selector::type MatrixTypeNested; typedef typename remove_reference::type _MatrixTypeNested; typedef typename MatrixType::StorageKind StorageKind; enum { @@ -52,8 +52,7 @@ struct traits > MatrixType::MaxColsAtCompileTime - EIGEN_PLAIN_ENUM_MAX( DiagIndex, 0))), MaxColsAtCompileTime = 1, MaskLvalueBit = is_lvalue::value ? LvalueBit : 0, - Flags = (unsigned int)_MatrixTypeNested::Flags & (HereditaryBits | LinearAccessBit | MaskLvalueBit | DirectAccessBit) & ~RowMajorBit, - CoeffReadCost = _MatrixTypeNested::CoeffReadCost, + Flags = (unsigned int)_MatrixTypeNested::Flags & (RowMajorBit | MaskLvalueBit | DirectAccessBit) & ~RowMajorBit, // FIXME DirectAccessBit should not be handled by expressions MatrixTypeOuterStride = outer_stride_at_compile_time::ret, InnerStrideAtCompileTime = MatrixTypeOuterStride == Dynamic ? Dynamic : MatrixTypeOuterStride+1, OuterStrideAtCompileTime = 0 @@ -70,20 +69,28 @@ template class Diagonal typedef typename internal::dense_xpr_base::type Base; EIGEN_DENSE_PUBLIC_INTERFACE(Diagonal) - inline Diagonal(MatrixType& matrix, Index a_index = DiagIndex) : m_matrix(matrix), m_index(a_index) {} + EIGEN_DEVICE_FUNC + explicit inline Diagonal(MatrixType& matrix, Index a_index = DiagIndex) : m_matrix(matrix), m_index(a_index) {} EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Diagonal) + EIGEN_DEVICE_FUNC inline Index rows() const - { return m_index.value()<0 ? (std::min)(m_matrix.cols(),m_matrix.rows()+m_index.value()) : (std::min)(m_matrix.rows(),m_matrix.cols()-m_index.value()); } + { + return m_index.value()<0 ? numext::mini(m_matrix.cols(),m_matrix.rows()+m_index.value()) + : numext::mini(m_matrix.rows(),m_matrix.cols()-m_index.value()); + } + EIGEN_DEVICE_FUNC inline Index cols() const { return 1; } + EIGEN_DEVICE_FUNC inline Index innerStride() const { return m_matrix.outerStride() + 1; } + EIGEN_DEVICE_FUNC inline Index outerStride() const { return 0; @@ -95,62 +102,75 @@ template class Diagonal const Scalar >::type ScalarWithConstIfNotLvalue; - inline ScalarWithConstIfNotLvalue* data() { return &(m_matrix.const_cast_derived().coeffRef(rowOffset(), colOffset())); } - inline const Scalar* data() const { return &(m_matrix.const_cast_derived().coeffRef(rowOffset(), colOffset())); } + EIGEN_DEVICE_FUNC + inline ScalarWithConstIfNotLvalue* data() { return &(m_matrix.coeffRef(rowOffset(), colOffset())); } + EIGEN_DEVICE_FUNC + inline const Scalar* data() const { return &(m_matrix.coeffRef(rowOffset(), colOffset())); } + EIGEN_DEVICE_FUNC inline Scalar& coeffRef(Index row, Index) { EIGEN_STATIC_ASSERT_LVALUE(MatrixType) - return m_matrix.const_cast_derived().coeffRef(row+rowOffset(), row+colOffset()); + return m_matrix.coeffRef(row+rowOffset(), row+colOffset()); } + EIGEN_DEVICE_FUNC inline const Scalar& coeffRef(Index row, Index) const { - return m_matrix.const_cast_derived().coeffRef(row+rowOffset(), row+colOffset()); + return m_matrix.coeffRef(row+rowOffset(), row+colOffset()); } + EIGEN_DEVICE_FUNC inline CoeffReturnType coeff(Index row, Index) const { return m_matrix.coeff(row+rowOffset(), row+colOffset()); } + EIGEN_DEVICE_FUNC inline Scalar& coeffRef(Index idx) { EIGEN_STATIC_ASSERT_LVALUE(MatrixType) - return m_matrix.const_cast_derived().coeffRef(idx+rowOffset(), idx+colOffset()); + return m_matrix.coeffRef(idx+rowOffset(), idx+colOffset()); } + EIGEN_DEVICE_FUNC inline const Scalar& coeffRef(Index idx) const { - return m_matrix.const_cast_derived().coeffRef(idx+rowOffset(), idx+colOffset()); + return m_matrix.coeffRef(idx+rowOffset(), idx+colOffset()); } + EIGEN_DEVICE_FUNC inline CoeffReturnType coeff(Index idx) const { return m_matrix.coeff(idx+rowOffset(), idx+colOffset()); } - const typename internal::remove_all::type& + EIGEN_DEVICE_FUNC + inline const typename internal::remove_all::type& nestedExpression() const { return m_matrix; } - int index() const + EIGEN_DEVICE_FUNC + inline Index index() const { return m_index.value(); } protected: - typename MatrixType::Nested m_matrix; + typename internal::ref_selector::non_const_type m_matrix; const internal::variable_if_dynamicindex m_index; private: // some compilers may fail to optimize std::max etc in case of compile-time constants... + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index absDiagIndex() const { return m_index.value()>0 ? m_index.value() : -m_index.value(); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index rowOffset() const { return m_index.value()>0 ? 0 : -m_index.value(); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index colOffset() const { return m_index.value()>0 ? m_index.value() : 0; } - // triger a compile time error is someone try to call packet + // trigger a compile-time error if someone try to call packet template typename MatrixType::PacketReturnType packet(Index) const; template typename MatrixType::PacketReturnType packet(Index,Index) const; }; @@ -167,7 +187,7 @@ template inline typename MatrixBase::DiagonalReturnType MatrixBase::diagonal() { - return derived(); + return DiagonalReturnType(derived()); } /** This is the const version of diagonal(). */ @@ -216,20 +236,20 @@ MatrixBase::diagonal(Index index) const * * \sa MatrixBase::diagonal(), class Diagonal */ template -template -inline typename MatrixBase::template DiagonalIndexReturnType::Type +template +inline typename MatrixBase::template DiagonalIndexReturnType::Type MatrixBase::diagonal() { - return derived(); + return typename DiagonalIndexReturnType::Type(derived()); } /** This is the const version of diagonal(). */ template -template -inline typename MatrixBase::template ConstDiagonalIndexReturnType::Type +template +inline typename MatrixBase::template ConstDiagonalIndexReturnType::Type MatrixBase::diagonal() const { - return derived(); + return typename ConstDiagonalIndexReturnType::Type(derived()); } } // end namespace Eigen diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Core/DiagonalMatrix.h b/ground/gcs/src/libs/eigen/Eigen/src/Core/DiagonalMatrix.h index e6c220f419..ecfdce8efa 100644 --- a/ground/gcs/src/libs/eigen/Eigen/src/Core/DiagonalMatrix.h +++ b/ground/gcs/src/libs/eigen/Eigen/src/Core/DiagonalMatrix.h @@ -22,7 +22,7 @@ class DiagonalBase : public EigenBase typedef typename DiagonalVectorType::Scalar Scalar; typedef typename DiagonalVectorType::RealScalar RealScalar; typedef typename internal::traits::StorageKind StorageKind; - typedef typename internal::traits::Index Index; + typedef typename internal::traits::StorageIndex StorageIndex; enum { RowsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, @@ -30,79 +30,61 @@ class DiagonalBase : public EigenBase MaxRowsAtCompileTime = DiagonalVectorType::MaxSizeAtCompileTime, MaxColsAtCompileTime = DiagonalVectorType::MaxSizeAtCompileTime, IsVectorAtCompileTime = 0, - Flags = 0 + Flags = NoPreferredStorageOrderBit }; typedef Matrix DenseMatrixType; typedef DenseMatrixType DenseType; typedef DiagonalMatrix PlainObject; + EIGEN_DEVICE_FUNC inline const Derived& derived() const { return *static_cast(this); } + EIGEN_DEVICE_FUNC inline Derived& derived() { return *static_cast(this); } + EIGEN_DEVICE_FUNC DenseMatrixType toDenseMatrix() const { return derived(); } - template - void evalTo(MatrixBase &other) const; - template - void addTo(MatrixBase &other) const - { other.diagonal() += diagonal(); } - template - void subTo(MatrixBase &other) const - { other.diagonal() -= diagonal(); } - + + EIGEN_DEVICE_FUNC inline const DiagonalVectorType& diagonal() const { return derived().diagonal(); } + EIGEN_DEVICE_FUNC inline DiagonalVectorType& diagonal() { return derived().diagonal(); } + EIGEN_DEVICE_FUNC inline Index rows() const { return diagonal().size(); } + EIGEN_DEVICE_FUNC inline Index cols() const { return diagonal().size(); } - /** \returns the diagonal matrix product of \c *this by the matrix \a matrix. - */ template - const DiagonalProduct + EIGEN_DEVICE_FUNC + const Product operator*(const MatrixBase &matrix) const { - return DiagonalProduct(matrix.derived(), derived()); + return Product(derived(),matrix.derived()); } - inline const DiagonalWrapper, const DiagonalVectorType> > + typedef DiagonalWrapper, const DiagonalVectorType> > InverseReturnType; + EIGEN_DEVICE_FUNC + inline const InverseReturnType inverse() const { - return diagonal().cwiseInverse(); + return InverseReturnType(diagonal().cwiseInverse()); } - inline const DiagonalWrapper, const DiagonalVectorType> > + EIGEN_DEVICE_FUNC + inline const DiagonalWrapper operator*(const Scalar& scalar) const { - return diagonal() * scalar; + return DiagonalWrapper(diagonal() * scalar); } - friend inline const DiagonalWrapper, const DiagonalVectorType> > + EIGEN_DEVICE_FUNC + friend inline const DiagonalWrapper operator*(const Scalar& scalar, const DiagonalBase& other) { - return other.diagonal() * scalar; - } - - #ifdef EIGEN2_SUPPORT - template - bool isApprox(const DiagonalBase& other, typename NumTraits::Real precision = NumTraits::dummy_precision()) const - { - return diagonal().isApprox(other.diagonal(), precision); + return DiagonalWrapper(scalar * other.diagonal()); } - template - bool isApprox(const MatrixBase& other, typename NumTraits::Real precision = NumTraits::dummy_precision()) const - { - return toDenseMatrix().isApprox(other, precision); - } - #endif }; -template -template -void DiagonalBase::evalTo(MatrixBase &other) const -{ - other.setZero(); - other.diagonal() = diagonal(); -} #endif /** \class DiagonalMatrix @@ -124,10 +106,9 @@ struct traits > : traits > { typedef Matrix<_Scalar,SizeAtCompileTime,1,0,MaxSizeAtCompileTime,1> DiagonalVectorType; - typedef Dense StorageKind; - typedef DenseIndex Index; + typedef DiagonalShape StorageKind; enum { - Flags = LvalueBit + Flags = LvalueBit | NoPreferredStorageOrderBit }; }; } @@ -141,7 +122,7 @@ class DiagonalMatrix typedef const DiagonalMatrix& Nested; typedef _Scalar Scalar; typedef typename internal::traits::StorageKind StorageKind; - typedef typename internal::traits::Index Index; + typedef typename internal::traits::StorageIndex StorageIndex; #endif protected: @@ -151,24 +132,31 @@ class DiagonalMatrix public: /** const version of diagonal(). */ + EIGEN_DEVICE_FUNC inline const DiagonalVectorType& diagonal() const { return m_diagonal; } /** \returns a reference to the stored vector of diagonal coefficients. */ + EIGEN_DEVICE_FUNC inline DiagonalVectorType& diagonal() { return m_diagonal; } /** Default constructor without initialization */ + EIGEN_DEVICE_FUNC inline DiagonalMatrix() {} /** Constructs a diagonal matrix with given dimension */ - inline DiagonalMatrix(Index dim) : m_diagonal(dim) {} + EIGEN_DEVICE_FUNC + explicit inline DiagonalMatrix(Index dim) : m_diagonal(dim) {} /** 2D constructor. */ + EIGEN_DEVICE_FUNC inline DiagonalMatrix(const Scalar& x, const Scalar& y) : m_diagonal(x,y) {} /** 3D constructor. */ + EIGEN_DEVICE_FUNC inline DiagonalMatrix(const Scalar& x, const Scalar& y, const Scalar& z) : m_diagonal(x,y,z) {} /** Copy constructor. */ template + EIGEN_DEVICE_FUNC inline DiagonalMatrix(const DiagonalBase& other) : m_diagonal(other.diagonal()) {} #ifndef EIGEN_PARSED_BY_DOXYGEN @@ -178,11 +166,13 @@ class DiagonalMatrix /** generic constructor from expression of the diagonal coefficients */ template + EIGEN_DEVICE_FUNC explicit inline DiagonalMatrix(const MatrixBase& other) : m_diagonal(other) {} /** Copy operator. */ template + EIGEN_DEVICE_FUNC DiagonalMatrix& operator=(const DiagonalBase& other) { m_diagonal = other.diagonal(); @@ -193,6 +183,7 @@ class DiagonalMatrix /** This is a special case of the templated operator=. Its purpose is to * prevent a default operator= from hiding the templated operator=. */ + EIGEN_DEVICE_FUNC DiagonalMatrix& operator=(const DiagonalMatrix& other) { m_diagonal = other.diagonal(); @@ -201,14 +192,19 @@ class DiagonalMatrix #endif /** Resizes to given size. */ + EIGEN_DEVICE_FUNC inline void resize(Index size) { m_diagonal.resize(size); } /** Sets all coefficients to zero. */ + EIGEN_DEVICE_FUNC inline void setZero() { m_diagonal.setZero(); } /** Resizes and sets all coefficients to zero. */ + EIGEN_DEVICE_FUNC inline void setZero(Index size) { m_diagonal.setZero(size); } /** Sets this matrix to be the identity matrix of the current size. */ + EIGEN_DEVICE_FUNC inline void setIdentity() { m_diagonal.setOnes(); } /** Sets this matrix to be the identity matrix of the given size. */ + EIGEN_DEVICE_FUNC inline void setIdentity(Index size) { m_diagonal.setOnes(size); } }; @@ -232,14 +228,15 @@ struct traits > { typedef _DiagonalVectorType DiagonalVectorType; typedef typename DiagonalVectorType::Scalar Scalar; - typedef typename DiagonalVectorType::Index Index; - typedef typename DiagonalVectorType::StorageKind StorageKind; + typedef typename DiagonalVectorType::StorageIndex StorageIndex; + typedef DiagonalShape StorageKind; + typedef typename traits::XprKind XprKind; enum { RowsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, ColsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, - MaxRowsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, - MaxColsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, - Flags = traits::Flags & LvalueBit + MaxRowsAtCompileTime = DiagonalVectorType::MaxSizeAtCompileTime, + MaxColsAtCompileTime = DiagonalVectorType::MaxSizeAtCompileTime, + Flags = (traits::Flags & LvalueBit) | NoPreferredStorageOrderBit }; }; } @@ -255,9 +252,11 @@ class DiagonalWrapper #endif /** Constructor from expression of diagonal coefficients to wrap. */ - inline DiagonalWrapper(DiagonalVectorType& a_diagonal) : m_diagonal(a_diagonal) {} + EIGEN_DEVICE_FUNC + explicit inline DiagonalWrapper(DiagonalVectorType& a_diagonal) : m_diagonal(a_diagonal) {} /** \returns a const reference to the wrapped expression of diagonal coefficients. */ + EIGEN_DEVICE_FUNC const DiagonalVectorType& diagonal() const { return m_diagonal; } protected: @@ -277,7 +276,7 @@ template inline const DiagonalWrapper MatrixBase::asDiagonal() const { - return derived(); + return DiagonalWrapper(derived()); } /** \returns true if *this is approximately equal to a diagonal matrix, @@ -291,12 +290,11 @@ MatrixBase::asDiagonal() const template bool MatrixBase::isDiagonal(const RealScalar& prec) const { - using std::abs; if(cols() != rows()) return false; RealScalar maxAbsOnDiagonal = static_cast(-1); for(Index j = 0; j < cols(); ++j) { - RealScalar absOnDiagonal = abs(coeff(j,j)); + RealScalar absOnDiagonal = numext::abs(coeff(j,j)); if(absOnDiagonal > maxAbsOnDiagonal) maxAbsOnDiagonal = absOnDiagonal; } for(Index j = 0; j < cols(); ++j) @@ -308,6 +306,38 @@ bool MatrixBase::isDiagonal(const RealScalar& prec) const return true; } +namespace internal { + +template<> struct storage_kind_to_shape { typedef DiagonalShape Shape; }; + +struct Diagonal2Dense {}; + +template<> struct AssignmentKind { typedef Diagonal2Dense Kind; }; + +// Diagonal matrix to Dense assignment +template< typename DstXprType, typename SrcXprType, typename Functor> +struct Assignment +{ + static void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op &/*func*/) + { + Index dstRows = src.rows(); + Index dstCols = src.cols(); + if((dst.rows()!=dstRows) || (dst.cols()!=dstCols)) + dst.resize(dstRows, dstCols); + + dst.setZero(); + dst.diagonal() = src.diagonal(); + } + + static void run(DstXprType &dst, const SrcXprType &src, const internal::add_assign_op &/*func*/) + { dst.diagonal() += src.diagonal(); } + + static void run(DstXprType &dst, const SrcXprType &src, const internal::sub_assign_op &/*func*/) + { dst.diagonal() -= src.diagonal(); } +}; + +} // namespace internal + } // end namespace Eigen #endif // EIGEN_DIAGONALMATRIX_H diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Core/DiagonalProduct.h b/ground/gcs/src/libs/eigen/Eigen/src/Core/DiagonalProduct.h index cc6b536e19..d372b938f6 100644 --- a/ground/gcs/src/libs/eigen/Eigen/src/Core/DiagonalProduct.h +++ b/ground/gcs/src/libs/eigen/Eigen/src/Core/DiagonalProduct.h @@ -13,117 +13,14 @@ namespace Eigen { -namespace internal { -template -struct traits > - : traits -{ - typedef typename scalar_product_traits::ReturnType Scalar; - enum { - RowsAtCompileTime = MatrixType::RowsAtCompileTime, - ColsAtCompileTime = MatrixType::ColsAtCompileTime, - MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime, - MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime, - - _StorageOrder = MatrixType::Flags & RowMajorBit ? RowMajor : ColMajor, - _ScalarAccessOnDiag = !((int(_StorageOrder) == ColMajor && int(ProductOrder) == OnTheLeft) - ||(int(_StorageOrder) == RowMajor && int(ProductOrder) == OnTheRight)), - _SameTypes = is_same::value, - // FIXME currently we need same types, but in the future the next rule should be the one - //_Vectorizable = bool(int(MatrixType::Flags)&PacketAccessBit) && ((!_PacketOnDiag) || (_SameTypes && bool(int(DiagonalType::DiagonalVectorType::Flags)&PacketAccessBit))), - _Vectorizable = bool(int(MatrixType::Flags)&PacketAccessBit) && _SameTypes && (_ScalarAccessOnDiag || (bool(int(DiagonalType::DiagonalVectorType::Flags)&PacketAccessBit))), - _LinearAccessMask = (RowsAtCompileTime==1 || ColsAtCompileTime==1) ? LinearAccessBit : 0, - - Flags = ((HereditaryBits|_LinearAccessMask|AlignedBit) & (unsigned int)(MatrixType::Flags)) | (_Vectorizable ? PacketAccessBit : 0),//(int(MatrixType::Flags)&int(DiagonalType::DiagonalVectorType::Flags)&AlignedBit), - Cost0 = EIGEN_ADD_COST(NumTraits::MulCost, MatrixType::CoeffReadCost), - CoeffReadCost = EIGEN_ADD_COST(Cost0,DiagonalType::DiagonalVectorType::CoeffReadCost) - }; -}; -} - -template -class DiagonalProduct : internal::no_assignment_operator, - public MatrixBase > -{ - public: - - typedef MatrixBase Base; - EIGEN_DENSE_PUBLIC_INTERFACE(DiagonalProduct) - - inline DiagonalProduct(const MatrixType& matrix, const DiagonalType& diagonal) - : m_matrix(matrix), m_diagonal(diagonal) - { - eigen_assert(diagonal.diagonal().size() == (ProductOrder == OnTheLeft ? matrix.rows() : matrix.cols())); - } - - EIGEN_STRONG_INLINE Index rows() const { return m_matrix.rows(); } - EIGEN_STRONG_INLINE Index cols() const { return m_matrix.cols(); } - - EIGEN_STRONG_INLINE const Scalar coeff(Index row, Index col) const - { - return m_diagonal.diagonal().coeff(ProductOrder == OnTheLeft ? row : col) * m_matrix.coeff(row, col); - } - - EIGEN_STRONG_INLINE const Scalar coeff(Index idx) const - { - enum { - StorageOrder = int(MatrixType::Flags) & RowMajorBit ? RowMajor : ColMajor - }; - return coeff(int(StorageOrder)==ColMajor?idx:0,int(StorageOrder)==ColMajor?0:idx); - } - - template - EIGEN_STRONG_INLINE PacketScalar packet(Index row, Index col) const - { - enum { - StorageOrder = Flags & RowMajorBit ? RowMajor : ColMajor - }; - const Index indexInDiagonalVector = ProductOrder == OnTheLeft ? row : col; - return packet_impl(row,col,indexInDiagonalVector,typename internal::conditional< - ((int(StorageOrder) == RowMajor && int(ProductOrder) == OnTheLeft) - ||(int(StorageOrder) == ColMajor && int(ProductOrder) == OnTheRight)), internal::true_type, internal::false_type>::type()); - } - - template - EIGEN_STRONG_INLINE PacketScalar packet(Index idx) const - { - enum { - StorageOrder = int(MatrixType::Flags) & RowMajorBit ? RowMajor : ColMajor - }; - return packet(int(StorageOrder)==ColMajor?idx:0,int(StorageOrder)==ColMajor?0:idx); - } - - protected: - template - EIGEN_STRONG_INLINE PacketScalar packet_impl(Index row, Index col, Index id, internal::true_type) const - { - return internal::pmul(m_matrix.template packet(row, col), - internal::pset1(m_diagonal.diagonal().coeff(id))); - } - - template - EIGEN_STRONG_INLINE PacketScalar packet_impl(Index row, Index col, Index id, internal::false_type) const - { - enum { - InnerSize = (MatrixType::Flags & RowMajorBit) ? MatrixType::ColsAtCompileTime : MatrixType::RowsAtCompileTime, - DiagonalVectorPacketLoadMode = (LoadMode == Aligned && (((InnerSize%16) == 0) || (int(DiagonalType::DiagonalVectorType::Flags)&AlignedBit)==AlignedBit) ? Aligned : Unaligned) - }; - return internal::pmul(m_matrix.template packet(row, col), - m_diagonal.diagonal().template packet(id)); - } - - typename MatrixType::Nested m_matrix; - typename DiagonalType::Nested m_diagonal; -}; - /** \returns the diagonal matrix product of \c *this by the diagonal matrix \a diagonal. */ template template -inline const DiagonalProduct +inline const Product MatrixBase::operator*(const DiagonalBase &a_diagonal) const { - return DiagonalProduct(derived(), a_diagonal.derived()); + return Product(derived(),a_diagonal.derived()); } } // end namespace Eigen diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Core/Dot.h b/ground/gcs/src/libs/eigen/Eigen/src/Core/Dot.h index 9d7651f1fd..06ef18b8be 100644 --- a/ground/gcs/src/libs/eigen/Eigen/src/Core/Dot.h +++ b/ground/gcs/src/libs/eigen/Eigen/src/Core/Dot.h @@ -28,26 +28,31 @@ template struct dot_nocheck { - typedef typename scalar_product_traits::Scalar,typename traits::Scalar>::ReturnType ResScalar; + typedef scalar_conj_product_op::Scalar,typename traits::Scalar> conj_prod; + typedef typename conj_prod::result_type ResScalar; + EIGEN_DEVICE_FUNC static inline ResScalar run(const MatrixBase& a, const MatrixBase& b) { - return a.template binaryExpr::Scalar,typename traits::Scalar> >(b).sum(); + return a.template binaryExpr(b).sum(); } }; template struct dot_nocheck { - typedef typename scalar_product_traits::Scalar,typename traits::Scalar>::ReturnType ResScalar; + typedef scalar_conj_product_op::Scalar,typename traits::Scalar> conj_prod; + typedef typename conj_prod::result_type ResScalar; + EIGEN_DEVICE_FUNC static inline ResScalar run(const MatrixBase& a, const MatrixBase& b) { - return a.transpose().template binaryExpr::Scalar,typename traits::Scalar> >(b).sum(); + return a.transpose().template binaryExpr(b).sum(); } }; } // end namespace internal -/** \returns the dot product of *this with other. +/** \fn MatrixBase::dot + * \returns the dot product of *this with other. * * \only_for_vectors * @@ -59,55 +64,30 @@ struct dot_nocheck */ template template -typename internal::scalar_product_traits::Scalar,typename internal::traits::Scalar>::ReturnType +EIGEN_DEVICE_FUNC +typename ScalarBinaryOpTraits::Scalar,typename internal::traits::Scalar>::ReturnType MatrixBase::dot(const MatrixBase& other) const { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) EIGEN_STATIC_ASSERT_VECTOR_ONLY(OtherDerived) EIGEN_STATIC_ASSERT_SAME_VECTOR_SIZE(Derived,OtherDerived) +#if !(defined(EIGEN_NO_STATIC_ASSERT) && defined(EIGEN_NO_DEBUG)) typedef internal::scalar_conj_product_op func; EIGEN_CHECK_BINARY_COMPATIBILIY(func,Scalar,typename OtherDerived::Scalar); - +#endif + eigen_assert(size() == other.size()); return internal::dot_nocheck::run(*this, other); } -#ifdef EIGEN2_SUPPORT -/** \returns the dot product of *this with other, with the Eigen2 convention that the dot product is linear in the first variable - * (conjugating the second variable). Of course this only makes a difference in the complex case. - * - * This method is only available in EIGEN2_SUPPORT mode. - * - * \only_for_vectors - * - * \sa dot() - */ -template -template -typename internal::traits::Scalar -MatrixBase::eigen2_dot(const MatrixBase& other) const -{ - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - EIGEN_STATIC_ASSERT_VECTOR_ONLY(OtherDerived) - EIGEN_STATIC_ASSERT_SAME_VECTOR_SIZE(Derived,OtherDerived) - EIGEN_STATIC_ASSERT((internal::is_same::value), - YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) - - eigen_assert(size() == other.size()); - - return internal::dot_nocheck::run(other,*this); -} -#endif - - //---------- implementation of L2 norm and related functions ---------- /** \returns, for vectors, the squared \em l2 norm of \c *this, and for matrices the Frobenius norm. * In both cases, it consists in the sum of the square of all the matrix entries. * For vectors, this is also equals to the dot product of \c *this with itself. * - * \sa dot(), norm() + * \sa dot(), norm(), lpNorm() */ template EIGEN_STRONG_INLINE typename NumTraits::Scalar>::Real MatrixBase::squaredNorm() const @@ -119,16 +99,18 @@ EIGEN_STRONG_INLINE typename NumTraits::Scala * In both cases, it consists in the square root of the sum of the square of all the matrix entries. * For vectors, this is also equals to the square root of the dot product of \c *this with itself. * - * \sa dot(), squaredNorm() + * \sa lpNorm(), dot(), squaredNorm() */ template inline typename NumTraits::Scalar>::Real MatrixBase::norm() const { - using std::sqrt; - return sqrt(squaredNorm()); + return numext::sqrt(squaredNorm()); } -/** \returns an expression of the quotient of *this by its own norm. +/** \returns an expression of the quotient of \c *this by its own norm. + * + * \warning If the input vector is too small (i.e., this->norm()==0), + * then this function returns a copy of the input. * * \only_for_vectors * @@ -138,22 +120,77 @@ template inline const typename MatrixBase::PlainObject MatrixBase::normalized() const { - typedef typename internal::nested::type Nested; - typedef typename internal::remove_reference::type _Nested; + typedef typename internal::nested_eval::type _Nested; _Nested n(derived()); - return n / n.norm(); + RealScalar z = n.squaredNorm(); + // NOTE: after extensive benchmarking, this conditional does not impact performance, at least on recent x86 CPU + if(z>RealScalar(0)) + return n / numext::sqrt(z); + else + return n; } /** Normalizes the vector, i.e. divides it by its own norm. * * \only_for_vectors * + * \warning If the input vector is too small (i.e., this->norm()==0), then \c *this is left unchanged. + * * \sa norm(), normalized() */ template inline void MatrixBase::normalize() { - *this /= norm(); + RealScalar z = squaredNorm(); + // NOTE: after extensive benchmarking, this conditional does not impact performance, at least on recent x86 CPU + if(z>RealScalar(0)) + derived() /= numext::sqrt(z); +} + +/** \returns an expression of the quotient of \c *this by its own norm while avoiding underflow and overflow. + * + * \only_for_vectors + * + * This method is analogue to the normalized() method, but it reduces the risk of + * underflow and overflow when computing the norm. + * + * \warning If the input vector is too small (i.e., this->norm()==0), + * then this function returns a copy of the input. + * + * \sa stableNorm(), stableNormalize(), normalized() + */ +template +inline const typename MatrixBase::PlainObject +MatrixBase::stableNormalized() const +{ + typedef typename internal::nested_eval::type _Nested; + _Nested n(derived()); + RealScalar w = n.cwiseAbs().maxCoeff(); + RealScalar z = (n/w).squaredNorm(); + if(z>RealScalar(0)) + return n / (numext::sqrt(z)*w); + else + return n; +} + +/** Normalizes the vector while avoid underflow and overflow + * + * \only_for_vectors + * + * This method is analogue to the normalize() method, but it reduces the risk of + * underflow and overflow when computing the norm. + * + * \warning If the input vector is too small (i.e., this->norm()==0), then \c *this is left unchanged. + * + * \sa stableNorm(), stableNormalized(), normalize() + */ +template +inline void MatrixBase::stableNormalize() +{ + RealScalar w = cwiseAbs().maxCoeff(); + RealScalar z = (derived()/w).squaredNorm(); + if(z>RealScalar(0)) + derived() /= numext::sqrt(z)*w; } //---------- implementation of other norms ---------- @@ -164,9 +201,10 @@ template struct lpNorm_selector { typedef typename NumTraits::Scalar>::Real RealScalar; + EIGEN_DEVICE_FUNC static inline RealScalar run(const MatrixBase& m) { - using std::pow; + EIGEN_USING_STD_MATH(pow) return pow(m.cwiseAbs().array().pow(p).sum(), RealScalar(1)/p); } }; @@ -174,6 +212,7 @@ struct lpNorm_selector template struct lpNorm_selector { + EIGEN_DEVICE_FUNC static inline typename NumTraits::Scalar>::Real run(const MatrixBase& m) { return m.cwiseAbs().sum(); @@ -183,6 +222,7 @@ struct lpNorm_selector template struct lpNorm_selector { + EIGEN_DEVICE_FUNC static inline typename NumTraits::Scalar>::Real run(const MatrixBase& m) { return m.norm(); @@ -192,23 +232,35 @@ struct lpNorm_selector template struct lpNorm_selector { - static inline typename NumTraits::Scalar>::Real run(const MatrixBase& m) + typedef typename NumTraits::Scalar>::Real RealScalar; + EIGEN_DEVICE_FUNC + static inline RealScalar run(const MatrixBase& m) { + if(Derived::SizeAtCompileTime==0 || (Derived::SizeAtCompileTime==Dynamic && m.size()==0)) + return RealScalar(0); return m.cwiseAbs().maxCoeff(); } }; } // end namespace internal -/** \returns the \f$ \ell^p \f$ norm of *this, that is, returns the p-th root of the sum of the p-th powers of the absolute values - * of the coefficients of *this. If \a p is the special value \a Eigen::Infinity, this function returns the \f$ \ell^\infty \f$ - * norm, that is the maximum of the absolute values of the coefficients of *this. +/** \returns the \b coefficient-wise \f$ \ell^p \f$ norm of \c *this, that is, returns the p-th root of the sum of the p-th powers of the absolute values + * of the coefficients of \c *this. If \a p is the special value \a Eigen::Infinity, this function returns the \f$ \ell^\infty \f$ + * norm, that is the maximum of the absolute values of the coefficients of \c *this. + * + * In all cases, if \c *this is empty, then the value 0 is returned. + * + * \note For matrices, this function does not compute the
operator-norm. That is, if \c *this is a matrix, then its coefficients are interpreted as a 1D vector. Nonetheless, you can easily compute the 1-norm and \f$\infty\f$-norm matrix operator norms using \link TutorialReductionsVisitorsBroadcastingReductionsNorm partial reductions \endlink. * * \sa norm() */ template template +#ifndef EIGEN_PARSED_BY_DOXYGEN inline typename NumTraits::Scalar>::Real +#else +MatrixBase::RealScalar +#endif MatrixBase::lpNorm() const { return internal::lpNorm_selector::run(*this); @@ -227,8 +279,8 @@ template bool MatrixBase::isOrthogonal (const MatrixBase& other, const RealScalar& prec) const { - typename internal::nested::type nested(derived()); - typename internal::nested::type otherNested(other.derived()); + typename internal::nested_eval::type nested(derived()); + typename internal::nested_eval::type otherNested(other.derived()); return numext::abs2(nested.dot(otherNested)) <= prec * prec * nested.squaredNorm() * otherNested.squaredNorm(); } @@ -246,13 +298,13 @@ bool MatrixBase::isOrthogonal template bool MatrixBase::isUnitary(const RealScalar& prec) const { - typename Derived::Nested nested(derived()); + typename internal::nested_eval::type self(derived()); for(Index i = 0; i < cols(); ++i) { - if(!internal::isApprox(nested.col(i).squaredNorm(), static_cast(1), prec)) + if(!internal::isApprox(self.col(i).squaredNorm(), static_cast(1), prec)) return false; for(Index j = 0; j < i; ++j) - if(!internal::isMuchSmallerThan(nested.col(i).dot(nested.col(j)), static_cast(1), prec)) + if(!internal::isMuchSmallerThan(self.col(i).dot(self.col(j)), static_cast(1), prec)) return false; } return true; diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Core/EigenBase.h b/ground/gcs/src/libs/eigen/Eigen/src/Core/EigenBase.h index fadb45852f..f76995af90 100644 --- a/ground/gcs/src/libs/eigen/Eigen/src/Core/EigenBase.h +++ b/ground/gcs/src/libs/eigen/Eigen/src/Core/EigenBase.h @@ -13,7 +13,9 @@ namespace Eigen { -/** Common base class for all classes T such that MatrixBase has an operator=(T) and a constructor MatrixBase(T). +/** \class EigenBase + * + * Common base class for all classes T such that MatrixBase has an operator=(T) and a constructor MatrixBase(T). * * In other words, an EigenBase object is an object that can be copied into a MatrixBase. * @@ -21,39 +23,57 @@ namespace Eigen { * * Notice that this class is trivial, it is only used to disambiguate overloaded functions. * - * \sa \ref TopicClassHierarchy + * \sa \blank \ref TopicClassHierarchy */ template struct EigenBase { // typedef typename internal::plain_matrix_type::type PlainObject; - + + /** \brief The interface type of indices + * \details To change this, \c \#define the preprocessor symbol \c EIGEN_DEFAULT_DENSE_INDEX_TYPE. + * \deprecated Since Eigen 3.3, its usage is deprecated. Use Eigen::Index instead. + * \sa StorageIndex, \ref TopicPreprocessorDirectives. + */ + typedef Eigen::Index Index; + + // FIXME is it needed? typedef typename internal::traits::StorageKind StorageKind; - typedef typename internal::traits::Index Index; /** \returns a reference to the derived object */ + EIGEN_DEVICE_FUNC Derived& derived() { return *static_cast(this); } /** \returns a const reference to the derived object */ + EIGEN_DEVICE_FUNC const Derived& derived() const { return *static_cast(this); } + EIGEN_DEVICE_FUNC inline Derived& const_cast_derived() const { return *static_cast(const_cast(this)); } + EIGEN_DEVICE_FUNC inline const Derived& const_derived() const { return *static_cast(this); } /** \returns the number of rows. \sa cols(), RowsAtCompileTime */ + EIGEN_DEVICE_FUNC inline Index rows() const { return derived().rows(); } /** \returns the number of columns. \sa rows(), ColsAtCompileTime*/ + EIGEN_DEVICE_FUNC inline Index cols() const { return derived().cols(); } /** \returns the number of coefficients, which is rows()*cols(). * \sa rows(), cols(), SizeAtCompileTime. */ + EIGEN_DEVICE_FUNC inline Index size() const { return rows() * cols(); } /** \internal Don't use it, but do the equivalent: \code dst = *this; \endcode */ - template inline void evalTo(Dest& dst) const + template + EIGEN_DEVICE_FUNC + inline void evalTo(Dest& dst) const { derived().evalTo(dst); } /** \internal Don't use it, but do the equivalent: \code dst += *this; \endcode */ - template inline void addTo(Dest& dst) const + template + EIGEN_DEVICE_FUNC + inline void addTo(Dest& dst) const { // This is the default implementation, // derived class can reimplement it in a more optimized way. @@ -63,7 +83,9 @@ template struct EigenBase } /** \internal Don't use it, but do the equivalent: \code dst -= *this; \endcode */ - template inline void subTo(Dest& dst) const + template + EIGEN_DEVICE_FUNC + inline void subTo(Dest& dst) const { // This is the default implementation, // derived class can reimplement it in a more optimized way. @@ -73,7 +95,8 @@ template struct EigenBase } /** \internal Don't use it, but do the equivalent: \code dst.applyOnTheRight(*this); \endcode */ - template inline void applyThisOnTheRight(Dest& dst) const + template + EIGEN_DEVICE_FUNC inline void applyThisOnTheRight(Dest& dst) const { // This is the default implementation, // derived class can reimplement it in a more optimized way. @@ -81,7 +104,8 @@ template struct EigenBase } /** \internal Don't use it, but do the equivalent: \code dst.applyOnTheLeft(*this); \endcode */ - template inline void applyThisOnTheLeft(Dest& dst) const + template + EIGEN_DEVICE_FUNC inline void applyThisOnTheLeft(Dest& dst) const { // This is the default implementation, // derived class can reimplement it in a more optimized way. @@ -106,7 +130,7 @@ template template Derived& DenseBase::operator=(const EigenBase &other) { - other.derived().evalTo(derived()); + call_assignment(derived(), other.derived()); return derived(); } @@ -114,7 +138,7 @@ template template Derived& DenseBase::operator+=(const EigenBase &other) { - other.derived().addTo(derived()); + call_assignment(derived(), other.derived(), internal::add_assign_op()); return derived(); } @@ -122,7 +146,7 @@ template template Derived& DenseBase::operator-=(const EigenBase &other) { - other.derived().subTo(derived()); + call_assignment(derived(), other.derived(), internal::sub_assign_op()); return derived(); } diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Core/Flagged.h b/ground/gcs/src/libs/eigen/Eigen/src/Core/Flagged.h deleted file mode 100644 index 1f2955fc1d..0000000000 --- a/ground/gcs/src/libs/eigen/Eigen/src/Core/Flagged.h +++ /dev/null @@ -1,140 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008 Benoit Jacob -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_FLAGGED_H -#define EIGEN_FLAGGED_H - -namespace Eigen { - -/** \class Flagged - * \ingroup Core_Module - * - * \brief Expression with modified flags - * - * \param ExpressionType the type of the object of which we are modifying the flags - * \param Added the flags added to the expression - * \param Removed the flags removed from the expression (has priority over Added). - * - * This class represents an expression whose flags have been modified. - * It is the return type of MatrixBase::flagged() - * and most of the time this is the only way it is used. - * - * \sa MatrixBase::flagged() - */ - -namespace internal { -template -struct traits > : traits -{ - enum { Flags = (ExpressionType::Flags | Added) & ~Removed }; -}; -} - -template class Flagged - : public MatrixBase > -{ - public: - - typedef MatrixBase Base; - - EIGEN_DENSE_PUBLIC_INTERFACE(Flagged) - typedef typename internal::conditional::ret, - ExpressionType, const ExpressionType&>::type ExpressionTypeNested; - typedef typename ExpressionType::InnerIterator InnerIterator; - - inline Flagged(const ExpressionType& matrix) : m_matrix(matrix) {} - - inline Index rows() const { return m_matrix.rows(); } - inline Index cols() const { return m_matrix.cols(); } - inline Index outerStride() const { return m_matrix.outerStride(); } - inline Index innerStride() const { return m_matrix.innerStride(); } - - inline CoeffReturnType coeff(Index row, Index col) const - { - return m_matrix.coeff(row, col); - } - - inline CoeffReturnType coeff(Index index) const - { - return m_matrix.coeff(index); - } - - inline const Scalar& coeffRef(Index row, Index col) const - { - return m_matrix.const_cast_derived().coeffRef(row, col); - } - - inline const Scalar& coeffRef(Index index) const - { - return m_matrix.const_cast_derived().coeffRef(index); - } - - inline Scalar& coeffRef(Index row, Index col) - { - return m_matrix.const_cast_derived().coeffRef(row, col); - } - - inline Scalar& coeffRef(Index index) - { - return m_matrix.const_cast_derived().coeffRef(index); - } - - template - inline const PacketScalar packet(Index row, Index col) const - { - return m_matrix.template packet(row, col); - } - - template - inline void writePacket(Index row, Index col, const PacketScalar& x) - { - m_matrix.const_cast_derived().template writePacket(row, col, x); - } - - template - inline const PacketScalar packet(Index index) const - { - return m_matrix.template packet(index); - } - - template - inline void writePacket(Index index, const PacketScalar& x) - { - m_matrix.const_cast_derived().template writePacket(index, x); - } - - const ExpressionType& _expression() const { return m_matrix; } - - template - typename ExpressionType::PlainObject solveTriangular(const MatrixBase& other) const; - - template - void solveTriangularInPlace(const MatrixBase& other) const; - - protected: - ExpressionTypeNested m_matrix; -}; - -/** \returns an expression of *this with added and removed flags - * - * This is mostly for internal use. - * - * \sa class Flagged - */ -template -template -inline const Flagged -DenseBase::flagged() const -{ - return derived(); -} - -} // end namespace Eigen - -#endif // EIGEN_FLAGGED_H diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Core/ForceAlignedAccess.h b/ground/gcs/src/libs/eigen/Eigen/src/Core/ForceAlignedAccess.h index 807c7a2934..7b08b45e67 100644 --- a/ground/gcs/src/libs/eigen/Eigen/src/Core/ForceAlignedAccess.h +++ b/ground/gcs/src/libs/eigen/Eigen/src/Core/ForceAlignedAccess.h @@ -39,29 +39,29 @@ template class ForceAlignedAccess typedef typename internal::dense_xpr_base::type Base; EIGEN_DENSE_PUBLIC_INTERFACE(ForceAlignedAccess) - inline ForceAlignedAccess(const ExpressionType& matrix) : m_expression(matrix) {} + EIGEN_DEVICE_FUNC explicit inline ForceAlignedAccess(const ExpressionType& matrix) : m_expression(matrix) {} - inline Index rows() const { return m_expression.rows(); } - inline Index cols() const { return m_expression.cols(); } - inline Index outerStride() const { return m_expression.outerStride(); } - inline Index innerStride() const { return m_expression.innerStride(); } + EIGEN_DEVICE_FUNC inline Index rows() const { return m_expression.rows(); } + EIGEN_DEVICE_FUNC inline Index cols() const { return m_expression.cols(); } + EIGEN_DEVICE_FUNC inline Index outerStride() const { return m_expression.outerStride(); } + EIGEN_DEVICE_FUNC inline Index innerStride() const { return m_expression.innerStride(); } - inline const CoeffReturnType coeff(Index row, Index col) const + EIGEN_DEVICE_FUNC inline const CoeffReturnType coeff(Index row, Index col) const { return m_expression.coeff(row, col); } - inline Scalar& coeffRef(Index row, Index col) + EIGEN_DEVICE_FUNC inline Scalar& coeffRef(Index row, Index col) { return m_expression.const_cast_derived().coeffRef(row, col); } - inline const CoeffReturnType coeff(Index index) const + EIGEN_DEVICE_FUNC inline const CoeffReturnType coeff(Index index) const { return m_expression.coeff(index); } - inline Scalar& coeffRef(Index index) + EIGEN_DEVICE_FUNC inline Scalar& coeffRef(Index index) { return m_expression.const_cast_derived().coeffRef(index); } @@ -90,7 +90,7 @@ template class ForceAlignedAccess m_expression.const_cast_derived().template writePacket(index, x); } - operator const ExpressionType&() const { return m_expression; } + EIGEN_DEVICE_FUNC operator const ExpressionType&() const { return m_expression; } protected: const ExpressionType& m_expression; @@ -127,7 +127,7 @@ template inline typename internal::add_const_on_value_type,Derived&>::type>::type MatrixBase::forceAlignedAccessIf() const { - return derived(); + return derived(); // FIXME This should not work but apparently is never used } /** \returns an expression of *this with forced aligned access if \a Enable is true. @@ -138,7 +138,7 @@ template inline typename internal::conditional,Derived&>::type MatrixBase::forceAlignedAccessIf() { - return derived(); + return derived(); // FIXME This should not work but apparently is never used } } // end namespace Eigen diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Core/Functors.h b/ground/gcs/src/libs/eigen/Eigen/src/Core/Functors.h deleted file mode 100644 index 5f14c6587e..0000000000 --- a/ground/gcs/src/libs/eigen/Eigen/src/Core/Functors.h +++ /dev/null @@ -1,1026 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008-2010 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_FUNCTORS_H -#define EIGEN_FUNCTORS_H - -namespace Eigen { - -namespace internal { - -// associative functors: - -/** \internal - * \brief Template functor to compute the sum of two scalars - * - * \sa class CwiseBinaryOp, MatrixBase::operator+, class VectorwiseOp, MatrixBase::sum() - */ -template struct scalar_sum_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_sum_op) - EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& a, const Scalar& b) const { return a + b; } - template - EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const - { return internal::padd(a,b); } - template - EIGEN_STRONG_INLINE const Scalar predux(const Packet& a) const - { return internal::predux(a); } -}; -template -struct functor_traits > { - enum { - Cost = NumTraits::AddCost, - PacketAccess = packet_traits::HasAdd - }; -}; - -/** \internal - * \brief Template functor to compute the product of two scalars - * - * \sa class CwiseBinaryOp, Cwise::operator*(), class VectorwiseOp, MatrixBase::redux() - */ -template struct scalar_product_op { - enum { - // TODO vectorize mixed product - Vectorizable = is_same::value && packet_traits::HasMul && packet_traits::HasMul - }; - typedef typename scalar_product_traits::ReturnType result_type; - EIGEN_EMPTY_STRUCT_CTOR(scalar_product_op) - EIGEN_STRONG_INLINE const result_type operator() (const LhsScalar& a, const RhsScalar& b) const { return a * b; } - template - EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const - { return internal::pmul(a,b); } - template - EIGEN_STRONG_INLINE const result_type predux(const Packet& a) const - { return internal::predux_mul(a); } -}; -template -struct functor_traits > { - enum { - Cost = (NumTraits::MulCost + NumTraits::MulCost)/2, // rough estimate! - PacketAccess = scalar_product_op::Vectorizable - }; -}; - -/** \internal - * \brief Template functor to compute the conjugate product of two scalars - * - * This is a short cut for conj(x) * y which is needed for optimization purpose; in Eigen2 support mode, this becomes x * conj(y) - */ -template struct scalar_conj_product_op { - - enum { - Conj = NumTraits::IsComplex - }; - - typedef typename scalar_product_traits::ReturnType result_type; - - EIGEN_EMPTY_STRUCT_CTOR(scalar_conj_product_op) - EIGEN_STRONG_INLINE const result_type operator() (const LhsScalar& a, const RhsScalar& b) const - { return conj_helper().pmul(a,b); } - - template - EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const - { return conj_helper().pmul(a,b); } -}; -template -struct functor_traits > { - enum { - Cost = NumTraits::MulCost, - PacketAccess = internal::is_same::value && packet_traits::HasMul - }; -}; - -/** \internal - * \brief Template functor to compute the min of two scalars - * - * \sa class CwiseBinaryOp, MatrixBase::cwiseMin, class VectorwiseOp, MatrixBase::minCoeff() - */ -template struct scalar_min_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_min_op) - EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& a, const Scalar& b) const { using std::min; return (min)(a, b); } - template - EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const - { return internal::pmin(a,b); } - template - EIGEN_STRONG_INLINE const Scalar predux(const Packet& a) const - { return internal::predux_min(a); } -}; -template -struct functor_traits > { - enum { - Cost = NumTraits::AddCost, - PacketAccess = packet_traits::HasMin - }; -}; - -/** \internal - * \brief Template functor to compute the max of two scalars - * - * \sa class CwiseBinaryOp, MatrixBase::cwiseMax, class VectorwiseOp, MatrixBase::maxCoeff() - */ -template struct scalar_max_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_max_op) - EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& a, const Scalar& b) const { using std::max; return (max)(a, b); } - template - EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const - { return internal::pmax(a,b); } - template - EIGEN_STRONG_INLINE const Scalar predux(const Packet& a) const - { return internal::predux_max(a); } -}; -template -struct functor_traits > { - enum { - Cost = NumTraits::AddCost, - PacketAccess = packet_traits::HasMax - }; -}; - -/** \internal - * \brief Template functor to compute the hypot of two scalars - * - * \sa MatrixBase::stableNorm(), class Redux - */ -template struct scalar_hypot_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_hypot_op) -// typedef typename NumTraits::Real result_type; - EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& _x, const Scalar& _y) const - { - using std::max; - using std::min; - using std::sqrt; - Scalar p = (max)(_x, _y); - Scalar q = (min)(_x, _y); - Scalar qp = q/p; - return p * sqrt(Scalar(1) + qp*qp); - } -}; -template -struct functor_traits > { - enum { Cost = 5 * NumTraits::MulCost, PacketAccess=0 }; -}; - -/** \internal - * \brief Template functor to compute the pow of two scalars - */ -template struct scalar_binary_pow_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_binary_pow_op) - inline Scalar operator() (const Scalar& a, const OtherScalar& b) const { return numext::pow(a, b); } -}; -template -struct functor_traits > { - enum { Cost = 5 * NumTraits::MulCost, PacketAccess = false }; -}; - -// other binary functors: - -/** \internal - * \brief Template functor to compute the difference of two scalars - * - * \sa class CwiseBinaryOp, MatrixBase::operator- - */ -template struct scalar_difference_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_difference_op) - EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& a, const Scalar& b) const { return a - b; } - template - EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const - { return internal::psub(a,b); } -}; -template -struct functor_traits > { - enum { - Cost = NumTraits::AddCost, - PacketAccess = packet_traits::HasSub - }; -}; - -/** \internal - * \brief Template functor to compute the quotient of two scalars - * - * \sa class CwiseBinaryOp, Cwise::operator/() - */ -template struct scalar_quotient_op { - enum { - // TODO vectorize mixed product - Vectorizable = is_same::value && packet_traits::HasDiv && packet_traits::HasDiv - }; - typedef typename scalar_product_traits::ReturnType result_type; - EIGEN_EMPTY_STRUCT_CTOR(scalar_quotient_op) - EIGEN_STRONG_INLINE const result_type operator() (const LhsScalar& a, const RhsScalar& b) const { return a / b; } - template - EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& b) const - { return internal::pdiv(a,b); } -}; -template -struct functor_traits > { - enum { - Cost = (NumTraits::MulCost + NumTraits::MulCost), // rough estimate! - PacketAccess = scalar_quotient_op::Vectorizable - }; -}; - - - -/** \internal - * \brief Template functor to compute the and of two booleans - * - * \sa class CwiseBinaryOp, ArrayBase::operator&& - */ -struct scalar_boolean_and_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_boolean_and_op) - EIGEN_STRONG_INLINE bool operator() (const bool& a, const bool& b) const { return a && b; } -}; -template<> struct functor_traits { - enum { - Cost = NumTraits::AddCost, - PacketAccess = false - }; -}; - -/** \internal - * \brief Template functor to compute the or of two booleans - * - * \sa class CwiseBinaryOp, ArrayBase::operator|| - */ -struct scalar_boolean_or_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_boolean_or_op) - EIGEN_STRONG_INLINE bool operator() (const bool& a, const bool& b) const { return a || b; } -}; -template<> struct functor_traits { - enum { - Cost = NumTraits::AddCost, - PacketAccess = false - }; -}; - -/** \internal - * \brief Template functors for comparison of two scalars - * \todo Implement packet-comparisons - */ -template struct scalar_cmp_op; - -template -struct functor_traits > { - enum { - Cost = NumTraits::AddCost, - PacketAccess = false - }; -}; - -template -struct result_of(Scalar,Scalar)> { - typedef bool type; -}; - - -template struct scalar_cmp_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_cmp_op) - EIGEN_STRONG_INLINE bool operator()(const Scalar& a, const Scalar& b) const {return a==b;} -}; -template struct scalar_cmp_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_cmp_op) - EIGEN_STRONG_INLINE bool operator()(const Scalar& a, const Scalar& b) const {return a struct scalar_cmp_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_cmp_op) - EIGEN_STRONG_INLINE bool operator()(const Scalar& a, const Scalar& b) const {return a<=b;} -}; -template struct scalar_cmp_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_cmp_op) - EIGEN_STRONG_INLINE bool operator()(const Scalar& a, const Scalar& b) const {return !(a<=b || b<=a);} -}; -template struct scalar_cmp_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_cmp_op) - EIGEN_STRONG_INLINE bool operator()(const Scalar& a, const Scalar& b) const {return a!=b;} -}; - -// unary functors: - -/** \internal - * \brief Template functor to compute the opposite of a scalar - * - * \sa class CwiseUnaryOp, MatrixBase::operator- - */ -template struct scalar_opposite_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_opposite_op) - EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& a) const { return -a; } - template - EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const - { return internal::pnegate(a); } -}; -template -struct functor_traits > -{ enum { - Cost = NumTraits::AddCost, - PacketAccess = packet_traits::HasNegate }; -}; - -/** \internal - * \brief Template functor to compute the absolute value of a scalar - * - * \sa class CwiseUnaryOp, Cwise::abs - */ -template struct scalar_abs_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_abs_op) - typedef typename NumTraits::Real result_type; - EIGEN_STRONG_INLINE const result_type operator() (const Scalar& a) const { using std::abs; return abs(a); } - template - EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const - { return internal::pabs(a); } -}; -template -struct functor_traits > -{ - enum { - Cost = NumTraits::AddCost, - PacketAccess = packet_traits::HasAbs - }; -}; - -/** \internal - * \brief Template functor to compute the squared absolute value of a scalar - * - * \sa class CwiseUnaryOp, Cwise::abs2 - */ -template struct scalar_abs2_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_abs2_op) - typedef typename NumTraits::Real result_type; - EIGEN_STRONG_INLINE const result_type operator() (const Scalar& a) const { return numext::abs2(a); } - template - EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const - { return internal::pmul(a,a); } -}; -template -struct functor_traits > -{ enum { Cost = NumTraits::MulCost, PacketAccess = packet_traits::HasAbs2 }; }; - -/** \internal - * \brief Template functor to compute the conjugate of a complex value - * - * \sa class CwiseUnaryOp, MatrixBase::conjugate() - */ -template struct scalar_conjugate_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_conjugate_op) - EIGEN_STRONG_INLINE const Scalar operator() (const Scalar& a) const { using numext::conj; return conj(a); } - template - EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const { return internal::pconj(a); } -}; -template -struct functor_traits > -{ - enum { - Cost = NumTraits::IsComplex ? NumTraits::AddCost : 0, - PacketAccess = packet_traits::HasConj - }; -}; - -/** \internal - * \brief Template functor to cast a scalar to another type - * - * \sa class CwiseUnaryOp, MatrixBase::cast() - */ -template -struct scalar_cast_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_cast_op) - typedef NewType result_type; - EIGEN_STRONG_INLINE const NewType operator() (const Scalar& a) const { return cast(a); } -}; -template -struct functor_traits > -{ enum { Cost = is_same::value ? 0 : NumTraits::AddCost, PacketAccess = false }; }; - -/** \internal - * \brief Template functor to extract the real part of a complex - * - * \sa class CwiseUnaryOp, MatrixBase::real() - */ -template -struct scalar_real_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_real_op) - typedef typename NumTraits::Real result_type; - EIGEN_STRONG_INLINE result_type operator() (const Scalar& a) const { return numext::real(a); } -}; -template -struct functor_traits > -{ enum { Cost = 0, PacketAccess = false }; }; - -/** \internal - * \brief Template functor to extract the imaginary part of a complex - * - * \sa class CwiseUnaryOp, MatrixBase::imag() - */ -template -struct scalar_imag_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_imag_op) - typedef typename NumTraits::Real result_type; - EIGEN_STRONG_INLINE result_type operator() (const Scalar& a) const { return numext::imag(a); } -}; -template -struct functor_traits > -{ enum { Cost = 0, PacketAccess = false }; }; - -/** \internal - * \brief Template functor to extract the real part of a complex as a reference - * - * \sa class CwiseUnaryOp, MatrixBase::real() - */ -template -struct scalar_real_ref_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_real_ref_op) - typedef typename NumTraits::Real result_type; - EIGEN_STRONG_INLINE result_type& operator() (const Scalar& a) const { return numext::real_ref(*const_cast(&a)); } -}; -template -struct functor_traits > -{ enum { Cost = 0, PacketAccess = false }; }; - -/** \internal - * \brief Template functor to extract the imaginary part of a complex as a reference - * - * \sa class CwiseUnaryOp, MatrixBase::imag() - */ -template -struct scalar_imag_ref_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_imag_ref_op) - typedef typename NumTraits::Real result_type; - EIGEN_STRONG_INLINE result_type& operator() (const Scalar& a) const { return numext::imag_ref(*const_cast(&a)); } -}; -template -struct functor_traits > -{ enum { Cost = 0, PacketAccess = false }; }; - -/** \internal - * - * \brief Template functor to compute the exponential of a scalar - * - * \sa class CwiseUnaryOp, Cwise::exp() - */ -template struct scalar_exp_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_exp_op) - inline const Scalar operator() (const Scalar& a) const { using std::exp; return exp(a); } - typedef typename packet_traits::type Packet; - inline Packet packetOp(const Packet& a) const { return internal::pexp(a); } -}; -template -struct functor_traits > -{ enum { Cost = 5 * NumTraits::MulCost, PacketAccess = packet_traits::HasExp }; }; - -/** \internal - * - * \brief Template functor to compute the logarithm of a scalar - * - * \sa class CwiseUnaryOp, Cwise::log() - */ -template struct scalar_log_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_log_op) - inline const Scalar operator() (const Scalar& a) const { using std::log; return log(a); } - typedef typename packet_traits::type Packet; - inline Packet packetOp(const Packet& a) const { return internal::plog(a); } -}; -template -struct functor_traits > -{ enum { Cost = 5 * NumTraits::MulCost, PacketAccess = packet_traits::HasLog }; }; - -/** \internal - * \brief Template functor to multiply a scalar by a fixed other one - * - * \sa class CwiseUnaryOp, MatrixBase::operator*, MatrixBase::operator/ - */ -/* NOTE why doing the pset1() in packetOp *is* an optimization ? - * indeed it seems better to declare m_other as a Packet and do the pset1() once - * in the constructor. However, in practice: - * - GCC does not like m_other as a Packet and generate a load every time it needs it - * - on the other hand GCC is able to moves the pset1() outside the loop :) - * - simpler code ;) - * (ICC and gcc 4.4 seems to perform well in both cases, the issue is visible with y = a*x + b*y) - */ -template -struct scalar_multiple_op { - typedef typename packet_traits::type Packet; - // FIXME default copy constructors seems bugged with std::complex<> - EIGEN_STRONG_INLINE scalar_multiple_op(const scalar_multiple_op& other) : m_other(other.m_other) { } - EIGEN_STRONG_INLINE scalar_multiple_op(const Scalar& other) : m_other(other) { } - EIGEN_STRONG_INLINE Scalar operator() (const Scalar& a) const { return a * m_other; } - EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const - { return internal::pmul(a, pset1(m_other)); } - typename add_const_on_value_type::Nested>::type m_other; -}; -template -struct functor_traits > -{ enum { Cost = NumTraits::MulCost, PacketAccess = packet_traits::HasMul }; }; - -template -struct scalar_multiple2_op { - typedef typename scalar_product_traits::ReturnType result_type; - EIGEN_STRONG_INLINE scalar_multiple2_op(const scalar_multiple2_op& other) : m_other(other.m_other) { } - EIGEN_STRONG_INLINE scalar_multiple2_op(const Scalar2& other) : m_other(other) { } - EIGEN_STRONG_INLINE result_type operator() (const Scalar1& a) const { return a * m_other; } - typename add_const_on_value_type::Nested>::type m_other; -}; -template -struct functor_traits > -{ enum { Cost = NumTraits::MulCost, PacketAccess = false }; }; - -/** \internal - * \brief Template functor to divide a scalar by a fixed other one - * - * This functor is used to implement the quotient of a matrix by - * a scalar where the scalar type is not necessarily a floating point type. - * - * \sa class CwiseUnaryOp, MatrixBase::operator/ - */ -template -struct scalar_quotient1_op { - typedef typename packet_traits::type Packet; - // FIXME default copy constructors seems bugged with std::complex<> - EIGEN_STRONG_INLINE scalar_quotient1_op(const scalar_quotient1_op& other) : m_other(other.m_other) { } - EIGEN_STRONG_INLINE scalar_quotient1_op(const Scalar& other) : m_other(other) {} - EIGEN_STRONG_INLINE Scalar operator() (const Scalar& a) const { return a / m_other; } - EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a) const - { return internal::pdiv(a, pset1(m_other)); } - typename add_const_on_value_type::Nested>::type m_other; -}; -template -struct functor_traits > -{ enum { Cost = 2 * NumTraits::MulCost, PacketAccess = packet_traits::HasDiv }; }; - -// nullary functors - -template -struct scalar_constant_op { - typedef typename packet_traits::type Packet; - EIGEN_STRONG_INLINE scalar_constant_op(const scalar_constant_op& other) : m_other(other.m_other) { } - EIGEN_STRONG_INLINE scalar_constant_op(const Scalar& other) : m_other(other) { } - template - EIGEN_STRONG_INLINE const Scalar operator() (Index, Index = 0) const { return m_other; } - template - EIGEN_STRONG_INLINE const Packet packetOp(Index, Index = 0) const { return internal::pset1(m_other); } - const Scalar m_other; -}; -template -struct functor_traits > -// FIXME replace this packet test by a safe one -{ enum { Cost = 1, PacketAccess = packet_traits::Vectorizable, IsRepeatable = true }; }; - -template struct scalar_identity_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_identity_op) - template - EIGEN_STRONG_INLINE const Scalar operator() (Index row, Index col) const { return row==col ? Scalar(1) : Scalar(0); } -}; -template -struct functor_traits > -{ enum { Cost = NumTraits::AddCost, PacketAccess = false, IsRepeatable = true }; }; - -template struct linspaced_op_impl; - -// linear access for packet ops: -// 1) initialization -// base = [low, ..., low] + ([step, ..., step] * [-size, ..., 0]) -// 2) each step (where size is 1 for coeff access or PacketSize for packet access) -// base += [size*step, ..., size*step] -// -// TODO: Perhaps it's better to initialize lazily (so not in the constructor but in packetOp) -// in order to avoid the padd() in operator() ? -template -struct linspaced_op_impl -{ - typedef typename packet_traits::type Packet; - - linspaced_op_impl(const Scalar& low, const Scalar& step) : - m_low(low), m_step(step), - m_packetStep(pset1(packet_traits::size*step)), - m_base(padd(pset1(low), pmul(pset1(step),plset(-packet_traits::size)))) {} - - template - EIGEN_STRONG_INLINE const Scalar operator() (Index i) const - { - m_base = padd(m_base, pset1(m_step)); - return m_low+Scalar(i)*m_step; - } - - template - EIGEN_STRONG_INLINE const Packet packetOp(Index) const { return m_base = padd(m_base,m_packetStep); } - - const Scalar m_low; - const Scalar m_step; - const Packet m_packetStep; - mutable Packet m_base; -}; - -// random access for packet ops: -// 1) each step -// [low, ..., low] + ( [step, ..., step] * ( [i, ..., i] + [0, ..., size] ) ) -template -struct linspaced_op_impl -{ - typedef typename packet_traits::type Packet; - - linspaced_op_impl(const Scalar& low, const Scalar& step) : - m_low(low), m_step(step), - m_lowPacket(pset1(m_low)), m_stepPacket(pset1(m_step)), m_interPacket(plset(0)) {} - - template - EIGEN_STRONG_INLINE const Scalar operator() (Index i) const { return m_low+i*m_step; } - - template - EIGEN_STRONG_INLINE const Packet packetOp(Index i) const - { return internal::padd(m_lowPacket, pmul(m_stepPacket, padd(pset1(Scalar(i)),m_interPacket))); } - - const Scalar m_low; - const Scalar m_step; - const Packet m_lowPacket; - const Packet m_stepPacket; - const Packet m_interPacket; -}; - -// ----- Linspace functor ---------------------------------------------------------------- - -// Forward declaration (we default to random access which does not really give -// us a speed gain when using packet access but it allows to use the functor in -// nested expressions). -template struct linspaced_op; -template struct functor_traits< linspaced_op > -{ enum { Cost = 1, PacketAccess = packet_traits::HasSetLinear, IsRepeatable = true }; }; -template struct linspaced_op -{ - typedef typename packet_traits::type Packet; - linspaced_op(const Scalar& low, const Scalar& high, DenseIndex num_steps) : impl((num_steps==1 ? high : low), (num_steps==1 ? Scalar() : (high-low)/Scalar(num_steps-1))) {} - - template - EIGEN_STRONG_INLINE const Scalar operator() (Index i) const { return impl(i); } - - // We need this function when assigning e.g. a RowVectorXd to a MatrixXd since - // there row==0 and col is used for the actual iteration. - template - EIGEN_STRONG_INLINE const Scalar operator() (Index row, Index col) const - { - eigen_assert(col==0 || row==0); - return impl(col + row); - } - - template - EIGEN_STRONG_INLINE const Packet packetOp(Index i) const { return impl.packetOp(i); } - - // We need this function when assigning e.g. a RowVectorXd to a MatrixXd since - // there row==0 and col is used for the actual iteration. - template - EIGEN_STRONG_INLINE const Packet packetOp(Index row, Index col) const - { - eigen_assert(col==0 || row==0); - return impl.packetOp(col + row); - } - - // This proxy object handles the actual required temporaries, the different - // implementations (random vs. sequential access) as well as the - // correct piping to size 2/4 packet operations. - const linspaced_op_impl impl; -}; - -// all functors allow linear access, except scalar_identity_op. So we fix here a quick meta -// to indicate whether a functor allows linear access, just always answering 'yes' except for -// scalar_identity_op. -// FIXME move this to functor_traits adding a functor_default -template struct functor_has_linear_access { enum { ret = 1 }; }; -template struct functor_has_linear_access > { enum { ret = 0 }; }; - -// In Eigen, any binary op (Product, CwiseBinaryOp) require the Lhs and Rhs to have the same scalar type, except for multiplication -// where the mixing of different types is handled by scalar_product_traits -// In particular, real * complex is allowed. -// FIXME move this to functor_traits adding a functor_default -template struct functor_is_product_like { enum { ret = 0 }; }; -template struct functor_is_product_like > { enum { ret = 1 }; }; -template struct functor_is_product_like > { enum { ret = 1 }; }; -template struct functor_is_product_like > { enum { ret = 1 }; }; - - -/** \internal - * \brief Template functor to add a scalar to a fixed other one - * \sa class CwiseUnaryOp, Array::operator+ - */ -/* If you wonder why doing the pset1() in packetOp() is an optimization check scalar_multiple_op */ -template -struct scalar_add_op { - typedef typename packet_traits::type Packet; - // FIXME default copy constructors seems bugged with std::complex<> - inline scalar_add_op(const scalar_add_op& other) : m_other(other.m_other) { } - inline scalar_add_op(const Scalar& other) : m_other(other) { } - inline Scalar operator() (const Scalar& a) const { return a + m_other; } - inline const Packet packetOp(const Packet& a) const - { return internal::padd(a, pset1(m_other)); } - const Scalar m_other; -}; -template -struct functor_traits > -{ enum { Cost = NumTraits::AddCost, PacketAccess = packet_traits::HasAdd }; }; - -/** \internal - * \brief Template functor to compute the square root of a scalar - * \sa class CwiseUnaryOp, Cwise::sqrt() - */ -template struct scalar_sqrt_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_sqrt_op) - inline const Scalar operator() (const Scalar& a) const { using std::sqrt; return sqrt(a); } - typedef typename packet_traits::type Packet; - inline Packet packetOp(const Packet& a) const { return internal::psqrt(a); } -}; -template -struct functor_traits > -{ enum { - Cost = 5 * NumTraits::MulCost, - PacketAccess = packet_traits::HasSqrt - }; -}; - -/** \internal - * \brief Template functor to compute the cosine of a scalar - * \sa class CwiseUnaryOp, ArrayBase::cos() - */ -template struct scalar_cos_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_cos_op) - inline Scalar operator() (const Scalar& a) const { using std::cos; return cos(a); } - typedef typename packet_traits::type Packet; - inline Packet packetOp(const Packet& a) const { return internal::pcos(a); } -}; -template -struct functor_traits > -{ - enum { - Cost = 5 * NumTraits::MulCost, - PacketAccess = packet_traits::HasCos - }; -}; - -/** \internal - * \brief Template functor to compute the sine of a scalar - * \sa class CwiseUnaryOp, ArrayBase::sin() - */ -template struct scalar_sin_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_sin_op) - inline const Scalar operator() (const Scalar& a) const { using std::sin; return sin(a); } - typedef typename packet_traits::type Packet; - inline Packet packetOp(const Packet& a) const { return internal::psin(a); } -}; -template -struct functor_traits > -{ - enum { - Cost = 5 * NumTraits::MulCost, - PacketAccess = packet_traits::HasSin - }; -}; - - -/** \internal - * \brief Template functor to compute the tan of a scalar - * \sa class CwiseUnaryOp, ArrayBase::tan() - */ -template struct scalar_tan_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_tan_op) - inline const Scalar operator() (const Scalar& a) const { using std::tan; return tan(a); } - typedef typename packet_traits::type Packet; - inline Packet packetOp(const Packet& a) const { return internal::ptan(a); } -}; -template -struct functor_traits > -{ - enum { - Cost = 5 * NumTraits::MulCost, - PacketAccess = packet_traits::HasTan - }; -}; - -/** \internal - * \brief Template functor to compute the arc cosine of a scalar - * \sa class CwiseUnaryOp, ArrayBase::acos() - */ -template struct scalar_acos_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_acos_op) - inline const Scalar operator() (const Scalar& a) const { using std::acos; return acos(a); } - typedef typename packet_traits::type Packet; - inline Packet packetOp(const Packet& a) const { return internal::pacos(a); } -}; -template -struct functor_traits > -{ - enum { - Cost = 5 * NumTraits::MulCost, - PacketAccess = packet_traits::HasACos - }; -}; - -/** \internal - * \brief Template functor to compute the arc sine of a scalar - * \sa class CwiseUnaryOp, ArrayBase::asin() - */ -template struct scalar_asin_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_asin_op) - inline const Scalar operator() (const Scalar& a) const { using std::asin; return asin(a); } - typedef typename packet_traits::type Packet; - inline Packet packetOp(const Packet& a) const { return internal::pasin(a); } -}; -template -struct functor_traits > -{ - enum { - Cost = 5 * NumTraits::MulCost, - PacketAccess = packet_traits::HasASin - }; -}; - -/** \internal - * \brief Template functor to raise a scalar to a power - * \sa class CwiseUnaryOp, Cwise::pow - */ -template -struct scalar_pow_op { - // FIXME default copy constructors seems bugged with std::complex<> - inline scalar_pow_op(const scalar_pow_op& other) : m_exponent(other.m_exponent) { } - inline scalar_pow_op(const Scalar& exponent) : m_exponent(exponent) {} - inline Scalar operator() (const Scalar& a) const { return numext::pow(a, m_exponent); } - const Scalar m_exponent; -}; -template -struct functor_traits > -{ enum { Cost = 5 * NumTraits::MulCost, PacketAccess = false }; }; - -/** \internal - * \brief Template functor to compute the quotient between a scalar and array entries. - * \sa class CwiseUnaryOp, Cwise::inverse() - */ -template -struct scalar_inverse_mult_op { - scalar_inverse_mult_op(const Scalar& other) : m_other(other) {} - inline Scalar operator() (const Scalar& a) const { return m_other / a; } - template - inline const Packet packetOp(const Packet& a) const - { return internal::pdiv(pset1(m_other),a); } - Scalar m_other; -}; - -/** \internal - * \brief Template functor to compute the inverse of a scalar - * \sa class CwiseUnaryOp, Cwise::inverse() - */ -template -struct scalar_inverse_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_inverse_op) - inline Scalar operator() (const Scalar& a) const { return Scalar(1)/a; } - template - inline const Packet packetOp(const Packet& a) const - { return internal::pdiv(pset1(Scalar(1)),a); } -}; -template -struct functor_traits > -{ enum { Cost = NumTraits::MulCost, PacketAccess = packet_traits::HasDiv }; }; - -/** \internal - * \brief Template functor to compute the square of a scalar - * \sa class CwiseUnaryOp, Cwise::square() - */ -template -struct scalar_square_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_square_op) - inline Scalar operator() (const Scalar& a) const { return a*a; } - template - inline const Packet packetOp(const Packet& a) const - { return internal::pmul(a,a); } -}; -template -struct functor_traits > -{ enum { Cost = NumTraits::MulCost, PacketAccess = packet_traits::HasMul }; }; - -/** \internal - * \brief Template functor to compute the cube of a scalar - * \sa class CwiseUnaryOp, Cwise::cube() - */ -template -struct scalar_cube_op { - EIGEN_EMPTY_STRUCT_CTOR(scalar_cube_op) - inline Scalar operator() (const Scalar& a) const { return a*a*a; } - template - inline const Packet packetOp(const Packet& a) const - { return internal::pmul(a,pmul(a,a)); } -}; -template -struct functor_traits > -{ enum { Cost = 2*NumTraits::MulCost, PacketAccess = packet_traits::HasMul }; }; - -// default functor traits for STL functors: - -template -struct functor_traits > -{ enum { Cost = NumTraits::MulCost, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = NumTraits::MulCost, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = NumTraits::AddCost, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = NumTraits::AddCost, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = NumTraits::AddCost, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = 1, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = 1, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = 1, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = 1, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = 1, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = 1, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = 1, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = 1, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = 1, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = functor_traits::Cost, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = functor_traits::Cost, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = 1 + functor_traits::Cost, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = 1 + functor_traits::Cost, PacketAccess = false }; }; - -#ifdef EIGEN_STDEXT_SUPPORT - -template -struct functor_traits > -{ enum { Cost = 0, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = 0, PacketAccess = false }; }; - -template -struct functor_traits > > -{ enum { Cost = 0, PacketAccess = false }; }; - -template -struct functor_traits > > -{ enum { Cost = 0, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = functor_traits::Cost + functor_traits::Cost, PacketAccess = false }; }; - -template -struct functor_traits > -{ enum { Cost = functor_traits::Cost + functor_traits::Cost + functor_traits::Cost, PacketAccess = false }; }; - -#endif // EIGEN_STDEXT_SUPPORT - -// allow to add new functors and specializations of functor_traits from outside Eigen. -// this macro is really needed because functor_traits must be specialized after it is declared but before it is used... -#ifdef EIGEN_FUNCTORS_PLUGIN -#include EIGEN_FUNCTORS_PLUGIN -#endif - -} // end namespace internal - -} // end namespace Eigen - -#endif // EIGEN_FUNCTORS_H diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Core/Fuzzy.h b/ground/gcs/src/libs/eigen/Eigen/src/Core/Fuzzy.h index fe63bd2984..3e403a09d9 100644 --- a/ground/gcs/src/libs/eigen/Eigen/src/Core/Fuzzy.h +++ b/ground/gcs/src/libs/eigen/Eigen/src/Core/Fuzzy.h @@ -19,18 +19,19 @@ namespace internal template::IsInteger> struct isApprox_selector { + EIGEN_DEVICE_FUNC static bool run(const Derived& x, const OtherDerived& y, const typename Derived::RealScalar& prec) { - using std::min; - typename internal::nested::type nested(x); - typename internal::nested::type otherNested(y); - return (nested - otherNested).cwiseAbs2().sum() <= prec * prec * (min)(nested.cwiseAbs2().sum(), otherNested.cwiseAbs2().sum()); + typename internal::nested_eval::type nested(x); + typename internal::nested_eval::type otherNested(y); + return (nested - otherNested).cwiseAbs2().sum() <= prec * prec * numext::mini(nested.cwiseAbs2().sum(), otherNested.cwiseAbs2().sum()); } }; template struct isApprox_selector { + EIGEN_DEVICE_FUNC static bool run(const Derived& x, const OtherDerived& y, const typename Derived::RealScalar&) { return x.matrix() == y.matrix(); @@ -40,6 +41,7 @@ struct isApprox_selector template::IsInteger> struct isMuchSmallerThan_object_selector { + EIGEN_DEVICE_FUNC static bool run(const Derived& x, const OtherDerived& y, const typename Derived::RealScalar& prec) { return x.cwiseAbs2().sum() <= numext::abs2(prec) * y.cwiseAbs2().sum(); @@ -49,6 +51,7 @@ struct isMuchSmallerThan_object_selector template struct isMuchSmallerThan_object_selector { + EIGEN_DEVICE_FUNC static bool run(const Derived& x, const OtherDerived&, const typename Derived::RealScalar&) { return x.matrix() == Derived::Zero(x.rows(), x.cols()).matrix(); @@ -58,6 +61,7 @@ struct isMuchSmallerThan_object_selector template::IsInteger> struct isMuchSmallerThan_scalar_selector { + EIGEN_DEVICE_FUNC static bool run(const Derived& x, const typename Derived::RealScalar& y, const typename Derived::RealScalar& prec) { return x.cwiseAbs2().sum() <= numext::abs2(prec * y); @@ -67,6 +71,7 @@ struct isMuchSmallerThan_scalar_selector template struct isMuchSmallerThan_scalar_selector { + EIGEN_DEVICE_FUNC static bool run(const Derived& x, const typename Derived::RealScalar&, const typename Derived::RealScalar&) { return x.matrix() == Derived::Zero(x.rows(), x.cols()).matrix(); diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Core/GeneralProduct.h b/ground/gcs/src/libs/eigen/Eigen/src/Core/GeneralProduct.h index 29ac522d2e..0f16cd8e39 100644 --- a/ground/gcs/src/libs/eigen/Eigen/src/Core/GeneralProduct.h +++ b/ground/gcs/src/libs/eigen/Eigen/src/Core/GeneralProduct.h @@ -11,29 +11,7 @@ #ifndef EIGEN_GENERAL_PRODUCT_H #define EIGEN_GENERAL_PRODUCT_H -namespace Eigen { - -/** \class GeneralProduct - * \ingroup Core_Module - * - * \brief Expression of the product of two general matrices or vectors - * - * \param LhsNested the type used to store the left-hand side - * \param RhsNested the type used to store the right-hand side - * \param ProductMode the type of the product - * - * This class represents an expression of the product of two general matrices. - * We call a general matrix, a dense matrix with full storage. For instance, - * This excludes triangular, selfadjoint, and sparse matrices. - * It is the return type of the operator* between general matrices. Its template - * arguments are determined automatically by ProductReturnType. Therefore, - * GeneralProduct should never be used direclty. To determine the result type of a - * function which involves a matrix product, use ProductReturnType::Type. - * - * \sa ProductReturnType, MatrixBase::operator*(const MatrixBase&) - */ -template::value> -class GeneralProduct; +namespace Eigen { enum { Large = 2, @@ -47,7 +25,8 @@ template struct product_type_selector; template struct product_size_category { enum { is_large = MaxSize == Dynamic || - Size >= EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD, + Size >= EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD || + (Size==Dynamic && MaxSize>=EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD), value = is_large ? Large : Size == 1 ? 1 : Small @@ -59,15 +38,14 @@ template struct product_type typedef typename remove_all::type _Lhs; typedef typename remove_all::type _Rhs; enum { - MaxRows = _Lhs::MaxRowsAtCompileTime, - Rows = _Lhs::RowsAtCompileTime, - MaxCols = _Rhs::MaxColsAtCompileTime, - Cols = _Rhs::ColsAtCompileTime, - MaxDepth = EIGEN_SIZE_MIN_PREFER_FIXED(_Lhs::MaxColsAtCompileTime, - _Rhs::MaxRowsAtCompileTime), - Depth = EIGEN_SIZE_MIN_PREFER_FIXED(_Lhs::ColsAtCompileTime, - _Rhs::RowsAtCompileTime), - LargeThreshold = EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD + MaxRows = traits<_Lhs>::MaxRowsAtCompileTime, + Rows = traits<_Lhs>::RowsAtCompileTime, + MaxCols = traits<_Rhs>::MaxColsAtCompileTime, + Cols = traits<_Rhs>::ColsAtCompileTime, + MaxDepth = EIGEN_SIZE_MIN_PREFER_FIXED(traits<_Lhs>::MaxColsAtCompileTime, + traits<_Rhs>::MaxRowsAtCompileTime), + Depth = EIGEN_SIZE_MIN_PREFER_FIXED(traits<_Lhs>::ColsAtCompileTime, + traits<_Rhs>::RowsAtCompileTime) }; // the splitting into different lines of code here, introducing the _select enums and the typedef below, @@ -82,7 +60,8 @@ template struct product_type public: enum { - value = selector::ret + value = selector::ret, + ret = selector::ret }; #ifdef EIGEN_DEBUG_PRODUCT static void debug() @@ -98,12 +77,13 @@ template struct product_type #endif }; - /* The following allows to select the kind of product at compile time * based on the three dimensions of the product. * This is a compile time mapping from {1,Small,Large}^3 -> {product types} */ // FIXME I'm not sure the current mapping is the ideal one. template struct product_type_selector { enum { ret = OuterProduct }; }; +template struct product_type_selector { enum { ret = LazyCoeffBasedProductMode }; }; +template struct product_type_selector<1, N, 1> { enum { ret = LazyCoeffBasedProductMode }; }; template struct product_type_selector<1, 1, Depth> { enum { ret = InnerProduct }; }; template<> struct product_type_selector<1, 1, 1> { enum { ret = InnerProduct }; }; template<> struct product_type_selector { enum { ret = CoeffBasedProductMode }; }; @@ -122,60 +102,12 @@ template<> struct product_type_selector { enum template<> struct product_type_selector { enum { ret = GemmProduct }; }; template<> struct product_type_selector { enum { ret = GemmProduct }; }; template<> struct product_type_selector { enum { ret = GemmProduct }; }; -template<> struct product_type_selector { enum { ret = GemmProduct }; }; -template<> struct product_type_selector { enum { ret = GemmProduct }; }; +template<> struct product_type_selector { enum { ret = CoeffBasedProductMode }; }; +template<> struct product_type_selector { enum { ret = CoeffBasedProductMode }; }; template<> struct product_type_selector { enum { ret = GemmProduct }; }; } // end namespace internal -/** \class ProductReturnType - * \ingroup Core_Module - * - * \brief Helper class to get the correct and optimized returned type of operator* - * - * \param Lhs the type of the left-hand side - * \param Rhs the type of the right-hand side - * \param ProductMode the type of the product (determined automatically by internal::product_mode) - * - * This class defines the typename Type representing the optimized product expression - * between two matrix expressions. In practice, using ProductReturnType::Type - * is the recommended way to define the result type of a function returning an expression - * which involve a matrix product. The class Product should never be - * used directly. - * - * \sa class Product, MatrixBase::operator*(const MatrixBase&) - */ -template -struct ProductReturnType -{ - // TODO use the nested type to reduce instanciations ???? -// typedef typename internal::nested::type LhsNested; -// typedef typename internal::nested::type RhsNested; - - typedef GeneralProduct Type; -}; - -template -struct ProductReturnType -{ - typedef typename internal::nested::type >::type LhsNested; - typedef typename internal::nested::type >::type RhsNested; - typedef CoeffBasedProduct Type; -}; - -template -struct ProductReturnType -{ - typedef typename internal::nested::type >::type LhsNested; - typedef typename internal::nested::type >::type RhsNested; - typedef CoeffBasedProduct Type; -}; - -// this is a workaround for sun CC -template -struct LazyProductReturnType : public ProductReturnType -{}; - /*********************************************************************** * Implementation of Inner Vector Vector Product ***********************************************************************/ @@ -187,119 +119,10 @@ struct LazyProductReturnType : public ProductReturnType with: operator=(Scalar x); -namespace internal { - -template -struct traits > - : traits::ReturnType,1,1> > -{}; - -} - -template -class GeneralProduct - : internal::no_assignment_operator, - public Matrix::ReturnType,1,1> -{ - typedef Matrix::ReturnType,1,1> Base; - public: - GeneralProduct(const Lhs& lhs, const Rhs& rhs) - { - EIGEN_STATIC_ASSERT((internal::is_same::value), - YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) - - Base::coeffRef(0,0) = (lhs.transpose().cwiseProduct(rhs)).sum(); - } - - /** Convertion to scalar */ - operator const typename Base::Scalar() const { - return Base::coeff(0,0); - } -}; - /*********************************************************************** * Implementation of Outer Vector Vector Product ***********************************************************************/ -namespace internal { - -// Column major -template -EIGEN_DONT_INLINE void outer_product_selector_run(const ProductType& prod, Dest& dest, const Func& func, const false_type&) -{ - typedef typename Dest::Index Index; - // FIXME make sure lhs is sequentially stored - // FIXME not very good if rhs is real and lhs complex while alpha is real too - const Index cols = dest.cols(); - for (Index j=0; j -EIGEN_DONT_INLINE void outer_product_selector_run(const ProductType& prod, Dest& dest, const Func& func, const true_type&) { - typedef typename Dest::Index Index; - // FIXME make sure rhs is sequentially stored - // FIXME not very good if lhs is real and rhs complex while alpha is real too - const Index rows = dest.rows(); - for (Index i=0; i -struct traits > - : traits, Lhs, Rhs> > -{}; - -} - -template -class GeneralProduct - : public ProductBase, Lhs, Rhs> -{ - template struct is_row_major : internal::conditional<(int(T::Flags)&RowMajorBit), internal::true_type, internal::false_type>::type {}; - - public: - EIGEN_PRODUCT_PUBLIC_INTERFACE(GeneralProduct) - - GeneralProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs) - { - EIGEN_STATIC_ASSERT((internal::is_same::value), - YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) - } - - struct set { template void operator()(const Dst& dst, const Src& src) const { dst.const_cast_derived() = src; } }; - struct add { template void operator()(const Dst& dst, const Src& src) const { dst.const_cast_derived() += src; } }; - struct sub { template void operator()(const Dst& dst, const Src& src) const { dst.const_cast_derived() -= src; } }; - struct adds { - Scalar m_scale; - adds(const Scalar& s) : m_scale(s) {} - template void operator()(const Dst& dst, const Src& src) const { - dst.const_cast_derived() += m_scale * src; - } - }; - - template - inline void evalTo(Dest& dest) const { - internal::outer_product_selector_run(*this, dest, set(), is_row_major()); - } - - template - inline void addTo(Dest& dest) const { - internal::outer_product_selector_run(*this, dest, add(), is_row_major()); - } - - template - inline void subTo(Dest& dest) const { - internal::outer_product_selector_run(*this, dest, sub(), is_row_major()); - } - - template void scaleAndAddTo(Dest& dest, const Scalar& alpha) const - { - internal::outer_product_selector_run(*this, dest, adds(alpha), is_row_major()); - } -}; - /*********************************************************************** * Implementation of General Matrix Vector Product ***********************************************************************/ @@ -313,60 +136,13 @@ class GeneralProduct */ namespace internal { -template -struct traits > - : traits, Lhs, Rhs> > -{}; - template -struct gemv_selector; +struct gemv_dense_selector; } // end namespace internal -template -class GeneralProduct - : public ProductBase, Lhs, Rhs> -{ - public: - EIGEN_PRODUCT_PUBLIC_INTERFACE(GeneralProduct) - - typedef typename Lhs::Scalar LhsScalar; - typedef typename Rhs::Scalar RhsScalar; - - GeneralProduct(const Lhs& a_lhs, const Rhs& a_rhs) : Base(a_lhs,a_rhs) - { -// EIGEN_STATIC_ASSERT((internal::is_same::value), -// YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) - } - - enum { Side = Lhs::IsVectorAtCompileTime ? OnTheLeft : OnTheRight }; - typedef typename internal::conditional::type MatrixType; - - template void scaleAndAddTo(Dest& dst, const Scalar& alpha) const - { - eigen_assert(m_lhs.rows() == dst.rows() && m_rhs.cols() == dst.cols()); - internal::gemv_selector::HasUsableDirectAccess)>::run(*this, dst, alpha); - } -}; - namespace internal { -// The vector is on the left => transposition -template -struct gemv_selector -{ - template - static void run(const ProductType& prod, Dest& dest, const typename ProductType::Scalar& alpha) - { - Transpose destT(dest); - enum { OtherStorageOrder = StorageOrder == RowMajor ? ColMajor : RowMajor }; - gemv_selector - ::run(GeneralProduct,Transpose, GemvProduct> - (prod.rhs().transpose(), prod.lhs().transpose()), destT, alpha); - } -}; - template struct gemv_static_vector_if; template @@ -384,46 +160,61 @@ struct gemv_static_vector_if template struct gemv_static_vector_if { - #if EIGEN_ALIGN_STATICALLY - internal::plain_array m_data; - EIGEN_STRONG_INLINE Scalar* data() { return m_data.array; } - #else - // Some architectures cannot align on the stack, - // => let's manually enforce alignment by allocating more data and return the address of the first aligned element. enum { ForceAlignment = internal::packet_traits::Vectorizable, PacketSize = internal::packet_traits::size }; - internal::plain_array m_data; + #if EIGEN_MAX_STATIC_ALIGN_BYTES!=0 + internal::plain_array m_data; + EIGEN_STRONG_INLINE Scalar* data() { return m_data.array; } + #else + // Some architectures cannot align on the stack, + // => let's manually enforce alignment by allocating more data and return the address of the first aligned element. + internal::plain_array m_data; EIGEN_STRONG_INLINE Scalar* data() { return ForceAlignment - ? reinterpret_cast((reinterpret_cast(m_data.array) & ~(size_t(15))) + 16) + ? reinterpret_cast((internal::UIntPtr(m_data.array) & ~(std::size_t(EIGEN_MAX_ALIGN_BYTES-1))) + EIGEN_MAX_ALIGN_BYTES) : m_data.array; } #endif }; -template<> struct gemv_selector +// The vector is on the left => transposition +template +struct gemv_dense_selector +{ + template + static void run(const Lhs &lhs, const Rhs &rhs, Dest& dest, const typename Dest::Scalar& alpha) + { + Transpose destT(dest); + enum { OtherStorageOrder = StorageOrder == RowMajor ? ColMajor : RowMajor }; + gemv_dense_selector + ::run(rhs.transpose(), lhs.transpose(), destT, alpha); + } +}; + +template<> struct gemv_dense_selector { - template - static inline void run(const ProductType& prod, Dest& dest, const typename ProductType::Scalar& alpha) + template + static inline void run(const Lhs &lhs, const Rhs &rhs, Dest& dest, const typename Dest::Scalar& alpha) { - typedef typename ProductType::Index Index; - typedef typename ProductType::LhsScalar LhsScalar; - typedef typename ProductType::RhsScalar RhsScalar; - typedef typename ProductType::Scalar ResScalar; - typedef typename ProductType::RealScalar RealScalar; - typedef typename ProductType::ActualLhsType ActualLhsType; - typedef typename ProductType::ActualRhsType ActualRhsType; - typedef typename ProductType::LhsBlasTraits LhsBlasTraits; - typedef typename ProductType::RhsBlasTraits RhsBlasTraits; - typedef Map, Aligned> MappedDest; - - ActualLhsType actualLhs = LhsBlasTraits::extract(prod.lhs()); - ActualRhsType actualRhs = RhsBlasTraits::extract(prod.rhs()); - - ResScalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(prod.lhs()) - * RhsBlasTraits::extractScalarFactor(prod.rhs()); + typedef typename Lhs::Scalar LhsScalar; + typedef typename Rhs::Scalar RhsScalar; + typedef typename Dest::Scalar ResScalar; + typedef typename Dest::RealScalar RealScalar; + + typedef internal::blas_traits LhsBlasTraits; + typedef typename LhsBlasTraits::DirectLinearAccessType ActualLhsType; + typedef internal::blas_traits RhsBlasTraits; + typedef typename RhsBlasTraits::DirectLinearAccessType ActualRhsType; + + typedef Map, EIGEN_PLAIN_ENUM_MIN(AlignedMax,internal::packet_traits::size)> MappedDest; + + ActualLhsType actualLhs = LhsBlasTraits::extract(lhs); + ActualRhsType actualRhs = RhsBlasTraits::extract(rhs); + + ResScalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(lhs) + * RhsBlasTraits::extractScalarFactor(rhs); // make sure Dest is a compile-time vector type (bug 1166) typedef typename conditional::type ActualDest; @@ -433,80 +224,97 @@ template<> struct gemv_selector // on, the other hand it is good for the cache to pack the vector anyways... EvalToDestAtCompileTime = (ActualDest::InnerStrideAtCompileTime==1), ComplexByReal = (NumTraits::IsComplex) && (!NumTraits::IsComplex), - MightCannotUseDest = (ActualDest::InnerStrideAtCompileTime!=1) || ComplexByReal + MightCannotUseDest = (!EvalToDestAtCompileTime) || ComplexByReal }; - gemv_static_vector_if static_dest; - - bool alphaIsCompatible = (!ComplexByReal) || (numext::imag(actualAlpha)==RealScalar(0)); - bool evalToDest = EvalToDestAtCompileTime && alphaIsCompatible; - + typedef const_blas_data_mapper LhsMapper; + typedef const_blas_data_mapper RhsMapper; RhsScalar compatibleAlpha = get_factor::run(actualAlpha); - ei_declare_aligned_stack_constructed_variable(ResScalar,actualDestPtr,dest.size(), - evalToDest ? dest.data() : static_dest.data()); - - if(!evalToDest) + if(!MightCannotUseDest) { - #ifdef EIGEN_DENSE_STORAGE_CTOR_PLUGIN - int size = dest.size(); - EIGEN_DENSE_STORAGE_CTOR_PLUGIN - #endif - if(!alphaIsCompatible) + // shortcut if we are sure to be able to use dest directly, + // this ease the compiler to generate cleaner and more optimzized code for most common cases + general_matrix_vector_product + ::run( + actualLhs.rows(), actualLhs.cols(), + LhsMapper(actualLhs.data(), actualLhs.outerStride()), + RhsMapper(actualRhs.data(), actualRhs.innerStride()), + dest.data(), 1, + compatibleAlpha); + } + else + { + gemv_static_vector_if static_dest; + + const bool alphaIsCompatible = (!ComplexByReal) || (numext::imag(actualAlpha)==RealScalar(0)); + const bool evalToDest = EvalToDestAtCompileTime && alphaIsCompatible; + + ei_declare_aligned_stack_constructed_variable(ResScalar,actualDestPtr,dest.size(), + evalToDest ? dest.data() : static_dest.data()); + + if(!evalToDest) { - MappedDest(actualDestPtr, dest.size()).setZero(); - compatibleAlpha = RhsScalar(1); + #ifdef EIGEN_DENSE_STORAGE_CTOR_PLUGIN + Index size = dest.size(); + EIGEN_DENSE_STORAGE_CTOR_PLUGIN + #endif + if(!alphaIsCompatible) + { + MappedDest(actualDestPtr, dest.size()).setZero(); + compatibleAlpha = RhsScalar(1); + } + else + MappedDest(actualDestPtr, dest.size()) = dest; } - else - MappedDest(actualDestPtr, dest.size()) = dest; - } - general_matrix_vector_product - ::run( - actualLhs.rows(), actualLhs.cols(), - actualLhs.data(), actualLhs.outerStride(), - actualRhs.data(), actualRhs.innerStride(), - actualDestPtr, 1, - compatibleAlpha); + general_matrix_vector_product + ::run( + actualLhs.rows(), actualLhs.cols(), + LhsMapper(actualLhs.data(), actualLhs.outerStride()), + RhsMapper(actualRhs.data(), actualRhs.innerStride()), + actualDestPtr, 1, + compatibleAlpha); - if (!evalToDest) - { - if(!alphaIsCompatible) - dest += actualAlpha * MappedDest(actualDestPtr, dest.size()); - else - dest = MappedDest(actualDestPtr, dest.size()); + if (!evalToDest) + { + if(!alphaIsCompatible) + dest.matrix() += actualAlpha * MappedDest(actualDestPtr, dest.size()); + else + dest = MappedDest(actualDestPtr, dest.size()); + } } } }; -template<> struct gemv_selector +template<> struct gemv_dense_selector { - template - static void run(const ProductType& prod, Dest& dest, const typename ProductType::Scalar& alpha) + template + static void run(const Lhs &lhs, const Rhs &rhs, Dest& dest, const typename Dest::Scalar& alpha) { - typedef typename ProductType::LhsScalar LhsScalar; - typedef typename ProductType::RhsScalar RhsScalar; - typedef typename ProductType::Scalar ResScalar; - typedef typename ProductType::Index Index; - typedef typename ProductType::ActualLhsType ActualLhsType; - typedef typename ProductType::ActualRhsType ActualRhsType; - typedef typename ProductType::_ActualRhsType _ActualRhsType; - typedef typename ProductType::LhsBlasTraits LhsBlasTraits; - typedef typename ProductType::RhsBlasTraits RhsBlasTraits; - - typename add_const::type actualLhs = LhsBlasTraits::extract(prod.lhs()); - typename add_const::type actualRhs = RhsBlasTraits::extract(prod.rhs()); - - ResScalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(prod.lhs()) - * RhsBlasTraits::extractScalarFactor(prod.rhs()); + typedef typename Lhs::Scalar LhsScalar; + typedef typename Rhs::Scalar RhsScalar; + typedef typename Dest::Scalar ResScalar; + + typedef internal::blas_traits LhsBlasTraits; + typedef typename LhsBlasTraits::DirectLinearAccessType ActualLhsType; + typedef internal::blas_traits RhsBlasTraits; + typedef typename RhsBlasTraits::DirectLinearAccessType ActualRhsType; + typedef typename internal::remove_all::type ActualRhsTypeCleaned; + + typename add_const::type actualLhs = LhsBlasTraits::extract(lhs); + typename add_const::type actualRhs = RhsBlasTraits::extract(rhs); + + ResScalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(lhs) + * RhsBlasTraits::extractScalarFactor(rhs); enum { // FIXME find a way to allow an inner stride on the result if packet_traits::size==1 // on, the other hand it is good for the cache to pack the vector anyways... - DirectlyUseRhs = _ActualRhsType::InnerStrideAtCompileTime==1 + DirectlyUseRhs = ActualRhsTypeCleaned::InnerStrideAtCompileTime==1 }; - gemv_static_vector_if static_rhs; + gemv_static_vector_if static_rhs; ei_declare_aligned_stack_constructed_variable(RhsScalar,actualRhsPtr,actualRhs.size(), DirectlyUseRhs ? const_cast(actualRhs.data()) : static_rhs.data()); @@ -514,45 +322,48 @@ template<> struct gemv_selector if(!DirectlyUseRhs) { #ifdef EIGEN_DENSE_STORAGE_CTOR_PLUGIN - int size = actualRhs.size(); + Index size = actualRhs.size(); EIGEN_DENSE_STORAGE_CTOR_PLUGIN #endif - Map(actualRhsPtr, actualRhs.size()) = actualRhs; + Map(actualRhsPtr, actualRhs.size()) = actualRhs; } + typedef const_blas_data_mapper LhsMapper; + typedef const_blas_data_mapper RhsMapper; general_matrix_vector_product - ::run( + ::run( actualLhs.rows(), actualLhs.cols(), - actualLhs.data(), actualLhs.outerStride(), - actualRhsPtr, 1, + LhsMapper(actualLhs.data(), actualLhs.outerStride()), + RhsMapper(actualRhsPtr, 1), dest.data(), dest.col(0).innerStride(), //NOTE if dest is not a vector at compile-time, then dest.innerStride() might be wrong. (bug 1166) actualAlpha); } }; -template<> struct gemv_selector +template<> struct gemv_dense_selector { - template - static void run(const ProductType& prod, Dest& dest, const typename ProductType::Scalar& alpha) + template + static void run(const Lhs &lhs, const Rhs &rhs, Dest& dest, const typename Dest::Scalar& alpha) { - typedef typename Dest::Index Index; - // TODO makes sure dest is sequentially stored in memory, otherwise use a temp - const Index size = prod.rhs().rows(); + EIGEN_STATIC_ASSERT((!nested_eval::Evaluate),EIGEN_INTERNAL_COMPILATION_ERROR_OR_YOU_MADE_A_PROGRAMMING_MISTAKE); + // TODO if rhs is large enough it might be beneficial to make sure that dest is sequentially stored in memory, otherwise use a temp + typename nested_eval::type actual_rhs(rhs); + const Index size = rhs.rows(); for(Index k=0; k struct gemv_selector +template<> struct gemv_dense_selector { - template - static void run(const ProductType& prod, Dest& dest, const typename ProductType::Scalar& alpha) + template + static void run(const Lhs &lhs, const Rhs &rhs, Dest& dest, const typename Dest::Scalar& alpha) { - typedef typename Dest::Index Index; - // TODO makes sure rhs is sequentially stored in memory, otherwise use a temp - const Index rows = prod.rows(); + EIGEN_STATIC_ASSERT((!nested_eval::Evaluate),EIGEN_INTERNAL_COMPILATION_ERROR_OR_YOU_MADE_A_PROGRAMMING_MISTAKE); + typename nested_eval::type actual_rhs(rhs); + const Index rows = dest.rows(); for(Index i=0; i struct gemv_selector * * \sa lazyProduct(), operator*=(const MatrixBase&), Cwise::operator*() */ +#ifndef __CUDACC__ + template template -inline const typename ProductReturnType::Type +inline const Product MatrixBase::operator*(const MatrixBase &other) const { // A note regarding the function declaration: In MSVC, this function will sometimes @@ -595,9 +408,12 @@ MatrixBase::operator*(const MatrixBase &other) const #ifdef EIGEN_DEBUG_PRODUCT internal::product_type::debug(); #endif - return typename ProductReturnType::Type(derived(), other.derived()); + + return Product(derived(), other.derived()); } +#endif // __CUDACC__ + /** \returns an expression of the matrix product of \c *this and \a other without implicit evaluation. * * The returned product will behave like any other expressions: the coefficients of the product will be @@ -611,7 +427,7 @@ MatrixBase::operator*(const MatrixBase &other) const */ template template -const typename LazyProductReturnType::Type +const Product MatrixBase::lazyProduct(const MatrixBase &other) const { enum { @@ -630,7 +446,7 @@ MatrixBase::lazyProduct(const MatrixBase &other) const INVALID_MATRIX_PRODUCT__IF_YOU_WANTED_A_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTION) EIGEN_STATIC_ASSERT(ProductIsValid || SameSizes, INVALID_MATRIX_PRODUCT) - return typename LazyProductReturnType::Type(derived(), other.derived()); + return Product(derived(), other.derived()); } } // end namespace Eigen diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Core/GenericPacketMath.h b/ground/gcs/src/libs/eigen/Eigen/src/Core/GenericPacketMath.h index 5f783ebeee..27033a2dd0 100644 --- a/ground/gcs/src/libs/eigen/Eigen/src/Core/GenericPacketMath.h +++ b/ground/gcs/src/libs/eigen/Eigen/src/Core/GenericPacketMath.h @@ -42,21 +42,28 @@ namespace internal { struct default_packet_traits { enum { + HasHalfPacket = 0, + HasAdd = 1, HasSub = 1, HasMul = 1, HasNegate = 1, HasAbs = 1, + HasArg = 0, HasAbs2 = 1, HasMin = 1, HasMax = 1, HasConj = 1, HasSetLinear = 1, + HasBlend = 0, HasDiv = 0, HasSqrt = 0, + HasRsqrt = 0, HasExp = 0, HasLog = 0, + HasLog1p = 0, + HasLog10 = 0, HasPow = 0, HasSin = 0, @@ -64,17 +71,37 @@ struct default_packet_traits HasTan = 0, HasASin = 0, HasACos = 0, - HasATan = 0 + HasATan = 0, + HasSinh = 0, + HasCosh = 0, + HasTanh = 0, + HasLGamma = 0, + HasDiGamma = 0, + HasZeta = 0, + HasPolygamma = 0, + HasErf = 0, + HasErfc = 0, + HasIGamma = 0, + HasIGammac = 0, + HasBetaInc = 0, + + HasRound = 0, + HasFloor = 0, + HasCeil = 0, + + HasSign = 0 }; }; template struct packet_traits : default_packet_traits { typedef T type; + typedef T half; enum { Vectorizable = 0, size = 1, - AlignedOnScalar = 0 + AlignedOnScalar = 0, + HasHalfPacket = 0 }; enum { HasAdd = 0, @@ -90,135 +117,239 @@ template struct packet_traits : default_packet_traits }; }; +template struct packet_traits : packet_traits { }; + +template struct type_casting_traits { + enum { + VectorizedCast = 0, + SrcCoeffRatio = 1, + TgtCoeffRatio = 1 + }; +}; + + +/** \internal \returns static_cast(a) (coeff-wise) */ +template +EIGEN_DEVICE_FUNC inline TgtPacket +pcast(const SrcPacket& a) { + return static_cast(a); +} +template +EIGEN_DEVICE_FUNC inline TgtPacket +pcast(const SrcPacket& a, const SrcPacket& /*b*/) { + return static_cast(a); +} + +template +EIGEN_DEVICE_FUNC inline TgtPacket +pcast(const SrcPacket& a, const SrcPacket& /*b*/, const SrcPacket& /*c*/, const SrcPacket& /*d*/) { + return static_cast(a); +} + /** \internal \returns a + b (coeff-wise) */ -template inline Packet +template EIGEN_DEVICE_FUNC inline Packet padd(const Packet& a, const Packet& b) { return a+b; } /** \internal \returns a - b (coeff-wise) */ -template inline Packet +template EIGEN_DEVICE_FUNC inline Packet psub(const Packet& a, const Packet& b) { return a-b; } /** \internal \returns -a (coeff-wise) */ -template inline Packet +template EIGEN_DEVICE_FUNC inline Packet pnegate(const Packet& a) { return -a; } /** \internal \returns conj(a) (coeff-wise) */ -template inline Packet + +template EIGEN_DEVICE_FUNC inline Packet pconj(const Packet& a) { return numext::conj(a); } /** \internal \returns a * b (coeff-wise) */ -template inline Packet +template EIGEN_DEVICE_FUNC inline Packet pmul(const Packet& a, const Packet& b) { return a*b; } /** \internal \returns a / b (coeff-wise) */ -template inline Packet +template EIGEN_DEVICE_FUNC inline Packet pdiv(const Packet& a, const Packet& b) { return a/b; } /** \internal \returns the min of \a a and \a b (coeff-wise) */ -template inline Packet +template EIGEN_DEVICE_FUNC inline Packet pmin(const Packet& a, - const Packet& b) { using std::min; return (min)(a, b); } + const Packet& b) { return numext::mini(a, b); } /** \internal \returns the max of \a a and \a b (coeff-wise) */ -template inline Packet +template EIGEN_DEVICE_FUNC inline Packet pmax(const Packet& a, - const Packet& b) { using std::max; return (max)(a, b); } + const Packet& b) { return numext::maxi(a, b); } /** \internal \returns the absolute value of \a a */ -template inline Packet +template EIGEN_DEVICE_FUNC inline Packet pabs(const Packet& a) { using std::abs; return abs(a); } +/** \internal \returns the phase angle of \a a */ +template EIGEN_DEVICE_FUNC inline Packet +parg(const Packet& a) { using numext::arg; return arg(a); } + /** \internal \returns the bitwise and of \a a and \a b */ -template inline Packet +template EIGEN_DEVICE_FUNC inline Packet pand(const Packet& a, const Packet& b) { return a & b; } /** \internal \returns the bitwise or of \a a and \a b */ -template inline Packet +template EIGEN_DEVICE_FUNC inline Packet por(const Packet& a, const Packet& b) { return a | b; } /** \internal \returns the bitwise xor of \a a and \a b */ -template inline Packet +template EIGEN_DEVICE_FUNC inline Packet pxor(const Packet& a, const Packet& b) { return a ^ b; } /** \internal \returns the bitwise andnot of \a a and \a b */ -template inline Packet +template EIGEN_DEVICE_FUNC inline Packet pandnot(const Packet& a, const Packet& b) { return a & (!b); } /** \internal \returns a packet version of \a *from, from must be 16 bytes aligned */ -template inline Packet +template EIGEN_DEVICE_FUNC inline Packet pload(const typename unpacket_traits::type* from) { return *from; } /** \internal \returns a packet version of \a *from, (un-aligned load) */ -template inline Packet +template EIGEN_DEVICE_FUNC inline Packet ploadu(const typename unpacket_traits::type* from) { return *from; } +/** \internal \returns a packet with constant coefficients \a a, e.g.: (a,a,a,a) */ +template EIGEN_DEVICE_FUNC inline Packet +pset1(const typename unpacket_traits::type& a) { return a; } + +/** \internal \returns a packet with constant coefficients \a a[0], e.g.: (a[0],a[0],a[0],a[0]) */ +template EIGEN_DEVICE_FUNC inline Packet +pload1(const typename unpacket_traits::type *a) { return pset1(*a); } + /** \internal \returns a packet with elements of \a *from duplicated. - * For instance, for a packet of 8 elements, 4 scalar will be read from \a *from and - * duplicated to form: {from[0],from[0],from[1],from[1],,from[2],from[2],,from[3],from[3]} + * For instance, for a packet of 8 elements, 4 scalars will be read from \a *from and + * duplicated to form: {from[0],from[0],from[1],from[1],from[2],from[2],from[3],from[3]} * Currently, this function is only used for scalar * complex products. - */ -template inline Packet + */ +template EIGEN_DEVICE_FUNC inline Packet ploaddup(const typename unpacket_traits::type* from) { return *from; } -/** \internal \returns a packet with constant coefficients \a a, e.g.: (a,a,a,a) */ -template inline Packet -pset1(const typename unpacket_traits::type& a) { return a; } +/** \internal \returns a packet with elements of \a *from quadrupled. + * For instance, for a packet of 8 elements, 2 scalars will be read from \a *from and + * replicated to form: {from[0],from[0],from[0],from[0],from[1],from[1],from[1],from[1]} + * Currently, this function is only used in matrix products. + * For packet-size smaller or equal to 4, this function is equivalent to pload1 + */ +template EIGEN_DEVICE_FUNC inline Packet +ploadquad(const typename unpacket_traits::type* from) +{ return pload1(from); } + +/** \internal equivalent to + * \code + * a0 = pload1(a+0); + * a1 = pload1(a+1); + * a2 = pload1(a+2); + * a3 = pload1(a+3); + * \endcode + * \sa pset1, pload1, ploaddup, pbroadcast2 + */ +template EIGEN_DEVICE_FUNC +inline void pbroadcast4(const typename unpacket_traits::type *a, + Packet& a0, Packet& a1, Packet& a2, Packet& a3) +{ + a0 = pload1(a+0); + a1 = pload1(a+1); + a2 = pload1(a+2); + a3 = pload1(a+3); +} + +/** \internal equivalent to + * \code + * a0 = pload1(a+0); + * a1 = pload1(a+1); + * \endcode + * \sa pset1, pload1, ploaddup, pbroadcast4 + */ +template EIGEN_DEVICE_FUNC +inline void pbroadcast2(const typename unpacket_traits::type *a, + Packet& a0, Packet& a1) +{ + a0 = pload1(a+0); + a1 = pload1(a+1); +} /** \internal \brief Returns a packet with coefficients (a,a+1,...,a+packet_size-1). */ -template inline typename packet_traits::type -plset(const Scalar& a) { return a; } +template inline Packet +plset(const typename unpacket_traits::type& a) { return a; } /** \internal copy the packet \a from to \a *to, \a to must be 16 bytes aligned */ -template inline void pstore(Scalar* to, const Packet& from) +template EIGEN_DEVICE_FUNC inline void pstore(Scalar* to, const Packet& from) { (*to) = from; } /** \internal copy the packet \a from to \a *to, (un-aligned store) */ -template inline void pstoreu(Scalar* to, const Packet& from) -{ (*to) = from; } +template EIGEN_DEVICE_FUNC inline void pstoreu(Scalar* to, const Packet& from) +{ (*to) = from; } + + template EIGEN_DEVICE_FUNC inline Packet pgather(const Scalar* from, Index /*stride*/) + { return ploadu(from); } + + template EIGEN_DEVICE_FUNC inline void pscatter(Scalar* to, const Packet& from, Index /*stride*/) + { pstore(to, from); } /** \internal tries to do cache prefetching of \a addr */ -template inline void prefetch(const Scalar* addr) +template EIGEN_DEVICE_FUNC inline void prefetch(const Scalar* addr) { -#if !defined(_MSC_VER) -__builtin_prefetch(addr); +#ifdef __CUDA_ARCH__ +#if defined(__LP64__) + // 64-bit pointer operand constraint for inlined asm + asm(" prefetch.L1 [ %1 ];" : "=l"(addr) : "l"(addr)); +#else + // 32-bit pointer operand constraint for inlined asm + asm(" prefetch.L1 [ %1 ];" : "=r"(addr) : "r"(addr)); +#endif +#elif (!EIGEN_COMP_MSVC) && (EIGEN_COMP_GNUC || EIGEN_COMP_CLANG || EIGEN_COMP_ICC) + __builtin_prefetch(addr); #endif } /** \internal \returns the first element of a packet */ -template inline typename unpacket_traits::type pfirst(const Packet& a) +template EIGEN_DEVICE_FUNC inline typename unpacket_traits::type pfirst(const Packet& a) { return a; } /** \internal \returns a packet where the element i contains the sum of the packet of \a vec[i] */ -template inline Packet +template EIGEN_DEVICE_FUNC inline Packet preduxp(const Packet* vecs) { return vecs[0]; } /** \internal \returns the sum of the elements of \a a*/ -template inline typename unpacket_traits::type predux(const Packet& a) +template EIGEN_DEVICE_FUNC inline typename unpacket_traits::type predux(const Packet& a) +{ return a; } + +/** \internal \returns the sum of the elements of \a a by block of 4 elements. + * For a packet {a0, a1, a2, a3, a4, a5, a6, a7}, it returns a half packet {a0+a4, a1+a5, a2+a6, a3+a7} + * For packet-size smaller or equal to 4, this boils down to a noop. + */ +template EIGEN_DEVICE_FUNC inline +typename conditional<(unpacket_traits::size%8)==0,typename unpacket_traits::half,Packet>::type +predux_downto4(const Packet& a) { return a; } /** \internal \returns the product of the elements of \a a*/ -template inline typename unpacket_traits::type predux_mul(const Packet& a) +template EIGEN_DEVICE_FUNC inline typename unpacket_traits::type predux_mul(const Packet& a) { return a; } /** \internal \returns the min of the elements of \a a*/ -template inline typename unpacket_traits::type predux_min(const Packet& a) +template EIGEN_DEVICE_FUNC inline typename unpacket_traits::type predux_min(const Packet& a) { return a; } /** \internal \returns the max of the elements of \a a*/ -template inline typename unpacket_traits::type predux_max(const Packet& a) +template EIGEN_DEVICE_FUNC inline typename unpacket_traits::type predux_max(const Packet& a) { return a; } /** \internal \returns the reversed elements of \a a*/ -template inline Packet preverse(const Packet& a) +template EIGEN_DEVICE_FUNC inline Packet preverse(const Packet& a) { return a; } - /** \internal \returns \a a with real and imaginary part flipped (for complex type only) */ -template inline Packet pcplxflip(const Packet& a) +template EIGEN_DEVICE_FUNC inline Packet pcplxflip(const Packet& a) { // FIXME: uncomment the following in case we drop the internal imag and real functions. // using std::imag; @@ -250,6 +381,22 @@ Packet pasin(const Packet& a) { using std::asin; return asin(a); } template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet pacos(const Packet& a) { using std::acos; return acos(a); } +/** \internal \returns the arc tangent of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet patan(const Packet& a) { using std::atan; return atan(a); } + +/** \internal \returns the hyperbolic sine of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet psinh(const Packet& a) { using std::sinh; return sinh(a); } + +/** \internal \returns the hyperbolic cosine of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet pcosh(const Packet& a) { using std::cosh; return cosh(a); } + +/** \internal \returns the hyperbolic tan of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet ptanh(const Packet& a) { using std::tanh; return tanh(a); } + /** \internal \returns the exp of \a a (coeff-wise) */ template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet pexp(const Packet& a) { using std::exp; return exp(a); } @@ -258,10 +405,36 @@ Packet pexp(const Packet& a) { using std::exp; return exp(a); } template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet plog(const Packet& a) { using std::log; return log(a); } +/** \internal \returns the log1p of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet plog1p(const Packet& a) { return numext::log1p(a); } + +/** \internal \returns the log10 of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet plog10(const Packet& a) { using std::log10; return log10(a); } + /** \internal \returns the square-root of \a a (coeff-wise) */ template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet psqrt(const Packet& a) { using std::sqrt; return sqrt(a); } +/** \internal \returns the reciprocal square-root of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet prsqrt(const Packet& a) { + return pdiv(pset1(1), psqrt(a)); +} + +/** \internal \returns the rounded value of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet pround(const Packet& a) { using numext::round; return round(a); } + +/** \internal \returns the floor of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet pfloor(const Packet& a) { using numext::floor; return floor(a); } + +/** \internal \returns the ceil of \a a (coeff-wise) */ +template EIGEN_DECLARE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS +Packet pceil(const Packet& a) { using numext::ceil; return ceil(a); } + /*************************************************************************** * The following functions might not have to be overwritten for vectorized types ***************************************************************************/ @@ -275,34 +448,45 @@ inline void pstore1(typename unpacket_traits::type* to, const typename u } /** \internal \returns a * b + c (coeff-wise) */ -template inline Packet +template EIGEN_DEVICE_FUNC inline Packet pmadd(const Packet& a, const Packet& b, const Packet& c) { return padd(pmul(a, b),c); } /** \internal \returns a packet version of \a *from. - * If LoadMode equals #Aligned, \a from must be 16 bytes aligned */ -template -inline Packet ploadt(const typename unpacket_traits::type* from) + * The pointer \a from must be aligned on a \a Alignment bytes boundary. */ +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE Packet ploadt(const typename unpacket_traits::type* from) { - if(LoadMode == Aligned) + if(Alignment >= unpacket_traits::alignment) return pload(from); else return ploadu(from); } /** \internal copy the packet \a from to \a *to. - * If StoreMode equals #Aligned, \a to must be 16 bytes aligned */ -template -inline void pstoret(Scalar* to, const Packet& from) + * The pointer \a from must be aligned on a \a Alignment bytes boundary. */ +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE void pstoret(Scalar* to, const Packet& from) { - if(LoadMode == Aligned) + if(Alignment >= unpacket_traits::alignment) pstore(to, from); else pstoreu(to, from); } +/** \internal \returns a packet version of \a *from. + * Unlike ploadt, ploadt_ro takes advantage of the read-only memory path on the + * hardware if available to speedup the loading of data that won't be modified + * by the current computation. + */ +template +inline Packet ploadt_ro(const typename unpacket_traits::type* from) +{ + return ploadt(from); +} + /** \internal default implementation of palign() allowing partial specialization */ template struct palign_impl @@ -336,15 +520,74 @@ inline void palign(PacketType& first, const PacketType& second) * Fast complex products (GCC generates a function call which is very slow) ***************************************************************************/ +// Eigen+CUDA does not support complexes. +#ifndef __CUDACC__ + template<> inline std::complex pmul(const std::complex& a, const std::complex& b) { return std::complex(real(a)*real(b) - imag(a)*imag(b), imag(a)*real(b) + real(a)*imag(b)); } template<> inline std::complex pmul(const std::complex& a, const std::complex& b) { return std::complex(real(a)*real(b) - imag(a)*imag(b), imag(a)*real(b) + real(a)*imag(b)); } +#endif + + +/*************************************************************************** + * PacketBlock, that is a collection of N packets where the number of words + * in the packet is a multiple of N. +***************************************************************************/ +template ::size> struct PacketBlock { + Packet packet[N]; +}; + +template EIGEN_DEVICE_FUNC inline void +ptranspose(PacketBlock& /*kernel*/) { + // Nothing to do in the scalar case, i.e. a 1x1 matrix. +} + +/*************************************************************************** + * Selector, i.e. vector of N boolean values used to select (i.e. blend) + * words from 2 packets. +***************************************************************************/ +template struct Selector { + bool select[N]; +}; + +template EIGEN_DEVICE_FUNC inline Packet +pblend(const Selector::size>& ifPacket, const Packet& thenPacket, const Packet& elsePacket) { + return ifPacket.select[0] ? thenPacket : elsePacket; +} + +/** \internal \returns \a a with the first coefficient replaced by the scalar b */ +template EIGEN_DEVICE_FUNC inline Packet +pinsertfirst(const Packet& a, typename unpacket_traits::type b) +{ + // Default implementation based on pblend. + // It must be specialized for higher performance. + Selector::size> mask; + mask.select[0] = true; + // This for loop should be optimized away by the compiler. + for(Index i=1; i::size; ++i) + mask.select[i] = false; + return pblend(mask, pset1(b), a); +} + +/** \internal \returns \a a with the last coefficient replaced by the scalar b */ +template EIGEN_DEVICE_FUNC inline Packet +pinsertlast(const Packet& a, typename unpacket_traits::type b) +{ + // Default implementation based on pblend. + // It must be specialized for higher performance. + Selector::size> mask; + // This for loop should be optimized away by the compiler. + for(Index i=0; i::size-1; ++i) + mask.select[i] = false; + mask.select[unpacket_traits::size-1] = true; + return pblend(mask, pset1(b), a); +} + } // end namespace internal } // end namespace Eigen #endif // EIGEN_GENERIC_PACKET_MATH_H - diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Core/GlobalFunctions.h b/ground/gcs/src/libs/eigen/Eigen/src/Core/GlobalFunctions.h index 2acf977233..769dc255c2 100644 --- a/ground/gcs/src/libs/eigen/Eigen/src/Core/GlobalFunctions.h +++ b/ground/gcs/src/libs/eigen/Eigen/src/Core/GlobalFunctions.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2010-2012 Gael Guennebaud +// Copyright (C) 2010-2016 Gael Guennebaud // Copyright (C) 2010 Benoit Jacob // // This Source Code Form is subject to the terms of the Mozilla @@ -11,13 +11,30 @@ #ifndef EIGEN_GLOBAL_FUNCTIONS_H #define EIGEN_GLOBAL_FUNCTIONS_H -#define EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(NAME,FUNCTOR) \ +#ifdef EIGEN_PARSED_BY_DOXYGEN + +#define EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(NAME,FUNCTOR,DOC_OP,DOC_DETAILS) \ + /** \returns an expression of the coefficient-wise DOC_OP of \a x + + DOC_DETAILS + + \sa Math functions, class CwiseUnaryOp + */ \ + template \ + inline const Eigen::CwiseUnaryOp, const Derived> \ + NAME(const Eigen::ArrayBase& x); + +#else + +#define EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(NAME,FUNCTOR,DOC_OP,DOC_DETAILS) \ template \ inline const Eigen::CwiseUnaryOp, const Derived> \ - NAME(const Eigen::ArrayBase& x) { \ - return x.derived(); \ + (NAME)(const Eigen::ArrayBase& x) { \ + return Eigen::CwiseUnaryOp, const Derived>(x.derived()); \ } +#endif // EIGEN_PARSED_BY_DOXYGEN + #define EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(NAME,FUNCTOR) \ \ template \ @@ -30,55 +47,133 @@ { \ static inline typename NAME##_retval >::type run(const Eigen::ArrayBase& x) \ { \ - return x.derived(); \ + return typename NAME##_retval >::type(x.derived()); \ } \ }; - namespace Eigen { - EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(real,scalar_real_op) - EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(imag,scalar_imag_op) - EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(conj,scalar_conjugate_op) - EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(sin,scalar_sin_op) - EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(cos,scalar_cos_op) - EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(asin,scalar_asin_op) - EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(acos,scalar_acos_op) - EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(tan,scalar_tan_op) - EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(exp,scalar_exp_op) - EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(log,scalar_log_op) - EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(abs,scalar_abs_op) - EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(sqrt,scalar_sqrt_op) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(real,scalar_real_op,real part,\sa ArrayBase::real) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(imag,scalar_imag_op,imaginary part,\sa ArrayBase::imag) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(conj,scalar_conjugate_op,complex conjugate,\sa ArrayBase::conjugate) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(inverse,scalar_inverse_op,inverse,\sa ArrayBase::inverse) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(sin,scalar_sin_op,sine,\sa ArrayBase::sin) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(cos,scalar_cos_op,cosine,\sa ArrayBase::cos) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(tan,scalar_tan_op,tangent,\sa ArrayBase::tan) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(atan,scalar_atan_op,arc-tangent,\sa ArrayBase::atan) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(asin,scalar_asin_op,arc-sine,\sa ArrayBase::asin) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(acos,scalar_acos_op,arc-consine,\sa ArrayBase::acos) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(sinh,scalar_sinh_op,hyperbolic sine,\sa ArrayBase::sinh) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(cosh,scalar_cosh_op,hyperbolic cosine,\sa ArrayBase::cosh) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(tanh,scalar_tanh_op,hyperbolic tangent,\sa ArrayBase::tanh) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(lgamma,scalar_lgamma_op,natural logarithm of the gamma function,\sa ArrayBase::lgamma) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(digamma,scalar_digamma_op,derivative of lgamma,\sa ArrayBase::digamma) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(erf,scalar_erf_op,error function,\sa ArrayBase::erf) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(erfc,scalar_erfc_op,complement error function,\sa ArrayBase::erfc) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(exp,scalar_exp_op,exponential,\sa ArrayBase::exp) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(log,scalar_log_op,natural logarithm,\sa Eigen::log10 DOXCOMMA ArrayBase::log) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(log1p,scalar_log1p_op,natural logarithm of 1 plus the value,\sa ArrayBase::log1p) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(log10,scalar_log10_op,base 10 logarithm,\sa Eigen::log DOXCOMMA ArrayBase::log) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(abs,scalar_abs_op,absolute value,\sa ArrayBase::abs DOXCOMMA MatrixBase::cwiseAbs) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(abs2,scalar_abs2_op,squared absolute value,\sa ArrayBase::abs2 DOXCOMMA MatrixBase::cwiseAbs2) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(arg,scalar_arg_op,complex argument,\sa ArrayBase::arg) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(sqrt,scalar_sqrt_op,square root,\sa ArrayBase::sqrt DOXCOMMA MatrixBase::cwiseSqrt) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(rsqrt,scalar_rsqrt_op,reciprocal square root,\sa ArrayBase::rsqrt) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(square,scalar_square_op,square (power 2),\sa Eigen::abs2 DOXCOMMA Eigen::pow DOXCOMMA ArrayBase::square) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(cube,scalar_cube_op,cube (power 3),\sa Eigen::pow DOXCOMMA ArrayBase::cube) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(round,scalar_round_op,nearest integer,\sa Eigen::floor DOXCOMMA Eigen::ceil DOXCOMMA ArrayBase::round) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(floor,scalar_floor_op,nearest integer not greater than the giben value,\sa Eigen::ceil DOXCOMMA ArrayBase::floor) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(ceil,scalar_ceil_op,nearest integer not less than the giben value,\sa Eigen::floor DOXCOMMA ArrayBase::ceil) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(isnan,scalar_isnan_op,not-a-number test,\sa Eigen::isinf DOXCOMMA Eigen::isfinite DOXCOMMA ArrayBase::isnan) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(isinf,scalar_isinf_op,infinite value test,\sa Eigen::isnan DOXCOMMA Eigen::isfinite DOXCOMMA ArrayBase::isinf) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(isfinite,scalar_isfinite_op,finite value test,\sa Eigen::isinf DOXCOMMA Eigen::isnan DOXCOMMA ArrayBase::isfinite) + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY(sign,scalar_sign_op,sign (or 0),\sa ArrayBase::sign) + /** \returns an expression of the coefficient-wise power of \a x to the given constant \a exponent. + * + * \tparam ScalarExponent is the scalar type of \a exponent. It must be compatible with the scalar type of the given expression (\c Derived::Scalar). + * + * \sa ArrayBase::pow() + * + * \relates ArrayBase + */ +#ifdef EIGEN_PARSED_BY_DOXYGEN + template + inline const CwiseBinaryOp,Derived,Constant > + pow(const Eigen::ArrayBase& x, const ScalarExponent& exponent); +#else + template + inline typename internal::enable_if< !(internal::is_same::value) && EIGEN_SCALAR_BINARY_SUPPORTED(pow,typename Derived::Scalar,ScalarExponent), + const EIGEN_EXPR_BINARYOP_SCALAR_RETURN_TYPE(Derived,ScalarExponent,pow) >::type + pow(const Eigen::ArrayBase& x, const ScalarExponent& exponent) { + return x.derived().pow(exponent); + } + template - inline const Eigen::CwiseUnaryOp, const Derived> + inline const EIGEN_EXPR_BINARYOP_SCALAR_RETURN_TYPE(Derived,typename Derived::Scalar,pow) pow(const Eigen::ArrayBase& x, const typename Derived::Scalar& exponent) { return x.derived().pow(exponent); } +#endif - template - inline const Eigen::CwiseBinaryOp, const Derived, const Derived> - pow(const Eigen::ArrayBase& x, const Eigen::ArrayBase& exponents) + /** \returns an expression of the coefficient-wise power of \a x to the given array of \a exponents. + * + * This function computes the coefficient-wise power. + * + * Example: \include Cwise_array_power_array.cpp + * Output: \verbinclude Cwise_array_power_array.out + * + * \sa ArrayBase::pow() + * + * \relates ArrayBase + */ + template + inline const Eigen::CwiseBinaryOp, const Derived, const ExponentDerived> + pow(const Eigen::ArrayBase& x, const Eigen::ArrayBase& exponents) { - return Eigen::CwiseBinaryOp, const Derived, const Derived>( + return Eigen::CwiseBinaryOp, const Derived, const ExponentDerived>( x.derived(), exponents.derived() ); } - /** - * \brief Component-wise division of a scalar by array elements. - **/ - template - inline const Eigen::CwiseUnaryOp, const Derived> - operator/(const typename Derived::Scalar& s, const Eigen::ArrayBase& a) + /** \returns an expression of the coefficient-wise power of the scalar \a x to the given array of \a exponents. + * + * This function computes the coefficient-wise power between a scalar and an array of exponents. + * + * \tparam Scalar is the scalar type of \a x. It must be compatible with the scalar type of the given array expression (\c Derived::Scalar). + * + * Example: \include Cwise_scalar_power_array.cpp + * Output: \verbinclude Cwise_scalar_power_array.out + * + * \sa ArrayBase::pow() + * + * \relates ArrayBase + */ +#ifdef EIGEN_PARSED_BY_DOXYGEN + template + inline const CwiseBinaryOp,Constant,Derived> + pow(const Scalar& x,const Eigen::ArrayBase& x); +#else + template + inline typename internal::enable_if< !(internal::is_same::value) && EIGEN_SCALAR_BINARY_SUPPORTED(pow,Scalar,typename Derived::Scalar), + const EIGEN_SCALAR_BINARYOP_EXPR_RETURN_TYPE(Scalar,Derived,pow) >::type + pow(const Scalar& x, const Eigen::ArrayBase& exponents) { - return Eigen::CwiseUnaryOp, const Derived>( - a.derived(), - Eigen::internal::scalar_inverse_mult_op(s) - ); + return EIGEN_SCALAR_BINARYOP_EXPR_RETURN_TYPE(Scalar,Derived,pow)( + typename internal::plain_constant_type::type(exponents.rows(), exponents.cols(), x), exponents.derived() ); } + template + inline const EIGEN_SCALAR_BINARYOP_EXPR_RETURN_TYPE(typename Derived::Scalar,Derived,pow) + pow(const typename Derived::Scalar& x, const Eigen::ArrayBase& exponents) + { + return EIGEN_SCALAR_BINARYOP_EXPR_RETURN_TYPE(typename Derived::Scalar,Derived,pow)( + typename internal::plain_constant_type::type(exponents.rows(), exponents.cols(), x), exponents.derived() ); + } +#endif + + namespace internal { EIGEN_ARRAY_DECLARE_GLOBAL_EIGEN_UNARY(real,scalar_real_op) diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Core/IO.h b/ground/gcs/src/libs/eigen/Eigen/src/Core/IO.h index 8d4bc59e9d..da7fd6cce2 100644 --- a/ground/gcs/src/libs/eigen/Eigen/src/Core/IO.h +++ b/ground/gcs/src/libs/eigen/Eigen/src/Core/IO.h @@ -49,7 +49,7 @@ std::ostream & print_matrix(std::ostream & s, const Derived& _m, const IOFormat& */ struct IOFormat { - /** Default contructor, see class IOFormat for the meaning of the parameters */ + /** Default constructor, see class IOFormat for the meaning of the parameters */ IOFormat(int _precision = StreamPrecision, int _flags = 0, const std::string& _coeffSeparator = " ", const std::string& _rowSeparator = "\n", const std::string& _rowPrefix="", const std::string& _rowSuffix="", @@ -57,6 +57,10 @@ struct IOFormat : matPrefix(_matPrefix), matSuffix(_matSuffix), rowPrefix(_rowPrefix), rowSuffix(_rowSuffix), rowSeparator(_rowSeparator), rowSpacer(""), coeffSeparator(_coeffSeparator), precision(_precision), flags(_flags) { + // TODO check if rowPrefix, rowSuffix or rowSeparator contains a newline + // don't add rowSpacer if columns are not to be aligned + if((flags & DontAlignCols)) + return; int i = int(matSuffix.length())-1; while (i>=0 && matSuffix[i]!='\n') { @@ -76,7 +80,7 @@ struct IOFormat * * \brief Pseudo expression providing matrix output with given format * - * \param ExpressionType the type of the object on which IO stream operations are performed + * \tparam ExpressionType the type of the object on which IO stream operations are performed * * This class represents an expression with stream operators controlled by a given IOFormat. * It is the return type of DenseBase::format() @@ -101,52 +105,24 @@ class WithFormat } protected: - const typename ExpressionType::Nested m_matrix; + typename ExpressionType::Nested m_matrix; IOFormat m_format; }; -/** \returns a WithFormat proxy object allowing to print a matrix the with given - * format \a fmt. - * - * See class IOFormat for some examples. - * - * \sa class IOFormat, class WithFormat - */ -template -inline const WithFormat -DenseBase::format(const IOFormat& fmt) const -{ - return WithFormat(derived(), fmt); -} - namespace internal { -template -struct significant_decimals_default_impl -{ - typedef typename NumTraits::Real RealScalar; - static inline int run() - { - using std::ceil; - using std::log; - return cast(ceil(-log(NumTraits::epsilon())/log(RealScalar(10)))); - } -}; - +// NOTE: This helper is kept for backward compatibility with previous code specializing +// this internal::significant_decimals_impl structure. In the future we should directly +// call digits10() which has been introduced in July 2016 in 3.3. template -struct significant_decimals_default_impl +struct significant_decimals_impl { static inline int run() { - return 0; + return NumTraits::digits10(); } }; -template -struct significant_decimals_impl - : significant_decimals_default_impl::IsInteger> -{}; - /** \internal * print the matrix \a _m to the output stream \a s using the output format \a fmt */ template @@ -160,7 +136,6 @@ std::ostream & print_matrix(std::ostream & s, const Derived& _m, const IOFormat& typename Derived::Nested m = _m; typedef typename Derived::Scalar Scalar; - typedef typename Derived::Index Index; Index width = 0; diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Core/Inverse.h b/ground/gcs/src/libs/eigen/Eigen/src/Core/Inverse.h new file mode 100644 index 0000000000..b76f0439d8 --- /dev/null +++ b/ground/gcs/src/libs/eigen/Eigen/src/Core/Inverse.h @@ -0,0 +1,118 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_INVERSE_H +#define EIGEN_INVERSE_H + +namespace Eigen { + +template class InverseImpl; + +namespace internal { + +template +struct traits > + : traits +{ + typedef typename XprType::PlainObject PlainObject; + typedef traits BaseTraits; + enum { + Flags = BaseTraits::Flags & RowMajorBit + }; +}; + +} // end namespace internal + +/** \class Inverse + * + * \brief Expression of the inverse of another expression + * + * \tparam XprType the type of the expression we are taking the inverse + * + * This class represents an abstract expression of A.inverse() + * and most of the time this is the only way it is used. + * + */ +template +class Inverse : public InverseImpl::StorageKind> +{ +public: + typedef typename XprType::StorageIndex StorageIndex; + typedef typename XprType::PlainObject PlainObject; + typedef typename XprType::Scalar Scalar; + typedef typename internal::ref_selector::type XprTypeNested; + typedef typename internal::remove_all::type XprTypeNestedCleaned; + typedef typename internal::ref_selector::type Nested; + typedef typename internal::remove_all::type NestedExpression; + + explicit EIGEN_DEVICE_FUNC Inverse(const XprType &xpr) + : m_xpr(xpr) + {} + + EIGEN_DEVICE_FUNC Index rows() const { return m_xpr.rows(); } + EIGEN_DEVICE_FUNC Index cols() const { return m_xpr.cols(); } + + EIGEN_DEVICE_FUNC const XprTypeNestedCleaned& nestedExpression() const { return m_xpr; } + +protected: + XprTypeNested m_xpr; +}; + +// Generic API dispatcher +template +class InverseImpl + : public internal::generic_xpr_base >::type +{ +public: + typedef typename internal::generic_xpr_base >::type Base; + typedef typename XprType::Scalar Scalar; +private: + + Scalar coeff(Index row, Index col) const; + Scalar coeff(Index i) const; +}; + +namespace internal { + +/** \internal + * \brief Default evaluator for Inverse expression. + * + * This default evaluator for Inverse expression simply evaluate the inverse into a temporary + * by a call to internal::call_assignment_no_alias. + * Therefore, inverse implementers only have to specialize Assignment, ...> for + * there own nested expression. + * + * \sa class Inverse + */ +template +struct unary_evaluator > + : public evaluator::PlainObject> +{ + typedef Inverse InverseType; + typedef typename InverseType::PlainObject PlainObject; + typedef evaluator Base; + + enum { Flags = Base::Flags | EvalBeforeNestingBit }; + + unary_evaluator(const InverseType& inv_xpr) + : m_result(inv_xpr.rows(), inv_xpr.cols()) + { + ::new (static_cast(this)) Base(m_result); + internal::call_assignment_no_alias(m_result, inv_xpr); + } + +protected: + PlainObject m_result; +}; + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_INVERSE_H diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Core/Map.h b/ground/gcs/src/libs/eigen/Eigen/src/Core/Map.h index f804c89d63..06d1967024 100644 --- a/ground/gcs/src/libs/eigen/Eigen/src/Core/Map.h +++ b/ground/gcs/src/libs/eigen/Eigen/src/Core/Map.h @@ -13,13 +13,35 @@ namespace Eigen { +namespace internal { +template +struct traits > + : public traits +{ + typedef traits TraitsBase; + enum { + InnerStrideAtCompileTime = StrideType::InnerStrideAtCompileTime == 0 + ? int(PlainObjectType::InnerStrideAtCompileTime) + : int(StrideType::InnerStrideAtCompileTime), + OuterStrideAtCompileTime = StrideType::OuterStrideAtCompileTime == 0 + ? int(PlainObjectType::OuterStrideAtCompileTime) + : int(StrideType::OuterStrideAtCompileTime), + Alignment = int(MapOptions)&int(AlignedMask), + Flags0 = TraitsBase::Flags & (~NestByRefBit), + Flags = is_lvalue::value ? int(Flags0) : (int(Flags0) & ~LvalueBit) + }; +private: + enum { Options }; // Expressions don't have Options +}; +} + /** \class Map * \ingroup Core_Module * * \brief A matrix or vector expression mapping an existing array of data. * * \tparam PlainObjectType the equivalent matrix type of the mapped data - * \tparam MapOptions specifies whether the pointer is \c #Aligned, or \c #Unaligned. + * \tparam MapOptions specifies the pointer alignment in bytes. It can be: \c #Aligned128, , \c #Aligned64, \c #Aligned32, \c #Aligned16, \c #Aligned8 or \c #Unaligned. * The default is \c #Unaligned. * \tparam StrideType optionally specifies strides. By default, Map assumes the memory layout * of an ordinary, contiguous array. This can be overridden by specifying strides. @@ -63,44 +85,6 @@ namespace Eigen { * * \sa PlainObjectBase::Map(), \ref TopicStorageOrders */ - -namespace internal { -template -struct traits > - : public traits -{ - typedef traits TraitsBase; - typedef typename PlainObjectType::Index Index; - typedef typename PlainObjectType::Scalar Scalar; - enum { - InnerStrideAtCompileTime = StrideType::InnerStrideAtCompileTime == 0 - ? int(PlainObjectType::InnerStrideAtCompileTime) - : int(StrideType::InnerStrideAtCompileTime), - OuterStrideAtCompileTime = StrideType::OuterStrideAtCompileTime == 0 - ? int(PlainObjectType::OuterStrideAtCompileTime) - : int(StrideType::OuterStrideAtCompileTime), - HasNoInnerStride = InnerStrideAtCompileTime == 1, - HasNoOuterStride = StrideType::OuterStrideAtCompileTime == 0, - HasNoStride = HasNoInnerStride && HasNoOuterStride, - IsAligned = bool(EIGEN_ALIGN) && ((int(MapOptions)&Aligned)==Aligned), - IsDynamicSize = PlainObjectType::SizeAtCompileTime==Dynamic, - KeepsPacketAccess = bool(HasNoInnerStride) - && ( bool(IsDynamicSize) - || HasNoOuterStride - || ( OuterStrideAtCompileTime!=Dynamic - && ((static_cast(sizeof(Scalar))*OuterStrideAtCompileTime)%16)==0 ) ), - Flags0 = TraitsBase::Flags & (~NestByRefBit), - Flags1 = IsAligned ? (int(Flags0) | AlignedBit) : (int(Flags0) & ~AlignedBit), - Flags2 = (bool(HasNoStride) || bool(PlainObjectType::IsVectorAtCompileTime)) - ? int(Flags1) : int(Flags1 & ~LinearAccessBit), - Flags3 = is_lvalue::value ? int(Flags2) : (int(Flags2) & ~LvalueBit), - Flags = KeepsPacketAccess ? int(Flags3) : (int(Flags3) & ~PacketAccessBit) - }; -private: - enum { Options }; // Expressions don't have Options -}; -} - template class Map : public MapBase > { @@ -110,19 +94,17 @@ template class Ma EIGEN_DENSE_PUBLIC_INTERFACE(Map) typedef typename Base::PointerType PointerType; -#if EIGEN2_SUPPORT_STAGE <= STAGE30_FULL_EIGEN3_API - typedef const Scalar* PointerArgType; - inline PointerType cast_to_pointer_type(PointerArgType ptr) { return const_cast(ptr); } -#else typedef PointerType PointerArgType; + EIGEN_DEVICE_FUNC inline PointerType cast_to_pointer_type(PointerArgType ptr) { return ptr; } -#endif + EIGEN_DEVICE_FUNC inline Index innerStride() const { return StrideType::InnerStrideAtCompileTime != 0 ? m_stride.inner() : 1; } + EIGEN_DEVICE_FUNC inline Index outerStride() const { return StrideType::OuterStrideAtCompileTime != 0 ? m_stride.outer() @@ -134,10 +116,11 @@ template class Ma /** Constructor in the fixed-size case. * * \param dataPtr pointer to the array to map - * \param a_stride optional Stride object, passing the strides. + * \param stride optional Stride object, passing the strides. */ - inline Map(PointerArgType dataPtr, const StrideType& a_stride = StrideType()) - : Base(cast_to_pointer_type(dataPtr)), m_stride(a_stride) + EIGEN_DEVICE_FUNC + explicit inline Map(PointerArgType dataPtr, const StrideType& stride = StrideType()) + : Base(cast_to_pointer_type(dataPtr)), m_stride(stride) { PlainObjectType::Base::_check_template_params(); } @@ -145,11 +128,12 @@ template class Ma /** Constructor in the dynamic-size vector case. * * \param dataPtr pointer to the array to map - * \param a_size the size of the vector expression - * \param a_stride optional Stride object, passing the strides. + * \param size the size of the vector expression + * \param stride optional Stride object, passing the strides. */ - inline Map(PointerArgType dataPtr, Index a_size, const StrideType& a_stride = StrideType()) - : Base(cast_to_pointer_type(dataPtr), a_size), m_stride(a_stride) + EIGEN_DEVICE_FUNC + inline Map(PointerArgType dataPtr, Index size, const StrideType& stride = StrideType()) + : Base(cast_to_pointer_type(dataPtr), size), m_stride(stride) { PlainObjectType::Base::_check_template_params(); } @@ -157,12 +141,13 @@ template class Ma /** Constructor in the dynamic-size matrix case. * * \param dataPtr pointer to the array to map - * \param nbRows the number of rows of the matrix expression - * \param nbCols the number of columns of the matrix expression - * \param a_stride optional Stride object, passing the strides. + * \param rows the number of rows of the matrix expression + * \param cols the number of columns of the matrix expression + * \param stride optional Stride object, passing the strides. */ - inline Map(PointerArgType dataPtr, Index nbRows, Index nbCols, const StrideType& a_stride = StrideType()) - : Base(cast_to_pointer_type(dataPtr), nbRows, nbCols), m_stride(a_stride) + EIGEN_DEVICE_FUNC + inline Map(PointerArgType dataPtr, Index rows, Index cols, const StrideType& stride = StrideType()) + : Base(cast_to_pointer_type(dataPtr), rows, cols), m_stride(stride) { PlainObjectType::Base::_check_template_params(); } @@ -173,19 +158,6 @@ template class Ma StrideType m_stride; }; -template -inline Array<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> - ::Array(const Scalar *data) -{ - this->_set_noalias(Eigen::Map(data)); -} - -template -inline Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> - ::Matrix(const Scalar *data) -{ - this->_set_noalias(Eigen::Map(data)); -} } // end namespace Eigen diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Core/MapBase.h b/ground/gcs/src/libs/eigen/Eigen/src/Core/MapBase.h index 81efc4a6d5..020f939ad6 100644 --- a/ground/gcs/src/libs/eigen/Eigen/src/Core/MapBase.h +++ b/ground/gcs/src/libs/eigen/Eigen/src/Core/MapBase.h @@ -12,15 +12,25 @@ #define EIGEN_MAPBASE_H #define EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS(Derived) \ - EIGEN_STATIC_ASSERT((int(internal::traits::Flags) & LinearAccessBit) || Derived::IsVectorAtCompileTime, \ + EIGEN_STATIC_ASSERT((int(internal::evaluator::Flags) & LinearAccessBit) || Derived::IsVectorAtCompileTime, \ YOU_ARE_TRYING_TO_USE_AN_INDEX_BASED_ACCESSOR_ON_AN_EXPRESSION_THAT_DOES_NOT_SUPPORT_THAT) namespace Eigen { -/** \class MapBase - * \ingroup Core_Module +/** \ingroup Core_Module * - * \brief Base class for Map and Block expression with direct access + * \brief Base class for dense Map and Block expression with direct access + * + * This base class provides the const low-level accessors (e.g. coeff, coeffRef) of dense + * Map and Block objects with direct access. + * Typical users do not have to directly deal with this class. + * + * This class can be extended by through the macro plugin \c EIGEN_MAPBASE_PLUGIN. + * See \link TopicCustomizing_Plugins customizing Eigen \endlink for details. + * + * The \c Derived class has to provide the following two methods describing the memory layout: + * \code Index innerStride() const; \endcode + * \code Index outerStride() const; \endcode * * \sa class Map, class Block */ @@ -37,7 +47,6 @@ template class MapBase }; typedef typename internal::traits::StorageKind StorageKind; - typedef typename internal::traits::Index Index; typedef typename internal::traits::Scalar Scalar; typedef typename internal::packet_traits::type PacketScalar; typedef typename NumTraits::Real RealScalar; @@ -76,8 +85,10 @@ template class MapBase typedef typename Base::CoeffReturnType CoeffReturnType; - inline Index rows() const { return m_rows.value(); } - inline Index cols() const { return m_cols.value(); } + /** \copydoc DenseBase::rows() */ + EIGEN_DEVICE_FUNC inline Index rows() const { return m_rows.value(); } + /** \copydoc DenseBase::cols() */ + EIGEN_DEVICE_FUNC inline Index cols() const { return m_cols.value(); } /** Returns a pointer to the first coefficient of the matrix or vector. * @@ -85,30 +96,39 @@ template class MapBase * * \sa innerStride(), outerStride() */ - inline const Scalar* data() const { return m_data; } + EIGEN_DEVICE_FUNC inline const Scalar* data() const { return m_data; } + /** \copydoc PlainObjectBase::coeff(Index,Index) const */ + EIGEN_DEVICE_FUNC inline const Scalar& coeff(Index rowId, Index colId) const { return m_data[colId * colStride() + rowId * rowStride()]; } + /** \copydoc PlainObjectBase::coeff(Index) const */ + EIGEN_DEVICE_FUNC inline const Scalar& coeff(Index index) const { EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS(Derived) return m_data[index * innerStride()]; } + /** \copydoc PlainObjectBase::coeffRef(Index,Index) const */ + EIGEN_DEVICE_FUNC inline const Scalar& coeffRef(Index rowId, Index colId) const { return this->m_data[colId * colStride() + rowId * rowStride()]; } + /** \copydoc PlainObjectBase::coeffRef(Index) const */ + EIGEN_DEVICE_FUNC inline const Scalar& coeffRef(Index index) const { EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS(Derived) return this->m_data[index * innerStride()]; } + /** \internal */ template inline PacketScalar packet(Index rowId, Index colId) const { @@ -116,6 +136,7 @@ template class MapBase (m_data + (colId * colStride() + rowId * rowStride())); } + /** \internal */ template inline PacketScalar packet(Index index) const { @@ -123,12 +144,16 @@ template class MapBase return internal::ploadt(m_data + index * innerStride()); } + /** \internal Constructor for fixed size matrices or vectors */ + EIGEN_DEVICE_FUNC explicit inline MapBase(PointerType dataPtr) : m_data(dataPtr), m_rows(RowsAtCompileTime), m_cols(ColsAtCompileTime) { EIGEN_STATIC_ASSERT_FIXED_SIZE(Derived) - checkSanity(); + checkSanity(); } + /** \internal Constructor for dynamically sized vectors */ + EIGEN_DEVICE_FUNC inline MapBase(PointerType dataPtr, Index vecSize) : m_data(dataPtr), m_rows(RowsAtCompileTime == Dynamic ? vecSize : Index(RowsAtCompileTime)), @@ -137,16 +162,18 @@ template class MapBase EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) eigen_assert(vecSize >= 0); eigen_assert(dataPtr == 0 || SizeAtCompileTime == Dynamic || SizeAtCompileTime == vecSize); - checkSanity(); + checkSanity(); } - inline MapBase(PointerType dataPtr, Index nbRows, Index nbCols) - : m_data(dataPtr), m_rows(nbRows), m_cols(nbCols) + /** \internal Constructor for dynamically sized matrices */ + EIGEN_DEVICE_FUNC + inline MapBase(PointerType dataPtr, Index rows, Index cols) + : m_data(dataPtr), m_rows(rows), m_cols(cols) { eigen_assert( (dataPtr == 0) - || ( nbRows >= 0 && (RowsAtCompileTime == Dynamic || RowsAtCompileTime == nbRows) - && nbCols >= 0 && (ColsAtCompileTime == Dynamic || ColsAtCompileTime == nbCols))); - checkSanity(); + || ( rows >= 0 && (RowsAtCompileTime == Dynamic || RowsAtCompileTime == rows) + && cols >= 0 && (ColsAtCompileTime == Dynamic || ColsAtCompileTime == cols))); + checkSanity(); } #ifdef EIGEN_MAPBASE_PLUGIN @@ -155,20 +182,36 @@ template class MapBase protected: - void checkSanity() const + template + EIGEN_DEVICE_FUNC + void checkSanity(typename internal::enable_if<(internal::traits::Alignment>0),void*>::type = 0) const { - EIGEN_STATIC_ASSERT(EIGEN_IMPLIES(internal::traits::Flags&PacketAccessBit, - internal::inner_stride_at_compile_time::ret==1), - PACKET_ACCESS_REQUIRES_TO_HAVE_INNER_STRIDE_FIXED_TO_1); - eigen_assert(EIGEN_IMPLIES(internal::traits::Flags&AlignedBit, (size_t(m_data) % 16) == 0) - && "input pointer is not aligned on a 16 byte boundary"); +#if EIGEN_MAX_ALIGN_BYTES>0 + eigen_assert(( ((internal::UIntPtr(m_data) % internal::traits::Alignment) == 0) + || (cols() * rows() * innerStride() * sizeof(Scalar)) < internal::traits::Alignment ) && "data is not aligned"); +#endif } + template + EIGEN_DEVICE_FUNC + void checkSanity(typename internal::enable_if::Alignment==0,void*>::type = 0) const + {} + PointerType m_data; const internal::variable_if_dynamic m_rows; const internal::variable_if_dynamic m_cols; }; +/** \ingroup Core_Module + * + * \brief Base class for non-const dense Map and Block expression with direct access + * + * This base class provides the non-const low-level accessors (e.g. coeff and coeffRef) of + * dense Map and Block objects with direct access. + * It inherits MapBase which defines the const variant for reading specific entries. + * + * \sa class Map, class Block + */ template class MapBase : public MapBase { @@ -179,7 +222,7 @@ template class MapBase typedef typename Base::Scalar Scalar; typedef typename Base::PacketScalar PacketScalar; - typedef typename Base::Index Index; + typedef typename Base::StorageIndex StorageIndex; typedef typename Base::PointerType PointerType; using Base::derived; @@ -200,14 +243,18 @@ template class MapBase const Scalar >::type ScalarWithConstIfNotLvalue; + EIGEN_DEVICE_FUNC inline const Scalar* data() const { return this->m_data; } + EIGEN_DEVICE_FUNC inline ScalarWithConstIfNotLvalue* data() { return this->m_data; } // no const-cast here so non-const-correct code will give a compile error + EIGEN_DEVICE_FUNC inline ScalarWithConstIfNotLvalue& coeffRef(Index row, Index col) { return this->m_data[col * colStride() + row * rowStride()]; } + EIGEN_DEVICE_FUNC inline ScalarWithConstIfNotLvalue& coeffRef(Index index) { EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS(Derived) @@ -229,10 +276,11 @@ template class MapBase (this->m_data + index * innerStride(), val); } - explicit inline MapBase(PointerType dataPtr) : Base(dataPtr) {} - inline MapBase(PointerType dataPtr, Index vecSize) : Base(dataPtr, vecSize) {} - inline MapBase(PointerType dataPtr, Index nbRows, Index nbCols) : Base(dataPtr, nbRows, nbCols) {} + EIGEN_DEVICE_FUNC explicit inline MapBase(PointerType dataPtr) : Base(dataPtr) {} + EIGEN_DEVICE_FUNC inline MapBase(PointerType dataPtr, Index vecSize) : Base(dataPtr, vecSize) {} + EIGEN_DEVICE_FUNC inline MapBase(PointerType dataPtr, Index rows, Index cols) : Base(dataPtr, rows, cols) {} + EIGEN_DEVICE_FUNC Derived& operator=(const MapBase& other) { ReadOnlyMapBase::Base::operator=(other); diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Core/MathFunctions.h b/ground/gcs/src/libs/eigen/Eigen/src/Core/MathFunctions.h index 4e17ecd4b4..8d47fb8a46 100644 --- a/ground/gcs/src/libs/eigen/Eigen/src/Core/MathFunctions.h +++ b/ground/gcs/src/libs/eigen/Eigen/src/Core/MathFunctions.h @@ -10,11 +10,25 @@ #ifndef EIGEN_MATHFUNCTIONS_H #define EIGEN_MATHFUNCTIONS_H +// source: http://www.geom.uiuc.edu/~huberty/math5337/groupe/digits.html +// TODO this should better be moved to NumTraits +#define EIGEN_PI 3.141592653589793238462643383279502884197169399375105820974944592307816406L + + namespace Eigen { +// On WINCE, std::abs is defined for int only, so let's defined our own overloads: +// This issue has been confirmed with MSVC 2008 only, but the issue might exist for more recent versions too. +#if EIGEN_OS_WINCE && EIGEN_COMP_MSVC && EIGEN_COMP_MSVC<=1500 +long abs(long x) { return (labs(x)); } +double abs(double x) { return (fabs(x)); } +float abs(float x) { return (fabsf(x)); } +long double abs(long double x) { return (fabsl(x)); } +#endif + namespace internal { -/** \internal \struct global_math_functions_filtering_base +/** \internal \class global_math_functions_filtering_base * * What it does: * Defines a typedef 'type' as follows: @@ -62,6 +76,7 @@ template::IsComplex> struct real_default_impl { typedef typename NumTraits::Real RealScalar; + EIGEN_DEVICE_FUNC static inline RealScalar run(const Scalar& x) { return x; @@ -72,6 +87,7 @@ template struct real_default_impl { typedef typename NumTraits::Real RealScalar; + EIGEN_DEVICE_FUNC static inline RealScalar run(const Scalar& x) { using std::real; @@ -81,13 +97,25 @@ struct real_default_impl template struct real_impl : real_default_impl {}; +#ifdef __CUDA_ARCH__ +template +struct real_impl > +{ + typedef T RealScalar; + EIGEN_DEVICE_FUNC + static inline T run(const std::complex& x) + { + return x.real(); + } +}; +#endif + template struct real_retval { typedef typename NumTraits::Real type; }; - /**************************************************************************** * Implementation of imag * ****************************************************************************/ @@ -96,6 +124,7 @@ template::IsComplex> struct imag_default_impl { typedef typename NumTraits::Real RealScalar; + EIGEN_DEVICE_FUNC static inline RealScalar run(const Scalar&) { return RealScalar(0); @@ -106,6 +135,7 @@ template struct imag_default_impl { typedef typename NumTraits::Real RealScalar; + EIGEN_DEVICE_FUNC static inline RealScalar run(const Scalar& x) { using std::imag; @@ -115,6 +145,19 @@ struct imag_default_impl template struct imag_impl : imag_default_impl {}; +#ifdef __CUDA_ARCH__ +template +struct imag_impl > +{ + typedef T RealScalar; + EIGEN_DEVICE_FUNC + static inline T run(const std::complex& x) + { + return x.imag(); + } +}; +#endif + template struct imag_retval { @@ -129,10 +172,12 @@ template struct real_ref_impl { typedef typename NumTraits::Real RealScalar; + EIGEN_DEVICE_FUNC static inline RealScalar& run(Scalar& x) { return reinterpret_cast(&x)[0]; } + EIGEN_DEVICE_FUNC static inline const RealScalar& run(const Scalar& x) { return reinterpret_cast(&x)[0]; @@ -153,10 +198,12 @@ template struct imag_ref_default_impl { typedef typename NumTraits::Real RealScalar; + EIGEN_DEVICE_FUNC static inline RealScalar& run(Scalar& x) { return reinterpret_cast(&x)[1]; } + EIGEN_DEVICE_FUNC static inline const RealScalar& run(const Scalar& x) { return reinterpret_cast(&x)[1]; @@ -166,10 +213,12 @@ struct imag_ref_default_impl template struct imag_ref_default_impl { + EIGEN_DEVICE_FUNC static inline Scalar run(Scalar&) { return Scalar(0); } + EIGEN_DEVICE_FUNC static inline const Scalar run(const Scalar&) { return Scalar(0); @@ -192,6 +241,7 @@ struct imag_ref_retval template::IsComplex> struct conj_impl { + EIGEN_DEVICE_FUNC static inline Scalar run(const Scalar& x) { return x; @@ -201,6 +251,7 @@ struct conj_impl template struct conj_impl { + EIGEN_DEVICE_FUNC static inline Scalar run(const Scalar& x) { using std::conj; @@ -218,25 +269,39 @@ struct conj_retval * Implementation of abs2 * ****************************************************************************/ -template -struct abs2_impl +template +struct abs2_impl_default { typedef typename NumTraits::Real RealScalar; + EIGEN_DEVICE_FUNC static inline RealScalar run(const Scalar& x) { return x*x; } }; -template -struct abs2_impl > +template +struct abs2_impl_default // IsComplex { - static inline RealScalar run(const std::complex& x) + typedef typename NumTraits::Real RealScalar; + EIGEN_DEVICE_FUNC + static inline RealScalar run(const Scalar& x) { return real(x)*real(x) + imag(x)*imag(x); } }; +template +struct abs2_impl +{ + typedef typename NumTraits::Real RealScalar; + EIGEN_DEVICE_FUNC + static inline RealScalar run(const Scalar& x) + { + return abs2_impl_default::IsComplex>::run(x); + } +}; + template struct abs2_retval { @@ -251,9 +316,10 @@ template struct norm1_default_impl { typedef typename NumTraits::Real RealScalar; + EIGEN_DEVICE_FUNC static inline RealScalar run(const Scalar& x) { - using std::abs; + EIGEN_USING_STD_MATH(abs); return abs(real(x)) + abs(imag(x)); } }; @@ -261,9 +327,10 @@ struct norm1_default_impl template struct norm1_default_impl { + EIGEN_DEVICE_FUNC static inline Scalar run(const Scalar& x) { - using std::abs; + EIGEN_USING_STD_MATH(abs); return abs(x); } }; @@ -287,16 +354,22 @@ struct hypot_impl typedef typename NumTraits::Real RealScalar; static inline RealScalar run(const Scalar& x, const Scalar& y) { - using std::max; - using std::min; - using std::abs; - using std::sqrt; + EIGEN_USING_STD_MATH(abs); + EIGEN_USING_STD_MATH(sqrt); RealScalar _x = abs(x); RealScalar _y = abs(y); - RealScalar p = (max)(_x, _y); + Scalar p, qp; + if(_x>_y) + { + p = _x; + qp = _y / p; + } + else + { + p = _y; + qp = _x / p; + } if(p==RealScalar(0)) return RealScalar(0); - RealScalar q = (min)(_x, _y); - RealScalar qp = q/p; return p * sqrt(RealScalar(1) + qp*qp); } }; @@ -314,6 +387,7 @@ struct hypot_retval template struct cast_impl { + EIGEN_DEVICE_FUNC static inline NewType run(const OldType& x) { return static_cast(x); @@ -323,48 +397,124 @@ struct cast_impl // here, for once, we're plainly returning NewType: we don't want cast to do weird things. template +EIGEN_DEVICE_FUNC inline NewType cast(const OldType& x) { return cast_impl::run(x); } /**************************************************************************** -* Implementation of atanh2 * +* Implementation of round * ****************************************************************************/ -template -struct atanh2_default_impl -{ - typedef Scalar retval; - typedef typename NumTraits::Real RealScalar; - static inline Scalar run(const Scalar& x, const Scalar& y) +#if EIGEN_HAS_CXX11_MATH + template + struct round_impl { + static inline Scalar run(const Scalar& x) + { + EIGEN_STATIC_ASSERT((!NumTraits::IsComplex), NUMERIC_TYPE_MUST_BE_REAL) + using std::round; + return round(x); + } + }; +#else + template + struct round_impl { - using std::abs; - using std::log; - using std::sqrt; - Scalar z = x / y; - if (y == Scalar(0) || abs(z) > sqrt(NumTraits::epsilon())) - return RealScalar(0.5) * log((y + x) / (y - x)); - else - return z + z*z*z / RealScalar(3); - } + static inline Scalar run(const Scalar& x) + { + EIGEN_STATIC_ASSERT((!NumTraits::IsComplex), NUMERIC_TYPE_MUST_BE_REAL) + EIGEN_USING_STD_MATH(floor); + EIGEN_USING_STD_MATH(ceil); + return (x > Scalar(0)) ? floor(x + Scalar(0.5)) : ceil(x - Scalar(0.5)); + } + }; +#endif + +template +struct round_retval +{ + typedef Scalar type; }; +/**************************************************************************** +* Implementation of arg * +****************************************************************************/ + +#if EIGEN_HAS_CXX11_MATH + template + struct arg_impl { + static inline Scalar run(const Scalar& x) + { + EIGEN_USING_STD_MATH(arg); + return arg(x); + } + }; +#else + template::IsComplex> + struct arg_default_impl + { + typedef typename NumTraits::Real RealScalar; + EIGEN_DEVICE_FUNC + static inline RealScalar run(const Scalar& x) + { + return (x < Scalar(0)) ? Scalar(EIGEN_PI) : Scalar(0); } + }; + + template + struct arg_default_impl + { + typedef typename NumTraits::Real RealScalar; + EIGEN_DEVICE_FUNC + static inline RealScalar run(const Scalar& x) + { + EIGEN_USING_STD_MATH(arg); + return arg(x); + } + }; + + template struct arg_impl : arg_default_impl {}; +#endif + template -struct atanh2_default_impl +struct arg_retval { - static inline Scalar run(const Scalar&, const Scalar&) + typedef typename NumTraits::Real type; +}; + +/**************************************************************************** +* Implementation of log1p * +****************************************************************************/ + +namespace std_fallback { + // fallback log1p implementation in case there is no log1p(Scalar) function in namespace of Scalar, + // or that there is no suitable std::log1p function available + template + EIGEN_DEVICE_FUNC inline Scalar log1p(const Scalar& x) { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar) + typedef typename NumTraits::Real RealScalar; + EIGEN_USING_STD_MATH(log); + Scalar x1p = RealScalar(1) + x; + return ( x1p == Scalar(1) ) ? x : x * ( log(x1p) / (x1p - RealScalar(1)) ); + } +} + +template +struct log1p_impl { + static inline Scalar run(const Scalar& x) { EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar) - return Scalar(0); + #if EIGEN_HAS_CXX11_MATH + using std::log1p; + #endif + using std_fallback::log1p; + return log1p(x); } }; -template -struct atanh2_impl : atanh2_default_impl::IsInteger> {}; template -struct atanh2_retval +struct log1p_retval { typedef Scalar type; }; @@ -373,24 +523,26 @@ struct atanh2_retval * Implementation of pow * ****************************************************************************/ -template -struct pow_default_impl +template::IsInteger&&NumTraits::IsInteger> +struct pow_impl { - typedef Scalar retval; - static inline Scalar run(const Scalar& x, const Scalar& y) + //typedef Scalar retval; + typedef typename ScalarBinaryOpTraits >::ReturnType result_type; + static EIGEN_DEVICE_FUNC inline result_type run(const ScalarX& x, const ScalarY& y) { - using std::pow; + EIGEN_USING_STD_MATH(pow); return pow(x, y); } }; -template -struct pow_default_impl +template +struct pow_impl { - static inline Scalar run(Scalar x, Scalar y) + typedef ScalarX result_type; + static EIGEN_DEVICE_FUNC inline ScalarX run(ScalarX x, ScalarY y) { - Scalar res(1); - eigen_assert(!NumTraits::IsSigned || y >= 0); + ScalarX res(1); + eigen_assert(!NumTraits::IsSigned || y >= 0); if(y & 1) res *= x; y >>= 1; while(y) @@ -403,15 +555,6 @@ struct pow_default_impl } }; -template -struct pow_impl : pow_default_impl::IsInteger> {}; - -template -struct pow_retval -{ - typedef Scalar type; -}; - /**************************************************************************** * Implementation of random * ****************************************************************************/ @@ -447,48 +590,48 @@ struct random_default_impl }; enum { - floor_log2_terminate, - floor_log2_move_up, - floor_log2_move_down, - floor_log2_bogus + meta_floor_log2_terminate, + meta_floor_log2_move_up, + meta_floor_log2_move_down, + meta_floor_log2_bogus }; -template struct floor_log2_selector +template struct meta_floor_log2_selector { enum { middle = (lower + upper) / 2, - value = (upper <= lower + 1) ? int(floor_log2_terminate) - : (n < (1 << middle)) ? int(floor_log2_move_down) - : (n==0) ? int(floor_log2_bogus) - : int(floor_log2_move_up) + value = (upper <= lower + 1) ? int(meta_floor_log2_terminate) + : (n < (1 << middle)) ? int(meta_floor_log2_move_down) + : (n==0) ? int(meta_floor_log2_bogus) + : int(meta_floor_log2_move_up) }; }; template::value> -struct floor_log2 {}; + int selector = meta_floor_log2_selector::value> +struct meta_floor_log2 {}; template -struct floor_log2 +struct meta_floor_log2 { - enum { value = floor_log2::middle>::value }; + enum { value = meta_floor_log2::middle>::value }; }; template -struct floor_log2 +struct meta_floor_log2 { - enum { value = floor_log2::middle, upper>::value }; + enum { value = meta_floor_log2::middle, upper>::value }; }; template -struct floor_log2 +struct meta_floor_log2 { enum { value = (n >= ((unsigned int)(1) << (lower+1))) ? lower+1 : lower }; }; template -struct floor_log2 +struct meta_floor_log2 { // no value, error at compile time }; @@ -496,11 +639,24 @@ struct floor_log2 template struct random_default_impl { - typedef typename NumTraits::NonInteger NonInteger; - static inline Scalar run(const Scalar& x, const Scalar& y) - { - return x + Scalar((NonInteger(y)-x+1) * std::rand() / (RAND_MAX + NonInteger(1))); + { + typedef typename conditional::IsSigned,std::ptrdiff_t,std::size_t>::type ScalarX; + if(y=x the result converted to an unsigned long is still correct. + std::size_t range = ScalarX(y)-ScalarX(x); + std::size_t offset = 0; + // rejection sampling + std::size_t divisor = 1; + std::size_t multiplier = 1; + if(range range); + return Scalar(ScalarX(x) + offset); } static inline Scalar run() @@ -508,7 +664,7 @@ struct random_default_impl #ifdef EIGEN_MAKING_DOCS return run(Scalar(NumTraits::IsSigned ? -10 : 0), Scalar(10)); #else - enum { rand_bits = floor_log2<(unsigned int)(RAND_MAX)+1>::value, + enum { rand_bits = meta_floor_log2<(unsigned int)(RAND_MAX)+1>::value, scalar_bits = sizeof(Scalar) * CHAR_BIT, shift = EIGEN_PLAIN_ENUM_MAX(0, int(rand_bits) - int(scalar_bits)), offset = NumTraits::IsSigned ? (1 << (EIGEN_PLAIN_ENUM_MIN(rand_bits,scalar_bits)-1)) : 0 @@ -545,97 +701,588 @@ inline EIGEN_MATHFUNC_RETVAL(random, Scalar) random() return EIGEN_MATHFUNC_IMPL(random, Scalar)::run(); } +// Implementatin of is* functions + +// std::is* do not work with fast-math and gcc, std::is* are available on MSVC 2013 and newer, as well as in clang. +#if (EIGEN_HAS_CXX11_MATH && !(EIGEN_COMP_GNUC_STRICT && __FINITE_MATH_ONLY__)) || (EIGEN_COMP_MSVC>=1800) || (EIGEN_COMP_CLANG) +#define EIGEN_USE_STD_FPCLASSIFY 1 +#else +#define EIGEN_USE_STD_FPCLASSIFY 0 +#endif + +template +EIGEN_DEVICE_FUNC +typename internal::enable_if::value,bool>::type +isnan_impl(const T&) { return false; } + +template +EIGEN_DEVICE_FUNC +typename internal::enable_if::value,bool>::type +isinf_impl(const T&) { return false; } + +template +EIGEN_DEVICE_FUNC +typename internal::enable_if::value,bool>::type +isfinite_impl(const T&) { return true; } + +template +EIGEN_DEVICE_FUNC +typename internal::enable_if<(!internal::is_integral::value)&&(!NumTraits::IsComplex),bool>::type +isfinite_impl(const T& x) +{ + #ifdef __CUDA_ARCH__ + return (::isfinite)(x); + #elif EIGEN_USE_STD_FPCLASSIFY + using std::isfinite; + return isfinite EIGEN_NOT_A_MACRO (x); + #else + return x<=NumTraits::highest() && x>=NumTraits::lowest(); + #endif +} + +template +EIGEN_DEVICE_FUNC +typename internal::enable_if<(!internal::is_integral::value)&&(!NumTraits::IsComplex),bool>::type +isinf_impl(const T& x) +{ + #ifdef __CUDA_ARCH__ + return (::isinf)(x); + #elif EIGEN_USE_STD_FPCLASSIFY + using std::isinf; + return isinf EIGEN_NOT_A_MACRO (x); + #else + return x>NumTraits::highest() || x::lowest(); + #endif +} + +template +EIGEN_DEVICE_FUNC +typename internal::enable_if<(!internal::is_integral::value)&&(!NumTraits::IsComplex),bool>::type +isnan_impl(const T& x) +{ + #ifdef __CUDA_ARCH__ + return (::isnan)(x); + #elif EIGEN_USE_STD_FPCLASSIFY + using std::isnan; + return isnan EIGEN_NOT_A_MACRO (x); + #else + return x != x; + #endif +} + +#if (!EIGEN_USE_STD_FPCLASSIFY) + +#if EIGEN_COMP_MSVC + +template EIGEN_DEVICE_FUNC bool isinf_msvc_helper(T x) +{ + return _fpclass(x)==_FPCLASS_NINF || _fpclass(x)==_FPCLASS_PINF; +} + +//MSVC defines a _isnan builtin function, but for double only +EIGEN_DEVICE_FUNC inline bool isnan_impl(const long double& x) { return _isnan(x)!=0; } +EIGEN_DEVICE_FUNC inline bool isnan_impl(const double& x) { return _isnan(x)!=0; } +EIGEN_DEVICE_FUNC inline bool isnan_impl(const float& x) { return _isnan(x)!=0; } + +EIGEN_DEVICE_FUNC inline bool isinf_impl(const long double& x) { return isinf_msvc_helper(x); } +EIGEN_DEVICE_FUNC inline bool isinf_impl(const double& x) { return isinf_msvc_helper(x); } +EIGEN_DEVICE_FUNC inline bool isinf_impl(const float& x) { return isinf_msvc_helper(x); } + +#elif (defined __FINITE_MATH_ONLY__ && __FINITE_MATH_ONLY__ && EIGEN_COMP_GNUC) + +#if EIGEN_GNUC_AT_LEAST(5,0) + #define EIGEN_TMP_NOOPT_ATTRIB EIGEN_DEVICE_FUNC inline __attribute__((optimize("no-finite-math-only"))) +#else + // NOTE the inline qualifier and noinline attribute are both needed: the former is to avoid linking issue (duplicate symbol), + // while the second prevent too aggressive optimizations in fast-math mode: + #define EIGEN_TMP_NOOPT_ATTRIB EIGEN_DEVICE_FUNC inline __attribute__((noinline,optimize("no-finite-math-only"))) +#endif + +template<> EIGEN_TMP_NOOPT_ATTRIB bool isnan_impl(const long double& x) { return __builtin_isnan(x); } +template<> EIGEN_TMP_NOOPT_ATTRIB bool isnan_impl(const double& x) { return __builtin_isnan(x); } +template<> EIGEN_TMP_NOOPT_ATTRIB bool isnan_impl(const float& x) { return __builtin_isnan(x); } +template<> EIGEN_TMP_NOOPT_ATTRIB bool isinf_impl(const double& x) { return __builtin_isinf(x); } +template<> EIGEN_TMP_NOOPT_ATTRIB bool isinf_impl(const float& x) { return __builtin_isinf(x); } +template<> EIGEN_TMP_NOOPT_ATTRIB bool isinf_impl(const long double& x) { return __builtin_isinf(x); } + +#undef EIGEN_TMP_NOOPT_ATTRIB + +#endif + +#endif + +// The following overload are defined at the end of this file +template EIGEN_DEVICE_FUNC bool isfinite_impl(const std::complex& x); +template EIGEN_DEVICE_FUNC bool isnan_impl(const std::complex& x); +template EIGEN_DEVICE_FUNC bool isinf_impl(const std::complex& x); + +template T generic_fast_tanh_float(const T& a_x); + } // end namespace internal /**************************************************************************** -* Generic math function * +* Generic math functions * ****************************************************************************/ namespace numext { +#ifndef __CUDA_ARCH__ +template +EIGEN_DEVICE_FUNC +EIGEN_ALWAYS_INLINE T mini(const T& x, const T& y) +{ + EIGEN_USING_STD_MATH(min); + return min EIGEN_NOT_A_MACRO (x,y); +} + +template +EIGEN_DEVICE_FUNC +EIGEN_ALWAYS_INLINE T maxi(const T& x, const T& y) +{ + EIGEN_USING_STD_MATH(max); + return max EIGEN_NOT_A_MACRO (x,y); +} +#else +template +EIGEN_DEVICE_FUNC +EIGEN_ALWAYS_INLINE T mini(const T& x, const T& y) +{ + return y < x ? y : x; +} +template<> +EIGEN_DEVICE_FUNC +EIGEN_ALWAYS_INLINE float mini(const float& x, const float& y) +{ + return fminf(x, y); +} +template +EIGEN_DEVICE_FUNC +EIGEN_ALWAYS_INLINE T maxi(const T& x, const T& y) +{ + return x < y ? y : x; +} +template<> +EIGEN_DEVICE_FUNC +EIGEN_ALWAYS_INLINE float maxi(const float& x, const float& y) +{ + return fmaxf(x, y); +} +#endif + + template +EIGEN_DEVICE_FUNC inline EIGEN_MATHFUNC_RETVAL(real, Scalar) real(const Scalar& x) { return EIGEN_MATHFUNC_IMPL(real, Scalar)::run(x); -} +} template +EIGEN_DEVICE_FUNC inline typename internal::add_const_on_value_type< EIGEN_MATHFUNC_RETVAL(real_ref, Scalar) >::type real_ref(const Scalar& x) { return internal::real_ref_impl::run(x); } template +EIGEN_DEVICE_FUNC inline EIGEN_MATHFUNC_RETVAL(real_ref, Scalar) real_ref(Scalar& x) { return EIGEN_MATHFUNC_IMPL(real_ref, Scalar)::run(x); } template +EIGEN_DEVICE_FUNC inline EIGEN_MATHFUNC_RETVAL(imag, Scalar) imag(const Scalar& x) { return EIGEN_MATHFUNC_IMPL(imag, Scalar)::run(x); } template +EIGEN_DEVICE_FUNC +inline EIGEN_MATHFUNC_RETVAL(arg, Scalar) arg(const Scalar& x) +{ + return EIGEN_MATHFUNC_IMPL(arg, Scalar)::run(x); +} + +template +EIGEN_DEVICE_FUNC inline typename internal::add_const_on_value_type< EIGEN_MATHFUNC_RETVAL(imag_ref, Scalar) >::type imag_ref(const Scalar& x) { return internal::imag_ref_impl::run(x); } template +EIGEN_DEVICE_FUNC inline EIGEN_MATHFUNC_RETVAL(imag_ref, Scalar) imag_ref(Scalar& x) { return EIGEN_MATHFUNC_IMPL(imag_ref, Scalar)::run(x); } template +EIGEN_DEVICE_FUNC inline EIGEN_MATHFUNC_RETVAL(conj, Scalar) conj(const Scalar& x) { return EIGEN_MATHFUNC_IMPL(conj, Scalar)::run(x); } template +EIGEN_DEVICE_FUNC inline EIGEN_MATHFUNC_RETVAL(abs2, Scalar) abs2(const Scalar& x) { return EIGEN_MATHFUNC_IMPL(abs2, Scalar)::run(x); } template +EIGEN_DEVICE_FUNC inline EIGEN_MATHFUNC_RETVAL(norm1, Scalar) norm1(const Scalar& x) { return EIGEN_MATHFUNC_IMPL(norm1, Scalar)::run(x); } template +EIGEN_DEVICE_FUNC inline EIGEN_MATHFUNC_RETVAL(hypot, Scalar) hypot(const Scalar& x, const Scalar& y) { return EIGEN_MATHFUNC_IMPL(hypot, Scalar)::run(x, y); } template -inline EIGEN_MATHFUNC_RETVAL(atanh2, Scalar) atanh2(const Scalar& x, const Scalar& y) +EIGEN_DEVICE_FUNC +inline EIGEN_MATHFUNC_RETVAL(log1p, Scalar) log1p(const Scalar& x) { - return EIGEN_MATHFUNC_IMPL(atanh2, Scalar)::run(x, y); + return EIGEN_MATHFUNC_IMPL(log1p, Scalar)::run(x); } +#ifdef __CUDACC__ +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +float log1p(const float &x) { return ::log1pf(x); } + +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +double log1p(const double &x) { return ::log1p(x); } +#endif + +template +EIGEN_DEVICE_FUNC +inline typename internal::pow_impl::result_type pow(const ScalarX& x, const ScalarY& y) +{ + return internal::pow_impl::run(x, y); +} + +template EIGEN_DEVICE_FUNC bool (isnan) (const T &x) { return internal::isnan_impl(x); } +template EIGEN_DEVICE_FUNC bool (isinf) (const T &x) { return internal::isinf_impl(x); } +template EIGEN_DEVICE_FUNC bool (isfinite)(const T &x) { return internal::isfinite_impl(x); } + template -inline EIGEN_MATHFUNC_RETVAL(pow, Scalar) pow(const Scalar& x, const Scalar& y) +EIGEN_DEVICE_FUNC +inline EIGEN_MATHFUNC_RETVAL(round, Scalar) round(const Scalar& x) +{ + return EIGEN_MATHFUNC_IMPL(round, Scalar)::run(x); +} + +template +EIGEN_DEVICE_FUNC +T (floor)(const T& x) +{ + EIGEN_USING_STD_MATH(floor); + return floor(x); +} + +#ifdef __CUDACC__ +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +float floor(const float &x) { return ::floorf(x); } + +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +double floor(const double &x) { return ::floor(x); } +#endif + +template +EIGEN_DEVICE_FUNC +T (ceil)(const T& x) +{ + EIGEN_USING_STD_MATH(ceil); + return ceil(x); +} + +#ifdef __CUDACC__ +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +float ceil(const float &x) { return ::ceilf(x); } + +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +double ceil(const double &x) { return ::ceil(x); } +#endif + + +/** Log base 2 for 32 bits positive integers. + * Conveniently returns 0 for x==0. */ +inline int log2(int x) { - return EIGEN_MATHFUNC_IMPL(pow, Scalar)::run(x, y); + eigen_assert(x>=0); + unsigned int v(x); + static const int table[32] = { 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31 }; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + return table[(v * 0x07C4ACDDU) >> 27]; } -// std::isfinite is non standard, so let's define our own version, -// even though it is not very efficient. -template bool (isfinite)(const T& x) +/** \returns the square root of \a x. + * + * It is essentially equivalent to \code using std::sqrt; return sqrt(x); \endcode, + * but slightly faster for float/double and some compilers (e.g., gcc), thanks to + * specializations when SSE is enabled. + * + * It's usage is justified in performance critical functions, like norm/normalize. + */ +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +T sqrt(const T &x) { - return x::highest() && x>NumTraits::lowest(); + EIGEN_USING_STD_MATH(sqrt); + return sqrt(x); +} + +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +T log(const T &x) { + EIGEN_USING_STD_MATH(log); + return log(x); +} + +#ifdef __CUDACC__ +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +float log(const float &x) { return ::logf(x); } + +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +double log(const double &x) { return ::log(x); } +#endif + +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +typename NumTraits::Real abs(const T &x) { + EIGEN_USING_STD_MATH(abs); + return abs(x); } +#ifdef __CUDACC__ +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +float abs(const float &x) { return ::fabsf(x); } + +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +double abs(const double &x) { return ::fabs(x); } + +template <> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +float abs(const std::complex& x) { + return ::hypotf(x.real(), x.imag()); +} + +template <> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +double abs(const std::complex& x) { + return ::hypot(x.real(), x.imag()); +} +#endif + +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +T exp(const T &x) { + EIGEN_USING_STD_MATH(exp); + return exp(x); +} + +#ifdef __CUDACC__ +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +float exp(const float &x) { return ::expf(x); } + +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +double exp(const double &x) { return ::exp(x); } +#endif + +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +T cos(const T &x) { + EIGEN_USING_STD_MATH(cos); + return cos(x); +} + +#ifdef __CUDACC__ +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +float cos(const float &x) { return ::cosf(x); } + +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +double cos(const double &x) { return ::cos(x); } +#endif + +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +T sin(const T &x) { + EIGEN_USING_STD_MATH(sin); + return sin(x); +} + +#ifdef __CUDACC__ +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +float sin(const float &x) { return ::sinf(x); } + +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +double sin(const double &x) { return ::sin(x); } +#endif + +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +T tan(const T &x) { + EIGEN_USING_STD_MATH(tan); + return tan(x); +} + +#ifdef __CUDACC__ +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +float tan(const float &x) { return ::tanf(x); } + +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +double tan(const double &x) { return ::tan(x); } +#endif + +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +T acos(const T &x) { + EIGEN_USING_STD_MATH(acos); + return acos(x); +} + +#ifdef __CUDACC__ +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +float acos(const float &x) { return ::acosf(x); } + +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +double acos(const double &x) { return ::acos(x); } +#endif + +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +T asin(const T &x) { + EIGEN_USING_STD_MATH(asin); + return asin(x); +} + +#ifdef __CUDACC__ +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +float asin(const float &x) { return ::asinf(x); } + +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +double asin(const double &x) { return ::asin(x); } +#endif + +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +T atan(const T &x) { + EIGEN_USING_STD_MATH(atan); + return atan(x); +} + +#ifdef __CUDACC__ +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +float atan(const float &x) { return ::atanf(x); } + +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +double atan(const double &x) { return ::atan(x); } +#endif + + +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +T cosh(const T &x) { + EIGEN_USING_STD_MATH(cosh); + return cosh(x); +} + +#ifdef __CUDACC__ +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +float cosh(const float &x) { return ::coshf(x); } + +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +double cosh(const double &x) { return ::cosh(x); } +#endif + +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +T sinh(const T &x) { + EIGEN_USING_STD_MATH(sinh); + return sinh(x); +} + +#ifdef __CUDACC__ +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +float sinh(const float &x) { return ::sinhf(x); } + +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +double sinh(const double &x) { return ::sinh(x); } +#endif + +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +T tanh(const T &x) { + EIGEN_USING_STD_MATH(tanh); + return tanh(x); +} + +#if (!defined(__CUDACC__)) && EIGEN_FAST_MATH +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +float tanh(float x) { return internal::generic_fast_tanh_float(x); } +#endif + +#ifdef __CUDACC__ +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +float tanh(const float &x) { return ::tanhf(x); } + +template<> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +double tanh(const double &x) { return ::tanh(x); } +#endif + +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +T fmod(const T& a, const T& b) { + EIGEN_USING_STD_MATH(fmod); + return fmod(a, b); +} + +#ifdef __CUDACC__ +template <> +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +float fmod(const float& a, const float& b) { + return ::fmodf(a, b); +} + +template <> +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +double fmod(const double& a, const double& b) { + return ::fmod(a, b); +} +#endif + } // end namespace numext namespace internal { +template +EIGEN_DEVICE_FUNC bool isfinite_impl(const std::complex& x) +{ + return (numext::isfinite)(numext::real(x)) && (numext::isfinite)(numext::imag(x)); +} + +template +EIGEN_DEVICE_FUNC bool isnan_impl(const std::complex& x) +{ + return (numext::isnan)(numext::real(x)) || (numext::isnan)(numext::imag(x)); +} + +template +EIGEN_DEVICE_FUNC bool isinf_impl(const std::complex& x) +{ + return ((numext::isinf)(numext::real(x)) || (numext::isinf)(numext::imag(x))) && (!(numext::isnan)(x)); +} + /**************************************************************************** * Implementation of fuzzy comparisons * ****************************************************************************/ @@ -649,18 +1296,17 @@ template struct scalar_fuzzy_default_impl { typedef typename NumTraits::Real RealScalar; - template + template EIGEN_DEVICE_FUNC static inline bool isMuchSmallerThan(const Scalar& x, const OtherScalar& y, const RealScalar& prec) { - using std::abs; - return abs(x) <= abs(y) * prec; + return numext::abs(x) <= numext::abs(y) * prec; } + EIGEN_DEVICE_FUNC static inline bool isApprox(const Scalar& x, const Scalar& y, const RealScalar& prec) { - using std::min; - using std::abs; - return abs(x - y) <= (min)(abs(x), abs(y)) * prec; + return numext::abs(x - y) <= numext::mini(numext::abs(x), numext::abs(y)) * prec; } + EIGEN_DEVICE_FUNC static inline bool isApproxOrLessThan(const Scalar& x, const Scalar& y, const RealScalar& prec) { return x <= y || isApprox(x, y, prec); @@ -671,15 +1317,17 @@ template struct scalar_fuzzy_default_impl { typedef typename NumTraits::Real RealScalar; - template + template EIGEN_DEVICE_FUNC static inline bool isMuchSmallerThan(const Scalar& x, const Scalar&, const RealScalar&) { return x == Scalar(0); } + EIGEN_DEVICE_FUNC static inline bool isApprox(const Scalar& x, const Scalar& y, const RealScalar&) { return x == y; } + EIGEN_DEVICE_FUNC static inline bool isApproxOrLessThan(const Scalar& x, const Scalar& y, const RealScalar&) { return x <= y; @@ -690,36 +1338,36 @@ template struct scalar_fuzzy_default_impl { typedef typename NumTraits::Real RealScalar; - template + template EIGEN_DEVICE_FUNC static inline bool isMuchSmallerThan(const Scalar& x, const OtherScalar& y, const RealScalar& prec) { return numext::abs2(x) <= numext::abs2(y) * prec * prec; } + EIGEN_DEVICE_FUNC static inline bool isApprox(const Scalar& x, const Scalar& y, const RealScalar& prec) { - using std::min; - return numext::abs2(x - y) <= (min)(numext::abs2(x), numext::abs2(y)) * prec * prec; + return numext::abs2(x - y) <= numext::mini(numext::abs2(x), numext::abs2(y)) * prec * prec; } }; template struct scalar_fuzzy_impl : scalar_fuzzy_default_impl::IsComplex, NumTraits::IsInteger> {}; -template +template EIGEN_DEVICE_FUNC inline bool isMuchSmallerThan(const Scalar& x, const OtherScalar& y, const typename NumTraits::Real &precision = NumTraits::dummy_precision()) { return scalar_fuzzy_impl::template isMuchSmallerThan(x, y, precision); } -template +template EIGEN_DEVICE_FUNC inline bool isApprox(const Scalar& x, const Scalar& y, const typename NumTraits::Real &precision = NumTraits::dummy_precision()) { return scalar_fuzzy_impl::isApprox(x, y, precision); } -template +template EIGEN_DEVICE_FUNC inline bool isApproxOrLessThan(const Scalar& x, const Scalar& y, const typename NumTraits::Real &precision = NumTraits::dummy_precision()) { @@ -742,17 +1390,19 @@ template<> struct scalar_fuzzy_impl { typedef bool RealScalar; - template + template EIGEN_DEVICE_FUNC static inline bool isMuchSmallerThan(const bool& x, const bool&, const bool&) { return !x; } + EIGEN_DEVICE_FUNC static inline bool isApprox(bool x, bool y, bool) { return x == y; } + EIGEN_DEVICE_FUNC static inline bool isApproxOrLessThan(const bool& x, const bool& y, const bool&) { return (!x) || y; diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Core/MathFunctionsImpl.h b/ground/gcs/src/libs/eigen/Eigen/src/Core/MathFunctionsImpl.h new file mode 100644 index 0000000000..3c9ef22fa6 --- /dev/null +++ b/ground/gcs/src/libs/eigen/Eigen/src/Core/MathFunctionsImpl.h @@ -0,0 +1,78 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Pedro Gonnet (pedro.gonnet@gmail.com) +// Copyright (C) 2016 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_MATHFUNCTIONSIMPL_H +#define EIGEN_MATHFUNCTIONSIMPL_H + +namespace Eigen { + +namespace internal { + +/** \internal \returns the hyperbolic tan of \a a (coeff-wise) + Doesn't do anything fancy, just a 13/6-degree rational interpolant which + is accurate up to a couple of ulp in the range [-9, 9], outside of which + the tanh(x) = +/-1. + + This implementation works on both scalars and packets. +*/ +template +T generic_fast_tanh_float(const T& a_x) +{ + // Clamp the inputs to the range [-9, 9] since anything outside + // this range is +/-1.0f in single-precision. + const T plus_9 = pset1(9.f); + const T minus_9 = pset1(-9.f); + // NOTE GCC prior to 6.3 might improperly optimize this max/min + // step such that if a_x is nan, x will be either 9 or -9, + // and tanh will return 1 or -1 instead of nan. + // This is supposed to be fixed in gcc6.3, + // see: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=72867 + const T x = pmax(minus_9,pmin(plus_9,a_x)); + // The monomial coefficients of the numerator polynomial (odd). + const T alpha_1 = pset1(4.89352455891786e-03f); + const T alpha_3 = pset1(6.37261928875436e-04f); + const T alpha_5 = pset1(1.48572235717979e-05f); + const T alpha_7 = pset1(5.12229709037114e-08f); + const T alpha_9 = pset1(-8.60467152213735e-11f); + const T alpha_11 = pset1(2.00018790482477e-13f); + const T alpha_13 = pset1(-2.76076847742355e-16f); + + // The monomial coefficients of the denominator polynomial (even). + const T beta_0 = pset1(4.89352518554385e-03f); + const T beta_2 = pset1(2.26843463243900e-03f); + const T beta_4 = pset1(1.18534705686654e-04f); + const T beta_6 = pset1(1.19825839466702e-06f); + + // Since the polynomials are odd/even, we need x^2. + const T x2 = pmul(x, x); + + // Evaluate the numerator polynomial p. + T p = pmadd(x2, alpha_13, alpha_11); + p = pmadd(x2, p, alpha_9); + p = pmadd(x2, p, alpha_7); + p = pmadd(x2, p, alpha_5); + p = pmadd(x2, p, alpha_3); + p = pmadd(x2, p, alpha_1); + p = pmul(x, p); + + // Evaluate the denominator polynomial p. + T q = pmadd(x2, beta_6, beta_4); + q = pmadd(x2, q, beta_2); + q = pmadd(x2, q, beta_0); + + // Divide the numerator by the denominator. + return pdiv(p, q); +} + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_MATHFUNCTIONSIMPL_H diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Core/Matrix.h b/ground/gcs/src/libs/eigen/Eigen/src/Core/Matrix.h index 02be142d8c..90c336d8ca 100644 --- a/ground/gcs/src/libs/eigen/Eigen/src/Core/Matrix.h +++ b/ground/gcs/src/libs/eigen/Eigen/src/Core/Matrix.h @@ -13,6 +13,45 @@ namespace Eigen { +namespace internal { +template +struct traits > +{ +private: + enum { size = internal::size_at_compile_time<_Rows,_Cols>::ret }; + typedef typename find_best_packet<_Scalar,size>::type PacketScalar; + enum { + row_major_bit = _Options&RowMajor ? RowMajorBit : 0, + is_dynamic_size_storage = _MaxRows==Dynamic || _MaxCols==Dynamic, + max_size = is_dynamic_size_storage ? Dynamic : _MaxRows*_MaxCols, + default_alignment = compute_default_alignment<_Scalar,max_size>::value, + actual_alignment = ((_Options&DontAlign)==0) ? default_alignment : 0, + required_alignment = unpacket_traits::alignment, + packet_access_bit = (packet_traits<_Scalar>::Vectorizable && (EIGEN_UNALIGNED_VECTORIZE || (actual_alignment>=required_alignment))) ? PacketAccessBit : 0 + }; + +public: + typedef _Scalar Scalar; + typedef Dense StorageKind; + typedef Eigen::Index StorageIndex; + typedef MatrixXpr XprKind; + enum { + RowsAtCompileTime = _Rows, + ColsAtCompileTime = _Cols, + MaxRowsAtCompileTime = _MaxRows, + MaxColsAtCompileTime = _MaxCols, + Flags = compute_matrix_flags<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols>::ret, + Options = _Options, + InnerStrideAtCompileTime = 1, + OuterStrideAtCompileTime = (Options&RowMajor) ? ColsAtCompileTime : RowsAtCompileTime, + + // FIXME, the following flag in only used to define NeedsToAlign in PlainObjectBase + EvaluatorFlags = LinearAccessBit | DirectAccessBit | packet_access_bit | row_major_bit, + Alignment = actual_alignment + }; +}; +} + /** \class Matrix * \ingroup Core_Module * @@ -24,13 +63,13 @@ namespace Eigen { * The %Matrix class encompasses \em both fixed-size and dynamic-size objects (\ref fixedsize "note"). * * The first three template parameters are required: - * \tparam _Scalar \anchor matrix_tparam_scalar Numeric type, e.g. float, double, int or std::complex. - * User defined sclar types are supported as well (see \ref user_defined_scalars "here"). + * \tparam _Scalar Numeric type, e.g. float, double, int or std::complex. + * User defined scalar types are supported as well (see \ref user_defined_scalars "here"). * \tparam _Rows Number of rows, or \b Dynamic * \tparam _Cols Number of columns, or \b Dynamic * * The remaining template parameters are optional -- in most cases you don't have to worry about them. - * \tparam _Options \anchor matrix_tparam_options A combination of either \b #RowMajor or \b #ColMajor, and of either + * \tparam _Options A combination of either \b #RowMajor or \b #ColMajor, and of either * \b #AutoAlign or \b #DontAlign. * The former controls \ref TopicStorageOrders "storage order", and defaults to column-major. The latter controls alignment, which is required * for vectorization. It defaults to aligning matrices except for fixed sizes that aren't a multiple of the packet size. @@ -67,7 +106,7 @@ namespace Eigen { * \endcode * * This class can be extended with the help of the plugin mechanism described on the page - * \ref TopicCustomizingEigen by defining the preprocessor symbol \c EIGEN_MATRIX_PLUGIN. + * \ref TopicCustomizing_Plugins by defining the preprocessor symbol \c EIGEN_MATRIX_PLUGIN. * * Some notes: * @@ -97,32 +136,44 @@ namespace Eigen { * are the dimensions of the original matrix, while _Rows and _Cols are Dynamic. *

c!lr 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

* - * \see MatrixBase for the majority of the API methods for matrices, \ref TopicClassHierarchy, - * \ref TopicStorageOrders + * ABI and storage layout + * + * The table below summarizes the ABI of some possible Matrix instances which is fixed thorough the lifetime of Eigen 3. + * + * + * + * + * + * + *
Matrix typeEquivalent C structure
\code Matrix \endcode\code + * struct { + * T *data; // with (size_t(data)%EIGEN_MAX_ALIGN_BYTES)==0 + * Eigen::Index rows, cols; + * }; + * \endcode
\code + * Matrix + * Matrix \endcode\code + * struct { + * T *data; // with (size_t(data)%EIGEN_MAX_ALIGN_BYTES)==0 + * Eigen::Index size; + * }; + * \endcode
\code Matrix \endcode\code + * struct { + * T data[Rows*Cols]; // with (size_t(data)%A(Rows*Cols*sizeof(T)))==0 + * }; + * \endcode
\code Matrix \endcode\code + * struct { + * T data[MaxRows*MaxCols]; // with (size_t(data)%A(MaxRows*MaxCols*sizeof(T)))==0 + * Eigen::Index rows, cols; + * }; + * \endcode
+ * Note that in this table Rows, Cols, MaxRows and MaxCols are all positive integers. A(S) is defined to the largest possible power-of-two + * smaller to EIGEN_MAX_STATIC_ALIGN_BYTES. + * + * \see MatrixBase for the majority of the API methods for matrices, \ref TopicClassHierarchy, + * \ref TopicStorageOrders */ -namespace internal { -template -struct traits > -{ - typedef _Scalar Scalar; - typedef Dense StorageKind; - typedef DenseIndex Index; - typedef MatrixXpr XprKind; - enum { - RowsAtCompileTime = _Rows, - ColsAtCompileTime = _Cols, - MaxRowsAtCompileTime = _MaxRows, - MaxColsAtCompileTime = _MaxCols, - Flags = compute_matrix_flags<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols>::ret, - CoeffReadCost = NumTraits::ReadCost, - Options = _Options, - InnerStrideAtCompileTime = 1, - OuterStrideAtCompileTime = (Options&RowMajor) ? ColsAtCompileTime : RowsAtCompileTime - }; -}; -} - template class Matrix : public PlainObjectBase > @@ -151,6 +202,7 @@ class Matrix * * \callgraph */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Matrix& operator=(const Matrix& other) { return Base::_set(other); @@ -167,7 +219,8 @@ class Matrix * remain row-vectors and vectors remain vectors. */ template - EIGEN_STRONG_INLINE Matrix& operator=(const MatrixBase& other) + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Matrix& operator=(const DenseBase& other) { return Base::_set(other); } @@ -179,12 +232,14 @@ class Matrix * \copydetails DenseBase::operator=(const EigenBase &other) */ template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Matrix& operator=(const EigenBase &other) { return Base::operator=(other); } template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Matrix& operator=(const ReturnByValue& func) { return Base::operator=(func); @@ -200,6 +255,7 @@ class Matrix * * \sa resize(Index,Index) */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Matrix() : Base() { Base::_check_template_params(); @@ -207,60 +263,87 @@ class Matrix } // FIXME is it still needed - Matrix(internal::constructor_without_unaligned_array_assert) + EIGEN_DEVICE_FUNC + explicit Matrix(internal::constructor_without_unaligned_array_assert) : Base(internal::constructor_without_unaligned_array_assert()) { Base::_check_template_params(); EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED } -#ifdef EIGEN_HAVE_RVALUE_REFERENCES - Matrix(Matrix&& other) +#if EIGEN_HAS_RVALUE_REFERENCES + EIGEN_DEVICE_FUNC + Matrix(Matrix&& other) EIGEN_NOEXCEPT_IF(std::is_nothrow_move_constructible::value) : Base(std::move(other)) { Base::_check_template_params(); if (RowsAtCompileTime!=Dynamic && ColsAtCompileTime!=Dynamic) Base::_set_noalias(other); } - Matrix& operator=(Matrix&& other) + EIGEN_DEVICE_FUNC + Matrix& operator=(Matrix&& other) EIGEN_NOEXCEPT_IF(std::is_nothrow_move_assignable::value) { other.swap(*this); return *this; } #endif - /** \brief Constructs a vector or row-vector with given dimension. \only_for_vectors - * - * Note that this is only useful for dynamic-size vectors. For fixed-size vectors, - * it is redundant to pass the dimension here, so it makes more sense to use the default - * constructor Matrix() instead. - */ - EIGEN_STRONG_INLINE explicit Matrix(Index dim) - : Base(dim, RowsAtCompileTime == 1 ? 1 : dim, ColsAtCompileTime == 1 ? 1 : dim) + #ifndef EIGEN_PARSED_BY_DOXYGEN + + // This constructor is for both 1x1 matrices and dynamic vectors + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE explicit Matrix(const T& x) { Base::_check_template_params(); - EIGEN_STATIC_ASSERT_VECTOR_ONLY(Matrix) - eigen_assert(dim >= 0); - eigen_assert(SizeAtCompileTime == Dynamic || SizeAtCompileTime == dim); - EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED + Base::template _init1(x); } - #ifndef EIGEN_PARSED_BY_DOXYGEN template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Matrix(const T0& x, const T1& y) { Base::_check_template_params(); Base::template _init2(x, y); } #else + /** \brief Constructs a fixed-sized matrix initialized with coefficients starting at \a data */ + EIGEN_DEVICE_FUNC + explicit Matrix(const Scalar *data); + + /** \brief Constructs a vector or row-vector with given dimension. \only_for_vectors + * + * This is useful for dynamic-size vectors. For fixed-size vectors, + * it is redundant to pass these parameters, so one should use the default constructor + * Matrix() instead. + * + * \warning This constructor is disabled for fixed-size \c 1x1 matrices. For instance, + * calling Matrix(1) will call the initialization constructor: Matrix(const Scalar&). + * For fixed-size \c 1x1 matrices it is therefore recommended to use the default + * constructor Matrix() instead, especially when using one of the non standard + * \c EIGEN_INITIALIZE_MATRICES_BY_{ZERO,\c NAN} macros (see \ref TopicPreprocessorDirectives). + */ + EIGEN_STRONG_INLINE explicit Matrix(Index dim); + /** \brief Constructs an initialized 1x1 matrix with the given coefficient */ + Matrix(const Scalar& x); /** \brief Constructs an uninitialized matrix with \a rows rows and \a cols columns. * * This is useful for dynamic-size matrices. For fixed-size matrices, * it is redundant to pass these parameters, so one should use the default constructor - * Matrix() instead. */ + * Matrix() instead. + * + * \warning This constructor is disabled for fixed-size \c 1x2 and \c 2x1 vectors. For instance, + * calling Matrix2f(2,1) will call the initialization constructor: Matrix(const Scalar& x, const Scalar& y). + * For fixed-size \c 1x2 or \c 2x1 vectors it is therefore recommended to use the default + * constructor Matrix() instead, especially when using one of the non standard + * \c EIGEN_INITIALIZE_MATRICES_BY_{ZERO,\c NAN} macros (see \ref TopicPreprocessorDirectives). + */ + EIGEN_DEVICE_FUNC Matrix(Index rows, Index cols); + /** \brief Constructs an initialized 2D vector with given coefficients */ Matrix(const Scalar& x, const Scalar& y); #endif /** \brief Constructs an initialized 3D vector with given coefficients */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Matrix(const Scalar& x, const Scalar& y, const Scalar& z) { Base::_check_template_params(); @@ -270,6 +353,7 @@ class Matrix m_storage.data()[2] = z; } /** \brief Constructs an initialized 4D vector with given coefficients */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Matrix(const Scalar& x, const Scalar& y, const Scalar& z, const Scalar& w) { Base::_check_template_params(); @@ -280,76 +364,33 @@ class Matrix m_storage.data()[3] = w; } - explicit Matrix(const Scalar *data); - /** \brief Constructor copying the value of the expression \a other */ - template - EIGEN_STRONG_INLINE Matrix(const MatrixBase& other) - : Base(other.rows() * other.cols(), other.rows(), other.cols()) - { - // This test resides here, to bring the error messages closer to the user. Normally, these checks - // are performed deeply within the library, thus causing long and scary error traces. - EIGEN_STATIC_ASSERT((internal::is_same::value), - YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) - - Base::_check_template_params(); - Base::_set_noalias(other); - } /** \brief Copy constructor */ - EIGEN_STRONG_INLINE Matrix(const Matrix& other) - : Base(other.rows() * other.cols(), other.rows(), other.cols()) - { - Base::_check_template_params(); - Base::_set_noalias(other); - } - /** \brief Copy constructor with in-place evaluation */ - template - EIGEN_STRONG_INLINE Matrix(const ReturnByValue& other) - { - Base::_check_template_params(); - Base::resize(other.rows(), other.cols()); - other.evalTo(*this); - } + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Matrix(const Matrix& other) : Base(other) + { } /** \brief Copy constructor for generic expressions. * \sa MatrixBase::operator=(const EigenBase&) */ template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Matrix(const EigenBase &other) - : Base(other.derived().rows() * other.derived().cols(), other.derived().rows(), other.derived().cols()) - { - Base::_check_template_params(); - Base::_resize_to_match(other); - // FIXME/CHECK: isn't *this = other.derived() more efficient. it allows to - // go for pure _set() implementations, right? - *this = other; - } - - /** \internal - * \brief Override MatrixBase::swap() since for dynamic-sized matrices - * of same type it is enough to swap the data pointers. - */ - template - void swap(MatrixBase const & other) - { this->_swap(other.derived()); } + : Base(other.derived()) + { } - inline Index innerStride() const { return 1; } - inline Index outerStride() const { return this->innerSize(); } + EIGEN_DEVICE_FUNC inline Index innerStride() const { return 1; } + EIGEN_DEVICE_FUNC inline Index outerStride() const { return this->innerSize(); } /////////// Geometry module /////////// template + EIGEN_DEVICE_FUNC explicit Matrix(const RotationBase& r); template + EIGEN_DEVICE_FUNC Matrix& operator=(const RotationBase& r); - #ifdef EIGEN2_SUPPORT - template - explicit Matrix(const eigen2_RotationBase& r); - template - Matrix& operator=(const eigen2_RotationBase& r); - #endif - // allow to extend Matrix outside Eigen #ifdef EIGEN_MATRIX_PLUGIN #include EIGEN_MATRIX_PLUGIN diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Core/MatrixBase.h b/ground/gcs/src/libs/eigen/Eigen/src/Core/MatrixBase.h index e83ef4dc05..f7cf04cde3 100644 --- a/ground/gcs/src/libs/eigen/Eigen/src/Core/MatrixBase.h +++ b/ground/gcs/src/libs/eigen/Eigen/src/Core/MatrixBase.h @@ -41,9 +41,9 @@ namespace Eigen { * \endcode * * This class can be extended with the help of the plugin mechanism described on the page - * \ref TopicCustomizingEigen by defining the preprocessor symbol \c EIGEN_MATRIXBASE_PLUGIN. + * \ref TopicCustomizing_Plugins by defining the preprocessor symbol \c EIGEN_MATRIXBASE_PLUGIN. * - * \sa \ref TopicClassHierarchy + * \sa \blank \ref TopicClassHierarchy */ template class MatrixBase : public DenseBase @@ -52,7 +52,7 @@ template class MatrixBase #ifndef EIGEN_PARSED_BY_DOXYGEN typedef MatrixBase StorageBaseType; typedef typename internal::traits::StorageKind StorageKind; - typedef typename internal::traits::Index Index; + typedef typename internal::traits::StorageIndex StorageIndex; typedef typename internal::traits::Scalar Scalar; typedef typename internal::packet_traits::type PacketScalar; typedef typename NumTraits::Real RealScalar; @@ -66,7 +66,6 @@ template class MatrixBase using Base::MaxSizeAtCompileTime; using Base::IsVectorAtCompileTime; using Base::Flags; - using Base::CoeffReadCost; using Base::derived; using Base::const_cast_derived; @@ -98,25 +97,14 @@ template class MatrixBase /** \returns the size of the main diagonal, which is min(rows(),cols()). * \sa rows(), cols(), SizeAtCompileTime. */ - inline Index diagonalSize() const { return (std::min)(rows(),cols()); } + EIGEN_DEVICE_FUNC + inline Index diagonalSize() const { return (numext::mini)(rows(),cols()); } - /** \brief The plain matrix type corresponding to this expression. - * - * This is not necessarily exactly the return type of eval(). In the case of plain matrices, - * the return type of eval() is a const reference to a matrix, not a matrix! It is however guaranteed - * that the return type of eval() is either PlainObject or const PlainObject&. - */ - typedef Matrix::Scalar, - internal::traits::RowsAtCompileTime, - internal::traits::ColsAtCompileTime, - AutoAlign | (internal::traits::Flags&RowMajorBit ? RowMajor : ColMajor), - internal::traits::MaxRowsAtCompileTime, - internal::traits::MaxColsAtCompileTime - > PlainObject; + typedef typename Base::PlainObject PlainObject; #ifndef EIGEN_PARSED_BY_DOXYGEN /** \internal Represents a matrix with all coefficients equal to one another*/ - typedef CwiseNullaryOp,Derived> ConstantReturnType; + typedef CwiseNullaryOp,PlainObject> ConstantReturnType; /** \internal the return type of MatrixBase::adjoint() */ typedef typename internal::conditional::IsComplex, CwiseUnaryOp, ConstTransposeReturnType>, @@ -125,7 +113,7 @@ template class MatrixBase /** \internal Return type of eigenvalues() */ typedef Matrix, internal::traits::ColsAtCompileTime, 1, ColMajor> EigenvaluesReturnType; /** \internal the return type of identity */ - typedef CwiseNullaryOp,Derived> IdentityReturnType; + typedef CwiseNullaryOp,PlainObject> IdentityReturnType; /** \internal the return type of unit vectors */ typedef Block, SquareMatrixType>, internal::traits::RowsAtCompileTime, @@ -133,6 +121,7 @@ template class MatrixBase #endif // not EIGEN_PARSED_BY_DOXYGEN #define EIGEN_CURRENT_STORAGE_BASE_CLASS Eigen::MatrixBase +#define EIGEN_DOC_UNARY_ADDONS(X,Y) # include "../plugins/CommonCwiseUnaryOps.h" # include "../plugins/CommonCwiseBinaryOps.h" # include "../plugins/MatrixCwiseUnaryOps.h" @@ -141,41 +130,53 @@ template class MatrixBase # include EIGEN_MATRIXBASE_PLUGIN # endif #undef EIGEN_CURRENT_STORAGE_BASE_CLASS +#undef EIGEN_DOC_UNARY_ADDONS /** Special case of the template operator=, in order to prevent the compiler * from generating a default operator= (issue hit with g++ 4.1) */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator=(const MatrixBase& other); // We cannot inherit here via Base::operator= since it is causing // trouble with MSVC. template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator=(const DenseBase& other); template + EIGEN_DEVICE_FUNC Derived& operator=(const EigenBase& other); template + EIGEN_DEVICE_FUNC Derived& operator=(const ReturnByValue& other); - template - Derived& lazyAssign(const ProductBase& other); - - template - Derived& lazyAssign(const MatrixPowerProduct& other); - template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator+=(const MatrixBase& other); template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator-=(const MatrixBase& other); +#ifdef __CUDACC__ + template + EIGEN_DEVICE_FUNC + const Product + operator*(const MatrixBase &other) const + { return this->lazyProduct(other); } +#else + template - const typename ProductReturnType::Type + const Product operator*(const MatrixBase &other) const; +#endif + template - const typename LazyProductReturnType::Type + EIGEN_DEVICE_FUNC + const Product lazyProduct(const MatrixBase &other) const; template @@ -188,84 +189,93 @@ template class MatrixBase void applyOnTheRight(const EigenBase& other); template - const DiagonalProduct + EIGEN_DEVICE_FUNC + const Product operator*(const DiagonalBase &diagonal) const; template - typename internal::scalar_product_traits::Scalar,typename internal::traits::Scalar>::ReturnType + EIGEN_DEVICE_FUNC + typename ScalarBinaryOpTraits::Scalar,typename internal::traits::Scalar>::ReturnType dot(const MatrixBase& other) const; - #ifdef EIGEN2_SUPPORT - template - Scalar eigen2_dot(const MatrixBase& other) const; - #endif - - RealScalar squaredNorm() const; - RealScalar norm() const; + EIGEN_DEVICE_FUNC RealScalar squaredNorm() const; + EIGEN_DEVICE_FUNC RealScalar norm() const; RealScalar stableNorm() const; RealScalar blueNorm() const; RealScalar hypotNorm() const; - const PlainObject normalized() const; - void normalize(); + EIGEN_DEVICE_FUNC const PlainObject normalized() const; + EIGEN_DEVICE_FUNC const PlainObject stableNormalized() const; + EIGEN_DEVICE_FUNC void normalize(); + EIGEN_DEVICE_FUNC void stableNormalize(); - const AdjointReturnType adjoint() const; - void adjointInPlace(); + EIGEN_DEVICE_FUNC const AdjointReturnType adjoint() const; + EIGEN_DEVICE_FUNC void adjointInPlace(); typedef Diagonal DiagonalReturnType; + EIGEN_DEVICE_FUNC DiagonalReturnType diagonal(); + typedef typename internal::add_const >::type ConstDiagonalReturnType; + EIGEN_DEVICE_FUNC ConstDiagonalReturnType diagonal() const; template struct DiagonalIndexReturnType { typedef Diagonal Type; }; template struct ConstDiagonalIndexReturnType { typedef const Diagonal Type; }; - template typename DiagonalIndexReturnType::Type diagonal(); - template typename ConstDiagonalIndexReturnType::Type diagonal() const; - + template + EIGEN_DEVICE_FUNC + typename DiagonalIndexReturnType::Type diagonal(); + + template + EIGEN_DEVICE_FUNC + typename ConstDiagonalIndexReturnType::Type diagonal() const; + typedef Diagonal DiagonalDynamicIndexReturnType; typedef typename internal::add_const >::type ConstDiagonalDynamicIndexReturnType; + EIGEN_DEVICE_FUNC DiagonalDynamicIndexReturnType diagonal(Index index); + EIGEN_DEVICE_FUNC ConstDiagonalDynamicIndexReturnType diagonal(Index index) const; - #ifdef EIGEN2_SUPPORT - template typename internal::eigen2_part_return_type::type part(); - template const typename internal::eigen2_part_return_type::type part() const; - - // huuuge hack. make Eigen2's matrix.part() work in eigen3. Problem: Diagonal is now a class template instead - // of an integer constant. Solution: overload the part() method template wrt template parameters list. - template class U> - const DiagonalWrapper part() const - { return diagonal().asDiagonal(); } - #endif // EIGEN2_SUPPORT - template struct TriangularViewReturnType { typedef TriangularView Type; }; template struct ConstTriangularViewReturnType { typedef const TriangularView Type; }; - template typename TriangularViewReturnType::Type triangularView(); - template typename ConstTriangularViewReturnType::Type triangularView() const; + template + EIGEN_DEVICE_FUNC + typename TriangularViewReturnType::Type triangularView(); + template + EIGEN_DEVICE_FUNC + typename ConstTriangularViewReturnType::Type triangularView() const; template struct SelfAdjointViewReturnType { typedef SelfAdjointView Type; }; template struct ConstSelfAdjointViewReturnType { typedef const SelfAdjointView Type; }; - template typename SelfAdjointViewReturnType::Type selfadjointView(); - template typename ConstSelfAdjointViewReturnType::Type selfadjointView() const; + template + EIGEN_DEVICE_FUNC + typename SelfAdjointViewReturnType::Type selfadjointView(); + template + EIGEN_DEVICE_FUNC + typename ConstSelfAdjointViewReturnType::Type selfadjointView() const; const SparseView sparseView(const Scalar& m_reference = Scalar(0), const typename NumTraits::Real& m_epsilon = NumTraits::dummy_precision()) const; - static const IdentityReturnType Identity(); - static const IdentityReturnType Identity(Index rows, Index cols); - static const BasisReturnType Unit(Index size, Index i); - static const BasisReturnType Unit(Index i); - static const BasisReturnType UnitX(); - static const BasisReturnType UnitY(); - static const BasisReturnType UnitZ(); - static const BasisReturnType UnitW(); - + EIGEN_DEVICE_FUNC static const IdentityReturnType Identity(); + EIGEN_DEVICE_FUNC static const IdentityReturnType Identity(Index rows, Index cols); + EIGEN_DEVICE_FUNC static const BasisReturnType Unit(Index size, Index i); + EIGEN_DEVICE_FUNC static const BasisReturnType Unit(Index i); + EIGEN_DEVICE_FUNC static const BasisReturnType UnitX(); + EIGEN_DEVICE_FUNC static const BasisReturnType UnitY(); + EIGEN_DEVICE_FUNC static const BasisReturnType UnitZ(); + EIGEN_DEVICE_FUNC static const BasisReturnType UnitW(); + + EIGEN_DEVICE_FUNC const DiagonalWrapper asDiagonal() const; const PermutationWrapper asPermutation() const; + EIGEN_DEVICE_FUNC Derived& setIdentity(); + EIGEN_DEVICE_FUNC Derived& setIdentity(Index rows, Index cols); bool isIdentity(const RealScalar& prec = NumTraits::dummy_precision()) const; @@ -297,59 +307,45 @@ template class MatrixBase NoAlias noalias(); - inline const ForceAlignedAccess forceAlignedAccess() const; - inline ForceAlignedAccess forceAlignedAccess(); - template inline typename internal::add_const_on_value_type,Derived&>::type>::type forceAlignedAccessIf() const; - template inline typename internal::conditional,Derived&>::type forceAlignedAccessIf(); + // TODO forceAlignedAccess is temporarily disabled + // Need to find a nicer workaround. + inline const Derived& forceAlignedAccess() const { return derived(); } + inline Derived& forceAlignedAccess() { return derived(); } + template inline const Derived& forceAlignedAccessIf() const { return derived(); } + template inline Derived& forceAlignedAccessIf() { return derived(); } - Scalar trace() const; + EIGEN_DEVICE_FUNC Scalar trace() const; -/////////// Array module /////////// + template EIGEN_DEVICE_FUNC RealScalar lpNorm() const; - template RealScalar lpNorm() const; - - MatrixBase& matrix() { return *this; } - const MatrixBase& matrix() const { return *this; } + EIGEN_DEVICE_FUNC MatrixBase& matrix() { return *this; } + EIGEN_DEVICE_FUNC const MatrixBase& matrix() const { return *this; } /** \returns an \link Eigen::ArrayBase Array \endlink expression of this matrix * \sa ArrayBase::matrix() */ - ArrayWrapper array() { return derived(); } - const ArrayWrapper array() const { return derived(); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE ArrayWrapper array() { return ArrayWrapper(derived()); } + /** \returns a const \link Eigen::ArrayBase Array \endlink expression of this matrix + * \sa ArrayBase::matrix() */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const ArrayWrapper array() const { return ArrayWrapper(derived()); } /////////// LU module /////////// - const FullPivLU fullPivLu() const; - const PartialPivLU partialPivLu() const; + inline const FullPivLU fullPivLu() const; + inline const PartialPivLU partialPivLu() const; - #if EIGEN2_SUPPORT_STAGE < STAGE20_RESOLVE_API_CONFLICTS - const LU lu() const; - #endif + inline const PartialPivLU lu() const; - #ifdef EIGEN2_SUPPORT - const LU eigen2_lu() const; - #endif + inline const Inverse inverse() const; - #if EIGEN2_SUPPORT_STAGE > STAGE20_RESOLVE_API_CONFLICTS - const PartialPivLU lu() const; - #endif - - #ifdef EIGEN2_SUPPORT template - void computeInverse(MatrixBase *result) const { - *result = this->inverse(); - } - #endif - - const internal::inverse_impl inverse() const; - template - void computeInverseAndDetWithCheck( + inline void computeInverseAndDetWithCheck( ResultType& inverse, typename ResultType::Scalar& determinant, bool& invertible, const RealScalar& absDeterminantThreshold = NumTraits::dummy_precision() ) const; template - void computeInverseWithCheck( + inline void computeInverseWithCheck( ResultType& inverse, bool& invertible, const RealScalar& absDeterminantThreshold = NumTraits::dummy_precision() @@ -358,65 +354,70 @@ template class MatrixBase /////////// Cholesky module /////////// - const LLT llt() const; - const LDLT ldlt() const; + inline const LLT llt() const; + inline const LDLT ldlt() const; /////////// QR module /////////// - const HouseholderQR householderQr() const; - const ColPivHouseholderQR colPivHouseholderQr() const; - const FullPivHouseholderQR fullPivHouseholderQr() const; - - #ifdef EIGEN2_SUPPORT - const QR qr() const; - #endif + inline const HouseholderQR householderQr() const; + inline const ColPivHouseholderQR colPivHouseholderQr() const; + inline const FullPivHouseholderQR fullPivHouseholderQr() const; + inline const CompleteOrthogonalDecomposition completeOrthogonalDecomposition() const; - EigenvaluesReturnType eigenvalues() const; - RealScalar operatorNorm() const; +/////////// Eigenvalues module /////////// -/////////// SVD module /////////// + inline EigenvaluesReturnType eigenvalues() const; + inline RealScalar operatorNorm() const; - JacobiSVD jacobiSvd(unsigned int computationOptions = 0) const; +/////////// SVD module /////////// - #ifdef EIGEN2_SUPPORT - SVD svd() const; - #endif + inline JacobiSVD jacobiSvd(unsigned int computationOptions = 0) const; + inline BDCSVD bdcSvd(unsigned int computationOptions = 0) const; /////////// Geometry module /////////// #ifndef EIGEN_PARSED_BY_DOXYGEN /// \internal helper struct to form the return type of the cross product template struct cross_product_return_type { - typedef typename internal::scalar_product_traits::Scalar,typename internal::traits::Scalar>::ReturnType Scalar; + typedef typename ScalarBinaryOpTraits::Scalar,typename internal::traits::Scalar>::ReturnType Scalar; typedef Matrix type; }; #endif // EIGEN_PARSED_BY_DOXYGEN template - typename cross_product_return_type::type + EIGEN_DEVICE_FUNC +#ifndef EIGEN_PARSED_BY_DOXYGEN + inline typename cross_product_return_type::type +#else + inline PlainObject +#endif cross(const MatrixBase& other) const; + template - PlainObject cross3(const MatrixBase& other) const; - PlainObject unitOrthogonal(void) const; - Matrix eulerAngles(Index a0, Index a1, Index a2) const; - - #if EIGEN2_SUPPORT_STAGE > STAGE20_RESOLVE_API_CONFLICTS - ScalarMultipleReturnType operator*(const UniformScaling& s) const; + EIGEN_DEVICE_FUNC + inline PlainObject cross3(const MatrixBase& other) const; + + EIGEN_DEVICE_FUNC + inline PlainObject unitOrthogonal(void) const; + + EIGEN_DEVICE_FUNC + inline Matrix eulerAngles(Index a0, Index a1, Index a2) const; + // put this as separate enum value to work around possible GCC 4.3 bug (?) - enum { HomogeneousReturnTypeDirection = ColsAtCompileTime==1?Vertical:Horizontal }; + enum { HomogeneousReturnTypeDirection = ColsAtCompileTime==1&&RowsAtCompileTime==1 ? ((internal::traits::Flags&RowMajorBit)==RowMajorBit ? Horizontal : Vertical) + : ColsAtCompileTime==1 ? Vertical : Horizontal }; typedef Homogeneous HomogeneousReturnType; - HomogeneousReturnType homogeneous() const; - #endif - + EIGEN_DEVICE_FUNC + inline HomogeneousReturnType homogeneous() const; + enum { SizeMinusOne = SizeAtCompileTime==Dynamic ? Dynamic : SizeAtCompileTime-1 }; typedef Block::ColsAtCompileTime==1 ? SizeMinusOne : 1, internal::traits::ColsAtCompileTime==1 ? 1 : SizeMinusOne> ConstStartMinusOne; - typedef CwiseUnaryOp::Scalar>, - const ConstStartMinusOne > HNormalizedReturnType; - - const HNormalizedReturnType hnormalized() const; + typedef EIGEN_EXPR_BINARYOP_SCALAR_RETURN_TYPE(ConstStartMinusOne,Scalar,quotient) HNormalizedReturnType; + EIGEN_DEVICE_FUNC + inline const HNormalizedReturnType hnormalized() const; ////////// Householder module /////////// @@ -461,49 +462,15 @@ template class MatrixBase const MatrixSquareRootReturnValue sqrt() const; const MatrixLogarithmReturnValue log() const; const MatrixPowerReturnValue pow(const RealScalar& p) const; - -#ifdef EIGEN2_SUPPORT - template - Derived& operator+=(const Flagged, 0, - EvalBeforeAssigningBit>& other); - - template - Derived& operator-=(const Flagged, 0, - EvalBeforeAssigningBit>& other); - - /** \deprecated because .lazy() is deprecated - * Overloaded for cache friendly product evaluation */ - template - Derived& lazyAssign(const Flagged& other) - { return lazyAssign(other._expression()); } - - template - const Flagged marked() const; - const Flagged lazy() const; - - inline const Cwise cwise() const; - inline Cwise cwise(); - - VectorBlock start(Index size); - const VectorBlock start(Index size) const; - VectorBlock end(Index size); - const VectorBlock end(Index size) const; - template VectorBlock start(); - template const VectorBlock start() const; - template VectorBlock end(); - template const VectorBlock end() const; - - Minor minor(Index row, Index col); - const Minor minor(Index row, Index col) const; -#endif + const MatrixComplexPowerReturnValue pow(const std::complex& p) const; protected: - MatrixBase() : Base() {} + EIGEN_DEVICE_FUNC MatrixBase() : Base() {} private: - explicit MatrixBase(int); - MatrixBase(int,int); - template explicit MatrixBase(const MatrixBase&); + EIGEN_DEVICE_FUNC explicit MatrixBase(int); + EIGEN_DEVICE_FUNC MatrixBase(int,int); + template EIGEN_DEVICE_FUNC explicit MatrixBase(const MatrixBase&); protected: // mixing arrays and matrices is not legal template Derived& operator+=(const ArrayBase& ) diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Core/NestByValue.h b/ground/gcs/src/libs/eigen/Eigen/src/Core/NestByValue.h index a893b1761b..13adf070e8 100644 --- a/ground/gcs/src/libs/eigen/Eigen/src/Core/NestByValue.h +++ b/ground/gcs/src/libs/eigen/Eigen/src/Core/NestByValue.h @@ -13,25 +13,24 @@ namespace Eigen { +namespace internal { +template +struct traits > : public traits +{}; +} + /** \class NestByValue * \ingroup Core_Module * * \brief Expression which must be nested by value * - * \param ExpressionType the type of the object of which we are requiring nesting-by-value + * \tparam ExpressionType the type of the object of which we are requiring nesting-by-value * * This class is the return type of MatrixBase::nestByValue() * and most of the time this is the only way it is used. * * \sa MatrixBase::nestByValue() */ - -namespace internal { -template -struct traits > : public traits -{}; -} - template class NestByValue : public internal::dense_xpr_base< NestByValue >::type { @@ -40,29 +39,29 @@ template class NestByValue typedef typename internal::dense_xpr_base::type Base; EIGEN_DENSE_PUBLIC_INTERFACE(NestByValue) - inline NestByValue(const ExpressionType& matrix) : m_expression(matrix) {} + EIGEN_DEVICE_FUNC explicit inline NestByValue(const ExpressionType& matrix) : m_expression(matrix) {} - inline Index rows() const { return m_expression.rows(); } - inline Index cols() const { return m_expression.cols(); } - inline Index outerStride() const { return m_expression.outerStride(); } - inline Index innerStride() const { return m_expression.innerStride(); } + EIGEN_DEVICE_FUNC inline Index rows() const { return m_expression.rows(); } + EIGEN_DEVICE_FUNC inline Index cols() const { return m_expression.cols(); } + EIGEN_DEVICE_FUNC inline Index outerStride() const { return m_expression.outerStride(); } + EIGEN_DEVICE_FUNC inline Index innerStride() const { return m_expression.innerStride(); } - inline const CoeffReturnType coeff(Index row, Index col) const + EIGEN_DEVICE_FUNC inline const CoeffReturnType coeff(Index row, Index col) const { return m_expression.coeff(row, col); } - inline Scalar& coeffRef(Index row, Index col) + EIGEN_DEVICE_FUNC inline Scalar& coeffRef(Index row, Index col) { return m_expression.const_cast_derived().coeffRef(row, col); } - inline const CoeffReturnType coeff(Index index) const + EIGEN_DEVICE_FUNC inline const CoeffReturnType coeff(Index index) const { return m_expression.coeff(index); } - inline Scalar& coeffRef(Index index) + EIGEN_DEVICE_FUNC inline Scalar& coeffRef(Index index) { return m_expression.const_cast_derived().coeffRef(index); } @@ -91,7 +90,7 @@ template class NestByValue m_expression.const_cast_derived().template writePacket(index, x); } - operator const ExpressionType&() const { return m_expression; } + EIGEN_DEVICE_FUNC operator const ExpressionType&() const { return m_expression; } protected: const ExpressionType m_expression; diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Core/NoAlias.h b/ground/gcs/src/libs/eigen/Eigen/src/Core/NoAlias.h index 768bfb18ca..33908010b4 100644 --- a/ground/gcs/src/libs/eigen/Eigen/src/Core/NoAlias.h +++ b/ground/gcs/src/libs/eigen/Eigen/src/Core/NoAlias.h @@ -17,7 +17,7 @@ namespace Eigen { * * \brief Pseudo expression providing an operator = assuming no aliasing * - * \param ExpressionType the type of the object on which to do the lazy assignment + * \tparam ExpressionType the type of the object on which to do the lazy assignment * * This class represents an expression with special assignment operators * assuming no aliasing between the target expression and the source expression. @@ -30,62 +30,36 @@ namespace Eigen { template class StorageBase> class NoAlias { - typedef typename ExpressionType::Scalar Scalar; public: - NoAlias(ExpressionType& expression) : m_expression(expression) {} - - /** Behaves like MatrixBase::lazyAssign(other) - * \sa MatrixBase::lazyAssign() */ + typedef typename ExpressionType::Scalar Scalar; + + explicit NoAlias(ExpressionType& expression) : m_expression(expression) {} + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE ExpressionType& operator=(const StorageBase& other) - { return internal::assign_selector::run(m_expression,other.derived()); } - - /** \sa MatrixBase::operator+= */ + { + call_assignment_no_alias(m_expression, other.derived(), internal::assign_op()); + return m_expression; + } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE ExpressionType& operator+=(const StorageBase& other) { - typedef SelfCwiseBinaryOp, ExpressionType, OtherDerived> SelfAdder; - SelfAdder tmp(m_expression); - typedef typename internal::nested::type OtherDerivedNested; - typedef typename internal::remove_all::type _OtherDerivedNested; - internal::assign_selector::run(tmp,OtherDerivedNested(other.derived())); + call_assignment_no_alias(m_expression, other.derived(), internal::add_assign_op()); return m_expression; } - - /** \sa MatrixBase::operator-= */ + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE ExpressionType& operator-=(const StorageBase& other) { - typedef SelfCwiseBinaryOp, ExpressionType, OtherDerived> SelfAdder; - SelfAdder tmp(m_expression); - typedef typename internal::nested::type OtherDerivedNested; - typedef typename internal::remove_all::type _OtherDerivedNested; - internal::assign_selector::run(tmp,OtherDerivedNested(other.derived())); + call_assignment_no_alias(m_expression, other.derived(), internal::sub_assign_op()); return m_expression; } -#ifndef EIGEN_PARSED_BY_DOXYGEN - template - EIGEN_STRONG_INLINE ExpressionType& operator+=(const ProductBase& other) - { other.derived().addTo(m_expression); return m_expression; } - - template - EIGEN_STRONG_INLINE ExpressionType& operator-=(const ProductBase& other) - { other.derived().subTo(m_expression); return m_expression; } - - template - EIGEN_STRONG_INLINE ExpressionType& operator+=(const CoeffBasedProduct& other) - { return m_expression.derived() += CoeffBasedProduct(other.lhs(), other.rhs()); } - - template - EIGEN_STRONG_INLINE ExpressionType& operator-=(const CoeffBasedProduct& other) - { return m_expression.derived() -= CoeffBasedProduct(other.lhs(), other.rhs()); } - - template - ExpressionType& operator=(const ReturnByValue& func) - { return m_expression = func; } -#endif - + EIGEN_DEVICE_FUNC ExpressionType& expression() const { return m_expression; @@ -126,7 +100,7 @@ class NoAlias template NoAlias MatrixBase::noalias() { - return derived(); + return NoAlias(derived()); } } // end namespace Eigen diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Core/NumTraits.h b/ground/gcs/src/libs/eigen/Eigen/src/Core/NumTraits.h index bac9e50b85..dd61195bc2 100644 --- a/ground/gcs/src/libs/eigen/Eigen/src/Core/NumTraits.h +++ b/ground/gcs/src/libs/eigen/Eigen/src/Core/NumTraits.h @@ -12,24 +12,57 @@ namespace Eigen { +namespace internal { + +// default implementation of digits10(), based on numeric_limits if specialized, +// 0 for integer types, and log10(epsilon()) otherwise. +template< typename T, + bool use_numeric_limits = std::numeric_limits::is_specialized, + bool is_integer = NumTraits::IsInteger> +struct default_digits10_impl +{ + static int run() { return std::numeric_limits::digits10; } +}; + +template +struct default_digits10_impl // Floating point +{ + static int run() { + using std::log10; + using std::ceil; + typedef typename NumTraits::Real Real; + return int(ceil(-log10(NumTraits::epsilon()))); + } +}; + +template +struct default_digits10_impl // Integer +{ + static int run() { return 0; } +}; + +} // end namespace internal + /** \class NumTraits * \ingroup Core_Module * * \brief Holds information about the various numeric (i.e. scalar) types allowed by Eigen. * - * \param T the numeric type at hand + * \tparam T the numeric type at hand * * This class stores enums, typedefs and static methods giving information about a numeric type. * * The provided data consists of: - * \li A typedef \a Real, giving the "real part" type of \a T. If \a T is already real, - * then \a Real is just a typedef to \a T. If \a T is \c std::complex then \a Real + * \li A typedef \c Real, giving the "real part" type of \a T. If \a T is already real, + * then \c Real is just a typedef to \a T. If \a T is \c std::complex then \c Real * is a typedef to \a U. - * \li A typedef \a NonInteger, giving the type that should be used for operations producing non-integral values, + * \li A typedef \c NonInteger, giving the type that should be used for operations producing non-integral values, * such as quotients, square roots, etc. If \a T is a floating-point type, then this typedef just gives * \a T again. Note however that many Eigen functions such as internal::sqrt simply refuse to * take integers. Outside of a few cases, Eigen doesn't do automatic type promotion. Thus, this typedef is * only intended as a helper for code that needs to explicitly promote types. + * \li A typedef \c Literal giving the type to use for numeric literals such as "2" or "0.5". For instance, for \c std::complex, Literal is defined as \c U. + * Of course, this type must be fully compatible with \a T. In doubt, just use \a T here. * \li A typedef \a Nested giving the type to use to nest a value inside of the expression tree. If you don't know what * this means, just use \a T here. * \li An enum value \a IsComplex. It is equal to 1 if \a T is a \c std::complex @@ -42,10 +75,14 @@ namespace Eigen { * \li An enum value \a IsSigned. It is equal to \c 1 if \a T is a signed type and to 0 if \a T is unsigned. * \li An enum value \a RequireInitialization. It is equal to \c 1 if the constructor of the numeric type \a T must * be called, and to 0 if it is safe not to call it. Default is 0 if \a T is an arithmetic type, and 1 otherwise. - * \li An epsilon() function which, unlike std::numeric_limits::epsilon(), returns a \a Real instead of a \a T. + * \li An epsilon() function which, unlike std::numeric_limits::epsilon(), + * it returns a \a Real instead of a \a T. * \li A dummy_precision() function returning a weak epsilon value. It is mainly used as a default * value by the fuzzy comparison operators. * \li highest() and lowest() functions returning the highest and lowest possible values respectively. + * \li digits10() function returning the number of decimal digits that can be represented without change. This is + * the analogue of std::numeric_limits::digits10 + * which is used as the default implementation if specialized. */ template struct GenericNumTraits @@ -67,22 +104,47 @@ template struct GenericNumTraits T >::type NonInteger; typedef T Nested; + typedef T Literal; + + EIGEN_DEVICE_FUNC + static inline Real epsilon() + { + return numext::numeric_limits::epsilon(); + } - static inline Real epsilon() { return std::numeric_limits::epsilon(); } + EIGEN_DEVICE_FUNC + static inline int digits10() + { + return internal::default_digits10_impl::run(); + } + + EIGEN_DEVICE_FUNC static inline Real dummy_precision() { // make sure to override this for floating-point types return Real(0); } - static inline T highest() { return (std::numeric_limits::max)(); } - static inline T lowest() { return IsInteger ? (std::numeric_limits::min)() : (-(std::numeric_limits::max)()); } - -#ifdef EIGEN2_SUPPORT - enum { - HasFloatingPoint = !IsInteger - }; - typedef NonInteger FloatingPoint; -#endif + + + EIGEN_DEVICE_FUNC + static inline T highest() { + return (numext::numeric_limits::max)(); + } + + EIGEN_DEVICE_FUNC + static inline T lowest() { + return IsInteger ? (numext::numeric_limits::min)() : (-(numext::numeric_limits::max)()); + } + + EIGEN_DEVICE_FUNC + static inline T infinity() { + return numext::numeric_limits::infinity(); + } + + EIGEN_DEVICE_FUNC + static inline T quiet_NaN() { + return numext::numeric_limits::quiet_NaN(); + } }; template struct NumTraits : GenericNumTraits @@ -91,11 +153,13 @@ template struct NumTraits : GenericNumTraits template<> struct NumTraits : GenericNumTraits { + EIGEN_DEVICE_FUNC static inline float dummy_precision() { return 1e-5f; } }; template<> struct NumTraits : GenericNumTraits { + EIGEN_DEVICE_FUNC static inline double dummy_precision() { return 1e-12; } }; @@ -109,6 +173,7 @@ template struct NumTraits > : GenericNumTraits > { typedef _Real Real; + typedef typename NumTraits<_Real>::Literal Literal; enum { IsComplex = 1, RequireInitialization = NumTraits<_Real>::RequireInitialization, @@ -117,8 +182,12 @@ template struct NumTraits > MulCost = 4 * NumTraits::MulCost + 2 * NumTraits::AddCost }; + EIGEN_DEVICE_FUNC static inline Real epsilon() { return NumTraits::epsilon(); } + EIGEN_DEVICE_FUNC static inline Real dummy_precision() { return NumTraits::dummy_precision(); } + EIGEN_DEVICE_FUNC + static inline int digits10() { return NumTraits::digits10(); } }; template @@ -130,21 +199,48 @@ struct NumTraits > typedef typename NumTraits::NonInteger NonIntegerScalar; typedef Array NonInteger; typedef ArrayType & Nested; - + typedef typename NumTraits::Literal Literal; + enum { IsComplex = NumTraits::IsComplex, IsInteger = NumTraits::IsInteger, IsSigned = NumTraits::IsSigned, RequireInitialization = 1, - ReadCost = ArrayType::SizeAtCompileTime==Dynamic ? Dynamic : ArrayType::SizeAtCompileTime * NumTraits::ReadCost, - AddCost = ArrayType::SizeAtCompileTime==Dynamic ? Dynamic : ArrayType::SizeAtCompileTime * NumTraits::AddCost, - MulCost = ArrayType::SizeAtCompileTime==Dynamic ? Dynamic : ArrayType::SizeAtCompileTime * NumTraits::MulCost + ReadCost = ArrayType::SizeAtCompileTime==Dynamic ? HugeCost : ArrayType::SizeAtCompileTime * NumTraits::ReadCost, + AddCost = ArrayType::SizeAtCompileTime==Dynamic ? HugeCost : ArrayType::SizeAtCompileTime * NumTraits::AddCost, + MulCost = ArrayType::SizeAtCompileTime==Dynamic ? HugeCost : ArrayType::SizeAtCompileTime * NumTraits::MulCost }; - + + EIGEN_DEVICE_FUNC static inline RealScalar epsilon() { return NumTraits::epsilon(); } + EIGEN_DEVICE_FUNC static inline RealScalar dummy_precision() { return NumTraits::dummy_precision(); } }; +template<> struct NumTraits + : GenericNumTraits +{ + enum { + RequireInitialization = 1, + ReadCost = HugeCost, + AddCost = HugeCost, + MulCost = HugeCost + }; + + static inline int digits10() { return 0; } + +private: + static inline std::string epsilon(); + static inline std::string dummy_precision(); + static inline std::string lowest(); + static inline std::string highest(); + static inline std::string infinity(); + static inline std::string quiet_NaN(); +}; + +// Empty specialization for void to allow template specialization based on NumTraits::Real with T==void and SFINAE. +template<> struct NumTraits {}; + } // end namespace Eigen #endif // EIGEN_NUMTRAITS_H diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Core/PermutationMatrix.h b/ground/gcs/src/libs/eigen/Eigen/src/Core/PermutationMatrix.h index 85ffae2653..b1fb455b98 100644 --- a/ground/gcs/src/libs/eigen/Eigen/src/Core/PermutationMatrix.h +++ b/ground/gcs/src/libs/eigen/Eigen/src/Core/PermutationMatrix.h @@ -2,7 +2,7 @@ // for linear algebra. // // Copyright (C) 2009 Benoit Jacob -// Copyright (C) 2009-2011 Gael Guennebaud +// Copyright (C) 2009-2015 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -13,14 +13,18 @@ namespace Eigen { -template class PermutedImpl; +namespace internal { + +enum PermPermProduct_t {PermPermProduct}; + +} // end namespace internal /** \class PermutationBase * \ingroup Core_Module * * \brief Base class for permutations * - * \param Derived the derived class + * \tparam Derived the derived class * * This class is the base class for all expressions representing a permutation matrix, * internally stored as a vector of integers. @@ -38,17 +42,6 @@ template -struct permut_matrix_product_retval; -template -struct permut_sparsematrix_product_retval; -enum PermPermProduct_t {PermPermProduct}; - -} // end namespace internal - template class PermutationBase : public EigenBase { @@ -60,19 +53,20 @@ class PermutationBase : public EigenBase typedef typename Traits::IndicesType IndicesType; enum { Flags = Traits::Flags, - CoeffReadCost = Traits::CoeffReadCost, RowsAtCompileTime = Traits::RowsAtCompileTime, ColsAtCompileTime = Traits::ColsAtCompileTime, MaxRowsAtCompileTime = Traits::MaxRowsAtCompileTime, MaxColsAtCompileTime = Traits::MaxColsAtCompileTime }; - typedef typename Traits::Scalar Scalar; - typedef typename Traits::Index Index; - typedef Matrix + typedef typename Traits::StorageIndex StorageIndex; + typedef Matrix DenseMatrixType; - typedef PermutationMatrix + typedef PermutationMatrix PlainPermutationType; + typedef PlainPermutationType PlainObject; using Base::derived; + typedef Inverse InverseReturnType; + typedef void Scalar; #endif /** Copies the other permutation into *this */ @@ -118,7 +112,7 @@ class PermutationBase : public EigenBase void evalTo(MatrixBase& other) const { other.setZero(); - for (int i=0; i /** Sets *this to be the identity permutation matrix */ void setIdentity() { - for(Index i = 0; i < size(); ++i) + StorageIndex n = StorageIndex(size()); + for(StorageIndex i = 0; i < n; ++i) indices().coeffRef(i) = i; } @@ -163,18 +158,18 @@ class PermutationBase : public EigenBase * * \returns a reference to *this. * - * \warning This is much slower than applyTranspositionOnTheRight(int,int): + * \warning This is much slower than applyTranspositionOnTheRight(Index,Index): * this has linear complexity and requires a lot of branching. * - * \sa applyTranspositionOnTheRight(int,int) + * \sa applyTranspositionOnTheRight(Index,Index) */ Derived& applyTranspositionOnTheLeft(Index i, Index j) { eigen_assert(i>=0 && j>=0 && i * * This is a fast operation, it only consists in swapping two indices. * - * \sa applyTranspositionOnTheLeft(int,int) + * \sa applyTranspositionOnTheLeft(Index,Index) */ Derived& applyTranspositionOnTheRight(Index i, Index j) { @@ -196,16 +191,16 @@ class PermutationBase : public EigenBase /** \returns the inverse permutation matrix. * - * \note \note_try_to_help_rvo + * \note \blank \note_try_to_help_rvo */ - inline Transpose inverse() const - { return derived(); } + inline InverseReturnType inverse() const + { return InverseReturnType(derived()); } /** \returns the tranpose permutation matrix. * - * \note \note_try_to_help_rvo + * \note \blank \note_try_to_help_rvo */ - inline Transpose transpose() const - { return derived(); } + inline InverseReturnType transpose() const + { return InverseReturnType(derived()); } /**** multiplication helpers to hopefully get RVO ****/ @@ -215,13 +210,13 @@ class PermutationBase : public EigenBase template void assignTranspose(const PermutationBase& other) { - for (int i=0; i void assignProduct(const Lhs& lhs, const Rhs& rhs) { eigen_assert(lhs.cols() == rhs.rows()); - for (int i=0; i /** \returns the product permutation matrix. * - * \note \note_try_to_help_rvo + * \note \blank \note_try_to_help_rvo */ template inline PlainPermutationType operator*(const PermutationBase& other) const @@ -237,18 +232,18 @@ class PermutationBase : public EigenBase /** \returns the product of a permutation with another inverse permutation. * - * \note \note_try_to_help_rvo + * \note \blank \note_try_to_help_rvo */ template - inline PlainPermutationType operator*(const Transpose >& other) const + inline PlainPermutationType operator*(const InverseImpl& other) const { return PlainPermutationType(internal::PermPermProduct, *this, other.eval()); } /** \returns the product of an inverse permutation with another permutation. * - * \note \note_try_to_help_rvo + * \note \blank \note_try_to_help_rvo */ template friend - inline PlainPermutationType operator*(const Transpose >& other, const PermutationBase& perm) + inline PlainPermutationType operator*(const InverseImpl& other, const PermutationBase& perm) { return PlainPermutationType(internal::PermPermProduct, other.eval(), perm); } /** \returns the determinant of the permutation matrix, which is either 1 or -1 depending on the parity of the permutation. @@ -284,39 +279,43 @@ class PermutationBase : public EigenBase }; +namespace internal { +template +struct traits > + : traits > +{ + typedef PermutationStorage StorageKind; + typedef Matrix<_StorageIndex, SizeAtCompileTime, 1, 0, MaxSizeAtCompileTime, 1> IndicesType; + typedef _StorageIndex StorageIndex; + typedef void Scalar; +}; +} + /** \class PermutationMatrix * \ingroup Core_Module * * \brief Permutation matrix * - * \param SizeAtCompileTime the number of rows/cols, or Dynamic - * \param MaxSizeAtCompileTime the maximum number of rows/cols, or Dynamic. This optional parameter defaults to SizeAtCompileTime. Most of the time, you should not have to specify it. - * \param IndexType the interger type of the indices + * \tparam SizeAtCompileTime the number of rows/cols, or Dynamic + * \tparam MaxSizeAtCompileTime the maximum number of rows/cols, or Dynamic. This optional parameter defaults to SizeAtCompileTime. Most of the time, you should not have to specify it. + * \tparam _StorageIndex the integer type of the indices * * This class represents a permutation matrix, internally stored as a vector of integers. * * \sa class PermutationBase, class PermutationWrapper, class DiagonalMatrix */ - -namespace internal { -template -struct traits > - : traits > -{ - typedef IndexType Index; - typedef Matrix IndicesType; -}; -} - -template -class PermutationMatrix : public PermutationBase > +template +class PermutationMatrix : public PermutationBase > { typedef PermutationBase Base; typedef internal::traits Traits; public: + typedef const PermutationMatrix& Nested; + #ifndef EIGEN_PARSED_BY_DOXYGEN typedef typename Traits::IndicesType IndicesType; + typedef typename Traits::StorageIndex StorageIndex; #endif inline PermutationMatrix() @@ -324,8 +323,10 @@ class PermutationMatrix : public PermutationBase::highest()); + } /** Copy constructor. */ template @@ -346,7 +347,7 @@ class PermutationMatrix : public PermutationBase - explicit inline PermutationMatrix(const MatrixBase& a_indices) : m_indices(a_indices) + explicit inline PermutationMatrix(const MatrixBase& indices) : m_indices(indices) {} /** Convert the Transpositions \a tr to a permutation matrix */ @@ -393,10 +394,13 @@ class PermutationMatrix : public PermutationBase - PermutationMatrix(const Transpose >& other) - : m_indices(other.nestedPermutation().size()) + PermutationMatrix(const InverseImpl& other) + : m_indices(other.derived().nestedExpression().size()) { - for (int i=0; i::highest()); + StorageIndex end = StorageIndex(m_indices.size()); + for (StorageIndex i=0; i PermutationMatrix(internal::PermPermProduct_t, const Lhs& lhs, const Rhs& rhs) @@ -413,18 +417,20 @@ class PermutationMatrix : public PermutationBase -struct traits,_PacketAccess> > - : traits > +template +struct traits,_PacketAccess> > + : traits > { - typedef IndexType Index; - typedef Map, _PacketAccess> IndicesType; + typedef PermutationStorage StorageKind; + typedef Map, _PacketAccess> IndicesType; + typedef _StorageIndex StorageIndex; + typedef void Scalar; }; } -template -class Map,_PacketAccess> - : public PermutationBase,_PacketAccess> > +template +class Map,_PacketAccess> + : public PermutationBase,_PacketAccess> > { typedef PermutationBase Base; typedef internal::traits Traits; @@ -432,14 +438,14 @@ class Map, #ifndef EIGEN_PARSED_BY_DOXYGEN typedef typename Traits::IndicesType IndicesType; - typedef typename IndicesType::Scalar Index; + typedef typename IndicesType::Scalar StorageIndex; #endif - inline Map(const Index* indicesPtr) + inline Map(const StorageIndex* indicesPtr) : m_indices(indicesPtr) {} - inline Map(const Index* indicesPtr, Index size) + inline Map(const StorageIndex* indicesPtr, Index size) : m_indices(indicesPtr,size) {} @@ -474,40 +480,36 @@ class Map, IndicesType m_indices; }; -/** \class PermutationWrapper - * \ingroup Core_Module - * - * \brief Class to view a vector of integers as a permutation matrix - * - * \param _IndicesType the type of the vector of integer (can be any compatible expression) - * - * This class allows to view any vector expression of integers as a permutation matrix. - * - * \sa class PermutationBase, class PermutationMatrix - */ - -struct PermutationStorage {}; - template class TranspositionsWrapper; namespace internal { template struct traits > { typedef PermutationStorage StorageKind; - typedef typename _IndicesType::Scalar Scalar; - typedef typename _IndicesType::Scalar Index; + typedef void Scalar; + typedef typename _IndicesType::Scalar StorageIndex; typedef _IndicesType IndicesType; enum { RowsAtCompileTime = _IndicesType::SizeAtCompileTime, ColsAtCompileTime = _IndicesType::SizeAtCompileTime, - MaxRowsAtCompileTime = IndicesType::MaxRowsAtCompileTime, - MaxColsAtCompileTime = IndicesType::MaxColsAtCompileTime, - Flags = 0, - CoeffReadCost = _IndicesType::CoeffReadCost + MaxRowsAtCompileTime = IndicesType::MaxSizeAtCompileTime, + MaxColsAtCompileTime = IndicesType::MaxSizeAtCompileTime, + Flags = 0 }; }; } +/** \class PermutationWrapper + * \ingroup Core_Module + * + * \brief Class to view a vector of integers as a permutation matrix + * + * \tparam _IndicesType the type of the vector of integer (can be any compatible expression) + * + * This class allows to view any vector expression of integers as a permutation matrix. + * + * \sa class PermutationBase, class PermutationMatrix + */ template class PermutationWrapper : public PermutationBase > { @@ -519,8 +521,8 @@ class PermutationWrapper : public PermutationBase -inline const internal::permut_matrix_product_retval -operator*(const MatrixBase& matrix, - const PermutationBase &permutation) +template +EIGEN_DEVICE_FUNC +const Product +operator*(const MatrixBase &matrix, + const PermutationBase& permutation) { - return internal::permut_matrix_product_retval - - (permutation.derived(), matrix.derived()); + return Product + (matrix.derived(), permutation.derived()); } /** \returns the matrix with the permutation applied to the rows. */ -template -inline const internal::permut_matrix_product_retval - +template +EIGEN_DEVICE_FUNC +const Product operator*(const PermutationBase &permutation, - const MatrixBase& matrix) + const MatrixBase& matrix) { - return internal::permut_matrix_product_retval - - (permutation.derived(), matrix.derived()); + return Product + (permutation.derived(), matrix.derived()); } -namespace internal { -template -struct traits > +template +class InverseImpl + : public EigenBase > { - typedef typename MatrixType::PlainObject ReturnType; -}; - -template -struct permut_matrix_product_retval - : public ReturnByValue > -{ - typedef typename remove_all::type MatrixTypeNestedCleaned; - typedef typename MatrixType::Index Index; - - permut_matrix_product_retval(const PermutationType& perm, const MatrixType& matrix) - : m_permutation(perm), m_matrix(matrix) - {} - - inline Index rows() const { return m_matrix.rows(); } - inline Index cols() const { return m_matrix.cols(); } - - template inline void evalTo(Dest& dst) const - { - const Index n = Side==OnTheLeft ? rows() : cols(); - // FIXME we need an is_same for expression that is not sensitive to constness. For instance - // is_same_xpr, Block >::value should be true. - if( is_same::value - && blas_traits::HasUsableDirectAccess - && blas_traits::HasUsableDirectAccess - && extract_data(dst) == extract_data(m_matrix)) - { - // apply the permutation inplace - Matrix mask(m_permutation.size()); - mask.fill(false); - Index r = 0; - while(r < m_permutation.size()) - { - // search for the next seed - while(r=m_permutation.size()) - break; - // we got one, let's follow it until we are back to the seed - Index k0 = r++; - Index kPrev = k0; - mask.coeffRef(k0) = true; - for(Index k=m_permutation.indices().coeff(k0); k!=k0; k=m_permutation.indices().coeff(k)) - { - Block(dst, k) - .swap(Block - (dst,((Side==OnTheLeft) ^ Transposed) ? k0 : kPrev)); - - mask.coeffRef(k) = true; - kPrev = k; - } - } - } - else - { - for(int i = 0; i < n; ++i) - { - Block - (dst, ((Side==OnTheLeft) ^ Transposed) ? m_permutation.indices().coeff(i) : i) - - = - - Block - (m_matrix, ((Side==OnTheRight) ^ Transposed) ? m_permutation.indices().coeff(i) : i); - } - } - } - - protected: - const PermutationType& m_permutation; - typename MatrixType::Nested m_matrix; -}; - -/* Template partial specialization for transposed/inverse permutations */ - -template -struct traits > > - : traits -{}; - -} // end namespace internal - -template -class Transpose > - : public EigenBase > > -{ - typedef Derived PermutationType; - typedef typename PermutationType::IndicesType IndicesType; typedef typename PermutationType::PlainPermutationType PlainPermutationType; + typedef internal::traits PermTraits; + protected: + InverseImpl() {} public: + typedef Inverse InverseType; + using EigenBase >::derived; #ifndef EIGEN_PARSED_BY_DOXYGEN - typedef internal::traits Traits; - typedef typename Derived::DenseMatrixType DenseMatrixType; + typedef typename PermutationType::DenseMatrixType DenseMatrixType; enum { - Flags = Traits::Flags, - CoeffReadCost = Traits::CoeffReadCost, - RowsAtCompileTime = Traits::RowsAtCompileTime, - ColsAtCompileTime = Traits::ColsAtCompileTime, - MaxRowsAtCompileTime = Traits::MaxRowsAtCompileTime, - MaxColsAtCompileTime = Traits::MaxColsAtCompileTime + RowsAtCompileTime = PermTraits::RowsAtCompileTime, + ColsAtCompileTime = PermTraits::ColsAtCompileTime, + MaxRowsAtCompileTime = PermTraits::MaxRowsAtCompileTime, + MaxColsAtCompileTime = PermTraits::MaxColsAtCompileTime }; - typedef typename Traits::Scalar Scalar; #endif - Transpose(const PermutationType& p) : m_permutation(p) {} - - inline int rows() const { return m_permutation.rows(); } - inline int cols() const { return m_permutation.cols(); } - #ifndef EIGEN_PARSED_BY_DOXYGEN template void evalTo(MatrixBase& other) const { other.setZero(); - for (int i=0; i friend - inline const internal::permut_matrix_product_retval - operator*(const MatrixBase& matrix, const Transpose& trPerm) + const Product + operator*(const MatrixBase& matrix, const InverseType& trPerm) { - return internal::permut_matrix_product_retval(trPerm.m_permutation, matrix.derived()); + return Product(matrix.derived(), trPerm.derived()); } /** \returns the matrix with the inverse permutation applied to the rows. */ template - inline const internal::permut_matrix_product_retval + const Product operator*(const MatrixBase& matrix) const { - return internal::permut_matrix_product_retval(m_permutation, matrix.derived()); + return Product(derived(), matrix.derived()); } - - const PermutationType& nestedPermutation() const { return m_permutation; } - - protected: - const PermutationType& m_permutation; }; template @@ -716,6 +622,12 @@ const PermutationWrapper MatrixBase::asPermutation() con return derived(); } +namespace internal { + +template<> struct AssignmentKind { typedef EigenBase2EigenBase Kind; }; + +} // end namespace internal + } // end namespace Eigen #endif // EIGEN_PERMUTATIONMATRIX_H diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Core/PlainObjectBase.h b/ground/gcs/src/libs/eigen/Eigen/src/Core/PlainObjectBase.h index a4e4af4a7b..77f4f60667 100644 --- a/ground/gcs/src/libs/eigen/Eigen/src/Core/PlainObjectBase.h +++ b/ground/gcs/src/libs/eigen/Eigen/src/Core/PlainObjectBase.h @@ -28,6 +28,7 @@ namespace internal { template struct check_rows_cols_for_overflow { template + EIGEN_DEVICE_FUNC static EIGEN_ALWAYS_INLINE void run(Index, Index) { } @@ -35,11 +36,12 @@ template struct check_rows_cols_for_overflow { template<> struct check_rows_cols_for_overflow { template + EIGEN_DEVICE_FUNC static EIGEN_ALWAYS_INLINE void run(Index rows, Index cols) { // http://hg.mozilla.org/mozilla-central/file/6c8a909977d3/xpcom/ds/CheckedInt.h#l242 // we assume Index is signed - Index max_index = (size_t(1) << (8 * sizeof(Index) - 1)) - 1; // assume Index is signed + Index max_index = (std::size_t(1) << (8 * sizeof(Index) - 1)) - 1; // assume Index is signed bool error = (rows == 0 || cols == 0) ? false : (rows > max_index / cols); if (error) @@ -56,33 +58,41 @@ template struct m } // end namespace internal -/** \class PlainObjectBase - * \brief %Dense storage base class for matrices and arrays. - * - * This class can be extended with the help of the plugin mechanism described on the page - * \ref TopicCustomizingEigen by defining the preprocessor symbol \c EIGEN_PLAINOBJECTBASE_PLUGIN. - * - * \sa \ref TopicClassHierarchy - */ #ifdef EIGEN_PARSED_BY_DOXYGEN -namespace internal { +namespace doxygen { -// this is a warkaround to doxygen not being able to understand the inheritence logic +// This is a workaround to doxygen not being able to understand the inheritance logic // when it is hidden by the dense_xpr_base helper struct. -template struct dense_xpr_base_dispatcher_for_doxygen;// : public MatrixBase {}; +// Moreover, doxygen fails to include members that are not documented in the declaration body of +// MatrixBase if we inherits MatrixBase >, +// this is why we simply inherits MatrixBase, though this does not make sense. + +/** This class is just a workaround for Doxygen and it does not not actually exist. */ +template struct dense_xpr_base_dispatcher; /** This class is just a workaround for Doxygen and it does not not actually exist. */ template -struct dense_xpr_base_dispatcher_for_doxygen > - : public MatrixBase > {}; +struct dense_xpr_base_dispatcher > + : public MatrixBase {}; /** This class is just a workaround for Doxygen and it does not not actually exist. */ template -struct dense_xpr_base_dispatcher_for_doxygen > - : public ArrayBase > {}; +struct dense_xpr_base_dispatcher > + : public ArrayBase {}; -} // namespace internal +} // namespace doxygen +/** \class PlainObjectBase + * \ingroup Core_Module + * \brief %Dense storage base class for matrices and arrays. + * + * This class can be extended with the help of the plugin mechanism described on the page + * \ref TopicCustomizing_Plugins by defining the preprocessor symbol \c EIGEN_PLAINOBJECTBASE_PLUGIN. + * + * \tparam Derived is the derived type, e.g., a Matrix or Array + * + * \sa \ref TopicClassHierarchy + */ template -class PlainObjectBase : public internal::dense_xpr_base_dispatcher_for_doxygen +class PlainObjectBase : public doxygen::dense_xpr_base_dispatcher #else template class PlainObjectBase : public internal::dense_xpr_base::type @@ -93,8 +103,8 @@ class PlainObjectBase : public internal::dense_xpr_base::type typedef typename internal::dense_xpr_base::type Base; typedef typename internal::traits::StorageKind StorageKind; - typedef typename internal::traits::Index Index; typedef typename internal::traits::Scalar Scalar; + typedef typename internal::packet_traits::type PacketScalar; typedef typename NumTraits::Real RealScalar; typedef Derived DenseType; @@ -113,28 +123,40 @@ class PlainObjectBase : public internal::dense_xpr_base::type typedef Eigen::Map MapType; friend class Eigen::Map; typedef const Eigen::Map ConstMapType; - friend class Eigen::Map; - typedef Eigen::Map AlignedMapType; - friend class Eigen::Map; - typedef const Eigen::Map ConstAlignedMapType; +#if EIGEN_MAX_ALIGN_BYTES>0 + // for EIGEN_MAX_ALIGN_BYTES==0, AlignedMax==Unaligned, and many compilers generate warnings for friend-ing a class twice. + friend class Eigen::Map; + friend class Eigen::Map; +#endif + typedef Eigen::Map AlignedMapType; + typedef const Eigen::Map ConstAlignedMapType; template struct StridedMapType { typedef Eigen::Map type; }; template struct StridedConstMapType { typedef Eigen::Map type; }; - template struct StridedAlignedMapType { typedef Eigen::Map type; }; - template struct StridedConstAlignedMapType { typedef Eigen::Map type; }; + template struct StridedAlignedMapType { typedef Eigen::Map type; }; + template struct StridedConstAlignedMapType { typedef Eigen::Map type; }; protected: DenseStorage m_storage; public: - enum { NeedsToAlign = SizeAtCompileTime != Dynamic && (internal::traits::Flags & AlignedBit) != 0 }; + enum { NeedsToAlign = (SizeAtCompileTime != Dynamic) && (internal::traits::Alignment>0) }; EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign) + EIGEN_DEVICE_FUNC Base& base() { return *static_cast(this); } + EIGEN_DEVICE_FUNC const Base& base() const { return *static_cast(this); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index rows() const { return m_storage.rows(); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index cols() const { return m_storage.cols(); } + /** This is an overloaded version of DenseCoeffsBase::coeff(Index,Index) const + * provided to by-pass the creation of an evaluator of the expression, thus saving compilation efforts. + * + * See DenseCoeffsBase::coeff(Index) const for details. */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar& coeff(Index rowId, Index colId) const { if(Flags & RowMajorBit) @@ -143,11 +165,21 @@ class PlainObjectBase : public internal::dense_xpr_base::type return m_storage.data()[rowId + colId * m_storage.rows()]; } + /** This is an overloaded version of DenseCoeffsBase::coeff(Index) const + * provided to by-pass the creation of an evaluator of the expression, thus saving compilation efforts. + * + * See DenseCoeffsBase::coeff(Index) const for details. */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar& coeff(Index index) const { return m_storage.data()[index]; } + /** This is an overloaded version of DenseCoeffsBase::coeffRef(Index,Index) const + * provided to by-pass the creation of an evaluator of the expression, thus saving compilation efforts. + * + * See DenseCoeffsBase::coeffRef(Index,Index) const for details. */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRef(Index rowId, Index colId) { if(Flags & RowMajorBit) @@ -156,11 +188,19 @@ class PlainObjectBase : public internal::dense_xpr_base::type return m_storage.data()[rowId + colId * m_storage.rows()]; } + /** This is an overloaded version of DenseCoeffsBase::coeffRef(Index) const + * provided to by-pass the creation of an evaluator of the expression, thus saving compilation efforts. + * + * See DenseCoeffsBase::coeffRef(Index) const for details. */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRef(Index index) { return m_storage.data()[index]; } + /** This is the const version of coeffRef(Index,Index) which is thus synonym of coeff(Index,Index). + * It is provided for convenience. */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar& coeffRef(Index rowId, Index colId) const { if(Flags & RowMajorBit) @@ -169,6 +209,9 @@ class PlainObjectBase : public internal::dense_xpr_base::type return m_storage.data()[rowId + colId * m_storage.rows()]; } + /** This is the const version of coeffRef(Index) which is thus synonym of coeff(Index). + * It is provided for convenience. */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar& coeffRef(Index index) const { return m_storage.data()[index]; @@ -209,11 +252,11 @@ class PlainObjectBase : public internal::dense_xpr_base::type } /** \returns a const pointer to the data array of this matrix */ - EIGEN_STRONG_INLINE const Scalar *data() const + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar *data() const { return m_storage.data(); } /** \returns a pointer to the data array of this matrix */ - EIGEN_STRONG_INLINE Scalar *data() + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar *data() { return m_storage.data(); } /** Resizes \c *this to a \a rows x \a cols matrix. @@ -232,22 +275,22 @@ class PlainObjectBase : public internal::dense_xpr_base::type * * \sa resize(Index) for vectors, resize(NoChange_t, Index), resize(Index, NoChange_t) */ - EIGEN_STRONG_INLINE void resize(Index nbRows, Index nbCols) - { - eigen_assert( EIGEN_IMPLIES(RowsAtCompileTime!=Dynamic,nbRows==RowsAtCompileTime) - && EIGEN_IMPLIES(ColsAtCompileTime!=Dynamic,nbCols==ColsAtCompileTime) - && EIGEN_IMPLIES(RowsAtCompileTime==Dynamic && MaxRowsAtCompileTime!=Dynamic,nbRows<=MaxRowsAtCompileTime) - && EIGEN_IMPLIES(ColsAtCompileTime==Dynamic && MaxColsAtCompileTime!=Dynamic,nbCols<=MaxColsAtCompileTime) - && nbRows>=0 && nbCols>=0 && "Invalid sizes when resizing a matrix or array."); - internal::check_rows_cols_for_overflow::run(nbRows, nbCols); + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void resize(Index rows, Index cols) + { + eigen_assert( EIGEN_IMPLIES(RowsAtCompileTime!=Dynamic,rows==RowsAtCompileTime) + && EIGEN_IMPLIES(ColsAtCompileTime!=Dynamic,cols==ColsAtCompileTime) + && EIGEN_IMPLIES(RowsAtCompileTime==Dynamic && MaxRowsAtCompileTime!=Dynamic,rows<=MaxRowsAtCompileTime) + && EIGEN_IMPLIES(ColsAtCompileTime==Dynamic && MaxColsAtCompileTime!=Dynamic,cols<=MaxColsAtCompileTime) + && rows>=0 && cols>=0 && "Invalid sizes when resizing a matrix or array."); + internal::check_rows_cols_for_overflow::run(rows, cols); #ifdef EIGEN_INITIALIZE_COEFFS - Index size = nbRows*nbCols; + Index size = rows*cols; bool size_changed = size != this->size(); - m_storage.resize(size, nbRows, nbCols); + m_storage.resize(size, rows, cols); if(size_changed) EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED #else - internal::check_rows_cols_for_overflow::run(nbRows, nbCols); - m_storage.resize(nbRows*nbCols, nbRows, nbCols); + m_storage.resize(rows*cols, rows, cols); #endif } @@ -262,6 +305,7 @@ class PlainObjectBase : public internal::dense_xpr_base::type * * \sa resize(Index,Index), resize(NoChange_t, Index), resize(Index, NoChange_t) */ + EIGEN_DEVICE_FUNC inline void resize(Index size) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(PlainObjectBase) @@ -286,9 +330,10 @@ class PlainObjectBase : public internal::dense_xpr_base::type * * \sa resize(Index,Index) */ - inline void resize(NoChange_t, Index nbCols) + EIGEN_DEVICE_FUNC + inline void resize(NoChange_t, Index cols) { - resize(rows(), nbCols); + resize(rows(), cols); } /** Resizes the matrix, changing only the number of rows. For the parameter of type NoChange_t, just pass the special value \c NoChange @@ -299,9 +344,10 @@ class PlainObjectBase : public internal::dense_xpr_base::type * * \sa resize(Index,Index) */ - inline void resize(Index nbRows, NoChange_t) + EIGEN_DEVICE_FUNC + inline void resize(Index rows, NoChange_t) { - resize(nbRows, cols()); + resize(rows, cols()); } /** Resizes \c *this to have the same dimensions as \a other. @@ -312,6 +358,7 @@ class PlainObjectBase : public internal::dense_xpr_base::type * remain row-vectors and vectors remain vectors. */ template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void resizeLike(const EigenBase& _other) { const OtherDerived& other = _other.derived(); @@ -339,9 +386,10 @@ class PlainObjectBase : public internal::dense_xpr_base::type * Matrices are resized relative to the top-left element. In case values need to be * appended to the matrix they will be uninitialized. */ - EIGEN_STRONG_INLINE void conservativeResize(Index nbRows, Index nbCols) + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void conservativeResize(Index rows, Index cols) { - internal::conservative_resize_like_impl::run(*this, nbRows, nbCols); + internal::conservative_resize_like_impl::run(*this, rows, cols); } /** Resizes the matrix to \a rows x \a cols while leaving old values untouched. @@ -351,10 +399,11 @@ class PlainObjectBase : public internal::dense_xpr_base::type * * In case the matrix is growing, new rows will be uninitialized. */ - EIGEN_STRONG_INLINE void conservativeResize(Index nbRows, NoChange_t) + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void conservativeResize(Index rows, NoChange_t) { // Note: see the comment in conservativeResize(Index,Index) - conservativeResize(nbRows, cols()); + conservativeResize(rows, cols()); } /** Resizes the matrix to \a rows x \a cols while leaving old values untouched. @@ -364,10 +413,11 @@ class PlainObjectBase : public internal::dense_xpr_base::type * * In case the matrix is growing, new columns will be uninitialized. */ - EIGEN_STRONG_INLINE void conservativeResize(NoChange_t, Index nbCols) + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void conservativeResize(NoChange_t, Index cols) { // Note: see the comment in conservativeResize(Index,Index) - conservativeResize(rows(), nbCols); + conservativeResize(rows(), cols); } /** Resizes the vector to \a size while retaining old values. @@ -378,6 +428,7 @@ class PlainObjectBase : public internal::dense_xpr_base::type * * When values are appended, they will be uninitialized. */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void conservativeResize(Index size) { internal::conservative_resize_like_impl::run(*this, size); @@ -393,6 +444,7 @@ class PlainObjectBase : public internal::dense_xpr_base::type * appended to the matrix they will copied from \c other. */ template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void conservativeResizeLike(const DenseBase& other) { internal::conservative_resize_like_impl::run(*this, other); @@ -401,6 +453,7 @@ class PlainObjectBase : public internal::dense_xpr_base::type /** This is a special case of the templated operator=. Its purpose is to * prevent a default operator= from hiding the templated operator=. */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator=(const PlainObjectBase& other) { return _set(other); @@ -408,6 +461,7 @@ class PlainObjectBase : public internal::dense_xpr_base::type /** \sa MatrixBase::lazyAssign() */ template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& lazyAssign(const DenseBase& other) { _resize_to_match(other); @@ -415,12 +469,18 @@ class PlainObjectBase : public internal::dense_xpr_base::type } template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator=(const ReturnByValue& func) { resize(func.rows(), func.cols()); return Base::operator=(func); } + // Prevent user from trying to instantiate PlainObjectBase objects + // by making all its constructor protected. See bug 1074. + protected: + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PlainObjectBase() : m_storage() { // _check_template_params(); @@ -430,20 +490,23 @@ class PlainObjectBase : public internal::dense_xpr_base::type #ifndef EIGEN_PARSED_BY_DOXYGEN // FIXME is it still needed ? /** \internal */ - PlainObjectBase(internal::constructor_without_unaligned_array_assert) + EIGEN_DEVICE_FUNC + explicit PlainObjectBase(internal::constructor_without_unaligned_array_assert) : m_storage(internal::constructor_without_unaligned_array_assert()) { // _check_template_params(); EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED } #endif -#ifdef EIGEN_HAVE_RVALUE_REFERENCES - PlainObjectBase(PlainObjectBase&& other) +#if EIGEN_HAS_RVALUE_REFERENCES + EIGEN_DEVICE_FUNC + PlainObjectBase(PlainObjectBase&& other) EIGEN_NOEXCEPT : m_storage( std::move(other.m_storage) ) { } - PlainObjectBase& operator=(PlainObjectBase&& other) + EIGEN_DEVICE_FUNC + PlainObjectBase& operator=(PlainObjectBase&& other) EIGEN_NOEXCEPT { using std::swap; swap(m_storage, other.m_storage); @@ -452,31 +515,56 @@ class PlainObjectBase : public internal::dense_xpr_base::type #endif /** Copy constructor */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PlainObjectBase(const PlainObjectBase& other) - : m_storage() + : Base(), m_storage(other.m_storage) { } + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE PlainObjectBase(Index size, Index rows, Index cols) + : m_storage(size, rows, cols) { - _check_template_params(); - lazyAssign(other); +// _check_template_params(); +// EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED } + /** \sa PlainObjectBase::operator=(const EigenBase&) */ template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PlainObjectBase(const DenseBase &other) : m_storage() { _check_template_params(); - lazyAssign(other); + resizeLike(other); + _set_noalias(other); } - EIGEN_STRONG_INLINE PlainObjectBase(Index a_size, Index nbRows, Index nbCols) - : m_storage(a_size, nbRows, nbCols) + /** \sa PlainObjectBase::operator=(const EigenBase&) */ + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE PlainObjectBase(const EigenBase &other) + : m_storage() { -// _check_template_params(); -// EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED + _check_template_params(); + resizeLike(other); + *this = other.derived(); + } + /** \brief Copy constructor with in-place evaluation */ + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE PlainObjectBase(const ReturnByValue& other) + { + _check_template_params(); + // FIXME this does not automatically transpose vectors if necessary + resize(other.rows(), other.cols()); + other.evalTo(this->derived()); } - /** \copydoc MatrixBase::operator=(const EigenBase&) + public: + + /** \brief Copies the generic expression \a other into *this. + * \copydetails DenseBase::operator=(const EigenBase &other) */ template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator=(const EigenBase &other) { _resize_to_match(other); @@ -484,16 +572,6 @@ class PlainObjectBase : public internal::dense_xpr_base::type return this->derived(); } - /** \sa MatrixBase::operator=(const EigenBase&) */ - template - EIGEN_STRONG_INLINE PlainObjectBase(const EigenBase &other) - : m_storage(other.derived().rows() * other.derived().cols(), other.derived().rows(), other.derived().cols()) - { - _check_template_params(); - internal::check_rows_cols_for_overflow::run(other.derived().rows(), other.derived().cols()); - Base::operator=(other.derived()); - } - /** \name Map * These are convenience functions returning Map objects. The Map() static functions return unaligned Map objects, * while the AlignedMap() functions return aligned Map objects and thus should be called only with 16-byte-aligned @@ -568,16 +646,16 @@ class PlainObjectBase : public internal::dense_xpr_base::type //@} using Base::setConstant; - Derived& setConstant(Index size, const Scalar& value); - Derived& setConstant(Index rows, Index cols, const Scalar& value); + EIGEN_DEVICE_FUNC Derived& setConstant(Index size, const Scalar& val); + EIGEN_DEVICE_FUNC Derived& setConstant(Index rows, Index cols, const Scalar& val); using Base::setZero; - Derived& setZero(Index size); - Derived& setZero(Index rows, Index cols); + EIGEN_DEVICE_FUNC Derived& setZero(Index size); + EIGEN_DEVICE_FUNC Derived& setZero(Index rows, Index cols); using Base::setOnes; - Derived& setOnes(Index size); - Derived& setOnes(Index rows, Index cols); + EIGEN_DEVICE_FUNC Derived& setOnes(Index size); + EIGEN_DEVICE_FUNC Derived& setOnes(Index rows, Index cols); using Base::setRandom; Derived& setRandom(Index size); @@ -596,6 +674,7 @@ class PlainObjectBase : public internal::dense_xpr_base::type * remain row-vectors and vectors remain vectors. */ template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void _resize_to_match(const EigenBase& other) { #ifdef EIGEN_NO_AUTOMATIC_RESIZING @@ -603,8 +682,6 @@ class PlainObjectBase : public internal::dense_xpr_base::type : (rows() == other.rows() && cols() == other.cols()))) && "Size mismatch. Automatic resizing is disabled because EIGEN_NO_AUTOMATIC_RESIZING is defined"); EIGEN_ONLY_USED_FOR_DEBUG(other); - if(this->size()==0) - resizeLike(other); #else resizeLike(other); #endif @@ -624,25 +701,23 @@ class PlainObjectBase : public internal::dense_xpr_base::type * * \internal */ + // aliasing is dealt once in internall::call_assignment + // so at this stage we have to assume aliasing... and resising has to be done later. template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& _set(const DenseBase& other) { - _set_selector(other.derived(), typename internal::conditional(int(OtherDerived::Flags) & EvalBeforeAssigningBit), internal::true_type, internal::false_type>::type()); + internal::call_assignment(this->derived(), other.derived()); return this->derived(); } - template - EIGEN_STRONG_INLINE void _set_selector(const OtherDerived& other, const internal::true_type&) { _set_noalias(other.eval()); } - - template - EIGEN_STRONG_INLINE void _set_selector(const OtherDerived& other, const internal::false_type&) { _set_noalias(other); } - /** \internal Like _set() but additionally makes the assumption that no aliasing effect can happen (which * is the case when creating a new matrix) so one can enforce lazy evaluation. * * \sa operator=(const MatrixBase&), _set() */ template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& _set_noalias(const DenseBase& other) { // I don't think we need this resize call since the lazyAssign will anyways resize @@ -650,40 +725,175 @@ class PlainObjectBase : public internal::dense_xpr_base::type //_resize_to_match(other); // the 'false' below means to enforce lazy evaluation. We don't use lazyAssign() because // it wouldn't allow to copy a row-vector into a column-vector. - return internal::assign_selector::run(this->derived(), other.derived()); + internal::call_assignment_no_alias(this->derived(), other.derived(), internal::assign_op()); + return this->derived(); } template - EIGEN_STRONG_INLINE void _init2(Index nbRows, Index nbCols, typename internal::enable_if::type* = 0) + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _init2(Index rows, Index cols, typename internal::enable_if::type* = 0) { EIGEN_STATIC_ASSERT(bool(NumTraits::IsInteger) && bool(NumTraits::IsInteger), FLOATING_POINT_ARGUMENT_PASSED__INTEGER_WAS_EXPECTED) - resize(nbRows,nbCols); + resize(rows,cols); + } + + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _init2(const T0& val0, const T1& val1, typename internal::enable_if::type* = 0) + { + EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(PlainObjectBase, 2) + m_storage.data()[0] = Scalar(val0); + m_storage.data()[1] = Scalar(val1); } + template - EIGEN_STRONG_INLINE void _init2(const Scalar& val0, const Scalar& val1, typename internal::enable_if::type* = 0) + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _init2(const Index& val0, const Index& val1, + typename internal::enable_if< (!internal::is_same::value) + && (internal::is_same::value) + && (internal::is_same::value) + && Base::SizeAtCompileTime==2,T1>::type* = 0) { EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(PlainObjectBase, 2) + m_storage.data()[0] = Scalar(val0); + m_storage.data()[1] = Scalar(val1); + } + + // The argument is convertible to the Index type and we either have a non 1x1 Matrix, or a dynamic-sized Array, + // then the argument is meant to be the size of the object. + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _init1(Index size, typename internal::enable_if< (Base::SizeAtCompileTime!=1 || !internal::is_convertible::value) + && ((!internal::is_same::XprKind,ArrayXpr>::value || Base::SizeAtCompileTime==Dynamic)),T>::type* = 0) + { + // NOTE MSVC 2008 complains if we directly put bool(NumTraits::IsInteger) as the EIGEN_STATIC_ASSERT argument. + const bool is_integer = NumTraits::IsInteger; + EIGEN_UNUSED_VARIABLE(is_integer); + EIGEN_STATIC_ASSERT(is_integer, + FLOATING_POINT_ARGUMENT_PASSED__INTEGER_WAS_EXPECTED) + resize(size); + } + + // We have a 1x1 matrix/array => the argument is interpreted as the value of the unique coefficient (case where scalar type can be implicitely converted) + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _init1(const Scalar& val0, typename internal::enable_if::value,T>::type* = 0) + { + EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(PlainObjectBase, 1) m_storage.data()[0] = val0; - m_storage.data()[1] = val1; + } + + // We have a 1x1 matrix/array => the argument is interpreted as the value of the unique coefficient (case where scalar type match the index type) + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _init1(const Index& val0, + typename internal::enable_if< (!internal::is_same::value) + && (internal::is_same::value) + && Base::SizeAtCompileTime==1 + && internal::is_convertible::value,T*>::type* = 0) + { + EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(PlainObjectBase, 1) + m_storage.data()[0] = Scalar(val0); } + // Initialize a fixed size matrix from a pointer to raw data + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _init1(const Scalar* data){ + this->_set_noalias(ConstMapType(data)); + } + + // Initialize an arbitrary matrix from a dense expression + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _init1(const DenseBase& other){ + this->_set_noalias(other); + } + + // Initialize an arbitrary matrix from an object convertible to the Derived type. + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _init1(const Derived& other){ + this->_set_noalias(other); + } + + // Initialize an arbitrary matrix from a generic Eigen expression + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _init1(const EigenBase& other){ + this->derived() = other; + } + + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _init1(const ReturnByValue& other) + { + resize(other.rows(), other.cols()); + other.evalTo(this->derived()); + } + + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _init1(const RotationBase& r) + { + this->derived() = r; + } + + // For fixed-size Array + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _init1(const Scalar& val0, + typename internal::enable_if< Base::SizeAtCompileTime!=Dynamic + && Base::SizeAtCompileTime!=1 + && internal::is_convertible::value + && internal::is_same::XprKind,ArrayXpr>::value,T>::type* = 0) + { + Base::setConstant(val0); + } + + // For fixed-size Array + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void _init1(const Index& val0, + typename internal::enable_if< (!internal::is_same::value) + && (internal::is_same::value) + && Base::SizeAtCompileTime!=Dynamic + && Base::SizeAtCompileTime!=1 + && internal::is_convertible::value + && internal::is_same::XprKind,ArrayXpr>::value,T*>::type* = 0) + { + Base::setConstant(val0); + } + template friend struct internal::matrix_swap_impl; - /** \internal generic implementation of swap for dense storage since for dynamic-sized matrices of same type it is enough to swap the - * data pointers. + public: + +#ifndef EIGEN_PARSED_BY_DOXYGEN + /** \internal + * \brief Override DenseBase::swap() since for dynamic-sized matrices + * of same type it is enough to swap the data pointers. */ template - void _swap(DenseBase const & other) + EIGEN_DEVICE_FUNC + void swap(DenseBase & other) { enum { SwapPointers = internal::is_same::value && Base::SizeAtCompileTime==Dynamic }; - internal::matrix_swap_impl::run(this->derived(), other.const_cast_derived()); + internal::matrix_swap_impl::run(this->derived(), other.derived()); } - - public: -#ifndef EIGEN_PARSED_BY_DOXYGEN + + /** \internal + * \brief const version forwarded to DenseBase::swap + */ + template + EIGEN_DEVICE_FUNC + void swap(DenseBase const & other) + { Base::swap(other.derived()); } + + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void _check_template_params() { EIGEN_STATIC_ASSERT((EIGEN_IMPLIES(MaxRowsAtCompileTime==1 && MaxColsAtCompileTime!=1, (Options&RowMajor)==RowMajor) @@ -697,10 +907,9 @@ class PlainObjectBase : public internal::dense_xpr_base::type && (Options & (DontAlign|RowMajor)) == Options), INVALID_MATRIX_TEMPLATE_PARAMETERS) } -#endif -private: - enum { ThisConstantIsPrivateInPlainObjectBase }; + enum { IsPlainObjectBase = 1 }; +#endif }; namespace internal { @@ -708,7 +917,6 @@ namespace internal { template struct conservative_resize_like_impl { - typedef typename Derived::Index Index; static void run(DenseBase& _this, Index rows, Index cols) { if (_this.rows() == rows && _this.cols() == cols) return; @@ -724,8 +932,8 @@ struct conservative_resize_like_impl { // The storage order does not allow us to use reallocation. typename Derived::PlainObject tmp(rows,cols); - const Index common_rows = (std::min)(rows, _this.rows()); - const Index common_cols = (std::min)(cols, _this.cols()); + const Index common_rows = numext::mini(rows, _this.rows()); + const Index common_cols = numext::mini(cols, _this.cols()); tmp.block(0,0,common_rows,common_cols) = _this.block(0,0,common_rows,common_cols); _this.derived().swap(tmp); } @@ -758,8 +966,8 @@ struct conservative_resize_like_impl { // The storage order does not allow us to use reallocation. typename Derived::PlainObject tmp(other); - const Index common_rows = (std::min)(tmp.rows(), _this.rows()); - const Index common_cols = (std::min)(tmp.cols(), _this.cols()); + const Index common_rows = numext::mini(tmp.rows(), _this.rows()); + const Index common_cols = numext::mini(tmp.cols(), _this.cols()); tmp.block(0,0,common_rows,common_cols) = _this.block(0,0,common_rows,common_cols); _this.derived().swap(tmp); } @@ -774,7 +982,6 @@ struct conservative_resize_like_impl { using conservative_resize_like_impl::run; - typedef typename Derived::Index Index; static void run(DenseBase& _this, Index size) { const Index new_rows = Derived::RowsAtCompileTime==1 ? 1 : size; @@ -800,6 +1007,7 @@ struct conservative_resize_like_impl template struct matrix_swap_impl { + EIGEN_DEVICE_FUNC static inline void run(MatrixTypeA& a, MatrixTypeB& b) { a.base().swap(b); @@ -809,6 +1017,7 @@ struct matrix_swap_impl template struct matrix_swap_impl { + EIGEN_DEVICE_FUNC static inline void run(MatrixTypeA& a, MatrixTypeB& b) { static_cast(a).m_storage.swap(static_cast(b).m_storage); diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Core/Product.h b/ground/gcs/src/libs/eigen/Eigen/src/Core/Product.h new file mode 100644 index 0000000000..ae0c94b38e --- /dev/null +++ b/ground/gcs/src/libs/eigen/Eigen/src/Core/Product.h @@ -0,0 +1,186 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2011 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_PRODUCT_H +#define EIGEN_PRODUCT_H + +namespace Eigen { + +template class ProductImpl; + +namespace internal { + +template +struct traits > +{ + typedef typename remove_all::type LhsCleaned; + typedef typename remove_all::type RhsCleaned; + typedef traits LhsTraits; + typedef traits RhsTraits; + + typedef MatrixXpr XprKind; + + typedef typename ScalarBinaryOpTraits::Scalar, typename traits::Scalar>::ReturnType Scalar; + typedef typename product_promote_storage_type::ret>::ret StorageKind; + typedef typename promote_index_type::type StorageIndex; + + enum { + RowsAtCompileTime = LhsTraits::RowsAtCompileTime, + ColsAtCompileTime = RhsTraits::ColsAtCompileTime, + MaxRowsAtCompileTime = LhsTraits::MaxRowsAtCompileTime, + MaxColsAtCompileTime = RhsTraits::MaxColsAtCompileTime, + + // FIXME: only needed by GeneralMatrixMatrixTriangular + InnerSize = EIGEN_SIZE_MIN_PREFER_FIXED(LhsTraits::ColsAtCompileTime, RhsTraits::RowsAtCompileTime), + + // The storage order is somewhat arbitrary here. The correct one will be determined through the evaluator. + Flags = (MaxRowsAtCompileTime==1 && MaxColsAtCompileTime!=1) ? RowMajorBit + : (MaxColsAtCompileTime==1 && MaxRowsAtCompileTime!=1) ? 0 + : ( ((LhsTraits::Flags&NoPreferredStorageOrderBit) && (RhsTraits::Flags&RowMajorBit)) + || ((RhsTraits::Flags&NoPreferredStorageOrderBit) && (LhsTraits::Flags&RowMajorBit)) ) ? RowMajorBit + : NoPreferredStorageOrderBit + }; +}; + +} // end namespace internal + +/** \class Product + * \ingroup Core_Module + * + * \brief Expression of the product of two arbitrary matrices or vectors + * + * \tparam _Lhs the type of the left-hand side expression + * \tparam _Rhs the type of the right-hand side expression + * + * This class represents an expression of the product of two arbitrary matrices. + * + * The other template parameters are: + * \tparam Option can be DefaultProduct, AliasFreeProduct, or LazyProduct + * + */ +template +class Product : public ProductImpl<_Lhs,_Rhs,Option, + typename internal::product_promote_storage_type::StorageKind, + typename internal::traits<_Rhs>::StorageKind, + internal::product_type<_Lhs,_Rhs>::ret>::ret> +{ + public: + + typedef _Lhs Lhs; + typedef _Rhs Rhs; + + typedef typename ProductImpl< + Lhs, Rhs, Option, + typename internal::product_promote_storage_type::StorageKind, + typename internal::traits::StorageKind, + internal::product_type::ret>::ret>::Base Base; + EIGEN_GENERIC_PUBLIC_INTERFACE(Product) + + typedef typename internal::ref_selector::type LhsNested; + typedef typename internal::ref_selector::type RhsNested; + typedef typename internal::remove_all::type LhsNestedCleaned; + typedef typename internal::remove_all::type RhsNestedCleaned; + + EIGEN_DEVICE_FUNC Product(const Lhs& lhs, const Rhs& rhs) : m_lhs(lhs), m_rhs(rhs) + { + eigen_assert(lhs.cols() == rhs.rows() + && "invalid matrix product" + && "if you wanted a coeff-wise or a dot product use the respective explicit functions"); + } + + EIGEN_DEVICE_FUNC inline Index rows() const { return m_lhs.rows(); } + EIGEN_DEVICE_FUNC inline Index cols() const { return m_rhs.cols(); } + + EIGEN_DEVICE_FUNC const LhsNestedCleaned& lhs() const { return m_lhs; } + EIGEN_DEVICE_FUNC const RhsNestedCleaned& rhs() const { return m_rhs; } + + protected: + + LhsNested m_lhs; + RhsNested m_rhs; +}; + +namespace internal { + +template::ret> +class dense_product_base + : public internal::dense_xpr_base >::type +{}; + +/** Convertion to scalar for inner-products */ +template +class dense_product_base + : public internal::dense_xpr_base >::type +{ + typedef Product ProductXpr; + typedef typename internal::dense_xpr_base::type Base; +public: + using Base::derived; + typedef typename Base::Scalar Scalar; + + operator const Scalar() const + { + return internal::evaluator(derived()).coeff(0,0); + } +}; + +} // namespace internal + +// Generic API dispatcher +template +class ProductImpl : public internal::generic_xpr_base, MatrixXpr, StorageKind>::type +{ + public: + typedef typename internal::generic_xpr_base, MatrixXpr, StorageKind>::type Base; +}; + +template +class ProductImpl + : public internal::dense_product_base +{ + typedef Product Derived; + + public: + + typedef typename internal::dense_product_base Base; + EIGEN_DENSE_PUBLIC_INTERFACE(Derived) + protected: + enum { + IsOneByOne = (RowsAtCompileTime == 1 || RowsAtCompileTime == Dynamic) && + (ColsAtCompileTime == 1 || ColsAtCompileTime == Dynamic), + EnableCoeff = IsOneByOne || Option==LazyProduct + }; + + public: + + EIGEN_DEVICE_FUNC Scalar coeff(Index row, Index col) const + { + EIGEN_STATIC_ASSERT(EnableCoeff, THIS_METHOD_IS_ONLY_FOR_INNER_OR_LAZY_PRODUCTS); + eigen_assert( (Option==LazyProduct) || (this->rows() == 1 && this->cols() == 1) ); + + return internal::evaluator(derived()).coeff(row,col); + } + + EIGEN_DEVICE_FUNC Scalar coeff(Index i) const + { + EIGEN_STATIC_ASSERT(EnableCoeff, THIS_METHOD_IS_ONLY_FOR_INNER_OR_LAZY_PRODUCTS); + eigen_assert( (Option==LazyProduct) || (this->rows() == 1 && this->cols() == 1) ); + + return internal::evaluator(derived()).coeff(i); + } + + +}; + +} // end namespace Eigen + +#endif // EIGEN_PRODUCT_H diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Core/ProductBase.h b/ground/gcs/src/libs/eigen/Eigen/src/Core/ProductBase.h deleted file mode 100644 index cf74470a9a..0000000000 --- a/ground/gcs/src/libs/eigen/Eigen/src/Core/ProductBase.h +++ /dev/null @@ -1,290 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2009-2010 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_PRODUCTBASE_H -#define EIGEN_PRODUCTBASE_H - -namespace Eigen { - -/** \class ProductBase - * \ingroup Core_Module - * - */ - -namespace internal { -template -struct traits > -{ - typedef MatrixXpr XprKind; - typedef typename remove_all<_Lhs>::type Lhs; - typedef typename remove_all<_Rhs>::type Rhs; - typedef typename scalar_product_traits::ReturnType Scalar; - typedef typename promote_storage_type::StorageKind, - typename traits::StorageKind>::ret StorageKind; - typedef typename promote_index_type::Index, - typename traits::Index>::type Index; - enum { - RowsAtCompileTime = traits::RowsAtCompileTime, - ColsAtCompileTime = traits::ColsAtCompileTime, - MaxRowsAtCompileTime = traits::MaxRowsAtCompileTime, - MaxColsAtCompileTime = traits::MaxColsAtCompileTime, - Flags = (MaxRowsAtCompileTime==1 ? RowMajorBit : 0) - | EvalBeforeNestingBit | EvalBeforeAssigningBit | NestByRefBit, - // Note that EvalBeforeNestingBit and NestByRefBit - // are not used in practice because nested is overloaded for products - CoeffReadCost = 0 // FIXME why is it needed ? - }; -}; -} - -#define EIGEN_PRODUCT_PUBLIC_INTERFACE(Derived) \ - typedef ProductBase Base; \ - EIGEN_DENSE_PUBLIC_INTERFACE(Derived) \ - typedef typename Base::LhsNested LhsNested; \ - typedef typename Base::_LhsNested _LhsNested; \ - typedef typename Base::LhsBlasTraits LhsBlasTraits; \ - typedef typename Base::ActualLhsType ActualLhsType; \ - typedef typename Base::_ActualLhsType _ActualLhsType; \ - typedef typename Base::RhsNested RhsNested; \ - typedef typename Base::_RhsNested _RhsNested; \ - typedef typename Base::RhsBlasTraits RhsBlasTraits; \ - typedef typename Base::ActualRhsType ActualRhsType; \ - typedef typename Base::_ActualRhsType _ActualRhsType; \ - using Base::m_lhs; \ - using Base::m_rhs; - -template -class ProductBase : public MatrixBase -{ - public: - typedef MatrixBase Base; - EIGEN_DENSE_PUBLIC_INTERFACE(ProductBase) - - typedef typename Lhs::Nested LhsNested; - typedef typename internal::remove_all::type _LhsNested; - typedef internal::blas_traits<_LhsNested> LhsBlasTraits; - typedef typename LhsBlasTraits::DirectLinearAccessType ActualLhsType; - typedef typename internal::remove_all::type _ActualLhsType; - typedef typename internal::traits::Scalar LhsScalar; - - typedef typename Rhs::Nested RhsNested; - typedef typename internal::remove_all::type _RhsNested; - typedef internal::blas_traits<_RhsNested> RhsBlasTraits; - typedef typename RhsBlasTraits::DirectLinearAccessType ActualRhsType; - typedef typename internal::remove_all::type _ActualRhsType; - typedef typename internal::traits::Scalar RhsScalar; - - // Diagonal of a product: no need to evaluate the arguments because they are going to be evaluated only once - typedef CoeffBasedProduct FullyLazyCoeffBaseProductType; - - public: - -#ifndef EIGEN_NO_MALLOC - typedef typename Base::PlainObject BasePlainObject; - typedef Matrix DynPlainObject; - typedef typename internal::conditional<(BasePlainObject::SizeAtCompileTime==Dynamic) || (BasePlainObject::SizeAtCompileTime*int(sizeof(Scalar)) < int(EIGEN_STACK_ALLOCATION_LIMIT)), - BasePlainObject, DynPlainObject>::type PlainObject; -#else - typedef typename Base::PlainObject PlainObject; -#endif - - ProductBase(const Lhs& a_lhs, const Rhs& a_rhs) - : m_lhs(a_lhs), m_rhs(a_rhs) - { - eigen_assert(a_lhs.cols() == a_rhs.rows() - && "invalid matrix product" - && "if you wanted a coeff-wise or a dot product use the respective explicit functions"); - } - - inline Index rows() const { return m_lhs.rows(); } - inline Index cols() const { return m_rhs.cols(); } - - template - inline void evalTo(Dest& dst) const { dst.setZero(); scaleAndAddTo(dst,Scalar(1)); } - - template - inline void addTo(Dest& dst) const { scaleAndAddTo(dst,Scalar(1)); } - - template - inline void subTo(Dest& dst) const { scaleAndAddTo(dst,Scalar(-1)); } - - template - inline void scaleAndAddTo(Dest& dst, const Scalar& alpha) const { derived().scaleAndAddTo(dst,alpha); } - - const _LhsNested& lhs() const { return m_lhs; } - const _RhsNested& rhs() const { return m_rhs; } - - // Implicit conversion to the nested type (trigger the evaluation of the product) - operator const PlainObject& () const - { - m_result.resize(m_lhs.rows(), m_rhs.cols()); - derived().evalTo(m_result); - return m_result; - } - - const Diagonal diagonal() const - { return FullyLazyCoeffBaseProductType(m_lhs, m_rhs); } - - template - const Diagonal diagonal() const - { return FullyLazyCoeffBaseProductType(m_lhs, m_rhs); } - - const Diagonal diagonal(Index index) const - { return FullyLazyCoeffBaseProductType(m_lhs, m_rhs).diagonal(index); } - - // restrict coeff accessors to 1x1 expressions. No need to care about mutators here since this isnt a Lvalue expression - typename Base::CoeffReturnType coeff(Index row, Index col) const - { -#ifdef EIGEN2_SUPPORT - return lhs().row(row).cwiseProduct(rhs().col(col).transpose()).sum(); -#else - EIGEN_STATIC_ASSERT_SIZE_1x1(Derived) - eigen_assert(this->rows() == 1 && this->cols() == 1); - Matrix result = *this; - return result.coeff(row,col); -#endif - } - - typename Base::CoeffReturnType coeff(Index i) const - { - EIGEN_STATIC_ASSERT_SIZE_1x1(Derived) - eigen_assert(this->rows() == 1 && this->cols() == 1); - Matrix result = *this; - return result.coeff(i); - } - - const Scalar& coeffRef(Index row, Index col) const - { - EIGEN_STATIC_ASSERT_SIZE_1x1(Derived) - eigen_assert(this->rows() == 1 && this->cols() == 1); - return derived().coeffRef(row,col); - } - - const Scalar& coeffRef(Index i) const - { - EIGEN_STATIC_ASSERT_SIZE_1x1(Derived) - eigen_assert(this->rows() == 1 && this->cols() == 1); - return derived().coeffRef(i); - } - - protected: - - LhsNested m_lhs; - RhsNested m_rhs; - - mutable PlainObject m_result; -}; - -// here we need to overload the nested rule for products -// such that the nested type is a const reference to a plain matrix -namespace internal { -template -struct nested, N, PlainObject> -{ - typedef typename GeneralProduct::PlainObject const& type; -}; -template -struct nested, N, PlainObject> -{ - typedef typename GeneralProduct::PlainObject const& type; -}; -} - -template -class ScaledProduct; - -// Note that these two operator* functions are not defined as member -// functions of ProductBase, because, otherwise we would have to -// define all overloads defined in MatrixBase. Furthermore, Using -// "using Base::operator*" would not work with MSVC. -// -// Also note that here we accept any compatible scalar types -template -const ScaledProduct -operator*(const ProductBase& prod, const typename Derived::Scalar& x) -{ return ScaledProduct(prod.derived(), x); } - -template -typename internal::enable_if::value, - const ScaledProduct >::type -operator*(const ProductBase& prod, const typename Derived::RealScalar& x) -{ return ScaledProduct(prod.derived(), x); } - - -template -const ScaledProduct -operator*(const typename Derived::Scalar& x,const ProductBase& prod) -{ return ScaledProduct(prod.derived(), x); } - -template -typename internal::enable_if::value, - const ScaledProduct >::type -operator*(const typename Derived::RealScalar& x,const ProductBase& prod) -{ return ScaledProduct(prod.derived(), x); } - -namespace internal { -template -struct traits > - : traits, - typename NestedProduct::_LhsNested, - typename NestedProduct::_RhsNested> > -{ - typedef typename traits::StorageKind StorageKind; -}; -} - -template -class ScaledProduct - : public ProductBase, - typename NestedProduct::_LhsNested, - typename NestedProduct::_RhsNested> -{ - public: - typedef ProductBase, - typename NestedProduct::_LhsNested, - typename NestedProduct::_RhsNested> Base; - typedef typename Base::Scalar Scalar; - typedef typename Base::PlainObject PlainObject; -// EIGEN_PRODUCT_PUBLIC_INTERFACE(ScaledProduct) - - ScaledProduct(const NestedProduct& prod, const Scalar& x) - : Base(prod.lhs(),prod.rhs()), m_prod(prod), m_alpha(x) {} - - template - inline void evalTo(Dest& dst) const { dst.setZero(); scaleAndAddTo(dst, Scalar(1)); } - - template - inline void addTo(Dest& dst) const { scaleAndAddTo(dst, Scalar(1)); } - - template - inline void subTo(Dest& dst) const { scaleAndAddTo(dst, Scalar(-1)); } - - template - inline void scaleAndAddTo(Dest& dst, const Scalar& a_alpha) const { m_prod.derived().scaleAndAddTo(dst,a_alpha * m_alpha); } - - const Scalar& alpha() const { return m_alpha; } - - protected: - const NestedProduct& m_prod; - Scalar m_alpha; -}; - -/** \internal - * Overloaded to perform an efficient C = (A*B).lazy() */ -template -template -Derived& MatrixBase::lazyAssign(const ProductBase& other) -{ - other.derived().evalTo(derived()); - return derived(); -} - -} // end namespace Eigen - -#endif // EIGEN_PRODUCTBASE_H diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Core/ProductEvaluators.h b/ground/gcs/src/libs/eigen/Eigen/src/Core/ProductEvaluators.h new file mode 100644 index 0000000000..583b7f59e3 --- /dev/null +++ b/ground/gcs/src/libs/eigen/Eigen/src/Core/ProductEvaluators.h @@ -0,0 +1,1099 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2006-2008 Benoit Jacob +// Copyright (C) 2008-2010 Gael Guennebaud +// Copyright (C) 2011 Jitse Niesen +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + + +#ifndef EIGEN_PRODUCTEVALUATORS_H +#define EIGEN_PRODUCTEVALUATORS_H + +namespace Eigen { + +namespace internal { + +/** \internal + * Evaluator of a product expression. + * Since products require special treatments to handle all possible cases, + * we simply deffer the evaluation logic to a product_evaluator class + * which offers more partial specialization possibilities. + * + * \sa class product_evaluator + */ +template +struct evaluator > + : public product_evaluator > +{ + typedef Product XprType; + typedef product_evaluator Base; + + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& xpr) : Base(xpr) {} +}; + +// Catch "scalar * ( A * B )" and transform it to "(A*scalar) * B" +// TODO we should apply that rule only if that's really helpful +template +struct evaluator_assume_aliasing, + const CwiseNullaryOp, Plain1>, + const Product > > +{ + static const bool value = true; +}; +template +struct evaluator, + const CwiseNullaryOp, Plain1>, + const Product > > + : public evaluator > +{ + typedef CwiseBinaryOp, + const CwiseNullaryOp, Plain1>, + const Product > XprType; + typedef evaluator > Base; + + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& xpr) + : Base(xpr.lhs().functor().m_other * xpr.rhs().lhs() * xpr.rhs().rhs()) + {} +}; + + +template +struct evaluator, DiagIndex> > + : public evaluator, DiagIndex> > +{ + typedef Diagonal, DiagIndex> XprType; + typedef evaluator, DiagIndex> > Base; + + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& xpr) + : Base(Diagonal, DiagIndex>( + Product(xpr.nestedExpression().lhs(), xpr.nestedExpression().rhs()), + xpr.index() )) + {} +}; + + +// Helper class to perform a matrix product with the destination at hand. +// Depending on the sizes of the factors, there are different evaluation strategies +// as controlled by internal::product_type. +template< typename Lhs, typename Rhs, + typename LhsShape = typename evaluator_traits::Shape, + typename RhsShape = typename evaluator_traits::Shape, + int ProductType = internal::product_type::value> +struct generic_product_impl; + +template +struct evaluator_assume_aliasing > { + static const bool value = true; +}; + +// This is the default evaluator implementation for products: +// It creates a temporary and call generic_product_impl +template +struct product_evaluator, ProductTag, LhsShape, RhsShape> + : public evaluator::PlainObject> +{ + typedef Product XprType; + typedef typename XprType::PlainObject PlainObject; + typedef evaluator Base; + enum { + Flags = Base::Flags | EvalBeforeNestingBit + }; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + explicit product_evaluator(const XprType& xpr) + : m_result(xpr.rows(), xpr.cols()) + { + ::new (static_cast(this)) Base(m_result); + +// FIXME shall we handle nested_eval here?, +// if so, then we must take care at removing the call to nested_eval in the specializations (e.g., in permutation_matrix_product, transposition_matrix_product, etc.) +// typedef typename internal::nested_eval::type LhsNested; +// typedef typename internal::nested_eval::type RhsNested; +// typedef typename internal::remove_all::type LhsNestedCleaned; +// typedef typename internal::remove_all::type RhsNestedCleaned; +// +// const LhsNested lhs(xpr.lhs()); +// const RhsNested rhs(xpr.rhs()); +// +// generic_product_impl::evalTo(m_result, lhs, rhs); + + generic_product_impl::evalTo(m_result, xpr.lhs(), xpr.rhs()); + } + +protected: + PlainObject m_result; +}; + +// The following three shortcuts are enabled only if the scalar types match excatly. +// TODO: we could enable them for different scalar types when the product is not vectorized. + +// Dense = Product +template< typename DstXprType, typename Lhs, typename Rhs, int Options, typename Scalar> +struct Assignment, internal::assign_op, Dense2Dense, + typename enable_if<(Options==DefaultProduct || Options==AliasFreeProduct)>::type> +{ + typedef Product SrcXprType; + static EIGEN_STRONG_INLINE + void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op &) + { + Index dstRows = src.rows(); + Index dstCols = src.cols(); + if((dst.rows()!=dstRows) || (dst.cols()!=dstCols)) + dst.resize(dstRows, dstCols); + // FIXME shall we handle nested_eval here? + generic_product_impl::evalTo(dst, src.lhs(), src.rhs()); + } +}; + +// Dense += Product +template< typename DstXprType, typename Lhs, typename Rhs, int Options, typename Scalar> +struct Assignment, internal::add_assign_op, Dense2Dense, + typename enable_if<(Options==DefaultProduct || Options==AliasFreeProduct)>::type> +{ + typedef Product SrcXprType; + static EIGEN_STRONG_INLINE + void run(DstXprType &dst, const SrcXprType &src, const internal::add_assign_op &) + { + eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); + // FIXME shall we handle nested_eval here? + generic_product_impl::addTo(dst, src.lhs(), src.rhs()); + } +}; + +// Dense -= Product +template< typename DstXprType, typename Lhs, typename Rhs, int Options, typename Scalar> +struct Assignment, internal::sub_assign_op, Dense2Dense, + typename enable_if<(Options==DefaultProduct || Options==AliasFreeProduct)>::type> +{ + typedef Product SrcXprType; + static EIGEN_STRONG_INLINE + void run(DstXprType &dst, const SrcXprType &src, const internal::sub_assign_op &) + { + eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); + // FIXME shall we handle nested_eval here? + generic_product_impl::subTo(dst, src.lhs(), src.rhs()); + } +}; + + +// Dense ?= scalar * Product +// TODO we should apply that rule if that's really helpful +// for instance, this is not good for inner products +template< typename DstXprType, typename Lhs, typename Rhs, typename AssignFunc, typename Scalar, typename ScalarBis, typename Plain> +struct Assignment, const CwiseNullaryOp,Plain>, + const Product >, AssignFunc, Dense2Dense> +{ + typedef CwiseBinaryOp, + const CwiseNullaryOp,Plain>, + const Product > SrcXprType; + static EIGEN_STRONG_INLINE + void run(DstXprType &dst, const SrcXprType &src, const AssignFunc& func) + { + call_assignment_no_alias(dst, (src.lhs().functor().m_other * src.rhs().lhs())*src.rhs().rhs(), func); + } +}; + +//---------------------------------------- +// Catch "Dense ?= xpr + Product<>" expression to save one temporary +// FIXME we could probably enable these rules for any product, i.e., not only Dense and DefaultProduct + +template +struct evaluator_assume_aliasing::Scalar>, const OtherXpr, + const Product >, DenseShape > { + static const bool value = true; +}; + +template +struct assignment_from_xpr_op_product +{ + template + static EIGEN_STRONG_INLINE + void run(DstXprType &dst, const SrcXprType &src, const InitialFunc& /*func*/) + { + call_assignment_no_alias(dst, src.lhs(), Func1()); + call_assignment_no_alias(dst, src.rhs(), Func2()); + } +}; + +#define EIGEN_CATCH_ASSIGN_XPR_OP_PRODUCT(ASSIGN_OP,BINOP,ASSIGN_OP2) \ + template< typename DstXprType, typename OtherXpr, typename Lhs, typename Rhs, typename DstScalar, typename SrcScalar, typename OtherScalar,typename ProdScalar> \ + struct Assignment, const OtherXpr, \ + const Product >, internal::ASSIGN_OP, Dense2Dense> \ + : assignment_from_xpr_op_product, internal::ASSIGN_OP, internal::ASSIGN_OP2 > \ + {} + +EIGEN_CATCH_ASSIGN_XPR_OP_PRODUCT(assign_op, scalar_sum_op,add_assign_op); +EIGEN_CATCH_ASSIGN_XPR_OP_PRODUCT(add_assign_op,scalar_sum_op,add_assign_op); +EIGEN_CATCH_ASSIGN_XPR_OP_PRODUCT(sub_assign_op,scalar_sum_op,sub_assign_op); + +EIGEN_CATCH_ASSIGN_XPR_OP_PRODUCT(assign_op, scalar_difference_op,sub_assign_op); +EIGEN_CATCH_ASSIGN_XPR_OP_PRODUCT(add_assign_op,scalar_difference_op,sub_assign_op); +EIGEN_CATCH_ASSIGN_XPR_OP_PRODUCT(sub_assign_op,scalar_difference_op,add_assign_op); + +//---------------------------------------- + +template +struct generic_product_impl +{ + template + static inline void evalTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { + dst.coeffRef(0,0) = (lhs.transpose().cwiseProduct(rhs)).sum(); + } + + template + static inline void addTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { + dst.coeffRef(0,0) += (lhs.transpose().cwiseProduct(rhs)).sum(); + } + + template + static void subTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { dst.coeffRef(0,0) -= (lhs.transpose().cwiseProduct(rhs)).sum(); } +}; + + +/*********************************************************************** +* Implementation of outer dense * dense vector product +***********************************************************************/ + +// Column major result +template +void outer_product_selector_run(Dst& dst, const Lhs &lhs, const Rhs &rhs, const Func& func, const false_type&) +{ + evaluator rhsEval(rhs); + typename nested_eval::type actual_lhs(lhs); + // FIXME if cols is large enough, then it might be useful to make sure that lhs is sequentially stored + // FIXME not very good if rhs is real and lhs complex while alpha is real too + const Index cols = dst.cols(); + for (Index j=0; j +void outer_product_selector_run(Dst& dst, const Lhs &lhs, const Rhs &rhs, const Func& func, const true_type&) +{ + evaluator lhsEval(lhs); + typename nested_eval::type actual_rhs(rhs); + // FIXME if rows is large enough, then it might be useful to make sure that rhs is sequentially stored + // FIXME not very good if lhs is real and rhs complex while alpha is real too + const Index rows = dst.rows(); + for (Index i=0; i +struct generic_product_impl +{ + template struct is_row_major : internal::conditional<(int(T::Flags)&RowMajorBit), internal::true_type, internal::false_type>::type {}; + typedef typename Product::Scalar Scalar; + + // TODO it would be nice to be able to exploit our *_assign_op functors for that purpose + struct set { template void operator()(const Dst& dst, const Src& src) const { dst.const_cast_derived() = src; } }; + struct add { template void operator()(const Dst& dst, const Src& src) const { dst.const_cast_derived() += src; } }; + struct sub { template void operator()(const Dst& dst, const Src& src) const { dst.const_cast_derived() -= src; } }; + struct adds { + Scalar m_scale; + explicit adds(const Scalar& s) : m_scale(s) {} + template void operator()(const Dst& dst, const Src& src) const { + dst.const_cast_derived() += m_scale * src; + } + }; + + template + static inline void evalTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { + internal::outer_product_selector_run(dst, lhs, rhs, set(), is_row_major()); + } + + template + static inline void addTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { + internal::outer_product_selector_run(dst, lhs, rhs, add(), is_row_major()); + } + + template + static inline void subTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { + internal::outer_product_selector_run(dst, lhs, rhs, sub(), is_row_major()); + } + + template + static inline void scaleAndAddTo(Dst& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) + { + internal::outer_product_selector_run(dst, lhs, rhs, adds(alpha), is_row_major()); + } + +}; + + +// This base class provides default implementations for evalTo, addTo, subTo, in terms of scaleAndAddTo +template +struct generic_product_impl_base +{ + typedef typename Product::Scalar Scalar; + + template + static EIGEN_STRONG_INLINE void evalTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { dst.setZero(); scaleAndAddTo(dst, lhs, rhs, Scalar(1)); } + + template + static EIGEN_STRONG_INLINE void addTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { scaleAndAddTo(dst,lhs, rhs, Scalar(1)); } + + template + static EIGEN_STRONG_INLINE void subTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { scaleAndAddTo(dst, lhs, rhs, Scalar(-1)); } + + template + static EIGEN_STRONG_INLINE void scaleAndAddTo(Dst& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) + { Derived::scaleAndAddTo(dst,lhs,rhs,alpha); } + +}; + +template +struct generic_product_impl + : generic_product_impl_base > +{ + typedef typename nested_eval::type LhsNested; + typedef typename nested_eval::type RhsNested; + typedef typename Product::Scalar Scalar; + enum { Side = Lhs::IsVectorAtCompileTime ? OnTheLeft : OnTheRight }; + typedef typename internal::remove_all::type>::type MatrixType; + + template + static EIGEN_STRONG_INLINE void scaleAndAddTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) + { + LhsNested actual_lhs(lhs); + RhsNested actual_rhs(rhs); + internal::gemv_dense_selector::HasUsableDirectAccess) + >::run(actual_lhs, actual_rhs, dst, alpha); + } +}; + +template +struct generic_product_impl +{ + typedef typename Product::Scalar Scalar; + + template + static EIGEN_STRONG_INLINE void evalTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { + // Same as: dst.noalias() = lhs.lazyProduct(rhs); + // but easier on the compiler side + call_assignment_no_alias(dst, lhs.lazyProduct(rhs), internal::assign_op()); + } + + template + static EIGEN_STRONG_INLINE void addTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { + // dst.noalias() += lhs.lazyProduct(rhs); + call_assignment_no_alias(dst, lhs.lazyProduct(rhs), internal::add_assign_op()); + } + + template + static EIGEN_STRONG_INLINE void subTo(Dst& dst, const Lhs& lhs, const Rhs& rhs) + { + // dst.noalias() -= lhs.lazyProduct(rhs); + call_assignment_no_alias(dst, lhs.lazyProduct(rhs), internal::sub_assign_op()); + } + +// template +// static inline void scaleAndAddTo(Dst& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) +// { dst.noalias() += alpha * lhs.lazyProduct(rhs); } +}; + +// This specialization enforces the use of a coefficient-based evaluation strategy +template +struct generic_product_impl + : generic_product_impl {}; + +// Case 2: Evaluate coeff by coeff +// +// This is mostly taken from CoeffBasedProduct.h +// The main difference is that we add an extra argument to the etor_product_*_impl::run() function +// for the inner dimension of the product, because evaluator object do not know their size. + +template +struct etor_product_coeff_impl; + +template +struct etor_product_packet_impl; + +template +struct product_evaluator, ProductTag, DenseShape, DenseShape> + : evaluator_base > +{ + typedef Product XprType; + typedef typename XprType::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + explicit product_evaluator(const XprType& xpr) + : m_lhs(xpr.lhs()), + m_rhs(xpr.rhs()), + m_lhsImpl(m_lhs), // FIXME the creation of the evaluator objects should result in a no-op, but check that! + m_rhsImpl(m_rhs), // Moreover, they are only useful for the packet path, so we could completely disable them when not needed, + // or perhaps declare them on the fly on the packet method... We have experiment to check what's best. + m_innerDim(xpr.lhs().cols()) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(NumTraits::MulCost); + EIGEN_INTERNAL_CHECK_COST_VALUE(NumTraits::AddCost); + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); +#if 0 + std::cerr << "LhsOuterStrideBytes= " << LhsOuterStrideBytes << "\n"; + std::cerr << "RhsOuterStrideBytes= " << RhsOuterStrideBytes << "\n"; + std::cerr << "LhsAlignment= " << LhsAlignment << "\n"; + std::cerr << "RhsAlignment= " << RhsAlignment << "\n"; + std::cerr << "CanVectorizeLhs= " << CanVectorizeLhs << "\n"; + std::cerr << "CanVectorizeRhs= " << CanVectorizeRhs << "\n"; + std::cerr << "CanVectorizeInner= " << CanVectorizeInner << "\n"; + std::cerr << "EvalToRowMajor= " << EvalToRowMajor << "\n"; + std::cerr << "Alignment= " << Alignment << "\n"; + std::cerr << "Flags= " << Flags << "\n"; +#endif + } + + // Everything below here is taken from CoeffBasedProduct.h + + typedef typename internal::nested_eval::type LhsNested; + typedef typename internal::nested_eval::type RhsNested; + + typedef typename internal::remove_all::type LhsNestedCleaned; + typedef typename internal::remove_all::type RhsNestedCleaned; + + typedef evaluator LhsEtorType; + typedef evaluator RhsEtorType; + + enum { + RowsAtCompileTime = LhsNestedCleaned::RowsAtCompileTime, + ColsAtCompileTime = RhsNestedCleaned::ColsAtCompileTime, + InnerSize = EIGEN_SIZE_MIN_PREFER_FIXED(LhsNestedCleaned::ColsAtCompileTime, RhsNestedCleaned::RowsAtCompileTime), + MaxRowsAtCompileTime = LhsNestedCleaned::MaxRowsAtCompileTime, + MaxColsAtCompileTime = RhsNestedCleaned::MaxColsAtCompileTime + }; + + typedef typename find_best_packet::type LhsVecPacketType; + typedef typename find_best_packet::type RhsVecPacketType; + + enum { + + LhsCoeffReadCost = LhsEtorType::CoeffReadCost, + RhsCoeffReadCost = RhsEtorType::CoeffReadCost, + CoeffReadCost = InnerSize==0 ? NumTraits::ReadCost + : InnerSize == Dynamic ? HugeCost + : InnerSize * (NumTraits::MulCost + LhsCoeffReadCost + RhsCoeffReadCost) + + (InnerSize - 1) * NumTraits::AddCost, + + Unroll = CoeffReadCost <= EIGEN_UNROLLING_LIMIT, + + LhsFlags = LhsEtorType::Flags, + RhsFlags = RhsEtorType::Flags, + + LhsRowMajor = LhsFlags & RowMajorBit, + RhsRowMajor = RhsFlags & RowMajorBit, + + LhsVecPacketSize = unpacket_traits::size, + RhsVecPacketSize = unpacket_traits::size, + + // Here, we don't care about alignment larger than the usable packet size. + LhsAlignment = EIGEN_PLAIN_ENUM_MIN(LhsEtorType::Alignment,LhsVecPacketSize*int(sizeof(typename LhsNestedCleaned::Scalar))), + RhsAlignment = EIGEN_PLAIN_ENUM_MIN(RhsEtorType::Alignment,RhsVecPacketSize*int(sizeof(typename RhsNestedCleaned::Scalar))), + + SameType = is_same::value, + + CanVectorizeRhs = bool(RhsRowMajor) && (RhsFlags & PacketAccessBit) && (ColsAtCompileTime!=1), + CanVectorizeLhs = (!LhsRowMajor) && (LhsFlags & PacketAccessBit) && (RowsAtCompileTime!=1), + + EvalToRowMajor = (MaxRowsAtCompileTime==1&&MaxColsAtCompileTime!=1) ? 1 + : (MaxColsAtCompileTime==1&&MaxRowsAtCompileTime!=1) ? 0 + : (bool(RhsRowMajor) && !CanVectorizeLhs), + + Flags = ((unsigned int)(LhsFlags | RhsFlags) & HereditaryBits & ~RowMajorBit) + | (EvalToRowMajor ? RowMajorBit : 0) + // TODO enable vectorization for mixed types + | (SameType && (CanVectorizeLhs || CanVectorizeRhs) ? PacketAccessBit : 0) + | (XprType::IsVectorAtCompileTime ? LinearAccessBit : 0), + + LhsOuterStrideBytes = int(LhsNestedCleaned::OuterStrideAtCompileTime) * int(sizeof(typename LhsNestedCleaned::Scalar)), + RhsOuterStrideBytes = int(RhsNestedCleaned::OuterStrideAtCompileTime) * int(sizeof(typename RhsNestedCleaned::Scalar)), + + Alignment = bool(CanVectorizeLhs) ? (LhsOuterStrideBytes<=0 || (int(LhsOuterStrideBytes) % EIGEN_PLAIN_ENUM_MAX(1,LhsAlignment))!=0 ? 0 : LhsAlignment) + : bool(CanVectorizeRhs) ? (RhsOuterStrideBytes<=0 || (int(RhsOuterStrideBytes) % EIGEN_PLAIN_ENUM_MAX(1,RhsAlignment))!=0 ? 0 : RhsAlignment) + : 0, + + /* CanVectorizeInner deserves special explanation. It does not affect the product flags. It is not used outside + * of Product. If the Product itself is not a packet-access expression, there is still a chance that the inner + * loop of the product might be vectorized. This is the meaning of CanVectorizeInner. Since it doesn't affect + * the Flags, it is safe to make this value depend on ActualPacketAccessBit, that doesn't affect the ABI. + */ + CanVectorizeInner = SameType + && LhsRowMajor + && (!RhsRowMajor) + && (LhsFlags & RhsFlags & ActualPacketAccessBit) + && (InnerSize % packet_traits::size == 0) + }; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const CoeffReturnType coeff(Index row, Index col) const + { + return (m_lhs.row(row).transpose().cwiseProduct( m_rhs.col(col) )).sum(); + } + + /* Allow index-based non-packet access. It is impossible though to allow index-based packed access, + * which is why we don't set the LinearAccessBit. + * TODO: this seems possible when the result is a vector + */ + EIGEN_DEVICE_FUNC const CoeffReturnType coeff(Index index) const + { + const Index row = (RowsAtCompileTime == 1 || MaxRowsAtCompileTime==1) ? 0 : index; + const Index col = (RowsAtCompileTime == 1 || MaxRowsAtCompileTime==1) ? index : 0; + return (m_lhs.row(row).transpose().cwiseProduct( m_rhs.col(col) )).sum(); + } + + template + const PacketType packet(Index row, Index col) const + { + PacketType res; + typedef etor_product_packet_impl PacketImpl; + PacketImpl::run(row, col, m_lhsImpl, m_rhsImpl, m_innerDim, res); + return res; + } + + template + const PacketType packet(Index index) const + { + const Index row = (RowsAtCompileTime == 1 || MaxRowsAtCompileTime==1) ? 0 : index; + const Index col = (RowsAtCompileTime == 1 || MaxRowsAtCompileTime==1) ? index : 0; + return packet(row,col); + } + +protected: + typename internal::add_const_on_value_type::type m_lhs; + typename internal::add_const_on_value_type::type m_rhs; + + LhsEtorType m_lhsImpl; + RhsEtorType m_rhsImpl; + + // TODO: Get rid of m_innerDim if known at compile time + Index m_innerDim; +}; + +template +struct product_evaluator, LazyCoeffBasedProductMode, DenseShape, DenseShape> + : product_evaluator, CoeffBasedProductMode, DenseShape, DenseShape> +{ + typedef Product XprType; + typedef Product BaseProduct; + typedef product_evaluator Base; + enum { + Flags = Base::Flags | EvalBeforeNestingBit + }; + EIGEN_DEVICE_FUNC explicit product_evaluator(const XprType& xpr) + : Base(BaseProduct(xpr.lhs(),xpr.rhs())) + {} +}; + +/**************************************** +*** Coeff based product, Packet path *** +****************************************/ + +template +struct etor_product_packet_impl +{ + static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Index innerDim, Packet &res) + { + etor_product_packet_impl::run(row, col, lhs, rhs, innerDim, res); + res = pmadd(pset1(lhs.coeff(row, Index(UnrollingIndex-1))), rhs.template packet(Index(UnrollingIndex-1), col), res); + } +}; + +template +struct etor_product_packet_impl +{ + static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Index innerDim, Packet &res) + { + etor_product_packet_impl::run(row, col, lhs, rhs, innerDim, res); + res = pmadd(lhs.template packet(row, Index(UnrollingIndex-1)), pset1(rhs.coeff(Index(UnrollingIndex-1), col)), res); + } +}; + +template +struct etor_product_packet_impl +{ + static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Index /*innerDim*/, Packet &res) + { + res = pmul(pset1(lhs.coeff(row, Index(0))),rhs.template packet(Index(0), col)); + } +}; + +template +struct etor_product_packet_impl +{ + static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Index /*innerDim*/, Packet &res) + { + res = pmul(lhs.template packet(row, Index(0)), pset1(rhs.coeff(Index(0), col))); + } +}; + +template +struct etor_product_packet_impl +{ + static EIGEN_STRONG_INLINE void run(Index /*row*/, Index /*col*/, const Lhs& /*lhs*/, const Rhs& /*rhs*/, Index /*innerDim*/, Packet &res) + { + res = pset1(typename unpacket_traits::type(0)); + } +}; + +template +struct etor_product_packet_impl +{ + static EIGEN_STRONG_INLINE void run(Index /*row*/, Index /*col*/, const Lhs& /*lhs*/, const Rhs& /*rhs*/, Index /*innerDim*/, Packet &res) + { + res = pset1(typename unpacket_traits::type(0)); + } +}; + +template +struct etor_product_packet_impl +{ + static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Index innerDim, Packet& res) + { + res = pset1(typename unpacket_traits::type(0)); + for(Index i = 0; i < innerDim; ++i) + res = pmadd(pset1(lhs.coeff(row, i)), rhs.template packet(i, col), res); + } +}; + +template +struct etor_product_packet_impl +{ + static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Index innerDim, Packet& res) + { + res = pset1(typename unpacket_traits::type(0)); + for(Index i = 0; i < innerDim; ++i) + res = pmadd(lhs.template packet(row, i), pset1(rhs.coeff(i, col)), res); + } +}; + + +/*************************************************************************** +* Triangular products +***************************************************************************/ +template +struct triangular_product_impl; + +template +struct generic_product_impl + : generic_product_impl_base > +{ + typedef typename Product::Scalar Scalar; + + template + static void scaleAndAddTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) + { + triangular_product_impl + ::run(dst, lhs.nestedExpression(), rhs, alpha); + } +}; + +template +struct generic_product_impl +: generic_product_impl_base > +{ + typedef typename Product::Scalar Scalar; + + template + static void scaleAndAddTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) + { + triangular_product_impl::run(dst, lhs, rhs.nestedExpression(), alpha); + } +}; + + +/*************************************************************************** +* SelfAdjoint products +***************************************************************************/ +template +struct selfadjoint_product_impl; + +template +struct generic_product_impl + : generic_product_impl_base > +{ + typedef typename Product::Scalar Scalar; + + template + static void scaleAndAddTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) + { + selfadjoint_product_impl::run(dst, lhs.nestedExpression(), rhs, alpha); + } +}; + +template +struct generic_product_impl +: generic_product_impl_base > +{ + typedef typename Product::Scalar Scalar; + + template + static void scaleAndAddTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha) + { + selfadjoint_product_impl::run(dst, lhs, rhs.nestedExpression(), alpha); + } +}; + + +/*************************************************************************** +* Diagonal products +***************************************************************************/ + +template +struct diagonal_product_evaluator_base + : evaluator_base +{ + typedef typename ScalarBinaryOpTraits::ReturnType Scalar; +public: + enum { + CoeffReadCost = NumTraits::MulCost + evaluator::CoeffReadCost + evaluator::CoeffReadCost, + + MatrixFlags = evaluator::Flags, + DiagFlags = evaluator::Flags, + _StorageOrder = MatrixFlags & RowMajorBit ? RowMajor : ColMajor, + _ScalarAccessOnDiag = !((int(_StorageOrder) == ColMajor && int(ProductOrder) == OnTheLeft) + ||(int(_StorageOrder) == RowMajor && int(ProductOrder) == OnTheRight)), + _SameTypes = is_same::value, + // FIXME currently we need same types, but in the future the next rule should be the one + //_Vectorizable = bool(int(MatrixFlags)&PacketAccessBit) && ((!_PacketOnDiag) || (_SameTypes && bool(int(DiagFlags)&PacketAccessBit))), + _Vectorizable = bool(int(MatrixFlags)&PacketAccessBit) && _SameTypes && (_ScalarAccessOnDiag || (bool(int(DiagFlags)&PacketAccessBit))), + _LinearAccessMask = (MatrixType::RowsAtCompileTime==1 || MatrixType::ColsAtCompileTime==1) ? LinearAccessBit : 0, + Flags = ((HereditaryBits|_LinearAccessMask) & (unsigned int)(MatrixFlags)) | (_Vectorizable ? PacketAccessBit : 0), + Alignment = evaluator::Alignment + }; + + diagonal_product_evaluator_base(const MatrixType &mat, const DiagonalType &diag) + : m_diagImpl(diag), m_matImpl(mat) + { + EIGEN_INTERNAL_CHECK_COST_VALUE(NumTraits::MulCost); + EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar coeff(Index idx) const + { + return m_diagImpl.coeff(idx) * m_matImpl.coeff(idx); + } + +protected: + template + EIGEN_STRONG_INLINE PacketType packet_impl(Index row, Index col, Index id, internal::true_type) const + { + return internal::pmul(m_matImpl.template packet(row, col), + internal::pset1(m_diagImpl.coeff(id))); + } + + template + EIGEN_STRONG_INLINE PacketType packet_impl(Index row, Index col, Index id, internal::false_type) const + { + enum { + InnerSize = (MatrixType::Flags & RowMajorBit) ? MatrixType::ColsAtCompileTime : MatrixType::RowsAtCompileTime, + DiagonalPacketLoadMode = EIGEN_PLAIN_ENUM_MIN(LoadMode,((InnerSize%16) == 0) ? int(Aligned16) : int(evaluator::Alignment)) // FIXME hardcoded 16!! + }; + return internal::pmul(m_matImpl.template packet(row, col), + m_diagImpl.template packet(id)); + } + + evaluator m_diagImpl; + evaluator m_matImpl; +}; + +// diagonal * dense +template +struct product_evaluator, ProductTag, DiagonalShape, DenseShape> + : diagonal_product_evaluator_base, OnTheLeft> +{ + typedef diagonal_product_evaluator_base, OnTheLeft> Base; + using Base::m_diagImpl; + using Base::m_matImpl; + using Base::coeff; + typedef typename Base::Scalar Scalar; + + typedef Product XprType; + typedef typename XprType::PlainObject PlainObject; + + enum { + StorageOrder = int(Rhs::Flags) & RowMajorBit ? RowMajor : ColMajor + }; + + EIGEN_DEVICE_FUNC explicit product_evaluator(const XprType& xpr) + : Base(xpr.rhs(), xpr.lhs().diagonal()) + { + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar coeff(Index row, Index col) const + { + return m_diagImpl.coeff(row) * m_matImpl.coeff(row, col); + } + +#ifndef __CUDACC__ + template + EIGEN_STRONG_INLINE PacketType packet(Index row, Index col) const + { + // FIXME: NVCC used to complain about the template keyword, but we have to check whether this is still the case. + // See also similar calls below. + return this->template packet_impl(row,col, row, + typename internal::conditional::type()); + } + + template + EIGEN_STRONG_INLINE PacketType packet(Index idx) const + { + return packet(int(StorageOrder)==ColMajor?idx:0,int(StorageOrder)==ColMajor?0:idx); + } +#endif +}; + +// dense * diagonal +template +struct product_evaluator, ProductTag, DenseShape, DiagonalShape> + : diagonal_product_evaluator_base, OnTheRight> +{ + typedef diagonal_product_evaluator_base, OnTheRight> Base; + using Base::m_diagImpl; + using Base::m_matImpl; + using Base::coeff; + typedef typename Base::Scalar Scalar; + + typedef Product XprType; + typedef typename XprType::PlainObject PlainObject; + + enum { StorageOrder = int(Lhs::Flags) & RowMajorBit ? RowMajor : ColMajor }; + + EIGEN_DEVICE_FUNC explicit product_evaluator(const XprType& xpr) + : Base(xpr.lhs(), xpr.rhs().diagonal()) + { + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar coeff(Index row, Index col) const + { + return m_matImpl.coeff(row, col) * m_diagImpl.coeff(col); + } + +#ifndef __CUDACC__ + template + EIGEN_STRONG_INLINE PacketType packet(Index row, Index col) const + { + return this->template packet_impl(row,col, col, + typename internal::conditional::type()); + } + + template + EIGEN_STRONG_INLINE PacketType packet(Index idx) const + { + return packet(int(StorageOrder)==ColMajor?idx:0,int(StorageOrder)==ColMajor?0:idx); + } +#endif +}; + +/*************************************************************************** +* Products with permutation matrices +***************************************************************************/ + +/** \internal + * \class permutation_matrix_product + * Internal helper class implementing the product between a permutation matrix and a matrix. + * This class is specialized for DenseShape below and for SparseShape in SparseCore/SparsePermutation.h + */ +template +struct permutation_matrix_product; + +template +struct permutation_matrix_product +{ + typedef typename nested_eval::type MatrixType; + typedef typename remove_all::type MatrixTypeCleaned; + + template + static inline void run(Dest& dst, const PermutationType& perm, const ExpressionType& xpr) + { + MatrixType mat(xpr); + const Index n = Side==OnTheLeft ? mat.rows() : mat.cols(); + // FIXME we need an is_same for expression that is not sensitive to constness. For instance + // is_same_xpr, Block >::value should be true. + //if(is_same::value && extract_data(dst) == extract_data(mat)) + if(is_same_dense(dst, mat)) + { + // apply the permutation inplace + Matrix mask(perm.size()); + mask.fill(false); + Index r = 0; + while(r < perm.size()) + { + // search for the next seed + while(r=perm.size()) + break; + // we got one, let's follow it until we are back to the seed + Index k0 = r++; + Index kPrev = k0; + mask.coeffRef(k0) = true; + for(Index k=perm.indices().coeff(k0); k!=k0; k=perm.indices().coeff(k)) + { + Block(dst, k) + .swap(Block + (dst,((Side==OnTheLeft) ^ Transposed) ? k0 : kPrev)); + + mask.coeffRef(k) = true; + kPrev = k; + } + } + } + else + { + for(Index i = 0; i < n; ++i) + { + Block + (dst, ((Side==OnTheLeft) ^ Transposed) ? perm.indices().coeff(i) : i) + + = + + Block + (mat, ((Side==OnTheRight) ^ Transposed) ? perm.indices().coeff(i) : i); + } + } + } +}; + +template +struct generic_product_impl +{ + template + static void evalTo(Dest& dst, const Lhs& lhs, const Rhs& rhs) + { + permutation_matrix_product::run(dst, lhs, rhs); + } +}; + +template +struct generic_product_impl +{ + template + static void evalTo(Dest& dst, const Lhs& lhs, const Rhs& rhs) + { + permutation_matrix_product::run(dst, rhs, lhs); + } +}; + +template +struct generic_product_impl, Rhs, PermutationShape, MatrixShape, ProductTag> +{ + template + static void evalTo(Dest& dst, const Inverse& lhs, const Rhs& rhs) + { + permutation_matrix_product::run(dst, lhs.nestedExpression(), rhs); + } +}; + +template +struct generic_product_impl, MatrixShape, PermutationShape, ProductTag> +{ + template + static void evalTo(Dest& dst, const Lhs& lhs, const Inverse& rhs) + { + permutation_matrix_product::run(dst, rhs.nestedExpression(), lhs); + } +}; + + +/*************************************************************************** +* Products with transpositions matrices +***************************************************************************/ + +// FIXME could we unify Transpositions and Permutation into a single "shape"?? + +/** \internal + * \class transposition_matrix_product + * Internal helper class implementing the product between a permutation matrix and a matrix. + */ +template +struct transposition_matrix_product +{ + typedef typename nested_eval::type MatrixType; + typedef typename remove_all::type MatrixTypeCleaned; + + template + static inline void run(Dest& dst, const TranspositionType& tr, const ExpressionType& xpr) + { + MatrixType mat(xpr); + typedef typename TranspositionType::StorageIndex StorageIndex; + const Index size = tr.size(); + StorageIndex j = 0; + + if(!is_same_dense(dst,mat)) + dst = mat; + + for(Index k=(Transposed?size-1:0) ; Transposed?k>=0:k +struct generic_product_impl +{ + template + static void evalTo(Dest& dst, const Lhs& lhs, const Rhs& rhs) + { + transposition_matrix_product::run(dst, lhs, rhs); + } +}; + +template +struct generic_product_impl +{ + template + static void evalTo(Dest& dst, const Lhs& lhs, const Rhs& rhs) + { + transposition_matrix_product::run(dst, rhs, lhs); + } +}; + + +template +struct generic_product_impl, Rhs, TranspositionsShape, MatrixShape, ProductTag> +{ + template + static void evalTo(Dest& dst, const Transpose& lhs, const Rhs& rhs) + { + transposition_matrix_product::run(dst, lhs.nestedExpression(), rhs); + } +}; + +template +struct generic_product_impl, MatrixShape, TranspositionsShape, ProductTag> +{ + template + static void evalTo(Dest& dst, const Lhs& lhs, const Transpose& rhs) + { + transposition_matrix_product::run(dst, rhs.nestedExpression(), lhs); + } +}; + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_PRODUCT_EVALUATORS_H diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Core/Random.h b/ground/gcs/src/libs/eigen/Eigen/src/Core/Random.h index 480fea408d..6faf789c76 100644 --- a/ground/gcs/src/libs/eigen/Eigen/src/Core/Random.h +++ b/ground/gcs/src/libs/eigen/Eigen/src/Core/Random.h @@ -16,8 +16,7 @@ namespace internal { template struct scalar_random_op { EIGEN_EMPTY_STRUCT_CTOR(scalar_random_op) - template - inline const Scalar operator() (Index, Index = 0) const { return random(); } + inline const Scalar operator() () const { return random(); } }; template @@ -28,12 +27,18 @@ struct functor_traits > /** \returns a random matrix expression * + * Numbers are uniformly spread through their whole definition range for integer types, + * and in the [-1:1] range for floating point scalar types. + * * The parameters \a rows and \a cols are the number of rows and of columns of * the returned matrix. Must be compatible with this MatrixBase type. * + * \not_reentrant + * * This variant is meant to be used for dynamic-size matrix types. For fixed-size types, * it is redundant to pass \a rows and \a cols as arguments, so Random() should be used * instead. + * * * Example: \include MatrixBase_random_int_int.cpp * Output: \verbinclude MatrixBase_random_int_int.out @@ -41,22 +46,28 @@ struct functor_traits > * This expression has the "evaluate before nesting" flag so that it will be evaluated into * a temporary matrix whenever it is nested in a larger expression. This prevents unexpected * behavior with expressions involving random matrices. + * + * See DenseBase::NullaryExpr(Index, const CustomNullaryOp&) for an example using C++11 random generators. * - * \sa MatrixBase::setRandom(), MatrixBase::Random(Index), MatrixBase::Random() + * \sa DenseBase::setRandom(), DenseBase::Random(Index), DenseBase::Random() */ template -inline const CwiseNullaryOp::Scalar>, Derived> +inline const typename DenseBase::RandomReturnType DenseBase::Random(Index rows, Index cols) { return NullaryExpr(rows, cols, internal::scalar_random_op()); } /** \returns a random vector expression + * + * Numbers are uniformly spread through their whole definition range for integer types, + * and in the [-1:1] range for floating point scalar types. * * The parameter \a size is the size of the returned vector. * Must be compatible with this MatrixBase type. * * \only_for_vectors + * \not_reentrant * * This variant is meant to be used for dynamic-size vector types. For fixed-size types, * it is redundant to pass \a size as argument, so Random() should be used @@ -69,10 +80,10 @@ DenseBase::Random(Index rows, Index cols) * a temporary vector whenever it is nested in a larger expression. This prevents unexpected * behavior with expressions involving random matrices. * - * \sa MatrixBase::setRandom(), MatrixBase::Random(Index,Index), MatrixBase::Random() + * \sa DenseBase::setRandom(), DenseBase::Random(Index,Index), DenseBase::Random() */ template -inline const CwiseNullaryOp::Scalar>, Derived> +inline const typename DenseBase::RandomReturnType DenseBase::Random(Index size) { return NullaryExpr(size, internal::scalar_random_op()); @@ -80,6 +91,9 @@ DenseBase::Random(Index size) /** \returns a fixed-size random matrix or vector expression * + * Numbers are uniformly spread through their whole definition range for integer types, + * and in the [-1:1] range for floating point scalar types. + * * This variant is only for fixed-size MatrixBase types. For dynamic-size types, you * need to use the variants taking size arguments. * @@ -89,11 +103,13 @@ DenseBase::Random(Index size) * This expression has the "evaluate before nesting" flag so that it will be evaluated into * a temporary matrix whenever it is nested in a larger expression. This prevents unexpected * behavior with expressions involving random matrices. + * + * \not_reentrant * - * \sa MatrixBase::setRandom(), MatrixBase::Random(Index,Index), MatrixBase::Random(Index) + * \sa DenseBase::setRandom(), DenseBase::Random(Index,Index), DenseBase::Random(Index) */ template -inline const CwiseNullaryOp::Scalar>, Derived> +inline const typename DenseBase::RandomReturnType DenseBase::Random() { return NullaryExpr(RowsAtCompileTime, ColsAtCompileTime, internal::scalar_random_op()); @@ -101,6 +117,11 @@ DenseBase::Random() /** Sets all coefficients in this expression to random values. * + * Numbers are uniformly spread through their whole definition range for integer types, + * and in the [-1:1] range for floating point scalar types. + * + * \not_reentrant + * * Example: \include MatrixBase_setRandom.cpp * Output: \verbinclude MatrixBase_setRandom.out * @@ -114,12 +135,16 @@ inline Derived& DenseBase::setRandom() /** Resizes to the given \a newSize, and sets all coefficients in this expression to random values. * + * Numbers are uniformly spread through their whole definition range for integer types, + * and in the [-1:1] range for floating point scalar types. + * * \only_for_vectors + * \not_reentrant * * Example: \include Matrix_setRandom_int.cpp * Output: \verbinclude Matrix_setRandom_int.out * - * \sa MatrixBase::setRandom(), setRandom(Index,Index), class CwiseNullaryOp, MatrixBase::Random() + * \sa DenseBase::setRandom(), setRandom(Index,Index), class CwiseNullaryOp, DenseBase::Random() */ template EIGEN_STRONG_INLINE Derived& @@ -131,19 +156,24 @@ PlainObjectBase::setRandom(Index newSize) /** Resizes to the given size, and sets all coefficients in this expression to random values. * - * \param nbRows the new number of rows - * \param nbCols the new number of columns + * Numbers are uniformly spread through their whole definition range for integer types, + * and in the [-1:1] range for floating point scalar types. + * + * \not_reentrant + * + * \param rows the new number of rows + * \param cols the new number of columns * * Example: \include Matrix_setRandom_int_int.cpp * Output: \verbinclude Matrix_setRandom_int_int.out * - * \sa MatrixBase::setRandom(), setRandom(Index), class CwiseNullaryOp, MatrixBase::Random() + * \sa DenseBase::setRandom(), setRandom(Index), class CwiseNullaryOp, DenseBase::Random() */ template EIGEN_STRONG_INLINE Derived& -PlainObjectBase::setRandom(Index nbRows, Index nbCols) +PlainObjectBase::setRandom(Index rows, Index cols) { - resize(nbRows, nbCols); + resize(rows, cols); return setRandom(); } diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Core/Redux.h b/ground/gcs/src/libs/eigen/Eigen/src/Core/Redux.h index 9b8662a6f9..b6e8f88870 100644 --- a/ground/gcs/src/libs/eigen/Eigen/src/Core/Redux.h +++ b/ground/gcs/src/libs/eigen/Eigen/src/Core/Redux.h @@ -27,8 +27,9 @@ template struct redux_traits { public: + typedef typename find_best_packet::type PacketType; enum { - PacketSize = packet_traits::size, + PacketSize = unpacket_traits::size, InnerMaxSize = int(Derived::IsRowMajor) ? Derived::MaxColsAtCompileTime : Derived::MaxRowsAtCompileTime @@ -37,8 +38,8 @@ struct redux_traits enum { MightVectorize = (int(Derived::Flags)&ActualPacketAccessBit) && (functor_traits::PacketAccess), - MayLinearVectorize = MightVectorize && (int(Derived::Flags)&LinearAccessBit), - MaySliceVectorize = MightVectorize && int(InnerMaxSize)>=3*PacketSize + MayLinearVectorize = bool(MightVectorize) && (int(Derived::Flags)&LinearAccessBit), + MaySliceVectorize = bool(MightVectorize) && int(InnerMaxSize)>=3*PacketSize }; public: @@ -50,21 +51,34 @@ struct redux_traits public: enum { - Cost = ( Derived::SizeAtCompileTime == Dynamic - || Derived::CoeffReadCost == Dynamic - || (Derived::SizeAtCompileTime!=1 && functor_traits::Cost == Dynamic) - ) ? Dynamic - : Derived::SizeAtCompileTime * Derived::CoeffReadCost - + (Derived::SizeAtCompileTime-1) * functor_traits::Cost, + Cost = Derived::SizeAtCompileTime == Dynamic ? HugeCost + : Derived::SizeAtCompileTime * Derived::CoeffReadCost + (Derived::SizeAtCompileTime-1) * functor_traits::Cost, UnrollingLimit = EIGEN_UNROLLING_LIMIT * (int(Traversal) == int(DefaultTraversal) ? 1 : int(PacketSize)) }; public: enum { - Unrolling = Cost != Dynamic && Cost <= UnrollingLimit - ? CompleteUnrolling - : NoUnrolling + Unrolling = Cost <= UnrollingLimit ? CompleteUnrolling : NoUnrolling }; + +#ifdef EIGEN_DEBUG_ASSIGN + static void debug() + { + std::cerr << "Xpr: " << typeid(typename Derived::XprType).name() << std::endl; + std::cerr.setf(std::ios::hex, std::ios::basefield); + EIGEN_DEBUG_VAR(Derived::Flags) + std::cerr.unsetf(std::ios::hex); + EIGEN_DEBUG_VAR(InnerMaxSize) + EIGEN_DEBUG_VAR(PacketSize) + EIGEN_DEBUG_VAR(MightVectorize) + EIGEN_DEBUG_VAR(MayLinearVectorize) + EIGEN_DEBUG_VAR(MaySliceVectorize) + EIGEN_DEBUG_VAR(Traversal) + EIGEN_DEBUG_VAR(UnrollingLimit) + EIGEN_DEBUG_VAR(Unrolling) + std::cerr << std::endl; + } +#endif }; /*************************************************************************** @@ -82,6 +96,7 @@ struct redux_novec_unroller typedef typename Derived::Scalar Scalar; + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE Scalar run(const Derived &mat, const Func& func) { return func(redux_novec_unroller::run(mat,func), @@ -99,6 +114,7 @@ struct redux_novec_unroller typedef typename Derived::Scalar Scalar; + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE Scalar run(const Derived &mat, const Func&) { return mat.coeffByOuterInner(outer, inner); @@ -112,6 +128,7 @@ template struct redux_novec_unroller { typedef typename Derived::Scalar Scalar; + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE Scalar run(const Derived&, const Func&) { return Scalar(); } }; @@ -121,12 +138,12 @@ template struct redux_vec_unroller { enum { - PacketSize = packet_traits::size, + PacketSize = redux_traits::PacketSize, HalfLength = Length/2 }; typedef typename Derived::Scalar Scalar; - typedef typename packet_traits::type PacketScalar; + typedef typename redux_traits::PacketType PacketScalar; static EIGEN_STRONG_INLINE PacketScalar run(const Derived &mat, const Func& func) { @@ -140,18 +157,18 @@ template struct redux_vec_unroller { enum { - index = Start * packet_traits::size, + index = Start * redux_traits::PacketSize, outer = index / int(Derived::InnerSizeAtCompileTime), inner = index % int(Derived::InnerSizeAtCompileTime), - alignment = (Derived::Flags & AlignedBit) ? Aligned : Unaligned + alignment = Derived::Alignment }; typedef typename Derived::Scalar Scalar; - typedef typename packet_traits::type PacketScalar; + typedef typename redux_traits::PacketType PacketScalar; static EIGEN_STRONG_INLINE PacketScalar run(const Derived &mat, const Func&) { - return mat.template packetByOuterInner(outer, inner); + return mat.template packetByOuterInner(outer, inner); } }; @@ -169,8 +186,8 @@ template struct redux_impl { typedef typename Derived::Scalar Scalar; - typedef typename Derived::Index Index; - static EIGEN_STRONG_INLINE Scalar run(const Derived& mat, const Func& func) + EIGEN_DEVICE_FUNC + static EIGEN_STRONG_INLINE Scalar run(const Derived &mat, const Func& func) { eigen_assert(mat.rows()>0 && mat.cols()>0 && "you are using an empty matrix"); Scalar res; @@ -193,19 +210,19 @@ template struct redux_impl { typedef typename Derived::Scalar Scalar; - typedef typename packet_traits::type PacketScalar; - typedef typename Derived::Index Index; + typedef typename redux_traits::PacketType PacketScalar; - static Scalar run(const Derived& mat, const Func& func) + static Scalar run(const Derived &mat, const Func& func) { const Index size = mat.size(); - eigen_assert(size && "you are using an empty matrix"); - const Index packetSize = packet_traits::size; - const Index alignedStart = internal::first_aligned(mat); + + const Index packetSize = redux_traits::PacketSize; + const int packetAlignment = unpacket_traits::alignment; enum { - alignment = bool(Derived::Flags & DirectAccessBit) || bool(Derived::Flags & AlignedBit) - ? Aligned : Unaligned + alignment0 = (bool(Derived::Flags & DirectAccessBit) && bool(packet_traits::AlignedOnScalar)) ? int(packetAlignment) : int(Unaligned), + alignment = EIGEN_PLAIN_ENUM_MAX(alignment0, Derived::Alignment) }; + const Index alignedStart = internal::first_default_aligned(mat.nestedExpression()); const Index alignedSize2 = ((size-alignedStart)/(2*packetSize))*(2*packetSize); const Index alignedSize = ((size-alignedStart)/(packetSize))*(packetSize); const Index alignedEnd2 = alignedStart + alignedSize2; @@ -213,19 +230,19 @@ struct redux_impl Scalar res; if(alignedSize) { - PacketScalar packet_res0 = mat.template packet(alignedStart); + PacketScalar packet_res0 = mat.template packet(alignedStart); if(alignedSize>packetSize) // we have at least two packets to partly unroll the loop { - PacketScalar packet_res1 = mat.template packet(alignedStart+packetSize); + PacketScalar packet_res1 = mat.template packet(alignedStart+packetSize); for(Index index = alignedStart + 2*packetSize; index < alignedEnd2; index += 2*packetSize) { - packet_res0 = func.packetOp(packet_res0, mat.template packet(index)); - packet_res1 = func.packetOp(packet_res1, mat.template packet(index+packetSize)); + packet_res0 = func.packetOp(packet_res0, mat.template packet(index)); + packet_res1 = func.packetOp(packet_res1, mat.template packet(index+packetSize)); } packet_res0 = func.packetOp(packet_res0,packet_res1); if(alignedEnd>alignedEnd2) - packet_res0 = func.packetOp(packet_res0, mat.template packet(alignedEnd2)); + packet_res0 = func.packetOp(packet_res0, mat.template packet(alignedEnd2)); } res = func.predux(packet_res0); @@ -252,25 +269,24 @@ template struct redux_impl { typedef typename Derived::Scalar Scalar; - typedef typename packet_traits::type PacketScalar; - typedef typename Derived::Index Index; + typedef typename redux_traits::PacketType PacketType; - static Scalar run(const Derived& mat, const Func& func) + EIGEN_DEVICE_FUNC static Scalar run(const Derived &mat, const Func& func) { eigen_assert(mat.rows()>0 && mat.cols()>0 && "you are using an empty matrix"); const Index innerSize = mat.innerSize(); const Index outerSize = mat.outerSize(); enum { - packetSize = packet_traits::size + packetSize = redux_traits::PacketSize }; const Index packetedInnerSize = ((innerSize)/packetSize)*packetSize; Scalar res; if(packetedInnerSize) { - PacketScalar packet_res = mat.template packet(0,0); + PacketType packet_res = mat.template packet(0,0); for(Index j=0; j(j,i)); + packet_res = func.packetOp(packet_res, mat.template packetByOuterInner(j,i)); res = func.predux(packet_res); for(Index j=0; j struct redux_impl { typedef typename Derived::Scalar Scalar; - typedef typename packet_traits::type PacketScalar; + + typedef typename redux_traits::PacketType PacketScalar; enum { - PacketSize = packet_traits::size, + PacketSize = redux_traits::PacketSize, Size = Derived::SizeAtCompileTime, VectorizedSize = (Size / PacketSize) * PacketSize }; - static EIGEN_STRONG_INLINE Scalar run(const Derived& mat, const Func& func) + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE Scalar run(const Derived &mat, const Func& func) { eigen_assert(mat.rows()>0 && mat.cols()>0 && "you are using an empty matrix"); - Scalar res = func.predux(redux_vec_unroller::run(mat,func)); - if (VectorizedSize != Size) - res = func(res,redux_novec_unroller::run(mat,func)); - return res; + if (VectorizedSize > 0) { + Scalar res = func.predux(redux_vec_unroller::run(mat,func)); + if (VectorizedSize != Size) + res = func(res,redux_novec_unroller::run(mat,func)); + return res; + } + else { + return redux_novec_unroller::run(mat,func); + } } }; +// evaluator adaptor +template +class redux_evaluator +{ +public: + typedef _XprType XprType; + EIGEN_DEVICE_FUNC explicit redux_evaluator(const XprType &xpr) : m_evaluator(xpr), m_xpr(xpr) {} + + typedef typename XprType::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + typedef typename XprType::PacketScalar PacketScalar; + typedef typename XprType::PacketReturnType PacketReturnType; + + enum { + MaxRowsAtCompileTime = XprType::MaxRowsAtCompileTime, + MaxColsAtCompileTime = XprType::MaxColsAtCompileTime, + // TODO we should not remove DirectAccessBit and rather find an elegant way to query the alignment offset at runtime from the evaluator + Flags = evaluator::Flags & ~DirectAccessBit, + IsRowMajor = XprType::IsRowMajor, + SizeAtCompileTime = XprType::SizeAtCompileTime, + InnerSizeAtCompileTime = XprType::InnerSizeAtCompileTime, + CoeffReadCost = evaluator::CoeffReadCost, + Alignment = evaluator::Alignment + }; + + EIGEN_DEVICE_FUNC Index rows() const { return m_xpr.rows(); } + EIGEN_DEVICE_FUNC Index cols() const { return m_xpr.cols(); } + EIGEN_DEVICE_FUNC Index size() const { return m_xpr.size(); } + EIGEN_DEVICE_FUNC Index innerSize() const { return m_xpr.innerSize(); } + EIGEN_DEVICE_FUNC Index outerSize() const { return m_xpr.outerSize(); } + + EIGEN_DEVICE_FUNC + CoeffReturnType coeff(Index row, Index col) const + { return m_evaluator.coeff(row, col); } + + EIGEN_DEVICE_FUNC + CoeffReturnType coeff(Index index) const + { return m_evaluator.coeff(index); } + + template + PacketType packet(Index row, Index col) const + { return m_evaluator.template packet(row, col); } + + template + PacketType packet(Index index) const + { return m_evaluator.template packet(index); } + + EIGEN_DEVICE_FUNC + CoeffReturnType coeffByOuterInner(Index outer, Index inner) const + { return m_evaluator.coeff(IsRowMajor ? outer : inner, IsRowMajor ? inner : outer); } + + template + PacketType packetByOuterInner(Index outer, Index inner) const + { return m_evaluator.template packet(IsRowMajor ? outer : inner, IsRowMajor ? inner : outer); } + + const XprType & nestedExpression() const { return m_xpr; } + +protected: + internal::evaluator m_evaluator; + const XprType &m_xpr; +}; + } // end namespace internal /*************************************************************************** @@ -317,18 +401,21 @@ struct redux_impl /** \returns the result of a full redux operation on the whole matrix or vector using \a func * * The template parameter \a BinaryOp is the type of the functor \a func which must be - * an associative operator. Both current STL and TR1 functor styles are handled. + * an associative operator. Both current C++98 and C++11 functor styles are handled. * * \sa DenseBase::sum(), DenseBase::minCoeff(), DenseBase::maxCoeff(), MatrixBase::colwise(), MatrixBase::rowwise() */ template template -EIGEN_STRONG_INLINE typename internal::result_of::Scalar)>::type +typename internal::traits::Scalar DenseBase::redux(const Func& func) const { - typedef typename internal::remove_all::type ThisNested; - return internal::redux_impl - ::run(derived(), func); + eigen_assert(this->rows()>0 && this->cols()>0 && "you are using an empty matrix"); + + typedef typename internal::redux_evaluator ThisEvaluator; + ThisEvaluator thisEval(derived()); + + return internal::redux_impl::run(thisEval, func); } /** \returns the minimum of all coefficients of \c *this. @@ -338,7 +425,7 @@ template EIGEN_STRONG_INLINE typename internal::traits::Scalar DenseBase::minCoeff() const { - return this->redux(Eigen::internal::scalar_min_op()); + return derived().redux(Eigen::internal::scalar_min_op()); } /** \returns the maximum of all coefficients of \c *this. @@ -348,10 +435,12 @@ template EIGEN_STRONG_INLINE typename internal::traits::Scalar DenseBase::maxCoeff() const { - return this->redux(Eigen::internal::scalar_max_op()); + return derived().redux(Eigen::internal::scalar_max_op()); } -/** \returns the sum of all coefficients of *this +/** \returns the sum of all coefficients of \c *this + * + * If \c *this is empty, then the value 0 is returned. * * \sa trace(), prod(), mean() */ @@ -361,7 +450,7 @@ DenseBase::sum() const { if(SizeAtCompileTime==0 || (SizeAtCompileTime==Dynamic && size()==0)) return Scalar(0); - return this->redux(Eigen::internal::scalar_sum_op()); + return derived().redux(Eigen::internal::scalar_sum_op()); } /** \returns the mean of all coefficients of *this @@ -372,7 +461,14 @@ template EIGEN_STRONG_INLINE typename internal::traits::Scalar DenseBase::mean() const { - return Scalar(this->redux(Eigen::internal::scalar_sum_op())) / Scalar(this->size()); +#ifdef __INTEL_COMPILER + #pragma warning push + #pragma warning ( disable : 2259 ) +#endif + return Scalar(derived().redux(Eigen::internal::scalar_sum_op())) / Scalar(this->size()); +#ifdef __INTEL_COMPILER + #pragma warning pop +#endif } /** \returns the product of all coefficients of *this @@ -388,7 +484,7 @@ DenseBase::prod() const { if(SizeAtCompileTime==0 || (SizeAtCompileTime==Dynamic && size()==0)) return Scalar(1); - return this->redux(Eigen::internal::scalar_product_op()); + return derived().redux(Eigen::internal::scalar_product_op()); } /** \returns the trace of \c *this, i.e. the sum of the coefficients on the main diagonal. diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Core/Ref.h b/ground/gcs/src/libs/eigen/Eigen/src/Core/Ref.h index 7a3becaf88..bdf24f52ad 100644 --- a/ground/gcs/src/libs/eigen/Eigen/src/Core/Ref.h +++ b/ground/gcs/src/libs/eigen/Eigen/src/Core/Ref.h @@ -12,79 +12,6 @@ namespace Eigen { -template class RefBase; -template,OuterStride<> >::type > class Ref; - -/** \class Ref - * \ingroup Core_Module - * - * \brief A matrix or vector expression mapping an existing expressions - * - * \tparam PlainObjectType the equivalent matrix type of the mapped data - * \tparam Options specifies whether the pointer is \c #Aligned, or \c #Unaligned. - * The default is \c #Unaligned. - * \tparam StrideType optionally specifies strides. By default, Ref implies a contiguous storage along the inner dimension (inner stride==1), - * but accept a variable outer stride (leading dimension). - * This can be overridden by specifying strides. - * The type passed here must be a specialization of the Stride template, see examples below. - * - * This class permits to write non template functions taking Eigen's object as parameters while limiting the number of copies. - * A Ref<> object can represent either a const expression or a l-value: - * \code - * // in-out argument: - * void foo1(Ref x); - * - * // read-only const argument: - * void foo2(const Ref& x); - * \endcode - * - * In the in-out case, the input argument must satisfies the constraints of the actual Ref<> type, otherwise a compilation issue will be triggered. - * By default, a Ref can reference any dense vector expression of float having a contiguous memory layout. - * Likewise, a Ref can reference any column major dense matrix expression of float whose column's elements are contiguously stored with - * the possibility to have a constant space inbetween each column, i.e.: the inner stride mmust be equal to 1, but the outer-stride (or leading dimension), - * can be greater than the number of rows. - * - * In the const case, if the input expression does not match the above requirement, then it is evaluated into a temporary before being passed to the function. - * Here are some examples: - * \code - * MatrixXf A; - * VectorXf a; - * foo1(a.head()); // OK - * foo1(A.col()); // OK - * foo1(A.row()); // compilation error because here innerstride!=1 - * foo2(A.row()); // The row is copied into a contiguous temporary - * foo2(2*a); // The expression is evaluated into a temporary - * foo2(A.col().segment(2,4)); // No temporary - * \endcode - * - * The range of inputs that can be referenced without temporary can be enlarged using the last two template parameter. - * Here is an example accepting an innerstride!=1: - * \code - * // in-out argument: - * void foo3(Ref > x); - * foo3(A.row()); // OK - * \endcode - * The downside here is that the function foo3 might be significantly slower than foo1 because it won't be able to exploit vectorization, and will involved more - * expensive address computations even if the input is contiguously stored in memory. To overcome this issue, one might propose to overloads internally calling a - * template function, e.g.: - * \code - * // in the .h: - * void foo(const Ref& A); - * void foo(const Ref >& A); - * - * // in the .cpp: - * template void foo_impl(const TypeOfA& A) { - * ... // crazy code goes here - * } - * void foo(const Ref& A) { foo_impl(A); } - * void foo(const Ref >& A) { foo_impl(A); } - * \endcode - * - * - * \sa PlainObjectBase::Map(), \ref TopicStorageOrders - */ - namespace internal { template @@ -95,7 +22,8 @@ struct traits > typedef _StrideType StrideType; enum { Options = _Options, - Flags = traits >::Flags | NestByRefBit + Flags = traits >::Flags | NestByRefBit, + Alignment = traits >::Alignment }; template struct match { @@ -107,7 +35,13 @@ struct traits > || (int(StrideType::InnerStrideAtCompileTime)==0 && int(Derived::InnerStrideAtCompileTime)==1), OuterStrideMatch = Derived::IsVectorAtCompileTime || int(StrideType::OuterStrideAtCompileTime)==int(Dynamic) || int(StrideType::OuterStrideAtCompileTime)==int(Derived::OuterStrideAtCompileTime), - AlignmentMatch = (_Options!=Aligned) || ((PlainObjectType::Flags&AlignedBit)==0) || ((traits::Flags&AlignedBit)==AlignedBit), + // NOTE, this indirection of evaluator::Alignment is needed + // to workaround a very strange bug in MSVC related to the instantiation + // of has_*ary_operator in evaluator. + // This line is surprisingly very sensitive. For instance, simply adding parenthesis + // as "DerivedAlignment = (int(evaluator::Alignment))," will make MSVC fail... + DerivedAlignment = int(evaluator::Alignment), + AlignmentMatch = (int(traits::Alignment)==int(Unaligned)) || (DerivedAlignment >= int(Alignment)), // FIXME the first condition is not very clear, it should be replaced by the required alignment ScalarTypeMatch = internal::is_same::value, MatchAtCompileTime = HasDirectAccess && StorageOrderMatch && InnerStrideMatch && OuterStrideMatch && AlignmentMatch && ScalarTypeMatch }; @@ -132,12 +66,12 @@ template class RefBase typedef MapBase Base; EIGEN_DENSE_PUBLIC_INTERFACE(RefBase) - inline Index innerStride() const + EIGEN_DEVICE_FUNC inline Index innerStride() const { return StrideType::InnerStrideAtCompileTime != 0 ? m_stride.inner() : 1; } - inline Index outerStride() const + EIGEN_DEVICE_FUNC inline Index outerStride() const { return StrideType::OuterStrideAtCompileTime != 0 ? m_stride.outer() : IsVectorAtCompileTime ? this->size() @@ -145,7 +79,7 @@ template class RefBase : this->rows(); } - RefBase() + EIGEN_DEVICE_FUNC RefBase() : Base(0,RowsAtCompileTime==Dynamic?0:RowsAtCompileTime,ColsAtCompileTime==Dynamic?0:ColsAtCompileTime), // Stride<> does not allow default ctor for Dynamic strides, so let' initialize it with dummy values: m_stride(StrideType::OuterStrideAtCompileTime==Dynamic?0:StrideType::OuterStrideAtCompileTime, @@ -159,7 +93,7 @@ template class RefBase typedef Stride StrideBase; template - void construct(Expression& expr) + EIGEN_DEVICE_FUNC void construct(Expression& expr) { if(PlainObjectType::RowsAtCompileTime==1) { @@ -184,15 +118,83 @@ template class RefBase StrideBase m_stride; }; - +/** \class Ref + * \ingroup Core_Module + * + * \brief A matrix or vector expression mapping an existing expression + * + * \tparam PlainObjectType the equivalent matrix type of the mapped data + * \tparam Options specifies the pointer alignment in bytes. It can be: \c #Aligned128, , \c #Aligned64, \c #Aligned32, \c #Aligned16, \c #Aligned8 or \c #Unaligned. + * The default is \c #Unaligned. + * \tparam StrideType optionally specifies strides. By default, Ref implies a contiguous storage along the inner dimension (inner stride==1), + * but accepts a variable outer stride (leading dimension). + * This can be overridden by specifying strides. + * The type passed here must be a specialization of the Stride template, see examples below. + * + * This class provides a way to write non-template functions taking Eigen objects as parameters while limiting the number of copies. + * A Ref<> object can represent either a const expression or a l-value: + * \code + * // in-out argument: + * void foo1(Ref x); + * + * // read-only const argument: + * void foo2(const Ref& x); + * \endcode + * + * In the in-out case, the input argument must satisfy the constraints of the actual Ref<> type, otherwise a compilation issue will be triggered. + * By default, a Ref can reference any dense vector expression of float having a contiguous memory layout. + * Likewise, a Ref can reference any column-major dense matrix expression of float whose column's elements are contiguously stored with + * the possibility to have a constant space in-between each column, i.e. the inner stride must be equal to 1, but the outer stride (or leading dimension) + * can be greater than the number of rows. + * + * In the const case, if the input expression does not match the above requirement, then it is evaluated into a temporary before being passed to the function. + * Here are some examples: + * \code + * MatrixXf A; + * VectorXf a; + * foo1(a.head()); // OK + * foo1(A.col()); // OK + * foo1(A.row()); // Compilation error because here innerstride!=1 + * foo2(A.row()); // Compilation error because A.row() is a 1xN object while foo2 is expecting a Nx1 object + * foo2(A.row().transpose()); // The row is copied into a contiguous temporary + * foo2(2*a); // The expression is evaluated into a temporary + * foo2(A.col().segment(2,4)); // No temporary + * \endcode + * + * The range of inputs that can be referenced without temporary can be enlarged using the last two template parameters. + * Here is an example accepting an innerstride!=1: + * \code + * // in-out argument: + * void foo3(Ref > x); + * foo3(A.row()); // OK + * \endcode + * The downside here is that the function foo3 might be significantly slower than foo1 because it won't be able to exploit vectorization, and will involve more + * expensive address computations even if the input is contiguously stored in memory. To overcome this issue, one might propose to overload internally calling a + * template function, e.g.: + * \code + * // in the .h: + * void foo(const Ref& A); + * void foo(const Ref >& A); + * + * // in the .cpp: + * template void foo_impl(const TypeOfA& A) { + * ... // crazy code goes here + * } + * void foo(const Ref& A) { foo_impl(A); } + * void foo(const Ref >& A) { foo_impl(A); } + * \endcode + * + * + * \sa PlainObjectBase::Map(), \ref TopicStorageOrders + */ template class Ref : public RefBase > { private: typedef internal::traits Traits; template - inline Ref(const PlainObjectBase& expr, - typename internal::enable_if::MatchAtCompileTime),Derived>::type* = 0); + EIGEN_DEVICE_FUNC inline Ref(const PlainObjectBase& expr, + typename internal::enable_if::MatchAtCompileTime),Derived>::type* = 0); public: typedef RefBase Base; @@ -201,23 +203,24 @@ template class Ref #ifndef EIGEN_PARSED_BY_DOXYGEN template - inline Ref(PlainObjectBase& expr, - typename internal::enable_if::MatchAtCompileTime),Derived>::type* = 0) + EIGEN_DEVICE_FUNC inline Ref(PlainObjectBase& expr, + typename internal::enable_if::MatchAtCompileTime),Derived>::type* = 0) { - EIGEN_STATIC_ASSERT(static_cast(Traits::template match::MatchAtCompileTime), STORAGE_LAYOUT_DOES_NOT_MATCH); + EIGEN_STATIC_ASSERT(bool(Traits::template match::MatchAtCompileTime), STORAGE_LAYOUT_DOES_NOT_MATCH); Base::construct(expr.derived()); } template - inline Ref(const DenseBase& expr, - typename internal::enable_if::MatchAtCompileTime),Derived>::type* = 0) + EIGEN_DEVICE_FUNC inline Ref(const DenseBase& expr, + typename internal::enable_if::MatchAtCompileTime),Derived>::type* = 0) #else + /** Implicit constructor from any dense expression */ template inline Ref(DenseBase& expr) #endif { - EIGEN_STATIC_ASSERT(static_cast(internal::is_lvalue::value), THIS_EXPRESSION_IS_NOT_A_LVALUE__IT_IS_READ_ONLY); - EIGEN_STATIC_ASSERT(static_cast(Traits::template match::MatchAtCompileTime), STORAGE_LAYOUT_DOES_NOT_MATCH); - enum { THIS_EXPRESSION_IS_NOT_A_LVALUE__IT_IS_READ_ONLY = Derived::ThisConstantIsPrivateInPlainObjectBase}; + EIGEN_STATIC_ASSERT(bool(internal::is_lvalue::value), THIS_EXPRESSION_IS_NOT_A_LVALUE__IT_IS_READ_ONLY); + EIGEN_STATIC_ASSERT(bool(Traits::template match::MatchAtCompileTime), STORAGE_LAYOUT_DOES_NOT_MATCH); + EIGEN_STATIC_ASSERT(!Derived::IsPlainObjectBase,THIS_EXPRESSION_IS_NOT_A_LVALUE__IT_IS_READ_ONLY); Base::construct(expr.const_cast_derived()); } @@ -236,36 +239,36 @@ template class Ref< EIGEN_DENSE_PUBLIC_INTERFACE(Ref) template - inline Ref(const DenseBase& expr, - typename internal::enable_if::ScalarTypeMatch),Derived>::type* = 0) + EIGEN_DEVICE_FUNC inline Ref(const DenseBase& expr, + typename internal::enable_if::ScalarTypeMatch),Derived>::type* = 0) { // std::cout << match_helper::HasDirectAccess << "," << match_helper::OuterStrideMatch << "," << match_helper::InnerStrideMatch << "\n"; // std::cout << int(StrideType::OuterStrideAtCompileTime) << " - " << int(Derived::OuterStrideAtCompileTime) << "\n"; // std::cout << int(StrideType::InnerStrideAtCompileTime) << " - " << int(Derived::InnerStrideAtCompileTime) << "\n"; construct(expr.derived(), typename Traits::template match::type()); } - - inline Ref(const Ref& other) : Base(other) { + + EIGEN_DEVICE_FUNC inline Ref(const Ref& other) : Base(other) { // copy constructor shall not copy the m_object, to avoid unnecessary malloc and copy } template - inline Ref(const RefBase& other) { + EIGEN_DEVICE_FUNC inline Ref(const RefBase& other) { construct(other.derived(), typename Traits::template match::type()); } protected: template - void construct(const Expression& expr,internal::true_type) + EIGEN_DEVICE_FUNC void construct(const Expression& expr,internal::true_type) { Base::construct(expr); } template - void construct(const Expression& expr, internal::false_type) + EIGEN_DEVICE_FUNC void construct(const Expression& expr, internal::false_type) { - m_object.lazyAssign(expr); + internal::call_assignment_no_alias(m_object,expr,internal::assign_op()); Base::construct(m_object); } diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Core/Replicate.h b/ground/gcs/src/libs/eigen/Eigen/src/Core/Replicate.h index ac4537c142..9960ef884e 100644 --- a/ground/gcs/src/libs/eigen/Eigen/src/Core/Replicate.h +++ b/ground/gcs/src/libs/eigen/Eigen/src/Core/Replicate.h @@ -12,21 +12,6 @@ namespace Eigen { -/** - * \class Replicate - * \ingroup Core_Module - * - * \brief Expression of the multiple replication of a matrix or vector - * - * \param MatrixType the type of the object we are replicating - * - * This class represents an expression of the multiple replication of a matrix or vector. - * It is the return type of DenseBase::replicate() and most of the time - * this is the only way it is used. - * - * \sa DenseBase::replicate() - */ - namespace internal { template struct traits > @@ -35,10 +20,7 @@ struct traits > typedef typename MatrixType::Scalar Scalar; typedef typename traits::StorageKind StorageKind; typedef typename traits::XprKind XprKind; - enum { - Factor = (RowFactor==Dynamic || ColFactor==Dynamic) ? Dynamic : RowFactor*ColFactor - }; - typedef typename nested::type MatrixTypeNested; + typedef typename ref_selector::type MatrixTypeNested; typedef typename remove_reference::type _MatrixTypeNested; enum { RowsAtCompileTime = RowFactor==Dynamic || int(MatrixType::RowsAtCompileTime)==Dynamic @@ -53,12 +35,29 @@ struct traits > IsRowMajor = MaxRowsAtCompileTime==1 && MaxColsAtCompileTime!=1 ? 1 : MaxColsAtCompileTime==1 && MaxRowsAtCompileTime!=1 ? 0 : (MatrixType::Flags & RowMajorBit) ? 1 : 0, - Flags = (_MatrixTypeNested::Flags & HereditaryBits & ~RowMajorBit) | (IsRowMajor ? RowMajorBit : 0), - CoeffReadCost = _MatrixTypeNested::CoeffReadCost + + // FIXME enable DirectAccess with negative strides? + Flags = IsRowMajor ? RowMajorBit : 0 }; }; } +/** + * \class Replicate + * \ingroup Core_Module + * + * \brief Expression of the multiple replication of a matrix or vector + * + * \tparam MatrixType the type of the object we are replicating + * \tparam RowFactor number of repetitions at compile time along the vertical direction, can be Dynamic. + * \tparam ColFactor number of repetitions at compile time along the horizontal direction, can be Dynamic. + * + * This class represents an expression of the multiple replication of a matrix or vector. + * It is the return type of DenseBase::replicate() and most of the time + * this is the only way it is used. + * + * \sa DenseBase::replicate() + */ template class Replicate : public internal::dense_xpr_base< Replicate >::type { @@ -68,10 +67,12 @@ template class Replicate typedef typename internal::dense_xpr_base::type Base; EIGEN_DENSE_PUBLIC_INTERFACE(Replicate) + typedef typename internal::remove_all::type NestedExpression; template - inline explicit Replicate(const OriginalMatrixType& a_matrix) - : m_matrix(a_matrix), m_rowFactor(RowFactor), m_colFactor(ColFactor) + EIGEN_DEVICE_FUNC + inline explicit Replicate(const OriginalMatrixType& matrix) + : m_matrix(matrix), m_rowFactor(RowFactor), m_colFactor(ColFactor) { EIGEN_STATIC_ASSERT((internal::is_same::type,OriginalMatrixType>::value), THE_MATRIX_OR_EXPRESSION_THAT_YOU_PASSED_DOES_NOT_HAVE_THE_EXPECTED_TYPE) @@ -79,41 +80,20 @@ template class Replicate } template - inline Replicate(const OriginalMatrixType& a_matrix, Index rowFactor, Index colFactor) - : m_matrix(a_matrix), m_rowFactor(rowFactor), m_colFactor(colFactor) + EIGEN_DEVICE_FUNC + inline Replicate(const OriginalMatrixType& matrix, Index rowFactor, Index colFactor) + : m_matrix(matrix), m_rowFactor(rowFactor), m_colFactor(colFactor) { EIGEN_STATIC_ASSERT((internal::is_same::type,OriginalMatrixType>::value), THE_MATRIX_OR_EXPRESSION_THAT_YOU_PASSED_DOES_NOT_HAVE_THE_EXPECTED_TYPE) } + EIGEN_DEVICE_FUNC inline Index rows() const { return m_matrix.rows() * m_rowFactor.value(); } + EIGEN_DEVICE_FUNC inline Index cols() const { return m_matrix.cols() * m_colFactor.value(); } - inline Scalar coeff(Index rowId, Index colId) const - { - // try to avoid using modulo; this is a pure optimization strategy - const Index actual_row = internal::traits::RowsAtCompileTime==1 ? 0 - : RowFactor==1 ? rowId - : rowId%m_matrix.rows(); - const Index actual_col = internal::traits::ColsAtCompileTime==1 ? 0 - : ColFactor==1 ? colId - : colId%m_matrix.cols(); - - return m_matrix.coeff(actual_row, actual_col); - } - template - inline PacketScalar packet(Index rowId, Index colId) const - { - const Index actual_row = internal::traits::RowsAtCompileTime==1 ? 0 - : RowFactor==1 ? rowId - : rowId%m_matrix.rows(); - const Index actual_col = internal::traits::ColsAtCompileTime==1 ? 0 - : ColFactor==1 ? colId - : colId%m_matrix.cols(); - - return m_matrix.template packet(actual_row, actual_col); - } - + EIGEN_DEVICE_FUNC const _MatrixTypeNested& nestedExpression() const { return m_matrix; @@ -141,21 +121,6 @@ DenseBase::replicate() const return Replicate(derived()); } -/** - * \return an expression of the replication of \c *this - * - * Example: \include MatrixBase_replicate_int_int.cpp - * Output: \verbinclude MatrixBase_replicate_int_int.out - * - * \sa VectorwiseOp::replicate(), DenseBase::replicate(), class Replicate - */ -template -const typename DenseBase::ReplicateReturnType -DenseBase::replicate(Index rowFactor,Index colFactor) const -{ - return Replicate(derived(),rowFactor,colFactor); -} - /** * \return an expression of the replication of each column (or row) of \c *this * diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Core/ReturnByValue.h b/ground/gcs/src/libs/eigen/Eigen/src/Core/ReturnByValue.h index f635598dcc..c44b7673bb 100644 --- a/ground/gcs/src/libs/eigen/Eigen/src/Core/ReturnByValue.h +++ b/ground/gcs/src/libs/eigen/Eigen/src/Core/ReturnByValue.h @@ -13,11 +13,6 @@ namespace Eigen { -/** \class ReturnByValue - * \ingroup Core_Module - * - */ - namespace internal { template @@ -38,17 +33,22 @@ struct traits > * So internal::nested always gives the plain return matrix type. * * FIXME: I don't understand why we need this specialization: isn't this taken care of by the EvalBeforeNestingBit ?? + * Answer: EvalBeforeNestingBit should be deprecated since we have the evaluators */ template -struct nested, n, PlainObject> +struct nested_eval, n, PlainObject> { typedef typename traits::ReturnType type; }; } // end namespace internal +/** \class ReturnByValue + * \ingroup Core_Module + * + */ template class ReturnByValue - : internal::no_assignment_operator, public internal::dense_xpr_base< ReturnByValue >::type + : public internal::dense_xpr_base< ReturnByValue >::type, internal::no_assignment_operator { public: typedef typename internal::traits::ReturnType ReturnType; @@ -57,10 +57,11 @@ template class ReturnByValue EIGEN_DENSE_PUBLIC_INTERFACE(ReturnByValue) template + EIGEN_DEVICE_FUNC inline void evalTo(Dest& dst) const { static_cast(this)->evalTo(dst); } - inline Index rows() const { return static_cast(this)->rows(); } - inline Index cols() const { return static_cast(this)->cols(); } + EIGEN_DEVICE_FUNC inline Index rows() const { return static_cast(this)->rows(); } + EIGEN_DEVICE_FUNC inline Index cols() const { return static_cast(this)->cols(); } #ifndef EIGEN_PARSED_BY_DOXYGEN #define Unusable YOU_ARE_TRYING_TO_ACCESS_A_SINGLE_COEFFICIENT_IN_A_SPECIAL_EXPRESSION_WHERE_THAT_IS_NOT_ALLOWED_BECAUSE_THAT_WOULD_BE_INEFFICIENT @@ -72,8 +73,7 @@ template class ReturnByValue const Unusable& coeff(Index,Index) const { return *reinterpret_cast(this); } Unusable& coeffRef(Index) { return *reinterpret_cast(this); } Unusable& coeffRef(Index,Index) { return *reinterpret_cast(this); } - template Unusable& packet(Index) const; - template Unusable& packet(Index, Index) const; +#undef Unusable #endif }; @@ -85,14 +85,32 @@ Derived& DenseBase::operator=(const ReturnByValue& other) return derived(); } +namespace internal { + +// Expression is evaluated in a temporary; default implementation of Assignment is bypassed so that +// when a ReturnByValue expression is assigned, the evaluator is not constructed. +// TODO: Finalize port to new regime; ReturnByValue should not exist in the expression world + template -template -Derived& DenseBase::lazyAssign(const ReturnByValue& other) +struct evaluator > + : public evaluator::ReturnType> { - other.evalTo(derived()); - return derived(); -} + typedef ReturnByValue XprType; + typedef typename internal::traits::ReturnType PlainObject; + typedef evaluator Base; + + EIGEN_DEVICE_FUNC explicit evaluator(const XprType& xpr) + : m_result(xpr.rows(), xpr.cols()) + { + ::new (static_cast(this)) Base(m_result); + xpr.evalTo(m_result); + } + +protected: + PlainObject m_result; +}; +} // end namespace internal } // end namespace Eigen diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Core/Reverse.h b/ground/gcs/src/libs/eigen/Eigen/src/Core/Reverse.h index e30ae3d281..0640cda2a1 100644 --- a/ground/gcs/src/libs/eigen/Eigen/src/Core/Reverse.h +++ b/ground/gcs/src/libs/eigen/Eigen/src/Core/Reverse.h @@ -14,20 +14,6 @@ namespace Eigen { -/** \class Reverse - * \ingroup Core_Module - * - * \brief Expression of the reverse of a vector or matrix - * - * \param MatrixType the type of the object of which we are taking the reverse - * - * This class represents an expression of the reverse of a vector. - * It is the return type of MatrixBase::reverse() and VectorwiseOp::reverse() - * and most of the time this is the only way it is used. - * - * \sa MatrixBase::reverse(), VectorwiseOp::reverse() - */ - namespace internal { template @@ -37,36 +23,43 @@ struct traits > typedef typename MatrixType::Scalar Scalar; typedef typename traits::StorageKind StorageKind; typedef typename traits::XprKind XprKind; - typedef typename nested::type MatrixTypeNested; + typedef typename ref_selector::type MatrixTypeNested; typedef typename remove_reference::type _MatrixTypeNested; enum { RowsAtCompileTime = MatrixType::RowsAtCompileTime, ColsAtCompileTime = MatrixType::ColsAtCompileTime, MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime, MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime, - - // let's enable LinearAccess only with vectorization because of the product overhead - LinearAccess = ( (Direction==BothDirections) && (int(_MatrixTypeNested::Flags)&PacketAccessBit) ) - ? LinearAccessBit : 0, - - Flags = int(_MatrixTypeNested::Flags) & (HereditaryBits | LvalueBit | PacketAccessBit | LinearAccess), - - CoeffReadCost = _MatrixTypeNested::CoeffReadCost + Flags = _MatrixTypeNested::Flags & (RowMajorBit | LvalueBit) }; }; -template struct reverse_packet_cond +template struct reverse_packet_cond { - static inline PacketScalar run(const PacketScalar& x) { return preverse(x); } + static inline PacketType run(const PacketType& x) { return preverse(x); } }; -template struct reverse_packet_cond +template struct reverse_packet_cond { - static inline PacketScalar run(const PacketScalar& x) { return x; } + static inline PacketType run(const PacketType& x) { return x; } }; } // end namespace internal +/** \class Reverse + * \ingroup Core_Module + * + * \brief Expression of the reverse of a vector or matrix + * + * \tparam MatrixType the type of the object of which we are taking the reverse + * \tparam Direction defines the direction of the reverse operation, can be Vertical, Horizontal, or BothDirections + * + * This class represents an expression of the reverse of a vector. + * It is the return type of MatrixBase::reverse() and VectorwiseOp::reverse() + * and most of the time this is the only way it is used. + * + * \sa MatrixBase::reverse(), VectorwiseOp::reverse() + */ template class Reverse : public internal::dense_xpr_base< Reverse >::type { @@ -74,12 +67,9 @@ template class Reverse typedef typename internal::dense_xpr_base::type Base; EIGEN_DENSE_PUBLIC_INTERFACE(Reverse) + typedef typename internal::remove_all::type NestedExpression; using Base::IsRowMajor; - // next line is necessary because otherwise const version of operator() - // is hidden by non-const version defined in this file - using Base::operator(); - protected: enum { PacketSize = internal::packet_traits::size, @@ -95,82 +85,19 @@ template class Reverse typedef internal::reverse_packet_cond reverse_packet; public: - inline Reverse(const MatrixType& matrix) : m_matrix(matrix) { } + EIGEN_DEVICE_FUNC explicit inline Reverse(const MatrixType& matrix) : m_matrix(matrix) { } EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Reverse) - inline Index rows() const { return m_matrix.rows(); } - inline Index cols() const { return m_matrix.cols(); } + EIGEN_DEVICE_FUNC inline Index rows() const { return m_matrix.rows(); } + EIGEN_DEVICE_FUNC inline Index cols() const { return m_matrix.cols(); } - inline Index innerStride() const + EIGEN_DEVICE_FUNC inline Index innerStride() const { return -m_matrix.innerStride(); } - inline Scalar& operator()(Index row, Index col) - { - eigen_assert(row >= 0 && row < rows() && col >= 0 && col < cols()); - return coeffRef(row, col); - } - - inline Scalar& coeffRef(Index row, Index col) - { - return m_matrix.const_cast_derived().coeffRef(ReverseRow ? m_matrix.rows() - row - 1 : row, - ReverseCol ? m_matrix.cols() - col - 1 : col); - } - - inline CoeffReturnType coeff(Index row, Index col) const - { - return m_matrix.coeff(ReverseRow ? m_matrix.rows() - row - 1 : row, - ReverseCol ? m_matrix.cols() - col - 1 : col); - } - - inline CoeffReturnType coeff(Index index) const - { - return m_matrix.coeff(m_matrix.size() - index - 1); - } - - inline Scalar& coeffRef(Index index) - { - return m_matrix.const_cast_derived().coeffRef(m_matrix.size() - index - 1); - } - - inline Scalar& operator()(Index index) - { - eigen_assert(index >= 0 && index < m_matrix.size()); - return coeffRef(index); - } - - template - inline const PacketScalar packet(Index row, Index col) const - { - return reverse_packet::run(m_matrix.template packet( - ReverseRow ? m_matrix.rows() - row - OffsetRow : row, - ReverseCol ? m_matrix.cols() - col - OffsetCol : col)); - } - - template - inline void writePacket(Index row, Index col, const PacketScalar& x) - { - m_matrix.const_cast_derived().template writePacket( - ReverseRow ? m_matrix.rows() - row - OffsetRow : row, - ReverseCol ? m_matrix.cols() - col - OffsetCol : col, - reverse_packet::run(x)); - } - - template - inline const PacketScalar packet(Index index) const - { - return internal::preverse(m_matrix.template packet( m_matrix.size() - index - PacketSize )); - } - - template - inline void writePacket(Index index, const PacketScalar& x) - { - m_matrix.const_cast_derived().template writePacket(m_matrix.size() - index - PacketSize, internal::preverse(x)); - } - - const typename internal::remove_all::type& + EIGEN_DEVICE_FUNC const typename internal::remove_all::type& nestedExpression() const { return m_matrix; @@ -190,33 +117,93 @@ template inline typename DenseBase::ReverseReturnType DenseBase::reverse() { - return derived(); + return ReverseReturnType(derived()); } -/** This is the const version of reverse(). */ -template -inline const typename DenseBase::ConstReverseReturnType -DenseBase::reverse() const -{ - return derived(); -} + +//reverse const overload moved DenseBase.h due to a CUDA compiler bug /** This is the "in place" version of reverse: it reverses \c *this. * * In most cases it is probably better to simply use the reversed expression * of a matrix. However, when reversing the matrix data itself is really needed, * then this "in-place" version is probably the right choice because it provides - * the following additional features: + * the following additional benefits: * - less error prone: doing the same operation with .reverse() requires special care: * \code m = m.reverse().eval(); \endcode - * - this API allows to avoid creating a temporary (the current implementation creates a temporary, but that could be avoided using swap) + * - this API enables reverse operations without the need for a temporary * - it allows future optimizations (cache friendliness, etc.) * - * \sa reverse() */ + * \sa VectorwiseOp::reverseInPlace(), reverse() */ template inline void DenseBase::reverseInPlace() { - derived() = derived().reverse().eval(); + if(cols()>rows()) + { + Index half = cols()/2; + leftCols(half).swap(rightCols(half).reverse()); + if((cols()%2)==1) + { + Index half2 = rows()/2; + col(half).head(half2).swap(col(half).tail(half2).reverse()); + } + } + else + { + Index half = rows()/2; + topRows(half).swap(bottomRows(half).reverse()); + if((rows()%2)==1) + { + Index half2 = cols()/2; + row(half).head(half2).swap(row(half).tail(half2).reverse()); + } + } +} + +namespace internal { + +template +struct vectorwise_reverse_inplace_impl; + +template<> +struct vectorwise_reverse_inplace_impl +{ + template + static void run(ExpressionType &xpr) + { + Index half = xpr.rows()/2; + xpr.topRows(half).swap(xpr.bottomRows(half).colwise().reverse()); + } +}; + +template<> +struct vectorwise_reverse_inplace_impl +{ + template + static void run(ExpressionType &xpr) + { + Index half = xpr.cols()/2; + xpr.leftCols(half).swap(xpr.rightCols(half).rowwise().reverse()); + } +}; + +} // end namespace internal + +/** This is the "in place" version of VectorwiseOp::reverse: it reverses each column or row of \c *this. + * + * In most cases it is probably better to simply use the reversed expression + * of a matrix. However, when reversing the matrix data itself is really needed, + * then this "in-place" version is probably the right choice because it provides + * the following additional benefits: + * - less error prone: doing the same operation with .reverse() requires special care: + * \code m = m.reverse().eval(); \endcode + * - this API enables reverse operations without the need for a temporary + * + * \sa DenseBase::reverseInPlace(), reverse() */ +template +void VectorwiseOp::reverseInPlace() +{ + internal::vectorwise_reverse_inplace_impl::run(_expression().const_cast_derived()); } } // end namespace Eigen diff --git a/ground/gcs/src/libs/eigen/Eigen/src/Core/Select.h b/ground/gcs/src/libs/eigen/Eigen/src/Core/Select.h index 87993bbb55..79eec1b5b0 100644 --- a/ground/gcs/src/libs/eigen/Eigen/src/Core/Select.h +++ b/ground/gcs/src/libs/eigen/Eigen/src/Core/Select.h @@ -43,23 +43,21 @@ struct traits > ColsAtCompileTime = ConditionMatrixType::ColsAtCompileTime, MaxRowsAtCompileTime = ConditionMatrixType::MaxRowsAtCompileTime, MaxColsAtCompileTime = ConditionMatrixType::MaxColsAtCompileTime, - Flags = (unsigned int)ThenMatrixType::Flags & ElseMatrixType::Flags & HereditaryBits, - CoeffReadCost = traits::type>::CoeffReadCost - + EIGEN_SIZE_MAX(traits::type>::CoeffReadCost, - traits::type>::CoeffReadCost) + Flags = (unsigned int)ThenMatrixType::Flags & ElseMatrixType::Flags & RowMajorBit }; }; } template -class Select : internal::no_assignment_operator, - public internal::dense_xpr_base< Select >::type +class Select : public internal::dense_xpr_base< Select >::type, + internal::no_assignment_operator { public: typedef typename internal::dense_xpr_base" << endl; + cerr << "available actions:" << endl; + for (auto it = available_actions.begin(); it != available_actions.end(); ++it) { + cerr << " " << (*it)->invokation_name() << endl; + } + cerr << "the input files should each contain an output of benchmark-blocking-sizes" << endl; + exit(1); +} + +int main(int argc, char* argv[]) +{ + cout.precision(default_precision); + cerr.precision(default_precision); + + vector> available_actions; + available_actions.emplace_back(new partition_action_t); + available_actions.emplace_back(new evaluate_defaults_action_t); + + vector input_filenames; + + action_t* action = nullptr; + + if (argc < 2) { + show_usage_and_exit(argc, argv, available_actions); + } + for (int i = 1; i < argc; i++) { + bool arg_handled = false; + // Step 1. Try to match action invokation names. + for (auto it = available_actions.begin(); it != available_actions.end(); ++it) { + if (!strcmp(argv[i], (*it)->invokation_name())) { + if (!action) { + action = it->get(); + arg_handled = true; + break; + } else { + cerr << "can't specify more than one action!" << endl; + show_usage_and_exit(argc, argv, available_actions); + } + } + } + if (arg_handled) { + continue; + } + // Step 2. Try to match option names. + if (argv[i][0] == '-') { + if (!strcmp(argv[i], "--only-cubic-sizes")) { + only_cubic_sizes = true; + arg_handled = true; + } + if (!strcmp(argv[i], "--dump-tables")) { + dump_tables = true; + arg_handled = true; + } + if (!arg_handled) { + cerr << "Unrecognized option: " << argv[i] << endl; + show_usage_and_exit(argc, argv, available_actions); + } + } + if (arg_handled) { + continue; + } + // Step 3. Default to interpreting args as input filenames. + input_filenames.emplace_back(argv[i]); + } + + if (dump_tables && only_cubic_sizes) { + cerr << "Incompatible options: --only-cubic-sizes and --dump-tables." << endl; + show_usage_and_exit(argc, argv, available_actions); + } + + if (!action) { + show_usage_and_exit(argc, argv, available_actions); + } + + action->run(input_filenames); +} diff --git a/ground/gcs/src/libs/eigen/bench/benchCholesky.cpp b/ground/gcs/src/libs/eigen/bench/benchCholesky.cpp index 42b3e1285f..9a8e7cf638 100644 --- a/ground/gcs/src/libs/eigen/bench/benchCholesky.cpp +++ b/ground/gcs/src/libs/eigen/bench/benchCholesky.cpp @@ -31,7 +31,7 @@ __attribute__ ((noinline)) void benchLLT(const MatrixType& m) int rows = m.rows(); int cols = m.cols(); - int cost = 0; + double cost = 0; for (int j=0; j0; ++i) + for (int i=0; dynsizes[i]>0; ++i) benchLLT(Matrix(dynsizes[i],dynsizes[i])); benchLLT(Matrix()); diff --git a/ground/gcs/src/libs/eigen/bench/bench_gemm.cpp b/ground/gcs/src/libs/eigen/bench/bench_gemm.cpp index 41ca8b3b6e..8528c55874 100644 --- a/ground/gcs/src/libs/eigen/bench/bench_gemm.cpp +++ b/ground/gcs/src/libs/eigen/bench/bench_gemm.cpp @@ -2,6 +2,14 @@ // g++-4.4 bench_gemm.cpp -I .. -O2 -DNDEBUG -lrt -fopenmp && OMP_NUM_THREADS=2 ./a.out // icpc bench_gemm.cpp -I .. -O3 -DNDEBUG -lrt -openmp && OMP_NUM_THREADS=2 ./a.out +// Compilation options: +// +// -DSCALAR=std::complex +// -DSCALARA=double or -DSCALARB=double +// -DHAVE_BLAS +// -DDECOUPLED +// + #include #include #include @@ -14,10 +22,18 @@ using namespace Eigen; #define SCALAR float #endif +#ifndef SCALARA +#define SCALARA SCALAR +#endif + +#ifndef SCALARB +#define SCALARB SCALAR +#endif + typedef SCALAR Scalar; typedef NumTraits::Real RealScalar; -typedef Matrix A; -typedef Matrix B; +typedef Matrix A; +typedef Matrix B; typedef Matrix C; typedef Matrix M; @@ -129,35 +145,69 @@ int main(int argc, char ** argv) int tries = 2; // number of tries, we keep the best int s = 2048; - int cache_size = -1; + int m = s; + int n = s; + int p = s; + int cache_size1=-1, cache_size2=l2, cache_size3 = 0; bool need_help = false; - for (int i=1; i c t p\n"; + std::cout << argv[0] << " -s -c -t -p \n"; + std::cout << " : size\n"; + std::cout << " : rows columns depth\n"; return 1; } - if(cache_size>0) - setCpuCacheSizes(cache_size,96*cache_size); - - int m = s; - int n = s; - int p = s; +#if EIGEN_VERSION_AT_LEAST(3,2,90) + if(cache_size1>0) + setCpuCacheSizes(cache_size1,cache_size2,cache_size3); +#endif + A a(m,p); a.setRandom(); B b(p,n); b.setRandom(); C c(m,n); c.setOnes(); @@ -172,6 +222,7 @@ int main(int argc, char ** argv) // check the parallel product is correct #if defined EIGEN_HAS_OPENMP + Eigen::initParallel(); int procs = omp_get_max_threads(); if(procs>1) { @@ -188,11 +239,20 @@ int main(int argc, char ** argv) #elif defined HAVE_BLAS blas_gemm(a,b,r); c.noalias() += a * b; - if(!r.isApprox(c)) std::cerr << "Warning, your product is crap!\n\n"; + if(!r.isApprox(c)) { + std::cout << r - c << "\n"; + std::cerr << "Warning, your product is crap!\n\n"; + } #else - gemm(a,b,c); - r.noalias() += a.cast() * b.cast(); - if(!r.isApprox(c)) std::cerr << "Warning, your product is crap!\n\n"; + if(1.*m*n*p<2000.*2000*2000) + { + gemm(a,b,c); + r.noalias() += a.cast() .lazyProduct( b.cast() ); + if(!r.isApprox(c)) { + std::cout << r - c << "\n"; + std::cerr << "Warning, your product is crap!\n\n"; + } + } #endif #ifdef HAVE_BLAS @@ -214,7 +274,7 @@ int main(int argc, char ** argv) { BenchTimer tmono; omp_set_num_threads(1); - Eigen::internal::setNbThreads(1); + Eigen::setNbThreads(1); c = rc; BENCH(tmono, tries, rep, gemm(a,b,c)); std::cout << "eigen mono cpu " << tmono.best(CPU_TIMER)/rep << "s \t" << (double(m)*n*p*rep*2/tmono.best(CPU_TIMER))*1e-9 << " GFLOPS \t(" << tmono.total(CPU_TIMER) << "s)\n"; @@ -223,6 +283,15 @@ int main(int argc, char ** argv) } #endif + if(1.*m*n*p<30*30*30) + { + BenchTimer tmt; + c = rc; + BENCH(tmt, tries, rep, c.noalias()+=a.lazyProduct(b)); + std::cout << "lazy cpu " << tmt.best(CPU_TIMER)/rep << "s \t" << (double(m)*n*p*rep*2/tmt.best(CPU_TIMER))*1e-9 << " GFLOPS \t(" << tmt.total(CPU_TIMER) << "s)\n"; + std::cout << "lazy real " << tmt.best(REAL_TIMER)/rep << "s \t" << (double(m)*n*p*rep*2/tmt.best(REAL_TIMER))*1e-9 << " GFLOPS \t(" << tmt.total(REAL_TIMER) << "s)\n"; + } + #ifdef DECOUPLED if((NumTraits::IsComplex) && (NumTraits::IsComplex)) { diff --git a/ground/gcs/src/libs/eigen/bench/bench_norm.cpp b/ground/gcs/src/libs/eigen/bench/bench_norm.cpp index 806db292c5..129afcfb25 100644 --- a/ground/gcs/src/libs/eigen/bench/bench_norm.cpp +++ b/ground/gcs/src/libs/eigen/bench/bench_norm.cpp @@ -6,19 +6,25 @@ using namespace Eigen; using namespace std; template -EIGEN_DONT_INLINE typename T::Scalar sqsumNorm(const T& v) +EIGEN_DONT_INLINE typename T::Scalar sqsumNorm(T& v) { return v.norm(); } template -EIGEN_DONT_INLINE typename T::Scalar hypotNorm(const T& v) +EIGEN_DONT_INLINE typename T::Scalar stableNorm(T& v) +{ + return v.stableNorm(); +} + +template +EIGEN_DONT_INLINE typename T::Scalar hypotNorm(T& v) { return v.hypotNorm(); } template -EIGEN_DONT_INLINE typename T::Scalar blueNorm(const T& v) +EIGEN_DONT_INLINE typename T::Scalar blueNorm(T& v) { return v.blueNorm(); } @@ -32,25 +38,25 @@ EIGEN_DONT_INLINE typename T::Scalar lapackNorm(T& v) Scalar ssq = 1; for (int i=0;i= ax) { - ssq += internal::abs2(ax/scale); + ssq += numext::abs2(ax/scale); } else { - ssq = Scalar(1) + ssq * internal::abs2(scale/ax); + ssq = Scalar(1) + ssq * numext::abs2(scale/ax); scale = ax; } } - return scale * internal::sqrt(ssq); + return scale * std::sqrt(ssq); } template EIGEN_DONT_INLINE typename T::Scalar twopassNorm(T& v) { typedef typename T::Scalar Scalar; - Scalar s = v.cwise().abs().maxCoeff(); + Scalar s = v.array().abs().maxCoeff(); return s*(v/s).norm(); } @@ -73,16 +79,20 @@ EIGEN_DONT_INLINE typename T::Scalar divacNorm(T& v) v(i) = v(2*i) + v(2*i+1); n = n/2; } - return internal::sqrt(v(0)); + return std::sqrt(v(0)); } +namespace Eigen { +namespace internal { #ifdef EIGEN_VECTORIZE -Packet4f internal::plt(const Packet4f& a, Packet4f& b) { return _mm_cmplt_ps(a,b); } -Packet2d internal::plt(const Packet2d& a, Packet2d& b) { return _mm_cmplt_pd(a,b); } +Packet4f plt(const Packet4f& a, Packet4f& b) { return _mm_cmplt_ps(a,b); } +Packet2d plt(const Packet2d& a, Packet2d& b) { return _mm_cmplt_pd(a,b); } -Packet4f internal::pandnot(const Packet4f& a, Packet4f& b) { return _mm_andnot_ps(a,b); } -Packet2d internal::pandnot(const Packet2d& a, Packet2d& b) { return _mm_andnot_pd(a,b); } +Packet4f pandnot(const Packet4f& a, Packet4f& b) { return _mm_andnot_ps(a,b); } +Packet2d pandnot(const Packet2d& a, Packet2d& b) { return _mm_andnot_pd(a,b); } #endif +} +} template EIGEN_DONT_INLINE typename T::Scalar pblueNorm(const T& v) @@ -126,7 +136,7 @@ EIGEN_DONT_INLINE typename T::Scalar pblueNorm(const T& v) overfl = rbig*s2m; // overfow boundary for abig eps = std::pow(ibeta, 1-it); - relerr = internal::sqrt(eps); // tolerance for neglecting asml + relerr = std::sqrt(eps); // tolerance for neglecting asml abig = 1.0/eps - 1.0; if (Scalar(nbig)>abig) nmax = abig; // largest safe n else nmax = nbig; @@ -134,13 +144,13 @@ EIGEN_DONT_INLINE typename T::Scalar pblueNorm(const T& v) typedef typename internal::packet_traits::type Packet; const int ps = internal::packet_traits::size; - Packet pasml = internal::pset1(Scalar(0)); - Packet pamed = internal::pset1(Scalar(0)); - Packet pabig = internal::pset1(Scalar(0)); - Packet ps2m = internal::pset1(s2m); - Packet ps1m = internal::pset1(s1m); - Packet pb2 = internal::pset1(b2); - Packet pb1 = internal::pset1(b1); + Packet pasml = internal::pset1(Scalar(0)); + Packet pamed = internal::pset1(Scalar(0)); + Packet pabig = internal::pset1(Scalar(0)); + Packet ps2m = internal::pset1(s2m); + Packet ps1m = internal::pset1(s1m); + Packet pb2 = internal::pset1(b2); + Packet pb1 = internal::pset1(b1); for(int j=0; j(j)); @@ -170,7 +180,7 @@ EIGEN_DONT_INLINE typename T::Scalar pblueNorm(const T& v) Scalar amed = internal::predux(pamed); if(abig > Scalar(0)) { - abig = internal::sqrt(abig); + abig = std::sqrt(abig); if(abig > overfl) { eigen_assert(false && "overflow"); @@ -179,7 +189,7 @@ EIGEN_DONT_INLINE typename T::Scalar pblueNorm(const T& v) if(amed > Scalar(0)) { abig = abig/s2m; - amed = internal::sqrt(amed); + amed = std::sqrt(amed); } else { @@ -191,55 +201,56 @@ EIGEN_DONT_INLINE typename T::Scalar pblueNorm(const T& v) { if (amed > Scalar(0)) { - abig = internal::sqrt(amed); - amed = internal::sqrt(asml) / s1m; + abig = std::sqrt(amed); + amed = std::sqrt(asml) / s1m; } else { - return internal::sqrt(asml)/s1m; + return std::sqrt(asml)/s1m; } } else { - return internal::sqrt(amed); + return std::sqrt(amed); } asml = std::min(abig, amed); abig = std::max(abig, amed); if(asml <= abig*relerr) return abig; else - return abig * internal::sqrt(Scalar(1) + internal::abs2(asml/abig)); + return abig * std::sqrt(Scalar(1) + numext::abs2(asml/abig)); #endif } #define BENCH_PERF(NRM) { \ + float af = 0; double ad = 0; std::complex ac = 0; \ Eigen::BenchTimer tf, td, tcf; tf.reset(); td.reset(); tcf.reset();\ for (int k=0; k()); - double yd = based * internal::abs(internal::random()); + double yf = basef * std::abs(internal::random()); + double yd = based * std::abs(internal::random()); VectorXf vf = VectorXf::Ones(s) * yf; VectorXd vd = VectorXd::Ones(s) * yd; - std::cout << "reference\t" << internal::sqrt(double(s))*yf << "\t" << internal::sqrt(double(s))*yd << "\n"; + std::cout << "reference\t" << std::sqrt(double(s))*yf << "\t" << std::sqrt(double(s))*yd << "\n"; std::cout << "sqsumNorm\t" << sqsumNorm(vf) << "\t" << sqsumNorm(vd) << "\n"; std::cout << "hypotNorm\t" << hypotNorm(vf) << "\t" << hypotNorm(vd) << "\n"; std::cout << "blueNorm\t" << blueNorm(vf) << "\t" << blueNorm(vd) << "\n"; @@ -255,8 +266,8 @@ void check_accuracy_var(int ef0, int ef1, int ed0, int ed1, int s) VectorXd vd(s); for (int i=0; i()) * std::pow(double(10), internal::random(ef0,ef1)); - vd[i] = internal::abs(internal::random()) * std::pow(double(10), internal::random(ed0,ed1)); + vf[i] = std::abs(internal::random()) * std::pow(double(10), internal::random(ef0,ef1)); + vd[i] = std::abs(internal::random()) * std::pow(double(10), internal::random(ed0,ed1)); } //std::cout << "reference\t" << internal::sqrt(double(s))*yf << "\t" << internal::sqrt(double(s))*yd << "\n"; @@ -312,34 +323,38 @@ int main(int argc, char** argv) std::cout << "\n"; } + y = 1; std::cout.precision(4); - std::cerr << "Performance (out of cache):\n"; + int s1 = 1024*1024*32; + std::cerr << "Performance (out of cache, " << s1 << "):\n"; { int iters = 1; - VectorXf vf = VectorXf::Random(1024*1024*32) * y; - VectorXd vd = VectorXd::Random(1024*1024*32) * y; - VectorXcf vcf = VectorXcf::Random(1024*1024*32) * y; + VectorXf vf = VectorXf::Random(s1) * y; + VectorXd vd = VectorXd::Random(s1) * y; + VectorXcf vcf = VectorXcf::Random(s1) * y; BENCH_PERF(sqsumNorm); + BENCH_PERF(stableNorm); BENCH_PERF(blueNorm); -// BENCH_PERF(pblueNorm); -// BENCH_PERF(lapackNorm); -// BENCH_PERF(hypotNorm); -// BENCH_PERF(twopassNorm); + BENCH_PERF(pblueNorm); + BENCH_PERF(lapackNorm); + BENCH_PERF(hypotNorm); + BENCH_PERF(twopassNorm); BENCH_PERF(bl2passNorm); } - std::cerr << "\nPerformance (in cache):\n"; + std::cerr << "\nPerformance (in cache, " << 512 << "):\n"; { int iters = 100000; VectorXf vf = VectorXf::Random(512) * y; VectorXd vd = VectorXd::Random(512) * y; VectorXcf vcf = VectorXcf::Random(512) * y; BENCH_PERF(sqsumNorm); + BENCH_PERF(stableNorm); BENCH_PERF(blueNorm); -// BENCH_PERF(pblueNorm); -// BENCH_PERF(lapackNorm); -// BENCH_PERF(hypotNorm); -// BENCH_PERF(twopassNorm); + BENCH_PERF(pblueNorm); + BENCH_PERF(lapackNorm); + BENCH_PERF(hypotNorm); + BENCH_PERF(twopassNorm); BENCH_PERF(bl2passNorm); } } diff --git a/ground/gcs/src/libs/eigen/bench/benchmark-blocking-sizes.cpp b/ground/gcs/src/libs/eigen/bench/benchmark-blocking-sizes.cpp new file mode 100644 index 0000000000..827be28802 --- /dev/null +++ b/ground/gcs/src/libs/eigen/bench/benchmark-blocking-sizes.cpp @@ -0,0 +1,677 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2015 Benoit Jacob +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include +#include +#include +#include +#include +#include +#include + +bool eigen_use_specific_block_size; +int eigen_block_size_k, eigen_block_size_m, eigen_block_size_n; +#define EIGEN_TEST_SPECIFIC_BLOCKING_SIZES eigen_use_specific_block_size +#define EIGEN_TEST_SPECIFIC_BLOCKING_SIZE_K eigen_block_size_k +#define EIGEN_TEST_SPECIFIC_BLOCKING_SIZE_M eigen_block_size_m +#define EIGEN_TEST_SPECIFIC_BLOCKING_SIZE_N eigen_block_size_n +#include + +#include + +using namespace Eigen; +using namespace std; + +static BenchTimer timer; + +// how many times we repeat each measurement. +// measurements are randomly shuffled - we're not doing +// all N identical measurements in a row. +const int measurement_repetitions = 3; + +// Timings below this value are too short to be accurate, +// we'll repeat measurements with more iterations until +// we get a timing above that threshold. +const float min_accurate_time = 1e-2f; + +// See --min-working-set-size command line parameter. +size_t min_working_set_size = 0; + +float max_clock_speed = 0.0f; + +// range of sizes that we will benchmark (in all 3 K,M,N dimensions) +const size_t maxsize = 2048; +const size_t minsize = 16; + +typedef MatrixXf MatrixType; +typedef MatrixType::Scalar Scalar; +typedef internal::packet_traits::type Packet; + +static_assert((maxsize & (maxsize - 1)) == 0, "maxsize must be a power of two"); +static_assert((minsize & (minsize - 1)) == 0, "minsize must be a power of two"); +static_assert(maxsize > minsize, "maxsize must be larger than minsize"); +static_assert(maxsize < (minsize << 16), "maxsize must be less than (minsize<<16)"); + +// just a helper to store a triple of K,M,N sizes for matrix product +struct size_triple_t +{ + size_t k, m, n; + size_triple_t() : k(0), m(0), n(0) {} + size_triple_t(size_t _k, size_t _m, size_t _n) : k(_k), m(_m), n(_n) {} + size_triple_t(const size_triple_t& o) : k(o.k), m(o.m), n(o.n) {} + size_triple_t(uint16_t compact) + { + k = 1 << ((compact & 0xf00) >> 8); + m = 1 << ((compact & 0x0f0) >> 4); + n = 1 << ((compact & 0x00f) >> 0); + } +}; + +uint8_t log2_pot(size_t x) { + size_t l = 0; + while (x >>= 1) l++; + return l; +} + +// Convert between size tripes and a compact form fitting in 12 bits +// where each size, which must be a POT, is encoded as its log2, on 4 bits +// so the largest representable size is 2^15 == 32k ... big enough. +uint16_t compact_size_triple(size_t k, size_t m, size_t n) +{ + return (log2_pot(k) << 8) | (log2_pot(m) << 4) | log2_pot(n); +} + +uint16_t compact_size_triple(const size_triple_t& t) +{ + return compact_size_triple(t.k, t.m, t.n); +} + +// A single benchmark. Initially only contains benchmark params. +// Then call run(), which stores the result in the gflops field. +struct benchmark_t +{ + uint16_t compact_product_size; + uint16_t compact_block_size; + bool use_default_block_size; + float gflops; + benchmark_t() + : compact_product_size(0) + , compact_block_size(0) + , use_default_block_size(false) + , gflops(0) + { + } + benchmark_t(size_t pk, size_t pm, size_t pn, + size_t bk, size_t bm, size_t bn) + : compact_product_size(compact_size_triple(pk, pm, pn)) + , compact_block_size(compact_size_triple(bk, bm, bn)) + , use_default_block_size(false) + , gflops(0) + {} + benchmark_t(size_t pk, size_t pm, size_t pn) + : compact_product_size(compact_size_triple(pk, pm, pn)) + , compact_block_size(0) + , use_default_block_size(true) + , gflops(0) + {} + + void run(); +}; + +ostream& operator<<(ostream& s, const benchmark_t& b) +{ + s << hex << b.compact_product_size << dec; + if (b.use_default_block_size) { + size_triple_t t(b.compact_product_size); + Index k = t.k, m = t.m, n = t.n; + internal::computeProductBlockingSizes(k, m, n); + s << " default(" << k << ", " << m << ", " << n << ")"; + } else { + s << " " << hex << b.compact_block_size << dec; + } + s << " " << b.gflops; + return s; +} + +// We sort first by increasing benchmark parameters, +// then by decreasing performance. +bool operator<(const benchmark_t& b1, const benchmark_t& b2) +{ + return b1.compact_product_size < b2.compact_product_size || + (b1.compact_product_size == b2.compact_product_size && ( + (b1.compact_block_size < b2.compact_block_size || ( + b1.compact_block_size == b2.compact_block_size && + b1.gflops > b2.gflops)))); +} + +void benchmark_t::run() +{ + size_triple_t productsizes(compact_product_size); + + if (use_default_block_size) { + eigen_use_specific_block_size = false; + } else { + // feed eigen with our custom blocking params + eigen_use_specific_block_size = true; + size_triple_t blocksizes(compact_block_size); + eigen_block_size_k = blocksizes.k; + eigen_block_size_m = blocksizes.m; + eigen_block_size_n = blocksizes.n; + } + + // set up the matrix pool + + const size_t combined_three_matrices_sizes = + sizeof(Scalar) * + (productsizes.k * productsizes.m + + productsizes.k * productsizes.n + + productsizes.m * productsizes.n); + + // 64 M is large enough that nobody has a cache bigger than that, + // while still being small enough that everybody has this much RAM, + // so conveniently we don't need to special-case platforms here. + const size_t unlikely_large_cache_size = 64 << 20; + + const size_t working_set_size = + min_working_set_size ? min_working_set_size : unlikely_large_cache_size; + + const size_t matrix_pool_size = + 1 + working_set_size / combined_three_matrices_sizes; + + MatrixType *lhs = new MatrixType[matrix_pool_size]; + MatrixType *rhs = new MatrixType[matrix_pool_size]; + MatrixType *dst = new MatrixType[matrix_pool_size]; + + for (size_t i = 0; i < matrix_pool_size; i++) { + lhs[i] = MatrixType::Zero(productsizes.m, productsizes.k); + rhs[i] = MatrixType::Zero(productsizes.k, productsizes.n); + dst[i] = MatrixType::Zero(productsizes.m, productsizes.n); + } + + // main benchmark loop + + int iters_at_a_time = 1; + float time_per_iter = 0.0f; + size_t matrix_index = 0; + while (true) { + + double starttime = timer.getCpuTime(); + for (int i = 0; i < iters_at_a_time; i++) { + dst[matrix_index].noalias() = lhs[matrix_index] * rhs[matrix_index]; + matrix_index++; + if (matrix_index == matrix_pool_size) { + matrix_index = 0; + } + } + double endtime = timer.getCpuTime(); + + const float timing = float(endtime - starttime); + + if (timing >= min_accurate_time) { + time_per_iter = timing / iters_at_a_time; + break; + } + + iters_at_a_time *= 2; + } + + delete[] lhs; + delete[] rhs; + delete[] dst; + + gflops = 2e-9 * productsizes.k * productsizes.m * productsizes.n / time_per_iter; +} + +void print_cpuinfo() +{ +#ifdef __linux__ + cout << "contents of /proc/cpuinfo:" << endl; + string line; + ifstream cpuinfo("/proc/cpuinfo"); + if (cpuinfo.is_open()) { + while (getline(cpuinfo, line)) { + cout << line << endl; + } + cpuinfo.close(); + } + cout << endl; +#elif defined __APPLE__ + cout << "output of sysctl hw:" << endl; + system("sysctl hw"); + cout << endl; +#endif +} + +template +string type_name() +{ + return "unknown"; +} + +template<> +string type_name() +{ + return "float"; +} + +template<> +string type_name() +{ + return "double"; +} + +struct action_t +{ + virtual const char* invokation_name() const { abort(); return nullptr; } + virtual void run() const { abort(); } + virtual ~action_t() {} +}; + +void show_usage_and_exit(int /*argc*/, char* argv[], + const vector>& available_actions) +{ + cerr << "usage: " << argv[0] << " [options...]" << endl << endl; + cerr << "available actions:" << endl << endl; + for (auto it = available_actions.begin(); it != available_actions.end(); ++it) { + cerr << " " << (*it)->invokation_name() << endl; + } + cerr << endl; + cerr << "options:" << endl << endl; + cerr << " --min-working-set-size=N:" << endl; + cerr << " Set the minimum working set size to N bytes." << endl; + cerr << " This is rounded up as needed to a multiple of matrix size." << endl; + cerr << " A larger working set lowers the chance of a warm cache." << endl; + cerr << " The default value 0 means use a large enough working" << endl; + cerr << " set to likely outsize caches." << endl; + cerr << " A value of 1 (that is, 1 byte) would mean don't do anything to" << endl; + cerr << " avoid warm caches." << endl; + exit(1); +} + +float measure_clock_speed() +{ + cerr << "Measuring clock speed... \r" << flush; + + vector all_gflops; + for (int i = 0; i < 8; i++) { + benchmark_t b(1024, 1024, 1024); + b.run(); + all_gflops.push_back(b.gflops); + } + + sort(all_gflops.begin(), all_gflops.end()); + float stable_estimate = all_gflops[2] + all_gflops[3] + all_gflops[4] + all_gflops[5]; + + // multiply by an arbitrary constant to discourage trying doing anything with the + // returned values besides just comparing them with each other. + float result = stable_estimate * 123.456f; + + return result; +} + +struct human_duration_t +{ + int seconds; + human_duration_t(int s) : seconds(s) {} +}; + +ostream& operator<<(ostream& s, const human_duration_t& d) +{ + int remainder = d.seconds; + if (remainder > 3600) { + int hours = remainder / 3600; + s << hours << " h "; + remainder -= hours * 3600; + } + if (remainder > 60) { + int minutes = remainder / 60; + s << minutes << " min "; + remainder -= minutes * 60; + } + if (d.seconds < 600) { + s << remainder << " s"; + } + return s; +} + +const char session_filename[] = "/data/local/tmp/benchmark-blocking-sizes-session.data"; + +void serialize_benchmarks(const char* filename, const vector& benchmarks, size_t first_benchmark_to_run) +{ + FILE* file = fopen(filename, "w"); + if (!file) { + cerr << "Could not open file " << filename << " for writing." << endl; + cerr << "Do you have write permissions on the current working directory?" << endl; + exit(1); + } + size_t benchmarks_vector_size = benchmarks.size(); + fwrite(&max_clock_speed, sizeof(max_clock_speed), 1, file); + fwrite(&benchmarks_vector_size, sizeof(benchmarks_vector_size), 1, file); + fwrite(&first_benchmark_to_run, sizeof(first_benchmark_to_run), 1, file); + fwrite(benchmarks.data(), sizeof(benchmark_t), benchmarks.size(), file); + fclose(file); +} + +bool deserialize_benchmarks(const char* filename, vector& benchmarks, size_t& first_benchmark_to_run) +{ + FILE* file = fopen(filename, "r"); + if (!file) { + return false; + } + if (1 != fread(&max_clock_speed, sizeof(max_clock_speed), 1, file)) { + return false; + } + size_t benchmarks_vector_size = 0; + if (1 != fread(&benchmarks_vector_size, sizeof(benchmarks_vector_size), 1, file)) { + return false; + } + if (1 != fread(&first_benchmark_to_run, sizeof(first_benchmark_to_run), 1, file)) { + return false; + } + benchmarks.resize(benchmarks_vector_size); + if (benchmarks.size() != fread(benchmarks.data(), sizeof(benchmark_t), benchmarks.size(), file)) { + return false; + } + unlink(filename); + return true; +} + +void try_run_some_benchmarks( + vector& benchmarks, + double time_start, + size_t& first_benchmark_to_run) +{ + if (first_benchmark_to_run == benchmarks.size()) { + return; + } + + double time_last_progress_update = 0; + double time_last_clock_speed_measurement = 0; + double time_now = 0; + + size_t benchmark_index = first_benchmark_to_run; + + while (true) { + float ratio_done = float(benchmark_index) / benchmarks.size(); + time_now = timer.getRealTime(); + + // We check clock speed every minute and at the end. + if (benchmark_index == benchmarks.size() || + time_now > time_last_clock_speed_measurement + 60.0f) + { + time_last_clock_speed_measurement = time_now; + + // Ensure that clock speed is as expected + float current_clock_speed = measure_clock_speed(); + + // The tolerance needs to be smaller than the relative difference between + // clock speeds that a device could operate under. + // It seems unlikely that a device would be throttling clock speeds by + // amounts smaller than 2%. + // With a value of 1%, I was getting within noise on a Sandy Bridge. + const float clock_speed_tolerance = 0.02f; + + if (current_clock_speed > (1 + clock_speed_tolerance) * max_clock_speed) { + // Clock speed is now higher than we previously measured. + // Either our initial measurement was inaccurate, which won't happen + // too many times as we are keeping the best clock speed value and + // and allowing some tolerance; or something really weird happened, + // which invalidates all benchmark results collected so far. + // Either way, we better restart all over again now. + if (benchmark_index) { + cerr << "Restarting at " << 100.0f * ratio_done + << " % because clock speed increased. " << endl; + } + max_clock_speed = current_clock_speed; + first_benchmark_to_run = 0; + return; + } + + bool rerun_last_tests = false; + + if (current_clock_speed < (1 - clock_speed_tolerance) * max_clock_speed) { + cerr << "Measurements completed so far: " + << 100.0f * ratio_done + << " % " << endl; + cerr << "Clock speed seems to be only " + << current_clock_speed/max_clock_speed + << " times what it used to be." << endl; + + unsigned int seconds_to_sleep_if_lower_clock_speed = 1; + + while (current_clock_speed < (1 - clock_speed_tolerance) * max_clock_speed) { + if (seconds_to_sleep_if_lower_clock_speed > 32) { + cerr << "Sleeping longer probably won't make a difference." << endl; + cerr << "Serializing benchmarks to " << session_filename << endl; + serialize_benchmarks(session_filename, benchmarks, first_benchmark_to_run); + cerr << "Now restart this benchmark, and it should pick up where we left." << endl; + exit(2); + } + rerun_last_tests = true; + cerr << "Sleeping " + << seconds_to_sleep_if_lower_clock_speed + << " s... \r" << endl; + sleep(seconds_to_sleep_if_lower_clock_speed); + current_clock_speed = measure_clock_speed(); + seconds_to_sleep_if_lower_clock_speed *= 2; + } + } + + if (rerun_last_tests) { + cerr << "Redoing the last " + << 100.0f * float(benchmark_index - first_benchmark_to_run) / benchmarks.size() + << " % because clock speed had been low. " << endl; + return; + } + + // nothing wrong with the clock speed so far, so there won't be a need to rerun + // benchmarks run so far in case we later encounter a lower clock speed. + first_benchmark_to_run = benchmark_index; + } + + if (benchmark_index == benchmarks.size()) { + // We're done! + first_benchmark_to_run = benchmarks.size(); + // Erase progress info + cerr << " " << endl; + return; + } + + // Display progress info on stderr + if (time_now > time_last_progress_update + 1.0f) { + time_last_progress_update = time_now; + cerr << "Measurements... " << 100.0f * ratio_done + << " %, ETA " + << human_duration_t(float(time_now - time_start) * (1.0f - ratio_done) / ratio_done) + << " \r" << flush; + } + + // This is where we actually run a benchmark! + benchmarks[benchmark_index].run(); + benchmark_index++; + } +} + +void run_benchmarks(vector& benchmarks) +{ + size_t first_benchmark_to_run; + vector deserialized_benchmarks; + bool use_deserialized_benchmarks = false; + if (deserialize_benchmarks(session_filename, deserialized_benchmarks, first_benchmark_to_run)) { + cerr << "Found serialized session with " + << 100.0f * first_benchmark_to_run / deserialized_benchmarks.size() + << " % already done" << endl; + if (deserialized_benchmarks.size() == benchmarks.size() && + first_benchmark_to_run > 0 && + first_benchmark_to_run < benchmarks.size()) + { + use_deserialized_benchmarks = true; + } + } + + if (use_deserialized_benchmarks) { + benchmarks = deserialized_benchmarks; + } else { + // not using deserialized benchmarks, starting from scratch + first_benchmark_to_run = 0; + + // Randomly shuffling benchmarks allows us to get accurate enough progress info, + // as now the cheap/expensive benchmarks are randomly mixed so they average out. + // It also means that if data is corrupted for some time span, the odds are that + // not all repetitions of a given benchmark will be corrupted. + random_shuffle(benchmarks.begin(), benchmarks.end()); + } + + for (int i = 0; i < 4; i++) { + max_clock_speed = max(max_clock_speed, measure_clock_speed()); + } + + double time_start = 0.0; + while (first_benchmark_to_run < benchmarks.size()) { + if (first_benchmark_to_run == 0) { + time_start = timer.getRealTime(); + } + try_run_some_benchmarks(benchmarks, + time_start, + first_benchmark_to_run); + } + + // Sort timings by increasing benchmark parameters, and decreasing gflops. + // The latter is very important. It means that we can ignore all but the first + // benchmark with given parameters. + sort(benchmarks.begin(), benchmarks.end()); + + // Collect best (i.e. now first) results for each parameter values. + vector best_benchmarks; + for (auto it = benchmarks.begin(); it != benchmarks.end(); ++it) { + if (best_benchmarks.empty() || + best_benchmarks.back().compact_product_size != it->compact_product_size || + best_benchmarks.back().compact_block_size != it->compact_block_size) + { + best_benchmarks.push_back(*it); + } + } + + // keep and return only the best benchmarks + benchmarks = best_benchmarks; +} + +struct measure_all_pot_sizes_action_t : action_t +{ + virtual const char* invokation_name() const { return "all-pot-sizes"; } + virtual void run() const + { + vector benchmarks; + for (int repetition = 0; repetition < measurement_repetitions; repetition++) { + for (size_t ksize = minsize; ksize <= maxsize; ksize *= 2) { + for (size_t msize = minsize; msize <= maxsize; msize *= 2) { + for (size_t nsize = minsize; nsize <= maxsize; nsize *= 2) { + for (size_t kblock = minsize; kblock <= ksize; kblock *= 2) { + for (size_t mblock = minsize; mblock <= msize; mblock *= 2) { + for (size_t nblock = minsize; nblock <= nsize; nblock *= 2) { + benchmarks.emplace_back(ksize, msize, nsize, kblock, mblock, nblock); + } + } + } + } + } + } + } + + run_benchmarks(benchmarks); + + cout << "BEGIN MEASUREMENTS ALL POT SIZES" << endl; + for (auto it = benchmarks.begin(); it != benchmarks.end(); ++it) { + cout << *it << endl; + } + } +}; + +struct measure_default_sizes_action_t : action_t +{ + virtual const char* invokation_name() const { return "default-sizes"; } + virtual void run() const + { + vector benchmarks; + for (int repetition = 0; repetition < measurement_repetitions; repetition++) { + for (size_t ksize = minsize; ksize <= maxsize; ksize *= 2) { + for (size_t msize = minsize; msize <= maxsize; msize *= 2) { + for (size_t nsize = minsize; nsize <= maxsize; nsize *= 2) { + benchmarks.emplace_back(ksize, msize, nsize); + } + } + } + } + + run_benchmarks(benchmarks); + + cout << "BEGIN MEASUREMENTS DEFAULT SIZES" << endl; + for (auto it = benchmarks.begin(); it != benchmarks.end(); ++it) { + cout << *it << endl; + } + } +}; + +int main(int argc, char* argv[]) +{ + double time_start = timer.getRealTime(); + cout.precision(4); + cerr.precision(4); + + vector> available_actions; + available_actions.emplace_back(new measure_all_pot_sizes_action_t); + available_actions.emplace_back(new measure_default_sizes_action_t); + + auto action = available_actions.end(); + + if (argc <= 1) { + show_usage_and_exit(argc, argv, available_actions); + } + for (auto it = available_actions.begin(); it != available_actions.end(); ++it) { + if (!strcmp(argv[1], (*it)->invokation_name())) { + action = it; + break; + } + } + + if (action == available_actions.end()) { + show_usage_and_exit(argc, argv, available_actions); + } + + for (int i = 2; i < argc; i++) { + if (argv[i] == strstr(argv[i], "--min-working-set-size=")) { + const char* equals_sign = strchr(argv[i], '='); + min_working_set_size = strtoul(equals_sign+1, nullptr, 10); + } else { + cerr << "unrecognized option: " << argv[i] << endl << endl; + show_usage_and_exit(argc, argv, available_actions); + } + } + + print_cpuinfo(); + + cout << "benchmark parameters:" << endl; + cout << "pointer size: " << 8*sizeof(void*) << " bits" << endl; + cout << "scalar type: " << type_name() << endl; + cout << "packet size: " << internal::packet_traits::size << endl; + cout << "minsize = " << minsize << endl; + cout << "maxsize = " << maxsize << endl; + cout << "measurement_repetitions = " << measurement_repetitions << endl; + cout << "min_accurate_time = " << min_accurate_time << endl; + cout << "min_working_set_size = " << min_working_set_size; + if (min_working_set_size == 0) { + cout << " (try to outsize caches)"; + } + cout << endl << endl; + + (*action)->run(); + + double time_end = timer.getRealTime(); + cerr << "Finished in " << human_duration_t(time_end - time_start) << endl; +} diff --git a/ground/gcs/src/libs/eigen/bench/btl/CMakeLists.txt b/ground/gcs/src/libs/eigen/bench/btl/CMakeLists.txt index 119b470d93..38ff9f4832 100644 --- a/ground/gcs/src/libs/eigen/bench/btl/CMakeLists.txt +++ b/ground/gcs/src/libs/eigen/bench/btl/CMakeLists.txt @@ -11,29 +11,24 @@ SET(CMAKE_INCLUDE_CURRENT_DIR ON) string(REGEX MATCH icpc IS_ICPC ${CMAKE_CXX_COMPILER}) IF(CMAKE_COMPILER_IS_GNUCXX OR IS_ICPC) - SET(CMAKE_CXX_FLAGS "-g0 -O3 -DNDEBUG") - SET(CMAKE_Fortran_FLAGS "-g0 -O3 -DNDEBUG") - IF(NOT BTL_NOVEC) - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -msse2") - SET(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -msse2") - ELSE(NOT BTL_NOVEC) + SET(CMAKE_CXX_FLAGS "-g0 -O3 -DNDEBUG ${CMAKE_CXX_FLAGS}") + SET(CMAKE_Fortran_FLAGS "-g0 -O3 -DNDEBUG ${CMAKE_Fortran_FLAGS}") + IF(BTL_NOVEC) SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DEIGEN_DONT_VECTORIZE") - ENDIF(NOT BTL_NOVEC) + ENDIF(BTL_NOVEC) ENDIF(CMAKE_COMPILER_IS_GNUCXX OR IS_ICPC) IF(MSVC) SET(CMAKE_CXX_FLAGS " /O2 /Ot /GL /fp:fast -DNDEBUG") # SET(CMAKE_Fortran_FLAGS "-g0 -O3 -DNDEBUG") - IF(NOT BTL_NOVEC) - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /arch:SSE2") - ELSE(NOT BTL_NOVEC) + IF(BTL_NOVEC) SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DEIGEN_DONT_VECTORIZE") - ENDIF(NOT BTL_NOVEC) + ENDIF(BTL_NOVEC) ENDIF(MSVC) if(IS_ICPC) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fast") - set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -fast") + set(CMAKE_CXX_FLAGS "-fast ${CMAKE_CXX_FLAGS}") + set(CMAKE_Fortran_FLAGS "-fast ${CMAKE_Fortran_FLAGS}") endif(IS_ICPC) include_directories( @@ -48,6 +43,12 @@ include_directories( # set(DEFAULT_LIBRARIES ${MKL_LIBRARIES}) # endif (MKL_FOUND) +find_library(EIGEN_BTL_RT_LIBRARY rt) +# if we cannot find it easily, then we don't need it! +if(NOT EIGEN_BTL_RT_LIBRARY) + set(EIGEN_BTL_RT_LIBRARY "") +endif() + MACRO(BTL_ADD_BENCH targetname) foreach(_current_var ${ARGN}) @@ -70,7 +71,7 @@ MACRO(BTL_ADD_BENCH targetname) IF(BUILD_${targetname}) ADD_EXECUTABLE(${targetname} ${_sources}) ADD_TEST(${targetname} "${targetname}") - target_link_libraries(${targetname} ${DEFAULT_LIBRARIES} rt) + target_link_libraries(${targetname} ${DEFAULT_LIBRARIES} ${EIGEN_BTL_RT_LIBRARY}) ENDIF(BUILD_${targetname}) ENDMACRO(BTL_ADD_BENCH) @@ -91,6 +92,7 @@ ENABLE_TESTING() add_subdirectory(libs/eigen3) add_subdirectory(libs/eigen2) +add_subdirectory(libs/tensors) add_subdirectory(libs/BLAS) add_subdirectory(libs/ublas) add_subdirectory(libs/gmm) @@ -98,6 +100,7 @@ add_subdirectory(libs/mtl4) add_subdirectory(libs/blitz) add_subdirectory(libs/tvmet) add_subdirectory(libs/STL) +add_subdirectory(libs/blaze) add_subdirectory(data) diff --git a/ground/gcs/src/libs/eigen/bench/btl/actions/action_axpby.hh b/ground/gcs/src/libs/eigen/bench/btl/actions/action_axpby.hh index 98511ab6a5..dadd0ccf3c 100644 --- a/ground/gcs/src/libs/eigen/bench/btl/actions/action_axpby.hh +++ b/ground/gcs/src/libs/eigen/bench/btl/actions/action_axpby.hh @@ -33,7 +33,7 @@ class Action_axpby { public : // Ctor - Action_axpby( int size ):_size(size),_alpha(0.5),_beta(0.95) + Action_axpby( int size ):_alpha(0.5),_beta(0.95),_size(size) { MESSAGE("Action_axpby Ctor"); diff --git a/ground/gcs/src/libs/eigen/bench/btl/actions/action_axpy.hh b/ground/gcs/src/libs/eigen/bench/btl/actions/action_axpy.hh index e4cb3a5bd6..261be4cb8e 100644 --- a/ground/gcs/src/libs/eigen/bench/btl/actions/action_axpy.hh +++ b/ground/gcs/src/libs/eigen/bench/btl/actions/action_axpy.hh @@ -35,7 +35,7 @@ public : // Ctor - Action_axpy( int size ):_size(size),_coef(1.0) + Action_axpy( int size ):_coef(1.0),_size(size) { MESSAGE("Action_axpy Ctor"); diff --git a/ground/gcs/src/libs/eigen/bench/btl/cmake/FindACML.cmake b/ground/gcs/src/libs/eigen/bench/btl/cmake/FindACML.cmake index f45ae1b0de..4989fa2f4c 100644 --- a/ground/gcs/src/libs/eigen/bench/btl/cmake/FindACML.cmake +++ b/ground/gcs/src/libs/eigen/bench/btl/cmake/FindACML.cmake @@ -17,6 +17,7 @@ find_file(ACML_LIBRARIES libacml_mp.so PATHS /usr/lib + /usr/lib64 $ENV{ACMLDIR}/lib ${LIB_INSTALL_DIR} ) @@ -35,6 +36,7 @@ if(NOT ACML_LIBRARIES) libacml.so libacml_mv.so PATHS /usr/lib + /usr/lib64 $ENV{ACMLDIR}/lib ${LIB_INSTALL_DIR} ) diff --git a/ground/gcs/src/libs/eigen/bench/btl/cmake/FindATLAS.cmake b/ground/gcs/src/libs/eigen/bench/btl/cmake/FindATLAS.cmake index 6b90652066..4136a989d6 100644 --- a/ground/gcs/src/libs/eigen/bench/btl/cmake/FindATLAS.cmake +++ b/ground/gcs/src/libs/eigen/bench/btl/cmake/FindATLAS.cmake @@ -3,33 +3,25 @@ if (ATLAS_LIBRARIES) set(ATLAS_FIND_QUIETLY TRUE) endif (ATLAS_LIBRARIES) -find_file(ATLAS_LIB libatlas.so.3 PATHS /usr/lib $ENV{ATLASDIR} ${LIB_INSTALL_DIR}) -find_library(ATLAS_LIB atlas PATHS $ENV{ATLASDIR} ${LIB_INSTALL_DIR}) +find_file(ATLAS_LIB libatlas.so.3 PATHS /usr/lib /usr/lib/atlas /usr/lib64 /usr/lib64/atlas $ENV{ATLASDIR} ${LIB_INSTALL_DIR}) +find_library(ATLAS_LIB satlas PATHS $ENV{ATLASDIR} ${LIB_INSTALL_DIR}) -find_file(ATLAS_CBLAS libcblas.so.3 PATHS /usr/lib $ENV{ATLASDIR} ${LIB_INSTALL_DIR}) -find_library(ATLAS_CBLAS cblas PATHS $ENV{ATLASDIR} ${LIB_INSTALL_DIR}) +find_file(ATLAS_LAPACK NAMES liblapack_atlas.so.3 liblapack.so.3 PATHS /usr/lib /usr/lib/atlas /usr/lib64 /usr/lib64/atlas $ENV{ATLASDIR} ${LIB_INSTALL_DIR}) +find_library(ATLAS_LAPACK NAMES lapack_atlas lapack PATHS $ENV{ATLASDIR} ${LIB_INSTALL_DIR}) -find_file(ATLAS_LAPACK liblapack_atlas.so.3 PATHS /usr/lib $ENV{ATLASDIR} ${LIB_INSTALL_DIR}) -find_library(ATLAS_LAPACK lapack_atlas PATHS $ENV{ATLASDIR} ${LIB_INSTALL_DIR}) - -if(NOT ATLAS_LAPACK) - find_file(ATLAS_LAPACK liblapack.so.3 PATHS /usr/lib/atlas $ENV{ATLASDIR} ${LIB_INSTALL_DIR}) - find_library(ATLAS_LAPACK lapack PATHS $ENV{ATLASDIR} ${LIB_INSTALL_DIR}) -endif(NOT ATLAS_LAPACK) - -find_file(ATLAS_F77BLAS libf77blas.so.3 PATHS /usr/lib $ENV{ATLASDIR} ${LIB_INSTALL_DIR}) +find_file(ATLAS_F77BLAS libf77blas.so.3 PATHS /usr/lib /usr/lib/atlas /usr/lib64 /usr/lib64/atlas $ENV{ATLASDIR} ${LIB_INSTALL_DIR}) find_library(ATLAS_F77BLAS f77blas PATHS $ENV{ATLASDIR} ${LIB_INSTALL_DIR}) if(ATLAS_LIB AND ATLAS_CBLAS AND ATLAS_LAPACK AND ATLAS_F77BLAS) - set(ATLAS_LIBRARIES ${ATLAS_LAPACK} ${ATLAS_CBLAS} ${ATLAS_F77BLAS} ${ATLAS_LIB}) + set(ATLAS_LIBRARIES ${ATLAS_LAPACK} ${ATLAS_LIB}) # search the default lapack lib link to it find_file(ATLAS_REFERENCE_LAPACK liblapack.so.3 PATHS /usr/lib /usr/lib64) find_library(ATLAS_REFERENCE_LAPACK NAMES lapack) - if(ATLAS_REFERENCE_LAPACK) - set(ATLAS_LIBRARIES ${ATLAS_LIBRARIES} ${ATLAS_REFERENCE_LAPACK}) - endif() +# if(ATLAS_REFERENCE_LAPACK) +# set(ATLAS_LIBRARIES ${ATLAS_LIBRARIES} ${ATLAS_REFERENCE_LAPACK}) +# endif() endif(ATLAS_LIB AND ATLAS_CBLAS AND ATLAS_LAPACK AND ATLAS_F77BLAS) diff --git a/ground/gcs/src/libs/eigen/bench/btl/cmake/FindBLAZE.cmake b/ground/gcs/src/libs/eigen/bench/btl/cmake/FindBLAZE.cmake new file mode 100644 index 0000000000..dba4c89f2d --- /dev/null +++ b/ground/gcs/src/libs/eigen/bench/btl/cmake/FindBLAZE.cmake @@ -0,0 +1,31 @@ +# - Try to find eigen2 headers +# Once done this will define +# +# BLAZE_FOUND - system has blaze lib +# BLAZE_INCLUDE_DIR - the blaze include directory +# +# Copyright (C) 2008 Gael Guennebaud +# Adapted from FindEigen.cmake: +# Copyright (c) 2006, 2007 Montel Laurent, +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +if (BLAZE_INCLUDE_DIR) + + # in cache already + set(BLAZE_FOUND TRUE) + +else (BLAZE_INCLUDE_DIR) + +find_path(BLAZE_INCLUDE_DIR NAMES blaze/Blaze.h + PATHS + ${INCLUDE_INSTALL_DIR} + ) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(BLAZE DEFAULT_MSG BLAZE_INCLUDE_DIR) + +mark_as_advanced(BLAZE_INCLUDE_DIR) + +endif(BLAZE_INCLUDE_DIR) + diff --git a/ground/gcs/src/libs/eigen/bench/btl/cmake/FindCBLAS.cmake b/ground/gcs/src/libs/eigen/bench/btl/cmake/FindCBLAS.cmake index 554f0291b4..ce0f2f2b2d 100644 --- a/ground/gcs/src/libs/eigen/bench/btl/cmake/FindCBLAS.cmake +++ b/ground/gcs/src/libs/eigen/bench/btl/cmake/FindCBLAS.cmake @@ -23,6 +23,7 @@ find_file(CBLAS_LIBRARIES libcblas.so.3 PATHS /usr/lib + /usr/lib64 $ENV{CBLASDIR}/lib ${LIB_INSTALL_DIR} ) diff --git a/ground/gcs/src/libs/eigen/bench/btl/cmake/FindGOTO.cmake b/ground/gcs/src/libs/eigen/bench/btl/cmake/FindGOTO.cmake deleted file mode 100644 index 67ea0934a5..0000000000 --- a/ground/gcs/src/libs/eigen/bench/btl/cmake/FindGOTO.cmake +++ /dev/null @@ -1,15 +0,0 @@ - -if (GOTO_LIBRARIES) - set(GOTO_FIND_QUIETLY TRUE) -endif (GOTO_LIBRARIES) - -find_library(GOTO_LIBRARIES goto PATHS $ENV{GOTODIR} ${LIB_INSTALL_DIR}) - -if(GOTO_LIBRARIES AND CMAKE_COMPILER_IS_GNUCXX) - set(GOTO_LIBRARIES ${GOTO_LIBRARIES} "-lpthread -lgfortran") -endif() - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(GOTO DEFAULT_MSG GOTO_LIBRARIES) - -mark_as_advanced(GOTO_LIBRARIES) diff --git a/ground/gcs/src/libs/eigen/bench/btl/cmake/FindGOTO2.cmake b/ground/gcs/src/libs/eigen/bench/btl/cmake/FindGOTO2.cmake deleted file mode 100644 index baa68d2136..0000000000 --- a/ground/gcs/src/libs/eigen/bench/btl/cmake/FindGOTO2.cmake +++ /dev/null @@ -1,25 +0,0 @@ - -if (GOTO2_LIBRARIES) - set(GOTO2_FIND_QUIETLY TRUE) -endif (GOTO2_LIBRARIES) -# -# find_path(GOTO_INCLUDES -# NAMES -# cblas.h -# PATHS -# $ENV{GOTODIR}/include -# ${INCLUDE_INSTALL_DIR} -# ) - -find_file(GOTO2_LIBRARIES libgoto2.so PATHS /usr/lib $ENV{GOTO2DIR} ${LIB_INSTALL_DIR}) -find_library(GOTO2_LIBRARIES goto2 PATHS $ENV{GOTO2DIR} ${LIB_INSTALL_DIR}) - -if(GOTO2_LIBRARIES AND CMAKE_COMPILER_IS_GNUCXX) - set(GOTO2_LIBRARIES ${GOTO2_LIBRARIES} "-lpthread -lgfortran") -endif() - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(GOTO2 DEFAULT_MSG - GOTO2_LIBRARIES) - -mark_as_advanced(GOTO2_LIBRARIES) diff --git a/ground/gcs/src/libs/eigen/bench/btl/cmake/FindOPENBLAS.cmake b/ground/gcs/src/libs/eigen/bench/btl/cmake/FindOPENBLAS.cmake new file mode 100644 index 0000000000..2a09194364 --- /dev/null +++ b/ground/gcs/src/libs/eigen/bench/btl/cmake/FindOPENBLAS.cmake @@ -0,0 +1,17 @@ + +if (OPENBLAS_LIBRARIES) + set(OPENBLAS_FIND_QUIETLY TRUE) +endif (OPENBLAS_LIBRARIES) + +find_file(OPENBLAS_LIBRARIES NAMES libopenblas.so libopenblas.so.0 PATHS /usr/lib /usr/lib64 $ENV{OPENBLASDIR} ${LIB_INSTALL_DIR}) +find_library(OPENBLAS_LIBRARIES openblas PATHS $ENV{OPENBLASDIR} ${LIB_INSTALL_DIR}) + +if(OPENBLAS_LIBRARIES AND CMAKE_COMPILER_IS_GNUCXX) + set(OPENBLAS_LIBRARIES ${OPENBLAS_LIBRARIES} "-lpthread -lgfortran") +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(OPENBLAS DEFAULT_MSG + OPENBLAS_LIBRARIES) + +mark_as_advanced(OPENBLAS_LIBRARIES) diff --git a/ground/gcs/src/libs/eigen/bench/btl/data/action_settings.txt b/ground/gcs/src/libs/eigen/bench/btl/data/action_settings.txt index e32213e22d..39d2b5dc48 100644 --- a/ground/gcs/src/libs/eigen/bench/btl/data/action_settings.txt +++ b/ground/gcs/src/libs/eigen/bench/btl/data/action_settings.txt @@ -1,19 +1,19 @@ -aat ; "{/*1.5 A x A^T}" ; "matrix size" ; 4:3000 -ata ; "{/*1.5 A^T x A}" ; "matrix size" ; 4:3000 -atv ; "{/*1.5 matrix^T x vector}" ; "matrix size" ; 4:3000 +aat ; "{/*1.5 A x A^T}" ; "matrix size" ; 4:5000 +ata ; "{/*1.5 A^T x A}" ; "matrix size" ; 4:5000 +atv ; "{/*1.5 matrix^T x vector}" ; "matrix size" ; 4:5000 axpby ; "{/*1.5 Y = alpha X + beta Y}" ; "vector size" ; 5:1000000 axpy ; "{/*1.5 Y += alpha X}" ; "vector size" ; 5:1000000 -matrix_matrix ; "{/*1.5 matrix matrix product}" ; "matrix size" ; 4:3000 -matrix_vector ; "{/*1.5 matrix vector product}" ; "matrix size" ; 4:3000 -trmm ; "{/*1.5 triangular matrix matrix product}" ; "matrix size" ; 4:3000 -trisolve_vector ; "{/*1.5 triangular solver - vector (X = inv(L) X)}" ; "size" ; 4:3000 -trisolve_matrix ; "{/*1.5 triangular solver - matrix (M = inv(L) M)}" ; "size" ; 4:3000 -cholesky ; "{/*1.5 Cholesky decomposition}" ; "matrix size" ; 4:3000 -complete_lu_decomp ; "{/*1.5 Complete LU decomposition}" ; "matrix size" ; 4:3000 -partial_lu_decomp ; "{/*1.5 Partial LU decomposition}" ; "matrix size" ; 4:3000 -tridiagonalization ; "{/*1.5 Tridiagonalization}" ; "matrix size" ; 4:3000 -hessenberg ; "{/*1.5 Hessenberg decomposition}" ; "matrix size" ; 4:3000 -symv ; "{/*1.5 symmetric matrix vector product}" ; "matrix size" ; 4:3000 -syr2 ; "{/*1.5 symmretric rank-2 update (A += u^T v + u v^T)}" ; "matrix size" ; 4:3000 -ger ; "{/*1.5 general rank-1 update (A += u v^T)}" ; "matrix size" ; 4:3000 -rot ; "{/*1.5 apply rotation in the plane}" ; "vector size" ; 4:1000000 \ No newline at end of file +matrix_matrix ; "{/*1.5 matrix matrix product}" ; "matrix size" ; 4:5000 +matrix_vector ; "{/*1.5 matrix vector product}" ; "matrix size" ; 4:5000 +trmm ; "{/*1.5 triangular matrix matrix product}" ; "matrix size" ; 4:5000 +trisolve_vector ; "{/*1.5 triangular solver - vector (X = inv(L) X)}" ; "size" ; 4:5000 +trisolve_matrix ; "{/*1.5 triangular solver - matrix (M = inv(L) M)}" ; "size" ; 4:5000 +cholesky ; "{/*1.5 Cholesky decomposition}" ; "matrix size" ; 4:5000 +complete_lu_decomp ; "{/*1.5 Complete LU decomposition}" ; "matrix size" ; 4:5000 +partial_lu_decomp ; "{/*1.5 Partial LU decomposition}" ; "matrix size" ; 4:5000 +tridiagonalization ; "{/*1.5 Tridiagonalization}" ; "matrix size" ; 4:5000 +hessenberg ; "{/*1.5 Hessenberg decomposition}" ; "matrix size" ; 4:5000 +symv ; "{/*1.5 symmetric matrix vector product}" ; "matrix size" ; 4:5000 +syr2 ; "{/*1.5 symmretric rank-2 update (A += u^T v + u v^T)}" ; "matrix size" ; 4:5000 +ger ; "{/*1.5 general rank-1 update (A += u v^T)}" ; "matrix size" ; 4:5000 +rot ; "{/*1.5 apply rotation in the plane}" ; "vector size" ; 4:1000000 diff --git a/ground/gcs/src/libs/eigen/bench/btl/data/perlib_plot_settings.txt b/ground/gcs/src/libs/eigen/bench/btl/data/perlib_plot_settings.txt index 6844bab289..f023cfe02f 100644 --- a/ground/gcs/src/libs/eigen/bench/btl/data/perlib_plot_settings.txt +++ b/ground/gcs/src/libs/eigen/bench/btl/data/perlib_plot_settings.txt @@ -10,7 +10,7 @@ ublas ; with lines lw 3 lt 1 lc rgbcolor "#00b7ff" mtl4 ; with lines lw 3 lt 1 lc rgbcolor "#d18847" blitz ; with lines lw 3 lt 1 lc rgbcolor "#ff00ff" F77 ; with lines lw 3 lt 3 lc rgbcolor "#e6e64c" -GOTO ; with lines lw 3 lt 3 lc rgbcolor "#C05600" -GOTO2 ; with lines lw 3 lt 1 lc rgbcolor "#C05600" +OPENBLAS ; with lines lw 3 lt 1 lc rgbcolor "#C05600" C ; with lines lw 3 lt 3 lc rgbcolor "#e6bd96" ACML ; with lines lw 2 lt 3 lc rgbcolor "#e6e64c" +blaze ; with lines lw 3 lt 1 lc rgbcolor "#ff00ff" diff --git a/ground/gcs/src/libs/eigen/bench/btl/generic_bench/bench.hh b/ground/gcs/src/libs/eigen/bench/btl/generic_bench/bench.hh index 005c363955..7b7b951b50 100644 --- a/ground/gcs/src/libs/eigen/bench/btl/generic_bench/bench.hh +++ b/ground/gcs/src/libs/eigen/bench/btl/generic_bench/bench.hh @@ -102,8 +102,8 @@ BTL_DONT_INLINE void bench( int size_min, int size_max, int nb_point ) // merge the two data std::vector newSizes; std::vector newFlops; - int i=0; - int j=0; + unsigned int i=0; + unsigned int j=0; while (i config = BtlString(_config).split(" \t\n"); - for (int i = 0; i BTL_DONT_INLINE void init_matrix(Vector & A, int size){ A.resize(size); - for (int row=0; row(A[row],size,row); } } @@ -50,11 +50,11 @@ BTL_DONT_INLINE void init_matrix(Vector & A, int size){ template BTL_DONT_INLINE void init_matrix_symm(Matrix& A, int size){ A.resize(size); - for (int row=0; row @@ -87,6 +87,48 @@ }; // Portable_Timer +#elif defined(__APPLE__) +#include +#include + + +class Portable_Timer +{ + public: + + Portable_Timer() + { + } + + void start() + { + m_start_time = double(mach_absolute_time())*1e-9;; + + } + + void stop() + { + m_stop_time = double(mach_absolute_time())*1e-9;; + + } + + double elapsed() + { + return user_time(); + } + + double user_time() + { + return m_stop_time - m_start_time; + } + + +private: + + double m_stop_time, m_start_time; + +}; // Portable_Timer (Apple) + #else #include @@ -138,7 +180,7 @@ private: int m_clkid; double m_stop_time, m_start_time; -}; // Portable_Timer +}; // Portable_Timer (Linux) #endif diff --git a/ground/gcs/src/libs/eigen/bench/btl/generic_bench/utils/size_lin_log.hh b/ground/gcs/src/libs/eigen/bench/btl/generic_bench/utils/size_lin_log.hh index bca3932aea..bbc9f543df 100644 --- a/ground/gcs/src/libs/eigen/bench/btl/generic_bench/utils/size_lin_log.hh +++ b/ground/gcs/src/libs/eigen/bench/btl/generic_bench/utils/size_lin_log.hh @@ -23,7 +23,7 @@ #include "size_log.hh" template -void size_lin_log(const int nb_point, const int size_min, const int size_max, Vector & X) +void size_lin_log(const int nb_point, const int /*size_min*/, const int size_max, Vector & X) { int ten=10; int nine=9; diff --git a/ground/gcs/src/libs/eigen/bench/btl/libs/BLAS/CMakeLists.txt b/ground/gcs/src/libs/eigen/bench/btl/libs/BLAS/CMakeLists.txt index de42fe047c..0272ccad07 100644 --- a/ground/gcs/src/libs/eigen/bench/btl/libs/BLAS/CMakeLists.txt +++ b/ground/gcs/src/libs/eigen/bench/btl/libs/BLAS/CMakeLists.txt @@ -18,27 +18,14 @@ if (MKL_FOUND) endif (MKL_FOUND) -find_package(GOTO2) -if (GOTO2_FOUND) - btl_add_bench(btl_goto2 main.cpp) - if(BUILD_btl_goto2) - target_link_libraries(btl_goto2 ${GOTO_LIBRARIES} ) - set_target_properties(btl_goto2 PROPERTIES COMPILE_FLAGS "-DCBLASNAME=GOTO2") - endif(BUILD_btl_goto2) -endif (GOTO2_FOUND) - -find_package(GOTO) -if (GOTO_FOUND) - if(GOTO2_FOUND) - btl_add_bench(btl_goto main.cpp OFF) - else() - btl_add_bench(btl_goto main.cpp) - endif() - if(BUILD_btl_goto) - target_link_libraries(btl_goto ${GOTO_LIBRARIES} ) - set_target_properties(btl_goto PROPERTIES COMPILE_FLAGS "-DCBLASNAME=GOTO") - endif(BUILD_btl_goto) -endif (GOTO_FOUND) +find_package(OPENBLAS) +if (OPENBLAS_FOUND) + btl_add_bench(btl_openblas main.cpp) + if(BUILD_btl_openblas) + target_link_libraries(btl_openblas ${OPENBLAS_LIBRARIES} ) + set_target_properties(btl_openblas PROPERTIES COMPILE_FLAGS "-DCBLASNAME=OPENBLAS") + endif(BUILD_btl_openblas) +endif (OPENBLAS_FOUND) find_package(ACML) if (ACML_FOUND) diff --git a/ground/gcs/src/libs/eigen/bench/btl/libs/BLAS/blas_interface_impl.hh b/ground/gcs/src/libs/eigen/bench/btl/libs/BLAS/blas_interface_impl.hh index 0e84df0386..fc4ba2a1f3 100644 --- a/ground/gcs/src/libs/eigen/bench/btl/libs/BLAS/blas_interface_impl.hh +++ b/ground/gcs/src/libs/eigen/bench/btl/libs/BLAS/blas_interface_impl.hh @@ -75,7 +75,6 @@ public : static inline void partial_lu_decomp(const gene_matrix & X, gene_matrix & C, int N){ int N2 = N*N; BLAS_FUNC(copy)(&N2, X, &intone, C, &intone); - char uplo = 'L'; int info = 0; int * ipiv = (int*)alloca(sizeof(int)*N); BLAS_FUNC(getrf)(&N, &N, C, &N, ipiv, &info); @@ -92,7 +91,7 @@ public : BLAS_FUNC(trsm)(&right, &lower, ¬rans, &nonunit, &N, &N, &fone, L, &N, X, &N); } - static inline void trmm(gene_matrix & A, gene_matrix & B, gene_matrix & X, int N){ + static inline void trmm(gene_matrix & A, gene_matrix & B, gene_matrix & /*X*/, int N){ BLAS_FUNC(trmm)(&left, &lower, ¬rans,&nonunit, &N,&N,&fone,A,&N,B,&N); } @@ -101,7 +100,6 @@ public : static inline void lu_decomp(const gene_matrix & X, gene_matrix & C, int N){ int N2 = N*N; BLAS_FUNC(copy)(&N2, X, &intone, C, &intone); - char uplo = 'L'; int info = 0; int * ipiv = (int*)alloca(sizeof(int)*N); int * jpiv = (int*)alloca(sizeof(int)*N); @@ -134,8 +132,6 @@ public : } char uplo = 'U'; int info = 0; - int ilo = 1; - int ihi = N; int bsize = 64; int worksize = N*bsize; SCALAR* d = new SCALAR[3*N+worksize]; diff --git a/ground/gcs/src/libs/eigen/bench/btl/libs/BLAS/c_interface_base.h b/ground/gcs/src/libs/eigen/bench/btl/libs/BLAS/c_interface_base.h index 515d8dcfc3..de613803b7 100644 --- a/ground/gcs/src/libs/eigen/bench/btl/libs/BLAS/c_interface_base.h +++ b/ground/gcs/src/libs/eigen/bench/btl/libs/BLAS/c_interface_base.h @@ -17,12 +17,12 @@ template class c_interface_base typedef real* gene_matrix; typedef real* gene_vector; - static void free_matrix(gene_matrix & A, int N){ - delete A; + static void free_matrix(gene_matrix & A, int /*N*/){ + delete[] A; } static void free_vector(gene_vector & B){ - delete B; + delete[] B; } static inline void matrix_from_stl(gene_matrix & A, stl_matrix & A_stl){ diff --git a/ground/gcs/src/libs/eigen/bench/btl/libs/BLAS/main.cpp b/ground/gcs/src/libs/eigen/bench/btl/libs/BLAS/main.cpp index 8347c9f0ba..564d55ef23 100644 --- a/ground/gcs/src/libs/eigen/bench/btl/libs/BLAS/main.cpp +++ b/ground/gcs/src/libs/eigen/bench/btl/libs/BLAS/main.cpp @@ -56,13 +56,13 @@ int main() bench > >(MIN_MM,MAX_MM,NB_POINT); - bench > >(MIN_MM,MAX_MM,NB_POINT); - bench > >(MIN_MM,MAX_MM,NB_POINT); + bench > >(MIN_LU,MAX_LU,NB_POINT); + bench > >(MIN_LU,MAX_LU,NB_POINT); #ifdef HAS_LAPACK - bench > >(MIN_MM,MAX_MM,NB_POINT); - bench > >(MIN_MM,MAX_MM,NB_POINT); - bench > >(MIN_MM,MAX_MM,NB_POINT); +// bench > >(MIN_LU,MAX_LU,NB_POINT); + bench > >(MIN_LU,MAX_LU,NB_POINT); + bench > >(MIN_LU,MAX_LU,NB_POINT); #endif //bench > >(MIN_LU,MAX_LU,NB_POINT); diff --git a/ground/gcs/src/libs/eigen/bench/btl/libs/STL/STL_interface.hh b/ground/gcs/src/libs/eigen/bench/btl/libs/STL/STL_interface.hh index 93e76bd553..ef4cc92330 100644 --- a/ground/gcs/src/libs/eigen/bench/btl/libs/STL/STL_interface.hh +++ b/ground/gcs/src/libs/eigen/bench/btl/libs/STL/STL_interface.hh @@ -44,9 +44,9 @@ public : return "STL"; } - static void free_matrix(gene_matrix & A, int N){} + static void free_matrix(gene_matrix & /*A*/, int /*N*/){} - static void free_vector(gene_vector & B){} + static void free_vector(gene_vector & /*B*/){} static inline void matrix_from_stl(gene_matrix & A, stl_matrix & A_stl){ A = A_stl; diff --git a/ground/gcs/src/libs/eigen/bench/btl/libs/blaze/CMakeLists.txt b/ground/gcs/src/libs/eigen/bench/btl/libs/blaze/CMakeLists.txt new file mode 100644 index 0000000000..e99a0855c9 --- /dev/null +++ b/ground/gcs/src/libs/eigen/bench/btl/libs/blaze/CMakeLists.txt @@ -0,0 +1,13 @@ + +find_package(BLAZE) +find_package(Boost COMPONENTS system) +if (BLAZE_FOUND AND Boost_FOUND) + include_directories(${BLAZE_INCLUDE_DIR} ${Boost_INCLUDE_DIRS}) + btl_add_bench(btl_blaze main.cpp) + # Note: The newest blaze version requires C++14. + # Ideally, we should set this depending on the version of Blaze we found + set_property(TARGET btl_blaze PROPERTY CXX_STANDARD 14) + if(BUILD_btl_blaze) + target_link_libraries(btl_blaze ${Boost_LIBRARIES}) + endif() +endif () diff --git a/ground/gcs/src/libs/eigen/bench/btl/libs/blaze/blaze_interface.hh b/ground/gcs/src/libs/eigen/bench/btl/libs/blaze/blaze_interface.hh new file mode 100644 index 0000000000..ee15239441 --- /dev/null +++ b/ground/gcs/src/libs/eigen/bench/btl/libs/blaze/blaze_interface.hh @@ -0,0 +1,140 @@ +//===================================================== +// Copyright (C) 2008 Gael Guennebaud +//===================================================== +// +// 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 2 +// 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 BLAZE_INTERFACE_HH +#define BLAZE_INTERFACE_HH + +#include +#include +// using namespace blaze; + +#include + +template +class blaze_interface { + +public : + + typedef real real_type ; + + typedef std::vector stl_vector; + typedef std::vector stl_matrix; + + typedef blaze::DynamicMatrix gene_matrix; + typedef blaze::DynamicVector gene_vector; + + static inline std::string name() { return "blaze"; } + + static void free_matrix(gene_matrix & A, int N){ + return ; + } + + static void free_vector(gene_vector & B){ + return ; + } + + static inline void matrix_from_stl(gene_matrix & A, stl_matrix & A_stl){ + A.resize(A_stl[0].size(), A_stl.size()); + + for (int j=0; j ipvt(N); +// lu_factor(R, ipvt); +// } + +// static inline void trisolve_lower(const gene_matrix & L, const gene_vector& B, gene_vector & X, int N){ +// X = lower_trisolve(L, B); +// } + + static inline void copy_matrix(const gene_matrix & source, gene_matrix & cible, int N){ + cible = source; + } + + static inline void copy_vector(const gene_vector & source, gene_vector & cible, int N){ + cible = source; + } + +}; + +#endif diff --git a/ground/gcs/src/libs/eigen/bench/btl/libs/blaze/main.cpp b/ground/gcs/src/libs/eigen/bench/btl/libs/blaze/main.cpp new file mode 100644 index 0000000000..80e8f4eaa0 --- /dev/null +++ b/ground/gcs/src/libs/eigen/bench/btl/libs/blaze/main.cpp @@ -0,0 +1,40 @@ +//===================================================== +// Copyright (C) 2008 Gael Guennebaud +//===================================================== +// +// 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 2 +// 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 "utilities.h" +#include "blaze_interface.hh" +#include "bench.hh" +#include "basic_actions.hh" + +BTL_MAIN; + +int main() +{ + + bench > >(MIN_AXPY,MAX_AXPY,NB_POINT); + bench > >(MIN_AXPY,MAX_AXPY,NB_POINT); + + bench > >(MIN_MV,MAX_MV,NB_POINT); + bench > >(MIN_MV,MAX_MV,NB_POINT); +// bench > >(MIN_MM,MAX_MM,NB_POINT); +// bench > >(MIN_MM,MAX_MM,NB_POINT); +// bench > >(MIN_MM,MAX_MM,NB_POINT); + + return 0; +} + + diff --git a/ground/gcs/src/libs/eigen/bench/btl/libs/eigen2/eigen2_interface.hh b/ground/gcs/src/libs/eigen/bench/btl/libs/eigen2/eigen2_interface.hh index 47fe581357..1deabdae21 100644 --- a/ground/gcs/src/libs/eigen/bench/btl/libs/eigen2/eigen2_interface.hh +++ b/ground/gcs/src/libs/eigen/bench/btl/libs/eigen2/eigen2_interface.hh @@ -47,7 +47,7 @@ public : { #if defined(EIGEN_VECTORIZE_SSE) if (SIZE==Dynamic) return "eigen2"; else return "tiny_eigen2"; - #elif defined(EIGEN_VECTORIZE_ALTIVEC) + #elif defined(EIGEN_VECTORIZE_ALTIVEC) || defined(EIGEN_VECTORIZE_VSX) if (SIZE==Dynamic) return "eigen2"; else return "tiny_eigen2"; #else if (SIZE==Dynamic) return "eigen2_novec"; else return "tiny_eigen2_novec"; diff --git a/ground/gcs/src/libs/eigen/bench/btl/libs/eigen3/eigen3_interface.hh b/ground/gcs/src/libs/eigen/bench/btl/libs/eigen3/eigen3_interface.hh index 31bcc1f933..b821fd7211 100644 --- a/ground/gcs/src/libs/eigen/bench/btl/libs/eigen3/eigen3_interface.hh +++ b/ground/gcs/src/libs/eigen/bench/btl/libs/eigen3/eigen3_interface.hh @@ -45,15 +45,15 @@ public : return EIGEN_MAKESTRING(BTL_PREFIX); } - static void free_matrix(gene_matrix & A, int N) {} + static void free_matrix(gene_matrix & /*A*/, int /*N*/) {} - static void free_vector(gene_vector & B) {} + static void free_vector(gene_vector & /*B*/) {} static BTL_DONT_INLINE void matrix_from_stl(gene_matrix & A, stl_matrix & A_stl){ A.resize(A_stl[0].size(), A_stl.size()); - for (int j=0; j().setZero(); X.template selfadjointView().rankUpdate(A); } - static inline void matrix_vector_product(const gene_matrix & A, const gene_vector & B, gene_vector & X, int N){ + static inline void matrix_vector_product(const gene_matrix & A, const gene_vector & B, gene_vector & X, int /*N*/){ X.noalias() = A*B; } - static inline void symv(const gene_matrix & A, const gene_vector & B, gene_vector & X, int N){ + static inline void symv(const gene_matrix & A, const gene_vector & B, gene_vector & X, int /*N*/){ X.noalias() = (A.template selfadjointView() * B); // internal::product_selfadjoint_vector(N,A.data(),N, B.data(), 1, X.data(), 1); } @@ -155,54 +155,54 @@ public : } } - static EIGEN_DONT_INLINE void syr2(gene_matrix & A, gene_vector & X, gene_vector & Y, int N){ + static EIGEN_DONT_INLINE void syr2(gene_matrix & A, gene_vector & X, gene_vector & Y, int N){ // internal::product_selfadjoint_rank2_update(N,A.data(),N, X.data(), 1, Y.data(), 1, -1); for(int j=0; j(c,s)); } - static inline void atv_product(gene_matrix & A, gene_vector & B, gene_vector & X, int N){ + static inline void atv_product(gene_matrix & A, gene_vector & B, gene_vector & X, int /*N*/){ X.noalias() = (A.transpose()*B); } - static inline void axpy(real coef, const gene_vector & X, gene_vector & Y, int N){ + static inline void axpy(real coef, const gene_vector & X, gene_vector & Y, int /*N*/){ Y += coef * X; } - static inline void axpby(real a, const gene_vector & X, real b, gene_vector & Y, int N){ + static inline void axpby(real a, const gene_vector & X, real b, gene_vector & Y, int /*N*/){ Y = a*X + b*Y; } - static EIGEN_DONT_INLINE void copy_matrix(const gene_matrix & source, gene_matrix & cible, int N){ + static EIGEN_DONT_INLINE void copy_matrix(const gene_matrix & source, gene_matrix & cible, int /*N*/){ cible = source; } - static EIGEN_DONT_INLINE void copy_vector(const gene_vector & source, gene_vector & cible, int N){ + static EIGEN_DONT_INLINE void copy_vector(const gene_vector & source, gene_vector & cible, int /*N*/){ cible = source; } - static inline void trisolve_lower(const gene_matrix & L, const gene_vector& B, gene_vector& X, int N){ + static inline void trisolve_lower(const gene_matrix & L, const gene_vector& B, gene_vector& X, int /*N*/){ X = L.template triangularView().solve(B); } - static inline void trisolve_lower_matrix(const gene_matrix & L, const gene_matrix& B, gene_matrix& X, int N){ + static inline void trisolve_lower_matrix(const gene_matrix & L, const gene_matrix& B, gene_matrix& X, int /*N*/){ X = L.template triangularView().solve(B); } - static inline void trmm(const gene_matrix & L, const gene_matrix& B, gene_matrix& X, int N){ + static inline void trmm(const gene_matrix & L, const gene_matrix& B, gene_matrix& X, int /*N*/){ X.noalias() = L.template triangularView() * B; } - static inline void cholesky(const gene_matrix & X, gene_matrix & C, int N){ + static inline void cholesky(const gene_matrix & X, gene_matrix & C, int /*N*/){ C = X; internal::llt_inplace::blocked(C); //C = X.llt().matrixL(); @@ -211,11 +211,11 @@ public : // Cholesky::computeInPlaceBlock(C); } - static inline void lu_decomp(const gene_matrix & X, gene_matrix & C, int N){ + static inline void lu_decomp(const gene_matrix & X, gene_matrix & C, int /*N*/){ C = X.fullPivLu().matrixLU(); } - static inline void partial_lu_decomp(const gene_matrix & X, gene_matrix & C, int N){ + static inline void partial_lu_decomp(const gene_matrix & X, gene_matrix & C, int N){ Matrix piv(N); DenseIndex nb; C = X; @@ -223,13 +223,13 @@ public : // C = X.partialPivLu().matrixLU(); } - static inline void tridiagonalization(const gene_matrix & X, gene_matrix & C, int N){ + static inline void tridiagonalization(const gene_matrix & X, gene_matrix & C, int N){ typename Tridiagonalization::CoeffVectorType aux(N-1); C = X; internal::tridiagonalization_inplace(C, aux); } - static inline void hessenberg(const gene_matrix & X, gene_matrix & C, int N){ + static inline void hessenberg(const gene_matrix & X, gene_matrix & C, int /*N*/){ C = HessenbergDecomposition(X).packedMatrix(); } diff --git a/ground/gcs/src/libs/eigen/bench/btl/libs/eigen3/main_adv.cpp b/ground/gcs/src/libs/eigen/bench/btl/libs/eigen3/main_adv.cpp index efe5857e48..95865357e0 100644 --- a/ground/gcs/src/libs/eigen/bench/btl/libs/eigen3/main_adv.cpp +++ b/ground/gcs/src/libs/eigen/bench/btl/libs/eigen3/main_adv.cpp @@ -29,14 +29,14 @@ BTL_MAIN; int main() { - bench > >(MIN_MM,MAX_MM,NB_POINT); - bench > >(MIN_MM,MAX_MM,NB_POINT); - bench > >(MIN_MM,MAX_MM,NB_POINT); - bench > >(MIN_MM,MAX_MM,NB_POINT); - bench > >(MIN_MM,MAX_MM,NB_POINT); + bench > >(MIN_LU,MAX_LU,NB_POINT); + bench > >(MIN_LU,MAX_LU,NB_POINT); + bench > >(MIN_LU,MAX_LU,NB_POINT); +// bench > >(MIN_LU,MAX_LU,NB_POINT); + bench > >(MIN_LU,MAX_LU,NB_POINT); - bench > >(MIN_MM,MAX_MM,NB_POINT); - bench > >(MIN_MM,MAX_MM,NB_POINT); +// bench > >(MIN_LU,MAX_LU,NB_POINT); + bench > >(MIN_LU,MAX_LU,NB_POINT); return 0; } diff --git a/ground/gcs/src/libs/eigen/bench/btl/libs/tensors/CMakeLists.txt b/ground/gcs/src/libs/eigen/bench/btl/libs/tensors/CMakeLists.txt new file mode 100644 index 0000000000..09d6d8e43e --- /dev/null +++ b/ground/gcs/src/libs/eigen/bench/btl/libs/tensors/CMakeLists.txt @@ -0,0 +1,44 @@ + + +if((NOT TENSOR_INCLUDE_DIR) AND Eigen_SOURCE_DIR) + # unless TENSOR_INCLUDE_DIR is defined, let's use current Eigen version + set(TENSOR_INCLUDE_DIR ${Eigen_SOURCE_DIR}) + set(TENSOR_FOUND TRUE) +else() + find_package(Tensor) +endif() + +if (TENSOR_FOUND) + + include_directories(${TENSOR_INCLUDE_DIR}) + btl_add_bench(btl_tensor_linear main_linear.cpp) + btl_add_bench(btl_tensor_vecmat main_vecmat.cpp) + btl_add_bench(btl_tensor_matmat main_matmat.cpp) + + btl_add_target_property(btl_tensor_linear COMPILE_FLAGS "-fno-exceptions -DBTL_PREFIX=tensor") + btl_add_target_property(btl_tensor_vecmat COMPILE_FLAGS "-fno-exceptions -DBTL_PREFIX=tensor") + btl_add_target_property(btl_tensor_matmat COMPILE_FLAGS "-fno-exceptions -DBTL_PREFIX=tensor") + + option(BTL_BENCH_NOGCCVEC "also bench Eigen explicit vec without GCC's auto vec" OFF) + if(CMAKE_COMPILER_IS_GNUCXX AND BTL_BENCH_NOGCCVEC) + btl_add_bench(btl_tensor_nogccvec_linear main_linear.cpp) + btl_add_bench(btl_tensor_nogccvec_vecmat main_vecmat.cpp) + btl_add_bench(btl_tensor_nogccvec_matmat main_matmat.cpp) + + btl_add_target_property(btl_tensor_nogccvec_linear COMPILE_FLAGS "-fno-exceptions -fno-tree-vectorize -DBTL_PREFIX=tensor_nogccvec") + btl_add_target_property(btl_tensor_nogccvec_vecmat COMPILE_FLAGS "-fno-exceptions -fno-tree-vectorize -DBTL_PREFIX=tensor_nogccvec") + btl_add_target_property(btl_tensor_nogccvec_matmat COMPILE_FLAGS "-fno-exceptions -fno-tree-vectorize -DBTL_PREFIX=tensor_nogccvec") + endif() + + + if(NOT BTL_NOVEC) + btl_add_bench(btl_tensor_novec_linear main_linear.cpp OFF) + btl_add_bench(btl_tensor_novec_vecmat main_vecmat.cpp OFF) + btl_add_bench(btl_tensor_novec_matmat main_matmat.cpp OFF) + btl_add_target_property(btl_tensor_novec_linear COMPILE_FLAGS "-fno-exceptions -DEIGEN_DONT_VECTORIZE -DBTL_PREFIX=tensor_novec") + btl_add_target_property(btl_tensor_novec_vecmat COMPILE_FLAGS "-fno-exceptions -DEIGEN_DONT_VECTORIZE -DBTL_PREFIX=tensor_novec") + btl_add_target_property(btl_tensor_novec_matmat COMPILE_FLAGS "-fno-exceptions -DEIGEN_DONT_VECTORIZE -DBTL_PREFIX=tensor_novec") + + endif(NOT BTL_NOVEC) + +endif (TENSOR_FOUND) diff --git a/ground/gcs/src/libs/eigen/bench/btl/libs/tensors/main_linear.cpp b/ground/gcs/src/libs/eigen/bench/btl/libs/tensors/main_linear.cpp new file mode 100644 index 0000000000..e257f1e72e --- /dev/null +++ b/ground/gcs/src/libs/eigen/bench/btl/libs/tensors/main_linear.cpp @@ -0,0 +1,23 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Benoit Steiner +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "utilities.h" +#include "tensor_interface.hh" +#include "bench.hh" +#include "basic_actions.hh" + +BTL_MAIN; + +int main() +{ + bench > >(MIN_AXPY,MAX_AXPY,NB_POINT); + bench > >(MIN_AXPY,MAX_AXPY,NB_POINT); + + return 0; +} diff --git a/ground/gcs/src/libs/eigen/bench/btl/libs/tensors/main_matmat.cpp b/ground/gcs/src/libs/eigen/bench/btl/libs/tensors/main_matmat.cpp new file mode 100644 index 0000000000..675fcfc6d5 --- /dev/null +++ b/ground/gcs/src/libs/eigen/bench/btl/libs/tensors/main_matmat.cpp @@ -0,0 +1,21 @@ +//===================================================== +// Copyright (C) 2014 Benoit Steiner +//===================================================== +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. +// +#include "utilities.h" +#include "tensor_interface.hh" +#include "bench.hh" +#include "basic_actions.hh" + +BTL_MAIN; + +int main() +{ + bench > >(MIN_MM,MAX_MM,NB_POINT); + + return 0; +} diff --git a/ground/gcs/src/libs/eigen/bench/btl/libs/tensors/main_vecmat.cpp b/ground/gcs/src/libs/eigen/bench/btl/libs/tensors/main_vecmat.cpp new file mode 100644 index 0000000000..1af00c81b4 --- /dev/null +++ b/ground/gcs/src/libs/eigen/bench/btl/libs/tensors/main_vecmat.cpp @@ -0,0 +1,21 @@ +//===================================================== +// Copyright (C) 2014 Benoit Steiner +//===================================================== +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. +// +#include "utilities.h" +#include "tensor_interface.hh" +#include "bench.hh" +#include "basic_actions.hh" + +BTL_MAIN; + +int main() +{ + bench > >(MIN_MV,MAX_MV,NB_POINT); + + return 0; +} diff --git a/ground/gcs/src/libs/eigen/bench/btl/libs/tensors/tensor_interface.hh b/ground/gcs/src/libs/eigen/bench/btl/libs/tensors/tensor_interface.hh new file mode 100644 index 0000000000..97b8e0f0b3 --- /dev/null +++ b/ground/gcs/src/libs/eigen/bench/btl/libs/tensors/tensor_interface.hh @@ -0,0 +1,105 @@ +//===================================================== +// Copyright (C) 2014 Benoit Steiner +//===================================================== +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. +// +#ifndef TENSOR_INTERFACE_HH +#define TENSOR_INTERFACE_HH + +#include +#include +#include "btl.hh" + +using namespace Eigen; + +template +class tensor_interface +{ +public : + typedef real real_type; + typedef typename Eigen::Tensor::Index Index; + + typedef std::vector stl_vector; + typedef std::vector stl_matrix; + + typedef Eigen::Tensor gene_matrix; + typedef Eigen::Tensor gene_vector; + + + static inline std::string name( void ) + { + return EIGEN_MAKESTRING(BTL_PREFIX); + } + + static void free_matrix(gene_matrix & /*A*/, int /*N*/) {} + + static void free_vector(gene_vector & /*B*/) {} + + static BTL_DONT_INLINE void matrix_from_stl(gene_matrix & A, stl_matrix & A_stl){ + A.resize(Eigen::array(A_stl[0].size(), A_stl.size())); + + for (unsigned int j=0; j(i,j)) = A_stl[j][i]; + } + } + } + + static BTL_DONT_INLINE void vector_from_stl(gene_vector & B, stl_vector & B_stl){ + B.resize(B_stl.size()); + + for (unsigned int i=0; i(i,j)); + } + } + } + + static inline void matrix_matrix_product(const gene_matrix & A, const gene_matrix & B, gene_matrix & X, int /*N*/){ + typedef typename Eigen::Tensor::DimensionPair DimPair; + const Eigen::array dims(DimPair(1, 0)); + X/*.noalias()*/ = A.contract(B, dims); + } + + static inline void matrix_vector_product(const gene_matrix & A, const gene_vector & B, gene_vector & X, int /*N*/){ + typedef typename Eigen::Tensor::DimensionPair DimPair; + const Eigen::array dims(DimPair(1, 0)); + X/*.noalias()*/ = A.contract(B, dims); + } + + static inline void axpy(real coef, const gene_vector & X, gene_vector & Y, int /*N*/){ + Y += X.constant(coef) * X; + } + + static inline void axpby(real a, const gene_vector & X, real b, gene_vector & Y, int /*N*/){ + Y = X.constant(a)*X + Y.constant(b)*Y; + } + + static EIGEN_DONT_INLINE void copy_matrix(const gene_matrix & source, gene_matrix & cible, int /*N*/){ + cible = source; + } + + static EIGEN_DONT_INLINE void copy_vector(const gene_vector & source, gene_vector & cible, int /*N*/){ + cible = source; + } +}; + +#endif diff --git a/ground/gcs/src/libs/eigen/bench/dense_solvers.cpp b/ground/gcs/src/libs/eigen/bench/dense_solvers.cpp new file mode 100644 index 0000000000..24343dcd88 --- /dev/null +++ b/ground/gcs/src/libs/eigen/bench/dense_solvers.cpp @@ -0,0 +1,186 @@ +#include +#include "BenchTimer.h" +#include +#include +#include +#include +#include +using namespace Eigen; + +std::map > results; +std::vector labels; +std::vector sizes; + +template +EIGEN_DONT_INLINE +void compute_norm_equation(Solver &solver, const MatrixType &A) { + if(A.rows()!=A.cols()) + solver.compute(A.transpose()*A); + else + solver.compute(A); +} + +template +EIGEN_DONT_INLINE +void compute(Solver &solver, const MatrixType &A) { + solver.compute(A); +} + +template +void bench(int id, int rows, int size = Size) +{ + typedef Matrix Mat; + typedef Matrix MatDyn; + typedef Matrix MatSquare; + Mat A(rows,size); + A.setRandom(); + if(rows==size) + A = A*A.adjoint(); + BenchTimer t_llt, t_ldlt, t_lu, t_fplu, t_qr, t_cpqr, t_cod, t_fpqr, t_jsvd, t_bdcsvd; + + int svd_opt = ComputeThinU|ComputeThinV; + + int tries = 5; + int rep = 1000/size; + if(rep==0) rep = 1; +// rep = rep*rep; + + LLT llt(size); + LDLT ldlt(size); + PartialPivLU lu(size); + FullPivLU fplu(size,size); + HouseholderQR qr(A.rows(),A.cols()); + ColPivHouseholderQR cpqr(A.rows(),A.cols()); + CompleteOrthogonalDecomposition cod(A.rows(),A.cols()); + FullPivHouseholderQR fpqr(A.rows(),A.cols()); + JacobiSVD jsvd(A.rows(),A.cols()); + BDCSVD bdcsvd(A.rows(),A.cols()); + + BENCH(t_llt, tries, rep, compute_norm_equation(llt,A)); + BENCH(t_ldlt, tries, rep, compute_norm_equation(ldlt,A)); + BENCH(t_lu, tries, rep, compute_norm_equation(lu,A)); + if(size<=1000) + BENCH(t_fplu, tries, rep, compute_norm_equation(fplu,A)); + BENCH(t_qr, tries, rep, compute(qr,A)); + BENCH(t_cpqr, tries, rep, compute(cpqr,A)); + BENCH(t_cod, tries, rep, compute(cod,A)); + if(size*rows<=10000000) + BENCH(t_fpqr, tries, rep, compute(fpqr,A)); + if(size<500) // JacobiSVD is really too slow for too large matrices + BENCH(t_jsvd, tries, rep, jsvd.compute(A,svd_opt)); +// if(size*rows<=20000000) + BENCH(t_bdcsvd, tries, rep, bdcsvd.compute(A,svd_opt)); + + results["LLT"][id] = t_llt.best(); + results["LDLT"][id] = t_ldlt.best(); + results["PartialPivLU"][id] = t_lu.best(); + results["FullPivLU"][id] = t_fplu.best(); + results["HouseholderQR"][id] = t_qr.best(); + results["ColPivHouseholderQR"][id] = t_cpqr.best(); + results["CompleteOrthogonalDecomposition"][id] = t_cod.best(); + results["FullPivHouseholderQR"][id] = t_fpqr.best(); + results["JacobiSVD"][id] = t_jsvd.best(); + results["BDCSVD"][id] = t_bdcsvd.best(); +} + + +int main() +{ + labels.push_back("LLT"); + labels.push_back("LDLT"); + labels.push_back("PartialPivLU"); + labels.push_back("FullPivLU"); + labels.push_back("HouseholderQR"); + labels.push_back("ColPivHouseholderQR"); + labels.push_back("CompleteOrthogonalDecomposition"); + labels.push_back("FullPivHouseholderQR"); + labels.push_back("JacobiSVD"); + labels.push_back("BDCSVD"); + + for(int i=0; i(k,sizes[k](0),sizes[k](1)); + } + + cout.width(32); + cout << "solver/size"; + cout << " "; + for(int k=0; k=1e6) cout << "-"; + else cout << r(k); + cout << " "; + } + cout << endl; + } + + // HTML output + cout << "" << endl; + cout << "" << endl; + for(int k=0; k" << sizes[k](0) << "x" << sizes[k](1) << ""; + cout << "" << endl; + for(int i=0; i"; + ArrayXf r = (results[labels[i]]*100000.f).floor()/100.f; + for(int k=0; k=1e6) cout << ""; + else + { + cout << ""; + } + } + cout << "" << endl; + } + cout << "
solver/size
" << labels[i] << "-" << r(k); + if(i>0) + cout << " (x" << numext::round(10.f*results[labels[i]](k)/results["LLT"](k))/10.f << ")"; + if(i<4 && sizes[k](0)!=sizes[k](1)) + cout << " *"; + cout << "
" << endl; + +// cout << "LLT (ms) " << (results["LLT"]*1000.).format(fmt) << "\n"; +// cout << "LDLT (%) " << (results["LDLT"]/results["LLT"]).format(fmt) << "\n"; +// cout << "PartialPivLU (%) " << (results["PartialPivLU"]/results["LLT"]).format(fmt) << "\n"; +// cout << "FullPivLU (%) " << (results["FullPivLU"]/results["LLT"]).format(fmt) << "\n"; +// cout << "HouseholderQR (%) " << (results["HouseholderQR"]/results["LLT"]).format(fmt) << "\n"; +// cout << "ColPivHouseholderQR (%) " << (results["ColPivHouseholderQR"]/results["LLT"]).format(fmt) << "\n"; +// cout << "CompleteOrthogonalDecomposition (%) " << (results["CompleteOrthogonalDecomposition"]/results["LLT"]).format(fmt) << "\n"; +// cout << "FullPivHouseholderQR (%) " << (results["FullPivHouseholderQR"]/results["LLT"]).format(fmt) << "\n"; +// cout << "JacobiSVD (%) " << (results["JacobiSVD"]/results["LLT"]).format(fmt) << "\n"; +// cout << "BDCSVD (%) " << (results["BDCSVD"]/results["LLT"]).format(fmt) << "\n"; +} diff --git a/ground/gcs/src/libs/eigen/bench/eig33.cpp b/ground/gcs/src/libs/eigen/bench/eig33.cpp index 1608b999d0..47947a9bed 100644 --- a/ground/gcs/src/libs/eigen/bench/eig33.cpp +++ b/ground/gcs/src/libs/eigen/bench/eig33.cpp @@ -50,7 +50,7 @@ inline void computeRoots(const Matrix& m, Roots& roots) { typedef typename Matrix::Scalar Scalar; const Scalar s_inv3 = 1.0/3.0; - const Scalar s_sqrt3 = internal::sqrt(Scalar(3.0)); + const Scalar s_sqrt3 = std::sqrt(Scalar(3.0)); // The characteristic equation is x^3 - c2*x^2 + c1*x - c0 = 0. The // eigenvalues are the roots to this equation, all guaranteed to be @@ -73,23 +73,13 @@ inline void computeRoots(const Matrix& m, Roots& roots) q = Scalar(0); // Compute the eigenvalues by solving for the roots of the polynomial. - Scalar rho = internal::sqrt(-a_over_3); - Scalar theta = std::atan2(internal::sqrt(-q),half_b)*s_inv3; - Scalar cos_theta = internal::cos(theta); - Scalar sin_theta = internal::sin(theta); - roots(0) = c2_over_3 + Scalar(2)*rho*cos_theta; - roots(1) = c2_over_3 - rho*(cos_theta + s_sqrt3*sin_theta); - roots(2) = c2_over_3 - rho*(cos_theta - s_sqrt3*sin_theta); - - // Sort in increasing order. - if (roots(0) >= roots(1)) - std::swap(roots(0),roots(1)); - if (roots(1) >= roots(2)) - { - std::swap(roots(1),roots(2)); - if (roots(0) >= roots(1)) - std::swap(roots(0),roots(1)); - } + Scalar rho = std::sqrt(-a_over_3); + Scalar theta = std::atan2(std::sqrt(-q),half_b)*s_inv3; + Scalar cos_theta = std::cos(theta); + Scalar sin_theta = std::sin(theta); + roots(2) = c2_over_3 + Scalar(2)*rho*cos_theta; + roots(0) = c2_over_3 - rho*(cos_theta + s_sqrt3*sin_theta); + roots(1) = c2_over_3 - rho*(cos_theta - s_sqrt3*sin_theta); } template @@ -99,9 +89,12 @@ void eigen33(const Matrix& mat, Matrix& evecs, Vector& evals) // Scale the matrix so its entries are in [-1,1]. The scaling is applied // only when at least one matrix entry has magnitude larger than 1. - Scalar scale = mat.cwiseAbs()/*.template triangularView()*/.maxCoeff(); + Scalar shift = mat.trace()/3; + Matrix scaledMat = mat; + scaledMat.diagonal().array() -= shift; + Scalar scale = scaledMat.cwiseAbs()/*.template triangularView()*/.maxCoeff(); scale = std::max(scale,Scalar(1)); - Matrix scaledMat = mat / scale; + scaledMat/=scale; // Compute the eigenvalues // scaledMat.setZero(); @@ -166,6 +159,7 @@ void eigen33(const Matrix& mat, Matrix& evecs, Vector& evals) // Rescale back to the original size. evals *= scale; + evals.array()+=shift; } int main() @@ -173,24 +167,29 @@ int main() BenchTimer t; int tries = 10; int rep = 400000; - typedef Matrix3f Mat; - typedef Vector3f Vec; + typedef Matrix3d Mat; + typedef Vector3d Vec; Mat A = Mat::Random(3,3); A = A.adjoint() * A; +// Mat Q = A.householderQr().householderQ(); +// A = Q * Vec(2.2424567,2.2424566,7.454353).asDiagonal() * Q.transpose(); SelfAdjointEigenSolver eig(A); BENCH(t, tries, rep, eig.compute(A)); - std::cout << "Eigen: " << t.best() << "s\n"; + std::cout << "Eigen iterative: " << t.best() << "s\n"; + + BENCH(t, tries, rep, eig.computeDirect(A)); + std::cout << "Eigen direct : " << t.best() << "s\n"; Mat evecs; Vec evals; BENCH(t, tries, rep, eigen33(A,evecs,evals)); std::cout << "Direct: " << t.best() << "s\n\n"; - std::cerr << "Eigenvalue/eigenvector diffs:\n"; - std::cerr << (evals - eig.eigenvalues()).transpose() << "\n"; - for(int k=0;k<3;++k) - if(evecs.col(k).dot(eig.eigenvectors().col(k))<0) - evecs.col(k) = -evecs.col(k); - std::cerr << evecs - eig.eigenvectors() << "\n\n"; +// std::cerr << "Eigenvalue/eigenvector diffs:\n"; +// std::cerr << (evals - eig.eigenvalues()).transpose() << "\n"; +// for(int k=0;k<3;++k) +// if(evecs.col(k).dot(eig.eigenvectors().col(k))<0) +// evecs.col(k) = -evecs.col(k); +// std::cerr << evecs - eig.eigenvectors() << "\n\n"; } diff --git a/ground/gcs/src/libs/eigen/bench/perf_monitoring/gemm/changesets.txt b/ground/gcs/src/libs/eigen/bench/perf_monitoring/gemm/changesets.txt new file mode 100644 index 0000000000..af8eb9b8f7 --- /dev/null +++ b/ground/gcs/src/libs/eigen/bench/perf_monitoring/gemm/changesets.txt @@ -0,0 +1,61 @@ +#3.0.1 +#3.1.1 +#3.2.0 +3.2.4 +#5745:37f59e65eb6c +5891:d8652709345d # introduce AVX +#5893:24b4dc92c6d3 # merge +5895:997c2ef9fc8b # introduce FMA +#5904:e1eafd14eaa1 # complex and AVX +5908:f8ee3c721251 # improve packing with ptranspose +#5921:ca808bb456b0 # merge +#5927:8b1001f9e3ac +5937:5a4ca1ad8c53 # New gebp kernel handling up to 3 packets x 4 register-level blocks +#5949:f3488f4e45b2 # merge +#5969:e09031dccfd9 # Disable 3pX4 kernel on Altivec +#5992:4a429f5e0483 # merge +before-evaluators +#6334:f6a45e5b8b7c # Implement evaluator for sparse outer products +#6639:c9121c60b5c7 +#6655:06f163b5221f # Properly detect FMA support on ARM +#6677:700e023044e7 # FMA has been wrongly disabled +#6681:11d31dafb0e3 +#6699:5e6e8e10aad1 # merge default to tensors +#6726:ff2d2388e7b9 # merge default to tensors +#6742:0cbd6195e829 # merge default to tensors +#6747:853d2bafeb8f # Generalized the gebp apis +6765:71584fd55762 # Made the blocking computation aware of the l3 cache; Also optimized the blocking parameters to take into account the number of threads used for a computation +#6781:9cc5a931b2c6 # generalized gemv +#6792:f6e1daab600a # ensured that contractions that can be reduced to a matrix vector product +#6844:039efd86b75c # merge tensor +6845:7333ed40c6ef # change prefetching in gebp +#6856:b5be5e10eb7f # merge index conversion +#6893:c3a64aba7c70 # clean blocking size computation +#6898:6fb31ebe6492 # rotating kernel for ARM +6899:877facace746 # rotating kernel for ARM only +#6904:c250623ae9fa # result_of +6921:915f1b1fc158 # fix prefetching change for ARM +6923:9ff25f6dacc6 # prefetching +6933:52572e60b5d3 # blocking size strategy +6937:c8c042f286b2 # avoid redundant pack_rhs +6981:7e5d6f78da59 # dynamic loop swapping +6984:45f26866c091 # rm dynamic loop swapping, adjust lhs's micro panel height to fully exploit L1 cache +6986:a675d05b6f8f # blocking heuristic: block on the rhs in L1 if the lhs fit in L1. +7013:f875e75f07e5 # organize a little our default cache sizes, and use a saner default L1 outside of x86 (10% faster on Nexus 5) +7015:8aad8f35c955 # Refactor computeProductBlockingSizes to make room for the possibility of using lookup tables +7016:a58d253e8c91 # Polish lookup tables generation +7018:9b27294a8186 # actual_panel_rows computation should always be resilient to parameters not consistent with the known L1 cache size, see comment +7019:c758b1e2c073 # Provide a empirical lookup table for blocking sizes measured on a Nexus 5. Only for float, only for Android on ARM 32bit for now. +7085:627e039fba68 # Bug 986: add support for coefficient-based product with 0 depth. +7098:b6f1db9cf9ec # Bug 992: don't select a 3p GEMM path with non-vectorizable scalar types, this hits unsupported paths in symm/triangular products code +7591:09a8e2186610 # 3.3-alpha1 +7650:b0f3c8f43025 # help clang inlining +#8744:74b789ada92a # Improved the matrix multiplication blocking in the case where mr is not a power of 2 (e.g on Haswell CPUs) +8789:efcb912e4356 # Made the index type a template parameter to evaluateProductBlockingSizes. Use numext::mini and numext::maxi instead of std::min/std::max to compute blocking sizes +8972:81d53c711775 # Don't optimize the processing of the last rows of a matrix matrix product in cases that violate the assumptions made by the optimized code path +8985:d935df21a082 # Remove the rotating kernel. +8988:6c2dc56e73b3 # Bug 256: enable vectorization with unaligned loads/stores. +9148:b8b8c421e36c # Relax mixing-type constraints for binary coefficient-wise operators +9174:d228bc282ac9 # merge +9212:c90098affa7b # Fix performance regression introduced in changeset 8aad8f35c955 +9213:9f1c14e4694b # Fix performance regression in dgemm introduced by changeset 81d53c711775 diff --git a/ground/gcs/src/libs/eigen/bench/perf_monitoring/gemm/gemm.cpp b/ground/gcs/src/libs/eigen/bench/perf_monitoring/gemm/gemm.cpp new file mode 100644 index 0000000000..614bd47373 --- /dev/null +++ b/ground/gcs/src/libs/eigen/bench/perf_monitoring/gemm/gemm.cpp @@ -0,0 +1,67 @@ +#include +#include +#include +#include +#include "../../BenchTimer.h" +using namespace Eigen; + +#ifndef SCALAR +#error SCALAR must be defined +#endif + +typedef SCALAR Scalar; + +typedef Matrix Mat; + +EIGEN_DONT_INLINE +void gemm(const Mat &A, const Mat &B, Mat &C) +{ + C.noalias() += A * B; +} + +EIGEN_DONT_INLINE +double bench(long m, long n, long k) +{ + Mat A(m,k); + Mat B(k,n); + Mat C(m,n); + A.setRandom(); + B.setRandom(); + C.setZero(); + + BenchTimer t; + + double up = 1e8*4/sizeof(Scalar); + double tm0 = 4, tm1 = 10; + if(NumTraits::IsComplex) + { + up /= 4; + tm0 = 2; + tm1 = 4; + } + + double flops = 2. * m * n * k; + long rep = std::max(1., std::min(100., up/flops) ); + long tries = std::max(tm0, std::min(tm1, up/flops) ); + + BENCH(t, tries, rep, gemm(A,B,C)); + + return 1e-9 * rep * flops / t.best(); +} + +int main(int argc, char **argv) +{ + std::vector results; + + std::ifstream settings("gemm_settings.txt"); + long m, n, k; + while(settings >> m >> n >> k) + { + //std::cerr << " Testing " << m << " " << n << " " << k << std::endl; + results.push_back( bench(m, n, k) ); + } + + std::cout << RowVectorXd::Map(results.data(), results.size()); + + return 0; +} diff --git a/ground/gcs/src/libs/eigen/bench/perf_monitoring/gemm/gemm_settings.txt b/ground/gcs/src/libs/eigen/bench/perf_monitoring/gemm/gemm_settings.txt new file mode 100644 index 0000000000..5c43e1c7d1 --- /dev/null +++ b/ground/gcs/src/libs/eigen/bench/perf_monitoring/gemm/gemm_settings.txt @@ -0,0 +1,15 @@ +8 8 8 +9 9 9 +24 24 24 +239 239 239 +240 240 240 +2400 24 24 +24 2400 24 +24 24 2400 +24 2400 2400 +2400 24 2400 +2400 2400 24 +2400 2400 64 +4800 23 160 +23 4800 160 +2400 2400 2400 diff --git a/ground/gcs/src/libs/eigen/bench/perf_monitoring/gemm/lazy_gemm.cpp b/ground/gcs/src/libs/eigen/bench/perf_monitoring/gemm/lazy_gemm.cpp new file mode 100644 index 0000000000..6dc3701552 --- /dev/null +++ b/ground/gcs/src/libs/eigen/bench/perf_monitoring/gemm/lazy_gemm.cpp @@ -0,0 +1,98 @@ +#include +#include +#include +#include +#include "../../BenchTimer.h" +using namespace Eigen; + +#ifndef SCALAR +#error SCALAR must be defined +#endif + +typedef SCALAR Scalar; + +template +EIGEN_DONT_INLINE +void lazy_gemm(const MatA &A, const MatB &B, MatC &C) +{ +// escape((void*)A.data()); +// escape((void*)B.data()); + C.noalias() += A.lazyProduct(B); +// escape((void*)C.data()); +} + +template +EIGEN_DONT_INLINE +double bench() +{ + typedef Matrix MatA; + typedef Matrix MatB; + typedef Matrix MatC; + + MatA A(m,k); + MatB B(k,n); + MatC C(m,n); + A.setRandom(); + B.setRandom(); + C.setZero(); + + BenchTimer t; + + double up = 1e7*4/sizeof(Scalar); + double tm0 = 10, tm1 = 20; + + double flops = 2. * m * n * k; + long rep = std::max(10., std::min(10000., up/flops) ); + long tries = std::max(tm0, std::min(tm1, up/flops) ); + + BENCH(t, tries, rep, lazy_gemm(A,B,C)); + + return 1e-9 * rep * flops / t.best(); +} + +template +double bench_t(int t) +{ + if(t) + return bench(); + else + return bench(); +} + +EIGEN_DONT_INLINE +double bench_mnk(int m, int n, int k, int t) +{ + int id = m*10000 + n*100 + k; + switch(id) { + case 10101 : return bench_t< 1, 1, 1>(t); break; + case 20202 : return bench_t< 2, 2, 2>(t); break; + case 30303 : return bench_t< 3, 3, 3>(t); break; + case 40404 : return bench_t< 4, 4, 4>(t); break; + case 50505 : return bench_t< 5, 5, 5>(t); break; + case 60606 : return bench_t< 6, 6, 6>(t); break; + case 70707 : return bench_t< 7, 7, 7>(t); break; + case 80808 : return bench_t< 8, 8, 8>(t); break; + case 90909 : return bench_t< 9, 9, 9>(t); break; + case 101010 : return bench_t<10,10,10>(t); break; + case 111111 : return bench_t<11,11,11>(t); break; + case 121212 : return bench_t<12,12,12>(t); break; + } + return 0; +} + +int main(int argc, char **argv) +{ + std::vector results; + + std::ifstream settings("lazy_gemm_settings.txt"); + long m, n, k, t; + while(settings >> m >> n >> k >> t) + { + //std::cerr << " Testing " << m << " " << n << " " << k << std::endl; + results.push_back( bench_mnk(m, n, k, t) ); + } + + std::cout << RowVectorXd::Map(results.data(), results.size()); + + return 0; +} diff --git a/ground/gcs/src/libs/eigen/bench/perf_monitoring/gemm/lazy_gemm_settings.txt b/ground/gcs/src/libs/eigen/bench/perf_monitoring/gemm/lazy_gemm_settings.txt new file mode 100644 index 0000000000..407d5d4fad --- /dev/null +++ b/ground/gcs/src/libs/eigen/bench/perf_monitoring/gemm/lazy_gemm_settings.txt @@ -0,0 +1,15 @@ +1 1 1 0 +2 2 2 0 +3 3 3 0 +4 4 4 0 +4 4 4 1 +5 5 5 0 +6 6 6 0 +7 7 7 0 +7 7 7 1 +8 8 8 0 +9 9 9 0 +10 10 10 0 +11 11 11 0 +12 12 12 0 +12 12 12 1 diff --git a/ground/gcs/src/libs/eigen/bench/perf_monitoring/gemm/make_plot.sh b/ground/gcs/src/libs/eigen/bench/perf_monitoring/gemm/make_plot.sh new file mode 100644 index 0000000000..cd3214ac91 --- /dev/null +++ b/ground/gcs/src/libs/eigen/bench/perf_monitoring/gemm/make_plot.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +# base name of the bench +# it reads $1.out +# and generates $1.pdf +WHAT=$1 +bench=$2 + +header="rev " +while read line +do + if [ ! -z '$line' ]; then + header="$header \"$line\"" + fi +done < $bench"_settings.txt" + +echo $header > $WHAT.out.header +cat $WHAT.out >> $WHAT.out.header + + +echo "set title '$WHAT'" > $WHAT.gnuplot +echo "set key autotitle columnhead outside " >> $WHAT.gnuplot +echo "set xtics rotate 1" >> $WHAT.gnuplot + +echo "set term pdf color rounded enhanced fontscale 0.35 size 7in,5in" >> $WHAT.gnuplot +echo set output "'"$WHAT.pdf"'" >> $WHAT.gnuplot + +col=`cat $bench"_settings.txt" | wc -l` +echo "plot for [col=2:$col+1] '$WHAT.out.header' using 0:col:xticlabels(1) with lines" >> $WHAT.gnuplot +echo " " >> $WHAT.gnuplot + +gnuplot -persist < $WHAT.gnuplot + +# generate a png file +# convert -background white -density 120 -rotate 90 -resize 800 +dither -colors 256 -quality 0 $WHAT.ps -background white -flatten .$WHAT.png + +# clean +rm $WHAT.out.header $WHAT.gnuplot \ No newline at end of file diff --git a/ground/gcs/src/libs/eigen/bench/perf_monitoring/gemm/run.sh b/ground/gcs/src/libs/eigen/bench/perf_monitoring/gemm/run.sh new file mode 100644 index 0000000000..9d6ee40bca --- /dev/null +++ b/ground/gcs/src/libs/eigen/bench/perf_monitoring/gemm/run.sh @@ -0,0 +1,156 @@ +#!/bin/bash + +# ./run.sh gemm +# ./run.sh lazy_gemm + +# Examples of environment variables to be set: +# PREFIX="haswell-fma-" +# CXX_FLAGS="-mfma" + +# Options: +# -up : enforce the recomputation of existing data, and keep best results as a merging strategy +# -s : recompute selected changesets only and keep bests + +bench=$1 + +if echo "$*" | grep '\-up' > /dev/null; then + update=true +else + update=false +fi + +if echo "$*" | grep '\-s' > /dev/null; then + selected=true +else + selected=false +fi + +global_args="$*" + +if [ $selected == true ]; then + echo "Recompute selected changesets only and keep bests" +elif [ $update == true ]; then + echo "(Re-)Compute all changesets and keep bests" +else + echo "Skip previously computed changesets" +fi + + + +if [ ! -d "eigen_src" ]; then + hg clone https://bitbucket.org/eigen/eigen eigen_src +else + cd eigen_src + hg pull -u + cd .. +fi + +if [ ! -z '$CXX' ]; then + CXX=g++ +fi + +function make_backup +{ + if [ -f "$1.out" ]; then + mv "$1.out" "$1.backup" + fi +} + +function merge +{ + count1=`echo $1 | wc -w` + count2=`echo $2 | wc -w` + + if [ $count1 == $count2 ]; then + a=( $1 ); b=( $2 ) + res="" + for (( i=0 ; i<$count1 ; i++ )); do + ai=${a[$i]}; bi=${b[$i]} + tmp=`echo "if ($ai > $bi) $ai else $bi " | bc -l` + res="$res $tmp" + done + echo $res + + else + echo $1 + fi +} + +function test_current +{ + rev=$1 + scalar=$2 + name=$3 + + prev="" + if [ -e "$name.backup" ]; then + prev=`grep $rev "$name.backup" | cut -c 14-` + fi + res=$prev + count_rev=`echo $prev | wc -w` + count_ref=`cat $bench"_settings.txt" | wc -l` + if echo "$global_args" | grep "$rev" > /dev/null; then + rev_found=true + else + rev_found=false + fi +# echo $update et $selected et $rev_found because $rev et "$global_args" +# echo $count_rev et $count_ref + if [ $update == true ] || [ $count_rev != $count_ref ] || ([ $selected == true ] && [ $rev_found == true ]); then + if $CXX -O2 -DNDEBUG -march=native $CXX_FLAGS -I eigen_src $bench.cpp -DSCALAR=$scalar -o $name; then + curr=`./$name` + if [ $count_rev == $count_ref ]; then + echo "merge previous $prev" + echo "with new $curr" + else + echo "got $curr" + fi + res=`merge "$curr" "$prev"` +# echo $res + echo "$rev $res" >> $name.out + else + echo "Compilation failed, skip rev $rev" + fi + else + echo "Skip existing results for $rev / $name" + echo "$rev $res" >> $name.out + fi +} + +make_backup $PREFIX"s"$bench +make_backup $PREFIX"d"$bench +make_backup $PREFIX"c"$bench + +cut -f1 -d"#" < changesets.txt | grep -E '[[:alnum:]]' | while read rev +do + if [ ! -z '$rev' ]; then + echo "Testing rev $rev" + cd eigen_src + hg up -C $rev > /dev/null + actual_rev=`hg identify | cut -f1 -d' '` + cd .. + + test_current $actual_rev float $PREFIX"s"$bench + test_current $actual_rev double $PREFIX"d"$bench + test_current $actual_rev "std::complex" $PREFIX"c"$bench + fi + +done + +echo "Float:" +cat $PREFIX"s""$bench.out" +echo " " + +echo "Double:" +cat $PREFIX"d""$bench.out" +echo "" + +echo "Complex:" +cat $PREFIX"c""$bench.out" +echo "" + +./make_plot.sh $PREFIX"s"$bench $bench +./make_plot.sh $PREFIX"d"$bench $bench +./make_plot.sh $PREFIX"c"$bench $bench + + diff --git a/ground/gcs/src/libs/eigen/bench/spbench/CMakeLists.txt b/ground/gcs/src/libs/eigen/bench/spbench/CMakeLists.txt index 6e0e1b1039..8d53f4ae2c 100644 --- a/ground/gcs/src/libs/eigen/bench/spbench/CMakeLists.txt +++ b/ground/gcs/src/libs/eigen/bench/spbench/CMakeLists.txt @@ -29,7 +29,7 @@ if(UMFPACK_FOUND AND BLAS_FOUND) set(UMFPACK_ALL_LIBS ${UMFPACK_LIBRARIES} ${BLAS_LIBRARIES}) endif() -find_package(SuperLU) +find_package(SuperLU 4.0) if(SUPERLU_FOUND AND BLAS_FOUND) add_definitions("-DEIGEN_SUPERLU_SUPPORT") include_directories(${SUPERLU_INCLUDES}) diff --git a/ground/gcs/src/libs/eigen/bench/spbench/spbenchstyle.h b/ground/gcs/src/libs/eigen/bench/spbench/spbenchstyle.h index 17a05ce710..f6a981778c 100644 --- a/ground/gcs/src/libs/eigen/bench/spbench/spbenchstyle.h +++ b/ground/gcs/src/libs/eigen/bench/spbench/spbenchstyle.h @@ -91,4 +91,5 @@ void printBenchStyle(std::ofstream& out) \n\n"; } -#endif \ No newline at end of file + +#endif diff --git a/ground/gcs/src/libs/eigen/bench/tensors/README b/ground/gcs/src/libs/eigen/bench/tensors/README new file mode 100644 index 0000000000..3a5fdbe17e --- /dev/null +++ b/ground/gcs/src/libs/eigen/bench/tensors/README @@ -0,0 +1,21 @@ +The tensor benchmark suite is made of several parts. + +The first part is a generic suite, in which each benchmark comes in 2 flavors: one that runs on CPU, and one that runs on GPU. + +To compile the floating point CPU benchmarks, simply call: +g++ tensor_benchmarks_cpu.cc benchmark_main.cc -I ../../ -std=c++11 -O3 -DNDEBUG -pthread -mavx -o benchmarks_cpu + +To compile the floating point GPU benchmarks, simply call: +nvcc tensor_benchmarks_gpu.cu benchmark_main.cc -I ../../ -std=c++11 -O2 -DNDEBUG -use_fast_math -ftz=true -arch compute_35 -o benchmarks_gpu + +We also provide a version of the generic GPU tensor benchmarks that uses half floats (aka fp16) instead of regular floats. To compile these benchmarks, simply call the command line below. You'll need a recent GPU that supports compute capability 5.3 or higher to run them and nvcc 7.5 or higher to compile the code. +nvcc tensor_benchmarks_fp16_gpu.cu benchmark_main.cc -I ../../ -std=c++11 -O2 -DNDEBUG -use_fast_math -ftz=true -arch compute_53 -o benchmarks_fp16_gpu + +last but not least, we also provide a suite of benchmarks to measure the scalability of the contraction code on CPU. To compile these benchmarks, call +g++ contraction_benchmarks_cpu.cc benchmark_main.cc -I ../../ -std=c++11 -O3 -DNDEBUG -pthread -mavx -o benchmarks_cpu + +To compile the benchmark for SYCL, using ComputeCpp you currently need 2 passes (only for translation units containing device code): +1. The device compilation pass that generates the device code (SYCL kernels and referenced device functions) and glue code needed by the host compiler to reference the device code from host code. +{ComputeCpp_ROOT}/bin/compute++ -I ../../ -I {ComputeCpp_ROOT}/include/ -std=c++11 -mllvm -inline-threshold=1000 -Wno-ignored-attributes -sycl -intelspirmetadata -emit-llvm -no-serial-memop -sycl-compress-name -DBUILD_PLATFORM_SPIR -DNDBUG -O3 -c tensor_benchmarks_sycl.cc +2. The host compilation pass that generates the final host binary. +clang++-3.7 -include tensor_benchmarks_sycl.sycl benchmark_main.cc tensor_benchmarks_sycl.cc -pthread -I ../../ -I {ComputeCpp_ROOT}/include/ -L {ComputeCpp_ROOT}/lib/ -lComputeCpp -lOpenCL -D_GLIBCXX_USE_CXX11_ABI=0 -std=c++11 -o tensor_benchmark_sycl diff --git a/ground/gcs/src/libs/eigen/bench/tensors/benchmark.h b/ground/gcs/src/libs/eigen/bench/tensors/benchmark.h new file mode 100644 index 0000000000..f115b54ad1 --- /dev/null +++ b/ground/gcs/src/libs/eigen/bench/tensors/benchmark.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include + +namespace testing { +class Benchmark { + public: + Benchmark(const char* name, void (*fn)(int)) { + Register(name, fn, NULL); + } + Benchmark(const char* name, void (*fn_range)(int, int)) { + Register(name, NULL, fn_range); + } + Benchmark* Arg(int x); + Benchmark* Range(int lo, int hi); + const char* Name(); + bool ShouldRun(int argc, char* argv[]); + void Run(); + private: + const char* name_; + void (*fn_)(int); + void (*fn_range_)(int, int); + std::vector args_; + void Register(const char* name, void (*fn)(int), void (*fn_range)(int, int)); + void RunRepeatedlyWithArg(int iterations, int arg); + void RunWithArg(int arg); +}; +} // namespace testing +void SetBenchmarkFlopsProcessed(int64_t); +void StopBenchmarkTiming(); +void StartBenchmarkTiming(); +#define BENCHMARK(f) \ + static ::testing::Benchmark* _benchmark_##f __attribute__((unused)) = \ + (new ::testing::Benchmark(#f, f)) diff --git a/ground/gcs/src/libs/eigen/bench/tensors/benchmark_main.cc b/ground/gcs/src/libs/eigen/bench/tensors/benchmark_main.cc new file mode 100644 index 0000000000..1efa0dbad6 --- /dev/null +++ b/ground/gcs/src/libs/eigen/bench/tensors/benchmark_main.cc @@ -0,0 +1,237 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "benchmark.h" +#include +#include +#include +#include +#include +#include +#include +#include + +static int64_t g_flops_processed; +static int64_t g_benchmark_total_time_ns; +static int64_t g_benchmark_start_time_ns; +typedef std::map BenchmarkMap; +typedef BenchmarkMap::iterator BenchmarkMapIt; + +BenchmarkMap& gBenchmarks() { + static BenchmarkMap g_benchmarks; + return g_benchmarks; +} + +static int g_name_column_width = 20; + +static int Round(int n) { + int base = 1; + while (base*10 < n) { + base *= 10; + } + if (n < 2*base) { + return 2*base; + } + if (n < 5*base) { + return 5*base; + } + return 10*base; +} + +#ifdef __APPLE__ + #include + static mach_timebase_info_data_t g_time_info; + static void __attribute__((constructor)) init_info() { + mach_timebase_info(&g_time_info); + } +#endif + +static int64_t NanoTime() { +#if defined(__APPLE__) + uint64_t t = mach_absolute_time(); + return t * g_time_info.numer / g_time_info.denom; +#else + struct timespec t; + t.tv_sec = t.tv_nsec = 0; + clock_gettime(CLOCK_MONOTONIC, &t); + return static_cast(t.tv_sec) * 1000000000LL + t.tv_nsec; +#endif +} + +namespace testing { +Benchmark* Benchmark::Arg(int arg) { + args_.push_back(arg); + return this; +} + +Benchmark* Benchmark::Range(int lo, int hi) { + const int kRangeMultiplier = 8; + if (hi < lo) { + int temp = hi; + hi = lo; + lo = temp; + } + while (lo < hi) { + args_.push_back(lo); + lo *= kRangeMultiplier; + } + // We always run the hi number. + args_.push_back(hi); + return this; +} + +const char* Benchmark::Name() { + return name_; +} +bool Benchmark::ShouldRun(int argc, char* argv[]) { + if (argc == 1) { + return true; // With no arguments, we run all benchmarks. + } + // Otherwise, we interpret each argument as a regular expression and + // see if any of our benchmarks match. + for (int i = 1; i < argc; i++) { + regex_t re; + if (regcomp(&re, argv[i], 0) != 0) { + fprintf(stderr, "couldn't compile \"%s\" as a regular expression!\n", argv[i]); + exit(EXIT_FAILURE); + } + int match = regexec(&re, name_, 0, NULL, 0); + regfree(&re); + if (match != REG_NOMATCH) { + return true; + } + } + return false; +} +void Benchmark::Register(const char* name, void (*fn)(int), void (*fn_range)(int, int)) { + name_ = name; + fn_ = fn; + fn_range_ = fn_range; + if (fn_ == NULL && fn_range_ == NULL) { + fprintf(stderr, "%s: missing function\n", name_); + exit(EXIT_FAILURE); + } + gBenchmarks().insert(std::make_pair(name, this)); +} +void Benchmark::Run() { + if (fn_ != NULL) { + RunWithArg(0); + } else { + if (args_.empty()) { + fprintf(stderr, "%s: no args!\n", name_); + exit(EXIT_FAILURE); + } + for (size_t i = 0; i < args_.size(); ++i) { + RunWithArg(args_[i]); + } + } +} +void Benchmark::RunRepeatedlyWithArg(int iterations, int arg) { + g_flops_processed = 0; + g_benchmark_total_time_ns = 0; + g_benchmark_start_time_ns = NanoTime(); + if (fn_ != NULL) { + fn_(iterations); + } else { + fn_range_(iterations, arg); + } + if (g_benchmark_start_time_ns != 0) { + g_benchmark_total_time_ns += NanoTime() - g_benchmark_start_time_ns; + } +} +void Benchmark::RunWithArg(int arg) { + // run once in case it's expensive + int iterations = 1; + RunRepeatedlyWithArg(iterations, arg); + while (g_benchmark_total_time_ns < 1e9 && iterations < 1e9) { + int last = iterations; + if (g_benchmark_total_time_ns/iterations == 0) { + iterations = 1e9; + } else { + iterations = 1e9 / (g_benchmark_total_time_ns/iterations); + } + iterations = std::max(last + 1, std::min(iterations + iterations/2, 100*last)); + iterations = Round(iterations); + RunRepeatedlyWithArg(iterations, arg); + } + char throughput[100]; + throughput[0] = '\0'; + if (g_benchmark_total_time_ns > 0 && g_flops_processed > 0) { + double mflops_processed = static_cast(g_flops_processed)/1e6; + double seconds = static_cast(g_benchmark_total_time_ns)/1e9; + snprintf(throughput, sizeof(throughput), " %8.2f MFlops/s", mflops_processed/seconds); + } + char full_name[100]; + if (fn_range_ != NULL) { + if (arg >= (1<<20)) { + snprintf(full_name, sizeof(full_name), "%s/%dM", name_, arg/(1<<20)); + } else if (arg >= (1<<10)) { + snprintf(full_name, sizeof(full_name), "%s/%dK", name_, arg/(1<<10)); + } else { + snprintf(full_name, sizeof(full_name), "%s/%d", name_, arg); + } + } else { + snprintf(full_name, sizeof(full_name), "%s", name_); + } + printf("%-*s %10d %10" PRId64 "%s\n", g_name_column_width, full_name, + iterations, g_benchmark_total_time_ns/iterations, throughput); + fflush(stdout); +} +} // namespace testing +void SetBenchmarkFlopsProcessed(int64_t x) { + g_flops_processed = x; +} +void StopBenchmarkTiming() { + if (g_benchmark_start_time_ns != 0) { + g_benchmark_total_time_ns += NanoTime() - g_benchmark_start_time_ns; + } + g_benchmark_start_time_ns = 0; +} +void StartBenchmarkTiming() { + if (g_benchmark_start_time_ns == 0) { + g_benchmark_start_time_ns = NanoTime(); + } +} +int main(int argc, char* argv[]) { + if (gBenchmarks().empty()) { + fprintf(stderr, "No benchmarks registered!\n"); + exit(EXIT_FAILURE); + } + for (BenchmarkMapIt it = gBenchmarks().begin(); it != gBenchmarks().end(); ++it) { + int name_width = static_cast(strlen(it->second->Name())); + g_name_column_width = std::max(g_name_column_width, name_width); + } + bool need_header = true; + for (BenchmarkMapIt it = gBenchmarks().begin(); it != gBenchmarks().end(); ++it) { + ::testing::Benchmark* b = it->second; + if (b->ShouldRun(argc, argv)) { + if (need_header) { + printf("%-*s %10s %10s\n", g_name_column_width, "", "iterations", "ns/op"); + fflush(stdout); + need_header = false; + } + b->Run(); + } + } + if (need_header) { + fprintf(stderr, "No matching benchmarks!\n"); + fprintf(stderr, "Available benchmarks:\n"); + for (BenchmarkMapIt it = gBenchmarks().begin(); it != gBenchmarks().end(); ++it) { + fprintf(stderr, " %s\n", it->second->Name()); + } + exit(EXIT_FAILURE); + } + return 0; +} diff --git a/ground/gcs/src/libs/eigen/bench/tensors/contraction_benchmarks_cpu.cc b/ground/gcs/src/libs/eigen/bench/tensors/contraction_benchmarks_cpu.cc new file mode 100644 index 0000000000..f9e57ad474 --- /dev/null +++ b/ground/gcs/src/libs/eigen/bench/tensors/contraction_benchmarks_cpu.cc @@ -0,0 +1,39 @@ +#define EIGEN_USE_THREADS + +#include + +#include "tensor_benchmarks.h" + +#define CREATE_THREAD_POOL(threads) \ +Eigen::ThreadPool pool(threads); \ +Eigen::ThreadPoolDevice device(&pool, threads); + + +// Contractions for number of threads ranging from 1 to 32 +// Dimensions are Rows, Cols, Depth +#define BM_ContractionCPU(D1, D2, D3) \ + static void BM_##Contraction##_##D1##x##D2##x##D3(int iters, int Threads) { \ + StopBenchmarkTiming(); \ + CREATE_THREAD_POOL(Threads); \ + BenchmarkSuite suite(device, D1, D2, D3); \ + suite.contraction(iters); \ + } \ + BENCHMARK_RANGE(BM_##Contraction##_##D1##x##D2##x##D3, 1, 32); + + +// Vector Matrix and Matrix Vector products +BM_ContractionCPU(1, 2000, 500); +BM_ContractionCPU(2000, 1, 500); + +// Various skinny matrices +BM_ContractionCPU(250, 3, 512); +BM_ContractionCPU(1500, 3, 512); + +BM_ContractionCPU(512, 800, 4); +BM_ContractionCPU(512, 80, 800); +BM_ContractionCPU(512, 80, 13522); +BM_ContractionCPU(1, 80, 13522); + +BM_ContractionCPU(3200, 512, 4); +BM_ContractionCPU(3200, 512, 80); +BM_ContractionCPU(3200, 80, 512); diff --git a/ground/gcs/src/libs/eigen/bench/tensors/tensor_benchmarks.h b/ground/gcs/src/libs/eigen/bench/tensors/tensor_benchmarks.h new file mode 100644 index 0000000000..c2fb3dedef --- /dev/null +++ b/ground/gcs/src/libs/eigen/bench/tensors/tensor_benchmarks.h @@ -0,0 +1,478 @@ +#ifndef THIRD_PARTY_EIGEN3_TENSOR_BENCHMARKS_H_ +#define THIRD_PARTY_EIGEN3_TENSOR_BENCHMARKS_H_ + +typedef int TensorIndex; +#define EIGEN_DEFAULT_DENSE_INDEX_TYPE int + +#include "unsupported/Eigen/CXX11/Tensor" +#include "benchmark.h" + +#define BENCHMARK_RANGE(bench, lo, hi) \ + BENCHMARK(bench)->Range(lo, hi) + +using Eigen::Tensor; +using Eigen::TensorMap; + +// TODO(bsteiner): also templatize on the input type since we have users +// for int8 as well as floats. +template class BenchmarkSuite { + public: + BenchmarkSuite(const Device& device, size_t m, size_t k, size_t n) + : m_(m), k_(k), n_(n), device_(device) { + initialize(); + } + + BenchmarkSuite(const Device& device, size_t m) + : m_(m), k_(m), n_(m), device_(device) { + initialize(); + } + + ~BenchmarkSuite() { + device_.deallocate(a_); + device_.deallocate(b_); + device_.deallocate(c_); + } + + void memcpy(int num_iters) { + eigen_assert(m_ == k_ && k_ == n_); + StartBenchmarkTiming(); + for (int iter = 0; iter < num_iters; ++iter) { + device_.memcpy(c_, a_, m_ * m_ * sizeof(T)); + } + // Record the number of values copied per second + finalizeBenchmark(static_cast(m_) * m_ * num_iters); + } + + void typeCasting(int num_iters) { + eigen_assert(m_ == n_); + Eigen::array sizes; + if (sizeof(T) >= sizeof(int)) { + sizes[0] = m_; + sizes[1] = k_; + } else { + sizes[0] = m_ * sizeof(T) / sizeof(int); + sizes[1] = k_ * sizeof(T) / sizeof(int); + } + const TensorMap, Eigen::Aligned> A((int*)a_, sizes); + TensorMap, Eigen::Aligned> B(b_, sizes); + + StartBenchmarkTiming(); + for (int iter = 0; iter < num_iters; ++iter) { + B.device(device_) = A.template cast(); + } + // Record the number of values copied per second + finalizeBenchmark(static_cast(m_) * k_ * num_iters); + } + + void random(int num_iters) { + eigen_assert(m_ == k_ && k_ == n_); + Eigen::array sizes; + sizes[0] = m_; + sizes[1] = m_; + TensorMap, Eigen::Aligned> C(c_, sizes); + + StartBenchmarkTiming(); + for (int iter = 0; iter < num_iters; ++iter) { + C.device(device_) = C.random(); + } + // Record the number of random numbers generated per second + finalizeBenchmark(static_cast(m_) * m_ * num_iters); + } + + void slicing(int num_iters) { + eigen_assert(m_ == k_ && k_ == n_); + Eigen::array sizes; + sizes[0] = m_; + sizes[1] = m_; + const TensorMap, Eigen::Aligned> A(a_, sizes); + const TensorMap, Eigen::Aligned> B(b_, sizes); + TensorMap, Eigen::Aligned> C(c_, sizes); + + const Eigen::DSizes quarter_sizes(m_/2, m_/2); + const Eigen::DSizes first_quadrant(0, 0); + const Eigen::DSizes second_quadrant(0, m_/2); + const Eigen::DSizes third_quadrant(m_/2, 0); + const Eigen::DSizes fourth_quadrant(m_/2, m_/2); + + StartBenchmarkTiming(); + for (int iter = 0; iter < num_iters; ++iter) { + C.slice(first_quadrant, quarter_sizes).device(device_) = + A.slice(first_quadrant, quarter_sizes); + C.slice(second_quadrant, quarter_sizes).device(device_) = + B.slice(second_quadrant, quarter_sizes); + C.slice(third_quadrant, quarter_sizes).device(device_) = + A.slice(third_quadrant, quarter_sizes); + C.slice(fourth_quadrant, quarter_sizes).device(device_) = + B.slice(fourth_quadrant, quarter_sizes); + } + // Record the number of values copied from the rhs slice to the lhs slice + // each second + finalizeBenchmark(static_cast(m_) * m_ * num_iters); + } + + void rowChip(int num_iters) { + Eigen::array input_size; + input_size[0] = k_; + input_size[1] = n_; + const TensorMap, Eigen::Aligned> B(b_, input_size); + Eigen::array output_size; + output_size[0] = n_; + TensorMap, Eigen::Aligned> C(c_, output_size); + + StartBenchmarkTiming(); + for (int iter = 0; iter < num_iters; ++iter) { + C.device(device_) = B.chip(iter % k_, 0); + } + // Record the number of values copied from the rhs chip to the lhs. + finalizeBenchmark(static_cast(n_) * num_iters); + } + + void colChip(int num_iters) { + Eigen::array input_size; + input_size[0] = k_; + input_size[1] = n_; + const TensorMap, Eigen::Aligned> B(b_, input_size); + Eigen::array output_size; + output_size[0] = n_; + TensorMap, Eigen::Aligned> C(c_, output_size); + + StartBenchmarkTiming(); + for (int iter = 0; iter < num_iters; ++iter) { + C.device(device_) = B.chip(iter % n_, 1); + } + // Record the number of values copied from the rhs chip to the lhs. + finalizeBenchmark(static_cast(n_) * num_iters); + } + + void shuffling(int num_iters) { + eigen_assert(m_ == n_); + Eigen::array size_a; + size_a[0] = m_; + size_a[1] = k_; + const TensorMap, Eigen::Aligned> A(a_, size_a); + Eigen::array size_b; + size_b[0] = k_; + size_b[1] = m_; + TensorMap, Eigen::Aligned> B(b_, size_b); + + Eigen::array shuffle; + shuffle[0] = 1; + shuffle[1] = 0; + + StartBenchmarkTiming(); + for (int iter = 0; iter < num_iters; ++iter) { + B.device(device_) = A.shuffle(shuffle); + } + // Record the number of values shuffled from A and copied to B each second + finalizeBenchmark(static_cast(m_) * k_ * num_iters); + } + + void padding(int num_iters) { + eigen_assert(m_ == k_); + Eigen::array size_a; + size_a[0] = m_; + size_a[1] = k_-3; + const TensorMap, Eigen::Aligned> A(a_, size_a); + Eigen::array size_b; + size_b[0] = k_; + size_b[1] = m_; + TensorMap, Eigen::Aligned> B(b_, size_b); + +#if defined(EIGEN_HAS_INDEX_LIST) + Eigen::IndexPairList, + Eigen::type2indexpair<2, 1> > paddings; +#else + Eigen::array, 2> paddings; + paddings[0] = Eigen::IndexPair(0, 0); + paddings[1] = Eigen::IndexPair(2, 1); +#endif + + StartBenchmarkTiming(); + for (int iter = 0; iter < num_iters; ++iter) { + B.device(device_) = A.pad(paddings); + } + // Record the number of values copied from the padded tensor A each second + finalizeBenchmark(static_cast(m_) * k_ * num_iters); + } + + void striding(int num_iters) { + eigen_assert(m_ == k_); + Eigen::array size_a; + size_a[0] = m_; + size_a[1] = k_; + const TensorMap, Eigen::Aligned> A(a_, size_a); + Eigen::array size_b; + size_b[0] = m_; + size_b[1] = k_/2; + TensorMap, Eigen::Aligned> B(b_, size_b); + +#ifndef EIGEN_HAS_INDEX_LIST + Eigen::array strides; + strides[0] = 1; + strides[1] = 2; +#else + // Take advantage of cxx11 to give the compiler information it can use to + // optimize the code. + Eigen::IndexList, Eigen::type2index<2> > strides; +#endif + + StartBenchmarkTiming(); + for (int iter = 0; iter < num_iters; ++iter) { + B.device(device_) = A.stride(strides); + } + // Record the number of values copied from the padded tensor A each second + finalizeBenchmark(static_cast(m_) * k_ * num_iters); + } + + void broadcasting(int num_iters) { + Eigen::array size_a; + size_a[0] = m_; + size_a[1] = 1; + const TensorMap, Eigen::Aligned> A(a_, size_a); + Eigen::array size_c; + size_c[0] = m_; + size_c[1] = n_; + TensorMap, Eigen::Aligned> C(c_, size_c); + +#ifndef EIGEN_HAS_INDEX_LIST + Eigen::array broadcast; + broadcast[0] = 1; + broadcast[1] = n_; +#else + // Take advantage of cxx11 to give the compiler information it can use to + // optimize the code. + Eigen::IndexList, int> broadcast; + broadcast.set(1, n_); +#endif + + StartBenchmarkTiming(); + for (int iter = 0; iter < num_iters; ++iter) { + C.device(device_) = A.broadcast(broadcast); + } + // Record the number of values broadcasted from A and copied to C each second + finalizeBenchmark(static_cast(m_) * n_ * num_iters); + } + + void coeffWiseOp(int num_iters) { + eigen_assert(m_ == k_ && k_ == n_); + Eigen::array sizes; + sizes[0] = m_; + sizes[1] = m_; + const TensorMap, Eigen::Aligned> A(a_, sizes); + const TensorMap, Eigen::Aligned> B(b_, sizes); + TensorMap, Eigen::Aligned> C(c_, sizes); + + StartBenchmarkTiming(); + for (int iter = 0; iter < num_iters; ++iter) { + C.device(device_) = A * A.constant(static_cast(3.14)) + B * B.constant(static_cast(2.7)); + } + // Record the number of FLOP executed per second (2 multiplications and + // 1 addition per value) + finalizeBenchmark(static_cast(3) * m_ * m_ * num_iters); + } + + void algebraicFunc(int num_iters) { + eigen_assert(m_ == k_ && k_ == n_); + Eigen::array sizes; + sizes[0] = m_; + sizes[1] = m_; + const TensorMap, Eigen::Aligned> A(a_, sizes); + const TensorMap, Eigen::Aligned> B(b_, sizes); + TensorMap, Eigen::Aligned> C(c_, sizes); + + StartBenchmarkTiming(); + for (int iter = 0; iter < num_iters; ++iter) { + C.device(device_) = A.rsqrt() + B.sqrt() * B.square(); + } + // Record the number of FLOP executed per second (assuming one operation + // per value) + finalizeBenchmark(static_cast(m_) * m_ * num_iters); + } + + void transcendentalFunc(int num_iters) { + eigen_assert(m_ == k_ && k_ == n_); + Eigen::array sizes; + sizes[0] = m_; + sizes[1] = m_; + const TensorMap, Eigen::Aligned> A(a_, sizes); + const TensorMap, Eigen::Aligned> B(b_, sizes); + TensorMap, Eigen::Aligned> C(c_, sizes); + + StartBenchmarkTiming(); + for (int iter = 0; iter < num_iters; ++iter) { + C.device(device_) = A.exp() + B.log(); + } + // Record the number of FLOP executed per second (assuming one operation + // per value) + finalizeBenchmark(static_cast(m_) * m_ * num_iters); + } + + // Row reduction + void rowReduction(int num_iters) { + Eigen::array input_size; + input_size[0] = k_; + input_size[1] = n_; + const TensorMap, Eigen::Aligned> B(b_, input_size); + Eigen::array output_size; + output_size[0] = n_; + TensorMap, Eigen::Aligned> C(c_, output_size); + +#ifndef EIGEN_HAS_INDEX_LIST + Eigen::array sum_along_dim; + sum_along_dim[0] = 0; +#else + // Take advantage of cxx11 to give the compiler information it can use to + // optimize the code. + Eigen::IndexList> sum_along_dim; +#endif + + StartBenchmarkTiming(); + for (int iter = 0; iter < num_iters; ++iter) { + C.device(device_) = B.sum(sum_along_dim); + } + // Record the number of FLOP executed per second (assuming one operation + // per value) + finalizeBenchmark(static_cast(k_) * n_ * num_iters); + } + + // Column reduction + void colReduction(int num_iters) { + Eigen::array input_size; + input_size[0] = k_; + input_size[1] = n_; + const TensorMap, Eigen::Aligned> B( + b_, input_size); + Eigen::array output_size; + output_size[0] = k_; + TensorMap, Eigen::Aligned> C( + c_, output_size); + +#ifndef EIGEN_HAS_INDEX_LIST + Eigen::array sum_along_dim; + sum_along_dim[0] = 1; +#else + // Take advantage of cxx11 to give the compiler information it can use to + // optimize the code. + Eigen::IndexList> sum_along_dim; +#endif + + StartBenchmarkTiming(); + for (int iter = 0; iter < num_iters; ++iter) { + C.device(device_) = B.sum(sum_along_dim); + } + // Record the number of FLOP executed per second (assuming one operation + // per value) + finalizeBenchmark(static_cast(k_) * n_ * num_iters); + } + + // Full reduction + void fullReduction(int num_iters) { + Eigen::array input_size; + input_size[0] = k_; + input_size[1] = n_; + const TensorMap, Eigen::Aligned> B( + b_, input_size); + Eigen::array output_size; + TensorMap, Eigen::Aligned> C( + c_, output_size); + + StartBenchmarkTiming(); + for (int iter = 0; iter < num_iters; ++iter) { + C.device(device_) = B.sum(); + } + // Record the number of FLOP executed per second (assuming one operation + // per value) + finalizeBenchmark(static_cast(k_) * n_ * num_iters); + } + + // do a contraction which is equivalent to a matrix multiplication + void contraction(int num_iters) { + Eigen::array sizeA; + sizeA[0] = m_; + sizeA[1] = k_; + Eigen::array sizeB; + sizeB[0] = k_; + sizeB[1] = n_; + Eigen::array sizeC; + sizeC[0] = m_; + sizeC[1] = n_; + + const TensorMap, Eigen::Aligned> A(a_, sizeA); + const TensorMap, Eigen::Aligned> B(b_, sizeB); + TensorMap, Eigen::Aligned> C(c_, sizeC); + + typedef typename Tensor::DimensionPair DimPair; + Eigen::array dims; + dims[0] = DimPair(1, 0); + + StartBenchmarkTiming(); + for (int iter = 0; iter < num_iters; ++iter) { + C.device(device_) = A.contract(B, dims); + } + // Record the number of FLOP executed per second (size_ multiplications and + // additions for each value in the resulting tensor) + finalizeBenchmark(static_cast(2) * m_ * n_ * k_ * num_iters); + } + + void convolution(int num_iters, int kernel_x, int kernel_y) { + Eigen::array input_sizes; + input_sizes[0] = m_; + input_sizes[1] = n_; + TensorMap, Eigen::Aligned> A(a_, input_sizes); + Eigen::array kernel_sizes; + kernel_sizes[0] = kernel_x; + kernel_sizes[1] = kernel_y; + TensorMap, Eigen::Aligned> B(b_, kernel_sizes); + Eigen::array result_sizes; + result_sizes[0] = m_ - kernel_x + 1; + result_sizes[1] = n_ - kernel_y + 1; + TensorMap, Eigen::Aligned> C(c_, result_sizes); + Eigen::array dims; + dims[0] = 0; + dims[1] = 1; + + StartBenchmarkTiming(); + for (int iter = 0; iter < num_iters; ++iter) { + C.device(device_) = A.convolve(B, dims); + } + // Record the number of FLOP executed per second (kernel_size + // multiplications and additions for each value in the resulting tensor) + finalizeBenchmark(static_cast(2) * + (m_ - kernel_x + 1) * (n_ - kernel_y + 1) * kernel_x * kernel_y * num_iters); + } + + private: + void initialize() { + a_ = (T *) device_.allocate(m_ * k_ * sizeof(T)); + b_ = (T *) device_.allocate(k_ * n_ * sizeof(T)); + c_ = (T *) device_.allocate(m_ * n_ * sizeof(T)); + + // Initialize the content of the memory pools to prevent asan from + // complaining. + device_.memset(a_, 12, m_ * k_ * sizeof(T)); + device_.memset(b_, 23, k_ * n_ * sizeof(T)); + device_.memset(c_, 31, m_ * n_ * sizeof(T)); + + //BenchmarkUseRealTime(); + } + + inline void finalizeBenchmark(int64_t num_items) { +#if defined(EIGEN_USE_GPU) && defined(__CUDACC__) + if (Eigen::internal::is_same::value) { + device_.synchronize(); + } +#endif + StopBenchmarkTiming(); + SetBenchmarkFlopsProcessed(num_items); + } + + + TensorIndex m_; + TensorIndex k_; + TensorIndex n_; + T* a_; + T* b_; + T* c_; + Device device_; +}; +#endif // THIRD_PARTY_EIGEN3_TENSOR_BENCHMARKS_H_ diff --git a/ground/gcs/src/libs/eigen/bench/tensors/tensor_benchmarks_cpu.cc b/ground/gcs/src/libs/eigen/bench/tensors/tensor_benchmarks_cpu.cc new file mode 100644 index 0000000000..8947f4b7fc --- /dev/null +++ b/ground/gcs/src/libs/eigen/bench/tensors/tensor_benchmarks_cpu.cc @@ -0,0 +1,168 @@ +#define EIGEN_USE_THREADS + +#include + +#include "tensor_benchmarks.h" + +#define CREATE_THREAD_POOL(threads) \ +Eigen::ThreadPool pool(threads); \ +Eigen::ThreadPoolDevice device(&pool, threads); + +// Simple functions +#define BM_FuncCPU(FUNC, THREADS) \ + static void BM_##FUNC##_##THREADS##T(int iters, int N) { \ + StopBenchmarkTiming(); \ + CREATE_THREAD_POOL(THREADS); \ + BenchmarkSuite suite(device, N); \ + suite.FUNC(iters); \ + } \ + BENCHMARK_RANGE(BM_##FUNC##_##THREADS##T, 10, 5000); + +BM_FuncCPU(memcpy, 4); +BM_FuncCPU(memcpy, 8); +BM_FuncCPU(memcpy, 12); + +BM_FuncCPU(typeCasting, 4); +BM_FuncCPU(typeCasting, 8); +BM_FuncCPU(typeCasting, 12); + +BM_FuncCPU(random, 4); +BM_FuncCPU(random, 8); +BM_FuncCPU(random, 12); + +BM_FuncCPU(slicing, 4); +BM_FuncCPU(slicing, 8); +BM_FuncCPU(slicing, 12); + +BM_FuncCPU(rowChip, 4); +BM_FuncCPU(rowChip, 8); +BM_FuncCPU(rowChip, 12); + +BM_FuncCPU(colChip, 4); +BM_FuncCPU(colChip, 8); +BM_FuncCPU(colChip, 12); + +BM_FuncCPU(shuffling, 4); +BM_FuncCPU(shuffling, 8); +BM_FuncCPU(shuffling, 12); + +BM_FuncCPU(padding, 4); +BM_FuncCPU(padding, 8); +BM_FuncCPU(padding, 12); + +BM_FuncCPU(striding, 4); +BM_FuncCPU(striding, 8); +BM_FuncCPU(striding, 12); + +BM_FuncCPU(broadcasting, 4); +BM_FuncCPU(broadcasting, 8); +BM_FuncCPU(broadcasting, 12); + +BM_FuncCPU(coeffWiseOp, 4); +BM_FuncCPU(coeffWiseOp, 8); +BM_FuncCPU(coeffWiseOp, 12); + +BM_FuncCPU(algebraicFunc, 4); +BM_FuncCPU(algebraicFunc, 8); +BM_FuncCPU(algebraicFunc, 12); + +BM_FuncCPU(transcendentalFunc, 4); +BM_FuncCPU(transcendentalFunc, 8); +BM_FuncCPU(transcendentalFunc, 12); + +BM_FuncCPU(rowReduction, 4); +BM_FuncCPU(rowReduction, 8); +BM_FuncCPU(rowReduction, 12); + +BM_FuncCPU(colReduction, 4); +BM_FuncCPU(colReduction, 8); +BM_FuncCPU(colReduction, 12); + + +// Contractions +#define BM_FuncWithInputDimsCPU(FUNC, D1, D2, D3, THREADS) \ + static void BM_##FUNC##_##D1##x##D2##x##D3##_##THREADS##T(int iters, int N) { \ + StopBenchmarkTiming(); \ + if (THREADS == 1) { \ + Eigen::DefaultDevice device; \ + BenchmarkSuite suite(device, D1, D2, D3); \ + suite.FUNC(iters); \ + } else { \ + CREATE_THREAD_POOL(THREADS); \ + BenchmarkSuite suite(device, D1, D2, D3); \ + suite.FUNC(iters); \ + } \ + } \ + BENCHMARK_RANGE(BM_##FUNC##_##D1##x##D2##x##D3##_##THREADS##T, 10, 5000); + + +BM_FuncWithInputDimsCPU(contraction, N, N, N, 1); +BM_FuncWithInputDimsCPU(contraction, N, N, N, 4); +BM_FuncWithInputDimsCPU(contraction, N, N, N, 8); +BM_FuncWithInputDimsCPU(contraction, N, N, N, 12); +BM_FuncWithInputDimsCPU(contraction, N, N, N, 16); + +BM_FuncWithInputDimsCPU(contraction, 64, N, N, 1); +BM_FuncWithInputDimsCPU(contraction, 64, N, N, 4); +BM_FuncWithInputDimsCPU(contraction, 64, N, N, 8); +BM_FuncWithInputDimsCPU(contraction, 64, N, N, 12); +BM_FuncWithInputDimsCPU(contraction, 64, N, N, 16); + +BM_FuncWithInputDimsCPU(contraction, N, 64, N, 1); +BM_FuncWithInputDimsCPU(contraction, N, 64, N, 4); +BM_FuncWithInputDimsCPU(contraction, N, 64, N, 8); +BM_FuncWithInputDimsCPU(contraction, N, 64, N, 12); +BM_FuncWithInputDimsCPU(contraction, N, 64, N, 16); + +BM_FuncWithInputDimsCPU(contraction, N, N, 64, 1); +BM_FuncWithInputDimsCPU(contraction, N, N, 64, 4); +BM_FuncWithInputDimsCPU(contraction, N, N, 64, 8); +BM_FuncWithInputDimsCPU(contraction, N, N, 64, 12); +BM_FuncWithInputDimsCPU(contraction, N, N, 64, 16); + +BM_FuncWithInputDimsCPU(contraction, 1, N, N, 1); +BM_FuncWithInputDimsCPU(contraction, 1, N, N, 4); +BM_FuncWithInputDimsCPU(contraction, 1, N, N, 8); +BM_FuncWithInputDimsCPU(contraction, 1, N, N, 12); +BM_FuncWithInputDimsCPU(contraction, 1, N, N, 16); + +BM_FuncWithInputDimsCPU(contraction, N, N, 1, 1); +BM_FuncWithInputDimsCPU(contraction, N, N, 1, 4); +BM_FuncWithInputDimsCPU(contraction, N, N, 1, 8); +BM_FuncWithInputDimsCPU(contraction, N, N, 1, 12); +BM_FuncWithInputDimsCPU(contraction, N, N, 1, 16); + + +// Convolutions +#define BM_FuncWithKernelDimsCPU(FUNC, DIM1, DIM2, THREADS) \ + static void BM_##FUNC##_##DIM1##x##DIM2##_##THREADS##T(int iters, int N) { \ + StopBenchmarkTiming(); \ + CREATE_THREAD_POOL(THREADS); \ + BenchmarkSuite suite(device, N); \ + suite.FUNC(iters, DIM1, DIM2); \ + } \ + BENCHMARK_RANGE(BM_##FUNC##_##DIM1##x##DIM2##_##THREADS##T, 128, 5000); + +BM_FuncWithKernelDimsCPU(convolution, 7, 1, 4); +BM_FuncWithKernelDimsCPU(convolution, 7, 1, 8); +BM_FuncWithKernelDimsCPU(convolution, 7, 1, 12); + +BM_FuncWithKernelDimsCPU(convolution, 1, 7, 4); +BM_FuncWithKernelDimsCPU(convolution, 1, 7, 8); +BM_FuncWithKernelDimsCPU(convolution, 1, 7, 12); + +BM_FuncWithKernelDimsCPU(convolution, 7, 4, 4); +BM_FuncWithKernelDimsCPU(convolution, 7, 4, 8); +BM_FuncWithKernelDimsCPU(convolution, 7, 4, 12); + +BM_FuncWithKernelDimsCPU(convolution, 4, 7, 4); +BM_FuncWithKernelDimsCPU(convolution, 4, 7, 8); +BM_FuncWithKernelDimsCPU(convolution, 4, 7, 12); + +BM_FuncWithKernelDimsCPU(convolution, 7, 64, 4); +BM_FuncWithKernelDimsCPU(convolution, 7, 64, 8); +BM_FuncWithKernelDimsCPU(convolution, 7, 64, 12); + +BM_FuncWithKernelDimsCPU(convolution, 64, 7, 4); +BM_FuncWithKernelDimsCPU(convolution, 64, 7, 8); +BM_FuncWithKernelDimsCPU(convolution, 64, 7, 12); diff --git a/ground/gcs/src/libs/eigen/bench/tensors/tensor_benchmarks_fp16_gpu.cu b/ground/gcs/src/libs/eigen/bench/tensors/tensor_benchmarks_fp16_gpu.cu new file mode 100644 index 0000000000..65784d0d67 --- /dev/null +++ b/ground/gcs/src/libs/eigen/bench/tensors/tensor_benchmarks_fp16_gpu.cu @@ -0,0 +1,77 @@ +#define EIGEN_USE_GPU + +#include +#include +#include + +#include "tensor_benchmarks.h" + +// Simple functions +#define BM_FuncGPU(FUNC) \ + static void BM_##FUNC(int iters, int N) { \ + StopBenchmarkTiming(); \ + Eigen::CudaStreamDevice stream; \ + Eigen::GpuDevice device(&stream); \ + BenchmarkSuite suite(device, N); \ + cudaDeviceSynchronize(); \ + suite.FUNC(iters); \ + } \ + BENCHMARK_RANGE(BM_##FUNC, 10, 5000); + +BM_FuncGPU(memcpy); +BM_FuncGPU(typeCasting); +//BM_FuncGPU(random); +BM_FuncGPU(slicing); +BM_FuncGPU(rowChip); +BM_FuncGPU(colChip); +BM_FuncGPU(shuffling); +BM_FuncGPU(padding); +BM_FuncGPU(striding); +BM_FuncGPU(broadcasting); +BM_FuncGPU(coeffWiseOp); +BM_FuncGPU(algebraicFunc); +BM_FuncGPU(transcendentalFunc); +BM_FuncGPU(rowReduction); +BM_FuncGPU(colReduction); +BM_FuncGPU(fullReduction); + + +// Contractions +#define BM_FuncWithInputDimsGPU(FUNC, D1, D2, D3) \ + static void BM_##FUNC##_##D1##x##D2##x##D3(int iters, int N) { \ + StopBenchmarkTiming(); \ + Eigen::CudaStreamDevice stream; \ + Eigen::GpuDevice device(&stream); \ + BenchmarkSuite suite(device, D1, D2, D3); \ + cudaDeviceSynchronize(); \ + suite.FUNC(iters); \ + } \ + BENCHMARK_RANGE(BM_##FUNC##_##D1##x##D2##x##D3, 10, 5000); + + +BM_FuncWithInputDimsGPU(contraction, N, N, N); +BM_FuncWithInputDimsGPU(contraction, 64, N, N); +BM_FuncWithInputDimsGPU(contraction, N, 64, N); +BM_FuncWithInputDimsGPU(contraction, N, N, 64); + + +// Convolutions +#define BM_FuncWithKernelDimsGPU(FUNC, DIM1, DIM2) \ + static void BM_##FUNC##_##DIM1##x##DIM2(int iters, int N) { \ + StopBenchmarkTiming(); \ + Eigen::CudaStreamDevice stream; \ + Eigen::GpuDevice device(&stream); \ + BenchmarkSuite suite(device, N); \ + cudaDeviceSynchronize(); \ + suite.FUNC(iters, DIM1, DIM2); \ + } \ + BENCHMARK_RANGE(BM_##FUNC##_##DIM1##x##DIM2, 128, 5000); + +/* +BM_FuncWithKernelDimsGPU(convolution, 7, 1); +BM_FuncWithKernelDimsGPU(convolution, 1, 7); +BM_FuncWithKernelDimsGPU(convolution, 7, 4); +BM_FuncWithKernelDimsGPU(convolution, 4, 7); +BM_FuncWithKernelDimsGPU(convolution, 7, 64); +BM_FuncWithKernelDimsGPU(convolution, 64, 7); +*/ diff --git a/ground/gcs/src/libs/eigen/bench/tensors/tensor_benchmarks_gpu.cu b/ground/gcs/src/libs/eigen/bench/tensors/tensor_benchmarks_gpu.cu new file mode 100644 index 0000000000..76d68c5c1b --- /dev/null +++ b/ground/gcs/src/libs/eigen/bench/tensors/tensor_benchmarks_gpu.cu @@ -0,0 +1,75 @@ +#define EIGEN_USE_GPU + +#include +#include +#include + +#include "tensor_benchmarks.h" + +// Simple functions +#define BM_FuncGPU(FUNC) \ + static void BM_##FUNC(int iters, int N) { \ + StopBenchmarkTiming(); \ + Eigen::CudaStreamDevice stream; \ + Eigen::GpuDevice device(&stream); \ + BenchmarkSuite suite(device, N); \ + cudaDeviceSynchronize(); \ + suite.FUNC(iters); \ + } \ + BENCHMARK_RANGE(BM_##FUNC, 10, 5000); + +BM_FuncGPU(memcpy); +BM_FuncGPU(typeCasting); +BM_FuncGPU(random); +BM_FuncGPU(slicing); +BM_FuncGPU(rowChip); +BM_FuncGPU(colChip); +BM_FuncGPU(shuffling); +BM_FuncGPU(padding); +BM_FuncGPU(striding); +BM_FuncGPU(broadcasting); +BM_FuncGPU(coeffWiseOp); +BM_FuncGPU(algebraicFunc); +BM_FuncGPU(transcendentalFunc); +BM_FuncGPU(rowReduction); +BM_FuncGPU(colReduction); +BM_FuncGPU(fullReduction); + + +// Contractions +#define BM_FuncWithInputDimsGPU(FUNC, D1, D2, D3) \ + static void BM_##FUNC##_##D1##x##D2##x##D3(int iters, int N) { \ + StopBenchmarkTiming(); \ + Eigen::CudaStreamDevice stream; \ + Eigen::GpuDevice device(&stream); \ + BenchmarkSuite suite(device, D1, D2, D3); \ + cudaDeviceSynchronize(); \ + suite.FUNC(iters); \ + } \ + BENCHMARK_RANGE(BM_##FUNC##_##D1##x##D2##x##D3, 10, 5000); + + +BM_FuncWithInputDimsGPU(contraction, N, N, N); +BM_FuncWithInputDimsGPU(contraction, 64, N, N); +BM_FuncWithInputDimsGPU(contraction, N, 64, N); +BM_FuncWithInputDimsGPU(contraction, N, N, 64); + + +// Convolutions +#define BM_FuncWithKernelDimsGPU(FUNC, DIM1, DIM2) \ + static void BM_##FUNC##_##DIM1##x##DIM2(int iters, int N) { \ + StopBenchmarkTiming(); \ + Eigen::CudaStreamDevice stream; \ + Eigen::GpuDevice device(&stream); \ + BenchmarkSuite suite(device, N); \ + cudaDeviceSynchronize(); \ + suite.FUNC(iters, DIM1, DIM2); \ + } \ + BENCHMARK_RANGE(BM_##FUNC##_##DIM1##x##DIM2, 128, 5000); + +BM_FuncWithKernelDimsGPU(convolution, 7, 1); +BM_FuncWithKernelDimsGPU(convolution, 1, 7); +BM_FuncWithKernelDimsGPU(convolution, 7, 4); +BM_FuncWithKernelDimsGPU(convolution, 4, 7); +BM_FuncWithKernelDimsGPU(convolution, 7, 64); +BM_FuncWithKernelDimsGPU(convolution, 64, 7); diff --git a/ground/gcs/src/libs/eigen/bench/tensors/tensor_benchmarks_sycl.cc b/ground/gcs/src/libs/eigen/bench/tensors/tensor_benchmarks_sycl.cc new file mode 100644 index 0000000000..7eca4d9660 --- /dev/null +++ b/ground/gcs/src/libs/eigen/bench/tensors/tensor_benchmarks_sycl.cc @@ -0,0 +1,37 @@ +#define EIGEN_USE_SYCL + +#include +#include + +#include "tensor_benchmarks.h" + +using Eigen::array; +using Eigen::SyclDevice; +using Eigen::Tensor; +using Eigen::TensorMap; +// Simple functions +template +cl::sycl::queue sycl_queue() { + return cl::sycl::queue(device_selector(), [=](cl::sycl::exception_list l) { + for (const auto& e : l) { + try { + std::rethrow_exception(e); + } catch (cl::sycl::exception e) { + std::cout << e.what() << std::endl; + } + } + }); +} + +#define BM_FuncGPU(FUNC) \ + static void BM_##FUNC(int iters, int N) { \ + StopBenchmarkTiming(); \ + cl::sycl::queue q = sycl_queue(); \ + Eigen::SyclDevice device(q); \ + BenchmarkSuite suite(device, N); \ + suite.FUNC(iters); \ + } \ + BENCHMARK_RANGE(BM_##FUNC, 10, 5000); + +BM_FuncGPU(broadcasting); +BM_FuncGPU(coeffWiseOp); diff --git a/ground/gcs/src/libs/eigen/blas/CMakeLists.txt b/ground/gcs/src/libs/eigen/blas/CMakeLists.txt index a9bc051374..d0efb41885 100644 --- a/ground/gcs/src/libs/eigen/blas/CMakeLists.txt +++ b/ground/gcs/src/libs/eigen/blas/CMakeLists.txt @@ -14,23 +14,18 @@ endif() add_custom_target(blas) -set(EigenBlas_SRCS single.cpp double.cpp complex_single.cpp complex_double.cpp xerbla.cpp) - -if(EIGEN_Fortran_COMPILER_WORKS) - -set(EigenBlas_SRCS ${EigenBlas_SRCS} - complexdots.f - srotm.f srotmg.f drotm.f drotmg.f - lsame.f dspmv.f ssbmv.f - chbmv.f sspmv.f - zhbmv.f chpmv.f dsbmv.f - zhpmv.f - dtbmv.f stbmv.f ctbmv.f ztbmv.f -) +set(EigenBlas_SRCS single.cpp double.cpp complex_single.cpp complex_double.cpp xerbla.cpp + f2c/srotm.c f2c/srotmg.c f2c/drotm.c f2c/drotmg.c + f2c/lsame.c f2c/dspmv.c f2c/ssbmv.c f2c/chbmv.c + f2c/sspmv.c f2c/zhbmv.c f2c/chpmv.c f2c/dsbmv.c + f2c/zhpmv.c f2c/dtbmv.c f2c/stbmv.c f2c/ctbmv.c + f2c/ztbmv.c f2c/d_cnjg.c f2c/r_cnjg.c + ) + +if (EIGEN_Fortran_COMPILER_WORKS) + set(EigenBlas_SRCS ${EigenBlas_SRCS} fortran/complexdots.f) else() - -message(WARNING " No fortran compiler has been detected, the blas build will be incomplete.") - + set(EigenBlas_SRCS ${EigenBlas_SRCS} f2c/complexdots.c) endif() add_library(eigen_blas_static ${EigenBlas_SRCS}) diff --git a/ground/gcs/src/libs/eigen/blas/PackedTriangularMatrixVector.h b/ground/gcs/src/libs/eigen/blas/PackedTriangularMatrixVector.h index e9886d56fb..0039536a86 100644 --- a/ground/gcs/src/libs/eigen/blas/PackedTriangularMatrixVector.h +++ b/ground/gcs/src/libs/eigen/blas/PackedTriangularMatrixVector.h @@ -18,7 +18,7 @@ struct packed_triangular_matrix_vector_product; template struct packed_triangular_matrix_vector_product { - typedef typename scalar_product_traits::ReturnType ResScalar; + typedef typename ScalarBinaryOpTraits::ReturnType ResScalar; enum { IsLower = (Mode & Lower) ==Lower, HasUnitDiag = (Mode & UnitDiag)==UnitDiag, @@ -47,7 +47,7 @@ struct packed_triangular_matrix_vector_product struct packed_triangular_matrix_vector_product { - typedef typename scalar_product_traits::ReturnType ResScalar; + typedef typename ScalarBinaryOpTraits::ReturnType ResScalar; enum { IsLower = (Mode & Lower) ==Lower, HasUnitDiag = (Mode & UnitDiag)==UnitDiag, diff --git a/ground/gcs/src/libs/eigen/blas/chbmv.f b/ground/gcs/src/libs/eigen/blas/chbmv.f deleted file mode 100644 index 1b1c330ea0..0000000000 --- a/ground/gcs/src/libs/eigen/blas/chbmv.f +++ /dev/null @@ -1,310 +0,0 @@ - SUBROUTINE CHBMV(UPLO,N,K,ALPHA,A,LDA,X,INCX,BETA,Y,INCY) -* .. Scalar Arguments .. - COMPLEX ALPHA,BETA - INTEGER INCX,INCY,K,LDA,N - CHARACTER UPLO -* .. -* .. Array Arguments .. - COMPLEX A(LDA,*),X(*),Y(*) -* .. -* -* Purpose -* ======= -* -* CHBMV performs the matrix-vector operation -* -* y := alpha*A*x + beta*y, -* -* where alpha and beta are scalars, x and y are n element vectors and -* A is an n by n hermitian band matrix, with k super-diagonals. -* -* Arguments -* ========== -* -* UPLO - CHARACTER*1. -* On entry, UPLO specifies whether the upper or lower -* triangular part of the band matrix A is being supplied as -* follows: -* -* UPLO = 'U' or 'u' The upper triangular part of A is -* being supplied. -* -* UPLO = 'L' or 'l' The lower triangular part of A is -* being supplied. -* -* Unchanged on exit. -* -* N - INTEGER. -* On entry, N specifies the order of the matrix A. -* N must be at least zero. -* Unchanged on exit. -* -* K - INTEGER. -* On entry, K specifies the number of super-diagonals of the -* matrix A. K must satisfy 0 .le. K. -* Unchanged on exit. -* -* ALPHA - COMPLEX . -* On entry, ALPHA specifies the scalar alpha. -* Unchanged on exit. -* -* A - COMPLEX array of DIMENSION ( LDA, n ). -* Before entry with UPLO = 'U' or 'u', the leading ( k + 1 ) -* by n part of the array A must contain the upper triangular -* band part of the hermitian matrix, supplied column by -* column, with the leading diagonal of the matrix in row -* ( k + 1 ) of the array, the first super-diagonal starting at -* position 2 in row k, and so on. The top left k by k triangle -* of the array A is not referenced. -* The following program segment will transfer the upper -* triangular part of a hermitian band matrix from conventional -* full matrix storage to band storage: -* -* DO 20, J = 1, N -* M = K + 1 - J -* DO 10, I = MAX( 1, J - K ), J -* A( M + I, J ) = matrix( I, J ) -* 10 CONTINUE -* 20 CONTINUE -* -* Before entry with UPLO = 'L' or 'l', the leading ( k + 1 ) -* by n part of the array A must contain the lower triangular -* band part of the hermitian matrix, supplied column by -* column, with the leading diagonal of the matrix in row 1 of -* the array, the first sub-diagonal starting at position 1 in -* row 2, and so on. The bottom right k by k triangle of the -* array A is not referenced. -* The following program segment will transfer the lower -* triangular part of a hermitian band matrix from conventional -* full matrix storage to band storage: -* -* DO 20, J = 1, N -* M = 1 - J -* DO 10, I = J, MIN( N, J + K ) -* A( M + I, J ) = matrix( I, J ) -* 10 CONTINUE -* 20 CONTINUE -* -* Note that the imaginary parts of the diagonal elements need -* not be set and are assumed to be zero. -* Unchanged on exit. -* -* LDA - INTEGER. -* On entry, LDA specifies the first dimension of A as declared -* in the calling (sub) program. LDA must be at least -* ( k + 1 ). -* Unchanged on exit. -* -* X - COMPLEX array of DIMENSION at least -* ( 1 + ( n - 1 )*abs( INCX ) ). -* Before entry, the incremented array X must contain the -* vector x. -* Unchanged on exit. -* -* INCX - INTEGER. -* On entry, INCX specifies the increment for the elements of -* X. INCX must not be zero. -* Unchanged on exit. -* -* BETA - COMPLEX . -* On entry, BETA specifies the scalar beta. -* Unchanged on exit. -* -* Y - COMPLEX array of DIMENSION at least -* ( 1 + ( n - 1 )*abs( INCY ) ). -* Before entry, the incremented array Y must contain the -* vector y. On exit, Y is overwritten by the updated vector y. -* -* INCY - INTEGER. -* On entry, INCY specifies the increment for the elements of -* Y. INCY must not be zero. -* Unchanged on exit. -* -* Further Details -* =============== -* -* Level 2 Blas routine. -* -* -- Written on 22-October-1986. -* Jack Dongarra, Argonne National Lab. -* Jeremy Du Croz, Nag Central Office. -* Sven Hammarling, Nag Central Office. -* Richard Hanson, Sandia National Labs. -* -* ===================================================================== -* -* .. Parameters .. - COMPLEX ONE - PARAMETER (ONE= (1.0E+0,0.0E+0)) - COMPLEX ZERO - PARAMETER (ZERO= (0.0E+0,0.0E+0)) -* .. -* .. Local Scalars .. - COMPLEX TEMP1,TEMP2 - INTEGER I,INFO,IX,IY,J,JX,JY,KPLUS1,KX,KY,L -* .. -* .. External Functions .. - LOGICAL LSAME - EXTERNAL LSAME -* .. -* .. External Subroutines .. - EXTERNAL XERBLA -* .. -* .. Intrinsic Functions .. - INTRINSIC CONJG,MAX,MIN,REAL -* .. -* -* Test the input parameters. -* - INFO = 0 - IF (.NOT.LSAME(UPLO,'U') .AND. .NOT.LSAME(UPLO,'L')) THEN - INFO = 1 - ELSE IF (N.LT.0) THEN - INFO = 2 - ELSE IF (K.LT.0) THEN - INFO = 3 - ELSE IF (LDA.LT. (K+1)) THEN - INFO = 6 - ELSE IF (INCX.EQ.0) THEN - INFO = 8 - ELSE IF (INCY.EQ.0) THEN - INFO = 11 - END IF - IF (INFO.NE.0) THEN - CALL XERBLA('CHBMV ',INFO) - RETURN - END IF -* -* Quick return if possible. -* - IF ((N.EQ.0) .OR. ((ALPHA.EQ.ZERO).AND. (BETA.EQ.ONE))) RETURN -* -* Set up the start points in X and Y. -* - IF (INCX.GT.0) THEN - KX = 1 - ELSE - KX = 1 - (N-1)*INCX - END IF - IF (INCY.GT.0) THEN - KY = 1 - ELSE - KY = 1 - (N-1)*INCY - END IF -* -* Start the operations. In this version the elements of the array A -* are accessed sequentially with one pass through A. -* -* First form y := beta*y. -* - IF (BETA.NE.ONE) THEN - IF (INCY.EQ.1) THEN - IF (BETA.EQ.ZERO) THEN - DO 10 I = 1,N - Y(I) = ZERO - 10 CONTINUE - ELSE - DO 20 I = 1,N - Y(I) = BETA*Y(I) - 20 CONTINUE - END IF - ELSE - IY = KY - IF (BETA.EQ.ZERO) THEN - DO 30 I = 1,N - Y(IY) = ZERO - IY = IY + INCY - 30 CONTINUE - ELSE - DO 40 I = 1,N - Y(IY) = BETA*Y(IY) - IY = IY + INCY - 40 CONTINUE - END IF - END IF - END IF - IF (ALPHA.EQ.ZERO) RETURN - IF (LSAME(UPLO,'U')) THEN -* -* Form y when upper triangle of A is stored. -* - KPLUS1 = K + 1 - IF ((INCX.EQ.1) .AND. (INCY.EQ.1)) THEN - DO 60 J = 1,N - TEMP1 = ALPHA*X(J) - TEMP2 = ZERO - L = KPLUS1 - J - DO 50 I = MAX(1,J-K),J - 1 - Y(I) = Y(I) + TEMP1*A(L+I,J) - TEMP2 = TEMP2 + CONJG(A(L+I,J))*X(I) - 50 CONTINUE - Y(J) = Y(J) + TEMP1*REAL(A(KPLUS1,J)) + ALPHA*TEMP2 - 60 CONTINUE - ELSE - JX = KX - JY = KY - DO 80 J = 1,N - TEMP1 = ALPHA*X(JX) - TEMP2 = ZERO - IX = KX - IY = KY - L = KPLUS1 - J - DO 70 I = MAX(1,J-K),J - 1 - Y(IY) = Y(IY) + TEMP1*A(L+I,J) - TEMP2 = TEMP2 + CONJG(A(L+I,J))*X(IX) - IX = IX + INCX - IY = IY + INCY - 70 CONTINUE - Y(JY) = Y(JY) + TEMP1*REAL(A(KPLUS1,J)) + ALPHA*TEMP2 - JX = JX + INCX - JY = JY + INCY - IF (J.GT.K) THEN - KX = KX + INCX - KY = KY + INCY - END IF - 80 CONTINUE - END IF - ELSE -* -* Form y when lower triangle of A is stored. -* - IF ((INCX.EQ.1) .AND. (INCY.EQ.1)) THEN - DO 100 J = 1,N - TEMP1 = ALPHA*X(J) - TEMP2 = ZERO - Y(J) = Y(J) + TEMP1*REAL(A(1,J)) - L = 1 - J - DO 90 I = J + 1,MIN(N,J+K) - Y(I) = Y(I) + TEMP1*A(L+I,J) - TEMP2 = TEMP2 + CONJG(A(L+I,J))*X(I) - 90 CONTINUE - Y(J) = Y(J) + ALPHA*TEMP2 - 100 CONTINUE - ELSE - JX = KX - JY = KY - DO 120 J = 1,N - TEMP1 = ALPHA*X(JX) - TEMP2 = ZERO - Y(JY) = Y(JY) + TEMP1*REAL(A(1,J)) - L = 1 - J - IX = JX - IY = JY - DO 110 I = J + 1,MIN(N,J+K) - IX = IX + INCX - IY = IY + INCY - Y(IY) = Y(IY) + TEMP1*A(L+I,J) - TEMP2 = TEMP2 + CONJG(A(L+I,J))*X(IX) - 110 CONTINUE - Y(JY) = Y(JY) + ALPHA*TEMP2 - JX = JX + INCX - JY = JY + INCY - 120 CONTINUE - END IF - END IF -* - RETURN -* -* End of CHBMV . -* - END diff --git a/ground/gcs/src/libs/eigen/blas/chpmv.f b/ground/gcs/src/libs/eigen/blas/chpmv.f deleted file mode 100644 index 158be5a7b7..0000000000 --- a/ground/gcs/src/libs/eigen/blas/chpmv.f +++ /dev/null @@ -1,272 +0,0 @@ - SUBROUTINE CHPMV(UPLO,N,ALPHA,AP,X,INCX,BETA,Y,INCY) -* .. Scalar Arguments .. - COMPLEX ALPHA,BETA - INTEGER INCX,INCY,N - CHARACTER UPLO -* .. -* .. Array Arguments .. - COMPLEX AP(*),X(*),Y(*) -* .. -* -* Purpose -* ======= -* -* CHPMV performs the matrix-vector operation -* -* y := alpha*A*x + beta*y, -* -* where alpha and beta are scalars, x and y are n element vectors and -* A is an n by n hermitian matrix, supplied in packed form. -* -* Arguments -* ========== -* -* UPLO - CHARACTER*1. -* On entry, UPLO specifies whether the upper or lower -* triangular part of the matrix A is supplied in the packed -* array AP as follows: -* -* UPLO = 'U' or 'u' The upper triangular part of A is -* supplied in AP. -* -* UPLO = 'L' or 'l' The lower triangular part of A is -* supplied in AP. -* -* Unchanged on exit. -* -* N - INTEGER. -* On entry, N specifies the order of the matrix A. -* N must be at least zero. -* Unchanged on exit. -* -* ALPHA - COMPLEX . -* On entry, ALPHA specifies the scalar alpha. -* Unchanged on exit. -* -* AP - COMPLEX array of DIMENSION at least -* ( ( n*( n + 1 ) )/2 ). -* Before entry with UPLO = 'U' or 'u', the array AP must -* contain the upper triangular part of the hermitian matrix -* packed sequentially, column by column, so that AP( 1 ) -* contains a( 1, 1 ), AP( 2 ) and AP( 3 ) contain a( 1, 2 ) -* and a( 2, 2 ) respectively, and so on. -* Before entry with UPLO = 'L' or 'l', the array AP must -* contain the lower triangular part of the hermitian matrix -* packed sequentially, column by column, so that AP( 1 ) -* contains a( 1, 1 ), AP( 2 ) and AP( 3 ) contain a( 2, 1 ) -* and a( 3, 1 ) respectively, and so on. -* Note that the imaginary parts of the diagonal elements need -* not be set and are assumed to be zero. -* Unchanged on exit. -* -* X - COMPLEX array of dimension at least -* ( 1 + ( n - 1 )*abs( INCX ) ). -* Before entry, the incremented array X must contain the n -* element vector x. -* Unchanged on exit. -* -* INCX - INTEGER. -* On entry, INCX specifies the increment for the elements of -* X. INCX must not be zero. -* Unchanged on exit. -* -* BETA - COMPLEX . -* On entry, BETA specifies the scalar beta. When BETA is -* supplied as zero then Y need not be set on input. -* Unchanged on exit. -* -* Y - COMPLEX array of dimension at least -* ( 1 + ( n - 1 )*abs( INCY ) ). -* Before entry, the incremented array Y must contain the n -* element vector y. On exit, Y is overwritten by the updated -* vector y. -* -* INCY - INTEGER. -* On entry, INCY specifies the increment for the elements of -* Y. INCY must not be zero. -* Unchanged on exit. -* -* Further Details -* =============== -* -* Level 2 Blas routine. -* -* -- Written on 22-October-1986. -* Jack Dongarra, Argonne National Lab. -* Jeremy Du Croz, Nag Central Office. -* Sven Hammarling, Nag Central Office. -* Richard Hanson, Sandia National Labs. -* -* ===================================================================== -* -* .. Parameters .. - COMPLEX ONE - PARAMETER (ONE= (1.0E+0,0.0E+0)) - COMPLEX ZERO - PARAMETER (ZERO= (0.0E+0,0.0E+0)) -* .. -* .. Local Scalars .. - COMPLEX TEMP1,TEMP2 - INTEGER I,INFO,IX,IY,J,JX,JY,K,KK,KX,KY -* .. -* .. External Functions .. - LOGICAL LSAME - EXTERNAL LSAME -* .. -* .. External Subroutines .. - EXTERNAL XERBLA -* .. -* .. Intrinsic Functions .. - INTRINSIC CONJG,REAL -* .. -* -* Test the input parameters. -* - INFO = 0 - IF (.NOT.LSAME(UPLO,'U') .AND. .NOT.LSAME(UPLO,'L')) THEN - INFO = 1 - ELSE IF (N.LT.0) THEN - INFO = 2 - ELSE IF (INCX.EQ.0) THEN - INFO = 6 - ELSE IF (INCY.EQ.0) THEN - INFO = 9 - END IF - IF (INFO.NE.0) THEN - CALL XERBLA('CHPMV ',INFO) - RETURN - END IF -* -* Quick return if possible. -* - IF ((N.EQ.0) .OR. ((ALPHA.EQ.ZERO).AND. (BETA.EQ.ONE))) RETURN -* -* Set up the start points in X and Y. -* - IF (INCX.GT.0) THEN - KX = 1 - ELSE - KX = 1 - (N-1)*INCX - END IF - IF (INCY.GT.0) THEN - KY = 1 - ELSE - KY = 1 - (N-1)*INCY - END IF -* -* Start the operations. In this version the elements of the array AP -* are accessed sequentially with one pass through AP. -* -* First form y := beta*y. -* - IF (BETA.NE.ONE) THEN - IF (INCY.EQ.1) THEN - IF (BETA.EQ.ZERO) THEN - DO 10 I = 1,N - Y(I) = ZERO - 10 CONTINUE - ELSE - DO 20 I = 1,N - Y(I) = BETA*Y(I) - 20 CONTINUE - END IF - ELSE - IY = KY - IF (BETA.EQ.ZERO) THEN - DO 30 I = 1,N - Y(IY) = ZERO - IY = IY + INCY - 30 CONTINUE - ELSE - DO 40 I = 1,N - Y(IY) = BETA*Y(IY) - IY = IY + INCY - 40 CONTINUE - END IF - END IF - END IF - IF (ALPHA.EQ.ZERO) RETURN - KK = 1 - IF (LSAME(UPLO,'U')) THEN -* -* Form y when AP contains the upper triangle. -* - IF ((INCX.EQ.1) .AND. (INCY.EQ.1)) THEN - DO 60 J = 1,N - TEMP1 = ALPHA*X(J) - TEMP2 = ZERO - K = KK - DO 50 I = 1,J - 1 - Y(I) = Y(I) + TEMP1*AP(K) - TEMP2 = TEMP2 + CONJG(AP(K))*X(I) - K = K + 1 - 50 CONTINUE - Y(J) = Y(J) + TEMP1*REAL(AP(KK+J-1)) + ALPHA*TEMP2 - KK = KK + J - 60 CONTINUE - ELSE - JX = KX - JY = KY - DO 80 J = 1,N - TEMP1 = ALPHA*X(JX) - TEMP2 = ZERO - IX = KX - IY = KY - DO 70 K = KK,KK + J - 2 - Y(IY) = Y(IY) + TEMP1*AP(K) - TEMP2 = TEMP2 + CONJG(AP(K))*X(IX) - IX = IX + INCX - IY = IY + INCY - 70 CONTINUE - Y(JY) = Y(JY) + TEMP1*REAL(AP(KK+J-1)) + ALPHA*TEMP2 - JX = JX + INCX - JY = JY + INCY - KK = KK + J - 80 CONTINUE - END IF - ELSE -* -* Form y when AP contains the lower triangle. -* - IF ((INCX.EQ.1) .AND. (INCY.EQ.1)) THEN - DO 100 J = 1,N - TEMP1 = ALPHA*X(J) - TEMP2 = ZERO - Y(J) = Y(J) + TEMP1*REAL(AP(KK)) - K = KK + 1 - DO 90 I = J + 1,N - Y(I) = Y(I) + TEMP1*AP(K) - TEMP2 = TEMP2 + CONJG(AP(K))*X(I) - K = K + 1 - 90 CONTINUE - Y(J) = Y(J) + ALPHA*TEMP2 - KK = KK + (N-J+1) - 100 CONTINUE - ELSE - JX = KX - JY = KY - DO 120 J = 1,N - TEMP1 = ALPHA*X(JX) - TEMP2 = ZERO - Y(JY) = Y(JY) + TEMP1*REAL(AP(KK)) - IX = JX - IY = JY - DO 110 K = KK + 1,KK + N - J - IX = IX + INCX - IY = IY + INCY - Y(IY) = Y(IY) + TEMP1*AP(K) - TEMP2 = TEMP2 + CONJG(AP(K))*X(IX) - 110 CONTINUE - Y(JY) = Y(JY) + ALPHA*TEMP2 - JX = JX + INCX - JY = JY + INCY - KK = KK + (N-J+1) - 120 CONTINUE - END IF - END IF -* - RETURN -* -* End of CHPMV . -* - END diff --git a/ground/gcs/src/libs/eigen/blas/common.h b/ground/gcs/src/libs/eigen/blas/common.h index 2bf642c6b4..61d8344d9a 100644 --- a/ground/gcs/src/libs/eigen/blas/common.h +++ b/ground/gcs/src/libs/eigen/blas/common.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2009-2010 Gael Guennebaud +// Copyright (C) 2009-2015 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -10,18 +10,16 @@ #ifndef EIGEN_BLAS_COMMON_H #define EIGEN_BLAS_COMMON_H -#include -#include +#include "../Eigen/Core" +#include "../Eigen/Jacobi" -#include #include #ifndef SCALAR #error the token SCALAR must be defined to compile this file #endif -#include - +#include "../Eigen/src/misc/blas.h" #define NOTR 0 #define TR 1 @@ -95,6 +93,7 @@ enum typedef Matrix PlainMatrixType; typedef Map, 0, OuterStride<> > MatrixType; +typedef Map, 0, OuterStride<> > ConstMatrixType; typedef Map, 0, InnerStride > StridedVectorType; typedef Map > CompactVectorType; @@ -106,26 +105,45 @@ matrix(T* data, int rows, int cols, int stride) } template -Map, 0, InnerStride > vector(T* data, int size, int incr) +Map, 0, OuterStride<> > +matrix(const T* data, int rows, int cols, int stride) +{ + return Map, 0, OuterStride<> >(data, rows, cols, OuterStride<>(stride)); +} + +template +Map, 0, InnerStride > make_vector(T* data, int size, int incr) { return Map, 0, InnerStride >(data, size, InnerStride(incr)); } template -Map > vector(T* data, int size) +Map, 0, InnerStride > make_vector(const T* data, int size, int incr) +{ + return Map, 0, InnerStride >(data, size, InnerStride(incr)); +} + +template +Map > make_vector(T* data, int size) { return Map >(data, size); } +template +Map > make_vector(const T* data, int size) +{ + return Map >(data, size); +} + template T* get_compact_vector(T* x, int n, int incx) { if(incx==1) return x; - T* ret = new Scalar[n]; - if(incx<0) vector(ret,n) = vector(x,n,-incx).reverse(); - else vector(ret,n) = vector(x,n, incx); + typename Eigen::internal::remove_const::type* ret = new Scalar[n]; + if(incx<0) make_vector(ret,n) = make_vector(x,n,-incx).reverse(); + else make_vector(ret,n) = make_vector(x,n, incx); return ret; } @@ -135,8 +153,8 @@ T* copy_back(T* x_cpy, T* x, int n, int incx) if(x_cpy==x) return 0; - if(incx<0) vector(x,n,-incx).reverse() = vector(x_cpy,n); - else vector(x,n, incx) = vector(x_cpy,n); + if(incx<0) make_vector(x,n,-incx).reverse() = make_vector(x_cpy,n); + else make_vector(x,n, incx) = make_vector(x_cpy,n); return x_cpy; } diff --git a/ground/gcs/src/libs/eigen/blas/ctbmv.f b/ground/gcs/src/libs/eigen/blas/ctbmv.f deleted file mode 100644 index 5a879fa01b..0000000000 --- a/ground/gcs/src/libs/eigen/blas/ctbmv.f +++ /dev/null @@ -1,366 +0,0 @@ - SUBROUTINE CTBMV(UPLO,TRANS,DIAG,N,K,A,LDA,X,INCX) -* .. Scalar Arguments .. - INTEGER INCX,K,LDA,N - CHARACTER DIAG,TRANS,UPLO -* .. -* .. Array Arguments .. - COMPLEX A(LDA,*),X(*) -* .. -* -* Purpose -* ======= -* -* CTBMV performs one of the matrix-vector operations -* -* x := A*x, or x := A'*x, or x := conjg( A' )*x, -* -* where x is an n element vector and A is an n by n unit, or non-unit, -* upper or lower triangular band matrix, with ( k + 1 ) diagonals. -* -* Arguments -* ========== -* -* UPLO - CHARACTER*1. -* On entry, UPLO specifies whether the matrix is an upper or -* lower triangular matrix as follows: -* -* UPLO = 'U' or 'u' A is an upper triangular matrix. -* -* UPLO = 'L' or 'l' A is a lower triangular matrix. -* -* Unchanged on exit. -* -* TRANS - CHARACTER*1. -* On entry, TRANS specifies the operation to be performed as -* follows: -* -* TRANS = 'N' or 'n' x := A*x. -* -* TRANS = 'T' or 't' x := A'*x. -* -* TRANS = 'C' or 'c' x := conjg( A' )*x. -* -* Unchanged on exit. -* -* DIAG - CHARACTER*1. -* On entry, DIAG specifies whether or not A is unit -* triangular as follows: -* -* DIAG = 'U' or 'u' A is assumed to be unit triangular. -* -* DIAG = 'N' or 'n' A is not assumed to be unit -* triangular. -* -* Unchanged on exit. -* -* N - INTEGER. -* On entry, N specifies the order of the matrix A. -* N must be at least zero. -* Unchanged on exit. -* -* K - INTEGER. -* On entry with UPLO = 'U' or 'u', K specifies the number of -* super-diagonals of the matrix A. -* On entry with UPLO = 'L' or 'l', K specifies the number of -* sub-diagonals of the matrix A. -* K must satisfy 0 .le. K. -* Unchanged on exit. -* -* A - COMPLEX array of DIMENSION ( LDA, n ). -* Before entry with UPLO = 'U' or 'u', the leading ( k + 1 ) -* by n part of the array A must contain the upper triangular -* band part of the matrix of coefficients, supplied column by -* column, with the leading diagonal of the matrix in row -* ( k + 1 ) of the array, the first super-diagonal starting at -* position 2 in row k, and so on. The top left k by k triangle -* of the array A is not referenced. -* The following program segment will transfer an upper -* triangular band matrix from conventional full matrix storage -* to band storage: -* -* DO 20, J = 1, N -* M = K + 1 - J -* DO 10, I = MAX( 1, J - K ), J -* A( M + I, J ) = matrix( I, J ) -* 10 CONTINUE -* 20 CONTINUE -* -* Before entry with UPLO = 'L' or 'l', the leading ( k + 1 ) -* by n part of the array A must contain the lower triangular -* band part of the matrix of coefficients, supplied column by -* column, with the leading diagonal of the matrix in row 1 of -* the array, the first sub-diagonal starting at position 1 in -* row 2, and so on. The bottom right k by k triangle of the -* array A is not referenced. -* The following program segment will transfer a lower -* triangular band matrix from conventional full matrix storage -* to band storage: -* -* DO 20, J = 1, N -* M = 1 - J -* DO 10, I = J, MIN( N, J + K ) -* A( M + I, J ) = matrix( I, J ) -* 10 CONTINUE -* 20 CONTINUE -* -* Note that when DIAG = 'U' or 'u' the elements of the array A -* corresponding to the diagonal elements of the matrix are not -* referenced, but are assumed to be unity. -* Unchanged on exit. -* -* LDA - INTEGER. -* On entry, LDA specifies the first dimension of A as declared -* in the calling (sub) program. LDA must be at least -* ( k + 1 ). -* Unchanged on exit. -* -* X - COMPLEX array of dimension at least -* ( 1 + ( n - 1 )*abs( INCX ) ). -* Before entry, the incremented array X must contain the n -* element vector x. On exit, X is overwritten with the -* tranformed vector x. -* -* INCX - INTEGER. -* On entry, INCX specifies the increment for the elements of -* X. INCX must not be zero. -* Unchanged on exit. -* -* Further Details -* =============== -* -* Level 2 Blas routine. -* -* -- Written on 22-October-1986. -* Jack Dongarra, Argonne National Lab. -* Jeremy Du Croz, Nag Central Office. -* Sven Hammarling, Nag Central Office. -* Richard Hanson, Sandia National Labs. -* -* ===================================================================== -* -* .. Parameters .. - COMPLEX ZERO - PARAMETER (ZERO= (0.0E+0,0.0E+0)) -* .. -* .. Local Scalars .. - COMPLEX TEMP - INTEGER I,INFO,IX,J,JX,KPLUS1,KX,L - LOGICAL NOCONJ,NOUNIT -* .. -* .. External Functions .. - LOGICAL LSAME - EXTERNAL LSAME -* .. -* .. External Subroutines .. - EXTERNAL XERBLA -* .. -* .. Intrinsic Functions .. - INTRINSIC CONJG,MAX,MIN -* .. -* -* Test the input parameters. -* - INFO = 0 - IF (.NOT.LSAME(UPLO,'U') .AND. .NOT.LSAME(UPLO,'L')) THEN - INFO = 1 - ELSE IF (.NOT.LSAME(TRANS,'N') .AND. .NOT.LSAME(TRANS,'T') .AND. - + .NOT.LSAME(TRANS,'C')) THEN - INFO = 2 - ELSE IF (.NOT.LSAME(DIAG,'U') .AND. .NOT.LSAME(DIAG,'N')) THEN - INFO = 3 - ELSE IF (N.LT.0) THEN - INFO = 4 - ELSE IF (K.LT.0) THEN - INFO = 5 - ELSE IF (LDA.LT. (K+1)) THEN - INFO = 7 - ELSE IF (INCX.EQ.0) THEN - INFO = 9 - END IF - IF (INFO.NE.0) THEN - CALL XERBLA('CTBMV ',INFO) - RETURN - END IF -* -* Quick return if possible. -* - IF (N.EQ.0) RETURN -* - NOCONJ = LSAME(TRANS,'T') - NOUNIT = LSAME(DIAG,'N') -* -* Set up the start point in X if the increment is not unity. This -* will be ( N - 1 )*INCX too small for descending loops. -* - IF (INCX.LE.0) THEN - KX = 1 - (N-1)*INCX - ELSE IF (INCX.NE.1) THEN - KX = 1 - END IF -* -* Start the operations. In this version the elements of A are -* accessed sequentially with one pass through A. -* - IF (LSAME(TRANS,'N')) THEN -* -* Form x := A*x. -* - IF (LSAME(UPLO,'U')) THEN - KPLUS1 = K + 1 - IF (INCX.EQ.1) THEN - DO 20 J = 1,N - IF (X(J).NE.ZERO) THEN - TEMP = X(J) - L = KPLUS1 - J - DO 10 I = MAX(1,J-K),J - 1 - X(I) = X(I) + TEMP*A(L+I,J) - 10 CONTINUE - IF (NOUNIT) X(J) = X(J)*A(KPLUS1,J) - END IF - 20 CONTINUE - ELSE - JX = KX - DO 40 J = 1,N - IF (X(JX).NE.ZERO) THEN - TEMP = X(JX) - IX = KX - L = KPLUS1 - J - DO 30 I = MAX(1,J-K),J - 1 - X(IX) = X(IX) + TEMP*A(L+I,J) - IX = IX + INCX - 30 CONTINUE - IF (NOUNIT) X(JX) = X(JX)*A(KPLUS1,J) - END IF - JX = JX + INCX - IF (J.GT.K) KX = KX + INCX - 40 CONTINUE - END IF - ELSE - IF (INCX.EQ.1) THEN - DO 60 J = N,1,-1 - IF (X(J).NE.ZERO) THEN - TEMP = X(J) - L = 1 - J - DO 50 I = MIN(N,J+K),J + 1,-1 - X(I) = X(I) + TEMP*A(L+I,J) - 50 CONTINUE - IF (NOUNIT) X(J) = X(J)*A(1,J) - END IF - 60 CONTINUE - ELSE - KX = KX + (N-1)*INCX - JX = KX - DO 80 J = N,1,-1 - IF (X(JX).NE.ZERO) THEN - TEMP = X(JX) - IX = KX - L = 1 - J - DO 70 I = MIN(N,J+K),J + 1,-1 - X(IX) = X(IX) + TEMP*A(L+I,J) - IX = IX - INCX - 70 CONTINUE - IF (NOUNIT) X(JX) = X(JX)*A(1,J) - END IF - JX = JX - INCX - IF ((N-J).GE.K) KX = KX - INCX - 80 CONTINUE - END IF - END IF - ELSE -* -* Form x := A'*x or x := conjg( A' )*x. -* - IF (LSAME(UPLO,'U')) THEN - KPLUS1 = K + 1 - IF (INCX.EQ.1) THEN - DO 110 J = N,1,-1 - TEMP = X(J) - L = KPLUS1 - J - IF (NOCONJ) THEN - IF (NOUNIT) TEMP = TEMP*A(KPLUS1,J) - DO 90 I = J - 1,MAX(1,J-K),-1 - TEMP = TEMP + A(L+I,J)*X(I) - 90 CONTINUE - ELSE - IF (NOUNIT) TEMP = TEMP*CONJG(A(KPLUS1,J)) - DO 100 I = J - 1,MAX(1,J-K),-1 - TEMP = TEMP + CONJG(A(L+I,J))*X(I) - 100 CONTINUE - END IF - X(J) = TEMP - 110 CONTINUE - ELSE - KX = KX + (N-1)*INCX - JX = KX - DO 140 J = N,1,-1 - TEMP = X(JX) - KX = KX - INCX - IX = KX - L = KPLUS1 - J - IF (NOCONJ) THEN - IF (NOUNIT) TEMP = TEMP*A(KPLUS1,J) - DO 120 I = J - 1,MAX(1,J-K),-1 - TEMP = TEMP + A(L+I,J)*X(IX) - IX = IX - INCX - 120 CONTINUE - ELSE - IF (NOUNIT) TEMP = TEMP*CONJG(A(KPLUS1,J)) - DO 130 I = J - 1,MAX(1,J-K),-1 - TEMP = TEMP + CONJG(A(L+I,J))*X(IX) - IX = IX - INCX - 130 CONTINUE - END IF - X(JX) = TEMP - JX = JX - INCX - 140 CONTINUE - END IF - ELSE - IF (INCX.EQ.1) THEN - DO 170 J = 1,N - TEMP = X(J) - L = 1 - J - IF (NOCONJ) THEN - IF (NOUNIT) TEMP = TEMP*A(1,J) - DO 150 I = J + 1,MIN(N,J+K) - TEMP = TEMP + A(L+I,J)*X(I) - 150 CONTINUE - ELSE - IF (NOUNIT) TEMP = TEMP*CONJG(A(1,J)) - DO 160 I = J + 1,MIN(N,J+K) - TEMP = TEMP + CONJG(A(L+I,J))*X(I) - 160 CONTINUE - END IF - X(J) = TEMP - 170 CONTINUE - ELSE - JX = KX - DO 200 J = 1,N - TEMP = X(JX) - KX = KX + INCX - IX = KX - L = 1 - J - IF (NOCONJ) THEN - IF (NOUNIT) TEMP = TEMP*A(1,J) - DO 180 I = J + 1,MIN(N,J+K) - TEMP = TEMP + A(L+I,J)*X(IX) - IX = IX + INCX - 180 CONTINUE - ELSE - IF (NOUNIT) TEMP = TEMP*CONJG(A(1,J)) - DO 190 I = J + 1,MIN(N,J+K) - TEMP = TEMP + CONJG(A(L+I,J))*X(IX) - IX = IX + INCX - 190 CONTINUE - END IF - X(JX) = TEMP - JX = JX + INCX - 200 CONTINUE - END IF - END IF - END IF -* - RETURN -* -* End of CTBMV . -* - END diff --git a/ground/gcs/src/libs/eigen/blas/double.cpp b/ground/gcs/src/libs/eigen/blas/double.cpp index 8fd0709ba8..295b1d1f2a 100644 --- a/ground/gcs/src/libs/eigen/blas/double.cpp +++ b/ground/gcs/src/libs/eigen/blas/double.cpp @@ -23,11 +23,10 @@ double BLASFUNC(dsdot)(int* n, float* x, int* incx, float* y, int* incy) { if(*n<=0) return 0; - if(*incx==1 && *incy==1) return (vector(x,*n).cast().cwiseProduct(vector(y,*n).cast())).sum(); - else if(*incx>0 && *incy>0) return (vector(x,*n,*incx).cast().cwiseProduct(vector(y,*n,*incy).cast())).sum(); - else if(*incx<0 && *incy>0) return (vector(x,*n,-*incx).reverse().cast().cwiseProduct(vector(y,*n,*incy).cast())).sum(); - else if(*incx>0 && *incy<0) return (vector(x,*n,*incx).cast().cwiseProduct(vector(y,*n,-*incy).reverse().cast())).sum(); - else if(*incx<0 && *incy<0) return (vector(x,*n,-*incx).reverse().cast().cwiseProduct(vector(y,*n,-*incy).reverse().cast())).sum(); + if(*incx==1 && *incy==1) return (make_vector(x,*n).cast().cwiseProduct(make_vector(y,*n).cast())).sum(); + else if(*incx>0 && *incy>0) return (make_vector(x,*n,*incx).cast().cwiseProduct(make_vector(y,*n,*incy).cast())).sum(); + else if(*incx<0 && *incy>0) return (make_vector(x,*n,-*incx).reverse().cast().cwiseProduct(make_vector(y,*n,*incy).cast())).sum(); + else if(*incx>0 && *incy<0) return (make_vector(x,*n,*incx).cast().cwiseProduct(make_vector(y,*n,-*incy).reverse().cast())).sum(); + else if(*incx<0 && *incy<0) return (make_vector(x,*n,-*incx).reverse().cast().cwiseProduct(make_vector(y,*n,-*incy).reverse().cast())).sum(); else return 0; } - diff --git a/ground/gcs/src/libs/eigen/blas/drotm.f b/ground/gcs/src/libs/eigen/blas/drotm.f deleted file mode 100644 index 63a3b1134f..0000000000 --- a/ground/gcs/src/libs/eigen/blas/drotm.f +++ /dev/null @@ -1,147 +0,0 @@ - SUBROUTINE DROTM(N,DX,INCX,DY,INCY,DPARAM) -* .. Scalar Arguments .. - INTEGER INCX,INCY,N -* .. -* .. Array Arguments .. - DOUBLE PRECISION DPARAM(5),DX(*),DY(*) -* .. -* -* Purpose -* ======= -* -* APPLY THE MODIFIED GIVENS TRANSFORMATION, H, TO THE 2 BY N MATRIX -* -* (DX**T) , WHERE **T INDICATES TRANSPOSE. THE ELEMENTS OF DX ARE IN -* (DY**T) -* -* DX(LX+I*INCX), I = 0 TO N-1, WHERE LX = 1 IF INCX .GE. 0, ELSE -* LX = (-INCX)*N, AND SIMILARLY FOR SY USING LY AND INCY. -* WITH DPARAM(1)=DFLAG, H HAS ONE OF THE FOLLOWING FORMS.. -* -* DFLAG=-1.D0 DFLAG=0.D0 DFLAG=1.D0 DFLAG=-2.D0 -* -* (DH11 DH12) (1.D0 DH12) (DH11 1.D0) (1.D0 0.D0) -* H=( ) ( ) ( ) ( ) -* (DH21 DH22), (DH21 1.D0), (-1.D0 DH22), (0.D0 1.D0). -* SEE DROTMG FOR A DESCRIPTION OF DATA STORAGE IN DPARAM. -* -* Arguments -* ========= -* -* N (input) INTEGER -* number of elements in input vector(s) -* -* DX (input/output) DOUBLE PRECISION array, dimension N -* double precision vector with N elements -* -* INCX (input) INTEGER -* storage spacing between elements of DX -* -* DY (input/output) DOUBLE PRECISION array, dimension N -* double precision vector with N elements -* -* INCY (input) INTEGER -* storage spacing between elements of DY -* -* DPARAM (input/output) DOUBLE PRECISION array, dimension 5 -* DPARAM(1)=DFLAG -* DPARAM(2)=DH11 -* DPARAM(3)=DH21 -* DPARAM(4)=DH12 -* DPARAM(5)=DH22 -* -* ===================================================================== -* -* .. Local Scalars .. - DOUBLE PRECISION DFLAG,DH11,DH12,DH21,DH22,TWO,W,Z,ZERO - INTEGER I,KX,KY,NSTEPS -* .. -* .. Data statements .. - DATA ZERO,TWO/0.D0,2.D0/ -* .. -* - DFLAG = DPARAM(1) - IF (N.LE.0 .OR. (DFLAG+TWO.EQ.ZERO)) GO TO 140 - IF (.NOT. (INCX.EQ.INCY.AND.INCX.GT.0)) GO TO 70 -* - NSTEPS = N*INCX - IF (DFLAG) 50,10,30 - 10 CONTINUE - DH12 = DPARAM(4) - DH21 = DPARAM(3) - DO 20 I = 1,NSTEPS,INCX - W = DX(I) - Z = DY(I) - DX(I) = W + Z*DH12 - DY(I) = W*DH21 + Z - 20 CONTINUE - GO TO 140 - 30 CONTINUE - DH11 = DPARAM(2) - DH22 = DPARAM(5) - DO 40 I = 1,NSTEPS,INCX - W = DX(I) - Z = DY(I) - DX(I) = W*DH11 + Z - DY(I) = -W + DH22*Z - 40 CONTINUE - GO TO 140 - 50 CONTINUE - DH11 = DPARAM(2) - DH12 = DPARAM(4) - DH21 = DPARAM(3) - DH22 = DPARAM(5) - DO 60 I = 1,NSTEPS,INCX - W = DX(I) - Z = DY(I) - DX(I) = W*DH11 + Z*DH12 - DY(I) = W*DH21 + Z*DH22 - 60 CONTINUE - GO TO 140 - 70 CONTINUE - KX = 1 - KY = 1 - IF (INCX.LT.0) KX = 1 + (1-N)*INCX - IF (INCY.LT.0) KY = 1 + (1-N)*INCY -* - IF (DFLAG) 120,80,100 - 80 CONTINUE - DH12 = DPARAM(4) - DH21 = DPARAM(3) - DO 90 I = 1,N - W = DX(KX) - Z = DY(KY) - DX(KX) = W + Z*DH12 - DY(KY) = W*DH21 + Z - KX = KX + INCX - KY = KY + INCY - 90 CONTINUE - GO TO 140 - 100 CONTINUE - DH11 = DPARAM(2) - DH22 = DPARAM(5) - DO 110 I = 1,N - W = DX(KX) - Z = DY(KY) - DX(KX) = W*DH11 + Z - DY(KY) = -W + DH22*Z - KX = KX + INCX - KY = KY + INCY - 110 CONTINUE - GO TO 140 - 120 CONTINUE - DH11 = DPARAM(2) - DH12 = DPARAM(4) - DH21 = DPARAM(3) - DH22 = DPARAM(5) - DO 130 I = 1,N - W = DX(KX) - Z = DY(KY) - DX(KX) = W*DH11 + Z*DH12 - DY(KY) = W*DH21 + Z*DH22 - KX = KX + INCX - KY = KY + INCY - 130 CONTINUE - 140 CONTINUE - RETURN - END diff --git a/ground/gcs/src/libs/eigen/blas/drotmg.f b/ground/gcs/src/libs/eigen/blas/drotmg.f deleted file mode 100644 index 3ae647b087..0000000000 --- a/ground/gcs/src/libs/eigen/blas/drotmg.f +++ /dev/null @@ -1,206 +0,0 @@ - SUBROUTINE DROTMG(DD1,DD2,DX1,DY1,DPARAM) -* .. Scalar Arguments .. - DOUBLE PRECISION DD1,DD2,DX1,DY1 -* .. -* .. Array Arguments .. - DOUBLE PRECISION DPARAM(5) -* .. -* -* Purpose -* ======= -* -* CONSTRUCT THE MODIFIED GIVENS TRANSFORMATION MATRIX H WHICH ZEROS -* THE SECOND COMPONENT OF THE 2-VECTOR (DSQRT(DD1)*DX1,DSQRT(DD2)* -* DY2)**T. -* WITH DPARAM(1)=DFLAG, H HAS ONE OF THE FOLLOWING FORMS.. -* -* DFLAG=-1.D0 DFLAG=0.D0 DFLAG=1.D0 DFLAG=-2.D0 -* -* (DH11 DH12) (1.D0 DH12) (DH11 1.D0) (1.D0 0.D0) -* H=( ) ( ) ( ) ( ) -* (DH21 DH22), (DH21 1.D0), (-1.D0 DH22), (0.D0 1.D0). -* LOCATIONS 2-4 OF DPARAM CONTAIN DH11, DH21, DH12, AND DH22 -* RESPECTIVELY. (VALUES OF 1.D0, -1.D0, OR 0.D0 IMPLIED BY THE -* VALUE OF DPARAM(1) ARE NOT STORED IN DPARAM.) -* -* THE VALUES OF GAMSQ AND RGAMSQ SET IN THE DATA STATEMENT MAY BE -* INEXACT. THIS IS OK AS THEY ARE ONLY USED FOR TESTING THE SIZE -* OF DD1 AND DD2. ALL ACTUAL SCALING OF DATA IS DONE USING GAM. -* -* -* Arguments -* ========= -* -* DD1 (input/output) DOUBLE PRECISION -* -* DD2 (input/output) DOUBLE PRECISION -* -* DX1 (input/output) DOUBLE PRECISION -* -* DY1 (input) DOUBLE PRECISION -* -* DPARAM (input/output) DOUBLE PRECISION array, dimension 5 -* DPARAM(1)=DFLAG -* DPARAM(2)=DH11 -* DPARAM(3)=DH21 -* DPARAM(4)=DH12 -* DPARAM(5)=DH22 -* -* ===================================================================== -* -* .. Local Scalars .. - DOUBLE PRECISION DFLAG,DH11,DH12,DH21,DH22,DP1,DP2,DQ1,DQ2,DTEMP, - + DU,GAM,GAMSQ,ONE,RGAMSQ,TWO,ZERO - INTEGER IGO -* .. -* .. Intrinsic Functions .. - INTRINSIC DABS -* .. -* .. Data statements .. -* - DATA ZERO,ONE,TWO/0.D0,1.D0,2.D0/ - DATA GAM,GAMSQ,RGAMSQ/4096.D0,16777216.D0,5.9604645D-8/ -* .. - - IF (.NOT.DD1.LT.ZERO) GO TO 10 -* GO ZERO-H-D-AND-DX1.. - GO TO 60 - 10 CONTINUE -* CASE-DD1-NONNEGATIVE - DP2 = DD2*DY1 - IF (.NOT.DP2.EQ.ZERO) GO TO 20 - DFLAG = -TWO - GO TO 260 -* REGULAR-CASE.. - 20 CONTINUE - DP1 = DD1*DX1 - DQ2 = DP2*DY1 - DQ1 = DP1*DX1 -* - IF (.NOT.DABS(DQ1).GT.DABS(DQ2)) GO TO 40 - DH21 = -DY1/DX1 - DH12 = DP2/DP1 -* - DU = ONE - DH12*DH21 -* - IF (.NOT.DU.LE.ZERO) GO TO 30 -* GO ZERO-H-D-AND-DX1.. - GO TO 60 - 30 CONTINUE - DFLAG = ZERO - DD1 = DD1/DU - DD2 = DD2/DU - DX1 = DX1*DU -* GO SCALE-CHECK.. - GO TO 100 - 40 CONTINUE - IF (.NOT.DQ2.LT.ZERO) GO TO 50 -* GO ZERO-H-D-AND-DX1.. - GO TO 60 - 50 CONTINUE - DFLAG = ONE - DH11 = DP1/DP2 - DH22 = DX1/DY1 - DU = ONE + DH11*DH22 - DTEMP = DD2/DU - DD2 = DD1/DU - DD1 = DTEMP - DX1 = DY1*DU -* GO SCALE-CHECK - GO TO 100 -* PROCEDURE..ZERO-H-D-AND-DX1.. - 60 CONTINUE - DFLAG = -ONE - DH11 = ZERO - DH12 = ZERO - DH21 = ZERO - DH22 = ZERO -* - DD1 = ZERO - DD2 = ZERO - DX1 = ZERO -* RETURN.. - GO TO 220 -* PROCEDURE..FIX-H.. - 70 CONTINUE - IF (.NOT.DFLAG.GE.ZERO) GO TO 90 -* - IF (.NOT.DFLAG.EQ.ZERO) GO TO 80 - DH11 = ONE - DH22 = ONE - DFLAG = -ONE - GO TO 90 - 80 CONTINUE - DH21 = -ONE - DH12 = ONE - DFLAG = -ONE - 90 CONTINUE - GO TO IGO(120,150,180,210) -* PROCEDURE..SCALE-CHECK - 100 CONTINUE - 110 CONTINUE - IF (.NOT.DD1.LE.RGAMSQ) GO TO 130 - IF (DD1.EQ.ZERO) GO TO 160 - ASSIGN 120 TO IGO -* FIX-H.. - GO TO 70 - 120 CONTINUE - DD1 = DD1*GAM**2 - DX1 = DX1/GAM - DH11 = DH11/GAM - DH12 = DH12/GAM - GO TO 110 - 130 CONTINUE - 140 CONTINUE - IF (.NOT.DD1.GE.GAMSQ) GO TO 160 - ASSIGN 150 TO IGO -* FIX-H.. - GO TO 70 - 150 CONTINUE - DD1 = DD1/GAM**2 - DX1 = DX1*GAM - DH11 = DH11*GAM - DH12 = DH12*GAM - GO TO 140 - 160 CONTINUE - 170 CONTINUE - IF (.NOT.DABS(DD2).LE.RGAMSQ) GO TO 190 - IF (DD2.EQ.ZERO) GO TO 220 - ASSIGN 180 TO IGO -* FIX-H.. - GO TO 70 - 180 CONTINUE - DD2 = DD2*GAM**2 - DH21 = DH21/GAM - DH22 = DH22/GAM - GO TO 170 - 190 CONTINUE - 200 CONTINUE - IF (.NOT.DABS(DD2).GE.GAMSQ) GO TO 220 - ASSIGN 210 TO IGO -* FIX-H.. - GO TO 70 - 210 CONTINUE - DD2 = DD2/GAM**2 - DH21 = DH21*GAM - DH22 = DH22*GAM - GO TO 200 - 220 CONTINUE - IF (DFLAG) 250,230,240 - 230 CONTINUE - DPARAM(3) = DH21 - DPARAM(4) = DH12 - GO TO 260 - 240 CONTINUE - DPARAM(2) = DH11 - DPARAM(5) = DH22 - GO TO 260 - 250 CONTINUE - DPARAM(2) = DH11 - DPARAM(3) = DH21 - DPARAM(4) = DH12 - DPARAM(5) = DH22 - 260 CONTINUE - DPARAM(1) = DFLAG - RETURN - END diff --git a/ground/gcs/src/libs/eigen/blas/dsbmv.f b/ground/gcs/src/libs/eigen/blas/dsbmv.f deleted file mode 100644 index 8c82d1fa1d..0000000000 --- a/ground/gcs/src/libs/eigen/blas/dsbmv.f +++ /dev/null @@ -1,304 +0,0 @@ - SUBROUTINE DSBMV(UPLO,N,K,ALPHA,A,LDA,X,INCX,BETA,Y,INCY) -* .. Scalar Arguments .. - DOUBLE PRECISION ALPHA,BETA - INTEGER INCX,INCY,K,LDA,N - CHARACTER UPLO -* .. -* .. Array Arguments .. - DOUBLE PRECISION A(LDA,*),X(*),Y(*) -* .. -* -* Purpose -* ======= -* -* DSBMV performs the matrix-vector operation -* -* y := alpha*A*x + beta*y, -* -* where alpha and beta are scalars, x and y are n element vectors and -* A is an n by n symmetric band matrix, with k super-diagonals. -* -* Arguments -* ========== -* -* UPLO - CHARACTER*1. -* On entry, UPLO specifies whether the upper or lower -* triangular part of the band matrix A is being supplied as -* follows: -* -* UPLO = 'U' or 'u' The upper triangular part of A is -* being supplied. -* -* UPLO = 'L' or 'l' The lower triangular part of A is -* being supplied. -* -* Unchanged on exit. -* -* N - INTEGER. -* On entry, N specifies the order of the matrix A. -* N must be at least zero. -* Unchanged on exit. -* -* K - INTEGER. -* On entry, K specifies the number of super-diagonals of the -* matrix A. K must satisfy 0 .le. K. -* Unchanged on exit. -* -* ALPHA - DOUBLE PRECISION. -* On entry, ALPHA specifies the scalar alpha. -* Unchanged on exit. -* -* A - DOUBLE PRECISION array of DIMENSION ( LDA, n ). -* Before entry with UPLO = 'U' or 'u', the leading ( k + 1 ) -* by n part of the array A must contain the upper triangular -* band part of the symmetric matrix, supplied column by -* column, with the leading diagonal of the matrix in row -* ( k + 1 ) of the array, the first super-diagonal starting at -* position 2 in row k, and so on. The top left k by k triangle -* of the array A is not referenced. -* The following program segment will transfer the upper -* triangular part of a symmetric band matrix from conventional -* full matrix storage to band storage: -* -* DO 20, J = 1, N -* M = K + 1 - J -* DO 10, I = MAX( 1, J - K ), J -* A( M + I, J ) = matrix( I, J ) -* 10 CONTINUE -* 20 CONTINUE -* -* Before entry with UPLO = 'L' or 'l', the leading ( k + 1 ) -* by n part of the array A must contain the lower triangular -* band part of the symmetric matrix, supplied column by -* column, with the leading diagonal of the matrix in row 1 of -* the array, the first sub-diagonal starting at position 1 in -* row 2, and so on. The bottom right k by k triangle of the -* array A is not referenced. -* The following program segment will transfer the lower -* triangular part of a symmetric band matrix from conventional -* full matrix storage to band storage: -* -* DO 20, J = 1, N -* M = 1 - J -* DO 10, I = J, MIN( N, J + K ) -* A( M + I, J ) = matrix( I, J ) -* 10 CONTINUE -* 20 CONTINUE -* -* Unchanged on exit. -* -* LDA - INTEGER. -* On entry, LDA specifies the first dimension of A as declared -* in the calling (sub) program. LDA must be at least -* ( k + 1 ). -* Unchanged on exit. -* -* X - DOUBLE PRECISION array of DIMENSION at least -* ( 1 + ( n - 1 )*abs( INCX ) ). -* Before entry, the incremented array X must contain the -* vector x. -* Unchanged on exit. -* -* INCX - INTEGER. -* On entry, INCX specifies the increment for the elements of -* X. INCX must not be zero. -* Unchanged on exit. -* -* BETA - DOUBLE PRECISION. -* On entry, BETA specifies the scalar beta. -* Unchanged on exit. -* -* Y - DOUBLE PRECISION array of DIMENSION at least -* ( 1 + ( n - 1 )*abs( INCY ) ). -* Before entry, the incremented array Y must contain the -* vector y. On exit, Y is overwritten by the updated vector y. -* -* INCY - INTEGER. -* On entry, INCY specifies the increment for the elements of -* Y. INCY must not be zero. -* Unchanged on exit. -* -* -* Level 2 Blas routine. -* -* -- Written on 22-October-1986. -* Jack Dongarra, Argonne National Lab. -* Jeremy Du Croz, Nag Central Office. -* Sven Hammarling, Nag Central Office. -* Richard Hanson, Sandia National Labs. -* -* ===================================================================== -* -* .. Parameters .. - DOUBLE PRECISION ONE,ZERO - PARAMETER (ONE=1.0D+0,ZERO=0.0D+0) -* .. -* .. Local Scalars .. - DOUBLE PRECISION TEMP1,TEMP2 - INTEGER I,INFO,IX,IY,J,JX,JY,KPLUS1,KX,KY,L -* .. -* .. External Functions .. - LOGICAL LSAME - EXTERNAL LSAME -* .. -* .. External Subroutines .. - EXTERNAL XERBLA -* .. -* .. Intrinsic Functions .. - INTRINSIC MAX,MIN -* .. -* -* Test the input parameters. -* - INFO = 0 - IF (.NOT.LSAME(UPLO,'U') .AND. .NOT.LSAME(UPLO,'L')) THEN - INFO = 1 - ELSE IF (N.LT.0) THEN - INFO = 2 - ELSE IF (K.LT.0) THEN - INFO = 3 - ELSE IF (LDA.LT. (K+1)) THEN - INFO = 6 - ELSE IF (INCX.EQ.0) THEN - INFO = 8 - ELSE IF (INCY.EQ.0) THEN - INFO = 11 - END IF - IF (INFO.NE.0) THEN - CALL XERBLA('DSBMV ',INFO) - RETURN - END IF -* -* Quick return if possible. -* - IF ((N.EQ.0) .OR. ((ALPHA.EQ.ZERO).AND. (BETA.EQ.ONE))) RETURN -* -* Set up the start points in X and Y. -* - IF (INCX.GT.0) THEN - KX = 1 - ELSE - KX = 1 - (N-1)*INCX - END IF - IF (INCY.GT.0) THEN - KY = 1 - ELSE - KY = 1 - (N-1)*INCY - END IF -* -* Start the operations. In this version the elements of the array A -* are accessed sequentially with one pass through A. -* -* First form y := beta*y. -* - IF (BETA.NE.ONE) THEN - IF (INCY.EQ.1) THEN - IF (BETA.EQ.ZERO) THEN - DO 10 I = 1,N - Y(I) = ZERO - 10 CONTINUE - ELSE - DO 20 I = 1,N - Y(I) = BETA*Y(I) - 20 CONTINUE - END IF - ELSE - IY = KY - IF (BETA.EQ.ZERO) THEN - DO 30 I = 1,N - Y(IY) = ZERO - IY = IY + INCY - 30 CONTINUE - ELSE - DO 40 I = 1,N - Y(IY) = BETA*Y(IY) - IY = IY + INCY - 40 CONTINUE - END IF - END IF - END IF - IF (ALPHA.EQ.ZERO) RETURN - IF (LSAME(UPLO,'U')) THEN -* -* Form y when upper triangle of A is stored. -* - KPLUS1 = K + 1 - IF ((INCX.EQ.1) .AND. (INCY.EQ.1)) THEN - DO 60 J = 1,N - TEMP1 = ALPHA*X(J) - TEMP2 = ZERO - L = KPLUS1 - J - DO 50 I = MAX(1,J-K),J - 1 - Y(I) = Y(I) + TEMP1*A(L+I,J) - TEMP2 = TEMP2 + A(L+I,J)*X(I) - 50 CONTINUE - Y(J) = Y(J) + TEMP1*A(KPLUS1,J) + ALPHA*TEMP2 - 60 CONTINUE - ELSE - JX = KX - JY = KY - DO 80 J = 1,N - TEMP1 = ALPHA*X(JX) - TEMP2 = ZERO - IX = KX - IY = KY - L = KPLUS1 - J - DO 70 I = MAX(1,J-K),J - 1 - Y(IY) = Y(IY) + TEMP1*A(L+I,J) - TEMP2 = TEMP2 + A(L+I,J)*X(IX) - IX = IX + INCX - IY = IY + INCY - 70 CONTINUE - Y(JY) = Y(JY) + TEMP1*A(KPLUS1,J) + ALPHA*TEMP2 - JX = JX + INCX - JY = JY + INCY - IF (J.GT.K) THEN - KX = KX + INCX - KY = KY + INCY - END IF - 80 CONTINUE - END IF - ELSE -* -* Form y when lower triangle of A is stored. -* - IF ((INCX.EQ.1) .AND. (INCY.EQ.1)) THEN - DO 100 J = 1,N - TEMP1 = ALPHA*X(J) - TEMP2 = ZERO - Y(J) = Y(J) + TEMP1*A(1,J) - L = 1 - J - DO 90 I = J + 1,MIN(N,J+K) - Y(I) = Y(I) + TEMP1*A(L+I,J) - TEMP2 = TEMP2 + A(L+I,J)*X(I) - 90 CONTINUE - Y(J) = Y(J) + ALPHA*TEMP2 - 100 CONTINUE - ELSE - JX = KX - JY = KY - DO 120 J = 1,N - TEMP1 = ALPHA*X(JX) - TEMP2 = ZERO - Y(JY) = Y(JY) + TEMP1*A(1,J) - L = 1 - J - IX = JX - IY = JY - DO 110 I = J + 1,MIN(N,J+K) - IX = IX + INCX - IY = IY + INCY - Y(IY) = Y(IY) + TEMP1*A(L+I,J) - TEMP2 = TEMP2 + A(L+I,J)*X(IX) - 110 CONTINUE - Y(JY) = Y(JY) + ALPHA*TEMP2 - JX = JX + INCX - JY = JY + INCY - 120 CONTINUE - END IF - END IF -* - RETURN -* -* End of DSBMV . -* - END diff --git a/ground/gcs/src/libs/eigen/blas/dspmv.f b/ground/gcs/src/libs/eigen/blas/dspmv.f deleted file mode 100644 index f6e121e765..0000000000 --- a/ground/gcs/src/libs/eigen/blas/dspmv.f +++ /dev/null @@ -1,265 +0,0 @@ - SUBROUTINE DSPMV(UPLO,N,ALPHA,AP,X,INCX,BETA,Y,INCY) -* .. Scalar Arguments .. - DOUBLE PRECISION ALPHA,BETA - INTEGER INCX,INCY,N - CHARACTER UPLO -* .. -* .. Array Arguments .. - DOUBLE PRECISION AP(*),X(*),Y(*) -* .. -* -* Purpose -* ======= -* -* DSPMV performs the matrix-vector operation -* -* y := alpha*A*x + beta*y, -* -* where alpha and beta are scalars, x and y are n element vectors and -* A is an n by n symmetric matrix, supplied in packed form. -* -* Arguments -* ========== -* -* UPLO - CHARACTER*1. -* On entry, UPLO specifies whether the upper or lower -* triangular part of the matrix A is supplied in the packed -* array AP as follows: -* -* UPLO = 'U' or 'u' The upper triangular part of A is -* supplied in AP. -* -* UPLO = 'L' or 'l' The lower triangular part of A is -* supplied in AP. -* -* Unchanged on exit. -* -* N - INTEGER. -* On entry, N specifies the order of the matrix A. -* N must be at least zero. -* Unchanged on exit. -* -* ALPHA - DOUBLE PRECISION. -* On entry, ALPHA specifies the scalar alpha. -* Unchanged on exit. -* -* AP - DOUBLE PRECISION array of DIMENSION at least -* ( ( n*( n + 1 ) )/2 ). -* Before entry with UPLO = 'U' or 'u', the array AP must -* contain the upper triangular part of the symmetric matrix -* packed sequentially, column by column, so that AP( 1 ) -* contains a( 1, 1 ), AP( 2 ) and AP( 3 ) contain a( 1, 2 ) -* and a( 2, 2 ) respectively, and so on. -* Before entry with UPLO = 'L' or 'l', the array AP must -* contain the lower triangular part of the symmetric matrix -* packed sequentially, column by column, so that AP( 1 ) -* contains a( 1, 1 ), AP( 2 ) and AP( 3 ) contain a( 2, 1 ) -* and a( 3, 1 ) respectively, and so on. -* Unchanged on exit. -* -* X - DOUBLE PRECISION array of dimension at least -* ( 1 + ( n - 1 )*abs( INCX ) ). -* Before entry, the incremented array X must contain the n -* element vector x. -* Unchanged on exit. -* -* INCX - INTEGER. -* On entry, INCX specifies the increment for the elements of -* X. INCX must not be zero. -* Unchanged on exit. -* -* BETA - DOUBLE PRECISION. -* On entry, BETA specifies the scalar beta. When BETA is -* supplied as zero then Y need not be set on input. -* Unchanged on exit. -* -* Y - DOUBLE PRECISION array of dimension at least -* ( 1 + ( n - 1 )*abs( INCY ) ). -* Before entry, the incremented array Y must contain the n -* element vector y. On exit, Y is overwritten by the updated -* vector y. -* -* INCY - INTEGER. -* On entry, INCY specifies the increment for the elements of -* Y. INCY must not be zero. -* Unchanged on exit. -* -* Further Details -* =============== -* -* Level 2 Blas routine. -* -* -- Written on 22-October-1986. -* Jack Dongarra, Argonne National Lab. -* Jeremy Du Croz, Nag Central Office. -* Sven Hammarling, Nag Central Office. -* Richard Hanson, Sandia National Labs. -* -* ===================================================================== -* -* .. Parameters .. - DOUBLE PRECISION ONE,ZERO - PARAMETER (ONE=1.0D+0,ZERO=0.0D+0) -* .. -* .. Local Scalars .. - DOUBLE PRECISION TEMP1,TEMP2 - INTEGER I,INFO,IX,IY,J,JX,JY,K,KK,KX,KY -* .. -* .. External Functions .. - LOGICAL LSAME - EXTERNAL LSAME -* .. -* .. External Subroutines .. - EXTERNAL XERBLA -* .. -* -* Test the input parameters. -* - INFO = 0 - IF (.NOT.LSAME(UPLO,'U') .AND. .NOT.LSAME(UPLO,'L')) THEN - INFO = 1 - ELSE IF (N.LT.0) THEN - INFO = 2 - ELSE IF (INCX.EQ.0) THEN - INFO = 6 - ELSE IF (INCY.EQ.0) THEN - INFO = 9 - END IF - IF (INFO.NE.0) THEN - CALL XERBLA('DSPMV ',INFO) - RETURN - END IF -* -* Quick return if possible. -* - IF ((N.EQ.0) .OR. ((ALPHA.EQ.ZERO).AND. (BETA.EQ.ONE))) RETURN -* -* Set up the start points in X and Y. -* - IF (INCX.GT.0) THEN - KX = 1 - ELSE - KX = 1 - (N-1)*INCX - END IF - IF (INCY.GT.0) THEN - KY = 1 - ELSE - KY = 1 - (N-1)*INCY - END IF -* -* Start the operations. In this version the elements of the array AP -* are accessed sequentially with one pass through AP. -* -* First form y := beta*y. -* - IF (BETA.NE.ONE) THEN - IF (INCY.EQ.1) THEN - IF (BETA.EQ.ZERO) THEN - DO 10 I = 1,N - Y(I) = ZERO - 10 CONTINUE - ELSE - DO 20 I = 1,N - Y(I) = BETA*Y(I) - 20 CONTINUE - END IF - ELSE - IY = KY - IF (BETA.EQ.ZERO) THEN - DO 30 I = 1,N - Y(IY) = ZERO - IY = IY + INCY - 30 CONTINUE - ELSE - DO 40 I = 1,N - Y(IY) = BETA*Y(IY) - IY = IY + INCY - 40 CONTINUE - END IF - END IF - END IF - IF (ALPHA.EQ.ZERO) RETURN - KK = 1 - IF (LSAME(UPLO,'U')) THEN -* -* Form y when AP contains the upper triangle. -* - IF ((INCX.EQ.1) .AND. (INCY.EQ.1)) THEN - DO 60 J = 1,N - TEMP1 = ALPHA*X(J) - TEMP2 = ZERO - K = KK - DO 50 I = 1,J - 1 - Y(I) = Y(I) + TEMP1*AP(K) - TEMP2 = TEMP2 + AP(K)*X(I) - K = K + 1 - 50 CONTINUE - Y(J) = Y(J) + TEMP1*AP(KK+J-1) + ALPHA*TEMP2 - KK = KK + J - 60 CONTINUE - ELSE - JX = KX - JY = KY - DO 80 J = 1,N - TEMP1 = ALPHA*X(JX) - TEMP2 = ZERO - IX = KX - IY = KY - DO 70 K = KK,KK + J - 2 - Y(IY) = Y(IY) + TEMP1*AP(K) - TEMP2 = TEMP2 + AP(K)*X(IX) - IX = IX + INCX - IY = IY + INCY - 70 CONTINUE - Y(JY) = Y(JY) + TEMP1*AP(KK+J-1) + ALPHA*TEMP2 - JX = JX + INCX - JY = JY + INCY - KK = KK + J - 80 CONTINUE - END IF - ELSE -* -* Form y when AP contains the lower triangle. -* - IF ((INCX.EQ.1) .AND. (INCY.EQ.1)) THEN - DO 100 J = 1,N - TEMP1 = ALPHA*X(J) - TEMP2 = ZERO - Y(J) = Y(J) + TEMP1*AP(KK) - K = KK + 1 - DO 90 I = J + 1,N - Y(I) = Y(I) + TEMP1*AP(K) - TEMP2 = TEMP2 + AP(K)*X(I) - K = K + 1 - 90 CONTINUE - Y(J) = Y(J) + ALPHA*TEMP2 - KK = KK + (N-J+1) - 100 CONTINUE - ELSE - JX = KX - JY = KY - DO 120 J = 1,N - TEMP1 = ALPHA*X(JX) - TEMP2 = ZERO - Y(JY) = Y(JY) + TEMP1*AP(KK) - IX = JX - IY = JY - DO 110 K = KK + 1,KK + N - J - IX = IX + INCX - IY = IY + INCY - Y(IY) = Y(IY) + TEMP1*AP(K) - TEMP2 = TEMP2 + AP(K)*X(IX) - 110 CONTINUE - Y(JY) = Y(JY) + ALPHA*TEMP2 - JX = JX + INCX - JY = JY + INCY - KK = KK + (N-J+1) - 120 CONTINUE - END IF - END IF -* - RETURN -* -* End of DSPMV . -* - END diff --git a/ground/gcs/src/libs/eigen/blas/dtbmv.f b/ground/gcs/src/libs/eigen/blas/dtbmv.f deleted file mode 100644 index a87ffdeaeb..0000000000 --- a/ground/gcs/src/libs/eigen/blas/dtbmv.f +++ /dev/null @@ -1,335 +0,0 @@ - SUBROUTINE DTBMV(UPLO,TRANS,DIAG,N,K,A,LDA,X,INCX) -* .. Scalar Arguments .. - INTEGER INCX,K,LDA,N - CHARACTER DIAG,TRANS,UPLO -* .. -* .. Array Arguments .. - DOUBLE PRECISION A(LDA,*),X(*) -* .. -* -* Purpose -* ======= -* -* DTBMV performs one of the matrix-vector operations -* -* x := A*x, or x := A'*x, -* -* where x is an n element vector and A is an n by n unit, or non-unit, -* upper or lower triangular band matrix, with ( k + 1 ) diagonals. -* -* Arguments -* ========== -* -* UPLO - CHARACTER*1. -* On entry, UPLO specifies whether the matrix is an upper or -* lower triangular matrix as follows: -* -* UPLO = 'U' or 'u' A is an upper triangular matrix. -* -* UPLO = 'L' or 'l' A is a lower triangular matrix. -* -* Unchanged on exit. -* -* TRANS - CHARACTER*1. -* On entry, TRANS specifies the operation to be performed as -* follows: -* -* TRANS = 'N' or 'n' x := A*x. -* -* TRANS = 'T' or 't' x := A'*x. -* -* TRANS = 'C' or 'c' x := A'*x. -* -* Unchanged on exit. -* -* DIAG - CHARACTER*1. -* On entry, DIAG specifies whether or not A is unit -* triangular as follows: -* -* DIAG = 'U' or 'u' A is assumed to be unit triangular. -* -* DIAG = 'N' or 'n' A is not assumed to be unit -* triangular. -* -* Unchanged on exit. -* -* N - INTEGER. -* On entry, N specifies the order of the matrix A. -* N must be at least zero. -* Unchanged on exit. -* -* K - INTEGER. -* On entry with UPLO = 'U' or 'u', K specifies the number of -* super-diagonals of the matrix A. -* On entry with UPLO = 'L' or 'l', K specifies the number of -* sub-diagonals of the matrix A. -* K must satisfy 0 .le. K. -* Unchanged on exit. -* -* A - DOUBLE PRECISION array of DIMENSION ( LDA, n ). -* Before entry with UPLO = 'U' or 'u', the leading ( k + 1 ) -* by n part of the array A must contain the upper triangular -* band part of the matrix of coefficients, supplied column by -* column, with the leading diagonal of the matrix in row -* ( k + 1 ) of the array, the first super-diagonal starting at -* position 2 in row k, and so on. The top left k by k triangle -* of the array A is not referenced. -* The following program segment will transfer an upper -* triangular band matrix from conventional full matrix storage -* to band storage: -* -* DO 20, J = 1, N -* M = K + 1 - J -* DO 10, I = MAX( 1, J - K ), J -* A( M + I, J ) = matrix( I, J ) -* 10 CONTINUE -* 20 CONTINUE -* -* Before entry with UPLO = 'L' or 'l', the leading ( k + 1 ) -* by n part of the array A must contain the lower triangular -* band part of the matrix of coefficients, supplied column by -* column, with the leading diagonal of the matrix in row 1 of -* the array, the first sub-diagonal starting at position 1 in -* row 2, and so on. The bottom right k by k triangle of the -* array A is not referenced. -* The following program segment will transfer a lower -* triangular band matrix from conventional full matrix storage -* to band storage: -* -* DO 20, J = 1, N -* M = 1 - J -* DO 10, I = J, MIN( N, J + K ) -* A( M + I, J ) = matrix( I, J ) -* 10 CONTINUE -* 20 CONTINUE -* -* Note that when DIAG = 'U' or 'u' the elements of the array A -* corresponding to the diagonal elements of the matrix are not -* referenced, but are assumed to be unity. -* Unchanged on exit. -* -* LDA - INTEGER. -* On entry, LDA specifies the first dimension of A as declared -* in the calling (sub) program. LDA must be at least -* ( k + 1 ). -* Unchanged on exit. -* -* X - DOUBLE PRECISION array of dimension at least -* ( 1 + ( n - 1 )*abs( INCX ) ). -* Before entry, the incremented array X must contain the n -* element vector x. On exit, X is overwritten with the -* tranformed vector x. -* -* INCX - INTEGER. -* On entry, INCX specifies the increment for the elements of -* X. INCX must not be zero. -* Unchanged on exit. -* -* Further Details -* =============== -* -* Level 2 Blas routine. -* -* -- Written on 22-October-1986. -* Jack Dongarra, Argonne National Lab. -* Jeremy Du Croz, Nag Central Office. -* Sven Hammarling, Nag Central Office. -* Richard Hanson, Sandia National Labs. -* -* ===================================================================== -* -* .. Parameters .. - DOUBLE PRECISION ZERO - PARAMETER (ZERO=0.0D+0) -* .. -* .. Local Scalars .. - DOUBLE PRECISION TEMP - INTEGER I,INFO,IX,J,JX,KPLUS1,KX,L - LOGICAL NOUNIT -* .. -* .. External Functions .. - LOGICAL LSAME - EXTERNAL LSAME -* .. -* .. External Subroutines .. - EXTERNAL XERBLA -* .. -* .. Intrinsic Functions .. - INTRINSIC MAX,MIN -* .. -* -* Test the input parameters. -* - INFO = 0 - IF (.NOT.LSAME(UPLO,'U') .AND. .NOT.LSAME(UPLO,'L')) THEN - INFO = 1 - ELSE IF (.NOT.LSAME(TRANS,'N') .AND. .NOT.LSAME(TRANS,'T') .AND. - + .NOT.LSAME(TRANS,'C')) THEN - INFO = 2 - ELSE IF (.NOT.LSAME(DIAG,'U') .AND. .NOT.LSAME(DIAG,'N')) THEN - INFO = 3 - ELSE IF (N.LT.0) THEN - INFO = 4 - ELSE IF (K.LT.0) THEN - INFO = 5 - ELSE IF (LDA.LT. (K+1)) THEN - INFO = 7 - ELSE IF (INCX.EQ.0) THEN - INFO = 9 - END IF - IF (INFO.NE.0) THEN - CALL XERBLA('DTBMV ',INFO) - RETURN - END IF -* -* Quick return if possible. -* - IF (N.EQ.0) RETURN -* - NOUNIT = LSAME(DIAG,'N') -* -* Set up the start point in X if the increment is not unity. This -* will be ( N - 1 )*INCX too small for descending loops. -* - IF (INCX.LE.0) THEN - KX = 1 - (N-1)*INCX - ELSE IF (INCX.NE.1) THEN - KX = 1 - END IF -* -* Start the operations. In this version the elements of A are -* accessed sequentially with one pass through A. -* - IF (LSAME(TRANS,'N')) THEN -* -* Form x := A*x. -* - IF (LSAME(UPLO,'U')) THEN - KPLUS1 = K + 1 - IF (INCX.EQ.1) THEN - DO 20 J = 1,N - IF (X(J).NE.ZERO) THEN - TEMP = X(J) - L = KPLUS1 - J - DO 10 I = MAX(1,J-K),J - 1 - X(I) = X(I) + TEMP*A(L+I,J) - 10 CONTINUE - IF (NOUNIT) X(J) = X(J)*A(KPLUS1,J) - END IF - 20 CONTINUE - ELSE - JX = KX - DO 40 J = 1,N - IF (X(JX).NE.ZERO) THEN - TEMP = X(JX) - IX = KX - L = KPLUS1 - J - DO 30 I = MAX(1,J-K),J - 1 - X(IX) = X(IX) + TEMP*A(L+I,J) - IX = IX + INCX - 30 CONTINUE - IF (NOUNIT) X(JX) = X(JX)*A(KPLUS1,J) - END IF - JX = JX + INCX - IF (J.GT.K) KX = KX + INCX - 40 CONTINUE - END IF - ELSE - IF (INCX.EQ.1) THEN - DO 60 J = N,1,-1 - IF (X(J).NE.ZERO) THEN - TEMP = X(J) - L = 1 - J - DO 50 I = MIN(N,J+K),J + 1,-1 - X(I) = X(I) + TEMP*A(L+I,J) - 50 CONTINUE - IF (NOUNIT) X(J) = X(J)*A(1,J) - END IF - 60 CONTINUE - ELSE - KX = KX + (N-1)*INCX - JX = KX - DO 80 J = N,1,-1 - IF (X(JX).NE.ZERO) THEN - TEMP = X(JX) - IX = KX - L = 1 - J - DO 70 I = MIN(N,J+K),J + 1,-1 - X(IX) = X(IX) + TEMP*A(L+I,J) - IX = IX - INCX - 70 CONTINUE - IF (NOUNIT) X(JX) = X(JX)*A(1,J) - END IF - JX = JX - INCX - IF ((N-J).GE.K) KX = KX - INCX - 80 CONTINUE - END IF - END IF - ELSE -* -* Form x := A'*x. -* - IF (LSAME(UPLO,'U')) THEN - KPLUS1 = K + 1 - IF (INCX.EQ.1) THEN - DO 100 J = N,1,-1 - TEMP = X(J) - L = KPLUS1 - J - IF (NOUNIT) TEMP = TEMP*A(KPLUS1,J) - DO 90 I = J - 1,MAX(1,J-K),-1 - TEMP = TEMP + A(L+I,J)*X(I) - 90 CONTINUE - X(J) = TEMP - 100 CONTINUE - ELSE - KX = KX + (N-1)*INCX - JX = KX - DO 120 J = N,1,-1 - TEMP = X(JX) - KX = KX - INCX - IX = KX - L = KPLUS1 - J - IF (NOUNIT) TEMP = TEMP*A(KPLUS1,J) - DO 110 I = J - 1,MAX(1,J-K),-1 - TEMP = TEMP + A(L+I,J)*X(IX) - IX = IX - INCX - 110 CONTINUE - X(JX) = TEMP - JX = JX - INCX - 120 CONTINUE - END IF - ELSE - IF (INCX.EQ.1) THEN - DO 140 J = 1,N - TEMP = X(J) - L = 1 - J - IF (NOUNIT) TEMP = TEMP*A(1,J) - DO 130 I = J + 1,MIN(N,J+K) - TEMP = TEMP + A(L+I,J)*X(I) - 130 CONTINUE - X(J) = TEMP - 140 CONTINUE - ELSE - JX = KX - DO 160 J = 1,N - TEMP = X(JX) - KX = KX + INCX - IX = KX - L = 1 - J - IF (NOUNIT) TEMP = TEMP*A(1,J) - DO 150 I = J + 1,MIN(N,J+K) - TEMP = TEMP + A(L+I,J)*X(IX) - IX = IX + INCX - 150 CONTINUE - X(JX) = TEMP - JX = JX + INCX - 160 CONTINUE - END IF - END IF - END IF -* - RETURN -* -* End of DTBMV . -* - END diff --git a/ground/gcs/src/libs/eigen/blas/f2c/chbmv.c b/ground/gcs/src/libs/eigen/blas/f2c/chbmv.c new file mode 100644 index 0000000000..f218fe3f57 --- /dev/null +++ b/ground/gcs/src/libs/eigen/blas/f2c/chbmv.c @@ -0,0 +1,487 @@ +/* chbmv.f -- translated by f2c (version 20100827). + You must link the resulting object file with libf2c: + on Microsoft Windows system, link with libf2c.lib; + on Linux or Unix systems, link with .../path/to/libf2c.a -lm + or, if you install libf2c.a in a standard place, with -lf2c -lm + -- in that order, at the end of the command line, as in + cc *.o -lf2c -lm + Source for libf2c is in /netlib/f2c/libf2c.zip, e.g., + + http://www.netlib.org/f2c/libf2c.zip +*/ + +#include "datatypes.h" + +/* Subroutine */ int chbmv_(char *uplo, integer *n, integer *k, complex * + alpha, complex *a, integer *lda, complex *x, integer *incx, complex * + beta, complex *y, integer *incy, ftnlen uplo_len) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4, i__5; + real r__1; + complex q__1, q__2, q__3, q__4; + + /* Builtin functions */ + void r_cnjg(complex *, complex *); + + /* Local variables */ + integer i__, j, l, ix, iy, jx, jy, kx, ky, info; + complex temp1, temp2; + extern logical lsame_(char *, char *, ftnlen, ftnlen); + integer kplus1; + extern /* Subroutine */ int xerbla_(char *, integer *, ftnlen); + +/* .. Scalar Arguments .. */ +/* .. */ +/* .. Array Arguments .. */ +/* .. */ + +/* Purpose */ +/* ======= */ + +/* CHBMV performs the matrix-vector operation */ + +/* y := alpha*A*x + beta*y, */ + +/* where alpha and beta are scalars, x and y are n element vectors and */ +/* A is an n by n hermitian band matrix, with k super-diagonals. */ + +/* Arguments */ +/* ========== */ + +/* UPLO - CHARACTER*1. */ +/* On entry, UPLO specifies whether the upper or lower */ +/* triangular part of the band matrix A is being supplied as */ +/* follows: */ + +/* UPLO = 'U' or 'u' The upper triangular part of A is */ +/* being supplied. */ + +/* UPLO = 'L' or 'l' The lower triangular part of A is */ +/* being supplied. */ + +/* Unchanged on exit. */ + +/* N - INTEGER. */ +/* On entry, N specifies the order of the matrix A. */ +/* N must be at least zero. */ +/* Unchanged on exit. */ + +/* K - INTEGER. */ +/* On entry, K specifies the number of super-diagonals of the */ +/* matrix A. K must satisfy 0 .le. K. */ +/* Unchanged on exit. */ + +/* ALPHA - COMPLEX . */ +/* On entry, ALPHA specifies the scalar alpha. */ +/* Unchanged on exit. */ + +/* A - COMPLEX array of DIMENSION ( LDA, n ). */ +/* Before entry with UPLO = 'U' or 'u', the leading ( k + 1 ) */ +/* by n part of the array A must contain the upper triangular */ +/* band part of the hermitian matrix, supplied column by */ +/* column, with the leading diagonal of the matrix in row */ +/* ( k + 1 ) of the array, the first super-diagonal starting at */ +/* position 2 in row k, and so on. The top left k by k triangle */ +/* of the array A is not referenced. */ +/* The following program segment will transfer the upper */ +/* triangular part of a hermitian band matrix from conventional */ +/* full matrix storage to band storage: */ + +/* DO 20, J = 1, N */ +/* M = K + 1 - J */ +/* DO 10, I = MAX( 1, J - K ), J */ +/* A( M + I, J ) = matrix( I, J ) */ +/* 10 CONTINUE */ +/* 20 CONTINUE */ + +/* Before entry with UPLO = 'L' or 'l', the leading ( k + 1 ) */ +/* by n part of the array A must contain the lower triangular */ +/* band part of the hermitian matrix, supplied column by */ +/* column, with the leading diagonal of the matrix in row 1 of */ +/* the array, the first sub-diagonal starting at position 1 in */ +/* row 2, and so on. The bottom right k by k triangle of the */ +/* array A is not referenced. */ +/* The following program segment will transfer the lower */ +/* triangular part of a hermitian band matrix from conventional */ +/* full matrix storage to band storage: */ + +/* DO 20, J = 1, N */ +/* M = 1 - J */ +/* DO 10, I = J, MIN( N, J + K ) */ +/* A( M + I, J ) = matrix( I, J ) */ +/* 10 CONTINUE */ +/* 20 CONTINUE */ + +/* Note that the imaginary parts of the diagonal elements need */ +/* not be set and are assumed to be zero. */ +/* Unchanged on exit. */ + +/* LDA - INTEGER. */ +/* On entry, LDA specifies the first dimension of A as declared */ +/* in the calling (sub) program. LDA must be at least */ +/* ( k + 1 ). */ +/* Unchanged on exit. */ + +/* X - COMPLEX array of DIMENSION at least */ +/* ( 1 + ( n - 1 )*abs( INCX ) ). */ +/* Before entry, the incremented array X must contain the */ +/* vector x. */ +/* Unchanged on exit. */ + +/* INCX - INTEGER. */ +/* On entry, INCX specifies the increment for the elements of */ +/* X. INCX must not be zero. */ +/* Unchanged on exit. */ + +/* BETA - COMPLEX . */ +/* On entry, BETA specifies the scalar beta. */ +/* Unchanged on exit. */ + +/* Y - COMPLEX array of DIMENSION at least */ +/* ( 1 + ( n - 1 )*abs( INCY ) ). */ +/* Before entry, the incremented array Y must contain the */ +/* vector y. On exit, Y is overwritten by the updated vector y. */ + +/* INCY - INTEGER. */ +/* On entry, INCY specifies the increment for the elements of */ +/* Y. INCY must not be zero. */ +/* Unchanged on exit. */ + +/* Further Details */ +/* =============== */ + +/* Level 2 Blas routine. */ + +/* -- Written on 22-October-1986. */ +/* Jack Dongarra, Argonne National Lab. */ +/* Jeremy Du Croz, Nag Central Office. */ +/* Sven Hammarling, Nag Central Office. */ +/* Richard Hanson, Sandia National Labs. */ + +/* ===================================================================== */ + +/* .. Parameters .. */ +/* .. */ +/* .. Local Scalars .. */ +/* .. */ +/* .. External Functions .. */ +/* .. */ +/* .. External Subroutines .. */ +/* .. */ +/* .. Intrinsic Functions .. */ +/* .. */ + +/* Test the input parameters. */ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --x; + --y; + + /* Function Body */ + info = 0; + if (! lsame_(uplo, "U", (ftnlen)1, (ftnlen)1) && ! lsame_(uplo, "L", ( + ftnlen)1, (ftnlen)1)) { + info = 1; + } else if (*n < 0) { + info = 2; + } else if (*k < 0) { + info = 3; + } else if (*lda < *k + 1) { + info = 6; + } else if (*incx == 0) { + info = 8; + } else if (*incy == 0) { + info = 11; + } + if (info != 0) { + xerbla_("CHBMV ", &info, (ftnlen)6); + return 0; + } + +/* Quick return if possible. */ + + if (*n == 0 || (alpha->r == 0.f && alpha->i == 0.f && (beta->r == 1.f && + beta->i == 0.f))) { + return 0; + } + +/* Set up the start points in X and Y. */ + + if (*incx > 0) { + kx = 1; + } else { + kx = 1 - (*n - 1) * *incx; + } + if (*incy > 0) { + ky = 1; + } else { + ky = 1 - (*n - 1) * *incy; + } + +/* Start the operations. In this version the elements of the array A */ +/* are accessed sequentially with one pass through A. */ + +/* First form y := beta*y. */ + + if (beta->r != 1.f || beta->i != 0.f) { + if (*incy == 1) { + if (beta->r == 0.f && beta->i == 0.f) { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__; + y[i__2].r = 0.f, y[i__2].i = 0.f; +/* L10: */ + } + } else { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__; + i__3 = i__; + q__1.r = beta->r * y[i__3].r - beta->i * y[i__3].i, + q__1.i = beta->r * y[i__3].i + beta->i * y[i__3] + .r; + y[i__2].r = q__1.r, y[i__2].i = q__1.i; +/* L20: */ + } + } + } else { + iy = ky; + if (beta->r == 0.f && beta->i == 0.f) { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = iy; + y[i__2].r = 0.f, y[i__2].i = 0.f; + iy += *incy; +/* L30: */ + } + } else { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = iy; + i__3 = iy; + q__1.r = beta->r * y[i__3].r - beta->i * y[i__3].i, + q__1.i = beta->r * y[i__3].i + beta->i * y[i__3] + .r; + y[i__2].r = q__1.r, y[i__2].i = q__1.i; + iy += *incy; +/* L40: */ + } + } + } + } + if (alpha->r == 0.f && alpha->i == 0.f) { + return 0; + } + if (lsame_(uplo, "U", (ftnlen)1, (ftnlen)1)) { + +/* Form y when upper triangle of A is stored. */ + + kplus1 = *k + 1; + if (*incx == 1 && *incy == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j; + q__1.r = alpha->r * x[i__2].r - alpha->i * x[i__2].i, q__1.i = + alpha->r * x[i__2].i + alpha->i * x[i__2].r; + temp1.r = q__1.r, temp1.i = q__1.i; + temp2.r = 0.f, temp2.i = 0.f; + l = kplus1 - j; +/* Computing MAX */ + i__2 = 1, i__3 = j - *k; + i__4 = j - 1; + for (i__ = max(i__2,i__3); i__ <= i__4; ++i__) { + i__2 = i__; + i__3 = i__; + i__5 = l + i__ + j * a_dim1; + q__2.r = temp1.r * a[i__5].r - temp1.i * a[i__5].i, + q__2.i = temp1.r * a[i__5].i + temp1.i * a[i__5] + .r; + q__1.r = y[i__3].r + q__2.r, q__1.i = y[i__3].i + q__2.i; + y[i__2].r = q__1.r, y[i__2].i = q__1.i; + r_cnjg(&q__3, &a[l + i__ + j * a_dim1]); + i__2 = i__; + q__2.r = q__3.r * x[i__2].r - q__3.i * x[i__2].i, q__2.i = + q__3.r * x[i__2].i + q__3.i * x[i__2].r; + q__1.r = temp2.r + q__2.r, q__1.i = temp2.i + q__2.i; + temp2.r = q__1.r, temp2.i = q__1.i; +/* L50: */ + } + i__4 = j; + i__2 = j; + i__3 = kplus1 + j * a_dim1; + r__1 = a[i__3].r; + q__3.r = r__1 * temp1.r, q__3.i = r__1 * temp1.i; + q__2.r = y[i__2].r + q__3.r, q__2.i = y[i__2].i + q__3.i; + q__4.r = alpha->r * temp2.r - alpha->i * temp2.i, q__4.i = + alpha->r * temp2.i + alpha->i * temp2.r; + q__1.r = q__2.r + q__4.r, q__1.i = q__2.i + q__4.i; + y[i__4].r = q__1.r, y[i__4].i = q__1.i; +/* L60: */ + } + } else { + jx = kx; + jy = ky; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__4 = jx; + q__1.r = alpha->r * x[i__4].r - alpha->i * x[i__4].i, q__1.i = + alpha->r * x[i__4].i + alpha->i * x[i__4].r; + temp1.r = q__1.r, temp1.i = q__1.i; + temp2.r = 0.f, temp2.i = 0.f; + ix = kx; + iy = ky; + l = kplus1 - j; +/* Computing MAX */ + i__4 = 1, i__2 = j - *k; + i__3 = j - 1; + for (i__ = max(i__4,i__2); i__ <= i__3; ++i__) { + i__4 = iy; + i__2 = iy; + i__5 = l + i__ + j * a_dim1; + q__2.r = temp1.r * a[i__5].r - temp1.i * a[i__5].i, + q__2.i = temp1.r * a[i__5].i + temp1.i * a[i__5] + .r; + q__1.r = y[i__2].r + q__2.r, q__1.i = y[i__2].i + q__2.i; + y[i__4].r = q__1.r, y[i__4].i = q__1.i; + r_cnjg(&q__3, &a[l + i__ + j * a_dim1]); + i__4 = ix; + q__2.r = q__3.r * x[i__4].r - q__3.i * x[i__4].i, q__2.i = + q__3.r * x[i__4].i + q__3.i * x[i__4].r; + q__1.r = temp2.r + q__2.r, q__1.i = temp2.i + q__2.i; + temp2.r = q__1.r, temp2.i = q__1.i; + ix += *incx; + iy += *incy; +/* L70: */ + } + i__3 = jy; + i__4 = jy; + i__2 = kplus1 + j * a_dim1; + r__1 = a[i__2].r; + q__3.r = r__1 * temp1.r, q__3.i = r__1 * temp1.i; + q__2.r = y[i__4].r + q__3.r, q__2.i = y[i__4].i + q__3.i; + q__4.r = alpha->r * temp2.r - alpha->i * temp2.i, q__4.i = + alpha->r * temp2.i + alpha->i * temp2.r; + q__1.r = q__2.r + q__4.r, q__1.i = q__2.i + q__4.i; + y[i__3].r = q__1.r, y[i__3].i = q__1.i; + jx += *incx; + jy += *incy; + if (j > *k) { + kx += *incx; + ky += *incy; + } +/* L80: */ + } + } + } else { + +/* Form y when lower triangle of A is stored. */ + + if (*incx == 1 && *incy == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__3 = j; + q__1.r = alpha->r * x[i__3].r - alpha->i * x[i__3].i, q__1.i = + alpha->r * x[i__3].i + alpha->i * x[i__3].r; + temp1.r = q__1.r, temp1.i = q__1.i; + temp2.r = 0.f, temp2.i = 0.f; + i__3 = j; + i__4 = j; + i__2 = j * a_dim1 + 1; + r__1 = a[i__2].r; + q__2.r = r__1 * temp1.r, q__2.i = r__1 * temp1.i; + q__1.r = y[i__4].r + q__2.r, q__1.i = y[i__4].i + q__2.i; + y[i__3].r = q__1.r, y[i__3].i = q__1.i; + l = 1 - j; +/* Computing MIN */ + i__4 = *n, i__2 = j + *k; + i__3 = min(i__4,i__2); + for (i__ = j + 1; i__ <= i__3; ++i__) { + i__4 = i__; + i__2 = i__; + i__5 = l + i__ + j * a_dim1; + q__2.r = temp1.r * a[i__5].r - temp1.i * a[i__5].i, + q__2.i = temp1.r * a[i__5].i + temp1.i * a[i__5] + .r; + q__1.r = y[i__2].r + q__2.r, q__1.i = y[i__2].i + q__2.i; + y[i__4].r = q__1.r, y[i__4].i = q__1.i; + r_cnjg(&q__3, &a[l + i__ + j * a_dim1]); + i__4 = i__; + q__2.r = q__3.r * x[i__4].r - q__3.i * x[i__4].i, q__2.i = + q__3.r * x[i__4].i + q__3.i * x[i__4].r; + q__1.r = temp2.r + q__2.r, q__1.i = temp2.i + q__2.i; + temp2.r = q__1.r, temp2.i = q__1.i; +/* L90: */ + } + i__3 = j; + i__4 = j; + q__2.r = alpha->r * temp2.r - alpha->i * temp2.i, q__2.i = + alpha->r * temp2.i + alpha->i * temp2.r; + q__1.r = y[i__4].r + q__2.r, q__1.i = y[i__4].i + q__2.i; + y[i__3].r = q__1.r, y[i__3].i = q__1.i; +/* L100: */ + } + } else { + jx = kx; + jy = ky; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__3 = jx; + q__1.r = alpha->r * x[i__3].r - alpha->i * x[i__3].i, q__1.i = + alpha->r * x[i__3].i + alpha->i * x[i__3].r; + temp1.r = q__1.r, temp1.i = q__1.i; + temp2.r = 0.f, temp2.i = 0.f; + i__3 = jy; + i__4 = jy; + i__2 = j * a_dim1 + 1; + r__1 = a[i__2].r; + q__2.r = r__1 * temp1.r, q__2.i = r__1 * temp1.i; + q__1.r = y[i__4].r + q__2.r, q__1.i = y[i__4].i + q__2.i; + y[i__3].r = q__1.r, y[i__3].i = q__1.i; + l = 1 - j; + ix = jx; + iy = jy; +/* Computing MIN */ + i__4 = *n, i__2 = j + *k; + i__3 = min(i__4,i__2); + for (i__ = j + 1; i__ <= i__3; ++i__) { + ix += *incx; + iy += *incy; + i__4 = iy; + i__2 = iy; + i__5 = l + i__ + j * a_dim1; + q__2.r = temp1.r * a[i__5].r - temp1.i * a[i__5].i, + q__2.i = temp1.r * a[i__5].i + temp1.i * a[i__5] + .r; + q__1.r = y[i__2].r + q__2.r, q__1.i = y[i__2].i + q__2.i; + y[i__4].r = q__1.r, y[i__4].i = q__1.i; + r_cnjg(&q__3, &a[l + i__ + j * a_dim1]); + i__4 = ix; + q__2.r = q__3.r * x[i__4].r - q__3.i * x[i__4].i, q__2.i = + q__3.r * x[i__4].i + q__3.i * x[i__4].r; + q__1.r = temp2.r + q__2.r, q__1.i = temp2.i + q__2.i; + temp2.r = q__1.r, temp2.i = q__1.i; +/* L110: */ + } + i__3 = jy; + i__4 = jy; + q__2.r = alpha->r * temp2.r - alpha->i * temp2.i, q__2.i = + alpha->r * temp2.i + alpha->i * temp2.r; + q__1.r = y[i__4].r + q__2.r, q__1.i = y[i__4].i + q__2.i; + y[i__3].r = q__1.r, y[i__3].i = q__1.i; + jx += *incx; + jy += *incy; +/* L120: */ + } + } + } + + return 0; + +/* End of CHBMV . */ + +} /* chbmv_ */ + diff --git a/ground/gcs/src/libs/eigen/blas/f2c/chpmv.c b/ground/gcs/src/libs/eigen/blas/f2c/chpmv.c new file mode 100644 index 0000000000..65bab1c7fc --- /dev/null +++ b/ground/gcs/src/libs/eigen/blas/f2c/chpmv.c @@ -0,0 +1,438 @@ +/* chpmv.f -- translated by f2c (version 20100827). + You must link the resulting object file with libf2c: + on Microsoft Windows system, link with libf2c.lib; + on Linux or Unix systems, link with .../path/to/libf2c.a -lm + or, if you install libf2c.a in a standard place, with -lf2c -lm + -- in that order, at the end of the command line, as in + cc *.o -lf2c -lm + Source for libf2c is in /netlib/f2c/libf2c.zip, e.g., + + http://www.netlib.org/f2c/libf2c.zip +*/ + +#include "datatypes.h" + +/* Subroutine */ int chpmv_(char *uplo, integer *n, complex *alpha, complex * + ap, complex *x, integer *incx, complex *beta, complex *y, integer * + incy, ftnlen uplo_len) +{ + /* System generated locals */ + integer i__1, i__2, i__3, i__4, i__5; + real r__1; + complex q__1, q__2, q__3, q__4; + + /* Builtin functions */ + void r_cnjg(complex *, complex *); + + /* Local variables */ + integer i__, j, k, kk, ix, iy, jx, jy, kx, ky, info; + complex temp1, temp2; + extern logical lsame_(char *, char *, ftnlen, ftnlen); + extern /* Subroutine */ int xerbla_(char *, integer *, ftnlen); + +/* .. Scalar Arguments .. */ +/* .. */ +/* .. Array Arguments .. */ +/* .. */ + +/* Purpose */ +/* ======= */ + +/* CHPMV performs the matrix-vector operation */ + +/* y := alpha*A*x + beta*y, */ + +/* where alpha and beta are scalars, x and y are n element vectors and */ +/* A is an n by n hermitian matrix, supplied in packed form. */ + +/* Arguments */ +/* ========== */ + +/* UPLO - CHARACTER*1. */ +/* On entry, UPLO specifies whether the upper or lower */ +/* triangular part of the matrix A is supplied in the packed */ +/* array AP as follows: */ + +/* UPLO = 'U' or 'u' The upper triangular part of A is */ +/* supplied in AP. */ + +/* UPLO = 'L' or 'l' The lower triangular part of A is */ +/* supplied in AP. */ + +/* Unchanged on exit. */ + +/* N - INTEGER. */ +/* On entry, N specifies the order of the matrix A. */ +/* N must be at least zero. */ +/* Unchanged on exit. */ + +/* ALPHA - COMPLEX . */ +/* On entry, ALPHA specifies the scalar alpha. */ +/* Unchanged on exit. */ + +/* AP - COMPLEX array of DIMENSION at least */ +/* ( ( n*( n + 1 ) )/2 ). */ +/* Before entry with UPLO = 'U' or 'u', the array AP must */ +/* contain the upper triangular part of the hermitian matrix */ +/* packed sequentially, column by column, so that AP( 1 ) */ +/* contains a( 1, 1 ), AP( 2 ) and AP( 3 ) contain a( 1, 2 ) */ +/* and a( 2, 2 ) respectively, and so on. */ +/* Before entry with UPLO = 'L' or 'l', the array AP must */ +/* contain the lower triangular part of the hermitian matrix */ +/* packed sequentially, column by column, so that AP( 1 ) */ +/* contains a( 1, 1 ), AP( 2 ) and AP( 3 ) contain a( 2, 1 ) */ +/* and a( 3, 1 ) respectively, and so on. */ +/* Note that the imaginary parts of the diagonal elements need */ +/* not be set and are assumed to be zero. */ +/* Unchanged on exit. */ + +/* X - COMPLEX array of dimension at least */ +/* ( 1 + ( n - 1 )*abs( INCX ) ). */ +/* Before entry, the incremented array X must contain the n */ +/* element vector x. */ +/* Unchanged on exit. */ + +/* INCX - INTEGER. */ +/* On entry, INCX specifies the increment for the elements of */ +/* X. INCX must not be zero. */ +/* Unchanged on exit. */ + +/* BETA - COMPLEX . */ +/* On entry, BETA specifies the scalar beta. When BETA is */ +/* supplied as zero then Y need not be set on input. */ +/* Unchanged on exit. */ + +/* Y - COMPLEX array of dimension at least */ +/* ( 1 + ( n - 1 )*abs( INCY ) ). */ +/* Before entry, the incremented array Y must contain the n */ +/* element vector y. On exit, Y is overwritten by the updated */ +/* vector y. */ + +/* INCY - INTEGER. */ +/* On entry, INCY specifies the increment for the elements of */ +/* Y. INCY must not be zero. */ +/* Unchanged on exit. */ + +/* Further Details */ +/* =============== */ + +/* Level 2 Blas routine. */ + +/* -- Written on 22-October-1986. */ +/* Jack Dongarra, Argonne National Lab. */ +/* Jeremy Du Croz, Nag Central Office. */ +/* Sven Hammarling, Nag Central Office. */ +/* Richard Hanson, Sandia National Labs. */ + +/* ===================================================================== */ + +/* .. Parameters .. */ +/* .. */ +/* .. Local Scalars .. */ +/* .. */ +/* .. External Functions .. */ +/* .. */ +/* .. External Subroutines .. */ +/* .. */ +/* .. Intrinsic Functions .. */ +/* .. */ + +/* Test the input parameters. */ + + /* Parameter adjustments */ + --y; + --x; + --ap; + + /* Function Body */ + info = 0; + if (! lsame_(uplo, "U", (ftnlen)1, (ftnlen)1) && ! lsame_(uplo, "L", ( + ftnlen)1, (ftnlen)1)) { + info = 1; + } else if (*n < 0) { + info = 2; + } else if (*incx == 0) { + info = 6; + } else if (*incy == 0) { + info = 9; + } + if (info != 0) { + xerbla_("CHPMV ", &info, (ftnlen)6); + return 0; + } + +/* Quick return if possible. */ + + if (*n == 0 || (alpha->r == 0.f && alpha->i == 0.f && (beta->r == 1.f && + beta->i == 0.f))) { + return 0; + } + +/* Set up the start points in X and Y. */ + + if (*incx > 0) { + kx = 1; + } else { + kx = 1 - (*n - 1) * *incx; + } + if (*incy > 0) { + ky = 1; + } else { + ky = 1 - (*n - 1) * *incy; + } + +/* Start the operations. In this version the elements of the array AP */ +/* are accessed sequentially with one pass through AP. */ + +/* First form y := beta*y. */ + + if (beta->r != 1.f || beta->i != 0.f) { + if (*incy == 1) { + if (beta->r == 0.f && beta->i == 0.f) { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__; + y[i__2].r = 0.f, y[i__2].i = 0.f; +/* L10: */ + } + } else { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__; + i__3 = i__; + q__1.r = beta->r * y[i__3].r - beta->i * y[i__3].i, + q__1.i = beta->r * y[i__3].i + beta->i * y[i__3] + .r; + y[i__2].r = q__1.r, y[i__2].i = q__1.i; +/* L20: */ + } + } + } else { + iy = ky; + if (beta->r == 0.f && beta->i == 0.f) { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = iy; + y[i__2].r = 0.f, y[i__2].i = 0.f; + iy += *incy; +/* L30: */ + } + } else { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = iy; + i__3 = iy; + q__1.r = beta->r * y[i__3].r - beta->i * y[i__3].i, + q__1.i = beta->r * y[i__3].i + beta->i * y[i__3] + .r; + y[i__2].r = q__1.r, y[i__2].i = q__1.i; + iy += *incy; +/* L40: */ + } + } + } + } + if (alpha->r == 0.f && alpha->i == 0.f) { + return 0; + } + kk = 1; + if (lsame_(uplo, "U", (ftnlen)1, (ftnlen)1)) { + +/* Form y when AP contains the upper triangle. */ + + if (*incx == 1 && *incy == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j; + q__1.r = alpha->r * x[i__2].r - alpha->i * x[i__2].i, q__1.i = + alpha->r * x[i__2].i + alpha->i * x[i__2].r; + temp1.r = q__1.r, temp1.i = q__1.i; + temp2.r = 0.f, temp2.i = 0.f; + k = kk; + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__; + i__4 = i__; + i__5 = k; + q__2.r = temp1.r * ap[i__5].r - temp1.i * ap[i__5].i, + q__2.i = temp1.r * ap[i__5].i + temp1.i * ap[i__5] + .r; + q__1.r = y[i__4].r + q__2.r, q__1.i = y[i__4].i + q__2.i; + y[i__3].r = q__1.r, y[i__3].i = q__1.i; + r_cnjg(&q__3, &ap[k]); + i__3 = i__; + q__2.r = q__3.r * x[i__3].r - q__3.i * x[i__3].i, q__2.i = + q__3.r * x[i__3].i + q__3.i * x[i__3].r; + q__1.r = temp2.r + q__2.r, q__1.i = temp2.i + q__2.i; + temp2.r = q__1.r, temp2.i = q__1.i; + ++k; +/* L50: */ + } + i__2 = j; + i__3 = j; + i__4 = kk + j - 1; + r__1 = ap[i__4].r; + q__3.r = r__1 * temp1.r, q__3.i = r__1 * temp1.i; + q__2.r = y[i__3].r + q__3.r, q__2.i = y[i__3].i + q__3.i; + q__4.r = alpha->r * temp2.r - alpha->i * temp2.i, q__4.i = + alpha->r * temp2.i + alpha->i * temp2.r; + q__1.r = q__2.r + q__4.r, q__1.i = q__2.i + q__4.i; + y[i__2].r = q__1.r, y[i__2].i = q__1.i; + kk += j; +/* L60: */ + } + } else { + jx = kx; + jy = ky; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = jx; + q__1.r = alpha->r * x[i__2].r - alpha->i * x[i__2].i, q__1.i = + alpha->r * x[i__2].i + alpha->i * x[i__2].r; + temp1.r = q__1.r, temp1.i = q__1.i; + temp2.r = 0.f, temp2.i = 0.f; + ix = kx; + iy = ky; + i__2 = kk + j - 2; + for (k = kk; k <= i__2; ++k) { + i__3 = iy; + i__4 = iy; + i__5 = k; + q__2.r = temp1.r * ap[i__5].r - temp1.i * ap[i__5].i, + q__2.i = temp1.r * ap[i__5].i + temp1.i * ap[i__5] + .r; + q__1.r = y[i__4].r + q__2.r, q__1.i = y[i__4].i + q__2.i; + y[i__3].r = q__1.r, y[i__3].i = q__1.i; + r_cnjg(&q__3, &ap[k]); + i__3 = ix; + q__2.r = q__3.r * x[i__3].r - q__3.i * x[i__3].i, q__2.i = + q__3.r * x[i__3].i + q__3.i * x[i__3].r; + q__1.r = temp2.r + q__2.r, q__1.i = temp2.i + q__2.i; + temp2.r = q__1.r, temp2.i = q__1.i; + ix += *incx; + iy += *incy; +/* L70: */ + } + i__2 = jy; + i__3 = jy; + i__4 = kk + j - 1; + r__1 = ap[i__4].r; + q__3.r = r__1 * temp1.r, q__3.i = r__1 * temp1.i; + q__2.r = y[i__3].r + q__3.r, q__2.i = y[i__3].i + q__3.i; + q__4.r = alpha->r * temp2.r - alpha->i * temp2.i, q__4.i = + alpha->r * temp2.i + alpha->i * temp2.r; + q__1.r = q__2.r + q__4.r, q__1.i = q__2.i + q__4.i; + y[i__2].r = q__1.r, y[i__2].i = q__1.i; + jx += *incx; + jy += *incy; + kk += j; +/* L80: */ + } + } + } else { + +/* Form y when AP contains the lower triangle. */ + + if (*incx == 1 && *incy == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j; + q__1.r = alpha->r * x[i__2].r - alpha->i * x[i__2].i, q__1.i = + alpha->r * x[i__2].i + alpha->i * x[i__2].r; + temp1.r = q__1.r, temp1.i = q__1.i; + temp2.r = 0.f, temp2.i = 0.f; + i__2 = j; + i__3 = j; + i__4 = kk; + r__1 = ap[i__4].r; + q__2.r = r__1 * temp1.r, q__2.i = r__1 * temp1.i; + q__1.r = y[i__3].r + q__2.r, q__1.i = y[i__3].i + q__2.i; + y[i__2].r = q__1.r, y[i__2].i = q__1.i; + k = kk + 1; + i__2 = *n; + for (i__ = j + 1; i__ <= i__2; ++i__) { + i__3 = i__; + i__4 = i__; + i__5 = k; + q__2.r = temp1.r * ap[i__5].r - temp1.i * ap[i__5].i, + q__2.i = temp1.r * ap[i__5].i + temp1.i * ap[i__5] + .r; + q__1.r = y[i__4].r + q__2.r, q__1.i = y[i__4].i + q__2.i; + y[i__3].r = q__1.r, y[i__3].i = q__1.i; + r_cnjg(&q__3, &ap[k]); + i__3 = i__; + q__2.r = q__3.r * x[i__3].r - q__3.i * x[i__3].i, q__2.i = + q__3.r * x[i__3].i + q__3.i * x[i__3].r; + q__1.r = temp2.r + q__2.r, q__1.i = temp2.i + q__2.i; + temp2.r = q__1.r, temp2.i = q__1.i; + ++k; +/* L90: */ + } + i__2 = j; + i__3 = j; + q__2.r = alpha->r * temp2.r - alpha->i * temp2.i, q__2.i = + alpha->r * temp2.i + alpha->i * temp2.r; + q__1.r = y[i__3].r + q__2.r, q__1.i = y[i__3].i + q__2.i; + y[i__2].r = q__1.r, y[i__2].i = q__1.i; + kk += *n - j + 1; +/* L100: */ + } + } else { + jx = kx; + jy = ky; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = jx; + q__1.r = alpha->r * x[i__2].r - alpha->i * x[i__2].i, q__1.i = + alpha->r * x[i__2].i + alpha->i * x[i__2].r; + temp1.r = q__1.r, temp1.i = q__1.i; + temp2.r = 0.f, temp2.i = 0.f; + i__2 = jy; + i__3 = jy; + i__4 = kk; + r__1 = ap[i__4].r; + q__2.r = r__1 * temp1.r, q__2.i = r__1 * temp1.i; + q__1.r = y[i__3].r + q__2.r, q__1.i = y[i__3].i + q__2.i; + y[i__2].r = q__1.r, y[i__2].i = q__1.i; + ix = jx; + iy = jy; + i__2 = kk + *n - j; + for (k = kk + 1; k <= i__2; ++k) { + ix += *incx; + iy += *incy; + i__3 = iy; + i__4 = iy; + i__5 = k; + q__2.r = temp1.r * ap[i__5].r - temp1.i * ap[i__5].i, + q__2.i = temp1.r * ap[i__5].i + temp1.i * ap[i__5] + .r; + q__1.r = y[i__4].r + q__2.r, q__1.i = y[i__4].i + q__2.i; + y[i__3].r = q__1.r, y[i__3].i = q__1.i; + r_cnjg(&q__3, &ap[k]); + i__3 = ix; + q__2.r = q__3.r * x[i__3].r - q__3.i * x[i__3].i, q__2.i = + q__3.r * x[i__3].i + q__3.i * x[i__3].r; + q__1.r = temp2.r + q__2.r, q__1.i = temp2.i + q__2.i; + temp2.r = q__1.r, temp2.i = q__1.i; +/* L110: */ + } + i__2 = jy; + i__3 = jy; + q__2.r = alpha->r * temp2.r - alpha->i * temp2.i, q__2.i = + alpha->r * temp2.i + alpha->i * temp2.r; + q__1.r = y[i__3].r + q__2.r, q__1.i = y[i__3].i + q__2.i; + y[i__2].r = q__1.r, y[i__2].i = q__1.i; + jx += *incx; + jy += *incy; + kk += *n - j + 1; +/* L120: */ + } + } + } + + return 0; + +/* End of CHPMV . */ + +} /* chpmv_ */ + diff --git a/ground/gcs/src/libs/eigen/blas/f2c/complexdots.c b/ground/gcs/src/libs/eigen/blas/f2c/complexdots.c new file mode 100644 index 0000000000..a856a231c3 --- /dev/null +++ b/ground/gcs/src/libs/eigen/blas/f2c/complexdots.c @@ -0,0 +1,84 @@ +/* This file has been modified to use the standard gfortran calling + convention, rather than the f2c calling convention. + + It does not require -ff2c when compiled with gfortran. +*/ + +/* complexdots.f -- translated by f2c (version 20100827). + You must link the resulting object file with libf2c: + on Microsoft Windows system, link with libf2c.lib; + on Linux or Unix systems, link with .../path/to/libf2c.a -lm + or, if you install libf2c.a in a standard place, with -lf2c -lm + -- in that order, at the end of the command line, as in + cc *.o -lf2c -lm + Source for libf2c is in /netlib/f2c/libf2c.zip, e.g., + + http://www.netlib.org/f2c/libf2c.zip +*/ + +#include "datatypes.h" + +complex cdotc_(integer *n, complex *cx, integer + *incx, complex *cy, integer *incy) +{ + complex res; + extern /* Subroutine */ int cdotcw_(integer *, complex *, integer *, + complex *, integer *, complex *); + + /* Parameter adjustments */ + --cy; + --cx; + + /* Function Body */ + cdotcw_(n, &cx[1], incx, &cy[1], incy, &res); + return res; +} /* cdotc_ */ + +complex cdotu_(integer *n, complex *cx, integer + *incx, complex *cy, integer *incy) +{ + complex res; + extern /* Subroutine */ int cdotuw_(integer *, complex *, integer *, + complex *, integer *, complex *); + + /* Parameter adjustments */ + --cy; + --cx; + + /* Function Body */ + cdotuw_(n, &cx[1], incx, &cy[1], incy, &res); + return res; +} /* cdotu_ */ + +doublecomplex zdotc_(integer *n, doublecomplex *cx, integer *incx, + doublecomplex *cy, integer *incy) +{ + doublecomplex res; + extern /* Subroutine */ int zdotcw_(integer *, doublecomplex *, integer *, + doublecomplex *, integer *, doublecomplex *); + + /* Parameter adjustments */ + --cy; + --cx; + + /* Function Body */ + zdotcw_(n, &cx[1], incx, &cy[1], incy, &res); + return res; +} /* zdotc_ */ + +doublecomplex zdotu_(integer *n, doublecomplex *cx, integer *incx, + doublecomplex *cy, integer *incy) +{ + doublecomplex res; + extern /* Subroutine */ int zdotuw_(integer *, doublecomplex *, integer *, + doublecomplex *, integer *, doublecomplex *); + + /* Parameter adjustments */ + --cy; + --cx; + + /* Function Body */ + zdotuw_(n, &cx[1], incx, &cy[1], incy, &res); + return res; +} /* zdotu_ */ + diff --git a/ground/gcs/src/libs/eigen/blas/f2c/ctbmv.c b/ground/gcs/src/libs/eigen/blas/f2c/ctbmv.c new file mode 100644 index 0000000000..790fd581fe --- /dev/null +++ b/ground/gcs/src/libs/eigen/blas/f2c/ctbmv.c @@ -0,0 +1,647 @@ +/* ctbmv.f -- translated by f2c (version 20100827). + You must link the resulting object file with libf2c: + on Microsoft Windows system, link with libf2c.lib; + on Linux or Unix systems, link with .../path/to/libf2c.a -lm + or, if you install libf2c.a in a standard place, with -lf2c -lm + -- in that order, at the end of the command line, as in + cc *.o -lf2c -lm + Source for libf2c is in /netlib/f2c/libf2c.zip, e.g., + + http://www.netlib.org/f2c/libf2c.zip +*/ + +#include "datatypes.h" + +/* Subroutine */ int ctbmv_(char *uplo, char *trans, char *diag, integer *n, + integer *k, complex *a, integer *lda, complex *x, integer *incx, + ftnlen uplo_len, ftnlen trans_len, ftnlen diag_len) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4, i__5; + complex q__1, q__2, q__3; + + /* Builtin functions */ + void r_cnjg(complex *, complex *); + + /* Local variables */ + integer i__, j, l, ix, jx, kx, info; + complex temp; + extern logical lsame_(char *, char *, ftnlen, ftnlen); + integer kplus1; + extern /* Subroutine */ int xerbla_(char *, integer *, ftnlen); + logical noconj, nounit; + +/* .. Scalar Arguments .. */ +/* .. */ +/* .. Array Arguments .. */ +/* .. */ + +/* Purpose */ +/* ======= */ + +/* CTBMV performs one of the matrix-vector operations */ + +/* x := A*x, or x := A'*x, or x := conjg( A' )*x, */ + +/* where x is an n element vector and A is an n by n unit, or non-unit, */ +/* upper or lower triangular band matrix, with ( k + 1 ) diagonals. */ + +/* Arguments */ +/* ========== */ + +/* UPLO - CHARACTER*1. */ +/* On entry, UPLO specifies whether the matrix is an upper or */ +/* lower triangular matrix as follows: */ + +/* UPLO = 'U' or 'u' A is an upper triangular matrix. */ + +/* UPLO = 'L' or 'l' A is a lower triangular matrix. */ + +/* Unchanged on exit. */ + +/* TRANS - CHARACTER*1. */ +/* On entry, TRANS specifies the operation to be performed as */ +/* follows: */ + +/* TRANS = 'N' or 'n' x := A*x. */ + +/* TRANS = 'T' or 't' x := A'*x. */ + +/* TRANS = 'C' or 'c' x := conjg( A' )*x. */ + +/* Unchanged on exit. */ + +/* DIAG - CHARACTER*1. */ +/* On entry, DIAG specifies whether or not A is unit */ +/* triangular as follows: */ + +/* DIAG = 'U' or 'u' A is assumed to be unit triangular. */ + +/* DIAG = 'N' or 'n' A is not assumed to be unit */ +/* triangular. */ + +/* Unchanged on exit. */ + +/* N - INTEGER. */ +/* On entry, N specifies the order of the matrix A. */ +/* N must be at least zero. */ +/* Unchanged on exit. */ + +/* K - INTEGER. */ +/* On entry with UPLO = 'U' or 'u', K specifies the number of */ +/* super-diagonals of the matrix A. */ +/* On entry with UPLO = 'L' or 'l', K specifies the number of */ +/* sub-diagonals of the matrix A. */ +/* K must satisfy 0 .le. K. */ +/* Unchanged on exit. */ + +/* A - COMPLEX array of DIMENSION ( LDA, n ). */ +/* Before entry with UPLO = 'U' or 'u', the leading ( k + 1 ) */ +/* by n part of the array A must contain the upper triangular */ +/* band part of the matrix of coefficients, supplied column by */ +/* column, with the leading diagonal of the matrix in row */ +/* ( k + 1 ) of the array, the first super-diagonal starting at */ +/* position 2 in row k, and so on. The top left k by k triangle */ +/* of the array A is not referenced. */ +/* The following program segment will transfer an upper */ +/* triangular band matrix from conventional full matrix storage */ +/* to band storage: */ + +/* DO 20, J = 1, N */ +/* M = K + 1 - J */ +/* DO 10, I = MAX( 1, J - K ), J */ +/* A( M + I, J ) = matrix( I, J ) */ +/* 10 CONTINUE */ +/* 20 CONTINUE */ + +/* Before entry with UPLO = 'L' or 'l', the leading ( k + 1 ) */ +/* by n part of the array A must contain the lower triangular */ +/* band part of the matrix of coefficients, supplied column by */ +/* column, with the leading diagonal of the matrix in row 1 of */ +/* the array, the first sub-diagonal starting at position 1 in */ +/* row 2, and so on. The bottom right k by k triangle of the */ +/* array A is not referenced. */ +/* The following program segment will transfer a lower */ +/* triangular band matrix from conventional full matrix storage */ +/* to band storage: */ + +/* DO 20, J = 1, N */ +/* M = 1 - J */ +/* DO 10, I = J, MIN( N, J + K ) */ +/* A( M + I, J ) = matrix( I, J ) */ +/* 10 CONTINUE */ +/* 20 CONTINUE */ + +/* Note that when DIAG = 'U' or 'u' the elements of the array A */ +/* corresponding to the diagonal elements of the matrix are not */ +/* referenced, but are assumed to be unity. */ +/* Unchanged on exit. */ + +/* LDA - INTEGER. */ +/* On entry, LDA specifies the first dimension of A as declared */ +/* in the calling (sub) program. LDA must be at least */ +/* ( k + 1 ). */ +/* Unchanged on exit. */ + +/* X - COMPLEX array of dimension at least */ +/* ( 1 + ( n - 1 )*abs( INCX ) ). */ +/* Before entry, the incremented array X must contain the n */ +/* element vector x. On exit, X is overwritten with the */ +/* tranformed vector x. */ + +/* INCX - INTEGER. */ +/* On entry, INCX specifies the increment for the elements of */ +/* X. INCX must not be zero. */ +/* Unchanged on exit. */ + +/* Further Details */ +/* =============== */ + +/* Level 2 Blas routine. */ + +/* -- Written on 22-October-1986. */ +/* Jack Dongarra, Argonne National Lab. */ +/* Jeremy Du Croz, Nag Central Office. */ +/* Sven Hammarling, Nag Central Office. */ +/* Richard Hanson, Sandia National Labs. */ + +/* ===================================================================== */ + +/* .. Parameters .. */ +/* .. */ +/* .. Local Scalars .. */ +/* .. */ +/* .. External Functions .. */ +/* .. */ +/* .. External Subroutines .. */ +/* .. */ +/* .. Intrinsic Functions .. */ +/* .. */ + +/* Test the input parameters. */ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --x; + + /* Function Body */ + info = 0; + if (! lsame_(uplo, "U", (ftnlen)1, (ftnlen)1) && ! lsame_(uplo, "L", ( + ftnlen)1, (ftnlen)1)) { + info = 1; + } else if (! lsame_(trans, "N", (ftnlen)1, (ftnlen)1) && ! lsame_(trans, + "T", (ftnlen)1, (ftnlen)1) && ! lsame_(trans, "C", (ftnlen)1, ( + ftnlen)1)) { + info = 2; + } else if (! lsame_(diag, "U", (ftnlen)1, (ftnlen)1) && ! lsame_(diag, + "N", (ftnlen)1, (ftnlen)1)) { + info = 3; + } else if (*n < 0) { + info = 4; + } else if (*k < 0) { + info = 5; + } else if (*lda < *k + 1) { + info = 7; + } else if (*incx == 0) { + info = 9; + } + if (info != 0) { + xerbla_("CTBMV ", &info, (ftnlen)6); + return 0; + } + +/* Quick return if possible. */ + + if (*n == 0) { + return 0; + } + + noconj = lsame_(trans, "T", (ftnlen)1, (ftnlen)1); + nounit = lsame_(diag, "N", (ftnlen)1, (ftnlen)1); + +/* Set up the start point in X if the increment is not unity. This */ +/* will be ( N - 1 )*INCX too small for descending loops. */ + + if (*incx <= 0) { + kx = 1 - (*n - 1) * *incx; + } else if (*incx != 1) { + kx = 1; + } + +/* Start the operations. In this version the elements of A are */ +/* accessed sequentially with one pass through A. */ + + if (lsame_(trans, "N", (ftnlen)1, (ftnlen)1)) { + +/* Form x := A*x. */ + + if (lsame_(uplo, "U", (ftnlen)1, (ftnlen)1)) { + kplus1 = *k + 1; + if (*incx == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j; + if (x[i__2].r != 0.f || x[i__2].i != 0.f) { + i__2 = j; + temp.r = x[i__2].r, temp.i = x[i__2].i; + l = kplus1 - j; +/* Computing MAX */ + i__2 = 1, i__3 = j - *k; + i__4 = j - 1; + for (i__ = max(i__2,i__3); i__ <= i__4; ++i__) { + i__2 = i__; + i__3 = i__; + i__5 = l + i__ + j * a_dim1; + q__2.r = temp.r * a[i__5].r - temp.i * a[i__5].i, + q__2.i = temp.r * a[i__5].i + temp.i * a[ + i__5].r; + q__1.r = x[i__3].r + q__2.r, q__1.i = x[i__3].i + + q__2.i; + x[i__2].r = q__1.r, x[i__2].i = q__1.i; +/* L10: */ + } + if (nounit) { + i__4 = j; + i__2 = j; + i__3 = kplus1 + j * a_dim1; + q__1.r = x[i__2].r * a[i__3].r - x[i__2].i * a[ + i__3].i, q__1.i = x[i__2].r * a[i__3].i + + x[i__2].i * a[i__3].r; + x[i__4].r = q__1.r, x[i__4].i = q__1.i; + } + } +/* L20: */ + } + } else { + jx = kx; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__4 = jx; + if (x[i__4].r != 0.f || x[i__4].i != 0.f) { + i__4 = jx; + temp.r = x[i__4].r, temp.i = x[i__4].i; + ix = kx; + l = kplus1 - j; +/* Computing MAX */ + i__4 = 1, i__2 = j - *k; + i__3 = j - 1; + for (i__ = max(i__4,i__2); i__ <= i__3; ++i__) { + i__4 = ix; + i__2 = ix; + i__5 = l + i__ + j * a_dim1; + q__2.r = temp.r * a[i__5].r - temp.i * a[i__5].i, + q__2.i = temp.r * a[i__5].i + temp.i * a[ + i__5].r; + q__1.r = x[i__2].r + q__2.r, q__1.i = x[i__2].i + + q__2.i; + x[i__4].r = q__1.r, x[i__4].i = q__1.i; + ix += *incx; +/* L30: */ + } + if (nounit) { + i__3 = jx; + i__4 = jx; + i__2 = kplus1 + j * a_dim1; + q__1.r = x[i__4].r * a[i__2].r - x[i__4].i * a[ + i__2].i, q__1.i = x[i__4].r * a[i__2].i + + x[i__4].i * a[i__2].r; + x[i__3].r = q__1.r, x[i__3].i = q__1.i; + } + } + jx += *incx; + if (j > *k) { + kx += *incx; + } +/* L40: */ + } + } + } else { + if (*incx == 1) { + for (j = *n; j >= 1; --j) { + i__1 = j; + if (x[i__1].r != 0.f || x[i__1].i != 0.f) { + i__1 = j; + temp.r = x[i__1].r, temp.i = x[i__1].i; + l = 1 - j; +/* Computing MIN */ + i__1 = *n, i__3 = j + *k; + i__4 = j + 1; + for (i__ = min(i__1,i__3); i__ >= i__4; --i__) { + i__1 = i__; + i__3 = i__; + i__2 = l + i__ + j * a_dim1; + q__2.r = temp.r * a[i__2].r - temp.i * a[i__2].i, + q__2.i = temp.r * a[i__2].i + temp.i * a[ + i__2].r; + q__1.r = x[i__3].r + q__2.r, q__1.i = x[i__3].i + + q__2.i; + x[i__1].r = q__1.r, x[i__1].i = q__1.i; +/* L50: */ + } + if (nounit) { + i__4 = j; + i__1 = j; + i__3 = j * a_dim1 + 1; + q__1.r = x[i__1].r * a[i__3].r - x[i__1].i * a[ + i__3].i, q__1.i = x[i__1].r * a[i__3].i + + x[i__1].i * a[i__3].r; + x[i__4].r = q__1.r, x[i__4].i = q__1.i; + } + } +/* L60: */ + } + } else { + kx += (*n - 1) * *incx; + jx = kx; + for (j = *n; j >= 1; --j) { + i__4 = jx; + if (x[i__4].r != 0.f || x[i__4].i != 0.f) { + i__4 = jx; + temp.r = x[i__4].r, temp.i = x[i__4].i; + ix = kx; + l = 1 - j; +/* Computing MIN */ + i__4 = *n, i__1 = j + *k; + i__3 = j + 1; + for (i__ = min(i__4,i__1); i__ >= i__3; --i__) { + i__4 = ix; + i__1 = ix; + i__2 = l + i__ + j * a_dim1; + q__2.r = temp.r * a[i__2].r - temp.i * a[i__2].i, + q__2.i = temp.r * a[i__2].i + temp.i * a[ + i__2].r; + q__1.r = x[i__1].r + q__2.r, q__1.i = x[i__1].i + + q__2.i; + x[i__4].r = q__1.r, x[i__4].i = q__1.i; + ix -= *incx; +/* L70: */ + } + if (nounit) { + i__3 = jx; + i__4 = jx; + i__1 = j * a_dim1 + 1; + q__1.r = x[i__4].r * a[i__1].r - x[i__4].i * a[ + i__1].i, q__1.i = x[i__4].r * a[i__1].i + + x[i__4].i * a[i__1].r; + x[i__3].r = q__1.r, x[i__3].i = q__1.i; + } + } + jx -= *incx; + if (*n - j >= *k) { + kx -= *incx; + } +/* L80: */ + } + } + } + } else { + +/* Form x := A'*x or x := conjg( A' )*x. */ + + if (lsame_(uplo, "U", (ftnlen)1, (ftnlen)1)) { + kplus1 = *k + 1; + if (*incx == 1) { + for (j = *n; j >= 1; --j) { + i__3 = j; + temp.r = x[i__3].r, temp.i = x[i__3].i; + l = kplus1 - j; + if (noconj) { + if (nounit) { + i__3 = kplus1 + j * a_dim1; + q__1.r = temp.r * a[i__3].r - temp.i * a[i__3].i, + q__1.i = temp.r * a[i__3].i + temp.i * a[ + i__3].r; + temp.r = q__1.r, temp.i = q__1.i; + } +/* Computing MAX */ + i__4 = 1, i__1 = j - *k; + i__3 = max(i__4,i__1); + for (i__ = j - 1; i__ >= i__3; --i__) { + i__4 = l + i__ + j * a_dim1; + i__1 = i__; + q__2.r = a[i__4].r * x[i__1].r - a[i__4].i * x[ + i__1].i, q__2.i = a[i__4].r * x[i__1].i + + a[i__4].i * x[i__1].r; + q__1.r = temp.r + q__2.r, q__1.i = temp.i + + q__2.i; + temp.r = q__1.r, temp.i = q__1.i; +/* L90: */ + } + } else { + if (nounit) { + r_cnjg(&q__2, &a[kplus1 + j * a_dim1]); + q__1.r = temp.r * q__2.r - temp.i * q__2.i, + q__1.i = temp.r * q__2.i + temp.i * + q__2.r; + temp.r = q__1.r, temp.i = q__1.i; + } +/* Computing MAX */ + i__4 = 1, i__1 = j - *k; + i__3 = max(i__4,i__1); + for (i__ = j - 1; i__ >= i__3; --i__) { + r_cnjg(&q__3, &a[l + i__ + j * a_dim1]); + i__4 = i__; + q__2.r = q__3.r * x[i__4].r - q__3.i * x[i__4].i, + q__2.i = q__3.r * x[i__4].i + q__3.i * x[ + i__4].r; + q__1.r = temp.r + q__2.r, q__1.i = temp.i + + q__2.i; + temp.r = q__1.r, temp.i = q__1.i; +/* L100: */ + } + } + i__3 = j; + x[i__3].r = temp.r, x[i__3].i = temp.i; +/* L110: */ + } + } else { + kx += (*n - 1) * *incx; + jx = kx; + for (j = *n; j >= 1; --j) { + i__3 = jx; + temp.r = x[i__3].r, temp.i = x[i__3].i; + kx -= *incx; + ix = kx; + l = kplus1 - j; + if (noconj) { + if (nounit) { + i__3 = kplus1 + j * a_dim1; + q__1.r = temp.r * a[i__3].r - temp.i * a[i__3].i, + q__1.i = temp.r * a[i__3].i + temp.i * a[ + i__3].r; + temp.r = q__1.r, temp.i = q__1.i; + } +/* Computing MAX */ + i__4 = 1, i__1 = j - *k; + i__3 = max(i__4,i__1); + for (i__ = j - 1; i__ >= i__3; --i__) { + i__4 = l + i__ + j * a_dim1; + i__1 = ix; + q__2.r = a[i__4].r * x[i__1].r - a[i__4].i * x[ + i__1].i, q__2.i = a[i__4].r * x[i__1].i + + a[i__4].i * x[i__1].r; + q__1.r = temp.r + q__2.r, q__1.i = temp.i + + q__2.i; + temp.r = q__1.r, temp.i = q__1.i; + ix -= *incx; +/* L120: */ + } + } else { + if (nounit) { + r_cnjg(&q__2, &a[kplus1 + j * a_dim1]); + q__1.r = temp.r * q__2.r - temp.i * q__2.i, + q__1.i = temp.r * q__2.i + temp.i * + q__2.r; + temp.r = q__1.r, temp.i = q__1.i; + } +/* Computing MAX */ + i__4 = 1, i__1 = j - *k; + i__3 = max(i__4,i__1); + for (i__ = j - 1; i__ >= i__3; --i__) { + r_cnjg(&q__3, &a[l + i__ + j * a_dim1]); + i__4 = ix; + q__2.r = q__3.r * x[i__4].r - q__3.i * x[i__4].i, + q__2.i = q__3.r * x[i__4].i + q__3.i * x[ + i__4].r; + q__1.r = temp.r + q__2.r, q__1.i = temp.i + + q__2.i; + temp.r = q__1.r, temp.i = q__1.i; + ix -= *incx; +/* L130: */ + } + } + i__3 = jx; + x[i__3].r = temp.r, x[i__3].i = temp.i; + jx -= *incx; +/* L140: */ + } + } + } else { + if (*incx == 1) { + i__3 = *n; + for (j = 1; j <= i__3; ++j) { + i__4 = j; + temp.r = x[i__4].r, temp.i = x[i__4].i; + l = 1 - j; + if (noconj) { + if (nounit) { + i__4 = j * a_dim1 + 1; + q__1.r = temp.r * a[i__4].r - temp.i * a[i__4].i, + q__1.i = temp.r * a[i__4].i + temp.i * a[ + i__4].r; + temp.r = q__1.r, temp.i = q__1.i; + } +/* Computing MIN */ + i__1 = *n, i__2 = j + *k; + i__4 = min(i__1,i__2); + for (i__ = j + 1; i__ <= i__4; ++i__) { + i__1 = l + i__ + j * a_dim1; + i__2 = i__; + q__2.r = a[i__1].r * x[i__2].r - a[i__1].i * x[ + i__2].i, q__2.i = a[i__1].r * x[i__2].i + + a[i__1].i * x[i__2].r; + q__1.r = temp.r + q__2.r, q__1.i = temp.i + + q__2.i; + temp.r = q__1.r, temp.i = q__1.i; +/* L150: */ + } + } else { + if (nounit) { + r_cnjg(&q__2, &a[j * a_dim1 + 1]); + q__1.r = temp.r * q__2.r - temp.i * q__2.i, + q__1.i = temp.r * q__2.i + temp.i * + q__2.r; + temp.r = q__1.r, temp.i = q__1.i; + } +/* Computing MIN */ + i__1 = *n, i__2 = j + *k; + i__4 = min(i__1,i__2); + for (i__ = j + 1; i__ <= i__4; ++i__) { + r_cnjg(&q__3, &a[l + i__ + j * a_dim1]); + i__1 = i__; + q__2.r = q__3.r * x[i__1].r - q__3.i * x[i__1].i, + q__2.i = q__3.r * x[i__1].i + q__3.i * x[ + i__1].r; + q__1.r = temp.r + q__2.r, q__1.i = temp.i + + q__2.i; + temp.r = q__1.r, temp.i = q__1.i; +/* L160: */ + } + } + i__4 = j; + x[i__4].r = temp.r, x[i__4].i = temp.i; +/* L170: */ + } + } else { + jx = kx; + i__3 = *n; + for (j = 1; j <= i__3; ++j) { + i__4 = jx; + temp.r = x[i__4].r, temp.i = x[i__4].i; + kx += *incx; + ix = kx; + l = 1 - j; + if (noconj) { + if (nounit) { + i__4 = j * a_dim1 + 1; + q__1.r = temp.r * a[i__4].r - temp.i * a[i__4].i, + q__1.i = temp.r * a[i__4].i + temp.i * a[ + i__4].r; + temp.r = q__1.r, temp.i = q__1.i; + } +/* Computing MIN */ + i__1 = *n, i__2 = j + *k; + i__4 = min(i__1,i__2); + for (i__ = j + 1; i__ <= i__4; ++i__) { + i__1 = l + i__ + j * a_dim1; + i__2 = ix; + q__2.r = a[i__1].r * x[i__2].r - a[i__1].i * x[ + i__2].i, q__2.i = a[i__1].r * x[i__2].i + + a[i__1].i * x[i__2].r; + q__1.r = temp.r + q__2.r, q__1.i = temp.i + + q__2.i; + temp.r = q__1.r, temp.i = q__1.i; + ix += *incx; +/* L180: */ + } + } else { + if (nounit) { + r_cnjg(&q__2, &a[j * a_dim1 + 1]); + q__1.r = temp.r * q__2.r - temp.i * q__2.i, + q__1.i = temp.r * q__2.i + temp.i * + q__2.r; + temp.r = q__1.r, temp.i = q__1.i; + } +/* Computing MIN */ + i__1 = *n, i__2 = j + *k; + i__4 = min(i__1,i__2); + for (i__ = j + 1; i__ <= i__4; ++i__) { + r_cnjg(&q__3, &a[l + i__ + j * a_dim1]); + i__1 = ix; + q__2.r = q__3.r * x[i__1].r - q__3.i * x[i__1].i, + q__2.i = q__3.r * x[i__1].i + q__3.i * x[ + i__1].r; + q__1.r = temp.r + q__2.r, q__1.i = temp.i + + q__2.i; + temp.r = q__1.r, temp.i = q__1.i; + ix += *incx; +/* L190: */ + } + } + i__4 = jx; + x[i__4].r = temp.r, x[i__4].i = temp.i; + jx += *incx; +/* L200: */ + } + } + } + } + + return 0; + +/* End of CTBMV . */ + +} /* ctbmv_ */ + diff --git a/ground/gcs/src/libs/eigen/blas/f2c/d_cnjg.c b/ground/gcs/src/libs/eigen/blas/f2c/d_cnjg.c new file mode 100644 index 0000000000..623090c6b0 --- /dev/null +++ b/ground/gcs/src/libs/eigen/blas/f2c/d_cnjg.c @@ -0,0 +1,6 @@ +#include "datatypes.h" + +void d_cnjg(doublecomplex *r, doublecomplex *z) { + r->r = z->r; + r->i = -(z->i); +} diff --git a/ground/gcs/src/libs/eigen/blas/f2c/datatypes.h b/ground/gcs/src/libs/eigen/blas/f2c/datatypes.h new file mode 100644 index 0000000000..63232b246a --- /dev/null +++ b/ground/gcs/src/libs/eigen/blas/f2c/datatypes.h @@ -0,0 +1,24 @@ +/* This contains a limited subset of the typedefs exposed by f2c + for use by the Eigen BLAS C-only implementation. +*/ + +#ifndef __EIGEN_DATATYPES_H__ +#define __EIGEN_DATATYPES_H__ + +typedef int integer; +typedef unsigned int uinteger; +typedef float real; +typedef double doublereal; +typedef struct { real r, i; } complex; +typedef struct { doublereal r, i; } doublecomplex; +typedef int ftnlen; +typedef int logical; + +#define abs(x) ((x) >= 0 ? (x) : -(x)) +#define dabs(x) (doublereal)abs(x) +#define min(a,b) ((a) <= (b) ? (a) : (b)) +#define max(a,b) ((a) >= (b) ? (a) : (b)) +#define dmin(a,b) (doublereal)min(a,b) +#define dmax(a,b) (doublereal)max(a,b) + +#endif diff --git a/ground/gcs/src/libs/eigen/blas/f2c/drotm.c b/ground/gcs/src/libs/eigen/blas/f2c/drotm.c new file mode 100644 index 0000000000..17a779b74b --- /dev/null +++ b/ground/gcs/src/libs/eigen/blas/f2c/drotm.c @@ -0,0 +1,215 @@ +/* drotm.f -- translated by f2c (version 20100827). + You must link the resulting object file with libf2c: + on Microsoft Windows system, link with libf2c.lib; + on Linux or Unix systems, link with .../path/to/libf2c.a -lm + or, if you install libf2c.a in a standard place, with -lf2c -lm + -- in that order, at the end of the command line, as in + cc *.o -lf2c -lm + Source for libf2c is in /netlib/f2c/libf2c.zip, e.g., + + http://www.netlib.org/f2c/libf2c.zip +*/ + +#include "datatypes.h" + +/* Subroutine */ int drotm_(integer *n, doublereal *dx, integer *incx, + doublereal *dy, integer *incy, doublereal *dparam) +{ + /* Initialized data */ + + static doublereal zero = 0.; + static doublereal two = 2.; + + /* System generated locals */ + integer i__1, i__2; + + /* Local variables */ + integer i__; + doublereal w, z__; + integer kx, ky; + doublereal dh11, dh12, dh21, dh22, dflag; + integer nsteps; + +/* .. Scalar Arguments .. */ +/* .. */ +/* .. Array Arguments .. */ +/* .. */ + +/* Purpose */ +/* ======= */ + +/* APPLY THE MODIFIED GIVENS TRANSFORMATION, H, TO THE 2 BY N MATRIX */ + +/* (DX**T) , WHERE **T INDICATES TRANSPOSE. THE ELEMENTS OF DX ARE IN */ +/* (DY**T) */ + +/* DX(LX+I*INCX), I = 0 TO N-1, WHERE LX = 1 IF INCX .GE. 0, ELSE */ +/* LX = (-INCX)*N, AND SIMILARLY FOR SY USING LY AND INCY. */ +/* WITH DPARAM(1)=DFLAG, H HAS ONE OF THE FOLLOWING FORMS.. */ + +/* DFLAG=-1.D0 DFLAG=0.D0 DFLAG=1.D0 DFLAG=-2.D0 */ + +/* (DH11 DH12) (1.D0 DH12) (DH11 1.D0) (1.D0 0.D0) */ +/* H=( ) ( ) ( ) ( ) */ +/* (DH21 DH22), (DH21 1.D0), (-1.D0 DH22), (0.D0 1.D0). */ +/* SEE DROTMG FOR A DESCRIPTION OF DATA STORAGE IN DPARAM. */ + +/* Arguments */ +/* ========= */ + +/* N (input) INTEGER */ +/* number of elements in input vector(s) */ + +/* DX (input/output) DOUBLE PRECISION array, dimension N */ +/* double precision vector with N elements */ + +/* INCX (input) INTEGER */ +/* storage spacing between elements of DX */ + +/* DY (input/output) DOUBLE PRECISION array, dimension N */ +/* double precision vector with N elements */ + +/* INCY (input) INTEGER */ +/* storage spacing between elements of DY */ + +/* DPARAM (input/output) DOUBLE PRECISION array, dimension 5 */ +/* DPARAM(1)=DFLAG */ +/* DPARAM(2)=DH11 */ +/* DPARAM(3)=DH21 */ +/* DPARAM(4)=DH12 */ +/* DPARAM(5)=DH22 */ + +/* ===================================================================== */ + +/* .. Local Scalars .. */ +/* .. */ +/* .. Data statements .. */ + /* Parameter adjustments */ + --dparam; + --dy; + --dx; + + /* Function Body */ +/* .. */ + + dflag = dparam[1]; + if (*n <= 0 || dflag + two == zero) { + goto L140; + } + if (! (*incx == *incy && *incx > 0)) { + goto L70; + } + + nsteps = *n * *incx; + if (dflag < 0.) { + goto L50; + } else if (dflag == 0) { + goto L10; + } else { + goto L30; + } +L10: + dh12 = dparam[4]; + dh21 = dparam[3]; + i__1 = nsteps; + i__2 = *incx; + for (i__ = 1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) { + w = dx[i__]; + z__ = dy[i__]; + dx[i__] = w + z__ * dh12; + dy[i__] = w * dh21 + z__; +/* L20: */ + } + goto L140; +L30: + dh11 = dparam[2]; + dh22 = dparam[5]; + i__2 = nsteps; + i__1 = *incx; + for (i__ = 1; i__1 < 0 ? i__ >= i__2 : i__ <= i__2; i__ += i__1) { + w = dx[i__]; + z__ = dy[i__]; + dx[i__] = w * dh11 + z__; + dy[i__] = -w + dh22 * z__; +/* L40: */ + } + goto L140; +L50: + dh11 = dparam[2]; + dh12 = dparam[4]; + dh21 = dparam[3]; + dh22 = dparam[5]; + i__1 = nsteps; + i__2 = *incx; + for (i__ = 1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) { + w = dx[i__]; + z__ = dy[i__]; + dx[i__] = w * dh11 + z__ * dh12; + dy[i__] = w * dh21 + z__ * dh22; +/* L60: */ + } + goto L140; +L70: + kx = 1; + ky = 1; + if (*incx < 0) { + kx = (1 - *n) * *incx + 1; + } + if (*incy < 0) { + ky = (1 - *n) * *incy + 1; + } + + if (dflag < 0.) { + goto L120; + } else if (dflag == 0) { + goto L80; + } else { + goto L100; + } +L80: + dh12 = dparam[4]; + dh21 = dparam[3]; + i__2 = *n; + for (i__ = 1; i__ <= i__2; ++i__) { + w = dx[kx]; + z__ = dy[ky]; + dx[kx] = w + z__ * dh12; + dy[ky] = w * dh21 + z__; + kx += *incx; + ky += *incy; +/* L90: */ + } + goto L140; +L100: + dh11 = dparam[2]; + dh22 = dparam[5]; + i__2 = *n; + for (i__ = 1; i__ <= i__2; ++i__) { + w = dx[kx]; + z__ = dy[ky]; + dx[kx] = w * dh11 + z__; + dy[ky] = -w + dh22 * z__; + kx += *incx; + ky += *incy; +/* L110: */ + } + goto L140; +L120: + dh11 = dparam[2]; + dh12 = dparam[4]; + dh21 = dparam[3]; + dh22 = dparam[5]; + i__2 = *n; + for (i__ = 1; i__ <= i__2; ++i__) { + w = dx[kx]; + z__ = dy[ky]; + dx[kx] = w * dh11 + z__ * dh12; + dy[ky] = w * dh21 + z__ * dh22; + kx += *incx; + ky += *incy; +/* L130: */ + } +L140: + return 0; +} /* drotm_ */ + diff --git a/ground/gcs/src/libs/eigen/blas/f2c/drotmg.c b/ground/gcs/src/libs/eigen/blas/f2c/drotmg.c new file mode 100644 index 0000000000..a63eb10834 --- /dev/null +++ b/ground/gcs/src/libs/eigen/blas/f2c/drotmg.c @@ -0,0 +1,293 @@ +/* drotmg.f -- translated by f2c (version 20100827). + You must link the resulting object file with libf2c: + on Microsoft Windows system, link with libf2c.lib; + on Linux or Unix systems, link with .../path/to/libf2c.a -lm + or, if you install libf2c.a in a standard place, with -lf2c -lm + -- in that order, at the end of the command line, as in + cc *.o -lf2c -lm + Source for libf2c is in /netlib/f2c/libf2c.zip, e.g., + + http://www.netlib.org/f2c/libf2c.zip +*/ + +#include "datatypes.h" + +/* Subroutine */ int drotmg_(doublereal *dd1, doublereal *dd2, doublereal * + dx1, doublereal *dy1, doublereal *dparam) +{ + /* Initialized data */ + + static doublereal zero = 0.; + static doublereal one = 1.; + static doublereal two = 2.; + static doublereal gam = 4096.; + static doublereal gamsq = 16777216.; + static doublereal rgamsq = 5.9604645e-8; + + /* Format strings */ + static char fmt_120[] = ""; + static char fmt_150[] = ""; + static char fmt_180[] = ""; + static char fmt_210[] = ""; + + /* System generated locals */ + doublereal d__1; + + /* Local variables */ + doublereal du, dp1, dp2, dq1, dq2, dh11, dh12, dh21, dh22; + integer igo; + doublereal dflag, dtemp; + + /* Assigned format variables */ + static char *igo_fmt; + +/* .. Scalar Arguments .. */ +/* .. */ +/* .. Array Arguments .. */ +/* .. */ + +/* Purpose */ +/* ======= */ + +/* CONSTRUCT THE MODIFIED GIVENS TRANSFORMATION MATRIX H WHICH ZEROS */ +/* THE SECOND COMPONENT OF THE 2-VECTOR (DSQRT(DD1)*DX1,DSQRT(DD2)* */ +/* DY2)**T. */ +/* WITH DPARAM(1)=DFLAG, H HAS ONE OF THE FOLLOWING FORMS.. */ + +/* DFLAG=-1.D0 DFLAG=0.D0 DFLAG=1.D0 DFLAG=-2.D0 */ + +/* (DH11 DH12) (1.D0 DH12) (DH11 1.D0) (1.D0 0.D0) */ +/* H=( ) ( ) ( ) ( ) */ +/* (DH21 DH22), (DH21 1.D0), (-1.D0 DH22), (0.D0 1.D0). */ +/* LOCATIONS 2-4 OF DPARAM CONTAIN DH11, DH21, DH12, AND DH22 */ +/* RESPECTIVELY. (VALUES OF 1.D0, -1.D0, OR 0.D0 IMPLIED BY THE */ +/* VALUE OF DPARAM(1) ARE NOT STORED IN DPARAM.) */ + +/* THE VALUES OF GAMSQ AND RGAMSQ SET IN THE DATA STATEMENT MAY BE */ +/* INEXACT. THIS IS OK AS THEY ARE ONLY USED FOR TESTING THE SIZE */ +/* OF DD1 AND DD2. ALL ACTUAL SCALING OF DATA IS DONE USING GAM. */ + + +/* Arguments */ +/* ========= */ + +/* DD1 (input/output) DOUBLE PRECISION */ + +/* DD2 (input/output) DOUBLE PRECISION */ + +/* DX1 (input/output) DOUBLE PRECISION */ + +/* DY1 (input) DOUBLE PRECISION */ + +/* DPARAM (input/output) DOUBLE PRECISION array, dimension 5 */ +/* DPARAM(1)=DFLAG */ +/* DPARAM(2)=DH11 */ +/* DPARAM(3)=DH21 */ +/* DPARAM(4)=DH12 */ +/* DPARAM(5)=DH22 */ + +/* ===================================================================== */ + +/* .. Local Scalars .. */ +/* .. */ +/* .. Intrinsic Functions .. */ +/* .. */ +/* .. Data statements .. */ + + /* Parameter adjustments */ + --dparam; + + /* Function Body */ +/* .. */ + if (! (*dd1 < zero)) { + goto L10; + } +/* GO ZERO-H-D-AND-DX1.. */ + goto L60; +L10: +/* CASE-DD1-NONNEGATIVE */ + dp2 = *dd2 * *dy1; + if (! (dp2 == zero)) { + goto L20; + } + dflag = -two; + goto L260; +/* REGULAR-CASE.. */ +L20: + dp1 = *dd1 * *dx1; + dq2 = dp2 * *dy1; + dq1 = dp1 * *dx1; + + if (! (abs(dq1) > abs(dq2))) { + goto L40; + } + dh21 = -(*dy1) / *dx1; + dh12 = dp2 / dp1; + + du = one - dh12 * dh21; + + if (! (du <= zero)) { + goto L30; + } +/* GO ZERO-H-D-AND-DX1.. */ + goto L60; +L30: + dflag = zero; + *dd1 /= du; + *dd2 /= du; + *dx1 *= du; +/* GO SCALE-CHECK.. */ + goto L100; +L40: + if (! (dq2 < zero)) { + goto L50; + } +/* GO ZERO-H-D-AND-DX1.. */ + goto L60; +L50: + dflag = one; + dh11 = dp1 / dp2; + dh22 = *dx1 / *dy1; + du = one + dh11 * dh22; + dtemp = *dd2 / du; + *dd2 = *dd1 / du; + *dd1 = dtemp; + *dx1 = *dy1 * du; +/* GO SCALE-CHECK */ + goto L100; +/* PROCEDURE..ZERO-H-D-AND-DX1.. */ +L60: + dflag = -one; + dh11 = zero; + dh12 = zero; + dh21 = zero; + dh22 = zero; + + *dd1 = zero; + *dd2 = zero; + *dx1 = zero; +/* RETURN.. */ + goto L220; +/* PROCEDURE..FIX-H.. */ +L70: + if (! (dflag >= zero)) { + goto L90; + } + + if (! (dflag == zero)) { + goto L80; + } + dh11 = one; + dh22 = one; + dflag = -one; + goto L90; +L80: + dh21 = -one; + dh12 = one; + dflag = -one; +L90: + switch (igo) { + case 0: goto L120; + case 1: goto L150; + case 2: goto L180; + case 3: goto L210; + } +/* PROCEDURE..SCALE-CHECK */ +L100: +L110: + if (! (*dd1 <= rgamsq)) { + goto L130; + } + if (*dd1 == zero) { + goto L160; + } + igo = 0; + igo_fmt = fmt_120; +/* FIX-H.. */ + goto L70; +L120: +/* Computing 2nd power */ + d__1 = gam; + *dd1 *= d__1 * d__1; + *dx1 /= gam; + dh11 /= gam; + dh12 /= gam; + goto L110; +L130: +L140: + if (! (*dd1 >= gamsq)) { + goto L160; + } + igo = 1; + igo_fmt = fmt_150; +/* FIX-H.. */ + goto L70; +L150: +/* Computing 2nd power */ + d__1 = gam; + *dd1 /= d__1 * d__1; + *dx1 *= gam; + dh11 *= gam; + dh12 *= gam; + goto L140; +L160: +L170: + if (! (abs(*dd2) <= rgamsq)) { + goto L190; + } + if (*dd2 == zero) { + goto L220; + } + igo = 2; + igo_fmt = fmt_180; +/* FIX-H.. */ + goto L70; +L180: +/* Computing 2nd power */ + d__1 = gam; + *dd2 *= d__1 * d__1; + dh21 /= gam; + dh22 /= gam; + goto L170; +L190: +L200: + if (! (abs(*dd2) >= gamsq)) { + goto L220; + } + igo = 3; + igo_fmt = fmt_210; +/* FIX-H.. */ + goto L70; +L210: +/* Computing 2nd power */ + d__1 = gam; + *dd2 /= d__1 * d__1; + dh21 *= gam; + dh22 *= gam; + goto L200; +L220: + if (dflag < 0.) { + goto L250; + } else if (dflag == 0) { + goto L230; + } else { + goto L240; + } +L230: + dparam[3] = dh21; + dparam[4] = dh12; + goto L260; +L240: + dparam[2] = dh11; + dparam[5] = dh22; + goto L260; +L250: + dparam[2] = dh11; + dparam[3] = dh21; + dparam[4] = dh12; + dparam[5] = dh22; +L260: + dparam[1] = dflag; + return 0; +} /* drotmg_ */ + diff --git a/ground/gcs/src/libs/eigen/blas/f2c/dsbmv.c b/ground/gcs/src/libs/eigen/blas/f2c/dsbmv.c new file mode 100644 index 0000000000..c6b4b21d65 --- /dev/null +++ b/ground/gcs/src/libs/eigen/blas/f2c/dsbmv.c @@ -0,0 +1,366 @@ +/* dsbmv.f -- translated by f2c (version 20100827). + You must link the resulting object file with libf2c: + on Microsoft Windows system, link with libf2c.lib; + on Linux or Unix systems, link with .../path/to/libf2c.a -lm + or, if you install libf2c.a in a standard place, with -lf2c -lm + -- in that order, at the end of the command line, as in + cc *.o -lf2c -lm + Source for libf2c is in /netlib/f2c/libf2c.zip, e.g., + + http://www.netlib.org/f2c/libf2c.zip +*/ + +#include "datatypes.h" + +/* Subroutine */ int dsbmv_(char *uplo, integer *n, integer *k, doublereal * + alpha, doublereal *a, integer *lda, doublereal *x, integer *incx, + doublereal *beta, doublereal *y, integer *incy, ftnlen uplo_len) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4; + + /* Local variables */ + integer i__, j, l, ix, iy, jx, jy, kx, ky, info; + doublereal temp1, temp2; + extern logical lsame_(char *, char *, ftnlen, ftnlen); + integer kplus1; + extern /* Subroutine */ int xerbla_(char *, integer *, ftnlen); + +/* .. Scalar Arguments .. */ +/* .. */ +/* .. Array Arguments .. */ +/* .. */ + +/* Purpose */ +/* ======= */ + +/* DSBMV performs the matrix-vector operation */ + +/* y := alpha*A*x + beta*y, */ + +/* where alpha and beta are scalars, x and y are n element vectors and */ +/* A is an n by n symmetric band matrix, with k super-diagonals. */ + +/* Arguments */ +/* ========== */ + +/* UPLO - CHARACTER*1. */ +/* On entry, UPLO specifies whether the upper or lower */ +/* triangular part of the band matrix A is being supplied as */ +/* follows: */ + +/* UPLO = 'U' or 'u' The upper triangular part of A is */ +/* being supplied. */ + +/* UPLO = 'L' or 'l' The lower triangular part of A is */ +/* being supplied. */ + +/* Unchanged on exit. */ + +/* N - INTEGER. */ +/* On entry, N specifies the order of the matrix A. */ +/* N must be at least zero. */ +/* Unchanged on exit. */ + +/* K - INTEGER. */ +/* On entry, K specifies the number of super-diagonals of the */ +/* matrix A. K must satisfy 0 .le. K. */ +/* Unchanged on exit. */ + +/* ALPHA - DOUBLE PRECISION. */ +/* On entry, ALPHA specifies the scalar alpha. */ +/* Unchanged on exit. */ + +/* A - DOUBLE PRECISION array of DIMENSION ( LDA, n ). */ +/* Before entry with UPLO = 'U' or 'u', the leading ( k + 1 ) */ +/* by n part of the array A must contain the upper triangular */ +/* band part of the symmetric matrix, supplied column by */ +/* column, with the leading diagonal of the matrix in row */ +/* ( k + 1 ) of the array, the first super-diagonal starting at */ +/* position 2 in row k, and so on. The top left k by k triangle */ +/* of the array A is not referenced. */ +/* The following program segment will transfer the upper */ +/* triangular part of a symmetric band matrix from conventional */ +/* full matrix storage to band storage: */ + +/* DO 20, J = 1, N */ +/* M = K + 1 - J */ +/* DO 10, I = MAX( 1, J - K ), J */ +/* A( M + I, J ) = matrix( I, J ) */ +/* 10 CONTINUE */ +/* 20 CONTINUE */ + +/* Before entry with UPLO = 'L' or 'l', the leading ( k + 1 ) */ +/* by n part of the array A must contain the lower triangular */ +/* band part of the symmetric matrix, supplied column by */ +/* column, with the leading diagonal of the matrix in row 1 of */ +/* the array, the first sub-diagonal starting at position 1 in */ +/* row 2, and so on. The bottom right k by k triangle of the */ +/* array A is not referenced. */ +/* The following program segment will transfer the lower */ +/* triangular part of a symmetric band matrix from conventional */ +/* full matrix storage to band storage: */ + +/* DO 20, J = 1, N */ +/* M = 1 - J */ +/* DO 10, I = J, MIN( N, J + K ) */ +/* A( M + I, J ) = matrix( I, J ) */ +/* 10 CONTINUE */ +/* 20 CONTINUE */ + +/* Unchanged on exit. */ + +/* LDA - INTEGER. */ +/* On entry, LDA specifies the first dimension of A as declared */ +/* in the calling (sub) program. LDA must be at least */ +/* ( k + 1 ). */ +/* Unchanged on exit. */ + +/* X - DOUBLE PRECISION array of DIMENSION at least */ +/* ( 1 + ( n - 1 )*abs( INCX ) ). */ +/* Before entry, the incremented array X must contain the */ +/* vector x. */ +/* Unchanged on exit. */ + +/* INCX - INTEGER. */ +/* On entry, INCX specifies the increment for the elements of */ +/* X. INCX must not be zero. */ +/* Unchanged on exit. */ + +/* BETA - DOUBLE PRECISION. */ +/* On entry, BETA specifies the scalar beta. */ +/* Unchanged on exit. */ + +/* Y - DOUBLE PRECISION array of DIMENSION at least */ +/* ( 1 + ( n - 1 )*abs( INCY ) ). */ +/* Before entry, the incremented array Y must contain the */ +/* vector y. On exit, Y is overwritten by the updated vector y. */ + +/* INCY - INTEGER. */ +/* On entry, INCY specifies the increment for the elements of */ +/* Y. INCY must not be zero. */ +/* Unchanged on exit. */ + + +/* Level 2 Blas routine. */ + +/* -- Written on 22-October-1986. */ +/* Jack Dongarra, Argonne National Lab. */ +/* Jeremy Du Croz, Nag Central Office. */ +/* Sven Hammarling, Nag Central Office. */ +/* Richard Hanson, Sandia National Labs. */ + +/* ===================================================================== */ + +/* .. Parameters .. */ +/* .. */ +/* .. Local Scalars .. */ +/* .. */ +/* .. External Functions .. */ +/* .. */ +/* .. External Subroutines .. */ +/* .. */ +/* .. Intrinsic Functions .. */ +/* .. */ + +/* Test the input parameters. */ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --x; + --y; + + /* Function Body */ + info = 0; + if (! lsame_(uplo, "U", (ftnlen)1, (ftnlen)1) && ! lsame_(uplo, "L", ( + ftnlen)1, (ftnlen)1)) { + info = 1; + } else if (*n < 0) { + info = 2; + } else if (*k < 0) { + info = 3; + } else if (*lda < *k + 1) { + info = 6; + } else if (*incx == 0) { + info = 8; + } else if (*incy == 0) { + info = 11; + } + if (info != 0) { + xerbla_("DSBMV ", &info, (ftnlen)6); + return 0; + } + +/* Quick return if possible. */ + + if (*n == 0 || (*alpha == 0. && *beta == 1.)) { + return 0; + } + +/* Set up the start points in X and Y. */ + + if (*incx > 0) { + kx = 1; + } else { + kx = 1 - (*n - 1) * *incx; + } + if (*incy > 0) { + ky = 1; + } else { + ky = 1 - (*n - 1) * *incy; + } + +/* Start the operations. In this version the elements of the array A */ +/* are accessed sequentially with one pass through A. */ + +/* First form y := beta*y. */ + + if (*beta != 1.) { + if (*incy == 1) { + if (*beta == 0.) { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + y[i__] = 0.; +/* L10: */ + } + } else { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + y[i__] = *beta * y[i__]; +/* L20: */ + } + } + } else { + iy = ky; + if (*beta == 0.) { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + y[iy] = 0.; + iy += *incy; +/* L30: */ + } + } else { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + y[iy] = *beta * y[iy]; + iy += *incy; +/* L40: */ + } + } + } + } + if (*alpha == 0.) { + return 0; + } + if (lsame_(uplo, "U", (ftnlen)1, (ftnlen)1)) { + +/* Form y when upper triangle of A is stored. */ + + kplus1 = *k + 1; + if (*incx == 1 && *incy == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + temp1 = *alpha * x[j]; + temp2 = 0.; + l = kplus1 - j; +/* Computing MAX */ + i__2 = 1, i__3 = j - *k; + i__4 = j - 1; + for (i__ = max(i__2,i__3); i__ <= i__4; ++i__) { + y[i__] += temp1 * a[l + i__ + j * a_dim1]; + temp2 += a[l + i__ + j * a_dim1] * x[i__]; +/* L50: */ + } + y[j] = y[j] + temp1 * a[kplus1 + j * a_dim1] + *alpha * temp2; +/* L60: */ + } + } else { + jx = kx; + jy = ky; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + temp1 = *alpha * x[jx]; + temp2 = 0.; + ix = kx; + iy = ky; + l = kplus1 - j; +/* Computing MAX */ + i__4 = 1, i__2 = j - *k; + i__3 = j - 1; + for (i__ = max(i__4,i__2); i__ <= i__3; ++i__) { + y[iy] += temp1 * a[l + i__ + j * a_dim1]; + temp2 += a[l + i__ + j * a_dim1] * x[ix]; + ix += *incx; + iy += *incy; +/* L70: */ + } + y[jy] = y[jy] + temp1 * a[kplus1 + j * a_dim1] + *alpha * + temp2; + jx += *incx; + jy += *incy; + if (j > *k) { + kx += *incx; + ky += *incy; + } +/* L80: */ + } + } + } else { + +/* Form y when lower triangle of A is stored. */ + + if (*incx == 1 && *incy == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + temp1 = *alpha * x[j]; + temp2 = 0.; + y[j] += temp1 * a[j * a_dim1 + 1]; + l = 1 - j; +/* Computing MIN */ + i__4 = *n, i__2 = j + *k; + i__3 = min(i__4,i__2); + for (i__ = j + 1; i__ <= i__3; ++i__) { + y[i__] += temp1 * a[l + i__ + j * a_dim1]; + temp2 += a[l + i__ + j * a_dim1] * x[i__]; +/* L90: */ + } + y[j] += *alpha * temp2; +/* L100: */ + } + } else { + jx = kx; + jy = ky; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + temp1 = *alpha * x[jx]; + temp2 = 0.; + y[jy] += temp1 * a[j * a_dim1 + 1]; + l = 1 - j; + ix = jx; + iy = jy; +/* Computing MIN */ + i__4 = *n, i__2 = j + *k; + i__3 = min(i__4,i__2); + for (i__ = j + 1; i__ <= i__3; ++i__) { + ix += *incx; + iy += *incy; + y[iy] += temp1 * a[l + i__ + j * a_dim1]; + temp2 += a[l + i__ + j * a_dim1] * x[ix]; +/* L110: */ + } + y[jy] += *alpha * temp2; + jx += *incx; + jy += *incy; +/* L120: */ + } + } + } + + return 0; + +/* End of DSBMV . */ + +} /* dsbmv_ */ + diff --git a/ground/gcs/src/libs/eigen/blas/f2c/dspmv.c b/ground/gcs/src/libs/eigen/blas/f2c/dspmv.c new file mode 100644 index 0000000000..0b4e92d5cf --- /dev/null +++ b/ground/gcs/src/libs/eigen/blas/f2c/dspmv.c @@ -0,0 +1,316 @@ +/* dspmv.f -- translated by f2c (version 20100827). + You must link the resulting object file with libf2c: + on Microsoft Windows system, link with libf2c.lib; + on Linux or Unix systems, link with .../path/to/libf2c.a -lm + or, if you install libf2c.a in a standard place, with -lf2c -lm + -- in that order, at the end of the command line, as in + cc *.o -lf2c -lm + Source for libf2c is in /netlib/f2c/libf2c.zip, e.g., + + http://www.netlib.org/f2c/libf2c.zip +*/ + +#include "datatypes.h" + +/* Subroutine */ int dspmv_(char *uplo, integer *n, doublereal *alpha, + doublereal *ap, doublereal *x, integer *incx, doublereal *beta, + doublereal *y, integer *incy, ftnlen uplo_len) +{ + /* System generated locals */ + integer i__1, i__2; + + /* Local variables */ + integer i__, j, k, kk, ix, iy, jx, jy, kx, ky, info; + doublereal temp1, temp2; + extern logical lsame_(char *, char *, ftnlen, ftnlen); + extern /* Subroutine */ int xerbla_(char *, integer *, ftnlen); + +/* .. Scalar Arguments .. */ +/* .. */ +/* .. Array Arguments .. */ +/* .. */ + +/* Purpose */ +/* ======= */ + +/* DSPMV performs the matrix-vector operation */ + +/* y := alpha*A*x + beta*y, */ + +/* where alpha and beta are scalars, x and y are n element vectors and */ +/* A is an n by n symmetric matrix, supplied in packed form. */ + +/* Arguments */ +/* ========== */ + +/* UPLO - CHARACTER*1. */ +/* On entry, UPLO specifies whether the upper or lower */ +/* triangular part of the matrix A is supplied in the packed */ +/* array AP as follows: */ + +/* UPLO = 'U' or 'u' The upper triangular part of A is */ +/* supplied in AP. */ + +/* UPLO = 'L' or 'l' The lower triangular part of A is */ +/* supplied in AP. */ + +/* Unchanged on exit. */ + +/* N - INTEGER. */ +/* On entry, N specifies the order of the matrix A. */ +/* N must be at least zero. */ +/* Unchanged on exit. */ + +/* ALPHA - DOUBLE PRECISION. */ +/* On entry, ALPHA specifies the scalar alpha. */ +/* Unchanged on exit. */ + +/* AP - DOUBLE PRECISION array of DIMENSION at least */ +/* ( ( n*( n + 1 ) )/2 ). */ +/* Before entry with UPLO = 'U' or 'u', the array AP must */ +/* contain the upper triangular part of the symmetric matrix */ +/* packed sequentially, column by column, so that AP( 1 ) */ +/* contains a( 1, 1 ), AP( 2 ) and AP( 3 ) contain a( 1, 2 ) */ +/* and a( 2, 2 ) respectively, and so on. */ +/* Before entry with UPLO = 'L' or 'l', the array AP must */ +/* contain the lower triangular part of the symmetric matrix */ +/* packed sequentially, column by column, so that AP( 1 ) */ +/* contains a( 1, 1 ), AP( 2 ) and AP( 3 ) contain a( 2, 1 ) */ +/* and a( 3, 1 ) respectively, and so on. */ +/* Unchanged on exit. */ + +/* X - DOUBLE PRECISION array of dimension at least */ +/* ( 1 + ( n - 1 )*abs( INCX ) ). */ +/* Before entry, the incremented array X must contain the n */ +/* element vector x. */ +/* Unchanged on exit. */ + +/* INCX - INTEGER. */ +/* On entry, INCX specifies the increment for the elements of */ +/* X. INCX must not be zero. */ +/* Unchanged on exit. */ + +/* BETA - DOUBLE PRECISION. */ +/* On entry, BETA specifies the scalar beta. When BETA is */ +/* supplied as zero then Y need not be set on input. */ +/* Unchanged on exit. */ + +/* Y - DOUBLE PRECISION array of dimension at least */ +/* ( 1 + ( n - 1 )*abs( INCY ) ). */ +/* Before entry, the incremented array Y must contain the n */ +/* element vector y. On exit, Y is overwritten by the updated */ +/* vector y. */ + +/* INCY - INTEGER. */ +/* On entry, INCY specifies the increment for the elements of */ +/* Y. INCY must not be zero. */ +/* Unchanged on exit. */ + +/* Further Details */ +/* =============== */ + +/* Level 2 Blas routine. */ + +/* -- Written on 22-October-1986. */ +/* Jack Dongarra, Argonne National Lab. */ +/* Jeremy Du Croz, Nag Central Office. */ +/* Sven Hammarling, Nag Central Office. */ +/* Richard Hanson, Sandia National Labs. */ + +/* ===================================================================== */ + +/* .. Parameters .. */ +/* .. */ +/* .. Local Scalars .. */ +/* .. */ +/* .. External Functions .. */ +/* .. */ +/* .. External Subroutines .. */ +/* .. */ + +/* Test the input parameters. */ + + /* Parameter adjustments */ + --y; + --x; + --ap; + + /* Function Body */ + info = 0; + if (! lsame_(uplo, "U", (ftnlen)1, (ftnlen)1) && ! lsame_(uplo, "L", ( + ftnlen)1, (ftnlen)1)) { + info = 1; + } else if (*n < 0) { + info = 2; + } else if (*incx == 0) { + info = 6; + } else if (*incy == 0) { + info = 9; + } + if (info != 0) { + xerbla_("DSPMV ", &info, (ftnlen)6); + return 0; + } + +/* Quick return if possible. */ + + if (*n == 0 || (*alpha == 0. && *beta == 1.)) { + return 0; + } + +/* Set up the start points in X and Y. */ + + if (*incx > 0) { + kx = 1; + } else { + kx = 1 - (*n - 1) * *incx; + } + if (*incy > 0) { + ky = 1; + } else { + ky = 1 - (*n - 1) * *incy; + } + +/* Start the operations. In this version the elements of the array AP */ +/* are accessed sequentially with one pass through AP. */ + +/* First form y := beta*y. */ + + if (*beta != 1.) { + if (*incy == 1) { + if (*beta == 0.) { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + y[i__] = 0.; +/* L10: */ + } + } else { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + y[i__] = *beta * y[i__]; +/* L20: */ + } + } + } else { + iy = ky; + if (*beta == 0.) { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + y[iy] = 0.; + iy += *incy; +/* L30: */ + } + } else { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + y[iy] = *beta * y[iy]; + iy += *incy; +/* L40: */ + } + } + } + } + if (*alpha == 0.) { + return 0; + } + kk = 1; + if (lsame_(uplo, "U", (ftnlen)1, (ftnlen)1)) { + +/* Form y when AP contains the upper triangle. */ + + if (*incx == 1 && *incy == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + temp1 = *alpha * x[j]; + temp2 = 0.; + k = kk; + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + y[i__] += temp1 * ap[k]; + temp2 += ap[k] * x[i__]; + ++k; +/* L50: */ + } + y[j] = y[j] + temp1 * ap[kk + j - 1] + *alpha * temp2; + kk += j; +/* L60: */ + } + } else { + jx = kx; + jy = ky; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + temp1 = *alpha * x[jx]; + temp2 = 0.; + ix = kx; + iy = ky; + i__2 = kk + j - 2; + for (k = kk; k <= i__2; ++k) { + y[iy] += temp1 * ap[k]; + temp2 += ap[k] * x[ix]; + ix += *incx; + iy += *incy; +/* L70: */ + } + y[jy] = y[jy] + temp1 * ap[kk + j - 1] + *alpha * temp2; + jx += *incx; + jy += *incy; + kk += j; +/* L80: */ + } + } + } else { + +/* Form y when AP contains the lower triangle. */ + + if (*incx == 1 && *incy == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + temp1 = *alpha * x[j]; + temp2 = 0.; + y[j] += temp1 * ap[kk]; + k = kk + 1; + i__2 = *n; + for (i__ = j + 1; i__ <= i__2; ++i__) { + y[i__] += temp1 * ap[k]; + temp2 += ap[k] * x[i__]; + ++k; +/* L90: */ + } + y[j] += *alpha * temp2; + kk += *n - j + 1; +/* L100: */ + } + } else { + jx = kx; + jy = ky; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + temp1 = *alpha * x[jx]; + temp2 = 0.; + y[jy] += temp1 * ap[kk]; + ix = jx; + iy = jy; + i__2 = kk + *n - j; + for (k = kk + 1; k <= i__2; ++k) { + ix += *incx; + iy += *incy; + y[iy] += temp1 * ap[k]; + temp2 += ap[k] * x[ix]; +/* L110: */ + } + y[jy] += *alpha * temp2; + jx += *incx; + jy += *incy; + kk += *n - j + 1; +/* L120: */ + } + } + } + + return 0; + +/* End of DSPMV . */ + +} /* dspmv_ */ + diff --git a/ground/gcs/src/libs/eigen/blas/f2c/dtbmv.c b/ground/gcs/src/libs/eigen/blas/f2c/dtbmv.c new file mode 100644 index 0000000000..fdf73ebb52 --- /dev/null +++ b/ground/gcs/src/libs/eigen/blas/f2c/dtbmv.c @@ -0,0 +1,428 @@ +/* dtbmv.f -- translated by f2c (version 20100827). + You must link the resulting object file with libf2c: + on Microsoft Windows system, link with libf2c.lib; + on Linux or Unix systems, link with .../path/to/libf2c.a -lm + or, if you install libf2c.a in a standard place, with -lf2c -lm + -- in that order, at the end of the command line, as in + cc *.o -lf2c -lm + Source for libf2c is in /netlib/f2c/libf2c.zip, e.g., + + http://www.netlib.org/f2c/libf2c.zip +*/ + +#include "datatypes.h" + +/* Subroutine */ int dtbmv_(char *uplo, char *trans, char *diag, integer *n, + integer *k, doublereal *a, integer *lda, doublereal *x, integer *incx, + ftnlen uplo_len, ftnlen trans_len, ftnlen diag_len) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4; + + /* Local variables */ + integer i__, j, l, ix, jx, kx, info; + doublereal temp; + extern logical lsame_(char *, char *, ftnlen, ftnlen); + integer kplus1; + extern /* Subroutine */ int xerbla_(char *, integer *, ftnlen); + logical nounit; + +/* .. Scalar Arguments .. */ +/* .. */ +/* .. Array Arguments .. */ +/* .. */ + +/* Purpose */ +/* ======= */ + +/* DTBMV performs one of the matrix-vector operations */ + +/* x := A*x, or x := A'*x, */ + +/* where x is an n element vector and A is an n by n unit, or non-unit, */ +/* upper or lower triangular band matrix, with ( k + 1 ) diagonals. */ + +/* Arguments */ +/* ========== */ + +/* UPLO - CHARACTER*1. */ +/* On entry, UPLO specifies whether the matrix is an upper or */ +/* lower triangular matrix as follows: */ + +/* UPLO = 'U' or 'u' A is an upper triangular matrix. */ + +/* UPLO = 'L' or 'l' A is a lower triangular matrix. */ + +/* Unchanged on exit. */ + +/* TRANS - CHARACTER*1. */ +/* On entry, TRANS specifies the operation to be performed as */ +/* follows: */ + +/* TRANS = 'N' or 'n' x := A*x. */ + +/* TRANS = 'T' or 't' x := A'*x. */ + +/* TRANS = 'C' or 'c' x := A'*x. */ + +/* Unchanged on exit. */ + +/* DIAG - CHARACTER*1. */ +/* On entry, DIAG specifies whether or not A is unit */ +/* triangular as follows: */ + +/* DIAG = 'U' or 'u' A is assumed to be unit triangular. */ + +/* DIAG = 'N' or 'n' A is not assumed to be unit */ +/* triangular. */ + +/* Unchanged on exit. */ + +/* N - INTEGER. */ +/* On entry, N specifies the order of the matrix A. */ +/* N must be at least zero. */ +/* Unchanged on exit. */ + +/* K - INTEGER. */ +/* On entry with UPLO = 'U' or 'u', K specifies the number of */ +/* super-diagonals of the matrix A. */ +/* On entry with UPLO = 'L' or 'l', K specifies the number of */ +/* sub-diagonals of the matrix A. */ +/* K must satisfy 0 .le. K. */ +/* Unchanged on exit. */ + +/* A - DOUBLE PRECISION array of DIMENSION ( LDA, n ). */ +/* Before entry with UPLO = 'U' or 'u', the leading ( k + 1 ) */ +/* by n part of the array A must contain the upper triangular */ +/* band part of the matrix of coefficients, supplied column by */ +/* column, with the leading diagonal of the matrix in row */ +/* ( k + 1 ) of the array, the first super-diagonal starting at */ +/* position 2 in row k, and so on. The top left k by k triangle */ +/* of the array A is not referenced. */ +/* The following program segment will transfer an upper */ +/* triangular band matrix from conventional full matrix storage */ +/* to band storage: */ + +/* DO 20, J = 1, N */ +/* M = K + 1 - J */ +/* DO 10, I = MAX( 1, J - K ), J */ +/* A( M + I, J ) = matrix( I, J ) */ +/* 10 CONTINUE */ +/* 20 CONTINUE */ + +/* Before entry with UPLO = 'L' or 'l', the leading ( k + 1 ) */ +/* by n part of the array A must contain the lower triangular */ +/* band part of the matrix of coefficients, supplied column by */ +/* column, with the leading diagonal of the matrix in row 1 of */ +/* the array, the first sub-diagonal starting at position 1 in */ +/* row 2, and so on. The bottom right k by k triangle of the */ +/* array A is not referenced. */ +/* The following program segment will transfer a lower */ +/* triangular band matrix from conventional full matrix storage */ +/* to band storage: */ + +/* DO 20, J = 1, N */ +/* M = 1 - J */ +/* DO 10, I = J, MIN( N, J + K ) */ +/* A( M + I, J ) = matrix( I, J ) */ +/* 10 CONTINUE */ +/* 20 CONTINUE */ + +/* Note that when DIAG = 'U' or 'u' the elements of the array A */ +/* corresponding to the diagonal elements of the matrix are not */ +/* referenced, but are assumed to be unity. */ +/* Unchanged on exit. */ + +/* LDA - INTEGER. */ +/* On entry, LDA specifies the first dimension of A as declared */ +/* in the calling (sub) program. LDA must be at least */ +/* ( k + 1 ). */ +/* Unchanged on exit. */ + +/* X - DOUBLE PRECISION array of dimension at least */ +/* ( 1 + ( n - 1 )*abs( INCX ) ). */ +/* Before entry, the incremented array X must contain the n */ +/* element vector x. On exit, X is overwritten with the */ +/* tranformed vector x. */ + +/* INCX - INTEGER. */ +/* On entry, INCX specifies the increment for the elements of */ +/* X. INCX must not be zero. */ +/* Unchanged on exit. */ + +/* Further Details */ +/* =============== */ + +/* Level 2 Blas routine. */ + +/* -- Written on 22-October-1986. */ +/* Jack Dongarra, Argonne National Lab. */ +/* Jeremy Du Croz, Nag Central Office. */ +/* Sven Hammarling, Nag Central Office. */ +/* Richard Hanson, Sandia National Labs. */ + +/* ===================================================================== */ + +/* .. Parameters .. */ +/* .. */ +/* .. Local Scalars .. */ +/* .. */ +/* .. External Functions .. */ +/* .. */ +/* .. External Subroutines .. */ +/* .. */ +/* .. Intrinsic Functions .. */ +/* .. */ + +/* Test the input parameters. */ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --x; + + /* Function Body */ + info = 0; + if (! lsame_(uplo, "U", (ftnlen)1, (ftnlen)1) && ! lsame_(uplo, "L", ( + ftnlen)1, (ftnlen)1)) { + info = 1; + } else if (! lsame_(trans, "N", (ftnlen)1, (ftnlen)1) && ! lsame_(trans, + "T", (ftnlen)1, (ftnlen)1) && ! lsame_(trans, "C", (ftnlen)1, ( + ftnlen)1)) { + info = 2; + } else if (! lsame_(diag, "U", (ftnlen)1, (ftnlen)1) && ! lsame_(diag, + "N", (ftnlen)1, (ftnlen)1)) { + info = 3; + } else if (*n < 0) { + info = 4; + } else if (*k < 0) { + info = 5; + } else if (*lda < *k + 1) { + info = 7; + } else if (*incx == 0) { + info = 9; + } + if (info != 0) { + xerbla_("DTBMV ", &info, (ftnlen)6); + return 0; + } + +/* Quick return if possible. */ + + if (*n == 0) { + return 0; + } + + nounit = lsame_(diag, "N", (ftnlen)1, (ftnlen)1); + +/* Set up the start point in X if the increment is not unity. This */ +/* will be ( N - 1 )*INCX too small for descending loops. */ + + if (*incx <= 0) { + kx = 1 - (*n - 1) * *incx; + } else if (*incx != 1) { + kx = 1; + } + +/* Start the operations. In this version the elements of A are */ +/* accessed sequentially with one pass through A. */ + + if (lsame_(trans, "N", (ftnlen)1, (ftnlen)1)) { + +/* Form x := A*x. */ + + if (lsame_(uplo, "U", (ftnlen)1, (ftnlen)1)) { + kplus1 = *k + 1; + if (*incx == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (x[j] != 0.) { + temp = x[j]; + l = kplus1 - j; +/* Computing MAX */ + i__2 = 1, i__3 = j - *k; + i__4 = j - 1; + for (i__ = max(i__2,i__3); i__ <= i__4; ++i__) { + x[i__] += temp * a[l + i__ + j * a_dim1]; +/* L10: */ + } + if (nounit) { + x[j] *= a[kplus1 + j * a_dim1]; + } + } +/* L20: */ + } + } else { + jx = kx; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (x[jx] != 0.) { + temp = x[jx]; + ix = kx; + l = kplus1 - j; +/* Computing MAX */ + i__4 = 1, i__2 = j - *k; + i__3 = j - 1; + for (i__ = max(i__4,i__2); i__ <= i__3; ++i__) { + x[ix] += temp * a[l + i__ + j * a_dim1]; + ix += *incx; +/* L30: */ + } + if (nounit) { + x[jx] *= a[kplus1 + j * a_dim1]; + } + } + jx += *incx; + if (j > *k) { + kx += *incx; + } +/* L40: */ + } + } + } else { + if (*incx == 1) { + for (j = *n; j >= 1; --j) { + if (x[j] != 0.) { + temp = x[j]; + l = 1 - j; +/* Computing MIN */ + i__1 = *n, i__3 = j + *k; + i__4 = j + 1; + for (i__ = min(i__1,i__3); i__ >= i__4; --i__) { + x[i__] += temp * a[l + i__ + j * a_dim1]; +/* L50: */ + } + if (nounit) { + x[j] *= a[j * a_dim1 + 1]; + } + } +/* L60: */ + } + } else { + kx += (*n - 1) * *incx; + jx = kx; + for (j = *n; j >= 1; --j) { + if (x[jx] != 0.) { + temp = x[jx]; + ix = kx; + l = 1 - j; +/* Computing MIN */ + i__4 = *n, i__1 = j + *k; + i__3 = j + 1; + for (i__ = min(i__4,i__1); i__ >= i__3; --i__) { + x[ix] += temp * a[l + i__ + j * a_dim1]; + ix -= *incx; +/* L70: */ + } + if (nounit) { + x[jx] *= a[j * a_dim1 + 1]; + } + } + jx -= *incx; + if (*n - j >= *k) { + kx -= *incx; + } +/* L80: */ + } + } + } + } else { + +/* Form x := A'*x. */ + + if (lsame_(uplo, "U", (ftnlen)1, (ftnlen)1)) { + kplus1 = *k + 1; + if (*incx == 1) { + for (j = *n; j >= 1; --j) { + temp = x[j]; + l = kplus1 - j; + if (nounit) { + temp *= a[kplus1 + j * a_dim1]; + } +/* Computing MAX */ + i__4 = 1, i__1 = j - *k; + i__3 = max(i__4,i__1); + for (i__ = j - 1; i__ >= i__3; --i__) { + temp += a[l + i__ + j * a_dim1] * x[i__]; +/* L90: */ + } + x[j] = temp; +/* L100: */ + } + } else { + kx += (*n - 1) * *incx; + jx = kx; + for (j = *n; j >= 1; --j) { + temp = x[jx]; + kx -= *incx; + ix = kx; + l = kplus1 - j; + if (nounit) { + temp *= a[kplus1 + j * a_dim1]; + } +/* Computing MAX */ + i__4 = 1, i__1 = j - *k; + i__3 = max(i__4,i__1); + for (i__ = j - 1; i__ >= i__3; --i__) { + temp += a[l + i__ + j * a_dim1] * x[ix]; + ix -= *incx; +/* L110: */ + } + x[jx] = temp; + jx -= *incx; +/* L120: */ + } + } + } else { + if (*incx == 1) { + i__3 = *n; + for (j = 1; j <= i__3; ++j) { + temp = x[j]; + l = 1 - j; + if (nounit) { + temp *= a[j * a_dim1 + 1]; + } +/* Computing MIN */ + i__1 = *n, i__2 = j + *k; + i__4 = min(i__1,i__2); + for (i__ = j + 1; i__ <= i__4; ++i__) { + temp += a[l + i__ + j * a_dim1] * x[i__]; +/* L130: */ + } + x[j] = temp; +/* L140: */ + } + } else { + jx = kx; + i__3 = *n; + for (j = 1; j <= i__3; ++j) { + temp = x[jx]; + kx += *incx; + ix = kx; + l = 1 - j; + if (nounit) { + temp *= a[j * a_dim1 + 1]; + } +/* Computing MIN */ + i__1 = *n, i__2 = j + *k; + i__4 = min(i__1,i__2); + for (i__ = j + 1; i__ <= i__4; ++i__) { + temp += a[l + i__ + j * a_dim1] * x[ix]; + ix += *incx; +/* L150: */ + } + x[jx] = temp; + jx += *incx; +/* L160: */ + } + } + } + } + + return 0; + +/* End of DTBMV . */ + +} /* dtbmv_ */ + diff --git a/ground/gcs/src/libs/eigen/blas/f2c/lsame.c b/ground/gcs/src/libs/eigen/blas/f2c/lsame.c new file mode 100644 index 0000000000..46324d9168 --- /dev/null +++ b/ground/gcs/src/libs/eigen/blas/f2c/lsame.c @@ -0,0 +1,117 @@ +/* lsame.f -- translated by f2c (version 20100827). + You must link the resulting object file with libf2c: + on Microsoft Windows system, link with libf2c.lib; + on Linux or Unix systems, link with .../path/to/libf2c.a -lm + or, if you install libf2c.a in a standard place, with -lf2c -lm + -- in that order, at the end of the command line, as in + cc *.o -lf2c -lm + Source for libf2c is in /netlib/f2c/libf2c.zip, e.g., + + http://www.netlib.org/f2c/libf2c.zip +*/ + +#include "datatypes.h" + +logical lsame_(char *ca, char *cb, ftnlen ca_len, ftnlen cb_len) +{ + /* System generated locals */ + logical ret_val; + + /* Local variables */ + integer inta, intb, zcode; + + +/* -- LAPACK auxiliary routine (version 3.1) -- */ +/* Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd.. */ +/* November 2006 */ + +/* .. Scalar Arguments .. */ +/* .. */ + +/* Purpose */ +/* ======= */ + +/* LSAME returns .TRUE. if CA is the same letter as CB regardless of */ +/* case. */ + +/* Arguments */ +/* ========= */ + +/* CA (input) CHARACTER*1 */ + +/* CB (input) CHARACTER*1 */ +/* CA and CB specify the single characters to be compared. */ + +/* ===================================================================== */ + +/* .. Intrinsic Functions .. */ +/* .. */ +/* .. Local Scalars .. */ +/* .. */ + +/* Test if the characters are equal */ + + ret_val = *(unsigned char *)ca == *(unsigned char *)cb; + if (ret_val) { + return ret_val; + } + +/* Now test for equivalence if both characters are alphabetic. */ + + zcode = 'Z'; + +/* Use 'Z' rather than 'A' so that ASCII can be detected on Prime */ +/* machines, on which ICHAR returns a value with bit 8 set. */ +/* ICHAR('A') on Prime machines returns 193 which is the same as */ +/* ICHAR('A') on an EBCDIC machine. */ + + inta = *(unsigned char *)ca; + intb = *(unsigned char *)cb; + + if (zcode == 90 || zcode == 122) { + +/* ASCII is assumed - ZCODE is the ASCII code of either lower or */ +/* upper case 'Z'. */ + + if (inta >= 97 && inta <= 122) { + inta += -32; + } + if (intb >= 97 && intb <= 122) { + intb += -32; + } + + } else if (zcode == 233 || zcode == 169) { + +/* EBCDIC is assumed - ZCODE is the EBCDIC code of either lower or */ +/* upper case 'Z'. */ + + if ((inta >= 129 && inta <= 137) || (inta >= 145 && inta <= 153) || + (inta >= 162 && inta <= 169)) { + inta += 64; + } + if ((intb >= 129 && intb <= 137) || (intb >= 145 && intb <= 153) || + (intb >= 162 && intb <= 169)) { + intb += 64; + } + + } else if (zcode == 218 || zcode == 250) { + +/* ASCII is assumed, on Prime machines - ZCODE is the ASCII code */ +/* plus 128 of either lower or upper case 'Z'. */ + + if (inta >= 225 && inta <= 250) { + inta += -32; + } + if (intb >= 225 && intb <= 250) { + intb += -32; + } + } + ret_val = inta == intb; + +/* RETURN */ + +/* End of LSAME */ + + return ret_val; +} /* lsame_ */ + diff --git a/ground/gcs/src/libs/eigen/blas/f2c/r_cnjg.c b/ground/gcs/src/libs/eigen/blas/f2c/r_cnjg.c new file mode 100644 index 0000000000..c08182f88e --- /dev/null +++ b/ground/gcs/src/libs/eigen/blas/f2c/r_cnjg.c @@ -0,0 +1,6 @@ +#include "datatypes.h" + +void r_cnjg(complex *r, complex *z) { + r->r = z->r; + r->i = -(z->i); +} diff --git a/ground/gcs/src/libs/eigen/blas/f2c/srotm.c b/ground/gcs/src/libs/eigen/blas/f2c/srotm.c new file mode 100644 index 0000000000..bd5944a99d --- /dev/null +++ b/ground/gcs/src/libs/eigen/blas/f2c/srotm.c @@ -0,0 +1,216 @@ +/* srotm.f -- translated by f2c (version 20100827). + You must link the resulting object file with libf2c: + on Microsoft Windows system, link with libf2c.lib; + on Linux or Unix systems, link with .../path/to/libf2c.a -lm + or, if you install libf2c.a in a standard place, with -lf2c -lm + -- in that order, at the end of the command line, as in + cc *.o -lf2c -lm + Source for libf2c is in /netlib/f2c/libf2c.zip, e.g., + + http://www.netlib.org/f2c/libf2c.zip +*/ + +#include "datatypes.h" + +/* Subroutine */ int srotm_(integer *n, real *sx, integer *incx, real *sy, + integer *incy, real *sparam) +{ + /* Initialized data */ + + static real zero = 0.f; + static real two = 2.f; + + /* System generated locals */ + integer i__1, i__2; + + /* Local variables */ + integer i__; + real w, z__; + integer kx, ky; + real sh11, sh12, sh21, sh22, sflag; + integer nsteps; + +/* .. Scalar Arguments .. */ +/* .. */ +/* .. Array Arguments .. */ +/* .. */ + +/* Purpose */ +/* ======= */ + +/* APPLY THE MODIFIED GIVENS TRANSFORMATION, H, TO THE 2 BY N MATRIX */ + +/* (SX**T) , WHERE **T INDICATES TRANSPOSE. THE ELEMENTS OF SX ARE IN */ +/* (DX**T) */ + +/* SX(LX+I*INCX), I = 0 TO N-1, WHERE LX = 1 IF INCX .GE. 0, ELSE */ +/* LX = (-INCX)*N, AND SIMILARLY FOR SY USING USING LY AND INCY. */ +/* WITH SPARAM(1)=SFLAG, H HAS ONE OF THE FOLLOWING FORMS.. */ + +/* SFLAG=-1.E0 SFLAG=0.E0 SFLAG=1.E0 SFLAG=-2.E0 */ + +/* (SH11 SH12) (1.E0 SH12) (SH11 1.E0) (1.E0 0.E0) */ +/* H=( ) ( ) ( ) ( ) */ +/* (SH21 SH22), (SH21 1.E0), (-1.E0 SH22), (0.E0 1.E0). */ +/* SEE SROTMG FOR A DESCRIPTION OF DATA STORAGE IN SPARAM. */ + + +/* Arguments */ +/* ========= */ + +/* N (input) INTEGER */ +/* number of elements in input vector(s) */ + +/* SX (input/output) REAL array, dimension N */ +/* double precision vector with N elements */ + +/* INCX (input) INTEGER */ +/* storage spacing between elements of SX */ + +/* SY (input/output) REAL array, dimension N */ +/* double precision vector with N elements */ + +/* INCY (input) INTEGER */ +/* storage spacing between elements of SY */ + +/* SPARAM (input/output) REAL array, dimension 5 */ +/* SPARAM(1)=SFLAG */ +/* SPARAM(2)=SH11 */ +/* SPARAM(3)=SH21 */ +/* SPARAM(4)=SH12 */ +/* SPARAM(5)=SH22 */ + +/* ===================================================================== */ + +/* .. Local Scalars .. */ +/* .. */ +/* .. Data statements .. */ + /* Parameter adjustments */ + --sparam; + --sy; + --sx; + + /* Function Body */ +/* .. */ + + sflag = sparam[1]; + if (*n <= 0 || sflag + two == zero) { + goto L140; + } + if (! (*incx == *incy && *incx > 0)) { + goto L70; + } + + nsteps = *n * *incx; + if (sflag < 0.f) { + goto L50; + } else if (sflag == 0) { + goto L10; + } else { + goto L30; + } +L10: + sh12 = sparam[4]; + sh21 = sparam[3]; + i__1 = nsteps; + i__2 = *incx; + for (i__ = 1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) { + w = sx[i__]; + z__ = sy[i__]; + sx[i__] = w + z__ * sh12; + sy[i__] = w * sh21 + z__; +/* L20: */ + } + goto L140; +L30: + sh11 = sparam[2]; + sh22 = sparam[5]; + i__2 = nsteps; + i__1 = *incx; + for (i__ = 1; i__1 < 0 ? i__ >= i__2 : i__ <= i__2; i__ += i__1) { + w = sx[i__]; + z__ = sy[i__]; + sx[i__] = w * sh11 + z__; + sy[i__] = -w + sh22 * z__; +/* L40: */ + } + goto L140; +L50: + sh11 = sparam[2]; + sh12 = sparam[4]; + sh21 = sparam[3]; + sh22 = sparam[5]; + i__1 = nsteps; + i__2 = *incx; + for (i__ = 1; i__2 < 0 ? i__ >= i__1 : i__ <= i__1; i__ += i__2) { + w = sx[i__]; + z__ = sy[i__]; + sx[i__] = w * sh11 + z__ * sh12; + sy[i__] = w * sh21 + z__ * sh22; +/* L60: */ + } + goto L140; +L70: + kx = 1; + ky = 1; + if (*incx < 0) { + kx = (1 - *n) * *incx + 1; + } + if (*incy < 0) { + ky = (1 - *n) * *incy + 1; + } + + if (sflag < 0.f) { + goto L120; + } else if (sflag == 0) { + goto L80; + } else { + goto L100; + } +L80: + sh12 = sparam[4]; + sh21 = sparam[3]; + i__2 = *n; + for (i__ = 1; i__ <= i__2; ++i__) { + w = sx[kx]; + z__ = sy[ky]; + sx[kx] = w + z__ * sh12; + sy[ky] = w * sh21 + z__; + kx += *incx; + ky += *incy; +/* L90: */ + } + goto L140; +L100: + sh11 = sparam[2]; + sh22 = sparam[5]; + i__2 = *n; + for (i__ = 1; i__ <= i__2; ++i__) { + w = sx[kx]; + z__ = sy[ky]; + sx[kx] = w * sh11 + z__; + sy[ky] = -w + sh22 * z__; + kx += *incx; + ky += *incy; +/* L110: */ + } + goto L140; +L120: + sh11 = sparam[2]; + sh12 = sparam[4]; + sh21 = sparam[3]; + sh22 = sparam[5]; + i__2 = *n; + for (i__ = 1; i__ <= i__2; ++i__) { + w = sx[kx]; + z__ = sy[ky]; + sx[kx] = w * sh11 + z__ * sh12; + sy[ky] = w * sh21 + z__ * sh22; + kx += *incx; + ky += *incy; +/* L130: */ + } +L140: + return 0; +} /* srotm_ */ + diff --git a/ground/gcs/src/libs/eigen/blas/f2c/srotmg.c b/ground/gcs/src/libs/eigen/blas/f2c/srotmg.c new file mode 100644 index 0000000000..75f789fe28 --- /dev/null +++ b/ground/gcs/src/libs/eigen/blas/f2c/srotmg.c @@ -0,0 +1,295 @@ +/* srotmg.f -- translated by f2c (version 20100827). + You must link the resulting object file with libf2c: + on Microsoft Windows system, link with libf2c.lib; + on Linux or Unix systems, link with .../path/to/libf2c.a -lm + or, if you install libf2c.a in a standard place, with -lf2c -lm + -- in that order, at the end of the command line, as in + cc *.o -lf2c -lm + Source for libf2c is in /netlib/f2c/libf2c.zip, e.g., + + http://www.netlib.org/f2c/libf2c.zip +*/ + +#include "datatypes.h" + +/* Subroutine */ int srotmg_(real *sd1, real *sd2, real *sx1, real *sy1, real + *sparam) +{ + /* Initialized data */ + + static real zero = 0.f; + static real one = 1.f; + static real two = 2.f; + static real gam = 4096.f; + static real gamsq = 16777200.f; + static real rgamsq = 5.96046e-8f; + + /* Format strings */ + static char fmt_120[] = ""; + static char fmt_150[] = ""; + static char fmt_180[] = ""; + static char fmt_210[] = ""; + + /* System generated locals */ + real r__1; + + /* Local variables */ + real su, sp1, sp2, sq1, sq2, sh11, sh12, sh21, sh22; + integer igo; + real sflag, stemp; + + /* Assigned format variables */ + static char *igo_fmt; + +/* .. Scalar Arguments .. */ +/* .. */ +/* .. Array Arguments .. */ +/* .. */ + +/* Purpose */ +/* ======= */ + +/* CONSTRUCT THE MODIFIED GIVENS TRANSFORMATION MATRIX H WHICH ZEROS */ +/* THE SECOND COMPONENT OF THE 2-VECTOR (SQRT(SD1)*SX1,SQRT(SD2)* */ +/* SY2)**T. */ +/* WITH SPARAM(1)=SFLAG, H HAS ONE OF THE FOLLOWING FORMS.. */ + +/* SFLAG=-1.E0 SFLAG=0.E0 SFLAG=1.E0 SFLAG=-2.E0 */ + +/* (SH11 SH12) (1.E0 SH12) (SH11 1.E0) (1.E0 0.E0) */ +/* H=( ) ( ) ( ) ( ) */ +/* (SH21 SH22), (SH21 1.E0), (-1.E0 SH22), (0.E0 1.E0). */ +/* LOCATIONS 2-4 OF SPARAM CONTAIN SH11,SH21,SH12, AND SH22 */ +/* RESPECTIVELY. (VALUES OF 1.E0, -1.E0, OR 0.E0 IMPLIED BY THE */ +/* VALUE OF SPARAM(1) ARE NOT STORED IN SPARAM.) */ + +/* THE VALUES OF GAMSQ AND RGAMSQ SET IN THE DATA STATEMENT MAY BE */ +/* INEXACT. THIS IS OK AS THEY ARE ONLY USED FOR TESTING THE SIZE */ +/* OF SD1 AND SD2. ALL ACTUAL SCALING OF DATA IS DONE USING GAM. */ + + +/* Arguments */ +/* ========= */ + + +/* SD1 (input/output) REAL */ + +/* SD2 (input/output) REAL */ + +/* SX1 (input/output) REAL */ + +/* SY1 (input) REAL */ + + +/* SPARAM (input/output) REAL array, dimension 5 */ +/* SPARAM(1)=SFLAG */ +/* SPARAM(2)=SH11 */ +/* SPARAM(3)=SH21 */ +/* SPARAM(4)=SH12 */ +/* SPARAM(5)=SH22 */ + +/* ===================================================================== */ + +/* .. Local Scalars .. */ +/* .. */ +/* .. Intrinsic Functions .. */ +/* .. */ +/* .. Data statements .. */ + + /* Parameter adjustments */ + --sparam; + + /* Function Body */ +/* .. */ + if (! (*sd1 < zero)) { + goto L10; + } +/* GO ZERO-H-D-AND-SX1.. */ + goto L60; +L10: +/* CASE-SD1-NONNEGATIVE */ + sp2 = *sd2 * *sy1; + if (! (sp2 == zero)) { + goto L20; + } + sflag = -two; + goto L260; +/* REGULAR-CASE.. */ +L20: + sp1 = *sd1 * *sx1; + sq2 = sp2 * *sy1; + sq1 = sp1 * *sx1; + + if (! (dabs(sq1) > dabs(sq2))) { + goto L40; + } + sh21 = -(*sy1) / *sx1; + sh12 = sp2 / sp1; + + su = one - sh12 * sh21; + + if (! (su <= zero)) { + goto L30; + } +/* GO ZERO-H-D-AND-SX1.. */ + goto L60; +L30: + sflag = zero; + *sd1 /= su; + *sd2 /= su; + *sx1 *= su; +/* GO SCALE-CHECK.. */ + goto L100; +L40: + if (! (sq2 < zero)) { + goto L50; + } +/* GO ZERO-H-D-AND-SX1.. */ + goto L60; +L50: + sflag = one; + sh11 = sp1 / sp2; + sh22 = *sx1 / *sy1; + su = one + sh11 * sh22; + stemp = *sd2 / su; + *sd2 = *sd1 / su; + *sd1 = stemp; + *sx1 = *sy1 * su; +/* GO SCALE-CHECK */ + goto L100; +/* PROCEDURE..ZERO-H-D-AND-SX1.. */ +L60: + sflag = -one; + sh11 = zero; + sh12 = zero; + sh21 = zero; + sh22 = zero; + + *sd1 = zero; + *sd2 = zero; + *sx1 = zero; +/* RETURN.. */ + goto L220; +/* PROCEDURE..FIX-H.. */ +L70: + if (! (sflag >= zero)) { + goto L90; + } + + if (! (sflag == zero)) { + goto L80; + } + sh11 = one; + sh22 = one; + sflag = -one; + goto L90; +L80: + sh21 = -one; + sh12 = one; + sflag = -one; +L90: + switch (igo) { + case 0: goto L120; + case 1: goto L150; + case 2: goto L180; + case 3: goto L210; + } +/* PROCEDURE..SCALE-CHECK */ +L100: +L110: + if (! (*sd1 <= rgamsq)) { + goto L130; + } + if (*sd1 == zero) { + goto L160; + } + igo = 0; + igo_fmt = fmt_120; +/* FIX-H.. */ + goto L70; +L120: +/* Computing 2nd power */ + r__1 = gam; + *sd1 *= r__1 * r__1; + *sx1 /= gam; + sh11 /= gam; + sh12 /= gam; + goto L110; +L130: +L140: + if (! (*sd1 >= gamsq)) { + goto L160; + } + igo = 1; + igo_fmt = fmt_150; +/* FIX-H.. */ + goto L70; +L150: +/* Computing 2nd power */ + r__1 = gam; + *sd1 /= r__1 * r__1; + *sx1 *= gam; + sh11 *= gam; + sh12 *= gam; + goto L140; +L160: +L170: + if (! (dabs(*sd2) <= rgamsq)) { + goto L190; + } + if (*sd2 == zero) { + goto L220; + } + igo = 2; + igo_fmt = fmt_180; +/* FIX-H.. */ + goto L70; +L180: +/* Computing 2nd power */ + r__1 = gam; + *sd2 *= r__1 * r__1; + sh21 /= gam; + sh22 /= gam; + goto L170; +L190: +L200: + if (! (dabs(*sd2) >= gamsq)) { + goto L220; + } + igo = 3; + igo_fmt = fmt_210; +/* FIX-H.. */ + goto L70; +L210: +/* Computing 2nd power */ + r__1 = gam; + *sd2 /= r__1 * r__1; + sh21 *= gam; + sh22 *= gam; + goto L200; +L220: + if (sflag < 0.f) { + goto L250; + } else if (sflag == 0) { + goto L230; + } else { + goto L240; + } +L230: + sparam[3] = sh21; + sparam[4] = sh12; + goto L260; +L240: + sparam[2] = sh11; + sparam[5] = sh22; + goto L260; +L250: + sparam[2] = sh11; + sparam[3] = sh21; + sparam[4] = sh12; + sparam[5] = sh22; +L260: + sparam[1] = sflag; + return 0; +} /* srotmg_ */ + diff --git a/ground/gcs/src/libs/eigen/blas/f2c/ssbmv.c b/ground/gcs/src/libs/eigen/blas/f2c/ssbmv.c new file mode 100644 index 0000000000..8599325f27 --- /dev/null +++ b/ground/gcs/src/libs/eigen/blas/f2c/ssbmv.c @@ -0,0 +1,368 @@ +/* ssbmv.f -- translated by f2c (version 20100827). + You must link the resulting object file with libf2c: + on Microsoft Windows system, link with libf2c.lib; + on Linux or Unix systems, link with .../path/to/libf2c.a -lm + or, if you install libf2c.a in a standard place, with -lf2c -lm + -- in that order, at the end of the command line, as in + cc *.o -lf2c -lm + Source for libf2c is in /netlib/f2c/libf2c.zip, e.g., + + http://www.netlib.org/f2c/libf2c.zip +*/ + +#include "datatypes.h" + +/* Subroutine */ int ssbmv_(char *uplo, integer *n, integer *k, real *alpha, + real *a, integer *lda, real *x, integer *incx, real *beta, real *y, + integer *incy, ftnlen uplo_len) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4; + + /* Local variables */ + integer i__, j, l, ix, iy, jx, jy, kx, ky, info; + real temp1, temp2; + extern logical lsame_(char *, char *, ftnlen, ftnlen); + integer kplus1; + extern /* Subroutine */ int xerbla_(char *, integer *, ftnlen); + +/* .. Scalar Arguments .. */ +/* .. */ +/* .. Array Arguments .. */ +/* .. */ + +/* Purpose */ +/* ======= */ + +/* SSBMV performs the matrix-vector operation */ + +/* y := alpha*A*x + beta*y, */ + +/* where alpha and beta are scalars, x and y are n element vectors and */ +/* A is an n by n symmetric band matrix, with k super-diagonals. */ + +/* Arguments */ +/* ========== */ + +/* UPLO - CHARACTER*1. */ +/* On entry, UPLO specifies whether the upper or lower */ +/* triangular part of the band matrix A is being supplied as */ +/* follows: */ + +/* UPLO = 'U' or 'u' The upper triangular part of A is */ +/* being supplied. */ + +/* UPLO = 'L' or 'l' The lower triangular part of A is */ +/* being supplied. */ + +/* Unchanged on exit. */ + +/* N - INTEGER. */ +/* On entry, N specifies the order of the matrix A. */ +/* N must be at least zero. */ +/* Unchanged on exit. */ + +/* K - INTEGER. */ +/* On entry, K specifies the number of super-diagonals of the */ +/* matrix A. K must satisfy 0 .le. K. */ +/* Unchanged on exit. */ + +/* ALPHA - REAL . */ +/* On entry, ALPHA specifies the scalar alpha. */ +/* Unchanged on exit. */ + +/* A - REAL array of DIMENSION ( LDA, n ). */ +/* Before entry with UPLO = 'U' or 'u', the leading ( k + 1 ) */ +/* by n part of the array A must contain the upper triangular */ +/* band part of the symmetric matrix, supplied column by */ +/* column, with the leading diagonal of the matrix in row */ +/* ( k + 1 ) of the array, the first super-diagonal starting at */ +/* position 2 in row k, and so on. The top left k by k triangle */ +/* of the array A is not referenced. */ +/* The following program segment will transfer the upper */ +/* triangular part of a symmetric band matrix from conventional */ +/* full matrix storage to band storage: */ + +/* DO 20, J = 1, N */ +/* M = K + 1 - J */ +/* DO 10, I = MAX( 1, J - K ), J */ +/* A( M + I, J ) = matrix( I, J ) */ +/* 10 CONTINUE */ +/* 20 CONTINUE */ + +/* Before entry with UPLO = 'L' or 'l', the leading ( k + 1 ) */ +/* by n part of the array A must contain the lower triangular */ +/* band part of the symmetric matrix, supplied column by */ +/* column, with the leading diagonal of the matrix in row 1 of */ +/* the array, the first sub-diagonal starting at position 1 in */ +/* row 2, and so on. The bottom right k by k triangle of the */ +/* array A is not referenced. */ +/* The following program segment will transfer the lower */ +/* triangular part of a symmetric band matrix from conventional */ +/* full matrix storage to band storage: */ + +/* DO 20, J = 1, N */ +/* M = 1 - J */ +/* DO 10, I = J, MIN( N, J + K ) */ +/* A( M + I, J ) = matrix( I, J ) */ +/* 10 CONTINUE */ +/* 20 CONTINUE */ + +/* Unchanged on exit. */ + +/* LDA - INTEGER. */ +/* On entry, LDA specifies the first dimension of A as declared */ +/* in the calling (sub) program. LDA must be at least */ +/* ( k + 1 ). */ +/* Unchanged on exit. */ + +/* X - REAL array of DIMENSION at least */ +/* ( 1 + ( n - 1 )*abs( INCX ) ). */ +/* Before entry, the incremented array X must contain the */ +/* vector x. */ +/* Unchanged on exit. */ + +/* INCX - INTEGER. */ +/* On entry, INCX specifies the increment for the elements of */ +/* X. INCX must not be zero. */ +/* Unchanged on exit. */ + +/* BETA - REAL . */ +/* On entry, BETA specifies the scalar beta. */ +/* Unchanged on exit. */ + +/* Y - REAL array of DIMENSION at least */ +/* ( 1 + ( n - 1 )*abs( INCY ) ). */ +/* Before entry, the incremented array Y must contain the */ +/* vector y. On exit, Y is overwritten by the updated vector y. */ + +/* INCY - INTEGER. */ +/* On entry, INCY specifies the increment for the elements of */ +/* Y. INCY must not be zero. */ +/* Unchanged on exit. */ + +/* Further Details */ +/* =============== */ + +/* Level 2 Blas routine. */ + +/* -- Written on 22-October-1986. */ +/* Jack Dongarra, Argonne National Lab. */ +/* Jeremy Du Croz, Nag Central Office. */ +/* Sven Hammarling, Nag Central Office. */ +/* Richard Hanson, Sandia National Labs. */ + +/* ===================================================================== */ + +/* .. Parameters .. */ +/* .. */ +/* .. Local Scalars .. */ +/* .. */ +/* .. External Functions .. */ +/* .. */ +/* .. External Subroutines .. */ +/* .. */ +/* .. Intrinsic Functions .. */ +/* .. */ + +/* Test the input parameters. */ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --x; + --y; + + /* Function Body */ + info = 0; + if (! lsame_(uplo, "U", (ftnlen)1, (ftnlen)1) && ! lsame_(uplo, "L", ( + ftnlen)1, (ftnlen)1)) { + info = 1; + } else if (*n < 0) { + info = 2; + } else if (*k < 0) { + info = 3; + } else if (*lda < *k + 1) { + info = 6; + } else if (*incx == 0) { + info = 8; + } else if (*incy == 0) { + info = 11; + } + if (info != 0) { + xerbla_("SSBMV ", &info, (ftnlen)6); + return 0; + } + +/* Quick return if possible. */ + + if (*n == 0 || (*alpha == 0.f && *beta == 1.f)) { + return 0; + } + +/* Set up the start points in X and Y. */ + + if (*incx > 0) { + kx = 1; + } else { + kx = 1 - (*n - 1) * *incx; + } + if (*incy > 0) { + ky = 1; + } else { + ky = 1 - (*n - 1) * *incy; + } + +/* Start the operations. In this version the elements of the array A */ +/* are accessed sequentially with one pass through A. */ + +/* First form y := beta*y. */ + + if (*beta != 1.f) { + if (*incy == 1) { + if (*beta == 0.f) { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + y[i__] = 0.f; +/* L10: */ + } + } else { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + y[i__] = *beta * y[i__]; +/* L20: */ + } + } + } else { + iy = ky; + if (*beta == 0.f) { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + y[iy] = 0.f; + iy += *incy; +/* L30: */ + } + } else { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + y[iy] = *beta * y[iy]; + iy += *incy; +/* L40: */ + } + } + } + } + if (*alpha == 0.f) { + return 0; + } + if (lsame_(uplo, "U", (ftnlen)1, (ftnlen)1)) { + +/* Form y when upper triangle of A is stored. */ + + kplus1 = *k + 1; + if (*incx == 1 && *incy == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + temp1 = *alpha * x[j]; + temp2 = 0.f; + l = kplus1 - j; +/* Computing MAX */ + i__2 = 1, i__3 = j - *k; + i__4 = j - 1; + for (i__ = max(i__2,i__3); i__ <= i__4; ++i__) { + y[i__] += temp1 * a[l + i__ + j * a_dim1]; + temp2 += a[l + i__ + j * a_dim1] * x[i__]; +/* L50: */ + } + y[j] = y[j] + temp1 * a[kplus1 + j * a_dim1] + *alpha * temp2; +/* L60: */ + } + } else { + jx = kx; + jy = ky; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + temp1 = *alpha * x[jx]; + temp2 = 0.f; + ix = kx; + iy = ky; + l = kplus1 - j; +/* Computing MAX */ + i__4 = 1, i__2 = j - *k; + i__3 = j - 1; + for (i__ = max(i__4,i__2); i__ <= i__3; ++i__) { + y[iy] += temp1 * a[l + i__ + j * a_dim1]; + temp2 += a[l + i__ + j * a_dim1] * x[ix]; + ix += *incx; + iy += *incy; +/* L70: */ + } + y[jy] = y[jy] + temp1 * a[kplus1 + j * a_dim1] + *alpha * + temp2; + jx += *incx; + jy += *incy; + if (j > *k) { + kx += *incx; + ky += *incy; + } +/* L80: */ + } + } + } else { + +/* Form y when lower triangle of A is stored. */ + + if (*incx == 1 && *incy == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + temp1 = *alpha * x[j]; + temp2 = 0.f; + y[j] += temp1 * a[j * a_dim1 + 1]; + l = 1 - j; +/* Computing MIN */ + i__4 = *n, i__2 = j + *k; + i__3 = min(i__4,i__2); + for (i__ = j + 1; i__ <= i__3; ++i__) { + y[i__] += temp1 * a[l + i__ + j * a_dim1]; + temp2 += a[l + i__ + j * a_dim1] * x[i__]; +/* L90: */ + } + y[j] += *alpha * temp2; +/* L100: */ + } + } else { + jx = kx; + jy = ky; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + temp1 = *alpha * x[jx]; + temp2 = 0.f; + y[jy] += temp1 * a[j * a_dim1 + 1]; + l = 1 - j; + ix = jx; + iy = jy; +/* Computing MIN */ + i__4 = *n, i__2 = j + *k; + i__3 = min(i__4,i__2); + for (i__ = j + 1; i__ <= i__3; ++i__) { + ix += *incx; + iy += *incy; + y[iy] += temp1 * a[l + i__ + j * a_dim1]; + temp2 += a[l + i__ + j * a_dim1] * x[ix]; +/* L110: */ + } + y[jy] += *alpha * temp2; + jx += *incx; + jy += *incy; +/* L120: */ + } + } + } + + return 0; + +/* End of SSBMV . */ + +} /* ssbmv_ */ + diff --git a/ground/gcs/src/libs/eigen/blas/f2c/sspmv.c b/ground/gcs/src/libs/eigen/blas/f2c/sspmv.c new file mode 100644 index 0000000000..47858ec6c1 --- /dev/null +++ b/ground/gcs/src/libs/eigen/blas/f2c/sspmv.c @@ -0,0 +1,316 @@ +/* sspmv.f -- translated by f2c (version 20100827). + You must link the resulting object file with libf2c: + on Microsoft Windows system, link with libf2c.lib; + on Linux or Unix systems, link with .../path/to/libf2c.a -lm + or, if you install libf2c.a in a standard place, with -lf2c -lm + -- in that order, at the end of the command line, as in + cc *.o -lf2c -lm + Source for libf2c is in /netlib/f2c/libf2c.zip, e.g., + + http://www.netlib.org/f2c/libf2c.zip +*/ + +#include "datatypes.h" + +/* Subroutine */ int sspmv_(char *uplo, integer *n, real *alpha, real *ap, + real *x, integer *incx, real *beta, real *y, integer *incy, ftnlen + uplo_len) +{ + /* System generated locals */ + integer i__1, i__2; + + /* Local variables */ + integer i__, j, k, kk, ix, iy, jx, jy, kx, ky, info; + real temp1, temp2; + extern logical lsame_(char *, char *, ftnlen, ftnlen); + extern /* Subroutine */ int xerbla_(char *, integer *, ftnlen); + +/* .. Scalar Arguments .. */ +/* .. */ +/* .. Array Arguments .. */ +/* .. */ + +/* Purpose */ +/* ======= */ + +/* SSPMV performs the matrix-vector operation */ + +/* y := alpha*A*x + beta*y, */ + +/* where alpha and beta are scalars, x and y are n element vectors and */ +/* A is an n by n symmetric matrix, supplied in packed form. */ + +/* Arguments */ +/* ========== */ + +/* UPLO - CHARACTER*1. */ +/* On entry, UPLO specifies whether the upper or lower */ +/* triangular part of the matrix A is supplied in the packed */ +/* array AP as follows: */ + +/* UPLO = 'U' or 'u' The upper triangular part of A is */ +/* supplied in AP. */ + +/* UPLO = 'L' or 'l' The lower triangular part of A is */ +/* supplied in AP. */ + +/* Unchanged on exit. */ + +/* N - INTEGER. */ +/* On entry, N specifies the order of the matrix A. */ +/* N must be at least zero. */ +/* Unchanged on exit. */ + +/* ALPHA - REAL . */ +/* On entry, ALPHA specifies the scalar alpha. */ +/* Unchanged on exit. */ + +/* AP - REAL array of DIMENSION at least */ +/* ( ( n*( n + 1 ) )/2 ). */ +/* Before entry with UPLO = 'U' or 'u', the array AP must */ +/* contain the upper triangular part of the symmetric matrix */ +/* packed sequentially, column by column, so that AP( 1 ) */ +/* contains a( 1, 1 ), AP( 2 ) and AP( 3 ) contain a( 1, 2 ) */ +/* and a( 2, 2 ) respectively, and so on. */ +/* Before entry with UPLO = 'L' or 'l', the array AP must */ +/* contain the lower triangular part of the symmetric matrix */ +/* packed sequentially, column by column, so that AP( 1 ) */ +/* contains a( 1, 1 ), AP( 2 ) and AP( 3 ) contain a( 2, 1 ) */ +/* and a( 3, 1 ) respectively, and so on. */ +/* Unchanged on exit. */ + +/* X - REAL array of dimension at least */ +/* ( 1 + ( n - 1 )*abs( INCX ) ). */ +/* Before entry, the incremented array X must contain the n */ +/* element vector x. */ +/* Unchanged on exit. */ + +/* INCX - INTEGER. */ +/* On entry, INCX specifies the increment for the elements of */ +/* X. INCX must not be zero. */ +/* Unchanged on exit. */ + +/* BETA - REAL . */ +/* On entry, BETA specifies the scalar beta. When BETA is */ +/* supplied as zero then Y need not be set on input. */ +/* Unchanged on exit. */ + +/* Y - REAL array of dimension at least */ +/* ( 1 + ( n - 1 )*abs( INCY ) ). */ +/* Before entry, the incremented array Y must contain the n */ +/* element vector y. On exit, Y is overwritten by the updated */ +/* vector y. */ + +/* INCY - INTEGER. */ +/* On entry, INCY specifies the increment for the elements of */ +/* Y. INCY must not be zero. */ +/* Unchanged on exit. */ + +/* Further Details */ +/* =============== */ + +/* Level 2 Blas routine. */ + +/* -- Written on 22-October-1986. */ +/* Jack Dongarra, Argonne National Lab. */ +/* Jeremy Du Croz, Nag Central Office. */ +/* Sven Hammarling, Nag Central Office. */ +/* Richard Hanson, Sandia National Labs. */ + +/* ===================================================================== */ + +/* .. Parameters .. */ +/* .. */ +/* .. Local Scalars .. */ +/* .. */ +/* .. External Functions .. */ +/* .. */ +/* .. External Subroutines .. */ +/* .. */ + +/* Test the input parameters. */ + + /* Parameter adjustments */ + --y; + --x; + --ap; + + /* Function Body */ + info = 0; + if (! lsame_(uplo, "U", (ftnlen)1, (ftnlen)1) && ! lsame_(uplo, "L", ( + ftnlen)1, (ftnlen)1)) { + info = 1; + } else if (*n < 0) { + info = 2; + } else if (*incx == 0) { + info = 6; + } else if (*incy == 0) { + info = 9; + } + if (info != 0) { + xerbla_("SSPMV ", &info, (ftnlen)6); + return 0; + } + +/* Quick return if possible. */ + + if (*n == 0 || (*alpha == 0.f && *beta == 1.f)) { + return 0; + } + +/* Set up the start points in X and Y. */ + + if (*incx > 0) { + kx = 1; + } else { + kx = 1 - (*n - 1) * *incx; + } + if (*incy > 0) { + ky = 1; + } else { + ky = 1 - (*n - 1) * *incy; + } + +/* Start the operations. In this version the elements of the array AP */ +/* are accessed sequentially with one pass through AP. */ + +/* First form y := beta*y. */ + + if (*beta != 1.f) { + if (*incy == 1) { + if (*beta == 0.f) { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + y[i__] = 0.f; +/* L10: */ + } + } else { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + y[i__] = *beta * y[i__]; +/* L20: */ + } + } + } else { + iy = ky; + if (*beta == 0.f) { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + y[iy] = 0.f; + iy += *incy; +/* L30: */ + } + } else { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + y[iy] = *beta * y[iy]; + iy += *incy; +/* L40: */ + } + } + } + } + if (*alpha == 0.f) { + return 0; + } + kk = 1; + if (lsame_(uplo, "U", (ftnlen)1, (ftnlen)1)) { + +/* Form y when AP contains the upper triangle. */ + + if (*incx == 1 && *incy == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + temp1 = *alpha * x[j]; + temp2 = 0.f; + k = kk; + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + y[i__] += temp1 * ap[k]; + temp2 += ap[k] * x[i__]; + ++k; +/* L50: */ + } + y[j] = y[j] + temp1 * ap[kk + j - 1] + *alpha * temp2; + kk += j; +/* L60: */ + } + } else { + jx = kx; + jy = ky; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + temp1 = *alpha * x[jx]; + temp2 = 0.f; + ix = kx; + iy = ky; + i__2 = kk + j - 2; + for (k = kk; k <= i__2; ++k) { + y[iy] += temp1 * ap[k]; + temp2 += ap[k] * x[ix]; + ix += *incx; + iy += *incy; +/* L70: */ + } + y[jy] = y[jy] + temp1 * ap[kk + j - 1] + *alpha * temp2; + jx += *incx; + jy += *incy; + kk += j; +/* L80: */ + } + } + } else { + +/* Form y when AP contains the lower triangle. */ + + if (*incx == 1 && *incy == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + temp1 = *alpha * x[j]; + temp2 = 0.f; + y[j] += temp1 * ap[kk]; + k = kk + 1; + i__2 = *n; + for (i__ = j + 1; i__ <= i__2; ++i__) { + y[i__] += temp1 * ap[k]; + temp2 += ap[k] * x[i__]; + ++k; +/* L90: */ + } + y[j] += *alpha * temp2; + kk += *n - j + 1; +/* L100: */ + } + } else { + jx = kx; + jy = ky; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + temp1 = *alpha * x[jx]; + temp2 = 0.f; + y[jy] += temp1 * ap[kk]; + ix = jx; + iy = jy; + i__2 = kk + *n - j; + for (k = kk + 1; k <= i__2; ++k) { + ix += *incx; + iy += *incy; + y[iy] += temp1 * ap[k]; + temp2 += ap[k] * x[ix]; +/* L110: */ + } + y[jy] += *alpha * temp2; + jx += *incx; + jy += *incy; + kk += *n - j + 1; +/* L120: */ + } + } + } + + return 0; + +/* End of SSPMV . */ + +} /* sspmv_ */ + diff --git a/ground/gcs/src/libs/eigen/blas/f2c/stbmv.c b/ground/gcs/src/libs/eigen/blas/f2c/stbmv.c new file mode 100644 index 0000000000..fcf9ce336f --- /dev/null +++ b/ground/gcs/src/libs/eigen/blas/f2c/stbmv.c @@ -0,0 +1,428 @@ +/* stbmv.f -- translated by f2c (version 20100827). + You must link the resulting object file with libf2c: + on Microsoft Windows system, link with libf2c.lib; + on Linux or Unix systems, link with .../path/to/libf2c.a -lm + or, if you install libf2c.a in a standard place, with -lf2c -lm + -- in that order, at the end of the command line, as in + cc *.o -lf2c -lm + Source for libf2c is in /netlib/f2c/libf2c.zip, e.g., + + http://www.netlib.org/f2c/libf2c.zip +*/ + +#include "datatypes.h" + +/* Subroutine */ int stbmv_(char *uplo, char *trans, char *diag, integer *n, + integer *k, real *a, integer *lda, real *x, integer *incx, ftnlen + uplo_len, ftnlen trans_len, ftnlen diag_len) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4; + + /* Local variables */ + integer i__, j, l, ix, jx, kx, info; + real temp; + extern logical lsame_(char *, char *, ftnlen, ftnlen); + integer kplus1; + extern /* Subroutine */ int xerbla_(char *, integer *, ftnlen); + logical nounit; + +/* .. Scalar Arguments .. */ +/* .. */ +/* .. Array Arguments .. */ +/* .. */ + +/* Purpose */ +/* ======= */ + +/* STBMV performs one of the matrix-vector operations */ + +/* x := A*x, or x := A'*x, */ + +/* where x is an n element vector and A is an n by n unit, or non-unit, */ +/* upper or lower triangular band matrix, with ( k + 1 ) diagonals. */ + +/* Arguments */ +/* ========== */ + +/* UPLO - CHARACTER*1. */ +/* On entry, UPLO specifies whether the matrix is an upper or */ +/* lower triangular matrix as follows: */ + +/* UPLO = 'U' or 'u' A is an upper triangular matrix. */ + +/* UPLO = 'L' or 'l' A is a lower triangular matrix. */ + +/* Unchanged on exit. */ + +/* TRANS - CHARACTER*1. */ +/* On entry, TRANS specifies the operation to be performed as */ +/* follows: */ + +/* TRANS = 'N' or 'n' x := A*x. */ + +/* TRANS = 'T' or 't' x := A'*x. */ + +/* TRANS = 'C' or 'c' x := A'*x. */ + +/* Unchanged on exit. */ + +/* DIAG - CHARACTER*1. */ +/* On entry, DIAG specifies whether or not A is unit */ +/* triangular as follows: */ + +/* DIAG = 'U' or 'u' A is assumed to be unit triangular. */ + +/* DIAG = 'N' or 'n' A is not assumed to be unit */ +/* triangular. */ + +/* Unchanged on exit. */ + +/* N - INTEGER. */ +/* On entry, N specifies the order of the matrix A. */ +/* N must be at least zero. */ +/* Unchanged on exit. */ + +/* K - INTEGER. */ +/* On entry with UPLO = 'U' or 'u', K specifies the number of */ +/* super-diagonals of the matrix A. */ +/* On entry with UPLO = 'L' or 'l', K specifies the number of */ +/* sub-diagonals of the matrix A. */ +/* K must satisfy 0 .le. K. */ +/* Unchanged on exit. */ + +/* A - REAL array of DIMENSION ( LDA, n ). */ +/* Before entry with UPLO = 'U' or 'u', the leading ( k + 1 ) */ +/* by n part of the array A must contain the upper triangular */ +/* band part of the matrix of coefficients, supplied column by */ +/* column, with the leading diagonal of the matrix in row */ +/* ( k + 1 ) of the array, the first super-diagonal starting at */ +/* position 2 in row k, and so on. The top left k by k triangle */ +/* of the array A is not referenced. */ +/* The following program segment will transfer an upper */ +/* triangular band matrix from conventional full matrix storage */ +/* to band storage: */ + +/* DO 20, J = 1, N */ +/* M = K + 1 - J */ +/* DO 10, I = MAX( 1, J - K ), J */ +/* A( M + I, J ) = matrix( I, J ) */ +/* 10 CONTINUE */ +/* 20 CONTINUE */ + +/* Before entry with UPLO = 'L' or 'l', the leading ( k + 1 ) */ +/* by n part of the array A must contain the lower triangular */ +/* band part of the matrix of coefficients, supplied column by */ +/* column, with the leading diagonal of the matrix in row 1 of */ +/* the array, the first sub-diagonal starting at position 1 in */ +/* row 2, and so on. The bottom right k by k triangle of the */ +/* array A is not referenced. */ +/* The following program segment will transfer a lower */ +/* triangular band matrix from conventional full matrix storage */ +/* to band storage: */ + +/* DO 20, J = 1, N */ +/* M = 1 - J */ +/* DO 10, I = J, MIN( N, J + K ) */ +/* A( M + I, J ) = matrix( I, J ) */ +/* 10 CONTINUE */ +/* 20 CONTINUE */ + +/* Note that when DIAG = 'U' or 'u' the elements of the array A */ +/* corresponding to the diagonal elements of the matrix are not */ +/* referenced, but are assumed to be unity. */ +/* Unchanged on exit. */ + +/* LDA - INTEGER. */ +/* On entry, LDA specifies the first dimension of A as declared */ +/* in the calling (sub) program. LDA must be at least */ +/* ( k + 1 ). */ +/* Unchanged on exit. */ + +/* X - REAL array of dimension at least */ +/* ( 1 + ( n - 1 )*abs( INCX ) ). */ +/* Before entry, the incremented array X must contain the n */ +/* element vector x. On exit, X is overwritten with the */ +/* tranformed vector x. */ + +/* INCX - INTEGER. */ +/* On entry, INCX specifies the increment for the elements of */ +/* X. INCX must not be zero. */ +/* Unchanged on exit. */ + +/* Further Details */ +/* =============== */ + +/* Level 2 Blas routine. */ + +/* -- Written on 22-October-1986. */ +/* Jack Dongarra, Argonne National Lab. */ +/* Jeremy Du Croz, Nag Central Office. */ +/* Sven Hammarling, Nag Central Office. */ +/* Richard Hanson, Sandia National Labs. */ + +/* ===================================================================== */ + +/* .. Parameters .. */ +/* .. */ +/* .. Local Scalars .. */ +/* .. */ +/* .. External Functions .. */ +/* .. */ +/* .. External Subroutines .. */ +/* .. */ +/* .. Intrinsic Functions .. */ +/* .. */ + +/* Test the input parameters. */ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --x; + + /* Function Body */ + info = 0; + if (! lsame_(uplo, "U", (ftnlen)1, (ftnlen)1) && ! lsame_(uplo, "L", ( + ftnlen)1, (ftnlen)1)) { + info = 1; + } else if (! lsame_(trans, "N", (ftnlen)1, (ftnlen)1) && ! lsame_(trans, + "T", (ftnlen)1, (ftnlen)1) && ! lsame_(trans, "C", (ftnlen)1, ( + ftnlen)1)) { + info = 2; + } else if (! lsame_(diag, "U", (ftnlen)1, (ftnlen)1) && ! lsame_(diag, + "N", (ftnlen)1, (ftnlen)1)) { + info = 3; + } else if (*n < 0) { + info = 4; + } else if (*k < 0) { + info = 5; + } else if (*lda < *k + 1) { + info = 7; + } else if (*incx == 0) { + info = 9; + } + if (info != 0) { + xerbla_("STBMV ", &info, (ftnlen)6); + return 0; + } + +/* Quick return if possible. */ + + if (*n == 0) { + return 0; + } + + nounit = lsame_(diag, "N", (ftnlen)1, (ftnlen)1); + +/* Set up the start point in X if the increment is not unity. This */ +/* will be ( N - 1 )*INCX too small for descending loops. */ + + if (*incx <= 0) { + kx = 1 - (*n - 1) * *incx; + } else if (*incx != 1) { + kx = 1; + } + +/* Start the operations. In this version the elements of A are */ +/* accessed sequentially with one pass through A. */ + + if (lsame_(trans, "N", (ftnlen)1, (ftnlen)1)) { + +/* Form x := A*x. */ + + if (lsame_(uplo, "U", (ftnlen)1, (ftnlen)1)) { + kplus1 = *k + 1; + if (*incx == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (x[j] != 0.f) { + temp = x[j]; + l = kplus1 - j; +/* Computing MAX */ + i__2 = 1, i__3 = j - *k; + i__4 = j - 1; + for (i__ = max(i__2,i__3); i__ <= i__4; ++i__) { + x[i__] += temp * a[l + i__ + j * a_dim1]; +/* L10: */ + } + if (nounit) { + x[j] *= a[kplus1 + j * a_dim1]; + } + } +/* L20: */ + } + } else { + jx = kx; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + if (x[jx] != 0.f) { + temp = x[jx]; + ix = kx; + l = kplus1 - j; +/* Computing MAX */ + i__4 = 1, i__2 = j - *k; + i__3 = j - 1; + for (i__ = max(i__4,i__2); i__ <= i__3; ++i__) { + x[ix] += temp * a[l + i__ + j * a_dim1]; + ix += *incx; +/* L30: */ + } + if (nounit) { + x[jx] *= a[kplus1 + j * a_dim1]; + } + } + jx += *incx; + if (j > *k) { + kx += *incx; + } +/* L40: */ + } + } + } else { + if (*incx == 1) { + for (j = *n; j >= 1; --j) { + if (x[j] != 0.f) { + temp = x[j]; + l = 1 - j; +/* Computing MIN */ + i__1 = *n, i__3 = j + *k; + i__4 = j + 1; + for (i__ = min(i__1,i__3); i__ >= i__4; --i__) { + x[i__] += temp * a[l + i__ + j * a_dim1]; +/* L50: */ + } + if (nounit) { + x[j] *= a[j * a_dim1 + 1]; + } + } +/* L60: */ + } + } else { + kx += (*n - 1) * *incx; + jx = kx; + for (j = *n; j >= 1; --j) { + if (x[jx] != 0.f) { + temp = x[jx]; + ix = kx; + l = 1 - j; +/* Computing MIN */ + i__4 = *n, i__1 = j + *k; + i__3 = j + 1; + for (i__ = min(i__4,i__1); i__ >= i__3; --i__) { + x[ix] += temp * a[l + i__ + j * a_dim1]; + ix -= *incx; +/* L70: */ + } + if (nounit) { + x[jx] *= a[j * a_dim1 + 1]; + } + } + jx -= *incx; + if (*n - j >= *k) { + kx -= *incx; + } +/* L80: */ + } + } + } + } else { + +/* Form x := A'*x. */ + + if (lsame_(uplo, "U", (ftnlen)1, (ftnlen)1)) { + kplus1 = *k + 1; + if (*incx == 1) { + for (j = *n; j >= 1; --j) { + temp = x[j]; + l = kplus1 - j; + if (nounit) { + temp *= a[kplus1 + j * a_dim1]; + } +/* Computing MAX */ + i__4 = 1, i__1 = j - *k; + i__3 = max(i__4,i__1); + for (i__ = j - 1; i__ >= i__3; --i__) { + temp += a[l + i__ + j * a_dim1] * x[i__]; +/* L90: */ + } + x[j] = temp; +/* L100: */ + } + } else { + kx += (*n - 1) * *incx; + jx = kx; + for (j = *n; j >= 1; --j) { + temp = x[jx]; + kx -= *incx; + ix = kx; + l = kplus1 - j; + if (nounit) { + temp *= a[kplus1 + j * a_dim1]; + } +/* Computing MAX */ + i__4 = 1, i__1 = j - *k; + i__3 = max(i__4,i__1); + for (i__ = j - 1; i__ >= i__3; --i__) { + temp += a[l + i__ + j * a_dim1] * x[ix]; + ix -= *incx; +/* L110: */ + } + x[jx] = temp; + jx -= *incx; +/* L120: */ + } + } + } else { + if (*incx == 1) { + i__3 = *n; + for (j = 1; j <= i__3; ++j) { + temp = x[j]; + l = 1 - j; + if (nounit) { + temp *= a[j * a_dim1 + 1]; + } +/* Computing MIN */ + i__1 = *n, i__2 = j + *k; + i__4 = min(i__1,i__2); + for (i__ = j + 1; i__ <= i__4; ++i__) { + temp += a[l + i__ + j * a_dim1] * x[i__]; +/* L130: */ + } + x[j] = temp; +/* L140: */ + } + } else { + jx = kx; + i__3 = *n; + for (j = 1; j <= i__3; ++j) { + temp = x[jx]; + kx += *incx; + ix = kx; + l = 1 - j; + if (nounit) { + temp *= a[j * a_dim1 + 1]; + } +/* Computing MIN */ + i__1 = *n, i__2 = j + *k; + i__4 = min(i__1,i__2); + for (i__ = j + 1; i__ <= i__4; ++i__) { + temp += a[l + i__ + j * a_dim1] * x[ix]; + ix += *incx; +/* L150: */ + } + x[jx] = temp; + jx += *incx; +/* L160: */ + } + } + } + } + + return 0; + +/* End of STBMV . */ + +} /* stbmv_ */ + diff --git a/ground/gcs/src/libs/eigen/blas/f2c/zhbmv.c b/ground/gcs/src/libs/eigen/blas/f2c/zhbmv.c new file mode 100644 index 0000000000..42da13dbba --- /dev/null +++ b/ground/gcs/src/libs/eigen/blas/f2c/zhbmv.c @@ -0,0 +1,488 @@ +/* zhbmv.f -- translated by f2c (version 20100827). + You must link the resulting object file with libf2c: + on Microsoft Windows system, link with libf2c.lib; + on Linux or Unix systems, link with .../path/to/libf2c.a -lm + or, if you install libf2c.a in a standard place, with -lf2c -lm + -- in that order, at the end of the command line, as in + cc *.o -lf2c -lm + Source for libf2c is in /netlib/f2c/libf2c.zip, e.g., + + http://www.netlib.org/f2c/libf2c.zip +*/ + +#include "datatypes.h" + +/* Subroutine */ int zhbmv_(char *uplo, integer *n, integer *k, doublecomplex + *alpha, doublecomplex *a, integer *lda, doublecomplex *x, integer * + incx, doublecomplex *beta, doublecomplex *y, integer *incy, ftnlen + uplo_len) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4, i__5; + doublereal d__1; + doublecomplex z__1, z__2, z__3, z__4; + + /* Builtin functions */ + void d_cnjg(doublecomplex *, doublecomplex *); + + /* Local variables */ + integer i__, j, l, ix, iy, jx, jy, kx, ky, info; + doublecomplex temp1, temp2; + extern logical lsame_(char *, char *, ftnlen, ftnlen); + integer kplus1; + extern /* Subroutine */ int xerbla_(char *, integer *, ftnlen); + +/* .. Scalar Arguments .. */ +/* .. */ +/* .. Array Arguments .. */ +/* .. */ + +/* Purpose */ +/* ======= */ + +/* ZHBMV performs the matrix-vector operation */ + +/* y := alpha*A*x + beta*y, */ + +/* where alpha and beta are scalars, x and y are n element vectors and */ +/* A is an n by n hermitian band matrix, with k super-diagonals. */ + +/* Arguments */ +/* ========== */ + +/* UPLO - CHARACTER*1. */ +/* On entry, UPLO specifies whether the upper or lower */ +/* triangular part of the band matrix A is being supplied as */ +/* follows: */ + +/* UPLO = 'U' or 'u' The upper triangular part of A is */ +/* being supplied. */ + +/* UPLO = 'L' or 'l' The lower triangular part of A is */ +/* being supplied. */ + +/* Unchanged on exit. */ + +/* N - INTEGER. */ +/* On entry, N specifies the order of the matrix A. */ +/* N must be at least zero. */ +/* Unchanged on exit. */ + +/* K - INTEGER. */ +/* On entry, K specifies the number of super-diagonals of the */ +/* matrix A. K must satisfy 0 .le. K. */ +/* Unchanged on exit. */ + +/* ALPHA - COMPLEX*16 . */ +/* On entry, ALPHA specifies the scalar alpha. */ +/* Unchanged on exit. */ + +/* A - COMPLEX*16 array of DIMENSION ( LDA, n ). */ +/* Before entry with UPLO = 'U' or 'u', the leading ( k + 1 ) */ +/* by n part of the array A must contain the upper triangular */ +/* band part of the hermitian matrix, supplied column by */ +/* column, with the leading diagonal of the matrix in row */ +/* ( k + 1 ) of the array, the first super-diagonal starting at */ +/* position 2 in row k, and so on. The top left k by k triangle */ +/* of the array A is not referenced. */ +/* The following program segment will transfer the upper */ +/* triangular part of a hermitian band matrix from conventional */ +/* full matrix storage to band storage: */ + +/* DO 20, J = 1, N */ +/* M = K + 1 - J */ +/* DO 10, I = MAX( 1, J - K ), J */ +/* A( M + I, J ) = matrix( I, J ) */ +/* 10 CONTINUE */ +/* 20 CONTINUE */ + +/* Before entry with UPLO = 'L' or 'l', the leading ( k + 1 ) */ +/* by n part of the array A must contain the lower triangular */ +/* band part of the hermitian matrix, supplied column by */ +/* column, with the leading diagonal of the matrix in row 1 of */ +/* the array, the first sub-diagonal starting at position 1 in */ +/* row 2, and so on. The bottom right k by k triangle of the */ +/* array A is not referenced. */ +/* The following program segment will transfer the lower */ +/* triangular part of a hermitian band matrix from conventional */ +/* full matrix storage to band storage: */ + +/* DO 20, J = 1, N */ +/* M = 1 - J */ +/* DO 10, I = J, MIN( N, J + K ) */ +/* A( M + I, J ) = matrix( I, J ) */ +/* 10 CONTINUE */ +/* 20 CONTINUE */ + +/* Note that the imaginary parts of the diagonal elements need */ +/* not be set and are assumed to be zero. */ +/* Unchanged on exit. */ + +/* LDA - INTEGER. */ +/* On entry, LDA specifies the first dimension of A as declared */ +/* in the calling (sub) program. LDA must be at least */ +/* ( k + 1 ). */ +/* Unchanged on exit. */ + +/* X - COMPLEX*16 array of DIMENSION at least */ +/* ( 1 + ( n - 1 )*abs( INCX ) ). */ +/* Before entry, the incremented array X must contain the */ +/* vector x. */ +/* Unchanged on exit. */ + +/* INCX - INTEGER. */ +/* On entry, INCX specifies the increment for the elements of */ +/* X. INCX must not be zero. */ +/* Unchanged on exit. */ + +/* BETA - COMPLEX*16 . */ +/* On entry, BETA specifies the scalar beta. */ +/* Unchanged on exit. */ + +/* Y - COMPLEX*16 array of DIMENSION at least */ +/* ( 1 + ( n - 1 )*abs( INCY ) ). */ +/* Before entry, the incremented array Y must contain the */ +/* vector y. On exit, Y is overwritten by the updated vector y. */ + +/* INCY - INTEGER. */ +/* On entry, INCY specifies the increment for the elements of */ +/* Y. INCY must not be zero. */ +/* Unchanged on exit. */ + +/* Further Details */ +/* =============== */ + +/* Level 2 Blas routine. */ + +/* -- Written on 22-October-1986. */ +/* Jack Dongarra, Argonne National Lab. */ +/* Jeremy Du Croz, Nag Central Office. */ +/* Sven Hammarling, Nag Central Office. */ +/* Richard Hanson, Sandia National Labs. */ + +/* ===================================================================== */ + +/* .. Parameters .. */ +/* .. */ +/* .. Local Scalars .. */ +/* .. */ +/* .. External Functions .. */ +/* .. */ +/* .. External Subroutines .. */ +/* .. */ +/* .. Intrinsic Functions .. */ +/* .. */ + +/* Test the input parameters. */ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --x; + --y; + + /* Function Body */ + info = 0; + if (! lsame_(uplo, "U", (ftnlen)1, (ftnlen)1) && ! lsame_(uplo, "L", ( + ftnlen)1, (ftnlen)1)) { + info = 1; + } else if (*n < 0) { + info = 2; + } else if (*k < 0) { + info = 3; + } else if (*lda < *k + 1) { + info = 6; + } else if (*incx == 0) { + info = 8; + } else if (*incy == 0) { + info = 11; + } + if (info != 0) { + xerbla_("ZHBMV ", &info, (ftnlen)6); + return 0; + } + +/* Quick return if possible. */ + + if (*n == 0 || (alpha->r == 0. && alpha->i == 0. && (beta->r == 1. && + beta->i == 0.))) { + return 0; + } + +/* Set up the start points in X and Y. */ + + if (*incx > 0) { + kx = 1; + } else { + kx = 1 - (*n - 1) * *incx; + } + if (*incy > 0) { + ky = 1; + } else { + ky = 1 - (*n - 1) * *incy; + } + +/* Start the operations. In this version the elements of the array A */ +/* are accessed sequentially with one pass through A. */ + +/* First form y := beta*y. */ + + if (beta->r != 1. || beta->i != 0.) { + if (*incy == 1) { + if (beta->r == 0. && beta->i == 0.) { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__; + y[i__2].r = 0., y[i__2].i = 0.; +/* L10: */ + } + } else { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__; + i__3 = i__; + z__1.r = beta->r * y[i__3].r - beta->i * y[i__3].i, + z__1.i = beta->r * y[i__3].i + beta->i * y[i__3] + .r; + y[i__2].r = z__1.r, y[i__2].i = z__1.i; +/* L20: */ + } + } + } else { + iy = ky; + if (beta->r == 0. && beta->i == 0.) { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = iy; + y[i__2].r = 0., y[i__2].i = 0.; + iy += *incy; +/* L30: */ + } + } else { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = iy; + i__3 = iy; + z__1.r = beta->r * y[i__3].r - beta->i * y[i__3].i, + z__1.i = beta->r * y[i__3].i + beta->i * y[i__3] + .r; + y[i__2].r = z__1.r, y[i__2].i = z__1.i; + iy += *incy; +/* L40: */ + } + } + } + } + if (alpha->r == 0. && alpha->i == 0.) { + return 0; + } + if (lsame_(uplo, "U", (ftnlen)1, (ftnlen)1)) { + +/* Form y when upper triangle of A is stored. */ + + kplus1 = *k + 1; + if (*incx == 1 && *incy == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j; + z__1.r = alpha->r * x[i__2].r - alpha->i * x[i__2].i, z__1.i = + alpha->r * x[i__2].i + alpha->i * x[i__2].r; + temp1.r = z__1.r, temp1.i = z__1.i; + temp2.r = 0., temp2.i = 0.; + l = kplus1 - j; +/* Computing MAX */ + i__2 = 1, i__3 = j - *k; + i__4 = j - 1; + for (i__ = max(i__2,i__3); i__ <= i__4; ++i__) { + i__2 = i__; + i__3 = i__; + i__5 = l + i__ + j * a_dim1; + z__2.r = temp1.r * a[i__5].r - temp1.i * a[i__5].i, + z__2.i = temp1.r * a[i__5].i + temp1.i * a[i__5] + .r; + z__1.r = y[i__3].r + z__2.r, z__1.i = y[i__3].i + z__2.i; + y[i__2].r = z__1.r, y[i__2].i = z__1.i; + d_cnjg(&z__3, &a[l + i__ + j * a_dim1]); + i__2 = i__; + z__2.r = z__3.r * x[i__2].r - z__3.i * x[i__2].i, z__2.i = + z__3.r * x[i__2].i + z__3.i * x[i__2].r; + z__1.r = temp2.r + z__2.r, z__1.i = temp2.i + z__2.i; + temp2.r = z__1.r, temp2.i = z__1.i; +/* L50: */ + } + i__4 = j; + i__2 = j; + i__3 = kplus1 + j * a_dim1; + d__1 = a[i__3].r; + z__3.r = d__1 * temp1.r, z__3.i = d__1 * temp1.i; + z__2.r = y[i__2].r + z__3.r, z__2.i = y[i__2].i + z__3.i; + z__4.r = alpha->r * temp2.r - alpha->i * temp2.i, z__4.i = + alpha->r * temp2.i + alpha->i * temp2.r; + z__1.r = z__2.r + z__4.r, z__1.i = z__2.i + z__4.i; + y[i__4].r = z__1.r, y[i__4].i = z__1.i; +/* L60: */ + } + } else { + jx = kx; + jy = ky; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__4 = jx; + z__1.r = alpha->r * x[i__4].r - alpha->i * x[i__4].i, z__1.i = + alpha->r * x[i__4].i + alpha->i * x[i__4].r; + temp1.r = z__1.r, temp1.i = z__1.i; + temp2.r = 0., temp2.i = 0.; + ix = kx; + iy = ky; + l = kplus1 - j; +/* Computing MAX */ + i__4 = 1, i__2 = j - *k; + i__3 = j - 1; + for (i__ = max(i__4,i__2); i__ <= i__3; ++i__) { + i__4 = iy; + i__2 = iy; + i__5 = l + i__ + j * a_dim1; + z__2.r = temp1.r * a[i__5].r - temp1.i * a[i__5].i, + z__2.i = temp1.r * a[i__5].i + temp1.i * a[i__5] + .r; + z__1.r = y[i__2].r + z__2.r, z__1.i = y[i__2].i + z__2.i; + y[i__4].r = z__1.r, y[i__4].i = z__1.i; + d_cnjg(&z__3, &a[l + i__ + j * a_dim1]); + i__4 = ix; + z__2.r = z__3.r * x[i__4].r - z__3.i * x[i__4].i, z__2.i = + z__3.r * x[i__4].i + z__3.i * x[i__4].r; + z__1.r = temp2.r + z__2.r, z__1.i = temp2.i + z__2.i; + temp2.r = z__1.r, temp2.i = z__1.i; + ix += *incx; + iy += *incy; +/* L70: */ + } + i__3 = jy; + i__4 = jy; + i__2 = kplus1 + j * a_dim1; + d__1 = a[i__2].r; + z__3.r = d__1 * temp1.r, z__3.i = d__1 * temp1.i; + z__2.r = y[i__4].r + z__3.r, z__2.i = y[i__4].i + z__3.i; + z__4.r = alpha->r * temp2.r - alpha->i * temp2.i, z__4.i = + alpha->r * temp2.i + alpha->i * temp2.r; + z__1.r = z__2.r + z__4.r, z__1.i = z__2.i + z__4.i; + y[i__3].r = z__1.r, y[i__3].i = z__1.i; + jx += *incx; + jy += *incy; + if (j > *k) { + kx += *incx; + ky += *incy; + } +/* L80: */ + } + } + } else { + +/* Form y when lower triangle of A is stored. */ + + if (*incx == 1 && *incy == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__3 = j; + z__1.r = alpha->r * x[i__3].r - alpha->i * x[i__3].i, z__1.i = + alpha->r * x[i__3].i + alpha->i * x[i__3].r; + temp1.r = z__1.r, temp1.i = z__1.i; + temp2.r = 0., temp2.i = 0.; + i__3 = j; + i__4 = j; + i__2 = j * a_dim1 + 1; + d__1 = a[i__2].r; + z__2.r = d__1 * temp1.r, z__2.i = d__1 * temp1.i; + z__1.r = y[i__4].r + z__2.r, z__1.i = y[i__4].i + z__2.i; + y[i__3].r = z__1.r, y[i__3].i = z__1.i; + l = 1 - j; +/* Computing MIN */ + i__4 = *n, i__2 = j + *k; + i__3 = min(i__4,i__2); + for (i__ = j + 1; i__ <= i__3; ++i__) { + i__4 = i__; + i__2 = i__; + i__5 = l + i__ + j * a_dim1; + z__2.r = temp1.r * a[i__5].r - temp1.i * a[i__5].i, + z__2.i = temp1.r * a[i__5].i + temp1.i * a[i__5] + .r; + z__1.r = y[i__2].r + z__2.r, z__1.i = y[i__2].i + z__2.i; + y[i__4].r = z__1.r, y[i__4].i = z__1.i; + d_cnjg(&z__3, &a[l + i__ + j * a_dim1]); + i__4 = i__; + z__2.r = z__3.r * x[i__4].r - z__3.i * x[i__4].i, z__2.i = + z__3.r * x[i__4].i + z__3.i * x[i__4].r; + z__1.r = temp2.r + z__2.r, z__1.i = temp2.i + z__2.i; + temp2.r = z__1.r, temp2.i = z__1.i; +/* L90: */ + } + i__3 = j; + i__4 = j; + z__2.r = alpha->r * temp2.r - alpha->i * temp2.i, z__2.i = + alpha->r * temp2.i + alpha->i * temp2.r; + z__1.r = y[i__4].r + z__2.r, z__1.i = y[i__4].i + z__2.i; + y[i__3].r = z__1.r, y[i__3].i = z__1.i; +/* L100: */ + } + } else { + jx = kx; + jy = ky; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__3 = jx; + z__1.r = alpha->r * x[i__3].r - alpha->i * x[i__3].i, z__1.i = + alpha->r * x[i__3].i + alpha->i * x[i__3].r; + temp1.r = z__1.r, temp1.i = z__1.i; + temp2.r = 0., temp2.i = 0.; + i__3 = jy; + i__4 = jy; + i__2 = j * a_dim1 + 1; + d__1 = a[i__2].r; + z__2.r = d__1 * temp1.r, z__2.i = d__1 * temp1.i; + z__1.r = y[i__4].r + z__2.r, z__1.i = y[i__4].i + z__2.i; + y[i__3].r = z__1.r, y[i__3].i = z__1.i; + l = 1 - j; + ix = jx; + iy = jy; +/* Computing MIN */ + i__4 = *n, i__2 = j + *k; + i__3 = min(i__4,i__2); + for (i__ = j + 1; i__ <= i__3; ++i__) { + ix += *incx; + iy += *incy; + i__4 = iy; + i__2 = iy; + i__5 = l + i__ + j * a_dim1; + z__2.r = temp1.r * a[i__5].r - temp1.i * a[i__5].i, + z__2.i = temp1.r * a[i__5].i + temp1.i * a[i__5] + .r; + z__1.r = y[i__2].r + z__2.r, z__1.i = y[i__2].i + z__2.i; + y[i__4].r = z__1.r, y[i__4].i = z__1.i; + d_cnjg(&z__3, &a[l + i__ + j * a_dim1]); + i__4 = ix; + z__2.r = z__3.r * x[i__4].r - z__3.i * x[i__4].i, z__2.i = + z__3.r * x[i__4].i + z__3.i * x[i__4].r; + z__1.r = temp2.r + z__2.r, z__1.i = temp2.i + z__2.i; + temp2.r = z__1.r, temp2.i = z__1.i; +/* L110: */ + } + i__3 = jy; + i__4 = jy; + z__2.r = alpha->r * temp2.r - alpha->i * temp2.i, z__2.i = + alpha->r * temp2.i + alpha->i * temp2.r; + z__1.r = y[i__4].r + z__2.r, z__1.i = y[i__4].i + z__2.i; + y[i__3].r = z__1.r, y[i__3].i = z__1.i; + jx += *incx; + jy += *incy; +/* L120: */ + } + } + } + + return 0; + +/* End of ZHBMV . */ + +} /* zhbmv_ */ + diff --git a/ground/gcs/src/libs/eigen/blas/f2c/zhpmv.c b/ground/gcs/src/libs/eigen/blas/f2c/zhpmv.c new file mode 100644 index 0000000000..fbe2f42b3d --- /dev/null +++ b/ground/gcs/src/libs/eigen/blas/f2c/zhpmv.c @@ -0,0 +1,438 @@ +/* zhpmv.f -- translated by f2c (version 20100827). + You must link the resulting object file with libf2c: + on Microsoft Windows system, link with libf2c.lib; + on Linux or Unix systems, link with .../path/to/libf2c.a -lm + or, if you install libf2c.a in a standard place, with -lf2c -lm + -- in that order, at the end of the command line, as in + cc *.o -lf2c -lm + Source for libf2c is in /netlib/f2c/libf2c.zip, e.g., + + http://www.netlib.org/f2c/libf2c.zip +*/ + +#include "datatypes.h" + +/* Subroutine */ int zhpmv_(char *uplo, integer *n, doublecomplex *alpha, + doublecomplex *ap, doublecomplex *x, integer *incx, doublecomplex * + beta, doublecomplex *y, integer *incy, ftnlen uplo_len) +{ + /* System generated locals */ + integer i__1, i__2, i__3, i__4, i__5; + doublereal d__1; + doublecomplex z__1, z__2, z__3, z__4; + + /* Builtin functions */ + void d_cnjg(doublecomplex *, doublecomplex *); + + /* Local variables */ + integer i__, j, k, kk, ix, iy, jx, jy, kx, ky, info; + doublecomplex temp1, temp2; + extern logical lsame_(char *, char *, ftnlen, ftnlen); + extern /* Subroutine */ int xerbla_(char *, integer *, ftnlen); + +/* .. Scalar Arguments .. */ +/* .. */ +/* .. Array Arguments .. */ +/* .. */ + +/* Purpose */ +/* ======= */ + +/* ZHPMV performs the matrix-vector operation */ + +/* y := alpha*A*x + beta*y, */ + +/* where alpha and beta are scalars, x and y are n element vectors and */ +/* A is an n by n hermitian matrix, supplied in packed form. */ + +/* Arguments */ +/* ========== */ + +/* UPLO - CHARACTER*1. */ +/* On entry, UPLO specifies whether the upper or lower */ +/* triangular part of the matrix A is supplied in the packed */ +/* array AP as follows: */ + +/* UPLO = 'U' or 'u' The upper triangular part of A is */ +/* supplied in AP. */ + +/* UPLO = 'L' or 'l' The lower triangular part of A is */ +/* supplied in AP. */ + +/* Unchanged on exit. */ + +/* N - INTEGER. */ +/* On entry, N specifies the order of the matrix A. */ +/* N must be at least zero. */ +/* Unchanged on exit. */ + +/* ALPHA - COMPLEX*16 . */ +/* On entry, ALPHA specifies the scalar alpha. */ +/* Unchanged on exit. */ + +/* AP - COMPLEX*16 array of DIMENSION at least */ +/* ( ( n*( n + 1 ) )/2 ). */ +/* Before entry with UPLO = 'U' or 'u', the array AP must */ +/* contain the upper triangular part of the hermitian matrix */ +/* packed sequentially, column by column, so that AP( 1 ) */ +/* contains a( 1, 1 ), AP( 2 ) and AP( 3 ) contain a( 1, 2 ) */ +/* and a( 2, 2 ) respectively, and so on. */ +/* Before entry with UPLO = 'L' or 'l', the array AP must */ +/* contain the lower triangular part of the hermitian matrix */ +/* packed sequentially, column by column, so that AP( 1 ) */ +/* contains a( 1, 1 ), AP( 2 ) and AP( 3 ) contain a( 2, 1 ) */ +/* and a( 3, 1 ) respectively, and so on. */ +/* Note that the imaginary parts of the diagonal elements need */ +/* not be set and are assumed to be zero. */ +/* Unchanged on exit. */ + +/* X - COMPLEX*16 array of dimension at least */ +/* ( 1 + ( n - 1 )*abs( INCX ) ). */ +/* Before entry, the incremented array X must contain the n */ +/* element vector x. */ +/* Unchanged on exit. */ + +/* INCX - INTEGER. */ +/* On entry, INCX specifies the increment for the elements of */ +/* X. INCX must not be zero. */ +/* Unchanged on exit. */ + +/* BETA - COMPLEX*16 . */ +/* On entry, BETA specifies the scalar beta. When BETA is */ +/* supplied as zero then Y need not be set on input. */ +/* Unchanged on exit. */ + +/* Y - COMPLEX*16 array of dimension at least */ +/* ( 1 + ( n - 1 )*abs( INCY ) ). */ +/* Before entry, the incremented array Y must contain the n */ +/* element vector y. On exit, Y is overwritten by the updated */ +/* vector y. */ + +/* INCY - INTEGER. */ +/* On entry, INCY specifies the increment for the elements of */ +/* Y. INCY must not be zero. */ +/* Unchanged on exit. */ + +/* Further Details */ +/* =============== */ + +/* Level 2 Blas routine. */ + +/* -- Written on 22-October-1986. */ +/* Jack Dongarra, Argonne National Lab. */ +/* Jeremy Du Croz, Nag Central Office. */ +/* Sven Hammarling, Nag Central Office. */ +/* Richard Hanson, Sandia National Labs. */ + +/* ===================================================================== */ + +/* .. Parameters .. */ +/* .. */ +/* .. Local Scalars .. */ +/* .. */ +/* .. External Functions .. */ +/* .. */ +/* .. External Subroutines .. */ +/* .. */ +/* .. Intrinsic Functions .. */ +/* .. */ + +/* Test the input parameters. */ + + /* Parameter adjustments */ + --y; + --x; + --ap; + + /* Function Body */ + info = 0; + if (! lsame_(uplo, "U", (ftnlen)1, (ftnlen)1) && ! lsame_(uplo, "L", ( + ftnlen)1, (ftnlen)1)) { + info = 1; + } else if (*n < 0) { + info = 2; + } else if (*incx == 0) { + info = 6; + } else if (*incy == 0) { + info = 9; + } + if (info != 0) { + xerbla_("ZHPMV ", &info, (ftnlen)6); + return 0; + } + +/* Quick return if possible. */ + + if (*n == 0 || (alpha->r == 0. && alpha->i == 0. && (beta->r == 1. && + beta->i == 0.))) { + return 0; + } + +/* Set up the start points in X and Y. */ + + if (*incx > 0) { + kx = 1; + } else { + kx = 1 - (*n - 1) * *incx; + } + if (*incy > 0) { + ky = 1; + } else { + ky = 1 - (*n - 1) * *incy; + } + +/* Start the operations. In this version the elements of the array AP */ +/* are accessed sequentially with one pass through AP. */ + +/* First form y := beta*y. */ + + if (beta->r != 1. || beta->i != 0.) { + if (*incy == 1) { + if (beta->r == 0. && beta->i == 0.) { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__; + y[i__2].r = 0., y[i__2].i = 0.; +/* L10: */ + } + } else { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = i__; + i__3 = i__; + z__1.r = beta->r * y[i__3].r - beta->i * y[i__3].i, + z__1.i = beta->r * y[i__3].i + beta->i * y[i__3] + .r; + y[i__2].r = z__1.r, y[i__2].i = z__1.i; +/* L20: */ + } + } + } else { + iy = ky; + if (beta->r == 0. && beta->i == 0.) { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = iy; + y[i__2].r = 0., y[i__2].i = 0.; + iy += *incy; +/* L30: */ + } + } else { + i__1 = *n; + for (i__ = 1; i__ <= i__1; ++i__) { + i__2 = iy; + i__3 = iy; + z__1.r = beta->r * y[i__3].r - beta->i * y[i__3].i, + z__1.i = beta->r * y[i__3].i + beta->i * y[i__3] + .r; + y[i__2].r = z__1.r, y[i__2].i = z__1.i; + iy += *incy; +/* L40: */ + } + } + } + } + if (alpha->r == 0. && alpha->i == 0.) { + return 0; + } + kk = 1; + if (lsame_(uplo, "U", (ftnlen)1, (ftnlen)1)) { + +/* Form y when AP contains the upper triangle. */ + + if (*incx == 1 && *incy == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j; + z__1.r = alpha->r * x[i__2].r - alpha->i * x[i__2].i, z__1.i = + alpha->r * x[i__2].i + alpha->i * x[i__2].r; + temp1.r = z__1.r, temp1.i = z__1.i; + temp2.r = 0., temp2.i = 0.; + k = kk; + i__2 = j - 1; + for (i__ = 1; i__ <= i__2; ++i__) { + i__3 = i__; + i__4 = i__; + i__5 = k; + z__2.r = temp1.r * ap[i__5].r - temp1.i * ap[i__5].i, + z__2.i = temp1.r * ap[i__5].i + temp1.i * ap[i__5] + .r; + z__1.r = y[i__4].r + z__2.r, z__1.i = y[i__4].i + z__2.i; + y[i__3].r = z__1.r, y[i__3].i = z__1.i; + d_cnjg(&z__3, &ap[k]); + i__3 = i__; + z__2.r = z__3.r * x[i__3].r - z__3.i * x[i__3].i, z__2.i = + z__3.r * x[i__3].i + z__3.i * x[i__3].r; + z__1.r = temp2.r + z__2.r, z__1.i = temp2.i + z__2.i; + temp2.r = z__1.r, temp2.i = z__1.i; + ++k; +/* L50: */ + } + i__2 = j; + i__3 = j; + i__4 = kk + j - 1; + d__1 = ap[i__4].r; + z__3.r = d__1 * temp1.r, z__3.i = d__1 * temp1.i; + z__2.r = y[i__3].r + z__3.r, z__2.i = y[i__3].i + z__3.i; + z__4.r = alpha->r * temp2.r - alpha->i * temp2.i, z__4.i = + alpha->r * temp2.i + alpha->i * temp2.r; + z__1.r = z__2.r + z__4.r, z__1.i = z__2.i + z__4.i; + y[i__2].r = z__1.r, y[i__2].i = z__1.i; + kk += j; +/* L60: */ + } + } else { + jx = kx; + jy = ky; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = jx; + z__1.r = alpha->r * x[i__2].r - alpha->i * x[i__2].i, z__1.i = + alpha->r * x[i__2].i + alpha->i * x[i__2].r; + temp1.r = z__1.r, temp1.i = z__1.i; + temp2.r = 0., temp2.i = 0.; + ix = kx; + iy = ky; + i__2 = kk + j - 2; + for (k = kk; k <= i__2; ++k) { + i__3 = iy; + i__4 = iy; + i__5 = k; + z__2.r = temp1.r * ap[i__5].r - temp1.i * ap[i__5].i, + z__2.i = temp1.r * ap[i__5].i + temp1.i * ap[i__5] + .r; + z__1.r = y[i__4].r + z__2.r, z__1.i = y[i__4].i + z__2.i; + y[i__3].r = z__1.r, y[i__3].i = z__1.i; + d_cnjg(&z__3, &ap[k]); + i__3 = ix; + z__2.r = z__3.r * x[i__3].r - z__3.i * x[i__3].i, z__2.i = + z__3.r * x[i__3].i + z__3.i * x[i__3].r; + z__1.r = temp2.r + z__2.r, z__1.i = temp2.i + z__2.i; + temp2.r = z__1.r, temp2.i = z__1.i; + ix += *incx; + iy += *incy; +/* L70: */ + } + i__2 = jy; + i__3 = jy; + i__4 = kk + j - 1; + d__1 = ap[i__4].r; + z__3.r = d__1 * temp1.r, z__3.i = d__1 * temp1.i; + z__2.r = y[i__3].r + z__3.r, z__2.i = y[i__3].i + z__3.i; + z__4.r = alpha->r * temp2.r - alpha->i * temp2.i, z__4.i = + alpha->r * temp2.i + alpha->i * temp2.r; + z__1.r = z__2.r + z__4.r, z__1.i = z__2.i + z__4.i; + y[i__2].r = z__1.r, y[i__2].i = z__1.i; + jx += *incx; + jy += *incy; + kk += j; +/* L80: */ + } + } + } else { + +/* Form y when AP contains the lower triangle. */ + + if (*incx == 1 && *incy == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j; + z__1.r = alpha->r * x[i__2].r - alpha->i * x[i__2].i, z__1.i = + alpha->r * x[i__2].i + alpha->i * x[i__2].r; + temp1.r = z__1.r, temp1.i = z__1.i; + temp2.r = 0., temp2.i = 0.; + i__2 = j; + i__3 = j; + i__4 = kk; + d__1 = ap[i__4].r; + z__2.r = d__1 * temp1.r, z__2.i = d__1 * temp1.i; + z__1.r = y[i__3].r + z__2.r, z__1.i = y[i__3].i + z__2.i; + y[i__2].r = z__1.r, y[i__2].i = z__1.i; + k = kk + 1; + i__2 = *n; + for (i__ = j + 1; i__ <= i__2; ++i__) { + i__3 = i__; + i__4 = i__; + i__5 = k; + z__2.r = temp1.r * ap[i__5].r - temp1.i * ap[i__5].i, + z__2.i = temp1.r * ap[i__5].i + temp1.i * ap[i__5] + .r; + z__1.r = y[i__4].r + z__2.r, z__1.i = y[i__4].i + z__2.i; + y[i__3].r = z__1.r, y[i__3].i = z__1.i; + d_cnjg(&z__3, &ap[k]); + i__3 = i__; + z__2.r = z__3.r * x[i__3].r - z__3.i * x[i__3].i, z__2.i = + z__3.r * x[i__3].i + z__3.i * x[i__3].r; + z__1.r = temp2.r + z__2.r, z__1.i = temp2.i + z__2.i; + temp2.r = z__1.r, temp2.i = z__1.i; + ++k; +/* L90: */ + } + i__2 = j; + i__3 = j; + z__2.r = alpha->r * temp2.r - alpha->i * temp2.i, z__2.i = + alpha->r * temp2.i + alpha->i * temp2.r; + z__1.r = y[i__3].r + z__2.r, z__1.i = y[i__3].i + z__2.i; + y[i__2].r = z__1.r, y[i__2].i = z__1.i; + kk += *n - j + 1; +/* L100: */ + } + } else { + jx = kx; + jy = ky; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = jx; + z__1.r = alpha->r * x[i__2].r - alpha->i * x[i__2].i, z__1.i = + alpha->r * x[i__2].i + alpha->i * x[i__2].r; + temp1.r = z__1.r, temp1.i = z__1.i; + temp2.r = 0., temp2.i = 0.; + i__2 = jy; + i__3 = jy; + i__4 = kk; + d__1 = ap[i__4].r; + z__2.r = d__1 * temp1.r, z__2.i = d__1 * temp1.i; + z__1.r = y[i__3].r + z__2.r, z__1.i = y[i__3].i + z__2.i; + y[i__2].r = z__1.r, y[i__2].i = z__1.i; + ix = jx; + iy = jy; + i__2 = kk + *n - j; + for (k = kk + 1; k <= i__2; ++k) { + ix += *incx; + iy += *incy; + i__3 = iy; + i__4 = iy; + i__5 = k; + z__2.r = temp1.r * ap[i__5].r - temp1.i * ap[i__5].i, + z__2.i = temp1.r * ap[i__5].i + temp1.i * ap[i__5] + .r; + z__1.r = y[i__4].r + z__2.r, z__1.i = y[i__4].i + z__2.i; + y[i__3].r = z__1.r, y[i__3].i = z__1.i; + d_cnjg(&z__3, &ap[k]); + i__3 = ix; + z__2.r = z__3.r * x[i__3].r - z__3.i * x[i__3].i, z__2.i = + z__3.r * x[i__3].i + z__3.i * x[i__3].r; + z__1.r = temp2.r + z__2.r, z__1.i = temp2.i + z__2.i; + temp2.r = z__1.r, temp2.i = z__1.i; +/* L110: */ + } + i__2 = jy; + i__3 = jy; + z__2.r = alpha->r * temp2.r - alpha->i * temp2.i, z__2.i = + alpha->r * temp2.i + alpha->i * temp2.r; + z__1.r = y[i__3].r + z__2.r, z__1.i = y[i__3].i + z__2.i; + y[i__2].r = z__1.r, y[i__2].i = z__1.i; + jx += *incx; + jy += *incy; + kk += *n - j + 1; +/* L120: */ + } + } + } + + return 0; + +/* End of ZHPMV . */ + +} /* zhpmv_ */ + diff --git a/ground/gcs/src/libs/eigen/blas/f2c/ztbmv.c b/ground/gcs/src/libs/eigen/blas/f2c/ztbmv.c new file mode 100644 index 0000000000..4cdcd7f889 --- /dev/null +++ b/ground/gcs/src/libs/eigen/blas/f2c/ztbmv.c @@ -0,0 +1,647 @@ +/* ztbmv.f -- translated by f2c (version 20100827). + You must link the resulting object file with libf2c: + on Microsoft Windows system, link with libf2c.lib; + on Linux or Unix systems, link with .../path/to/libf2c.a -lm + or, if you install libf2c.a in a standard place, with -lf2c -lm + -- in that order, at the end of the command line, as in + cc *.o -lf2c -lm + Source for libf2c is in /netlib/f2c/libf2c.zip, e.g., + + http://www.netlib.org/f2c/libf2c.zip +*/ + +#include "datatypes.h" + +/* Subroutine */ int ztbmv_(char *uplo, char *trans, char *diag, integer *n, + integer *k, doublecomplex *a, integer *lda, doublecomplex *x, integer + *incx, ftnlen uplo_len, ftnlen trans_len, ftnlen diag_len) +{ + /* System generated locals */ + integer a_dim1, a_offset, i__1, i__2, i__3, i__4, i__5; + doublecomplex z__1, z__2, z__3; + + /* Builtin functions */ + void d_cnjg(doublecomplex *, doublecomplex *); + + /* Local variables */ + integer i__, j, l, ix, jx, kx, info; + doublecomplex temp; + extern logical lsame_(char *, char *, ftnlen, ftnlen); + integer kplus1; + extern /* Subroutine */ int xerbla_(char *, integer *, ftnlen); + logical noconj, nounit; + +/* .. Scalar Arguments .. */ +/* .. */ +/* .. Array Arguments .. */ +/* .. */ + +/* Purpose */ +/* ======= */ + +/* ZTBMV performs one of the matrix-vector operations */ + +/* x := A*x, or x := A'*x, or x := conjg( A' )*x, */ + +/* where x is an n element vector and A is an n by n unit, or non-unit, */ +/* upper or lower triangular band matrix, with ( k + 1 ) diagonals. */ + +/* Arguments */ +/* ========== */ + +/* UPLO - CHARACTER*1. */ +/* On entry, UPLO specifies whether the matrix is an upper or */ +/* lower triangular matrix as follows: */ + +/* UPLO = 'U' or 'u' A is an upper triangular matrix. */ + +/* UPLO = 'L' or 'l' A is a lower triangular matrix. */ + +/* Unchanged on exit. */ + +/* TRANS - CHARACTER*1. */ +/* On entry, TRANS specifies the operation to be performed as */ +/* follows: */ + +/* TRANS = 'N' or 'n' x := A*x. */ + +/* TRANS = 'T' or 't' x := A'*x. */ + +/* TRANS = 'C' or 'c' x := conjg( A' )*x. */ + +/* Unchanged on exit. */ + +/* DIAG - CHARACTER*1. */ +/* On entry, DIAG specifies whether or not A is unit */ +/* triangular as follows: */ + +/* DIAG = 'U' or 'u' A is assumed to be unit triangular. */ + +/* DIAG = 'N' or 'n' A is not assumed to be unit */ +/* triangular. */ + +/* Unchanged on exit. */ + +/* N - INTEGER. */ +/* On entry, N specifies the order of the matrix A. */ +/* N must be at least zero. */ +/* Unchanged on exit. */ + +/* K - INTEGER. */ +/* On entry with UPLO = 'U' or 'u', K specifies the number of */ +/* super-diagonals of the matrix A. */ +/* On entry with UPLO = 'L' or 'l', K specifies the number of */ +/* sub-diagonals of the matrix A. */ +/* K must satisfy 0 .le. K. */ +/* Unchanged on exit. */ + +/* A - COMPLEX*16 array of DIMENSION ( LDA, n ). */ +/* Before entry with UPLO = 'U' or 'u', the leading ( k + 1 ) */ +/* by n part of the array A must contain the upper triangular */ +/* band part of the matrix of coefficients, supplied column by */ +/* column, with the leading diagonal of the matrix in row */ +/* ( k + 1 ) of the array, the first super-diagonal starting at */ +/* position 2 in row k, and so on. The top left k by k triangle */ +/* of the array A is not referenced. */ +/* The following program segment will transfer an upper */ +/* triangular band matrix from conventional full matrix storage */ +/* to band storage: */ + +/* DO 20, J = 1, N */ +/* M = K + 1 - J */ +/* DO 10, I = MAX( 1, J - K ), J */ +/* A( M + I, J ) = matrix( I, J ) */ +/* 10 CONTINUE */ +/* 20 CONTINUE */ + +/* Before entry with UPLO = 'L' or 'l', the leading ( k + 1 ) */ +/* by n part of the array A must contain the lower triangular */ +/* band part of the matrix of coefficients, supplied column by */ +/* column, with the leading diagonal of the matrix in row 1 of */ +/* the array, the first sub-diagonal starting at position 1 in */ +/* row 2, and so on. The bottom right k by k triangle of the */ +/* array A is not referenced. */ +/* The following program segment will transfer a lower */ +/* triangular band matrix from conventional full matrix storage */ +/* to band storage: */ + +/* DO 20, J = 1, N */ +/* M = 1 - J */ +/* DO 10, I = J, MIN( N, J + K ) */ +/* A( M + I, J ) = matrix( I, J ) */ +/* 10 CONTINUE */ +/* 20 CONTINUE */ + +/* Note that when DIAG = 'U' or 'u' the elements of the array A */ +/* corresponding to the diagonal elements of the matrix are not */ +/* referenced, but are assumed to be unity. */ +/* Unchanged on exit. */ + +/* LDA - INTEGER. */ +/* On entry, LDA specifies the first dimension of A as declared */ +/* in the calling (sub) program. LDA must be at least */ +/* ( k + 1 ). */ +/* Unchanged on exit. */ + +/* X - COMPLEX*16 array of dimension at least */ +/* ( 1 + ( n - 1 )*abs( INCX ) ). */ +/* Before entry, the incremented array X must contain the n */ +/* element vector x. On exit, X is overwritten with the */ +/* tranformed vector x. */ + +/* INCX - INTEGER. */ +/* On entry, INCX specifies the increment for the elements of */ +/* X. INCX must not be zero. */ +/* Unchanged on exit. */ + +/* Further Details */ +/* =============== */ + +/* Level 2 Blas routine. */ + +/* -- Written on 22-October-1986. */ +/* Jack Dongarra, Argonne National Lab. */ +/* Jeremy Du Croz, Nag Central Office. */ +/* Sven Hammarling, Nag Central Office. */ +/* Richard Hanson, Sandia National Labs. */ + +/* ===================================================================== */ + +/* .. Parameters .. */ +/* .. */ +/* .. Local Scalars .. */ +/* .. */ +/* .. External Functions .. */ +/* .. */ +/* .. External Subroutines .. */ +/* .. */ +/* .. Intrinsic Functions .. */ +/* .. */ + +/* Test the input parameters. */ + + /* Parameter adjustments */ + a_dim1 = *lda; + a_offset = 1 + a_dim1; + a -= a_offset; + --x; + + /* Function Body */ + info = 0; + if (! lsame_(uplo, "U", (ftnlen)1, (ftnlen)1) && ! lsame_(uplo, "L", ( + ftnlen)1, (ftnlen)1)) { + info = 1; + } else if (! lsame_(trans, "N", (ftnlen)1, (ftnlen)1) && ! lsame_(trans, + "T", (ftnlen)1, (ftnlen)1) && ! lsame_(trans, "C", (ftnlen)1, ( + ftnlen)1)) { + info = 2; + } else if (! lsame_(diag, "U", (ftnlen)1, (ftnlen)1) && ! lsame_(diag, + "N", (ftnlen)1, (ftnlen)1)) { + info = 3; + } else if (*n < 0) { + info = 4; + } else if (*k < 0) { + info = 5; + } else if (*lda < *k + 1) { + info = 7; + } else if (*incx == 0) { + info = 9; + } + if (info != 0) { + xerbla_("ZTBMV ", &info, (ftnlen)6); + return 0; + } + +/* Quick return if possible. */ + + if (*n == 0) { + return 0; + } + + noconj = lsame_(trans, "T", (ftnlen)1, (ftnlen)1); + nounit = lsame_(diag, "N", (ftnlen)1, (ftnlen)1); + +/* Set up the start point in X if the increment is not unity. This */ +/* will be ( N - 1 )*INCX too small for descending loops. */ + + if (*incx <= 0) { + kx = 1 - (*n - 1) * *incx; + } else if (*incx != 1) { + kx = 1; + } + +/* Start the operations. In this version the elements of A are */ +/* accessed sequentially with one pass through A. */ + + if (lsame_(trans, "N", (ftnlen)1, (ftnlen)1)) { + +/* Form x := A*x. */ + + if (lsame_(uplo, "U", (ftnlen)1, (ftnlen)1)) { + kplus1 = *k + 1; + if (*incx == 1) { + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__2 = j; + if (x[i__2].r != 0. || x[i__2].i != 0.) { + i__2 = j; + temp.r = x[i__2].r, temp.i = x[i__2].i; + l = kplus1 - j; +/* Computing MAX */ + i__2 = 1, i__3 = j - *k; + i__4 = j - 1; + for (i__ = max(i__2,i__3); i__ <= i__4; ++i__) { + i__2 = i__; + i__3 = i__; + i__5 = l + i__ + j * a_dim1; + z__2.r = temp.r * a[i__5].r - temp.i * a[i__5].i, + z__2.i = temp.r * a[i__5].i + temp.i * a[ + i__5].r; + z__1.r = x[i__3].r + z__2.r, z__1.i = x[i__3].i + + z__2.i; + x[i__2].r = z__1.r, x[i__2].i = z__1.i; +/* L10: */ + } + if (nounit) { + i__4 = j; + i__2 = j; + i__3 = kplus1 + j * a_dim1; + z__1.r = x[i__2].r * a[i__3].r - x[i__2].i * a[ + i__3].i, z__1.i = x[i__2].r * a[i__3].i + + x[i__2].i * a[i__3].r; + x[i__4].r = z__1.r, x[i__4].i = z__1.i; + } + } +/* L20: */ + } + } else { + jx = kx; + i__1 = *n; + for (j = 1; j <= i__1; ++j) { + i__4 = jx; + if (x[i__4].r != 0. || x[i__4].i != 0.) { + i__4 = jx; + temp.r = x[i__4].r, temp.i = x[i__4].i; + ix = kx; + l = kplus1 - j; +/* Computing MAX */ + i__4 = 1, i__2 = j - *k; + i__3 = j - 1; + for (i__ = max(i__4,i__2); i__ <= i__3; ++i__) { + i__4 = ix; + i__2 = ix; + i__5 = l + i__ + j * a_dim1; + z__2.r = temp.r * a[i__5].r - temp.i * a[i__5].i, + z__2.i = temp.r * a[i__5].i + temp.i * a[ + i__5].r; + z__1.r = x[i__2].r + z__2.r, z__1.i = x[i__2].i + + z__2.i; + x[i__4].r = z__1.r, x[i__4].i = z__1.i; + ix += *incx; +/* L30: */ + } + if (nounit) { + i__3 = jx; + i__4 = jx; + i__2 = kplus1 + j * a_dim1; + z__1.r = x[i__4].r * a[i__2].r - x[i__4].i * a[ + i__2].i, z__1.i = x[i__4].r * a[i__2].i + + x[i__4].i * a[i__2].r; + x[i__3].r = z__1.r, x[i__3].i = z__1.i; + } + } + jx += *incx; + if (j > *k) { + kx += *incx; + } +/* L40: */ + } + } + } else { + if (*incx == 1) { + for (j = *n; j >= 1; --j) { + i__1 = j; + if (x[i__1].r != 0. || x[i__1].i != 0.) { + i__1 = j; + temp.r = x[i__1].r, temp.i = x[i__1].i; + l = 1 - j; +/* Computing MIN */ + i__1 = *n, i__3 = j + *k; + i__4 = j + 1; + for (i__ = min(i__1,i__3); i__ >= i__4; --i__) { + i__1 = i__; + i__3 = i__; + i__2 = l + i__ + j * a_dim1; + z__2.r = temp.r * a[i__2].r - temp.i * a[i__2].i, + z__2.i = temp.r * a[i__2].i + temp.i * a[ + i__2].r; + z__1.r = x[i__3].r + z__2.r, z__1.i = x[i__3].i + + z__2.i; + x[i__1].r = z__1.r, x[i__1].i = z__1.i; +/* L50: */ + } + if (nounit) { + i__4 = j; + i__1 = j; + i__3 = j * a_dim1 + 1; + z__1.r = x[i__1].r * a[i__3].r - x[i__1].i * a[ + i__3].i, z__1.i = x[i__1].r * a[i__3].i + + x[i__1].i * a[i__3].r; + x[i__4].r = z__1.r, x[i__4].i = z__1.i; + } + } +/* L60: */ + } + } else { + kx += (*n - 1) * *incx; + jx = kx; + for (j = *n; j >= 1; --j) { + i__4 = jx; + if (x[i__4].r != 0. || x[i__4].i != 0.) { + i__4 = jx; + temp.r = x[i__4].r, temp.i = x[i__4].i; + ix = kx; + l = 1 - j; +/* Computing MIN */ + i__4 = *n, i__1 = j + *k; + i__3 = j + 1; + for (i__ = min(i__4,i__1); i__ >= i__3; --i__) { + i__4 = ix; + i__1 = ix; + i__2 = l + i__ + j * a_dim1; + z__2.r = temp.r * a[i__2].r - temp.i * a[i__2].i, + z__2.i = temp.r * a[i__2].i + temp.i * a[ + i__2].r; + z__1.r = x[i__1].r + z__2.r, z__1.i = x[i__1].i + + z__2.i; + x[i__4].r = z__1.r, x[i__4].i = z__1.i; + ix -= *incx; +/* L70: */ + } + if (nounit) { + i__3 = jx; + i__4 = jx; + i__1 = j * a_dim1 + 1; + z__1.r = x[i__4].r * a[i__1].r - x[i__4].i * a[ + i__1].i, z__1.i = x[i__4].r * a[i__1].i + + x[i__4].i * a[i__1].r; + x[i__3].r = z__1.r, x[i__3].i = z__1.i; + } + } + jx -= *incx; + if (*n - j >= *k) { + kx -= *incx; + } +/* L80: */ + } + } + } + } else { + +/* Form x := A'*x or x := conjg( A' )*x. */ + + if (lsame_(uplo, "U", (ftnlen)1, (ftnlen)1)) { + kplus1 = *k + 1; + if (*incx == 1) { + for (j = *n; j >= 1; --j) { + i__3 = j; + temp.r = x[i__3].r, temp.i = x[i__3].i; + l = kplus1 - j; + if (noconj) { + if (nounit) { + i__3 = kplus1 + j * a_dim1; + z__1.r = temp.r * a[i__3].r - temp.i * a[i__3].i, + z__1.i = temp.r * a[i__3].i + temp.i * a[ + i__3].r; + temp.r = z__1.r, temp.i = z__1.i; + } +/* Computing MAX */ + i__4 = 1, i__1 = j - *k; + i__3 = max(i__4,i__1); + for (i__ = j - 1; i__ >= i__3; --i__) { + i__4 = l + i__ + j * a_dim1; + i__1 = i__; + z__2.r = a[i__4].r * x[i__1].r - a[i__4].i * x[ + i__1].i, z__2.i = a[i__4].r * x[i__1].i + + a[i__4].i * x[i__1].r; + z__1.r = temp.r + z__2.r, z__1.i = temp.i + + z__2.i; + temp.r = z__1.r, temp.i = z__1.i; +/* L90: */ + } + } else { + if (nounit) { + d_cnjg(&z__2, &a[kplus1 + j * a_dim1]); + z__1.r = temp.r * z__2.r - temp.i * z__2.i, + z__1.i = temp.r * z__2.i + temp.i * + z__2.r; + temp.r = z__1.r, temp.i = z__1.i; + } +/* Computing MAX */ + i__4 = 1, i__1 = j - *k; + i__3 = max(i__4,i__1); + for (i__ = j - 1; i__ >= i__3; --i__) { + d_cnjg(&z__3, &a[l + i__ + j * a_dim1]); + i__4 = i__; + z__2.r = z__3.r * x[i__4].r - z__3.i * x[i__4].i, + z__2.i = z__3.r * x[i__4].i + z__3.i * x[ + i__4].r; + z__1.r = temp.r + z__2.r, z__1.i = temp.i + + z__2.i; + temp.r = z__1.r, temp.i = z__1.i; +/* L100: */ + } + } + i__3 = j; + x[i__3].r = temp.r, x[i__3].i = temp.i; +/* L110: */ + } + } else { + kx += (*n - 1) * *incx; + jx = kx; + for (j = *n; j >= 1; --j) { + i__3 = jx; + temp.r = x[i__3].r, temp.i = x[i__3].i; + kx -= *incx; + ix = kx; + l = kplus1 - j; + if (noconj) { + if (nounit) { + i__3 = kplus1 + j * a_dim1; + z__1.r = temp.r * a[i__3].r - temp.i * a[i__3].i, + z__1.i = temp.r * a[i__3].i + temp.i * a[ + i__3].r; + temp.r = z__1.r, temp.i = z__1.i; + } +/* Computing MAX */ + i__4 = 1, i__1 = j - *k; + i__3 = max(i__4,i__1); + for (i__ = j - 1; i__ >= i__3; --i__) { + i__4 = l + i__ + j * a_dim1; + i__1 = ix; + z__2.r = a[i__4].r * x[i__1].r - a[i__4].i * x[ + i__1].i, z__2.i = a[i__4].r * x[i__1].i + + a[i__4].i * x[i__1].r; + z__1.r = temp.r + z__2.r, z__1.i = temp.i + + z__2.i; + temp.r = z__1.r, temp.i = z__1.i; + ix -= *incx; +/* L120: */ + } + } else { + if (nounit) { + d_cnjg(&z__2, &a[kplus1 + j * a_dim1]); + z__1.r = temp.r * z__2.r - temp.i * z__2.i, + z__1.i = temp.r * z__2.i + temp.i * + z__2.r; + temp.r = z__1.r, temp.i = z__1.i; + } +/* Computing MAX */ + i__4 = 1, i__1 = j - *k; + i__3 = max(i__4,i__1); + for (i__ = j - 1; i__ >= i__3; --i__) { + d_cnjg(&z__3, &a[l + i__ + j * a_dim1]); + i__4 = ix; + z__2.r = z__3.r * x[i__4].r - z__3.i * x[i__4].i, + z__2.i = z__3.r * x[i__4].i + z__3.i * x[ + i__4].r; + z__1.r = temp.r + z__2.r, z__1.i = temp.i + + z__2.i; + temp.r = z__1.r, temp.i = z__1.i; + ix -= *incx; +/* L130: */ + } + } + i__3 = jx; + x[i__3].r = temp.r, x[i__3].i = temp.i; + jx -= *incx; +/* L140: */ + } + } + } else { + if (*incx == 1) { + i__3 = *n; + for (j = 1; j <= i__3; ++j) { + i__4 = j; + temp.r = x[i__4].r, temp.i = x[i__4].i; + l = 1 - j; + if (noconj) { + if (nounit) { + i__4 = j * a_dim1 + 1; + z__1.r = temp.r * a[i__4].r - temp.i * a[i__4].i, + z__1.i = temp.r * a[i__4].i + temp.i * a[ + i__4].r; + temp.r = z__1.r, temp.i = z__1.i; + } +/* Computing MIN */ + i__1 = *n, i__2 = j + *k; + i__4 = min(i__1,i__2); + for (i__ = j + 1; i__ <= i__4; ++i__) { + i__1 = l + i__ + j * a_dim1; + i__2 = i__; + z__2.r = a[i__1].r * x[i__2].r - a[i__1].i * x[ + i__2].i, z__2.i = a[i__1].r * x[i__2].i + + a[i__1].i * x[i__2].r; + z__1.r = temp.r + z__2.r, z__1.i = temp.i + + z__2.i; + temp.r = z__1.r, temp.i = z__1.i; +/* L150: */ + } + } else { + if (nounit) { + d_cnjg(&z__2, &a[j * a_dim1 + 1]); + z__1.r = temp.r * z__2.r - temp.i * z__2.i, + z__1.i = temp.r * z__2.i + temp.i * + z__2.r; + temp.r = z__1.r, temp.i = z__1.i; + } +/* Computing MIN */ + i__1 = *n, i__2 = j + *k; + i__4 = min(i__1,i__2); + for (i__ = j + 1; i__ <= i__4; ++i__) { + d_cnjg(&z__3, &a[l + i__ + j * a_dim1]); + i__1 = i__; + z__2.r = z__3.r * x[i__1].r - z__3.i * x[i__1].i, + z__2.i = z__3.r * x[i__1].i + z__3.i * x[ + i__1].r; + z__1.r = temp.r + z__2.r, z__1.i = temp.i + + z__2.i; + temp.r = z__1.r, temp.i = z__1.i; +/* L160: */ + } + } + i__4 = j; + x[i__4].r = temp.r, x[i__4].i = temp.i; +/* L170: */ + } + } else { + jx = kx; + i__3 = *n; + for (j = 1; j <= i__3; ++j) { + i__4 = jx; + temp.r = x[i__4].r, temp.i = x[i__4].i; + kx += *incx; + ix = kx; + l = 1 - j; + if (noconj) { + if (nounit) { + i__4 = j * a_dim1 + 1; + z__1.r = temp.r * a[i__4].r - temp.i * a[i__4].i, + z__1.i = temp.r * a[i__4].i + temp.i * a[ + i__4].r; + temp.r = z__1.r, temp.i = z__1.i; + } +/* Computing MIN */ + i__1 = *n, i__2 = j + *k; + i__4 = min(i__1,i__2); + for (i__ = j + 1; i__ <= i__4; ++i__) { + i__1 = l + i__ + j * a_dim1; + i__2 = ix; + z__2.r = a[i__1].r * x[i__2].r - a[i__1].i * x[ + i__2].i, z__2.i = a[i__1].r * x[i__2].i + + a[i__1].i * x[i__2].r; + z__1.r = temp.r + z__2.r, z__1.i = temp.i + + z__2.i; + temp.r = z__1.r, temp.i = z__1.i; + ix += *incx; +/* L180: */ + } + } else { + if (nounit) { + d_cnjg(&z__2, &a[j * a_dim1 + 1]); + z__1.r = temp.r * z__2.r - temp.i * z__2.i, + z__1.i = temp.r * z__2.i + temp.i * + z__2.r; + temp.r = z__1.r, temp.i = z__1.i; + } +/* Computing MIN */ + i__1 = *n, i__2 = j + *k; + i__4 = min(i__1,i__2); + for (i__ = j + 1; i__ <= i__4; ++i__) { + d_cnjg(&z__3, &a[l + i__ + j * a_dim1]); + i__1 = ix; + z__2.r = z__3.r * x[i__1].r - z__3.i * x[i__1].i, + z__2.i = z__3.r * x[i__1].i + z__3.i * x[ + i__1].r; + z__1.r = temp.r + z__2.r, z__1.i = temp.i + + z__2.i; + temp.r = z__1.r, temp.i = z__1.i; + ix += *incx; +/* L190: */ + } + } + i__4 = jx; + x[i__4].r = temp.r, x[i__4].i = temp.i; + jx += *incx; +/* L200: */ + } + } + } + } + + return 0; + +/* End of ZTBMV . */ + +} /* ztbmv_ */ + diff --git a/ground/gcs/src/libs/eigen/blas/complexdots.f b/ground/gcs/src/libs/eigen/blas/fortran/complexdots.f similarity index 100% rename from ground/gcs/src/libs/eigen/blas/complexdots.f rename to ground/gcs/src/libs/eigen/blas/fortran/complexdots.f diff --git a/ground/gcs/src/libs/eigen/blas/level1_cplx_impl.h b/ground/gcs/src/libs/eigen/blas/level1_cplx_impl.h index 283b9f827b..719f5bac91 100644 --- a/ground/gcs/src/libs/eigen/blas/level1_cplx_impl.h +++ b/ground/gcs/src/libs/eigen/blas/level1_cplx_impl.h @@ -32,45 +32,52 @@ RealScalar EIGEN_CAT(EIGEN_CAT(REAL_SCALAR_SUFFIX,SCALAR_SUFFIX),asum_)(int *n, if(*n<=0) return 0; - if(*incx==1) return vector(x,*n).unaryExpr().sum(); - else return vector(x,*n,std::abs(*incx)).unaryExpr().sum(); + if(*incx==1) return make_vector(x,*n).unaryExpr().sum(); + else return make_vector(x,*n,std::abs(*incx)).unaryExpr().sum(); } // computes a dot product of a conjugated vector with another vector. int EIGEN_BLAS_FUNC(dotcw)(int *n, RealScalar *px, int *incx, RealScalar *py, int *incy, RealScalar* pres) { // std::cerr << "_dotc " << *n << " " << *incx << " " << *incy << "\n"; + Scalar* res = reinterpret_cast(pres); - if(*n<=0) return 0; + if(*n<=0) + { + *res = Scalar(0); + return 0; + } Scalar* x = reinterpret_cast(px); Scalar* y = reinterpret_cast(py); - Scalar* res = reinterpret_cast(pres); - if(*incx==1 && *incy==1) *res = (vector(x,*n).dot(vector(y,*n))); - else if(*incx>0 && *incy>0) *res = (vector(x,*n,*incx).dot(vector(y,*n,*incy))); - else if(*incx<0 && *incy>0) *res = (vector(x,*n,-*incx).reverse().dot(vector(y,*n,*incy))); - else if(*incx>0 && *incy<0) *res = (vector(x,*n,*incx).dot(vector(y,*n,-*incy).reverse())); - else if(*incx<0 && *incy<0) *res = (vector(x,*n,-*incx).reverse().dot(vector(y,*n,-*incy).reverse())); + if(*incx==1 && *incy==1) *res = (make_vector(x,*n).dot(make_vector(y,*n))); + else if(*incx>0 && *incy>0) *res = (make_vector(x,*n,*incx).dot(make_vector(y,*n,*incy))); + else if(*incx<0 && *incy>0) *res = (make_vector(x,*n,-*incx).reverse().dot(make_vector(y,*n,*incy))); + else if(*incx>0 && *incy<0) *res = (make_vector(x,*n,*incx).dot(make_vector(y,*n,-*incy).reverse())); + else if(*incx<0 && *incy<0) *res = (make_vector(x,*n,-*incx).reverse().dot(make_vector(y,*n,-*incy).reverse())); return 0; } // computes a vector-vector dot product without complex conjugation. int EIGEN_BLAS_FUNC(dotuw)(int *n, RealScalar *px, int *incx, RealScalar *py, int *incy, RealScalar* pres) { -// std::cerr << "_dotu " << *n << " " << *incx << " " << *incy << "\n"; + Scalar* res = reinterpret_cast(pres); - if(*n<=0) return 0; + if(*n<=0) + { + *res = Scalar(0); + return 0; + } Scalar* x = reinterpret_cast(px); Scalar* y = reinterpret_cast(py); - Scalar* res = reinterpret_cast(pres); - if(*incx==1 && *incy==1) *res = (vector(x,*n).cwiseProduct(vector(y,*n))).sum(); - else if(*incx>0 && *incy>0) *res = (vector(x,*n,*incx).cwiseProduct(vector(y,*n,*incy))).sum(); - else if(*incx<0 && *incy>0) *res = (vector(x,*n,-*incx).reverse().cwiseProduct(vector(y,*n,*incy))).sum(); - else if(*incx>0 && *incy<0) *res = (vector(x,*n,*incx).cwiseProduct(vector(y,*n,-*incy).reverse())).sum(); - else if(*incx<0 && *incy<0) *res = (vector(x,*n,-*incx).reverse().cwiseProduct(vector(y,*n,-*incy).reverse())).sum(); + if(*incx==1 && *incy==1) *res = (make_vector(x,*n).cwiseProduct(make_vector(y,*n))).sum(); + else if(*incx>0 && *incy>0) *res = (make_vector(x,*n,*incx).cwiseProduct(make_vector(y,*n,*incy))).sum(); + else if(*incx<0 && *incy>0) *res = (make_vector(x,*n,-*incx).reverse().cwiseProduct(make_vector(y,*n,*incy))).sum(); + else if(*incx>0 && *incy<0) *res = (make_vector(x,*n,*incx).cwiseProduct(make_vector(y,*n,-*incy).reverse())).sum(); + else if(*incx<0 && *incy<0) *res = (make_vector(x,*n,-*incx).reverse().cwiseProduct(make_vector(y,*n,-*incy).reverse())).sum(); return 0; } @@ -82,9 +89,9 @@ RealScalar EIGEN_CAT(EIGEN_CAT(REAL_SCALAR_SUFFIX,SCALAR_SUFFIX),nrm2_)(int *n, Scalar* x = reinterpret_cast(px); if(*incx==1) - return vector(x,*n).stableNorm(); + return make_vector(x,*n).stableNorm(); - return vector(x,*n,*incx).stableNorm(); + return make_vector(x,*n,*incx).stableNorm(); } int EIGEN_CAT(EIGEN_CAT(SCALAR_SUFFIX,REAL_SCALAR_SUFFIX),rot_)(int *n, RealScalar *px, int *incx, RealScalar *py, int *incy, RealScalar *pc, RealScalar *ps) @@ -96,8 +103,8 @@ int EIGEN_CAT(EIGEN_CAT(SCALAR_SUFFIX,REAL_SCALAR_SUFFIX),rot_)(int *n, RealScal RealScalar c = *pc; RealScalar s = *ps; - StridedVectorType vx(vector(x,*n,std::abs(*incx))); - StridedVectorType vy(vector(y,*n,std::abs(*incy))); + StridedVectorType vx(make_vector(x,*n,std::abs(*incx))); + StridedVectorType vy(make_vector(y,*n,std::abs(*incy))); Reverse rvx(vx); Reverse rvy(vy); @@ -119,9 +126,8 @@ int EIGEN_CAT(EIGEN_CAT(SCALAR_SUFFIX,REAL_SCALAR_SUFFIX),scal_)(int *n, RealSca // std::cerr << "__scal " << *n << " " << alpha << " " << *incx << "\n"; - if(*incx==1) vector(x,*n) *= alpha; - else vector(x,*n,std::abs(*incx)) *= alpha; + if(*incx==1) make_vector(x,*n) *= alpha; + else make_vector(x,*n,std::abs(*incx)) *= alpha; return 0; } - diff --git a/ground/gcs/src/libs/eigen/blas/level1_impl.h b/ground/gcs/src/libs/eigen/blas/level1_impl.h index b08c2f6bed..f857bfa20c 100644 --- a/ground/gcs/src/libs/eigen/blas/level1_impl.h +++ b/ground/gcs/src/libs/eigen/blas/level1_impl.h @@ -9,19 +9,19 @@ #include "common.h" -int EIGEN_BLAS_FUNC(axpy)(int *n, RealScalar *palpha, RealScalar *px, int *incx, RealScalar *py, int *incy) +int EIGEN_BLAS_FUNC(axpy)(const int *n, const RealScalar *palpha, const RealScalar *px, const int *incx, RealScalar *py, const int *incy) { - Scalar* x = reinterpret_cast(px); + const Scalar* x = reinterpret_cast(px); Scalar* y = reinterpret_cast(py); - Scalar alpha = *reinterpret_cast(palpha); + Scalar alpha = *reinterpret_cast(palpha); if(*n<=0) return 0; - if(*incx==1 && *incy==1) vector(y,*n) += alpha * vector(x,*n); - else if(*incx>0 && *incy>0) vector(y,*n,*incy) += alpha * vector(x,*n,*incx); - else if(*incx>0 && *incy<0) vector(y,*n,-*incy).reverse() += alpha * vector(x,*n,*incx); - else if(*incx<0 && *incy>0) vector(y,*n,*incy) += alpha * vector(x,*n,-*incx).reverse(); - else if(*incx<0 && *incy<0) vector(y,*n,-*incy).reverse() += alpha * vector(x,*n,-*incx).reverse(); + if(*incx==1 && *incy==1) make_vector(y,*n) += alpha * make_vector(x,*n); + else if(*incx>0 && *incy>0) make_vector(y,*n,*incy) += alpha * make_vector(x,*n,*incx); + else if(*incx>0 && *incy<0) make_vector(y,*n,-*incy).reverse() += alpha * make_vector(x,*n,*incx); + else if(*incx<0 && *incy>0) make_vector(y,*n,*incy) += alpha * make_vector(x,*n,-*incx).reverse(); + else if(*incx<0 && *incy<0) make_vector(y,*n,-*incy).reverse() += alpha * make_vector(x,*n,-*incx).reverse(); return 0; } @@ -35,7 +35,7 @@ int EIGEN_BLAS_FUNC(copy)(int *n, RealScalar *px, int *incx, RealScalar *py, int // be carefull, *incx==0 is allowed !! if(*incx==1 && *incy==1) - vector(y,*n) = vector(x,*n); + make_vector(y,*n) = make_vector(x,*n); else { if(*incx<0) x = x - (*n-1)*(*incx); @@ -57,27 +57,27 @@ int EIGEN_CAT(EIGEN_CAT(i,SCALAR_SUFFIX),amax_)(int *n, RealScalar *px, int *inc Scalar* x = reinterpret_cast(px); DenseIndex ret; - if(*incx==1) vector(x,*n).cwiseAbs().maxCoeff(&ret); - else vector(x,*n,std::abs(*incx)).cwiseAbs().maxCoeff(&ret); - return ret+1; + if(*incx==1) make_vector(x,*n).cwiseAbs().maxCoeff(&ret); + else make_vector(x,*n,std::abs(*incx)).cwiseAbs().maxCoeff(&ret); + return int(ret)+1; } int EIGEN_CAT(EIGEN_CAT(i,SCALAR_SUFFIX),amin_)(int *n, RealScalar *px, int *incx) { if(*n<=0) return 0; Scalar* x = reinterpret_cast(px); - + DenseIndex ret; - if(*incx==1) vector(x,*n).cwiseAbs().minCoeff(&ret); - else vector(x,*n,std::abs(*incx)).cwiseAbs().minCoeff(&ret); - return ret+1; + if(*incx==1) make_vector(x,*n).cwiseAbs().minCoeff(&ret); + else make_vector(x,*n,std::abs(*incx)).cwiseAbs().minCoeff(&ret); + return int(ret)+1; } int EIGEN_BLAS_FUNC(rotg)(RealScalar *pa, RealScalar *pb, RealScalar *pc, RealScalar *ps) { using std::sqrt; using std::abs; - + Scalar& a = *reinterpret_cast(pa); Scalar& b = *reinterpret_cast(pb); RealScalar* c = pc; @@ -143,8 +143,8 @@ int EIGEN_BLAS_FUNC(scal)(int *n, RealScalar *palpha, RealScalar *px, int *incx) Scalar* x = reinterpret_cast(px); Scalar alpha = *reinterpret_cast(palpha); - if(*incx==1) vector(x,*n) *= alpha; - else vector(x,*n,std::abs(*incx)) *= alpha; + if(*incx==1) make_vector(x,*n) *= alpha; + else make_vector(x,*n,std::abs(*incx)) *= alpha; return 0; } @@ -156,12 +156,11 @@ int EIGEN_BLAS_FUNC(swap)(int *n, RealScalar *px, int *incx, RealScalar *py, int Scalar* x = reinterpret_cast(px); Scalar* y = reinterpret_cast(py); - if(*incx==1 && *incy==1) vector(y,*n).swap(vector(x,*n)); - else if(*incx>0 && *incy>0) vector(y,*n,*incy).swap(vector(x,*n,*incx)); - else if(*incx>0 && *incy<0) vector(y,*n,-*incy).reverse().swap(vector(x,*n,*incx)); - else if(*incx<0 && *incy>0) vector(y,*n,*incy).swap(vector(x,*n,-*incx).reverse()); - else if(*incx<0 && *incy<0) vector(y,*n,-*incy).reverse().swap(vector(x,*n,-*incx).reverse()); + if(*incx==1 && *incy==1) make_vector(y,*n).swap(make_vector(x,*n)); + else if(*incx>0 && *incy>0) make_vector(y,*n,*incy).swap(make_vector(x,*n,*incx)); + else if(*incx>0 && *incy<0) make_vector(y,*n,-*incy).reverse().swap(make_vector(x,*n,*incx)); + else if(*incx<0 && *incy>0) make_vector(y,*n,*incy).swap(make_vector(x,*n,-*incx).reverse()); + else if(*incx<0 && *incy<0) make_vector(y,*n,-*incy).reverse().swap(make_vector(x,*n,-*incx).reverse()); return 1; } - diff --git a/ground/gcs/src/libs/eigen/blas/level1_real_impl.h b/ground/gcs/src/libs/eigen/blas/level1_real_impl.h index 8acecdfc6d..02586d5195 100644 --- a/ground/gcs/src/libs/eigen/blas/level1_real_impl.h +++ b/ground/gcs/src/libs/eigen/blas/level1_real_impl.h @@ -19,8 +19,8 @@ RealScalar EIGEN_BLAS_FUNC(asum)(int *n, RealScalar *px, int *incx) if(*n<=0) return 0; - if(*incx==1) return vector(x,*n).cwiseAbs().sum(); - else return vector(x,*n,std::abs(*incx)).cwiseAbs().sum(); + if(*incx==1) return make_vector(x,*n).cwiseAbs().sum(); + else return make_vector(x,*n,std::abs(*incx)).cwiseAbs().sum(); } // computes a vector-vector dot product. @@ -33,11 +33,11 @@ Scalar EIGEN_BLAS_FUNC(dot)(int *n, RealScalar *px, int *incx, RealScalar *py, i Scalar* x = reinterpret_cast(px); Scalar* y = reinterpret_cast(py); - if(*incx==1 && *incy==1) return (vector(x,*n).cwiseProduct(vector(y,*n))).sum(); - else if(*incx>0 && *incy>0) return (vector(x,*n,*incx).cwiseProduct(vector(y,*n,*incy))).sum(); - else if(*incx<0 && *incy>0) return (vector(x,*n,-*incx).reverse().cwiseProduct(vector(y,*n,*incy))).sum(); - else if(*incx>0 && *incy<0) return (vector(x,*n,*incx).cwiseProduct(vector(y,*n,-*incy).reverse())).sum(); - else if(*incx<0 && *incy<0) return (vector(x,*n,-*incx).reverse().cwiseProduct(vector(y,*n,-*incy).reverse())).sum(); + if(*incx==1 && *incy==1) return (make_vector(x,*n).cwiseProduct(make_vector(y,*n))).sum(); + else if(*incx>0 && *incy>0) return (make_vector(x,*n,*incx).cwiseProduct(make_vector(y,*n,*incy))).sum(); + else if(*incx<0 && *incy>0) return (make_vector(x,*n,-*incx).reverse().cwiseProduct(make_vector(y,*n,*incy))).sum(); + else if(*incx>0 && *incy<0) return (make_vector(x,*n,*incx).cwiseProduct(make_vector(y,*n,-*incy).reverse())).sum(); + else if(*incx<0 && *incy<0) return (make_vector(x,*n,-*incx).reverse().cwiseProduct(make_vector(y,*n,-*incy).reverse())).sum(); else return 0; } @@ -50,8 +50,8 @@ Scalar EIGEN_BLAS_FUNC(nrm2)(int *n, RealScalar *px, int *incx) Scalar* x = reinterpret_cast(px); - if(*incx==1) return vector(x,*n).stableNorm(); - else return vector(x,*n,std::abs(*incx)).stableNorm(); + if(*incx==1) return make_vector(x,*n).stableNorm(); + else return make_vector(x,*n,std::abs(*incx)).stableNorm(); } int EIGEN_BLAS_FUNC(rot)(int *n, RealScalar *px, int *incx, RealScalar *py, int *incy, RealScalar *pc, RealScalar *ps) @@ -64,8 +64,8 @@ int EIGEN_BLAS_FUNC(rot)(int *n, RealScalar *px, int *incx, RealScalar *py, int Scalar c = *reinterpret_cast(pc); Scalar s = *reinterpret_cast(ps); - StridedVectorType vx(vector(x,*n,std::abs(*incx))); - StridedVectorType vy(vector(y,*n,std::abs(*incy))); + StridedVectorType vx(make_vector(x,*n,std::abs(*incx))); + StridedVectorType vy(make_vector(y,*n,std::abs(*incy))); Reverse rvx(vx); Reverse rvy(vy); diff --git a/ground/gcs/src/libs/eigen/blas/level2_cplx_impl.h b/ground/gcs/src/libs/eigen/blas/level2_cplx_impl.h index b850b6cd1b..e3ce61435e 100644 --- a/ground/gcs/src/libs/eigen/blas/level2_cplx_impl.h +++ b/ground/gcs/src/libs/eigen/blas/level2_cplx_impl.h @@ -16,28 +16,22 @@ * where alpha and beta are scalars, x and y are n element vectors and * A is an n by n hermitian matrix. */ -int EIGEN_BLAS_FUNC(hemv)(char *uplo, int *n, RealScalar *palpha, RealScalar *pa, int *lda, RealScalar *px, int *incx, RealScalar *pbeta, RealScalar *py, int *incy) +int EIGEN_BLAS_FUNC(hemv)(const char *uplo, const int *n, const RealScalar *palpha, const RealScalar *pa, const int *lda, + const RealScalar *px, const int *incx, const RealScalar *pbeta, RealScalar *py, const int *incy) { - typedef void (*functype)(int, const Scalar*, int, const Scalar*, int, Scalar*, Scalar); - static functype func[2]; - - static bool init = false; - if(!init) - { - for(int k=0; k<2; ++k) - func[k] = 0; - - func[UP] = (internal::selfadjoint_matrix_vector_product::run); - func[LO] = (internal::selfadjoint_matrix_vector_product::run); - - init = true; - } - - Scalar* a = reinterpret_cast(pa); - Scalar* x = reinterpret_cast(px); + typedef void (*functype)(int, const Scalar*, int, const Scalar*, Scalar*, Scalar); + static const functype func[2] = { + // array index: UP + (internal::selfadjoint_matrix_vector_product::run), + // array index: LO + (internal::selfadjoint_matrix_vector_product::run), + }; + + const Scalar* a = reinterpret_cast(pa); + const Scalar* x = reinterpret_cast(px); Scalar* y = reinterpret_cast(py); - Scalar alpha = *reinterpret_cast(palpha); - Scalar beta = *reinterpret_cast(pbeta); + Scalar alpha = *reinterpret_cast(palpha); + Scalar beta = *reinterpret_cast(pbeta); // check arguments int info = 0; @@ -52,13 +46,13 @@ int EIGEN_BLAS_FUNC(hemv)(char *uplo, int *n, RealScalar *palpha, RealScalar *pa if(*n==0) return 1; - Scalar* actual_x = get_compact_vector(x,*n,*incx); + const Scalar* actual_x = get_compact_vector(x,*n,*incx); Scalar* actual_y = get_compact_vector(y,*n,*incy); if(beta!=Scalar(1)) { - if(beta==Scalar(0)) vector(actual_y, *n).setZero(); - else vector(actual_y, *n) *= beta; + if(beta==Scalar(0)) make_vector(actual_y, *n).setZero(); + else make_vector(actual_y, *n) *= beta; } if(alpha!=Scalar(0)) @@ -67,7 +61,7 @@ int EIGEN_BLAS_FUNC(hemv)(char *uplo, int *n, RealScalar *palpha, RealScalar *pa if(code>=2 || func[code]==0) return 0; - func[code](*n, a, *lda, actual_x, 1, actual_y, alpha); + func[code](*n, a, *lda, actual_x, actual_y, alpha); } if(actual_x!=x) delete[] actual_x; @@ -111,19 +105,12 @@ int EIGEN_BLAS_FUNC(hemv)(char *uplo, int *n, RealScalar *palpha, RealScalar *pa int EIGEN_BLAS_FUNC(hpr)(char *uplo, int *n, RealScalar *palpha, RealScalar *px, int *incx, RealScalar *pap) { typedef void (*functype)(int, Scalar*, const Scalar*, RealScalar); - static functype func[2]; - - static bool init = false; - if(!init) - { - for(int k=0; k<2; ++k) - func[k] = 0; - - func[UP] = (internal::selfadjoint_packed_rank1_update::run); - func[LO] = (internal::selfadjoint_packed_rank1_update::run); - - init = true; - } + static const functype func[2] = { + // array index: UP + (internal::selfadjoint_packed_rank1_update::run), + // array index: LO + (internal::selfadjoint_packed_rank1_update::run), + }; Scalar* x = reinterpret_cast(px); Scalar* ap = reinterpret_cast(pap); @@ -162,19 +149,12 @@ int EIGEN_BLAS_FUNC(hpr)(char *uplo, int *n, RealScalar *palpha, RealScalar *px, int EIGEN_BLAS_FUNC(hpr2)(char *uplo, int *n, RealScalar *palpha, RealScalar *px, int *incx, RealScalar *py, int *incy, RealScalar *pap) { typedef void (*functype)(int, Scalar*, const Scalar*, const Scalar*, Scalar); - static functype func[2]; - - static bool init = false; - if(!init) - { - for(int k=0; k<2; ++k) - func[k] = 0; - - func[UP] = (internal::packed_rank2_update_selector::run); - func[LO] = (internal::packed_rank2_update_selector::run); - - init = true; - } + static const functype func[2] = { + // array index: UP + (internal::packed_rank2_update_selector::run), + // array index: LO + (internal::packed_rank2_update_selector::run), + }; Scalar* x = reinterpret_cast(px); Scalar* y = reinterpret_cast(py); @@ -217,19 +197,12 @@ int EIGEN_BLAS_FUNC(hpr2)(char *uplo, int *n, RealScalar *palpha, RealScalar *px int EIGEN_BLAS_FUNC(her)(char *uplo, int *n, RealScalar *palpha, RealScalar *px, int *incx, RealScalar *pa, int *lda) { typedef void (*functype)(int, Scalar*, int, const Scalar*, const Scalar*, const Scalar&); - static functype func[2]; - - static bool init = false; - if(!init) - { - for(int k=0; k<2; ++k) - func[k] = 0; - - func[UP] = (selfadjoint_rank1_update::run); - func[LO] = (selfadjoint_rank1_update::run); - - init = true; - } + static const functype func[2] = { + // array index: UP + (selfadjoint_rank1_update::run), + // array index: LO + (selfadjoint_rank1_update::run), + }; Scalar* x = reinterpret_cast(px); Scalar* a = reinterpret_cast(pa); @@ -271,19 +244,12 @@ int EIGEN_BLAS_FUNC(her)(char *uplo, int *n, RealScalar *palpha, RealScalar *px, int EIGEN_BLAS_FUNC(her2)(char *uplo, int *n, RealScalar *palpha, RealScalar *px, int *incx, RealScalar *py, int *incy, RealScalar *pa, int *lda) { typedef void (*functype)(int, Scalar*, int, const Scalar*, const Scalar*, Scalar); - static functype func[2]; - - static bool init = false; - if(!init) - { - for(int k=0; k<2; ++k) - func[k] = 0; - - func[UP] = (internal::rank2_update_selector::run); - func[LO] = (internal::rank2_update_selector::run); - - init = true; - } + static const functype func[2] = { + // array index: UP + (internal::rank2_update_selector::run), + // array index: LO + (internal::rank2_update_selector::run), + }; Scalar* x = reinterpret_cast(px); Scalar* y = reinterpret_cast(py); diff --git a/ground/gcs/src/libs/eigen/blas/level2_impl.h b/ground/gcs/src/libs/eigen/blas/level2_impl.h index 5f39419759..173f40b441 100644 --- a/ground/gcs/src/libs/eigen/blas/level2_impl.h +++ b/ground/gcs/src/libs/eigen/blas/level2_impl.h @@ -9,29 +9,39 @@ #include "common.h" -int EIGEN_BLAS_FUNC(gemv)(char *opa, int *m, int *n, RealScalar *palpha, RealScalar *pa, int *lda, RealScalar *pb, int *incb, RealScalar *pbeta, RealScalar *pc, int *incc) +template +struct general_matrix_vector_product_wrapper { - typedef void (*functype)(int, int, const Scalar *, int, const Scalar *, int , Scalar *, int, Scalar); - static functype func[4]; - - static bool init = false; - if(!init) + static void run(Index rows, Index cols,const Scalar *lhs, Index lhsStride, const Scalar *rhs, Index rhsIncr, Scalar* res, Index resIncr, Scalar alpha) { - for(int k=0; k<4; ++k) - func[k] = 0; - - func[NOTR] = (internal::general_matrix_vector_product::run); - func[TR ] = (internal::general_matrix_vector_product::run); - func[ADJ ] = (internal::general_matrix_vector_product::run); - - init = true; + typedef internal::const_blas_data_mapper LhsMapper; + typedef internal::const_blas_data_mapper RhsMapper; + + internal::general_matrix_vector_product + ::run( + rows, cols, LhsMapper(lhs, lhsStride), RhsMapper(rhs, rhsIncr), res, resIncr, alpha); } +}; - Scalar* a = reinterpret_cast(pa); - Scalar* b = reinterpret_cast(pb); +int EIGEN_BLAS_FUNC(gemv)(const char *opa, const int *m, const int *n, const RealScalar *palpha, + const RealScalar *pa, const int *lda, const RealScalar *pb, const int *incb, const RealScalar *pbeta, RealScalar *pc, const int *incc) +{ + typedef void (*functype)(int, int, const Scalar *, int, const Scalar *, int , Scalar *, int, Scalar); + static const functype func[4] = { + // array index: NOTR + (general_matrix_vector_product_wrapper::run), + // array index: TR + (general_matrix_vector_product_wrapper::run), + // array index: ADJ + (general_matrix_vector_product_wrapper::run), + 0 + }; + + const Scalar* a = reinterpret_cast(pa); + const Scalar* b = reinterpret_cast(pb); Scalar* c = reinterpret_cast(pc); - Scalar alpha = *reinterpret_cast(palpha); - Scalar beta = *reinterpret_cast(pbeta); + Scalar alpha = *reinterpret_cast(palpha); + Scalar beta = *reinterpret_cast(pbeta); // check arguments int info = 0; @@ -53,13 +63,13 @@ int EIGEN_BLAS_FUNC(gemv)(char *opa, int *m, int *n, RealScalar *palpha, RealSca if(code!=NOTR) std::swap(actual_m,actual_n); - Scalar* actual_b = get_compact_vector(b,actual_n,*incb); + const Scalar* actual_b = get_compact_vector(b,actual_n,*incb); Scalar* actual_c = get_compact_vector(c,actual_m,*incc); if(beta!=Scalar(1)) { - if(beta==Scalar(0)) vector(actual_c, actual_m).setZero(); - else vector(actual_c, actual_m) *= beta; + if(beta==Scalar(0)) make_vector(actual_c, actual_m).setZero(); + else make_vector(actual_c, actual_m) *= beta; } if(code>=4 || func[code]==0) @@ -73,37 +83,41 @@ int EIGEN_BLAS_FUNC(gemv)(char *opa, int *m, int *n, RealScalar *palpha, RealSca return 1; } -int EIGEN_BLAS_FUNC(trsv)(char *uplo, char *opa, char *diag, int *n, RealScalar *pa, int *lda, RealScalar *pb, int *incb) +int EIGEN_BLAS_FUNC(trsv)(const char *uplo, const char *opa, const char *diag, const int *n, const RealScalar *pa, const int *lda, RealScalar *pb, const int *incb) { typedef void (*functype)(int, const Scalar *, int, Scalar *); - static functype func[16]; - - static bool init = false; - if(!init) - { - for(int k=0; k<16; ++k) - func[k] = 0; - - func[NOTR | (UP << 2) | (NUNIT << 3)] = (internal::triangular_solve_vector::run); - func[TR | (UP << 2) | (NUNIT << 3)] = (internal::triangular_solve_vector::run); - func[ADJ | (UP << 2) | (NUNIT << 3)] = (internal::triangular_solve_vector::run); - - func[NOTR | (LO << 2) | (NUNIT << 3)] = (internal::triangular_solve_vector::run); - func[TR | (LO << 2) | (NUNIT << 3)] = (internal::triangular_solve_vector::run); - func[ADJ | (LO << 2) | (NUNIT << 3)] = (internal::triangular_solve_vector::run); - - func[NOTR | (UP << 2) | (UNIT << 3)] = (internal::triangular_solve_vector::run); - func[TR | (UP << 2) | (UNIT << 3)] = (internal::triangular_solve_vector::run); - func[ADJ | (UP << 2) | (UNIT << 3)] = (internal::triangular_solve_vector::run); - - func[NOTR | (LO << 2) | (UNIT << 3)] = (internal::triangular_solve_vector::run); - func[TR | (LO << 2) | (UNIT << 3)] = (internal::triangular_solve_vector::run); - func[ADJ | (LO << 2) | (UNIT << 3)] = (internal::triangular_solve_vector::run); - - init = true; - } - - Scalar* a = reinterpret_cast(pa); + static const functype func[16] = { + // array index: NOTR | (UP << 2) | (NUNIT << 3) + (internal::triangular_solve_vector::run), + // array index: TR | (UP << 2) | (NUNIT << 3) + (internal::triangular_solve_vector::run), + // array index: ADJ | (UP << 2) | (NUNIT << 3) + (internal::triangular_solve_vector::run), + 0, + // array index: NOTR | (LO << 2) | (NUNIT << 3) + (internal::triangular_solve_vector::run), + // array index: TR | (LO << 2) | (NUNIT << 3) + (internal::triangular_solve_vector::run), + // array index: ADJ | (LO << 2) | (NUNIT << 3) + (internal::triangular_solve_vector::run), + 0, + // array index: NOTR | (UP << 2) | (UNIT << 3) + (internal::triangular_solve_vector::run), + // array index: TR | (UP << 2) | (UNIT << 3) + (internal::triangular_solve_vector::run), + // array index: ADJ | (UP << 2) | (UNIT << 3) + (internal::triangular_solve_vector::run), + 0, + // array index: NOTR | (LO << 2) | (UNIT << 3) + (internal::triangular_solve_vector::run), + // array index: TR | (LO << 2) | (UNIT << 3) + (internal::triangular_solve_vector::run), + // array index: ADJ | (LO << 2) | (UNIT << 3) + (internal::triangular_solve_vector::run), + 0 + }; + + const Scalar* a = reinterpret_cast(pa); Scalar* b = reinterpret_cast(pb); int info = 0; @@ -128,37 +142,41 @@ int EIGEN_BLAS_FUNC(trsv)(char *uplo, char *opa, char *diag, int *n, RealScalar -int EIGEN_BLAS_FUNC(trmv)(char *uplo, char *opa, char *diag, int *n, RealScalar *pa, int *lda, RealScalar *pb, int *incb) +int EIGEN_BLAS_FUNC(trmv)(const char *uplo, const char *opa, const char *diag, const int *n, const RealScalar *pa, const int *lda, RealScalar *pb, const int *incb) { typedef void (*functype)(int, int, const Scalar *, int, const Scalar *, int, Scalar *, int, const Scalar&); - static functype func[16]; - - static bool init = false; - if(!init) - { - for(int k=0; k<16; ++k) - func[k] = 0; - - func[NOTR | (UP << 2) | (NUNIT << 3)] = (internal::triangular_matrix_vector_product::run); - func[TR | (UP << 2) | (NUNIT << 3)] = (internal::triangular_matrix_vector_product::run); - func[ADJ | (UP << 2) | (NUNIT << 3)] = (internal::triangular_matrix_vector_product::run); - - func[NOTR | (LO << 2) | (NUNIT << 3)] = (internal::triangular_matrix_vector_product::run); - func[TR | (LO << 2) | (NUNIT << 3)] = (internal::triangular_matrix_vector_product::run); - func[ADJ | (LO << 2) | (NUNIT << 3)] = (internal::triangular_matrix_vector_product::run); - - func[NOTR | (UP << 2) | (UNIT << 3)] = (internal::triangular_matrix_vector_product::run); - func[TR | (UP << 2) | (UNIT << 3)] = (internal::triangular_matrix_vector_product::run); - func[ADJ | (UP << 2) | (UNIT << 3)] = (internal::triangular_matrix_vector_product::run); - - func[NOTR | (LO << 2) | (UNIT << 3)] = (internal::triangular_matrix_vector_product::run); - func[TR | (LO << 2) | (UNIT << 3)] = (internal::triangular_matrix_vector_product::run); - func[ADJ | (LO << 2) | (UNIT << 3)] = (internal::triangular_matrix_vector_product::run); - - init = true; - } - - Scalar* a = reinterpret_cast(pa); + static const functype func[16] = { + // array index: NOTR | (UP << 2) | (NUNIT << 3) + (internal::triangular_matrix_vector_product::run), + // array index: TR | (UP << 2) | (NUNIT << 3) + (internal::triangular_matrix_vector_product::run), + // array index: ADJ | (UP << 2) | (NUNIT << 3) + (internal::triangular_matrix_vector_product::run), + 0, + // array index: NOTR | (LO << 2) | (NUNIT << 3) + (internal::triangular_matrix_vector_product::run), + // array index: TR | (LO << 2) | (NUNIT << 3) + (internal::triangular_matrix_vector_product::run), + // array index: ADJ | (LO << 2) | (NUNIT << 3) + (internal::triangular_matrix_vector_product::run), + 0, + // array index: NOTR | (UP << 2) | (UNIT << 3) + (internal::triangular_matrix_vector_product::run), + // array index: TR | (UP << 2) | (UNIT << 3) + (internal::triangular_matrix_vector_product::run), + // array index: ADJ | (UP << 2) | (UNIT << 3) + (internal::triangular_matrix_vector_product::run), + 0, + // array index: NOTR | (LO << 2) | (UNIT << 3) + (internal::triangular_matrix_vector_product::run), + // array index: TR | (LO << 2) | (UNIT << 3) + (internal::triangular_matrix_vector_product::run), + // array index: ADJ | (LO << 2) | (UNIT << 3) + (internal::triangular_matrix_vector_product::run), + 0 + }; + + const Scalar* a = reinterpret_cast(pa); Scalar* b = reinterpret_cast(pb); int info = 0; @@ -200,13 +218,13 @@ int EIGEN_BLAS_FUNC(trmv)(char *uplo, char *opa, char *diag, int *n, RealScalar int EIGEN_BLAS_FUNC(gbmv)(char *trans, int *m, int *n, int *kl, int *ku, RealScalar *palpha, RealScalar *pa, int *lda, RealScalar *px, int *incx, RealScalar *pbeta, RealScalar *py, int *incy) { - Scalar* a = reinterpret_cast(pa); - Scalar* x = reinterpret_cast(px); + const Scalar* a = reinterpret_cast(pa); + const Scalar* x = reinterpret_cast(px); Scalar* y = reinterpret_cast(py); - Scalar alpha = *reinterpret_cast(palpha); - Scalar beta = *reinterpret_cast(pbeta); + Scalar alpha = *reinterpret_cast(palpha); + Scalar beta = *reinterpret_cast(pbeta); int coeff_rows = *kl+*ku+1; - + int info = 0; if(OP(*trans)==INVALID) info = 1; else if(*m<0) info = 2; @@ -218,26 +236,26 @@ int EIGEN_BLAS_FUNC(gbmv)(char *trans, int *m, int *n, int *kl, int *ku, RealSca else if(*incy==0) info = 13; if(info) return xerbla_(SCALAR_SUFFIX_UP"GBMV ",&info,6); - + if(*m==0 || *n==0 || (alpha==Scalar(0) && beta==Scalar(1))) return 0; - + int actual_m = *m; int actual_n = *n; if(OP(*trans)!=NOTR) std::swap(actual_m,actual_n); - - Scalar* actual_x = get_compact_vector(x,actual_n,*incx); + + const Scalar* actual_x = get_compact_vector(x,actual_n,*incx); Scalar* actual_y = get_compact_vector(y,actual_m,*incy); - + if(beta!=Scalar(1)) { - if(beta==Scalar(0)) vector(actual_y, actual_m).setZero(); - else vector(actual_y, actual_m) *= beta; + if(beta==Scalar(0)) make_vector(actual_y, actual_m).setZero(); + else make_vector(actual_y, actual_m) *= beta; } - - MatrixType mat_coeffs(a,coeff_rows,*n,*lda); - + + ConstMatrixType mat_coeffs(a,coeff_rows,*n,*lda); + int nb = std::min(*n,(*m)+(*ku)); for(int j=0; j(pa); Scalar* x = reinterpret_cast(px); int coeff_rows = *k + 1; - + int info = 0; if(UPLO(*uplo)==INVALID) info = 1; else if(OP(*opa)==INVALID) info = 2; @@ -283,37 +301,37 @@ int EIGEN_BLAS_FUNC(tbmv)(char *uplo, char *opa, char *diag, int *n, int *k, Rea else if(*incx==0) info = 9; if(info) return xerbla_(SCALAR_SUFFIX_UP"TBMV ",&info,6); - + if(*n==0) return 0; - + int actual_n = *n; - + Scalar* actual_x = get_compact_vector(x,actual_n,*incx); - + MatrixType mat_coeffs(a,coeff_rows,*n,*lda); - + int ku = UPLO(*uplo)==UPPER ? *k : 0; int kl = UPLO(*uplo)==LOWER ? *k : 0; - + for(int j=0; j<*n; ++j) { int start = std::max(0,j - ku); int end = std::min((*m)-1,j + kl); int len = end - start + 1; int offset = (ku) - j + start; - + if(OP(*trans)==NOTR) - vector(actual_y+start,len) += (alpha*actual_x[j]) * mat_coeffs.col(j).segment(offset,len); + make_vector(actual_y+start,len) += (alpha*actual_x[j]) * mat_coeffs.col(j).segment(offset,len); else if(OP(*trans)==TR) - actual_y[j] += alpha * ( mat_coeffs.col(j).segment(offset,len).transpose() * vector(actual_x+start,len) ).value(); + actual_y[j] += alpha * ( mat_coeffs.col(j).segment(offset,len).transpose() * make_vector(actual_x+start,len) ).value(); else - actual_y[j] += alpha * ( mat_coeffs.col(j).segment(offset,len).adjoint() * vector(actual_x+start,len) ).value(); - } - + actual_y[j] += alpha * ( mat_coeffs.col(j).segment(offset,len).adjoint() * make_vector(actual_x+start,len) ).value(); + } + if(actual_x!=x) delete[] actual_x; if(actual_y!=y) delete[] copy_back(actual_y,y,actual_m,*incy); - + return 0; } #endif @@ -332,37 +350,41 @@ int EIGEN_BLAS_FUNC(tbmv)(char *uplo, char *opa, char *diag, int *n, int *k, Rea int EIGEN_BLAS_FUNC(tbsv)(char *uplo, char *op, char *diag, int *n, int *k, RealScalar *pa, int *lda, RealScalar *px, int *incx) { typedef void (*functype)(int, int, const Scalar *, int, Scalar *); - static functype func[16]; - - static bool init = false; - if(!init) - { - for(int k=0; k<16; ++k) - func[k] = 0; - - func[NOTR | (UP << 2) | (NUNIT << 3)] = (internal::band_solve_triangular_selector::run); - func[TR | (UP << 2) | (NUNIT << 3)] = (internal::band_solve_triangular_selector::run); - func[ADJ | (UP << 2) | (NUNIT << 3)] = (internal::band_solve_triangular_selector::run); - - func[NOTR | (LO << 2) | (NUNIT << 3)] = (internal::band_solve_triangular_selector::run); - func[TR | (LO << 2) | (NUNIT << 3)] = (internal::band_solve_triangular_selector::run); - func[ADJ | (LO << 2) | (NUNIT << 3)] = (internal::band_solve_triangular_selector::run); - - func[NOTR | (UP << 2) | (UNIT << 3)] = (internal::band_solve_triangular_selector::run); - func[TR | (UP << 2) | (UNIT << 3)] = (internal::band_solve_triangular_selector::run); - func[ADJ | (UP << 2) | (UNIT << 3)] = (internal::band_solve_triangular_selector::run); - - func[NOTR | (LO << 2) | (UNIT << 3)] = (internal::band_solve_triangular_selector::run); - func[TR | (LO << 2) | (UNIT << 3)] = (internal::band_solve_triangular_selector::run); - func[ADJ | (LO << 2) | (UNIT << 3)] = (internal::band_solve_triangular_selector::run); - - init = true; - } + static const functype func[16] = { + // array index: NOTR | (UP << 2) | (NUNIT << 3) + (internal::band_solve_triangular_selector::run), + // array index: TR | (UP << 2) | (NUNIT << 3) + (internal::band_solve_triangular_selector::run), + // array index: ADJ | (UP << 2) | (NUNIT << 3) + (internal::band_solve_triangular_selector::run), + 0, + // array index: NOTR | (LO << 2) | (NUNIT << 3) + (internal::band_solve_triangular_selector::run), + // array index: TR | (LO << 2) | (NUNIT << 3) + (internal::band_solve_triangular_selector::run), + // array index: ADJ | (LO << 2) | (NUNIT << 3) + (internal::band_solve_triangular_selector::run), + 0, + // array index: NOTR | (UP << 2) | (UNIT << 3) + (internal::band_solve_triangular_selector::run), + // array index: TR | (UP << 2) | (UNIT << 3) + (internal::band_solve_triangular_selector::run), + // array index: ADJ | (UP << 2) | (UNIT << 3) + (internal::band_solve_triangular_selector::run), + 0, + // array index: NOTR | (LO << 2) | (UNIT << 3) + (internal::band_solve_triangular_selector::run), + // array index: TR | (LO << 2) | (UNIT << 3) + (internal::band_solve_triangular_selector::run), + // array index: ADJ | (LO << 2) | (UNIT << 3) + (internal::band_solve_triangular_selector::run), + 0, + }; Scalar* a = reinterpret_cast(pa); Scalar* x = reinterpret_cast(px); int coeff_rows = *k+1; - + int info = 0; if(UPLO(*uplo)==INVALID) info = 1; else if(OP(*op)==INVALID) info = 2; @@ -373,22 +395,22 @@ int EIGEN_BLAS_FUNC(tbsv)(char *uplo, char *op, char *diag, int *n, int *k, Real else if(*incx==0) info = 9; if(info) return xerbla_(SCALAR_SUFFIX_UP"TBSV ",&info,6); - + if(*n==0 || (*k==0 && DIAG(*diag)==UNIT)) return 0; - + int actual_n = *n; - + Scalar* actual_x = get_compact_vector(x,actual_n,*incx); - + int code = OP(*op) | (UPLO(*uplo) << 2) | (DIAG(*diag) << 3); if(code>=16 || func[code]==0) return 0; func[code](*n, *k, a, *lda, actual_x); - + if(actual_x!=x) delete[] copy_back(actual_x,x,actual_n,*incx); - + return 0; } @@ -402,32 +424,36 @@ int EIGEN_BLAS_FUNC(tbsv)(char *uplo, char *op, char *diag, int *n, int *k, Real int EIGEN_BLAS_FUNC(tpmv)(char *uplo, char *opa, char *diag, int *n, RealScalar *pap, RealScalar *px, int *incx) { typedef void (*functype)(int, const Scalar*, const Scalar*, Scalar*, Scalar); - static functype func[16]; - - static bool init = false; - if(!init) - { - for(int k=0; k<16; ++k) - func[k] = 0; - - func[NOTR | (UP << 2) | (NUNIT << 3)] = (internal::packed_triangular_matrix_vector_product::run); - func[TR | (UP << 2) | (NUNIT << 3)] = (internal::packed_triangular_matrix_vector_product::run); - func[ADJ | (UP << 2) | (NUNIT << 3)] = (internal::packed_triangular_matrix_vector_product::run); - - func[NOTR | (LO << 2) | (NUNIT << 3)] = (internal::packed_triangular_matrix_vector_product::run); - func[TR | (LO << 2) | (NUNIT << 3)] = (internal::packed_triangular_matrix_vector_product::run); - func[ADJ | (LO << 2) | (NUNIT << 3)] = (internal::packed_triangular_matrix_vector_product::run); - - func[NOTR | (UP << 2) | (UNIT << 3)] = (internal::packed_triangular_matrix_vector_product::run); - func[TR | (UP << 2) | (UNIT << 3)] = (internal::packed_triangular_matrix_vector_product::run); - func[ADJ | (UP << 2) | (UNIT << 3)] = (internal::packed_triangular_matrix_vector_product::run); - - func[NOTR | (LO << 2) | (UNIT << 3)] = (internal::packed_triangular_matrix_vector_product::run); - func[TR | (LO << 2) | (UNIT << 3)] = (internal::packed_triangular_matrix_vector_product::run); - func[ADJ | (LO << 2) | (UNIT << 3)] = (internal::packed_triangular_matrix_vector_product::run); - - init = true; - } + static const functype func[16] = { + // array index: NOTR | (UP << 2) | (NUNIT << 3) + (internal::packed_triangular_matrix_vector_product::run), + // array index: TR | (UP << 2) | (NUNIT << 3) + (internal::packed_triangular_matrix_vector_product::run), + // array index: ADJ | (UP << 2) | (NUNIT << 3) + (internal::packed_triangular_matrix_vector_product::run), + 0, + // array index: NOTR | (LO << 2) | (NUNIT << 3) + (internal::packed_triangular_matrix_vector_product::run), + // array index: TR | (LO << 2) | (NUNIT << 3) + (internal::packed_triangular_matrix_vector_product::run), + // array index: ADJ | (LO << 2) | (NUNIT << 3) + (internal::packed_triangular_matrix_vector_product::run), + 0, + // array index: NOTR | (UP << 2) | (UNIT << 3) + (internal::packed_triangular_matrix_vector_product::run), + // array index: TR | (UP << 2) | (UNIT << 3) + (internal::packed_triangular_matrix_vector_product::run), + // array index: ADJ | (UP << 2) | (UNIT << 3) + (internal::packed_triangular_matrix_vector_product::run), + 0, + // array index: NOTR | (LO << 2) | (UNIT << 3) + (internal::packed_triangular_matrix_vector_product::run), + // array index: TR | (LO << 2) | (UNIT << 3) + (internal::packed_triangular_matrix_vector_product::run), + // array index: ADJ | (LO << 2) | (UNIT << 3) + (internal::packed_triangular_matrix_vector_product::run), + 0 + }; Scalar* ap = reinterpret_cast(pap); Scalar* x = reinterpret_cast(px); @@ -473,32 +499,36 @@ int EIGEN_BLAS_FUNC(tpmv)(char *uplo, char *opa, char *diag, int *n, RealScalar int EIGEN_BLAS_FUNC(tpsv)(char *uplo, char *opa, char *diag, int *n, RealScalar *pap, RealScalar *px, int *incx) { typedef void (*functype)(int, const Scalar*, Scalar*); - static functype func[16]; - - static bool init = false; - if(!init) - { - for(int k=0; k<16; ++k) - func[k] = 0; - - func[NOTR | (UP << 2) | (NUNIT << 3)] = (internal::packed_triangular_solve_vector::run); - func[TR | (UP << 2) | (NUNIT << 3)] = (internal::packed_triangular_solve_vector::run); - func[ADJ | (UP << 2) | (NUNIT << 3)] = (internal::packed_triangular_solve_vector::run); - - func[NOTR | (LO << 2) | (NUNIT << 3)] = (internal::packed_triangular_solve_vector::run); - func[TR | (LO << 2) | (NUNIT << 3)] = (internal::packed_triangular_solve_vector::run); - func[ADJ | (LO << 2) | (NUNIT << 3)] = (internal::packed_triangular_solve_vector::run); - - func[NOTR | (UP << 2) | (UNIT << 3)] = (internal::packed_triangular_solve_vector::run); - func[TR | (UP << 2) | (UNIT << 3)] = (internal::packed_triangular_solve_vector::run); - func[ADJ | (UP << 2) | (UNIT << 3)] = (internal::packed_triangular_solve_vector::run); - - func[NOTR | (LO << 2) | (UNIT << 3)] = (internal::packed_triangular_solve_vector::run); - func[TR | (LO << 2) | (UNIT << 3)] = (internal::packed_triangular_solve_vector::run); - func[ADJ | (LO << 2) | (UNIT << 3)] = (internal::packed_triangular_solve_vector::run); - - init = true; - } + static const functype func[16] = { + // array index: NOTR | (UP << 2) | (NUNIT << 3) + (internal::packed_triangular_solve_vector::run), + // array index: TR | (UP << 2) | (NUNIT << 3) + (internal::packed_triangular_solve_vector::run), + // array index: ADJ | (UP << 2) | (NUNIT << 3) + (internal::packed_triangular_solve_vector::run), + 0, + // array index: NOTR | (LO << 2) | (NUNIT << 3) + (internal::packed_triangular_solve_vector::run), + // array index: TR | (LO << 2) | (NUNIT << 3) + (internal::packed_triangular_solve_vector::run), + // array index: ADJ | (LO << 2) | (NUNIT << 3) + (internal::packed_triangular_solve_vector::run), + 0, + // array index: NOTR | (UP << 2) | (UNIT << 3) + (internal::packed_triangular_solve_vector::run), + // array index: TR | (UP << 2) | (UNIT << 3) + (internal::packed_triangular_solve_vector::run), + // array index: ADJ | (UP << 2) | (UNIT << 3) + (internal::packed_triangular_solve_vector::run), + 0, + // array index: NOTR | (LO << 2) | (UNIT << 3) + (internal::packed_triangular_solve_vector::run), + // array index: TR | (LO << 2) | (UNIT << 3) + (internal::packed_triangular_solve_vector::run), + // array index: ADJ | (LO << 2) | (UNIT << 3) + (internal::packed_triangular_solve_vector::run), + 0 + }; Scalar* ap = reinterpret_cast(pap); Scalar* x = reinterpret_cast(px); @@ -521,4 +551,3 @@ int EIGEN_BLAS_FUNC(tpsv)(char *uplo, char *opa, char *diag, int *n, RealScalar return 1; } - diff --git a/ground/gcs/src/libs/eigen/blas/level2_real_impl.h b/ground/gcs/src/libs/eigen/blas/level2_real_impl.h index 8d56eaaa14..7620f0a389 100644 --- a/ground/gcs/src/libs/eigen/blas/level2_real_impl.h +++ b/ground/gcs/src/libs/eigen/blas/level2_real_impl.h @@ -10,28 +10,22 @@ #include "common.h" // y = alpha*A*x + beta*y -int EIGEN_BLAS_FUNC(symv) (char *uplo, int *n, RealScalar *palpha, RealScalar *pa, int *lda, RealScalar *px, int *incx, RealScalar *pbeta, RealScalar *py, int *incy) +int EIGEN_BLAS_FUNC(symv) (const char *uplo, const int *n, const RealScalar *palpha, const RealScalar *pa, const int *lda, + const RealScalar *px, const int *incx, const RealScalar *pbeta, RealScalar *py, const int *incy) { - typedef void (*functype)(int, const Scalar*, int, const Scalar*, int, Scalar*, Scalar); - static functype func[2]; - - static bool init = false; - if(!init) - { - for(int k=0; k<2; ++k) - func[k] = 0; - - func[UP] = (internal::selfadjoint_matrix_vector_product::run); - func[LO] = (internal::selfadjoint_matrix_vector_product::run); - - init = true; - } - - Scalar* a = reinterpret_cast(pa); - Scalar* x = reinterpret_cast(px); + typedef void (*functype)(int, const Scalar*, int, const Scalar*, Scalar*, Scalar); + static const functype func[2] = { + // array index: UP + (internal::selfadjoint_matrix_vector_product::run), + // array index: LO + (internal::selfadjoint_matrix_vector_product::run), + }; + + const Scalar* a = reinterpret_cast(pa); + const Scalar* x = reinterpret_cast(px); Scalar* y = reinterpret_cast(py); - Scalar alpha = *reinterpret_cast(palpha); - Scalar beta = *reinterpret_cast(pbeta); + Scalar alpha = *reinterpret_cast(palpha); + Scalar beta = *reinterpret_cast(pbeta); // check arguments int info = 0; @@ -46,20 +40,20 @@ int EIGEN_BLAS_FUNC(symv) (char *uplo, int *n, RealScalar *palpha, RealScalar *p if(*n==0) return 0; - Scalar* actual_x = get_compact_vector(x,*n,*incx); + const Scalar* actual_x = get_compact_vector(x,*n,*incx); Scalar* actual_y = get_compact_vector(y,*n,*incy); if(beta!=Scalar(1)) { - if(beta==Scalar(0)) vector(actual_y, *n).setZero(); - else vector(actual_y, *n) *= beta; + if(beta==Scalar(0)) make_vector(actual_y, *n).setZero(); + else make_vector(actual_y, *n) *= beta; } int code = UPLO(*uplo); if(code>=2 || func[code]==0) return 0; - func[code](*n, a, *lda, actual_x, 1, actual_y, alpha); + func[code](*n, a, *lda, actual_x, actual_y, alpha); if(actual_x!=x) delete[] actual_x; if(actual_y!=y) delete[] copy_back(actual_y,y,*n,*incy); @@ -68,41 +62,20 @@ int EIGEN_BLAS_FUNC(symv) (char *uplo, int *n, RealScalar *palpha, RealScalar *p } // C := alpha*x*x' + C -int EIGEN_BLAS_FUNC(syr)(char *uplo, int *n, RealScalar *palpha, RealScalar *px, int *incx, RealScalar *pc, int *ldc) +int EIGEN_BLAS_FUNC(syr)(const char *uplo, const int *n, const RealScalar *palpha, const RealScalar *px, const int *incx, RealScalar *pc, const int *ldc) { -// typedef void (*functype)(int, const Scalar *, int, Scalar *, int, Scalar); -// static functype func[2]; - -// static bool init = false; -// if(!init) -// { -// for(int k=0; k<2; ++k) -// func[k] = 0; -// -// func[UP] = (internal::selfadjoint_product::run); -// func[LO] = (internal::selfadjoint_product::run); - -// init = true; -// } typedef void (*functype)(int, Scalar*, int, const Scalar*, const Scalar*, const Scalar&); - static functype func[2]; - - static bool init = false; - if(!init) - { - for(int k=0; k<2; ++k) - func[k] = 0; - - func[UP] = (selfadjoint_rank1_update::run); - func[LO] = (selfadjoint_rank1_update::run); - - init = true; - } - - Scalar* x = reinterpret_cast(px); + static const functype func[2] = { + // array index: UP + (selfadjoint_rank1_update::run), + // array index: LO + (selfadjoint_rank1_update::run), + }; + + const Scalar* x = reinterpret_cast(px); Scalar* c = reinterpret_cast(pc); - Scalar alpha = *reinterpret_cast(palpha); + Scalar alpha = *reinterpret_cast(palpha); int info = 0; if(UPLO(*uplo)==INVALID) info = 1; @@ -115,7 +88,7 @@ int EIGEN_BLAS_FUNC(syr)(char *uplo, int *n, RealScalar *palpha, RealScalar *px, if(*n==0 || alpha==Scalar(0)) return 1; // if the increment is not 1, let's copy it to a temporary vector to enable vectorization - Scalar* x_cpy = get_compact_vector(x,*n,*incx); + const Scalar* x_cpy = get_compact_vector(x,*n,*incx); int code = UPLO(*uplo); if(code>=2 || func[code]==0) @@ -129,41 +102,20 @@ int EIGEN_BLAS_FUNC(syr)(char *uplo, int *n, RealScalar *palpha, RealScalar *px, } // C := alpha*x*y' + alpha*y*x' + C -int EIGEN_BLAS_FUNC(syr2)(char *uplo, int *n, RealScalar *palpha, RealScalar *px, int *incx, RealScalar *py, int *incy, RealScalar *pc, int *ldc) +int EIGEN_BLAS_FUNC(syr2)(const char *uplo, const int *n, const RealScalar *palpha, const RealScalar *px, const int *incx, const RealScalar *py, const int *incy, RealScalar *pc, const int *ldc) { -// typedef void (*functype)(int, const Scalar *, int, const Scalar *, int, Scalar *, int, Scalar); -// static functype func[2]; -// -// static bool init = false; -// if(!init) -// { -// for(int k=0; k<2; ++k) -// func[k] = 0; -// -// func[UP] = (internal::selfadjoint_product::run); -// func[LO] = (internal::selfadjoint_product::run); -// -// init = true; -// } typedef void (*functype)(int, Scalar*, int, const Scalar*, const Scalar*, Scalar); - static functype func[2]; - - static bool init = false; - if(!init) - { - for(int k=0; k<2; ++k) - func[k] = 0; - - func[UP] = (internal::rank2_update_selector::run); - func[LO] = (internal::rank2_update_selector::run); - - init = true; - } - - Scalar* x = reinterpret_cast(px); - Scalar* y = reinterpret_cast(py); + static const functype func[2] = { + // array index: UP + (internal::rank2_update_selector::run), + // array index: LO + (internal::rank2_update_selector::run), + }; + + const Scalar* x = reinterpret_cast(px); + const Scalar* y = reinterpret_cast(py); Scalar* c = reinterpret_cast(pc); - Scalar alpha = *reinterpret_cast(palpha); + Scalar alpha = *reinterpret_cast(palpha); int info = 0; if(UPLO(*uplo)==INVALID) info = 1; @@ -177,9 +129,9 @@ int EIGEN_BLAS_FUNC(syr2)(char *uplo, int *n, RealScalar *palpha, RealScalar *px if(alpha==Scalar(0)) return 1; - Scalar* x_cpy = get_compact_vector(x,*n,*incx); - Scalar* y_cpy = get_compact_vector(y,*n,*incy); - + const Scalar* x_cpy = get_compact_vector(x,*n,*incx); + const Scalar* y_cpy = get_compact_vector(y,*n,*incy); + int code = UPLO(*uplo); if(code>=2 || func[code]==0) return 0; @@ -234,19 +186,12 @@ int EIGEN_BLAS_FUNC(syr2)(char *uplo, int *n, RealScalar *palpha, RealScalar *px int EIGEN_BLAS_FUNC(spr)(char *uplo, int *n, Scalar *palpha, Scalar *px, int *incx, Scalar *pap) { typedef void (*functype)(int, Scalar*, const Scalar*, Scalar); - static functype func[2]; - - static bool init = false; - if(!init) - { - for(int k=0; k<2; ++k) - func[k] = 0; - - func[UP] = (internal::selfadjoint_packed_rank1_update::run); - func[LO] = (internal::selfadjoint_packed_rank1_update::run); - - init = true; - } + static const functype func[2] = { + // array index: UP + (internal::selfadjoint_packed_rank1_update::run), + // array index: LO + (internal::selfadjoint_packed_rank1_update::run), + }; Scalar* x = reinterpret_cast(px); Scalar* ap = reinterpret_cast(pap); @@ -285,19 +230,12 @@ int EIGEN_BLAS_FUNC(spr)(char *uplo, int *n, Scalar *palpha, Scalar *px, int *in int EIGEN_BLAS_FUNC(spr2)(char *uplo, int *n, RealScalar *palpha, RealScalar *px, int *incx, RealScalar *py, int *incy, RealScalar *pap) { typedef void (*functype)(int, Scalar*, const Scalar*, const Scalar*, Scalar); - static functype func[2]; - - static bool init = false; - if(!init) - { - for(int k=0; k<2; ++k) - func[k] = 0; - - func[UP] = (internal::packed_rank2_update_selector::run); - func[LO] = (internal::packed_rank2_update_selector::run); - - init = true; - } + static const functype func[2] = { + // array index: UP + (internal::packed_rank2_update_selector::run), + // array index: LO + (internal::packed_rank2_update_selector::run), + }; Scalar* x = reinterpret_cast(px); Scalar* y = reinterpret_cast(py); @@ -366,5 +304,3 @@ int EIGEN_BLAS_FUNC(ger)(int *m, int *n, Scalar *palpha, Scalar *px, int *incx, return 1; } - - diff --git a/ground/gcs/src/libs/eigen/blas/level3_impl.h b/ground/gcs/src/libs/eigen/blas/level3_impl.h index 07dbc22ff2..6c802cd5fd 100644 --- a/ground/gcs/src/libs/eigen/blas/level3_impl.h +++ b/ground/gcs/src/libs/eigen/blas/level3_impl.h @@ -6,37 +6,43 @@ // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - +#include #include "common.h" -int EIGEN_BLAS_FUNC(gemm)(char *opa, char *opb, int *m, int *n, int *k, RealScalar *palpha, RealScalar *pa, int *lda, RealScalar *pb, int *ldb, RealScalar *pbeta, RealScalar *pc, int *ldc) +int EIGEN_BLAS_FUNC(gemm)(const char *opa, const char *opb, const int *m, const int *n, const int *k, const RealScalar *palpha, + const RealScalar *pa, const int *lda, const RealScalar *pb, const int *ldb, const RealScalar *pbeta, RealScalar *pc, const int *ldc) { // std::cerr << "in gemm " << *opa << " " << *opb << " " << *m << " " << *n << " " << *k << " " << *lda << " " << *ldb << " " << *ldc << " " << *palpha << " " << *pbeta << "\n"; typedef void (*functype)(DenseIndex, DenseIndex, DenseIndex, const Scalar *, DenseIndex, const Scalar *, DenseIndex, Scalar *, DenseIndex, Scalar, internal::level3_blocking&, Eigen::internal::GemmParallelInfo*); - static functype func[12]; - - static bool init = false; - if(!init) - { - for(int k=0; k<12; ++k) - func[k] = 0; - func[NOTR | (NOTR << 2)] = (internal::general_matrix_matrix_product::run); - func[TR | (NOTR << 2)] = (internal::general_matrix_matrix_product::run); - func[ADJ | (NOTR << 2)] = (internal::general_matrix_matrix_product::run); - func[NOTR | (TR << 2)] = (internal::general_matrix_matrix_product::run); - func[TR | (TR << 2)] = (internal::general_matrix_matrix_product::run); - func[ADJ | (TR << 2)] = (internal::general_matrix_matrix_product::run); - func[NOTR | (ADJ << 2)] = (internal::general_matrix_matrix_product::run); - func[TR | (ADJ << 2)] = (internal::general_matrix_matrix_product::run); - func[ADJ | (ADJ << 2)] = (internal::general_matrix_matrix_product::run); - init = true; - } - - Scalar* a = reinterpret_cast(pa); - Scalar* b = reinterpret_cast(pb); + static const functype func[12] = { + // array index: NOTR | (NOTR << 2) + (internal::general_matrix_matrix_product::run), + // array index: TR | (NOTR << 2) + (internal::general_matrix_matrix_product::run), + // array index: ADJ | (NOTR << 2) + (internal::general_matrix_matrix_product::run), + 0, + // array index: NOTR | (TR << 2) + (internal::general_matrix_matrix_product::run), + // array index: TR | (TR << 2) + (internal::general_matrix_matrix_product::run), + // array index: ADJ | (TR << 2) + (internal::general_matrix_matrix_product::run), + 0, + // array index: NOTR | (ADJ << 2) + (internal::general_matrix_matrix_product::run), + // array index: TR | (ADJ << 2) + (internal::general_matrix_matrix_product::run), + // array index: ADJ | (ADJ << 2) + (internal::general_matrix_matrix_product::run), + 0 + }; + + const Scalar* a = reinterpret_cast(pa); + const Scalar* b = reinterpret_cast(pb); Scalar* c = reinterpret_cast(pc); - Scalar alpha = *reinterpret_cast(palpha); - Scalar beta = *reinterpret_cast(pbeta); + Scalar alpha = *reinterpret_cast(palpha); + Scalar beta = *reinterpret_cast(pbeta); int info = 0; if(OP(*opa)==INVALID) info = 1; @@ -50,70 +56,92 @@ int EIGEN_BLAS_FUNC(gemm)(char *opa, char *opb, int *m, int *n, int *k, RealScal if(info) return xerbla_(SCALAR_SUFFIX_UP"GEMM ",&info,6); + if (*m == 0 || *n == 0) + return 0; + if(beta!=Scalar(1)) { if(beta==Scalar(0)) matrix(c, *m, *n, *ldc).setZero(); else matrix(c, *m, *n, *ldc) *= beta; } - internal::gemm_blocking_space blocking(*m,*n,*k); + if(*k == 0) + return 0; + + internal::gemm_blocking_space blocking(*m,*n,*k,1,true); int code = OP(*opa) | (OP(*opb) << 2); func[code](*m, *n, *k, a, *lda, b, *ldb, c, *ldc, alpha, blocking, 0); return 0; } -int EIGEN_BLAS_FUNC(trsm)(char *side, char *uplo, char *opa, char *diag, int *m, int *n, RealScalar *palpha, RealScalar *pa, int *lda, RealScalar *pb, int *ldb) +int EIGEN_BLAS_FUNC(trsm)(const char *side, const char *uplo, const char *opa, const char *diag, const int *m, const int *n, + const RealScalar *palpha, const RealScalar *pa, const int *lda, RealScalar *pb, const int *ldb) { // std::cerr << "in trsm " << *side << " " << *uplo << " " << *opa << " " << *diag << " " << *m << "," << *n << " " << *palpha << " " << *lda << " " << *ldb<< "\n"; typedef void (*functype)(DenseIndex, DenseIndex, const Scalar *, DenseIndex, Scalar *, DenseIndex, internal::level3_blocking&); - static functype func[32]; - - static bool init = false; - if(!init) - { - for(int k=0; k<32; ++k) - func[k] = 0; - - func[NOTR | (LEFT << 2) | (UP << 3) | (NUNIT << 4)] = (internal::triangular_solve_matrix::run); - func[TR | (LEFT << 2) | (UP << 3) | (NUNIT << 4)] = (internal::triangular_solve_matrix::run); - func[ADJ | (LEFT << 2) | (UP << 3) | (NUNIT << 4)] = (internal::triangular_solve_matrix::run); - - func[NOTR | (RIGHT << 2) | (UP << 3) | (NUNIT << 4)] = (internal::triangular_solve_matrix::run); - func[TR | (RIGHT << 2) | (UP << 3) | (NUNIT << 4)] = (internal::triangular_solve_matrix::run); - func[ADJ | (RIGHT << 2) | (UP << 3) | (NUNIT << 4)] = (internal::triangular_solve_matrix::run); - - func[NOTR | (LEFT << 2) | (LO << 3) | (NUNIT << 4)] = (internal::triangular_solve_matrix::run); - func[TR | (LEFT << 2) | (LO << 3) | (NUNIT << 4)] = (internal::triangular_solve_matrix::run); - func[ADJ | (LEFT << 2) | (LO << 3) | (NUNIT << 4)] = (internal::triangular_solve_matrix::run); - - func[NOTR | (RIGHT << 2) | (LO << 3) | (NUNIT << 4)] = (internal::triangular_solve_matrix::run); - func[TR | (RIGHT << 2) | (LO << 3) | (NUNIT << 4)] = (internal::triangular_solve_matrix::run); - func[ADJ | (RIGHT << 2) | (LO << 3) | (NUNIT << 4)] = (internal::triangular_solve_matrix::run); - - - func[NOTR | (LEFT << 2) | (UP << 3) | (UNIT << 4)] = (internal::triangular_solve_matrix::run); - func[TR | (LEFT << 2) | (UP << 3) | (UNIT << 4)] = (internal::triangular_solve_matrix::run); - func[ADJ | (LEFT << 2) | (UP << 3) | (UNIT << 4)] = (internal::triangular_solve_matrix::run); - - func[NOTR | (RIGHT << 2) | (UP << 3) | (UNIT << 4)] = (internal::triangular_solve_matrix::run); - func[TR | (RIGHT << 2) | (UP << 3) | (UNIT << 4)] = (internal::triangular_solve_matrix::run); - func[ADJ | (RIGHT << 2) | (UP << 3) | (UNIT << 4)] = (internal::triangular_solve_matrix::run); - - func[NOTR | (LEFT << 2) | (LO << 3) | (UNIT << 4)] = (internal::triangular_solve_matrix::run); - func[TR | (LEFT << 2) | (LO << 3) | (UNIT << 4)] = (internal::triangular_solve_matrix::run); - func[ADJ | (LEFT << 2) | (LO << 3) | (UNIT << 4)] = (internal::triangular_solve_matrix::run); - - func[NOTR | (RIGHT << 2) | (LO << 3) | (UNIT << 4)] = (internal::triangular_solve_matrix::run); - func[TR | (RIGHT << 2) | (LO << 3) | (UNIT << 4)] = (internal::triangular_solve_matrix::run); - func[ADJ | (RIGHT << 2) | (LO << 3) | (UNIT << 4)] = (internal::triangular_solve_matrix::run); - - init = true; - } - - Scalar* a = reinterpret_cast(pa); + static const functype func[32] = { + // array index: NOTR | (LEFT << 2) | (UP << 3) | (NUNIT << 4) + (internal::triangular_solve_matrix::run), + // array index: TR | (LEFT << 2) | (UP << 3) | (NUNIT << 4) + (internal::triangular_solve_matrix::run), + // array index: ADJ | (LEFT << 2) | (UP << 3) | (NUNIT << 4) + (internal::triangular_solve_matrix::run),\ + 0, + // array index: NOTR | (RIGHT << 2) | (UP << 3) | (NUNIT << 4) + (internal::triangular_solve_matrix::run), + // array index: TR | (RIGHT << 2) | (UP << 3) | (NUNIT << 4) + (internal::triangular_solve_matrix::run), + // array index: ADJ | (RIGHT << 2) | (UP << 3) | (NUNIT << 4) + (internal::triangular_solve_matrix::run), + 0, + // array index: NOTR | (LEFT << 2) | (LO << 3) | (NUNIT << 4) + (internal::triangular_solve_matrix::run), + // array index: TR | (LEFT << 2) | (LO << 3) | (NUNIT << 4) + (internal::triangular_solve_matrix::run), + // array index: ADJ | (LEFT << 2) | (LO << 3) | (NUNIT << 4) + (internal::triangular_solve_matrix::run), + 0, + // array index: NOTR | (RIGHT << 2) | (LO << 3) | (NUNIT << 4) + (internal::triangular_solve_matrix::run), + // array index: TR | (RIGHT << 2) | (LO << 3) | (NUNIT << 4) + (internal::triangular_solve_matrix::run), + // array index: ADJ | (RIGHT << 2) | (LO << 3) | (NUNIT << 4) + (internal::triangular_solve_matrix::run), + 0, + // array index: NOTR | (LEFT << 2) | (UP << 3) | (UNIT << 4) + (internal::triangular_solve_matrix::run), + // array index: TR | (LEFT << 2) | (UP << 3) | (UNIT << 4) + (internal::triangular_solve_matrix::run), + // array index: ADJ | (LEFT << 2) | (UP << 3) | (UNIT << 4) + (internal::triangular_solve_matrix::run), + 0, + // array index: NOTR | (RIGHT << 2) | (UP << 3) | (UNIT << 4) + (internal::triangular_solve_matrix::run), + // array index: TR | (RIGHT << 2) | (UP << 3) | (UNIT << 4) + (internal::triangular_solve_matrix::run), + // array index: ADJ | (RIGHT << 2) | (UP << 3) | (UNIT << 4) + (internal::triangular_solve_matrix::run), + 0, + // array index: NOTR | (LEFT << 2) | (LO << 3) | (UNIT << 4) + (internal::triangular_solve_matrix::run), + // array index: TR | (LEFT << 2) | (LO << 3) | (UNIT << 4) + (internal::triangular_solve_matrix::run), + // array index: ADJ | (LEFT << 2) | (LO << 3) | (UNIT << 4) + (internal::triangular_solve_matrix::run), + 0, + // array index: NOTR | (RIGHT << 2) | (LO << 3) | (UNIT << 4) + (internal::triangular_solve_matrix::run), + // array index: TR | (RIGHT << 2) | (LO << 3) | (UNIT << 4) + (internal::triangular_solve_matrix::run), + // array index: ADJ | (RIGHT << 2) | (LO << 3) | (UNIT << 4) + (internal::triangular_solve_matrix::run), + 0 + }; + + const Scalar* a = reinterpret_cast(pa); Scalar* b = reinterpret_cast(pb); - Scalar alpha = *reinterpret_cast(palpha); + Scalar alpha = *reinterpret_cast(palpha); int info = 0; if(SIDE(*side)==INVALID) info = 1; @@ -127,16 +155,19 @@ int EIGEN_BLAS_FUNC(trsm)(char *side, char *uplo, char *opa, char *diag, int *m, if(info) return xerbla_(SCALAR_SUFFIX_UP"TRSM ",&info,6); + if(*m==0 || *n==0) + return 0; + int code = OP(*opa) | (SIDE(*side) << 2) | (UPLO(*uplo) << 3) | (DIAG(*diag) << 4); - + if(SIDE(*side)==LEFT) { - internal::gemm_blocking_space blocking(*m,*n,*m); + internal::gemm_blocking_space blocking(*m,*n,*m,1,false); func[code](*m, *n, a, *lda, b, *ldb, blocking); } else { - internal::gemm_blocking_space blocking(*m,*n,*n); + internal::gemm_blocking_space blocking(*m,*n,*n,1,false); func[code](*n, *m, a, *lda, b, *ldb, blocking); } @@ -149,55 +180,73 @@ int EIGEN_BLAS_FUNC(trsm)(char *side, char *uplo, char *opa, char *diag, int *m, // b = alpha*op(a)*b for side = 'L'or'l' // b = alpha*b*op(a) for side = 'R'or'r' -int EIGEN_BLAS_FUNC(trmm)(char *side, char *uplo, char *opa, char *diag, int *m, int *n, RealScalar *palpha, RealScalar *pa, int *lda, RealScalar *pb, int *ldb) +int EIGEN_BLAS_FUNC(trmm)(const char *side, const char *uplo, const char *opa, const char *diag, const int *m, const int *n, + const RealScalar *palpha, const RealScalar *pa, const int *lda, RealScalar *pb, const int *ldb) { // std::cerr << "in trmm " << *side << " " << *uplo << " " << *opa << " " << *diag << " " << *m << " " << *n << " " << *lda << " " << *ldb << " " << *palpha << "\n"; typedef void (*functype)(DenseIndex, DenseIndex, DenseIndex, const Scalar *, DenseIndex, const Scalar *, DenseIndex, Scalar *, DenseIndex, const Scalar&, internal::level3_blocking&); - static functype func[32]; - static bool init = false; - if(!init) - { - for(int k=0; k<32; ++k) - func[k] = 0; - - func[NOTR | (LEFT << 2) | (UP << 3) | (NUNIT << 4)] = (internal::product_triangular_matrix_matrix::run); - func[TR | (LEFT << 2) | (UP << 3) | (NUNIT << 4)] = (internal::product_triangular_matrix_matrix::run); - func[ADJ | (LEFT << 2) | (UP << 3) | (NUNIT << 4)] = (internal::product_triangular_matrix_matrix::run); - - func[NOTR | (RIGHT << 2) | (UP << 3) | (NUNIT << 4)] = (internal::product_triangular_matrix_matrix::run); - func[TR | (RIGHT << 2) | (UP << 3) | (NUNIT << 4)] = (internal::product_triangular_matrix_matrix::run); - func[ADJ | (RIGHT << 2) | (UP << 3) | (NUNIT << 4)] = (internal::product_triangular_matrix_matrix::run); - - func[NOTR | (LEFT << 2) | (LO << 3) | (NUNIT << 4)] = (internal::product_triangular_matrix_matrix::run); - func[TR | (LEFT << 2) | (LO << 3) | (NUNIT << 4)] = (internal::product_triangular_matrix_matrix::run); - func[ADJ | (LEFT << 2) | (LO << 3) | (NUNIT << 4)] = (internal::product_triangular_matrix_matrix::run); - - func[NOTR | (RIGHT << 2) | (LO << 3) | (NUNIT << 4)] = (internal::product_triangular_matrix_matrix::run); - func[TR | (RIGHT << 2) | (LO << 3) | (NUNIT << 4)] = (internal::product_triangular_matrix_matrix::run); - func[ADJ | (RIGHT << 2) | (LO << 3) | (NUNIT << 4)] = (internal::product_triangular_matrix_matrix::run); - - func[NOTR | (LEFT << 2) | (UP << 3) | (UNIT << 4)] = (internal::product_triangular_matrix_matrix::run); - func[TR | (LEFT << 2) | (UP << 3) | (UNIT << 4)] = (internal::product_triangular_matrix_matrix::run); - func[ADJ | (LEFT << 2) | (UP << 3) | (UNIT << 4)] = (internal::product_triangular_matrix_matrix::run); - - func[NOTR | (RIGHT << 2) | (UP << 3) | (UNIT << 4)] = (internal::product_triangular_matrix_matrix::run); - func[TR | (RIGHT << 2) | (UP << 3) | (UNIT << 4)] = (internal::product_triangular_matrix_matrix::run); - func[ADJ | (RIGHT << 2) | (UP << 3) | (UNIT << 4)] = (internal::product_triangular_matrix_matrix::run); - - func[NOTR | (LEFT << 2) | (LO << 3) | (UNIT << 4)] = (internal::product_triangular_matrix_matrix::run); - func[TR | (LEFT << 2) | (LO << 3) | (UNIT << 4)] = (internal::product_triangular_matrix_matrix::run); - func[ADJ | (LEFT << 2) | (LO << 3) | (UNIT << 4)] = (internal::product_triangular_matrix_matrix::run); - - func[NOTR | (RIGHT << 2) | (LO << 3) | (UNIT << 4)] = (internal::product_triangular_matrix_matrix::run); - func[TR | (RIGHT << 2) | (LO << 3) | (UNIT << 4)] = (internal::product_triangular_matrix_matrix::run); - func[ADJ | (RIGHT << 2) | (LO << 3) | (UNIT << 4)] = (internal::product_triangular_matrix_matrix::run); - - init = true; - } - - Scalar* a = reinterpret_cast(pa); + static const functype func[32] = { + // array index: NOTR | (LEFT << 2) | (UP << 3) | (NUNIT << 4) + (internal::product_triangular_matrix_matrix::run), + // array index: TR | (LEFT << 2) | (UP << 3) | (NUNIT << 4) + (internal::product_triangular_matrix_matrix::run), + // array index: ADJ | (LEFT << 2) | (UP << 3) | (NUNIT << 4) + (internal::product_triangular_matrix_matrix::run), + 0, + // array index: NOTR | (RIGHT << 2) | (UP << 3) | (NUNIT << 4) + (internal::product_triangular_matrix_matrix::run), + // array index: TR | (RIGHT << 2) | (UP << 3) | (NUNIT << 4) + (internal::product_triangular_matrix_matrix::run), + // array index: ADJ | (RIGHT << 2) | (UP << 3) | (NUNIT << 4) + (internal::product_triangular_matrix_matrix::run), + 0, + // array index: NOTR | (LEFT << 2) | (LO << 3) | (NUNIT << 4) + (internal::product_triangular_matrix_matrix::run), + // array index: TR | (LEFT << 2) | (LO << 3) | (NUNIT << 4) + (internal::product_triangular_matrix_matrix::run), + // array index: ADJ | (LEFT << 2) | (LO << 3) | (NUNIT << 4) + (internal::product_triangular_matrix_matrix::run), + 0, + // array index: NOTR | (RIGHT << 2) | (LO << 3) | (NUNIT << 4) + (internal::product_triangular_matrix_matrix::run), + // array index: TR | (RIGHT << 2) | (LO << 3) | (NUNIT << 4) + (internal::product_triangular_matrix_matrix::run), + // array index: ADJ | (RIGHT << 2) | (LO << 3) | (NUNIT << 4) + (internal::product_triangular_matrix_matrix::run), + 0, + // array index: NOTR | (LEFT << 2) | (UP << 3) | (UNIT << 4) + (internal::product_triangular_matrix_matrix::run), + // array index: TR | (LEFT << 2) | (UP << 3) | (UNIT << 4) + (internal::product_triangular_matrix_matrix::run), + // array index: ADJ | (LEFT << 2) | (UP << 3) | (UNIT << 4) + (internal::product_triangular_matrix_matrix::run), + 0, + // array index: NOTR | (RIGHT << 2) | (UP << 3) | (UNIT << 4) + (internal::product_triangular_matrix_matrix::run), + // array index: TR | (RIGHT << 2) | (UP << 3) | (UNIT << 4) + (internal::product_triangular_matrix_matrix::run), + // array index: ADJ | (RIGHT << 2) | (UP << 3) | (UNIT << 4) + (internal::product_triangular_matrix_matrix::run), + 0, + // array index: NOTR | (LEFT << 2) | (LO << 3) | (UNIT << 4) + (internal::product_triangular_matrix_matrix::run), + // array index: TR | (LEFT << 2) | (LO << 3) | (UNIT << 4) + (internal::product_triangular_matrix_matrix::run), + // array index: ADJ | (LEFT << 2) | (LO << 3) | (UNIT << 4) + (internal::product_triangular_matrix_matrix::run), + 0, + // array index: NOTR | (RIGHT << 2) | (LO << 3) | (UNIT << 4) + (internal::product_triangular_matrix_matrix::run), + // array index: TR | (RIGHT << 2) | (LO << 3) | (UNIT << 4) + (internal::product_triangular_matrix_matrix::run), + // array index: ADJ | (RIGHT << 2) | (LO << 3) | (UNIT << 4) + (internal::product_triangular_matrix_matrix::run), + 0 + }; + + const Scalar* a = reinterpret_cast(pa); Scalar* b = reinterpret_cast(pb); - Scalar alpha = *reinterpret_cast(palpha); + Scalar alpha = *reinterpret_cast(palpha); int info = 0; if(SIDE(*side)==INVALID) info = 1; @@ -222,12 +271,12 @@ int EIGEN_BLAS_FUNC(trmm)(char *side, char *uplo, char *opa, char *diag, int *m, if(SIDE(*side)==LEFT) { - internal::gemm_blocking_space blocking(*m,*n,*m); + internal::gemm_blocking_space blocking(*m,*n,*m,1,false); func[code](*m, *n, *m, a, *lda, tmp.data(), tmp.outerStride(), b, *ldb, alpha, blocking); } else { - internal::gemm_blocking_space blocking(*m,*n,*n); + internal::gemm_blocking_space blocking(*m,*n,*n,1,false); func[code](*m, *n, *n, tmp.data(), tmp.outerStride(), a, *lda, b, *ldb, alpha, blocking); } return 1; @@ -235,14 +284,15 @@ int EIGEN_BLAS_FUNC(trmm)(char *side, char *uplo, char *opa, char *diag, int *m, // c = alpha*a*b + beta*c for side = 'L'or'l' // c = alpha*b*a + beta*c for side = 'R'or'r -int EIGEN_BLAS_FUNC(symm)(char *side, char *uplo, int *m, int *n, RealScalar *palpha, RealScalar *pa, int *lda, RealScalar *pb, int *ldb, RealScalar *pbeta, RealScalar *pc, int *ldc) +int EIGEN_BLAS_FUNC(symm)(const char *side, const char *uplo, const int *m, const int *n, const RealScalar *palpha, + const RealScalar *pa, const int *lda, const RealScalar *pb, const int *ldb, const RealScalar *pbeta, RealScalar *pc, const int *ldc) { // std::cerr << "in symm " << *side << " " << *uplo << " " << *m << "x" << *n << " lda:" << *lda << " ldb:" << *ldb << " ldc:" << *ldc << " alpha:" << *palpha << " beta:" << *pbeta << "\n"; - Scalar* a = reinterpret_cast(pa); - Scalar* b = reinterpret_cast(pb); + const Scalar* a = reinterpret_cast(pa); + const Scalar* b = reinterpret_cast(pb); Scalar* c = reinterpret_cast(pc); - Scalar alpha = *reinterpret_cast(palpha); - Scalar beta = *reinterpret_cast(pbeta); + Scalar alpha = *reinterpret_cast(palpha); + Scalar beta = *reinterpret_cast(pbeta); int info = 0; if(SIDE(*side)==INVALID) info = 1; @@ -266,9 +316,9 @@ int EIGEN_BLAS_FUNC(symm)(char *side, char *uplo, int *m, int *n, RealScalar *pa return 1; } + int size = (SIDE(*side)==LEFT) ? (*m) : (*n); #if ISCOMPLEX // FIXME add support for symmetric complex matrix - int size = (SIDE(*side)==LEFT) ? (*m) : (*n); Matrix matA(size,size); if(UPLO(*uplo)==UP) { @@ -285,13 +335,15 @@ int EIGEN_BLAS_FUNC(symm)(char *side, char *uplo, int *m, int *n, RealScalar *pa else if(SIDE(*side)==RIGHT) matrix(c, *m, *n, *ldc) += alpha * matrix(b, *m, *n, *ldb) * matA; #else + internal::gemm_blocking_space blocking(*m,*n,size,1,false); + if(SIDE(*side)==LEFT) - if(UPLO(*uplo)==UP) internal::product_selfadjoint_matrix::run(*m, *n, a, *lda, b, *ldb, c, *ldc, alpha); - else if(UPLO(*uplo)==LO) internal::product_selfadjoint_matrix::run(*m, *n, a, *lda, b, *ldb, c, *ldc, alpha); + if(UPLO(*uplo)==UP) internal::product_selfadjoint_matrix::run(*m, *n, a, *lda, b, *ldb, c, *ldc, alpha, blocking); + else if(UPLO(*uplo)==LO) internal::product_selfadjoint_matrix::run(*m, *n, a, *lda, b, *ldb, c, *ldc, alpha, blocking); else return 0; else if(SIDE(*side)==RIGHT) - if(UPLO(*uplo)==UP) internal::product_selfadjoint_matrix::run(*m, *n, b, *ldb, a, *lda, c, *ldc, alpha); - else if(UPLO(*uplo)==LO) internal::product_selfadjoint_matrix::run(*m, *n, b, *ldb, a, *lda, c, *ldc, alpha); + if(UPLO(*uplo)==UP) internal::product_selfadjoint_matrix::run(*m, *n, b, *ldb, a, *lda, c, *ldc, alpha, blocking); + else if(UPLO(*uplo)==LO) internal::product_selfadjoint_matrix::run(*m, *n, b, *ldb, a, *lda, c, *ldc, alpha, blocking); else return 0; else return 0; @@ -302,39 +354,38 @@ int EIGEN_BLAS_FUNC(symm)(char *side, char *uplo, int *m, int *n, RealScalar *pa // c = alpha*a*a' + beta*c for op = 'N'or'n' // c = alpha*a'*a + beta*c for op = 'T'or't','C'or'c' -int EIGEN_BLAS_FUNC(syrk)(char *uplo, char *op, int *n, int *k, RealScalar *palpha, RealScalar *pa, int *lda, RealScalar *pbeta, RealScalar *pc, int *ldc) +int EIGEN_BLAS_FUNC(syrk)(const char *uplo, const char *op, const int *n, const int *k, + const RealScalar *palpha, const RealScalar *pa, const int *lda, const RealScalar *pbeta, RealScalar *pc, const int *ldc) { // std::cerr << "in syrk " << *uplo << " " << *op << " " << *n << " " << *k << " " << *palpha << " " << *lda << " " << *pbeta << " " << *ldc << "\n"; #if !ISCOMPLEX - typedef void (*functype)(DenseIndex, DenseIndex, const Scalar *, DenseIndex, const Scalar *, DenseIndex, Scalar *, DenseIndex, const Scalar&); - static functype func[8]; - - static bool init = false; - if(!init) - { - for(int k=0; k<8; ++k) - func[k] = 0; - - func[NOTR | (UP << 2)] = (internal::general_matrix_matrix_triangular_product::run); - func[TR | (UP << 2)] = (internal::general_matrix_matrix_triangular_product::run); - func[ADJ | (UP << 2)] = (internal::general_matrix_matrix_triangular_product::run); - - func[NOTR | (LO << 2)] = (internal::general_matrix_matrix_triangular_product::run); - func[TR | (LO << 2)] = (internal::general_matrix_matrix_triangular_product::run); - func[ADJ | (LO << 2)] = (internal::general_matrix_matrix_triangular_product::run); - - init = true; - } + typedef void (*functype)(DenseIndex, DenseIndex, const Scalar *, DenseIndex, const Scalar *, DenseIndex, Scalar *, DenseIndex, const Scalar&, internal::level3_blocking&); + static const functype func[8] = { + // array index: NOTR | (UP << 2) + (internal::general_matrix_matrix_triangular_product::run), + // array index: TR | (UP << 2) + (internal::general_matrix_matrix_triangular_product::run), + // array index: ADJ | (UP << 2) + (internal::general_matrix_matrix_triangular_product::run), + 0, + // array index: NOTR | (LO << 2) + (internal::general_matrix_matrix_triangular_product::run), + // array index: TR | (LO << 2) + (internal::general_matrix_matrix_triangular_product::run), + // array index: ADJ | (LO << 2) + (internal::general_matrix_matrix_triangular_product::run), + 0 + }; #endif - Scalar* a = reinterpret_cast(pa); + const Scalar* a = reinterpret_cast(pa); Scalar* c = reinterpret_cast(pc); - Scalar alpha = *reinterpret_cast(palpha); - Scalar beta = *reinterpret_cast(pbeta); + Scalar alpha = *reinterpret_cast(palpha); + Scalar beta = *reinterpret_cast(pbeta); int info = 0; if(UPLO(*uplo)==INVALID) info = 1; - else if(OP(*op)==INVALID) info = 2; + else if(OP(*op)==INVALID || (ISCOMPLEX && OP(*op)==ADJ) ) info = 2; else if(*n<0) info = 3; else if(*k<0) info = 4; else if(*lda() *= beta; } + if(*n==0 || *k==0) + return 0; + #if ISCOMPLEX // FIXME add support for symmetric complex matrix if(UPLO(*uplo)==UP) @@ -369,8 +423,10 @@ int EIGEN_BLAS_FUNC(syrk)(char *uplo, char *op, int *n, int *k, RealScalar *palp matrix(c, *n, *n, *ldc).triangularView() += alpha * matrix(a,*k,*n,*lda).transpose() * matrix(a,*k,*n,*lda); } #else + internal::gemm_blocking_space blocking(*n,*n,*k,1,false); + int code = OP(*op) | (UPLO(*uplo) << 2); - func[code](*n, *k, a, *lda, a, *lda, c, *ldc, alpha); + func[code](*n, *k, a, *lda, a, *lda, c, *ldc, alpha, blocking); #endif return 0; @@ -378,17 +434,20 @@ int EIGEN_BLAS_FUNC(syrk)(char *uplo, char *op, int *n, int *k, RealScalar *palp // c = alpha*a*b' + alpha*b*a' + beta*c for op = 'N'or'n' // c = alpha*a'*b + alpha*b'*a + beta*c for op = 'T'or't' -int EIGEN_BLAS_FUNC(syr2k)(char *uplo, char *op, int *n, int *k, RealScalar *palpha, RealScalar *pa, int *lda, RealScalar *pb, int *ldb, RealScalar *pbeta, RealScalar *pc, int *ldc) +int EIGEN_BLAS_FUNC(syr2k)(const char *uplo, const char *op, const int *n, const int *k, const RealScalar *palpha, + const RealScalar *pa, const int *lda, const RealScalar *pb, const int *ldb, const RealScalar *pbeta, RealScalar *pc, const int *ldc) { - Scalar* a = reinterpret_cast(pa); - Scalar* b = reinterpret_cast(pb); + const Scalar* a = reinterpret_cast(pa); + const Scalar* b = reinterpret_cast(pb); Scalar* c = reinterpret_cast(pc); - Scalar alpha = *reinterpret_cast(palpha); - Scalar beta = *reinterpret_cast(pbeta); + Scalar alpha = *reinterpret_cast(palpha); + Scalar beta = *reinterpret_cast(pbeta); + +// std::cerr << "in syr2k " << *uplo << " " << *op << " " << *n << " " << *k << " " << alpha << " " << *lda << " " << *ldb << " " << beta << " " << *ldc << "\n"; int info = 0; if(UPLO(*uplo)==INVALID) info = 1; - else if(OP(*op)==INVALID) info = 2; + else if(OP(*op)==INVALID || (ISCOMPLEX && OP(*op)==ADJ) ) info = 2; else if(*n<0) info = 3; else if(*k<0) info = 4; else if(*lda(pa); - Scalar* b = reinterpret_cast(pb); + const Scalar* a = reinterpret_cast(pa); + const Scalar* b = reinterpret_cast(pb); Scalar* c = reinterpret_cast(pc); - Scalar alpha = *reinterpret_cast(palpha); - Scalar beta = *reinterpret_cast(pbeta); + Scalar alpha = *reinterpret_cast(palpha); + Scalar beta = *reinterpret_cast(pbeta); // std::cerr << "in hemm " << *side << " " << *uplo << " " << *m << " " << *n << " " << alpha << " " << *lda << " " << beta << " " << *ldc << "\n"; @@ -472,20 +532,23 @@ int EIGEN_BLAS_FUNC(hemm)(char *side, char *uplo, int *m, int *n, RealScalar *pa return 1; } + int size = (SIDE(*side)==LEFT) ? (*m) : (*n); + internal::gemm_blocking_space blocking(*m,*n,size,1,false); + if(SIDE(*side)==LEFT) { if(UPLO(*uplo)==UP) internal::product_selfadjoint_matrix - ::run(*m, *n, a, *lda, b, *ldb, c, *ldc, alpha); + ::run(*m, *n, a, *lda, b, *ldb, c, *ldc, alpha, blocking); else if(UPLO(*uplo)==LO) internal::product_selfadjoint_matrix - ::run(*m, *n, a, *lda, b, *ldb, c, *ldc, alpha); + ::run(*m, *n, a, *lda, b, *ldb, c, *ldc, alpha, blocking); else return 0; } else if(SIDE(*side)==RIGHT) { if(UPLO(*uplo)==UP) matrix(c,*m,*n,*ldc) += alpha * matrix(b,*m,*n,*ldb) * matrix(a,*n,*n,*lda).selfadjointView();/*internal::product_selfadjoint_matrix - ::run(*m, *n, b, *ldb, a, *lda, c, *ldc, alpha);*/ + ::run(*m, *n, b, *ldb, a, *lda, c, *ldc, alpha, blocking);*/ else if(UPLO(*uplo)==LO) internal::product_selfadjoint_matrix - ::run(*m, *n, b, *ldb, a, *lda, c, *ldc, alpha); + ::run(*m, *n, b, *ldb, a, *lda, c, *ldc, alpha, blocking); else return 0; } else @@ -498,27 +561,28 @@ int EIGEN_BLAS_FUNC(hemm)(char *side, char *uplo, int *m, int *n, RealScalar *pa // c = alpha*a*conj(a') + beta*c for op = 'N'or'n' // c = alpha*conj(a')*a + beta*c for op = 'C'or'c' -int EIGEN_BLAS_FUNC(herk)(char *uplo, char *op, int *n, int *k, RealScalar *palpha, RealScalar *pa, int *lda, RealScalar *pbeta, RealScalar *pc, int *ldc) +int EIGEN_BLAS_FUNC(herk)(const char *uplo, const char *op, const int *n, const int *k, + const RealScalar *palpha, const RealScalar *pa, const int *lda, const RealScalar *pbeta, RealScalar *pc, const int *ldc) { - typedef void (*functype)(DenseIndex, DenseIndex, const Scalar *, DenseIndex, const Scalar *, DenseIndex, Scalar *, DenseIndex, const Scalar&); - static functype func[8]; - - static bool init = false; - if(!init) - { - for(int k=0; k<8; ++k) - func[k] = 0; - - func[NOTR | (UP << 2)] = (internal::general_matrix_matrix_triangular_product::run); - func[ADJ | (UP << 2)] = (internal::general_matrix_matrix_triangular_product::run); - - func[NOTR | (LO << 2)] = (internal::general_matrix_matrix_triangular_product::run); - func[ADJ | (LO << 2)] = (internal::general_matrix_matrix_triangular_product::run); - - init = true; - } - - Scalar* a = reinterpret_cast(pa); +// std::cerr << "in herk " << *uplo << " " << *op << " " << *n << " " << *k << " " << *palpha << " " << *lda << " " << *pbeta << " " << *ldc << "\n"; + + typedef void (*functype)(DenseIndex, DenseIndex, const Scalar *, DenseIndex, const Scalar *, DenseIndex, Scalar *, DenseIndex, const Scalar&, internal::level3_blocking&); + static const functype func[8] = { + // array index: NOTR | (UP << 2) + (internal::general_matrix_matrix_triangular_product::run), + 0, + // array index: ADJ | (UP << 2) + (internal::general_matrix_matrix_triangular_product::run), + 0, + // array index: NOTR | (LO << 2) + (internal::general_matrix_matrix_triangular_product::run), + 0, + // array index: ADJ | (LO << 2) + (internal::general_matrix_matrix_triangular_product::run), + 0 + }; + + const Scalar* a = reinterpret_cast(pa); Scalar* c = reinterpret_cast(pc); RealScalar alpha = *palpha; RealScalar beta = *pbeta; @@ -545,7 +609,7 @@ int EIGEN_BLAS_FUNC(herk)(char *uplo, char *op, int *n, int *k, RealScalar *palp else if(beta==Scalar(0)) matrix(c, *n, *n, *ldc).triangularView().setZero(); else matrix(c, *n, *n, *ldc).triangularView() *= beta; - + if(beta!=Scalar(0)) { matrix(c, *n, *n, *ldc).diagonal().real() *= beta; @@ -555,7 +619,8 @@ int EIGEN_BLAS_FUNC(herk)(char *uplo, char *op, int *n, int *k, RealScalar *palp if(*k>0 && alpha!=RealScalar(0)) { - func[code](*n, *k, a, *lda, a, *lda, c, *ldc, alpha); + internal::gemm_blocking_space blocking(*n,*n,*k,1,false); + func[code](*n, *k, a, *lda, a, *lda, c, *ldc, alpha, blocking); matrix(c, *n, *n, *ldc).diagonal().imag().setZero(); } return 0; @@ -563,21 +628,24 @@ int EIGEN_BLAS_FUNC(herk)(char *uplo, char *op, int *n, int *k, RealScalar *palp // c = alpha*a*conj(b') + conj(alpha)*b*conj(a') + beta*c, for op = 'N'or'n' // c = alpha*conj(a')*b + conj(alpha)*conj(b')*a + beta*c, for op = 'C'or'c' -int EIGEN_BLAS_FUNC(her2k)(char *uplo, char *op, int *n, int *k, RealScalar *palpha, RealScalar *pa, int *lda, RealScalar *pb, int *ldb, RealScalar *pbeta, RealScalar *pc, int *ldc) +int EIGEN_BLAS_FUNC(her2k)(const char *uplo, const char *op, const int *n, const int *k, + const RealScalar *palpha, const RealScalar *pa, const int *lda, const RealScalar *pb, const int *ldb, const RealScalar *pbeta, RealScalar *pc, const int *ldc) { - Scalar* a = reinterpret_cast(pa); - Scalar* b = reinterpret_cast(pb); + const Scalar* a = reinterpret_cast(pa); + const Scalar* b = reinterpret_cast(pb); Scalar* c = reinterpret_cast(pc); - Scalar alpha = *reinterpret_cast(palpha); + Scalar alpha = *reinterpret_cast(palpha); RealScalar beta = *pbeta; +// std::cerr << "in her2k " << *uplo << " " << *op << " " << *n << " " << *k << " " << alpha << " " << *lda << " " << *ldb << " " << beta << " " << *ldc << "\n"; + int info = 0; if(UPLO(*uplo)==INVALID) info = 1; else if((OP(*op)==INVALID) || (OP(*op)==TR)) info = 2; else if(*n<0) info = 3; else if(*k<0) info = 4; else if(*lda \brief \b CBLAT1 +* +* =========== DOCUMENTATION =========== +* +* Online html documentation available at +* http://www.netlib.org/lapack/explore-html/ +* +* Definition: +* =========== +* +* PROGRAM CBLAT1 +* +* +*> \par Purpose: +* ============= +*> +*> \verbatim +*> +*> Test program for the COMPLEX Level 1 BLAS. +*> Based upon the original BLAS test routine together with: +*> +*> F06GAF Example Program Text +*> \endverbatim +* +* Authors: +* ======== +* +*> \author Univ. of Tennessee +*> \author Univ. of California Berkeley +*> \author Univ. of Colorado Denver +*> \author NAG Ltd. +* +*> \date April 2012 +* +*> \ingroup complex_blas_testing +* +* ===================================================================== PROGRAM CBLAT1 -* Test program for the COMPLEX Level 1 BLAS. -* Based upon the original BLAS test routine together with: -* F06GAF Example Program Text +* +* -- Reference BLAS test routine (version 3.4.1) -- +* -- Reference BLAS is a software package provided by Univ. of Tennessee, -- +* -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- +* April 2012 +* +* ===================================================================== +* * .. Parameters .. INTEGER NOUT PARAMETER (NOUT=6) @@ -114,8 +156,8 @@ SUBROUTINE CHECK1(SFAC) + (5.0E0,6.0E0), (5.0E0,6.0E0), (0.1E0,0.1E0), + (-0.6E0,0.1E0), (0.1E0,-0.3E0), (7.0E0,8.0E0), + (7.0E0,8.0E0), (7.0E0,8.0E0), (7.0E0,8.0E0), - + (7.0E0,8.0E0), (0.3E0,0.1E0), (0.1E0,0.4E0), - + (0.4E0,0.1E0), (0.1E0,0.2E0), (2.0E0,3.0E0), + + (7.0E0,8.0E0), (0.3E0,0.1E0), (0.5E0,0.0E0), + + (0.0E0,0.5E0), (0.0E0,0.2E0), (2.0E0,3.0E0), + (2.0E0,3.0E0), (2.0E0,3.0E0), (2.0E0,3.0E0)/ DATA ((CV(I,J,2),I=1,8),J=1,5)/(0.1E0,0.1E0), + (4.0E0,5.0E0), (4.0E0,5.0E0), (4.0E0,5.0E0), @@ -129,10 +171,10 @@ SUBROUTINE CHECK1(SFAC) + (3.0E0,6.0E0), (-0.6E0,0.1E0), (4.0E0,7.0E0), + (0.1E0,-0.3E0), (7.0E0,2.0E0), (7.0E0,2.0E0), + (7.0E0,2.0E0), (0.3E0,0.1E0), (5.0E0,8.0E0), - + (0.1E0,0.4E0), (6.0E0,9.0E0), (0.4E0,0.1E0), - + (8.0E0,3.0E0), (0.1E0,0.2E0), (9.0E0,4.0E0)/ - DATA STRUE2/0.0E0, 0.5E0, 0.6E0, 0.7E0, 0.7E0/ - DATA STRUE4/0.0E0, 0.7E0, 1.0E0, 1.3E0, 1.7E0/ + + (0.5E0,0.0E0), (6.0E0,9.0E0), (0.0E0,0.5E0), + + (8.0E0,3.0E0), (0.0E0,0.2E0), (9.0E0,4.0E0)/ + DATA STRUE2/0.0E0, 0.5E0, 0.6E0, 0.7E0, 0.8E0/ + DATA STRUE4/0.0E0, 0.7E0, 1.0E0, 1.3E0, 1.6E0/ DATA ((CTRUE5(I,J,1),I=1,8),J=1,5)/(0.1E0,0.1E0), + (1.0E0,2.0E0), (1.0E0,2.0E0), (1.0E0,2.0E0), + (1.0E0,2.0E0), (1.0E0,2.0E0), (1.0E0,2.0E0), @@ -145,8 +187,8 @@ SUBROUTINE CHECK1(SFAC) + (0.11E0,-0.03E0), (-0.17E0,0.46E0), + (-0.17E0,-0.19E0), (7.0E0,8.0E0), (7.0E0,8.0E0), + (7.0E0,8.0E0), (7.0E0,8.0E0), (7.0E0,8.0E0), - + (0.19E0,-0.17E0), (0.32E0,0.09E0), - + (0.23E0,-0.24E0), (0.18E0,0.01E0), + + (0.19E0,-0.17E0), (0.20E0,-0.35E0), + + (0.35E0,0.20E0), (0.14E0,0.08E0), + (2.0E0,3.0E0), (2.0E0,3.0E0), (2.0E0,3.0E0), + (2.0E0,3.0E0)/ DATA ((CTRUE5(I,J,2),I=1,8),J=1,5)/(0.1E0,0.1E0), @@ -162,9 +204,9 @@ SUBROUTINE CHECK1(SFAC) + (-0.17E0,0.46E0), (4.0E0,7.0E0), + (-0.17E0,-0.19E0), (7.0E0,2.0E0), (7.0E0,2.0E0), + (7.0E0,2.0E0), (0.19E0,-0.17E0), (5.0E0,8.0E0), - + (0.32E0,0.09E0), (6.0E0,9.0E0), - + (0.23E0,-0.24E0), (8.0E0,3.0E0), - + (0.18E0,0.01E0), (9.0E0,4.0E0)/ + + (0.20E0,-0.35E0), (6.0E0,9.0E0), + + (0.35E0,0.20E0), (8.0E0,3.0E0), + + (0.14E0,0.08E0), (9.0E0,4.0E0)/ DATA ((CTRUE6(I,J,1),I=1,8),J=1,5)/(0.1E0,0.1E0), + (1.0E0,2.0E0), (1.0E0,2.0E0), (1.0E0,2.0E0), + (1.0E0,2.0E0), (1.0E0,2.0E0), (1.0E0,2.0E0), @@ -177,8 +219,8 @@ SUBROUTINE CHECK1(SFAC) + (0.03E0,0.03E0), (-0.18E0,0.03E0), + (0.03E0,-0.09E0), (7.0E0,8.0E0), (7.0E0,8.0E0), + (7.0E0,8.0E0), (7.0E0,8.0E0), (7.0E0,8.0E0), - + (0.09E0,0.03E0), (0.03E0,0.12E0), - + (0.12E0,0.03E0), (0.03E0,0.06E0), (2.0E0,3.0E0), + + (0.09E0,0.03E0), (0.15E0,0.00E0), + + (0.00E0,0.15E0), (0.00E0,0.06E0), (2.0E0,3.0E0), + (2.0E0,3.0E0), (2.0E0,3.0E0), (2.0E0,3.0E0)/ DATA ((CTRUE6(I,J,2),I=1,8),J=1,5)/(0.1E0,0.1E0), + (4.0E0,5.0E0), (4.0E0,5.0E0), (4.0E0,5.0E0), @@ -193,8 +235,8 @@ SUBROUTINE CHECK1(SFAC) + (-0.18E0,0.03E0), (4.0E0,7.0E0), + (0.03E0,-0.09E0), (7.0E0,2.0E0), (7.0E0,2.0E0), + (7.0E0,2.0E0), (0.09E0,0.03E0), (5.0E0,8.0E0), - + (0.03E0,0.12E0), (6.0E0,9.0E0), (0.12E0,0.03E0), - + (8.0E0,3.0E0), (0.03E0,0.06E0), (9.0E0,4.0E0)/ + + (0.15E0,0.00E0), (6.0E0,9.0E0), (0.00E0,0.15E0), + + (8.0E0,3.0E0), (0.00E0,0.06E0), (9.0E0,4.0E0)/ DATA ITRUE3/0, 1, 2, 2, 2/ * .. Executable Statements .. DO 60 INCX = 1, 2 @@ -529,7 +571,8 @@ SUBROUTINE STEST(LEN,SCOMP,STRUE,SSIZE,SFAC) * * .. Parameters .. INTEGER NOUT - PARAMETER (NOUT=6) + REAL ZERO + PARAMETER (NOUT=6, ZERO=0.0E0) * .. Scalar Arguments .. REAL SFAC INTEGER LEN @@ -552,7 +595,7 @@ SUBROUTINE STEST(LEN,SCOMP,STRUE,SSIZE,SFAC) * DO 40 I = 1, LEN SD = SCOMP(I) - STRUE(I) - IF (SDIFF(ABS(SSIZE(I))+ABS(SFAC*SD),ABS(SSIZE(I))).EQ.0.0E0) + IF (ABS(SFAC*SD) .LE. ABS(SSIZE(I))*EPSILON(ZERO)) + GO TO 40 * * HERE SCOMP(I) IS NOT CLOSE TO STRUE(I). diff --git a/ground/gcs/src/libs/eigen/blas/testing/cblat2.f b/ground/gcs/src/libs/eigen/blas/testing/cblat2.f index 20f1881005..5833ea81ae 100644 --- a/ground/gcs/src/libs/eigen/blas/testing/cblat2.f +++ b/ground/gcs/src/libs/eigen/blas/testing/cblat2.f @@ -1,68 +1,114 @@ +*> \brief \b CBLAT2 +* +* =========== DOCUMENTATION =========== +* +* Online html documentation available at +* http://www.netlib.org/lapack/explore-html/ +* +* Definition: +* =========== +* +* PROGRAM CBLAT2 +* +* +*> \par Purpose: +* ============= +*> +*> \verbatim +*> +*> Test program for the COMPLEX Level 2 Blas. +*> +*> The program must be driven by a short data file. The first 18 records +*> of the file are read using list-directed input, the last 17 records +*> are read using the format ( A6, L2 ). An annotated example of a data +*> file can be obtained by deleting the first 3 characters from the +*> following 35 lines: +*> 'cblat2.out' NAME OF SUMMARY OUTPUT FILE +*> 6 UNIT NUMBER OF SUMMARY FILE +*> 'CBLA2T.SNAP' NAME OF SNAPSHOT OUTPUT FILE +*> -1 UNIT NUMBER OF SNAPSHOT FILE (NOT USED IF .LT. 0) +*> F LOGICAL FLAG, T TO REWIND SNAPSHOT FILE AFTER EACH RECORD. +*> F LOGICAL FLAG, T TO STOP ON FAILURES. +*> T LOGICAL FLAG, T TO TEST ERROR EXITS. +*> 16.0 THRESHOLD VALUE OF TEST RATIO +*> 6 NUMBER OF VALUES OF N +*> 0 1 2 3 5 9 VALUES OF N +*> 4 NUMBER OF VALUES OF K +*> 0 1 2 4 VALUES OF K +*> 4 NUMBER OF VALUES OF INCX AND INCY +*> 1 2 -1 -2 VALUES OF INCX AND INCY +*> 3 NUMBER OF VALUES OF ALPHA +*> (0.0,0.0) (1.0,0.0) (0.7,-0.9) VALUES OF ALPHA +*> 3 NUMBER OF VALUES OF BETA +*> (0.0,0.0) (1.0,0.0) (1.3,-1.1) VALUES OF BETA +*> CGEMV T PUT F FOR NO TEST. SAME COLUMNS. +*> CGBMV T PUT F FOR NO TEST. SAME COLUMNS. +*> CHEMV T PUT F FOR NO TEST. SAME COLUMNS. +*> CHBMV T PUT F FOR NO TEST. SAME COLUMNS. +*> CHPMV T PUT F FOR NO TEST. SAME COLUMNS. +*> CTRMV T PUT F FOR NO TEST. SAME COLUMNS. +*> CTBMV T PUT F FOR NO TEST. SAME COLUMNS. +*> CTPMV T PUT F FOR NO TEST. SAME COLUMNS. +*> CTRSV T PUT F FOR NO TEST. SAME COLUMNS. +*> CTBSV T PUT F FOR NO TEST. SAME COLUMNS. +*> CTPSV T PUT F FOR NO TEST. SAME COLUMNS. +*> CGERC T PUT F FOR NO TEST. SAME COLUMNS. +*> CGERU T PUT F FOR NO TEST. SAME COLUMNS. +*> CHER T PUT F FOR NO TEST. SAME COLUMNS. +*> CHPR T PUT F FOR NO TEST. SAME COLUMNS. +*> CHER2 T PUT F FOR NO TEST. SAME COLUMNS. +*> CHPR2 T PUT F FOR NO TEST. SAME COLUMNS. +*> +*> Further Details +*> =============== +*> +*> See: +*> +*> Dongarra J. J., Du Croz J. J., Hammarling S. and Hanson R. J.. +*> An extended set of Fortran Basic Linear Algebra Subprograms. +*> +*> Technical Memoranda Nos. 41 (revision 3) and 81, Mathematics +*> and Computer Science Division, Argonne National Laboratory, +*> 9700 South Cass Avenue, Argonne, Illinois 60439, US. +*> +*> Or +*> +*> NAG Technical Reports TR3/87 and TR4/87, Numerical Algorithms +*> Group Ltd., NAG Central Office, 256 Banbury Road, Oxford +*> OX2 7DE, UK, and Numerical Algorithms Group Inc., 1101 31st +*> Street, Suite 100, Downers Grove, Illinois 60515-1263, USA. +*> +*> +*> -- Written on 10-August-1987. +*> Richard Hanson, Sandia National Labs. +*> Jeremy Du Croz, NAG Central Office. +*> +*> 10-9-00: Change STATUS='NEW' to 'UNKNOWN' so that the testers +*> can be run multiple times without deleting generated +*> output files (susan) +*> \endverbatim +* +* Authors: +* ======== +* +*> \author Univ. of Tennessee +*> \author Univ. of California Berkeley +*> \author Univ. of Colorado Denver +*> \author NAG Ltd. +* +*> \date April 2012 +* +*> \ingroup complex_blas_testing +* +* ===================================================================== PROGRAM CBLAT2 * -* Test program for the COMPLEX Level 2 Blas. -* -* The program must be driven by a short data file. The first 18 records -* of the file are read using list-directed input, the last 17 records -* are read using the format ( A6, L2 ). An annotated example of a data -* file can be obtained by deleting the first 3 characters from the -* following 35 lines: -* 'CBLAT2.SUMM' NAME OF SUMMARY OUTPUT FILE -* 6 UNIT NUMBER OF SUMMARY FILE -* 'CBLA2T.SNAP' NAME OF SNAPSHOT OUTPUT FILE -* -1 UNIT NUMBER OF SNAPSHOT FILE (NOT USED IF .LT. 0) -* F LOGICAL FLAG, T TO REWIND SNAPSHOT FILE AFTER EACH RECORD. -* F LOGICAL FLAG, T TO STOP ON FAILURES. -* T LOGICAL FLAG, T TO TEST ERROR EXITS. -* 16.0 THRESHOLD VALUE OF TEST RATIO -* 6 NUMBER OF VALUES OF N -* 0 1 2 3 5 9 VALUES OF N -* 4 NUMBER OF VALUES OF K -* 0 1 2 4 VALUES OF K -* 4 NUMBER OF VALUES OF INCX AND INCY -* 1 2 -1 -2 VALUES OF INCX AND INCY -* 3 NUMBER OF VALUES OF ALPHA -* (0.0,0.0) (1.0,0.0) (0.7,-0.9) VALUES OF ALPHA -* 3 NUMBER OF VALUES OF BETA -* (0.0,0.0) (1.0,0.0) (1.3,-1.1) VALUES OF BETA -* CGEMV T PUT F FOR NO TEST. SAME COLUMNS. -* CGBMV T PUT F FOR NO TEST. SAME COLUMNS. -* CHEMV T PUT F FOR NO TEST. SAME COLUMNS. -* CHBMV T PUT F FOR NO TEST. SAME COLUMNS. -* CHPMV T PUT F FOR NO TEST. SAME COLUMNS. -* CTRMV T PUT F FOR NO TEST. SAME COLUMNS. -* CTBMV T PUT F FOR NO TEST. SAME COLUMNS. -* CTPMV T PUT F FOR NO TEST. SAME COLUMNS. -* CTRSV T PUT F FOR NO TEST. SAME COLUMNS. -* CTBSV T PUT F FOR NO TEST. SAME COLUMNS. -* CTPSV T PUT F FOR NO TEST. SAME COLUMNS. -* CGERC T PUT F FOR NO TEST. SAME COLUMNS. -* CGERU T PUT F FOR NO TEST. SAME COLUMNS. -* CHER T PUT F FOR NO TEST. SAME COLUMNS. -* CHPR T PUT F FOR NO TEST. SAME COLUMNS. -* CHER2 T PUT F FOR NO TEST. SAME COLUMNS. -* CHPR2 T PUT F FOR NO TEST. SAME COLUMNS. -* -* See: -* -* Dongarra J. J., Du Croz J. J., Hammarling S. and Hanson R. J.. -* An extended set of Fortran Basic Linear Algebra Subprograms. -* -* Technical Memoranda Nos. 41 (revision 3) and 81, Mathematics -* and Computer Science Division, Argonne National Laboratory, -* 9700 South Cass Avenue, Argonne, Illinois 60439, US. -* -* Or -* -* NAG Technical Reports TR3/87 and TR4/87, Numerical Algorithms -* Group Ltd., NAG Central Office, 256 Banbury Road, Oxford -* OX2 7DE, UK, and Numerical Algorithms Group Inc., 1101 31st -* Street, Suite 100, Downers Grove, Illinois 60515-1263, USA. +* -- Reference BLAS test routine (version 3.4.1) -- +* -- Reference BLAS is a software package provided by Univ. of Tennessee, -- +* -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- +* April 2012 * -* -* -- Written on 10-August-1987. -* Richard Hanson, Sandia National Labs. -* Jeremy Du Croz, NAG Central Office. +* ===================================================================== * * .. Parameters .. INTEGER NIN @@ -71,8 +117,8 @@ PROGRAM CBLAT2 PARAMETER ( NSUBS = 17 ) COMPLEX ZERO, ONE PARAMETER ( ZERO = ( 0.0, 0.0 ), ONE = ( 1.0, 0.0 ) ) - REAL RZERO, RHALF, RONE - PARAMETER ( RZERO = 0.0, RHALF = 0.5, RONE = 1.0 ) + REAL RZERO + PARAMETER ( RZERO = 0.0 ) INTEGER NMAX, INCMAX PARAMETER ( NMAX = 65, INCMAX = 2 ) INTEGER NINMAX, NIDMAX, NKBMAX, NALMAX, NBEMAX @@ -126,7 +172,7 @@ PROGRAM CBLAT2 * READ( NIN, FMT = * )SUMMRY READ( NIN, FMT = * )NOUT - OPEN( NOUT, FILE = SUMMRY, STATUS = 'NEW' ) + OPEN( NOUT, FILE = SUMMRY, STATUS = 'UNKNOWN' ) NOUTC = NOUT * * Read name and unit number for snapshot output file and open file. @@ -135,7 +181,7 @@ PROGRAM CBLAT2 READ( NIN, FMT = * )NTRA TRACE = NTRA.GE.0 IF( TRACE )THEN - OPEN( NTRA, FILE = SNAPS, STATUS = 'NEW' ) + OPEN( NTRA, FILE = SNAPS, STATUS = 'UNKNOWN' ) END IF * Read the flag that directs rewinding of the snapshot file. READ( NIN, FMT = * )REWI @@ -240,14 +286,7 @@ PROGRAM CBLAT2 * * Compute EPS (the machine precision). * - EPS = RONE - 90 CONTINUE - IF( SDIFF( RONE + EPS, RONE ).EQ.RZERO ) - $ GO TO 100 - EPS = RHALF*EPS - GO TO 90 - 100 CONTINUE - EPS = EPS + EPS + EPS = EPSILON(RZERO) WRITE( NOUT, FMT = 9998 )EPS * * Check the reliability of CMVCH using exact data. @@ -3079,7 +3118,6 @@ LOGICAL FUNCTION LCERES( TYPE, UPLO, M, N, AA, AS, LDA ) 50 CONTINUE END IF * - 60 CONTINUE LCERES = .TRUE. GO TO 80 70 CONTINUE diff --git a/ground/gcs/src/libs/eigen/blas/testing/cblat3.f b/ground/gcs/src/libs/eigen/blas/testing/cblat3.f index b26be91e6b..09f2cb9c5c 100644 --- a/ground/gcs/src/libs/eigen/blas/testing/cblat3.f +++ b/ground/gcs/src/libs/eigen/blas/testing/cblat3.f @@ -1,50 +1,96 @@ +*> \brief \b CBLAT3 +* +* =========== DOCUMENTATION =========== +* +* Online html documentation available at +* http://www.netlib.org/lapack/explore-html/ +* +* Definition: +* =========== +* +* PROGRAM CBLAT3 +* +* +*> \par Purpose: +* ============= +*> +*> \verbatim +*> +*> Test program for the COMPLEX Level 3 Blas. +*> +*> The program must be driven by a short data file. The first 14 records +*> of the file are read using list-directed input, the last 9 records +*> are read using the format ( A6, L2 ). An annotated example of a data +*> file can be obtained by deleting the first 3 characters from the +*> following 23 lines: +*> 'cblat3.out' NAME OF SUMMARY OUTPUT FILE +*> 6 UNIT NUMBER OF SUMMARY FILE +*> 'CBLAT3.SNAP' NAME OF SNAPSHOT OUTPUT FILE +*> -1 UNIT NUMBER OF SNAPSHOT FILE (NOT USED IF .LT. 0) +*> F LOGICAL FLAG, T TO REWIND SNAPSHOT FILE AFTER EACH RECORD. +*> F LOGICAL FLAG, T TO STOP ON FAILURES. +*> T LOGICAL FLAG, T TO TEST ERROR EXITS. +*> 16.0 THRESHOLD VALUE OF TEST RATIO +*> 6 NUMBER OF VALUES OF N +*> 0 1 2 3 5 9 VALUES OF N +*> 3 NUMBER OF VALUES OF ALPHA +*> (0.0,0.0) (1.0,0.0) (0.7,-0.9) VALUES OF ALPHA +*> 3 NUMBER OF VALUES OF BETA +*> (0.0,0.0) (1.0,0.0) (1.3,-1.1) VALUES OF BETA +*> CGEMM T PUT F FOR NO TEST. SAME COLUMNS. +*> CHEMM T PUT F FOR NO TEST. SAME COLUMNS. +*> CSYMM T PUT F FOR NO TEST. SAME COLUMNS. +*> CTRMM T PUT F FOR NO TEST. SAME COLUMNS. +*> CTRSM T PUT F FOR NO TEST. SAME COLUMNS. +*> CHERK T PUT F FOR NO TEST. SAME COLUMNS. +*> CSYRK T PUT F FOR NO TEST. SAME COLUMNS. +*> CHER2K T PUT F FOR NO TEST. SAME COLUMNS. +*> CSYR2K T PUT F FOR NO TEST. SAME COLUMNS. +*> +*> Further Details +*> =============== +*> +*> See: +*> +*> Dongarra J. J., Du Croz J. J., Duff I. S. and Hammarling S. +*> A Set of Level 3 Basic Linear Algebra Subprograms. +*> +*> Technical Memorandum No.88 (Revision 1), Mathematics and +*> Computer Science Division, Argonne National Laboratory, 9700 +*> South Cass Avenue, Argonne, Illinois 60439, US. +*> +*> -- Written on 8-February-1989. +*> Jack Dongarra, Argonne National Laboratory. +*> Iain Duff, AERE Harwell. +*> Jeremy Du Croz, Numerical Algorithms Group Ltd. +*> Sven Hammarling, Numerical Algorithms Group Ltd. +*> +*> 10-9-00: Change STATUS='NEW' to 'UNKNOWN' so that the testers +*> can be run multiple times without deleting generated +*> output files (susan) +*> \endverbatim +* +* Authors: +* ======== +* +*> \author Univ. of Tennessee +*> \author Univ. of California Berkeley +*> \author Univ. of Colorado Denver +*> \author NAG Ltd. +* +*> \date April 2012 +* +*> \ingroup complex_blas_testing +* +* ===================================================================== PROGRAM CBLAT3 * -* Test program for the COMPLEX Level 3 Blas. -* -* The program must be driven by a short data file. The first 14 records -* of the file are read using list-directed input, the last 9 records -* are read using the format ( A6, L2 ). An annotated example of a data -* file can be obtained by deleting the first 3 characters from the -* following 23 lines: -* 'CBLAT3.SUMM' NAME OF SUMMARY OUTPUT FILE -* 6 UNIT NUMBER OF SUMMARY FILE -* 'CBLAT3.SNAP' NAME OF SNAPSHOT OUTPUT FILE -* -1 UNIT NUMBER OF SNAPSHOT FILE (NOT USED IF .LT. 0) -* F LOGICAL FLAG, T TO REWIND SNAPSHOT FILE AFTER EACH RECORD. -* F LOGICAL FLAG, T TO STOP ON FAILURES. -* T LOGICAL FLAG, T TO TEST ERROR EXITS. -* 16.0 THRESHOLD VALUE OF TEST RATIO -* 6 NUMBER OF VALUES OF N -* 0 1 2 3 5 9 VALUES OF N -* 3 NUMBER OF VALUES OF ALPHA -* (0.0,0.0) (1.0,0.0) (0.7,-0.9) VALUES OF ALPHA -* 3 NUMBER OF VALUES OF BETA -* (0.0,0.0) (1.0,0.0) (1.3,-1.1) VALUES OF BETA -* CGEMM T PUT F FOR NO TEST. SAME COLUMNS. -* CHEMM T PUT F FOR NO TEST. SAME COLUMNS. -* CSYMM T PUT F FOR NO TEST. SAME COLUMNS. -* CTRMM T PUT F FOR NO TEST. SAME COLUMNS. -* CTRSM T PUT F FOR NO TEST. SAME COLUMNS. -* CHERK T PUT F FOR NO TEST. SAME COLUMNS. -* CSYRK T PUT F FOR NO TEST. SAME COLUMNS. -* CHER2K T PUT F FOR NO TEST. SAME COLUMNS. -* CSYR2K T PUT F FOR NO TEST. SAME COLUMNS. -* -* See: -* -* Dongarra J. J., Du Croz J. J., Duff I. S. and Hammarling S. -* A Set of Level 3 Basic Linear Algebra Subprograms. -* -* Technical Memorandum No.88 (Revision 1), Mathematics and -* Computer Science Division, Argonne National Laboratory, 9700 -* South Cass Avenue, Argonne, Illinois 60439, US. +* -- Reference BLAS test routine (version 3.4.1) -- +* -- Reference BLAS is a software package provided by Univ. of Tennessee, -- +* -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- +* April 2012 * -* -- Written on 8-February-1989. -* Jack Dongarra, Argonne National Laboratory. -* Iain Duff, AERE Harwell. -* Jeremy Du Croz, Numerical Algorithms Group Ltd. -* Sven Hammarling, Numerical Algorithms Group Ltd. +* ===================================================================== * * .. Parameters .. INTEGER NIN @@ -53,8 +99,8 @@ PROGRAM CBLAT3 PARAMETER ( NSUBS = 9 ) COMPLEX ZERO, ONE PARAMETER ( ZERO = ( 0.0, 0.0 ), ONE = ( 1.0, 0.0 ) ) - REAL RZERO, RHALF, RONE - PARAMETER ( RZERO = 0.0, RHALF = 0.5, RONE = 1.0 ) + REAL RZERO + PARAMETER ( RZERO = 0.0 ) INTEGER NMAX PARAMETER ( NMAX = 65 ) INTEGER NIDMAX, NALMAX, NBEMAX @@ -103,7 +149,7 @@ PROGRAM CBLAT3 * READ( NIN, FMT = * )SUMMRY READ( NIN, FMT = * )NOUT - OPEN( NOUT, FILE = SUMMRY, STATUS = 'NEW' ) + OPEN( NOUT, FILE = SUMMRY ) NOUTC = NOUT * * Read name and unit number for snapshot output file and open file. @@ -112,7 +158,7 @@ PROGRAM CBLAT3 READ( NIN, FMT = * )NTRA TRACE = NTRA.GE.0 IF( TRACE )THEN - OPEN( NTRA, FILE = SNAPS, STATUS = 'NEW' ) + OPEN( NTRA, FILE = SNAPS ) END IF * Read the flag that directs rewinding of the snapshot file. READ( NIN, FMT = * )REWI @@ -189,14 +235,7 @@ PROGRAM CBLAT3 * * Compute EPS (the machine precision). * - EPS = RONE - 70 CONTINUE - IF( SDIFF( RONE + EPS, RONE ).EQ.RZERO ) - $ GO TO 80 - EPS = RHALF*EPS - GO TO 70 - 80 CONTINUE - EPS = EPS + EPS + EPS = EPSILON(RZERO) WRITE( NOUT, FMT = 9998 )EPS * * Check the reliability of CMMCH using exact data. @@ -1946,7 +1985,7 @@ SUBROUTINE CCHKE( ISNUM, SRNAMT, NOUT ) * * Tests the error exits from the Level 3 Blas. * Requires a special version of the error-handling routine XERBLA. -* ALPHA, RALPHA, BETA, RBETA, A, B and C should not need to be defined. +* A, B and C should not need to be defined. * * Auxiliary routine for test program for Level 3 Blas. * @@ -1956,12 +1995,19 @@ SUBROUTINE CCHKE( ISNUM, SRNAMT, NOUT ) * Jeremy Du Croz, Numerical Algorithms Group Ltd. * Sven Hammarling, Numerical Algorithms Group Ltd. * +* 3-19-92: Initialize ALPHA, BETA, RALPHA, and RBETA (eca) +* 3-19-92: Fix argument 12 in calls to CSYMM and CHEMM +* with INFOT = 9 (eca) +* * .. Scalar Arguments .. INTEGER ISNUM, NOUT CHARACTER*6 SRNAMT * .. Scalars in Common .. INTEGER INFOT, NOUTC LOGICAL LERR, OK +* .. Parameters .. + REAL ONE, TWO + PARAMETER ( ONE = 1.0E0, TWO = 2.0E0 ) * .. Local Scalars .. COMPLEX ALPHA, BETA REAL RALPHA, RBETA @@ -1979,6 +2025,14 @@ SUBROUTINE CCHKE( ISNUM, SRNAMT, NOUT ) * LERR is set to .TRUE. by the special version of XERBLA each time * it is called, and is then tested and re-set by CHKXER. LERR = .FALSE. +* +* Initialize ALPHA, BETA, RALPHA, and RBETA. +* + ALPHA = CMPLX( ONE, -ONE ) + BETA = CMPLX( TWO, -TWO ) + RALPHA = ONE + RBETA = TWO +* GO TO ( 10, 20, 30, 40, 50, 60, 70, 80, $ 90 )ISNUM 10 INFOT = 1 @@ -2205,16 +2259,16 @@ SUBROUTINE CCHKE( ISNUM, SRNAMT, NOUT ) CALL CHEMM( 'R', 'L', 0, 2, ALPHA, A, 1, B, 1, BETA, C, 1 ) CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK ) INFOT = 9 - CALL CHEMM( 'L', 'U', 2, 0, ALPHA, A, 2, B, 1, BETA, C, 1 ) + CALL CHEMM( 'L', 'U', 2, 0, ALPHA, A, 2, B, 1, BETA, C, 2 ) CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK ) INFOT = 9 - CALL CHEMM( 'R', 'U', 2, 0, ALPHA, A, 1, B, 1, BETA, C, 1 ) + CALL CHEMM( 'R', 'U', 2, 0, ALPHA, A, 1, B, 1, BETA, C, 2 ) CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK ) INFOT = 9 - CALL CHEMM( 'L', 'L', 2, 0, ALPHA, A, 2, B, 1, BETA, C, 1 ) + CALL CHEMM( 'L', 'L', 2, 0, ALPHA, A, 2, B, 1, BETA, C, 2 ) CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK ) INFOT = 9 - CALL CHEMM( 'R', 'L', 2, 0, ALPHA, A, 1, B, 1, BETA, C, 1 ) + CALL CHEMM( 'R', 'L', 2, 0, ALPHA, A, 1, B, 1, BETA, C, 2 ) CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK ) INFOT = 12 CALL CHEMM( 'L', 'U', 2, 0, ALPHA, A, 2, B, 2, BETA, C, 1 ) @@ -2272,16 +2326,16 @@ SUBROUTINE CCHKE( ISNUM, SRNAMT, NOUT ) CALL CSYMM( 'R', 'L', 0, 2, ALPHA, A, 1, B, 1, BETA, C, 1 ) CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK ) INFOT = 9 - CALL CSYMM( 'L', 'U', 2, 0, ALPHA, A, 2, B, 1, BETA, C, 1 ) + CALL CSYMM( 'L', 'U', 2, 0, ALPHA, A, 2, B, 1, BETA, C, 2 ) CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK ) INFOT = 9 - CALL CSYMM( 'R', 'U', 2, 0, ALPHA, A, 1, B, 1, BETA, C, 1 ) + CALL CSYMM( 'R', 'U', 2, 0, ALPHA, A, 1, B, 1, BETA, C, 2 ) CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK ) INFOT = 9 - CALL CSYMM( 'L', 'L', 2, 0, ALPHA, A, 2, B, 1, BETA, C, 1 ) + CALL CSYMM( 'L', 'L', 2, 0, ALPHA, A, 2, B, 1, BETA, C, 2 ) CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK ) INFOT = 9 - CALL CSYMM( 'R', 'L', 2, 0, ALPHA, A, 1, B, 1, BETA, C, 1 ) + CALL CSYMM( 'R', 'L', 2, 0, ALPHA, A, 1, B, 1, BETA, C, 2 ) CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK ) INFOT = 12 CALL CSYMM( 'L', 'U', 2, 0, ALPHA, A, 2, B, 2, BETA, C, 1 ) @@ -3268,7 +3322,6 @@ LOGICAL FUNCTION LCERES( TYPE, UPLO, M, N, AA, AS, LDA ) 50 CONTINUE END IF * - 60 CONTINUE LCERES = .TRUE. GO TO 80 70 CONTINUE diff --git a/ground/gcs/src/libs/eigen/blas/testing/dblat2.f b/ground/gcs/src/libs/eigen/blas/testing/dblat2.f index 4002d43689..0fa80afa4d 100644 --- a/ground/gcs/src/libs/eigen/blas/testing/dblat2.f +++ b/ground/gcs/src/libs/eigen/blas/testing/dblat2.f @@ -1,75 +1,121 @@ +*> \brief \b DBLAT2 +* +* =========== DOCUMENTATION =========== +* +* Online html documentation available at +* http://www.netlib.org/lapack/explore-html/ +* +* Definition: +* =========== +* +* PROGRAM DBLAT2 +* +* +*> \par Purpose: +* ============= +*> +*> \verbatim +*> +*> Test program for the DOUBLE PRECISION Level 2 Blas. +*> +*> The program must be driven by a short data file. The first 18 records +*> of the file are read using list-directed input, the last 16 records +*> are read using the format ( A6, L2 ). An annotated example of a data +*> file can be obtained by deleting the first 3 characters from the +*> following 34 lines: +*> 'dblat2.out' NAME OF SUMMARY OUTPUT FILE +*> 6 UNIT NUMBER OF SUMMARY FILE +*> 'DBLAT2.SNAP' NAME OF SNAPSHOT OUTPUT FILE +*> -1 UNIT NUMBER OF SNAPSHOT FILE (NOT USED IF .LT. 0) +*> F LOGICAL FLAG, T TO REWIND SNAPSHOT FILE AFTER EACH RECORD. +*> F LOGICAL FLAG, T TO STOP ON FAILURES. +*> T LOGICAL FLAG, T TO TEST ERROR EXITS. +*> 16.0 THRESHOLD VALUE OF TEST RATIO +*> 6 NUMBER OF VALUES OF N +*> 0 1 2 3 5 9 VALUES OF N +*> 4 NUMBER OF VALUES OF K +*> 0 1 2 4 VALUES OF K +*> 4 NUMBER OF VALUES OF INCX AND INCY +*> 1 2 -1 -2 VALUES OF INCX AND INCY +*> 3 NUMBER OF VALUES OF ALPHA +*> 0.0 1.0 0.7 VALUES OF ALPHA +*> 3 NUMBER OF VALUES OF BETA +*> 0.0 1.0 0.9 VALUES OF BETAC +*> DGEMV T PUT F FOR NO TEST. SAME COLUMNS. +*> DGBMV T PUT F FOR NO TEST. SAME COLUMNS. +*> DSYMV T PUT F FOR NO TEST. SAME COLUMNS. +*> DSBMV T PUT F FOR NO TEST. SAME COLUMNS. +*> DSPMV T PUT F FOR NO TEST. SAME COLUMNS. +*> DTRMV T PUT F FOR NO TEST. SAME COLUMNS. +*> DTBMV T PUT F FOR NO TEST. SAME COLUMNS. +*> DTPMV T PUT F FOR NO TEST. SAME COLUMNS. +*> DTRSV T PUT F FOR NO TEST. SAME COLUMNS. +*> DTBSV T PUT F FOR NO TEST. SAME COLUMNS. +*> DTPSV T PUT F FOR NO TEST. SAME COLUMNS. +*> DGER T PUT F FOR NO TEST. SAME COLUMNS. +*> DSYR T PUT F FOR NO TEST. SAME COLUMNS. +*> DSPR T PUT F FOR NO TEST. SAME COLUMNS. +*> DSYR2 T PUT F FOR NO TEST. SAME COLUMNS. +*> DSPR2 T PUT F FOR NO TEST. SAME COLUMNS. +*> +*> Further Details +*> =============== +*> +*> See: +*> +*> Dongarra J. J., Du Croz J. J., Hammarling S. and Hanson R. J.. +*> An extended set of Fortran Basic Linear Algebra Subprograms. +*> +*> Technical Memoranda Nos. 41 (revision 3) and 81, Mathematics +*> and Computer Science Division, Argonne National Laboratory, +*> 9700 South Cass Avenue, Argonne, Illinois 60439, US. +*> +*> Or +*> +*> NAG Technical Reports TR3/87 and TR4/87, Numerical Algorithms +*> Group Ltd., NAG Central Office, 256 Banbury Road, Oxford +*> OX2 7DE, UK, and Numerical Algorithms Group Inc., 1101 31st +*> Street, Suite 100, Downers Grove, Illinois 60515-1263, USA. +*> +*> +*> -- Written on 10-August-1987. +*> Richard Hanson, Sandia National Labs. +*> Jeremy Du Croz, NAG Central Office. +*> +*> 10-9-00: Change STATUS='NEW' to 'UNKNOWN' so that the testers +*> can be run multiple times without deleting generated +*> output files (susan) +*> \endverbatim +* +* Authors: +* ======== +* +*> \author Univ. of Tennessee +*> \author Univ. of California Berkeley +*> \author Univ. of Colorado Denver +*> \author NAG Ltd. +* +*> \date April 2012 +* +*> \ingroup double_blas_testing +* +* ===================================================================== PROGRAM DBLAT2 * -* Test program for the DOUBLE PRECISION Level 2 Blas. -* -* The program must be driven by a short data file. The first 18 records -* of the file are read using list-directed input, the last 16 records -* are read using the format ( A6, L2 ). An annotated example of a data -* file can be obtained by deleting the first 3 characters from the -* following 34 lines: -* 'DBLAT2.SUMM' NAME OF SUMMARY OUTPUT FILE -* 6 UNIT NUMBER OF SUMMARY FILE -* 'DBLAT2.SNAP' NAME OF SNAPSHOT OUTPUT FILE -* -1 UNIT NUMBER OF SNAPSHOT FILE (NOT USED IF .LT. 0) -* F LOGICAL FLAG, T TO REWIND SNAPSHOT FILE AFTER EACH RECORD. -* F LOGICAL FLAG, T TO STOP ON FAILURES. -* T LOGICAL FLAG, T TO TEST ERROR EXITS. -* 16.0 THRESHOLD VALUE OF TEST RATIO -* 6 NUMBER OF VALUES OF N -* 0 1 2 3 5 9 VALUES OF N -* 4 NUMBER OF VALUES OF K -* 0 1 2 4 VALUES OF K -* 4 NUMBER OF VALUES OF INCX AND INCY -* 1 2 -1 -2 VALUES OF INCX AND INCY -* 3 NUMBER OF VALUES OF ALPHA -* 0.0 1.0 0.7 VALUES OF ALPHA -* 3 NUMBER OF VALUES OF BETA -* 0.0 1.0 0.9 VALUES OF BETA -* DGEMV T PUT F FOR NO TEST. SAME COLUMNS. -* DGBMV T PUT F FOR NO TEST. SAME COLUMNS. -* DSYMV T PUT F FOR NO TEST. SAME COLUMNS. -* DSBMV T PUT F FOR NO TEST. SAME COLUMNS. -* DSPMV T PUT F FOR NO TEST. SAME COLUMNS. -* DTRMV T PUT F FOR NO TEST. SAME COLUMNS. -* DTBMV T PUT F FOR NO TEST. SAME COLUMNS. -* DTPMV T PUT F FOR NO TEST. SAME COLUMNS. -* DTRSV T PUT F FOR NO TEST. SAME COLUMNS. -* DTBSV T PUT F FOR NO TEST. SAME COLUMNS. -* DTPSV T PUT F FOR NO TEST. SAME COLUMNS. -* DGER T PUT F FOR NO TEST. SAME COLUMNS. -* DSYR T PUT F FOR NO TEST. SAME COLUMNS. -* DSPR T PUT F FOR NO TEST. SAME COLUMNS. -* DSYR2 T PUT F FOR NO TEST. SAME COLUMNS. -* DSPR2 T PUT F FOR NO TEST. SAME COLUMNS. -* -* See: -* -* Dongarra J. J., Du Croz J. J., Hammarling S. and Hanson R. J.. -* An extended set of Fortran Basic Linear Algebra Subprograms. -* -* Technical Memoranda Nos. 41 (revision 3) and 81, Mathematics -* and Computer Science Division, Argonne National Laboratory, -* 9700 South Cass Avenue, Argonne, Illinois 60439, US. -* -* Or -* -* NAG Technical Reports TR3/87 and TR4/87, Numerical Algorithms -* Group Ltd., NAG Central Office, 256 Banbury Road, Oxford -* OX2 7DE, UK, and Numerical Algorithms Group Inc., 1101 31st -* Street, Suite 100, Downers Grove, Illinois 60515-1263, USA. +* -- Reference BLAS test routine (version 3.4.1) -- +* -- Reference BLAS is a software package provided by Univ. of Tennessee, -- +* -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- +* April 2012 * -* -* -- Written on 10-August-1987. -* Richard Hanson, Sandia National Labs. -* Jeremy Du Croz, NAG Central Office. +* ===================================================================== * * .. Parameters .. INTEGER NIN PARAMETER ( NIN = 5 ) INTEGER NSUBS PARAMETER ( NSUBS = 16 ) - DOUBLE PRECISION ZERO, HALF, ONE - PARAMETER ( ZERO = 0.0D0, HALF = 0.5D0, ONE = 1.0D0 ) + DOUBLE PRECISION ZERO, ONE + PARAMETER ( ZERO = 0.0D0, ONE = 1.0D0 ) INTEGER NMAX, INCMAX PARAMETER ( NMAX = 65, INCMAX = 2 ) INTEGER NINMAX, NIDMAX, NKBMAX, NALMAX, NBEMAX @@ -121,7 +167,7 @@ PROGRAM DBLAT2 * READ( NIN, FMT = * )SUMMRY READ( NIN, FMT = * )NOUT - OPEN( NOUT, FILE = SUMMRY, STATUS = 'NEW' ) + OPEN( NOUT, FILE = SUMMRY, STATUS = 'UNKNOWN' ) NOUTC = NOUT * * Read name and unit number for snapshot output file and open file. @@ -130,7 +176,7 @@ PROGRAM DBLAT2 READ( NIN, FMT = * )NTRA TRACE = NTRA.GE.0 IF( TRACE )THEN - OPEN( NTRA, FILE = SNAPS, STATUS = 'NEW' ) + OPEN( NTRA, FILE = SNAPS, STATUS = 'UNKNOWN' ) END IF * Read the flag that directs rewinding of the snapshot file. READ( NIN, FMT = * )REWI @@ -235,14 +281,7 @@ PROGRAM DBLAT2 * * Compute EPS (the machine precision). * - EPS = ONE - 90 CONTINUE - IF( DDIFF( ONE + EPS, ONE ).EQ.ZERO ) - $ GO TO 100 - EPS = HALF*EPS - GO TO 90 - 100 CONTINUE - EPS = EPS + EPS + EPS = EPSILON(ZERO) WRITE( NOUT, FMT = 9998 )EPS * * Check the reliability of DMVCH using exact data. @@ -2982,7 +3021,6 @@ LOGICAL FUNCTION LDERES( TYPE, UPLO, M, N, AA, AS, LDA ) 50 CONTINUE END IF * - 60 CONTINUE LDERES = .TRUE. GO TO 80 70 CONTINUE diff --git a/ground/gcs/src/libs/eigen/blas/testing/dblat3.f b/ground/gcs/src/libs/eigen/blas/testing/dblat3.f index 082e03e5e2..8d37c74531 100644 --- a/ground/gcs/src/libs/eigen/blas/testing/dblat3.f +++ b/ground/gcs/src/libs/eigen/blas/testing/dblat3.f @@ -1,55 +1,101 @@ +*> \brief \b DBLAT3 +* +* =========== DOCUMENTATION =========== +* +* Online html documentation available at +* http://www.netlib.org/lapack/explore-html/ +* +* Definition: +* =========== +* +* PROGRAM DBLAT3 +* +* +*> \par Purpose: +* ============= +*> +*> \verbatim +*> +*> Test program for the DOUBLE PRECISION Level 3 Blas. +*> +*> The program must be driven by a short data file. The first 14 records +*> of the file are read using list-directed input, the last 6 records +*> are read using the format ( A6, L2 ). An annotated example of a data +*> file can be obtained by deleting the first 3 characters from the +*> following 20 lines: +*> 'dblat3.out' NAME OF SUMMARY OUTPUT FILE +*> 6 UNIT NUMBER OF SUMMARY FILE +*> 'DBLAT3.SNAP' NAME OF SNAPSHOT OUTPUT FILE +*> -1 UNIT NUMBER OF SNAPSHOT FILE (NOT USED IF .LT. 0) +*> F LOGICAL FLAG, T TO REWIND SNAPSHOT FILE AFTER EACH RECORD. +*> F LOGICAL FLAG, T TO STOP ON FAILURES. +*> T LOGICAL FLAG, T TO TEST ERROR EXITS. +*> 16.0 THRESHOLD VALUE OF TEST RATIO +*> 6 NUMBER OF VALUES OF N +*> 0 1 2 3 5 9 VALUES OF N +*> 3 NUMBER OF VALUES OF ALPHA +*> 0.0 1.0 0.7 VALUES OF ALPHA +*> 3 NUMBER OF VALUES OF BETA +*> 0.0 1.0 1.3 VALUES OF BETA +*> DGEMM T PUT F FOR NO TEST. SAME COLUMNS. +*> DSYMM T PUT F FOR NO TEST. SAME COLUMNS. +*> DTRMM T PUT F FOR NO TEST. SAME COLUMNS. +*> DTRSM T PUT F FOR NO TEST. SAME COLUMNS. +*> DSYRK T PUT F FOR NO TEST. SAME COLUMNS. +*> DSYR2K T PUT F FOR NO TEST. SAME COLUMNS. +*> +*> Further Details +*> =============== +*> +*> See: +*> +*> Dongarra J. J., Du Croz J. J., Duff I. S. and Hammarling S. +*> A Set of Level 3 Basic Linear Algebra Subprograms. +*> +*> Technical Memorandum No.88 (Revision 1), Mathematics and +*> Computer Science Division, Argonne National Laboratory, 9700 +*> South Cass Avenue, Argonne, Illinois 60439, US. +*> +*> -- Written on 8-February-1989. +*> Jack Dongarra, Argonne National Laboratory. +*> Iain Duff, AERE Harwell. +*> Jeremy Du Croz, Numerical Algorithms Group Ltd. +*> Sven Hammarling, Numerical Algorithms Group Ltd. +*> +*> 10-9-00: Change STATUS='NEW' to 'UNKNOWN' so that the testers +*> can be run multiple times without deleting generated +*> output files (susan) +*> \endverbatim +* +* Authors: +* ======== +* +*> \author Univ. of Tennessee +*> \author Univ. of California Berkeley +*> \author Univ. of Colorado Denver +*> \author NAG Ltd. +* +*> \date April 2012 +* +*> \ingroup double_blas_testing +* +* ===================================================================== PROGRAM DBLAT3 * -* Test program for the DOUBLE PRECISION Level 3 Blas. -* -* The program must be driven by a short data file. The first 14 records -* of the file are read using list-directed input, the last 6 records -* are read using the format ( A6, L2 ). An annotated example of a data -* file can be obtained by deleting the first 3 characters from the -* following 20 lines: -* 'DBLAT3.SUMM' NAME OF SUMMARY OUTPUT FILE -* 6 UNIT NUMBER OF SUMMARY FILE -* 'DBLAT3.SNAP' NAME OF SNAPSHOT OUTPUT FILE -* -1 UNIT NUMBER OF SNAPSHOT FILE (NOT USED IF .LT. 0) -* F LOGICAL FLAG, T TO REWIND SNAPSHOT FILE AFTER EACH RECORD. -* F LOGICAL FLAG, T TO STOP ON FAILURES. -* T LOGICAL FLAG, T TO TEST ERROR EXITS. -* 16.0 THRESHOLD VALUE OF TEST RATIO -* 6 NUMBER OF VALUES OF N -* 0 1 2 3 5 9 VALUES OF N -* 3 NUMBER OF VALUES OF ALPHA -* 0.0 1.0 0.7 VALUES OF ALPHA -* 3 NUMBER OF VALUES OF BETA -* 0.0 1.0 1.3 VALUES OF BETA -* DGEMM T PUT F FOR NO TEST. SAME COLUMNS. -* DSYMM T PUT F FOR NO TEST. SAME COLUMNS. -* DTRMM T PUT F FOR NO TEST. SAME COLUMNS. -* DTRSM T PUT F FOR NO TEST. SAME COLUMNS. -* DSYRK T PUT F FOR NO TEST. SAME COLUMNS. -* DSYR2K T PUT F FOR NO TEST. SAME COLUMNS. -* -* See: -* -* Dongarra J. J., Du Croz J. J., Duff I. S. and Hammarling S. -* A Set of Level 3 Basic Linear Algebra Subprograms. -* -* Technical Memorandum No.88 (Revision 1), Mathematics and -* Computer Science Division, Argonne National Laboratory, 9700 -* South Cass Avenue, Argonne, Illinois 60439, US. +* -- Reference BLAS test routine (version 3.4.1) -- +* -- Reference BLAS is a software package provided by Univ. of Tennessee, -- +* -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- +* April 2012 * -* -- Written on 8-February-1989. -* Jack Dongarra, Argonne National Laboratory. -* Iain Duff, AERE Harwell. -* Jeremy Du Croz, Numerical Algorithms Group Ltd. -* Sven Hammarling, Numerical Algorithms Group Ltd. +* ===================================================================== * * .. Parameters .. INTEGER NIN PARAMETER ( NIN = 5 ) INTEGER NSUBS PARAMETER ( NSUBS = 6 ) - DOUBLE PRECISION ZERO, HALF, ONE - PARAMETER ( ZERO = 0.0D0, HALF = 0.5D0, ONE = 1.0D0 ) + DOUBLE PRECISION ZERO, ONE + PARAMETER ( ZERO = 0.0D0, ONE = 1.0D0 ) INTEGER NMAX PARAMETER ( NMAX = 65 ) INTEGER NIDMAX, NALMAX, NBEMAX @@ -96,7 +142,7 @@ PROGRAM DBLAT3 * READ( NIN, FMT = * )SUMMRY READ( NIN, FMT = * )NOUT - OPEN( NOUT, FILE = SUMMRY, STATUS = 'NEW' ) + OPEN( NOUT, FILE = SUMMRY, STATUS = 'UNKNOWN' ) NOUTC = NOUT * * Read name and unit number for snapshot output file and open file. @@ -105,7 +151,7 @@ PROGRAM DBLAT3 READ( NIN, FMT = * )NTRA TRACE = NTRA.GE.0 IF( TRACE )THEN - OPEN( NTRA, FILE = SNAPS, STATUS = 'NEW' ) + OPEN( NTRA, FILE = SNAPS, STATUS = 'UNKNOWN' ) END IF * Read the flag that directs rewinding of the snapshot file. READ( NIN, FMT = * )REWI @@ -182,14 +228,7 @@ PROGRAM DBLAT3 * * Compute EPS (the machine precision). * - EPS = ONE - 70 CONTINUE - IF( DDIFF( ONE + EPS, ONE ).EQ.ZERO ) - $ GO TO 80 - EPS = HALF*EPS - GO TO 70 - 80 CONTINUE - EPS = EPS + EPS + EPS = EPSILON(ZERO) WRITE( NOUT, FMT = 9998 )EPS * * Check the reliability of DMMCH using exact data. @@ -1802,7 +1841,7 @@ SUBROUTINE DCHKE( ISNUM, SRNAMT, NOUT ) * * Tests the error exits from the Level 3 Blas. * Requires a special version of the error-handling routine XERBLA. -* ALPHA, BETA, A, B and C should not need to be defined. +* A, B and C should not need to be defined. * * Auxiliary routine for test program for Level 3 Blas. * @@ -1812,12 +1851,18 @@ SUBROUTINE DCHKE( ISNUM, SRNAMT, NOUT ) * Jeremy Du Croz, Numerical Algorithms Group Ltd. * Sven Hammarling, Numerical Algorithms Group Ltd. * +* 3-19-92: Initialize ALPHA and BETA (eca) +* 3-19-92: Fix argument 12 in calls to SSYMM with INFOT = 9 (eca) +* * .. Scalar Arguments .. INTEGER ISNUM, NOUT CHARACTER*6 SRNAMT * .. Scalars in Common .. INTEGER INFOT, NOUTC LOGICAL LERR, OK +* .. Parameters .. + DOUBLE PRECISION ONE, TWO + PARAMETER ( ONE = 1.0D0, TWO = 2.0D0 ) * .. Local Scalars .. DOUBLE PRECISION ALPHA, BETA * .. Local Arrays .. @@ -1834,6 +1879,12 @@ SUBROUTINE DCHKE( ISNUM, SRNAMT, NOUT ) * LERR is set to .TRUE. by the special version of XERBLA each time * it is called, and is then tested and re-set by CHKXER. LERR = .FALSE. +* +* Initialize ALPHA and BETA. +* + ALPHA = ONE + BETA = TWO +* GO TO ( 10, 20, 30, 40, 50, 60 )ISNUM 10 INFOT = 1 CALL DGEMM( '/', 'N', 0, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 ) @@ -1963,16 +2014,16 @@ SUBROUTINE DCHKE( ISNUM, SRNAMT, NOUT ) CALL DSYMM( 'R', 'L', 0, 2, ALPHA, A, 1, B, 1, BETA, C, 1 ) CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK ) INFOT = 9 - CALL DSYMM( 'L', 'U', 2, 0, ALPHA, A, 2, B, 1, BETA, C, 1 ) + CALL DSYMM( 'L', 'U', 2, 0, ALPHA, A, 2, B, 1, BETA, C, 2 ) CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK ) INFOT = 9 - CALL DSYMM( 'R', 'U', 2, 0, ALPHA, A, 1, B, 1, BETA, C, 1 ) + CALL DSYMM( 'R', 'U', 2, 0, ALPHA, A, 1, B, 1, BETA, C, 2 ) CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK ) INFOT = 9 - CALL DSYMM( 'L', 'L', 2, 0, ALPHA, A, 2, B, 1, BETA, C, 1 ) + CALL DSYMM( 'L', 'L', 2, 0, ALPHA, A, 2, B, 1, BETA, C, 2 ) CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK ) INFOT = 9 - CALL DSYMM( 'R', 'L', 2, 0, ALPHA, A, 1, B, 1, BETA, C, 1 ) + CALL DSYMM( 'R', 'L', 2, 0, ALPHA, A, 1, B, 1, BETA, C, 2 ) CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK ) INFOT = 12 CALL DSYMM( 'L', 'U', 2, 0, ALPHA, A, 2, B, 2, BETA, C, 1 ) @@ -2660,7 +2711,6 @@ LOGICAL FUNCTION LDERES( TYPE, UPLO, M, N, AA, AS, LDA ) 50 CONTINUE END IF * - 60 CONTINUE LDERES = .TRUE. GO TO 80 70 CONTINUE diff --git a/ground/gcs/src/libs/eigen/blas/testing/sblat2.f b/ground/gcs/src/libs/eigen/blas/testing/sblat2.f index 057a85429a..71605ed312 100644 --- a/ground/gcs/src/libs/eigen/blas/testing/sblat2.f +++ b/ground/gcs/src/libs/eigen/blas/testing/sblat2.f @@ -1,75 +1,121 @@ +*> \brief \b SBLAT2 +* +* =========== DOCUMENTATION =========== +* +* Online html documentation available at +* http://www.netlib.org/lapack/explore-html/ +* +* Definition: +* =========== +* +* PROGRAM SBLAT2 +* +* +*> \par Purpose: +* ============= +*> +*> \verbatim +*> +*> Test program for the REAL Level 2 Blas. +*> +*> The program must be driven by a short data file. The first 18 records +*> of the file are read using list-directed input, the last 16 records +*> are read using the format ( A6, L2 ). An annotated example of a data +*> file can be obtained by deleting the first 3 characters from the +*> following 34 lines: +*> 'sblat2.out' NAME OF SUMMARY OUTPUT FILE +*> 6 UNIT NUMBER OF SUMMARY FILE +*> 'SBLAT2.SNAP' NAME OF SNAPSHOT OUTPUT FILE +*> -1 UNIT NUMBER OF SNAPSHOT FILE (NOT USED IF .LT. 0) +*> F LOGICAL FLAG, T TO REWIND SNAPSHOT FILE AFTER EACH RECORD. +*> F LOGICAL FLAG, T TO STOP ON FAILURES. +*> T LOGICAL FLAG, T TO TEST ERROR EXITS. +*> 16.0 THRESHOLD VALUE OF TEST RATIO +*> 6 NUMBER OF VALUES OF N +*> 0 1 2 3 5 9 VALUES OF N +*> 4 NUMBER OF VALUES OF K +*> 0 1 2 4 VALUES OF K +*> 4 NUMBER OF VALUES OF INCX AND INCY +*> 1 2 -1 -2 VALUES OF INCX AND INCY +*> 3 NUMBER OF VALUES OF ALPHA +*> 0.0 1.0 0.7 VALUES OF ALPHA +*> 3 NUMBER OF VALUES OF BETA +*> 0.0 1.0 0.9 VALUES OF BETA +*> SGEMV T PUT F FOR NO TEST. SAME COLUMNS. +*> SGBMV T PUT F FOR NO TEST. SAME COLUMNS. +*> SSYMV T PUT F FOR NO TEST. SAME COLUMNS. +*> SSBMV T PUT F FOR NO TEST. SAME COLUMNS. +*> SSPMV T PUT F FOR NO TEST. SAME COLUMNS. +*> STRMV T PUT F FOR NO TEST. SAME COLUMNS. +*> STBMV T PUT F FOR NO TEST. SAME COLUMNS. +*> STPMV T PUT F FOR NO TEST. SAME COLUMNS. +*> STRSV T PUT F FOR NO TEST. SAME COLUMNS. +*> STBSV T PUT F FOR NO TEST. SAME COLUMNS. +*> STPSV T PUT F FOR NO TEST. SAME COLUMNS. +*> SGER T PUT F FOR NO TEST. SAME COLUMNS. +*> SSYR T PUT F FOR NO TEST. SAME COLUMNS. +*> SSPR T PUT F FOR NO TEST. SAME COLUMNS. +*> SSYR2 T PUT F FOR NO TEST. SAME COLUMNS. +*> SSPR2 T PUT F FOR NO TEST. SAME COLUMNS. +*> +*> Further Details +*> =============== +*> +*> See: +*> +*> Dongarra J. J., Du Croz J. J., Hammarling S. and Hanson R. J.. +*> An extended set of Fortran Basic Linear Algebra Subprograms. +*> +*> Technical Memoranda Nos. 41 (revision 3) and 81, Mathematics +*> and Computer Science Division, Argonne National Laboratory, +*> 9700 South Cass Avenue, Argonne, Illinois 60439, US. +*> +*> Or +*> +*> NAG Technical Reports TR3/87 and TR4/87, Numerical Algorithms +*> Group Ltd., NAG Central Office, 256 Banbury Road, Oxford +*> OX2 7DE, UK, and Numerical Algorithms Group Inc., 1101 31st +*> Street, Suite 100, Downers Grove, Illinois 60515-1263, USA. +*> +*> +*> -- Written on 10-August-1987. +*> Richard Hanson, Sandia National Labs. +*> Jeremy Du Croz, NAG Central Office. +*> +*> 10-9-00: Change STATUS='NEW' to 'UNKNOWN' so that the testers +*> can be run multiple times without deleting generated +*> output files (susan) +*> \endverbatim +* +* Authors: +* ======== +* +*> \author Univ. of Tennessee +*> \author Univ. of California Berkeley +*> \author Univ. of Colorado Denver +*> \author NAG Ltd. +* +*> \date April 2012 +* +*> \ingroup single_blas_testing +* +* ===================================================================== PROGRAM SBLAT2 * -* Test program for the REAL Level 2 Blas. -* -* The program must be driven by a short data file. The first 18 records -* of the file are read using list-directed input, the last 16 records -* are read using the format ( A6, L2 ). An annotated example of a data -* file can be obtained by deleting the first 3 characters from the -* following 34 lines: -* 'SBLAT2.SUMM' NAME OF SUMMARY OUTPUT FILE -* 6 UNIT NUMBER OF SUMMARY FILE -* 'SBLAT2.SNAP' NAME OF SNAPSHOT OUTPUT FILE -* -1 UNIT NUMBER OF SNAPSHOT FILE (NOT USED IF .LT. 0) -* F LOGICAL FLAG, T TO REWIND SNAPSHOT FILE AFTER EACH RECORD. -* F LOGICAL FLAG, T TO STOP ON FAILURES. -* T LOGICAL FLAG, T TO TEST ERROR EXITS. -* 16.0 THRESHOLD VALUE OF TEST RATIO -* 6 NUMBER OF VALUES OF N -* 0 1 2 3 5 9 VALUES OF N -* 4 NUMBER OF VALUES OF K -* 0 1 2 4 VALUES OF K -* 4 NUMBER OF VALUES OF INCX AND INCY -* 1 2 -1 -2 VALUES OF INCX AND INCY -* 3 NUMBER OF VALUES OF ALPHA -* 0.0 1.0 0.7 VALUES OF ALPHA -* 3 NUMBER OF VALUES OF BETA -* 0.0 1.0 0.9 VALUES OF BETA -* SGEMV T PUT F FOR NO TEST. SAME COLUMNS. -* SGBMV T PUT F FOR NO TEST. SAME COLUMNS. -* SSYMV T PUT F FOR NO TEST. SAME COLUMNS. -* SSBMV T PUT F FOR NO TEST. SAME COLUMNS. -* SSPMV T PUT F FOR NO TEST. SAME COLUMNS. -* STRMV T PUT F FOR NO TEST. SAME COLUMNS. -* STBMV T PUT F FOR NO TEST. SAME COLUMNS. -* STPMV T PUT F FOR NO TEST. SAME COLUMNS. -* STRSV T PUT F FOR NO TEST. SAME COLUMNS. -* STBSV T PUT F FOR NO TEST. SAME COLUMNS. -* STPSV T PUT F FOR NO TEST. SAME COLUMNS. -* SGER T PUT F FOR NO TEST. SAME COLUMNS. -* SSYR T PUT F FOR NO TEST. SAME COLUMNS. -* SSPR T PUT F FOR NO TEST. SAME COLUMNS. -* SSYR2 T PUT F FOR NO TEST. SAME COLUMNS. -* SSPR2 T PUT F FOR NO TEST. SAME COLUMNS. -* -* See: -* -* Dongarra J. J., Du Croz J. J., Hammarling S. and Hanson R. J.. -* An extended set of Fortran Basic Linear Algebra Subprograms. -* -* Technical Memoranda Nos. 41 (revision 3) and 81, Mathematics -* and Computer Science Division, Argonne National Laboratory, -* 9700 South Cass Avenue, Argonne, Illinois 60439, US. -* -* Or -* -* NAG Technical Reports TR3/87 and TR4/87, Numerical Algorithms -* Group Ltd., NAG Central Office, 256 Banbury Road, Oxford -* OX2 7DE, UK, and Numerical Algorithms Group Inc., 1101 31st -* Street, Suite 100, Downers Grove, Illinois 60515-1263, USA. +* -- Reference BLAS test routine (version 3.4.1) -- +* -- Reference BLAS is a software package provided by Univ. of Tennessee, -- +* -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- +* April 2012 * -* -* -- Written on 10-August-1987. -* Richard Hanson, Sandia National Labs. -* Jeremy Du Croz, NAG Central Office. +* ===================================================================== * * .. Parameters .. INTEGER NIN PARAMETER ( NIN = 5 ) INTEGER NSUBS PARAMETER ( NSUBS = 16 ) - REAL ZERO, HALF, ONE - PARAMETER ( ZERO = 0.0, HALF = 0.5, ONE = 1.0 ) + REAL ZERO, ONE + PARAMETER ( ZERO = 0.0, ONE = 1.0 ) INTEGER NMAX, INCMAX PARAMETER ( NMAX = 65, INCMAX = 2 ) INTEGER NINMAX, NIDMAX, NKBMAX, NALMAX, NBEMAX @@ -121,7 +167,7 @@ PROGRAM SBLAT2 * READ( NIN, FMT = * )SUMMRY READ( NIN, FMT = * )NOUT - OPEN( NOUT, FILE = SUMMRY, STATUS = 'NEW' ) + OPEN( NOUT, FILE = SUMMRY, STATUS = 'UNKNOWN' ) NOUTC = NOUT * * Read name and unit number for snapshot output file and open file. @@ -130,7 +176,7 @@ PROGRAM SBLAT2 READ( NIN, FMT = * )NTRA TRACE = NTRA.GE.0 IF( TRACE )THEN - OPEN( NTRA, FILE = SNAPS, STATUS = 'NEW' ) + OPEN( NTRA, FILE = SNAPS, STATUS = 'UNKNOWN' ) END IF * Read the flag that directs rewinding of the snapshot file. READ( NIN, FMT = * )REWI @@ -235,14 +281,7 @@ PROGRAM SBLAT2 * * Compute EPS (the machine precision). * - EPS = ONE - 90 CONTINUE - IF( SDIFF( ONE + EPS, ONE ).EQ.ZERO ) - $ GO TO 100 - EPS = HALF*EPS - GO TO 90 - 100 CONTINUE - EPS = EPS + EPS + EPS = EPSILON(ZERO) WRITE( NOUT, FMT = 9998 )EPS * * Check the reliability of SMVCH using exact data. @@ -2982,7 +3021,6 @@ LOGICAL FUNCTION LSERES( TYPE, UPLO, M, N, AA, AS, LDA ) 50 CONTINUE END IF * - 60 CONTINUE LSERES = .TRUE. GO TO 80 70 CONTINUE diff --git a/ground/gcs/src/libs/eigen/blas/testing/sblat3.f b/ground/gcs/src/libs/eigen/blas/testing/sblat3.f index 325a9eb927..8792696337 100644 --- a/ground/gcs/src/libs/eigen/blas/testing/sblat3.f +++ b/ground/gcs/src/libs/eigen/blas/testing/sblat3.f @@ -1,55 +1,101 @@ +*> \brief \b SBLAT3 +* +* =========== DOCUMENTATION =========== +* +* Online html documentation available at +* http://www.netlib.org/lapack/explore-html/ +* +* Definition: +* =========== +* +* PROGRAM SBLAT3 +* +* +*> \par Purpose: +* ============= +*> +*> \verbatim +*> +*> Test program for the REAL Level 3 Blas. +*> +*> The program must be driven by a short data file. The first 14 records +*> of the file are read using list-directed input, the last 6 records +*> are read using the format ( A6, L2 ). An annotated example of a data +*> file can be obtained by deleting the first 3 characters from the +*> following 20 lines: +*> 'sblat3.out' NAME OF SUMMARY OUTPUT FILE +*> 6 UNIT NUMBER OF SUMMARY FILE +*> 'SBLAT3.SNAP' NAME OF SNAPSHOT OUTPUT FILE +*> -1 UNIT NUMBER OF SNAPSHOT FILE (NOT USED IF .LT. 0) +*> F LOGICAL FLAG, T TO REWIND SNAPSHOT FILE AFTER EACH RECORD. +*> F LOGICAL FLAG, T TO STOP ON FAILURES. +*> T LOGICAL FLAG, T TO TEST ERROR EXITS. +*> 16.0 THRESHOLD VALUE OF TEST RATIO +*> 6 NUMBER OF VALUES OF N +*> 0 1 2 3 5 9 VALUES OF N +*> 3 NUMBER OF VALUES OF ALPHA +*> 0.0 1.0 0.7 VALUES OF ALPHA +*> 3 NUMBER OF VALUES OF BETA +*> 0.0 1.0 1.3 VALUES OF BETA +*> SGEMM T PUT F FOR NO TEST. SAME COLUMNS. +*> SSYMM T PUT F FOR NO TEST. SAME COLUMNS. +*> STRMM T PUT F FOR NO TEST. SAME COLUMNS. +*> STRSM T PUT F FOR NO TEST. SAME COLUMNS. +*> SSYRK T PUT F FOR NO TEST. SAME COLUMNS. +*> SSYR2K T PUT F FOR NO TEST. SAME COLUMNS. +*> +*> Further Details +*> =============== +*> +*> See: +*> +*> Dongarra J. J., Du Croz J. J., Duff I. S. and Hammarling S. +*> A Set of Level 3 Basic Linear Algebra Subprograms. +*> +*> Technical Memorandum No.88 (Revision 1), Mathematics and +*> Computer Science Division, Argonne National Laboratory, 9700 +*> South Cass Avenue, Argonne, Illinois 60439, US. +*> +*> -- Written on 8-February-1989. +*> Jack Dongarra, Argonne National Laboratory. +*> Iain Duff, AERE Harwell. +*> Jeremy Du Croz, Numerical Algorithms Group Ltd. +*> Sven Hammarling, Numerical Algorithms Group Ltd. +*> +*> 10-9-00: Change STATUS='NEW' to 'UNKNOWN' so that the testers +*> can be run multiple times without deleting generated +*> output files (susan) +*> \endverbatim +* +* Authors: +* ======== +* +*> \author Univ. of Tennessee +*> \author Univ. of California Berkeley +*> \author Univ. of Colorado Denver +*> \author NAG Ltd. +* +*> \date April 2012 +* +*> \ingroup single_blas_testing +* +* ===================================================================== PROGRAM SBLAT3 * -* Test program for the REAL Level 3 Blas. -* -* The program must be driven by a short data file. The first 14 records -* of the file are read using list-directed input, the last 6 records -* are read using the format ( A6, L2 ). An annotated example of a data -* file can be obtained by deleting the first 3 characters from the -* following 20 lines: -* 'SBLAT3.SUMM' NAME OF SUMMARY OUTPUT FILE -* 6 UNIT NUMBER OF SUMMARY FILE -* 'SBLAT3.SNAP' NAME OF SNAPSHOT OUTPUT FILE -* -1 UNIT NUMBER OF SNAPSHOT FILE (NOT USED IF .LT. 0) -* F LOGICAL FLAG, T TO REWIND SNAPSHOT FILE AFTER EACH RECORD. -* F LOGICAL FLAG, T TO STOP ON FAILURES. -* T LOGICAL FLAG, T TO TEST ERROR EXITS. -* 16.0 THRESHOLD VALUE OF TEST RATIO -* 6 NUMBER OF VALUES OF N -* 0 1 2 3 5 9 VALUES OF N -* 3 NUMBER OF VALUES OF ALPHA -* 0.0 1.0 0.7 VALUES OF ALPHA -* 3 NUMBER OF VALUES OF BETA -* 0.0 1.0 1.3 VALUES OF BETA -* SGEMM T PUT F FOR NO TEST. SAME COLUMNS. -* SSYMM T PUT F FOR NO TEST. SAME COLUMNS. -* STRMM T PUT F FOR NO TEST. SAME COLUMNS. -* STRSM T PUT F FOR NO TEST. SAME COLUMNS. -* SSYRK T PUT F FOR NO TEST. SAME COLUMNS. -* SSYR2K T PUT F FOR NO TEST. SAME COLUMNS. -* -* See: -* -* Dongarra J. J., Du Croz J. J., Duff I. S. and Hammarling S. -* A Set of Level 3 Basic Linear Algebra Subprograms. -* -* Technical Memorandum No.88 (Revision 1), Mathematics and -* Computer Science Division, Argonne National Laboratory, 9700 -* South Cass Avenue, Argonne, Illinois 60439, US. +* -- Reference BLAS test routine (version 3.4.1) -- +* -- Reference BLAS is a software package provided by Univ. of Tennessee, -- +* -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- +* April 2012 * -* -- Written on 8-February-1989. -* Jack Dongarra, Argonne National Laboratory. -* Iain Duff, AERE Harwell. -* Jeremy Du Croz, Numerical Algorithms Group Ltd. -* Sven Hammarling, Numerical Algorithms Group Ltd. +* ===================================================================== * * .. Parameters .. INTEGER NIN PARAMETER ( NIN = 5 ) INTEGER NSUBS PARAMETER ( NSUBS = 6 ) - REAL ZERO, HALF, ONE - PARAMETER ( ZERO = 0.0, HALF = 0.5, ONE = 1.0 ) + REAL ZERO, ONE + PARAMETER ( ZERO = 0.0, ONE = 1.0 ) INTEGER NMAX PARAMETER ( NMAX = 65 ) INTEGER NIDMAX, NALMAX, NBEMAX @@ -96,7 +142,7 @@ PROGRAM SBLAT3 * READ( NIN, FMT = * )SUMMRY READ( NIN, FMT = * )NOUT - OPEN( NOUT, FILE = SUMMRY, STATUS = 'NEW' ) + OPEN( NOUT, FILE = SUMMRY ) NOUTC = NOUT * * Read name and unit number for snapshot output file and open file. @@ -105,7 +151,7 @@ PROGRAM SBLAT3 READ( NIN, FMT = * )NTRA TRACE = NTRA.GE.0 IF( TRACE )THEN - OPEN( NTRA, FILE = SNAPS, STATUS = 'NEW' ) + OPEN( NTRA, FILE = SNAPS ) END IF * Read the flag that directs rewinding of the snapshot file. READ( NIN, FMT = * )REWI @@ -182,14 +228,7 @@ PROGRAM SBLAT3 * * Compute EPS (the machine precision). * - EPS = ONE - 70 CONTINUE - IF( SDIFF( ONE + EPS, ONE ).EQ.ZERO ) - $ GO TO 80 - EPS = HALF*EPS - GO TO 70 - 80 CONTINUE - EPS = EPS + EPS + EPS = EPSILON(ZERO) WRITE( NOUT, FMT = 9998 )EPS * * Check the reliability of SMMCH using exact data. @@ -1802,7 +1841,7 @@ SUBROUTINE SCHKE( ISNUM, SRNAMT, NOUT ) * * Tests the error exits from the Level 3 Blas. * Requires a special version of the error-handling routine XERBLA. -* ALPHA, BETA, A, B and C should not need to be defined. +* A, B and C should not need to be defined. * * Auxiliary routine for test program for Level 3 Blas. * @@ -1812,12 +1851,18 @@ SUBROUTINE SCHKE( ISNUM, SRNAMT, NOUT ) * Jeremy Du Croz, Numerical Algorithms Group Ltd. * Sven Hammarling, Numerical Algorithms Group Ltd. * +* 3-19-92: Initialize ALPHA and BETA (eca) +* 3-19-92: Fix argument 12 in calls to SSYMM with INFOT = 9 (eca) +* * .. Scalar Arguments .. INTEGER ISNUM, NOUT CHARACTER*6 SRNAMT * .. Scalars in Common .. INTEGER INFOT, NOUTC LOGICAL LERR, OK +* .. Parameters .. + REAL ONE, TWO + PARAMETER ( ONE = 1.0E0, TWO = 2.0E0 ) * .. Local Scalars .. REAL ALPHA, BETA * .. Local Arrays .. @@ -1834,6 +1879,12 @@ SUBROUTINE SCHKE( ISNUM, SRNAMT, NOUT ) * LERR is set to .TRUE. by the special version of XERBLA each time * it is called, and is then tested and re-set by CHKXER. LERR = .FALSE. +* +* Initialize ALPHA and BETA. +* + ALPHA = ONE + BETA = TWO +* GO TO ( 10, 20, 30, 40, 50, 60 )ISNUM 10 INFOT = 1 CALL SGEMM( '/', 'N', 0, 0, 0, ALPHA, A, 1, B, 1, BETA, C, 1 ) @@ -1963,16 +2014,16 @@ SUBROUTINE SCHKE( ISNUM, SRNAMT, NOUT ) CALL SSYMM( 'R', 'L', 0, 2, ALPHA, A, 1, B, 1, BETA, C, 1 ) CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK ) INFOT = 9 - CALL SSYMM( 'L', 'U', 2, 0, ALPHA, A, 2, B, 1, BETA, C, 1 ) + CALL SSYMM( 'L', 'U', 2, 0, ALPHA, A, 2, B, 1, BETA, C, 2 ) CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK ) INFOT = 9 - CALL SSYMM( 'R', 'U', 2, 0, ALPHA, A, 1, B, 1, BETA, C, 1 ) + CALL SSYMM( 'R', 'U', 2, 0, ALPHA, A, 1, B, 1, BETA, C, 2 ) CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK ) INFOT = 9 - CALL SSYMM( 'L', 'L', 2, 0, ALPHA, A, 2, B, 1, BETA, C, 1 ) + CALL SSYMM( 'L', 'L', 2, 0, ALPHA, A, 2, B, 1, BETA, C, 2 ) CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK ) INFOT = 9 - CALL SSYMM( 'R', 'L', 2, 0, ALPHA, A, 1, B, 1, BETA, C, 1 ) + CALL SSYMM( 'R', 'L', 2, 0, ALPHA, A, 1, B, 1, BETA, C, 2 ) CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK ) INFOT = 12 CALL SSYMM( 'L', 'U', 2, 0, ALPHA, A, 2, B, 2, BETA, C, 1 ) @@ -2660,7 +2711,6 @@ LOGICAL FUNCTION LSERES( TYPE, UPLO, M, N, AA, AS, LDA ) 50 CONTINUE END IF * - 60 CONTINUE LSERES = .TRUE. GO TO 80 70 CONTINUE diff --git a/ground/gcs/src/libs/eigen/blas/testing/zblat1.f b/ground/gcs/src/libs/eigen/blas/testing/zblat1.f index e2415e1c46..d30112c637 100644 --- a/ground/gcs/src/libs/eigen/blas/testing/zblat1.f +++ b/ground/gcs/src/libs/eigen/blas/testing/zblat1.f @@ -1,7 +1,49 @@ +*> \brief \b ZBLAT1 +* +* =========== DOCUMENTATION =========== +* +* Online html documentation available at +* http://www.netlib.org/lapack/explore-html/ +* +* Definition: +* =========== +* +* PROGRAM ZBLAT1 +* +* +*> \par Purpose: +* ============= +*> +*> \verbatim +*> +*> Test program for the COMPLEX*16 Level 1 BLAS. +*> +*> Based upon the original BLAS test routine together with: +*> F06GAF Example Program Text +*> \endverbatim +* +* Authors: +* ======== +* +*> \author Univ. of Tennessee +*> \author Univ. of California Berkeley +*> \author Univ. of Colorado Denver +*> \author NAG Ltd. +* +*> \date April 2012 +* +*> \ingroup complex16_blas_testing +* +* ===================================================================== PROGRAM ZBLAT1 -* Test program for the COMPLEX*16 Level 1 BLAS. -* Based upon the original BLAS test routine together with: -* F06GAF Example Program Text +* +* -- Reference BLAS test routine (version 3.4.1) -- +* -- Reference BLAS is a software package provided by Univ. of Tennessee, -- +* -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- +* April 2012 +* +* ===================================================================== +* * .. Parameters .. INTEGER NOUT PARAMETER (NOUT=6) @@ -114,8 +156,8 @@ SUBROUTINE CHECK1(SFAC) + (5.0D0,6.0D0), (5.0D0,6.0D0), (0.1D0,0.1D0), + (-0.6D0,0.1D0), (0.1D0,-0.3D0), (7.0D0,8.0D0), + (7.0D0,8.0D0), (7.0D0,8.0D0), (7.0D0,8.0D0), - + (7.0D0,8.0D0), (0.3D0,0.1D0), (0.1D0,0.4D0), - + (0.4D0,0.1D0), (0.1D0,0.2D0), (2.0D0,3.0D0), + + (7.0D0,8.0D0), (0.3D0,0.1D0), (0.5D0,0.0D0), + + (0.0D0,0.5D0), (0.0D0,0.2D0), (2.0D0,3.0D0), + (2.0D0,3.0D0), (2.0D0,3.0D0), (2.0D0,3.0D0)/ DATA ((CV(I,J,2),I=1,8),J=1,5)/(0.1D0,0.1D0), + (4.0D0,5.0D0), (4.0D0,5.0D0), (4.0D0,5.0D0), @@ -129,10 +171,10 @@ SUBROUTINE CHECK1(SFAC) + (3.0D0,6.0D0), (-0.6D0,0.1D0), (4.0D0,7.0D0), + (0.1D0,-0.3D0), (7.0D0,2.0D0), (7.0D0,2.0D0), + (7.0D0,2.0D0), (0.3D0,0.1D0), (5.0D0,8.0D0), - + (0.1D0,0.4D0), (6.0D0,9.0D0), (0.4D0,0.1D0), - + (8.0D0,3.0D0), (0.1D0,0.2D0), (9.0D0,4.0D0)/ - DATA STRUE2/0.0D0, 0.5D0, 0.6D0, 0.7D0, 0.7D0/ - DATA STRUE4/0.0D0, 0.7D0, 1.0D0, 1.3D0, 1.7D0/ + + (0.5D0,0.0D0), (6.0D0,9.0D0), (0.0D0,0.5D0), + + (8.0D0,3.0D0), (0.0D0,0.2D0), (9.0D0,4.0D0)/ + DATA STRUE2/0.0D0, 0.5D0, 0.6D0, 0.7D0, 0.8D0/ + DATA STRUE4/0.0D0, 0.7D0, 1.0D0, 1.3D0, 1.6D0/ DATA ((CTRUE5(I,J,1),I=1,8),J=1,5)/(0.1D0,0.1D0), + (1.0D0,2.0D0), (1.0D0,2.0D0), (1.0D0,2.0D0), + (1.0D0,2.0D0), (1.0D0,2.0D0), (1.0D0,2.0D0), @@ -145,8 +187,8 @@ SUBROUTINE CHECK1(SFAC) + (0.11D0,-0.03D0), (-0.17D0,0.46D0), + (-0.17D0,-0.19D0), (7.0D0,8.0D0), (7.0D0,8.0D0), + (7.0D0,8.0D0), (7.0D0,8.0D0), (7.0D0,8.0D0), - + (0.19D0,-0.17D0), (0.32D0,0.09D0), - + (0.23D0,-0.24D0), (0.18D0,0.01D0), + + (0.19D0,-0.17D0), (0.20D0,-0.35D0), + + (0.35D0,0.20D0), (0.14D0,0.08D0), + (2.0D0,3.0D0), (2.0D0,3.0D0), (2.0D0,3.0D0), + (2.0D0,3.0D0)/ DATA ((CTRUE5(I,J,2),I=1,8),J=1,5)/(0.1D0,0.1D0), @@ -162,9 +204,9 @@ SUBROUTINE CHECK1(SFAC) + (-0.17D0,0.46D0), (4.0D0,7.0D0), + (-0.17D0,-0.19D0), (7.0D0,2.0D0), (7.0D0,2.0D0), + (7.0D0,2.0D0), (0.19D0,-0.17D0), (5.0D0,8.0D0), - + (0.32D0,0.09D0), (6.0D0,9.0D0), - + (0.23D0,-0.24D0), (8.0D0,3.0D0), - + (0.18D0,0.01D0), (9.0D0,4.0D0)/ + + (0.20D0,-0.35D0), (6.0D0,9.0D0), + + (0.35D0,0.20D0), (8.0D0,3.0D0), + + (0.14D0,0.08D0), (9.0D0,4.0D0)/ DATA ((CTRUE6(I,J,1),I=1,8),J=1,5)/(0.1D0,0.1D0), + (1.0D0,2.0D0), (1.0D0,2.0D0), (1.0D0,2.0D0), + (1.0D0,2.0D0), (1.0D0,2.0D0), (1.0D0,2.0D0), @@ -177,8 +219,8 @@ SUBROUTINE CHECK1(SFAC) + (0.03D0,0.03D0), (-0.18D0,0.03D0), + (0.03D0,-0.09D0), (7.0D0,8.0D0), (7.0D0,8.0D0), + (7.0D0,8.0D0), (7.0D0,8.0D0), (7.0D0,8.0D0), - + (0.09D0,0.03D0), (0.03D0,0.12D0), - + (0.12D0,0.03D0), (0.03D0,0.06D0), (2.0D0,3.0D0), + + (0.09D0,0.03D0), (0.15D0,0.00D0), + + (0.00D0,0.15D0), (0.00D0,0.06D0), (2.0D0,3.0D0), + (2.0D0,3.0D0), (2.0D0,3.0D0), (2.0D0,3.0D0)/ DATA ((CTRUE6(I,J,2),I=1,8),J=1,5)/(0.1D0,0.1D0), + (4.0D0,5.0D0), (4.0D0,5.0D0), (4.0D0,5.0D0), @@ -193,8 +235,8 @@ SUBROUTINE CHECK1(SFAC) + (-0.18D0,0.03D0), (4.0D0,7.0D0), + (0.03D0,-0.09D0), (7.0D0,2.0D0), (7.0D0,2.0D0), + (7.0D0,2.0D0), (0.09D0,0.03D0), (5.0D0,8.0D0), - + (0.03D0,0.12D0), (6.0D0,9.0D0), (0.12D0,0.03D0), - + (8.0D0,3.0D0), (0.03D0,0.06D0), (9.0D0,4.0D0)/ + + (0.15D0,0.00D0), (6.0D0,9.0D0), (0.00D0,0.15D0), + + (8.0D0,3.0D0), (0.00D0,0.06D0), (9.0D0,4.0D0)/ DATA ITRUE3/0, 1, 2, 2, 2/ * .. Executable Statements .. DO 60 INCX = 1, 2 @@ -529,7 +571,8 @@ SUBROUTINE STEST(LEN,SCOMP,STRUE,SSIZE,SFAC) * * .. Parameters .. INTEGER NOUT - PARAMETER (NOUT=6) + DOUBLE PRECISION ZERO + PARAMETER (NOUT=6, ZERO=0.0D0) * .. Scalar Arguments .. DOUBLE PRECISION SFAC INTEGER LEN @@ -552,7 +595,7 @@ SUBROUTINE STEST(LEN,SCOMP,STRUE,SSIZE,SFAC) * DO 40 I = 1, LEN SD = SCOMP(I) - STRUE(I) - IF (SDIFF(ABS(SSIZE(I))+ABS(SFAC*SD),ABS(SSIZE(I))).EQ.0.0D0) + IF (ABS(SFAC*SD) .LE. ABS(SSIZE(I))*EPSILON(ZERO)) + GO TO 40 * * HERE SCOMP(I) IS NOT CLOSE TO STRUE(I). diff --git a/ground/gcs/src/libs/eigen/blas/testing/zblat2.f b/ground/gcs/src/libs/eigen/blas/testing/zblat2.f index e65cdcc703..53129a11e9 100644 --- a/ground/gcs/src/libs/eigen/blas/testing/zblat2.f +++ b/ground/gcs/src/libs/eigen/blas/testing/zblat2.f @@ -1,68 +1,114 @@ +*> \brief \b ZBLAT2 +* +* =========== DOCUMENTATION =========== +* +* Online html documentation available at +* http://www.netlib.org/lapack/explore-html/ +* +* Definition: +* =========== +* +* PROGRAM ZBLAT2 +* +* +*> \par Purpose: +* ============= +*> +*> \verbatim +*> +*> Test program for the COMPLEX*16 Level 2 Blas. +*> +*> The program must be driven by a short data file. The first 18 records +*> of the file are read using list-directed input, the last 17 records +*> are read using the format ( A6, L2 ). An annotated example of a data +*> file can be obtained by deleting the first 3 characters from the +*> following 35 lines: +*> 'zblat2.out' NAME OF SUMMARY OUTPUT FILE +*> 6 UNIT NUMBER OF SUMMARY FILE +*> 'CBLA2T.SNAP' NAME OF SNAPSHOT OUTPUT FILE +*> -1 UNIT NUMBER OF SNAPSHOT FILE (NOT USED IF .LT. 0) +*> F LOGICAL FLAG, T TO REWIND SNAPSHOT FILE AFTER EACH RECORD. +*> F LOGICAL FLAG, T TO STOP ON FAILURES. +*> T LOGICAL FLAG, T TO TEST ERROR EXITS. +*> 16.0 THRESHOLD VALUE OF TEST RATIO +*> 6 NUMBER OF VALUES OF N +*> 0 1 2 3 5 9 VALUES OF N +*> 4 NUMBER OF VALUES OF K +*> 0 1 2 4 VALUES OF K +*> 4 NUMBER OF VALUES OF INCX AND INCY +*> 1 2 -1 -2 VALUES OF INCX AND INCY +*> 3 NUMBER OF VALUES OF ALPHA +*> (0.0,0.0) (1.0,0.0) (0.7,-0.9) VALUES OF ALPHA +*> 3 NUMBER OF VALUES OF BETA +*> (0.0,0.0) (1.0,0.0) (1.3,-1.1) VALUES OF BETA +*> ZGEMV T PUT F FOR NO TEST. SAME COLUMNS. +*> ZGBMV T PUT F FOR NO TEST. SAME COLUMNS. +*> ZHEMV T PUT F FOR NO TEST. SAME COLUMNS. +*> ZHBMV T PUT F FOR NO TEST. SAME COLUMNS. +*> ZHPMV T PUT F FOR NO TEST. SAME COLUMNS. +*> ZTRMV T PUT F FOR NO TEST. SAME COLUMNS. +*> ZTBMV T PUT F FOR NO TEST. SAME COLUMNS. +*> ZTPMV T PUT F FOR NO TEST. SAME COLUMNS. +*> ZTRSV T PUT F FOR NO TEST. SAME COLUMNS. +*> ZTBSV T PUT F FOR NO TEST. SAME COLUMNS. +*> ZTPSV T PUT F FOR NO TEST. SAME COLUMNS. +*> ZGERC T PUT F FOR NO TEST. SAME COLUMNS. +*> ZGERU T PUT F FOR NO TEST. SAME COLUMNS. +*> ZHER T PUT F FOR NO TEST. SAME COLUMNS. +*> ZHPR T PUT F FOR NO TEST. SAME COLUMNS. +*> ZHER2 T PUT F FOR NO TEST. SAME COLUMNS. +*> ZHPR2 T PUT F FOR NO TEST. SAME COLUMNS. +*> +*> Further Details +*> =============== +*> +*> See: +*> +*> Dongarra J. J., Du Croz J. J., Hammarling S. and Hanson R. J.. +*> An extended set of Fortran Basic Linear Algebra Subprograms. +*> +*> Technical Memoranda Nos. 41 (revision 3) and 81, Mathematics +*> and Computer Science Division, Argonne National Laboratory, +*> 9700 South Cass Avenue, Argonne, Illinois 60439, US. +*> +*> Or +*> +*> NAG Technical Reports TR3/87 and TR4/87, Numerical Algorithms +*> Group Ltd., NAG Central Office, 256 Banbury Road, Oxford +*> OX2 7DE, UK, and Numerical Algorithms Group Inc., 1101 31st +*> Street, Suite 100, Downers Grove, Illinois 60515-1263, USA. +*> +*> +*> -- Written on 10-August-1987. +*> Richard Hanson, Sandia National Labs. +*> Jeremy Du Croz, NAG Central Office. +*> +*> 10-9-00: Change STATUS='NEW' to 'UNKNOWN' so that the testers +*> can be run multiple times without deleting generated +*> output files (susan) +*> \endverbatim +* +* Authors: +* ======== +* +*> \author Univ. of Tennessee +*> \author Univ. of California Berkeley +*> \author Univ. of Colorado Denver +*> \author NAG Ltd. +* +*> \date April 2012 +* +*> \ingroup complex16_blas_testing +* +* ===================================================================== PROGRAM ZBLAT2 * -* Test program for the COMPLEX*16 Level 2 Blas. -* -* The program must be driven by a short data file. The first 18 records -* of the file are read using list-directed input, the last 17 records -* are read using the format ( A6, L2 ). An annotated example of a data -* file can be obtained by deleting the first 3 characters from the -* following 35 lines: -* 'ZBLAT2.SUMM' NAME OF SUMMARY OUTPUT FILE -* 6 UNIT NUMBER OF SUMMARY FILE -* 'CBLA2T.SNAP' NAME OF SNAPSHOT OUTPUT FILE -* -1 UNIT NUMBER OF SNAPSHOT FILE (NOT USED IF .LT. 0) -* F LOGICAL FLAG, T TO REWIND SNAPSHOT FILE AFTER EACH RECORD. -* F LOGICAL FLAG, T TO STOP ON FAILURES. -* T LOGICAL FLAG, T TO TEST ERROR EXITS. -* 16.0 THRESHOLD VALUE OF TEST RATIO -* 6 NUMBER OF VALUES OF N -* 0 1 2 3 5 9 VALUES OF N -* 4 NUMBER OF VALUES OF K -* 0 1 2 4 VALUES OF K -* 4 NUMBER OF VALUES OF INCX AND INCY -* 1 2 -1 -2 VALUES OF INCX AND INCY -* 3 NUMBER OF VALUES OF ALPHA -* (0.0,0.0) (1.0,0.0) (0.7,-0.9) VALUES OF ALPHA -* 3 NUMBER OF VALUES OF BETA -* (0.0,0.0) (1.0,0.0) (1.3,-1.1) VALUES OF BETA -* ZGEMV T PUT F FOR NO TEST. SAME COLUMNS. -* ZGBMV T PUT F FOR NO TEST. SAME COLUMNS. -* ZHEMV T PUT F FOR NO TEST. SAME COLUMNS. -* ZHBMV T PUT F FOR NO TEST. SAME COLUMNS. -* ZHPMV T PUT F FOR NO TEST. SAME COLUMNS. -* ZTRMV T PUT F FOR NO TEST. SAME COLUMNS. -* ZTBMV T PUT F FOR NO TEST. SAME COLUMNS. -* ZTPMV T PUT F FOR NO TEST. SAME COLUMNS. -* ZTRSV T PUT F FOR NO TEST. SAME COLUMNS. -* ZTBSV T PUT F FOR NO TEST. SAME COLUMNS. -* ZTPSV T PUT F FOR NO TEST. SAME COLUMNS. -* ZGERC T PUT F FOR NO TEST. SAME COLUMNS. -* ZGERU T PUT F FOR NO TEST. SAME COLUMNS. -* ZHER T PUT F FOR NO TEST. SAME COLUMNS. -* ZHPR T PUT F FOR NO TEST. SAME COLUMNS. -* ZHER2 T PUT F FOR NO TEST. SAME COLUMNS. -* ZHPR2 T PUT F FOR NO TEST. SAME COLUMNS. -* -* See: -* -* Dongarra J. J., Du Croz J. J., Hammarling S. and Hanson R. J.. -* An extended set of Fortran Basic Linear Algebra Subprograms. -* -* Technical Memoranda Nos. 41 (revision 3) and 81, Mathematics -* and Computer Science Division, Argonne National Laboratory, -* 9700 South Cass Avenue, Argonne, Illinois 60439, US. -* -* Or -* -* NAG Technical Reports TR3/87 and TR4/87, Numerical Algorithms -* Group Ltd., NAG Central Office, 256 Banbury Road, Oxford -* OX2 7DE, UK, and Numerical Algorithms Group Inc., 1101 31st -* Street, Suite 100, Downers Grove, Illinois 60515-1263, USA. +* -- Reference BLAS test routine (version 3.4.1) -- +* -- Reference BLAS is a software package provided by Univ. of Tennessee, -- +* -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- +* April 2012 * -* -* -- Written on 10-August-1987. -* Richard Hanson, Sandia National Labs. -* Jeremy Du Croz, NAG Central Office. +* ===================================================================== * * .. Parameters .. INTEGER NIN @@ -72,8 +118,8 @@ PROGRAM ZBLAT2 COMPLEX*16 ZERO, ONE PARAMETER ( ZERO = ( 0.0D0, 0.0D0 ), $ ONE = ( 1.0D0, 0.0D0 ) ) - DOUBLE PRECISION RZERO, RHALF, RONE - PARAMETER ( RZERO = 0.0D0, RHALF = 0.5D0, RONE = 1.0D0 ) + DOUBLE PRECISION RZERO + PARAMETER ( RZERO = 0.0D0 ) INTEGER NMAX, INCMAX PARAMETER ( NMAX = 65, INCMAX = 2 ) INTEGER NINMAX, NIDMAX, NKBMAX, NALMAX, NBEMAX @@ -127,7 +173,7 @@ PROGRAM ZBLAT2 * READ( NIN, FMT = * )SUMMRY READ( NIN, FMT = * )NOUT - OPEN( NOUT, FILE = SUMMRY, STATUS = 'NEW' ) + OPEN( NOUT, FILE = SUMMRY, STATUS = 'UNKNOWN' ) NOUTC = NOUT * * Read name and unit number for snapshot output file and open file. @@ -136,7 +182,7 @@ PROGRAM ZBLAT2 READ( NIN, FMT = * )NTRA TRACE = NTRA.GE.0 IF( TRACE )THEN - OPEN( NTRA, FILE = SNAPS, STATUS = 'NEW' ) + OPEN( NTRA, FILE = SNAPS, STATUS = 'UNKNOWN' ) END IF * Read the flag that directs rewinding of the snapshot file. READ( NIN, FMT = * )REWI @@ -241,14 +287,7 @@ PROGRAM ZBLAT2 * * Compute EPS (the machine precision). * - EPS = RONE - 90 CONTINUE - IF( DDIFF( RONE + EPS, RONE ).EQ.RZERO ) - $ GO TO 100 - EPS = RHALF*EPS - GO TO 90 - 100 CONTINUE - EPS = EPS + EPS + EPS = EPSILON(RZERO) WRITE( NOUT, FMT = 9998 )EPS * * Check the reliability of ZMVCH using exact data. @@ -3087,7 +3126,6 @@ LOGICAL FUNCTION LZERES( TYPE, UPLO, M, N, AA, AS, LDA ) 50 CONTINUE END IF * - 60 CONTINUE LZERES = .TRUE. GO TO 80 70 CONTINUE diff --git a/ground/gcs/src/libs/eigen/blas/testing/zblat3.f b/ground/gcs/src/libs/eigen/blas/testing/zblat3.f index d6a522f2ae..59ca241456 100644 --- a/ground/gcs/src/libs/eigen/blas/testing/zblat3.f +++ b/ground/gcs/src/libs/eigen/blas/testing/zblat3.f @@ -1,50 +1,97 @@ +*> \brief \b ZBLAT3 +* +* =========== DOCUMENTATION =========== +* +* Online html documentation available at +* http://www.netlib.org/lapack/explore-html/ +* +* Definition: +* =========== +* +* PROGRAM ZBLAT3 +* +* +*> \par Purpose: +* ============= +*> +*> \verbatim +*> +*> Test program for the COMPLEX*16 Level 3 Blas. +*> +*> The program must be driven by a short data file. The first 14 records +*> of the file are read using list-directed input, the last 9 records +*> are read using the format ( A6, L2 ). An annotated example of a data +*> file can be obtained by deleting the first 3 characters from the +*> following 23 lines: +*> 'zblat3.out' NAME OF SUMMARY OUTPUT FILE +*> 6 UNIT NUMBER OF SUMMARY FILE +*> 'ZBLAT3.SNAP' NAME OF SNAPSHOT OUTPUT FILE +*> -1 UNIT NUMBER OF SNAPSHOT FILE (NOT USED IF .LT. 0) +*> F LOGICAL FLAG, T TO REWIND SNAPSHOT FILE AFTER EACH RECORD. +*> F LOGICAL FLAG, T TO STOP ON FAILURES. +*> T LOGICAL FLAG, T TO TEST ERROR EXITS. +*> 16.0 THRESHOLD VALUE OF TEST RATIO +*> 6 NUMBER OF VALUES OF N +*> 0 1 2 3 5 9 VALUES OF N +*> 3 NUMBER OF VALUES OF ALPHA +*> (0.0,0.0) (1.0,0.0) (0.7,-0.9) VALUES OF ALPHA +*> 3 NUMBER OF VALUES OF BETA +*> (0.0,0.0) (1.0,0.0) (1.3,-1.1) VALUES OF BETA +*> ZGEMM T PUT F FOR NO TEST. SAME COLUMNS. +*> ZHEMM T PUT F FOR NO TEST. SAME COLUMNS. +*> ZSYMM T PUT F FOR NO TEST. SAME COLUMNS. +*> ZTRMM T PUT F FOR NO TEST. SAME COLUMNS. +*> ZTRSM T PUT F FOR NO TEST. SAME COLUMNS. +*> ZHERK T PUT F FOR NO TEST. SAME COLUMNS. +*> ZSYRK T PUT F FOR NO TEST. SAME COLUMNS. +*> ZHER2K T PUT F FOR NO TEST. SAME COLUMNS. +*> ZSYR2K T PUT F FOR NO TEST. SAME COLUMNS. +*> +*> +*> Further Details +*> =============== +*> +*> See: +*> +*> Dongarra J. J., Du Croz J. J., Duff I. S. and Hammarling S. +*> A Set of Level 3 Basic Linear Algebra Subprograms. +*> +*> Technical Memorandum No.88 (Revision 1), Mathematics and +*> Computer Science Division, Argonne National Laboratory, 9700 +*> South Cass Avenue, Argonne, Illinois 60439, US. +*> +*> -- Written on 8-February-1989. +*> Jack Dongarra, Argonne National Laboratory. +*> Iain Duff, AERE Harwell. +*> Jeremy Du Croz, Numerical Algorithms Group Ltd. +*> Sven Hammarling, Numerical Algorithms Group Ltd. +*> +*> 10-9-00: Change STATUS='NEW' to 'UNKNOWN' so that the testers +*> can be run multiple times without deleting generated +*> output files (susan) +*> \endverbatim +* +* Authors: +* ======== +* +*> \author Univ. of Tennessee +*> \author Univ. of California Berkeley +*> \author Univ. of Colorado Denver +*> \author NAG Ltd. +* +*> \date April 2012 +* +*> \ingroup complex16_blas_testing +* +* ===================================================================== PROGRAM ZBLAT3 * -* Test program for the COMPLEX*16 Level 3 Blas. -* -* The program must be driven by a short data file. The first 14 records -* of the file are read using list-directed input, the last 9 records -* are read using the format ( A6, L2 ). An annotated example of a data -* file can be obtained by deleting the first 3 characters from the -* following 23 lines: -* 'ZBLAT3.SUMM' NAME OF SUMMARY OUTPUT FILE -* 6 UNIT NUMBER OF SUMMARY FILE -* 'ZBLAT3.SNAP' NAME OF SNAPSHOT OUTPUT FILE -* -1 UNIT NUMBER OF SNAPSHOT FILE (NOT USED IF .LT. 0) -* F LOGICAL FLAG, T TO REWIND SNAPSHOT FILE AFTER EACH RECORD. -* F LOGICAL FLAG, T TO STOP ON FAILURES. -* T LOGICAL FLAG, T TO TEST ERROR EXITS. -* 16.0 THRESHOLD VALUE OF TEST RATIO -* 6 NUMBER OF VALUES OF N -* 0 1 2 3 5 9 VALUES OF N -* 3 NUMBER OF VALUES OF ALPHA -* (0.0,0.0) (1.0,0.0) (0.7,-0.9) VALUES OF ALPHA -* 3 NUMBER OF VALUES OF BETA -* (0.0,0.0) (1.0,0.0) (1.3,-1.1) VALUES OF BETA -* ZGEMM T PUT F FOR NO TEST. SAME COLUMNS. -* ZHEMM T PUT F FOR NO TEST. SAME COLUMNS. -* ZSYMM T PUT F FOR NO TEST. SAME COLUMNS. -* ZTRMM T PUT F FOR NO TEST. SAME COLUMNS. -* ZTRSM T PUT F FOR NO TEST. SAME COLUMNS. -* ZHERK T PUT F FOR NO TEST. SAME COLUMNS. -* ZSYRK T PUT F FOR NO TEST. SAME COLUMNS. -* ZHER2K T PUT F FOR NO TEST. SAME COLUMNS. -* ZSYR2K T PUT F FOR NO TEST. SAME COLUMNS. -* -* See: -* -* Dongarra J. J., Du Croz J. J., Duff I. S. and Hammarling S. -* A Set of Level 3 Basic Linear Algebra Subprograms. -* -* Technical Memorandum No.88 (Revision 1), Mathematics and -* Computer Science Division, Argonne National Laboratory, 9700 -* South Cass Avenue, Argonne, Illinois 60439, US. +* -- Reference BLAS test routine (version 3.4.1) -- +* -- Reference BLAS is a software package provided by Univ. of Tennessee, -- +* -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- +* April 2012 * -* -- Written on 8-February-1989. -* Jack Dongarra, Argonne National Laboratory. -* Iain Duff, AERE Harwell. -* Jeremy Du Croz, Numerical Algorithms Group Ltd. -* Sven Hammarling, Numerical Algorithms Group Ltd. +* ===================================================================== * * .. Parameters .. INTEGER NIN @@ -54,8 +101,8 @@ PROGRAM ZBLAT3 COMPLEX*16 ZERO, ONE PARAMETER ( ZERO = ( 0.0D0, 0.0D0 ), $ ONE = ( 1.0D0, 0.0D0 ) ) - DOUBLE PRECISION RZERO, RHALF, RONE - PARAMETER ( RZERO = 0.0D0, RHALF = 0.5D0, RONE = 1.0D0 ) + DOUBLE PRECISION RZERO + PARAMETER ( RZERO = 0.0D0 ) INTEGER NMAX PARAMETER ( NMAX = 65 ) INTEGER NIDMAX, NALMAX, NBEMAX @@ -104,7 +151,7 @@ PROGRAM ZBLAT3 * READ( NIN, FMT = * )SUMMRY READ( NIN, FMT = * )NOUT - OPEN( NOUT, FILE = SUMMRY, STATUS = 'NEW' ) + OPEN( NOUT, FILE = SUMMRY, STATUS = 'UNKNOWN' ) NOUTC = NOUT * * Read name and unit number for snapshot output file and open file. @@ -113,7 +160,7 @@ PROGRAM ZBLAT3 READ( NIN, FMT = * )NTRA TRACE = NTRA.GE.0 IF( TRACE )THEN - OPEN( NTRA, FILE = SNAPS, STATUS = 'NEW' ) + OPEN( NTRA, FILE = SNAPS, STATUS = 'UNKNOWN' ) END IF * Read the flag that directs rewinding of the snapshot file. READ( NIN, FMT = * )REWI @@ -190,14 +237,7 @@ PROGRAM ZBLAT3 * * Compute EPS (the machine precision). * - EPS = RONE - 70 CONTINUE - IF( DDIFF( RONE + EPS, RONE ).EQ.RZERO ) - $ GO TO 80 - EPS = RHALF*EPS - GO TO 70 - 80 CONTINUE - EPS = EPS + EPS + EPS = EPSILON(RZERO) WRITE( NOUT, FMT = 9998 )EPS * * Check the reliability of ZMMCH using exact data. @@ -1949,7 +1989,7 @@ SUBROUTINE ZCHKE( ISNUM, SRNAMT, NOUT ) * * Tests the error exits from the Level 3 Blas. * Requires a special version of the error-handling routine XERBLA. -* ALPHA, RALPHA, BETA, RBETA, A, B and C should not need to be defined. +* A, B and C should not need to be defined. * * Auxiliary routine for test program for Level 3 Blas. * @@ -1959,12 +1999,20 @@ SUBROUTINE ZCHKE( ISNUM, SRNAMT, NOUT ) * Jeremy Du Croz, Numerical Algorithms Group Ltd. * Sven Hammarling, Numerical Algorithms Group Ltd. * +* 3-19-92: Initialize ALPHA, BETA, RALPHA, and RBETA (eca) +* 3-19-92: Fix argument 12 in calls to ZSYMM and ZHEMM +* with INFOT = 9 (eca) +* 10-9-00: Declared INTRINSIC DCMPLX (susan) +* * .. Scalar Arguments .. INTEGER ISNUM, NOUT CHARACTER*6 SRNAMT * .. Scalars in Common .. INTEGER INFOT, NOUTC LOGICAL LERR, OK +* .. Parameters .. + REAL ONE, TWO + PARAMETER ( ONE = 1.0D0, TWO = 2.0D0 ) * .. Local Scalars .. COMPLEX*16 ALPHA, BETA DOUBLE PRECISION RALPHA, RBETA @@ -1973,6 +2021,8 @@ SUBROUTINE ZCHKE( ISNUM, SRNAMT, NOUT ) * .. External Subroutines .. EXTERNAL ZGEMM, ZHEMM, ZHER2K, ZHERK, CHKXER, ZSYMM, $ ZSYR2K, ZSYRK, ZTRMM, ZTRSM +* .. Intrinsic Functions .. + INTRINSIC DCMPLX * .. Common blocks .. COMMON /INFOC/INFOT, NOUTC, OK, LERR * .. Executable Statements .. @@ -1982,6 +2032,14 @@ SUBROUTINE ZCHKE( ISNUM, SRNAMT, NOUT ) * LERR is set to .TRUE. by the special version of XERBLA each time * it is called, and is then tested and re-set by CHKXER. LERR = .FALSE. +* +* Initialize ALPHA, BETA, RALPHA, and RBETA. +* + ALPHA = DCMPLX( ONE, -ONE ) + BETA = DCMPLX( TWO, -TWO ) + RALPHA = ONE + RBETA = TWO +* GO TO ( 10, 20, 30, 40, 50, 60, 70, 80, $ 90 )ISNUM 10 INFOT = 1 @@ -2208,16 +2266,16 @@ SUBROUTINE ZCHKE( ISNUM, SRNAMT, NOUT ) CALL ZHEMM( 'R', 'L', 0, 2, ALPHA, A, 1, B, 1, BETA, C, 1 ) CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK ) INFOT = 9 - CALL ZHEMM( 'L', 'U', 2, 0, ALPHA, A, 2, B, 1, BETA, C, 1 ) + CALL ZHEMM( 'L', 'U', 2, 0, ALPHA, A, 2, B, 1, BETA, C, 2 ) CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK ) INFOT = 9 - CALL ZHEMM( 'R', 'U', 2, 0, ALPHA, A, 1, B, 1, BETA, C, 1 ) + CALL ZHEMM( 'R', 'U', 2, 0, ALPHA, A, 1, B, 1, BETA, C, 2 ) CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK ) INFOT = 9 - CALL ZHEMM( 'L', 'L', 2, 0, ALPHA, A, 2, B, 1, BETA, C, 1 ) + CALL ZHEMM( 'L', 'L', 2, 0, ALPHA, A, 2, B, 1, BETA, C, 2 ) CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK ) INFOT = 9 - CALL ZHEMM( 'R', 'L', 2, 0, ALPHA, A, 1, B, 1, BETA, C, 1 ) + CALL ZHEMM( 'R', 'L', 2, 0, ALPHA, A, 1, B, 1, BETA, C, 2 ) CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK ) INFOT = 12 CALL ZHEMM( 'L', 'U', 2, 0, ALPHA, A, 2, B, 2, BETA, C, 1 ) @@ -2275,16 +2333,16 @@ SUBROUTINE ZCHKE( ISNUM, SRNAMT, NOUT ) CALL ZSYMM( 'R', 'L', 0, 2, ALPHA, A, 1, B, 1, BETA, C, 1 ) CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK ) INFOT = 9 - CALL ZSYMM( 'L', 'U', 2, 0, ALPHA, A, 2, B, 1, BETA, C, 1 ) + CALL ZSYMM( 'L', 'U', 2, 0, ALPHA, A, 2, B, 1, BETA, C, 2 ) CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK ) INFOT = 9 - CALL ZSYMM( 'R', 'U', 2, 0, ALPHA, A, 1, B, 1, BETA, C, 1 ) + CALL ZSYMM( 'R', 'U', 2, 0, ALPHA, A, 1, B, 1, BETA, C, 2 ) CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK ) INFOT = 9 - CALL ZSYMM( 'L', 'L', 2, 0, ALPHA, A, 2, B, 1, BETA, C, 1 ) + CALL ZSYMM( 'L', 'L', 2, 0, ALPHA, A, 2, B, 1, BETA, C, 2 ) CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK ) INFOT = 9 - CALL ZSYMM( 'R', 'L', 2, 0, ALPHA, A, 1, B, 1, BETA, C, 1 ) + CALL ZSYMM( 'R', 'L', 2, 0, ALPHA, A, 1, B, 1, BETA, C, 2 ) CALL CHKXER( SRNAMT, INFOT, NOUT, LERR, OK ) INFOT = 12 CALL ZSYMM( 'L', 'U', 2, 0, ALPHA, A, 2, B, 2, BETA, C, 1 ) @@ -3274,7 +3332,6 @@ LOGICAL FUNCTION LZERES( TYPE, UPLO, M, N, AA, AS, LDA ) 50 CONTINUE END IF * - 60 CONTINUE LZERES = .TRUE. GO TO 80 70 CONTINUE diff --git a/ground/gcs/src/libs/eigen/blas/xerbla.cpp b/ground/gcs/src/libs/eigen/blas/xerbla.cpp index dd39a52442..c373e86996 100644 --- a/ground/gcs/src/libs/eigen/blas/xerbla.cpp +++ b/ground/gcs/src/libs/eigen/blas/xerbla.cpp @@ -1,5 +1,5 @@ -#include +#include #if (defined __GNUC__) && (!defined __MINGW32__) && (!defined __CYGWIN__) #define EIGEN_WEAK_LINKING __attribute__ ((weak)) @@ -14,7 +14,7 @@ extern "C" EIGEN_WEAK_LINKING int xerbla_(const char * msg, int *info, int) { - std::cerr << "Eigen BLAS ERROR #" << *info << ": " << msg << "\n"; + printf("Eigen BLAS ERROR #%i: %s\n", *info, msg ); return 0; } diff --git a/ground/gcs/src/libs/eigen/blas/zhbmv.f b/ground/gcs/src/libs/eigen/blas/zhbmv.f deleted file mode 100644 index bca0da5fcd..0000000000 --- a/ground/gcs/src/libs/eigen/blas/zhbmv.f +++ /dev/null @@ -1,310 +0,0 @@ - SUBROUTINE ZHBMV(UPLO,N,K,ALPHA,A,LDA,X,INCX,BETA,Y,INCY) -* .. Scalar Arguments .. - DOUBLE COMPLEX ALPHA,BETA - INTEGER INCX,INCY,K,LDA,N - CHARACTER UPLO -* .. -* .. Array Arguments .. - DOUBLE COMPLEX A(LDA,*),X(*),Y(*) -* .. -* -* Purpose -* ======= -* -* ZHBMV performs the matrix-vector operation -* -* y := alpha*A*x + beta*y, -* -* where alpha and beta are scalars, x and y are n element vectors and -* A is an n by n hermitian band matrix, with k super-diagonals. -* -* Arguments -* ========== -* -* UPLO - CHARACTER*1. -* On entry, UPLO specifies whether the upper or lower -* triangular part of the band matrix A is being supplied as -* follows: -* -* UPLO = 'U' or 'u' The upper triangular part of A is -* being supplied. -* -* UPLO = 'L' or 'l' The lower triangular part of A is -* being supplied. -* -* Unchanged on exit. -* -* N - INTEGER. -* On entry, N specifies the order of the matrix A. -* N must be at least zero. -* Unchanged on exit. -* -* K - INTEGER. -* On entry, K specifies the number of super-diagonals of the -* matrix A. K must satisfy 0 .le. K. -* Unchanged on exit. -* -* ALPHA - COMPLEX*16 . -* On entry, ALPHA specifies the scalar alpha. -* Unchanged on exit. -* -* A - COMPLEX*16 array of DIMENSION ( LDA, n ). -* Before entry with UPLO = 'U' or 'u', the leading ( k + 1 ) -* by n part of the array A must contain the upper triangular -* band part of the hermitian matrix, supplied column by -* column, with the leading diagonal of the matrix in row -* ( k + 1 ) of the array, the first super-diagonal starting at -* position 2 in row k, and so on. The top left k by k triangle -* of the array A is not referenced. -* The following program segment will transfer the upper -* triangular part of a hermitian band matrix from conventional -* full matrix storage to band storage: -* -* DO 20, J = 1, N -* M = K + 1 - J -* DO 10, I = MAX( 1, J - K ), J -* A( M + I, J ) = matrix( I, J ) -* 10 CONTINUE -* 20 CONTINUE -* -* Before entry with UPLO = 'L' or 'l', the leading ( k + 1 ) -* by n part of the array A must contain the lower triangular -* band part of the hermitian matrix, supplied column by -* column, with the leading diagonal of the matrix in row 1 of -* the array, the first sub-diagonal starting at position 1 in -* row 2, and so on. The bottom right k by k triangle of the -* array A is not referenced. -* The following program segment will transfer the lower -* triangular part of a hermitian band matrix from conventional -* full matrix storage to band storage: -* -* DO 20, J = 1, N -* M = 1 - J -* DO 10, I = J, MIN( N, J + K ) -* A( M + I, J ) = matrix( I, J ) -* 10 CONTINUE -* 20 CONTINUE -* -* Note that the imaginary parts of the diagonal elements need -* not be set and are assumed to be zero. -* Unchanged on exit. -* -* LDA - INTEGER. -* On entry, LDA specifies the first dimension of A as declared -* in the calling (sub) program. LDA must be at least -* ( k + 1 ). -* Unchanged on exit. -* -* X - COMPLEX*16 array of DIMENSION at least -* ( 1 + ( n - 1 )*abs( INCX ) ). -* Before entry, the incremented array X must contain the -* vector x. -* Unchanged on exit. -* -* INCX - INTEGER. -* On entry, INCX specifies the increment for the elements of -* X. INCX must not be zero. -* Unchanged on exit. -* -* BETA - COMPLEX*16 . -* On entry, BETA specifies the scalar beta. -* Unchanged on exit. -* -* Y - COMPLEX*16 array of DIMENSION at least -* ( 1 + ( n - 1 )*abs( INCY ) ). -* Before entry, the incremented array Y must contain the -* vector y. On exit, Y is overwritten by the updated vector y. -* -* INCY - INTEGER. -* On entry, INCY specifies the increment for the elements of -* Y. INCY must not be zero. -* Unchanged on exit. -* -* Further Details -* =============== -* -* Level 2 Blas routine. -* -* -- Written on 22-October-1986. -* Jack Dongarra, Argonne National Lab. -* Jeremy Du Croz, Nag Central Office. -* Sven Hammarling, Nag Central Office. -* Richard Hanson, Sandia National Labs. -* -* ===================================================================== -* -* .. Parameters .. - DOUBLE COMPLEX ONE - PARAMETER (ONE= (1.0D+0,0.0D+0)) - DOUBLE COMPLEX ZERO - PARAMETER (ZERO= (0.0D+0,0.0D+0)) -* .. -* .. Local Scalars .. - DOUBLE COMPLEX TEMP1,TEMP2 - INTEGER I,INFO,IX,IY,J,JX,JY,KPLUS1,KX,KY,L -* .. -* .. External Functions .. - LOGICAL LSAME - EXTERNAL LSAME -* .. -* .. External Subroutines .. - EXTERNAL XERBLA -* .. -* .. Intrinsic Functions .. - INTRINSIC DBLE,DCONJG,MAX,MIN -* .. -* -* Test the input parameters. -* - INFO = 0 - IF (.NOT.LSAME(UPLO,'U') .AND. .NOT.LSAME(UPLO,'L')) THEN - INFO = 1 - ELSE IF (N.LT.0) THEN - INFO = 2 - ELSE IF (K.LT.0) THEN - INFO = 3 - ELSE IF (LDA.LT. (K+1)) THEN - INFO = 6 - ELSE IF (INCX.EQ.0) THEN - INFO = 8 - ELSE IF (INCY.EQ.0) THEN - INFO = 11 - END IF - IF (INFO.NE.0) THEN - CALL XERBLA('ZHBMV ',INFO) - RETURN - END IF -* -* Quick return if possible. -* - IF ((N.EQ.0) .OR. ((ALPHA.EQ.ZERO).AND. (BETA.EQ.ONE))) RETURN -* -* Set up the start points in X and Y. -* - IF (INCX.GT.0) THEN - KX = 1 - ELSE - KX = 1 - (N-1)*INCX - END IF - IF (INCY.GT.0) THEN - KY = 1 - ELSE - KY = 1 - (N-1)*INCY - END IF -* -* Start the operations. In this version the elements of the array A -* are accessed sequentially with one pass through A. -* -* First form y := beta*y. -* - IF (BETA.NE.ONE) THEN - IF (INCY.EQ.1) THEN - IF (BETA.EQ.ZERO) THEN - DO 10 I = 1,N - Y(I) = ZERO - 10 CONTINUE - ELSE - DO 20 I = 1,N - Y(I) = BETA*Y(I) - 20 CONTINUE - END IF - ELSE - IY = KY - IF (BETA.EQ.ZERO) THEN - DO 30 I = 1,N - Y(IY) = ZERO - IY = IY + INCY - 30 CONTINUE - ELSE - DO 40 I = 1,N - Y(IY) = BETA*Y(IY) - IY = IY + INCY - 40 CONTINUE - END IF - END IF - END IF - IF (ALPHA.EQ.ZERO) RETURN - IF (LSAME(UPLO,'U')) THEN -* -* Form y when upper triangle of A is stored. -* - KPLUS1 = K + 1 - IF ((INCX.EQ.1) .AND. (INCY.EQ.1)) THEN - DO 60 J = 1,N - TEMP1 = ALPHA*X(J) - TEMP2 = ZERO - L = KPLUS1 - J - DO 50 I = MAX(1,J-K),J - 1 - Y(I) = Y(I) + TEMP1*A(L+I,J) - TEMP2 = TEMP2 + DCONJG(A(L+I,J))*X(I) - 50 CONTINUE - Y(J) = Y(J) + TEMP1*DBLE(A(KPLUS1,J)) + ALPHA*TEMP2 - 60 CONTINUE - ELSE - JX = KX - JY = KY - DO 80 J = 1,N - TEMP1 = ALPHA*X(JX) - TEMP2 = ZERO - IX = KX - IY = KY - L = KPLUS1 - J - DO 70 I = MAX(1,J-K),J - 1 - Y(IY) = Y(IY) + TEMP1*A(L+I,J) - TEMP2 = TEMP2 + DCONJG(A(L+I,J))*X(IX) - IX = IX + INCX - IY = IY + INCY - 70 CONTINUE - Y(JY) = Y(JY) + TEMP1*DBLE(A(KPLUS1,J)) + ALPHA*TEMP2 - JX = JX + INCX - JY = JY + INCY - IF (J.GT.K) THEN - KX = KX + INCX - KY = KY + INCY - END IF - 80 CONTINUE - END IF - ELSE -* -* Form y when lower triangle of A is stored. -* - IF ((INCX.EQ.1) .AND. (INCY.EQ.1)) THEN - DO 100 J = 1,N - TEMP1 = ALPHA*X(J) - TEMP2 = ZERO - Y(J) = Y(J) + TEMP1*DBLE(A(1,J)) - L = 1 - J - DO 90 I = J + 1,MIN(N,J+K) - Y(I) = Y(I) + TEMP1*A(L+I,J) - TEMP2 = TEMP2 + DCONJG(A(L+I,J))*X(I) - 90 CONTINUE - Y(J) = Y(J) + ALPHA*TEMP2 - 100 CONTINUE - ELSE - JX = KX - JY = KY - DO 120 J = 1,N - TEMP1 = ALPHA*X(JX) - TEMP2 = ZERO - Y(JY) = Y(JY) + TEMP1*DBLE(A(1,J)) - L = 1 - J - IX = JX - IY = JY - DO 110 I = J + 1,MIN(N,J+K) - IX = IX + INCX - IY = IY + INCY - Y(IY) = Y(IY) + TEMP1*A(L+I,J) - TEMP2 = TEMP2 + DCONJG(A(L+I,J))*X(IX) - 110 CONTINUE - Y(JY) = Y(JY) + ALPHA*TEMP2 - JX = JX + INCX - JY = JY + INCY - 120 CONTINUE - END IF - END IF -* - RETURN -* -* End of ZHBMV . -* - END diff --git a/ground/gcs/src/libs/eigen/blas/zhpmv.f b/ground/gcs/src/libs/eigen/blas/zhpmv.f deleted file mode 100644 index b686108b36..0000000000 --- a/ground/gcs/src/libs/eigen/blas/zhpmv.f +++ /dev/null @@ -1,272 +0,0 @@ - SUBROUTINE ZHPMV(UPLO,N,ALPHA,AP,X,INCX,BETA,Y,INCY) -* .. Scalar Arguments .. - DOUBLE COMPLEX ALPHA,BETA - INTEGER INCX,INCY,N - CHARACTER UPLO -* .. -* .. Array Arguments .. - DOUBLE COMPLEX AP(*),X(*),Y(*) -* .. -* -* Purpose -* ======= -* -* ZHPMV performs the matrix-vector operation -* -* y := alpha*A*x + beta*y, -* -* where alpha and beta are scalars, x and y are n element vectors and -* A is an n by n hermitian matrix, supplied in packed form. -* -* Arguments -* ========== -* -* UPLO - CHARACTER*1. -* On entry, UPLO specifies whether the upper or lower -* triangular part of the matrix A is supplied in the packed -* array AP as follows: -* -* UPLO = 'U' or 'u' The upper triangular part of A is -* supplied in AP. -* -* UPLO = 'L' or 'l' The lower triangular part of A is -* supplied in AP. -* -* Unchanged on exit. -* -* N - INTEGER. -* On entry, N specifies the order of the matrix A. -* N must be at least zero. -* Unchanged on exit. -* -* ALPHA - COMPLEX*16 . -* On entry, ALPHA specifies the scalar alpha. -* Unchanged on exit. -* -* AP - COMPLEX*16 array of DIMENSION at least -* ( ( n*( n + 1 ) )/2 ). -* Before entry with UPLO = 'U' or 'u', the array AP must -* contain the upper triangular part of the hermitian matrix -* packed sequentially, column by column, so that AP( 1 ) -* contains a( 1, 1 ), AP( 2 ) and AP( 3 ) contain a( 1, 2 ) -* and a( 2, 2 ) respectively, and so on. -* Before entry with UPLO = 'L' or 'l', the array AP must -* contain the lower triangular part of the hermitian matrix -* packed sequentially, column by column, so that AP( 1 ) -* contains a( 1, 1 ), AP( 2 ) and AP( 3 ) contain a( 2, 1 ) -* and a( 3, 1 ) respectively, and so on. -* Note that the imaginary parts of the diagonal elements need -* not be set and are assumed to be zero. -* Unchanged on exit. -* -* X - COMPLEX*16 array of dimension at least -* ( 1 + ( n - 1 )*abs( INCX ) ). -* Before entry, the incremented array X must contain the n -* element vector x. -* Unchanged on exit. -* -* INCX - INTEGER. -* On entry, INCX specifies the increment for the elements of -* X. INCX must not be zero. -* Unchanged on exit. -* -* BETA - COMPLEX*16 . -* On entry, BETA specifies the scalar beta. When BETA is -* supplied as zero then Y need not be set on input. -* Unchanged on exit. -* -* Y - COMPLEX*16 array of dimension at least -* ( 1 + ( n - 1 )*abs( INCY ) ). -* Before entry, the incremented array Y must contain the n -* element vector y. On exit, Y is overwritten by the updated -* vector y. -* -* INCY - INTEGER. -* On entry, INCY specifies the increment for the elements of -* Y. INCY must not be zero. -* Unchanged on exit. -* -* Further Details -* =============== -* -* Level 2 Blas routine. -* -* -- Written on 22-October-1986. -* Jack Dongarra, Argonne National Lab. -* Jeremy Du Croz, Nag Central Office. -* Sven Hammarling, Nag Central Office. -* Richard Hanson, Sandia National Labs. -* -* ===================================================================== -* -* .. Parameters .. - DOUBLE COMPLEX ONE - PARAMETER (ONE= (1.0D+0,0.0D+0)) - DOUBLE COMPLEX ZERO - PARAMETER (ZERO= (0.0D+0,0.0D+0)) -* .. -* .. Local Scalars .. - DOUBLE COMPLEX TEMP1,TEMP2 - INTEGER I,INFO,IX,IY,J,JX,JY,K,KK,KX,KY -* .. -* .. External Functions .. - LOGICAL LSAME - EXTERNAL LSAME -* .. -* .. External Subroutines .. - EXTERNAL XERBLA -* .. -* .. Intrinsic Functions .. - INTRINSIC DBLE,DCONJG -* .. -* -* Test the input parameters. -* - INFO = 0 - IF (.NOT.LSAME(UPLO,'U') .AND. .NOT.LSAME(UPLO,'L')) THEN - INFO = 1 - ELSE IF (N.LT.0) THEN - INFO = 2 - ELSE IF (INCX.EQ.0) THEN - INFO = 6 - ELSE IF (INCY.EQ.0) THEN - INFO = 9 - END IF - IF (INFO.NE.0) THEN - CALL XERBLA('ZHPMV ',INFO) - RETURN - END IF -* -* Quick return if possible. -* - IF ((N.EQ.0) .OR. ((ALPHA.EQ.ZERO).AND. (BETA.EQ.ONE))) RETURN -* -* Set up the start points in X and Y. -* - IF (INCX.GT.0) THEN - KX = 1 - ELSE - KX = 1 - (N-1)*INCX - END IF - IF (INCY.GT.0) THEN - KY = 1 - ELSE - KY = 1 - (N-1)*INCY - END IF -* -* Start the operations. In this version the elements of the array AP -* are accessed sequentially with one pass through AP. -* -* First form y := beta*y. -* - IF (BETA.NE.ONE) THEN - IF (INCY.EQ.1) THEN - IF (BETA.EQ.ZERO) THEN - DO 10 I = 1,N - Y(I) = ZERO - 10 CONTINUE - ELSE - DO 20 I = 1,N - Y(I) = BETA*Y(I) - 20 CONTINUE - END IF - ELSE - IY = KY - IF (BETA.EQ.ZERO) THEN - DO 30 I = 1,N - Y(IY) = ZERO - IY = IY + INCY - 30 CONTINUE - ELSE - DO 40 I = 1,N - Y(IY) = BETA*Y(IY) - IY = IY + INCY - 40 CONTINUE - END IF - END IF - END IF - IF (ALPHA.EQ.ZERO) RETURN - KK = 1 - IF (LSAME(UPLO,'U')) THEN -* -* Form y when AP contains the upper triangle. -* - IF ((INCX.EQ.1) .AND. (INCY.EQ.1)) THEN - DO 60 J = 1,N - TEMP1 = ALPHA*X(J) - TEMP2 = ZERO - K = KK - DO 50 I = 1,J - 1 - Y(I) = Y(I) + TEMP1*AP(K) - TEMP2 = TEMP2 + DCONJG(AP(K))*X(I) - K = K + 1 - 50 CONTINUE - Y(J) = Y(J) + TEMP1*DBLE(AP(KK+J-1)) + ALPHA*TEMP2 - KK = KK + J - 60 CONTINUE - ELSE - JX = KX - JY = KY - DO 80 J = 1,N - TEMP1 = ALPHA*X(JX) - TEMP2 = ZERO - IX = KX - IY = KY - DO 70 K = KK,KK + J - 2 - Y(IY) = Y(IY) + TEMP1*AP(K) - TEMP2 = TEMP2 + DCONJG(AP(K))*X(IX) - IX = IX + INCX - IY = IY + INCY - 70 CONTINUE - Y(JY) = Y(JY) + TEMP1*DBLE(AP(KK+J-1)) + ALPHA*TEMP2 - JX = JX + INCX - JY = JY + INCY - KK = KK + J - 80 CONTINUE - END IF - ELSE -* -* Form y when AP contains the lower triangle. -* - IF ((INCX.EQ.1) .AND. (INCY.EQ.1)) THEN - DO 100 J = 1,N - TEMP1 = ALPHA*X(J) - TEMP2 = ZERO - Y(J) = Y(J) + TEMP1*DBLE(AP(KK)) - K = KK + 1 - DO 90 I = J + 1,N - Y(I) = Y(I) + TEMP1*AP(K) - TEMP2 = TEMP2 + DCONJG(AP(K))*X(I) - K = K + 1 - 90 CONTINUE - Y(J) = Y(J) + ALPHA*TEMP2 - KK = KK + (N-J+1) - 100 CONTINUE - ELSE - JX = KX - JY = KY - DO 120 J = 1,N - TEMP1 = ALPHA*X(JX) - TEMP2 = ZERO - Y(JY) = Y(JY) + TEMP1*DBLE(AP(KK)) - IX = JX - IY = JY - DO 110 K = KK + 1,KK + N - J - IX = IX + INCX - IY = IY + INCY - Y(IY) = Y(IY) + TEMP1*AP(K) - TEMP2 = TEMP2 + DCONJG(AP(K))*X(IX) - 110 CONTINUE - Y(JY) = Y(JY) + ALPHA*TEMP2 - JX = JX + INCX - JY = JY + INCY - KK = KK + (N-J+1) - 120 CONTINUE - END IF - END IF -* - RETURN -* -* End of ZHPMV . -* - END diff --git a/ground/gcs/src/libs/eigen/blas/ztbmv.f b/ground/gcs/src/libs/eigen/blas/ztbmv.f deleted file mode 100644 index 7c85c1b550..0000000000 --- a/ground/gcs/src/libs/eigen/blas/ztbmv.f +++ /dev/null @@ -1,366 +0,0 @@ - SUBROUTINE ZTBMV(UPLO,TRANS,DIAG,N,K,A,LDA,X,INCX) -* .. Scalar Arguments .. - INTEGER INCX,K,LDA,N - CHARACTER DIAG,TRANS,UPLO -* .. -* .. Array Arguments .. - DOUBLE COMPLEX A(LDA,*),X(*) -* .. -* -* Purpose -* ======= -* -* ZTBMV performs one of the matrix-vector operations -* -* x := A*x, or x := A'*x, or x := conjg( A' )*x, -* -* where x is an n element vector and A is an n by n unit, or non-unit, -* upper or lower triangular band matrix, with ( k + 1 ) diagonals. -* -* Arguments -* ========== -* -* UPLO - CHARACTER*1. -* On entry, UPLO specifies whether the matrix is an upper or -* lower triangular matrix as follows: -* -* UPLO = 'U' or 'u' A is an upper triangular matrix. -* -* UPLO = 'L' or 'l' A is a lower triangular matrix. -* -* Unchanged on exit. -* -* TRANS - CHARACTER*1. -* On entry, TRANS specifies the operation to be performed as -* follows: -* -* TRANS = 'N' or 'n' x := A*x. -* -* TRANS = 'T' or 't' x := A'*x. -* -* TRANS = 'C' or 'c' x := conjg( A' )*x. -* -* Unchanged on exit. -* -* DIAG - CHARACTER*1. -* On entry, DIAG specifies whether or not A is unit -* triangular as follows: -* -* DIAG = 'U' or 'u' A is assumed to be unit triangular. -* -* DIAG = 'N' or 'n' A is not assumed to be unit -* triangular. -* -* Unchanged on exit. -* -* N - INTEGER. -* On entry, N specifies the order of the matrix A. -* N must be at least zero. -* Unchanged on exit. -* -* K - INTEGER. -* On entry with UPLO = 'U' or 'u', K specifies the number of -* super-diagonals of the matrix A. -* On entry with UPLO = 'L' or 'l', K specifies the number of -* sub-diagonals of the matrix A. -* K must satisfy 0 .le. K. -* Unchanged on exit. -* -* A - COMPLEX*16 array of DIMENSION ( LDA, n ). -* Before entry with UPLO = 'U' or 'u', the leading ( k + 1 ) -* by n part of the array A must contain the upper triangular -* band part of the matrix of coefficients, supplied column by -* column, with the leading diagonal of the matrix in row -* ( k + 1 ) of the array, the first super-diagonal starting at -* position 2 in row k, and so on. The top left k by k triangle -* of the array A is not referenced. -* The following program segment will transfer an upper -* triangular band matrix from conventional full matrix storage -* to band storage: -* -* DO 20, J = 1, N -* M = K + 1 - J -* DO 10, I = MAX( 1, J - K ), J -* A( M + I, J ) = matrix( I, J ) -* 10 CONTINUE -* 20 CONTINUE -* -* Before entry with UPLO = 'L' or 'l', the leading ( k + 1 ) -* by n part of the array A must contain the lower triangular -* band part of the matrix of coefficients, supplied column by -* column, with the leading diagonal of the matrix in row 1 of -* the array, the first sub-diagonal starting at position 1 in -* row 2, and so on. The bottom right k by k triangle of the -* array A is not referenced. -* The following program segment will transfer a lower -* triangular band matrix from conventional full matrix storage -* to band storage: -* -* DO 20, J = 1, N -* M = 1 - J -* DO 10, I = J, MIN( N, J + K ) -* A( M + I, J ) = matrix( I, J ) -* 10 CONTINUE -* 20 CONTINUE -* -* Note that when DIAG = 'U' or 'u' the elements of the array A -* corresponding to the diagonal elements of the matrix are not -* referenced, but are assumed to be unity. -* Unchanged on exit. -* -* LDA - INTEGER. -* On entry, LDA specifies the first dimension of A as declared -* in the calling (sub) program. LDA must be at least -* ( k + 1 ). -* Unchanged on exit. -* -* X - COMPLEX*16 array of dimension at least -* ( 1 + ( n - 1 )*abs( INCX ) ). -* Before entry, the incremented array X must contain the n -* element vector x. On exit, X is overwritten with the -* tranformed vector x. -* -* INCX - INTEGER. -* On entry, INCX specifies the increment for the elements of -* X. INCX must not be zero. -* Unchanged on exit. -* -* Further Details -* =============== -* -* Level 2 Blas routine. -* -* -- Written on 22-October-1986. -* Jack Dongarra, Argonne National Lab. -* Jeremy Du Croz, Nag Central Office. -* Sven Hammarling, Nag Central Office. -* Richard Hanson, Sandia National Labs. -* -* ===================================================================== -* -* .. Parameters .. - DOUBLE COMPLEX ZERO - PARAMETER (ZERO= (0.0D+0,0.0D+0)) -* .. -* .. Local Scalars .. - DOUBLE COMPLEX TEMP - INTEGER I,INFO,IX,J,JX,KPLUS1,KX,L - LOGICAL NOCONJ,NOUNIT -* .. -* .. External Functions .. - LOGICAL LSAME - EXTERNAL LSAME -* .. -* .. External Subroutines .. - EXTERNAL XERBLA -* .. -* .. Intrinsic Functions .. - INTRINSIC DCONJG,MAX,MIN -* .. -* -* Test the input parameters. -* - INFO = 0 - IF (.NOT.LSAME(UPLO,'U') .AND. .NOT.LSAME(UPLO,'L')) THEN - INFO = 1 - ELSE IF (.NOT.LSAME(TRANS,'N') .AND. .NOT.LSAME(TRANS,'T') .AND. - + .NOT.LSAME(TRANS,'C')) THEN - INFO = 2 - ELSE IF (.NOT.LSAME(DIAG,'U') .AND. .NOT.LSAME(DIAG,'N')) THEN - INFO = 3 - ELSE IF (N.LT.0) THEN - INFO = 4 - ELSE IF (K.LT.0) THEN - INFO = 5 - ELSE IF (LDA.LT. (K+1)) THEN - INFO = 7 - ELSE IF (INCX.EQ.0) THEN - INFO = 9 - END IF - IF (INFO.NE.0) THEN - CALL XERBLA('ZTBMV ',INFO) - RETURN - END IF -* -* Quick return if possible. -* - IF (N.EQ.0) RETURN -* - NOCONJ = LSAME(TRANS,'T') - NOUNIT = LSAME(DIAG,'N') -* -* Set up the start point in X if the increment is not unity. This -* will be ( N - 1 )*INCX too small for descending loops. -* - IF (INCX.LE.0) THEN - KX = 1 - (N-1)*INCX - ELSE IF (INCX.NE.1) THEN - KX = 1 - END IF -* -* Start the operations. In this version the elements of A are -* accessed sequentially with one pass through A. -* - IF (LSAME(TRANS,'N')) THEN -* -* Form x := A*x. -* - IF (LSAME(UPLO,'U')) THEN - KPLUS1 = K + 1 - IF (INCX.EQ.1) THEN - DO 20 J = 1,N - IF (X(J).NE.ZERO) THEN - TEMP = X(J) - L = KPLUS1 - J - DO 10 I = MAX(1,J-K),J - 1 - X(I) = X(I) + TEMP*A(L+I,J) - 10 CONTINUE - IF (NOUNIT) X(J) = X(J)*A(KPLUS1,J) - END IF - 20 CONTINUE - ELSE - JX = KX - DO 40 J = 1,N - IF (X(JX).NE.ZERO) THEN - TEMP = X(JX) - IX = KX - L = KPLUS1 - J - DO 30 I = MAX(1,J-K),J - 1 - X(IX) = X(IX) + TEMP*A(L+I,J) - IX = IX + INCX - 30 CONTINUE - IF (NOUNIT) X(JX) = X(JX)*A(KPLUS1,J) - END IF - JX = JX + INCX - IF (J.GT.K) KX = KX + INCX - 40 CONTINUE - END IF - ELSE - IF (INCX.EQ.1) THEN - DO 60 J = N,1,-1 - IF (X(J).NE.ZERO) THEN - TEMP = X(J) - L = 1 - J - DO 50 I = MIN(N,J+K),J + 1,-1 - X(I) = X(I) + TEMP*A(L+I,J) - 50 CONTINUE - IF (NOUNIT) X(J) = X(J)*A(1,J) - END IF - 60 CONTINUE - ELSE - KX = KX + (N-1)*INCX - JX = KX - DO 80 J = N,1,-1 - IF (X(JX).NE.ZERO) THEN - TEMP = X(JX) - IX = KX - L = 1 - J - DO 70 I = MIN(N,J+K),J + 1,-1 - X(IX) = X(IX) + TEMP*A(L+I,J) - IX = IX - INCX - 70 CONTINUE - IF (NOUNIT) X(JX) = X(JX)*A(1,J) - END IF - JX = JX - INCX - IF ((N-J).GE.K) KX = KX - INCX - 80 CONTINUE - END IF - END IF - ELSE -* -* Form x := A'*x or x := conjg( A' )*x. -* - IF (LSAME(UPLO,'U')) THEN - KPLUS1 = K + 1 - IF (INCX.EQ.1) THEN - DO 110 J = N,1,-1 - TEMP = X(J) - L = KPLUS1 - J - IF (NOCONJ) THEN - IF (NOUNIT) TEMP = TEMP*A(KPLUS1,J) - DO 90 I = J - 1,MAX(1,J-K),-1 - TEMP = TEMP + A(L+I,J)*X(I) - 90 CONTINUE - ELSE - IF (NOUNIT) TEMP = TEMP*DCONJG(A(KPLUS1,J)) - DO 100 I = J - 1,MAX(1,J-K),-1 - TEMP = TEMP + DCONJG(A(L+I,J))*X(I) - 100 CONTINUE - END IF - X(J) = TEMP - 110 CONTINUE - ELSE - KX = KX + (N-1)*INCX - JX = KX - DO 140 J = N,1,-1 - TEMP = X(JX) - KX = KX - INCX - IX = KX - L = KPLUS1 - J - IF (NOCONJ) THEN - IF (NOUNIT) TEMP = TEMP*A(KPLUS1,J) - DO 120 I = J - 1,MAX(1,J-K),-1 - TEMP = TEMP + A(L+I,J)*X(IX) - IX = IX - INCX - 120 CONTINUE - ELSE - IF (NOUNIT) TEMP = TEMP*DCONJG(A(KPLUS1,J)) - DO 130 I = J - 1,MAX(1,J-K),-1 - TEMP = TEMP + DCONJG(A(L+I,J))*X(IX) - IX = IX - INCX - 130 CONTINUE - END IF - X(JX) = TEMP - JX = JX - INCX - 140 CONTINUE - END IF - ELSE - IF (INCX.EQ.1) THEN - DO 170 J = 1,N - TEMP = X(J) - L = 1 - J - IF (NOCONJ) THEN - IF (NOUNIT) TEMP = TEMP*A(1,J) - DO 150 I = J + 1,MIN(N,J+K) - TEMP = TEMP + A(L+I,J)*X(I) - 150 CONTINUE - ELSE - IF (NOUNIT) TEMP = TEMP*DCONJG(A(1,J)) - DO 160 I = J + 1,MIN(N,J+K) - TEMP = TEMP + DCONJG(A(L+I,J))*X(I) - 160 CONTINUE - END IF - X(J) = TEMP - 170 CONTINUE - ELSE - JX = KX - DO 200 J = 1,N - TEMP = X(JX) - KX = KX + INCX - IX = KX - L = 1 - J - IF (NOCONJ) THEN - IF (NOUNIT) TEMP = TEMP*A(1,J) - DO 180 I = J + 1,MIN(N,J+K) - TEMP = TEMP + A(L+I,J)*X(IX) - IX = IX + INCX - 180 CONTINUE - ELSE - IF (NOUNIT) TEMP = TEMP*DCONJG(A(1,J)) - DO 190 I = J + 1,MIN(N,J+K) - TEMP = TEMP + DCONJG(A(L+I,J))*X(IX) - IX = IX + INCX - 190 CONTINUE - END IF - X(JX) = TEMP - JX = JX + INCX - 200 CONTINUE - END IF - END IF - END IF -* - RETURN -* -* End of ZTBMV . -* - END diff --git a/ground/gcs/src/libs/eigen/cmake/Eigen3Config.cmake.in b/ground/gcs/src/libs/eigen/cmake/Eigen3Config.cmake.in new file mode 100644 index 0000000000..c5c5468877 --- /dev/null +++ b/ground/gcs/src/libs/eigen/cmake/Eigen3Config.cmake.in @@ -0,0 +1,21 @@ +# This file exports the Eigen3::Eigen CMake target which should be passed to the +# target_link_libraries command. + +@PACKAGE_INIT@ + +include ("${CMAKE_CURRENT_LIST_DIR}/Eigen3Targets.cmake") + +# Legacy variables, do *not* use. May be removed in the future. + +set (EIGEN3_FOUND 1) +set (EIGEN3_USE_FILE "${CMAKE_CURRENT_LIST_DIR}/UseEigen3.cmake") + +set (EIGEN3_DEFINITIONS "@EIGEN_DEFINITIONS@") +set (EIGEN3_INCLUDE_DIR "@PACKAGE_EIGEN_INCLUDE_DIR@") +set (EIGEN3_INCLUDE_DIRS "@PACKAGE_EIGEN_INCLUDE_DIR@") +set (EIGEN3_ROOT_DIR "@PACKAGE_EIGEN_ROOT_DIR@") + +set (EIGEN3_VERSION_STRING "@EIGEN_VERSION_STRING@") +set (EIGEN3_VERSION_MAJOR "@EIGEN_VERSION_MAJOR@") +set (EIGEN3_VERSION_MINOR "@EIGEN_VERSION_MINOR@") +set (EIGEN3_VERSION_PATCH "@EIGEN_VERSION_PATCH@") diff --git a/ground/gcs/src/libs/eigen/cmake/Eigen3ConfigLegacy.cmake.in b/ground/gcs/src/libs/eigen/cmake/Eigen3ConfigLegacy.cmake.in new file mode 100644 index 0000000000..62d722469b --- /dev/null +++ b/ground/gcs/src/libs/eigen/cmake/Eigen3ConfigLegacy.cmake.in @@ -0,0 +1,30 @@ +# -*- cmake -*- +# +# Eigen3Config.cmake(.in) + +# Use the following variables to compile and link against Eigen: +# EIGEN3_FOUND - True if Eigen was found on your system +# EIGEN3_USE_FILE - The file making Eigen usable +# EIGEN3_DEFINITIONS - Definitions needed to build with Eigen +# EIGEN3_INCLUDE_DIR - Directory where signature_of_eigen3_matrix_library can be found +# EIGEN3_INCLUDE_DIRS - List of directories of Eigen and it's dependencies +# EIGEN3_ROOT_DIR - The base directory of Eigen +# EIGEN3_VERSION_STRING - A human-readable string containing the version +# EIGEN3_VERSION_MAJOR - The major version of Eigen +# EIGEN3_VERSION_MINOR - The minor version of Eigen +# EIGEN3_VERSION_PATCH - The patch version of Eigen + +@PACKAGE_INIT@ + +set ( EIGEN3_FOUND 1 ) +set ( EIGEN3_USE_FILE "${CMAKE_CURRENT_LIST_DIR}/UseEigen3.cmake" ) + +set ( EIGEN3_DEFINITIONS "@EIGEN_DEFINITIONS@" ) +set ( EIGEN3_INCLUDE_DIR "@PACKAGE_EIGEN_INCLUDE_DIR@" ) +set ( EIGEN3_INCLUDE_DIRS "@PACKAGE_EIGEN_INCLUDE_DIR@" ) +set ( EIGEN3_ROOT_DIR "@PACKAGE_EIGEN_ROOT_DIR@" ) + +set ( EIGEN3_VERSION_STRING "@EIGEN_VERSION_STRING@" ) +set ( EIGEN3_VERSION_MAJOR "@EIGEN_VERSION_MAJOR@" ) +set ( EIGEN3_VERSION_MINOR "@EIGEN_VERSION_MINOR@" ) +set ( EIGEN3_VERSION_PATCH "@EIGEN_VERSION_PATCH@" ) diff --git a/ground/gcs/src/libs/eigen/cmake/EigenConfigureTesting.cmake b/ground/gcs/src/libs/eigen/cmake/EigenConfigureTesting.cmake index 2b11d8360d..afc24b5e99 100644 --- a/ground/gcs/src/libs/eigen/cmake/EigenConfigureTesting.cmake +++ b/ground/gcs/src/libs/eigen/cmake/EigenConfigureTesting.cmake @@ -14,17 +14,10 @@ add_dependencies(check buildtests) # check whether /bin/bash exists find_file(EIGEN_BIN_BASH_EXISTS "/bin/bash" PATHS "/" NO_DEFAULT_PATH) -# CMake/Ctest does not allow us to change the build command, -# so we have to workaround by directly editing the generated DartConfiguration.tcl file -# save CMAKE_MAKE_PROGRAM -set(CMAKE_MAKE_PROGRAM_SAVE ${CMAKE_MAKE_PROGRAM}) -# and set a fake one -set(CMAKE_MAKE_PROGRAM "@EIGEN_MAKECOMMAND_PLACEHOLDER@") - # This call activates testing and generates the DartConfiguration.tcl include(CTest) -set(EIGEN_TEST_BUILD_FLAGS " " CACHE STRING "Options passed to the build command of unit tests") +set(EIGEN_TEST_BUILD_FLAGS "" CACHE STRING "Options passed to the build command of unit tests") # Overwrite default DartConfiguration.tcl such that ctest can build our unit tests. # Recall that our unit tests are not in the "all" target, so we have to explicitely ask ctest to build our custom 'buildtests' target. @@ -53,18 +46,16 @@ if(CMAKE_COMPILER_IS_GNUCXX) if(EIGEN_COVERAGE_TESTING) set(COVERAGE_FLAGS "-fprofile-arcs -ftest-coverage") set(CTEST_CUSTOM_COVERAGE_EXCLUDE "/test/") - else(EIGEN_COVERAGE_TESTING) - set(COVERAGE_FLAGS "") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COVERAGE_FLAGS}") endif(EIGEN_COVERAGE_TESTING) - if(EIGEN_TEST_C++0x) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++0x") - endif(EIGEN_TEST_C++0x) - if(CMAKE_SYSTEM_NAME MATCHES Linux) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COVERAGE_FLAGS} -g2") - set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} ${COVERAGE_FLAGS} -O2 -g2") - set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${COVERAGE_FLAGS} -fno-inline-functions") - set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${COVERAGE_FLAGS} -O0 -g3") - endif(CMAKE_SYSTEM_NAME MATCHES Linux) + elseif(MSVC) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /D_CRT_SECURE_NO_WARNINGS /D_SCL_SECURE_NO_WARNINGS") endif(CMAKE_COMPILER_IS_GNUCXX) + + +check_cxx_compiler_flag("-std=c++11" EIGEN_COMPILER_SUPPORT_CXX11) + +if(EIGEN_TEST_CXX11 AND EIGEN_COMPILER_SUPPORT_CXX11) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") +endif() diff --git a/ground/gcs/src/libs/eigen/cmake/EigenDetermineOSVersion.cmake b/ground/gcs/src/libs/eigen/cmake/EigenDetermineOSVersion.cmake index 3c48d4c374..9246fa67c8 100644 --- a/ground/gcs/src/libs/eigen/cmake/EigenDetermineOSVersion.cmake +++ b/ground/gcs/src/libs/eigen/cmake/EigenDetermineOSVersion.cmake @@ -26,7 +26,7 @@ function(DetermineShortWindowsName WIN_VERSION win_num_version) endfunction() function(DetermineOSVersion OS_VERSION) - if (WIN32) + if (WIN32 AND CMAKE_HOST_SYSTEM_NAME MATCHES Windows) file (TO_NATIVE_PATH "$ENV{COMSPEC}" SHELL) exec_program( ${SHELL} ARGS "/c" "ver" OUTPUT_VARIABLE ver_output) diff --git a/ground/gcs/src/libs/eigen/cmake/EigenDetermineVSServicePack.cmake b/ground/gcs/src/libs/eigen/cmake/EigenDetermineVSServicePack.cmake index 8e5546a851..fed78194d2 100644 --- a/ground/gcs/src/libs/eigen/cmake/EigenDetermineVSServicePack.cmake +++ b/ground/gcs/src/libs/eigen/cmake/EigenDetermineVSServicePack.cmake @@ -4,7 +4,6 @@ include(CMakeDetermineVSServicePack) # _DetermineVSServicePack_FastCheckVersionWithCompiler which lead to errors on some systems. function(EigenDetermineVSServicePack _pack) if(NOT DETERMINED_VS_SERVICE_PACK OR NOT ${_pack}) - if(NOT DETERMINED_VS_SERVICE_PACK) _DetermineVSServicePack_CheckVersionWithTryCompile(DETERMINED_VS_SERVICE_PACK _cl_version) if(NOT DETERMINED_VS_SERVICE_PACK) @@ -13,10 +12,25 @@ function(EigenDetermineVSServicePack _pack) endif() if(DETERMINED_VS_SERVICE_PACK) - if(_cl_version) # Call helper function to determine VS version _DetermineVSServicePackFromCompiler(_sp "${_cl_version}") + + # temporary fix, until CMake catches up + if (NOT _sp) + if(${_cl_version} VERSION_EQUAL "17.00.50727.1") + set(_sp "vc110") + elseif(${_cl_version} VERSION_EQUAL "17.00.51106.1") + set(_sp "vc110sp1") + elseif(${_cl_version} VERSION_EQUAL "17.00.60315.1") + set(_sp "vc110sp2") + elseif(${_cl_version} VERSION_EQUAL "17.00.60610.1") + set(_sp "vc110sp3") + else() + set(_sp ${CMAKE_CXX_COMPILER_VERSION}) + endif() + endif() + if(_sp) set(${_pack} ${_sp} CACHE INTERNAL "The Visual Studio Release with Service Pack") diff --git a/ground/gcs/src/libs/eigen/cmake/EigenTesting.cmake b/ground/gcs/src/libs/eigen/cmake/EigenTesting.cmake index cbe12d51b8..a92a2978b0 100644 --- a/ground/gcs/src/libs/eigen/cmake/EigenTesting.cmake +++ b/ground/gcs/src/libs/eigen/cmake/EigenTesting.cmake @@ -1,19 +1,48 @@ macro(ei_add_property prop value) - get_property(previous GLOBAL PROPERTY ${prop}) + get_property(previous GLOBAL PROPERTY ${prop}) if ((NOT previous) OR (previous STREQUAL "")) set_property(GLOBAL PROPERTY ${prop} "${value}") else() set_property(GLOBAL PROPERTY ${prop} "${previous} ${value}") - endif() + endif() endmacro(ei_add_property) #internal. See documentation of ei_add_test for details. macro(ei_add_test_internal testname testname_with_suffix) set(targetname ${testname_with_suffix}) - set(filename ${testname}.cpp) - add_executable(${targetname} ${filename}) + if(EIGEN_ADD_TEST_FILENAME_EXTENSION) + set(filename ${testname}.${EIGEN_ADD_TEST_FILENAME_EXTENSION}) + else() + set(filename ${testname}.cpp) + endif() + + if(EIGEN_ADD_TEST_FILENAME_EXTENSION STREQUAL cu) + if(EIGEN_TEST_CUDA_CLANG) + set_source_files_properties(${filename} PROPERTIES LANGUAGE CXX) + if(CUDA_64_BIT_DEVICE_CODE) + link_directories("${CUDA_TOOLKIT_ROOT_DIR}/lib64") + else() + link_directories("${CUDA_TOOLKIT_ROOT_DIR}/lib") + endif() + if (${ARGC} GREATER 2) + add_executable(${targetname} ${filename}) + else() + add_executable(${targetname} ${filename} OPTIONS ${ARGV2}) + endif() + target_link_libraries(${targetname} "cudart_static" "cuda" "dl" "rt" "pthread") + else() + if (${ARGC} GREATER 2) + cuda_add_executable(${targetname} ${filename} OPTIONS ${ARGV2}) + else() + cuda_add_executable(${targetname} ${filename}) + endif() + endif() + else() + add_executable(${targetname} ${filename}) + endif() + if (targetname MATCHES "^eigen2_") add_dependencies(eigen2_buildtests ${targetname}) else() @@ -27,20 +56,20 @@ macro(ei_add_test_internal testname testname_with_suffix) ei_add_target_property(${targetname} COMPILE_FLAGS "-DEIGEN_DEBUG_ASSERTS=1") endif(EIGEN_DEBUG_ASSERTS) endif(EIGEN_NO_ASSERTION_CHECKING) - + ei_add_target_property(${targetname} COMPILE_FLAGS "-DEIGEN_TEST_MAX_SIZE=${EIGEN_TEST_MAX_SIZE}") ei_add_target_property(${targetname} COMPILE_FLAGS "-DEIGEN_TEST_FUNC=${testname}") - - if(MSVC AND NOT EIGEN_SPLIT_LARGE_TESTS) + + if(MSVC) ei_add_target_property(${targetname} COMPILE_FLAGS "/bigobj") - endif() + endif() # let the user pass flags. if(${ARGC} GREATER 2) ei_add_target_property(${targetname} COMPILE_FLAGS "${ARGV2}") endif(${ARGC} GREATER 2) - + if(EIGEN_TEST_CUSTOM_CXX_FLAGS) ei_add_target_property(${targetname} COMPILE_FLAGS "${EIGEN_TEST_CUSTOM_CXX_FLAGS}") endif() @@ -66,16 +95,12 @@ macro(ei_add_test_internal testname testname_with_suffix) # notice: no double quotes around ${libs_to_link} here. It may be a list. target_link_libraries(${targetname} ${libs_to_link}) endif() - endif() - - if(EIGEN_BIN_BASH_EXISTS) - add_test(${testname_with_suffix} "${Eigen_SOURCE_DIR}/test/runtest.sh" "${testname_with_suffix}") - else() - add_test(${testname_with_suffix} "${targetname}") endif() - + + add_test(${testname_with_suffix} "${targetname}") + # Specify target and test labels accoirding to EIGEN_CURRENT_SUBPROJECT - get_property(current_subproject GLOBAL PROPERTY EIGEN_CURRENT_SUBPROJECT) + get_property(current_subproject GLOBAL PROPERTY EIGEN_CURRENT_SUBPROJECT) if ((current_subproject) AND (NOT (current_subproject STREQUAL ""))) set_property(TARGET ${targetname} PROPERTY LABELS "Build${current_subproject}") add_dependencies("Build${current_subproject}" ${targetname}) @@ -84,6 +109,103 @@ macro(ei_add_test_internal testname testname_with_suffix) endmacro(ei_add_test_internal) +# SYCL +macro(ei_add_test_internal_sycl testname testname_with_suffix) + include_directories( SYSTEM ${COMPUTECPP_PACKAGE_ROOT_DIR}/include) + set(targetname ${testname_with_suffix}) + + if(EIGEN_ADD_TEST_FILENAME_EXTENSION) + set(filename ${testname}.${EIGEN_ADD_TEST_FILENAME_EXTENSION}) + else() + set(filename ${testname}.cpp) + endif() + + set( include_file ${CMAKE_CURRENT_BINARY_DIR}/inc_${filename}) + set( bc_file ${CMAKE_CURRENT_BINARY_DIR}/${filename}) + set( host_file ${CMAKE_CURRENT_SOURCE_DIR}/${filename}) + + ADD_CUSTOM_COMMAND( + OUTPUT ${include_file} + COMMAND ${CMAKE_COMMAND} -E echo "\\#include \\\"${host_file}\\\"" > ${include_file} + COMMAND ${CMAKE_COMMAND} -E echo "\\#include \\\"${bc_file}.sycl\\\"" >> ${include_file} + DEPENDS ${filename} ${bc_file}.sycl + COMMENT "Building ComputeCpp integration header file ${include_file}" + ) + # Add a custom target for the generated integration header + add_custom_target(${testname}_integration_header_sycl DEPENDS ${include_file}) + + add_executable(${targetname} ${include_file}) + add_dependencies(${targetname} ${testname}_integration_header_sycl) + add_sycl_to_target(${targetname} ${filename} ${CMAKE_CURRENT_BINARY_DIR}) + + if (targetname MATCHES "^eigen2_") + add_dependencies(eigen2_buildtests ${targetname}) + else() + add_dependencies(buildtests ${targetname}) + endif() + + if(EIGEN_NO_ASSERTION_CHECKING) + ei_add_target_property(${targetname} COMPILE_FLAGS "-DEIGEN_NO_ASSERTION_CHECKING=1") + else(EIGEN_NO_ASSERTION_CHECKING) + if(EIGEN_DEBUG_ASSERTS) + ei_add_target_property(${targetname} COMPILE_FLAGS "-DEIGEN_DEBUG_ASSERTS=1") + endif(EIGEN_DEBUG_ASSERTS) + endif(EIGEN_NO_ASSERTION_CHECKING) + + ei_add_target_property(${targetname} COMPILE_FLAGS "-DEIGEN_TEST_MAX_SIZE=${EIGEN_TEST_MAX_SIZE}") + + ei_add_target_property(${targetname} COMPILE_FLAGS "-DEIGEN_TEST_FUNC=${testname}") + + if(MSVC AND NOT EIGEN_SPLIT_LARGE_TESTS) + ei_add_target_property(${targetname} COMPILE_FLAGS "/bigobj") + endif() + + # let the user pass flags. + if(${ARGC} GREATER 2) + ei_add_target_property(${targetname} COMPILE_FLAGS "${ARGV2}") + endif(${ARGC} GREATER 2) + + if(EIGEN_TEST_CUSTOM_CXX_FLAGS) + ei_add_target_property(${targetname} COMPILE_FLAGS "${EIGEN_TEST_CUSTOM_CXX_FLAGS}") + endif() + + if(EIGEN_STANDARD_LIBRARIES_TO_LINK_TO) + target_link_libraries(${targetname} ${EIGEN_STANDARD_LIBRARIES_TO_LINK_TO}) + endif() + if(EXTERNAL_LIBS) + target_link_libraries(${targetname} ${EXTERNAL_LIBS}) + endif() + if(EIGEN_TEST_CUSTOM_LINKER_FLAGS) + target_link_libraries(${targetname} ${EIGEN_TEST_CUSTOM_LINKER_FLAGS}) + endif() + + if(${ARGC} GREATER 3) + set(libs_to_link ${ARGV3}) + # it could be that some cmake module provides a bad library string " " (just spaces), + # and that severely breaks target_link_libraries ("can't link to -l-lstdc++" errors). + # so we check for strings containing only spaces. + string(STRIP "${libs_to_link}" libs_to_link_stripped) + string(LENGTH "${libs_to_link_stripped}" libs_to_link_stripped_length) + if(${libs_to_link_stripped_length} GREATER 0) + # notice: no double quotes around ${libs_to_link} here. It may be a list. + target_link_libraries(${targetname} ${libs_to_link}) + endif() + endif() + + add_test(${testname_with_suffix} "${targetname}") + + # Specify target and test labels according to EIGEN_CURRENT_SUBPROJECT + get_property(current_subproject GLOBAL PROPERTY EIGEN_CURRENT_SUBPROJECT) + if ((current_subproject) AND (NOT (current_subproject STREQUAL ""))) + set_property(TARGET ${targetname} PROPERTY LABELS "Build${current_subproject}") + add_dependencies("Build${current_subproject}" ${targetname}) + set_property(TEST ${testname_with_suffix} PROPERTY LABELS "${current_subproject}") + endif() + + +endmacro(ei_add_test_internal_sycl) + + # Macro to add a test # # the unique mandatory parameter testname must correspond to a file @@ -131,7 +253,13 @@ macro(ei_add_test testname) set(EIGEN_TESTS_LIST "${EIGEN_TESTS_LIST}${testname}\n") set_property(GLOBAL PROPERTY EIGEN_TESTS_LIST "${EIGEN_TESTS_LIST}") - file(READ "${testname}.cpp" test_source) + if(EIGEN_ADD_TEST_FILENAME_EXTENSION) + set(filename ${testname}.${EIGEN_ADD_TEST_FILENAME_EXTENSION}) + else() + set(filename ${testname}.cpp) + endif() + + file(READ "${filename}" test_source) set(parts 0) string(REGEX MATCHALL "CALL_SUBTEST_[0-9]+|EIGEN_TEST_PART_[0-9]+|EIGEN_SUFFIXES(;[0-9]+)+" occurences "${test_source}") @@ -154,6 +282,39 @@ macro(ei_add_test testname) endif(EIGEN_SPLIT_LARGE_TESTS AND suffixes) endmacro(ei_add_test) +macro(ei_add_test_sycl testname) + get_property(EIGEN_TESTS_LIST GLOBAL PROPERTY EIGEN_TESTS_LIST) + set(EIGEN_TESTS_LIST "${EIGEN_TESTS_LIST}${testname}\n") + set_property(GLOBAL PROPERTY EIGEN_TESTS_LIST "${EIGEN_TESTS_LIST}") + + if(EIGEN_ADD_TEST_FILENAME_EXTENSION) + set(filename ${testname}.${EIGEN_ADD_TEST_FILENAME_EXTENSION}) + else() + set(filename ${testname}.cpp) + endif() + + file(READ "${filename}" test_source) + set(parts 0) + string(REGEX MATCHALL "CALL_SUBTEST_[0-9]+|EIGEN_TEST_PART_[0-9]+|EIGEN_SUFFIXES(;[0-9]+)+" + occurences "${test_source}") + string(REGEX REPLACE "CALL_SUBTEST_|EIGEN_TEST_PART_|EIGEN_SUFFIXES" "" suffixes "${occurences}") + list(REMOVE_DUPLICATES suffixes) + if(EIGEN_SPLIT_LARGE_TESTS AND suffixes) + add_custom_target(${testname}) + foreach(suffix ${suffixes}) + ei_add_test_internal_sycl(${testname} ${testname}_${suffix} + "${ARGV1} -DEIGEN_TEST_PART_${suffix}=1" "${ARGV2}") + add_dependencies(${testname} ${testname}_${suffix}) + endforeach(suffix) + else(EIGEN_SPLIT_LARGE_TESTS AND suffixes) + set(symbols_to_enable_all_parts "") + foreach(suffix ${suffixes}) + set(symbols_to_enable_all_parts + "${symbols_to_enable_all_parts} -DEIGEN_TEST_PART_${suffix}=1") + endforeach(suffix) + ei_add_test_internal_sycl(${testname} ${testname} "${ARGV1} ${symbols_to_enable_all_parts}" "${ARGV2}") + endif(EIGEN_SPLIT_LARGE_TESTS AND suffixes) +endmacro(ei_add_test_sycl) # adds a failtest, i.e. a test that succeed if the program fails to compile # note that the test runner for these is CMake itself, when passed -DEIGEN_FAILTEST=ON @@ -218,7 +379,7 @@ macro(ei_testing_print_summary) elseif(EIGEN_TEST_NO_EXPLICIT_VECTORIZATION) message(STATUS "Explicit vectorization disabled (alignment kept enabled)") else() - + message(STATUS "Maximal matrix/vector size: ${EIGEN_TEST_MAX_SIZE}") if(EIGEN_TEST_SSE2) @@ -251,18 +412,75 @@ macro(ei_testing_print_summary) message(STATUS "SSE4.2: Using architecture defaults") endif() + if(EIGEN_TEST_AVX) + message(STATUS "AVX: ON") + else() + message(STATUS "AVX: Using architecture defaults") + endif() + + if(EIGEN_TEST_FMA) + message(STATUS "FMA: ON") + else() + message(STATUS "FMA: Using architecture defaults") + endif() + + if(EIGEN_TEST_AVX512) + message(STATUS "AVX512: ON") + else() + message(STATUS "AVX512: Using architecture defaults") + endif() + if(EIGEN_TEST_ALTIVEC) message(STATUS "Altivec: ON") else() message(STATUS "Altivec: Using architecture defaults") endif() + if(EIGEN_TEST_VSX) + message(STATUS "VSX: ON") + else() + message(STATUS "VSX: Using architecture defaults") + endif() + if(EIGEN_TEST_NEON) message(STATUS "ARM NEON: ON") else() message(STATUS "ARM NEON: Using architecture defaults") endif() + if(EIGEN_TEST_NEON64) + message(STATUS "ARMv8 NEON: ON") + else() + message(STATUS "ARMv8 NEON: Using architecture defaults") + endif() + + if(EIGEN_TEST_ZVECTOR) + message(STATUS "S390X ZVECTOR: ON") + else() + message(STATUS "S390X ZVECTOR: Using architecture defaults") + endif() + + if(EIGEN_TEST_CXX11) + message(STATUS "C++11: ON") + else() + message(STATUS "C++11: OFF") + endif() + + if(EIGEN_TEST_SYCL) + message(STATUS "SYCL: ON") + else() + message(STATUS "SYCL: OFF") + endif() + if(EIGEN_TEST_CUDA) + if(EIGEN_TEST_CUDA_CLANG) + message(STATUS "CUDA: ON (using clang)") + else() + message(STATUS "CUDA: ON (using nvcc)") + endif() + else() + message(STATUS "CUDA: OFF") + endif() + endif() # vectorization / alignment options message(STATUS "\n${EIGEN_TESTING_SUMMARY}") @@ -287,7 +505,7 @@ macro(ei_init_testing) set_property(GLOBAL PROPERTY EIGEN_FAILTEST_FAILURE_COUNT "0") set_property(GLOBAL PROPERTY EIGEN_FAILTEST_COUNT "0") - + # uncomment anytime you change the ei_get_compilerver_from_cxx_version_string macro # ei_test_get_compilerver_from_cxx_version_string() endmacro(ei_init_testing) @@ -296,47 +514,47 @@ macro(ei_set_sitename) # if the sitename is not yet set, try to set it if(NOT ${SITE} OR ${SITE} STREQUAL "") set(eigen_computername $ENV{COMPUTERNAME}) - set(eigen_hostname $ENV{HOSTNAME}) + set(eigen_hostname $ENV{HOSTNAME}) if(eigen_hostname) set(SITE ${eigen_hostname}) - elseif(eigen_computername) - set(SITE ${eigen_computername}) + elseif(eigen_computername) + set(SITE ${eigen_computername}) endif() endif() # in case it is already set, enforce lower case if(SITE) string(TOLOWER ${SITE} SITE) - endif() + endif() endmacro(ei_set_sitename) macro(ei_get_compilerver VAR) - if(MSVC) - # on windows system, we use a modified CMake script - include(EigenDetermineVSServicePack) - EigenDetermineVSServicePack( my_service_pack ) + if(MSVC) + # on windows system, we use a modified CMake script + include(EigenDetermineVSServicePack) + EigenDetermineVSServicePack( my_service_pack ) - if( my_service_pack ) - set(${VAR} ${my_service_pack}) + if( my_service_pack ) + set(${VAR} ${my_service_pack}) + else() + set(${VAR} "na") + endif() else() - set(${VAR} "na") - endif() - else() # on all other system we rely on ${CMAKE_CXX_COMPILER} # supporting a "--version" or "/version" flag - + if(WIN32 AND ${CMAKE_CXX_COMPILER_ID} EQUAL "Intel") set(EIGEN_CXX_FLAG_VERSION "/version") else() set(EIGEN_CXX_FLAG_VERSION "--version") endif() - - execute_process(COMMAND ${CMAKE_CXX_COMPILER} ${EIGEN_CXX_FLAG_VERSION} + + execute_process(COMMAND ${CMAKE_CXX_COMPILER} ${EIGEN_CXX_FLAG_VERSION} OUTPUT_VARIABLE eigen_cxx_compiler_version_string OUTPUT_STRIP_TRAILING_WHITESPACE) string(REGEX REPLACE "[\n\r].*" "" eigen_cxx_compiler_version_string ${eigen_cxx_compiler_version_string}) - + ei_get_compilerver_from_cxx_version_string("${eigen_cxx_compiler_version_string}" CNAME CVER) set(${VAR} "${CNAME}-${CVER}") - + endif() endmacro(ei_get_compilerver) @@ -345,18 +563,20 @@ endmacro(ei_get_compilerver) # the testing macro call in ei_init_testing() of the EigenTesting.cmake file. # See also the ei_test_get_compilerver_from_cxx_version_string macro at the end of the file macro(ei_get_compilerver_from_cxx_version_string VERSTRING CNAME CVER) - # extract possible compiler names + # extract possible compiler names string(REGEX MATCH "g\\+\\+" ei_has_gpp ${VERSTRING}) string(REGEX MATCH "llvm|LLVM" ei_has_llvm ${VERSTRING}) string(REGEX MATCH "gcc|GCC" ei_has_gcc ${VERSTRING}) string(REGEX MATCH "icpc|ICC" ei_has_icpc ${VERSTRING}) string(REGEX MATCH "clang|CLANG" ei_has_clang ${VERSTRING}) - + # combine them if((ei_has_llvm) AND (ei_has_gpp OR ei_has_gcc)) set(${CNAME} "llvm-g++") elseif((ei_has_llvm) AND (ei_has_clang)) set(${CNAME} "llvm-clang++") + elseif(ei_has_clang) + set(${CNAME} "clang++") elseif(ei_has_icpc) set(${CNAME} "icpc") elseif(ei_has_gpp OR ei_has_gcc) @@ -364,7 +584,7 @@ macro(ei_get_compilerver_from_cxx_version_string VERSTRING CNAME CVER) else() set(${CNAME} "_") endif() - + # extract possible version numbers # first try to extract 3 isolated numbers: string(REGEX MATCH " [0-9]+\\.[0-9]+\\.[0-9]+" eicver ${VERSTRING}) @@ -382,9 +602,9 @@ macro(ei_get_compilerver_from_cxx_version_string VERSTRING CNAME CVER) endif() endif() endif() - + string(REGEX REPLACE ".(.*)" "\\1" ${CVER} ${eicver}) - + endmacro(ei_get_compilerver_from_cxx_version_string) macro(ei_get_cxxflags VAR) @@ -392,8 +612,18 @@ macro(ei_get_cxxflags VAR) ei_is_64bit_env(IS_64BIT_ENV) if(EIGEN_TEST_NEON) set(${VAR} NEON) + elseif(EIGEN_TEST_NEON64) + set(${VAR} NEON) + elseif(EIGEN_TEST_ZVECTOR) + set(${VAR} ZVECTOR) + elseif(EIGEN_TEST_VSX) + set(${VAR} VSX) elseif(EIGEN_TEST_ALTIVEC) set(${VAR} ALVEC) + elseif(EIGEN_TEST_FMA) + set(${VAR} FMA) + elseif(EIGEN_TEST_AVX) + set(${VAR} AVX) elseif(EIGEN_TEST_SSE4_2) set(${VAR} SSE42) elseif(EIGEN_TEST_SSE4_1) @@ -403,30 +633,30 @@ macro(ei_get_cxxflags VAR) elseif(EIGEN_TEST_SSE3) set(${VAR} SSE3) elseif(EIGEN_TEST_SSE2 OR IS_64BIT_ENV) - set(${VAR} SSE2) + set(${VAR} SSE2) endif() if(EIGEN_TEST_OPENMP) if (${VAR} STREQUAL "") - set(${VAR} OMP) - else() - set(${VAR} ${${VAR}}-OMP) - endif() + set(${VAR} OMP) + else() + set(${VAR} ${${VAR}}-OMP) + endif() endif() - + if(EIGEN_DEFAULT_TO_ROW_MAJOR) if (${VAR} STREQUAL "") - set(${VAR} ROW) - else() - set(${VAR} ${${VAR}}-ROWMAJ) - endif() + set(${VAR} ROW) + else() + set(${VAR} ${${VAR}}-ROWMAJ) + endif() endif() endmacro(ei_get_cxxflags) macro(ei_set_build_string) ei_get_compilerver(LOCAL_COMPILER_VERSION) ei_get_cxxflags(LOCAL_COMPILER_FLAGS) - + include(EigenDetermineOSVersion) DetermineOSVersion(OS_VERSION) @@ -442,7 +672,11 @@ macro(ei_set_build_string) else() set(TMP_BUILD_STRING ${TMP_BUILD_STRING}-64bit) endif() - + + if(EIGEN_TEST_CXX11) + set(TMP_BUILD_STRING ${TMP_BUILD_STRING}-cxx11) + endif() + if(EIGEN_BUILD_STRING_SUFFIX) set(TMP_BUILD_STRING ${TMP_BUILD_STRING}-${EIGEN_BUILD_STRING_SUFFIX}) endif() diff --git a/ground/gcs/src/libs/eigen/cmake/EigenUninstall.cmake b/ground/gcs/src/libs/eigen/cmake/EigenUninstall.cmake new file mode 100644 index 0000000000..4dae8c85c8 --- /dev/null +++ b/ground/gcs/src/libs/eigen/cmake/EigenUninstall.cmake @@ -0,0 +1,40 @@ +################ CMake Uninstall Template ####################### +# CMake Template file for uninstallation of files +# mentioned in 'install_manifest.txt' +# +# Used by uinstall target +################################################################# + +set(MANIFEST "${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt") + +if(EXISTS ${MANIFEST}) + message(STATUS "============== Uninstalling Eigen ===================") + + file(STRINGS ${MANIFEST} files) + foreach(file ${files}) + if(EXISTS ${file}) + message(STATUS "Removing file: '${file}'") + + execute_process( + COMMAND ${CMAKE_COMMAND} -E remove ${file} + OUTPUT_VARIABLE rm_out + RESULT_VARIABLE rm_retval + ) + + if(NOT "${rm_retval}" STREQUAL 0) + message(FATAL_ERROR "Failed to remove file: '${file}'.") + endif() + else() + message(STATUS "File '${file}' does not exist.") + endif() + endforeach(file) + + message(STATUS "========== Finished Uninstalling Eigen ==============") +else() + message(STATUS "Cannot find install manifest: '${MANIFEST}'") + message(STATUS "Probably make install has not been performed") + message(STATUS " or install_manifest.txt has been deleted.") +endif() + + + diff --git a/ground/gcs/src/libs/eigen/cmake/FindAdolc.cmake b/ground/gcs/src/libs/eigen/cmake/FindAdolc.cmake index 1a7ff3628a..937e549904 100644 --- a/ground/gcs/src/libs/eigen/cmake/FindAdolc.cmake +++ b/ground/gcs/src/libs/eigen/cmake/FindAdolc.cmake @@ -5,7 +5,7 @@ endif (ADOLC_INCLUDES AND ADOLC_LIBRARIES) find_path(ADOLC_INCLUDES NAMES - adolc/adouble.h + adolc/adtl.h PATHS $ENV{ADOLCDIR} ${INCLUDE_INSTALL_DIR} diff --git a/ground/gcs/src/libs/eigen/cmake/FindComputeCpp.cmake b/ground/gcs/src/libs/eigen/cmake/FindComputeCpp.cmake new file mode 100644 index 0000000000..07ebed61b9 --- /dev/null +++ b/ground/gcs/src/libs/eigen/cmake/FindComputeCpp.cmake @@ -0,0 +1,245 @@ +#.rst: +# FindComputeCpp +#--------------- +# +# Copyright 2016 Codeplay Software Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use these files except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +######################### +# FindComputeCpp.cmake +######################### +# +# Tools for finding and building with ComputeCpp. +# +# User must define COMPUTECPP_PACKAGE_ROOT_DIR pointing to the ComputeCpp +# installation. +# +# Latest version of this file can be found at: +# https://github.com/codeplaysoftware/computecpp-sdk + +# Require CMake version 3.2.2 or higher +cmake_minimum_required(VERSION 3.2.2) + +# Check that a supported host compiler can be found +if(CMAKE_COMPILER_IS_GNUCXX) + # Require at least gcc 4.8 + if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.8) + message(FATAL_ERROR + "host compiler - Not found! (gcc version must be at least 4.8)") + # Require the GCC dual ABI to be disabled for 5.1 or higher + elseif (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 5.1) + set(COMPUTECPP_DISABLE_GCC_DUAL_ABI "True") + message(STATUS + "host compiler - gcc ${CMAKE_CXX_COMPILER_VERSION} (note pre 5.1 gcc ABI enabled)") + else() + message(STATUS "host compiler - gcc ${CMAKE_CXX_COMPILER_VERSION}") + endif() +elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + # Require at least clang 3.6 + if (${CMAKE_CXX_COMPILER_VERSION} VERSION_LESS 3.6) + message(FATAL_ERROR + "host compiler - Not found! (clang version must be at least 3.6)") + else() + message(STATUS "host compiler - clang ${CMAKE_CXX_COMPILER_VERSION}") + endif() +else() + message(WARNING + "host compiler - Not found! (ComputeCpp supports GCC and Clang, see readme)") +endif() + +set(COMPUTECPP_64_BIT_DEFAULT ON) +option(COMPUTECPP_64_BIT_CODE "Compile device code in 64 bit mode" + ${COMPUTECPP_64_BIT_DEFAULT}) +mark_as_advanced(COMPUTECPP_64_BIT_CODE) + +# Find OpenCL package +find_package(OpenCL REQUIRED) + +# Find ComputeCpp packagee +if(NOT COMPUTECPP_PACKAGE_ROOT_DIR) + message(FATAL_ERROR + "ComputeCpp package - Not found! (please set COMPUTECPP_PACKAGE_ROOT_DIR") +else() + message(STATUS "ComputeCpp package - Found") +endif() +option(COMPUTECPP_PACKAGE_ROOT_DIR "Path to the ComputeCpp Package") + +# Obtain the path to compute++ +find_program(COMPUTECPP_DEVICE_COMPILER compute++ PATHS + ${COMPUTECPP_PACKAGE_ROOT_DIR} PATH_SUFFIXES bin) +if (EXISTS ${COMPUTECPP_DEVICE_COMPILER}) + mark_as_advanced(COMPUTECPP_DEVICE_COMPILER) + message(STATUS "compute++ - Found") +else() + message(FATAL_ERROR "compute++ - Not found! (${COMPUTECPP_DEVICE_COMPILER})") +endif() + +# Obtain the path to computecpp_info +find_program(COMPUTECPP_INFO_TOOL computecpp_info PATHS + ${COMPUTECPP_PACKAGE_ROOT_DIR} PATH_SUFFIXES bin) +if (EXISTS ${COMPUTECPP_INFO_TOOL}) + mark_as_advanced(${COMPUTECPP_INFO_TOOL}) + message(STATUS "computecpp_info - Found") +else() + message(FATAL_ERROR "computecpp_info - Not found! (${COMPUTECPP_INFO_TOOL})") +endif() + +# Obtain the path to the ComputeCpp runtime library +find_library(COMPUTECPP_RUNTIME_LIBRARY ComputeCpp PATHS ${COMPUTECPP_PACKAGE_ROOT_DIR} + HINTS ${COMPUTECPP_PACKAGE_ROOT_DIR}/lib PATH_SUFFIXES lib + DOC "ComputeCpp Runtime Library" NO_DEFAULT_PATH) + +if (EXISTS ${COMPUTECPP_RUNTIME_LIBRARY}) + mark_as_advanced(COMPUTECPP_RUNTIME_LIBRARY) + message(STATUS "libComputeCpp.so - Found") +else() + message(FATAL_ERROR "libComputeCpp.so - Not found!") +endif() + +# Obtain the ComputeCpp include directory +set(COMPUTECPP_INCLUDE_DIRECTORY ${COMPUTECPP_PACKAGE_ROOT_DIR}/include/) +if (NOT EXISTS ${COMPUTECPP_INCLUDE_DIRECTORY}) + message(FATAL_ERROR "ComputeCpp includes - Not found!") +else() + message(STATUS "ComputeCpp includes - Found") +endif() + +# Obtain the package version +execute_process(COMMAND ${COMPUTECPP_INFO_TOOL} "--dump-version" + OUTPUT_VARIABLE COMPUTECPP_PACKAGE_VERSION + RESULT_VARIABLE COMPUTECPP_INFO_TOOL_RESULT OUTPUT_STRIP_TRAILING_WHITESPACE) +if(NOT COMPUTECPP_INFO_TOOL_RESULT EQUAL "0") + message(FATAL_ERROR "Package version - Error obtaining version!") +else() + mark_as_advanced(COMPUTECPP_PACKAGE_VERSION) + message(STATUS "Package version - ${COMPUTECPP_PACKAGE_VERSION}") +endif() + +# Obtain the device compiler flags +execute_process(COMMAND ${COMPUTECPP_INFO_TOOL} "--dump-device-compiler-flags" + OUTPUT_VARIABLE COMPUTECPP_DEVICE_COMPILER_FLAGS + RESULT_VARIABLE COMPUTECPP_INFO_TOOL_RESULT OUTPUT_STRIP_TRAILING_WHITESPACE) +if(NOT COMPUTECPP_INFO_TOOL_RESULT EQUAL "0") + message(FATAL_ERROR "compute++ flags - Error obtaining compute++ flags!") +else() + mark_as_advanced(COMPUTECPP_COMPILER_FLAGS) + message(STATUS "compute++ flags - ${COMPUTECPP_DEVICE_COMPILER_FLAGS}") +endif() + +set(COMPUTECPP_DEVICE_COMPILER_FLAGS ${COMPUTECPP_DEVICE_COMPILER_FLAGS} -sycl-compress-name -no-serial-memop -DEIGEN_NO_ASSERTION_CHECKING=1) + +# Check if the platform is supported +execute_process(COMMAND ${COMPUTECPP_INFO_TOOL} "--dump-is-supported" + OUTPUT_VARIABLE COMPUTECPP_PLATFORM_IS_SUPPORTED + RESULT_VARIABLE COMPUTECPP_INFO_TOOL_RESULT OUTPUT_STRIP_TRAILING_WHITESPACE) +if(NOT COMPUTECPP_INFO_TOOL_RESULT EQUAL "0") + message(FATAL_ERROR "platform - Error checking platform support!") +else() + mark_as_advanced(COMPUTECPP_PLATFORM_IS_SUPPORTED) + if (COMPUTECPP_PLATFORM_IS_SUPPORTED) + message(STATUS "platform - your system can support ComputeCpp") + else() + message(STATUS "platform - your system CANNOT support ComputeCpp") + endif() +endif() + +#################### +# __build_sycl +#################### +# +# Adds a custom target for running compute++ and adding a dependency for the +# resulting integration header. +# +# targetName : Name of the target. +# sourceFile : Source file to be compiled. +# binaryDir : Intermediate directory to output the integration header. +# +function(__build_spir targetName sourceFile binaryDir) + + # Retrieve source file name. + get_filename_component(sourceFileName ${sourceFile} NAME) + + # Set the path to the Sycl file. + set(outputSyclFile ${binaryDir}/${sourceFileName}.sycl) + + # Add any user-defined include to the device compiler + get_property(includeDirectories DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY + INCLUDE_DIRECTORIES) + set(device_compiler_includes "") + foreach(directory ${includeDirectories}) + set(device_compiler_includes "-I${directory}" ${device_compiler_includes}) + endforeach() + if (CMAKE_INCLUDE_PATH) + foreach(directory ${CMAKE_INCLUDE_PATH}) + set(device_compiler_includes "-I${directory}" + ${device_compiler_includes}) + endforeach() + endif() + + # Convert argument list format + separate_arguments(COMPUTECPP_DEVICE_COMPILER_FLAGS) + + # Add custom command for running compute++ + add_custom_command( + OUTPUT ${outputSyclFile} + COMMAND ${COMPUTECPP_DEVICE_COMPILER} + ${COMPUTECPP_DEVICE_COMPILER_FLAGS} + -isystem ${COMPUTECPP_INCLUDE_DIRECTORY} + ${COMPUTECPP_PLATFORM_SPECIFIC_ARGS} + ${device_compiler_includes} + -o ${outputSyclFile} + -c ${CMAKE_CURRENT_SOURCE_DIR}/${sourceFile} + DEPENDS ${sourceFile} + WORKING_DIRECTORY ${binaryDir} + COMMENT "Building ComputeCpp integration header file ${outputSyclFile}") + + # Add a custom target for the generated integration header + add_custom_target(${targetName}_integration_header DEPENDS ${outputSyclFile}) + + # Add a dependency on the integration header + add_dependencies(${targetName} ${targetName}_integration_header) + + # Set the host compiler C++ standard to C++11 + set_property(TARGET ${targetName} PROPERTY CXX_STANDARD 11) + + # Disable GCC dual ABI on GCC 5.1 and higher + if(COMPUTECPP_DISABLE_GCC_DUAL_ABI) + set_property(TARGET ${targetName} APPEND PROPERTY COMPILE_DEFINITIONS + "_GLIBCXX_USE_CXX11_ABI=0") + endif() + +endfunction() + +####################### +# add_sycl_to_target +####################### +# +# Adds a SYCL compilation custom command associated with an existing +# target and sets a dependancy on that new command. +# +# targetName : Name of the target to add a SYCL to. +# sourceFile : Source file to be compiled for SYCL. +# binaryDir : Intermediate directory to output the integration header. +# +function(add_sycl_to_target targetName sourceFile binaryDir) + + # Add custom target to run compute++ and generate the integration header + __build_spir(${targetName} ${sourceFile} ${binaryDir}) + + # Link with the ComputeCpp runtime library + target_link_libraries(${targetName} PUBLIC ${COMPUTECPP_RUNTIME_LIBRARY} + PUBLIC ${OpenCL_LIBRARIES}) + +endfunction(add_sycl_to_target) diff --git a/ground/gcs/src/libs/eigen/cmake/FindEigen3.cmake b/ground/gcs/src/libs/eigen/cmake/FindEigen3.cmake index 9c546a05d8..9e96978608 100644 --- a/ground/gcs/src/libs/eigen/cmake/FindEigen3.cmake +++ b/ground/gcs/src/libs/eigen/cmake/FindEigen3.cmake @@ -9,6 +9,12 @@ # EIGEN3_FOUND - system has eigen lib with correct version # EIGEN3_INCLUDE_DIR - the eigen include directory # EIGEN3_VERSION - eigen version +# +# This module reads hints about search locations from +# the following enviroment variables: +# +# EIGEN3_ROOT +# EIGEN3_ROOT_DIR # Copyright (c) 2006, 2007 Montel Laurent, # Copyright (c) 2008, 2009 Gael Guennebaud, @@ -60,13 +66,23 @@ if (EIGEN3_INCLUDE_DIR) set(EIGEN3_FOUND ${EIGEN3_VERSION_OK}) else (EIGEN3_INCLUDE_DIR) - - find_path(EIGEN3_INCLUDE_DIR NAMES signature_of_eigen3_matrix_library - PATHS - ${CMAKE_INSTALL_PREFIX}/include - ${KDE4_INCLUDE_DIR} - PATH_SUFFIXES eigen3 eigen - ) + + # search first if an Eigen3Config.cmake is available in the system, + # if successful this would set EIGEN3_INCLUDE_DIR and the rest of + # the script will work as usual + find_package(Eigen3 ${Eigen3_FIND_VERSION} NO_MODULE QUIET) + + if(NOT EIGEN3_INCLUDE_DIR) + find_path(EIGEN3_INCLUDE_DIR NAMES signature_of_eigen3_matrix_library + HINTS + ENV EIGEN3_ROOT + ENV EIGEN3_ROOT_DIR + PATHS + ${CMAKE_INSTALL_PREFIX}/include + ${KDE4_INCLUDE_DIR} + PATH_SUFFIXES eigen3 eigen + ) + endif(NOT EIGEN3_INCLUDE_DIR) if(EIGEN3_INCLUDE_DIR) _eigen3_check_version() diff --git a/ground/gcs/src/libs/eigen/cmake/FindSuperLU.cmake b/ground/gcs/src/libs/eigen/cmake/FindSuperLU.cmake index 8a3df36668..f38146e06c 100644 --- a/ground/gcs/src/libs/eigen/cmake/FindSuperLU.cmake +++ b/ground/gcs/src/libs/eigen/cmake/FindSuperLU.cmake @@ -17,10 +17,81 @@ find_path(SUPERLU_INCLUDES SRC ) -find_library(SUPERLU_LIBRARIES superlu PATHS $ENV{SUPERLUDIR} ${LIB_INSTALL_DIR} PATH_SUFFIXES lib) - +find_library(SUPERLU_LIBRARIES + NAMES "superlu_5.2.1" "superlu_5.2" "superlu_5.1.1" "superlu_5.1" "superlu_5.0" "superlu_4.3" "superlu_4.2" "superlu_4.1" "superlu_4.0" "superlu_3.1" "superlu_3.0" "superlu" + PATHS $ENV{SUPERLUDIR} ${LIB_INSTALL_DIR} + PATH_SUFFIXES lib) + +if(SUPERLU_INCLUDES AND SUPERLU_LIBRARIES) + +include(CheckCXXSourceCompiles) +include(CMakePushCheckState) +cmake_push_check_state() + +set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES} ${SUPERLU_INCLUDES}) + +# check whether struct mem_usage_t is globally defined +check_cxx_source_compiles(" +typedef int int_t; +#include +#include +int main() { + mem_usage_t mem; + return 0; +}" +SUPERLU_HAS_GLOBAL_MEM_USAGE_T) + + +check_cxx_source_compiles(" +typedef int int_t; +#include +#include +int main() { + return SLU_SINGLE; +}" +SUPERLU_HAS_CLEAN_ENUMS) + +check_cxx_source_compiles(" +typedef int int_t; +#include +#include +int main(void) +{ + GlobalLU_t glu; + return 0; +}" +SUPERLU_HAS_GLOBALLU_T) + +if(SUPERLU_HAS_GLOBALLU_T) + # at least 5.0 + set(SUPERLU_VERSION_VAR "5.0") +elseif(SUPERLU_HAS_CLEAN_ENUMS) + # at least 4.3 + set(SUPERLU_VERSION_VAR "4.3") +elseif(SUPERLU_HAS_GLOBAL_MEM_USAGE_T) + # at least 4.0 + set(SUPERLU_VERSION_VAR "4.0") +else() + set(SUPERLU_VERSION_VAR "3.0") +endif() + +cmake_pop_check_state() + +if(SuperLU_FIND_VERSION) + if(${SUPERLU_VERSION_VAR} VERSION_LESS ${SuperLU_FIND_VERSION}) + set(SUPERLU_VERSION_OK FALSE) + else() + set(SUPERLU_VERSION_OK TRUE) + endif() +else() + set(SUPERLU_VERSION_OK TRUE) +endif() + +endif() + include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(SUPERLU DEFAULT_MSG - SUPERLU_INCLUDES SUPERLU_LIBRARIES) +find_package_handle_standard_args(SUPERLU + REQUIRED_VARS SUPERLU_INCLUDES SUPERLU_LIBRARIES SUPERLU_VERSION_OK + VERSION_VAR SUPERLU_VERSION_VAR) mark_as_advanced(SUPERLU_INCLUDES SUPERLU_LIBRARIES) diff --git a/ground/gcs/src/libs/eigen/cmake/UseEigen3.cmake b/ground/gcs/src/libs/eigen/cmake/UseEigen3.cmake new file mode 100644 index 0000000000..a38bac82d5 --- /dev/null +++ b/ground/gcs/src/libs/eigen/cmake/UseEigen3.cmake @@ -0,0 +1,6 @@ +# -*- cmake -*- +# +# UseEigen3.cmake + +add_definitions ( ${EIGEN3_DEFINITIONS} ) +include_directories ( ${EIGEN3_INCLUDE_DIRS} ) diff --git a/ground/gcs/src/libs/eigen/cmake/language_support.cmake b/ground/gcs/src/libs/eigen/cmake/language_support.cmake index 231f7ff703..2f14f30b84 100644 --- a/ground/gcs/src/libs/eigen/cmake/language_support.cmake +++ b/ground/gcs/src/libs/eigen/cmake/language_support.cmake @@ -43,7 +43,7 @@ function(workaround_9220 language language_works) if(return_code EQUAL 0) # Second run execute_process ( - COMMAND ${CMAKE_COMMAND} . + COMMAND ${CMAKE_COMMAND} . -G "${CMAKE_GENERATOR}" WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/language_tests/${language} RESULT_VARIABLE return_code OUTPUT_QUIET @@ -64,3 +64,4 @@ endfunction(workaround_9220) #message("CXX_language_works = ${CXX_language_works}") #workaround_9220(CXXp CXXp_language_works) #message("CXXp_language_works = ${CXXp_language_works}") + diff --git a/ground/gcs/src/libs/eigen/debug/gdb/printers.py b/ground/gcs/src/libs/eigen/debug/gdb/printers.py index 86996a4f9f..0d67a5f998 100644 --- a/ground/gcs/src/libs/eigen/debug/gdb/printers.py +++ b/ground/gcs/src/libs/eigen/debug/gdb/printers.py @@ -49,7 +49,7 @@ def __init__(self, variety, val): regex = re.compile('\<.*\>') m = regex.findall(tag)[0][1:-1] template_params = m.split(',') - template_params = map(lambda x:x.replace(" ", ""), template_params) + template_params = [x.replace(" ", "") for x in template_params] if template_params[1] == '-0x00000000000000001' or template_params[1] == '-0x000000001' or template_params[1] == '-1': self.rows = val['m_storage']['m_rows'] @@ -88,8 +88,11 @@ def __init__ (self, rows, cols, dataPtr, rowMajor): def __iter__ (self): return self - + def next(self): + return self.__next__() # Python 2.x compatibility + + def __next__(self): row = self.currentRow col = self.currentCol @@ -151,8 +154,11 @@ def __init__ (self, dataPtr): def __iter__ (self): return self - + def next(self): + return self.__next__() # Python 2.x compatibility + + def __next__(self): element = self.currentElement if self.currentElement >= 4: #there are 4 elements in a quanternion diff --git a/ground/gcs/src/libs/eigen/demos/opengl/quaternion_demo.cpp b/ground/gcs/src/libs/eigen/demos/opengl/quaternion_demo.cpp index 04165619b0..dd323a4c96 100644 --- a/ground/gcs/src/libs/eigen/demos/opengl/quaternion_demo.cpp +++ b/ground/gcs/src/libs/eigen/demos/opengl/quaternion_demo.cpp @@ -234,7 +234,7 @@ void RenderingWidget::drawScene() gpu.drawVector(Vector3f::Zero(), length*Vector3f::UnitZ(), Color(0,0,1,1)); // draw the fractal object - float sqrt3 = internal::sqrt(3.); + float sqrt3 = std::sqrt(3.); glLightfv(GL_LIGHT0, GL_AMBIENT, Vector4f(0.5,0.5,0.5,1).data()); glLightfv(GL_LIGHT0, GL_DIFFUSE, Vector4f(0.5,1,0.5,1).data()); glLightfv(GL_LIGHT0, GL_SPECULAR, Vector4f(1,1,1,1).data()); diff --git a/ground/gcs/src/libs/eigen/demos/opengl/trackball.cpp b/ground/gcs/src/libs/eigen/demos/opengl/trackball.cpp index 77ac790c84..7c2da8e965 100644 --- a/ground/gcs/src/libs/eigen/demos/opengl/trackball.cpp +++ b/ground/gcs/src/libs/eigen/demos/opengl/trackball.cpp @@ -23,7 +23,7 @@ void Trackball::track(const Vector2i& point2D) { Vector3f axis = mLastPoint3D.cross(newPoint3D).normalized(); float cos_angle = mLastPoint3D.dot(newPoint3D); - if ( internal::abs(cos_angle) < 1.0 ) + if ( std::abs(cos_angle) < 1.0 ) { float angle = 2. * acos(cos_angle); if (mMode==Around) diff --git a/ground/gcs/src/libs/eigen/doc/A05_PortingFrom2To3.dox b/ground/gcs/src/libs/eigen/doc/A05_PortingFrom2To3.dox index 4d5f3ae1ff..51555f9967 100644 --- a/ground/gcs/src/libs/eigen/doc/A05_PortingFrom2To3.dox +++ b/ground/gcs/src/libs/eigen/doc/A05_PortingFrom2To3.dox @@ -2,8 +2,6 @@ namespace Eigen { /** \page Eigen2ToEigen3 Porting from Eigen2 to Eigen3 -
Eigen2 support is deprecated in Eigen 3.2.x and it will be removed in Eigen 3.3.
- This page lists the most important API changes between Eigen2 and Eigen3, and gives tips to help porting your application from Eigen2 to Eigen3. @@ -11,11 +9,8 @@ and gives tips to help porting your application from Eigen2 to Eigen3. \section CompatibilitySupport Eigen2 compatibility support -In order to ease the switch from Eigen2 to Eigen3, Eigen3 features \subpage Eigen2SupportModes "Eigen2 support modes". - -The quick way to enable this is to define the \c EIGEN2_SUPPORT preprocessor token \b before including any Eigen header (typically it should be set in your project options). - -A more powerful, \em staged migration path is also provided, which may be useful to migrate larger projects from Eigen2 to Eigen3. This is explained in the \ref Eigen2SupportModes "Eigen 2 support modes" page. +Up to version 3.2 %Eigen provides Eigen2 support modes. These are removed now, because they were barely used anymore and became hard to maintain after internal re-designs. +You can still use them by first porting your code to Eigen 3.2. \section Using The USING_PART_OF_NAMESPACE_EIGEN macro @@ -228,7 +223,7 @@ triangular part to work on \section GeometryModule Changes in the Geometry module -The Geometry module is the one that changed the most. If you rely heavily on it, it's probably a good idea to use the \ref Eigen2SupportModes "Eigen 2 support modes" to perform your migration. +The Geometry module is the one that changed the most. If you rely heavily on it, it's probably a good idea to use the "Eigen 2 support modes" to perform your migration. \section Transform The Transform class @@ -266,7 +261,7 @@ use it unless you are sure of what you are doing, i.e., you have rigourosly meas The EIGEN_ALIGN_128 macro has been renamed to EIGEN_ALIGN16. Don't be surprised, it's just that we switched to counting in bytes ;-) -The EIGEN_DONT_ALIGN option still exists in Eigen 3, but it has a new cousin: EIGEN_DONT_ALIGN_STATICALLY. It allows to get rid of all static alignment issues while keeping alignment of dynamic-size heap-allocated arrays, thus keeping vectorization for dynamic-size objects. +The \link TopicPreprocessorDirectivesPerformance EIGEN_DONT_ALIGN \endlink option still exists in Eigen 3, but it has a new cousin: \link TopicPreprocessorDirectivesPerformance EIGEN_DONT_ALIGN_STATICALLY.\endlink It allows to get rid of all static alignment issues while keeping alignment of dynamic-size heap-allocated arrays. Vectorization of statically allocated arrays is still preserved (unless you define \link TopicPreprocessorDirectivesPerformance EIGEN_UNALIGNED_VECTORIZE \endlink =0), at the cost of unaligned memory stores. \section AlignedMap Aligned Map objects @@ -283,7 +278,7 @@ result = Vector4f::MapAligned(some_aligned_array); \section StdContainers STL Containers -In Eigen2, #include tweaked std::vector to automatically align elements. The problem was that that was quite invasive. In Eigen3, we only override standard behavior if you use Eigen::aligned_allocator as your allocator type. So for example, if you use std::vector, you need to do the following change (note that aligned_allocator is under namespace Eigen): +In Eigen2, \#include\ tweaked std::vector to automatically align elements. The problem was that that was quite invasive. In Eigen3, we only override standard behavior if you use Eigen::aligned_allocator as your allocator type. So for example, if you use std::vector, you need to do the following change (note that aligned_allocator is under namespace Eigen): diff --git a/ground/gcs/src/libs/eigen/doc/A10_Eigen2SupportModes.dox b/ground/gcs/src/libs/eigen/doc/A10_Eigen2SupportModes.dox deleted file mode 100644 index f3df91515a..0000000000 --- a/ground/gcs/src/libs/eigen/doc/A10_Eigen2SupportModes.dox +++ /dev/null @@ -1,95 +0,0 @@ -namespace Eigen { - -/** \page Eigen2SupportModes Eigen 2 support modes - -
Eigen2 support is deprecated in Eigen 3.2.x and it will be removed in Eigen 3.3.
- -This page documents the Eigen2 support modes, a powerful tool to help migrating your project from Eigen 2 to Eigen 3. -Don't miss our page on \ref Eigen2ToEigen3 "API changes" between Eigen 2 and Eigen 3. - -\eigenAutoToc - -\section EIGEN2_SUPPORT_Macro The quick way: define EIGEN2_SUPPORT - -By defining EIGEN2_SUPPORT before including any Eigen 3 header, you get back a large part of the Eigen 2 API, while keeping the Eigen 3 API and ABI unchanged. - -This defaults to the \ref Stage30 "stage 30" described below. - -The rest of this page describes an optional, more powerful \em staged migration path. - -\section StagedMigrationPathOverview Overview of the staged migration path - -The primary reason why EIGEN2_SUPPORT alone may not be enough to migrate a large project from Eigen 2 to Eigen 3 is that some of the Eigen 2 API is inherently incompatible with the Eigen 3 API. This happens when the same identifier is used in Eigen 2 and in Eigen 3 with different meanings. To help migrate projects that rely on such API, we provide a staged migration path allowing to perform the migration \em incrementally. - -It goes as follows: -\li Step 0: start with a project using Eigen 2. -\li Step 1: build your project against Eigen 3 with \ref Stage10 "Eigen 2 support stage 10". This mode enables maximum compatibility with the Eigen 2 API, with just a few exceptions. -\li Step 2: build your project against Eigen 3 with \ref Stage20 "Eigen 2 support stage 20". This mode forces you to add eigen2_ prefixes to the Eigen2 identifiers that conflict with Eigen 3 API. -\li Step 3: build your project against Eigen 3 with \ref Stage30 "Eigen 2 support stage 30". This mode enables the full Eigen 3 API. -\li Step 4: build your project against Eigen 3 with \ref Stage40 "Eigen 2 support stage 40". This mode enables the full Eigen 3 strictness on matters, such as const-correctness, where Eigen 2 was looser. -\li Step 5: build your project against Eigen 3 without any Eigen 2 support mode. - -\section Stage10 Stage 10: define EIGEN2_SUPPORT_STAGE10_FULL_EIGEN2_API - -Enable this mode by defining the EIGEN2_SUPPORT_STAGE10_FULL_EIGEN2_API preprocessor macro before including any Eigen 3 header. - -This mode maximizes support for the Eigen 2 API. As a result, it does not offer the full Eigen 3 API. Also, it doesn't offer quite 100% of the Eigen 2 API. - -The part of the Eigen 3 API that is not present in this mode, is Eigen 3's Geometry module. Indeed, this mode completely replaces it by a copy of Eigen 2's Geometry module. - -The parts of the API that are still not 100% Eigen 2 compatible in this mode are: -\li Dot products over complex numbers. Eigen 2's dot product was linear in the first variable. Eigen 3's dot product is linear in the second variable. In other words, the Eigen 2 code \code x.dot(y) \endcode is equivalent to the Eigen 3 code \code y.dot(x) \endcode In yet other words, dot products are complex-conjugated in Eigen 3 compared to Eigen 2. The switch to the new convention was commanded by common usage, especially with the notation \f$ x^Ty \f$ for dot products of column-vectors. -\li The Sparse module. -\li Certain fine details of linear algebraic decompositions. For example, LDLT decomposition is now pivoting in Eigen 3 whereas it wasn't in Eigen 2, so code that was relying on its underlying matrix structure will break. -\li Usage of Eigen types in STL containers, \ref Eigen2ToEigen3 "as explained on this page". - -\section Stage20 Stage 20: define EIGEN2_SUPPORT_STAGE20_RESOLVE_API_CONFLICTS - -Enable this mode by defining the EIGEN2_SUPPORT_STAGE10_FULL_EIGEN2_API preprocessor macro before including any Eigen 3 header. - -This mode removes the Eigen 2 API that is directly conflicting with Eigen 3 API. Instead, these bits of Eigen 2 API remain available with eigen2_ prefixes. The main examples of such API are: -\li the whole Geometry module. For example, replace \c Quaternion by \c eigen2_Quaternion, replace \c Transform3f by \c eigen2_Transform3f, etc. -\li the lu() method to obtain a LU decomposition. Replace by eigen2_lu(). - -There is also one more eigen2_-prefixed identifier that you should know about, even though its use is not checked at compile time by this mode: the dot() method. As was discussed above, over complex numbers, its meaning is different between Eigen 2 and Eigen 3. You can use eigen2_dot() to get the Eigen 2 behavior. - -\section Stage30 Stage 30: define EIGEN2_SUPPORT_STAGE30_FULL_EIGEN3_API - -Enable this mode by defining the EIGEN2_SUPPORT_STAGE30_FULL_EIGEN3_API preprocessor macro before including any Eigen 3 header. Also, this mode is what you get by default when you just define EIGEN2_SUPPORT. - -This mode gives you the full unaltered Eigen 3 API, while still keeping as much support as possible for the Eigen 2 API. - -The eigen2_-prefixed identifiers are still available, but at this stage you should now replace them by Eigen 3 identifiers. Have a look at our page on \ref Eigen2ToEigen3 "API changes" between Eigen 2 and Eigen 3. - -\section Stage40 Stage 40: define EIGEN2_SUPPORT_STAGE40_FULL_EIGEN3_STRICTNESS - -Enable this mode by defining the EIGEN2_SUPPORT_STAGE40_FULL_EIGEN3_STRICTNESS preprocessor macro before including any Eigen 3 header. - -This mode tightens the last bits of strictness, especially const-correctness, that had to be loosened to support what Eigen 2 allowed. For example, this code compiled in Eigen 2: -\code -const float array[4]; -x = Map(array); -\endcode -That allowed to circumvent constness. This is no longer allowed in Eigen 3. If you have to map const data in Eigen 3, map it as a const-qualified type. However, rather than explictly constructing Map objects, we strongly encourage you to use the static Map methods instead, as they take care of all of this for you: -\code -const float array[4]; -x = Vector4f::Map(array); -\endcode -This lets Eigen do the right thing for you and works equally well in Eigen 2 and in Eigen 3. - -\section FinallyDropAllEigen2Support Finally drop all Eigen 2 support - -Stage 40 is the first where it's "comfortable" to stay for a little longer period, since it preserves 100% Eigen 3 compatibility. However, we still encourage you to complete your migration as quickly as possible. While we do run the Eigen 2 test suite against Eigen 3's stage 10 support mode, we can't guarantee the same level of support and quality assurance for Eigen 2 support as we do for Eigen 3 itself, especially not in the long term. \ref Eigen2ToEigen3 "This page" describes a large part of the changes that you may need to perform. - -\section ABICompatibility What about ABI compatibility? - -It goes as follows: -\li Stage 10 already is ABI compatible with Eigen 3 for the basic (Matrix, Array, SparseMatrix...) types. However, since this stage uses a copy of Eigen 2's Geometry module instead of Eigen 3's own Geometry module, the ABI in the Geometry module is not Eigen 3 compatible. -\li Stage 20 removes the Eigen 3-incompatible Eigen 2 Geometry module (it remains available with eigen2_ prefix). So at this stage, all the identifiers that exist in Eigen 3 have the Eigen 3 ABI (and API). -\li Stage 30 introduces the remaining Eigen 3 identifiers. So at this stage, you have the full Eigen 3 ABI. -\li Stage 40 is no different than Stage 30 in these matters. - - -*/ - -} diff --git a/ground/gcs/src/libs/eigen/doc/AsciiQuickReference.txt b/ground/gcs/src/libs/eigen/doc/AsciiQuickReference.txt index b9f497f87e..8409f88506 100644 --- a/ground/gcs/src/libs/eigen/doc/AsciiQuickReference.txt +++ b/ground/gcs/src/libs/eigen/doc/AsciiQuickReference.txt @@ -32,17 +32,19 @@ A << 1, 2, 3, // Initialize A. The elements can also be B << A, A, A; // B is three horizontally stacked A's. A.fill(10); // Fill A with all 10's. -// Eigen // Matlab -MatrixXd::Identity(rows,cols) // eye(rows,cols) -C.setIdentity(rows,cols) // C = eye(rows,cols) -MatrixXd::Zero(rows,cols) // zeros(rows,cols) -C.setZero(rows,cols) // C = ones(rows,cols) -MatrixXd::Ones(rows,cols) // ones(rows,cols) -C.setOnes(rows,cols) // C = ones(rows,cols) -MatrixXd::Random(rows,cols) // rand(rows,cols)*2-1 // MatrixXd::Random returns uniform random numbers in (-1, 1). -C.setRandom(rows,cols) // C = rand(rows,cols)*2-1 -VectorXd::LinSpaced(size,low,high) // linspace(low,high,size)' -v.setLinSpaced(size,low,high) // v = linspace(low,high,size)' +// Eigen // Matlab +MatrixXd::Identity(rows,cols) // eye(rows,cols) +C.setIdentity(rows,cols) // C = eye(rows,cols) +MatrixXd::Zero(rows,cols) // zeros(rows,cols) +C.setZero(rows,cols) // C = zeros(rows,cols) +MatrixXd::Ones(rows,cols) // ones(rows,cols) +C.setOnes(rows,cols) // C = ones(rows,cols) +MatrixXd::Random(rows,cols) // rand(rows,cols)*2-1 // MatrixXd::Random returns uniform random numbers in (-1, 1). +C.setRandom(rows,cols) // C = rand(rows,cols)*2-1 +VectorXd::LinSpaced(size,low,high) // linspace(low,high,size)' +v.setLinSpaced(size,low,high) // v = linspace(low,high,size)' +VectorXi::LinSpaced(((hi-low)/step)+1, // low:step:hi + low,low+step*(size-1)) // // Matrix slicing and blocks. All expressions listed here are read/write. @@ -82,17 +84,20 @@ P.bottomRightCorner() // P(end-rows+1:end, end-cols+1:end) // Of particular note is Eigen's swap function which is highly optimized. // Eigen // Matlab -R.row(i) = P.col(j); // R(i, :) = P(:, i) +R.row(i) = P.col(j); // R(i, :) = P(:, j) R.col(j1).swap(mat1.col(j2)); // R(:, [j1 j2]) = R(:, [j2, j1]) -// Views, transpose, etc; all read-write except for .adjoint(). +// Views, transpose, etc; // Eigen // Matlab R.adjoint() // R' -R.transpose() // R.' or conj(R') -R.diagonal() // diag(R) +R.transpose() // R.' or conj(R') // Read-write +R.diagonal() // diag(R) // Read-write x.asDiagonal() // diag(x) -R.transpose().colwise().reverse(); // rot90(R) -R.conjugate() // conj(R) +R.transpose().colwise().reverse() // rot90(R) // Read-write +R.rowwise().reverse() // fliplr(R) +R.colwise().reverse() // flipud(R) +R.replicate(i,j) // repmat(P,i,j) + // All the same as Matlab, but matlab doesn't have *= style operators. // Matrix-vector. Matrix-matrix. Matrix-scalar. @@ -104,37 +109,40 @@ a *= M; R = P + Q; R = P/s; R -= Q; R /= s; // Vectorized operations on each element independently -// Eigen // Matlab -R = P.cwiseProduct(Q); // R = P .* Q -R = P.array() * s.array();// R = P .* s -R = P.cwiseQuotient(Q); // R = P ./ Q -R = P.array() / Q.array();// R = P ./ Q -R = P.array() + s.array();// R = P + s -R = P.array() - s.array();// R = P - s -R.array() += s; // R = R + s -R.array() -= s; // R = R - s -R.array() < Q.array(); // R < Q -R.array() <= Q.array(); // R <= Q -R.cwiseInverse(); // 1 ./ P -R.array().inverse(); // 1 ./ P -R.array().sin() // sin(P) -R.array().cos() // cos(P) -R.array().pow(s) // P .^ s -R.array().square() // P .^ 2 -R.array().cube() // P .^ 3 -R.cwiseSqrt() // sqrt(P) -R.array().sqrt() // sqrt(P) -R.array().exp() // exp(P) -R.array().log() // log(P) -R.cwiseMax(P) // max(R, P) -R.array().max(P.array()) // max(R, P) -R.cwiseMin(P) // min(R, P) -R.array().min(P.array()) // min(R, P) -R.cwiseAbs() // abs(P) -R.array().abs() // abs(P) -R.cwiseAbs2() // abs(P.^2) -R.array().abs2() // abs(P.^2) -(R.array() < s).select(P,Q); // (R < s ? P : Q) +// Eigen // Matlab +R = P.cwiseProduct(Q); // R = P .* Q +R = P.array() * s.array(); // R = P .* s +R = P.cwiseQuotient(Q); // R = P ./ Q +R = P.array() / Q.array(); // R = P ./ Q +R = P.array() + s.array(); // R = P + s +R = P.array() - s.array(); // R = P - s +R.array() += s; // R = R + s +R.array() -= s; // R = R - s +R.array() < Q.array(); // R < Q +R.array() <= Q.array(); // R <= Q +R.cwiseInverse(); // 1 ./ P +R.array().inverse(); // 1 ./ P +R.array().sin() // sin(P) +R.array().cos() // cos(P) +R.array().pow(s) // P .^ s +R.array().square() // P .^ 2 +R.array().cube() // P .^ 3 +R.cwiseSqrt() // sqrt(P) +R.array().sqrt() // sqrt(P) +R.array().exp() // exp(P) +R.array().log() // log(P) +R.cwiseMax(P) // max(R, P) +R.array().max(P.array()) // max(R, P) +R.cwiseMin(P) // min(R, P) +R.array().min(P.array()) // min(R, P) +R.cwiseAbs() // abs(P) +R.array().abs() // abs(P) +R.cwiseAbs2() // abs(P.^2) +R.array().abs2() // abs(P.^2) +(R.array() < s).select(P,Q ); // (R < s ? P : Q) +R = (Q.array()==0).select(P,A) // R(Q==0) = P(Q==0) +R = P.unaryExpr(ptr_fun(func)) // R = arrayfun(func, P) // with: scalar func(const scalar &x); + // Reductions. int r, c; @@ -165,12 +173,12 @@ x.dot(y) // dot(x, y) x.cross(y) // cross(x, y) Requires #include //// Type conversion -// Eigen // Matlab -A.cast(); // double(A) -A.cast(); // single(A) -A.cast(); // int32(A) -A.real(); // real(A) -A.imag(); // imag(A) +// Eigen // Matlab +A.cast(); // double(A) +A.cast(); // single(A) +A.cast(); // int32(A) +A.real(); // real(A) +A.imag(); // imag(A) // if the original type equals destination type, no work is done // Note that for most operations Eigen requires all operands to have the same type: diff --git a/ground/gcs/src/libs/eigen/doc/B01_Experimental.dox b/ground/gcs/src/libs/eigen/doc/B01_Experimental.dox index 5fc0ccd609..e1f031db84 100644 --- a/ground/gcs/src/libs/eigen/doc/B01_Experimental.dox +++ b/ground/gcs/src/libs/eigen/doc/B01_Experimental.dox @@ -4,7 +4,7 @@ namespace Eigen { \eigenAutoToc -\section summary Summary +\section Experimental_summary Summary With the 2.0 release, Eigen's API is, to a large extent, stable. However, we wish to retain the freedom to make API incompatible changes. To that effect, we call many parts of Eigen "experimental" which means that they are not subject to API stability guarantee. @@ -17,7 +17,7 @@ Experimental features may at any time: \li be subject to an API incompatible change; \li introduce API or ABI incompatible changes in your own code if you let them affect your API or ABI. -\section modules Experimental modules +\section Experimental_modules Experimental modules The following modules are considered entirely experimental, and we make no firm API stability guarantee about them for the time being: \li SVD @@ -26,7 +26,7 @@ The following modules are considered entirely experimental, and we make no firm \li Sparse \li Geometry (this one should be mostly stable, but it's a little too early to make a formal guarantee) -\section core Experimental parts of the Core module +\section Experimental_core Experimental parts of the Core module In the Core module, the only classes subject to ABI stability guarantee (meaning that you can use it for data members in your public ABI) is: \li Matrix diff --git a/ground/gcs/src/libs/eigen/doc/CMakeLists.txt b/ground/gcs/src/libs/eigen/doc/CMakeLists.txt index 02790ee43d..db413bc656 100644 --- a/ground/gcs/src/libs/eigen/doc/CMakeLists.txt +++ b/ground/gcs/src/libs/eigen/doc/CMakeLists.txt @@ -10,12 +10,20 @@ if(CMAKE_COMPILER_IS_GNUCXX) endif(CMAKE_SYSTEM_NAME MATCHES Linux) endif(CMAKE_COMPILER_IS_GNUCXX) +option(EIGEN_INTERNAL_DOCUMENTATION "Build internal documentation" OFF) + + # Set some Doxygen flags set(EIGEN_DOXY_PROJECT_NAME "Eigen") set(EIGEN_DOXY_OUTPUT_DIRECTORY_SUFFIX "") set(EIGEN_DOXY_INPUT "\"${Eigen_SOURCE_DIR}/Eigen\" \"${Eigen_SOURCE_DIR}/doc\"") set(EIGEN_DOXY_HTML_COLORSTYLE_HUE "220") set(EIGEN_DOXY_TAGFILES "") +if(EIGEN_INTERNAL_DOCUMENTATION) + set(EIGEN_DOXY_INTERNAL "YES") +else(EIGEN_INTERNAL_DOCUMENTATION) + set(EIGEN_DOXY_INTERNAL "NO") +endif(EIGEN_INTERNAL_DOCUMENTATION) configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in @@ -70,6 +78,8 @@ add_custom_target( COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/html/ COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/eigen_navtree_hacks.js ${CMAKE_CURRENT_BINARY_DIR}/html/ COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/Eigen_Silly_Professor_64x64.png ${CMAKE_CURRENT_BINARY_DIR}/html/ + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/ftv2pnode.png ${CMAKE_CURRENT_BINARY_DIR}/html/ + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/ftv2node.png ${CMAKE_CURRENT_BINARY_DIR}/html/ COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/AsciiQuickReference.txt ${CMAKE_CURRENT_BINARY_DIR}/html/ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) @@ -80,6 +90,8 @@ add_custom_target( COMMAND ${CMAKE_COMMAND} -E make_directory ${Eigen_BINARY_DIR}/doc/html/unsupported COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/eigen_navtree_hacks.js ${CMAKE_CURRENT_BINARY_DIR}/html/unsupported/ COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/Eigen_Silly_Professor_64x64.png ${CMAKE_CURRENT_BINARY_DIR}/html/unsupported/ + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/ftv2pnode.png ${CMAKE_CURRENT_BINARY_DIR}/html/unsupported/ + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/ftv2node.png ${CMAKE_CURRENT_BINARY_DIR}/html/unsupported/ WORKING_DIRECTORY ${Eigen_BINARY_DIR}/doc ) diff --git a/ground/gcs/src/libs/eigen/doc/CoeffwiseMathFunctionsTable.dox b/ground/gcs/src/libs/eigen/doc/CoeffwiseMathFunctionsTable.dox new file mode 100644 index 0000000000..3ae9420dc6 --- /dev/null +++ b/ground/gcs/src/libs/eigen/doc/CoeffwiseMathFunctionsTable.dox @@ -0,0 +1,525 @@ +namespace Eigen { + +/** \eigenManualPage CoeffwiseMathFunctions Catalog of coefficient-wise math functions + + + + +This table presents a catalog of the coefficient-wise math functions supported by %Eigen. +In this table, \c a, \c b, refer to Array objects or expressions, and \c m refers to a linear algebra Matrix/Vector object. Standard scalar types are abbreviated as follows: + - \c int: \c i32 + - \c float: \c f + - \c double: \c d + - \c std::complex: \c cf + - \c std::complex: \c cd + +For each row, the first column list the equivalent calls for arrays, and matrices when supported. Of course, all functions are available for matrices by first casting it as an array: \c m.array(). + +The third column gives some hints in the underlying scalar implementation. In most cases, %Eigen does not implement itself the math function but relies on the STL for standard scalar types, or user-provided functions for custom scalar types. +For instance, some simply calls the respective function of the STL while preserving argument-dependent lookup for custom types. +The following: +\code +using std::foo; +foo(a[i]); +\endcode +means that the STL's function \c std::foo will be potentially called if it is compatible with the underlying scalar type. If not, then the user must ensure that an overload of the function foo is available for the given scalar type (usually defined in the same namespace as the given scalar type). +This also means that, unless specified, if the function \c std::foo is available only in some recent c++ versions (e.g., c++11), then the respective %Eigen's function/method will be usable on standard types only if the compiler support the required c++ version. + +
Eigen 2Eigen 3
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
APIDescriptionDefault scalar implementationSIMD
Basic operations
+ \anchor cwisetable_abs + a.\link ArrayBase::abs abs\endlink(); \n + \link Eigen::abs abs\endlink(a); \n + m.\link MatrixBase::cwiseAbs cwiseAbs\endlink(); + absolute value (\f$ |a_i| \f$) + using std::abs; \n + abs(a[i]); + SSE2, AVX (i32,f,d)
+ \anchor cwisetable_inverse + a.\link ArrayBase::inverse inverse\endlink(); \n + \link Eigen::inverse inverse\endlink(a); \n + m.\link MatrixBase::cwiseInverse cwiseInverse\endlink(); + inverse value (\f$ 1/a_i \f$) + 1/a[i]; + All engines (f,d,fc,fd)
+ \anchor cwisetable_conj + a.\link ArrayBase::conjugate conjugate\endlink(); \n + \link Eigen::conj conj\endlink(a); \n + m.\link MatrixBase::conjugate conjugate(); + complex conjugate (\f$ \bar{a_i} \f$),\n + no-op for real + using std::conj; \n + conj(a[i]); + All engines (fc,fd)
Exponential functions
+ \anchor cwisetable_exp + a.\link ArrayBase::exp exp\endlink(); \n + \link Eigen::exp exp\endlink(a); + \f$ e \f$ raised to the given power (\f$ e^{a_i} \f$) + using std::exp; \n + exp(a[i]); + SSE2, AVX (f,d)
+ \anchor cwisetable_log + a.\link ArrayBase::log log\endlink(); \n + \link Eigen::log log\endlink(a); + natural (base \f$ e \f$) logarithm (\f$ \ln({a_i}) \f$) + using std::log; \n + log(a[i]); + SSE2, AVX (f)
+ \anchor cwisetable_log1p + a.\link ArrayBase::log1p log1p\endlink(); \n + \link Eigen::log1p log1p\endlink(a); + natural (base \f$ e \f$) logarithm of 1 plus \n the given number (\f$ \ln({1+a_i}) \f$)built-in generic implementation based on \c log,\n + plus \c using \c std::log1p ; \cpp11
+ \anchor cwisetable_log10 + a.\link ArrayBase::log10 log10\endlink(); \n + \link Eigen::log10 log10\endlink(a); + base 10 logarithm (\f$ \log_{10}({a_i}) \f$) + using std::log10; \n + log10(a[i]); +
Power functions
+ \anchor cwisetable_pow + a.\link ArrayBase::pow pow\endlink(b); \n + \link Eigen::pow pow\endlink(a,b); + raises a number to the given power (\f$ a_i ^ {b_i} \f$) \n \c a and \c b can be either an array or scalar. + using std::pow; \n + pow(a[i],b[i]);\n + (plus builtin for integer types)
+ \anchor cwisetable_sqrt + a.\link ArrayBase::sqrt sqrt\endlink(); \n + \link Eigen::sqrt sqrt\endlink(a);\n + m.\link MatrixBase::cwiseSqrt cwiseSqrt\endlink(); + computes square root (\f$ \sqrt a_i \f$) + using std::sqrt; \n + sqrt(a[i]);SSE2, AVX (f,d)
+ \anchor cwisetable_rsqrt + a.\link ArrayBase::rsqrt rsqrt\endlink(); \n + \link Eigen::rsqrt rsqrt\endlink(a); + reciprocal square root (\f$ 1/{\sqrt a_i} \f$) + using std::sqrt; \n + 1/sqrt(a[i]); \n + SSE2, AVX, AltiVec, ZVector (f,d)\n + (approx + 1 Newton iteration)
+ \anchor cwisetable_square + a.\link ArrayBase::square square\endlink(); \n + \link Eigen::square square\endlink(a); + computes square power (\f$ a_i^2 \f$) + a[i]*a[i]All (i32,f,d,cf,cd)
+ \anchor cwisetable_cube + a.\link ArrayBase::cube cube\endlink(); \n + \link Eigen::cube cube\endlink(a); + computes cubic power (\f$ a_i^3 \f$) + a[i]*a[i]*a[i]All (i32,f,d,cf,cd)
+ \anchor cwisetable_abs2 + a.\link ArrayBase::abs2 abs2\endlink(); \n + \link Eigen::abs2 abs2\endlink(a);\n + m.\link MatrixBase::cwiseAbs2 cwiseAbs2\endlink(); + computes the squared absolute value (\f$ |a_i|^2 \f$) + real: a[i]*a[i] \n + complex: real(a[i])*real(a[i]) \n +        + imag(a[i])*imag(a[i])All (i32,f,d)
Trigonometric functions
+ \anchor cwisetable_sin + a.\link ArrayBase::sin sin\endlink(); \n + \link Eigen::sin sin\endlink(a); + computes sine + using std::sin; \n + sin(a[i]);SSE2, AVX (f)
+ \anchor cwisetable_cos + a.\link ArrayBase::cos cos\endlink(); \n + \link Eigen::cos cos\endlink(a); + computes cosine + using std::cos; \n + cos(a[i]);SSE2, AVX (f)
+ \anchor cwisetable_tan + a.\link ArrayBase::tan tan\endlink(); \n + \link Eigen::tan tan\endlink(a); + computes tangent + using std::tan; \n + tan(a[i]);
+ \anchor cwisetable_asin + a.\link ArrayBase::asin asin\endlink(); \n + \link Eigen::asin asin\endlink(a); + computes arc sine (\f$ \sin^{-1} a_i \f$) + using std::asin; \n + asin(a[i]);
+ \anchor cwisetable_acos + a.\link ArrayBase::acos acos\endlink(); \n + \link Eigen::acos acos\endlink(a); + computes arc cosine (\f$ \cos^{-1} a_i \f$) + using std::acos; \n + acos(a[i]);
+ \anchor cwisetable_atan + a.\link ArrayBase::atan tan\endlink(); \n + \link Eigen::atan atan\endlink(a); + computes arc tangent (\f$ \tan^{-1} a_i \f$) + using std::atan; \n + atan(a[i]);
Hyperbolic functions
+ \anchor cwisetable_sinh + a.\link ArrayBase::sinh sinh\endlink(); \n + \link Eigen::sinh sinh\endlink(a); + computes hyperbolic sine + using std::sinh; \n + sinh(a[i]);
+ \anchor cwisetable_cosh + a.\link ArrayBase::cosh cohs\endlink(); \n + \link Eigen::cosh cosh\endlink(a); + computes hyperbolic cosine + using std::cosh; \n + cosh(a[i]);
+ \anchor cwisetable_tanh + a.\link ArrayBase::tanh tanh\endlink(); \n + \link Eigen::tanh tanh\endlink(a); + computes hyperbolic tangent + using std::tanh; \n + tanh(a[i]);
Nearest integer floating point operations
+ \anchor cwisetable_ceil + a.\link ArrayBase::ceil ceil\endlink(); \n + \link Eigen::ceil ceil\endlink(a); + nearest integer not less than the given value + using std::ceil; \n + ceil(a[i]);SSE4,AVX,ZVector (f,d)
+ \anchor cwisetable_floor + a.\link ArrayBase::floor floor\endlink(); \n + \link Eigen::floor floor\endlink(a); + nearest integer not greater than the given value + using std::floor; \n + floor(a[i]);SSE4,AVX,ZVector (f,d)
+ \anchor cwisetable_round + a.\link ArrayBase::round round\endlink(); \n + \link Eigen::round round\endlink(a); + nearest integer, \n rounding away from zero in halfway casesbuilt-in generic implementation \n based on \c floor and \c ceil,\n + plus \c using \c std::round ; \cpp11SSE4,AVX,ZVector (f,d)
Floating point manipulation functions
Classification and comparison
+ \anchor cwisetable_isfinite + a.\link ArrayBase::isFinite isFinite\endlink(); \n + \link Eigen::isfinite isfinite\endlink(a); + checks if the given number has finite valuebuilt-in generic implementation,\n + plus \c using \c std::isfinite ; \cpp11
+ \anchor cwisetable_isinf + a.\link ArrayBase::isInf isInf\endlink(); \n + \link Eigen::isinf isinf\endlink(a); + checks if the given number is infinitebuilt-in generic implementation,\n + plus \c using \c std::isinf ; \cpp11
+ \anchor cwisetable_isnan + a.\link ArrayBase::isNaN isNaN\endlink(); \n + \link Eigen::isnan isnan\endlink(a); + checks if the given number is not a numberbuilt-in generic implementation,\n + plus \c using \c std::isnan ; \cpp11
Error and gamma functions
Require \c \#include \c
+ \anchor cwisetable_erf + a.\link ArrayBase::erf erf\endlink(); \n + \link Eigen::erf erf\endlink(a); + error function + using std::erf; \cpp11 \n + erf(a[i]); +
+ \anchor cwisetable_erfc + a.\link ArrayBase::erfc erfc\endlink(); \n + \link Eigen::erfc erfc\endlink(a); + complementary error function + using std::erfc; \cpp11 \n + erfc(a[i]); +
+ \anchor cwisetable_lgamma + a.\link ArrayBase::lgamma lgamma\endlink(); \n + \link Eigen::lgamma lgamma\endlink(a); + natural logarithm of the gamma function + using std::lgamma; \cpp11 \n + lgamma(a[i]); +
+ \anchor cwisetable_digamma + a.\link ArrayBase::digamma digamma\endlink(); \n + \link Eigen::digamma digamma\endlink(a); + logarithmic derivative of the gamma function + built-in for float and double +
+ \anchor cwisetable_igamma + \link Eigen::igamma igamma\endlink(a,x); + lower incomplete gamma integral + \n \f$ \gamma(a_i,x_i)= \frac{1}{|a_i|} \int_{0}^{x_i}e^{\text{-}t} t^{a_i-1} \mathrm{d} t \f$ + built-in for float and double,\n but requires \cpp11 +
+ \anchor cwisetable_igammac + \link Eigen::igammac igammac\endlink(a,x); + upper incomplete gamma integral + \n \f$ \Gamma(a_i,x_i) = \frac{1}{|a_i|} \int_{x_i}^{\infty}e^{\text{-}t} t^{a_i-1} \mathrm{d} t \f$ + built-in for float and double,\n but requires \cpp11 +
Special functions
Require \c \#include \c
+ \anchor cwisetable_polygamma + \link Eigen::polygamma polygamma\endlink(n,x); + n-th derivative of digamma at x + built-in generic based on\n \c lgamma , + \c digamma + and \c zeta . +
+ \anchor cwisetable_betainc + \link Eigen::betainc betainc\endlink(a,b,x); + Incomplete beta function + built-in for float and double,\n but requires \cpp11 +
+ \anchor cwisetable_zeta + \link Eigen::zeta zeta\endlink(a,b); + Hurwitz zeta function + \n \f$ \zeta(a_i,b_i)=\sum_{k=0}^{\infty}(b_i+k)^{\text{-}a_i} \f$ + built-in for float and double +
+ +\n + +*/ + +} diff --git a/ground/gcs/src/libs/eigen/doc/CustomizingEigen.dox b/ground/gcs/src/libs/eigen/doc/CustomizingEigen.dox deleted file mode 100644 index 5a0890ea9d..0000000000 --- a/ground/gcs/src/libs/eigen/doc/CustomizingEigen.dox +++ /dev/null @@ -1,188 +0,0 @@ -namespace Eigen { - -/** \page TopicCustomizingEigen Customizing/Extending Eigen - -Eigen can be extended in several ways, for instance, by defining global methods, \ref ExtendingMatrixBase "by adding custom methods to MatrixBase", adding support to \ref CustomScalarType "custom types" etc. - -\eigenAutoToc - -\section ExtendingMatrixBase Extending MatrixBase (and other classes) - -In this section we will see how to add custom methods to MatrixBase. Since all expressions and matrix types inherit MatrixBase, adding a method to MatrixBase make it immediately available to all expressions ! A typical use case is, for instance, to make Eigen compatible with another API. - -You certainly know that in C++ it is not possible to add methods to an existing class. So how that's possible ? Here the trick is to include in the declaration of MatrixBase a file defined by the preprocessor token \c EIGEN_MATRIXBASE_PLUGIN: -\code -class MatrixBase { - // ... - #ifdef EIGEN_MATRIXBASE_PLUGIN - #include EIGEN_MATRIXBASE_PLUGIN - #endif -}; -\endcode -Therefore to extend MatrixBase with your own methods you just have to create a file with your method declaration and define EIGEN_MATRIXBASE_PLUGIN before you include any Eigen's header file. - -You can extend many of the other classes used in Eigen by defining similarly named preprocessor symbols. For instance, define \c EIGEN_ARRAYBASE_PLUGIN if you want to extend the ArrayBase class. A full list of classes that can be extended in this way and the corresponding preprocessor symbols can be found on our page \ref TopicPreprocessorDirectives. - -Here is an example of an extension file for adding methods to MatrixBase: \n -\b MatrixBaseAddons.h -\code -inline Scalar at(uint i, uint j) const { return this->operator()(i,j); } -inline Scalar& at(uint i, uint j) { return this->operator()(i,j); } -inline Scalar at(uint i) const { return this->operator[](i); } -inline Scalar& at(uint i) { return this->operator[](i); } - -inline RealScalar squaredLength() const { return squaredNorm(); } -inline RealScalar length() const { return norm(); } -inline RealScalar invLength(void) const { return fast_inv_sqrt(squaredNorm()); } - -template -inline Scalar squaredDistanceTo(const MatrixBase& other) const -{ return (derived() - other.derived()).squaredNorm(); } - -template -inline RealScalar distanceTo(const MatrixBase& other) const -{ return internal::sqrt(derived().squaredDistanceTo(other)); } - -inline void scaleTo(RealScalar l) { RealScalar vl = norm(); if (vl>1e-9) derived() *= (l/vl); } - -inline Transpose transposed() {return this->transpose();} -inline const Transpose transposed() const {return this->transpose();} - -inline uint minComponentId(void) const { int i; this->minCoeff(&i); return i; } -inline uint maxComponentId(void) const { int i; this->maxCoeff(&i); return i; } - -template -void makeFloor(const MatrixBase& other) { derived() = derived().cwiseMin(other.derived()); } -template -void makeCeil(const MatrixBase& other) { derived() = derived().cwiseMax(other.derived()); } - -const CwiseUnaryOp, Derived> -operator+(const Scalar& scalar) const -{ return CwiseUnaryOp, Derived>(derived(), internal::scalar_add_op(scalar)); } - -friend const CwiseUnaryOp, Derived> -operator+(const Scalar& scalar, const MatrixBase& mat) -{ return CwiseUnaryOp, Derived>(mat.derived(), internal::scalar_add_op(scalar)); } -\endcode - -Then one can the following declaration in the config.h or whatever prerequisites header file of his project: -\code -#define EIGEN_MATRIXBASE_PLUGIN "MatrixBaseAddons.h" -\endcode - -\section InheritingFromMatrix Inheriting from Matrix - -Before inheriting from Matrix, be really, i mean REALLY sure that using -EIGEN_MATRIX_PLUGIN is not what you really want (see previous section). -If you just need to add few members to Matrix, this is the way to go. - -An example of when you actually need to inherit Matrix, is when you have -several layers of heritage such as MyVerySpecificVector1,MyVerySpecificVector1 -> MyVector1 -> Matrix and. -MyVerySpecificVector3,MyVerySpecificVector4 -> MyVector2 -> Matrix. - -In order for your object to work within the %Eigen framework, you need to -define a few members in your inherited class. - -Here is a minimalistic example:\n -\code -class MyVectorType : public Eigen::VectorXd -{ -public: - MyVectorType(void):Eigen::VectorXd() {} - - typedef Eigen::VectorXd Base; - - // This constructor allows you to construct MyVectorType from Eigen expressions - template - MyVectorType(const Eigen::MatrixBase& other) - : Eigen::Vector3d(other) - { } - - // This method allows you to assign Eigen expressions to MyVectorType - template - MyVectorType & operator= (const Eigen::MatrixBase & other) - { - this->Base::operator=(other); - return *this; - } -}; -\endcode - -This is the kind of error you can get if you don't provide those methods -\code -error: no match for ‘operator=’ in ‘delta = -(((Eigen::MatrixBase, 10000, 1, 2, 10000, -1> >*)(& delta)) + 8u)->Eigen::MatrixBase::cwise [with Derived = -Eigen::Matrix, 10000, 1, 2, 10000, -1>]().Eigen::Cwise::operator* [with OtherDerived = -Eigen::Matrix, 10000, 1, 2, 10000, 1>, ExpressionType = -Eigen::Matrix, 10000, 1, 2, 10000, 1>](((const -Eigen::MatrixBase, 10000, 1, 2, 10000, 1> ->&)(((const Eigen::MatrixBase, 10000, 1, ->2, 10000, 1> >*)((const spectral1d*)where)) + 8u)))’ -\endcode - -\anchor user_defined_scalars \section CustomScalarType Using custom scalar types - -By default, Eigen currently supports standard floating-point types (\c float, \c double, \c std::complex, \c std::complex, \c long \c double), as well as all native integer types (e.g., \c int, \c unsigned \c int, \c short, etc.), and \c bool. -On x86-64 systems, \c long \c double permits to locally enforces the use of x87 registers with extended accuracy (in comparison to SSE). - -In order to add support for a custom type \c T you need: --# make sure the common operator (+,-,*,/,etc.) are supported by the type \c T --# add a specialization of struct Eigen::NumTraits (see \ref NumTraits) --# define the math functions that makes sense for your type. This includes standard ones like sqrt, pow, sin, tan, conj, real, imag, etc, as well as abs2 which is Eigen specific. - (see the file Eigen/src/Core/MathFunctions.h) - -The math function should be defined in the same namespace than \c T, or in the \c std namespace though that second approach is not recommended. - -Here is a concrete example adding support for the Adolc's \c adouble type. Adolc is an automatic differentiation library. The type \c adouble is basically a real value tracking the values of any number of partial derivatives. - -\code -#ifndef ADOLCSUPPORT_H -#define ADOLCSUPPORT_H - -#define ADOLC_TAPELESS -#include -#include - -namespace Eigen { - -template<> struct NumTraits - : NumTraits // permits to get the epsilon, dummy_precision, lowest, highest functions -{ - typedef adtl::adouble Real; - typedef adtl::adouble NonInteger; - typedef adtl::adouble Nested; - - enum { - IsComplex = 0, - IsInteger = 0, - IsSigned = 1, - RequireInitialization = 1, - ReadCost = 1, - AddCost = 3, - MulCost = 3 - }; -}; - -} - -namespace adtl { - -inline const adouble& conj(const adouble& x) { return x; } -inline const adouble& real(const adouble& x) { return x; } -inline adouble imag(const adouble&) { return 0.; } -inline adouble abs(const adouble& x) { return fabs(x); } -inline adouble abs2(const adouble& x) { return x*x; } - -} - -#endif // ADOLCSUPPORT_H -\endcode - - -\sa \ref TopicPreprocessorDirectives - -*/ - -} diff --git a/ground/gcs/src/libs/eigen/doc/CustomizingEigen_CustomScalar.dox b/ground/gcs/src/libs/eigen/doc/CustomizingEigen_CustomScalar.dox new file mode 100644 index 0000000000..1ee78cbe5f --- /dev/null +++ b/ground/gcs/src/libs/eigen/doc/CustomizingEigen_CustomScalar.dox @@ -0,0 +1,120 @@ +namespace Eigen { + +/** \page TopicCustomizing_CustomScalar Using custom scalar types +\anchor user_defined_scalars + +By default, Eigen currently supports standard floating-point types (\c float, \c double, \c std::complex, \c std::complex, \c long \c double), as well as all native integer types (e.g., \c int, \c unsigned \c int, \c short, etc.), and \c bool. +On x86-64 systems, \c long \c double permits to locally enforces the use of x87 registers with extended accuracy (in comparison to SSE). + +In order to add support for a custom type \c T you need: +-# make sure the common operator (+,-,*,/,etc.) are supported by the type \c T +-# add a specialization of struct Eigen::NumTraits (see \ref NumTraits) +-# define the math functions that makes sense for your type. This includes standard ones like sqrt, pow, sin, tan, conj, real, imag, etc, as well as abs2 which is Eigen specific. + (see the file Eigen/src/Core/MathFunctions.h) + +The math function should be defined in the same namespace than \c T, or in the \c std namespace though that second approach is not recommended. + +Here is a concrete example adding support for the Adolc's \c adouble type. Adolc is an automatic differentiation library. The type \c adouble is basically a real value tracking the values of any number of partial derivatives. + +\code +#ifndef ADOLCSUPPORT_H +#define ADOLCSUPPORT_H + +#define ADOLC_TAPELESS +#include +#include + +namespace Eigen { + +template<> struct NumTraits + : NumTraits // permits to get the epsilon, dummy_precision, lowest, highest functions +{ + typedef adtl::adouble Real; + typedef adtl::adouble NonInteger; + typedef adtl::adouble Nested; + + enum { + IsComplex = 0, + IsInteger = 0, + IsSigned = 1, + RequireInitialization = 1, + ReadCost = 1, + AddCost = 3, + MulCost = 3 + }; +}; + +} + +namespace adtl { + +inline const adouble& conj(const adouble& x) { return x; } +inline const adouble& real(const adouble& x) { return x; } +inline adouble imag(const adouble&) { return 0.; } +inline adouble abs(const adouble& x) { return fabs(x); } +inline adouble abs2(const adouble& x) { return x*x; } + +} + +#endif // ADOLCSUPPORT_H +\endcode + +This other example adds support for the \c mpq_class type from GMP. It shows in particular how to change the way Eigen picks the best pivot during LU factorization. It selects the coefficient with the highest score, where the score is by default the absolute value of a number, but we can define a different score, for instance to prefer pivots with a more compact representation (this is an example, not a recommendation). Note that the scores should always be non-negative and only zero is allowed to have a score of zero. Also, this can interact badly with thresholds for inexact scalar types. + +\code +#include +#include +#include + +namespace Eigen { + template<> struct NumTraits : GenericNumTraits + { + typedef mpq_class Real; + typedef mpq_class NonInteger; + typedef mpq_class Nested; + + static inline Real epsilon() { return 0; } + static inline Real dummy_precision() { return 0; } + static inline Real digits10() { return 0; } + + enum { + IsInteger = 0, + IsSigned = 1, + IsComplex = 0, + RequireInitialization = 1, + ReadCost = 6, + AddCost = 150, + MulCost = 100 + }; + }; + + namespace internal { + + template<> struct scalar_score_coeff_op { + struct result_type : boost::totally_ordered1 { + std::size_t len; + result_type(int i = 0) : len(i) {} // Eigen uses Score(0) and Score() + result_type(mpq_class const& q) : + len(mpz_size(q.get_num_mpz_t())+ + mpz_size(q.get_den_mpz_t())-1) {} + friend bool operator<(result_type x, result_type y) { + // 0 is the worst possible pivot + if (x.len == 0) return y.len > 0; + if (y.len == 0) return false; + // Prefer a pivot with a small representation + return x.len > y.len; + } + friend bool operator==(result_type x, result_type y) { + // Only used to test if the score is 0 + return x.len == y.len; + } + }; + result_type operator()(mpq_class const& x) const { return x; } + }; + } +} +\endcode + +*/ + +} diff --git a/ground/gcs/src/libs/eigen/doc/CustomizingEigen_InheritingMatrix.dox b/ground/gcs/src/libs/eigen/doc/CustomizingEigen_InheritingMatrix.dox new file mode 100644 index 0000000000..b21e554337 --- /dev/null +++ b/ground/gcs/src/libs/eigen/doc/CustomizingEigen_InheritingMatrix.dox @@ -0,0 +1,34 @@ +namespace Eigen { + +/** \page TopicCustomizing_InheritingMatrix Inheriting from Matrix + +Before inheriting from Matrix, be really, I mean REALLY, sure that using +EIGEN_MATRIX_PLUGIN is not what you really want (see previous section). +If you just need to add few members to Matrix, this is the way to go. + +An example of when you actually need to inherit Matrix, is when you +have several layers of heritage such as +MyVerySpecificVector1, MyVerySpecificVector2 -> MyVector1 -> Matrix and +MyVerySpecificVector3, MyVerySpecificVector4 -> MyVector2 -> Matrix. + +In order for your object to work within the %Eigen framework, you need to +define a few members in your inherited class. + +Here is a minimalistic example: + +\include CustomizingEigen_Inheritance.cpp + +Output: \verbinclude CustomizingEigen_Inheritance.out + +This is the kind of error you can get if you don't provide those methods +\verbatim +error: no match for ‘operator=’ in ‘v = Eigen::operator*( +const Eigen::MatrixBase >::Scalar&, +const Eigen::MatrixBase >::StorageBaseType&) +(((const Eigen::MatrixBase >::StorageBaseType&) +((const Eigen::MatrixBase >::StorageBaseType*)(& v))))’ +\endverbatim + +*/ + +} diff --git a/ground/gcs/src/libs/eigen/doc/CustomizingEigen_NullaryExpr.dox b/ground/gcs/src/libs/eigen/doc/CustomizingEigen_NullaryExpr.dox new file mode 100644 index 0000000000..37c8dcd896 --- /dev/null +++ b/ground/gcs/src/libs/eigen/doc/CustomizingEigen_NullaryExpr.dox @@ -0,0 +1,86 @@ +namespace Eigen { + +/** \page TopicCustomizing_NullaryExpr Matrix manipulation via nullary-expressions + + +The main purpose of the class CwiseNullaryOp is to define \em procedural matrices such as constant or random matrices as returned by the Ones(), Zero(), Constant(), Identity() and Random() methods. +Nevertheless, with some imagination it is possible to accomplish very sophisticated matrix manipulation with minimal efforts such that \ref TopicNewExpressionType "implementing new expression" is rarely needed. + +\section NullaryExpr_Circulant Example 1: circulant matrix + +To explore these possibilities let us start with the \em circulant example of the \ref TopicNewExpressionType "implementing new expression" topic. +Let us recall that a circulant matrix is a matrix where each column is the same as the +column to the left, except that it is cyclically shifted downwards. +For example, here is a 4-by-4 circulant matrix: +\f[ \begin{bmatrix} + 1 & 8 & 4 & 2 \\ + 2 & 1 & 8 & 4 \\ + 4 & 2 & 1 & 8 \\ + 8 & 4 & 2 & 1 +\end{bmatrix} \f] +A circulant matrix is uniquely determined by its first column. We wish +to write a function \c makeCirculant which, given the first column, +returns an expression representing the circulant matrix. + +For this exercise, the return type of \c makeCirculant will be a CwiseNullaryOp that we need to instantiate with: +1 - a proper \c circulant_functor storing the input vector and implementing the adequate coefficient accessor \c operator(i,j) +2 - a template instantiation of class Matrix conveying compile-time information such as the scalar type, sizes, and preferred storage layout. + +Calling \c ArgType the type of the input vector, we can construct the equivalent squared Matrix type as follows: + +\snippet make_circulant2.cpp square + +This little helper structure will help us to implement our \c makeCirculant function as follows: + +\snippet make_circulant2.cpp makeCirculant + +As usual, our function takes as argument a \c MatrixBase (see this \ref TopicFunctionTakingEigenTypes "page" for more details). +Then, the CwiseNullaryOp object is constructed through the DenseBase::NullaryExpr static method with the adequate runtime sizes. + +Then, we need to implement our \c circulant_functor, which is a straightforward exercise: + +\snippet make_circulant2.cpp circulant_func + +We are now all set to try our new feature: + +\snippet make_circulant2.cpp main + + +If all the fragments are combined, the following output is produced, +showing that the program works as expected: + +\include make_circulant2.out + +This implementation of \c makeCirculant is much simpler than \ref TopicNewExpressionType "defining a new expression" from scratch. + + +\section NullaryExpr_Indexing Example 2: indexing rows and columns + +The goal here is to mimic MatLab's ability to index a matrix through two vectors of indices referencing the rows and columns to be picked respectively, like this: + +\snippet nullary_indexing.out main1 + +To this end, let us first write a nullary-functor storing references to the input matrix and to the two arrays of indices, and implementing the required \c operator()(i,j): + +\snippet nullary_indexing.cpp functor + +Then, let's create an \c indexing(A,rows,cols) function creating the nullary expression: + +\snippet nullary_indexing.cpp function + +Finally, here is an example of how this function can be used: + +\snippet nullary_indexing.cpp main1 + +This straightforward implementation is already quite powerful as the row or column index arrays can also be expressions to perform offsetting, modulo, striding, reverse, etc. + +\snippet nullary_indexing.cpp main2 + +and the output is: + +\snippet nullary_indexing.out main2 + +*/ + +} + diff --git a/ground/gcs/src/libs/eigen/doc/CustomizingEigen_Plugins.dox b/ground/gcs/src/libs/eigen/doc/CustomizingEigen_Plugins.dox new file mode 100644 index 0000000000..d88f2409b9 --- /dev/null +++ b/ground/gcs/src/libs/eigen/doc/CustomizingEigen_Plugins.dox @@ -0,0 +1,69 @@ +namespace Eigen { + +/** \page TopicCustomizing_Plugins Extending MatrixBase (and other classes) + +In this section we will see how to add custom methods to MatrixBase. Since all expressions and matrix types inherit MatrixBase, adding a method to MatrixBase make it immediately available to all expressions ! A typical use case is, for instance, to make Eigen compatible with another API. + +You certainly know that in C++ it is not possible to add methods to an existing class. So how that's possible ? Here the trick is to include in the declaration of MatrixBase a file defined by the preprocessor token \c EIGEN_MATRIXBASE_PLUGIN: +\code +class MatrixBase { + // ... + #ifdef EIGEN_MATRIXBASE_PLUGIN + #include EIGEN_MATRIXBASE_PLUGIN + #endif +}; +\endcode +Therefore to extend MatrixBase with your own methods you just have to create a file with your method declaration and define EIGEN_MATRIXBASE_PLUGIN before you include any Eigen's header file. + +You can extend many of the other classes used in Eigen by defining similarly named preprocessor symbols. For instance, define \c EIGEN_ARRAYBASE_PLUGIN if you want to extend the ArrayBase class. A full list of classes that can be extended in this way and the corresponding preprocessor symbols can be found on our page \ref TopicPreprocessorDirectives. + +Here is an example of an extension file for adding methods to MatrixBase: \n +\b MatrixBaseAddons.h +\code +inline Scalar at(uint i, uint j) const { return this->operator()(i,j); } +inline Scalar& at(uint i, uint j) { return this->operator()(i,j); } +inline Scalar at(uint i) const { return this->operator[](i); } +inline Scalar& at(uint i) { return this->operator[](i); } + +inline RealScalar squaredLength() const { return squaredNorm(); } +inline RealScalar length() const { return norm(); } +inline RealScalar invLength(void) const { return fast_inv_sqrt(squaredNorm()); } + +template +inline Scalar squaredDistanceTo(const MatrixBase& other) const +{ return (derived() - other.derived()).squaredNorm(); } + +template +inline RealScalar distanceTo(const MatrixBase& other) const +{ return internal::sqrt(derived().squaredDistanceTo(other)); } + +inline void scaleTo(RealScalar l) { RealScalar vl = norm(); if (vl>1e-9) derived() *= (l/vl); } + +inline Transpose transposed() {return this->transpose();} +inline const Transpose transposed() const {return this->transpose();} + +inline uint minComponentId(void) const { int i; this->minCoeff(&i); return i; } +inline uint maxComponentId(void) const { int i; this->maxCoeff(&i); return i; } + +template +void makeFloor(const MatrixBase& other) { derived() = derived().cwiseMin(other.derived()); } +template +void makeCeil(const MatrixBase& other) { derived() = derived().cwiseMax(other.derived()); } + +const CwiseBinaryOp, const Derived, const ConstantReturnType> +operator+(const Scalar& scalar) const +{ return CwiseBinaryOp, const Derived, const ConstantReturnType>(derived(), Constant(rows(),cols(),scalar)); } + +friend const CwiseBinaryOp, const ConstantReturnType, Derived> +operator+(const Scalar& scalar, const MatrixBase& mat) +{ return CwiseBinaryOp, const ConstantReturnType, Derived>(Constant(rows(),cols(),scalar), mat.derived()); } +\endcode + +Then one can the following declaration in the config.h or whatever prerequisites header file of his project: +\code +#define EIGEN_MATRIXBASE_PLUGIN "MatrixBaseAddons.h" +\endcode + +*/ + +} diff --git a/ground/gcs/src/libs/eigen/doc/DenseDecompositionBenchmark.dox b/ground/gcs/src/libs/eigen/doc/DenseDecompositionBenchmark.dox new file mode 100644 index 0000000000..7be9c70cd5 --- /dev/null +++ b/ground/gcs/src/libs/eigen/doc/DenseDecompositionBenchmark.dox @@ -0,0 +1,42 @@ +namespace Eigen { + +/** \eigenManualPage DenseDecompositionBenchmark Benchmark of dense decompositions + +This page presents a speed comparison of the dense matrix decompositions offered by %Eigen for a wide range of square matrices and overconstrained problems. + +For a more general overview on the features and numerical robustness of linear solvers and decompositions, check this \link TopicLinearAlgebraDecompositions table \endlink. + +This benchmark has been run on a laptop equipped with an Intel core i7 \@ 2,6 GHz, and compiled with clang with \b AVX and \b FMA instruction sets enabled but without multi-threading. +It uses \b single \b precision \b float numbers. For double, you can get a good estimate by multiplying the timings by a factor 2. + +The square matrices are symmetric, and for the overconstrained matrices, the reported timmings include the cost to compute the symmetric covariance matrix \f$ A^T A \f$ for the first four solvers based on Cholesky and LU, as denoted by the \b * symbol (top-right corner part of the table). +Timings are in \b milliseconds, and factors are relative to the LLT decomposition which is the fastest but also the least general and robust. + + + + + + + + + + + + + + +
solver/size8x8 100x100 1000x1000 4000x4000 10000x8 10000x100 10000x1000 10000x4000
LLT0.050.425.83374.556.79 *30.15 *236.34 *3847.17 *
LDLT0.07 (x1.3)0.65 (x1.5)26.86 (x4.6)2361.18 (x6.3)6.81 (x1) *31.91 (x1.1) *252.61 (x1.1) *5807.66 (x1.5) *
PartialPivLU0.08 (x1.5)0.69 (x1.6)15.63 (x2.7)709.32 (x1.9)6.81 (x1) *31.32 (x1) *241.68 (x1) *4270.48 (x1.1) *
FullPivLU0.1 (x1.9)4.48 (x10.6)281.33 (x48.2)-6.83 (x1) *32.67 (x1.1) *498.25 (x2.1) *-
HouseholderQR0.19 (x3.5)2.18 (x5.2)23.42 (x4)1337.52 (x3.6)34.26 (x5)129.01 (x4.3)377.37 (x1.6)4839.1 (x1.3)
ColPivHouseholderQR0.23 (x4.3)2.23 (x5.3)103.34 (x17.7)9987.16 (x26.7)36.05 (x5.3)163.18 (x5.4)2354.08 (x10)37860.5 (x9.8)
CompleteOrthogonalDecomposition0.23 (x4.3)2.22 (x5.2)99.44 (x17.1)10555.3 (x28.2)35.75 (x5.3)169.39 (x5.6)2150.56 (x9.1)36981.8 (x9.6)
FullPivHouseholderQR0.23 (x4.3)4.64 (x11)289.1 (x49.6)-69.38 (x10.2)446.73 (x14.8)4852.12 (x20.5)-
JacobiSVD1.01 (x18.6)71.43 (x168.4)--113.81 (x16.7)1179.66 (x39.1)--
BDCSVD1.07 (x19.7)21.83 (x51.5)331.77 (x56.9)18587.9 (x49.6)110.53 (x16.3)397.67 (x13.2)2975 (x12.6)48593.2 (x12.6)
+ +\b *: This decomposition do not support direct least-square solving for over-constrained problems, and the reported timing include the cost to form the symmetric covariance matrix \f$ A^T A \f$. + +\b Observations: + + LLT is always the fastest solvers. + + For largely over-constrained problems, the cost of Cholesky/LU decompositions is dominated by the computation of the symmetric covariance matrix. + + For large problem sizes, only the decomposition implementing a cache-friendly blocking strategy scale well. Those include LLT, PartialPivLU, HouseholderQR, and BDCSVD. This explain why for a 4k x 4k matrix, HouseholderQR is faster than LDLT. In the future, LDLT and ColPivHouseholderQR will also implement blocking strategies. + + CompleteOrthogonalDecomposition is based on ColPivHouseholderQR and they thus achieve the same level of performance. + +The above table has been generated by the bench/dense_solvers.cpp file, feel-free to hack it to generate a table matching your hardware, compiler, and favorite problem sizes. + +*/ + +} diff --git a/ground/gcs/src/libs/eigen/doc/Doxyfile.in b/ground/gcs/src/libs/eigen/doc/Doxyfile.in index 696dd2af1c..48bb0a8ec2 100644 --- a/ground/gcs/src/libs/eigen/doc/Doxyfile.in +++ b/ground/gcs/src/libs/eigen/doc/Doxyfile.in @@ -125,7 +125,7 @@ ALWAYS_DETAILED_SEC = NO # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. -INLINE_INHERITED_MEMB = YES +INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set @@ -206,6 +206,7 @@ TAB_SIZE = 8 # You can put \n's in the value part of an alias to insert newlines. ALIASES = "only_for_vectors=This is only for vectors (either row-vectors or column-vectors), i.e. matrices which are known at compile-time to have either one row or one column." \ + "not_reentrant=\warning This function is not re-entrant." \ "array_module=This is defined in the %Array module. \code #include \endcode" \ "cholesky_module=This is defined in the %Cholesky module. \code #include \endcode" \ "eigenvalues_module=This is defined in the %Eigenvalues module. \code #include \endcode" \ @@ -215,6 +216,7 @@ ALIASES = "only_for_vectors=This is only for vectors (either row- "lu_module=This is defined in the %LU module. \code #include \endcode" \ "qr_module=This is defined in the %QR module. \code #include \endcode" \ "svd_module=This is defined in the %SVD module. \code #include \endcode" \ + "specialfunctions_module=This is defined in the \b unsupported SpecialFunctions module. \code #include \endcode" \ "label=\bug" \ "matrixworld=*" \ "arrayworld=*" \ @@ -222,7 +224,13 @@ ALIASES = "only_for_vectors=This is only for vectors (either row- "note_about_using_kernel_to_study_multiple_solutions=If you need a complete analysis of the space of solutions, take the one solution obtained by this method and add to it elements of the kernel, as determined by kernel()." \ "note_about_checking_solutions=This method just tries to find as good a solution as possible. If you want to check whether a solution exists or if it is accurate, just call this function to get a result and then compute the error of this result, or use MatrixBase::isApprox() directly, for instance like this: \code bool a_solution_exists = (A*result).isApprox(b, precision); \endcode This method avoids dividing by zero, so that the non-existence of a solution doesn't by itself mean that you'll get \c inf or \c nan values." \ "note_try_to_help_rvo=This function returns the result by value. In order to make that efficient, it is implemented as just a return statement using a special constructor, hopefully allowing the compiler to perform a RVO (return value optimization)." \ - "nonstableyet=\warning This is not considered to be part of the stable public API yet. Changes may happen in future releases. See \ref Experimental \"Experimental parts of Eigen\"" + "nonstableyet=\warning This is not considered to be part of the stable public API yet. Changes may happen in future releases. See \ref Experimental \"Experimental parts of Eigen\"" \ + "implsparsesolverconcept=This class follows the \link TutorialSparseSolverConcept sparse solver concept \endlink." \ + "blank= " \ + "cpp11=[c++11]" \ + "cpp14=[c++14]" \ + "cpp17=[c++17]" + ALIASES += "eigenAutoToc= " ALIASES += "eigenManualPage=\defgroup" @@ -270,7 +278,7 @@ OPTIMIZE_OUTPUT_VHDL = NO # (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions # you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. -EXTENSION_MAPPING = +EXTENSION_MAPPING = .h=C++ no_extension=C++ # If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all # comments according to the Markdown format, which allows for more readable @@ -458,7 +466,7 @@ HIDE_IN_BODY_DOCS = NO # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. -INTERNAL_DOCS = NO +INTERNAL_DOCS = ${EIGEN_DOXY_INTERNAL} # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also @@ -472,13 +480,13 @@ CASE_SENSE_NAMES = YES # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. -HIDE_SCOPE_NAMES = YES +HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. -SHOW_INCLUDE_FILES = NO +SHOW_INCLUDE_FILES = ${EIGEN_DOXY_INTERNAL} # If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen # will list include files with double quotes in the documentation @@ -544,7 +552,7 @@ STRICT_PROTO_MATCHING = NO # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. -GENERATE_TODOLIST = NO +GENERATE_TODOLIST = ${EIGEN_DOXY_INTERNAL} # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test @@ -556,7 +564,7 @@ GENERATE_TESTLIST = NO # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. -GENERATE_BUGLIST = NO +GENERATE_BUGLIST = ${EIGEN_DOXY_INTERNAL} # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting @@ -719,7 +727,8 @@ RECURSIVE = YES # Note that relative paths are relative to the directory from which doxygen is # run. -EXCLUDE = "${Eigen_SOURCE_DIR}/Eigen/Eigen2Support" \ +EXCLUDE = "${Eigen_SOURCE_DIR}/Eigen/src/Core/products" \ + "${Eigen_SOURCE_DIR}/Eigen/Eigen2Support" \ "${Eigen_SOURCE_DIR}/Eigen/src/Eigen2Support" \ "${Eigen_SOURCE_DIR}/doc/examples" \ "${Eigen_SOURCE_DIR}/doc/special_examples" \ @@ -800,7 +809,7 @@ EXAMPLE_RECURSIVE = NO # directories that contain image that are included in the documentation (see # the \image command). -IMAGE_PATH = +IMAGE_PATH = ${Eigen_BINARY_DIR}/doc/html # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program @@ -864,13 +873,13 @@ STRIP_CODE_COMMENTS = YES # then for each documented function all documented # functions referencing it will be listed. -REFERENCED_BY_RELATION = YES +REFERENCED_BY_RELATION = NO # If the REFERENCES_RELATION tag is set to YES # then for each documented function all documented entities # called/used by that function will be listed. -REFERENCES_RELATION = YES +REFERENCES_RELATION = NO # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from @@ -1581,9 +1590,14 @@ PREDEFINED = EIGEN_EMPTY_STRUCT \ EIGEN_VECTORIZE \ EIGEN_QT_SUPPORT \ EIGEN_STRONG_INLINE=inline \ - "EIGEN2_SUPPORT_STAGE=99" \ + EIGEN_DEVICE_FUNC= \ "EIGEN_MAKE_CWISE_BINARY_OP(METHOD,FUNCTOR)=template const CwiseBinaryOp, const Derived, const OtherDerived> METHOD(const EIGEN_CURRENT_STORAGE_BASE_CLASS &other) const;" \ - "EIGEN_CWISE_PRODUCT_RETURN_TYPE(LHS,RHS)=CwiseBinaryOp, const LHS, const RHS>" + "EIGEN_CWISE_PRODUCT_RETURN_TYPE(LHS,RHS)=CwiseBinaryOp, const LHS, const RHS>"\ + "EIGEN_CAT2(a,b)= a ## b"\ + "EIGEN_CAT(a,b)=EIGEN_CAT2(a,b)"\ + "EIGEN_CWISE_BINARY_RETURN_TYPE(LHS,RHS,OPNAME)=CwiseBinaryOp, const LHS, const RHS>"\ + DOXCOMMA=, + # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. @@ -1599,7 +1613,15 @@ EXPAND_AS_DEFINED = EIGEN_MAKE_TYPEDEFS \ EIGEN_CURRENT_STORAGE_BASE_CLASS \ EIGEN_MATHFUNC_IMPL \ _EIGEN_GENERIC_PUBLIC_INTERFACE \ - EIGEN2_SUPPORT + EIGEN_ARRAY_DECLARE_GLOBAL_UNARY \ + EIGEN_EMPTY \ + EIGEN_EULER_ANGLES_TYPEDEFS \ + EIGEN_EULER_ANGLES_SINGLE_TYPEDEF \ + EIGEN_EULER_SYSTEM_TYPEDEF \ + EIGEN_DOC_UNARY_ADDONS \ + EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL \ + EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF + # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all references to function-like macros diff --git a/ground/gcs/src/libs/eigen/doc/FixedSizeVectorizable.dox b/ground/gcs/src/libs/eigen/doc/FixedSizeVectorizable.dox index 8ae1351738..49e38af768 100644 --- a/ground/gcs/src/libs/eigen/doc/FixedSizeVectorizable.dox +++ b/ground/gcs/src/libs/eigen/doc/FixedSizeVectorizable.dox @@ -4,7 +4,7 @@ namespace Eigen { The goal of this page is to explain what we mean by "fixed-size vectorizable". -\section summary Executive Summary +\section FixedSizeVectorizable_summary Executive Summary An Eigen object is called "fixed-size vectorizable" if it has fixed size and that size is a multiple of 16 bytes. @@ -21,7 +21,7 @@ Examples include: \li Eigen::Quaterniond \li Eigen::Quaternionf -\section explanation Explanation +\section FixedSizeVectorizable_explanation Explanation First, "fixed-size" should be clear: an Eigen object has fixed size if its number of rows and its number of columns are fixed at compile-time. So for example Matrix3f has fixed size, but MatrixXf doesn't (the opposite of fixed-size is dynamic-size). diff --git a/ground/gcs/src/libs/eigen/doc/InplaceDecomposition.dox b/ground/gcs/src/libs/eigen/doc/InplaceDecomposition.dox new file mode 100644 index 0000000000..cb1c6d4138 --- /dev/null +++ b/ground/gcs/src/libs/eigen/doc/InplaceDecomposition.dox @@ -0,0 +1,115 @@ +namespace Eigen { + +/** \eigenManualPage InplaceDecomposition Inplace matrix decompositions + +Starting from %Eigen 3.3, the LU, Cholesky, and QR decompositions can operate \em inplace, that is, directly within the given input matrix. +This feature is especially useful when dealing with huge matrices, and or when the available memory is very limited (embedded systems). + +To this end, the respective decomposition class must be instantiated with a Ref<> matrix type, and the decomposition object must be constructed with the input matrix as argument. As an example, let us consider an inplace LU decomposition with partial pivoting. + +Let's start with the basic inclusions, and declaration of a 2x2 matrix \c A: + + + + + + + +
codeoutput
\snippet TutorialInplaceLU.cpp init + \snippet TutorialInplaceLU.out init +
+ +No surprise here! Then, let's declare our inplace LU object \c lu, and check the content of the matrix \c A: + + + + + + +
\snippet TutorialInplaceLU.cpp declaration + \snippet TutorialInplaceLU.out declaration +
+ +Here, the \c lu object computes and stores the \c L and \c U factors within the memory held by the matrix \c A. +The coefficients of \c A have thus been destroyed during the factorization, and replaced by the L and U factors as one can verify: + + + + + + +
\snippet TutorialInplaceLU.cpp matrixLU + \snippet TutorialInplaceLU.out matrixLU +
+ +Then, one can use the \c lu object as usual, for instance to solve the Ax=b problem: + + + + + +
\snippet TutorialInplaceLU.cpp solve + \snippet TutorialInplaceLU.out solve +
+ +Here, since the content of the original matrix \c A has been lost, we had to declared a new matrix \c A0 to verify the result. + +Since the memory is shared between \c A and \c lu, modifying the matrix \c A will make \c lu invalid. +This can easily be verified by modifying the content of \c A and trying to solve the initial problem again: + + + + + + +
\snippet TutorialInplaceLU.cpp modifyA + \snippet TutorialInplaceLU.out modifyA +
+ +Note that there is no shared pointer under the hood, it is the \b responsibility \b of \b the \b user to keep the input matrix \c A in life as long as \c lu is living. + +If one wants to update the factorization with the modified A, one has to call the compute method as usual: + + + + + +
\snippet TutorialInplaceLU.cpp recompute + \snippet TutorialInplaceLU.out recompute +
+ +Note that calling compute does not change the memory which is referenced by the \c lu object. Therefore, if the compute method is called with another matrix \c A1 different than \c A, then the content of \c A1 won't be modified. This is still the content of \c A that will be used to store the L and U factors of the matrix \c A1. +This can easily be verified as follows: + + + + + +
\snippet TutorialInplaceLU.cpp recompute_bis0 + \snippet TutorialInplaceLU.out recompute_bis0 +
+The matrix \c A1 is unchanged, and one can thus solve A1*x=b, and directly check the residual without any copy of \c A1: + + + + + +
\snippet TutorialInplaceLU.cpp recompute_bis1 + \snippet TutorialInplaceLU.out recompute_bis1 +
+ + +Here is the list of matrix decompositions supporting this inplace mechanism: + +- class LLT +- class LDLT +- class PartialPivLU +- class FullPivLU +- class HouseholderQR +- class ColPivHouseholderQR +- class FullPivHouseholderQR +- class CompleteOrthogonalDecomposition + +*/ + +} \ No newline at end of file diff --git a/ground/gcs/src/libs/eigen/doc/LeastSquares.dox b/ground/gcs/src/libs/eigen/doc/LeastSquares.dox new file mode 100644 index 0000000000..e2191a22f7 --- /dev/null +++ b/ground/gcs/src/libs/eigen/doc/LeastSquares.dox @@ -0,0 +1,70 @@ +namespace Eigen { + +/** \eigenManualPage LeastSquares Solving linear least squares systems + +This page describes how to solve linear least squares systems using %Eigen. An overdetermined system +of equations, say \a Ax = \a b, has no solutions. In this case, it makes sense to search for the +vector \a x which is closest to being a solution, in the sense that the difference \a Ax - \a b is +as small as possible. This \a x is called the least square solution (if the Euclidean norm is used). + +The three methods discussed on this page are the SVD decomposition, the QR decomposition and normal +equations. Of these, the SVD decomposition is generally the most accurate but the slowest, normal +equations is the fastest but least accurate, and the QR decomposition is in between. + +\eigenAutoToc + + +\section LeastSquaresSVD Using the SVD decomposition + +The \link JacobiSVD::solve() solve() \endlink method in the JacobiSVD class can be directly used to +solve linear squares systems. It is not enough to compute only the singular values (the default for +this class); you also need the singular vectors but the thin SVD decomposition suffices for +computing least squares solutions: + + + + + + + +
Example:Output:
\include TutorialLinAlgSVDSolve.cpp \verbinclude TutorialLinAlgSVDSolve.out
+ +This is example from the page \link TutorialLinearAlgebra Linear algebra and decompositions \endlink. + + +\section LeastSquaresQR Using the QR decomposition + +The solve() method in QR decomposition classes also computes the least squares solution. There are +three QR decomposition classes: HouseholderQR (no pivoting, so fast but unstable), +ColPivHouseholderQR (column pivoting, thus a bit slower but more accurate) and FullPivHouseholderQR +(full pivoting, so slowest and most stable). Here is an example with column pivoting: + + + + + + + +
Example:Output:
\include LeastSquaresQR.cpp \verbinclude LeastSquaresQR.out
+ + +\section LeastSquaresNormalEquations Using normal equations + +Finding the least squares solution of \a Ax = \a b is equivalent to solving the normal equation +ATAx = ATb. This leads to the following code + + + + + + + +
Example:Output:
\include LeastSquaresNormalEquations.cpp \verbinclude LeastSquaresNormalEquations.out
+ +If the matrix \a A is ill-conditioned, then this is not a good method, because the condition number +of ATA is the square of the condition number of \a A. This means that you +lose twice as many digits using normal equation than if you use the other methods. + +*/ + +} \ No newline at end of file diff --git a/ground/gcs/src/libs/eigen/doc/Manual.dox b/ground/gcs/src/libs/eigen/doc/Manual.dox index 52427f0668..342b145fde 100644 --- a/ground/gcs/src/libs/eigen/doc/Manual.dox +++ b/ground/gcs/src/libs/eigen/doc/Manual.dox @@ -3,19 +3,32 @@ namespace Eigen { +/** \page UserManual_CustomizingEigen Extending/Customizing Eigen + %Eigen can be extended in several ways, for instance, by defining global methods, by inserting custom methods within main %Eigen's classes through the \ref TopicCustomizing_Plugins "plugin" mechanism, by adding support to \ref TopicCustomizing_CustomScalar "custom scalar types" etc. See below for the respective sub-topics. + - \subpage TopicCustomizing_Plugins + - \subpage TopicCustomizing_InheritingMatrix + - \subpage TopicCustomizing_CustomScalar + - \subpage TopicCustomizing_NullaryExpr + - \subpage TopicNewExpressionType + \sa \ref TopicPreprocessorDirectives +*/ + + /** \page UserManual_Generalities General topics - \subpage Eigen2ToEigen3 - \subpage TopicFunctionTakingEigenTypes - \subpage TopicPreprocessorDirectives - \subpage TopicAssertions - - \subpage TopicCustomizingEigen - \subpage TopicMultiThreading + - \subpage TopicUsingBlasLapack - \subpage TopicUsingIntelMKL + - \subpage TopicCUDA - \subpage TopicPitfalls - \subpage TopicTemplateKeyword - \subpage UserManual_UnderstandingEigen + - \subpage TopicCMakeGuide */ - + /** \page UserManual_UnderstandingEigen Understanding Eigen - \subpage TopicInsideEigenExample - \subpage TopicClassHierarchy @@ -57,6 +70,8 @@ namespace Eigen { \ingroup DenseMatrixManipulation_chapter */ /** \addtogroup TutorialMapClass \ingroup DenseMatrixManipulation_chapter */ +/** \addtogroup TutorialReshapeSlicing + \ingroup DenseMatrixManipulation_chapter */ /** \addtogroup TopicAliasing \ingroup DenseMatrixManipulation_chapter */ /** \addtogroup TopicStorageOrders @@ -86,6 +101,9 @@ namespace Eigen { /** \addtogroup Householder_Module \ingroup DenseMatrixManipulation_Reference */ +/** \addtogroup CoeffwiseMathFunctions + \ingroup DenseMatrixManipulation_chapter */ + /** \addtogroup QuickRefPage \ingroup DenseMatrixManipulation_chapter */ @@ -97,6 +115,12 @@ namespace Eigen { \ingroup DenseLinearSolvers_chapter */ /** \addtogroup TopicLinearAlgebraDecompositions \ingroup DenseLinearSolvers_chapter */ +/** \addtogroup LeastSquares + \ingroup DenseLinearSolvers_chapter */ +/** \addtogroup InplaceDecomposition + \ingroup DenseLinearSolvers_chapter */ +/** \addtogroup DenseDecompositionBenchmark + \ingroup DenseLinearSolvers_chapter */ /** \addtogroup DenseLinearSolvers_Reference \ingroup DenseLinearSolvers_chapter */ @@ -159,4 +183,7 @@ namespace Eigen { \ingroup Geometry_Reference */ /** \addtogroup Splines_Module \ingroup Geometry_Reference */ + +/** \internal \brief Namespace containing low-level routines from the %Eigen library. */ +namespace internal {} } diff --git a/ground/gcs/src/libs/eigen/doc/MatrixfreeSolverExample.dox b/ground/gcs/src/libs/eigen/doc/MatrixfreeSolverExample.dox index 9921c72614..3efa292b56 100644 --- a/ground/gcs/src/libs/eigen/doc/MatrixfreeSolverExample.dox +++ b/ground/gcs/src/libs/eigen/doc/MatrixfreeSolverExample.dox @@ -6,13 +6,12 @@ namespace Eigen { \eigenManualPage MatrixfreeSolverExample Matrix-free solvers Iterative solvers such as ConjugateGradient and BiCGSTAB can be used in a matrix free context. To this end, user must provide a wrapper class inheriting EigenBase<> and implementing the following methods: - - Index rows() and Index cols(): returns number of rows and columns respectively - - operator* with and Eigen dense column vector - - resize(rows,cols): needed for source compatibility (can stay empty) + - \c Index \c rows() and \c Index \c cols(): returns number of rows and columns respectively + - \c operator* with your type and an %Eigen dense column vector (its actual implementation goes in a specialization of the internal::generic_product_impl class) -Eigen::internal::traits<> must also be specialized for the wrapper type. +\c Eigen::internal::traits<> must also be specialized for the wrapper type. -For efficiency purpose, one might also want to provide a custom preconditioner. Here is an example using ConjugateGradient and implementing also a custom Jacobi preconditioner: +Here is a complete example wrapping an Eigen::SparseMatrix: \include matrixfree_cg.cpp Output: \verbinclude matrixfree_cg.out diff --git a/ground/gcs/src/libs/eigen/doc/NewExpressionType.dox b/ground/gcs/src/libs/eigen/doc/NewExpressionType.dox new file mode 100644 index 0000000000..c2f2433128 --- /dev/null +++ b/ground/gcs/src/libs/eigen/doc/NewExpressionType.dox @@ -0,0 +1,143 @@ +namespace Eigen { + +/** \page TopicNewExpressionType Adding a new expression type + + +\warning +Disclaimer: this page is tailored to very advanced users who are not afraid of dealing with some %Eigen's internal aspects. +In most cases, a custom expression can be avoided by either using custom \ref MatrixBase::unaryExpr "unary" or \ref MatrixBase::binaryExpr "binary" functors, +while extremely complex matrix manipulations can be achieved by a nullary functors as described in the \ref TopicCustomizing_NullaryExpr "previous page". + +This page describes with the help of an example how to implement a new +light-weight expression type in %Eigen. This consists of three parts: +the expression type itself, a traits class containing compile-time +information about the expression, and the evaluator class which is +used to evaluate the expression to a matrix. + +\b TO \b DO: Write a page explaining the design, with details on +vectorization etc., and refer to that page here. + + +\eigenAutoToc + +\section TopicSetting The setting + +A circulant matrix is a matrix where each column is the same as the +column to the left, except that it is cyclically shifted downwards. +For example, here is a 4-by-4 circulant matrix: +\f[ \begin{bmatrix} + 1 & 8 & 4 & 2 \\ + 2 & 1 & 8 & 4 \\ + 4 & 2 & 1 & 8 \\ + 8 & 4 & 2 & 1 +\end{bmatrix} \f] +A circulant matrix is uniquely determined by its first column. We wish +to write a function \c makeCirculant which, given the first column, +returns an expression representing the circulant matrix. + +For simplicity, we restrict the \c makeCirculant function to dense +matrices. It may make sense to also allow arrays, or sparse matrices, +but we will not do so here. We also do not want to support +vectorization. + + +\section TopicPreamble Getting started + +We will present the file implementing the \c makeCirculant function +part by part. We start by including the appropriate header files and +forward declaring the expression class, which we will call +\c Circulant. The \c makeCirculant function will return an object of +this type. The class \c Circulant is in fact a class template; the +template argument \c ArgType refers to the type of the vector passed +to the \c makeCirculant function. + +\include make_circulant.cpp.preamble + + +\section TopicTraits The traits class + +For every expression class \c X, there should be a traits class +\c Traits in the \c Eigen::internal namespace containing +information about \c X known as compile time. + +As explained in \ref TopicSetting, we designed the \c Circulant +expression class to refer to dense matrices. The entries of the +circulant matrix have the same type as the entries of the vector +passed to the \c makeCirculant function. The type used to index the +entries is also the same. Again for simplicity, we will only return +column-major matrices. Finally, the circulant matrix is a square +matrix (number of rows equals number of columns), and the number of +rows equals the number of rows of the column vector passed to the +\c makeCirculant function. If this is a dynamic-size vector, then the +size of the circulant matrix is not known at compile-time. + +This leads to the following code: + +\include make_circulant.cpp.traits + + +\section TopicExpression The expression class + +The next step is to define the expression class itself. In our case, +we want to inherit from \c MatrixBase in order to expose the interface +for dense matrices. In the constructor, we check that we are passed a +column vector (see \ref TopicAssertions) and we store the vector from +which we are going to build the circulant matrix in the member +variable \c m_arg. Finally, the expression class should compute the +size of the corresponding circulant matrix. As explained above, this +is a square matrix with as many columns as the vector used to +construct the matrix. + +\b TO \b DO: What about the \c Nested typedef? It seems to be +necessary; is this only temporary? + +\include make_circulant.cpp.expression + + +\section TopicEvaluator The evaluator + +The last big fragment implements the evaluator for the \c Circulant +expression. The evaluator computes the entries of the circulant +matrix; this is done in the \c .coeff() member function. The entries +are computed by finding the corresponding entry of the vector from +which the circulant matrix is constructed. Getting this entry may +actually be non-trivial when the circulant matrix is constructed from +a vector which is given by a complicated expression, so we use the +evaluator which corresponds to the vector. + +The \c CoeffReadCost constant records the cost of computing an entry +of the circulant matrix; we ignore the index computation and say that +this is the same as the cost of computing an entry of the vector from +which the circulant matrix is constructed. + +In the constructor, we save the evaluator for the column vector which +defined the circulant matrix. We also save the size of that vector; +remember that we can query an expression object to find the size but +not the evaluator. + +\include make_circulant.cpp.evaluator + + +\section TopicEntry The entry point + +After all this, the \c makeCirculant function is very simple. It +simply creates an expression object and returns it. + +\include make_circulant.cpp.entry + + +\section TopicMain A simple main function for testing + +Finally, a short \c main function that shows how the \c makeCirculant +function can be called. + +\include make_circulant.cpp.main + +If all the fragments are combined, the following output is produced, +showing that the program works as expected: + +\include make_circulant.out + +*/ +} + diff --git a/ground/gcs/src/libs/eigen/doc/Overview.dox b/ground/gcs/src/libs/eigen/doc/Overview.dox index 9ab96233a7..dbb49bd218 100644 --- a/ground/gcs/src/libs/eigen/doc/Overview.dox +++ b/ground/gcs/src/libs/eigen/doc/Overview.dox @@ -17,7 +17,9 @@ You're a MatLab user? There is also a short AS The \b main \b documentation is organized into \em chapters covering different domains of features. They are themselves composed of \em user \em manual pages describing the different features in a comprehensive way, and \em reference pages that gives you access to the API documentation through the related Eigen's \em modules and \em classes. -Under the \subpage UserManual_Generalities section, you will find documentation on more general topics such as preprocessor directives, controlling assertions, multi-threading, MKL support, some Eigen's internal insights, and much more... +Under the \subpage UserManual_CustomizingEigen section, you will find discussions and examples on extending %Eigen's features and supporting custom scalar types. + +Under the \subpage UserManual_Generalities section, you will find documentation on more general topics such as preprocessor directives, controlling assertions, multi-threading, MKL support, some Eigen's internal insights, and much more... Finally, do not miss the search engine, useful to quickly get to the documentation of a given class or function. diff --git a/ground/gcs/src/libs/eigen/doc/PreprocessorDirectives.dox b/ground/gcs/src/libs/eigen/doc/PreprocessorDirectives.dox index cfaba35d84..f01b39aec5 100644 --- a/ground/gcs/src/libs/eigen/doc/PreprocessorDirectives.dox +++ b/ground/gcs/src/libs/eigen/doc/PreprocessorDirectives.dox @@ -5,7 +5,7 @@ namespace Eigen { You can control some aspects of %Eigen by defining the preprocessor tokens using \c \#define. These macros should be defined before any %Eigen headers are included. Often they are best set in the project options. -This page lists the preprocesor tokens recognised by %Eigen. +This page lists the preprocessor tokens recognized by %Eigen. \eigenAutoToc @@ -18,25 +18,67 @@ one option, and other parts (or libraries that you use) are compiled with anothe fail to link or exhibit subtle bugs. Nevertheless, these options can be useful for people who know what they are doing. - - \b EIGEN2_SUPPORT - if defined, enables the Eigen2 compatibility mode. This is meant to ease the transition - of Eigen2 to Eigen3 (see \ref Eigen2ToEigen3). Not defined by default. - - \b EIGEN2_SUPPORT_STAGEnn_xxx (for various values of nn and xxx) - staged migration path from Eigen2 to - Eigen3; see \ref Eigen2SupportModes. + - \b EIGEN2_SUPPORT and \b EIGEN2_SUPPORT_STAGEnn_xxx are disabled starting from the 3.3 release. + Defining one of these will raise a compile-error. If you need to compile Eigen2 code, + check this site. - \b EIGEN_DEFAULT_DENSE_INDEX_TYPE - the type for column and row indices in matrices, vectors and array (DenseBase::Index). Set to \c std::ptrdiff_t by default. - \b EIGEN_DEFAULT_IO_FORMAT - the IOFormat to use when printing a matrix if no %IOFormat is specified. Defaults to the %IOFormat constructed by the default constructor IOFormat::IOFormat(). - \b EIGEN_INITIALIZE_MATRICES_BY_ZERO - if defined, all entries of newly constructed matrices and arrays are initialized to zero, as are new entries in matrices and arrays after resizing. Not defined by default. + \warning The unary (resp. binary) constructor of \c 1x1 (resp. \c 2x1 or \c 1x2) fixed size matrices is + always interpreted as an initialization constructor where the argument(s) are the coefficient values + and not the sizes. For instance, \code Vector2d v(2,1); \endcode will create a vector with coeficients [2,1], + and \b not a \c 2x1 vector initialized with zeros (i.e., [0,0]). If such cases might occur, then it is + recommended to use the default constructor with a explicit call to resize: + \code + Matrix v; + v.resize(size); + Matrix m; + m.resize(rows,cols); + \endcode - \b EIGEN_INITIALIZE_MATRICES_BY_NAN - if defined, all entries of newly constructed matrices and arrays are initialized to NaN, as are new entries in matrices and arrays after resizing. This option is especially useful for debugging purpose, though a memory tool like valgrind is preferable. Not defined by default. + \warning See the documentation of \c EIGEN_INITIALIZE_MATRICES_BY_ZERO for a discussion on a limitations + of these macros when applied to \c 1x1, \c 1x2, and \c 2x1 fixed-size matrices. - \b EIGEN_NO_AUTOMATIC_RESIZING - if defined, the matrices (or arrays) on both sides of an assignment a = b have to be of the same size; otherwise, %Eigen automatically resizes \c a so that it is of the correct size. Not defined by default. +\section TopicPreprocessorDirectivesCppVersion C++ standard features + +By default, %Eigen strive to automatically detect and enable langage features at compile-time based on +the information provided by the compiler. + + - \b EIGEN_MAX_CPP_VER - disables usage of C++ features requiring a version greater than EIGEN_MAX_CPP_VER. + Possible values are: 03, 11, 14, 17, etc. If not defined (the default), %Eigen enables all features supported + by the compiler. + +Individual features can be explicitly enabled or disabled by defining the following token to 0 or 1 respectively. +For instance, one might limit the C++ version to C++03 by defining EIGEN_MAX_CPP_VER=03, but still enable C99 math +functions by defining EIGEN_HAS_C99_MATH=1. + + - \b EIGEN_HAS_C99_MATH - controls the usage of C99 math functions such as erf, erfc, lgamma, etc. + Automatic detection disabled if EIGEN_MAX_CPP_VER<11. + - \b EIGEN_HAS_CXX11_MATH - controls the implementation of some functions such as round, logp1, isinf, isnan, etc. + Automatic detection disabled if EIGEN_MAX_CPP_VER<11. + - \b EIGEN_HAS_RVALUE_REFERENCES - defines whetehr rvalue references are supported + Automatic detection disabled if EIGEN_MAX_CPP_VER<11. + - \b EIGEN_HAS_STD_RESULT_OF - defines whether std::result_of is supported + Automatic detection disabled if EIGEN_MAX_CPP_VER<11. + - \b EIGEN_HAS_VARIADIC_TEMPLATES - defines whether variadic templates are supported + Automatic detection disabled if EIGEN_MAX_CPP_VER<11. + - \b EIGEN_HAS_CONSTEXPR - defines whether relaxed const expression are supported + Automatic detection disabled if EIGEN_MAX_CPP_VER<14. + - \b EIGEN_HAS_CXX11_CONTAINERS - defines whether STL's containers follows C++11 specifications + Automatic detection disabled if EIGEN_MAX_CPP_VER<11. + - \b EIGEN_HAS_CXX11_NOEXCEPT - defines whether noexcept is supported + Automatic detection disabled if EIGEN_MAX_CPP_VER<11. + \section TopicPreprocessorDirectivesAssertions Assertions The %Eigen library contains many assertions to guard against programming errors, both at compile time and at @@ -55,32 +97,39 @@ run time. However, these assertions do cost time and can thus be turned off. \section TopicPreprocessorDirectivesPerformance Alignment, vectorization and performance tweaking - - \b EIGEN_MALLOC_ALREADY_ALIGNED - Can be set to 0 or 1 to tell whether default system malloc already + - \b \c EIGEN_MALLOC_ALREADY_ALIGNED - Can be set to 0 or 1 to tell whether default system \c malloc already returns aligned buffers. In not defined, then this information is automatically deduced from the compiler and system preprocessor tokens. - - \b EIGEN_DONT_ALIGN - disables alignment completely. %Eigen will not try to align its objects and does not - expect that any objects passed to it are aligned. This will turn off vectorization. Not defined by default. - - \b EIGEN_DONT_ALIGN_STATICALLY - disables alignment of arrays on the stack. Not defined by default, unless - \c EIGEN_DONT_ALIGN is defined. - - \b EIGEN_DONT_PARALLELIZE - if defined, this disables multi-threading. This is only relevant if you enabled OpenMP. + - \b \c EIGEN_MAX_ALIGN_BYTES - Must be a power of two, or 0. Defines an upper bound on the memory boundary in bytes on which dynamically and statically allocated data may be aligned by %Eigen. If not defined, a default value is automatically computed based on architecture, compiler, and OS. + This option is typically used to enforce binary compatibility between code/libraries compiled with different SIMD options. For instance, one may compile AVX code and enforce ABI compatibility with existing SSE code by defining \c EIGEN_MAX_ALIGN_BYTES=16. In the other way round, since by default AVX implies 32 bytes alignment for best performance, one can compile SSE code to be ABI compatible with AVX code by defining \c EIGEN_MAX_ALIGN_BYTES=32. + - \b \c EIGEN_MAX_STATIC_ALIGN_BYTES - Same as \c EIGEN_MAX_ALIGN_BYTES but for statically allocated data only. By default, if only \c EIGEN_MAX_ALIGN_BYTES is defined, then \c EIGEN_MAX_STATIC_ALIGN_BYTES == \c EIGEN_MAX_ALIGN_BYTES, otherwise a default value is automatically computed based on architecture, compiler, and OS (can be smaller than the default value of EIGEN_MAX_ALIGN_BYTES on architectures that do not support stack alignment). + Let us emphasize that \c EIGEN_MAX_*_ALIGN_BYTES define only a diserable upper bound. In practice data is aligned to largest power-of-two common divisor of \c EIGEN_MAX_STATIC_ALIGN_BYTES and the size of the data, such that memory is not wasted. + - \b \c EIGEN_DONT_PARALLELIZE - if defined, this disables multi-threading. This is only relevant if you enabled OpenMP. See \ref TopicMultiThreading for details. - \b EIGEN_DONT_VECTORIZE - disables explicit vectorization when defined. Not defined by default, unless alignment is disabled by %Eigen's platform test or the user defining \c EIGEN_DONT_ALIGN. - - \b EIGEN_FAST_MATH - enables some optimizations which might affect the accuracy of the result. This currently + - \b \c EIGEN_UNALIGNED_VECTORIZE - disables/enables vectorization with unaligned stores. Default is 1 (enabled). + If set to 0 (disabled), then expression for which the destination cannot be aligned are not vectorized (e.g., unaligned + small fixed size vectors or matrices) + - \b \c EIGEN_FAST_MATH - enables some optimizations which might affect the accuracy of the result. This currently enables the SSE vectorization of sin() and cos(), and speedups sqrt() for single precision. Defined to 1 by default. Define it to 0 to disable. - - \b EIGEN_UNROLLING_LIMIT - defines the size of a loop to enable meta unrolling. Set it to zero to disable + - \b \c EIGEN_UNROLLING_LIMIT - defines the size of a loop to enable meta unrolling. Set it to zero to disable unrolling. The size of a loop here is expressed in %Eigen's own notion of "number of FLOPS", it does not correspond to the number of iterations or the number of instructions. The default is value 100. - - \b EIGEN_STACK_ALLOCATION_LIMIT - defines the maximum bytes for a buffer to be allocated on the stack. For internal + - \b \c EIGEN_STACK_ALLOCATION_LIMIT - defines the maximum bytes for a buffer to be allocated on the stack. For internal temporary buffers, dynamic memory allocation is employed as a fall back. For fixed-size matrices or arrays, exceeding this threshold raises a compile time assertion. Use 0 to set no limit. Default is 128 KB. + - \c EIGEN_DONT_ALIGN - Deprecated, it is a synonym for \c EIGEN_MAX_ALIGN_BYTES=0. It disables alignment completely. %Eigen will not try to align its objects and does not expect that any objects passed to it are aligned. This will turn off vectorization if \b EIGEN_UNALIGNED_VECTORIZE=1. Not defined by default. + - \c EIGEN_DONT_ALIGN_STATICALLY - Deprecated, it is a synonym for \c EIGEN_MAX_STATIC_ALIGN_BYTES=0. It disables alignment of arrays on the stack. Not defined by default, unless \c EIGEN_DONT_ALIGN is defined. + + \section TopicPreprocessorDirectivesPlugins Plugins It is possible to add new methods to many fundamental classes in %Eigen by writing a plugin. As explained in -the section \ref ExtendingMatrixBase, the plugin is specified by defining a \c EIGEN_xxx_PLUGIN macro. The +the section \ref TopicCustomizing_Plugins, the plugin is specified by defining a \c EIGEN_xxx_PLUGIN macro. The following macros are supported; none of them are defined by default. - \b EIGEN_ARRAY_PLUGIN - filename of plugin for extending the Array class. @@ -92,6 +141,7 @@ following macros are supported; none of them are defined by default. - \b EIGEN_MATRIXBASE_PLUGIN - filename of plugin for extending the MatrixBase class. - \b EIGEN_PLAINOBJECTBASE_PLUGIN - filename of plugin for extending the PlainObjectBase class. - \b EIGEN_MAPBASE_PLUGIN - filename of plugin for extending the MapBase class. + - \b EIGEN_QUATERNION_PLUGIN - filename of plugin for extending the Quaternion class. - \b EIGEN_QUATERNIONBASE_PLUGIN - filename of plugin for extending the QuaternionBase class. - \b EIGEN_SPARSEMATRIX_PLUGIN - filename of plugin for extending the SparseMatrix class. - \b EIGEN_SPARSEMATRIXBASE_PLUGIN - filename of plugin for extending the SparseMatrixBase class. diff --git a/ground/gcs/src/libs/eigen/doc/QuickReference.dox b/ground/gcs/src/libs/eigen/doc/QuickReference.dox index a4be0f68a1..44f5410db7 100644 --- a/ground/gcs/src/libs/eigen/doc/QuickReference.dox +++ b/ground/gcs/src/libs/eigen/doc/QuickReference.dox @@ -13,17 +13,17 @@ The Eigen library is divided in a Core module and several additional modules. Ea - + - - - - - - - - - + + + + + + + + +
ModuleHeader fileContents
\link Core_Module Core \endlink\code#include \endcodeMatrix and Array classes, basic linear algebra (including triangular and selfadjoint products), array manipulation
\link Core_Module Core \endlink\code#include \endcodeMatrix and Array classes, basic linear algebra (including triangular and selfadjoint products), array manipulation
\link Geometry_Module Geometry \endlink\code#include \endcodeTransform, Translation, Scaling, Rotation2D and 3D rotations (Quaternion, AngleAxis)
\link LU_Module LU \endlink\code#include \endcodeInverse, determinant, LU decompositions with solver (FullPivLU, PartialPivLU)
\link Cholesky_Module Cholesky \endlink\code#include \endcodeLLT and LDLT Cholesky factorization with solver
\link Householder_Module Householder \endlink\code#include \endcodeHouseholder transformations; this module is used by several linear algebra modules
\link SVD_Module SVD \endlink\code#include \endcodeSVD decomposition with least-squares solver (JacobiSVD)
\link QR_Module QR \endlink\code#include \endcodeQR decomposition with solver (HouseholderQR, ColPivHouseholderQR, FullPivHouseholderQR)
\link Eigenvalues_Module Eigenvalues \endlink\code#include \endcodeEigenvalue, eigenvector decompositions (EigenSolver, SelfAdjointEigenSolver, ComplexEigenSolver)
\link Sparse_modules Sparse \endlink\code#include \endcode%Sparse matrix storage and related basic linear algebra (SparseMatrix, DynamicSparseMatrix, SparseVector)
\code#include \endcodeIncludes Core, Geometry, LU, Cholesky, SVD, QR, and Eigenvalues header files
\code#include \endcodeIncludes %Dense and %Sparse header files (the whole Eigen library)
\link LU_Module LU \endlink\code#include \endcodeInverse, determinant, LU decompositions with solver (FullPivLU, PartialPivLU)
\link Cholesky_Module Cholesky \endlink\code#include \endcodeLLT and LDLT Cholesky factorization with solver
\link Householder_Module Householder \endlink\code#include \endcodeHouseholder transformations; this module is used by several linear algebra modules
\link SVD_Module SVD \endlink\code#include \endcodeSVD decompositions with least-squares solver (JacobiSVD, BDCSVD)
\link QR_Module QR \endlink\code#include \endcodeQR decomposition with solver (HouseholderQR, ColPivHouseholderQR, FullPivHouseholderQR)
\link Eigenvalues_Module Eigenvalues \endlink\code#include \endcodeEigenvalue, eigenvector decompositions (EigenSolver, SelfAdjointEigenSolver, ComplexEigenSolver)
\link Sparse_Module Sparse \endlink\code#include \endcode%Sparse matrix storage and related basic linear algebra (SparseMatrix, SparseVector) \n (see \ref SparseQuickRefPage for details on sparse modules)
\code#include \endcodeIncludes Core, Geometry, LU, Cholesky, SVD, QR, and Eigenvalues header files
\code#include \endcodeIncludes %Dense and %Sparse header files (the whole Eigen library)
top @@ -340,7 +340,7 @@ mat1 = mat2.adjoint(); mat1.adjointInPlace(); \endcode -\link MatrixBase::dot() dot \endlink product \n inner product \matrixworld\code +\link MatrixBase::dot dot \endlink product \n inner product \matrixworld\code scalar = vec1.dot(vec2); scalar = col1.adjoint() * col2; scalar = (col1.adjoint() * col2).value();\endcode @@ -364,32 +364,10 @@ vec3 = vec1.cross(vec2);\endcode top \section QuickRef_Coeffwise Coefficient-wise \& Array operators -Coefficient-wise operators for matrices and vectors: - - - -
Matrix API \matrixworldVia Array conversions
\code -mat1.cwiseMin(mat2) -mat1.cwiseMax(mat2) -mat1.cwiseAbs2() -mat1.cwiseAbs() -mat1.cwiseSqrt() -mat1.cwiseProduct(mat2) -mat1.cwiseQuotient(mat2)\endcode -\code -mat1.array().min(mat2.array()) -mat1.array().max(mat2.array()) -mat1.array().abs2() -mat1.array().abs() -mat1.array().sqrt() -mat1.array() * mat2.array() -mat1.array() / mat2.array() -\endcode
- -It is also very simple to apply any user defined function \c foo using DenseBase::unaryExpr together with std::ptr_fun: -\code mat1.unaryExpr(std::ptr_fun(foo))\endcode -Array operators:\arrayworld +In addition to the aforementioned operators, Eigen supports numerous coefficient-wise operator and functions. +Most of them unambiguously makes sense in array-world\arrayworld. The following operators are readily available for arrays, +or available through .array() for vectors and matrices: - +
Arithmetic operators\code @@ -400,28 +378,108 @@ array1 + scalar array1 - scalar array1 += scalar array1 -= scalar array1 < array2 array1 > array2 array1 < scalar array1 > scalar array1 <= array2 array1 >= array2 array1 <= scalar array1 >= scalar array1 == array2 array1 != array2 array1 == scalar array1 != scalar +array1.min(array2) array1.max(array2) array1.min(scalar) array1.max(scalar) \endcode
Trigo, power, and \n misc functions \n and the STL variants\code -array1.min(array2) -array1.max(array2) +
Trigo, power, and \n misc functions \n and the STL-like variants\code array1.abs2() array1.abs() abs(array1) array1.sqrt() sqrt(array1) array1.log() log(array1) +array1.log10() log10(array1) array1.exp() exp(array1) -array1.pow(exponent) pow(array1,exponent) +array1.pow(array2) pow(array1,array2) +array1.pow(scalar) pow(array1,scalar) + pow(scalar,array2) array1.square() array1.cube() array1.inverse() + array1.sin() sin(array1) array1.cos() cos(array1) array1.tan() tan(array1) array1.asin() asin(array1) array1.acos() acos(array1) +array1.atan() atan(array1) +array1.sinh() sinh(array1) +array1.cosh() cosh(array1) +array1.tanh() tanh(array1) +array1.arg() arg(array1) + +array1.floor() floor(array1) +array1.ceil() ceil(array1) +array1.round() round(aray1) + +array1.isFinite() isfinite(array1) +array1.isInf() isinf(array1) +array1.isNaN() isnan(array1) +\endcode +
+ + +The following coefficient-wise operators are available for all kind of expressions (matrices, vectors, and arrays), and for both real or complex scalar types: + + + +
Eigen's APISTL-like APIs\arrayworld Comments
\code +mat1.real() +mat1.imag() +mat1.conjugate() +\endcode +\code +real(array1) +imag(array1) +conj(array1) +\endcode + +\code + // read-write, no-op for real expressions + // read-only for real, read-write for complexes + // no-op for real expressions \endcode
+Some coefficient-wise operators are readily available for for matrices and vectors through the following cwise* methods: + + + +
Matrix API \matrixworldVia Array conversions
\code +mat1.cwiseMin(mat2) mat1.cwiseMin(scalar) +mat1.cwiseMax(mat2) mat1.cwiseMax(scalar) +mat1.cwiseAbs2() +mat1.cwiseAbs() +mat1.cwiseSqrt() +mat1.cwiseInverse() +mat1.cwiseProduct(mat2) +mat1.cwiseQuotient(mat2) +mat1.cwiseEqual(mat2) mat1.cwiseEqual(scalar) +mat1.cwiseNotEqual(mat2) +\endcode +\code +mat1.array().min(mat2.array()) mat1.array().min(scalar) +mat1.array().max(mat2.array()) mat1.array().max(scalar) +mat1.array().abs2() +mat1.array().abs() +mat1.array().sqrt() +mat1.array().inverse() +mat1.array() * mat2.array() +mat1.array() / mat2.array() +mat1.array() == mat2.array() mat1.array() == scalar +mat1.array() != mat2.array() +\endcode
+The main difference between the two API is that the one based on cwise* methods returns an expression in the matrix world, +while the second one (based on .array()) returns an array expression. +Recall that .array() has no cost, it only changes the available API and interpretation of the data. + +It is also very simple to apply any user defined function \c foo using DenseBase::unaryExpr together with std::ptr_fun (c++03), std::ref (c++11), or lambdas (c++11): +\code +mat1.unaryExpr(std::ptr_fun(foo)); +mat1.unaryExpr(std::ref(foo)); +mat1.unaryExpr([](double x) { return foo(x); }); +\endcode + + top \section QuickRef_Reductions Reductions diff --git a/ground/gcs/src/libs/eigen/doc/SparseLinearSystems.dox b/ground/gcs/src/libs/eigen/doc/SparseLinearSystems.dox index 051a02ed96..fc33b93e7e 100644 --- a/ground/gcs/src/libs/eigen/doc/SparseLinearSystems.dox +++ b/ground/gcs/src/libs/eigen/doc/SparseLinearSystems.dox @@ -4,33 +4,63 @@ In Eigen, there are several methods available to solve linear systems when the c \eigenAutoToc -\section TutorialSparseDirectSolvers Sparse solvers +\section TutorialSparseSolverList List of sparse solvers -%Eigen currently provides a limited set of built-in solvers, as well as wrappers to external solver libraries. -They are summarized in the following table: +%Eigen currently provides a wide set of built-in solvers, as well as wrappers to external solver libraries. +They are summarized in the following tables: + +\subsection TutorialSparseSolverList_Direct Built-in direct solvers - - - - + + + + + - - + + + - - - - - - - + + - - + + + + - - + + +
ClassModuleSolver kindMatrix kindFeatures related to performanceDependencies,License

Notes

SimplicialLLT \link SparseCholesky_Module SparseCholesky \endlinkDirect LLt factorizationSPDFill-in reducingbuilt-in, LGPL
ClassSolver kindMatrix kindFeatures related to performanceLicense

Notes

SimplicialLLT \n \#includeDirect LLt factorizationSPDFill-in reducingLGPL SimplicialLDLT is often preferable
SimplicialLDLT \link SparseCholesky_Module SparseCholesky \endlinkDirect LDLt factorizationSPDFill-in reducingbuilt-in, LGPL
SimplicialLDLT \n \#includeDirect LDLt factorizationSPDFill-in reducingLGPL Recommended for very sparse and not too large problems (e.g., 2D Poisson eq.)
ConjugateGradient\link IterativeLinearSolvers_Module IterativeLinearSolvers \endlinkClassic iterative CGSPDPreconditionningbuilt-in, MPL2Recommended for large symmetric problems (e.g., 3D Poisson eq.)
BiCGSTAB\link IterativeLinearSolvers_Module IterativeLinearSolvers \endlinkIterative stabilized bi-conjugate gradientSquarePreconditionningbuilt-in, MPL2To speedup the convergence, try it with the \ref IncompleteLUT preconditioner.
SparseLU \link SparseLU_Module SparseLU \endlink LU factorization
SparseLU \n \#include LU factorization Square Fill-in reducing, Leverage fast dense algebra built-in, MPL2 optimized for small and large problems with irregular patterns
SparseQR \link SparseQR_Module SparseQR \endlink QR factorizationMPL2optimized for small and large problems with irregular patterns
SparseQR \n \#include QR factorization Any, rectangular Fill-in reducingbuilt-in, MPL2recommended for least-square problems, has a basic rank-revealing feature
Wrappers to external solvers
MPL2recommended for least-square problems, has a basic rank-revealing feature
+ +\subsection TutorialSparseSolverList_Iterative Built-in iterative solvers + + + + + + + + + + + + + + + + + + + +
ClassSolver kindMatrix kindSupported preconditioners, [default]License

Notes

ConjugateGradient \n \#include Classic iterative CGSPDIdentityPreconditioner, [DiagonalPreconditioner], IncompleteCholeskyMPL2Recommended for large symmetric problems (e.g., 3D Poisson eq.)
LeastSquaresConjugateGradient \n \#includeCG for rectangular least-square problemRectangularIdentityPreconditioner, [LeastSquareDiagonalPreconditioner]MPL2Solve for min |A'Ax-b|^2 without forming A'A
BiCGSTAB \n \#includeIterative stabilized bi-conjugate gradientSquareIdentityPreconditioner, [DiagonalPreconditioner], IncompleteLUTMPL2To speedup the convergence, try it with the \ref IncompleteLUT preconditioner.
+ +\subsection TutorialSparseSolverList_Wrapper Wrappers to external solvers + + + + @@ -46,10 +76,15 @@ They are summarized in the following table: + + +
ClassModuleSolver kindMatrix kindFeatures related to performanceDependencies,License

Notes

PastixLLT \n PastixLDLT \n PastixLU\link PaStiXSupport_Module PaStiXSupport \endlinkDirect LLt, LDLt, LU factorizationsSPD \n SPD \n SquareFill-in reducing, Leverage fast dense algebra, Multithreading Requires the PaStiX package, \b CeCILL-C optimized for tough problems and symmetric patterns
SPQR\link SPQRSupport_Module SPQRSupport \endlink QR factorization Any, rectangularfill-in reducing, multithreaded, fast dense algebra requires the SuiteSparse package, \b GPL recommended for linear least-squares problems, has a rank-revealing feature
PardisoLLT \n PardisoLDLT \n PardisoLU\link PardisoSupport_Module PardisoSupport \endlinkDirect LLt, LDLt, LU factorizationsSPD \n SPD \n SquareFill-in reducing, Leverage fast dense algebra, MultithreadingRequires the Intel MKL package, \b Proprietary optimized for tough problems patterns, see also \link TopicUsingIntelMKL using MKL with Eigen \endlink
Here \c SPD means symmetric positive definite. +\section TutorialSparseSolverConcept Sparse solver concept + All these solvers follow the same general concept. Here is a typical and general example: \code @@ -101,8 +136,10 @@ x2 = solver.solve(b2); \endcode The compute() method is equivalent to calling both analyzePattern() and factorize(). -Finally, each solver provides some specific features, such as determinant, access to the factors, controls of the iterations, and so on. -More details are availble in the documentations of the respective classes. +Each solver provides some specific features, such as determinant, access to the factors, controls of the iterations, and so on. +More details are available in the documentations of the respective classes. + +Finally, most of the iterative solvers, can also be used in a \b matrix-free context, see the following \link MatrixfreeSolverExample example \endlink. \section TheSparseCompute The Compute Step In the compute() function, the matrix is generally factorized: LLT for self-adjoint matrices, LDLT for general hermitian matrices, LU for non hermitian matrices and QR for rectangular matrices. These are the results of using direct solvers. For this class of solvers precisely, the compute step is further subdivided into analyzePattern() and factorize(). @@ -140,7 +177,16 @@ x2 = solver.solve(b2); For direct methods, the solution are computed at the machine precision. Sometimes, the solution need not be too accurate. In this case, the iterative methods are more suitable and the desired accuracy can be set before the solve step using \b setTolerance(). For all the available functions, please, refer to the documentation of the \link IterativeLinearSolvers_Module Iterative solvers module \endlink. \section BenchmarkRoutine -Most of the time, all you need is to know how much time it will take to qolve your system, and hopefully, what is the most suitable solver. In Eigen, we provide a benchmark routine that can be used for this purpose. It is very easy to use. In the build directory, navigate to bench/spbench and compile the routine by typing \b make \e spbenchsolver. Run it with --help option to get the list of all available options. Basically, the matrices to test should be in MatrixMarket Coordinate format, and the routine returns the statistics from all available solvers in Eigen. +Most of the time, all you need is to know how much time it will take to solve your system, and hopefully, what is the most suitable solver. In Eigen, we provide a benchmark routine that can be used for this purpose. It is very easy to use. In the build directory, navigate to bench/spbench and compile the routine by typing \b make \e spbenchsolver. Run it with --help option to get the list of all available options. Basically, the matrices to test should be in MatrixMarket Coordinate format, and the routine returns the statistics from all available solvers in Eigen. + +To export your matrices and right-hand-side vectors in the matrix-market format, you can the the unsupported SparseExtra module: +\code +#include +... +Eigen::saveMarket(A, "filename.mtx"); +Eigen::saveMarket(A, "filename_SPD.mtx", Eigen::Symmetric); // if A is symmetric-positive-definite +Eigen::saveMarketVector(B, "filename_b.mtx"); +\endcode The following table gives an example of XML statistics from several Eigen built-in and external solvers. diff --git a/ground/gcs/src/libs/eigen/doc/SparseQuickReference.dox b/ground/gcs/src/libs/eigen/doc/SparseQuickReference.dox index e0a30edccb..a25622e800 100644 --- a/ground/gcs/src/libs/eigen/doc/SparseQuickReference.dox +++ b/ground/gcs/src/libs/eigen/doc/SparseQuickReference.dox @@ -206,7 +206,7 @@ See \ref TutorialSparse_SubMatrices and below for read-write sub-matrices. sm1.innerVectors(start, size); // RW sm1.leftCols(size); // RW sm2.rightCols(size); // RO because sm2 is row-major - sm1.middleRows(start, numRows); // RO becasue sm1 is column-major + sm1.middleRows(start, numRows); // RO because sm1 is column-major sm1.middleCols(start, numCols); // RW sm1.col(j); // RW \endcode @@ -253,6 +253,20 @@ If the matrix is not in compressed form, makeCompressed() should be called befor Note that these functions are mostly provided for interoperability purposes with external libraries.\n A better access to the values of the matrix is done by using the InnerIterator class as described in \link TutorialSparse the Tutorial Sparse \endlink section + + + + +
Mapping external buffers
+\code +int outerIndexPtr[cols+1]; +int innerIndices[nnz]; +double values[nnz]; +Map > sm1(rows,cols,nnz,outerIndexPtr, // read-write + innerIndices,values); +Map > sm2(...); // read-only +\endcode +As for dense matrices, class Map can be used to see external buffers as an %Eigen's SparseMatrix object.
*/ } diff --git a/ground/gcs/src/libs/eigen/doc/StlContainers.dox b/ground/gcs/src/libs/eigen/doc/StlContainers.dox index d8d0d529c5..e0f8714a95 100644 --- a/ground/gcs/src/libs/eigen/doc/StlContainers.dox +++ b/ground/gcs/src/libs/eigen/doc/StlContainers.dox @@ -4,7 +4,7 @@ namespace Eigen { \eigenAutoToc -\section summary Executive summary +\section StlContainers_summary Executive summary Using STL containers on \ref TopicFixedSizeVectorizable "fixed-size vectorizable Eigen types", or classes having members of such types, requires taking the following two steps: @@ -28,7 +28,7 @@ std::map, \endcode Note that the third parameter "std::less" is just the default value, but we have to include it because we want to specify the fourth parameter, which is the allocator type. -\section vector The case of std::vector +\section StlContainers_vector The case of std::vector The situation with std::vector was even worse (explanation below) so we had to specialize it for the Eigen::aligned_allocator type. In practice you \b must use the Eigen::aligned_allocator (not another aligned allocator), \b and \#include . diff --git a/ground/gcs/src/libs/eigen/doc/StructHavingEigenMembers.dox b/ground/gcs/src/libs/eigen/doc/StructHavingEigenMembers.dox index 74a8d52173..7fbed0eb01 100644 --- a/ground/gcs/src/libs/eigen/doc/StructHavingEigenMembers.dox +++ b/ground/gcs/src/libs/eigen/doc/StructHavingEigenMembers.dox @@ -4,11 +4,11 @@ namespace Eigen { \eigenAutoToc -\section summary Executive Summary +\section StructHavingEigenMembers_summary Executive Summary -If you define a structure having members of \ref TopicFixedSizeVectorizable "fixed-size vectorizable Eigen types", you must overload its "operator new" so that it generates 16-bytes-aligned pointers. Fortunately, Eigen provides you with a macro EIGEN_MAKE_ALIGNED_OPERATOR_NEW that does that for you. +If you define a structure having members of \ref TopicFixedSizeVectorizable "fixed-size vectorizable Eigen types", you must overload its "operator new" so that it generates 16-bytes-aligned pointers. Fortunately, %Eigen provides you with a macro EIGEN_MAKE_ALIGNED_OPERATOR_NEW that does that for you. -\section what What kind of code needs to be changed? +\section StructHavingEigenMembers_what What kind of code needs to be changed? The kind of code that needs to be changed is this: @@ -27,7 +27,7 @@ Foo *foo = new Foo; In other words: you have a class that has as a member a \ref TopicFixedSizeVectorizable "fixed-size vectorizable Eigen object", and then you dynamically create an object of that class. -\section how How should such code be modified? +\section StructHavingEigenMembers_how How should such code be modified? Very easy, you just need to put a EIGEN_MAKE_ALIGNED_OPERATOR_NEW macro in a public part of your class, like this: @@ -48,9 +48,9 @@ Foo *foo = new Foo; This macro makes "new Foo" always return an aligned pointer. -If this approach is too intrusive, see also the \ref othersolutions. +If this approach is too intrusive, see also the \ref StructHavingEigenMembers_othersolutions "other solutions". -\section why Why is this needed? +\section StructHavingEigenMembers_why Why is this needed? OK let's say that your code looks like this: @@ -67,7 +67,7 @@ class Foo Foo *foo = new Foo; \endcode -A Eigen::Vector2d consists of 2 doubles, which is 128 bits. Which is exactly the size of a SSE packet, which makes it possible to use SSE for all sorts of operations on this vector. But SSE instructions (at least the ones that Eigen uses, which are the fast ones) require 128-bit alignment. Otherwise you get a segmentation fault. +A Eigen::Vector2d consists of 2 doubles, which is 128 bits. Which is exactly the size of a SSE packet, which makes it possible to use SSE for all sorts of operations on this vector. But SSE instructions (at least the ones that %Eigen uses, which are the fast ones) require 128-bit alignment. Otherwise you get a segmentation fault. For this reason, Eigen takes care by itself to require 128-bit alignment for Eigen::Vector2d, by doing two things: \li Eigen requires 128-bit alignment for the Eigen::Vector2d's array (of 2 doubles). With GCC, this is done with a __attribute__ ((aligned(16))). @@ -81,7 +81,7 @@ The alignment attribute of the member v is then relative to the start of the cla The solution is to let class Foo have an aligned "operator new", as we showed in the previous section. -\section movetotop Should I then put all the members of Eigen types at the beginning of my class? +\section StructHavingEigenMembers_movetotop Should I then put all the members of Eigen types at the beginning of my class? That's not required. Since Eigen takes care of declaring 128-bit alignment, all members that need it are automatically 128-bit aligned relatively to the class. So code like this works fine: @@ -95,15 +95,15 @@ public: }; \endcode -\section dynamicsize What about dynamic-size matrices and vectors? +\section StructHavingEigenMembers_dynamicsize What about dynamic-size matrices and vectors? Dynamic-size matrices and vectors, such as Eigen::VectorXd, allocate dynamically their own array of coefficients, so they take care of requiring absolute alignment automatically. So they don't cause this issue. The issue discussed here is only with \ref TopicFixedSizeVectorizable "fixed-size vectorizable matrices and vectors". -\section bugineigen So is this a bug in Eigen? +\section StructHavingEigenMembers_bugineigen So is this a bug in Eigen? No, it's not our bug. It's more like an inherent problem of the C++98 language specification, and seems to be taken care of in the upcoming language revision: see this document. -\section conditional What if I want to do this conditionnally (depending on template parameters) ? +\section StructHavingEigenMembers_conditional What if I want to do this conditionnally (depending on template parameters) ? For this situation, we offer the macro EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign). It will generate aligned operators like EIGEN_MAKE_ALIGNED_OPERATOR_NEW if NeedsToAlign is true. It will generate operators with the default alignment if NeedsToAlign is false. @@ -128,7 +128,7 @@ Foo<3> *foo3 = new Foo<3>; // foo3 has only the system default alignment guarant \endcode -\section othersolutions Other solutions +\section StructHavingEigenMembers_othersolutions Other solutions In case putting the EIGEN_MAKE_ALIGNED_OPERATOR_NEW macro everywhere is too intrusive, there exists at least two other solutions. diff --git a/ground/gcs/src/libs/eigen/doc/TemplateKeyword.dox b/ground/gcs/src/libs/eigen/doc/TemplateKeyword.dox index f4e4f237e5..b84cfdae96 100644 --- a/ground/gcs/src/libs/eigen/doc/TemplateKeyword.dox +++ b/ground/gcs/src/libs/eigen/doc/TemplateKeyword.dox @@ -5,7 +5,8 @@ namespace Eigen { There are two uses for the \c template and \c typename keywords in C++. One of them is fairly well known amongst programmers: to define templates. The other use is more obscure: to specify that an expression refers to a template function or a type. This regularly trips up programmers that use the %Eigen library, often -leading to error messages from the compiler that are difficult to understand. +leading to error messages from the compiler that are difficult to understand, such as "expected expression" or +"no match for operator<". \eigenAutoToc @@ -72,23 +73,23 @@ for operator<". The reason that the \c template keyword is necessary in the last example has to do with the rules for how templates are supposed to be compiled in C++. The compiler has to check the code for correct syntax at the point where the template is defined, without knowing the actual value of the template arguments (\c Derived1 -and \c Derived2 in the example). That means that the compiler cannot know that dst.triangularPart is +and \c Derived2 in the example). That means that the compiler cannot know that dst.triangularView is a member template and that the following < symbol is part of the delimiter for the template -parameter. Another possibility would be that dst.triangularPart is a member variable with the < +parameter. Another possibility would be that dst.triangularView is a member variable with the < symbol refering to the operator<() function. In fact, the compiler should choose the second -possibility, according to the standard. If dst.triangularPart is a member template (as in our case), +possibility, according to the standard. If dst.triangularView is a member template (as in our case), the programmer should specify this explicitly with the \c template keyword and write dst.template -triangularPart. +triangularView. The precise rules are rather complicated, but ignoring some subtleties we can summarize them as follows: - A dependent name is name that depends (directly or indirectly) on a template parameter. In the example, \c dst is a dependent name because it is of type MatrixBase<Derived1> which depends on the template parameter \c Derived1. -- If the code contains either one of the contructions xxx.yyy or xxx->yyy and \c xxx is a +- If the code contains either one of the constructs xxx.yyy or xxx->yyy and \c xxx is a dependent name and \c yyy refers to a member template, then the \c template keyword must be used before \c yyy, leading to xxx.template yyy or xxx->template yyy. -- If the code contains the contruction xxx::yyy and \c xxx is a dependent name and \c yyy refers to a - member typedef, then the \c typename keyword must be used before the whole construction, leading to +- If the code contains the construct xxx::yyy and \c xxx is a dependent name and \c yyy refers to a + member typedef, then the \c typename keyword must be used before the whole construct, leading to typename xxx::yyy. As an example where the \c typename keyword is required, consider the following code in \ref TutorialSparse diff --git a/ground/gcs/src/libs/eigen/doc/TopicAliasing.dox b/ground/gcs/src/libs/eigen/doc/TopicAliasing.dox index c2654aed26..a8f1644284 100644 --- a/ground/gcs/src/libs/eigen/doc/TopicAliasing.dox +++ b/ground/gcs/src/libs/eigen/doc/TopicAliasing.dox @@ -153,10 +153,11 @@ not necessary to evaluate the right-hand side explicitly. \section TopicAliasingMatrixMult Aliasing and matrix multiplication -Matrix multiplication is the only operation in %Eigen that assumes aliasing by default. Thus, if \c matA is a -matrix, then the statement matA = matA * matA; is safe. All other operations in %Eigen assume that -there are no aliasing problems, either because the result is assigned to a different matrix or because it is a -component-wise operation. +Matrix multiplication is the only operation in %Eigen that assumes aliasing by default, under the +condition that the destination matrix is not resized. +Thus, if \c matA is a \b squared matrix, then the statement matA = matA * matA; is safe. +All other operations in %Eigen assume that there are no aliasing problems, +either because the result is assigned to a different matrix or because it is a component-wise operation. @@ -198,6 +199,27 @@ may get wrong results: \verbinclude TopicAliasing_mult3.out
ExampleOutput
+Moreover, starting in Eigen 3.3, aliasing is \b not assumed if the destination matrix is resized and the product is not directly assigned to the destination. +Therefore, the following example is also wrong: + + + + +
ExampleOutput
+\include TopicAliasing_mult4.cpp + +\verbinclude TopicAliasing_mult4.out +
+ +As for any aliasing issue, you can resolve it by explicitly evaluating the expression prior to assignment: + + + +
ExampleOutput
+\include TopicAliasing_mult5.cpp + +\verbinclude TopicAliasing_mult5.out +
\section TopicAliasingSummary Summary diff --git a/ground/gcs/src/libs/eigen/doc/TopicAssertions.dox b/ground/gcs/src/libs/eigen/doc/TopicAssertions.dox index 4ead40174b..c8b4d84f2f 100644 --- a/ground/gcs/src/libs/eigen/doc/TopicAssertions.dox +++ b/ground/gcs/src/libs/eigen/doc/TopicAssertions.dox @@ -16,7 +16,7 @@ Both eigen_assert and eigen_plain_assert are defined in Macros.h. Defining eigen #include #undef eigen_assert #define eigen_assert(x) \ - if (!x) { throw (std::runtime_error("Put your message here")); } + if (!(x)) { throw (std::runtime_error("Put your message here")); } \endcode \subsection DisableAssert Disabling assertions diff --git a/ground/gcs/src/libs/eigen/doc/TopicCMakeGuide.dox b/ground/gcs/src/libs/eigen/doc/TopicCMakeGuide.dox new file mode 100644 index 0000000000..896cfa831d --- /dev/null +++ b/ground/gcs/src/libs/eigen/doc/TopicCMakeGuide.dox @@ -0,0 +1,52 @@ +namespace Eigen { + +/** + +\page TopicCMakeGuide Using %Eigen in CMake Projects + +%Eigen provides native CMake support which allows the library to be easily +used in CMake projects. + +\note %CMake 3.0 (or later) is required to enable this functionality. + +%Eigen exports a CMake target called `Eigen3::Eigen` which can be imported +using the `find_package` CMake command and used by calling +`target_link_libraries` as in the following example: +\code{.cmake} +cmake_minimum_required (VERSION 3.0) +project (myproject) + +find_package (Eigen3 3.3 REQUIRED NO_MODULE) + +add_executable (example example.cpp) +target_link_libraries (example Eigen3::Eigen) +\endcode + +The above code snippet must be placed in a file called `CMakeLists.txt` alongside +`example.cpp`. After running +\code{.sh} +$ cmake path-to-example-directory +\endcode +CMake will produce project files that generate an executable called `example` +which requires at least version 3.3 of %Eigen. Here, `path-to-example-directory` +is the path to the directory that contains both `CMakeLists.txt` and +`example.cpp`. + +If you have multiple installed version of %Eigen, you can pick your favorite one by setting the \c Eigen3_DIR cmake's variable to the respective path containing the \c Eigen3*.cmake files. For instance: +\code +cmake path-to-example-directory -DEigen3_DIR=$HOME/mypackages/share/eigen3/cmake/ +\endcode + +If the `REQUIRED` option is omitted when locating %Eigen using +`find_package`, one can check whether the package was found as follows: +\code{.cmake} +find_package (Eigen3 3.3 NO_MODULE) + +if (TARGET Eigen3::Eigen) + # Use the imported target +endif (TARGET Eigen3::Eigen) +\endcode + +*/ + +} diff --git a/ground/gcs/src/libs/eigen/doc/TopicLazyEvaluation.dox b/ground/gcs/src/libs/eigen/doc/TopicLazyEvaluation.dox index 393bc41d87..101ef8c72c 100644 --- a/ground/gcs/src/libs/eigen/doc/TopicLazyEvaluation.dox +++ b/ground/gcs/src/libs/eigen/doc/TopicLazyEvaluation.dox @@ -36,7 +36,7 @@ Here is now a more involved example: Eigen chooses lazy evaluation at every stage in that example, which is clearly the correct choice. In fact, lazy evaluation is the "default choice" and Eigen will choose it except in a few circumstances. -The first circumstance in which Eigen chooses immediate evaluation, is when it sees an assignment a = b; and the expression \c b has the evaluate-before-assigning \link flags flag\endlink. The most important example of such an expression is the \link GeneralProduct matrix product expression\endlink. For example, when you do +The first circumstance in which Eigen chooses immediate evaluation, is when it sees an assignment a = b; and the expression \c b has the evaluate-before-assigning \link flags flag\endlink. The most important example of such an expression is the \link Product matrix product expression\endlink. For example, when you do \code matrix = matrix * matrix; \endcode @@ -48,7 +48,7 @@ What if you know that the result does no alias the operand of the product and wa Here, since we know that matrix2 is not the same matrix as matrix1, we know that lazy evaluation is not dangerous, so we may force lazy evaluation. Concretely, the effect of noalias() here is to bypass the evaluate-before-assigning \link flags flag\endlink. -The second circumstance in which Eigen chooses immediate evaluation, is when it sees a nested expression such as a + b where \c b is already an expression having the evaluate-before-nesting \link flags flag\endlink. Again, the most important example of such an expression is the \link GeneralProduct matrix product expression\endlink. For example, when you do +The second circumstance in which Eigen chooses immediate evaluation, is when it sees a nested expression such as a + b where \c b is already an expression having the evaluate-before-nesting \link flags flag\endlink. Again, the most important example of such an expression is the \link Product matrix product expression\endlink. For example, when you do \code matrix1 = matrix2 + matrix3 * matrix4; \endcode diff --git a/ground/gcs/src/libs/eigen/doc/TopicLinearAlgebraDecompositions.dox b/ground/gcs/src/libs/eigen/doc/TopicLinearAlgebraDecompositions.dox index 8649cc27b6..4914706279 100644 --- a/ground/gcs/src/libs/eigen/doc/TopicLinearAlgebraDecompositions.dox +++ b/ground/gcs/src/libs/eigen/doc/TopicLinearAlgebraDecompositions.dox @@ -4,6 +4,7 @@ namespace Eigen { This page presents a catalogue of the dense matrix decompositions offered by Eigen. For an introduction on linear solvers and decompositions, check this \link TutorialLinearAlgebra page \endlink. +To get an overview of the true relative speed of the different decomposition, check this \link DenseDecompositionBenchmark benchmark \endlink. \section TopicLinAlgBigTable Catalogue of decompositions offered by Eigen @@ -116,7 +117,7 @@ For an introduction on linear solvers and decompositions, check this \link Tutor JacobiSVD (two-sided) - Slow (but fast for small matrices) - Excellent-Proven3 + Proven3 Yes Singular values/vectors, least squares Yes (and does least squares) @@ -132,7 +133,7 @@ For an introduction on linear solvers and decompositions, check this \link Tutor Yes Eigenvalues/vectors - - Good + Excellent Closed forms for 2x2 and 3x3 @@ -249,13 +250,14 @@ For an introduction on linear solvers and decompositions, check this \link Tutor
Implicit Multi Threading (MT)
Means the algorithm can take advantage of multicore processors via OpenMP. "Implicit" means the algortihm itself is not parallelized, but that it relies on parallelized matrix-matrix product rountines.
Explicit Multi Threading (MT)
-
Means the algorithm is explicitely parallelized to take advantage of multicore processors via OpenMP.
+
Means the algorithm is explicitly parallelized to take advantage of multicore processors via OpenMP.
Meta-unroller
Means the algorithm is automatically and explicitly unrolled for very small fixed size matrices.
+ */ } diff --git a/ground/gcs/src/libs/eigen/doc/TopicMultithreading.dox b/ground/gcs/src/libs/eigen/doc/TopicMultithreading.dox index 7db2b0e070..47c9b261f8 100644 --- a/ground/gcs/src/libs/eigen/doc/TopicMultithreading.dox +++ b/ground/gcs/src/libs/eigen/doc/TopicMultithreading.dox @@ -8,13 +8,13 @@ Some Eigen's algorithms can exploit the multiple cores present in your hardware. * GCC: \c -fopenmp * ICC: \c -openmp * MSVC: check the respective option in the build properties. -You can control the number of thread that will be used using either the OpenMP API or Eiegn's API using the following priority: +You can control the number of thread that will be used using either the OpenMP API or Eigen's API using the following priority: \code OMP_NUM_THREADS=n ./my_program omp_set_num_threads(n); Eigen::setNbThreads(n); \endcode -Unless setNbThreads has been called, Eigen uses the number of threads specified by OpenMP. You can restore this bahavior by calling \code setNbThreads(0); \endcode +Unless setNbThreads has been called, Eigen uses the number of threads specified by OpenMP. You can restore this behavior by calling \code setNbThreads(0); \endcode You can query the number of threads that will be used with: \code n = Eigen::nbThreads( ); @@ -22,8 +22,12 @@ n = Eigen::nbThreads( ); You can disable Eigen's multi threading at compile time by defining the EIGEN_DONT_PARALLELIZE preprocessor token. Currently, the following algorithms can make use of multi-threading: - * general matrix - matrix products - * PartialPivLU + - general dense matrix - matrix products + - PartialPivLU + - row-major-sparse * dense vector/matrix products + - ConjugateGradient with \c Lower|Upper as the \c UpLo template parameter. + - BiCGSTAB with a row-major sparse matrix format. + - LeastSquaresConjugateGradient \section TopicMultiThreading_UsingEigenWithMT Using Eigen in a multi-threaded application @@ -39,6 +43,10 @@ int main(int argc, char** argv) } \endcode +\note With Eigen 3.3, and a fully C++11 compliant compiler (i.e., thread-safe static local variable initialization), then calling \c initParallel() is optional. + +\warning note that all functions generating random matrices are \b not re-entrant nor thread-safe. Those include DenseBase::Random(), and DenseBase::setRandom() despite a call to Eigen::initParallel(). This is because these functions are based on std::rand which is not re-entrant. For thread-safe random generator, we recommend the use of boost::random or c++11 random feature. + In the case your application is parallelized with OpenMP, you might want to disable Eigen's own parallization as detailed in the previous section. */ diff --git a/ground/gcs/src/libs/eigen/doc/TutorialArrayClass.dox b/ground/gcs/src/libs/eigen/doc/TutorialArrayClass.dox index 6432684aa5..f6f351091a 100644 --- a/ground/gcs/src/libs/eigen/doc/TutorialArrayClass.dox +++ b/ground/gcs/src/libs/eigen/doc/TutorialArrayClass.dox @@ -157,7 +157,7 @@ The following example shows how to use array operations on a Matrix object by em * to multiply them coefficient-wise and assigns the result to the matrix variable \c result (this is legal because Eigen allows assigning array expressions to matrix variables). -As a matter of fact, this usage case is so common that Eigen provides a \link MatrixBase::cwiseProduct() const +As a matter of fact, this usage case is so common that Eigen provides a \link MatrixBase::cwiseProduct const .cwiseProduct(.) \endlink method for matrices to compute the coefficient-wise product. This is also shown in the example program. diff --git a/ground/gcs/src/libs/eigen/doc/TutorialGeometry.dox b/ground/gcs/src/libs/eigen/doc/TutorialGeometry.dox index 372a275de4..2e1420f98c 100644 --- a/ground/gcs/src/libs/eigen/doc/TutorialGeometry.dox +++ b/ground/gcs/src/libs/eigen/doc/TutorialGeometry.dox @@ -126,11 +126,12 @@ Apply the transformation to a \b vector \code VectorNf vec1, vec2; vec2 = t.linear() * vec1;\endcode -Apply a \em general transformation \n to a \b normal \b vector -(explanations)\code +Apply a \em general transformation \n to a \b normal \b vector \n +\code VectorNf n1, n2; MatrixNf normalMatrix = t.linear().inverse().transpose(); n2 = (normalMatrix * n1).normalized();\endcode +(See subject 5.27 of this faq for the explanations) Apply a transformation with \em pure \em rotation \n to a \b normal \b vector (no scaling, no shear)\code @@ -231,8 +232,8 @@ On the other hand, since there exist 24 different conventions, they are pretty c to create a rotation matrix according to the 2-1-2 convention.\code Matrix3f m; m = AngleAxisf(angle1, Vector3f::UnitZ()) -* * AngleAxisf(angle2, Vector3f::UnitY()) -* * AngleAxisf(angle3, Vector3f::UnitZ()); + * AngleAxisf(angle2, Vector3f::UnitY()) + * AngleAxisf(angle3, Vector3f::UnitZ()); \endcode diff --git a/ground/gcs/src/libs/eigen/doc/TutorialLinearAlgebra.dox b/ground/gcs/src/libs/eigen/doc/TutorialLinearAlgebra.dox index b09f3543e9..cb92ceeae1 100644 --- a/ground/gcs/src/libs/eigen/doc/TutorialLinearAlgebra.dox +++ b/ground/gcs/src/libs/eigen/doc/TutorialLinearAlgebra.dox @@ -40,8 +40,9 @@ depending on your matrix and the trade-off you want to make: Decomposition Method - Requirements on the matrix - Speed + Requirements
on the matrix + Speed
(small-to-medium) + Speed
(large) Accuracy @@ -49,6 +50,7 @@ depending on your matrix and the trade-off you want to make: partialPivLu() Invertible ++ + ++ + @@ -56,6 +58,7 @@ depending on your matrix and the trade-off you want to make: fullPivLu() None - + - - +++ @@ -63,20 +66,23 @@ depending on your matrix and the trade-off you want to make: householderQr() None ++ + ++ + ColPivHouseholderQR colPivHouseholderQr() None - + ++ + - + +++ FullPivHouseholderQR fullPivHouseholderQr() None - + - - +++ @@ -84,21 +90,31 @@ depending on your matrix and the trade-off you want to make: llt() Positive definite +++ + +++ + LDLT ldlt() - Positive or negative semidefinite + Positive or negative
semidefinite +++ + + ++ + + JacobiSVD + jacobiSvd() + None + - - + - - - + +++ + All of these decompositions offer a solve() method that works as in the above example. For example, if your matrix is positive definite, the above table says that a very good -choice is then the LDLT decomposition. Here's an example, also demonstrating that using a general +choice is then the LLT or LDLT decomposition. Here's an example, also demonstrating that using a general matrix (not a vector) as right hand side is possible. @@ -167,8 +183,8 @@ Here is an example: \section TutorialLinAlgLeastsquares Least squares solving -The best way to do least squares solving is with a SVD decomposition. Eigen provides one as the JacobiSVD class, and its solve() -is doing least-squares solving. +The most accurate method to do least squares solving is with a SVD decomposition. Eigen provides one +as the JacobiSVD class, and its solve() is doing least-squares solving. Here is an example:
@@ -179,9 +195,10 @@ Here is an example:
-Another way, potentially faster but less reliable, is to use a LDLT decomposition -of the normal matrix. In any case, just read any reference text on least squares, and it will be very easy for you -to implement any linear least squares computation on top of Eigen. +Another methods, potentially faster but less reliable, are to use a Cholesky decomposition of the +normal matrix or a QR decomposition. Our page on \link LeastSquares least squares solving \endlink +has more details. + \section TutorialLinAlgSeparateComputation Separating the computation from the construction diff --git a/ground/gcs/src/libs/eigen/doc/TutorialReductionsVisitorsBroadcasting.dox b/ground/gcs/src/libs/eigen/doc/TutorialReductionsVisitorsBroadcasting.dox index 992cf6f345..f5322b4a6f 100644 --- a/ground/gcs/src/libs/eigen/doc/TutorialReductionsVisitorsBroadcasting.dox +++ b/ground/gcs/src/libs/eigen/doc/TutorialReductionsVisitorsBroadcasting.dox @@ -32,7 +32,7 @@ Eigen also provides the \link MatrixBase::norm() norm() \endlink method, which r These operations can also operate on matrices; in that case, a n-by-p matrix is seen as a vector of size (n*p), so for example the \link MatrixBase::norm() norm() \endlink method returns the "Frobenius" or "Hilbert-Schmidt" norm. We refrain from speaking of the \f$\ell^2\f$ norm of a matrix because that can mean different things. -If you want other \f$\ell^p\f$ norms, use the \link MatrixBase::lpNorm() lpNnorm

() \endlink method. The template parameter \a p can take the special value \a Infinity if you want the \f$\ell^\infty\f$ norm, which is the maximum of the absolute values of the coefficients. +If you want other coefficient-wise \f$\ell^p\f$ norms, use the \link MatrixBase::lpNorm lpNorm

() \endlink method. The template parameter \a p can take the special value \a Infinity if you want the \f$\ell^\infty\f$ norm, which is the maximum of the absolute values of the coefficients. The following example demonstrates these methods. @@ -45,6 +45,17 @@ The following example demonstrates these methods. \verbinclude Tutorial_ReductionsVisitorsBroadcasting_reductions_norm.out +\b Operator \b norm: The 1-norm and \f$\infty\f$-norm matrix operator norms can easily be computed as follows: + + + +
Example:Output:
+\include Tutorial_ReductionsVisitorsBroadcasting_reductions_operatornorm.cpp + +\verbinclude Tutorial_ReductionsVisitorsBroadcasting_reductions_operatornorm.out +
+See below for more explanations on the syntax of these expressions. + \subsection TutorialReductionsVisitorsBroadcastingReductionsBool Boolean reductions The following reductions operate on boolean values: @@ -79,7 +90,7 @@ Array. The arguments passed to a visitor are pointers to the variables where the row and column position are to be stored. These variables should be of type -\link DenseBase::Index Index \endlink, as shown below: +\link Eigen::Index Index \endlink, as shown below: @@ -90,17 +101,16 @@ row and column position are to be stored. These variables should be of type \verbinclude Tutorial_ReductionsVisitorsBroadcasting_visitors.out
Example:Output:
-Note that both functions also return the value of the minimum or maximum coefficient if needed, -as if it was a typical reduction operation. +Both functions also return the value of the minimum or maximum coefficient. \section TutorialReductionsVisitorsBroadcastingPartialReductions Partial reductions Partial reductions are reductions that can operate column- or row-wise on a Matrix or Array, applying the reduction operation on each column or row and -returning a column or row-vector with the corresponding values. Partial reductions are applied +returning a column or row vector with the corresponding values. Partial reductions are applied with \link DenseBase::colwise() colwise() \endlink or \link DenseBase::rowwise() rowwise() \endlink. A simple example is obtaining the maximum of the elements -in each column in a given matrix, storing the result in a row-vector: +in each column in a given matrix, storing the result in a row vector: @@ -122,8 +132,7 @@ The same operation can be performed row-wise: \verbinclude Tutorial_ReductionsVisitorsBroadcasting_rowwise.out
Example:Output:
-Note that column-wise operations return a 'row-vector' while row-wise operations -return a 'column-vector' +Note that column-wise operations return a row vector, while row-wise operations return a column vector. \subsection TutorialReductionsVisitorsBroadcastingPartialReductionsCombined Combining partial reductions with other operations It is also possible to use the result of a partial reduction to do further processing. @@ -165,7 +174,7 @@ The concept behind broadcasting is similar to partial reductions, with the diffe constructs an expression where a vector (column or row) is interpreted as a matrix by replicating it in one direction. -A simple example is to add a certain column-vector to each column in a matrix. +A simple example is to add a certain column vector to each column in a matrix. This can be accomplished with: @@ -242,7 +251,7 @@ is a new matrix whose size is the same as matrix m: \f[ \f] - (m.colwise() - v).colwise().squaredNorm() is a partial reduction, computing the squared norm column-wise. The result of -this operation is a row-vector where each coefficient is the squared Euclidean distance between each column in m and v: \f[ +this operation is a row vector where each coefficient is the squared Euclidean distance between each column in m and v: \f[ \mbox{(m.colwise() - v).colwise().squaredNorm()} = \begin{bmatrix} 1 & 505 & 32 & 50 diff --git a/ground/gcs/src/libs/eigen/doc/TutorialReshapeSlicing.dox b/ground/gcs/src/libs/eigen/doc/TutorialReshapeSlicing.dox new file mode 100644 index 0000000000..3730a5de6e --- /dev/null +++ b/ground/gcs/src/libs/eigen/doc/TutorialReshapeSlicing.dox @@ -0,0 +1,65 @@ +namespace Eigen { + +/** \eigenManualPage TutorialReshapeSlicing Reshape and Slicing + +%Eigen does not expose convenient methods to take slices or to reshape a matrix yet. +Nonetheless, such features can easily be emulated using the Map class. + +\eigenAutoToc + +\section TutorialReshape Reshape + +A reshape operation consists in modifying the sizes of a matrix while keeping the same coefficients. +Instead of modifying the input matrix itself, which is not possible for compile-time sizes, the approach consist in creating a different \em view on the storage using class Map. +Here is a typical example creating a 1D linear view of a matrix: + +
+ + +
Example:Output:
+\include Tutorial_ReshapeMat2Vec.cpp + +\verbinclude Tutorial_ReshapeMat2Vec.out +
+ +Remark how the storage order of the input matrix modifies the order of the coefficients in the linear view. +Here is another example reshaping a 2x6 matrix to a 6x2 one: + + + +
Example:Output:
+\include Tutorial_ReshapeMat2Mat.cpp + +\verbinclude Tutorial_ReshapeMat2Mat.out +
+ + + +\section TutorialSlicing Slicing + +Slicing consists in taking a set of rows, columns, or elements, uniformly spaced within a matrix. +Again, the class Map allows to easily mimic this feature. + +For instance, one can skip every P elements in a vector: + + + +
Example:Output:
+\include Tutorial_SlicingVec.cpp + +\verbinclude Tutorial_SlicingVec.out +
+ +One can olso take one column over three using an adequate outer-stride or inner-stride depending on the actual storage order: + + + +
Example:Output:
+\include Tutorial_SlicingCol.cpp + +\verbinclude Tutorial_SlicingCol.out +
+ +*/ + +} diff --git a/ground/gcs/src/libs/eigen/doc/TutorialSparse.dox b/ground/gcs/src/libs/eigen/doc/TutorialSparse.dox index ee206cc421..3529074088 100644 --- a/ground/gcs/src/libs/eigen/doc/TutorialSparse.dox +++ b/ground/gcs/src/libs/eigen/doc/TutorialSparse.dox @@ -83,7 +83,7 @@ There is no notion of compressed/uncompressed mode for a SparseVector. \section TutorialSparseExample First example -Before describing each individual class, let's start with the following typical example: solving the Laplace equation \f$ \nabla u = 0 \f$ on a regular 2D grid using a finite difference scheme and Dirichlet boundary conditions. +Before describing each individual class, let's start with the following typical example: solving the Laplace equation \f$ \Delta u = 0 \f$ on a regular 2D grid using a finite difference scheme and Dirichlet boundary conditions. Such problem can be mathematically expressed as a linear problem of the form \f$ Ax=b \f$ where \f$ x \f$ is the vector of \c m unknowns (in our case, the values of the pixels), \f$ b \f$ is the right hand side vector resulting from the boundary conditions, and \f$ A \f$ is an \f$ m \times m \f$ matrix containing only a few non-zero elements resulting from the discretization of the Laplacian operator. @@ -253,15 +253,19 @@ SparseMatrix A, B; B = SparseMatrix(A.transpose()) + A; \endcode -Some binary coefficient-wise operators can also mix sparse and dense expressions: +Binary coefficient wise operators can also mix sparse and dense expressions: \code sm2 = sm1.cwiseProduct(dm1); -dm1 += sm1; +dm2 = sm1 + dm1; +dm2 = dm1 - sm1; \endcode +Performance-wise, the adding/subtracting sparse and dense matrices is better performed in two steps. For instance, instead of doing dm2 = sm1 + dm1, better write: +\code +dm2 = dm1; +dm2 += sm1; +\endcode +This version has the advantage to fully exploit the higher performance of dense storage (no indirection, SIMD, etc.), and to pay the cost of slow sparse evaluation on the few non-zeros of the sparse matrix only. -However, it is not yet possible to add a sparse and a dense matrix as in dm2 = sm1 + dm1. -Please write this as the equivalent dm2 = dm1; dm2 += sm1 (we plan to lift this restriction -in the next release of %Eigen). %Sparse expressions also support transposition: \code diff --git a/ground/gcs/src/libs/eigen/doc/UnalignedArrayAssert.dox b/ground/gcs/src/libs/eigen/doc/UnalignedArrayAssert.dox index b0d6e18f29..95d95a2d51 100644 --- a/ground/gcs/src/libs/eigen/doc/UnalignedArrayAssert.dox +++ b/ground/gcs/src/libs/eigen/doc/UnalignedArrayAssert.dox @@ -8,7 +8,7 @@ my_program: path/to/eigen/Eigen/src/Core/DenseStorage.h:44: Eigen::internal::matrix_array::internal::matrix_array() [with T = double, int Size = 2, int MatrixOptions = 2, bool Align = true]: Assertion `(reinterpret_cast(array) & (sizemask)) == 0 && "this assertion -is explained here: http://eigen.tuxfamily.org/dox/group__TopicUnalignedArrayAssert.html +is explained here: http://eigen.tuxfamily.org/dox-devel/group__TopicUnalignedArrayAssert.html **** READ THIS WEB PAGE !!! ****"' failed. @@ -92,27 +92,28 @@ Note that here, Eigen::Quaternionf is only used as an example, more generally th \section explanation General explanation of this assertion -\ref TopicFixedSizeVectorizable "fixed-size vectorizable Eigen objects" must absolutely be created at 16-byte-aligned locations, otherwise SIMD instructions adressing them will crash. +\ref TopicFixedSizeVectorizable "fixed-size vectorizable Eigen objects" must absolutely be created at 16-byte-aligned locations, otherwise SIMD instructions addressing them will crash. Eigen normally takes care of these alignment issues for you, by setting an alignment attribute on them and by overloading their "operator new". However there are a few corner cases where these alignment settings get overridden: they are the possible causes for this assertion. -\section getrid I don't care about vectorization, how do I get rid of that stuff? +\section getrid I don't care about optimal vectorization, how do I get rid of that stuff? -Two possibilities: +Three possibilities:
    -
  • Define EIGEN_DONT_ALIGN_STATICALLY. That disables all 128-bit static alignment code, while keeping 128-bit heap alignment. This has the effect of - disabling vectorization for fixed-size objects (like Matrix4d) while keeping vectorization of dynamic-size objects - (like MatrixXd). But do note that this breaks ABI compatibility with the default behavior of 128-bit static alignment.
  • -
  • Or define both EIGEN_DONT_VECTORIZE and EIGEN_DISABLE_UNALIGNED_ARRAY_ASSERT. This keeps the - 128-bit alignment code and thus preserves ABI compatibility, but completely disables vectorization.
  • +
  • Use the \c DontAlign option to Matrix, Array, Quaternion, etc. objects that gives you trouble. This way Eigen won't try to align them, and thus won"t assume any special alignment. On the down side, you will pay the cost of unaligned loads/stores for them, but on modern CPUs, the overhead is either null or marginal. See \link StructHavingEigenMembers_othersolutions here \endlink for an example.
  • +
  • Define \link TopicPreprocessorDirectivesPerformance EIGEN_DONT_ALIGN_STATICALLY \endlink. That disables all 16-byte (and above) static alignment code, while keeping 16-byte (or above) heap alignment. This has the effect of + vectorizing fixed-size objects (like Matrix4d) through unaligned stores (as controlled by \link TopicPreprocessorDirectivesPerformance EIGEN_UNALIGNED_VECTORIZE \endlink), while keeping unchanged the vectorization of dynamic-size objects + (like MatrixXd). But do note that this breaks ABI compatibility with the default behavior of static alignment.
  • +
  • Or define both \link TopicPreprocessorDirectivesPerformance EIGEN_DONT_VECTORIZE \endlink and EIGEN_DISABLE_UNALIGNED_ARRAY_ASSERT. This keeps the + 16-byte alignment code and thus preserves ABI compatibility, but completely disables vectorization.
-If you want to know why defining EIGEN_DONT_VECTORIZE does not by itself disable 128-bit alignment and the assertion, here's the explanation: +If you want to know why defining EIGEN_DONT_VECTORIZE does not by itself disable 16-byte alignment and the assertion, here's the explanation: It doesn't disable the assertion, because otherwise code that runs fine without vectorization would suddenly crash when enabling vectorization. -It doesn't disable 128bit alignment, because that would mean that vectorized and non-vectorized code are not mutually ABI-compatible. This ABI compatibility is very important, even for people who develop only an in-house application, as for instance one may want to have in the same application a vectorized path and a non-vectorized path. +It doesn't disable 16-byte alignment, because that would mean that vectorized and non-vectorized code are not mutually ABI-compatible. This ABI compatibility is very important, even for people who develop only an in-house application, as for instance one may want to have in the same application a vectorized path and a non-vectorized path. */ diff --git a/ground/gcs/src/libs/eigen/doc/UsingBlasLapackBackends.dox b/ground/gcs/src/libs/eigen/doc/UsingBlasLapackBackends.dox new file mode 100644 index 0000000000..caa597122a --- /dev/null +++ b/ground/gcs/src/libs/eigen/doc/UsingBlasLapackBackends.dox @@ -0,0 +1,133 @@ +/* + Copyright (c) 2011, Intel Corporation. All rights reserved. + Copyright (C) 2011-2016 Gael Guennebaud + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of Intel Corporation nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + ******************************************************************************** + * Content : Documentation on the use of BLAS/LAPACK libraries through Eigen + ******************************************************************************** +*/ + +namespace Eigen { + +/** \page TopicUsingBlasLapack Using BLAS/LAPACK from %Eigen + + +Since %Eigen version 3.3 and later, any F77 compatible BLAS or LAPACK libraries can be used as backends for dense matrix products and dense matrix decompositions. +For instance, one can use Intel® MKL, Apple's Accelerate framework on OSX, OpenBLAS, Netlib LAPACK, etc. + +Do not miss this \link TopicUsingIntelMKL page \endlink for further discussions on the specific use of Intel® MKL (also includes VML, PARDISO, etc.) + +In order to use an external BLAS and/or LAPACK library, you must link you own application to the respective libraries and their dependencies. +For LAPACK, you must also link to the standard Lapacke library, which is used as a convenient think layer between %Eigen's C++ code and LAPACK F77 interface. Then you must activate their usage by defining one or multiple of the following macros (\b before including any %Eigen's header): + +\note For Mac users, in order to use the lapack version shipped with the Accelerate framework, you also need the lapacke library. +Using MacPorts, this is as easy as: +\code +sudo port install lapack +\endcode +and then use the following link flags: \c -framework \c Accelerate \c /opt/local/lib/lapack/liblapacke.dylib + +
+ + + +
\c EIGEN_USE_BLAS Enables the use of external BLAS level 2 and 3 routines (compatible with any F77 BLAS interface)
\c EIGEN_USE_LAPACKE Enables the use of external Lapack routines via the Lapacke C interface to Lapack (compatible with any F77 LAPACK interface)
\c EIGEN_USE_LAPACKE_STRICT Same as \c EIGEN_USE_LAPACKE but algorithms of lower numerical robustness are disabled. \n This currently concerns only JacobiSVD which otherwise would be replaced by \c gesvd that is less robust than Jacobi rotations.
+ +When doing so, a number of %Eigen's algorithms are silently substituted with calls to BLAS or LAPACK routines. +These substitutions apply only for \b Dynamic \b or \b large enough objects with one of the following four standard scalar types: \c float, \c double, \c complex, and \c complex. +Operations on other scalar types or mixing reals and complexes will continue to use the built-in algorithms. + +The breadth of %Eigen functionality that can be substituted is listed in the table below. + + + + + + + + + + +
Functional domainCode exampleBLAS/LAPACK routines
Matrix-matrix operations \n \c EIGEN_USE_BLAS \code +m1*m2.transpose(); +m1.selfadjointView()*m2; +m1*m2.triangularView(); +m1.selfadjointView().rankUpdate(m2,1.0); +\endcode\code +?gemm +?symm/?hemm +?trmm +dsyrk/ssyrk +\endcode
Matrix-vector operations \n \c EIGEN_USE_BLAS \code +m1.adjoint()*b; +m1.selfadjointView()*b; +m1.triangularView()*b; +\endcode\code +?gemv +?symv/?hemv +?trmv +\endcode
LU decomposition \n \c EIGEN_USE_LAPACKE \n \c EIGEN_USE_LAPACKE_STRICT \code +v1 = m1.lu().solve(v2); +\endcode\code +?getrf +\endcode
Cholesky decomposition \n \c EIGEN_USE_LAPACKE \n \c EIGEN_USE_LAPACKE_STRICT \code +v1 = m2.selfadjointView().llt().solve(v2); +\endcode\code +?potrf +\endcode
QR decomposition \n \c EIGEN_USE_LAPACKE \n \c EIGEN_USE_LAPACKE_STRICT \code +m1.householderQr(); +m1.colPivHouseholderQr(); +\endcode\code +?geqrf +?geqp3 +\endcode
Singular value decomposition \n \c EIGEN_USE_LAPACKE \code +JacobiSVD svd; +svd.compute(m1, ComputeThinV); +\endcode\code +?gesvd +\endcode
Eigen-value decompositions \n \c EIGEN_USE_LAPACKE \n \c EIGEN_USE_LAPACKE_STRICT \code +EigenSolver es(m1); +ComplexEigenSolver ces(m1); +SelfAdjointEigenSolver saes(m1+m1.transpose()); +GeneralizedSelfAdjointEigenSolver + gsaes(m1+m1.transpose(),m2+m2.transpose()); +\endcode\code +?gees +?gees +?syev/?heev +?syev/?heev, +?potrf +\endcode
Schur decomposition \n \c EIGEN_USE_LAPACKE \n \c EIGEN_USE_LAPACKE_STRICT \code +RealSchur schurR(m1); +ComplexSchur schurC(m1); +\endcode\code +?gees +\endcode
+In the examples, m1 and m2 are dense matrices and v1 and v2 are dense vectors. + +*/ + +} diff --git a/ground/gcs/src/libs/eigen/doc/UsingIntelMKL.dox b/ground/gcs/src/libs/eigen/doc/UsingIntelMKL.dox index 84db992b63..a1a3a18f26 100644 --- a/ground/gcs/src/libs/eigen/doc/UsingIntelMKL.dox +++ b/ground/gcs/src/libs/eigen/doc/UsingIntelMKL.dox @@ -32,107 +32,45 @@ namespace Eigen { -/** \page TopicUsingIntelMKL Using Intel® Math Kernel Library from Eigen +/** \page TopicUsingIntelMKL Using Intel® MKL from %Eigen -\section TopicUsingIntelMKL_Intro Eigen and Intel® Math Kernel Library (Intel® MKL) + + +Since %Eigen version 3.1 and later, users can benefit from built-in Intel® Math Kernel Library (MKL) optimizations with an installed copy of Intel MKL 10.3 (or later). -Since Eigen version 3.1 and later, users can benefit from built-in Intel MKL optimizations with an installed copy of Intel MKL 10.3 (or later). Intel MKL provides highly optimized multi-threaded mathematical routines for x86-compatible architectures. Intel MKL is available on Linux, Mac and Windows for both Intel64 and IA32 architectures. \note Intel® MKL is a proprietary software and it is the responsibility of users to buy or register for community (free) Intel MKL licenses for their products. Moreover, the license of the user product has to allow linking to proprietary software that excludes any unmodified versions of the GPL. -Using Intel MKL through Eigen is easy: --# define the \c EIGEN_USE_MKL_ALL macro before including any Eigen's header +Using Intel MKL through %Eigen is easy: +-# define the \c EIGEN_USE_MKL_ALL macro before including any %Eigen's header -# link your program to MKL libraries (see the MKL linking advisor) -# on a 64bits system, you must use the LP64 interface (not the ILP64 one) -When doing so, a number of Eigen's algorithms are silently substituted with calls to Intel MKL routines. +When doing so, a number of %Eigen's algorithms are silently substituted with calls to Intel MKL routines. These substitutions apply only for \b Dynamic \b or \b large enough objects with one of the following four standard scalar types: \c float, \c double, \c complex, and \c complex. Operations on other scalar types or mixing reals and complexes will continue to use the built-in algorithms. -In addition you can coarsely select choose which parts will be substituted by defining one or multiple of the following macros: +In addition you can choose which parts will be substituted by defining one or multiple of the following macros: - - - + + +
\c EIGEN_USE_BLAS Enables the use of external BLAS level 2 and 3 routines (currently works with Intel MKL only)
\c EIGEN_USE_LAPACKE Enables the use of external Lapack routines via the Intel Lapacke C interface to Lapack (currently works with Intel MKL only)
\c EIGEN_USE_LAPACKE_STRICT Same as \c EIGEN_USE_LAPACKE but algorithm of lower robustness are disabled. This currently concerns only JacobiSVD which otherwise would be replaced by \c gesvd that is less robust than Jacobi rotations.
\c EIGEN_USE_BLAS Enables the use of external BLAS level 2 and 3 routines
\c EIGEN_USE_LAPACKE Enables the use of external Lapack routines via the Lapacke C interface to Lapack
\c EIGEN_USE_LAPACKE_STRICT Same as \c EIGEN_USE_LAPACKE but algorithm of lower robustness are disabled. \n This currently concerns only JacobiSVD which otherwise would be replaced by \c gesvd that is less robust than Jacobi rotations.
\c EIGEN_USE_MKL_VML Enables the use of Intel VML (vector operations)
\c EIGEN_USE_MKL_ALL Defines \c EIGEN_USE_BLAS, \c EIGEN_USE_LAPACKE, and \c EIGEN_USE_MKL_VML
-Finally, the PARDISO sparse solver shipped with Intel MKL can be used through the \ref PardisoLU, \ref PardisoLLT and \ref PardisoLDLT classes of the \ref PardisoSupport_Module. - +Note that the BLAS and LAPACKE backends can be enabled for any F77 compatible BLAS and LAPACK libraries. See this \link TopicUsingBlasLapack page \endlink for the details. -\section TopicUsingIntelMKL_SupportedFeatures List of supported features +Finally, the PARDISO sparse solver shipped with Intel MKL can be used through the \ref PardisoLU, \ref PardisoLLT and \ref PardisoLDLT classes of the \ref PardisoSupport_Module. -The breadth of Eigen functionality covered by Intel MKL is listed in the table below. +The following table summarizes the list of functions covered by \c EIGEN_USE_MKL_VML: - - - - - - - - - - +
Functional domainCode exampleMKL routines
Matrix-matrix operations \n \c EIGEN_USE_BLAS \code -m1*m2.transpose(); -m1.selfadjointView()*m2; -m1*m2.triangularView(); -m1.selfadjointView().rankUpdate(m2,1.0); -\endcode\code -?gemm -?symm/?hemm -?trmm -dsyrk/ssyrk -\endcode
Matrix-vector operations \n \c EIGEN_USE_BLAS \code -m1.adjoint()*b; -m1.selfadjointView()*b; -m1.triangularView()*b; -\endcode\code -?gemv -?symv/?hemv -?trmv -\endcode
LU decomposition \n \c EIGEN_USE_LAPACKE \n \c EIGEN_USE_LAPACKE_STRICT \code -v1 = m1.lu().solve(v2); -\endcode\code -?getrf -\endcode
Cholesky decomposition \n \c EIGEN_USE_LAPACKE \n \c EIGEN_USE_LAPACKE_STRICT \code -v1 = m2.selfadjointView().llt().solve(v2); -\endcode\code -?potrf -\endcode
QR decomposition \n \c EIGEN_USE_LAPACKE \n \c EIGEN_USE_LAPACKE_STRICT \code -m1.householderQr(); -m1.colPivHouseholderQr(); -\endcode\code -?geqrf -?geqp3 -\endcode
Singular value decomposition \n \c EIGEN_USE_LAPACKE \code -JacobiSVD svd; -svd.compute(m1, ComputeThinV); -\endcode\code -?gesvd -\endcode
Eigen-value decompositions \n \c EIGEN_USE_LAPACKE \n \c EIGEN_USE_LAPACKE_STRICT \code -EigenSolver es(m1); -ComplexEigenSolver ces(m1); -SelfAdjointEigenSolver saes(m1+m1.transpose()); -GeneralizedSelfAdjointEigenSolver - gsaes(m1+m1.transpose(),m2+m2.transpose()); -\endcode\code -?gees -?gees -?syev/?heev -?syev/?heev, -?potrf -\endcode
Schur decomposition \n \c EIGEN_USE_LAPACKE \n \c EIGEN_USE_LAPACKE_STRICT \code -RealSchur schurR(m1); -ComplexSchur schurC(m1); -\endcode\code -?gees -\endcode
Vector Math \n \c EIGEN_USE_MKL_VML \code +
Code exampleMKL routines
\code v2=v1.array().sin(); v2=v1.array().asin(); v2=v1.array().cos(); @@ -156,7 +94,7 @@ v?Sqr v?Powx \endcode
-In the examples, m1 and m2 are dense matrices and v1 and v2 are dense vectors. +In the examples, v1 and v2 are dense vectors. \section TopicUsingIntelMKL_Links Links diff --git a/ground/gcs/src/libs/eigen/doc/UsingNVCC.dox b/ground/gcs/src/libs/eigen/doc/UsingNVCC.dox new file mode 100644 index 0000000000..f8e755b79d --- /dev/null +++ b/ground/gcs/src/libs/eigen/doc/UsingNVCC.dox @@ -0,0 +1,32 @@ + +namespace Eigen { + +/** \page TopicCUDA Using Eigen in CUDA kernels + +\b Disclaimer: this page is about an \b experimental feature in %Eigen. + +Staring from CUDA 5.0, the CUDA compiler, \c nvcc, is able to properly parse %Eigen's code (almost). +A few adaptations of the %Eigen's code already allows to use some parts of %Eigen in your own CUDA kernels. +To this end you need the devel branch of %Eigen, CUDA 5.0 or greater with GCC. + +Known issues: + + - \c nvcc with MS Visual Studio does not work (patch welcome) + + - \c nvcc with \c clang does not work (patch welcome) + + - \c nvcc 5.5 with gcc-4.7 (or greater) has issues with the standard \c \ header file. To workaround this, you can add the following before including any other files: + \code + // workaround issue between gcc >= 4.7 and cuda 5.5 + #if (defined __GNUC__) && (__GNUC__>4 || __GNUC_MINOR__>=7) + #undef _GLIBCXX_ATOMIC_BUILTINS + #undef _GLIBCXX_USE_INT128 + #endif + \endcode + + - On 64bits system Eigen uses \c long \c int as the default type for indexes and sizes. On CUDA device, it would make sense to default to 32 bits \c int. + However, to keep host and CUDA code compatible, this cannot be done automatically by %Eigen, and the user is thus required to define \c EIGEN_DEFAULT_DENSE_INDEX_TYPE to \c int throughout his code (or only for CUDA code if there is no interaction between host and CUDA code through %Eigen's object). + +*/ + +} diff --git a/ground/gcs/src/libs/eigen/doc/eigendoxy.css b/ground/gcs/src/libs/eigen/doc/eigendoxy.css index efaeb46dc2..6274e6c704 100644 --- a/ground/gcs/src/libs/eigen/doc/eigendoxy.css +++ b/ground/gcs/src/libs/eigen/doc/eigendoxy.css @@ -45,7 +45,7 @@ pre.fragment { /* Common style for all Eigen's tables */ -table.example, table.manual, table.manual-vl { +table.example, table.manual, table.manual-vl, table.manual-hl { max-width:100%; border-collapse: collapse; border-style: solid; @@ -58,7 +58,7 @@ table.example, table.manual, table.manual-vl { -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); } -table.example th, table.manual th, table.manual-vl th { +table.example th, table.manual th, table.manual-vl th, table.manual-hl th { padding: 0.5em 0.5em 0.5em 0.5em; text-align: left; padding-right: 1em; @@ -70,7 +70,7 @@ table.example th, table.manual th, table.manual-vl th { filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFF', endColorstr='#F4F4E5'); } -table.example td, table.manual td, table.manual-vl td { +table.example td, table.manual td, table.manual-vl td, table.manual-hl td { vertical-align:top; border-width: 1px; border-color: #cccccc; @@ -108,15 +108,15 @@ table.example td { /* standard class for the manual */ -table.manual, table.manual-vl { +table.manual, table.manual-vl, table.manual-hl { padding: 0.2em 0em 0.5em 0em; } -table.manual th, table.manual-vl th { +table.manual th, table.manual-vl th, table.manual-hl th { margin: 0em 0em 0.3em 0em; } -table.manual td, table.manual-vl td { +table.manual td, table.manual-vl td, table.manual-hl td { padding: 0.3em 0.5em 0.3em 0.5em; vertical-align:top; border-width: 1px; @@ -136,6 +136,16 @@ table.manual-vl th.inter { border-style: solid solid solid solid; } +table.manual-hl td { + border-color: #cccccc; + border-width: 1px; + border-style: solid none solid none; +} + +table td.code { + font-family: monospace; +} + h2 { margin-top:2em; border-style: none none solid none; @@ -166,6 +176,11 @@ div.toc ul { margin: 0.2em 0 0.4em 0.5em; } +span.cpp11,span.cpp14,span.cpp17 { + color: #119911; + font-weight: bold; +} + /**** old Eigen's styles ****/ @@ -177,8 +192,8 @@ table.tutorial_code td { /* Whenever doxygen meets a '\n' or a '
', it will put - * the text containing the characted into a

. - * This little hack togehter with table.tutorial_code td.note + * the text containing the character into a

. + * This little hack together with table.tutorial_code td.note * aims at fixing this issue. */ table.tutorial_code td.note p.starttd { margin: 0px; @@ -199,13 +214,3 @@ h3.version { td.width20em p.endtd { width: 20em; } - -.bigwarning { - font-size:2em; - font-weight:bold; - margin:1em; - padding:1em; - color:red; - border:solid; -} - diff --git a/ground/gcs/src/libs/eigen/doc/examples/CMakeLists.txt b/ground/gcs/src/libs/eigen/doc/examples/CMakeLists.txt index 08cf8efd7c..f7a19055fc 100644 --- a/ground/gcs/src/libs/eigen/doc/examples/CMakeLists.txt +++ b/ground/gcs/src/libs/eigen/doc/examples/CMakeLists.txt @@ -14,3 +14,8 @@ foreach(example_src ${examples_SRCS}) ) add_dependencies(all_examples ${example}) endforeach(example_src) + +check_cxx_compiler_flag("-std=c++11" EIGEN_COMPILER_SUPPORT_CPP11) +if(EIGEN_COMPILER_SUPPORT_CPP11) +ei_add_target_property(nullary_indexing COMPILE_FLAGS "-std=c++11") +endif() \ No newline at end of file diff --git a/ground/gcs/src/libs/eigen/doc/examples/CustomizingEigen_Inheritance.cpp b/ground/gcs/src/libs/eigen/doc/examples/CustomizingEigen_Inheritance.cpp new file mode 100644 index 0000000000..48df64ee36 --- /dev/null +++ b/ground/gcs/src/libs/eigen/doc/examples/CustomizingEigen_Inheritance.cpp @@ -0,0 +1,30 @@ +#include +#include + +class MyVectorType : public Eigen::VectorXd +{ +public: + MyVectorType(void):Eigen::VectorXd() {} + + // This constructor allows you to construct MyVectorType from Eigen expressions + template + MyVectorType(const Eigen::MatrixBase& other) + : Eigen::VectorXd(other) + { } + + // This method allows you to assign Eigen expressions to MyVectorType + template + MyVectorType& operator=(const Eigen::MatrixBase & other) + { + this->Eigen::VectorXd::operator=(other); + return *this; + } +}; + +int main() +{ + MyVectorType v = MyVectorType::Ones(4); + v(2) += 10; + v = 2 * v; + std::cout << v.transpose() << std::endl; +} diff --git a/ground/gcs/src/libs/eigen/doc/examples/Cwise_erf.cpp b/ground/gcs/src/libs/eigen/doc/examples/Cwise_erf.cpp new file mode 100644 index 0000000000..e7cd2c1c0f --- /dev/null +++ b/ground/gcs/src/libs/eigen/doc/examples/Cwise_erf.cpp @@ -0,0 +1,9 @@ +#include +#include +#include +using namespace Eigen; +int main() +{ + Array4d v(-0.5,2,0,-7); + std::cout << v.erf() << std::endl; +} diff --git a/ground/gcs/src/libs/eigen/doc/examples/Cwise_erfc.cpp b/ground/gcs/src/libs/eigen/doc/examples/Cwise_erfc.cpp new file mode 100644 index 0000000000..d8bb04c307 --- /dev/null +++ b/ground/gcs/src/libs/eigen/doc/examples/Cwise_erfc.cpp @@ -0,0 +1,9 @@ +#include +#include +#include +using namespace Eigen; +int main() +{ + Array4d v(-0.5,2,0,-7); + std::cout << v.erfc() << std::endl; +} diff --git a/ground/gcs/src/libs/eigen/doc/examples/Cwise_lgamma.cpp b/ground/gcs/src/libs/eigen/doc/examples/Cwise_lgamma.cpp new file mode 100644 index 0000000000..f1c4f503e1 --- /dev/null +++ b/ground/gcs/src/libs/eigen/doc/examples/Cwise_lgamma.cpp @@ -0,0 +1,9 @@ +#include +#include +#include +using namespace Eigen; +int main() +{ + Array4d v(0.5,10,0,-1); + std::cout << v.lgamma() << std::endl; +} \ No newline at end of file diff --git a/ground/gcs/src/libs/eigen/doc/examples/MatrixBase_cwise_const.cpp b/ground/gcs/src/libs/eigen/doc/examples/MatrixBase_cwise_const.cpp deleted file mode 100644 index 23700e0b6c..0000000000 --- a/ground/gcs/src/libs/eigen/doc/examples/MatrixBase_cwise_const.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#define EIGEN2_SUPPORT -#include -#include - -using namespace Eigen; -using namespace std; - -int main() -{ - Matrix3i m = Matrix3i::Random(); - cout << "Here is the matrix m:" << endl << m << endl; - Matrix3i n = Matrix3i::Random(); - cout << "And here is the matrix n:" << endl << n << endl; - cout << "The coefficient-wise product of m and n is:" << endl; - cout << m.cwise() * n << endl; - cout << "Taking the cube of the coefficients of m yields:" << endl; - cout << m.cwise().pow(3) << endl; -} diff --git a/ground/gcs/src/libs/eigen/doc/examples/TutorialInplaceLU.cpp b/ground/gcs/src/libs/eigen/doc/examples/TutorialInplaceLU.cpp new file mode 100644 index 0000000000..cb9c59b607 --- /dev/null +++ b/ground/gcs/src/libs/eigen/doc/examples/TutorialInplaceLU.cpp @@ -0,0 +1,61 @@ +#include +struct init { + init() { std::cout << "[" << "init" << "]" << std::endl; } +}; +init init_obj; +// [init] +#include +#include + +using namespace std; +using namespace Eigen; + +int main() +{ + MatrixXd A(2,2); + A << 2, -1, 1, 3; + cout << "Here is the input matrix A before decomposition:\n" << A << endl; +cout << "[init]" << endl; + +cout << "[declaration]" << endl; + PartialPivLU > lu(A); + cout << "Here is the input matrix A after decomposition:\n" << A << endl; +cout << "[declaration]" << endl; + +cout << "[matrixLU]" << endl; + cout << "Here is the matrix storing the L and U factors:\n" << lu.matrixLU() << endl; +cout << "[matrixLU]" << endl; + +cout << "[solve]" << endl; + MatrixXd A0(2,2); A0 << 2, -1, 1, 3; + VectorXd b(2); b << 1, 2; + VectorXd x = lu.solve(b); + cout << "Residual: " << (A0 * x - b).norm() << endl; +cout << "[solve]" << endl; + +cout << "[modifyA]" << endl; + A << 3, 4, -2, 1; + x = lu.solve(b); + cout << "Residual: " << (A0 * x - b).norm() << endl; +cout << "[modifyA]" << endl; + +cout << "[recompute]" << endl; + A0 = A; // save A + lu.compute(A); + x = lu.solve(b); + cout << "Residual: " << (A0 * x - b).norm() << endl; +cout << "[recompute]" << endl; + +cout << "[recompute_bis0]" << endl; + MatrixXd A1(2,2); + A1 << 5,-2,3,4; + lu.compute(A1); + cout << "Here is the input matrix A1 after decomposition:\n" << A1 << endl; +cout << "[recompute_bis0]" << endl; + +cout << "[recompute_bis1]" << endl; + x = lu.solve(b); + cout << "Residual: " << (A1 * x - b).norm() << endl; +cout << "[recompute_bis1]" << endl; + +} diff --git a/ground/gcs/src/libs/eigen/doc/examples/TutorialLinAlgInverseDeterminant.cpp b/ground/gcs/src/libs/eigen/doc/examples/TutorialLinAlgInverseDeterminant.cpp index 43970ff053..14dde5b357 100644 --- a/ground/gcs/src/libs/eigen/doc/examples/TutorialLinAlgInverseDeterminant.cpp +++ b/ground/gcs/src/libs/eigen/doc/examples/TutorialLinAlgInverseDeterminant.cpp @@ -13,4 +13,4 @@ int main() cout << "Here is the matrix A:\n" << A << endl; cout << "The determinant of A is " << A.determinant() << endl; cout << "The inverse of A is:\n" << A.inverse() << endl; -} \ No newline at end of file +} diff --git a/ground/gcs/src/libs/eigen/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_reductions_operatornorm.cpp b/ground/gcs/src/libs/eigen/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_reductions_operatornorm.cpp new file mode 100644 index 0000000000..62e28fc316 --- /dev/null +++ b/ground/gcs/src/libs/eigen/doc/examples/Tutorial_ReductionsVisitorsBroadcasting_reductions_operatornorm.cpp @@ -0,0 +1,18 @@ +#include +#include + +using namespace Eigen; +using namespace std; + +int main() +{ + MatrixXf m(2,2); + m << 1,-2, + -3,4; + + cout << "1-norm(m) = " << m.cwiseAbs().colwise().sum().maxCoeff() + << " == " << m.colwise().lpNorm<1>().maxCoeff() << endl; + + cout << "infty-norm(m) = " << m.cwiseAbs().rowwise().sum().maxCoeff() + << " == " << m.rowwise().lpNorm<1>().maxCoeff() << endl; +} diff --git a/ground/gcs/src/libs/eigen/doc/examples/make_circulant.cpp b/ground/gcs/src/libs/eigen/doc/examples/make_circulant.cpp new file mode 100644 index 0000000000..92e6aaa2b2 --- /dev/null +++ b/ground/gcs/src/libs/eigen/doc/examples/make_circulant.cpp @@ -0,0 +1,11 @@ +/* +This program is presented in several fragments in the doc page. +Every fragment is in its own file; this file simply combines them. +*/ + +#include "make_circulant.cpp.preamble" +#include "make_circulant.cpp.traits" +#include "make_circulant.cpp.expression" +#include "make_circulant.cpp.evaluator" +#include "make_circulant.cpp.entry" +#include "make_circulant.cpp.main" diff --git a/ground/gcs/src/libs/eigen/doc/examples/make_circulant.cpp.entry b/ground/gcs/src/libs/eigen/doc/examples/make_circulant.cpp.entry new file mode 100644 index 0000000000..f9d2eb8a95 --- /dev/null +++ b/ground/gcs/src/libs/eigen/doc/examples/make_circulant.cpp.entry @@ -0,0 +1,5 @@ +template +Circulant makeCirculant(const Eigen::MatrixBase& arg) +{ + return Circulant(arg.derived()); +} diff --git a/ground/gcs/src/libs/eigen/doc/examples/make_circulant.cpp.evaluator b/ground/gcs/src/libs/eigen/doc/examples/make_circulant.cpp.evaluator new file mode 100644 index 0000000000..2ba79e7836 --- /dev/null +++ b/ground/gcs/src/libs/eigen/doc/examples/make_circulant.cpp.evaluator @@ -0,0 +1,32 @@ +namespace Eigen { + namespace internal { + template + struct evaluator > + : evaluator_base > + { + typedef Circulant XprType; + typedef typename nested_eval::type ArgTypeNested; + typedef typename remove_all::type ArgTypeNestedCleaned; + typedef typename XprType::CoeffReturnType CoeffReturnType; + + enum { + CoeffReadCost = evaluator::CoeffReadCost, + Flags = Eigen::ColMajor + }; + + evaluator(const XprType& xpr) + : m_argImpl(xpr.m_arg), m_rows(xpr.rows()) + { } + + CoeffReturnType coeff(Index row, Index col) const + { + Index index = row - col; + if (index < 0) index += m_rows; + return m_argImpl.coeff(index); + } + + evaluator m_argImpl; + const Index m_rows; + }; + } +} diff --git a/ground/gcs/src/libs/eigen/doc/examples/make_circulant.cpp.expression b/ground/gcs/src/libs/eigen/doc/examples/make_circulant.cpp.expression new file mode 100644 index 0000000000..380cd44504 --- /dev/null +++ b/ground/gcs/src/libs/eigen/doc/examples/make_circulant.cpp.expression @@ -0,0 +1,20 @@ +template +class Circulant : public Eigen::MatrixBase > +{ +public: + Circulant(const ArgType& arg) + : m_arg(arg) + { + EIGEN_STATIC_ASSERT(ArgType::ColsAtCompileTime == 1, + YOU_TRIED_CALLING_A_VECTOR_METHOD_ON_A_MATRIX); + } + + typedef typename Eigen::internal::ref_selector::type Nested; + + typedef Eigen::Index Index; + Index rows() const { return m_arg.rows(); } + Index cols() const { return m_arg.rows(); } + + typedef typename Eigen::internal::ref_selector::type ArgTypeNested; + ArgTypeNested m_arg; +}; diff --git a/ground/gcs/src/libs/eigen/doc/examples/make_circulant.cpp.main b/ground/gcs/src/libs/eigen/doc/examples/make_circulant.cpp.main new file mode 100644 index 0000000000..877f97f62a --- /dev/null +++ b/ground/gcs/src/libs/eigen/doc/examples/make_circulant.cpp.main @@ -0,0 +1,8 @@ +int main() +{ + Eigen::VectorXd vec(4); + vec << 1, 2, 4, 8; + Eigen::MatrixXd mat; + mat = makeCirculant(vec); + std::cout << mat << std::endl; +} diff --git a/ground/gcs/src/libs/eigen/doc/examples/make_circulant.cpp.preamble b/ground/gcs/src/libs/eigen/doc/examples/make_circulant.cpp.preamble new file mode 100644 index 0000000000..e575cce146 --- /dev/null +++ b/ground/gcs/src/libs/eigen/doc/examples/make_circulant.cpp.preamble @@ -0,0 +1,4 @@ +#include +#include + +template class Circulant; diff --git a/ground/gcs/src/libs/eigen/doc/examples/make_circulant.cpp.traits b/ground/gcs/src/libs/eigen/doc/examples/make_circulant.cpp.traits new file mode 100644 index 0000000000..4e04535d31 --- /dev/null +++ b/ground/gcs/src/libs/eigen/doc/examples/make_circulant.cpp.traits @@ -0,0 +1,19 @@ +namespace Eigen { + namespace internal { + template + struct traits > + { + typedef Eigen::Dense StorageKind; + typedef Eigen::MatrixXpr XprKind; + typedef typename ArgType::StorageIndex StorageIndex; + typedef typename ArgType::Scalar Scalar; + enum { + Flags = Eigen::ColMajor, + RowsAtCompileTime = ArgType::RowsAtCompileTime, + ColsAtCompileTime = ArgType::RowsAtCompileTime, + MaxRowsAtCompileTime = ArgType::MaxRowsAtCompileTime, + MaxColsAtCompileTime = ArgType::MaxRowsAtCompileTime + }; + }; + } +} diff --git a/ground/gcs/src/libs/eigen/doc/examples/make_circulant2.cpp b/ground/gcs/src/libs/eigen/doc/examples/make_circulant2.cpp new file mode 100644 index 0000000000..95d3dd31a1 --- /dev/null +++ b/ground/gcs/src/libs/eigen/doc/examples/make_circulant2.cpp @@ -0,0 +1,52 @@ +#include +#include + +using namespace Eigen; + +// [circulant_func] +template +class circulant_functor { + const ArgType &m_vec; +public: + circulant_functor(const ArgType& arg) : m_vec(arg) {} + + const typename ArgType::Scalar& operator() (Index row, Index col) const { + Index index = row - col; + if (index < 0) index += m_vec.size(); + return m_vec(index); + } +}; +// [circulant_func] + +// [square] +template +struct circulant_helper { + typedef Matrix MatrixType; +}; +// [square] + +// [makeCirculant] +template +CwiseNullaryOp, typename circulant_helper::MatrixType> +makeCirculant(const Eigen::MatrixBase& arg) +{ + typedef typename circulant_helper::MatrixType MatrixType; + return MatrixType::NullaryExpr(arg.size(), arg.size(), circulant_functor(arg.derived())); +} +// [makeCirculant] + +// [main] +int main() +{ + Eigen::VectorXd vec(4); + vec << 1, 2, 4, 8; + Eigen::MatrixXd mat; + mat = makeCirculant(vec); + std::cout << mat << std::endl; +} +// [main] diff --git a/ground/gcs/src/libs/eigen/doc/examples/matrixfree_cg.cpp b/ground/gcs/src/libs/eigen/doc/examples/matrixfree_cg.cpp index f0631c3a31..6a205aea3e 100644 --- a/ground/gcs/src/libs/eigen/doc/examples/matrixfree_cg.cpp +++ b/ground/gcs/src/libs/eigen/doc/examples/matrixfree_cg.cpp @@ -2,179 +2,127 @@ #include #include #include +#include class MatrixReplacement; -template class MatrixReplacement_ProductReturnType; +using Eigen::SparseMatrix; namespace Eigen { namespace internal { + // MatrixReplacement looks-like a SparseMatrix, so let's inherits its traits: template<> - struct traits : Eigen::internal::traits > + struct traits : public Eigen::internal::traits > {}; - - template - struct traits > { - // The equivalent plain objet type of the product. This type is used if the product needs to be evaluated into a temporary. - typedef Eigen::Matrix ReturnType; - }; } } -// Inheriting EigenBase should not be needed in the future. +// Example of a matrix-free wrapper from a user type to Eigen's compatible type +// For the sake of simplicity, this example simply wrap a Eigen::SparseMatrix. class MatrixReplacement : public Eigen::EigenBase { public: - // Expose some compile-time information to Eigen: + // Required typedefs, constants, and method: typedef double Scalar; typedef double RealScalar; + typedef int StorageIndex; enum { ColsAtCompileTime = Eigen::Dynamic, - RowsAtCompileTime = Eigen::Dynamic, MaxColsAtCompileTime = Eigen::Dynamic, - MaxRowsAtCompileTime = Eigen::Dynamic + IsRowMajor = false }; - Index rows() const { return 4; } - Index cols() const { return 4; } + Index rows() const { return mp_mat->rows(); } + Index cols() const { return mp_mat->cols(); } - void resize(Index a_rows, Index a_cols) - { - // This method should not be needed in the future. - assert(a_rows==0 && a_cols==0 || a_rows==rows() && a_cols==cols()); - } - - // In the future, the return type should be Eigen::Product template - MatrixReplacement_ProductReturnType operator*(const Eigen::MatrixBase& x) const { - return MatrixReplacement_ProductReturnType(*this, x.derived()); + Eigen::Product operator*(const Eigen::MatrixBase& x) const { + return Eigen::Product(*this, x.derived()); } -}; + // Custom API: + MatrixReplacement() : mp_mat(0) {} -// The proxy class representing the product of a MatrixReplacement with a MatrixBase<> -template -class MatrixReplacement_ProductReturnType : public Eigen::ReturnByValue > { -public: - typedef MatrixReplacement::Index Index; - - // The ctor store references to the matrix and right-hand-side object (usually a vector). - MatrixReplacement_ProductReturnType(const MatrixReplacement& matrix, const Rhs& rhs) - : m_matrix(matrix), m_rhs(rhs) - {} - - Index rows() const { return m_matrix.rows(); } - Index cols() const { return m_rhs.cols(); } - - // This function is automatically called by Eigen. It must evaluate the product of matrix * rhs into y. - template - void evalTo(Dest& y) const - { - y.setZero(4); - - y(0) += 2 * m_rhs(0); y(1) += 1 * m_rhs(0); - y(0) += 1 * m_rhs(1); y(1) += 2 * m_rhs(1); y(2) += 1 * m_rhs(1); - y(1) += 1 * m_rhs(2); y(2) += 2 * m_rhs(2); y(3) += 1 * m_rhs(2); - y(2) += 1 * m_rhs(3); y(3) += 2 * m_rhs(3); + void attachMyMatrix(const SparseMatrix &mat) { + mp_mat = &mat; } + const SparseMatrix my_matrix() const { return *mp_mat; } -protected: - const MatrixReplacement& m_matrix; - typename Rhs::Nested m_rhs; +private: + const SparseMatrix *mp_mat; }; -/*****/ - -// This class simply warp a diagonal matrix as a Jacobi preconditioner. -// In the future such simple and generic wrapper should be shipped within Eigen itsel. -template -class MyJacobiPreconditioner -{ - typedef _Scalar Scalar; - typedef Eigen::Matrix Vector; - typedef typename Vector::Index Index; - - public: - // this typedef is only to export the scalar type and compile-time dimensions to solve_retval - typedef Eigen::Matrix MatrixType; - - MyJacobiPreconditioner() : m_isInitialized(false) {} - - void setInvDiag(const Eigen::VectorXd &invdiag) { - m_invdiag=invdiag; - m_isInitialized=true; - } - - Index rows() const { return m_invdiag.size(); } - Index cols() const { return m_invdiag.size(); } - - template - MyJacobiPreconditioner& analyzePattern(const MatType& ) { return *this; } - - template - MyJacobiPreconditioner& factorize(const MatType& mat) { return *this; } - - template - MyJacobiPreconditioner& compute(const MatType& mat) { return *this; } - - template - void _solve(const Rhs& b, Dest& x) const - { - x = m_invdiag.array() * b.array() ; - } - - template inline const Eigen::internal::solve_retval - solve(const Eigen::MatrixBase& b) const - { - eigen_assert(m_isInitialized && "MyJacobiPreconditioner is not initialized."); - eigen_assert(m_invdiag.size()==b.rows() - && "MyJacobiPreconditioner::solve(): invalid number of rows of the right hand side matrix b"); - return Eigen::internal::solve_retval(*this, b.derived()); - } - - protected: - Vector m_invdiag; - bool m_isInitialized; -}; - +// Implementation of MatrixReplacement * Eigen::DenseVector though a specialization of internal::generic_product_impl: namespace Eigen { namespace internal { -template -struct solve_retval, Rhs> - : solve_retval_base, Rhs> -{ - typedef MyJacobiPreconditioner<_MatrixType> Dec; - EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs) - - template void evalTo(Dest& dst) const + template + struct generic_product_impl // GEMV stands for matrix-vector + : generic_product_impl_base > { - dec()._solve(rhs(),dst); - } -}; + typedef typename Product::Scalar Scalar; + + template + static void scaleAndAddTo(Dest& dst, const MatrixReplacement& lhs, const Rhs& rhs, const Scalar& alpha) + { + // This method should implement "dst += alpha * lhs * rhs" inplace, + // however, for iterative solvers, alpha is always equal to 1, so let's not bother about it. + assert(alpha==Scalar(1) && "scaling is not implemented"); + + // Here we could simply call dst.noalias() += lhs.my_matrix() * rhs, + // but let's do something fancier (and less efficient): + for(Index i=0; i S = Eigen::MatrixXd::Random(n,n).sparseView(0.5,1); + S = S.transpose()*S; + MatrixReplacement A; - Eigen::VectorXd b(4), x; - b << 1, 1, 1, 1; + A.attachMyMatrix(S); - // solve Ax = b using CG with matrix-free version: - Eigen::ConjugateGradient < MatrixReplacement, Eigen::Lower|Eigen::Upper, MyJacobiPreconditioner > cg; + Eigen::VectorXd b(n), x; + b.setRandom(); - Eigen::VectorXd invdiag(4); - invdiag << 1./3., 1./4., 1./4., 1./3.; + // Solve Ax = b using various iterative solver with matrix-free version: + { + Eigen::ConjugateGradient cg; + cg.compute(A); + x = cg.solve(b); + std::cout << "CG: #iterations: " << cg.iterations() << ", estimated error: " << cg.error() << std::endl; + } + + { + Eigen::BiCGSTAB bicg; + bicg.compute(A); + x = bicg.solve(b); + std::cout << "BiCGSTAB: #iterations: " << bicg.iterations() << ", estimated error: " << bicg.error() << std::endl; + } + + { + Eigen::GMRES gmres; + gmres.compute(A); + x = gmres.solve(b); + std::cout << "GMRES: #iterations: " << gmres.iterations() << ", estimated error: " << gmres.error() << std::endl; + } - cg.preconditioner().setInvDiag(invdiag); - cg.compute(A); - x = cg.solve(b); + { + Eigen::DGMRES gmres; + gmres.compute(A); + x = gmres.solve(b); + std::cout << "DGMRES: #iterations: " << gmres.iterations() << ", estimated error: " << gmres.error() << std::endl; + } - std::cout << "#iterations: " << cg.iterations() << std::endl; - std::cout << "estimated error: " << cg.error() << std::endl; + { + Eigen::MINRES minres; + minres.compute(A); + x = minres.solve(b); + std::cout << "MINRES: #iterations: " << minres.iterations() << ", estimated error: " << minres.error() << std::endl; + } } diff --git a/ground/gcs/src/libs/eigen/doc/examples/nullary_indexing.cpp b/ground/gcs/src/libs/eigen/doc/examples/nullary_indexing.cpp new file mode 100644 index 0000000000..e27c3585ab --- /dev/null +++ b/ground/gcs/src/libs/eigen/doc/examples/nullary_indexing.cpp @@ -0,0 +1,66 @@ +#include +#include + +using namespace Eigen; + +// [functor] +template +class indexing_functor { + const ArgType &m_arg; + const RowIndexType &m_rowIndices; + const ColIndexType &m_colIndices; +public: + typedef Matrix MatrixType; + + indexing_functor(const ArgType& arg, const RowIndexType& row_indices, const ColIndexType& col_indices) + : m_arg(arg), m_rowIndices(row_indices), m_colIndices(col_indices) + {} + + const typename ArgType::Scalar& operator() (Index row, Index col) const { + return m_arg(m_rowIndices[row], m_colIndices[col]); + } +}; +// [functor] + +// [function] +template +CwiseNullaryOp, typename indexing_functor::MatrixType> +indexing(const Eigen::MatrixBase& arg, const RowIndexType& row_indices, const ColIndexType& col_indices) +{ + typedef indexing_functor Func; + typedef typename Func::MatrixType MatrixType; + return MatrixType::NullaryExpr(row_indices.size(), col_indices.size(), Func(arg.derived(), row_indices, col_indices)); +} +// [function] + + +int main() +{ + std::cout << "[main1]\n"; + Eigen::MatrixXi A = Eigen::MatrixXi::Random(4,4); + Array3i ri(1,2,1); + ArrayXi ci(6); ci << 3,2,1,0,0,2; + Eigen::MatrixXi B = indexing(A, ri, ci); + std::cout << "A =" << std::endl; + std::cout << A << std::endl << std::endl; + std::cout << "A([" << ri.transpose() << "], [" << ci.transpose() << "]) =" << std::endl; + std::cout << B << std::endl; + std::cout << "[main1]\n"; + + std::cout << "[main2]\n"; + B = indexing(A, ri+1, ci); + std::cout << "A(ri+1,ci) =" << std::endl; + std::cout << B << std::endl << std::endl; +#if __cplusplus >= 201103L + B = indexing(A, ArrayXi::LinSpaced(13,0,12).unaryExpr([](int x){return x%4;}), ArrayXi::LinSpaced(4,0,3)); + std::cout << "A(ArrayXi::LinSpaced(13,0,12).unaryExpr([](int x){return x%4;}), ArrayXi::LinSpaced(4,0,3)) =" << std::endl; + std::cout << B << std::endl << std::endl; +#endif + std::cout << "[main2]\n"; +} + diff --git a/ground/gcs/src/libs/eigen/doc/ftv2node.png b/ground/gcs/src/libs/eigen/doc/ftv2node.png new file mode 100644 index 0000000000000000000000000000000000000000..63c605bb4c3d941c921a4b6cfa74951e946bcb48 GIT binary patch literal 86 zcmeAS@N?(olHy`uVBq!ia0vp^0zfRr!3HExu9B$%QnH>djv*C{Z|`mdau^P8_z}#X h?B8GEpdi4(BFDx$je&7RrDQEg&ePS;Wt~$(69Dh@6T1Ka literal 0 HcmV?d00001 diff --git a/ground/gcs/src/libs/eigen/doc/ftv2pnode.png b/ground/gcs/src/libs/eigen/doc/ftv2pnode.png new file mode 100644 index 0000000000000000000000000000000000000000..c6ee22f937a07d1dbfc27c669d11f8ed13e2f152 GIT binary patch literal 229 zcmV^P)R?RzRoKvklcaQ%HF6%rK2&ZgO(-ihJ_C zzrKgp4jgO( fd_(yg|3PpEQb#9`a?Pz_00000NkvXXu0mjftR`5K literal 0 HcmV?d00001 diff --git a/ground/gcs/src/libs/eigen/doc/snippets/BiCGSTAB_simple.cpp b/ground/gcs/src/libs/eigen/doc/snippets/BiCGSTAB_simple.cpp new file mode 100644 index 0000000000..5520f4f1f0 --- /dev/null +++ b/ground/gcs/src/libs/eigen/doc/snippets/BiCGSTAB_simple.cpp @@ -0,0 +1,11 @@ + int n = 10000; + VectorXd x(n), b(n); + SparseMatrix A(n,n); + /* ... fill A and b ... */ + BiCGSTAB > solver; + solver.compute(A); + x = solver.solve(b); + std::cout << "#iterations: " << solver.iterations() << std::endl; + std::cout << "estimated error: " << solver.error() << std::endl; + /* ... update b ... */ + x = solver.solve(b); // solve again \ No newline at end of file diff --git a/ground/gcs/src/libs/eigen/doc/snippets/BiCGSTAB_step_by_step.cpp b/ground/gcs/src/libs/eigen/doc/snippets/BiCGSTAB_step_by_step.cpp new file mode 100644 index 0000000000..06147bb81e --- /dev/null +++ b/ground/gcs/src/libs/eigen/doc/snippets/BiCGSTAB_step_by_step.cpp @@ -0,0 +1,14 @@ + int n = 10000; + VectorXd x(n), b(n); + SparseMatrix A(n,n); + /* ... fill A and b ... */ + BiCGSTAB > solver(A); + // start from a random solution + x = VectorXd::Random(n); + solver.setMaxIterations(1); + int i = 0; + do { + x = solver.solveWithGuess(b,x); + std::cout << i << " : " << solver.error() << std::endl; + ++i; + } while (solver.info()!=Success && i<100); \ No newline at end of file diff --git a/ground/gcs/src/libs/eigen/doc/snippets/CMakeLists.txt b/ground/gcs/src/libs/eigen/doc/snippets/CMakeLists.txt index 1135900cf4..1baf32fbac 100644 --- a/ground/gcs/src/libs/eigen/doc/snippets/CMakeLists.txt +++ b/ground/gcs/src/libs/eigen/doc/snippets/CMakeLists.txt @@ -24,5 +24,3 @@ foreach(snippet_src ${snippets_SRCS}) set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/${compile_snippet_src} PROPERTIES OBJECT_DEPENDS ${snippet_src}) endforeach(snippet_src) - -ei_add_target_property(compile_tut_arithmetic_transpose_aliasing COMPILE_FLAGS -DEIGEN_NO_DEBUG) diff --git a/ground/gcs/src/libs/eigen/doc/snippets/Cwise_arg.cpp b/ground/gcs/src/libs/eigen/doc/snippets/Cwise_arg.cpp new file mode 100644 index 0000000000..3f45133b62 --- /dev/null +++ b/ground/gcs/src/libs/eigen/doc/snippets/Cwise_arg.cpp @@ -0,0 +1,3 @@ +ArrayXcf v = ArrayXcf::Random(3); +cout << v << endl << endl; +cout << arg(v) << endl; diff --git a/ground/gcs/src/libs/eigen/doc/snippets/Cwise_array_power_array.cpp b/ground/gcs/src/libs/eigen/doc/snippets/Cwise_array_power_array.cpp new file mode 100644 index 0000000000..432a76ee59 --- /dev/null +++ b/ground/gcs/src/libs/eigen/doc/snippets/Cwise_array_power_array.cpp @@ -0,0 +1,4 @@ +Array x(8,25,3), + e(1./3.,0.5,2.); +cout << "[" << x << "]^[" << e << "] = " << x.pow(e) << endl; // using ArrayBase::pow +cout << "[" << x << "]^[" << e << "] = " << pow(x,e) << endl; // using Eigen::pow diff --git a/ground/gcs/src/libs/eigen/doc/snippets/Cwise_atan.cpp b/ground/gcs/src/libs/eigen/doc/snippets/Cwise_atan.cpp new file mode 100644 index 0000000000..4468447266 --- /dev/null +++ b/ground/gcs/src/libs/eigen/doc/snippets/Cwise_atan.cpp @@ -0,0 +1,2 @@ +ArrayXd v = ArrayXd::LinSpaced(5,0,1); +cout << v.atan() << endl; diff --git a/ground/gcs/src/libs/eigen/doc/snippets/Cwise_boolean_not.cpp b/ground/gcs/src/libs/eigen/doc/snippets/Cwise_boolean_not.cpp new file mode 100644 index 0000000000..40009f15ae --- /dev/null +++ b/ground/gcs/src/libs/eigen/doc/snippets/Cwise_boolean_not.cpp @@ -0,0 +1,5 @@ +Array3d v(1,2,3); +v(1) *= 0.0/0.0; +v(2) /= 0.0; +cout << v << endl << endl; +cout << !isfinite(v) << endl; diff --git a/ground/gcs/src/libs/eigen/doc/snippets/Cwise_boolean_xor.cpp b/ground/gcs/src/libs/eigen/doc/snippets/Cwise_boolean_xor.cpp new file mode 100644 index 0000000000..fafbec8064 --- /dev/null +++ b/ground/gcs/src/libs/eigen/doc/snippets/Cwise_boolean_xor.cpp @@ -0,0 +1,2 @@ +Array3d v(-1,2,1), w(-3,2,3); +cout << ((v e(2,-3,1./3.); +cout << "10^[" << e << "] = " << pow(10,e) << endl; diff --git a/ground/gcs/src/libs/eigen/doc/snippets/Cwise_sign.cpp b/ground/gcs/src/libs/eigen/doc/snippets/Cwise_sign.cpp new file mode 100644 index 0000000000..49920e4f12 --- /dev/null +++ b/ground/gcs/src/libs/eigen/doc/snippets/Cwise_sign.cpp @@ -0,0 +1,2 @@ +Array3d v(-3,5,0); +cout << v.sign() << endl; diff --git a/ground/gcs/src/libs/eigen/doc/snippets/Cwise_sinh.cpp b/ground/gcs/src/libs/eigen/doc/snippets/Cwise_sinh.cpp new file mode 100644 index 0000000000..fac9b19a85 --- /dev/null +++ b/ground/gcs/src/libs/eigen/doc/snippets/Cwise_sinh.cpp @@ -0,0 +1,2 @@ +ArrayXd v = ArrayXd::LinSpaced(5,0,1); +cout << sinh(v) << endl; diff --git a/ground/gcs/src/libs/eigen/doc/snippets/Cwise_tanh.cpp b/ground/gcs/src/libs/eigen/doc/snippets/Cwise_tanh.cpp new file mode 100644 index 0000000000..30cd0450d9 --- /dev/null +++ b/ground/gcs/src/libs/eigen/doc/snippets/Cwise_tanh.cpp @@ -0,0 +1,2 @@ +ArrayXd v = ArrayXd::LinSpaced(5,0,1); +cout << tanh(v) << endl; diff --git a/ground/gcs/src/libs/eigen/doc/snippets/DenseBase_LinSpacedInt.cpp b/ground/gcs/src/libs/eigen/doc/snippets/DenseBase_LinSpacedInt.cpp new file mode 100644 index 0000000000..0d7ae068e4 --- /dev/null +++ b/ground/gcs/src/libs/eigen/doc/snippets/DenseBase_LinSpacedInt.cpp @@ -0,0 +1,8 @@ +cout << "Even spacing inputs:" << endl; +cout << VectorXi::LinSpaced(8,1,4).transpose() << endl; +cout << VectorXi::LinSpaced(8,1,8).transpose() << endl; +cout << VectorXi::LinSpaced(8,1,15).transpose() << endl; +cout << "Uneven spacing inputs:" << endl; +cout << VectorXi::LinSpaced(8,1,7).transpose() << endl; +cout << VectorXi::LinSpaced(8,1,9).transpose() << endl; +cout << VectorXi::LinSpaced(8,1,16).transpose() << endl; diff --git a/ground/gcs/src/libs/eigen/doc/snippets/DirectionWise_hnormalized.cpp b/ground/gcs/src/libs/eigen/doc/snippets/DirectionWise_hnormalized.cpp new file mode 100644 index 0000000000..3410790a87 --- /dev/null +++ b/ground/gcs/src/libs/eigen/doc/snippets/DirectionWise_hnormalized.cpp @@ -0,0 +1,7 @@ +typedef Matrix Matrix4Xd; +Matrix4Xd M = Matrix4Xd::Random(4,5); +Projective3d P(Matrix4d::Random()); +cout << "The matrix M is:" << endl << M << endl << endl; +cout << "M.colwise().hnormalized():" << endl << M.colwise().hnormalized() << endl << endl; +cout << "P*M:" << endl << P*M << endl << endl; +cout << "(P*M).colwise().hnormalized():" << endl << (P*M).colwise().hnormalized() << endl << endl; \ No newline at end of file diff --git a/ground/gcs/src/libs/eigen/doc/snippets/EigenSolver_eigenvectors.cpp b/ground/gcs/src/libs/eigen/doc/snippets/EigenSolver_eigenvectors.cpp index 0fad4dadb4..8355f76c94 100644 --- a/ground/gcs/src/libs/eigen/doc/snippets/EigenSolver_eigenvectors.cpp +++ b/ground/gcs/src/libs/eigen/doc/snippets/EigenSolver_eigenvectors.cpp @@ -1,4 +1,4 @@ MatrixXd ones = MatrixXd::Ones(3,3); EigenSolver es(ones); -cout << "The first eigenvector of the 3x3 matrix of ones is:" - << endl << es.eigenvectors().col(1) << endl; +cout << "The first eigenvector of the 3x3 matrix of ones is:" + << endl << es.eigenvectors().col(0) << endl; diff --git a/ground/gcs/src/libs/eigen/doc/snippets/LeastSquaresNormalEquations.cpp b/ground/gcs/src/libs/eigen/doc/snippets/LeastSquaresNormalEquations.cpp new file mode 100644 index 0000000000..997cf1715b --- /dev/null +++ b/ground/gcs/src/libs/eigen/doc/snippets/LeastSquaresNormalEquations.cpp @@ -0,0 +1,4 @@ +MatrixXf A = MatrixXf::Random(3, 2); +VectorXf b = VectorXf::Random(3); +cout << "The solution using normal equations is:\n" + << (A.transpose() * A).ldlt().solve(A.transpose() * b) << endl; diff --git a/ground/gcs/src/libs/eigen/doc/snippets/LeastSquaresQR.cpp b/ground/gcs/src/libs/eigen/doc/snippets/LeastSquaresQR.cpp new file mode 100644 index 0000000000..6c97045479 --- /dev/null +++ b/ground/gcs/src/libs/eigen/doc/snippets/LeastSquaresQR.cpp @@ -0,0 +1,4 @@ +MatrixXf A = MatrixXf::Random(3, 2); +VectorXf b = VectorXf::Random(3); +cout << "The solution using the QR decomposition is:\n" + << A.colPivHouseholderQr().solve(b) << endl; diff --git a/ground/gcs/src/libs/eigen/doc/snippets/MatrixBase_cwiseSign.cpp b/ground/gcs/src/libs/eigen/doc/snippets/MatrixBase_cwiseSign.cpp new file mode 100644 index 0000000000..efd717955f --- /dev/null +++ b/ground/gcs/src/libs/eigen/doc/snippets/MatrixBase_cwiseSign.cpp @@ -0,0 +1,4 @@ +MatrixXd m(2,3); +m << 2, -4, 6, + -5, 1, 0; +cout << m.cwiseSign() << endl; diff --git a/ground/gcs/src/libs/eigen/doc/snippets/MatrixBase_hnormalized.cpp b/ground/gcs/src/libs/eigen/doc/snippets/MatrixBase_hnormalized.cpp new file mode 100644 index 0000000000..652cd77c09 --- /dev/null +++ b/ground/gcs/src/libs/eigen/doc/snippets/MatrixBase_hnormalized.cpp @@ -0,0 +1,6 @@ +Vector4d v = Vector4d::Random(); +Projective3d P(Matrix4d::Random()); +cout << "v = " << v.transpose() << "]^T" << endl; +cout << "v.hnormalized() = " << v.hnormalized().transpose() << "]^T" << endl; +cout << "P*v = " << (P*v).transpose() << "]^T" << endl; +cout << "(P*v).hnormalized() = " << (P*v).hnormalized().transpose() << "]^T" << endl; \ No newline at end of file diff --git a/ground/gcs/src/libs/eigen/doc/snippets/MatrixBase_homogeneous.cpp b/ground/gcs/src/libs/eigen/doc/snippets/MatrixBase_homogeneous.cpp new file mode 100644 index 0000000000..457c28f91a --- /dev/null +++ b/ground/gcs/src/libs/eigen/doc/snippets/MatrixBase_homogeneous.cpp @@ -0,0 +1,6 @@ +Vector3d v = Vector3d::Random(), w; +Projective3d P(Matrix4d::Random()); +cout << "v = [" << v.transpose() << "]^T" << endl; +cout << "h.homogeneous() = [" << v.homogeneous().transpose() << "]^T" << endl; +cout << "(P * v.homogeneous()) = [" << (P * v.homogeneous()).transpose() << "]^T" << endl; +cout << "(P * v.homogeneous()).hnormalized() = [" << (P * v.homogeneous()).eval().hnormalized().transpose() << "]^T" << endl; \ No newline at end of file diff --git a/ground/gcs/src/libs/eigen/doc/snippets/MatrixBase_marked.cpp b/ground/gcs/src/libs/eigen/doc/snippets/MatrixBase_marked.cpp deleted file mode 100644 index f60712178a..0000000000 --- a/ground/gcs/src/libs/eigen/doc/snippets/MatrixBase_marked.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef _MSC_VER - #warning deprecated -#endif -/* -Matrix3d m = Matrix3d::Zero(); -m.part().setOnes(); -cout << "Here is the matrix m:" << endl << m << endl; -Matrix3d n = Matrix3d::Ones(); -n.part() *= 2; -cout << "Here is the matrix n:" << endl << n << endl; -cout << "And now here is m.inverse()*n, taking advantage of the fact that" - " m is upper-triangular:" << endl - << m.marked().solveTriangular(n); -*/ \ No newline at end of file diff --git a/ground/gcs/src/libs/eigen/doc/snippets/MatrixBase_part.cpp b/ground/gcs/src/libs/eigen/doc/snippets/MatrixBase_part.cpp deleted file mode 100644 index d3e7f482e7..0000000000 --- a/ground/gcs/src/libs/eigen/doc/snippets/MatrixBase_part.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef _MSC_VER - #warning deprecated -#endif -/* -Matrix3d m = Matrix3d::Zero(); -m.part().setOnes(); -cout << "Here is the matrix m:" << endl << m << endl; -cout << "And let us now compute m*m.adjoint() in a very optimized way" << endl - << "taking advantage of the symmetry." << endl; -Matrix3d n; -n.part() = (m*m.adjoint()).lazy(); -cout << "The result is:" << endl << n << endl; -*/ \ No newline at end of file diff --git a/ground/gcs/src/libs/eigen/doc/snippets/MatrixBase_selfadjointView.cpp b/ground/gcs/src/libs/eigen/doc/snippets/MatrixBase_selfadjointView.cpp new file mode 100644 index 0000000000..4bd3c7eeb2 --- /dev/null +++ b/ground/gcs/src/libs/eigen/doc/snippets/MatrixBase_selfadjointView.cpp @@ -0,0 +1,6 @@ +Matrix3i m = Matrix3i::Random(); +cout << "Here is the matrix m:" << endl << m << endl; +cout << "Here is the symmetric matrix extracted from the upper part of m:" << endl + << Matrix3i(m.selfadjointView()) << endl; +cout << "Here is the symmetric matrix extracted from the lower part of m:" << endl + << Matrix3i(m.selfadjointView()) << endl; diff --git a/ground/gcs/src/libs/eigen/doc/snippets/MatrixBase_extract.cpp b/ground/gcs/src/libs/eigen/doc/snippets/MatrixBase_triangularView.cpp similarity index 55% rename from ground/gcs/src/libs/eigen/doc/snippets/MatrixBase_extract.cpp rename to ground/gcs/src/libs/eigen/doc/snippets/MatrixBase_triangularView.cpp index c96220f72c..03aa303f0d 100644 --- a/ground/gcs/src/libs/eigen/doc/snippets/MatrixBase_extract.cpp +++ b/ground/gcs/src/libs/eigen/doc/snippets/MatrixBase_triangularView.cpp @@ -1,13 +1,9 @@ -#ifndef _MSC_VER - #warning deprecated -#endif -/* deprecated Matrix3i m = Matrix3i::Random(); cout << "Here is the matrix m:" << endl << m << endl; cout << "Here is the upper-triangular matrix extracted from m:" << endl - << m.part() << endl; + << Matrix3i(m.triangularView()) << endl; cout << "Here is the strictly-upper-triangular matrix extracted from m:" << endl - << m.part() << endl; + << Matrix3i(m.triangularView()) << endl; cout << "Here is the unit-lower-triangular matrix extracted from m:" << endl - << m.part() << endl; -*/ \ No newline at end of file + << Matrix3i(m.triangularView()) << endl; +// FIXME need to implement output for triangularViews (Bug 885) diff --git a/ground/gcs/src/libs/eigen/doc/snippets/PartialRedux_count.cpp b/ground/gcs/src/libs/eigen/doc/snippets/PartialRedux_count.cpp index c7b3097e4d..1c3b3a28f9 100644 --- a/ground/gcs/src/libs/eigen/doc/snippets/PartialRedux_count.cpp +++ b/ground/gcs/src/libs/eigen/doc/snippets/PartialRedux_count.cpp @@ -1,3 +1,5 @@ Matrix3d m = Matrix3d::Random(); cout << "Here is the matrix m:" << endl << m << endl; -cout << "Here is the count of elements larger or equal than 0.5 of each row:" << endl << (m.array() >= 0.5).rowwise().count() << endl; +Matrix res = (m.array() >= 0.5).rowwise().count(); +cout << "Here is the count of elements larger or equal than 0.5 of each row:" << endl; +cout << res << endl; diff --git a/ground/gcs/src/libs/eigen/doc/snippets/SparseMatrix_coeffs.cpp b/ground/gcs/src/libs/eigen/doc/snippets/SparseMatrix_coeffs.cpp new file mode 100644 index 0000000000..f71a69b078 --- /dev/null +++ b/ground/gcs/src/libs/eigen/doc/snippets/SparseMatrix_coeffs.cpp @@ -0,0 +1,9 @@ +SparseMatrix A(3,3); +A.insert(1,2) = 0; +A.insert(0,1) = 1; +A.insert(2,0) = 2; +A.makeCompressed(); +cout << "The matrix A is:" << endl << MatrixXd(A) << endl; +cout << "it has " << A.nonZeros() << " stored non zero coefficients that are: " << A.coeffs().transpose() << endl; +A.coeffs() += 10; +cout << "After adding 10 to every stored non zero coefficient, the matrix A is:" << endl << MatrixXd(A) << endl; diff --git a/ground/gcs/src/libs/eigen/doc/snippets/TopicAliasing_mult4.cpp b/ground/gcs/src/libs/eigen/doc/snippets/TopicAliasing_mult4.cpp new file mode 100644 index 0000000000..8a8992f6ca --- /dev/null +++ b/ground/gcs/src/libs/eigen/doc/snippets/TopicAliasing_mult4.cpp @@ -0,0 +1,5 @@ +MatrixXf A(2,2), B(3,2); +B << 2, 0, 0, 3, 1, 1; +A << 2, 0, 0, -2; +A = (B * A).cwiseAbs(); +cout << A; \ No newline at end of file diff --git a/ground/gcs/src/libs/eigen/doc/snippets/TopicAliasing_mult5.cpp b/ground/gcs/src/libs/eigen/doc/snippets/TopicAliasing_mult5.cpp new file mode 100644 index 0000000000..1a36defde3 --- /dev/null +++ b/ground/gcs/src/libs/eigen/doc/snippets/TopicAliasing_mult5.cpp @@ -0,0 +1,5 @@ +MatrixXf A(2,2), B(3,2); +B << 2, 0, 0, 3, 1, 1; +A << 2, 0, 0, -2; +A = (B * A).eval().cwiseAbs(); +cout << A; diff --git a/ground/gcs/src/libs/eigen/doc/snippets/Triangular_solve.cpp b/ground/gcs/src/libs/eigen/doc/snippets/Triangular_solve.cpp new file mode 100644 index 0000000000..5484424673 --- /dev/null +++ b/ground/gcs/src/libs/eigen/doc/snippets/Triangular_solve.cpp @@ -0,0 +1,11 @@ +Matrix3d m = Matrix3d::Zero(); +m.triangularView().setOnes(); +cout << "Here is the matrix m:\n" << m << endl; +Matrix3d n = Matrix3d::Ones(); +n.triangularView() *= 2; +cout << "Here is the matrix n:\n" << n << endl; +cout << "And now here is m.inverse()*n, taking advantage of the fact that" + " m is upper-triangular:\n" + << m.triangularView().solve(n) << endl; +cout << "And this is n*m.inverse():\n" + << m.triangularView().solve(n); diff --git a/ground/gcs/src/libs/eigen/doc/snippets/Tutorial_AdvancedInitialization_Join.cpp b/ground/gcs/src/libs/eigen/doc/snippets/Tutorial_AdvancedInitialization_Join.cpp index 84e8715cbe..55a21539d6 100644 --- a/ground/gcs/src/libs/eigen/doc/snippets/Tutorial_AdvancedInitialization_Join.cpp +++ b/ground/gcs/src/libs/eigen/doc/snippets/Tutorial_AdvancedInitialization_Join.cpp @@ -3,7 +3,7 @@ vec1 << 1, 2, 3; std::cout << "vec1 = " << vec1 << std::endl; RowVectorXd vec2(4); -vec2 << 1, 4, 9, 16;; +vec2 << 1, 4, 9, 16; std::cout << "vec2 = " << vec2 << std::endl; RowVectorXd joined(7); diff --git a/ground/gcs/src/libs/eigen/doc/snippets/Tutorial_ReshapeMat2Mat.cpp b/ground/gcs/src/libs/eigen/doc/snippets/Tutorial_ReshapeMat2Mat.cpp new file mode 100644 index 0000000000..f84d6e76d0 --- /dev/null +++ b/ground/gcs/src/libs/eigen/doc/snippets/Tutorial_ReshapeMat2Mat.cpp @@ -0,0 +1,6 @@ +MatrixXf M1(2,6); // Column-major storage +M1 << 1, 2, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12; + +Map M2(M1.data(), 6,2); +cout << "M2:" << endl << M2 << endl; \ No newline at end of file diff --git a/ground/gcs/src/libs/eigen/doc/snippets/Tutorial_ReshapeMat2Vec.cpp b/ground/gcs/src/libs/eigen/doc/snippets/Tutorial_ReshapeMat2Vec.cpp new file mode 100644 index 0000000000..95bd4e0e6b --- /dev/null +++ b/ground/gcs/src/libs/eigen/doc/snippets/Tutorial_ReshapeMat2Vec.cpp @@ -0,0 +1,11 @@ +MatrixXf M1(3,3); // Column-major storage +M1 << 1, 2, 3, + 4, 5, 6, + 7, 8, 9; + +Map v1(M1.data(), M1.size()); +cout << "v1:" << endl << v1 << endl; + +Matrix M2(M1); +Map v2(M2.data(), M2.size()); +cout << "v2:" << endl << v2 << endl; \ No newline at end of file diff --git a/ground/gcs/src/libs/eigen/doc/snippets/Tutorial_SlicingCol.cpp b/ground/gcs/src/libs/eigen/doc/snippets/Tutorial_SlicingCol.cpp new file mode 100644 index 0000000000..f667ff6894 --- /dev/null +++ b/ground/gcs/src/libs/eigen/doc/snippets/Tutorial_SlicingCol.cpp @@ -0,0 +1,11 @@ +MatrixXf M1 = MatrixXf::Random(3,8); +cout << "Column major input:" << endl << M1 << "\n"; +Map > M2(M1.data(), M1.rows(), (M1.cols()+2)/3, OuterStride<>(M1.outerStride()*3)); +cout << "1 column over 3:" << endl << M2 << "\n"; + +typedef Matrix RowMajorMatrixXf; +RowMajorMatrixXf M3(M1); +cout << "Row major input:" << endl << M3 << "\n"; +Map > M4(M3.data(), M3.rows(), (M3.cols()+2)/3, + Stride(M3.outerStride(),3)); +cout << "1 column over 3:" << endl << M4 << "\n"; \ No newline at end of file diff --git a/ground/gcs/src/libs/eigen/doc/snippets/Tutorial_SlicingVec.cpp b/ground/gcs/src/libs/eigen/doc/snippets/Tutorial_SlicingVec.cpp new file mode 100644 index 0000000000..07e10bf695 --- /dev/null +++ b/ground/gcs/src/libs/eigen/doc/snippets/Tutorial_SlicingVec.cpp @@ -0,0 +1,4 @@ +RowVectorXf v = RowVectorXf::LinSpaced(20,0,19); +cout << "Input:" << endl << v << endl; +Map > v2(v.data(), v.size()/2); +cout << "Even:" << v2 << endl; \ No newline at end of file diff --git a/ground/gcs/src/libs/eigen/doc/snippets/VectorwiseOp_homogeneous.cpp b/ground/gcs/src/libs/eigen/doc/snippets/VectorwiseOp_homogeneous.cpp new file mode 100644 index 0000000000..aba4fed0eb --- /dev/null +++ b/ground/gcs/src/libs/eigen/doc/snippets/VectorwiseOp_homogeneous.cpp @@ -0,0 +1,7 @@ +typedef Matrix Matrix3Xd; +Matrix3Xd M = Matrix3Xd::Random(3,5); +Projective3d P(Matrix4d::Random()); +cout << "The matrix M is:" << endl << M << endl << endl; +cout << "M.colwise().homogeneous():" << endl << M.colwise().homogeneous() << endl << endl; +cout << "P * M.colwise().homogeneous():" << endl << P * M.colwise().homogeneous() << endl << endl; +cout << "P * M.colwise().homogeneous().hnormalized(): " << endl << (P * M.colwise().homogeneous()).colwise().hnormalized() << endl << endl; \ No newline at end of file diff --git a/ground/gcs/src/libs/eigen/doc/snippets/compile_snippet.cpp.in b/ground/gcs/src/libs/eigen/doc/snippets/compile_snippet.cpp.in index 894cd526c2..d63f371a30 100644 --- a/ground/gcs/src/libs/eigen/doc/snippets/compile_snippet.cpp.in +++ b/ground/gcs/src/libs/eigen/doc/snippets/compile_snippet.cpp.in @@ -1,5 +1,13 @@ -#include +static bool eigen_did_assert = false; +#define eigen_assert(X) if(!eigen_did_assert && !(X)){ std::cout << "### Assertion raised in " << __FILE__ << ":" << __LINE__ << ":\n" #X << "\n### The following would happen without assertions:\n"; eigen_did_assert = true;} + #include +#include + +#ifndef M_PI +#define M_PI 3.1415926535897932384626433832795 +#endif + using namespace Eigen; using namespace std; diff --git a/ground/gcs/src/libs/eigen/doc/special_examples/CMakeLists.txt b/ground/gcs/src/libs/eigen/doc/special_examples/CMakeLists.txt index 3ab75dbfe9..101fbc5f9c 100644 --- a/ground/gcs/src/libs/eigen/doc/special_examples/CMakeLists.txt +++ b/ground/gcs/src/libs/eigen/doc/special_examples/CMakeLists.txt @@ -19,3 +19,17 @@ if(QT4_FOUND) add_dependencies(all_examples Tutorial_sparse_example) endif(QT4_FOUND) +check_cxx_compiler_flag("-std=c++11" EIGEN_COMPILER_SUPPORT_CPP11) +if(EIGEN_COMPILER_SUPPORT_CPP11) + add_executable(random_cpp11 random_cpp11.cpp) + target_link_libraries(random_cpp11 ${EIGEN_STANDARD_LIBRARIES_TO_LINK_TO}) + add_dependencies(all_examples random_cpp11) + ei_add_target_property(random_cpp11 COMPILE_FLAGS "-std=c++11") + + add_custom_command( + TARGET random_cpp11 + POST_BUILD + COMMAND random_cpp11 + ARGS >${CMAKE_CURRENT_BINARY_DIR}/random_cpp11.out + ) +endif() diff --git a/ground/gcs/src/libs/eigen/doc/special_examples/Tutorial_sparse_example.cpp b/ground/gcs/src/libs/eigen/doc/special_examples/Tutorial_sparse_example.cpp index 002f19f017..830e196eaa 100644 --- a/ground/gcs/src/libs/eigen/doc/special_examples/Tutorial_sparse_example.cpp +++ b/ground/gcs/src/libs/eigen/doc/special_examples/Tutorial_sparse_example.cpp @@ -9,6 +9,8 @@ void saveAsBitmap(const Eigen::VectorXd& x, int n, const char* filename); int main(int argc, char** argv) { + assert(argc==2); + int n = 300; // size of the image int m = n*n; // number of unknows (=number of pixels) diff --git a/ground/gcs/src/libs/eigen/doc/special_examples/Tutorial_sparse_example_details.cpp b/ground/gcs/src/libs/eigen/doc/special_examples/Tutorial_sparse_example_details.cpp index 7d820b44a2..bc18b01884 100644 --- a/ground/gcs/src/libs/eigen/doc/special_examples/Tutorial_sparse_example_details.cpp +++ b/ground/gcs/src/libs/eigen/doc/special_examples/Tutorial_sparse_example_details.cpp @@ -8,7 +8,7 @@ typedef Eigen::Triplet T; void insertCoefficient(int id, int i, int j, double w, std::vector& coeffs, Eigen::VectorXd& b, const Eigen::VectorXd& boundary) { - int n = boundary.size(); + int n = int(boundary.size()); int id1 = i+j*n; if(i==-1 || i==n) b(id) -= w * boundary(j); // constrained coefficient diff --git a/ground/gcs/src/libs/eigen/doc/special_examples/random_cpp11.cpp b/ground/gcs/src/libs/eigen/doc/special_examples/random_cpp11.cpp new file mode 100644 index 0000000000..33744c0516 --- /dev/null +++ b/ground/gcs/src/libs/eigen/doc/special_examples/random_cpp11.cpp @@ -0,0 +1,14 @@ +#include +#include +#include + +using namespace Eigen; + +int main() { + std::default_random_engine generator; + std::poisson_distribution distribution(4.1); + auto poisson = [&] () {return distribution(generator);}; + + RowVectorXi v = RowVectorXi::NullaryExpr(10, poisson ); + std::cout << v << "\n"; +} diff --git a/ground/gcs/src/libs/eigen/failtest/CMakeLists.txt b/ground/gcs/src/libs/eigen/failtest/CMakeLists.txt index cadc6a2556..1a73f05e62 100644 --- a/ground/gcs/src/libs/eigen/failtest/CMakeLists.txt +++ b/ground/gcs/src/libs/eigen/failtest/CMakeLists.txt @@ -7,6 +7,9 @@ ei_add_failtest("block_nonconst_ctor_on_const_xpr_1") ei_add_failtest("block_nonconst_ctor_on_const_xpr_2") ei_add_failtest("transpose_nonconst_ctor_on_const_xpr") ei_add_failtest("diagonal_nonconst_ctor_on_const_xpr") +ei_add_failtest("cwiseunaryview_nonconst_ctor_on_const_xpr") +ei_add_failtest("triangularview_nonconst_ctor_on_const_xpr") +ei_add_failtest("selfadjointview_nonconst_ctor_on_const_xpr") ei_add_failtest("const_qualified_block_method_retval_0") ei_add_failtest("const_qualified_block_method_retval_1") @@ -25,6 +28,9 @@ ei_add_failtest("block_on_const_type_actually_const_0") ei_add_failtest("block_on_const_type_actually_const_1") ei_add_failtest("transpose_on_const_type_actually_const") ei_add_failtest("diagonal_on_const_type_actually_const") +ei_add_failtest("cwiseunaryview_on_const_type_actually_const") +ei_add_failtest("triangularview_on_const_type_actually_const") +ei_add_failtest("selfadjointview_on_const_type_actually_const") ei_add_failtest("ref_1") ei_add_failtest("ref_2") @@ -32,6 +38,20 @@ ei_add_failtest("ref_3") ei_add_failtest("ref_4") ei_add_failtest("ref_5") +ei_add_failtest("swap_1") +ei_add_failtest("swap_2") + +ei_add_failtest("ternary_1") +ei_add_failtest("ternary_2") + +ei_add_failtest("sparse_ref_1") +ei_add_failtest("sparse_ref_2") +ei_add_failtest("sparse_ref_3") +ei_add_failtest("sparse_ref_4") +ei_add_failtest("sparse_ref_5") + +ei_add_failtest("sparse_storage_mismatch") + ei_add_failtest("partialpivlu_int") ei_add_failtest("fullpivlu_int") ei_add_failtest("llt_int") @@ -40,6 +60,7 @@ ei_add_failtest("qr_int") ei_add_failtest("colpivqr_int") ei_add_failtest("fullpivqr_int") ei_add_failtest("jacobisvd_int") +ei_add_failtest("bdcsvd_int") ei_add_failtest("eigensolver_int") ei_add_failtest("eigensolver_cplx") diff --git a/ground/gcs/src/libs/eigen/failtest/bdcsvd_int.cpp b/ground/gcs/src/libs/eigen/failtest/bdcsvd_int.cpp new file mode 100644 index 0000000000..670752cf59 --- /dev/null +++ b/ground/gcs/src/libs/eigen/failtest/bdcsvd_int.cpp @@ -0,0 +1,14 @@ +#include "../Eigen/SVD" + +#ifdef EIGEN_SHOULD_FAIL_TO_BUILD +#define SCALAR int +#else +#define SCALAR float +#endif + +using namespace Eigen; + +int main() +{ + BDCSVD > qr(Matrix::Random(10,10)); +} diff --git a/ground/gcs/src/libs/eigen/failtest/cwiseunaryview_nonconst_ctor_on_const_xpr.cpp b/ground/gcs/src/libs/eigen/failtest/cwiseunaryview_nonconst_ctor_on_const_xpr.cpp new file mode 100644 index 0000000000..e23cf8fd8d --- /dev/null +++ b/ground/gcs/src/libs/eigen/failtest/cwiseunaryview_nonconst_ctor_on_const_xpr.cpp @@ -0,0 +1,15 @@ +#include "../Eigen/Core" + +#ifdef EIGEN_SHOULD_FAIL_TO_BUILD +#define CV_QUALIFIER const +#else +#define CV_QUALIFIER +#endif + +using namespace Eigen; + +void foo(CV_QUALIFIER Matrix3d &m){ + CwiseUnaryView,Matrix3d> t(m); +} + +int main() {} diff --git a/ground/gcs/src/libs/eigen/failtest/cwiseunaryview_on_const_type_actually_const.cpp b/ground/gcs/src/libs/eigen/failtest/cwiseunaryview_on_const_type_actually_const.cpp new file mode 100644 index 0000000000..fcd41dfdb8 --- /dev/null +++ b/ground/gcs/src/libs/eigen/failtest/cwiseunaryview_on_const_type_actually_const.cpp @@ -0,0 +1,16 @@ +#include "../Eigen/Core" + +#ifdef EIGEN_SHOULD_FAIL_TO_BUILD +#define CV_QUALIFIER const +#else +#define CV_QUALIFIER +#endif + +using namespace Eigen; + +void foo(){ + MatrixXf m; + CwiseUnaryView,CV_QUALIFIER MatrixXf>(m).coeffRef(0, 0) = 1.0f; +} + +int main() {} diff --git a/ground/gcs/src/libs/eigen/failtest/selfadjointview_nonconst_ctor_on_const_xpr.cpp b/ground/gcs/src/libs/eigen/failtest/selfadjointview_nonconst_ctor_on_const_xpr.cpp new file mode 100644 index 0000000000..a240f81848 --- /dev/null +++ b/ground/gcs/src/libs/eigen/failtest/selfadjointview_nonconst_ctor_on_const_xpr.cpp @@ -0,0 +1,15 @@ +#include "../Eigen/Core" + +#ifdef EIGEN_SHOULD_FAIL_TO_BUILD +#define CV_QUALIFIER const +#else +#define CV_QUALIFIER +#endif + +using namespace Eigen; + +void foo(CV_QUALIFIER Matrix3d &m){ + SelfAdjointView t(m); +} + +int main() {} diff --git a/ground/gcs/src/libs/eigen/failtest/selfadjointview_on_const_type_actually_const.cpp b/ground/gcs/src/libs/eigen/failtest/selfadjointview_on_const_type_actually_const.cpp new file mode 100644 index 0000000000..19aaad6d09 --- /dev/null +++ b/ground/gcs/src/libs/eigen/failtest/selfadjointview_on_const_type_actually_const.cpp @@ -0,0 +1,16 @@ +#include "../Eigen/Core" + +#ifdef EIGEN_SHOULD_FAIL_TO_BUILD +#define CV_QUALIFIER const +#else +#define CV_QUALIFIER +#endif + +using namespace Eigen; + +void foo(){ + MatrixXf m; + SelfAdjointView(m).coeffRef(0, 0) = 1.0f; +} + +int main() {} diff --git a/ground/gcs/src/libs/eigen/failtest/sparse_ref_1.cpp b/ground/gcs/src/libs/eigen/failtest/sparse_ref_1.cpp new file mode 100644 index 0000000000..d78d1f9b11 --- /dev/null +++ b/ground/gcs/src/libs/eigen/failtest/sparse_ref_1.cpp @@ -0,0 +1,18 @@ +#include "../Eigen/Sparse" + +#ifdef EIGEN_SHOULD_FAIL_TO_BUILD +#define CV_QUALIFIER const +#else +#define CV_QUALIFIER +#endif + +using namespace Eigen; + +void call_ref(Ref > a) { } + +int main() +{ + SparseMatrix a(10,10); + CV_QUALIFIER SparseMatrix& ac(a); + call_ref(ac); +} diff --git a/ground/gcs/src/libs/eigen/failtest/sparse_ref_2.cpp b/ground/gcs/src/libs/eigen/failtest/sparse_ref_2.cpp new file mode 100644 index 0000000000..46c9440c2f --- /dev/null +++ b/ground/gcs/src/libs/eigen/failtest/sparse_ref_2.cpp @@ -0,0 +1,15 @@ +#include "../Eigen/Sparse" + +using namespace Eigen; + +void call_ref(Ref > a) { } + +int main() +{ + SparseMatrix A(10,10); +#ifdef EIGEN_SHOULD_FAIL_TO_BUILD + call_ref(A.row(3)); +#else + call_ref(A.col(3)); +#endif +} diff --git a/ground/gcs/src/libs/eigen/failtest/sparse_ref_3.cpp b/ground/gcs/src/libs/eigen/failtest/sparse_ref_3.cpp new file mode 100644 index 0000000000..a9949b552c --- /dev/null +++ b/ground/gcs/src/libs/eigen/failtest/sparse_ref_3.cpp @@ -0,0 +1,15 @@ +#include "../Eigen/Sparse" + +using namespace Eigen; + +#ifdef EIGEN_SHOULD_FAIL_TO_BUILD +void call_ref(Ref > a) { } +#else +void call_ref(const Ref > &a) { } +#endif + +int main() +{ + SparseMatrix a(10,10); + call_ref(a+a); +} diff --git a/ground/gcs/src/libs/eigen/failtest/sparse_ref_4.cpp b/ground/gcs/src/libs/eigen/failtest/sparse_ref_4.cpp new file mode 100644 index 0000000000..57bb6a1fcd --- /dev/null +++ b/ground/gcs/src/libs/eigen/failtest/sparse_ref_4.cpp @@ -0,0 +1,15 @@ +#include "../Eigen/Sparse" + +using namespace Eigen; + +void call_ref(Ref > a) {} + +int main() +{ + SparseMatrix A(10,10); +#ifdef EIGEN_SHOULD_FAIL_TO_BUILD + call_ref(A.transpose()); +#else + call_ref(A); +#endif +} diff --git a/ground/gcs/src/libs/eigen/failtest/sparse_ref_5.cpp b/ground/gcs/src/libs/eigen/failtest/sparse_ref_5.cpp new file mode 100644 index 0000000000..4478f6f2f1 --- /dev/null +++ b/ground/gcs/src/libs/eigen/failtest/sparse_ref_5.cpp @@ -0,0 +1,16 @@ +#include "../Eigen/Sparse" + +using namespace Eigen; + +void call_ref(Ref > a) { } + +int main() +{ + SparseMatrix a(10,10); + SparseMatrixBase > &ac(a); +#ifdef EIGEN_SHOULD_FAIL_TO_BUILD + call_ref(ac); +#else + call_ref(ac.derived()); +#endif +} diff --git a/ground/gcs/src/libs/eigen/failtest/sparse_storage_mismatch.cpp b/ground/gcs/src/libs/eigen/failtest/sparse_storage_mismatch.cpp new file mode 100644 index 0000000000..51840d416a --- /dev/null +++ b/ground/gcs/src/libs/eigen/failtest/sparse_storage_mismatch.cpp @@ -0,0 +1,16 @@ +#include "../Eigen/Sparse" +using namespace Eigen; + +typedef SparseMatrix Mat1; +#ifdef EIGEN_SHOULD_FAIL_TO_BUILD +typedef SparseMatrix Mat2; +#else +typedef SparseMatrix Mat2; +#endif + +int main() +{ + Mat1 a(10,10); + Mat2 b(10,10); + a += b; +} diff --git a/ground/gcs/src/libs/eigen/failtest/swap_1.cpp b/ground/gcs/src/libs/eigen/failtest/swap_1.cpp new file mode 100644 index 0000000000..106379720a --- /dev/null +++ b/ground/gcs/src/libs/eigen/failtest/swap_1.cpp @@ -0,0 +1,14 @@ +#include "../Eigen/Core" + +using namespace Eigen; + +int main() +{ + VectorXf a(10), b(10); +#ifdef EIGEN_SHOULD_FAIL_TO_BUILD + const DenseBase &ac(a); +#else + DenseBase &ac(a); +#endif + b.swap(ac); +} diff --git a/ground/gcs/src/libs/eigen/failtest/swap_2.cpp b/ground/gcs/src/libs/eigen/failtest/swap_2.cpp new file mode 100644 index 0000000000..c130ba6e4e --- /dev/null +++ b/ground/gcs/src/libs/eigen/failtest/swap_2.cpp @@ -0,0 +1,14 @@ +#include "../Eigen/Core" + +using namespace Eigen; + +int main() +{ + VectorXf a(10), b(10); + VectorXf const &ac(a); +#ifdef EIGEN_SHOULD_FAIL_TO_BUILD + b.swap(ac); +#else + b.swap(ac.const_cast_derived()); +#endif +} \ No newline at end of file diff --git a/ground/gcs/src/libs/eigen/failtest/ternary_1.cpp b/ground/gcs/src/libs/eigen/failtest/ternary_1.cpp new file mode 100644 index 0000000000..b40bcb0cc2 --- /dev/null +++ b/ground/gcs/src/libs/eigen/failtest/ternary_1.cpp @@ -0,0 +1,13 @@ +#include "../Eigen/Core" + +using namespace Eigen; + +int main(int argc,char **) +{ + VectorXf a(10), b(10); +#ifdef EIGEN_SHOULD_FAIL_TO_BUILD + b = argc>1 ? 2*a : -a; +#else + b = argc>1 ? 2*a : VectorXf(-a); +#endif +} diff --git a/ground/gcs/src/libs/eigen/failtest/ternary_2.cpp b/ground/gcs/src/libs/eigen/failtest/ternary_2.cpp new file mode 100644 index 0000000000..a46b12b2b9 --- /dev/null +++ b/ground/gcs/src/libs/eigen/failtest/ternary_2.cpp @@ -0,0 +1,13 @@ +#include "../Eigen/Core" + +using namespace Eigen; + +int main(int argc,char **) +{ + VectorXf a(10), b(10); +#ifdef EIGEN_SHOULD_FAIL_TO_BUILD + b = argc>1 ? 2*a : a+a; +#else + b = argc>1 ? VectorXf(2*a) : VectorXf(a+a); +#endif +} diff --git a/ground/gcs/src/libs/eigen/failtest/triangularview_nonconst_ctor_on_const_xpr.cpp b/ground/gcs/src/libs/eigen/failtest/triangularview_nonconst_ctor_on_const_xpr.cpp new file mode 100644 index 0000000000..807447e4bf --- /dev/null +++ b/ground/gcs/src/libs/eigen/failtest/triangularview_nonconst_ctor_on_const_xpr.cpp @@ -0,0 +1,15 @@ +#include "../Eigen/Core" + +#ifdef EIGEN_SHOULD_FAIL_TO_BUILD +#define CV_QUALIFIER const +#else +#define CV_QUALIFIER +#endif + +using namespace Eigen; + +void foo(CV_QUALIFIER Matrix3d &m){ + TriangularView t(m); +} + +int main() {} diff --git a/ground/gcs/src/libs/eigen/failtest/triangularview_on_const_type_actually_const.cpp b/ground/gcs/src/libs/eigen/failtest/triangularview_on_const_type_actually_const.cpp new file mode 100644 index 0000000000..0a381a6126 --- /dev/null +++ b/ground/gcs/src/libs/eigen/failtest/triangularview_on_const_type_actually_const.cpp @@ -0,0 +1,16 @@ +#include "../Eigen/Core" + +#ifdef EIGEN_SHOULD_FAIL_TO_BUILD +#define CV_QUALIFIER const +#else +#define CV_QUALIFIER +#endif + +using namespace Eigen; + +void foo(){ + MatrixXf m; + TriangularView(m).coeffRef(0, 0) = 1.0f; +} + +int main() {} diff --git a/ground/gcs/src/libs/eigen/lapack/complex_double.cpp b/ground/gcs/src/libs/eigen/lapack/complex_double.cpp index 424d2b8ca3..c9c5752731 100644 --- a/ground/gcs/src/libs/eigen/lapack/complex_double.cpp +++ b/ground/gcs/src/libs/eigen/lapack/complex_double.cpp @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2009-2011 Gael Guennebaud +// Copyright (C) 2009-2014 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -15,3 +15,4 @@ #include "cholesky.cpp" #include "lu.cpp" +#include "svd.cpp" diff --git a/ground/gcs/src/libs/eigen/lapack/complex_single.cpp b/ground/gcs/src/libs/eigen/lapack/complex_single.cpp index c0b2d29aeb..6d11b26cdf 100644 --- a/ground/gcs/src/libs/eigen/lapack/complex_single.cpp +++ b/ground/gcs/src/libs/eigen/lapack/complex_single.cpp @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2009-2011 Gael Guennebaud +// Copyright (C) 2009-2014 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -15,3 +15,4 @@ #include "cholesky.cpp" #include "lu.cpp" +#include "svd.cpp" diff --git a/ground/gcs/src/libs/eigen/lapack/double.cpp b/ground/gcs/src/libs/eigen/lapack/double.cpp index d86549e193..ea78bb6621 100644 --- a/ground/gcs/src/libs/eigen/lapack/double.cpp +++ b/ground/gcs/src/libs/eigen/lapack/double.cpp @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2009-2011 Gael Guennebaud +// Copyright (C) 2009-2014 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -15,3 +15,4 @@ #include "cholesky.cpp" #include "lu.cpp" #include "eigenvalues.cpp" +#include "svd.cpp" diff --git a/ground/gcs/src/libs/eigen/lapack/eigenvalues.cpp b/ground/gcs/src/libs/eigen/lapack/eigenvalues.cpp index a1526ebcd0..921c515697 100644 --- a/ground/gcs/src/libs/eigen/lapack/eigenvalues.cpp +++ b/ground/gcs/src/libs/eigen/lapack/eigenvalues.cpp @@ -7,10 +7,10 @@ // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. -#include "common.h" +#include "lapack_common.h" #include -// computes an LU factorization of a general M-by-N matrix A using partial pivoting with row interchanges +// computes eigen values and vectors of a general N-by-N matrix A EIGEN_LAPACK_FUNC(syev,(char *jobz, char *uplo, int* n, Scalar* a, int *lda, Scalar* w, Scalar* /*work*/, int* lwork, int *info)) { // TODO exploit the work buffer @@ -22,24 +22,7 @@ EIGEN_LAPACK_FUNC(syev,(char *jobz, char *uplo, int* n, Scalar* a, int *lda, Sca else if(*n<0) *info = -3; else if(*lda +// Copyright (C) 2010-2014 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -11,6 +11,7 @@ #define EIGEN_LAPACK_COMMON_H #include "../blas/common.h" +#include "../Eigen/src/misc/lapack.h" #define EIGEN_LAPACK_FUNC(FUNC,ARGLIST) \ extern "C" { int EIGEN_BLAS_FUNC(FUNC) ARGLIST; } \ @@ -18,6 +19,11 @@ typedef Eigen::Map > PivotsType; +#if ISCOMPLEX +#define EIGEN_LAPACK_ARG_IF_COMPLEX(X) X, +#else +#define EIGEN_LAPACK_ARG_IF_COMPLEX(X) +#endif #endif // EIGEN_LAPACK_COMMON_H diff --git a/ground/gcs/src/libs/eigen/lapack/single.cpp b/ground/gcs/src/libs/eigen/lapack/single.cpp index a64ed44e1c..c7da3effad 100644 --- a/ground/gcs/src/libs/eigen/lapack/single.cpp +++ b/ground/gcs/src/libs/eigen/lapack/single.cpp @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2009-2011 Gael Guennebaud +// Copyright (C) 2009-2014 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -15,3 +15,4 @@ #include "cholesky.cpp" #include "lu.cpp" #include "eigenvalues.cpp" +#include "svd.cpp" diff --git a/ground/gcs/src/libs/eigen/lapack/svd.cpp b/ground/gcs/src/libs/eigen/lapack/svd.cpp new file mode 100644 index 0000000000..77b302b6b4 --- /dev/null +++ b/ground/gcs/src/libs/eigen/lapack/svd.cpp @@ -0,0 +1,138 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "lapack_common.h" +#include + +// computes the singular values/vectors a general M-by-N matrix A using divide-and-conquer +EIGEN_LAPACK_FUNC(gesdd,(char *jobz, int *m, int* n, Scalar* a, int *lda, RealScalar *s, Scalar *u, int *ldu, Scalar *vt, int *ldvt, Scalar* /*work*/, int* lwork, + EIGEN_LAPACK_ARG_IF_COMPLEX(RealScalar */*rwork*/) int * /*iwork*/, int *info)) +{ + // TODO exploit the work buffer + bool query_size = *lwork==-1; + int diag_size = (std::min)(*m,*n); + + *info = 0; + if(*jobz!='A' && *jobz!='S' && *jobz!='O' && *jobz!='N') *info = -1; + else if(*m<0) *info = -2; + else if(*n<0) *info = -3; + else if(*lda=*n && *ldvt<*n)) *info = -10; + + if(*info!=0) + { + int e = -*info; + return xerbla_(SCALAR_SUFFIX_UP"GESDD ", &e, 6); + } + + if(query_size) + { + *lwork = 0; + return 0; + } + + if(*n==0 || *m==0) + return 0; + + PlainMatrixType mat(*m,*n); + mat = matrix(a,*m,*n,*lda); + + int option = *jobz=='A' ? ComputeFullU|ComputeFullV + : *jobz=='S' ? ComputeThinU|ComputeThinV + : *jobz=='O' ? ComputeThinU|ComputeThinV + : 0; + + BDCSVD svd(mat,option); + + make_vector(s,diag_size) = svd.singularValues().head(diag_size); + + if(*jobz=='A') + { + matrix(u,*m,*m,*ldu) = svd.matrixU(); + matrix(vt,*n,*n,*ldvt) = svd.matrixV().adjoint(); + } + else if(*jobz=='S') + { + matrix(u,*m,diag_size,*ldu) = svd.matrixU(); + matrix(vt,diag_size,*n,*ldvt) = svd.matrixV().adjoint(); + } + else if(*jobz=='O' && *m>=*n) + { + matrix(a,*m,*n,*lda) = svd.matrixU(); + matrix(vt,*n,*n,*ldvt) = svd.matrixV().adjoint(); + } + else if(*jobz=='O') + { + matrix(u,*m,*m,*ldu) = svd.matrixU(); + matrix(a,diag_size,*n,*lda) = svd.matrixV().adjoint(); + } + + return 0; +} + +// computes the singular values/vectors a general M-by-N matrix A using two sided jacobi algorithm +EIGEN_LAPACK_FUNC(gesvd,(char *jobu, char *jobv, int *m, int* n, Scalar* a, int *lda, RealScalar *s, Scalar *u, int *ldu, Scalar *vt, int *ldvt, Scalar* /*work*/, int* lwork, + EIGEN_LAPACK_ARG_IF_COMPLEX(RealScalar */*rwork*/) int *info)) +{ + // TODO exploit the work buffer + bool query_size = *lwork==-1; + int diag_size = (std::min)(*m,*n); + + *info = 0; + if( *jobu!='A' && *jobu!='S' && *jobu!='O' && *jobu!='N') *info = -1; + else if((*jobv!='A' && *jobv!='S' && *jobv!='O' && *jobv!='N') + || (*jobu=='O' && *jobv=='O')) *info = -2; + else if(*m<0) *info = -3; + else if(*n<0) *info = -4; + else if(*lda svd(mat,option); + + make_vector(s,diag_size) = svd.singularValues().head(diag_size); + { + if(*jobu=='A') matrix(u,*m,*m,*ldu) = svd.matrixU(); + else if(*jobu=='S') matrix(u,*m,diag_size,*ldu) = svd.matrixU(); + else if(*jobu=='O') matrix(a,*m,diag_size,*lda) = svd.matrixU(); + } + { + if(*jobv=='A') matrix(vt,*n,*n,*ldvt) = svd.matrixV().adjoint(); + else if(*jobv=='S') matrix(vt,diag_size,*n,*ldvt) = svd.matrixV().adjoint(); + else if(*jobv=='O') matrix(a,diag_size,*n,*lda) = svd.matrixV().adjoint(); + } + return 0; +} diff --git a/ground/gcs/src/libs/eigen/scripts/buildtests.in b/ground/gcs/src/libs/eigen/scripts/buildtests.in index 7026373cfc..526d5b74b9 100755 --- a/ground/gcs/src/libs/eigen/scripts/buildtests.in +++ b/ground/gcs/src/libs/eigen/scripts/buildtests.in @@ -2,7 +2,7 @@ if [[ $# != 1 || $1 == *help ]] then - echo "usage: ./check regexp" + echo "usage: $0 regexp" echo " Builds tests matching the regexp." echo " The EIGEN_MAKE_ARGS environment variable allows to pass args to 'make'." echo " For example, to launch 5 concurrent builds, use EIGEN_MAKE_ARGS='-j5'" @@ -14,9 +14,9 @@ targets_to_make=`echo "$TESTSLIST" | egrep "$1" | xargs echo` if [ -n "${EIGEN_MAKE_ARGS:+x}" ] then - make $targets_to_make ${EIGEN_MAKE_ARGS} + @CMAKE_MAKE_PROGRAM@ $targets_to_make ${EIGEN_MAKE_ARGS} else - make $targets_to_make + @CMAKE_MAKE_PROGRAM@ $targets_to_make @EIGEN_TEST_BUILD_FLAGS@ fi exit $? diff --git a/ground/gcs/src/libs/eigen/scripts/check.in b/ground/gcs/src/libs/eigen/scripts/check.in index a90061a579..7717e2d939 100755 --- a/ground/gcs/src/libs/eigen/scripts/check.in +++ b/ground/gcs/src/libs/eigen/scripts/check.in @@ -3,7 +3,7 @@ if [[ $# != 1 || $1 == *help ]] then - echo "usage: ./check regexp" + echo "usage: $0 regexp" echo " Builds and runs tests matching the regexp." echo " The EIGEN_MAKE_ARGS environment variable allows to pass args to 'make'." echo " For example, to launch 5 concurrent builds, use EIGEN_MAKE_ARGS='-j5'" diff --git a/ground/gcs/src/libs/eigen/scripts/eigen_gen_docs b/ground/gcs/src/libs/eigen/scripts/eigen_gen_docs index 0e6f9ada24..787dcb325f 100644 --- a/ground/gcs/src/libs/eigen/scripts/eigen_gen_docs +++ b/ground/gcs/src/libs/eigen/scripts/eigen_gen_docs @@ -4,7 +4,7 @@ # You should call this script with USER set as you want, else some default # will be used USER=${USER:-'orzel'} -UPLOAD_DIR=dox +UPLOAD_DIR=dox-devel #ulimit -v 1024000 diff --git a/ground/gcs/src/libs/eigen/test/CMakeLists.txt b/ground/gcs/src/libs/eigen/test/CMakeLists.txt index c0d8a4e288..2141d07c2b 100644 --- a/ground/gcs/src/libs/eigen/test/CMakeLists.txt +++ b/ground/gcs/src/libs/eigen/test/CMakeLists.txt @@ -1,22 +1,38 @@ - -# generate split test header file -message(STATUS ${CMAKE_CURRENT_BINARY_DIR}) -file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/split_test_helper.h "") -foreach(i RANGE 1 999) - file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/split_test_helper.h - "#ifdef EIGEN_TEST_PART_${i}\n" - "#define CALL_SUBTEST_${i}(FUNC) CALL_SUBTEST(FUNC)\n" - "#else\n" - "#define CALL_SUBTEST_${i}(FUNC)\n" - "#endif\n\n" +# generate split test header file only if it does not yet exist +# in order to prevent a rebuild everytime cmake is configured +if(NOT EXISTS ${CMAKE_CURRENT_BINARY_DIR}/split_test_helper.h) + file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/split_test_helper.h "") + foreach(i RANGE 1 999) + file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/split_test_helper.h + "#ifdef EIGEN_TEST_PART_${i}\n" + "#define CALL_SUBTEST_${i}(FUNC) CALL_SUBTEST(FUNC)\n" + "#else\n" + "#define CALL_SUBTEST_${i}(FUNC)\n" + "#endif\n\n" ) -endforeach() + endforeach() +endif() + +# check if we have a Fortran compiler +include("../cmake/language_support.cmake") + +workaround_9220(Fortran EIGEN_Fortran_COMPILER_WORKS) + +if(EIGEN_Fortran_COMPILER_WORKS) + enable_language(Fortran OPTIONAL) + if(NOT CMAKE_Fortran_COMPILER) + set(EIGEN_Fortran_COMPILER_WORKS OFF) + endif() +endif() + +if(NOT EIGEN_Fortran_COMPILER_WORKS) + # search for a default Lapack library to complete Eigen's one + find_package(LAPACK) +endif() # configure blas/lapack (use Eigen's ones) -set(BLAS_FOUND TRUE) -set(LAPACK_FOUND TRUE) -set(BLAS_LIBRARIES eigen_blas) -set(LAPACK_LIBRARIES eigen_lapack) +set(EIGEN_BLAS_LIBRARIES eigen_blas) +set(EIGEN_LAPACK_LIBRARIES eigen_lapack) set(EIGEN_TEST_MATRIX_DIR "" CACHE STRING "Enable testing of realword sparse matrices contained in the specified path") if(EIGEN_TEST_MATRIX_DIR) @@ -31,33 +47,33 @@ endif(EIGEN_TEST_MATRIX_DIR) set(SPARSE_LIBS " ") find_package(Cholmod) -if(CHOLMOD_FOUND AND BLAS_FOUND AND LAPACK_FOUND) +if(CHOLMOD_FOUND) add_definitions("-DEIGEN_CHOLMOD_SUPPORT") include_directories(${CHOLMOD_INCLUDES}) - set(SPARSE_LIBS ${SPARSE_LIBS} ${CHOLMOD_LIBRARIES} ${BLAS_LIBRARIES} ${LAPACK_LIBRARIES}) - set(CHOLMOD_ALL_LIBS ${CHOLMOD_LIBRARIES} ${BLAS_LIBRARIES} ${LAPACK_LIBRARIES}) + set(SPARSE_LIBS ${SPARSE_LIBS} ${CHOLMOD_LIBRARIES} ${EIGEN_BLAS_LIBRARIES} ${EIGEN_LAPACK_LIBRARIES}) + set(CHOLMOD_ALL_LIBS ${CHOLMOD_LIBRARIES} ${EIGEN_BLAS_LIBRARIES} ${EIGEN_LAPACK_LIBRARIES}) ei_add_property(EIGEN_TESTED_BACKENDS "Cholmod, ") else() ei_add_property(EIGEN_MISSING_BACKENDS "Cholmod, ") endif() find_package(Umfpack) -if(UMFPACK_FOUND AND BLAS_FOUND) +if(UMFPACK_FOUND) add_definitions("-DEIGEN_UMFPACK_SUPPORT") include_directories(${UMFPACK_INCLUDES}) - set(SPARSE_LIBS ${SPARSE_LIBS} ${UMFPACK_LIBRARIES} ${BLAS_LIBRARIES}) - set(UMFPACK_ALL_LIBS ${UMFPACK_LIBRARIES} ${BLAS_LIBRARIES}) + set(SPARSE_LIBS ${SPARSE_LIBS} ${UMFPACK_LIBRARIES} ${EIGEN_BLAS_LIBRARIES}) + set(UMFPACK_ALL_LIBS ${UMFPACK_LIBRARIES} ${EIGEN_BLAS_LIBRARIES}) ei_add_property(EIGEN_TESTED_BACKENDS "UmfPack, ") else() ei_add_property(EIGEN_MISSING_BACKENDS "UmfPack, ") endif() -find_package(SuperLU) -if(SUPERLU_FOUND AND BLAS_FOUND) +find_package(SuperLU 4.0) +if(SUPERLU_FOUND) add_definitions("-DEIGEN_SUPERLU_SUPPORT") include_directories(${SUPERLU_INCLUDES}) - set(SPARSE_LIBS ${SPARSE_LIBS} ${SUPERLU_LIBRARIES} ${BLAS_LIBRARIES}) - set(SUPERLU_ALL_LIBS ${SUPERLU_LIBRARIES} ${BLAS_LIBRARIES}) + set(SPARSE_LIBS ${SPARSE_LIBS} ${SUPERLU_LIBRARIES} ${EIGEN_BLAS_LIBRARIES}) + set(SUPERLU_ALL_LIBS ${SUPERLU_LIBRARIES} ${EIGEN_BLAS_LIBRARIES}) ei_add_property(EIGEN_TESTED_BACKENDS "SuperLU, ") else() ei_add_property(EIGEN_MISSING_BACKENDS "SuperLU, ") @@ -67,7 +83,7 @@ endif() find_package(Pastix) find_package(Scotch) find_package(Metis 5.0 REQUIRED) -if(PASTIX_FOUND AND BLAS_FOUND) +if(PASTIX_FOUND) add_definitions("-DEIGEN_PASTIX_SUPPORT") include_directories(${PASTIX_INCLUDES}) if(SCOTCH_FOUND) @@ -79,8 +95,8 @@ if(PASTIX_FOUND AND BLAS_FOUND) else(SCOTCH_FOUND) ei_add_property(EIGEN_MISSING_BACKENDS "PaStiX, ") endif(SCOTCH_FOUND) - set(SPARSE_LIBS ${SPARSE_LIBS} ${PASTIX_LIBRARIES} ${ORDERING_LIBRARIES} ${BLAS_LIBRARIES}) - set(PASTIX_ALL_LIBS ${PASTIX_LIBRARIES} ${BLAS_LIBRARIES}) + set(SPARSE_LIBS ${SPARSE_LIBS} ${PASTIX_LIBRARIES} ${ORDERING_LIBRARIES} ${EIGEN_BLAS_LIBRARIES}) + set(PASTIX_ALL_LIBS ${PASTIX_LIBRARIES} ${EIGEN_BLAS_LIBRARIES}) ei_add_property(EIGEN_TESTED_BACKENDS "PaStiX, ") else() ei_add_property(EIGEN_MISSING_BACKENDS "PaStiX, ") @@ -95,16 +111,14 @@ else() endif() find_package(SPQR) -if(SPQR_FOUND AND BLAS_FOUND AND LAPACK_FOUND) - if(CHOLMOD_FOUND) - add_definitions("-DEIGEN_SPQR_SUPPORT") - include_directories(${SPQR_INCLUDES}) - set(SPQR_ALL_LIBS ${SPQR_LIBRARIES} ${CHOLMOD_LIBRARIES} ${LAPACK_LIBRARIES} ${BLAS_LIBRARIES}) - set(SPARSE_LIBS ${SPARSE_LIBS} ${SPQR_ALL_LIBS}) - ei_add_property(EIGEN_TESTED_BACKENDS "SPQR, ") - else(CHOLMOD_FOUND) - ei_add_property(EIGEN_MISSING_BACKENDS "SPQR, ") - endif(CHOLMOD_FOUND) +if(SPQR_FOUND AND CHOLMOD_FOUND AND (EIGEN_Fortran_COMPILER_WORKS OR LAPACK_FOUND) ) + add_definitions("-DEIGEN_SPQR_SUPPORT") + include_directories(${SPQR_INCLUDES}) + set(SPQR_ALL_LIBS ${SPQR_LIBRARIES} ${CHOLMOD_LIBRARIES} ${EIGEN_LAPACK_LIBRARIES} ${EIGEN_BLAS_LIBRARIES} ${LAPACK_LIBRARIES}) + set(SPARSE_LIBS ${SPARSE_LIBS} ${SPQR_ALL_LIBS}) + ei_add_property(EIGEN_TESTED_BACKENDS "SPQR, ") +else() + ei_add_property(EIGEN_MISSING_BACKENDS "SPQR, ") endif() option(EIGEN_TEST_NOQT "Disable Qt support in unit tests" OFF) @@ -125,25 +139,32 @@ endif(TEST_LIB) set_property(GLOBAL PROPERTY EIGEN_CURRENT_SUBPROJECT "Official") add_custom_target(BuildOfficial) +ei_add_test(rand) ei_add_test(meta) ei_add_test(sizeof) ei_add_test(dynalloc) ei_add_test(nomalloc) ei_add_test(first_aligned) +ei_add_test(nullary) ei_add_test(mixingtypes) -ei_add_test(packetmath) +ei_add_test(packetmath "-DEIGEN_FAST_MATH=1") ei_add_test(unalignedassert) ei_add_test(vectorization_logic) ei_add_test(basicstuff) +ei_add_test(constructor) ei_add_test(linearstructure) ei_add_test(integer_types) -ei_add_test(cwiseop) ei_add_test(unalignedcount) -ei_add_test(exceptions) +if(NOT EIGEN_TEST_NO_EXCEPTIONS) + ei_add_test(exceptions) +endif() ei_add_test(redux) ei_add_test(visitor) ei_add_test(block) ei_add_test(corners) +ei_add_test(swap) +ei_add_test(resize) +ei_add_test(conservative_resize) ei_add_test(product_small) ei_add_test(product_large) ei_add_test(product_extra) @@ -161,6 +182,7 @@ ei_add_test(array_for_matrix) ei_add_test(array_replicate) ei_add_test(array_reverse) ei_add_test(ref) +ei_add_test(is_same_dense) ei_add_test(triangular) ei_add_test(selfadjoint) ei_add_test(product_selfadjoint) @@ -172,6 +194,7 @@ ei_add_test(product_trsolve) ei_add_test(product_mmtr) ei_add_test(product_notemporary) ei_add_test(stable_norm) +ei_add_test(permutationmatrices) ei_add_test(bandmatrix) ei_add_test(cholesky) ei_add_test(lu) @@ -191,56 +214,75 @@ ei_add_test(real_qz) ei_add_test(eigensolver_generalized_real) ei_add_test(jacobi) ei_add_test(jacobisvd) +ei_add_test(bdcsvd) +ei_add_test(householder) ei_add_test(geo_orthomethods) -ei_add_test(geo_homogeneous) ei_add_test(geo_quaternion) -ei_add_test(geo_transformations) ei_add_test(geo_eulerangles) -ei_add_test(geo_hyperplane) ei_add_test(geo_parametrizedline) ei_add_test(geo_alignedbox) +ei_add_test(geo_hyperplane) +ei_add_test(geo_transformations) +ei_add_test(geo_homogeneous) ei_add_test(stdvector) ei_add_test(stdvector_overload) ei_add_test(stdlist) ei_add_test(stdlist_overload) ei_add_test(stddeque) ei_add_test(stddeque_overload) -ei_add_test(resize) -ei_add_test(sparse_vector) ei_add_test(sparse_basic) +ei_add_test(sparse_block) +ei_add_test(sparse_vector) ei_add_test(sparse_product) +ei_add_test(sparse_ref) ei_add_test(sparse_solvers) -ei_add_test(umeyama) -ei_add_test(householder) -ei_add_test(swap) -ei_add_test(conservative_resize) -ei_add_test(permutationmatrices) ei_add_test(sparse_permutations) -ei_add_test(nullary) +ei_add_test(simplicial_cholesky) +ei_add_test(conjugate_gradient) +ei_add_test(incomplete_cholesky) +ei_add_test(bicgstab) +ei_add_test(lscg) +ei_add_test(sparselu) +ei_add_test(sparseqr) +ei_add_test(umeyama) ei_add_test(nesting_ops "${CMAKE_CXX_FLAGS_DEBUG}") ei_add_test(zerosized) ei_add_test(dontalign) -ei_add_test(sizeoverflow) +ei_add_test(evaluators) +if(NOT EIGEN_TEST_NO_EXCEPTIONS) + ei_add_test(sizeoverflow) +endif() ei_add_test(prec_inverse_4x4) ei_add_test(vectorwiseop) ei_add_test(special_numbers) ei_add_test(rvalue_types) +ei_add_test(dense_storage) +ei_add_test(ctorleak) ei_add_test(mpl2only) +ei_add_test(inplace_decomposition) +ei_add_test(half_float) +ei_add_test(array_of_string) -ei_add_test(simplicial_cholesky) -ei_add_test(conjugate_gradient) -ei_add_test(bicgstab) -ei_add_test(sparselu) -ei_add_test(sparseqr) +add_executable(bug1213 bug1213.cpp bug1213_main.cpp) + +check_cxx_compiler_flag("-ffast-math" COMPILER_SUPPORT_FASTMATH) +if(COMPILER_SUPPORT_FASTMATH) + set(EIGEN_FASTMATH_FLAGS "-ffast-math") +else() + check_cxx_compiler_flag("/fp:fast" COMPILER_SUPPORT_FPFAST) + if(COMPILER_SUPPORT_FPFAST) + set(EIGEN_FASTMATH_FLAGS "/fp:fast") + endif() +endif() -# ei_add_test(denseLM) +ei_add_test(fastmath " ${EIGEN_FASTMATH_FLAGS} ") + +# # ei_add_test(denseLM) if(QT4_FOUND) ei_add_test(qtvector "" "${QT_QTCORE_LIBRARY}") endif(QT4_FOUND) -ei_add_test(eigen2support) - if(UMFPACK_FOUND) ei_add_test(umfpack_support "" "${UMFPACK_ALL_LIBS}") endif() @@ -285,9 +327,54 @@ ei_add_property(EIGEN_TESTING_SUMMARY "Sparse lib flags: ${SPARSE_LIBS}\n") option(EIGEN_TEST_EIGEN2 "Run whole Eigen2 test suite against EIGEN2_SUPPORT" OFF) mark_as_advanced(EIGEN_TEST_EIGEN2) if(EIGEN_TEST_EIGEN2) - add_subdirectory(eigen2) + message(WARNING "The Eigen2 test suite has been removed") +endif() + +# boost MP unit test +find_package(Boost) +if(Boost_FOUND) + include_directories(${Boost_INCLUDE_DIRS}) + ei_add_test(boostmultiprec "" "${Boost_LIBRARIES}") + ei_add_property(EIGEN_TESTED_BACKENDS "Boost.Multiprecision, ") +else() + ei_add_property(EIGEN_MISSING_BACKENDS "Boost.Multiprecision, ") +endif() + + +# CUDA unit tests +option(EIGEN_TEST_CUDA "Enable CUDA support in unit tests" OFF) +option(EIGEN_TEST_CUDA_CLANG "Use clang instead of nvcc to compile the CUDA tests" OFF) + +if(EIGEN_TEST_CUDA_CLANG AND NOT CMAKE_CXX_COMPILER MATCHES "clang") + message(WARNING "EIGEN_TEST_CUDA_CLANG is set, but CMAKE_CXX_COMPILER does not appear to be clang.") endif() +if(EIGEN_TEST_CUDA) + +find_package(CUDA 5.0) +if(CUDA_FOUND) + + set(CUDA_PROPAGATE_HOST_FLAGS OFF) + if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + set(CUDA_NVCC_FLAGS "-ccbin ${CMAKE_C_COMPILER}" CACHE STRING "nvcc flags" FORCE) + endif() + if(EIGEN_TEST_CUDA_CLANG) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 --cuda-gpu-arch=sm_30") + endif() + cuda_include_directories(${CMAKE_CURRENT_BINARY_DIR}) + set(EIGEN_ADD_TEST_FILENAME_EXTENSION "cu") + + ei_add_test(cuda_basic) + + unset(EIGEN_ADD_TEST_FILENAME_EXTENSION) + +endif(CUDA_FOUND) + +endif(EIGEN_TEST_CUDA) + + +file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/failtests) +add_test(NAME failtests WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/failtests COMMAND ${CMAKE_COMMAND} ${Eigen_SOURCE_DIR} -G "${CMAKE_GENERATOR}" -DEIGEN_FAILTEST=ON) option(EIGEN_TEST_BUILD_DOCUMENTATION "Test building the doxygen documentation" OFF) IF(EIGEN_TEST_BUILD_DOCUMENTATION) diff --git a/ground/gcs/src/libs/eigen/test/adjoint.cpp b/ground/gcs/src/libs/eigen/test/adjoint.cpp index ea36f7841d..bdea51c108 100644 --- a/ground/gcs/src/libs/eigen/test/adjoint.cpp +++ b/ground/gcs/src/libs/eigen/test/adjoint.cpp @@ -42,6 +42,17 @@ template<> struct adjoint_specific { VERIFY_IS_APPROX(v1, v1.norm() * v3); VERIFY_IS_APPROX(v3, v1.normalized()); VERIFY_IS_APPROX(v3.norm(), RealScalar(1)); + + // check null inputs + VERIFY_IS_APPROX((v1*0).normalized(), (v1*0)); +#if (!EIGEN_ARCH_i386) || defined(EIGEN_VECTORIZE) + RealScalar very_small = (std::numeric_limits::min)(); + VERIFY( (v1*very_small).norm() == 0 ); + VERIFY_IS_APPROX((v1*very_small).normalized(), (v1*very_small)); + v3 = v1*very_small; + v3.normalize(); + VERIFY_IS_APPROX(v3, (v1*very_small)); +#endif // check compatibility of dot and adjoint ref = NumTraits::IsInteger ? 0 : (std::max)((std::max)(v1.norm(),v2.norm()),(std::max)((square * v2).norm(),(square.adjoint() * v1).norm())); @@ -64,6 +75,7 @@ template void adjoint(const MatrixType& m) typedef typename NumTraits::Real RealScalar; typedef Matrix VectorType; typedef Matrix SquareMatrixType; + const Index PacketSize = internal::packet_traits::size; Index rows = m.rows(); Index cols = m.cols(); @@ -108,6 +120,17 @@ template void adjoint(const MatrixType& m) VERIFY_IS_APPROX(m3,m1.transpose()); m3.transposeInPlace(); VERIFY_IS_APPROX(m3,m1); + + if(PacketSize(0,m3.rows()-PacketSize); + Index j = internal::random(0,m3.cols()-PacketSize); + m3.template block(i,j).transposeInPlace(); + VERIFY_IS_APPROX( (m3.template block(i,j)), (m1.template block(i,j).transpose()) ); + m3.template block(i,j).transposeInPlace(); + VERIFY_IS_APPROX(m3,m1); + } // check inplace adjoint m3 = m1; @@ -129,14 +152,24 @@ void test_adjoint() CALL_SUBTEST_1( adjoint(Matrix()) ); CALL_SUBTEST_2( adjoint(Matrix3d()) ); CALL_SUBTEST_3( adjoint(Matrix4f()) ); + CALL_SUBTEST_4( adjoint(MatrixXcf(internal::random(1,EIGEN_TEST_MAX_SIZE/2), internal::random(1,EIGEN_TEST_MAX_SIZE/2))) ); CALL_SUBTEST_5( adjoint(MatrixXi(internal::random(1,EIGEN_TEST_MAX_SIZE), internal::random(1,EIGEN_TEST_MAX_SIZE))) ); CALL_SUBTEST_6( adjoint(MatrixXf(internal::random(1,EIGEN_TEST_MAX_SIZE), internal::random(1,EIGEN_TEST_MAX_SIZE))) ); + + // Complement for 128 bits vectorization: + CALL_SUBTEST_8( adjoint(Matrix2d()) ); + CALL_SUBTEST_9( adjoint(Matrix()) ); + + // 256 bits vectorization: + CALL_SUBTEST_10( adjoint(Matrix()) ); + CALL_SUBTEST_11( adjoint(Matrix()) ); + CALL_SUBTEST_12( adjoint(Matrix()) ); } // test a large static matrix only once CALL_SUBTEST_7( adjoint(Matrix()) ); -#ifdef EIGEN_TEST_PART_4 +#ifdef EIGEN_TEST_PART_13 { MatrixXcf a(10,10), b(10,10); VERIFY_RAISES_ASSERT(a = a.transpose()); @@ -154,6 +187,13 @@ void test_adjoint() a.transpose() = a.adjoint(); a.transpose() += a.adjoint(); a.transpose() += a.adjoint() + b; + + // regression tests for check_for_aliasing + MatrixXd c(10,10); + c = 1.0 * MatrixXd::Ones(10,10) + c; + c = MatrixXd::Ones(10,10) * 1.0 + c; + c = c + MatrixXd::Ones(10,10) .cwiseProduct( MatrixXd::Zero(10,10) ); + c = MatrixXd::Ones(10,10) * MatrixXd::Zero(10,10); } #endif } diff --git a/ground/gcs/src/libs/eigen/test/array.cpp b/ground/gcs/src/libs/eigen/test/array.cpp index 68f6b3d7ab..15c3266a98 100644 --- a/ground/gcs/src/libs/eigen/test/array.cpp +++ b/ground/gcs/src/libs/eigen/test/array.cpp @@ -13,6 +13,7 @@ template void array(const ArrayType& m) { typedef typename ArrayType::Index Index; typedef typename ArrayType::Scalar Scalar; + typedef typename ArrayType::RealScalar RealScalar; typedef Array ColVectorType; typedef Array RowVectorType; @@ -22,6 +23,8 @@ template void array(const ArrayType& m) ArrayType m1 = ArrayType::Random(rows, cols), m2 = ArrayType::Random(rows, cols), m3(rows, cols); + ArrayType m4 = m1; // copy constructor + VERIFY_IS_APPROX(m1, m4); ColVectorType cv1 = ColVectorType::Random(rows); RowVectorType rv1 = RowVectorType::Random(cols); @@ -70,7 +73,7 @@ template void array(const ArrayType& m) VERIFY_IS_MUCH_SMALLER_THAN(abs(m1.rowwise().sum().sum() - m1.sum()), m1.abs().sum()); if (!internal::isMuchSmallerThan(abs(m1.sum() - (m1+m2).sum()), m1.abs().sum(), test_precision())) VERIFY_IS_NOT_APPROX(((m1+m2).rowwise().sum()).sum(), m1.sum()); - VERIFY_IS_APPROX(m1.colwise().sum(), m1.colwise().redux(internal::scalar_sum_op())); + VERIFY_IS_APPROX(m1.colwise().sum(), m1.colwise().redux(internal::scalar_sum_op())); // vector-wise ops m3 = m1; @@ -81,6 +84,47 @@ template void array(const ArrayType& m) VERIFY_IS_APPROX(m3.rowwise() += rv1, m1.rowwise() + rv1); m3 = m1; VERIFY_IS_APPROX(m3.rowwise() -= rv1, m1.rowwise() - rv1); + + // Conversion from scalar + VERIFY_IS_APPROX((m3 = s1), ArrayType::Constant(rows,cols,s1)); + VERIFY_IS_APPROX((m3 = 1), ArrayType::Constant(rows,cols,1)); + VERIFY_IS_APPROX((m3.topLeftCorner(rows,cols) = 1), ArrayType::Constant(rows,cols,1)); + typedef Array FixedArrayType; + FixedArrayType f1(s1); + VERIFY_IS_APPROX(f1, FixedArrayType::Constant(s1)); + FixedArrayType f2(numext::real(s1)); + VERIFY_IS_APPROX(f2, FixedArrayType::Constant(numext::real(s1))); + FixedArrayType f3((int)100*numext::real(s1)); + VERIFY_IS_APPROX(f3, FixedArrayType::Constant((int)100*numext::real(s1))); + f1.setRandom(); + FixedArrayType f4(f1.data()); + VERIFY_IS_APPROX(f4, f1); + + // pow + VERIFY_IS_APPROX(m1.pow(2), m1.square()); + VERIFY_IS_APPROX(pow(m1,2), m1.square()); + VERIFY_IS_APPROX(m1.pow(3), m1.cube()); + VERIFY_IS_APPROX(pow(m1,3), m1.cube()); + VERIFY_IS_APPROX((-m1).pow(3), -m1.cube()); + VERIFY_IS_APPROX(pow(2*m1,3), 8*m1.cube()); + ArrayType exponents = ArrayType::Constant(rows, cols, RealScalar(2)); + VERIFY_IS_APPROX(Eigen::pow(m1,exponents), m1.square()); + VERIFY_IS_APPROX(m1.pow(exponents), m1.square()); + VERIFY_IS_APPROX(Eigen::pow(2*m1,exponents), 4*m1.square()); + VERIFY_IS_APPROX((2*m1).pow(exponents), 4*m1.square()); + VERIFY_IS_APPROX(Eigen::pow(m1,2*exponents), m1.square().square()); + VERIFY_IS_APPROX(m1.pow(2*exponents), m1.square().square()); + VERIFY_IS_APPROX(Eigen::pow(m1(0,0), exponents), ArrayType::Constant(rows,cols,m1(0,0)*m1(0,0))); + + // Check possible conflicts with 1D ctor + typedef Array OneDArrayType; + OneDArrayType o1(rows); + VERIFY(o1.size()==rows); + OneDArrayType o4((int)rows); + VERIFY(o4.size()==rows); } template void comparisons(const ArrayType& m) @@ -97,8 +141,11 @@ template void comparisons(const ArrayType& m) c = internal::random(0, cols-1); ArrayType m1 = ArrayType::Random(rows, cols), - m2 = ArrayType::Random(rows, cols), - m3(rows, cols); + m2 = ArrayType::Random(rows, cols), + m3(rows, cols), + m4 = m1; + + m4 = (m4.abs()==Scalar(0)).select(1,m4); VERIFY(((m1 + Scalar(1)) > m1).all()); VERIFY(((m1 - Scalar(1)) < m1).all()); @@ -112,11 +159,17 @@ template void comparisons(const ArrayType& m) VERIFY(!(m1 > m2 && m1 < m2).any()); VERIFY((m1 <= m2 || m1 >= m2).all()); - // comparisons to scalar + // comparisons array to scalar VERIFY( (m1 != (m1(r,c)+1) ).any() ); - VERIFY( (m1 > (m1(r,c)-1) ).any() ); - VERIFY( (m1 < (m1(r,c)+1) ).any() ); - VERIFY( (m1 == m1(r,c) ).any() ); + VERIFY( (m1 > (m1(r,c)-1) ).any() ); + VERIFY( (m1 < (m1(r,c)+1) ).any() ); + VERIFY( (m1 == m1(r,c) ).any() ); + + // comparisons scalar to array + VERIFY( ( (m1(r,c)+1) != m1).any() ); + VERIFY( ( (m1(r,c)-1) < m1).any() ); + VERIFY( ( (m1(r,c)+1) > m1).any() ); + VERIFY( ( m1(r,c) == m1).any() ); // test Select VERIFY_IS_APPROX( (m1 void array_real(const ArrayType& m) ArrayType m1 = ArrayType::Random(rows, cols), m2 = ArrayType::Random(rows, cols), - m3(rows, cols); + m3(rows, cols), + m4 = m1; + + m4 = (m4.abs()==Scalar(0)).select(1,m4); Scalar s1 = internal::random(); - // these tests are mostly to check possible compilation issues. + // these tests are mostly to check possible compilation issues with free-functions. VERIFY_IS_APPROX(m1.sin(), sin(m1)); VERIFY_IS_APPROX(m1.cos(), cos(m1)); + VERIFY_IS_APPROX(m1.tan(), tan(m1)); VERIFY_IS_APPROX(m1.asin(), asin(m1)); VERIFY_IS_APPROX(m1.acos(), acos(m1)); - VERIFY_IS_APPROX(m1.tan(), tan(m1)); - + VERIFY_IS_APPROX(m1.atan(), atan(m1)); + VERIFY_IS_APPROX(m1.sinh(), sinh(m1)); + VERIFY_IS_APPROX(m1.cosh(), cosh(m1)); + VERIFY_IS_APPROX(m1.tanh(), tanh(m1)); + + VERIFY_IS_APPROX(m1.arg(), arg(m1)); + VERIFY_IS_APPROX(m1.round(), round(m1)); + VERIFY_IS_APPROX(m1.floor(), floor(m1)); + VERIFY_IS_APPROX(m1.ceil(), ceil(m1)); + VERIFY((m1.isNaN() == (Eigen::isnan)(m1)).all()); + VERIFY((m1.isInf() == (Eigen::isinf)(m1)).all()); + VERIFY((m1.isFinite() == (Eigen::isfinite)(m1)).all()); + VERIFY_IS_APPROX(m1.inverse(), inverse(m1)); + VERIFY_IS_APPROX(m1.abs(), abs(m1)); + VERIFY_IS_APPROX(m1.abs2(), abs2(m1)); + VERIFY_IS_APPROX(m1.square(), square(m1)); + VERIFY_IS_APPROX(m1.cube(), cube(m1)); VERIFY_IS_APPROX(cos(m1+RealScalar(3)*m2), cos((m1+RealScalar(3)*m2).eval())); + VERIFY_IS_APPROX(m1.sign(), sign(m1)); + - VERIFY_IS_APPROX(m1.abs().sqrt(), sqrt(abs(m1))); - VERIFY_IS_APPROX(m1.abs(), sqrt(numext::abs2(m1))); + // avoid NaNs with abs() so verification doesn't fail + m3 = m1.abs(); + VERIFY_IS_APPROX(m3.sqrt(), sqrt(abs(m1))); + VERIFY_IS_APPROX(m3.rsqrt(), Scalar(1)/sqrt(abs(m1))); + VERIFY_IS_APPROX(rsqrt(m3), Scalar(1)/sqrt(abs(m1))); + VERIFY_IS_APPROX(m3.log(), log(m3)); + VERIFY_IS_APPROX(m3.log1p(), log1p(m3)); + VERIFY_IS_APPROX(m3.log10(), log10(m3)); + + + VERIFY((!(m1>m2) == (m1<=m2)).all()); + + VERIFY_IS_APPROX(sin(m1.asin()), m1); + VERIFY_IS_APPROX(cos(m1.acos()), m1); + VERIFY_IS_APPROX(tan(m1.atan()), m1); + VERIFY_IS_APPROX(sinh(m1), 0.5*(exp(m1)-exp(-m1))); + VERIFY_IS_APPROX(cosh(m1), 0.5*(exp(m1)+exp(-m1))); + VERIFY_IS_APPROX(tanh(m1), (0.5*(exp(m1)-exp(-m1)))/(0.5*(exp(m1)+exp(-m1)))); + VERIFY_IS_APPROX(arg(m1), ((m1<0).template cast())*std::acos(-1.0)); + VERIFY((round(m1) <= ceil(m1) && round(m1) >= floor(m1)).all()); + VERIFY((Eigen::isnan)((m1*0.0)/0.0).all()); + VERIFY((Eigen::isinf)(m4/0.0).all()); + VERIFY(((Eigen::isfinite)(m1) && (!(Eigen::isfinite)(m1*0.0/0.0)) && (!(Eigen::isfinite)(m4/0.0))).all()); + VERIFY_IS_APPROX(inverse(inverse(m1)),m1); + VERIFY((abs(m1) == m1 || abs(m1) == -m1).all()); + VERIFY_IS_APPROX(m3, sqrt(abs2(m1))); + VERIFY_IS_APPROX( m1.sign(), -(-m1).sign() ); + VERIFY_IS_APPROX( m1*m1.sign(),m1.abs()); + VERIFY_IS_APPROX(m1.sign() * m1.abs(), m1); VERIFY_IS_APPROX(numext::abs2(numext::real(m1)) + numext::abs2(numext::imag(m1)), numext::abs2(m1)); VERIFY_IS_APPROX(numext::abs2(real(m1)) + numext::abs2(imag(m1)), numext::abs2(m1)); @@ -187,52 +288,138 @@ template void array_real(const ArrayType& m) // shift argument of logarithm so that it is not zero Scalar smallNumber = NumTraits::dummy_precision(); - VERIFY_IS_APPROX((m1.abs() + smallNumber).log() , log(abs(m1) + smallNumber)); + VERIFY_IS_APPROX((m3 + smallNumber).log() , log(abs(m1) + smallNumber)); + VERIFY_IS_APPROX((m3 + smallNumber + 1).log() , log1p(abs(m1) + smallNumber)); VERIFY_IS_APPROX(m1.exp() * m2.exp(), exp(m1+m2)); VERIFY_IS_APPROX(m1.exp(), exp(m1)); VERIFY_IS_APPROX(m1.exp() / m2.exp(),(m1-m2).exp()); - VERIFY_IS_APPROX(m1.pow(2), m1.square()); - VERIFY_IS_APPROX(pow(m1,2), m1.square()); - - ArrayType exponents = ArrayType::Constant(rows, cols, RealScalar(2)); - VERIFY_IS_APPROX(Eigen::pow(m1,exponents), m1.square()); - - m3 = m1.abs(); VERIFY_IS_APPROX(m3.pow(RealScalar(0.5)), m3.sqrt()); VERIFY_IS_APPROX(pow(m3,RealScalar(0.5)), m3.sqrt()); + VERIFY_IS_APPROX(m3.pow(RealScalar(-0.5)), m3.rsqrt()); + VERIFY_IS_APPROX(pow(m3,RealScalar(-0.5)), m3.rsqrt()); + + VERIFY_IS_APPROX(log10(m3), log(m3)/log(10)); + // scalar by array division const RealScalar tiny = sqrt(std::numeric_limits::epsilon()); s1 += Scalar(tiny); m1 += ArrayType::Constant(rows,cols,Scalar(tiny)); VERIFY_IS_APPROX(s1/m1, s1 * m1.inverse()); - + // check inplace transpose m3 = m1; m3.transposeInPlace(); - VERIFY_IS_APPROX(m3,m1.transpose()); + VERIFY_IS_APPROX(m3, m1.transpose()); m3.transposeInPlace(); - VERIFY_IS_APPROX(m3,m1); + VERIFY_IS_APPROX(m3, m1); } template void array_complex(const ArrayType& m) { typedef typename ArrayType::Index Index; + typedef typename ArrayType::Scalar Scalar; + typedef typename NumTraits::Real RealScalar; Index rows = m.rows(); Index cols = m.cols(); ArrayType m1 = ArrayType::Random(rows, cols), - m2(rows, cols); + m2(rows, cols), + m4 = m1; + + m4.real() = (m4.real().abs()==RealScalar(0)).select(RealScalar(1),m4.real()); + m4.imag() = (m4.imag().abs()==RealScalar(0)).select(RealScalar(1),m4.imag()); + + Array m3(rows, cols); for (Index i = 0; i < m.rows(); ++i) for (Index j = 0; j < m.cols(); ++j) m2(i,j) = sqrt(m1(i,j)); - VERIFY_IS_APPROX(m1.sqrt(), m2); - VERIFY_IS_APPROX(m1.sqrt(), Eigen::sqrt(m1)); + // these tests are mostly to check possible compilation issues with free-functions. + VERIFY_IS_APPROX(m1.sin(), sin(m1)); + VERIFY_IS_APPROX(m1.cos(), cos(m1)); + VERIFY_IS_APPROX(m1.tan(), tan(m1)); + VERIFY_IS_APPROX(m1.sinh(), sinh(m1)); + VERIFY_IS_APPROX(m1.cosh(), cosh(m1)); + VERIFY_IS_APPROX(m1.tanh(), tanh(m1)); + VERIFY_IS_APPROX(m1.arg(), arg(m1)); + VERIFY((m1.isNaN() == (Eigen::isnan)(m1)).all()); + VERIFY((m1.isInf() == (Eigen::isinf)(m1)).all()); + VERIFY((m1.isFinite() == (Eigen::isfinite)(m1)).all()); + VERIFY_IS_APPROX(m1.inverse(), inverse(m1)); + VERIFY_IS_APPROX(m1.log(), log(m1)); + VERIFY_IS_APPROX(m1.log10(), log10(m1)); + VERIFY_IS_APPROX(m1.abs(), abs(m1)); + VERIFY_IS_APPROX(m1.abs2(), abs2(m1)); + VERIFY_IS_APPROX(m1.sqrt(), sqrt(m1)); + VERIFY_IS_APPROX(m1.square(), square(m1)); + VERIFY_IS_APPROX(m1.cube(), cube(m1)); + VERIFY_IS_APPROX(cos(m1+RealScalar(3)*m2), cos((m1+RealScalar(3)*m2).eval())); + VERIFY_IS_APPROX(m1.sign(), sign(m1)); + + + VERIFY_IS_APPROX(m1.exp() * m2.exp(), exp(m1+m2)); + VERIFY_IS_APPROX(m1.exp(), exp(m1)); + VERIFY_IS_APPROX(m1.exp() / m2.exp(),(m1-m2).exp()); + + VERIFY_IS_APPROX(sinh(m1), 0.5*(exp(m1)-exp(-m1))); + VERIFY_IS_APPROX(cosh(m1), 0.5*(exp(m1)+exp(-m1))); + VERIFY_IS_APPROX(tanh(m1), (0.5*(exp(m1)-exp(-m1)))/(0.5*(exp(m1)+exp(-m1)))); + + for (Index i = 0; i < m.rows(); ++i) + for (Index j = 0; j < m.cols(); ++j) + m3(i,j) = std::atan2(imag(m1(i,j)), real(m1(i,j))); + VERIFY_IS_APPROX(arg(m1), m3); + + std::complex zero(0.0,0.0); + VERIFY((Eigen::isnan)(m1*zero/zero).all()); +#if EIGEN_COMP_MSVC + // msvc complex division is not robust + VERIFY((Eigen::isinf)(m4/RealScalar(0)).all()); +#else +#if EIGEN_COMP_CLANG + // clang's complex division is notoriously broken too + if((numext::isinf)(m4(0,0)/RealScalar(0))) { +#endif + VERIFY((Eigen::isinf)(m4/zero).all()); +#if EIGEN_COMP_CLANG + } + else + { + VERIFY((Eigen::isinf)(m4.real()/zero.real()).all()); + } +#endif +#endif // MSVC + + VERIFY(((Eigen::isfinite)(m1) && (!(Eigen::isfinite)(m1*zero/zero)) && (!(Eigen::isfinite)(m1/zero))).all()); + + VERIFY_IS_APPROX(inverse(inverse(m1)),m1); + VERIFY_IS_APPROX(conj(m1.conjugate()), m1); + VERIFY_IS_APPROX(abs(m1), sqrt(square(real(m1))+square(imag(m1)))); + VERIFY_IS_APPROX(abs(m1), sqrt(abs2(m1))); + VERIFY_IS_APPROX(log10(m1), log(m1)/log(10)); + + VERIFY_IS_APPROX( m1.sign(), -(-m1).sign() ); + VERIFY_IS_APPROX( m1.sign() * m1.abs(), m1); + + // scalar by array division + Scalar s1 = internal::random(); + const RealScalar tiny = std::sqrt(std::numeric_limits::epsilon()); + s1 += Scalar(tiny); + m1 += ArrayType::Constant(rows,cols,Scalar(tiny)); + VERIFY_IS_APPROX(s1/m1, s1 * m1.inverse()); + + // check inplace transpose + m2 = m1; + m2.transposeInPlace(); + VERIFY_IS_APPROX(m2, m1.transpose()); + m2.transposeInPlace(); + VERIFY_IS_APPROX(m2, m1); + } template void min_max(const ArrayType& m) @@ -301,7 +488,7 @@ void test_array() VERIFY((internal::is_same< internal::global_math_functions_filtering_base::type, int >::value)); VERIFY((internal::is_same< internal::global_math_functions_filtering_base::type, float >::value)); VERIFY((internal::is_same< internal::global_math_functions_filtering_base::type, ArrayBase >::value)); - typedef CwiseUnaryOp, ArrayXd > Xpr; + typedef CwiseUnaryOp, ArrayXd > Xpr; VERIFY((internal::is_same< internal::global_math_functions_filtering_base::type, ArrayBase >::value)); diff --git a/ground/gcs/src/libs/eigen/test/array_for_matrix.cpp b/ground/gcs/src/libs/eigen/test/array_for_matrix.cpp index 9667e1f143..c1501947b9 100644 --- a/ground/gcs/src/libs/eigen/test/array_for_matrix.cpp +++ b/ground/gcs/src/libs/eigen/test/array_for_matrix.cpp @@ -45,7 +45,7 @@ template void array_for_matrix(const MatrixType& m) VERIFY_IS_MUCH_SMALLER_THAN(m1.rowwise().sum().sum() - m1.sum(), m1.squaredNorm()); VERIFY_IS_MUCH_SMALLER_THAN(m1.colwise().sum() + m2.colwise().sum() - (m1+m2).colwise().sum(), (m1+m2).squaredNorm()); VERIFY_IS_MUCH_SMALLER_THAN(m1.rowwise().sum() - m2.rowwise().sum() - (m1-m2).rowwise().sum(), (m1-m2).squaredNorm()); - VERIFY_IS_APPROX(m1.colwise().sum(), m1.colwise().redux(internal::scalar_sum_op())); + VERIFY_IS_APPROX(m1.colwise().sum(), m1.colwise().redux(internal::scalar_sum_op())); // vector-wise ops m3 = m1; @@ -68,6 +68,16 @@ template void array_for_matrix(const MatrixType& m) const Scalar& ref_a2 = m.array().matrix().coeffRef(0,0); VERIFY(&ref_a1 == &ref_m1); VERIFY(&ref_a2 == &ref_m2); + + // Check write accessors: + m1.array().coeffRef(0,0) = 1; + VERIFY_IS_APPROX(m1(0,0),Scalar(1)); + m1.array()(0,0) = 2; + VERIFY_IS_APPROX(m1(0,0),Scalar(2)); + m1.array().matrix().coeffRef(0,0) = 3; + VERIFY_IS_APPROX(m1(0,0),Scalar(3)); + m1.array().matrix()(0,0) = 4; + VERIFY_IS_APPROX(m1(0,0),Scalar(4)); } template void comparisons(const MatrixType& m) @@ -124,6 +134,12 @@ template void comparisons(const MatrixType& m) // count VERIFY(((m1.array().abs()+1)>RealScalar(0.1)).count() == rows*cols); + // and/or + VERIFY( ((m1.array()RealScalar(0)).matrix()).count() == 0); + VERIFY( ((m1.array()=RealScalar(0)).matrix()).count() == rows*cols); + RealScalar a = m1.cwiseAbs().mean(); + VERIFY( ((m1.array()<-a).matrix() || (m1.array()>a).matrix()).count() == (m1.cwiseAbs().array()>a).count()); + typedef Matrix VectorOfIndices; // TODO allows colwise/rowwise for array @@ -134,9 +150,21 @@ template void comparisons(const MatrixType& m) template void lpNorm(const VectorType& v) { using std::sqrt; + typedef typename VectorType::RealScalar RealScalar; VectorType u = VectorType::Random(v.size()); - VERIFY_IS_APPROX(u.template lpNorm(), u.cwiseAbs().maxCoeff()); + if(v.size()==0) + { + VERIFY_IS_APPROX(u.template lpNorm(), RealScalar(0)); + VERIFY_IS_APPROX(u.template lpNorm<1>(), RealScalar(0)); + VERIFY_IS_APPROX(u.template lpNorm<2>(), RealScalar(0)); + VERIFY_IS_APPROX(u.template lpNorm<5>(), RealScalar(0)); + } + else + { + VERIFY_IS_APPROX(u.template lpNorm(), u.cwiseAbs().maxCoeff()); + } + VERIFY_IS_APPROX(u.template lpNorm<1>(), u.cwiseAbs().sum()); VERIFY_IS_APPROX(u.template lpNorm<2>(), sqrt(u.array().abs().square().sum())); VERIFY_IS_APPROX(numext::pow(u.template lpNorm<5>(), typename VectorType::RealScalar(5)), u.array().abs().pow(5).sum()); @@ -245,6 +273,8 @@ void test_array_for_matrix() CALL_SUBTEST_5( lpNorm(VectorXf(internal::random(1,EIGEN_TEST_MAX_SIZE))) ); CALL_SUBTEST_4( lpNorm(VectorXcf(internal::random(1,EIGEN_TEST_MAX_SIZE))) ); } + CALL_SUBTEST_5( lpNorm(VectorXf(0)) ); + CALL_SUBTEST_4( lpNorm(VectorXcf(0)) ); for(int i = 0; i < g_repeat; i++) { CALL_SUBTEST_4( resize(MatrixXcf(internal::random(1,EIGEN_TEST_MAX_SIZE), internal::random(1,EIGEN_TEST_MAX_SIZE))) ); CALL_SUBTEST_5( resize(MatrixXf(internal::random(1,EIGEN_TEST_MAX_SIZE), internal::random(1,EIGEN_TEST_MAX_SIZE))) ); diff --git a/ground/gcs/src/libs/eigen/test/array_of_string.cpp b/ground/gcs/src/libs/eigen/test/array_of_string.cpp new file mode 100644 index 0000000000..e23b7c59e6 --- /dev/null +++ b/ground/gcs/src/libs/eigen/test/array_of_string.cpp @@ -0,0 +1,32 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2016 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "main.h" + +void test_array_of_string() +{ + typedef Array ArrayXs; + ArrayXs a1(3), a2(3), a3(3), a3ref(3); + a1 << "one", "two", "three"; + a2 << "1", "2", "3"; + a3ref << "one (1)", "two (2)", "three (3)"; + std::stringstream s1; + s1 << a1; + VERIFY_IS_EQUAL(s1.str(), std::string(" one two three")); + a3 = a1 + std::string(" (") + a2 + std::string(")"); + VERIFY((a3==a3ref).all()); + + a3 = a1; + a3 += std::string(" (") + a2 + std::string(")"); + VERIFY((a3==a3ref).all()); + + a1.swap(a3); + VERIFY((a1==a3ref).all()); + VERIFY((a3!=a3ref).all()); +} diff --git a/ground/gcs/src/libs/eigen/test/array_replicate.cpp b/ground/gcs/src/libs/eigen/test/array_replicate.cpp index f412d1aed7..779c8fc2f7 100644 --- a/ground/gcs/src/libs/eigen/test/array_replicate.cpp +++ b/ground/gcs/src/libs/eigen/test/array_replicate.cpp @@ -44,6 +44,19 @@ template void replicate(const MatrixType& m) x2 << m2, m2, m2, m2, m2, m2; VERIFY_IS_APPROX(x2, (m2.template replicate<2,3>())); + + x2.resize(rows,3*cols); + x2 << m2, m2, m2; + VERIFY_IS_APPROX(x2, (m2.template replicate<1,3>())); + + vx1.resize(3*rows,cols); + vx1 << m2, m2, m2; + VERIFY_IS_APPROX(vx1+vx1, vx1+(m2.template replicate<3,1>())); + + vx1=m2+(m2.colwise().replicate(1)); + + if(m2.cols()==1) + VERIFY_IS_APPROX(m2.coeff(0), (m2.template replicate<3,1>().coeff(m2.rows()))); x2.resize(rows,f1); for (int j=0; j void reverse(const MatrixType& m) // this test relies a lot on Random.h, and there's not much more that we can do // to test it, hence I consider that we will have tested Random.h - MatrixType m1 = MatrixType::Random(rows, cols); + MatrixType m1 = MatrixType::Random(rows, cols), m2; VectorType v1 = VectorType::Random(rows); MatrixType m1_r = m1.reverse(); @@ -96,14 +96,32 @@ template void reverse(const MatrixType& m) m1.reverse()(r, c) = x; VERIFY_IS_APPROX(x, m1(rows - 1 - r, cols - 1 - c)); + + m2 = m1; + m2.reverseInPlace(); + VERIFY_IS_APPROX(m2,m1.reverse().eval()); + + m2 = m1; + m2.col(0).reverseInPlace(); + VERIFY_IS_APPROX(m2.col(0),m1.col(0).reverse().eval()); + + m2 = m1; + m2.row(0).reverseInPlace(); + VERIFY_IS_APPROX(m2.row(0),m1.row(0).reverse().eval()); + + m2 = m1; + m2.rowwise().reverseInPlace(); + VERIFY_IS_APPROX(m2,m1.rowwise().reverse().eval()); + + m2 = m1; + m2.colwise().reverseInPlace(); + VERIFY_IS_APPROX(m2,m1.colwise().reverse().eval()); - /* m1.colwise().reverse()(r, c) = x; VERIFY_IS_APPROX(x, m1(rows - 1 - r, c)); m1.rowwise().reverse()(r, c) = x; VERIFY_IS_APPROX(x, m1(r, cols - 1 - c)); - */ } void test_array_reverse() @@ -113,11 +131,11 @@ void test_array_reverse() CALL_SUBTEST_2( reverse(Matrix2f()) ); CALL_SUBTEST_3( reverse(Matrix4f()) ); CALL_SUBTEST_4( reverse(Matrix4d()) ); - CALL_SUBTEST_5( reverse(MatrixXcf(3, 3)) ); - CALL_SUBTEST_6( reverse(MatrixXi(6, 3)) ); - CALL_SUBTEST_7( reverse(MatrixXcd(20, 20)) ); + CALL_SUBTEST_5( reverse(MatrixXcf(internal::random(1,EIGEN_TEST_MAX_SIZE), internal::random(1,EIGEN_TEST_MAX_SIZE))) ); + CALL_SUBTEST_6( reverse(MatrixXi(internal::random(1,EIGEN_TEST_MAX_SIZE), internal::random(1,EIGEN_TEST_MAX_SIZE))) ); + CALL_SUBTEST_7( reverse(MatrixXcd(internal::random(1,EIGEN_TEST_MAX_SIZE), internal::random(1,EIGEN_TEST_MAX_SIZE))) ); CALL_SUBTEST_8( reverse(Matrix()) ); - CALL_SUBTEST_9( reverse(Matrix(6,3)) ); + CALL_SUBTEST_9( reverse(Matrix(internal::random(1,EIGEN_TEST_MAX_SIZE), internal::random(1,EIGEN_TEST_MAX_SIZE))) ); } #ifdef EIGEN_TEST_PART_3 Vector4f x; x << 1, 2, 3, 4; diff --git a/ground/gcs/src/libs/eigen/test/bandmatrix.cpp b/ground/gcs/src/libs/eigen/test/bandmatrix.cpp index 5e4e8e07b1..f8c38f7c31 100644 --- a/ground/gcs/src/libs/eigen/test/bandmatrix.cpp +++ b/ground/gcs/src/libs/eigen/test/bandmatrix.cpp @@ -11,7 +11,6 @@ template void bandmatrix(const MatrixType& _m) { - typedef typename MatrixType::Index Index; typedef typename MatrixType::Scalar Scalar; typedef typename NumTraits::Real RealScalar; typedef Matrix DenseMatrixType; @@ -62,8 +61,6 @@ using Eigen::internal::BandMatrix; void test_bandmatrix() { - typedef BandMatrix::Index Index; - for(int i = 0; i < 10*g_repeat ; i++) { Index rows = internal::random(1,10); Index cols = internal::random(1,10); diff --git a/ground/gcs/src/libs/eigen/test/basicstuff.cpp b/ground/gcs/src/libs/eigen/test/basicstuff.cpp index 8c0621ecd2..99d91f9daf 100644 --- a/ground/gcs/src/libs/eigen/test/basicstuff.cpp +++ b/ground/gcs/src/libs/eigen/test/basicstuff.cpp @@ -126,6 +126,20 @@ template void basicStuff(const MatrixType& m) for(typename MatrixType::Index i=0;i(0,10)>5; + m3 = b ? m1 : m2; + if(b) VERIFY_IS_APPROX(m3,m1); + else VERIFY_IS_APPROX(m3,m2); + m3 = b ? -m1 : m2; + if(b) VERIFY_IS_APPROX(m3,-m1); + else VERIFY_IS_APPROX(m3,m2); + m3 = b ? m1 : -m2; + if(b) VERIFY_IS_APPROX(m3,m1); + else VERIFY_IS_APPROX(m3,-m2); + } } template void basicStuffComplex(const MatrixType& m) @@ -180,15 +194,64 @@ void casting() template void fixedSizeMatrixConstruction() { - const Scalar raw[3] = {1,2,3}; - Matrix m(raw); - Array a(raw); - VERIFY(m(0) == 1); - VERIFY(m(1) == 2); - VERIFY(m(2) == 3); - VERIFY(a(0) == 1); - VERIFY(a(1) == 2); - VERIFY(a(2) == 3); + Scalar raw[4]; + for(int k=0; k<4; ++k) + raw[k] = internal::random(); + + { + Matrix m(raw); + Array a(raw); + for(int k=0; k<4; ++k) VERIFY(m(k) == raw[k]); + for(int k=0; k<4; ++k) VERIFY(a(k) == raw[k]); + VERIFY_IS_EQUAL(m,(Matrix(raw[0],raw[1],raw[2],raw[3]))); + VERIFY((a==(Array(raw[0],raw[1],raw[2],raw[3]))).all()); + } + { + Matrix m(raw); + Array a(raw); + for(int k=0; k<3; ++k) VERIFY(m(k) == raw[k]); + for(int k=0; k<3; ++k) VERIFY(a(k) == raw[k]); + VERIFY_IS_EQUAL(m,(Matrix(raw[0],raw[1],raw[2]))); + VERIFY((a==Array(raw[0],raw[1],raw[2])).all()); + } + { + Matrix m(raw), m2( (DenseIndex(raw[0])), (DenseIndex(raw[1])) ); + Array a(raw), a2( (DenseIndex(raw[0])), (DenseIndex(raw[1])) ); + for(int k=0; k<2; ++k) VERIFY(m(k) == raw[k]); + for(int k=0; k<2; ++k) VERIFY(a(k) == raw[k]); + VERIFY_IS_EQUAL(m,(Matrix(raw[0],raw[1]))); + VERIFY((a==Array(raw[0],raw[1])).all()); + for(int k=0; k<2; ++k) VERIFY(m2(k) == DenseIndex(raw[k])); + for(int k=0; k<2; ++k) VERIFY(a2(k) == DenseIndex(raw[k])); + } + { + Matrix m(raw), + m2( (DenseIndex(raw[0])), (DenseIndex(raw[1])) ), + m3( (int(raw[0])), (int(raw[1])) ), + m4( (float(raw[0])), (float(raw[1])) ); + Array a(raw), a2( (DenseIndex(raw[0])), (DenseIndex(raw[1])) ); + for(int k=0; k<2; ++k) VERIFY(m(k) == raw[k]); + for(int k=0; k<2; ++k) VERIFY(a(k) == raw[k]); + VERIFY_IS_EQUAL(m,(Matrix(raw[0],raw[1]))); + VERIFY((a==Array(raw[0],raw[1])).all()); + for(int k=0; k<2; ++k) VERIFY(m2(k) == DenseIndex(raw[k])); + for(int k=0; k<2; ++k) VERIFY(a2(k) == DenseIndex(raw[k])); + for(int k=0; k<2; ++k) VERIFY(m3(k) == int(raw[k])); + for(int k=0; k<2; ++k) VERIFY((m4(k)) == Scalar(float(raw[k]))); + } + { + Matrix m(raw), m1(raw[0]), m2( (DenseIndex(raw[0])) ), m3( (int(raw[0])) ); + Array a(raw), a1(raw[0]), a2( (DenseIndex(raw[0])) ); + VERIFY(m(0) == raw[0]); + VERIFY(a(0) == raw[0]); + VERIFY(m1(0) == raw[0]); + VERIFY(a1(0) == raw[0]); + VERIFY(m2(0) == DenseIndex(raw[0])); + VERIFY(a2(0) == DenseIndex(raw[0])); + VERIFY(m3(0) == int(raw[0])); + VERIFY_IS_EQUAL(m,(Matrix(raw[0]))); + VERIFY((a==Array(raw[0])).all()); + } } void test_basicstuff() @@ -207,8 +270,11 @@ void test_basicstuff() } CALL_SUBTEST_1(fixedSizeMatrixConstruction()); + CALL_SUBTEST_1(fixedSizeMatrixConstruction()); CALL_SUBTEST_1(fixedSizeMatrixConstruction()); - CALL_SUBTEST_1(fixedSizeMatrixConstruction()); + CALL_SUBTEST_1(fixedSizeMatrixConstruction()); + CALL_SUBTEST_1(fixedSizeMatrixConstruction()); + CALL_SUBTEST_1(fixedSizeMatrixConstruction()); CALL_SUBTEST_2(casting()); } diff --git a/ground/gcs/src/libs/eigen/test/bdcsvd.cpp b/ground/gcs/src/libs/eigen/test/bdcsvd.cpp new file mode 100644 index 0000000000..f9f687aacd --- /dev/null +++ b/ground/gcs/src/libs/eigen/test/bdcsvd.cpp @@ -0,0 +1,111 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2013 Gauthier Brun +// Copyright (C) 2013 Nicolas Carre +// Copyright (C) 2013 Jean Ceccato +// Copyright (C) 2013 Pierre Zoppitelli +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/ + +// discard stack allocation as that too bypasses malloc +#define EIGEN_STACK_ALLOCATION_LIMIT 0 +#define EIGEN_RUNTIME_NO_MALLOC + +#include "main.h" +#include +#include +#include + + +#define SVD_DEFAULT(M) BDCSVD +#define SVD_FOR_MIN_NORM(M) BDCSVD +#include "svd_common.h" + +// Check all variants of JacobiSVD +template +void bdcsvd(const MatrixType& a = MatrixType(), bool pickrandom = true) +{ + MatrixType m = a; + if(pickrandom) + svd_fill_random(m); + + CALL_SUBTEST(( svd_test_all_computation_options >(m, false) )); +} + +template +void bdcsvd_method() +{ + enum { Size = MatrixType::RowsAtCompileTime }; + typedef typename MatrixType::RealScalar RealScalar; + typedef Matrix RealVecType; + MatrixType m = MatrixType::Identity(); + VERIFY_IS_APPROX(m.bdcSvd().singularValues(), RealVecType::Ones()); + VERIFY_RAISES_ASSERT(m.bdcSvd().matrixU()); + VERIFY_RAISES_ASSERT(m.bdcSvd().matrixV()); + VERIFY_IS_APPROX(m.bdcSvd(ComputeFullU|ComputeFullV).solve(m), m); +} + +// compare the Singular values returned with Jacobi and Bdc +template +void compare_bdc_jacobi(const MatrixType& a = MatrixType(), unsigned int computationOptions = 0) +{ + MatrixType m = MatrixType::Random(a.rows(), a.cols()); + BDCSVD bdc_svd(m); + JacobiSVD jacobi_svd(m); + VERIFY_IS_APPROX(bdc_svd.singularValues(), jacobi_svd.singularValues()); + if(computationOptions & ComputeFullU) VERIFY_IS_APPROX(bdc_svd.matrixU(), jacobi_svd.matrixU()); + if(computationOptions & ComputeThinU) VERIFY_IS_APPROX(bdc_svd.matrixU(), jacobi_svd.matrixU()); + if(computationOptions & ComputeFullV) VERIFY_IS_APPROX(bdc_svd.matrixV(), jacobi_svd.matrixV()); + if(computationOptions & ComputeThinV) VERIFY_IS_APPROX(bdc_svd.matrixV(), jacobi_svd.matrixV()); +} + +void test_bdcsvd() +{ + CALL_SUBTEST_3(( svd_verify_assert >(Matrix3f()) )); + CALL_SUBTEST_4(( svd_verify_assert >(Matrix4d()) )); + CALL_SUBTEST_7(( svd_verify_assert >(MatrixXf(10,12)) )); + CALL_SUBTEST_8(( svd_verify_assert >(MatrixXcd(7,5)) )); + + CALL_SUBTEST_101(( svd_all_trivial_2x2(bdcsvd) )); + CALL_SUBTEST_102(( svd_all_trivial_2x2(bdcsvd) )); + + for(int i = 0; i < g_repeat; i++) { + CALL_SUBTEST_3(( bdcsvd() )); + CALL_SUBTEST_4(( bdcsvd() )); + CALL_SUBTEST_5(( bdcsvd >() )); + + int r = internal::random(1, EIGEN_TEST_MAX_SIZE/2), + c = internal::random(1, EIGEN_TEST_MAX_SIZE/2); + + TEST_SET_BUT_UNUSED_VARIABLE(r) + TEST_SET_BUT_UNUSED_VARIABLE(c) + + CALL_SUBTEST_6(( bdcsvd(Matrix(r,2)) )); + CALL_SUBTEST_7(( bdcsvd(MatrixXf(r,c)) )); + CALL_SUBTEST_7(( compare_bdc_jacobi(MatrixXf(r,c)) )); + CALL_SUBTEST_10(( bdcsvd(MatrixXd(r,c)) )); + CALL_SUBTEST_10(( compare_bdc_jacobi(MatrixXd(r,c)) )); + CALL_SUBTEST_8(( bdcsvd(MatrixXcd(r,c)) )); + CALL_SUBTEST_8(( compare_bdc_jacobi(MatrixXcd(r,c)) )); + + // Test on inf/nan matrix + CALL_SUBTEST_7( (svd_inf_nan, MatrixXf>()) ); + CALL_SUBTEST_10( (svd_inf_nan, MatrixXd>()) ); + } + + // test matrixbase method + CALL_SUBTEST_1(( bdcsvd_method() )); + CALL_SUBTEST_3(( bdcsvd_method() )); + + // Test problem size constructors + CALL_SUBTEST_7( BDCSVD(10,10) ); + + // Check that preallocation avoids subsequent mallocs + CALL_SUBTEST_9( svd_preallocate() ); + + CALL_SUBTEST_2( svd_underoverflow() ); +} + diff --git a/ground/gcs/src/libs/eigen/test/bicgstab.cpp b/ground/gcs/src/libs/eigen/test/bicgstab.cpp index f327e2facf..4cc0dd31cf 100644 --- a/ground/gcs/src/libs/eigen/test/bicgstab.cpp +++ b/ground/gcs/src/libs/eigen/test/bicgstab.cpp @@ -10,13 +10,16 @@ #include "sparse_solver.h" #include -template void test_bicgstab_T() +template void test_bicgstab_T() { - BiCGSTAB, DiagonalPreconditioner > bicgstab_colmajor_diag; - BiCGSTAB, IdentityPreconditioner > bicgstab_colmajor_I; - BiCGSTAB, IncompleteLUT > bicgstab_colmajor_ilut; + BiCGSTAB, DiagonalPreconditioner > bicgstab_colmajor_diag; + BiCGSTAB, IdentityPreconditioner > bicgstab_colmajor_I; + BiCGSTAB, IncompleteLUT > bicgstab_colmajor_ilut; //BiCGSTAB, SSORPreconditioner > bicgstab_colmajor_ssor; + bicgstab_colmajor_diag.setTolerance(NumTraits::epsilon()*4); + bicgstab_colmajor_ilut.setTolerance(NumTraits::epsilon()*4); + CALL_SUBTEST( check_sparse_square_solving(bicgstab_colmajor_diag) ); // CALL_SUBTEST( check_sparse_square_solving(bicgstab_colmajor_I) ); CALL_SUBTEST( check_sparse_square_solving(bicgstab_colmajor_ilut) ); @@ -25,6 +28,7 @@ template void test_bicgstab_T() void test_bicgstab() { - CALL_SUBTEST_1(test_bicgstab_T()); - CALL_SUBTEST_2(test_bicgstab_T >()); + CALL_SUBTEST_1((test_bicgstab_T()) ); + CALL_SUBTEST_2((test_bicgstab_T, int>())); + CALL_SUBTEST_3((test_bicgstab_T())); } diff --git a/ground/gcs/src/libs/eigen/test/block.cpp b/ground/gcs/src/libs/eigen/test/block.cpp index 9ed5d7bc5e..39565af831 100644 --- a/ground/gcs/src/libs/eigen/test/block.cpp +++ b/ground/gcs/src/libs/eigen/test/block.cpp @@ -130,6 +130,14 @@ template void block(const MatrixType& m) VERIFY(numext::real(ones.col(c1).dot(ones.col(c2))) == RealScalar(rows)); VERIFY(numext::real(ones.row(r1).dot(ones.row(r2))) == RealScalar(cols)); + + // chekc that linear acccessors works on blocks + m1 = m1_copy; + if((MatrixType::Flags&RowMajorBit)==0) + VERIFY_IS_EQUAL(m1.leftCols(c1).coeff(r1+c1*rows), m1(r1,c1)); + else + VERIFY_IS_EQUAL(m1.topRows(r1).coeff(c1+r1*cols), m1(r1,c1)); + // now test some block-inside-of-block. @@ -141,11 +149,11 @@ template void block(const MatrixType& m) VERIFY_IS_EQUAL( (m1.transpose().block(c1,r1,c2-c1+1,r2-r1+1).col(0)) , (m1.row(r1).segment(c1,c2-c1+1)).transpose() ); // expressions without direct access - VERIFY_IS_EQUAL( ((m1+m2).block(r1,c1,rows-r1,cols-c1).block(r2-r1,c2-c1,rows-r2,cols-c2)) , ((m1+m2).block(r2,c2,rows-r2,cols-c2)) ); - VERIFY_IS_EQUAL( ((m1+m2).block(r1,c1,r2-r1+1,c2-c1+1).row(0)) , ((m1+m2).row(r1).segment(c1,c2-c1+1)) ); - VERIFY_IS_EQUAL( ((m1+m2).block(r1,c1,r2-r1+1,c2-c1+1).col(0)) , ((m1+m2).col(c1).segment(r1,r2-r1+1)) ); - VERIFY_IS_EQUAL( ((m1+m2).block(r1,c1,r2-r1+1,c2-c1+1).transpose().col(0)) , ((m1+m2).row(r1).segment(c1,c2-c1+1)).transpose() ); - VERIFY_IS_EQUAL( ((m1+m2).transpose().block(c1,r1,c2-c1+1,r2-r1+1).col(0)) , ((m1+m2).row(r1).segment(c1,c2-c1+1)).transpose() ); + VERIFY_IS_APPROX( ((m1+m2).block(r1,c1,rows-r1,cols-c1).block(r2-r1,c2-c1,rows-r2,cols-c2)) , ((m1+m2).block(r2,c2,rows-r2,cols-c2)) ); + VERIFY_IS_APPROX( ((m1+m2).block(r1,c1,r2-r1+1,c2-c1+1).row(0)) , ((m1+m2).row(r1).segment(c1,c2-c1+1)) ); + VERIFY_IS_APPROX( ((m1+m2).block(r1,c1,r2-r1+1,c2-c1+1).col(0)) , ((m1+m2).col(c1).segment(r1,r2-r1+1)) ); + VERIFY_IS_APPROX( ((m1+m2).block(r1,c1,r2-r1+1,c2-c1+1).transpose().col(0)) , ((m1+m2).row(r1).segment(c1,c2-c1+1)).transpose() ); + VERIFY_IS_APPROX( ((m1+m2).transpose().block(c1,r1,c2-c1+1,r2-r1+1).col(0)) , ((m1+m2).row(r1).segment(c1,c2-c1+1)).transpose() ); // evaluation into plain matrices from expressions with direct access (stress MapBase) DynamicMatrixType dm; @@ -173,6 +181,19 @@ template void block(const MatrixType& m) dm = m1.row(r1).segment(c1,c2-c1+1).transpose(); dv = m1.transpose().block(c1,r1,c2-c1+1,r2-r1+1).col(0); VERIFY_IS_EQUAL(dv, dm); + + VERIFY_IS_EQUAL( (m1.template block(1,0,0,1)), m1.block(1,0,0,1)); + VERIFY_IS_EQUAL( (m1.template block<1,Dynamic>(0,1,1,0)), m1.block(0,1,1,0)); + VERIFY_IS_EQUAL( ((m1*1).template block(1,0,0,1)), m1.block(1,0,0,1)); + VERIFY_IS_EQUAL( ((m1*1).template block<1,Dynamic>(0,1,1,0)), m1.block(0,1,1,0)); + + if (rows>=2 && cols>=2) + { + VERIFY_RAISES_ASSERT( m1 += m1.col(0) ); + VERIFY_RAISES_ASSERT( m1 -= m1.col(0) ); + VERIFY_RAISES_ASSERT( m1.array() *= m1.col(0).array() ); + VERIFY_RAISES_ASSERT( m1.array() /= m1.col(0).array() ); + } } diff --git a/ground/gcs/src/libs/eigen/test/boostmultiprec.cpp b/ground/gcs/src/libs/eigen/test/boostmultiprec.cpp new file mode 100644 index 0000000000..e06e9bdaf6 --- /dev/null +++ b/ground/gcs/src/libs/eigen/test/boostmultiprec.cpp @@ -0,0 +1,201 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2016 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include + +#ifdef EIGEN_TEST_MAX_SIZE +#undef EIGEN_TEST_MAX_SIZE +#endif + +#define EIGEN_TEST_MAX_SIZE 50 + +#ifdef EIGEN_TEST_PART_1 +#include "cholesky.cpp" +#endif + +#ifdef EIGEN_TEST_PART_2 +#include "lu.cpp" +#endif + +#ifdef EIGEN_TEST_PART_3 +#include "qr.cpp" +#endif + +#ifdef EIGEN_TEST_PART_4 +#include "qr_colpivoting.cpp" +#endif + +#ifdef EIGEN_TEST_PART_5 +#include "qr_fullpivoting.cpp" +#endif + +#ifdef EIGEN_TEST_PART_6 +#include "eigensolver_selfadjoint.cpp" +#endif + +#ifdef EIGEN_TEST_PART_7 +#include "eigensolver_generic.cpp" +#endif + +#ifdef EIGEN_TEST_PART_8 +#include "eigensolver_generalized_real.cpp" +#endif + +#ifdef EIGEN_TEST_PART_9 +#include "jacobisvd.cpp" +#endif + +#ifdef EIGEN_TEST_PART_10 +#include "bdcsvd.cpp" +#endif + +#include + +#undef min +#undef max +#undef isnan +#undef isinf +#undef isfinite + +#include +#include +#include +#include + +namespace mp = boost::multiprecision; +typedef mp::number, mp::et_on> Real; + +namespace Eigen { + template<> struct NumTraits : GenericNumTraits { + static inline Real dummy_precision() { return 1e-50; } + }; + + template + struct NumTraits > : NumTraits {}; + + template<> + Real test_precision() { return 1e-50; } + + // needed in C++93 mode where number does not support explicit cast. + namespace internal { + template + struct cast_impl { + static inline NewType run(const Real& x) { + return x.template convert_to(); + } + }; + + template<> + struct cast_impl > { + static inline std::complex run(const Real& x) { + return std::complex(x); + } + }; + } +} + +namespace boost { +namespace multiprecision { + // to make ADL works as expected: + using boost::math::isfinite; + using boost::math::isnan; + using boost::math::isinf; + using boost::math::copysign; + using boost::math::hypot; + + // The following is needed for std::complex: + Real fabs(const Real& a) { return abs EIGEN_NOT_A_MACRO (a); } + Real fmax(const Real& a, const Real& b) { using std::max; return max(a,b); } + + // some specialization for the unit tests: + inline bool test_isMuchSmallerThan(const Real& a, const Real& b) { + return internal::isMuchSmallerThan(a, b, test_precision()); + } + + inline bool test_isApprox(const Real& a, const Real& b) { + return internal::isApprox(a, b, test_precision()); + } + + inline bool test_isApproxOrLessThan(const Real& a, const Real& b) { + return internal::isApproxOrLessThan(a, b, test_precision()); + } + + Real get_test_precision(const Real&) { + return test_precision(); + } + + Real test_relative_error(const Real &a, const Real &b) { + using Eigen::numext::abs2; + return sqrt(abs2(a-b)/Eigen::numext::mini(abs2(a),abs2(b))); + } +} +} + +namespace Eigen { + +} + +void test_boostmultiprec() +{ + typedef Matrix Mat; + typedef Matrix,Dynamic,Dynamic> MatC; + + std::cout << "NumTraits::epsilon() = " << NumTraits::epsilon() << std::endl; + std::cout << "NumTraits::dummy_precision() = " << NumTraits::dummy_precision() << std::endl; + std::cout << "NumTraits::lowest() = " << NumTraits::lowest() << std::endl; + std::cout << "NumTraits::highest() = " << NumTraits::highest() << std::endl; + std::cout << "NumTraits::digits10() = " << NumTraits::digits10() << std::endl; + + // chekc stream output + { + Mat A(10,10); + A.setRandom(); + std::stringstream ss; + ss << A; + } + { + MatC A(10,10); + A.setRandom(); + std::stringstream ss; + ss << A; + } + + for(int i = 0; i < g_repeat; i++) { + int s = internal::random(1,EIGEN_TEST_MAX_SIZE); + + CALL_SUBTEST_1( cholesky(Mat(s,s)) ); + + CALL_SUBTEST_2( lu_non_invertible() ); + CALL_SUBTEST_2( lu_invertible() ); + CALL_SUBTEST_2( lu_non_invertible() ); + CALL_SUBTEST_2( lu_invertible() ); + + CALL_SUBTEST_3( qr(Mat(internal::random(1,EIGEN_TEST_MAX_SIZE),internal::random(1,EIGEN_TEST_MAX_SIZE))) ); + CALL_SUBTEST_3( qr_invertible() ); + + CALL_SUBTEST_4( qr() ); + CALL_SUBTEST_4( cod() ); + CALL_SUBTEST_4( qr_invertible() ); + + CALL_SUBTEST_5( qr() ); + CALL_SUBTEST_5( qr_invertible() ); + + CALL_SUBTEST_6( selfadjointeigensolver(Mat(s,s)) ); + + CALL_SUBTEST_7( eigensolver(Mat(s,s)) ); + + CALL_SUBTEST_8( generalized_eigensolver_real(Mat(s,s)) ); + + TEST_SET_BUT_UNUSED_VARIABLE(s) + } + + CALL_SUBTEST_9(( jacobisvd(Mat(internal::random(EIGEN_TEST_MAX_SIZE/4, EIGEN_TEST_MAX_SIZE), internal::random(EIGEN_TEST_MAX_SIZE/4, EIGEN_TEST_MAX_SIZE/2))) )); + CALL_SUBTEST_10(( bdcsvd(Mat(internal::random(EIGEN_TEST_MAX_SIZE/4, EIGEN_TEST_MAX_SIZE), internal::random(EIGEN_TEST_MAX_SIZE/4, EIGEN_TEST_MAX_SIZE/2))) )); +} + diff --git a/ground/gcs/src/libs/eigen/test/bug1213.cpp b/ground/gcs/src/libs/eigen/test/bug1213.cpp new file mode 100644 index 0000000000..581760c1a6 --- /dev/null +++ b/ground/gcs/src/libs/eigen/test/bug1213.cpp @@ -0,0 +1,13 @@ + +// This anonymous enum is essential to trigger the linking issue +enum { + Foo +}; + +#include "bug1213.h" + +bool bug1213_1(const Eigen::Vector3f& x) +{ + return bug1213_2(x); +} + diff --git a/ground/gcs/src/libs/eigen/test/bug1213.h b/ground/gcs/src/libs/eigen/test/bug1213.h new file mode 100644 index 0000000000..040e5a470d --- /dev/null +++ b/ground/gcs/src/libs/eigen/test/bug1213.h @@ -0,0 +1,8 @@ + +#include + +template +bool bug1213_2(const Eigen::Matrix& x); + +bool bug1213_1(const Eigen::Vector3f& x); + diff --git a/ground/gcs/src/libs/eigen/test/bug1213_main.cpp b/ground/gcs/src/libs/eigen/test/bug1213_main.cpp new file mode 100644 index 0000000000..4802c00032 --- /dev/null +++ b/ground/gcs/src/libs/eigen/test/bug1213_main.cpp @@ -0,0 +1,18 @@ + +// This is a regression unit regarding a weird linking issue with gcc. + +#include "bug1213.h" + +int main() +{ + return 0; +} + + +template +bool bug1213_2(const Eigen::Matrix& ) +{ + return true; +} + +template bool bug1213_2(const Eigen::Vector3f&); diff --git a/ground/gcs/src/libs/eigen/test/cholesky.cpp b/ground/gcs/src/libs/eigen/test/cholesky.cpp index 56885deb75..8ad5ac6397 100644 --- a/ground/gcs/src/libs/eigen/test/cholesky.cpp +++ b/ground/gcs/src/libs/eigen/test/cholesky.cpp @@ -11,20 +11,17 @@ #define EIGEN_NO_ASSERTION_CHECKING #endif -static int nb_temporaries; - -#define EIGEN_DENSE_STORAGE_CTOR_PLUGIN { if(size!=0) nb_temporaries++; } +#define TEST_ENABLE_TEMPORARY_TRACKING #include "main.h" #include #include -#define VERIFY_EVALUATION_COUNT(XPR,N) {\ - nb_temporaries = 0; \ - XPR; \ - if(nb_temporaries!=N) std::cerr << "nb_temporaries == " << nb_temporaries << "\n"; \ - VERIFY( (#XPR) && nb_temporaries==N ); \ - } +template +typename MatrixType::RealScalar matrix_l1_norm(const MatrixType& m) { + MatrixType symm = m.template selfadjointView(); + return symm.cwiseAbs().colwise().sum().maxCoeff(); +} template class CholType> void test_chol_update(const MatrixType& symm) { @@ -83,14 +80,10 @@ template void cholesky(const MatrixType& m) symm += a1 * a1.adjoint(); } - // to test if really Cholesky only uses the upper triangular part, uncomment the following - // FIXME: currently that fails !! - //symm.template part().setZero(); - { SquareMatrixType symmUp = symm.template triangularView(); SquareMatrixType symmLo = symm.template triangularView(); - + LLT chollo(symmLo); VERIFY_IS_APPROX(symm, chollo.reconstructedMatrix()); vecX = chollo.solve(vecB); @@ -98,6 +91,14 @@ template void cholesky(const MatrixType& m) matX = chollo.solve(matB); VERIFY_IS_APPROX(symm * matX, matB); + const MatrixType symmLo_inverse = chollo.solve(MatrixType::Identity(rows,cols)); + RealScalar rcond = (RealScalar(1) / matrix_l1_norm(symmLo)) / + matrix_l1_norm(symmLo_inverse); + RealScalar rcond_est = chollo.rcond(); + // Verify that the estimated condition number is within a factor of 10 of the + // truth. + VERIFY(rcond_est > rcond / 10 && rcond_est < rcond * 10); + // test the upper mode LLT cholup(symmUp); VERIFY_IS_APPROX(symm, cholup.reconstructedMatrix()); @@ -106,6 +107,15 @@ template void cholesky(const MatrixType& m) matX = cholup.solve(matB); VERIFY_IS_APPROX(symm * matX, matB); + // Verify that the estimated condition number is within a factor of 10 of the + // truth. + const MatrixType symmUp_inverse = cholup.solve(MatrixType::Identity(rows,cols)); + rcond = (RealScalar(1) / matrix_l1_norm(symmUp)) / + matrix_l1_norm(symmUp_inverse); + rcond_est = cholup.rcond(); + VERIFY(rcond_est > rcond / 10 && rcond_est < rcond * 10); + + MatrixType neg = -symmLo; chollo.compute(neg); VERIFY(chollo.info()==NumericalIssue); @@ -114,7 +124,7 @@ template void cholesky(const MatrixType& m) VERIFY_IS_APPROX(MatrixType(chollo.matrixU().transpose().conjugate()), MatrixType(chollo.matrixL())); VERIFY_IS_APPROX(MatrixType(cholup.matrixL().transpose().conjugate()), MatrixType(cholup.matrixU())); VERIFY_IS_APPROX(MatrixType(cholup.matrixU().transpose().conjugate()), MatrixType(cholup.matrixL())); - + // test some special use cases of SelfCwiseBinaryOp: MatrixType m1 = MatrixType::Random(rows,cols), m2(rows,cols); m2 = m1; @@ -144,19 +154,38 @@ template void cholesky(const MatrixType& m) SquareMatrixType symmLo = symm.template triangularView(); LDLT ldltlo(symmLo); + VERIFY(ldltlo.info()==Success); VERIFY_IS_APPROX(symm, ldltlo.reconstructedMatrix()); vecX = ldltlo.solve(vecB); VERIFY_IS_APPROX(symm * vecX, vecB); matX = ldltlo.solve(matB); VERIFY_IS_APPROX(symm * matX, matB); + const MatrixType symmLo_inverse = ldltlo.solve(MatrixType::Identity(rows,cols)); + RealScalar rcond = (RealScalar(1) / matrix_l1_norm(symmLo)) / + matrix_l1_norm(symmLo_inverse); + RealScalar rcond_est = ldltlo.rcond(); + // Verify that the estimated condition number is within a factor of 10 of the + // truth. + VERIFY(rcond_est > rcond / 10 && rcond_est < rcond * 10); + + LDLT ldltup(symmUp); + VERIFY(ldltup.info()==Success); VERIFY_IS_APPROX(symm, ldltup.reconstructedMatrix()); vecX = ldltup.solve(vecB); VERIFY_IS_APPROX(symm * vecX, vecB); matX = ldltup.solve(matB); VERIFY_IS_APPROX(symm * matX, matB); + // Verify that the estimated condition number is within a factor of 10 of the + // truth. + const MatrixType symmUp_inverse = ldltup.solve(MatrixType::Identity(rows,cols)); + rcond = (RealScalar(1) / matrix_l1_norm(symmUp)) / + matrix_l1_norm(symmUp_inverse); + rcond_est = ldltup.rcond(); + VERIFY(rcond_est > rcond / 10 && rcond_est < rcond * 10); + VERIFY_IS_APPROX(MatrixType(ldltlo.matrixL().transpose().conjugate()), MatrixType(ldltlo.matrixU())); VERIFY_IS_APPROX(MatrixType(ldltlo.matrixU().transpose().conjugate()), MatrixType(ldltlo.matrixL())); VERIFY_IS_APPROX(MatrixType(ldltup.matrixL().transpose().conjugate()), MatrixType(ldltup.matrixU())); @@ -185,7 +214,7 @@ template void cholesky(const MatrixType& m) if(rows>=3) { SquareMatrixType A = symm; - int c = internal::random(0,rows-2); + Index c = internal::random(0,rows-2); A.bottomRightCorner(c,c).setZero(); // Make sure a solution exists: vecX.setRandom(); @@ -196,11 +225,11 @@ template void cholesky(const MatrixType& m) vecX = ldltlo.solve(vecB); VERIFY_IS_APPROX(A * vecX, vecB); } - + // check non-full rank matrices if(rows>=3) { - int r = internal::random(1,rows-1); + Index r = internal::random(1,rows-1); Matrix a = Matrix::Random(rows,r); SquareMatrixType A = a * a.adjoint(); // Make sure a solution exists: @@ -212,15 +241,17 @@ template void cholesky(const MatrixType& m) vecX = ldltlo.solve(vecB); VERIFY_IS_APPROX(A * vecX, vecB); } - + // check matrices with a wide spectrum if(rows>=3) { + using std::pow; + using std::sqrt; RealScalar s = (std::min)(16,std::numeric_limits::max_exponent10/8); Matrix a = Matrix::Random(rows,rows); Matrix d = Matrix::Random(rows); - for(int k=0; k(-s,s)); + for(Index k=0; k(-s,s)); SquareMatrixType A = a * d.asDiagonal() * a.adjoint(); // Make sure a solution exists: vecX.setRandom(); @@ -229,7 +260,20 @@ template void cholesky(const MatrixType& m) ldltlo.compute(A); VERIFY_IS_APPROX(A, ldltlo.reconstructedMatrix()); vecX = ldltlo.solve(vecB); - VERIFY_IS_APPROX(A * vecX, vecB); + + if(ldltlo.vectorD().real().cwiseAbs().minCoeff()>RealScalar(0)) + { + VERIFY_IS_APPROX(A * vecX,vecB); + } + else + { + RealScalar large_tol = sqrt(test_precision()); + VERIFY((A * vecX).isApprox(vecB, large_tol)); + + ++g_test_level; + VERIFY_IS_APPROX(A * vecX,vecB); + --g_test_level; + } } } @@ -289,6 +333,7 @@ template void cholesky_cplx(const MatrixType& m) RealMatrixType symmLo = symm.template triangularView(); LDLT ldltlo(symmLo); + VERIFY(ldltlo.info()==Success); VERIFY_IS_APPROX(symm, ldltlo.reconstructedMatrix()); vecX = ldltlo.solve(vecB); VERIFY_IS_APPROX(symm * vecX, vecB); @@ -314,46 +359,101 @@ template void cholesky_bug241(const MatrixType& m) } // LDLT is not guaranteed to work for indefinite matrices, but happens to work fine if matrix is diagonal. -// This test checks that LDLT reports correctly that matrix is indefinite. +// This test checks that LDLT reports correctly that matrix is indefinite. // See http://forum.kde.org/viewtopic.php?f=74&t=106942 and bug 736 template void cholesky_definiteness(const MatrixType& m) { eigen_assert(m.rows() == 2 && m.cols() == 2); MatrixType mat; LDLT ldlt(2); - + { mat << 1, 0, 0, -1; ldlt.compute(mat); + VERIFY(ldlt.info()==Success); VERIFY(!ldlt.isNegative()); VERIFY(!ldlt.isPositive()); } { mat << 1, 2, 2, 1; ldlt.compute(mat); + VERIFY(ldlt.info()==Success); VERIFY(!ldlt.isNegative()); VERIFY(!ldlt.isPositive()); } { mat << 0, 0, 0, 0; ldlt.compute(mat); + VERIFY(ldlt.info()==Success); VERIFY(ldlt.isNegative()); VERIFY(ldlt.isPositive()); } { mat << 0, 0, 0, 1; ldlt.compute(mat); + VERIFY(ldlt.info()==Success); VERIFY(!ldlt.isNegative()); VERIFY(ldlt.isPositive()); } { mat << -1, 0, 0, 0; ldlt.compute(mat); + VERIFY(ldlt.info()==Success); VERIFY(ldlt.isNegative()); VERIFY(!ldlt.isPositive()); } } +template +void cholesky_faillure_cases() +{ + MatrixXd mat; + LDLT ldlt; + + { + mat.resize(2,2); + mat << 0, 1, 1, 0; + ldlt.compute(mat); + VERIFY_IS_NOT_APPROX(mat,ldlt.reconstructedMatrix()); + VERIFY(ldlt.info()==NumericalIssue); + } +#if (!EIGEN_ARCH_i386) || defined(EIGEN_VECTORIZE_SSE2) + { + mat.resize(3,3); + mat << -1, -3, 3, + -3, -8.9999999999999999999, 1, + 3, 1, 0; + ldlt.compute(mat); + VERIFY(ldlt.info()==NumericalIssue); + VERIFY_IS_NOT_APPROX(mat,ldlt.reconstructedMatrix()); + } +#endif + { + mat.resize(3,3); + mat << 1, 2, 3, + 2, 4, 1, + 3, 1, 0; + ldlt.compute(mat); + VERIFY(ldlt.info()==NumericalIssue); + VERIFY_IS_NOT_APPROX(mat,ldlt.reconstructedMatrix()); + } + + { + mat.resize(8,8); + mat << 0.1, 0, -0.1, 0, 0, 0, 1, 0, + 0, 4.24667, 0, 2.00333, 0, 0, 0, 0, + -0.1, 0, 0.2, 0, -0.1, 0, 0, 0, + 0, 2.00333, 0, 8.49333, 0, 2.00333, 0, 0, + 0, 0, -0.1, 0, 0.1, 0, 0, 1, + 0, 0, 0, 2.00333, 0, 4.24667, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 0, 0; + ldlt.compute(mat); + VERIFY(ldlt.info()==NumericalIssue); + VERIFY_IS_NOT_APPROX(mat,ldlt.reconstructedMatrix()); + } +} + template void cholesky_verify_assert() { MatrixType tmp; @@ -384,10 +484,14 @@ void test_cholesky() CALL_SUBTEST_3( cholesky_definiteness(Matrix2d()) ); CALL_SUBTEST_4( cholesky(Matrix3f()) ); CALL_SUBTEST_5( cholesky(Matrix4d()) ); + s = internal::random(1,EIGEN_TEST_MAX_SIZE); CALL_SUBTEST_2( cholesky(MatrixXd(s,s)) ); + TEST_SET_BUT_UNUSED_VARIABLE(s) + s = internal::random(1,EIGEN_TEST_MAX_SIZE/2); CALL_SUBTEST_6( cholesky_cplx(MatrixXcd(s,s)) ); + TEST_SET_BUT_UNUSED_VARIABLE(s) } CALL_SUBTEST_4( cholesky_verify_assert() ); @@ -398,7 +502,8 @@ void test_cholesky() // Test problem size constructors CALL_SUBTEST_9( LLT(10) ); CALL_SUBTEST_9( LDLT(10) ); - - TEST_SET_BUT_UNUSED_VARIABLE(s) + + CALL_SUBTEST_2( cholesky_faillure_cases() ); + TEST_SET_BUT_UNUSED_VARIABLE(nb_temporaries) } diff --git a/ground/gcs/src/libs/eigen/test/cholmod_support.cpp b/ground/gcs/src/libs/eigen/test/cholmod_support.cpp index 8f8be3c0e0..a7eda28f79 100644 --- a/ground/gcs/src/libs/eigen/test/cholmod_support.cpp +++ b/ground/gcs/src/libs/eigen/test/cholmod_support.cpp @@ -7,6 +7,7 @@ // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. +#define EIGEN_NO_DEBUG_SMALL_PRODUCT_BLOCKS #include "sparse_solver.h" #include @@ -40,13 +41,13 @@ template void test_cholmod_T() check_sparse_spd_solving(llt_colmajor_upper); check_sparse_spd_solving(ldlt_colmajor_lower); check_sparse_spd_solving(ldlt_colmajor_upper); - -// check_sparse_spd_determinant(chol_colmajor_lower); -// check_sparse_spd_determinant(chol_colmajor_upper); -// check_sparse_spd_determinant(llt_colmajor_lower); -// check_sparse_spd_determinant(llt_colmajor_upper); -// check_sparse_spd_determinant(ldlt_colmajor_lower); -// check_sparse_spd_determinant(ldlt_colmajor_upper); + + check_sparse_spd_determinant(chol_colmajor_lower); + check_sparse_spd_determinant(chol_colmajor_upper); + check_sparse_spd_determinant(llt_colmajor_lower); + check_sparse_spd_determinant(llt_colmajor_upper); + check_sparse_spd_determinant(ldlt_colmajor_lower); + check_sparse_spd_determinant(ldlt_colmajor_upper); } void test_cholmod_support() diff --git a/ground/gcs/src/libs/eigen/test/commainitializer.cpp b/ground/gcs/src/libs/eigen/test/commainitializer.cpp index 99102b966b..9844adbd22 100644 --- a/ground/gcs/src/libs/eigen/test/commainitializer.cpp +++ b/ground/gcs/src/libs/eigen/test/commainitializer.cpp @@ -9,6 +9,62 @@ #include "main.h" + +template +void test_blocks() +{ + Matrix m_fixed; + MatrixXi m_dynamic(M1+M2, N1+N2); + + Matrix mat11; mat11.setRandom(); + Matrix mat12; mat12.setRandom(); + Matrix mat21; mat21.setRandom(); + Matrix mat22; mat22.setRandom(); + + MatrixXi matx11 = mat11, matx12 = mat12, matx21 = mat21, matx22 = mat22; + + { + VERIFY_IS_EQUAL((m_fixed << mat11, mat12, mat21, matx22).finished(), (m_dynamic << mat11, matx12, mat21, matx22).finished()); + VERIFY_IS_EQUAL((m_fixed.template topLeftCorner()), mat11); + VERIFY_IS_EQUAL((m_fixed.template topRightCorner()), mat12); + VERIFY_IS_EQUAL((m_fixed.template bottomLeftCorner()), mat21); + VERIFY_IS_EQUAL((m_fixed.template bottomRightCorner()), mat22); + VERIFY_IS_EQUAL((m_fixed << mat12, mat11, matx21, mat22).finished(), (m_dynamic << mat12, matx11, matx21, mat22).finished()); + } + + if(N1 > 0) + { + VERIFY_RAISES_ASSERT((m_fixed << mat11, mat12, mat11, mat21, mat22)); + VERIFY_RAISES_ASSERT((m_fixed << mat11, mat12, mat21, mat21, mat22)); + } + else + { + // allow insertion of zero-column blocks: + VERIFY_IS_EQUAL((m_fixed << mat11, mat12, mat11, mat11, mat21, mat21, mat22).finished(), (m_dynamic << mat12, mat22).finished()); + } + if(M1 != M2) + { + VERIFY_RAISES_ASSERT((m_fixed << mat11, mat21, mat12, mat22)); + } +} + + +template +struct test_block_recursion +{ + static void run() + { + test_blocks<(N>>6)&3, (N>>4)&3, (N>>2)&3, N & 3>(); + test_block_recursion::run(); + } +}; + +template<> +struct test_block_recursion<-1> +{ + static void run() { } +}; + void test_commainitializer() { Matrix3d m3; @@ -43,4 +99,8 @@ void test_commainitializer() 4, 5, 6, vec[2].transpose(); VERIFY_IS_APPROX(m3, ref); + + + // recursively test all block-sizes from 0 to 3: + test_block_recursion<(1<<8) - 1>(); } diff --git a/ground/gcs/src/libs/eigen/test/conjugate_gradient.cpp b/ground/gcs/src/libs/eigen/test/conjugate_gradient.cpp index 019cc4d64f..9622fd86dd 100644 --- a/ground/gcs/src/libs/eigen/test/conjugate_gradient.cpp +++ b/ground/gcs/src/libs/eigen/test/conjugate_gradient.cpp @@ -10,13 +10,14 @@ #include "sparse_solver.h" #include -template void test_conjugate_gradient_T() +template void test_conjugate_gradient_T() { - ConjugateGradient, Lower > cg_colmajor_lower_diag; - ConjugateGradient, Upper > cg_colmajor_upper_diag; - ConjugateGradient, Lower|Upper> cg_colmajor_loup_diag; - ConjugateGradient, Lower, IdentityPreconditioner> cg_colmajor_lower_I; - ConjugateGradient, Upper, IdentityPreconditioner> cg_colmajor_upper_I; + typedef SparseMatrix SparseMatrixType; + ConjugateGradient cg_colmajor_lower_diag; + ConjugateGradient cg_colmajor_upper_diag; + ConjugateGradient cg_colmajor_loup_diag; + ConjugateGradient cg_colmajor_lower_I; + ConjugateGradient cg_colmajor_upper_I; CALL_SUBTEST( check_sparse_spd_solving(cg_colmajor_lower_diag) ); CALL_SUBTEST( check_sparse_spd_solving(cg_colmajor_upper_diag) ); @@ -27,6 +28,7 @@ template void test_conjugate_gradient_T() void test_conjugate_gradient() { - CALL_SUBTEST_1(test_conjugate_gradient_T()); - CALL_SUBTEST_2(test_conjugate_gradient_T >()); + CALL_SUBTEST_1(( test_conjugate_gradient_T() )); + CALL_SUBTEST_2(( test_conjugate_gradient_T, int>() )); + CALL_SUBTEST_3(( test_conjugate_gradient_T() )); } diff --git a/ground/gcs/src/libs/eigen/test/constructor.cpp b/ground/gcs/src/libs/eigen/test/constructor.cpp new file mode 100644 index 0000000000..eec9e21929 --- /dev/null +++ b/ground/gcs/src/libs/eigen/test/constructor.cpp @@ -0,0 +1,84 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2017 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + + +#define TEST_ENABLE_TEMPORARY_TRACKING + +#include "main.h" + +template struct Wrapper +{ + MatrixType m_mat; + inline Wrapper(const MatrixType &x) : m_mat(x) {} + inline operator const MatrixType& () const { return m_mat; } + inline operator MatrixType& () { return m_mat; } +}; + +template void ctor_init1(const MatrixType& m) +{ + // Check logic in PlainObjectBase::_init1 + Index rows = m.rows(); + Index cols = m.cols(); + + MatrixType m0 = MatrixType::Random(rows,cols); + + VERIFY_EVALUATION_COUNT( MatrixType m1(m0), 1); + VERIFY_EVALUATION_COUNT( MatrixType m2(m0+m0), 1); + VERIFY_EVALUATION_COUNT( MatrixType m2(m0.block(0,0,rows,cols)) , 1); + + Wrapper wrapper(m0); + VERIFY_EVALUATION_COUNT( MatrixType m3(wrapper) , 1); +} + + +void test_constructor() +{ + for(int i = 0; i < g_repeat; i++) { + CALL_SUBTEST_1( ctor_init1(Matrix()) ); + CALL_SUBTEST_1( ctor_init1(Matrix4d()) ); + CALL_SUBTEST_1( ctor_init1(MatrixXcf(internal::random(1,EIGEN_TEST_MAX_SIZE), internal::random(1,EIGEN_TEST_MAX_SIZE))) ); + CALL_SUBTEST_1( ctor_init1(MatrixXi(internal::random(1,EIGEN_TEST_MAX_SIZE), internal::random(1,EIGEN_TEST_MAX_SIZE))) ); + } + { + Matrix a(123); + VERIFY_IS_EQUAL(a[0], 123); + } + { + Matrix a(123.0); + VERIFY_IS_EQUAL(a[0], 123); + } + { + Matrix a(123); + VERIFY_IS_EQUAL(a[0], 123.f); + } + { + Array a(123); + VERIFY_IS_EQUAL(a[0], 123); + } + { + Array a(123.0); + VERIFY_IS_EQUAL(a[0], 123); + } + { + Array a(123); + VERIFY_IS_EQUAL(a[0], 123.f); + } + { + Array a(123); + VERIFY_IS_EQUAL(a(4), 123); + } + { + Array a(123.0); + VERIFY_IS_EQUAL(a(4), 123); + } + { + Array a(123); + VERIFY_IS_EQUAL(a(4), 123.f); + } +} diff --git a/ground/gcs/src/libs/eigen/test/ctorleak.cpp b/ground/gcs/src/libs/eigen/test/ctorleak.cpp new file mode 100644 index 0000000000..c158f5e4ee --- /dev/null +++ b/ground/gcs/src/libs/eigen/test/ctorleak.cpp @@ -0,0 +1,69 @@ +#include "main.h" + +#include // std::exception + +struct Foo +{ + static Index object_count; + static Index object_limit; + int dummy; + + Foo() + { +#ifdef EIGEN_EXCEPTIONS + // TODO: Is this the correct way to handle this? + if (Foo::object_count > Foo::object_limit) { std::cout << "\nThrow!\n"; throw Foo::Fail(); } +#endif + std::cout << '+'; + ++Foo::object_count; + } + + ~Foo() + { + std::cout << '-'; + --Foo::object_count; + } + + class Fail : public std::exception {}; +}; + +Index Foo::object_count = 0; +Index Foo::object_limit = 0; + +#undef EIGEN_TEST_MAX_SIZE +#define EIGEN_TEST_MAX_SIZE 3 + +void test_ctorleak() +{ + typedef Matrix MatrixX; + typedef Matrix VectorX; + Foo::object_count = 0; + for(int i = 0; i < g_repeat; i++) { + Index rows = internal::random(2,EIGEN_TEST_MAX_SIZE), cols = internal::random(2,EIGEN_TEST_MAX_SIZE); + Foo::object_limit = internal::random(0, rows*cols - 2); + std::cout << "object_limit =" << Foo::object_limit << std::endl; +#ifdef EIGEN_EXCEPTIONS + try + { +#endif + std::cout << "\nMatrixX m(" << rows << ", " << cols << ");\n"; + MatrixX m(rows, cols); +#ifdef EIGEN_EXCEPTIONS + VERIFY(false); // not reached if exceptions are enabled + } + catch (const Foo::Fail&) { /* ignore */ } +#endif + VERIFY_IS_EQUAL(Index(0), Foo::object_count); + + { + Foo::object_limit = (rows+1)*(cols+1); + MatrixX A(rows, cols); + VERIFY_IS_EQUAL(Foo::object_count, rows*cols); + VectorX v=A.row(0); + VERIFY_IS_EQUAL(Foo::object_count, (rows+1)*cols); + v = A.col(0); + VERIFY_IS_EQUAL(Foo::object_count, rows*(cols+1)); + } + VERIFY_IS_EQUAL(Index(0), Foo::object_count); + } +} diff --git a/ground/gcs/src/libs/eigen/test/cuda_basic.cu b/ground/gcs/src/libs/eigen/test/cuda_basic.cu new file mode 100644 index 0000000000..cb2e4167a4 --- /dev/null +++ b/ground/gcs/src/libs/eigen/test/cuda_basic.cu @@ -0,0 +1,173 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2015-2016 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// workaround issue between gcc >= 4.7 and cuda 5.5 +#if (defined __GNUC__) && (__GNUC__>4 || __GNUC_MINOR__>=7) + #undef _GLIBCXX_ATOMIC_BUILTINS + #undef _GLIBCXX_USE_INT128 +#endif + +#define EIGEN_TEST_NO_LONGDOUBLE +#define EIGEN_TEST_NO_COMPLEX +#define EIGEN_TEST_FUNC cuda_basic +#define EIGEN_DEFAULT_DENSE_INDEX_TYPE int + +#include +#include +#if defined __CUDACC_VER__ && __CUDACC_VER__ >= 70500 +#include +#endif +#include "main.h" +#include "cuda_common.h" + +// Check that dense modules can be properly parsed by nvcc +#include + +// struct Foo{ +// EIGEN_DEVICE_FUNC +// void operator()(int i, const float* mats, float* vecs) const { +// using namespace Eigen; +// // Matrix3f M(data); +// // Vector3f x(data+9); +// // Map(data+9) = M.inverse() * x; +// Matrix3f M(mats+i/16); +// Vector3f x(vecs+i*3); +// // using std::min; +// // using std::sqrt; +// Map(vecs+i*3) << x.minCoeff(), 1, 2;// / x.dot(x);//(M.inverse() * x) / x.x(); +// //x = x*2 + x.y() * x + x * x.maxCoeff() - x / x.sum(); +// } +// }; + +template +struct coeff_wise { + EIGEN_DEVICE_FUNC + void operator()(int i, const typename T::Scalar* in, typename T::Scalar* out) const + { + using namespace Eigen; + T x1(in+i); + T x2(in+i+1); + T x3(in+i+2); + Map res(out+i*T::MaxSizeAtCompileTime); + + res.array() += (in[0] * x1 + x2).array() * x3.array(); + } +}; + +template +struct replicate { + EIGEN_DEVICE_FUNC + void operator()(int i, const typename T::Scalar* in, typename T::Scalar* out) const + { + using namespace Eigen; + T x1(in+i); + int step = x1.size() * 4; + int stride = 3 * step; + + typedef Map > MapType; + MapType(out+i*stride+0*step, x1.rows()*2, x1.cols()*2) = x1.replicate(2,2); + MapType(out+i*stride+1*step, x1.rows()*3, x1.cols()) = in[i] * x1.colwise().replicate(3); + MapType(out+i*stride+2*step, x1.rows(), x1.cols()*3) = in[i] * x1.rowwise().replicate(3); + } +}; + +template +struct redux { + EIGEN_DEVICE_FUNC + void operator()(int i, const typename T::Scalar* in, typename T::Scalar* out) const + { + using namespace Eigen; + int N = 10; + T x1(in+i); + out[i*N+0] = x1.minCoeff(); + out[i*N+1] = x1.maxCoeff(); + out[i*N+2] = x1.sum(); + out[i*N+3] = x1.prod(); + out[i*N+4] = x1.matrix().squaredNorm(); + out[i*N+5] = x1.matrix().norm(); + out[i*N+6] = x1.colwise().sum().maxCoeff(); + out[i*N+7] = x1.rowwise().maxCoeff().sum(); + out[i*N+8] = x1.matrix().colwise().squaredNorm().sum(); + } +}; + +template +struct prod_test { + EIGEN_DEVICE_FUNC + void operator()(int i, const typename T1::Scalar* in, typename T1::Scalar* out) const + { + using namespace Eigen; + typedef Matrix T3; + T1 x1(in+i); + T2 x2(in+i+1); + Map res(out+i*T3::MaxSizeAtCompileTime); + res += in[i] * x1 * x2; + } +}; + +template +struct diagonal { + EIGEN_DEVICE_FUNC + void operator()(int i, const typename T1::Scalar* in, typename T1::Scalar* out) const + { + using namespace Eigen; + T1 x1(in+i); + Map res(out+i*T2::MaxSizeAtCompileTime); + res += x1.diagonal(); + } +}; + +template +struct eigenvalues { + EIGEN_DEVICE_FUNC + void operator()(int i, const typename T::Scalar* in, typename T::Scalar* out) const + { + using namespace Eigen; + typedef Matrix Vec; + T M(in+i); + Map res(out+i*Vec::MaxSizeAtCompileTime); + T A = M*M.adjoint(); + SelfAdjointEigenSolver eig; + eig.computeDirect(M); + res = eig.eigenvalues(); + } +}; + +void test_cuda_basic() +{ + ei_test_init_cuda(); + + int nthreads = 100; + Eigen::VectorXf in, out; + + #ifndef __CUDA_ARCH__ + int data_size = nthreads * 512; + in.setRandom(data_size); + out.setRandom(data_size); + #endif + + CALL_SUBTEST( run_and_compare_to_cuda(coeff_wise(), nthreads, in, out) ); + CALL_SUBTEST( run_and_compare_to_cuda(coeff_wise(), nthreads, in, out) ); + + CALL_SUBTEST( run_and_compare_to_cuda(replicate(), nthreads, in, out) ); + CALL_SUBTEST( run_and_compare_to_cuda(replicate(), nthreads, in, out) ); + + CALL_SUBTEST( run_and_compare_to_cuda(redux(), nthreads, in, out) ); + CALL_SUBTEST( run_and_compare_to_cuda(redux(), nthreads, in, out) ); + + CALL_SUBTEST( run_and_compare_to_cuda(prod_test(), nthreads, in, out) ); + CALL_SUBTEST( run_and_compare_to_cuda(prod_test(), nthreads, in, out) ); + + CALL_SUBTEST( run_and_compare_to_cuda(diagonal(), nthreads, in, out) ); + CALL_SUBTEST( run_and_compare_to_cuda(diagonal(), nthreads, in, out) ); + + CALL_SUBTEST( run_and_compare_to_cuda(eigenvalues(), nthreads, in, out) ); + CALL_SUBTEST( run_and_compare_to_cuda(eigenvalues(), nthreads, in, out) ); + +} diff --git a/ground/gcs/src/libs/eigen/test/cuda_common.h b/ground/gcs/src/libs/eigen/test/cuda_common.h new file mode 100644 index 0000000000..9737693acf --- /dev/null +++ b/ground/gcs/src/libs/eigen/test/cuda_common.h @@ -0,0 +1,101 @@ + +#ifndef EIGEN_TEST_CUDA_COMMON_H +#define EIGEN_TEST_CUDA_COMMON_H + +#include +#include +#include +#include + +#ifndef __CUDACC__ +dim3 threadIdx, blockDim, blockIdx; +#endif + +template +void run_on_cpu(const Kernel& ker, int n, const Input& in, Output& out) +{ + for(int i=0; i +__global__ +void run_on_cuda_meta_kernel(const Kernel ker, int n, const Input* in, Output* out) +{ + int i = threadIdx.x + blockIdx.x*blockDim.x; + if(i +void run_on_cuda(const Kernel& ker, int n, const Input& in, Output& out) +{ + typename Input::Scalar* d_in; + typename Output::Scalar* d_out; + std::ptrdiff_t in_bytes = in.size() * sizeof(typename Input::Scalar); + std::ptrdiff_t out_bytes = out.size() * sizeof(typename Output::Scalar); + + cudaMalloc((void**)(&d_in), in_bytes); + cudaMalloc((void**)(&d_out), out_bytes); + + cudaMemcpy(d_in, in.data(), in_bytes, cudaMemcpyHostToDevice); + cudaMemcpy(d_out, out.data(), out_bytes, cudaMemcpyHostToDevice); + + // Simple and non-optimal 1D mapping assuming n is not too large + // That's only for unit testing! + dim3 Blocks(128); + dim3 Grids( (n+int(Blocks.x)-1)/int(Blocks.x) ); + + cudaThreadSynchronize(); + run_on_cuda_meta_kernel<<>>(ker, n, d_in, d_out); + cudaThreadSynchronize(); + + // check inputs have not been modified + cudaMemcpy(const_cast(in.data()), d_in, in_bytes, cudaMemcpyDeviceToHost); + cudaMemcpy(out.data(), d_out, out_bytes, cudaMemcpyDeviceToHost); + + cudaFree(d_in); + cudaFree(d_out); +} + + +template +void run_and_compare_to_cuda(const Kernel& ker, int n, const Input& in, Output& out) +{ + Input in_ref, in_cuda; + Output out_ref, out_cuda; + #ifndef __CUDA_ARCH__ + in_ref = in_cuda = in; + out_ref = out_cuda = out; + #endif + run_on_cpu (ker, n, in_ref, out_ref); + run_on_cuda(ker, n, in_cuda, out_cuda); + #ifndef __CUDA_ARCH__ + VERIFY_IS_APPROX(in_ref, in_cuda); + VERIFY_IS_APPROX(out_ref, out_cuda); + #endif +} + + +void ei_test_init_cuda() +{ + int device = 0; + cudaDeviceProp deviceProp; + cudaGetDeviceProperties(&deviceProp, device); + std::cout << "CUDA device info:\n"; + std::cout << " name: " << deviceProp.name << "\n"; + std::cout << " capability: " << deviceProp.major << "." << deviceProp.minor << "\n"; + std::cout << " multiProcessorCount: " << deviceProp.multiProcessorCount << "\n"; + std::cout << " maxThreadsPerMultiProcessor: " << deviceProp.maxThreadsPerMultiProcessor << "\n"; + std::cout << " warpSize: " << deviceProp.warpSize << "\n"; + std::cout << " regsPerBlock: " << deviceProp.regsPerBlock << "\n"; + std::cout << " concurrentKernels: " << deviceProp.concurrentKernels << "\n"; + std::cout << " clockRate: " << deviceProp.clockRate << "\n"; + std::cout << " canMapHostMemory: " << deviceProp.canMapHostMemory << "\n"; + std::cout << " computeMode: " << deviceProp.computeMode << "\n"; +} + +#endif // EIGEN_TEST_CUDA_COMMON_H diff --git a/ground/gcs/src/libs/eigen/test/cwiseop.cpp b/ground/gcs/src/libs/eigen/test/cwiseop.cpp deleted file mode 100644 index e3361da17e..0000000000 --- a/ground/gcs/src/libs/eigen/test/cwiseop.cpp +++ /dev/null @@ -1,184 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008 Gael Guennebaud -// Copyright (C) 2006-2008 Benoit Jacob -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#define EIGEN2_SUPPORT -#define EIGEN_NO_EIGEN2_DEPRECATED_WARNING - -#define EIGEN_NO_STATIC_ASSERT -#include "main.h" -#include - -#ifdef min -#undef min -#endif - -#ifdef max -#undef max -#endif - -using namespace std; - -template struct AddIfNull { - const Scalar operator() (const Scalar a, const Scalar b) const {return a<=1e-3 ? b : a;} - enum { Cost = NumTraits::AddCost }; -}; - -template -typename Eigen::internal::enable_if::IsInteger,typename MatrixType::Scalar>::type -cwiseops_real_only(MatrixType& m1, MatrixType& m2, MatrixType& m3, MatrixType& mones) -{ - typedef typename MatrixType::Scalar Scalar; - typedef typename NumTraits::Real RealScalar; - - VERIFY_IS_APPROX(m1.cwise() / m2, m1.cwise() * (m2.cwise().inverse())); - m3 = m1.cwise().abs().cwise().sqrt(); - VERIFY_IS_APPROX(m3.cwise().square(), m1.cwise().abs()); - VERIFY_IS_APPROX(m1.cwise().square().cwise().sqrt(), m1.cwise().abs()); - VERIFY_IS_APPROX(m1.cwise().abs().cwise().log().cwise().exp() , m1.cwise().abs()); - - VERIFY_IS_APPROX(m1.cwise().pow(2), m1.cwise().square()); - m3 = (m1.cwise().abs().cwise()<=RealScalar(0.01)).select(mones,m1); - VERIFY_IS_APPROX(m3.cwise().pow(-1), m3.cwise().inverse()); - m3 = m1.cwise().abs(); - VERIFY_IS_APPROX(m3.cwise().pow(RealScalar(0.5)), m3.cwise().sqrt()); - -// VERIFY_IS_APPROX(m1.cwise().tan(), m1.cwise().sin().cwise() / m1.cwise().cos()); - VERIFY_IS_APPROX(mones, m1.cwise().sin().cwise().square() + m1.cwise().cos().cwise().square()); - m3 = m1; - m3.cwise() /= m2; - VERIFY_IS_APPROX(m3, m1.cwise() / m2); - - return Scalar(0); -} - -template -typename Eigen::internal::enable_if::IsInteger,typename MatrixType::Scalar>::type -cwiseops_real_only(MatrixType& , MatrixType& , MatrixType& , MatrixType& ) -{ - return 0; -} - -template void cwiseops(const MatrixType& m) -{ - typedef typename MatrixType::Index Index; - typedef typename MatrixType::Scalar Scalar; - typedef Matrix VectorType; - - Index rows = m.rows(); - Index cols = m.cols(); - - MatrixType m1 = MatrixType::Random(rows, cols), - m1bis = m1, - m2 = MatrixType::Random(rows, cols), - m3(rows, cols), - m4(rows, cols), - mzero = MatrixType::Zero(rows, cols), - mones = MatrixType::Ones(rows, cols), - identity = Matrix - ::Identity(rows, rows); - VectorType vzero = VectorType::Zero(rows), - vones = VectorType::Ones(rows), - v3(rows); - - Index r = internal::random(0, rows-1), - c = internal::random(0, cols-1); - - Scalar s1 = internal::random(); - - // test Zero, Ones, Constant, and the set* variants - m3 = MatrixType::Constant(rows, cols, s1); - for (int j=0; j >(mones); - - VERIFY_IS_APPROX(m1.cwise().pow(2), m1.cwise().abs2()); - VERIFY_IS_APPROX(m1.cwise().pow(2), m1.cwise().square()); - VERIFY_IS_APPROX(m1.cwise().pow(3), m1.cwise().cube()); - - VERIFY_IS_APPROX(m1 + mones, m1.cwise()+Scalar(1)); - VERIFY_IS_APPROX(m1 - mones, m1.cwise()-Scalar(1)); - m3 = m1; m3.cwise() += 1; - VERIFY_IS_APPROX(m1 + mones, m3); - m3 = m1; m3.cwise() -= 1; - VERIFY_IS_APPROX(m1 - mones, m3); - - VERIFY_IS_APPROX(m2, m2.cwise() * mones); - VERIFY_IS_APPROX(m1.cwise() * m2, m2.cwise() * m1); - m3 = m1; - m3.cwise() *= m2; - VERIFY_IS_APPROX(m3, m1.cwise() * m2); - - VERIFY_IS_APPROX(mones, m2.cwise()/m2); - - // check min - VERIFY_IS_APPROX( m1.cwise().min(m2), m2.cwise().min(m1) ); - VERIFY_IS_APPROX( m1.cwise().min(m1+mones), m1 ); - VERIFY_IS_APPROX( m1.cwise().min(m1-mones), m1-mones ); - - // check max - VERIFY_IS_APPROX( m1.cwise().max(m2), m2.cwise().max(m1) ); - VERIFY_IS_APPROX( m1.cwise().max(m1-mones), m1 ); - VERIFY_IS_APPROX( m1.cwise().max(m1+mones), m1+mones ); - - VERIFY( (m1.cwise() == m1).all() ); - VERIFY( (m1.cwise() != m2).any() ); - VERIFY(!(m1.cwise() == (m1+mones)).any() ); - if (rows*cols>1) - { - m3 = m1; - m3(r,c) += 1; - VERIFY( (m1.cwise() == m3).any() ); - VERIFY( !(m1.cwise() == m3).all() ); - } - VERIFY( (m1.cwise().min(m2).cwise() <= m2).all() ); - VERIFY( (m1.cwise().max(m2).cwise() >= m2).all() ); - VERIFY( (m1.cwise().min(m2).cwise() < (m1+mones)).all() ); - VERIFY( (m1.cwise().max(m2).cwise() > (m1-mones)).all() ); - - VERIFY( (m1.cwise()(), Scalar(1)))).all() ); - VERIFY( !(m1.cwise()(), Scalar(1)))).all() ); - VERIFY( !(m1.cwise()>m1bis.unaryExpr(bind2nd(plus(), Scalar(1)))).any() ); - - cwiseops_real_only(m1, m2, m3, mones); -} - -void test_cwiseop() -{ - for(int i = 0; i < g_repeat ; i++) { - CALL_SUBTEST_1( cwiseops(Matrix()) ); - CALL_SUBTEST_2( cwiseops(Matrix4d()) ); - CALL_SUBTEST_3( cwiseops(MatrixXf(internal::random(1,EIGEN_TEST_MAX_SIZE), internal::random(1,EIGEN_TEST_MAX_SIZE))) ); - CALL_SUBTEST_4( cwiseops(MatrixXf(internal::random(1,EIGEN_TEST_MAX_SIZE), internal::random(1,EIGEN_TEST_MAX_SIZE))) ); - CALL_SUBTEST_5( cwiseops(MatrixXi(internal::random(1,EIGEN_TEST_MAX_SIZE), internal::random(1,EIGEN_TEST_MAX_SIZE))) ); - CALL_SUBTEST_6( cwiseops(MatrixXd(internal::random(1,EIGEN_TEST_MAX_SIZE), internal::random(1,EIGEN_TEST_MAX_SIZE))) ); - } -} diff --git a/ground/gcs/src/libs/eigen/test/dense_storage.cpp b/ground/gcs/src/libs/eigen/test/dense_storage.cpp new file mode 100644 index 0000000000..e63712b1a4 --- /dev/null +++ b/ground/gcs/src/libs/eigen/test/dense_storage.cpp @@ -0,0 +1,76 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2013 Hauke Heibel +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "main.h" + +#include + +template +void dense_storage_copy() +{ + static const int Size = ((Rows==Dynamic || Cols==Dynamic) ? Dynamic : Rows*Cols); + typedef DenseStorage DenseStorageType; + + const int rows = (Rows==Dynamic) ? 4 : Rows; + const int cols = (Cols==Dynamic) ? 3 : Cols; + const int size = rows*cols; + DenseStorageType reference(size, rows, cols); + T* raw_reference = reference.data(); + for (int i=0; i(i); + + DenseStorageType copied_reference(reference); + const T* raw_copied_reference = copied_reference.data(); + for (int i=0; i +void dense_storage_assignment() +{ + static const int Size = ((Rows==Dynamic || Cols==Dynamic) ? Dynamic : Rows*Cols); + typedef DenseStorage DenseStorageType; + + const int rows = (Rows==Dynamic) ? 4 : Rows; + const int cols = (Cols==Dynamic) ? 3 : Cols; + const int size = rows*cols; + DenseStorageType reference(size, rows, cols); + T* raw_reference = reference.data(); + for (int i=0; i(i); + + DenseStorageType copied_reference; + copied_reference = reference; + const T* raw_copied_reference = copied_reference.data(); + for (int i=0; i(); + dense_storage_copy(); + dense_storage_copy(); + dense_storage_copy(); + + dense_storage_copy(); + dense_storage_copy(); + dense_storage_copy(); + dense_storage_copy(); + + dense_storage_assignment(); + dense_storage_assignment(); + dense_storage_assignment(); + dense_storage_assignment(); + + dense_storage_assignment(); + dense_storage_assignment(); + dense_storage_assignment(); + dense_storage_assignment(); +} diff --git a/ground/gcs/src/libs/eigen/test/diagonal.cpp b/ground/gcs/src/libs/eigen/test/diagonal.cpp index 53814a5885..c1546e97da 100644 --- a/ground/gcs/src/libs/eigen/test/diagonal.cpp +++ b/ground/gcs/src/libs/eigen/test/diagonal.cpp @@ -20,6 +20,8 @@ template void diagonal(const MatrixType& m) MatrixType m1 = MatrixType::Random(rows, cols), m2 = MatrixType::Random(rows, cols); + Scalar s1 = internal::random(); + //check diagonal() VERIFY_IS_APPROX(m1.diagonal(), m1.transpose().diagonal()); m2.diagonal() = 2 * m1.diagonal(); @@ -58,6 +60,26 @@ template void diagonal(const MatrixType& m) VERIFY_IS_APPROX(m2.template diagonal(), static_cast(2) * m1.diagonal(N2)); m2.diagonal(N2)[0] *= 3; VERIFY_IS_APPROX(m2.diagonal(N2)[0], static_cast(6) * m1.diagonal(N2)[0]); + + m2.diagonal(N2).x() = s1; + VERIFY_IS_APPROX(m2.diagonal(N2).x(), s1); + m2.diagonal(N2).coeffRef(0) = Scalar(2)*s1; + VERIFY_IS_APPROX(m2.diagonal(N2).coeff(0), Scalar(2)*s1); + } +} + +template void diagonal_assert(const MatrixType& m) { + Index rows = m.rows(); + Index cols = m.cols(); + + MatrixType m1 = MatrixType::Random(rows, cols); + + if (rows>=2 && cols>=2) + { + VERIFY_RAISES_ASSERT( m1 += m1.diagonal() ); + VERIFY_RAISES_ASSERT( m1 -= m1.diagonal() ); + VERIFY_RAISES_ASSERT( m1.array() *= m1.diagonal().array() ); + VERIFY_RAISES_ASSERT( m1.array() /= m1.diagonal().array() ); } } @@ -74,4 +96,6 @@ void test_diagonal() CALL_SUBTEST_1( diagonal(MatrixXf(internal::random(1,EIGEN_TEST_MAX_SIZE), internal::random(1,EIGEN_TEST_MAX_SIZE))) ); CALL_SUBTEST_1( diagonal(Matrix(3, 4)) ); } + + CALL_SUBTEST_1( diagonal_assert(MatrixXf(internal::random(1,EIGEN_TEST_MAX_SIZE), internal::random(1,EIGEN_TEST_MAX_SIZE))) ); } diff --git a/ground/gcs/src/libs/eigen/test/diagonalmatrices.cpp b/ground/gcs/src/libs/eigen/test/diagonalmatrices.cpp index 149f1db2f7..cd6dc8cf05 100644 --- a/ground/gcs/src/libs/eigen/test/diagonalmatrices.cpp +++ b/ground/gcs/src/libs/eigen/test/diagonalmatrices.cpp @@ -17,6 +17,7 @@ template void diagonalmatrices(const MatrixType& m) typedef Matrix VectorType; typedef Matrix RowVectorType; typedef Matrix SquareMatrixType; + typedef Matrix DynMatrixType; typedef DiagonalMatrix LeftDiagonalMatrix; typedef DiagonalMatrix RightDiagonalMatrix; typedef Matrix BigMatrix; @@ -64,6 +65,13 @@ template void diagonalmatrices(const MatrixType& m) VERIFY_IS_APPROX( (((v1+v2).asDiagonal() * (m1+m2))(i,j)) , (v1+v2)(i) * (m1+m2)(i,j) ); VERIFY_IS_APPROX( ((m1 * (rv1+rv2).asDiagonal())(i,j)) , (rv1+rv2)(j) * m1(i,j) ); VERIFY_IS_APPROX( (((m1+m2) * (rv1+rv2).asDiagonal())(i,j)) , (rv1+rv2)(j) * (m1+m2)(i,j) ); + + if(rows>1) + { + DynMatrixType tmp = m1.topRows(rows/2), res; + VERIFY_IS_APPROX( (res = m1.topRows(rows/2) * rv1.asDiagonal()), tmp * rv1.asDiagonal() ); + VERIFY_IS_APPROX( (res = v1.head(rows/2).asDiagonal()*m1.topRows(rows/2)), v1.head(rows/2).asDiagonal()*tmp ); + } BigMatrix big; big.setZero(2*rows, 2*cols); @@ -84,6 +92,24 @@ template void diagonalmatrices(const MatrixType& m) VERIFY_IS_APPROX(m1 * (rdm1 * s1), (m1 * rdm1) * s1); VERIFY_IS_APPROX(m1 * (s1 * rdm1), (m1 * rdm1) * s1); + + // Diagonal to dense + sq_m1.setRandom(); + sq_m2 = sq_m1; + VERIFY_IS_APPROX( (sq_m1 += (s1*v1).asDiagonal()), sq_m2 += (s1*v1).asDiagonal().toDenseMatrix() ); + VERIFY_IS_APPROX( (sq_m1 -= (s1*v1).asDiagonal()), sq_m2 -= (s1*v1).asDiagonal().toDenseMatrix() ); + VERIFY_IS_APPROX( (sq_m1 = (s1*v1).asDiagonal()), (s1*v1).asDiagonal().toDenseMatrix() ); +} + +template +void bug987() +{ + Matrix3Xd points = Matrix3Xd::Random(3, 3); + Vector2d diag = Vector2d::Random(); + Matrix2Xd tmp1 = points.topRows<2>(), res1, res2; + VERIFY_IS_APPROX( res1 = diag.asDiagonal() * points.topRows<2>(), res2 = diag.asDiagonal() * tmp1 ); + Matrix2d tmp2 = points.topLeftCorner<2,2>(); + VERIFY_IS_APPROX(( res1 = points.topLeftCorner<2,2>()*diag.asDiagonal()) , res2 = tmp2*diag.asDiagonal() ); } void test_diagonalmatrices() @@ -99,4 +125,5 @@ void test_diagonalmatrices() CALL_SUBTEST_8( diagonalmatrices(Matrix(internal::random(1,EIGEN_TEST_MAX_SIZE), internal::random(1,EIGEN_TEST_MAX_SIZE))) ); CALL_SUBTEST_9( diagonalmatrices(MatrixXf(internal::random(1,EIGEN_TEST_MAX_SIZE), internal::random(1,EIGEN_TEST_MAX_SIZE))) ); } + CALL_SUBTEST_10( bug987<0>() ); } diff --git a/ground/gcs/src/libs/eigen/test/dynalloc.cpp b/ground/gcs/src/libs/eigen/test/dynalloc.cpp index ef92c0507c..f1cc70beeb 100644 --- a/ground/gcs/src/libs/eigen/test/dynalloc.cpp +++ b/ground/gcs/src/libs/eigen/test/dynalloc.cpp @@ -9,18 +9,20 @@ #include "main.h" -#if EIGEN_ALIGN -#define ALIGNMENT 16 +#if EIGEN_MAX_ALIGN_BYTES>0 +#define ALIGNMENT EIGEN_MAX_ALIGN_BYTES #else #define ALIGNMENT 1 #endif +typedef Matrix Vector8f; + void check_handmade_aligned_malloc() { for(int i = 1; i < 1000; i++) { char *p = (char*)internal::handmade_aligned_malloc(i); - VERIFY(size_t(p)%ALIGNMENT==0); + VERIFY(internal::UIntPtr(p)%ALIGNMENT==0); // if the buffer is wrongly allocated this will give a bad write --> check with valgrind for(int j = 0; j < i; j++) p[j]=0; internal::handmade_aligned_free(p); @@ -29,10 +31,10 @@ void check_handmade_aligned_malloc() void check_aligned_malloc() { - for(int i = 1; i < 1000; i++) + for(int i = ALIGNMENT; i < 1000; i++) { char *p = (char*)internal::aligned_malloc(i); - VERIFY(size_t(p)%ALIGNMENT==0); + VERIFY(internal::UIntPtr(p)%ALIGNMENT==0); // if the buffer is wrongly allocated this will give a bad write --> check with valgrind for(int j = 0; j < i; j++) p[j]=0; internal::aligned_free(p); @@ -41,10 +43,10 @@ void check_aligned_malloc() void check_aligned_new() { - for(int i = 1; i < 1000; i++) + for(int i = ALIGNMENT; i < 1000; i++) { float *p = internal::aligned_new(i); - VERIFY(size_t(p)%ALIGNMENT==0); + VERIFY(internal::UIntPtr(p)%ALIGNMENT==0); // if the buffer is wrongly allocated this will give a bad write --> check with valgrind for(int j = 0; j < i; j++) p[j]=0; internal::aligned_delete(p,i); @@ -53,10 +55,10 @@ void check_aligned_new() void check_aligned_stack_alloc() { - for(int i = 1; i < 400; i++) + for(int i = ALIGNMENT; i < 400; i++) { ei_declare_aligned_stack_constructed_variable(float,p,i,0); - VERIFY(size_t(p)%ALIGNMENT==0); + VERIFY(internal::UIntPtr(p)%ALIGNMENT==0); // if the buffer is wrongly allocated this will give a bad write --> check with valgrind for(int j = 0; j < i; j++) p[j]=0; } @@ -68,7 +70,7 @@ struct MyStruct { EIGEN_MAKE_ALIGNED_OPERATOR_NEW char dummychar; - Vector4f avec; + Vector8f avec; }; class MyClassA @@ -76,15 +78,19 @@ class MyClassA public: EIGEN_MAKE_ALIGNED_OPERATOR_NEW char dummychar; - Vector4f avec; + Vector8f avec; }; template void check_dynaligned() { - T* obj = new T; - VERIFY(T::NeedsToAlign==1); - VERIFY(size_t(obj)%ALIGNMENT==0); - delete obj; + // TODO have to be updated once we support multiple alignment values + if(T::SizeAtCompileTime % ALIGNMENT == 0) + { + T* obj = new T; + VERIFY(T::NeedsToAlign==1); + VERIFY(internal::UIntPtr(obj)%ALIGNMENT==0); + delete obj; + } } template void check_custom_new_delete() @@ -100,7 +106,7 @@ template void check_custom_new_delete() delete[] t; } -#ifdef EIGEN_ALIGN +#if EIGEN_MAX_ALIGN_BYTES>0 { T* t = static_cast((T::operator new)(sizeof(T))); (T::operator delete)(t, sizeof(T)); @@ -120,9 +126,17 @@ void test_dynalloc() CALL_SUBTEST(check_aligned_malloc()); CALL_SUBTEST(check_aligned_new()); CALL_SUBTEST(check_aligned_stack_alloc()); + + for (int i=0; i() ); + CALL_SUBTEST( check_custom_new_delete() ); + CALL_SUBTEST( check_custom_new_delete() ); + CALL_SUBTEST( check_custom_new_delete() ); + } // check static allocation, who knows ? - #if EIGEN_ALIGN_STATICALLY + #if EIGEN_MAX_STATIC_ALIGN_BYTES for (int i=0; i() ); @@ -130,23 +144,19 @@ void test_dynalloc() CALL_SUBTEST(check_dynaligned() ); CALL_SUBTEST(check_dynaligned() ); CALL_SUBTEST(check_dynaligned() ); - - CALL_SUBTEST( check_custom_new_delete() ); - CALL_SUBTEST( check_custom_new_delete() ); - CALL_SUBTEST( check_custom_new_delete() ); - CALL_SUBTEST( check_custom_new_delete() ); + CALL_SUBTEST(check_dynaligned() ); } { - MyStruct foo0; VERIFY(size_t(foo0.avec.data())%ALIGNMENT==0); - MyClassA fooA; VERIFY(size_t(fooA.avec.data())%ALIGNMENT==0); + MyStruct foo0; VERIFY(internal::UIntPtr(foo0.avec.data())%ALIGNMENT==0); + MyClassA fooA; VERIFY(internal::UIntPtr(fooA.avec.data())%ALIGNMENT==0); } // dynamic allocation, single object for (int i=0; iavec.data())%ALIGNMENT==0); - MyClassA *fooA = new MyClassA(); VERIFY(size_t(fooA->avec.data())%ALIGNMENT==0); + MyStruct *foo0 = new MyStruct(); VERIFY(internal::UIntPtr(foo0->avec.data())%ALIGNMENT==0); + MyClassA *fooA = new MyClassA(); VERIFY(internal::UIntPtr(fooA->avec.data())%ALIGNMENT==0); delete foo0; delete fooA; } @@ -155,8 +165,8 @@ void test_dynalloc() const int N = 10; for (int i=0; iavec.data())%ALIGNMENT==0); - MyClassA *fooA = new MyClassA[N]; VERIFY(size_t(fooA->avec.data())%ALIGNMENT==0); + MyStruct *foo0 = new MyStruct[N]; VERIFY(internal::UIntPtr(foo0->avec.data())%ALIGNMENT==0); + MyClassA *fooA = new MyClassA[N]; VERIFY(internal::UIntPtr(fooA->avec.data())%ALIGNMENT==0); delete[] foo0; delete[] fooA; } diff --git a/ground/gcs/src/libs/eigen/test/eigen2/CMakeLists.txt b/ground/gcs/src/libs/eigen/test/eigen2/CMakeLists.txt deleted file mode 100644 index 9615a6026e..0000000000 --- a/ground/gcs/src/libs/eigen/test/eigen2/CMakeLists.txt +++ /dev/null @@ -1,61 +0,0 @@ -add_custom_target(eigen2_buildtests) -add_custom_target(eigen2_check COMMAND "ctest -R eigen2") -add_dependencies(eigen2_check eigen2_buildtests) -add_dependencies(buildtests eigen2_buildtests) - -add_definitions("-DEIGEN2_SUPPORT_STAGE10_FULL_EIGEN2_API") -add_definitions("-DEIGEN_NO_EIGEN2_DEPRECATED_WARNING") - -ei_add_test(eigen2_meta) -ei_add_test(eigen2_sizeof) -ei_add_test(eigen2_dynalloc) -ei_add_test(eigen2_nomalloc) -#ei_add_test(eigen2_first_aligned) -ei_add_test(eigen2_mixingtypes) -#ei_add_test(eigen2_packetmath) -ei_add_test(eigen2_unalignedassert) -#ei_add_test(eigen2_vectorization_logic) -ei_add_test(eigen2_basicstuff) -ei_add_test(eigen2_linearstructure) -ei_add_test(eigen2_cwiseop) -ei_add_test(eigen2_sum) -ei_add_test(eigen2_product_small) -ei_add_test(eigen2_product_large ${EI_OFLAG}) -ei_add_test(eigen2_adjoint) -ei_add_test(eigen2_submatrices) -ei_add_test(eigen2_miscmatrices) -ei_add_test(eigen2_commainitializer) -ei_add_test(eigen2_smallvectors) -ei_add_test(eigen2_map) -ei_add_test(eigen2_array) -ei_add_test(eigen2_triangular) -ei_add_test(eigen2_cholesky " " "${GSL_LIBRARIES}") -ei_add_test(eigen2_lu ${EI_OFLAG}) -ei_add_test(eigen2_determinant ${EI_OFLAG}) -ei_add_test(eigen2_inverse) -ei_add_test(eigen2_qr) -ei_add_test(eigen2_eigensolver " " "${GSL_LIBRARIES}") -ei_add_test(eigen2_svd) -ei_add_test(eigen2_geometry) -ei_add_test(eigen2_geometry_with_eigen2_prefix) -ei_add_test(eigen2_hyperplane) -ei_add_test(eigen2_parametrizedline) -ei_add_test(eigen2_alignedbox) -ei_add_test(eigen2_regression) -ei_add_test(eigen2_stdvector) -ei_add_test(eigen2_newstdvector) -if(QT4_FOUND) - ei_add_test(eigen2_qtvector " " "${QT_QTCORE_LIBRARY}") -endif(QT4_FOUND) -# no support for eigen2 sparse module -# if(NOT EIGEN_DEFAULT_TO_ROW_MAJOR) -# ei_add_test(eigen2_sparse_vector) -# ei_add_test(eigen2_sparse_basic) -# ei_add_test(eigen2_sparse_solvers " " "${SPARSE_LIBS}") -# ei_add_test(eigen2_sparse_product) -# endif() -ei_add_test(eigen2_swap) -ei_add_test(eigen2_visitor) -ei_add_test(eigen2_bug_132) - -ei_add_test(eigen2_prec_inverse_4x4 ${EI_OFLAG}) diff --git a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_adjoint.cpp b/ground/gcs/src/libs/eigen/test/eigen2/eigen2_adjoint.cpp deleted file mode 100644 index c0f8114599..0000000000 --- a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_adjoint.cpp +++ /dev/null @@ -1,99 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. Eigen itself is part of the KDE project. -// -// Copyright (C) 2006-2008 Benoit Jacob -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#include "main.h" - -template void adjoint(const MatrixType& m) -{ - /* this test covers the following files: - Transpose.h Conjugate.h Dot.h - */ - - typedef typename MatrixType::Scalar Scalar; - typedef typename NumTraits::Real RealScalar; - typedef Matrix VectorType; - typedef Matrix SquareMatrixType; - int rows = m.rows(); - int cols = m.cols(); - - RealScalar largerEps = test_precision(); - if (ei_is_same_type::ret) - largerEps = RealScalar(1e-3f); - - MatrixType m1 = MatrixType::Random(rows, cols), - m2 = MatrixType::Random(rows, cols), - m3(rows, cols), - square = SquareMatrixType::Random(rows, rows); - VectorType v1 = VectorType::Random(rows), - v2 = VectorType::Random(rows), - v3 = VectorType::Random(rows), - vzero = VectorType::Zero(rows); - - Scalar s1 = ei_random(), - s2 = ei_random(); - - // check basic compatibility of adjoint, transpose, conjugate - VERIFY_IS_APPROX(m1.transpose().conjugate().adjoint(), m1); - VERIFY_IS_APPROX(m1.adjoint().conjugate().transpose(), m1); - - // check multiplicative behavior - VERIFY_IS_APPROX((m1.adjoint() * m2).adjoint(), m2.adjoint() * m1); - VERIFY_IS_APPROX((s1 * m1).adjoint(), ei_conj(s1) * m1.adjoint()); - - // check basic properties of dot, norm, norm2 - typedef typename NumTraits::Real RealScalar; - VERIFY(ei_isApprox((s1 * v1 + s2 * v2).eigen2_dot(v3), s1 * v1.eigen2_dot(v3) + s2 * v2.eigen2_dot(v3), largerEps)); - VERIFY(ei_isApprox(v3.eigen2_dot(s1 * v1 + s2 * v2), ei_conj(s1)*v3.eigen2_dot(v1)+ei_conj(s2)*v3.eigen2_dot(v2), largerEps)); - VERIFY_IS_APPROX(ei_conj(v1.eigen2_dot(v2)), v2.eigen2_dot(v1)); - VERIFY_IS_APPROX(ei_real(v1.eigen2_dot(v1)), v1.squaredNorm()); - if(NumTraits::HasFloatingPoint) - VERIFY_IS_APPROX(v1.squaredNorm(), v1.norm() * v1.norm()); - VERIFY_IS_MUCH_SMALLER_THAN(ei_abs(vzero.eigen2_dot(v1)), static_cast(1)); - if(NumTraits::HasFloatingPoint) - VERIFY_IS_MUCH_SMALLER_THAN(vzero.norm(), static_cast(1)); - - // check compatibility of dot and adjoint - VERIFY(ei_isApprox(v1.eigen2_dot(square * v2), (square.adjoint() * v1).eigen2_dot(v2), largerEps)); - - // like in testBasicStuff, test operator() to check const-qualification - int r = ei_random(0, rows-1), - c = ei_random(0, cols-1); - VERIFY_IS_APPROX(m1.conjugate()(r,c), ei_conj(m1(r,c))); - VERIFY_IS_APPROX(m1.adjoint()(c,r), ei_conj(m1(r,c))); - - if(NumTraits::HasFloatingPoint) - { - // check that Random().normalized() works: tricky as the random xpr must be evaluated by - // normalized() in order to produce a consistent result. - VERIFY_IS_APPROX(VectorType::Random(rows).normalized().norm(), RealScalar(1)); - } - - // check inplace transpose - m3 = m1; - m3.transposeInPlace(); - VERIFY_IS_APPROX(m3,m1.transpose()); - m3.transposeInPlace(); - VERIFY_IS_APPROX(m3,m1); - -} - -void test_eigen2_adjoint() -{ - for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST_1( adjoint(Matrix()) ); - CALL_SUBTEST_2( adjoint(Matrix3d()) ); - CALL_SUBTEST_3( adjoint(Matrix4f()) ); - CALL_SUBTEST_4( adjoint(MatrixXcf(4, 4)) ); - CALL_SUBTEST_5( adjoint(MatrixXi(8, 12)) ); - CALL_SUBTEST_6( adjoint(MatrixXf(21, 21)) ); - } - // test a large matrix only once - CALL_SUBTEST_7( adjoint(Matrix()) ); -} - diff --git a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_alignedbox.cpp b/ground/gcs/src/libs/eigen/test/eigen2/eigen2_alignedbox.cpp deleted file mode 100644 index 35043b9587..0000000000 --- a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_alignedbox.cpp +++ /dev/null @@ -1,60 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. Eigen itself is part of the KDE project. -// -// Copyright (C) 2008 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#include "main.h" -#include -#include -#include - -template void alignedbox(const BoxType& _box) -{ - /* this test covers the following files: - AlignedBox.h - */ - - const int dim = _box.dim(); - typedef typename BoxType::Scalar Scalar; - typedef typename NumTraits::Real RealScalar; - typedef Matrix VectorType; - - VectorType p0 = VectorType::Random(dim); - VectorType p1 = VectorType::Random(dim); - RealScalar s1 = ei_random(0,1); - - BoxType b0(dim); - BoxType b1(VectorType::Random(dim),VectorType::Random(dim)); - BoxType b2; - - b0.extend(p0); - b0.extend(p1); - VERIFY(b0.contains(p0*s1+(Scalar(1)-s1)*p1)); - VERIFY(!b0.contains(p0 + (1+s1)*(p1-p0))); - - (b2 = b0).extend(b1); - VERIFY(b2.contains(b0)); - VERIFY(b2.contains(b1)); - VERIFY_IS_APPROX(b2.clamp(b0), b0); - - // casting - const int Dim = BoxType::AmbientDimAtCompileTime; - typedef typename GetDifferentType::type OtherScalar; - AlignedBox hp1f = b0.template cast(); - VERIFY_IS_APPROX(hp1f.template cast(),b0); - AlignedBox hp1d = b0.template cast(); - VERIFY_IS_APPROX(hp1d.template cast(),b0); -} - -void test_eigen2_alignedbox() -{ - for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST_1( alignedbox(AlignedBox()) ); - CALL_SUBTEST_2( alignedbox(AlignedBox()) ); - CALL_SUBTEST_3( alignedbox(AlignedBox()) ); - } -} diff --git a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_array.cpp b/ground/gcs/src/libs/eigen/test/eigen2/eigen2_array.cpp deleted file mode 100644 index c1ff40ce7d..0000000000 --- a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_array.cpp +++ /dev/null @@ -1,142 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. Eigen itself is part of the KDE project. -// -// Copyright (C) 2008 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#include "main.h" -#include - -template void array(const MatrixType& m) -{ - /* this test covers the following files: - Array.cpp - */ - - typedef typename MatrixType::Scalar Scalar; - typedef typename NumTraits::Real RealScalar; - typedef Matrix VectorType; - - int rows = m.rows(); - int cols = m.cols(); - - MatrixType m1 = MatrixType::Random(rows, cols), - m2 = MatrixType::Random(rows, cols), - m3(rows, cols); - - Scalar s1 = ei_random(), - s2 = ei_random(); - - // scalar addition - VERIFY_IS_APPROX(m1.cwise() + s1, s1 + m1.cwise()); - VERIFY_IS_APPROX(m1.cwise() + s1, MatrixType::Constant(rows,cols,s1) + m1); - VERIFY_IS_APPROX((m1*Scalar(2)).cwise() - s2, (m1+m1) - MatrixType::Constant(rows,cols,s2) ); - m3 = m1; - m3.cwise() += s2; - VERIFY_IS_APPROX(m3, m1.cwise() + s2); - m3 = m1; - m3.cwise() -= s1; - VERIFY_IS_APPROX(m3, m1.cwise() - s1); - - // reductions - VERIFY_IS_APPROX(m1.colwise().sum().sum(), m1.sum()); - VERIFY_IS_APPROX(m1.rowwise().sum().sum(), m1.sum()); - if (!ei_isApprox(m1.sum(), (m1+m2).sum())) - VERIFY_IS_NOT_APPROX(((m1+m2).rowwise().sum()).sum(), m1.sum()); - VERIFY_IS_APPROX(m1.colwise().sum(), m1.colwise().redux(internal::scalar_sum_op())); -} - -template void comparisons(const MatrixType& m) -{ - typedef typename MatrixType::Scalar Scalar; - typedef typename NumTraits::Real RealScalar; - typedef Matrix VectorType; - - int rows = m.rows(); - int cols = m.cols(); - - int r = ei_random(0, rows-1), - c = ei_random(0, cols-1); - - MatrixType m1 = MatrixType::Random(rows, cols), - m2 = MatrixType::Random(rows, cols), - m3(rows, cols); - - VERIFY(((m1.cwise() + Scalar(1)).cwise() > m1).all()); - VERIFY(((m1.cwise() - Scalar(1)).cwise() < m1).all()); - if (rows*cols>1) - { - m3 = m1; - m3(r,c) += 1; - VERIFY(! (m1.cwise() < m3).all() ); - VERIFY(! (m1.cwise() > m3).all() ); - } - - // comparisons to scalar - VERIFY( (m1.cwise() != (m1(r,c)+1) ).any() ); - VERIFY( (m1.cwise() > (m1(r,c)-1) ).any() ); - VERIFY( (m1.cwise() < (m1(r,c)+1) ).any() ); - VERIFY( (m1.cwise() == m1(r,c) ).any() ); - - // test Select - VERIFY_IS_APPROX( (m1.cwise()m2).select(m1,m2), m1.cwise().max(m2) ); - Scalar mid = (m1.cwise().abs().minCoeff() + m1.cwise().abs().maxCoeff())/Scalar(2); - for (int j=0; j=MatrixType::Constant(rows,cols,mid)) - .select(m1,0), m3); - // even shorter version: - VERIFY_IS_APPROX( (m1.cwise().abs().cwise()RealScalar(0.1)).count() == rows*cols); - VERIFY_IS_APPROX(((m1.cwise().abs().cwise()+1).cwise()>RealScalar(0.1)).colwise().count().template cast(), RowVectorXi::Constant(cols,rows)); - VERIFY_IS_APPROX(((m1.cwise().abs().cwise()+1).cwise()>RealScalar(0.1)).rowwise().count().template cast(), VectorXi::Constant(rows, cols)); -} - -template void lpNorm(const VectorType& v) -{ - VectorType u = VectorType::Random(v.size()); - - VERIFY_IS_APPROX(u.template lpNorm(), u.cwise().abs().maxCoeff()); - VERIFY_IS_APPROX(u.template lpNorm<1>(), u.cwise().abs().sum()); - VERIFY_IS_APPROX(u.template lpNorm<2>(), ei_sqrt(u.cwise().abs().cwise().square().sum())); - VERIFY_IS_APPROX(ei_pow(u.template lpNorm<5>(), typename VectorType::RealScalar(5)), u.cwise().abs().cwise().pow(5).sum()); -} - -void test_eigen2_array() -{ - for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST_1( array(Matrix()) ); - CALL_SUBTEST_2( array(Matrix2f()) ); - CALL_SUBTEST_3( array(Matrix4d()) ); - CALL_SUBTEST_4( array(MatrixXcf(3, 3)) ); - CALL_SUBTEST_5( array(MatrixXf(8, 12)) ); - CALL_SUBTEST_6( array(MatrixXi(8, 12)) ); - } - for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST_1( comparisons(Matrix()) ); - CALL_SUBTEST_2( comparisons(Matrix2f()) ); - CALL_SUBTEST_3( comparisons(Matrix4d()) ); - CALL_SUBTEST_5( comparisons(MatrixXf(8, 12)) ); - CALL_SUBTEST_6( comparisons(MatrixXi(8, 12)) ); - } - for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST_1( lpNorm(Matrix()) ); - CALL_SUBTEST_2( lpNorm(Vector2f()) ); - CALL_SUBTEST_3( lpNorm(Vector3d()) ); - CALL_SUBTEST_4( lpNorm(Vector4f()) ); - CALL_SUBTEST_5( lpNorm(VectorXf(16)) ); - CALL_SUBTEST_7( lpNorm(VectorXcd(10)) ); - } -} diff --git a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_basicstuff.cpp b/ground/gcs/src/libs/eigen/test/eigen2/eigen2_basicstuff.cpp deleted file mode 100644 index dd2dec1eff..0000000000 --- a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_basicstuff.cpp +++ /dev/null @@ -1,105 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. Eigen itself is part of the KDE project. -// -// Copyright (C) 2006-2008 Benoit Jacob -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#include "main.h" - -template void basicStuff(const MatrixType& m) -{ - typedef typename MatrixType::Scalar Scalar; - typedef Matrix VectorType; - - int rows = m.rows(); - int cols = m.cols(); - - // this test relies a lot on Random.h, and there's not much more that we can do - // to test it, hence I consider that we will have tested Random.h - MatrixType m1 = MatrixType::Random(rows, cols), - m2 = MatrixType::Random(rows, cols), - m3(rows, cols), - mzero = MatrixType::Zero(rows, cols), - square = Matrix::Random(rows, rows); - VectorType v1 = VectorType::Random(rows), - vzero = VectorType::Zero(rows); - - Scalar x = ei_random(); - - int r = ei_random(0, rows-1), - c = ei_random(0, cols-1); - - m1.coeffRef(r,c) = x; - VERIFY_IS_APPROX(x, m1.coeff(r,c)); - m1(r,c) = x; - VERIFY_IS_APPROX(x, m1(r,c)); - v1.coeffRef(r) = x; - VERIFY_IS_APPROX(x, v1.coeff(r)); - v1(r) = x; - VERIFY_IS_APPROX(x, v1(r)); - v1[r] = x; - VERIFY_IS_APPROX(x, v1[r]); - - VERIFY_IS_APPROX( v1, v1); - VERIFY_IS_NOT_APPROX( v1, 2*v1); - VERIFY_IS_MUCH_SMALLER_THAN( vzero, v1); - if(NumTraits::HasFloatingPoint) - VERIFY_IS_MUCH_SMALLER_THAN( vzero, v1.norm()); - VERIFY_IS_NOT_MUCH_SMALLER_THAN(v1, v1); - VERIFY_IS_APPROX( vzero, v1-v1); - VERIFY_IS_APPROX( m1, m1); - VERIFY_IS_NOT_APPROX( m1, 2*m1); - VERIFY_IS_MUCH_SMALLER_THAN( mzero, m1); - VERIFY_IS_NOT_MUCH_SMALLER_THAN(m1, m1); - VERIFY_IS_APPROX( mzero, m1-m1); - - // always test operator() on each read-only expression class, - // in order to check const-qualifiers. - // indeed, if an expression class (here Zero) is meant to be read-only, - // hence has no _write() method, the corresponding MatrixBase method (here zero()) - // should return a const-qualified object so that it is the const-qualified - // operator() that gets called, which in turn calls _read(). - VERIFY_IS_MUCH_SMALLER_THAN(MatrixType::Zero(rows,cols)(r,c), static_cast(1)); - - // now test copying a row-vector into a (column-)vector and conversely. - square.col(r) = square.row(r).eval(); - Matrix rv(rows); - Matrix cv(rows); - rv = square.row(r); - cv = square.col(r); - VERIFY_IS_APPROX(rv, cv.transpose()); - - if(cols!=1 && rows!=1 && MatrixType::SizeAtCompileTime!=Dynamic) - { - VERIFY_RAISES_ASSERT(m1 = (m2.block(0,0, rows-1, cols-1))); - } - - VERIFY_IS_APPROX(m3 = m1,m1); - MatrixType m4; - VERIFY_IS_APPROX(m4 = m1,m1); - - // test swap - m3 = m1; - m1.swap(m2); - VERIFY_IS_APPROX(m3, m2); - if(rows*cols>=3) - { - VERIFY_IS_NOT_APPROX(m3, m1); - } -} - -void test_eigen2_basicstuff() -{ - for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST_1( basicStuff(Matrix()) ); - CALL_SUBTEST_2( basicStuff(Matrix4d()) ); - CALL_SUBTEST_3( basicStuff(MatrixXcf(3, 3)) ); - CALL_SUBTEST_4( basicStuff(MatrixXi(8, 12)) ); - CALL_SUBTEST_5( basicStuff(MatrixXcd(20, 20)) ); - CALL_SUBTEST_6( basicStuff(Matrix()) ); - CALL_SUBTEST_7( basicStuff(Matrix(10,10)) ); - } -} diff --git a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_bug_132.cpp b/ground/gcs/src/libs/eigen/test/eigen2/eigen2_bug_132.cpp deleted file mode 100644 index 7fe3610ce8..0000000000 --- a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_bug_132.cpp +++ /dev/null @@ -1,26 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. Eigen itself is part of the KDE project. -// -// Copyright (C) 2010 Benoit Jacob -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#include "main.h" - -void test_eigen2_bug_132() { - int size = 100; - MatrixXd A(size, size); - VectorXd b(size), c(size); - { - VectorXd y = A.transpose() * (b-c); // bug 132: infinite recursion in coeffRef - VectorXd z = (b-c).transpose() * A; // bug 132: infinite recursion in coeffRef - } - - // the following ones weren't failing, but let's include them for completeness: - { - VectorXd y = A * (b-c); - VectorXd z = (b-c).transpose() * A.transpose(); - } -} diff --git a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_cholesky.cpp b/ground/gcs/src/libs/eigen/test/eigen2/eigen2_cholesky.cpp deleted file mode 100644 index 9c4b6f5619..0000000000 --- a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_cholesky.cpp +++ /dev/null @@ -1,113 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. Eigen itself is part of the KDE project. -// -// Copyright (C) 2008 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#define EIGEN_NO_ASSERTION_CHECKING -#include "main.h" -#include -#include - -#ifdef HAS_GSL -#include "gsl_helper.h" -#endif - -template void cholesky(const MatrixType& m) -{ - /* this test covers the following files: - LLT.h LDLT.h - */ - int rows = m.rows(); - int cols = m.cols(); - - typedef typename MatrixType::Scalar Scalar; - typedef typename NumTraits::Real RealScalar; - typedef Matrix SquareMatrixType; - typedef Matrix VectorType; - - MatrixType a0 = MatrixType::Random(rows,cols); - VectorType vecB = VectorType::Random(rows), vecX(rows); - MatrixType matB = MatrixType::Random(rows,cols), matX(rows,cols); - SquareMatrixType symm = a0 * a0.adjoint(); - // let's make sure the matrix is not singular or near singular - MatrixType a1 = MatrixType::Random(rows,cols); - symm += a1 * a1.adjoint(); - - #ifdef HAS_GSL - if (ei_is_same_type::ret) - { - typedef GslTraits Gsl; - typename Gsl::Matrix gMatA=0, gSymm=0; - typename Gsl::Vector gVecB=0, gVecX=0; - convert(symm, gSymm); - convert(symm, gMatA); - convert(vecB, gVecB); - convert(vecB, gVecX); - Gsl::cholesky(gMatA); - Gsl::cholesky_solve(gMatA, gVecB, gVecX); - VectorType vecX(rows), _vecX, _vecB; - convert(gVecX, _vecX); - symm.llt().solve(vecB, &vecX); - Gsl::prod(gSymm, gVecX, gVecB); - convert(gVecB, _vecB); - // test gsl itself ! - VERIFY_IS_APPROX(vecB, _vecB); - VERIFY_IS_APPROX(vecX, _vecX); - - Gsl::free(gMatA); - Gsl::free(gSymm); - Gsl::free(gVecB); - Gsl::free(gVecX); - } - #endif - - { - LDLT ldlt(symm); - VERIFY(ldlt.isPositiveDefinite()); - // in eigen3, LDLT is pivoting - //VERIFY_IS_APPROX(symm, ldlt.matrixL() * ldlt.vectorD().asDiagonal() * ldlt.matrixL().adjoint()); - ldlt.solve(vecB, &vecX); - VERIFY_IS_APPROX(symm * vecX, vecB); - ldlt.solve(matB, &matX); - VERIFY_IS_APPROX(symm * matX, matB); - } - - { - LLT chol(symm); - VERIFY(chol.isPositiveDefinite()); - VERIFY_IS_APPROX(symm, chol.matrixL() * chol.matrixL().adjoint()); - chol.solve(vecB, &vecX); - VERIFY_IS_APPROX(symm * vecX, vecB); - chol.solve(matB, &matX); - VERIFY_IS_APPROX(symm * matX, matB); - } - -#if 0 // cholesky is not rank-revealing anyway - // test isPositiveDefinite on non definite matrix - if (rows>4) - { - SquareMatrixType symm = a0.block(0,0,rows,cols-4) * a0.block(0,0,rows,cols-4).adjoint(); - LLT chol(symm); - VERIFY(!chol.isPositiveDefinite()); - LDLT cholnosqrt(symm); - VERIFY(!cholnosqrt.isPositiveDefinite()); - } -#endif -} - -void test_eigen2_cholesky() -{ - for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST_1( cholesky(Matrix()) ); - CALL_SUBTEST_2( cholesky(Matrix2d()) ); - CALL_SUBTEST_3( cholesky(Matrix3f()) ); - CALL_SUBTEST_4( cholesky(Matrix4d()) ); - CALL_SUBTEST_5( cholesky(MatrixXcd(7,7)) ); - CALL_SUBTEST_6( cholesky(MatrixXf(17,17)) ); - CALL_SUBTEST_7( cholesky(MatrixXd(33,33)) ); - } -} diff --git a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_commainitializer.cpp b/ground/gcs/src/libs/eigen/test/eigen2/eigen2_commainitializer.cpp deleted file mode 100644 index e0f901e0bd..0000000000 --- a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_commainitializer.cpp +++ /dev/null @@ -1,46 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. Eigen itself is part of the KDE project. -// -// Copyright (C) 2008 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#include "main.h" - -void test_eigen2_commainitializer() -{ - Matrix3d m3; - Matrix4d m4; - - VERIFY_RAISES_ASSERT( (m3 << 1, 2, 3, 4, 5, 6, 7, 8) ); - - #ifndef _MSC_VER - VERIFY_RAISES_ASSERT( (m3 << 1, 2, 3, 4, 5, 6, 7, 8, 9, 10) ); - #endif - - double data[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; - Matrix3d ref = Map >(data); - - m3 = Matrix3d::Random(); - m3 << 1, 2, 3, 4, 5, 6, 7, 8, 9; - VERIFY_IS_APPROX(m3, ref ); - - Vector3d vec[3]; - vec[0] << 1, 4, 7; - vec[1] << 2, 5, 8; - vec[2] << 3, 6, 9; - m3 = Matrix3d::Random(); - m3 << vec[0], vec[1], vec[2]; - VERIFY_IS_APPROX(m3, ref); - - vec[0] << 1, 2, 3; - vec[1] << 4, 5, 6; - vec[2] << 7, 8, 9; - m3 = Matrix3d::Random(); - m3 << vec[0].transpose(), - 4, 5, 6, - vec[2].transpose(); - VERIFY_IS_APPROX(m3, ref); -} diff --git a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_cwiseop.cpp b/ground/gcs/src/libs/eigen/test/eigen2/eigen2_cwiseop.cpp deleted file mode 100644 index 22e1cc3429..0000000000 --- a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_cwiseop.cpp +++ /dev/null @@ -1,155 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. Eigen itself is part of the KDE project. -// -// Copyright (C) 2008 Gael Guennebaud -// Copyright (C) 2006-2008 Benoit Jacob -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#include "main.h" -#include -#include - -using namespace std; - -template struct AddIfNull { - const Scalar operator() (const Scalar a, const Scalar b) const {return a<=1e-3 ? b : a;} - enum { Cost = NumTraits::AddCost }; -}; - -template void cwiseops(const MatrixType& m) -{ - typedef typename MatrixType::Scalar Scalar; - typedef typename NumTraits::Real RealScalar; - typedef Matrix VectorType; - - int rows = m.rows(); - int cols = m.cols(); - - MatrixType m1 = MatrixType::Random(rows, cols), - m2 = MatrixType::Random(rows, cols), - m3(rows, cols), - m4(rows, cols), - mzero = MatrixType::Zero(rows, cols), - mones = MatrixType::Ones(rows, cols), - identity = Matrix - ::Identity(rows, rows); - VectorType vzero = VectorType::Zero(rows), - vones = VectorType::Ones(rows), - v3(rows); - - int r = ei_random(0, rows-1), - c = ei_random(0, cols-1); - - Scalar s1 = ei_random(); - - // test Zero, Ones, Constant, and the set* variants - m3 = MatrixType::Constant(rows, cols, s1); - for (int j=0; j >(mones); - - VERIFY_IS_APPROX(m1.cwise().pow(2), m1.cwise().abs2()); - VERIFY_IS_APPROX(m1.cwise().pow(2), m1.cwise().square()); - VERIFY_IS_APPROX(m1.cwise().pow(3), m1.cwise().cube()); - - VERIFY_IS_APPROX(m1 + mones, m1.cwise()+Scalar(1)); - VERIFY_IS_APPROX(m1 - mones, m1.cwise()-Scalar(1)); - m3 = m1; m3.cwise() += 1; - VERIFY_IS_APPROX(m1 + mones, m3); - m3 = m1; m3.cwise() -= 1; - VERIFY_IS_APPROX(m1 - mones, m3); - - VERIFY_IS_APPROX(m2, m2.cwise() * mones); - VERIFY_IS_APPROX(m1.cwise() * m2, m2.cwise() * m1); - m3 = m1; - m3.cwise() *= m2; - VERIFY_IS_APPROX(m3, m1.cwise() * m2); - - VERIFY_IS_APPROX(mones, m2.cwise()/m2); - if(NumTraits::HasFloatingPoint) - { - VERIFY_IS_APPROX(m1.cwise() / m2, m1.cwise() * (m2.cwise().inverse())); - m3 = m1.cwise().abs().cwise().sqrt(); - VERIFY_IS_APPROX(m3.cwise().square(), m1.cwise().abs()); - VERIFY_IS_APPROX(m1.cwise().square().cwise().sqrt(), m1.cwise().abs()); - VERIFY_IS_APPROX(m1.cwise().abs().cwise().log().cwise().exp() , m1.cwise().abs()); - - VERIFY_IS_APPROX(m1.cwise().pow(2), m1.cwise().square()); - m3 = (m1.cwise().abs().cwise()<=RealScalar(0.01)).select(mones,m1); - VERIFY_IS_APPROX(m3.cwise().pow(-1), m3.cwise().inverse()); - m3 = m1.cwise().abs(); - VERIFY_IS_APPROX(m3.cwise().pow(RealScalar(0.5)), m3.cwise().sqrt()); - -// VERIFY_IS_APPROX(m1.cwise().tan(), m1.cwise().sin().cwise() / m1.cwise().cos()); - VERIFY_IS_APPROX(mones, m1.cwise().sin().cwise().square() + m1.cwise().cos().cwise().square()); - m3 = m1; - m3.cwise() /= m2; - VERIFY_IS_APPROX(m3, m1.cwise() / m2); - } - - // check min - VERIFY_IS_APPROX( m1.cwise().min(m2), m2.cwise().min(m1) ); - VERIFY_IS_APPROX( m1.cwise().min(m1+mones), m1 ); - VERIFY_IS_APPROX( m1.cwise().min(m1-mones), m1-mones ); - - // check max - VERIFY_IS_APPROX( m1.cwise().max(m2), m2.cwise().max(m1) ); - VERIFY_IS_APPROX( m1.cwise().max(m1-mones), m1 ); - VERIFY_IS_APPROX( m1.cwise().max(m1+mones), m1+mones ); - - VERIFY( (m1.cwise() == m1).all() ); - VERIFY( (m1.cwise() != m2).any() ); - VERIFY(!(m1.cwise() == (m1+mones)).any() ); - if (rows*cols>1) - { - m3 = m1; - m3(r,c) += 1; - VERIFY( (m1.cwise() == m3).any() ); - VERIFY( !(m1.cwise() == m3).all() ); - } - VERIFY( (m1.cwise().min(m2).cwise() <= m2).all() ); - VERIFY( (m1.cwise().max(m2).cwise() >= m2).all() ); - VERIFY( (m1.cwise().min(m2).cwise() < (m1+mones)).all() ); - VERIFY( (m1.cwise().max(m2).cwise() > (m1-mones)).all() ); - - VERIFY( (m1.cwise()(), Scalar(1)))).all() ); - VERIFY( !(m1.cwise()(), Scalar(1)))).all() ); - VERIFY( !(m1.cwise()>m1.unaryExpr(bind2nd(plus(), Scalar(1)))).any() ); -} - -void test_eigen2_cwiseop() -{ - for(int i = 0; i < g_repeat ; i++) { - CALL_SUBTEST_1( cwiseops(Matrix()) ); - CALL_SUBTEST_2( cwiseops(Matrix4d()) ); - CALL_SUBTEST_3( cwiseops(MatrixXf(3, 3)) ); - CALL_SUBTEST_3( cwiseops(MatrixXf(22, 22)) ); - CALL_SUBTEST_4( cwiseops(MatrixXi(8, 12)) ); - CALL_SUBTEST_5( cwiseops(MatrixXd(20, 20)) ); - } -} diff --git a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_determinant.cpp b/ground/gcs/src/libs/eigen/test/eigen2/eigen2_determinant.cpp deleted file mode 100644 index c7b4ad0533..0000000000 --- a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_determinant.cpp +++ /dev/null @@ -1,61 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. Eigen itself is part of the KDE project. -// -// Copyright (C) 2008 Benoit Jacob -// Copyright (C) 2008 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#include "main.h" -#include - -template void determinant(const MatrixType& m) -{ - /* this test covers the following files: - Determinant.h - */ - int size = m.rows(); - - MatrixType m1(size, size), m2(size, size); - m1.setRandom(); - m2.setRandom(); - typedef typename MatrixType::Scalar Scalar; - Scalar x = ei_random(); - VERIFY_IS_APPROX(MatrixType::Identity(size, size).determinant(), Scalar(1)); - VERIFY_IS_APPROX((m1*m2).determinant(), m1.determinant() * m2.determinant()); - if(size==1) return; - int i = ei_random(0, size-1); - int j; - do { - j = ei_random(0, size-1); - } while(j==i); - m2 = m1; - m2.row(i).swap(m2.row(j)); - VERIFY_IS_APPROX(m2.determinant(), -m1.determinant()); - m2 = m1; - m2.col(i).swap(m2.col(j)); - VERIFY_IS_APPROX(m2.determinant(), -m1.determinant()); - VERIFY_IS_APPROX(m2.determinant(), m2.transpose().determinant()); - VERIFY_IS_APPROX(ei_conj(m2.determinant()), m2.adjoint().determinant()); - m2 = m1; - m2.row(i) += x*m2.row(j); - VERIFY_IS_APPROX(m2.determinant(), m1.determinant()); - m2 = m1; - m2.row(i) *= x; - VERIFY_IS_APPROX(m2.determinant(), m1.determinant() * x); -} - -void test_eigen2_determinant() -{ - for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST_1( determinant(Matrix()) ); - CALL_SUBTEST_2( determinant(Matrix()) ); - CALL_SUBTEST_3( determinant(Matrix()) ); - CALL_SUBTEST_4( determinant(Matrix()) ); - CALL_SUBTEST_5( determinant(Matrix, 10, 10>()) ); - CALL_SUBTEST_6( determinant(MatrixXd(20, 20)) ); - } - CALL_SUBTEST_6( determinant(MatrixXd(200, 200)) ); -} diff --git a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_dynalloc.cpp b/ground/gcs/src/libs/eigen/test/eigen2/eigen2_dynalloc.cpp deleted file mode 100644 index 1891a9e333..0000000000 --- a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_dynalloc.cpp +++ /dev/null @@ -1,131 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. Eigen itself is part of the KDE project. -// -// Copyright (C) 2008 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#include "main.h" - -#if EIGEN_ARCH_WANTS_ALIGNMENT -#define ALIGNMENT 16 -#else -#define ALIGNMENT 1 -#endif - -void check_handmade_aligned_malloc() -{ - for(int i = 1; i < 1000; i++) - { - char *p = (char*)ei_handmade_aligned_malloc(i); - VERIFY(std::size_t(p)%ALIGNMENT==0); - // if the buffer is wrongly allocated this will give a bad write --> check with valgrind - for(int j = 0; j < i; j++) p[j]=0; - ei_handmade_aligned_free(p); - } -} - -void check_aligned_malloc() -{ - for(int i = 1; i < 1000; i++) - { - char *p = (char*)ei_aligned_malloc(i); - VERIFY(std::size_t(p)%ALIGNMENT==0); - // if the buffer is wrongly allocated this will give a bad write --> check with valgrind - for(int j = 0; j < i; j++) p[j]=0; - ei_aligned_free(p); - } -} - -void check_aligned_new() -{ - for(int i = 1; i < 1000; i++) - { - float *p = ei_aligned_new(i); - VERIFY(std::size_t(p)%ALIGNMENT==0); - // if the buffer is wrongly allocated this will give a bad write --> check with valgrind - for(int j = 0; j < i; j++) p[j]=0; - ei_aligned_delete(p,i); - } -} - -void check_aligned_stack_alloc() -{ - for(int i = 1; i < 1000; i++) - { - ei_declare_aligned_stack_constructed_variable(float, p, i, 0); - VERIFY(std::size_t(p)%ALIGNMENT==0); - // if the buffer is wrongly allocated this will give a bad write --> check with valgrind - for(int j = 0; j < i; j++) p[j]=0; - } -} - - -// test compilation with both a struct and a class... -struct MyStruct -{ - EIGEN_MAKE_ALIGNED_OPERATOR_NEW - char dummychar; - Vector4f avec; -}; - -class MyClassA -{ - public: - EIGEN_MAKE_ALIGNED_OPERATOR_NEW - char dummychar; - Vector4f avec; -}; - -template void check_dynaligned() -{ - T* obj = new T; - VERIFY(std::size_t(obj)%ALIGNMENT==0); - delete obj; -} - -void test_eigen2_dynalloc() -{ - // low level dynamic memory allocation - CALL_SUBTEST(check_handmade_aligned_malloc()); - CALL_SUBTEST(check_aligned_malloc()); - CALL_SUBTEST(check_aligned_new()); - CALL_SUBTEST(check_aligned_stack_alloc()); - - for (int i=0; i() ); - CALL_SUBTEST( check_dynaligned() ); - CALL_SUBTEST( check_dynaligned() ); - CALL_SUBTEST( check_dynaligned() ); - CALL_SUBTEST( check_dynaligned() ); - } - - // check static allocation, who knows ? - { - MyStruct foo0; VERIFY(std::size_t(foo0.avec.data())%ALIGNMENT==0); - MyClassA fooA; VERIFY(std::size_t(fooA.avec.data())%ALIGNMENT==0); - } - - // dynamic allocation, single object - for (int i=0; iavec.data())%ALIGNMENT==0); - MyClassA *fooA = new MyClassA(); VERIFY(std::size_t(fooA->avec.data())%ALIGNMENT==0); - delete foo0; - delete fooA; - } - - // dynamic allocation, array - const int N = 10; - for (int i=0; iavec.data())%ALIGNMENT==0); - MyClassA *fooA = new MyClassA[N]; VERIFY(std::size_t(fooA->avec.data())%ALIGNMENT==0); - delete[] foo0; - delete[] fooA; - } - -} diff --git a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_eigensolver.cpp b/ground/gcs/src/libs/eigen/test/eigen2/eigen2_eigensolver.cpp deleted file mode 100644 index 48b4ace436..0000000000 --- a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_eigensolver.cpp +++ /dev/null @@ -1,146 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. Eigen itself is part of the KDE project. -// -// Copyright (C) 2008 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#include "main.h" -#include - -#ifdef HAS_GSL -#include "gsl_helper.h" -#endif - -template void selfadjointeigensolver(const MatrixType& m) -{ - /* this test covers the following files: - EigenSolver.h, SelfAdjointEigenSolver.h (and indirectly: Tridiagonalization.h) - */ - int rows = m.rows(); - int cols = m.cols(); - - typedef typename MatrixType::Scalar Scalar; - typedef typename NumTraits::Real RealScalar; - typedef Matrix VectorType; - typedef Matrix RealVectorType; - typedef typename std::complex::Real> Complex; - - RealScalar largerEps = 10*test_precision(); - - MatrixType a = MatrixType::Random(rows,cols); - MatrixType a1 = MatrixType::Random(rows,cols); - MatrixType symmA = a.adjoint() * a + a1.adjoint() * a1; - - MatrixType b = MatrixType::Random(rows,cols); - MatrixType b1 = MatrixType::Random(rows,cols); - MatrixType symmB = b.adjoint() * b + b1.adjoint() * b1; - - SelfAdjointEigenSolver eiSymm(symmA); - // generalized eigen pb - SelfAdjointEigenSolver eiSymmGen(symmA, symmB); - - #ifdef HAS_GSL - if (ei_is_same_type::ret) - { - typedef GslTraits Gsl; - typename Gsl::Matrix gEvec=0, gSymmA=0, gSymmB=0; - typename GslTraits::Vector gEval=0; - RealVectorType _eval; - MatrixType _evec; - convert(symmA, gSymmA); - convert(symmB, gSymmB); - convert(symmA, gEvec); - gEval = GslTraits::createVector(rows); - - Gsl::eigen_symm(gSymmA, gEval, gEvec); - convert(gEval, _eval); - convert(gEvec, _evec); - - // test gsl itself ! - VERIFY((symmA * _evec).isApprox(_evec * _eval.asDiagonal(), largerEps)); - - // compare with eigen - VERIFY_IS_APPROX(_eval, eiSymm.eigenvalues()); - VERIFY_IS_APPROX(_evec.cwise().abs(), eiSymm.eigenvectors().cwise().abs()); - - // generalized pb - Gsl::eigen_symm_gen(gSymmA, gSymmB, gEval, gEvec); - convert(gEval, _eval); - convert(gEvec, _evec); - // test GSL itself: - VERIFY((symmA * _evec).isApprox(symmB * (_evec * _eval.asDiagonal()), largerEps)); - - // compare with eigen - MatrixType normalized_eivec = eiSymmGen.eigenvectors()*eiSymmGen.eigenvectors().colwise().norm().asDiagonal().inverse(); - VERIFY_IS_APPROX(_eval, eiSymmGen.eigenvalues()); - VERIFY_IS_APPROX(_evec.cwiseAbs(), normalized_eivec.cwiseAbs()); - - Gsl::free(gSymmA); - Gsl::free(gSymmB); - GslTraits::free(gEval); - Gsl::free(gEvec); - } - #endif - - VERIFY((symmA * eiSymm.eigenvectors()).isApprox( - eiSymm.eigenvectors() * eiSymm.eigenvalues().asDiagonal(), largerEps)); - - // generalized eigen problem Ax = lBx - VERIFY((symmA * eiSymmGen.eigenvectors()).isApprox( - symmB * (eiSymmGen.eigenvectors() * eiSymmGen.eigenvalues().asDiagonal()), largerEps)); - - MatrixType sqrtSymmA = eiSymm.operatorSqrt(); - VERIFY_IS_APPROX(symmA, sqrtSymmA*sqrtSymmA); - VERIFY_IS_APPROX(sqrtSymmA, symmA*eiSymm.operatorInverseSqrt()); -} - -template void eigensolver(const MatrixType& m) -{ - /* this test covers the following files: - EigenSolver.h - */ - int rows = m.rows(); - int cols = m.cols(); - - typedef typename MatrixType::Scalar Scalar; - typedef typename NumTraits::Real RealScalar; - typedef Matrix VectorType; - typedef Matrix RealVectorType; - typedef typename std::complex::Real> Complex; - - // RealScalar largerEps = 10*test_precision(); - - MatrixType a = MatrixType::Random(rows,cols); - MatrixType a1 = MatrixType::Random(rows,cols); - MatrixType symmA = a.adjoint() * a + a1.adjoint() * a1; - - EigenSolver ei0(symmA); - VERIFY_IS_APPROX(symmA * ei0.pseudoEigenvectors(), ei0.pseudoEigenvectors() * ei0.pseudoEigenvalueMatrix()); - VERIFY_IS_APPROX((symmA.template cast()) * (ei0.pseudoEigenvectors().template cast()), - (ei0.pseudoEigenvectors().template cast()) * (ei0.eigenvalues().asDiagonal())); - - EigenSolver ei1(a); - VERIFY_IS_APPROX(a * ei1.pseudoEigenvectors(), ei1.pseudoEigenvectors() * ei1.pseudoEigenvalueMatrix()); - VERIFY_IS_APPROX(a.template cast() * ei1.eigenvectors(), - ei1.eigenvectors() * ei1.eigenvalues().asDiagonal()); - -} - -void test_eigen2_eigensolver() -{ - for(int i = 0; i < g_repeat; i++) { - // very important to test a 3x3 matrix since we provide a special path for it - CALL_SUBTEST_1( selfadjointeigensolver(Matrix3f()) ); - CALL_SUBTEST_2( selfadjointeigensolver(Matrix4d()) ); - CALL_SUBTEST_3( selfadjointeigensolver(MatrixXf(7,7)) ); - CALL_SUBTEST_4( selfadjointeigensolver(MatrixXcd(5,5)) ); - CALL_SUBTEST_5( selfadjointeigensolver(MatrixXd(19,19)) ); - - CALL_SUBTEST_6( eigensolver(Matrix4f()) ); - CALL_SUBTEST_5( eigensolver(MatrixXd(17,17)) ); - } -} - diff --git a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_first_aligned.cpp b/ground/gcs/src/libs/eigen/test/eigen2/eigen2_first_aligned.cpp deleted file mode 100644 index 51bb3cad13..0000000000 --- a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_first_aligned.cpp +++ /dev/null @@ -1,49 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2009 Benoit Jacob -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#include "main.h" - -template -void test_eigen2_first_aligned_helper(Scalar *array, int size) -{ - const int packet_size = sizeof(Scalar) * ei_packet_traits::size; - VERIFY(((std::size_t(array) + sizeof(Scalar) * ei_alignmentOffset(array, size)) % packet_size) == 0); -} - -template -void test_eigen2_none_aligned_helper(Scalar *array, int size) -{ - VERIFY(ei_packet_traits::size == 1 || ei_alignmentOffset(array, size) == size); -} - -struct some_non_vectorizable_type { float x; }; - -void test_eigen2_first_aligned() -{ - EIGEN_ALIGN_128 float array_float[100]; - test_first_aligned_helper(array_float, 50); - test_first_aligned_helper(array_float+1, 50); - test_first_aligned_helper(array_float+2, 50); - test_first_aligned_helper(array_float+3, 50); - test_first_aligned_helper(array_float+4, 50); - test_first_aligned_helper(array_float+5, 50); - - EIGEN_ALIGN_128 double array_double[100]; - test_first_aligned_helper(array_double, 50); - test_first_aligned_helper(array_double+1, 50); - test_first_aligned_helper(array_double+2, 50); - - double *array_double_plus_4_bytes = (double*)(std::size_t(array_double)+4); - test_none_aligned_helper(array_double_plus_4_bytes, 50); - test_none_aligned_helper(array_double_plus_4_bytes+1, 50); - - some_non_vectorizable_type array_nonvec[100]; - test_first_aligned_helper(array_nonvec, 100); - test_none_aligned_helper(array_nonvec, 100); -} diff --git a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_geometry.cpp b/ground/gcs/src/libs/eigen/test/eigen2/eigen2_geometry.cpp deleted file mode 100644 index 5140407740..0000000000 --- a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_geometry.cpp +++ /dev/null @@ -1,432 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. Eigen itself is part of the KDE project. -// -// Copyright (C) 2008 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#include "main.h" -#include -#include -#include - -template void geometry(void) -{ - /* this test covers the following files: - Cross.h Quaternion.h, Transform.cpp - */ - - typedef Matrix Matrix2; - typedef Matrix Matrix3; - typedef Matrix Matrix4; - typedef Matrix Vector2; - typedef Matrix Vector3; - typedef Matrix Vector4; - typedef Quaternion Quaternionx; - typedef AngleAxis AngleAxisx; - typedef Transform Transform2; - typedef Transform Transform3; - typedef Scaling Scaling2; - typedef Scaling Scaling3; - typedef Translation Translation2; - typedef Translation Translation3; - - Scalar largeEps = test_precision(); - if (ei_is_same_type::ret) - largeEps = 1e-2f; - - Vector3 v0 = Vector3::Random(), - v1 = Vector3::Random(), - v2 = Vector3::Random(); - Vector2 u0 = Vector2::Random(); - Matrix3 matrot1; - - Scalar a = ei_random(-Scalar(M_PI), Scalar(M_PI)); - - // cross product - VERIFY_IS_MUCH_SMALLER_THAN(v1.cross(v2).eigen2_dot(v1), Scalar(1)); - Matrix3 m; - m << v0.normalized(), - (v0.cross(v1)).normalized(), - (v0.cross(v1).cross(v0)).normalized(); - VERIFY(m.isUnitary()); - - // Quaternion: Identity(), setIdentity(); - Quaternionx q1, q2; - q2.setIdentity(); - VERIFY_IS_APPROX(Quaternionx(Quaternionx::Identity()).coeffs(), q2.coeffs()); - q1.coeffs().setRandom(); - VERIFY_IS_APPROX(q1.coeffs(), (q1*q2).coeffs()); - - // unitOrthogonal - VERIFY_IS_MUCH_SMALLER_THAN(u0.unitOrthogonal().eigen2_dot(u0), Scalar(1)); - VERIFY_IS_MUCH_SMALLER_THAN(v0.unitOrthogonal().eigen2_dot(v0), Scalar(1)); - VERIFY_IS_APPROX(u0.unitOrthogonal().norm(), Scalar(1)); - VERIFY_IS_APPROX(v0.unitOrthogonal().norm(), Scalar(1)); - - - VERIFY_IS_APPROX(v0, AngleAxisx(a, v0.normalized()) * v0); - VERIFY_IS_APPROX(-v0, AngleAxisx(Scalar(M_PI), v0.unitOrthogonal()) * v0); - VERIFY_IS_APPROX(ei_cos(a)*v0.squaredNorm(), v0.eigen2_dot(AngleAxisx(a, v0.unitOrthogonal()) * v0)); - m = AngleAxisx(a, v0.normalized()).toRotationMatrix().adjoint(); - VERIFY_IS_APPROX(Matrix3::Identity(), m * AngleAxisx(a, v0.normalized())); - VERIFY_IS_APPROX(Matrix3::Identity(), AngleAxisx(a, v0.normalized()) * m); - - q1 = AngleAxisx(a, v0.normalized()); - q2 = AngleAxisx(a, v1.normalized()); - - // angular distance - Scalar refangle = ei_abs(AngleAxisx(q1.inverse()*q2).angle()); - if (refangle>Scalar(M_PI)) - refangle = Scalar(2)*Scalar(M_PI) - refangle; - - if((q1.coeffs()-q2.coeffs()).norm() > 10*largeEps) - { - VERIFY(ei_isApprox(q1.angularDistance(q2), refangle, largeEps)); - } - - // rotation matrix conversion - VERIFY_IS_APPROX(q1 * v2, q1.toRotationMatrix() * v2); - VERIFY_IS_APPROX(q1 * q2 * v2, - q1.toRotationMatrix() * q2.toRotationMatrix() * v2); - - VERIFY( (q2*q1).isApprox(q1*q2, largeEps) || !(q2 * q1 * v2).isApprox( - q1.toRotationMatrix() * q2.toRotationMatrix() * v2)); - - q2 = q1.toRotationMatrix(); - VERIFY_IS_APPROX(q1*v1,q2*v1); - - matrot1 = AngleAxisx(Scalar(0.1), Vector3::UnitX()) - * AngleAxisx(Scalar(0.2), Vector3::UnitY()) - * AngleAxisx(Scalar(0.3), Vector3::UnitZ()); - VERIFY_IS_APPROX(matrot1 * v1, - AngleAxisx(Scalar(0.1), Vector3(1,0,0)).toRotationMatrix() - * (AngleAxisx(Scalar(0.2), Vector3(0,1,0)).toRotationMatrix() - * (AngleAxisx(Scalar(0.3), Vector3(0,0,1)).toRotationMatrix() * v1))); - - // angle-axis conversion - AngleAxisx aa = q1; - VERIFY_IS_APPROX(q1 * v1, Quaternionx(aa) * v1); - VERIFY_IS_NOT_APPROX(q1 * v1, Quaternionx(AngleAxisx(aa.angle()*2,aa.axis())) * v1); - - // from two vector creation - VERIFY_IS_APPROX(v2.normalized(),(q2.setFromTwoVectors(v1,v2)*v1).normalized()); - VERIFY_IS_APPROX(v2.normalized(),(q2.setFromTwoVectors(v1,v2)*v1).normalized()); - - // inverse and conjugate - VERIFY_IS_APPROX(q1 * (q1.inverse() * v1), v1); - VERIFY_IS_APPROX(q1 * (q1.conjugate() * v1), v1); - - // AngleAxis - VERIFY_IS_APPROX(AngleAxisx(a,v1.normalized()).toRotationMatrix(), - Quaternionx(AngleAxisx(a,v1.normalized())).toRotationMatrix()); - - AngleAxisx aa1; - m = q1.toRotationMatrix(); - aa1 = m; - VERIFY_IS_APPROX(AngleAxisx(m).toRotationMatrix(), - Quaternionx(m).toRotationMatrix()); - - // Transform - // TODO complete the tests ! - a = 0; - while (ei_abs(a)(-Scalar(0.4)*Scalar(M_PI), Scalar(0.4)*Scalar(M_PI)); - q1 = AngleAxisx(a, v0.normalized()); - Transform3 t0, t1, t2; - // first test setIdentity() and Identity() - t0.setIdentity(); - VERIFY_IS_APPROX(t0.matrix(), Transform3::MatrixType::Identity()); - t0.matrix().setZero(); - t0 = Transform3::Identity(); - VERIFY_IS_APPROX(t0.matrix(), Transform3::MatrixType::Identity()); - - t0.linear() = q1.toRotationMatrix(); - t1.setIdentity(); - t1.linear() = q1.toRotationMatrix(); - - v0 << 50, 2, 1;//= ei_random_matrix().cwiseProduct(Vector3(10,2,0.5)); - t0.scale(v0); - t1.prescale(v0); - - VERIFY_IS_APPROX( (t0 * Vector3(1,0,0)).norm(), v0.x()); - //VERIFY(!ei_isApprox((t1 * Vector3(1,0,0)).norm(), v0.x())); - - t0.setIdentity(); - t1.setIdentity(); - v1 << 1, 2, 3; - t0.linear() = q1.toRotationMatrix(); - t0.pretranslate(v0); - t0.scale(v1); - t1.linear() = q1.conjugate().toRotationMatrix(); - t1.prescale(v1.cwise().inverse()); - t1.translate(-v0); - - VERIFY((t0.matrix() * t1.matrix()).isIdentity(test_precision())); - - t1.fromPositionOrientationScale(v0, q1, v1); - VERIFY_IS_APPROX(t1.matrix(), t0.matrix()); - VERIFY_IS_APPROX(t1*v1, t0*v1); - - t0.setIdentity(); t0.scale(v0).rotate(q1.toRotationMatrix()); - t1.setIdentity(); t1.scale(v0).rotate(q1); - VERIFY_IS_APPROX(t0.matrix(), t1.matrix()); - - t0.setIdentity(); t0.scale(v0).rotate(AngleAxisx(q1)); - VERIFY_IS_APPROX(t0.matrix(), t1.matrix()); - - VERIFY_IS_APPROX(t0.scale(a).matrix(), t1.scale(Vector3::Constant(a)).matrix()); - VERIFY_IS_APPROX(t0.prescale(a).matrix(), t1.prescale(Vector3::Constant(a)).matrix()); - - // More transform constructors, operator=, operator*= - - Matrix3 mat3 = Matrix3::Random(); - Matrix4 mat4; - mat4 << mat3 , Vector3::Zero() , Vector4::Zero().transpose(); - Transform3 tmat3(mat3), tmat4(mat4); - tmat4.matrix()(3,3) = Scalar(1); - VERIFY_IS_APPROX(tmat3.matrix(), tmat4.matrix()); - - Scalar a3 = ei_random(-Scalar(M_PI), Scalar(M_PI)); - Vector3 v3 = Vector3::Random().normalized(); - AngleAxisx aa3(a3, v3); - Transform3 t3(aa3); - Transform3 t4; - t4 = aa3; - VERIFY_IS_APPROX(t3.matrix(), t4.matrix()); - t4.rotate(AngleAxisx(-a3,v3)); - VERIFY_IS_APPROX(t4.matrix(), Matrix4::Identity()); - t4 *= aa3; - VERIFY_IS_APPROX(t3.matrix(), t4.matrix()); - - v3 = Vector3::Random(); - Translation3 tv3(v3); - Transform3 t5(tv3); - t4 = tv3; - VERIFY_IS_APPROX(t5.matrix(), t4.matrix()); - t4.translate(-v3); - VERIFY_IS_APPROX(t4.matrix(), Matrix4::Identity()); - t4 *= tv3; - VERIFY_IS_APPROX(t5.matrix(), t4.matrix()); - - Scaling3 sv3(v3); - Transform3 t6(sv3); - t4 = sv3; - VERIFY_IS_APPROX(t6.matrix(), t4.matrix()); - t4.scale(v3.cwise().inverse()); - VERIFY_IS_APPROX(t4.matrix(), Matrix4::Identity()); - t4 *= sv3; - VERIFY_IS_APPROX(t6.matrix(), t4.matrix()); - - // matrix * transform - VERIFY_IS_APPROX(Transform3(t3.matrix()*t4).matrix(), Transform3(t3*t4).matrix()); - - // chained Transform product - VERIFY_IS_APPROX(((t3*t4)*t5).matrix(), (t3*(t4*t5)).matrix()); - - // check that Transform product doesn't have aliasing problems - t5 = t4; - t5 = t5*t5; - VERIFY_IS_APPROX(t5, t4*t4); - - // 2D transformation - Transform2 t20, t21; - Vector2 v20 = Vector2::Random(); - Vector2 v21 = Vector2::Random(); - for (int k=0; k<2; ++k) - if (ei_abs(v21[k])(a).toRotationMatrix(); - VERIFY_IS_APPROX(t20.fromPositionOrientationScale(v20,a,v21).matrix(), - t21.pretranslate(v20).scale(v21).matrix()); - - t21.setIdentity(); - t21.linear() = Rotation2D(-a).toRotationMatrix(); - VERIFY( (t20.fromPositionOrientationScale(v20,a,v21) - * (t21.prescale(v21.cwise().inverse()).translate(-v20))).matrix().isIdentity(test_precision()) ); - - // Transform - new API - // 3D - t0.setIdentity(); - t0.rotate(q1).scale(v0).translate(v0); - // mat * scaling and mat * translation - t1 = (Matrix3(q1) * Scaling3(v0)) * Translation3(v0); - VERIFY_IS_APPROX(t0.matrix(), t1.matrix()); - // mat * transformation and scaling * translation - t1 = Matrix3(q1) * (Scaling3(v0) * Translation3(v0)); - VERIFY_IS_APPROX(t0.matrix(), t1.matrix()); - - t0.setIdentity(); - t0.prerotate(q1).prescale(v0).pretranslate(v0); - // translation * scaling and transformation * mat - t1 = (Translation3(v0) * Scaling3(v0)) * Matrix3(q1); - VERIFY_IS_APPROX(t0.matrix(), t1.matrix()); - // scaling * mat and translation * mat - t1 = Translation3(v0) * (Scaling3(v0) * Matrix3(q1)); - VERIFY_IS_APPROX(t0.matrix(), t1.matrix()); - - t0.setIdentity(); - t0.scale(v0).translate(v0).rotate(q1); - // translation * mat and scaling * transformation - t1 = Scaling3(v0) * (Translation3(v0) * Matrix3(q1)); - VERIFY_IS_APPROX(t0.matrix(), t1.matrix()); - // transformation * scaling - t0.scale(v0); - t1 = t1 * Scaling3(v0); - VERIFY_IS_APPROX(t0.matrix(), t1.matrix()); - // transformation * translation - t0.translate(v0); - t1 = t1 * Translation3(v0); - VERIFY_IS_APPROX(t0.matrix(), t1.matrix()); - // translation * transformation - t0.pretranslate(v0); - t1 = Translation3(v0) * t1; - VERIFY_IS_APPROX(t0.matrix(), t1.matrix()); - - // transform * quaternion - t0.rotate(q1); - t1 = t1 * q1; - VERIFY_IS_APPROX(t0.matrix(), t1.matrix()); - - // translation * quaternion - t0.translate(v1).rotate(q1); - t1 = t1 * (Translation3(v1) * q1); - VERIFY_IS_APPROX(t0.matrix(), t1.matrix()); - - // scaling * quaternion - t0.scale(v1).rotate(q1); - t1 = t1 * (Scaling3(v1) * q1); - VERIFY_IS_APPROX(t0.matrix(), t1.matrix()); - - // quaternion * transform - t0.prerotate(q1); - t1 = q1 * t1; - VERIFY_IS_APPROX(t0.matrix(), t1.matrix()); - - // quaternion * translation - t0.rotate(q1).translate(v1); - t1 = t1 * (q1 * Translation3(v1)); - VERIFY_IS_APPROX(t0.matrix(), t1.matrix()); - - // quaternion * scaling - t0.rotate(q1).scale(v1); - t1 = t1 * (q1 * Scaling3(v1)); - VERIFY_IS_APPROX(t0.matrix(), t1.matrix()); - - // translation * vector - t0.setIdentity(); - t0.translate(v0); - VERIFY_IS_APPROX(t0 * v1, Translation3(v0) * v1); - - // scaling * vector - t0.setIdentity(); - t0.scale(v0); - VERIFY_IS_APPROX(t0 * v1, Scaling3(v0) * v1); - - // test transform inversion - t0.setIdentity(); - t0.translate(v0); - t0.linear().setRandom(); - VERIFY_IS_APPROX(t0.inverse(Affine), t0.matrix().inverse()); - t0.setIdentity(); - t0.translate(v0).rotate(q1); - VERIFY_IS_APPROX(t0.inverse(Isometry), t0.matrix().inverse()); - - // test extract rotation and scaling - t0.setIdentity(); - t0.translate(v0).rotate(q1).scale(v1); - VERIFY_IS_APPROX(t0.rotation() * v1, Matrix3(q1) * v1); - - Matrix3 mat_rotation, mat_scaling; - t0.setIdentity(); - t0.translate(v0).rotate(q1).scale(v1); - t0.computeRotationScaling(&mat_rotation, &mat_scaling); - VERIFY_IS_APPROX(t0.linear(), mat_rotation * mat_scaling); - VERIFY_IS_APPROX(mat_rotation*mat_rotation.adjoint(), Matrix3::Identity()); - VERIFY_IS_APPROX(mat_rotation.determinant(), Scalar(1)); - t0.computeScalingRotation(&mat_scaling, &mat_rotation); - VERIFY_IS_APPROX(t0.linear(), mat_scaling * mat_rotation); - VERIFY_IS_APPROX(mat_rotation*mat_rotation.adjoint(), Matrix3::Identity()); - VERIFY_IS_APPROX(mat_rotation.determinant(), Scalar(1)); - - // test casting - Transform t1f = t1.template cast(); - VERIFY_IS_APPROX(t1f.template cast(),t1); - Transform t1d = t1.template cast(); - VERIFY_IS_APPROX(t1d.template cast(),t1); - - Translation3 tr1(v0); - Translation tr1f = tr1.template cast(); - VERIFY_IS_APPROX(tr1f.template cast(),tr1); - Translation tr1d = tr1.template cast(); - VERIFY_IS_APPROX(tr1d.template cast(),tr1); - - Scaling3 sc1(v0); - Scaling sc1f = sc1.template cast(); - VERIFY_IS_APPROX(sc1f.template cast(),sc1); - Scaling sc1d = sc1.template cast(); - VERIFY_IS_APPROX(sc1d.template cast(),sc1); - - Quaternion q1f = q1.template cast(); - VERIFY_IS_APPROX(q1f.template cast(),q1); - Quaternion q1d = q1.template cast(); - VERIFY_IS_APPROX(q1d.template cast(),q1); - - AngleAxis aa1f = aa1.template cast(); - VERIFY_IS_APPROX(aa1f.template cast(),aa1); - AngleAxis aa1d = aa1.template cast(); - VERIFY_IS_APPROX(aa1d.template cast(),aa1); - - Rotation2D r2d1(ei_random()); - Rotation2D r2d1f = r2d1.template cast(); - VERIFY_IS_APPROX(r2d1f.template cast(),r2d1); - Rotation2D r2d1d = r2d1.template cast(); - VERIFY_IS_APPROX(r2d1d.template cast(),r2d1); - - m = q1; -// m.col(1) = Vector3(0,ei_random(),ei_random()).normalized(); -// m.col(0) = Vector3(-1,0,0).normalized(); -// m.col(2) = m.col(0).cross(m.col(1)); - #define VERIFY_EULER(I,J,K, X,Y,Z) { \ - Vector3 ea = m.eulerAngles(I,J,K); \ - Matrix3 m1 = Matrix3(AngleAxisx(ea[0], Vector3::Unit##X()) * AngleAxisx(ea[1], Vector3::Unit##Y()) * AngleAxisx(ea[2], Vector3::Unit##Z())); \ - VERIFY_IS_APPROX(m, m1); \ - VERIFY_IS_APPROX(m, Matrix3(AngleAxisx(ea[0], Vector3::Unit##X()) * AngleAxisx(ea[1], Vector3::Unit##Y()) * AngleAxisx(ea[2], Vector3::Unit##Z()))); \ - } - VERIFY_EULER(0,1,2, X,Y,Z); - VERIFY_EULER(0,1,0, X,Y,X); - VERIFY_EULER(0,2,1, X,Z,Y); - VERIFY_EULER(0,2,0, X,Z,X); - - VERIFY_EULER(1,2,0, Y,Z,X); - VERIFY_EULER(1,2,1, Y,Z,Y); - VERIFY_EULER(1,0,2, Y,X,Z); - VERIFY_EULER(1,0,1, Y,X,Y); - - VERIFY_EULER(2,0,1, Z,X,Y); - VERIFY_EULER(2,0,2, Z,X,Z); - VERIFY_EULER(2,1,0, Z,Y,X); - VERIFY_EULER(2,1,2, Z,Y,Z); - - // colwise/rowwise cross product - mat3.setRandom(); - Vector3 vec3 = Vector3::Random(); - Matrix3 mcross; - int i = ei_random(0,2); - mcross = mat3.colwise().cross(vec3); - VERIFY_IS_APPROX(mcross.col(i), mat3.col(i).cross(vec3)); - mcross = mat3.rowwise().cross(vec3); - VERIFY_IS_APPROX(mcross.row(i), mat3.row(i).cross(vec3)); - - -} - -void test_eigen2_geometry() -{ - for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST_1( geometry() ); - CALL_SUBTEST_2( geometry() ); - } -} diff --git a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_geometry_with_eigen2_prefix.cpp b/ground/gcs/src/libs/eigen/test/eigen2/eigen2_geometry_with_eigen2_prefix.cpp deleted file mode 100644 index 12d4a71c3c..0000000000 --- a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_geometry_with_eigen2_prefix.cpp +++ /dev/null @@ -1,435 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. Eigen itself is part of the KDE project. -// -// Copyright (C) 2008 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#define EIGEN2_SUPPORT_STAGE15_RESOLVE_API_CONFLICTS_WARN - -#include "main.h" -#include -#include -#include - -template void geometry(void) -{ - /* this test covers the following files: - Cross.h Quaternion.h, Transform.cpp - */ - - typedef Matrix Matrix2; - typedef Matrix Matrix3; - typedef Matrix Matrix4; - typedef Matrix Vector2; - typedef Matrix Vector3; - typedef Matrix Vector4; - typedef eigen2_Quaternion Quaternionx; - typedef eigen2_AngleAxis AngleAxisx; - typedef eigen2_Transform Transform2; - typedef eigen2_Transform Transform3; - typedef eigen2_Scaling Scaling2; - typedef eigen2_Scaling Scaling3; - typedef eigen2_Translation Translation2; - typedef eigen2_Translation Translation3; - - Scalar largeEps = test_precision(); - if (ei_is_same_type::ret) - largeEps = 1e-2f; - - Vector3 v0 = Vector3::Random(), - v1 = Vector3::Random(), - v2 = Vector3::Random(); - Vector2 u0 = Vector2::Random(); - Matrix3 matrot1; - - Scalar a = ei_random(-Scalar(M_PI), Scalar(M_PI)); - - // cross product - VERIFY_IS_MUCH_SMALLER_THAN(v1.cross(v2).eigen2_dot(v1), Scalar(1)); - Matrix3 m; - m << v0.normalized(), - (v0.cross(v1)).normalized(), - (v0.cross(v1).cross(v0)).normalized(); - VERIFY(m.isUnitary()); - - // Quaternion: Identity(), setIdentity(); - Quaternionx q1, q2; - q2.setIdentity(); - VERIFY_IS_APPROX(Quaternionx(Quaternionx::Identity()).coeffs(), q2.coeffs()); - q1.coeffs().setRandom(); - VERIFY_IS_APPROX(q1.coeffs(), (q1*q2).coeffs()); - - // unitOrthogonal - VERIFY_IS_MUCH_SMALLER_THAN(u0.unitOrthogonal().eigen2_dot(u0), Scalar(1)); - VERIFY_IS_MUCH_SMALLER_THAN(v0.unitOrthogonal().eigen2_dot(v0), Scalar(1)); - VERIFY_IS_APPROX(u0.unitOrthogonal().norm(), Scalar(1)); - VERIFY_IS_APPROX(v0.unitOrthogonal().norm(), Scalar(1)); - - - VERIFY_IS_APPROX(v0, AngleAxisx(a, v0.normalized()) * v0); - VERIFY_IS_APPROX(-v0, AngleAxisx(Scalar(M_PI), v0.unitOrthogonal()) * v0); - VERIFY_IS_APPROX(ei_cos(a)*v0.squaredNorm(), v0.eigen2_dot(AngleAxisx(a, v0.unitOrthogonal()) * v0)); - m = AngleAxisx(a, v0.normalized()).toRotationMatrix().adjoint(); - VERIFY_IS_APPROX(Matrix3::Identity(), m * AngleAxisx(a, v0.normalized())); - VERIFY_IS_APPROX(Matrix3::Identity(), AngleAxisx(a, v0.normalized()) * m); - - q1 = AngleAxisx(a, v0.normalized()); - q2 = AngleAxisx(a, v1.normalized()); - - // angular distance - Scalar refangle = ei_abs(AngleAxisx(q1.inverse()*q2).angle()); - if (refangle>Scalar(M_PI)) - refangle = Scalar(2)*Scalar(M_PI) - refangle; - - if((q1.coeffs()-q2.coeffs()).norm() > 10*largeEps) - { - VERIFY(ei_isApprox(q1.angularDistance(q2), refangle, largeEps)); - } - - // rotation matrix conversion - VERIFY_IS_APPROX(q1 * v2, q1.toRotationMatrix() * v2); - VERIFY_IS_APPROX(q1 * q2 * v2, - q1.toRotationMatrix() * q2.toRotationMatrix() * v2); - - VERIFY( (q2*q1).isApprox(q1*q2, largeEps) || !(q2 * q1 * v2).isApprox( - q1.toRotationMatrix() * q2.toRotationMatrix() * v2)); - - q2 = q1.toRotationMatrix(); - VERIFY_IS_APPROX(q1*v1,q2*v1); - - matrot1 = AngleAxisx(Scalar(0.1), Vector3::UnitX()) - * AngleAxisx(Scalar(0.2), Vector3::UnitY()) - * AngleAxisx(Scalar(0.3), Vector3::UnitZ()); - VERIFY_IS_APPROX(matrot1 * v1, - AngleAxisx(Scalar(0.1), Vector3(1,0,0)).toRotationMatrix() - * (AngleAxisx(Scalar(0.2), Vector3(0,1,0)).toRotationMatrix() - * (AngleAxisx(Scalar(0.3), Vector3(0,0,1)).toRotationMatrix() * v1))); - - // angle-axis conversion - AngleAxisx aa = q1; - VERIFY_IS_APPROX(q1 * v1, Quaternionx(aa) * v1); - VERIFY_IS_NOT_APPROX(q1 * v1, Quaternionx(AngleAxisx(aa.angle()*2,aa.axis())) * v1); - - // from two vector creation - VERIFY_IS_APPROX(v2.normalized(),(q2.setFromTwoVectors(v1,v2)*v1).normalized()); - VERIFY_IS_APPROX(v2.normalized(),(q2.setFromTwoVectors(v1,v2)*v1).normalized()); - - // inverse and conjugate - VERIFY_IS_APPROX(q1 * (q1.inverse() * v1), v1); - VERIFY_IS_APPROX(q1 * (q1.conjugate() * v1), v1); - - // AngleAxis - VERIFY_IS_APPROX(AngleAxisx(a,v1.normalized()).toRotationMatrix(), - Quaternionx(AngleAxisx(a,v1.normalized())).toRotationMatrix()); - - AngleAxisx aa1; - m = q1.toRotationMatrix(); - aa1 = m; - VERIFY_IS_APPROX(AngleAxisx(m).toRotationMatrix(), - Quaternionx(m).toRotationMatrix()); - - // Transform - // TODO complete the tests ! - a = 0; - while (ei_abs(a)(-Scalar(0.4)*Scalar(M_PI), Scalar(0.4)*Scalar(M_PI)); - q1 = AngleAxisx(a, v0.normalized()); - Transform3 t0, t1, t2; - // first test setIdentity() and Identity() - t0.setIdentity(); - VERIFY_IS_APPROX(t0.matrix(), Transform3::MatrixType::Identity()); - t0.matrix().setZero(); - t0 = Transform3::Identity(); - VERIFY_IS_APPROX(t0.matrix(), Transform3::MatrixType::Identity()); - - t0.linear() = q1.toRotationMatrix(); - t1.setIdentity(); - t1.linear() = q1.toRotationMatrix(); - - v0 << 50, 2, 1;//= ei_random_matrix().cwiseProduct(Vector3(10,2,0.5)); - t0.scale(v0); - t1.prescale(v0); - - VERIFY_IS_APPROX( (t0 * Vector3(1,0,0)).norm(), v0.x()); - //VERIFY(!ei_isApprox((t1 * Vector3(1,0,0)).norm(), v0.x())); - - t0.setIdentity(); - t1.setIdentity(); - v1 << 1, 2, 3; - t0.linear() = q1.toRotationMatrix(); - t0.pretranslate(v0); - t0.scale(v1); - t1.linear() = q1.conjugate().toRotationMatrix(); - t1.prescale(v1.cwise().inverse()); - t1.translate(-v0); - - VERIFY((t0.matrix() * t1.matrix()).isIdentity(test_precision())); - - t1.fromPositionOrientationScale(v0, q1, v1); - VERIFY_IS_APPROX(t1.matrix(), t0.matrix()); - VERIFY_IS_APPROX(t1*v1, t0*v1); - - t0.setIdentity(); t0.scale(v0).rotate(q1.toRotationMatrix()); - t1.setIdentity(); t1.scale(v0).rotate(q1); - VERIFY_IS_APPROX(t0.matrix(), t1.matrix()); - - t0.setIdentity(); t0.scale(v0).rotate(AngleAxisx(q1)); - VERIFY_IS_APPROX(t0.matrix(), t1.matrix()); - - VERIFY_IS_APPROX(t0.scale(a).matrix(), t1.scale(Vector3::Constant(a)).matrix()); - VERIFY_IS_APPROX(t0.prescale(a).matrix(), t1.prescale(Vector3::Constant(a)).matrix()); - - // More transform constructors, operator=, operator*= - - Matrix3 mat3 = Matrix3::Random(); - Matrix4 mat4; - mat4 << mat3 , Vector3::Zero() , Vector4::Zero().transpose(); - Transform3 tmat3(mat3), tmat4(mat4); - tmat4.matrix()(3,3) = Scalar(1); - VERIFY_IS_APPROX(tmat3.matrix(), tmat4.matrix()); - - Scalar a3 = ei_random(-Scalar(M_PI), Scalar(M_PI)); - Vector3 v3 = Vector3::Random().normalized(); - AngleAxisx aa3(a3, v3); - Transform3 t3(aa3); - Transform3 t4; - t4 = aa3; - VERIFY_IS_APPROX(t3.matrix(), t4.matrix()); - t4.rotate(AngleAxisx(-a3,v3)); - VERIFY_IS_APPROX(t4.matrix(), Matrix4::Identity()); - t4 *= aa3; - VERIFY_IS_APPROX(t3.matrix(), t4.matrix()); - - v3 = Vector3::Random(); - Translation3 tv3(v3); - Transform3 t5(tv3); - t4 = tv3; - VERIFY_IS_APPROX(t5.matrix(), t4.matrix()); - t4.translate(-v3); - VERIFY_IS_APPROX(t4.matrix(), Matrix4::Identity()); - t4 *= tv3; - VERIFY_IS_APPROX(t5.matrix(), t4.matrix()); - - Scaling3 sv3(v3); - Transform3 t6(sv3); - t4 = sv3; - VERIFY_IS_APPROX(t6.matrix(), t4.matrix()); - t4.scale(v3.cwise().inverse()); - VERIFY_IS_APPROX(t4.matrix(), Matrix4::Identity()); - t4 *= sv3; - VERIFY_IS_APPROX(t6.matrix(), t4.matrix()); - - // matrix * transform - VERIFY_IS_APPROX(Transform3(t3.matrix()*t4).matrix(), Transform3(t3*t4).matrix()); - - // chained Transform product - VERIFY_IS_APPROX(((t3*t4)*t5).matrix(), (t3*(t4*t5)).matrix()); - - // check that Transform product doesn't have aliasing problems - t5 = t4; - t5 = t5*t5; - VERIFY_IS_APPROX(t5, t4*t4); - - // 2D transformation - Transform2 t20, t21; - Vector2 v20 = Vector2::Random(); - Vector2 v21 = Vector2::Random(); - for (int k=0; k<2; ++k) - if (ei_abs(v21[k])(a).toRotationMatrix(); - VERIFY_IS_APPROX(t20.fromPositionOrientationScale(v20,a,v21).matrix(), - t21.pretranslate(v20).scale(v21).matrix()); - - t21.setIdentity(); - t21.linear() = Rotation2D(-a).toRotationMatrix(); - VERIFY( (t20.fromPositionOrientationScale(v20,a,v21) - * (t21.prescale(v21.cwise().inverse()).translate(-v20))).matrix().isIdentity(test_precision()) ); - - // Transform - new API - // 3D - t0.setIdentity(); - t0.rotate(q1).scale(v0).translate(v0); - // mat * scaling and mat * translation - t1 = (Matrix3(q1) * Scaling3(v0)) * Translation3(v0); - VERIFY_IS_APPROX(t0.matrix(), t1.matrix()); - // mat * transformation and scaling * translation - t1 = Matrix3(q1) * (Scaling3(v0) * Translation3(v0)); - VERIFY_IS_APPROX(t0.matrix(), t1.matrix()); - - t0.setIdentity(); - t0.prerotate(q1).prescale(v0).pretranslate(v0); - // translation * scaling and transformation * mat - t1 = (Translation3(v0) * Scaling3(v0)) * Matrix3(q1); - VERIFY_IS_APPROX(t0.matrix(), t1.matrix()); - // scaling * mat and translation * mat - t1 = Translation3(v0) * (Scaling3(v0) * Matrix3(q1)); - VERIFY_IS_APPROX(t0.matrix(), t1.matrix()); - - t0.setIdentity(); - t0.scale(v0).translate(v0).rotate(q1); - // translation * mat and scaling * transformation - t1 = Scaling3(v0) * (Translation3(v0) * Matrix3(q1)); - VERIFY_IS_APPROX(t0.matrix(), t1.matrix()); - // transformation * scaling - t0.scale(v0); - t1 = t1 * Scaling3(v0); - VERIFY_IS_APPROX(t0.matrix(), t1.matrix()); - // transformation * translation - t0.translate(v0); - t1 = t1 * Translation3(v0); - VERIFY_IS_APPROX(t0.matrix(), t1.matrix()); - // translation * transformation - t0.pretranslate(v0); - t1 = Translation3(v0) * t1; - VERIFY_IS_APPROX(t0.matrix(), t1.matrix()); - - // transform * quaternion - t0.rotate(q1); - t1 = t1 * q1; - VERIFY_IS_APPROX(t0.matrix(), t1.matrix()); - - // translation * quaternion - t0.translate(v1).rotate(q1); - t1 = t1 * (Translation3(v1) * q1); - VERIFY_IS_APPROX(t0.matrix(), t1.matrix()); - - // scaling * quaternion - t0.scale(v1).rotate(q1); - t1 = t1 * (Scaling3(v1) * q1); - VERIFY_IS_APPROX(t0.matrix(), t1.matrix()); - - // quaternion * transform - t0.prerotate(q1); - t1 = q1 * t1; - VERIFY_IS_APPROX(t0.matrix(), t1.matrix()); - - // quaternion * translation - t0.rotate(q1).translate(v1); - t1 = t1 * (q1 * Translation3(v1)); - VERIFY_IS_APPROX(t0.matrix(), t1.matrix()); - - // quaternion * scaling - t0.rotate(q1).scale(v1); - t1 = t1 * (q1 * Scaling3(v1)); - VERIFY_IS_APPROX(t0.matrix(), t1.matrix()); - - // translation * vector - t0.setIdentity(); - t0.translate(v0); - VERIFY_IS_APPROX(t0 * v1, Translation3(v0) * v1); - - // scaling * vector - t0.setIdentity(); - t0.scale(v0); - VERIFY_IS_APPROX(t0 * v1, Scaling3(v0) * v1); - - // test transform inversion - t0.setIdentity(); - t0.translate(v0); - t0.linear().setRandom(); - VERIFY_IS_APPROX(t0.inverse(Affine), t0.matrix().inverse()); - t0.setIdentity(); - t0.translate(v0).rotate(q1); - VERIFY_IS_APPROX(t0.inverse(Isometry), t0.matrix().inverse()); - - // test extract rotation and scaling - t0.setIdentity(); - t0.translate(v0).rotate(q1).scale(v1); - VERIFY_IS_APPROX(t0.rotation() * v1, Matrix3(q1) * v1); - - Matrix3 mat_rotation, mat_scaling; - t0.setIdentity(); - t0.translate(v0).rotate(q1).scale(v1); - t0.computeRotationScaling(&mat_rotation, &mat_scaling); - VERIFY_IS_APPROX(t0.linear(), mat_rotation * mat_scaling); - VERIFY_IS_APPROX(mat_rotation*mat_rotation.adjoint(), Matrix3::Identity()); - VERIFY_IS_APPROX(mat_rotation.determinant(), Scalar(1)); - t0.computeScalingRotation(&mat_scaling, &mat_rotation); - VERIFY_IS_APPROX(t0.linear(), mat_scaling * mat_rotation); - VERIFY_IS_APPROX(mat_rotation*mat_rotation.adjoint(), Matrix3::Identity()); - VERIFY_IS_APPROX(mat_rotation.determinant(), Scalar(1)); - - // test casting - eigen2_Transform t1f = t1.template cast(); - VERIFY_IS_APPROX(t1f.template cast(),t1); - eigen2_Transform t1d = t1.template cast(); - VERIFY_IS_APPROX(t1d.template cast(),t1); - - Translation3 tr1(v0); - eigen2_Translation tr1f = tr1.template cast(); - VERIFY_IS_APPROX(tr1f.template cast(),tr1); - eigen2_Translation tr1d = tr1.template cast(); - VERIFY_IS_APPROX(tr1d.template cast(),tr1); - - Scaling3 sc1(v0); - eigen2_Scaling sc1f = sc1.template cast(); - VERIFY_IS_APPROX(sc1f.template cast(),sc1); - eigen2_Scaling sc1d = sc1.template cast(); - VERIFY_IS_APPROX(sc1d.template cast(),sc1); - - eigen2_Quaternion q1f = q1.template cast(); - VERIFY_IS_APPROX(q1f.template cast(),q1); - eigen2_Quaternion q1d = q1.template cast(); - VERIFY_IS_APPROX(q1d.template cast(),q1); - - eigen2_AngleAxis aa1f = aa1.template cast(); - VERIFY_IS_APPROX(aa1f.template cast(),aa1); - eigen2_AngleAxis aa1d = aa1.template cast(); - VERIFY_IS_APPROX(aa1d.template cast(),aa1); - - eigen2_Rotation2D r2d1(ei_random()); - eigen2_Rotation2D r2d1f = r2d1.template cast(); - VERIFY_IS_APPROX(r2d1f.template cast(),r2d1); - eigen2_Rotation2D r2d1d = r2d1.template cast(); - VERIFY_IS_APPROX(r2d1d.template cast(),r2d1); - - m = q1; -// m.col(1) = Vector3(0,ei_random(),ei_random()).normalized(); -// m.col(0) = Vector3(-1,0,0).normalized(); -// m.col(2) = m.col(0).cross(m.col(1)); - #define VERIFY_EULER(I,J,K, X,Y,Z) { \ - Vector3 ea = m.eulerAngles(I,J,K); \ - Matrix3 m1 = Matrix3(AngleAxisx(ea[0], Vector3::Unit##X()) * AngleAxisx(ea[1], Vector3::Unit##Y()) * AngleAxisx(ea[2], Vector3::Unit##Z())); \ - VERIFY_IS_APPROX(m, m1); \ - VERIFY_IS_APPROX(m, Matrix3(AngleAxisx(ea[0], Vector3::Unit##X()) * AngleAxisx(ea[1], Vector3::Unit##Y()) * AngleAxisx(ea[2], Vector3::Unit##Z()))); \ - } - VERIFY_EULER(0,1,2, X,Y,Z); - VERIFY_EULER(0,1,0, X,Y,X); - VERIFY_EULER(0,2,1, X,Z,Y); - VERIFY_EULER(0,2,0, X,Z,X); - - VERIFY_EULER(1,2,0, Y,Z,X); - VERIFY_EULER(1,2,1, Y,Z,Y); - VERIFY_EULER(1,0,2, Y,X,Z); - VERIFY_EULER(1,0,1, Y,X,Y); - - VERIFY_EULER(2,0,1, Z,X,Y); - VERIFY_EULER(2,0,2, Z,X,Z); - VERIFY_EULER(2,1,0, Z,Y,X); - VERIFY_EULER(2,1,2, Z,Y,Z); - - // colwise/rowwise cross product - mat3.setRandom(); - Vector3 vec3 = Vector3::Random(); - Matrix3 mcross; - int i = ei_random(0,2); - mcross = mat3.colwise().cross(vec3); - VERIFY_IS_APPROX(mcross.col(i), mat3.col(i).cross(vec3)); - mcross = mat3.rowwise().cross(vec3); - VERIFY_IS_APPROX(mcross.row(i), mat3.row(i).cross(vec3)); - - -} - -void test_eigen2_geometry_with_eigen2_prefix() -{ - std::cout << "eigen2 support: " << EIGEN2_SUPPORT_STAGE << std::endl; - for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST_1( geometry() ); - CALL_SUBTEST_2( geometry() ); - } -} diff --git a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_hyperplane.cpp b/ground/gcs/src/libs/eigen/test/eigen2/eigen2_hyperplane.cpp deleted file mode 100644 index f3f85e14df..0000000000 --- a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_hyperplane.cpp +++ /dev/null @@ -1,126 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. Eigen itself is part of the KDE project. -// -// Copyright (C) 2008 Gael Guennebaud -// Copyright (C) 2008 Benoit Jacob -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#include "main.h" -#include -#include -#include - -template void hyperplane(const HyperplaneType& _plane) -{ - /* this test covers the following files: - Hyperplane.h - */ - - const int dim = _plane.dim(); - typedef typename HyperplaneType::Scalar Scalar; - typedef typename NumTraits::Real RealScalar; - typedef Matrix VectorType; - typedef Matrix MatrixType; - - VectorType p0 = VectorType::Random(dim); - VectorType p1 = VectorType::Random(dim); - - VectorType n0 = VectorType::Random(dim).normalized(); - VectorType n1 = VectorType::Random(dim).normalized(); - - HyperplaneType pl0(n0, p0); - HyperplaneType pl1(n1, p1); - HyperplaneType pl2 = pl1; - - Scalar s0 = ei_random(); - Scalar s1 = ei_random(); - - VERIFY_IS_APPROX( n1.eigen2_dot(n1), Scalar(1) ); - - VERIFY_IS_MUCH_SMALLER_THAN( pl0.absDistance(p0), Scalar(1) ); - VERIFY_IS_APPROX( pl1.signedDistance(p1 + n1 * s0), s0 ); - VERIFY_IS_MUCH_SMALLER_THAN( pl1.signedDistance(pl1.projection(p0)), Scalar(1) ); - VERIFY_IS_MUCH_SMALLER_THAN( pl1.absDistance(p1 + pl1.normal().unitOrthogonal() * s1), Scalar(1) ); - - // transform - if (!NumTraits::IsComplex) - { - MatrixType rot = MatrixType::Random(dim,dim).qr().matrixQ(); - Scaling scaling(VectorType::Random()); - Translation translation(VectorType::Random()); - - pl2 = pl1; - VERIFY_IS_MUCH_SMALLER_THAN( pl2.transform(rot).absDistance(rot * p1), Scalar(1) ); - pl2 = pl1; - VERIFY_IS_MUCH_SMALLER_THAN( pl2.transform(rot,Isometry).absDistance(rot * p1), Scalar(1) ); - pl2 = pl1; - VERIFY_IS_MUCH_SMALLER_THAN( pl2.transform(rot*scaling).absDistance((rot*scaling) * p1), Scalar(1) ); - pl2 = pl1; - VERIFY_IS_MUCH_SMALLER_THAN( pl2.transform(rot*scaling*translation) - .absDistance((rot*scaling*translation) * p1), Scalar(1) ); - pl2 = pl1; - VERIFY_IS_MUCH_SMALLER_THAN( pl2.transform(rot*translation,Isometry) - .absDistance((rot*translation) * p1), Scalar(1) ); - } - - // casting - const int Dim = HyperplaneType::AmbientDimAtCompileTime; - typedef typename GetDifferentType::type OtherScalar; - Hyperplane hp1f = pl1.template cast(); - VERIFY_IS_APPROX(hp1f.template cast(),pl1); - Hyperplane hp1d = pl1.template cast(); - VERIFY_IS_APPROX(hp1d.template cast(),pl1); -} - -template void lines() -{ - typedef Hyperplane HLine; - typedef ParametrizedLine PLine; - typedef Matrix Vector; - typedef Matrix CoeffsType; - - for(int i = 0; i < 10; i++) - { - Vector center = Vector::Random(); - Vector u = Vector::Random(); - Vector v = Vector::Random(); - Scalar a = ei_random(); - while (ei_abs(a-1) < 1e-4) a = ei_random(); - while (u.norm() < 1e-4) u = Vector::Random(); - while (v.norm() < 1e-4) v = Vector::Random(); - - HLine line_u = HLine::Through(center + u, center + a*u); - HLine line_v = HLine::Through(center + v, center + a*v); - - // the line equations should be normalized so that a^2+b^2=1 - VERIFY_IS_APPROX(line_u.normal().norm(), Scalar(1)); - VERIFY_IS_APPROX(line_v.normal().norm(), Scalar(1)); - - Vector result = line_u.intersection(line_v); - - // the lines should intersect at the point we called "center" - VERIFY_IS_APPROX(result, center); - - // check conversions between two types of lines - PLine pl(line_u); // gcc 3.3 will commit suicide if we don't name this variable - CoeffsType converted_coeffs(HLine(pl).coeffs()); - converted_coeffs *= line_u.coeffs()(0)/converted_coeffs(0); - VERIFY(line_u.coeffs().isApprox(converted_coeffs)); - } -} - -void test_eigen2_hyperplane() -{ - for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST_1( hyperplane(Hyperplane()) ); - CALL_SUBTEST_2( hyperplane(Hyperplane()) ); - CALL_SUBTEST_3( hyperplane(Hyperplane()) ); - CALL_SUBTEST_4( hyperplane(Hyperplane,5>()) ); - CALL_SUBTEST_5( lines() ); - CALL_SUBTEST_6( lines() ); - } -} diff --git a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_inverse.cpp b/ground/gcs/src/libs/eigen/test/eigen2/eigen2_inverse.cpp deleted file mode 100644 index ccd24a194d..0000000000 --- a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_inverse.cpp +++ /dev/null @@ -1,62 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. Eigen itself is part of the KDE project. -// -// Copyright (C) 2008 Gael Guennebaud -// Copyright (C) 2008 Benoit Jacob -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#include "main.h" -#include - -template void inverse(const MatrixType& m) -{ - /* this test covers the following files: - Inverse.h - */ - int rows = m.rows(); - int cols = m.cols(); - - typedef typename MatrixType::Scalar Scalar; - typedef typename NumTraits::Real RealScalar; - typedef Matrix VectorType; - - MatrixType m1 = MatrixType::Random(rows, cols), - m2(rows, cols), - identity = MatrixType::Identity(rows, rows); - - while(ei_abs(m1.determinant()) < RealScalar(0.1) && rows <= 8) - { - m1 = MatrixType::Random(rows, cols); - } - - m2 = m1.inverse(); - VERIFY_IS_APPROX(m1, m2.inverse() ); - - m1.computeInverse(&m2); - VERIFY_IS_APPROX(m1, m2.inverse() ); - - VERIFY_IS_APPROX((Scalar(2)*m2).inverse(), m2.inverse()*Scalar(0.5)); - - VERIFY_IS_APPROX(identity, m1.inverse() * m1 ); - VERIFY_IS_APPROX(identity, m1 * m1.inverse() ); - - VERIFY_IS_APPROX(m1, m1.inverse().inverse() ); - - // since for the general case we implement separately row-major and col-major, test that - VERIFY_IS_APPROX(m1.transpose().inverse(), m1.inverse().transpose()); -} - -void test_eigen2_inverse() -{ - for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST_1( inverse(Matrix()) ); - CALL_SUBTEST_2( inverse(Matrix2d()) ); - CALL_SUBTEST_3( inverse(Matrix3f()) ); - CALL_SUBTEST_4( inverse(Matrix4f()) ); - CALL_SUBTEST_5( inverse(MatrixXf(8,8)) ); - CALL_SUBTEST_6( inverse(MatrixXcd(7,7)) ); - } -} diff --git a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_linearstructure.cpp b/ground/gcs/src/libs/eigen/test/eigen2/eigen2_linearstructure.cpp deleted file mode 100644 index 488f4c4850..0000000000 --- a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_linearstructure.cpp +++ /dev/null @@ -1,83 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. Eigen itself is part of the KDE project. -// -// Copyright (C) 2006-2008 Benoit Jacob -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#include "main.h" - -template void linearStructure(const MatrixType& m) -{ - /* this test covers the following files: - Sum.h Difference.h Opposite.h ScalarMultiple.h - */ - - typedef typename MatrixType::Scalar Scalar; - typedef Matrix VectorType; - - int rows = m.rows(); - int cols = m.cols(); - - // this test relies a lot on Random.h, and there's not much more that we can do - // to test it, hence I consider that we will have tested Random.h - MatrixType m1 = MatrixType::Random(rows, cols), - m2 = MatrixType::Random(rows, cols), - m3(rows, cols); - - Scalar s1 = ei_random(); - while (ei_abs(s1)<1e-3) s1 = ei_random(); - - int r = ei_random(0, rows-1), - c = ei_random(0, cols-1); - - VERIFY_IS_APPROX(-(-m1), m1); - VERIFY_IS_APPROX(m1+m1, 2*m1); - VERIFY_IS_APPROX(m1+m2-m1, m2); - VERIFY_IS_APPROX(-m2+m1+m2, m1); - VERIFY_IS_APPROX(m1*s1, s1*m1); - VERIFY_IS_APPROX((m1+m2)*s1, s1*m1+s1*m2); - VERIFY_IS_APPROX((-m1+m2)*s1, -s1*m1+s1*m2); - m3 = m2; m3 += m1; - VERIFY_IS_APPROX(m3, m1+m2); - m3 = m2; m3 -= m1; - VERIFY_IS_APPROX(m3, m2-m1); - m3 = m2; m3 *= s1; - VERIFY_IS_APPROX(m3, s1*m2); - if(NumTraits::HasFloatingPoint) - { - m3 = m2; m3 /= s1; - VERIFY_IS_APPROX(m3, m2/s1); - } - - // again, test operator() to check const-qualification - VERIFY_IS_APPROX((-m1)(r,c), -(m1(r,c))); - VERIFY_IS_APPROX((m1-m2)(r,c), (m1(r,c))-(m2(r,c))); - VERIFY_IS_APPROX((m1+m2)(r,c), (m1(r,c))+(m2(r,c))); - VERIFY_IS_APPROX((s1*m1)(r,c), s1*(m1(r,c))); - VERIFY_IS_APPROX((m1*s1)(r,c), (m1(r,c))*s1); - if(NumTraits::HasFloatingPoint) - VERIFY_IS_APPROX((m1/s1)(r,c), (m1(r,c))/s1); - - // use .block to disable vectorization and compare to the vectorized version - VERIFY_IS_APPROX(m1+m1.block(0,0,rows,cols), m1+m1); - VERIFY_IS_APPROX(m1.cwise() * m1.block(0,0,rows,cols), m1.cwise() * m1); - VERIFY_IS_APPROX(m1 - m1.block(0,0,rows,cols), m1 - m1); - VERIFY_IS_APPROX(m1.block(0,0,rows,cols) * s1, m1 * s1); -} - -void test_eigen2_linearstructure() -{ - for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST_1( linearStructure(Matrix()) ); - CALL_SUBTEST_2( linearStructure(Matrix2f()) ); - CALL_SUBTEST_3( linearStructure(Vector3d()) ); - CALL_SUBTEST_4( linearStructure(Matrix4d()) ); - CALL_SUBTEST_5( linearStructure(MatrixXcf(3, 3)) ); - CALL_SUBTEST_6( linearStructure(MatrixXf(8, 12)) ); - CALL_SUBTEST_7( linearStructure(MatrixXi(8, 12)) ); - CALL_SUBTEST_8( linearStructure(MatrixXcd(20, 20)) ); - } -} diff --git a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_lu.cpp b/ground/gcs/src/libs/eigen/test/eigen2/eigen2_lu.cpp deleted file mode 100644 index e993b1c7c0..0000000000 --- a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_lu.cpp +++ /dev/null @@ -1,122 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. Eigen itself is part of the KDE project. -// -// Copyright (C) 2008 Benoit Jacob -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#include "main.h" -#include - -template -void doSomeRankPreservingOperations(Eigen::MatrixBase& m) -{ - typedef typename Derived::RealScalar RealScalar; - for(int a = 0; a < 3*(m.rows()+m.cols()); a++) - { - RealScalar d = Eigen::ei_random(-1,1); - int i = Eigen::ei_random(0,m.rows()-1); // i is a random row number - int j; - do { - j = Eigen::ei_random(0,m.rows()-1); - } while (i==j); // j is another one (must be different) - m.row(i) += d * m.row(j); - - i = Eigen::ei_random(0,m.cols()-1); // i is a random column number - do { - j = Eigen::ei_random(0,m.cols()-1); - } while (i==j); // j is another one (must be different) - m.col(i) += d * m.col(j); - } -} - -template void lu_non_invertible() -{ - /* this test covers the following files: - LU.h - */ - // NOTE there seems to be a problem with too small sizes -- could easily lie in the doSomeRankPreservingOperations function - int rows = ei_random(20,200), cols = ei_random(20,200), cols2 = ei_random(20,200); - int rank = ei_random(1, std::min(rows, cols)-1); - - MatrixType m1(rows, cols), m2(cols, cols2), m3(rows, cols2), k(1,1); - m1 = MatrixType::Random(rows,cols); - if(rows <= cols) - for(int i = rank; i < rows; i++) m1.row(i).setZero(); - else - for(int i = rank; i < cols; i++) m1.col(i).setZero(); - doSomeRankPreservingOperations(m1); - - LU lu(m1); - typename LU::KernelResultType m1kernel = lu.kernel(); - typename LU::ImageResultType m1image = lu.image(); - - VERIFY(rank == lu.rank()); - VERIFY(cols - lu.rank() == lu.dimensionOfKernel()); - VERIFY(!lu.isInjective()); - VERIFY(!lu.isInvertible()); - VERIFY(lu.isSurjective() == (lu.rank() == rows)); - VERIFY((m1 * m1kernel).isMuchSmallerThan(m1)); - VERIFY(m1image.lu().rank() == rank); - MatrixType sidebyside(m1.rows(), m1.cols() + m1image.cols()); - sidebyside << m1, m1image; - VERIFY(sidebyside.lu().rank() == rank); - m2 = MatrixType::Random(cols,cols2); - m3 = m1*m2; - m2 = MatrixType::Random(cols,cols2); - lu.solve(m3, &m2); - VERIFY_IS_APPROX(m3, m1*m2); - /* solve now always returns true - m3 = MatrixType::Random(rows,cols2); - VERIFY(!lu.solve(m3, &m2)); - */ -} - -template void lu_invertible() -{ - /* this test covers the following files: - LU.h - */ - typedef typename NumTraits::Real RealScalar; - int size = ei_random(10,200); - - MatrixType m1(size, size), m2(size, size), m3(size, size); - m1 = MatrixType::Random(size,size); - - if (ei_is_same_type::ret) - { - // let's build a matrix more stable to inverse - MatrixType a = MatrixType::Random(size,size*2); - m1 += a * a.adjoint(); - } - - LU lu(m1); - VERIFY(0 == lu.dimensionOfKernel()); - VERIFY(size == lu.rank()); - VERIFY(lu.isInjective()); - VERIFY(lu.isSurjective()); - VERIFY(lu.isInvertible()); - VERIFY(lu.image().lu().isInvertible()); - m3 = MatrixType::Random(size,size); - lu.solve(m3, &m2); - VERIFY_IS_APPROX(m3, m1*m2); - VERIFY_IS_APPROX(m2, lu.inverse()*m3); - m3 = MatrixType::Random(size,size); - VERIFY(lu.solve(m3, &m2)); -} - -void test_eigen2_lu() -{ - for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST_1( lu_non_invertible() ); - CALL_SUBTEST_2( lu_non_invertible() ); - CALL_SUBTEST_3( lu_non_invertible() ); - CALL_SUBTEST_4( lu_non_invertible() ); - CALL_SUBTEST_1( lu_invertible() ); - CALL_SUBTEST_2( lu_invertible() ); - CALL_SUBTEST_3( lu_invertible() ); - CALL_SUBTEST_4( lu_invertible() ); - } -} diff --git a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_map.cpp b/ground/gcs/src/libs/eigen/test/eigen2/eigen2_map.cpp deleted file mode 100644 index 4a1c4e11ad..0000000000 --- a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_map.cpp +++ /dev/null @@ -1,114 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. Eigen itself is part of the KDE project. -// -// Copyright (C) 2007-2010 Benoit Jacob -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#include "main.h" - -template void map_class_vector(const VectorType& m) -{ - typedef typename VectorType::Scalar Scalar; - - int size = m.size(); - - // test Map.h - Scalar* array1 = ei_aligned_new(size); - Scalar* array2 = ei_aligned_new(size); - Scalar* array3 = new Scalar[size+1]; - Scalar* array3unaligned = std::size_t(array3)%16 == 0 ? array3+1 : array3; - - Map(array1, size) = VectorType::Random(size); - Map(array2, size) = Map(array1, size); - Map(array3unaligned, size) = Map((const Scalar*)array1, size); // test non-const-correctness support in eigen2 - VectorType ma1 = Map(array1, size); - VectorType ma2 = Map(array2, size); - VectorType ma3 = Map(array3unaligned, size); - VERIFY_IS_APPROX(ma1, ma2); - VERIFY_IS_APPROX(ma1, ma3); - - ei_aligned_delete(array1, size); - ei_aligned_delete(array2, size); - delete[] array3; -} - -template void map_class_matrix(const MatrixType& m) -{ - typedef typename MatrixType::Scalar Scalar; - - int rows = m.rows(), cols = m.cols(), size = rows*cols; - - // test Map.h - Scalar* array1 = ei_aligned_new(size); - for(int i = 0; i < size; i++) array1[i] = Scalar(1); - Scalar* array2 = ei_aligned_new(size); - for(int i = 0; i < size; i++) array2[i] = Scalar(1); - Scalar* array3 = new Scalar[size+1]; - for(int i = 0; i < size+1; i++) array3[i] = Scalar(1); - Scalar* array3unaligned = std::size_t(array3)%16 == 0 ? array3+1 : array3; - Map(array1, rows, cols) = MatrixType::Ones(rows,cols); - Map(array2, rows, cols) = Map((const Scalar*)array1, rows, cols); // test non-const-correctness support in eigen2 - Map(array3unaligned, rows, cols) = Map(array1, rows, cols); - MatrixType ma1 = Map(array1, rows, cols); - MatrixType ma2 = Map(array2, rows, cols); - VERIFY_IS_APPROX(ma1, ma2); - MatrixType ma3 = Map(array3unaligned, rows, cols); - VERIFY_IS_APPROX(ma1, ma3); - - ei_aligned_delete(array1, size); - ei_aligned_delete(array2, size); - delete[] array3; -} - -template void map_static_methods(const VectorType& m) -{ - typedef typename VectorType::Scalar Scalar; - - int size = m.size(); - - // test Map.h - Scalar* array1 = ei_aligned_new(size); - Scalar* array2 = ei_aligned_new(size); - Scalar* array3 = new Scalar[size+1]; - Scalar* array3unaligned = std::size_t(array3)%16 == 0 ? array3+1 : array3; - - VectorType::MapAligned(array1, size) = VectorType::Random(size); - VectorType::Map(array2, size) = VectorType::Map(array1, size); - VectorType::Map(array3unaligned, size) = VectorType::Map(array1, size); - VectorType ma1 = VectorType::Map(array1, size); - VectorType ma2 = VectorType::MapAligned(array2, size); - VectorType ma3 = VectorType::Map(array3unaligned, size); - VERIFY_IS_APPROX(ma1, ma2); - VERIFY_IS_APPROX(ma1, ma3); - - ei_aligned_delete(array1, size); - ei_aligned_delete(array2, size); - delete[] array3; -} - - -void test_eigen2_map() -{ - for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST_1( map_class_vector(Matrix()) ); - CALL_SUBTEST_2( map_class_vector(Vector4d()) ); - CALL_SUBTEST_3( map_class_vector(RowVector4f()) ); - CALL_SUBTEST_4( map_class_vector(VectorXcf(8)) ); - CALL_SUBTEST_5( map_class_vector(VectorXi(12)) ); - - CALL_SUBTEST_1( map_class_matrix(Matrix()) ); - CALL_SUBTEST_2( map_class_matrix(Matrix4d()) ); - CALL_SUBTEST_6( map_class_matrix(Matrix()) ); - CALL_SUBTEST_4( map_class_matrix(MatrixXcf(ei_random(1,10),ei_random(1,10))) ); - CALL_SUBTEST_5( map_class_matrix(MatrixXi(ei_random(1,10),ei_random(1,10))) ); - - CALL_SUBTEST_1( map_static_methods(Matrix()) ); - CALL_SUBTEST_2( map_static_methods(Vector3f()) ); - CALL_SUBTEST_7( map_static_methods(RowVector3d()) ); - CALL_SUBTEST_4( map_static_methods(VectorXcd(8)) ); - CALL_SUBTEST_5( map_static_methods(VectorXf(12)) ); - } -} diff --git a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_meta.cpp b/ground/gcs/src/libs/eigen/test/eigen2/eigen2_meta.cpp deleted file mode 100644 index 1d01bd84d5..0000000000 --- a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_meta.cpp +++ /dev/null @@ -1,60 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. Eigen itself is part of the KDE project. -// -// Copyright (C) 2008 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#include "main.h" - -void test_eigen2_meta() -{ - typedef float & FloatRef; - typedef const float & ConstFloatRef; - - VERIFY((ei_meta_if<(3<4),ei_meta_true, ei_meta_false>::ret::ret)); - VERIFY(( ei_is_same_type::ret)); - VERIFY((!ei_is_same_type::ret)); - VERIFY((!ei_is_same_type::ret)); - VERIFY((!ei_is_same_type::ret)); - - VERIFY(( ei_is_same_type::type >::ret)); - VERIFY(( ei_is_same_type::type >::ret)); - VERIFY(( ei_is_same_type::type >::ret)); - VERIFY(( ei_is_same_type::type >::ret)); - VERIFY(( ei_is_same_type::type >::ret)); - VERIFY(( ei_is_same_type::type >::ret)); - VERIFY(( ei_is_same_type::type >::ret)); - - VERIFY(( ei_is_same_type::type >::ret)); - VERIFY(( ei_is_same_type::type >::ret)); - VERIFY(( ei_is_same_type::type >::ret)); - - VERIFY(( ei_is_same_type::type >::ret)); - VERIFY(( ei_is_same_type::type >::ret)); - VERIFY(( ei_is_same_type::type >::ret)); - VERIFY(( ei_is_same_type::type >::ret)); - VERIFY(( ei_is_same_type::type >::ret)); - VERIFY(( ei_is_same_type::type >::ret)); - - VERIFY(ei_meta_sqrt<1>::ret == 1); - #define VERIFY_META_SQRT(X) VERIFY(ei_meta_sqrt::ret == int(ei_sqrt(double(X)))) - VERIFY_META_SQRT(2); - VERIFY_META_SQRT(3); - VERIFY_META_SQRT(4); - VERIFY_META_SQRT(5); - VERIFY_META_SQRT(6); - VERIFY_META_SQRT(8); - VERIFY_META_SQRT(9); - VERIFY_META_SQRT(15); - VERIFY_META_SQRT(16); - VERIFY_META_SQRT(17); - VERIFY_META_SQRT(255); - VERIFY_META_SQRT(256); - VERIFY_META_SQRT(257); - VERIFY_META_SQRT(1023); - VERIFY_META_SQRT(1024); - VERIFY_META_SQRT(1025); -} diff --git a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_miscmatrices.cpp b/ground/gcs/src/libs/eigen/test/eigen2/eigen2_miscmatrices.cpp deleted file mode 100644 index 8bbb20cc81..0000000000 --- a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_miscmatrices.cpp +++ /dev/null @@ -1,48 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. Eigen itself is part of the KDE project. -// -// Copyright (C) 2006-2008 Benoit Jacob -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#include "main.h" - -template void miscMatrices(const MatrixType& m) -{ - /* this test covers the following files: - DiagonalMatrix.h Ones.h - */ - - typedef typename MatrixType::Scalar Scalar; - typedef Matrix VectorType; - typedef Matrix RowVectorType; - int rows = m.rows(); - int cols = m.cols(); - - int r = ei_random(0, rows-1), r2 = ei_random(0, rows-1), c = ei_random(0, cols-1); - VERIFY_IS_APPROX(MatrixType::Ones(rows,cols)(r,c), static_cast(1)); - MatrixType m1 = MatrixType::Ones(rows,cols); - VERIFY_IS_APPROX(m1(r,c), static_cast(1)); - VectorType v1 = VectorType::Random(rows); - v1[0]; - Matrix - square = v1.asDiagonal(); - if(r==r2) VERIFY_IS_APPROX(square(r,r2), v1[r]); - else VERIFY_IS_MUCH_SMALLER_THAN(square(r,r2), static_cast(1)); - square = MatrixType::Zero(rows, rows); - square.diagonal() = VectorType::Ones(rows); - VERIFY_IS_APPROX(square, MatrixType::Identity(rows, rows)); -} - -void test_eigen2_miscmatrices() -{ - for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST_1( miscMatrices(Matrix()) ); - CALL_SUBTEST_2( miscMatrices(Matrix4d()) ); - CALL_SUBTEST_3( miscMatrices(MatrixXcf(3, 3)) ); - CALL_SUBTEST_4( miscMatrices(MatrixXi(8, 12)) ); - CALL_SUBTEST_5( miscMatrices(MatrixXcd(20, 20)) ); - } -} diff --git a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_mixingtypes.cpp b/ground/gcs/src/libs/eigen/test/eigen2/eigen2_mixingtypes.cpp deleted file mode 100644 index fb5ac5ddad..0000000000 --- a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_mixingtypes.cpp +++ /dev/null @@ -1,77 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. Eigen itself is part of the KDE project. -// -// Copyright (C) 2008 Gael Guennebaud -// Copyright (C) 2008 Benoit Jacob -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_NO_STATIC_ASSERT -#define EIGEN_NO_STATIC_ASSERT // turn static asserts into runtime asserts in order to check them -#endif - -#ifndef EIGEN_DONT_VECTORIZE -#define EIGEN_DONT_VECTORIZE // SSE intrinsics aren't designed to allow mixing types -#endif - -#include "main.h" - - -template void mixingtypes(int size = SizeAtCompileType) -{ - typedef Matrix Mat_f; - typedef Matrix Mat_d; - typedef Matrix, SizeAtCompileType, SizeAtCompileType> Mat_cf; - typedef Matrix, SizeAtCompileType, SizeAtCompileType> Mat_cd; - typedef Matrix Vec_f; - typedef Matrix Vec_d; - typedef Matrix, SizeAtCompileType, 1> Vec_cf; - typedef Matrix, SizeAtCompileType, 1> Vec_cd; - - Mat_f mf(size,size); - Mat_d md(size,size); - Mat_cf mcf(size,size); - Mat_cd mcd(size,size); - Vec_f vf(size,1); - Vec_d vd(size,1); - Vec_cf vcf(size,1); - Vec_cd vcd(size,1); - - mf+mf; - VERIFY_RAISES_ASSERT(mf+md); - VERIFY_RAISES_ASSERT(mf+mcf); - VERIFY_RAISES_ASSERT(vf=vd); - VERIFY_RAISES_ASSERT(vf+=vd); - VERIFY_RAISES_ASSERT(mcd=md); - - mf*mf; - md*mcd; - mcd*md; - mf*vcf; - mcf*vf; - mcf *= mf; - vcd = md*vcd; - vcf = mcf*vf; -#if 0 - // these are know generating hard build errors in eigen3 - VERIFY_RAISES_ASSERT(mf*md); - VERIFY_RAISES_ASSERT(mcf*mcd); - VERIFY_RAISES_ASSERT(mcf*vcd); - VERIFY_RAISES_ASSERT(vcf = mf*vf); - - vf.eigen2_dot(vf); - VERIFY_RAISES_ASSERT(vd.eigen2_dot(vf)); - VERIFY_RAISES_ASSERT(vcf.eigen2_dot(vf)); // yeah eventually we should allow this but i'm too lazy to make that change now in Dot.h - // especially as that might be rewritten as cwise product .sum() which would make that automatic. -#endif -} - -void test_eigen2_mixingtypes() -{ - // check that our operator new is indeed called: - CALL_SUBTEST_1(mixingtypes<3>()); - CALL_SUBTEST_2(mixingtypes<4>()); - CALL_SUBTEST_3(mixingtypes(20)); -} diff --git a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_newstdvector.cpp b/ground/gcs/src/libs/eigen/test/eigen2/eigen2_newstdvector.cpp deleted file mode 100644 index 5f90099019..0000000000 --- a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_newstdvector.cpp +++ /dev/null @@ -1,149 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008 Benoit Jacob -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#define EIGEN_USE_NEW_STDVECTOR -#include "main.h" -#include -#include - -template -void check_stdvector_matrix(const MatrixType& m) -{ - int rows = m.rows(); - int cols = m.cols(); - MatrixType x = MatrixType::Random(rows,cols), y = MatrixType::Random(rows,cols); - std::vector > v(10, MatrixType(rows,cols)), w(20, y); - v[5] = x; - w[6] = v[5]; - VERIFY_IS_APPROX(w[6], v[5]); - v = w; - for(int i = 0; i < 20; i++) - { - VERIFY_IS_APPROX(w[i], v[i]); - } - - v.resize(21); - v[20] = x; - VERIFY_IS_APPROX(v[20], x); - v.resize(22,y); - VERIFY_IS_APPROX(v[21], y); - v.push_back(x); - VERIFY_IS_APPROX(v[22], x); - VERIFY((std::size_t)&(v[22]) == (std::size_t)&(v[21]) + sizeof(MatrixType)); - - // do a lot of push_back such that the vector gets internally resized - // (with memory reallocation) - MatrixType* ref = &w[0]; - for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i) - v.push_back(w[i%w.size()]); - for(unsigned int i=23; i -void check_stdvector_transform(const TransformType&) -{ - typedef typename TransformType::MatrixType MatrixType; - TransformType x(MatrixType::Random()), y(MatrixType::Random()); - std::vector > v(10), w(20, y); - v[5] = x; - w[6] = v[5]; - VERIFY_IS_APPROX(w[6], v[5]); - v = w; - for(int i = 0; i < 20; i++) - { - VERIFY_IS_APPROX(w[i], v[i]); - } - - v.resize(21); - v[20] = x; - VERIFY_IS_APPROX(v[20], x); - v.resize(22,y); - VERIFY_IS_APPROX(v[21], y); - v.push_back(x); - VERIFY_IS_APPROX(v[22], x); - VERIFY((std::size_t)&(v[22]) == (std::size_t)&(v[21]) + sizeof(TransformType)); - - // do a lot of push_back such that the vector gets internally resized - // (with memory reallocation) - TransformType* ref = &w[0]; - for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i) - v.push_back(w[i%w.size()]); - for(unsigned int i=23; i -void check_stdvector_quaternion(const QuaternionType&) -{ - typedef typename QuaternionType::Coefficients Coefficients; - QuaternionType x(Coefficients::Random()), y(Coefficients::Random()); - std::vector > v(10), w(20, y); - v[5] = x; - w[6] = v[5]; - VERIFY_IS_APPROX(w[6], v[5]); - v = w; - for(int i = 0; i < 20; i++) - { - VERIFY_IS_APPROX(w[i], v[i]); - } - - v.resize(21); - v[20] = x; - VERIFY_IS_APPROX(v[20], x); - v.resize(22,y); - VERIFY_IS_APPROX(v[21], y); - v.push_back(x); - VERIFY_IS_APPROX(v[22], x); - VERIFY((std::size_t)&(v[22]) == (std::size_t)&(v[21]) + sizeof(QuaternionType)); - - // do a lot of push_back such that the vector gets internally resized - // (with memory reallocation) - QuaternionType* ref = &w[0]; - for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i) - v.push_back(w[i%w.size()]); - for(unsigned int i=23; i -// Copyright (C) 2006-2008 Benoit Jacob -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -// this hack is needed to make this file compiles with -pedantic (gcc) -#ifdef __GNUC__ -#define throw(X) -#endif -// discard stack allocation as that too bypasses malloc -#define EIGEN_STACK_ALLOCATION_LIMIT 0 -// any heap allocation will raise an assert -#define EIGEN_NO_MALLOC - -#include "main.h" - -template void nomalloc(const MatrixType& m) -{ - /* this test check no dynamic memory allocation are issued with fixed-size matrices - */ - - typedef typename MatrixType::Scalar Scalar; - - int rows = m.rows(); - int cols = m.cols(); - - MatrixType m1 = MatrixType::Random(rows, cols), - m2 = MatrixType::Random(rows, cols); - - Scalar s1 = ei_random(); - - int r = ei_random(0, rows-1), - c = ei_random(0, cols-1); - - VERIFY_IS_APPROX((m1+m2)*s1, s1*m1+s1*m2); - VERIFY_IS_APPROX((m1+m2)(r,c), (m1(r,c))+(m2(r,c))); - VERIFY_IS_APPROX(m1.cwise() * m1.block(0,0,rows,cols), m1.cwise() * m1); - VERIFY_IS_APPROX((m1*m1.transpose())*m2, m1*(m1.transpose()*m2)); -} - -void test_eigen2_nomalloc() -{ - // check that our operator new is indeed called: - VERIFY_RAISES_ASSERT(MatrixXd dummy = MatrixXd::Random(3,3)); - CALL_SUBTEST_1( nomalloc(Matrix()) ); - CALL_SUBTEST_2( nomalloc(Matrix4d()) ); - CALL_SUBTEST_3( nomalloc(Matrix()) ); -} diff --git a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_packetmath.cpp b/ground/gcs/src/libs/eigen/test/eigen2/eigen2_packetmath.cpp deleted file mode 100644 index b1f325fe76..0000000000 --- a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_packetmath.cpp +++ /dev/null @@ -1,132 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. Eigen itself is part of the KDE project. -// -// Copyright (C) 2006-2008 Benoit Jacob -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#include "main.h" - -// using namespace Eigen; - -template bool areApprox(const Scalar* a, const Scalar* b, int size) -{ - for (int i=0; i const complex& min(const complex& a, const complex& b) -{ return a.real() < b.real() ? a : b; } - -template<> const complex& max(const complex& a, const complex& b) -{ return a.real() < b.real() ? b : a; } - -} - -template void packetmath() -{ - typedef typename ei_packet_traits::type Packet; - const int PacketSize = ei_packet_traits::size; - - const int size = PacketSize*4; - EIGEN_ALIGN_128 Scalar data1[ei_packet_traits::size*4]; - EIGEN_ALIGN_128 Scalar data2[ei_packet_traits::size*4]; - EIGEN_ALIGN_128 Packet packets[PacketSize*2]; - EIGEN_ALIGN_128 Scalar ref[ei_packet_traits::size*4]; - for (int i=0; i(); - data2[i] = ei_random(); - } - - ei_pstore(data2, ei_pload(data1)); - VERIFY(areApprox(data1, data2, PacketSize) && "aligned load/store"); - - for (int offset=0; offset(packets[0], packets[1]); - else if (offset==1) ei_palign<1>(packets[0], packets[1]); - else if (offset==2) ei_palign<2>(packets[0], packets[1]); - else if (offset==3) ei_palign<3>(packets[0], packets[1]); - ei_pstore(data2, packets[0]); - - for (int i=0; i Vector; - VERIFY(areApprox(ref, data2, PacketSize) && "ei_palign"); - } - - CHECK_CWISE(REF_ADD, ei_padd); - CHECK_CWISE(REF_SUB, ei_psub); - CHECK_CWISE(REF_MUL, ei_pmul); - #ifndef EIGEN_VECTORIZE_ALTIVEC - if (!ei_is_same_type::ret) - CHECK_CWISE(REF_DIV, ei_pdiv); - #endif - CHECK_CWISE(std::min, ei_pmin); - CHECK_CWISE(std::max, ei_pmax); - - for (int i=0; i() ); - CALL_SUBTEST_2( packetmath() ); - CALL_SUBTEST_3( packetmath() ); - CALL_SUBTEST_4( packetmath >() ); - } -} diff --git a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_parametrizedline.cpp b/ground/gcs/src/libs/eigen/test/eigen2/eigen2_parametrizedline.cpp deleted file mode 100644 index 8147288709..0000000000 --- a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_parametrizedline.cpp +++ /dev/null @@ -1,62 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. Eigen itself is part of the KDE project. -// -// Copyright (C) 2008 Gael Guennebaud -// Copyright (C) 2008 Benoit Jacob -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#include "main.h" -#include -#include -#include - -template void parametrizedline(const LineType& _line) -{ - /* this test covers the following files: - ParametrizedLine.h - */ - - const int dim = _line.dim(); - typedef typename LineType::Scalar Scalar; - typedef typename NumTraits::Real RealScalar; - typedef Matrix VectorType; - typedef Matrix MatrixType; - - VectorType p0 = VectorType::Random(dim); - VectorType p1 = VectorType::Random(dim); - - VectorType d0 = VectorType::Random(dim).normalized(); - - LineType l0(p0, d0); - - Scalar s0 = ei_random(); - Scalar s1 = ei_abs(ei_random()); - - VERIFY_IS_MUCH_SMALLER_THAN( l0.distance(p0), RealScalar(1) ); - VERIFY_IS_MUCH_SMALLER_THAN( l0.distance(p0+s0*d0), RealScalar(1) ); - VERIFY_IS_APPROX( (l0.projection(p1)-p1).norm(), l0.distance(p1) ); - VERIFY_IS_MUCH_SMALLER_THAN( l0.distance(l0.projection(p1)), RealScalar(1) ); - VERIFY_IS_APPROX( Scalar(l0.distance((p0+s0*d0) + d0.unitOrthogonal() * s1)), s1 ); - - // casting - const int Dim = LineType::AmbientDimAtCompileTime; - typedef typename GetDifferentType::type OtherScalar; - ParametrizedLine hp1f = l0.template cast(); - VERIFY_IS_APPROX(hp1f.template cast(),l0); - ParametrizedLine hp1d = l0.template cast(); - VERIFY_IS_APPROX(hp1d.template cast(),l0); -} - -void test_eigen2_parametrizedline() -{ - for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST_1( parametrizedline(ParametrizedLine()) ); - CALL_SUBTEST_2( parametrizedline(ParametrizedLine()) ); - CALL_SUBTEST_3( parametrizedline(ParametrizedLine()) ); - CALL_SUBTEST_4( parametrizedline(ParametrizedLine,5>()) ); - } -} diff --git a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_prec_inverse_4x4.cpp b/ground/gcs/src/libs/eigen/test/eigen2/eigen2_prec_inverse_4x4.cpp deleted file mode 100644 index 8bfa556948..0000000000 --- a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_prec_inverse_4x4.cpp +++ /dev/null @@ -1,84 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2009 Benoit Jacob -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#include "main.h" -#include -#include - -template std::string type_name() { return "other"; } -template<> std::string type_name() { return "float"; } -template<> std::string type_name() { return "double"; } -template<> std::string type_name() { return "int"; } -template<> std::string type_name >() { return "complex"; } -template<> std::string type_name >() { return "complex"; } -template<> std::string type_name >() { return "complex"; } - -#define EIGEN_DEBUG_VAR(x) std::cerr << #x << " = " << x << std::endl; - -template inline typename NumTraits::Real epsilon() -{ - return std::numeric_limits::Real>::epsilon(); -} - -template void inverse_permutation_4x4() -{ - typedef typename MatrixType::Scalar Scalar; - typedef typename MatrixType::RealScalar RealScalar; - Vector4i indices(0,1,2,3); - for(int i = 0; i < 24; ++i) - { - MatrixType m = MatrixType::Zero(); - m(indices(0),0) = 1; - m(indices(1),1) = 1; - m(indices(2),2) = 1; - m(indices(3),3) = 1; - MatrixType inv = m.inverse(); - double error = double( (m*inv-MatrixType::Identity()).norm() / epsilon() ); - VERIFY(error == 0.0); - std::next_permutation(indices.data(),indices.data()+4); - } -} - -template void inverse_general_4x4(int repeat) -{ - typedef typename MatrixType::Scalar Scalar; - typedef typename MatrixType::RealScalar RealScalar; - double error_sum = 0., error_max = 0.; - for(int i = 0; i < repeat; ++i) - { - MatrixType m; - RealScalar absdet; - do { - m = MatrixType::Random(); - absdet = ei_abs(m.determinant()); - } while(absdet < 10 * epsilon()); - MatrixType inv = m.inverse(); - double error = double( (m*inv-MatrixType::Identity()).norm() * absdet / epsilon() ); - error_sum += error; - error_max = std::max(error_max, error); - } - std::cerr << "inverse_general_4x4, Scalar = " << type_name() << std::endl; - double error_avg = error_sum / repeat; - EIGEN_DEBUG_VAR(error_avg); - EIGEN_DEBUG_VAR(error_max); - VERIFY(error_avg < (NumTraits::IsComplex ? 8.0 : 1.25)); - VERIFY(error_max < (NumTraits::IsComplex ? 64.0 : 20.0)); -} - -void test_eigen2_prec_inverse_4x4() -{ - CALL_SUBTEST_1((inverse_permutation_4x4())); - CALL_SUBTEST_1(( inverse_general_4x4(200000 * g_repeat) )); - - CALL_SUBTEST_2((inverse_permutation_4x4 >())); - CALL_SUBTEST_2(( inverse_general_4x4 >(200000 * g_repeat) )); - - CALL_SUBTEST_3((inverse_permutation_4x4())); - CALL_SUBTEST_3((inverse_general_4x4(50000 * g_repeat))); -} diff --git a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_product_large.cpp b/ground/gcs/src/libs/eigen/test/eigen2/eigen2_product_large.cpp deleted file mode 100644 index 5149ef7483..0000000000 --- a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_product_large.cpp +++ /dev/null @@ -1,45 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. Eigen itself is part of the KDE project. -// -// Copyright (C) 2006-2008 Benoit Jacob -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#include "product.h" - -void test_eigen2_product_large() -{ - for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST_1( product(MatrixXf(ei_random(1,320), ei_random(1,320))) ); - CALL_SUBTEST_2( product(MatrixXd(ei_random(1,320), ei_random(1,320))) ); - CALL_SUBTEST_3( product(MatrixXi(ei_random(1,320), ei_random(1,320))) ); - CALL_SUBTEST_4( product(MatrixXcf(ei_random(1,50), ei_random(1,50))) ); - CALL_SUBTEST_5( product(Matrix(ei_random(1,320), ei_random(1,320))) ); - } - -#ifdef EIGEN_TEST_PART_6 - { - // test a specific issue in DiagonalProduct - int N = 1000000; - VectorXf v = VectorXf::Ones(N); - MatrixXf m = MatrixXf::Ones(N,3); - m = (v+v).asDiagonal() * m; - VERIFY_IS_APPROX(m, MatrixXf::Constant(N,3,2)); - } - - { - // test deferred resizing in Matrix::operator= - MatrixXf a = MatrixXf::Random(10,4), b = MatrixXf::Random(4,10), c = a; - VERIFY_IS_APPROX((a = a * b), (c * b).eval()); - } - - { - MatrixXf mat1(10,10); mat1.setRandom(); - MatrixXf mat2(32,10); mat2.setRandom(); - MatrixXf result = mat1.row(2)*mat2.transpose(); - VERIFY_IS_APPROX(result, (mat1.row(2)*mat2.transpose()).eval()); - } -#endif -} diff --git a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_product_small.cpp b/ground/gcs/src/libs/eigen/test/eigen2/eigen2_product_small.cpp deleted file mode 100644 index 4cd8c102f3..0000000000 --- a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_product_small.cpp +++ /dev/null @@ -1,22 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. Eigen itself is part of the KDE project. -// -// Copyright (C) 2006-2008 Benoit Jacob -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#define EIGEN_NO_STATIC_ASSERT -#include "product.h" - -void test_eigen2_product_small() -{ - for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST_1( product(Matrix()) ); - CALL_SUBTEST_2( product(Matrix()) ); - CALL_SUBTEST_3( product(Matrix3d()) ); - CALL_SUBTEST_4( product(Matrix4d()) ); - CALL_SUBTEST_5( product(Matrix4f()) ); - } -} diff --git a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_qr.cpp b/ground/gcs/src/libs/eigen/test/eigen2/eigen2_qr.cpp deleted file mode 100644 index 76977e4c1c..0000000000 --- a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_qr.cpp +++ /dev/null @@ -1,69 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. Eigen itself is part of the KDE project. -// -// Copyright (C) 2008 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#include "main.h" -#include - -template void qr(const MatrixType& m) -{ - /* this test covers the following files: - QR.h - */ - int rows = m.rows(); - int cols = m.cols(); - - typedef typename MatrixType::Scalar Scalar; - typedef Matrix SquareMatrixType; - typedef Matrix VectorType; - - MatrixType a = MatrixType::Random(rows,cols); - QR qrOfA(a); - VERIFY_IS_APPROX(a, qrOfA.matrixQ() * qrOfA.matrixR()); - VERIFY_IS_NOT_APPROX(a+MatrixType::Identity(rows, cols), qrOfA.matrixQ() * qrOfA.matrixR()); - - #if 0 // eigenvalues module not yet ready - SquareMatrixType b = a.adjoint() * a; - - // check tridiagonalization - Tridiagonalization tridiag(b); - VERIFY_IS_APPROX(b, tridiag.matrixQ() * tridiag.matrixT() * tridiag.matrixQ().adjoint()); - - // check hessenberg decomposition - HessenbergDecomposition hess(b); - VERIFY_IS_APPROX(b, hess.matrixQ() * hess.matrixH() * hess.matrixQ().adjoint()); - VERIFY_IS_APPROX(tridiag.matrixT(), hess.matrixH()); - b = SquareMatrixType::Random(cols,cols); - hess.compute(b); - VERIFY_IS_APPROX(b, hess.matrixQ() * hess.matrixH() * hess.matrixQ().adjoint()); - #endif -} - -void test_eigen2_qr() -{ - for(int i = 0; i < 1; i++) { - CALL_SUBTEST_1( qr(Matrix2f()) ); - CALL_SUBTEST_2( qr(Matrix4d()) ); - CALL_SUBTEST_3( qr(MatrixXf(12,8)) ); - CALL_SUBTEST_4( qr(MatrixXcd(5,5)) ); - CALL_SUBTEST_4( qr(MatrixXcd(7,3)) ); - } - -#ifdef EIGEN_TEST_PART_5 - // small isFullRank test - { - Matrix3d mat; - mat << 1, 45, 1, 2, 2, 2, 1, 2, 3; - VERIFY(mat.qr().isFullRank()); - mat << 1, 1, 1, 2, 2, 2, 1, 2, 3; - //always returns true in eigen2support - //VERIFY(!mat.qr().isFullRank()); - } - -#endif -} diff --git a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_qtvector.cpp b/ground/gcs/src/libs/eigen/test/eigen2/eigen2_qtvector.cpp deleted file mode 100644 index 6cfb58a26c..0000000000 --- a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_qtvector.cpp +++ /dev/null @@ -1,158 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. Eigen itself is part of the KDE project. -// -// Copyright (C) 2008 Gael Guennebaud -// Copyright (C) 2008 Benoit Jacob -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#define EIGEN_WORK_AROUND_QT_BUG_CALLING_WRONG_OPERATOR_NEW_FIXED_IN_QT_4_5 - -#include "main.h" - -#include -#include - -#include - -template -void check_qtvector_matrix(const MatrixType& m) -{ - int rows = m.rows(); - int cols = m.cols(); - MatrixType x = MatrixType::Random(rows,cols), y = MatrixType::Random(rows,cols); - QVector v(10, MatrixType(rows,cols)), w(20, y); - for(int i = 0; i < 20; i++) - { - VERIFY_IS_APPROX(w[i], y); - } - v[5] = x; - w[6] = v[5]; - VERIFY_IS_APPROX(w[6], v[5]); - v = w; - for(int i = 0; i < 20; i++) - { - VERIFY_IS_APPROX(w[i], v[i]); - } - - v.resize(21); - v[20] = x; - VERIFY_IS_APPROX(v[20], x); - v.fill(y,22); - VERIFY_IS_APPROX(v[21], y); - v.push_back(x); - VERIFY_IS_APPROX(v[22], x); - VERIFY((size_t)&(v[22]) == (size_t)&(v[21]) + sizeof(MatrixType)); - - // do a lot of push_back such that the vector gets internally resized - // (with memory reallocation) - MatrixType* ref = &w[0]; - for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i) - v.push_back(w[i%w.size()]); - for(int i=23; i -void check_qtvector_transform(const TransformType&) -{ - typedef typename TransformType::MatrixType MatrixType; - TransformType x(MatrixType::Random()), y(MatrixType::Random()); - QVector v(10), w(20, y); - v[5] = x; - w[6] = v[5]; - VERIFY_IS_APPROX(w[6], v[5]); - v = w; - for(int i = 0; i < 20; i++) - { - VERIFY_IS_APPROX(w[i], v[i]); - } - - v.resize(21); - v[20] = x; - VERIFY_IS_APPROX(v[20], x); - v.fill(y,22); - VERIFY_IS_APPROX(v[21], y); - v.push_back(x); - VERIFY_IS_APPROX(v[22], x); - VERIFY((size_t)&(v[22]) == (size_t)&(v[21]) + sizeof(TransformType)); - - // do a lot of push_back such that the vector gets internally resized - // (with memory reallocation) - TransformType* ref = &w[0]; - for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i) - v.push_back(w[i%w.size()]); - for(unsigned int i=23; int(i) -void check_qtvector_quaternion(const QuaternionType&) -{ - typedef typename QuaternionType::Coefficients Coefficients; - QuaternionType x(Coefficients::Random()), y(Coefficients::Random()); - QVector v(10), w(20, y); - v[5] = x; - w[6] = v[5]; - VERIFY_IS_APPROX(w[6], v[5]); - v = w; - for(int i = 0; i < 20; i++) - { - VERIFY_IS_APPROX(w[i], v[i]); - } - - v.resize(21); - v[20] = x; - VERIFY_IS_APPROX(v[20], x); - v.fill(y,22); - VERIFY_IS_APPROX(v[21], y); - v.push_back(x); - VERIFY_IS_APPROX(v[22], x); - VERIFY((size_t)&(v[22]) == (size_t)&(v[21]) + sizeof(QuaternionType)); - - // do a lot of push_back such that the vector gets internally resized - // (with memory reallocation) - QuaternionType* ref = &w[0]; - for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i) - v.push_back(w[i%w.size()]); - for(unsigned int i=23; int(i) -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#include "main.h" -#include - -template -void makeNoisyCohyperplanarPoints(int numPoints, - VectorType **points, - HyperplaneType *hyperplane, - typename VectorType::Scalar noiseAmplitude) -{ - typedef typename VectorType::Scalar Scalar; - const int size = points[0]->size(); - // pick a random hyperplane, store the coefficients of its equation - hyperplane->coeffs().resize(size + 1); - for(int j = 0; j < size + 1; j++) - { - do { - hyperplane->coeffs().coeffRef(j) = ei_random(); - } while(ei_abs(hyperplane->coeffs().coeff(j)) < 0.5); - } - - // now pick numPoints random points on this hyperplane - for(int i = 0; i < numPoints; i++) - { - VectorType& cur_point = *(points[i]); - do - { - cur_point = VectorType::Random(size)/*.normalized()*/; - // project cur_point onto the hyperplane - Scalar x = - (hyperplane->coeffs().start(size).cwise()*cur_point).sum(); - cur_point *= hyperplane->coeffs().coeff(size) / x; - } while( cur_point.norm() < 0.5 - || cur_point.norm() > 2.0 ); - } - - // add some noise to these points - for(int i = 0; i < numPoints; i++ ) - *(points[i]) += noiseAmplitude * VectorType::Random(size); -} - -template -void check_linearRegression(int numPoints, - VectorType **points, - const VectorType& original, - typename VectorType::Scalar tolerance) -{ - int size = points[0]->size(); - assert(size==2); - VectorType result(size); - linearRegression(numPoints, points, &result, 1); - typename VectorType::Scalar error = (result - original).norm() / original.norm(); - VERIFY(ei_abs(error) < ei_abs(tolerance)); -} - -template -void check_fitHyperplane(int numPoints, - VectorType **points, - const HyperplaneType& original, - typename VectorType::Scalar tolerance) -{ - int size = points[0]->size(); - HyperplaneType result(size); - fitHyperplane(numPoints, points, &result); - result.coeffs() *= original.coeffs().coeff(size)/result.coeffs().coeff(size); - typename VectorType::Scalar error = (result.coeffs() - original.coeffs()).norm() / original.coeffs().norm(); - std::cout << ei_abs(error) << " xxx " << ei_abs(tolerance) << std::endl; - VERIFY(ei_abs(error) < ei_abs(tolerance)); -} - -void test_eigen2_regression() -{ - for(int i = 0; i < g_repeat; i++) - { -#ifdef EIGEN_TEST_PART_1 - { - Vector2f points2f [1000]; - Vector2f *points2f_ptrs [1000]; - for(int i = 0; i < 1000; i++) points2f_ptrs[i] = &(points2f[i]); - Vector2f coeffs2f; - Hyperplane coeffs3f; - makeNoisyCohyperplanarPoints(1000, points2f_ptrs, &coeffs3f, 0.01f); - coeffs2f[0] = -coeffs3f.coeffs()[0]/coeffs3f.coeffs()[1]; - coeffs2f[1] = -coeffs3f.coeffs()[2]/coeffs3f.coeffs()[1]; - CALL_SUBTEST(check_linearRegression(10, points2f_ptrs, coeffs2f, 0.05f)); - CALL_SUBTEST(check_linearRegression(100, points2f_ptrs, coeffs2f, 0.01f)); - CALL_SUBTEST(check_linearRegression(1000, points2f_ptrs, coeffs2f, 0.002f)); - } -#endif -#ifdef EIGEN_TEST_PART_2 - { - Vector2f points2f [1000]; - Vector2f *points2f_ptrs [1000]; - for(int i = 0; i < 1000; i++) points2f_ptrs[i] = &(points2f[i]); - Hyperplane coeffs3f; - makeNoisyCohyperplanarPoints(1000, points2f_ptrs, &coeffs3f, 0.01f); - CALL_SUBTEST(check_fitHyperplane(10, points2f_ptrs, coeffs3f, 0.05f)); - CALL_SUBTEST(check_fitHyperplane(100, points2f_ptrs, coeffs3f, 0.01f)); - CALL_SUBTEST(check_fitHyperplane(1000, points2f_ptrs, coeffs3f, 0.002f)); - } -#endif -#ifdef EIGEN_TEST_PART_3 - { - Vector4d points4d [1000]; - Vector4d *points4d_ptrs [1000]; - for(int i = 0; i < 1000; i++) points4d_ptrs[i] = &(points4d[i]); - Hyperplane coeffs5d; - makeNoisyCohyperplanarPoints(1000, points4d_ptrs, &coeffs5d, 0.01); - CALL_SUBTEST(check_fitHyperplane(10, points4d_ptrs, coeffs5d, 0.05)); - CALL_SUBTEST(check_fitHyperplane(100, points4d_ptrs, coeffs5d, 0.01)); - CALL_SUBTEST(check_fitHyperplane(1000, points4d_ptrs, coeffs5d, 0.002)); - } -#endif -#ifdef EIGEN_TEST_PART_4 - { - VectorXcd *points11cd_ptrs[1000]; - for(int i = 0; i < 1000; i++) points11cd_ptrs[i] = new VectorXcd(11); - Hyperplane,Dynamic> *coeffs12cd = new Hyperplane,Dynamic>(11); - makeNoisyCohyperplanarPoints(1000, points11cd_ptrs, coeffs12cd, 0.01); - CALL_SUBTEST(check_fitHyperplane(100, points11cd_ptrs, *coeffs12cd, 0.025)); - CALL_SUBTEST(check_fitHyperplane(1000, points11cd_ptrs, *coeffs12cd, 0.006)); - delete coeffs12cd; - for(int i = 0; i < 1000; i++) delete points11cd_ptrs[i]; - } -#endif - } -} diff --git a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_sizeof.cpp b/ground/gcs/src/libs/eigen/test/eigen2/eigen2_sizeof.cpp deleted file mode 100644 index ec1af5a066..0000000000 --- a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_sizeof.cpp +++ /dev/null @@ -1,31 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. Eigen itself is part of the KDE project. -// -// Copyright (C) 2008 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#include "main.h" - -template void verifySizeOf(const MatrixType&) -{ - typedef typename MatrixType::Scalar Scalar; - if (MatrixType::RowsAtCompileTime!=Dynamic && MatrixType::ColsAtCompileTime!=Dynamic) - VERIFY(sizeof(MatrixType)==sizeof(Scalar)*MatrixType::SizeAtCompileTime); - else - VERIFY(sizeof(MatrixType)==sizeof(Scalar*) + 2 * sizeof(typename MatrixType::Index)); -} - -void test_eigen2_sizeof() -{ - CALL_SUBTEST( verifySizeOf(Matrix()) ); - CALL_SUBTEST( verifySizeOf(Matrix4d()) ); - CALL_SUBTEST( verifySizeOf(Matrix()) ); - CALL_SUBTEST( verifySizeOf(Matrix()) ); - CALL_SUBTEST( verifySizeOf(MatrixXcf(3, 3)) ); - CALL_SUBTEST( verifySizeOf(MatrixXi(8, 12)) ); - CALL_SUBTEST( verifySizeOf(MatrixXcd(20, 20)) ); - CALL_SUBTEST( verifySizeOf(Matrix()) ); -} diff --git a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_smallvectors.cpp b/ground/gcs/src/libs/eigen/test/eigen2/eigen2_smallvectors.cpp deleted file mode 100644 index 03962b17d9..0000000000 --- a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_smallvectors.cpp +++ /dev/null @@ -1,42 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. Eigen itself is part of the KDE project. -// -// Copyright (C) 2006-2008 Benoit Jacob -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#include "main.h" - -template void smallVectors() -{ - typedef Matrix V2; - typedef Matrix V3; - typedef Matrix V4; - Scalar x1 = ei_random(), - x2 = ei_random(), - x3 = ei_random(), - x4 = ei_random(); - V2 v2(x1, x2); - V3 v3(x1, x2, x3); - V4 v4(x1, x2, x3, x4); - VERIFY_IS_APPROX(x1, v2.x()); - VERIFY_IS_APPROX(x1, v3.x()); - VERIFY_IS_APPROX(x1, v4.x()); - VERIFY_IS_APPROX(x2, v2.y()); - VERIFY_IS_APPROX(x2, v3.y()); - VERIFY_IS_APPROX(x2, v4.y()); - VERIFY_IS_APPROX(x3, v3.z()); - VERIFY_IS_APPROX(x3, v4.z()); - VERIFY_IS_APPROX(x4, v4.w()); -} - -void test_eigen2_smallvectors() -{ - for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST( smallVectors() ); - CALL_SUBTEST( smallVectors() ); - CALL_SUBTEST( smallVectors() ); - } -} diff --git a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_sparse_basic.cpp b/ground/gcs/src/libs/eigen/test/eigen2/eigen2_sparse_basic.cpp deleted file mode 100644 index 049077670e..0000000000 --- a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_sparse_basic.cpp +++ /dev/null @@ -1,317 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. Eigen itself is part of the KDE project. -// -// Copyright (C) 2008 Daniel Gomez Ferro -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#include "sparse.h" - -template -bool test_random_setter(SparseMatrix& sm, const DenseType& ref, const std::vector& nonzeroCoords) -{ - typedef SparseMatrix SparseType; - { - sm.setZero(); - SetterType w(sm); - std::vector remaining = nonzeroCoords; - while(!remaining.empty()) - { - int i = ei_random(0,remaining.size()-1); - w(remaining[i].x(),remaining[i].y()) = ref.coeff(remaining[i].x(),remaining[i].y()); - remaining[i] = remaining.back(); - remaining.pop_back(); - } - } - return sm.isApprox(ref); -} - -template -bool test_random_setter(DynamicSparseMatrix& sm, const DenseType& ref, const std::vector& nonzeroCoords) -{ - sm.setZero(); - std::vector remaining = nonzeroCoords; - while(!remaining.empty()) - { - int i = ei_random(0,remaining.size()-1); - sm.coeffRef(remaining[i].x(),remaining[i].y()) = ref.coeff(remaining[i].x(),remaining[i].y()); - remaining[i] = remaining.back(); - remaining.pop_back(); - } - return sm.isApprox(ref); -} - -template void sparse_basic(const SparseMatrixType& ref) -{ - const int rows = ref.rows(); - const int cols = ref.cols(); - typedef typename SparseMatrixType::Scalar Scalar; - enum { Flags = SparseMatrixType::Flags }; - - double density = std::max(8./(rows*cols), 0.01); - typedef Matrix DenseMatrix; - typedef Matrix DenseVector; - Scalar eps = 1e-6; - - SparseMatrixType m(rows, cols); - DenseMatrix refMat = DenseMatrix::Zero(rows, cols); - DenseVector vec1 = DenseVector::Random(rows); - Scalar s1 = ei_random(); - - std::vector zeroCoords; - std::vector nonzeroCoords; - initSparse(density, refMat, m, 0, &zeroCoords, &nonzeroCoords); - - if (zeroCoords.size()==0 || nonzeroCoords.size()==0) - return; - - // test coeff and coeffRef - for (int i=0; i<(int)zeroCoords.size(); ++i) - { - VERIFY_IS_MUCH_SMALLER_THAN( m.coeff(zeroCoords[i].x(),zeroCoords[i].y()), eps ); - if(ei_is_same_type >::ret) - VERIFY_RAISES_ASSERT( m.coeffRef(zeroCoords[0].x(),zeroCoords[0].y()) = 5 ); - } - VERIFY_IS_APPROX(m, refMat); - - m.coeffRef(nonzeroCoords[0].x(), nonzeroCoords[0].y()) = Scalar(5); - refMat.coeffRef(nonzeroCoords[0].x(), nonzeroCoords[0].y()) = Scalar(5); - - VERIFY_IS_APPROX(m, refMat); - /* - // test InnerIterators and Block expressions - for (int t=0; t<10; ++t) - { - int j = ei_random(0,cols-1); - int i = ei_random(0,rows-1); - int w = ei_random(1,cols-j-1); - int h = ei_random(1,rows-i-1); - -// VERIFY_IS_APPROX(m.block(i,j,h,w), refMat.block(i,j,h,w)); - for(int c=0; c w(m); -// for (int i=0; icoeffRef(nonzeroCoords[i].x(),nonzeroCoords[i].y()) = refMat.coeff(nonzeroCoords[i].x(),nonzeroCoords[i].y()); -// } -// } -// VERIFY_IS_APPROX(m, refMat); - - // random setter -// { -// m.setZero(); -// VERIFY_IS_NOT_APPROX(m, refMat); -// SparseSetter w(m); -// std::vector remaining = nonzeroCoords; -// while(!remaining.empty()) -// { -// int i = ei_random(0,remaining.size()-1); -// w->coeffRef(remaining[i].x(),remaining[i].y()) = refMat.coeff(remaining[i].x(),remaining[i].y()); -// remaining[i] = remaining.back(); -// remaining.pop_back(); -// } -// } -// VERIFY_IS_APPROX(m, refMat); - - VERIFY(( test_random_setter >(m,refMat,nonzeroCoords) )); - #ifdef EIGEN_UNORDERED_MAP_SUPPORT - VERIFY(( test_random_setter >(m,refMat,nonzeroCoords) )); - #endif - #ifdef _DENSE_HASH_MAP_H_ - VERIFY(( test_random_setter >(m,refMat,nonzeroCoords) )); - #endif - #ifdef _SPARSE_HASH_MAP_H_ - VERIFY(( test_random_setter >(m,refMat,nonzeroCoords) )); - #endif - - // test fillrand - { - DenseMatrix m1(rows,cols); - m1.setZero(); - SparseMatrixType m2(rows,cols); - m2.startFill(); - for (int j=0; j(0,rows-1); - if (m1.coeff(i,j)==Scalar(0)) - m2.fillrand(i,j) = m1(i,j) = ei_random(); - } - } - m2.endFill(); - VERIFY_IS_APPROX(m2,m1); - } - - // test RandomSetter - /*{ - SparseMatrixType m1(rows,cols), m2(rows,cols); - DenseMatrix refM1 = DenseMatrix::Zero(rows, rows); - initSparse(density, refM1, m1); - { - Eigen::RandomSetter setter(m2); - for (int j=0; j(density, refM1, m1); - initSparse(density, refM2, m2); - initSparse(density, refM3, m3); - initSparse(density, refM4, m4); - - VERIFY_IS_APPROX(m1+m2, refM1+refM2); - VERIFY_IS_APPROX(m1+m2+m3, refM1+refM2+refM3); - VERIFY_IS_APPROX(m3.cwise()*(m1+m2), refM3.cwise()*(refM1+refM2)); - VERIFY_IS_APPROX(m1*s1-m2, refM1*s1-refM2); - - VERIFY_IS_APPROX(m1*=s1, refM1*=s1); - VERIFY_IS_APPROX(m1/=s1, refM1/=s1); - - VERIFY_IS_APPROX(m1+=m2, refM1+=refM2); - VERIFY_IS_APPROX(m1-=m2, refM1-=refM2); - - VERIFY_IS_APPROX(m1.col(0).eigen2_dot(refM2.row(0)), refM1.col(0).eigen2_dot(refM2.row(0))); - - refM4.setRandom(); - // sparse cwise* dense - VERIFY_IS_APPROX(m3.cwise()*refM4, refM3.cwise()*refM4); -// VERIFY_IS_APPROX(m3.cwise()/refM4, refM3.cwise()/refM4); - } - - // test innerVector() - { - DenseMatrix refMat2 = DenseMatrix::Zero(rows, rows); - SparseMatrixType m2(rows, rows); - initSparse(density, refMat2, m2); - int j0 = ei_random(0,rows-1); - int j1 = ei_random(0,rows-1); - VERIFY_IS_APPROX(m2.innerVector(j0), refMat2.col(j0)); - VERIFY_IS_APPROX(m2.innerVector(j0)+m2.innerVector(j1), refMat2.col(j0)+refMat2.col(j1)); - //m2.innerVector(j0) = 2*m2.innerVector(j1); - //refMat2.col(j0) = 2*refMat2.col(j1); - //VERIFY_IS_APPROX(m2, refMat2); - } - - // test innerVectors() - { - DenseMatrix refMat2 = DenseMatrix::Zero(rows, rows); - SparseMatrixType m2(rows, rows); - initSparse(density, refMat2, m2); - int j0 = ei_random(0,rows-2); - int j1 = ei_random(0,rows-2); - int n0 = ei_random(1,rows-std::max(j0,j1)); - VERIFY_IS_APPROX(m2.innerVectors(j0,n0), refMat2.block(0,j0,rows,n0)); - VERIFY_IS_APPROX(m2.innerVectors(j0,n0)+m2.innerVectors(j1,n0), - refMat2.block(0,j0,rows,n0)+refMat2.block(0,j1,rows,n0)); - //m2.innerVectors(j0,n0) = m2.innerVectors(j0,n0) + m2.innerVectors(j1,n0); - //refMat2.block(0,j0,rows,n0) = refMat2.block(0,j0,rows,n0) + refMat2.block(0,j1,rows,n0); - } - - // test transpose - { - DenseMatrix refMat2 = DenseMatrix::Zero(rows, rows); - SparseMatrixType m2(rows, rows); - initSparse(density, refMat2, m2); - VERIFY_IS_APPROX(m2.transpose().eval(), refMat2.transpose().eval()); - VERIFY_IS_APPROX(m2.transpose(), refMat2.transpose()); - } - - // test prune - { - SparseMatrixType m2(rows, rows); - DenseMatrix refM2(rows, rows); - refM2.setZero(); - int countFalseNonZero = 0; - int countTrueNonZero = 0; - m2.startFill(); - for (int j=0; j(0,1); - if (x<0.1) - { - // do nothing - } - else if (x<0.5) - { - countFalseNonZero++; - m2.fill(i,j) = Scalar(0); - } - else - { - countTrueNonZero++; - m2.fill(i,j) = refM2(i,j) = Scalar(1); - } - } - m2.endFill(); - VERIFY(countFalseNonZero+countTrueNonZero == m2.nonZeros()); - VERIFY_IS_APPROX(m2, refM2); - m2.prune(1); - VERIFY(countTrueNonZero==m2.nonZeros()); - VERIFY_IS_APPROX(m2, refM2); - } -} - -void test_eigen2_sparse_basic() -{ - for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST_1( sparse_basic(SparseMatrix(8, 8)) ); - CALL_SUBTEST_2( sparse_basic(SparseMatrix >(16, 16)) ); - CALL_SUBTEST_1( sparse_basic(SparseMatrix(33, 33)) ); - - CALL_SUBTEST_3( sparse_basic(DynamicSparseMatrix(8, 8)) ); - } -} diff --git a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_sparse_product.cpp b/ground/gcs/src/libs/eigen/test/eigen2/eigen2_sparse_product.cpp deleted file mode 100644 index d28e76dff7..0000000000 --- a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_sparse_product.cpp +++ /dev/null @@ -1,115 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. Eigen itself is part of the KDE project. -// -// Copyright (C) 2008 Daniel Gomez Ferro -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#include "sparse.h" - -template void sparse_product(const SparseMatrixType& ref) -{ - const int rows = ref.rows(); - const int cols = ref.cols(); - typedef typename SparseMatrixType::Scalar Scalar; - enum { Flags = SparseMatrixType::Flags }; - - double density = std::max(8./(rows*cols), 0.01); - typedef Matrix DenseMatrix; - typedef Matrix DenseVector; - - // test matrix-matrix product - { - DenseMatrix refMat2 = DenseMatrix::Zero(rows, rows); - DenseMatrix refMat3 = DenseMatrix::Zero(rows, rows); - DenseMatrix refMat4 = DenseMatrix::Zero(rows, rows); - DenseMatrix dm4 = DenseMatrix::Zero(rows, rows); - SparseMatrixType m2(rows, rows); - SparseMatrixType m3(rows, rows); - SparseMatrixType m4(rows, rows); - initSparse(density, refMat2, m2); - initSparse(density, refMat3, m3); - initSparse(density, refMat4, m4); - VERIFY_IS_APPROX(m4=m2*m3, refMat4=refMat2*refMat3); - VERIFY_IS_APPROX(m4=m2.transpose()*m3, refMat4=refMat2.transpose()*refMat3); - VERIFY_IS_APPROX(m4=m2.transpose()*m3.transpose(), refMat4=refMat2.transpose()*refMat3.transpose()); - VERIFY_IS_APPROX(m4=m2*m3.transpose(), refMat4=refMat2*refMat3.transpose()); - - // sparse * dense - VERIFY_IS_APPROX(dm4=m2*refMat3, refMat4=refMat2*refMat3); - VERIFY_IS_APPROX(dm4=m2*refMat3.transpose(), refMat4=refMat2*refMat3.transpose()); - VERIFY_IS_APPROX(dm4=m2.transpose()*refMat3, refMat4=refMat2.transpose()*refMat3); - VERIFY_IS_APPROX(dm4=m2.transpose()*refMat3.transpose(), refMat4=refMat2.transpose()*refMat3.transpose()); - - // dense * sparse - VERIFY_IS_APPROX(dm4=refMat2*m3, refMat4=refMat2*refMat3); - VERIFY_IS_APPROX(dm4=refMat2*m3.transpose(), refMat4=refMat2*refMat3.transpose()); - VERIFY_IS_APPROX(dm4=refMat2.transpose()*m3, refMat4=refMat2.transpose()*refMat3); - VERIFY_IS_APPROX(dm4=refMat2.transpose()*m3.transpose(), refMat4=refMat2.transpose()*refMat3.transpose()); - - VERIFY_IS_APPROX(m3=m3*m3, refMat3=refMat3*refMat3); - } - - // test matrix - diagonal product - if(false) // it compiles, but the precision is terrible. probably doesn't matter in this branch.... - { - DenseMatrix refM2 = DenseMatrix::Zero(rows, rows); - DenseMatrix refM3 = DenseMatrix::Zero(rows, rows); - DiagonalMatrix d1(DenseVector::Random(rows)); - SparseMatrixType m2(rows, rows); - SparseMatrixType m3(rows, rows); - initSparse(density, refM2, m2); - initSparse(density, refM3, m3); - VERIFY_IS_APPROX(m3=m2*d1, refM3=refM2*d1); - VERIFY_IS_APPROX(m3=m2.transpose()*d1, refM3=refM2.transpose()*d1); - VERIFY_IS_APPROX(m3=d1*m2, refM3=d1*refM2); - VERIFY_IS_APPROX(m3=d1*m2.transpose(), refM3=d1 * refM2.transpose()); - } - - // test self adjoint products - { - DenseMatrix b = DenseMatrix::Random(rows, rows); - DenseMatrix x = DenseMatrix::Random(rows, rows); - DenseMatrix refX = DenseMatrix::Random(rows, rows); - DenseMatrix refUp = DenseMatrix::Zero(rows, rows); - DenseMatrix refLo = DenseMatrix::Zero(rows, rows); - DenseMatrix refS = DenseMatrix::Zero(rows, rows); - SparseMatrixType mUp(rows, rows); - SparseMatrixType mLo(rows, rows); - SparseMatrixType mS(rows, rows); - do { - initSparse(density, refUp, mUp, ForceRealDiag|/*ForceNonZeroDiag|*/MakeUpperTriangular); - } while (refUp.isZero()); - refLo = refUp.transpose().conjugate(); - mLo = mUp.transpose().conjugate(); - refS = refUp + refLo; - refS.diagonal() *= 0.5; - mS = mUp + mLo; - for (int k=0; k()*b, refX=refS*b); - VERIFY_IS_APPROX(x=mLo.template marked()*b, refX=refS*b); - VERIFY_IS_APPROX(x=mS.template marked()*b, refX=refS*b); - } - -} - -void test_eigen2_sparse_product() -{ - for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST_1( sparse_product(SparseMatrix(8, 8)) ); - CALL_SUBTEST_2( sparse_product(SparseMatrix >(16, 16)) ); - CALL_SUBTEST_1( sparse_product(SparseMatrix(33, 33)) ); - - CALL_SUBTEST_3( sparse_product(DynamicSparseMatrix(8, 8)) ); - } -} diff --git a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_sparse_solvers.cpp b/ground/gcs/src/libs/eigen/test/eigen2/eigen2_sparse_solvers.cpp deleted file mode 100644 index 3aef27ab40..0000000000 --- a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_sparse_solvers.cpp +++ /dev/null @@ -1,200 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. Eigen itself is part of the KDE project. -// -// Copyright (C) 2008 Daniel Gomez Ferro -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#include "sparse.h" - -template void -initSPD(double density, - Matrix& refMat, - SparseMatrix& sparseMat) -{ - Matrix aux(refMat.rows(),refMat.cols()); - initSparse(density,refMat,sparseMat); - refMat = refMat * refMat.adjoint(); - for (int k=0; k<2; ++k) - { - initSparse(density,aux,sparseMat,ForceNonZeroDiag); - refMat += aux * aux.adjoint(); - } - sparseMat.startFill(); - for (int j=0 ; j void sparse_solvers(int rows, int cols) -{ - double density = std::max(8./(rows*cols), 0.01); - typedef Matrix DenseMatrix; - typedef Matrix DenseVector; - // Scalar eps = 1e-6; - - DenseVector vec1 = DenseVector::Random(rows); - - std::vector zeroCoords; - std::vector nonzeroCoords; - - // test triangular solver - { - DenseVector vec2 = vec1, vec3 = vec1; - SparseMatrix m2(rows, cols); - DenseMatrix refMat2 = DenseMatrix::Zero(rows, cols); - - // lower - initSparse(density, refMat2, m2, ForceNonZeroDiag|MakeLowerTriangular, &zeroCoords, &nonzeroCoords); - VERIFY_IS_APPROX(refMat2.template marked().solveTriangular(vec2), - m2.template marked().solveTriangular(vec3)); - - // lower - transpose - initSparse(density, refMat2, m2, ForceNonZeroDiag|MakeLowerTriangular, &zeroCoords, &nonzeroCoords); - VERIFY_IS_APPROX(refMat2.template marked().transpose().solveTriangular(vec2), - m2.template marked().transpose().solveTriangular(vec3)); - - // upper - initSparse(density, refMat2, m2, ForceNonZeroDiag|MakeUpperTriangular, &zeroCoords, &nonzeroCoords); - VERIFY_IS_APPROX(refMat2.template marked().solveTriangular(vec2), - m2.template marked().solveTriangular(vec3)); - - // upper - transpose - initSparse(density, refMat2, m2, ForceNonZeroDiag|MakeUpperTriangular, &zeroCoords, &nonzeroCoords); - VERIFY_IS_APPROX(refMat2.template marked().transpose().solveTriangular(vec2), - m2.template marked().transpose().solveTriangular(vec3)); - } - - // test LLT - { - // TODO fix the issue with complex (see SparseLLT::solveInPlace) - SparseMatrix m2(rows, cols); - DenseMatrix refMat2(rows, cols); - - DenseVector b = DenseVector::Random(cols); - DenseVector refX(cols), x(cols); - - initSPD(density, refMat2, m2); - - refMat2.llt().solve(b, &refX); - typedef SparseMatrix SparseSelfAdjointMatrix; - if (!NumTraits::IsComplex) - { - x = b; - SparseLLT (m2).solveInPlace(x); - VERIFY(refX.isApprox(x,test_precision()) && "LLT: default"); - } - #ifdef EIGEN_CHOLMOD_SUPPORT - x = b; - SparseLLT(m2).solveInPlace(x); - VERIFY(refX.isApprox(x,test_precision()) && "LLT: cholmod"); - #endif - if (!NumTraits::IsComplex) - { - #ifdef EIGEN_TAUCS_SUPPORT - x = b; - SparseLLT(m2,IncompleteFactorization).solveInPlace(x); - VERIFY(refX.isApprox(x,test_precision()) && "LLT: taucs (IncompleteFactorization)"); - x = b; - SparseLLT(m2,SupernodalMultifrontal).solveInPlace(x); - VERIFY(refX.isApprox(x,test_precision()) && "LLT: taucs (SupernodalMultifrontal)"); - x = b; - SparseLLT(m2,SupernodalLeftLooking).solveInPlace(x); - VERIFY(refX.isApprox(x,test_precision()) && "LLT: taucs (SupernodalLeftLooking)"); - #endif - } - } - - // test LDLT - if (!NumTraits::IsComplex) - { - // TODO fix the issue with complex (see SparseLDLT::solveInPlace) - SparseMatrix m2(rows, cols); - DenseMatrix refMat2(rows, cols); - - DenseVector b = DenseVector::Random(cols); - DenseVector refX(cols), x(cols); - - //initSPD(density, refMat2, m2); - initSparse(density, refMat2, m2, ForceNonZeroDiag|MakeUpperTriangular, 0, 0); - refMat2 += refMat2.adjoint(); - refMat2.diagonal() *= 0.5; - - refMat2.ldlt().solve(b, &refX); - typedef SparseMatrix SparseSelfAdjointMatrix; - x = b; - SparseLDLT ldlt(m2); - if (ldlt.succeeded()) - ldlt.solveInPlace(x); - VERIFY(refX.isApprox(x,test_precision()) && "LDLT: default"); - } - - // test LU - { - static int count = 0; - SparseMatrix m2(rows, cols); - DenseMatrix refMat2(rows, cols); - - DenseVector b = DenseVector::Random(cols); - DenseVector refX(cols), x(cols); - - initSparse(density, refMat2, m2, ForceNonZeroDiag, &zeroCoords, &nonzeroCoords); - - LU refLu(refMat2); - refLu.solve(b, &refX); - #if defined(EIGEN_SUPERLU_SUPPORT) || defined(EIGEN_UMFPACK_SUPPORT) - Scalar refDet = refLu.determinant(); - #endif - x.setZero(); - // // SparseLU > (m2).solve(b,&x); - // // VERIFY(refX.isApprox(x,test_precision()) && "LU: default"); - #ifdef EIGEN_SUPERLU_SUPPORT - { - x.setZero(); - SparseLU,SuperLU> slu(m2); - if (slu.succeeded()) - { - if (slu.solve(b,&x)) { - VERIFY(refX.isApprox(x,test_precision()) && "LU: SuperLU"); - } - // std::cerr << refDet << " == " << slu.determinant() << "\n"; - if (count==0) { - VERIFY_IS_APPROX(refDet,slu.determinant()); // FIXME det is not very stable for complex - } - } - } - #endif - #ifdef EIGEN_UMFPACK_SUPPORT - { - // check solve - x.setZero(); - SparseLU,UmfPack> slu(m2); - if (slu.succeeded()) { - if (slu.solve(b,&x)) { - if (count==0) { - VERIFY(refX.isApprox(x,test_precision()) && "LU: umfpack"); // FIXME solve is not very stable for complex - } - } - VERIFY_IS_APPROX(refDet,slu.determinant()); - // TODO check the extracted data - //std::cerr << slu.matrixL() << "\n"; - } - } - #endif - count++; - } - -} - -void test_eigen2_sparse_solvers() -{ - for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST_1( sparse_solvers(8, 8) ); - CALL_SUBTEST_2( sparse_solvers >(16, 16) ); - CALL_SUBTEST_1( sparse_solvers(101, 101) ); - } -} diff --git a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_sparse_vector.cpp b/ground/gcs/src/libs/eigen/test/eigen2/eigen2_sparse_vector.cpp deleted file mode 100644 index e6d2d77a1b..0000000000 --- a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_sparse_vector.cpp +++ /dev/null @@ -1,84 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. Eigen itself is part of the KDE project. -// -// Copyright (C) 2008 Daniel Gomez Ferro -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#include "sparse.h" - -template void sparse_vector(int rows, int cols) -{ - double densityMat = std::max(8./(rows*cols), 0.01); - double densityVec = std::max(8./float(rows), 0.1); - typedef Matrix DenseMatrix; - typedef Matrix DenseVector; - typedef SparseVector SparseVectorType; - typedef SparseMatrix SparseMatrixType; - Scalar eps = 1e-6; - - SparseMatrixType m1(rows,cols); - SparseVectorType v1(rows), v2(rows), v3(rows); - DenseMatrix refM1 = DenseMatrix::Zero(rows, cols); - DenseVector refV1 = DenseVector::Random(rows), - refV2 = DenseVector::Random(rows), - refV3 = DenseVector::Random(rows); - - std::vector zerocoords, nonzerocoords; - initSparse(densityVec, refV1, v1, &zerocoords, &nonzerocoords); - initSparse(densityMat, refM1, m1); - - initSparse(densityVec, refV2, v2); - initSparse(densityVec, refV3, v3); - - Scalar s1 = ei_random(); - - // test coeff and coeffRef - for (unsigned int i=0; i(8, 8) ); - CALL_SUBTEST_2( sparse_vector >(16, 16) ); - CALL_SUBTEST_1( sparse_vector(299, 535) ); - } -} - diff --git a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_stdvector.cpp b/ground/gcs/src/libs/eigen/test/eigen2/eigen2_stdvector.cpp deleted file mode 100644 index 6ab05c20a3..0000000000 --- a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_stdvector.cpp +++ /dev/null @@ -1,148 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. Eigen itself is part of the KDE project. -// -// Copyright (C) 2008 Benoit Jacob -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#include -#include "main.h" -#include - -template -void check_stdvector_matrix(const MatrixType& m) -{ - int rows = m.rows(); - int cols = m.cols(); - MatrixType x = MatrixType::Random(rows,cols), y = MatrixType::Random(rows,cols); - std::vector > v(10, MatrixType(rows,cols)), w(20, y); - v[5] = x; - w[6] = v[5]; - VERIFY_IS_APPROX(w[6], v[5]); - v = w; - for(int i = 0; i < 20; i++) - { - VERIFY_IS_APPROX(w[i], v[i]); - } - - v.resize(21); - v[20] = x; - VERIFY_IS_APPROX(v[20], x); - v.resize(22,y); - VERIFY_IS_APPROX(v[21], y); - v.push_back(x); - VERIFY_IS_APPROX(v[22], x); - VERIFY((std::size_t)&(v[22]) == (std::size_t)&(v[21]) + sizeof(MatrixType)); - - // do a lot of push_back such that the vector gets internally resized - // (with memory reallocation) - MatrixType* ref = &w[0]; - for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i) - v.push_back(w[i%w.size()]); - for(unsigned int i=23; i -void check_stdvector_transform(const TransformType&) -{ - typedef typename TransformType::MatrixType MatrixType; - TransformType x(MatrixType::Random()), y(MatrixType::Random()); - std::vector > v(10), w(20, y); - v[5] = x; - w[6] = v[5]; - VERIFY_IS_APPROX(w[6], v[5]); - v = w; - for(int i = 0; i < 20; i++) - { - VERIFY_IS_APPROX(w[i], v[i]); - } - - v.resize(21); - v[20] = x; - VERIFY_IS_APPROX(v[20], x); - v.resize(22,y); - VERIFY_IS_APPROX(v[21], y); - v.push_back(x); - VERIFY_IS_APPROX(v[22], x); - VERIFY((std::size_t)&(v[22]) == (std::size_t)&(v[21]) + sizeof(TransformType)); - - // do a lot of push_back such that the vector gets internally resized - // (with memory reallocation) - TransformType* ref = &w[0]; - for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i) - v.push_back(w[i%w.size()]); - for(unsigned int i=23; i -void check_stdvector_quaternion(const QuaternionType&) -{ - typedef typename QuaternionType::Coefficients Coefficients; - QuaternionType x(Coefficients::Random()), y(Coefficients::Random()); - std::vector > v(10), w(20, y); - v[5] = x; - w[6] = v[5]; - VERIFY_IS_APPROX(w[6], v[5]); - v = w; - for(int i = 0; i < 20; i++) - { - VERIFY_IS_APPROX(w[i], v[i]); - } - - v.resize(21); - v[20] = x; - VERIFY_IS_APPROX(v[20], x); - v.resize(22,y); - VERIFY_IS_APPROX(v[21], y); - v.push_back(x); - VERIFY_IS_APPROX(v[22], x); - VERIFY((std::size_t)&(v[22]) == (std::size_t)&(v[21]) + sizeof(QuaternionType)); - - // do a lot of push_back such that the vector gets internally resized - // (with memory reallocation) - QuaternionType* ref = &w[0]; - for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i) - v.push_back(w[i%w.size()]); - for(unsigned int i=23; i -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#include "main.h" - -// check minor separately in order to avoid the possible creation of a zero-sized -// array. Comes from a compilation error with gcc-3.4 or gcc-4 with -ansi -pedantic. -// Another solution would be to declare the array like this: T m_data[Size==0?1:Size]; in ei_matrix_storage -// but this is probably not bad to raise such an error at compile time... -template struct CheckMinor -{ - typedef Matrix MatrixType; - CheckMinor(MatrixType& m1, int r1, int c1) - { - int rows = m1.rows(); - int cols = m1.cols(); - - Matrix mi = m1.minor(0,0).eval(); - VERIFY_IS_APPROX(mi, m1.block(1,1,rows-1,cols-1)); - mi = m1.minor(r1,c1); - VERIFY_IS_APPROX(mi.transpose(), m1.transpose().minor(c1,r1)); - //check operator(), both constant and non-constant, on minor() - m1.minor(r1,c1)(0,0) = m1.minor(0,0)(0,0); - } -}; - -template struct CheckMinor -{ - typedef Matrix MatrixType; - CheckMinor(MatrixType&, int, int) {} -}; - -template void submatrices(const MatrixType& m) -{ - /* this test covers the following files: - Row.h Column.h Block.h Minor.h DiagonalCoeffs.h - */ - typedef typename MatrixType::Scalar Scalar; - typedef typename MatrixType::RealScalar RealScalar; - typedef Matrix VectorType; - typedef Matrix RowVectorType; - int rows = m.rows(); - int cols = m.cols(); - - MatrixType m1 = MatrixType::Random(rows, cols), - m2 = MatrixType::Random(rows, cols), - m3(rows, cols), - ones = MatrixType::Ones(rows, cols), - square = Matrix - ::Random(rows, rows); - VectorType v1 = VectorType::Random(rows); - - Scalar s1 = ei_random(); - - int r1 = ei_random(0,rows-1); - int r2 = ei_random(r1,rows-1); - int c1 = ei_random(0,cols-1); - int c2 = ei_random(c1,cols-1); - - //check row() and col() - VERIFY_IS_APPROX(m1.col(c1).transpose(), m1.transpose().row(c1)); - VERIFY_IS_APPROX(square.row(r1).eigen2_dot(m1.col(c1)), (square.lazy() * m1.conjugate())(r1,c1)); - //check operator(), both constant and non-constant, on row() and col() - m1.row(r1) += s1 * m1.row(r2); - m1.col(c1) += s1 * m1.col(c2); - - //check block() - Matrix b1(1,1); b1(0,0) = m1(r1,c1); - RowVectorType br1(m1.block(r1,0,1,cols)); - VectorType bc1(m1.block(0,c1,rows,1)); - VERIFY_IS_APPROX(b1, m1.block(r1,c1,1,1)); - VERIFY_IS_APPROX(m1.row(r1), br1); - VERIFY_IS_APPROX(m1.col(c1), bc1); - //check operator(), both constant and non-constant, on block() - m1.block(r1,c1,r2-r1+1,c2-c1+1) = s1 * m2.block(0, 0, r2-r1+1,c2-c1+1); - m1.block(r1,c1,r2-r1+1,c2-c1+1)(r2-r1,c2-c1) = m2.block(0, 0, r2-r1+1,c2-c1+1)(0,0); - - //check minor() - CheckMinor checkminor(m1,r1,c1); - - //check diagonal() - VERIFY_IS_APPROX(m1.diagonal(), m1.transpose().diagonal()); - m2.diagonal() = 2 * m1.diagonal(); - m2.diagonal()[0] *= 3; - VERIFY_IS_APPROX(m2.diagonal()[0], static_cast(6) * m1.diagonal()[0]); - - enum { - BlockRows = EIGEN_SIZE_MIN_PREFER_FIXED(MatrixType::RowsAtCompileTime,2), - BlockCols = EIGEN_SIZE_MIN_PREFER_FIXED(MatrixType::ColsAtCompileTime,5) - }; - if (rows>=5 && cols>=8) - { - // test fixed block() as lvalue - m1.template block(1,1) *= s1; - // test operator() on fixed block() both as constant and non-constant - m1.template block(1,1)(0, 3) = m1.template block<2,5>(1,1)(1,2); - // check that fixed block() and block() agree - Matrix b = m1.template block(3,3); - VERIFY_IS_APPROX(b, m1.block(3,3,BlockRows,BlockCols)); - } - - if (rows>2) - { - // test sub vectors - VERIFY_IS_APPROX(v1.template start<2>(), v1.block(0,0,2,1)); - VERIFY_IS_APPROX(v1.template start<2>(), v1.start(2)); - VERIFY_IS_APPROX(v1.template start<2>(), v1.segment(0,2)); - VERIFY_IS_APPROX(v1.template start<2>(), v1.template segment<2>(0)); - int i = rows-2; - VERIFY_IS_APPROX(v1.template end<2>(), v1.block(i,0,2,1)); - VERIFY_IS_APPROX(v1.template end<2>(), v1.end(2)); - VERIFY_IS_APPROX(v1.template end<2>(), v1.segment(i,2)); - VERIFY_IS_APPROX(v1.template end<2>(), v1.template segment<2>(i)); - i = ei_random(0,rows-2); - VERIFY_IS_APPROX(v1.segment(i,2), v1.template segment<2>(i)); - } - - // stress some basic stuffs with block matrices - VERIFY(ei_real(ones.col(c1).sum()) == RealScalar(rows)); - VERIFY(ei_real(ones.row(r1).sum()) == RealScalar(cols)); - - VERIFY(ei_real(ones.col(c1).eigen2_dot(ones.col(c2))) == RealScalar(rows)); - VERIFY(ei_real(ones.row(r1).eigen2_dot(ones.row(r2))) == RealScalar(cols)); -} - -void test_eigen2_submatrices() -{ - for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST_1( submatrices(Matrix()) ); - CALL_SUBTEST_2( submatrices(Matrix4d()) ); - CALL_SUBTEST_3( submatrices(MatrixXcf(3, 3)) ); - CALL_SUBTEST_4( submatrices(MatrixXi(8, 12)) ); - CALL_SUBTEST_5( submatrices(MatrixXcd(20, 20)) ); - CALL_SUBTEST_6( submatrices(MatrixXf(20, 20)) ); - } -} diff --git a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_sum.cpp b/ground/gcs/src/libs/eigen/test/eigen2/eigen2_sum.cpp deleted file mode 100644 index b47057caab..0000000000 --- a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_sum.cpp +++ /dev/null @@ -1,71 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. Eigen itself is part of the KDE project. -// -// Copyright (C) 2008 Benoit Jacob -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#include "main.h" - -template void matrixSum(const MatrixType& m) -{ - typedef typename MatrixType::Scalar Scalar; - - int rows = m.rows(); - int cols = m.cols(); - - MatrixType m1 = MatrixType::Random(rows, cols); - - VERIFY_IS_MUCH_SMALLER_THAN(MatrixType::Zero(rows, cols).sum(), Scalar(1)); - VERIFY_IS_APPROX(MatrixType::Ones(rows, cols).sum(), Scalar(float(rows*cols))); // the float() here to shut up excessive MSVC warning about int->complex conversion being lossy - Scalar x = Scalar(0); - for(int i = 0; i < rows; i++) for(int j = 0; j < cols; j++) x += m1(i,j); - VERIFY_IS_APPROX(m1.sum(), x); -} - -template void vectorSum(const VectorType& w) -{ - typedef typename VectorType::Scalar Scalar; - int size = w.size(); - - VectorType v = VectorType::Random(size); - for(int i = 1; i < size; i++) - { - Scalar s = Scalar(0); - for(int j = 0; j < i; j++) s += v[j]; - VERIFY_IS_APPROX(s, v.start(i).sum()); - } - - for(int i = 0; i < size-1; i++) - { - Scalar s = Scalar(0); - for(int j = i; j < size; j++) s += v[j]; - VERIFY_IS_APPROX(s, v.end(size-i).sum()); - } - - for(int i = 0; i < size/2; i++) - { - Scalar s = Scalar(0); - for(int j = i; j < size-i; j++) s += v[j]; - VERIFY_IS_APPROX(s, v.segment(i, size-2*i).sum()); - } -} - -void test_eigen2_sum() -{ - for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST_1( matrixSum(Matrix()) ); - CALL_SUBTEST_2( matrixSum(Matrix2f()) ); - CALL_SUBTEST_3( matrixSum(Matrix4d()) ); - CALL_SUBTEST_4( matrixSum(MatrixXcf(3, 3)) ); - CALL_SUBTEST_5( matrixSum(MatrixXf(8, 12)) ); - CALL_SUBTEST_6( matrixSum(MatrixXi(8, 12)) ); - } - for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST_5( vectorSum(VectorXf(5)) ); - CALL_SUBTEST_7( vectorSum(VectorXd(10)) ); - CALL_SUBTEST_5( vectorSum(VectorXf(33)) ); - } -} diff --git a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_svd.cpp b/ground/gcs/src/libs/eigen/test/eigen2/eigen2_svd.cpp deleted file mode 100644 index d4689a56f4..0000000000 --- a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_svd.cpp +++ /dev/null @@ -1,87 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. Eigen itself is part of the KDE project. -// -// Copyright (C) 2008 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#include "main.h" -#include - -template void svd(const MatrixType& m) -{ - /* this test covers the following files: - SVD.h - */ - int rows = m.rows(); - int cols = m.cols(); - - typedef typename MatrixType::Scalar Scalar; - typedef typename NumTraits::Real RealScalar; - MatrixType a = MatrixType::Random(rows,cols); - Matrix b = - Matrix::Random(rows,1); - Matrix x(cols,1), x2(cols,1); - - RealScalar largerEps = test_precision(); - if (ei_is_same_type::ret) - largerEps = 1e-3f; - - { - SVD svd(a); - MatrixType sigma = MatrixType::Zero(rows,cols); - MatrixType matU = MatrixType::Zero(rows,rows); - sigma.block(0,0,cols,cols) = svd.singularValues().asDiagonal(); - matU.block(0,0,rows,cols) = svd.matrixU(); - VERIFY_IS_APPROX(a, matU * sigma * svd.matrixV().transpose()); - } - - - if (rows==cols) - { - if (ei_is_same_type::ret) - { - MatrixType a1 = MatrixType::Random(rows,cols); - a += a * a.adjoint() + a1 * a1.adjoint(); - } - SVD svd(a); - svd.solve(b, &x); - VERIFY_IS_APPROX(a * x,b); - } - - - if(rows==cols) - { - SVD svd(a); - MatrixType unitary, positive; - svd.computeUnitaryPositive(&unitary, &positive); - VERIFY_IS_APPROX(unitary * unitary.adjoint(), MatrixType::Identity(unitary.rows(),unitary.rows())); - VERIFY_IS_APPROX(positive, positive.adjoint()); - for(int i = 0; i < rows; i++) VERIFY(positive.diagonal()[i] >= 0); // cheap necessary (not sufficient) condition for positivity - VERIFY_IS_APPROX(unitary*positive, a); - - svd.computePositiveUnitary(&positive, &unitary); - VERIFY_IS_APPROX(unitary * unitary.adjoint(), MatrixType::Identity(unitary.rows(),unitary.rows())); - VERIFY_IS_APPROX(positive, positive.adjoint()); - for(int i = 0; i < rows; i++) VERIFY(positive.diagonal()[i] >= 0); // cheap necessary (not sufficient) condition for positivity - VERIFY_IS_APPROX(positive*unitary, a); - } -} - -void test_eigen2_svd() -{ - for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST_1( svd(Matrix3f()) ); - CALL_SUBTEST_2( svd(Matrix4d()) ); - CALL_SUBTEST_3( svd(MatrixXf(7,7)) ); - CALL_SUBTEST_4( svd(MatrixXd(14,7)) ); - // complex are not implemented yet -// CALL_SUBTEST( svd(MatrixXcd(6,6)) ); -// CALL_SUBTEST( svd(MatrixXcf(3,3)) ); - SVD s; - MatrixXf m = MatrixXf::Random(10,1); - s.compute(m); - } -} diff --git a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_swap.cpp b/ground/gcs/src/libs/eigen/test/eigen2/eigen2_swap.cpp deleted file mode 100644 index f3a8846d94..0000000000 --- a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_swap.cpp +++ /dev/null @@ -1,83 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2009 Benoit Jacob -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#define EIGEN_NO_STATIC_ASSERT -#include "main.h" - -template -struct other_matrix_type -{ - typedef int type; -}; - -template -struct other_matrix_type > -{ - typedef Matrix<_Scalar, _Rows, _Cols, _Options^RowMajor, _MaxRows, _MaxCols> type; -}; - -template void swap(const MatrixType& m) -{ - typedef typename other_matrix_type::type OtherMatrixType; - typedef typename MatrixType::Scalar Scalar; - - ei_assert((!ei_is_same_type::ret)); - int rows = m.rows(); - int cols = m.cols(); - - // construct 3 matrix guaranteed to be distinct - MatrixType m1 = MatrixType::Random(rows,cols); - MatrixType m2 = MatrixType::Random(rows,cols) + Scalar(100) * MatrixType::Identity(rows,cols); - OtherMatrixType m3 = OtherMatrixType::Random(rows,cols) + Scalar(200) * OtherMatrixType::Identity(rows,cols); - - MatrixType m1_copy = m1; - MatrixType m2_copy = m2; - OtherMatrixType m3_copy = m3; - - // test swapping 2 matrices of same type - m1.swap(m2); - VERIFY_IS_APPROX(m1,m2_copy); - VERIFY_IS_APPROX(m2,m1_copy); - m1 = m1_copy; - m2 = m2_copy; - - // test swapping 2 matrices of different types - m1.swap(m3); - VERIFY_IS_APPROX(m1,m3_copy); - VERIFY_IS_APPROX(m3,m1_copy); - m1 = m1_copy; - m3 = m3_copy; - - // test swapping matrix with expression - m1.swap(m2.block(0,0,rows,cols)); - VERIFY_IS_APPROX(m1,m2_copy); - VERIFY_IS_APPROX(m2,m1_copy); - m1 = m1_copy; - m2 = m2_copy; - - // test swapping two expressions of different types - m1.transpose().swap(m3.transpose()); - VERIFY_IS_APPROX(m1,m3_copy); - VERIFY_IS_APPROX(m3,m1_copy); - m1 = m1_copy; - m3 = m3_copy; - - // test assertion on mismatching size -- matrix case - VERIFY_RAISES_ASSERT(m1.swap(m1.row(0))); - // test assertion on mismatching size -- xpr case - VERIFY_RAISES_ASSERT(m1.row(0).swap(m1)); -} - -void test_eigen2_swap() -{ - CALL_SUBTEST_1( swap(Matrix3f()) ); // fixed size, no vectorization - CALL_SUBTEST_1( swap(Matrix4d()) ); // fixed size, possible vectorization - CALL_SUBTEST_1( swap(MatrixXd(3,3)) ); // dyn size, no vectorization - CALL_SUBTEST_1( swap(MatrixXf(30,30)) ); // dyn size, possible vectorization -} diff --git a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_triangular.cpp b/ground/gcs/src/libs/eigen/test/eigen2/eigen2_triangular.cpp deleted file mode 100644 index 6f17b7dffe..0000000000 --- a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_triangular.cpp +++ /dev/null @@ -1,148 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. Eigen itself is part of the KDE project. -// -// Copyright (C) 2008 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#include "main.h" - -template void triangular(const MatrixType& m) -{ - typedef typename MatrixType::Scalar Scalar; - typedef typename NumTraits::Real RealScalar; - - RealScalar largerEps = 10*test_precision(); - - int rows = m.rows(); - int cols = m.cols(); - - MatrixType m1 = MatrixType::Random(rows, cols), - m2 = MatrixType::Random(rows, cols), - m3(rows, cols), - m4(rows, cols), - r1(rows, cols), - r2(rows, cols); - - MatrixType m1up = m1.template part(); - MatrixType m2up = m2.template part(); - - if (rows*cols>1) - { - VERIFY(m1up.isUpperTriangular()); - VERIFY(m2up.transpose().isLowerTriangular()); - VERIFY(!m2.isLowerTriangular()); - } - -// VERIFY_IS_APPROX(m1up.transpose() * m2, m1.upper().transpose().lower() * m2); - - // test overloaded operator+= - r1.setZero(); - r2.setZero(); - r1.template part() += m1; - r2 += m1up; - VERIFY_IS_APPROX(r1,r2); - - // test overloaded operator= - m1.setZero(); - m1.template part() = (m2.transpose() * m2).lazy(); - m3 = m2.transpose() * m2; - VERIFY_IS_APPROX(m3.template part().transpose(), m1); - - // test overloaded operator= - m1.setZero(); - m1.template part() = (m2.transpose() * m2).lazy(); - VERIFY_IS_APPROX(m3.template part(), m1); - - VERIFY_IS_APPROX(m3.template part(), m3.diagonal().asDiagonal()); - - m1 = MatrixType::Random(rows, cols); - for (int i=0; i(); - - Transpose trm4(m4); - // test back and forward subsitution - m3 = m1.template part(); - VERIFY(m3.template marked().solveTriangular(m3).cwise().abs().isIdentity(test_precision())); - VERIFY(m3.transpose().template marked() - .solveTriangular(m3.transpose()).cwise().abs().isIdentity(test_precision())); - // check M * inv(L) using in place API - m4 = m3; - m3.transpose().template marked().solveTriangularInPlace(trm4); - VERIFY(m4.cwise().abs().isIdentity(test_precision())); - - m3 = m1.template part(); - VERIFY(m3.template marked().solveTriangular(m3).cwise().abs().isIdentity(test_precision())); - VERIFY(m3.transpose().template marked() - .solveTriangular(m3.transpose()).cwise().abs().isIdentity(test_precision())); - // check M * inv(U) using in place API - m4 = m3; - m3.transpose().template marked().solveTriangularInPlace(trm4); - VERIFY(m4.cwise().abs().isIdentity(test_precision())); - - m3 = m1.template part(); - VERIFY(m2.isApprox(m3 * (m3.template marked().solveTriangular(m2)), largerEps)); - m3 = m1.template part(); - VERIFY(m2.isApprox(m3 * (m3.template marked().solveTriangular(m2)), largerEps)); - - VERIFY((m1.template part() * m2.template part()).isUpperTriangular()); - - // test swap - m1.setOnes(); - m2.setZero(); - m2.template part().swap(m1); - m3.setZero(); - m3.template part().setOnes(); - VERIFY_IS_APPROX(m2,m3); - -} - -void selfadjoint() -{ - Matrix2i m; - m << 1, 2, - 3, 4; - - Matrix2i m1 = Matrix2i::Zero(); - m1.part() = m; - Matrix2i ref1; - ref1 << 1, 2, - 2, 4; - VERIFY(m1 == ref1); - - Matrix2i m2 = Matrix2i::Zero(); - m2.part() = m.part(); - Matrix2i ref2; - ref2 << 1, 2, - 2, 4; - VERIFY(m2 == ref2); - - Matrix2i m3 = Matrix2i::Zero(); - m3.part() = m.part(); - Matrix2i ref3; - ref3 << 1, 0, - 0, 4; - VERIFY(m3 == ref3); - - // example inspired from bug 159 - int array[] = {1, 2, 3, 4}; - Matrix2i::Map(array).part() = Matrix2i::Random().part(); - - std::cout << "hello\n" << array << std::endl; -} - -void test_eigen2_triangular() -{ - CALL_SUBTEST_8( selfadjoint() ); - for(int i = 0; i < g_repeat ; i++) { - CALL_SUBTEST_1( triangular(Matrix()) ); - CALL_SUBTEST_2( triangular(Matrix()) ); - CALL_SUBTEST_3( triangular(Matrix3d()) ); - CALL_SUBTEST_4( triangular(MatrixXcf(4, 4)) ); - CALL_SUBTEST_5( triangular(Matrix,8, 8>()) ); - CALL_SUBTEST_6( triangular(MatrixXd(17,17)) ); - CALL_SUBTEST_7( triangular(Matrix(5, 5)) ); - } -} diff --git a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_unalignedassert.cpp b/ground/gcs/src/libs/eigen/test/eigen2/eigen2_unalignedassert.cpp deleted file mode 100644 index d10b6f5385..0000000000 --- a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_unalignedassert.cpp +++ /dev/null @@ -1,116 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. Eigen itself is part of the KDE project. -// -// Copyright (C) 2008 Benoit Jacob -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#include "main.h" - -struct Good1 -{ - MatrixXd m; // good: m will allocate its own array, taking care of alignment. - Good1() : m(20,20) {} -}; - -struct Good2 -{ - Matrix3d m; // good: m's size isn't a multiple of 16 bytes, so m doesn't have to be aligned -}; - -struct Good3 -{ - Vector2f m; // good: same reason -}; - -struct Bad4 -{ - Vector2d m; // bad: sizeof(m)%16==0 so alignment is required -}; - -struct Bad5 -{ - Matrix m; // bad: same reason -}; - -struct Bad6 -{ - Matrix m; // bad: same reason -}; - -struct Good7 -{ - EIGEN_MAKE_ALIGNED_OPERATOR_NEW - Vector2d m; - float f; // make the struct have sizeof%16!=0 to make it a little more tricky when we allow an array of 2 such objects -}; - -struct Good8 -{ - EIGEN_MAKE_ALIGNED_OPERATOR_NEW - float f; // try the f at first -- the EIGEN_ALIGN_128 attribute of m should make that still work - Matrix4f m; -}; - -struct Good9 -{ - Matrix m; // good: no alignment requested - float f; -}; - -template struct Depends -{ - EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(Align) - Vector2d m; - float f; -}; - -template -void check_unalignedassert_good() -{ - T *x, *y; - x = new T; - delete x; - y = new T[2]; - delete[] y; -} - -#if EIGEN_ARCH_WANTS_ALIGNMENT -template -void check_unalignedassert_bad() -{ - float buf[sizeof(T)+16]; - float *unaligned = buf; - while((reinterpret_cast(unaligned)&0xf)==0) ++unaligned; // make sure unaligned is really unaligned - T *x = ::new(static_cast(unaligned)) T; - x->~T(); -} -#endif - -void unalignedassert() -{ - check_unalignedassert_good(); - check_unalignedassert_good(); - check_unalignedassert_good(); -#if EIGEN_ARCH_WANTS_ALIGNMENT - VERIFY_RAISES_ASSERT(check_unalignedassert_bad()); - VERIFY_RAISES_ASSERT(check_unalignedassert_bad()); - VERIFY_RAISES_ASSERT(check_unalignedassert_bad()); -#endif - - check_unalignedassert_good(); - check_unalignedassert_good(); - check_unalignedassert_good(); - check_unalignedassert_good >(); - -#if EIGEN_ARCH_WANTS_ALIGNMENT - VERIFY_RAISES_ASSERT(check_unalignedassert_bad >()); -#endif -} - -void test_eigen2_unalignedassert() -{ - CALL_SUBTEST(unalignedassert()); -} diff --git a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_visitor.cpp b/ground/gcs/src/libs/eigen/test/eigen2/eigen2_visitor.cpp deleted file mode 100644 index 4781991de7..0000000000 --- a/ground/gcs/src/libs/eigen/test/eigen2/eigen2_visitor.cpp +++ /dev/null @@ -1,116 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008 Benoit Jacob -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#include "main.h" - -template void matrixVisitor(const MatrixType& p) -{ - typedef typename MatrixType::Scalar Scalar; - - int rows = p.rows(); - int cols = p.cols(); - - // construct a random matrix where all coefficients are different - MatrixType m; - m = MatrixType::Random(rows, cols); - for(int i = 0; i < m.size(); i++) - for(int i2 = 0; i2 < i; i2++) - while(m(i) == m(i2)) // yes, == - m(i) = ei_random(); - - Scalar minc = Scalar(1000), maxc = Scalar(-1000); - int minrow=0,mincol=0,maxrow=0,maxcol=0; - for(int j = 0; j < cols; j++) - for(int i = 0; i < rows; i++) - { - if(m(i,j) < minc) - { - minc = m(i,j); - minrow = i; - mincol = j; - } - if(m(i,j) > maxc) - { - maxc = m(i,j); - maxrow = i; - maxcol = j; - } - } - int eigen_minrow, eigen_mincol, eigen_maxrow, eigen_maxcol; - Scalar eigen_minc, eigen_maxc; - eigen_minc = m.minCoeff(&eigen_minrow,&eigen_mincol); - eigen_maxc = m.maxCoeff(&eigen_maxrow,&eigen_maxcol); - VERIFY(minrow == eigen_minrow); - VERIFY(maxrow == eigen_maxrow); - VERIFY(mincol == eigen_mincol); - VERIFY(maxcol == eigen_maxcol); - VERIFY_IS_APPROX(minc, eigen_minc); - VERIFY_IS_APPROX(maxc, eigen_maxc); - VERIFY_IS_APPROX(minc, m.minCoeff()); - VERIFY_IS_APPROX(maxc, m.maxCoeff()); -} - -template void vectorVisitor(const VectorType& w) -{ - typedef typename VectorType::Scalar Scalar; - - int size = w.size(); - - // construct a random vector where all coefficients are different - VectorType v; - v = VectorType::Random(size); - for(int i = 0; i < size; i++) - for(int i2 = 0; i2 < i; i2++) - while(v(i) == v(i2)) // yes, == - v(i) = ei_random(); - - Scalar minc = Scalar(1000), maxc = Scalar(-1000); - int minidx=0,maxidx=0; - for(int i = 0; i < size; i++) - { - if(v(i) < minc) - { - minc = v(i); - minidx = i; - } - if(v(i) > maxc) - { - maxc = v(i); - maxidx = i; - } - } - int eigen_minidx, eigen_maxidx; - Scalar eigen_minc, eigen_maxc; - eigen_minc = v.minCoeff(&eigen_minidx); - eigen_maxc = v.maxCoeff(&eigen_maxidx); - VERIFY(minidx == eigen_minidx); - VERIFY(maxidx == eigen_maxidx); - VERIFY_IS_APPROX(minc, eigen_minc); - VERIFY_IS_APPROX(maxc, eigen_maxc); - VERIFY_IS_APPROX(minc, v.minCoeff()); - VERIFY_IS_APPROX(maxc, v.maxCoeff()); -} - -void test_eigen2_visitor() -{ - for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST_1( matrixVisitor(Matrix()) ); - CALL_SUBTEST_2( matrixVisitor(Matrix2f()) ); - CALL_SUBTEST_3( matrixVisitor(Matrix4d()) ); - CALL_SUBTEST_4( matrixVisitor(MatrixXd(8, 12)) ); - CALL_SUBTEST_5( matrixVisitor(Matrix(20, 20)) ); - CALL_SUBTEST_6( matrixVisitor(MatrixXi(8, 12)) ); - } - for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST_7( vectorVisitor(Vector4f()) ); - CALL_SUBTEST_4( vectorVisitor(VectorXd(10)) ); - CALL_SUBTEST_4( vectorVisitor(RowVectorXd(10)) ); - CALL_SUBTEST_8( vectorVisitor(VectorXf(33)) ); - } -} diff --git a/ground/gcs/src/libs/eigen/test/eigen2/gsl_helper.h b/ground/gcs/src/libs/eigen/test/eigen2/gsl_helper.h deleted file mode 100644 index d1d8545333..0000000000 --- a/ground/gcs/src/libs/eigen/test/eigen2/gsl_helper.h +++ /dev/null @@ -1,175 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. Eigen itself is part of the KDE project. -// -// Copyright (C) 2008 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_GSL_HELPER -#define EIGEN_GSL_HELPER - -#include - -#include -#include -#include -#include -#include -#include - -namespace Eigen { - -template::IsComplex> struct GslTraits -{ - typedef gsl_matrix* Matrix; - typedef gsl_vector* Vector; - static Matrix createMatrix(int rows, int cols) { return gsl_matrix_alloc(rows,cols); } - static Vector createVector(int size) { return gsl_vector_alloc(size); } - static void free(Matrix& m) { gsl_matrix_free(m); m=0; } - static void free(Vector& m) { gsl_vector_free(m); m=0; } - static void prod(const Matrix& m, const Vector& v, Vector& x) { gsl_blas_dgemv(CblasNoTrans,1,m,v,0,x); } - static void cholesky(Matrix& m) { gsl_linalg_cholesky_decomp(m); } - static void cholesky_solve(const Matrix& m, const Vector& b, Vector& x) { gsl_linalg_cholesky_solve(m,b,x); } - static void eigen_symm(const Matrix& m, Vector& eval, Matrix& evec) - { - gsl_eigen_symmv_workspace * w = gsl_eigen_symmv_alloc(m->size1); - Matrix a = createMatrix(m->size1, m->size2); - gsl_matrix_memcpy(a, m); - gsl_eigen_symmv(a,eval,evec,w); - gsl_eigen_symmv_sort(eval, evec, GSL_EIGEN_SORT_VAL_ASC); - gsl_eigen_symmv_free(w); - free(a); - } - static void eigen_symm_gen(const Matrix& m, const Matrix& _b, Vector& eval, Matrix& evec) - { - gsl_eigen_gensymmv_workspace * w = gsl_eigen_gensymmv_alloc(m->size1); - Matrix a = createMatrix(m->size1, m->size2); - Matrix b = createMatrix(_b->size1, _b->size2); - gsl_matrix_memcpy(a, m); - gsl_matrix_memcpy(b, _b); - gsl_eigen_gensymmv(a,b,eval,evec,w); - gsl_eigen_symmv_sort(eval, evec, GSL_EIGEN_SORT_VAL_ASC); - gsl_eigen_gensymmv_free(w); - free(a); - } -}; - -template struct GslTraits -{ - typedef gsl_matrix_complex* Matrix; - typedef gsl_vector_complex* Vector; - static Matrix createMatrix(int rows, int cols) { return gsl_matrix_complex_alloc(rows,cols); } - static Vector createVector(int size) { return gsl_vector_complex_alloc(size); } - static void free(Matrix& m) { gsl_matrix_complex_free(m); m=0; } - static void free(Vector& m) { gsl_vector_complex_free(m); m=0; } - static void cholesky(Matrix& m) { gsl_linalg_complex_cholesky_decomp(m); } - static void cholesky_solve(const Matrix& m, const Vector& b, Vector& x) { gsl_linalg_complex_cholesky_solve(m,b,x); } - static void prod(const Matrix& m, const Vector& v, Vector& x) - { gsl_blas_zgemv(CblasNoTrans,gsl_complex_rect(1,0),m,v,gsl_complex_rect(0,0),x); } - static void eigen_symm(const Matrix& m, gsl_vector* &eval, Matrix& evec) - { - gsl_eigen_hermv_workspace * w = gsl_eigen_hermv_alloc(m->size1); - Matrix a = createMatrix(m->size1, m->size2); - gsl_matrix_complex_memcpy(a, m); - gsl_eigen_hermv(a,eval,evec,w); - gsl_eigen_hermv_sort(eval, evec, GSL_EIGEN_SORT_VAL_ASC); - gsl_eigen_hermv_free(w); - free(a); - } - static void eigen_symm_gen(const Matrix& m, const Matrix& _b, gsl_vector* &eval, Matrix& evec) - { - gsl_eigen_genhermv_workspace * w = gsl_eigen_genhermv_alloc(m->size1); - Matrix a = createMatrix(m->size1, m->size2); - Matrix b = createMatrix(_b->size1, _b->size2); - gsl_matrix_complex_memcpy(a, m); - gsl_matrix_complex_memcpy(b, _b); - gsl_eigen_genhermv(a,b,eval,evec,w); - gsl_eigen_hermv_sort(eval, evec, GSL_EIGEN_SORT_VAL_ASC); - gsl_eigen_genhermv_free(w); - free(a); - } -}; - -template -void convert(const MatrixType& m, gsl_matrix* &res) -{ -// if (res) -// gsl_matrix_free(res); - res = gsl_matrix_alloc(m.rows(), m.cols()); - for (int i=0 ; i -void convert(const gsl_matrix* m, MatrixType& res) -{ - res.resize(int(m->size1), int(m->size2)); - for (int i=0 ; i -void convert(const VectorType& m, gsl_vector* &res) -{ - if (res) gsl_vector_free(res); - res = gsl_vector_alloc(m.size()); - for (int i=0 ; i -void convert(const gsl_vector* m, VectorType& res) -{ - res.resize (m->size); - for (int i=0 ; i -void convert(const MatrixType& m, gsl_matrix_complex* &res) -{ - res = gsl_matrix_complex_alloc(m.rows(), m.cols()); - for (int i=0 ; i -void convert(const gsl_matrix_complex* m, MatrixType& res) -{ - res.resize(int(m->size1), int(m->size2)); - for (int i=0 ; i -void convert(const VectorType& m, gsl_vector_complex* &res) -{ - res = gsl_vector_complex_alloc(m.size()); - for (int i=0 ; i -void convert(const gsl_vector_complex* m, VectorType& res) -{ - res.resize(m->size); - for (int i=0 ; i -// Copyright (C) 2008 Gael Guennebaud -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#include -#include -#include -#include -#include - -#ifndef EIGEN_TEST_FUNC -#error EIGEN_TEST_FUNC must be defined -#endif - -#define DEFAULT_REPEAT 10 - -namespace Eigen -{ - static std::vector g_test_stack; - static int g_repeat; -} - -#define EI_PP_MAKE_STRING2(S) #S -#define EI_PP_MAKE_STRING(S) EI_PP_MAKE_STRING2(S) - -#define EI_PP_CAT2(a,b) a ## b -#define EI_PP_CAT(a,b) EI_PP_CAT2(a,b) - -#ifndef EIGEN_NO_ASSERTION_CHECKING - - namespace Eigen - { - static const bool should_raise_an_assert = false; - - // Used to avoid to raise two exceptions at a time in which - // case the exception is not properly caught. - // This may happen when a second exceptions is raise in a destructor. - static bool no_more_assert = false; - - struct eigen_assert_exception - { - eigen_assert_exception(void) {} - ~eigen_assert_exception() { Eigen::no_more_assert = false; } - }; - } - - // If EIGEN_DEBUG_ASSERTS is defined and if no assertion is raised while - // one should have been, then the list of excecuted assertions is printed out. - // - // EIGEN_DEBUG_ASSERTS is not enabled by default as it - // significantly increases the compilation time - // and might even introduce side effects that would hide - // some memory errors. - #ifdef EIGEN_DEBUG_ASSERTS - - namespace Eigen - { - static bool ei_push_assert = false; - static std::vector eigen_assert_list; - } - - #define eigen_assert(a) \ - if( (!(a)) && (!no_more_assert) ) \ - { \ - Eigen::no_more_assert = true; \ - throw Eigen::eigen_assert_exception(); \ - } \ - else if (Eigen::ei_push_assert) \ - { \ - eigen_assert_list.push_back(std::string(EI_PP_MAKE_STRING(__FILE__)" ("EI_PP_MAKE_STRING(__LINE__)") : "#a) ); \ - } - - #define VERIFY_RAISES_ASSERT(a) \ - { \ - Eigen::no_more_assert = false; \ - try { \ - Eigen::eigen_assert_list.clear(); \ - Eigen::ei_push_assert = true; \ - a; \ - Eigen::ei_push_assert = false; \ - std::cerr << "One of the following asserts should have been raised:\n"; \ - for (uint ai=0 ; ai - - -#define VERIFY(a) do { if (!(a)) { \ - std::cerr << "Test " << g_test_stack.back() << " failed in "EI_PP_MAKE_STRING(__FILE__) << " (" << EI_PP_MAKE_STRING(__LINE__) << ")" \ - << std::endl << " " << EI_PP_MAKE_STRING(a) << std::endl << std::endl; \ - abort(); \ - } } while (0) - -#define VERIFY_IS_APPROX(a, b) VERIFY(test_ei_isApprox(a, b)) -#define VERIFY_IS_NOT_APPROX(a, b) VERIFY(!test_ei_isApprox(a, b)) -#define VERIFY_IS_MUCH_SMALLER_THAN(a, b) VERIFY(test_ei_isMuchSmallerThan(a, b)) -#define VERIFY_IS_NOT_MUCH_SMALLER_THAN(a, b) VERIFY(!test_ei_isMuchSmallerThan(a, b)) -#define VERIFY_IS_APPROX_OR_LESS_THAN(a, b) VERIFY(test_ei_isApproxOrLessThan(a, b)) -#define VERIFY_IS_NOT_APPROX_OR_LESS_THAN(a, b) VERIFY(!test_ei_isApproxOrLessThan(a, b)) - -#define CALL_SUBTEST(FUNC) do { \ - g_test_stack.push_back(EI_PP_MAKE_STRING(FUNC)); \ - FUNC; \ - g_test_stack.pop_back(); \ - } while (0) - -namespace Eigen { - -template inline typename NumTraits::Real test_precision(); -template<> inline int test_precision() { return 0; } -template<> inline float test_precision() { return 1e-3f; } -template<> inline double test_precision() { return 1e-6; } -template<> inline float test_precision >() { return test_precision(); } -template<> inline double test_precision >() { return test_precision(); } -template<> inline long double test_precision() { return 1e-6; } - -inline bool test_ei_isApprox(const int& a, const int& b) -{ return ei_isApprox(a, b, test_precision()); } -inline bool test_ei_isMuchSmallerThan(const int& a, const int& b) -{ return ei_isMuchSmallerThan(a, b, test_precision()); } -inline bool test_ei_isApproxOrLessThan(const int& a, const int& b) -{ return ei_isApproxOrLessThan(a, b, test_precision()); } - -inline bool test_ei_isApprox(const float& a, const float& b) -{ return ei_isApprox(a, b, test_precision()); } -inline bool test_ei_isMuchSmallerThan(const float& a, const float& b) -{ return ei_isMuchSmallerThan(a, b, test_precision()); } -inline bool test_ei_isApproxOrLessThan(const float& a, const float& b) -{ return ei_isApproxOrLessThan(a, b, test_precision()); } - -inline bool test_ei_isApprox(const double& a, const double& b) -{ return ei_isApprox(a, b, test_precision()); } -inline bool test_ei_isMuchSmallerThan(const double& a, const double& b) -{ return ei_isMuchSmallerThan(a, b, test_precision()); } -inline bool test_ei_isApproxOrLessThan(const double& a, const double& b) -{ return ei_isApproxOrLessThan(a, b, test_precision()); } - -inline bool test_ei_isApprox(const std::complex& a, const std::complex& b) -{ return ei_isApprox(a, b, test_precision >()); } -inline bool test_ei_isMuchSmallerThan(const std::complex& a, const std::complex& b) -{ return ei_isMuchSmallerThan(a, b, test_precision >()); } - -inline bool test_ei_isApprox(const std::complex& a, const std::complex& b) -{ return ei_isApprox(a, b, test_precision >()); } -inline bool test_ei_isMuchSmallerThan(const std::complex& a, const std::complex& b) -{ return ei_isMuchSmallerThan(a, b, test_precision >()); } - -inline bool test_ei_isApprox(const long double& a, const long double& b) -{ return ei_isApprox(a, b, test_precision()); } -inline bool test_ei_isMuchSmallerThan(const long double& a, const long double& b) -{ return ei_isMuchSmallerThan(a, b, test_precision()); } -inline bool test_ei_isApproxOrLessThan(const long double& a, const long double& b) -{ return ei_isApproxOrLessThan(a, b, test_precision()); } - -template -inline bool test_ei_isApprox(const Type1& a, const Type2& b) -{ - return a.isApprox(b, test_precision()); -} - -template -inline bool test_ei_isMuchSmallerThan(const MatrixBase& m1, - const MatrixBase& m2) -{ - return m1.isMuchSmallerThan(m2, test_precision::Scalar>()); -} - -template -inline bool test_ei_isMuchSmallerThan(const MatrixBase& m, - const typename NumTraits::Scalar>::Real& s) -{ - return m.isMuchSmallerThan(s, test_precision::Scalar>()); -} - -} // end namespace Eigen - -template struct GetDifferentType; - -template<> struct GetDifferentType { typedef double type; }; -template<> struct GetDifferentType { typedef float type; }; -template struct GetDifferentType > -{ typedef std::complex::type> type; }; - -// forward declaration of the main test function -void EI_PP_CAT(test_,EIGEN_TEST_FUNC)(); - -using namespace Eigen; - -#ifdef EIGEN_TEST_PART_1 -#define CALL_SUBTEST_1(FUNC) CALL_SUBTEST(FUNC) -#else -#define CALL_SUBTEST_1(FUNC) -#endif - -#ifdef EIGEN_TEST_PART_2 -#define CALL_SUBTEST_2(FUNC) CALL_SUBTEST(FUNC) -#else -#define CALL_SUBTEST_2(FUNC) -#endif - -#ifdef EIGEN_TEST_PART_3 -#define CALL_SUBTEST_3(FUNC) CALL_SUBTEST(FUNC) -#else -#define CALL_SUBTEST_3(FUNC) -#endif - -#ifdef EIGEN_TEST_PART_4 -#define CALL_SUBTEST_4(FUNC) CALL_SUBTEST(FUNC) -#else -#define CALL_SUBTEST_4(FUNC) -#endif - -#ifdef EIGEN_TEST_PART_5 -#define CALL_SUBTEST_5(FUNC) CALL_SUBTEST(FUNC) -#else -#define CALL_SUBTEST_5(FUNC) -#endif - -#ifdef EIGEN_TEST_PART_6 -#define CALL_SUBTEST_6(FUNC) CALL_SUBTEST(FUNC) -#else -#define CALL_SUBTEST_6(FUNC) -#endif - -#ifdef EIGEN_TEST_PART_7 -#define CALL_SUBTEST_7(FUNC) CALL_SUBTEST(FUNC) -#else -#define CALL_SUBTEST_7(FUNC) -#endif - -#ifdef EIGEN_TEST_PART_8 -#define CALL_SUBTEST_8(FUNC) CALL_SUBTEST(FUNC) -#else -#define CALL_SUBTEST_8(FUNC) -#endif - -#ifdef EIGEN_TEST_PART_9 -#define CALL_SUBTEST_9(FUNC) CALL_SUBTEST(FUNC) -#else -#define CALL_SUBTEST_9(FUNC) -#endif - -#ifdef EIGEN_TEST_PART_10 -#define CALL_SUBTEST_10(FUNC) CALL_SUBTEST(FUNC) -#else -#define CALL_SUBTEST_10(FUNC) -#endif - -#ifdef EIGEN_TEST_PART_11 -#define CALL_SUBTEST_11(FUNC) CALL_SUBTEST(FUNC) -#else -#define CALL_SUBTEST_11(FUNC) -#endif - -#ifdef EIGEN_TEST_PART_12 -#define CALL_SUBTEST_12(FUNC) CALL_SUBTEST(FUNC) -#else -#define CALL_SUBTEST_12(FUNC) -#endif - -#ifdef EIGEN_TEST_PART_13 -#define CALL_SUBTEST_13(FUNC) CALL_SUBTEST(FUNC) -#else -#define CALL_SUBTEST_13(FUNC) -#endif - -#ifdef EIGEN_TEST_PART_14 -#define CALL_SUBTEST_14(FUNC) CALL_SUBTEST(FUNC) -#else -#define CALL_SUBTEST_14(FUNC) -#endif - -#ifdef EIGEN_TEST_PART_15 -#define CALL_SUBTEST_15(FUNC) CALL_SUBTEST(FUNC) -#else -#define CALL_SUBTEST_15(FUNC) -#endif - -#ifdef EIGEN_TEST_PART_16 -#define CALL_SUBTEST_16(FUNC) CALL_SUBTEST(FUNC) -#else -#define CALL_SUBTEST_16(FUNC) -#endif - - - -int main(int argc, char *argv[]) -{ - bool has_set_repeat = false; - bool has_set_seed = false; - bool need_help = false; - unsigned int seed = 0; - int repeat = DEFAULT_REPEAT; - - for(int i = 1; i < argc; i++) - { - if(argv[i][0] == 'r') - { - if(has_set_repeat) - { - std::cout << "Argument " << argv[i] << " conflicting with a former argument" << std::endl; - return 1; - } - repeat = std::atoi(argv[i]+1); - has_set_repeat = true; - if(repeat <= 0) - { - std::cout << "Invalid \'repeat\' value " << argv[i]+1 << std::endl; - return 1; - } - } - else if(argv[i][0] == 's') - { - if(has_set_seed) - { - std::cout << "Argument " << argv[i] << " conflicting with a former argument" << std::endl; - return 1; - } - seed = int(std::strtoul(argv[i]+1, 0, 10)); - has_set_seed = true; - bool ok = seed!=0; - if(!ok) - { - std::cout << "Invalid \'seed\' value " << argv[i]+1 << std::endl; - return 1; - } - } - else - { - need_help = true; - } - } - - if(need_help) - { - std::cout << "This test application takes the following optional arguments:" << std::endl; - std::cout << " rN Repeat each test N times (default: " << DEFAULT_REPEAT << ")" << std::endl; - std::cout << " sN Use N as seed for random numbers (default: based on current time)" << std::endl; - return 1; - } - - if(!has_set_seed) seed = (unsigned int) std::time(NULL); - if(!has_set_repeat) repeat = DEFAULT_REPEAT; - - std::cout << "Initializing random number generator with seed " << seed << std::endl; - std::srand(seed); - std::cout << "Repeating each test " << repeat << " times" << std::endl; - - Eigen::g_repeat = repeat; - Eigen::g_test_stack.push_back(EI_PP_MAKE_STRING(EIGEN_TEST_FUNC)); - - EI_PP_CAT(test_,EIGEN_TEST_FUNC)(); - return 0; -} - - - diff --git a/ground/gcs/src/libs/eigen/test/eigen2/product.h b/ground/gcs/src/libs/eigen/test/eigen2/product.h deleted file mode 100644 index ae1b4bae47..0000000000 --- a/ground/gcs/src/libs/eigen/test/eigen2/product.h +++ /dev/null @@ -1,129 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. Eigen itself is part of the KDE project. -// -// Copyright (C) 2006-2008 Benoit Jacob -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#include "main.h" -#include -#include - -template -bool areNotApprox(const MatrixBase& m1, const MatrixBase& m2, typename Derived1::RealScalar epsilon = precision()) -{ - return !((m1-m2).cwise().abs2().maxCoeff() < epsilon * epsilon - * std::max(m1.cwise().abs2().maxCoeff(), m2.cwise().abs2().maxCoeff())); -} - -template void product(const MatrixType& m) -{ - /* this test covers the following files: - Identity.h Product.h - */ - - typedef typename MatrixType::Scalar Scalar; - typedef typename NumTraits::FloatingPoint FloatingPoint; - typedef Matrix RowVectorType; - typedef Matrix ColVectorType; - typedef Matrix RowSquareMatrixType; - typedef Matrix ColSquareMatrixType; - typedef Matrix OtherMajorMatrixType; - - int rows = m.rows(); - int cols = m.cols(); - - // this test relies a lot on Random.h, and there's not much more that we can do - // to test it, hence I consider that we will have tested Random.h - MatrixType m1 = MatrixType::Random(rows, cols), - m2 = MatrixType::Random(rows, cols), - m3(rows, cols); - RowSquareMatrixType - identity = RowSquareMatrixType::Identity(rows, rows), - square = RowSquareMatrixType::Random(rows, rows), - res = RowSquareMatrixType::Random(rows, rows); - ColSquareMatrixType - square2 = ColSquareMatrixType::Random(cols, cols), - res2 = ColSquareMatrixType::Random(cols, cols); - RowVectorType v1 = RowVectorType::Random(rows); - ColVectorType vc2 = ColVectorType::Random(cols), vcres(cols); - OtherMajorMatrixType tm1 = m1; - - Scalar s1 = ei_random(); - - int r = ei_random(0, rows-1), - c = ei_random(0, cols-1); - - // begin testing Product.h: only associativity for now - // (we use Transpose.h but this doesn't count as a test for it) - - VERIFY_IS_APPROX((m1*m1.transpose())*m2, m1*(m1.transpose()*m2)); - m3 = m1; - m3 *= m1.transpose() * m2; - VERIFY_IS_APPROX(m3, m1 * (m1.transpose()*m2)); - VERIFY_IS_APPROX(m3, m1.lazy() * (m1.transpose()*m2)); - - // continue testing Product.h: distributivity - VERIFY_IS_APPROX(square*(m1 + m2), square*m1+square*m2); - VERIFY_IS_APPROX(square*(m1 - m2), square*m1-square*m2); - - // continue testing Product.h: compatibility with ScalarMultiple.h - VERIFY_IS_APPROX(s1*(square*m1), (s1*square)*m1); - VERIFY_IS_APPROX(s1*(square*m1), square*(m1*s1)); - - // again, test operator() to check const-qualification - s1 += (square.lazy() * m1)(r,c); - - // test Product.h together with Identity.h - VERIFY_IS_APPROX(v1, identity*v1); - VERIFY_IS_APPROX(v1.transpose(), v1.transpose() * identity); - // again, test operator() to check const-qualification - VERIFY_IS_APPROX(MatrixType::Identity(rows, cols)(r,c), static_cast(r==c)); - - if (rows!=cols) - VERIFY_RAISES_ASSERT(m3 = m1*m1); - - // test the previous tests were not screwed up because operator* returns 0 - // (we use the more accurate default epsilon) - if (NumTraits::HasFloatingPoint && std::min(rows,cols)>1) - { - VERIFY(areNotApprox(m1.transpose()*m2,m2.transpose()*m1)); - } - - // test optimized operator+= path - res = square; - res += (m1 * m2.transpose()).lazy(); - VERIFY_IS_APPROX(res, square + m1 * m2.transpose()); - if (NumTraits::HasFloatingPoint && std::min(rows,cols)>1) - { - VERIFY(areNotApprox(res,square + m2 * m1.transpose())); - } - vcres = vc2; - vcres += (m1.transpose() * v1).lazy(); - VERIFY_IS_APPROX(vcres, vc2 + m1.transpose() * v1); - tm1 = m1; - VERIFY_IS_APPROX(tm1.transpose() * v1, m1.transpose() * v1); - VERIFY_IS_APPROX(v1.transpose() * tm1, v1.transpose() * m1); - - // test submatrix and matrix/vector product - for (int i=0; i::HasFloatingPoint && std::min(rows,cols)>1) - { - VERIFY(areNotApprox(res2,square2 + m2.transpose() * m1)); - } -} - diff --git a/ground/gcs/src/libs/eigen/test/eigen2/runtest.sh b/ground/gcs/src/libs/eigen/test/eigen2/runtest.sh deleted file mode 100755 index bc693af131..0000000000 --- a/ground/gcs/src/libs/eigen/test/eigen2/runtest.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash - -black='\E[30m' -red='\E[31m' -green='\E[32m' -yellow='\E[33m' -blue='\E[34m' -magenta='\E[35m' -cyan='\E[36m' -white='\E[37m' - -if make test_$1 > /dev/null 2> .runtest.log ; then - if ! ./test_$1 r20 > /dev/null 2> .runtest.log ; then - echo -e $red Test $1 failed: $black - echo -e $blue - cat .runtest.log - echo -e $black - exit 1 - else - echo -e $green Test $1 passed$black - fi -else - echo -e $red Build of target $1 failed: $black - echo -e $blue - cat .runtest.log - echo -e $black - exit 1 -fi diff --git a/ground/gcs/src/libs/eigen/test/eigen2/sparse.h b/ground/gcs/src/libs/eigen/test/eigen2/sparse.h deleted file mode 100644 index e12f899903..0000000000 --- a/ground/gcs/src/libs/eigen/test/eigen2/sparse.h +++ /dev/null @@ -1,154 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. Eigen itself is part of the KDE project. -// -// Copyright (C) 2008 Daniel Gomez Ferro -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -#ifndef EIGEN_TESTSPARSE_H - -#include "main.h" - -#if EIGEN_GNUC_AT_LEAST(4,0) && !defined __ICC -#include -#define EIGEN_UNORDERED_MAP_SUPPORT -namespace std { - using std::tr1::unordered_map; -} -#endif - -#ifdef EIGEN_GOOGLEHASH_SUPPORT - #include -#endif - -#include -#include -#include - -enum { - ForceNonZeroDiag = 1, - MakeLowerTriangular = 2, - MakeUpperTriangular = 4, - ForceRealDiag = 8 -}; - -/* Initializes both a sparse and dense matrix with same random values, - * and a ratio of \a density non zero entries. - * \param flags is a union of ForceNonZeroDiag, MakeLowerTriangular and MakeUpperTriangular - * allowing to control the shape of the matrix. - * \param zeroCoords and nonzeroCoords allows to get the coordinate lists of the non zero, - * and zero coefficients respectively. - */ -template void -initSparse(double density, - Matrix& refMat, - SparseMatrix& sparseMat, - int flags = 0, - std::vector* zeroCoords = 0, - std::vector* nonzeroCoords = 0) -{ - sparseMat.startFill(int(refMat.rows()*refMat.cols()*density)); - for(int j=0; j(0,1) < density) ? ei_random() : Scalar(0); - if ((flags&ForceNonZeroDiag) && (i==j)) - { - v = ei_random()*Scalar(3.); - v = v*v + Scalar(5.); - } - if ((flags & MakeLowerTriangular) && j>i) - v = Scalar(0); - else if ((flags & MakeUpperTriangular) && jpush_back(Vector2i(i,j)); - } - else if (zeroCoords) - { - zeroCoords->push_back(Vector2i(i,j)); - } - refMat(i,j) = v; - } - } - sparseMat.endFill(); -} - -template void -initSparse(double density, - Matrix& refMat, - DynamicSparseMatrix& sparseMat, - int flags = 0, - std::vector* zeroCoords = 0, - std::vector* nonzeroCoords = 0) -{ - sparseMat.startFill(int(refMat.rows()*refMat.cols()*density)); - for(int j=0; j(0,1) < density) ? ei_random() : Scalar(0); - if ((flags&ForceNonZeroDiag) && (i==j)) - { - v = ei_random()*Scalar(3.); - v = v*v + Scalar(5.); - } - if ((flags & MakeLowerTriangular) && j>i) - v = Scalar(0); - else if ((flags & MakeUpperTriangular) && jpush_back(Vector2i(i,j)); - } - else if (zeroCoords) - { - zeroCoords->push_back(Vector2i(i,j)); - } - refMat(i,j) = v; - } - } - sparseMat.endFill(); -} - -template void -initSparse(double density, - Matrix& refVec, - SparseVector& sparseVec, - std::vector* zeroCoords = 0, - std::vector* nonzeroCoords = 0) -{ - sparseVec.reserve(int(refVec.size()*density)); - sparseVec.setZero(); - for(int i=0; i(0,1) < density) ? ei_random() : Scalar(0); - if (v!=Scalar(0)) - { - sparseVec.fill(i) = v; - if (nonzeroCoords) - nonzeroCoords->push_back(i); - } - else if (zeroCoords) - zeroCoords->push_back(i); - refVec[i] = v; - } -} - -#endif // EIGEN_TESTSPARSE_H diff --git a/ground/gcs/src/libs/eigen/test/eigen2/testsuite.cmake b/ground/gcs/src/libs/eigen/test/eigen2/testsuite.cmake deleted file mode 100644 index 12b6bfa2eb..0000000000 --- a/ground/gcs/src/libs/eigen/test/eigen2/testsuite.cmake +++ /dev/null @@ -1,197 +0,0 @@ - -#################################################################### -# -# Usage: -# - create a new folder, let's call it cdash -# - in that folder, do: -# ctest -S path/to/eigen2/test/testsuite.cmake[,option1=value1[,option2=value2]] -# -# Options: -# - EIGEN_CXX: compiler, eg.: g++-4.2 -# default: default c++ compiler -# - EIGEN_SITE: eg, INRIA-Bdx_pc-gael, or the name of the contributor, etc. -# default: hostname -# - EIGEN_BUILD_STRING: a string which identify the system/compiler. It should be formed like that: -# --- -# with: -# = opensuse, debian, osx, windows, cygwin, freebsd, solaris, etc. -# = 11.1, XP, vista, leopard, etc. -# = i386, x86_64, ia64, powerpc, etc. -# = gcc-4.3.2, icc-11.0, MSVC-2008, etc. -# - EIGEN_EXPLICIT_VECTORIZATION: novec, SSE2, Altivec -# default: SSE2 for x86_64 systems, novec otherwise -# Its value is automatically appended to EIGEN_BUILD_STRING -# - EIGEN_CMAKE_DIR: path to cmake executable -# - EIGEN_MODE: dashboard model, can be Experimental, Nightly, or Continuous -# default: Nightly -# - EIGEN_WORK_DIR: directory used to download the source files and make the builds -# default: folder which contains this script -# - EIGEN_CMAKE_ARGS: additional arguments passed to cmake -# - CTEST_SOURCE_DIRECTORY: path to eigen's src (use a new and empty folder, not the one you are working on) -# default: /src -# - CTEST_BINARY_DIRECTORY: build directory -# default: /nightly- -# -# Here is an example running several compilers on a linux system: -# #!/bin/bash -# ARCH=`uname -m` -# SITE=`hostname` -# VERSION=opensuse-11.1 -# WORK_DIR=/home/gael/Coding/eigen2/cdash -# # get the last version of the script -# wget http://bitbucket.org/eigen/eigen/raw/tip/test/testsuite.cmake -o $WORK_DIR/testsuite.cmake -# COMMON="ctest -S $WORK_DIR/testsuite.cmake,EIGEN_WORK_DIR=$WORK_DIR,EIGEN_SITE=$SITE,EIGEN_MODE=$1,EIGEN_BUILD_STRING=$OS_VERSION-$ARCH" -# $COMMON-gcc-3.4.6,EIGEN_CXX=g++-3.4 -# $COMMON-gcc-4.0.1,EIGEN_CXX=g++-4.0.1 -# $COMMON-gcc-4.3.2,EIGEN_CXX=g++-4.3,EIGEN_EXPLICIT_VECTORIZATION=novec -# $COMMON-gcc-4.3.2,EIGEN_CXX=g++-4.3,EIGEN_EXPLICIT_VECTORIZATION=SSE2 -# $COMMON-icc-11.0,EIGEN_CXX=icpc -# -#################################################################### - -# process the arguments - -set(ARGLIST ${CTEST_SCRIPT_ARG}) -while(${ARGLIST} MATCHES ".+.*") - - # pick first - string(REGEX MATCH "([^,]*)(,.*)?" DUMMY ${ARGLIST}) - SET(TOP ${CMAKE_MATCH_1}) - - # remove first - string(REGEX MATCHALL "[^,]*,(.*)" DUMMY ${ARGLIST}) - SET(ARGLIST ${CMAKE_MATCH_1}) - - # decompose as a pair key=value - string(REGEX MATCH "([^=]*)(=.*)?" DUMMY ${TOP}) - SET(KEY ${CMAKE_MATCH_1}) - - string(REGEX MATCH "[^=]*=(.*)" DUMMY ${TOP}) - SET(VALUE ${CMAKE_MATCH_1}) - - # set the variable to the specified value - if(VALUE) - SET(${KEY} ${VALUE}) - else(VALUE) - SET(${KEY} ON) - endif(VALUE) - -endwhile(${ARGLIST} MATCHES ".+.*") - -#################################################################### -# Automatically set some user variables if they have not been defined manually -#################################################################### -cmake_minimum_required(VERSION 2.6 FATAL_ERROR) - -if(NOT EIGEN_SITE) - site_name(EIGEN_SITE) -endif(NOT EIGEN_SITE) - -if(NOT EIGEN_CMAKE_DIR) - SET(EIGEN_CMAKE_DIR "") -endif(NOT EIGEN_CMAKE_DIR) - -if(NOT EIGEN_BUILD_STRING) - - # let's try to find all information we need to make the build string ourself - - # OS - build_name(EIGEN_OS_VERSION) - - # arch - set(EIGEN_ARCH ${CMAKE_SYSTEM_PROCESSOR}) - if(WIN32) - set(EIGEN_ARCH $ENV{PROCESSOR_ARCHITECTURE}) - else(WIN32) - execute_process(COMMAND uname -m OUTPUT_VARIABLE EIGEN_ARCH OUTPUT_STRIP_TRAILING_WHITESPACE) - endif(WIN32) - - set(EIGEN_BUILD_STRING ${EIGEN_OS_VERSION}${EIGEN_ARCH}-${EIGEN_CXX}) - -endif(NOT EIGEN_BUILD_STRING) - -if(DEFINED EIGEN_EXPLICIT_VECTORIZATION) - set(EIGEN_BUILD_STRING ${EIGEN_BUILD_STRING}-${EIGEN_EXPLICIT_VECTORIZATION}) -endif(DEFINED EIGEN_EXPLICIT_VECTORIZATION) - -if(NOT EIGEN_WORK_DIR) - set(EIGEN_WORK_DIR ${CTEST_SCRIPT_DIRECTORY}) -endif(NOT EIGEN_WORK_DIR) - -if(NOT CTEST_SOURCE_DIRECTORY) - SET (CTEST_SOURCE_DIRECTORY "${EIGEN_WORK_DIR}/src") -endif(NOT CTEST_SOURCE_DIRECTORY) - -if(NOT CTEST_BINARY_DIRECTORY) - SET (CTEST_BINARY_DIRECTORY "${EIGEN_WORK_DIR}/nightly_${EIGEN_CXX}") -endif(NOT CTEST_BINARY_DIRECTORY) - -if(NOT EIGEN_MODE) - set(EIGEN_MODE Nightly) -endif(NOT EIGEN_MODE) - -## mandatory variables (the default should be ok in most cases): - -SET (CTEST_CVS_COMMAND "hg") -SET (CTEST_CVS_CHECKOUT "${CTEST_CVS_COMMAND} clone -r 2.0 http://bitbucket.org/eigen/eigen \"${CTEST_SOURCE_DIRECTORY}\"") - -# which ctest command to use for running the dashboard -SET (CTEST_COMMAND "${EIGEN_CMAKE_DIR}ctest -D ${EIGEN_MODE}") - -# what cmake command to use for configuring this dashboard -SET (CTEST_CMAKE_COMMAND "${EIGEN_CMAKE_DIR}cmake -DEIGEN_BUILD_TESTS=on ") - -#################################################################### -# The values in this section are optional you can either -# have them or leave them commented out -#################################################################### - -# this make sure we get consistent outputs -SET($ENV{LC_MESSAGES} "en_EN") - -# should ctest wipe the binary tree before running -SET(CTEST_START_WITH_EMPTY_BINARY_DIRECTORY TRUE) -SET(CTEST_BACKUP_AND_RESTORE TRUE) - -# this is the initial cache to use for the binary tree, be careful to escape -# any quotes inside of this string if you use it -if(WIN32 AND NOT UNIX) - #message(SEND_ERROR "win32") - set(CTEST_CMAKE_COMMAND "${CTEST_CMAKE_COMMAND} -G \"NMake Makefiles\" -DCMAKE_MAKE_PROGRAM=nmake") - SET (CTEST_INITIAL_CACHE " - MAKECOMMAND:STRING=nmake -i - CMAKE_MAKE_PROGRAM:FILEPATH=nmake - CMAKE_GENERATOR:INTERNAL=NMake Makefiles - BUILDNAME:STRING=${EIGEN_BUILD_STRING} - SITE:STRING=${EIGEN_SITE} - ") -else(WIN32 AND NOT UNIX) - SET (CTEST_INITIAL_CACHE " - BUILDNAME:STRING=${EIGEN_BUILD_STRING} - SITE:STRING=${EIGEN_SITE} - ") -endif(WIN32 AND NOT UNIX) - -# set any extra environment variables to use during the execution of the script here: - -if(EIGEN_CXX) - set(CTEST_ENVIRONMENT "CXX=${EIGEN_CXX}") -endif(EIGEN_CXX) - -if(DEFINED EIGEN_EXPLICIT_VECTORIZATION) - if(EIGEN_EXPLICIT_VECTORIZATION MATCHES SSE2) - set(CTEST_CMAKE_COMMAND "${CTEST_CMAKE_COMMAND} -DEIGEN_TEST_SSE2=ON") - elseif(EIGEN_EXPLICIT_VECTORIZATION MATCHES SSE3) - set(CTEST_CMAKE_COMMAND "${CTEST_CMAKE_COMMAND} -DEIGEN_TEST_SSE2=ON -DEIGEN_TEST_SSE3=ON") - elseif(EIGEN_EXPLICIT_VECTORIZATION MATCHES Altivec) - set(CTEST_CMAKE_COMMAND "${CTEST_CMAKE_COMMAND} -DEIGEN_TEST_ALTIVEC=ON") - elseif(EIGEN_EXPLICIT_VECTORIZATION MATCHES novec) - set(CTEST_CMAKE_COMMAND "${CTEST_CMAKE_COMMAND} -DEIGEN_TEST_NO_EXPLICIT_VECTORIZATION=ON") - else(EIGEN_EXPLICIT_VECTORIZATION MATCHES SSE2) - message(FATAL_ERROR "Invalid value for EIGEN_EXPLICIT_VECTORIZATION (${EIGEN_EXPLICIT_VECTORIZATION}), must be: novec, SSE2, SSE3, Altivec") - endif(EIGEN_EXPLICIT_VECTORIZATION MATCHES SSE2) -endif(DEFINED EIGEN_EXPLICIT_VECTORIZATION) - -if(DEFINED EIGEN_CMAKE_ARGS) - set(CTEST_CMAKE_COMMAND "${CTEST_CMAKE_COMMAND} ${EIGEN_CMAKE_ARGS}") -endif(DEFINED EIGEN_CMAKE_ARGS) diff --git a/ground/gcs/src/libs/eigen/test/eigen2support.cpp b/ground/gcs/src/libs/eigen/test/eigen2support.cpp index 1fa49a8c87..ad1d980916 100644 --- a/ground/gcs/src/libs/eigen/test/eigen2support.cpp +++ b/ground/gcs/src/libs/eigen/test/eigen2support.cpp @@ -8,7 +8,6 @@ // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #define EIGEN2_SUPPORT -#define EIGEN_NO_EIGEN2_DEPRECATED_WARNING #include "main.h" diff --git a/ground/gcs/src/libs/eigen/test/eigensolver_complex.cpp b/ground/gcs/src/libs/eigen/test/eigensolver_complex.cpp index c9d8c0877e..293b1b2656 100644 --- a/ground/gcs/src/libs/eigen/test/eigensolver_complex.cpp +++ b/ground/gcs/src/libs/eigen/test/eigensolver_complex.cpp @@ -13,20 +13,59 @@ #include #include -/* Check that two column vectors are approximately equal upto permutations, - by checking that the k-th power sums are equal for k = 1, ..., vec1.rows() */ +template bool find_pivot(typename MatrixType::Scalar tol, MatrixType &diffs, Index col=0) +{ + bool match = diffs.diagonal().sum() <= tol; + if(match || col==diffs.cols()) + { + return match; + } + else + { + Index n = diffs.cols(); + std::vector > transpositions; + for(Index i=col; i tol) + break; + + best_index += col; + + diffs.row(col).swap(diffs.row(best_index)); + if(find_pivot(tol,diffs,col+1)) return true; + diffs.row(col).swap(diffs.row(best_index)); + + // move current pivot to the end + diffs.row(n-(i-col)-1).swap(diffs.row(best_index)); + transpositions.push_back(std::pair(n-(i-col)-1,best_index)); + } + // restore + for(Index k=transpositions.size()-1; k>=0; --k) + diffs.row(transpositions[k].first).swap(diffs.row(transpositions[k].second)); + } + return false; +} + +/* Check that two column vectors are approximately equal upto permutations. + * Initially, this method checked that the k-th power sums are equal for all k = 1, ..., vec1.rows(), + * however this strategy is numerically inacurate because of numerical cancellation issues. + */ template void verify_is_approx_upto_permutation(const VectorType& vec1, const VectorType& vec2) { - typedef typename NumTraits::Real RealScalar; + typedef typename VectorType::Scalar Scalar; + typedef typename NumTraits::Real RealScalar; VERIFY(vec1.cols() == 1); VERIFY(vec2.cols() == 1); VERIFY(vec1.rows() == vec2.rows()); - for (int k = 1; k <= vec1.rows(); ++k) - { - VERIFY_IS_APPROX(vec1.array().pow(RealScalar(k)).sum(), vec2.array().pow(RealScalar(k)).sum()); - } + + Index n = vec1.rows(); + RealScalar tol = test_precision()*test_precision()*numext::maxi(vec1.squaredNorm(),vec2.squaredNorm()); + Matrix diffs = (vec1.rowwise().replicate(n) - vec2.rowwise().replicate(n).transpose()).cwiseAbs2(); + + VERIFY( find_pivot(tol, diffs) ); } @@ -79,13 +118,28 @@ template void eigensolver(const MatrixType& m) MatrixType id = MatrixType::Identity(rows, cols); VERIFY_IS_APPROX(id.operatorNorm(), RealScalar(1)); - if (rows > 1) + if (rows > 1 && rows < 20) { // Test matrix with NaN a(0,0) = std::numeric_limits::quiet_NaN(); ComplexEigenSolver eiNaN(a); VERIFY_IS_EQUAL(eiNaN.info(), NoConvergence); } + + // regression test for bug 1098 + { + ComplexEigenSolver eig(a.adjoint() * a); + eig.compute(a.adjoint() * a); + } + + // regression test for bug 478 + { + a.setZero(); + ComplexEigenSolver ei3(a); + VERIFY_IS_EQUAL(ei3.info(), Success); + VERIFY_IS_MUCH_SMALLER_THAN(ei3.eigenvalues().norm(),RealScalar(1)); + VERIFY((ei3.eigenvectors().transpose()*ei3.eigenvectors().transpose()).eval().isIdentity()); + } } template void eigensolver_verify_assert(const MatrixType& m) @@ -108,6 +162,7 @@ void test_eigensolver_complex() CALL_SUBTEST_2( eigensolver(MatrixXcd(s,s)) ); CALL_SUBTEST_3( eigensolver(Matrix, 1, 1>()) ); CALL_SUBTEST_4( eigensolver(Matrix3f()) ); + TEST_SET_BUT_UNUSED_VARIABLE(s) } CALL_SUBTEST_1( eigensolver_verify_assert(Matrix4cf()) ); s = internal::random(1,EIGEN_TEST_MAX_SIZE/4); diff --git a/ground/gcs/src/libs/eigen/test/eigensolver_generalized_real.cpp b/ground/gcs/src/libs/eigen/test/eigensolver_generalized_real.cpp index 566a4bdc63..9c0838ba4e 100644 --- a/ground/gcs/src/libs/eigen/test/eigensolver_generalized_real.cpp +++ b/ground/gcs/src/libs/eigen/test/eigensolver_generalized_real.cpp @@ -1,15 +1,17 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2012 Gael Guennebaud +// Copyright (C) 2012-2016 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. +#define EIGEN_RUNTIME_NO_MALLOC #include "main.h" #include #include +#include template void generalized_eigensolver_real(const MatrixType& m) { @@ -21,6 +23,7 @@ template void generalized_eigensolver_real(const MatrixType Index cols = m.cols(); typedef typename MatrixType::Scalar Scalar; + typedef std::complex ComplexScalar; typedef Matrix VectorType; MatrixType a = MatrixType::Random(rows,cols); @@ -31,14 +34,49 @@ template void generalized_eigensolver_real(const MatrixType MatrixType spdB = b.adjoint() * b + b1.adjoint() * b1; // lets compare to GeneralizedSelfAdjointEigenSolver - GeneralizedSelfAdjointEigenSolver symmEig(spdA, spdB); - GeneralizedEigenSolver eig(spdA, spdB); + { + GeneralizedSelfAdjointEigenSolver symmEig(spdA, spdB); + GeneralizedEigenSolver eig(spdA, spdB); - VERIFY_IS_EQUAL(eig.eigenvalues().imag().cwiseAbs().maxCoeff(), 0); + VERIFY_IS_EQUAL(eig.eigenvalues().imag().cwiseAbs().maxCoeff(), 0); - VectorType realEigenvalues = eig.eigenvalues().real(); - std::sort(realEigenvalues.data(), realEigenvalues.data()+realEigenvalues.size()); - VERIFY_IS_APPROX(realEigenvalues, symmEig.eigenvalues()); + VectorType realEigenvalues = eig.eigenvalues().real(); + std::sort(realEigenvalues.data(), realEigenvalues.data()+realEigenvalues.size()); + VERIFY_IS_APPROX(realEigenvalues, symmEig.eigenvalues()); + + // check eigenvectors + typename GeneralizedEigenSolver::EigenvectorsType D = eig.eigenvalues().asDiagonal(); + typename GeneralizedEigenSolver::EigenvectorsType V = eig.eigenvectors(); + VERIFY_IS_APPROX(spdA*V, spdB*V*D); + } + + // non symmetric case: + { + GeneralizedEigenSolver eig(rows); + // TODO enable full-prealocation of required memory, this probably requires an in-place mode for HessenbergDecomposition + //Eigen::internal::set_is_malloc_allowed(false); + eig.compute(a,b); + //Eigen::internal::set_is_malloc_allowed(true); + for(Index k=0; k tmp = (eig.betas()(k)*a).template cast() - eig.alphas()(k)*b; + if(tmp.size()>1 && tmp.norm()>(std::numeric_limits::min)()) + tmp /= tmp.norm(); + VERIFY_IS_MUCH_SMALLER_THAN( std::abs(tmp.determinant()), Scalar(1) ); + } + // check eigenvectors + typename GeneralizedEigenSolver::EigenvectorsType D = eig.eigenvalues().asDiagonal(); + typename GeneralizedEigenSolver::EigenvectorsType V = eig.eigenvectors(); + VERIFY_IS_APPROX(a*V, b*V*D); + } + + // regression test for bug 1098 + { + GeneralizedSelfAdjointEigenSolver eig1(a.adjoint() * a,b.adjoint() * b); + eig1.compute(a.adjoint() * a,b.adjoint() * b); + GeneralizedEigenSolver eig2(a.adjoint() * a,b.adjoint() * b); + eig2.compute(a.adjoint() * a,b.adjoint() * b); + } } void test_eigensolver_generalized_real() @@ -49,7 +87,7 @@ void test_eigensolver_generalized_real() s = internal::random(1,EIGEN_TEST_MAX_SIZE/4); CALL_SUBTEST_2( generalized_eigensolver_real(MatrixXd(s,s)) ); - // some trivial but implementation-wise tricky cases + // some trivial but implementation-wise special cases CALL_SUBTEST_2( generalized_eigensolver_real(MatrixXd(1,1)) ); CALL_SUBTEST_2( generalized_eigensolver_real(MatrixXd(2,2)) ); CALL_SUBTEST_3( generalized_eigensolver_real(Matrix()) ); diff --git a/ground/gcs/src/libs/eigen/test/eigensolver_generic.cpp b/ground/gcs/src/libs/eigen/test/eigensolver_generic.cpp index 005af81ebb..d0e644d4be 100644 --- a/ground/gcs/src/libs/eigen/test/eigensolver_generic.cpp +++ b/ground/gcs/src/libs/eigen/test/eigensolver_generic.cpp @@ -63,13 +63,28 @@ template void eigensolver(const MatrixType& m) MatrixType id = MatrixType::Identity(rows, cols); VERIFY_IS_APPROX(id.operatorNorm(), RealScalar(1)); - if (rows > 2) + if (rows > 2 && rows < 20) { // Test matrix with NaN a(0,0) = std::numeric_limits::quiet_NaN(); EigenSolver eiNaN(a); VERIFY_IS_EQUAL(eiNaN.info(), NoConvergence); } + + // regression test for bug 1098 + { + EigenSolver eig(a.adjoint() * a); + eig.compute(a.adjoint() * a); + } + + // regression test for bug 478 + { + a.setZero(); + EigenSolver ei3(a); + VERIFY_IS_EQUAL(ei3.info(), Success); + VERIFY_IS_MUCH_SMALLER_THAN(ei3.eigenvalues().norm(),RealScalar(1)); + VERIFY((ei3.eigenvectors().transpose()*ei3.eigenvectors().transpose()).eval().isIdentity()); + } } template void eigensolver_verify_assert(const MatrixType& m) @@ -93,6 +108,7 @@ void test_eigensolver_generic() CALL_SUBTEST_1( eigensolver(Matrix4f()) ); s = internal::random(1,EIGEN_TEST_MAX_SIZE/4); CALL_SUBTEST_2( eigensolver(MatrixXd(s,s)) ); + TEST_SET_BUT_UNUSED_VARIABLE(s) // some trivial but implementation-wise tricky cases CALL_SUBTEST_2( eigensolver(MatrixXd(1,1)) ); @@ -114,12 +130,37 @@ void test_eigensolver_generic() CALL_SUBTEST_2( { MatrixXd A(1,1); - A(0,0) = std::sqrt(-1.); + A(0,0) = std::sqrt(-1.); // is Not-a-Number Eigen::EigenSolver solver(A); - MatrixXd V(1, 1); - V(0,0) = solver.eigenvectors()(0,0).real(); + VERIFY_IS_EQUAL(solver.info(), NumericalIssue); } ); +#ifdef EIGEN_TEST_PART_2 + { + // regression test for bug 793 + MatrixXd a(3,3); + a << 0, 0, 1, + 1, 1, 1, + 1, 1e+200, 1; + Eigen::EigenSolver eig(a); + double scale = 1e-200; // scale to avoid overflow during the comparisons + VERIFY_IS_APPROX(a * eig.pseudoEigenvectors()*scale, eig.pseudoEigenvectors() * eig.pseudoEigenvalueMatrix()*scale); + VERIFY_IS_APPROX(a * eig.eigenvectors()*scale, eig.eigenvectors() * eig.eigenvalues().asDiagonal()*scale); + } + { + // check a case where all eigenvalues are null. + MatrixXd a(2,2); + a << 1, 1, + -1, -1; + Eigen::EigenSolver eig(a); + VERIFY_IS_APPROX(eig.pseudoEigenvectors().squaredNorm(), 2.); + VERIFY_IS_APPROX((a * eig.pseudoEigenvectors()).norm()+1., 1.); + VERIFY_IS_APPROX((eig.pseudoEigenvectors() * eig.pseudoEigenvalueMatrix()).norm()+1., 1.); + VERIFY_IS_APPROX((a * eig.eigenvectors()).norm()+1., 1.); + VERIFY_IS_APPROX((eig.eigenvectors() * eig.eigenvalues().asDiagonal()).norm()+1., 1.); + } +#endif + TEST_SET_BUT_UNUSED_VARIABLE(s) } diff --git a/ground/gcs/src/libs/eigen/test/eigensolver_selfadjoint.cpp b/ground/gcs/src/libs/eigen/test/eigensolver_selfadjoint.cpp index 38689cfbf3..39ad4130e8 100644 --- a/ground/gcs/src/libs/eigen/test/eigensolver_selfadjoint.cpp +++ b/ground/gcs/src/libs/eigen/test/eigensolver_selfadjoint.cpp @@ -9,8 +9,62 @@ // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #include "main.h" +#include "svd_fill.h" #include #include +#include + + +template void selfadjointeigensolver_essential_check(const MatrixType& m) +{ + typedef typename MatrixType::Scalar Scalar; + typedef typename NumTraits::Real RealScalar; + RealScalar eival_eps = numext::mini(test_precision(), NumTraits::dummy_precision()*20000); + + SelfAdjointEigenSolver eiSymm(m); + VERIFY_IS_EQUAL(eiSymm.info(), Success); + + RealScalar scaling = m.cwiseAbs().maxCoeff(); + + if(scaling<(std::numeric_limits::min)()) + { + VERIFY(eiSymm.eigenvalues().cwiseAbs().maxCoeff() <= (std::numeric_limits::min)()); + } + else + { + VERIFY_IS_APPROX((m.template selfadjointView() * eiSymm.eigenvectors())/scaling, + (eiSymm.eigenvectors() * eiSymm.eigenvalues().asDiagonal())/scaling); + } + VERIFY_IS_APPROX(m.template selfadjointView().eigenvalues(), eiSymm.eigenvalues()); + VERIFY_IS_UNITARY(eiSymm.eigenvectors()); + + if(m.cols()<=4) + { + SelfAdjointEigenSolver eiDirect; + eiDirect.computeDirect(m); + VERIFY_IS_EQUAL(eiDirect.info(), Success); + if(! eiSymm.eigenvalues().isApprox(eiDirect.eigenvalues(), eival_eps) ) + { + std::cerr << "reference eigenvalues: " << eiSymm.eigenvalues().transpose() << "\n" + << "obtained eigenvalues: " << eiDirect.eigenvalues().transpose() << "\n" + << "diff: " << (eiSymm.eigenvalues()-eiDirect.eigenvalues()).transpose() << "\n" + << "error (eps): " << (eiSymm.eigenvalues()-eiDirect.eigenvalues()).norm() / eiSymm.eigenvalues().norm() << " (" << eival_eps << ")\n"; + } + if(scaling<(std::numeric_limits::min)()) + { + VERIFY(eiDirect.eigenvalues().cwiseAbs().maxCoeff() <= (std::numeric_limits::min)()); + } + else + { + VERIFY_IS_APPROX(eiSymm.eigenvalues()/scaling, eiDirect.eigenvalues()/scaling); + VERIFY_IS_APPROX((m.template selfadjointView() * eiDirect.eigenvectors())/scaling, + (eiDirect.eigenvectors() * eiDirect.eigenvalues().asDiagonal())/scaling); + VERIFY_IS_APPROX(m.template selfadjointView().eigenvalues()/scaling, eiDirect.eigenvalues()/scaling); + } + + VERIFY_IS_UNITARY(eiDirect.eigenvectors()); + } +} template void selfadjointeigensolver(const MatrixType& m) { @@ -31,17 +85,8 @@ template void selfadjointeigensolver(const MatrixType& m) MatrixType symmA = a.adjoint() * a + a1.adjoint() * a1; MatrixType symmC = symmA; - // randomly nullify some rows/columns - { - Index count = 1;//internal::random(-cols,cols); - for(Index k=0; k(0,cols-1); - symmA.row(i).setZero(); - symmA.col(i).setZero(); - } - } - + svd_fill_random(symmA,Symmetric); + symmA.template triangularView().setZero(); symmC.template triangularView().setZero(); @@ -49,23 +94,13 @@ template void selfadjointeigensolver(const MatrixType& m) MatrixType b1 = MatrixType::Random(rows,cols); MatrixType symmB = b.adjoint() * b + b1.adjoint() * b1; symmB.template triangularView().setZero(); + + CALL_SUBTEST( selfadjointeigensolver_essential_check(symmA) ); SelfAdjointEigenSolver eiSymm(symmA); - SelfAdjointEigenSolver eiDirect; - eiDirect.computeDirect(symmA); // generalized eigen pb GeneralizedSelfAdjointEigenSolver eiSymmGen(symmC, symmB); - VERIFY_IS_EQUAL(eiSymm.info(), Success); - VERIFY((symmA.template selfadjointView() * eiSymm.eigenvectors()).isApprox( - eiSymm.eigenvectors() * eiSymm.eigenvalues().asDiagonal(), largerEps)); - VERIFY_IS_APPROX(symmA.template selfadjointView().eigenvalues(), eiSymm.eigenvalues()); - - VERIFY_IS_EQUAL(eiDirect.info(), Success); - VERIFY((symmA.template selfadjointView() * eiDirect.eigenvectors()).isApprox( - eiDirect.eigenvectors() * eiDirect.eigenvalues().asDiagonal(), largerEps)); - VERIFY_IS_APPROX(symmA.template selfadjointView().eigenvalues(), eiDirect.eigenvalues()); - SelfAdjointEigenSolver eiSymmNoEivecs(symmA, false); VERIFY_IS_EQUAL(eiSymmNoEivecs.info(), Success); VERIFY_IS_APPROX(eiSymm.eigenvalues(), eiSymmNoEivecs.eigenvalues()); @@ -111,37 +146,111 @@ template void selfadjointeigensolver(const MatrixType& m) // test Tridiagonalization's methods Tridiagonalization tridiag(symmC); - // FIXME tridiag.matrixQ().adjoint() does not work + VERIFY_IS_APPROX(tridiag.diagonal(), tridiag.matrixT().diagonal()); + VERIFY_IS_APPROX(tridiag.subDiagonal(), tridiag.matrixT().template diagonal<-1>()); + Matrix T = tridiag.matrixT(); + if(rows>1 && cols>1) { + // FIXME check that upper and lower part are 0: + //VERIFY(T.topRightCorner(rows-2, cols-2).template triangularView().isZero()); + } + VERIFY_IS_APPROX(tridiag.diagonal(), T.diagonal()); + VERIFY_IS_APPROX(tridiag.subDiagonal(), T.template diagonal<1>()); VERIFY_IS_APPROX(MatrixType(symmC.template selfadjointView()), tridiag.matrixQ() * tridiag.matrixT().eval() * MatrixType(tridiag.matrixQ()).adjoint()); + VERIFY_IS_APPROX(MatrixType(symmC.template selfadjointView()), tridiag.matrixQ() * tridiag.matrixT() * tridiag.matrixQ().adjoint()); - if (rows > 1) + // Test computation of eigenvalues from tridiagonal matrix + if(rows > 1) + { + SelfAdjointEigenSolver eiSymmTridiag; + eiSymmTridiag.computeFromTridiagonal(tridiag.matrixT().diagonal(), tridiag.matrixT().diagonal(-1), ComputeEigenvectors); + VERIFY_IS_APPROX(eiSymm.eigenvalues(), eiSymmTridiag.eigenvalues()); + VERIFY_IS_APPROX(tridiag.matrixT(), eiSymmTridiag.eigenvectors().real() * eiSymmTridiag.eigenvalues().asDiagonal() * eiSymmTridiag.eigenvectors().real().transpose()); + } + + if (rows > 1 && rows < 20) { // Test matrix with NaN symmC(0,0) = std::numeric_limits::quiet_NaN(); SelfAdjointEigenSolver eiSymmNaN(symmC); VERIFY_IS_EQUAL(eiSymmNaN.info(), NoConvergence); } + + // regression test for bug 1098 + { + SelfAdjointEigenSolver eig(a.adjoint() * a); + eig.compute(a.adjoint() * a); + } + + // regression test for bug 478 + { + a.setZero(); + SelfAdjointEigenSolver ei3(a); + VERIFY_IS_EQUAL(ei3.info(), Success); + VERIFY_IS_MUCH_SMALLER_THAN(ei3.eigenvalues().norm(),RealScalar(1)); + VERIFY((ei3.eigenvectors().transpose()*ei3.eigenvectors().transpose()).eval().isIdentity()); + } +} + +template +void bug_854() +{ + Matrix3d m; + m << 850.961, 51.966, 0, + 51.966, 254.841, 0, + 0, 0, 0; + selfadjointeigensolver_essential_check(m); +} + +template +void bug_1014() +{ + Matrix3d m; + m << 0.11111111111111114658, 0, 0, + 0, 0.11111111111111109107, 0, + 0, 0, 0.11111111111111107719; + selfadjointeigensolver_essential_check(m); +} + +template +void bug_1225() +{ + Matrix3d m1, m2; + m1.setRandom(); + m1 = m1*m1.transpose(); + m2 = m1.triangularView(); + SelfAdjointEigenSolver eig1(m1); + SelfAdjointEigenSolver eig2(m2.selfadjointView()); + VERIFY_IS_APPROX(eig1.eigenvalues(), eig2.eigenvalues()); +} + +template +void bug_1204() +{ + SparseMatrix A(2,2); + A.setIdentity(); + SelfAdjointEigenSolver > eig(A); } void test_eigensolver_selfadjoint() { int s = 0; for(int i = 0; i < g_repeat; i++) { + // trivial test for 1x1 matrices: + CALL_SUBTEST_1( selfadjointeigensolver(Matrix())); + CALL_SUBTEST_1( selfadjointeigensolver(Matrix())); // very important to test 3x3 and 2x2 matrices since we provide special paths for them - CALL_SUBTEST_1( selfadjointeigensolver(Matrix2f()) ); - CALL_SUBTEST_1( selfadjointeigensolver(Matrix2d()) ); - CALL_SUBTEST_1( selfadjointeigensolver(Matrix3f()) ); - CALL_SUBTEST_1( selfadjointeigensolver(Matrix3d()) ); + CALL_SUBTEST_12( selfadjointeigensolver(Matrix2f()) ); + CALL_SUBTEST_12( selfadjointeigensolver(Matrix2d()) ); + CALL_SUBTEST_13( selfadjointeigensolver(Matrix3f()) ); + CALL_SUBTEST_13( selfadjointeigensolver(Matrix3d()) ); CALL_SUBTEST_2( selfadjointeigensolver(Matrix4d()) ); + s = internal::random(1,EIGEN_TEST_MAX_SIZE/4); CALL_SUBTEST_3( selfadjointeigensolver(MatrixXf(s,s)) ); - s = internal::random(1,EIGEN_TEST_MAX_SIZE/4); CALL_SUBTEST_4( selfadjointeigensolver(MatrixXd(s,s)) ); - s = internal::random(1,EIGEN_TEST_MAX_SIZE/4); CALL_SUBTEST_5( selfadjointeigensolver(MatrixXcd(s,s)) ); - - s = internal::random(1,EIGEN_TEST_MAX_SIZE/4); CALL_SUBTEST_9( selfadjointeigensolver(Matrix,Dynamic,Dynamic,RowMajor>(s,s)) ); + TEST_SET_BUT_UNUSED_VARIABLE(s) // some trivial but implementation-wise tricky cases CALL_SUBTEST_4( selfadjointeigensolver(MatrixXd(1,1)) ); @@ -149,6 +258,11 @@ void test_eigensolver_selfadjoint() CALL_SUBTEST_6( selfadjointeigensolver(Matrix()) ); CALL_SUBTEST_7( selfadjointeigensolver(Matrix()) ); } + + CALL_SUBTEST_13( bug_854<0>() ); + CALL_SUBTEST_13( bug_1014<0>() ); + CALL_SUBTEST_13( bug_1204<0>() ); + CALL_SUBTEST_13( bug_1225<0>() ); // Test problem size constructors s = internal::random(1,EIGEN_TEST_MAX_SIZE/4); diff --git a/ground/gcs/src/libs/eigen/test/evaluator_common.h b/ground/gcs/src/libs/eigen/test/evaluator_common.h new file mode 100644 index 0000000000..e69de29bb2 diff --git a/ground/gcs/src/libs/eigen/test/evaluators.cpp b/ground/gcs/src/libs/eigen/test/evaluators.cpp new file mode 100644 index 0000000000..aed5a05a7f --- /dev/null +++ b/ground/gcs/src/libs/eigen/test/evaluators.cpp @@ -0,0 +1,499 @@ + +#include "main.h" + +namespace Eigen { + + template + const Product + prod(const Lhs& lhs, const Rhs& rhs) + { + return Product(lhs,rhs); + } + + template + const Product + lazyprod(const Lhs& lhs, const Rhs& rhs) + { + return Product(lhs,rhs); + } + + template + EIGEN_STRONG_INLINE + DstXprType& copy_using_evaluator(const EigenBase &dst, const SrcXprType &src) + { + call_assignment(dst.const_cast_derived(), src.derived(), internal::assign_op()); + return dst.const_cast_derived(); + } + + template class StorageBase, typename SrcXprType> + EIGEN_STRONG_INLINE + const DstXprType& copy_using_evaluator(const NoAlias& dst, const SrcXprType &src) + { + call_assignment(dst, src.derived(), internal::assign_op()); + return dst.expression(); + } + + template + EIGEN_STRONG_INLINE + DstXprType& copy_using_evaluator(const PlainObjectBase &dst, const SrcXprType &src) + { + #ifdef EIGEN_NO_AUTOMATIC_RESIZING + eigen_assert((dst.size()==0 || (IsVectorAtCompileTime ? (dst.size() == src.size()) + : (dst.rows() == src.rows() && dst.cols() == src.cols()))) + && "Size mismatch. Automatic resizing is disabled because EIGEN_NO_AUTOMATIC_RESIZING is defined"); + #else + dst.const_cast_derived().resizeLike(src.derived()); + #endif + + call_assignment(dst.const_cast_derived(), src.derived(), internal::assign_op()); + return dst.const_cast_derived(); + } + + template + void add_assign_using_evaluator(const DstXprType& dst, const SrcXprType& src) + { + typedef typename DstXprType::Scalar Scalar; + call_assignment(const_cast(dst), src.derived(), internal::add_assign_op()); + } + + template + void subtract_assign_using_evaluator(const DstXprType& dst, const SrcXprType& src) + { + typedef typename DstXprType::Scalar Scalar; + call_assignment(const_cast(dst), src.derived(), internal::sub_assign_op()); + } + + template + void multiply_assign_using_evaluator(const DstXprType& dst, const SrcXprType& src) + { + typedef typename DstXprType::Scalar Scalar; + call_assignment(dst.const_cast_derived(), src.derived(), internal::mul_assign_op()); + } + + template + void divide_assign_using_evaluator(const DstXprType& dst, const SrcXprType& src) + { + typedef typename DstXprType::Scalar Scalar; + call_assignment(dst.const_cast_derived(), src.derived(), internal::div_assign_op()); + } + + template + void swap_using_evaluator(const DstXprType& dst, const SrcXprType& src) + { + typedef typename DstXprType::Scalar Scalar; + call_assignment(dst.const_cast_derived(), src.const_cast_derived(), internal::swap_assign_op()); + } + + namespace internal { + template class StorageBase, typename Src, typename Func> + EIGEN_DEVICE_FUNC void call_assignment(const NoAlias& dst, const Src& src, const Func& func) + { + call_assignment_no_alias(dst.expression(), src, func); + } + } + +} + +template long get_cost(const XprType& ) { return Eigen::internal::evaluator::CoeffReadCost; } + +using namespace std; + +#define VERIFY_IS_APPROX_EVALUATOR(DEST,EXPR) VERIFY_IS_APPROX(copy_using_evaluator(DEST,(EXPR)), (EXPR).eval()); +#define VERIFY_IS_APPROX_EVALUATOR2(DEST,EXPR,REF) VERIFY_IS_APPROX(copy_using_evaluator(DEST,(EXPR)), (REF).eval()); + +void test_evaluators() +{ + // Testing Matrix evaluator and Transpose + Vector2d v = Vector2d::Random(); + const Vector2d v_const(v); + Vector2d v2; + RowVector2d w; + + VERIFY_IS_APPROX_EVALUATOR(v2, v); + VERIFY_IS_APPROX_EVALUATOR(v2, v_const); + + // Testing Transpose + VERIFY_IS_APPROX_EVALUATOR(w, v.transpose()); // Transpose as rvalue + VERIFY_IS_APPROX_EVALUATOR(w, v_const.transpose()); + + copy_using_evaluator(w.transpose(), v); // Transpose as lvalue + VERIFY_IS_APPROX(w,v.transpose().eval()); + + copy_using_evaluator(w.transpose(), v_const); + VERIFY_IS_APPROX(w,v_const.transpose().eval()); + + // Testing Array evaluator + { + ArrayXXf a(2,3); + ArrayXXf b(3,2); + a << 1,2,3, 4,5,6; + const ArrayXXf a_const(a); + + VERIFY_IS_APPROX_EVALUATOR(b, a.transpose()); + + VERIFY_IS_APPROX_EVALUATOR(b, a_const.transpose()); + + // Testing CwiseNullaryOp evaluator + copy_using_evaluator(w, RowVector2d::Random()); + VERIFY((w.array() >= -1).all() && (w.array() <= 1).all()); // not easy to test ... + + VERIFY_IS_APPROX_EVALUATOR(w, RowVector2d::Zero()); + + VERIFY_IS_APPROX_EVALUATOR(w, RowVector2d::Constant(3)); + + // mix CwiseNullaryOp and transpose + VERIFY_IS_APPROX_EVALUATOR(w, Vector2d::Zero().transpose()); + } + + { + // test product expressions + int s = internal::random(1,100); + MatrixXf a(s,s), b(s,s), c(s,s), d(s,s); + a.setRandom(); + b.setRandom(); + c.setRandom(); + d.setRandom(); + VERIFY_IS_APPROX_EVALUATOR(d, (a + b)); + VERIFY_IS_APPROX_EVALUATOR(d, (a + b).transpose()); + VERIFY_IS_APPROX_EVALUATOR2(d, prod(a,b), a*b); + VERIFY_IS_APPROX_EVALUATOR2(d.noalias(), prod(a,b), a*b); + VERIFY_IS_APPROX_EVALUATOR2(d, prod(a,b) + c, a*b + c); + VERIFY_IS_APPROX_EVALUATOR2(d, s * prod(a,b), s * a*b); + VERIFY_IS_APPROX_EVALUATOR2(d, prod(a,b).transpose(), (a*b).transpose()); + VERIFY_IS_APPROX_EVALUATOR2(d, prod(a,b) + prod(b,c), a*b + b*c); + + // check that prod works even with aliasing present + c = a*a; + copy_using_evaluator(a, prod(a,a)); + VERIFY_IS_APPROX(a,c); + + // check compound assignment of products + d = c; + add_assign_using_evaluator(c.noalias(), prod(a,b)); + d.noalias() += a*b; + VERIFY_IS_APPROX(c, d); + + d = c; + subtract_assign_using_evaluator(c.noalias(), prod(a,b)); + d.noalias() -= a*b; + VERIFY_IS_APPROX(c, d); + } + + { + // test product with all possible sizes + int s = internal::random(1,100); + Matrix m11, res11; m11.setRandom(1,1); + Matrix m14, res14; m14.setRandom(1,4); + Matrix m1X, res1X; m1X.setRandom(1,s); + Matrix m41, res41; m41.setRandom(4,1); + Matrix m44, res44; m44.setRandom(4,4); + Matrix m4X, res4X; m4X.setRandom(4,s); + Matrix mX1, resX1; mX1.setRandom(s,1); + Matrix mX4, resX4; mX4.setRandom(s,4); + Matrix mXX, resXX; mXX.setRandom(s,s); + + VERIFY_IS_APPROX_EVALUATOR2(res11, prod(m11,m11), m11*m11); + VERIFY_IS_APPROX_EVALUATOR2(res11, prod(m14,m41), m14*m41); + VERIFY_IS_APPROX_EVALUATOR2(res11, prod(m1X,mX1), m1X*mX1); + VERIFY_IS_APPROX_EVALUATOR2(res14, prod(m11,m14), m11*m14); + VERIFY_IS_APPROX_EVALUATOR2(res14, prod(m14,m44), m14*m44); + VERIFY_IS_APPROX_EVALUATOR2(res14, prod(m1X,mX4), m1X*mX4); + VERIFY_IS_APPROX_EVALUATOR2(res1X, prod(m11,m1X), m11*m1X); + VERIFY_IS_APPROX_EVALUATOR2(res1X, prod(m14,m4X), m14*m4X); + VERIFY_IS_APPROX_EVALUATOR2(res1X, prod(m1X,mXX), m1X*mXX); + VERIFY_IS_APPROX_EVALUATOR2(res41, prod(m41,m11), m41*m11); + VERIFY_IS_APPROX_EVALUATOR2(res41, prod(m44,m41), m44*m41); + VERIFY_IS_APPROX_EVALUATOR2(res41, prod(m4X,mX1), m4X*mX1); + VERIFY_IS_APPROX_EVALUATOR2(res44, prod(m41,m14), m41*m14); + VERIFY_IS_APPROX_EVALUATOR2(res44, prod(m44,m44), m44*m44); + VERIFY_IS_APPROX_EVALUATOR2(res44, prod(m4X,mX4), m4X*mX4); + VERIFY_IS_APPROX_EVALUATOR2(res4X, prod(m41,m1X), m41*m1X); + VERIFY_IS_APPROX_EVALUATOR2(res4X, prod(m44,m4X), m44*m4X); + VERIFY_IS_APPROX_EVALUATOR2(res4X, prod(m4X,mXX), m4X*mXX); + VERIFY_IS_APPROX_EVALUATOR2(resX1, prod(mX1,m11), mX1*m11); + VERIFY_IS_APPROX_EVALUATOR2(resX1, prod(mX4,m41), mX4*m41); + VERIFY_IS_APPROX_EVALUATOR2(resX1, prod(mXX,mX1), mXX*mX1); + VERIFY_IS_APPROX_EVALUATOR2(resX4, prod(mX1,m14), mX1*m14); + VERIFY_IS_APPROX_EVALUATOR2(resX4, prod(mX4,m44), mX4*m44); + VERIFY_IS_APPROX_EVALUATOR2(resX4, prod(mXX,mX4), mXX*mX4); + VERIFY_IS_APPROX_EVALUATOR2(resXX, prod(mX1,m1X), mX1*m1X); + VERIFY_IS_APPROX_EVALUATOR2(resXX, prod(mX4,m4X), mX4*m4X); + VERIFY_IS_APPROX_EVALUATOR2(resXX, prod(mXX,mXX), mXX*mXX); + } + + { + ArrayXXf a(2,3); + ArrayXXf b(3,2); + a << 1,2,3, 4,5,6; + const ArrayXXf a_const(a); + + // this does not work because Random is eval-before-nested: + // copy_using_evaluator(w, Vector2d::Random().transpose()); + + // test CwiseUnaryOp + VERIFY_IS_APPROX_EVALUATOR(v2, 3 * v); + VERIFY_IS_APPROX_EVALUATOR(w, (3 * v).transpose()); + VERIFY_IS_APPROX_EVALUATOR(b, (a + 3).transpose()); + VERIFY_IS_APPROX_EVALUATOR(b, (2 * a_const + 3).transpose()); + + // test CwiseBinaryOp + VERIFY_IS_APPROX_EVALUATOR(v2, v + Vector2d::Ones()); + VERIFY_IS_APPROX_EVALUATOR(w, (v + Vector2d::Ones()).transpose().cwiseProduct(RowVector2d::Constant(3))); + + // dynamic matrices and arrays + MatrixXd mat1(6,6), mat2(6,6); + VERIFY_IS_APPROX_EVALUATOR(mat1, MatrixXd::Identity(6,6)); + VERIFY_IS_APPROX_EVALUATOR(mat2, mat1); + copy_using_evaluator(mat2.transpose(), mat1); + VERIFY_IS_APPROX(mat2.transpose(), mat1); + + ArrayXXd arr1(6,6), arr2(6,6); + VERIFY_IS_APPROX_EVALUATOR(arr1, ArrayXXd::Constant(6,6, 3.0)); + VERIFY_IS_APPROX_EVALUATOR(arr2, arr1); + + // test automatic resizing + mat2.resize(3,3); + VERIFY_IS_APPROX_EVALUATOR(mat2, mat1); + arr2.resize(9,9); + VERIFY_IS_APPROX_EVALUATOR(arr2, arr1); + + // test direct traversal + Matrix3f m3; + Array33f a3; + VERIFY_IS_APPROX_EVALUATOR(m3, Matrix3f::Identity()); // matrix, nullary + // TODO: find a way to test direct traversal with array + VERIFY_IS_APPROX_EVALUATOR(m3.transpose(), Matrix3f::Identity().transpose()); // transpose + VERIFY_IS_APPROX_EVALUATOR(m3, 2 * Matrix3f::Identity()); // unary + VERIFY_IS_APPROX_EVALUATOR(m3, Matrix3f::Identity() + Matrix3f::Zero()); // binary + VERIFY_IS_APPROX_EVALUATOR(m3.block(0,0,2,2), Matrix3f::Identity().block(1,1,2,2)); // block + + // test linear traversal + VERIFY_IS_APPROX_EVALUATOR(m3, Matrix3f::Zero()); // matrix, nullary + VERIFY_IS_APPROX_EVALUATOR(a3, Array33f::Zero()); // array + VERIFY_IS_APPROX_EVALUATOR(m3.transpose(), Matrix3f::Zero().transpose()); // transpose + VERIFY_IS_APPROX_EVALUATOR(m3, 2 * Matrix3f::Zero()); // unary + VERIFY_IS_APPROX_EVALUATOR(m3, Matrix3f::Zero() + m3); // binary + + // test inner vectorization + Matrix4f m4, m4src = Matrix4f::Random(); + Array44f a4, a4src = Matrix4f::Random(); + VERIFY_IS_APPROX_EVALUATOR(m4, m4src); // matrix + VERIFY_IS_APPROX_EVALUATOR(a4, a4src); // array + VERIFY_IS_APPROX_EVALUATOR(m4.transpose(), m4src.transpose()); // transpose + // TODO: find out why Matrix4f::Zero() does not allow inner vectorization + VERIFY_IS_APPROX_EVALUATOR(m4, 2 * m4src); // unary + VERIFY_IS_APPROX_EVALUATOR(m4, m4src + m4src); // binary + + // test linear vectorization + MatrixXf mX(6,6), mXsrc = MatrixXf::Random(6,6); + ArrayXXf aX(6,6), aXsrc = ArrayXXf::Random(6,6); + VERIFY_IS_APPROX_EVALUATOR(mX, mXsrc); // matrix + VERIFY_IS_APPROX_EVALUATOR(aX, aXsrc); // array + VERIFY_IS_APPROX_EVALUATOR(mX.transpose(), mXsrc.transpose()); // transpose + VERIFY_IS_APPROX_EVALUATOR(mX, MatrixXf::Zero(6,6)); // nullary + VERIFY_IS_APPROX_EVALUATOR(mX, 2 * mXsrc); // unary + VERIFY_IS_APPROX_EVALUATOR(mX, mXsrc + mXsrc); // binary + + // test blocks and slice vectorization + VERIFY_IS_APPROX_EVALUATOR(m4, (mXsrc.block<4,4>(1,0))); + VERIFY_IS_APPROX_EVALUATOR(aX, ArrayXXf::Constant(10, 10, 3.0).block(2, 3, 6, 6)); + + Matrix4f m4ref = m4; + copy_using_evaluator(m4.block(1, 1, 2, 3), m3.bottomRows(2)); + m4ref.block(1, 1, 2, 3) = m3.bottomRows(2); + VERIFY_IS_APPROX(m4, m4ref); + + mX.setIdentity(20,20); + MatrixXf mXref = MatrixXf::Identity(20,20); + mXsrc = MatrixXf::Random(9,12); + copy_using_evaluator(mX.block(4, 4, 9, 12), mXsrc); + mXref.block(4, 4, 9, 12) = mXsrc; + VERIFY_IS_APPROX(mX, mXref); + + // test Map + const float raw[3] = {1,2,3}; + float buffer[3] = {0,0,0}; + Vector3f v3; + Array3f a3f; + VERIFY_IS_APPROX_EVALUATOR(v3, Map(raw)); + VERIFY_IS_APPROX_EVALUATOR(a3f, Map(raw)); + Vector3f::Map(buffer) = 2*v3; + VERIFY(buffer[0] == 2); + VERIFY(buffer[1] == 4); + VERIFY(buffer[2] == 6); + + // test CwiseUnaryView + mat1.setRandom(); + mat2.setIdentity(); + MatrixXcd matXcd(6,6), matXcd_ref(6,6); + copy_using_evaluator(matXcd.real(), mat1); + copy_using_evaluator(matXcd.imag(), mat2); + matXcd_ref.real() = mat1; + matXcd_ref.imag() = mat2; + VERIFY_IS_APPROX(matXcd, matXcd_ref); + + // test Select + VERIFY_IS_APPROX_EVALUATOR(aX, (aXsrc > 0).select(aXsrc, -aXsrc)); + + // test Replicate + mXsrc = MatrixXf::Random(6, 6); + VectorXf vX = VectorXf::Random(6); + mX.resize(6, 6); + VERIFY_IS_APPROX_EVALUATOR(mX, mXsrc.colwise() + vX); + matXcd.resize(12, 12); + VERIFY_IS_APPROX_EVALUATOR(matXcd, matXcd_ref.replicate(2,2)); + VERIFY_IS_APPROX_EVALUATOR(matXcd, (matXcd_ref.replicate<2,2>())); + + // test partial reductions + VectorXd vec1(6); + VERIFY_IS_APPROX_EVALUATOR(vec1, mat1.rowwise().sum()); + VERIFY_IS_APPROX_EVALUATOR(vec1, mat1.colwise().sum().transpose()); + + // test MatrixWrapper and ArrayWrapper + mat1.setRandom(6,6); + arr1.setRandom(6,6); + VERIFY_IS_APPROX_EVALUATOR(mat2, arr1.matrix()); + VERIFY_IS_APPROX_EVALUATOR(arr2, mat1.array()); + VERIFY_IS_APPROX_EVALUATOR(mat2, (arr1 + 2).matrix()); + VERIFY_IS_APPROX_EVALUATOR(arr2, mat1.array() + 2); + mat2.array() = arr1 * arr1; + VERIFY_IS_APPROX(mat2, (arr1 * arr1).matrix()); + arr2.matrix() = MatrixXd::Identity(6,6); + VERIFY_IS_APPROX(arr2, MatrixXd::Identity(6,6).array()); + + // test Reverse + VERIFY_IS_APPROX_EVALUATOR(arr2, arr1.reverse()); + VERIFY_IS_APPROX_EVALUATOR(arr2, arr1.colwise().reverse()); + VERIFY_IS_APPROX_EVALUATOR(arr2, arr1.rowwise().reverse()); + arr2.reverse() = arr1; + VERIFY_IS_APPROX(arr2, arr1.reverse()); + mat2.array() = mat1.array().reverse(); + VERIFY_IS_APPROX(mat2.array(), mat1.array().reverse()); + + // test Diagonal + VERIFY_IS_APPROX_EVALUATOR(vec1, mat1.diagonal()); + vec1.resize(5); + VERIFY_IS_APPROX_EVALUATOR(vec1, mat1.diagonal(1)); + VERIFY_IS_APPROX_EVALUATOR(vec1, mat1.diagonal<-1>()); + vec1.setRandom(); + + mat2 = mat1; + copy_using_evaluator(mat1.diagonal(1), vec1); + mat2.diagonal(1) = vec1; + VERIFY_IS_APPROX(mat1, mat2); + + copy_using_evaluator(mat1.diagonal<-1>(), mat1.diagonal(1)); + mat2.diagonal<-1>() = mat2.diagonal(1); + VERIFY_IS_APPROX(mat1, mat2); + } + + { + // test swapping + MatrixXd mat1, mat2, mat1ref, mat2ref; + mat1ref = mat1 = MatrixXd::Random(6, 6); + mat2ref = mat2 = 2 * mat1 + MatrixXd::Identity(6, 6); + swap_using_evaluator(mat1, mat2); + mat1ref.swap(mat2ref); + VERIFY_IS_APPROX(mat1, mat1ref); + VERIFY_IS_APPROX(mat2, mat2ref); + + swap_using_evaluator(mat1.block(0, 0, 3, 3), mat2.block(3, 3, 3, 3)); + mat1ref.block(0, 0, 3, 3).swap(mat2ref.block(3, 3, 3, 3)); + VERIFY_IS_APPROX(mat1, mat1ref); + VERIFY_IS_APPROX(mat2, mat2ref); + + swap_using_evaluator(mat1.row(2), mat2.col(3).transpose()); + mat1.row(2).swap(mat2.col(3).transpose()); + VERIFY_IS_APPROX(mat1, mat1ref); + VERIFY_IS_APPROX(mat2, mat2ref); + } + + { + // test compound assignment + const Matrix4d mat_const = Matrix4d::Random(); + Matrix4d mat, mat_ref; + mat = mat_ref = Matrix4d::Identity(); + add_assign_using_evaluator(mat, mat_const); + mat_ref += mat_const; + VERIFY_IS_APPROX(mat, mat_ref); + + subtract_assign_using_evaluator(mat.row(1), 2*mat.row(2)); + mat_ref.row(1) -= 2*mat_ref.row(2); + VERIFY_IS_APPROX(mat, mat_ref); + + const ArrayXXf arr_const = ArrayXXf::Random(5,3); + ArrayXXf arr, arr_ref; + arr = arr_ref = ArrayXXf::Constant(5, 3, 0.5); + multiply_assign_using_evaluator(arr, arr_const); + arr_ref *= arr_const; + VERIFY_IS_APPROX(arr, arr_ref); + + divide_assign_using_evaluator(arr.row(1), arr.row(2) + 1); + arr_ref.row(1) /= (arr_ref.row(2) + 1); + VERIFY_IS_APPROX(arr, arr_ref); + } + + { + // test triangular shapes + MatrixXd A = MatrixXd::Random(6,6), B(6,6), C(6,6), D(6,6); + A.setRandom();B.setRandom(); + VERIFY_IS_APPROX_EVALUATOR2(B, A.triangularView(), MatrixXd(A.triangularView())); + + A.setRandom();B.setRandom(); + VERIFY_IS_APPROX_EVALUATOR2(B, A.triangularView(), MatrixXd(A.triangularView())); + + A.setRandom();B.setRandom(); + VERIFY_IS_APPROX_EVALUATOR2(B, A.triangularView(), MatrixXd(A.triangularView())); + + A.setRandom();B.setRandom(); + C = B; C.triangularView() = A; + copy_using_evaluator(B.triangularView(), A); + VERIFY(B.isApprox(C) && "copy_using_evaluator(B.triangularView(), A)"); + + A.setRandom();B.setRandom(); + C = B; C.triangularView() = A.triangularView(); + copy_using_evaluator(B.triangularView(), A.triangularView()); + VERIFY(B.isApprox(C) && "copy_using_evaluator(B.triangularView(), A.triangularView())"); + + + A.setRandom();B.setRandom(); + C = B; C.triangularView() = A.triangularView().transpose(); + copy_using_evaluator(B.triangularView(), A.triangularView().transpose()); + VERIFY(B.isApprox(C) && "copy_using_evaluator(B.triangularView(), A.triangularView().transpose())"); + + + A.setRandom();B.setRandom(); C = B; D = A; + C.triangularView().swap(D.triangularView()); + swap_using_evaluator(B.triangularView(), A.triangularView()); + VERIFY(B.isApprox(C) && "swap_using_evaluator(B.triangularView(), A.triangularView())"); + + + VERIFY_IS_APPROX_EVALUATOR2(B, prod(A.triangularView(),A), MatrixXd(A.triangularView()*A)); + + VERIFY_IS_APPROX_EVALUATOR2(B, prod(A.selfadjointView(),A), MatrixXd(A.selfadjointView()*A)); + } + + { + // test diagonal shapes + VectorXd d = VectorXd::Random(6); + MatrixXd A = MatrixXd::Random(6,6), B(6,6); + A.setRandom();B.setRandom(); + + VERIFY_IS_APPROX_EVALUATOR2(B, lazyprod(d.asDiagonal(),A), MatrixXd(d.asDiagonal()*A)); + VERIFY_IS_APPROX_EVALUATOR2(B, lazyprod(A,d.asDiagonal()), MatrixXd(A*d.asDiagonal())); + } + + { + // test CoeffReadCost + Matrix4d a, b; + VERIFY_IS_EQUAL( get_cost(a), 1 ); + VERIFY_IS_EQUAL( get_cost(a+b), 3); + VERIFY_IS_EQUAL( get_cost(2*a+b), 4); + VERIFY_IS_EQUAL( get_cost(a*b), 1); + VERIFY_IS_EQUAL( get_cost(a.lazyProduct(b)), 15); + VERIFY_IS_EQUAL( get_cost(a*(a*b)), 1); + VERIFY_IS_EQUAL( get_cost(a.lazyProduct(a*b)), 15); + VERIFY_IS_EQUAL( get_cost(a*(a+b)), 1); + VERIFY_IS_EQUAL( get_cost(a.lazyProduct(a+b)), 15); + } +} diff --git a/ground/gcs/src/libs/eigen/test/fastmath.cpp b/ground/gcs/src/libs/eigen/test/fastmath.cpp new file mode 100644 index 0000000000..cc5db07463 --- /dev/null +++ b/ground/gcs/src/libs/eigen/test/fastmath.cpp @@ -0,0 +1,99 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2015 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "main.h" + +void check(bool b, bool ref) +{ + std::cout << b; + if(b==ref) + std::cout << " OK "; + else + std::cout << " BAD "; +} + +#if EIGEN_COMP_MSVC && EIGEN_COMP_MSVC < 1800 +namespace std { + template bool (isfinite)(T x) { return _finite(x); } + template bool (isnan)(T x) { return _isnan(x); } + template bool (isinf)(T x) { return _fpclass(x)==_FPCLASS_NINF || _fpclass(x)==_FPCLASS_PINF; } +} +#endif + +template +void check_inf_nan(bool dryrun) { + Matrix m(10); + m.setRandom(); + m(3) = std::numeric_limits::quiet_NaN(); + + if(dryrun) + { + std::cout << "std::isfinite(" << m(3) << ") = "; check((std::isfinite)(m(3)),false); std::cout << " ; numext::isfinite = "; check((numext::isfinite)(m(3)), false); std::cout << "\n"; + std::cout << "std::isinf(" << m(3) << ") = "; check((std::isinf)(m(3)),false); std::cout << " ; numext::isinf = "; check((numext::isinf)(m(3)), false); std::cout << "\n"; + std::cout << "std::isnan(" << m(3) << ") = "; check((std::isnan)(m(3)),true); std::cout << " ; numext::isnan = "; check((numext::isnan)(m(3)), true); std::cout << "\n"; + std::cout << "allFinite: "; check(m.allFinite(), 0); std::cout << "\n"; + std::cout << "hasNaN: "; check(m.hasNaN(), 1); std::cout << "\n"; + std::cout << "\n"; + } + else + { + VERIFY( !(numext::isfinite)(m(3)) ); + VERIFY( !(numext::isinf)(m(3)) ); + VERIFY( (numext::isnan)(m(3)) ); + VERIFY( !m.allFinite() ); + VERIFY( m.hasNaN() ); + } + T hidden_zero = (std::numeric_limits::min)()*(std::numeric_limits::min)(); + m(4) /= hidden_zero; + if(dryrun) + { + std::cout << "std::isfinite(" << m(4) << ") = "; check((std::isfinite)(m(4)),false); std::cout << " ; numext::isfinite = "; check((numext::isfinite)(m(4)), false); std::cout << "\n"; + std::cout << "std::isinf(" << m(4) << ") = "; check((std::isinf)(m(4)),true); std::cout << " ; numext::isinf = "; check((numext::isinf)(m(4)), true); std::cout << "\n"; + std::cout << "std::isnan(" << m(4) << ") = "; check((std::isnan)(m(4)),false); std::cout << " ; numext::isnan = "; check((numext::isnan)(m(4)), false); std::cout << "\n"; + std::cout << "allFinite: "; check(m.allFinite(), 0); std::cout << "\n"; + std::cout << "hasNaN: "; check(m.hasNaN(), 1); std::cout << "\n"; + std::cout << "\n"; + } + else + { + VERIFY( !(numext::isfinite)(m(4)) ); + VERIFY( (numext::isinf)(m(4)) ); + VERIFY( !(numext::isnan)(m(4)) ); + VERIFY( !m.allFinite() ); + VERIFY( m.hasNaN() ); + } + m(3) = 0; + if(dryrun) + { + std::cout << "std::isfinite(" << m(3) << ") = "; check((std::isfinite)(m(3)),true); std::cout << " ; numext::isfinite = "; check((numext::isfinite)(m(3)), true); std::cout << "\n"; + std::cout << "std::isinf(" << m(3) << ") = "; check((std::isinf)(m(3)),false); std::cout << " ; numext::isinf = "; check((numext::isinf)(m(3)), false); std::cout << "\n"; + std::cout << "std::isnan(" << m(3) << ") = "; check((std::isnan)(m(3)),false); std::cout << " ; numext::isnan = "; check((numext::isnan)(m(3)), false); std::cout << "\n"; + std::cout << "allFinite: "; check(m.allFinite(), 0); std::cout << "\n"; + std::cout << "hasNaN: "; check(m.hasNaN(), 0); std::cout << "\n"; + std::cout << "\n\n"; + } + else + { + VERIFY( (numext::isfinite)(m(3)) ); + VERIFY( !(numext::isinf)(m(3)) ); + VERIFY( !(numext::isnan)(m(3)) ); + VERIFY( !m.allFinite() ); + VERIFY( !m.hasNaN() ); + } +} + +void test_fastmath() { + std::cout << "*** float *** \n\n"; check_inf_nan(true); + std::cout << "*** double ***\n\n"; check_inf_nan(true); + std::cout << "*** long double *** \n\n"; check_inf_nan(true); + + check_inf_nan(false); + check_inf_nan(false); + check_inf_nan(false); +} diff --git a/ground/gcs/src/libs/eigen/test/first_aligned.cpp b/ground/gcs/src/libs/eigen/test/first_aligned.cpp index 467f945100..ae2d4bc424 100644 --- a/ground/gcs/src/libs/eigen/test/first_aligned.cpp +++ b/ground/gcs/src/libs/eigen/test/first_aligned.cpp @@ -13,7 +13,7 @@ template void test_first_aligned_helper(Scalar *array, int size) { const int packet_size = sizeof(Scalar) * internal::packet_traits::size; - VERIFY(((size_t(array) + sizeof(Scalar) * internal::first_aligned(array, size)) % packet_size) == 0); + VERIFY(((size_t(array) + sizeof(Scalar) * internal::first_default_aligned(array, size)) % packet_size) == 0); } template @@ -21,7 +21,7 @@ void test_none_aligned_helper(Scalar *array, int size) { EIGEN_UNUSED_VARIABLE(array); EIGEN_UNUSED_VARIABLE(size); - VERIFY(internal::packet_traits::size == 1 || internal::first_aligned(array, size) == size); + VERIFY(internal::packet_traits::size == 1 || internal::first_default_aligned(array, size) == size); } struct some_non_vectorizable_type { float x; }; @@ -41,7 +41,7 @@ void test_first_aligned() test_first_aligned_helper(array_double+1, 50); test_first_aligned_helper(array_double+2, 50); - double *array_double_plus_4_bytes = (double*)(size_t(array_double)+4); + double *array_double_plus_4_bytes = (double*)(internal::UIntPtr(array_double)+4); test_none_aligned_helper(array_double_plus_4_bytes, 50); test_none_aligned_helper(array_double_plus_4_bytes+1, 50); diff --git a/ground/gcs/src/libs/eigen/test/geo_alignedbox.cpp b/ground/gcs/src/libs/eigen/test/geo_alignedbox.cpp index 84663ad1f4..d2339a6511 100644 --- a/ground/gcs/src/libs/eigen/test/geo_alignedbox.cpp +++ b/ground/gcs/src/libs/eigen/test/geo_alignedbox.cpp @@ -16,7 +16,7 @@ using namespace std; template EIGEN_DONT_INLINE -void kill_extra_precision(T& x) { eigen_assert(&x != 0); } +void kill_extra_precision(T& x) { eigen_assert((void*)(&x) != (void*)0); } template void alignedbox(const BoxType& _box) @@ -48,12 +48,21 @@ template void alignedbox(const BoxType& _box) b0.extend(p0); b0.extend(p1); VERIFY(b0.contains(p0*s1+(Scalar(1)-s1)*p1)); + VERIFY(b0.contains(b0.center())); + VERIFY_IS_APPROX(b0.center(),(p0+p1)/Scalar(2)); (b2 = b0).extend(b1); VERIFY(b2.contains(b0)); VERIFY(b2.contains(b1)); VERIFY_IS_APPROX(b2.clamp(b0), b0); + // intersection + BoxType box1(VectorType::Random(dim)); + box1.extend(VectorType::Random(dim)); + BoxType box2(VectorType::Random(dim)); + box2.extend(VectorType::Random(dim)); + + VERIFY(box1.intersects(box2) == !box1.intersection(box2).isEmpty()); // alignment -- make sure there is no memory alignment assertion BoxType *bp0 = new BoxType(dim); diff --git a/ground/gcs/src/libs/eigen/test/geo_eulerangles.cpp b/ground/gcs/src/libs/eigen/test/geo_eulerangles.cpp index b4830bd41f..932ebe7732 100644 --- a/ground/gcs/src/libs/eigen/test/geo_eulerangles.cpp +++ b/ground/gcs/src/libs/eigen/test/geo_eulerangles.cpp @@ -26,16 +26,16 @@ void verify_euler(const Matrix& ea, int i, int j, int k) VERIFY_IS_APPROX(m, mbis); /* If I==K, and ea[1]==0, then there no unique solution. */ /* The remark apply in the case where I!=K, and |ea[1]| is close to pi/2. */ - if( (i!=k || ea[1]!=0) && (i==k || !internal::isApprox(abs(ea[1]),Scalar(M_PI/2),test_precision())) ) + if( (i!=k || ea[1]!=0) && (i==k || !internal::isApprox(abs(ea[1]),Scalar(EIGEN_PI/2),test_precision())) ) VERIFY((ea-eabis).norm() <= test_precision()); // approx_or_less_than does not work for 0 VERIFY(0 < eabis[0] || test_isMuchSmallerThan(eabis[0], Scalar(1))); - VERIFY_IS_APPROX_OR_LESS_THAN(eabis[0], Scalar(M_PI)); - VERIFY_IS_APPROX_OR_LESS_THAN(-Scalar(M_PI), eabis[1]); - VERIFY_IS_APPROX_OR_LESS_THAN(eabis[1], Scalar(M_PI)); - VERIFY_IS_APPROX_OR_LESS_THAN(-Scalar(M_PI), eabis[2]); - VERIFY_IS_APPROX_OR_LESS_THAN(eabis[2], Scalar(M_PI)); + VERIFY_IS_APPROX_OR_LESS_THAN(eabis[0], Scalar(EIGEN_PI)); + VERIFY_IS_APPROX_OR_LESS_THAN(-Scalar(EIGEN_PI), eabis[1]); + VERIFY_IS_APPROX_OR_LESS_THAN(eabis[1], Scalar(EIGEN_PI)); + VERIFY_IS_APPROX_OR_LESS_THAN(-Scalar(EIGEN_PI), eabis[2]); + VERIFY_IS_APPROX_OR_LESS_THAN(eabis[2], Scalar(EIGEN_PI)); } template void check_all_var(const Matrix& ea) @@ -64,7 +64,7 @@ template void eulerangles() typedef Quaternion Quaternionx; typedef AngleAxis AngleAxisx; - Scalar a = internal::random(-Scalar(M_PI), Scalar(M_PI)); + Scalar a = internal::random(-Scalar(EIGEN_PI), Scalar(EIGEN_PI)); Quaternionx q1; q1 = AngleAxisx(a, Vector3::Random().normalized()); Matrix3 m; @@ -84,13 +84,13 @@ template void eulerangles() check_all_var(ea); // Check with random angles in range [0:pi]x[-pi:pi]x[-pi:pi]. - ea = (Array3::Random() + Array3(1,0,0))*Scalar(M_PI)*Array3(0.5,1,1); + ea = (Array3::Random() + Array3(1,0,0))*Scalar(EIGEN_PI)*Array3(0.5,1,1); check_all_var(ea); - ea[2] = ea[0] = internal::random(0,Scalar(M_PI)); + ea[2] = ea[0] = internal::random(0,Scalar(EIGEN_PI)); check_all_var(ea); - ea[0] = ea[1] = internal::random(0,Scalar(M_PI)); + ea[0] = ea[1] = internal::random(0,Scalar(EIGEN_PI)); check_all_var(ea); ea[1] = 0; diff --git a/ground/gcs/src/libs/eigen/test/geo_homogeneous.cpp b/ground/gcs/src/libs/eigen/test/geo_homogeneous.cpp index c91bde819c..2187c7bf98 100644 --- a/ground/gcs/src/libs/eigen/test/geo_homogeneous.cpp +++ b/ground/gcs/src/libs/eigen/test/geo_homogeneous.cpp @@ -38,6 +38,10 @@ template void homogeneous(void) hv0 << v0, 1; VERIFY_IS_APPROX(v0.homogeneous(), hv0); VERIFY_IS_APPROX(v0, hv0.hnormalized()); + + VERIFY_IS_APPROX(v0.homogeneous().sum(), hv0.sum()); + VERIFY_IS_APPROX(v0.homogeneous().minCoeff(), hv0.minCoeff()); + VERIFY_IS_APPROX(v0.homogeneous().maxCoeff(), hv0.maxCoeff()); hm0 << m0, ones.transpose(); VERIFY_IS_APPROX(m0.colwise().homogeneous(), hm0); @@ -54,10 +58,11 @@ template void homogeneous(void) T2MatrixType t2 = T2MatrixType::Random(); VERIFY_IS_APPROX(t2 * (v0.homogeneous().eval()), t2 * v0.homogeneous()); VERIFY_IS_APPROX(t2 * (m0.colwise().homogeneous().eval()), t2 * m0.colwise().homogeneous()); + VERIFY_IS_APPROX(t2 * (v0.homogeneous().asDiagonal()), t2 * hv0.asDiagonal()); + VERIFY_IS_APPROX((v0.homogeneous().asDiagonal()) * t2, hv0.asDiagonal() * t2); VERIFY_IS_APPROX((v0.transpose().rowwise().homogeneous().eval()) * t2, v0.transpose().rowwise().homogeneous() * t2); - m0.transpose().rowwise().homogeneous().eval(); VERIFY_IS_APPROX((m0.transpose().rowwise().homogeneous().eval()) * t2, m0.transpose().rowwise().homogeneous() * t2); @@ -82,7 +87,7 @@ template void homogeneous(void) VERIFY_IS_APPROX(aff * pts.colwise().homogeneous(), (aff * pts1).colwise().hnormalized()); VERIFY_IS_APPROX(caff * pts.colwise().homogeneous(), (caff * pts1).colwise().hnormalized()); VERIFY_IS_APPROX(proj * pts.colwise().homogeneous(), (proj * pts1)); - + VERIFY_IS_APPROX((aff * pts1).colwise().hnormalized(), aff * pts); VERIFY_IS_APPROX((caff * pts1).colwise().hnormalized(), caff * pts); @@ -91,6 +96,23 @@ template void homogeneous(void) VERIFY_IS_APPROX((aff * pts2).colwise().hnormalized(), aff * pts2.colwise().hnormalized()); VERIFY_IS_APPROX((caff * pts2).colwise().hnormalized(), caff * pts2.colwise().hnormalized()); VERIFY_IS_APPROX((proj * pts2).colwise().hnormalized(), (proj * pts2.colwise().hnormalized().colwise().homogeneous()).colwise().hnormalized()); + + // Test combination of homogeneous + + VERIFY_IS_APPROX( (t2 * v0.homogeneous()).hnormalized(), + (t2.template topLeftCorner() * v0 + t2.template topRightCorner()) + / ((t2.template bottomLeftCorner<1,Size>()*v0).value() + t2(Size,Size)) ); + + VERIFY_IS_APPROX( (t2 * pts.colwise().homogeneous()).colwise().hnormalized(), + (Matrix(t2 * pts1).colwise().hnormalized()) ); + + VERIFY_IS_APPROX( (t2 .lazyProduct( v0.homogeneous() )).hnormalized(), (t2 * v0.homogeneous()).hnormalized() ); + VERIFY_IS_APPROX( (t2 .lazyProduct ( pts.colwise().homogeneous() )).colwise().hnormalized(), (t2 * pts1).colwise().hnormalized() ); + + VERIFY_IS_APPROX( (v0.transpose().homogeneous() .lazyProduct( t2 )).hnormalized(), (v0.transpose().homogeneous()*t2).hnormalized() ); + VERIFY_IS_APPROX( (pts.transpose().rowwise().homogeneous() .lazyProduct( t2 )).rowwise().hnormalized(), (pts1.transpose()*t2).rowwise().hnormalized() ); + + VERIFY_IS_APPROX( (t2.template triangularView() * v0.homogeneous()).eval(), (t2.template triangularView()*hv0) ); } void test_geo_homogeneous() diff --git a/ground/gcs/src/libs/eigen/test/geo_hyperplane.cpp b/ground/gcs/src/libs/eigen/test/geo_hyperplane.cpp index 3275378011..27892850da 100644 --- a/ground/gcs/src/libs/eigen/test/geo_hyperplane.cpp +++ b/ground/gcs/src/libs/eigen/test/geo_hyperplane.cpp @@ -18,10 +18,12 @@ template void hyperplane(const HyperplaneType& _plane) /* this test covers the following files: Hyperplane.h */ + using std::abs; typedef typename HyperplaneType::Index Index; const Index dim = _plane.dim(); enum { Options = HyperplaneType::Options }; typedef typename HyperplaneType::Scalar Scalar; + typedef typename HyperplaneType::RealScalar RealScalar; typedef Matrix VectorType; typedef Matrix MatrixType; @@ -42,7 +44,10 @@ template void hyperplane(const HyperplaneType& _plane) VERIFY_IS_APPROX( n1.dot(n1), Scalar(1) ); VERIFY_IS_MUCH_SMALLER_THAN( pl0.absDistance(p0), Scalar(1) ); - VERIFY_IS_APPROX( pl1.signedDistance(p1 + n1 * s0), s0 ); + if(numext::abs2(s0)>RealScalar(1e-6)) + VERIFY_IS_APPROX( pl1.signedDistance(p1 + n1 * s0), s0); + else + VERIFY_IS_MUCH_SMALLER_THAN( abs(pl1.signedDistance(p1 + n1 * s0) - s0), Scalar(1) ); VERIFY_IS_MUCH_SMALLER_THAN( pl1.signedDistance(pl1.projection(p0)), Scalar(1) ); VERIFY_IS_MUCH_SMALLER_THAN( pl1.absDistance(p1 + pl1.normal().unitOrthogonal() * s1), Scalar(1) ); @@ -52,6 +57,8 @@ template void hyperplane(const HyperplaneType& _plane) MatrixType rot = MatrixType::Random(dim,dim).householderQr().householderQ(); DiagonalMatrix scaling(VectorType::Random()); Translation translation(VectorType::Random()); + + while(scaling.diagonal().cwiseAbs().minCoeff() void hyperplane(const HyperplaneType& _plane) VERIFY_IS_MUCH_SMALLER_THAN( pl2.transform(rot,Isometry).absDistance(rot * p1), Scalar(1) ); pl2 = pl1; VERIFY_IS_MUCH_SMALLER_THAN( pl2.transform(rot*scaling).absDistance((rot*scaling) * p1), Scalar(1) ); + VERIFY_IS_APPROX( pl2.normal().norm(), RealScalar(1) ); pl2 = pl1; VERIFY_IS_MUCH_SMALLER_THAN( pl2.transform(rot*scaling*translation) - .absDistance((rot*scaling*translation) * p1), Scalar(1) ); + .absDistance((rot*scaling*translation) * p1), Scalar(1) ); + VERIFY_IS_APPROX( pl2.normal().norm(), RealScalar(1) ); pl2 = pl1; VERIFY_IS_MUCH_SMALLER_THAN( pl2.transform(rot*translation,Isometry) .absDistance((rot*translation) * p1), Scalar(1) ); + VERIFY_IS_APPROX( pl2.normal().norm(), RealScalar(1) ); } // casting @@ -90,9 +100,9 @@ template void lines() Vector u = Vector::Random(); Vector v = Vector::Random(); Scalar a = internal::random(); - while (abs(a-1) < 1e-4) a = internal::random(); - while (u.norm() < 1e-4) u = Vector::Random(); - while (v.norm() < 1e-4) v = Vector::Random(); + while (abs(a-1) < Scalar(1e-4)) a = internal::random(); + while (u.norm() < Scalar(1e-4)) u = Vector::Random(); + while (v.norm() < Scalar(1e-4)) v = Vector::Random(); HLine line_u = HLine::Through(center + u, center + a*u); HLine line_v = HLine::Through(center + v, center + a*v); @@ -104,12 +114,15 @@ template void lines() Vector result = line_u.intersection(line_v); // the lines should intersect at the point we called "center" - VERIFY_IS_APPROX(result, center); + if(abs(a-1) > Scalar(1e-2) && abs(v.normalized().dot(u.normalized())) void hyperplane_alignment() typedef Hyperplane Plane3a; typedef Hyperplane Plane3u; - EIGEN_ALIGN16 Scalar array1[4]; - EIGEN_ALIGN16 Scalar array2[4]; - EIGEN_ALIGN16 Scalar array3[4+1]; + EIGEN_ALIGN_MAX Scalar array1[4]; + EIGEN_ALIGN_MAX Scalar array2[4]; + EIGEN_ALIGN_MAX Scalar array3[4+1]; Scalar* array3u = array3+1; Plane3a *p1 = ::new(reinterpret_cast(array1)) Plane3a; @@ -161,8 +174,8 @@ template void hyperplane_alignment() VERIFY_IS_APPROX(p1->coeffs(), p2->coeffs()); VERIFY_IS_APPROX(p1->coeffs(), p3->coeffs()); - #if defined(EIGEN_VECTORIZE) && EIGEN_ALIGN_STATICALLY - if(internal::packet_traits::Vectorizable) + #if defined(EIGEN_VECTORIZE) && EIGEN_MAX_STATIC_ALIGN_BYTES > 0 + if(internal::packet_traits::Vectorizable && internal::packet_traits::size<=4) VERIFY_RAISES_ASSERT((::new(reinterpret_cast(array3u)) Plane3a)); #endif } diff --git a/ground/gcs/src/libs/eigen/test/geo_orthomethods.cpp b/ground/gcs/src/libs/eigen/test/geo_orthomethods.cpp index c836dae40c..e178df2575 100644 --- a/ground/gcs/src/libs/eigen/test/geo_orthomethods.cpp +++ b/ground/gcs/src/libs/eigen/test/geo_orthomethods.cpp @@ -33,12 +33,16 @@ template void orthomethods_3() VERIFY_IS_MUCH_SMALLER_THAN(v1.dot(v1.cross(v2)), Scalar(1)); VERIFY_IS_MUCH_SMALLER_THAN(v1.cross(v2).dot(v2), Scalar(1)); VERIFY_IS_MUCH_SMALLER_THAN(v2.dot(v1.cross(v2)), Scalar(1)); + VERIFY_IS_MUCH_SMALLER_THAN(v1.cross(Vector3::Random()).dot(v1), Scalar(1)); Matrix3 mat3; mat3 << v0.normalized(), (v0.cross(v1)).normalized(), (v0.cross(v1).cross(v0)).normalized(); VERIFY(mat3.isUnitary()); - + + mat3.setRandom(); + VERIFY_IS_APPROX(v0.cross(mat3*v1), -(mat3*v1).cross(v0)); + VERIFY_IS_APPROX(v0.cross(mat3.lazyProduct(v1)), -(mat3.lazyProduct(v1)).cross(v0)); // colwise/rowwise cross product mat3.setRandom(); @@ -47,6 +51,13 @@ template void orthomethods_3() int i = internal::random(0,2); mcross = mat3.colwise().cross(vec3); VERIFY_IS_APPROX(mcross.col(i), mat3.col(i).cross(vec3)); + + VERIFY_IS_MUCH_SMALLER_THAN((mat3.adjoint() * mat3.colwise().cross(vec3)).diagonal().cwiseAbs().sum(), Scalar(1)); + VERIFY_IS_MUCH_SMALLER_THAN((mat3.adjoint() * mat3.colwise().cross(Vector3::Random())).diagonal().cwiseAbs().sum(), Scalar(1)); + + VERIFY_IS_MUCH_SMALLER_THAN((vec3.adjoint() * mat3.colwise().cross(vec3)).cwiseAbs().sum(), Scalar(1)); + VERIFY_IS_MUCH_SMALLER_THAN((vec3.adjoint() * Matrix3::Random().colwise().cross(vec3)).cwiseAbs().sum(), Scalar(1)); + mcross = mat3.rowwise().cross(vec3); VERIFY_IS_APPROX(mcross.row(i), mat3.row(i).cross(vec3)); @@ -57,6 +68,7 @@ template void orthomethods_3() v40.w() = v41.w() = v42.w() = 0; v42.template head<3>() = v40.template head<3>().cross(v41.template head<3>()); VERIFY_IS_APPROX(v40.cross3(v41), v42); + VERIFY_IS_MUCH_SMALLER_THAN(v40.cross3(Vector4::Random()).dot(v40), Scalar(1)); // check mixed product typedef Matrix RealVector3; diff --git a/ground/gcs/src/libs/eigen/test/geo_parametrizedline.cpp b/ground/gcs/src/libs/eigen/test/geo_parametrizedline.cpp index f0462d40ad..9bf5f3c1d5 100644 --- a/ground/gcs/src/libs/eigen/test/geo_parametrizedline.cpp +++ b/ground/gcs/src/libs/eigen/test/geo_parametrizedline.cpp @@ -66,9 +66,9 @@ template void parametrizedline_alignment() typedef ParametrizedLine Line4a; typedef ParametrizedLine Line4u; - EIGEN_ALIGN16 Scalar array1[8]; - EIGEN_ALIGN16 Scalar array2[8]; - EIGEN_ALIGN16 Scalar array3[8+1]; + EIGEN_ALIGN_MAX Scalar array1[16]; + EIGEN_ALIGN_MAX Scalar array2[16]; + EIGEN_ALIGN_MAX Scalar array3[16+1]; Scalar* array3u = array3+1; Line4a *p1 = ::new(reinterpret_cast(array1)) Line4a; @@ -85,8 +85,8 @@ template void parametrizedline_alignment() VERIFY_IS_APPROX(p1->direction(), p2->direction()); VERIFY_IS_APPROX(p1->direction(), p3->direction()); - #if defined(EIGEN_VECTORIZE) && EIGEN_ALIGN_STATICALLY - if(internal::packet_traits::Vectorizable) + #if defined(EIGEN_VECTORIZE) && EIGEN_MAX_STATIC_ALIGN_BYTES>0 + if(internal::packet_traits::Vectorizable && internal::packet_traits::size<=4) VERIFY_RAISES_ASSERT((::new(reinterpret_cast(array3u)) Line4a)); #endif } diff --git a/ground/gcs/src/libs/eigen/test/geo_quaternion.cpp b/ground/gcs/src/libs/eigen/test/geo_quaternion.cpp index 1694b32c7b..96889e7220 100644 --- a/ground/gcs/src/libs/eigen/test/geo_quaternion.cpp +++ b/ground/gcs/src/libs/eigen/test/geo_quaternion.cpp @@ -30,8 +30,8 @@ template void check_slerp(const QuatType& q0, const QuatType& Scalar largeEps = test_precision(); Scalar theta_tot = AA(q1*q0.inverse()).angle(); - if(theta_tot>M_PI) - theta_tot = Scalar(2.*M_PI)-theta_tot; + if(theta_tot>Scalar(EIGEN_PI)) + theta_tot = Scalar(2.)*Scalar(EIGEN_PI)-theta_tot; for(Scalar t=0; t<=Scalar(1.001); t+=Scalar(0.1)) { QuatType q = q0.slerp(t,q1); @@ -49,13 +49,13 @@ template void quaternion(void) */ using std::abs; typedef Matrix Vector3; - typedef Matrix Vector4; + typedef Matrix Matrix3; typedef Quaternion Quaternionx; typedef AngleAxis AngleAxisx; Scalar largeEps = test_precision(); if (internal::is_same::value) - largeEps = 1e-3f; + largeEps = Scalar(1e-3); Scalar eps = internal::random() * Scalar(1e-2); @@ -64,8 +64,8 @@ template void quaternion(void) v2 = Vector3::Random(), v3 = Vector3::Random(); - Scalar a = internal::random(-Scalar(M_PI), Scalar(M_PI)), - b = internal::random(-Scalar(M_PI), Scalar(M_PI)); + Scalar a = internal::random(-Scalar(EIGEN_PI), Scalar(EIGEN_PI)), + b = internal::random(-Scalar(EIGEN_PI), Scalar(EIGEN_PI)); // Quaternion: Identity(), setIdentity(); Quaternionx q1, q2; @@ -82,8 +82,8 @@ template void quaternion(void) // angular distance Scalar refangle = abs(AngleAxisx(q1.inverse()*q2).angle()); - if (refangle>Scalar(M_PI)) - refangle = Scalar(2)*Scalar(M_PI) - refangle; + if (refangle>Scalar(EIGEN_PI)) + refangle = Scalar(2)*Scalar(EIGEN_PI) - refangle; if((q1.coeffs()-q2.coeffs()).norm() > 10*largeEps) { @@ -101,6 +101,11 @@ template void quaternion(void) q2 = q1.toRotationMatrix(); VERIFY_IS_APPROX(q1*v1,q2*v1); + Matrix3 rot1(q1); + VERIFY_IS_APPROX(q1*v1,rot1*v1); + Quaternionx q3(rot1.transpose()*rot1); + VERIFY_IS_APPROX(q3*v1,v1); + // angle-axis conversion AngleAxisx aa = AngleAxisx(q1); @@ -109,8 +114,8 @@ template void quaternion(void) // Do not execute the test if the rotation angle is almost zero, or // the rotation axis and v1 are almost parallel. if (abs(aa.angle()) > 5*test_precision() - && (aa.axis() - v1.normalized()).norm() < 1.99 - && (aa.axis() + v1.normalized()).norm() < 1.99) + && (aa.axis() - v1.normalized()).norm() < Scalar(1.99) + && (aa.axis() + v1.normalized()).norm() < Scalar(1.99)) { VERIFY_IS_NOT_APPROX(q1 * v1, Quaternionx(AngleAxisx(aa.angle()*2,aa.axis())) * v1); } @@ -151,19 +156,19 @@ template void quaternion(void) Quaternionx *q = new Quaternionx; delete q; - q1 = AngleAxisx(a, v0.normalized()); - q2 = AngleAxisx(b, v1.normalized()); + q1 = Quaternionx::UnitRandom(); + q2 = Quaternionx::UnitRandom(); check_slerp(q1,q2); q1 = AngleAxisx(b, v1.normalized()); - q2 = AngleAxisx(b+Scalar(M_PI), v1.normalized()); + q2 = AngleAxisx(b+Scalar(EIGEN_PI), v1.normalized()); check_slerp(q1,q2); q1 = AngleAxisx(b, v1.normalized()); q2 = AngleAxisx(-b, -v1.normalized()); check_slerp(q1,q2); - q1.coeffs() = Vector4::Random().normalized(); + q1 = Quaternionx::UnitRandom(); q2.coeffs() = -q1.coeffs(); check_slerp(q1,q2); } @@ -179,11 +184,11 @@ template void mapQuaternion(void){ Vector3 v0 = Vector3::Random(), v1 = Vector3::Random(); - Scalar a = internal::random(-Scalar(M_PI), Scalar(M_PI)); + Scalar a = internal::random(-Scalar(EIGEN_PI), Scalar(EIGEN_PI)); - EIGEN_ALIGN16 Scalar array1[4]; - EIGEN_ALIGN16 Scalar array2[4]; - EIGEN_ALIGN16 Scalar array3[4+1]; + EIGEN_ALIGN_MAX Scalar array1[4]; + EIGEN_ALIGN_MAX Scalar array2[4]; + EIGEN_ALIGN_MAX Scalar array3[4+1]; Scalar* array3unaligned = array3+1; MQuaternionA mq1(array1); @@ -232,9 +237,9 @@ template void quaternionAlignment(void){ typedef Quaternion QuaternionA; typedef Quaternion QuaternionUA; - EIGEN_ALIGN16 Scalar array1[4]; - EIGEN_ALIGN16 Scalar array2[4]; - EIGEN_ALIGN16 Scalar array3[4+1]; + EIGEN_ALIGN_MAX Scalar array1[4]; + EIGEN_ALIGN_MAX Scalar array2[4]; + EIGEN_ALIGN_MAX Scalar array3[4+1]; Scalar* arrayunaligned = array3+1; QuaternionA *q1 = ::new(reinterpret_cast(array1)) QuaternionA; @@ -247,8 +252,8 @@ template void quaternionAlignment(void){ VERIFY_IS_APPROX(q1->coeffs(), q2->coeffs()); VERIFY_IS_APPROX(q1->coeffs(), q3->coeffs()); - #if defined(EIGEN_VECTORIZE) && EIGEN_ALIGN_STATICALLY - if(internal::packet_traits::Vectorizable) + #if defined(EIGEN_VECTORIZE) && EIGEN_MAX_STATIC_ALIGN_BYTES>0 + if(internal::packet_traits::Vectorizable && internal::packet_traits::size<=4) VERIFY_RAISES_ASSERT((::new(reinterpret_cast(arrayunaligned)) QuaternionA)); #endif } diff --git a/ground/gcs/src/libs/eigen/test/geo_transformations.cpp b/ground/gcs/src/libs/eigen/test/geo_transformations.cpp index 5477657145..278e527c25 100644 --- a/ground/gcs/src/libs/eigen/test/geo_transformations.cpp +++ b/ground/gcs/src/libs/eigen/test/geo_transformations.cpp @@ -12,6 +12,17 @@ #include #include +template +Matrix angleToVec(T a) +{ + return Matrix(std::cos(a), std::sin(a)); +} + +// This permits to workaround a bug in clang/llvm code generation. +template +EIGEN_DONT_INLINE +void dont_over_optimize(T& x) { volatile typename T::Scalar tmp = x(0); x(0) = tmp; } + template void non_projective_only() { /* this test covers the following files: @@ -29,7 +40,7 @@ template void non_projective_only() Transform3 t0, t1, t2; - Scalar a = internal::random(-Scalar(M_PI), Scalar(M_PI)); + Scalar a = internal::random(-Scalar(EIGEN_PI), Scalar(EIGEN_PI)); Quaternionx q1, q2; @@ -97,16 +108,14 @@ template void transformations() v1 = Vector3::Random(); Matrix3 matrot1, m; - Scalar a = internal::random(-Scalar(M_PI), Scalar(M_PI)); - Scalar s0 = internal::random(), - s1 = internal::random(); + Scalar a = internal::random(-Scalar(EIGEN_PI), Scalar(EIGEN_PI)); + Scalar s0 = internal::random(), s1 = internal::random(); while(v0.norm() < test_precision()) v0 = Vector3::Random(); while(v1.norm() < test_precision()) v1 = Vector3::Random(); - VERIFY_IS_APPROX(v0, AngleAxisx(a, v0.normalized()) * v0); - VERIFY_IS_APPROX(-v0, AngleAxisx(Scalar(M_PI), v0.unitOrthogonal()) * v0); + VERIFY_IS_APPROX(-v0, AngleAxisx(Scalar(EIGEN_PI), v0.unitOrthogonal()) * v0); if(abs(cos(a)) > test_precision()) { VERIFY_IS_APPROX(cos(a)*v0.squaredNorm(), v0.dot(AngleAxisx(a, v0.unitOrthogonal()) * v0)); @@ -132,14 +141,16 @@ template void transformations() AngleAxisx aa = AngleAxisx(q1); VERIFY_IS_APPROX(q1 * v1, Quaternionx(aa) * v1); - if(abs(aa.angle()) > NumTraits::dummy_precision()) + // The following test is stable only if 2*angle != angle and v1 is not colinear with axis + if( (abs(aa.angle()) > test_precision()) && (abs(aa.axis().dot(v1.normalized()))<(Scalar(1)-Scalar(4)*test_precision())) ) { VERIFY( !(q1 * v1).isApprox(Quaternionx(AngleAxisx(aa.angle()*2,aa.axis())) * v1) ); } aa.fromRotationMatrix(aa.toRotationMatrix()); VERIFY_IS_APPROX(q1 * v1, Quaternionx(aa) * v1); - if(abs(aa.angle()) > NumTraits::dummy_precision()) + // The following test is stable only if 2*angle != angle and v1 is not colinear with axis + if( (abs(aa.angle()) > test_precision()) && (abs(aa.axis().dot(v1.normalized()))<(Scalar(1)-Scalar(4)*test_precision())) ) { VERIFY( !(q1 * v1).isApprox(Quaternionx(AngleAxisx(aa.angle()*2,aa.axis())) * v1) ); } @@ -158,7 +169,7 @@ template void transformations() // TODO complete the tests ! a = 0; while (abs(a)(-Scalar(0.4)*Scalar(M_PI), Scalar(0.4)*Scalar(M_PI)); + a = internal::random(-Scalar(0.4)*Scalar(EIGEN_PI), Scalar(0.4)*Scalar(EIGEN_PI)); q1 = AngleAxisx(a, v0.normalized()); Transform3 t0, t1, t2; @@ -204,7 +215,7 @@ template void transformations() tmat4.matrix()(3,3) = Scalar(1); VERIFY_IS_APPROX(tmat3.matrix(), tmat4.matrix()); - Scalar a3 = internal::random(-Scalar(M_PI), Scalar(M_PI)); + Scalar a3 = internal::random(-Scalar(EIGEN_PI), Scalar(EIGEN_PI)); Vector3 v3 = Vector3::Random().normalized(); AngleAxisx aa3(a3, v3); Transform3 t3(aa3); @@ -216,12 +227,15 @@ template void transformations() t4 *= aa3; VERIFY_IS_APPROX(t3.matrix(), t4.matrix()); - v3 = Vector3::Random(); + do { + v3 = Vector3::Random(); + dont_over_optimize(v3); + } while (v3.cwiseAbs().minCoeff()::epsilon()); Translation3 tv3(v3); Transform3 t5(tv3); t4 = tv3; VERIFY_IS_APPROX(t5.matrix(), t4.matrix()); - t4.translate(-v3); + t4.translate((-v3).eval()); VERIFY_IS_APPROX(t4.matrix(), MatrixType::Identity()); t4 *= tv3; VERIFY_IS_APPROX(t5.matrix(), t4.matrix()); @@ -320,6 +334,9 @@ template void transformations() t0.scale(v0); t1 *= AlignedScaling3(v0); VERIFY_IS_APPROX(t0.matrix(), t1.matrix()); + t1 = AlignedScaling3(v0) * (Translation3(v0) * Transform3(q1)); + t1 = t1 * v0.asDiagonal(); + VERIFY_IS_APPROX(t0.matrix(), t1.matrix()); // transformation * translation t0.translate(v0); t1 = t1 * Translation3(v0); @@ -410,12 +427,28 @@ template void transformations() VERIFY_IS_APPROX(r2d1f.template cast(),r2d1); Rotation2D r2d1d = r2d1.template cast(); VERIFY_IS_APPROX(r2d1d.template cast(),r2d1); - - t20 = Translation2(v20) * (Rotation2D(s0) * Eigen::Scaling(s0)); - t21 = Translation2(v20) * Rotation2D(s0) * Eigen::Scaling(s0); - VERIFY_IS_APPROX(t20,t21); + for(int k=0; k<100; ++k) + { + Scalar angle = internal::random(-100,100); + Rotation2D rot2(angle); + VERIFY( rot2.smallestPositiveAngle() >= 0 ); + VERIFY( rot2.smallestPositiveAngle() <= Scalar(2)*Scalar(EIGEN_PI) ); + VERIFY_IS_APPROX( angleToVec(rot2.smallestPositiveAngle()), angleToVec(rot2.angle()) ); + + VERIFY( rot2.smallestAngle() >= -Scalar(EIGEN_PI) ); + VERIFY( rot2.smallestAngle() <= Scalar(EIGEN_PI) ); + VERIFY_IS_APPROX( angleToVec(rot2.smallestAngle()), angleToVec(rot2.angle()) ); + + Matrix rot2_as_mat(rot2); + Rotation2D rot3(rot2_as_mat); + VERIFY_IS_APPROX( angleToVec(rot2.smallestAngle()), angleToVec(rot3.angle()) ); + } + + s0 = internal::random(-100,100); + s1 = internal::random(-100,100); Rotation2D R0(s0), R1(s1); + t20 = Translation2(v20) * (R0 * Eigen::Scaling(s0)); t21 = Translation2(v20) * R0 * Eigen::Scaling(s0); VERIFY_IS_APPROX(t20,t21); @@ -425,9 +458,24 @@ template void transformations() VERIFY_IS_APPROX(t20,t21); VERIFY_IS_APPROX(s0, (R0.slerp(0, R1)).angle()); - VERIFY_IS_APPROX(s1, (R0.slerp(1, R1)).angle()); - VERIFY_IS_APPROX(s0, (R0.slerp(0.5, R0)).angle()); - VERIFY_IS_APPROX(Scalar(0), (R0.slerp(0.5, R0.inverse())).angle()); + VERIFY_IS_APPROX( angleToVec(R1.smallestPositiveAngle()), angleToVec((R0.slerp(1, R1)).smallestPositiveAngle()) ); + VERIFY_IS_APPROX(R0.smallestPositiveAngle(), (R0.slerp(0.5, R0)).smallestPositiveAngle()); + + if(std::cos(s0)>0) + VERIFY_IS_MUCH_SMALLER_THAN((R0.slerp(0.5, R0.inverse())).smallestAngle(), Scalar(1)); + else + VERIFY_IS_APPROX(Scalar(EIGEN_PI), (R0.slerp(0.5, R0.inverse())).smallestPositiveAngle()); + + // Check path length + Scalar l = 0; + int path_steps = 100; + for(int k=0; k::epsilon()*Scalar(path_steps/2))); // check basic features { @@ -437,6 +485,79 @@ template void transformations() Rotation2D r2(r1); // copy ctor VERIFY_IS_APPROX(r2.angle(),s0); } + + { + Transform3 t32(Matrix4::Random()), t33, t34; + t34 = t33 = t32; + t32.scale(v0); + t33*=AlignedScaling3(v0); + VERIFY_IS_APPROX(t32.matrix(), t33.matrix()); + t33 = t34 * AlignedScaling3(v0); + VERIFY_IS_APPROX(t32.matrix(), t33.matrix()); + } + +} + +template +void transform_associativity_left(const A1& a1, const A2& a2, const P& p, const Q& q, const V& v, const H& h) +{ + VERIFY_IS_APPROX( q*(a1*v), (q*a1)*v ); + VERIFY_IS_APPROX( q*(a2*v), (q*a2)*v ); + VERIFY_IS_APPROX( q*(p*h).hnormalized(), ((q*p)*h).hnormalized() ); +} + +template +void transform_associativity2(const A1& a1, const A2& a2, const P& p, const Q& q, const V& v, const H& h) +{ + VERIFY_IS_APPROX( a1*(q*v), (a1*q)*v ); + VERIFY_IS_APPROX( a2*(q*v), (a2*q)*v ); + VERIFY_IS_APPROX( p *(q*v).homogeneous(), (p *q)*v.homogeneous() ); + + transform_associativity_left(a1, a2,p, q, v, h); +} + +template +void transform_associativity(const RotationType& R) +{ + typedef Matrix VectorType; + typedef Matrix HVectorType; + typedef Matrix LinearType; + typedef Matrix MatrixType; + typedef Transform AffineCompactType; + typedef Transform AffineType; + typedef Transform ProjectiveType; + typedef DiagonalMatrix ScalingType; + typedef Translation TranslationType; + + AffineCompactType A1c; A1c.matrix().setRandom(); + AffineCompactType A2c; A2c.matrix().setRandom(); + AffineType A1(A1c); + AffineType A2(A2c); + ProjectiveType P1; P1.matrix().setRandom(); + VectorType v1 = VectorType::Random(); + VectorType v2 = VectorType::Random(); + HVectorType h1 = HVectorType::Random(); + Scalar s1 = internal::random(); + LinearType L = LinearType::Random(); + MatrixType M = MatrixType::Random(); + + CALL_SUBTEST( transform_associativity2(A1c, A1, P1, A2, v2, h1) ); + CALL_SUBTEST( transform_associativity2(A1c, A1, P1, A2c, v2, h1) ); + CALL_SUBTEST( transform_associativity2(A1c, A1, P1, v1.asDiagonal(), v2, h1) ); + CALL_SUBTEST( transform_associativity2(A1c, A1, P1, ScalingType(v1), v2, h1) ); + CALL_SUBTEST( transform_associativity2(A1c, A1, P1, Scaling(v1), v2, h1) ); + CALL_SUBTEST( transform_associativity2(A1c, A1, P1, Scaling(s1), v2, h1) ); + CALL_SUBTEST( transform_associativity2(A1c, A1, P1, TranslationType(v1), v2, h1) ); + CALL_SUBTEST( transform_associativity_left(A1c, A1, P1, L, v2, h1) ); + CALL_SUBTEST( transform_associativity2(A1c, A1, P1, R, v2, h1) ); + + VERIFY_IS_APPROX( A1*(M*h1), (A1*M)*h1 ); + VERIFY_IS_APPROX( A1c*(M*h1), (A1c*M)*h1 ); + VERIFY_IS_APPROX( P1*(M*h1), (P1*M)*h1 ); + + VERIFY_IS_APPROX( M*(A1*h1), (M*A1)*h1 ); + VERIFY_IS_APPROX( M*(A1c*h1), (M*A1c)*h1 ); + VERIFY_IS_APPROX( M*(P1*h1), ((M*P1)*h1) ); } template void transform_alignment() @@ -444,9 +565,9 @@ template void transform_alignment() typedef Transform Projective3a; typedef Transform Projective3u; - EIGEN_ALIGN16 Scalar array1[16]; - EIGEN_ALIGN16 Scalar array2[16]; - EIGEN_ALIGN16 Scalar array3[16+1]; + EIGEN_ALIGN_MAX Scalar array1[16]; + EIGEN_ALIGN_MAX Scalar array2[16]; + EIGEN_ALIGN_MAX Scalar array3[16+1]; Scalar* array3u = array3+1; Projective3a *p1 = ::new(reinterpret_cast(array1)) Projective3a; @@ -462,7 +583,7 @@ template void transform_alignment() VERIFY_IS_APPROX( (*p1) * (*p1), (*p2)*(*p3)); - #if defined(EIGEN_VECTORIZE) && EIGEN_ALIGN_STATICALLY + #if defined(EIGEN_VECTORIZE) && EIGEN_MAX_STATIC_ALIGN_BYTES>0 if(internal::packet_traits::Vectorizable) VERIFY_RAISES_ASSERT((::new(reinterpret_cast(array3u)) Projective3a)); #endif @@ -517,5 +638,8 @@ void test_geo_transformations() CALL_SUBTEST_7(( transform_products() )); CALL_SUBTEST_7(( transform_products() )); + + CALL_SUBTEST_8(( transform_associativity(Rotation2D(internal::random()*double(EIGEN_PI))) )); + CALL_SUBTEST_8(( transform_associativity(Quaterniond::UnitRandom()) )); } } diff --git a/ground/gcs/src/libs/eigen/test/half_float.cpp b/ground/gcs/src/libs/eigen/test/half_float.cpp new file mode 100644 index 0000000000..f8d438e2fc --- /dev/null +++ b/ground/gcs/src/libs/eigen/test/half_float.cpp @@ -0,0 +1,252 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include + +#include "main.h" + +#include + +// Make sure it's possible to forward declare Eigen::half +namespace Eigen { +struct half; +} + +using Eigen::half; + +void test_conversion() +{ + using Eigen::half_impl::__half; + + // Conversion from float. + VERIFY_IS_EQUAL(half(1.0f).x, 0x3c00); + VERIFY_IS_EQUAL(half(0.5f).x, 0x3800); + VERIFY_IS_EQUAL(half(0.33333f).x, 0x3555); + VERIFY_IS_EQUAL(half(0.0f).x, 0x0000); + VERIFY_IS_EQUAL(half(-0.0f).x, 0x8000); + VERIFY_IS_EQUAL(half(65504.0f).x, 0x7bff); + VERIFY_IS_EQUAL(half(65536.0f).x, 0x7c00); // Becomes infinity. + + // Denormals. + VERIFY_IS_EQUAL(half(-5.96046e-08f).x, 0x8001); + VERIFY_IS_EQUAL(half(5.96046e-08f).x, 0x0001); + VERIFY_IS_EQUAL(half(1.19209e-07f).x, 0x0002); + + // Verify round-to-nearest-even behavior. + float val1 = float(half(__half(0x3c00))); + float val2 = float(half(__half(0x3c01))); + float val3 = float(half(__half(0x3c02))); + VERIFY_IS_EQUAL(half(0.5f * (val1 + val2)).x, 0x3c00); + VERIFY_IS_EQUAL(half(0.5f * (val2 + val3)).x, 0x3c02); + + // Conversion from int. + VERIFY_IS_EQUAL(half(-1).x, 0xbc00); + VERIFY_IS_EQUAL(half(0).x, 0x0000); + VERIFY_IS_EQUAL(half(1).x, 0x3c00); + VERIFY_IS_EQUAL(half(2).x, 0x4000); + VERIFY_IS_EQUAL(half(3).x, 0x4200); + + // Conversion from bool. + VERIFY_IS_EQUAL(half(false).x, 0x0000); + VERIFY_IS_EQUAL(half(true).x, 0x3c00); + + // Conversion to float. + VERIFY_IS_EQUAL(float(half(__half(0x0000))), 0.0f); + VERIFY_IS_EQUAL(float(half(__half(0x3c00))), 1.0f); + + // Denormals. + VERIFY_IS_APPROX(float(half(__half(0x8001))), -5.96046e-08f); + VERIFY_IS_APPROX(float(half(__half(0x0001))), 5.96046e-08f); + VERIFY_IS_APPROX(float(half(__half(0x0002))), 1.19209e-07f); + + // NaNs and infinities. + VERIFY(!(numext::isinf)(float(half(65504.0f)))); // Largest finite number. + VERIFY(!(numext::isnan)(float(half(0.0f)))); + VERIFY((numext::isinf)(float(half(__half(0xfc00))))); + VERIFY((numext::isnan)(float(half(__half(0xfc01))))); + VERIFY((numext::isinf)(float(half(__half(0x7c00))))); + VERIFY((numext::isnan)(float(half(__half(0x7c01))))); + +#if !EIGEN_COMP_MSVC + // Visual Studio errors out on divisions by 0 + VERIFY((numext::isnan)(float(half(0.0 / 0.0)))); + VERIFY((numext::isinf)(float(half(1.0 / 0.0)))); + VERIFY((numext::isinf)(float(half(-1.0 / 0.0)))); +#endif + + // Exactly same checks as above, just directly on the half representation. + VERIFY(!(numext::isinf)(half(__half(0x7bff)))); + VERIFY(!(numext::isnan)(half(__half(0x0000)))); + VERIFY((numext::isinf)(half(__half(0xfc00)))); + VERIFY((numext::isnan)(half(__half(0xfc01)))); + VERIFY((numext::isinf)(half(__half(0x7c00)))); + VERIFY((numext::isnan)(half(__half(0x7c01)))); + +#if !EIGEN_COMP_MSVC + // Visual Studio errors out on divisions by 0 + VERIFY((numext::isnan)(half(0.0 / 0.0))); + VERIFY((numext::isinf)(half(1.0 / 0.0))); + VERIFY((numext::isinf)(half(-1.0 / 0.0))); +#endif +} + +void test_numtraits() +{ + std::cout << "epsilon = " << NumTraits::epsilon() << std::endl; + std::cout << "highest = " << NumTraits::highest() << std::endl; + std::cout << "lowest = " << NumTraits::lowest() << std::endl; + std::cout << "inifinty = " << NumTraits::infinity() << std::endl; + std::cout << "nan = " << NumTraits::quiet_NaN() << std::endl; + +} + +void test_arithmetic() +{ + VERIFY_IS_EQUAL(float(half(2) + half(2)), 4); + VERIFY_IS_EQUAL(float(half(2) + half(-2)), 0); + VERIFY_IS_APPROX(float(half(0.33333f) + half(0.66667f)), 1.0f); + VERIFY_IS_EQUAL(float(half(2.0f) * half(-5.5f)), -11.0f); + VERIFY_IS_APPROX(float(half(1.0f) / half(3.0f)), 0.33333f); + VERIFY_IS_EQUAL(float(-half(4096.0f)), -4096.0f); + VERIFY_IS_EQUAL(float(-half(-4096.0f)), 4096.0f); +} + +void test_comparison() +{ + VERIFY(half(1.0f) > half(0.5f)); + VERIFY(half(0.5f) < half(1.0f)); + VERIFY(!(half(1.0f) < half(0.5f))); + VERIFY(!(half(0.5f) > half(1.0f))); + + VERIFY(!(half(4.0f) > half(4.0f))); + VERIFY(!(half(4.0f) < half(4.0f))); + + VERIFY(!(half(0.0f) < half(-0.0f))); + VERIFY(!(half(-0.0f) < half(0.0f))); + VERIFY(!(half(0.0f) > half(-0.0f))); + VERIFY(!(half(-0.0f) > half(0.0f))); + + VERIFY(half(0.2f) > half(-1.0f)); + VERIFY(half(-1.0f) < half(0.2f)); + VERIFY(half(-16.0f) < half(-15.0f)); + + VERIFY(half(1.0f) == half(1.0f)); + VERIFY(half(1.0f) != half(2.0f)); + + // Comparisons with NaNs and infinities. +#if !EIGEN_COMP_MSVC + // Visual Studio errors out on divisions by 0 + VERIFY(!(half(0.0 / 0.0) == half(0.0 / 0.0))); + VERIFY(half(0.0 / 0.0) != half(0.0 / 0.0)); + + VERIFY(!(half(1.0) == half(0.0 / 0.0))); + VERIFY(!(half(1.0) < half(0.0 / 0.0))); + VERIFY(!(half(1.0) > half(0.0 / 0.0))); + VERIFY(half(1.0) != half(0.0 / 0.0)); + + VERIFY(half(1.0) < half(1.0 / 0.0)); + VERIFY(half(1.0) > half(-1.0 / 0.0)); +#endif +} + +void test_basic_functions() +{ + VERIFY_IS_EQUAL(float(numext::abs(half(3.5f))), 3.5f); + VERIFY_IS_EQUAL(float(abs(half(3.5f))), 3.5f); + VERIFY_IS_EQUAL(float(numext::abs(half(-3.5f))), 3.5f); + VERIFY_IS_EQUAL(float(abs(half(-3.5f))), 3.5f); + + VERIFY_IS_EQUAL(float(numext::floor(half(3.5f))), 3.0f); + VERIFY_IS_EQUAL(float(floor(half(3.5f))), 3.0f); + VERIFY_IS_EQUAL(float(numext::floor(half(-3.5f))), -4.0f); + VERIFY_IS_EQUAL(float(floor(half(-3.5f))), -4.0f); + + VERIFY_IS_EQUAL(float(numext::ceil(half(3.5f))), 4.0f); + VERIFY_IS_EQUAL(float(ceil(half(3.5f))), 4.0f); + VERIFY_IS_EQUAL(float(numext::ceil(half(-3.5f))), -3.0f); + VERIFY_IS_EQUAL(float(ceil(half(-3.5f))), -3.0f); + + VERIFY_IS_APPROX(float(numext::sqrt(half(0.0f))), 0.0f); + VERIFY_IS_APPROX(float(sqrt(half(0.0f))), 0.0f); + VERIFY_IS_APPROX(float(numext::sqrt(half(4.0f))), 2.0f); + VERIFY_IS_APPROX(float(sqrt(half(4.0f))), 2.0f); + + VERIFY_IS_APPROX(float(numext::pow(half(0.0f), half(1.0f))), 0.0f); + VERIFY_IS_APPROX(float(pow(half(0.0f), half(1.0f))), 0.0f); + VERIFY_IS_APPROX(float(numext::pow(half(2.0f), half(2.0f))), 4.0f); + VERIFY_IS_APPROX(float(pow(half(2.0f), half(2.0f))), 4.0f); + + VERIFY_IS_EQUAL(float(numext::exp(half(0.0f))), 1.0f); + VERIFY_IS_EQUAL(float(exp(half(0.0f))), 1.0f); + VERIFY_IS_APPROX(float(numext::exp(half(EIGEN_PI))), 20.f + float(EIGEN_PI)); + VERIFY_IS_APPROX(float(exp(half(EIGEN_PI))), 20.f + float(EIGEN_PI)); + + VERIFY_IS_EQUAL(float(numext::log(half(1.0f))), 0.0f); + VERIFY_IS_EQUAL(float(log(half(1.0f))), 0.0f); + VERIFY_IS_APPROX(float(numext::log(half(10.0f))), 2.30273f); + VERIFY_IS_APPROX(float(log(half(10.0f))), 2.30273f); + + VERIFY_IS_EQUAL(float(numext::log1p(half(0.0f))), 0.0f); + VERIFY_IS_EQUAL(float(log1p(half(0.0f))), 0.0f); + VERIFY_IS_APPROX(float(numext::log1p(half(10.0f))), 2.3978953f); + VERIFY_IS_APPROX(float(log1p(half(10.0f))), 2.3978953f); +} + +void test_trigonometric_functions() +{ + VERIFY_IS_APPROX(numext::cos(half(0.0f)), half(cosf(0.0f))); + VERIFY_IS_APPROX(cos(half(0.0f)), half(cosf(0.0f))); + VERIFY_IS_APPROX(numext::cos(half(EIGEN_PI)), half(cosf(EIGEN_PI))); + //VERIFY_IS_APPROX(numext::cos(half(EIGEN_PI/2)), half(cosf(EIGEN_PI/2))); + //VERIFY_IS_APPROX(numext::cos(half(3*EIGEN_PI/2)), half(cosf(3*EIGEN_PI/2))); + VERIFY_IS_APPROX(numext::cos(half(3.5f)), half(cosf(3.5f))); + + VERIFY_IS_APPROX(numext::sin(half(0.0f)), half(sinf(0.0f))); + VERIFY_IS_APPROX(sin(half(0.0f)), half(sinf(0.0f))); + // VERIFY_IS_APPROX(numext::sin(half(EIGEN_PI)), half(sinf(EIGEN_PI))); + VERIFY_IS_APPROX(numext::sin(half(EIGEN_PI/2)), half(sinf(EIGEN_PI/2))); + VERIFY_IS_APPROX(numext::sin(half(3*EIGEN_PI/2)), half(sinf(3*EIGEN_PI/2))); + VERIFY_IS_APPROX(numext::sin(half(3.5f)), half(sinf(3.5f))); + + VERIFY_IS_APPROX(numext::tan(half(0.0f)), half(tanf(0.0f))); + VERIFY_IS_APPROX(tan(half(0.0f)), half(tanf(0.0f))); + // VERIFY_IS_APPROX(numext::tan(half(EIGEN_PI)), half(tanf(EIGEN_PI))); + // VERIFY_IS_APPROX(numext::tan(half(EIGEN_PI/2)), half(tanf(EIGEN_PI/2))); + //VERIFY_IS_APPROX(numext::tan(half(3*EIGEN_PI/2)), half(tanf(3*EIGEN_PI/2))); + VERIFY_IS_APPROX(numext::tan(half(3.5f)), half(tanf(3.5f))); +} + +void test_array() +{ + typedef Array ArrayXh; + Index size = internal::random(1,10); + Index i = internal::random(0,size-1); + ArrayXh a1 = ArrayXh::Random(size), a2 = ArrayXh::Random(size); + VERIFY_IS_APPROX( a1+a1, half(2)*a1 ); + VERIFY( (a1.abs() >= half(0)).all() ); + VERIFY_IS_APPROX( (a1*a1).sqrt(), a1.abs() ); + + VERIFY( ((a1.min)(a2) <= (a1.max)(a2)).all() ); + a1(i) = half(-10.); + VERIFY_IS_EQUAL( a1.minCoeff(), half(-10.) ); + a1(i) = half(10.); + VERIFY_IS_EQUAL( a1.maxCoeff(), half(10.) ); + + std::stringstream ss; + ss << a1; +} + +void test_half_float() +{ + CALL_SUBTEST(test_conversion()); + CALL_SUBTEST(test_numtraits()); + CALL_SUBTEST(test_arithmetic()); + CALL_SUBTEST(test_comparison()); + CALL_SUBTEST(test_basic_functions()); + CALL_SUBTEST(test_trigonometric_functions()); + CALL_SUBTEST(test_array()); +} diff --git a/ground/gcs/src/libs/eigen/test/incomplete_cholesky.cpp b/ground/gcs/src/libs/eigen/test/incomplete_cholesky.cpp new file mode 100644 index 0000000000..59ffe92595 --- /dev/null +++ b/ground/gcs/src/libs/eigen/test/incomplete_cholesky.cpp @@ -0,0 +1,65 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2015-2016 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. +// #define EIGEN_DONT_VECTORIZE +// #define EIGEN_MAX_ALIGN_BYTES 0 +#include "sparse_solver.h" +#include +#include + +template void test_incomplete_cholesky_T() +{ + typedef SparseMatrix SparseMatrixType; + ConjugateGradient > > cg_illt_lower_amd; + ConjugateGradient > > cg_illt_lower_nat; + ConjugateGradient > > cg_illt_upper_amd; + ConjugateGradient > > cg_illt_upper_nat; + ConjugateGradient > > cg_illt_uplo_amd; + + + CALL_SUBTEST( check_sparse_spd_solving(cg_illt_lower_amd) ); + CALL_SUBTEST( check_sparse_spd_solving(cg_illt_lower_nat) ); + CALL_SUBTEST( check_sparse_spd_solving(cg_illt_upper_amd) ); + CALL_SUBTEST( check_sparse_spd_solving(cg_illt_upper_nat) ); + CALL_SUBTEST( check_sparse_spd_solving(cg_illt_uplo_amd) ); +} + +void test_incomplete_cholesky() +{ + CALL_SUBTEST_1(( test_incomplete_cholesky_T() )); + CALL_SUBTEST_2(( test_incomplete_cholesky_T, int>() )); + CALL_SUBTEST_3(( test_incomplete_cholesky_T() )); + +#ifdef EIGEN_TEST_PART_1 + // regression for bug 1150 + for(int N = 1; N<20; ++N) + { + Eigen::MatrixXd b( N, N ); + b.setOnes(); + + Eigen::SparseMatrix m( N, N ); + m.reserve(Eigen::VectorXi::Constant(N,4)); + for( int i = 0; i < N; ++i ) + { + m.insert( i, i ) = 1; + m.coeffRef( i, i / 2 ) = 2; + m.coeffRef( i, i / 3 ) = 2; + m.coeffRef( i, i / 4 ) = 2; + } + + Eigen::SparseMatrix A; + A = m * m.transpose(); + + Eigen::ConjugateGradient, + Eigen::Lower | Eigen::Upper, + Eigen::IncompleteCholesky > solver( A ); + VERIFY(solver.preconditioner().info() == Eigen::Success); + VERIFY(solver.info() == Eigen::Success); + } +#endif +} diff --git a/ground/gcs/src/libs/eigen/test/inplace_decomposition.cpp b/ground/gcs/src/libs/eigen/test/inplace_decomposition.cpp new file mode 100644 index 0000000000..92d0d91b6b --- /dev/null +++ b/ground/gcs/src/libs/eigen/test/inplace_decomposition.cpp @@ -0,0 +1,110 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2016 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "main.h" +#include +#include +#include + +// This file test inplace decomposition through Ref<>, as supported by Cholesky, LU, and QR decompositions. + +template void inplace(bool square = false, bool SPD = false) +{ + typedef typename MatrixType::Scalar Scalar; + typedef Matrix RhsType; + typedef Matrix ResType; + + Index rows = MatrixType::RowsAtCompileTime==Dynamic ? internal::random(2,EIGEN_TEST_MAX_SIZE/2) : Index(MatrixType::RowsAtCompileTime); + Index cols = MatrixType::ColsAtCompileTime==Dynamic ? (square?rows:internal::random(2,rows)) : Index(MatrixType::ColsAtCompileTime); + + MatrixType A = MatrixType::Random(rows,cols); + RhsType b = RhsType::Random(rows); + ResType x(cols); + + if(SPD) + { + assert(square); + A.topRows(cols) = A.topRows(cols).adjoint() * A.topRows(cols); + A.diagonal().array() += 1e-3; + } + + MatrixType A0 = A; + MatrixType A1 = A; + + DecType dec(A); + + // Check that the content of A has been modified + VERIFY_IS_NOT_APPROX( A, A0 ); + + // Check that the decomposition is correct: + if(rows==cols) + { + VERIFY_IS_APPROX( A0 * (x = dec.solve(b)), b ); + } + else + { + VERIFY_IS_APPROX( A0.transpose() * A0 * (x = dec.solve(b)), A0.transpose() * b ); + } + + // Check that modifying A breaks the current dec: + A.setRandom(); + if(rows==cols) + { + VERIFY_IS_NOT_APPROX( A0 * (x = dec.solve(b)), b ); + } + else + { + VERIFY_IS_NOT_APPROX( A0.transpose() * A0 * (x = dec.solve(b)), A0.transpose() * b ); + } + + // Check that calling compute(A1) does not modify A1: + A = A0; + dec.compute(A1); + VERIFY_IS_EQUAL(A0,A1); + VERIFY_IS_NOT_APPROX( A, A0 ); + if(rows==cols) + { + VERIFY_IS_APPROX( A0 * (x = dec.solve(b)), b ); + } + else + { + VERIFY_IS_APPROX( A0.transpose() * A0 * (x = dec.solve(b)), A0.transpose() * b ); + } +} + + +void test_inplace_decomposition() +{ + EIGEN_UNUSED typedef Matrix Matrix43d; + for(int i = 0; i < g_repeat; i++) { + CALL_SUBTEST_1(( inplace >, MatrixXd>(true,true) )); + CALL_SUBTEST_1(( inplace >, Matrix4d>(true,true) )); + + CALL_SUBTEST_2(( inplace >, MatrixXd>(true,true) )); + CALL_SUBTEST_2(( inplace >, Matrix4d>(true,true) )); + + CALL_SUBTEST_3(( inplace >, MatrixXd>(true,false) )); + CALL_SUBTEST_3(( inplace >, Matrix4d>(true,false) )); + + CALL_SUBTEST_4(( inplace >, MatrixXd>(true,false) )); + CALL_SUBTEST_4(( inplace >, Matrix4d>(true,false) )); + + CALL_SUBTEST_5(( inplace >, MatrixXd>(false,false) )); + CALL_SUBTEST_5(( inplace >, Matrix43d>(false,false) )); + + CALL_SUBTEST_6(( inplace >, MatrixXd>(false,false) )); + CALL_SUBTEST_6(( inplace >, Matrix43d>(false,false) )); + + CALL_SUBTEST_7(( inplace >, MatrixXd>(false,false) )); + CALL_SUBTEST_7(( inplace >, Matrix43d>(false,false) )); + + CALL_SUBTEST_8(( inplace >, MatrixXd>(false,false) )); + CALL_SUBTEST_8(( inplace >, Matrix43d>(false,false) )); + } +} diff --git a/ground/gcs/src/libs/eigen/test/integer_types.cpp b/ground/gcs/src/libs/eigen/test/integer_types.cpp index 950f8e9be8..a21f73a81b 100644 --- a/ground/gcs/src/libs/eigen/test/integer_types.cpp +++ b/ground/gcs/src/libs/eigen/test/integer_types.cpp @@ -158,4 +158,12 @@ void test_integer_types() CALL_SUBTEST_8( integer_type_tests(Matrix(1, 5)) ); } +#ifdef EIGEN_TEST_PART_9 + VERIFY_IS_EQUAL(internal::scalar_div_cost::value, 8); + VERIFY_IS_EQUAL(internal::scalar_div_cost::value, 8); + if(sizeof(long)>sizeof(int)) { + VERIFY(internal::scalar_div_cost::value > internal::scalar_div_cost::value); + VERIFY(internal::scalar_div_cost::value > internal::scalar_div_cost::value); + } +#endif } diff --git a/ground/gcs/src/libs/eigen/test/inverse.cpp b/ground/gcs/src/libs/eigen/test/inverse.cpp index 8187b088de..5c6777a18b 100644 --- a/ground/gcs/src/libs/eigen/test/inverse.cpp +++ b/ground/gcs/src/libs/eigen/test/inverse.cpp @@ -68,6 +68,15 @@ template void inverse(const MatrixType& m) VERIFY_IS_MUCH_SMALLER_THAN(abs(det-m3.determinant()), RealScalar(1)); m3.computeInverseWithCheck(m4, invertible); VERIFY( rows==1 ? invertible : !invertible ); + + // check with submatrices + { + Matrix m5; + m5.setRandom(); + m5.topLeftCorner(rows,rows) = m1; + m2 = m5.template topLeftCorner().inverse(); + VERIFY_IS_APPROX( (m5.template topLeftCorner()), m2.inverse() ); + } #endif // check in-place inversion @@ -93,12 +102,16 @@ void test_inverse() CALL_SUBTEST_3( inverse(Matrix3f()) ); CALL_SUBTEST_4( inverse(Matrix4f()) ); CALL_SUBTEST_4( inverse(Matrix()) ); + s = internal::random(50,320); CALL_SUBTEST_5( inverse(MatrixXf(s,s)) ); + TEST_SET_BUT_UNUSED_VARIABLE(s) + s = internal::random(25,100); CALL_SUBTEST_6( inverse(MatrixXcd(s,s)) ); + TEST_SET_BUT_UNUSED_VARIABLE(s) + CALL_SUBTEST_7( inverse(Matrix4d()) ); CALL_SUBTEST_7( inverse(Matrix()) ); } - TEST_SET_BUT_UNUSED_VARIABLE(s) } diff --git a/ground/gcs/src/libs/eigen/test/is_same_dense.cpp b/ground/gcs/src/libs/eigen/test/is_same_dense.cpp new file mode 100644 index 0000000000..2c7838ce96 --- /dev/null +++ b/ground/gcs/src/libs/eigen/test/is_same_dense.cpp @@ -0,0 +1,33 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2015 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "main.h" + +using internal::is_same_dense; + +void test_is_same_dense() +{ + typedef Matrix ColMatrixXd; + ColMatrixXd m1(10,10); + Ref ref_m1(m1); + Ref const_ref_m1(m1); + VERIFY(is_same_dense(m1,m1)); + VERIFY(is_same_dense(m1,ref_m1)); + VERIFY(is_same_dense(const_ref_m1,m1)); + VERIFY(is_same_dense(const_ref_m1,ref_m1)); + + VERIFY(is_same_dense(m1.block(0,0,m1.rows(),m1.cols()),m1)); + VERIFY(!is_same_dense(m1.row(0),m1.col(0))); + + Ref const_ref_m1_row(m1.row(1)); + VERIFY(!is_same_dense(m1.row(1),const_ref_m1_row)); + + Ref const_ref_m1_col(m1.col(1)); + VERIFY(is_same_dense(m1.col(1),const_ref_m1_col)); +} diff --git a/ground/gcs/src/libs/eigen/test/jacobisvd.cpp b/ground/gcs/src/libs/eigen/test/jacobisvd.cpp index 12c556e59a..7f5f715628 100644 --- a/ground/gcs/src/libs/eigen/test/jacobisvd.cpp +++ b/ground/gcs/src/libs/eigen/test/jacobisvd.cpp @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008 Gael Guennebaud +// Copyright (C) 2008-2014 Gael Guennebaud // Copyright (C) 2009 Benoit Jacob // // This Source Code Form is subject to the terms of the Mozilla @@ -14,279 +14,47 @@ #include "main.h" #include -template -void jacobisvd_check_full(const MatrixType& m, const JacobiSVD& svd) -{ - typedef typename MatrixType::Index Index; - Index rows = m.rows(); - Index cols = m.cols(); - - enum { - RowsAtCompileTime = MatrixType::RowsAtCompileTime, - ColsAtCompileTime = MatrixType::ColsAtCompileTime - }; - - typedef typename MatrixType::Scalar Scalar; - typedef Matrix MatrixUType; - typedef Matrix MatrixVType; - - MatrixType sigma = MatrixType::Zero(rows,cols); - sigma.diagonal() = svd.singularValues().template cast(); - MatrixUType u = svd.matrixU(); - MatrixVType v = svd.matrixV(); - - VERIFY_IS_APPROX(m, u * sigma * v.adjoint()); - VERIFY_IS_UNITARY(u); - VERIFY_IS_UNITARY(v); -} - -template -void jacobisvd_compare_to_full(const MatrixType& m, - unsigned int computationOptions, - const JacobiSVD& referenceSvd) -{ - typedef typename MatrixType::Index Index; - Index rows = m.rows(); - Index cols = m.cols(); - Index diagSize = (std::min)(rows, cols); - - JacobiSVD svd(m, computationOptions); - - VERIFY_IS_APPROX(svd.singularValues(), referenceSvd.singularValues()); - if(computationOptions & ComputeFullU) - VERIFY_IS_APPROX(svd.matrixU(), referenceSvd.matrixU()); - if(computationOptions & ComputeThinU) - VERIFY_IS_APPROX(svd.matrixU(), referenceSvd.matrixU().leftCols(diagSize)); - if(computationOptions & ComputeFullV) - VERIFY_IS_APPROX(svd.matrixV(), referenceSvd.matrixV()); - if(computationOptions & ComputeThinV) - VERIFY_IS_APPROX(svd.matrixV(), referenceSvd.matrixV().leftCols(diagSize)); -} - -template -void jacobisvd_solve(const MatrixType& m, unsigned int computationOptions) -{ - typedef typename MatrixType::Scalar Scalar; - typedef typename MatrixType::RealScalar RealScalar; - typedef typename MatrixType::Index Index; - Index rows = m.rows(); - Index cols = m.cols(); - - enum { - RowsAtCompileTime = MatrixType::RowsAtCompileTime, - ColsAtCompileTime = MatrixType::ColsAtCompileTime - }; - - typedef Matrix RhsType; - typedef Matrix SolutionType; - - RhsType rhs = RhsType::Random(rows, internal::random(1, cols)); - JacobiSVD svd(m, computationOptions); - - if(internal::is_same::value) svd.setThreshold(1e-8); - else if(internal::is_same::value) svd.setThreshold(1e-4); - - SolutionType x = svd.solve(rhs); - - RealScalar residual = (m*x-rhs).norm(); - // Check that there is no significantly better solution in the neighborhood of x - if(!test_isMuchSmallerThan(residual,rhs.norm())) - { - // If the residual is very small, then we have an exact solution, so we are already good. - for(int k=0;k::epsilon(); - RealScalar residual_y = (m*y-rhs).norm(); - VERIFY( test_isApprox(residual_y,residual) || residual < residual_y ); - - y.row(k) = x.row(k).array() - 2*NumTraits::epsilon(); - residual_y = (m*y-rhs).norm(); - VERIFY( test_isApprox(residual_y,residual) || residual < residual_y ); - } - } - - // evaluate normal equation which works also for least-squares solutions - if(internal::is_same::value) - { - // This test is not stable with single precision. - // This is probably because squaring m signicantly affects the precision. - VERIFY_IS_APPROX(m.adjoint()*m*x,m.adjoint()*rhs); - } - - // check minimal norm solutions - { - // generate a full-rank m x n problem with m MatrixType2; - typedef Matrix RhsType2; - typedef Matrix MatrixType2T; - Index rank = RankAtCompileTime2==Dynamic ? internal::random(1,cols) : Index(RankAtCompileTime2); - MatrixType2 m2(rank,cols); - int guard = 0; - do { - m2.setRandom(); - } while(m2.jacobiSvd().setThreshold(test_precision()).rank()!=rank && (++guard)<10); - VERIFY(guard<10); - RhsType2 rhs2 = RhsType2::Random(rank); - // use QR to find a reference minimal norm solution - HouseholderQR qr(m2.adjoint()); - Matrix tmp = qr.matrixQR().topLeftCorner(rank,rank).template triangularView().adjoint().solve(rhs2); - tmp.conservativeResize(cols); - tmp.tail(cols-rank).setZero(); - SolutionType x21 = qr.householderQ() * tmp; - // now check with SVD - JacobiSVD svd2(m2, computationOptions); - SolutionType x22 = svd2.solve(rhs2); - VERIFY_IS_APPROX(m2*x21, rhs2); - VERIFY_IS_APPROX(m2*x22, rhs2); - VERIFY_IS_APPROX(x21, x22); - - // Now check with a rank deficient matrix - typedef Matrix MatrixType3; - typedef Matrix RhsType3; - Index rows3 = RowsAtCompileTime3==Dynamic ? internal::random(rank+1,2*cols) : Index(RowsAtCompileTime3); - Matrix C = Matrix::Random(rows3,rank); - MatrixType3 m3 = C * m2; - RhsType3 rhs3 = C * rhs2; - JacobiSVD svd3(m3, computationOptions); - SolutionType x3 = svd3.solve(rhs3); - if(svd3.rank()!=rank) { - std::cout << m3 << "\n\n"; - std::cout << svd3.singularValues().transpose() << "\n"; - std::cout << svd3.rank() << " == " << rank << "\n"; - std::cout << x21.norm() << " == " << x3.norm() << "\n"; - } -// VERIFY_IS_APPROX(m3*x3, rhs3); - VERIFY_IS_APPROX(m3*x21, rhs3); - VERIFY_IS_APPROX(m2*x3, rhs2); - - VERIFY_IS_APPROX(x21, x3); - } -} - -template -void jacobisvd_test_all_computation_options(const MatrixType& m) -{ - if (QRPreconditioner == NoQRPreconditioner && m.rows() != m.cols()) - return; - JacobiSVD fullSvd(m, ComputeFullU|ComputeFullV); - CALL_SUBTEST(( jacobisvd_check_full(m, fullSvd) )); - CALL_SUBTEST(( jacobisvd_solve(m, ComputeFullU | ComputeFullV) )); - - #if defined __INTEL_COMPILER - // remark #111: statement is unreachable - #pragma warning disable 111 - #endif - if(QRPreconditioner == FullPivHouseholderQRPreconditioner) - return; - - CALL_SUBTEST(( jacobisvd_compare_to_full(m, ComputeFullU, fullSvd) )); - CALL_SUBTEST(( jacobisvd_compare_to_full(m, ComputeFullV, fullSvd) )); - CALL_SUBTEST(( jacobisvd_compare_to_full(m, 0, fullSvd) )); - - if (MatrixType::ColsAtCompileTime == Dynamic) { - // thin U/V are only available with dynamic number of columns - CALL_SUBTEST(( jacobisvd_compare_to_full(m, ComputeFullU|ComputeThinV, fullSvd) )); - CALL_SUBTEST(( jacobisvd_compare_to_full(m, ComputeThinV, fullSvd) )); - CALL_SUBTEST(( jacobisvd_compare_to_full(m, ComputeThinU|ComputeFullV, fullSvd) )); - CALL_SUBTEST(( jacobisvd_compare_to_full(m, ComputeThinU , fullSvd) )); - CALL_SUBTEST(( jacobisvd_compare_to_full(m, ComputeThinU|ComputeThinV, fullSvd) )); - CALL_SUBTEST(( jacobisvd_solve(m, ComputeFullU | ComputeThinV) )); - CALL_SUBTEST(( jacobisvd_solve(m, ComputeThinU | ComputeFullV) )); - CALL_SUBTEST(( jacobisvd_solve(m, ComputeThinU | ComputeThinV) )); - - // test reconstruction - typedef typename MatrixType::Index Index; - Index diagSize = (std::min)(m.rows(), m.cols()); - JacobiSVD svd(m, ComputeThinU | ComputeThinV); - VERIFY_IS_APPROX(m, svd.matrixU().leftCols(diagSize) * svd.singularValues().asDiagonal() * svd.matrixV().leftCols(diagSize).adjoint()); - } -} +#define SVD_DEFAULT(M) JacobiSVD +#define SVD_FOR_MIN_NORM(M) JacobiSVD +#include "svd_common.h" +// Check all variants of JacobiSVD template void jacobisvd(const MatrixType& a = MatrixType(), bool pickrandom = true) { MatrixType m = a; if(pickrandom) - { - typedef typename MatrixType::Scalar Scalar; - typedef typename MatrixType::RealScalar RealScalar; - typedef typename MatrixType::Index Index; - Index diagSize = (std::min)(a.rows(), a.cols()); - RealScalar s = std::numeric_limits::max_exponent10/4; - s = internal::random(1,s); - Matrix d = Matrix::Random(diagSize); - for(Index k=0; k(-s,s)); - m = Matrix::Random(a.rows(),diagSize) * d.asDiagonal() * Matrix::Random(diagSize,a.cols()); - // cancel some coeffs - Index n = internal::random(0,m.size()-1); - for(Index i=0; i(0,m.rows()-1), internal::random(0,m.cols()-1)) = Scalar(0); - } + svd_fill_random(m); - CALL_SUBTEST(( jacobisvd_test_all_computation_options(m) )); - CALL_SUBTEST(( jacobisvd_test_all_computation_options(m) )); - CALL_SUBTEST(( jacobisvd_test_all_computation_options(m) )); - CALL_SUBTEST(( jacobisvd_test_all_computation_options(m) )); + CALL_SUBTEST(( svd_test_all_computation_options >(m, true) )); // check full only + CALL_SUBTEST(( svd_test_all_computation_options >(m, false) )); + CALL_SUBTEST(( svd_test_all_computation_options >(m, false) )); + if(m.rows()==m.cols()) + CALL_SUBTEST(( svd_test_all_computation_options >(m, false) )); } template void jacobisvd_verify_assert(const MatrixType& m) { - typedef typename MatrixType::Scalar Scalar; + svd_verify_assert >(m); typedef typename MatrixType::Index Index; Index rows = m.rows(); Index cols = m.cols(); enum { - RowsAtCompileTime = MatrixType::RowsAtCompileTime, ColsAtCompileTime = MatrixType::ColsAtCompileTime }; - typedef Matrix RhsType; - - RhsType rhs(rows); - - JacobiSVD svd; - VERIFY_RAISES_ASSERT(svd.matrixU()) - VERIFY_RAISES_ASSERT(svd.singularValues()) - VERIFY_RAISES_ASSERT(svd.matrixV()) - VERIFY_RAISES_ASSERT(svd.solve(rhs)) MatrixType a = MatrixType::Zero(rows, cols); a.setZero(); - svd.compute(a, 0); - VERIFY_RAISES_ASSERT(svd.matrixU()) - VERIFY_RAISES_ASSERT(svd.matrixV()) - svd.singularValues(); - VERIFY_RAISES_ASSERT(svd.solve(rhs)) if (ColsAtCompileTime == Dynamic) { - svd.compute(a, ComputeThinU); - svd.matrixU(); - VERIFY_RAISES_ASSERT(svd.matrixV()) - VERIFY_RAISES_ASSERT(svd.solve(rhs)) - - svd.compute(a, ComputeThinV); - svd.matrixV(); - VERIFY_RAISES_ASSERT(svd.matrixU()) - VERIFY_RAISES_ASSERT(svd.solve(rhs)) - JacobiSVD svd_fullqr; VERIFY_RAISES_ASSERT(svd_fullqr.compute(a, ComputeFullU|ComputeThinV)) VERIFY_RAISES_ASSERT(svd_fullqr.compute(a, ComputeThinU|ComputeThinV)) VERIFY_RAISES_ASSERT(svd_fullqr.compute(a, ComputeThinU|ComputeFullV)) } - else - { - VERIFY_RAISES_ASSERT(svd.compute(a, ComputeThinU)) - VERIFY_RAISES_ASSERT(svd.compute(a, ComputeThinV)) - } } template @@ -302,126 +70,17 @@ void jacobisvd_method() VERIFY_IS_APPROX(m.jacobiSvd(ComputeFullU|ComputeFullV).solve(m), m); } -// work around stupid msvc error when constructing at compile time an expression that involves -// a division by zero, even if the numeric type has floating point -template -EIGEN_DONT_INLINE Scalar zero() { return Scalar(0); } - -// workaround aggressive optimization in ICC -template EIGEN_DONT_INLINE T sub(T a, T b) { return a - b; } - -template -void jacobisvd_inf_nan() -{ - // all this function does is verify we don't iterate infinitely on nan/inf values - - JacobiSVD svd; - typedef typename MatrixType::Scalar Scalar; - Scalar some_inf = Scalar(1) / zero(); - VERIFY(sub(some_inf, some_inf) != sub(some_inf, some_inf)); - svd.compute(MatrixType::Constant(10,10,some_inf), ComputeFullU | ComputeFullV); - - Scalar nan = std::numeric_limits::quiet_NaN(); - VERIFY(nan != nan); - svd.compute(MatrixType::Constant(10,10,nan), ComputeFullU | ComputeFullV); - - MatrixType m = MatrixType::Zero(10,10); - m(internal::random(0,9), internal::random(0,9)) = some_inf; - svd.compute(m, ComputeFullU | ComputeFullV); - - m = MatrixType::Zero(10,10); - m(internal::random(0,9), internal::random(0,9)) = nan; - svd.compute(m, ComputeFullU | ComputeFullV); - - // regression test for bug 791 - m.resize(3,3); - m << 0, 2*NumTraits::epsilon(), 0.5, - 0, -0.5, 0, - nan, 0, 0; - svd.compute(m, ComputeFullU | ComputeFullV); -} - -// Regression test for bug 286: JacobiSVD loops indefinitely with some -// matrices containing denormal numbers. -void jacobisvd_bug286() -{ -#if defined __INTEL_COMPILER -// shut up warning #239: floating point underflow -#pragma warning push -#pragma warning disable 239 -#endif - Matrix2d M; - M << -7.90884e-313, -4.94e-324, - 0, 5.60844e-313; -#if defined __INTEL_COMPILER -#pragma warning pop -#endif - JacobiSVD svd; - svd.compute(M); // just check we don't loop indefinitely -} - -void jacobisvd_preallocate() -{ - Vector3f v(3.f, 2.f, 1.f); - MatrixXf m = v.asDiagonal(); - - internal::set_is_malloc_allowed(false); - VERIFY_RAISES_ASSERT(VectorXf tmp(10);) - JacobiSVD svd; - internal::set_is_malloc_allowed(true); - svd.compute(m); - VERIFY_IS_APPROX(svd.singularValues(), v); - - JacobiSVD svd2(3,3); - internal::set_is_malloc_allowed(false); - svd2.compute(m); - internal::set_is_malloc_allowed(true); - VERIFY_IS_APPROX(svd2.singularValues(), v); - VERIFY_RAISES_ASSERT(svd2.matrixU()); - VERIFY_RAISES_ASSERT(svd2.matrixV()); - svd2.compute(m, ComputeFullU | ComputeFullV); - VERIFY_IS_APPROX(svd2.matrixU(), Matrix3f::Identity()); - VERIFY_IS_APPROX(svd2.matrixV(), Matrix3f::Identity()); - internal::set_is_malloc_allowed(false); - svd2.compute(m); - internal::set_is_malloc_allowed(true); - - JacobiSVD svd3(3,3,ComputeFullU|ComputeFullV); - internal::set_is_malloc_allowed(false); - svd2.compute(m); - internal::set_is_malloc_allowed(true); - VERIFY_IS_APPROX(svd2.singularValues(), v); - VERIFY_IS_APPROX(svd2.matrixU(), Matrix3f::Identity()); - VERIFY_IS_APPROX(svd2.matrixV(), Matrix3f::Identity()); - internal::set_is_malloc_allowed(false); - svd2.compute(m, ComputeFullU|ComputeFullV); - internal::set_is_malloc_allowed(true); -} - void test_jacobisvd() { CALL_SUBTEST_3(( jacobisvd_verify_assert(Matrix3f()) )); CALL_SUBTEST_4(( jacobisvd_verify_assert(Matrix4d()) )); CALL_SUBTEST_7(( jacobisvd_verify_assert(MatrixXf(10,12)) )); CALL_SUBTEST_8(( jacobisvd_verify_assert(MatrixXcd(7,5)) )); + + CALL_SUBTEST_11(svd_all_trivial_2x2(jacobisvd)); + CALL_SUBTEST_12(svd_all_trivial_2x2(jacobisvd)); for(int i = 0; i < g_repeat; i++) { - Matrix2cd m; - m << 0, 1, - 0, 1; - CALL_SUBTEST_1(( jacobisvd(m, false) )); - m << 1, 0, - 1, 0; - CALL_SUBTEST_1(( jacobisvd(m, false) )); - - Matrix2d n; - n << 0, 0, - 0, 0; - CALL_SUBTEST_2(( jacobisvd(n, false) )); - n << 0, 0, - 0, 1; - CALL_SUBTEST_2(( jacobisvd(n, false) )); - CALL_SUBTEST_3(( jacobisvd() )); CALL_SUBTEST_4(( jacobisvd() )); CALL_SUBTEST_5(( jacobisvd >() )); @@ -440,8 +99,14 @@ void test_jacobisvd() (void) c; // Test on inf/nan matrix - CALL_SUBTEST_7( jacobisvd_inf_nan() ); - CALL_SUBTEST_10( jacobisvd_inf_nan() ); + CALL_SUBTEST_7( (svd_inf_nan, MatrixXf>()) ); + CALL_SUBTEST_10( (svd_inf_nan, MatrixXd>()) ); + + // bug1395 test compile-time vectors as input + CALL_SUBTEST_13(( jacobisvd_verify_assert(Matrix()) )); + CALL_SUBTEST_13(( jacobisvd_verify_assert(Matrix()) )); + CALL_SUBTEST_13(( jacobisvd_verify_assert(Matrix(r)) )); + CALL_SUBTEST_13(( jacobisvd_verify_assert(Matrix(c)) )); } CALL_SUBTEST_7(( jacobisvd(MatrixXf(internal::random(EIGEN_TEST_MAX_SIZE/4, EIGEN_TEST_MAX_SIZE/2), internal::random(EIGEN_TEST_MAX_SIZE/4, EIGEN_TEST_MAX_SIZE/2))) )); @@ -455,8 +120,7 @@ void test_jacobisvd() CALL_SUBTEST_7( JacobiSVD(10,10) ); // Check that preallocation avoids subsequent mallocs - CALL_SUBTEST_9( jacobisvd_preallocate() ); + CALL_SUBTEST_9( svd_preallocate() ); - // Regression check for bug 286 - CALL_SUBTEST_2( jacobisvd_bug286() ); + CALL_SUBTEST_2( svd_underoverflow() ); } diff --git a/ground/gcs/src/libs/eigen/test/linearstructure.cpp b/ground/gcs/src/libs/eigen/test/linearstructure.cpp index 618984d5c2..17474af108 100644 --- a/ground/gcs/src/libs/eigen/test/linearstructure.cpp +++ b/ground/gcs/src/libs/eigen/test/linearstructure.cpp @@ -2,11 +2,15 @@ // for linear algebra. // // Copyright (C) 2006-2008 Benoit Jacob +// Copyright (C) 2014 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. +static bool g_called; +#define EIGEN_SCALAR_BINARY_OP_PLUGIN { g_called |= (!internal::is_same::value); } + #include "main.h" template void linearStructure(const MatrixType& m) @@ -17,6 +21,7 @@ template void linearStructure(const MatrixType& m) */ typedef typename MatrixType::Index Index; typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::RealScalar RealScalar; Index rows = m.rows(); Index cols = m.cols(); @@ -28,7 +33,7 @@ template void linearStructure(const MatrixType& m) m3(rows, cols); Scalar s1 = internal::random(); - while (abs(s1)<1e-3) s1 = internal::random(); + while (abs(s1)(); Index r = internal::random(0, rows-1), c = internal::random(0, cols-1); @@ -68,8 +73,48 @@ template void linearStructure(const MatrixType& m) VERIFY_IS_APPROX(m1.block(0,0,rows,cols) * s1, m1 * s1); } +// Make sure that complex * real and real * complex are properly optimized +template void real_complex(DenseIndex rows = MatrixType::RowsAtCompileTime, DenseIndex cols = MatrixType::ColsAtCompileTime) +{ + typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::RealScalar RealScalar; + + RealScalar s = internal::random(); + MatrixType m1 = MatrixType::Random(rows, cols); + + g_called = false; + VERIFY_IS_APPROX(s*m1, Scalar(s)*m1); + VERIFY(g_called && "real * matrix not properly optimized"); + + g_called = false; + VERIFY_IS_APPROX(m1*s, m1*Scalar(s)); + VERIFY(g_called && "matrix * real not properly optimized"); + + g_called = false; + VERIFY_IS_APPROX(m1/s, m1/Scalar(s)); + VERIFY(g_called && "matrix / real not properly optimized"); + + g_called = false; + VERIFY_IS_APPROX(s+m1.array(), Scalar(s)+m1.array()); + VERIFY(g_called && "real + matrix not properly optimized"); + + g_called = false; + VERIFY_IS_APPROX(m1.array()+s, m1.array()+Scalar(s)); + VERIFY(g_called && "matrix + real not properly optimized"); + + g_called = false; + VERIFY_IS_APPROX(s-m1.array(), Scalar(s)-m1.array()); + VERIFY(g_called && "real - matrix not properly optimized"); + + g_called = false; + VERIFY_IS_APPROX(m1.array()-s, m1.array()-Scalar(s)); + VERIFY(g_called && "matrix - real not properly optimized"); +} + void test_linearstructure() { + g_called = true; + VERIFY(g_called); // avoid `unneeded-internal-declaration` warning. for(int i = 0; i < g_repeat; i++) { CALL_SUBTEST_1( linearStructure(Matrix()) ); CALL_SUBTEST_2( linearStructure(Matrix2f()) ); @@ -80,5 +125,25 @@ void test_linearstructure() CALL_SUBTEST_7( linearStructure(MatrixXi (internal::random(1,EIGEN_TEST_MAX_SIZE), internal::random(1,EIGEN_TEST_MAX_SIZE))) ); CALL_SUBTEST_8( linearStructure(MatrixXcd(internal::random(1,EIGEN_TEST_MAX_SIZE/2), internal::random(1,EIGEN_TEST_MAX_SIZE/2))) ); CALL_SUBTEST_9( linearStructure(ArrayXXf (internal::random(1,EIGEN_TEST_MAX_SIZE), internal::random(1,EIGEN_TEST_MAX_SIZE))) ); + CALL_SUBTEST_10( linearStructure(ArrayXXcf (internal::random(1,EIGEN_TEST_MAX_SIZE), internal::random(1,EIGEN_TEST_MAX_SIZE))) ); + + CALL_SUBTEST_11( real_complex() ); + CALL_SUBTEST_11( real_complex(10,10) ); + CALL_SUBTEST_11( real_complex(10,10) ); + } + +#ifdef EIGEN_TEST_PART_4 + { + // make sure that /=scalar and /scalar do not overflow + // rational: 1.0/4.94e-320 overflow, but m/4.94e-320 should not + Matrix4d m2, m3; + m3 = m2 = Matrix4d::Random()*1e-20; + m2 = m2 / 4.9e-320; + VERIFY_IS_APPROX(m2.cwiseQuotient(m2), Matrix4d::Ones()); + m3 /= 4.9e-320; + VERIFY_IS_APPROX(m3.cwiseQuotient(m3), Matrix4d::Ones()); + + } +#endif } diff --git a/ground/gcs/src/libs/eigen/test/lscg.cpp b/ground/gcs/src/libs/eigen/test/lscg.cpp new file mode 100644 index 0000000000..daa62a9540 --- /dev/null +++ b/ground/gcs/src/libs/eigen/test/lscg.cpp @@ -0,0 +1,29 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2011 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "sparse_solver.h" +#include + +template void test_lscg_T() +{ + LeastSquaresConjugateGradient > lscg_colmajor_diag; + LeastSquaresConjugateGradient, IdentityPreconditioner> lscg_colmajor_I; + + CALL_SUBTEST( check_sparse_square_solving(lscg_colmajor_diag) ); + CALL_SUBTEST( check_sparse_square_solving(lscg_colmajor_I) ); + + CALL_SUBTEST( check_sparse_leastsquare_solving(lscg_colmajor_diag) ); + CALL_SUBTEST( check_sparse_leastsquare_solving(lscg_colmajor_I) ); +} + +void test_lscg() +{ + CALL_SUBTEST_1(test_lscg_T()); + CALL_SUBTEST_2(test_lscg_T >()); +} diff --git a/ground/gcs/src/libs/eigen/test/lu.cpp b/ground/gcs/src/libs/eigen/test/lu.cpp index 3746526946..9787f4d86f 100644 --- a/ground/gcs/src/libs/eigen/test/lu.cpp +++ b/ground/gcs/src/libs/eigen/test/lu.cpp @@ -11,6 +11,11 @@ #include using namespace std; +template +typename MatrixType::RealScalar matrix_l1_norm(const MatrixType& m) { + return m.cwiseAbs().colwise().sum().maxCoeff(); +} + template void lu_non_invertible() { typedef typename MatrixType::Index Index; @@ -92,6 +97,26 @@ template void lu_non_invertible() // test that the code, which does resize(), may be applied to an xpr m2.block(0,0,m2.rows(),m2.cols()) = lu.solve(m3); VERIFY_IS_APPROX(m3, m1*m2); + + // test solve with transposed + m3 = MatrixType::Random(rows,cols2); + m2 = m1.transpose()*m3; + m3 = MatrixType::Random(rows,cols2); + lu.template _solve_impl_transposed(m2, m3); + VERIFY_IS_APPROX(m2, m1.transpose()*m3); + m3 = MatrixType::Random(rows,cols2); + m3 = lu.transpose().solve(m2); + VERIFY_IS_APPROX(m2, m1.transpose()*m3); + + // test solve with conjugate transposed + m3 = MatrixType::Random(rows,cols2); + m2 = m1.adjoint()*m3; + m3 = MatrixType::Random(rows,cols2); + lu.template _solve_impl_transposed(m2, m3); + VERIFY_IS_APPROX(m2, m1.adjoint()*m3); + m3 = MatrixType::Random(rows,cols2); + m3 = lu.adjoint().solve(m2); + VERIFY_IS_APPROX(m2, m1.adjoint()*m3); } template void lu_invertible() @@ -100,9 +125,9 @@ template void lu_invertible() LU.h */ typedef typename NumTraits::Real RealScalar; - DenseIndex size = MatrixType::RowsAtCompileTime; + Index size = MatrixType::RowsAtCompileTime; if( size==Dynamic) - size = internal::random(1,EIGEN_TEST_MAX_SIZE); + size = internal::random(1,EIGEN_TEST_MAX_SIZE); MatrixType m1(size, size), m2(size, size), m3(size, size); FullPivLU lu; @@ -123,7 +148,28 @@ template void lu_invertible() m3 = MatrixType::Random(size,size); m2 = lu.solve(m3); VERIFY_IS_APPROX(m3, m1*m2); - VERIFY_IS_APPROX(m2, lu.inverse()*m3); + MatrixType m1_inverse = lu.inverse(); + VERIFY_IS_APPROX(m2, m1_inverse*m3); + + RealScalar rcond = (RealScalar(1) / matrix_l1_norm(m1)) / matrix_l1_norm(m1_inverse); + const RealScalar rcond_est = lu.rcond(); + // Verify that the estimated condition number is within a factor of 10 of the + // truth. + VERIFY(rcond_est > rcond / 10 && rcond_est < rcond * 10); + + // test solve with transposed + lu.template _solve_impl_transposed(m3, m2); + VERIFY_IS_APPROX(m3, m1.transpose()*m2); + m3 = MatrixType::Random(size,size); + m3 = lu.transpose().solve(m2); + VERIFY_IS_APPROX(m2, m1.transpose()*m3); + + // test solve with conjugate transposed + lu.template _solve_impl_transposed(m3, m2); + VERIFY_IS_APPROX(m3, m1.adjoint()*m2); + m3 = MatrixType::Random(size,size); + m3 = lu.adjoint().solve(m2); + VERIFY_IS_APPROX(m2, m1.adjoint()*m3); // Regression test for Bug 302 MatrixType m4 = MatrixType::Random(size,size); @@ -136,14 +182,39 @@ template void lu_partial_piv() PartialPivLU.h */ typedef typename MatrixType::Index Index; - Index rows = internal::random(1,4); - Index cols = rows; + typedef typename NumTraits::Real RealScalar; + Index size = internal::random(1,4); - MatrixType m1(cols, rows); + MatrixType m1(size, size), m2(size, size), m3(size, size); m1.setRandom(); PartialPivLU plu(m1); VERIFY_IS_APPROX(m1, plu.reconstructedMatrix()); + + m3 = MatrixType::Random(size,size); + m2 = plu.solve(m3); + VERIFY_IS_APPROX(m3, m1*m2); + MatrixType m1_inverse = plu.inverse(); + VERIFY_IS_APPROX(m2, m1_inverse*m3); + + RealScalar rcond = (RealScalar(1) / matrix_l1_norm(m1)) / matrix_l1_norm(m1_inverse); + const RealScalar rcond_est = plu.rcond(); + // Verify that the estimate is within a factor of 10 of the truth. + VERIFY(rcond_est > rcond / 10 && rcond_est < rcond * 10); + + // test solve with transposed + plu.template _solve_impl_transposed(m3, m2); + VERIFY_IS_APPROX(m3, m1.transpose()*m2); + m3 = MatrixType::Random(size,size); + m3 = plu.transpose().solve(m2); + VERIFY_IS_APPROX(m2, m1.transpose()*m3); + + // test solve with conjugate transposed + plu.template _solve_impl_transposed(m3, m2); + VERIFY_IS_APPROX(m3, m1.adjoint()*m2); + m3 = MatrixType::Random(size,size); + m3 = plu.adjoint().solve(m2); + VERIFY_IS_APPROX(m2, m1.adjoint()*m3); } template void lu_verify_assert() diff --git a/ground/gcs/src/libs/eigen/test/main.h b/ground/gcs/src/libs/eigen/test/main.h index 6642048662..25d2dcf43e 100644 --- a/ground/gcs/src/libs/eigen/test/main.h +++ b/ground/gcs/src/libs/eigen/test/main.h @@ -41,7 +41,14 @@ #include #include #include +#include #include +#if __cplusplus >= 201103L +#include +#ifdef EIGEN_USE_THREADS +#include +#endif +#endif // To test that all calls from Eigen code to std::min() and std::max() are // protected by parenthesis against macro expansion, the min()/max() macros @@ -49,14 +56,48 @@ // compiler error. #define min(A,B) please_protect_your_min_with_parentheses #define max(A,B) please_protect_your_max_with_parentheses +#define isnan(X) please_protect_your_isnan_with_parentheses +#define isinf(X) please_protect_your_isinf_with_parentheses +#define isfinite(X) please_protect_your_isfinite_with_parentheses +#ifdef M_PI +#undef M_PI +#endif +#define M_PI please_use_EIGEN_PI_instead_of_M_PI #define FORBIDDEN_IDENTIFIER (this_identifier_is_forbidden_to_avoid_clashes) this_identifier_is_forbidden_to_avoid_clashes // B0 is defined in POSIX header termios.h #define B0 FORBIDDEN_IDENTIFIER +// Unit tests calling Eigen's blas library must preserve the default blocking size +// to avoid troubles. +#ifndef EIGEN_NO_DEBUG_SMALL_PRODUCT_BLOCKS +#define EIGEN_DEBUG_SMALL_PRODUCT_BLOCKS +#endif // shuts down ICC's remark #593: variable "XXX" was set but never used -#define TEST_SET_BUT_UNUSED_VARIABLE(X) X = X + 0; +#define TEST_SET_BUT_UNUSED_VARIABLE(X) EIGEN_UNUSED_VARIABLE(X) + +#ifdef TEST_ENABLE_TEMPORARY_TRACKING + +static long int nb_temporaries; +static long int nb_temporaries_on_assert = -1; + +inline void on_temporary_creation(long int size) { + // here's a great place to set a breakpoint when debugging failures in this test! + if(size!=0) nb_temporaries++; + if(nb_temporaries_on_assert>0) assert(nb_temporaries g_test_stack; + // level == 0 <=> abort if test fail + // level >= 1 <=> warning message to std::cerr if test fail + static int g_test_level = 0; static int g_repeat; static unsigned int g_seed; static bool g_has_set_repeat, g_has_set_seed; } +#define TRACK std::cerr << __FILE__ << " " << __LINE__ << std::endl +// #define TRACK while() + #define EI_PP_MAKE_STRING2(S) #S #define EI_PP_MAKE_STRING(S) EI_PP_MAKE_STRING2(S) #define EIGEN_DEFAULT_IO_FORMAT IOFormat(4, 0, " ", "\n", "", "", "", "") +#if (defined(_CPPUNWIND) || defined(__EXCEPTIONS)) && !defined(__CUDA_ARCH__) + #define EIGEN_EXCEPTIONS +#endif + #ifndef EIGEN_NO_ASSERTION_CHECKING namespace Eigen @@ -135,33 +186,35 @@ namespace Eigen if(report_on_cerr_on_assert_failure) \ std::cerr << #a << " " __FILE__ << "(" << __LINE__ << ")\n"; \ Eigen::no_more_assert = true; \ - throw Eigen::eigen_assert_exception(); \ + EIGEN_THROW_X(Eigen::eigen_assert_exception()); \ } \ else if (Eigen::internal::push_assert) \ { \ eigen_assert_list.push_back(std::string(EI_PP_MAKE_STRING(__FILE__) " (" EI_PP_MAKE_STRING(__LINE__) ") : " #a) ); \ } + #ifdef EIGEN_EXCEPTIONS #define VERIFY_RAISES_ASSERT(a) \ { \ Eigen::no_more_assert = false; \ - Eigen::eigen_assert_list.clear(); \ - Eigen::internal::push_assert = true; \ + Eigen::eigen_assert_list.clear(); \ + Eigen::internal::push_assert = true; \ Eigen::report_on_cerr_on_assert_failure = false; \ try { \ a; \ std::cerr << "One of the following asserts should have been triggered:\n"; \ - for (uint ai=0 ; ai0) + std::cerr << "WARNING: "; std::cerr << "Test " << testname << " failed in " << file << " (" << line << ")" << std::endl << " " << condition_as_string << std::endl; std::cerr << "Stack:\n"; @@ -208,14 +271,20 @@ inline void verify_impl(bool condition, const char *testname, const char *file, for(int i=test_stack_size-1; i>=0; --i) std::cerr << " - " << Eigen::g_test_stack[i] << "\n"; std::cerr << "\n"; - abort(); + if(Eigen::g_test_level==0) + abort(); } } #define VERIFY(a) ::verify_impl(a, g_test_stack.back().c_str(), __FILE__, __LINE__, EI_PP_MAKE_STRING(a)) -#define VERIFY_IS_EQUAL(a, b) VERIFY(test_is_equal(a, b)) -#define VERIFY_IS_APPROX(a, b) VERIFY(test_isApprox(a, b)) +#define VERIFY_GE(a, b) ::verify_impl(a >= b, g_test_stack.back().c_str(), __FILE__, __LINE__, EI_PP_MAKE_STRING(a >= b)) +#define VERIFY_LE(a, b) ::verify_impl(a <= b, g_test_stack.back().c_str(), __FILE__, __LINE__, EI_PP_MAKE_STRING(a <= b)) + + +#define VERIFY_IS_EQUAL(a, b) VERIFY(test_is_equal(a, b, true)) +#define VERIFY_IS_NOT_EQUAL(a, b) VERIFY(test_is_equal(a, b, false)) +#define VERIFY_IS_APPROX(a, b) VERIFY(verifyIsApprox(a, b)) #define VERIFY_IS_NOT_APPROX(a, b) VERIFY(!test_isApprox(a, b)) #define VERIFY_IS_MUCH_SMALLER_THAN(a, b) VERIFY(test_isMuchSmallerThan(a, b)) #define VERIFY_IS_NOT_MUCH_SMALLER_THAN(a, b) VERIFY(!test_isMuchSmallerThan(a, b)) @@ -236,9 +305,10 @@ namespace Eigen { template inline typename NumTraits::Real test_precision() { return NumTraits::dummy_precision(); } template<> inline float test_precision() { return 1e-3f; } template<> inline double test_precision() { return 1e-6; } +template<> inline long double test_precision() { return 1e-6l; } template<> inline float test_precision >() { return test_precision(); } template<> inline double test_precision >() { return test_precision(); } -template<> inline long double test_precision() { return 1e-6; } +template<> inline long double test_precision >() { return test_precision(); } inline bool test_isApprox(const int& a, const int& b) { return internal::isApprox(a, b, test_precision()); } @@ -253,14 +323,15 @@ inline bool test_isMuchSmallerThan(const float& a, const float& b) { return internal::isMuchSmallerThan(a, b, test_precision()); } inline bool test_isApproxOrLessThan(const float& a, const float& b) { return internal::isApproxOrLessThan(a, b, test_precision()); } + inline bool test_isApprox(const double& a, const double& b) { return internal::isApprox(a, b, test_precision()); } - inline bool test_isMuchSmallerThan(const double& a, const double& b) { return internal::isMuchSmallerThan(a, b, test_precision()); } inline bool test_isApproxOrLessThan(const double& a, const double& b) { return internal::isApproxOrLessThan(a, b, test_precision()); } +#ifndef EIGEN_TEST_NO_COMPLEX inline bool test_isApprox(const std::complex& a, const std::complex& b) { return internal::isApprox(a, b, test_precision >()); } inline bool test_isMuchSmallerThan(const std::complex& a, const std::complex& b) @@ -271,6 +342,15 @@ inline bool test_isApprox(const std::complex& a, const std::complex& a, const std::complex& b) { return internal::isMuchSmallerThan(a, b, test_precision >()); } +#ifndef EIGEN_TEST_NO_LONGDOUBLE +inline bool test_isApprox(const std::complex& a, const std::complex& b) +{ return internal::isApprox(a, b, test_precision >()); } +inline bool test_isMuchSmallerThan(const std::complex& a, const std::complex& b) +{ return internal::isMuchSmallerThan(a, b, test_precision >()); } +#endif +#endif + +#ifndef EIGEN_TEST_NO_LONGDOUBLE inline bool test_isApprox(const long double& a, const long double& b) { bool ret = internal::isApprox(a, b, test_precision()); @@ -284,13 +364,127 @@ inline bool test_isMuchSmallerThan(const long double& a, const long double& b) { return internal::isMuchSmallerThan(a, b, test_precision()); } inline bool test_isApproxOrLessThan(const long double& a, const long double& b) { return internal::isApproxOrLessThan(a, b, test_precision()); } +#endif // EIGEN_TEST_NO_LONGDOUBLE + +inline bool test_isApprox(const half& a, const half& b) +{ return internal::isApprox(a, b, test_precision()); } +inline bool test_isMuchSmallerThan(const half& a, const half& b) +{ return internal::isMuchSmallerThan(a, b, test_precision()); } +inline bool test_isApproxOrLessThan(const half& a, const half& b) +{ return internal::isApproxOrLessThan(a, b, test_precision()); } + +// test_relative_error returns the relative difference between a and b as a real scalar as used in isApprox. +template +typename NumTraits::NonInteger test_relative_error(const EigenBase &a, const EigenBase &b) +{ + using std::sqrt; + typedef typename NumTraits::NonInteger RealScalar; + typename internal::nested_eval::type ea(a.derived()); + typename internal::nested_eval::type eb(b.derived()); + return sqrt(RealScalar((ea-eb).cwiseAbs2().sum()) / RealScalar((std::min)(eb.cwiseAbs2().sum(),ea.cwiseAbs2().sum()))); +} + +template +typename T1::RealScalar test_relative_error(const T1 &a, const T2 &b, const typename T1::Coefficients* = 0) +{ + return test_relative_error(a.coeffs(), b.coeffs()); +} + +template +typename T1::Scalar test_relative_error(const T1 &a, const T2 &b, const typename T1::MatrixType* = 0) +{ + return test_relative_error(a.matrix(), b.matrix()); +} + +template +S test_relative_error(const Translation &a, const Translation &b) +{ + return test_relative_error(a.vector(), b.vector()); +} + +template +S test_relative_error(const ParametrizedLine &a, const ParametrizedLine &b) +{ + return (std::max)(test_relative_error(a.origin(), b.origin()), test_relative_error(a.origin(), b.origin())); +} + +template +S test_relative_error(const AlignedBox &a, const AlignedBox &b) +{ + return (std::max)(test_relative_error((a.min)(), (b.min)()), test_relative_error((a.max)(), (b.max)())); +} + +template class SparseMatrixBase; +template +typename T1::RealScalar test_relative_error(const MatrixBase &a, const SparseMatrixBase &b) +{ + return test_relative_error(a,b.toDense()); +} + +template class SparseMatrixBase; +template +typename T1::RealScalar test_relative_error(const SparseMatrixBase &a, const MatrixBase &b) +{ + return test_relative_error(a.toDense(),b); +} + +template class SparseMatrixBase; +template +typename T1::RealScalar test_relative_error(const SparseMatrixBase &a, const SparseMatrixBase &b) +{ + return test_relative_error(a.toDense(),b.toDense()); +} + +template +typename NumTraits::Real>::NonInteger test_relative_error(const T1 &a, const T2 &b, typename internal::enable_if::Real>::value, T1>::type* = 0) +{ + typedef typename NumTraits::Real>::NonInteger RealScalar; + return numext::sqrt(RealScalar(numext::abs2(a-b))/RealScalar((numext::mini)(numext::abs2(a),numext::abs2(b)))); +} + +template +T test_relative_error(const Rotation2D &a, const Rotation2D &b) +{ + return test_relative_error(a.angle(), b.angle()); +} + +template +T test_relative_error(const AngleAxis &a, const AngleAxis &b) +{ + return (std::max)(test_relative_error(a.angle(), b.angle()), test_relative_error(a.axis(), b.axis())); +} template -inline bool test_isApprox(const Type1& a, const Type2& b) +inline bool test_isApprox(const Type1& a, const Type2& b, typename Type1::Scalar* = 0) // Enabled for Eigen's type only { return a.isApprox(b, test_precision()); } +// get_test_precision is a small wrapper to test_precision allowing to return the scalar precision for either scalars or expressions +template +typename NumTraits::Real get_test_precision(const T&, const typename T::Scalar* = 0) +{ + return test_precision::Real>(); +} + +template +typename NumTraits::Real get_test_precision(const T&,typename internal::enable_if::Real>::value, T>::type* = 0) +{ + return test_precision::Real>(); +} + +// verifyIsApprox is a wrapper to test_isApprox that outputs the relative difference magnitude if the test fails. +template +inline bool verifyIsApprox(const Type1& a, const Type2& b) +{ + bool ret = test_isApprox(a,b); + if(!ret) + { + std::cerr << "Difference too large wrt tolerance " << get_test_precision(a) << ", relative error is: " << test_relative_error(a,b) << std::endl; + } + return ret; +} + // The idea behind this function is to compare the two scalars a and b where // the scalar ref is a hint about the expected order of magnitude of a and b. // WARNING: the scalar a and b must be positive @@ -326,17 +520,17 @@ inline bool test_isUnitary(const MatrixBase& m) // Forward declaration to avoid ICC warning template -bool test_is_equal(const T& actual, const U& expected); +bool test_is_equal(const T& actual, const U& expected, bool expect_equal=true); template -bool test_is_equal(const T& actual, const U& expected) +bool test_is_equal(const T& actual, const U& expected, bool expect_equal) { - if (actual==expected) + if ((actual==expected) == expect_equal) return true; // false: std::cerr - << std::endl << " actual = " << actual - << std::endl << " expected = " << expected << std::endl << std::endl; + << "\n actual = " << actual + << "\n expected " << (expect_equal ? "= " : "!=") << expected << "\n\n"; return false; } @@ -347,11 +541,10 @@ bool test_is_equal(const T& actual, const U& expected) */ // Forward declaration to avoid ICC warning template -void createRandomPIMatrixOfRank(typename MatrixType::Index desired_rank, typename MatrixType::Index rows, typename MatrixType::Index cols, MatrixType& m); +void createRandomPIMatrixOfRank(Index desired_rank, Index rows, Index cols, MatrixType& m); template -void createRandomPIMatrixOfRank(typename MatrixType::Index desired_rank, typename MatrixType::Index rows, typename MatrixType::Index cols, MatrixType& m) +void createRandomPIMatrixOfRank(Index desired_rank, Index rows, Index cols, MatrixType& m) { - typedef typename internal::traits::Index Index; typedef typename internal::traits::Scalar Scalar; enum { Rows = MatrixType::RowsAtCompileTime, Cols = MatrixType::ColsAtCompileTime }; @@ -388,11 +581,10 @@ void createRandomPIMatrixOfRank(typename MatrixType::Index desired_rank, typenam // Forward declaration to avoid ICC warning template -void randomPermutationVector(PermutationVectorType& v, typename PermutationVectorType::Index size); +void randomPermutationVector(PermutationVectorType& v, Index size); template -void randomPermutationVector(PermutationVectorType& v, typename PermutationVectorType::Index size) +void randomPermutationVector(PermutationVectorType& v, Index size) { - typedef typename PermutationVectorType::Index Index; typedef typename PermutationVectorType::Scalar Scalar; v.resize(size); for(Index i = 0; i < size; ++i) v(i) = Scalar(i); @@ -411,12 +603,7 @@ template bool isNotNaN(const T& x) return x==x; } -template bool isNaN(const T& x) -{ - return x!=x; -} - -template bool isInf(const T& x) +template bool isPlusInf(const T& x) { return x > NumTraits::highest(); } @@ -437,13 +624,15 @@ template struct GetDifferentType > // Forward declaration to avoid ICC warning template std::string type_name(); -template std::string type_name() { return "other"; } -template<> std::string type_name() { return "float"; } -template<> std::string type_name() { return "double"; } -template<> std::string type_name() { return "int"; } -template<> std::string type_name >() { return "complex"; } -template<> std::string type_name >() { return "complex"; } -template<> std::string type_name >() { return "complex"; } +template std::string type_name() { return "other"; } +template<> std::string type_name() { return "float"; } +template<> std::string type_name() { return "double"; } +template<> std::string type_name() { return "long double"; } +template<> std::string type_name() { return "int"; } +template<> std::string type_name >() { return "complex"; } +template<> std::string type_name >() { return "complex"; } +template<> std::string type_name >() { return "complex"; } +template<> std::string type_name >() { return "complex"; } // forward declaration of the main test function void EIGEN_CAT(test_,EIGEN_TEST_FUNC)(); @@ -550,3 +739,8 @@ int main(int argc, char *argv[]) // remark #1572: floating-point equality and inequality comparisons are unreliable #pragma warning disable 279 383 1418 1572 #endif + +#ifdef _MSC_VER + // 4503 - decorated name length exceeded, name was truncated + #pragma warning( disable : 4503) +#endif diff --git a/ground/gcs/src/libs/eigen/test/mapped_matrix.cpp b/ground/gcs/src/libs/eigen/test/mapped_matrix.cpp index 58904fa376..6a84c58975 100644 --- a/ground/gcs/src/libs/eigen/test/mapped_matrix.cpp +++ b/ground/gcs/src/libs/eigen/test/mapped_matrix.cpp @@ -13,6 +13,8 @@ #include "main.h" +#define EIGEN_TESTMAP_MAX_SIZE 256 + template void map_class_vector(const VectorType& m) { typedef typename VectorType::Index Index; @@ -20,23 +22,26 @@ template void map_class_vector(const VectorType& m) Index size = m.size(); - // test Map.h Scalar* array1 = internal::aligned_new(size); Scalar* array2 = internal::aligned_new(size); Scalar* array3 = new Scalar[size+1]; - Scalar* array3unaligned = size_t(array3)%16 == 0 ? array3+1 : array3; + Scalar* array3unaligned = (internal::UIntPtr(array3)%EIGEN_MAX_ALIGN_BYTES) == 0 ? array3+1 : array3; + Scalar array4[EIGEN_TESTMAP_MAX_SIZE]; - Map(array1, size) = VectorType::Random(size); - Map(array2, size) = Map(array1, size); + Map(array1, size) = VectorType::Random(size); + Map(array2, size) = Map(array1, size); Map(array3unaligned, size) = Map(array1, size); - VectorType ma1 = Map(array1, size); - VectorType ma2 = Map(array2, size); + Map(array4, size) = Map(array1, size); + VectorType ma1 = Map(array1, size); + VectorType ma2 = Map(array2, size); VectorType ma3 = Map(array3unaligned, size); + VectorType ma4 = Map(array4, size); VERIFY_IS_EQUAL(ma1, ma2); VERIFY_IS_EQUAL(ma1, ma3); + VERIFY_IS_EQUAL(ma1, ma4); #ifdef EIGEN_VECTORIZE - if(internal::packet_traits::Vectorizable) - VERIFY_RAISES_ASSERT((Map(array3unaligned, size))) + if(internal::packet_traits::Vectorizable && size>=AlignedMax) + VERIFY_RAISES_ASSERT((Map(array3unaligned, size))) #endif internal::aligned_delete(array1, size); @@ -50,23 +55,64 @@ template void map_class_matrix(const MatrixType& m) typedef typename MatrixType::Scalar Scalar; Index rows = m.rows(), cols = m.cols(), size = rows*cols; + Scalar s1 = internal::random(); - // test Map.h + // array1 and array2 -> aligned heap allocation Scalar* array1 = internal::aligned_new(size); for(int i = 0; i < size; i++) array1[i] = Scalar(1); Scalar* array2 = internal::aligned_new(size); for(int i = 0; i < size; i++) array2[i] = Scalar(1); + // array3unaligned -> unaligned pointer to heap Scalar* array3 = new Scalar[size+1]; for(int i = 0; i < size+1; i++) array3[i] = Scalar(1); - Scalar* array3unaligned = size_t(array3)%16 == 0 ? array3+1 : array3; - Map(array1, rows, cols) = MatrixType::Ones(rows,cols); - Map(array2, rows, cols) = Map(array1, rows, cols); - Map(array3unaligned, rows, cols) = Map(array1, rows, cols); - MatrixType ma1 = Map(array1, rows, cols); - MatrixType ma2 = Map(array2, rows, cols); + Scalar* array3unaligned = internal::UIntPtr(array3)%EIGEN_MAX_ALIGN_BYTES == 0 ? array3+1 : array3; + Scalar array4[256]; + if(size<=256) + for(int i = 0; i < size; i++) array4[i] = Scalar(1); + + Map map1(array1, rows, cols); + Map map2(array2, rows, cols); + Map map3(array3unaligned, rows, cols); + Map map4(array4, rows, cols); + + VERIFY_IS_EQUAL(map1, MatrixType::Ones(rows,cols)); + VERIFY_IS_EQUAL(map2, MatrixType::Ones(rows,cols)); + VERIFY_IS_EQUAL(map3, MatrixType::Ones(rows,cols)); + map1 = MatrixType::Random(rows,cols); + map2 = map1; + map3 = map1; + MatrixType ma1 = map1; + MatrixType ma2 = map2; + MatrixType ma3 = map3; + VERIFY_IS_EQUAL(map1, map2); + VERIFY_IS_EQUAL(map1, map3); VERIFY_IS_EQUAL(ma1, ma2); - MatrixType ma3 = Map(array3unaligned, rows, cols); VERIFY_IS_EQUAL(ma1, ma3); + VERIFY_IS_EQUAL(ma1, map3); + + VERIFY_IS_APPROX(s1*map1, s1*map2); + VERIFY_IS_APPROX(s1*ma1, s1*ma2); + VERIFY_IS_EQUAL(s1*ma1, s1*ma3); + VERIFY_IS_APPROX(s1*map1, s1*map3); + + map2 *= s1; + map3 *= s1; + VERIFY_IS_APPROX(s1*map1, map2); + VERIFY_IS_APPROX(s1*map1, map3); + + if(size<=256) + { + VERIFY_IS_EQUAL(map4, MatrixType::Ones(rows,cols)); + map4 = map1; + MatrixType ma4 = map4; + VERIFY_IS_EQUAL(map1, map4); + VERIFY_IS_EQUAL(ma1, map4); + VERIFY_IS_EQUAL(ma1, ma4); + VERIFY_IS_APPROX(s1*map1, s1*map4); + + map4 *= s1; + VERIFY_IS_APPROX(s1*map1, map4); + } internal::aligned_delete(array1, size); internal::aligned_delete(array2, size); @@ -80,11 +126,10 @@ template void map_static_methods(const VectorType& m) Index size = m.size(); - // test Map.h Scalar* array1 = internal::aligned_new(size); Scalar* array2 = internal::aligned_new(size); Scalar* array3 = new Scalar[size+1]; - Scalar* array3unaligned = size_t(array3)%16 == 0 ? array3+1 : array3; + Scalar* array3unaligned = internal::UIntPtr(array3)%EIGEN_MAX_ALIGN_BYTES == 0 ? array3+1 : array3; VectorType::MapAligned(array1, size) = VectorType::Random(size); VectorType::Map(array2, size) = VectorType::Map(array1, size); @@ -109,9 +154,9 @@ template void check_const_correctness(const PlainObjec // verify that map-to-const don't have LvalueBit typedef typename internal::add_const::type ConstPlainObjectType; VERIFY( !(internal::traits >::Flags & LvalueBit) ); - VERIFY( !(internal::traits >::Flags & LvalueBit) ); + VERIFY( !(internal::traits >::Flags & LvalueBit) ); VERIFY( !(Map::Flags & LvalueBit) ); - VERIFY( !(Map::Flags & LvalueBit) ); + VERIFY( !(Map::Flags & LvalueBit) ); } template @@ -142,6 +187,7 @@ void test_mapped_matrix() CALL_SUBTEST_1( map_class_vector(Matrix()) ); CALL_SUBTEST_1( check_const_correctness(Matrix()) ); CALL_SUBTEST_2( map_class_vector(Vector4d()) ); + CALL_SUBTEST_2( map_class_vector(VectorXd(13)) ); CALL_SUBTEST_2( check_const_correctness(Matrix4d()) ); CALL_SUBTEST_3( map_class_vector(RowVector4f()) ); CALL_SUBTEST_4( map_class_vector(VectorXcf(8)) ); diff --git a/ground/gcs/src/libs/eigen/test/mapstaticmethods.cpp b/ground/gcs/src/libs/eigen/test/mapstaticmethods.cpp index 5b512bde48..06272d1062 100644 --- a/ground/gcs/src/libs/eigen/test/mapstaticmethods.cpp +++ b/ground/gcs/src/libs/eigen/test/mapstaticmethods.cpp @@ -69,7 +69,8 @@ struct mapstaticmethods_impl { static void run(const PlainObjectType& m) { - int rows = m.rows(), cols = m.cols(); + typedef typename PlainObjectType::Index Index; + Index rows = m.rows(), cols = m.cols(); int i = internal::random(2,5), j = internal::random(2,5); @@ -115,7 +116,8 @@ struct mapstaticmethods_impl { static void run(const PlainObjectType& v) { - int size = v.size(); + typedef typename PlainObjectType::Index Index; + Index size = v.size(); int i = internal::random(2,5); diff --git a/ground/gcs/src/libs/eigen/test/mapstride.cpp b/ground/gcs/src/libs/eigen/test/mapstride.cpp index b1dc9de2ab..4858f8fea2 100644 --- a/ground/gcs/src/libs/eigen/test/mapstride.cpp +++ b/ground/gcs/src/libs/eigen/test/mapstride.cpp @@ -23,7 +23,7 @@ template void map_class_vector(const VectorTy Scalar* a_array = internal::aligned_new(arraysize+1); Scalar* array = a_array; if(Alignment!=Aligned) - array = (Scalar*)(ptrdiff_t(a_array) + (internal::packet_traits::AlignedOnScalar?sizeof(Scalar):sizeof(typename NumTraits::Real))); + array = (Scalar*)(internal::IntPtr(a_array) + (internal::packet_traits::AlignedOnScalar?sizeof(Scalar):sizeof(typename NumTraits::Real))); { Map > map(array, size); @@ -56,16 +56,30 @@ template void map_class_matrix(const MatrixTy Index rows = _m.rows(), cols = _m.cols(); MatrixType m = MatrixType::Random(rows,cols); + Scalar s1 = internal::random(); Index arraysize = 2*(rows+4)*(cols+4); - Scalar* a_array = internal::aligned_new(arraysize+1); - Scalar* array = a_array; + Scalar* a_array1 = internal::aligned_new(arraysize+1); + Scalar* array1 = a_array1; if(Alignment!=Aligned) - array = (Scalar*)(ptrdiff_t(a_array) + (internal::packet_traits::AlignedOnScalar?sizeof(Scalar):sizeof(typename NumTraits::Real))); + array1 = (Scalar*)(internal::IntPtr(a_array1) + (internal::packet_traits::AlignedOnScalar?sizeof(Scalar):sizeof(typename NumTraits::Real))); + Scalar a_array2[256]; + Scalar* array2 = a_array2; + if(Alignment!=Aligned) + array2 = (Scalar*)(internal::IntPtr(a_array2) + (internal::packet_traits::AlignedOnScalar?sizeof(Scalar):sizeof(typename NumTraits::Real))); + else + array2 = (Scalar*)(((internal::UIntPtr(a_array2)+EIGEN_MAX_ALIGN_BYTES-1)/EIGEN_MAX_ALIGN_BYTES)*EIGEN_MAX_ALIGN_BYTES); + Index maxsize2 = a_array2 - array2 + 256; + // test no inner stride and some dynamic outer stride + for(int k=0; k<2; ++k) { + if(k==1 && (m.innerSize()+1)*m.outerSize() > maxsize2) + break; + Scalar* array = (k==0 ? array1 : array2); + Map > map(array, rows, cols, OuterStride(m.innerSize()+1)); map = m; VERIFY(map.outerStride() == map.innerSize()+1); @@ -75,11 +89,19 @@ template void map_class_matrix(const MatrixTy VERIFY(array[map.outerStride()*i+j] == m.coeffByOuterInner(i,j)); VERIFY(map.coeffByOuterInner(i,j) == m.coeffByOuterInner(i,j)); } + VERIFY_IS_APPROX(s1*map,s1*m); + map *= s1; + VERIFY_IS_APPROX(map,s1*m); } // test no inner stride and an outer stride of +4. This is quite important as for fixed-size matrices, // this allows to hit the special case where it's vectorizable. + for(int k=0; k<2; ++k) { + if(k==1 && (m.innerSize()+4)*m.outerSize() > maxsize2) + break; + Scalar* array = (k==0 ? array1 : array2); + enum { InnerSize = MatrixType::InnerSizeAtCompileTime, OuterStrideAtCompileTime = InnerSize==Dynamic ? Dynamic : InnerSize+4 @@ -94,10 +116,18 @@ template void map_class_matrix(const MatrixTy VERIFY(array[map.outerStride()*i+j] == m.coeffByOuterInner(i,j)); VERIFY(map.coeffByOuterInner(i,j) == m.coeffByOuterInner(i,j)); } + VERIFY_IS_APPROX(s1*map,s1*m); + map *= s1; + VERIFY_IS_APPROX(map,s1*m); } // test both inner stride and outer stride + for(int k=0; k<2; ++k) { + if(k==1 && (2*m.innerSize()+1)*(m.outerSize()*2) > maxsize2) + break; + Scalar* array = (k==0 ? array1 : array2); + Map > map(array, rows, cols, Stride(2*m.innerSize()+1, 2)); map = m; VERIFY(map.outerStride() == 2*map.innerSize()+1); @@ -108,9 +138,12 @@ template void map_class_matrix(const MatrixTy VERIFY(array[map.outerStride()*i+map.innerStride()*j] == m.coeffByOuterInner(i,j)); VERIFY(map.coeffByOuterInner(i,j) == m.coeffByOuterInner(i,j)); } + VERIFY_IS_APPROX(s1*map,s1*m); + map *= s1; + VERIFY_IS_APPROX(map,s1*m); } - internal::aligned_delete(a_array, arraysize+1); + internal::aligned_delete(a_array1, arraysize+1); } void test_mapstride() diff --git a/ground/gcs/src/libs/eigen/test/meta.cpp b/ground/gcs/src/libs/eigen/test/meta.cpp index 3302c5887f..b8dea68e80 100644 --- a/ground/gcs/src/libs/eigen/test/meta.cpp +++ b/ground/gcs/src/libs/eigen/test/meta.cpp @@ -9,6 +9,12 @@ #include "main.h" +template +bool check_is_convertible(const From&, const To&) +{ + return internal::is_convertible::value; +} + void test_meta() { VERIFY((internal::conditional<(3<4),internal::true_type, internal::false_type>::type::value)); @@ -52,6 +58,24 @@ void test_meta() VERIFY(( internal::is_same::type >::value)); VERIFY(( internal::is_same::type >::value)); + VERIFY(( internal::is_convertible::value )); + VERIFY(( internal::is_convertible::value )); + VERIFY(( internal::is_convertible::value )); + VERIFY((!internal::is_convertible,double>::value )); + VERIFY(( internal::is_convertible::value )); +// VERIFY((!internal::is_convertible::value )); //does not work because the conversion is prevented by a static assertion + VERIFY((!internal::is_convertible::value )); + VERIFY((!internal::is_convertible::value )); + { + float f; + MatrixXf A, B; + VectorXf a, b; + VERIFY(( check_is_convertible(a.dot(b), f) )); + VERIFY(( check_is_convertible(a.transpose()*b, f) )); + VERIFY((!check_is_convertible(A*B, f) )); + VERIFY(( check_is_convertible(A*B, A) )); + } + VERIFY(internal::meta_sqrt<1>::ret == 1); #define VERIFY_META_SQRT(X) VERIFY(internal::meta_sqrt::ret == int(std::sqrt(double(X)))) VERIFY_META_SQRT(2); diff --git a/ground/gcs/src/libs/eigen/test/metis_support.cpp b/ground/gcs/src/libs/eigen/test/metis_support.cpp index 932b040748..d87c56a130 100644 --- a/ground/gcs/src/libs/eigen/test/metis_support.cpp +++ b/ground/gcs/src/libs/eigen/test/metis_support.cpp @@ -3,24 +3,10 @@ // // Copyright (C) 2012 Désiré Nuentsa-Wakam // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, 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 2 of -// the License, or (at your option) any later version. -// -// Eigen 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 Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + #include "sparse_solver.h" #include #include diff --git a/ground/gcs/src/libs/eigen/test/mixingtypes.cpp b/ground/gcs/src/libs/eigen/test/mixingtypes.cpp index 6c2f748755..ad9c2c6525 100644 --- a/ground/gcs/src/libs/eigen/test/mixingtypes.cpp +++ b/ground/gcs/src/libs/eigen/test/mixingtypes.cpp @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008 Gael Guennebaud +// Copyright (C) 2008-2015 Gael Guennebaud // Copyright (C) 2008 Benoit Jacob // // This Source Code Form is subject to the terms of the Mozilla @@ -15,14 +15,26 @@ #define EIGEN_NO_STATIC_ASSERT // turn static asserts into runtime asserts in order to check them #endif -// #ifndef EIGEN_DONT_VECTORIZE -// #define EIGEN_DONT_VECTORIZE // SSE intrinsics aren't designed to allow mixing types -// #endif +#if defined(EIGEN_TEST_PART_1) || defined(EIGEN_TEST_PART_2) || defined(EIGEN_TEST_PART_3) + +#ifndef EIGEN_DONT_VECTORIZE +#define EIGEN_DONT_VECTORIZE +#endif + +#endif + +static bool g_called; +#define EIGEN_SCALAR_BINARY_OP_PLUGIN { g_called |= (!internal::is_same::value); } #include "main.h" using namespace std; +#define VERIFY_MIX_SCALAR(XPR,REF) \ + g_called = false; \ + VERIFY_IS_APPROX(XPR,REF); \ + VERIFY( g_called && #XPR" not properly optimized"); + template void mixingtypes(int size = SizeAtCompileType) { typedef std::complex CF; @@ -38,8 +50,10 @@ template void mixingtypes(int size = SizeAtCompileType) Mat_f mf = Mat_f::Random(size,size); Mat_d md = mf.template cast(); + //Mat_d rd = md; Mat_cf mcf = Mat_cf::Random(size,size); Mat_cd mcd = mcf.template cast >(); + Mat_cd rcd = mcd; Vec_f vf = Vec_f::Random(size,1); Vec_d vd = vf.template cast(); Vec_cf vcf = Vec_cf::Random(size,1); @@ -49,19 +63,59 @@ template void mixingtypes(int size = SizeAtCompileType) complex scf = internal::random >(); complex scd = internal::random >(); - mf+mf; - VERIFY_RAISES_ASSERT(mf+md); - VERIFY_RAISES_ASSERT(mf+mcf); + + float epsf = std::sqrt(std::numeric_limits ::min EIGEN_EMPTY ()); + double epsd = std::sqrt(std::numeric_limits::min EIGEN_EMPTY ()); + + while(std::abs(sf )(); + while(std::abs(sd )(); + while(std::abs(scf)(); + while(std::abs(scd)(); + +// VERIFY_RAISES_ASSERT(mf+md); // does not even compile + +#ifdef EIGEN_DONT_VECTORIZE VERIFY_RAISES_ASSERT(vf=vd); VERIFY_RAISES_ASSERT(vf+=vd); - VERIFY_RAISES_ASSERT(mcd=md); - +#endif + // check scalar products - VERIFY_IS_APPROX(vcf * sf , vcf * complex(sf)); - VERIFY_IS_APPROX(sd * vcd, complex(sd) * vcd); - VERIFY_IS_APPROX(vf * scf , vf.template cast >() * scf); - VERIFY_IS_APPROX(scd * vd, scd * vd.template cast >()); + VERIFY_MIX_SCALAR(vcf * sf , vcf * complex(sf)); + VERIFY_MIX_SCALAR(sd * vcd , complex(sd) * vcd); + VERIFY_MIX_SCALAR(vf * scf , vf.template cast >() * scf); + VERIFY_MIX_SCALAR(scd * vd , scd * vd.template cast >()); + + VERIFY_MIX_SCALAR(vcf * 2 , vcf * complex(2)); + VERIFY_MIX_SCALAR(vcf * 2.1 , vcf * complex(2.1)); + VERIFY_MIX_SCALAR(2 * vcf, vcf * complex(2)); + VERIFY_MIX_SCALAR(2.1 * vcf , vcf * complex(2.1)); + + // check scalar quotients + VERIFY_MIX_SCALAR(vcf / sf , vcf / complex(sf)); + VERIFY_MIX_SCALAR(vf / scf , vf.template cast >() / scf); + VERIFY_MIX_SCALAR(vf.array() / scf, vf.template cast >().array() / scf); + VERIFY_MIX_SCALAR(scd / vd.array() , scd / vd.template cast >().array()); + + // check scalar increment + VERIFY_MIX_SCALAR(vcf.array() + sf , vcf.array() + complex(sf)); + VERIFY_MIX_SCALAR(sd + vcd.array(), complex(sd) + vcd.array()); + VERIFY_MIX_SCALAR(vf.array() + scf, vf.template cast >().array() + scf); + VERIFY_MIX_SCALAR(scd + vd.array() , scd + vd.template cast >().array()); + + // check scalar subtractions + VERIFY_MIX_SCALAR(vcf.array() - sf , vcf.array() - complex(sf)); + VERIFY_MIX_SCALAR(sd - vcd.array(), complex(sd) - vcd.array()); + VERIFY_MIX_SCALAR(vf.array() - scf, vf.template cast >().array() - scf); + VERIFY_MIX_SCALAR(scd - vd.array() , scd - vd.template cast >().array()); + + // check scalar powers + VERIFY_MIX_SCALAR( pow(vcf.array(), sf), Eigen::pow(vcf.array(), complex(sf)) ); + VERIFY_MIX_SCALAR( vcf.array().pow(sf) , Eigen::pow(vcf.array(), complex(sf)) ); + VERIFY_MIX_SCALAR( pow(sd, vcd.array()), Eigen::pow(complex(sd), vcd.array()) ); + VERIFY_MIX_SCALAR( Eigen::pow(vf.array(), scf), Eigen::pow(vf.template cast >().array(), scf) ); + VERIFY_MIX_SCALAR( vf.array().pow(scf) , Eigen::pow(vf.template cast >().array(), scf) ); + VERIFY_MIX_SCALAR( Eigen::pow(scd, vd.array()), Eigen::pow(scd, vd.template cast >().array()) ); // check dot product vf.dot(vf); @@ -75,6 +129,7 @@ template void mixingtypes(int size = SizeAtCompileType) VERIFY_IS_APPROX(vcd.asDiagonal() * md, vcd.asDiagonal() * md.template cast >()); VERIFY_IS_APPROX(mcf * vf.asDiagonal(), mcf * vf.template cast >().asDiagonal()); VERIFY_IS_APPROX(md * vcd.asDiagonal(), md.template cast >() * vcd.asDiagonal()); + // vd.asDiagonal() * mf; // does not even compile // vcd.asDiagonal() * mf; // does not even compile @@ -92,7 +147,6 @@ template void mixingtypes(int size = SizeAtCompileType) VERIFY_IS_APPROX(mcd.array() *= md.array(), mcd2.array() *= md.array().template cast >()); // check matrix-matrix products - VERIFY_IS_APPROX(sd*md*mcd, (sd*md).template cast().eval()*mcd); VERIFY_IS_APPROX(sd*mcd*md, sd*mcd*md.template cast()); VERIFY_IS_APPROX(scd*md*mcd, scd*md.template cast().eval()*mcd); @@ -103,6 +157,20 @@ template void mixingtypes(int size = SizeAtCompileType) VERIFY_IS_APPROX(scf*mf*mcf, scf*mf.template cast()*mcf); VERIFY_IS_APPROX(scf*mcf*mf, scf*mcf*mf.template cast()); + VERIFY_IS_APPROX(sd*md.adjoint()*mcd, (sd*md).template cast().eval().adjoint()*mcd); + VERIFY_IS_APPROX(sd*mcd.adjoint()*md, sd*mcd.adjoint()*md.template cast()); + VERIFY_IS_APPROX(sd*md.adjoint()*mcd.adjoint(), (sd*md).template cast().eval().adjoint()*mcd.adjoint()); + VERIFY_IS_APPROX(sd*mcd.adjoint()*md.adjoint(), sd*mcd.adjoint()*md.template cast().adjoint()); + VERIFY_IS_APPROX(sd*md*mcd.adjoint(), (sd*md).template cast().eval()*mcd.adjoint()); + VERIFY_IS_APPROX(sd*mcd*md.adjoint(), sd*mcd*md.template cast().adjoint()); + + VERIFY_IS_APPROX(sf*mf.adjoint()*mcf, (sf*mf).template cast().eval().adjoint()*mcf); + VERIFY_IS_APPROX(sf*mcf.adjoint()*mf, sf*mcf.adjoint()*mf.template cast()); + VERIFY_IS_APPROX(sf*mf.adjoint()*mcf.adjoint(), (sf*mf).template cast().eval().adjoint()*mcf.adjoint()); + VERIFY_IS_APPROX(sf*mcf.adjoint()*mf.adjoint(), sf*mcf.adjoint()*mf.template cast().adjoint()); + VERIFY_IS_APPROX(sf*mf*mcf.adjoint(), (sf*mf).template cast().eval()*mcf.adjoint()); + VERIFY_IS_APPROX(sf*mcf*mf.adjoint(), sf*mcf*mf.template cast().adjoint()); + VERIFY_IS_APPROX(sf*mf*vcf, (sf*mf).template cast().eval()*vcf); VERIFY_IS_APPROX(scf*mf*vcf,(scf*mf.template cast()).eval()*vcf); VERIFY_IS_APPROX(sf*mcf*vf, sf*mcf*vf.template cast()); @@ -122,11 +190,111 @@ template void mixingtypes(int size = SizeAtCompileType) VERIFY_IS_APPROX(scd*vcd.adjoint()*md, scd*vcd.adjoint()*md.template cast().eval()); VERIFY_IS_APPROX(sd*vd.adjoint()*mcd, sd*vd.adjoint().template cast().eval()*mcd); VERIFY_IS_APPROX(scd*vd.adjoint()*mcd, scd*vd.adjoint().template cast().eval()*mcd); + + VERIFY_IS_APPROX( sd*vcd.adjoint()*md.template triangularView(), sd*vcd.adjoint()*md.template cast().eval().template triangularView()); + VERIFY_IS_APPROX(scd*vcd.adjoint()*md.template triangularView(), scd*vcd.adjoint()*md.template cast().eval().template triangularView()); + VERIFY_IS_APPROX( sd*vcd.adjoint()*md.transpose().template triangularView(), sd*vcd.adjoint()*md.transpose().template cast().eval().template triangularView()); + VERIFY_IS_APPROX(scd*vcd.adjoint()*md.transpose().template triangularView(), scd*vcd.adjoint()*md.transpose().template cast().eval().template triangularView()); + VERIFY_IS_APPROX( sd*vd.adjoint()*mcd.template triangularView(), sd*vd.adjoint().template cast().eval()*mcd.template triangularView()); + VERIFY_IS_APPROX(scd*vd.adjoint()*mcd.template triangularView(), scd*vd.adjoint().template cast().eval()*mcd.template triangularView()); + VERIFY_IS_APPROX( sd*vd.adjoint()*mcd.transpose().template triangularView(), sd*vd.adjoint().template cast().eval()*mcd.transpose().template triangularView()); + VERIFY_IS_APPROX(scd*vd.adjoint()*mcd.transpose().template triangularView(), scd*vd.adjoint().template cast().eval()*mcd.transpose().template triangularView()); + + // Not supported yet: trmm +// VERIFY_IS_APPROX(sd*mcd*md.template triangularView(), sd*mcd*md.template cast().eval().template triangularView()); +// VERIFY_IS_APPROX(scd*mcd*md.template triangularView(), scd*mcd*md.template cast().eval().template triangularView()); +// VERIFY_IS_APPROX(sd*md*mcd.template triangularView(), sd*md.template cast().eval()*mcd.template triangularView()); +// VERIFY_IS_APPROX(scd*md*mcd.template triangularView(), scd*md.template cast().eval()*mcd.template triangularView()); + + // Not supported yet: symv +// VERIFY_IS_APPROX(sd*vcd.adjoint()*md.template selfadjointView(), sd*vcd.adjoint()*md.template cast().eval().template selfadjointView()); +// VERIFY_IS_APPROX(scd*vcd.adjoint()*md.template selfadjointView(), scd*vcd.adjoint()*md.template cast().eval().template selfadjointView()); +// VERIFY_IS_APPROX(sd*vd.adjoint()*mcd.template selfadjointView(), sd*vd.adjoint().template cast().eval()*mcd.template selfadjointView()); +// VERIFY_IS_APPROX(scd*vd.adjoint()*mcd.template selfadjointView(), scd*vd.adjoint().template cast().eval()*mcd.template selfadjointView()); + + // Not supported yet: symm +// VERIFY_IS_APPROX(sd*vcd.adjoint()*md.template selfadjointView(), sd*vcd.adjoint()*md.template cast().eval().template selfadjointView()); +// VERIFY_IS_APPROX(scd*vcd.adjoint()*md.template selfadjointView(), scd*vcd.adjoint()*md.template cast().eval().template selfadjointView()); +// VERIFY_IS_APPROX(sd*vd.adjoint()*mcd.template selfadjointView(), sd*vd.adjoint().template cast().eval()*mcd.template selfadjointView()); +// VERIFY_IS_APPROX(scd*vd.adjoint()*mcd.template selfadjointView(), scd*vd.adjoint().template cast().eval()*mcd.template selfadjointView()); + + rcd.setZero(); + VERIFY_IS_APPROX(Mat_cd(rcd.template triangularView() = sd * mcd * md), + Mat_cd((sd * mcd * md.template cast().eval()).template triangularView())); + VERIFY_IS_APPROX(Mat_cd(rcd.template triangularView() = sd * md * mcd), + Mat_cd((sd * md.template cast().eval() * mcd).template triangularView())); + VERIFY_IS_APPROX(Mat_cd(rcd.template triangularView() = scd * mcd * md), + Mat_cd((scd * mcd * md.template cast().eval()).template triangularView())); + VERIFY_IS_APPROX(Mat_cd(rcd.template triangularView() = scd * md * mcd), + Mat_cd((scd * md.template cast().eval() * mcd).template triangularView())); + + + VERIFY_IS_APPROX( md.array() * mcd.array(), md.template cast().eval().array() * mcd.array() ); + VERIFY_IS_APPROX( mcd.array() * md.array(), mcd.array() * md.template cast().eval().array() ); + + VERIFY_IS_APPROX( md.array() + mcd.array(), md.template cast().eval().array() + mcd.array() ); + VERIFY_IS_APPROX( mcd.array() + md.array(), mcd.array() + md.template cast().eval().array() ); + + VERIFY_IS_APPROX( md.array() - mcd.array(), md.template cast().eval().array() - mcd.array() ); + VERIFY_IS_APPROX( mcd.array() - md.array(), mcd.array() - md.template cast().eval().array() ); + + if(mcd.array().abs().minCoeff()>epsd) + { + VERIFY_IS_APPROX( md.array() / mcd.array(), md.template cast().eval().array() / mcd.array() ); + } + if(md.array().abs().minCoeff()>epsd) + { + VERIFY_IS_APPROX( mcd.array() / md.array(), mcd.array() / md.template cast().eval().array() ); + } + + if(md.array().abs().minCoeff()>epsd || mcd.array().abs().minCoeff()>epsd) + { + VERIFY_IS_APPROX( md.array().pow(mcd.array()), md.template cast().eval().array().pow(mcd.array()) ); + VERIFY_IS_APPROX( mcd.array().pow(md.array()), mcd.array().pow(md.template cast().eval().array()) ); + + VERIFY_IS_APPROX( pow(md.array(),mcd.array()), md.template cast().eval().array().pow(mcd.array()) ); + VERIFY_IS_APPROX( pow(mcd.array(),md.array()), mcd.array().pow(md.template cast().eval().array()) ); + } + + rcd = mcd; + VERIFY_IS_APPROX( rcd = md, md.template cast().eval() ); + rcd = mcd; + VERIFY_IS_APPROX( rcd += md, mcd + md.template cast().eval() ); + rcd = mcd; + VERIFY_IS_APPROX( rcd -= md, mcd - md.template cast().eval() ); + rcd = mcd; + VERIFY_IS_APPROX( rcd.array() *= md.array(), mcd.array() * md.template cast().eval().array() ); + rcd = mcd; + if(md.array().abs().minCoeff()>epsd) + { + VERIFY_IS_APPROX( rcd.array() /= md.array(), mcd.array() / md.template cast().eval().array() ); + } + + rcd = mcd; + VERIFY_IS_APPROX( rcd.noalias() += md + mcd*md, mcd + (md.template cast().eval()) + mcd*(md.template cast().eval())); + + VERIFY_IS_APPROX( rcd.noalias() = md*md, ((md*md).eval().template cast()) ); + rcd = mcd; + VERIFY_IS_APPROX( rcd.noalias() += md*md, mcd + ((md*md).eval().template cast()) ); + rcd = mcd; + VERIFY_IS_APPROX( rcd.noalias() -= md*md, mcd - ((md*md).eval().template cast()) ); + + VERIFY_IS_APPROX( rcd.noalias() = mcd + md*md, mcd + ((md*md).eval().template cast()) ); + rcd = mcd; + VERIFY_IS_APPROX( rcd.noalias() += mcd + md*md, mcd + mcd + ((md*md).eval().template cast()) ); + rcd = mcd; + VERIFY_IS_APPROX( rcd.noalias() -= mcd + md*md, - ((md*md).eval().template cast()) ); } void test_mixingtypes() { - CALL_SUBTEST_1(mixingtypes<3>()); - CALL_SUBTEST_2(mixingtypes<4>()); - CALL_SUBTEST_3(mixingtypes(internal::random(1,EIGEN_TEST_MAX_SIZE))); + for(int i = 0; i < g_repeat; i++) { + CALL_SUBTEST_1(mixingtypes<3>()); + CALL_SUBTEST_2(mixingtypes<4>()); + CALL_SUBTEST_3(mixingtypes(internal::random(1,EIGEN_TEST_MAX_SIZE))); + + CALL_SUBTEST_4(mixingtypes<3>()); + CALL_SUBTEST_5(mixingtypes<4>()); + CALL_SUBTEST_6(mixingtypes(internal::random(1,EIGEN_TEST_MAX_SIZE))); + } } diff --git a/ground/gcs/src/libs/eigen/test/mpl2only.cpp b/ground/gcs/src/libs/eigen/test/mpl2only.cpp index 5ef0d2b2e8..7d04d6bba6 100644 --- a/ground/gcs/src/libs/eigen/test/mpl2only.cpp +++ b/ground/gcs/src/libs/eigen/test/mpl2only.cpp @@ -12,7 +12,9 @@ #include #include #include +#include #include +#include int main() { diff --git a/ground/gcs/src/libs/eigen/test/nesting_ops.cpp b/ground/gcs/src/libs/eigen/test/nesting_ops.cpp index 1e85232833..a419b0e44a 100644 --- a/ground/gcs/src/libs/eigen/test/nesting_ops.cpp +++ b/ground/gcs/src/libs/eigen/test/nesting_ops.cpp @@ -2,16 +2,37 @@ // for linear algebra. // // Copyright (C) 2010 Hauke Heibel +// Copyright (C) 2015 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. +#define TEST_ENABLE_TEMPORARY_TRACKING + #include "main.h" -template void run_nesting_ops(const MatrixType& _m) +template +void use_n_times(const XprType &xpr) { - typename MatrixType::Nested m(_m); + typename internal::nested_eval::type mat(xpr); + typename XprType::PlainObject res(mat.rows(), mat.cols()); + nb_temporaries--; // remove res + res.setZero(); + for(int i=0; i +bool verify_eval_type(const XprType &, const ReferenceType&) +{ + typedef typename internal::nested_eval::type EvalType; + return internal::is_same::type, typename internal::remove_all::type>::value; +} + +template void run_nesting_ops_1(const MatrixType& _m) +{ + typename internal::nested_eval::type m(_m); // Make really sure that we are in debug mode! VERIFY_RAISES_ASSERT(eigen_assert(false)); @@ -24,10 +45,63 @@ template void run_nesting_ops(const MatrixType& _m) VERIFY_IS_APPROX( (m.transpose() * m).array().abs().sum(), (m.transpose() * m).array().abs().sum() ); } +template void run_nesting_ops_2(const MatrixType& _m) +{ + typedef typename MatrixType::Scalar Scalar; + Index rows = _m.rows(); + Index cols = _m.cols(); + MatrixType m1 = MatrixType::Random(rows,cols); + Matrix m2; + + if((MatrixType::SizeAtCompileTime==Dynamic)) + { + VERIFY_EVALUATION_COUNT( use_n_times<1>(m1 + m1*m1), 1 ); + VERIFY_EVALUATION_COUNT( use_n_times<10>(m1 + m1*m1), 1 ); + + VERIFY_EVALUATION_COUNT( use_n_times<1>(m1.template triangularView().solve(m1.col(0))), 1 ); + VERIFY_EVALUATION_COUNT( use_n_times<10>(m1.template triangularView().solve(m1.col(0))), 1 ); + + VERIFY_EVALUATION_COUNT( use_n_times<1>(Scalar(2)*m1.template triangularView().solve(m1.col(0))), 2 ); // FIXME could be one by applying the scaling in-place on the solve result + VERIFY_EVALUATION_COUNT( use_n_times<1>(m1.col(0)+m1.template triangularView().solve(m1.col(0))), 2 ); // FIXME could be one by adding m1.col() inplace + VERIFY_EVALUATION_COUNT( use_n_times<10>(m1.col(0)+m1.template triangularView().solve(m1.col(0))), 2 ); + } + + { + VERIFY( verify_eval_type<10>(m1, m1) ); + if(!NumTraits::IsComplex) + { + VERIFY( verify_eval_type<3>(2*m1, 2*m1) ); + VERIFY( verify_eval_type<4>(2*m1, m1) ); + } + else + { + VERIFY( verify_eval_type<2>(2*m1, 2*m1) ); + VERIFY( verify_eval_type<3>(2*m1, m1) ); + } + VERIFY( verify_eval_type<2>(m1+m1, m1+m1) ); + VERIFY( verify_eval_type<3>(m1+m1, m1) ); + VERIFY( verify_eval_type<1>(m1*m1.transpose(), m2) ); + VERIFY( verify_eval_type<1>(m1*(m1+m1).transpose(), m2) ); + VERIFY( verify_eval_type<2>(m1*m1.transpose(), m2) ); + VERIFY( verify_eval_type<1>(m1+m1*m1, m1) ); + + VERIFY( verify_eval_type<1>(m1.template triangularView().solve(m1), m1) ); + VERIFY( verify_eval_type<1>(m1+m1.template triangularView().solve(m1), m1) ); + } +} + + void test_nesting_ops() { - CALL_SUBTEST_1(run_nesting_ops(MatrixXf::Random(25,25))); - CALL_SUBTEST_2(run_nesting_ops(MatrixXd::Random(25,25))); - CALL_SUBTEST_3(run_nesting_ops(Matrix4f::Random())); - CALL_SUBTEST_4(run_nesting_ops(Matrix4d::Random())); + CALL_SUBTEST_1(run_nesting_ops_1(MatrixXf::Random(25,25))); + CALL_SUBTEST_2(run_nesting_ops_1(MatrixXcd::Random(25,25))); + CALL_SUBTEST_3(run_nesting_ops_1(Matrix4f::Random())); + CALL_SUBTEST_4(run_nesting_ops_1(Matrix2d::Random())); + + Index s = internal::random(1,EIGEN_TEST_MAX_SIZE); + CALL_SUBTEST_1( run_nesting_ops_2(MatrixXf(s,s)) ); + CALL_SUBTEST_2( run_nesting_ops_2(MatrixXcd(s,s)) ); + CALL_SUBTEST_3( run_nesting_ops_2(Matrix4f()) ); + CALL_SUBTEST_4( run_nesting_ops_2(Matrix2d()) ); + TEST_SET_BUT_UNUSED_VARIABLE(s) } diff --git a/ground/gcs/src/libs/eigen/test/nomalloc.cpp b/ground/gcs/src/libs/eigen/test/nomalloc.cpp index 8e0402358e..50756c2fb4 100644 --- a/ground/gcs/src/libs/eigen/test/nomalloc.cpp +++ b/ground/gcs/src/libs/eigen/test/nomalloc.cpp @@ -8,20 +8,10 @@ // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. -// this hack is needed to make this file compiles with -pedantic (gcc) -#ifdef __GNUC__ -#define throw(X) -#endif - -#ifdef __INTEL_COMPILER - // disable "warning #76: argument to macro is empty" produced by the above hack - #pragma warning disable 76 -#endif - // discard stack allocation as that too bypasses malloc #define EIGEN_STACK_ALLOCATION_LIMIT 0 -// any heap allocation will raise an assert -#define EIGEN_NO_MALLOC +// heap allocation will raise an assert if enabled at runtime +#define EIGEN_RUNTIME_NO_MALLOC #include "main.h" #include @@ -88,14 +78,15 @@ template void nomalloc(const MatrixType& m) VERIFY_IS_APPROX(m2,m2); m2.template selfadjointView().rankUpdate(m1.col(0),-1); - m2.template selfadjointView().rankUpdate(m1.row(0),-1); + m2.template selfadjointView().rankUpdate(m1.row(0),-1); + m2.template selfadjointView().rankUpdate(m1.col(0), m1.col(0)); // rank-2 // The following fancy matrix-matrix products are not safe yet regarding static allocation -// m1 += m1.template triangularView() * m2.col(; -// m1.template selfadjointView().rankUpdate(m2); -// m1 += m1.template triangularView() * m2; -// m1 += m1.template selfadjointView() * m2; -// VERIFY_IS_APPROX(m1,m1); + m2.template selfadjointView().rankUpdate(m1); + m2 += m2.template triangularView() * m1; + m2.template triangularView() = m2 * m2; + m1 += m1.template selfadjointView() * m2; + VERIFY_IS_APPROX(m2,m2); } template @@ -171,7 +162,7 @@ void test_zerosized() { Eigen::VectorXd v; // explicit zero-sized: Eigen::ArrayXXd A0(0,0); - Eigen::ArrayXd v0(std::ptrdiff_t(0)); // FIXME ArrayXd(0) is ambiguous + Eigen::ArrayXd v0(0); // assigning empty objects to each other: A=A0; @@ -183,9 +174,11 @@ template void test_reference(const MatrixType& m) { enum { Flag = MatrixType::IsRowMajor ? Eigen::RowMajor : Eigen::ColMajor}; enum { TransposeFlag = !MatrixType::IsRowMajor ? Eigen::RowMajor : Eigen::ColMajor}; typename MatrixType::Index rows = m.rows(), cols=m.cols(); + typedef Eigen::Matrix MatrixX; + typedef Eigen::Matrix MatrixXT; // Dynamic reference: - typedef Eigen::Ref > Ref; - typedef Eigen::Ref > RefT; + typedef Eigen::Ref Ref; + typedef Eigen::Ref RefT; Ref r1(m); Ref r2(m.block(rows/3, cols/4, rows/2, cols/2)); @@ -195,10 +188,30 @@ template void test_reference(const MatrixType& m) { VERIFY_RAISES_ASSERT(RefT r5(m)); VERIFY_RAISES_ASSERT(Ref r6(m.transpose())); VERIFY_RAISES_ASSERT(Ref r7(Scalar(2) * m)); + + // Copy constructors shall also never malloc + Ref r8 = r1; + RefT r9 = r3; + + // Initializing from a compatible Ref shall also never malloc + Eigen::Ref > r10=r8, r11=m; + + // Initializing from an incompatible Ref will malloc: + typedef Eigen::Ref RefAligned; + VERIFY_RAISES_ASSERT(RefAligned r12=r10); + VERIFY_RAISES_ASSERT(Ref r13=r10); // r10 has more dynamic strides + } void test_nomalloc() { + // create some dynamic objects + Eigen::MatrixXd M1 = MatrixXd::Random(3,3); + Ref R1 = 2.0*M1; // Ref requires temporary + + // from here on prohibit malloc: + Eigen::internal::set_is_malloc_allowed(false); + // check that our operator new is indeed called: VERIFY_RAISES_ASSERT(MatrixXd dummy(MatrixXd::Random(3,3))); CALL_SUBTEST_1(nomalloc(Matrix()) ); @@ -207,6 +220,10 @@ void test_nomalloc() // Check decomposition modules with dynamic matrices that have a known compile-time max size (ctms) CALL_SUBTEST_4(ctms_decompositions()); + CALL_SUBTEST_5(test_zerosized()); + CALL_SUBTEST_6(test_reference(Matrix())); + CALL_SUBTEST_7(test_reference(R1)); + CALL_SUBTEST_8(Ref R2 = M1.topRows<2>(); test_reference(R2)); } diff --git a/ground/gcs/src/libs/eigen/test/nullary.cpp b/ground/gcs/src/libs/eigen/test/nullary.cpp index fbc721a1a1..acd55506e9 100644 --- a/ground/gcs/src/libs/eigen/test/nullary.cpp +++ b/ground/gcs/src/libs/eigen/test/nullary.cpp @@ -2,6 +2,7 @@ // for linear algebra. // // Copyright (C) 2010-2011 Jitse Niesen +// Copyright (C) 2016 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -12,7 +13,6 @@ template bool equalsIdentity(const MatrixType& A) { - typedef typename MatrixType::Index Index; typedef typename MatrixType::Scalar Scalar; Scalar zero = static_cast(0); @@ -30,13 +30,41 @@ bool equalsIdentity(const MatrixType& A) bool diagOK = (A.diagonal().array() == 1).all(); return offDiagOK && diagOK; + +} + +template +void check_extremity_accuracy(const VectorType &v, const typename VectorType::Scalar &low, const typename VectorType::Scalar &high) +{ + typedef typename VectorType::Scalar Scalar; + typedef typename VectorType::RealScalar RealScalar; + + RealScalar prec = internal::is_same::value ? NumTraits::dummy_precision()*10 : NumTraits::dummy_precision()/10; + Index size = v.size(); + + if(size<20) + return; + + for (int i=0; isize-6) + { + Scalar ref = (low*RealScalar(size-i-1))/RealScalar(size-1) + (high*RealScalar(i))/RealScalar(size-1); + if(std::abs(ref)>1) + { + if(!internal::isApprox(v(i), ref, prec)) + std::cout << v(i) << " != " << ref << " ; relative error: " << std::abs((v(i)-ref)/ref) << " ; required precision: " << prec << " ; range: " << low << "," << high << " ; i: " << i << "\n"; + VERIFY(internal::isApprox(v(i), (low*RealScalar(size-i-1))/RealScalar(size-1) + (high*RealScalar(i))/RealScalar(size-1), prec)); + } + } + } } template void testVectorType(const VectorType& base) { - typedef typename internal::traits::Index Index; - typedef typename internal::traits::Scalar Scalar; + typedef typename VectorType::Scalar Scalar; + typedef typename VectorType::RealScalar RealScalar; const Index size = base.size(); @@ -44,36 +72,61 @@ void testVectorType(const VectorType& base) Scalar low = (size == 1 ? high : internal::random(-500,500)); if (low>high) std::swap(low,high); + // check low==high + if(internal::random(0.f,1.f)<0.05f) + low = high; + // check abs(low) >> abs(high) + else if(size>2 && std::numeric_limits::max_exponent10>0 && internal::random(0.f,1.f)<0.1f) + low = -internal::random(1,2) * RealScalar(std::pow(RealScalar(10),std::numeric_limits::max_exponent10/2)); + const Scalar step = ((size == 1) ? 1 : (high-low)/(size-1)); // check whether the result yields what we expect it to do VectorType m(base); m.setLinSpaced(size,low,high); - VectorType n(size); - for (int i=0; i::IsInteger) + { + VectorType n(size); + for (int i=0; i::IsInteger) || ((high-low)>=size && (Index(high-low)%(size-1))==0) || (Index(high-low+1)::IsInteger) || (high-low>=size)) + for (int i=0; i::epsilon() ); + // random access version + m = VectorType::LinSpaced(size,low,high); + VERIFY_IS_APPROX(m,n); + VERIFY( internal::isApprox(m(m.size()-1),high) ); + VERIFY( size==1 || internal::isApprox(m(0),low) ); + VERIFY_IS_EQUAL(m(m.size()-1) , high); + if(!NumTraits::IsInteger) + CALL_SUBTEST( check_extremity_accuracy(m, low, high) ); + } - // These guys sometimes fail! This is not good. Any ideas how to fix them!? - //VERIFY( m(m.size()-1) == high ); - //VERIFY( m(0) == low ); + VERIFY( m(m.size()-1) <= high ); + VERIFY( (m.array() <= high).all() ); + VERIFY( (m.array() >= low).all() ); - // sequential access version - m = VectorType::LinSpaced(Sequential,size,low,high); - VERIFY_IS_APPROX(m,n); - // These guys sometimes fail! This is not good. Any ideas how to fix them!? - //VERIFY( m(m.size()-1) == high ); - //VERIFY( m(0) == low ); + VERIFY( m(m.size()-1) >= low ); + if(size>=1) + { + VERIFY( internal::isApprox(m(0),low) ); + VERIFY_IS_EQUAL(m(0) , low); + } // check whether everything works with row and col major vectors Matrix row_vector(size); @@ -95,23 +148,77 @@ void testVectorType(const VectorType& base) VERIFY_IS_APPROX( ScalarMatrix::LinSpaced(1,low,high), ScalarMatrix::Constant(high) ); // regression test for bug 526 (linear vectorized transversal) - if (size > 1) { + if (size > 1 && (!NumTraits::IsInteger)) { m.tail(size-1).setLinSpaced(low, high); VERIFY_IS_APPROX(m(size-1), high); } + + // regression test for bug 1383 (LinSpaced with empty size/range) + { + Index n0 = VectorType::SizeAtCompileTime==Dynamic ? 0 : VectorType::SizeAtCompileTime; + low = internal::random(); + m = VectorType::LinSpaced(n0,low,low-1); + VERIFY(m.size()==n0); + + if(VectorType::SizeAtCompileTime==Dynamic) + { + VERIFY_IS_EQUAL(VectorType::LinSpaced(n0,0,Scalar(n0-1)).sum(),Scalar(0)); + VERIFY_IS_EQUAL(VectorType::LinSpaced(n0,low,low-1).sum(),Scalar(0)); + } + + m.setLinSpaced(n0,0,Scalar(n0-1)); + VERIFY(m.size()==n0); + m.setLinSpaced(n0,low,low-1); + VERIFY(m.size()==n0); + + // empty range only: + VERIFY_IS_APPROX(VectorType::LinSpaced(size,low,low),VectorType::Constant(size,low)); + m.setLinSpaced(size,low,low); + VERIFY_IS_APPROX(m,VectorType::Constant(size,low)); + + if(NumTraits::IsInteger) + { + VERIFY_IS_APPROX( VectorType::LinSpaced(size,low,Scalar(low+size-1)), VectorType::LinSpaced(size,Scalar(low+size-1),low).reverse() ); + + if(VectorType::SizeAtCompileTime==Dynamic) + { + // Check negative multiplicator path: + for(Index k=1; k<5; ++k) + VERIFY_IS_APPROX( VectorType::LinSpaced(size,low,Scalar(low+(size-1)*k)), VectorType::LinSpaced(size,Scalar(low+(size-1)*k),low).reverse() ); + // Check negative divisor path: + for(Index k=1; k<5; ++k) + VERIFY_IS_APPROX( VectorType::LinSpaced(size*k,low,Scalar(low+size-1)), VectorType::LinSpaced(size*k,Scalar(low+size-1),low).reverse() ); + } + } + } } template void testMatrixType(const MatrixType& m) { - typedef typename MatrixType::Index Index; + using std::abs; const Index rows = m.rows(); const Index cols = m.cols(); + typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::RealScalar RealScalar; + + Scalar s1; + do { + s1 = internal::random(); + } while(abs(s1)::IsInteger)); MatrixType A; A.setIdentity(rows, cols); VERIFY(equalsIdentity(A)); VERIFY(equalsIdentity(MatrixType::Identity(rows, cols))); + + + A = MatrixType::Constant(rows,cols,s1); + Index i = internal::random(0,rows-1); + Index j = internal::random(0,cols-1); + VERIFY_IS_APPROX( MatrixType::Constant(rows,cols,s1)(i,j), s1 ); + VERIFY_IS_APPROX( MatrixType::Constant(rows,cols,s1).coeff(i,j), s1 ); + VERIFY_IS_APPROX( A(i,j), s1 ); } void test_nullary() @@ -120,12 +227,78 @@ void test_nullary() CALL_SUBTEST_2( testMatrixType(MatrixXcf(internal::random(1,300),internal::random(1,300))) ); CALL_SUBTEST_3( testMatrixType(MatrixXf(internal::random(1,300),internal::random(1,300))) ); - for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST_4( testVectorType(VectorXd(internal::random(1,300))) ); + for(int i = 0; i < g_repeat*10; i++) { + CALL_SUBTEST_4( testVectorType(VectorXd(internal::random(1,30000))) ); CALL_SUBTEST_5( testVectorType(Vector4d()) ); // regression test for bug 232 CALL_SUBTEST_6( testVectorType(Vector3d()) ); - CALL_SUBTEST_7( testVectorType(VectorXf(internal::random(1,300))) ); + CALL_SUBTEST_7( testVectorType(VectorXf(internal::random(1,30000))) ); CALL_SUBTEST_8( testVectorType(Vector3f()) ); + CALL_SUBTEST_8( testVectorType(Vector4f()) ); + CALL_SUBTEST_8( testVectorType(Matrix()) ); CALL_SUBTEST_8( testVectorType(Matrix()) ); + + CALL_SUBTEST_9( testVectorType(VectorXi(internal::random(1,10))) ); + CALL_SUBTEST_9( testVectorType(VectorXi(internal::random(9,300))) ); + CALL_SUBTEST_9( testVectorType(Matrix()) ); + } + +#ifdef EIGEN_TEST_PART_6 + // Assignment of a RowVectorXd to a MatrixXd (regression test for bug #79). + VERIFY( (MatrixXd(RowVectorXd::LinSpaced(3, 0, 1)) - RowVector3d(0, 0.5, 1)).norm() < std::numeric_limits::epsilon() ); +#endif + +#ifdef EIGEN_TEST_PART_9 + // Check possible overflow issue + { + int n = 60000; + ArrayXi a1(n), a2(n); + a1.setLinSpaced(n, 0, n-1); + for(int i=0; i >::value )); + VERIFY(( !internal::has_unary_operator >::value )); + VERIFY(( !internal::has_binary_operator >::value )); + VERIFY(( internal::functor_has_linear_access >::ret )); + + VERIFY(( !internal::has_nullary_operator >::value )); + VERIFY(( !internal::has_unary_operator >::value )); + VERIFY(( internal::has_binary_operator >::value )); + VERIFY(( !internal::functor_has_linear_access >::ret )); + + VERIFY(( !internal::has_nullary_operator >::value )); + VERIFY(( internal::has_unary_operator >::value )); + VERIFY(( !internal::has_binary_operator >::value )); + VERIFY(( internal::functor_has_linear_access >::ret )); + + // Regression unit test for a weird MSVC bug. + // Search "nullary_wrapper_workaround_msvc" in CoreEvaluators.h for the details. + // See also traits::match. + { + MatrixXf A = MatrixXf::Random(3,3); + Ref R = 2.0*A; + VERIFY_IS_APPROX(R, A+A); + + Ref R1 = MatrixXf::Random(3,3)+A; + + VectorXi V = VectorXi::Random(3); + Ref R2 = VectorXi::LinSpaced(3,1,3)+V; + VERIFY_IS_APPROX(R2, V+Vector3i(1,2,3)); + + VERIFY(( internal::has_nullary_operator >::value )); + VERIFY(( !internal::has_unary_operator >::value )); + VERIFY(( !internal::has_binary_operator >::value )); + VERIFY(( internal::functor_has_linear_access >::ret )); + + VERIFY(( !internal::has_nullary_operator >::value )); + VERIFY(( internal::has_unary_operator >::value )); + VERIFY(( !internal::has_binary_operator >::value )); + VERIFY(( internal::functor_has_linear_access >::ret )); } +#endif } diff --git a/ground/gcs/src/libs/eigen/test/packetmath.cpp b/ground/gcs/src/libs/eigen/test/packetmath.cpp index 38aa256ce8..7821a1738d 100644 --- a/ground/gcs/src/libs/eigen/test/packetmath.cpp +++ b/ground/gcs/src/libs/eigen/test/packetmath.cpp @@ -9,16 +9,28 @@ // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #include "main.h" +#include "unsupported/Eigen/SpecialFunctions" +#if defined __GNUC__ && __GNUC__>=6 + #pragma GCC diagnostic ignored "-Wignored-attributes" +#endif // using namespace Eigen; +#ifdef EIGEN_VECTORIZE_SSE +const bool g_vectorize_sse = true; +#else +const bool g_vectorize_sse = false; +#endif + namespace Eigen { namespace internal { template T negate(const T& x) { return -x; } } } -template bool isApproxAbs(const Scalar& a, const Scalar& b, const typename NumTraits::Real& refvalue) +// NOTE: we disbale inlining for this function to workaround a GCC issue when using -O3 and the i387 FPU. +template EIGEN_DONT_INLINE +bool isApproxAbs(const Scalar& a, const Scalar& b, const typename NumTraits::Real& refvalue) { return internal::isMuchSmallerThan(a-b, refvalue); } @@ -29,7 +41,7 @@ template bool areApproxAbs(const Scalar* a, const Scalar* b, in { if (!isApproxAbs(a[i],b[i],refvalue)) { - std::cout << "[" << Map >(a,size) << "]" << " != " << Map >(b,size) << "\n"; + std::cout << "ref: [" << Map >(a,size) << "]" << " != vec: [" << Map >(b,size) << "]\n"; return false; } } @@ -42,21 +54,13 @@ template bool areApprox(const Scalar* a, const Scalar* b, int s { if (a[i]!=b[i] && !internal::isApprox(a[i],b[i])) { - std::cout << "[" << Map >(a,size) << "]" << " != " << Map >(b,size) << "\n"; + std::cout << "ref: [" << Map >(a,size) << "]" << " != vec: [" << Map >(b,size) << "]\n"; return false; } } return true; } - -#define CHECK_CWISE2(REFOP, POP) { \ - for (int i=0; i(data1), internal::pload(data1+PacketSize))); \ - VERIFY(areApprox(ref, data2, PacketSize) && #POP); \ -} - #define CHECK_CWISE1(REFOP, POP) { \ for (int i=0; i VERIFY(areApprox(ref, data2, PacketSize) && #POP); \ } +#define CHECK_CWISE2_IF(COND, REFOP, POP) if(COND) { \ + packet_helper h; \ + for (int i=0; i template void packetmath() { using std::abs; - typedef typename internal::packet_traits::type Packet; - const int PacketSize = internal::packet_traits::size; + typedef internal::packet_traits PacketTraits; + typedef typename PacketTraits::type Packet; + const int PacketSize = PacketTraits::size; typedef typename NumTraits::Real RealScalar; - const int size = PacketSize*4; - EIGEN_ALIGN16 Scalar data1[internal::packet_traits::size*4]; - EIGEN_ALIGN16 Scalar data2[internal::packet_traits::size*4]; - EIGEN_ALIGN16 Packet packets[PacketSize*2]; - EIGEN_ALIGN16 Scalar ref[internal::packet_traits::size*4]; + const int max_size = PacketSize > 4 ? PacketSize : 4; + const int size = PacketSize*max_size; + EIGEN_ALIGN_MAX Scalar data1[size]; + EIGEN_ALIGN_MAX Scalar data2[size]; + EIGEN_ALIGN_MAX Packet packets[PacketSize*2]; + EIGEN_ALIGN_MAX Scalar ref[size]; RealScalar refvalue = 0; for (int i=0; i void packetmath() else if (offset==1) internal::palign<1>(packets[0], packets[1]); else if (offset==2) internal::palign<2>(packets[0], packets[1]); else if (offset==3) internal::palign<3>(packets[0], packets[1]); + else if (offset==4) internal::palign<4>(packets[0], packets[1]); + else if (offset==5) internal::palign<5>(packets[0], packets[1]); + else if (offset==6) internal::palign<6>(packets[0], packets[1]); + else if (offset==7) internal::palign<7>(packets[0], packets[1]); + else if (offset==8) internal::palign<8>(packets[0], packets[1]); + else if (offset==9) internal::palign<9>(packets[0], packets[1]); + else if (offset==10) internal::palign<10>(packets[0], packets[1]); + else if (offset==11) internal::palign<11>(packets[0], packets[1]); + else if (offset==12) internal::palign<12>(packets[0], packets[1]); + else if (offset==13) internal::palign<13>(packets[0], packets[1]); + else if (offset==14) internal::palign<14>(packets[0], packets[1]); + else if (offset==15) internal::palign<15>(packets[0], packets[1]); internal::pstore(data2, packets[0]); for (int i=0; i void packetmath() VERIFY(areApprox(ref, data2, PacketSize) && "internal::palign"); } - CHECK_CWISE2(REF_ADD, internal::padd); - CHECK_CWISE2(REF_SUB, internal::psub); - CHECK_CWISE2(REF_MUL, internal::pmul); - #ifndef EIGEN_VECTORIZE_ALTIVEC - if (!internal::is_same::value) - CHECK_CWISE2(REF_DIV, internal::pdiv); - #endif + VERIFY((!PacketTraits::Vectorizable) || PacketTraits::HasAdd); + VERIFY((!PacketTraits::Vectorizable) || PacketTraits::HasSub); + VERIFY((!PacketTraits::Vectorizable) || PacketTraits::HasMul); + VERIFY((!PacketTraits::Vectorizable) || PacketTraits::HasNegate); + VERIFY((internal::is_same::value) || (!PacketTraits::Vectorizable) || PacketTraits::HasDiv); + + CHECK_CWISE2_IF(PacketTraits::HasAdd, REF_ADD, internal::padd); + CHECK_CWISE2_IF(PacketTraits::HasSub, REF_SUB, internal::psub); + CHECK_CWISE2_IF(PacketTraits::HasMul, REF_MUL, internal::pmul); + CHECK_CWISE2_IF(PacketTraits::HasDiv, REF_DIV, internal::pdiv); + CHECK_CWISE1(internal::negate, internal::pnegate); CHECK_CWISE1(numext::conj, internal::pconj); @@ -165,9 +195,31 @@ template void packetmath() internal::pstore(data2, internal::pset1(data1[offset])); VERIFY(areApprox(ref, data2, PacketSize) && "internal::pset1"); } - + + { + for (int i=0; i(data1, A0, A1, A2, A3); + internal::pstore(data2+0*PacketSize, A0); + internal::pstore(data2+1*PacketSize, A1); + internal::pstore(data2+2*PacketSize, A2); + internal::pstore(data2+3*PacketSize, A3); + VERIFY(areApprox(ref, data2, 4*PacketSize) && "internal::pbroadcast4"); + } + + { + for (int i=0; i(data1, A0, A1); + internal::pstore(data2+0*PacketSize, A0); + internal::pstore(data2+1*PacketSize, A1); + VERIFY(areApprox(ref, data2, 2*PacketSize) && "internal::pbroadcast2"); + } + VERIFY(internal::isApprox(data1[0], internal::pfirst(internal::pload(data1))) && "internal::pfirst"); - + if(PacketSize>1) { for(int offset=0;offset<4;++offset) @@ -179,11 +231,31 @@ template void packetmath() } } + if(PacketSize>2) + { + for(int offset=0;offset<4;++offset) + { + for(int i=0;i(data1+offset)); + VERIFY(areApprox(ref, data2, PacketSize) && "ploadquad"); + } + } + ref[0] = 0; for (int i=0; i(data1)), refvalue) && "internal::predux"); + { + for (int i=0; i<4; ++i) + ref[i] = 0; + for (int i=0; i(data1))); + VERIFY(areApprox(ref, data2, PacketSize>4?PacketSize/2:PacketSize) && "internal::predux_downto4"); + } + ref[0] = 1; for (int i=0; i void packetmath() ref[i] = data1[PacketSize-i-1]; internal::pstore(data2, internal::preverse(internal::pload(data1))); VERIFY(areApprox(ref, data2, PacketSize) && "internal::preverse"); + + internal::PacketBlock kernel; + for (int i=0; i(data1+i*PacketSize); + } + ptranspose(kernel); + for (int i=0; i(data1); + Packet elsePacket = internal::pload(data2); + EIGEN_ALIGN_MAX internal::Selector selector; + for (int i = 0; i < PacketSize; ++i) { + selector.select[i] = i; + } + + Packet blend = internal::pblend(selector, thenPacket, elsePacket); + EIGEN_ALIGN_MAX Scalar result[size]; + internal::pstore(result, blend); + for (int i = 0; i < PacketSize; ++i) { + VERIFY(isApproxAbs(result[i], (selector.select[i] ? data1[i] : data2[i]), refvalue)); + } + } + + if (PacketTraits::HasBlend || g_vectorize_sse) { + // pinsertfirst + for (int i=0; i(); + ref[0] = s; + internal::pstore(data2, internal::pinsertfirst(internal::pload(data1),s)); + VERIFY(areApprox(ref, data2, PacketSize) && "internal::pinsertfirst"); + } + + if (PacketTraits::HasBlend || g_vectorize_sse) { + // pinsertlast + for (int i=0; i(); + ref[PacketSize-1] = s; + internal::pstore(data2, internal::pinsertlast(internal::pload(data1),s)); + VERIFY(areApprox(ref, data2, PacketSize) && "internal::pinsertlast"); + } } template void packetmath_real() { using std::abs; - typedef typename internal::packet_traits::type Packet; - const int PacketSize = internal::packet_traits::size; + typedef internal::packet_traits PacketTraits; + typedef typename PacketTraits::type Packet; + const int PacketSize = PacketTraits::size; const int size = PacketSize*4; - EIGEN_ALIGN16 Scalar data1[internal::packet_traits::size*4]; - EIGEN_ALIGN16 Scalar data2[internal::packet_traits::size*4]; - EIGEN_ALIGN16 Scalar ref[internal::packet_traits::size*4]; + EIGEN_ALIGN_MAX Scalar data1[PacketTraits::size*4]; + EIGEN_ALIGN_MAX Scalar data2[PacketTraits::size*4]; + EIGEN_ALIGN_MAX Scalar ref[PacketTraits::size*4]; for (int i=0; i(-1,1) * std::pow(Scalar(10), internal::random(-3,3)); data2[i] = internal::random(-1,1) * std::pow(Scalar(10), internal::random(-3,3)); } - CHECK_CWISE1_IF(internal::packet_traits::HasSin, std::sin, internal::psin); - CHECK_CWISE1_IF(internal::packet_traits::HasCos, std::cos, internal::pcos); - CHECK_CWISE1_IF(internal::packet_traits::HasTan, std::tan, internal::ptan); - + CHECK_CWISE1_IF(PacketTraits::HasSin, std::sin, internal::psin); + CHECK_CWISE1_IF(PacketTraits::HasCos, std::cos, internal::pcos); + CHECK_CWISE1_IF(PacketTraits::HasTan, std::tan, internal::ptan); + + CHECK_CWISE1_IF(PacketTraits::HasRound, numext::round, internal::pround); + CHECK_CWISE1_IF(PacketTraits::HasCeil, numext::ceil, internal::pceil); + CHECK_CWISE1_IF(PacketTraits::HasFloor, numext::floor, internal::pfloor); + for (int i=0; i(-1,1); data2[i] = internal::random(-1,1); } - CHECK_CWISE1_IF(internal::packet_traits::HasASin, std::asin, internal::pasin); - CHECK_CWISE1_IF(internal::packet_traits::HasACos, std::acos, internal::pacos); + CHECK_CWISE1_IF(PacketTraits::HasASin, std::asin, internal::pasin); + CHECK_CWISE1_IF(PacketTraits::HasACos, std::acos, internal::pacos); for (int i=0; i(-87,88); data2[i] = internal::random(-87,88); } - CHECK_CWISE1_IF(internal::packet_traits::HasExp, std::exp, internal::pexp); + CHECK_CWISE1_IF(PacketTraits::HasExp, std::exp, internal::pexp); + for (int i=0; i(-1,1) * std::pow(Scalar(10), internal::random(-6,6)); + data2[i] = internal::random(-1,1) * std::pow(Scalar(10), internal::random(-6,6)); + } + CHECK_CWISE1_IF(PacketTraits::HasTanh, std::tanh, internal::ptanh); + if(PacketTraits::HasExp && PacketTraits::size>=2) + { + data1[0] = std::numeric_limits::quiet_NaN(); + data1[1] = std::numeric_limits::epsilon(); + packet_helper h; + h.store(data2, internal::pexp(h.load(data1))); + VERIFY((numext::isnan)(data2[0])); + VERIFY_IS_EQUAL(std::exp(std::numeric_limits::epsilon()), data2[1]); + + data1[0] = -std::numeric_limits::epsilon(); + data1[1] = 0; + h.store(data2, internal::pexp(h.load(data1))); + VERIFY_IS_EQUAL(std::exp(-std::numeric_limits::epsilon()), data2[0]); + VERIFY_IS_EQUAL(std::exp(Scalar(0)), data2[1]); + + data1[0] = (std::numeric_limits::min)(); + data1[1] = -(std::numeric_limits::min)(); + h.store(data2, internal::pexp(h.load(data1))); + VERIFY_IS_EQUAL(std::exp((std::numeric_limits::min)()), data2[0]); + VERIFY_IS_EQUAL(std::exp(-(std::numeric_limits::min)()), data2[1]); + + data1[0] = std::numeric_limits::denorm_min(); + data1[1] = -std::numeric_limits::denorm_min(); + h.store(data2, internal::pexp(h.load(data1))); + VERIFY_IS_EQUAL(std::exp(std::numeric_limits::denorm_min()), data2[0]); + VERIFY_IS_EQUAL(std::exp(-std::numeric_limits::denorm_min()), data2[1]); + } + + if (PacketTraits::HasTanh) { + // NOTE this test migh fail with GCC prior to 6.3, see MathFunctionsImpl.h for details. + data1[0] = std::numeric_limits::quiet_NaN(); + packet_helper::HasTanh,Packet> h; + h.store(data2, internal::ptanh(h.load(data1))); + VERIFY((numext::isnan)(data2[0])); + } + +#if EIGEN_HAS_C99_MATH + { + data1[0] = std::numeric_limits::quiet_NaN(); + packet_helper::HasLGamma,Packet> h; + h.store(data2, internal::plgamma(h.load(data1))); + VERIFY((numext::isnan)(data2[0])); + } { data1[0] = std::numeric_limits::quiet_NaN(); - packet_helper::HasExp,Packet> h; - h.store(data2, internal::pexp(h.load(data1))); - VERIFY(isNaN(data2[0])); + packet_helper::HasErf,Packet> h; + h.store(data2, internal::perf(h.load(data1))); + VERIFY((numext::isnan)(data2[0])); } + { + data1[0] = std::numeric_limits::quiet_NaN(); + packet_helper::HasErfc,Packet> h; + h.store(data2, internal::perfc(h.load(data1))); + VERIFY((numext::isnan)(data2[0])); + } +#endif // EIGEN_HAS_C99_MATH for (int i=0; i(0,1) * std::pow(Scalar(10), internal::random(-6,6)); data2[i] = internal::random(0,1) * std::pow(Scalar(10), internal::random(-6,6)); } - if(internal::random(0,1)<0.1) + + if(internal::random(0,1)<0.1f) data1[internal::random(0, PacketSize)] = 0; - CHECK_CWISE1_IF(internal::packet_traits::HasSqrt, std::sqrt, internal::psqrt); - CHECK_CWISE1_IF(internal::packet_traits::HasLog, std::log, internal::plog); + CHECK_CWISE1_IF(PacketTraits::HasSqrt, std::sqrt, internal::psqrt); + CHECK_CWISE1_IF(PacketTraits::HasLog, std::log, internal::plog); +#if EIGEN_HAS_C99_MATH && (__cplusplus > 199711L) + CHECK_CWISE1_IF(PacketTraits::HasLog1p, std::log1p, internal::plog1p); + CHECK_CWISE1_IF(internal::packet_traits::HasLGamma, std::lgamma, internal::plgamma); + CHECK_CWISE1_IF(internal::packet_traits::HasErf, std::erf, internal::perf); + CHECK_CWISE1_IF(internal::packet_traits::HasErfc, std::erfc, internal::perfc); +#endif + + if(PacketTraits::HasLog && PacketTraits::size>=2) { data1[0] = std::numeric_limits::quiet_NaN(); - packet_helper::HasLog,Packet> h; + data1[1] = std::numeric_limits::epsilon(); + packet_helper h; h.store(data2, internal::plog(h.load(data1))); - VERIFY(isNaN(data2[0])); - data1[0] = -1.0f; + VERIFY((numext::isnan)(data2[0])); + VERIFY_IS_EQUAL(std::log(std::numeric_limits::epsilon()), data2[1]); + + data1[0] = -std::numeric_limits::epsilon(); + data1[1] = 0; + h.store(data2, internal::plog(h.load(data1))); + VERIFY((numext::isnan)(data2[0])); + VERIFY_IS_EQUAL(std::log(Scalar(0)), data2[1]); + + data1[0] = (std::numeric_limits::min)(); + data1[1] = -(std::numeric_limits::min)(); + h.store(data2, internal::plog(h.load(data1))); + VERIFY_IS_EQUAL(std::log((std::numeric_limits::min)()), data2[0]); + VERIFY((numext::isnan)(data2[1])); + + data1[0] = std::numeric_limits::denorm_min(); + data1[1] = -std::numeric_limits::denorm_min(); + h.store(data2, internal::plog(h.load(data1))); + // VERIFY_IS_EQUAL(std::log(std::numeric_limits::denorm_min()), data2[0]); + VERIFY((numext::isnan)(data2[1])); + + data1[0] = Scalar(-1.0f); h.store(data2, internal::plog(h.load(data1))); - VERIFY(isNaN(data2[0])); -#if !EIGEN_FAST_MATH + VERIFY((numext::isnan)(data2[0])); h.store(data2, internal::psqrt(h.load(data1))); - VERIFY(isNaN(data2[0])); - VERIFY(isNaN(data2[1])); -#endif + VERIFY((numext::isnan)(data2[0])); + VERIFY((numext::isnan)(data2[1])); } } template void packetmath_notcomplex() { using std::abs; - typedef typename internal::packet_traits::type Packet; - const int PacketSize = internal::packet_traits::size; + typedef internal::packet_traits PacketTraits; + typedef typename PacketTraits::type Packet; + const int PacketSize = PacketTraits::size; + + EIGEN_ALIGN_MAX Scalar data1[PacketTraits::size*4]; + EIGEN_ALIGN_MAX Scalar data2[PacketTraits::size*4]; + EIGEN_ALIGN_MAX Scalar ref[PacketTraits::size*4]; - EIGEN_ALIGN16 Scalar data1[internal::packet_traits::size*4]; - EIGEN_ALIGN16 Scalar data2[internal::packet_traits::size*4]; - EIGEN_ALIGN16 Scalar ref[internal::packet_traits::size*4]; - - Array::Map(data1, internal::packet_traits::size*4).setRandom(); + Array::Map(data1, PacketTraits::size*4).setRandom(); ref[0] = data1[0]; for (int i=0; i(data1))) && "internal::predux_min"); - CHECK_CWISE2((std::min), internal::pmin); - CHECK_CWISE2((std::max), internal::pmax); + VERIFY((!PacketTraits::Vectorizable) || PacketTraits::HasMin); + VERIFY((!PacketTraits::Vectorizable) || PacketTraits::HasMax); + + CHECK_CWISE2_IF(PacketTraits::HasMin, (std::min), internal::pmin); + CHECK_CWISE2_IF(PacketTraits::HasMax, (std::max), internal::pmax); CHECK_CWISE1(abs, internal::pabs); ref[0] = data1[0]; for (int i=0; i(data1))) && "internal::predux_max"); - + for (int i=0; i(data1[0])); VERIFY(areApprox(ref, data2, PacketSize) && "internal::plset"); } template void test_conj_helper(Scalar* data1, Scalar* data2, Scalar* ref, Scalar* pval) { - typedef typename internal::packet_traits::type Packet; - const int PacketSize = internal::packet_traits::size; - + typedef internal::packet_traits PacketTraits; + typedef typename PacketTraits::type Packet; + const int PacketSize = PacketTraits::size; + internal::conj_if cj0; internal::conj_if cj1; internal::conj_helper cj; internal::conj_helper pcj; - + for(int i=0;i void test_conj_helper(Scalar } internal::pstore(pval,pcj.pmul(internal::pload(data1),internal::pload(data2))); VERIFY(areApprox(ref, pval, PacketSize) && "conj_helper pmul"); - + for(int i=0;i void test_conj_helper(Scalar template void packetmath_complex() { - typedef typename internal::packet_traits::type Packet; - const int PacketSize = internal::packet_traits::size; + typedef internal::packet_traits PacketTraits; + typedef typename PacketTraits::type Packet; + const int PacketSize = PacketTraits::size; const int size = PacketSize*4; - EIGEN_ALIGN16 Scalar data1[PacketSize*4]; - EIGEN_ALIGN16 Scalar data2[PacketSize*4]; - EIGEN_ALIGN16 Scalar ref[PacketSize*4]; - EIGEN_ALIGN16 Scalar pval[PacketSize*4]; + EIGEN_ALIGN_MAX Scalar data1[PacketSize*4]; + EIGEN_ALIGN_MAX Scalar data2[PacketSize*4]; + EIGEN_ALIGN_MAX Scalar ref[PacketSize*4]; + EIGEN_ALIGN_MAX Scalar pval[PacketSize*4]; for (int i=0; i() * Scalar(1e2); data2[i] = internal::random() * Scalar(1e2); } - + test_conj_helper (data1,data2,ref,pval); test_conj_helper (data1,data2,ref,pval); test_conj_helper (data1,data2,ref,pval); test_conj_helper (data1,data2,ref,pval); - + { for(int i=0;i(data1))); VERIFY(areApprox(ref, pval, PacketSize) && "pcplxflip"); } - - +} + +template void packetmath_scatter_gather() +{ + typedef internal::packet_traits PacketTraits; + typedef typename PacketTraits::type Packet; + typedef typename NumTraits::Real RealScalar; + const int PacketSize = PacketTraits::size; + EIGEN_ALIGN_MAX Scalar data1[PacketSize]; + RealScalar refvalue = 0; + for (int i=0; i()/RealScalar(PacketSize); + } + + int stride = internal::random(1,20); + + EIGEN_ALIGN_MAX Scalar buffer[PacketSize*20]; + memset(buffer, 0, 20*PacketSize*sizeof(Scalar)); + Packet packet = internal::pload(data1); + internal::pscatter(buffer, packet, stride); + + for (int i = 0; i < PacketSize*20; ++i) { + if ((i%stride) == 0 && i()/RealScalar(PacketSize); + } + packet = internal::pgather(buffer, 7); + internal::pstore(data1, packet); + for (int i = 0; i < PacketSize; ++i) { + VERIFY(isApproxAbs(data1[i], buffer[i*7], refvalue) && "pgather"); + } } void test_packetmath() @@ -369,17 +619,23 @@ void test_packetmath() CALL_SUBTEST_1( packetmath() ); CALL_SUBTEST_2( packetmath() ); CALL_SUBTEST_3( packetmath() ); - CALL_SUBTEST_1( packetmath >() ); - CALL_SUBTEST_2( packetmath >() ); + CALL_SUBTEST_4( packetmath >() ); + CALL_SUBTEST_5( packetmath >() ); CALL_SUBTEST_1( packetmath_notcomplex() ); CALL_SUBTEST_2( packetmath_notcomplex() ); CALL_SUBTEST_3( packetmath_notcomplex() ); - + CALL_SUBTEST_1( packetmath_real() ); CALL_SUBTEST_2( packetmath_real() ); - CALL_SUBTEST_1( packetmath_complex >() ); - CALL_SUBTEST_2( packetmath_complex >() ); + CALL_SUBTEST_4( packetmath_complex >() ); + CALL_SUBTEST_5( packetmath_complex >() ); + + CALL_SUBTEST_1( packetmath_scatter_gather() ); + CALL_SUBTEST_2( packetmath_scatter_gather() ); + CALL_SUBTEST_3( packetmath_scatter_gather() ); + CALL_SUBTEST_4( packetmath_scatter_gather >() ); + CALL_SUBTEST_5( packetmath_scatter_gather >() ); } } diff --git a/ground/gcs/src/libs/eigen/test/pastix_support.cpp b/ground/gcs/src/libs/eigen/test/pastix_support.cpp index 14da0944be..b62f857394 100644 --- a/ground/gcs/src/libs/eigen/test/pastix_support.cpp +++ b/ground/gcs/src/libs/eigen/test/pastix_support.cpp @@ -7,6 +7,8 @@ // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#define EIGEN_NO_DEBUG_SMALL_PRODUCT_BLOCKS #include "sparse_solver.h" #include #include @@ -25,6 +27,14 @@ template void test_pastix_T() check_sparse_spd_solving(pastix_llt_upper); check_sparse_spd_solving(pastix_ldlt_upper); check_sparse_square_solving(pastix_lu); + + // Some compilation check: + pastix_llt_lower.iparm(); + pastix_llt_lower.dparm(); + pastix_ldlt_lower.iparm(); + pastix_ldlt_lower.dparm(); + pastix_lu.iparm(); + pastix_lu.dparm(); } // There is no support for selfadjoint matrices with PaStiX. diff --git a/ground/gcs/src/libs/eigen/test/permutationmatrices.cpp b/ground/gcs/src/libs/eigen/test/permutationmatrices.cpp index 7b0dbc7638..db12665797 100644 --- a/ground/gcs/src/libs/eigen/test/permutationmatrices.cpp +++ b/ground/gcs/src/libs/eigen/test/permutationmatrices.cpp @@ -7,6 +7,8 @@ // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. +#define TEST_ENABLE_TEMPORARY_TRACKING + #include "main.h" using namespace std; @@ -33,7 +35,9 @@ template void permutationmatrices(const MatrixType& m) RightPermutationVectorType rv; randomPermutationVector(rv, cols); RightPermutationType rp(rv); - MatrixType m_permuted = lp * m_original * rp; + MatrixType m_permuted = MatrixType::Random(rows,cols); + + VERIFY_EVALUATION_COUNT(m_permuted = lp * m_original * rp, 1); // 1 temp for sub expression "lp * m_original" for (int i=0; i void permutationmatrices(const MatrixType& m) Matrix rm(rp); VERIFY_IS_APPROX(m_permuted, lm*m_original*rm); - + + m_permuted = m_original; + VERIFY_EVALUATION_COUNT(m_permuted = lp * m_permuted * rp, 1); + VERIFY_IS_APPROX(m_permuted, lm*m_original*rm); + VERIFY_IS_APPROX(lp.inverse()*m_permuted*rp.inverse(), m_original); VERIFY_IS_APPROX(lv.asPermutation().inverse()*m_permuted*rv.asPermutation().inverse(), m_original); VERIFY_IS_APPROX(MapLeftPerm(lv.data(),lv.size()).inverse()*m_permuted*MapRightPerm(rv.data(),rv.size()).inverse(), m_original); @@ -63,22 +71,22 @@ template void permutationmatrices(const MatrixType& m) LeftPermutationType identityp; identityp.setIdentity(rows); VERIFY_IS_APPROX(m_original, identityp*m_original); - + // check inplace permutations m_permuted = m_original; - m_permuted = lp.inverse() * m_permuted; + VERIFY_EVALUATION_COUNT(m_permuted.noalias()= lp.inverse() * m_permuted, 1); // 1 temp to allocate the mask VERIFY_IS_APPROX(m_permuted, lp.inverse()*m_original); - + m_permuted = m_original; - m_permuted = m_permuted * rp.inverse(); + VERIFY_EVALUATION_COUNT(m_permuted.noalias() = m_permuted * rp.inverse(), 1); // 1 temp to allocate the mask VERIFY_IS_APPROX(m_permuted, m_original*rp.inverse()); - + m_permuted = m_original; - m_permuted = lp * m_permuted; + VERIFY_EVALUATION_COUNT(m_permuted.noalias() = lp * m_permuted, 1); // 1 temp to allocate the mask VERIFY_IS_APPROX(m_permuted, lp*m_original); - + m_permuted = m_original; - m_permuted = m_permuted * rp; + VERIFY_EVALUATION_COUNT(m_permuted.noalias() = m_permuted * rp, 1); // 1 temp to allocate the mask VERIFY_IS_APPROX(m_permuted, m_original*rp); if(rows>1 && cols>1) @@ -99,7 +107,38 @@ template void permutationmatrices(const MatrixType& m) rm = rp; rm.col(i).swap(rm.col(j)); VERIFY_IS_APPROX(rm, rp2.toDenseMatrix().template cast()); - } + } + + { + // simple compilation check + Matrix A = rp; + Matrix B = rp.transpose(); + VERIFY_IS_APPROX(A, B.transpose()); + } +} + +template +void bug890() +{ + typedef Matrix MatrixType; + typedef Matrix VectorType; + typedef Stride S; + typedef Map MapType; + typedef PermutationMatrix Perm; + + VectorType v1(2), v2(2), op(4), rhs(2); + v1 << 666,667; + op << 1,0,0,1; + rhs << 42,42; + + Perm P(2); + P.indices() << 1, 0; + + MapType(v1.data(),2,1,S(1,1)) = P * MapType(rhs.data(),2,1,S(1,1)); + VERIFY_IS_APPROX(v1, (P * rhs).eval()); + + MapType(v1.data(),2,1,S(1,1)) = P.inverse() * MapType(rhs.data(),2,1,S(1,1)); + VERIFY_IS_APPROX(v1, (P.inverse() * rhs).eval()); } void test_permutationmatrices() @@ -113,4 +152,5 @@ void test_permutationmatrices() CALL_SUBTEST_6( permutationmatrices(Matrix(20, 30)) ); CALL_SUBTEST_7( permutationmatrices(MatrixXcf(15, 10)) ); } + CALL_SUBTEST_5( bug890() ); } diff --git a/ground/gcs/src/libs/eigen/test/prec_inverse_4x4.cpp b/ground/gcs/src/libs/eigen/test/prec_inverse_4x4.cpp index c4ef2d4bdf..eb6ad18c94 100644 --- a/ground/gcs/src/libs/eigen/test/prec_inverse_4x4.cpp +++ b/ground/gcs/src/libs/eigen/test/prec_inverse_4x4.cpp @@ -53,14 +53,29 @@ template void inverse_general_4x4(int repeat) // FIXME that 1.25 used to be 1.2 until we tested gcc 4.1 on 30 June 2010 and got 1.21. VERIFY(error_avg < (NumTraits::IsComplex ? 8.0 : 1.25)); VERIFY(error_max < (NumTraits::IsComplex ? 64.0 : 20.0)); + + { + int s = 5;//internal::random(4,10); + int i = 0;//internal::random(0,s-4); + int j = 0;//internal::random(0,s-4); + Matrix mat(s,s); + mat.setRandom(); + MatrixType submat = mat.template block<4,4>(i,j); + MatrixType mat_inv = mat.template block<4,4>(i,j).inverse(); + VERIFY_IS_APPROX(mat_inv, submat.inverse()); + mat.template block<4,4>(i,j) = submat.inverse(); + VERIFY_IS_APPROX(mat_inv, (mat.template block<4,4>(i,j))); + } } void test_prec_inverse_4x4() { CALL_SUBTEST_1((inverse_permutation_4x4())); CALL_SUBTEST_1(( inverse_general_4x4(200000 * g_repeat) )); + CALL_SUBTEST_1(( inverse_general_4x4 >(200000 * g_repeat) )); CALL_SUBTEST_2((inverse_permutation_4x4 >())); + CALL_SUBTEST_2(( inverse_general_4x4 >(200000 * g_repeat) )); CALL_SUBTEST_2(( inverse_general_4x4 >(200000 * g_repeat) )); CALL_SUBTEST_3((inverse_permutation_4x4())); diff --git a/ground/gcs/src/libs/eigen/test/product.h b/ground/gcs/src/libs/eigen/test/product.h index 0d054ff469..3b65112706 100644 --- a/ground/gcs/src/libs/eigen/test/product.h +++ b/ground/gcs/src/libs/eigen/test/product.h @@ -22,7 +22,6 @@ template void product(const MatrixType& m) /* this test covers the following files: Identity.h Product.h */ - typedef typename MatrixType::Index Index; typedef typename MatrixType::Scalar Scalar; typedef Matrix RowVectorType; typedef Matrix ColVectorType; @@ -112,6 +111,23 @@ template void product(const MatrixType& m) vcres.noalias() -= m1.transpose() * v1; VERIFY_IS_APPROX(vcres, vc2 - m1.transpose() * v1); + // test d ?= a+b*c rules + res.noalias() = square + m1 * m2.transpose(); + VERIFY_IS_APPROX(res, square + m1 * m2.transpose()); + res.noalias() += square + m1 * m2.transpose(); + VERIFY_IS_APPROX(res, 2*(square + m1 * m2.transpose())); + res.noalias() -= square + m1 * m2.transpose(); + VERIFY_IS_APPROX(res, square + m1 * m2.transpose()); + + // test d ?= a-b*c rules + res.noalias() = square - m1 * m2.transpose(); + VERIFY_IS_APPROX(res, square - m1 * m2.transpose()); + res.noalias() += square - m1 * m2.transpose(); + VERIFY_IS_APPROX(res, 2*(square - m1 * m2.transpose())); + res.noalias() -= square - m1 * m2.transpose(); + VERIFY_IS_APPROX(res, square - m1 * m2.transpose()); + + tm1 = m1; VERIFY_IS_APPROX(tm1.transpose() * v1, m1.transpose() * v1); VERIFY_IS_APPROX(v1.transpose() * tm1, v1.transpose() * m1); @@ -152,19 +168,44 @@ template void product(const MatrixType& m) VERIFY_IS_APPROX(res2.block(0,0,1,cols).noalias() = m1.block(0,0,1,cols) * square2, (ref2.row(0) = m1.row(0) * square2)); } + // vector.block() (see bug 1283) + { + RowVectorType w1(rows); + VERIFY_IS_APPROX(square * v1.block(0,0,rows,1), square * v1); + VERIFY_IS_APPROX(w1.noalias() = square * v1.block(0,0,rows,1), square * v1); + VERIFY_IS_APPROX(w1.block(0,0,rows,1).noalias() = square * v1.block(0,0,rows,1), square * v1); + + Matrix w2(cols); + VERIFY_IS_APPROX(vc2.block(0,0,cols,1).transpose() * square2, vc2.transpose() * square2); + VERIFY_IS_APPROX(w2.noalias() = vc2.block(0,0,cols,1).transpose() * square2, vc2.transpose() * square2); + VERIFY_IS_APPROX(w2.block(0,0,1,cols).noalias() = vc2.block(0,0,cols,1).transpose() * square2, vc2.transpose() * square2); + + vc2 = square2.block(0,0,1,cols).transpose(); + VERIFY_IS_APPROX(square2.block(0,0,1,cols) * square2, vc2.transpose() * square2); + VERIFY_IS_APPROX(w2.noalias() = square2.block(0,0,1,cols) * square2, vc2.transpose() * square2); + VERIFY_IS_APPROX(w2.block(0,0,1,cols).noalias() = square2.block(0,0,1,cols) * square2, vc2.transpose() * square2); + + vc2 = square2.block(0,0,cols,1); + VERIFY_IS_APPROX(square2.block(0,0,cols,1).transpose() * square2, vc2.transpose() * square2); + VERIFY_IS_APPROX(w2.noalias() = square2.block(0,0,cols,1).transpose() * square2, vc2.transpose() * square2); + VERIFY_IS_APPROX(w2.block(0,0,1,cols).noalias() = square2.block(0,0,cols,1).transpose() * square2, vc2.transpose() * square2); + } + // inner product { Scalar x = square2.row(c) * square2.col(c2); VERIFY_IS_APPROX(x, square2.row(c).transpose().cwiseProduct(square2.col(c2)).sum()); } - + // outer product - VERIFY_IS_APPROX(m1.col(c) * m1.row(r), m1.block(0,c,rows,1) * m1.block(r,0,1,cols)); - VERIFY_IS_APPROX(m1.row(r).transpose() * m1.col(c).transpose(), m1.block(r,0,1,cols).transpose() * m1.block(0,c,rows,1).transpose()); - VERIFY_IS_APPROX(m1.block(0,c,rows,1) * m1.row(r), m1.block(0,c,rows,1) * m1.block(r,0,1,cols)); - VERIFY_IS_APPROX(m1.col(c) * m1.block(r,0,1,cols), m1.block(0,c,rows,1) * m1.block(r,0,1,cols)); - VERIFY_IS_APPROX(m1.leftCols(1) * m1.row(r), m1.block(0,0,rows,1) * m1.block(r,0,1,cols)); - VERIFY_IS_APPROX(m1.col(c) * m1.topRows(1), m1.block(0,c,rows,1) * m1.block(0,0,1,cols)); + { + VERIFY_IS_APPROX(m1.col(c) * m1.row(r), m1.block(0,c,rows,1) * m1.block(r,0,1,cols)); + VERIFY_IS_APPROX(m1.row(r).transpose() * m1.col(c).transpose(), m1.block(r,0,1,cols).transpose() * m1.block(0,c,rows,1).transpose()); + VERIFY_IS_APPROX(m1.block(0,c,rows,1) * m1.row(r), m1.block(0,c,rows,1) * m1.block(r,0,1,cols)); + VERIFY_IS_APPROX(m1.col(c) * m1.block(r,0,1,cols), m1.block(0,c,rows,1) * m1.block(r,0,1,cols)); + VERIFY_IS_APPROX(m1.leftCols(1) * m1.row(r), m1.block(0,0,rows,1) * m1.block(r,0,1,cols)); + VERIFY_IS_APPROX(m1.col(c) * m1.topRows(1), m1.block(0,c,rows,1) * m1.block(0,0,1,cols)); + } // Aliasing { @@ -178,4 +219,13 @@ template void product(const MatrixType& m) // CwiseUnaryOp VERIFY_IS_APPROX(x = Scalar(1.)*(A*x), A*z); } + + // regression for blas_trais + { + VERIFY_IS_APPROX(square * (square*square).transpose(), square * square.transpose() * square.transpose()); + VERIFY_IS_APPROX(square * (-(square*square)), -square * square * square); + VERIFY_IS_APPROX(square * (s1*(square*square)), s1 * square * square * square); + VERIFY_IS_APPROX(square * (square*square).conjugate(), square * square.conjugate() * square.conjugate()); + } + } diff --git a/ground/gcs/src/libs/eigen/test/product_extra.cpp b/ground/gcs/src/libs/eigen/test/product_extra.cpp index ea24869371..e2b855bff0 100644 --- a/ground/gcs/src/libs/eigen/test/product_extra.cpp +++ b/ground/gcs/src/libs/eigen/test/product_extra.cpp @@ -98,6 +98,16 @@ template void product_extra(const MatrixType& m) // regression test MatrixType tmp = m1 * m1.adjoint() * s1; VERIFY_IS_APPROX(tmp, m1 * m1.adjoint() * s1); + + // regression test for bug 1343, assignment to arrays + Array a1 = m1 * vc2; + VERIFY_IS_APPROX(a1.matrix(),m1*vc2); + Array a2 = s1 * (m1 * vc2); + VERIFY_IS_APPROX(a2.matrix(),s1*m1*vc2); + Array a3 = v1 * m1; + VERIFY_IS_APPROX(a3.matrix(),v1*m1); + Array a4 = m1 * m2.adjoint(); + VERIFY_IS_APPROX(a4.matrix(),m1*m2.adjoint()); } // Regression test for bug reported at http://forum.kde.org/viewtopic.php?f=74&t=96947 @@ -116,8 +126,8 @@ void zero_sized_objects(const MatrixType& m) typedef typename MatrixType::Scalar Scalar; const int PacketSize = internal::packet_traits::size; const int PacketSize1 = PacketSize>1 ? PacketSize-1 : 1; - DenseIndex rows = m.rows(); - DenseIndex cols = m.cols(); + Index rows = m.rows(); + Index cols = m.cols(); { MatrixType res, a(rows,0), b(0,cols); @@ -169,6 +179,7 @@ void zero_sized_objects(const MatrixType& m) } } +template void bug_127() { // Bug 127 @@ -193,6 +204,16 @@ void bug_127() a*b; } +template void bug_817() +{ + ArrayXXf B = ArrayXXf::Random(10,10), C; + VectorXf x = VectorXf::Random(10); + C = (x.transpose()*B.matrix()); + B = (x.transpose()*B.matrix()); + VERIFY_IS_APPROX(B,C); +} + +template void unaligned_objects() { // Regression test for the bug reported here: @@ -222,6 +243,116 @@ void unaligned_objects() } } +template +EIGEN_DONT_INLINE +Index test_compute_block_size(Index m, Index n, Index k) +{ + Index mc(m), nc(n), kc(k); + internal::computeProductBlockingSizes(kc, mc, nc); + return kc+mc+nc; +} + +template +Index compute_block_size() +{ + Index ret = 0; + ret += test_compute_block_size(0,1,1); + ret += test_compute_block_size(1,0,1); + ret += test_compute_block_size(1,1,0); + ret += test_compute_block_size(0,0,1); + ret += test_compute_block_size(0,1,0); + ret += test_compute_block_size(1,0,0); + ret += test_compute_block_size(0,0,0); + return ret; +} + +template +void aliasing_with_resize() +{ + Index m = internal::random(10,50); + Index n = internal::random(10,50); + MatrixXd A, B, C(m,n), D(m,m); + VectorXd a, b, c(n); + C.setRandom(); + D.setRandom(); + c.setRandom(); + double s = internal::random(1,10); + + A = C; + B = A * A.transpose(); + A = A * A.transpose(); + VERIFY_IS_APPROX(A,B); + + A = C; + B = (A * A.transpose())/s; + A = (A * A.transpose())/s; + VERIFY_IS_APPROX(A,B); + + A = C; + B = (A * A.transpose()) + D; + A = (A * A.transpose()) + D; + VERIFY_IS_APPROX(A,B); + + A = C; + B = D + (A * A.transpose()); + A = D + (A * A.transpose()); + VERIFY_IS_APPROX(A,B); + + A = C; + B = s * (A * A.transpose()); + A = s * (A * A.transpose()); + VERIFY_IS_APPROX(A,B); + + A = C; + a = c; + b = (A * a)/s; + a = (A * a)/s; + VERIFY_IS_APPROX(a,b); +} + +template +void bug_1308() +{ + int n = 10; + MatrixXd r(n,n); + VectorXd v = VectorXd::Random(n); + r = v * RowVectorXd::Ones(n); + VERIFY_IS_APPROX(r, v.rowwise().replicate(n)); + r = VectorXd::Ones(n) * v.transpose(); + VERIFY_IS_APPROX(r, v.rowwise().replicate(n).transpose()); + + Matrix4d ones44 = Matrix4d::Ones(); + Matrix4d m44 = Matrix4d::Ones() * Matrix4d::Ones(); + VERIFY_IS_APPROX(m44,Matrix4d::Constant(4)); + VERIFY_IS_APPROX(m44.noalias()=ones44*Matrix4d::Ones(), Matrix4d::Constant(4)); + VERIFY_IS_APPROX(m44.noalias()=ones44.transpose()*Matrix4d::Ones(), Matrix4d::Constant(4)); + VERIFY_IS_APPROX(m44.noalias()=Matrix4d::Ones()*ones44, Matrix4d::Constant(4)); + VERIFY_IS_APPROX(m44.noalias()=Matrix4d::Ones()*ones44.transpose(), Matrix4d::Constant(4)); + + typedef Matrix RMatrix4d; + RMatrix4d r44 = Matrix4d::Ones() * Matrix4d::Ones(); + VERIFY_IS_APPROX(r44,Matrix4d::Constant(4)); + VERIFY_IS_APPROX(r44.noalias()=ones44*Matrix4d::Ones(), Matrix4d::Constant(4)); + VERIFY_IS_APPROX(r44.noalias()=ones44.transpose()*Matrix4d::Ones(), Matrix4d::Constant(4)); + VERIFY_IS_APPROX(r44.noalias()=Matrix4d::Ones()*ones44, Matrix4d::Constant(4)); + VERIFY_IS_APPROX(r44.noalias()=Matrix4d::Ones()*ones44.transpose(), Matrix4d::Constant(4)); + VERIFY_IS_APPROX(r44.noalias()=ones44*RMatrix4d::Ones(), Matrix4d::Constant(4)); + VERIFY_IS_APPROX(r44.noalias()=ones44.transpose()*RMatrix4d::Ones(), Matrix4d::Constant(4)); + VERIFY_IS_APPROX(r44.noalias()=RMatrix4d::Ones()*ones44, Matrix4d::Constant(4)); + VERIFY_IS_APPROX(r44.noalias()=RMatrix4d::Ones()*ones44.transpose(), Matrix4d::Constant(4)); + +// RowVector4d r4; + m44.setOnes(); + r44.setZero(); + VERIFY_IS_APPROX(r44.noalias() += m44.row(0).transpose() * RowVector4d::Ones(), ones44); + r44.setZero(); + VERIFY_IS_APPROX(r44.noalias() += m44.col(0) * RowVector4d::Ones(), ones44); + r44.setZero(); + VERIFY_IS_APPROX(r44.noalias() += Vector4d::Ones() * m44.row(0), ones44); + r44.setZero(); + VERIFY_IS_APPROX(r44.noalias() += Vector4d::Ones() * m44.col(0).transpose(), ones44); +} + void test_product_extra() { for(int i = 0; i < g_repeat; i++) { @@ -232,6 +363,13 @@ void test_product_extra() CALL_SUBTEST_4( product_extra(MatrixXcd(internal::random(1,EIGEN_TEST_MAX_SIZE/2), internal::random(1,EIGEN_TEST_MAX_SIZE/2))) ); CALL_SUBTEST_1( zero_sized_objects(MatrixXf(internal::random(1,EIGEN_TEST_MAX_SIZE), internal::random(1,EIGEN_TEST_MAX_SIZE))) ); } - CALL_SUBTEST_5( bug_127() ); - CALL_SUBTEST_6( unaligned_objects() ); + CALL_SUBTEST_5( bug_127<0>() ); + CALL_SUBTEST_5( bug_817<0>() ); + CALL_SUBTEST_5( bug_1308<0>() ); + CALL_SUBTEST_6( unaligned_objects<0>() ); + CALL_SUBTEST_7( compute_block_size() ); + CALL_SUBTEST_7( compute_block_size() ); + CALL_SUBTEST_7( compute_block_size >() ); + CALL_SUBTEST_8( aliasing_with_resize() ); + } diff --git a/ground/gcs/src/libs/eigen/test/product_large.cpp b/ground/gcs/src/libs/eigen/test/product_large.cpp index 6bb4d1ad1c..845cd40ca1 100644 --- a/ground/gcs/src/libs/eigen/test/product_large.cpp +++ b/ground/gcs/src/libs/eigen/test/product_large.cpp @@ -21,12 +21,12 @@ void test_aliasing() VectorType y(rows); y.setZero(); MatrixType A(rows,cols); A.setRandom(); // CwiseBinaryOp - VERIFY_IS_APPROX(x = y + A*x, A*z); + VERIFY_IS_APPROX(x = y + A*x, A*z); // OK because "y + A*x" is marked as "assume-aliasing" x = z; // CwiseUnaryOp - VERIFY_IS_APPROX(x = T(1.)*(A*x), A*z); + VERIFY_IS_APPROX(x = T(1.)*(A*x), A*z); // OK because 1*(A*x) is replaced by (1*A*x) which is a Product<> expression x = z; - VERIFY_IS_APPROX(x = y+(-(A*x)), -A*z); + // VERIFY_IS_APPROX(x = y-A*x, -A*z); // Not OK in 3.3 because x is resized before A*x gets evaluated x = z; } @@ -62,15 +62,16 @@ void test_product_large() // check the functions to setup blocking sizes compile and do not segfault // FIXME check they do what they are supposed to do !! std::ptrdiff_t l1 = internal::random(10000,20000); - std::ptrdiff_t l2 = internal::random(1000000,2000000); - setCpuCacheSizes(l1,l2); + std::ptrdiff_t l2 = internal::random(100000,200000); + std::ptrdiff_t l3 = internal::random(1000000,2000000); + setCpuCacheSizes(l1,l2,l3); VERIFY(l1==l1CacheSize()); VERIFY(l2==l2CacheSize()); std::ptrdiff_t k1 = internal::random(10,100)*16; std::ptrdiff_t m1 = internal::random(10,100)*16; std::ptrdiff_t n1 = internal::random(10,100)*16; // only makes sure it compiles fine - internal::computeProductBlockingSizes(k1,m1,n1); + internal::computeProductBlockingSizes(k1,m1,n1,1); } { @@ -83,5 +84,24 @@ void test_product_large() MatrixXf r2 = mat1.row(2)*mat2; VERIFY_IS_APPROX(r2, (mat1.row(2)*mat2).eval()); } + + { + Eigen::MatrixXd A(10,10), B, C; + A.setRandom(); + C = A; + for(int k=0; k<79; ++k) + C = C * A; + B.noalias() = (((A*A)*(A*A))*((A*A)*(A*A))*((A*A)*(A*A))*((A*A)*(A*A))*((A*A)*(A*A)) * ((A*A)*(A*A))*((A*A)*(A*A))*((A*A)*(A*A))*((A*A)*(A*A))*((A*A)*(A*A))) + * (((A*A)*(A*A))*((A*A)*(A*A))*((A*A)*(A*A))*((A*A)*(A*A))*((A*A)*(A*A)) * ((A*A)*(A*A))*((A*A)*(A*A))*((A*A)*(A*A))*((A*A)*(A*A))*((A*A)*(A*A))); + VERIFY_IS_APPROX(B,C); + } +#endif + + // Regression test for bug 714: +#if defined EIGEN_HAS_OPENMP + omp_set_dynamic(1); + for(int i = 0; i < g_repeat; i++) { + CALL_SUBTEST_6( product(Matrix(internal::random(1,EIGEN_TEST_MAX_SIZE), internal::random(1,EIGEN_TEST_MAX_SIZE))) ); + } #endif } diff --git a/ground/gcs/src/libs/eigen/test/product_mmtr.cpp b/ground/gcs/src/libs/eigen/test/product_mmtr.cpp index aeba009f4f..f6e4bb1ae7 100644 --- a/ground/gcs/src/libs/eigen/test/product_mmtr.cpp +++ b/ground/gcs/src/libs/eigen/test/product_mmtr.cpp @@ -13,7 +13,8 @@ ref2 = ref1 = DEST; \ DEST.template triangularView() OP; \ ref1 OP; \ - ref2.template triangularView() = ref1; \ + ref2.template triangularView() \ + = ref1.template triangularView(); \ VERIFY_IS_APPROX(DEST,ref2); \ } @@ -32,6 +33,8 @@ template void mmtr(int size) MatrixColMaj osc(othersize,size); osc.setRandom(); MatrixRowMaj sor(size,othersize); sor.setRandom(); MatrixRowMaj osr(othersize,size); osr.setRandom(); + MatrixColMaj sqc(size,size); sqc.setRandom(); + MatrixRowMaj sqr(size,size); sqr.setRandom(); Scalar s = internal::random(); @@ -49,6 +52,29 @@ template void mmtr(int size) CHECK_MMTR(matc, Upper, -= s*(osc.transpose()*osc.conjugate())); CHECK_MMTR(matr, Lower, -= s*soc*soc.adjoint()); CHECK_MMTR(matr, Upper, -= soc*(s*soc.adjoint())); + + CHECK_MMTR(matc, Lower, -= s*sqr*sqc.template triangularView()); + CHECK_MMTR(matc, Upper, = s*sqc*sqr.template triangularView()); + CHECK_MMTR(matc, Lower, += s*sqr*sqc.template triangularView()); + CHECK_MMTR(matc, Upper, = s*sqc*sqc.template triangularView()); + + CHECK_MMTR(matc, Lower, = (s*sqr).template triangularView()*sqc); + CHECK_MMTR(matc, Upper, -= (s*sqc).template triangularView()*sqc); + CHECK_MMTR(matc, Lower, = (s*sqr).template triangularView()*sqc); + CHECK_MMTR(matc, Upper, += (s*sqc).template triangularView()*sqc); + + // check aliasing + ref2 = ref1 = matc; + ref1 = sqc.adjoint() * matc * sqc; + ref2.template triangularView() = ref1.template triangularView(); + matc.template triangularView() = sqc.adjoint() * matc * sqc; + VERIFY_IS_APPROX(matc, ref2); + + ref2 = ref1 = matc; + ref1 = sqc * matc * sqc.adjoint(); + ref2.template triangularView() = ref1.template triangularView(); + matc.template triangularView() = sqc * matc * sqc.adjoint(); + VERIFY_IS_APPROX(matc, ref2); } void test_product_mmtr() diff --git a/ground/gcs/src/libs/eigen/test/product_notemporary.cpp b/ground/gcs/src/libs/eigen/test/product_notemporary.cpp index 5599d268d8..8bf71b4f2e 100644 --- a/ground/gcs/src/libs/eigen/test/product_notemporary.cpp +++ b/ground/gcs/src/libs/eigen/test/product_notemporary.cpp @@ -7,25 +7,10 @@ // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. -static int nb_temporaries; - -inline void on_temporary_creation(int size) { - // here's a great place to set a breakpoint when debugging failures in this test! - if(size!=0) nb_temporaries++; -} - - -#define EIGEN_DENSE_STORAGE_CTOR_PLUGIN { on_temporary_creation(size); } +#define TEST_ENABLE_TEMPORARY_TRACKING #include "main.h" -#define VERIFY_EVALUATION_COUNT(XPR,N) {\ - nb_temporaries = 0; \ - XPR; \ - if(nb_temporaries!=N) std::cerr << "nb_temporaries == " << nb_temporaries << "\n"; \ - VERIFY( (#XPR) && nb_temporaries==N ); \ - } - template void product_notemporary(const MatrixType& m) { /* This test checks the number of temporaries created @@ -62,14 +47,18 @@ template void product_notemporary(const MatrixType& m) VERIFY_EVALUATION_COUNT( m3.noalias() = m1 * m2.adjoint(), 0); VERIFY_EVALUATION_COUNT( m3 = s1 * (m1 * m2.transpose()), 1); - VERIFY_EVALUATION_COUNT( m3 = m3 + s1 * (m1 * m2.transpose()), 1); +// VERIFY_EVALUATION_COUNT( m3 = m3 + s1 * (m1 * m2.transpose()), 1); VERIFY_EVALUATION_COUNT( m3.noalias() = s1 * (m1 * m2.transpose()), 0); VERIFY_EVALUATION_COUNT( m3 = m3 + (m1 * m2.adjoint()), 1); + VERIFY_EVALUATION_COUNT( m3 = m3 + (m1 * m2.adjoint()).transpose(), 1); - VERIFY_EVALUATION_COUNT( m3.noalias() = m3 + m1 * m2.transpose(), 1); // 0 in 3.3 - VERIFY_EVALUATION_COUNT( m3.noalias() += m3 + m1 * m2.transpose(), 1); // 0 in 3.3 - VERIFY_EVALUATION_COUNT( m3.noalias() -= m3 + m1 * m2.transpose(), 1); // 0 in 3.3 + VERIFY_EVALUATION_COUNT( m3.noalias() = m3 + m1 * m2.transpose(), 0); + VERIFY_EVALUATION_COUNT( m3.noalias() += m3 + m1 * m2.transpose(), 0); + VERIFY_EVALUATION_COUNT( m3.noalias() -= m3 + m1 * m2.transpose(), 0); + VERIFY_EVALUATION_COUNT( m3.noalias() = m3 - m1 * m2.transpose(), 0); + VERIFY_EVALUATION_COUNT( m3.noalias() += m3 - m1 * m2.transpose(), 0); + VERIFY_EVALUATION_COUNT( m3.noalias() -= m3 - m1 * m2.transpose(), 0); VERIFY_EVALUATION_COUNT( m3.noalias() = s1 * m1 * s2 * m2.adjoint(), 0); VERIFY_EVALUATION_COUNT( m3.noalias() = s1 * m1 * s2 * (m1*s3+m2*s2).adjoint(), 1); @@ -86,7 +75,7 @@ template void product_notemporary(const MatrixType& m) VERIFY_EVALUATION_COUNT( m3.noalias() -= (s1 * m1).template triangularView() * m2, 0); VERIFY_EVALUATION_COUNT( rm3.noalias() = (s1 * m1.adjoint()).template triangularView() * (m2+m2), 1); VERIFY_EVALUATION_COUNT( rm3.noalias() = (s1 * m1.adjoint()).template triangularView() * m2.adjoint(), 0); - + VERIFY_EVALUATION_COUNT( m3.template triangularView() = (m1 * m2.adjoint()), 0); VERIFY_EVALUATION_COUNT( m3.template triangularView() -= (m1 * m2.adjoint()), 0); @@ -123,8 +112,7 @@ template void product_notemporary(const MatrixType& m) VERIFY_EVALUATION_COUNT( Scalar tmp = 0; tmp += Scalar(RealScalar(1)) / (m3.transpose() * m3).diagonal().array().abs().sum(), 0 ); // Zero temporaries for ... CoeffBasedProductMode - // - does not work with GCC because of the <..>, we'ld need variadic macros ... - //VERIFY_EVALUATION_COUNT( m3.col(0).head<5>() * m3.col(0).transpose() + m3.col(0).head<5>() * m3.col(0).transpose(), 0 ); + VERIFY_EVALUATION_COUNT( m3.col(0).template head<5>() * m3.col(0).transpose() + m3.col(0).template head<5>() * m3.col(0).transpose(), 0 ); // Check matrix * vectors VERIFY_EVALUATION_COUNT( cvres.noalias() = m1 * cv1, 0 ); @@ -132,6 +120,26 @@ template void product_notemporary(const MatrixType& m) VERIFY_EVALUATION_COUNT( cvres.noalias() -= m1 * m2.col(0), 0 ); VERIFY_EVALUATION_COUNT( cvres.noalias() -= m1 * rv1.adjoint(), 0 ); VERIFY_EVALUATION_COUNT( cvres.noalias() -= m1 * m2.row(0).transpose(), 0 ); + + VERIFY_EVALUATION_COUNT( cvres.noalias() = (m1+m1) * cv1, 0 ); + VERIFY_EVALUATION_COUNT( cvres.noalias() = (rm3+rm3) * cv1, 0 ); + VERIFY_EVALUATION_COUNT( cvres.noalias() = (m1+m1) * (m1*cv1), 1 ); + VERIFY_EVALUATION_COUNT( cvres.noalias() = (rm3+rm3) * (m1*cv1), 1 ); + + // Check outer products + m3 = cv1 * rv1; + VERIFY_EVALUATION_COUNT( m3.noalias() = cv1 * rv1, 0 ); + VERIFY_EVALUATION_COUNT( m3.noalias() = (cv1+cv1) * (rv1+rv1), 1 ); + VERIFY_EVALUATION_COUNT( m3.noalias() = (m1*cv1) * (rv1), 1 ); + VERIFY_EVALUATION_COUNT( m3.noalias() += (m1*cv1) * (rv1), 1 ); + VERIFY_EVALUATION_COUNT( rm3.noalias() = (cv1) * (rv1 * m1), 1 ); + VERIFY_EVALUATION_COUNT( rm3.noalias() -= (cv1) * (rv1 * m1), 1 ); + VERIFY_EVALUATION_COUNT( rm3.noalias() = (m1*cv1) * (rv1 * m1), 2 ); + VERIFY_EVALUATION_COUNT( rm3.noalias() += (m1*cv1) * (rv1 * m1), 2 ); + + // Check nested products + VERIFY_EVALUATION_COUNT( cvres.noalias() = m1.adjoint() * m1 * cv1, 1 ); + VERIFY_EVALUATION_COUNT( rvres.noalias() = rv1 * (m1 * m2.adjoint()), 1 ); } void test_product_notemporary() @@ -140,11 +148,12 @@ void test_product_notemporary() for(int i = 0; i < g_repeat; i++) { s = internal::random(16,EIGEN_TEST_MAX_SIZE); CALL_SUBTEST_1( product_notemporary(MatrixXf(s, s)) ); - s = internal::random(16,EIGEN_TEST_MAX_SIZE); CALL_SUBTEST_2( product_notemporary(MatrixXd(s, s)) ); + TEST_SET_BUT_UNUSED_VARIABLE(s) + s = internal::random(16,EIGEN_TEST_MAX_SIZE/2); CALL_SUBTEST_3( product_notemporary(MatrixXcf(s,s)) ); - s = internal::random(16,EIGEN_TEST_MAX_SIZE/2); CALL_SUBTEST_4( product_notemporary(MatrixXcd(s,s)) ); + TEST_SET_BUT_UNUSED_VARIABLE(s) } } diff --git a/ground/gcs/src/libs/eigen/test/product_selfadjoint.cpp b/ground/gcs/src/libs/eigen/test/product_selfadjoint.cpp index 374e2393b7..3d768aa7e2 100644 --- a/ground/gcs/src/libs/eigen/test/product_selfadjoint.cpp +++ b/ground/gcs/src/libs/eigen/test/product_selfadjoint.cpp @@ -67,14 +67,21 @@ void test_product_selfadjoint() CALL_SUBTEST_1( product_selfadjoint(Matrix()) ); CALL_SUBTEST_2( product_selfadjoint(Matrix()) ); CALL_SUBTEST_3( product_selfadjoint(Matrix3d()) ); + s = internal::random(1,EIGEN_TEST_MAX_SIZE/2); CALL_SUBTEST_4( product_selfadjoint(MatrixXcf(s, s)) ); + TEST_SET_BUT_UNUSED_VARIABLE(s) + s = internal::random(1,EIGEN_TEST_MAX_SIZE/2); CALL_SUBTEST_5( product_selfadjoint(MatrixXcd(s,s)) ); + TEST_SET_BUT_UNUSED_VARIABLE(s) + s = internal::random(1,EIGEN_TEST_MAX_SIZE); CALL_SUBTEST_6( product_selfadjoint(MatrixXd(s,s)) ); + TEST_SET_BUT_UNUSED_VARIABLE(s) + s = internal::random(1,EIGEN_TEST_MAX_SIZE); CALL_SUBTEST_7( product_selfadjoint(Matrix(s,s)) ); + TEST_SET_BUT_UNUSED_VARIABLE(s) } - TEST_SET_BUT_UNUSED_VARIABLE(s) } diff --git a/ground/gcs/src/libs/eigen/test/product_small.cpp b/ground/gcs/src/libs/eigen/test/product_small.cpp index 8b132abb67..fdfdd9f6c5 100644 --- a/ground/gcs/src/libs/eigen/test/product_small.cpp +++ b/ground/gcs/src/libs/eigen/test/product_small.cpp @@ -9,8 +9,10 @@ #define EIGEN_NO_STATIC_ASSERT #include "product.h" +#include // regression test for bug 447 +template void product1x1() { Matrix matAstatic; @@ -28,16 +30,237 @@ void product1x1() matAdynamic.cwiseProduct(matBdynamic.transpose()).sum() ); } +template +const TC& ref_prod(TC &C, const TA &A, const TB &B) +{ + for(Index i=0;i +typename internal::enable_if::type +test_lazy_single(int rows, int cols, int depth) +{ + Matrix A(rows,depth); A.setRandom(); + Matrix B(depth,cols); B.setRandom(); + Matrix C(rows,cols); C.setRandom(); + Matrix D(C); + VERIFY_IS_APPROX(C+=A.lazyProduct(B), ref_prod(D,A,B)); +} + +template +typename internal::enable_if< ( (Rows ==1&&Depth!=1&&OA==ColMajor) + || (Depth==1&&Rows !=1&&OA==RowMajor) + || (Cols ==1&&Depth!=1&&OB==RowMajor) + || (Depth==1&&Cols !=1&&OB==ColMajor) + || (Rows ==1&&Cols !=1&&OC==ColMajor) + || (Cols ==1&&Rows !=1&&OC==RowMajor)),void>::type +test_lazy_single(int, int, int) +{ +} + +template +void test_lazy_all_layout(int rows=Rows, int cols=Cols, int depth=Depth) +{ + CALL_SUBTEST(( test_lazy_single(rows,cols,depth) )); + CALL_SUBTEST(( test_lazy_single(rows,cols,depth) )); + CALL_SUBTEST(( test_lazy_single(rows,cols,depth) )); + CALL_SUBTEST(( test_lazy_single(rows,cols,depth) )); + CALL_SUBTEST(( test_lazy_single(rows,cols,depth) )); + CALL_SUBTEST(( test_lazy_single(rows,cols,depth) )); + CALL_SUBTEST(( test_lazy_single(rows,cols,depth) )); + CALL_SUBTEST(( test_lazy_single(rows,cols,depth) )); +} + +template +void test_lazy_l1() +{ + int rows = internal::random(1,12); + int cols = internal::random(1,12); + int depth = internal::random(1,12); + + // Inner + CALL_SUBTEST(( test_lazy_all_layout() )); + CALL_SUBTEST(( test_lazy_all_layout() )); + CALL_SUBTEST(( test_lazy_all_layout() )); + CALL_SUBTEST(( test_lazy_all_layout() )); + CALL_SUBTEST(( test_lazy_all_layout() )); + CALL_SUBTEST(( test_lazy_all_layout(1,1,depth) )); + + // Outer + CALL_SUBTEST(( test_lazy_all_layout() )); + CALL_SUBTEST(( test_lazy_all_layout() )); + CALL_SUBTEST(( test_lazy_all_layout() )); + CALL_SUBTEST(( test_lazy_all_layout() )); + CALL_SUBTEST(( test_lazy_all_layout() )); + CALL_SUBTEST(( test_lazy_all_layout() )); + CALL_SUBTEST(( test_lazy_all_layout(4,cols) )); + CALL_SUBTEST(( test_lazy_all_layout(7,cols) )); + CALL_SUBTEST(( test_lazy_all_layout(rows) )); + CALL_SUBTEST(( test_lazy_all_layout(rows) )); + CALL_SUBTEST(( test_lazy_all_layout(rows,cols) )); +} + +template +void test_lazy_l2() +{ + int rows = internal::random(1,12); + int cols = internal::random(1,12); + int depth = internal::random(1,12); + + // mat-vec + CALL_SUBTEST(( test_lazy_all_layout() )); + CALL_SUBTEST(( test_lazy_all_layout() )); + CALL_SUBTEST(( test_lazy_all_layout() )); + CALL_SUBTEST(( test_lazy_all_layout() )); + CALL_SUBTEST(( test_lazy_all_layout() )); + CALL_SUBTEST(( test_lazy_all_layout() )); + CALL_SUBTEST(( test_lazy_all_layout() )); + CALL_SUBTEST(( test_lazy_all_layout() )); + CALL_SUBTEST(( test_lazy_all_layout() )); + CALL_SUBTEST(( test_lazy_all_layout(rows) )); + CALL_SUBTEST(( test_lazy_all_layout(4,1,depth) )); + CALL_SUBTEST(( test_lazy_all_layout(rows,1,depth) )); + + // vec-mat + CALL_SUBTEST(( test_lazy_all_layout() )); + CALL_SUBTEST(( test_lazy_all_layout() )); + CALL_SUBTEST(( test_lazy_all_layout() )); + CALL_SUBTEST(( test_lazy_all_layout() )); + CALL_SUBTEST(( test_lazy_all_layout() )); + CALL_SUBTEST(( test_lazy_all_layout() )); + CALL_SUBTEST(( test_lazy_all_layout() )); + CALL_SUBTEST(( test_lazy_all_layout() )); + CALL_SUBTEST(( test_lazy_all_layout() )); + CALL_SUBTEST(( test_lazy_all_layout(1,cols) )); + CALL_SUBTEST(( test_lazy_all_layout(1,4,depth) )); + CALL_SUBTEST(( test_lazy_all_layout(1,cols,depth) )); +} + +template +void test_lazy_l3() +{ + int rows = internal::random(1,12); + int cols = internal::random(1,12); + int depth = internal::random(1,12); + // mat-mat + CALL_SUBTEST(( test_lazy_all_layout() )); + CALL_SUBTEST(( test_lazy_all_layout() )); + CALL_SUBTEST(( test_lazy_all_layout() )); + CALL_SUBTEST(( test_lazy_all_layout() )); + CALL_SUBTEST(( test_lazy_all_layout() )); + CALL_SUBTEST(( test_lazy_all_layout() )); + CALL_SUBTEST(( test_lazy_all_layout() )); + CALL_SUBTEST(( test_lazy_all_layout() )); + CALL_SUBTEST(( test_lazy_all_layout() )); + CALL_SUBTEST(( test_lazy_all_layout(rows) )); + CALL_SUBTEST(( test_lazy_all_layout(4,3,depth) )); + CALL_SUBTEST(( test_lazy_all_layout(rows,6,depth) )); + CALL_SUBTEST(( test_lazy_all_layout() )); + CALL_SUBTEST(( test_lazy_all_layout() )); + CALL_SUBTEST(( test_lazy_all_layout() )); + CALL_SUBTEST(( test_lazy_all_layout() )); + CALL_SUBTEST(( test_lazy_all_layout() )); + CALL_SUBTEST(( test_lazy_all_layout() )); + CALL_SUBTEST(( test_lazy_all_layout() )); + CALL_SUBTEST(( test_lazy_all_layout() )); + CALL_SUBTEST(( test_lazy_all_layout() )); + CALL_SUBTEST(( test_lazy_all_layout(8,cols) )); + CALL_SUBTEST(( test_lazy_all_layout(3,4,depth) )); + CALL_SUBTEST(( test_lazy_all_layout(4,cols,depth) )); +} + +template +void test_linear_but_not_vectorizable() +{ + // Check tricky cases for which the result of the product is a vector and thus must exhibit the LinearBit flag, + // but is not vectorizable along the linear dimension. + Index n = N==Dynamic ? internal::random(1,32) : N; + Index m = M==Dynamic ? internal::random(1,32) : M; + Index k = K==Dynamic ? internal::random(1,32) : K; + + { + Matrix A; A.setRandom(n,m+1); + Matrix B; B.setRandom(m*2,k); + Matrix C; + Matrix R; + + C.noalias() = A.template topLeftCorner<1,M>() * (B.template topRows()+B.template bottomRows()); + R.noalias() = A.template topLeftCorner<1,M>() * (B.template topRows()+B.template bottomRows()).eval(); + VERIFY_IS_APPROX(C,R); + } + + { + Matrix A; A.setRandom(m+1,n); + Matrix B; B.setRandom(k,m*2); + Matrix C; + Matrix R; + + C.noalias() = (B.template leftCols()+B.template rightCols()) * A.template topLeftCorner(); + R.noalias() = (B.template leftCols()+B.template rightCols()).eval() * A.template topLeftCorner(); + VERIFY_IS_APPROX(C,R); + } +} + +template +void bug_1311() +{ + Matrix< double, Rows, 2 > A; A.setRandom(); + Vector2d b = Vector2d::Random() ; + Matrix res; + res.noalias() = 1. * (A * b); + VERIFY_IS_APPROX(res, A*b); + res.noalias() = 1.*A * b; + VERIFY_IS_APPROX(res, A*b); + res.noalias() = (1.*A).lazyProduct(b); + VERIFY_IS_APPROX(res, A*b); + res.noalias() = (1.*A).lazyProduct(1.*b); + VERIFY_IS_APPROX(res, A*b); + res.noalias() = (A).lazyProduct(1.*b); + VERIFY_IS_APPROX(res, A*b); +} void test_product_small() { for(int i = 0; i < g_repeat; i++) { CALL_SUBTEST_1( product(Matrix()) ); - CALL_SUBTEST_2( product(Matrix()) ); + CALL_SUBTEST_2( product(Matrix()) ); + CALL_SUBTEST_8( product(Matrix()) ); CALL_SUBTEST_3( product(Matrix3d()) ); CALL_SUBTEST_4( product(Matrix4d()) ); CALL_SUBTEST_5( product(Matrix4f()) ); - CALL_SUBTEST_6( product1x1() ); + CALL_SUBTEST_6( product1x1<0>() ); + + CALL_SUBTEST_11( test_lazy_l1() ); + CALL_SUBTEST_12( test_lazy_l2() ); + CALL_SUBTEST_13( test_lazy_l3() ); + + CALL_SUBTEST_21( test_lazy_l1() ); + CALL_SUBTEST_22( test_lazy_l2() ); + CALL_SUBTEST_23( test_lazy_l3() ); + + CALL_SUBTEST_31( test_lazy_l1 >() ); + CALL_SUBTEST_32( test_lazy_l2 >() ); + CALL_SUBTEST_33( test_lazy_l3 >() ); + + CALL_SUBTEST_41( test_lazy_l1 >() ); + CALL_SUBTEST_42( test_lazy_l2 >() ); + CALL_SUBTEST_43( test_lazy_l3 >() ); + + CALL_SUBTEST_7(( test_linear_but_not_vectorizable() )); + CALL_SUBTEST_7(( test_linear_but_not_vectorizable() )); + CALL_SUBTEST_7(( test_linear_but_not_vectorizable() )); + + CALL_SUBTEST_6( bug_1311<3>() ); + CALL_SUBTEST_6( bug_1311<5>() ); } #ifdef EIGEN_TEST_PART_6 @@ -46,5 +269,25 @@ void test_product_small() Vector3f v = Vector3f::Random(); VERIFY_IS_APPROX( (v * v.transpose()) * v, (v * v.transpose()).eval() * v); } + + { + // regression test for pull-request #93 + Eigen::Matrix A; A.setRandom(); + Eigen::Matrix B; B.setRandom(); + Eigen::Matrix C; C.setRandom(); + VERIFY_IS_APPROX(B * A.inverse(), B * A.inverse()[0]); + VERIFY_IS_APPROX(A.inverse() * C, A.inverse()[0] * C); + } + + { + Eigen::Matrix A, B, C; + A.setRandom(); + C = A; + for(int k=0; k<79; ++k) + C = C * A; + B.noalias() = (((A*A)*(A*A))*((A*A)*(A*A))*((A*A)*(A*A))*((A*A)*(A*A))*((A*A)*(A*A)) * ((A*A)*(A*A))*((A*A)*(A*A))*((A*A)*(A*A))*((A*A)*(A*A))*((A*A)*(A*A))) + * (((A*A)*(A*A))*((A*A)*(A*A))*((A*A)*(A*A))*((A*A)*(A*A))*((A*A)*(A*A)) * ((A*A)*(A*A))*((A*A)*(A*A))*((A*A)*(A*A))*((A*A)*(A*A))*((A*A)*(A*A))); + VERIFY_IS_APPROX(B,C); + } #endif } diff --git a/ground/gcs/src/libs/eigen/test/product_symm.cpp b/ground/gcs/src/libs/eigen/test/product_symm.cpp index 74d7329b11..8c44383f9e 100644 --- a/ground/gcs/src/libs/eigen/test/product_symm.cpp +++ b/ground/gcs/src/libs/eigen/test/product_symm.cpp @@ -39,6 +39,24 @@ template void symm(int size = Size, in VERIFY_IS_APPROX(rhs12 = (s1*m2).template selfadjointView() * (s2*rhs1), rhs13 = (s1*m1) * (s2*rhs1)); + VERIFY_IS_APPROX(rhs12 = (s1*m2).transpose().template selfadjointView() * (s2*rhs1), + rhs13 = (s1*m1.transpose()) * (s2*rhs1)); + + VERIFY_IS_APPROX(rhs12 = (s1*m2).template selfadjointView().transpose() * (s2*rhs1), + rhs13 = (s1*m1.transpose()) * (s2*rhs1)); + + VERIFY_IS_APPROX(rhs12 = (s1*m2).conjugate().template selfadjointView() * (s2*rhs1), + rhs13 = (s1*m1).conjugate() * (s2*rhs1)); + + VERIFY_IS_APPROX(rhs12 = (s1*m2).template selfadjointView().conjugate() * (s2*rhs1), + rhs13 = (s1*m1).conjugate() * (s2*rhs1)); + + VERIFY_IS_APPROX(rhs12 = (s1*m2).adjoint().template selfadjointView() * (s2*rhs1), + rhs13 = (s1*m1).adjoint() * (s2*rhs1)); + + VERIFY_IS_APPROX(rhs12 = (s1*m2).template selfadjointView().adjoint() * (s2*rhs1), + rhs13 = (s1*m1).adjoint() * (s2*rhs1)); + m2 = m1.template triangularView(); rhs12.setRandom(); rhs13 = rhs12; m3 = m2.template selfadjointView(); VERIFY_IS_EQUAL(m1, m3); diff --git a/ground/gcs/src/libs/eigen/test/product_syrk.cpp b/ground/gcs/src/libs/eigen/test/product_syrk.cpp index 73c95000ce..e10f0f2f23 100644 --- a/ground/gcs/src/libs/eigen/test/product_syrk.cpp +++ b/ground/gcs/src/libs/eigen/test/product_syrk.cpp @@ -125,11 +125,12 @@ void test_product_syrk() int s; s = internal::random(1,EIGEN_TEST_MAX_SIZE); CALL_SUBTEST_1( syrk(MatrixXf(s, s)) ); - s = internal::random(1,EIGEN_TEST_MAX_SIZE); CALL_SUBTEST_2( syrk(MatrixXd(s, s)) ); + TEST_SET_BUT_UNUSED_VARIABLE(s) + s = internal::random(1,EIGEN_TEST_MAX_SIZE/2); CALL_SUBTEST_3( syrk(MatrixXcf(s, s)) ); - s = internal::random(1,EIGEN_TEST_MAX_SIZE/2); CALL_SUBTEST_4( syrk(MatrixXcd(s, s)) ); + TEST_SET_BUT_UNUSED_VARIABLE(s) } } diff --git a/ground/gcs/src/libs/eigen/test/product_trmm.cpp b/ground/gcs/src/libs/eigen/test/product_trmm.cpp index d715b9a363..12e554410a 100644 --- a/ground/gcs/src/libs/eigen/test/product_trmm.cpp +++ b/ground/gcs/src/libs/eigen/test/product_trmm.cpp @@ -9,10 +9,18 @@ #include "main.h" +template +int get_random_size() +{ + const int factor = NumTraits::ReadCost; + const int max_test_size = EIGEN_TEST_MAX_SIZE>2*factor ? EIGEN_TEST_MAX_SIZE/factor : EIGEN_TEST_MAX_SIZE; + return internal::random(1,max_test_size); +} + template -void trmm(int rows=internal::random(1,EIGEN_TEST_MAX_SIZE), - int cols=internal::random(1,EIGEN_TEST_MAX_SIZE), - int otherCols = OtherCols==Dynamic?internal::random(1,EIGEN_TEST_MAX_SIZE):OtherCols) +void trmm(int rows=get_random_size(), + int cols=get_random_size(), + int otherCols = OtherCols==Dynamic?get_random_size():OtherCols) { typedef Matrix TriMatrix; typedef Matrix OnTheRight; @@ -42,13 +50,13 @@ void trmm(int rows=internal::random(1,EIGEN_TEST_MAX_SIZE), VERIFY_IS_APPROX( ge_xs.noalias() = mat.template triangularView() * ge_right, tri * ge_right); VERIFY_IS_APPROX( ge_sx.noalias() = ge_left * mat.template triangularView(), ge_left * tri); - + VERIFY_IS_APPROX( ge_xs.noalias() = (s1*mat.adjoint()).template triangularView() * (s2*ge_left.transpose()), s1*triTr.conjugate() * (s2*ge_left.transpose())); VERIFY_IS_APPROX( ge_sx.noalias() = ge_right.transpose() * mat.adjoint().template triangularView(), ge_right.transpose() * triTr.conjugate()); VERIFY_IS_APPROX( ge_xs.noalias() = (s1*mat.adjoint()).template triangularView() * (s2*ge_left.adjoint()), s1*triTr.conjugate() * (s2*ge_left.adjoint())); VERIFY_IS_APPROX( ge_sx.noalias() = ge_right.adjoint() * mat.adjoint().template triangularView(), ge_right.adjoint() * triTr.conjugate()); - + ge_xs_save = ge_xs; VERIFY_IS_APPROX( (ge_xs_save + s1*triTr.conjugate() * (s2*ge_left.adjoint())).eval(), ge_xs.noalias() += (s1*mat.adjoint()).template triangularView() * (s2*ge_left.adjoint()) ); ge_sx.setRandom(); @@ -61,13 +69,13 @@ void trmm(int rows=internal::random(1,EIGEN_TEST_MAX_SIZE), } template -void trmv(int rows=internal::random(1,EIGEN_TEST_MAX_SIZE), int cols=internal::random(1,EIGEN_TEST_MAX_SIZE)) +void trmv(int rows=get_random_size(), int cols=get_random_size()) { trmm(rows,cols,1); } template -void trmm(int rows=internal::random(1,EIGEN_TEST_MAX_SIZE), int cols=internal::random(1,EIGEN_TEST_MAX_SIZE), int otherCols = internal::random(1,EIGEN_TEST_MAX_SIZE)) +void trmm(int rows=get_random_size(), int cols=get_random_size(), int otherCols = get_random_size()) { trmm(rows,cols,otherCols); } diff --git a/ground/gcs/src/libs/eigen/test/product_trmv.cpp b/ground/gcs/src/libs/eigen/test/product_trmv.cpp index 4c3c435c25..57a202afc6 100644 --- a/ground/gcs/src/libs/eigen/test/product_trmv.cpp +++ b/ground/gcs/src/libs/eigen/test/product_trmv.cpp @@ -78,12 +78,14 @@ void test_product_trmv() CALL_SUBTEST_1( trmv(Matrix()) ); CALL_SUBTEST_2( trmv(Matrix()) ); CALL_SUBTEST_3( trmv(Matrix3d()) ); + s = internal::random(1,EIGEN_TEST_MAX_SIZE/2); CALL_SUBTEST_4( trmv(MatrixXcf(s,s)) ); - s = internal::random(1,EIGEN_TEST_MAX_SIZE/2); CALL_SUBTEST_5( trmv(MatrixXcd(s,s)) ); + TEST_SET_BUT_UNUSED_VARIABLE(s) + s = internal::random(1,EIGEN_TEST_MAX_SIZE); CALL_SUBTEST_6( trmv(Matrix(s, s)) ); + TEST_SET_BUT_UNUSED_VARIABLE(s) } - TEST_SET_BUT_UNUSED_VARIABLE(s); } diff --git a/ground/gcs/src/libs/eigen/test/product_trsolve.cpp b/ground/gcs/src/libs/eigen/test/product_trsolve.cpp index 69892b3a82..4b97fa9d64 100644 --- a/ground/gcs/src/libs/eigen/test/product_trsolve.cpp +++ b/ground/gcs/src/libs/eigen/test/product_trsolve.cpp @@ -84,10 +84,18 @@ void test_product_trsolve() CALL_SUBTEST_4((trsolve,Dynamic,Dynamic>(internal::random(1,EIGEN_TEST_MAX_SIZE/2),internal::random(1,EIGEN_TEST_MAX_SIZE/2)))); // vectors - CALL_SUBTEST_1((trsolve(internal::random(1,EIGEN_TEST_MAX_SIZE)))); - CALL_SUBTEST_5((trsolve,Dynamic,1>(internal::random(1,EIGEN_TEST_MAX_SIZE)))); - CALL_SUBTEST_6((trsolve())); - CALL_SUBTEST_7((trsolve())); - CALL_SUBTEST_8((trsolve,4,1>())); + CALL_SUBTEST_5((trsolve(internal::random(1,EIGEN_TEST_MAX_SIZE)))); + CALL_SUBTEST_6((trsolve(internal::random(1,EIGEN_TEST_MAX_SIZE)))); + CALL_SUBTEST_7((trsolve,Dynamic,1>(internal::random(1,EIGEN_TEST_MAX_SIZE)))); + CALL_SUBTEST_8((trsolve,Dynamic,1>(internal::random(1,EIGEN_TEST_MAX_SIZE)))); + + // meta-unrollers + CALL_SUBTEST_9((trsolve())); + CALL_SUBTEST_10((trsolve())); + CALL_SUBTEST_11((trsolve,4,1>())); + CALL_SUBTEST_12((trsolve())); + CALL_SUBTEST_13((trsolve())); + CALL_SUBTEST_14((trsolve())); + } } diff --git a/ground/gcs/src/libs/eigen/test/qr.cpp b/ground/gcs/src/libs/eigen/test/qr.cpp index a79e0dd34f..dfcc1e8f97 100644 --- a/ground/gcs/src/libs/eigen/test/qr.cpp +++ b/ground/gcs/src/libs/eigen/test/qr.cpp @@ -54,6 +54,8 @@ template void qr_invertible() { using std::log; using std::abs; + using std::pow; + using std::max; typedef typename NumTraits::Real RealScalar; typedef typename MatrixType::Scalar Scalar; @@ -65,7 +67,7 @@ template void qr_invertible() if (internal::is_same::value) { // let's build a matrix more stable to inverse - MatrixType a = MatrixType::Random(size,size*2); + MatrixType a = MatrixType::Random(size,size*4); m1 += a * a.adjoint(); } @@ -81,8 +83,11 @@ template void qr_invertible() m3 = qr.householderQ(); // get a unitary m1 = m3 * m1 * m3; qr.compute(m1); - VERIFY_IS_APPROX(absdet, qr.absDeterminant()); VERIFY_IS_APPROX(log(absdet), qr.logAbsDeterminant()); + // This test is tricky if the determinant becomes too small. + // Since we generate random numbers with magnitude rrange [0,1], the average determinant is 0.5^size + VERIFY_IS_MUCH_SMALLER_THAN( abs(absdet-qr.absDeterminant()), numext::maxi(RealScalar(pow(0.5,size)),numext::maxi(abs(absdet),abs(qr.absDeterminant()))) ); + } template void qr_verify_assert() diff --git a/ground/gcs/src/libs/eigen/test/qr_colpivoting.cpp b/ground/gcs/src/libs/eigen/test/qr_colpivoting.cpp index eb3feac01a..26ed27f5cd 100644 --- a/ground/gcs/src/libs/eigen/test/qr_colpivoting.cpp +++ b/ground/gcs/src/libs/eigen/test/qr_colpivoting.cpp @@ -10,21 +10,103 @@ #include "main.h" #include +#include + +template +void cod() { + typedef typename MatrixType::Index Index; + + Index rows = internal::random(2, EIGEN_TEST_MAX_SIZE); + Index cols = internal::random(2, EIGEN_TEST_MAX_SIZE); + Index cols2 = internal::random(2, EIGEN_TEST_MAX_SIZE); + Index rank = internal::random(1, (std::min)(rows, cols) - 1); + + typedef typename MatrixType::Scalar Scalar; + typedef Matrix + MatrixQType; + MatrixType matrix; + createRandomPIMatrixOfRank(rank, rows, cols, matrix); + CompleteOrthogonalDecomposition cod(matrix); + VERIFY(rank == cod.rank()); + VERIFY(cols - cod.rank() == cod.dimensionOfKernel()); + VERIFY(!cod.isInjective()); + VERIFY(!cod.isInvertible()); + VERIFY(!cod.isSurjective()); + + MatrixQType q = cod.householderQ(); + VERIFY_IS_UNITARY(q); + + MatrixType z = cod.matrixZ(); + VERIFY_IS_UNITARY(z); + + MatrixType t; + t.setZero(rows, cols); + t.topLeftCorner(rank, rank) = + cod.matrixT().topLeftCorner(rank, rank).template triangularView(); + + MatrixType c = q * t * z * cod.colsPermutation().inverse(); + VERIFY_IS_APPROX(matrix, c); + + MatrixType exact_solution = MatrixType::Random(cols, cols2); + MatrixType rhs = matrix * exact_solution; + MatrixType cod_solution = cod.solve(rhs); + VERIFY_IS_APPROX(rhs, matrix * cod_solution); + + // Verify that we get the same minimum-norm solution as the SVD. + JacobiSVD svd(matrix, ComputeThinU | ComputeThinV); + MatrixType svd_solution = svd.solve(rhs); + VERIFY_IS_APPROX(cod_solution, svd_solution); + + MatrixType pinv = cod.pseudoInverse(); + VERIFY_IS_APPROX(cod_solution, pinv * rhs); +} + +template +void cod_fixedsize() { + enum { + Rows = MatrixType::RowsAtCompileTime, + Cols = MatrixType::ColsAtCompileTime + }; + typedef typename MatrixType::Scalar Scalar; + int rank = internal::random(1, (std::min)(int(Rows), int(Cols)) - 1); + Matrix matrix; + createRandomPIMatrixOfRank(rank, Rows, Cols, matrix); + CompleteOrthogonalDecomposition > cod(matrix); + VERIFY(rank == cod.rank()); + VERIFY(Cols - cod.rank() == cod.dimensionOfKernel()); + VERIFY(cod.isInjective() == (rank == Rows)); + VERIFY(cod.isSurjective() == (rank == Cols)); + VERIFY(cod.isInvertible() == (cod.isInjective() && cod.isSurjective())); + + Matrix exact_solution; + exact_solution.setRandom(Cols, Cols2); + Matrix rhs = matrix * exact_solution; + Matrix cod_solution = cod.solve(rhs); + VERIFY_IS_APPROX(rhs, matrix * cod_solution); + + // Verify that we get the same minimum-norm solution as the SVD. + JacobiSVD svd(matrix, ComputeFullU | ComputeFullV); + Matrix svd_solution = svd.solve(rhs); + VERIFY_IS_APPROX(cod_solution, svd_solution); +} template void qr() { + using std::sqrt; typedef typename MatrixType::Index Index; Index rows = internal::random(2,EIGEN_TEST_MAX_SIZE), cols = internal::random(2,EIGEN_TEST_MAX_SIZE), cols2 = internal::random(2,EIGEN_TEST_MAX_SIZE); Index rank = internal::random(1, (std::min)(rows, cols)-1); typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::RealScalar RealScalar; typedef Matrix MatrixQType; MatrixType m1; createRandomPIMatrixOfRank(rank,rows,cols,m1); ColPivHouseholderQR qr(m1); - VERIFY(rank == qr.rank()); - VERIFY(cols - qr.rank() == qr.dimensionOfKernel()); + VERIFY_IS_EQUAL(rank, qr.rank()); + VERIFY_IS_EQUAL(cols - qr.rank(), qr.dimensionOfKernel()); VERIFY(!qr.isInjective()); VERIFY(!qr.isInvertible()); VERIFY(!qr.isSurjective()); @@ -36,26 +118,59 @@ template void qr() MatrixType c = q * r * qr.colsPermutation().inverse(); VERIFY_IS_APPROX(m1, c); + // Verify that the absolute value of the diagonal elements in R are + // non-increasing until they reach the singularity threshold. + RealScalar threshold = + sqrt(RealScalar(rows)) * numext::abs(r(0, 0)) * NumTraits::epsilon(); + for (Index i = 0; i < (std::min)(rows, cols) - 1; ++i) { + RealScalar x = numext::abs(r(i, i)); + RealScalar y = numext::abs(r(i + 1, i + 1)); + if (x < threshold && y < threshold) continue; + if (!test_isApproxOrLessThan(y, x)) { + for (Index j = 0; j < (std::min)(rows, cols); ++j) { + std::cout << "i = " << j << ", |r_ii| = " << numext::abs(r(j, j)) << std::endl; + } + std::cout << "Failure at i=" << i << ", rank=" << rank + << ", threshold=" << threshold << std::endl; + } + VERIFY_IS_APPROX_OR_LESS_THAN(y, x); + } + MatrixType m2 = MatrixType::Random(cols,cols2); MatrixType m3 = m1*m2; m2 = MatrixType::Random(cols,cols2); m2 = qr.solve(m3); VERIFY_IS_APPROX(m3, m1*m2); + + { + Index size = rows; + do { + m1 = MatrixType::Random(size,size); + qr.compute(m1); + } while(!qr.isInvertible()); + MatrixType m1_inv = qr.inverse(); + m3 = m1 * MatrixType::Random(size,cols2); + m2 = qr.solve(m3); + VERIFY_IS_APPROX(m2, m1_inv*m3); + } } template void qr_fixedsize() { + using std::sqrt; + using std::abs; enum { Rows = MatrixType::RowsAtCompileTime, Cols = MatrixType::ColsAtCompileTime }; typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::RealScalar RealScalar; int rank = internal::random(1, (std::min)(int(Rows), int(Cols))-1); Matrix m1; createRandomPIMatrixOfRank(rank,Rows,Cols,m1); ColPivHouseholderQR > qr(m1); - VERIFY(rank == qr.rank()); - VERIFY(Cols - qr.rank() == qr.dimensionOfKernel()); - VERIFY(qr.isInjective() == (rank == Rows)); - VERIFY(qr.isSurjective() == (rank == Cols)); - VERIFY(qr.isInvertible() == (qr.isInjective() && qr.isSurjective())); + VERIFY_IS_EQUAL(rank, qr.rank()); + VERIFY_IS_EQUAL(Cols - qr.rank(), qr.dimensionOfKernel()); + VERIFY_IS_EQUAL(qr.isInjective(), (rank == Rows)); + VERIFY_IS_EQUAL(qr.isSurjective(), (rank == Cols)); + VERIFY_IS_EQUAL(qr.isInvertible(), (qr.isInjective() && qr.isSurjective())); Matrix r = qr.matrixQR().template triangularView(); Matrix c = qr.householderQ() * r * qr.colsPermutation().inverse(); @@ -66,6 +181,71 @@ template void qr_fixedsize() m2 = Matrix::Random(Cols,Cols2); m2 = qr.solve(m3); VERIFY_IS_APPROX(m3, m1*m2); + // Verify that the absolute value of the diagonal elements in R are + // non-increasing until they reache the singularity threshold. + RealScalar threshold = + sqrt(RealScalar(Rows)) * (std::abs)(r(0, 0)) * NumTraits::epsilon(); + for (Index i = 0; i < (std::min)(int(Rows), int(Cols)) - 1; ++i) { + RealScalar x = numext::abs(r(i, i)); + RealScalar y = numext::abs(r(i + 1, i + 1)); + if (x < threshold && y < threshold) continue; + if (!test_isApproxOrLessThan(y, x)) { + for (Index j = 0; j < (std::min)(int(Rows), int(Cols)); ++j) { + std::cout << "i = " << j << ", |r_ii| = " << numext::abs(r(j, j)) << std::endl; + } + std::cout << "Failure at i=" << i << ", rank=" << rank + << ", threshold=" << threshold << std::endl; + } + VERIFY_IS_APPROX_OR_LESS_THAN(y, x); + } +} + +// This test is meant to verify that pivots are chosen such that +// even for a graded matrix, the diagonal of R falls of roughly +// monotonically until it reaches the threshold for singularity. +// We use the so-called Kahan matrix, which is a famous counter-example +// for rank-revealing QR. See +// http://www.netlib.org/lapack/lawnspdf/lawn176.pdf +// page 3 for more detail. +template void qr_kahan_matrix() +{ + using std::sqrt; + using std::abs; + typedef typename MatrixType::Index Index; + typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::RealScalar RealScalar; + + Index rows = 300, cols = rows; + + MatrixType m1; + m1.setZero(rows,cols); + RealScalar s = std::pow(NumTraits::epsilon(), 1.0 / rows); + RealScalar c = std::sqrt(1 - s*s); + RealScalar pow_s_i(1.0); // pow(s,i) + for (Index i = 0; i < rows; ++i) { + m1(i, i) = pow_s_i; + m1.row(i).tail(rows - i - 1) = -pow_s_i * c * MatrixType::Ones(1, rows - i - 1); + pow_s_i *= s; + } + m1 = (m1 + m1.transpose()).eval(); + ColPivHouseholderQR qr(m1); + MatrixType r = qr.matrixQR().template triangularView(); + + RealScalar threshold = + std::sqrt(RealScalar(rows)) * numext::abs(r(0, 0)) * NumTraits::epsilon(); + for (Index i = 0; i < (std::min)(rows, cols) - 1; ++i) { + RealScalar x = numext::abs(r(i, i)); + RealScalar y = numext::abs(r(i + 1, i + 1)); + if (x < threshold && y < threshold) continue; + if (!test_isApproxOrLessThan(y, x)) { + for (Index j = 0; j < (std::min)(rows, cols); ++j) { + std::cout << "i = " << j << ", |r_ii| = " << numext::abs(r(j, j)) << std::endl; + } + std::cout << "Failure at i=" << i << ", rank=" << qr.rank() + << ", threshold=" << threshold << std::endl; + } + VERIFY_IS_APPROX_OR_LESS_THAN(y, x); + } } template void qr_invertible() @@ -131,6 +311,15 @@ void test_qr_colpivoting() CALL_SUBTEST_5(( qr_fixedsize, 1 >() )); } + for(int i = 0; i < g_repeat; i++) { + CALL_SUBTEST_1( cod() ); + CALL_SUBTEST_2( cod() ); + CALL_SUBTEST_3( cod() ); + CALL_SUBTEST_4(( cod_fixedsize, 4 >() )); + CALL_SUBTEST_5(( cod_fixedsize, 3 >() )); + CALL_SUBTEST_5(( cod_fixedsize, 1 >() )); + } + for(int i = 0; i < g_repeat; i++) { CALL_SUBTEST_1( qr_invertible() ); CALL_SUBTEST_2( qr_invertible() ); @@ -147,4 +336,7 @@ void test_qr_colpivoting() // Test problem size constructors CALL_SUBTEST_9(ColPivHouseholderQR(10, 20)); + + CALL_SUBTEST_1( qr_kahan_matrix() ); + CALL_SUBTEST_2( qr_kahan_matrix() ); } diff --git a/ground/gcs/src/libs/eigen/test/qr_fullpivoting.cpp b/ground/gcs/src/libs/eigen/test/qr_fullpivoting.cpp index 511f2473f7..70e89c198b 100644 --- a/ground/gcs/src/libs/eigen/test/qr_fullpivoting.cpp +++ b/ground/gcs/src/libs/eigen/test/qr_fullpivoting.cpp @@ -15,16 +15,20 @@ template void qr() { typedef typename MatrixType::Index Index; - Index rows = internal::random(20,200), cols = internal::random(20,200), cols2 = internal::random(20,200); - Index rank = internal::random(1, (std::min)(rows, cols)-1); + Index max_size = EIGEN_TEST_MAX_SIZE; + Index min_size = numext::maxi(1,EIGEN_TEST_MAX_SIZE/10); + Index rows = internal::random(min_size,max_size), + cols = internal::random(min_size,max_size), + cols2 = internal::random(min_size,max_size), + rank = internal::random(1, (std::min)(rows, cols)-1); typedef typename MatrixType::Scalar Scalar; typedef Matrix MatrixQType; MatrixType m1; createRandomPIMatrixOfRank(rank,rows,cols,m1); FullPivHouseholderQR qr(m1); - VERIFY(rank == qr.rank()); - VERIFY(cols - qr.rank() == qr.dimensionOfKernel()); + VERIFY_IS_EQUAL(rank, qr.rank()); + VERIFY_IS_EQUAL(cols - qr.rank(), qr.dimensionOfKernel()); VERIFY(!qr.isInjective()); VERIFY(!qr.isInvertible()); VERIFY(!qr.isSurjective()); @@ -40,12 +44,28 @@ template void qr() MatrixType c = qr.matrixQ() * r * qr.colsPermutation().inverse(); VERIFY_IS_APPROX(m1, c); - + + // stress the ReturnByValue mechanism + MatrixType tmp; + VERIFY_IS_APPROX(tmp.noalias() = qr.matrixQ() * r, (qr.matrixQ() * r).eval()); + MatrixType m2 = MatrixType::Random(cols,cols2); MatrixType m3 = m1*m2; m2 = MatrixType::Random(cols,cols2); m2 = qr.solve(m3); VERIFY_IS_APPROX(m3, m1*m2); + + { + Index size = rows; + do { + m1 = MatrixType::Random(size,size); + qr.compute(m1); + } while(!qr.isInvertible()); + MatrixType m1_inv = qr.inverse(); + m3 = m1 * MatrixType::Random(size,cols2); + m2 = qr.solve(m3); + VERIFY_IS_APPROX(m2, m1_inv*m3); + } } template void qr_invertible() @@ -55,7 +75,9 @@ template void qr_invertible() typedef typename NumTraits::Real RealScalar; typedef typename MatrixType::Scalar Scalar; - int size = internal::random(10,50); + Index max_size = numext::mini(50,EIGEN_TEST_MAX_SIZE); + Index min_size = numext::maxi(1,EIGEN_TEST_MAX_SIZE/10); + Index size = internal::random(min_size,max_size); MatrixType m1(size, size), m2(size, size), m3(size, size); m1 = MatrixType::Random(size,size); diff --git a/ground/gcs/src/libs/eigen/test/rand.cpp b/ground/gcs/src/libs/eigen/test/rand.cpp new file mode 100644 index 0000000000..51cf01773f --- /dev/null +++ b/ground/gcs/src/libs/eigen/test/rand.cpp @@ -0,0 +1,118 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2015 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "main.h" + +typedef long long int64; + +template Scalar check_in_range(Scalar x, Scalar y) +{ + Scalar r = internal::random(x,y); + VERIFY(r>=x); + if(y>=x) + { + VERIFY(r<=y); + } + return r; +} + +template void check_all_in_range(Scalar x, Scalar y) +{ + Array mask(y-x+1); + mask.fill(0); + long n = (y-x+1)*32; + for(long k=0; k0).all() ); +} + +template void check_histogram(Scalar x, Scalar y, int bins) +{ + Array hist(bins); + hist.fill(0); + int f = 100000; + int n = bins*f; + int64 range = int64(y)-int64(x); + int divisor = int((range+1)/bins); + assert(((range+1)%bins)==0); + for(int k=0; k()/double(f))-1.0).abs()<0.02).all() ); +} + +void test_rand() +{ + long long_ref = NumTraits::highest()/10; + signed char char_offset = (std::min)(g_repeat,64); + signed char short_offset = (std::min)(g_repeat,16000); + + for(int i = 0; i < g_repeat*10000; i++) { + CALL_SUBTEST(check_in_range(10,11)); + CALL_SUBTEST(check_in_range(1.24234523,1.24234523)); + CALL_SUBTEST(check_in_range(-1,1)); + CALL_SUBTEST(check_in_range(-1432.2352,-1432.2352)); + + CALL_SUBTEST(check_in_range(10,11)); + CALL_SUBTEST(check_in_range(1.24234523,1.24234523)); + CALL_SUBTEST(check_in_range(-1,1)); + CALL_SUBTEST(check_in_range(-1432.2352,-1432.2352)); + + CALL_SUBTEST(check_in_range(0,-1)); + CALL_SUBTEST(check_in_range(0,-1)); + CALL_SUBTEST(check_in_range(0,-1)); + CALL_SUBTEST(check_in_range(-673456,673456)); + CALL_SUBTEST(check_in_range(-RAND_MAX+10,RAND_MAX-10)); + CALL_SUBTEST(check_in_range(-24345,24345)); + CALL_SUBTEST(check_in_range(-long_ref,long_ref)); + } + + CALL_SUBTEST(check_all_in_range(11,11)); + CALL_SUBTEST(check_all_in_range(11,11+char_offset)); + CALL_SUBTEST(check_all_in_range(-5,5)); + CALL_SUBTEST(check_all_in_range(-11-char_offset,-11)); + CALL_SUBTEST(check_all_in_range(-126,-126+char_offset)); + CALL_SUBTEST(check_all_in_range(126-char_offset,126)); + CALL_SUBTEST(check_all_in_range(-126,126)); + + CALL_SUBTEST(check_all_in_range(11,11)); + CALL_SUBTEST(check_all_in_range(11,11+short_offset)); + CALL_SUBTEST(check_all_in_range(-5,5)); + CALL_SUBTEST(check_all_in_range(-11-short_offset,-11)); + CALL_SUBTEST(check_all_in_range(-24345,-24345+short_offset)); + CALL_SUBTEST(check_all_in_range(24345,24345+short_offset)); + + CALL_SUBTEST(check_all_in_range(11,11)); + CALL_SUBTEST(check_all_in_range(11,11+g_repeat)); + CALL_SUBTEST(check_all_in_range(-5,5)); + CALL_SUBTEST(check_all_in_range(-11-g_repeat,-11)); + CALL_SUBTEST(check_all_in_range(-673456,-673456+g_repeat)); + CALL_SUBTEST(check_all_in_range(673456,673456+g_repeat)); + + CALL_SUBTEST(check_all_in_range(11,11)); + CALL_SUBTEST(check_all_in_range(11,11+g_repeat)); + CALL_SUBTEST(check_all_in_range(-5,5)); + CALL_SUBTEST(check_all_in_range(-11-g_repeat,-11)); + CALL_SUBTEST(check_all_in_range(-long_ref,-long_ref+g_repeat)); + CALL_SUBTEST(check_all_in_range( long_ref, long_ref+g_repeat)); + + CALL_SUBTEST(check_histogram(-5,5,11)); + int bins = 100; + CALL_SUBTEST(check_histogram(-3333,-3333+bins*(3333/bins)-1,bins)); + bins = 1000; + CALL_SUBTEST(check_histogram(-RAND_MAX+10,-RAND_MAX+10+bins*(RAND_MAX/bins)-1,bins)); + CALL_SUBTEST(check_histogram(-RAND_MAX+10,-int64(RAND_MAX)+10+bins*(2*int64(RAND_MAX)/bins)-1,bins)); +} diff --git a/ground/gcs/src/libs/eigen/test/real_qz.cpp b/ground/gcs/src/libs/eigen/test/real_qz.cpp index a1766c6d95..99ac31235f 100644 --- a/ground/gcs/src/libs/eigen/test/real_qz.cpp +++ b/ground/gcs/src/libs/eigen/test/real_qz.cpp @@ -7,6 +7,7 @@ // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. +#define EIGEN_RUNTIME_NO_MALLOC #include "main.h" #include #include @@ -41,7 +42,11 @@ template void real_qz(const MatrixType& m) break; } - RealQZ qz(A,B); + RealQZ qz(dim); + // TODO enable full-prealocation of required memory, this probably requires an in-place mode for HessenbergDecomposition + //Eigen::internal::set_is_malloc_allowed(false); + qz.compute(A,B); + //Eigen::internal::set_is_malloc_allowed(true); VERIFY_IS_EQUAL(qz.info(), Success); // check for zeros @@ -49,11 +54,20 @@ template void real_qz(const MatrixType& m) for (Index i=0; i void matrixRedux(const MatrixType& m) @@ -21,7 +24,7 @@ template void matrixRedux(const MatrixType& m) MatrixType m1 = MatrixType::Random(rows, cols); // The entries of m1 are uniformly distributed in [0,1], so m1.prod() is very small. This may lead to test - // failures if we underflow into denormals. Thus, we scale so that entires are close to 1. + // failures if we underflow into denormals. Thus, we scale so that entries are close to 1. MatrixType m1_for_prod = MatrixType::Ones(rows, cols) + RealScalar(0.2) * m1; VERIFY_IS_MUCH_SMALLER_THAN(MatrixType::Zero(rows, cols).sum(), Scalar(1)); @@ -65,6 +68,12 @@ template void matrixRedux(const MatrixType& m) // test empty objects VERIFY_IS_APPROX(m1.block(r0,c0,0,0).sum(), Scalar(0)); VERIFY_IS_APPROX(m1.block(r0,c0,0,0).prod(), Scalar(1)); + + // test nesting complex expression + VERIFY_EVALUATION_COUNT( (m1.matrix()*m1.matrix().transpose()).sum(), (MatrixType::IsVectorAtCompileTime && MatrixType::SizeAtCompileTime!=1 ? 0 : 1) ); + Matrix m2(rows,rows); + m2.setRandom(); + VERIFY_EVALUATION_COUNT( ((m1.matrix()*m1.matrix().transpose())+m2).sum(),(MatrixType::IsVectorAtCompileTime && MatrixType::SizeAtCompileTime!=1 ? 0 : 1)); } template void vectorRedux(const VectorType& w) @@ -147,8 +156,10 @@ void test_redux() CALL_SUBTEST_1( matrixRedux(Array()) ); CALL_SUBTEST_2( matrixRedux(Matrix2f()) ); CALL_SUBTEST_2( matrixRedux(Array2f()) ); + CALL_SUBTEST_2( matrixRedux(Array22f()) ); CALL_SUBTEST_3( matrixRedux(Matrix4d()) ); CALL_SUBTEST_3( matrixRedux(Array4d()) ); + CALL_SUBTEST_3( matrixRedux(Array44d()) ); CALL_SUBTEST_4( matrixRedux(MatrixXcf(internal::random(1,maxsize), internal::random(1,maxsize))) ); CALL_SUBTEST_4( matrixRedux(ArrayXXcf(internal::random(1,maxsize), internal::random(1,maxsize))) ); CALL_SUBTEST_5( matrixRedux(MatrixXd (internal::random(1,maxsize), internal::random(1,maxsize))) ); diff --git a/ground/gcs/src/libs/eigen/test/ref.cpp b/ground/gcs/src/libs/eigen/test/ref.cpp index 8297e263a9..769db0414b 100644 --- a/ground/gcs/src/libs/eigen/test/ref.cpp +++ b/ground/gcs/src/libs/eigen/test/ref.cpp @@ -12,26 +12,10 @@ #undef EIGEN_DEFAULT_TO_ROW_MAJOR #endif -static int nb_temporaries; - -inline void on_temporary_creation(int) { - // here's a great place to set a breakpoint when debugging failures in this test! - nb_temporaries++; -} - - -#define EIGEN_DENSE_STORAGE_CTOR_PLUGIN { on_temporary_creation(size); } +#define TEST_ENABLE_TEMPORARY_TRACKING #include "main.h" -#define VERIFY_EVALUATION_COUNT(XPR,N) {\ - nb_temporaries = 0; \ - XPR; \ - if(nb_temporaries!=N) std::cerr << "nb_temporaries == " << nb_temporaries << "\n"; \ - VERIFY( (#XPR) && nb_temporaries==N ); \ - } - - // test Ref.h // Deal with i387 extended precision @@ -248,6 +232,12 @@ int test_ref_overload_fun1(Ref ) { return 3; } int test_ref_overload_fun2(Ref ) { return 4; } int test_ref_overload_fun2(Ref ) { return 5; } +void test_ref_ambiguous(const Ref &A, Ref B) +{ + B = A; + B = A - A; +} + // See also bug 969 void test_ref_overloads() { @@ -260,6 +250,9 @@ void test_ref_overloads() VERIFY( test_ref_overload_fun2(Ad)==4 ); VERIFY( test_ref_overload_fun2(Ad+Bd)==4 ); VERIFY( test_ref_overload_fun2(Af+Bf)==5 ); + + ArrayXd A, B; + test_ref_ambiguous(A, B); } void test_ref() diff --git a/ground/gcs/src/libs/eigen/test/runtest.sh b/ground/gcs/src/libs/eigen/test/runtest.sh deleted file mode 100755 index 2be250819f..0000000000 --- a/ground/gcs/src/libs/eigen/test/runtest.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash - -black='\E[30m' -red='\E[31m' -green='\E[32m' -yellow='\E[33m' -blue='\E[34m' -magenta='\E[35m' -cyan='\E[36m' -white='\E[37m' - -if ! ./$1 > /dev/null 2> .runtest.log ; then - echo -e $red Test $1 failed: $black - echo -e $blue - cat .runtest.log - echo -e $black - exit 1 -else -echo -e $green Test $1 passed$black -fi diff --git a/ground/gcs/src/libs/eigen/test/rvalue_types.cpp b/ground/gcs/src/libs/eigen/test/rvalue_types.cpp index b3c85652cb..8887f1b1b9 100644 --- a/ground/gcs/src/libs/eigen/test/rvalue_types.cpp +++ b/ground/gcs/src/libs/eigen/test/rvalue_types.cpp @@ -11,20 +11,22 @@ #include -#ifdef EIGEN_HAVE_RVALUE_REFERENCES +using internal::UIntPtr; + +#if EIGEN_HAS_RVALUE_REFERENCES template void rvalue_copyassign(const MatrixType& m) { typedef typename internal::traits::Scalar Scalar; - + // create a temporary which we are about to destroy by moving MatrixType tmp = m; - long src_address = reinterpret_cast(tmp.data()); - + UIntPtr src_address = reinterpret_cast(tmp.data()); + // move the temporary to n MatrixType n = std::move(tmp); - long dst_address = reinterpret_cast(n.data()); + UIntPtr dst_address = reinterpret_cast(n.data()); if (MatrixType::RowsAtCompileTime==Dynamic|| MatrixType::ColsAtCompileTime==Dynamic) { @@ -51,7 +53,7 @@ void test_rvalue_types() CALL_SUBTEST_1(rvalue_copyassign( Matrix::Random(50).eval() )); CALL_SUBTEST_1(rvalue_copyassign( Array::Random(50).eval() )); - + CALL_SUBTEST_2(rvalue_copyassign( Array::Random().eval() )); CALL_SUBTEST_2(rvalue_copyassign( Array::Random().eval() )); CALL_SUBTEST_2(rvalue_copyassign( Array::Random().eval() )); diff --git a/ground/gcs/src/libs/eigen/test/schur_complex.cpp b/ground/gcs/src/libs/eigen/test/schur_complex.cpp index 5e869790f4..deb78e44e6 100644 --- a/ground/gcs/src/libs/eigen/test/schur_complex.cpp +++ b/ground/gcs/src/libs/eigen/test/schur_complex.cpp @@ -25,7 +25,7 @@ template void schur(int size = MatrixType::ColsAtCompileTim ComplexMatrixType T = schurOfA.matrixT(); for(int row = 1; row < size; ++row) { for(int col = 0; col < row; ++col) { - VERIFY(T(row,col) == (typename MatrixType::Scalar)0); + VERIFY(T(row,col) == (typename MatrixType::Scalar)0); } } VERIFY_IS_APPROX(A.template cast(), U * T * U.adjoint()); @@ -70,7 +70,7 @@ template void schur(int size = MatrixType::ColsAtCompileTim VERIFY_IS_EQUAL(cs1.matrixT(), csOnlyT.matrixT()); VERIFY_RAISES_ASSERT(csOnlyT.matrixU()); - if (size > 1) + if (size > 1 && size < 20) { // Test matrix with NaN A(0,0) = std::numeric_limits::quiet_NaN(); diff --git a/ground/gcs/src/libs/eigen/test/schur_real.cpp b/ground/gcs/src/libs/eigen/test/schur_real.cpp index 36b9c24d1d..4aede87df6 100644 --- a/ground/gcs/src/libs/eigen/test/schur_real.cpp +++ b/ground/gcs/src/libs/eigen/test/schur_real.cpp @@ -82,7 +82,7 @@ template void schur(int size = MatrixType::ColsAtCompileTim Atriangular.template triangularView().setZero(); rs3.setMaxIterations(1).compute(Atriangular); // triangular matrices do not need any iterations VERIFY_IS_EQUAL(rs3.info(), Success); - VERIFY_IS_EQUAL(rs3.matrixT(), Atriangular); + VERIFY_IS_APPROX(rs3.matrixT(), Atriangular); // approx because of scaling... VERIFY_IS_EQUAL(rs3.matrixU(), MatrixType::Identity(size, size)); // Test computation of only T, not U @@ -91,7 +91,7 @@ template void schur(int size = MatrixType::ColsAtCompileTim VERIFY_IS_EQUAL(rs1.matrixT(), rsOnlyT.matrixT()); VERIFY_RAISES_ASSERT(rsOnlyT.matrixU()); - if (size > 2) + if (size > 2 && size < 20) { // Test matrix with NaN A(0,0) = std::numeric_limits::quiet_NaN(); diff --git a/ground/gcs/src/libs/eigen/test/selfadjoint.cpp b/ground/gcs/src/libs/eigen/test/selfadjoint.cpp index 76dab6d64a..92401e5065 100644 --- a/ground/gcs/src/libs/eigen/test/selfadjoint.cpp +++ b/ground/gcs/src/libs/eigen/test/selfadjoint.cpp @@ -21,7 +21,9 @@ template void selfadjoint(const MatrixType& m) Index cols = m.cols(); MatrixType m1 = MatrixType::Random(rows, cols), - m3(rows, cols); + m2 = MatrixType::Random(rows, cols), + m3(rows, cols), + m4(rows, cols); m1.diagonal() = m1.diagonal().real().template cast(); @@ -30,10 +32,19 @@ template void selfadjoint(const MatrixType& m) VERIFY_IS_APPROX(MatrixType(m3.template triangularView()), MatrixType(m1.template triangularView())); VERIFY_IS_APPROX(m3, m3.adjoint()); - m3 = m1.template selfadjointView(); VERIFY_IS_APPROX(MatrixType(m3.template triangularView()), MatrixType(m1.template triangularView())); VERIFY_IS_APPROX(m3, m3.adjoint()); + + m3 = m1.template selfadjointView(); + m4 = m2; + m4 += m1.template selfadjointView(); + VERIFY_IS_APPROX(m4, m2+m3); + + m3 = m1.template selfadjointView(); + m4 = m2; + m4 -= m1.template selfadjointView(); + VERIFY_IS_APPROX(m4, m2-m3); } void bug_159() diff --git a/ground/gcs/src/libs/eigen/test/simplicial_cholesky.cpp b/ground/gcs/src/libs/eigen/test/simplicial_cholesky.cpp index 7864684210..649c817b4b 100644 --- a/ground/gcs/src/libs/eigen/test/simplicial_cholesky.cpp +++ b/ground/gcs/src/libs/eigen/test/simplicial_cholesky.cpp @@ -9,16 +9,17 @@ #include "sparse_solver.h" -template void test_simplicial_cholesky_T() +template void test_simplicial_cholesky_T() { - SimplicialCholesky, Lower> chol_colmajor_lower_amd; - SimplicialCholesky, Upper> chol_colmajor_upper_amd; - SimplicialLLT, Lower> llt_colmajor_lower_amd; - SimplicialLLT, Upper> llt_colmajor_upper_amd; - SimplicialLDLT, Lower> ldlt_colmajor_lower_amd; - SimplicialLDLT, Upper> ldlt_colmajor_upper_amd; - SimplicialLDLT, Lower, NaturalOrdering > ldlt_colmajor_lower_nat; - SimplicialLDLT, Upper, NaturalOrdering > ldlt_colmajor_upper_nat; + typedef SparseMatrix SparseMatrixType; + SimplicialCholesky chol_colmajor_lower_amd; + SimplicialCholesky chol_colmajor_upper_amd; + SimplicialLLT< SparseMatrixType, Lower> llt_colmajor_lower_amd; + SimplicialLLT< SparseMatrixType, Upper> llt_colmajor_upper_amd; + SimplicialLDLT< SparseMatrixType, Lower> ldlt_colmajor_lower_amd; + SimplicialLDLT< SparseMatrixType, Upper> ldlt_colmajor_upper_amd; + SimplicialLDLT< SparseMatrixType, Lower, NaturalOrdering > ldlt_colmajor_lower_nat; + SimplicialLDLT< SparseMatrixType, Upper, NaturalOrdering > ldlt_colmajor_upper_nat; check_sparse_spd_solving(chol_colmajor_lower_amd); check_sparse_spd_solving(chol_colmajor_upper_amd); @@ -34,12 +35,13 @@ template void test_simplicial_cholesky_T() check_sparse_spd_determinant(ldlt_colmajor_lower_amd); check_sparse_spd_determinant(ldlt_colmajor_upper_amd); - check_sparse_spd_solving(ldlt_colmajor_lower_nat); - check_sparse_spd_solving(ldlt_colmajor_upper_nat); + check_sparse_spd_solving(ldlt_colmajor_lower_nat, 300, 1000); + check_sparse_spd_solving(ldlt_colmajor_upper_nat, 300, 1000); } void test_simplicial_cholesky() { - CALL_SUBTEST_1(test_simplicial_cholesky_T()); - CALL_SUBTEST_2(test_simplicial_cholesky_T >()); + CALL_SUBTEST_1(( test_simplicial_cholesky_T() )); + CALL_SUBTEST_2(( test_simplicial_cholesky_T, int>() )); + CALL_SUBTEST_3(( test_simplicial_cholesky_T() )); } diff --git a/ground/gcs/src/libs/eigen/test/sizeof.cpp b/ground/gcs/src/libs/eigen/test/sizeof.cpp index d9ad356205..03ad204538 100644 --- a/ground/gcs/src/libs/eigen/test/sizeof.cpp +++ b/ground/gcs/src/libs/eigen/test/sizeof.cpp @@ -13,14 +13,27 @@ template void verifySizeOf(const MatrixType&) { typedef typename MatrixType::Scalar Scalar; if (MatrixType::RowsAtCompileTime!=Dynamic && MatrixType::ColsAtCompileTime!=Dynamic) - VERIFY(std::ptrdiff_t(sizeof(MatrixType))==std::ptrdiff_t(sizeof(Scalar))*std::ptrdiff_t(MatrixType::SizeAtCompileTime)); + VERIFY_IS_EQUAL(std::ptrdiff_t(sizeof(MatrixType)),std::ptrdiff_t(sizeof(Scalar))*std::ptrdiff_t(MatrixType::SizeAtCompileTime)); else - VERIFY(sizeof(MatrixType)==sizeof(Scalar*) + 2 * sizeof(typename MatrixType::Index)); + VERIFY_IS_EQUAL(sizeof(MatrixType),sizeof(Scalar*) + 2 * sizeof(typename MatrixType::Index)); } void test_sizeof() { CALL_SUBTEST(verifySizeOf(Matrix()) ); + CALL_SUBTEST(verifySizeOf(Array()) ); + CALL_SUBTEST(verifySizeOf(Array()) ); + CALL_SUBTEST(verifySizeOf(Array()) ); + CALL_SUBTEST(verifySizeOf(Array()) ); + CALL_SUBTEST(verifySizeOf(Array()) ); + CALL_SUBTEST(verifySizeOf(Array()) ); + CALL_SUBTEST(verifySizeOf(Array()) ); + CALL_SUBTEST(verifySizeOf(Array()) ); + CALL_SUBTEST(verifySizeOf(Array()) ); + CALL_SUBTEST(verifySizeOf(Array()) ); + CALL_SUBTEST(verifySizeOf(Array()) ); + CALL_SUBTEST(verifySizeOf(Vector2d()) ); + CALL_SUBTEST(verifySizeOf(Vector4f()) ); CALL_SUBTEST(verifySizeOf(Matrix4d()) ); CALL_SUBTEST(verifySizeOf(Matrix()) ); CALL_SUBTEST(verifySizeOf(Matrix()) ); diff --git a/ground/gcs/src/libs/eigen/test/sizeoverflow.cpp b/ground/gcs/src/libs/eigen/test/sizeoverflow.cpp index 16d6f8d040..240d22294c 100644 --- a/ground/gcs/src/libs/eigen/test/sizeoverflow.cpp +++ b/ground/gcs/src/libs/eigen/test/sizeoverflow.cpp @@ -18,8 +18,6 @@ VERIFY(threw && "should have thrown bad_alloc: " #a); \ } -typedef DenseIndex Index; - template void triggerMatrixBadAlloc(Index rows, Index cols) { diff --git a/ground/gcs/src/libs/eigen/test/sparse.h b/ground/gcs/src/libs/eigen/test/sparse.h index e19a76316e..9912e1e246 100644 --- a/ground/gcs/src/libs/eigen/test/sparse.h +++ b/ground/gcs/src/libs/eigen/test/sparse.h @@ -53,15 +53,15 @@ enum { * \param zeroCoords and nonzeroCoords allows to get the coordinate lists of the non zero, * and zero coefficients respectively. */ -template void +template void initSparse(double density, Matrix& refMat, - SparseMatrix& sparseMat, + SparseMatrix& sparseMat, int flags = 0, - std::vector >* zeroCoords = 0, - std::vector >* nonzeroCoords = 0) + std::vector >* zeroCoords = 0, + std::vector >* nonzeroCoords = 0) { - enum { IsRowMajor = SparseMatrix::IsRowMajor }; + enum { IsRowMajor = SparseMatrix::IsRowMajor }; sparseMat.setZero(); //sparseMat.reserve(int(refMat.rows()*refMat.cols()*density)); sparseMat.reserve(VectorXi::Constant(IsRowMajor ? refMat.rows() : refMat.cols(), int((1.5*density)*(IsRowMajor?refMat.cols():refMat.rows())))); @@ -71,14 +71,17 @@ initSparse(double density, //sparseMat.startVec(j); for(Index i=0; i(0,1) < density) ? internal::random() : Scalar(0); if ((flags&ForceNonZeroDiag) && (i==j)) { + // FIXME: the following is too conservative v = internal::random()*Scalar(3.); - v = v*v + Scalar(5.); + v = v*v; + if(numext::real(v)>0) v += Scalar(5); + else v -= Scalar(5); } if ((flags & MakeLowerTriangular) && aj>ai) v = Scalar(0); @@ -93,11 +96,11 @@ initSparse(double density, //sparseMat.insertBackByOuterInner(j,i) = v; sparseMat.insertByOuterInner(j,i) = v; if (nonzeroCoords) - nonzeroCoords->push_back(Matrix (ai,aj)); + nonzeroCoords->push_back(Matrix (ai,aj)); } else if (zeroCoords) { - zeroCoords->push_back(Matrix (ai,aj)); + zeroCoords->push_back(Matrix (ai,aj)); } refMat(ai,aj) = v; } @@ -163,7 +166,7 @@ initSparse(double density, { sparseVec.reserve(int(refVec.size()*density)); sparseVec.setZero(); - for(Index i=0; i(0,1) < density) ? internal::random() : Scalar(0); if (v!=Scalar(0)) diff --git a/ground/gcs/src/libs/eigen/test/sparse_basic.cpp b/ground/gcs/src/libs/eigen/test/sparse_basic.cpp index abe6a9d143..384985028f 100644 --- a/ground/gcs/src/libs/eigen/test/sparse_basic.cpp +++ b/ground/gcs/src/libs/eigen/test/sparse_basic.cpp @@ -9,22 +9,28 @@ // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. +static long g_realloc_count = 0; +#define EIGEN_SPARSE_COMPRESSED_STORAGE_REALLOCATE_PLUGIN g_realloc_count++; + #include "sparse.h" template void sparse_basic(const SparseMatrixType& ref) { - typedef typename SparseMatrixType::Index Index; - typedef Matrix Vector2; + typedef typename SparseMatrixType::StorageIndex StorageIndex; + typedef Matrix Vector2; const Index rows = ref.rows(); const Index cols = ref.cols(); + //const Index inner = ref.innerSize(); + //const Index outer = ref.outerSize(); + typedef typename SparseMatrixType::Scalar Scalar; + typedef typename SparseMatrixType::RealScalar RealScalar; enum { Flags = SparseMatrixType::Flags }; double density = (std::max)(8./(rows*cols), 0.01); typedef Matrix DenseMatrix; typedef Matrix DenseVector; - typedef Matrix RowDenseVector; Scalar eps = 1e-6; Scalar s1 = internal::random(); @@ -37,94 +43,22 @@ template void sparse_basic(const SparseMatrixType& re std::vector nonzeroCoords; initSparse(density, refMat, m, 0, &zeroCoords, &nonzeroCoords); - if (zeroCoords.size()==0 || nonzeroCoords.size()==0) - return; - // test coeff and coeffRef - for (int i=0; i<(int)zeroCoords.size(); ++i) + for (std::size_t i=0; i >::value) - VERIFY_RAISES_ASSERT( m.coeffRef(zeroCoords[0].x(),zeroCoords[0].y()) = 5 ); + VERIFY_RAISES_ASSERT( m.coeffRef(zeroCoords[i].x(),zeroCoords[i].y()) = 5 ); } VERIFY_IS_APPROX(m, refMat); - m.coeffRef(nonzeroCoords[0].x(), nonzeroCoords[0].y()) = Scalar(5); - refMat.coeffRef(nonzeroCoords[0].x(), nonzeroCoords[0].y()) = Scalar(5); + if(!nonzeroCoords.empty()) { + m.coeffRef(nonzeroCoords[0].x(), nonzeroCoords[0].y()) = Scalar(5); + refMat.coeffRef(nonzeroCoords[0].x(), nonzeroCoords[0].y()) = Scalar(5); + } VERIFY_IS_APPROX(m, refMat); - - // test InnerIterators and Block expressions - for (int t=0; t<10; ++t) - { - int j = internal::random(0,cols-1); - int i = internal::random(0,rows-1); - int w = internal::random(1,cols-j-1); - int h = internal::random(1,rows-i-1); - VERIFY_IS_APPROX(m.block(i,j,h,w), refMat.block(i,j,h,w)); - for(int c=0; c void sparse_basic(const SparseMatrixType& re DenseMatrix m1(rows,cols); m1.setZero(); SparseMatrixType m2(rows,cols); - if(internal::random()%2) - m2.reserve(VectorXi::Constant(m2.outerSize(), 2)); + bool call_reserve = internal::random()%2; + Index nnz = internal::random(1,int(rows)/2); + if(call_reserve) + { + if(internal::random()%2) + m2.reserve(VectorXi::Constant(m2.outerSize(), int(nnz))); + else + m2.reserve(m2.outerSize() * nnz); + } + g_realloc_count = 0; for (Index j=0; j(0,rows-1); if (m1.coeff(i,j)==Scalar(0)) m2.insert(i,j) = m1(i,j) = internal::random(); } } + + if(call_reserve && !SparseMatrixType::IsRowMajor) + { + VERIFY(g_realloc_count==0); + } + m2.finalize(); VERIFY_IS_APPROX(m2,m1); } @@ -179,9 +127,9 @@ template void sparse_basic(const SparseMatrixType& re DenseMatrix m1(rows,cols); m1.setZero(); SparseMatrixType m2(rows,cols); - VectorXi r(VectorXi::Constant(m2.outerSize(), ((mode%2)==0) ? m2.innerSize() : std::max(1,m2.innerSize()/8))); + VectorXi r(VectorXi::Constant(m2.outerSize(), ((mode%2)==0) ? int(m2.innerSize()) : std::max(1,int(m2.innerSize())/8))); m2.reserve(r); - for (int k=0; k(0,rows-1); Index j = internal::random(0,cols-1); @@ -195,110 +143,46 @@ template void sparse_basic(const SparseMatrixType& re VERIFY_IS_APPROX(m2,m1); } - // test innerVector() - { - DenseMatrix refMat2 = DenseMatrix::Zero(rows, rows); - SparseMatrixType m2(rows, rows); - initSparse(density, refMat2, m2); - Index j0 = internal::random(0,rows-1); - Index j1 = internal::random(0,rows-1); - if(SparseMatrixType::IsRowMajor) - VERIFY_IS_APPROX(m2.innerVector(j0), refMat2.row(j0)); - else - VERIFY_IS_APPROX(m2.innerVector(j0), refMat2.col(j0)); - - if(SparseMatrixType::IsRowMajor) - VERIFY_IS_APPROX(m2.innerVector(j0)+m2.innerVector(j1), refMat2.row(j0)+refMat2.row(j1)); - else - VERIFY_IS_APPROX(m2.innerVector(j0)+m2.innerVector(j1), refMat2.col(j0)+refMat2.col(j1)); - - SparseMatrixType m3(rows,rows); - m3.reserve(VectorXi::Constant(rows,rows/2)); - for(Index j=0; j0) - VERIFY(j==numext::real(m3.innerVector(j).lastCoeff())); - } - m3.makeCompressed(); - for(Index j=0; j0) - VERIFY(j==numext::real(m3.innerVector(j).lastCoeff())); - } - - //m2.innerVector(j0) = 2*m2.innerVector(j1); - //refMat2.col(j0) = 2*refMat2.col(j1); - //VERIFY_IS_APPROX(m2, refMat2); - } - - // test innerVectors() - { - DenseMatrix refMat2 = DenseMatrix::Zero(rows, rows); - SparseMatrixType m2(rows, rows); - initSparse(density, refMat2, m2); - if(internal::random(0,1)>0.5) m2.makeCompressed(); - - Index j0 = internal::random(0,rows-2); - Index j1 = internal::random(0,rows-2); - Index n0 = internal::random(1,rows-(std::max)(j0,j1)); - if(SparseMatrixType::IsRowMajor) - VERIFY_IS_APPROX(m2.innerVectors(j0,n0), refMat2.block(j0,0,n0,cols)); - else - VERIFY_IS_APPROX(m2.innerVectors(j0,n0), refMat2.block(0,j0,rows,n0)); - if(SparseMatrixType::IsRowMajor) - VERIFY_IS_APPROX(m2.innerVectors(j0,n0)+m2.innerVectors(j1,n0), - refMat2.middleRows(j0,n0)+refMat2.middleRows(j1,n0)); - else - VERIFY_IS_APPROX(m2.innerVectors(j0,n0)+m2.innerVectors(j1,n0), - refMat2.block(0,j0,rows,n0)+refMat2.block(0,j1,rows,n0)); - - VERIFY_IS_APPROX(m2, refMat2); - - m2.innerVectors(j0,n0) = m2.innerVectors(j0,n0) + m2.innerVectors(j1,n0); - if(SparseMatrixType::IsRowMajor) - refMat2.middleRows(j0,n0) = (refMat2.middleRows(j0,n0) + refMat2.middleRows(j1,n0)).eval(); - else - refMat2.middleCols(j0,n0) = (refMat2.middleCols(j0,n0) + refMat2.middleCols(j1,n0)).eval(); - - VERIFY_IS_APPROX(m2, refMat2); - - } - // test basic computations { - DenseMatrix refM1 = DenseMatrix::Zero(rows, rows); - DenseMatrix refM2 = DenseMatrix::Zero(rows, rows); - DenseMatrix refM3 = DenseMatrix::Zero(rows, rows); - DenseMatrix refM4 = DenseMatrix::Zero(rows, rows); - SparseMatrixType m1(rows, rows); - SparseMatrixType m2(rows, rows); - SparseMatrixType m3(rows, rows); - SparseMatrixType m4(rows, rows); + DenseMatrix refM1 = DenseMatrix::Zero(rows, cols); + DenseMatrix refM2 = DenseMatrix::Zero(rows, cols); + DenseMatrix refM3 = DenseMatrix::Zero(rows, cols); + DenseMatrix refM4 = DenseMatrix::Zero(rows, cols); + SparseMatrixType m1(rows, cols); + SparseMatrixType m2(rows, cols); + SparseMatrixType m3(rows, cols); + SparseMatrixType m4(rows, cols); initSparse(density, refM1, m1); initSparse(density, refM2, m2); initSparse(density, refM3, m3); initSparse(density, refM4, m4); + if(internal::random()) + m1.makeCompressed(); + + Index m1_nnz = m1.nonZeros(); + + VERIFY_IS_APPROX(m1*s1, refM1*s1); VERIFY_IS_APPROX(m1+m2, refM1+refM2); VERIFY_IS_APPROX(m1+m2+m3, refM1+refM2+refM3); VERIFY_IS_APPROX(m3.cwiseProduct(m1+m2), refM3.cwiseProduct(refM1+refM2)); VERIFY_IS_APPROX(m1*s1-m2, refM1*s1-refM2); - - VERIFY_IS_APPROX(m1*=s1, refM1*=s1); - VERIFY_IS_APPROX(m1/=s1, refM1/=s1); - - VERIFY_IS_APPROX(m1+=m2, refM1+=refM2); - VERIFY_IS_APPROX(m1-=m2, refM1-=refM2); + VERIFY_IS_APPROX(m4=m1/s1, refM1/s1); + VERIFY_IS_EQUAL(m4.nonZeros(), m1_nnz); if(SparseMatrixType::IsRowMajor) VERIFY_IS_APPROX(m1.innerVector(0).dot(refM2.row(0)), refM1.row(0).dot(refM2.row(0))); else - VERIFY_IS_APPROX(m1.innerVector(0).dot(refM2.row(0)), refM1.col(0).dot(refM2.row(0))); + VERIFY_IS_APPROX(m1.innerVector(0).dot(refM2.col(0)), refM1.col(0).dot(refM2.col(0))); + + DenseVector rv = DenseVector::Random(m1.cols()); + DenseVector cv = DenseVector::Random(m1.rows()); + Index r = internal::random(0,m1.rows()-2); + Index c = internal::random(0,m1.cols()-1); + VERIFY_IS_APPROX(( m1.template block<1,Dynamic>(r,0,1,m1.cols()).dot(rv)) , refM1.row(r).dot(rv)); + VERIFY_IS_APPROX(m1.row(r).dot(rv), refM1.row(r).dot(rv)); + VERIFY_IS_APPROX(m1.col(c).dot(cv), refM1.col(c).dot(cv)); VERIFY_IS_APPROX(m1.conjugate(), refM1.conjugate()); VERIFY_IS_APPROX(m1.real(), refM1.real()); @@ -310,103 +194,163 @@ template void sparse_basic(const SparseMatrixType& re VERIFY_IS_APPROX(refM4.cwiseProduct(m3), refM4.cwiseProduct(refM3)); // VERIFY_IS_APPROX(m3.cwise()/refM4, refM3.cwise()/refM4); + VERIFY_IS_APPROX(refM4 + m3, refM4 + refM3); + VERIFY_IS_APPROX(m3 + refM4, refM3 + refM4); + VERIFY_IS_APPROX(refM4 - m3, refM4 - refM3); + VERIFY_IS_APPROX(m3 - refM4, refM3 - refM4); + VERIFY_IS_APPROX((RealScalar(0.5)*refM4 + RealScalar(0.5)*m3).eval(), RealScalar(0.5)*refM4 + RealScalar(0.5)*refM3); + VERIFY_IS_APPROX((RealScalar(0.5)*refM4 + m3*RealScalar(0.5)).eval(), RealScalar(0.5)*refM4 + RealScalar(0.5)*refM3); + VERIFY_IS_APPROX((RealScalar(0.5)*refM4 + m3.cwiseProduct(m3)).eval(), RealScalar(0.5)*refM4 + refM3.cwiseProduct(refM3)); + + VERIFY_IS_APPROX((RealScalar(0.5)*refM4 + RealScalar(0.5)*m3).eval(), RealScalar(0.5)*refM4 + RealScalar(0.5)*refM3); + VERIFY_IS_APPROX((RealScalar(0.5)*refM4 + m3*RealScalar(0.5)).eval(), RealScalar(0.5)*refM4 + RealScalar(0.5)*refM3); + VERIFY_IS_APPROX((RealScalar(0.5)*refM4 + (m3+m3)).eval(), RealScalar(0.5)*refM4 + (refM3+refM3)); + VERIFY_IS_APPROX(((refM3+m3)+RealScalar(0.5)*m3).eval(), RealScalar(0.5)*refM3 + (refM3+refM3)); + VERIFY_IS_APPROX((RealScalar(0.5)*refM4 + (refM3+m3)).eval(), RealScalar(0.5)*refM4 + (refM3+refM3)); + VERIFY_IS_APPROX((RealScalar(0.5)*refM4 + (m3+refM3)).eval(), RealScalar(0.5)*refM4 + (refM3+refM3)); + + + VERIFY_IS_APPROX(m1.sum(), refM1.sum()); + + m4 = m1; refM4 = m4; + + VERIFY_IS_APPROX(m1*=s1, refM1*=s1); + VERIFY_IS_EQUAL(m1.nonZeros(), m1_nnz); + VERIFY_IS_APPROX(m1/=s1, refM1/=s1); + VERIFY_IS_EQUAL(m1.nonZeros(), m1_nnz); + + VERIFY_IS_APPROX(m1+=m2, refM1+=refM2); + VERIFY_IS_APPROX(m1-=m2, refM1-=refM2); + + if (rows>=2 && cols>=2) + { + VERIFY_RAISES_ASSERT( m1 += m1.innerVector(0) ); + VERIFY_RAISES_ASSERT( m1 -= m1.innerVector(0) ); + VERIFY_RAISES_ASSERT( refM1 -= m1.innerVector(0) ); + VERIFY_RAISES_ASSERT( refM1 += m1.innerVector(0) ); + m1 = m4; refM1 = refM4; + } + // test aliasing VERIFY_IS_APPROX((m1 = -m1), (refM1 = -refM1)); + VERIFY_IS_EQUAL(m1.nonZeros(), m1_nnz); + m1 = m4; refM1 = refM4; VERIFY_IS_APPROX((m1 = m1.transpose()), (refM1 = refM1.transpose().eval())); + VERIFY_IS_EQUAL(m1.nonZeros(), m1_nnz); + m1 = m4; refM1 = refM4; VERIFY_IS_APPROX((m1 = -m1.transpose()), (refM1 = -refM1.transpose().eval())); + VERIFY_IS_EQUAL(m1.nonZeros(), m1_nnz); + m1 = m4; refM1 = refM4; VERIFY_IS_APPROX((m1 += -m1), (refM1 += -refM1)); + VERIFY_IS_EQUAL(m1.nonZeros(), m1_nnz); + m1 = m4; refM1 = refM4; + + if(m1.isCompressed()) + { + VERIFY_IS_APPROX(m1.coeffs().sum(), m1.sum()); + m1.coeffs() += s1; + for(Index j = 0; j SpBool; + SpBool mb1 = m1.real().template cast(); + SpBool mb2 = m2.real().template cast(); + VERIFY_IS_EQUAL(mb1.template cast().sum(), refM1.real().template cast().count()); + VERIFY_IS_EQUAL((mb1 && mb2).template cast().sum(), (refM1.real().template cast() && refM2.real().template cast()).count()); + VERIFY_IS_EQUAL((mb1 || mb2).template cast().sum(), (refM1.real().template cast() || refM2.real().template cast()).count()); + SpBool mb3 = mb1 && mb2; + if(mb1.coeffs().all() && mb2.coeffs().all()) + { + VERIFY_IS_EQUAL(mb3.nonZeros(), (refM1.real().template cast() && refM2.real().template cast()).count()); + } + } } - // test transpose + // test reverse iterators { - DenseMatrix refMat2 = DenseMatrix::Zero(rows, rows); - SparseMatrixType m2(rows, rows); + DenseMatrix refMat2 = DenseMatrix::Zero(rows, cols); + SparseMatrixType m2(rows, cols); initSparse(density, refMat2, m2); - VERIFY_IS_APPROX(m2.transpose().eval(), refMat2.transpose().eval()); - VERIFY_IS_APPROX(m2.transpose(), refMat2.transpose()); + std::vector ref_value(m2.innerSize()); + std::vector ref_index(m2.innerSize()); + if(internal::random()) + m2.makeCompressed(); + for(Index j = 0; j(density, refMat2, m2); - Index j0 = internal::random(0,rows-2); - Index j1 = internal::random(0,rows-2); - Index n0 = internal::random(1,rows-(std::max)(j0,j1)); - if(SparseMatrixType::IsRowMajor) - VERIFY_IS_APPROX(m2.block(j0,0,n0,cols), refMat2.block(j0,0,n0,cols)); - else - VERIFY_IS_APPROX(m2.block(0,j0,rows,n0), refMat2.block(0,j0,rows,n0)); - - if(SparseMatrixType::IsRowMajor) - VERIFY_IS_APPROX(m2.block(j0,0,n0,cols)+m2.block(j1,0,n0,cols), - refMat2.block(j0,0,n0,cols)+refMat2.block(j1,0,n0,cols)); - else - VERIFY_IS_APPROX(m2.block(0,j0,rows,n0)+m2.block(0,j1,rows,n0), - refMat2.block(0,j0,rows,n0)+refMat2.block(0,j1,rows,n0)); - - Index i = internal::random(0,m2.outerSize()-1); - if(SparseMatrixType::IsRowMajor) { - m2.innerVector(i) = m2.innerVector(i) * s1; - refMat2.row(i) = refMat2.row(i) * s1; - VERIFY_IS_APPROX(m2,refMat2); - } else { - m2.innerVector(i) = m2.innerVector(i) * s1; - refMat2.col(i) = refMat2.col(i) * s1; - VERIFY_IS_APPROX(m2,refMat2); - } - - VERIFY_IS_APPROX(DenseVector(m2.col(j0)), refMat2.col(j0)); - VERIFY_IS_APPROX(m2.col(j0), refMat2.col(j0)); - - VERIFY_IS_APPROX(RowDenseVector(m2.row(j0)), refMat2.row(j0)); - VERIFY_IS_APPROX(m2.row(j0), refMat2.row(j0)); + VERIFY_IS_APPROX(m2.transpose().eval(), refMat2.transpose().eval()); + VERIFY_IS_APPROX(m2.transpose(), refMat2.transpose()); + + VERIFY_IS_APPROX(SparseMatrixType(m2.adjoint()), refMat2.adjoint()); - VERIFY_IS_APPROX(m2.block(j0,j1,n0,n0), refMat2.block(j0,j1,n0,n0)); - VERIFY_IS_APPROX((2*m2).block(j0,j1,n0,n0), (2*refMat2).block(j0,j1,n0,n0)); + // check isApprox handles opposite storage order + typename Transpose::PlainObject m3(m2); + VERIFY(m2.isApprox(m3)); } // test prune { - SparseMatrixType m2(rows, rows); - DenseMatrix refM2(rows, rows); + SparseMatrixType m2(rows, cols); + DenseMatrix refM2(rows, cols); refM2.setZero(); int countFalseNonZero = 0; int countTrueNonZero = 0; - for (Index j=0; j(0,1); - if (x<0.1) + if (x<0.1f) { // do nothing } - else if (x<0.5) + else if (x<0.5f) { countFalseNonZero++; - m2.insertBackByOuterInner(j,i) = Scalar(0); + m2.insert(i,j) = Scalar(0); } else { countTrueNonZero++; - m2.insertBackByOuterInner(j,i) = Scalar(1); - if(SparseMatrixType::IsRowMajor) - refM2(j,i) = Scalar(1); - else - refM2(i,j) = Scalar(1); + m2.insert(i,j) = Scalar(1); + refM2(i,j) = Scalar(1); } } } - m2.finalize(); + if(internal::random()) + m2.makeCompressed(); VERIFY(countFalseNonZero+countTrueNonZero == m2.nonZeros()); - VERIFY_IS_APPROX(m2, refM2); + if(countTrueNonZero>0) + VERIFY_IS_APPROX(m2, refM2); m2.prune(Scalar(1)); VERIFY(countTrueNonZero==m2.nonZeros()); VERIFY_IS_APPROX(m2, refM2); @@ -414,29 +358,74 @@ template void sparse_basic(const SparseMatrixType& re // test setFromTriplets { - typedef Triplet TripletType; + typedef Triplet TripletType; std::vector triplets; - int ntriplets = rows*cols; + Index ntriplets = rows*cols; triplets.reserve(ntriplets); - DenseMatrix refMat(rows,cols); - refMat.setZero(); - for(int i=0;i(0,rows-1); - Index c = internal::random(0,cols-1); + StorageIndex r = internal::random(0,StorageIndex(rows-1)); + StorageIndex c = internal::random(0,StorageIndex(cols-1)); Scalar v = internal::random(); triplets.push_back(TripletType(r,c,v)); - refMat(r,c) += v; + refMat_sum(r,c) += v; + if(std::abs(refMat_prod(r,c))==0) + refMat_prod(r,c) = v; + else + refMat_prod(r,c) *= v; + refMat_last(r,c) = v; } SparseMatrixType m(rows,cols); m.setFromTriplets(triplets.begin(), triplets.end()); - VERIFY_IS_APPROX(m, refMat); + VERIFY_IS_APPROX(m, refMat_sum); + + m.setFromTriplets(triplets.begin(), triplets.end(), std::multiplies()); + VERIFY_IS_APPROX(m, refMat_prod); +#if (defined(__cplusplus) && __cplusplus >= 201103L) + m.setFromTriplets(triplets.begin(), triplets.end(), [] (Scalar,Scalar b) { return b; }); + VERIFY_IS_APPROX(m, refMat_last); +#endif + } + + // test Map + { + DenseMatrix refMat2(rows, cols), refMat3(rows, cols); + SparseMatrixType m2(rows, cols), m3(rows, cols); + initSparse(density, refMat2, m2); + initSparse(density, refMat3, m3); + { + Map mapMat2(m2.rows(), m2.cols(), m2.nonZeros(), m2.outerIndexPtr(), m2.innerIndexPtr(), m2.valuePtr(), m2.innerNonZeroPtr()); + Map mapMat3(m3.rows(), m3.cols(), m3.nonZeros(), m3.outerIndexPtr(), m3.innerIndexPtr(), m3.valuePtr(), m3.innerNonZeroPtr()); + VERIFY_IS_APPROX(mapMat2+mapMat3, refMat2+refMat3); + VERIFY_IS_APPROX(mapMat2+mapMat3, refMat2+refMat3); + } + { + MappedSparseMatrix mapMat2(m2.rows(), m2.cols(), m2.nonZeros(), m2.outerIndexPtr(), m2.innerIndexPtr(), m2.valuePtr(), m2.innerNonZeroPtr()); + MappedSparseMatrix mapMat3(m3.rows(), m3.cols(), m3.nonZeros(), m3.outerIndexPtr(), m3.innerIndexPtr(), m3.valuePtr(), m3.innerNonZeroPtr()); + VERIFY_IS_APPROX(mapMat2+mapMat3, refMat2+refMat3); + VERIFY_IS_APPROX(mapMat2+mapMat3, refMat2+refMat3); + } + + Index i = internal::random(0,rows-1); + Index j = internal::random(0,cols-1); + m2.coeffRef(i,j) = 123; + if(internal::random()) + m2.makeCompressed(); + Map mapMat2(rows, cols, m2.nonZeros(), m2.outerIndexPtr(), m2.innerIndexPtr(), m2.valuePtr(), m2.innerNonZeroPtr()); + VERIFY_IS_EQUAL(m2.coeff(i,j),Scalar(123)); + VERIFY_IS_EQUAL(mapMat2.coeff(i,j),Scalar(123)); + mapMat2.coeffRef(i,j) = -123; + VERIFY_IS_EQUAL(m2.coeff(i,j),Scalar(-123)); } // test triangularView { - DenseMatrix refMat2(rows, rows), refMat3(rows, rows); - SparseMatrixType m2(rows, rows), m3(rows, rows); + DenseMatrix refMat2(rows, cols), refMat3(rows, cols); + SparseMatrixType m2(rows, cols), m3(rows, cols); initSparse(density, refMat2, m2); refMat3 = refMat2.template triangularView(); m3 = m2.template triangularView(); @@ -446,13 +435,15 @@ template void sparse_basic(const SparseMatrixType& re m3 = m2.template triangularView(); VERIFY_IS_APPROX(m3, refMat3); - refMat3 = refMat2.template triangularView(); - m3 = m2.template triangularView(); - VERIFY_IS_APPROX(m3, refMat3); + { + refMat3 = refMat2.template triangularView(); + m3 = m2.template triangularView(); + VERIFY_IS_APPROX(m3, refMat3); - refMat3 = refMat2.template triangularView(); - m3 = m2.template triangularView(); - VERIFY_IS_APPROX(m3, refMat3); + refMat3 = refMat2.template triangularView(); + m3 = m2.template triangularView(); + VERIFY_IS_APPROX(m3, refMat3); + } refMat3 = refMat2.template triangularView(); m3 = m2.template triangularView(); @@ -461,6 +452,10 @@ template void sparse_basic(const SparseMatrixType& re refMat3 = refMat2.template triangularView(); m3 = m2.template triangularView(); VERIFY_IS_APPROX(m3, refMat3); + + // check sparse-triangular to dense + refMat3 = m2.template triangularView(); + VERIFY_IS_APPROX(refMat3, DenseMatrix(refMat2.template triangularView())); } // test selfadjointView @@ -472,6 +467,19 @@ template void sparse_basic(const SparseMatrixType& re refMat3 = refMat2.template selfadjointView(); m3 = m2.template selfadjointView(); VERIFY_IS_APPROX(m3, refMat3); + + refMat3 += refMat2.template selfadjointView(); + m3 += m2.template selfadjointView(); + VERIFY_IS_APPROX(m3, refMat3); + + refMat3 -= refMat2.template selfadjointView(); + m3 -= m2.template selfadjointView(); + VERIFY_IS_APPROX(m3, refMat3); + + // selfadjointView only works for square matrices: + SparseMatrixType m4(rows, rows+1); + VERIFY_RAISES_ASSERT(m4.template selfadjointView()); + VERIFY_RAISES_ASSERT(m4.template selfadjointView()); } // test sparseView @@ -480,28 +488,59 @@ template void sparse_basic(const SparseMatrixType& re SparseMatrixType m2(rows, rows); initSparse(density, refMat2, m2); VERIFY_IS_APPROX(m2.eval(), refMat2.sparseView().eval()); + + // sparse view on expressions: + VERIFY_IS_APPROX((s1*m2).eval(), (s1*refMat2).sparseView().eval()); + VERIFY_IS_APPROX((m2+m2).eval(), (refMat2+refMat2).sparseView().eval()); + VERIFY_IS_APPROX((m2*m2).eval(), (refMat2.lazyProduct(refMat2)).sparseView().eval()); + VERIFY_IS_APPROX((m2*m2).eval(), (refMat2*refMat2).sparseView().eval()); } // test diagonal { - DenseMatrix refMat2 = DenseMatrix::Zero(rows, rows); - SparseMatrixType m2(rows, rows); + DenseMatrix refMat2 = DenseMatrix::Zero(rows, cols); + SparseMatrixType m2(rows, cols); initSparse(density, refMat2, m2); VERIFY_IS_APPROX(m2.diagonal(), refMat2.diagonal().eval()); + DenseVector d = m2.diagonal(); + VERIFY_IS_APPROX(d, refMat2.diagonal().eval()); + d = m2.diagonal().array(); + VERIFY_IS_APPROX(d, refMat2.diagonal().eval()); + VERIFY_IS_APPROX(const_cast(m2).diagonal(), refMat2.diagonal().eval()); + + initSparse(density, refMat2, m2, ForceNonZeroDiag); + m2.diagonal() += refMat2.diagonal(); + refMat2.diagonal() += refMat2.diagonal(); + VERIFY_IS_APPROX(m2, refMat2); + } + + // test diagonal to sparse + { + DenseVector d = DenseVector::Random(rows); + DenseMatrix refMat2 = d.asDiagonal(); + SparseMatrixType m2(rows, rows); + m2 = d.asDiagonal(); + VERIFY_IS_APPROX(m2, refMat2); + SparseMatrixType m3(d.asDiagonal()); + VERIFY_IS_APPROX(m3, refMat2); + refMat2 += d.asDiagonal(); + m2 += d.asDiagonal(); + VERIFY_IS_APPROX(m2, refMat2); } // test conservative resize { - std::vector< std::pair > inc; - inc.push_back(std::pair(-3,-2)); - inc.push_back(std::pair(0,0)); - inc.push_back(std::pair(3,2)); - inc.push_back(std::pair(3,0)); - inc.push_back(std::pair(0,3)); + std::vector< std::pair > inc; + if(rows > 3 && cols > 2) + inc.push_back(std::pair(-3,-2)); + inc.push_back(std::pair(0,0)); + inc.push_back(std::pair(3,2)); + inc.push_back(std::pair(3,0)); + inc.push_back(std::pair(0,3)); for(size_t i = 0; i< inc.size(); i++) { - Index incRows = inc[i].first; - Index incCols = inc[i].second; + StorageIndex incRows = inc[i].first; + StorageIndex incCols = inc[i].second; SparseMatrixType m1(rows, cols); DenseMatrix refMat1 = DenseMatrix::Zero(rows, cols); initSparse(density, refMat1, m1); @@ -546,21 +585,104 @@ template void sparse_basic(const SparseMatrixType& re refMat1.setIdentity(); VERIFY_IS_APPROX(m1, refMat1); } + + // test array/vector of InnerIterator + { + typedef typename SparseMatrixType::InnerIterator IteratorType; + + DenseMatrix refMat2 = DenseMatrix::Zero(rows, cols); + SparseMatrixType m2(rows, cols); + initSparse(density, refMat2, m2); + IteratorType static_array[2]; + static_array[0] = IteratorType(m2,0); + static_array[1] = IteratorType(m2,m2.outerSize()-1); + VERIFY( static_array[0] || m2.innerVector(static_array[0].outer()).nonZeros() == 0 ); + VERIFY( static_array[1] || m2.innerVector(static_array[1].outer()).nonZeros() == 0 ); + if(static_array[0] && static_array[1]) + { + ++(static_array[1]); + static_array[1] = IteratorType(m2,0); + VERIFY( static_array[1] ); + VERIFY( static_array[1].index() == static_array[0].index() ); + VERIFY( static_array[1].outer() == static_array[0].outer() ); + VERIFY( static_array[1].value() == static_array[0].value() ); + } + + std::vector iters(2); + iters[0] = IteratorType(m2,0); + iters[1] = IteratorType(m2,m2.outerSize()-1); + } +} + + +template +void big_sparse_triplet(Index rows, Index cols, double density) { + typedef typename SparseMatrixType::StorageIndex StorageIndex; + typedef typename SparseMatrixType::Scalar Scalar; + typedef Triplet TripletType; + std::vector triplets; + double nelements = density * rows*cols; + VERIFY(nelements>=0 && nelements < NumTraits::highest()); + Index ntriplets = Index(nelements); + triplets.reserve(ntriplets); + Scalar sum = Scalar(0); + for(Index i=0;i(0,rows-1); + Index c = internal::random(0,cols-1); + Scalar v = internal::random(); + triplets.push_back(TripletType(r,c,v)); + sum += v; + } + SparseMatrixType m(rows,cols); + m.setFromTriplets(triplets.begin(), triplets.end()); + VERIFY(m.nonZeros() <= ntriplets); + VERIFY_IS_APPROX(sum, m.sum()); } + void test_sparse_basic() { for(int i = 0; i < g_repeat; i++) { - int s = Eigen::internal::random(1,50); - EIGEN_UNUSED_VARIABLE(s); + int r = Eigen::internal::random(1,200), c = Eigen::internal::random(1,200); + if(Eigen::internal::random(0,4) == 0) { + r = c; // check square matrices in 25% of tries + } + EIGEN_UNUSED_VARIABLE(r+c); + CALL_SUBTEST_1(( sparse_basic(SparseMatrix(1, 1)) )); CALL_SUBTEST_1(( sparse_basic(SparseMatrix(8, 8)) )); - CALL_SUBTEST_2(( sparse_basic(SparseMatrix, ColMajor>(s, s)) )); - CALL_SUBTEST_2(( sparse_basic(SparseMatrix, RowMajor>(s, s)) )); - CALL_SUBTEST_1(( sparse_basic(SparseMatrix(s, s)) )); - CALL_SUBTEST_1(( sparse_basic(SparseMatrix(s, s)) )); - CALL_SUBTEST_1(( sparse_basic(SparseMatrix(s, s)) )); + CALL_SUBTEST_2(( sparse_basic(SparseMatrix, ColMajor>(r, c)) )); + CALL_SUBTEST_2(( sparse_basic(SparseMatrix, RowMajor>(r, c)) )); + CALL_SUBTEST_1(( sparse_basic(SparseMatrix(r, c)) )); + CALL_SUBTEST_5(( sparse_basic(SparseMatrix(r, c)) )); + CALL_SUBTEST_5(( sparse_basic(SparseMatrix(r, c)) )); - CALL_SUBTEST_1(( sparse_basic(SparseMatrix(short(s), short(s))) )); - CALL_SUBTEST_1(( sparse_basic(SparseMatrix(short(s), short(s))) )); + r = Eigen::internal::random(1,100); + c = Eigen::internal::random(1,100); + if(Eigen::internal::random(0,4) == 0) { + r = c; // check square matrices in 25% of tries + } + + CALL_SUBTEST_6(( sparse_basic(SparseMatrix(short(r), short(c))) )); + CALL_SUBTEST_6(( sparse_basic(SparseMatrix(short(r), short(c))) )); + } + + // Regression test for bug 900: (manually insert higher values here, if you have enough RAM): + CALL_SUBTEST_3((big_sparse_triplet >(10000, 10000, 0.125))); + CALL_SUBTEST_4((big_sparse_triplet >(10000, 10000, 0.125))); + + // Regression test for bug 1105 +#ifdef EIGEN_TEST_PART_7 + { + int n = Eigen::internal::random(200,600); + SparseMatrix,0, long> mat(n, n); + std::complex val; + + for(int i=0; i +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "sparse.h" + +template +typename Eigen::internal::enable_if<(T::Flags&RowMajorBit)==RowMajorBit, typename T::RowXpr>::type +innervec(T& A, Index i) +{ + return A.row(i); +} + +template +typename Eigen::internal::enable_if<(T::Flags&RowMajorBit)==0, typename T::ColXpr>::type +innervec(T& A, Index i) +{ + return A.col(i); +} + +template void sparse_block(const SparseMatrixType& ref) +{ + const Index rows = ref.rows(); + const Index cols = ref.cols(); + const Index inner = ref.innerSize(); + const Index outer = ref.outerSize(); + + typedef typename SparseMatrixType::Scalar Scalar; + typedef typename SparseMatrixType::StorageIndex StorageIndex; + + double density = (std::max)(8./(rows*cols), 0.01); + typedef Matrix DenseMatrix; + typedef Matrix DenseVector; + typedef Matrix RowDenseVector; + typedef SparseVector SparseVectorType; + + Scalar s1 = internal::random(); + { + SparseMatrixType m(rows, cols); + DenseMatrix refMat = DenseMatrix::Zero(rows, cols); + initSparse(density, refMat, m); + + VERIFY_IS_APPROX(m, refMat); + + // test InnerIterators and Block expressions + for (int t=0; t<10; ++t) + { + Index j = internal::random(0,cols-2); + Index i = internal::random(0,rows-2); + Index w = internal::random(1,cols-j); + Index h = internal::random(1,rows-i); + + VERIFY_IS_APPROX(m.block(i,j,h,w), refMat.block(i,j,h,w)); + for(Index c=0; c(density, refMat2, m2); + Index j0 = internal::random(0,outer-1); + Index j1 = internal::random(0,outer-1); + Index r0 = internal::random(0,rows-1); + Index c0 = internal::random(0,cols-1); + + VERIFY_IS_APPROX(m2.innerVector(j0), innervec(refMat2,j0)); + VERIFY_IS_APPROX(m2.innerVector(j0)+m2.innerVector(j1), innervec(refMat2,j0)+innervec(refMat2,j1)); + + m2.innerVector(j0) *= Scalar(2); + innervec(refMat2,j0) *= Scalar(2); + VERIFY_IS_APPROX(m2, refMat2); + + m2.row(r0) *= Scalar(3); + refMat2.row(r0) *= Scalar(3); + VERIFY_IS_APPROX(m2, refMat2); + + m2.col(c0) *= Scalar(4); + refMat2.col(c0) *= Scalar(4); + VERIFY_IS_APPROX(m2, refMat2); + + m2.row(r0) /= Scalar(3); + refMat2.row(r0) /= Scalar(3); + VERIFY_IS_APPROX(m2, refMat2); + + m2.col(c0) /= Scalar(4); + refMat2.col(c0) /= Scalar(4); + VERIFY_IS_APPROX(m2, refMat2); + + SparseVectorType v1; + VERIFY_IS_APPROX(v1 = m2.col(c0) * 4, refMat2.col(c0)*4); + VERIFY_IS_APPROX(v1 = m2.row(r0) * 4, refMat2.row(r0).transpose()*4); + + SparseMatrixType m3(rows,cols); + m3.reserve(VectorXi::Constant(outer,int(inner/2))); + for(Index j=0; j(k+1); + for(Index j=0; j<(std::min)(outer, inner); ++j) + { + VERIFY(j==numext::real(m3.innerVector(j).nonZeros())); + if(j>0) + VERIFY(j==numext::real(m3.innerVector(j).lastCoeff())); + } + m3.makeCompressed(); + for(Index j=0; j<(std::min)(outer, inner); ++j) + { + VERIFY(j==numext::real(m3.innerVector(j).nonZeros())); + if(j>0) + VERIFY(j==numext::real(m3.innerVector(j).lastCoeff())); + } + + VERIFY(m3.innerVector(j0).nonZeros() == m3.transpose().innerVector(j0).nonZeros()); + +// m2.innerVector(j0) = 2*m2.innerVector(j1); +// refMat2.col(j0) = 2*refMat2.col(j1); +// VERIFY_IS_APPROX(m2, refMat2); + } + + // test innerVectors() + { + DenseMatrix refMat2 = DenseMatrix::Zero(rows, cols); + SparseMatrixType m2(rows, cols); + initSparse(density, refMat2, m2); + if(internal::random(0,1)>0.5f) m2.makeCompressed(); + Index j0 = internal::random(0,outer-2); + Index j1 = internal::random(0,outer-2); + Index n0 = internal::random(1,outer-(std::max)(j0,j1)); + if(SparseMatrixType::IsRowMajor) + VERIFY_IS_APPROX(m2.innerVectors(j0,n0), refMat2.block(j0,0,n0,cols)); + else + VERIFY_IS_APPROX(m2.innerVectors(j0,n0), refMat2.block(0,j0,rows,n0)); + if(SparseMatrixType::IsRowMajor) + VERIFY_IS_APPROX(m2.innerVectors(j0,n0)+m2.innerVectors(j1,n0), + refMat2.middleRows(j0,n0)+refMat2.middleRows(j1,n0)); + else + VERIFY_IS_APPROX(m2.innerVectors(j0,n0)+m2.innerVectors(j1,n0), + refMat2.block(0,j0,rows,n0)+refMat2.block(0,j1,rows,n0)); + + VERIFY_IS_APPROX(m2, refMat2); + + VERIFY(m2.innerVectors(j0,n0).nonZeros() == m2.transpose().innerVectors(j0,n0).nonZeros()); + + m2.innerVectors(j0,n0) = m2.innerVectors(j0,n0) + m2.innerVectors(j1,n0); + if(SparseMatrixType::IsRowMajor) + refMat2.middleRows(j0,n0) = (refMat2.middleRows(j0,n0) + refMat2.middleRows(j1,n0)).eval(); + else + refMat2.middleCols(j0,n0) = (refMat2.middleCols(j0,n0) + refMat2.middleCols(j1,n0)).eval(); + + VERIFY_IS_APPROX(m2, refMat2); + } + + // test generic blocks + { + DenseMatrix refMat2 = DenseMatrix::Zero(rows, cols); + SparseMatrixType m2(rows, cols); + initSparse(density, refMat2, m2); + Index j0 = internal::random(0,outer-2); + Index j1 = internal::random(0,outer-2); + Index n0 = internal::random(1,outer-(std::max)(j0,j1)); + if(SparseMatrixType::IsRowMajor) + VERIFY_IS_APPROX(m2.block(j0,0,n0,cols), refMat2.block(j0,0,n0,cols)); + else + VERIFY_IS_APPROX(m2.block(0,j0,rows,n0), refMat2.block(0,j0,rows,n0)); + + if(SparseMatrixType::IsRowMajor) + VERIFY_IS_APPROX(m2.block(j0,0,n0,cols)+m2.block(j1,0,n0,cols), + refMat2.block(j0,0,n0,cols)+refMat2.block(j1,0,n0,cols)); + else + VERIFY_IS_APPROX(m2.block(0,j0,rows,n0)+m2.block(0,j1,rows,n0), + refMat2.block(0,j0,rows,n0)+refMat2.block(0,j1,rows,n0)); + + Index i = internal::random(0,m2.outerSize()-1); + if(SparseMatrixType::IsRowMajor) { + m2.innerVector(i) = m2.innerVector(i) * s1; + refMat2.row(i) = refMat2.row(i) * s1; + VERIFY_IS_APPROX(m2,refMat2); + } else { + m2.innerVector(i) = m2.innerVector(i) * s1; + refMat2.col(i) = refMat2.col(i) * s1; + VERIFY_IS_APPROX(m2,refMat2); + } + + Index r0 = internal::random(0,rows-2); + Index c0 = internal::random(0,cols-2); + Index r1 = internal::random(1,rows-r0); + Index c1 = internal::random(1,cols-c0); + + VERIFY_IS_APPROX(DenseVector(m2.col(c0)), refMat2.col(c0)); + VERIFY_IS_APPROX(m2.col(c0), refMat2.col(c0)); + + VERIFY_IS_APPROX(RowDenseVector(m2.row(r0)), refMat2.row(r0)); + VERIFY_IS_APPROX(m2.row(r0), refMat2.row(r0)); + + VERIFY_IS_APPROX(m2.block(r0,c0,r1,c1), refMat2.block(r0,c0,r1,c1)); + VERIFY_IS_APPROX((2*m2).block(r0,c0,r1,c1), (2*refMat2).block(r0,c0,r1,c1)); + + if(m2.nonZeros()>0) + { + VERIFY_IS_APPROX(m2, refMat2); + SparseMatrixType m3(rows, cols); + DenseMatrix refMat3(rows, cols); refMat3.setZero(); + Index n = internal::random(1,10); + for(Index k=0; k(0,outer-1); + Index o2 = internal::random(0,outer-1); + if(SparseMatrixType::IsRowMajor) + { + m3.innerVector(o1) = m2.row(o2); + refMat3.row(o1) = refMat2.row(o2); + } + else + { + m3.innerVector(o1) = m2.col(o2); + refMat3.col(o1) = refMat2.col(o2); + } + if(internal::random()) + m3.makeCompressed(); + } + if(m3.nonZeros()>0) + VERIFY_IS_APPROX(m3, refMat3); + } + } +} + +void test_sparse_block() +{ + for(int i = 0; i < g_repeat; i++) { + int r = Eigen::internal::random(1,200), c = Eigen::internal::random(1,200); + if(Eigen::internal::random(0,4) == 0) { + r = c; // check square matrices in 25% of tries + } + EIGEN_UNUSED_VARIABLE(r+c); + CALL_SUBTEST_1(( sparse_block(SparseMatrix(1, 1)) )); + CALL_SUBTEST_1(( sparse_block(SparseMatrix(8, 8)) )); + CALL_SUBTEST_1(( sparse_block(SparseMatrix(r, c)) )); + CALL_SUBTEST_2(( sparse_block(SparseMatrix, ColMajor>(r, c)) )); + CALL_SUBTEST_2(( sparse_block(SparseMatrix, RowMajor>(r, c)) )); + + CALL_SUBTEST_3(( sparse_block(SparseMatrix(r, c)) )); + CALL_SUBTEST_3(( sparse_block(SparseMatrix(r, c)) )); + + r = Eigen::internal::random(1,100); + c = Eigen::internal::random(1,100); + if(Eigen::internal::random(0,4) == 0) { + r = c; // check square matrices in 25% of tries + } + + CALL_SUBTEST_4(( sparse_block(SparseMatrix(short(r), short(c))) )); + CALL_SUBTEST_4(( sparse_block(SparseMatrix(short(r), short(c))) )); + } +} diff --git a/ground/gcs/src/libs/eigen/test/sparse_permutations.cpp b/ground/gcs/src/libs/eigen/test/sparse_permutations.cpp index e4ce1d6796..b82cceff80 100644 --- a/ground/gcs/src/libs/eigen/test/sparse_permutations.cpp +++ b/ground/gcs/src/libs/eigen/test/sparse_permutations.cpp @@ -1,25 +1,57 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2011 Gael Guennebaud +// Copyright (C) 2011-2015 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +static long int nb_transposed_copies; +#define EIGEN_SPARSE_TRANSPOSED_COPY_PLUGIN {nb_transposed_copies++;} +#define VERIFY_TRANSPOSITION_COUNT(XPR,N) {\ + nb_transposed_copies = 0; \ + XPR; \ + if(nb_transposed_copies!=N) std::cerr << "nb_transposed_copies == " << nb_transposed_copies << "\n"; \ + VERIFY( (#XPR) && nb_transposed_copies==N ); \ + } + #include "sparse.h" -template void sparse_permutations(const SparseMatrixType& ref) +template +bool is_sorted(const T& mat) { + for(Index k = 0; k=it.index()) + return false; + prev = it.index(); + } + } + return true; +} + +template +typename internal::nested_eval::type eval(const T &xpr) { - typedef typename SparseMatrixType::Index Index; + VERIFY( int(internal::nested_eval::type::Flags&RowMajorBit) == int(internal::evaluator::Flags&RowMajorBit) ); + return xpr; +} +template void sparse_permutations(const SparseMatrixType& ref) +{ const Index rows = ref.rows(); const Index cols = ref.cols(); typedef typename SparseMatrixType::Scalar Scalar; - typedef typename SparseMatrixType::Index Index; - typedef SparseMatrix OtherSparseMatrixType; + typedef typename SparseMatrixType::StorageIndex StorageIndex; + typedef SparseMatrix OtherSparseMatrixType; typedef Matrix DenseMatrix; - typedef Matrix VectorI; + typedef Matrix VectorI; +// bool IsRowMajor1 = SparseMatrixType::IsRowMajor; +// bool IsRowMajor2 = OtherSparseMatrixType::IsRowMajor; double density = (std::max)(8./(rows*cols), 0.01); @@ -44,58 +76,69 @@ template void sparse_permutations(c randomPermutationVector(pi, cols); p.indices() = pi; - res = mat*p; + VERIFY( is_sorted( ::eval(mat*p) )); + VERIFY( is_sorted( res = mat*p )); + VERIFY_TRANSPOSITION_COUNT( ::eval(mat*p), 0); + //VERIFY_TRANSPOSITION_COUNT( res = mat*p, IsRowMajor ? 1 : 0 ); res_d = mat_d*p; VERIFY(res.isApprox(res_d) && "mat*p"); - res = p*mat; + VERIFY( is_sorted( ::eval(p*mat) )); + VERIFY( is_sorted( res = p*mat )); + VERIFY_TRANSPOSITION_COUNT( ::eval(p*mat), 0); res_d = p*mat_d; VERIFY(res.isApprox(res_d) && "p*mat"); - res = mat*p.inverse(); + VERIFY( is_sorted( (mat*p).eval() )); + VERIFY( is_sorted( res = mat*p.inverse() )); + VERIFY_TRANSPOSITION_COUNT( ::eval(mat*p.inverse()), 0); res_d = mat*p.inverse(); VERIFY(res.isApprox(res_d) && "mat*inv(p)"); - res = p.inverse()*mat; + VERIFY( is_sorted( (p*mat+p*mat).eval() )); + VERIFY( is_sorted( res = p.inverse()*mat )); + VERIFY_TRANSPOSITION_COUNT( ::eval(p.inverse()*mat), 0); res_d = p.inverse()*mat_d; VERIFY(res.isApprox(res_d) && "inv(p)*mat"); - res = mat.twistedBy(p); + VERIFY( is_sorted( (p * mat * p.inverse()).eval() )); + VERIFY( is_sorted( res = mat.twistedBy(p) )); + VERIFY_TRANSPOSITION_COUNT( ::eval(p * mat * p.inverse()), 0); res_d = (p * mat_d) * p.inverse(); VERIFY(res.isApprox(res_d) && "p*mat*inv(p)"); - res = mat.template selfadjointView().twistedBy(p_null); + VERIFY( is_sorted( res = mat.template selfadjointView().twistedBy(p_null) )); res_d = up_sym_d; VERIFY(res.isApprox(res_d) && "full selfadjoint upper to full"); - res = mat.template selfadjointView().twistedBy(p_null); + VERIFY( is_sorted( res = mat.template selfadjointView().twistedBy(p_null) )); res_d = lo_sym_d; VERIFY(res.isApprox(res_d) && "full selfadjoint lower to full"); - res = up.template selfadjointView().twistedBy(p_null); + VERIFY( is_sorted( res = up.template selfadjointView().twistedBy(p_null) )); res_d = up_sym_d; VERIFY(res.isApprox(res_d) && "upper selfadjoint to full"); - res = lo.template selfadjointView().twistedBy(p_null); + VERIFY( is_sorted( res = lo.template selfadjointView().twistedBy(p_null) )); res_d = lo_sym_d; VERIFY(res.isApprox(res_d) && "lower selfadjoint full"); - res = mat.template selfadjointView(); + VERIFY( is_sorted( res = mat.template selfadjointView() )); res_d = up_sym_d; VERIFY(res.isApprox(res_d) && "full selfadjoint upper to full"); - res = mat.template selfadjointView(); + VERIFY( is_sorted( res = mat.template selfadjointView() )); res_d = lo_sym_d; VERIFY(res.isApprox(res_d) && "full selfadjoint lower to full"); - res = up.template selfadjointView(); + VERIFY( is_sorted( res = up.template selfadjointView() )); res_d = up_sym_d; VERIFY(res.isApprox(res_d) && "upper selfadjoint to full"); - res = lo.template selfadjointView(); + VERIFY( is_sorted( res = lo.template selfadjointView() )); res_d = lo_sym_d; VERIFY(res.isApprox(res_d) && "lower selfadjoint full"); @@ -152,19 +195,19 @@ template void sparse_permutations(c VERIFY(res.isApprox(res_d) && "upper selfadjoint twisted to lower"); - res = mat.template selfadjointView().twistedBy(p); + VERIFY( is_sorted( res = mat.template selfadjointView().twistedBy(p) )); res_d = (p * up_sym_d) * p.inverse(); VERIFY(res.isApprox(res_d) && "full selfadjoint upper twisted to full"); - res = mat.template selfadjointView().twistedBy(p); + VERIFY( is_sorted( res = mat.template selfadjointView().twistedBy(p) )); res_d = (p * lo_sym_d) * p.inverse(); VERIFY(res.isApprox(res_d) && "full selfadjoint lower twisted to full"); - res = up.template selfadjointView().twistedBy(p); + VERIFY( is_sorted( res = up.template selfadjointView().twistedBy(p) )); res_d = (p * up_sym_d) * p.inverse(); VERIFY(res.isApprox(res_d) && "upper selfadjoint twisted to full"); - res = lo.template selfadjointView().twistedBy(p); + VERIFY( is_sorted( res = lo.template selfadjointView().twistedBy(p) )); res_d = (p * lo_sym_d) * p.inverse(); VERIFY(res.isApprox(res_d) && "lower selfadjoint twisted to full"); } @@ -184,4 +227,10 @@ void test_sparse_permutations() CALL_SUBTEST_1(( sparse_permutations_all(s) )); CALL_SUBTEST_2(( sparse_permutations_all >(s) )); } + + VERIFY((internal::is_same,OnTheRight,false,SparseShape>::ReturnType, + internal::nested_eval,PermutationMatrix,AliasFreeProduct>,1>::type>::value)); + + VERIFY((internal::is_same,OnTheLeft,false,SparseShape>::ReturnType, + internal::nested_eval,SparseMatrix,AliasFreeProduct>,1>::type>::value)); } diff --git a/ground/gcs/src/libs/eigen/test/sparse_product.cpp b/ground/gcs/src/libs/eigen/test/sparse_product.cpp index a2ea9d5b79..c1edd26e3a 100644 --- a/ground/gcs/src/libs/eigen/test/sparse_product.cpp +++ b/ground/gcs/src/libs/eigen/test/sparse_product.cpp @@ -7,37 +7,29 @@ // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. -#include "sparse.h" +static long int nb_temporaries; -template struct test_outer; +inline void on_temporary_creation() { + // here's a great place to set a breakpoint when debugging failures in this test! + nb_temporaries++; +} -template struct test_outer { - static void run(SparseMatrixType& m2, SparseMatrixType& m4, DenseMatrix& refMat2, DenseMatrix& refMat4) { - typedef typename SparseMatrixType::Index Index; - Index c = internal::random(0,m2.cols()-1); - Index c1 = internal::random(0,m2.cols()-1); - VERIFY_IS_APPROX(m4=m2.col(c)*refMat2.col(c1).transpose(), refMat4=refMat2.col(c)*refMat2.col(c1).transpose()); - VERIFY_IS_APPROX(m4=refMat2.col(c1)*m2.col(c).transpose(), refMat4=refMat2.col(c1)*refMat2.col(c).transpose()); - } -}; - -template struct test_outer { - static void run(SparseMatrixType& m2, SparseMatrixType& m4, DenseMatrix& refMat2, DenseMatrix& refMat4) { - typedef typename SparseMatrixType::Index Index; - Index r = internal::random(0,m2.rows()-1); - Index c1 = internal::random(0,m2.cols()-1); - VERIFY_IS_APPROX(m4=m2.row(r).transpose()*refMat2.col(c1).transpose(), refMat4=refMat2.row(r).transpose()*refMat2.col(c1).transpose()); - VERIFY_IS_APPROX(m4=refMat2.col(c1)*m2.row(r), refMat4=refMat2.col(c1)*refMat2.row(r)); +#define EIGEN_SPARSE_CREATE_TEMPORARY_PLUGIN { on_temporary_creation(); } + +#include "sparse.h" + +#define VERIFY_EVALUATION_COUNT(XPR,N) {\ + nb_temporaries = 0; \ + CALL_SUBTEST( XPR ); \ + if(nb_temporaries!=N) std::cerr << "nb_temporaries == " << nb_temporaries << "\n"; \ + VERIFY( (#XPR) && nb_temporaries==N ); \ } -}; -// (m2,m4,refMat2,refMat4,dv1); -// VERIFY_IS_APPROX(m4=m2.innerVector(c)*dv1.transpose(), refMat4=refMat2.colVector(c)*dv1.transpose()); -// VERIFY_IS_APPROX(m4=dv1*mcm.col(c).transpose(), refMat4=dv1*refMat2.col(c).transpose()); + template void sparse_product() { - typedef typename SparseMatrixType::Index Index; + typedef typename SparseMatrixType::StorageIndex StorageIndex; Index n = 100; const Index rows = internal::random(1,n); const Index cols = internal::random(1,n); @@ -45,12 +37,12 @@ template void sparse_product() typedef typename SparseMatrixType::Scalar Scalar; enum { Flags = SparseMatrixType::Flags }; - double density = (std::max)(8./(rows*cols), 0.1); + double density = (std::max)(8./(rows*cols), 0.2); typedef Matrix DenseMatrix; typedef Matrix DenseVector; typedef Matrix RowDenseVector; - typedef SparseVector ColSpVector; - typedef SparseVector RowSpVector; + typedef SparseVector ColSpVector; + typedef SparseVector RowSpVector; Scalar s1 = internal::random(); Scalar s2 = internal::random(); @@ -93,33 +85,124 @@ template void sparse_product() VERIFY_IS_APPROX(m4 = m2*m3/s1, refMat4 = refMat2*refMat3/s1); VERIFY_IS_APPROX(m4 = m2*m3*s1, refMat4 = refMat2*refMat3*s1); VERIFY_IS_APPROX(m4 = s2*m2*m3*s1, refMat4 = s2*refMat2*refMat3*s1); + VERIFY_IS_APPROX(m4 = (m2+m2)*m3, refMat4 = (refMat2+refMat2)*refMat3); + VERIFY_IS_APPROX(m4 = m2*m3.leftCols(cols/2), refMat4 = refMat2*refMat3.leftCols(cols/2)); + VERIFY_IS_APPROX(m4 = m2*(m3+m3).leftCols(cols/2), refMat4 = refMat2*(refMat3+refMat3).leftCols(cols/2)); VERIFY_IS_APPROX(m4=(m2*m3).pruned(0), refMat4=refMat2*refMat3); VERIFY_IS_APPROX(m4=(m2t.transpose()*m3).pruned(0), refMat4=refMat2t.transpose()*refMat3); VERIFY_IS_APPROX(m4=(m2t.transpose()*m3t.transpose()).pruned(0), refMat4=refMat2t.transpose()*refMat3t.transpose()); VERIFY_IS_APPROX(m4=(m2*m3t.transpose()).pruned(0), refMat4=refMat2*refMat3t.transpose()); + // make sure the right product implementation is called: + if((!SparseMatrixType::IsRowMajor) && m2.rows()<=m3.cols()) + { + VERIFY_EVALUATION_COUNT(m4 = m2*m3, 3); // 1 temp for the result + 2 for transposing and get a sorted result. + VERIFY_EVALUATION_COUNT(m4 = (m2*m3).pruned(0), 1); + VERIFY_EVALUATION_COUNT(m4 = (m2*m3).eval().pruned(0), 4); + } + + // and that pruning is effective: + { + DenseMatrix Ad(2,2); + Ad << -1, 1, 1, 1; + SparseMatrixType As(Ad.sparseView()), B(2,2); + VERIFY_IS_EQUAL( (As*As.transpose()).eval().nonZeros(), 4); + VERIFY_IS_EQUAL( (Ad*Ad.transpose()).eval().sparseView().eval().nonZeros(), 2); + VERIFY_IS_EQUAL( (As*As.transpose()).pruned(1e-6).eval().nonZeros(), 2); + } + + // dense ?= sparse * sparse + VERIFY_IS_APPROX(dm4 =m2*m3, refMat4 =refMat2*refMat3); + VERIFY_IS_APPROX(dm4+=m2*m3, refMat4+=refMat2*refMat3); + VERIFY_IS_APPROX(dm4-=m2*m3, refMat4-=refMat2*refMat3); + VERIFY_IS_APPROX(dm4 =m2t.transpose()*m3, refMat4 =refMat2t.transpose()*refMat3); + VERIFY_IS_APPROX(dm4+=m2t.transpose()*m3, refMat4+=refMat2t.transpose()*refMat3); + VERIFY_IS_APPROX(dm4-=m2t.transpose()*m3, refMat4-=refMat2t.transpose()*refMat3); + VERIFY_IS_APPROX(dm4 =m2t.transpose()*m3t.transpose(), refMat4 =refMat2t.transpose()*refMat3t.transpose()); + VERIFY_IS_APPROX(dm4+=m2t.transpose()*m3t.transpose(), refMat4+=refMat2t.transpose()*refMat3t.transpose()); + VERIFY_IS_APPROX(dm4-=m2t.transpose()*m3t.transpose(), refMat4-=refMat2t.transpose()*refMat3t.transpose()); + VERIFY_IS_APPROX(dm4 =m2*m3t.transpose(), refMat4 =refMat2*refMat3t.transpose()); + VERIFY_IS_APPROX(dm4+=m2*m3t.transpose(), refMat4+=refMat2*refMat3t.transpose()); + VERIFY_IS_APPROX(dm4-=m2*m3t.transpose(), refMat4-=refMat2*refMat3t.transpose()); + VERIFY_IS_APPROX(dm4 = m2*m3*s1, refMat4 = refMat2*refMat3*s1); + // test aliasing m4 = m2; refMat4 = refMat2; VERIFY_IS_APPROX(m4=m4*m3, refMat4=refMat4*refMat3); - // sparse * dense + // sparse * dense matrix VERIFY_IS_APPROX(dm4=m2*refMat3, refMat4=refMat2*refMat3); VERIFY_IS_APPROX(dm4=m2*refMat3t.transpose(), refMat4=refMat2*refMat3t.transpose()); VERIFY_IS_APPROX(dm4=m2t.transpose()*refMat3, refMat4=refMat2t.transpose()*refMat3); VERIFY_IS_APPROX(dm4=m2t.transpose()*refMat3t.transpose(), refMat4=refMat2t.transpose()*refMat3t.transpose()); + VERIFY_IS_APPROX(dm4=m2*refMat3, refMat4=refMat2*refMat3); + VERIFY_IS_APPROX(dm4=dm4+m2*refMat3, refMat4=refMat4+refMat2*refMat3); + VERIFY_IS_APPROX(dm4+=m2*refMat3, refMat4+=refMat2*refMat3); + VERIFY_IS_APPROX(dm4-=m2*refMat3, refMat4-=refMat2*refMat3); + VERIFY_IS_APPROX(dm4.noalias()+=m2*refMat3, refMat4+=refMat2*refMat3); + VERIFY_IS_APPROX(dm4.noalias()-=m2*refMat3, refMat4-=refMat2*refMat3); VERIFY_IS_APPROX(dm4=m2*(refMat3+refMat3), refMat4=refMat2*(refMat3+refMat3)); VERIFY_IS_APPROX(dm4=m2t.transpose()*(refMat3+refMat5)*0.5, refMat4=refMat2t.transpose()*(refMat3+refMat5)*0.5); + + // sparse * dense vector + VERIFY_IS_APPROX(dm4.col(0)=m2*refMat3.col(0), refMat4.col(0)=refMat2*refMat3.col(0)); + VERIFY_IS_APPROX(dm4.col(0)=m2*refMat3t.transpose().col(0), refMat4.col(0)=refMat2*refMat3t.transpose().col(0)); + VERIFY_IS_APPROX(dm4.col(0)=m2t.transpose()*refMat3.col(0), refMat4.col(0)=refMat2t.transpose()*refMat3.col(0)); + VERIFY_IS_APPROX(dm4.col(0)=m2t.transpose()*refMat3t.transpose().col(0), refMat4.col(0)=refMat2t.transpose()*refMat3t.transpose().col(0)); // dense * sparse VERIFY_IS_APPROX(dm4=refMat2*m3, refMat4=refMat2*refMat3); + VERIFY_IS_APPROX(dm4=dm4+refMat2*m3, refMat4=refMat4+refMat2*refMat3); + VERIFY_IS_APPROX(dm4+=refMat2*m3, refMat4+=refMat2*refMat3); + VERIFY_IS_APPROX(dm4-=refMat2*m3, refMat4-=refMat2*refMat3); + VERIFY_IS_APPROX(dm4.noalias()+=refMat2*m3, refMat4+=refMat2*refMat3); + VERIFY_IS_APPROX(dm4.noalias()-=refMat2*m3, refMat4-=refMat2*refMat3); VERIFY_IS_APPROX(dm4=refMat2*m3t.transpose(), refMat4=refMat2*refMat3t.transpose()); VERIFY_IS_APPROX(dm4=refMat2t.transpose()*m3, refMat4=refMat2t.transpose()*refMat3); VERIFY_IS_APPROX(dm4=refMat2t.transpose()*m3t.transpose(), refMat4=refMat2t.transpose()*refMat3t.transpose()); // sparse * dense and dense * sparse outer product - test_outer::run(m2,m4,refMat2,refMat4); + { + Index c = internal::random(0,depth-1); + Index r = internal::random(0,rows-1); + Index c1 = internal::random(0,cols-1); + Index r1 = internal::random(0,depth-1); + DenseMatrix dm5 = DenseMatrix::Random(depth, cols); + + VERIFY_IS_APPROX( m4=m2.col(c)*dm5.col(c1).transpose(), refMat4=refMat2.col(c)*dm5.col(c1).transpose()); + VERIFY_IS_EQUAL(m4.nonZeros(), (refMat4.array()!=0).count()); + VERIFY_IS_APPROX( m4=m2.middleCols(c,1)*dm5.col(c1).transpose(), refMat4=refMat2.col(c)*dm5.col(c1).transpose()); + VERIFY_IS_EQUAL(m4.nonZeros(), (refMat4.array()!=0).count()); + VERIFY_IS_APPROX(dm4=m2.col(c)*dm5.col(c1).transpose(), refMat4=refMat2.col(c)*dm5.col(c1).transpose()); + + VERIFY_IS_APPROX(m4=dm5.col(c1)*m2.col(c).transpose(), refMat4=dm5.col(c1)*refMat2.col(c).transpose()); + VERIFY_IS_EQUAL(m4.nonZeros(), (refMat4.array()!=0).count()); + VERIFY_IS_APPROX(m4=dm5.col(c1)*m2.middleCols(c,1).transpose(), refMat4=dm5.col(c1)*refMat2.col(c).transpose()); + VERIFY_IS_EQUAL(m4.nonZeros(), (refMat4.array()!=0).count()); + VERIFY_IS_APPROX(dm4=dm5.col(c1)*m2.col(c).transpose(), refMat4=dm5.col(c1)*refMat2.col(c).transpose()); + + VERIFY_IS_APPROX( m4=dm5.row(r1).transpose()*m2.col(c).transpose(), refMat4=dm5.row(r1).transpose()*refMat2.col(c).transpose()); + VERIFY_IS_EQUAL(m4.nonZeros(), (refMat4.array()!=0).count()); + VERIFY_IS_APPROX(dm4=dm5.row(r1).transpose()*m2.col(c).transpose(), refMat4=dm5.row(r1).transpose()*refMat2.col(c).transpose()); + + VERIFY_IS_APPROX( m4=m2.row(r).transpose()*dm5.col(c1).transpose(), refMat4=refMat2.row(r).transpose()*dm5.col(c1).transpose()); + VERIFY_IS_EQUAL(m4.nonZeros(), (refMat4.array()!=0).count()); + VERIFY_IS_APPROX( m4=m2.middleRows(r,1).transpose()*dm5.col(c1).transpose(), refMat4=refMat2.row(r).transpose()*dm5.col(c1).transpose()); + VERIFY_IS_EQUAL(m4.nonZeros(), (refMat4.array()!=0).count()); + VERIFY_IS_APPROX(dm4=m2.row(r).transpose()*dm5.col(c1).transpose(), refMat4=refMat2.row(r).transpose()*dm5.col(c1).transpose()); + + VERIFY_IS_APPROX( m4=dm5.col(c1)*m2.row(r), refMat4=dm5.col(c1)*refMat2.row(r)); + VERIFY_IS_EQUAL(m4.nonZeros(), (refMat4.array()!=0).count()); + VERIFY_IS_APPROX( m4=dm5.col(c1)*m2.middleRows(r,1), refMat4=dm5.col(c1)*refMat2.row(r)); + VERIFY_IS_EQUAL(m4.nonZeros(), (refMat4.array()!=0).count()); + VERIFY_IS_APPROX(dm4=dm5.col(c1)*m2.row(r), refMat4=dm5.col(c1)*refMat2.row(r)); + + VERIFY_IS_APPROX( m4=dm5.row(r1).transpose()*m2.row(r), refMat4=dm5.row(r1).transpose()*refMat2.row(r)); + VERIFY_IS_EQUAL(m4.nonZeros(), (refMat4.array()!=0).count()); + VERIFY_IS_APPROX(dm4=dm5.row(r1).transpose()*m2.row(r), refMat4=dm5.row(r1).transpose()*refMat2.row(r)); + } VERIFY_IS_APPROX(m6=m6*m6, refMat6=refMat6*refMat6); @@ -131,11 +214,11 @@ template void sparse_product() RowSpVector rv0(depth), rv1; RowDenseVector drv0(depth), drv1(rv1); initSparse(2*density,drv0, rv0); - - VERIFY_IS_APPROX(cv1=rv0*m3, dcv1=drv0*refMat3); + + VERIFY_IS_APPROX(cv1=m3*cv0, dcv1=refMat3*dcv0); VERIFY_IS_APPROX(rv1=rv0*m3, drv1=drv0*refMat3); - VERIFY_IS_APPROX(cv1=m3*cv0, dcv1=refMat3*dcv0); VERIFY_IS_APPROX(cv1=m3t.adjoint()*cv0, dcv1=refMat3t.adjoint()*dcv0); + VERIFY_IS_APPROX(cv1=rv0*m3, dcv1=drv0*refMat3); VERIFY_IS_APPROX(rv1=m3*cv0, drv1=refMat3*dcv0); } @@ -158,12 +241,16 @@ template void sparse_product() // also check with a SparseWrapper: DenseVector v1 = DenseVector::Random(cols); DenseVector v2 = DenseVector::Random(rows); + DenseVector v3 = DenseVector::Random(rows); VERIFY_IS_APPROX(m3=m2*v1.asDiagonal(), refM3=refM2*v1.asDiagonal()); VERIFY_IS_APPROX(m3=m2.transpose()*v2.asDiagonal(), refM3=refM2.transpose()*v2.asDiagonal()); VERIFY_IS_APPROX(m3=v2.asDiagonal()*m2, refM3=v2.asDiagonal()*refM2); VERIFY_IS_APPROX(m3=v1.asDiagonal()*m2.transpose(), refM3=v1.asDiagonal()*refM2.transpose()); VERIFY_IS_APPROX(m3=v2.asDiagonal()*m2*v1.asDiagonal(), refM3=v2.asDiagonal()*refM2*v1.asDiagonal()); + + VERIFY_IS_APPROX(v2=m2*v1.asDiagonal()*v1, refM2*v1.asDiagonal()*v1); + VERIFY_IS_APPROX(v3=v2.asDiagonal()*m2*v1, v2.asDiagonal()*refM2*v1); // evaluate to a dense matrix to check the .row() and .col() iterator functions VERIFY_IS_APPROX(d3=m2*d1, refM3=refM2*d1); @@ -172,7 +259,7 @@ template void sparse_product() VERIFY_IS_APPROX(d3=d1*m2.transpose(), refM3=d1*refM2.transpose()); } - // test self adjoint products + // test self-adjoint and triangular-view products { DenseMatrix b = DenseMatrix::Random(rows, rows); DenseMatrix x = DenseMatrix::Random(rows, rows); @@ -180,9 +267,12 @@ template void sparse_product() DenseMatrix refUp = DenseMatrix::Zero(rows, rows); DenseMatrix refLo = DenseMatrix::Zero(rows, rows); DenseMatrix refS = DenseMatrix::Zero(rows, rows); + DenseMatrix refA = DenseMatrix::Zero(rows, rows); SparseMatrixType mUp(rows, rows); SparseMatrixType mLo(rows, rows); SparseMatrixType mS(rows, rows); + SparseMatrixType mA(rows, rows); + initSparse(density, refA, mA); do { initSparse(density, refUp, mUp, ForceRealDiag|/*ForceNonZeroDiag|*/MakeUpperTriangular); } while (refUp.isZero()); @@ -195,26 +285,41 @@ template void sparse_product() for (int k=0; k()*b, refX=refS*b); VERIFY_IS_APPROX(x=mLo.template selfadjointView()*b, refX=refS*b); VERIFY_IS_APPROX(x=mS.template selfadjointView()*b, refX=refS*b); + + VERIFY_IS_APPROX(x.noalias()+=mUp.template selfadjointView()*b, refX+=refS*b); + VERIFY_IS_APPROX(x.noalias()-=mLo.template selfadjointView()*b, refX-=refS*b); + VERIFY_IS_APPROX(x.noalias()+=mS.template selfadjointView()*b, refX+=refS*b); - // sparse selfadjointView * sparse + // sparse selfadjointView with sparse matrices SparseMatrixType mSres(rows,rows); VERIFY_IS_APPROX(mSres = mLo.template selfadjointView()*mS, refX = refLo.template selfadjointView()*refS); - // sparse * sparse selfadjointview VERIFY_IS_APPROX(mSres = mS * mLo.template selfadjointView(), refX = refS * refLo.template selfadjointView()); + + // sparse triangularView with dense matrices + VERIFY_IS_APPROX(x=mA.template triangularView()*b, refX=refA.template triangularView()*b); + VERIFY_IS_APPROX(x=mA.template triangularView()*b, refX=refA.template triangularView()*b); + VERIFY_IS_APPROX(x=b*mA.template triangularView(), refX=b*refA.template triangularView()); + VERIFY_IS_APPROX(x=b*mA.template triangularView(), refX=b*refA.template triangularView()); + + // sparse triangularView with sparse matrices + VERIFY_IS_APPROX(mSres = mA.template triangularView()*mS, refX = refA.template triangularView()*refS); + VERIFY_IS_APPROX(mSres = mS * mA.template triangularView(), refX = refS * refA.template triangularView()); + VERIFY_IS_APPROX(mSres = mA.template triangularView()*mS, refX = refA.template triangularView()*refS); + VERIFY_IS_APPROX(mSres = mS * mA.template triangularView(), refX = refS * refA.template triangularView()); } - } // New test for Bug in SparseTimeDenseProduct @@ -239,11 +344,35 @@ template void sparse_produc VERIFY_IS_APPROX( m4(0,0), 0.0 ); } +template +void bug_942() +{ + typedef Matrix Vector; + typedef SparseMatrix ColSpMat; + typedef SparseMatrix RowSpMat; + ColSpMat cmA(1,1); + cmA.insert(0,0) = 1; + + RowSpMat rmA(1,1); + rmA.insert(0,0) = 1; + + Vector d(1); + d[0] = 2; + + double res = 2; + + VERIFY_IS_APPROX( ( cmA*d.asDiagonal() ).eval().coeff(0,0), res ); + VERIFY_IS_APPROX( ( d.asDiagonal()*rmA ).eval().coeff(0,0), res ); + VERIFY_IS_APPROX( ( rmA*d.asDiagonal() ).eval().coeff(0,0), res ); + VERIFY_IS_APPROX( ( d.asDiagonal()*cmA ).eval().coeff(0,0), res ); +} + void test_sparse_product() { for(int i = 0; i < g_repeat; i++) { CALL_SUBTEST_1( (sparse_product >()) ); CALL_SUBTEST_1( (sparse_product >()) ); + CALL_SUBTEST_1( (bug_942()) ); CALL_SUBTEST_2( (sparse_product, ColMajor > >()) ); CALL_SUBTEST_2( (sparse_product, RowMajor > >()) ); CALL_SUBTEST_3( (sparse_product >()) ); diff --git a/ground/gcs/src/libs/eigen/test/sparse_ref.cpp b/ground/gcs/src/libs/eigen/test/sparse_ref.cpp new file mode 100644 index 0000000000..5e9607234d --- /dev/null +++ b/ground/gcs/src/libs/eigen/test/sparse_ref.cpp @@ -0,0 +1,139 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 20015 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// This unit test cannot be easily written to work with EIGEN_DEFAULT_TO_ROW_MAJOR +#ifdef EIGEN_DEFAULT_TO_ROW_MAJOR +#undef EIGEN_DEFAULT_TO_ROW_MAJOR +#endif + +static long int nb_temporaries; + +inline void on_temporary_creation() { + // here's a great place to set a breakpoint when debugging failures in this test! + nb_temporaries++; +} + +#define EIGEN_SPARSE_CREATE_TEMPORARY_PLUGIN { on_temporary_creation(); } + +#include "main.h" +#include + +#define VERIFY_EVALUATION_COUNT(XPR,N) {\ + nb_temporaries = 0; \ + CALL_SUBTEST( XPR ); \ + if(nb_temporaries!=N) std::cerr << "nb_temporaries == " << nb_temporaries << "\n"; \ + VERIFY( (#XPR) && nb_temporaries==N ); \ + } + +template void check_const_correctness(const PlainObjectType&) +{ + // verify that ref-to-const don't have LvalueBit + typedef typename internal::add_const::type ConstPlainObjectType; + VERIFY( !(internal::traits >::Flags & LvalueBit) ); + VERIFY( !(internal::traits >::Flags & LvalueBit) ); + VERIFY( !(Ref::Flags & LvalueBit) ); + VERIFY( !(Ref::Flags & LvalueBit) ); +} + +template +EIGEN_DONT_INLINE void call_ref_1(Ref > a, const B &b) { VERIFY_IS_EQUAL(a.toDense(),b.toDense()); } + +template +EIGEN_DONT_INLINE void call_ref_2(const Ref >& a, const B &b) { VERIFY_IS_EQUAL(a.toDense(),b.toDense()); } + +template +EIGEN_DONT_INLINE void call_ref_3(const Ref, StandardCompressedFormat>& a, const B &b) { + VERIFY(a.isCompressed()); + VERIFY_IS_EQUAL(a.toDense(),b.toDense()); +} + +template +EIGEN_DONT_INLINE void call_ref_4(Ref > a, const B &b) { VERIFY_IS_EQUAL(a.toDense(),b.toDense()); } + +template +EIGEN_DONT_INLINE void call_ref_5(const Ref >& a, const B &b) { VERIFY_IS_EQUAL(a.toDense(),b.toDense()); } + +void call_ref() +{ + SparseMatrix A = MatrixXf::Random(10,10).sparseView(0.5,1); + SparseMatrix B = MatrixXf::Random(10,10).sparseView(0.5,1); + SparseMatrix C = MatrixXf::Random(10,10).sparseView(0.5,1); + C.reserve(VectorXi::Constant(C.outerSize(), 2)); + const SparseMatrix& Ac(A); + Block > Ab(A,0,1, 3,3); + const Block > Abc(A,0,1,3,3); + SparseVector vc = VectorXf::Random(10).sparseView(0.5,1); + SparseVector vr = VectorXf::Random(10).sparseView(0.5,1); + SparseMatrix AA = A*A; + + + VERIFY_EVALUATION_COUNT( call_ref_1(A, A), 0); +// VERIFY_EVALUATION_COUNT( call_ref_1(Ac, Ac), 0); // does not compile on purpose + VERIFY_EVALUATION_COUNT( call_ref_2(A, A), 0); + VERIFY_EVALUATION_COUNT( call_ref_3(A, A), 0); + VERIFY_EVALUATION_COUNT( call_ref_2(A.transpose(), A.transpose()), 1); + VERIFY_EVALUATION_COUNT( call_ref_3(A.transpose(), A.transpose()), 1); + VERIFY_EVALUATION_COUNT( call_ref_2(Ac,Ac), 0); + VERIFY_EVALUATION_COUNT( call_ref_3(Ac,Ac), 0); + VERIFY_EVALUATION_COUNT( call_ref_2(A+A,2*Ac), 1); + VERIFY_EVALUATION_COUNT( call_ref_3(A+A,2*Ac), 1); + VERIFY_EVALUATION_COUNT( call_ref_2(B, B), 1); + VERIFY_EVALUATION_COUNT( call_ref_3(B, B), 1); + VERIFY_EVALUATION_COUNT( call_ref_2(B.transpose(), B.transpose()), 0); + VERIFY_EVALUATION_COUNT( call_ref_3(B.transpose(), B.transpose()), 0); + VERIFY_EVALUATION_COUNT( call_ref_2(A*A, AA), 3); + VERIFY_EVALUATION_COUNT( call_ref_3(A*A, AA), 3); + + VERIFY(!C.isCompressed()); + VERIFY_EVALUATION_COUNT( call_ref_3(C, C), 1); + + Ref > Ar(A); + VERIFY_IS_APPROX(Ar+Ar, A+A); + VERIFY_EVALUATION_COUNT( call_ref_1(Ar, A), 0); + VERIFY_EVALUATION_COUNT( call_ref_2(Ar, A), 0); + + Ref > Br(B); + VERIFY_EVALUATION_COUNT( call_ref_1(Br.transpose(), Br.transpose()), 0); + VERIFY_EVALUATION_COUNT( call_ref_2(Br, Br), 1); + VERIFY_EVALUATION_COUNT( call_ref_2(Br.transpose(), Br.transpose()), 0); + + Ref > Arc(A); +// VERIFY_EVALUATION_COUNT( call_ref_1(Arc, Arc), 0); // does not compile on purpose + VERIFY_EVALUATION_COUNT( call_ref_2(Arc, Arc), 0); + + VERIFY_EVALUATION_COUNT( call_ref_2(A.middleCols(1,3), A.middleCols(1,3)), 0); + + VERIFY_EVALUATION_COUNT( call_ref_2(A.col(2), A.col(2)), 0); + VERIFY_EVALUATION_COUNT( call_ref_2(vc, vc), 0); + VERIFY_EVALUATION_COUNT( call_ref_2(vr.transpose(), vr.transpose()), 0); + VERIFY_EVALUATION_COUNT( call_ref_2(vr, vr.transpose()), 0); + + VERIFY_EVALUATION_COUNT( call_ref_2(A.block(1,1,3,3), A.block(1,1,3,3)), 1); // should be 0 (allocate starts/nnz only) + + VERIFY_EVALUATION_COUNT( call_ref_4(vc, vc), 0); + VERIFY_EVALUATION_COUNT( call_ref_4(vr, vr.transpose()), 0); + VERIFY_EVALUATION_COUNT( call_ref_5(vc, vc), 0); + VERIFY_EVALUATION_COUNT( call_ref_5(vr, vr.transpose()), 0); + VERIFY_EVALUATION_COUNT( call_ref_4(A.col(2), A.col(2)), 0); + VERIFY_EVALUATION_COUNT( call_ref_5(A.col(2), A.col(2)), 0); + // VERIFY_EVALUATION_COUNT( call_ref_4(A.row(2), A.row(2).transpose()), 1); // does not compile on purpose + VERIFY_EVALUATION_COUNT( call_ref_5(A.row(2), A.row(2).transpose()), 1); +} + +void test_sparse_ref() +{ + for(int i = 0; i < g_repeat; i++) { + CALL_SUBTEST_1( check_const_correctness(SparseMatrix()) ); + CALL_SUBTEST_1( check_const_correctness(SparseMatrix()) ); + CALL_SUBTEST_2( call_ref() ); + + CALL_SUBTEST_3( check_const_correctness(SparseVector()) ); + CALL_SUBTEST_3( check_const_correctness(SparseVector()) ); + } +} diff --git a/ground/gcs/src/libs/eigen/test/sparse_solver.h b/ground/gcs/src/libs/eigen/test/sparse_solver.h index e1619d62a3..5145bc3eb5 100644 --- a/ground/gcs/src/libs/eigen/test/sparse_solver.h +++ b/ground/gcs/src/libs/eigen/test/sparse_solver.h @@ -9,68 +9,123 @@ #include "sparse.h" #include +#include + +template +void solve_with_guess(IterativeSolverBase& solver, const MatrixBase& b, const Guess& g, Result &x) { + if(internal::random()) + { + // With a temporary through evaluator + x = solver.derived().solveWithGuess(b,g) + Result::Zero(x.rows(), x.cols()); + } + else + { + // direct evaluation within x through Assignment + x = solver.derived().solveWithGuess(b.derived(),g); + } +} + +template +void solve_with_guess(SparseSolverBase& solver, const MatrixBase& b, const Guess& , Result& x) { + if(internal::random()) + x = solver.derived().solve(b) + Result::Zero(x.rows(), x.cols()); + else + x = solver.derived().solve(b); +} + +template +void solve_with_guess(SparseSolverBase& solver, const SparseMatrixBase& b, const Guess& , Result& x) { + x = solver.derived().solve(b); +} template void check_sparse_solving(Solver& solver, const typename Solver::MatrixType& A, const Rhs& b, const DenseMat& dA, const DenseRhs& db) { typedef typename Solver::MatrixType Mat; typedef typename Mat::Scalar Scalar; + typedef typename Mat::StorageIndex StorageIndex; - DenseRhs refX = dA.lu().solve(db); + DenseRhs refX = dA.householderQr().solve(db); { - Rhs x(b.rows(), b.cols()); + Rhs x(A.cols(), b.cols()); Rhs oldb = b; solver.compute(A); if (solver.info() != Success) { - std::cerr << "sparse solver testing: factorization failed (check_sparse_solving)\n"; - exit(0); - return; + std::cerr << "ERROR | sparse solver testing, factorization failed (" << typeid(Solver).name() << ")\n"; + VERIFY(solver.info() == Success); } x = solver.solve(b); if (solver.info() != Success) { - std::cerr << "sparse solver testing: solving failed\n"; + std::cerr << "WARNING | sparse solver testing: solving failed (" << typeid(Solver).name() << ")\n"; return; } VERIFY(oldb.isApprox(b) && "sparse solver testing: the rhs should not be modified!"); + VERIFY(x.isApprox(refX,test_precision())); + x.setZero(); + solve_with_guess(solver, b, x, x); + VERIFY(solver.info() == Success && "solving failed when using analyzePattern/factorize API"); + VERIFY(oldb.isApprox(b) && "sparse solver testing: the rhs should not be modified!"); VERIFY(x.isApprox(refX,test_precision())); + x.setZero(); // test the analyze/factorize API solver.analyzePattern(A); solver.factorize(A); - if (solver.info() != Success) - { - std::cerr << "sparse solver testing: factorization failed (check_sparse_solving)\n"; - exit(0); - return; - } + VERIFY(solver.info() == Success && "factorization failed when using analyzePattern/factorize API"); x = solver.solve(b); - if (solver.info() != Success) - { - std::cerr << "sparse solver testing: solving failed\n"; - return; - } + VERIFY(solver.info() == Success && "solving failed when using analyzePattern/factorize API"); VERIFY(oldb.isApprox(b) && "sparse solver testing: the rhs should not be modified!"); - VERIFY(x.isApprox(refX,test_precision())); - } - - // test dense Block as the result and rhs: - { - DenseRhs x(db.rows(), db.cols()); - DenseRhs oldb(db); + x.setZero(); - x.block(0,0,x.rows(),x.cols()) = solver.solve(db.block(0,0,db.rows(),db.cols())); - VERIFY(oldb.isApprox(db) && "sparse solver testing: the rhs should not be modified!"); - VERIFY(x.isApprox(refX,test_precision())); + // test with Map + MappedSparseMatrix Am(A.rows(), A.cols(), A.nonZeros(), const_cast(A.outerIndexPtr()), const_cast(A.innerIndexPtr()), const_cast(A.valuePtr())); + solver.compute(Am); + VERIFY(solver.info() == Success && "factorization failed when using Map"); + DenseRhs dx(refX); + dx.setZero(); + Map xm(dx.data(), dx.rows(), dx.cols()); + Map bm(db.data(), db.rows(), db.cols()); + xm = solver.solve(bm); + VERIFY(solver.info() == Success && "solving failed when using Map"); + VERIFY(oldb.isApprox(bm) && "sparse solver testing: the rhs should not be modified!"); + VERIFY(xm.isApprox(refX,test_precision())); } - + // if not too large, do some extra check: if(A.rows()<2000) { + // test initialization ctor + { + Rhs x(b.rows(), b.cols()); + Solver solver2(A); + VERIFY(solver2.info() == Success); + x = solver2.solve(b); + VERIFY(x.isApprox(refX,test_precision())); + } + + // test dense Block as the result and rhs: + { + DenseRhs x(refX.rows(), refX.cols()); + DenseRhs oldb(db); + x.setZero(); + x.block(0,0,x.rows(),x.cols()) = solver.solve(db.block(0,0,db.rows(),db.cols())); + VERIFY(oldb.isApprox(db) && "sparse solver testing: the rhs should not be modified!"); + VERIFY(x.isApprox(refX,test_precision())); + } + + // test uncompressed inputs + { + Mat A2 = A; + A2.reserve((ArrayXf::Random(A.outerSize())+2).template cast().eval()); + solver.compute(A2); + Rhs x = solver.solve(b); + VERIFY(x.isApprox(refX,test_precision())); + } // test expression as input { @@ -86,41 +141,35 @@ void check_sparse_solving(Solver& solver, const typename Solver::MatrixType& A, } template -void check_sparse_solving_real_cases(Solver& solver, const typename Solver::MatrixType& A, const Rhs& b, const Rhs& refX) +void check_sparse_solving_real_cases(Solver& solver, const typename Solver::MatrixType& A, const Rhs& b, const typename Solver::MatrixType& fullA, const Rhs& refX) { typedef typename Solver::MatrixType Mat; typedef typename Mat::Scalar Scalar; typedef typename Mat::RealScalar RealScalar; - Rhs x(b.rows(), b.cols()); - + Rhs x(A.cols(), b.cols()); + solver.compute(A); if (solver.info() != Success) { - std::cerr << "sparse solver testing: factorization failed (check_sparse_solving_real_cases)\n"; - exit(0); - return; + std::cerr << "ERROR | sparse solver testing, factorization failed (" << typeid(Solver).name() << ")\n"; + VERIFY(solver.info() == Success); } x = solver.solve(b); + if (solver.info() != Success) { - std::cerr << "sparse solver testing: solving failed\n"; + std::cerr << "WARNING | sparse solver testing, solving failed (" << typeid(Solver).name() << ")\n"; return; } - RealScalar res_error; - // Compute the norm of the relative error - if(refX.size() != 0) - res_error = (refX - x).norm()/refX.norm(); - else - { - // Compute the relative residual norm - res_error = (b - A * x).norm()/b.norm(); - } - if (res_error > test_precision() ){ - std::cerr << "Test " << g_test_stack.back() << " failed in "EI_PP_MAKE_STRING(__FILE__) - << " (" << EI_PP_MAKE_STRING(__LINE__) << ")" << std::endl << std::endl; - abort(); + RealScalar res_error = (fullA*x-b).norm()/b.norm(); + VERIFY( (res_error <= test_precision() ) && "sparse solver failed without noticing it"); + + + if(refX.size() != 0 && (refX - x).norm()/refX.norm() > test_precision()) + { + std::cerr << "WARNING | found solution is different from the provided reference one\n"; } } @@ -133,7 +182,7 @@ void check_sparse_determinant(Solver& solver, const typename Solver::MatrixType& solver.compute(A); if (solver.info() != Success) { - std::cerr << "sparse solver testing: factorization failed (check_sparse_determinant)\n"; + std::cerr << "WARNING | sparse solver testing: factorization failed (check_sparse_determinant)\n"; return; } @@ -150,7 +199,7 @@ void check_sparse_abs_determinant(Solver& solver, const typename Solver::MatrixT solver.compute(A); if (solver.info() != Success) { - std::cerr << "sparse solver testing: factorization failed (check_sparse_abs_determinant)\n"; + std::cerr << "WARNING | sparse solver testing: factorization failed (check_sparse_abs_determinant)\n"; return; } @@ -197,13 +246,33 @@ inline std::string get_matrixfolder() mat_folder = mat_folder + static_cast("/real/"); return mat_folder; } +std::string sym_to_string(int sym) +{ + if(sym==Symmetric) return "Symmetric "; + if(sym==SPD) return "SPD "; + return ""; +} +template +std::string solver_stats(const IterativeSolverBase &solver) +{ + std::stringstream ss; + ss << solver.iterations() << " iters, error: " << solver.error(); + return ss.str(); +} +template +std::string solver_stats(const SparseSolverBase &/*solver*/) +{ + return ""; +} #endif -template void check_sparse_spd_solving(Solver& solver) +template void check_sparse_spd_solving(Solver& solver, int maxSize = 300, int maxRealWorldSize = 100000) { typedef typename Solver::MatrixType Mat; typedef typename Mat::Scalar Scalar; - typedef SparseMatrix SpMat; + typedef typename Mat::StorageIndex StorageIndex; + typedef SparseMatrix SpMat; + typedef SparseVector SpVec; typedef Matrix DenseMatrix; typedef Matrix DenseVector; @@ -211,7 +280,7 @@ template void check_sparse_spd_solving(Solver& solver) Mat A, halfA; DenseMatrix dA; for (int i = 0; i < g_repeat; i++) { - int size = generate_sparse_spd_problem(solver, A, halfA, dA); + int size = generate_sparse_spd_problem(solver, A, halfA, dA, maxSize); // generate the right hand sides int rhsCols = internal::random(1,16); @@ -220,13 +289,17 @@ template void check_sparse_spd_solving(Solver& solver) DenseVector b = DenseVector::Random(size); DenseMatrix dB(size,rhsCols); initSparse(density, dB, B, ForceNonZeroDiag); + SpVec c = B.col(0); + DenseVector dc = dB.col(0); - check_sparse_solving(solver, A, b, dA, b); - check_sparse_solving(solver, halfA, b, dA, b); - check_sparse_solving(solver, A, dB, dA, dB); - check_sparse_solving(solver, halfA, dB, dA, dB); - check_sparse_solving(solver, A, B, dA, dB); - check_sparse_solving(solver, halfA, B, dA, dB); + CALL_SUBTEST( check_sparse_solving(solver, A, b, dA, b) ); + CALL_SUBTEST( check_sparse_solving(solver, halfA, b, dA, b) ); + CALL_SUBTEST( check_sparse_solving(solver, A, dB, dA, dB) ); + CALL_SUBTEST( check_sparse_solving(solver, halfA, dB, dA, dB) ); + CALL_SUBTEST( check_sparse_solving(solver, A, B, dA, dB) ); + CALL_SUBTEST( check_sparse_solving(solver, halfA, B, dA, dB) ); + CALL_SUBTEST( check_sparse_solving(solver, A, c, dA, dc) ); + CALL_SUBTEST( check_sparse_solving(solver, halfA, c, dA, dc) ); // check only once if(i==0) @@ -237,25 +310,44 @@ template void check_sparse_spd_solving(Solver& solver) } // First, get the folder -#ifdef TEST_REAL_CASES - if (internal::is_same::value - || internal::is_same >::value) - return ; - - std::string mat_folder = get_matrixfolder(); - MatrixMarketIterator it(mat_folder); - for (; it; ++it) +#ifdef TEST_REAL_CASES + // Test real problems with double precision only + if (internal::is_same::Real, double>::value) { - if (it.sym() == SPD){ - Mat halfA; - PermutationMatrix pnull; - halfA.template selfadjointView() = it.matrix().template triangularView().twistedBy(pnull); - - std::cout<< " ==== SOLVING WITH MATRIX " << it.matname() << " ==== \n"; - check_sparse_solving_real_cases(solver, it.matrix(), it.rhs(), it.refX()); - check_sparse_solving_real_cases(solver, halfA, it.rhs(), it.refX()); + std::string mat_folder = get_matrixfolder(); + MatrixMarketIterator it(mat_folder); + for (; it; ++it) + { + if (it.sym() == SPD){ + A = it.matrix(); + if(A.diagonal().size() <= maxRealWorldSize) + { + DenseVector b = it.rhs(); + DenseVector refX = it.refX(); + PermutationMatrix pnull; + halfA.resize(A.rows(), A.cols()); + if(Solver::UpLo == (Lower|Upper)) + halfA = A; + else + halfA.template selfadjointView() = A.template triangularView().twistedBy(pnull); + + std::cout << "INFO | Testing " << sym_to_string(it.sym()) << "sparse problem " << it.matname() + << " (" << A.rows() << "x" << A.cols() << ") using " << typeid(Solver).name() << "..." << std::endl; + CALL_SUBTEST( check_sparse_solving_real_cases(solver, A, b, A, refX) ); + std::string stats = solver_stats(solver); + if(stats.size()>0) + std::cout << "INFO | " << stats << std::endl; + CALL_SUBTEST( check_sparse_solving_real_cases(solver, halfA, b, A, refX) ); + } + else + { + std::cout << "INFO | Skip sparse problem \"" << it.matname() << "\" (too large)" << std::endl; + } + } } } +#else + EIGEN_UNUSED_VARIABLE(maxRealWorldSize); #endif } @@ -277,37 +369,39 @@ template void check_sparse_spd_determinant(Solver& solver) } template -int generate_sparse_square_problem(Solver&, typename Solver::MatrixType& A, DenseMat& dA, int maxSize = 300) +Index generate_sparse_square_problem(Solver&, typename Solver::MatrixType& A, DenseMat& dA, int maxSize = 300, int options = ForceNonZeroDiag) { typedef typename Solver::MatrixType Mat; typedef typename Mat::Scalar Scalar; - int size = internal::random(1,maxSize); + Index size = internal::random(1,maxSize); double density = (std::max)(8./(size*size), 0.01); A.resize(size,size); dA.resize(size,size); - initSparse(density, dA, A, ForceNonZeroDiag); + initSparse(density, dA, A, options); return size; } struct prune_column { - int m_col; - prune_column(int col) : m_col(col) {} + Index m_col; + prune_column(Index col) : m_col(col) {} template - bool operator()(int, int col, const Scalar&) const { + bool operator()(Index, Index col, const Scalar&) const { return col != m_col; } }; -template void check_sparse_square_solving(Solver& solver, bool checkDeficient = false) + +template void check_sparse_square_solving(Solver& solver, int maxSize = 300, int maxRealWorldSize = 100000, bool checkDeficient = false) { typedef typename Solver::MatrixType Mat; typedef typename Mat::Scalar Scalar; - typedef SparseMatrix SpMat; + typedef SparseMatrix SpMat; + typedef SparseVector SpVec; typedef Matrix DenseMatrix; typedef Matrix DenseVector; @@ -316,7 +410,7 @@ template void check_sparse_square_solving(Solver& solver, bool Mat A; DenseMatrix dA; for (int i = 0; i < g_repeat; i++) { - int size = generate_sparse_square_problem(solver, A, dA); + Index size = generate_sparse_square_problem(solver, A, dA, maxSize); A.makeCompressed(); DenseVector b = DenseVector::Random(size); @@ -325,9 +419,12 @@ template void check_sparse_square_solving(Solver& solver, bool double density = (std::max)(8./(size*rhsCols), 0.1); initSparse(density, dB, B, ForceNonZeroDiag); B.makeCompressed(); - check_sparse_solving(solver, A, b, dA, b); - check_sparse_solving(solver, A, dB, dA, dB); - check_sparse_solving(solver, A, B, dA, dB); + SpVec c = B.col(0); + DenseVector dc = dB.col(0); + CALL_SUBTEST(check_sparse_solving(solver, A, b, dA, b)); + CALL_SUBTEST(check_sparse_solving(solver, A, dB, dA, dB)); + CALL_SUBTEST(check_sparse_solving(solver, A, B, dA, dB)); + CALL_SUBTEST(check_sparse_solving(solver, A, c, dA, dc)); // check only once if(i==0) @@ -337,7 +434,7 @@ template void check_sparse_square_solving(Solver& solver, bool } // regression test for Bug 792 (structurally rank deficient matrices): if(checkDeficient && size>1) { - int col = internal::random(0,size-1); + Index col = internal::random(0,int(size-1)); A.prune(prune_column(col)); solver.compute(A); VERIFY_IS_EQUAL(solver.info(), NumericalIssue); @@ -346,17 +443,33 @@ template void check_sparse_square_solving(Solver& solver, bool // First, get the folder #ifdef TEST_REAL_CASES - if (internal::is_same::value - || internal::is_same >::value) - return ; - - std::string mat_folder = get_matrixfolder(); - MatrixMarketIterator it(mat_folder); - for (; it; ++it) + // Test real problems with double precision only + if (internal::is_same::Real, double>::value) { - std::cout<< " ==== SOLVING WITH MATRIX " << it.matname() << " ==== \n"; - check_sparse_solving_real_cases(solver, it.matrix(), it.rhs(), it.refX()); + std::string mat_folder = get_matrixfolder(); + MatrixMarketIterator it(mat_folder); + for (; it; ++it) + { + A = it.matrix(); + if(A.diagonal().size() <= maxRealWorldSize) + { + DenseVector b = it.rhs(); + DenseVector refX = it.refX(); + std::cout << "INFO | Testing " << sym_to_string(it.sym()) << "sparse problem " << it.matname() + << " (" << A.rows() << "x" << A.cols() << ") using " << typeid(Solver).name() << "..." << std::endl; + CALL_SUBTEST(check_sparse_solving_real_cases(solver, A, b, A, refX)); + std::string stats = solver_stats(solver); + if(stats.size()>0) + std::cout << "INFO | " << stats << std::endl; + } + else + { + std::cout << "INFO | SKIP sparse problem \"" << it.matname() << "\" (too large)" << std::endl; + } + } } +#else + EIGEN_UNUSED_VARIABLE(maxRealWorldSize); #endif } @@ -366,13 +479,20 @@ template void check_sparse_square_determinant(Solver& solver) typedef typename Solver::MatrixType Mat; typedef typename Mat::Scalar Scalar; typedef Matrix DenseMatrix; - - // generate the problem - Mat A; - DenseMatrix dA; - generate_sparse_square_problem(solver, A, dA, 30); - A.makeCompressed(); + for (int i = 0; i < g_repeat; i++) { + // generate the problem + Mat A; + DenseMatrix dA; + + int size = internal::random(1,30); + dA.setRandom(size,size); + + dA = (dA.array().abs()<0.3).select(0,dA); + dA.diagonal() = (dA.diagonal().array()==0).select(1,dA.diagonal()); + A = dA.sparseView(); + A.makeCompressed(); + check_sparse_determinant(solver, A, dA); } } @@ -383,13 +503,63 @@ template void check_sparse_square_abs_determinant(Solver& solve typedef typename Mat::Scalar Scalar; typedef Matrix DenseMatrix; - // generate the problem - Mat A; - DenseMatrix dA; - generate_sparse_square_problem(solver, A, dA, 30); - A.makeCompressed(); for (int i = 0; i < g_repeat; i++) { + // generate the problem + Mat A; + DenseMatrix dA; + generate_sparse_square_problem(solver, A, dA, 30); + A.makeCompressed(); check_sparse_abs_determinant(solver, A, dA); } } +template +void generate_sparse_leastsquare_problem(Solver&, typename Solver::MatrixType& A, DenseMat& dA, int maxSize = 300, int options = ForceNonZeroDiag) +{ + typedef typename Solver::MatrixType Mat; + typedef typename Mat::Scalar Scalar; + + int rows = internal::random(1,maxSize); + int cols = internal::random(1,rows); + double density = (std::max)(8./(rows*cols), 0.01); + + A.resize(rows,cols); + dA.resize(rows,cols); + + initSparse(density, dA, A, options); +} + +template void check_sparse_leastsquare_solving(Solver& solver) +{ + typedef typename Solver::MatrixType Mat; + typedef typename Mat::Scalar Scalar; + typedef SparseMatrix SpMat; + typedef Matrix DenseMatrix; + typedef Matrix DenseVector; + + int rhsCols = internal::random(1,16); + + Mat A; + DenseMatrix dA; + for (int i = 0; i < g_repeat; i++) { + generate_sparse_leastsquare_problem(solver, A, dA); + + A.makeCompressed(); + DenseVector b = DenseVector::Random(A.rows()); + DenseMatrix dB(A.rows(),rhsCols); + SpMat B(A.rows(),rhsCols); + double density = (std::max)(8./(A.rows()*rhsCols), 0.1); + initSparse(density, dB, B, ForceNonZeroDiag); + B.makeCompressed(); + check_sparse_solving(solver, A, b, dA, b); + check_sparse_solving(solver, A, dB, dA, dB); + check_sparse_solving(solver, A, B, dA, dB); + + // check only once + if(i==0) + { + b = DenseVector::Zero(A.rows()); + check_sparse_solving(solver, A, b, dA, b); + } + } +} diff --git a/ground/gcs/src/libs/eigen/test/sparse_vector.cpp b/ground/gcs/src/libs/eigen/test/sparse_vector.cpp index 0c94768034..b3e1dda259 100644 --- a/ground/gcs/src/libs/eigen/test/sparse_vector.cpp +++ b/ground/gcs/src/libs/eigen/test/sparse_vector.cpp @@ -9,22 +9,22 @@ #include "sparse.h" -template void sparse_vector(int rows, int cols) +template void sparse_vector(int rows, int cols) { double densityMat = (std::max)(8./(rows*cols), 0.01); - double densityVec = (std::max)(8./float(rows), 0.1); + double densityVec = (std::max)(8./(rows), 0.1); typedef Matrix DenseMatrix; typedef Matrix DenseVector; - typedef SparseVector SparseVectorType; - typedef SparseMatrix SparseMatrixType; + typedef SparseVector SparseVectorType; + typedef SparseMatrix SparseMatrixType; Scalar eps = 1e-6; SparseMatrixType m1(rows,rows); SparseVectorType v1(rows), v2(rows), v3(rows); DenseMatrix refM1 = DenseMatrix::Zero(rows, rows); DenseVector refV1 = DenseVector::Random(rows), - refV2 = DenseVector::Random(rows), - refV3 = DenseVector::Random(rows); + refV2 = DenseVector::Random(rows), + refV3 = DenseVector::Random(rows); std::vector zerocoords, nonzerocoords; initSparse(densityVec, refV1, v1, &zerocoords, &nonzerocoords); @@ -52,6 +52,20 @@ template void sparse_vector(int rows, int cols) } } VERIFY_IS_APPROX(v1, refV1); + + // test coeffRef with reallocation + { + SparseVectorType v4(rows); + DenseVector v5 = DenseVector::Zero(rows); + for(int k=0; k(0,rows-1); + Scalar v = internal::random(); + v4.coeffRef(i) += v; + v5.coeffRef(i) += v; + } + VERIFY_IS_APPROX(v4,v5); + } v1.coeffRef(nonzerocoords[0]) = Scalar(5); refV1.coeffRef(nonzerocoords[0]) = Scalar(5); @@ -71,9 +85,12 @@ template void sparse_vector(int rows, int cols) VERIFY_IS_APPROX(v1.dot(v2), refV1.dot(refV2)); VERIFY_IS_APPROX(v1.dot(refV2), refV1.dot(refV2)); + VERIFY_IS_APPROX(m1*v2, refM1*refV2); VERIFY_IS_APPROX(v1.dot(m1*v2), refV1.dot(refM1*refV2)); - int i = internal::random(0,rows-1); - VERIFY_IS_APPROX(v1.dot(m1.col(i)), refV1.dot(refM1.col(i))); + { + int i = internal::random(0,rows-1); + VERIFY_IS_APPROX(v1.dot(m1.col(i)), refV1.dot(refM1.col(i))); + } VERIFY_IS_APPROX(v1.squaredNorm(), refV1.squaredNorm()); @@ -96,15 +113,51 @@ template void sparse_vector(int rows, int cols) VERIFY_IS_APPROX(refV3 = v1.transpose(),v1.toDense()); VERIFY_IS_APPROX(DenseVector(v1),v1.toDense()); + // test conservative resize + { + std::vector inc; + if(rows > 3) + inc.push_back(-3); + inc.push_back(0); + inc.push_back(3); + inc.push_back(1); + inc.push_back(10); + + for(std::size_t i = 0; i< inc.size(); i++) { + StorageIndex incRows = inc[i]; + SparseVectorType vec1(rows); + DenseVector refVec1 = DenseVector::Zero(rows); + initSparse(densityVec, refVec1, vec1); + + vec1.conservativeResize(rows+incRows); + refVec1.conservativeResize(rows+incRows); + if (incRows > 0) refVec1.tail(incRows).setZero(); + + VERIFY_IS_APPROX(vec1, refVec1); + + // Insert new values + if (incRows > 0) + vec1.insert(vec1.rows()-1) = refVec1(refVec1.rows()-1) = 1; + + VERIFY_IS_APPROX(vec1, refVec1); + } + } + } void test_sparse_vector() { for(int i = 0; i < g_repeat; i++) { + int r = Eigen::internal::random(1,500), c = Eigen::internal::random(1,500); + if(Eigen::internal::random(0,4) == 0) { + r = c; // check square matrices in 25% of tries + } + EIGEN_UNUSED_VARIABLE(r+c); + CALL_SUBTEST_1(( sparse_vector(8, 8) )); - CALL_SUBTEST_2(( sparse_vector, int>(16, 16) )); - CALL_SUBTEST_1(( sparse_vector(299, 535) )); - CALL_SUBTEST_1(( sparse_vector(299, 535) )); + CALL_SUBTEST_2(( sparse_vector, int>(r, c) )); + CALL_SUBTEST_1(( sparse_vector(r, c) )); + CALL_SUBTEST_1(( sparse_vector(r, c) )); } } diff --git a/ground/gcs/src/libs/eigen/test/sparselu.cpp b/ground/gcs/src/libs/eigen/test/sparselu.cpp index b3d67aea88..bd000baf10 100644 --- a/ground/gcs/src/libs/eigen/test/sparselu.cpp +++ b/ground/gcs/src/libs/eigen/test/sparselu.cpp @@ -3,25 +3,9 @@ // // Copyright (C) 2012 Désiré Nuentsa-Wakam // -// Eigen is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 3 of the License, or (at your option) any later version. -// -// Alternatively, 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 2 of -// the License, or (at your option) any later version. -// -// Eigen 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 Lesser General Public License or the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License and a copy of the GNU General Public License along with -// Eigen. If not, see . - +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. // SparseLU solve does not accept column major matrices for the destination. // However, as expected, the generic check_sparse_square_solving routines produces row-major @@ -41,9 +25,9 @@ template void test_sparselu_T() SparseLU, AMDOrdering > sparselu_amd; SparseLU, NaturalOrdering > sparselu_natural; - check_sparse_square_solving(sparselu_colamd, true); - check_sparse_square_solving(sparselu_amd, true); - check_sparse_square_solving(sparselu_natural,true); + check_sparse_square_solving(sparselu_colamd, 300, 100000, true); + check_sparse_square_solving(sparselu_amd, 300, 10000, true); + check_sparse_square_solving(sparselu_natural, 300, 2000, true); check_sparse_square_abs_determinant(sparselu_colamd); check_sparse_square_abs_determinant(sparselu_amd); diff --git a/ground/gcs/src/libs/eigen/test/sparseqr.cpp b/ground/gcs/src/libs/eigen/test/sparseqr.cpp index 451c0e7f82..e8605fd210 100644 --- a/ground/gcs/src/libs/eigen/test/sparseqr.cpp +++ b/ground/gcs/src/libs/eigen/test/sparseqr.cpp @@ -10,11 +10,12 @@ #include template -int generate_sparse_rectangular_problem(MatrixType& A, DenseMat& dA, int maxRows = 300) +int generate_sparse_rectangular_problem(MatrixType& A, DenseMat& dA, int maxRows = 300, int maxCols = 150) { + eigen_assert(maxRows >= maxCols); typedef typename MatrixType::Scalar Scalar; int rows = internal::random(1,maxRows); - int cols = internal::random(1,rows); + int cols = internal::random(1,maxCols); double density = (std::max)(8./(rows*cols), 0.01); A.resize(rows,cols); @@ -53,7 +54,7 @@ template void test_sparseqr_scalar() b = dA * DenseVector::Random(A.cols()); solver.compute(A); - if(internal::random(0,1)>0.5) + if(internal::random(0,1)>0.5f) solver.factorize(A); // this checks that calling analyzePattern is not needed if the pattern do not change. if (solver.info() != Success) { @@ -88,6 +89,11 @@ template void test_sparseqr_scalar() QtQ = Q * Q.adjoint(); idM.resize(Q.rows(), Q.rows()); idM.setIdentity(); VERIFY(idM.isApprox(QtQ)); + + // Q to dense + DenseMat dQ; + dQ = solver.matrixQ(); + VERIFY_IS_APPROX(Q, dQ); } void test_sparseqr() { diff --git a/ground/gcs/src/libs/eigen/test/spqr_support.cpp b/ground/gcs/src/libs/eigen/test/spqr_support.cpp index b8980e0816..81e63b6a57 100644 --- a/ground/gcs/src/libs/eigen/test/spqr_support.cpp +++ b/ground/gcs/src/libs/eigen/test/spqr_support.cpp @@ -5,6 +5,8 @@ // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed + +#define EIGEN_NO_DEBUG_SMALL_PRODUCT_BLOCKS #include "sparse.h" #include @@ -18,8 +20,8 @@ int generate_sparse_rectangular_problem(MatrixType& A, DenseMat& dA, int maxRows int cols = internal::random(1,rows); double density = (std::max)(8./(rows*cols), 0.01); - A.resize(rows,rows); - dA.resize(rows,rows); + A.resize(rows,cols); + dA.resize(rows,cols); initSparse(density, dA, A,ForceNonZeroDiag); A.makeCompressed(); return rows; @@ -35,7 +37,7 @@ template void test_spqr_scalar() SPQR solver; generate_sparse_rectangular_problem(A,dA); - int m = A.rows(); + Index m = A.rows(); b = DenseVector::Random(m); solver.compute(A); if (solver.info() != Success) diff --git a/ground/gcs/src/libs/eigen/test/stable_norm.cpp b/ground/gcs/src/libs/eigen/test/stable_norm.cpp index 231dd9189d..c3eb5ff313 100644 --- a/ground/gcs/src/libs/eigen/test/stable_norm.cpp +++ b/ground/gcs/src/libs/eigen/test/stable_norm.cpp @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2009 Gael Guennebaud +// Copyright (C) 2009-2014 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -9,14 +9,6 @@ #include "main.h" -// workaround aggressive optimization in ICC -template EIGEN_DONT_INLINE T sub(T a, T b) { return a - b; } - -template bool isFinite(const T& x) -{ - return isNotNaN(sub(x,x)); -} - template EIGEN_DONT_INLINE T copy(const T& x) { return x; @@ -32,6 +24,8 @@ template void stable_norm(const MatrixType& m) typedef typename MatrixType::Index Index; typedef typename MatrixType::Scalar Scalar; typedef typename NumTraits::Real RealScalar; + + bool complex_real_product_ok = true; // Check the basic machine-dependent constants. { @@ -44,6 +38,16 @@ template void stable_norm(const MatrixType& m) VERIFY( (!(iemin > 1 - 2*it || 1+it>iemax || (it==2 && ibeta<5) || (it<=4 && ibeta <= 3 ) || it<2)) && "the stable norm algorithm cannot be guaranteed on this computer"); + + Scalar inf = std::numeric_limits::infinity(); + if(NumTraits::IsComplex && (numext::isnan)(inf*RealScalar(1)) ) + { + complex_real_product_ok = false; + static bool first = true; + if(first) + std::cerr << "WARNING: compiler mess up complex*real product, " << inf << " * " << 1.0 << " = " << inf*RealScalar(1) << std::endl; + first = false; + } } @@ -76,19 +80,19 @@ template void stable_norm(const MatrixType& m) RealScalar size = static_cast(m.size()); - // test isFinite - VERIFY(!isFinite( std::numeric_limits::infinity())); - VERIFY(!isFinite(sqrt(-abs(big)))); + // test numext::isfinite + VERIFY(!(numext::isfinite)( std::numeric_limits::infinity())); + VERIFY(!(numext::isfinite)(sqrt(-abs(big)))); // test overflow - VERIFY(isFinite(sqrt(size)*abs(big))); + VERIFY((numext::isfinite)(sqrt(size)*abs(big))); VERIFY_IS_NOT_APPROX(sqrt(copy(vbig.squaredNorm())), abs(sqrt(size)*big)); // here the default norm must fail VERIFY_IS_APPROX(vbig.stableNorm(), sqrt(size)*abs(big)); VERIFY_IS_APPROX(vbig.blueNorm(), sqrt(size)*abs(big)); VERIFY_IS_APPROX(vbig.hypotNorm(), sqrt(size)*abs(big)); // test underflow - VERIFY(isFinite(sqrt(size)*abs(small))); + VERIFY((numext::isfinite)(sqrt(size)*abs(small))); VERIFY_IS_NOT_APPROX(sqrt(copy(vsmall.squaredNorm())), abs(sqrt(size)*small)); // here the default norm must fail VERIFY_IS_APPROX(vsmall.stableNorm(), sqrt(size)*abs(small)); VERIFY_IS_APPROX(vsmall.blueNorm(), sqrt(size)*abs(small)); @@ -101,6 +105,79 @@ template void stable_norm(const MatrixType& m) VERIFY_IS_APPROX(vrand.rowwise().stableNorm(), vrand.rowwise().norm()); VERIFY_IS_APPROX(vrand.rowwise().blueNorm(), vrand.rowwise().norm()); VERIFY_IS_APPROX(vrand.rowwise().hypotNorm(), vrand.rowwise().norm()); + + // test NaN, +inf, -inf + MatrixType v; + Index i = internal::random(0,rows-1); + Index j = internal::random(0,cols-1); + + // NaN + { + v = vrand; + v(i,j) = std::numeric_limits::quiet_NaN(); + VERIFY(!(numext::isfinite)(v.squaredNorm())); VERIFY((numext::isnan)(v.squaredNorm())); + VERIFY(!(numext::isfinite)(v.norm())); VERIFY((numext::isnan)(v.norm())); + VERIFY(!(numext::isfinite)(v.stableNorm())); VERIFY((numext::isnan)(v.stableNorm())); + VERIFY(!(numext::isfinite)(v.blueNorm())); VERIFY((numext::isnan)(v.blueNorm())); + VERIFY(!(numext::isfinite)(v.hypotNorm())); VERIFY((numext::isnan)(v.hypotNorm())); + } + + // +inf + { + v = vrand; + v(i,j) = std::numeric_limits::infinity(); + VERIFY(!(numext::isfinite)(v.squaredNorm())); VERIFY(isPlusInf(v.squaredNorm())); + VERIFY(!(numext::isfinite)(v.norm())); VERIFY(isPlusInf(v.norm())); + VERIFY(!(numext::isfinite)(v.stableNorm())); + if(complex_real_product_ok){ + VERIFY(isPlusInf(v.stableNorm())); + } + VERIFY(!(numext::isfinite)(v.blueNorm())); VERIFY(isPlusInf(v.blueNorm())); + VERIFY(!(numext::isfinite)(v.hypotNorm())); VERIFY(isPlusInf(v.hypotNorm())); + } + + // -inf + { + v = vrand; + v(i,j) = -std::numeric_limits::infinity(); + VERIFY(!(numext::isfinite)(v.squaredNorm())); VERIFY(isPlusInf(v.squaredNorm())); + VERIFY(!(numext::isfinite)(v.norm())); VERIFY(isPlusInf(v.norm())); + VERIFY(!(numext::isfinite)(v.stableNorm())); + if(complex_real_product_ok) { + VERIFY(isPlusInf(v.stableNorm())); + } + VERIFY(!(numext::isfinite)(v.blueNorm())); VERIFY(isPlusInf(v.blueNorm())); + VERIFY(!(numext::isfinite)(v.hypotNorm())); VERIFY(isPlusInf(v.hypotNorm())); + } + + // mix + { + Index i2 = internal::random(0,rows-1); + Index j2 = internal::random(0,cols-1); + v = vrand; + v(i,j) = -std::numeric_limits::infinity(); + v(i2,j2) = std::numeric_limits::quiet_NaN(); + VERIFY(!(numext::isfinite)(v.squaredNorm())); VERIFY((numext::isnan)(v.squaredNorm())); + VERIFY(!(numext::isfinite)(v.norm())); VERIFY((numext::isnan)(v.norm())); + VERIFY(!(numext::isfinite)(v.stableNorm())); VERIFY((numext::isnan)(v.stableNorm())); + VERIFY(!(numext::isfinite)(v.blueNorm())); VERIFY((numext::isnan)(v.blueNorm())); + VERIFY(!(numext::isfinite)(v.hypotNorm())); VERIFY((numext::isnan)(v.hypotNorm())); + } + + // stableNormalize[d] + { + VERIFY_IS_APPROX(vrand.stableNormalized(), vrand.normalized()); + MatrixType vcopy(vrand); + vcopy.stableNormalize(); + VERIFY_IS_APPROX(vcopy, vrand.normalized()); + VERIFY_IS_APPROX((vrand.stableNormalized()).norm(), RealScalar(1)); + VERIFY_IS_APPROX(vcopy.norm(), RealScalar(1)); + VERIFY_IS_APPROX((vbig.stableNormalized()).norm(), RealScalar(1)); + VERIFY_IS_APPROX((vsmall.stableNormalized()).norm(), RealScalar(1)); + RealScalar big_scaling = ((std::numeric_limits::max)() * RealScalar(1e-4)); + VERIFY_IS_APPROX(vbig/big_scaling, (vbig.stableNorm() * vbig.stableNormalized()).eval()/big_scaling); + VERIFY_IS_APPROX(vsmall, vsmall.stableNorm() * vsmall.stableNormalized()); + } } void test_stable_norm() diff --git a/ground/gcs/src/libs/eigen/test/stdvector.cpp b/ground/gcs/src/libs/eigen/test/stdvector.cpp index 6e173c678b..50cb3341da 100644 --- a/ground/gcs/src/libs/eigen/test/stdvector.cpp +++ b/ground/gcs/src/libs/eigen/test/stdvector.cpp @@ -34,7 +34,7 @@ void check_stdvector_matrix(const MatrixType& m) VERIFY_IS_APPROX(v[21], y); v.push_back(x); VERIFY_IS_APPROX(v[22], x); - VERIFY((size_t)&(v[22]) == (size_t)&(v[21]) + sizeof(MatrixType)); + VERIFY((internal::UIntPtr)&(v[22]) == (internal::UIntPtr)&(v[21]) + sizeof(MatrixType)); // do a lot of push_back such that the vector gets internally resized // (with memory reallocation) @@ -69,7 +69,7 @@ void check_stdvector_transform(const TransformType&) VERIFY_IS_APPROX(v[21], y); v.push_back(x); VERIFY_IS_APPROX(v[22], x); - VERIFY((size_t)&(v[22]) == (size_t)&(v[21]) + sizeof(TransformType)); + VERIFY((internal::UIntPtr)&(v[22]) == (internal::UIntPtr)&(v[21]) + sizeof(TransformType)); // do a lot of push_back such that the vector gets internally resized // (with memory reallocation) @@ -104,7 +104,7 @@ void check_stdvector_quaternion(const QuaternionType&) VERIFY_IS_APPROX(v[21], y); v.push_back(x); VERIFY_IS_APPROX(v[22], x); - VERIFY((size_t)&(v[22]) == (size_t)&(v[21]) + sizeof(QuaternionType)); + VERIFY((internal::UIntPtr)&(v[22]) == (internal::UIntPtr)&(v[21]) + sizeof(QuaternionType)); // do a lot of push_back such that the vector gets internally resized // (with memory reallocation) diff --git a/ground/gcs/src/libs/eigen/test/stdvector_overload.cpp b/ground/gcs/src/libs/eigen/test/stdvector_overload.cpp index 736ff0ee79..959665954e 100644 --- a/ground/gcs/src/libs/eigen/test/stdvector_overload.cpp +++ b/ground/gcs/src/libs/eigen/test/stdvector_overload.cpp @@ -48,7 +48,7 @@ void check_stdvector_matrix(const MatrixType& m) VERIFY_IS_APPROX(v[21], y); v.push_back(x); VERIFY_IS_APPROX(v[22], x); - VERIFY((size_t)&(v[22]) == (size_t)&(v[21]) + sizeof(MatrixType)); + VERIFY((internal::UIntPtr)&(v[22]) == (internal::UIntPtr)&(v[21]) + sizeof(MatrixType)); // do a lot of push_back such that the vector gets internally resized // (with memory reallocation) @@ -83,7 +83,7 @@ void check_stdvector_transform(const TransformType&) VERIFY_IS_APPROX(v[21], y); v.push_back(x); VERIFY_IS_APPROX(v[22], x); - VERIFY((size_t)&(v[22]) == (size_t)&(v[21]) + sizeof(TransformType)); + VERIFY((internal::UIntPtr)&(v[22]) == (internal::UIntPtr)&(v[21]) + sizeof(TransformType)); // do a lot of push_back such that the vector gets internally resized // (with memory reallocation) @@ -118,7 +118,7 @@ void check_stdvector_quaternion(const QuaternionType&) VERIFY_IS_APPROX(v[21], y); v.push_back(x); VERIFY_IS_APPROX(v[22], x); - VERIFY((size_t)&(v[22]) == (size_t)&(v[21]) + sizeof(QuaternionType)); + VERIFY((internal::UIntPtr)&(v[22]) == (internal::UIntPtr)&(v[21]) + sizeof(QuaternionType)); // do a lot of push_back such that the vector gets internally resized // (with memory reallocation) diff --git a/ground/gcs/src/libs/eigen/test/superlu_support.cpp b/ground/gcs/src/libs/eigen/test/superlu_support.cpp index 3b16135bc3..98a7bc5c82 100644 --- a/ground/gcs/src/libs/eigen/test/superlu_support.cpp +++ b/ground/gcs/src/libs/eigen/test/superlu_support.cpp @@ -7,6 +7,7 @@ // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. +#define EIGEN_NO_DEBUG_SMALL_PRODUCT_BLOCKS #include "sparse_solver.h" #include diff --git a/ground/gcs/src/libs/eigen/test/svd_common.h b/ground/gcs/src/libs/eigen/test/svd_common.h new file mode 100644 index 0000000000..605d5dfeff --- /dev/null +++ b/ground/gcs/src/libs/eigen/test/svd_common.h @@ -0,0 +1,483 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2014 Gael Guennebaud +// Copyright (C) 2009 Benoit Jacob +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef SVD_DEFAULT +#error a macro SVD_DEFAULT(MatrixType) must be defined prior to including svd_common.h +#endif + +#ifndef SVD_FOR_MIN_NORM +#error a macro SVD_FOR_MIN_NORM(MatrixType) must be defined prior to including svd_common.h +#endif + +#include "svd_fill.h" + +// Check that the matrix m is properly reconstructed and that the U and V factors are unitary +// The SVD must have already been computed. +template +void svd_check_full(const MatrixType& m, const SvdType& svd) +{ + typedef typename MatrixType::Index Index; + Index rows = m.rows(); + Index cols = m.cols(); + + enum { + RowsAtCompileTime = MatrixType::RowsAtCompileTime, + ColsAtCompileTime = MatrixType::ColsAtCompileTime + }; + + typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::RealScalar RealScalar; + typedef Matrix MatrixUType; + typedef Matrix MatrixVType; + + MatrixType sigma = MatrixType::Zero(rows,cols); + sigma.diagonal() = svd.singularValues().template cast(); + MatrixUType u = svd.matrixU(); + MatrixVType v = svd.matrixV(); + RealScalar scaling = m.cwiseAbs().maxCoeff(); + if(scaling<(std::numeric_limits::min)()) + { + VERIFY(sigma.cwiseAbs().maxCoeff() <= (std::numeric_limits::min)()); + } + else + { + VERIFY_IS_APPROX(m/scaling, u * (sigma/scaling) * v.adjoint()); + } + VERIFY_IS_UNITARY(u); + VERIFY_IS_UNITARY(v); +} + +// Compare partial SVD defined by computationOptions to a full SVD referenceSvd +template +void svd_compare_to_full(const MatrixType& m, + unsigned int computationOptions, + const SvdType& referenceSvd) +{ + typedef typename MatrixType::RealScalar RealScalar; + Index rows = m.rows(); + Index cols = m.cols(); + Index diagSize = (std::min)(rows, cols); + RealScalar prec = test_precision(); + + SvdType svd(m, computationOptions); + + VERIFY_IS_APPROX(svd.singularValues(), referenceSvd.singularValues()); + + if(computationOptions & (ComputeFullV|ComputeThinV)) + { + VERIFY( (svd.matrixV().adjoint()*svd.matrixV()).isIdentity(prec) ); + VERIFY_IS_APPROX( svd.matrixV().leftCols(diagSize) * svd.singularValues().asDiagonal() * svd.matrixV().leftCols(diagSize).adjoint(), + referenceSvd.matrixV().leftCols(diagSize) * referenceSvd.singularValues().asDiagonal() * referenceSvd.matrixV().leftCols(diagSize).adjoint()); + } + + if(computationOptions & (ComputeFullU|ComputeThinU)) + { + VERIFY( (svd.matrixU().adjoint()*svd.matrixU()).isIdentity(prec) ); + VERIFY_IS_APPROX( svd.matrixU().leftCols(diagSize) * svd.singularValues().cwiseAbs2().asDiagonal() * svd.matrixU().leftCols(diagSize).adjoint(), + referenceSvd.matrixU().leftCols(diagSize) * referenceSvd.singularValues().cwiseAbs2().asDiagonal() * referenceSvd.matrixU().leftCols(diagSize).adjoint()); + } + + // The following checks are not critical. + // For instance, with Dived&Conquer SVD, if only the factor 'V' is computedt then different matrix-matrix product implementation will be used + // and the resulting 'V' factor might be significantly different when the SVD decomposition is not unique, especially with single precision float. + ++g_test_level; + if(computationOptions & ComputeFullU) VERIFY_IS_APPROX(svd.matrixU(), referenceSvd.matrixU()); + if(computationOptions & ComputeThinU) VERIFY_IS_APPROX(svd.matrixU(), referenceSvd.matrixU().leftCols(diagSize)); + if(computationOptions & ComputeFullV) VERIFY_IS_APPROX(svd.matrixV().cwiseAbs(), referenceSvd.matrixV().cwiseAbs()); + if(computationOptions & ComputeThinV) VERIFY_IS_APPROX(svd.matrixV(), referenceSvd.matrixV().leftCols(diagSize)); + --g_test_level; +} + +// +template +void svd_least_square(const MatrixType& m, unsigned int computationOptions) +{ + typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::RealScalar RealScalar; + typedef typename MatrixType::Index Index; + Index rows = m.rows(); + Index cols = m.cols(); + + enum { + RowsAtCompileTime = MatrixType::RowsAtCompileTime, + ColsAtCompileTime = MatrixType::ColsAtCompileTime + }; + + typedef Matrix RhsType; + typedef Matrix SolutionType; + + RhsType rhs = RhsType::Random(rows, internal::random(1, cols)); + SvdType svd(m, computationOptions); + + if(internal::is_same::value) svd.setThreshold(1e-8); + else if(internal::is_same::value) svd.setThreshold(2e-4); + + SolutionType x = svd.solve(rhs); + + RealScalar residual = (m*x-rhs).norm(); + RealScalar rhs_norm = rhs.norm(); + if(!test_isMuchSmallerThan(residual,rhs.norm())) + { + // ^^^ If the residual is very small, then we have an exact solution, so we are already good. + + // evaluate normal equation which works also for least-squares solutions + if(internal::is_same::value || svd.rank()==m.diagonal().size()) + { + using std::sqrt; + // This test is not stable with single precision. + // This is probably because squaring m signicantly affects the precision. + if(internal::is_same::value) ++g_test_level; + + VERIFY_IS_APPROX(m.adjoint()*(m*x),m.adjoint()*rhs); + + if(internal::is_same::value) --g_test_level; + } + + // Check that there is no significantly better solution in the neighborhood of x + for(Index k=0;k::epsilon())*x.row(k); + RealScalar residual_y = (m*y-rhs).norm(); + VERIFY( test_isMuchSmallerThan(abs(residual_y-residual), rhs_norm) || residual < residual_y ); + if(internal::is_same::value) ++g_test_level; + VERIFY( test_isApprox(residual_y,residual) || residual < residual_y ); + if(internal::is_same::value) --g_test_level; + + y.row(k) = (RealScalar(1)-2*NumTraits::epsilon())*x.row(k); + residual_y = (m*y-rhs).norm(); + VERIFY( test_isMuchSmallerThan(abs(residual_y-residual), rhs_norm) || residual < residual_y ); + if(internal::is_same::value) ++g_test_level; + VERIFY( test_isApprox(residual_y,residual) || residual < residual_y ); + if(internal::is_same::value) --g_test_level; + } + } +} + +// check minimal norm solutions, the inoput matrix m is only used to recover problem size +template +void svd_min_norm(const MatrixType& m, unsigned int computationOptions) +{ + typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::Index Index; + Index cols = m.cols(); + + enum { + ColsAtCompileTime = MatrixType::ColsAtCompileTime + }; + + typedef Matrix SolutionType; + + // generate a full-rank m x n problem with m MatrixType2; + typedef Matrix RhsType2; + typedef Matrix MatrixType2T; + Index rank = RankAtCompileTime2==Dynamic ? internal::random(1,cols) : Index(RankAtCompileTime2); + MatrixType2 m2(rank,cols); + int guard = 0; + do { + m2.setRandom(); + } while(SVD_FOR_MIN_NORM(MatrixType2)(m2).setThreshold(test_precision()).rank()!=rank && (++guard)<10); + VERIFY(guard<10); + + RhsType2 rhs2 = RhsType2::Random(rank); + // use QR to find a reference minimal norm solution + HouseholderQR qr(m2.adjoint()); + Matrix tmp = qr.matrixQR().topLeftCorner(rank,rank).template triangularView().adjoint().solve(rhs2); + tmp.conservativeResize(cols); + tmp.tail(cols-rank).setZero(); + SolutionType x21 = qr.householderQ() * tmp; + // now check with SVD + SVD_FOR_MIN_NORM(MatrixType2) svd2(m2, computationOptions); + SolutionType x22 = svd2.solve(rhs2); + VERIFY_IS_APPROX(m2*x21, rhs2); + VERIFY_IS_APPROX(m2*x22, rhs2); + VERIFY_IS_APPROX(x21, x22); + + // Now check with a rank deficient matrix + typedef Matrix MatrixType3; + typedef Matrix RhsType3; + Index rows3 = RowsAtCompileTime3==Dynamic ? internal::random(rank+1,2*cols) : Index(RowsAtCompileTime3); + Matrix C = Matrix::Random(rows3,rank); + MatrixType3 m3 = C * m2; + RhsType3 rhs3 = C * rhs2; + SVD_FOR_MIN_NORM(MatrixType3) svd3(m3, computationOptions); + SolutionType x3 = svd3.solve(rhs3); + VERIFY_IS_APPROX(m3*x3, rhs3); + VERIFY_IS_APPROX(m3*x21, rhs3); + VERIFY_IS_APPROX(m2*x3, rhs2); + VERIFY_IS_APPROX(x21, x3); +} + +// Check full, compare_to_full, least_square, and min_norm for all possible compute-options +template +void svd_test_all_computation_options(const MatrixType& m, bool full_only) +{ +// if (QRPreconditioner == NoQRPreconditioner && m.rows() != m.cols()) +// return; + SvdType fullSvd(m, ComputeFullU|ComputeFullV); + CALL_SUBTEST(( svd_check_full(m, fullSvd) )); + CALL_SUBTEST(( svd_least_square(m, ComputeFullU | ComputeFullV) )); + CALL_SUBTEST(( svd_min_norm(m, ComputeFullU | ComputeFullV) )); + + #if defined __INTEL_COMPILER + // remark #111: statement is unreachable + #pragma warning disable 111 + #endif + if(full_only) + return; + + CALL_SUBTEST(( svd_compare_to_full(m, ComputeFullU, fullSvd) )); + CALL_SUBTEST(( svd_compare_to_full(m, ComputeFullV, fullSvd) )); + CALL_SUBTEST(( svd_compare_to_full(m, 0, fullSvd) )); + + if (MatrixType::ColsAtCompileTime == Dynamic) { + // thin U/V are only available with dynamic number of columns + CALL_SUBTEST(( svd_compare_to_full(m, ComputeFullU|ComputeThinV, fullSvd) )); + CALL_SUBTEST(( svd_compare_to_full(m, ComputeThinV, fullSvd) )); + CALL_SUBTEST(( svd_compare_to_full(m, ComputeThinU|ComputeFullV, fullSvd) )); + CALL_SUBTEST(( svd_compare_to_full(m, ComputeThinU , fullSvd) )); + CALL_SUBTEST(( svd_compare_to_full(m, ComputeThinU|ComputeThinV, fullSvd) )); + + CALL_SUBTEST(( svd_least_square(m, ComputeFullU | ComputeThinV) )); + CALL_SUBTEST(( svd_least_square(m, ComputeThinU | ComputeFullV) )); + CALL_SUBTEST(( svd_least_square(m, ComputeThinU | ComputeThinV) )); + + CALL_SUBTEST(( svd_min_norm(m, ComputeFullU | ComputeThinV) )); + CALL_SUBTEST(( svd_min_norm(m, ComputeThinU | ComputeFullV) )); + CALL_SUBTEST(( svd_min_norm(m, ComputeThinU | ComputeThinV) )); + + // test reconstruction + typedef typename MatrixType::Index Index; + Index diagSize = (std::min)(m.rows(), m.cols()); + SvdType svd(m, ComputeThinU | ComputeThinV); + VERIFY_IS_APPROX(m, svd.matrixU().leftCols(diagSize) * svd.singularValues().asDiagonal() * svd.matrixV().leftCols(diagSize).adjoint()); + } +} + + +// work around stupid msvc error when constructing at compile time an expression that involves +// a division by zero, even if the numeric type has floating point +template +EIGEN_DONT_INLINE Scalar zero() { return Scalar(0); } + +// workaround aggressive optimization in ICC +template EIGEN_DONT_INLINE T sub(T a, T b) { return a - b; } + +// all this function does is verify we don't iterate infinitely on nan/inf values +template +void svd_inf_nan() +{ + SvdType svd; + typedef typename MatrixType::Scalar Scalar; + Scalar some_inf = Scalar(1) / zero(); + VERIFY(sub(some_inf, some_inf) != sub(some_inf, some_inf)); + svd.compute(MatrixType::Constant(10,10,some_inf), ComputeFullU | ComputeFullV); + + Scalar nan = std::numeric_limits::quiet_NaN(); + VERIFY(nan != nan); + svd.compute(MatrixType::Constant(10,10,nan), ComputeFullU | ComputeFullV); + + MatrixType m = MatrixType::Zero(10,10); + m(internal::random(0,9), internal::random(0,9)) = some_inf; + svd.compute(m, ComputeFullU | ComputeFullV); + + m = MatrixType::Zero(10,10); + m(internal::random(0,9), internal::random(0,9)) = nan; + svd.compute(m, ComputeFullU | ComputeFullV); + + // regression test for bug 791 + m.resize(3,3); + m << 0, 2*NumTraits::epsilon(), 0.5, + 0, -0.5, 0, + nan, 0, 0; + svd.compute(m, ComputeFullU | ComputeFullV); + + m.resize(4,4); + m << 1, 0, 0, 0, + 0, 3, 1, 2e-308, + 1, 0, 1, nan, + 0, nan, nan, 0; + svd.compute(m, ComputeFullU | ComputeFullV); +} + +// Regression test for bug 286: JacobiSVD loops indefinitely with some +// matrices containing denormal numbers. +template +void svd_underoverflow() +{ +#if defined __INTEL_COMPILER +// shut up warning #239: floating point underflow +#pragma warning push +#pragma warning disable 239 +#endif + Matrix2d M; + M << -7.90884e-313, -4.94e-324, + 0, 5.60844e-313; + SVD_DEFAULT(Matrix2d) svd; + svd.compute(M,ComputeFullU|ComputeFullV); + CALL_SUBTEST( svd_check_full(M,svd) ); + + // Check all 2x2 matrices made with the following coefficients: + VectorXd value_set(9); + value_set << 0, 1, -1, 5.60844e-313, -5.60844e-313, 4.94e-324, -4.94e-324, -4.94e-223, 4.94e-223; + Array4i id(0,0,0,0); + int k = 0; + do + { + M << value_set(id(0)), value_set(id(1)), value_set(id(2)), value_set(id(3)); + svd.compute(M,ComputeFullU|ComputeFullV); + CALL_SUBTEST( svd_check_full(M,svd) ); + + id(k)++; + if(id(k)>=value_set.size()) + { + while(k<3 && id(k)>=value_set.size()) id(++k)++; + id.head(k).setZero(); + k=0; + } + + } while((id +void svd_all_trivial_2x2( void (*cb)(const MatrixType&,bool) ) +{ + MatrixType M; + VectorXd value_set(3); + value_set << 0, 1, -1; + Array4i id(0,0,0,0); + int k = 0; + do + { + M << value_set(id(0)), value_set(id(1)), value_set(id(2)), value_set(id(3)); + + cb(M,false); + + id(k)++; + if(id(k)>=value_set.size()) + { + while(k<3 && id(k)>=value_set.size()) id(++k)++; + id.head(k).setZero(); + k=0; + } + + } while((id +void svd_preallocate() +{ + Vector3f v(3.f, 2.f, 1.f); + MatrixXf m = v.asDiagonal(); + + internal::set_is_malloc_allowed(false); + VERIFY_RAISES_ASSERT(VectorXf tmp(10);) + SVD_DEFAULT(MatrixXf) svd; + internal::set_is_malloc_allowed(true); + svd.compute(m); + VERIFY_IS_APPROX(svd.singularValues(), v); + + SVD_DEFAULT(MatrixXf) svd2(3,3); + internal::set_is_malloc_allowed(false); + svd2.compute(m); + internal::set_is_malloc_allowed(true); + VERIFY_IS_APPROX(svd2.singularValues(), v); + VERIFY_RAISES_ASSERT(svd2.matrixU()); + VERIFY_RAISES_ASSERT(svd2.matrixV()); + svd2.compute(m, ComputeFullU | ComputeFullV); + VERIFY_IS_APPROX(svd2.matrixU(), Matrix3f::Identity()); + VERIFY_IS_APPROX(svd2.matrixV(), Matrix3f::Identity()); + internal::set_is_malloc_allowed(false); + svd2.compute(m); + internal::set_is_malloc_allowed(true); + + SVD_DEFAULT(MatrixXf) svd3(3,3,ComputeFullU|ComputeFullV); + internal::set_is_malloc_allowed(false); + svd2.compute(m); + internal::set_is_malloc_allowed(true); + VERIFY_IS_APPROX(svd2.singularValues(), v); + VERIFY_IS_APPROX(svd2.matrixU(), Matrix3f::Identity()); + VERIFY_IS_APPROX(svd2.matrixV(), Matrix3f::Identity()); + internal::set_is_malloc_allowed(false); + svd2.compute(m, ComputeFullU|ComputeFullV); + internal::set_is_malloc_allowed(true); +} + +template +void svd_verify_assert(const MatrixType& m) +{ + typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::Index Index; + Index rows = m.rows(); + Index cols = m.cols(); + + enum { + RowsAtCompileTime = MatrixType::RowsAtCompileTime, + ColsAtCompileTime = MatrixType::ColsAtCompileTime + }; + + typedef Matrix RhsType; + RhsType rhs(rows); + SvdType svd; + VERIFY_RAISES_ASSERT(svd.matrixU()) + VERIFY_RAISES_ASSERT(svd.singularValues()) + VERIFY_RAISES_ASSERT(svd.matrixV()) + VERIFY_RAISES_ASSERT(svd.solve(rhs)) + MatrixType a = MatrixType::Zero(rows, cols); + a.setZero(); + svd.compute(a, 0); + VERIFY_RAISES_ASSERT(svd.matrixU()) + VERIFY_RAISES_ASSERT(svd.matrixV()) + svd.singularValues(); + VERIFY_RAISES_ASSERT(svd.solve(rhs)) + + if (ColsAtCompileTime == Dynamic) + { + svd.compute(a, ComputeThinU); + svd.matrixU(); + VERIFY_RAISES_ASSERT(svd.matrixV()) + VERIFY_RAISES_ASSERT(svd.solve(rhs)) + svd.compute(a, ComputeThinV); + svd.matrixV(); + VERIFY_RAISES_ASSERT(svd.matrixU()) + VERIFY_RAISES_ASSERT(svd.solve(rhs)) + } + else + { + VERIFY_RAISES_ASSERT(svd.compute(a, ComputeThinU)) + VERIFY_RAISES_ASSERT(svd.compute(a, ComputeThinV)) + } +} + +#undef SVD_DEFAULT +#undef SVD_FOR_MIN_NORM diff --git a/ground/gcs/src/libs/eigen/test/svd_fill.h b/ground/gcs/src/libs/eigen/test/svd_fill.h new file mode 100644 index 0000000000..3877c0c7ef --- /dev/null +++ b/ground/gcs/src/libs/eigen/test/svd_fill.h @@ -0,0 +1,119 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014-2015 Gael Guennebaud +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +template +Array four_denorms(); + +template<> +Array4f four_denorms() { return Array4f(5.60844e-39f, -5.60844e-39f, 4.94e-44f, -4.94e-44f); } +template<> +Array4d four_denorms() { return Array4d(5.60844e-313, -5.60844e-313, 4.94e-324, -4.94e-324); } +template +Array four_denorms() { return four_denorms().cast(); } + +template +void svd_fill_random(MatrixType &m, int Option = 0) +{ + using std::pow; + typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::RealScalar RealScalar; + typedef typename MatrixType::Index Index; + Index diagSize = (std::min)(m.rows(), m.cols()); + RealScalar s = std::numeric_limits::max_exponent10/4; + s = internal::random(1,s); + Matrix d = Matrix::Random(diagSize); + for(Index k=0; k(-s,s)); + + bool dup = internal::random(0,10) < 3; + bool unit_uv = internal::random(0,10) < (dup?7:3); // if we duplicate some diagonal entries, then increase the chance to preserve them using unitary U and V factors + + // duplicate some singular values + if(dup) + { + Index n = internal::random(0,d.size()-1); + for(Index i=0; i(0,d.size()-1)) = d(internal::random(0,d.size()-1)); + } + + Matrix U(m.rows(),diagSize); + Matrix VT(diagSize,m.cols()); + if(unit_uv) + { + // in very rare cases let's try with a pure diagonal matrix + if(internal::random(0,10) < 1) + { + U.setIdentity(); + VT.setIdentity(); + } + else + { + createRandomPIMatrixOfRank(diagSize,U.rows(), U.cols(), U); + createRandomPIMatrixOfRank(diagSize,VT.rows(), VT.cols(), VT); + } + } + else + { + U.setRandom(); + VT.setRandom(); + } + + Matrix samples(9); + samples << 0, four_denorms(), + -RealScalar(1)/NumTraits::highest(), RealScalar(1)/NumTraits::highest(), (std::numeric_limits::min)(), pow((std::numeric_limits::min)(),0.8); + + if(Option==Symmetric) + { + m = U * d.asDiagonal() * U.transpose(); + + // randomly nullify some rows/columns + { + Index count = internal::random(-diagSize,diagSize); + for(Index k=0; k(0,diagSize-1); + m.row(i).setZero(); + m.col(i).setZero(); + } + if(count<0) + // (partly) cancel some coeffs + if(!(dup && unit_uv)) + { + + Index n = internal::random(0,m.size()-1); + for(Index k=0; k(0,m.rows()-1); + Index j = internal::random(0,m.cols()-1); + m(j,i) = m(i,j) = samples(internal::random(0,samples.size()-1)); + if(NumTraits::IsComplex) + *(&numext::real_ref(m(j,i))+1) = *(&numext::real_ref(m(i,j))+1) = samples.real()(internal::random(0,samples.size()-1)); + } + } + } + } + else + { + m = U * d.asDiagonal() * VT; + // (partly) cancel some coeffs + if(!(dup && unit_uv)) + { + Index n = internal::random(0,m.size()-1); + for(Index k=0; k(0,m.rows()-1); + Index j = internal::random(0,m.cols()-1); + m(i,j) = samples(internal::random(0,samples.size()-1)); + if(NumTraits::IsComplex) + *(&numext::real_ref(m(i,j))+1) = samples.real()(internal::random(0,samples.size()-1)); + } + } + } +} + diff --git a/ground/gcs/src/libs/eigen/test/swap.cpp b/ground/gcs/src/libs/eigen/test/swap.cpp index 36b3531486..f76e3624dd 100644 --- a/ground/gcs/src/libs/eigen/test/swap.cpp +++ b/ground/gcs/src/libs/eigen/test/swap.cpp @@ -41,9 +41,15 @@ template void swap(const MatrixType& m) OtherMatrixType m3_copy = m3; // test swapping 2 matrices of same type + Scalar *d1=m1.data(), *d2=m2.data(); m1.swap(m2); VERIFY_IS_APPROX(m1,m2_copy); VERIFY_IS_APPROX(m2,m1_copy); + if(MatrixType::SizeAtCompileTime==Dynamic) + { + VERIFY(m1.data()==d2); + VERIFY(m2.data()==d1); + } m1 = m1_copy; m2 = m2_copy; @@ -68,16 +74,21 @@ template void swap(const MatrixType& m) m1 = m1_copy; m3 = m3_copy; - // test assertion on mismatching size -- matrix case - VERIFY_RAISES_ASSERT(m1.swap(m1.row(0))); - // test assertion on mismatching size -- xpr case - VERIFY_RAISES_ASSERT(m1.row(0).swap(m1)); + if(m1.rows()>1) + { + // test assertion on mismatching size -- matrix case + VERIFY_RAISES_ASSERT(m1.swap(m1.row(0))); + // test assertion on mismatching size -- xpr case + VERIFY_RAISES_ASSERT(m1.row(0).swap(m1)); + } } void test_swap() { + int s = internal::random(1,EIGEN_TEST_MAX_SIZE); CALL_SUBTEST_1( swap(Matrix3f()) ); // fixed size, no vectorization CALL_SUBTEST_2( swap(Matrix4d()) ); // fixed size, possible vectorization - CALL_SUBTEST_3( swap(MatrixXd(3,3)) ); // dyn size, no vectorization - CALL_SUBTEST_4( swap(MatrixXf(30,30)) ); // dyn size, possible vectorization + CALL_SUBTEST_3( swap(MatrixXd(s,s)) ); // dyn size, no vectorization + CALL_SUBTEST_4( swap(MatrixXf(s,s)) ); // dyn size, possible vectorization + TEST_SET_BUT_UNUSED_VARIABLE(s) } diff --git a/ground/gcs/src/libs/eigen/test/testsuite.cmake b/ground/gcs/src/libs/eigen/test/testsuite.cmake deleted file mode 100644 index 3bec56b3fa..0000000000 --- a/ground/gcs/src/libs/eigen/test/testsuite.cmake +++ /dev/null @@ -1,229 +0,0 @@ - -#################################################################### -# -# Usage: -# - create a new folder, let's call it cdash -# - in that folder, do: -# ctest -S path/to/eigen/test/testsuite.cmake[,option1=value1[,option2=value2]] -# -# Options: -# - EIGEN_CXX: compiler, eg.: g++-4.2 -# default: default c++ compiler -# - EIGEN_SITE: eg, INRIA-Bdx_pc-gael, or the name of the contributor, etc. -# default: hostname -# - EIGEN_BUILD_STRING: a string which identify the system/compiler. It should be formed like that: -# --- -# with: -# = opensuse, debian, osx, windows, cygwin, freebsd, solaris, etc. -# = 11.1, XP, vista, leopard, etc. -# = i386, x86_64, ia64, powerpc, etc. -# = gcc-4.3.2, icc-11.0, MSVC-2008, etc. -# - EIGEN_EXPLICIT_VECTORIZATION: novec, SSE2, Altivec -# default: SSE2 for x86_64 systems, novec otherwise -# Its value is automatically appended to EIGEN_BUILD_STRING -# - EIGEN_CMAKE_DIR: path to cmake executable -# - EIGEN_MODE: dashboard model, can be Experimental, Nightly, or Continuous -# default: Nightly -# - EIGEN_WORK_DIR: directory used to download the source files and make the builds -# default: folder which contains this script -# - EIGEN_CMAKE_ARGS: additional arguments passed to cmake -# - EIGEN_GENERATOR_TYPE: allows to overwrite the generator type -# default: nmake (windows -# See http://www.cmake.org/cmake/help/cmake2.6docs.html#section_Generators for a complete -# list of supported generators. -# - EIGEN_NO_UPDATE: allows to submit dash boards from local repositories -# This might be interesting in case you want to submit dashboards -# including local changes. -# - CTEST_SOURCE_DIRECTORY: path to eigen's src (use a new and empty folder, not the one you are working on) -# default: /src -# - CTEST_BINARY_DIRECTORY: build directory -# default: /nightly- -# -# Here is an example running several compilers on a linux system: -# #!/bin/bash -# ARCH=`uname -m` -# SITE=`hostname` -# VERSION=opensuse-11.1 -# WORK_DIR=/home/gael/Coding/eigen/cdash -# # get the last version of the script -# wget http://bitbucket.org/eigen/eigen/raw/tip/test/testsuite.cmake -o $WORK_DIR/testsuite.cmake -# COMMON="ctest -S $WORK_DIR/testsuite.cmake,EIGEN_WORK_DIR=$WORK_DIR,EIGEN_SITE=$SITE,EIGEN_MODE=$1,EIGEN_BUILD_STRING=$OS_VERSION-$ARCH" -# $COMMON-gcc-3.4.6,EIGEN_CXX=g++-3.4 -# $COMMON-gcc-4.0.1,EIGEN_CXX=g++-4.0.1 -# $COMMON-gcc-4.3.2,EIGEN_CXX=g++-4.3,EIGEN_EXPLICIT_VECTORIZATION=novec -# $COMMON-gcc-4.3.2,EIGEN_CXX=g++-4.3,EIGEN_EXPLICIT_VECTORIZATION=SSE2 -# $COMMON-icc-11.0,EIGEN_CXX=icpc -# -#################################################################### - -# process the arguments - -set(ARGLIST ${CTEST_SCRIPT_ARG}) -while(${ARGLIST} MATCHES ".+.*") - - # pick first - string(REGEX MATCH "([^,]*)(,.*)?" DUMMY ${ARGLIST}) - SET(TOP ${CMAKE_MATCH_1}) - - # remove first - string(REGEX MATCHALL "[^,]*,(.*)" DUMMY ${ARGLIST}) - SET(ARGLIST ${CMAKE_MATCH_1}) - - # decompose as a pair key=value - string(REGEX MATCH "([^=]*)(=.*)?" DUMMY ${TOP}) - SET(KEY ${CMAKE_MATCH_1}) - - string(REGEX MATCH "[^=]*=(.*)" DUMMY ${TOP}) - SET(VALUE ${CMAKE_MATCH_1}) - - # set the variable to the specified value - if(VALUE) - SET(${KEY} ${VALUE}) - else(VALUE) - SET(${KEY} ON) - endif(VALUE) - -endwhile(${ARGLIST} MATCHES ".+.*") - -#################################################################### -# Automatically set some user variables if they have not been defined manually -#################################################################### -cmake_minimum_required(VERSION 2.6 FATAL_ERROR) - -if(NOT EIGEN_SITE) - site_name(EIGEN_SITE) -endif(NOT EIGEN_SITE) - -if(NOT EIGEN_CMAKE_DIR) - SET(EIGEN_CMAKE_DIR "") -endif(NOT EIGEN_CMAKE_DIR) - -if(NOT EIGEN_BUILD_STRING) - - # let's try to find all information we need to make the build string ourself - - # OS - build_name(EIGEN_OS_VERSION) - - # arch - set(EIGEN_ARCH ${CMAKE_SYSTEM_PROCESSOR}) - if(WIN32) - set(EIGEN_ARCH $ENV{PROCESSOR_ARCHITECTURE}) - else(WIN32) - execute_process(COMMAND uname -m OUTPUT_VARIABLE EIGEN_ARCH OUTPUT_STRIP_TRAILING_WHITESPACE) - endif(WIN32) - - set(EIGEN_BUILD_STRING ${EIGEN_OS_VERSION}${EIGEN_ARCH}-${EIGEN_CXX}) - -endif(NOT EIGEN_BUILD_STRING) - -if(DEFINED EIGEN_EXPLICIT_VECTORIZATION) - set(EIGEN_BUILD_STRING ${EIGEN_BUILD_STRING}-${EIGEN_EXPLICIT_VECTORIZATION}) -endif(DEFINED EIGEN_EXPLICIT_VECTORIZATION) - -if(NOT EIGEN_WORK_DIR) - set(EIGEN_WORK_DIR ${CTEST_SCRIPT_DIRECTORY}) -endif(NOT EIGEN_WORK_DIR) - -if(NOT CTEST_SOURCE_DIRECTORY) - SET (CTEST_SOURCE_DIRECTORY "${EIGEN_WORK_DIR}/src") -endif(NOT CTEST_SOURCE_DIRECTORY) - -if(NOT CTEST_BINARY_DIRECTORY) - SET (CTEST_BINARY_DIRECTORY "${EIGEN_WORK_DIR}/nightly_${EIGEN_CXX}") -endif(NOT CTEST_BINARY_DIRECTORY) - -if(NOT EIGEN_MODE) - set(EIGEN_MODE Nightly) -endif(NOT EIGEN_MODE) - -## mandatory variables (the default should be ok in most cases): - -if(NOT EIGEN_NO_UPDATE) - SET (CTEST_CVS_COMMAND "hg") - SET (CTEST_CVS_CHECKOUT "${CTEST_CVS_COMMAND} clone http://bitbucket.org/eigen/eigen \"${CTEST_SOURCE_DIRECTORY}\"") - SET(CTEST_BACKUP_AND_RESTORE TRUE) # the backup is CVS related ... -endif(NOT EIGEN_NO_UPDATE) - -# which ctest command to use for running the dashboard -SET (CTEST_COMMAND "${EIGEN_CMAKE_DIR}ctest -D ${EIGEN_MODE} --no-compress-output") -if($ENV{EIGEN_CTEST_ARGS}) -SET (CTEST_COMMAND "${CTEST_COMMAND} $ENV{EIGEN_CTEST_ARGS}") -endif($ENV{EIGEN_CTEST_ARGS}) -# what cmake command to use for configuring this dashboard -SET (CTEST_CMAKE_COMMAND "${EIGEN_CMAKE_DIR}cmake -DEIGEN_LEAVE_TEST_IN_ALL_TARGET=ON") - -#################################################################### -# The values in this section are optional you can either -# have them or leave them commented out -#################################################################### - -# this make sure we get consistent outputs -SET($ENV{LC_MESSAGES} "en_EN") - -# should ctest wipe the binary tree before running -SET(CTEST_START_WITH_EMPTY_BINARY_DIRECTORY TRUE) - -# raise the warning/error limit -set(CTEST_CUSTOM_MAXIMUM_NUMBER_OF_WARNINGS "33331") -set(CTEST_CUSTOM_MAXIMUM_NUMBER_OF_ERRORS "33331") - -# this is the initial cache to use for the binary tree, be careful to escape -# any quotes inside of this string if you use it -if(WIN32 AND NOT UNIX) - #message(SEND_ERROR "win32") - if(EIGEN_GENERATOR_TYPE) - set(CTEST_CMAKE_COMMAND "${CTEST_CMAKE_COMMAND} -G \"${EIGEN_GENERATOR_TYPE}\"") - SET (CTEST_INITIAL_CACHE " - CMAKE_BUILD_TYPE:STRING=Release - BUILDNAME:STRING=${EIGEN_BUILD_STRING} - SITE:STRING=${EIGEN_SITE} - ") - else(EIGEN_GENERATOR_TYPE) - set(CTEST_CMAKE_COMMAND "${CTEST_CMAKE_COMMAND} -G \"NMake Makefiles\" -DCMAKE_MAKE_PROGRAM=nmake") - SET (CTEST_INITIAL_CACHE " - MAKECOMMAND:STRING=nmake /i - CMAKE_MAKE_PROGRAM:FILEPATH=nmake - CMAKE_GENERATOR:INTERNAL=NMake Makefiles - CMAKE_BUILD_TYPE:STRING=Release - BUILDNAME:STRING=${EIGEN_BUILD_STRING} - SITE:STRING=${EIGEN_SITE} - ") - endif(EIGEN_GENERATOR_TYPE) -else(WIN32 AND NOT UNIX) - SET (CTEST_INITIAL_CACHE " - BUILDNAME:STRING=${EIGEN_BUILD_STRING} - SITE:STRING=${EIGEN_SITE} - ") -endif(WIN32 AND NOT UNIX) - -# set any extra environment variables to use during the execution of the script here: -# setting this variable on windows machines causes trouble ... - -if(EIGEN_CXX AND NOT WIN32) - set(CTEST_ENVIRONMENT "CXX=${EIGEN_CXX}") -endif(EIGEN_CXX AND NOT WIN32) - -if(DEFINED EIGEN_EXPLICIT_VECTORIZATION) - if(EIGEN_EXPLICIT_VECTORIZATION MATCHES SSE2) - set(CTEST_CMAKE_COMMAND "${CTEST_CMAKE_COMMAND} -DEIGEN_TEST_SSE2=ON") - elseif(EIGEN_EXPLICIT_VECTORIZATION MATCHES SSE3) - set(CTEST_CMAKE_COMMAND "${CTEST_CMAKE_COMMAND} -DEIGEN_TEST_SSE2=ON -DEIGEN_TEST_SSE3=ON") - elseif(EIGEN_EXPLICIT_VECTORIZATION MATCHES SSSE3) - set(CTEST_CMAKE_COMMAND "${CTEST_CMAKE_COMMAND} -DEIGEN_TEST_SSE2=ON -DEIGEN_TEST_SSE3=ON -DEIGEN_TEST_SSSE3=ON") - elseif(EIGEN_EXPLICIT_VECTORIZATION MATCHES SSE4_1) - set(CTEST_CMAKE_COMMAND "${CTEST_CMAKE_COMMAND} -DEIGEN_TEST_SSE2=ON -DEIGEN_TEST_SSE3=ON -DEIGEN_TEST_SSSE3=ON -DEIGEN_TEST_SSE4_1=ON") - elseif(EIGEN_EXPLICIT_VECTORIZATION MATCHES SSE4_2) - set(CTEST_CMAKE_COMMAND "${CTEST_CMAKE_COMMAND} -DEIGEN_TEST_SSE2=ON -DEIGEN_TEST_SSE3=ON -DEIGEN_TEST_SSSE3=ON -DEIGEN_TEST_SSE4_1=ON -DEIGEN_TEST_SSE4_2=ON") - elseif(EIGEN_EXPLICIT_VECTORIZATION MATCHES Altivec) - set(CTEST_CMAKE_COMMAND "${CTEST_CMAKE_COMMAND} -DEIGEN_TEST_ALTIVEC=ON") - elseif(EIGEN_EXPLICIT_VECTORIZATION MATCHES novec) - set(CTEST_CMAKE_COMMAND "${CTEST_CMAKE_COMMAND} -DEIGEN_TEST_NO_EXPLICIT_VECTORIZATION=ON") - else(EIGEN_EXPLICIT_VECTORIZATION MATCHES SSE2) - message(FATAL_ERROR "Invalid value for EIGEN_EXPLICIT_VECTORIZATION (${EIGEN_EXPLICIT_VECTORIZATION}), must be: novec, SSE2, SSE3, Altivec") - endif(EIGEN_EXPLICIT_VECTORIZATION MATCHES SSE2) -endif(DEFINED EIGEN_EXPLICIT_VECTORIZATION) - -if(DEFINED EIGEN_CMAKE_ARGS) - set(CTEST_CMAKE_COMMAND "${CTEST_CMAKE_COMMAND} ${EIGEN_CMAKE_ARGS}") -endif(DEFINED EIGEN_CMAKE_ARGS) diff --git a/ground/gcs/src/libs/eigen/test/triangular.cpp b/ground/gcs/src/libs/eigen/test/triangular.cpp index 54320390ba..b968564864 100644 --- a/ground/gcs/src/libs/eigen/test/triangular.cpp +++ b/ground/gcs/src/libs/eigen/test/triangular.cpp @@ -65,7 +65,7 @@ template void triangular_square(const MatrixType& m) m1 = MatrixType::Random(rows, cols); for (int i=0; i(); + while (numext::abs2(m1(i,i))(); Transpose trm4(m4); // test back and forward subsitution with a vector as the rhs @@ -78,7 +78,7 @@ template void triangular_square(const MatrixType& m) m3 = m1.template triangularView(); VERIFY(v2.isApprox(m3.conjugate() * (m1.conjugate().template triangularView().solve(v2)), largerEps)); - // test back and forward subsitution with a matrix as the rhs + // test back and forward substitution with a matrix as the rhs m3 = m1.template triangularView(); VERIFY(m2.isApprox(m3.adjoint() * (m1.adjoint().template triangularView().solve(m2)), largerEps)); m3 = m1.template triangularView(); @@ -113,6 +113,21 @@ template void triangular_square(const MatrixType& m) m3.setZero(); m3.template triangularView().setOnes(); VERIFY_IS_APPROX(m2,m3); + + m1.setRandom(); + m3 = m1.template triangularView(); + Matrix m5(cols, internal::random(1,20)); m5.setRandom(); + Matrix m6(internal::random(1,20), rows); m6.setRandom(); + VERIFY_IS_APPROX(m1.template triangularView() * m5, m3*m5); + VERIFY_IS_APPROX(m6*m1.template triangularView(), m6*m3); + + m1up = m1.template triangularView(); + VERIFY_IS_APPROX(m1.template selfadjointView().template triangularView().toDenseMatrix(), m1up); + VERIFY_IS_APPROX(m1up.template selfadjointView().template triangularView().toDenseMatrix(), m1up); + VERIFY_IS_APPROX(m1.template selfadjointView().template triangularView().toDenseMatrix(), m1up.adjoint()); + VERIFY_IS_APPROX(m1up.template selfadjointView().template triangularView().toDenseMatrix(), m1up.adjoint()); + + VERIFY_IS_APPROX(m1.template selfadjointView().diagonal(), m1.diagonal()); } diff --git a/ground/gcs/src/libs/eigen/test/umfpack_support.cpp b/ground/gcs/src/libs/eigen/test/umfpack_support.cpp index 9eb84c14bc..37ab11f0b9 100644 --- a/ground/gcs/src/libs/eigen/test/umfpack_support.cpp +++ b/ground/gcs/src/libs/eigen/test/umfpack_support.cpp @@ -7,6 +7,7 @@ // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. +#define EIGEN_NO_DEBUG_SMALL_PRODUCT_BLOCKS #include "sparse_solver.h" #include diff --git a/ground/gcs/src/libs/eigen/test/unalignedassert.cpp b/ground/gcs/src/libs/eigen/test/unalignedassert.cpp index 601dbf214a..731a08977c 100644 --- a/ground/gcs/src/libs/eigen/test/unalignedassert.cpp +++ b/ground/gcs/src/libs/eigen/test/unalignedassert.cpp @@ -2,13 +2,39 @@ // for linear algebra. // // Copyright (C) 2008 Benoit Jacob +// Copyright (C) 2015 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. +#if defined(EIGEN_TEST_PART_1) + // default +#elif defined(EIGEN_TEST_PART_2) + #define EIGEN_MAX_STATIC_ALIGN_BYTES 16 + #define EIGEN_MAX_ALIGN_BYTES 16 +#elif defined(EIGEN_TEST_PART_3) + #define EIGEN_MAX_STATIC_ALIGN_BYTES 32 + #define EIGEN_MAX_ALIGN_BYTES 32 +#elif defined(EIGEN_TEST_PART_4) + #define EIGEN_MAX_STATIC_ALIGN_BYTES 64 + #define EIGEN_MAX_ALIGN_BYTES 64 +#endif + #include "main.h" +typedef Matrix Vector6f; +typedef Matrix Vector8f; +typedef Matrix Vector12f; + +typedef Matrix Vector5d; +typedef Matrix Vector6d; +typedef Matrix Vector7d; +typedef Matrix Vector8d; +typedef Matrix Vector9d; +typedef Matrix Vector10d; +typedef Matrix Vector12d; + struct TestNew1 { MatrixXd m; // good: m will allocate its own array, taking care of alignment. @@ -36,7 +62,7 @@ struct TestNew4 struct TestNew5 { EIGEN_MAKE_ALIGNED_OPERATOR_NEW - float f; // try the f at first -- the EIGEN_ALIGN16 attribute of m should make that still work + float f; // try the f at first -- the EIGEN_ALIGN_MAX attribute of m should make that still work Matrix4f m; }; @@ -63,13 +89,13 @@ void check_unalignedassert_good() delete[] y; } -#if EIGEN_ALIGN_STATICALLY +#if EIGEN_MAX_STATIC_ALIGN_BYTES>0 template void construct_at_boundary(int boundary) { char buf[sizeof(T)+256]; - size_t _buf = reinterpret_cast(buf); - _buf += (16 - (_buf % 16)); // make 16-byte aligned + size_t _buf = reinterpret_cast(buf); + _buf += (EIGEN_MAX_ALIGN_BYTES - (_buf % EIGEN_MAX_ALIGN_BYTES)); // make 16/32/...-byte aligned _buf += boundary; // make exact boundary-aligned T *x = ::new(reinterpret_cast(_buf)) T; x[0].setZero(); // just in order to silence warnings @@ -79,26 +105,36 @@ void construct_at_boundary(int boundary) void unalignedassert() { - #if EIGEN_ALIGN_STATICALLY +#if EIGEN_MAX_STATIC_ALIGN_BYTES>0 construct_at_boundary(4); construct_at_boundary(4); construct_at_boundary(16); + construct_at_boundary(4); + construct_at_boundary(EIGEN_MAX_ALIGN_BYTES); + construct_at_boundary(16); construct_at_boundary(16); construct_at_boundary(4); - construct_at_boundary(16); + construct_at_boundary(EIGEN_MAX_ALIGN_BYTES); construct_at_boundary(16); construct_at_boundary(4); - construct_at_boundary(16); - construct_at_boundary(16); + construct_at_boundary(EIGEN_MAX_ALIGN_BYTES); + construct_at_boundary(4); + construct_at_boundary(16); + construct_at_boundary(4); + construct_at_boundary(EIGEN_MAX_ALIGN_BYTES); + construct_at_boundary(4); + construct_at_boundary(16); + construct_at_boundary(EIGEN_MAX_ALIGN_BYTES); + construct_at_boundary(EIGEN_MAX_ALIGN_BYTES); construct_at_boundary(4); - construct_at_boundary(16); + construct_at_boundary(EIGEN_MAX_ALIGN_BYTES); construct_at_boundary(16); construct_at_boundary(4); - construct_at_boundary(16); + construct_at_boundary(EIGEN_MAX_ALIGN_BYTES); construct_at_boundary(16); - #endif +#endif check_unalignedassert_good(); check_unalignedassert_good(); @@ -109,15 +145,32 @@ void unalignedassert() check_unalignedassert_good(); check_unalignedassert_good >(); -#if EIGEN_ALIGN_STATICALLY - VERIFY_RAISES_ASSERT(construct_at_boundary(8)); - VERIFY_RAISES_ASSERT(construct_at_boundary(8)); - VERIFY_RAISES_ASSERT(construct_at_boundary(8)); - VERIFY_RAISES_ASSERT(construct_at_boundary(8)); - VERIFY_RAISES_ASSERT(construct_at_boundary(8)); - VERIFY_RAISES_ASSERT(construct_at_boundary(8)); - VERIFY_RAISES_ASSERT(construct_at_boundary(8)); - VERIFY_RAISES_ASSERT(construct_at_boundary(8)); +#if EIGEN_MAX_STATIC_ALIGN_BYTES>0 + if(EIGEN_MAX_ALIGN_BYTES>=16) + { + VERIFY_RAISES_ASSERT(construct_at_boundary(8)); + VERIFY_RAISES_ASSERT(construct_at_boundary(8)); + VERIFY_RAISES_ASSERT(construct_at_boundary(8)); + VERIFY_RAISES_ASSERT(construct_at_boundary(8)); + VERIFY_RAISES_ASSERT(construct_at_boundary(8)); + VERIFY_RAISES_ASSERT(construct_at_boundary(8)); + VERIFY_RAISES_ASSERT(construct_at_boundary(8)); + VERIFY_RAISES_ASSERT(construct_at_boundary(8)); + VERIFY_RAISES_ASSERT(construct_at_boundary(8)); + // Complexes are disabled because the compiler might aggressively vectorize + // the initialization of complex coeffs to 0 before we can check for alignedness + //VERIFY_RAISES_ASSERT(construct_at_boundary(8)); + VERIFY_RAISES_ASSERT(construct_at_boundary(8)); + } + for(int b=8; b(b)); + if(b<64) VERIFY_RAISES_ASSERT(construct_at_boundary(b)); + if(b<32) VERIFY_RAISES_ASSERT(construct_at_boundary(b)); + if(b<32) VERIFY_RAISES_ASSERT(construct_at_boundary(b)); + if(b<128) VERIFY_RAISES_ASSERT(construct_at_boundary(b)); + //if(b<32) VERIFY_RAISES_ASSERT(construct_at_boundary(b)); + } #endif } diff --git a/ground/gcs/src/libs/eigen/test/unalignedcount.cpp b/ground/gcs/src/libs/eigen/test/unalignedcount.cpp index ca7e159f3b..d6ffeafdf9 100644 --- a/ground/gcs/src/libs/eigen/test/unalignedcount.cpp +++ b/ground/gcs/src/libs/eigen/test/unalignedcount.cpp @@ -30,7 +30,14 @@ static int nb_storeu; void test_unalignedcount() { - #ifdef EIGEN_VECTORIZE_SSE + #if defined(EIGEN_VECTORIZE_AVX) + VectorXf a(40), b(40); + VERIFY_ALIGNED_UNALIGNED_COUNT(a += b, 10, 0, 5, 0); + VERIFY_ALIGNED_UNALIGNED_COUNT(a.segment(0,40) += b.segment(0,40), 5, 5, 5, 0); + VERIFY_ALIGNED_UNALIGNED_COUNT(a.segment(0,40) -= b.segment(0,40), 5, 5, 5, 0); + VERIFY_ALIGNED_UNALIGNED_COUNT(a.segment(0,40) *= 3.5, 5, 0, 5, 0); + VERIFY_ALIGNED_UNALIGNED_COUNT(a.segment(0,40) /= 3.5, 5, 0, 5, 0); + #elif defined(EIGEN_VECTORIZE_SSE) VectorXf a(40), b(40); VERIFY_ALIGNED_UNALIGNED_COUNT(a += b, 20, 0, 10, 0); VERIFY_ALIGNED_UNALIGNED_COUNT(a.segment(0,40) += b.segment(0,40), 10, 10, 10, 0); diff --git a/ground/gcs/src/libs/eigen/test/upperbidiagonalization.cpp b/ground/gcs/src/libs/eigen/test/upperbidiagonalization.cpp index d15bf588b2..847b34b550 100644 --- a/ground/gcs/src/libs/eigen/test/upperbidiagonalization.cpp +++ b/ground/gcs/src/libs/eigen/test/upperbidiagonalization.cpp @@ -35,7 +35,7 @@ void test_upperbidiagonalization() CALL_SUBTEST_1( upperbidiag(MatrixXf(3,3)) ); CALL_SUBTEST_2( upperbidiag(MatrixXd(17,12)) ); CALL_SUBTEST_3( upperbidiag(MatrixXcf(20,20)) ); - CALL_SUBTEST_4( upperbidiag(MatrixXcd(16,15)) ); + CALL_SUBTEST_4( upperbidiag(Matrix,Dynamic,Dynamic,RowMajor>(16,15)) ); CALL_SUBTEST_5( upperbidiag(Matrix()) ); CALL_SUBTEST_6( upperbidiag(Matrix()) ); CALL_SUBTEST_7( upperbidiag(Matrix()) ); diff --git a/ground/gcs/src/libs/eigen/test/vectorization_logic.cpp b/ground/gcs/src/libs/eigen/test/vectorization_logic.cpp index aee68a87f5..83c1439ada 100644 --- a/ground/gcs/src/libs/eigen/test/vectorization_logic.cpp +++ b/ground/gcs/src/libs/eigen/test/vectorization_logic.cpp @@ -1,45 +1,51 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008 Gael Guennebaud +// Copyright (C) 2015 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. +#ifdef EIGEN_TEST_PART_1 +#define EIGEN_UNALIGNED_VECTORIZE 1 +#endif + +#ifdef EIGEN_TEST_PART_2 +#define EIGEN_UNALIGNED_VECTORIZE 0 +#endif + +#ifdef EIGEN_DEFAULT_TO_ROW_MAJOR +#undef EIGEN_DEFAULT_TO_ROW_MAJOR +#endif #define EIGEN_DEBUG_ASSIGN #include "main.h" #include -std::string demangle_traversal(int t) -{ - if(t==DefaultTraversal) return "DefaultTraversal"; - if(t==LinearTraversal) return "LinearTraversal"; - if(t==InnerVectorizedTraversal) return "InnerVectorizedTraversal"; - if(t==LinearVectorizedTraversal) return "LinearVectorizedTraversal"; - if(t==SliceVectorizedTraversal) return "SliceVectorizedTraversal"; - return "?"; -} -std::string demangle_unrolling(int t) -{ - if(t==NoUnrolling) return "NoUnrolling"; - if(t==InnerUnrolling) return "InnerUnrolling"; - if(t==CompleteUnrolling) return "CompleteUnrolling"; - return "?"; -} +using internal::demangle_flags; +using internal::demangle_traversal; +using internal::demangle_unrolling; template bool test_assign(const Dst&, const Src&, int traversal, int unrolling) { - internal::assign_traits::debug(); - bool res = internal::assign_traits::Traversal==traversal - && internal::assign_traits::Unrolling==unrolling; + typedef internal::copy_using_evaluator_traits,internal::evaluator, internal::assign_op > traits; + bool res = traits::Traversal==traversal; + if(unrolling==InnerUnrolling+CompleteUnrolling) + res = res && (int(traits::Unrolling)==InnerUnrolling || int(traits::Unrolling)==CompleteUnrolling); + else + res = res && int(traits::Unrolling)==unrolling; if(!res) { + std::cerr << "Src: " << demangle_flags(Src::Flags) << std::endl; + std::cerr << " " << demangle_flags(internal::evaluator::Flags) << std::endl; + std::cerr << "Dst: " << demangle_flags(Dst::Flags) << std::endl; + std::cerr << " " << demangle_flags(internal::evaluator::Flags) << std::endl; + traits::debug(); std::cerr << " Expected Traversal == " << demangle_traversal(traversal) - << " got " << demangle_traversal(internal::assign_traits::Traversal) << "\n"; + << " got " << demangle_traversal(traits::Traversal) << "\n"; std::cerr << " Expected Unrolling == " << demangle_unrolling(unrolling) - << " got " << demangle_unrolling(internal::assign_traits::Unrolling) << "\n"; + << " got " << demangle_unrolling(traits::Unrolling) << "\n"; } return res; } @@ -47,15 +53,19 @@ bool test_assign(const Dst&, const Src&, int traversal, int unrolling) template bool test_assign(int traversal, int unrolling) { - internal::assign_traits::debug(); - bool res = internal::assign_traits::Traversal==traversal - && internal::assign_traits::Unrolling==unrolling; + typedef internal::copy_using_evaluator_traits,internal::evaluator, internal::assign_op > traits; + bool res = traits::Traversal==traversal && traits::Unrolling==unrolling; if(!res) { + std::cerr << "Src: " << demangle_flags(Src::Flags) << std::endl; + std::cerr << " " << demangle_flags(internal::evaluator::Flags) << std::endl; + std::cerr << "Dst: " << demangle_flags(Dst::Flags) << std::endl; + std::cerr << " " << demangle_flags(internal::evaluator::Flags) << std::endl; + traits::debug(); std::cerr << " Expected Traversal == " << demangle_traversal(traversal) - << " got " << demangle_traversal(internal::assign_traits::Traversal) << "\n"; + << " got " << demangle_traversal(traits::Traversal) << "\n"; std::cerr << " Expected Unrolling == " << demangle_unrolling(unrolling) - << " got " << demangle_unrolling(internal::assign_traits::Unrolling) << "\n"; + << " got " << demangle_unrolling(traits::Unrolling) << "\n"; } return res; } @@ -63,10 +73,16 @@ bool test_assign(int traversal, int unrolling) template bool test_redux(const Xpr&, int traversal, int unrolling) { - typedef internal::redux_traits,Xpr> traits; + typedef typename Xpr::Scalar Scalar; + typedef internal::redux_traits,internal::redux_evaluator > traits; + bool res = traits::Traversal==traversal && traits::Unrolling==unrolling; if(!res) { + std::cerr << demangle_flags(Xpr::Flags) << std::endl; + std::cerr << demangle_flags(internal::evaluator::Flags) << std::endl; + traits::debug(); + std::cerr << " Expected Traversal == " << demangle_traversal(traversal) << " got " << demangle_traversal(traits::Traversal) << "\n"; std::cerr << " Expected Unrolling == " << demangle_unrolling(unrolling) @@ -75,10 +91,16 @@ bool test_redux(const Xpr&, int traversal, int unrolling) return res; } -template::Vectorizable> struct vectorization_logic +template::Vectorizable> +struct vectorization_logic { + typedef internal::packet_traits PacketTraits; + + typedef typename internal::packet_traits::type PacketType; + typedef typename internal::unpacket_traits::half HalfPacketType; enum { - PacketSize = internal::packet_traits::size + PacketSize = internal::unpacket_traits::size, + HalfPacketSize = internal::unpacket_traits::size }; static void run() { @@ -90,8 +112,8 @@ template::Vectori typedef Matrix Matrix22; typedef Matrix Matrix44; typedef Matrix Matrix44u; - typedef Matrix Matrix44c; - typedef Matrix Matrix44r; + typedef Matrix Matrix44c; + typedef Matrix Matrix44r; typedef Matrix::Vectori InnerVectorizedTraversal,InnerUnrolling)); VERIFY(test_assign(Matrix44u(),Matrix44()+Matrix44(), - LinearTraversal,NoUnrolling)); + EIGEN_UNALIGNED_VECTORIZE ? InnerVectorizedTraversal : LinearTraversal, + EIGEN_UNALIGNED_VECTORIZE ? InnerUnrolling : NoUnrolling)); + + VERIFY(test_assign(Matrix1(),Matrix1()+Matrix1(), + (Matrix1::InnerSizeAtCompileTime % PacketSize)==0 ? InnerVectorizedTraversal : LinearVectorizedTraversal, + CompleteUnrolling)); VERIFY(test_assign(Matrix1u(),Matrix1()+Matrix1(), - LinearTraversal,CompleteUnrolling)); + EIGEN_UNALIGNED_VECTORIZE ? ((Matrix1::InnerSizeAtCompileTime % PacketSize)==0 ? InnerVectorizedTraversal : LinearVectorizedTraversal) + : LinearTraversal, CompleteUnrolling)); VERIFY(test_assign(Matrix44c().col(1),Matrix44c().col(2)+Matrix44c().col(3), InnerVectorizedTraversal,CompleteUnrolling)); - + VERIFY(test_assign(Matrix44r().row(2),Matrix44r().row(1)+Matrix44r().row(1), InnerVectorizedTraversal,CompleteUnrolling)); - + if(PacketSize>1) { typedef Matrix Matrix33c; + typedef Matrix Vector3; VERIFY(test_assign(Matrix33c().row(2),Matrix33c().row(1)+Matrix33c().row(1), LinearTraversal,CompleteUnrolling)); + VERIFY(test_assign(Vector3(),Vector3()+Vector3(), + EIGEN_UNALIGNED_VECTORIZE ? (HalfPacketSize==1 ? InnerVectorizedTraversal : LinearVectorizedTraversal) : (HalfPacketSize==1 ? InnerVectorizedTraversal : LinearTraversal), CompleteUnrolling)); VERIFY(test_assign(Matrix33c().col(0),Matrix33c().col(1)+Matrix33c().col(1), - LinearTraversal,CompleteUnrolling)); - - VERIFY(test_assign(Matrix3(),Matrix3().cwiseQuotient(Matrix3()), + EIGEN_UNALIGNED_VECTORIZE ? (HalfPacketSize==1 ? InnerVectorizedTraversal : LinearVectorizedTraversal) : (HalfPacketSize==1 ? SliceVectorizedTraversal : LinearTraversal), + ((!EIGEN_UNALIGNED_VECTORIZE) && HalfPacketSize==1) ? NoUnrolling : CompleteUnrolling)); + + VERIFY(test_assign(Matrix3(),Matrix3().cwiseProduct(Matrix3()), LinearVectorizedTraversal,CompleteUnrolling)); VERIFY(test_assign(Matrix(),Matrix()+Matrix(), - LinearTraversal,NoUnrolling)); + HalfPacketSize==1 ? InnerVectorizedTraversal : + EIGEN_UNALIGNED_VECTORIZE ? LinearVectorizedTraversal : + LinearTraversal, + NoUnrolling)); - VERIFY(test_assign(Matrix11(),Matrix().template block(2,3)+Matrix().template block(10,4), - DefaultTraversal,CompleteUnrolling)); + VERIFY(test_assign(Matrix11(), Matrix11()+Matrix11(),InnerVectorizedTraversal,CompleteUnrolling)); + + + VERIFY(test_assign(Matrix11(),Matrix().template block(2,3)+Matrix().template block(8,4), + (EIGEN_UNALIGNED_VECTORIZE) ? InnerVectorizedTraversal : DefaultTraversal, CompleteUnrolling|InnerUnrolling)); + + VERIFY(test_assign(Vector1(),Matrix11()*Vector1(), + InnerVectorizedTraversal,CompleteUnrolling)); + + VERIFY(test_assign(Matrix11(),Matrix11().lazyProduct(Matrix11()), + InnerVectorizedTraversal,InnerUnrolling+CompleteUnrolling)); } - + + VERIFY(test_redux(Vector1(), + LinearVectorizedTraversal,CompleteUnrolling)); + + VERIFY(test_redux(Matrix(), + LinearVectorizedTraversal,CompleteUnrolling)); + VERIFY(test_redux(Matrix3(), LinearVectorizedTraversal,CompleteUnrolling)); @@ -174,18 +224,19 @@ template::Vectori VERIFY(test_redux(Matrix44r().template block<1,2*PacketSize>(2,1), LinearVectorizedTraversal,CompleteUnrolling)); - + VERIFY((test_assign< - Map >, + Map >, Matrix22 >(InnerVectorizedTraversal,CompleteUnrolling))); VERIFY((test_assign< - Map >, - Matrix22 - >(DefaultTraversal,CompleteUnrolling))); + Map, AlignedMax, InnerStride<3*PacketSize> >, + Matrix + >(DefaultTraversal,PacketSize>=8?InnerUnrolling:CompleteUnrolling))); - VERIFY((test_assign(Matrix11(), Matrix11()*Matrix11(), InnerVectorizedTraversal, CompleteUnrolling))); + VERIFY((test_assign(Matrix11(), Matrix()*Matrix(), + InnerVectorizedTraversal, CompleteUnrolling))); #endif VERIFY(test_assign(MatrixXX(10,10),MatrixXX(20,20).block(10,10,2,3), @@ -193,12 +244,138 @@ template::Vectori VERIFY(test_redux(VectorX(10), LinearVectorizedTraversal,NoUnrolling)); + } +}; + +template struct vectorization_logic +{ + static void run() {} +}; + +template::type>::half, + typename internal::packet_traits::type>::value > +struct vectorization_logic_half +{ + typedef internal::packet_traits PacketTraits; + typedef typename internal::unpacket_traits::type>::half PacketType; + enum { + PacketSize = internal::unpacket_traits::size + }; + static void run() + { + + typedef Matrix Vector1; + typedef Matrix Matrix11; + typedef Matrix Matrix57; + typedef Matrix Matrix35; + typedef Matrix Matrix57u; +// typedef Matrix Matrix44; +// typedef Matrix Matrix44u; +// typedef Matrix Matrix44c; +// typedef Matrix Matrix44r; + + typedef Matrix Matrix1; + + typedef Matrix Matrix1u; + // this type is made such that it can only be vectorized when viewed as a linear 1D vector + typedef Matrix Matrix3; + #if !EIGEN_GCC_AND_ARCH_DOESNT_WANT_STACK_ALIGNMENT + VERIFY(test_assign(Vector1(),Vector1(), + InnerVectorizedTraversal,CompleteUnrolling)); + VERIFY(test_assign(Vector1(),Vector1()+Vector1(), + InnerVectorizedTraversal,CompleteUnrolling)); + VERIFY(test_assign(Vector1(),Vector1().template segment(0).derived(), + EIGEN_UNALIGNED_VECTORIZE ? InnerVectorizedTraversal : LinearVectorizedTraversal,CompleteUnrolling)); + VERIFY(test_assign(Vector1(),Scalar(2.1)*Vector1()-Vector1(), + InnerVectorizedTraversal,CompleteUnrolling)); + VERIFY(test_assign(Vector1(),(Scalar(2.1)*Vector1().template segment(0)-Vector1().template segment(0)).derived(), + EIGEN_UNALIGNED_VECTORIZE ? InnerVectorizedTraversal : LinearVectorizedTraversal,CompleteUnrolling)); + VERIFY(test_assign(Vector1(),Vector1().cwiseProduct(Vector1()), + InnerVectorizedTraversal,CompleteUnrolling)); + VERIFY(test_assign(Vector1(),Vector1().template cast(), + InnerVectorizedTraversal,CompleteUnrolling)); + + + VERIFY(test_assign(Vector1(),Vector1(), + InnerVectorizedTraversal,CompleteUnrolling)); + VERIFY(test_assign(Vector1(),Vector1()+Vector1(), + InnerVectorizedTraversal,CompleteUnrolling)); + VERIFY(test_assign(Vector1(),Vector1().cwiseProduct(Vector1()), + InnerVectorizedTraversal,CompleteUnrolling)); + + VERIFY(test_assign(Matrix57(),Matrix57()+Matrix57(), + InnerVectorizedTraversal,InnerUnrolling)); + + VERIFY(test_assign(Matrix57u(),Matrix57()+Matrix57(), + EIGEN_UNALIGNED_VECTORIZE ? InnerVectorizedTraversal : LinearTraversal, + EIGEN_UNALIGNED_VECTORIZE ? InnerUnrolling : NoUnrolling)); + + VERIFY(test_assign(Matrix1u(),Matrix1()+Matrix1(), + EIGEN_UNALIGNED_VECTORIZE ? ((Matrix1::InnerSizeAtCompileTime % PacketSize)==0 ? InnerVectorizedTraversal : LinearVectorizedTraversal) : LinearTraversal,CompleteUnrolling)); + + if(PacketSize>1) + { + typedef Matrix Matrix33c; + VERIFY(test_assign(Matrix33c().row(2),Matrix33c().row(1)+Matrix33c().row(1), + LinearTraversal,CompleteUnrolling)); + VERIFY(test_assign(Matrix33c().col(0),Matrix33c().col(1)+Matrix33c().col(1), + EIGEN_UNALIGNED_VECTORIZE ? (PacketSize==1 ? InnerVectorizedTraversal : LinearVectorizedTraversal) : LinearTraversal,CompleteUnrolling)); + + VERIFY(test_assign(Matrix3(),Matrix3().cwiseQuotient(Matrix3()), + PacketTraits::HasDiv ? LinearVectorizedTraversal : LinearTraversal,CompleteUnrolling)); + + VERIFY(test_assign(Matrix(),Matrix()+Matrix(), + EIGEN_UNALIGNED_VECTORIZE ? (PacketSize==1 ? InnerVectorizedTraversal : LinearVectorizedTraversal) : LinearTraversal, + NoUnrolling)); + + VERIFY(test_assign(Matrix11(),Matrix().template block(2,3)+Matrix().template block(8,4), + EIGEN_UNALIGNED_VECTORIZE ? InnerVectorizedTraversal : DefaultTraversal,PacketSize>4?InnerUnrolling:CompleteUnrolling)); + + VERIFY(test_assign(Vector1(),Matrix11()*Vector1(), + InnerVectorizedTraversal,CompleteUnrolling)); + + VERIFY(test_assign(Matrix11(),Matrix11().lazyProduct(Matrix11()), + InnerVectorizedTraversal,InnerUnrolling+CompleteUnrolling)); + } + + VERIFY(test_redux(Vector1(), + LinearVectorizedTraversal,CompleteUnrolling)); + + VERIFY(test_redux(Matrix(), + LinearVectorizedTraversal,CompleteUnrolling)); + + VERIFY(test_redux(Matrix3(), + LinearVectorizedTraversal,CompleteUnrolling)); + + VERIFY(test_redux(Matrix35(), + LinearVectorizedTraversal,CompleteUnrolling)); + + VERIFY(test_redux(Matrix57().template block(1,0), + DefaultTraversal,CompleteUnrolling)); + + VERIFY((test_assign< + Map, AlignedMax, InnerStride<3*PacketSize> >, + Matrix + >(DefaultTraversal,CompleteUnrolling))); + + VERIFY((test_assign(Matrix57(), Matrix()*Matrix(), + InnerVectorizedTraversal, InnerUnrolling|CompleteUnrolling))); + #endif } }; -template struct vectorization_logic +template struct vectorization_logic_half { static void run() {} }; @@ -208,27 +385,34 @@ void test_vectorization_logic() #ifdef EIGEN_VECTORIZE + CALL_SUBTEST( vectorization_logic::run() ); CALL_SUBTEST( vectorization_logic::run() ); CALL_SUBTEST( vectorization_logic::run() ); CALL_SUBTEST( vectorization_logic >::run() ); CALL_SUBTEST( vectorization_logic >::run() ); + CALL_SUBTEST( vectorization_logic_half::run() ); + CALL_SUBTEST( vectorization_logic_half::run() ); + CALL_SUBTEST( vectorization_logic_half::run() ); + CALL_SUBTEST( vectorization_logic_half >::run() ); + CALL_SUBTEST( vectorization_logic_half >::run() ); + if(internal::packet_traits::Vectorizable) { VERIFY(test_assign(Matrix(),Matrix()+Matrix(), - LinearTraversal,CompleteUnrolling)); + EIGEN_UNALIGNED_VECTORIZE ? LinearVectorizedTraversal : LinearTraversal,CompleteUnrolling)); VERIFY(test_redux(Matrix(), - DefaultTraversal,CompleteUnrolling)); + EIGEN_UNALIGNED_VECTORIZE ? LinearVectorizedTraversal : DefaultTraversal,CompleteUnrolling)); } if(internal::packet_traits::Vectorizable) { VERIFY(test_assign(Matrix(),Matrix()+Matrix(), - LinearTraversal,CompleteUnrolling)); + EIGEN_UNALIGNED_VECTORIZE ? LinearVectorizedTraversal : LinearTraversal,CompleteUnrolling)); VERIFY(test_redux(Matrix(), - DefaultTraversal,CompleteUnrolling)); + EIGEN_UNALIGNED_VECTORIZE ? LinearVectorizedTraversal : DefaultTraversal,CompleteUnrolling)); } #endif // EIGEN_VECTORIZE diff --git a/ground/gcs/src/libs/eigen/test/vectorwiseop.cpp b/ground/gcs/src/libs/eigen/test/vectorwiseop.cpp index d32fd10ccc..f3ab561ee7 100644 --- a/ground/gcs/src/libs/eigen/test/vectorwiseop.cpp +++ b/ground/gcs/src/libs/eigen/test/vectorwiseop.cpp @@ -2,11 +2,13 @@ // for linear algebra. // // Copyright (C) 2011 Benoit Jacob +// Copyright (C) 2015 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. +#define TEST_ENABLE_TEMPORARY_TRACKING #define EIGEN_NO_STATIC_ASSERT #include "main.h" @@ -101,11 +103,11 @@ template void vectorwiseop_array(const ArrayType& m) VERIFY_RAISES_ASSERT(m2.rowwise() /= rowvec.transpose()); VERIFY_RAISES_ASSERT(m1.rowwise() / rowvec.transpose()); - + m2 = m1; // yes, there might be an aliasing issue there but ".rowwise() /=" - // is suppposed to evaluate " m2.colwise().sum()" into to temporary to avoid - // evaluating the reducions multiple times + // is supposed to evaluate " m2.colwise().sum()" into a temporary to avoid + // evaluating the reduction multiple times if(ArrayType::RowsAtCompileTime>2 || ArrayType::RowsAtCompileTime==Dynamic) { m2.rowwise() /= m2.colwise().sum(); @@ -156,16 +158,22 @@ template void vectorwiseop_matrix(const MatrixType& m) VERIFY_IS_APPROX(m2, m1.colwise() + colvec); VERIFY_IS_APPROX(m2.col(c), m1.col(c) + colvec); - VERIFY_RAISES_ASSERT(m2.colwise() += colvec.transpose()); - VERIFY_RAISES_ASSERT(m1.colwise() + colvec.transpose()); + if(rows>1) + { + VERIFY_RAISES_ASSERT(m2.colwise() += colvec.transpose()); + VERIFY_RAISES_ASSERT(m1.colwise() + colvec.transpose()); + } m2 = m1; m2.rowwise() += rowvec; VERIFY_IS_APPROX(m2, m1.rowwise() + rowvec); VERIFY_IS_APPROX(m2.row(r), m1.row(r) + rowvec); - VERIFY_RAISES_ASSERT(m2.rowwise() += rowvec.transpose()); - VERIFY_RAISES_ASSERT(m1.rowwise() + rowvec.transpose()); + if(cols>1) + { + VERIFY_RAISES_ASSERT(m2.rowwise() += rowvec.transpose()); + VERIFY_RAISES_ASSERT(m1.rowwise() + rowvec.transpose()); + } // test substraction @@ -174,29 +182,43 @@ template void vectorwiseop_matrix(const MatrixType& m) VERIFY_IS_APPROX(m2, m1.colwise() - colvec); VERIFY_IS_APPROX(m2.col(c), m1.col(c) - colvec); - VERIFY_RAISES_ASSERT(m2.colwise() -= colvec.transpose()); - VERIFY_RAISES_ASSERT(m1.colwise() - colvec.transpose()); + if(rows>1) + { + VERIFY_RAISES_ASSERT(m2.colwise() -= colvec.transpose()); + VERIFY_RAISES_ASSERT(m1.colwise() - colvec.transpose()); + } m2 = m1; m2.rowwise() -= rowvec; VERIFY_IS_APPROX(m2, m1.rowwise() - rowvec); VERIFY_IS_APPROX(m2.row(r), m1.row(r) - rowvec); - VERIFY_RAISES_ASSERT(m2.rowwise() -= rowvec.transpose()); - VERIFY_RAISES_ASSERT(m1.rowwise() - rowvec.transpose()); - + if(cols>1) + { + VERIFY_RAISES_ASSERT(m2.rowwise() -= rowvec.transpose()); + VERIFY_RAISES_ASSERT(m1.rowwise() - rowvec.transpose()); + } + // test norm rrres = m1.colwise().norm(); VERIFY_IS_APPROX(rrres(c), m1.col(c).norm()); rcres = m1.rowwise().norm(); VERIFY_IS_APPROX(rcres(r), m1.row(r).norm()); - + + VERIFY_IS_APPROX(m1.cwiseAbs().colwise().sum(), m1.colwise().template lpNorm<1>()); + VERIFY_IS_APPROX(m1.cwiseAbs().rowwise().sum(), m1.rowwise().template lpNorm<1>()); + VERIFY_IS_APPROX(m1.cwiseAbs().colwise().maxCoeff(), m1.colwise().template lpNorm()); + VERIFY_IS_APPROX(m1.cwiseAbs().rowwise().maxCoeff(), m1.rowwise().template lpNorm()); + + // regression for bug 1158 + VERIFY_IS_APPROX(m1.cwiseAbs().colwise().sum().x(), m1.col(0).cwiseAbs().sum()); + // test normalized m2 = m1.colwise().normalized(); VERIFY_IS_APPROX(m2.col(c), m1.col(c).normalized()); m2 = m1.rowwise().normalized(); VERIFY_IS_APPROX(m2.row(r), m1.row(r).normalized()); - + // test normalize m2 = m1; m2.colwise().normalize(); @@ -204,14 +226,27 @@ template void vectorwiseop_matrix(const MatrixType& m) m2 = m1; m2.rowwise().normalize(); VERIFY_IS_APPROX(m2.row(r), m1.row(r).normalized()); + + // test with partial reduction of products + Matrix m1m1 = m1 * m1.transpose(); + VERIFY_IS_APPROX( (m1 * m1.transpose()).colwise().sum(), m1m1.colwise().sum()); + Matrix tmp(rows); + VERIFY_EVALUATION_COUNT( tmp = (m1 * m1.transpose()).colwise().sum(), 1); + + m2 = m1.rowwise() - (m1.colwise().sum()/RealScalar(m1.rows())).eval(); + m1 = m1.rowwise() - (m1.colwise().sum()/RealScalar(m1.rows())); + VERIFY_IS_APPROX( m1, m2 ); + VERIFY_EVALUATION_COUNT( m2 = (m1.rowwise() - m1.colwise().sum()/RealScalar(m1.rows())), (MatrixType::RowsAtCompileTime!=1 ? 1 : 0) ); } void test_vectorwiseop() { - CALL_SUBTEST_1(vectorwiseop_array(Array22cd())); - CALL_SUBTEST_2(vectorwiseop_array(Array())); - CALL_SUBTEST_3(vectorwiseop_array(ArrayXXf(3, 4))); - CALL_SUBTEST_4(vectorwiseop_matrix(Matrix4cf())); - CALL_SUBTEST_5(vectorwiseop_matrix(Matrix())); - CALL_SUBTEST_6(vectorwiseop_matrix(MatrixXd(7,2))); + CALL_SUBTEST_1( vectorwiseop_array(Array22cd()) ); + CALL_SUBTEST_2( vectorwiseop_array(Array()) ); + CALL_SUBTEST_3( vectorwiseop_array(ArrayXXf(3, 4)) ); + CALL_SUBTEST_4( vectorwiseop_matrix(Matrix4cf()) ); + CALL_SUBTEST_5( vectorwiseop_matrix(Matrix()) ); + CALL_SUBTEST_6( vectorwiseop_matrix(MatrixXd(internal::random(1,EIGEN_TEST_MAX_SIZE), internal::random(1,EIGEN_TEST_MAX_SIZE))) ); + CALL_SUBTEST_7( vectorwiseop_matrix(VectorXd(internal::random(1,EIGEN_TEST_MAX_SIZE))) ); + CALL_SUBTEST_7( vectorwiseop_matrix(RowVectorXd(internal::random(1,EIGEN_TEST_MAX_SIZE))) ); } diff --git a/ground/gcs/src/libs/eigen/test/zerosized.cpp b/ground/gcs/src/libs/eigen/test/zerosized.cpp index da7dd04814..477ff0070c 100644 --- a/ground/gcs/src/libs/eigen/test/zerosized.cpp +++ b/ground/gcs/src/libs/eigen/test/zerosized.cpp @@ -25,6 +25,7 @@ template void zeroReduction(const MatrixType& m) { template void zeroSizedMatrix() { MatrixType t1; + typedef typename MatrixType::Scalar Scalar; if (MatrixType::SizeAtCompileTime == Dynamic || MatrixType::SizeAtCompileTime == 0) { @@ -37,7 +38,7 @@ template void zeroSizedMatrix() if (MatrixType::RowsAtCompileTime == Dynamic && MatrixType::ColsAtCompileTime == Dynamic) { - MatrixType t2(0, 0); + MatrixType t2(0, 0), t3(t1); VERIFY(t2.rows() == 0); VERIFY(t2.cols() == 0); @@ -45,6 +46,23 @@ template void zeroSizedMatrix() VERIFY(t1==t2); } } + + if(MatrixType::MaxColsAtCompileTime!=0 && MatrixType::MaxRowsAtCompileTime!=0) + { + Index rows = MatrixType::RowsAtCompileTime==Dynamic ? internal::random(1,10) : Index(MatrixType::RowsAtCompileTime); + Index cols = MatrixType::ColsAtCompileTime==Dynamic ? internal::random(1,10) : Index(MatrixType::ColsAtCompileTime); + MatrixType m(rows,cols); + zeroReduction(m.template block<0,MatrixType::ColsAtCompileTime>(0,0,0,cols)); + zeroReduction(m.template block(0,0,rows,0)); + zeroReduction(m.template block<0,1>(0,0)); + zeroReduction(m.template block<1,0>(0,0)); + Matrix prod = m.template block(0,0,rows,0) * m.template block<0,MatrixType::ColsAtCompileTime>(0,0,0,cols); + VERIFY(prod.rows()==rows && prod.cols()==cols); + VERIFY(prod.isZero()); + prod = m.template block<1,0>(0,0) * m.template block<0,1>(0,0); + VERIFY(prod.size()==1); + VERIFY(prod.isZero()); + } } template void zeroSizedVector() diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/AdolcForward b/ground/gcs/src/libs/eigen/unsupported/Eigen/AdolcForward index 2627decd0f..15f5f0731a 100644 --- a/ground/gcs/src/libs/eigen/unsupported/Eigen/AdolcForward +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/AdolcForward @@ -25,7 +25,7 @@ #ifndef NUMBER_DIRECTIONS # define NUMBER_DIRECTIONS 2 #endif -#include +#include // adolc defines some very stupid macros: #if defined(malloc) diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/AlignedVector3 b/ground/gcs/src/libs/eigen/unsupported/Eigen/AlignedVector3 index 29d5c90fb5..47a86d4c00 100644 --- a/ground/gcs/src/libs/eigen/unsupported/Eigen/AlignedVector3 +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/AlignedVector3 @@ -57,6 +57,11 @@ template class AlignedVector3 inline Index rows() const { return 3; } inline Index cols() const { return 1; } + + Scalar* data() { return m_coeffs.data(); } + const Scalar* data() const { return m_coeffs.data(); } + Index innerStride() const { return 1; } + Index outerStride() const { return 3; } inline const Scalar& coeff(Index row, Index col) const { return m_coeffs.coeff(row, col); } @@ -100,7 +105,7 @@ template class AlignedVector3 }; template - inline explicit AlignedVector3(const MatrixBase& other) + inline AlignedVector3(const MatrixBase& other) { generic_assign_selector::run(*this,other.derived()); } @@ -108,6 +113,12 @@ template class AlignedVector3 inline AlignedVector3& operator=(const AlignedVector3& other) { m_coeffs = other.m_coeffs; return *this; } + template + inline AlignedVector3& operator=(const MatrixBase& other) + { + generic_assign_selector::run(*this,other.derived()); + return *this; + } inline AlignedVector3 operator+(const AlignedVector3& other) const { return AlignedVector3(m_coeffs + other.m_coeffs); } @@ -148,7 +159,7 @@ template class AlignedVector3 m_coeffs /= norm(); } - inline AlignedVector3 normalized() + inline AlignedVector3 normalized() const { return AlignedVector3(m_coeffs / norm()); } @@ -181,8 +192,31 @@ template class AlignedVector3 { return m_coeffs.template head<3>().isApprox(other,eps); } + + CoeffType& coeffs() { return m_coeffs; } + const CoeffType& coeffs() const { return m_coeffs; } }; +namespace internal { + +template +struct eval, Dense> +{ + typedef const AlignedVector3<_Scalar>& type; +}; + +template +struct evaluator > + : evaluator > +{ + typedef AlignedVector3 XprType; + typedef evaluator > Base; + + evaluator(const XprType &m) : Base(m.coeffs()) {} +}; + +} + //@} } diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/CMakeLists.txt b/ground/gcs/src/libs/eigen/unsupported/Eigen/CMakeLists.txt index e1fbf97e2b..631a060145 100644 --- a/ground/gcs/src/libs/eigen/unsupported/Eigen/CMakeLists.txt +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/CMakeLists.txt @@ -1,11 +1,32 @@ -set(Eigen_HEADERS AdolcForward AlignedVector3 ArpackSupport AutoDiff BVH FFT IterativeSolvers KroneckerProduct LevenbergMarquardt - MatrixFunctions MoreVectorization MPRealSupport NonLinearOptimization NumericalDiff OpenGLSupport Polynomials - Skyline SparseExtra Splines - ) +set(Eigen_HEADERS + AdolcForward + AlignedVector3 + ArpackSupport + AutoDiff + BVH + EulerAngles + FFT + IterativeSolvers + KroneckerProduct + LevenbergMarquardt + MatrixFunctions + MoreVectorization + MPRealSupport + NonLinearOptimization + NumericalDiff + OpenGLSupport + Polynomials + Skyline + SparseExtra + SpecialFunctions + Splines + ) install(FILES ${Eigen_HEADERS} DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen COMPONENT Devel ) -add_subdirectory(src) +install(DIRECTORY src DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen COMPONENT Devel FILES_MATCHING PATTERN "*.h") + +add_subdirectory(CXX11) diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/CMakeLists.txt b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/CMakeLists.txt new file mode 100644 index 0000000000..385ed240c2 --- /dev/null +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/CMakeLists.txt @@ -0,0 +1,8 @@ +set(Eigen_CXX11_HEADERS Tensor TensorSymmetry ThreadPool) + +install(FILES + ${Eigen_CXX11_HEADERS} + DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen/CXX11 COMPONENT Devel + ) + +install(DIRECTORY src DESTINATION ${INCLUDE_INSTALL_DIR}/unsupported/Eigen/CXX11 COMPONENT Devel FILES_MATCHING PATTERN "*.h") diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/Tensor b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/Tensor new file mode 100644 index 0000000000..7ecb4c74d8 --- /dev/null +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/Tensor @@ -0,0 +1,152 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Benoit Steiner +// Copyright (C) 2013 Christian Seiler +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +//#ifndef EIGEN_CXX11_TENSOR_MODULE +//#define EIGEN_CXX11_TENSOR_MODULE + +#include "../../../Eigen/Core" + +#ifdef EIGEN_USE_SYCL +#undef min +#undef max +#undef isnan +#undef isinf +#undef isfinite +#include +#include +#include +#include +#endif + +#include + +#include "../SpecialFunctions" +#include "src/util/CXX11Meta.h" +#include "src/util/MaxSizeVector.h" + +/** \defgroup CXX11_Tensor_Module Tensor Module + * + * This module provides a Tensor class for storing arbitrarily indexed + * objects. + * + * \code + * #include + * \endcode + */ + +#include +#include +#include + +#ifdef _WIN32 +typedef __int16 int16_t; +typedef unsigned __int16 uint16_t; +typedef __int32 int32_t; +typedef unsigned __int32 uint32_t; +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; +#else +#include +#endif + +#if __cplusplus > 199711 || EIGEN_COMP_MSVC >= 1900 +#include +#endif + +#ifdef _WIN32 +#include +#elif defined(__APPLE__) +#include +#else +#include +#endif + +#ifdef EIGEN_USE_THREADS +#include "ThreadPool" +#endif + +#ifdef EIGEN_USE_GPU +#include +#include +#if __cplusplus >= 201103L +#include +#include +#endif +#endif + +#include "src/Tensor/TensorMacros.h" +#include "src/Tensor/TensorForwardDeclarations.h" +#include "src/Tensor/TensorMeta.h" +#include "src/Tensor/TensorFunctors.h" +#include "src/Tensor/TensorCostModel.h" +#include "src/Tensor/TensorDeviceDefault.h" +#include "src/Tensor/TensorDeviceThreadPool.h" +#include "src/Tensor/TensorDeviceCuda.h" +#include "src/Tensor/TensorDeviceSycl.h" +#include "src/Tensor/TensorIndexList.h" +#include "src/Tensor/TensorDimensionList.h" +#include "src/Tensor/TensorDimensions.h" +#include "src/Tensor/TensorInitializer.h" +#include "src/Tensor/TensorTraits.h" +#include "src/Tensor/TensorRandom.h" +#include "src/Tensor/TensorUInt128.h" +#include "src/Tensor/TensorIntDiv.h" +#include "src/Tensor/TensorGlobalFunctions.h" + +#include "src/Tensor/TensorBase.h" + +#include "src/Tensor/TensorEvaluator.h" +#include "src/Tensor/TensorExpr.h" +#include "src/Tensor/TensorReduction.h" +#include "src/Tensor/TensorReductionCuda.h" +#include "src/Tensor/TensorArgMax.h" +#include "src/Tensor/TensorConcatenation.h" +#include "src/Tensor/TensorContractionMapper.h" +#include "src/Tensor/TensorContractionBlocking.h" +#include "src/Tensor/TensorContraction.h" +#include "src/Tensor/TensorContractionThreadPool.h" +#include "src/Tensor/TensorContractionCuda.h" +#include "src/Tensor/TensorConversion.h" +#include "src/Tensor/TensorConvolution.h" +#include "src/Tensor/TensorFFT.h" +#include "src/Tensor/TensorPatch.h" +#include "src/Tensor/TensorImagePatch.h" +#include "src/Tensor/TensorVolumePatch.h" +#include "src/Tensor/TensorBroadcasting.h" +#include "src/Tensor/TensorChipping.h" +#include "src/Tensor/TensorInflation.h" +#include "src/Tensor/TensorLayoutSwap.h" +#include "src/Tensor/TensorMorphing.h" +#include "src/Tensor/TensorPadding.h" +#include "src/Tensor/TensorReverse.h" +#include "src/Tensor/TensorShuffling.h" +#include "src/Tensor/TensorStriding.h" +#include "src/Tensor/TensorCustomOp.h" +#include "src/Tensor/TensorEvalTo.h" +#include "src/Tensor/TensorForcedEval.h" +#include "src/Tensor/TensorGenerator.h" +#include "src/Tensor/TensorAssign.h" +#include "src/Tensor/TensorScan.h" + +#include "src/Tensor/TensorSycl.h" +#include "src/Tensor/TensorExecutor.h" +#include "src/Tensor/TensorDevice.h" + +#include "src/Tensor/TensorStorage.h" +#include "src/Tensor/Tensor.h" +#include "src/Tensor/TensorFixedSize.h" +#include "src/Tensor/TensorMap.h" +#include "src/Tensor/TensorRef.h" + +#include "src/Tensor/TensorIO.h" + +#include + +//#endif // EIGEN_CXX11_TENSOR_MODULE diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/TensorSymmetry b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/TensorSymmetry new file mode 100644 index 0000000000..fb1b0c0fbc --- /dev/null +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/TensorSymmetry @@ -0,0 +1,42 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2013 Christian Seiler +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CXX11_TENSORSYMMETRY_MODULE +#define EIGEN_CXX11_TENSORSYMMETRY_MODULE + +#include + +#include + +#include "src/util/CXX11Meta.h" + +/** \defgroup CXX11_TensorSymmetry_Module Tensor Symmetry Module + * + * This module provides a classes that allow for the definition of + * symmetries w.r.t. tensor indices. + * + * Including this module will implicitly include the Tensor module. + * + * \code + * #include + * \endcode + */ + +#include "src/TensorSymmetry/util/TemplateGroupTheory.h" +#include "src/TensorSymmetry/Symmetry.h" +#include "src/TensorSymmetry/StaticSymmetry.h" +#include "src/TensorSymmetry/DynamicSymmetry.h" + +#include + +#endif // EIGEN_CXX11_TENSORSYMMETRY_MODULE + +/* + * kate: space-indent on; indent-width 2; mixedindent off; indent-mode cstyle; + */ diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/ThreadPool b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/ThreadPool new file mode 100644 index 0000000000..09d637e9a0 --- /dev/null +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/ThreadPool @@ -0,0 +1,65 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2016 Benoit Steiner +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CXX11_THREADPOOL_MODULE +#define EIGEN_CXX11_THREADPOOL_MODULE + +#include "../../../Eigen/Core" + +#include + +/** \defgroup CXX11_ThreadPool_Module C++11 ThreadPool Module + * + * This module provides 2 threadpool implementations + * - a simple reference implementation + * - a faster non blocking implementation + * + * This module requires C++11. + * + * \code + * #include + * \endcode + */ + + +// The code depends on CXX11, so only include the module if the +// compiler supports it. +#if __cplusplus > 199711L || EIGEN_COMP_MSVC >= 1900 +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "src/util/CXX11Meta.h" +#include "src/util/MaxSizeVector.h" + +#include "src/ThreadPool/ThreadLocal.h" +#include "src/ThreadPool/ThreadYield.h" +#include "src/ThreadPool/EventCount.h" +#include "src/ThreadPool/RunQueue.h" +#include "src/ThreadPool/ThreadPoolInterface.h" +#include "src/ThreadPool/ThreadEnvironment.h" +#include "src/ThreadPool/SimpleThreadPool.h" +#include "src/ThreadPool/NonBlockingThreadPool.h" + +#endif + +#include + +#endif // EIGEN_CXX11_THREADPOOL_MODULE + diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/README.md b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/README.md new file mode 100644 index 0000000000..02146527b5 --- /dev/null +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/README.md @@ -0,0 +1,1757 @@ +# Eigen Tensors + +Tensors are multidimensional arrays of elements. Elements are typically scalars, +but more complex types such as strings are also supported. + +[TOC] + +## Tensor Classes + +You can manipulate a tensor with one of the following classes. They all are in +the namespace ```::Eigen.``` + + +### Class Tensor + +This is the class to use to create a tensor and allocate memory for it. The +class is templatized with the tensor datatype, such as float or int, and the +tensor rank. The rank is the number of dimensions, for example rank 2 is a +matrix. + +Tensors of this class are resizable. For example, if you assign a tensor of a +different size to a Tensor, that tensor is resized to match its new value. + +#### Constructor Tensor(size0, size1, ...) + +Constructor for a Tensor. The constructor must be passed ```rank``` integers +indicating the sizes of the instance along each of the the ```rank``` +dimensions. + + // Create a tensor of rank 3 of sizes 2, 3, 4. This tensor owns + // memory to hold 24 floating point values (24 = 2 x 3 x 4). + Tensor t_3d(2, 3, 4); + + // Resize t_3d by assigning a tensor of different sizes, but same rank. + t_3d = Tensor(3, 4, 3); + +#### Constructor Tensor(size_array) + +Constructor where the sizes for the constructor are specified as an array of +values instead of an explicitly list of parameters. The array type to use is +```Eigen::array```. The array can be constructed automatically +from an initializer list. + + // Create a tensor of strings of rank 2 with sizes 5, 7. + Tensor t_2d({5, 7}); + + +### Class TensorFixedSize> + +Class to use for tensors of fixed size, where the size is known at compile +time. Fixed sized tensors can provide very fast computations because all their +dimensions are known by the compiler. FixedSize tensors are not resizable. + +If the total number of elements in a fixed size tensor is small enough the +tensor data is held onto the stack and does not cause heap allocation and free. + + // Create a 4 x 3 tensor of floats. + TensorFixedSize> t_4x3; + +### Class TensorMap> + +This is the class to use to create a tensor on top of memory allocated and +owned by another part of your code. It allows to view any piece of allocated +memory as a Tensor. Instances of this class do not own the memory where the +data are stored. + +A TensorMap is not resizable because it does not own the memory where its data +are stored. + +#### Constructor TensorMap>(data, size0, size1, ...) + +Constructor for a Tensor. The constructor must be passed a pointer to the +storage for the data, and "rank" size attributes. The storage has to be +large enough to hold all the data. + + // Map a tensor of ints on top of stack-allocated storage. + int storage[128]; // 2 x 4 x 2 x 8 = 128 + TensorMap t_4d(storage, 2, 4, 2, 8); + + // The same storage can be viewed as a different tensor. + // You can also pass the sizes as an array. + TensorMap t_2d(storage, 16, 8); + + // You can also map fixed-size tensors. Here we get a 1d view of + // the 2d fixed-size tensor. + Tensor> t_4x3; + TensorMap t_12(t_4x3, 12); + + +#### Class TensorRef + +See Assigning to a TensorRef below. + +## Accessing Tensor Elements + +#### tensor(index0, index1...) + +Return the element at position ```(index0, index1...)``` in tensor +```tensor```. You must pass as many parameters as the rank of ```tensor```. +The expression can be used as an l-value to set the value of the element at the +specified position. The value returned is of the datatype of the tensor. + + // Set the value of the element at position (0, 1, 0); + Tensor t_3d(2, 3, 4); + t_3d(0, 1, 0) = 12.0f; + + // Initialize all elements to random values. + for (int i = 0; i < 2; ++i) { + for (int j = 0; j < 3; ++j) { + for (int k = 0; k < 4; ++k) { + t_3d(i, j, k) = ...some random value...; + } + } + } + + // Print elements of a tensor. + for (int i = 0; i < 2; ++i) { + LOG(INFO) << t_3d(i, 0, 0); + } + + +## TensorLayout + +The tensor library supports 2 layouts: ```ColMajor``` (the default) and +```RowMajor```. Only the default column major layout is currently fully +supported, and it is therefore not recommended to attempt to use the row major +layout at the moment. + +The layout of a tensor is optionally specified as part of its type. If not +specified explicitly column major is assumed. + + Tensor col_major; // equivalent to Tensor + TensorMap > row_major(data, ...); + +All the arguments to an expression must use the same layout. Attempting to mix +different layouts will result in a compilation error. + +It is possible to change the layout of a tensor or an expression using the +```swap_layout()``` method. Note that this will also reverse the order of the +dimensions. + + Tensor col_major(2, 4); + Tensor row_major(2, 4); + + Tensor col_major_result = col_major; // ok, layouts match + Tensor col_major_result = row_major; // will not compile + + // Simple layout swap + col_major_result = row_major.swap_layout(); + eigen_assert(col_major_result.dimension(0) == 4); + eigen_assert(col_major_result.dimension(1) == 2); + + // Swap the layout and preserve the order of the dimensions + array shuffle(1, 0); + col_major_result = row_major.swap_layout().shuffle(shuffle); + eigen_assert(col_major_result.dimension(0) == 2); + eigen_assert(col_major_result.dimension(1) == 4); + + +## Tensor Operations + +The Eigen Tensor library provides a vast library of operations on Tensors: +numerical operations such as addition and multiplication, geometry operations +such as slicing and shuffling, etc. These operations are available as methods +of the Tensor classes, and in some cases as operator overloads. For example +the following code computes the elementwise addition of two tensors: + + Tensor t1(2, 3, 4); + ...set some values in t1... + Tensor t2(2, 3, 4); + ...set some values in t2... + // Set t3 to the element wise sum of t1 and t2 + Tensor t3 = t1 + t2; + +While the code above looks easy enough, it is important to understand that the +expression ```t1 + t2``` is not actually adding the values of the tensors. The +expression instead constructs a "tensor operator" object of the class +TensorCwiseBinaryOp, which has references to the tensors +```t1``` and ```t2```. This is a small C++ object that knows how to add +```t1``` and ```t2```. It is only when the value of the expression is assigned +to the tensor ```t3``` that the addition is actually performed. Technically, +this happens through the overloading of ```operator=()``` in the Tensor class. + +This mechanism for computing tensor expressions allows for lazy evaluation and +optimizations which are what make the tensor library very fast. + +Of course, the tensor operators do nest, and the expression ```t1 + t2 * +0.3f``` is actually represented with the (approximate) tree of operators: + + TensorCwiseBinaryOp(t1, TensorCwiseUnaryOp(t2, 0.3f)) + + +### Tensor Operations and C++ "auto" + +Because Tensor operations create tensor operators, the C++ ```auto``` keyword +does not have its intuitive meaning. Consider these 2 lines of code: + + Tensor t3 = t1 + t2; + auto t4 = t1 + t2; + +In the first line we allocate the tensor ```t3``` and it will contain the +result of the addition of ```t1``` and ```t2```. In the second line, ```t4``` +is actually the tree of tensor operators that will compute the addition of +```t1``` and ```t2```. In fact, ```t4``` is *not* a tensor and you cannot get +the values of its elements: + + Tensor t3 = t1 + t2; + cout << t3(0, 0, 0); // OK prints the value of t1(0, 0, 0) + t2(0, 0, 0) + + auto t4 = t1 + t2; + cout << t4(0, 0, 0); // Compilation error! + +When you use ```auto``` you do not get a Tensor as a result but instead a +non-evaluated expression. So only use ```auto``` to delay evaluation. + +Unfortunately, there is no single underlying concrete type for holding +non-evaluated expressions, hence you have to use auto in the case when you do +want to hold non-evaluated expressions. + +When you need the results of set of tensor computations you have to assign the +result to a Tensor that will be capable of holding onto them. This can be +either a normal Tensor, a fixed size Tensor, or a TensorMap on an existing +piece of memory. All the following will work: + + auto t4 = t1 + t2; + + Tensor result = t4; // Could also be: result(t4); + cout << result(0, 0, 0); + + TensorMap result(, , ...) = t4; + cout << result(0, 0, 0); + + TensorFixedSize> result = t4; + cout << result(0, 0, 0); + +Until you need the results, you can keep the operation around, and even reuse +it for additional operations. As long as you keep the expression as an +operation, no computation is performed. + + // One way to compute exp((t1 + t2) * 0.2f); + auto t3 = t1 + t2; + auto t4 = t3 * 0.2f; + auto t5 = t4.exp(); + Tensor result = t5; + + // Another way, exactly as efficient as the previous one: + Tensor result = ((t1 + t2) * 0.2f).exp(); + +### Controlling When Expression are Evaluated + +There are several ways to control when expressions are evaluated: + +* Assignment to a Tensor, TensorFixedSize, or TensorMap. +* Use of the eval() method. +* Assignment to a TensorRef. + +#### Assigning to a Tensor, TensorFixedSize, or TensorMap. + +The most common way to evaluate an expression is to assign it to a Tensor. In +the example below, the ```auto``` declarations make the intermediate values +"Operations", not Tensors, and do not cause the expressions to be evaluated. +The assignment to the Tensor ```result``` causes the evaluation of all the +operations. + + auto t3 = t1 + t2; // t3 is an Operation. + auto t4 = t3 * 0.2f; // t4 is an Operation. + auto t5 = t4.exp(); // t5 is an Operation. + Tensor result = t5; // The operations are evaluated. + +If you know the ranks and sizes of the Operation value you can assign the +Operation to a TensorFixedSize instead of a Tensor, which is a bit more +efficient. + + // We know that the result is a 4x4x2 tensor! + TensorFixedSize result = t5; + +Simiarly, assigning an expression to a TensorMap causes its evaluation. Like +tensors of type TensorFixedSize, TensorMaps cannot be resized so they have to +have the rank and sizes of the expression that are assigned to them. + +#### Calling eval(). + +When you compute large composite expressions, you sometimes want to tell Eigen +that an intermediate value in the expression tree is worth evaluating ahead of +time. This is done by inserting a call to the ```eval()``` method of the +expression Operation. + + // The previous example could have been written: + Tensor result = ((t1 + t2) * 0.2f).exp(); + + // If you want to compute (t1 + t2) once ahead of time you can write: + Tensor result = ((t1 + t2).eval() * 0.2f).exp(); + +Semantically, calling ```eval()``` is equivalent to materializing the value of +the expression in a temporary Tensor of the right size. The code above in +effect does: + + // .eval() knows the size! + TensorFixedSize tmp = t1 + t2; + Tensor result = (tmp * 0.2f).exp(); + +Note that the return value of ```eval()``` is itself an Operation, so the +following code does not do what you may think: + + // Here t3 is an evaluation Operation. t3 has not been evaluated yet. + auto t3 = (t1 + t2).eval(); + + // You can use t3 in another expression. Still no evaluation. + auto t4 = (t3 * 0.2f).exp(); + + // The value is evaluated when you assign the Operation to a Tensor, using + // an intermediate tensor to represent t3.x + Tensor result = t4; + +While in the examples above calling ```eval()``` does not make a difference in +performance, in other cases it can make a huge difference. In the expression +below the ```broadcast()``` expression causes the ```X.maximum()``` expression +to be evaluated many times: + + Tensor<...> X ...; + Tensor<...> Y = ((X - X.maximum(depth_dim).reshape(dims2d).broadcast(bcast)) + * beta).exp(); + +Inserting a call to ```eval()``` between the ```maximum()``` and +```reshape()``` calls guarantees that maximum() is only computed once and +greatly speeds-up execution: + + Tensor<...> Y = + ((X - X.maximum(depth_dim).eval().reshape(dims2d).broadcast(bcast)) + * beta).exp(); + +In the other example below, the tensor ```Y``` is both used in the expression +and its assignment. This is an aliasing problem and if the evaluation is not +done in the right order Y will be updated incrementally during the evaluation +resulting in bogus results: + + Tensor<...> Y ...; + Y = Y / (Y.sum(depth_dim).reshape(dims2d).broadcast(bcast)); + +Inserting a call to ```eval()``` between the ```sum()``` and ```reshape()``` +expressions ensures that the sum is computed before any updates to ```Y``` are +done. + + Y = Y / (Y.sum(depth_dim).eval().reshape(dims2d).broadcast(bcast)); + +Note that an eval around the full right hand side expression is not needed +because the generated has to compute the i-th value of the right hand side +before assigning it to the left hand side. + +However, if you were assigning the expression value to a shuffle of ```Y``` +then you would need to force an eval for correctness by adding an ```eval()``` +call for the right hand side: + + Y.shuffle(...) = + (Y / (Y.sum(depth_dim).eval().reshape(dims2d).broadcast(bcast))).eval(); + + +#### Assigning to a TensorRef. + +If you need to access only a few elements from the value of an expression you +can avoid materializing the value in a full tensor by using a TensorRef. + +A TensorRef is a small wrapper class for any Eigen Operation. It provides +overloads for the ```()``` operator that let you access individual values in +the expression. TensorRef is convenient, because the Operation themselves do +not provide a way to access individual elements. + + // Create a TensorRef for the expression. The expression is not + // evaluated yet. + TensorRef > ref = ((t1 + t2) * 0.2f).exp(); + + // Use "ref" to access individual elements. The expression is evaluated + // on the fly. + float at_0 = ref(0, 0, 0); + cout << ref(0, 1, 0); + +Only use TensorRef when you need a subset of the values of the expression. +TensorRef only computes the values you access. However note that if you are +going to access all the values it will be much faster to materialize the +results in a Tensor first. + +In some cases, if the full Tensor result would be very large, you may save +memory by accessing it as a TensorRef. But not always. So don't count on it. + + +### Controlling How Expressions Are Evaluated + +The tensor library provides several implementations of the various operations +such as contractions and convolutions. The implementations are optimized for +different environments: single threaded on CPU, multi threaded on CPU, or on a +GPU using cuda. Additional implementations may be added later. + +You can choose which implementation to use with the ```device()``` call. If +you do not choose an implementation explicitly the default implementation that +uses a single thread on the CPU is used. + +The default implementation has been optimized for recent Intel CPUs, taking +advantage of SSE, AVX, and FMA instructions. Work is ongoing to tune the +library on ARM CPUs. Note that you need to pass compiler-dependent flags +to enable the use of SSE, AVX, and other instructions. + +For example, the following code adds two tensors using the default +single-threaded CPU implementation: + + Tensor a(30, 40); + Tensor b(30, 40); + Tensor c = a + b; + +To choose a different implementation you have to insert a ```device()``` call +before the assignment of the result. For technical C++ reasons this requires +that the Tensor for the result be declared on its own. This means that you +have to know the size of the result. + + Eigen::Tensor c(30, 40); + c.device(...) = a + b; + +The call to ```device()``` must be the last call on the left of the operator=. + +You must pass to the ```device()``` call an Eigen device object. There are +presently three devices you can use: DefaultDevice, ThreadPoolDevice and +GpuDevice. + + +#### Evaluating With the DefaultDevice + +This is exactly the same as not inserting a ```device()``` call. + + DefaultDevice my_device; + c.device(my_device) = a + b; + +#### Evaluating with a Thread Pool + + // Create the Eigen ThreadPoolDevice. + Eigen::ThreadPoolDevice my_device(4 /* number of threads to use */); + + // Now just use the device when evaluating expressions. + Eigen::Tensor c(30, 50); + c.device(my_device) = a.contract(b, dot_product_dims); + + +#### Evaluating On GPU + +This is presently a bit more complicated than just using a thread pool device. +You need to create a GPU device but you also need to explicitly allocate the +memory for tensors with cuda. + + +## API Reference + +### Datatypes + +In the documentation of the tensor methods and Operation we mention datatypes +that are tensor-type specific: + +#### ::Dimensions + +Acts like an array of ints. Has an ```int size``` attribute, and can be +indexed like an array to access individual values. Used to represent the +dimensions of a tensor. See ```dimensions()```. + +#### ::Index + +Acts like an ```int```. Used for indexing tensors along their dimensions. See +```operator()```, ```dimension()```, and ```size()```. + +#### ::Scalar + +Represents the datatype of individual tensor elements. For example, for a +```Tensor```, ```Scalar``` is the type ```float```. See +```setConstant()```. + +#### + +We use this pseudo type to indicate that a tensor Operation is returned by a +method. We indicate in the text the type and dimensions of the tensor that the +Operation returns after evaluation. + +The Operation will have to be evaluated, for example by assigning it to a +tensor, before you can access the values of the resulting tensor. You can also +access the values through a TensorRef. + + +## Built-in Tensor Methods + +These are usual C++ methods that act on tensors immediately. They are not +Operations which provide delayed evaluation of their results. Unless specified +otherwise, all the methods listed below are available on all tensor classes: +Tensor, TensorFixedSize, and TensorMap. + +## Metadata + +### int NumDimensions + +Constant value indicating the number of dimensions of a Tensor. This is also +known as the tensor "rank". + + Eigen::Tensor a(3, 4); + cout << "Dims " << a.NumDimensions; + => Dims 2 + +### Dimensions dimensions() + +Returns an array-like object representing the dimensions of the tensor. +The actual type of the dimensions() result is ::Dimensions. + + Eigen::Tensor a(3, 4); + const Eigen::Tensor::Dimensions& d = a.dimensions(); + cout << "Dim size: " << d.size << ", dim 0: " << d[0] + << ", dim 1: " << d[1]; + => Dim size: 2, dim 0: 3, dim 1: 4 + +If you use a C++11 compiler, you can use ```auto``` to simplify the code: + + const auto& d = a.dimensions(); + cout << "Dim size: " << d.size << ", dim 0: " << d[0] + << ", dim 1: " << d[1]; + => Dim size: 2, dim 0: 3, dim 1: 4 + +### Index dimension(Index n) + +Returns the n-th dimension of the tensor. The actual type of the +```dimension()``` result is ```::Index```, but you can +always use it like an int. + + Eigen::Tensor a(3, 4); + int dim1 = a.dimension(1); + cout << "Dim 1: " << dim1; + => Dim 1: 4 + +### Index size() + +Returns the total number of elements in the tensor. This is the product of all +the tensor dimensions. The actual type of the ```size()``` result is +```::Index```, but you can always use it like an int. + + Eigen::Tensor a(3, 4); + cout << "Size: " << a.size(); + => Size: 12 + + +### Getting Dimensions From An Operation + +A few operations provide ```dimensions()``` directly, +e.g. ```TensorReslicingOp```. Most operations defer calculating dimensions +until the operation is being evaluated. If you need access to the dimensions +of a deferred operation, you can wrap it in a TensorRef (see Assigning to a +TensorRef above), which provides ```dimensions()``` and ```dimension()``` as +above. + +TensorRef can also wrap the plain Tensor types, so this is a useful idiom in +templated contexts where the underlying object could be either a raw Tensor +or some deferred operation (e.g. a slice of a Tensor). In this case, the +template code can wrap the object in a TensorRef and reason about its +dimensionality while remaining agnostic to the underlying type. + + +## Constructors + +### Tensor + +Creates a tensor of the specified size. The number of arguments must be equal +to the rank of the tensor. The content of the tensor is not initialized. + + Eigen::Tensor a(3, 4); + cout << "NumRows: " << a.dimension(0) << " NumCols: " << a.dimension(1) << endl; + => NumRows: 3 NumCols: 4 + +### TensorFixedSize + +Creates a tensor of the specified size. The number of arguments in the Size<> +template parameter determines the rank of the tensor. The content of the tensor +is not initialized. + + Eigen::TensorFixedSize> a; + cout << "Rank: " << a.rank() << endl; + => Rank: 2 + cout << "NumRows: " << a.dimension(0) << " NumCols: " << a.dimension(1) << endl; + => NumRows: 3 NumCols: 4 + +### TensorMap + +Creates a tensor mapping an existing array of data. The data must not be freed +until the TensorMap is discarded, and the size of the data must be large enough +to accomodate of the coefficients of the tensor. + + float data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; + Eigen::TensorMap a(data, 3, 4); + cout << "NumRows: " << a.dimension(0) << " NumCols: " << a.dimension(1) << endl; + => NumRows: 3 NumCols: 4 + cout << "a(1, 2): " << a(1, 2) << endl; + => a(1, 2): 9 + + +## Contents Initialization + +When a new Tensor or a new TensorFixedSize are created, memory is allocated to +hold all the tensor elements, but the memory is not initialized. Similarly, +when a new TensorMap is created on top of non-initialized memory the memory its +contents are not initialized. + +You can use one of the methods below to initialize the tensor memory. These +have an immediate effect on the tensor and return the tensor itself as a +result. These are not tensor Operations which delay evaluation. + +### setConstant(const Scalar& val) + +Sets all elements of the tensor to the constant value ```val```. ```Scalar``` +is the type of data stored in the tensor. You can pass any value that is +convertible to that type. + +Returns the tensor itself in case you want to chain another call. + + a.setConstant(12.3f); + cout << "Constant: " << endl << a << endl << endl; + => + Constant: + 12.3 12.3 12.3 12.3 + 12.3 12.3 12.3 12.3 + 12.3 12.3 12.3 12.3 + +Note that ```setConstant()``` can be used on any tensor where the element type +has a copy constructor and an ```operator=()```: + + Eigen::Tensor a(2, 3); + a.setConstant("yolo"); + cout << "String tensor: " << endl << a << endl << endl; + => + String tensor: + yolo yolo yolo + yolo yolo yolo + + +### setZero() + +Fills the tensor with zeros. Equivalent to ```setConstant(Scalar(0))```. +Returns the tensor itself in case you want to chain another call. + + a.setZero(); + cout << "Zeros: " << endl << a << endl << endl; + => + Zeros: + 0 0 0 0 + 0 0 0 0 + 0 0 0 0 + + +### setValues({..initializer_list}) + +Fills the tensor with explicit values specified in a std::initializer_list. +The type of the initializer list depends on the type and rank of the tensor. + +If the tensor has rank N, the initializer list must be nested N times. The +most deeply nested lists must contains P scalars of the Tensor type where P is +the size of the last dimension of the Tensor. + +For example, for a ```TensorFixedSize``` the initializer list must +contains 2 lists of 3 floats each. + +```setValues()``` returns the tensor itself in case you want to chain another +call. + + Eigen::Tensor a(2, 3); + a.setValues({{0.0f, 1.0f, 2.0f}, {3.0f, 4.0f, 5.0f}}); + cout << "a" << endl << a << endl << endl; + => + a + 0 1 2 + 3 4 5 + +If a list is too short, the corresponding elements of the tensor will not be +changed. This is valid at each level of nesting. For example the following +code only sets the values of the first row of the tensor. + + Eigen::Tensor a(2, 3); + a.setConstant(1000); + a.setValues({{10, 20, 30}}); + cout << "a" << endl << a << endl << endl; + => + a + 10 20 30 + 1000 1000 1000 + +### setRandom() + +Fills the tensor with random values. Returns the tensor itself in case you +want to chain another call. + + a.setRandom(); + cout << "Random: " << endl << a << endl << endl; + => + Random: + 0.680375 0.59688 -0.329554 0.10794 + -0.211234 0.823295 0.536459 -0.0452059 + 0.566198 -0.604897 -0.444451 0.257742 + +You can customize ```setRandom()``` by providing your own random number +generator as a template argument: + + a.setRandom(); + +Here, ```MyRandomGenerator``` must be a struct with the following member +functions, where Scalar and Index are the same as ```::Scalar``` +and ```::Index```. + +See ```struct UniformRandomGenerator``` in TensorFunctors.h for an example. + + // Custom number generator for use with setRandom(). + struct MyRandomGenerator { + // Default and copy constructors. Both are needed + MyRandomGenerator() { } + MyRandomGenerator(const MyRandomGenerator& ) { } + + // Return a random value to be used. "element_location" is the + // location of the entry to set in the tensor, it can typically + // be ignored. + Scalar operator()(Eigen::DenseIndex element_location, + Eigen::DenseIndex /*unused*/ = 0) const { + return ; + } + + // Same as above but generates several numbers at a time. + typename internal::packet_traits::type packetOp( + Eigen::DenseIndex packet_location, Eigen::DenseIndex /*unused*/ = 0) const { + return ; + } + }; + +You can also use one of the 2 random number generators that are part of the +tensor library: +* UniformRandomGenerator +* NormalRandomGenerator + + +## Data Access + +The Tensor, TensorFixedSize, and TensorRef classes provide the following +accessors to access the tensor coefficients: + + const Scalar& operator()(const array& indices) + const Scalar& operator()(Index firstIndex, IndexTypes... otherIndices) + Scalar& operator()(const array& indices) + Scalar& operator()(Index firstIndex, IndexTypes... otherIndices) + +The number of indices must be equal to the rank of the tensor. Moreover, these +accessors are not available on tensor expressions. In order to access the +values of a tensor expression, the expression must either be evaluated or +wrapped in a TensorRef. + + +### Scalar* data() and const Scalar* data() const + +Returns a pointer to the storage for the tensor. The pointer is const if the +tensor was const. This allows direct access to the data. The layout of the +data depends on the tensor layout: RowMajor or ColMajor. + +This access is usually only needed for special cases, for example when mixing +Eigen Tensor code with other libraries. + +Scalar is the type of data stored in the tensor. + + Eigen::Tensor a(3, 4); + float* a_data = a.data(); + a_data[0] = 123.45f; + cout << "a(0, 0): " << a(0, 0); + => a(0, 0): 123.45 + + +## Tensor Operations + +All the methods documented below return non evaluated tensor ```Operations```. +These can be chained: you can apply another Tensor Operation to the value +returned by the method. + +The chain of Operation is evaluated lazily, typically when it is assigned to a +tensor. See "Controlling when Expression are Evaluated" for more details about +their evaluation. + +### constant(const Scalar& val) + +Returns a tensor of the same type and dimensions as the original tensor but +where all elements have the value ```val```. + +This is useful, for example, when you want to add or subtract a constant from a +tensor, or multiply every element of a tensor by a scalar. + + Eigen::Tensor a(2, 3); + a.setConstant(1.0f); + Eigen::Tensor b = a + a.constant(2.0f); + Eigen::Tensor c = b * b.constant(0.2f); + cout << "a" << endl << a << endl << endl; + cout << "b" << endl << b << endl << endl; + cout << "c" << endl << c << endl << endl; + => + a + 1 1 1 + 1 1 1 + + b + 3 3 3 + 3 3 3 + + c + 0.6 0.6 0.6 + 0.6 0.6 0.6 + +### random() + +Returns a tensor of the same type and dimensions as the current tensor +but where all elements have random values. + +This is for example useful to add random values to an existing tensor. +The generation of random values can be customized in the same manner +as for ```setRandom()```. + + Eigen::Tensor a(2, 3); + a.setConstant(1.0f); + Eigen::Tensor b = a + a.random(); + cout << "a" << endl << a << endl << endl; + cout << "b" << endl << b << endl << endl; + => + a + 1 1 1 + 1 1 1 + + b + 1.68038 1.5662 1.82329 + 0.788766 1.59688 0.395103 + + +## Unary Element Wise Operations + +All these operations take a single input tensor as argument and return a tensor +of the same type and dimensions as the tensor to which they are applied. The +requested operations are applied to each element independently. + +### operator-() + +Returns a tensor of the same type and dimensions as the original tensor +containing the opposite values of the original tensor. + + Eigen::Tensor a(2, 3); + a.setConstant(1.0f); + Eigen::Tensor b = -a; + cout << "a" << endl << a << endl << endl; + cout << "b" << endl << b << endl << endl; + => + a + 1 1 1 + 1 1 1 + + b + -1 -1 -1 + -1 -1 -1 + +### sqrt() + +Returns a tensor of the same type and dimensions as the original tensor +containing the square roots of the original tensor. + +### rsqrt() + +Returns a tensor of the same type and dimensions as the original tensor +containing the inverse square roots of the original tensor. + +### square() + +Returns a tensor of the same type and dimensions as the original tensor +containing the squares of the original tensor values. + +### inverse() + +Returns a tensor of the same type and dimensions as the original tensor +containing the inverse of the original tensor values. + +### exp() + +Returns a tensor of the same type and dimensions as the original tensor +containing the exponential of the original tensor. + +### log() + +Returns a tensor of the same type and dimensions as the original tensor +containing the natural logarithms of the original tensor. + +### abs() + +Returns a tensor of the same type and dimensions as the original tensor +containing the absolute values of the original tensor. + +### pow(Scalar exponent) + +Returns a tensor of the same type and dimensions as the original tensor +containing the coefficients of the original tensor to the power of the +exponent. + +The type of the exponent, Scalar, is always the same as the type of the +tensor coefficients. For example, only integer exponents can be used in +conjuntion with tensors of integer values. + +You can use cast() to lift this restriction. For example this computes +cubic roots of an int Tensor: + + Eigen::Tensor a(2, 3); + a.setValues({{0, 1, 8}, {27, 64, 125}}); + Eigen::Tensor b = a.cast().pow(1.0 / 3.0); + cout << "a" << endl << a << endl << endl; + cout << "b" << endl << b << endl << endl; + => + a + 0 1 8 + 27 64 125 + + b + 0 1 2 + 3 4 5 + +### operator * (Scalar scale) + +Multiplies all the coefficients of the input tensor by the provided scale. + +### cwiseMax(Scalar threshold) +TODO + +### cwiseMin(Scalar threshold) +TODO + +### unaryExpr(const CustomUnaryOp& func) +TODO + + +## Binary Element Wise Operations + +These operations take two input tensors as arguments. The 2 input tensors should +be of the same type and dimensions. The result is a tensor of the same +dimensions as the tensors to which they are applied, and unless otherwise +specified it is also of the same type. The requested operations are applied to +each pair of elements independently. + +### operator+(const OtherDerived& other) + +Returns a tensor of the same type and dimensions as the input tensors +containing the coefficient wise sums of the inputs. + +### operator-(const OtherDerived& other) + +Returns a tensor of the same type and dimensions as the input tensors +containing the coefficient wise differences of the inputs. + +### operator*(const OtherDerived& other) + +Returns a tensor of the same type and dimensions as the input tensors +containing the coefficient wise products of the inputs. + +### operator/(const OtherDerived& other) + +Returns a tensor of the same type and dimensions as the input tensors +containing the coefficient wise quotients of the inputs. + +This operator is not supported for integer types. + +### cwiseMax(const OtherDerived& other) + +Returns a tensor of the same type and dimensions as the input tensors +containing the coefficient wise maximums of the inputs. + +### cwiseMin(const OtherDerived& other) + +Returns a tensor of the same type and dimensions as the input tensors +containing the coefficient wise mimimums of the inputs. + +### Logical operators + +The following logical operators are supported as well: + +* operator&&(const OtherDerived& other) +* operator||(const OtherDerived& other) +* operator<(const OtherDerived& other) +* operator<=(const OtherDerived& other) +* operator>(const OtherDerived& other) +* operator>=(const OtherDerived& other) +* operator==(const OtherDerived& other) +* operator!=(const OtherDerived& other) + +They all return a tensor of boolean values. + + +## Selection (select(const ThenDerived& thenTensor, const ElseDerived& elseTensor) + +Selection is a coefficient-wise ternary operator that is the tensor equivalent +to the if-then-else operation. + + Tensor if = ...; + Tensor then = ...; + Tensor else = ...; + Tensor result = if.select(then, else); + +The 3 arguments must be of the same dimensions, which will also be the dimension +of the result. The 'if' tensor must be of type boolean, the 'then' and the +'else' tensor must be of the same type, which will also be the type of the +result. + +Each coefficient in the result is equal to the corresponding coefficient in the +'then' tensor if the corresponding value in the 'if' tensor is true. If not, the +resulting coefficient will come from the 'else' tensor. + + +## Contraction + +Tensor *contractions* are a generalization of the matrix product to the +multidimensional case. + + // Create 2 matrices using tensors of rank 2 + Eigen::Tensor a(2, 3); + a.setValues({{1, 2, 3}, {6, 5, 4}}); + Eigen::Tensor b(3, 2); + a.setValues({{1, 2}, {4, 5}, {5, 6}}); + + // Compute the traditional matrix product + array, 1> product_dims = { IndexPair(1, 0) }; + Eigen::Tensor AB = a.contract(b, product_dims); + + // Compute the product of the transpose of the matrices + array, 1> transpose_product_dims = { IndexPair(0, 1) }; + Eigen::Tensor AtBt = a.contract(b, transposed_product_dims); + + +## Reduction Operations + +A *Reduction* operation returns a tensor with fewer dimensions than the +original tensor. The values in the returned tensor are computed by applying a +*reduction operator* to slices of values from the original tensor. You specify +the dimensions along which the slices are made. + +The Eigen Tensor library provides a set of predefined reduction operators such +as ```maximum()``` and ```sum()``` and lets you define additional operators by +implementing a few methods from a reductor template. + +### Reduction Dimensions + +All reduction operations take a single parameter of type +```::Dimensions``` which can always be specified as an array of +ints. These are called the "reduction dimensions." The values are the indices +of the dimensions of the input tensor over which the reduction is done. The +parameter can have at most as many element as the rank of the input tensor; +each element must be less than the tensor rank, as it indicates one of the +dimensions to reduce. + +Each dimension of the input tensor should occur at most once in the reduction +dimensions as the implementation does not remove duplicates. + +The order of the values in the reduction dimensions does not affect the +results, but the code may execute faster if you list the dimensions in +increasing order. + +Example: Reduction along one dimension. + + // Create a tensor of 2 dimensions + Eigen::Tensor a(2, 3); + a.setValues({{1, 2, 3}, {6, 5, 4}}); + // Reduce it along the second dimension (1)... + Eigen::array dims({1 /* dimension to reduce */}); + // ...using the "maximum" operator. + // The result is a tensor with one dimension. The size of + // that dimension is the same as the first (non-reduced) dimension of a. + Eigen::Tensor b = a.maximum(dims); + cout << "a" << endl << a << endl << endl; + cout << "b" << endl << b << endl << endl; + => + a + 1 2 3 + 6 5 4 + + b + 3 + 6 + +Example: Reduction along two dimensions. + + Eigen::Tensor a(2, 3, 4); + a.setValues({{{0.0f, 1.0f, 2.0f, 3.0f}, + {7.0f, 6.0f, 5.0f, 4.0f}, + {8.0f, 9.0f, 10.0f, 11.0f}}, + {{12.0f, 13.0f, 14.0f, 15.0f}, + {19.0f, 18.0f, 17.0f, 16.0f}, + {20.0f, 21.0f, 22.0f, 23.0f}}}); + // The tensor a has 3 dimensions. We reduce along the + // first 2, resulting in a tensor with a single dimension + // of size 4 (the last dimension of a.) + // Note that we pass the array of reduction dimensions + // directly to the maximum() call. + Eigen::Tensor b = + a.maximum(Eigen::array({0, 1})); + cout << "b" << endl << b << endl << endl; + => + b + 20 + 21 + 22 + 23 + +#### Reduction along all dimensions + +As a special case, if you pass no parameter to a reduction operation the +original tensor is reduced along *all* its dimensions. The result is a +scalar, represented as a zero-dimension tensor. + + Eigen::Tensor a(2, 3, 4); + a.setValues({{{0.0f, 1.0f, 2.0f, 3.0f}, + {7.0f, 6.0f, 5.0f, 4.0f}, + {8.0f, 9.0f, 10.0f, 11.0f}}, + {{12.0f, 13.0f, 14.0f, 15.0f}, + {19.0f, 18.0f, 17.0f, 16.0f}, + {20.0f, 21.0f, 22.0f, 23.0f}}}); + // Reduce along all dimensions using the sum() operator. + Eigen::Tensor b = a.sum(); + cout << "b" << endl << b << endl << endl; + => + b + 276 + + +### sum(const Dimensions& new_dims) +### sum() + +Reduce a tensor using the sum() operator. The resulting values +are the sum of the reduced values. + +### mean(const Dimensions& new_dims) +### mean() + +Reduce a tensor using the mean() operator. The resulting values +are the mean of the reduced values. + +### maximum(const Dimensions& new_dims) +### maximum() + +Reduce a tensor using the maximum() operator. The resulting values are the +largest of the reduced values. + +### minimum(const Dimensions& new_dims) +### minimum() + +Reduce a tensor using the minimum() operator. The resulting values +are the smallest of the reduced values. + +### prod(const Dimensions& new_dims) +### prod() + +Reduce a tensor using the prod() operator. The resulting values +are the product of the reduced values. + +### all(const Dimensions& new_dims) +### all() +Reduce a tensor using the all() operator. Casts tensor to bool and then checks +whether all elements are true. Runs through all elements rather than +short-circuiting, so may be significantly inefficient. + +### any(const Dimensions& new_dims) +### any() +Reduce a tensor using the any() operator. Casts tensor to bool and then checks +whether any element is true. Runs through all elements rather than +short-circuiting, so may be significantly inefficient. + + +### reduce(const Dimensions& new_dims, const Reducer& reducer) + +Reduce a tensor using a user-defined reduction operator. See ```SumReducer``` +in TensorFunctors.h for information on how to implement a reduction operator. + + +## Scan Operations + +A *Scan* operation returns a tensor with the same dimensions as the original +tensor. The operation performs an inclusive scan along the specified +axis, which means it computes a running total along the axis for a given +reduction operation. +If the reduction operation corresponds to summation, then this computes the +prefix sum of the tensor along the given axis. + +Example: +dd a comment to this line + + // Create a tensor of 2 dimensions + Eigen::Tensor a(2, 3); + a.setValues({{1, 2, 3}, {4, 5, 6}}); + // Scan it along the second dimension (1) using summation + Eigen::Tensor b = a.cumsum(1); + // The result is a tensor with the same size as the input + cout << "a" << endl << a << endl << endl; + cout << "b" << endl << b << endl << endl; + => + a + 1 2 3 + 6 5 4 + + b + 1 3 6 + 4 9 15 + +### cumsum(const Index& axis) + +Perform a scan by summing consecutive entries. + +### cumprod(const Index& axis) + +Perform a scan by multiplying consecutive entries. + + +## Convolutions + +### convolve(const Kernel& kernel, const Dimensions& dims) + +Returns a tensor that is the output of the convolution of the input tensor with the kernel, +along the specified dimensions of the input tensor. The dimension size for dimensions of the output tensor +which were part of the convolution will be reduced by the formula: +output_dim_size = input_dim_size - kernel_dim_size + 1 (requires: input_dim_size >= kernel_dim_size). +The dimension sizes for dimensions that were not part of the convolution will remain the same. +Performance of the convolution can depend on the length of the stride(s) of the input tensor dimension(s) along which the +convolution is computed (the first dimension has the shortest stride for ColMajor, whereas RowMajor's shortest stride is +for the last dimension). + + // Compute convolution along the second and third dimension. + Tensor input(3, 3, 7, 11); + Tensor kernel(2, 2); + Tensor output(3, 2, 6, 11); + input.setRandom(); + kernel.setRandom(); + + Eigen::array dims({1, 2}); // Specify second and third dimension for convolution. + output = input.convolve(kernel, dims); + + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 2; ++j) { + for (int k = 0; k < 6; ++k) { + for (int l = 0; l < 11; ++l) { + const float result = output(i,j,k,l); + const float expected = input(i,j+0,k+0,l) * kernel(0,0) + + input(i,j+1,k+0,l) * kernel(1,0) + + input(i,j+0,k+1,l) * kernel(0,1) + + input(i,j+1,k+1,l) * kernel(1,1); + VERIFY_IS_APPROX(result, expected); + } + } + } + } + + +## Geometrical Operations + +These operations return a Tensor with different dimensions than the original +Tensor. They can be used to access slices of tensors, see them with different +dimensions, or pad tensors with additional data. + +### reshape(const Dimensions& new_dims) + +Returns a view of the input tensor that has been reshaped to the specified +new dimensions. The argument new_dims is an array of Index values. The +rank of the resulting tensor is equal to the number of elements in new_dims. + +The product of all the sizes in the new dimension array must be equal to +the number of elements in the input tensor. + + // Increase the rank of the input tensor by introducing a new dimension + // of size 1. + Tensor input(7, 11); + array three_dims{{7, 11, 1}}; + Tensor result = input.reshape(three_dims); + + // Decrease the rank of the input tensor by merging 2 dimensions; + array one_dim{{7 * 11}}; + Tensor result = input.reshape(one_dim); + +This operation does not move any data in the input tensor, so the resulting +contents of a reshaped Tensor depend on the data layout of the original Tensor. + +For example this is what happens when you ```reshape()``` a 2D ColMajor tensor +to one dimension: + + Eigen::Tensor a(2, 3); + a.setValues({{0.0f, 100.0f, 200.0f}, {300.0f, 400.0f, 500.0f}}); + Eigen::array one_dim({3 * 2}); + Eigen::Tensor b = a.reshape(one_dim); + cout << "b" << endl << b << endl; + => + b + 0 + 300 + 100 + 400 + 200 + 500 + +This is what happens when the 2D Tensor is RowMajor: + + Eigen::Tensor a(2, 3); + a.setValues({{0.0f, 100.0f, 200.0f}, {300.0f, 400.0f, 500.0f}}); + Eigen::array one_dim({3 * 2}); + Eigen::Tensor b = a.reshape(one_dim); + cout << "b" << endl << b << endl; + => + b + 0 + 100 + 200 + 300 + 400 + 500 + +The reshape operation is a lvalue. In other words, it can be used on the left +side of the assignment operator. + +The previous example can be rewritten as follow: + + Eigen::Tensor a(2, 3); + a.setValues({{0.0f, 100.0f, 200.0f}, {300.0f, 400.0f, 500.0f}}); + Eigen::array two_dim({2, 3}); + Eigen::Tensor b; + b.reshape(two_dim) = a; + cout << "b" << endl << b << endl; + => + b + 0 + 300 + 100 + 400 + 200 + 500 + +Note that "b" itself was not reshaped but that instead the assignment is done to +the reshape view of b. + + +### shuffle(const Shuffle& shuffle) + +Returns a copy of the input tensor whose dimensions have been +reordered according to the specified permutation. The argument shuffle +is an array of Index values. Its size is the rank of the input +tensor. It must contain a permutation of 0, 1, ..., rank - 1. The i-th +dimension of the output tensor equals to the size of the shuffle[i]-th +dimension of the input tensor. For example: + + // Shuffle all dimensions to the left by 1. + Tensor input(20, 30, 50); + // ... set some values in input. + Tensor output = input.shuffle({1, 2, 0}) + + eigen_assert(output.dimension(0) == 30); + eigen_assert(output.dimension(1) == 50); + eigen_assert(output.dimension(2) == 20); + +Indices into the output tensor are shuffled accordingly to formulate +indices into the input tensor. For example, one can assert in the above +code snippet that: + + eigen_assert(output(3, 7, 11) == input(11, 3, 7)); + +In general, one can assert that + + eigen_assert(output(..., indices[shuffle[i]], ...) == + input(..., indices[i], ...)) + +The shuffle operation results in a lvalue, which means that it can be assigned +to. In other words, it can be used on the left side of the assignment operator. + +Let's rewrite the previous example to take advantage of this feature: + + // Shuffle all dimensions to the left by 1. + Tensor input(20, 30, 50); + // ... set some values in input. + Tensor output(30, 50, 20); + output.shuffle({2, 0, 1}) = input; + + +### stride(const Strides& strides) + +Returns a view of the input tensor that strides (skips stride-1 +elements) along each of the dimensions. The argument strides is an +array of Index values. The dimensions of the resulting tensor are +ceil(input_dimensions[i] / strides[i]). + +For example this is what happens when you ```stride()``` a 2D tensor: + + Eigen::Tensor a(4, 3); + a.setValues({{0, 100, 200}, {300, 400, 500}, {600, 700, 800}, {900, 1000, 1100}}); + Eigen::array strides({3, 2}); + Eigen::Tensor b = a.stride(strides); + cout << "b" << endl << b << endl; + => + b + 0 200 + 900 1100 + +It is possible to assign a tensor to a stride: + Tensor input(20, 30, 50); + // ... set some values in input. + Tensor output(40, 90, 200); + output.stride({2, 3, 4}) = input; + + +### slice(const StartIndices& offsets, const Sizes& extents) + +Returns a sub-tensor of the given tensor. For each dimension i, the slice is +made of the coefficients stored between offset[i] and offset[i] + extents[i] in +the input tensor. + + Eigen::Tensor a(4, 3); + a.setValues({{0, 100, 200}, {300, 400, 500}, + {600, 700, 800}, {900, 1000, 1100}}); + Eigen::array offsets = {1, 0}; + Eigen::array extents = {2, 2}; + Eigen::Tensor slice = a.slice(offsets, extents); + cout << "a" << endl << a << endl; + => + a + 0 100 200 + 300 400 500 + 600 700 800 + 900 1000 1100 + cout << "slice" << endl << slice << endl; + => + slice + 300 400 + 600 700 + + +### chip(const Index offset, const Index dim) + +A chip is a special kind of slice. It is the subtensor at the given offset in +the dimension dim. The returned tensor has one fewer dimension than the input +tensor: the dimension dim is removed. + +For example, a matrix chip would be either a row or a column of the input +matrix. + + Eigen::Tensor a(4, 3); + a.setValues({{0, 100, 200}, {300, 400, 500}, + {600, 700, 800}, {900, 1000, 1100}}); + Eigen::Tensor row_3 = a.chip(2, 0); + Eigen::Tensor col_2 = a.chip(1, 1); + cout << "a" << endl << a << endl; + => + a + 0 100 200 + 300 400 500 + 600 700 800 + 900 1000 1100 + cout << "row_3" << endl << row_3 << endl; + => + row_3 + 600 700 800 + cout << "col_2" << endl << col_2 << endl; + => + col_2 + 100 400 700 1000 + +It is possible to assign values to a tensor chip since the chip operation is a +lvalue. For example: + + Eigen::Tensor a(3); + a.setValues({{100, 200, 300}}); + Eigen::Tensor b(2, 3); + b.setZero(); + b.chip(0, 0) = a; + cout << "a" << endl << a << endl; + => + a + 100 + 200 + 300 + cout << "b" << endl << b << endl; + => + b + 100 200 300 + 0 0 0 + + +### reverse(const ReverseDimensions& reverse) + +Returns a view of the input tensor that reverses the order of the coefficients +along a subset of the dimensions. The argument reverse is an array of boolean +values that indicates whether or not the order of the coefficients should be +reversed along each of the dimensions. This operation preserves the dimensions +of the input tensor. + +For example this is what happens when you ```reverse()``` the first dimension +of a 2D tensor: + + Eigen::Tensor a(4, 3); + a.setValues({{0, 100, 200}, {300, 400, 500}, + {600, 700, 800}, {900, 1000, 1100}}); + Eigen::array reverse({true, false}); + Eigen::Tensor b = a.reverse(reverse); + cout << "a" << endl << a << endl << "b" << endl << b << endl; + => + a + 0 100 200 + 300 400 500 + 600 700 800 + 900 1000 1100 + b + 900 1000 1100 + 600 700 800 + 300 400 500 + 0 100 200 + + +### broadcast(const Broadcast& broadcast) + +Returns a view of the input tensor in which the input is replicated one to many +times. +The broadcast argument specifies how many copies of the input tensor need to be +made in each of the dimensions. + + Eigen::Tensor a(2, 3); + a.setValues({{0, 100, 200}, {300, 400, 500}}); + Eigen::array bcast({3, 2}); + Eigen::Tensor b = a.broadcast(bcast); + cout << "a" << endl << a << endl << "b" << endl << b << endl; + => + a + 0 100 200 + 300 400 500 + b + 0 100 200 0 100 200 + 300 400 500 300 400 500 + 0 100 200 0 100 200 + 300 400 500 300 400 500 + 0 100 200 0 100 200 + 300 400 500 300 400 500 + +### concatenate(const OtherDerived& other, Axis axis) + +TODO + +### pad(const PaddingDimensions& padding) + +Returns a view of the input tensor in which the input is padded with zeros. + + Eigen::Tensor a(2, 3); + a.setValues({{0, 100, 200}, {300, 400, 500}}); + Eigen::array, 2> paddings; + paddings[0] = make_pair(0, 1); + paddings[1] = make_pair(2, 3); + Eigen::Tensor b = a.pad(paddings); + cout << "a" << endl << a << endl << "b" << endl << b << endl; + => + a + 0 100 200 + 300 400 500 + b + 0 0 0 0 + 0 0 0 0 + 0 100 200 0 + 300 400 500 0 + 0 0 0 0 + 0 0 0 0 + 0 0 0 0 + + +### extract_patches(const PatchDims& patch_dims) + +Returns a tensor of coefficient patches extracted from the input tensor, where +each patch is of dimension specified by 'patch_dims'. The returned tensor has +one greater dimension than the input tensor, which is used to index each patch. +The patch index in the output tensor depends on the data layout of the input +tensor: the patch index is the last dimension ColMajor layout, and the first +dimension in RowMajor layout. + +For example, given the following input tensor: + + Eigen::Tensor tensor(3,4); + tensor.setValues({{0.0f, 1.0f, 2.0f, 3.0f}, + {4.0f, 5.0f, 6.0f, 7.0f}, + {8.0f, 9.0f, 10.0f, 11.0f}}); + + cout << "tensor: " << endl << tensor << endl; +=> +tensor: + 0 1 2 3 + 4 5 6 7 + 8 9 10 11 + +Six 2x2 patches can be extracted and indexed using the following code: + + Eigen::Tensor patch; + Eigen::array patch_dims; + patch_dims[0] = 2; + patch_dims[1] = 2; + patch = tensor.extract_patches(patch_dims); + for (int k = 0; k < 6; ++k) { + cout << "patch index: " << k << endl; + for (int i = 0; i < 2; ++i) { + for (int j = 0; j < 2; ++j) { + if (DataLayout == ColMajor) { + cout << patch(i, j, k) << " "; + } else { + cout << patch(k, i, j) << " "; + } + } + cout << endl; + } + } + +This code results in the following output when the data layout is ColMajor: + +patch index: 0 +0 1 +4 5 +patch index: 1 +4 5 +8 9 +patch index: 2 +1 2 +5 6 +patch index: 3 +5 6 +9 10 +patch index: 4 +2 3 +6 7 +patch index: 5 +6 7 +10 11 + +This code results in the following output when the data layout is RowMajor: +(NOTE: the set of patches is the same as in ColMajor, but are indexed differently). + +patch index: 0 +0 1 +4 5 +patch index: 1 +1 2 +5 6 +patch index: 2 +2 3 +6 7 +patch index: 3 +4 5 +8 9 +patch index: 4 +5 6 +9 10 +patch index: 5 +6 7 +10 11 + +### extract_image_patches(const Index patch_rows, const Index patch_cols, + const Index row_stride, const Index col_stride, + const PaddingType padding_type) + +Returns a tensor of coefficient image patches extracted from the input tensor, +which is expected to have dimensions ordered as follows (depending on the data +layout of the input tensor, and the number of additional dimensions 'N'): + +*) ColMajor +1st dimension: channels (of size d) +2nd dimension: rows (of size r) +3rd dimension: columns (of size c) +4th-Nth dimension: time (for video) or batch (for bulk processing). + +*) RowMajor (reverse order of ColMajor) +1st-Nth dimension: time (for video) or batch (for bulk processing). +N+1'th dimension: columns (of size c) +N+2'th dimension: rows (of size r) +N+3'th dimension: channels (of size d) + +The returned tensor has one greater dimension than the input tensor, which is +used to index each patch. The patch index in the output tensor depends on the +data layout of the input tensor: the patch index is the 4'th dimension in +ColMajor layout, and the 4'th from the last dimension in RowMajor layout. + +For example, given the following input tensor with the following dimension +sizes: + *) depth: 2 + *) rows: 3 + *) columns: 5 + *) batch: 7 + + Tensor tensor(2,3,5,7); + Tensor tensor_row_major = tensor.swap_layout(); + +2x2 image patches can be extracted and indexed using the following code: + +*) 2D patch: ColMajor (patch indexed by second-to-last dimension) + Tensor twod_patch; + twod_patch = tensor.extract_image_patches<2, 2>(); + // twod_patch.dimension(0) == 2 + // twod_patch.dimension(1) == 2 + // twod_patch.dimension(2) == 2 + // twod_patch.dimension(3) == 3*5 + // twod_patch.dimension(4) == 7 + +*) 2D patch: RowMajor (patch indexed by the second dimension) + Tensor twod_patch_row_major; + twod_patch_row_major = tensor_row_major.extract_image_patches<2, 2>(); + // twod_patch_row_major.dimension(0) == 7 + // twod_patch_row_major.dimension(1) == 3*5 + // twod_patch_row_major.dimension(2) == 2 + // twod_patch_row_major.dimension(3) == 2 + // twod_patch_row_major.dimension(4) == 2 + +## Special Operations + +### cast() + +Returns a tensor of type T with the same dimensions as the original tensor. +The returned tensor contains the values of the original tensor converted to +type T. + + Eigen::Tensor a(2, 3); + Eigen::Tensor b = a.cast(); + +This can be useful for example if you need to do element-wise division of +Tensors of integers. This is not currently supported by the Tensor library +but you can easily cast the tensors to floats to do the division: + + Eigen::Tensor a(2, 3); + a.setValues({{0, 1, 2}, {3, 4, 5}}); + Eigen::Tensor b = + (a.cast() / a.constant(2).cast()).cast(); + cout << "a" << endl << a << endl << endl; + cout << "b" << endl << b << endl << endl; + => + a + 0 1 2 + 3 4 5 + + b + 0 0 1 + 1 2 2 + + +### eval() + +TODO + + +## Representation of scalar values + +Scalar values are often represented by tensors of size 1 and rank 1. It would be +more logical and user friendly to use tensors of rank 0 instead. For example +Tensor::maximum() currently returns a Tensor. Similarly, the inner +product of 2 1d tensors (through contractions) returns a 1d tensor. In the +future these operations might be updated to return 0d tensors instead. + +## Limitations + +* The number of tensor dimensions is currently limited to 250 when using a + compiler that supports cxx11. It is limited to only 5 for older compilers. +* The IndexList class requires a cxx11 compliant compiler. You can use an + array of indices instead if you don't have access to a modern compiler. +* On GPUs only floating point values are properly tested and optimized for. +* Complex and integer values are known to be broken on GPUs. If you try to use + them you'll most likely end up triggering a static assertion failure such as + EIGEN_STATIC_ASSERT(packetSize > 1, YOU_MADE_A_PROGRAMMING_MISTAKE) + + diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/Tensor.h b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/Tensor.h new file mode 100644 index 0000000000..1940a9692f --- /dev/null +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/Tensor.h @@ -0,0 +1,527 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Benoit Steiner +// Copyright (C) 2013 Christian Seiler +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CXX11_TENSOR_TENSOR_H +#define EIGEN_CXX11_TENSOR_TENSOR_H + +namespace Eigen { + +/** \class Tensor + * \ingroup CXX11_Tensor_Module + * + * \brief The tensor class. + * + * The %Tensor class is the work-horse for all \em dense tensors within Eigen. + * + * The %Tensor class encompasses only dynamic-size objects so far. + * + * The first two template parameters are required: + * \tparam Scalar_ \anchor tensor_tparam_scalar Numeric type, e.g. float, double, int or std::complex. + * User defined scalar types are supported as well (see \ref user_defined_scalars "here"). + * \tparam NumIndices_ Number of indices (i.e. rank of the tensor) + * + * The remaining template parameters are optional -- in most cases you don't have to worry about them. + * \tparam Options_ \anchor tensor_tparam_options A combination of either \b #RowMajor or \b #ColMajor, and of either + * \b #AutoAlign or \b #DontAlign. + * The former controls \ref TopicStorageOrders "storage order", and defaults to column-major. The latter controls alignment, which is required + * for vectorization. It defaults to aligning tensors. Note that tensors currently do not support any operations that profit from vectorization. + * Support for such operations (i.e. adding two tensors etc.) is planned. + * + * You can access elements of tensors using normal subscripting: + * + * \code + * Eigen::Tensor t(10, 10, 10, 10); + * t(0, 1, 2, 3) = 42.0; + * \endcode + * + * This class can be extended with the help of the plugin mechanism described on the page + * \ref TopicCustomizingEigen by defining the preprocessor symbol \c EIGEN_TENSOR_PLUGIN. + * + * Some notes: + * + *

+ *
Relation to other parts of Eigen:
+ *
The midterm developement goal for this class is to have a similar hierarchy as Eigen uses for matrices, so that + * taking blocks or using tensors in expressions is easily possible, including an interface with the vector/matrix code + * by providing .asMatrix() and .asVector() (or similar) methods for rank 2 and 1 tensors. However, currently, the %Tensor + * class does not provide any of these features and is only available as a stand-alone class that just allows for + * coefficient access. Also, when fixed-size tensors are implemented, the number of template arguments is likely to + * change dramatically.
+ *
+ * + * \ref TopicStorageOrders + */ + +template +class Tensor : public TensorBase > +{ + public: + typedef Tensor Self; + typedef TensorBase > Base; + typedef typename Eigen::internal::nested::type Nested; + typedef typename internal::traits::StorageKind StorageKind; + typedef typename internal::traits::Index Index; + typedef Scalar_ Scalar; + typedef typename NumTraits::Real RealScalar; + typedef typename Base::CoeffReturnType CoeffReturnType; + + enum { + IsAligned = bool(EIGEN_MAX_ALIGN_BYTES>0) & !(Options_&DontAlign), + Layout = Options_ & RowMajor ? RowMajor : ColMajor, + CoordAccess = true, + RawAccess = true + }; + + static const int Options = Options_; + static const int NumIndices = NumIndices_; + typedef DSizes Dimensions; + + protected: + TensorStorage m_storage; + +#ifdef EIGEN_HAS_SFINAE + template + struct isOfNormalIndex{ + static const bool is_array = internal::is_base_of, CustomIndices>::value; + static const bool is_int = NumTraits::IsInteger; + static const bool value = is_array | is_int; + }; +#endif + + public: + // Metadata + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index rank() const { return NumIndices; } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index dimension(std::size_t n) const { return m_storage.dimensions()[n]; } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Dimensions& dimensions() const { return m_storage.dimensions(); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index size() const { return m_storage.size(); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar *data() { return m_storage.data(); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar *data() const { return m_storage.data(); } + + // This makes EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED + // work, because that uses base().coeffRef() - and we don't yet + // implement a similar class hierarchy + inline Self& base() { return *this; } + inline const Self& base() const { return *this; } + +#if EIGEN_HAS_VARIADIC_TEMPLATES + template + EIGEN_DEVICE_FUNC inline const Scalar& coeff(Index firstIndex, Index secondIndex, IndexTypes... otherIndices) const + { + // The number of indices used to access a tensor coefficient must be equal to the rank of the tensor. + EIGEN_STATIC_ASSERT(sizeof...(otherIndices) + 2 == NumIndices, YOU_MADE_A_PROGRAMMING_MISTAKE) + return coeff(array{{firstIndex, secondIndex, otherIndices...}}); + } +#endif + + // normal indices + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar& coeff(const array& indices) const + { + eigen_internal_assert(checkIndexRange(indices)); + return m_storage.data()[linearizedIndex(indices)]; + } + + // custom indices +#ifdef EIGEN_HAS_SFINAE + template::value) ) + > + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar& coeff(CustomIndices& indices) const + { + return coeff(internal::customIndices2Array(indices)); + } +#endif + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar& coeff() const + { + EIGEN_STATIC_ASSERT(NumIndices == 0, YOU_MADE_A_PROGRAMMING_MISTAKE); + return m_storage.data()[0]; + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar& coeff(Index index) const + { + eigen_internal_assert(index >= 0 && index < size()); + return m_storage.data()[index]; + } + +#if EIGEN_HAS_VARIADIC_TEMPLATES + template + inline Scalar& coeffRef(Index firstIndex, Index secondIndex, IndexTypes... otherIndices) + { + // The number of indices used to access a tensor coefficient must be equal to the rank of the tensor. + EIGEN_STATIC_ASSERT(sizeof...(otherIndices) + 2 == NumIndices, YOU_MADE_A_PROGRAMMING_MISTAKE) + return coeffRef(array{{firstIndex, secondIndex, otherIndices...}}); + } +#endif + + // normal indices + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRef(const array& indices) + { + eigen_internal_assert(checkIndexRange(indices)); + return m_storage.data()[linearizedIndex(indices)]; + } + + // custom indices +#ifdef EIGEN_HAS_SFINAE + template::value) ) + > + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRef(CustomIndices& indices) + { + return coeffRef(internal::customIndices2Array(indices)); + } +#endif + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRef() + { + EIGEN_STATIC_ASSERT(NumIndices == 0, YOU_MADE_A_PROGRAMMING_MISTAKE); + return m_storage.data()[0]; + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRef(Index index) + { + eigen_internal_assert(index >= 0 && index < size()); + return m_storage.data()[index]; + } + +#if EIGEN_HAS_VARIADIC_TEMPLATES + template + inline const Scalar& operator()(Index firstIndex, Index secondIndex, IndexTypes... otherIndices) const + { + // The number of indices used to access a tensor coefficient must be equal to the rank of the tensor. + EIGEN_STATIC_ASSERT(sizeof...(otherIndices) + 2 == NumIndices, YOU_MADE_A_PROGRAMMING_MISTAKE) + return this->operator()(array{{firstIndex, secondIndex, otherIndices...}}); + } +#else + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const Scalar& operator()(Index i0, Index i1) const + { + return coeff(array(i0, i1)); + } + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const Scalar& operator()(Index i0, Index i1, Index i2) const + { + return coeff(array(i0, i1, i2)); + } + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const Scalar& operator()(Index i0, Index i1, Index i2, Index i3) const + { + return coeff(array(i0, i1, i2, i3)); + } + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const Scalar& operator()(Index i0, Index i1, Index i2, Index i3, Index i4) const + { + return coeff(array(i0, i1, i2, i3, i4)); + } +#endif + + // custom indices +#ifdef EIGEN_HAS_SFINAE + template::value) ) + > + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar& operator()(CustomIndices& indices) const + { + return coeff(internal::customIndices2Array(indices)); + } +#endif + + // normal indices + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar& operator()(const array& indices) const + { + return coeff(indices); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar& operator()(Index index) const + { + eigen_internal_assert(index >= 0 && index < size()); + return coeff(index); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar& operator()() const + { + EIGEN_STATIC_ASSERT(NumIndices == 0, YOU_MADE_A_PROGRAMMING_MISTAKE); + return coeff(); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar& operator[](Index index) const + { + // The bracket operator is only for vectors, use the parenthesis operator instead. + EIGEN_STATIC_ASSERT(NumIndices == 1, YOU_MADE_A_PROGRAMMING_MISTAKE); + return coeff(index); + } + +#if EIGEN_HAS_VARIADIC_TEMPLATES + template + inline Scalar& operator()(Index firstIndex, Index secondIndex, IndexTypes... otherIndices) + { + // The number of indices used to access a tensor coefficient must be equal to the rank of the tensor. + EIGEN_STATIC_ASSERT(sizeof...(otherIndices) + 2 == NumIndices, YOU_MADE_A_PROGRAMMING_MISTAKE) + return operator()(array{{firstIndex, secondIndex, otherIndices...}}); + } +#else + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Scalar& operator()(Index i0, Index i1) + { + return coeffRef(array(i0, i1)); + } + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Scalar& operator()(Index i0, Index i1, Index i2) + { + return coeffRef(array(i0, i1, i2)); + } + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Scalar& operator()(Index i0, Index i1, Index i2, Index i3) + { + return coeffRef(array(i0, i1, i2, i3)); + } + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Scalar& operator()(Index i0, Index i1, Index i2, Index i3, Index i4) + { + return coeffRef(array(i0, i1, i2, i3, i4)); + } +#endif + + // normal indices + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& operator()(const array& indices) + { + return coeffRef(indices); + } + + // custom indices +#ifdef EIGEN_HAS_SFINAE + template::value) ) + > + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& operator()(CustomIndices& indices) + { + return coeffRef(internal::customIndices2Array(indices)); + } +#endif + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& operator()(Index index) + { + eigen_assert(index >= 0 && index < size()); + return coeffRef(index); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& operator()() + { + EIGEN_STATIC_ASSERT(NumIndices == 0, YOU_MADE_A_PROGRAMMING_MISTAKE); + return coeffRef(); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& operator[](Index index) + { + // The bracket operator is only for vectors, use the parenthesis operator instead + EIGEN_STATIC_ASSERT(NumIndices == 1, YOU_MADE_A_PROGRAMMING_MISTAKE) + return coeffRef(index); + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Tensor() + : m_storage() + { + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Tensor(const Self& other) + : m_storage(other.m_storage) + { + } + +#if EIGEN_HAS_VARIADIC_TEMPLATES + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Tensor(Index firstDimension, IndexTypes... otherDimensions) + : m_storage(firstDimension, otherDimensions...) + { + // The number of dimensions used to construct a tensor must be equal to the rank of the tensor. + EIGEN_STATIC_ASSERT(sizeof...(otherDimensions) + 1 == NumIndices, YOU_MADE_A_PROGRAMMING_MISTAKE) + } +#else + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE explicit Tensor(Index dim1) + : m_storage(dim1, array(dim1)) + { + EIGEN_STATIC_ASSERT(1 == NumIndices, YOU_MADE_A_PROGRAMMING_MISTAKE) + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Tensor(Index dim1, Index dim2) + : m_storage(dim1*dim2, array(dim1, dim2)) + { + EIGEN_STATIC_ASSERT(2 == NumIndices, YOU_MADE_A_PROGRAMMING_MISTAKE) + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Tensor(Index dim1, Index dim2, Index dim3) + : m_storage(dim1*dim2*dim3, array(dim1, dim2, dim3)) + { + EIGEN_STATIC_ASSERT(3 == NumIndices, YOU_MADE_A_PROGRAMMING_MISTAKE) + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Tensor(Index dim1, Index dim2, Index dim3, Index dim4) + : m_storage(dim1*dim2*dim3*dim4, array(dim1, dim2, dim3, dim4)) + { + EIGEN_STATIC_ASSERT(4 == NumIndices, YOU_MADE_A_PROGRAMMING_MISTAKE) + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Tensor(Index dim1, Index dim2, Index dim3, Index dim4, Index dim5) + : m_storage(dim1*dim2*dim3*dim4*dim5, array(dim1, dim2, dim3, dim4, dim5)) + { + EIGEN_STATIC_ASSERT(5 == NumIndices, YOU_MADE_A_PROGRAMMING_MISTAKE) + } +#endif + + /** Normal Dimension */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE explicit Tensor(const array& dimensions) + : m_storage(internal::array_prod(dimensions), dimensions) + { + EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED + } + + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Tensor(const TensorBase& other) + { + typedef TensorAssignOp Assign; + Assign assign(*this, other.derived()); + resize(TensorEvaluator(assign, DefaultDevice()).dimensions()); + internal::TensorExecutor::run(assign, DefaultDevice()); + } + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Tensor(const TensorBase& other) + { + typedef TensorAssignOp Assign; + Assign assign(*this, other.derived()); + resize(TensorEvaluator(assign, DefaultDevice()).dimensions()); + internal::TensorExecutor::run(assign, DefaultDevice()); + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Tensor& operator=(const Tensor& other) + { + typedef TensorAssignOp Assign; + Assign assign(*this, other); + resize(TensorEvaluator(assign, DefaultDevice()).dimensions()); + internal::TensorExecutor::run(assign, DefaultDevice()); + return *this; + } + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Tensor& operator=(const OtherDerived& other) + { + typedef TensorAssignOp Assign; + Assign assign(*this, other); + resize(TensorEvaluator(assign, DefaultDevice()).dimensions()); + internal::TensorExecutor::run(assign, DefaultDevice()); + return *this; + } + +#if EIGEN_HAS_VARIADIC_TEMPLATES + template EIGEN_DEVICE_FUNC + void resize(Index firstDimension, IndexTypes... otherDimensions) + { + // The number of dimensions used to resize a tensor must be equal to the rank of the tensor. + EIGEN_STATIC_ASSERT(sizeof...(otherDimensions) + 1 == NumIndices, YOU_MADE_A_PROGRAMMING_MISTAKE) + resize(array{{firstDimension, otherDimensions...}}); + } +#endif + + /** Normal Dimension */ + EIGEN_DEVICE_FUNC void resize(const array& dimensions) + { + int i; + Index size = Index(1); + for (i = 0; i < NumIndices; i++) { + internal::check_rows_cols_for_overflow::run(size, dimensions[i]); + size *= dimensions[i]; + } + #ifdef EIGEN_INITIALIZE_COEFFS + bool size_changed = size != this->size(); + m_storage.resize(size, dimensions); + if(size_changed) EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED + #else + m_storage.resize(size, dimensions); + #endif + } + + // Why this overload, DSizes is derived from array ??? // + EIGEN_DEVICE_FUNC void resize(const DSizes& dimensions) { + array dims; + for (int i = 0; i < NumIndices; ++i) { + dims[i] = dimensions[i]; + } + resize(dims); + } + + EIGEN_DEVICE_FUNC + void resize() + { + EIGEN_STATIC_ASSERT(NumIndices == 0, YOU_MADE_A_PROGRAMMING_MISTAKE); + // Nothing to do: rank 0 tensors have fixed size + } + + /** Custom Dimension */ +#ifdef EIGEN_HAS_SFINAE + template::value) ) + > + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void resize(CustomDimension& dimensions) + { + resize(internal::customIndices2Array(dimensions)); + } +#endif + +#ifndef EIGEN_EMULATE_CXX11_META_H + template + EIGEN_DEVICE_FUNC + void resize(const Sizes& dimensions) { + array dims; + for (int i = 0; i < NumIndices; ++i) { + dims[i] = static_cast(dimensions[i]); + } + resize(dims); + } +#else + template + EIGEN_DEVICE_FUNC + void resize(const Sizes& dimensions) { + array dims; + for (int i = 0; i < NumIndices; ++i) { + dims[i] = static_cast(dimensions[i]); + } + resize(dims); + } +#endif + + protected: + + bool checkIndexRange(const array& indices) const + { + using internal::array_apply_and_reduce; + using internal::array_zip_and_reduce; + using internal::greater_equal_zero_op; + using internal::logical_and_op; + using internal::lesser_op; + + return + // check whether the indices are all >= 0 + array_apply_and_reduce(indices) && + // check whether the indices fit in the dimensions + array_zip_and_reduce(indices, m_storage.dimensions()); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index linearizedIndex(const array& indices) const + { + if (Options&RowMajor) { + return m_storage.dimensions().IndexOfRowMajor(indices); + } else { + return m_storage.dimensions().IndexOfColMajor(indices); + } + } +}; + +} // end namespace Eigen + +#endif // EIGEN_CXX11_TENSOR_TENSOR_H diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorArgMax.h b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorArgMax.h new file mode 100644 index 0000000000..d06f40cd86 --- /dev/null +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorArgMax.h @@ -0,0 +1,299 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2015 Eugene Brevdo +// Benoit Steiner +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CXX11_TENSOR_TENSOR_ARG_MAX_H +#define EIGEN_CXX11_TENSOR_TENSOR_ARG_MAX_H + +namespace Eigen { +namespace internal { + +/** \class TensorIndexTuple + * \ingroup CXX11_Tensor_Module + * + * \brief Tensor + Index Tuple class. + * + * + */ +template +struct traits > : public traits +{ + typedef traits XprTraits; + typedef typename XprTraits::StorageKind StorageKind; + typedef typename XprTraits::Index Index; + typedef Tuple Scalar; + typedef typename XprType::Nested Nested; + typedef typename remove_reference::type _Nested; + static const int NumDimensions = XprTraits::NumDimensions; + static const int Layout = XprTraits::Layout; +}; + +template +struct eval, Eigen::Dense> +{ + typedef const TensorIndexTupleOp& type; +}; + +template +struct nested, 1, + typename eval >::type> +{ + typedef TensorIndexTupleOp type; +}; + +} // end namespace internal + +template +class TensorIndexTupleOp : public TensorBase, ReadOnlyAccessors> +{ + public: + typedef typename Eigen::internal::traits::Scalar Scalar; + typedef typename Eigen::NumTraits::Real RealScalar; + typedef typename Eigen::internal::nested::type Nested; + typedef typename Eigen::internal::traits::StorageKind StorageKind; + typedef typename Eigen::internal::traits::Index Index; + typedef Tuple CoeffReturnType; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorIndexTupleOp(const XprType& expr) + : m_xpr(expr) {} + + EIGEN_DEVICE_FUNC + const typename internal::remove_all::type& + expression() const { return m_xpr; } + + protected: + typename XprType::Nested m_xpr; +}; + +// Eval as rvalue +template +struct TensorEvaluator, Device> +{ + typedef TensorIndexTupleOp XprType; + typedef typename XprType::Index Index; + typedef typename XprType::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + + typedef typename TensorEvaluator::Dimensions Dimensions; + static const int NumDims = internal::array_size::value; + + enum { + IsAligned = /*TensorEvaluator::IsAligned*/ false, + PacketAccess = /*TensorEvaluator::PacketAccess*/ false, + BlockAccess = false, + Layout = TensorEvaluator::Layout, + CoordAccess = false, // to be implemented + RawAccess = false + }; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorEvaluator(const XprType& op, const Device& device) + : m_impl(op.expression(), device) { } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Dimensions& dimensions() const { + return m_impl.dimensions(); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(Scalar* /*data*/) { + m_impl.evalSubExprsIfNeeded(NULL); + return true; + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void cleanup() { + m_impl.cleanup(); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const + { + return CoeffReturnType(index, m_impl.coeff(index)); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost + costPerCoeff(bool vectorized) const { + return m_impl.costPerCoeff(vectorized) + TensorOpCost(0, 0, 1); + } + + EIGEN_DEVICE_FUNC Scalar* data() const { return NULL; } + + protected: + TensorEvaluator m_impl; +}; + +namespace internal { + +/** \class TensorTupleIndex + * \ingroup CXX11_Tensor_Module + * + * \brief Converts to Tensor > and reduces to Tensor. + * + */ +template +struct traits > : public traits +{ + typedef traits XprTraits; + typedef typename XprTraits::StorageKind StorageKind; + typedef typename XprTraits::Index Index; + typedef Index Scalar; + typedef typename XprType::Nested Nested; + typedef typename remove_reference::type _Nested; + static const int NumDimensions = XprTraits::NumDimensions - array_size::value; + static const int Layout = XprTraits::Layout; +}; + +template +struct eval, Eigen::Dense> +{ + typedef const TensorTupleReducerOp& type; +}; + +template +struct nested, 1, + typename eval >::type> +{ + typedef TensorTupleReducerOp type; +}; + +} // end namespace internal + +template +class TensorTupleReducerOp : public TensorBase, ReadOnlyAccessors> +{ + public: + typedef typename Eigen::internal::traits::Scalar Scalar; + typedef typename Eigen::NumTraits::Real RealScalar; + typedef typename Eigen::internal::nested::type Nested; + typedef typename Eigen::internal::traits::StorageKind StorageKind; + typedef typename Eigen::internal::traits::Index Index; + typedef Index CoeffReturnType; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorTupleReducerOp(const XprType& expr, + const ReduceOp& reduce_op, + const int return_dim, + const Dims& reduce_dims) + : m_xpr(expr), m_reduce_op(reduce_op), m_return_dim(return_dim), m_reduce_dims(reduce_dims) {} + + EIGEN_DEVICE_FUNC + const typename internal::remove_all::type& + expression() const { return m_xpr; } + + EIGEN_DEVICE_FUNC + const ReduceOp& reduce_op() const { return m_reduce_op; } + + EIGEN_DEVICE_FUNC + const Dims& reduce_dims() const { return m_reduce_dims; } + + EIGEN_DEVICE_FUNC + int return_dim() const { return m_return_dim; } + + protected: + typename XprType::Nested m_xpr; + const ReduceOp m_reduce_op; + const int m_return_dim; + const Dims m_reduce_dims; +}; + +// Eval as rvalue +template +struct TensorEvaluator, Device> +{ + typedef TensorTupleReducerOp XprType; + typedef typename XprType::Index Index; + typedef typename XprType::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + typedef typename TensorIndexTupleOp::CoeffReturnType TupleType; + typedef typename TensorEvaluator >, Device>::Dimensions Dimensions; + typedef typename TensorEvaluator , Device>::Dimensions InputDimensions; + static const int NumDims = internal::array_size::value; + typedef array StrideDims; + + enum { + IsAligned = /*TensorEvaluator::IsAligned*/ false, + PacketAccess = /*TensorEvaluator::PacketAccess*/ false, + BlockAccess = false, + Layout = TensorEvaluator >, Device>::Layout, + CoordAccess = false, // to be implemented + RawAccess = false + }; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorEvaluator(const XprType& op, const Device& device) + : m_orig_impl(op.expression(), device), + m_impl(op.expression().index_tuples().reduce(op.reduce_dims(), op.reduce_op()), device), + m_return_dim(op.return_dim()) { + + gen_strides(m_orig_impl.dimensions(), m_strides); + if (Layout == static_cast(ColMajor)) { + const Index total_size = internal::array_prod(m_orig_impl.dimensions()); + m_stride_mod = (m_return_dim < NumDims - 1) ? m_strides[m_return_dim + 1] : total_size; + } else { + const Index total_size = internal::array_prod(m_orig_impl.dimensions()); + m_stride_mod = (m_return_dim > 0) ? m_strides[m_return_dim - 1] : total_size; + } + m_stride_div = m_strides[m_return_dim]; + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Dimensions& dimensions() const { + return m_impl.dimensions(); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(Scalar* /*data*/) { + m_impl.evalSubExprsIfNeeded(NULL); + return true; + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void cleanup() { + m_impl.cleanup(); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const { + const TupleType v = m_impl.coeff(index); + return (m_return_dim < 0) ? v.first : (v.first % m_stride_mod) / m_stride_div; + } + + EIGEN_DEVICE_FUNC Scalar* data() const { return NULL; } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost + costPerCoeff(bool vectorized) const { + const double compute_cost = 1.0 + + (m_return_dim < 0 ? 0.0 : (TensorOpCost::ModCost() + TensorOpCost::DivCost())); + return m_orig_impl.costPerCoeff(vectorized) + + m_impl.costPerCoeff(vectorized) + TensorOpCost(0, 0, compute_cost); + } + + private: + EIGEN_DEVICE_FUNC void gen_strides(const InputDimensions& dims, StrideDims& strides) { + if (m_return_dim < 0) { + return; // Won't be using the strides. + } + eigen_assert(m_return_dim < NumDims && + "Asking to convert index to a dimension outside of the rank"); + + // Calculate m_stride_div and m_stride_mod, which are used to + // calculate the value of an index w.r.t. the m_return_dim. + if (Layout == static_cast(ColMajor)) { + strides[0] = 1; + for (int i = 1; i < NumDims; ++i) { + strides[i] = strides[i-1] * dims[i-1]; + } + } else { + strides[NumDims-1] = 1; + for (int i = NumDims - 2; i >= 0; --i) { + strides[i] = strides[i+1] * dims[i+1]; + } + } + } + + protected: + TensorEvaluator, Device> m_orig_impl; + TensorEvaluator >, Device> m_impl; + const int m_return_dim; + StrideDims m_strides; + Index m_stride_mod; + Index m_stride_div; +}; + +} // end namespace Eigen + +#endif // EIGEN_CXX11_TENSOR_TENSOR_ARG_MAX_H diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorAssign.h b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorAssign.h new file mode 100644 index 0000000000..166be200c5 --- /dev/null +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorAssign.h @@ -0,0 +1,181 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Benoit Steiner +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CXX11_TENSOR_TENSOR_ASSIGN_H +#define EIGEN_CXX11_TENSOR_TENSOR_ASSIGN_H + +namespace Eigen { + +/** \class TensorAssign + * \ingroup CXX11_Tensor_Module + * + * \brief The tensor assignment class. + * + * This class is represents the assignment of the values resulting from the evaluation of + * the rhs expression to the memory locations denoted by the lhs expression. + */ +namespace internal { +template +struct traits > +{ + typedef typename LhsXprType::Scalar Scalar; + typedef typename traits::StorageKind StorageKind; + typedef typename promote_index_type::Index, + typename traits::Index>::type Index; + typedef typename LhsXprType::Nested LhsNested; + typedef typename RhsXprType::Nested RhsNested; + typedef typename remove_reference::type _LhsNested; + typedef typename remove_reference::type _RhsNested; + static const std::size_t NumDimensions = internal::traits::NumDimensions; + static const int Layout = internal::traits::Layout; + + enum { + Flags = 0 + }; +}; + +template +struct eval, Eigen::Dense> +{ + typedef const TensorAssignOp& type; +}; + +template +struct nested, 1, typename eval >::type> +{ + typedef TensorAssignOp type; +}; + +} // end namespace internal + + + +template +class TensorAssignOp : public TensorBase > +{ + public: + typedef typename Eigen::internal::traits::Scalar Scalar; + typedef typename Eigen::NumTraits::Real RealScalar; + typedef typename LhsXprType::CoeffReturnType CoeffReturnType; + typedef typename Eigen::internal::nested::type Nested; + typedef typename Eigen::internal::traits::StorageKind StorageKind; + typedef typename Eigen::internal::traits::Index Index; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorAssignOp(LhsXprType& lhs, const RhsXprType& rhs) + : m_lhs_xpr(lhs), m_rhs_xpr(rhs) {} + + /** \returns the nested expressions */ + EIGEN_DEVICE_FUNC + typename internal::remove_all::type& + lhsExpression() const { return *((typename internal::remove_all::type*)&m_lhs_xpr); } + + EIGEN_DEVICE_FUNC + const typename internal::remove_all::type& + rhsExpression() const { return m_rhs_xpr; } + + protected: + typename internal::remove_all::type& m_lhs_xpr; + const typename internal::remove_all::type& m_rhs_xpr; +}; + + +template +struct TensorEvaluator, Device> +{ + typedef TensorAssignOp XprType; + typedef typename XprType::Index Index; + typedef typename XprType::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + typedef typename PacketType::type PacketReturnType; + typedef typename TensorEvaluator::Dimensions Dimensions; + static const int PacketSize = internal::unpacket_traits::size; + + enum { + IsAligned = TensorEvaluator::IsAligned & TensorEvaluator::IsAligned, + PacketAccess = TensorEvaluator::PacketAccess & TensorEvaluator::PacketAccess, + Layout = TensorEvaluator::Layout, + RawAccess = TensorEvaluator::RawAccess + }; + + EIGEN_DEVICE_FUNC TensorEvaluator(const XprType& op, const Device& device) : + m_leftImpl(op.lhsExpression(), device), + m_rightImpl(op.rhsExpression(), device) + { + EIGEN_STATIC_ASSERT((static_cast(TensorEvaluator::Layout) == static_cast(TensorEvaluator::Layout)), YOU_MADE_A_PROGRAMMING_MISTAKE); + } + + EIGEN_DEVICE_FUNC const Dimensions& dimensions() const + { + // The dimensions of the lhs and the rhs tensors should be equal to prevent + // overflows and ensure the result is fully initialized. + // TODO: use left impl instead if right impl dimensions are known at compile time. + return m_rightImpl.dimensions(); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(Scalar*) { + eigen_assert(dimensions_match(m_leftImpl.dimensions(), m_rightImpl.dimensions())); + m_leftImpl.evalSubExprsIfNeeded(NULL); + // If the lhs provides raw access to its storage area (i.e. if m_leftImpl.data() returns a non + // null value), attempt to evaluate the rhs expression in place. Returns true iff in place + // evaluation isn't supported and the caller still needs to manually assign the values generated + // by the rhs to the lhs. + return m_rightImpl.evalSubExprsIfNeeded(m_leftImpl.data()); + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void cleanup() { + m_leftImpl.cleanup(); + m_rightImpl.cleanup(); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void evalScalar(Index i) { + m_leftImpl.coeffRef(i) = m_rightImpl.coeff(i); + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void evalPacket(Index i) { + const int LhsStoreMode = TensorEvaluator::IsAligned ? Aligned : Unaligned; + const int RhsLoadMode = TensorEvaluator::IsAligned ? Aligned : Unaligned; + m_leftImpl.template writePacket(i, m_rightImpl.template packet(i)); + } + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index index) const + { + return m_leftImpl.coeff(index); + } + template + EIGEN_DEVICE_FUNC PacketReturnType packet(Index index) const + { + return m_leftImpl.template packet(index); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost + costPerCoeff(bool vectorized) const { + // We assume that evalPacket or evalScalar is called to perform the + // assignment and account for the cost of the write here, but reduce left + // cost by one load because we are using m_leftImpl.coeffRef. + TensorOpCost left = m_leftImpl.costPerCoeff(vectorized); + return m_rightImpl.costPerCoeff(vectorized) + + TensorOpCost( + numext::maxi(0.0, left.bytes_loaded() - sizeof(CoeffReturnType)), + left.bytes_stored(), left.compute_cycles()) + + TensorOpCost(0, sizeof(CoeffReturnType), 0, vectorized, PacketSize); + } + + /// required by sycl in order to extract the accessor + const TensorEvaluator& left_impl() const { return m_leftImpl; } + /// required by sycl in order to extract the accessor + const TensorEvaluator& right_impl() const { return m_rightImpl; } + + EIGEN_DEVICE_FUNC CoeffReturnType* data() const { return m_leftImpl.data(); } + + private: + TensorEvaluator m_leftImpl; + TensorEvaluator m_rightImpl; +}; + +} + + +#endif // EIGEN_CXX11_TENSOR_TENSOR_ASSIGN_H diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorBase.h b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorBase.h new file mode 100644 index 0000000000..7a45a5cf48 --- /dev/null +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorBase.h @@ -0,0 +1,1010 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Benoit Steiner +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CXX11_TENSOR_TENSOR_BASE_H +#define EIGEN_CXX11_TENSOR_TENSOR_BASE_H + +// clang-format off + +namespace Eigen { + +/** \class TensorBase + * \ingroup CXX11_Tensor_Module + * + * \brief The tensor base class. + * + * This class is the common parent of the Tensor and TensorMap class, thus + * making it possible to use either class interchangably in expressions. + */ + +template +class TensorBase +{ + public: + typedef internal::traits DerivedTraits; + typedef typename DerivedTraits::Scalar Scalar; + typedef typename DerivedTraits::Index Index; + typedef typename internal::remove_const::type CoeffReturnType; + static const int NumDimensions = DerivedTraits::NumDimensions; + + // Generic nullary operation support. + template EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const TensorCwiseNullaryOp + nullaryExpr(const CustomNullaryOp& func) const { + return TensorCwiseNullaryOp(derived(), func); + } + + // Coefficient-wise nullary operators + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const TensorCwiseNullaryOp, const Derived> + constant(const Scalar& value) const { + return nullaryExpr(internal::scalar_constant_op(value)); + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const TensorCwiseNullaryOp, const Derived> + random() const { + return nullaryExpr(internal::UniformRandomGenerator()); + } + template EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const TensorCwiseNullaryOp + random(const RandomGenerator& gen = RandomGenerator()) const { + return nullaryExpr(gen); + } + + // Tensor generation + template EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const TensorGeneratorOp + generate(const Generator& generator) const { + return TensorGeneratorOp(derived(), generator); + } + + // Generic unary operation support. + template EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const TensorCwiseUnaryOp + unaryExpr(const CustomUnaryOp& func) const { + return TensorCwiseUnaryOp(derived(), func); + } + + // Coefficient-wise unary operators + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const TensorCwiseUnaryOp, const Derived> + operator-() const { + return unaryExpr(internal::scalar_opposite_op()); + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const TensorCwiseUnaryOp, const Derived> + sqrt() const { + return unaryExpr(internal::scalar_sqrt_op()); + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const TensorCwiseUnaryOp, const Derived> + sign() const { + return unaryExpr(internal::scalar_sign_op()); + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const TensorCwiseUnaryOp, const Derived> + rsqrt() const { + return unaryExpr(internal::scalar_rsqrt_op()); + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const TensorCwiseUnaryOp, const Derived> + square() const { + return unaryExpr(internal::scalar_square_op()); + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const TensorCwiseUnaryOp, const Derived> + cube() const { + return unaryExpr(internal::scalar_cube_op()); + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const TensorCwiseUnaryOp, const Derived> + inverse() const { + return unaryExpr(internal::scalar_inverse_op()); + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const TensorCwiseUnaryOp, const Derived> + tanh() const { + return unaryExpr(internal::scalar_tanh_op()); + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const TensorCwiseUnaryOp, const Derived> + lgamma() const { + return unaryExpr(internal::scalar_lgamma_op()); + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const TensorCwiseUnaryOp, const Derived> + digamma() const { + return unaryExpr(internal::scalar_digamma_op()); + } + + // igamma(a = this, x = other) + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorCwiseBinaryOp, const Derived, const OtherDerived> + igamma(const OtherDerived& other) const { + return binaryExpr(other.derived(), internal::scalar_igamma_op()); + } + + // igammac(a = this, x = other) + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorCwiseBinaryOp, const Derived, const OtherDerived> + igammac(const OtherDerived& other) const { + return binaryExpr(other.derived(), internal::scalar_igammac_op()); + } + + // zeta(x = this, q = other) + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorCwiseBinaryOp, const Derived, const OtherDerived> + zeta(const OtherDerived& other) const { + return binaryExpr(other.derived(), internal::scalar_zeta_op()); + } + + // polygamma(n = this, x = other) + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorCwiseBinaryOp, const Derived, const OtherDerived> + polygamma(const OtherDerived& other) const { + return binaryExpr(other.derived(), internal::scalar_polygamma_op()); + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const TensorCwiseUnaryOp, const Derived> + erf() const { + return unaryExpr(internal::scalar_erf_op()); + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const TensorCwiseUnaryOp, const Derived> + erfc() const { + return unaryExpr(internal::scalar_erfc_op()); + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const TensorCwiseUnaryOp, const Derived> + sigmoid() const { + return unaryExpr(internal::scalar_sigmoid_op()); + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const TensorCwiseUnaryOp, const Derived> + exp() const { + return unaryExpr(internal::scalar_exp_op()); + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const TensorCwiseUnaryOp, const Derived> + log() const { + return unaryExpr(internal::scalar_log_op()); + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const TensorCwiseUnaryOp, const Derived> + log1p() const { + return unaryExpr(internal::scalar_log1p_op()); + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const TensorCwiseUnaryOp, const Derived> + abs() const { + return unaryExpr(internal::scalar_abs_op()); + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const TensorCwiseUnaryOp, const Derived> + conjugate() const { + return unaryExpr(internal::scalar_conjugate_op()); + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const TensorCwiseUnaryOp >, const Derived> + pow(Scalar exponent) const { + return unaryExpr(internal::bind2nd_op >(exponent)); + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const TensorCwiseUnaryOp, const Derived> + real() const { + return unaryExpr(internal::scalar_real_op()); + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const TensorCwiseUnaryOp, const Derived> + imag() const { + return unaryExpr(internal::scalar_imag_op()); + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const TensorCwiseUnaryOp >, const Derived> + operator+ (Scalar rhs) const { + return unaryExpr(internal::bind2nd_op >(rhs)); + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE friend + const TensorCwiseUnaryOp >, const Derived> + operator+ (Scalar lhs, const Derived& rhs) { + return rhs.unaryExpr(internal::bind1st_op >(lhs)); + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const TensorCwiseUnaryOp >, const Derived> + operator- (Scalar rhs) const { + EIGEN_STATIC_ASSERT((NumTraits::IsSigned || internal::is_same >::value), YOU_MADE_A_PROGRAMMING_MISTAKE); + return unaryExpr(internal::bind2nd_op >(rhs)); + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE friend + const TensorCwiseUnaryOp >, const Derived> + operator- (Scalar lhs, const Derived& rhs) { + return rhs.unaryExpr(internal::bind1st_op >(lhs)); + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const TensorCwiseUnaryOp >, const Derived> + operator* (Scalar rhs) const { + return unaryExpr(internal::bind2nd_op >(rhs)); + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE friend + const TensorCwiseUnaryOp >, const Derived> + operator* (Scalar lhs, const Derived& rhs) { + return rhs.unaryExpr(internal::bind1st_op >(lhs)); + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const TensorCwiseUnaryOp >, const Derived> + operator/ (Scalar rhs) const { + return unaryExpr(internal::bind2nd_op >(rhs)); + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE friend + const TensorCwiseUnaryOp >, const Derived> + operator/ (Scalar lhs, const Derived& rhs) { + return rhs.unaryExpr(internal::bind1st_op >(lhs)); + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const TensorCwiseUnaryOp, const Derived> + operator% (Scalar rhs) const { + EIGEN_STATIC_ASSERT(NumTraits::IsInteger, YOU_MADE_A_PROGRAMMING_MISTAKE_TRY_MOD); + return unaryExpr(internal::scalar_mod_op(rhs)); + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const TensorCwiseBinaryOp, const Derived, const TensorCwiseNullaryOp, const Derived> > + cwiseMax(Scalar threshold) const { + return cwiseMax(constant(threshold)); + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const TensorCwiseBinaryOp, const Derived, const TensorCwiseNullaryOp, const Derived> > + cwiseMin(Scalar threshold) const { + return cwiseMin(constant(threshold)); + } + + template EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const TensorConversionOp + cast() const { + return TensorConversionOp(derived()); + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const TensorCwiseUnaryOp, const Derived> + round() const { + return unaryExpr(internal::scalar_round_op()); + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const TensorCwiseUnaryOp, const Derived> + ceil() const { + return unaryExpr(internal::scalar_ceil_op()); + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const TensorCwiseUnaryOp, const Derived> + floor() const { + return unaryExpr(internal::scalar_floor_op()); + } + + // Generic binary operation support. + template EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const TensorCwiseBinaryOp + binaryExpr(const OtherDerived& other, const CustomBinaryOp& func) const { + return TensorCwiseBinaryOp(derived(), other, func); + } + + // Coefficient-wise binary operators. + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorCwiseBinaryOp, const Derived, const OtherDerived> + operator+(const OtherDerived& other) const { + return binaryExpr(other.derived(), internal::scalar_sum_op()); + } + + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorCwiseBinaryOp, const Derived, const OtherDerived> + operator-(const OtherDerived& other) const { + return binaryExpr(other.derived(), internal::scalar_difference_op()); + } + + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorCwiseBinaryOp, const Derived, const OtherDerived> + operator*(const OtherDerived& other) const { + return binaryExpr(other.derived(), internal::scalar_product_op()); + } + + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorCwiseBinaryOp, const Derived, const OtherDerived> + operator/(const OtherDerived& other) const { + return binaryExpr(other.derived(), internal::scalar_quotient_op()); + } + + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorCwiseBinaryOp, const Derived, const OtherDerived> + cwiseMax(const OtherDerived& other) const { + return binaryExpr(other.derived(), internal::scalar_max_op()); + } + + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorCwiseBinaryOp, const Derived, const OtherDerived> + cwiseMin(const OtherDerived& other) const { + return binaryExpr(other.derived(), internal::scalar_min_op()); + } + + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorCwiseBinaryOp + operator&&(const OtherDerived& other) const { + return binaryExpr(other.derived(), internal::scalar_boolean_and_op()); + } + + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorCwiseBinaryOp + operator||(const OtherDerived& other) const { + return binaryExpr(other.derived(), internal::scalar_boolean_or_op()); + } + + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorCwiseBinaryOp + operator^(const OtherDerived& other) const { + return binaryExpr(other.derived(), internal::scalar_boolean_xor_op()); + } + + // Comparisons and tests. + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorCwiseBinaryOp, const Derived, const OtherDerived> + operator<(const OtherDerived& other) const { + return binaryExpr(other.derived(), internal::scalar_cmp_op()); + } + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorCwiseBinaryOp, const Derived, const OtherDerived> + operator<=(const OtherDerived& other) const { + return binaryExpr(other.derived(), internal::scalar_cmp_op()); + } + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorCwiseBinaryOp, const Derived, const OtherDerived> + operator>(const OtherDerived& other) const { + return binaryExpr(other.derived(), internal::scalar_cmp_op()); + } + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorCwiseBinaryOp, const Derived, const OtherDerived> + operator>=(const OtherDerived& other) const { + return binaryExpr(other.derived(), internal::scalar_cmp_op()); + } + + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorCwiseBinaryOp, const Derived, const OtherDerived> + operator==(const OtherDerived& other) const { + return binaryExpr(other.derived(), internal::scalar_cmp_op()); + } + + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorCwiseBinaryOp, const Derived, const OtherDerived> + operator!=(const OtherDerived& other) const { + return binaryExpr(other.derived(), internal::scalar_cmp_op()); + } + + // comparisons and tests for Scalars + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const TensorCwiseBinaryOp, const Derived, const TensorCwiseNullaryOp, const Derived> > + operator<(Scalar threshold) const { + return operator<(constant(threshold)); + } + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const TensorCwiseBinaryOp, const Derived, const TensorCwiseNullaryOp, const Derived> > + operator<=(Scalar threshold) const { + return operator<=(constant(threshold)); + } + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const TensorCwiseBinaryOp, const Derived, const TensorCwiseNullaryOp, const Derived> > + operator>(Scalar threshold) const { + return operator>(constant(threshold)); + } + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const TensorCwiseBinaryOp, const Derived, const TensorCwiseNullaryOp, const Derived> > + operator>=(Scalar threshold) const { + return operator>=(constant(threshold)); + } + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const TensorCwiseBinaryOp, const Derived, const TensorCwiseNullaryOp, const Derived> > + operator==(Scalar threshold) const { + return operator==(constant(threshold)); + } + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const TensorCwiseBinaryOp, const Derived, const TensorCwiseNullaryOp, const Derived> > + operator!=(Scalar threshold) const { + return operator!=(constant(threshold)); + } + + // Checks + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const TensorCwiseUnaryOp, const Derived> + (isnan)() const { + return unaryExpr(internal::scalar_isnan_op()); + } + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const TensorCwiseUnaryOp, const Derived> + (isinf)() const { + return unaryExpr(internal::scalar_isinf_op()); + } + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const TensorCwiseUnaryOp, const Derived> + (isfinite)() const { + return unaryExpr(internal::scalar_isfinite_op()); + } + + // Coefficient-wise ternary operators. + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorSelectOp + select(const ThenDerived& thenTensor, const ElseDerived& elseTensor) const { + return TensorSelectOp(derived(), thenTensor.derived(), elseTensor.derived()); + } + + // Contractions. + typedef Eigen::IndexPair DimensionPair; + + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorContractionOp + contract(const OtherDerived& other, const Dimensions& dims) const { + return TensorContractionOp(derived(), other.derived(), dims); + } + + // Convolutions. + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorConvolutionOp + convolve(const KernelDerived& kernel, const Dimensions& dims) const { + return TensorConvolutionOp(derived(), kernel.derived(), dims); + } + + // Fourier transforms + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorFFTOp + fft(const FFT& fft) const { + return TensorFFTOp(derived(), fft); + } + + // Scan. + typedef TensorScanOp, const Derived> TensorScanSumOp; + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorScanSumOp + cumsum(const Index& axis, bool exclusive = false) const { + return TensorScanSumOp(derived(), axis, exclusive); + } + + typedef TensorScanOp, const Derived> TensorScanProdOp; + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorScanProdOp + cumprod(const Index& axis, bool exclusive = false) const { + return TensorScanProdOp(derived(), axis, exclusive); + } + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorScanOp + scan(const Index& axis, const Reducer& reducer, bool exclusive = false) const { + return TensorScanOp(derived(), axis, exclusive, reducer); + } + + // Reductions. + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorReductionOp, const Dims, const Derived> + sum(const Dims& dims) const { + return TensorReductionOp, const Dims, const Derived>(derived(), dims, internal::SumReducer()); + } + + const TensorReductionOp, const DimensionList, const Derived> + sum() const { + DimensionList in_dims; + return TensorReductionOp, const DimensionList, const Derived>(derived(), in_dims, internal::SumReducer()); + } + + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorReductionOp, const Dims, const Derived> + mean(const Dims& dims) const { + return TensorReductionOp, const Dims, const Derived>(derived(), dims, internal::MeanReducer()); + } + + const TensorReductionOp, const DimensionList, const Derived> + mean() const { + DimensionList in_dims; + return TensorReductionOp, const DimensionList, const Derived>(derived(), in_dims, internal::MeanReducer()); + } + + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorReductionOp, const Dims, const Derived> + prod(const Dims& dims) const { + return TensorReductionOp, const Dims, const Derived>(derived(), dims, internal::ProdReducer()); + } + + const TensorReductionOp, const DimensionList, const Derived> + prod() const { + DimensionList in_dims; + return TensorReductionOp, const DimensionList, const Derived>(derived(), in_dims, internal::ProdReducer()); + } + + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorReductionOp, const Dims, const Derived> + maximum(const Dims& dims) const { + return TensorReductionOp, const Dims, const Derived>(derived(), dims, internal::MaxReducer()); + } + + const TensorReductionOp, const DimensionList, const Derived> + maximum() const { + DimensionList in_dims; + return TensorReductionOp, const DimensionList, const Derived>(derived(), in_dims, internal::MaxReducer()); + } + + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorReductionOp, const Dims, const Derived> + minimum(const Dims& dims) const { + return TensorReductionOp, const Dims, const Derived>(derived(), dims, internal::MinReducer()); + } + + const TensorReductionOp, const DimensionList, const Derived> + minimum() const { + DimensionList in_dims; + return TensorReductionOp, const DimensionList, const Derived>(derived(), in_dims, internal::MinReducer()); + } + + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorReductionOp > + all(const Dims& dims) const { + return cast().reduce(dims, internal::AndReducer()); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorReductionOp, const TensorConversionOp > + all() const { + DimensionList in_dims; + return cast().reduce(in_dims, internal::AndReducer()); + } + + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorReductionOp > + any(const Dims& dims) const { + return cast().reduce(dims, internal::OrReducer()); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorReductionOp, const TensorConversionOp > + any() const { + DimensionList in_dims; + return cast().reduce(in_dims, internal::OrReducer()); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorTupleReducerOp< + internal::ArgMaxTupleReducer >, + const array, const Derived> + argmax() const { + array in_dims; + for (int d = 0; d < NumDimensions; ++d) in_dims[d] = d; + return TensorTupleReducerOp< + internal::ArgMaxTupleReducer >, + const array, + const Derived>(derived(), internal::ArgMaxTupleReducer >(), -1, in_dims); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorTupleReducerOp< + internal::ArgMinTupleReducer >, + const array, const Derived> + argmin() const { + array in_dims; + for (int d = 0; d < NumDimensions; ++d) in_dims[d] = d; + return TensorTupleReducerOp< + internal::ArgMinTupleReducer >, + const array, + const Derived>(derived(), internal::ArgMinTupleReducer >(), -1, in_dims); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorTupleReducerOp< + internal::ArgMaxTupleReducer >, + const array, const Derived> + argmax(const int return_dim) const { + array in_dims; + in_dims[0] = return_dim; + return TensorTupleReducerOp< + internal::ArgMaxTupleReducer >, + const array, + const Derived>(derived(), internal::ArgMaxTupleReducer >(), return_dim, in_dims); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorTupleReducerOp< + internal::ArgMinTupleReducer >, + const array, const Derived> + argmin(const int return_dim) const { + array in_dims; + in_dims[0] = return_dim; + return TensorTupleReducerOp< + internal::ArgMinTupleReducer >, + const array, + const Derived>(derived(), internal::ArgMinTupleReducer >(), return_dim, in_dims); + } + + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorReductionOp + reduce(const Dims& dims, const Reducer& reducer) const { + return TensorReductionOp(derived(), dims, reducer); + } + + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorBroadcastingOp + broadcast(const Broadcast& broadcast) const { + return TensorBroadcastingOp(derived(), broadcast); + } + + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorConcatenationOp + concatenate(const OtherDerived& other, Axis axis) const { + return TensorConcatenationOp(derived(), other.derived(), axis); + } + + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorPatchOp + extract_patches(const PatchDims& patch_dims) const { + return TensorPatchOp(derived(), patch_dims); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorImagePatchOp + extract_image_patches(const Index patch_rows = 1, const Index patch_cols = 1, + const Index row_stride = 1, const Index col_stride = 1, + const Index in_row_stride = 1, const Index in_col_stride = 1, + const PaddingType padding_type = PADDING_SAME, const Scalar padding_value = Scalar(0)) const { + return TensorImagePatchOp(derived(), patch_rows, patch_cols, row_stride, col_stride, + in_row_stride, in_col_stride, 1, 1, padding_type, padding_value); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorImagePatchOp + extract_image_patches(const Index patch_rows, const Index patch_cols, + const Index row_stride, const Index col_stride, + const Index in_row_stride, const Index in_col_stride, + const Index row_inflate_stride, const Index col_inflate_stride, + const Index padding_top, const Index padding_bottom, + const Index padding_left,const Index padding_right, + const Scalar padding_value) const { + return TensorImagePatchOp(derived(), patch_rows, patch_cols, row_stride, col_stride, + in_row_stride, in_col_stride, row_inflate_stride, col_inflate_stride, + padding_top, padding_bottom, padding_left, padding_right, padding_value); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorVolumePatchOp + extract_volume_patches(const Index patch_planes, const Index patch_rows, const Index patch_cols, + const Index plane_stride = 1, const Index row_stride = 1, const Index col_stride = 1, + const PaddingType padding_type = PADDING_SAME, const Scalar padding_value = Scalar(0)) const { + return TensorVolumePatchOp(derived(), patch_planes, patch_rows, patch_cols, plane_stride, row_stride, col_stride, 1, 1, 1, 1, 1, 1, padding_type, padding_value); + } + + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorVolumePatchOp + extract_volume_patches(const Index patch_planes, const Index patch_rows, const Index patch_cols, + const Index plane_stride, const Index row_stride, const Index col_stride, + const Index plane_inflate_stride, const Index row_inflate_stride, const Index col_inflate_stride, + const Index padding_top_z, const Index padding_bottom_z, + const Index padding_top, const Index padding_bottom, + const Index padding_left, const Index padding_right, const Scalar padding_value = Scalar(0)) const { + return TensorVolumePatchOp(derived(), patch_planes, patch_rows, patch_cols, plane_stride, row_stride, col_stride, 1, 1, 1, plane_inflate_stride, row_inflate_stride, col_inflate_stride, padding_top_z, padding_bottom_z, padding_top, padding_bottom, padding_left, padding_right, padding_value); + } + + // Morphing operators. + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorLayoutSwapOp + swap_layout() const { + return TensorLayoutSwapOp(derived()); + } + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorReshapingOp + reshape(const NewDimensions& newDimensions) const { + return TensorReshapingOp(derived(), newDimensions); + } + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorSlicingOp + slice(const StartIndices& startIndices, const Sizes& sizes) const { + return TensorSlicingOp(derived(), startIndices, sizes); + } + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorStridingSlicingOp + stridedSlice(const StartIndices& startIndices, const StopIndices& stopIndices, const Strides& strides) const { + return TensorStridingSlicingOp(derived(), startIndices, stopIndices, strides); + } + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorChippingOp + chip(const Index offset) const { + return TensorChippingOp(derived(), offset, DimId); + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorChippingOp + chip(const Index offset, const Index dim) const { + return TensorChippingOp(derived(), offset, dim); + } + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorReverseOp + reverse(const ReverseDimensions& rev) const { + return TensorReverseOp(derived(), rev); + } + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorPaddingOp + pad(const PaddingDimensions& padding) const { + return TensorPaddingOp(derived(), padding, internal::scalar_cast_op()(0)); + } + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorPaddingOp + pad(const PaddingDimensions& padding, const Scalar padding_value) const { + return TensorPaddingOp(derived(), padding, padding_value); + } + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorShufflingOp + shuffle(const Shuffle& shuffle) const { + return TensorShufflingOp(derived(), shuffle); + } + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorStridingOp + stride(const Strides& strides) const { + return TensorStridingOp(derived(), strides); + } + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorInflationOp + inflate(const Strides& strides) const { + return TensorInflationOp(derived(), strides); + } + + // Returns a tensor containing index/value tuples + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorIndexTupleOp + index_tuples() const { + return TensorIndexTupleOp(derived()); + } + + // Support for custom unary and binary operations + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorCustomUnaryOp customOp(const CustomUnaryFunc& op) const { + return TensorCustomUnaryOp(derived(), op); + } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorCustomBinaryOp customOp(const OtherDerived& other, const CustomBinaryFunc& op) const { + return TensorCustomBinaryOp(derived(), other, op); + } + + // Force the evaluation of the expression. + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorForcedEvalOp eval() const { + return TensorForcedEvalOp(derived()); + } + + protected: + template friend class Tensor; + template friend class TensorFixedSize; + template friend class TensorBase; + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const Derived& derived() const { return *static_cast(this); } +}; + +template::value> +class TensorBase : public TensorBase { + public: + typedef internal::traits DerivedTraits; + typedef typename DerivedTraits::Scalar Scalar; + typedef typename DerivedTraits::Index Index; + typedef Scalar CoeffReturnType; + static const int NumDimensions = DerivedTraits::NumDimensions; + + template friend class Tensor; + template friend class TensorFixedSize; + template friend class TensorBase; + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Derived& setZero() { + return setConstant(Scalar(0)); + } + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Derived& setConstant(const Scalar& val) { + return derived() = this->constant(val); + } + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Derived& setRandom() { + return derived() = this->random(); + } + template EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Derived& setRandom() { + return derived() = this->template random(); + } + +#if EIGEN_HAS_VARIADIC_TEMPLATES + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Derived& setValues( + const typename internal::Initializer::InitList& vals) { + TensorEvaluator eval(derived(), DefaultDevice()); + internal::initialize_tensor(eval, vals); + return derived(); + } +#endif // EIGEN_HAS_VARIADIC_TEMPLATES + + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Derived& operator+=(const OtherDerived& other) { + return derived() = derived() + other.derived(); + } + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Derived& operator-=(const OtherDerived& other) { + return derived() = derived() - other.derived(); + } + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Derived& operator*=(const OtherDerived& other) { + return derived() = derived() * other.derived(); + } + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Derived& operator/=(const OtherDerived& other) { + return derived() = derived() / other.derived(); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorLayoutSwapOp + swap_layout() const { + return TensorLayoutSwapOp(derived()); + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + TensorLayoutSwapOp + swap_layout() { + return TensorLayoutSwapOp(derived()); + } + + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorConcatenationOp + concatenate(const OtherDerived& other, const Axis& axis) const { + return TensorConcatenationOp(derived(), other, axis); + } + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + TensorConcatenationOp + concatenate(const OtherDerived& other, const Axis& axis) { + return TensorConcatenationOp(derived(), other, axis); + } + + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorReshapingOp + reshape(const NewDimensions& newDimensions) const { + return TensorReshapingOp(derived(), newDimensions); + } + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + TensorReshapingOp + reshape(const NewDimensions& newDimensions) { + return TensorReshapingOp(derived(), newDimensions); + } + + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorSlicingOp + slice(const StartIndices& startIndices, const Sizes& sizes) const { + return TensorSlicingOp(derived(), startIndices, sizes); + } + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + TensorSlicingOp + slice(const StartIndices& startIndices, const Sizes& sizes) { + return TensorSlicingOp(derived(), startIndices, sizes); + } + + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorStridingSlicingOp + stridedSlice(const StartIndices& startIndices, const StopIndices& stopIndices, const Strides& strides) const { + return TensorStridingSlicingOp(derived(), startIndices, stopIndices, strides); + } + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + TensorStridingSlicingOp + stridedSlice(const StartIndices& startIndices, const StopIndices& stopIndices, const Strides& strides) { + return TensorStridingSlicingOp(derived(), startIndices, stopIndices, strides); + } + + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorChippingOp + chip(const Index offset) const { + return TensorChippingOp(derived(), offset, DimId); + } + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + TensorChippingOp + chip(const Index offset) { + return TensorChippingOp(derived(), offset, DimId); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorChippingOp + chip(const Index offset, const Index dim) const { + return TensorChippingOp(derived(), offset, dim); + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + TensorChippingOp + chip(const Index offset, const Index dim) { + return TensorChippingOp(derived(), offset, dim); + } + + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorReverseOp + reverse(const ReverseDimensions& rev) const { + return TensorReverseOp(derived(), rev); + } + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + TensorReverseOp + reverse(const ReverseDimensions& rev) { + return TensorReverseOp(derived(), rev); + } + + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorShufflingOp + shuffle(const Shuffle& shuffle) const { + return TensorShufflingOp(derived(), shuffle); + } + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + TensorShufflingOp + shuffle(const Shuffle& shuffle) { + return TensorShufflingOp(derived(), shuffle); + } + + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const TensorStridingOp + stride(const Strides& strides) const { + return TensorStridingOp(derived(), strides); + } + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + TensorStridingOp + stride(const Strides& strides) { + return TensorStridingOp(derived(), strides); + } + + // Select the device on which to evaluate the expression. + template + TensorDevice device(const DeviceType& device) { + return TensorDevice(device, derived()); + } + + protected: + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Derived& derived() { return *static_cast(this); } + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const Derived& derived() const { return *static_cast(this); } +}; + +} // end namespace Eigen + +#endif // EIGEN_CXX11_TENSOR_TENSOR_BASE_H diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorBroadcasting.h b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorBroadcasting.h new file mode 100644 index 0000000000..4cfe300eb4 --- /dev/null +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorBroadcasting.h @@ -0,0 +1,392 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Benoit Steiner +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CXX11_TENSOR_TENSOR_BROADCASTING_H +#define EIGEN_CXX11_TENSOR_TENSOR_BROADCASTING_H + +namespace Eigen { + +/** \class TensorBroadcasting + * \ingroup CXX11_Tensor_Module + * + * \brief Tensor broadcasting class. + * + * + */ +namespace internal { +template +struct traits > : public traits +{ + typedef typename XprType::Scalar Scalar; + typedef traits XprTraits; + typedef typename XprTraits::StorageKind StorageKind; + typedef typename XprTraits::Index Index; + typedef typename XprType::Nested Nested; + typedef typename remove_reference::type _Nested; + static const int NumDimensions = XprTraits::NumDimensions; + static const int Layout = XprTraits::Layout; +}; + +template +struct eval, Eigen::Dense> +{ + typedef const TensorBroadcastingOp& type; +}; + +template +struct nested, 1, typename eval >::type> +{ + typedef TensorBroadcastingOp type; +}; + +template +struct is_input_scalar { + static const bool value = false; +}; +template <> +struct is_input_scalar > { + static const bool value = true; +}; +#ifndef EIGEN_EMULATE_CXX11_META_H +template +struct is_input_scalar > { + static const bool value = (Sizes::total_size == 1); +}; +#endif + +} // end namespace internal + + + +template +class TensorBroadcastingOp : public TensorBase, ReadOnlyAccessors> +{ + public: + typedef typename Eigen::internal::traits::Scalar Scalar; + typedef typename Eigen::NumTraits::Real RealScalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + typedef typename Eigen::internal::nested::type Nested; + typedef typename Eigen::internal::traits::StorageKind StorageKind; + typedef typename Eigen::internal::traits::Index Index; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorBroadcastingOp(const XprType& expr, const Broadcast& broadcast) + : m_xpr(expr), m_broadcast(broadcast) {} + + EIGEN_DEVICE_FUNC + const Broadcast& broadcast() const { return m_broadcast; } + + EIGEN_DEVICE_FUNC + const typename internal::remove_all::type& + expression() const { return m_xpr; } + + protected: + typename XprType::Nested m_xpr; + const Broadcast m_broadcast; +}; + + +// Eval as rvalue +template +struct TensorEvaluator, Device> +{ + typedef TensorBroadcastingOp XprType; + typedef typename XprType::Index Index; + static const int NumDims = internal::array_size::Dimensions>::value; + typedef DSizes Dimensions; + typedef typename XprType::Scalar Scalar; + typedef typename TensorEvaluator::Dimensions InputDimensions; + typedef typename XprType::CoeffReturnType CoeffReturnType; + typedef typename PacketType::type PacketReturnType; + static const int PacketSize = internal::unpacket_traits::size; + + enum { + IsAligned = true, + PacketAccess = TensorEvaluator::PacketAccess, + Layout = TensorEvaluator::Layout, + RawAccess = false + }; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorEvaluator(const XprType& op, const Device& device) + : m_broadcast(op.broadcast()),m_impl(op.expression(), device) + { + // The broadcasting op doesn't change the rank of the tensor. One can't broadcast a scalar + // and store the result in a scalar. Instead one should reshape the scalar into a a N-D + // tensor with N >= 1 of 1 element first and then broadcast. + EIGEN_STATIC_ASSERT((NumDims > 0), YOU_MADE_A_PROGRAMMING_MISTAKE); + const InputDimensions& input_dims = m_impl.dimensions(); + const Broadcast& broadcast = op.broadcast(); + for (int i = 0; i < NumDims; ++i) { + eigen_assert(input_dims[i] > 0); + m_dimensions[i] = input_dims[i] * broadcast[i]; + } + + if (static_cast(Layout) == static_cast(ColMajor)) { + m_inputStrides[0] = 1; + m_outputStrides[0] = 1; + for (int i = 1; i < NumDims; ++i) { + m_inputStrides[i] = m_inputStrides[i-1] * input_dims[i-1]; + m_outputStrides[i] = m_outputStrides[i-1] * m_dimensions[i-1]; + } + } else { + m_inputStrides[NumDims-1] = 1; + m_outputStrides[NumDims-1] = 1; + for (int i = NumDims-2; i >= 0; --i) { + m_inputStrides[i] = m_inputStrides[i+1] * input_dims[i+1]; + m_outputStrides[i] = m_outputStrides[i+1] * m_dimensions[i+1]; + } + } + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Dimensions& dimensions() const { return m_dimensions; } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(Scalar* /*data*/) { + m_impl.evalSubExprsIfNeeded(NULL); + return true; + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void cleanup() { + m_impl.cleanup(); + } + + EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE CoeffReturnType coeff(Index index) const + { + if (internal::is_input_scalar::type>::value) { + return m_impl.coeff(0); + } + + if (static_cast(Layout) == static_cast(ColMajor)) { + return coeffColMajor(index); + } else { + return coeffRowMajor(index); + } + } + + // TODO: attempt to speed this up. The integer divisions and modulo are slow + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeffColMajor(Index index) const + { + Index inputIndex = 0; + for (int i = NumDims - 1; i > 0; --i) { + const Index idx = index / m_outputStrides[i]; + if (internal::index_statically_eq(i, 1)) { + eigen_assert(idx < m_impl.dimensions()[i]); + inputIndex += idx * m_inputStrides[i]; + } else { + if (internal::index_statically_eq(i, 1)) { + eigen_assert(idx % m_impl.dimensions()[i] == 0); + } else { + inputIndex += (idx % m_impl.dimensions()[i]) * m_inputStrides[i]; + } + } + index -= idx * m_outputStrides[i]; + } + if (internal::index_statically_eq(0, 1)) { + eigen_assert(index < m_impl.dimensions()[0]); + inputIndex += index; + } else { + if (internal::index_statically_eq(0, 1)) { + eigen_assert(index % m_impl.dimensions()[0] == 0); + } else { + inputIndex += (index % m_impl.dimensions()[0]); + } + } + return m_impl.coeff(inputIndex); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeffRowMajor(Index index) const + { + Index inputIndex = 0; + for (int i = 0; i < NumDims - 1; ++i) { + const Index idx = index / m_outputStrides[i]; + if (internal::index_statically_eq(i, 1)) { + eigen_assert(idx < m_impl.dimensions()[i]); + inputIndex += idx * m_inputStrides[i]; + } else { + if (internal::index_statically_eq(i, 1)) { + eigen_assert(idx % m_impl.dimensions()[i] == 0); + } else { + inputIndex += (idx % m_impl.dimensions()[i]) * m_inputStrides[i]; + } + } + index -= idx * m_outputStrides[i]; + } + if (internal::index_statically_eq(NumDims-1, 1)) { + eigen_assert(index < m_impl.dimensions()[NumDims-1]); + inputIndex += index; + } else { + if (internal::index_statically_eq(NumDims-1, 1)) { + eigen_assert(index % m_impl.dimensions()[NumDims-1] == 0); + } else { + inputIndex += (index % m_impl.dimensions()[NumDims-1]); + } + } + return m_impl.coeff(inputIndex); + } + + template + EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE PacketReturnType packet(Index index) const + { + if (internal::is_input_scalar::type>::value) { + return internal::pset1(m_impl.coeff(0)); + } + + if (static_cast(Layout) == static_cast(ColMajor)) { + return packetColMajor(index); + } else { + return packetRowMajor(index); + } + } + + // Ignore the LoadMode and always use unaligned loads since we can't guarantee + // the alignment at compile time. + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packetColMajor(Index index) const + { + EIGEN_STATIC_ASSERT((PacketSize > 1), YOU_MADE_A_PROGRAMMING_MISTAKE) + eigen_assert(index+PacketSize-1 < dimensions().TotalSize()); + + const Index originalIndex = index; + + Index inputIndex = 0; + for (int i = NumDims - 1; i > 0; --i) { + const Index idx = index / m_outputStrides[i]; + if (internal::index_statically_eq(i, 1)) { + eigen_assert(idx < m_impl.dimensions()[i]); + inputIndex += idx * m_inputStrides[i]; + } else { + if (internal::index_statically_eq(i, 1)) { + eigen_assert(idx % m_impl.dimensions()[i] == 0); + } else { + inputIndex += (idx % m_impl.dimensions()[i]) * m_inputStrides[i]; + } + } + index -= idx * m_outputStrides[i]; + } + Index innermostLoc; + if (internal::index_statically_eq(0, 1)) { + eigen_assert(index < m_impl.dimensions()[0]); + innermostLoc = index; + } else { + if (internal::index_statically_eq(0, 1)) { + eigen_assert(index % m_impl.dimensions()[0] == 0); + innermostLoc = 0; + } else { + innermostLoc = index % m_impl.dimensions()[0]; + } + } + inputIndex += innermostLoc; + + // Todo: this could be extended to the second dimension if we're not + // broadcasting alongside the first dimension, and so on. + if (innermostLoc + PacketSize <= m_impl.dimensions()[0]) { + return m_impl.template packet(inputIndex); + } else { + EIGEN_ALIGN_MAX typename internal::remove_const::type values[PacketSize]; + values[0] = m_impl.coeff(inputIndex); + for (int i = 1; i < PacketSize; ++i) { + values[i] = coeffColMajor(originalIndex+i); + } + PacketReturnType rslt = internal::pload(values); + return rslt; + } + } + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packetRowMajor(Index index) const + { + EIGEN_STATIC_ASSERT((PacketSize > 1), YOU_MADE_A_PROGRAMMING_MISTAKE) + eigen_assert(index+PacketSize-1 < dimensions().TotalSize()); + + const Index originalIndex = index; + + Index inputIndex = 0; + for (int i = 0; i < NumDims - 1; ++i) { + const Index idx = index / m_outputStrides[i]; + if (internal::index_statically_eq(i, 1)) { + eigen_assert(idx < m_impl.dimensions()[i]); + inputIndex += idx * m_inputStrides[i]; + } else { + if (internal::index_statically_eq(i, 1)) { + eigen_assert(idx % m_impl.dimensions()[i] == 0); + } else { + inputIndex += (idx % m_impl.dimensions()[i]) * m_inputStrides[i]; + } + } + index -= idx * m_outputStrides[i]; + } + Index innermostLoc; + if (internal::index_statically_eq(NumDims-1, 1)) { + eigen_assert(index < m_impl.dimensions()[NumDims-1]); + innermostLoc = index; + } else { + if (internal::index_statically_eq(NumDims-1, 1)) { + eigen_assert(index % m_impl.dimensions()[NumDims-1] == 0); + innermostLoc = 0; + } else { + innermostLoc = index % m_impl.dimensions()[NumDims-1]; + } + } + inputIndex += innermostLoc; + + // Todo: this could be extended to the second dimension if we're not + // broadcasting alongside the first dimension, and so on. + if (innermostLoc + PacketSize <= m_impl.dimensions()[NumDims-1]) { + return m_impl.template packet(inputIndex); + } else { + EIGEN_ALIGN_MAX typename internal::remove_const::type values[PacketSize]; + values[0] = m_impl.coeff(inputIndex); + for (int i = 1; i < PacketSize; ++i) { + values[i] = coeffRowMajor(originalIndex+i); + } + PacketReturnType rslt = internal::pload(values); + return rslt; + } + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost + costPerCoeff(bool vectorized) const { + double compute_cost = TensorOpCost::AddCost(); + if (NumDims > 0) { + for (int i = NumDims - 1; i > 0; --i) { + compute_cost += TensorOpCost::DivCost(); + if (internal::index_statically_eq(i, 1)) { + compute_cost += + TensorOpCost::MulCost() + TensorOpCost::AddCost(); + } else { + if (!internal::index_statically_eq(i, 1)) { + compute_cost += TensorOpCost::MulCost() + + TensorOpCost::ModCost() + + TensorOpCost::AddCost(); + } + } + compute_cost += + TensorOpCost::MulCost() + TensorOpCost::AddCost(); + } + } + return m_impl.costPerCoeff(vectorized) + + TensorOpCost(0, 0, compute_cost, vectorized, PacketSize); + } + + EIGEN_DEVICE_FUNC Scalar* data() const { return NULL; } + + const TensorEvaluator& impl() const { return m_impl; } + + Broadcast functor() const { return m_broadcast; } + + protected: + const Broadcast m_broadcast; + Dimensions m_dimensions; + array m_outputStrides; + array m_inputStrides; + TensorEvaluator m_impl; +}; + + +} // end namespace Eigen + +#endif // EIGEN_CXX11_TENSOR_TENSOR_BROADCASTING_H diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorChipping.h b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorChipping.h new file mode 100644 index 0000000000..1ba7ef170c --- /dev/null +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorChipping.h @@ -0,0 +1,384 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Benoit Steiner +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CXX11_TENSOR_TENSOR_CHIPPING_H +#define EIGEN_CXX11_TENSOR_TENSOR_CHIPPING_H + +namespace Eigen { + +/** \class TensorKChippingReshaping + * \ingroup CXX11_Tensor_Module + * + * \brief A chip is a thin slice, corresponding to a column or a row in a 2-d tensor. + * + * + */ + +namespace internal { +template +struct traits > : public traits +{ + typedef typename XprType::Scalar Scalar; + typedef traits XprTraits; + typedef typename XprTraits::StorageKind StorageKind; + typedef typename XprTraits::Index Index; + typedef typename XprType::Nested Nested; + typedef typename remove_reference::type _Nested; + static const int NumDimensions = XprTraits::NumDimensions - 1; + static const int Layout = XprTraits::Layout; +}; + +template +struct eval, Eigen::Dense> +{ + typedef const TensorChippingOp& type; +}; + +template +struct nested, 1, typename eval >::type> +{ + typedef TensorChippingOp type; +}; + +template +struct DimensionId +{ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE DimensionId(DenseIndex dim) { + eigen_assert(dim == DimId); + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE DenseIndex actualDim() const { + return DimId; + } +}; +template <> +struct DimensionId +{ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE DimensionId(DenseIndex dim) : actual_dim(dim) { + eigen_assert(dim >= 0); + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE DenseIndex actualDim() const { + return actual_dim; + } + private: + const DenseIndex actual_dim; +}; + + +} // end namespace internal + + + +template +class TensorChippingOp : public TensorBase > +{ + public: + typedef typename Eigen::internal::traits::Scalar Scalar; + typedef typename Eigen::NumTraits::Real RealScalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + typedef typename Eigen::internal::nested::type Nested; + typedef typename Eigen::internal::traits::StorageKind StorageKind; + typedef typename Eigen::internal::traits::Index Index; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorChippingOp(const XprType& expr, const Index offset, const Index dim) + : m_xpr(expr), m_offset(offset), m_dim(dim) { + } + + EIGEN_DEVICE_FUNC + const Index offset() const { return m_offset; } + EIGEN_DEVICE_FUNC + const Index dim() const { return m_dim.actualDim(); } + + EIGEN_DEVICE_FUNC + const typename internal::remove_all::type& + expression() const { return m_xpr; } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE TensorChippingOp& operator = (const TensorChippingOp& other) + { + typedef TensorAssignOp Assign; + Assign assign(*this, other); + internal::TensorExecutor::run(assign, DefaultDevice()); + return *this; + } + + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE TensorChippingOp& operator = (const OtherDerived& other) + { + typedef TensorAssignOp Assign; + Assign assign(*this, other); + internal::TensorExecutor::run(assign, DefaultDevice()); + return *this; + } + + protected: + typename XprType::Nested m_xpr; + const Index m_offset; + const internal::DimensionId m_dim; +}; + + +// Eval as rvalue +template +struct TensorEvaluator, Device> +{ + typedef TensorChippingOp XprType; + static const int NumInputDims = internal::array_size::Dimensions>::value; + static const int NumDims = NumInputDims-1; + typedef typename XprType::Index Index; + typedef DSizes Dimensions; + typedef typename XprType::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + typedef typename PacketType::type PacketReturnType; + static const int PacketSize = internal::unpacket_traits::size; + + + enum { + // Alignment can't be guaranteed at compile time since it depends on the + // slice offsets. + IsAligned = false, + PacketAccess = TensorEvaluator::PacketAccess, + Layout = TensorEvaluator::Layout, + CoordAccess = false, // to be implemented + RawAccess = false + }; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorEvaluator(const XprType& op, const Device& device) + : m_impl(op.expression(), device), m_dim(op.dim()), m_device(device) + { + EIGEN_STATIC_ASSERT((NumInputDims >= 1), YOU_MADE_A_PROGRAMMING_MISTAKE); + eigen_assert(NumInputDims > m_dim.actualDim()); + + const typename TensorEvaluator::Dimensions& input_dims = m_impl.dimensions(); + eigen_assert(op.offset() < input_dims[m_dim.actualDim()]); + + int j = 0; + for (int i = 0; i < NumInputDims; ++i) { + if (i != m_dim.actualDim()) { + m_dimensions[j] = input_dims[i]; + ++j; + } + } + + m_stride = 1; + m_inputStride = 1; + if (static_cast(Layout) == static_cast(ColMajor)) { + for (int i = 0; i < m_dim.actualDim(); ++i) { + m_stride *= input_dims[i]; + m_inputStride *= input_dims[i]; + } + } else { + for (int i = NumInputDims-1; i > m_dim.actualDim(); --i) { + m_stride *= input_dims[i]; + m_inputStride *= input_dims[i]; + } + } + m_inputStride *= input_dims[m_dim.actualDim()]; + m_inputOffset = m_stride * op.offset(); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Dimensions& dimensions() const { return m_dimensions; } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(Scalar* /*data*/) { + m_impl.evalSubExprsIfNeeded(NULL); + return true; + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void cleanup() { + m_impl.cleanup(); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const + { + return m_impl.coeff(srcCoeff(index)); + } + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packet(Index index) const + { + EIGEN_STATIC_ASSERT((PacketSize > 1), YOU_MADE_A_PROGRAMMING_MISTAKE) + eigen_assert(index+PacketSize-1 < dimensions().TotalSize()); + + if ((static_cast(Layout) == static_cast(ColMajor) && m_dim.actualDim() == 0) || + (static_cast(Layout) == static_cast(RowMajor) && m_dim.actualDim() == NumInputDims-1)) { + // m_stride is equal to 1, so let's avoid the integer division. + eigen_assert(m_stride == 1); + Index inputIndex = index * m_inputStride + m_inputOffset; + EIGEN_ALIGN_MAX typename internal::remove_const::type values[PacketSize]; + for (int i = 0; i < PacketSize; ++i) { + values[i] = m_impl.coeff(inputIndex); + inputIndex += m_inputStride; + } + PacketReturnType rslt = internal::pload(values); + return rslt; + } else if ((static_cast(Layout) == static_cast(ColMajor) && m_dim.actualDim() == NumInputDims - 1) || + (static_cast(Layout) == static_cast(RowMajor) && m_dim.actualDim() == 0)) { + // m_stride is aways greater than index, so let's avoid the integer division. + eigen_assert(m_stride > index); + return m_impl.template packet(index + m_inputOffset); + } else { + const Index idx = index / m_stride; + const Index rem = index - idx * m_stride; + if (rem + PacketSize <= m_stride) { + Index inputIndex = idx * m_inputStride + m_inputOffset + rem; + return m_impl.template packet(inputIndex); + } else { + // Cross the stride boundary. Fallback to slow path. + EIGEN_ALIGN_MAX typename internal::remove_const::type values[PacketSize]; + for (int i = 0; i < PacketSize; ++i) { + values[i] = coeff(index); + ++index; + } + PacketReturnType rslt = internal::pload(values); + return rslt; + } + } + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost + costPerCoeff(bool vectorized) const { + double cost = 0; + if ((static_cast(Layout) == static_cast(ColMajor) && + m_dim.actualDim() == 0) || + (static_cast(Layout) == static_cast(RowMajor) && + m_dim.actualDim() == NumInputDims - 1)) { + cost += TensorOpCost::MulCost() + TensorOpCost::AddCost(); + } else if ((static_cast(Layout) == static_cast(ColMajor) && + m_dim.actualDim() == NumInputDims - 1) || + (static_cast(Layout) == static_cast(RowMajor) && + m_dim.actualDim() == 0)) { + cost += TensorOpCost::AddCost(); + } else { + cost += 3 * TensorOpCost::MulCost() + TensorOpCost::DivCost() + + 3 * TensorOpCost::AddCost(); + } + + return m_impl.costPerCoeff(vectorized) + + TensorOpCost(0, 0, cost, vectorized, PacketSize); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType* data() const { + CoeffReturnType* result = const_cast(m_impl.data()); + if (((static_cast(Layout) == static_cast(ColMajor) && m_dim.actualDim() == NumDims) || + (static_cast(Layout) == static_cast(RowMajor) && m_dim.actualDim() == 0)) && + result) { + return result + m_inputOffset; + } else { + return NULL; + } + } + + protected: + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index srcCoeff(Index index) const + { + Index inputIndex; + if ((static_cast(Layout) == static_cast(ColMajor) && m_dim.actualDim() == 0) || + (static_cast(Layout) == static_cast(RowMajor) && m_dim.actualDim() == NumInputDims-1)) { + // m_stride is equal to 1, so let's avoid the integer division. + eigen_assert(m_stride == 1); + inputIndex = index * m_inputStride + m_inputOffset; + } else if ((static_cast(Layout) == static_cast(ColMajor) && m_dim.actualDim() == NumInputDims-1) || + (static_cast(Layout) == static_cast(RowMajor) && m_dim.actualDim() == 0)) { + // m_stride is aways greater than index, so let's avoid the integer division. + eigen_assert(m_stride > index); + inputIndex = index + m_inputOffset; + } else { + const Index idx = index / m_stride; + inputIndex = idx * m_inputStride + m_inputOffset; + index -= idx * m_stride; + inputIndex += index; + } + return inputIndex; + } + + Dimensions m_dimensions; + Index m_stride; + Index m_inputOffset; + Index m_inputStride; + TensorEvaluator m_impl; + const internal::DimensionId m_dim; + const Device& m_device; +}; + + +// Eval as lvalue +template +struct TensorEvaluator, Device> + : public TensorEvaluator, Device> +{ + typedef TensorEvaluator, Device> Base; + typedef TensorChippingOp XprType; + static const int NumInputDims = internal::array_size::Dimensions>::value; + static const int NumDims = NumInputDims-1; + typedef typename XprType::Index Index; + typedef DSizes Dimensions; + typedef typename XprType::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + typedef typename PacketType::type PacketReturnType; + static const int PacketSize = internal::unpacket_traits::size; + + enum { + IsAligned = false, + PacketAccess = TensorEvaluator::PacketAccess, + RawAccess = false + }; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorEvaluator(const XprType& op, const Device& device) + : Base(op, device) + { } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType& coeffRef(Index index) + { + return this->m_impl.coeffRef(this->srcCoeff(index)); + } + + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + void writePacket(Index index, const PacketReturnType& x) + { + EIGEN_STATIC_ASSERT((PacketSize > 1), YOU_MADE_A_PROGRAMMING_MISTAKE) + + if ((static_cast(this->Layout) == static_cast(ColMajor) && this->m_dim.actualDim() == 0) || + (static_cast(this->Layout) == static_cast(RowMajor) && this->m_dim.actualDim() == NumInputDims-1)) { + // m_stride is equal to 1, so let's avoid the integer division. + eigen_assert(this->m_stride == 1); + EIGEN_ALIGN_MAX typename internal::remove_const::type values[PacketSize]; + internal::pstore(values, x); + Index inputIndex = index * this->m_inputStride + this->m_inputOffset; + for (int i = 0; i < PacketSize; ++i) { + this->m_impl.coeffRef(inputIndex) = values[i]; + inputIndex += this->m_inputStride; + } + } else if ((static_cast(this->Layout) == static_cast(ColMajor) && this->m_dim.actualDim() == NumInputDims-1) || + (static_cast(this->Layout) == static_cast(RowMajor) && this->m_dim.actualDim() == 0)) { + // m_stride is aways greater than index, so let's avoid the integer division. + eigen_assert(this->m_stride > index); + this->m_impl.template writePacket(index + this->m_inputOffset, x); + } else { + const Index idx = index / this->m_stride; + const Index rem = index - idx * this->m_stride; + if (rem + PacketSize <= this->m_stride) { + const Index inputIndex = idx * this->m_inputStride + this->m_inputOffset + rem; + this->m_impl.template writePacket(inputIndex, x); + } else { + // Cross stride boundary. Fallback to slow path. + EIGEN_ALIGN_MAX typename internal::remove_const::type values[PacketSize]; + internal::pstore(values, x); + for (int i = 0; i < PacketSize; ++i) { + this->coeffRef(index) = values[i]; + ++index; + } + } + } + } +}; + + +} // end namespace Eigen + +#endif // EIGEN_CXX11_TENSOR_TENSOR_CHIPPING_H diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorConcatenation.h b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorConcatenation.h new file mode 100644 index 0000000000..59bf90d939 --- /dev/null +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorConcatenation.h @@ -0,0 +1,361 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Benoit Steiner +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CXX11_TENSOR_TENSOR_CONCATENATION_H +#define EIGEN_CXX11_TENSOR_TENSOR_CONCATENATION_H + +namespace Eigen { + +/** \class TensorConcatenationOp + * \ingroup CXX11_Tensor_Module + * + * \brief Tensor concatenation class. + * + * + */ +namespace internal { +template +struct traits > +{ + // Type promotion to handle the case where the types of the lhs and the rhs are different. + typedef typename promote_storage_type::ret Scalar; + typedef typename promote_storage_type::StorageKind, + typename traits::StorageKind>::ret StorageKind; + typedef typename promote_index_type::Index, + typename traits::Index>::type Index; + typedef typename LhsXprType::Nested LhsNested; + typedef typename RhsXprType::Nested RhsNested; + typedef typename remove_reference::type _LhsNested; + typedef typename remove_reference::type _RhsNested; + static const int NumDimensions = traits::NumDimensions; + static const int Layout = traits::Layout; + enum { Flags = 0 }; +}; + +template +struct eval, Eigen::Dense> +{ + typedef const TensorConcatenationOp& type; +}; + +template +struct nested, 1, typename eval >::type> +{ + typedef TensorConcatenationOp type; +}; + +} // end namespace internal + + +template +class TensorConcatenationOp : public TensorBase, WriteAccessors> +{ + public: + typedef typename internal::traits::Scalar Scalar; + typedef typename internal::traits::StorageKind StorageKind; + typedef typename internal::traits::Index Index; + typedef typename internal::nested::type Nested; + typedef typename internal::promote_storage_type::ret CoeffReturnType; + typedef typename NumTraits::Real RealScalar; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorConcatenationOp(const LhsXprType& lhs, const RhsXprType& rhs, Axis axis) + : m_lhs_xpr(lhs), m_rhs_xpr(rhs), m_axis(axis) {} + + EIGEN_DEVICE_FUNC + const typename internal::remove_all::type& + lhsExpression() const { return m_lhs_xpr; } + + EIGEN_DEVICE_FUNC + const typename internal::remove_all::type& + rhsExpression() const { return m_rhs_xpr; } + + EIGEN_DEVICE_FUNC const Axis& axis() const { return m_axis; } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE TensorConcatenationOp& operator = (const TensorConcatenationOp& other) + { + typedef TensorAssignOp Assign; + Assign assign(*this, other); + internal::TensorExecutor::run(assign, DefaultDevice()); + return *this; + } + + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE TensorConcatenationOp& operator = (const OtherDerived& other) + { + typedef TensorAssignOp Assign; + Assign assign(*this, other); + internal::TensorExecutor::run(assign, DefaultDevice()); + return *this; + } + + protected: + typename LhsXprType::Nested m_lhs_xpr; + typename RhsXprType::Nested m_rhs_xpr; + const Axis m_axis; +}; + + +// Eval as rvalue +template +struct TensorEvaluator, Device> +{ + typedef TensorConcatenationOp XprType; + typedef typename XprType::Index Index; + static const int NumDims = internal::array_size::Dimensions>::value; + static const int RightNumDims = internal::array_size::Dimensions>::value; + typedef DSizes Dimensions; + typedef typename XprType::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + typedef typename PacketType::type PacketReturnType; + enum { + IsAligned = false, + PacketAccess = TensorEvaluator::PacketAccess & TensorEvaluator::PacketAccess, + Layout = TensorEvaluator::Layout, + RawAccess = false + }; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorEvaluator(const XprType& op, const Device& device) + : m_leftImpl(op.lhsExpression(), device), m_rightImpl(op.rhsExpression(), device), m_axis(op.axis()) + { + EIGEN_STATIC_ASSERT((static_cast(TensorEvaluator::Layout) == static_cast(TensorEvaluator::Layout) || NumDims == 1), YOU_MADE_A_PROGRAMMING_MISTAKE); + EIGEN_STATIC_ASSERT((NumDims == RightNumDims), YOU_MADE_A_PROGRAMMING_MISTAKE); + EIGEN_STATIC_ASSERT((NumDims > 0), YOU_MADE_A_PROGRAMMING_MISTAKE); + + eigen_assert(0 <= m_axis && m_axis < NumDims); + const Dimensions& lhs_dims = m_leftImpl.dimensions(); + const Dimensions& rhs_dims = m_rightImpl.dimensions(); + { + int i = 0; + for (; i < m_axis; ++i) { + eigen_assert(lhs_dims[i] > 0); + eigen_assert(lhs_dims[i] == rhs_dims[i]); + m_dimensions[i] = lhs_dims[i]; + } + eigen_assert(lhs_dims[i] > 0); // Now i == m_axis. + eigen_assert(rhs_dims[i] > 0); + m_dimensions[i] = lhs_dims[i] + rhs_dims[i]; + for (++i; i < NumDims; ++i) { + eigen_assert(lhs_dims[i] > 0); + eigen_assert(lhs_dims[i] == rhs_dims[i]); + m_dimensions[i] = lhs_dims[i]; + } + } + + if (static_cast(Layout) == static_cast(ColMajor)) { + m_leftStrides[0] = 1; + m_rightStrides[0] = 1; + m_outputStrides[0] = 1; + + for (int j = 1; j < NumDims; ++j) { + m_leftStrides[j] = m_leftStrides[j-1] * lhs_dims[j-1]; + m_rightStrides[j] = m_rightStrides[j-1] * rhs_dims[j-1]; + m_outputStrides[j] = m_outputStrides[j-1] * m_dimensions[j-1]; + } + } else { + m_leftStrides[NumDims - 1] = 1; + m_rightStrides[NumDims - 1] = 1; + m_outputStrides[NumDims - 1] = 1; + + for (int j = NumDims - 2; j >= 0; --j) { + m_leftStrides[j] = m_leftStrides[j+1] * lhs_dims[j+1]; + m_rightStrides[j] = m_rightStrides[j+1] * rhs_dims[j+1]; + m_outputStrides[j] = m_outputStrides[j+1] * m_dimensions[j+1]; + } + } + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Dimensions& dimensions() const { return m_dimensions; } + + // TODO(phli): Add short-circuit memcpy evaluation if underlying data are linear? + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(Scalar* /*data*/) + { + m_leftImpl.evalSubExprsIfNeeded(NULL); + m_rightImpl.evalSubExprsIfNeeded(NULL); + return true; + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void cleanup() + { + m_leftImpl.cleanup(); + m_rightImpl.cleanup(); + } + + // TODO(phli): attempt to speed this up. The integer divisions and modulo are slow. + // See CL/76180724 comments for more ideas. + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const + { + // Collect dimension-wise indices (subs). + array subs; + if (static_cast(Layout) == static_cast(ColMajor)) { + for (int i = NumDims - 1; i > 0; --i) { + subs[i] = index / m_outputStrides[i]; + index -= subs[i] * m_outputStrides[i]; + } + subs[0] = index; + } else { + for (int i = 0; i < NumDims - 1; ++i) { + subs[i] = index / m_outputStrides[i]; + index -= subs[i] * m_outputStrides[i]; + } + subs[NumDims - 1] = index; + } + + const Dimensions& left_dims = m_leftImpl.dimensions(); + if (subs[m_axis] < left_dims[m_axis]) { + Index left_index; + if (static_cast(Layout) == static_cast(ColMajor)) { + left_index = subs[0]; + for (int i = 1; i < NumDims; ++i) { + left_index += (subs[i] % left_dims[i]) * m_leftStrides[i]; + } + } else { + left_index = subs[NumDims - 1]; + for (int i = NumDims - 2; i >= 0; --i) { + left_index += (subs[i] % left_dims[i]) * m_leftStrides[i]; + } + } + return m_leftImpl.coeff(left_index); + } else { + subs[m_axis] -= left_dims[m_axis]; + const Dimensions& right_dims = m_rightImpl.dimensions(); + Index right_index; + if (static_cast(Layout) == static_cast(ColMajor)) { + right_index = subs[0]; + for (int i = 1; i < NumDims; ++i) { + right_index += (subs[i] % right_dims[i]) * m_rightStrides[i]; + } + } else { + right_index = subs[NumDims - 1]; + for (int i = NumDims - 2; i >= 0; --i) { + right_index += (subs[i] % right_dims[i]) * m_rightStrides[i]; + } + } + return m_rightImpl.coeff(right_index); + } + } + + // TODO(phli): Add a real vectorization. + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packet(Index index) const + { + const int packetSize = internal::unpacket_traits::size; + EIGEN_STATIC_ASSERT((packetSize > 1), YOU_MADE_A_PROGRAMMING_MISTAKE) + eigen_assert(index + packetSize - 1 < dimensions().TotalSize()); + + EIGEN_ALIGN_MAX CoeffReturnType values[packetSize]; + for (int i = 0; i < packetSize; ++i) { + values[i] = coeff(index+i); + } + PacketReturnType rslt = internal::pload(values); + return rslt; + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost + costPerCoeff(bool vectorized) const { + const double compute_cost = NumDims * (2 * TensorOpCost::AddCost() + + 2 * TensorOpCost::MulCost() + + TensorOpCost::DivCost() + + TensorOpCost::ModCost()); + const double lhs_size = m_leftImpl.dimensions().TotalSize(); + const double rhs_size = m_rightImpl.dimensions().TotalSize(); + return (lhs_size / (lhs_size + rhs_size)) * + m_leftImpl.costPerCoeff(vectorized) + + (rhs_size / (lhs_size + rhs_size)) * + m_rightImpl.costPerCoeff(vectorized) + + TensorOpCost(0, 0, compute_cost); + } + + EIGEN_DEVICE_FUNC Scalar* data() const { return NULL; } + + protected: + Dimensions m_dimensions; + array m_outputStrides; + array m_leftStrides; + array m_rightStrides; + TensorEvaluator m_leftImpl; + TensorEvaluator m_rightImpl; + const Axis m_axis; +}; + +// Eval as lvalue +template + struct TensorEvaluator, Device> + : public TensorEvaluator, Device> +{ + typedef TensorEvaluator, Device> Base; + typedef TensorConcatenationOp XprType; + typedef typename Base::Dimensions Dimensions; + enum { + IsAligned = false, + PacketAccess = TensorEvaluator::PacketAccess & TensorEvaluator::PacketAccess, + Layout = TensorEvaluator::Layout, + RawAccess = false + }; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorEvaluator(XprType& op, const Device& device) + : Base(op, device) + { + EIGEN_STATIC_ASSERT((static_cast(Layout) == static_cast(ColMajor)), YOU_MADE_A_PROGRAMMING_MISTAKE); + } + + typedef typename XprType::Index Index; + typedef typename XprType::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + typedef typename PacketType::type PacketReturnType; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType& coeffRef(Index index) + { + // Collect dimension-wise indices (subs). + array subs; + for (int i = Base::NumDims - 1; i > 0; --i) { + subs[i] = index / this->m_outputStrides[i]; + index -= subs[i] * this->m_outputStrides[i]; + } + subs[0] = index; + + const Dimensions& left_dims = this->m_leftImpl.dimensions(); + if (subs[this->m_axis] < left_dims[this->m_axis]) { + Index left_index = subs[0]; + for (int i = 1; i < Base::NumDims; ++i) { + left_index += (subs[i] % left_dims[i]) * this->m_leftStrides[i]; + } + return this->m_leftImpl.coeffRef(left_index); + } else { + subs[this->m_axis] -= left_dims[this->m_axis]; + const Dimensions& right_dims = this->m_rightImpl.dimensions(); + Index right_index = subs[0]; + for (int i = 1; i < Base::NumDims; ++i) { + right_index += (subs[i] % right_dims[i]) * this->m_rightStrides[i]; + } + return this->m_rightImpl.coeffRef(right_index); + } + } + + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + void writePacket(Index index, const PacketReturnType& x) + { + const int packetSize = internal::unpacket_traits::size; + EIGEN_STATIC_ASSERT((packetSize > 1), YOU_MADE_A_PROGRAMMING_MISTAKE) + eigen_assert(index + packetSize - 1 < this->dimensions().TotalSize()); + + EIGEN_ALIGN_MAX CoeffReturnType values[packetSize]; + internal::pstore(values, x); + for (int i = 0; i < packetSize; ++i) { + coeffRef(index+i) = values[i]; + } + } +}; + +} // end namespace Eigen + +#endif // EIGEN_CXX11_TENSOR_TENSOR_CONCATENATION_H diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorContraction.h b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorContraction.h new file mode 100644 index 0000000000..20b29e5fde --- /dev/null +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorContraction.h @@ -0,0 +1,628 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Benoit Steiner +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CXX11_TENSOR_TENSOR_CONTRACTION_H +#define EIGEN_CXX11_TENSOR_TENSOR_CONTRACTION_H + +namespace Eigen { + +/** \class TensorContraction + * \ingroup CXX11_Tensor_Module + * + * \brief Tensor contraction class. + * + * + */ +namespace internal { + +template +struct traits > +{ + // Type promotion to handle the case where the types of the lhs and the rhs are different. + typedef typename gebp_traits::type, + typename remove_const::type>::ResScalar Scalar; + + typedef typename promote_storage_type::StorageKind, + typename traits::StorageKind>::ret StorageKind; + typedef typename promote_index_type::Index, + typename traits::Index>::type Index; + typedef typename LhsXprType::Nested LhsNested; + typedef typename RhsXprType::Nested RhsNested; + typedef typename remove_reference::type _LhsNested; + typedef typename remove_reference::type _RhsNested; + + // From NumDims below. + static const int NumDimensions = traits::NumDimensions + traits::NumDimensions - 2 * array_size::value; + static const int Layout = traits::Layout; + + enum { + Flags = 0 + }; +}; + +template +struct eval, Eigen::Dense> +{ + typedef const TensorContractionOp& type; +}; + +template +struct nested, 1, typename eval >::type> +{ + typedef TensorContractionOp type; +}; + +template +struct traits, Device_> > { + typedef Indices_ Indices; + typedef LeftArgType_ LeftArgType; + typedef RightArgType_ RightArgType; + typedef Device_ Device; + + // From NumDims below. + static const int NumDimensions = traits::NumDimensions + traits::NumDimensions - 2 * array_size::value; +}; + +} // end namespace internal + +template +class TensorContractionOp : public TensorBase, ReadOnlyAccessors> +{ + public: + typedef typename Eigen::internal::traits::Scalar Scalar; + typedef typename internal::gebp_traits::ResScalar CoeffReturnType; + typedef typename Eigen::internal::nested::type Nested; + typedef typename Eigen::internal::traits::StorageKind StorageKind; + typedef typename Eigen::internal::traits::Index Index; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorContractionOp( + const LhsXprType& lhs, const RhsXprType& rhs, const Indices& dims) + : m_lhs_xpr(lhs), m_rhs_xpr(rhs), m_indices(dims) {} + + EIGEN_DEVICE_FUNC + const Indices& indices() const { return m_indices; } + + /** \returns the nested expressions */ + EIGEN_DEVICE_FUNC + const typename internal::remove_all::type& + lhsExpression() const { return m_lhs_xpr; } + + EIGEN_DEVICE_FUNC + const typename internal::remove_all::type& + rhsExpression() const { return m_rhs_xpr; } + + protected: + typename LhsXprType::Nested m_lhs_xpr; + typename RhsXprType::Nested m_rhs_xpr; + const Indices m_indices; +}; + + +template +struct TensorContractionEvaluatorBase +{ + typedef typename internal::traits::Indices Indices; + typedef typename internal::traits::LeftArgType LeftArgType; + typedef typename internal::traits::RightArgType RightArgType; + typedef typename internal::traits::Device Device; + + typedef TensorContractionOp XprType; + typedef typename internal::remove_const::type Scalar; + typedef typename XprType::Index Index; + typedef typename XprType::CoeffReturnType CoeffReturnType; + typedef typename PacketType::type PacketReturnType; + + enum { + IsAligned = true, + PacketAccess = (internal::unpacket_traits::size > 1), + Layout = TensorEvaluator::Layout, + CoordAccess = false, // to be implemented + RawAccess = true + }; + + // Most of the code is assuming that both input tensors are ColMajor. If the + // inputs are RowMajor, we will "cheat" by swapping the LHS and RHS: + // If we want to compute A * B = C, where A is LHS and B is RHS, the code + // will pretend B is LHS and A is RHS. + typedef typename internal::conditional< + static_cast(Layout) == static_cast(ColMajor), LeftArgType, RightArgType>::type EvalLeftArgType; + typedef typename internal::conditional< + static_cast(Layout) == static_cast(ColMajor), RightArgType, LeftArgType>::type EvalRightArgType; + + static const int LDims = + internal::array_size::Dimensions>::value; + static const int RDims = + internal::array_size::Dimensions>::value; + static const int ContractDims = internal::array_size::value; + static const int NumDims = LDims + RDims - 2 * ContractDims; + + typedef array contract_t; + typedef array left_nocontract_t; + typedef array right_nocontract_t; + + typedef DSizes Dimensions; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + TensorContractionEvaluatorBase(const XprType& op, const Device& device) + : m_leftImpl(choose(Cond(Layout) == static_cast(ColMajor)>(), + op.lhsExpression(), op.rhsExpression()), device), + m_rightImpl(choose(Cond(Layout) == static_cast(ColMajor)>(), + op.rhsExpression(), op.lhsExpression()), device), + m_device(device), + m_result(NULL) { + EIGEN_STATIC_ASSERT((static_cast(TensorEvaluator::Layout) == + static_cast(TensorEvaluator::Layout)), + YOU_MADE_A_PROGRAMMING_MISTAKE); + + + DSizes eval_left_dims; + DSizes eval_right_dims; + array, ContractDims> eval_op_indices; + if (static_cast(Layout) == static_cast(ColMajor)) { + // For ColMajor, we keep using the existing dimensions + for (int i = 0; i < LDims; i++) { + eval_left_dims[i] = m_leftImpl.dimensions()[i]; + } + for (int i = 0; i < RDims; i++) { + eval_right_dims[i] = m_rightImpl.dimensions()[i]; + } + // We keep the pairs of contracting indices. + for (int i = 0; i < ContractDims; i++) { + eval_op_indices[i].first = op.indices()[i].first; + eval_op_indices[i].second = op.indices()[i].second; + } + } else { + // For RowMajor, we need to reverse the existing dimensions + for (int i = 0; i < LDims; i++) { + eval_left_dims[i] = m_leftImpl.dimensions()[LDims - i - 1]; + } + for (int i = 0; i < RDims; i++) { + eval_right_dims[i] = m_rightImpl.dimensions()[RDims - i - 1]; + } + // We need to flip all the pairs of contracting indices as well as + // reversing the dimensions. + for (int i = 0; i < ContractDims; i++) { + eval_op_indices[i].first = LDims - 1 - op.indices()[ContractDims - 1 - i].second; + eval_op_indices[i].second = RDims - 1 - op.indices()[ContractDims - 1 - i].first; + } + } + + // Check for duplicate axes and make sure the first index in eval_op_indices + // is increasing. Using O(n^2) sorting is OK since ContractDims is small + for (int i = 0; i < ContractDims; i++) { + for (int j = i + 1; j < ContractDims; j++) { + eigen_assert(eval_op_indices[j].first != eval_op_indices[i].first && + eval_op_indices[j].second != eval_op_indices[i].second && + "contraction axes should be unique"); + if (eval_op_indices[j].first < eval_op_indices[i].first) { + numext::swap(eval_op_indices[j], eval_op_indices[i]); + } + } + } + + array lhs_strides; + lhs_strides[0] = 1; + for (int i = 0; i < LDims-1; ++i) { + lhs_strides[i+1] = lhs_strides[i] * eval_left_dims[i]; + } + + array rhs_strides; + rhs_strides[0] = 1; + for (int i = 0; i < RDims-1; ++i) { + rhs_strides[i+1] = rhs_strides[i] * eval_right_dims[i]; + } + + if (m_i_strides.size() > 0) m_i_strides[0] = 1; + if (m_j_strides.size() > 0) m_j_strides[0] = 1; + if (m_k_strides.size() > 0) m_k_strides[0] = 1; + + m_i_size = 1; + m_j_size = 1; + m_k_size = 1; + + // To compute the dimension, we simply concatenate the non-contracting + // dimensions of the left and then the right tensor. Additionally, we also + // compute the strides corresponding to the left non-contracting + // dimensions and right non-contracting dimensions. + m_lhs_inner_dim_contiguous = true; + int dim_idx = 0; + unsigned int nocontract_idx = 0; + + for (int i = 0; i < LDims; i++) { + // find if we are contracting on index i of left tensor + bool contracting = false; + for (int j = 0; j < ContractDims; j++) { + if (eval_op_indices[j].first == i) { + contracting = true; + break; + } + } + if (!contracting) { + // add dimension size to output dimensions + m_dimensions[dim_idx] = eval_left_dims[i]; + m_left_nocontract_strides[nocontract_idx] = lhs_strides[i]; + if (dim_idx != i) { + m_lhs_inner_dim_contiguous = false; + } + if (nocontract_idx+1 < internal::array_size::value) { + m_i_strides[nocontract_idx+1] = + m_i_strides[nocontract_idx] * eval_left_dims[i]; + } else { + m_i_size = m_i_strides[nocontract_idx] * eval_left_dims[i]; + } + dim_idx++; + nocontract_idx++; + } + } + + nocontract_idx = 0; + for (int i = 0; i < RDims; i++) { + bool contracting = false; + // find if we are contracting on index i of right tensor + for (int j = 0; j < ContractDims; j++) { + if (eval_op_indices[j].second == i) { + contracting = true; + break; + } + } + if (!contracting) { + m_dimensions[dim_idx] = eval_right_dims[i]; + if (nocontract_idx+1 < internal::array_size::value) { + m_j_strides[nocontract_idx+1] = + m_j_strides[nocontract_idx] * eval_right_dims[i]; + } else { + m_j_size = m_j_strides[nocontract_idx] * eval_right_dims[i]; + } + m_right_nocontract_strides[nocontract_idx] = rhs_strides[i]; + dim_idx++; + nocontract_idx++; + } + } + + // Now compute the strides corresponding to the contracting dimensions. We + // assumed above that non-contracting axes are represented in the same order + // in the matrix as they are in the tensor. This is not the case for + // contracting axes. As the contracting axes must be of the same size in + // each tensor, we'll only look at the first tensor here. + m_rhs_inner_dim_contiguous = true; + m_rhs_inner_dim_reordered = false; + for (int i = 0; i < ContractDims; i++) { + Index left = eval_op_indices[i].first; + Index right = eval_op_indices[i].second; + + Index size = eval_left_dims[left]; + eigen_assert(size == eval_right_dims[right] && + "Contraction axes must be same size"); + + if (i+1 < static_cast(internal::array_size::value)) { + m_k_strides[i+1] = m_k_strides[i] * size; + } else { + m_k_size = m_k_strides[i] * size; + } + m_left_contracting_strides[i] = lhs_strides[left]; + m_right_contracting_strides[i] = rhs_strides[right]; + + if (i > 0 && right < eval_op_indices[i-1].second) { + m_rhs_inner_dim_reordered = true; + } + if (right != i) { + m_rhs_inner_dim_contiguous = false; + } + } + + // If the layout is RowMajor, we need to reverse the m_dimensions + if (static_cast(Layout) == static_cast(RowMajor)) { + for (int i = 0, j = NumDims - 1; i < j; i++, j--) { + numext::swap(m_dimensions[i], m_dimensions[j]); + } + } + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Dimensions& dimensions() const { return m_dimensions; } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(Scalar* data) { + m_leftImpl.evalSubExprsIfNeeded(NULL); + m_rightImpl.evalSubExprsIfNeeded(NULL); + if (data) { + evalTo(data); + return false; + } else { + m_result = static_cast(m_device.allocate(dimensions().TotalSize() * sizeof(Scalar))); + evalTo(m_result); + return true; + } + } + + EIGEN_DEVICE_FUNC void evalTo(Scalar* buffer) const { + if (this->m_lhs_inner_dim_contiguous) { + if (this->m_rhs_inner_dim_contiguous) { + if (this->m_rhs_inner_dim_reordered) { + static_cast(this)->template evalProduct(buffer); + } + else { + static_cast(this)->template evalProduct(buffer); + } + } + else { + if (this->m_rhs_inner_dim_reordered) { + static_cast(this)->template evalProduct(buffer); + } + else { + static_cast(this)->template evalProduct(buffer); + } + } + } + else { + if (this->m_rhs_inner_dim_contiguous) { + if (this->m_rhs_inner_dim_reordered) { + static_cast(this)->template evalProduct(buffer); + } + else { + static_cast(this)->template evalProduct(buffer); + } + } + else { + if (this->m_rhs_inner_dim_reordered) { + static_cast(this)->template evalProduct(buffer); + } + else { + static_cast(this)->template evalProduct(buffer); + } + } + } + } + + template + EIGEN_DEVICE_FUNC void evalGemv(Scalar* buffer) const { + const Index rows = m_i_size; + const Index cols = m_k_size; + + typedef typename internal::remove_const::type LhsScalar; + typedef typename internal::remove_const::type RhsScalar; + typedef TensorEvaluator LeftEvaluator; + typedef TensorEvaluator RightEvaluator; + const Index lhs_packet_size = internal::unpacket_traits::size; + const Index rhs_packet_size = internal::unpacket_traits::size; + const int lhs_alignment = LeftEvaluator::IsAligned ? Aligned : Unaligned; + const int rhs_alignment = RightEvaluator::IsAligned ? Aligned : Unaligned; + typedef internal::TensorContractionInputMapper LhsMapper; + + typedef internal::TensorContractionInputMapper RhsMapper; + + LhsMapper lhs(m_leftImpl, m_left_nocontract_strides, m_i_strides, + m_left_contracting_strides, m_k_strides); + RhsMapper rhs(m_rightImpl, m_right_nocontract_strides, m_j_strides, + m_right_contracting_strides, m_k_strides); + + const Scalar alpha(1); + const Index resIncr(1); + + // zero out the result buffer (which must be of size at least rows * sizeof(Scalar) + m_device.memset(buffer, 0, rows * sizeof(Scalar)); + + internal::general_matrix_vector_product::run( + rows, cols, lhs, rhs, + buffer, resIncr, alpha); + } + + template + EIGEN_DEVICE_FUNC void evalGemm(Scalar* buffer) const { + // columns in left side, rows in right side + const Index k = this->m_k_size; + + // rows in left side + const Index m = this->m_i_size; + + // columns in right side + const Index n = this->m_j_size; + + // zero out the result buffer (which must be of size at least m * n * sizeof(Scalar) + this->m_device.memset(buffer, 0, m * n * sizeof(Scalar)); + + // define mr, nr, and all of my data mapper types + typedef typename internal::remove_const::type LhsScalar; + typedef typename internal::remove_const::type RhsScalar; + typedef typename internal::gebp_traits Traits; + + const Index nr = Traits::nr; + const Index mr = Traits::mr; + + typedef TensorEvaluator LeftEvaluator; + typedef TensorEvaluator RightEvaluator; + + const Index lhs_packet_size = internal::unpacket_traits::size; + const Index rhs_packet_size = internal::unpacket_traits::size; + + typedef internal::TensorContractionInputMapper LhsMapper; + + typedef internal::TensorContractionInputMapper RhsMapper; + + typedef internal::blas_data_mapper OutputMapper; + + // Declare GEBP packing and kernel structs + internal::gemm_pack_lhs pack_lhs; + internal::gemm_pack_rhs pack_rhs; + + internal::gebp_kernel gebp; + + // initialize data mappers + LhsMapper lhs(this->m_leftImpl, this->m_left_nocontract_strides, this->m_i_strides, + this->m_left_contracting_strides, this->m_k_strides); + + RhsMapper rhs(this->m_rightImpl, this->m_right_nocontract_strides, this->m_j_strides, + this->m_right_contracting_strides, this->m_k_strides); + + OutputMapper output(buffer, m); + + // Sizes of the blocks to load in cache. See the Goto paper for details. + internal::TensorContractionBlocking blocking(k, m, n, 1); + const Index kc = blocking.kc(); + const Index mc = numext::mini(m, blocking.mc()); + const Index nc = numext::mini(n, blocking.nc()); + const Index sizeA = mc * kc; + const Index sizeB = kc * nc; + + LhsScalar* blockA = static_cast(this->m_device.allocate(sizeA * sizeof(LhsScalar))); + RhsScalar* blockB = static_cast(this->m_device.allocate(sizeB * sizeof(RhsScalar))); + + for(Index i2=0; i2m_device.deallocate(blockA); + this->m_device.deallocate(blockB); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void cleanup() { + m_leftImpl.cleanup(); + m_rightImpl.cleanup(); + + if (m_result != NULL) { + m_device.deallocate(m_result); + m_result = NULL; + } + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const { + return m_result[index]; + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost costPerCoeff(bool) const { + return TensorOpCost(sizeof(CoeffReturnType), 0, 0); + } + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packet(Index index) const { + return internal::ploadt(m_result + index); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar* data() const { return m_result; } + + protected: + // Prevent assignment + TensorContractionEvaluatorBase& operator = (const TensorContractionEvaluatorBase&); + Dimensions m_dimensions; + + contract_t m_k_strides; + contract_t m_left_contracting_strides; + contract_t m_right_contracting_strides; + + bool m_lhs_inner_dim_contiguous; + bool m_rhs_inner_dim_contiguous; + bool m_rhs_inner_dim_reordered; + + left_nocontract_t m_i_strides; + right_nocontract_t m_j_strides; + left_nocontract_t m_left_nocontract_strides; + right_nocontract_t m_right_nocontract_strides; + + Index m_i_size; + Index m_j_size; + Index m_k_size; + + TensorEvaluator m_leftImpl; + TensorEvaluator m_rightImpl; + const Device& m_device; + Scalar* m_result; +}; + + +// evaluator for default device +template +struct TensorEvaluator, Device> : + public TensorContractionEvaluatorBase< + TensorEvaluator, Device> > { + typedef TensorEvaluator, Device> Self; + typedef TensorContractionEvaluatorBase Base; + + typedef TensorContractionOp XprType; + typedef typename internal::remove_const::type Scalar; + typedef typename XprType::Index Index; + typedef typename XprType::CoeffReturnType CoeffReturnType; + typedef typename PacketType::type PacketReturnType; + + enum { + Layout = TensorEvaluator::Layout + }; + + // Most of the code is assuming that both input tensors are ColMajor. If the + // inputs are RowMajor, we will "cheat" by swapping the LHS and RHS: + // If we want to compute A * B = C, where A is LHS and B is RHS, the code + // will pretend B is LHS and A is RHS. + typedef typename internal::conditional< + static_cast(Layout) == static_cast(ColMajor), LeftArgType, RightArgType>::type EvalLeftArgType; + typedef typename internal::conditional< + static_cast(Layout) == static_cast(ColMajor), RightArgType, LeftArgType>::type EvalRightArgType; + + static const int LDims = + internal::array_size::Dimensions>::value; + static const int RDims = + internal::array_size::Dimensions>::value; + static const int ContractDims = internal::array_size::value; + + typedef array contract_t; + typedef array left_nocontract_t; + typedef array right_nocontract_t; + + static const int NumDims = LDims + RDims - 2 * ContractDims; + + // Could we use NumDimensions here? + typedef DSizes Dimensions; + + EIGEN_DEVICE_FUNC TensorEvaluator(const XprType& op, const Device& device) : + Base(op, device) { } + + template + EIGEN_DEVICE_FUNC void evalProduct(Scalar* buffer) const { + if (this->m_j_size == 1) { + this->template evalGemv(buffer); + return; + } + + this->template evalGemm(buffer); + } +}; + +} // end namespace Eigen + +#endif // EIGEN_CXX11_TENSOR_TENSOR_CONTRACTION_H diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorContractionBlocking.h b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorContractionBlocking.h new file mode 100644 index 0000000000..5cf7b4f718 --- /dev/null +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorContractionBlocking.h @@ -0,0 +1,56 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Benoit Steiner +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CXX11_TENSOR_TENSOR_CONTRACTION_BLOCKING_H +#define EIGEN_CXX11_TENSOR_TENSOR_CONTRACTION_BLOCKING_H + + +namespace Eigen { +namespace internal { + +enum { + ShardByRow = 0, + ShardByCol = 1 +}; + + +// Default Blocking Strategy +template +class TensorContractionBlocking { + public: + + typedef typename LhsMapper::Scalar LhsScalar; + typedef typename RhsMapper::Scalar RhsScalar; + + EIGEN_DEVICE_FUNC TensorContractionBlocking(Index k, Index m, Index n, Index num_threads = 1) : + kc_(k), mc_(m), nc_(n) + { + if (ShardingType == ShardByCol) { + computeProductBlockingSizes(kc_, mc_, nc_, num_threads); + } + else { + computeProductBlockingSizes(kc_, nc_, mc_, num_threads); + } + } + + EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE Index kc() const { return kc_; } + EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE Index mc() const { return mc_; } + EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE Index nc() const { return nc_; } + + private: + Index kc_; + Index mc_; + Index nc_; +}; + + +} // end namespace internal +} // end namespace Eigen + +#endif // EIGEN_CXX11_TENSOR_TENSOR_CONTRACTION_BLOCKING_H diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorContractionCuda.h b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorContractionCuda.h new file mode 100644 index 0000000000..d65dbb40f1 --- /dev/null +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorContractionCuda.h @@ -0,0 +1,1391 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014-2015 Benoit Steiner +// Copyright (C) 2015 Navdeep Jaitly +// Copyright (C) 2014 Eric Martin +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CXX11_TENSOR_TENSOR_CONTRACTION_CUDA_H +#define EIGEN_CXX11_TENSOR_TENSOR_CONTRACTION_CUDA_H + +#if defined(EIGEN_USE_GPU) && defined(__CUDACC__) + +namespace Eigen { + +template +__device__ EIGEN_STRONG_INLINE void +EigenContractionKernelInternal(const LhsMapper lhs, const RhsMapper rhs, + const OutputMapper output, Scalar* lhs_shmem, Scalar* rhs_shmem, + const Index m_size, const Index n_size, const Index k_size) { + + const Index m_block_idx = blockIdx.x; + const Index n_block_idx = blockIdx.y; + + const Index base_m = 64 * m_block_idx; + const Index base_n = 64 * n_block_idx; + + // declare and initialize 64 registers for output 8x8 block + + // prefetch registers + Scalar lhs_pf0; + Scalar lhs_pf1; + Scalar lhs_pf2; + Scalar lhs_pf3; + Scalar lhs_pf4; + Scalar lhs_pf5; + Scalar lhs_pf6; + Scalar lhs_pf7; + + Scalar rhs_pf0; + Scalar rhs_pf1; + Scalar rhs_pf2; + Scalar rhs_pf3; + Scalar rhs_pf4; + Scalar rhs_pf5; + Scalar rhs_pf6; + Scalar rhs_pf7; + + // shared memory is formatted + // (contract idx in block, nocontract idx in block, block idx) + // where block idx is column major. This transposition limits the number of + // bank conflicts when reading the LHS. The core idea is that since the contracting + // index is shared by both sides, then the contracting index should be in threadIdx.x. + + // On the LHS, we pad each row inside of each block with an extra element. This makes + // each block 8 rows of 9 elements, which is 72 elements. This gives no bank conflicts + // on writes and very few 2-way conflicts on reads. There is an 8x8 grid of these blocks. + + // On the RHS we just add 8 padding elements to the end of each block. This gives no bank + // conflicts on writes and also none on reads. + + // storage indices + const Index lhs_store_idx_base = threadIdx.y * 72 + threadIdx.x * 9 + threadIdx.z; + const Index rhs_store_idx_base = threadIdx.y * 72 + threadIdx.z * 8 + threadIdx.x; + + const Index lhs_store_idx_0 = lhs_store_idx_base + 576 * 0; + const Index lhs_store_idx_1 = lhs_store_idx_base + 576 * 1; + const Index lhs_store_idx_2 = lhs_store_idx_base + 576 * 2; + const Index lhs_store_idx_3 = lhs_store_idx_base + 576 * 3; + const Index lhs_store_idx_4 = lhs_store_idx_base + 576 * 4; + const Index lhs_store_idx_5 = lhs_store_idx_base + 576 * 5; + const Index lhs_store_idx_6 = lhs_store_idx_base + 576 * 6; + const Index lhs_store_idx_7 = lhs_store_idx_base + 576 * 7; + + const Index rhs_store_idx_0 = rhs_store_idx_base + 576 * 0; + const Index rhs_store_idx_1 = rhs_store_idx_base + 576 * 1; + const Index rhs_store_idx_2 = rhs_store_idx_base + 576 * 2; + const Index rhs_store_idx_3 = rhs_store_idx_base + 576 * 3; + const Index rhs_store_idx_4 = rhs_store_idx_base + 576 * 4; + const Index rhs_store_idx_5 = rhs_store_idx_base + 576 * 5; + const Index rhs_store_idx_6 = rhs_store_idx_base + 576 * 6; + const Index rhs_store_idx_7 = rhs_store_idx_base + 576 * 7; + + // in the loading code, the following variables are important: + // threadIdx.x: the vertical position in an 8x8 block + // threadIdx.y: the vertical index of the 8x8 block in the grid + // threadIdx.z: the horizontal position in an 8x8 block + // k: the horizontal index of the 8x8 block in the grid + // + // The k parameter is implicit (it was the loop counter for a loop that went + // from 0 to <8, but now that loop is unrolled in the below code. + + const Index load_idx_vert = threadIdx.x + 8 * threadIdx.y; + const Index lhs_vert = base_m + load_idx_vert; + +#define prefetchIntoRegisters(base_k) \ + { \ + lhs_pf0 = conv(0); \ + lhs_pf1 = conv(0); \ + lhs_pf2 = conv(0); \ + lhs_pf3 = conv(0); \ + lhs_pf4 = conv(0); \ + lhs_pf5 = conv(0); \ + lhs_pf6 = conv(0); \ + lhs_pf7 = conv(0); \ + \ + rhs_pf0 = conv(0); \ + rhs_pf1 = conv(0); \ + rhs_pf2 = conv(0); \ + rhs_pf3 = conv(0); \ + rhs_pf4 = conv(0); \ + rhs_pf5 = conv(0); \ + rhs_pf6 = conv(0); \ + rhs_pf7 = conv(0); \ + \ + if (!needs_edge_check || lhs_vert < m_size) { \ + const Index lhs_horiz_0 = base_k + threadIdx.z + 0 * 8; \ + const Index lhs_horiz_1 = base_k + threadIdx.z + 1 * 8; \ + const Index lhs_horiz_2 = base_k + threadIdx.z + 2 * 8; \ + const Index lhs_horiz_3 = base_k + threadIdx.z + 3 * 8; \ + const Index lhs_horiz_4 = base_k + threadIdx.z + 4 * 8; \ + const Index lhs_horiz_5 = base_k + threadIdx.z + 5 * 8; \ + const Index lhs_horiz_6 = base_k + threadIdx.z + 6 * 8; \ + const Index lhs_horiz_7 = base_k + threadIdx.z + 7 * 8; \ + \ + if (!needs_edge_check || lhs_horiz_7 < k_size) { \ + lhs_pf0 = lhs(lhs_vert, lhs_horiz_0); \ + lhs_pf1 = lhs(lhs_vert, lhs_horiz_1); \ + lhs_pf2 = lhs(lhs_vert, lhs_horiz_2); \ + lhs_pf3 = lhs(lhs_vert, lhs_horiz_3); \ + lhs_pf4 = lhs(lhs_vert, lhs_horiz_4); \ + lhs_pf5 = lhs(lhs_vert, lhs_horiz_5); \ + lhs_pf6 = lhs(lhs_vert, lhs_horiz_6); \ + lhs_pf7 = lhs(lhs_vert, lhs_horiz_7); \ + } else if (lhs_horiz_6 < k_size) { \ + lhs_pf0 = lhs(lhs_vert, lhs_horiz_0); \ + lhs_pf1 = lhs(lhs_vert, lhs_horiz_1); \ + lhs_pf2 = lhs(lhs_vert, lhs_horiz_2); \ + lhs_pf3 = lhs(lhs_vert, lhs_horiz_3); \ + lhs_pf4 = lhs(lhs_vert, lhs_horiz_4); \ + lhs_pf5 = lhs(lhs_vert, lhs_horiz_5); \ + lhs_pf6 = lhs(lhs_vert, lhs_horiz_6); \ + } else if (lhs_horiz_5 < k_size) { \ + lhs_pf0 = lhs(lhs_vert, lhs_horiz_0); \ + lhs_pf1 = lhs(lhs_vert, lhs_horiz_1); \ + lhs_pf2 = lhs(lhs_vert, lhs_horiz_2); \ + lhs_pf3 = lhs(lhs_vert, lhs_horiz_3); \ + lhs_pf4 = lhs(lhs_vert, lhs_horiz_4); \ + lhs_pf5 = lhs(lhs_vert, lhs_horiz_5); \ + } else if (lhs_horiz_4 < k_size) { \ + lhs_pf0 = lhs(lhs_vert, lhs_horiz_0); \ + lhs_pf1 = lhs(lhs_vert, lhs_horiz_1); \ + lhs_pf2 = lhs(lhs_vert, lhs_horiz_2); \ + lhs_pf3 = lhs(lhs_vert, lhs_horiz_3); \ + lhs_pf4 = lhs(lhs_vert, lhs_horiz_4); \ + } else if (lhs_horiz_3 < k_size) { \ + lhs_pf0 = lhs(lhs_vert, lhs_horiz_0); \ + lhs_pf1 = lhs(lhs_vert, lhs_horiz_1); \ + lhs_pf2 = lhs(lhs_vert, lhs_horiz_2); \ + lhs_pf3 = lhs(lhs_vert, lhs_horiz_3); \ + } else if (lhs_horiz_2 < k_size) { \ + lhs_pf0 = lhs(lhs_vert, lhs_horiz_0); \ + lhs_pf1 = lhs(lhs_vert, lhs_horiz_1); \ + lhs_pf2 = lhs(lhs_vert, lhs_horiz_2); \ + } else if (lhs_horiz_1 < k_size) { \ + lhs_pf0 = lhs(lhs_vert, lhs_horiz_0); \ + lhs_pf1 = lhs(lhs_vert, lhs_horiz_1); \ + } else if (lhs_horiz_0 < k_size) { \ + lhs_pf0 = lhs(lhs_vert, lhs_horiz_0); \ + } \ + } \ + \ + const Index rhs_vert = base_k + load_idx_vert; \ + if (!needs_edge_check || rhs_vert < k_size) { \ + const Index rhs_horiz_0 = base_n + threadIdx.z + 0 * 8; \ + const Index rhs_horiz_1 = base_n + threadIdx.z + 1 * 8; \ + const Index rhs_horiz_2 = base_n + threadIdx.z + 2 * 8; \ + const Index rhs_horiz_3 = base_n + threadIdx.z + 3 * 8; \ + const Index rhs_horiz_4 = base_n + threadIdx.z + 4 * 8; \ + const Index rhs_horiz_5 = base_n + threadIdx.z + 5 * 8; \ + const Index rhs_horiz_6 = base_n + threadIdx.z + 6 * 8; \ + const Index rhs_horiz_7 = base_n + threadIdx.z + 7 * 8; \ + \ + if (rhs_horiz_7 < n_size) { \ + rhs_pf0 = rhs(rhs_vert, rhs_horiz_0); \ + rhs_pf1 = rhs(rhs_vert, rhs_horiz_1); \ + rhs_pf2 = rhs(rhs_vert, rhs_horiz_2); \ + rhs_pf3 = rhs(rhs_vert, rhs_horiz_3); \ + rhs_pf4 = rhs(rhs_vert, rhs_horiz_4); \ + rhs_pf5 = rhs(rhs_vert, rhs_horiz_5); \ + rhs_pf6 = rhs(rhs_vert, rhs_horiz_6); \ + rhs_pf7 = rhs(rhs_vert, rhs_horiz_7); \ + } else if (rhs_horiz_6 < n_size) { \ + rhs_pf0 = rhs(rhs_vert, rhs_horiz_0); \ + rhs_pf1 = rhs(rhs_vert, rhs_horiz_1); \ + rhs_pf2 = rhs(rhs_vert, rhs_horiz_2); \ + rhs_pf3 = rhs(rhs_vert, rhs_horiz_3); \ + rhs_pf4 = rhs(rhs_vert, rhs_horiz_4); \ + rhs_pf5 = rhs(rhs_vert, rhs_horiz_5); \ + rhs_pf6 = rhs(rhs_vert, rhs_horiz_6); \ + } else if (rhs_horiz_5 < n_size) { \ + rhs_pf0 = rhs(rhs_vert, rhs_horiz_0); \ + rhs_pf1 = rhs(rhs_vert, rhs_horiz_1); \ + rhs_pf2 = rhs(rhs_vert, rhs_horiz_2); \ + rhs_pf3 = rhs(rhs_vert, rhs_horiz_3); \ + rhs_pf4 = rhs(rhs_vert, rhs_horiz_4); \ + rhs_pf5 = rhs(rhs_vert, rhs_horiz_5); \ + } else if (rhs_horiz_4 < n_size) { \ + rhs_pf0 = rhs(rhs_vert, rhs_horiz_0); \ + rhs_pf1 = rhs(rhs_vert, rhs_horiz_1); \ + rhs_pf2 = rhs(rhs_vert, rhs_horiz_2); \ + rhs_pf3 = rhs(rhs_vert, rhs_horiz_3); \ + rhs_pf4 = rhs(rhs_vert, rhs_horiz_4); \ + } else if (rhs_horiz_3 < n_size) { \ + rhs_pf0 = rhs(rhs_vert, rhs_horiz_0); \ + rhs_pf1 = rhs(rhs_vert, rhs_horiz_1); \ + rhs_pf2 = rhs(rhs_vert, rhs_horiz_2); \ + rhs_pf3 = rhs(rhs_vert, rhs_horiz_3); \ + } else if (rhs_horiz_2 < n_size) { \ + rhs_pf0 = rhs(rhs_vert, rhs_horiz_0); \ + rhs_pf1 = rhs(rhs_vert, rhs_horiz_1); \ + rhs_pf2 = rhs(rhs_vert, rhs_horiz_2); \ + } else if (rhs_horiz_1 < n_size) { \ + rhs_pf0 = rhs(rhs_vert, rhs_horiz_0); \ + rhs_pf1 = rhs(rhs_vert, rhs_horiz_1); \ + } else if (rhs_horiz_0 < n_size) { \ + rhs_pf0 = rhs(rhs_vert, rhs_horiz_0); \ + } \ + } \ + } \ + +#define writeRegToShmem(_) \ + lhs_shmem[lhs_store_idx_0] = lhs_pf0; \ + rhs_shmem[rhs_store_idx_0] = rhs_pf0; \ + \ + lhs_shmem[lhs_store_idx_1] = lhs_pf1; \ + rhs_shmem[rhs_store_idx_1] = rhs_pf1; \ + \ + lhs_shmem[lhs_store_idx_2] = lhs_pf2; \ + rhs_shmem[rhs_store_idx_2] = rhs_pf2; \ + \ + lhs_shmem[lhs_store_idx_3] = lhs_pf3; \ + rhs_shmem[rhs_store_idx_3] = rhs_pf3; \ + \ + lhs_shmem[lhs_store_idx_4] = lhs_pf4; \ + rhs_shmem[rhs_store_idx_4] = rhs_pf4; \ + \ + lhs_shmem[lhs_store_idx_5] = lhs_pf5; \ + rhs_shmem[rhs_store_idx_5] = rhs_pf5; \ + \ + lhs_shmem[lhs_store_idx_6] = lhs_pf6; \ + rhs_shmem[rhs_store_idx_6] = rhs_pf6; \ + \ + lhs_shmem[lhs_store_idx_7] = lhs_pf7; \ + rhs_shmem[rhs_store_idx_7] = rhs_pf7; \ + + // declare and initialize result array +#define res(i, j) _res_##i##j +#define initResultRow(i) \ + Scalar res(i, 0) = conv(0); \ + Scalar res(i, 1) = conv(0); \ + Scalar res(i, 2) = conv(0); \ + Scalar res(i, 3) = conv(0); \ + Scalar res(i, 4) = conv(0); \ + Scalar res(i, 5) = conv(0); \ + Scalar res(i, 6) = conv(0); \ + Scalar res(i, 7) = conv(0); \ + + internal::scalar_cast_op conv; + initResultRow(0); + initResultRow(1); + initResultRow(2); + initResultRow(3); + initResultRow(4); + initResultRow(5); + initResultRow(6); + initResultRow(7); +#undef initResultRow + + for (Index base_k = 0; base_k < k_size; base_k += 64) { + // wait for previous iteration to finish with shmem. Despite common sense, + // the code is a bit faster with this here then at bottom of loop + __syncthreads(); + + prefetchIntoRegisters(base_k); + writeRegToShmem(); + + #undef prefetchIntoRegisters + #undef writeRegToShmem + + // wait for shared mem packing to be done before starting computation + __syncthreads(); + + // compute 8x8 matrix product by outer product. This involves packing one column + // of LHS and one row of RHS into registers (takes 16 registers). + +#define lcol(i) _lcol##i + Scalar lcol(0); + Scalar lcol(1); + Scalar lcol(2); + Scalar lcol(3); + Scalar lcol(4); + Scalar lcol(5); + Scalar lcol(6); + Scalar lcol(7); + +#define rrow(j) _rrow##j + Scalar rrow(0); + Scalar rrow(1); + Scalar rrow(2); + Scalar rrow(3); + Scalar rrow(4); + Scalar rrow(5); + Scalar rrow(6); + Scalar rrow(7); + + // Now x corresponds to k, y to m, and z to n + const Scalar* lhs_block = &lhs_shmem[threadIdx.x + 9 * threadIdx.y]; + const Scalar* rhs_block = &rhs_shmem[threadIdx.x + 8 * threadIdx.z]; + +#define lhs_element(i, j) lhs_block[72 * ((i) + 8 * (j))] +#define rhs_element(i, j) rhs_block[72 * ((i) + 8 * (j))] + +#define loadData(i, j) \ + lcol(0) = lhs_element(0, j); \ + rrow(0) = rhs_element(i, 0); \ + lcol(1) = lhs_element(1, j); \ + rrow(1) = rhs_element(i, 1); \ + lcol(2) = lhs_element(2, j); \ + rrow(2) = rhs_element(i, 2); \ + lcol(3) = lhs_element(3, j); \ + rrow(3) = rhs_element(i, 3); \ + lcol(4) = lhs_element(4, j); \ + rrow(4) = rhs_element(i, 4); \ + lcol(5) = lhs_element(5, j); \ + rrow(5) = rhs_element(i, 5); \ + lcol(6) = lhs_element(6, j); \ + rrow(6) = rhs_element(i, 6); \ + lcol(7) = lhs_element(7, j); \ + rrow(7) = rhs_element(i, 7); \ + +#define computeCol(j) \ + res(0, j) += lcol(0) * rrow(j); \ + res(1, j) += lcol(1) * rrow(j); \ + res(2, j) += lcol(2) * rrow(j); \ + res(3, j) += lcol(3) * rrow(j); \ + res(4, j) += lcol(4) * rrow(j); \ + res(5, j) += lcol(5) * rrow(j); \ + res(6, j) += lcol(6) * rrow(j); \ + res(7, j) += lcol(7) * rrow(j); \ + +#define computePass(i) \ + loadData(i, i); \ + \ + computeCol(0); \ + computeCol(1); \ + computeCol(2); \ + computeCol(3); \ + computeCol(4); \ + computeCol(5); \ + computeCol(6); \ + computeCol(7); \ + + computePass(0); + computePass(1); + computePass(2); + computePass(3); + computePass(4); + computePass(5); + computePass(6); + computePass(7); + +#undef lcol +#undef rrow +#undef lhs_element +#undef rhs_element +#undef loadData +#undef computeCol +#undef computePass + } // end loop over k + + // we've now iterated over all of the large (ie width 64) k blocks and + // accumulated results in registers. At this point thread (x, y, z) contains + // the sum across all big k blocks of the product of little k block of index (x, y) + // with block of index (y, z). To compute the final output, we need to reduce + // the 8 threads over y by summation. +#define shuffleInc(i, j, mask) res(i, j) += __shfl_xor(res(i, j), mask) + +#define reduceRow(i, mask) \ + shuffleInc(i, 0, mask); \ + shuffleInc(i, 1, mask); \ + shuffleInc(i, 2, mask); \ + shuffleInc(i, 3, mask); \ + shuffleInc(i, 4, mask); \ + shuffleInc(i, 5, mask); \ + shuffleInc(i, 6, mask); \ + shuffleInc(i, 7, mask); \ + +#define reduceMatrix(mask) \ + reduceRow(0, mask); \ + reduceRow(1, mask); \ + reduceRow(2, mask); \ + reduceRow(3, mask); \ + reduceRow(4, mask); \ + reduceRow(5, mask); \ + reduceRow(6, mask); \ + reduceRow(7, mask); \ + + // actually perform the reduction, now each thread of index (_, y, z) + // contains the correct values in its registers that belong in the output + // block + reduceMatrix(1); + reduceMatrix(2); + reduceMatrix(4); + +#undef shuffleInc +#undef reduceRow +#undef reduceMatrix + + // now we need to copy the 64 values into main memory. We can't split work + // among threads because all variables are in registers. There's 2 ways + // to do this: + // (1) have 1 thread do 64 writes from registers into global memory + // (2) have 1 thread do 64 writes into shared memory, and then 8 threads + // each do 8 writes into global memory. We can just overwrite the shared + // memory from the problem we just solved. + // (2) is slightly faster than (1) due to less branching and more ILP + + // TODO: won't yield much gain, but could just use currently unused shared mem + // and then we won't have to sync + // wait for shared mem to be out of use + __syncthreads(); + +#define writeResultShmem(i, j) \ + lhs_shmem[i + 8 * threadIdx.y + 64 * threadIdx.z + 512 * j] = res(i, j); \ + +#define writeRow(i) \ + writeResultShmem(i, 0); \ + writeResultShmem(i, 1); \ + writeResultShmem(i, 2); \ + writeResultShmem(i, 3); \ + writeResultShmem(i, 4); \ + writeResultShmem(i, 5); \ + writeResultShmem(i, 6); \ + writeResultShmem(i, 7); \ + + if (threadIdx.x == 0) { + writeRow(0); + writeRow(1); + writeRow(2); + writeRow(3); + writeRow(4); + writeRow(5); + writeRow(6); + writeRow(7); + } +#undef writeResultShmem +#undef writeRow + + const int max_i_write = numext::mini((int)((m_size - base_m - threadIdx.y + 7) / 8), 8); + const int max_j_write = numext::mini((int)((n_size - base_n - threadIdx.z + 7) / 8), 8); + + if (threadIdx.x < max_i_write) { + if (max_j_write == 8) { + // TODO: can i trade bank conflicts for coalesced writes? + Scalar val0 = lhs_shmem[threadIdx.x + 8 * threadIdx.y + 64 * threadIdx.z + 512 * 0]; + Scalar val1 = lhs_shmem[threadIdx.x + 8 * threadIdx.y + 64 * threadIdx.z + 512 * 1]; + Scalar val2 = lhs_shmem[threadIdx.x + 8 * threadIdx.y + 64 * threadIdx.z + 512 * 2]; + Scalar val3 = lhs_shmem[threadIdx.x + 8 * threadIdx.y + 64 * threadIdx.z + 512 * 3]; + Scalar val4 = lhs_shmem[threadIdx.x + 8 * threadIdx.y + 64 * threadIdx.z + 512 * 4]; + Scalar val5 = lhs_shmem[threadIdx.x + 8 * threadIdx.y + 64 * threadIdx.z + 512 * 5]; + Scalar val6 = lhs_shmem[threadIdx.x + 8 * threadIdx.y + 64 * threadIdx.z + 512 * 6]; + Scalar val7 = lhs_shmem[threadIdx.x + 8 * threadIdx.y + 64 * threadIdx.z + 512 * 7]; + + output(base_m + threadIdx.y + 8 * threadIdx.x, base_n + threadIdx.z + 8 * 0) = val0; + output(base_m + threadIdx.y + 8 * threadIdx.x, base_n + threadIdx.z + 8 * 1) = val1; + output(base_m + threadIdx.y + 8 * threadIdx.x, base_n + threadIdx.z + 8 * 2) = val2; + output(base_m + threadIdx.y + 8 * threadIdx.x, base_n + threadIdx.z + 8 * 3) = val3; + output(base_m + threadIdx.y + 8 * threadIdx.x, base_n + threadIdx.z + 8 * 4) = val4; + output(base_m + threadIdx.y + 8 * threadIdx.x, base_n + threadIdx.z + 8 * 5) = val5; + output(base_m + threadIdx.y + 8 * threadIdx.x, base_n + threadIdx.z + 8 * 6) = val6; + output(base_m + threadIdx.y + 8 * threadIdx.x, base_n + threadIdx.z + 8 * 7) = val7; + } else { +#pragma unroll 7 + for (int j = 0; j < max_j_write; j++) { + Scalar val = lhs_shmem[threadIdx.x + 8 * threadIdx.y + 64 * threadIdx.z + 512 * j]; + output(base_m + threadIdx.y + 8 * threadIdx.x, base_n + threadIdx.z + 8 * j) = val; + } + } + } +#undef res +} + + +template +__global__ void +__launch_bounds__(512) +EigenContractionKernel(const LhsMapper lhs, const RhsMapper rhs, + const OutputMapper output, + const Index m_size, const Index n_size, const Index k_size) { + __shared__ Scalar lhs_shmem[72 * 64]; + __shared__ Scalar rhs_shmem[72 * 64]; + + const Index m_block_idx = blockIdx.x; + const Index n_block_idx = blockIdx.y; + + const Index base_m = 64 * m_block_idx; + const Index base_n = 64 * n_block_idx; + + if (base_m + 63 < m_size && base_n + 63 < n_size) { + EigenContractionKernelInternal(lhs, rhs, output, lhs_shmem, rhs_shmem, m_size, n_size, k_size); + } else { + EigenContractionKernelInternal(lhs, rhs, output, lhs_shmem, rhs_shmem, m_size, n_size, k_size); + } +} + + +template +__device__ EIGEN_STRONG_INLINE void +EigenFloatContractionKernelInternal16x16(const LhsMapper lhs, const RhsMapper rhs, + const OutputMapper output, float2 lhs_shmem2[][16], + float2 rhs_shmem2[][8], const Index m_size, + const Index n_size, const Index k_size, + const Index base_m, const Index base_n) { + typedef float Scalar; + + // prefetch registers + float4 lhs_pf0, rhs_pf0; + + float4 results[4]; + for (int i=0; i < 4; i++) { + results[i].x = results[i].y = results[i].z = results[i].w = 0; + } + + +#define prefetch_lhs(reg, row, col) \ + if (!CHECK_LHS_BOUNDARY) { \ + if (col < k_size) { \ + reg =lhs.loadPacket(row, col); \ + } \ + } else { \ + if (col < k_size) { \ + if (row + 3 < m_size) { \ + reg =lhs.loadPacket(row, col); \ + } else if (row + 2 < m_size) { \ + reg.x =lhs(row + 0, col); \ + reg.y =lhs(row + 1, col); \ + reg.z =lhs(row + 2, col); \ + } else if (row + 1 < m_size) { \ + reg.x =lhs(row + 0, col); \ + reg.y =lhs(row + 1, col); \ + } else if (row < m_size) { \ + reg.x =lhs(row + 0, col); \ + } \ + } \ + } \ + + + Index lhs_vert = base_m+threadIdx.x*4; + + for (Index k = 0; k < k_size; k += 16) { + lhs_pf0 = internal::pset1(0); + rhs_pf0 = internal::pset1(0); + + Index lhs_horiz = threadIdx.y+k; + prefetch_lhs(lhs_pf0, lhs_vert, lhs_horiz) + + Index rhs_vert = k+(threadIdx.x%4)*4; + Index rhs_horiz0 = (threadIdx.x>>2)+threadIdx.y*4+base_n; + + if (!CHECK_RHS_BOUNDARY) { + if ((rhs_vert + 3) < k_size) { + // just CHECK_RHS_BOUNDARY + rhs_pf0 = rhs.loadPacket(rhs_vert, rhs_horiz0); + } else if (rhs_vert + 2 < k_size) { + // just CHECK_RHS_BOUNDARY + rhs_pf0.x = rhs(rhs_vert, rhs_horiz0); + rhs_pf0.y = rhs(rhs_vert + 1, rhs_horiz0); + rhs_pf0.z = rhs(rhs_vert + 2, rhs_horiz0); + } else if (rhs_vert + 1 < k_size) { + rhs_pf0.x = rhs(rhs_vert, rhs_horiz0); + rhs_pf0.y = rhs(rhs_vert + 1, rhs_horiz0); + } else if (rhs_vert < k_size) { + rhs_pf0.x = rhs(rhs_vert, rhs_horiz0); + } + } else { + if (rhs_horiz0 < n_size) { + if ((rhs_vert + 3) < k_size) { + rhs_pf0 = rhs.loadPacket(rhs_vert, rhs_horiz0); + } else if ((rhs_vert + 2) < k_size) { + rhs_pf0.x = rhs(rhs_vert, rhs_horiz0); + rhs_pf0.y = rhs(rhs_vert + 1, rhs_horiz0); + rhs_pf0.z = rhs(rhs_vert + 2, rhs_horiz0); + } else if ((rhs_vert + 1) < k_size) { + rhs_pf0.x = rhs(rhs_vert, rhs_horiz0); + rhs_pf0.y = rhs(rhs_vert + 1, rhs_horiz0); + } else if (rhs_vert < k_size) { + rhs_pf0.x = rhs(rhs_vert, rhs_horiz0); + } + } + } + float x1, x2 ; + // the following can be a bitwise operation..... some day. + if((threadIdx.x%8) < 4) { + x1 = rhs_pf0.y; + x2 = rhs_pf0.w; + } else { + x1 = rhs_pf0.x; + x2 = rhs_pf0.z; + } + x1 = __shfl_xor(x1, 4); + x2 = __shfl_xor(x2, 4); + if((threadIdx.x%8) < 4) { + rhs_pf0.y = x1; + rhs_pf0.w = x2; + } else { + rhs_pf0.x = x1; + rhs_pf0.z = x2; + } + + // We have 64 features. + // Row 0 -> times (0, 4, 8, 12, 1, 5, 9, 13) for features 0, 1. + // Row 1 -> times (0, 4, 8, 12, 1, 5, 9, 13) for features 2, 3. + // ... + // Row 31 -> times (0, 4, 8, 12, 1, 5, 9, 13) for features 62, 63 + // Row 32 -> times (2, 6, 10, 14, 3, 7, 11, 15) for features 0, 1 + // ... + rhs_shmem2[(threadIdx.x>>3)+ threadIdx.y*2][threadIdx.x%8] = make_float2(rhs_pf0.x, rhs_pf0.y); + rhs_shmem2[(threadIdx.x>>3)+ threadIdx.y*2+32][threadIdx.x%8] = make_float2(rhs_pf0.z, rhs_pf0.w); + + // Row 0 (time 0) -> features (0, 1), (4, 5), .. (28, 29), (32, 33), .. (60, 61) + // Row 1 (time 1) -> features (0, 1), (4, 5), .. (28, 29), (32, 33), .. (60, 61) + // ... + // Row 15 (time 15) -> features (0, 1), (4, 5), .. (28, 29), (32, 33), .. (60, 61) + // Row 16 (time 0) -> features (2, 3), (6, 7), .. (30, 31), (34, 35), .. (62, 63) + // ... + + lhs_shmem2[threadIdx.y][threadIdx.x] = make_float2(lhs_pf0.x, lhs_pf0.y); + lhs_shmem2[threadIdx.y+16][threadIdx.x] = make_float2(lhs_pf0.z, lhs_pf0.w); + + +#define add_vals(fl1, fl2, fr1, fr2)\ + results[0].x += fl1.x * fr1.x;\ + results[0].y += fl1.y * fr1.x;\ + results[0].z += fl2.x * fr1.x;\ + results[0].w += fl2.y * fr1.x;\ +\ + results[1].x += fl1.x * fr1.y;\ + results[1].y += fl1.y * fr1.y;\ + results[1].z += fl2.x * fr1.y;\ + results[1].w += fl2.y * fr1.y;\ +\ + results[2].x += fl1.x * fr2.x;\ + results[2].y += fl1.y * fr2.x;\ + results[2].z += fl2.x * fr2.x;\ + results[2].w += fl2.y * fr2.x;\ +\ + results[3].x += fl1.x * fr2.y;\ + results[3].y += fl1.y * fr2.y;\ + results[3].z += fl2.x * fr2.y;\ + results[3].w += fl2.y * fr2.y;\ + + __syncthreads(); + + // Do the multiplies. + #pragma unroll + for (int koff = 0; koff < 16; koff ++) { + // 32 x threads. + float2 fl1 = lhs_shmem2[koff][threadIdx.x]; + float2 fl2 = lhs_shmem2[koff + 16][threadIdx.x]; + + int start_feature = threadIdx.y * 4; + float2 fr1 = rhs_shmem2[(start_feature>>1) + 32*((koff%4)/2)][koff/4 + (koff%2)*4]; + float2 fr2 = rhs_shmem2[(start_feature>>1) + 1 + 32*((koff%4)/2)][koff/4 + (koff%2)*4]; + + add_vals(fl1, fl2, fr1, fr2) + } + __syncthreads(); + } + +#undef prefetch_lhs +#undef add_vals + + Index horiz_base = threadIdx.y*4+base_n; + if (!CHECK_LHS_BOUNDARY && !CHECK_RHS_BOUNDARY) { + for (int i = 0; i < 4; i++) { + output(lhs_vert, horiz_base + i) = results[i].x; + output(lhs_vert + 1, horiz_base + i) = results[i].y; + output(lhs_vert + 2, horiz_base + i) = results[i].z; + output(lhs_vert + 3, horiz_base + i) = results[i].w; + } + } else if (!CHECK_RHS_BOUNDARY) { + // CHECK LHS + if (lhs_vert + 3 < m_size) { + for (int i = 0; i < 4; i++) { + output(lhs_vert, horiz_base + i) = results[i].x; + output(lhs_vert + 1, horiz_base + i) = results[i].y; + output(lhs_vert + 2, horiz_base + i) = results[i].z; + output(lhs_vert + 3, horiz_base + i) = results[i].w; + } + } else if (lhs_vert + 2 < m_size) { + for (int i = 0; i < 4; i++) { + output(lhs_vert, horiz_base + i) = results[i].x; + output(lhs_vert + 1, horiz_base + i) = results[i].y; + output(lhs_vert + 2, horiz_base + i) = results[i].z; + } + } else if (lhs_vert + 1 < m_size) { + for (int i = 0; i < 4; i++) { + output(lhs_vert, horiz_base + i) = results[i].x; + output(lhs_vert + 1, horiz_base + i) = results[i].y; + } + } else if (lhs_vert < m_size) { + for (int i = 0; i < 4; i++) { + output(lhs_vert, horiz_base + i) = results[i].x; + } + } + } else if (!CHECK_LHS_BOUNDARY) { + // CHECK RHS + /* + int ncols_rem = fminf(n_size- horiz_base, 4); + for (int i = 0; i < ncols_rem; i++) { + output(lhs_vert, horiz_base + i) = results[i].x; + output(lhs_vert + 1, horiz_base + i) = results[i].y; + output(lhs_vert + 2, horiz_base + i) = results[i].z; + output(lhs_vert + 3, horiz_base + i) = results[i].w; + }*/ + for (int i = 0; i < 4; i++) { + if (horiz_base+i < n_size) { + output(lhs_vert, horiz_base + i) = results[i].x; + output(lhs_vert + 1, horiz_base + i) = results[i].y; + output(lhs_vert + 2, horiz_base + i) = results[i].z; + output(lhs_vert + 3, horiz_base + i) = results[i].w; + } + } + } else { + // CHECK both boundaries. + for (int i = 0; i < 4; i++) { + if (horiz_base+i < n_size) { + if (lhs_vert < m_size) + output(lhs_vert, horiz_base + i) = results[i].x; + if (lhs_vert + 1 < m_size) + output(lhs_vert + 1, horiz_base + i) = results[i].y; + if (lhs_vert + 2 < m_size) + output(lhs_vert + 2, horiz_base + i) = results[i].z; + if (lhs_vert + 3 < m_size) + output(lhs_vert + 3, horiz_base + i) = results[i].w; + } + } + } +} + + +template +__device__ EIGEN_STRONG_INLINE void +EigenFloatContractionKernelInternal(const LhsMapper lhs, const RhsMapper rhs, + const OutputMapper output, float2 lhs_shmem2[][32], + float2 rhs_shmem2[][8], const Index m_size, + const Index n_size, const Index k_size, + const Index base_m, const Index base_n) { + typedef float Scalar; + + // prefetch registers + float4 lhs_pf0, lhs_pf1, lhs_pf2, lhs_pf3; + float4 rhs_pf0, rhs_pf1; + + float4 results[8]; + for (int i=0; i < 8; i++) { + results[i].x = results[i].y = results[i].z = results[i].w = 0; + } + + + Index lhs_vert = base_m+threadIdx.x*4+(threadIdx.y%4)*32; + for (Index k = 0; k < k_size; k += 32) { + lhs_pf0 = internal::pset1(0); + lhs_pf1 = internal::pset1(0); + lhs_pf2 = internal::pset1(0); + lhs_pf3 = internal::pset1(0); + + rhs_pf0 = internal::pset1(0); + rhs_pf1 = internal::pset1(0); + + if (!CHECK_LHS_BOUNDARY) { + if ((threadIdx.y/4+k+24) < k_size) { + lhs_pf0 =lhs.loadPacket(lhs_vert, (threadIdx.y/4+k)); + lhs_pf1 =lhs.loadPacket(lhs_vert, (threadIdx.y/4+k+8)); + lhs_pf2 =lhs.loadPacket(lhs_vert, (threadIdx.y/4+k+16)); + lhs_pf3 =lhs.loadPacket(lhs_vert, (threadIdx.y/4+k+24)); + } else if ((threadIdx.y/4+k+16) < k_size) { + lhs_pf0 =lhs.loadPacket(lhs_vert, (threadIdx.y/4+k)); + lhs_pf1 =lhs.loadPacket(lhs_vert, (threadIdx.y/4+k+8)); + lhs_pf2 =lhs.loadPacket(lhs_vert, (threadIdx.y/4+k+16)); + } else if ((threadIdx.y/4+k+8) < k_size) { + lhs_pf0 =lhs.loadPacket(lhs_vert, (threadIdx.y/4+k)); + lhs_pf1 =lhs.loadPacket(lhs_vert, (threadIdx.y/4+k+8)); + } else if ((threadIdx.y/4+k) < k_size) { + lhs_pf0 =lhs.loadPacket(lhs_vert, (threadIdx.y/4+k)); + } + } else { + // just CHECK_LHS_BOUNDARY + if (lhs_vert + 3 < m_size) { + if ((threadIdx.y/4+k+24) < k_size) { + lhs_pf0 =lhs.loadPacket(lhs_vert, (threadIdx.y/4+k)); + lhs_pf1 =lhs.loadPacket(lhs_vert, (threadIdx.y/4+k+8)); + lhs_pf2 =lhs.loadPacket(lhs_vert, (threadIdx.y/4+k+16)); + lhs_pf3 =lhs.loadPacket(lhs_vert, (threadIdx.y/4+k+24)); + } else if ((threadIdx.y/4+k+16) < k_size) { + lhs_pf0 =lhs.loadPacket(lhs_vert, (threadIdx.y/4+k)); + lhs_pf1 =lhs.loadPacket(lhs_vert, (threadIdx.y/4+k+8)); + lhs_pf2 =lhs.loadPacket(lhs_vert, (threadIdx.y/4+k+16)); + } else if ((threadIdx.y/4+k+8) < k_size) { + lhs_pf0 =lhs.loadPacket(lhs_vert, (threadIdx.y/4+k)); + lhs_pf1 =lhs.loadPacket(lhs_vert, (threadIdx.y/4+k+8)); + } else if ((threadIdx.y/4+k) < k_size) { + lhs_pf0 =lhs.loadPacket(lhs_vert, (threadIdx.y/4+k)); + } + } else if (lhs_vert + 2 < m_size) { + if ((threadIdx.y/4+k+24) < k_size) { + lhs_pf0.x =lhs(lhs_vert + 0, (threadIdx.y/4+k)); + lhs_pf0.y =lhs(lhs_vert + 1, (threadIdx.y/4+k)); + lhs_pf0.z =lhs(lhs_vert + 2, (threadIdx.y/4+k)); + lhs_pf1.x =lhs(lhs_vert + 0, (threadIdx.y/4+k+8)); + lhs_pf1.y =lhs(lhs_vert + 1, (threadIdx.y/4+k+8)); + lhs_pf1.z =lhs(lhs_vert + 2, (threadIdx.y/4+k+8)); + lhs_pf2.x =lhs(lhs_vert + 0, (threadIdx.y/4+k+16)); + lhs_pf2.y =lhs(lhs_vert + 1, (threadIdx.y/4+k+16)); + lhs_pf2.z =lhs(lhs_vert + 2, (threadIdx.y/4+k+16)); + lhs_pf3.x =lhs(lhs_vert + 0, (threadIdx.y/4+k+24)); + lhs_pf3.y =lhs(lhs_vert + 1, (threadIdx.y/4+k+24)); + lhs_pf3.z =lhs(lhs_vert + 2, (threadIdx.y/4+k+24)); + } else if ((threadIdx.y/4+k+16) < k_size) { + lhs_pf0.x =lhs(lhs_vert + 0, (threadIdx.y/4+k)); + lhs_pf0.y =lhs(lhs_vert + 1, (threadIdx.y/4+k)); + lhs_pf0.z =lhs(lhs_vert + 2, (threadIdx.y/4+k)); + lhs_pf1.x =lhs(lhs_vert + 0, (threadIdx.y/4+k+8)); + lhs_pf1.y =lhs(lhs_vert + 1, (threadIdx.y/4+k+8)); + lhs_pf1.z =lhs(lhs_vert + 2, (threadIdx.y/4+k+8)); + lhs_pf2.x =lhs(lhs_vert + 0, (threadIdx.y/4+k+16)); + lhs_pf2.y =lhs(lhs_vert + 1, (threadIdx.y/4+k+16)); + lhs_pf2.z =lhs(lhs_vert + 2, (threadIdx.y/4+k+16)); + } else if ((threadIdx.y/4+k+8) < k_size) { + lhs_pf0.x =lhs(lhs_vert + 0, (threadIdx.y/4+k)); + lhs_pf0.y =lhs(lhs_vert + 1, (threadIdx.y/4+k)); + lhs_pf0.z =lhs(lhs_vert + 2, (threadIdx.y/4+k)); + lhs_pf1.x =lhs(lhs_vert + 0, (threadIdx.y/4+k+8)); + lhs_pf1.y =lhs(lhs_vert + 1, (threadIdx.y/4+k+8)); + lhs_pf1.z =lhs(lhs_vert + 2, (threadIdx.y/4+k+8)); + } else if ((threadIdx.y/4+k) < k_size) { + lhs_pf0.x =lhs(lhs_vert + 0, (threadIdx.y/4+k)); + lhs_pf0.y =lhs(lhs_vert + 1, (threadIdx.y/4+k)); + lhs_pf0.z =lhs(lhs_vert + 2, (threadIdx.y/4+k)); + } + } else if (lhs_vert + 1 < m_size) { + if ((threadIdx.y/4+k+24) < k_size) { + lhs_pf0.x =lhs(lhs_vert + 0, (threadIdx.y/4+k)); + lhs_pf0.y =lhs(lhs_vert + 1, (threadIdx.y/4+k)); + lhs_pf1.x =lhs(lhs_vert + 0, (threadIdx.y/4+k+8)); + lhs_pf1.y =lhs(lhs_vert + 1, (threadIdx.y/4+k+8)); + lhs_pf2.x =lhs(lhs_vert + 0, (threadIdx.y/4+k+16)); + lhs_pf2.y =lhs(lhs_vert + 1, (threadIdx.y/4+k+16)); + lhs_pf3.x =lhs(lhs_vert + 0, (threadIdx.y/4+k+24)); + lhs_pf3.y =lhs(lhs_vert + 1, (threadIdx.y/4+k+24)); + } else if ((threadIdx.y/4+k+16) < k_size) { + lhs_pf0.x =lhs(lhs_vert + 0, (threadIdx.y/4+k)); + lhs_pf0.y =lhs(lhs_vert + 1, (threadIdx.y/4+k)); + lhs_pf1.x =lhs(lhs_vert + 0, (threadIdx.y/4+k+8)); + lhs_pf1.y =lhs(lhs_vert + 1, (threadIdx.y/4+k+8)); + lhs_pf2.x =lhs(lhs_vert + 0, (threadIdx.y/4+k+16)); + lhs_pf2.y =lhs(lhs_vert + 1, (threadIdx.y/4+k+16)); + } else if ((threadIdx.y/4+k+8) < k_size) { + lhs_pf0.x =lhs(lhs_vert + 0, (threadIdx.y/4+k)); + lhs_pf0.y =lhs(lhs_vert + 1, (threadIdx.y/4+k)); + lhs_pf1.x =lhs(lhs_vert + 0, (threadIdx.y/4+k+8)); + lhs_pf1.y =lhs(lhs_vert + 1, (threadIdx.y/4+k+8)); + } else if ((threadIdx.y/4+k) < k_size) { + lhs_pf0.x =lhs(lhs_vert + 0, (threadIdx.y/4+k)); + lhs_pf0.y =lhs(lhs_vert + 1, (threadIdx.y/4+k)); + } + } else if (lhs_vert < m_size) { + if ((threadIdx.y/4+k+24) < k_size) { + lhs_pf0.x =lhs(lhs_vert + 0, (threadIdx.y/4+k)); + lhs_pf1.x =lhs(lhs_vert + 0, (threadIdx.y/4+k+8)); + lhs_pf2.x =lhs(lhs_vert + 0, (threadIdx.y/4+k+16)); + lhs_pf3.x =lhs(lhs_vert + 0, (threadIdx.y/4+k+24)); + } else if ((threadIdx.y/4+k+16) < k_size) { + lhs_pf0.x =lhs(lhs_vert + 0, (threadIdx.y/4+k)); + lhs_pf1.x =lhs(lhs_vert + 0, (threadIdx.y/4+k+8)); + lhs_pf2.x =lhs(lhs_vert + 0, (threadIdx.y/4+k+16)); + } else if ((threadIdx.y/4+k+8) < k_size) { + lhs_pf0.x =lhs(lhs_vert + 0, (threadIdx.y/4+k)); + lhs_pf1.x =lhs(lhs_vert + 0, (threadIdx.y/4+k+8)); + } else if ((threadIdx.y/4+k) < k_size) { + lhs_pf0.x =lhs(lhs_vert + 0, (threadIdx.y/4+k)); + } + } + } + __syncthreads(); + Index rhs_vert = k+threadIdx.x*4; + Index rhs_horiz0 = threadIdx.y*2+base_n; + Index rhs_horiz1 = threadIdx.y*2+1+base_n; + if (!CHECK_RHS_BOUNDARY) { + if ((rhs_vert + 3) < k_size) { + // just CHECK_RHS_BOUNDARY + rhs_pf0 = rhs.loadPacket(rhs_vert, rhs_horiz0); + rhs_pf1 = rhs.loadPacket(rhs_vert, rhs_horiz1); + } else if (rhs_vert + 2 < k_size) { + // just CHECK_RHS_BOUNDARY + rhs_pf0.x = rhs(rhs_vert, rhs_horiz0); + rhs_pf0.y = rhs(rhs_vert + 1, rhs_horiz0); + rhs_pf0.z = rhs(rhs_vert + 2, rhs_horiz0); + rhs_pf1.x = rhs(rhs_vert, rhs_horiz1); + rhs_pf1.y = rhs(rhs_vert + 1, rhs_horiz1); + rhs_pf1.z = rhs(rhs_vert + 2, rhs_horiz1); + } else if (rhs_vert + 1 < k_size) { + rhs_pf0.x = rhs(rhs_vert, rhs_horiz0); + rhs_pf0.y = rhs(rhs_vert + 1, rhs_horiz0); + rhs_pf1.x = rhs(rhs_vert, rhs_horiz1); + rhs_pf1.y = rhs(rhs_vert + 1, rhs_horiz1); + } else if (rhs_vert < k_size) { + rhs_pf0.x = rhs(rhs_vert, rhs_horiz0); + rhs_pf1.x = rhs(rhs_vert, rhs_horiz1); + } + } else { + if (rhs_horiz1 < n_size) { + if ((rhs_vert + 3) < k_size) { + // just CHECK_RHS_BOUNDARY + rhs_pf0 = rhs.loadPacket(rhs_vert, rhs_horiz0); + rhs_pf1 = rhs.loadPacket(rhs_vert, rhs_horiz1); + } else if (rhs_vert + 2 < k_size) { + // just CHECK_RHS_BOUNDARY + rhs_pf0.x = rhs(rhs_vert, rhs_horiz0); + rhs_pf0.y = rhs(rhs_vert + 1, rhs_horiz0); + rhs_pf0.z = rhs(rhs_vert + 2, rhs_horiz0); + rhs_pf1.x = rhs(rhs_vert, rhs_horiz1); + rhs_pf1.y = rhs(rhs_vert + 1, rhs_horiz1); + rhs_pf1.z = rhs(rhs_vert + 2, rhs_horiz1); + } else if (k+threadIdx.x*4 + 1 < k_size) { + rhs_pf0.x = rhs(rhs_vert, rhs_horiz0); + rhs_pf0.y = rhs(rhs_vert + 1, rhs_horiz0); + rhs_pf1.x = rhs(rhs_vert, rhs_horiz1); + rhs_pf1.y = rhs(rhs_vert + 1, rhs_horiz1); + } else if (k+threadIdx.x*4 < k_size) { + rhs_pf0.x = rhs(rhs_vert, rhs_horiz0); + rhs_pf1.x = rhs(rhs_vert, rhs_horiz1); + } + } else if (rhs_horiz0 < n_size) { + if ((rhs_vert + 3) < k_size) { + // just CHECK_RHS_BOUNDARY + rhs_pf0 = rhs.loadPacket(rhs_vert, rhs_horiz0); + } else if ((rhs_vert + 2) < k_size) { + // just CHECK_RHS_BOUNDARY + rhs_pf0.x = rhs(rhs_vert, rhs_horiz0); + rhs_pf0.y = rhs(rhs_vert + 1, rhs_horiz0); + rhs_pf0.z = rhs(rhs_vert + 2, rhs_horiz0); + } else if ((rhs_vert + 1) < k_size) { + rhs_pf0.x = rhs(rhs_vert, rhs_horiz0); + rhs_pf0.y = rhs(rhs_vert + 1, rhs_horiz0); + } else if (rhs_vert < k_size) { + rhs_pf0.x = rhs(rhs_vert, rhs_horiz0); + } + } + } + __syncthreads(); + // Loaded. Do computation + // Row 0 -> times (0, 4, 8, .. 28) for features 0, 1. + // Row 1 -> times (0, 4, 8, .. 28) for features 2, 3. + // .. + // Row 31 -> times (0, 4, 8, .. 28) for features 62, 63 + rhs_shmem2[threadIdx.y][threadIdx.x] = make_float2(rhs_pf0.x, rhs_pf1.x); + // Row 32 -> times (1, 5, 9, .. 29) for features 0, 1. + // Row 33 -> times (1, 5, 9, .. 29) for features 2, 3. + // .. + rhs_shmem2[threadIdx.y+32][threadIdx.x] = make_float2(rhs_pf0.y, rhs_pf1.y); + // Row 64 -> times (2, 6, 10, .. 30) for features 0, 1. + // Row 65 -> times (2, 6, 10, .. 30) for features 2, 3. + rhs_shmem2[threadIdx.y+64][threadIdx.x] = make_float2(rhs_pf0.z, rhs_pf1.z); + // Row 96 -> times (3, 7, 11, .. 31) for features 0, 1. + // Row 97 -> times (3, 7, 11, .. 31) for features 2, 3. + rhs_shmem2[threadIdx.y+96][threadIdx.x] = make_float2(rhs_pf0.w, rhs_pf1.w); + + // LHS. + // Row 0 (time 0) -> features (0, 1), (4, 5), .. (28, 29), (32, 33), .. (60, 61) .. (124, 125) + // Row 1 (time 1) -> features (0, 1), (4, 5), .. (28, 29), (32, 33), .. (60, 61) .. (124, 125) + // ... + // Row 8 (time 0) -> features (2, 3), (6, 7), .. (30, 31), (34, 35), .. (62, 63) .. (126, 127) + // Row 15 (time 7) -> features (2, 3), (6, 7), .. (30, 31), (34, 35), .. (62, 63) .. (126, 127) + + +#define add_vals(a_feat1, a_feat2, f1, f2, f3, f4)\ + results[0].x += a_feat1.x * f1.x;\ + results[1].x += a_feat1.x * f1.y;\ + results[2].x += a_feat1.x * f2.x;\ + results[3].x += a_feat1.x * f2.y;\ + results[4].x += a_feat1.x * f3.x;\ + results[5].x += a_feat1.x * f3.y;\ + results[6].x += a_feat1.x * f4.x;\ + results[7].x += a_feat1.x * f4.y;\ +\ + results[0].y += a_feat1.y * f1.x;\ + results[1].y += a_feat1.y * f1.y;\ + results[2].y += a_feat1.y * f2.x;\ + results[3].y += a_feat1.y * f2.y;\ + results[4].y += a_feat1.y * f3.x;\ + results[5].y += a_feat1.y * f3.y;\ + results[6].y += a_feat1.y * f4.x;\ + results[7].y += a_feat1.y * f4.y;\ +\ + results[0].z += a_feat2.x * f1.x;\ + results[1].z += a_feat2.x * f1.y;\ + results[2].z += a_feat2.x * f2.x;\ + results[3].z += a_feat2.x * f2.y;\ + results[4].z += a_feat2.x * f3.x;\ + results[5].z += a_feat2.x * f3.y;\ + results[6].z += a_feat2.x * f4.x;\ + results[7].z += a_feat2.x * f4.y;\ +\ + results[0].w += a_feat2.y * f1.x;\ + results[1].w += a_feat2.y * f1.y;\ + results[2].w += a_feat2.y * f2.x;\ + results[3].w += a_feat2.y * f2.y;\ + results[4].w += a_feat2.y * f3.x;\ + results[5].w += a_feat2.y * f3.y;\ + results[6].w += a_feat2.y * f4.x;\ + results[7].w += a_feat2.y * f4.y;\ + + lhs_shmem2[threadIdx.y/4][threadIdx.x+(threadIdx.y%4)*8] = make_float2(lhs_pf0.x, lhs_pf0.y); + lhs_shmem2[threadIdx.y/4+8][threadIdx.x+(threadIdx.y%4)*8] = make_float2(lhs_pf1.x, lhs_pf1.y); + lhs_shmem2[threadIdx.y/4+16][threadIdx.x+(threadIdx.y%4)*8] = make_float2(lhs_pf2.x, lhs_pf2.y); + lhs_shmem2[threadIdx.y/4+24][threadIdx.x+(threadIdx.y%4)*8] = make_float2(lhs_pf3.x, lhs_pf3.y); + + lhs_shmem2[threadIdx.y/4 + 32][threadIdx.x+(threadIdx.y%4)*8] = make_float2(lhs_pf0.z, lhs_pf0.w); + lhs_shmem2[threadIdx.y/4 + 40][threadIdx.x+(threadIdx.y%4)*8] = make_float2(lhs_pf1.z, lhs_pf1.w); + lhs_shmem2[threadIdx.y/4 + 48][threadIdx.x+(threadIdx.y%4)*8] = make_float2(lhs_pf2.z, lhs_pf2.w); + lhs_shmem2[threadIdx.y/4 + 56][threadIdx.x+(threadIdx.y%4)*8] = make_float2(lhs_pf3.z, lhs_pf3.w); + + __syncthreads(); + + // Do the multiplies. + #pragma unroll + for (int koff = 0; koff < 32; koff ++) { + float2 a3 = lhs_shmem2[koff][threadIdx.x + (threadIdx.y % 4) * 8]; + float2 a4 = lhs_shmem2[koff + 32][threadIdx.x + (threadIdx.y % 4) * 8]; + + // first feature is at (threadIdx.y/4) * 8 last is at start + 8. + int start_feature = (threadIdx.y / 4) * 8; + + float2 br1 = rhs_shmem2[start_feature/2 + (koff % 4) * 32][koff/4]; + float2 br2 = rhs_shmem2[start_feature/2 + 1 + (koff % 4) * 32][koff/4]; + float2 br3 = rhs_shmem2[start_feature/2 + 2 + (koff % 4) * 32][koff/4]; + float2 br4 = rhs_shmem2[start_feature/2 + 3 + (koff % 4) * 32][koff/4]; + + add_vals(a3, a4, br1, br2, br3, br4) + } + __syncthreads(); + } // end loop over k + + + __syncthreads(); + Index horiz_base = (threadIdx.y/4)*8+base_n; + if (!CHECK_LHS_BOUNDARY && !CHECK_RHS_BOUNDARY) { + for (int i = 0; i < 8; i++) { + output(lhs_vert, horiz_base + i) = results[i].x; + output(lhs_vert + 1, horiz_base + i) = results[i].y; + output(lhs_vert + 2, horiz_base + i) = results[i].z; + output(lhs_vert + 3, horiz_base + i) = results[i].w; + } + } else if (!CHECK_RHS_BOUNDARY) { + if (lhs_vert + 3 < m_size) { + for (int i = 0; i < 8; i++) { + output(lhs_vert, horiz_base + i) = results[i].x; + output(lhs_vert + 1, horiz_base + i) = results[i].y; + output(lhs_vert + 2, horiz_base + i) = results[i].z; + output(lhs_vert + 3, horiz_base + i) = results[i].w; + } + } else if (lhs_vert + 2 < m_size) { + for (int i = 0; i < 8; i++) { + output(lhs_vert, horiz_base + i) = results[i].x; + output(lhs_vert + 1, horiz_base + i) = results[i].y; + output(lhs_vert + 2, horiz_base + i) = results[i].z; + } + } else if (lhs_vert + 1 < m_size) { + for (int i = 0; i < 8; i++) { + output(lhs_vert, horiz_base + i) = results[i].x; + output(lhs_vert + 1, horiz_base + i) = results[i].y; + } + } else if (lhs_vert < m_size) { + for (int i = 0; i < 8; i++) { + output(lhs_vert, horiz_base + i) = results[i].x; + } + } + } else if (!CHECK_LHS_BOUNDARY) { + // CHECK BOUNDARY_B + for (int i = 0; i < 8; i++) { + if (horiz_base + i < n_size) { + output(lhs_vert, horiz_base + i) = results[i].x; + output(lhs_vert + 1, horiz_base + i) = results[i].y; + output(lhs_vert + 2, horiz_base + i) = results[i].z; + output(lhs_vert + 3, horiz_base + i) = results[i].w; + } + } + } else { + // CHECK both boundaries. + for (int i = 0; i < 8; i++) { + if (horiz_base + i < n_size) { + if (lhs_vert < m_size) + output(lhs_vert, horiz_base + i) = results[i].x; + if (lhs_vert + 1 < m_size) + output(lhs_vert + 1, horiz_base + i) = results[i].y; + if (lhs_vert + 2 < m_size) + output(lhs_vert + 2, horiz_base + i) = results[i].z; + if (lhs_vert + 3 < m_size) + output(lhs_vert + 3, horiz_base + i) = results[i].w; + } + } + } +} + + +template +__global__ void +__launch_bounds__(256) +EigenFloatContractionKernel(const LhsMapper lhs, const RhsMapper rhs, + const OutputMapper output, + const Index m_size, const Index n_size, const Index k_size) { + __shared__ float2 lhs_shmem[64*32]; + __shared__ float2 rhs_shmem[128*8]; + + typedef float2 LHS_MEM[64][32]; + typedef float2 RHS_MEM[128][8]; + + typedef float2 LHS_MEM16x16[32][16]; + typedef float2 RHS_MEM16x16[64][8]; + + const Index m_block_idx = blockIdx.x; + const Index n_block_idx = blockIdx.y; + + const Index base_m = 128 * m_block_idx; + const Index base_n = 64 * n_block_idx; + + bool check_rhs = (base_n + 63) >= n_size; + bool check_lhs128 = (base_m + 127) >= m_size; + + if (!check_rhs) { + if (!check_lhs128) { + // >= 128 rows left + EigenFloatContractionKernelInternal( + lhs, rhs, output, *((LHS_MEM *) lhs_shmem), *((RHS_MEM *) rhs_shmem), m_size, n_size, k_size, base_m, base_n); + } else { + EigenFloatContractionKernelInternal( + lhs, rhs, output, *((LHS_MEM *) lhs_shmem), *((RHS_MEM *) rhs_shmem), m_size, n_size, k_size, base_m, base_n); + } + } else { + if (!check_lhs128) { + // >= 128 rows left + EigenFloatContractionKernelInternal( + lhs, rhs, output, *((LHS_MEM *) lhs_shmem), *((RHS_MEM *) rhs_shmem), m_size, n_size, k_size, base_m, base_n); + } else { + EigenFloatContractionKernelInternal( + lhs, rhs, output, *((LHS_MEM *) lhs_shmem), *((RHS_MEM *) rhs_shmem), m_size, n_size, k_size, base_m, base_n); + } + } +} + +template +__global__ void +__launch_bounds__(256) +EigenFloatContractionKernel16x16(const LhsMapper lhs, const RhsMapper rhs, + const OutputMapper output, + const Index m_size, const Index n_size, const Index k_size) { + __shared__ float2 lhs_shmem[32][16]; + __shared__ float2 rhs_shmem[64][8]; + + const Index m_block_idx = blockIdx.x; + const Index n_block_idx = blockIdx.y; + + const Index base_m = 64 * m_block_idx; + const Index base_n = 64 * n_block_idx; + + if (base_m + 63 < m_size) { + if (base_n + 63 < n_size) { + EigenFloatContractionKernelInternal16x16(lhs, rhs, output, lhs_shmem, rhs_shmem, m_size, n_size, k_size, base_m, base_n); + } else { + EigenFloatContractionKernelInternal16x16(lhs, rhs, output, lhs_shmem, rhs_shmem, m_size, n_size, k_size, base_m, base_n); + } + } else { + if (base_n + 63 < n_size) { + EigenFloatContractionKernelInternal16x16(lhs, rhs, output, lhs_shmem, rhs_shmem, m_size, n_size, k_size, base_m, base_n); + } else { + EigenFloatContractionKernelInternal16x16(lhs, rhs, output, lhs_shmem, rhs_shmem, m_size, n_size, k_size, base_m, base_n); + } + } +} + + +template +struct TensorEvaluator, GpuDevice> : + public TensorContractionEvaluatorBase, GpuDevice> > { + + typedef GpuDevice Device; + + typedef TensorEvaluator, Device> Self; + typedef TensorContractionEvaluatorBase Base; + + typedef TensorContractionOp XprType; + typedef typename internal::remove_const::type Scalar; + typedef typename XprType::Index Index; + typedef typename XprType::CoeffReturnType CoeffReturnType; + typedef typename PacketType::type PacketReturnType; + + enum { + Layout = TensorEvaluator::Layout, + }; + + // Most of the code is assuming that both input tensors are ColMajor. If the + // inputs are RowMajor, we will "cheat" by swapping the LHS and RHS: + // If we want to compute A * B = C, where A is LHS and B is RHS, the code + // will pretend B is LHS and A is RHS. + typedef typename internal::conditional< + static_cast(Layout) == static_cast(ColMajor), LeftArgType, RightArgType>::type EvalLeftArgType; + typedef typename internal::conditional< + static_cast(Layout) == static_cast(ColMajor), RightArgType, LeftArgType>::type EvalRightArgType; + + static const int LDims = + internal::array_size::Dimensions>::value; + static const int RDims = + internal::array_size::Dimensions>::value; + static const int ContractDims = internal::array_size::value; + + typedef array left_dim_mapper_t; + typedef array right_dim_mapper_t; + + typedef array contract_t; + typedef array left_nocontract_t; + typedef array right_nocontract_t; + + static const int NumDims = LDims + RDims - 2 * ContractDims; + + typedef DSizes Dimensions; + + // typedefs needed in evalTo + typedef typename internal::remove_const::type LhsScalar; + typedef typename internal::remove_const::type RhsScalar; + + typedef TensorEvaluator LeftEvaluator; + typedef TensorEvaluator RightEvaluator; + + typedef typename LeftEvaluator::Dimensions LeftDimensions; + typedef typename RightEvaluator::Dimensions RightDimensions; + + EIGEN_DEVICE_FUNC TensorEvaluator(const XprType& op, const Device& device) : + Base(op, device) {} + + // We need to redefine this method to make nvcc happy + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(Scalar* data) { + this->m_leftImpl.evalSubExprsIfNeeded(NULL); + this->m_rightImpl.evalSubExprsIfNeeded(NULL); + if (data) { + evalTo(data); + return false; + } else { + this->m_result = static_cast(this->m_device.allocate(this->dimensions().TotalSize() * sizeof(Scalar))); + evalTo(this->m_result); + return true; + } + } + + void evalTo(Scalar* buffer) const { + if (this->m_lhs_inner_dim_contiguous) { + if (this->m_rhs_inner_dim_contiguous) { + if (this->m_rhs_inner_dim_reordered) { + evalTyped(buffer); + } + else { + evalTyped(buffer); + } + } + else { + if (this->m_rhs_inner_dim_reordered) { + evalTyped(buffer); + } + else { + evalTyped(buffer); + } + } + } + else { + if (this->m_rhs_inner_dim_contiguous) { + if (this->m_rhs_inner_dim_reordered) { + evalTyped(buffer); + } + else { + evalTyped(buffer); + } + } + else { + if (this->m_rhs_inner_dim_reordered) { + evalTyped(buffer); + } + else { + evalTyped(buffer); + } + } + } + } + + template struct LaunchKernels { + static void Run(const LhsMapper& lhs, const RhsMapper& rhs, const OutputMapper& output, Index m, Index n, Index k, const GpuDevice& device) { + const Index m_blocks = (m + 63) / 64; + const Index n_blocks = (n + 63) / 64; + const dim3 num_blocks(m_blocks, n_blocks, 1); + const dim3 block_size(8, 8, 8); + LAUNCH_CUDA_KERNEL((EigenContractionKernel), num_blocks, block_size, 0, device, lhs, rhs, output, m, n, k); + } + }; + + template struct LaunchKernels { + static void Run(const LhsMapper& lhs, const RhsMapper& rhs, const OutputMapper& output, Index m, Index n, Index k, const GpuDevice& device) { + if (m < 768 || n < 768) { + const Index m_blocks = (m + 63) / 64; + const Index n_blocks = (n + 63) / 64; + const dim3 num_blocks(m_blocks, n_blocks, 1); + const dim3 block_size(16, 16, 1); + LAUNCH_CUDA_KERNEL((EigenFloatContractionKernel16x16), num_blocks, block_size, 0, device, lhs, rhs, output, m, n, k); + } else { + const Index m_blocks = (m + 127) / 128; + const Index n_blocks = (n + 63) / 64; + const dim3 num_blocks(m_blocks, n_blocks, 1); + const dim3 block_size(8, 32, 1); + LAUNCH_CUDA_KERNEL((EigenFloatContractionKernel), num_blocks, block_size, 0, device, lhs, rhs, output, m, n, k); + } + } + }; + + template + void evalTyped(Scalar* buffer) const { + // columns in left side, rows in right side + const Index k = this->m_k_size; + EIGEN_UNUSED_VARIABLE(k) + + // rows in left side + const Index m = this->m_i_size; + + // columns in right side + const Index n = this->m_j_size; + + // zero out the result buffer (which must be of size at least m * n * sizeof(Scalar) + this->m_device.memset(buffer, 0, m * n * sizeof(Scalar)); + + typedef internal::TensorContractionInputMapper LhsMapper; + + typedef internal::TensorContractionInputMapper RhsMapper; + + typedef internal::blas_data_mapper OutputMapper; + + + // initialize data mappers + LhsMapper lhs(this->m_leftImpl, this->m_left_nocontract_strides, this->m_i_strides, + this->m_left_contracting_strides, this->m_k_strides); + + RhsMapper rhs(this->m_rightImpl, this->m_right_nocontract_strides, this->m_j_strides, + this->m_right_contracting_strides, this->m_k_strides); + + OutputMapper output(buffer, m); + + setCudaSharedMemConfig(cudaSharedMemBankSizeEightByte); + LaunchKernels::Run(lhs, rhs, output, m, n, k, this->m_device); + } +}; + +} // end namespace Eigen + +#endif // EIGEN_USE_GPU and __CUDACC__ +#endif // EIGEN_CXX11_TENSOR_TENSOR_CONTRACTION_CUDA_H diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorContractionMapper.h b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorContractionMapper.h new file mode 100644 index 0000000000..9b2cb3ff6b --- /dev/null +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorContractionMapper.h @@ -0,0 +1,467 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Benoit Steiner +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CXX11_TENSOR_TENSOR_CONTRACTION_MAPPER_H +#define EIGEN_CXX11_TENSOR_TENSOR_CONTRACTION_MAPPER_H + +namespace Eigen { + +namespace internal { + +enum { + Rhs = 0, + Lhs = 1 +}; + +/* + * Implementation of the Eigen blas_data_mapper class for tensors. + */ + +template struct CoeffLoader { + enum { + DirectOffsets = false + }; + + EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE CoeffLoader(const Tensor& tensor) : m_tensor(tensor) { } + + EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE void offsetBuffer(typename Tensor::Index) { + eigen_assert(false && "unsupported"); + } + + EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE typename Tensor::Scalar coeff(typename Tensor::Index index) const { return m_tensor.coeff(index); } + + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + typename Tensor::PacketReturnType packet(typename Tensor::Index index) const + { + return m_tensor.template packet(index); + } + + + private: + const Tensor m_tensor; +}; + +template struct CoeffLoader { + enum { + DirectOffsets = true + }; + + EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE CoeffLoader(const Tensor& tensor) : m_data(tensor.data()) {} + + EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE void offsetBuffer(typename Tensor::Index offset) { + m_data += offset; + } + + EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE typename Tensor::Scalar coeff(typename Tensor::Index index) const { return loadConstant(m_data+index); } + + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + typename Tensor::PacketReturnType packet(typename Tensor::Index index) const + { + return internal::ploadt_ro(m_data + index); + } + private: + typedef typename Tensor::Scalar Scalar; + const Scalar* m_data; +}; + +template +class SimpleTensorContractionMapper { + public: + EIGEN_DEVICE_FUNC + SimpleTensorContractionMapper(const Tensor& tensor, + const nocontract_t& nocontract_strides, + const nocontract_t& ij_strides, + const contract_t& contract_strides, + const contract_t& k_strides) : + m_tensor(tensor), + m_nocontract_strides(nocontract_strides), + m_ij_strides(ij_strides), + m_contract_strides(contract_strides), + m_k_strides(k_strides) { } + + enum { + DirectOffsets = CoeffLoader::DirectOffsets + }; + + EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE void offsetBuffer(typename Tensor::Index offset) { + m_tensor.offsetBuffer(offset); + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE void prefetch(Index /*i*/) { } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Scalar operator()(Index row) const { + // column major assumption + return operator()(row, 0); + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Scalar operator()(Index row, Index col) const { + return m_tensor.coeff(computeIndex(row, col)); + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Index computeIndex(Index row, Index col) const { + const bool left = (side == Lhs); + Index nocontract_val = left ? row : col; + Index linidx = 0; + for (int i = static_cast(array_size::value) - 1; i > 0; i--) { + const Index idx = nocontract_val / m_ij_strides[i]; + linidx += idx * m_nocontract_strides[i]; + nocontract_val -= idx * m_ij_strides[i]; + } + if (array_size::value > array_size::value) { + if (side == Lhs && inner_dim_contiguous) { + eigen_assert(m_nocontract_strides[0] == 1); + linidx += nocontract_val; + } else { + linidx += nocontract_val * m_nocontract_strides[0]; + } + } + + Index contract_val = left ? col : row; + if(array_size::value > 0) { + for (int i = static_cast(array_size::value) - 1; i > 0; i--) { + const Index idx = contract_val / m_k_strides[i]; + linidx += idx * m_contract_strides[i]; + contract_val -= idx * m_k_strides[i]; + } + + if (side == Rhs && inner_dim_contiguous) { + eigen_assert(m_contract_strides[0] == 1); + linidx += contract_val; + } else { + linidx += contract_val * m_contract_strides[0]; + } + } + + return linidx; + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE IndexPair computeIndexPair(Index row, Index col, const Index distance) const { + const bool left = (side == Lhs); + Index nocontract_val[2] = {left ? row : col, left ? row + distance : col}; + Index linidx[2] = {0, 0}; + if (array_size::value > array_size::value) { + for (int i = static_cast(array_size::value) - 1; i > 0; i--) { + const Index idx0 = nocontract_val[0] / m_ij_strides[i]; + const Index idx1 = nocontract_val[1] / m_ij_strides[i]; + linidx[0] += idx0 * m_nocontract_strides[i]; + linidx[1] += idx1 * m_nocontract_strides[i]; + nocontract_val[0] -= idx0 * m_ij_strides[i]; + nocontract_val[1] -= idx1 * m_ij_strides[i]; + } + if (side == Lhs && inner_dim_contiguous) { + eigen_assert(m_nocontract_strides[0] == 1); + linidx[0] += nocontract_val[0]; + linidx[1] += nocontract_val[1]; + } else { + linidx[0] += nocontract_val[0] * m_nocontract_strides[0]; + linidx[1] += nocontract_val[1] * m_nocontract_strides[0]; + } + } + + Index contract_val[2] = {left ? col : row, left ? col : row + distance}; + if (array_size::value> 0) { + for (int i = static_cast(array_size::value) - 1; i > 0; i--) { + const Index idx0 = contract_val[0] / m_k_strides[i]; + const Index idx1 = contract_val[1] / m_k_strides[i]; + linidx[0] += idx0 * m_contract_strides[i]; + linidx[1] += idx1 * m_contract_strides[i]; + contract_val[0] -= idx0 * m_k_strides[i]; + contract_val[1] -= idx1 * m_k_strides[i]; + } + + if (side == Rhs && inner_dim_contiguous) { + eigen_assert(m_contract_strides[0] == 1); + linidx[0] += contract_val[0]; + linidx[1] += contract_val[1]; + } else { + linidx[0] += contract_val[0] * m_contract_strides[0]; + linidx[1] += contract_val[1] * m_contract_strides[0]; + } + } + return IndexPair(linidx[0], linidx[1]); + } + + EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE Index firstAligned(Index size) const { + // Only claim alignment when we can compute the actual stride (ie when we're + // dealing with the lhs with inner_dim_contiguous. This is because the + // matrix-vector product relies on the stride when dealing with aligned inputs. + return (Alignment == Aligned) && (side == Lhs) && inner_dim_contiguous ? 0 : size; + } + EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE Index stride() const { + return ((side == Lhs) && inner_dim_contiguous && array_size::value > 0) ? m_contract_strides[0] : 1; + } + + protected: + CoeffLoader m_tensor; + const nocontract_t m_nocontract_strides; + const nocontract_t m_ij_strides; + const contract_t m_contract_strides; + const contract_t m_k_strides; +}; + + +template +class BaseTensorContractionMapper : public SimpleTensorContractionMapper +{ + public: + typedef SimpleTensorContractionMapper ParentMapper; + + EIGEN_DEVICE_FUNC + BaseTensorContractionMapper(const Tensor& tensor, + const nocontract_t& nocontract_strides, + const nocontract_t& ij_strides, + const contract_t& contract_strides, + const contract_t& k_strides) : + ParentMapper(tensor, nocontract_strides, ij_strides, contract_strides, k_strides) { } + + typedef typename Tensor::PacketReturnType Packet; + typedef typename unpacket_traits::half HalfPacket; + + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Packet loadPacket(Index i, Index j) const { + // whole method makes column major assumption + + // don't need to add offsets for now (because operator handles that) + // current code assumes packet size must be a multiple of 2 + EIGEN_STATIC_ASSERT(packet_size % 2 == 0, YOU_MADE_A_PROGRAMMING_MISTAKE); + + if (Tensor::PacketAccess && inner_dim_contiguous && !inner_dim_reordered) { + const Index index = this->computeIndex(i, j); + eigen_assert(this->computeIndex(i+packet_size-1, j) == index + packet_size-1); + return this->m_tensor.template packet(index); + } + + const IndexPair indexPair = this->computeIndexPair(i, j, packet_size - 1); + const Index first = indexPair.first; + const Index last = indexPair.second; + + // We can always do optimized packet reads from left hand side right now, because + // the vertical matrix dimension on the left hand side is never contracting. + // On the right hand side we need to check if the contracting dimensions may have + // been shuffled first. + if (Tensor::PacketAccess && + (side == Lhs || internal::array_size::value <= 1 || !inner_dim_reordered) && + (last - first) == (packet_size - 1)) { + + return this->m_tensor.template packet(first); + } + + EIGEN_ALIGN_MAX Scalar data[packet_size]; + + data[0] = this->m_tensor.coeff(first); + for (Index k = 1; k < packet_size - 1; k += 2) { + const IndexPair internal_pair = this->computeIndexPair(i + k, j, 1); + data[k] = this->m_tensor.coeff(internal_pair.first); + data[k + 1] = this->m_tensor.coeff(internal_pair.second); + } + data[packet_size - 1] = this->m_tensor.coeff(last); + + return pload(data); + } + + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE HalfPacket loadHalfPacket(Index i, Index j) const { + // whole method makes column major assumption + + // don't need to add offsets for now (because operator handles that) + const Index half_packet_size = unpacket_traits::size; + if (half_packet_size == packet_size) { + return loadPacket(i, j); + } + EIGEN_ALIGN_MAX Scalar data[half_packet_size]; + for (Index k = 0; k < half_packet_size; k++) { + data[k] = operator()(i + k, j); + } + return pload(data); + } +}; + + +template +class BaseTensorContractionMapper : public SimpleTensorContractionMapper +{ + public: + typedef SimpleTensorContractionMapper ParentMapper; + + EIGEN_DEVICE_FUNC + BaseTensorContractionMapper(const Tensor& tensor, + const nocontract_t& nocontract_strides, + const nocontract_t& ij_strides, + const contract_t& contract_strides, + const contract_t& k_strides) : + ParentMapper(tensor, nocontract_strides, ij_strides, contract_strides, k_strides) { } + + typedef typename Tensor::PacketReturnType Packet; + template EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Packet loadPacket(Index i, Index j) const { + EIGEN_ALIGN_MAX Scalar data[1]; + data[0] = this->m_tensor.coeff(this->computeIndex(i, j)); + return pload(data); + } + template EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Packet loadHalfPacket(Index i, Index j) const { + return loadPacket(i, j); + } +}; + + +template +class TensorContractionSubMapper { + public: + typedef typename Tensor::PacketReturnType Packet; + typedef typename unpacket_traits::half HalfPacket; + + typedef BaseTensorContractionMapper ParentMapper; + typedef TensorContractionSubMapper Self; + typedef Self LinearMapper; + + enum { + // We can use direct offsets iff the parent mapper supports then and we can compute the strides. + // TODO: we should also enable direct offsets for the Rhs case. + UseDirectOffsets = ParentMapper::DirectOffsets && (side == Lhs) && inner_dim_contiguous && (array_size::value > 0) + }; + + EIGEN_DEVICE_FUNC TensorContractionSubMapper(const ParentMapper& base_mapper, Index vert_offset, Index horiz_offset) + : m_base_mapper(base_mapper), m_vert_offset(vert_offset), m_horiz_offset(horiz_offset) { + // Bake the offsets into the buffer used by the base mapper whenever possible. This avoids the need to recompute + // this offset every time we attempt to access a coefficient. + if (UseDirectOffsets) { + Index stride = m_base_mapper.stride(); + m_base_mapper.offsetBuffer(vert_offset + horiz_offset * stride); + } + } + + EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE Scalar operator()(Index i) const { + if (UseDirectOffsets) { + return m_base_mapper(i, 0); + } + return m_base_mapper(i + m_vert_offset, m_horiz_offset); + } + EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE Scalar operator()(Index i, Index j) const { + if (UseDirectOffsets) { + return m_base_mapper(i, j); + } + return m_base_mapper(i + m_vert_offset, j + m_horiz_offset); + } + + EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE Packet loadPacket(Index i) const { + if (UseDirectOffsets) { + return m_base_mapper.template loadPacket(i, 0); + } + return m_base_mapper.template loadPacket(i + m_vert_offset, m_horiz_offset); + } + EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE Packet loadPacket(Index i, Index j) const { + if (UseDirectOffsets) { + return m_base_mapper.template loadPacket(i, j); + } + return m_base_mapper.template loadPacket(i + m_vert_offset, j + m_horiz_offset); + } + + EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE HalfPacket loadHalfPacket(Index i) const { + if (UseDirectOffsets) { + return m_base_mapper.template loadHalfPacket(i, 0); + } + return m_base_mapper.template loadHalfPacket(i + m_vert_offset, m_horiz_offset); + } + + EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE void storePacket(Index i, Packet p) const { + if (UseDirectOffsets) { + m_base_mapper.storePacket(i, 0, p); + } + m_base_mapper.storePacket(i + m_vert_offset, m_horiz_offset, p); + } + + EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE LinearMapper getLinearMapper(Index i, Index j) const { + if (UseDirectOffsets) { + return LinearMapper(m_base_mapper, i, j); + } + return LinearMapper(m_base_mapper, i + m_vert_offset, j + m_horiz_offset); + } + + template + EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE PacketT load(Index i) const { + EIGEN_STATIC_ASSERT((internal::is_same::value), YOU_MADE_A_PROGRAMMING_MISTAKE); + const int ActualAlignment = (AlignmentType == Aligned) && (Alignment == Aligned) ? Aligned : Unaligned; + if (UseDirectOffsets) { + return m_base_mapper.template loadPacket(i, 0); + } + return m_base_mapper.template loadPacket(i + m_vert_offset, m_horiz_offset); + } + + template + EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool aligned(Index) const { + return false; + } + + private: + ParentMapper m_base_mapper; + const Index m_vert_offset; + const Index m_horiz_offset; +}; + + +template +class TensorContractionInputMapper + : public BaseTensorContractionMapper { + + public: + typedef Scalar_ Scalar; + typedef BaseTensorContractionMapper Base; + typedef TensorContractionSubMapper SubMapper; + typedef SubMapper VectorMapper; + + EIGEN_DEVICE_FUNC TensorContractionInputMapper(const Tensor& tensor, + const nocontract_t& nocontract_strides, + const nocontract_t& ij_strides, + const contract_t& contract_strides, + const contract_t& k_strides) + : Base(tensor, nocontract_strides, ij_strides, contract_strides, k_strides) { } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE SubMapper getSubMapper(Index i, Index j) const { + return SubMapper(*this, i, j); + } + + EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE VectorMapper getVectorMapper(Index i, Index j) const { + return VectorMapper(*this, i, j); + } +}; + + + +} // end namespace internal +} // end namespace Eigen + +#endif // EIGEN_CXX11_TENSOR_TENSOR_CONTRACTION_MAPPER_H diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorContractionThreadPool.h b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorContractionThreadPool.h new file mode 100644 index 0000000000..ee16cde9b1 --- /dev/null +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorContractionThreadPool.h @@ -0,0 +1,1052 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Benoit Steiner +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CXX11_TENSOR_TENSOR_CONTRACTION_THREAD_POOL_H +#define EIGEN_CXX11_TENSOR_TENSOR_CONTRACTION_THREAD_POOL_H + +// evaluator for thread pool device +#ifdef EIGEN_USE_THREADS + +namespace Eigen { + +#ifdef EIGEN_USE_SIMPLE_THREAD_POOL +namespace internal { + +template +struct packLhsArg { + LhsScalar* blockA; + const LhsMapper& lhs; + const Index m_start; + const Index k_start; + const Index mc; + const Index kc; +}; + +template +struct packRhsAndKernelArg { + const MaxSizeVector* blockAs; + RhsScalar* blockB; + const RhsMapper& rhs; + OutputMapper& output; + const Index m; + const Index k; + const Index n; + const Index mc; + const Index kc; + const Index nc; + const Index num_threads; + const Index num_blockAs; + const Index max_m; + const Index k_block_idx; + const Index m_block_idx; + const Index n_block_idx; + const Index m_blocks; + const Index n_blocks; + MaxSizeVector* kernel_notifications; + const MaxSizeVector* lhs_notifications; + const bool need_to_pack; +}; + +} // end namespace internal +#endif // EIGEN_USE_SIMPLE_THREAD_POOL + +template +struct TensorEvaluator, ThreadPoolDevice> : + public TensorContractionEvaluatorBase, ThreadPoolDevice> > { + + typedef ThreadPoolDevice Device; + + typedef TensorEvaluator, Device> Self; + typedef TensorContractionEvaluatorBase Base; + + typedef TensorContractionOp XprType; + typedef typename internal::remove_const::type Scalar; + typedef typename XprType::Index Index; + typedef typename XprType::CoeffReturnType CoeffReturnType; + typedef typename PacketType::type PacketReturnType; + + enum { + Layout = TensorEvaluator::Layout, + }; + + // Most of the code is assuming that both input tensors are ColMajor. If the + // inputs are RowMajor, we will "cheat" by swapping the LHS and RHS: + // If we want to compute A * B = C, where A is LHS and B is RHS, the code + // will pretend B is LHS and A is RHS. + typedef typename internal::conditional< + static_cast(Layout) == static_cast(ColMajor), LeftArgType, RightArgType>::type EvalLeftArgType; + typedef typename internal::conditional< + static_cast(Layout) == static_cast(ColMajor), RightArgType, LeftArgType>::type EvalRightArgType; + + static const int LDims = + internal::array_size::Dimensions>::value; + static const int RDims = + internal::array_size::Dimensions>::value; + static const int ContractDims = internal::array_size::value; + + typedef array left_dim_mapper_t; + typedef array right_dim_mapper_t; + + typedef array contract_t; + typedef array left_nocontract_t; + typedef array right_nocontract_t; + + static const int NumDims = LDims + RDims - 2 * ContractDims; + + typedef DSizes Dimensions; + + // typedefs needed in evalTo + typedef typename internal::remove_const::type LhsScalar; + typedef typename internal::remove_const::type RhsScalar; + typedef typename internal::gebp_traits Traits; + + typedef TensorEvaluator LeftEvaluator; + typedef TensorEvaluator RightEvaluator; + + TensorEvaluator(const XprType& op, const Device& device) : + Base(op, device) {} + +#ifndef EIGEN_USE_SIMPLE_THREAD_POOL + template + void evalProduct(Scalar* buffer) const { + typedef + typename internal::remove_const::type + LhsScalar; + typedef + typename internal::remove_const::type + RhsScalar; + typedef typename internal::gebp_traits Traits; + typedef TensorEvaluator LeftEvaluator; + typedef TensorEvaluator RightEvaluator; + typedef internal::TensorContractionInputMapper< + LhsScalar, Index, internal::Lhs, LeftEvaluator, left_nocontract_t, + contract_t, internal::packet_traits::size, + lhs_inner_dim_contiguous, false, Unaligned> + LhsMapper; + typedef internal::TensorContractionInputMapper< + RhsScalar, Index, internal::Rhs, RightEvaluator, right_nocontract_t, + contract_t, internal::packet_traits::size, + rhs_inner_dim_contiguous, rhs_inner_dim_reordered, Unaligned> + RhsMapper; + typedef internal::blas_data_mapper OutputMapper; + typedef internal::gemm_pack_lhs + LhsPacker; + typedef internal::gemm_pack_rhs< + RhsScalar, Index, typename RhsMapper::SubMapper, Traits::nr, ColMajor> + RhsPacker; + typedef internal::gebp_kernel + GebpKernel; + + const Index m = this->m_i_size; + const Index n = this->m_j_size; + const Index k = this->m_k_size; + if (m == 0 || n == 0 || k == 0) return; + + // Compute a set of algorithm parameters: + // - kernel block sizes (bm, bn, bk) + // - task grain sizes (number of kernels executed per task: gm, gn) + // - number of threads + // - sharding by row/column + // - parallel packing or first lhs then rhs + // and some derived parameters: + // - number of tasks (nm, nn, nk) + // - number of kernels (nm0, nn0) + // Unfortunately, all these parameters are tightly interdependent. + // So in some cases we first compute approximate values, then compute other + // values based on these approximations and then refine the approximations. + + // There are lots of heuristics here. There is some reasoning behind them, + // but ultimately they are just tuned on contraction benchmarks for + // different input configurations, thread counts and instruction sets. + // So feel free to question any of them. + + // Compute whether we want to shard by row or by column. + // This is a first approximation, it will be refined later. Since we don't + // know number of threads yet we use 2, because what's we are most + // interested in at this point is whether it makes sense to use + // parallelization at all or not. + bool shard_by_col = shardByCol(m, n, 2); + + // First approximation of kernel blocking sizes. + // Again, we don't know number of threads yet, so we use 2. + Index bm, bn, bk; + if (shard_by_col) { + internal::TensorContractionBlocking + blocking(k, m, n, 2); + bm = blocking.mc(); + bn = blocking.nc(); + bk = blocking.kc(); + } else { + internal::TensorContractionBlocking + blocking(k, m, n, 2); + bm = blocking.mc(); + bn = blocking.nc(); + bk = blocking.kc(); + } + + // Compute optimal number of threads. + // Note: we use bk instead of k here because we are interested in amount of + // _parallelizable_ computations, and computations are not parallelizable + // across k dimension. + const TensorOpCost cost = + contractionCost(m, n, bm, bn, bk, shard_by_col, false); + int num_threads = TensorCostModel::numThreads( + static_cast(n) * m, cost, this->m_device.numThreads()); + + // TODO(dvyukov): this is a stop-gap to prevent regressions while the cost + // model is not tuned. Remove this when the cost model is tuned. + if (n == 1) num_threads = 1; + + if (num_threads == 1) { + // The single-threaded algorithm should be faster in this case. + if (n == 1) + this->template evalGemv(buffer); + else + this->template evalGemm(buffer); + return; + } + + // Now that we know number of threads, recalculate sharding and blocking. + shard_by_col = shardByCol(m, n, num_threads); + if (shard_by_col) { + internal::TensorContractionBlocking + blocking(k, m, n, num_threads); + bm = blocking.mc(); + bn = blocking.nc(); + bk = blocking.kc(); + } else { + internal::TensorContractionBlocking + blocking(k, m, n, num_threads); + bm = blocking.mc(); + bn = blocking.nc(); + bk = blocking.kc(); + } + + // Number of kernels for each dimension. + Index nm0 = divup(m, bm); + Index nn0 = divup(n, bn); + Index nk = divup(k, bk); + + // Calculate task grain size (number of kernels executed per task). + // This task size coarsening serves two purposes: + // 1. It reduces per-task overheads including synchronization overheads. + // 2. It allows to use caches better (reuse the same packed rhs in several + // consecutive kernels). + Index gm = 1; + Index gn = 1; + // If we are sharding by column, then we prefer to reduce rows first. + if (shard_by_col) { + gm = coarsenM(m, n, bm, bn, bk, gn, num_threads, shard_by_col); + gn = coarsenN(m, n, bm, bn, bk, gm, num_threads, shard_by_col); + } else { + gn = coarsenN(m, n, bm, bn, bk, gm, num_threads, shard_by_col); + gm = coarsenM(m, n, bm, bn, bk, gn, num_threads, shard_by_col); + } + // Number of tasks in each dimension. + Index nm = divup(nm0, gm); + Index nn = divup(nn0, gn); + + // Last by not least, decide whether we want to issue both lhs and rhs + // packing in parallel; or issue lhs packing first, and then issue rhs + // packing when lhs packing completes (for !shard_by_col lhs and rhs are + // swapped). Parallel packing allows more parallelism (for both packing and + // kernels), while sequential packing provides better locality (once + // a thread finishes rhs packing it proceed to kernels with that rhs). + // First, we are interested in parallel packing if there are few tasks. + bool parallel_pack = num_threads >= nm * nn; + // Also do parallel packing if all data fits into L2$. + if (m * bk * Index(sizeof(LhsScalar)) + n * bk * Index(sizeof(RhsScalar)) <= + l2CacheSize() * num_threads) + parallel_pack = true; + // But don't do it if we will use each rhs only once. Locality seems to be + // more important in this case. + if ((shard_by_col ? nm : nn) == 1) parallel_pack = false; + + LhsMapper lhs(this->m_leftImpl, this->m_left_nocontract_strides, + this->m_i_strides, this->m_left_contracting_strides, + this->m_k_strides); + + RhsMapper rhs(this->m_rightImpl, this->m_right_nocontract_strides, + this->m_j_strides, this->m_right_contracting_strides, + this->m_k_strides); + + Context(this->m_device, num_threads, lhs, rhs, buffer, m, n, + k, bm, bn, bk, nm, nn, nk, gm, gn, nm0, nn0, + shard_by_col, parallel_pack) + .run(); + } + + // Context coordinates a single parallel gemm operation. + template + class Context { + public: + Context(const Device& device, int num_threads, LhsMapper& lhs, + RhsMapper& rhs, Scalar* buffer, Index tm, Index tn, Index tk, Index bm, + Index bn, Index bk, Index nm, Index nn, Index nk, Index gm, + Index gn, Index nm0, Index nn0, bool shard_by_col, + bool parallel_pack) + : device_(device), + lhs_(lhs), + rhs_(rhs), + buffer_(buffer), + output_(buffer, tm), + num_threads_(num_threads), + shard_by_col_(shard_by_col), + parallel_pack_(parallel_pack), + m_(tm), + n_(tn), + k_(tk), + bm_(bm), + bn_(bn), + bk_(bk), + nm_(nm), + nn_(nn), + nk_(nk), + gm_(gm), + gn_(gn), + nm0_(nm0), + nn0_(nn0) + { + for (Index x = 0; x < P; x++) { + // Normal number of notifications for k slice switch is + // nm_ + nn_ + nm_ * nn_. However, first P - 1 slices will receive only + // nm_ + nn_ notifications, because they will not receive notifications + // from preceeding kernels. + state_switch_[x] = + x == 0 + ? 1 + : (parallel_pack_ ? nn_ + nm_ : (shard_by_col_ ? nn_ : nm_)) + + (x == P - 1 ? nm_ * nn_ : 0); + state_packing_ready_[x] = + parallel_pack_ ? 0 : (shard_by_col_ ? nm_ : nn_); + state_kernel_[x] = new std::atomic*[nm_]; + for (Index m = 0; m < nm_; m++) { + state_kernel_[x][m] = new std::atomic[nn_]; + // Kernels generally receive 3 notifications (previous kernel + 2 + // packing), but the first slice won't get notifications from previous + // kernels. + for (Index n = 0; n < nn_; n++) + state_kernel_[x][m][n].store( + (x == 0 ? 0 : 1) + (parallel_pack_ ? 2 : 1), + std::memory_order_relaxed); + } + } + + // Allocate memory for packed rhs/lhs matrices. + size_t align = numext::maxi(EIGEN_MAX_ALIGN_BYTES, 1); + size_t lhs_size = + divup(bm_ * bk_ * sizeof(LhsScalar), align) * align; + size_t rhs_size = + divup(bn_ * bk_ * sizeof(RhsScalar), align) * align; + packed_mem_ = static_cast(internal::aligned_malloc( + (nm0_ * lhs_size + nn0_ * rhs_size) * std::min(nk_, P - 1))); + char* mem = static_cast(packed_mem_); + for (Index x = 0; x < numext::mini(nk_, P - 1); x++) { + packed_lhs_[x].resize(nm0_); + for (Index m = 0; m < nm0_; m++) { + packed_lhs_[x][m] = reinterpret_cast(mem); + mem += lhs_size; + } + packed_rhs_[x].resize(nn0_); + for (Index n = 0; n < nn0_; n++) { + packed_rhs_[x][n] = reinterpret_cast(mem); + mem += rhs_size; + } + } + } + + ~Context() { + for (Index x = 0; x < P; x++) { + for (Index m = 0; m < nm_; m++) delete[] state_kernel_[x][m]; + delete[] state_kernel_[x]; + } + internal::aligned_free(packed_mem_); + } + + void run() { + // Kick off packing of the first slice. + signal_switch(0, 1); + // Wait for overall completion. + // TODO(dvyukov): this wait can lead to deadlock. + // If nthreads contractions are concurrently submitted from worker + // threads, this wait will block all worker threads and the system will + // deadlock. + done_.Wait(); + } + + private: + Notification done_; + const Device& device_; + LhsMapper& lhs_; + RhsMapper& rhs_; + Scalar* const buffer_; + OutputMapper output_; + const int num_threads_; + const bool shard_by_col_; + const bool parallel_pack_; + // Matrix sizes. + const Index m_; + const Index n_; + const Index k_; + // Block sizes. + const Index bm_; + const Index bn_; + const Index bk_; + // Number of tasks. + const Index nm_; + const Index nn_; + const Index nk_; + // Task grain sizes (number of kernels executed per task). + const Index gm_; + const Index gn_; + // Number of blocks (this is different from ni_/nn_ because of task size + // coarsening). + const Index nm0_; + const Index nn0_; + + // Parallelization strategy. + // + // Blocks related to the same k block can run in parallel because they write + // to different output blocks. So we parallelize within k slices, this + // gives us parallelism level of m x n. Before we can start any kernels + // related to k-th slice, we need to issue m lhs packing tasks and n rhs + // packing tasks. + // + // However, there is a bottleneck when we are finishing kernels for k-th + // slice (at the very end there is only 1 runnable kernel). To mitigate this + // bottleneck we allow kernels from k-th and k+1-th slices to run in + // parallel. Note that (m, n, k) and (m, n, k+1) kernels write to the same + // output block, so they must not run in parallel. + // + // This gives us the following dependency graph. + // On each k slice we have m x n kernel tasks, m lhs paking tasks and n rhs + // packing tasks. + // Kernel (m, n, k) can start when: + // - kernel (m, n, k-1) has finished + // - lhs packing (m, k) has finished + // - rhs packing (n, k) has finished + // Lhs/rhs packing can start when: + // - all k-1 packing has finished (artificially imposed to limit amount of + // parallel packing) + // + // On top of that we limit runnable tasks to two consecutive k slices. + // This is done to limit amount of memory we need for packed lhs/rhs + // (for each k slice we need m*bk + n*bk memory in packed_lhs_/packed_rhs_). + // + // state_switch_ tracks when we are ready to switch to the next k slice. + // state_kernel_[m][n] tracks when we are ready to kick off kernel (m, n). + // These variable are rolling over 3 consecutive k slices: first two we are + // actively executing + one to track completion of kernels in the second + // slice. + static const Index P = 3; + void* packed_mem_; + std::vector packed_lhs_[P - 1]; + std::vector packed_rhs_[P - 1]; + std::atomic** state_kernel_[P]; + // state_switch_ is frequently modified by worker threads, while other + // fields are read-only after constructor. Let's move it to a separate cache + // line to reduce cache-coherency traffic. + char pad_[128]; + std::atomic state_packing_ready_[P]; + std::atomic state_switch_[P]; + + void pack_lhs(Index m, Index k) { + const Index mend = m * gm_ + gm(m); + for (Index m1 = m * gm_; m1 < mend; m1++) + LhsPacker()(packed_lhs_[k % (P - 1)][m1], + lhs_.getSubMapper(m1 * bm_, k * bk_), bk(k), bm(m1)); + + if (!parallel_pack_ && shard_by_col_) { + signal_packing(k); + } else { + signal_switch(k + 1); + for (Index n = nn_ - 1; n >= 0; n--) signal_kernel(m, n, k, n == 0); + } + } + + void pack_rhs(Index n, Index k) { + const Index nend = n * gn_ + gn(n); + for (Index n1 = n * gn_; n1 < nend; n1++) { + if (k == 0) { + // Zero the output memory in parallel. + // On 10000x2x10000 mm zeroing can easily take half of time. + // Zero (bn x m) row. Safe to do here because all kernels that will + // write to this memory depend on completion of this task. + // Note: don't call device_.memset() here. device_.memset() blocks on + // thread pool worker thread, which can lead to underutilization and + // deadlocks. + memset(buffer_ + n1 * bn_ * m_, 0, bn(n1) * m_ * sizeof(Scalar)); + } + RhsPacker()(packed_rhs_[k % (P - 1)][n1], + rhs_.getSubMapper(k * bk_, n1 * bn_), bk(k), bn(n1)); + } + + if (parallel_pack_ || shard_by_col_) { + signal_switch(k + 1); + for (Index m = nm_ - 1; m >= 0; m--) signal_kernel(m, n, k, m == 0); + } else { + signal_packing(k); + } + } + + void kernel(Index m, Index n, Index k) { + // Note: order of iteration matters here. Iteration over m is innermost + // because we want to reuse the same packed rhs in consequetive tasks + // (rhs fits into L2$ while lhs only into L3$). + const Index nend = n * gn_ + gn(n); + const Index mend = m * gm_ + gm(m); + if (shard_by_col_) { + for (Index n1 = n * gn_; n1 < nend; n1++) { + for (Index m1 = m * gm_; m1 < mend; m1++) + GebpKernel()(output_.getSubMapper(m1 * bm_, n1 * bn_), + packed_lhs_[k % (P - 1)][m1], + packed_rhs_[k % (P - 1)][n1], bm(m1), bk(k), bn(n1), + Scalar(1), -1, -1, 0, 0); + } + } else { + for (Index m1 = m * gm_; m1 < mend; m1++) + for (Index n1 = n * gn_; n1 < nend; n1++) { + GebpKernel()(output_.getSubMapper(m1 * bm_, n1 * bn_), + packed_lhs_[k % (P - 1)][m1], + packed_rhs_[k % (P - 1)][n1], bm(m1), bk(k), bn(n1), + Scalar(1), -1, -1, 0, 0); + } + } + signal_kernel(m, n, k + 1, false); + signal_switch(k + 2); + } + + void signal_packing(Index k) { + eigen_assert(!parallel_pack_); + Index s = state_packing_ready_[k % P].fetch_sub(1); + eigen_assert(s > 0); + if (s != 1) return; + state_packing_ready_[k % P] = shard_by_col_ ? nm_ : nn_; + enqueue_packing(k, shard_by_col_); + } + + void signal_kernel(Index m, Index n, Index k, bool sync) { + std::atomic* state = &state_kernel_[k % P][m][n]; + Index s = state->load(); + eigen_assert(s > 0); + if (s != 1 && state->fetch_sub(1) != 1) return; + state->store(parallel_pack_ ? 3 : 2, std::memory_order_relaxed); + if (sync) + kernel(m, n, k); + else + device_.enqueueNoNotification([=]() { kernel(m, n, k); }); + } + + void signal_switch(Index k, Index v = 1) { + Index s = state_switch_[k % P].fetch_sub(v); + eigen_assert(s >= v); + if (s != v) return; + + // Ready to switch to the next k slice. + // Reset counter for the next iteration. + state_switch_[k % P] = + (parallel_pack_ ? nm_ + nn_ : (shard_by_col_ ? nn_ : nm_)) + + nm_ * nn_; + if (k < nk_) { + // Issue lhs/rhs packing. Their completion will in turn kick off + // kernels. + if (parallel_pack_) { + enqueue_packing(k, !shard_by_col_); + enqueue_packing(k, shard_by_col_); + } else if (shard_by_col_) { + enqueue_packing(k, false); + } else { + enqueue_packing(k, true); + } + + // Termination handling. + // Because kernel completion signals k + 2 switch, we need to finish nk + // + 2 slices without issuing any tasks on nk + 1 slice. So here we + // pretend that all nk + 1 packing tasks just finish instantly; so that + // nk + 2 switch only waits for completion of nk kernels. + } else if (k == nk_) { + signal_switch(k + 1, + parallel_pack_ ? nm_ + nn_ : (shard_by_col_ ? nn_ : nm_)); + } else { + done_.Notify(); + } + } + + // Enqueue all rhs/lhs packing for k-th slice. + void enqueue_packing(Index k, bool rhs) { + enqueue_packing_helper(0, rhs ? nn_ : nm_, k, rhs); + } + + void enqueue_packing_helper(Index start, Index end, Index k, bool rhs) { + if (end - start == 1) { + if (rhs) + pack_rhs(start, k); + else + pack_lhs(start, k); + } else { + Index mid = (start + end) / 2; + device_.enqueueNoNotification( + [=]() { enqueue_packing_helper(mid, end, k, rhs); }); + device_.enqueueNoNotification( + [=]() { enqueue_packing_helper(start, mid, k, rhs); }); + } + } + + // Block sizes with accounting for potentially incomplete last block. + Index bm(Index m) const { return m + 1 < nm0_ ? bm_ : m_ + bm_ - bm_ * nm0_; } + Index bn(Index n) const { return n + 1 < nn0_ ? bn_ : n_ + bn_ - bn_ * nn0_; } + Index bk(Index k) const { return k + 1 < nk_ ? bk_ : k_ + bk_ - bk_ * nk_; } + // Task grain sizes accounting for potentially incomplete last task. + Index gm(Index m) const { return m + 1 < nm_ ? gm_ : nm0_ + gm_ - gm_ * nm_; } + Index gn(Index n) const { return n + 1 < nn_ ? gn_ : nn0_ + gn_ - gn_ * nn_; } + + Context(const Context&) = delete; + void operator=(const Context&) = delete; + }; + + // Decide whether we want to shard m x n contraction by columns or by rows. + static bool shardByCol(Index m, Index n, Index num_threads) { + // Note: we are comparing both n and m against Traits::nr, it is not + // a mistake. We are trying to figure out how both n and m will fit into + // the main sharding dimension. + + // Sharding by column is the default + // ... unless there is enough data for vectorization over rows + if (m / num_threads >= Traits::nr && + // and not enough data for vectorization over columns + (n / num_threads < Traits::nr || + // ... or barely enough data for vectorization over columns, + // but it is not evenly dividable across threads + (n / num_threads < 4 * Traits::nr && + (n % (num_threads * Traits::nr)) != 0 && + // ... and it is evenly dividable across threads for rows + ((m % (num_threads * Traits::nr)) == 0 || + // .. or it is not evenly dividable for both dimensions but + // there is much more data over rows so that corner effects are + // mitigated. + (m / n >= 6))))) + return false; + // Wait, or if matrices are just substantially prolonged over the other + // dimension. + if (n / num_threads < 16 * Traits::nr && m > n * 32) return false; + return true; + } + + Index coarsenM(Index m, Index n, Index bm, Index bn, Index bk, Index gn, + int num_threads, bool shard_by_col) const { + Index gm = 1; + Index gm1 = 1; + Index nm0 = divup(m, bm); + Index nm1 = nm0; + for (;;) { + // Find the next candidate for m grain size. It needs to result in + // different number of blocks. E.g. if we have 10 kernels, we want to try + // 5 and 10, but not 6, 7, 8 and 9. + while (gm1 <= nm0 && nm1 == divup(nm0, gm1)) gm1++; + if (gm1 > nm0) break; + // Check the candidate. + int res = checkGrain(m, n, bm, bn, bk, gm1, gn, gm, gn, num_threads, + shard_by_col); + if (res < 0) break; + nm1 = divup(nm0, gm1); + if (res == 0) continue; + // Commit new grain size. + gm = gm1; + } + return gm; + } + + Index coarsenN(Index m, Index n, Index bm, Index bn, Index bk, Index gm, + int num_threads, bool shard_by_col) const { + Index gn = 1; + Index gn1 = 1; + Index nn0 = divup(n, bn); + Index nn1 = nn0; + for (;;) { + while (gn1 <= nn0 && nn1 == divup(nn0, gn1)) gn1++; + if (gn1 > nn0) break; + int res = checkGrain(m, n, bm, bn, bk, gm, gn1, gm, gn, num_threads, + shard_by_col); + if (res < 0) break; + nn1 = divup(nn0, gn1); + if (res == 0) continue; + gn = gn1; + } + return gn; + } + + // checkGrain checks whether grain (gm, gn) is suitable and is better than + // (oldgm, oldgn). + int checkGrain(Index m, Index n, Index bm, Index bn, Index bk, Index gm, + Index gn, Index oldgm, Index oldgn, int num_threads, + bool shard_by_col) const { + const TensorOpCost cost = + contractionCost(bm * gm, bn * gn, bm, bn, bk, shard_by_col, true); + double taskSize = TensorCostModel::taskSize( + static_cast(bm) * gm * bn * gn, cost); + // If the task is too small, then we agree on it regardless of anything + // else. Otherwise synchronization overheads will dominate. + if (taskSize < 1) return 1; + // If it is too large, then we reject it and all larger tasks. + if (taskSize > 2) return -1; + // Now we are in presumably good task size range. + // The main deciding factor here is parallelism. Consider that we have 12 + // kernels and 4 threads. Grains of 2, 3 and 4 all yield good task sizes. + // But 2/4 yield 6/3 tasks, which gives us parallelism of 0.75 (at most 3/4 + // of cores will be busy). While grain size 3 gives us 4 tasks, which gives + // us parallelism of 1 (we can load all cores). + Index nm0 = divup(m, bm); + Index nn0 = divup(n, bn); + Index new_tasks = divup(nm0, gm) * divup(nn0, gn); + double new_parallelism = static_cast(new_tasks) / + (divup(new_tasks, num_threads) * num_threads); + Index old_tasks = divup(nm0, oldgm) * divup(nn0, oldgn); + double old_parallelism = static_cast(old_tasks) / + (divup(old_tasks, num_threads) * num_threads); + if (new_parallelism > old_parallelism || new_parallelism == 1) return 1; + return 0; + } + +#else // EIGEN_USE_SIMPLE_THREAD_POOL + + template + void evalProduct(Scalar* buffer) const { + if (this->m_j_size == 1) { + this->template evalGemv(buffer); + return; + } + + evalGemm(buffer); + } + + template + void evalGemm(Scalar* buffer) const { + // columns in left side, rows in right side + const Index k = this->m_k_size; + + // rows in left side + const Index m = this->m_i_size; + + // columns in right side + const Index n = this->m_j_size; + + // zero out the result buffer (which must be of size at least m * n * sizeof(Scalar) + this->m_device.memset(buffer, 0, m * n * sizeof(Scalar)); + + + const int lhs_packet_size = internal::unpacket_traits::size; + const int rhs_packet_size = internal::unpacket_traits::size; + + typedef internal::TensorContractionInputMapper LhsMapper; + + typedef internal::TensorContractionInputMapper RhsMapper; + + typedef internal::blas_data_mapper OutputMapper; + + // TODO: packing could be faster sometimes if we supported row major tensor mappers + typedef internal::gemm_pack_lhs LhsPacker; + typedef internal::gemm_pack_rhs RhsPacker; + + // TODO: replace false, false with conjugate values? + typedef internal::gebp_kernel GebpKernel; + + typedef internal::packLhsArg packLArg; + typedef internal::packRhsAndKernelArg packRKArg; + + // initialize data mappers + LhsMapper lhs(this->m_leftImpl, this->m_left_nocontract_strides, this->m_i_strides, + this->m_left_contracting_strides, this->m_k_strides); + + RhsMapper rhs(this->m_rightImpl, this->m_right_nocontract_strides, this->m_j_strides, + this->m_right_contracting_strides, this->m_k_strides); + + OutputMapper output(buffer, m); + + // compute block sizes (which depend on number of threads) + const Index num_threads = this->m_device.numThreads(); + internal::TensorContractionBlocking blocking(k, m, n, num_threads); + Index mc = blocking.mc(); + Index nc = blocking.nc(); + Index kc = blocking.kc(); + eigen_assert(mc <= m); + eigen_assert(nc <= n); + eigen_assert(kc <= k); + +#define CEIL_DIV(a, b) (((a) + (b) - 1) / (b)) + const Index k_blocks = CEIL_DIV(k, kc); + const Index n_blocks = CEIL_DIV(n, nc); + const Index m_blocks = CEIL_DIV(m, mc); + const Index sizeA = mc * kc; + const Index sizeB = kc * nc; + + /* cout << "m: " << m << " n: " << n << " k: " << k << endl; + cout << "mc: " << mc << " nc: " << nc << " kc: " << kc << endl; + cout << "m_blocks: " << m_blocks << " n_blocks: " << n_blocks << " k_blocks: " << k_blocks << endl; + cout << "num threads: " << num_threads << endl; + */ + + // note: m_device.allocate should return 16 byte aligned pointers, but if blockA and blockB + // aren't 16 byte aligned segfaults will happen due to SIMD instructions + // note: You can get away with allocating just a single blockA and offsets and meet the + // the alignment requirements with the assumption that + // (Traits::mr * sizeof(ResScalar)) % 16 == 0 + const Index numBlockAs = numext::mini(num_threads, m_blocks); + MaxSizeVector blockAs(num_threads); + for (int i = 0; i < num_threads; i++) { + blockAs.push_back(static_cast(this->m_device.allocate(sizeA * sizeof(LhsScalar)))); + } + + // To circumvent alignment issues, I'm just going to separately allocate the memory for each thread + // TODO: is this too much memory to allocate? This simplifies coding a lot, but is wasteful. + // Other options: (1) reuse memory when a thread finishes. con: tricky + // (2) allocate block B memory in each thread. con: overhead + MaxSizeVector blockBs(n_blocks); + for (int i = 0; i < n_blocks; i++) { + blockBs.push_back(static_cast(this->m_device.allocate(sizeB * sizeof(RhsScalar)))); + } + + // lhs_notifications starts with all null Notifications + MaxSizeVector lhs_notifications(num_threads, nullptr); + + // this should really be numBlockAs * n_blocks; + const Index num_kernel_notifications = num_threads * n_blocks; + MaxSizeVector kernel_notifications(num_kernel_notifications, + nullptr); + + for (Index k_block_idx = 0; k_block_idx < k_blocks; k_block_idx++) { + const Index k_start = k_block_idx * kc; + // make sure we don't overshoot right edge of left matrix + const Index actual_kc = numext::mini(k_start + kc, k) - k_start; + + for (Index m_block_idx = 0; m_block_idx < m_blocks; m_block_idx += numBlockAs) { + const Index num_blocks = numext::mini(m_blocks-m_block_idx, numBlockAs); + + for (Index mt_block_idx = m_block_idx; mt_block_idx < m_block_idx+num_blocks; mt_block_idx++) { + const Index m_start = mt_block_idx * mc; + const Index actual_mc = numext::mini(m_start + mc, m) - m_start; + eigen_assert(actual_mc > 0); + + Index blockAId = (k_block_idx * m_blocks + mt_block_idx) % num_threads; + + for (int i = 0; i < n_blocks; ++i) { + Index notification_id = (blockAId * n_blocks + i); + // Wait for any current kernels using this slot to complete + // before using it. + if (kernel_notifications[notification_id]) { + wait_until_ready(kernel_notifications[notification_id]); + delete kernel_notifications[notification_id]; + } + kernel_notifications[notification_id] = new Notification(); + } + const packLArg arg = { + blockAs[blockAId], // blockA + lhs, // lhs + m_start, // m + k_start, // k + actual_mc, // mc + actual_kc, // kc + }; + + // Delete any existing notification since we may be + // replacing it. The algorithm should ensure that there are + // no existing waiters on this notification. + delete lhs_notifications[blockAId]; + lhs_notifications[blockAId] = + this->m_device.enqueue(&Self::packLhs, arg); + } + + // now start kernels. + const Index m_base_start = m_block_idx * mc; + const bool need_to_pack = m_block_idx == 0; + + for (Index n_block_idx = 0; n_block_idx < n_blocks; n_block_idx++) { + const Index n_start = n_block_idx * nc; + const Index actual_nc = numext::mini(n_start + nc, n) - n_start; + + // first make sure the previous kernels are all done before overwriting rhs. Also wait if + // we're going to start new k. In both cases need_to_pack is true. + if (need_to_pack) { + for (Index i = num_blocks; i < num_threads; ++i) { + Index blockAId = (k_block_idx * m_blocks + i + m_block_idx) % num_threads; + Index future_id = (blockAId * n_blocks + n_block_idx); + wait_until_ready(kernel_notifications[future_id]); + } + } + + packRKArg arg = { + &blockAs, // blockA + blockBs[n_block_idx], // blockB + rhs, // rhs + output, // output + m_base_start, // m + k_start, // k + n_start, // n + mc, // mc + actual_kc, // kc + actual_nc, // nc + num_threads, + numBlockAs, + m, + k_block_idx, + m_block_idx, + n_block_idx, // n_block_idx + m_blocks, // m_blocks + n_blocks, // n_blocks + &kernel_notifications, // kernel notifications + &lhs_notifications, // lhs notifications + need_to_pack, // need_to_pack + }; + + // We asynchronously kick off this function, which ends up + // notifying the appropriate kernel_notifications objects, + // which this thread waits on before exiting. + this->m_device.enqueueNoNotification(&Self::packRhsAndKernel, arg); + } + } + } + + // Make sure all the kernels are done. + for (size_t i = 0; i < kernel_notifications.size(); ++i) { + wait_until_ready(kernel_notifications[i]); + delete kernel_notifications[i]; + } + + // No need to wait for lhs notifications since they should have + // already been waited on. Just clean them up. + for (size_t i = 0; i < lhs_notifications.size(); ++i) { + delete lhs_notifications[i]; + } + + // deallocate all of the memory for both A and B's + for (size_t i = 0; i < blockAs.size(); i++) { + this->m_device.deallocate(blockAs[i]); + } + for (size_t i = 0; i < blockBs.size(); i++) { + this->m_device.deallocate(blockBs[i]); + } + +#undef CEIL_DIV + } + + /* + * Packs a LHS block of size (mt, kc) starting at lhs(m, k). Before packing + * the LHS block, check that all of the kernels that worked on the same + * mt_block_idx in the previous m_block are done. + */ + template + static void packLhs(const packLArg arg) { + // perform actual packing + LhsPacker pack_lhs; + pack_lhs(arg.blockA, arg.lhs.getSubMapper(arg.m_start, arg.k_start), arg.kc, arg.mc); + } + + /* + * Packs a RHS block of size (kc, nc) starting at (k, n) after checking that + * all kernels in the previous block are done. + * Then for each LHS future, we wait on the future and then call GEBP + * on the area packed by the future (which starts at + * blockA + future_idx * mt * kc) on the LHS and with the full packed + * RHS block. + * The output of this GEBP is written to output(m + i * mt, n). + */ + template + static void packRhsAndKernel(packRKArg arg) { + if (arg.need_to_pack) { + RhsPacker pack_rhs; + pack_rhs(arg.blockB, arg.rhs.getSubMapper(arg.k, arg.n), arg.kc, arg.nc); + } + + GebpKernel gebp; + for (Index mt_block_idx = 0; mt_block_idx < arg.num_blockAs; mt_block_idx++) { + const Index m_base_start = arg.m + arg.mc*mt_block_idx; + if (m_base_start < arg.max_m) { + Index blockAId = (arg.k_block_idx * arg.m_blocks + mt_block_idx + arg.m_block_idx) % arg.num_threads; + wait_until_ready((*arg.lhs_notifications)[blockAId]); + const Index actual_mc = numext::mini(m_base_start + arg.mc, arg.max_m) - m_base_start; + gebp(arg.output.getSubMapper(m_base_start, arg.n), + (*arg.blockAs)[blockAId], arg.blockB, + actual_mc, arg.kc, arg.nc, Scalar(1), -1, -1, 0, 0); + + // Notify that the kernel is done. + const Index set_idx = blockAId * arg.n_blocks + arg.n_block_idx; + (*arg.kernel_notifications)[set_idx]->Notify(); + } + } + } +#endif // EIGEN_USE_SIMPLE_THREAD_POOL + + TensorOpCost contractionCost(Index m, Index n, Index bm, Index bn, Index bk, + bool shard_by_col, bool prepacked) const { + const int packed_size = std::min(PacketType::size, + PacketType::size); + const int output_packet_size = internal::unpacket_traits::size; + const double kd = static_cast(bk); + // Peak VFMA bandwidth is 0.5. However if we have not enough data for + // vectorization bandwidth drops. The 4.0 and 2.0 bandwidth is determined + // experimentally. + double computeBandwidth = bk == 1 ? 4.0 : + (shard_by_col ? bn : bm) < Traits::nr || + (shard_by_col ? bm : bn) < Traits::mr ? 2.0 : 0.5; +#ifndef EIGEN_VECTORIZE_FMA + // Bandwidth of all of VFMA/MULPS/ADDPS is 0.5 on latest Intel processors. + // However for MULPS/ADDPS we have dependent sequence of 2 such instructions, + // so overall bandwidth is 1.0. + if (computeBandwidth == 0.5) computeBandwidth = 1.0; +#endif + // Computations. + TensorOpCost cost = TensorOpCost(0, 0, kd * computeBandwidth, true, packed_size); + // Output stores. + cost += TensorOpCost(0, sizeof(CoeffReturnType), 0, true, output_packet_size); + if (prepacked) { + // Packing and kernels are executed in different tasks. When we calculate + // task grain size we look only at kernel cost assuming that kernel + // is more expensive than packing. + return cost; + } + // Lhs/rhs loads + computations. + TensorOpCost lhsCost = this->m_leftImpl.costPerCoeff(true) * (kd / n); + TensorOpCost rhsCost = this->m_rightImpl.costPerCoeff(true) * (kd / m); + // Lhs packing memory cost does not contribute considerably to overall + // execution time because lhs is prefetched early and accessed sequentially. + if (shard_by_col) + lhsCost.dropMemoryCost(); + else + rhsCost.dropMemoryCost(); + return cost + lhsCost + rhsCost; + } +}; + +} // end namespace Eigen + +#endif // EIGEN_USE_THREADS +#endif // EIGEN_CXX11_TENSOR_TENSOR_CONTRACTION_THREAD_POOL_H diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorConversion.h b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorConversion.h new file mode 100644 index 0000000000..860a6949a9 --- /dev/null +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorConversion.h @@ -0,0 +1,279 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2015 Benoit Steiner +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CXX11_TENSOR_TENSOR_CONVERSION_H +#define EIGEN_CXX11_TENSOR_TENSOR_CONVERSION_H + +namespace Eigen { + +/** \class TensorConversionOp + * \ingroup CXX11_Tensor_Module + * + * \brief Tensor conversion class. This class makes it possible to vectorize + * type casting operations when the number of scalars per packet in the source + * and the destination type differ + */ +namespace internal { +template +struct traits > +{ + // Type promotion to handle the case where the types of the lhs and the rhs are different. + typedef TargetType Scalar; + typedef typename traits::StorageKind StorageKind; + typedef typename traits::Index Index; + typedef typename XprType::Nested Nested; + typedef typename remove_reference::type _Nested; + static const int NumDimensions = traits::NumDimensions; + static const int Layout = traits::Layout; + enum { Flags = 0 }; +}; + +template +struct eval, Eigen::Dense> +{ + typedef const TensorConversionOp& type; +}; + +template +struct nested, 1, typename eval >::type> +{ + typedef TensorConversionOp type; +}; + +} // end namespace internal + + +template +struct PacketConverter { + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + PacketConverter(const TensorEvaluator& impl) + : m_impl(impl) {} + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TgtPacket packet(Index index) const { + return internal::pcast(m_impl.template packet(index)); + } + + private: + const TensorEvaluator& m_impl; +}; + + +template +struct PacketConverter { + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + PacketConverter(const TensorEvaluator& impl) + : m_impl(impl) {} + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TgtPacket packet(Index index) const { + const int SrcPacketSize = internal::unpacket_traits::size; + + SrcPacket src1 = m_impl.template packet(index); + SrcPacket src2 = m_impl.template packet(index + SrcPacketSize); + TgtPacket result = internal::pcast(src1, src2); + return result; + } + + private: + const TensorEvaluator& m_impl; +}; + +template +struct PacketConverter { + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + PacketConverter(const TensorEvaluator& impl) + : m_impl(impl) {} + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TgtPacket packet(Index index) const { + const int SrcPacketSize = internal::unpacket_traits::size; + + SrcPacket src1 = m_impl.template packet(index); + SrcPacket src2 = m_impl.template packet(index + SrcPacketSize); + SrcPacket src3 = m_impl.template packet(index + 2 * SrcPacketSize); + SrcPacket src4 = m_impl.template packet(index + 3 * SrcPacketSize); + TgtPacket result = internal::pcast(src1, src2, src3, src4); + return result; + } + + private: + const TensorEvaluator& m_impl; +}; + +template +struct PacketConverter { + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + PacketConverter(const TensorEvaluator& impl) + : m_impl(impl), m_maxIndex(impl.dimensions().TotalSize()) {} + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TgtPacket packet(Index index) const { + const int SrcPacketSize = internal::unpacket_traits::size; + // Only call m_impl.packet() when we have direct access to the underlying data. This + // ensures that we don't compute the subexpression twice. We may however load some + // coefficients twice, but in practice this doesn't negatively impact performance. + if (m_impl.data() && (index + SrcPacketSize < m_maxIndex)) { + // Force unaligned memory loads since we can't ensure alignment anymore + return internal::pcast(m_impl.template packet(index)); + } else { + const int TgtPacketSize = internal::unpacket_traits::size; + typedef typename internal::unpacket_traits::type SrcType; + typedef typename internal::unpacket_traits::type TgtType; + internal::scalar_cast_op converter; + EIGEN_ALIGN_MAX typename internal::unpacket_traits::type values[TgtPacketSize]; + for (int i = 0; i < TgtPacketSize; ++i) { + values[i] = converter(m_impl.coeff(index+i)); + } + TgtPacket rslt = internal::pload(values); + return rslt; + } + } + + private: + const TensorEvaluator& m_impl; + const typename TensorEvaluator::Index m_maxIndex; +}; + +template +class TensorConversionOp : public TensorBase, ReadOnlyAccessors> +{ + public: + typedef typename internal::traits::Scalar Scalar; + typedef typename internal::traits::StorageKind StorageKind; + typedef typename internal::traits::Index Index; + typedef typename internal::nested::type Nested; + typedef Scalar CoeffReturnType; + typedef typename NumTraits::Real RealScalar; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorConversionOp(const XprType& xpr) + : m_xpr(xpr) {} + + EIGEN_DEVICE_FUNC + const typename internal::remove_all::type& + expression() const { return m_xpr; } + + protected: + typename XprType::Nested m_xpr; +}; + +template struct ConversionSubExprEval { + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool run(Eval& impl, Scalar*) { + impl.evalSubExprsIfNeeded(NULL); + return true; + } +}; + +template struct ConversionSubExprEval { + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool run(Eval& impl, Scalar* data) { + return impl.evalSubExprsIfNeeded(data); + } +}; + + +// Eval as rvalue +template +struct TensorEvaluator, Device> +{ + typedef TensorConversionOp XprType; + typedef typename XprType::Index Index; + typedef typename TensorEvaluator::Dimensions Dimensions; + typedef TargetType Scalar; + typedef TargetType CoeffReturnType; + typedef typename internal::remove_all::Scalar>::type SrcType; + typedef typename PacketType::type PacketReturnType; + typedef typename PacketType::type PacketSourceType; + static const int PacketSize = internal::unpacket_traits::size; + + enum { + IsAligned = false, + PacketAccess = true, + Layout = TensorEvaluator::Layout, + RawAccess = false + }; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorEvaluator(const XprType& op, const Device& device) + : m_impl(op.expression(), device) + { + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Dimensions& dimensions() const { return m_impl.dimensions(); } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(Scalar* data) + { + return ConversionSubExprEval::value, TensorEvaluator, Scalar>::run(m_impl, data); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void cleanup() + { + m_impl.cleanup(); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const + { + internal::scalar_cast_op converter; + return converter(m_impl.coeff(index)); + } + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packet(Index index) const + { + const bool Vectorizable = TensorEvaluator::PacketAccess & + internal::type_casting_traits::VectorizedCast; + return PacketConv::run(m_impl, index); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost + costPerCoeff(bool vectorized) const { + const double cast_cost = TensorOpCost::CastCost(); + if (vectorized) { + const double SrcCoeffRatio = + internal::type_casting_traits::SrcCoeffRatio; + const double TgtCoeffRatio = + internal::type_casting_traits::TgtCoeffRatio; + return m_impl.costPerCoeff(vectorized) * (SrcCoeffRatio / PacketSize) + + TensorOpCost(0, 0, TgtCoeffRatio * (cast_cost / PacketSize)); + } else { + return m_impl.costPerCoeff(vectorized) + TensorOpCost(0, 0, cast_cost); + } + } + + EIGEN_DEVICE_FUNC Scalar* data() const { return NULL; } + + protected: + template + struct PacketConv { + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType run(const TensorEvaluator& impl, Index index) { + internal::scalar_cast_op converter; + EIGEN_ALIGN_MAX typename internal::remove_const::type values[PacketSize]; + for (int i = 0; i < PacketSize; ++i) { + values[i] = converter(impl.coeff(index+i)); + } + PacketReturnType rslt = internal::pload(values); + return rslt; + } + }; + + template + struct PacketConv { + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType run(const TensorEvaluator& impl, Index index) { + const int SrcCoeffRatio = internal::type_casting_traits::SrcCoeffRatio; + const int TgtCoeffRatio = internal::type_casting_traits::TgtCoeffRatio; + PacketConverter, PacketSourceType, PacketReturnType, + SrcCoeffRatio, TgtCoeffRatio> converter(impl); + return converter.template packet(index); + } + }; + + TensorEvaluator m_impl; +}; + +} // end namespace Eigen + +#endif // EIGEN_CXX11_TENSOR_TENSOR_CONVERSION_H diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorConvolution.h b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorConvolution.h new file mode 100644 index 0000000000..abdf742c6e --- /dev/null +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorConvolution.h @@ -0,0 +1,1104 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Benoit Steiner +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CXX11_TENSOR_TENSOR_CONVOLUTION_H +#define EIGEN_CXX11_TENSOR_TENSOR_CONVOLUTION_H + +namespace Eigen { + +/** \class TensorConvolution + * \ingroup CXX11_Tensor_Module + * + * \brief Tensor convolution class. + * + * + */ +namespace internal { + +template +class IndexMapper { + public: + IndexMapper(const InputDims& input_dims, const array& kernel_dims, + const array& indices) { + + array dimensions = input_dims; + for (int i = 0; i < NumKernelDims; ++i) { + const Index index = indices[i]; + const Index input_dim = input_dims[index]; + const Index kernel_dim = kernel_dims[i]; + const Index result_dim = input_dim - kernel_dim + 1; + dimensions[index] = result_dim; + } + + array inputStrides; + array outputStrides; + if (static_cast(Layout) == static_cast(ColMajor)) { + inputStrides[0] = 1; + outputStrides[0] = 1; + for (int i = 1; i < NumDims; ++i) { + inputStrides[i] = inputStrides[i-1] * input_dims[i-1]; + outputStrides[i] = outputStrides[i-1] * dimensions[i-1]; + } + } else { + inputStrides[NumDims - 1] = 1; + outputStrides[NumDims - 1] = 1; + for (int i = static_cast(NumDims) - 2; i >= 0; --i) { + inputStrides[i] = inputStrides[i + 1] * input_dims[i + 1]; + outputStrides[i] = outputStrides[i + 1] * dimensions[i + 1]; + } + } + + array cudaInputDimensions; + array cudaOutputDimensions; + array tmp = dimensions; + array ordering; + const size_t offset = static_cast(Layout) == static_cast(ColMajor) + ? 0 + : NumDims - NumKernelDims; + for (int i = 0; i < NumKernelDims; ++i) { + const Index index = i + offset; + ordering[index] = indices[i]; + tmp[indices[i]] = -1; + cudaInputDimensions[index] = input_dims[indices[i]]; + cudaOutputDimensions[index] = dimensions[indices[i]]; + } + + int written = static_cast(Layout) == static_cast(ColMajor) + ? NumKernelDims + : 0; + for (int i = 0; i < NumDims; ++i) { + if (tmp[i] >= 0) { + ordering[written] = i; + cudaInputDimensions[written] = input_dims[i]; + cudaOutputDimensions[written] = dimensions[i]; + ++written; + } + } + + for (int i = 0; i < NumDims; ++i) { + m_inputStrides[i] = inputStrides[ordering[i]]; + m_outputStrides[i] = outputStrides[ordering[i]]; + } + + if (static_cast(Layout) == static_cast(ColMajor)) { + for (int i = 0; i < NumDims; ++i) { + if (i > NumKernelDims) { + m_cudaInputStrides[i] = + m_cudaInputStrides[i - 1] * cudaInputDimensions[i - 1]; + m_cudaOutputStrides[i] = + m_cudaOutputStrides[i - 1] * cudaOutputDimensions[i - 1]; + } else { + m_cudaInputStrides[i] = 1; + m_cudaOutputStrides[i] = 1; + } + } + } else { + for (int i = NumDims - 1; i >= 0; --i) { + if (i + 1 < offset) { + m_cudaInputStrides[i] = + m_cudaInputStrides[i + 1] * cudaInputDimensions[i + 1]; + m_cudaOutputStrides[i] = + m_cudaOutputStrides[i + 1] * cudaOutputDimensions[i + 1]; + } else { + m_cudaInputStrides[i] = 1; + m_cudaOutputStrides[i] = 1; + } + } + } + } + + EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC Index mapCudaInputPlaneToTensorInputOffset(Index p) const { + Index inputIndex = 0; + if (static_cast(Layout) == static_cast(ColMajor)) { + for (int d = NumDims - 1; d > NumKernelDims; --d) { + const Index idx = p / m_cudaInputStrides[d]; + inputIndex += idx * m_inputStrides[d]; + p -= idx * m_cudaInputStrides[d]; + } + inputIndex += p * m_inputStrides[NumKernelDims]; + } else { + std::ptrdiff_t limit = 0; + if (NumKernelDims < NumDims) { + limit = NumDims - NumKernelDims - 1; + } + for (int d = 0; d < limit; ++d) { + const Index idx = p / m_cudaInputStrides[d]; + inputIndex += idx * m_inputStrides[d]; + p -= idx * m_cudaInputStrides[d]; + } + inputIndex += p * m_inputStrides[limit]; + } + return inputIndex; + } + + EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC Index mapCudaOutputPlaneToTensorOutputOffset(Index p) const { + Index outputIndex = 0; + if (static_cast(Layout) == static_cast(ColMajor)) { + for (int d = NumDims - 1; d > NumKernelDims; --d) { + const Index idx = p / m_cudaOutputStrides[d]; + outputIndex += idx * m_outputStrides[d]; + p -= idx * m_cudaOutputStrides[d]; + } + outputIndex += p * m_outputStrides[NumKernelDims]; + } else { + std::ptrdiff_t limit = 0; + if (NumKernelDims < NumDims) { + limit = NumDims - NumKernelDims - 1; + } + for (int d = 0; d < limit; ++d) { + const Index idx = p / m_cudaOutputStrides[d]; + outputIndex += idx * m_outputStrides[d]; + p -= idx * m_cudaOutputStrides[d]; + } + outputIndex += p * m_outputStrides[limit]; + } + return outputIndex; + } + + EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC Index mapCudaInputKernelToTensorInputOffset(Index i) const { + const size_t offset = static_cast(Layout) == static_cast(ColMajor) + ? 0 + : NumDims - NumKernelDims; + return i * m_inputStrides[offset]; + } + + EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC Index mapCudaOutputKernelToTensorOutputOffset(Index i) const { + const size_t offset = static_cast(Layout) == static_cast(ColMajor) + ? 0 + : NumDims - NumKernelDims; + return i * m_outputStrides[offset]; + } + + EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC Index mapCudaInputKernelToTensorInputOffset(Index i, Index j) const { + const size_t offset = static_cast(Layout) == static_cast(ColMajor) + ? 0 + : NumDims - NumKernelDims; + return i * m_inputStrides[offset] + j * m_inputStrides[offset + 1]; + } + + EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC Index mapCudaOutputKernelToTensorOutputOffset(Index i, Index j) const { + const size_t offset = static_cast(Layout) == static_cast(ColMajor) + ? 0 + : NumDims - NumKernelDims; + return i * m_outputStrides[offset] + j * m_outputStrides[offset + 1]; + } + + EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC Index mapCudaInputKernelToTensorInputOffset(Index i, Index j, Index k) const { + const size_t offset = static_cast(Layout) == static_cast(ColMajor) + ? 0 + : NumDims - NumKernelDims; + return i * m_inputStrides[offset] + j * m_inputStrides[offset + 1] + + k * m_inputStrides[offset + 2]; + } + + EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC Index mapCudaOutputKernelToTensorOutputOffset(Index i, Index j, Index k) const { + const size_t offset = static_cast(Layout) == static_cast(ColMajor) + ? 0 + : NumDims - NumKernelDims; + return i * m_outputStrides[offset] + j * m_outputStrides[offset + 1] + + k * m_outputStrides[offset + 2]; + } + + private: + static const int NumDims = internal::array_size::value; + array m_inputStrides; + array m_outputStrides; + array m_cudaInputStrides; + array m_cudaOutputStrides; +}; + + + +template +struct traits > +{ + // Type promotion to handle the case where the types of the lhs and the rhs are different. + typedef typename promote_storage_type::ret Scalar; + typedef typename promote_storage_type::StorageKind, + typename traits::StorageKind>::ret StorageKind; + typedef typename promote_index_type::Index, + typename traits::Index>::type Index; + typedef typename InputXprType::Nested LhsNested; + typedef typename KernelXprType::Nested RhsNested; + typedef typename remove_reference::type _LhsNested; + typedef typename remove_reference::type _RhsNested; + static const int NumDimensions = traits::NumDimensions; + static const int Layout = traits::Layout; + + enum { + Flags = 0 + }; +}; + +template +struct eval, Eigen::Dense> +{ + typedef const TensorConvolutionOp& type; +}; + +template +struct nested, 1, typename eval >::type> +{ + typedef TensorConvolutionOp type; +}; + +} // end namespace internal + + + +template +class TensorConvolutionOp : public TensorBase, ReadOnlyAccessors> +{ + public: + typedef typename Eigen::internal::traits::Scalar Scalar; + typedef typename Eigen::NumTraits::Real RealScalar; + typedef typename internal::promote_storage_type::ret CoeffReturnType; + typedef typename Eigen::internal::nested::type Nested; + typedef typename Eigen::internal::traits::StorageKind StorageKind; + typedef typename Eigen::internal::traits::Index Index; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorConvolutionOp(const InputXprType& input, const KernelXprType& kernel, const Indices& dims) + : m_input_xpr(input), m_kernel_xpr(kernel), m_indices(dims) {} + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const Indices& indices() const { return m_indices; } + + /** \returns the nested expressions */ + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const typename internal::remove_all::type& + inputExpression() const { return m_input_xpr; } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const typename internal::remove_all::type& + kernelExpression() const { return m_kernel_xpr; } + + protected: + typename InputXprType::Nested m_input_xpr; + typename KernelXprType::Nested m_kernel_xpr; + const Indices m_indices; +}; + + +template +struct TensorEvaluator, Device> +{ + typedef TensorConvolutionOp XprType; + + static const int NumDims = internal::array_size::Dimensions>::value; + static const int NumKernelDims = internal::array_size::value; + typedef typename XprType::Index Index; + typedef DSizes Dimensions; + + typedef typename XprType::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + typedef typename PacketType::type PacketReturnType; + static const int PacketSize = internal::unpacket_traits::size; + + enum { + IsAligned = TensorEvaluator::IsAligned & TensorEvaluator::IsAligned, + PacketAccess = TensorEvaluator::PacketAccess & TensorEvaluator::PacketAccess, + Layout = TensorEvaluator::Layout, + CoordAccess = false, // to be implemented + RawAccess = false + }; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorEvaluator(const XprType& op, const Device& device) + : m_inputImpl(op.inputExpression(), device), m_kernelImpl(op.kernelExpression(), device), m_kernelArg(op.kernelExpression()), m_kernel(NULL), m_local_kernel(false), m_device(device) + { + EIGEN_STATIC_ASSERT((static_cast(TensorEvaluator::Layout) == static_cast(TensorEvaluator::Layout)), YOU_MADE_A_PROGRAMMING_MISTAKE); + + const typename TensorEvaluator::Dimensions& input_dims = m_inputImpl.dimensions(); + const typename TensorEvaluator::Dimensions& kernel_dims = m_kernelImpl.dimensions(); + + if (static_cast(Layout) == static_cast(ColMajor)) { + m_inputStride[0] = 1; + for (int i = 1; i < NumDims; ++i) { + m_inputStride[i] = m_inputStride[i - 1] * input_dims[i - 1]; + } + } else { + m_inputStride[NumDims - 1] = 1; + for (int i = NumDims - 2; i >= 0; --i) { + m_inputStride[i] = m_inputStride[i + 1] * input_dims[i + 1]; + } + } + + m_dimensions = m_inputImpl.dimensions(); + if (static_cast(Layout) == static_cast(ColMajor)) { + for (int i = 0; i < NumKernelDims; ++i) { + const Index index = op.indices()[i]; + const Index input_dim = input_dims[index]; + const Index kernel_dim = kernel_dims[i]; + const Index result_dim = input_dim - kernel_dim + 1; + m_dimensions[index] = result_dim; + if (i > 0) { + m_kernelStride[i] = m_kernelStride[i - 1] * kernel_dims[i - 1]; + } else { + m_kernelStride[0] = 1; + } + m_indexStride[i] = m_inputStride[index]; + } + + m_outputStride[0] = 1; + for (int i = 1; i < NumDims; ++i) { + m_outputStride[i] = m_outputStride[i - 1] * m_dimensions[i - 1]; + } + } else { + for (int i = NumKernelDims - 1; i >= 0; --i) { + const Index index = op.indices()[i]; + const Index input_dim = input_dims[index]; + const Index kernel_dim = kernel_dims[i]; + const Index result_dim = input_dim - kernel_dim + 1; + m_dimensions[index] = result_dim; + if (i < NumKernelDims - 1) { + m_kernelStride[i] = m_kernelStride[i + 1] * kernel_dims[i + 1]; + } else { + m_kernelStride[NumKernelDims - 1] = 1; + } + m_indexStride[i] = m_inputStride[index]; + } + + m_outputStride[NumDims - 1] = 1; + for (int i = NumDims - 2; i >= 0; --i) { + m_outputStride[i] = m_outputStride[i + 1] * m_dimensions[i + 1]; + } + } + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Dimensions& dimensions() const { return m_dimensions; } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(Scalar*) { + m_inputImpl.evalSubExprsIfNeeded(NULL); + preloadKernel(); + return true; + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void cleanup() { + m_inputImpl.cleanup(); + if (m_local_kernel) { + m_device.deallocate((void*)m_kernel); + m_local_kernel = false; + } + m_kernel = NULL; + } + + void evalTo(typename XprType::Scalar* buffer) { + evalSubExprsIfNeeded(NULL); + for (int i = 0; i < dimensions().TotalSize(); ++i) { + buffer[i] += coeff(i); + } + cleanup(); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const + { + CoeffReturnType result = CoeffReturnType(0); + convolve(firstInput(index), 0, NumKernelDims-1, result); + return result; + } + + template + EIGEN_DEVICE_FUNC PacketReturnType packet(const Index index) const + { + Index indices[2] = {index, index+PacketSize-1}; + Index startInputs[2] = {0, 0}; + if (static_cast(Layout) == static_cast(ColMajor)) { + for (int i = NumDims - 1; i > 0; --i) { + const Index idx0 = indices[0] / m_outputStride[i]; + const Index idx1 = indices[1] / m_outputStride[i]; + startInputs[0] += idx0 * m_inputStride[i]; + startInputs[1] += idx1 * m_inputStride[i]; + indices[0] -= idx0 * m_outputStride[i]; + indices[1] -= idx1 * m_outputStride[i]; + } + } else { + for (int i = 0; i < NumDims - 1; ++i) { + const Index idx0 = indices[0] / m_outputStride[i]; + const Index idx1 = indices[1] / m_outputStride[i]; + startInputs[0] += idx0 * m_inputStride[i]; + startInputs[1] += idx1 * m_inputStride[i]; + indices[0] -= idx0 * m_outputStride[i]; + indices[1] -= idx1 * m_outputStride[i]; + } + } + startInputs[0] += indices[0]; + startInputs[1] += indices[1]; + + if (startInputs[1]-startInputs[0] == PacketSize-1) { + PacketReturnType result = internal::pset1(0); + convolvePacket(startInputs[0], 0, NumKernelDims-1, result); + return result; + } else { + EIGEN_ALIGN_MAX Scalar data[PacketSize]; + data[0] = Scalar(0); + convolve(startInputs[0], 0, NumKernelDims-1, data[0]); + for (int i = 1; i < PacketSize-1; ++i) { + data[i] = Scalar(0); + convolve(firstInput(index+i), 0, NumKernelDims-1, data[i]); + } + data[PacketSize-1] = Scalar(0); + convolve(startInputs[1], 0, NumKernelDims-1, data[PacketSize-1]); + return internal::pload(data); + } + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost + costPerCoeff(bool vectorized) const { + const double kernel_size = m_kernelImpl.dimensions().TotalSize(); + // We ignore the use of fused multiply-add. + const double convolve_compute_cost = + TensorOpCost::AddCost() + TensorOpCost::MulCost(); + const double firstIndex_compute_cost = + NumDims * + (2 * TensorOpCost::AddCost() + 2 * TensorOpCost::MulCost() + + TensorOpCost::DivCost()); + return TensorOpCost(0, 0, firstIndex_compute_cost, vectorized, PacketSize) + + kernel_size * (m_inputImpl.costPerCoeff(vectorized) + + m_kernelImpl.costPerCoeff(vectorized) + + TensorOpCost(0, 0, convolve_compute_cost, vectorized, + PacketSize)); + } + + EIGEN_DEVICE_FUNC Scalar* data() const { return NULL; } + + private: + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index firstInput(Index index) const { + Index startInput = 0; + if (static_cast(Layout) == static_cast(ColMajor)) { + for (int i = NumDims - 1; i > 0; --i) { + const Index idx = index / m_outputStride[i]; + startInput += idx * m_inputStride[i]; + index -= idx * m_outputStride[i]; + } + } else { + for (int i = 0; i < NumDims - 1; ++i) { + const Index idx = index / m_outputStride[i]; + startInput += idx * m_inputStride[i]; + index -= idx * m_outputStride[i]; + } + } + startInput += index; + return startInput; + } + + EIGEN_DEVICE_FUNC void convolve(Index firstIndex, Index firstKernel, int DimIndex, CoeffReturnType& accum) const { + for (int j = 0; j < m_kernelImpl.dimensions()[DimIndex]; ++j) { + const Index input = firstIndex + j * m_indexStride[DimIndex]; + const Index kernel = firstKernel + j * m_kernelStride[DimIndex]; + if (DimIndex > 0) { + convolve(input, kernel, DimIndex-1, accum); + } else { + accum += m_inputImpl.coeff(input) * m_kernel[kernel]; + } + } + } + + template + EIGEN_DEVICE_FUNC void convolvePacket(Index firstIndex, Index firstKernel, int DimIndex, Packet& accum) const { + for (int j = 0; j < m_kernelImpl.dimensions()[DimIndex]; ++j) { + const Index input = firstIndex + j * m_indexStride[DimIndex]; + const Index kernel = firstKernel + j * m_kernelStride[DimIndex]; + if (DimIndex > 0) { + convolvePacket(input, kernel, DimIndex-1, accum); + } else { + accum = internal::pmadd(m_inputImpl.template packet(input), internal::pset1(m_kernel[kernel]), accum); + } + } + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void preloadKernel() { + // Don't make a local copy of the kernel unless we have to (i.e. it's an + // expression that needs to be evaluated) + const Scalar* in_place = m_kernelImpl.data(); + if (in_place) { + m_kernel = in_place; + m_local_kernel = false; + } else { + size_t kernel_sz = m_kernelImpl.dimensions().TotalSize() * sizeof(Scalar); + Scalar* local = (Scalar*)m_device.allocate(kernel_sz); + typedef TensorEvalToOp EvalTo; + EvalTo evalToTmp(local, m_kernelArg); + const bool PacketAccess = internal::IsVectorizable::value; + internal::TensorExecutor::run(evalToTmp, m_device); + + m_kernel = local; + m_local_kernel = true; + } + } + + array m_inputStride; + array m_outputStride; + + array m_indexStride; + array m_kernelStride; + TensorEvaluator m_inputImpl; + TensorEvaluator m_kernelImpl; + Dimensions m_dimensions; + + KernelArgType m_kernelArg; + const Scalar* m_kernel; + bool m_local_kernel; + const Device& m_device; +}; + + + + +// Use an optimized implementation of the evaluation code for GPUs whenever possible. +#if defined(EIGEN_USE_GPU) && defined(__CUDACC__) + +template +struct GetKernelSize { + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE int operator() (const int /*kernelSize*/) const { + return StaticKernelSize; + } +}; +template <> +struct GetKernelSize { + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE int operator() (const int kernelSize) const { + return kernelSize; + } +}; + +template +__global__ void EigenConvolutionKernel1D( + InputEvaluator eval, + const internal::IndexMapper + indexMapper, + const float* __restrict kernel, const int numPlanes, const int numX, + const int maxX, const int kernelSize, float* buffer) { + extern __shared__ float s[]; + + const int first_x = blockIdx.x * maxX; + const int last_x = (first_x + maxX < numX ? first_x + maxX : numX) - 1; + const int num_x_input = last_x - first_x + GetKernelSize()(kernelSize); + const int num_x_output = last_x - first_x + 1; + + const int first_plane = blockIdx.y * blockDim.y; + const int plane_stride = blockDim.y * gridDim.y; + + for (int p = first_plane + threadIdx.y; p < numPlanes; p += plane_stride) { + // Load inputs to shared memory + const int plane_input_offset = indexMapper.mapCudaInputPlaneToTensorInputOffset(p); + const int plane_kernel_offset = threadIdx.y * num_x_input; + #pragma unroll + for (int i = threadIdx.x; i < num_x_input; i += blockDim.x) { + const int tensor_index = plane_input_offset + indexMapper.mapCudaInputKernelToTensorInputOffset(i+first_x); + s[i + plane_kernel_offset] = eval.coeff(tensor_index); + } + + __syncthreads(); + + // Compute the convolution + const int plane_output_offset = indexMapper.mapCudaOutputPlaneToTensorOutputOffset(p); + + #pragma unroll + for (int i = threadIdx.x; i < num_x_output; i += blockDim.x) { + const int kernel_offset = plane_kernel_offset + i; + float result = 0.0f; + #pragma unroll + for (int k = 0; k < GetKernelSize()(kernelSize); ++k) { + result += s[k + kernel_offset] * kernel[k]; + } + const int tensor_index = plane_output_offset + indexMapper.mapCudaOutputKernelToTensorOutputOffset(i+first_x); + buffer[tensor_index] = result; + } + __syncthreads(); + } +}; + +template +__global__ void EigenConvolutionKernel2D( + InputEvaluator eval, + const internal::IndexMapper + indexMapper, + const float* __restrict kernel, const int numPlanes, const int numX, + const int maxX, const int numY, const int maxY, const int kernelSizeX, + const int kernelSizeY, float* buffer) { + extern __shared__ float s[]; + + const int first_x = blockIdx.x * maxX; + const int last_x = (first_x + maxX < numX ? first_x + maxX : numX) - 1; + const int num_x_input = last_x - first_x + GetKernelSize()(kernelSizeX); + const int num_x_output = last_x - first_x + 1; + + const int first_y = blockIdx.y * maxY; + const int last_y = (first_y + maxY < numY ? first_y + maxY : numY) - 1; + const int num_y_input = last_y - first_y + GetKernelSize()(kernelSizeY); + const int num_y_output = last_y - first_y + 1; + + const int first_plane = blockIdx.z * blockDim.z; + const int plane_stride = blockDim.z * gridDim.z; + + for (int p = first_plane + threadIdx.z; p < numPlanes; p += plane_stride) { + + const int plane_input_offset = indexMapper.mapCudaInputPlaneToTensorInputOffset(p); + const int plane_kernel_offset = threadIdx.z * num_y_input; + + // Load inputs to shared memory + #pragma unroll + for (int j = threadIdx.y; j < num_y_input; j += blockDim.y) { + const int input_offset = num_x_input * (j + plane_kernel_offset); + #pragma unroll + for (int i = threadIdx.x; i < num_x_input; i += blockDim.x) { + const int tensor_index = plane_input_offset + indexMapper.mapCudaInputKernelToTensorInputOffset(i+first_x, j+first_y); + s[i + input_offset] = eval.coeff(tensor_index); + } + } + + __syncthreads(); + + // Convolution + const int plane_output_offset = indexMapper.mapCudaOutputPlaneToTensorOutputOffset(p); + + #pragma unroll + for (int j = threadIdx.y; j < num_y_output; j += blockDim.y) { + #pragma unroll + for (int i = threadIdx.x; i < num_x_output; i += blockDim.x) { + float result = 0.0f; + #pragma unroll + for (int l = 0; l < GetKernelSize()(kernelSizeY); ++l) { + const int kernel_offset = kernelSizeX * l; + const int input_offset = i + num_x_input * (j + l + plane_kernel_offset); + #pragma unroll + for (int k = 0; k < GetKernelSize()(kernelSizeX); ++k) { + result += s[k + input_offset] * kernel[k + kernel_offset]; + } + } + const int tensor_index = plane_output_offset + indexMapper.mapCudaOutputKernelToTensorOutputOffset(i+first_x, j+first_y); + buffer[tensor_index] = result; + } + } + + __syncthreads(); + } +}; + +template +__global__ void EigenConvolutionKernel3D( + InputEvaluator eval, + const internal::IndexMapper + indexMapper, + const float* __restrict kernel, const size_t numPlanes, const size_t numX, + const size_t maxX, const size_t numY, const size_t maxY, const size_t numZ, + const size_t maxZ, const size_t kernelSizeX, const size_t kernelSizeY, + const size_t kernelSizeZ, float* buffer) { + extern __shared__ float s[]; + + // Load inputs to shared memory + const int first_x = blockIdx.x * maxX; + const int last_x = (first_x + maxX < numX ? first_x + maxX : numX) - 1; + const int num_x_input = last_x - first_x + kernelSizeX; + + const int first_y = blockIdx.y * maxY; + const int last_y = (first_y + maxY < numY ? first_y + maxY : numY) - 1; + const int num_y_input = last_y - first_y + kernelSizeY; + + const int first_z = blockIdx.z * maxZ; + const int last_z = (first_z + maxZ < numZ ? first_z + maxZ : numZ) - 1; + const int num_z_input = last_z - first_z + kernelSizeZ; + + for (int p = 0; p < numPlanes; ++p) { + + const int plane_input_offset = indexMapper.mapCudaInputPlaneToTensorInputOffset(p); + const int plane_kernel_offset = 0; + + for (int k = threadIdx.z; k < num_z_input; k += blockDim.z) { + for (int j = threadIdx.y; j < num_y_input; j += blockDim.y) { + for (int i = threadIdx.x; i < num_x_input; i += blockDim.x) { + const int tensor_index = plane_input_offset + indexMapper.mapCudaInputKernelToTensorInputOffset(i+first_x, j+first_y, k+first_z); + s[i + num_x_input * (j + num_y_input * (k + plane_kernel_offset))] = eval.coeff(tensor_index); + } + } + } + + __syncthreads(); + + // Convolution + const int num_z_output = last_z - first_z + 1; + const int num_y_output = last_y - first_y + 1; + const int num_x_output = last_x - first_x + 1; + const int plane_output_offset = indexMapper.mapCudaOutputPlaneToTensorOutputOffset(p); + + for (int k = threadIdx.z; k < num_z_output; k += blockDim.z) { + for (int j = threadIdx.y; j < num_y_output; j += blockDim.y) { + for (int i = threadIdx.x; i < num_x_output; i += blockDim.x) { + float result = 0.0f; + for (int n = 0; n < kernelSizeZ; ++n) { + for (int m = 0; m < kernelSizeY; ++m) { + for (int l = 0; l < kernelSizeX; ++l) { + result += s[i + l + num_x_input * (j + m + num_y_input * (k + n + plane_kernel_offset))] * kernel[l + kernelSizeX * (m + kernelSizeY * n)]; + } + } + } + const int tensor_index = plane_output_offset + indexMapper.mapCudaOutputKernelToTensorOutputOffset(i+first_x, j+first_y, k+first_z); + buffer[tensor_index] = result; + } + } + } + __syncthreads(); + } +}; + + + +template +struct TensorEvaluator, GpuDevice> +{ + typedef TensorConvolutionOp XprType; + + static const int NumDims = internal::array_size::Dimensions>::value; + static const int NumKernelDims = internal::array_size::value; + typedef typename XprType::Index Index; + typedef DSizes Dimensions; + typedef typename TensorEvaluator::Dimensions KernelDimensions; + + enum { + IsAligned = TensorEvaluator::IsAligned & TensorEvaluator::IsAligned, + PacketAccess = false, + Layout = TensorEvaluator::Layout, + CoordAccess = false, // to be implemented + RawAccess = false + }; + + EIGEN_DEVICE_FUNC TensorEvaluator(const XprType& op, const GpuDevice& device) + : m_inputImpl(op.inputExpression(), device), m_kernelArg(op.kernelExpression()), m_kernelImpl(op.kernelExpression(), device), m_indices(op.indices()), m_buf(NULL), m_kernel(NULL), m_local_kernel(false), m_device(device) + { + EIGEN_STATIC_ASSERT((static_cast(TensorEvaluator::Layout) == static_cast(TensorEvaluator::Layout)), YOU_MADE_A_PROGRAMMING_MISTAKE); + + const typename TensorEvaluator::Dimensions& input_dims = m_inputImpl.dimensions(); + const typename TensorEvaluator::Dimensions& kernel_dims = m_kernelImpl.dimensions(); + + m_dimensions = m_inputImpl.dimensions(); + for (int i = 0; i < NumKernelDims; ++i) { + const Index index = op.indices()[i]; + const Index input_dim = input_dims[index]; + const Index kernel_dim = kernel_dims[i]; + const Index result_dim = input_dim - kernel_dim + 1; + m_dimensions[index] = result_dim; + } + } + + typedef typename XprType::CoeffReturnType CoeffReturnType; + typedef typename PacketType::type PacketReturnType; + typedef typename InputArgType::Scalar Scalar; + static const int PacketSize = internal::unpacket_traits::size; + + EIGEN_DEVICE_FUNC const Dimensions& dimensions() const { return m_dimensions; } + + EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(Scalar* data) { + preloadKernel(); + m_inputImpl.evalSubExprsIfNeeded(NULL); + if (data) { + executeEval(data); + return false; + } else { + m_buf = (Scalar*)m_device.allocate(dimensions().TotalSize() * sizeof(Scalar)); + executeEval(m_buf); + return true; + } + } + + EIGEN_STRONG_INLINE void cleanup() { + m_inputImpl.cleanup(); + if (m_buf) { + m_device.deallocate(m_buf); + m_buf = NULL; + } + if (m_local_kernel) { + m_device.deallocate((void*)m_kernel); + m_local_kernel = false; + } + m_kernel = NULL; + } + + EIGEN_STRONG_INLINE void preloadKernel() { + // Don't make a local copy of the kernel unless we have to (i.e. it's an + // expression that needs to be evaluated) + const Scalar* in_place = m_kernelImpl.data(); + if (in_place) { + m_kernel = in_place; + m_local_kernel = false; + } else { + size_t kernel_sz = m_kernelImpl.dimensions().TotalSize() * sizeof(Scalar); + Scalar* local = (Scalar*)m_device.allocate(kernel_sz); + typedef TensorEvalToOp EvalTo; + EvalTo evalToTmp(local, m_kernelArg); + const bool PacketAccess = internal::IsVectorizable::value; + internal::TensorExecutor::run(evalToTmp, m_device); + + m_kernel = local; + m_local_kernel = true; + } + } + + static unsigned int ceil(unsigned int num, unsigned int denom) { + const unsigned int rounded_toward_zero = num / denom; + if (num > rounded_toward_zero * denom) { + return rounded_toward_zero + 1; + } + return rounded_toward_zero; + } + + void executeEval(Scalar* data) const { + typedef typename TensorEvaluator::Dimensions InputDims; + + const int maxSharedMem = m_device.sharedMemPerBlock(); + const int maxThreadsPerBlock = m_device.maxCudaThreadsPerBlock(); + const int maxBlocksPerProcessor = m_device.maxCudaThreadsPerMultiProcessor() / maxThreadsPerBlock; + const int numMultiProcessors = m_device.getNumCudaMultiProcessors(); + const int warpSize = 32; + + switch (NumKernelDims) { + case 1: { + const int kernel_size = m_kernelImpl.dimensions().TotalSize(); + + const int numX = dimensions()[m_indices[0]]; + const int numP = dimensions().TotalSize() / numX; + int maxX; + dim3 block_size; + + const int single_stride_dim = + static_cast(Layout) == static_cast(ColMajor) + ? 0 + : m_inputImpl.dimensions().rank() - 1; + if (m_indices[0] == single_stride_dim) { + // Maximum the reuse + const int inner_dim = ((maxSharedMem / (sizeof(Scalar)) - kernel_size + 1 + 31) / 32) * 32; + maxX = numext::mini(inner_dim, numX); + const int maxP = numext::mini(maxSharedMem / ((kernel_size - 1 + maxX) * sizeof(Scalar)), numP); + block_size.x = numext::mini(maxThreadsPerBlock, maxX); + block_size.y = numext::mini(maxThreadsPerBlock / block_size.x, maxP); + } + else { + // Read as much as possible alongside the inner most dimension, that is the plane + const int inner_dim = maxSharedMem / ((warpSize + kernel_size) * sizeof(Scalar)); + const int maxP = numext::mini(inner_dim, numP); + maxX = numext::mini(maxSharedMem / (inner_dim * sizeof(Scalar)) - kernel_size + 1, numX); + + block_size.x = numext::mini(warpSize, maxX); + block_size.y = numext::mini(maxThreadsPerBlock/block_size.x, maxP); + } + + const int shared_mem = block_size.y * (maxX + kernel_size - 1) * sizeof(Scalar); + assert(shared_mem <= maxSharedMem); + + const int num_x_blocks = ceil(numX, maxX); + const int blocksPerProcessor = numext::mini(maxBlocksPerProcessor, maxSharedMem / shared_mem); + const int num_y_blocks = ceil(numMultiProcessors * blocksPerProcessor, num_x_blocks); + + dim3 num_blocks(num_x_blocks, numext::mini(num_y_blocks, ceil(numP, block_size.y))); + + + //cout << "launching 1D kernel with block_size.x: " << block_size.x << " block_size.y: " << block_size.y << " num_blocks.x: " << num_blocks.x << " num_blocks.y: " << num_blocks.y << " maxX: " << maxX << " shared_mem: " << shared_mem << " in stream " << m_device.stream() << endl; + + const array indices(m_indices[0]); + const array kernel_dims(m_kernelImpl.dimensions()[0]); + internal::IndexMapper indexMapper( + m_inputImpl.dimensions(), kernel_dims, indices); + switch(kernel_size) { + case 4: { + LAUNCH_CUDA_KERNEL((EigenConvolutionKernel1D, Index, InputDims, 4>), num_blocks, block_size, shared_mem, m_device, m_inputImpl, indexMapper, m_kernel, numP, numX, maxX, 4, data); + break; + } + case 7: { + LAUNCH_CUDA_KERNEL((EigenConvolutionKernel1D, Index, InputDims, 7>), num_blocks, block_size, shared_mem, m_device, m_inputImpl, indexMapper, m_kernel, numP, numX, maxX, 7, data); + break; + } + default: { + LAUNCH_CUDA_KERNEL((EigenConvolutionKernel1D, Index, InputDims, Dynamic>), num_blocks, block_size, shared_mem, m_device, m_inputImpl, indexMapper, m_kernel, numP, numX, maxX, kernel_size, data); + } + } + break; + } + + case 2: { + const int idxX = + static_cast(Layout) == static_cast(ColMajor) ? 0 : 1; + const int idxY = + static_cast(Layout) == static_cast(ColMajor) ? 1 : 0; + const int kernel_size_x = m_kernelImpl.dimensions()[idxX]; + const int kernel_size_y = m_kernelImpl.dimensions()[idxY]; + + const int numX = dimensions()[m_indices[idxX]]; + const int numY = dimensions()[m_indices[idxY]]; + const int numP = dimensions().TotalSize() / (numX*numY); + + const float scaling_factor = sqrtf(static_cast(maxSharedMem) / (sizeof(Scalar) * kernel_size_y * kernel_size_x)); + + // Snap maxX to warp size + int inner_dim = ((static_cast(scaling_factor * kernel_size_x) - kernel_size_x + 1 + 32) / 32) * 32; + const int maxX = numext::mini(inner_dim, numX); + const int maxY = numext::mini(maxSharedMem / (sizeof(Scalar) * (maxX + kernel_size_x - 1)) - kernel_size_y + 1, numY); + const int maxP = numext::mini(maxSharedMem / ((kernel_size_x - 1 + maxX) * (kernel_size_y - 1 + maxY) * sizeof(Scalar)), numP); + + dim3 block_size; + block_size.x = numext::mini(1024, maxX); + block_size.y = numext::mini(1024/block_size.x, maxY); + block_size.z = numext::mini(1024/(block_size.x*block_size.y), maxP); + + const int shared_mem = block_size.z * (maxX + kernel_size_x - 1) * (maxY + kernel_size_y - 1) * sizeof(Scalar); + assert(shared_mem <= maxSharedMem); + + const int num_x_blocks = ceil(numX, maxX); + const int num_y_blocks = ceil(numY, maxY); + const int blocksPerProcessor = numext::mini(maxBlocksPerProcessor, maxSharedMem / shared_mem); + const int num_z_blocks = ceil(numMultiProcessors * blocksPerProcessor, num_x_blocks * num_y_blocks); + + dim3 num_blocks(num_x_blocks, num_y_blocks, numext::mini(num_z_blocks, ceil(numP, block_size.z))); + + + //cout << "launching 2D kernel with block_size.x: " << block_size.x << " block_size.y: " << block_size.y << " block_size.z: " << block_size.z << " num_blocks.x: " << num_blocks.x << " num_blocks.y: " << num_blocks.y << " num_blocks.z: " << num_blocks.z << " maxX: " << maxX << " maxY: " << maxY << " maxP: " << maxP << " shared_mem: " << shared_mem << " in stream " << m_device.stream() << endl; + + const array indices(m_indices[idxX], m_indices[idxY]); + const array kernel_dims(m_kernelImpl.dimensions()[idxX], + m_kernelImpl.dimensions()[idxY]); + internal::IndexMapper indexMapper( + m_inputImpl.dimensions(), kernel_dims, indices); + switch (kernel_size_x) { + case 4: { + switch (kernel_size_y) { + case 7: { + LAUNCH_CUDA_KERNEL((EigenConvolutionKernel2D, Index, InputDims, 4, 7>), num_blocks, block_size, shared_mem, m_device, m_inputImpl, indexMapper, m_kernel, numP, numX, maxX, numY, maxY, 4, 7, data); + break; + } + default: { + LAUNCH_CUDA_KERNEL((EigenConvolutionKernel2D, Index, InputDims, 4, Dynamic>), num_blocks, block_size, shared_mem, m_device, m_inputImpl, indexMapper, m_kernel, numP, numX, maxX, numY, maxY, 4, kernel_size_y, data); + break; + } + } + break; + } + case 7: { + switch (kernel_size_y) { + case 4: { + LAUNCH_CUDA_KERNEL((EigenConvolutionKernel2D, Index, InputDims, 7, 4>), num_blocks, block_size, shared_mem, m_device, m_inputImpl, indexMapper, m_kernel, numP, numX, maxX, numY, maxY, 7, 4, data); + break; + } + default: { + LAUNCH_CUDA_KERNEL((EigenConvolutionKernel2D, Index, InputDims, 7, Dynamic>), num_blocks, block_size, shared_mem, m_device, m_inputImpl, indexMapper, m_kernel, numP, numX, maxX, numY, maxY, 7, kernel_size_y, data); + break; + } + } + break; + } + default: { + LAUNCH_CUDA_KERNEL((EigenConvolutionKernel2D, Index, InputDims, Dynamic, Dynamic>), num_blocks, block_size, shared_mem, m_device, m_inputImpl, indexMapper, m_kernel, numP, numX, maxX, numY, maxY, kernel_size_x, kernel_size_y, data); + break; + } + } + break; + } + + case 3: { + const int idxX = + static_cast(Layout) == static_cast(ColMajor) ? 0 : 2; + const int idxY = + static_cast(Layout) == static_cast(ColMajor) ? 1 : 1; + const int idxZ = + static_cast(Layout) == static_cast(ColMajor) ? 2 : 0; + + const int kernel_size_x = m_kernelImpl.dimensions()[idxX]; + const int kernel_size_y = m_kernelImpl.dimensions()[idxY]; + const int kernel_size_z = m_kernelImpl.dimensions()[idxZ]; + + const int numX = dimensions()[m_indices[idxX]]; + const int numY = dimensions()[m_indices[idxY]]; + const int numZ = dimensions()[m_indices[idxZ]]; + const int numP = dimensions().TotalSize() / (numX*numY*numZ); + + const int maxX = numext::mini(128, numext::mini(maxSharedMem / (sizeof(Scalar) * kernel_size_y * kernel_size_z) - kernel_size_x + 1, numX)); + const int maxY = numext::mini(128, numext::mini(maxSharedMem / (sizeof(Scalar) * (maxX + kernel_size_x - 1) * kernel_size_z) - kernel_size_y + 1, numY)); + const int maxZ = numext::mini(128, numext::mini(maxSharedMem / (sizeof(Scalar) * (maxX + kernel_size_x - 1) * (maxY + kernel_size_y - 1)) - kernel_size_z + 1, numZ)); + + dim3 block_size; + block_size.x = numext::mini(32, maxX); + block_size.y = numext::mini(32, maxY); + block_size.z = numext::mini(1024/(block_size.x*block_size.y), maxZ); + dim3 num_blocks(ceil(numX, maxX), ceil(numY, maxY), ceil(numZ, maxZ)); + + const int shared_mem = (maxX + kernel_size_x - 1) * (maxY + kernel_size_y - 1) * (maxZ + kernel_size_z - 1) * sizeof(Scalar); + assert(shared_mem <= maxSharedMem); + + //cout << "launching 3D kernel with block_size.x: " << block_size.x << " block_size.y: " << block_size.y << " block_size.z: " << block_size.z << " num_blocks.x: " << num_blocks.x << " num_blocks.y: " << num_blocks.y << " num_blocks.z: " << num_blocks.z << " shared_mem: " << shared_mem << " in stream " << m_device.stream() << endl; + const array indices(m_indices[idxX], m_indices[idxY], + m_indices[idxZ]); + const array kernel_dims(m_kernelImpl.dimensions()[idxX], + m_kernelImpl.dimensions()[idxY], + m_kernelImpl.dimensions()[idxZ]); + internal::IndexMapper indexMapper( + m_inputImpl.dimensions(), kernel_dims, indices); + + LAUNCH_CUDA_KERNEL((EigenConvolutionKernel3D, Index, InputDims>), num_blocks, block_size, shared_mem, m_device, m_inputImpl, indexMapper, m_kernel, numP, numX, maxX, numY, maxY, numZ, maxZ, kernel_size_x, kernel_size_y, kernel_size_z, data); + break; + } + + default: { + EIGEN_STATIC_ASSERT((NumKernelDims >= 1 && NumKernelDims <= 3), THIS_METHOD_IS_ONLY_FOR_OBJECTS_OF_A_SPECIFIC_SIZE); + } + } + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const + { + eigen_assert(m_buf); + eigen_assert(index < m_dimensions.TotalSize()); + return m_buf[index]; + } + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packet(const Index index) const + { + eigen_assert(m_buf); + eigen_assert(index < m_dimensions.TotalSize()); + return internal::ploadt(m_buf+index); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost + costPerCoeff(bool vectorized) const { + // TODO(rmlarsen): FIXME: For now, this is just a copy of the CPU cost + // model. + const double kernel_size = m_kernelImpl.dimensions().TotalSize(); + // We ignore the use of fused multiply-add. + const double convolve_compute_cost = + TensorOpCost::AddCost() + TensorOpCost::MulCost(); + const double firstIndex_compute_cost = + NumDims * + (2 * TensorOpCost::AddCost() + 2 * TensorOpCost::MulCost() + + TensorOpCost::DivCost()); + return TensorOpCost(0, 0, firstIndex_compute_cost, vectorized, PacketSize) + + kernel_size * (m_inputImpl.costPerCoeff(vectorized) + + m_kernelImpl.costPerCoeff(vectorized) + + TensorOpCost(0, 0, convolve_compute_cost, vectorized, + PacketSize)); + } + + private: + // No assignment (copies are needed by the kernels) + TensorEvaluator& operator = (const TensorEvaluator&); + + TensorEvaluator m_inputImpl; + TensorEvaluator m_kernelImpl; + KernelArgType m_kernelArg; + Indices m_indices; + Dimensions m_dimensions; + Scalar* m_buf; + const Scalar* m_kernel; + bool m_local_kernel; + + const GpuDevice& m_device; +}; +#endif + + +} // end namespace Eigen + +#endif // EIGEN_CXX11_TENSOR_TENSOR_CONVOLUTION_H diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorCostModel.h b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorCostModel.h new file mode 100644 index 0000000000..83c449cf19 --- /dev/null +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorCostModel.h @@ -0,0 +1,212 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2016 Rasmus Munk Larsen +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CXX11_TENSOR_TENSOR_COST_MODEL_H +#define EIGEN_CXX11_TENSOR_TENSOR_COST_MODEL_H + +namespace Eigen { + +/** \class TensorEvaluator + * \ingroup CXX11_Tensor_Module + * + * \brief A cost model used to limit the number of threads used for evaluating + * tensor expression. + * + */ + +// Class storing the cost of evaluating a tensor expression in terms of the +// estimated number of operand bytes loads, bytes stored, and compute cycles. +class TensorOpCost { + public: + // TODO(rmlarsen): Fix the scalar op costs in Eigen proper. Even a simple + // model based on minimal reciprocal throughput numbers from Intel or + // Agner Fog's tables would be better than what is there now. + template + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE int MulCost() { + return internal::functor_traits< + internal::scalar_product_op >::Cost; + } + template + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE int AddCost() { + return internal::functor_traits >::Cost; + } + template + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE int DivCost() { + return internal::functor_traits< + internal::scalar_quotient_op >::Cost; + } + template + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE int ModCost() { + return internal::functor_traits >::Cost; + } + template + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE int CastCost() { + return internal::functor_traits< + internal::scalar_cast_op >::Cost; + } + + EIGEN_DEVICE_FUNC + TensorOpCost() : bytes_loaded_(0), bytes_stored_(0), compute_cycles_(0) {} + EIGEN_DEVICE_FUNC + TensorOpCost(double bytes_loaded, double bytes_stored, double compute_cycles) + : bytes_loaded_(bytes_loaded), + bytes_stored_(bytes_stored), + compute_cycles_(compute_cycles) {} + + EIGEN_DEVICE_FUNC + TensorOpCost(double bytes_loaded, double bytes_stored, double compute_cycles, + bool vectorized, double packet_size) + : bytes_loaded_(bytes_loaded), + bytes_stored_(bytes_stored), + compute_cycles_(vectorized ? compute_cycles / packet_size + : compute_cycles) { + eigen_assert(bytes_loaded >= 0 && (numext::isfinite)(bytes_loaded)); + eigen_assert(bytes_stored >= 0 && (numext::isfinite)(bytes_stored)); + eigen_assert(compute_cycles >= 0 && (numext::isfinite)(compute_cycles)); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE double bytes_loaded() const { + return bytes_loaded_; + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE double bytes_stored() const { + return bytes_stored_; + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE double compute_cycles() const { + return compute_cycles_; + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE double total_cost( + double load_cost, double store_cost, double compute_cost) const { + return load_cost * bytes_loaded_ + store_cost * bytes_stored_ + + compute_cost * compute_cycles_; + } + + // Drop memory access component. Intended for cases when memory accesses are + // sequential or are completely masked by computations. + EIGEN_DEVICE_FUNC void dropMemoryCost() { + bytes_loaded_ = 0; + bytes_stored_ = 0; + } + + // TODO(rmlarsen): Define min in terms of total cost, not elementwise. + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost cwiseMin( + const TensorOpCost& rhs) const { + double bytes_loaded = numext::mini(bytes_loaded_, rhs.bytes_loaded()); + double bytes_stored = numext::mini(bytes_stored_, rhs.bytes_stored()); + double compute_cycles = numext::mini(compute_cycles_, rhs.compute_cycles()); + return TensorOpCost(bytes_loaded, bytes_stored, compute_cycles); + } + + // TODO(rmlarsen): Define max in terms of total cost, not elementwise. + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost cwiseMax( + const TensorOpCost& rhs) const { + double bytes_loaded = numext::maxi(bytes_loaded_, rhs.bytes_loaded()); + double bytes_stored = numext::maxi(bytes_stored_, rhs.bytes_stored()); + double compute_cycles = numext::maxi(compute_cycles_, rhs.compute_cycles()); + return TensorOpCost(bytes_loaded, bytes_stored, compute_cycles); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost& operator+=( + const TensorOpCost& rhs) { + bytes_loaded_ += rhs.bytes_loaded(); + bytes_stored_ += rhs.bytes_stored(); + compute_cycles_ += rhs.compute_cycles(); + return *this; + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost& operator*=(double rhs) { + bytes_loaded_ *= rhs; + bytes_stored_ *= rhs; + compute_cycles_ *= rhs; + return *this; + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE friend TensorOpCost operator+( + TensorOpCost lhs, const TensorOpCost& rhs) { + lhs += rhs; + return lhs; + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE friend TensorOpCost operator*( + TensorOpCost lhs, double rhs) { + lhs *= rhs; + return lhs; + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE friend TensorOpCost operator*( + double lhs, TensorOpCost rhs) { + rhs *= lhs; + return rhs; + } + + friend std::ostream& operator<<(std::ostream& os, const TensorOpCost& tc) { + return os << "[bytes_loaded = " << tc.bytes_loaded() + << ", bytes_stored = " << tc.bytes_stored() + << ", compute_cycles = " << tc.compute_cycles() << "]"; + } + + private: + double bytes_loaded_; + double bytes_stored_; + double compute_cycles_; +}; + +// TODO(rmlarsen): Implement a policy that chooses an "optimal" number of theads +// in [1:max_threads] instead of just switching multi-threading off for small +// work units. +template +class TensorCostModel { + public: + // Scaling from Eigen compute cost to device cycles. + static const int kDeviceCyclesPerComputeCycle = 1; + + // Costs in device cycles. + static const int kStartupCycles = 100000; + static const int kPerThreadCycles = 100000; + static const int kTaskSize = 40000; + + // Returns the number of threads in [1:max_threads] to use for + // evaluating an expression with the given output size and cost per + // coefficient. + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE int numThreads( + double output_size, const TensorOpCost& cost_per_coeff, int max_threads) { + double cost = totalCost(output_size, cost_per_coeff); + int threads = (cost - kStartupCycles) / kPerThreadCycles + 0.9; + return numext::mini(max_threads, numext::maxi(1, threads)); + } + + // taskSize assesses parallel task size. + // Value of 1.0 means ideal parallel task size. Values < 1.0 mean that task + // granularity needs to be increased to mitigate parallelization overheads. + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE double taskSize( + double output_size, const TensorOpCost& cost_per_coeff) { + return totalCost(output_size, cost_per_coeff) / kTaskSize; + } + + private: + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE double totalCost( + double output_size, const TensorOpCost& cost_per_coeff) { + // Cost of memory fetches from L2 cache. 64 is typical cache line size. + // 11 is L2 cache latency on Haswell. + // We don't know whether data is in L1, L2 or L3. But we are most interested + // in single-threaded computational time around 100us-10ms (smaller time + // is too small for parallelization, larger time is not intersting + // either because we are probably using all available threads already). + // And for the target time range, L2 seems to be what matters. Data set + // fitting into L1 is too small to take noticeable time. Data set fitting + // only into L3 presumably will take more than 10ms to load and process. + const double kLoadCycles = 1.0 / 64 * 11; + const double kStoreCycles = 1.0 / 64 * 11; + // Scaling from Eigen compute cost to device cycles. + return output_size * + cost_per_coeff.total_cost(kLoadCycles, kStoreCycles, + kDeviceCyclesPerComputeCycle); + } +}; + +} // namespace Eigen + +#endif // EIGEN_CXX11_TENSOR_TENSOR_COST_MODEL_H diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorCustomOp.h b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorCustomOp.h new file mode 100644 index 0000000000..e020d076f0 --- /dev/null +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorCustomOp.h @@ -0,0 +1,313 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Benoit Steiner +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CXX11_TENSOR_TENSOR_CUSTOM_OP_H +#define EIGEN_CXX11_TENSOR_TENSOR_CUSTOM_OP_H + +namespace Eigen { + +/** \class TensorCustomUnaryOp + * \ingroup CXX11_Tensor_Module + * + * \brief Tensor custom class. + * + * + */ +namespace internal { +template +struct traits > +{ + typedef typename XprType::Scalar Scalar; + typedef typename XprType::StorageKind StorageKind; + typedef typename XprType::Index Index; + typedef typename XprType::Nested Nested; + typedef typename remove_reference::type _Nested; + static const int NumDimensions = traits::NumDimensions; + static const int Layout = traits::Layout; +}; + +template +struct eval, Eigen::Dense> +{ + typedef const TensorCustomUnaryOp& type; +}; + +template +struct nested > +{ + typedef TensorCustomUnaryOp type; +}; + +} // end namespace internal + + + +template +class TensorCustomUnaryOp : public TensorBase, ReadOnlyAccessors> +{ + public: + typedef typename internal::traits::Scalar Scalar; + typedef typename Eigen::NumTraits::Real RealScalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + typedef typename internal::nested::type Nested; + typedef typename internal::traits::StorageKind StorageKind; + typedef typename internal::traits::Index Index; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorCustomUnaryOp(const XprType& expr, const CustomUnaryFunc& func) + : m_expr(expr), m_func(func) {} + + EIGEN_DEVICE_FUNC + const CustomUnaryFunc& func() const { return m_func; } + + EIGEN_DEVICE_FUNC + const typename internal::remove_all::type& + expression() const { return m_expr; } + + protected: + typename XprType::Nested m_expr; + const CustomUnaryFunc m_func; +}; + + +// Eval as rvalue +template +struct TensorEvaluator, Device> +{ + typedef TensorCustomUnaryOp ArgType; + typedef typename internal::traits::Index Index; + static const int NumDims = internal::traits::NumDimensions; + typedef DSizes Dimensions; + typedef typename internal::remove_const::type Scalar; + typedef typename internal::remove_const::type CoeffReturnType; + typedef typename PacketType::type PacketReturnType; + static const int PacketSize = internal::unpacket_traits::size; + + enum { + IsAligned = false, + PacketAccess = (internal::packet_traits::size > 1), + BlockAccess = false, + Layout = TensorEvaluator::Layout, + CoordAccess = false, // to be implemented + RawAccess = false + }; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorEvaluator(const ArgType& op, const Device& device) + : m_op(op), m_device(device), m_result(NULL) + { + m_dimensions = op.func().dimensions(op.expression()); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Dimensions& dimensions() const { return m_dimensions; } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(CoeffReturnType* data) { + if (data) { + evalTo(data); + return false; + } else { + m_result = static_cast( + m_device.allocate(dimensions().TotalSize() * sizeof(Scalar))); + evalTo(m_result); + return true; + } + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void cleanup() { + if (m_result != NULL) { + m_device.deallocate(m_result); + m_result = NULL; + } + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const { + return m_result[index]; + } + + template + EIGEN_DEVICE_FUNC PacketReturnType packet(Index index) const { + return internal::ploadt(m_result + index); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost costPerCoeff(bool vectorized) const { + // TODO(rmlarsen): Extend CustomOp API to return its cost estimate. + return TensorOpCost(sizeof(CoeffReturnType), 0, 0, vectorized, PacketSize); + } + + EIGEN_DEVICE_FUNC CoeffReturnType* data() const { return m_result; } + + protected: + EIGEN_DEVICE_FUNC void evalTo(Scalar* data) { + TensorMap > result( + data, m_dimensions); + m_op.func().eval(m_op.expression(), result, m_device); + } + + Dimensions m_dimensions; + const ArgType m_op; + const Device& m_device; + CoeffReturnType* m_result; +}; + + + +/** \class TensorCustomBinaryOp + * \ingroup CXX11_Tensor_Module + * + * \brief Tensor custom class. + * + * + */ +namespace internal { +template +struct traits > +{ + typedef typename internal::promote_storage_type::ret Scalar; + typedef typename internal::promote_storage_type::ret CoeffReturnType; + typedef typename promote_storage_type::StorageKind, + typename traits::StorageKind>::ret StorageKind; + typedef typename promote_index_type::Index, + typename traits::Index>::type Index; + typedef typename LhsXprType::Nested LhsNested; + typedef typename RhsXprType::Nested RhsNested; + typedef typename remove_reference::type _LhsNested; + typedef typename remove_reference::type _RhsNested; + static const int NumDimensions = traits::NumDimensions; + static const int Layout = traits::Layout; +}; + +template +struct eval, Eigen::Dense> +{ + typedef const TensorCustomBinaryOp& type; +}; + +template +struct nested > +{ + typedef TensorCustomBinaryOp type; +}; + +} // end namespace internal + + + +template +class TensorCustomBinaryOp : public TensorBase, ReadOnlyAccessors> +{ + public: + typedef typename internal::traits::Scalar Scalar; + typedef typename Eigen::NumTraits::Real RealScalar; + typedef typename internal::traits::CoeffReturnType CoeffReturnType; + typedef typename internal::nested::type Nested; + typedef typename internal::traits::StorageKind StorageKind; + typedef typename internal::traits::Index Index; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorCustomBinaryOp(const LhsXprType& lhs, const RhsXprType& rhs, const CustomBinaryFunc& func) + + : m_lhs_xpr(lhs), m_rhs_xpr(rhs), m_func(func) {} + + EIGEN_DEVICE_FUNC + const CustomBinaryFunc& func() const { return m_func; } + + EIGEN_DEVICE_FUNC + const typename internal::remove_all::type& + lhsExpression() const { return m_lhs_xpr; } + + EIGEN_DEVICE_FUNC + const typename internal::remove_all::type& + rhsExpression() const { return m_rhs_xpr; } + + protected: + typename LhsXprType::Nested m_lhs_xpr; + typename RhsXprType::Nested m_rhs_xpr; + const CustomBinaryFunc m_func; +}; + + +// Eval as rvalue +template +struct TensorEvaluator, Device> +{ + typedef TensorCustomBinaryOp XprType; + typedef typename internal::traits::Index Index; + static const int NumDims = internal::traits::NumDimensions; + typedef DSizes Dimensions; + typedef typename XprType::Scalar Scalar; + typedef typename internal::remove_const::type CoeffReturnType; + typedef typename PacketType::type PacketReturnType; + static const int PacketSize = internal::unpacket_traits::size; + + enum { + IsAligned = false, + PacketAccess = (internal::packet_traits::size > 1), + BlockAccess = false, + Layout = TensorEvaluator::Layout, + CoordAccess = false, // to be implemented + RawAccess = false + }; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorEvaluator(const XprType& op, const Device& device) + : m_op(op), m_device(device), m_result(NULL) + { + m_dimensions = op.func().dimensions(op.lhsExpression(), op.rhsExpression()); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Dimensions& dimensions() const { return m_dimensions; } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(CoeffReturnType* data) { + if (data) { + evalTo(data); + return false; + } else { + m_result = static_cast(m_device.allocate(dimensions().TotalSize() * sizeof(Scalar))); + evalTo(m_result); + return true; + } + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void cleanup() { + if (m_result != NULL) { + m_device.deallocate(m_result); + m_result = NULL; + } + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const { + return m_result[index]; + } + + template + EIGEN_DEVICE_FUNC PacketReturnType packet(Index index) const { + return internal::ploadt(m_result + index); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost costPerCoeff(bool vectorized) const { + // TODO(rmlarsen): Extend CustomOp API to return its cost estimate. + return TensorOpCost(sizeof(CoeffReturnType), 0, 0, vectorized, PacketSize); + } + + EIGEN_DEVICE_FUNC CoeffReturnType* data() const { return m_result; } + + protected: + EIGEN_DEVICE_FUNC void evalTo(Scalar* data) { + TensorMap > result(data, m_dimensions); + m_op.func().eval(m_op.lhsExpression(), m_op.rhsExpression(), result, m_device); + } + + Dimensions m_dimensions; + const XprType m_op; + const Device& m_device; + CoeffReturnType* m_result; +}; + + +} // end namespace Eigen + +#endif // EIGEN_CXX11_TENSOR_TENSOR_CUSTOM_OP_H diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorDevice.h b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorDevice.h new file mode 100644 index 0000000000..29e50a3b2d --- /dev/null +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorDevice.h @@ -0,0 +1,68 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Benoit Steiner +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CXX11_TENSOR_TENSOR_DEVICE_H +#define EIGEN_CXX11_TENSOR_TENSOR_DEVICE_H + +namespace Eigen { + +/** \class TensorDevice + * \ingroup CXX11_Tensor_Module + * + * \brief Pseudo expression providing an operator = that will evaluate its argument + * on the specified computing 'device' (GPU, thread pool, ...) + * + * Example: + * C.device(EIGEN_GPU) = A + B; + * + * Todo: operator *= and /=. + */ + +template class TensorDevice { + public: + TensorDevice(const DeviceType& device, ExpressionType& expression) : m_device(device), m_expression(expression) {} + + template + EIGEN_STRONG_INLINE TensorDevice& operator=(const OtherDerived& other) { + typedef TensorAssignOp Assign; + Assign assign(m_expression, other); + internal::TensorExecutor::run(assign, m_device); + return *this; + } + + template + EIGEN_STRONG_INLINE TensorDevice& operator+=(const OtherDerived& other) { + typedef typename OtherDerived::Scalar Scalar; + typedef TensorCwiseBinaryOp, const ExpressionType, const OtherDerived> Sum; + Sum sum(m_expression, other); + typedef TensorAssignOp Assign; + Assign assign(m_expression, sum); + internal::TensorExecutor::run(assign, m_device); + return *this; + } + + template + EIGEN_STRONG_INLINE TensorDevice& operator-=(const OtherDerived& other) { + typedef typename OtherDerived::Scalar Scalar; + typedef TensorCwiseBinaryOp, const ExpressionType, const OtherDerived> Difference; + Difference difference(m_expression, other); + typedef TensorAssignOp Assign; + Assign assign(m_expression, difference); + internal::TensorExecutor::run(assign, m_device); + return *this; + } + + protected: + const DeviceType& m_device; + ExpressionType& m_expression; +}; + +} // end namespace Eigen + +#endif // EIGEN_CXX11_TENSOR_TENSOR_DEVICE_H diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorDeviceCuda.h b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorDeviceCuda.h new file mode 100644 index 0000000000..4f5767bc7f --- /dev/null +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorDeviceCuda.h @@ -0,0 +1,337 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Benoit Steiner +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#if defined(EIGEN_USE_GPU) && !defined(EIGEN_CXX11_TENSOR_TENSOR_DEVICE_CUDA_H) +#define EIGEN_CXX11_TENSOR_TENSOR_DEVICE_CUDA_H + +namespace Eigen { + +static const int kCudaScratchSize = 1024; + +// This defines an interface that GPUDevice can take to use +// CUDA streams underneath. +class StreamInterface { + public: + virtual ~StreamInterface() {} + + virtual const cudaStream_t& stream() const = 0; + virtual const cudaDeviceProp& deviceProperties() const = 0; + + // Allocate memory on the actual device where the computation will run + virtual void* allocate(size_t num_bytes) const = 0; + virtual void deallocate(void* buffer) const = 0; + + // Return a scratchpad buffer of size 1k + virtual void* scratchpad() const = 0; + + // Return a semaphore. The semaphore is initially initialized to 0, and + // each kernel using it is responsible for resetting to 0 upon completion + // to maintain the invariant that the semaphore is always equal to 0 upon + // each kernel start. + virtual unsigned int* semaphore() const = 0; +}; + +static cudaDeviceProp* m_deviceProperties; +static bool m_devicePropInitialized = false; + +static void initializeDeviceProp() { + if (!m_devicePropInitialized) { + // Attempts to ensure proper behavior in the case of multiple threads + // calling this function simultaneously. This would be trivial to + // implement if we could use std::mutex, but unfortunately mutex don't + // compile with nvcc, so we resort to atomics and thread fences instead. + // Note that if the caller uses a compiler that doesn't support c++11 we + // can't ensure that the initialization is thread safe. +#if __cplusplus >= 201103L + static std::atomic first(true); + if (first.exchange(false)) { +#else + static bool first = true; + if (first) { + first = false; +#endif + // We're the first thread to reach this point. + int num_devices; + cudaError_t status = cudaGetDeviceCount(&num_devices); + if (status != cudaSuccess) { + std::cerr << "Failed to get the number of CUDA devices: " + << cudaGetErrorString(status) + << std::endl; + assert(status == cudaSuccess); + } + m_deviceProperties = new cudaDeviceProp[num_devices]; + for (int i = 0; i < num_devices; ++i) { + status = cudaGetDeviceProperties(&m_deviceProperties[i], i); + if (status != cudaSuccess) { + std::cerr << "Failed to initialize CUDA device #" + << i + << ": " + << cudaGetErrorString(status) + << std::endl; + assert(status == cudaSuccess); + } + } + +#if __cplusplus >= 201103L + std::atomic_thread_fence(std::memory_order_release); +#endif + m_devicePropInitialized = true; + } else { + // Wait for the other thread to inititialize the properties. + while (!m_devicePropInitialized) { +#if __cplusplus >= 201103L + std::atomic_thread_fence(std::memory_order_acquire); +#endif + sleep(1); + } + } + } +} + +static const cudaStream_t default_stream = cudaStreamDefault; + +class CudaStreamDevice : public StreamInterface { + public: + // Use the default stream on the current device + CudaStreamDevice() : stream_(&default_stream), scratch_(NULL), semaphore_(NULL) { + cudaGetDevice(&device_); + initializeDeviceProp(); + } + // Use the default stream on the specified device + CudaStreamDevice(int device) : stream_(&default_stream), device_(device), scratch_(NULL), semaphore_(NULL) { + initializeDeviceProp(); + } + // Use the specified stream. Note that it's the + // caller responsibility to ensure that the stream can run on + // the specified device. If no device is specified the code + // assumes that the stream is associated to the current gpu device. + CudaStreamDevice(const cudaStream_t* stream, int device = -1) + : stream_(stream), device_(device), scratch_(NULL), semaphore_(NULL) { + if (device < 0) { + cudaGetDevice(&device_); + } else { + int num_devices; + cudaError_t err = cudaGetDeviceCount(&num_devices); + EIGEN_UNUSED_VARIABLE(err) + assert(err == cudaSuccess); + assert(device < num_devices); + device_ = device; + } + initializeDeviceProp(); + } + + virtual ~CudaStreamDevice() { + if (scratch_) { + deallocate(scratch_); + } + } + + const cudaStream_t& stream() const { return *stream_; } + const cudaDeviceProp& deviceProperties() const { + return m_deviceProperties[device_]; + } + virtual void* allocate(size_t num_bytes) const { + cudaError_t err = cudaSetDevice(device_); + EIGEN_UNUSED_VARIABLE(err) + assert(err == cudaSuccess); + void* result; + err = cudaMalloc(&result, num_bytes); + assert(err == cudaSuccess); + assert(result != NULL); + return result; + } + virtual void deallocate(void* buffer) const { + cudaError_t err = cudaSetDevice(device_); + EIGEN_UNUSED_VARIABLE(err) + assert(err == cudaSuccess); + assert(buffer != NULL); + err = cudaFree(buffer); + assert(err == cudaSuccess); + } + + virtual void* scratchpad() const { + if (scratch_ == NULL) { + scratch_ = allocate(kCudaScratchSize + sizeof(unsigned int)); + } + return scratch_; + } + + virtual unsigned int* semaphore() const { + if (semaphore_ == NULL) { + char* scratch = static_cast(scratchpad()) + kCudaScratchSize; + semaphore_ = reinterpret_cast(scratch); + cudaError_t err = cudaMemsetAsync(semaphore_, 0, sizeof(unsigned int), *stream_); + EIGEN_UNUSED_VARIABLE(err) + assert(err == cudaSuccess); + } + return semaphore_; + } + + private: + const cudaStream_t* stream_; + int device_; + mutable void* scratch_; + mutable unsigned int* semaphore_; +}; + +struct GpuDevice { + // The StreamInterface is not owned: the caller is + // responsible for its initialization and eventual destruction. + explicit GpuDevice(const StreamInterface* stream) : stream_(stream), max_blocks_(INT_MAX) { + eigen_assert(stream); + } + explicit GpuDevice(const StreamInterface* stream, int num_blocks) : stream_(stream), max_blocks_(num_blocks) { + eigen_assert(stream); + } + // TODO(bsteiner): This is an internal API, we should not expose it. + EIGEN_STRONG_INLINE const cudaStream_t& stream() const { + return stream_->stream(); + } + + EIGEN_STRONG_INLINE void* allocate(size_t num_bytes) const { + return stream_->allocate(num_bytes); + } + + EIGEN_STRONG_INLINE void deallocate(void* buffer) const { + stream_->deallocate(buffer); + } + + EIGEN_STRONG_INLINE void* scratchpad() const { + return stream_->scratchpad(); + } + + EIGEN_STRONG_INLINE unsigned int* semaphore() const { + return stream_->semaphore(); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void memcpy(void* dst, const void* src, size_t n) const { +#ifndef __CUDA_ARCH__ + cudaError_t err = cudaMemcpyAsync(dst, src, n, cudaMemcpyDeviceToDevice, + stream_->stream()); + EIGEN_UNUSED_VARIABLE(err) + assert(err == cudaSuccess); +#else + eigen_assert(false && "The default device should be used instead to generate kernel code"); +#endif + } + + EIGEN_STRONG_INLINE void memcpyHostToDevice(void* dst, const void* src, size_t n) const { + cudaError_t err = + cudaMemcpyAsync(dst, src, n, cudaMemcpyHostToDevice, stream_->stream()); + EIGEN_UNUSED_VARIABLE(err) + assert(err == cudaSuccess); + } + + EIGEN_STRONG_INLINE void memcpyDeviceToHost(void* dst, const void* src, size_t n) const { + cudaError_t err = + cudaMemcpyAsync(dst, src, n, cudaMemcpyDeviceToHost, stream_->stream()); + EIGEN_UNUSED_VARIABLE(err) + assert(err == cudaSuccess); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void memset(void* buffer, int c, size_t n) const { +#ifndef __CUDA_ARCH__ + cudaError_t err = cudaMemsetAsync(buffer, c, n, stream_->stream()); + EIGEN_UNUSED_VARIABLE(err) + assert(err == cudaSuccess); +#else + eigen_assert(false && "The default device should be used instead to generate kernel code"); +#endif + } + + EIGEN_STRONG_INLINE size_t numThreads() const { + // FIXME + return 32; + } + + EIGEN_STRONG_INLINE size_t firstLevelCacheSize() const { + // FIXME + return 48*1024; + } + + EIGEN_STRONG_INLINE size_t lastLevelCacheSize() const { + // We won't try to take advantage of the l2 cache for the time being, and + // there is no l3 cache on cuda devices. + return firstLevelCacheSize(); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void synchronize() const { +#if defined(__CUDACC__) && !defined(__CUDA_ARCH__) + cudaError_t err = cudaStreamSynchronize(stream_->stream()); + if (err != cudaSuccess) { + std::cerr << "Error detected in CUDA stream: " + << cudaGetErrorString(err) + << std::endl; + assert(err == cudaSuccess); + } +#else + assert(false && "The default device should be used instead to generate kernel code"); +#endif + } + + EIGEN_STRONG_INLINE int getNumCudaMultiProcessors() const { + return stream_->deviceProperties().multiProcessorCount; + } + EIGEN_STRONG_INLINE int maxCudaThreadsPerBlock() const { + return stream_->deviceProperties().maxThreadsPerBlock; + } + EIGEN_STRONG_INLINE int maxCudaThreadsPerMultiProcessor() const { + return stream_->deviceProperties().maxThreadsPerMultiProcessor; + } + EIGEN_STRONG_INLINE int sharedMemPerBlock() const { + return stream_->deviceProperties().sharedMemPerBlock; + } + EIGEN_STRONG_INLINE int majorDeviceVersion() const { + return stream_->deviceProperties().major; + } + EIGEN_STRONG_INLINE int minorDeviceVersion() const { + return stream_->deviceProperties().minor; + } + + EIGEN_STRONG_INLINE int maxBlocks() const { + return max_blocks_; + } + + // This function checks if the CUDA runtime recorded an error for the + // underlying stream device. + inline bool ok() const { +#ifdef __CUDACC__ + cudaError_t error = cudaStreamQuery(stream_->stream()); + return (error == cudaSuccess) || (error == cudaErrorNotReady); +#else + return false; +#endif + } + + private: + const StreamInterface* stream_; + int max_blocks_; +}; + +#define LAUNCH_CUDA_KERNEL(kernel, gridsize, blocksize, sharedmem, device, ...) \ + (kernel) <<< (gridsize), (blocksize), (sharedmem), (device).stream() >>> (__VA_ARGS__); \ + assert(cudaGetLastError() == cudaSuccess); + + +// FIXME: Should be device and kernel specific. +#ifdef __CUDACC__ +static EIGEN_DEVICE_FUNC inline void setCudaSharedMemConfig(cudaSharedMemConfig config) { +#ifndef __CUDA_ARCH__ + cudaError_t status = cudaDeviceSetSharedMemConfig(config); + EIGEN_UNUSED_VARIABLE(status) + assert(status == cudaSuccess); +#else + EIGEN_UNUSED_VARIABLE(config) +#endif +} +#endif + +} // end namespace Eigen + +#endif // EIGEN_CXX11_TENSOR_TENSOR_DEVICE_CUDA_H diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorDeviceDefault.h b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorDeviceDefault.h new file mode 100644 index 0000000000..9d141395b7 --- /dev/null +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorDeviceDefault.h @@ -0,0 +1,81 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Benoit Steiner +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CXX11_TENSOR_TENSOR_DEVICE_DEFAULT_H +#define EIGEN_CXX11_TENSOR_TENSOR_DEVICE_DEFAULT_H + + +namespace Eigen { + +// Default device for the machine (typically a single cpu core) +struct DefaultDevice { + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void* allocate(size_t num_bytes) const { + return internal::aligned_malloc(num_bytes); + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void deallocate(void* buffer) const { + internal::aligned_free(buffer); + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void memcpy(void* dst, const void* src, size_t n) const { + ::memcpy(dst, src, n); + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void memcpyHostToDevice(void* dst, const void* src, size_t n) const { + memcpy(dst, src, n); + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void memcpyDeviceToHost(void* dst, const void* src, size_t n) const { + memcpy(dst, src, n); + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void memset(void* buffer, int c, size_t n) const { + ::memset(buffer, c, n); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE size_t numThreads() const { +#ifndef __CUDA_ARCH__ + // Running on the host CPU + return 1; +#else + // Running on a CUDA device + return 32; +#endif + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE size_t firstLevelCacheSize() const { +#ifndef __CUDA_ARCH__ + // Running on the host CPU + return l1CacheSize(); +#else + // Running on a CUDA device, return the amount of shared memory available. + return 48*1024; +#endif + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE size_t lastLevelCacheSize() const { +#ifndef __CUDA_ARCH__ + // Running single threaded on the host CPU + return l3CacheSize(); +#else + // Running on a CUDA device + return firstLevelCacheSize(); +#endif + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE int majorDeviceVersion() const { +#ifndef __CUDA_ARCH__ + // Running single threaded on the host CPU + // Should return an enum that encodes the ISA supported by the CPU + return 1; +#else + // Running on a CUDA device + return __CUDA_ARCH__ / 100; +#endif + } +}; + +} // namespace Eigen + +#endif // EIGEN_CXX11_TENSOR_TENSOR_DEVICE_DEFAULT_H diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorDeviceSycl.h b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorDeviceSycl.h new file mode 100644 index 0000000000..7c039890e2 --- /dev/null +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorDeviceSycl.h @@ -0,0 +1,122 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Mehdi Goli Codeplay Software Ltd. +// Ralph Potter Codeplay Software Ltd. +// Luke Iwanski Codeplay Software Ltd. +// Contact: +// Copyright (C) 2016 Benoit Steiner + +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#if defined(EIGEN_USE_SYCL) && !defined(EIGEN_CXX11_TENSOR_TENSOR_DEVICE_SYCL_H) +#define EIGEN_CXX11_TENSOR_TENSOR_DEVICE_SYCL_H + +namespace Eigen { +struct SyclDevice { + /// class members + /// sycl queue + mutable cl::sycl::queue m_queue; + /// std::map is the container used to make sure that we create only one buffer + /// per pointer. The lifespan of the buffer now depends on the lifespan of SyclDevice. + /// If a non-read-only pointer is needed to be accessed on the host we should manually deallocate it. + mutable std::map> buffer_map; + /// creating device by using selector + template SyclDevice(dev_Selector s) + : +#ifdef EIGEN_EXCEPTIONS + m_queue(cl::sycl::queue(s, [=](cl::sycl::exception_list l) { + for (const auto& e : l) { + try { + std::rethrow_exception(e); + } catch (cl::sycl::exception e) { + std::cout << e.what() << std::endl; + } + } + })) +#else + m_queue(cl::sycl::queue(s)) +#endif + {} + // destructor + ~SyclDevice() { deallocate_all(); } + + template void deallocate(T *p) const { + auto it = buffer_map.find(p); + if (it != buffer_map.end()) { + buffer_map.erase(it); + internal::aligned_free(p); + } + } + void deallocate_all() const { + std::map>::iterator it=buffer_map.begin(); + while (it!=buffer_map.end()) { + auto p=it->first; + buffer_map.erase(it); + internal::aligned_free(const_cast(p)); + it=buffer_map.begin(); + } + buffer_map.clear(); + } + + /// creation of sycl accessor for a buffer. This function first tries to find + /// the buffer in the buffer_map. If found it gets the accessor from it, if not, + ///the function then adds an entry by creating a sycl buffer for that particular pointer. + template inline cl::sycl::accessor + get_sycl_accessor(size_t num_bytes, cl::sycl::handler &cgh, const T * ptr) const { + return (get_sycl_buffer(num_bytes, ptr)->template get_access(cgh)); + } + + template inline std::pair>::iterator,bool> add_sycl_buffer(const T *ptr, size_t num_bytes) const { + using Type = cl::sycl::buffer; + std::pair>::iterator,bool> ret = buffer_map.insert(std::pair>(ptr, std::shared_ptr(new Type(cl::sycl::range<1>(num_bytes)), + [](void *dataMem) { delete static_cast(dataMem); }))); + (static_cast(buffer_map.at(ptr).get()))->set_final_data(nullptr); + return ret; + } + + template inline cl::sycl::buffer* get_sycl_buffer(size_t num_bytes,const T * ptr) const { + return static_cast*>(add_sycl_buffer(ptr, num_bytes).first->second.get()); + } + + /// allocating memory on the cpu + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void *allocate(size_t) const { + return internal::aligned_malloc(8); + } + + // some runtime conditions that can be applied here + bool isDeviceSuitable() const { return true; } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void memcpy(void *dst, const void *src, size_t n) const { + ::memcpy(dst, src, n); + } + + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void memcpyHostToDevice(T *dst, const T *src, size_t n) const { + auto host_acc= (static_cast*>(add_sycl_buffer(dst, n).first->second.get()))-> template get_access(); + memcpy(host_acc.get_pointer(), src, n); + } + /// whith the current implementation of sycl, the data is copied twice from device to host. This will be fixed soon. + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void memcpyDeviceToHost(T *dst, const T *src, size_t n) const { + auto it = buffer_map.find(src); + if (it != buffer_map.end()) { + auto host_acc= (static_cast*>(it->second.get()))-> template get_access(); + memcpy(dst,host_acc.get_pointer(), n); + } else{ + eigen_assert("no device memory found. The memory might be destroyed before creation"); + } + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void memset(void *buffer, int c, size_t n) const { + ::memset(buffer, c, n); + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE int majorDeviceVersion() const { + return 1; + } +}; + +} // end namespace Eigen + +#endif // EIGEN_CXX11_TENSOR_TENSOR_DEVICE_SYCL_H diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorDeviceThreadPool.h b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorDeviceThreadPool.h new file mode 100644 index 0000000000..069680a117 --- /dev/null +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorDeviceThreadPool.h @@ -0,0 +1,279 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Benoit Steiner +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#if defined(EIGEN_USE_THREADS) && !defined(EIGEN_CXX11_TENSOR_TENSOR_DEVICE_THREAD_POOL_H) +#define EIGEN_CXX11_TENSOR_TENSOR_DEVICE_THREAD_POOL_H + +namespace Eigen { + +// Use the SimpleThreadPool by default. We'll switch to the new non blocking +// thread pool later. +#ifndef EIGEN_USE_SIMPLE_THREAD_POOL +template using ThreadPoolTempl = NonBlockingThreadPoolTempl; +typedef NonBlockingThreadPool ThreadPool; +#else +template using ThreadPoolTempl = SimpleThreadPoolTempl; +typedef SimpleThreadPool ThreadPool; +#endif + + +// Barrier is an object that allows one or more threads to wait until +// Notify has been called a specified number of times. +class Barrier { + public: + Barrier(unsigned int count) : state_(count << 1), notified_(false) { + eigen_assert(((count << 1) >> 1) == count); + } + ~Barrier() { + eigen_assert((state_>>1) == 0); + } + + void Notify() { + unsigned int v = state_.fetch_sub(2, std::memory_order_acq_rel) - 2; + if (v != 1) { + eigen_assert(((v + 2) & ~1) != 0); + return; // either count has not dropped to 0, or waiter is not waiting + } + std::unique_lock l(mu_); + eigen_assert(!notified_); + notified_ = true; + cv_.notify_all(); + } + + void Wait() { + unsigned int v = state_.fetch_or(1, std::memory_order_acq_rel); + if ((v >> 1) == 0) return; + std::unique_lock l(mu_); + while (!notified_) { + cv_.wait(l); + } + } + + private: + std::mutex mu_; + std::condition_variable cv_; + std::atomic state_; // low bit is waiter flag + bool notified_; +}; + + +// Notification is an object that allows a user to to wait for another +// thread to signal a notification that an event has occurred. +// +// Multiple threads can wait on the same Notification object, +// but only one caller must call Notify() on the object. +struct Notification : Barrier { + Notification() : Barrier(1) {}; +}; + + +// Runs an arbitrary function and then calls Notify() on the passed in +// Notification. +template struct FunctionWrapperWithNotification +{ + static void run(Notification* n, Function f, Args... args) { + f(args...); + if (n) { + n->Notify(); + } + } +}; + +template struct FunctionWrapperWithBarrier +{ + static void run(Barrier* b, Function f, Args... args) { + f(args...); + if (b) { + b->Notify(); + } + } +}; + +template +static EIGEN_STRONG_INLINE void wait_until_ready(SyncType* n) { + if (n) { + n->Wait(); + } +} + + +// Build a thread pool device on top the an existing pool of threads. +struct ThreadPoolDevice { + // The ownership of the thread pool remains with the caller. + ThreadPoolDevice(ThreadPoolInterface* pool, int num_cores) : pool_(pool), num_threads_(num_cores) { } + + EIGEN_STRONG_INLINE void* allocate(size_t num_bytes) const { + return internal::aligned_malloc(num_bytes); + } + + EIGEN_STRONG_INLINE void deallocate(void* buffer) const { + internal::aligned_free(buffer); + } + + EIGEN_STRONG_INLINE void memcpy(void* dst, const void* src, size_t n) const { + ::memcpy(dst, src, n); + } + EIGEN_STRONG_INLINE void memcpyHostToDevice(void* dst, const void* src, size_t n) const { + memcpy(dst, src, n); + } + EIGEN_STRONG_INLINE void memcpyDeviceToHost(void* dst, const void* src, size_t n) const { + memcpy(dst, src, n); + } + + EIGEN_STRONG_INLINE void memset(void* buffer, int c, size_t n) const { + ::memset(buffer, c, n); + } + + EIGEN_STRONG_INLINE int numThreads() const { + return num_threads_; + } + + EIGEN_STRONG_INLINE size_t firstLevelCacheSize() const { + return l1CacheSize(); + } + + EIGEN_STRONG_INLINE size_t lastLevelCacheSize() const { + // The l3 cache size is shared between all the cores. + return l3CacheSize() / num_threads_; + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE int majorDeviceVersion() const { + // Should return an enum that encodes the ISA supported by the CPU + return 1; + } + + template + EIGEN_STRONG_INLINE Notification* enqueue(Function&& f, Args&&... args) const { + Notification* n = new Notification(); + pool_->Schedule(std::bind(&FunctionWrapperWithNotification::run, n, f, args...)); + return n; + } + + template + EIGEN_STRONG_INLINE void enqueue_with_barrier(Barrier* b, + Function&& f, + Args&&... args) const { + pool_->Schedule(std::bind( + &FunctionWrapperWithBarrier::run, b, f, args...)); + } + + template + EIGEN_STRONG_INLINE void enqueueNoNotification(Function&& f, Args&&... args) const { + pool_->Schedule(std::bind(f, args...)); + } + + // Returns a logical thread index between 0 and pool_->NumThreads() - 1 if + // called from one of the threads in pool_. Returns -1 otherwise. + EIGEN_STRONG_INLINE int currentThreadId() const { + return pool_->CurrentThreadId(); + } + + // parallelFor executes f with [0, n) arguments in parallel and waits for + // completion. F accepts a half-open interval [first, last). + // Block size is choosen based on the iteration cost and resulting parallel + // efficiency. If block_align is not nullptr, it is called to round up the + // block size. + void parallelFor(Index n, const TensorOpCost& cost, + std::function block_align, + std::function f) const { + typedef TensorCostModel CostModel; + if (n <= 1 || numThreads() == 1 || + CostModel::numThreads(n, cost, static_cast(numThreads())) == 1) { + f(0, n); + return; + } + + // Calculate block size based on (1) the iteration cost and (2) parallel + // efficiency. We want blocks to be not too small to mitigate + // parallelization overheads; not too large to mitigate tail + // effect and potential load imbalance and we also want number + // of blocks to be evenly dividable across threads. + + double block_size_f = 1.0 / CostModel::taskSize(1, cost); + Index block_size = numext::mini(n, numext::maxi(1, block_size_f)); + const Index max_block_size = + numext::mini(n, numext::maxi(1, 2 * block_size_f)); + if (block_align) { + Index new_block_size = block_align(block_size); + eigen_assert(new_block_size >= block_size); + block_size = numext::mini(n, new_block_size); + } + Index block_count = divup(n, block_size); + // Calculate parallel efficiency as fraction of total CPU time used for + // computations: + double max_efficiency = + static_cast(block_count) / + (divup(block_count, numThreads()) * numThreads()); + // Now try to increase block size up to max_block_size as long as it + // doesn't decrease parallel efficiency. + for (Index prev_block_count = block_count; prev_block_count > 1;) { + // This is the next block size that divides size into a smaller number + // of blocks than the current block_size. + Index coarser_block_size = divup(n, prev_block_count - 1); + if (block_align) { + Index new_block_size = block_align(coarser_block_size); + eigen_assert(new_block_size >= coarser_block_size); + coarser_block_size = numext::mini(n, new_block_size); + } + if (coarser_block_size > max_block_size) { + break; // Reached max block size. Stop. + } + // Recalculate parallel efficiency. + const Index coarser_block_count = divup(n, coarser_block_size); + eigen_assert(coarser_block_count < prev_block_count); + prev_block_count = coarser_block_count; + const double coarser_efficiency = + static_cast(coarser_block_count) / + (divup(coarser_block_count, numThreads()) * numThreads()); + if (coarser_efficiency + 0.01 >= max_efficiency) { + // Taking it. + block_size = coarser_block_size; + block_count = coarser_block_count; + if (max_efficiency < coarser_efficiency) { + max_efficiency = coarser_efficiency; + } + } + } + + // Recursively divide size into halves until we reach block_size. + // Division code rounds mid to block_size, so we are guaranteed to get + // block_count leaves that do actual computations. + Barrier barrier(static_cast(block_count)); + std::function handleRange; + handleRange = [=, &handleRange, &barrier, &f](Index first, Index last) { + if (last - first <= block_size) { + // Single block or less, execute directly. + f(first, last); + barrier.Notify(); + return; + } + // Split into halves and submit to the pool. + Index mid = first + divup((last - first) / 2, block_size) * block_size; + pool_->Schedule([=, &handleRange]() { handleRange(mid, last); }); + pool_->Schedule([=, &handleRange]() { handleRange(first, mid); }); + }; + handleRange(0, n); + barrier.Wait(); + } + + // Convenience wrapper for parallelFor that does not align blocks. + void parallelFor(Index n, const TensorOpCost& cost, + std::function f) const { + parallelFor(n, cost, nullptr, std::move(f)); + } + + private: + ThreadPoolInterface* pool_; + int num_threads_; +}; + + +} // end namespace Eigen + +#endif // EIGEN_CXX11_TENSOR_TENSOR_DEVICE_THREAD_POOL_H diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorDimensionList.h b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorDimensionList.h new file mode 100644 index 0000000000..1a30e45fb1 --- /dev/null +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorDimensionList.h @@ -0,0 +1,236 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2015 Benoit Steiner +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CXX11_TENSOR_TENSOR_DIMENSION_LIST_H +#define EIGEN_CXX11_TENSOR_TENSOR_DIMENSION_LIST_H + +namespace Eigen { + +/** \internal + * + * \class TensorDimensionList + * \ingroup CXX11_Tensor_Module + * + * \brief Special case of tensor index list used to list all the dimensions of a tensor of rank n. + * + * \sa Tensor + */ + +template struct DimensionList { + EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE + const Index operator[] (const Index i) const { return i; } +}; + +namespace internal { + +template struct array_size > { + static const size_t value = Rank; +}; +template struct array_size > { + static const size_t value = Rank; +}; + +template const Index array_get(DimensionList&) { + return n; +} +template const Index array_get(const DimensionList&) { + return n; +} + + +#if EIGEN_HAS_CONSTEXPR +template +struct index_known_statically_impl > { + EIGEN_DEVICE_FUNC static constexpr bool run(const DenseIndex) { + return true; + } +}; +template +struct index_known_statically_impl > { + EIGEN_DEVICE_FUNC static constexpr bool run(const DenseIndex) { + return true; + } +}; + +template +struct all_indices_known_statically_impl > { + EIGEN_DEVICE_FUNC static constexpr bool run() { + return true; + } +}; +template +struct all_indices_known_statically_impl > { + EIGEN_DEVICE_FUNC static constexpr bool run() { + return true; + } +}; + +template +struct indices_statically_known_to_increase_impl > { + EIGEN_DEVICE_FUNC static constexpr bool run() { + return true; + } +}; +template +struct indices_statically_known_to_increase_impl > { + EIGEN_DEVICE_FUNC static constexpr bool run() { + return true; + } +}; + +template +struct index_statically_eq_impl > { + static constexpr bool run(const DenseIndex i, const DenseIndex value) { + return i == value; + } +}; +template +struct index_statically_eq_impl > { + EIGEN_DEVICE_FUNC static constexpr bool run(const DenseIndex i, const DenseIndex value) { + return i == value; + } +}; + +template +struct index_statically_ne_impl > { + EIGEN_DEVICE_FUNC static constexpr bool run(const DenseIndex i, const DenseIndex value) { + return i != value; + } +}; +template +struct index_statically_ne_impl > { + static constexpr bool run(const DenseIndex i, const DenseIndex value) { + return i != value; + } +}; + +template +struct index_statically_gt_impl > { + EIGEN_DEVICE_FUNC static constexpr bool run(const DenseIndex i, const DenseIndex value) { + return i > value; + } +}; +template +struct index_statically_gt_impl > { + EIGEN_DEVICE_FUNC static constexpr bool run(const DenseIndex i, const DenseIndex value) { + return i > value; + } +}; + +template +struct index_statically_lt_impl > { + EIGEN_DEVICE_FUNC static constexpr bool run(const DenseIndex i, const DenseIndex value) { + return i < value; + } +}; +template +struct index_statically_lt_impl > { + EIGEN_DEVICE_FUNC static constexpr bool run(const DenseIndex i, const DenseIndex value) { + return i < value; + } +}; + +#else +template +struct index_known_statically_impl > { + EIGEN_DEVICE_FUNC static EIGEN_ALWAYS_INLINE bool run(const DenseIndex) { + return true; + } +}; +template +struct index_known_statically_impl > { + EIGEN_DEVICE_FUNC static EIGEN_ALWAYS_INLINE bool run(const DenseIndex) { + return true; + } +}; + +template +struct all_indices_known_statically_impl > { + EIGEN_DEVICE_FUNC static EIGEN_ALWAYS_INLINE bool run() { + return true; + } +}; +template +struct all_indices_known_statically_impl > { + EIGEN_DEVICE_FUNC static EIGEN_ALWAYS_INLINE bool run() { + return true; + } +}; + +template +struct indices_statically_known_to_increase_impl > { + static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool run() { + return true; + } +}; +template +struct indices_statically_known_to_increase_impl > { + static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool run() { + return true; + } +}; + +template +struct index_statically_eq_impl > { + static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool run(const DenseIndex, const DenseIndex) { + return false; + } +}; +template +struct index_statically_eq_impl > { + static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool run(const DenseIndex, const DenseIndex) { + return false; + } +}; + +template +struct index_statically_ne_impl > { + static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool run(const DenseIndex, const DenseIndex){ + return false; + } +}; +template +struct index_statically_ne_impl > { + static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool run(const DenseIndex, const DenseIndex) { + return false; + } +}; + +template +struct index_statically_gt_impl > { + static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool run(const DenseIndex, const DenseIndex) { + return false; + } +}; +template +struct index_statically_gt_impl > { + static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool run(const DenseIndex, const DenseIndex) { + return false; + } +}; + +template +struct index_statically_lt_impl > { + static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool run(const DenseIndex, const DenseIndex) { + return false; + } +}; +template +struct index_statically_lt_impl > { + static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool run(const DenseIndex, const DenseIndex) { + return false; + } +}; +#endif + +} // end namespace internal +} // end namespace Eigen + + +#endif // EIGEN_CXX11_TENSOR_TENSOR_DIMENSION_LIST_H diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorDimensions.h b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorDimensions.h new file mode 100644 index 0000000000..b24cdebf1e --- /dev/null +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorDimensions.h @@ -0,0 +1,428 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Benoit Steiner +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CXX11_TENSOR_TENSOR_DIMENSIONS_H +#define EIGEN_CXX11_TENSOR_TENSOR_DIMENSIONS_H + + +namespace Eigen { + +/** \internal + * + * \class TensorDimensions + * \ingroup CXX11_Tensor_Module + * + * \brief Set of classes used to encode and store the dimensions of a Tensor. + * + * The Sizes class encodes as part of the type the number of dimensions and the + * sizes corresponding to each dimension. It uses no storage space since it is + * entirely known at compile time. + * The DSizes class is its dynamic sibling: the number of dimensions is known + * at compile time but the sizes are set during execution. + * + * \sa Tensor + */ + +// Boilerplate code +namespace internal { + +template struct dget { + static const std::size_t value = get::value; +}; + + +template +struct fixed_size_tensor_index_linearization_helper +{ + template EIGEN_DEVICE_FUNC + static inline Index run(array const& indices, + const Dimensions& dimensions) + { + return array_get(indices) + + dget::value * + fixed_size_tensor_index_linearization_helper::run(indices, dimensions); + } +}; + +template +struct fixed_size_tensor_index_linearization_helper +{ + template EIGEN_DEVICE_FUNC + static inline Index run(array const&, const Dimensions&) + { + return 0; + } +}; + +template +struct fixed_size_tensor_index_extraction_helper +{ + template EIGEN_DEVICE_FUNC + static inline Index run(const Index index, + const Dimensions& dimensions) + { + const Index mult = (index == n-1) ? 1 : 0; + return array_get(dimensions) * mult + + fixed_size_tensor_index_extraction_helper::run(index, dimensions); + } +}; + +template +struct fixed_size_tensor_index_extraction_helper +{ + template EIGEN_DEVICE_FUNC + static inline Index run(const Index, + const Dimensions&) + { + return 0; + } + }; + +} // end namespace internal + + +// Fixed size +#ifndef EIGEN_EMULATE_CXX11_META_H +template +struct Sizes : internal::numeric_list { + typedef internal::numeric_list Base; + static const std::ptrdiff_t total_size = internal::arg_prod(Indices...); + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE std::ptrdiff_t rank() const { + return Base::count; + } + + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE std::ptrdiff_t TotalSize() { + return internal::arg_prod(Indices...); + } + + EIGEN_DEVICE_FUNC Sizes() { } + template + explicit EIGEN_DEVICE_FUNC Sizes(const array& /*indices*/) { + // todo: add assertion + } +#if EIGEN_HAS_VARIADIC_TEMPLATES + template EIGEN_DEVICE_FUNC Sizes(DenseIndex...) { } + explicit EIGEN_DEVICE_FUNC Sizes(std::initializer_list /*l*/) { + // todo: add assertion + } +#endif + + template Sizes& operator = (const T& /*other*/) { + // add assertion failure if the size of other is different + return *this; + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE std::ptrdiff_t operator[] (const std::size_t index) const { + return internal::fixed_size_tensor_index_extraction_helper::run(index, *this); + } + + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + size_t IndexOfColMajor(const array& indices) const { + return internal::fixed_size_tensor_index_linearization_helper::run(indices, *static_cast(this)); + } + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + size_t IndexOfRowMajor(const array& indices) const { + return internal::fixed_size_tensor_index_linearization_helper::run(indices, *static_cast(this)); + } +}; + +namespace internal { +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE std::ptrdiff_t array_prod(const Sizes&) { + return Sizes::total_size; +} +} + +#else + +template +struct non_zero_size { + typedef internal::type2val type; +}; +template <> +struct non_zero_size<0> { + typedef internal::null_type type; +}; + +template struct Sizes { + typedef typename internal::make_type_list::type, typename non_zero_size::type, typename non_zero_size::type, typename non_zero_size::type, typename non_zero_size::type >::type Base; + static const size_t count = Base::count; + static const std::size_t total_size = internal::arg_prod::value; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE size_t rank() const { + return count; + } + + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE size_t TotalSize() { + return internal::arg_prod::value; + } + + Sizes() { } + template + explicit Sizes(const array& /*indices*/) { + // todo: add assertion + } + template Sizes& operator = (const T& /*other*/) { + // add assertion failure if the size of other is different + return *this; + } + +#if EIGEN_HAS_VARIADIC_TEMPLATES + template Sizes(DenseIndex... /*indices*/) { } + explicit Sizes(std::initializer_list) { + // todo: add assertion + } +#else + EIGEN_DEVICE_FUNC explicit Sizes(const DenseIndex) { + } + EIGEN_DEVICE_FUNC Sizes(const DenseIndex, const DenseIndex) { + } + EIGEN_DEVICE_FUNC Sizes(const DenseIndex, const DenseIndex, const DenseIndex) { + } + EIGEN_DEVICE_FUNC Sizes(const DenseIndex, const DenseIndex, const DenseIndex, const DenseIndex) { + } + EIGEN_DEVICE_FUNC Sizes(const DenseIndex, const DenseIndex, const DenseIndex, const DenseIndex, const DenseIndex) { + } +#endif + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE DenseIndex operator[] (const int index) const { + switch (index) { + case 0: + return internal::get<0, Base>::value; + case 1: + return internal::get<1, Base>::value; + case 2: + return internal::get<2, Base>::value; + case 3: + return internal::get<3, Base>::value; + case 4: + return internal::get<4, Base>::value; + default: + eigen_assert(false && "index overflow"); + return static_cast(-1); + } + } + + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + size_t IndexOfColMajor(const array& indices) const { + return internal::fixed_size_tensor_index_linearization_helper::run(indices, *reinterpret_cast(this)); + } + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + size_t IndexOfRowMajor(const array& indices) const { + return internal::fixed_size_tensor_index_linearization_helper::run(indices, *reinterpret_cast(this)); + } +}; + +namespace internal { +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE std::size_t array_prod(const Sizes&) { + return Sizes::total_size; +} +} + +#endif + +// Boilerplate +namespace internal { +template +struct tensor_index_linearization_helper +{ + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Index run(array const& indices, array const& dimensions) + { + return array_get(indices) + + array_get(dimensions) * + tensor_index_linearization_helper::run(indices, dimensions); + } +}; + +template +struct tensor_index_linearization_helper +{ + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Index run(array const& indices, array const&) + { + return array_get(indices); + } +}; +} // end namespace internal + + + +// Dynamic size +template +struct DSizes : array { + typedef array Base; + static const int count = NumDims; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE size_t rank() const { + return NumDims; + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE DenseIndex TotalSize() const { + return (NumDims == 0) ? 1 : internal::array_prod(*static_cast(this)); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE DSizes() { + for (int i = 0 ; i < NumDims; ++i) { + (*this)[i] = 0; + } + } + EIGEN_DEVICE_FUNC explicit DSizes(const array& a) : Base(a) { } + + EIGEN_DEVICE_FUNC explicit DSizes(const DenseIndex i0) { + eigen_assert(NumDims == 1); + (*this)[0] = i0; + } + +#if EIGEN_HAS_VARIADIC_TEMPLATES + template EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE explicit DSizes(DenseIndex firstDimension, DenseIndex secondDimension, IndexTypes... otherDimensions) : Base({{firstDimension, secondDimension, otherDimensions...}}) { + EIGEN_STATIC_ASSERT(sizeof...(otherDimensions) + 2 == NumDims, YOU_MADE_A_PROGRAMMING_MISTAKE) + } +#else + EIGEN_DEVICE_FUNC DSizes(const DenseIndex i0, const DenseIndex i1) { + eigen_assert(NumDims == 2); + (*this)[0] = i0; + (*this)[1] = i1; + } + EIGEN_DEVICE_FUNC DSizes(const DenseIndex i0, const DenseIndex i1, const DenseIndex i2) { + eigen_assert(NumDims == 3); + (*this)[0] = i0; + (*this)[1] = i1; + (*this)[2] = i2; + } + EIGEN_DEVICE_FUNC DSizes(const DenseIndex i0, const DenseIndex i1, const DenseIndex i2, const DenseIndex i3) { + eigen_assert(NumDims == 4); + (*this)[0] = i0; + (*this)[1] = i1; + (*this)[2] = i2; + (*this)[3] = i3; + } + EIGEN_DEVICE_FUNC DSizes(const DenseIndex i0, const DenseIndex i1, const DenseIndex i2, const DenseIndex i3, const DenseIndex i4) { + eigen_assert(NumDims == 5); + (*this)[0] = i0; + (*this)[1] = i1; + (*this)[2] = i2; + (*this)[3] = i3; + (*this)[4] = i4; + } +#endif + + EIGEN_DEVICE_FUNC DSizes& operator = (const array& other) { + *static_cast(this) = other; + return *this; + } + + // A constexpr would be so much better here + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE DenseIndex IndexOfColMajor(const array& indices) const { + return internal::tensor_index_linearization_helper::run(indices, *static_cast(this)); + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE DenseIndex IndexOfRowMajor(const array& indices) const { + return internal::tensor_index_linearization_helper::run(indices, *static_cast(this)); + } +}; + + + + +// Boilerplate +namespace internal { +template +struct tensor_vsize_index_linearization_helper +{ + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Index run(array const& indices, std::vector const& dimensions) + { + return array_get(indices) + + array_get(dimensions) * + tensor_vsize_index_linearization_helper::run(indices, dimensions); + } +}; + +template +struct tensor_vsize_index_linearization_helper +{ + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Index run(array const& indices, std::vector const&) + { + return array_get(indices); + } +}; +} // end namespace internal + + +namespace internal { + +template struct array_size > { + static const size_t value = NumDims; +}; +template struct array_size > { + static const size_t value = NumDims; +}; +#ifndef EIGEN_EMULATE_CXX11_META_H +template struct array_size > { +static const std::ptrdiff_t value = Sizes::count; +}; +template struct array_size > { +static const std::ptrdiff_t value = Sizes::count; +}; +template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE std::ptrdiff_t array_get(const Sizes&) { + return get >::value; +} +template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE std::ptrdiff_t array_get(const Sizes<>&) { + eigen_assert(false && "should never be called"); + return -1; +} +#else +template struct array_size > { + static const size_t value = Sizes::count; +}; +template struct array_size > { + static const size_t value = Sizes::count; +}; +template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE std::size_t array_get(const Sizes&) { + return get::Base>::value; +} + +#endif + + +template +struct sizes_match_below_dim { + static EIGEN_DEVICE_FUNC inline bool run(Dims1&, Dims2&) { + return false; + } +}; +template +struct sizes_match_below_dim { + static EIGEN_DEVICE_FUNC inline bool run(Dims1& dims1, Dims2& dims2) { + return (array_get(dims1) == array_get(dims2)) & + sizes_match_below_dim::run(dims1, dims2); + } +}; +template +struct sizes_match_below_dim { + static EIGEN_DEVICE_FUNC inline bool run(Dims1&, Dims2&) { + return true; + } +}; + +} // end namespace internal + + +template +EIGEN_DEVICE_FUNC bool dimensions_match(Dims1& dims1, Dims2& dims2) { + return internal::sizes_match_below_dim::value, internal::array_size::value>::run(dims1, dims2); +} + +} // end namespace Eigen + +#endif // EIGEN_CXX11_TENSOR_TENSOR_DIMENSIONS_H diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorEvalTo.h b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorEvalTo.h new file mode 100644 index 0000000000..06987132b6 --- /dev/null +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorEvalTo.h @@ -0,0 +1,181 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Benoit Steiner +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CXX11_TENSOR_TENSOR_EVAL_TO_H +#define EIGEN_CXX11_TENSOR_TENSOR_EVAL_TO_H + +namespace Eigen { + +/** \class TensorForcedEval + * \ingroup CXX11_Tensor_Module + * + * \brief Tensor reshaping class. + * + * + */ +namespace internal { +template class MakePointer_> +struct traits > +{ + // Type promotion to handle the case where the types of the lhs and the rhs are different. + typedef typename XprType::Scalar Scalar; + typedef traits XprTraits; + typedef typename XprTraits::StorageKind StorageKind; + typedef typename XprTraits::Index Index; + typedef typename XprType::Nested Nested; + typedef typename remove_reference::type _Nested; + static const int NumDimensions = XprTraits::NumDimensions; + static const int Layout = XprTraits::Layout; + + enum { + Flags = 0 + }; + template + struct MakePointer { + // Intermediate typedef to workaround MSVC issue. + typedef MakePointer_ MakePointerT; + typedef typename MakePointerT::Type Type; + }; +}; + +template class MakePointer_> +struct eval, Eigen::Dense> +{ + typedef const TensorEvalToOp& type; +}; + +template class MakePointer_> +struct nested, 1, typename eval >::type> +{ + typedef TensorEvalToOp type; +}; + +} // end namespace internal + + + + +template class MakePointer_> +class TensorEvalToOp : public TensorBase, ReadOnlyAccessors> +{ + public: + typedef typename Eigen::internal::traits::Scalar Scalar; + typedef typename Eigen::NumTraits::Real RealScalar; + typedef typename internal::remove_const::type CoeffReturnType; + typedef typename MakePointer_::Type PointerType; + typedef typename Eigen::internal::nested::type Nested; + typedef typename Eigen::internal::traits::StorageKind StorageKind; + typedef typename Eigen::internal::traits::Index Index; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorEvalToOp(PointerType buffer, const XprType& expr) + : m_xpr(expr), m_buffer(buffer) {} + + EIGEN_DEVICE_FUNC + const typename internal::remove_all::type& + expression() const { return m_xpr; } + + EIGEN_DEVICE_FUNC PointerType buffer() const { return m_buffer; } + + protected: + typename XprType::Nested m_xpr; + PointerType m_buffer; +}; + + + +template class MakePointer_> +struct TensorEvaluator, Device> +{ + typedef TensorEvalToOp XprType; + typedef typename ArgType::Scalar Scalar; + typedef typename TensorEvaluator::Dimensions Dimensions; + typedef typename XprType::Index Index; + typedef typename internal::remove_const::type CoeffReturnType; + typedef typename PacketType::type PacketReturnType; + static const int PacketSize = internal::unpacket_traits::size; + + enum { + IsAligned = TensorEvaluator::IsAligned, + PacketAccess = TensorEvaluator::PacketAccess, + Layout = TensorEvaluator::Layout, + CoordAccess = false, // to be implemented + RawAccess = true + }; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorEvaluator(const XprType& op, const Device& device) + : m_impl(op.expression(), device), m_device(device), + m_buffer(op.buffer()), m_op(op), m_expression(op.expression()) + { } + + // Used for accessor extraction in SYCL Managed TensorMap: + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const XprType& op() const { + return m_op; + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE ~TensorEvaluator() { + } + + typedef typename internal::traits >::template MakePointer::Type DevicePointer; + EIGEN_DEVICE_FUNC const Dimensions& dimensions() const { return m_impl.dimensions(); } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(DevicePointer scalar) { + EIGEN_UNUSED_VARIABLE(scalar); + eigen_assert(scalar == NULL); + return m_impl.evalSubExprsIfNeeded(m_buffer); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void evalScalar(Index i) { + m_buffer[i] = m_impl.coeff(i); + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void evalPacket(Index i) { + internal::pstoret(m_buffer + i, m_impl.template packet::IsAligned ? Aligned : Unaligned>(i)); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void cleanup() { + m_impl.cleanup(); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const + { + return m_buffer[index]; + } + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packet(Index index) const + { + return internal::ploadt(m_buffer + index); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost costPerCoeff(bool vectorized) const { + // We assume that evalPacket or evalScalar is called to perform the + // assignment and account for the cost of the write here. + return m_impl.costPerCoeff(vectorized) + + TensorOpCost(0, sizeof(CoeffReturnType), 0, vectorized, PacketSize); + } + + EIGEN_DEVICE_FUNC DevicePointer data() const { return m_buffer; } + ArgType expression() const { return m_expression; } + + /// required by sycl in order to extract the accessor + const TensorEvaluator& impl() const { return m_impl; } + /// added for sycl in order to construct the buffer from the sycl device + const Device& device() const{return m_device;} + + private: + TensorEvaluator m_impl; + const Device& m_device; + DevicePointer m_buffer; + const XprType& m_op; + const ArgType m_expression; +}; + + +} // end namespace Eigen + +#endif // EIGEN_CXX11_TENSOR_TENSOR_EVAL_TO_H diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorEvaluator.h b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorEvaluator.h new file mode 100644 index 0000000000..834ce07df5 --- /dev/null +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorEvaluator.h @@ -0,0 +1,633 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Benoit Steiner +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CXX11_TENSOR_TENSOR_EVALUATOR_H +#define EIGEN_CXX11_TENSOR_TENSOR_EVALUATOR_H + +namespace Eigen { + +/** \class TensorEvaluator + * \ingroup CXX11_Tensor_Module + * + * \brief The tensor evaluator classes. + * + * These classes are responsible for the evaluation of the tensor expression. + * + * TODO: add support for more types of expressions, in particular expressions + * leading to lvalues (slicing, reshaping, etc...) + */ + +// Generic evaluator +template +struct TensorEvaluator +{ + typedef typename Derived::Index Index; + typedef typename Derived::Scalar Scalar; + typedef typename Derived::Scalar CoeffReturnType; + typedef typename PacketType::type PacketReturnType; + typedef typename Derived::Dimensions Dimensions; + + // NumDimensions is -1 for variable dim tensors + static const int NumCoords = internal::traits::NumDimensions > 0 ? + internal::traits::NumDimensions : 0; + + enum { + IsAligned = Derived::IsAligned, + PacketAccess = (internal::unpacket_traits::size > 1), + Layout = Derived::Layout, + CoordAccess = NumCoords > 0, + RawAccess = true + }; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorEvaluator(const Derived& m, const Device& device) + : m_data(const_cast::template MakePointer::Type>(m.data())), m_dims(m.dimensions()), m_device(device), m_impl(m) + { } + + // Used for accessor extraction in SYCL Managed TensorMap: + const Derived& derived() const { return m_impl; } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Dimensions& dimensions() const { return m_dims; } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(CoeffReturnType* dest) { + if (dest) { + m_device.memcpy((void*)dest, m_data, sizeof(Scalar) * m_dims.TotalSize()); + return false; + } + return true; + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void cleanup() { } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const { + eigen_assert(m_data); + return m_data[index]; + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRef(Index index) { + eigen_assert(m_data); + return m_data[index]; + } + + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + PacketReturnType packet(Index index) const + { + return internal::ploadt(m_data + index); + } + + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + void writePacket(Index index, const PacketReturnType& x) + { + return internal::pstoret(m_data + index, x); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(const array& coords) const { + eigen_assert(m_data); + if (static_cast(Layout) == static_cast(ColMajor)) { + return m_data[m_dims.IndexOfColMajor(coords)]; + } else { + return m_data[m_dims.IndexOfRowMajor(coords)]; + } + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRef(const array& coords) { + eigen_assert(m_data); + if (static_cast(Layout) == static_cast(ColMajor)) { + return m_data[m_dims.IndexOfColMajor(coords)]; + } else { + return m_data[m_dims.IndexOfRowMajor(coords)]; + } + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost costPerCoeff(bool vectorized) const { + return TensorOpCost(sizeof(CoeffReturnType), 0, 0, vectorized, + internal::unpacket_traits::size); + } + + EIGEN_DEVICE_FUNC typename internal::traits::template MakePointer::Type data() const { return m_data; } + + /// required by sycl in order to construct sycl buffer from raw pointer + const Device& device() const{return m_device;} + + protected: + typename internal::traits::template MakePointer::Type m_data; + Dimensions m_dims; + const Device& m_device; + const Derived& m_impl; +}; + +namespace { +template EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +T loadConstant(const T* address) { + return *address; +} +// Use the texture cache on CUDA devices whenever possible +#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 350 +template <> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +float loadConstant(const float* address) { + return __ldg(address); +} +template <> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +double loadConstant(const double* address) { + return __ldg(address); +} +template <> EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +Eigen::half loadConstant(const Eigen::half* address) { + return Eigen::half(half_impl::raw_uint16_to_half(__ldg(&address->x))); +} +#endif +} + + +// Default evaluator for rvalues +template +struct TensorEvaluator +{ + typedef typename Derived::Index Index; + typedef typename Derived::Scalar Scalar; + typedef typename Derived::Scalar CoeffReturnType; + typedef typename PacketType::type PacketReturnType; + typedef typename Derived::Dimensions Dimensions; + + // NumDimensions is -1 for variable dim tensors + static const int NumCoords = internal::traits::NumDimensions > 0 ? + internal::traits::NumDimensions : 0; + + enum { + IsAligned = Derived::IsAligned, + PacketAccess = (internal::unpacket_traits::size > 1), + Layout = Derived::Layout, + CoordAccess = NumCoords > 0, + RawAccess = true + }; + + // Used for accessor extraction in SYCL Managed TensorMap: + const Derived& derived() const { return m_impl; } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorEvaluator(const Derived& m, const Device& device) + : m_data(m.data()), m_dims(m.dimensions()), m_device(device), m_impl(m) + { } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Dimensions& dimensions() const { return m_dims; } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(CoeffReturnType* data) { + if (!NumTraits::type>::RequireInitialization && data) { + m_device.memcpy((void*)data, m_data, m_dims.TotalSize() * sizeof(Scalar)); + return false; + } + return true; + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void cleanup() { } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const { + eigen_assert(m_data); + return loadConstant(m_data+index); + } + + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + PacketReturnType packet(Index index) const + { + return internal::ploadt_ro(m_data + index); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(const array& coords) const { + eigen_assert(m_data); + const Index index = (static_cast(Layout) == static_cast(ColMajor)) ? m_dims.IndexOfColMajor(coords) + : m_dims.IndexOfRowMajor(coords); + return loadConstant(m_data+index); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost costPerCoeff(bool vectorized) const { + return TensorOpCost(sizeof(CoeffReturnType), 0, 0, vectorized, + internal::unpacket_traits::size); + } + + EIGEN_DEVICE_FUNC typename internal::traits::template MakePointer::Type data() const { return m_data; } + + /// added for sycl in order to construct the buffer from the sycl device + const Device& device() const{return m_device;} + + protected: + typename internal::traits::template MakePointer::Type m_data; + Dimensions m_dims; + const Device& m_device; + const Derived& m_impl; +}; + + + + +// -------------------- CwiseNullaryOp -------------------- + +template +struct TensorEvaluator, Device> +{ + typedef TensorCwiseNullaryOp XprType; + + enum { + IsAligned = true, + PacketAccess = internal::functor_traits::PacketAccess, + Layout = TensorEvaluator::Layout, + CoordAccess = false, // to be implemented + RawAccess = false + }; + + EIGEN_DEVICE_FUNC + TensorEvaluator(const XprType& op, const Device& device) + : m_functor(op.functor()), m_argImpl(op.nestedExpression(), device), m_wrapper() + { } + + typedef typename XprType::Index Index; + typedef typename XprType::Scalar Scalar; + typedef typename internal::traits::Scalar CoeffReturnType; + typedef typename PacketType::type PacketReturnType; + static const int PacketSize = internal::unpacket_traits::size; + typedef typename TensorEvaluator::Dimensions Dimensions; + + EIGEN_DEVICE_FUNC const Dimensions& dimensions() const { return m_argImpl.dimensions(); } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(CoeffReturnType*) { return true; } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void cleanup() { } + + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index index) const + { + return m_wrapper(m_functor, index); + } + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packet(Index index) const + { + return m_wrapper.template packetOp(m_functor, index); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost + costPerCoeff(bool vectorized) const { + return TensorOpCost(sizeof(CoeffReturnType), 0, 0, vectorized, + internal::unpacket_traits::size); + } + + EIGEN_DEVICE_FUNC CoeffReturnType* data() const { return NULL; } + + /// required by sycl in order to extract the accessor + const TensorEvaluator& impl() const { return m_argImpl; } + /// required by sycl in order to extract the accessor + NullaryOp functor() const { return m_functor; } + + + private: + const NullaryOp m_functor; + TensorEvaluator m_argImpl; + const internal::nullary_wrapper m_wrapper; +}; + + + +// -------------------- CwiseUnaryOp -------------------- + +template +struct TensorEvaluator, Device> +{ + typedef TensorCwiseUnaryOp XprType; + + enum { + IsAligned = TensorEvaluator::IsAligned, + PacketAccess = TensorEvaluator::PacketAccess & internal::functor_traits::PacketAccess, + Layout = TensorEvaluator::Layout, + CoordAccess = false, // to be implemented + RawAccess = false + }; + + EIGEN_DEVICE_FUNC TensorEvaluator(const XprType& op, const Device& device) + : m_functor(op.functor()), + m_argImpl(op.nestedExpression(), device) + { } + + typedef typename XprType::Index Index; + typedef typename XprType::Scalar Scalar; + typedef typename internal::traits::Scalar CoeffReturnType; + typedef typename PacketType::type PacketReturnType; + static const int PacketSize = internal::unpacket_traits::size; + typedef typename TensorEvaluator::Dimensions Dimensions; + + EIGEN_DEVICE_FUNC const Dimensions& dimensions() const { return m_argImpl.dimensions(); } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(Scalar*) { + m_argImpl.evalSubExprsIfNeeded(NULL); + return true; + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void cleanup() { + m_argImpl.cleanup(); + } + + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index index) const + { + return m_functor(m_argImpl.coeff(index)); + } + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packet(Index index) const + { + return m_functor.packetOp(m_argImpl.template packet(index)); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost costPerCoeff(bool vectorized) const { + const double functor_cost = internal::functor_traits::Cost; + return m_argImpl.costPerCoeff(vectorized) + + TensorOpCost(0, 0, functor_cost, vectorized, PacketSize); + } + + EIGEN_DEVICE_FUNC CoeffReturnType* data() const { return NULL; } + + /// required by sycl in order to extract the accessor + const TensorEvaluator & impl() const { return m_argImpl; } + /// added for sycl in order to construct the buffer from sycl device + UnaryOp functor() const { return m_functor; } + + + private: + const UnaryOp m_functor; + TensorEvaluator m_argImpl; +}; + + +// -------------------- CwiseBinaryOp -------------------- + +template +struct TensorEvaluator, Device> +{ + typedef TensorCwiseBinaryOp XprType; + + enum { + IsAligned = TensorEvaluator::IsAligned & TensorEvaluator::IsAligned, + PacketAccess = TensorEvaluator::PacketAccess & TensorEvaluator::PacketAccess & + internal::functor_traits::PacketAccess, + Layout = TensorEvaluator::Layout, + CoordAccess = false, // to be implemented + RawAccess = false + }; + + EIGEN_DEVICE_FUNC TensorEvaluator(const XprType& op, const Device& device) + : m_functor(op.functor()), + m_leftImpl(op.lhsExpression(), device), + m_rightImpl(op.rhsExpression(), device) + { + EIGEN_STATIC_ASSERT((static_cast(TensorEvaluator::Layout) == static_cast(TensorEvaluator::Layout) || internal::traits::NumDimensions <= 1), YOU_MADE_A_PROGRAMMING_MISTAKE); + eigen_assert(dimensions_match(m_leftImpl.dimensions(), m_rightImpl.dimensions())); + } + + typedef typename XprType::Index Index; + typedef typename XprType::Scalar Scalar; + typedef typename internal::traits::Scalar CoeffReturnType; + typedef typename PacketType::type PacketReturnType; + static const int PacketSize = internal::unpacket_traits::size; + typedef typename TensorEvaluator::Dimensions Dimensions; + + EIGEN_DEVICE_FUNC const Dimensions& dimensions() const + { + // TODO: use right impl instead if right impl dimensions are known at compile time. + return m_leftImpl.dimensions(); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(CoeffReturnType*) { + m_leftImpl.evalSubExprsIfNeeded(NULL); + m_rightImpl.evalSubExprsIfNeeded(NULL); + return true; + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void cleanup() { + m_leftImpl.cleanup(); + m_rightImpl.cleanup(); + } + + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index index) const + { + return m_functor(m_leftImpl.coeff(index), m_rightImpl.coeff(index)); + } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packet(Index index) const + { + return m_functor.packetOp(m_leftImpl.template packet(index), m_rightImpl.template packet(index)); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost + costPerCoeff(bool vectorized) const { + const double functor_cost = internal::functor_traits::Cost; + return m_leftImpl.costPerCoeff(vectorized) + + m_rightImpl.costPerCoeff(vectorized) + + TensorOpCost(0, 0, functor_cost, vectorized, PacketSize); + } + + EIGEN_DEVICE_FUNC CoeffReturnType* data() const { return NULL; } + /// required by sycl in order to extract the accessor + const TensorEvaluator& left_impl() const { return m_leftImpl; } + /// required by sycl in order to extract the accessor + const TensorEvaluator& right_impl() const { return m_rightImpl; } + /// required by sycl in order to extract the accessor + BinaryOp functor() const { return m_functor; } + + private: + const BinaryOp m_functor; + TensorEvaluator m_leftImpl; + TensorEvaluator m_rightImpl; +}; + +// -------------------- CwiseTernaryOp -------------------- + +template +struct TensorEvaluator, Device> +{ + typedef TensorCwiseTernaryOp XprType; + + enum { + IsAligned = TensorEvaluator::IsAligned & TensorEvaluator::IsAligned & TensorEvaluator::IsAligned, + PacketAccess = TensorEvaluator::PacketAccess & TensorEvaluator::PacketAccess & TensorEvaluator::PacketAccess & + internal::functor_traits::PacketAccess, + Layout = TensorEvaluator::Layout, + CoordAccess = false, // to be implemented + RawAccess = false + }; + + EIGEN_DEVICE_FUNC TensorEvaluator(const XprType& op, const Device& device) + : m_functor(op.functor()), + m_arg1Impl(op.arg1Expression(), device), + m_arg2Impl(op.arg2Expression(), device), + m_arg3Impl(op.arg3Expression(), device) + { + EIGEN_STATIC_ASSERT((static_cast(TensorEvaluator::Layout) == static_cast(TensorEvaluator::Layout) || internal::traits::NumDimensions <= 1), YOU_MADE_A_PROGRAMMING_MISTAKE); + + EIGEN_STATIC_ASSERT((internal::is_same::StorageKind, + typename internal::traits::StorageKind>::value), + STORAGE_KIND_MUST_MATCH) + EIGEN_STATIC_ASSERT((internal::is_same::StorageKind, + typename internal::traits::StorageKind>::value), + STORAGE_KIND_MUST_MATCH) + EIGEN_STATIC_ASSERT((internal::is_same::Index, + typename internal::traits::Index>::value), + STORAGE_INDEX_MUST_MATCH) + EIGEN_STATIC_ASSERT((internal::is_same::Index, + typename internal::traits::Index>::value), + STORAGE_INDEX_MUST_MATCH) + + eigen_assert(dimensions_match(m_arg1Impl.dimensions(), m_arg2Impl.dimensions()) && dimensions_match(m_arg1Impl.dimensions(), m_arg3Impl.dimensions())); + } + + typedef typename XprType::Index Index; + typedef typename XprType::Scalar Scalar; + typedef typename internal::traits::Scalar CoeffReturnType; + typedef typename PacketType::type PacketReturnType; + static const int PacketSize = internal::unpacket_traits::size; + typedef typename TensorEvaluator::Dimensions Dimensions; + + EIGEN_DEVICE_FUNC const Dimensions& dimensions() const + { + // TODO: use arg2 or arg3 dimensions if they are known at compile time. + return m_arg1Impl.dimensions(); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(CoeffReturnType*) { + m_arg1Impl.evalSubExprsIfNeeded(NULL); + m_arg2Impl.evalSubExprsIfNeeded(NULL); + m_arg3Impl.evalSubExprsIfNeeded(NULL); + return true; + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void cleanup() { + m_arg1Impl.cleanup(); + m_arg2Impl.cleanup(); + m_arg3Impl.cleanup(); + } + + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index index) const + { + return m_functor(m_arg1Impl.coeff(index), m_arg2Impl.coeff(index), m_arg3Impl.coeff(index)); + } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packet(Index index) const + { + return m_functor.packetOp(m_arg1Impl.template packet(index), + m_arg2Impl.template packet(index), + m_arg3Impl.template packet(index)); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost + costPerCoeff(bool vectorized) const { + const double functor_cost = internal::functor_traits::Cost; + return m_arg1Impl.costPerCoeff(vectorized) + + m_arg2Impl.costPerCoeff(vectorized) + + m_arg3Impl.costPerCoeff(vectorized) + + TensorOpCost(0, 0, functor_cost, vectorized, PacketSize); + } + + EIGEN_DEVICE_FUNC CoeffReturnType* data() const { return NULL; } + + /// required by sycl in order to extract the accessor + const TensorEvaluator & arg1Impl() const { return m_arg1Impl; } + /// required by sycl in order to extract the accessor + const TensorEvaluator& arg2Impl() const { return m_arg2Impl; } + /// required by sycl in order to extract the accessor + const TensorEvaluator& arg3Impl() const { return m_arg3Impl; } + + private: + const TernaryOp m_functor; + TensorEvaluator m_arg1Impl; + TensorEvaluator m_arg2Impl; + TensorEvaluator m_arg3Impl; +}; + + +// -------------------- SelectOp -------------------- + +template +struct TensorEvaluator, Device> +{ + typedef TensorSelectOp XprType; + typedef typename XprType::Scalar Scalar; + + enum { + IsAligned = TensorEvaluator::IsAligned & TensorEvaluator::IsAligned, + PacketAccess = TensorEvaluator::PacketAccess & TensorEvaluator::PacketAccess & + internal::packet_traits::HasBlend, + Layout = TensorEvaluator::Layout, + CoordAccess = false, // to be implemented + RawAccess = false + }; + + EIGEN_DEVICE_FUNC TensorEvaluator(const XprType& op, const Device& device) + : m_condImpl(op.ifExpression(), device), + m_thenImpl(op.thenExpression(), device), + m_elseImpl(op.elseExpression(), device) + { + EIGEN_STATIC_ASSERT((static_cast(TensorEvaluator::Layout) == static_cast(TensorEvaluator::Layout)), YOU_MADE_A_PROGRAMMING_MISTAKE); + EIGEN_STATIC_ASSERT((static_cast(TensorEvaluator::Layout) == static_cast(TensorEvaluator::Layout)), YOU_MADE_A_PROGRAMMING_MISTAKE); + eigen_assert(dimensions_match(m_condImpl.dimensions(), m_thenImpl.dimensions())); + eigen_assert(dimensions_match(m_thenImpl.dimensions(), m_elseImpl.dimensions())); + } + + typedef typename XprType::Index Index; + typedef typename internal::traits::Scalar CoeffReturnType; + typedef typename PacketType::type PacketReturnType; + static const int PacketSize = internal::unpacket_traits::size; + typedef typename TensorEvaluator::Dimensions Dimensions; + + EIGEN_DEVICE_FUNC const Dimensions& dimensions() const + { + // TODO: use then or else impl instead if they happen to be known at compile time. + return m_condImpl.dimensions(); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(CoeffReturnType*) { + m_condImpl.evalSubExprsIfNeeded(NULL); + m_thenImpl.evalSubExprsIfNeeded(NULL); + m_elseImpl.evalSubExprsIfNeeded(NULL); + return true; + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void cleanup() { + m_condImpl.cleanup(); + m_thenImpl.cleanup(); + m_elseImpl.cleanup(); + } + + EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index index) const + { + return m_condImpl.coeff(index) ? m_thenImpl.coeff(index) : m_elseImpl.coeff(index); + } + template + EIGEN_DEVICE_FUNC PacketReturnType packet(Index index) const + { + internal::Selector select; + for (Index i = 0; i < PacketSize; ++i) { + select.select[i] = m_condImpl.coeff(index+i); + } + return internal::pblend(select, + m_thenImpl.template packet(index), + m_elseImpl.template packet(index)); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost + costPerCoeff(bool vectorized) const { + return m_condImpl.costPerCoeff(vectorized) + + m_thenImpl.costPerCoeff(vectorized) + .cwiseMax(m_elseImpl.costPerCoeff(vectorized)); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType* data() const { return NULL; } + /// required by sycl in order to extract the accessor + const TensorEvaluator & cond_impl() const { return m_condImpl; } + /// required by sycl in order to extract the accessor + const TensorEvaluator& then_impl() const { return m_thenImpl; } + /// required by sycl in order to extract the accessor + const TensorEvaluator& else_impl() const { return m_elseImpl; } + + private: + TensorEvaluator m_condImpl; + TensorEvaluator m_thenImpl; + TensorEvaluator m_elseImpl; +}; + + +} // end namespace Eigen + +#endif // EIGEN_CXX11_TENSOR_TENSOR_EVALUATOR_H diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorExecutor.h b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorExecutor.h new file mode 100644 index 0000000000..f01d77c0a0 --- /dev/null +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorExecutor.h @@ -0,0 +1,288 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Benoit Steiner +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CXX11_TENSOR_TENSOR_EXECUTOR_H +#define EIGEN_CXX11_TENSOR_TENSOR_EXECUTOR_H + +namespace Eigen { + +/** \class TensorExecutor + * \ingroup CXX11_Tensor_Module + * + * \brief The tensor executor class. + * + * This class is responsible for launch the evaluation of the expression on + * the specified computing device. + */ +namespace internal { + +// Default strategy: the expression is evaluated with a single cpu thread. +template +class TensorExecutor +{ + public: + typedef typename Expression::Index Index; + EIGEN_DEVICE_FUNC + static inline void run(const Expression& expr, const Device& device = Device()) + { + TensorEvaluator evaluator(expr, device); + const bool needs_assign = evaluator.evalSubExprsIfNeeded(NULL); + if (needs_assign) + { + const Index size = array_prod(evaluator.dimensions()); + for (Index i = 0; i < size; ++i) { + evaluator.evalScalar(i); + } + } + evaluator.cleanup(); + } +}; + + +template +class TensorExecutor +{ + public: + typedef typename Expression::Index Index; + EIGEN_DEVICE_FUNC + static inline void run(const Expression& expr, const DefaultDevice& device = DefaultDevice()) + { + TensorEvaluator evaluator(expr, device); + const bool needs_assign = evaluator.evalSubExprsIfNeeded(NULL); + if (needs_assign) + { + const Index size = array_prod(evaluator.dimensions()); + const int PacketSize = unpacket_traits::PacketReturnType>::size; + // Give the compiler a strong hint to unroll the loop. But don't insist + // on unrolling, because if the function is expensive the compiler should not + // unroll the loop at the expense of inlining. + const Index UnrolledSize = (size / (4 * PacketSize)) * 4 * PacketSize; + for (Index i = 0; i < UnrolledSize; i += 4*PacketSize) { + for (Index j = 0; j < 4; j++) { + evaluator.evalPacket(i + j * PacketSize); + } + } + const Index VectorizedSize = (size / PacketSize) * PacketSize; + for (Index i = UnrolledSize; i < VectorizedSize; i += PacketSize) { + evaluator.evalPacket(i); + } + for (Index i = VectorizedSize; i < size; ++i) { + evaluator.evalScalar(i); + } + } + evaluator.cleanup(); + } +}; + + + +// Multicore strategy: the index space is partitioned and each partition is executed on a single core +#ifdef EIGEN_USE_THREADS +template +struct EvalRange { + static void run(Evaluator* evaluator_in, const Index first, const Index last) { + Evaluator evaluator = *evaluator_in; + eigen_assert(last >= first); + for (Index i = first; i < last; ++i) { + evaluator.evalScalar(i); + } + } + + static Index alignBlockSize(Index size) { + return size; + } +}; + +template +struct EvalRange { + static const int PacketSize = unpacket_traits::size; + + static void run(Evaluator* evaluator_in, const Index first, const Index last) { + Evaluator evaluator = *evaluator_in; + eigen_assert(last >= first); + Index i = first; + if (last - first >= PacketSize) { + eigen_assert(first % PacketSize == 0); + Index last_chunk_offset = last - 4 * PacketSize; + // Give the compiler a strong hint to unroll the loop. But don't insist + // on unrolling, because if the function is expensive the compiler should not + // unroll the loop at the expense of inlining. + for (; i <= last_chunk_offset; i += 4*PacketSize) { + for (Index j = 0; j < 4; j++) { + evaluator.evalPacket(i + j * PacketSize); + } + } + last_chunk_offset = last - PacketSize; + for (; i <= last_chunk_offset; i += PacketSize) { + evaluator.evalPacket(i); + } + } + for (; i < last; ++i) { + evaluator.evalScalar(i); + } + } + + static Index alignBlockSize(Index size) { + // Align block size to packet size and account for unrolling in run above. + if (size >= 16 * PacketSize) { + return (size + 4 * PacketSize - 1) & ~(4 * PacketSize - 1); + } + // Aligning to 4 * PacketSize would increase block size by more than 25%. + return (size + PacketSize - 1) & ~(PacketSize - 1); + } +}; + +template +class TensorExecutor { + public: + typedef typename Expression::Index Index; + static inline void run(const Expression& expr, const ThreadPoolDevice& device) + { + typedef TensorEvaluator Evaluator; + Evaluator evaluator(expr, device); + const bool needs_assign = evaluator.evalSubExprsIfNeeded(NULL); + if (needs_assign) + { + const Index size = array_prod(evaluator.dimensions()); +#if !defined(EIGEN_USE_SIMPLE_THREAD_POOL) + device.parallelFor(size, evaluator.costPerCoeff(Vectorizable), + EvalRange::alignBlockSize, + [&evaluator](Index first, Index last) { + EvalRange::run(&evaluator, first, last); + }); +#else + size_t num_threads = device.numThreads(); + if (num_threads > 1) { + num_threads = TensorCostModel::numThreads( + size, evaluator.costPerCoeff(Vectorizable), num_threads); + } + if (num_threads == 1) { + EvalRange::run(&evaluator, 0, size); + } else { + const Index PacketSize = Vectorizable ? unpacket_traits::size : 1; + Index blocksz = std::ceil(static_cast(size)/num_threads) + PacketSize - 1; + const Index blocksize = numext::maxi(PacketSize, (blocksz - (blocksz % PacketSize))); + const Index numblocks = size / blocksize; + + Barrier barrier(numblocks); + for (int i = 0; i < numblocks; ++i) { + device.enqueue_with_barrier( + &barrier, &EvalRange::run, + &evaluator, i * blocksize, (i + 1) * blocksize); + } + if (numblocks * blocksize < size) { + EvalRange::run( + &evaluator, numblocks * blocksize, size); + } + barrier.Wait(); + } +#endif // defined(!EIGEN_USE_SIMPLE_THREAD_POOL) + } + evaluator.cleanup(); + } +}; +#endif // EIGEN_USE_THREADS + + +// GPU: the evaluation of the expression is offloaded to a GPU. +#if defined(EIGEN_USE_GPU) + +template +class TensorExecutor { + public: + typedef typename Expression::Index Index; + static void run(const Expression& expr, const GpuDevice& device); +}; + + +#if defined(__CUDACC__) +template +struct EigenMetaKernelEval { + static __device__ EIGEN_ALWAYS_INLINE + void run(Evaluator& eval, Index first, Index last, Index step_size) { + for (Index i = first; i < last; i += step_size) { + eval.evalScalar(i); + } + } +}; + +template +struct EigenMetaKernelEval { + static __device__ EIGEN_ALWAYS_INLINE + void run(Evaluator& eval, Index first, Index last, Index step_size) { + const Index PacketSize = unpacket_traits::size; + const Index vectorized_size = (last / PacketSize) * PacketSize; + const Index vectorized_step_size = step_size * PacketSize; + + // Use the vector path + for (Index i = first * PacketSize; i < vectorized_size; + i += vectorized_step_size) { + eval.evalPacket(i); + } + for (Index i = vectorized_size + first; i < last; i += step_size) { + eval.evalScalar(i); + } + } +}; + +template +__global__ void +__launch_bounds__(1024) +EigenMetaKernel(Evaluator eval, Index size) { + + const Index first_index = blockIdx.x * blockDim.x + threadIdx.x; + const Index step_size = blockDim.x * gridDim.x; + + const bool vectorizable = Evaluator::PacketAccess & Evaluator::IsAligned; + EigenMetaKernelEval::run(eval, first_index, size, step_size); +} + +/*static*/ +template +inline void TensorExecutor::run( + const Expression& expr, const GpuDevice& device) { + TensorEvaluator evaluator(expr, device); + const bool needs_assign = evaluator.evalSubExprsIfNeeded(NULL); + if (needs_assign) { + const int block_size = device.maxCudaThreadsPerBlock(); + const int max_blocks = device.getNumCudaMultiProcessors() * + device.maxCudaThreadsPerMultiProcessor() / block_size; + const Index size = array_prod(evaluator.dimensions()); + // Create a least one block to ensure we won't crash when tensorflow calls with tensors of size 0. + const int num_blocks = numext::maxi(numext::mini(max_blocks, divup(size, block_size)), 1); + + LAUNCH_CUDA_KERNEL( + (EigenMetaKernel, Index>), + num_blocks, block_size, 0, device, evaluator, size); + } + evaluator.cleanup(); +} + +#endif // __CUDACC__ +#endif // EIGEN_USE_GPU + +// SYCL Executor policy +#ifdef EIGEN_USE_SYCL + +template +class TensorExecutor { +public: + static inline void run(const Expression &expr, const SyclDevice &device) { + // call TensorSYCL module + TensorSycl::run(expr, device); + } +}; + +#endif + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_CXX11_TENSOR_TENSOR_EXECUTOR_H diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorExpr.h b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorExpr.h new file mode 100644 index 0000000000..85dfc7a69f --- /dev/null +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorExpr.h @@ -0,0 +1,371 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Benoit Steiner +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CXX11_TENSOR_TENSOR_EXPR_H +#define EIGEN_CXX11_TENSOR_TENSOR_EXPR_H + +namespace Eigen { + +/** \class TensorExpr + * \ingroup CXX11_Tensor_Module + * + * \brief Tensor expression classes. + * + * The TensorCwiseNullaryOp class applies a nullary operators to an expression. + * This is typically used to generate constants. + * + * The TensorCwiseUnaryOp class represents an expression where a unary operator + * (e.g. cwiseSqrt) is applied to an expression. + * + * The TensorCwiseBinaryOp class represents an expression where a binary + * operator (e.g. addition) is applied to a lhs and a rhs expression. + * + */ +namespace internal { +template +struct traits > + : traits +{ + typedef traits XprTraits; + typedef typename XprType::Scalar Scalar; + typedef typename XprType::Nested XprTypeNested; + typedef typename remove_reference::type _XprTypeNested; + static const int NumDimensions = XprTraits::NumDimensions; + static const int Layout = XprTraits::Layout; + + enum { + Flags = 0 + }; +}; + +} // end namespace internal + + + +template +class TensorCwiseNullaryOp : public TensorBase, ReadOnlyAccessors> +{ + public: + typedef typename Eigen::internal::traits::Scalar Scalar; + typedef typename Eigen::NumTraits::Real RealScalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + typedef TensorCwiseNullaryOp Nested; + typedef typename Eigen::internal::traits::StorageKind StorageKind; + typedef typename Eigen::internal::traits::Index Index; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorCwiseNullaryOp(const XprType& xpr, const NullaryOp& func = NullaryOp()) + : m_xpr(xpr), m_functor(func) {} + + EIGEN_DEVICE_FUNC + const typename internal::remove_all::type& + nestedExpression() const { return m_xpr; } + + EIGEN_DEVICE_FUNC + const NullaryOp& functor() const { return m_functor; } + + protected: + typename XprType::Nested m_xpr; + const NullaryOp m_functor; +}; + + + +namespace internal { +template +struct traits > + : traits +{ + // TODO(phli): Add InputScalar, InputPacket. Check references to + // current Scalar/Packet to see if the intent is Input or Output. + typedef typename result_of::type Scalar; + typedef traits XprTraits; + typedef typename XprType::Nested XprTypeNested; + typedef typename remove_reference::type _XprTypeNested; + static const int NumDimensions = XprTraits::NumDimensions; + static const int Layout = XprTraits::Layout; +}; + +template +struct eval, Eigen::Dense> +{ + typedef const TensorCwiseUnaryOp& type; +}; + +template +struct nested, 1, typename eval >::type> +{ + typedef TensorCwiseUnaryOp type; +}; + +} // end namespace internal + + + +template +class TensorCwiseUnaryOp : public TensorBase, ReadOnlyAccessors> +{ + public: + // TODO(phli): Add InputScalar, InputPacket. Check references to + // current Scalar/Packet to see if the intent is Input or Output. + typedef typename Eigen::internal::traits::Scalar Scalar; + typedef typename Eigen::NumTraits::Real RealScalar; + typedef Scalar CoeffReturnType; + typedef typename Eigen::internal::nested::type Nested; + typedef typename Eigen::internal::traits::StorageKind StorageKind; + typedef typename Eigen::internal::traits::Index Index; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorCwiseUnaryOp(const XprType& xpr, const UnaryOp& func = UnaryOp()) + : m_xpr(xpr), m_functor(func) {} + + EIGEN_DEVICE_FUNC + const UnaryOp& functor() const { return m_functor; } + + /** \returns the nested expression */ + EIGEN_DEVICE_FUNC + const typename internal::remove_all::type& + nestedExpression() const { return m_xpr; } + + protected: + typename XprType::Nested m_xpr; + const UnaryOp m_functor; +}; + + +namespace internal { +template +struct traits > +{ + // Type promotion to handle the case where the types of the lhs and the rhs + // are different. + // TODO(phli): Add Lhs/RhsScalar, Lhs/RhsPacket. Check references to + // current Scalar/Packet to see if the intent is Inputs or Output. + typedef typename result_of< + BinaryOp(typename LhsXprType::Scalar, + typename RhsXprType::Scalar)>::type Scalar; + typedef traits XprTraits; + typedef typename promote_storage_type< + typename traits::StorageKind, + typename traits::StorageKind>::ret StorageKind; + typedef typename promote_index_type< + typename traits::Index, + typename traits::Index>::type Index; + typedef typename LhsXprType::Nested LhsNested; + typedef typename RhsXprType::Nested RhsNested; + typedef typename remove_reference::type _LhsNested; + typedef typename remove_reference::type _RhsNested; + static const int NumDimensions = XprTraits::NumDimensions; + static const int Layout = XprTraits::Layout; + + enum { + Flags = 0 + }; +}; + +template +struct eval, Eigen::Dense> +{ + typedef const TensorCwiseBinaryOp& type; +}; + +template +struct nested, 1, typename eval >::type> +{ + typedef TensorCwiseBinaryOp type; +}; + +} // end namespace internal + + + +template +class TensorCwiseBinaryOp : public TensorBase, ReadOnlyAccessors> +{ + public: + // TODO(phli): Add Lhs/RhsScalar, Lhs/RhsPacket. Check references to + // current Scalar/Packet to see if the intent is Inputs or Output. + typedef typename Eigen::internal::traits::Scalar Scalar; + typedef typename Eigen::NumTraits::Real RealScalar; + typedef Scalar CoeffReturnType; + typedef typename Eigen::internal::nested::type Nested; + typedef typename Eigen::internal::traits::StorageKind StorageKind; + typedef typename Eigen::internal::traits::Index Index; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorCwiseBinaryOp(const LhsXprType& lhs, const RhsXprType& rhs, const BinaryOp& func = BinaryOp()) + : m_lhs_xpr(lhs), m_rhs_xpr(rhs), m_functor(func) {} + + EIGEN_DEVICE_FUNC + const BinaryOp& functor() const { return m_functor; } + + /** \returns the nested expressions */ + EIGEN_DEVICE_FUNC + const typename internal::remove_all::type& + lhsExpression() const { return m_lhs_xpr; } + + EIGEN_DEVICE_FUNC + const typename internal::remove_all::type& + rhsExpression() const { return m_rhs_xpr; } + + protected: + typename LhsXprType::Nested m_lhs_xpr; + typename RhsXprType::Nested m_rhs_xpr; + const BinaryOp m_functor; +}; + + +namespace internal { +template +struct traits > +{ + // Type promotion to handle the case where the types of the args are different. + typedef typename result_of< + TernaryOp(typename Arg1XprType::Scalar, + typename Arg2XprType::Scalar, + typename Arg3XprType::Scalar)>::type Scalar; + typedef traits XprTraits; + typedef typename traits::StorageKind StorageKind; + typedef typename traits::Index Index; + typedef typename Arg1XprType::Nested Arg1Nested; + typedef typename Arg2XprType::Nested Arg2Nested; + typedef typename Arg3XprType::Nested Arg3Nested; + typedef typename remove_reference::type _Arg1Nested; + typedef typename remove_reference::type _Arg2Nested; + typedef typename remove_reference::type _Arg3Nested; + static const int NumDimensions = XprTraits::NumDimensions; + static const int Layout = XprTraits::Layout; + + enum { + Flags = 0 + }; +}; + +template +struct eval, Eigen::Dense> +{ + typedef const TensorCwiseTernaryOp& type; +}; + +template +struct nested, 1, typename eval >::type> +{ + typedef TensorCwiseTernaryOp type; +}; + +} // end namespace internal + + + +template +class TensorCwiseTernaryOp : public TensorBase, ReadOnlyAccessors> +{ + public: + typedef typename Eigen::internal::traits::Scalar Scalar; + typedef typename Eigen::NumTraits::Real RealScalar; + typedef Scalar CoeffReturnType; + typedef typename Eigen::internal::nested::type Nested; + typedef typename Eigen::internal::traits::StorageKind StorageKind; + typedef typename Eigen::internal::traits::Index Index; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorCwiseTernaryOp(const Arg1XprType& arg1, const Arg2XprType& arg2, const Arg3XprType& arg3, const TernaryOp& func = TernaryOp()) + : m_arg1_xpr(arg1), m_arg2_xpr(arg2), m_arg3_xpr(arg3), m_functor(func) {} + + EIGEN_DEVICE_FUNC + const TernaryOp& functor() const { return m_functor; } + + /** \returns the nested expressions */ + EIGEN_DEVICE_FUNC + const typename internal::remove_all::type& + arg1Expression() const { return m_arg1_xpr; } + + EIGEN_DEVICE_FUNC + const typename internal::remove_all::type& + arg2Expression() const { return m_arg2_xpr; } + + EIGEN_DEVICE_FUNC + const typename internal::remove_all::type& + arg3Expression() const { return m_arg3_xpr; } + + protected: + typename Arg1XprType::Nested m_arg1_xpr; + typename Arg2XprType::Nested m_arg2_xpr; + typename Arg3XprType::Nested m_arg3_xpr; + const TernaryOp m_functor; +}; + + +namespace internal { +template +struct traits > + : traits +{ + typedef typename traits::Scalar Scalar; + typedef traits XprTraits; + typedef typename promote_storage_type::StorageKind, + typename traits::StorageKind>::ret StorageKind; + typedef typename promote_index_type::Index, + typename traits::Index>::type Index; + typedef typename IfXprType::Nested IfNested; + typedef typename ThenXprType::Nested ThenNested; + typedef typename ElseXprType::Nested ElseNested; + static const int NumDimensions = XprTraits::NumDimensions; + static const int Layout = XprTraits::Layout; +}; + +template +struct eval, Eigen::Dense> +{ + typedef const TensorSelectOp& type; +}; + +template +struct nested, 1, typename eval >::type> +{ + typedef TensorSelectOp type; +}; + +} // end namespace internal + + +template +class TensorSelectOp : public TensorBase, ReadOnlyAccessors> +{ + public: + typedef typename Eigen::internal::traits::Scalar Scalar; + typedef typename Eigen::NumTraits::Real RealScalar; + typedef typename internal::promote_storage_type::ret CoeffReturnType; + typedef typename Eigen::internal::nested::type Nested; + typedef typename Eigen::internal::traits::StorageKind StorageKind; + typedef typename Eigen::internal::traits::Index Index; + + EIGEN_DEVICE_FUNC + TensorSelectOp(const IfXprType& a_condition, + const ThenXprType& a_then, + const ElseXprType& a_else) + : m_condition(a_condition), m_then(a_then), m_else(a_else) + { } + + EIGEN_DEVICE_FUNC + const IfXprType& ifExpression() const { return m_condition; } + + EIGEN_DEVICE_FUNC + const ThenXprType& thenExpression() const { return m_then; } + + EIGEN_DEVICE_FUNC + const ElseXprType& elseExpression() const { return m_else; } + + protected: + typename IfXprType::Nested m_condition; + typename ThenXprType::Nested m_then; + typename ElseXprType::Nested m_else; +}; + + +} // end namespace Eigen + +#endif // EIGEN_CXX11_TENSOR_TENSOR_EXPR_H diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorFFT.h b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorFFT.h new file mode 100644 index 0000000000..08eb5595a2 --- /dev/null +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorFFT.h @@ -0,0 +1,651 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2015 Jianwei Cui +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CXX11_TENSOR_TENSOR_FFT_H +#define EIGEN_CXX11_TENSOR_TENSOR_FFT_H + +// This code requires the ability to initialize arrays of constant +// values directly inside a class. +#if __cplusplus >= 201103L || EIGEN_COMP_MSVC >= 1900 + +namespace Eigen { + +/** \class TensorFFT + * \ingroup CXX11_Tensor_Module + * + * \brief Tensor FFT class. + * + * TODO: + * Vectorize the Cooley Tukey and the Bluestein algorithm + * Add support for multithreaded evaluation + * Improve the performance on GPU + */ + +template struct MakeComplex { + template + EIGEN_DEVICE_FUNC + T operator() (const T& val) const { return val; } +}; + +template <> struct MakeComplex { + template + EIGEN_DEVICE_FUNC + std::complex operator() (const T& val) const { return std::complex(val, 0); } +}; + +template <> struct MakeComplex { + template + EIGEN_DEVICE_FUNC + std::complex operator() (const std::complex& val) const { return val; } +}; + +template struct PartOf { + template T operator() (const T& val) const { return val; } +}; + +template <> struct PartOf { + template T operator() (const std::complex& val) const { return val.real(); } +}; + +template <> struct PartOf { + template T operator() (const std::complex& val) const { return val.imag(); } +}; + +namespace internal { +template +struct traits > : public traits { + typedef traits XprTraits; + typedef typename NumTraits::Real RealScalar; + typedef typename std::complex ComplexScalar; + typedef typename XprTraits::Scalar InputScalar; + typedef typename conditional::type OutputScalar; + typedef typename XprTraits::StorageKind StorageKind; + typedef typename XprTraits::Index Index; + typedef typename XprType::Nested Nested; + typedef typename remove_reference::type _Nested; + static const int NumDimensions = XprTraits::NumDimensions; + static const int Layout = XprTraits::Layout; +}; + +template +struct eval, Eigen::Dense> { + typedef const TensorFFTOp& type; +}; + +template +struct nested, 1, typename eval >::type> { + typedef TensorFFTOp type; +}; + +} // end namespace internal + +template +class TensorFFTOp : public TensorBase, ReadOnlyAccessors> { + public: + typedef typename Eigen::internal::traits::Scalar Scalar; + typedef typename Eigen::NumTraits::Real RealScalar; + typedef typename std::complex ComplexScalar; + typedef typename internal::conditional::type OutputScalar; + typedef OutputScalar CoeffReturnType; + typedef typename Eigen::internal::nested::type Nested; + typedef typename Eigen::internal::traits::StorageKind StorageKind; + typedef typename Eigen::internal::traits::Index Index; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorFFTOp(const XprType& expr, const FFT& fft) + : m_xpr(expr), m_fft(fft) {} + + EIGEN_DEVICE_FUNC + const FFT& fft() const { return m_fft; } + + EIGEN_DEVICE_FUNC + const typename internal::remove_all::type& expression() const { + return m_xpr; + } + + protected: + typename XprType::Nested m_xpr; + const FFT m_fft; +}; + +// Eval as rvalue +template +struct TensorEvaluator, Device> { + typedef TensorFFTOp XprType; + typedef typename XprType::Index Index; + static const int NumDims = internal::array_size::Dimensions>::value; + typedef DSizes Dimensions; + typedef typename XprType::Scalar Scalar; + typedef typename Eigen::NumTraits::Real RealScalar; + typedef typename std::complex ComplexScalar; + typedef typename TensorEvaluator::Dimensions InputDimensions; + typedef internal::traits XprTraits; + typedef typename XprTraits::Scalar InputScalar; + typedef typename internal::conditional::type OutputScalar; + typedef OutputScalar CoeffReturnType; + typedef typename PacketType::type PacketReturnType; + static const int PacketSize = internal::unpacket_traits::size; + + enum { + IsAligned = false, + PacketAccess = true, + BlockAccess = false, + Layout = TensorEvaluator::Layout, + CoordAccess = false, + RawAccess = false + }; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorEvaluator(const XprType& op, const Device& device) : m_fft(op.fft()), m_impl(op.expression(), device), m_data(NULL), m_device(device) { + const typename TensorEvaluator::Dimensions& input_dims = m_impl.dimensions(); + for (int i = 0; i < NumDims; ++i) { + eigen_assert(input_dims[i] > 0); + m_dimensions[i] = input_dims[i]; + } + + if (static_cast(Layout) == static_cast(ColMajor)) { + m_strides[0] = 1; + for (int i = 1; i < NumDims; ++i) { + m_strides[i] = m_strides[i - 1] * m_dimensions[i - 1]; + } + } else { + m_strides[NumDims - 1] = 1; + for (int i = NumDims - 2; i >= 0; --i) { + m_strides[i] = m_strides[i + 1] * m_dimensions[i + 1]; + } + } + m_size = m_dimensions.TotalSize(); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Dimensions& dimensions() const { + return m_dimensions; + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(OutputScalar* data) { + m_impl.evalSubExprsIfNeeded(NULL); + if (data) { + evalToBuf(data); + return false; + } else { + m_data = (CoeffReturnType*)m_device.allocate(sizeof(CoeffReturnType) * m_size); + evalToBuf(m_data); + return true; + } + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void cleanup() { + if (m_data) { + m_device.deallocate(m_data); + m_data = NULL; + } + m_impl.cleanup(); + } + + EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE CoeffReturnType coeff(Index index) const { + return m_data[index]; + } + + template + EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE PacketReturnType + packet(Index index) const { + return internal::ploadt(m_data + index); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost + costPerCoeff(bool vectorized) const { + return TensorOpCost(sizeof(CoeffReturnType), 0, 0, vectorized, PacketSize); + } + + EIGEN_DEVICE_FUNC Scalar* data() const { return m_data; } + + + private: + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void evalToBuf(OutputScalar* data) { + const bool write_to_out = internal::is_same::value; + ComplexScalar* buf = write_to_out ? (ComplexScalar*)data : (ComplexScalar*)m_device.allocate(sizeof(ComplexScalar) * m_size); + + for (Index i = 0; i < m_size; ++i) { + buf[i] = MakeComplex::value>()(m_impl.coeff(i)); + } + + for (size_t i = 0; i < m_fft.size(); ++i) { + Index dim = m_fft[i]; + eigen_assert(dim >= 0 && dim < NumDims); + Index line_len = m_dimensions[dim]; + eigen_assert(line_len >= 1); + ComplexScalar* line_buf = (ComplexScalar*)m_device.allocate(sizeof(ComplexScalar) * line_len); + const bool is_power_of_two = isPowerOfTwo(line_len); + const Index good_composite = is_power_of_two ? 0 : findGoodComposite(line_len); + const Index log_len = is_power_of_two ? getLog2(line_len) : getLog2(good_composite); + + ComplexScalar* a = is_power_of_two ? NULL : (ComplexScalar*)m_device.allocate(sizeof(ComplexScalar) * good_composite); + ComplexScalar* b = is_power_of_two ? NULL : (ComplexScalar*)m_device.allocate(sizeof(ComplexScalar) * good_composite); + ComplexScalar* pos_j_base_powered = is_power_of_two ? NULL : (ComplexScalar*)m_device.allocate(sizeof(ComplexScalar) * (line_len + 1)); + if (!is_power_of_two) { + // Compute twiddle factors + // t_n = exp(sqrt(-1) * pi * n^2 / line_len) + // for n = 0, 1,..., line_len-1. + // For n > 2 we use the recurrence t_n = t_{n-1}^2 / t_{n-2} * t_1^2 + pos_j_base_powered[0] = ComplexScalar(1, 0); + if (line_len > 1) { + const RealScalar pi_over_len(EIGEN_PI / line_len); + const ComplexScalar pos_j_base = ComplexScalar( + std::cos(pi_over_len), std::sin(pi_over_len)); + pos_j_base_powered[1] = pos_j_base; + if (line_len > 2) { + const ComplexScalar pos_j_base_sq = pos_j_base * pos_j_base; + for (int j = 2; j < line_len + 1; ++j) { + pos_j_base_powered[j] = pos_j_base_powered[j - 1] * + pos_j_base_powered[j - 1] / + pos_j_base_powered[j - 2] * pos_j_base_sq; + } + } + } + } + + for (Index partial_index = 0; partial_index < m_size / line_len; ++partial_index) { + const Index base_offset = getBaseOffsetFromIndex(partial_index, dim); + + // get data into line_buf + const Index stride = m_strides[dim]; + if (stride == 1) { + memcpy(line_buf, &buf[base_offset], line_len*sizeof(ComplexScalar)); + } else { + Index offset = base_offset; + for (int j = 0; j < line_len; ++j, offset += stride) { + line_buf[j] = buf[offset]; + } + } + + // processs the line + if (is_power_of_two) { + processDataLineCooleyTukey(line_buf, line_len, log_len); + } + else { + processDataLineBluestein(line_buf, line_len, good_composite, log_len, a, b, pos_j_base_powered); + } + + // write back + if (FFTDir == FFT_FORWARD && stride == 1) { + memcpy(&buf[base_offset], line_buf, line_len*sizeof(ComplexScalar)); + } else { + Index offset = base_offset; + const ComplexScalar div_factor = ComplexScalar(1.0 / line_len, 0); + for (int j = 0; j < line_len; ++j, offset += stride) { + buf[offset] = (FFTDir == FFT_FORWARD) ? line_buf[j] : line_buf[j] * div_factor; + } + } + } + m_device.deallocate(line_buf); + if (!is_power_of_two) { + m_device.deallocate(a); + m_device.deallocate(b); + m_device.deallocate(pos_j_base_powered); + } + } + + if(!write_to_out) { + for (Index i = 0; i < m_size; ++i) { + data[i] = PartOf()(buf[i]); + } + m_device.deallocate(buf); + } + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE static bool isPowerOfTwo(Index x) { + eigen_assert(x > 0); + return !(x & (x - 1)); + } + + // The composite number for padding, used in Bluestein's FFT algorithm + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE static Index findGoodComposite(Index n) { + Index i = 2; + while (i < 2 * n - 1) i *= 2; + return i; + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE static Index getLog2(Index m) { + Index log2m = 0; + while (m >>= 1) log2m++; + return log2m; + } + + // Call Cooley Tukey algorithm directly, data length must be power of 2 + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void processDataLineCooleyTukey(ComplexScalar* line_buf, Index line_len, Index log_len) { + eigen_assert(isPowerOfTwo(line_len)); + scramble_FFT(line_buf, line_len); + compute_1D_Butterfly(line_buf, line_len, log_len); + } + + // Call Bluestein's FFT algorithm, m is a good composite number greater than (2 * n - 1), used as the padding length + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void processDataLineBluestein(ComplexScalar* line_buf, Index line_len, Index good_composite, Index log_len, ComplexScalar* a, ComplexScalar* b, const ComplexScalar* pos_j_base_powered) { + Index n = line_len; + Index m = good_composite; + ComplexScalar* data = line_buf; + + for (Index i = 0; i < n; ++i) { + if(FFTDir == FFT_FORWARD) { + a[i] = data[i] * numext::conj(pos_j_base_powered[i]); + } + else { + a[i] = data[i] * pos_j_base_powered[i]; + } + } + for (Index i = n; i < m; ++i) { + a[i] = ComplexScalar(0, 0); + } + + for (Index i = 0; i < n; ++i) { + if(FFTDir == FFT_FORWARD) { + b[i] = pos_j_base_powered[i]; + } + else { + b[i] = numext::conj(pos_j_base_powered[i]); + } + } + for (Index i = n; i < m - n; ++i) { + b[i] = ComplexScalar(0, 0); + } + for (Index i = m - n; i < m; ++i) { + if(FFTDir == FFT_FORWARD) { + b[i] = pos_j_base_powered[m-i]; + } + else { + b[i] = numext::conj(pos_j_base_powered[m-i]); + } + } + + scramble_FFT(a, m); + compute_1D_Butterfly(a, m, log_len); + + scramble_FFT(b, m); + compute_1D_Butterfly(b, m, log_len); + + for (Index i = 0; i < m; ++i) { + a[i] *= b[i]; + } + + scramble_FFT(a, m); + compute_1D_Butterfly(a, m, log_len); + + //Do the scaling after ifft + for (Index i = 0; i < m; ++i) { + a[i] /= m; + } + + for (Index i = 0; i < n; ++i) { + if(FFTDir == FFT_FORWARD) { + data[i] = a[i] * numext::conj(pos_j_base_powered[i]); + } + else { + data[i] = a[i] * pos_j_base_powered[i]; + } + } + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE static void scramble_FFT(ComplexScalar* data, Index n) { + eigen_assert(isPowerOfTwo(n)); + Index j = 1; + for (Index i = 1; i < n; ++i){ + if (j > i) { + std::swap(data[j-1], data[i-1]); + } + Index m = n >> 1; + while (m >= 2 && j > m) { + j -= m; + m >>= 1; + } + j += m; + } + } + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void butterfly_2(ComplexScalar* data) { + ComplexScalar tmp = data[1]; + data[1] = data[0] - data[1]; + data[0] += tmp; + } + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void butterfly_4(ComplexScalar* data) { + ComplexScalar tmp[4]; + tmp[0] = data[0] + data[1]; + tmp[1] = data[0] - data[1]; + tmp[2] = data[2] + data[3]; + if (Dir == FFT_FORWARD) { + tmp[3] = ComplexScalar(0.0, -1.0) * (data[2] - data[3]); + } else { + tmp[3] = ComplexScalar(0.0, 1.0) * (data[2] - data[3]); + } + data[0] = tmp[0] + tmp[2]; + data[1] = tmp[1] + tmp[3]; + data[2] = tmp[0] - tmp[2]; + data[3] = tmp[1] - tmp[3]; + } + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void butterfly_8(ComplexScalar* data) { + ComplexScalar tmp_1[8]; + ComplexScalar tmp_2[8]; + + tmp_1[0] = data[0] + data[1]; + tmp_1[1] = data[0] - data[1]; + tmp_1[2] = data[2] + data[3]; + if (Dir == FFT_FORWARD) { + tmp_1[3] = (data[2] - data[3]) * ComplexScalar(0, -1); + } else { + tmp_1[3] = (data[2] - data[3]) * ComplexScalar(0, 1); + } + tmp_1[4] = data[4] + data[5]; + tmp_1[5] = data[4] - data[5]; + tmp_1[6] = data[6] + data[7]; + if (Dir == FFT_FORWARD) { + tmp_1[7] = (data[6] - data[7]) * ComplexScalar(0, -1); + } else { + tmp_1[7] = (data[6] - data[7]) * ComplexScalar(0, 1); + } + tmp_2[0] = tmp_1[0] + tmp_1[2]; + tmp_2[1] = tmp_1[1] + tmp_1[3]; + tmp_2[2] = tmp_1[0] - tmp_1[2]; + tmp_2[3] = tmp_1[1] - tmp_1[3]; + tmp_2[4] = tmp_1[4] + tmp_1[6]; +// SQRT2DIV2 = sqrt(2)/2 +#define SQRT2DIV2 0.7071067811865476 + if (Dir == FFT_FORWARD) { + tmp_2[5] = (tmp_1[5] + tmp_1[7]) * ComplexScalar(SQRT2DIV2, -SQRT2DIV2); + tmp_2[6] = (tmp_1[4] - tmp_1[6]) * ComplexScalar(0, -1); + tmp_2[7] = (tmp_1[5] - tmp_1[7]) * ComplexScalar(-SQRT2DIV2, -SQRT2DIV2); + } else { + tmp_2[5] = (tmp_1[5] + tmp_1[7]) * ComplexScalar(SQRT2DIV2, SQRT2DIV2); + tmp_2[6] = (tmp_1[4] - tmp_1[6]) * ComplexScalar(0, 1); + tmp_2[7] = (tmp_1[5] - tmp_1[7]) * ComplexScalar(-SQRT2DIV2, SQRT2DIV2); + } + data[0] = tmp_2[0] + tmp_2[4]; + data[1] = tmp_2[1] + tmp_2[5]; + data[2] = tmp_2[2] + tmp_2[6]; + data[3] = tmp_2[3] + tmp_2[7]; + data[4] = tmp_2[0] - tmp_2[4]; + data[5] = tmp_2[1] - tmp_2[5]; + data[6] = tmp_2[2] - tmp_2[6]; + data[7] = tmp_2[3] - tmp_2[7]; + } + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void butterfly_1D_merge( + ComplexScalar* data, Index n, Index n_power_of_2) { + // Original code: + // RealScalar wtemp = std::sin(M_PI/n); + // RealScalar wpi = -std::sin(2 * M_PI/n); + const RealScalar wtemp = m_sin_PI_div_n_LUT[n_power_of_2]; + const RealScalar wpi = (Dir == FFT_FORWARD) + ? m_minus_sin_2_PI_div_n_LUT[n_power_of_2] + : -m_minus_sin_2_PI_div_n_LUT[n_power_of_2]; + + const ComplexScalar wp(wtemp, wpi); + const ComplexScalar wp_one = wp + ComplexScalar(1, 0); + const ComplexScalar wp_one_2 = wp_one * wp_one; + const ComplexScalar wp_one_3 = wp_one_2 * wp_one; + const ComplexScalar wp_one_4 = wp_one_3 * wp_one; + const Index n2 = n / 2; + ComplexScalar w(1.0, 0.0); + for (Index i = 0; i < n2; i += 4) { + ComplexScalar temp0(data[i + n2] * w); + ComplexScalar temp1(data[i + 1 + n2] * w * wp_one); + ComplexScalar temp2(data[i + 2 + n2] * w * wp_one_2); + ComplexScalar temp3(data[i + 3 + n2] * w * wp_one_3); + w = w * wp_one_4; + + data[i + n2] = data[i] - temp0; + data[i] += temp0; + + data[i + 1 + n2] = data[i + 1] - temp1; + data[i + 1] += temp1; + + data[i + 2 + n2] = data[i + 2] - temp2; + data[i + 2] += temp2; + + data[i + 3 + n2] = data[i + 3] - temp3; + data[i + 3] += temp3; + } + } + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void compute_1D_Butterfly( + ComplexScalar* data, Index n, Index n_power_of_2) { + eigen_assert(isPowerOfTwo(n)); + if (n > 8) { + compute_1D_Butterfly(data, n / 2, n_power_of_2 - 1); + compute_1D_Butterfly(data + n / 2, n / 2, n_power_of_2 - 1); + butterfly_1D_merge(data, n, n_power_of_2); + } else if (n == 8) { + butterfly_8(data); + } else if (n == 4) { + butterfly_4(data); + } else if (n == 2) { + butterfly_2(data); + } + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index getBaseOffsetFromIndex(Index index, Index omitted_dim) const { + Index result = 0; + + if (static_cast(Layout) == static_cast(ColMajor)) { + for (int i = NumDims - 1; i > omitted_dim; --i) { + const Index partial_m_stride = m_strides[i] / m_dimensions[omitted_dim]; + const Index idx = index / partial_m_stride; + index -= idx * partial_m_stride; + result += idx * m_strides[i]; + } + result += index; + } + else { + for (Index i = 0; i < omitted_dim; ++i) { + const Index partial_m_stride = m_strides[i] / m_dimensions[omitted_dim]; + const Index idx = index / partial_m_stride; + index -= idx * partial_m_stride; + result += idx * m_strides[i]; + } + result += index; + } + // Value of index_coords[omitted_dim] is not determined to this step + return result; + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index getIndexFromOffset(Index base, Index omitted_dim, Index offset) const { + Index result = base + offset * m_strides[omitted_dim] ; + return result; + } + + protected: + Index m_size; + const FFT& m_fft; + Dimensions m_dimensions; + array m_strides; + TensorEvaluator m_impl; + CoeffReturnType* m_data; + const Device& m_device; + + // This will support a maximum FFT size of 2^32 for each dimension + // m_sin_PI_div_n_LUT[i] = (-2) * std::sin(M_PI / std::pow(2,i)) ^ 2; + const RealScalar m_sin_PI_div_n_LUT[32] = { + RealScalar(0.0), + RealScalar(-2), + RealScalar(-0.999999999999999), + RealScalar(-0.292893218813453), + RealScalar(-0.0761204674887130), + RealScalar(-0.0192147195967696), + RealScalar(-0.00481527332780311), + RealScalar(-0.00120454379482761), + RealScalar(-3.01181303795779e-04), + RealScalar(-7.52981608554592e-05), + RealScalar(-1.88247173988574e-05), + RealScalar(-4.70619042382852e-06), + RealScalar(-1.17654829809007e-06), + RealScalar(-2.94137117780840e-07), + RealScalar(-7.35342821488550e-08), + RealScalar(-1.83835707061916e-08), + RealScalar(-4.59589268710903e-09), + RealScalar(-1.14897317243732e-09), + RealScalar(-2.87243293150586e-10), + RealScalar( -7.18108232902250e-11), + RealScalar(-1.79527058227174e-11), + RealScalar(-4.48817645568941e-12), + RealScalar(-1.12204411392298e-12), + RealScalar(-2.80511028480785e-13), + RealScalar(-7.01277571201985e-14), + RealScalar(-1.75319392800498e-14), + RealScalar(-4.38298482001247e-15), + RealScalar(-1.09574620500312e-15), + RealScalar(-2.73936551250781e-16), + RealScalar(-6.84841378126949e-17), + RealScalar(-1.71210344531737e-17), + RealScalar(-4.28025861329343e-18) + }; + + // m_minus_sin_2_PI_div_n_LUT[i] = -std::sin(2 * M_PI / std::pow(2,i)); + const RealScalar m_minus_sin_2_PI_div_n_LUT[32] = { + RealScalar(0.0), + RealScalar(0.0), + RealScalar(-1.00000000000000e+00), + RealScalar(-7.07106781186547e-01), + RealScalar(-3.82683432365090e-01), + RealScalar(-1.95090322016128e-01), + RealScalar(-9.80171403295606e-02), + RealScalar(-4.90676743274180e-02), + RealScalar(-2.45412285229123e-02), + RealScalar(-1.22715382857199e-02), + RealScalar(-6.13588464915448e-03), + RealScalar(-3.06795676296598e-03), + RealScalar(-1.53398018628477e-03), + RealScalar(-7.66990318742704e-04), + RealScalar(-3.83495187571396e-04), + RealScalar(-1.91747597310703e-04), + RealScalar(-9.58737990959773e-05), + RealScalar(-4.79368996030669e-05), + RealScalar(-2.39684498084182e-05), + RealScalar(-1.19842249050697e-05), + RealScalar(-5.99211245264243e-06), + RealScalar(-2.99605622633466e-06), + RealScalar(-1.49802811316901e-06), + RealScalar(-7.49014056584716e-07), + RealScalar(-3.74507028292384e-07), + RealScalar(-1.87253514146195e-07), + RealScalar(-9.36267570730981e-08), + RealScalar(-4.68133785365491e-08), + RealScalar(-2.34066892682746e-08), + RealScalar(-1.17033446341373e-08), + RealScalar(-5.85167231706864e-09), + RealScalar(-2.92583615853432e-09) + }; +}; + +} // end namespace Eigen + +#endif // EIGEN_HAS_CONSTEXPR + + +#endif // EIGEN_CXX11_TENSOR_TENSOR_FFT_H diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorFixedSize.h b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorFixedSize.h new file mode 100644 index 0000000000..fcee5f60d0 --- /dev/null +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorFixedSize.h @@ -0,0 +1,389 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Benoit Steiner +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CXX11_TENSOR_TENSOR_FIXED_SIZE_H +#define EIGEN_CXX11_TENSOR_TENSOR_FIXED_SIZE_H + +namespace Eigen { + +/** \class TensorFixedSize + * \ingroup CXX11_Tensor_Module + * + * \brief The fixed sized version of the tensor class. + * + * The fixed sized equivalent of + * Eigen::Tensor t(3, 5, 7); + * is + * Eigen::TensorFixedSize> t; + */ + +template +class TensorFixedSize : public TensorBase > +{ + public: + typedef TensorFixedSize Self; + typedef TensorBase > Base; + typedef typename Eigen::internal::nested::type Nested; + typedef typename internal::traits::StorageKind StorageKind; + typedef typename internal::traits::Index Index; + typedef Scalar_ Scalar; + typedef typename NumTraits::Real RealScalar; + typedef typename Base::CoeffReturnType CoeffReturnType; + + static const int Options = Options_; + + enum { + IsAligned = bool(EIGEN_MAX_ALIGN_BYTES>0), + Layout = Options_ & RowMajor ? RowMajor : ColMajor, + CoordAccess = true, + RawAccess = true + }; + + typedef Dimensions_ Dimensions; + static const std::size_t NumIndices = Dimensions::count; + + protected: + TensorStorage m_storage; + + public: + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index rank() const { return NumIndices; } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index dimension(std::size_t n) const { return m_storage.dimensions()[n]; } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Dimensions& dimensions() const { return m_storage.dimensions(); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index size() const { return m_storage.size(); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar *data() { return m_storage.data(); } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar *data() const { return m_storage.data(); } + + // This makes EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED + // work, because that uses base().coeffRef() - and we don't yet + // implement a similar class hierarchy + inline Self& base() { return *this; } + inline const Self& base() const { return *this; } + +#if EIGEN_HAS_VARIADIC_TEMPLATES + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar& coeff(Index firstIndex, IndexTypes... otherIndices) const + { + // The number of indices used to access a tensor coefficient must be equal to the rank of the tensor. + EIGEN_STATIC_ASSERT(sizeof...(otherIndices) + 1 == NumIndices, YOU_MADE_A_PROGRAMMING_MISTAKE) + return coeff(array{{firstIndex, otherIndices...}}); + } +#endif + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const Scalar& coeff(const array& indices) const + { + eigen_internal_assert(checkIndexRange(indices)); + return m_storage.data()[linearizedIndex(indices)]; + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const Scalar& coeff(Index index) const + { + eigen_internal_assert(index >= 0 && index < size()); + return m_storage.data()[index]; + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const Scalar& coeff() const + { + EIGEN_STATIC_ASSERT(NumIndices == 0, YOU_MADE_A_PROGRAMMING_MISTAKE); + return m_storage.data()[0]; + } + + +#if EIGEN_HAS_VARIADIC_TEMPLATES + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRef(Index firstIndex, IndexTypes... otherIndices) + { + // The number of indices used to access a tensor coefficient must be equal to the rank of the tensor. + EIGEN_STATIC_ASSERT(sizeof...(otherIndices) + 1 == NumIndices, YOU_MADE_A_PROGRAMMING_MISTAKE) + return coeffRef(array{{firstIndex, otherIndices...}}); + } +#endif + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Scalar& coeffRef(const array& indices) + { + eigen_internal_assert(checkIndexRange(indices)); + return m_storage.data()[linearizedIndex(indices)]; + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Scalar& coeffRef(Index index) + { + eigen_internal_assert(index >= 0 && index < size()); + return m_storage.data()[index]; + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Scalar& coeffRef() + { + EIGEN_STATIC_ASSERT(NumIndices == 0, YOU_MADE_A_PROGRAMMING_MISTAKE); + return m_storage.data()[0]; + } + +#if EIGEN_HAS_VARIADIC_TEMPLATES + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar& operator()(Index firstIndex, IndexTypes... otherIndices) const + { + // The number of indices used to access a tensor coefficient must be equal to the rank of the tensor. + EIGEN_STATIC_ASSERT(sizeof...(otherIndices) + 1 == NumIndices, YOU_MADE_A_PROGRAMMING_MISTAKE) + return this->operator()(array{{firstIndex, otherIndices...}}); + } +#else + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const Scalar& operator()(Index i0, Index i1) const + { + if (Options&RowMajor) { + const Index index = i1 + i0 * m_storage.dimensions()[1]; + return m_storage.data()[index]; + } else { + const Index index = i0 + i1 * m_storage.dimensions()[0]; + return m_storage.data()[index]; + } + } + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const Scalar& operator()(Index i0, Index i1, Index i2) const + { + if (Options&RowMajor) { + const Index index = i2 + m_storage.dimensions()[2] * (i1 + m_storage.dimensions()[1] * i0); + return m_storage.data()[index]; + } else { + const Index index = i0 + m_storage.dimensions()[0] * (i1 + m_storage.dimensions()[1] * i2); + return m_storage.data()[index]; + } + } + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const Scalar& operator()(Index i0, Index i1, Index i2, Index i3) const + { + if (Options&RowMajor) { + const Index index = i3 + m_storage.dimensions()[3] * (i2 + m_storage.dimensions()[2] * (i1 + m_storage.dimensions()[1] * i0)); + return m_storage.data()[index]; + } else { + const Index index = i0 + m_storage.dimensions()[0] * (i1 + m_storage.dimensions()[1] * (i2 + m_storage.dimensions()[2] * i3)); + return m_storage.data()[index]; + } + } + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const Scalar& operator()(Index i0, Index i1, Index i2, Index i3, Index i4) const + { + if (Options&RowMajor) { + const Index index = i4 + m_storage.dimensions()[4] * (i3 + m_storage.dimensions()[3] * (i2 + m_storage.dimensions()[2] * (i1 + m_storage.dimensions()[1] * i0))); + return m_storage.data()[index]; + } else { + const Index index = i0 + m_storage.dimensions()[0] * (i1 + m_storage.dimensions()[1] * (i2 + m_storage.dimensions()[2] * (i3 + m_storage.dimensions()[3] * i4))); + return m_storage.data()[index]; + } + } +#endif + + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const Scalar& operator()(const array& indices) const + { + eigen_assert(checkIndexRange(indices)); + return coeff(indices); + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const Scalar& operator()(Index index) const + { + eigen_internal_assert(index >= 0 && index < size()); + return coeff(index); + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const Scalar& operator()() const + { + EIGEN_STATIC_ASSERT(NumIndices == 0, YOU_MADE_A_PROGRAMMING_MISTAKE); + return coeff(); + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const Scalar& operator[](Index index) const + { + // The bracket operator is only for vectors, use the parenthesis operator instead. + EIGEN_STATIC_ASSERT(NumIndices == 1, YOU_MADE_A_PROGRAMMING_MISTAKE); + return coeff(index); + } + +#if EIGEN_HAS_VARIADIC_TEMPLATES + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& operator()(Index firstIndex, IndexTypes... otherIndices) + { + // The number of indices used to access a tensor coefficient must be equal to the rank of the tensor. + EIGEN_STATIC_ASSERT(sizeof...(otherIndices) + 1 == NumIndices, YOU_MADE_A_PROGRAMMING_MISTAKE) + return operator()(array{{firstIndex, otherIndices...}}); + } +#else + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Scalar& operator()(Index i0, Index i1) + { + if (Options&RowMajor) { + const Index index = i1 + i0 * m_storage.dimensions()[1]; + return m_storage.data()[index]; + } else { + const Index index = i0 + i1 * m_storage.dimensions()[0]; + return m_storage.data()[index]; + } + } + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Scalar& operator()(Index i0, Index i1, Index i2) + { + if (Options&RowMajor) { + const Index index = i2 + m_storage.dimensions()[2] * (i1 + m_storage.dimensions()[1] * i0); + return m_storage.data()[index]; + } else { + const Index index = i0 + m_storage.dimensions()[0] * (i1 + m_storage.dimensions()[1] * i2); + return m_storage.data()[index]; + } + } + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Scalar& operator()(Index i0, Index i1, Index i2, Index i3) + { + if (Options&RowMajor) { + const Index index = i3 + m_storage.dimensions()[3] * (i2 + m_storage.dimensions()[2] * (i1 + m_storage.dimensions()[1] * i0)); + return m_storage.data()[index]; + } else { + const Index index = i0 + m_storage.dimensions()[0] * (i1 + m_storage.dimensions()[1] * (i2 + m_storage.dimensions()[2] * i3)); + return m_storage.data()[index]; + } + } + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Scalar& operator()(Index i0, Index i1, Index i2, Index i3, Index i4) + { + if (Options&RowMajor) { + const Index index = i4 + m_storage.dimensions()[4] * (i3 + m_storage.dimensions()[3] * (i2 + m_storage.dimensions()[2] * (i1 + m_storage.dimensions()[1] * i0))); + return m_storage.data()[index]; + } else { + const Index index = i0 + m_storage.dimensions()[0] * (i1 + m_storage.dimensions()[1] * (i2 + m_storage.dimensions()[2] * (i3 + m_storage.dimensions()[3] * i4))); + return m_storage.data()[index]; + } + } +#endif + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Scalar& operator()(const array& indices) + { + eigen_assert(checkIndexRange(indices)); + return coeffRef(indices); + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Scalar& operator()(Index index) + { + eigen_assert(index >= 0 && index < size()); + return coeffRef(index); + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Scalar& operator()() + { + EIGEN_STATIC_ASSERT(NumIndices == 0, YOU_MADE_A_PROGRAMMING_MISTAKE); + return coeffRef(); + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Scalar& operator[](Index index) + { + // The bracket operator is only for vectors, use the parenthesis operator instead + EIGEN_STATIC_ASSERT(NumIndices == 1, YOU_MADE_A_PROGRAMMING_MISTAKE) + return coeffRef(index); + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE TensorFixedSize() + : m_storage() + { + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE TensorFixedSize(const Self& other) + : m_storage(other.m_storage) + { + } + +#if EIGEN_HAS_RVALUE_REFERENCES + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorFixedSize(Self&& other) + : m_storage(other.m_storage) + { + } +#endif + + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE TensorFixedSize(const TensorBase& other) + { + typedef TensorAssignOp Assign; + Assign assign(*this, other.derived()); + internal::TensorExecutor::run(assign, DefaultDevice()); + } + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE TensorFixedSize(const TensorBase& other) + { + typedef TensorAssignOp Assign; + Assign assign(*this, other.derived()); + internal::TensorExecutor::run(assign, DefaultDevice()); + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE TensorFixedSize& operator=(const TensorFixedSize& other) + { + // FIXME: check that the dimensions of other match the dimensions of *this. + // Unfortunately this isn't possible yet when the rhs is an expression. + typedef TensorAssignOp Assign; + Assign assign(*this, other); + internal::TensorExecutor::run(assign, DefaultDevice()); + return *this; + } + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE TensorFixedSize& operator=(const OtherDerived& other) + { + // FIXME: check that the dimensions of other match the dimensions of *this. + // Unfortunately this isn't possible yet when the rhs is an expression. + typedef TensorAssignOp Assign; + Assign assign(*this, other); + internal::TensorExecutor::run(assign, DefaultDevice()); + return *this; + } + + protected: + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE bool checkIndexRange(const array& /*indices*/) const + { + using internal::array_apply_and_reduce; + using internal::array_zip_and_reduce; + using internal::greater_equal_zero_op; + using internal::logical_and_op; + using internal::lesser_op; + + return true; + // check whether the indices are all >= 0 + /* array_apply_and_reduce(indices) && + // check whether the indices fit in the dimensions + array_zip_and_reduce(indices, m_storage.dimensions());*/ + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Index linearizedIndex(const array& indices) const + { + if (Options&RowMajor) { + return m_storage.dimensions().IndexOfRowMajor(indices); + } else { + return m_storage.dimensions().IndexOfColMajor(indices); + } + } +}; + + +} // end namespace Eigen + +#endif // EIGEN_CXX11_TENSOR_TENSOR_FIXED_SIZE_H diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorForcedEval.h b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorForcedEval.h new file mode 100644 index 0000000000..bbd5eb3743 --- /dev/null +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorForcedEval.h @@ -0,0 +1,167 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Benoit Steiner +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CXX11_TENSOR_TENSOR_FORCED_EVAL_H +#define EIGEN_CXX11_TENSOR_TENSOR_FORCED_EVAL_H + +namespace Eigen { + +/** \class TensorForcedEval + * \ingroup CXX11_Tensor_Module + * + * \brief Tensor reshaping class. + * + * + */ +/// template class MakePointer_ is added to convert the host pointer to the device pointer. +/// It is added due to the fact that for our device compiler T* is not allowed. +/// If we wanted to use the same Evaluator functions we have to convert that type to our pointer T. +/// This is done through our MakePointer_ class. By default the Type in the MakePointer_ is T* . +/// Therefore, by adding the default value, we managed to convert the type and it does not break any +/// existing code as its default value is T*. +namespace internal { +template class MakePointer_> +struct traits > +{ + // Type promotion to handle the case where the types of the lhs and the rhs are different. + typedef typename XprType::Scalar Scalar; + typedef traits XprTraits; + typedef typename traits::StorageKind StorageKind; + typedef typename traits::Index Index; + typedef typename XprType::Nested Nested; + typedef typename remove_reference::type _Nested; + static const int NumDimensions = XprTraits::NumDimensions; + static const int Layout = XprTraits::Layout; + + enum { + Flags = 0 + }; + template struct MakePointer { + // Intermediate typedef to workaround MSVC issue. + typedef MakePointer_ MakePointerT; + typedef typename MakePointerT::Type Type; + }; +}; + +template class MakePointer_> +struct eval, Eigen::Dense> +{ + typedef const TensorForcedEvalOp& type; +}; + +template class MakePointer_> +struct nested, 1, typename eval >::type> +{ + typedef TensorForcedEvalOp type; +}; + +} // end namespace internal + + + +template class MakePointer_> +class TensorForcedEvalOp : public TensorBase, ReadOnlyAccessors> +{ + public: + typedef typename Eigen::internal::traits::Scalar Scalar; + typedef typename Eigen::NumTraits::Real RealScalar; + typedef typename internal::remove_const::type CoeffReturnType; + typedef typename Eigen::internal::nested::type Nested; + typedef typename Eigen::internal::traits::StorageKind StorageKind; + typedef typename Eigen::internal::traits::Index Index; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorForcedEvalOp(const XprType& expr) + : m_xpr(expr) {} + + EIGEN_DEVICE_FUNC + const typename internal::remove_all::type& + expression() const { return m_xpr; } + + protected: + typename XprType::Nested m_xpr; +}; + + +template class MakePointer_> +struct TensorEvaluator, Device> +{ + typedef TensorForcedEvalOp XprType; + typedef typename ArgType::Scalar Scalar; + typedef typename TensorEvaluator::Dimensions Dimensions; + typedef typename XprType::Index Index; + typedef typename XprType::CoeffReturnType CoeffReturnType; + typedef typename PacketType::type PacketReturnType; + static const int PacketSize = internal::unpacket_traits::size; + + enum { + IsAligned = true, + PacketAccess = (PacketSize > 1), + Layout = TensorEvaluator::Layout, + RawAccess = true + }; + + EIGEN_DEVICE_FUNC TensorEvaluator(const XprType& op, const Device& device) + /// op_ is used for sycl + : m_impl(op.expression(), device), m_op(op.expression()), m_device(device), m_buffer(NULL) + { } + + EIGEN_DEVICE_FUNC const Dimensions& dimensions() const { return m_impl.dimensions(); } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(CoeffReturnType*) { + const Index numValues = internal::array_prod(m_impl.dimensions()); + m_buffer = (CoeffReturnType*)m_device.allocate(numValues * sizeof(CoeffReturnType)); + // Should initialize the memory in case we're dealing with non POD types. + if (NumTraits::RequireInitialization) { + for (Index i = 0; i < numValues; ++i) { + new(m_buffer+i) CoeffReturnType(); + } + } + typedef TensorEvalToOp< const typename internal::remove_const::type > EvalTo; + EvalTo evalToTmp(m_buffer, m_op); + const bool PacketAccess = internal::IsVectorizable::value; + internal::TensorExecutor::type, PacketAccess>::run(evalToTmp, m_device); + return true; + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void cleanup() { + m_device.deallocate(m_buffer); + m_buffer = NULL; + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const + { + return m_buffer[index]; + } + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packet(Index index) const + { + return internal::ploadt(m_buffer + index); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost costPerCoeff(bool vectorized) const { + return TensorOpCost(sizeof(CoeffReturnType), 0, 0, vectorized, PacketSize); + } + + EIGEN_DEVICE_FUNC typename MakePointer::Type data() const { return m_buffer; } + + /// required by sycl in order to extract the sycl accessor + const TensorEvaluator& impl() { return m_impl; } + /// used by sycl in order to build the sycl buffer + const Device& device() const{return m_device;} + private: + TensorEvaluator m_impl; + const ArgType m_op; + const Device& m_device; + typename MakePointer::Type m_buffer; +}; + + +} // end namespace Eigen + +#endif // EIGEN_CXX11_TENSOR_TENSOR_FORCED_EVAL_H diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorForwardDeclarations.h b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorForwardDeclarations.h new file mode 100644 index 0000000000..52b803d7f2 --- /dev/null +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorForwardDeclarations.h @@ -0,0 +1,109 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Benoit Steiner +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CXX11_TENSOR_TENSOR_FORWARD_DECLARATIONS_H +#define EIGEN_CXX11_TENSOR_TENSOR_FORWARD_DECLARATIONS_H + +namespace Eigen { + +// MakePointer class is used as a container of the adress space of the pointer +// on the host and on the device. From the host side it generates the T* pointer +// and when EIGEN_USE_SYCL is used it construct a buffer with a map_allocator to +// T* m_data on the host. It is always called on the device. +// Specialisation of MakePointer class for creating the sycl buffer with +// map_allocator. +template struct MakePointer { + typedef T* Type; +}; + +template class MakePointer_ = MakePointer> class TensorMap; +template class Tensor; +template class TensorFixedSize; +template class TensorRef; +template class TensorBase; + +template class TensorCwiseNullaryOp; +template class TensorCwiseUnaryOp; +template class TensorCwiseBinaryOp; +template class TensorCwiseTernaryOp; +template class TensorSelectOp; +template class MakePointer_ = MakePointer > class TensorReductionOp; +template class TensorIndexTupleOp; +template class TensorTupleReducerOp; +template class TensorConcatenationOp; +template class TensorContractionOp; +template class TensorConversionOp; +template class TensorConvolutionOp; +template class TensorFFTOp; +template class TensorPatchOp; +template class TensorImagePatchOp; +template class TensorVolumePatchOp; +template class TensorBroadcastingOp; +template class TensorChippingOp; +template class TensorReshapingOp; +template class TensorLayoutSwapOp; +template class TensorSlicingOp; +template class TensorReverseOp; +template class TensorPaddingOp; +template class TensorShufflingOp; +template class TensorStridingOp; +template class TensorStridingSlicingOp; +template class TensorInflationOp; +template class TensorGeneratorOp; +template class TensorAssignOp; +template class TensorScanOp; + +template class TensorCustomUnaryOp; +template class TensorCustomBinaryOp; + +template class MakePointer_ = MakePointer> class TensorEvalToOp; +template class MakePointer_ = MakePointer> class TensorForcedEvalOp; + +template class TensorDevice; +template struct TensorEvaluator; + +struct DefaultDevice; +struct ThreadPoolDevice; +struct GpuDevice; +struct SyclDevice; + +enum FFTResultType { + RealPart = 0, + ImagPart = 1, + BothParts = 2 +}; + +enum FFTDirection { + FFT_FORWARD = 0, + FFT_REVERSE = 1 +}; + + +namespace internal { + +template +struct IsVectorizable { + static const bool value = TensorEvaluator::PacketAccess; +}; + +template +struct IsVectorizable { + static const bool value = TensorEvaluator::PacketAccess && + TensorEvaluator::IsAligned; +}; + +template ::value> +class TensorExecutor; + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_CXX11_TENSOR_TENSOR_FORWARD_DECLARATIONS_H diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorFunctors.h b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorFunctors.h new file mode 100644 index 0000000000..d73f6dc683 --- /dev/null +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorFunctors.h @@ -0,0 +1,489 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Benoit Steiner +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CXX11_TENSOR_TENSOR_FUNCTORS_H +#define EIGEN_CXX11_TENSOR_TENSOR_FUNCTORS_H + +namespace Eigen { +namespace internal { + + +/** \internal + * \brief Template functor to compute the modulo between an array and a scalar. + */ +template +struct scalar_mod_op { + EIGEN_DEVICE_FUNC scalar_mod_op(const Scalar& divisor) : m_divisor(divisor) {} + EIGEN_DEVICE_FUNC inline Scalar operator() (const Scalar& a) const { return a % m_divisor; } + const Scalar m_divisor; +}; +template +struct functor_traits > +{ enum { Cost = scalar_div_cost::value, PacketAccess = false }; }; + + +/** \internal + * \brief Template functor to compute the modulo between 2 arrays. + */ +template +struct scalar_mod2_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_mod2_op); + EIGEN_DEVICE_FUNC inline Scalar operator() (const Scalar& a, const Scalar& b) const { return a % b; } +}; +template +struct functor_traits > +{ enum { Cost = scalar_div_cost::value, PacketAccess = false }; }; + +template +struct scalar_fmod_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_fmod_op); + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar + operator()(const Scalar& a, const Scalar& b) const { + return numext::fmod(a, b); + } +}; +template +struct functor_traits > { + enum { Cost = 13, // Reciprocal throughput of FPREM on Haswell. + PacketAccess = false }; +}; + + +/** \internal + * \brief Template functor to compute the sigmoid of a scalar + * \sa class CwiseUnaryOp, ArrayBase::sigmoid() + */ +template +struct scalar_sigmoid_op { + EIGEN_EMPTY_STRUCT_CTOR(scalar_sigmoid_op) + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T operator()(const T& x) const { + const T one = T(1); + return one / (one + numext::exp(-x)); + } + + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Packet packetOp(const Packet& x) const { + const Packet one = pset1(T(1)); + return pdiv(one, padd(one, pexp(pnegate(x)))); + } +}; + +template +struct functor_traits > { + enum { + Cost = NumTraits::AddCost * 2 + NumTraits::MulCost * 6, + PacketAccess = packet_traits::HasAdd && packet_traits::HasDiv && + packet_traits::HasNegate && packet_traits::HasExp + }; +}; + + +template +struct reducer_traits { + enum { + Cost = 1, + PacketAccess = false + }; +}; + +// Standard reduction functors +template struct SumReducer +{ + static const bool PacketAccess = packet_traits::HasAdd; + static const bool IsStateful = false; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reduce(const T t, T* accum) const { + internal::scalar_sum_op sum_op; + *accum = sum_op(*accum, t); + } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reducePacket(const Packet& p, Packet* accum) const { + (*accum) = padd(*accum, p); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T initialize() const { + internal::scalar_cast_op conv; + return conv(0); + } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet initializePacket() const { + return pset1(initialize()); + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalize(const T accum) const { + return accum; + } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet finalizePacket(const Packet& vaccum) const { + return vaccum; + } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalizeBoth(const T saccum, const Packet& vaccum) const { + internal::scalar_sum_op sum_op; + return sum_op(saccum, predux(vaccum)); + } +}; + +template +struct reducer_traits, Device> { + enum { + Cost = NumTraits::AddCost, + PacketAccess = PacketType::HasAdd + }; +}; + + +template struct MeanReducer +{ + static const bool PacketAccess = packet_traits::HasAdd && !NumTraits::IsInteger; + static const bool IsStateful = true; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + MeanReducer() : scalarCount_(0), packetCount_(0) { } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reduce(const T t, T* accum) { + internal::scalar_sum_op sum_op; + *accum = sum_op(*accum, t); + scalarCount_++; + } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reducePacket(const Packet& p, Packet* accum) { + (*accum) = padd(*accum, p); + packetCount_++; + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T initialize() const { + internal::scalar_cast_op conv; + return conv(0); + } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet initializePacket() const { + return pset1(initialize()); + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalize(const T accum) const { + return accum / scalarCount_; + } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet finalizePacket(const Packet& vaccum) const { + return pdiv(vaccum, pset1(packetCount_)); + } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalizeBoth(const T saccum, const Packet& vaccum) const { + internal::scalar_sum_op sum_op; + return sum_op(saccum, predux(vaccum)) / (scalarCount_ + packetCount_ * unpacket_traits::size); + } + + protected: + DenseIndex scalarCount_; + DenseIndex packetCount_; +}; + +template +struct reducer_traits, Device> { + enum { + Cost = NumTraits::AddCost, + PacketAccess = PacketType::HasAdd + }; +}; + + +template +struct MinMaxBottomValue { + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE T bottom_value() { + return Eigen::NumTraits::lowest(); + } +}; +template +struct MinMaxBottomValue { + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE T bottom_value() { + return -Eigen::NumTraits::infinity(); + } +}; +template +struct MinMaxBottomValue { + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE T bottom_value() { + return Eigen::NumTraits::highest(); + } +}; +template +struct MinMaxBottomValue { + EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE T bottom_value() { + return Eigen::NumTraits::infinity(); + } +}; + + +template struct MaxReducer +{ + static const bool PacketAccess = packet_traits::HasMax; + static const bool IsStateful = false; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reduce(const T t, T* accum) const { + if (t > *accum) { *accum = t; } + } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reducePacket(const Packet& p, Packet* accum) const { + (*accum) = pmax(*accum, p); + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T initialize() const { + return MinMaxBottomValue::IsInteger>::bottom_value(); + } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet initializePacket() const { + return pset1(initialize()); + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalize(const T accum) const { + return accum; + } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet finalizePacket(const Packet& vaccum) const { + return vaccum; + } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalizeBoth(const T saccum, const Packet& vaccum) const { + return numext::maxi(saccum, predux_max(vaccum)); + } +}; + +template +struct reducer_traits, Device> { + enum { + Cost = NumTraits::AddCost, + PacketAccess = PacketType::HasMax + }; +}; + + +template struct MinReducer +{ + static const bool PacketAccess = packet_traits::HasMin; + static const bool IsStateful = false; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reduce(const T t, T* accum) const { + if (t < *accum) { *accum = t; } + } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reducePacket(const Packet& p, Packet* accum) const { + (*accum) = pmin(*accum, p); + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T initialize() const { + return MinMaxBottomValue::IsInteger>::bottom_value(); + } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet initializePacket() const { + return pset1(initialize()); + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalize(const T accum) const { + return accum; + } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet finalizePacket(const Packet& vaccum) const { + return vaccum; + } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalizeBoth(const T saccum, const Packet& vaccum) const { + return numext::mini(saccum, predux_min(vaccum)); + } +}; + +template +struct reducer_traits, Device> { + enum { + Cost = NumTraits::AddCost, + PacketAccess = PacketType::HasMin + }; +}; + + +template struct ProdReducer +{ + static const bool PacketAccess = packet_traits::HasMul; + static const bool IsStateful = false; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reduce(const T t, T* accum) const { + internal::scalar_product_op prod_op; + (*accum) = prod_op(*accum, t); + } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reducePacket(const Packet& p, Packet* accum) const { + (*accum) = pmul(*accum, p); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T initialize() const { + internal::scalar_cast_op conv; + return conv(1); + } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet initializePacket() const { + return pset1(initialize()); + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalize(const T accum) const { + return accum; + } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet finalizePacket(const Packet& vaccum) const { + return vaccum; + } + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalizeBoth(const T saccum, const Packet& vaccum) const { + internal::scalar_product_op prod_op; + return prod_op(saccum, predux_mul(vaccum)); + } +}; + +template +struct reducer_traits, Device> { + enum { + Cost = NumTraits::MulCost, + PacketAccess = PacketType::HasMul + }; +}; + + +struct AndReducer +{ + static const bool PacketAccess = false; + static const bool IsStateful = false; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reduce(bool t, bool* accum) const { + *accum = *accum && t; + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool initialize() const { + return true; + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool finalize(bool accum) const { + return accum; + } +}; + +template +struct reducer_traits { + enum { + Cost = 1, + PacketAccess = false + }; +}; + + +struct OrReducer { + static const bool PacketAccess = false; + static const bool IsStateful = false; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reduce(bool t, bool* accum) const { + *accum = *accum || t; + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool initialize() const { + return false; + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool finalize(bool accum) const { + return accum; + } +}; + +template +struct reducer_traits { + enum { + Cost = 1, + PacketAccess = false + }; +}; + + +// Argmin/Argmax reducers +template struct ArgMaxTupleReducer +{ + static const bool PacketAccess = false; + static const bool IsStateful = false; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reduce(const T t, T* accum) const { + if (t.second > accum->second) { *accum = t; } + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T initialize() const { + return T(0, NumTraits::lowest()); + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalize(const T& accum) const { + return accum; + } +}; + +template +struct reducer_traits, Device> { + enum { + Cost = NumTraits::AddCost, + PacketAccess = false + }; +}; + + +template struct ArgMinTupleReducer +{ + static const bool PacketAccess = false; + static const bool IsStateful = false; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reduce(const T& t, T* accum) const { + if (t.second < accum->second) { *accum = t; } + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T initialize() const { + return T(0, NumTraits::highest()); + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalize(const T& accum) const { + return accum; + } +}; + +template +struct reducer_traits, Device> { + enum { + Cost = NumTraits::AddCost, + PacketAccess = false + }; +}; + + +template +class GaussianGenerator { + public: + static const bool PacketAccess = false; + + EIGEN_DEVICE_FUNC GaussianGenerator(const array& means, + const array& std_devs) + : m_means(means) + { + for (size_t i = 0; i < NumDims; ++i) { + m_two_sigmas[i] = std_devs[i] * std_devs[i] * 2; + } + } + + EIGEN_DEVICE_FUNC T operator()(const array& coordinates) const { + T tmp = T(0); + for (size_t i = 0; i < NumDims; ++i) { + T offset = coordinates[i] - m_means[i]; + tmp += offset * offset / m_two_sigmas[i]; + } + return numext::exp(-tmp); + } + + private: + array m_means; + array m_two_sigmas; +}; + +template +struct functor_traits > { + enum { + Cost = NumDims * (2 * NumTraits::AddCost + NumTraits::MulCost + + functor_traits >::Cost) + + functor_traits >::Cost, + PacketAccess = GaussianGenerator::PacketAccess + }; +}; + +} // end namespace internal +} // end namespace Eigen + +#endif // EIGEN_CXX11_TENSOR_TENSOR_FUNCTORS_H diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorGenerator.h b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorGenerator.h new file mode 100644 index 0000000000..eb1d4934ed --- /dev/null +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorGenerator.h @@ -0,0 +1,185 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2015 Benoit Steiner +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CXX11_TENSOR_TENSOR_GENERATOR_H +#define EIGEN_CXX11_TENSOR_TENSOR_GENERATOR_H + +namespace Eigen { + +/** \class TensorGenerator + * \ingroup CXX11_Tensor_Module + * + * \brief Tensor generator class. + * + * + */ +namespace internal { +template +struct traits > : public traits +{ + typedef typename XprType::Scalar Scalar; + typedef traits XprTraits; + typedef typename XprTraits::StorageKind StorageKind; + typedef typename XprTraits::Index Index; + typedef typename XprType::Nested Nested; + typedef typename remove_reference::type _Nested; + static const int NumDimensions = XprTraits::NumDimensions; + static const int Layout = XprTraits::Layout; +}; + +template +struct eval, Eigen::Dense> +{ + typedef const TensorGeneratorOp& type; +}; + +template +struct nested, 1, typename eval >::type> +{ + typedef TensorGeneratorOp type; +}; + +} // end namespace internal + + + +template +class TensorGeneratorOp : public TensorBase, ReadOnlyAccessors> +{ + public: + typedef typename Eigen::internal::traits::Scalar Scalar; + typedef typename Eigen::NumTraits::Real RealScalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + typedef typename Eigen::internal::nested::type Nested; + typedef typename Eigen::internal::traits::StorageKind StorageKind; + typedef typename Eigen::internal::traits::Index Index; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorGeneratorOp(const XprType& expr, const Generator& generator) + : m_xpr(expr), m_generator(generator) {} + + EIGEN_DEVICE_FUNC + const Generator& generator() const { return m_generator; } + + EIGEN_DEVICE_FUNC + const typename internal::remove_all::type& + expression() const { return m_xpr; } + + protected: + typename XprType::Nested m_xpr; + const Generator m_generator; +}; + + +// Eval as rvalue +template +struct TensorEvaluator, Device> +{ + typedef TensorGeneratorOp XprType; + typedef typename XprType::Index Index; + typedef typename TensorEvaluator::Dimensions Dimensions; + static const int NumDims = internal::array_size::value; + typedef typename XprType::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + typedef typename PacketType::type PacketReturnType; + enum { + IsAligned = false, + PacketAccess = (internal::unpacket_traits::size > 1), + BlockAccess = false, + Layout = TensorEvaluator::Layout, + CoordAccess = false, // to be implemented + RawAccess = false + }; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorEvaluator(const XprType& op, const Device& device) + : m_generator(op.generator()) + { + TensorEvaluator impl(op.expression(), device); + m_dimensions = impl.dimensions(); + + if (static_cast(Layout) == static_cast(ColMajor)) { + m_strides[0] = 1; + for (int i = 1; i < NumDims; ++i) { + m_strides[i] = m_strides[i - 1] * m_dimensions[i - 1]; + } + } else { + m_strides[NumDims - 1] = 1; + for (int i = NumDims - 2; i >= 0; --i) { + m_strides[i] = m_strides[i + 1] * m_dimensions[i + 1]; + } + } + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Dimensions& dimensions() const { return m_dimensions; } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(Scalar* /*data*/) { + return true; + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void cleanup() { + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const + { + array coords; + extract_coordinates(index, coords); + return m_generator(coords); + } + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packet(Index index) const + { + const int packetSize = internal::unpacket_traits::size; + EIGEN_STATIC_ASSERT((packetSize > 1), YOU_MADE_A_PROGRAMMING_MISTAKE) + eigen_assert(index+packetSize-1 < dimensions().TotalSize()); + + EIGEN_ALIGN_MAX typename internal::remove_const::type values[packetSize]; + for (int i = 0; i < packetSize; ++i) { + values[i] = coeff(index+i); + } + PacketReturnType rslt = internal::pload(values); + return rslt; + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost + costPerCoeff(bool) const { + // TODO(rmlarsen): This is just a placeholder. Define interface to make + // generators return their cost. + return TensorOpCost(0, 0, TensorOpCost::AddCost() + + TensorOpCost::MulCost()); + } + + EIGEN_DEVICE_FUNC Scalar* data() const { return NULL; } + + protected: + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + void extract_coordinates(Index index, array& coords) const { + if (static_cast(Layout) == static_cast(ColMajor)) { + for (int i = NumDims - 1; i > 0; --i) { + const Index idx = index / m_strides[i]; + index -= idx * m_strides[i]; + coords[i] = idx; + } + coords[0] = index; + } else { + for (int i = 0; i < NumDims - 1; ++i) { + const Index idx = index / m_strides[i]; + index -= idx * m_strides[i]; + coords[i] = idx; + } + coords[NumDims-1] = index; + } + } + + Dimensions m_dimensions; + array m_strides; + Generator m_generator; +}; + +} // end namespace Eigen + +#endif // EIGEN_CXX11_TENSOR_TENSOR_GENERATOR_H diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorGlobalFunctions.h b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorGlobalFunctions.h new file mode 100644 index 0000000000..665b861cfd --- /dev/null +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorGlobalFunctions.h @@ -0,0 +1,33 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2016 Eugene Brevdo +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CXX11_TENSOR_TENSOR_GLOBAL_FUNCTIONS_H +#define EIGEN_CXX11_TENSOR_TENSOR_GLOBAL_FUNCTIONS_H + +namespace Eigen { + +/** \cpp11 \returns an expression of the coefficient-wise betainc(\a x, \a a, \a b) to the given tensors. + * + * This function computes the regularized incomplete beta function (integral). + * + */ +template +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const + TensorCwiseTernaryOp, + const ADerived, const BDerived, const XDerived> + betainc(const ADerived& a, const BDerived& b, const XDerived& x) { + return TensorCwiseTernaryOp< + internal::scalar_betainc_op, const ADerived, + const BDerived, const XDerived>( + a, b, x, internal::scalar_betainc_op()); +} + +} // end namespace Eigen + +#endif // EIGEN_CXX11_TENSOR_TENSOR_GLOBAL_FUNCTIONS_H diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorIO.h b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorIO.h new file mode 100644 index 0000000000..a901c5dd45 --- /dev/null +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorIO.h @@ -0,0 +1,79 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Benoit Steiner +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CXX11_TENSOR_TENSOR_IO_H +#define EIGEN_CXX11_TENSOR_TENSOR_IO_H + +namespace Eigen { + +namespace internal { + +// Print the tensor as a 2d matrix +template +struct TensorPrinter { + static void run (std::ostream& os, const Tensor& tensor) { + typedef typename internal::remove_const::type Scalar; + typedef typename Tensor::Index Index; + const Index total_size = internal::array_prod(tensor.dimensions()); + if (total_size > 0) { + const Index first_dim = Eigen::internal::array_get<0>(tensor.dimensions()); + static const int layout = Tensor::Layout; + Map > matrix(const_cast(tensor.data()), first_dim, total_size/first_dim); + os << matrix; + } + } +}; + + +// Print the tensor as a vector +template +struct TensorPrinter { + static void run (std::ostream& os, const Tensor& tensor) { + typedef typename internal::remove_const::type Scalar; + typedef typename Tensor::Index Index; + const Index total_size = internal::array_prod(tensor.dimensions()); + if (total_size > 0) { + Map > array(const_cast(tensor.data()), total_size); + os << array; + } + } +}; + + +// Print the tensor as a scalar +template +struct TensorPrinter { + static void run (std::ostream& os, const Tensor& tensor) { + os << tensor.coeff(0); + } +}; +} + +template +std::ostream& operator << (std::ostream& os, const TensorBase& expr) { + typedef TensorEvaluator, DefaultDevice> Evaluator; + typedef typename Evaluator::Dimensions Dimensions; + + // Evaluate the expression if needed + TensorForcedEvalOp eval = expr.eval(); + Evaluator tensor(eval, DefaultDevice()); + tensor.evalSubExprsIfNeeded(NULL); + + // Print the result + static const int rank = internal::array_size::value; + internal::TensorPrinter::run(os, tensor); + + // Cleanup. + tensor.cleanup(); + return os; +} + +} // end namespace Eigen + +#endif // EIGEN_CXX11_TENSOR_TENSOR_IO_H diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorImagePatch.h b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorImagePatch.h new file mode 100644 index 0000000000..566856ed20 --- /dev/null +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorImagePatch.h @@ -0,0 +1,509 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Benoit Steiner +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CXX11_TENSOR_TENSOR_IMAGE_PATCH_H +#define EIGEN_CXX11_TENSOR_TENSOR_IMAGE_PATCH_H + +namespace Eigen { + +/** \class TensorImagePatch + * \ingroup CXX11_Tensor_Module + * + * \brief Patch extraction specialized for image processing. + * This assumes that the input has a least 3 dimensions ordered as follow: + * 1st dimension: channels (of size d) + * 2nd dimension: rows (of size r) + * 3rd dimension: columns (of size c) + * There can be additional dimensions such as time (for video) or batch (for + * bulk processing after the first 3. + * Calling the image patch code with patch_rows and patch_cols is equivalent + * to calling the regular patch extraction code with parameters d, patch_rows, + * patch_cols, and 1 for all the additional dimensions. + */ +namespace internal { +template +struct traits > : public traits +{ + typedef typename internal::remove_const::type Scalar; + typedef traits XprTraits; + typedef typename XprTraits::StorageKind StorageKind; + typedef typename XprTraits::Index Index; + typedef typename XprType::Nested Nested; + typedef typename remove_reference::type _Nested; + static const int NumDimensions = XprTraits::NumDimensions + 1; + static const int Layout = XprTraits::Layout; +}; + +template +struct eval, Eigen::Dense> +{ + typedef const TensorImagePatchOp& type; +}; + +template +struct nested, 1, typename eval >::type> +{ + typedef TensorImagePatchOp type; +}; + +} // end namespace internal + +template +class TensorImagePatchOp : public TensorBase, ReadOnlyAccessors> +{ + public: + typedef typename Eigen::internal::traits::Scalar Scalar; + typedef typename Eigen::NumTraits::Real RealScalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + typedef typename Eigen::internal::nested::type Nested; + typedef typename Eigen::internal::traits::StorageKind StorageKind; + typedef typename Eigen::internal::traits::Index Index; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorImagePatchOp(const XprType& expr, DenseIndex patch_rows, DenseIndex patch_cols, + DenseIndex row_strides, DenseIndex col_strides, + DenseIndex in_row_strides, DenseIndex in_col_strides, + DenseIndex row_inflate_strides, DenseIndex col_inflate_strides, + PaddingType padding_type, Scalar padding_value) + : m_xpr(expr), m_patch_rows(patch_rows), m_patch_cols(patch_cols), + m_row_strides(row_strides), m_col_strides(col_strides), + m_in_row_strides(in_row_strides), m_in_col_strides(in_col_strides), + m_row_inflate_strides(row_inflate_strides), m_col_inflate_strides(col_inflate_strides), + m_padding_explicit(false), m_padding_top(0), m_padding_bottom(0), m_padding_left(0), m_padding_right(0), + m_padding_type(padding_type), m_padding_value(padding_value) {} + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorImagePatchOp(const XprType& expr, DenseIndex patch_rows, DenseIndex patch_cols, + DenseIndex row_strides, DenseIndex col_strides, + DenseIndex in_row_strides, DenseIndex in_col_strides, + DenseIndex row_inflate_strides, DenseIndex col_inflate_strides, + DenseIndex padding_top, DenseIndex padding_bottom, + DenseIndex padding_left, DenseIndex padding_right, + Scalar padding_value) + : m_xpr(expr), m_patch_rows(patch_rows), m_patch_cols(patch_cols), + m_row_strides(row_strides), m_col_strides(col_strides), + m_in_row_strides(in_row_strides), m_in_col_strides(in_col_strides), + m_row_inflate_strides(row_inflate_strides), m_col_inflate_strides(col_inflate_strides), + m_padding_explicit(true), m_padding_top(padding_top), m_padding_bottom(padding_bottom), + m_padding_left(padding_left), m_padding_right(padding_right), + m_padding_type(PADDING_VALID), m_padding_value(padding_value) {} + + EIGEN_DEVICE_FUNC + DenseIndex patch_rows() const { return m_patch_rows; } + EIGEN_DEVICE_FUNC + DenseIndex patch_cols() const { return m_patch_cols; } + EIGEN_DEVICE_FUNC + DenseIndex row_strides() const { return m_row_strides; } + EIGEN_DEVICE_FUNC + DenseIndex col_strides() const { return m_col_strides; } + EIGEN_DEVICE_FUNC + DenseIndex in_row_strides() const { return m_in_row_strides; } + EIGEN_DEVICE_FUNC + DenseIndex in_col_strides() const { return m_in_col_strides; } + EIGEN_DEVICE_FUNC + DenseIndex row_inflate_strides() const { return m_row_inflate_strides; } + EIGEN_DEVICE_FUNC + DenseIndex col_inflate_strides() const { return m_col_inflate_strides; } + EIGEN_DEVICE_FUNC + bool padding_explicit() const { return m_padding_explicit; } + EIGEN_DEVICE_FUNC + DenseIndex padding_top() const { return m_padding_top; } + EIGEN_DEVICE_FUNC + DenseIndex padding_bottom() const { return m_padding_bottom; } + EIGEN_DEVICE_FUNC + DenseIndex padding_left() const { return m_padding_left; } + EIGEN_DEVICE_FUNC + DenseIndex padding_right() const { return m_padding_right; } + EIGEN_DEVICE_FUNC + PaddingType padding_type() const { return m_padding_type; } + EIGEN_DEVICE_FUNC + Scalar padding_value() const { return m_padding_value; } + + EIGEN_DEVICE_FUNC + const typename internal::remove_all::type& + expression() const { return m_xpr; } + + protected: + typename XprType::Nested m_xpr; + const DenseIndex m_patch_rows; + const DenseIndex m_patch_cols; + const DenseIndex m_row_strides; + const DenseIndex m_col_strides; + const DenseIndex m_in_row_strides; + const DenseIndex m_in_col_strides; + const DenseIndex m_row_inflate_strides; + const DenseIndex m_col_inflate_strides; + const bool m_padding_explicit; + const DenseIndex m_padding_top; + const DenseIndex m_padding_bottom; + const DenseIndex m_padding_left; + const DenseIndex m_padding_right; + const PaddingType m_padding_type; + const Scalar m_padding_value; +}; + +// Eval as rvalue +template +struct TensorEvaluator, Device> +{ + typedef TensorImagePatchOp XprType; + typedef typename XprType::Index Index; + static const int NumInputDims = internal::array_size::Dimensions>::value; + static const int NumDims = NumInputDims + 1; + typedef DSizes Dimensions; + typedef typename internal::remove_const::type Scalar; + typedef TensorEvaluator, + Device> Self; + typedef TensorEvaluator Impl; + typedef typename XprType::CoeffReturnType CoeffReturnType; + typedef typename PacketType::type PacketReturnType; + static const int PacketSize = internal::unpacket_traits::size; + + enum { + IsAligned = false, + PacketAccess = TensorEvaluator::PacketAccess, + Layout = TensorEvaluator::Layout, + CoordAccess = false, + RawAccess = false + }; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorEvaluator(const XprType& op, const Device& device) + : m_impl(op.expression(), device) + { + EIGEN_STATIC_ASSERT((NumDims >= 4), YOU_MADE_A_PROGRAMMING_MISTAKE); + + m_paddingValue = op.padding_value(); + + const typename TensorEvaluator::Dimensions& input_dims = m_impl.dimensions(); + + // Caches a few variables. + if (static_cast(Layout) == static_cast(ColMajor)) { + m_inputDepth = input_dims[0]; + m_inputRows = input_dims[1]; + m_inputCols = input_dims[2]; + } else { + m_inputDepth = input_dims[NumInputDims-1]; + m_inputRows = input_dims[NumInputDims-2]; + m_inputCols = input_dims[NumInputDims-3]; + } + + m_row_strides = op.row_strides(); + m_col_strides = op.col_strides(); + + // Input strides and effective input/patch size + m_in_row_strides = op.in_row_strides(); + m_in_col_strides = op.in_col_strides(); + m_row_inflate_strides = op.row_inflate_strides(); + m_col_inflate_strides = op.col_inflate_strides(); + // The "effective" input rows and input cols are the input rows and cols + // after inflating them with zeros. + // For examples, a 2x3 matrix with row_inflate_strides and + // col_inflate_strides of 2 comes from: + // A B C + // D E F + // + // to a matrix is 3 x 5: + // + // A . B . C + // . . . . . + // D . E . F + + m_input_rows_eff = (m_inputRows - 1) * m_row_inflate_strides + 1; + m_input_cols_eff = (m_inputCols - 1) * m_col_inflate_strides + 1; + m_patch_rows_eff = op.patch_rows() + (op.patch_rows() - 1) * (m_in_row_strides - 1); + m_patch_cols_eff = op.patch_cols() + (op.patch_cols() - 1) * (m_in_col_strides - 1); + + if (op.padding_explicit()) { + m_outputRows = numext::ceil((m_input_rows_eff + op.padding_top() + op.padding_bottom() - m_patch_rows_eff + 1.f) / static_cast(m_row_strides)); + m_outputCols = numext::ceil((m_input_cols_eff + op.padding_left() + op.padding_right() - m_patch_cols_eff + 1.f) / static_cast(m_col_strides)); + m_rowPaddingTop = op.padding_top(); + m_colPaddingLeft = op.padding_left(); + } else { + // Computing padding from the type + switch (op.padding_type()) { + case PADDING_VALID: + m_outputRows = numext::ceil((m_input_rows_eff - m_patch_rows_eff + 1.f) / static_cast(m_row_strides)); + m_outputCols = numext::ceil((m_input_cols_eff - m_patch_cols_eff + 1.f) / static_cast(m_col_strides)); + // Calculate the padding + m_rowPaddingTop = numext::maxi(0, ((m_outputRows - 1) * m_row_strides + m_patch_rows_eff - m_input_rows_eff) / 2); + m_colPaddingLeft = numext::maxi(0, ((m_outputCols - 1) * m_col_strides + m_patch_cols_eff - m_input_cols_eff) / 2); + break; + case PADDING_SAME: + m_outputRows = numext::ceil(m_input_rows_eff / static_cast(m_row_strides)); + m_outputCols = numext::ceil(m_input_cols_eff / static_cast(m_col_strides)); + // Calculate the padding + m_rowPaddingTop = ((m_outputRows - 1) * m_row_strides + m_patch_rows_eff - m_input_rows_eff) / 2; + m_colPaddingLeft = ((m_outputCols - 1) * m_col_strides + m_patch_cols_eff - m_input_cols_eff) / 2; + break; + default: + eigen_assert(false && "unexpected padding"); + } + } + eigen_assert(m_outputRows > 0); + eigen_assert(m_outputCols > 0); + + // Dimensions for result of extraction. + if (static_cast(Layout) == static_cast(ColMajor)) { + // ColMajor + // 0: depth + // 1: patch_rows + // 2: patch_cols + // 3: number of patches + // 4 and beyond: anything else (such as batch). + m_dimensions[0] = input_dims[0]; + m_dimensions[1] = op.patch_rows(); + m_dimensions[2] = op.patch_cols(); + m_dimensions[3] = m_outputRows * m_outputCols; + for (int i = 4; i < NumDims; ++i) { + m_dimensions[i] = input_dims[i-1]; + } + } else { + // RowMajor + // NumDims-1: depth + // NumDims-2: patch_rows + // NumDims-3: patch_cols + // NumDims-4: number of patches + // NumDims-5 and beyond: anything else (such as batch). + m_dimensions[NumDims-1] = input_dims[NumInputDims-1]; + m_dimensions[NumDims-2] = op.patch_rows(); + m_dimensions[NumDims-3] = op.patch_cols(); + m_dimensions[NumDims-4] = m_outputRows * m_outputCols; + for (int i = NumDims-5; i >= 0; --i) { + m_dimensions[i] = input_dims[i]; + } + } + + // Strides for moving the patch in various dimensions. + if (static_cast(Layout) == static_cast(ColMajor)) { + m_colStride = m_dimensions[1]; + m_patchStride = m_colStride * m_dimensions[2] * m_dimensions[0]; + m_otherStride = m_patchStride * m_dimensions[3]; + } else { + m_colStride = m_dimensions[NumDims-2]; + m_patchStride = m_colStride * m_dimensions[NumDims-3] * m_dimensions[NumDims-1]; + m_otherStride = m_patchStride * m_dimensions[NumDims-4]; + } + + // Strides for navigating through the input tensor. + m_rowInputStride = m_inputDepth; + m_colInputStride = m_inputDepth * m_inputRows; + m_patchInputStride = m_inputDepth * m_inputRows * m_inputCols; + + // Fast representations of different variables. + m_fastOtherStride = internal::TensorIntDivisor(m_otherStride); + m_fastPatchStride = internal::TensorIntDivisor(m_patchStride); + m_fastColStride = internal::TensorIntDivisor(m_colStride); + m_fastInflateRowStride = internal::TensorIntDivisor(m_row_inflate_strides); + m_fastInflateColStride = internal::TensorIntDivisor(m_col_inflate_strides); + m_fastInputColsEff = internal::TensorIntDivisor(m_input_cols_eff); + + // Number of patches in the width dimension. + m_fastOutputRows = internal::TensorIntDivisor(m_outputRows); + if (static_cast(Layout) == static_cast(ColMajor)) { + m_fastOutputDepth = internal::TensorIntDivisor(m_dimensions[0]); + } else { + m_fastOutputDepth = internal::TensorIntDivisor(m_dimensions[NumDims-1]); + } + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Dimensions& dimensions() const { return m_dimensions; } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(Scalar* /*data*/) { + m_impl.evalSubExprsIfNeeded(NULL); + return true; + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void cleanup() { + m_impl.cleanup(); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const + { + // Patch index corresponding to the passed in index. + const Index patchIndex = index / m_fastPatchStride; + // Find the offset of the element wrt the location of the first element. + const Index patchOffset = (index - patchIndex * m_patchStride) / m_fastOutputDepth; + + // Other ways to index this element. + const Index otherIndex = (NumDims == 4) ? 0 : index / m_fastOtherStride; + const Index patch2DIndex = (NumDims == 4) ? patchIndex : (index - otherIndex * m_otherStride) / m_fastPatchStride; + + // Calculate col index in the input original tensor. + const Index colIndex = patch2DIndex / m_fastOutputRows; + const Index colOffset = patchOffset / m_fastColStride; + const Index inputCol = colIndex * m_col_strides + colOffset * m_in_col_strides - m_colPaddingLeft; + const Index origInputCol = (m_col_inflate_strides == 1) ? inputCol : ((inputCol >= 0) ? (inputCol / m_fastInflateColStride) : 0); + if (inputCol < 0 || inputCol >= m_input_cols_eff || + ((m_col_inflate_strides != 1) && (inputCol != origInputCol * m_col_inflate_strides))) { + return Scalar(m_paddingValue); + } + + // Calculate row index in the original input tensor. + const Index rowIndex = patch2DIndex - colIndex * m_outputRows; + const Index rowOffset = patchOffset - colOffset * m_colStride; + const Index inputRow = rowIndex * m_row_strides + rowOffset * m_in_row_strides - m_rowPaddingTop; + const Index origInputRow = (m_row_inflate_strides == 1) ? inputRow : ((inputRow >= 0) ? (inputRow / m_fastInflateRowStride) : 0); + if (inputRow < 0 || inputRow >= m_input_rows_eff || + ((m_row_inflate_strides != 1) && (inputRow != origInputRow * m_row_inflate_strides))) { + return Scalar(m_paddingValue); + } + + const int depth_index = static_cast(Layout) == static_cast(ColMajor) ? 0 : NumDims - 1; + const Index depth = index - (index / m_fastOutputDepth) * m_dimensions[depth_index]; + + const Index inputIndex = depth + origInputRow * m_rowInputStride + origInputCol * m_colInputStride + otherIndex * m_patchInputStride; + return m_impl.coeff(inputIndex); + } + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packet(Index index) const + { + EIGEN_STATIC_ASSERT((PacketSize > 1), YOU_MADE_A_PROGRAMMING_MISTAKE) + eigen_assert(index+PacketSize-1 < dimensions().TotalSize()); + + if (m_in_row_strides != 1 || m_in_col_strides != 1 || m_row_inflate_strides != 1 || m_col_inflate_strides != 1) { + return packetWithPossibleZero(index); + } + + const Index indices[2] = {index, index + PacketSize - 1}; + const Index patchIndex = indices[0] / m_fastPatchStride; + if (patchIndex != indices[1] / m_fastPatchStride) { + return packetWithPossibleZero(index); + } + const Index otherIndex = (NumDims == 4) ? 0 : indices[0] / m_fastOtherStride; + eigen_assert(otherIndex == indices[1] / m_fastOtherStride); + + // Find the offset of the element wrt the location of the first element. + const Index patchOffsets[2] = {(indices[0] - patchIndex * m_patchStride) / m_fastOutputDepth, + (indices[1] - patchIndex * m_patchStride) / m_fastOutputDepth}; + + const Index patch2DIndex = (NumDims == 4) ? patchIndex : (indices[0] - otherIndex * m_otherStride) / m_fastPatchStride; + eigen_assert(patch2DIndex == (indices[1] - otherIndex * m_otherStride) / m_fastPatchStride); + + const Index colIndex = patch2DIndex / m_fastOutputRows; + const Index colOffsets[2] = {patchOffsets[0] / m_fastColStride, patchOffsets[1] / m_fastColStride}; + + // Calculate col indices in the original input tensor. + const Index inputCols[2] = {colIndex * m_col_strides + colOffsets[0] - + m_colPaddingLeft, colIndex * m_col_strides + colOffsets[1] - m_colPaddingLeft}; + if (inputCols[1] < 0 || inputCols[0] >= m_inputCols) { + return internal::pset1(Scalar(m_paddingValue)); + } + + if (inputCols[0] == inputCols[1]) { + const Index rowIndex = patch2DIndex - colIndex * m_outputRows; + const Index rowOffsets[2] = {patchOffsets[0] - colOffsets[0]*m_colStride, patchOffsets[1] - colOffsets[1]*m_colStride}; + eigen_assert(rowOffsets[0] <= rowOffsets[1]); + // Calculate col indices in the original input tensor. + const Index inputRows[2] = {rowIndex * m_row_strides + rowOffsets[0] - + m_rowPaddingTop, rowIndex * m_row_strides + rowOffsets[1] - m_rowPaddingTop}; + + if (inputRows[1] < 0 || inputRows[0] >= m_inputRows) { + return internal::pset1(Scalar(m_paddingValue)); + } + + if (inputRows[0] >= 0 && inputRows[1] < m_inputRows) { + // no padding + const int depth_index = static_cast(Layout) == static_cast(ColMajor) ? 0 : NumDims - 1; + const Index depth = index - (index / m_fastOutputDepth) * m_dimensions[depth_index]; + const Index inputIndex = depth + inputRows[0] * m_rowInputStride + inputCols[0] * m_colInputStride + otherIndex * m_patchInputStride; + return m_impl.template packet(inputIndex); + } + } + + return packetWithPossibleZero(index); + } + + EIGEN_DEVICE_FUNC Scalar* data() const { return NULL; } + + const TensorEvaluator& impl() const { return m_impl; } + + Index rowPaddingTop() const { return m_rowPaddingTop; } + Index colPaddingLeft() const { return m_colPaddingLeft; } + Index outputRows() const { return m_outputRows; } + Index outputCols() const { return m_outputCols; } + Index userRowStride() const { return m_row_strides; } + Index userColStride() const { return m_col_strides; } + Index userInRowStride() const { return m_in_row_strides; } + Index userInColStride() const { return m_in_col_strides; } + Index rowInflateStride() const { return m_row_inflate_strides; } + Index colInflateStride() const { return m_col_inflate_strides; } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost + costPerCoeff(bool vectorized) const { + // We conservatively estimate the cost for the code path where the computed + // index is inside the original image and + // TensorEvaluator::CoordAccess is false. + const double compute_cost = 3 * TensorOpCost::DivCost() + + 6 * TensorOpCost::MulCost() + + 8 * TensorOpCost::MulCost(); + return m_impl.costPerCoeff(vectorized) + + TensorOpCost(0, 0, compute_cost, vectorized, PacketSize); + } + + protected: + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packetWithPossibleZero(Index index) const + { + EIGEN_ALIGN_MAX typename internal::remove_const::type values[PacketSize]; + for (int i = 0; i < PacketSize; ++i) { + values[i] = coeff(index+i); + } + PacketReturnType rslt = internal::pload(values); + return rslt; + } + + Dimensions m_dimensions; + + Index m_otherStride; + Index m_patchStride; + Index m_colStride; + Index m_row_strides; + Index m_col_strides; + + Index m_in_row_strides; + Index m_in_col_strides; + Index m_row_inflate_strides; + Index m_col_inflate_strides; + + Index m_input_rows_eff; + Index m_input_cols_eff; + Index m_patch_rows_eff; + Index m_patch_cols_eff; + + internal::TensorIntDivisor m_fastOtherStride; + internal::TensorIntDivisor m_fastPatchStride; + internal::TensorIntDivisor m_fastColStride; + internal::TensorIntDivisor m_fastInflateRowStride; + internal::TensorIntDivisor m_fastInflateColStride; + internal::TensorIntDivisor m_fastInputColsEff; + + Index m_rowInputStride; + Index m_colInputStride; + Index m_patchInputStride; + + Index m_inputDepth; + Index m_inputRows; + Index m_inputCols; + + Index m_outputRows; + Index m_outputCols; + + Index m_rowPaddingTop; + Index m_colPaddingLeft; + + internal::TensorIntDivisor m_fastOutputRows; + internal::TensorIntDivisor m_fastOutputDepth; + + Scalar m_paddingValue; + + TensorEvaluator m_impl; +}; + + +} // end namespace Eigen + +#endif // EIGEN_CXX11_TENSOR_TENSOR_IMAGE_PATCH_H diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorIndexList.h b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorIndexList.h new file mode 100644 index 0000000000..3209fecd34 --- /dev/null +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorIndexList.h @@ -0,0 +1,725 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Benoit Steiner +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CXX11_TENSOR_TENSOR_INDEX_LIST_H +#define EIGEN_CXX11_TENSOR_TENSOR_INDEX_LIST_H + + +#if EIGEN_HAS_CONSTEXPR && EIGEN_HAS_VARIADIC_TEMPLATES + +#define EIGEN_HAS_INDEX_LIST + +namespace Eigen { + +/** \internal + * + * \class TensorIndexList + * \ingroup CXX11_Tensor_Module + * + * \brief Set of classes used to encode a set of Tensor dimensions/indices. + * + * The indices in the list can be known at compile time or at runtime. A mix + * of static and dynamic indices can also be provided if needed. The tensor + * code will attempt to take advantage of the indices that are known at + * compile time to optimize the code it generates. + * + * This functionality requires a c++11 compliant compiler. If your compiler + * is older you need to use arrays of indices instead. + * + * Several examples are provided in the cxx11_tensor_index_list.cpp file. + * + * \sa Tensor + */ + +template +struct type2index { + static const DenseIndex value = n; + EIGEN_DEVICE_FUNC constexpr operator DenseIndex() const { return n; } + EIGEN_DEVICE_FUNC void set(DenseIndex val) { + eigen_assert(val == n); + } +}; + +// This can be used with IndexPairList to get compile-time constant pairs, +// such as IndexPairList, type2indexpair<3,4>>(). +template +struct type2indexpair { + static const DenseIndex first = f; + static const DenseIndex second = s; + + constexpr EIGEN_DEVICE_FUNC operator IndexPair() const { + return IndexPair(f, s); + } + + EIGEN_DEVICE_FUNC void set(const IndexPair& val) { + eigen_assert(val.first == f); + eigen_assert(val.second == s); + } +}; + + +template struct NumTraits > +{ + typedef DenseIndex Real; + enum { + IsComplex = 0, + RequireInitialization = false, + ReadCost = 1, + AddCost = 1, + MulCost = 1 + }; + + EIGEN_DEVICE_FUNC static inline Real epsilon() { return 0; } + EIGEN_DEVICE_FUNC static inline Real dummy_precision() { return 0; } + EIGEN_DEVICE_FUNC static inline Real highest() { return n; } + EIGEN_DEVICE_FUNC static inline Real lowest() { return n; } +}; + +namespace internal { +template +EIGEN_DEVICE_FUNC void update_value(T& val, DenseIndex new_val) { + val = new_val; +} +template +EIGEN_DEVICE_FUNC void update_value(type2index& val, DenseIndex new_val) { + val.set(new_val); +} + +template +EIGEN_DEVICE_FUNC void update_value(T& val, IndexPair new_val) { + val = new_val; +} +template +EIGEN_DEVICE_FUNC void update_value(type2indexpair& val, IndexPair new_val) { + val.set(new_val); +} + + +template +struct is_compile_time_constant { + static constexpr bool value = false; +}; + +template +struct is_compile_time_constant > { + static constexpr bool value = true; +}; +template +struct is_compile_time_constant > { + static constexpr bool value = true; +}; +template +struct is_compile_time_constant& > { + static constexpr bool value = true; +}; +template +struct is_compile_time_constant& > { + static constexpr bool value = true; +}; + +template +struct is_compile_time_constant > { + static constexpr bool value = true; +}; +template +struct is_compile_time_constant > { + static constexpr bool value = true; +}; +template +struct is_compile_time_constant& > { + static constexpr bool value = true; +}; +template +struct is_compile_time_constant& > { + static constexpr bool value = true; +}; + + +template +struct IndexTuple; + +template +struct IndexTuple { + EIGEN_DEVICE_FUNC constexpr IndexTuple() : head(), others() { } + EIGEN_DEVICE_FUNC constexpr IndexTuple(const T& v, const O... o) : head(v), others(o...) { } + + constexpr static int count = 1 + sizeof...(O); + T head; + IndexTuple others; + typedef T Head; + typedef IndexTuple Other; +}; + +template + struct IndexTuple { + EIGEN_DEVICE_FUNC constexpr IndexTuple() : head() { } + EIGEN_DEVICE_FUNC constexpr IndexTuple(const T& v) : head(v) { } + + constexpr static int count = 1; + T head; + typedef T Head; +}; + + +template +struct IndexTupleExtractor; + +template +struct IndexTupleExtractor { + + typedef typename IndexTupleExtractor::ValType ValType; + + EIGEN_DEVICE_FUNC static constexpr ValType& get_val(IndexTuple& val) { + return IndexTupleExtractor::get_val(val.others); + } + + EIGEN_DEVICE_FUNC static constexpr const ValType& get_val(const IndexTuple& val) { + return IndexTupleExtractor::get_val(val.others); + } + template + EIGEN_DEVICE_FUNC static void set_val(IndexTuple& val, V& new_val) { + IndexTupleExtractor::set_val(val.others, new_val); + } + +}; + +template + struct IndexTupleExtractor<0, T, O...> { + + typedef T ValType; + + EIGEN_DEVICE_FUNC static constexpr ValType& get_val(IndexTuple& val) { + return val.head; + } + EIGEN_DEVICE_FUNC static constexpr const ValType& get_val(const IndexTuple& val) { + return val.head; + } + template + EIGEN_DEVICE_FUNC static void set_val(IndexTuple& val, V& new_val) { + val.head = new_val; + } +}; + + + +template +EIGEN_DEVICE_FUNC constexpr typename IndexTupleExtractor::ValType& array_get(IndexTuple& tuple) { + return IndexTupleExtractor::get_val(tuple); +} +template +EIGEN_DEVICE_FUNC constexpr const typename IndexTupleExtractor::ValType& array_get(const IndexTuple& tuple) { + return IndexTupleExtractor::get_val(tuple); +} +template + struct array_size > { + static const size_t value = IndexTuple::count; +}; +template + struct array_size > { + static const size_t value = IndexTuple::count; +}; + + + + +template +struct tuple_coeff { + template + EIGEN_DEVICE_FUNC static constexpr ValueT get(const DenseIndex i, const IndexTuple& t) { + // return array_get(t) * (i == Idx) + tuple_coeff::get(i, t) * (i != Idx); + return (i == Idx ? array_get(t) : tuple_coeff::get(i, t)); + } + template + EIGEN_DEVICE_FUNC static void set(const DenseIndex i, IndexTuple& t, const ValueT& value) { + if (i == Idx) { + update_value(array_get(t), value); + } else { + tuple_coeff::set(i, t, value); + } + } + + template + EIGEN_DEVICE_FUNC static constexpr bool value_known_statically(const DenseIndex i, const IndexTuple& t) { + return ((i == Idx) & is_compile_time_constant::ValType>::value) || + tuple_coeff::value_known_statically(i, t); + } + + template + EIGEN_DEVICE_FUNC static constexpr bool values_up_to_known_statically(const IndexTuple& t) { + return is_compile_time_constant::ValType>::value && + tuple_coeff::values_up_to_known_statically(t); + } + + template + EIGEN_DEVICE_FUNC static constexpr bool values_up_to_statically_known_to_increase(const IndexTuple& t) { + return is_compile_time_constant::ValType>::value && + is_compile_time_constant::ValType>::value && + array_get(t) > array_get(t) && + tuple_coeff::values_up_to_statically_known_to_increase(t); + } +}; + +template +struct tuple_coeff<0, ValueT> { + template + EIGEN_DEVICE_FUNC static constexpr ValueT get(const DenseIndex /*i*/, const IndexTuple& t) { + // eigen_assert (i == 0); // gcc fails to compile assertions in constexpr + return array_get<0>(t)/* * (i == 0)*/; + } + template + EIGEN_DEVICE_FUNC static void set(const DenseIndex i, IndexTuple& t, const ValueT value) { + eigen_assert (i == 0); + update_value(array_get<0>(t), value); + } + template + EIGEN_DEVICE_FUNC static constexpr bool value_known_statically(const DenseIndex i, const IndexTuple&) { + return is_compile_time_constant::ValType>::value & (i == 0); + } + + template + EIGEN_DEVICE_FUNC static constexpr bool values_up_to_known_statically(const IndexTuple&) { + return is_compile_time_constant::ValType>::value; + } + + template + EIGEN_DEVICE_FUNC static constexpr bool values_up_to_statically_known_to_increase(const IndexTuple&) { + return true; + } +}; +} // namespace internal + + + +template +struct IndexList : internal::IndexTuple { + EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC constexpr DenseIndex operator[] (const DenseIndex i) const { + return internal::tuple_coeff >::value-1, DenseIndex>::get(i, *this); + } + EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC constexpr DenseIndex get(const DenseIndex i) const { + return internal::tuple_coeff >::value-1, DenseIndex>::get(i, *this); + } + EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC void set(const DenseIndex i, const DenseIndex value) { + return internal::tuple_coeff >::value-1, DenseIndex>::set(i, *this, value); + } + + EIGEN_DEVICE_FUNC constexpr IndexList(const internal::IndexTuple& other) : internal::IndexTuple(other) { } + EIGEN_DEVICE_FUNC constexpr IndexList(FirstType& first, OtherTypes... other) : internal::IndexTuple(first, other...) { } + EIGEN_DEVICE_FUNC constexpr IndexList() : internal::IndexTuple() { } + + EIGEN_DEVICE_FUNC constexpr bool value_known_statically(const DenseIndex i) const { + return internal::tuple_coeff >::value-1, DenseIndex>::value_known_statically(i, *this); + } + EIGEN_DEVICE_FUNC constexpr bool all_values_known_statically() const { + return internal::tuple_coeff >::value-1, DenseIndex>::values_up_to_known_statically(*this); + } + + EIGEN_DEVICE_FUNC constexpr bool values_statically_known_to_increase() const { + return internal::tuple_coeff >::value-1, DenseIndex>::values_up_to_statically_known_to_increase(*this); + } +}; + + +template +constexpr IndexList make_index_list(FirstType val1, OtherTypes... other_vals) { + return IndexList(val1, other_vals...); +} + + +template +struct IndexPairList : internal::IndexTuple { + EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC constexpr IndexPair operator[] (const DenseIndex i) const { + return internal::tuple_coeff >::value-1, IndexPair>::get(i, *this); + } + EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC void set(const DenseIndex i, const IndexPair value) { + return internal::tuple_coeff>::value-1, IndexPair >::set(i, *this, value); + } + + EIGEN_DEVICE_FUNC constexpr IndexPairList(const internal::IndexTuple& other) : internal::IndexTuple(other) { } + EIGEN_DEVICE_FUNC constexpr IndexPairList() : internal::IndexTuple() { } + + EIGEN_DEVICE_FUNC constexpr bool value_known_statically(const DenseIndex i) const { + return internal::tuple_coeff >::value-1, DenseIndex>::value_known_statically(i, *this); + } +}; + +namespace internal { + +template size_t array_prod(const IndexList& sizes) { + size_t result = 1; + for (int i = 0; i < array_size >::value; ++i) { + result *= sizes[i]; + } + return result; +} + +template struct array_size > { + static const size_t value = array_size >::value; +}; +template struct array_size > { + static const size_t value = array_size >::value; +}; + +template struct array_size > { + static const size_t value = std::tuple_size >::value; +}; +template struct array_size > { + static const size_t value = std::tuple_size >::value; +}; + +template EIGEN_DEVICE_FUNC constexpr DenseIndex array_get(IndexList& a) { + return IndexTupleExtractor::get_val(a); +} +template EIGEN_DEVICE_FUNC constexpr DenseIndex array_get(const IndexList& a) { + return IndexTupleExtractor::get_val(a); +} + +template +struct index_known_statically_impl { + EIGEN_DEVICE_FUNC static constexpr bool run(const DenseIndex) { + return false; + } +}; + +template +struct index_known_statically_impl > { + EIGEN_DEVICE_FUNC static constexpr bool run(const DenseIndex i) { + return IndexList().value_known_statically(i); + } +}; + +template +struct index_known_statically_impl > { + EIGEN_DEVICE_FUNC static constexpr bool run(const DenseIndex i) { + return IndexList().value_known_statically(i); + } +}; + + +template +struct all_indices_known_statically_impl { + static constexpr bool run() { + return false; + } +}; + +template +struct all_indices_known_statically_impl > { + EIGEN_DEVICE_FUNC static constexpr bool run() { + return IndexList().all_values_known_statically(); + } +}; + +template +struct all_indices_known_statically_impl > { + EIGEN_DEVICE_FUNC static constexpr bool run() { + return IndexList().all_values_known_statically(); + } +}; + + +template +struct indices_statically_known_to_increase_impl { + EIGEN_DEVICE_FUNC static constexpr bool run() { + return false; + } +}; + +template + struct indices_statically_known_to_increase_impl > { + EIGEN_DEVICE_FUNC static constexpr bool run() { + return Eigen::IndexList().values_statically_known_to_increase(); + } +}; + +template + struct indices_statically_known_to_increase_impl > { + EIGEN_DEVICE_FUNC static constexpr bool run() { + return Eigen::IndexList().values_statically_known_to_increase(); + } +}; + + +template +struct index_statically_eq_impl { + EIGEN_DEVICE_FUNC static constexpr bool run(DenseIndex, DenseIndex) { + return false; + } +}; + +template +struct index_statically_eq_impl > { + EIGEN_DEVICE_FUNC static constexpr bool run(const DenseIndex i, const DenseIndex value) { + return IndexList().value_known_statically(i) & + (IndexList().get(i) == value); + } +}; + +template +struct index_statically_eq_impl > { + EIGEN_DEVICE_FUNC static constexpr bool run(const DenseIndex i, const DenseIndex value) { + return IndexList().value_known_statically(i) & + (IndexList().get(i) == value); + } +}; + + +template +struct index_statically_ne_impl { + EIGEN_DEVICE_FUNC static constexpr bool run(DenseIndex, DenseIndex) { + return false; + } +}; + +template +struct index_statically_ne_impl > { + EIGEN_DEVICE_FUNC static constexpr bool run(const DenseIndex i, const DenseIndex value) { + return IndexList().value_known_statically(i) & + (IndexList().get(i) != value); + } +}; + +template +struct index_statically_ne_impl > { + EIGEN_DEVICE_FUNC static constexpr bool run(const DenseIndex i, const DenseIndex value) { + return IndexList().value_known_statically(i) & + (IndexList().get(i) != value); + } +}; + + +template +struct index_statically_gt_impl { + EIGEN_DEVICE_FUNC static constexpr bool run(DenseIndex, DenseIndex) { + return false; + } +}; + +template +struct index_statically_gt_impl > { + EIGEN_DEVICE_FUNC static constexpr bool run(const DenseIndex i, const DenseIndex value) { + return IndexList().value_known_statically(i) & + (IndexList().get(i) > value); + } +}; + +template +struct index_statically_gt_impl > { + EIGEN_DEVICE_FUNC static constexpr bool run(const DenseIndex i, const DenseIndex value) { + return IndexList().value_known_statically(i) & + (IndexList().get(i) > value); + } +}; + + + +template +struct index_statically_lt_impl { + EIGEN_DEVICE_FUNC static constexpr bool run(DenseIndex, DenseIndex) { + return false; + } +}; + +template +struct index_statically_lt_impl > { + EIGEN_DEVICE_FUNC static constexpr bool run(const DenseIndex i, const DenseIndex value) { + return IndexList().value_known_statically(i) & + (IndexList().get(i) < value); + } +}; + +template +struct index_statically_lt_impl > { + EIGEN_DEVICE_FUNC static constexpr bool run(const DenseIndex i, const DenseIndex value) { + return IndexList().value_known_statically(i) & + (IndexList().get(i) < value); + } +}; + + + +template +struct index_pair_first_statically_eq_impl { + EIGEN_DEVICE_FUNC static constexpr bool run(DenseIndex, DenseIndex) { + return false; + } +}; + +template +struct index_pair_first_statically_eq_impl > { + EIGEN_DEVICE_FUNC static constexpr bool run(const DenseIndex i, const DenseIndex value) { + return IndexPairList().value_known_statically(i) & + (IndexPairList().operator[](i).first == value); + } +}; + +template +struct index_pair_first_statically_eq_impl > { + EIGEN_DEVICE_FUNC static constexpr bool run(const DenseIndex i, const DenseIndex value) { + return IndexPairList().value_known_statically(i) & + (IndexPairList().operator[](i).first == value); + } +}; + + + +template +struct index_pair_second_statically_eq_impl { + EIGEN_DEVICE_FUNC static constexpr bool run(DenseIndex, DenseIndex) { + return false; + } +}; + +template +struct index_pair_second_statically_eq_impl > { + EIGEN_DEVICE_FUNC static constexpr bool run(const DenseIndex i, const DenseIndex value) { + return IndexPairList().value_known_statically(i) & + (IndexPairList().operator[](i).second == value); + } +}; + +template +struct index_pair_second_statically_eq_impl > { + EIGEN_DEVICE_FUNC static constexpr bool run(const DenseIndex i, const DenseIndex value) { + return IndexPairList().value_known_statically(i) & + (IndexPairList().operator[](i).second == value); + } +}; + + +} // end namespace internal +} // end namespace Eigen + +#else + +namespace Eigen { +namespace internal { + +template +struct index_known_statically_impl { + static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool run(const DenseIndex) { + return false; + } +}; + +template +struct all_indices_known_statically_impl { + static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool run() { + return false; + } +}; + +template +struct indices_statically_known_to_increase_impl { + static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool run() { + return false; + } +}; + +template +struct index_statically_eq_impl { + static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool run(DenseIndex, DenseIndex) { + return false; + } +}; + +template +struct index_statically_ne_impl { + static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool run(DenseIndex, DenseIndex) { + return false; + } +}; + +template +struct index_statically_gt_impl { + static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool run(DenseIndex, DenseIndex) { + return false; + } +}; + +template +struct index_statically_lt_impl { + static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool run(DenseIndex, DenseIndex) { + return false; + } +}; + +template +struct index_pair_first_statically_eq_impl { + static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool run(DenseIndex, DenseIndex) { + return false; + } +}; + +template +struct index_pair_second_statically_eq_impl { + static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool run(DenseIndex, DenseIndex) { + return false; + } +}; + + + +} // end namespace internal +} // end namespace Eigen + +#endif + + +namespace Eigen { +namespace internal { +template +static EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR bool index_known_statically(DenseIndex i) { + return index_known_statically_impl::run(i); +} + +template +static EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR bool all_indices_known_statically() { + return all_indices_known_statically_impl::run(); +} + +template +static EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR bool indices_statically_known_to_increase() { + return indices_statically_known_to_increase_impl::run(); +} + +template +static EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR bool index_statically_eq(DenseIndex i, DenseIndex value) { + return index_statically_eq_impl::run(i, value); +} + +template +static EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR bool index_statically_ne(DenseIndex i, DenseIndex value) { + return index_statically_ne_impl::run(i, value); +} + +template +static EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR bool index_statically_gt(DenseIndex i, DenseIndex value) { + return index_statically_gt_impl::run(i, value); +} + +template +static EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR bool index_statically_lt(DenseIndex i, DenseIndex value) { + return index_statically_lt_impl::run(i, value); +} + +template +static EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR bool index_pair_first_statically_eq(DenseIndex i, DenseIndex value) { + return index_pair_first_statically_eq_impl::run(i, value); +} + +template +static EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR bool index_pair_second_statically_eq(DenseIndex i, DenseIndex value) { + return index_pair_second_statically_eq_impl::run(i, value); +} + +} // end namespace internal +} // end namespace Eigen + + +#endif // EIGEN_CXX11_TENSOR_TENSOR_INDEX_LIST_H diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorInflation.h b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorInflation.h new file mode 100644 index 0000000000..f391fb9ee5 --- /dev/null +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorInflation.h @@ -0,0 +1,229 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2015 Ke Yang +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CXX11_TENSOR_TENSOR_INFLATION_H +#define EIGEN_CXX11_TENSOR_TENSOR_INFLATION_H + +namespace Eigen { + +/** \class TensorInflation + * \ingroup CXX11_Tensor_Module + * + * \brief Tensor inflation class. + * + * + */ +namespace internal { +template +struct traits > : public traits +{ + typedef typename XprType::Scalar Scalar; + typedef traits XprTraits; + typedef typename XprTraits::StorageKind StorageKind; + typedef typename XprTraits::Index Index; + typedef typename XprType::Nested Nested; + typedef typename remove_reference::type _Nested; + static const int NumDimensions = XprTraits::NumDimensions; + static const int Layout = XprTraits::Layout; +}; + +template +struct eval, Eigen::Dense> +{ + typedef const TensorInflationOp& type; +}; + +template +struct nested, 1, typename eval >::type> +{ + typedef TensorInflationOp type; +}; + +} // end namespace internal + +template +class TensorInflationOp : public TensorBase, ReadOnlyAccessors> +{ + public: + typedef typename Eigen::internal::traits::Scalar Scalar; + typedef typename Eigen::NumTraits::Real RealScalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + typedef typename Eigen::internal::nested::type Nested; + typedef typename Eigen::internal::traits::StorageKind StorageKind; + typedef typename Eigen::internal::traits::Index Index; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorInflationOp(const XprType& expr, const Strides& strides) + : m_xpr(expr), m_strides(strides) {} + + EIGEN_DEVICE_FUNC + const Strides& strides() const { return m_strides; } + + EIGEN_DEVICE_FUNC + const typename internal::remove_all::type& + expression() const { return m_xpr; } + + protected: + typename XprType::Nested m_xpr; + const Strides m_strides; +}; + +// Eval as rvalue +template +struct TensorEvaluator, Device> +{ + typedef TensorInflationOp XprType; + typedef typename XprType::Index Index; + static const int NumDims = internal::array_size::Dimensions>::value; + typedef DSizes Dimensions; + typedef typename XprType::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + typedef typename PacketType::type PacketReturnType; + static const int PacketSize = internal::unpacket_traits::size; + + enum { + IsAligned = /*TensorEvaluator::IsAligned*/ false, + PacketAccess = TensorEvaluator::PacketAccess, + BlockAccess = false, + Layout = TensorEvaluator::Layout, + CoordAccess = false, // to be implemented + RawAccess = false + }; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorEvaluator(const XprType& op, const Device& device) + : m_impl(op.expression(), device), m_strides(op.strides()) + { + m_dimensions = m_impl.dimensions(); + // Expand each dimension to the inflated dimension. + for (int i = 0; i < NumDims; ++i) { + m_dimensions[i] = (m_dimensions[i] - 1) * op.strides()[i] + 1; + } + + // Remember the strides for fast division. + for (int i = 0; i < NumDims; ++i) { + m_fastStrides[i] = internal::TensorIntDivisor(m_strides[i]); + } + + const typename TensorEvaluator::Dimensions& input_dims = m_impl.dimensions(); + if (static_cast(Layout) == static_cast(ColMajor)) { + m_outputStrides[0] = 1; + m_inputStrides[0] = 1; + for (int i = 1; i < NumDims; ++i) { + m_outputStrides[i] = m_outputStrides[i-1] * m_dimensions[i-1]; + m_inputStrides[i] = m_inputStrides[i-1] * input_dims[i-1]; + } + } else { // RowMajor + m_outputStrides[NumDims-1] = 1; + m_inputStrides[NumDims-1] = 1; + for (int i = NumDims - 2; i >= 0; --i) { + m_outputStrides[i] = m_outputStrides[i+1] * m_dimensions[i+1]; + m_inputStrides[i] = m_inputStrides[i+1] * input_dims[i+1]; + } + } + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Dimensions& dimensions() const { return m_dimensions; } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(Scalar* /*data*/) { + m_impl.evalSubExprsIfNeeded(NULL); + return true; + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void cleanup() { + m_impl.cleanup(); + } + + // Computes the input index given the output index. Returns true if the output + // index doesn't fall into a hole. + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool getInputIndex(Index index, Index* inputIndex) const + { + eigen_assert(index < dimensions().TotalSize()); + *inputIndex = 0; + if (static_cast(Layout) == static_cast(ColMajor)) { + for (int i = NumDims - 1; i > 0; --i) { + const Index idx = index / m_outputStrides[i]; + if (idx != idx / m_fastStrides[i] * m_strides[i]) { + return false; + } + *inputIndex += idx / m_strides[i] * m_inputStrides[i]; + index -= idx * m_outputStrides[i]; + } + if (index != index / m_fastStrides[0] * m_strides[0]) { + return false; + } + *inputIndex += index / m_strides[0]; + return true; + } else { + for (int i = 0; i < NumDims - 1; ++i) { + const Index idx = index / m_outputStrides[i]; + if (idx != idx / m_fastStrides[i] * m_strides[i]) { + return false; + } + *inputIndex += idx / m_strides[i] * m_inputStrides[i]; + index -= idx * m_outputStrides[i]; + } + if (index != index / m_fastStrides[NumDims-1] * m_strides[NumDims-1]) { + return false; + } + *inputIndex += index / m_strides[NumDims - 1]; + } + return true; + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const + { + Index inputIndex = 0; + if (getInputIndex(index, &inputIndex)) { + return m_impl.coeff(inputIndex); + } else { + return Scalar(0); + } + } + + // TODO(yangke): optimize this function so that we can detect and produce + // all-zero packets + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packet(Index index) const + { + EIGEN_STATIC_ASSERT((PacketSize > 1), YOU_MADE_A_PROGRAMMING_MISTAKE) + eigen_assert(index+PacketSize-1 < dimensions().TotalSize()); + + EIGEN_ALIGN_MAX typename internal::remove_const::type values[PacketSize]; + for (int i = 0; i < PacketSize; ++i) { + values[i] = coeff(index+i); + } + PacketReturnType rslt = internal::pload(values); + return rslt; + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost costPerCoeff(bool vectorized) const { + const double compute_cost = NumDims * (3 * TensorOpCost::DivCost() + + 3 * TensorOpCost::MulCost() + + 2 * TensorOpCost::AddCost()); + const double input_size = m_impl.dimensions().TotalSize(); + const double output_size = m_dimensions.TotalSize(); + if (output_size == 0) + return TensorOpCost(); + return m_impl.costPerCoeff(vectorized) + + TensorOpCost(sizeof(CoeffReturnType) * input_size / output_size, 0, + compute_cost, vectorized, PacketSize); + } + + EIGEN_DEVICE_FUNC Scalar* data() const { return NULL; } + + protected: + Dimensions m_dimensions; + array m_outputStrides; + array m_inputStrides; + TensorEvaluator m_impl; + const Strides m_strides; + array, NumDims> m_fastStrides; +}; + +} // end namespace Eigen + +#endif // EIGEN_CXX11_TENSOR_TENSOR_INFLATION_H diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorInitializer.h b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorInitializer.h new file mode 100644 index 0000000000..33edc49e39 --- /dev/null +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorInitializer.h @@ -0,0 +1,82 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Benoit Steiner +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CXX11_TENSOR_TENSOR_INITIALIZER_H +#define EIGEN_CXX11_TENSOR_TENSOR_INITIALIZER_H + +#if EIGEN_HAS_VARIADIC_TEMPLATES + +#include + +namespace Eigen { + +/** \class TensorInitializer + * \ingroup CXX11_Tensor_Module + * + * \brief Helper template to initialize Tensors from std::initializer_lists. + */ +namespace internal { + +template +struct Initializer { + typedef std::initializer_list< + typename Initializer::InitList> InitList; + + static void run(TensorEvaluator& tensor, + Eigen::array::Index, traits::NumDimensions>* indices, + const InitList& vals) { + int i = 0; + for (auto v : vals) { + (*indices)[traits::NumDimensions - N] = i++; + Initializer::run(tensor, indices, v); + } + } +}; + +template +struct Initializer { + typedef std::initializer_list::Scalar> InitList; + + static void run(TensorEvaluator& tensor, + Eigen::array::Index, traits::NumDimensions>* indices, + const InitList& vals) { + int i = 0; + // There is likely a faster way to do that than iterating. + for (auto v : vals) { + (*indices)[traits::NumDimensions - 1] = i++; + tensor.coeffRef(*indices) = v; + } + } +}; + +template +struct Initializer { + typedef typename traits::Scalar InitList; + + static void run(TensorEvaluator& tensor, + Eigen::array::Index, traits::NumDimensions>*, + const InitList& v) { + tensor.coeffRef(0) = v; + } +}; + + +template +void initialize_tensor(TensorEvaluator& tensor, + const typename Initializer::NumDimensions>::InitList& vals) { + Eigen::array::Index, traits::NumDimensions> indices; + Initializer::NumDimensions>::run(tensor, &indices, vals); +} + +} // namespace internal +} // namespace Eigen + +#endif // EIGEN_HAS_VARIADIC_TEMPLATES + +#endif // EIGEN_CXX11_TENSOR_TENSOR_INITIALIZER_H diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorIntDiv.h b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorIntDiv.h new file mode 100644 index 0000000000..ede3939c26 --- /dev/null +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorIntDiv.h @@ -0,0 +1,253 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Benoit Steiner +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CXX11_TENSOR_TENSOR_INTDIV_H +#define EIGEN_CXX11_TENSOR_TENSOR_INTDIV_H + + +namespace Eigen { + +/** \internal + * + * \class TensorIntDiv + * \ingroup CXX11_Tensor_Module + * + * \brief Fast integer division by a constant. + * + * See the paper from Granlund and Montgomery for explanation. + * (at http://dx.doi.org/10.1145/773473.178249) + * + * \sa Tensor + */ + +namespace internal { + +namespace { + + // Note: result is undefined if val == 0 + template + EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE + typename internal::enable_if::type count_leading_zeros(const T val) + { +#ifdef __CUDA_ARCH__ + return __clz(val); +#elif EIGEN_COMP_MSVC + unsigned long index; + _BitScanReverse(&index, val); + return 31 - index; +#else + EIGEN_STATIC_ASSERT(sizeof(unsigned long long) == 8, YOU_MADE_A_PROGRAMMING_MISTAKE); + return __builtin_clz(static_cast(val)); +#endif + } + + template + EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE + typename internal::enable_if::type count_leading_zeros(const T val) + { +#ifdef __CUDA_ARCH__ + return __clzll(val); +#elif EIGEN_COMP_MSVC && EIGEN_ARCH_x86_64 + unsigned long index; + _BitScanReverse64(&index, val); + return 63 - index; +#elif EIGEN_COMP_MSVC + // MSVC's _BitScanReverse64 is not available for 32bits builds. + unsigned int lo = (unsigned int)(val&0xffffffff); + unsigned int hi = (unsigned int)((val>>32)&0xffffffff); + int n; + if(hi==0) + n = 32 + count_leading_zeros(lo); + else + n = count_leading_zeros(hi); + return n; +#else + EIGEN_STATIC_ASSERT(sizeof(unsigned long long) == 8, YOU_MADE_A_PROGRAMMING_MISTAKE); + return __builtin_clzll(static_cast(val)); +#endif + } + + template + struct UnsignedTraits { + typedef typename conditional::type type; + }; + + template + struct DividerTraits { + typedef typename UnsignedTraits::type type; + static const int N = sizeof(T) * 8; + }; + + template + EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE uint32_t muluh(const uint32_t a, const T b) { +#if defined(__CUDA_ARCH__) + return __umulhi(a, b); +#else + return (static_cast(a) * b) >> 32; +#endif + } + + template + EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE uint64_t muluh(const uint64_t a, const T b) { +#if defined(__CUDA_ARCH__) + return __umul64hi(a, b); +#elif defined(__SIZEOF_INT128__) + __uint128_t v = static_cast<__uint128_t>(a) * static_cast<__uint128_t>(b); + return static_cast(v >> 64); +#else + return (TensorUInt128, uint64_t>(a) * TensorUInt128, uint64_t>(b)).upper(); +#endif + } + + template + struct DividerHelper { + static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE uint32_t computeMultiplier(const int log_div, const T divider) { + EIGEN_STATIC_ASSERT(N == 32, YOU_MADE_A_PROGRAMMING_MISTAKE); + return static_cast((static_cast(1) << (N+log_div)) / divider - (static_cast(1) << N) + 1); + } + }; + + template + struct DividerHelper<64, T> { + static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE uint64_t computeMultiplier(const int log_div, const T divider) { +#if defined(__SIZEOF_INT128__) && !defined(__CUDA_ARCH__) + return static_cast((static_cast<__uint128_t>(1) << (64+log_div)) / static_cast<__uint128_t>(divider) - (static_cast<__uint128_t>(1) << 64) + 1); +#else + const uint64_t shift = 1ULL << log_div; + TensorUInt128 result = TensorUInt128 >(shift, 0) / TensorUInt128, uint64_t>(divider) + - TensorUInt128, static_val<0> >(1, 0) + + TensorUInt128, static_val<1> >(1); + return static_cast(result); +#endif + } + }; +} + + +template +struct TensorIntDivisor { + public: + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorIntDivisor() { + multiplier = 0; + shift1 = 0; + shift2 = 0; + } + + // Must have 0 < divider < 2^31. This is relaxed to + // 0 < divider < 2^63 when using 64-bit indices on platforms that support + // the __uint128_t type. + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorIntDivisor(const T divider) { + const int N = DividerTraits::N; + eigen_assert(static_cast::type>(divider) < NumTraits::highest()/2); + eigen_assert(divider > 0); + + // fast ln2 + const int leading_zeros = count_leading_zeros(static_cast(divider)); + int log_div = N - leading_zeros; + // if divider is a power of two then log_div is 1 more than it should be. + if ((static_cast::type>(1) << (log_div-1)) == static_cast::type>(divider)) + log_div--; + + multiplier = DividerHelper::computeMultiplier(log_div, divider); + shift1 = log_div > 1 ? 1 : log_div; + shift2 = log_div > 1 ? log_div-1 : 0; + } + + // Must have 0 <= numerator. On platforms that dont support the __uint128_t + // type numerator should also be less than 2^32-1. + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T divide(const T numerator) const { + eigen_assert(static_cast::type>(numerator) < NumTraits::highest()/2); + //eigen_assert(numerator >= 0); // this is implicitly asserted by the line above + + UnsignedType t1 = muluh(multiplier, numerator); + UnsignedType t = (static_cast(numerator) - t1) >> shift1; + return (t1 + t) >> shift2; + } + + private: + typedef typename DividerTraits::type UnsignedType; + UnsignedType multiplier; + int32_t shift1; + int32_t shift2; +}; + + +// Optimized version for signed 32 bit integers. +// Derived from Hacker's Delight. +// Only works for divisors strictly greater than one +template <> +class TensorIntDivisor { + public: + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorIntDivisor() { + magic = 0; + shift = 0; + } + // Must have 2 <= divider + EIGEN_DEVICE_FUNC TensorIntDivisor(int32_t divider) { + eigen_assert(divider >= 2); + calcMagic(divider); + } + + EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE int divide(const int32_t n) const { +#ifdef __CUDA_ARCH__ + return (__umulhi(magic, n) >> shift); +#else + uint64_t v = static_cast(magic) * static_cast(n); + return (static_cast(v >> 32) >> shift); +#endif + } + +private: + // Compute the magic numbers. See Hacker's Delight section 10 for an in + // depth explanation. + EIGEN_DEVICE_FUNC void calcMagic(int32_t d) { + const unsigned two31 = 0x80000000; // 2**31. + unsigned ad = d; + unsigned t = two31 + (ad >> 31); + unsigned anc = t - 1 - t%ad; // Absolute value of nc. + int p = 31; // Init. p. + unsigned q1 = two31/anc; // Init. q1 = 2**p/|nc|. + unsigned r1 = two31 - q1*anc; // Init. r1 = rem(2**p, |nc|). + unsigned q2 = two31/ad; // Init. q2 = 2**p/|d|. + unsigned r2 = two31 - q2*ad; // Init. r2 = rem(2**p, |d|). + unsigned delta = 0; + do { + p = p + 1; + q1 = 2*q1; // Update q1 = 2**p/|nc|. + r1 = 2*r1; // Update r1 = rem(2**p, |nc|). + if (r1 >= anc) { // (Must be an unsigned + q1 = q1 + 1; // comparison here). + r1 = r1 - anc;} + q2 = 2*q2; // Update q2 = 2**p/|d|. + r2 = 2*r2; // Update r2 = rem(2**p, |d|). + if (r2 >= ad) { // (Must be an unsigned + q2 = q2 + 1; // comparison here). + r2 = r2 - ad;} + delta = ad - r2; + } while (q1 < delta || (q1 == delta && r1 == 0)); + + magic = (unsigned)(q2 + 1); + shift = p - 32; + } + + uint32_t magic; + int32_t shift; +}; + + +template +static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T operator / (const T& numerator, const TensorIntDivisor& divisor) { + return divisor.divide(numerator); +} + + +} // end namespace internal +} // end namespace Eigen + +#endif // EIGEN_CXX11_TENSOR_TENSOR_INTDIV_H diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorLayoutSwap.h b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorLayoutSwap.h new file mode 100644 index 0000000000..cd0109ef44 --- /dev/null +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorLayoutSwap.h @@ -0,0 +1,209 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Benoit Steiner +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CXX11_TENSOR_TENSOR_LAYOUT_SWAP_H +#define EIGEN_CXX11_TENSOR_TENSOR_LAYOUT_SWAP_H + +namespace Eigen { + +/** \class TensorLayoutSwap + * \ingroup CXX11_Tensor_Module + * + * \brief Swap the layout from col-major to row-major, or row-major + * to col-major, and invert the order of the dimensions. + * + * Beware: the dimensions are reversed by this operation. If you want to + * preserve the ordering of the dimensions, you need to combine this + * operation with a shuffle. + * + * \example: + * Tensor input(2, 4); + * Tensor output = input.swap_layout(); + * eigen_assert(output.dimension(0) == 4); + * eigen_assert(output.dimension(1) == 2); + * + * array shuffle(1, 0); + * output = input.swap_layout().shuffle(shuffle); + * eigen_assert(output.dimension(0) == 2); + * eigen_assert(output.dimension(1) == 4); + * + */ +namespace internal { +template +struct traits > : public traits +{ + typedef typename XprType::Scalar Scalar; + typedef traits XprTraits; + typedef typename XprTraits::StorageKind StorageKind; + typedef typename XprTraits::Index Index; + typedef typename XprType::Nested Nested; + typedef typename remove_reference::type _Nested; + static const int NumDimensions = traits::NumDimensions; + static const int Layout = (traits::Layout == ColMajor) ? RowMajor : ColMajor; +}; + +template +struct eval, Eigen::Dense> +{ + typedef const TensorLayoutSwapOp& type; +}; + +template +struct nested, 1, typename eval >::type> +{ + typedef TensorLayoutSwapOp type; +}; + +} // end namespace internal + + + +template +class TensorLayoutSwapOp : public TensorBase, WriteAccessors> +{ + public: + typedef typename Eigen::internal::traits::Scalar Scalar; + typedef typename Eigen::NumTraits::Real RealScalar; + typedef typename internal::remove_const::type CoeffReturnType; + typedef typename Eigen::internal::nested::type Nested; + typedef typename Eigen::internal::traits::StorageKind StorageKind; + typedef typename Eigen::internal::traits::Index Index; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorLayoutSwapOp(const XprType& expr) + : m_xpr(expr) {} + + EIGEN_DEVICE_FUNC + const typename internal::remove_all::type& + expression() const { return m_xpr; } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE TensorLayoutSwapOp& operator = (const TensorLayoutSwapOp& other) + { + typedef TensorAssignOp Assign; + Assign assign(*this, other); + internal::TensorExecutor::run(assign, DefaultDevice()); + return *this; + } + + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE TensorLayoutSwapOp& operator = (const OtherDerived& other) + { + typedef TensorAssignOp Assign; + Assign assign(*this, other); + internal::TensorExecutor::run(assign, DefaultDevice()); + return *this; + } + + protected: + typename XprType::Nested m_xpr; +}; + + +// Eval as rvalue +template +struct TensorEvaluator, Device> +{ + typedef TensorLayoutSwapOp XprType; + typedef typename XprType::Index Index; + static const int NumDims = internal::array_size::Dimensions>::value; + typedef DSizes Dimensions; + + enum { + IsAligned = TensorEvaluator::IsAligned, + PacketAccess = TensorEvaluator::PacketAccess, + Layout = (static_cast(TensorEvaluator::Layout) == static_cast(ColMajor)) ? RowMajor : ColMajor, + CoordAccess = false, // to be implemented + RawAccess = TensorEvaluator::RawAccess + }; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorEvaluator(const XprType& op, const Device& device) + : m_impl(op.expression(), device) + { + for(int i = 0; i < NumDims; ++i) { + m_dimensions[i] = m_impl.dimensions()[NumDims-1-i]; + } + } + + typedef typename XprType::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + typedef typename PacketType::type PacketReturnType; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Dimensions& dimensions() const { return m_dimensions; } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(CoeffReturnType* data) { + return m_impl.evalSubExprsIfNeeded(data); + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void cleanup() { + m_impl.cleanup(); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const + { + return m_impl.coeff(index); + } + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packet(Index index) const + { + return m_impl.template packet(index); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost costPerCoeff(bool vectorized) const { + return m_impl.costPerCoeff(vectorized); + } + + EIGEN_DEVICE_FUNC Scalar* data() const { return m_impl.data(); } + + const TensorEvaluator& impl() const { return m_impl; } + + protected: + TensorEvaluator m_impl; + Dimensions m_dimensions; +}; + + +// Eval as lvalue +template + struct TensorEvaluator, Device> + : public TensorEvaluator, Device> +{ + typedef TensorEvaluator, Device> Base; + typedef TensorLayoutSwapOp XprType; + + enum { + IsAligned = TensorEvaluator::IsAligned, + PacketAccess = TensorEvaluator::PacketAccess, + Layout = (static_cast(TensorEvaluator::Layout) == static_cast(ColMajor)) ? RowMajor : ColMajor, + CoordAccess = false // to be implemented + }; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorEvaluator(const XprType& op, const Device& device) + : Base(op, device) + { } + + typedef typename XprType::Index Index; + typedef typename XprType::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + typedef typename PacketType::type PacketReturnType; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType& coeffRef(Index index) + { + return this->m_impl.coeffRef(index); + } + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + void writePacket(Index index, const PacketReturnType& x) + { + this->m_impl.template writePacket(index, x); + } +}; + +} // end namespace Eigen + +#endif // EIGEN_CXX11_TENSOR_TENSOR_LAYOUT_SWAP_H diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorMacros.h b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorMacros.h new file mode 100644 index 0000000000..ee0078bbcc --- /dev/null +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorMacros.h @@ -0,0 +1,54 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2015 Benoit Steiner +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CXX11_TENSOR_TENSOR_META_MACROS_H +#define EIGEN_CXX11_TENSOR_TENSOR_META_MACROS_H + + +/** use this macro in sfinae selection in templated functions + * + * template::value , int >::type = 0 + * > + * void foo(){} + * + * becomes => + * + * template::value ) + * > + * void foo(){} + */ + +// SFINAE requires variadic templates +#ifndef __CUDACC__ +#if EIGEN_HAS_VARIADIC_TEMPLATES + // SFINAE doesn't work for gcc <= 4.7 + #ifdef EIGEN_COMP_GNUC + #if EIGEN_GNUC_AT_LEAST(4,8) + #define EIGEN_HAS_SFINAE + #endif + #else + #define EIGEN_HAS_SFINAE + #endif +#endif +#endif + +#define EIGEN_SFINAE_ENABLE_IF( __condition__ ) \ + typename internal::enable_if< ( __condition__ ) , int >::type = 0 + + +#if EIGEN_HAS_CONSTEXPR +#define EIGEN_CONSTEXPR constexpr +#else +#define EIGEN_CONSTEXPR +#endif + + +#endif diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorMap.h b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorMap.h new file mode 100644 index 0000000000..a8e55757e4 --- /dev/null +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorMap.h @@ -0,0 +1,321 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Benoit Steiner +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CXX11_TENSOR_TENSOR_MAP_H +#define EIGEN_CXX11_TENSOR_TENSOR_MAP_H + +namespace Eigen { + +/** \class TensorMap + * \ingroup CXX11_Tensor_Module + * + * \brief A tensor expression mapping an existing array of data. + * + */ +/// template class MakePointer_ is added to convert the host pointer to the device pointer. +/// It is added due to the fact that for our device compiler T* is not allowed. +/// If we wanted to use the same Evaluator functions we have to convert that type to our pointer T. +/// This is done through our MakePointer_ class. By default the Type in the MakePointer_ is T* . +/// Therefore, by adding the default value, we managed to convert the type and it does not break any +/// existing code as its default value is T*. +template class MakePointer_> class TensorMap : public TensorBase > +{ + public: + typedef TensorMap Self; + typedef typename PlainObjectType::Base Base; + typedef typename Eigen::internal::nested::type Nested; + typedef typename internal::traits::StorageKind StorageKind; + typedef typename internal::traits::Index Index; + typedef typename internal::traits::Scalar Scalar; + typedef typename NumTraits::Real RealScalar; + typedef typename Base::CoeffReturnType CoeffReturnType; + + /* typedef typename internal::conditional< + bool(internal::is_lvalue::value), + Scalar *, + const Scalar *>::type + PointerType;*/ + typedef typename MakePointer_::Type PointerType; + typedef PointerType PointerArgType; + + static const int Options = Options_; + + static const Index NumIndices = PlainObjectType::NumIndices; + typedef typename PlainObjectType::Dimensions Dimensions; + + enum { + IsAligned = ((int(Options_)&Aligned)==Aligned), + Layout = PlainObjectType::Layout, + CoordAccess = true, + RawAccess = true + }; + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE TensorMap(PointerArgType dataPtr) : m_data(dataPtr), m_dimensions() { + // The number of dimensions used to construct a tensor must be equal to the rank of the tensor. + EIGEN_STATIC_ASSERT((0 == NumIndices || NumIndices == Dynamic), YOU_MADE_A_PROGRAMMING_MISTAKE) + } + +#if EIGEN_HAS_VARIADIC_TEMPLATES + template EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE TensorMap(PointerArgType dataPtr, Index firstDimension, IndexTypes... otherDimensions) : m_data(dataPtr), m_dimensions(firstDimension, otherDimensions...) { + // The number of dimensions used to construct a tensor must be equal to the rank of the tensor. + EIGEN_STATIC_ASSERT((sizeof...(otherDimensions) + 1 == NumIndices || NumIndices == Dynamic), YOU_MADE_A_PROGRAMMING_MISTAKE) + } +#else + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE TensorMap(PointerArgType dataPtr, Index firstDimension) : m_data(dataPtr), m_dimensions(firstDimension) { + // The number of dimensions used to construct a tensor must be equal to the rank of the tensor. + EIGEN_STATIC_ASSERT((1 == NumIndices || NumIndices == Dynamic), YOU_MADE_A_PROGRAMMING_MISTAKE) + } + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE TensorMap(PointerArgType dataPtr, Index dim1, Index dim2) : m_data(dataPtr), m_dimensions(dim1, dim2) { + EIGEN_STATIC_ASSERT(2 == NumIndices || NumIndices == Dynamic, YOU_MADE_A_PROGRAMMING_MISTAKE) + } + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE TensorMap(PointerArgType dataPtr, Index dim1, Index dim2, Index dim3) : m_data(dataPtr), m_dimensions(dim1, dim2, dim3) { + EIGEN_STATIC_ASSERT(3 == NumIndices || NumIndices == Dynamic, YOU_MADE_A_PROGRAMMING_MISTAKE) + } + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE TensorMap(PointerArgType dataPtr, Index dim1, Index dim2, Index dim3, Index dim4) : m_data(dataPtr), m_dimensions(dim1, dim2, dim3, dim4) { + EIGEN_STATIC_ASSERT(4 == NumIndices || NumIndices == Dynamic, YOU_MADE_A_PROGRAMMING_MISTAKE) + } + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE TensorMap(PointerArgType dataPtr, Index dim1, Index dim2, Index dim3, Index dim4, Index dim5) : m_data(dataPtr), m_dimensions(dim1, dim2, dim3, dim4, dim5) { + EIGEN_STATIC_ASSERT(5 == NumIndices || NumIndices == Dynamic, YOU_MADE_A_PROGRAMMING_MISTAKE) + } +#endif + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorMap(PointerArgType dataPtr, const array& dimensions) + : m_data(dataPtr), m_dimensions(dimensions) + { } + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorMap(PointerArgType dataPtr, const Dimensions& dimensions) + : m_data(dataPtr), m_dimensions(dimensions) + { } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorMap(PlainObjectType& tensor) + : m_data(tensor.data()), m_dimensions(tensor.dimensions()) + { } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Index rank() const { return m_dimensions.rank(); } + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Index dimension(Index n) const { return m_dimensions[n]; } + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const Dimensions& dimensions() const { return m_dimensions; } + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Index size() const { return m_dimensions.TotalSize(); } + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE PointerType data() { return m_data; } + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const PointerType data() const { return m_data; } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const Scalar& operator()(const array& indices) const + { + // eigen_assert(checkIndexRange(indices)); + if (PlainObjectType::Options&RowMajor) { + const Index index = m_dimensions.IndexOfRowMajor(indices); + return m_data[index]; + } else { + const Index index = m_dimensions.IndexOfColMajor(indices); + return m_data[index]; + } + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const Scalar& operator()() const + { + EIGEN_STATIC_ASSERT(NumIndices == 0, YOU_MADE_A_PROGRAMMING_MISTAKE) + return m_data[0]; + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const Scalar& operator()(Index index) const + { + eigen_internal_assert(index >= 0 && index < size()); + return m_data[index]; + } + +#if EIGEN_HAS_VARIADIC_TEMPLATES + template EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const Scalar& operator()(Index firstIndex, Index secondIndex, IndexTypes... otherIndices) const + { + EIGEN_STATIC_ASSERT(sizeof...(otherIndices) + 2 == NumIndices, YOU_MADE_A_PROGRAMMING_MISTAKE) + if (PlainObjectType::Options&RowMajor) { + const Index index = m_dimensions.IndexOfRowMajor(array{{firstIndex, secondIndex, otherIndices...}}); + return m_data[index]; + } else { + const Index index = m_dimensions.IndexOfColMajor(array{{firstIndex, secondIndex, otherIndices...}}); + return m_data[index]; + } + } +#else + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const Scalar& operator()(Index i0, Index i1) const + { + if (PlainObjectType::Options&RowMajor) { + const Index index = i1 + i0 * m_dimensions[1]; + return m_data[index]; + } else { + const Index index = i0 + i1 * m_dimensions[0]; + return m_data[index]; + } + } + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const Scalar& operator()(Index i0, Index i1, Index i2) const + { + if (PlainObjectType::Options&RowMajor) { + const Index index = i2 + m_dimensions[2] * (i1 + m_dimensions[1] * i0); + return m_data[index]; + } else { + const Index index = i0 + m_dimensions[0] * (i1 + m_dimensions[1] * i2); + return m_data[index]; + } + } + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const Scalar& operator()(Index i0, Index i1, Index i2, Index i3) const + { + if (PlainObjectType::Options&RowMajor) { + const Index index = i3 + m_dimensions[3] * (i2 + m_dimensions[2] * (i1 + m_dimensions[1] * i0)); + return m_data[index]; + } else { + const Index index = i0 + m_dimensions[0] * (i1 + m_dimensions[1] * (i2 + m_dimensions[2] * i3)); + return m_data[index]; + } + } + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE const Scalar& operator()(Index i0, Index i1, Index i2, Index i3, Index i4) const + { + if (PlainObjectType::Options&RowMajor) { + const Index index = i4 + m_dimensions[4] * (i3 + m_dimensions[3] * (i2 + m_dimensions[2] * (i1 + m_dimensions[1] * i0))); + return m_data[index]; + } else { + const Index index = i0 + m_dimensions[0] * (i1 + m_dimensions[1] * (i2 + m_dimensions[2] * (i3 + m_dimensions[3] * i4))); + return m_data[index]; + } + } +#endif + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Scalar& operator()(const array& indices) + { + // eigen_assert(checkIndexRange(indices)); + if (PlainObjectType::Options&RowMajor) { + const Index index = m_dimensions.IndexOfRowMajor(indices); + return m_data[index]; + } else { + const Index index = m_dimensions.IndexOfColMajor(indices); + return m_data[index]; + } + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Scalar& operator()() + { + EIGEN_STATIC_ASSERT(NumIndices == 0, YOU_MADE_A_PROGRAMMING_MISTAKE) + return m_data[0]; + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Scalar& operator()(Index index) + { + eigen_internal_assert(index >= 0 && index < size()); + return m_data[index]; + } + +#if EIGEN_HAS_VARIADIC_TEMPLATES + template EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Scalar& operator()(Index firstIndex, Index secondIndex, IndexTypes... otherIndices) + { + static_assert(sizeof...(otherIndices) + 2 == NumIndices || NumIndices == Dynamic, "Number of indices used to access a tensor coefficient must be equal to the rank of the tensor."); + const std::size_t NumDims = sizeof...(otherIndices) + 2; + if (PlainObjectType::Options&RowMajor) { + const Index index = m_dimensions.IndexOfRowMajor(array{{firstIndex, secondIndex, otherIndices...}}); + return m_data[index]; + } else { + const Index index = m_dimensions.IndexOfColMajor(array{{firstIndex, secondIndex, otherIndices...}}); + return m_data[index]; + } + } +#else + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Scalar& operator()(Index i0, Index i1) + { + if (PlainObjectType::Options&RowMajor) { + const Index index = i1 + i0 * m_dimensions[1]; + return m_data[index]; + } else { + const Index index = i0 + i1 * m_dimensions[0]; + return m_data[index]; + } + } + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Scalar& operator()(Index i0, Index i1, Index i2) + { + if (PlainObjectType::Options&RowMajor) { + const Index index = i2 + m_dimensions[2] * (i1 + m_dimensions[1] * i0); + return m_data[index]; + } else { + const Index index = i0 + m_dimensions[0] * (i1 + m_dimensions[1] * i2); + return m_data[index]; + } + } + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Scalar& operator()(Index i0, Index i1, Index i2, Index i3) + { + if (PlainObjectType::Options&RowMajor) { + const Index index = i3 + m_dimensions[3] * (i2 + m_dimensions[2] * (i1 + m_dimensions[1] * i0)); + return m_data[index]; + } else { + const Index index = i0 + m_dimensions[0] * (i1 + m_dimensions[1] * (i2 + m_dimensions[2] * i3)); + return m_data[index]; + } + } + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE Scalar& operator()(Index i0, Index i1, Index i2, Index i3, Index i4) + { + if (PlainObjectType::Options&RowMajor) { + const Index index = i4 + m_dimensions[4] * (i3 + m_dimensions[3] * (i2 + m_dimensions[2] * (i1 + m_dimensions[1] * i0))); + return m_data[index]; + } else { + const Index index = i0 + m_dimensions[0] * (i1 + m_dimensions[1] * (i2 + m_dimensions[2] * (i3 + m_dimensions[3] * i4))); + return m_data[index]; + } + } +#endif + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Self& operator=(const Self& other) + { + typedef TensorAssignOp Assign; + Assign assign(*this, other); + internal::TensorExecutor::run(assign, DefaultDevice()); + return *this; + } + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Self& operator=(const OtherDerived& other) + { + typedef TensorAssignOp Assign; + Assign assign(*this, other); + internal::TensorExecutor::run(assign, DefaultDevice()); + return *this; + } + + private: + typename MakePointer_::Type m_data; + Dimensions m_dimensions; +}; + +} // end namespace Eigen + +#endif // EIGEN_CXX11_TENSOR_TENSOR_MAP_H diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorMeta.h b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorMeta.h new file mode 100644 index 0000000000..615559d445 --- /dev/null +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorMeta.h @@ -0,0 +1,218 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2015 Benoit Steiner +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CXX11_TENSOR_TENSOR_META_H +#define EIGEN_CXX11_TENSOR_TENSOR_META_H + +namespace Eigen { + +template struct Cond {}; + +template EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +const T1& choose(Cond, const T1& first, const T2&) { + return first; +} + +template EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +const T2& choose(Cond, const T1&, const T2& second) { + return second; +} + + +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +T divup(const X x, const Y y) { + return static_cast((x + y - 1) / y); +} + +template +EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE +T divup(const T x, const T y) { + return static_cast((x + y - 1) / y); +} + +template struct max_n_1 { + static const size_t size = n; +}; +template <> struct max_n_1<0> { + static const size_t size = 1; +}; + + +// Default packet types +template +struct PacketType : internal::packet_traits { + typedef typename internal::packet_traits::type type; +}; + +// For CUDA packet types when using a GpuDevice +#if defined(EIGEN_USE_GPU) && defined(__CUDACC__) && defined(EIGEN_HAS_CUDA_FP16) +template <> +struct PacketType { + typedef half2 type; + static const int size = 2; + enum { + HasAdd = 1, + HasSub = 1, + HasMul = 1, + HasNegate = 1, + HasAbs = 1, + HasArg = 0, + HasAbs2 = 0, + HasMin = 1, + HasMax = 1, + HasConj = 0, + HasSetLinear = 0, + HasBlend = 0, + + HasDiv = 1, + HasSqrt = 1, + HasRsqrt = 1, + HasExp = 1, + HasLog = 1, + HasLog1p = 0, + HasLog10 = 0, + HasPow = 1, + }; +}; +#endif + +#if defined(EIGEN_USE_SYCL) +template + struct PacketType { + typedef T type; + static const int size = 1; + enum { + HasAdd = 0, + HasSub = 0, + HasMul = 0, + HasNegate = 0, + HasAbs = 0, + HasArg = 0, + HasAbs2 = 0, + HasMin = 0, + HasMax = 0, + HasConj = 0, + HasSetLinear = 0, + HasBlend = 0 + }; +}; +#endif + + +// Tuple mimics std::pair but works on e.g. nvcc. +template struct Tuple { + public: + U first; + V second; + + typedef U first_type; + typedef V second_type; + + EIGEN_CONSTEXPR EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Tuple() : first(), second() {} + + EIGEN_CONSTEXPR EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Tuple(const U& f, const V& s) : first(f), second(s) {} + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Tuple& operator= (const Tuple& rhs) { + if (&rhs == this) return *this; + first = rhs.first; + second = rhs.second; + return *this; + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + void swap(Tuple& rhs) { + using numext::swap; + swap(first, rhs.first); + swap(second, rhs.second); + } +}; + +template +EIGEN_CONSTEXPR EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +bool operator==(const Tuple& x, const Tuple& y) { + return (x.first == y.first && x.second == y.second); +} + +template +EIGEN_CONSTEXPR EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +bool operator!=(const Tuple& x, const Tuple& y) { + return !(x == y); +} + + +// Can't use std::pairs on cuda devices +template struct IndexPair { + EIGEN_CONSTEXPR EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE IndexPair() : first(0), second(0) {} + EIGEN_CONSTEXPR EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE IndexPair(Idx f, Idx s) : first(f), second(s) {} + + EIGEN_DEVICE_FUNC void set(IndexPair val) { + first = val.first; + second = val.second; + } + + Idx first; + Idx second; +}; + + +#ifdef EIGEN_HAS_SFINAE +namespace internal { + + template + EIGEN_CONSTEXPR EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + array customIndices2Array(IndexType& idx, numeric_list) { + return { idx[Is]... }; + } + template + EIGEN_CONSTEXPR EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + array customIndices2Array(IndexType&, numeric_list) { + return array(); + } + + /** Make an array (for index/dimensions) out of a custom index */ + template + EIGEN_CONSTEXPR EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + array customIndices2Array(IndexType& idx) { + return customIndices2Array(idx, typename gen_numeric_list::type{}); + } + + + template + struct is_base_of + { + + typedef char (&yes)[1]; + typedef char (&no)[2]; + + template + struct Host + { + operator BB*() const; + operator DD*(); + }; + + template + static yes check(D*, T); + static no check(B*, int); + + static const bool value = sizeof(check(Host(), int())) == sizeof(yes); + }; + +} +#endif + + + +} // namespace Eigen + +#endif // EIGEN_CXX11_TENSOR_TENSOR_META_H diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorMorphing.h b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorMorphing.h new file mode 100644 index 0000000000..d34f1e328c --- /dev/null +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorMorphing.h @@ -0,0 +1,888 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Benoit Steiner +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CXX11_TENSOR_TENSOR_MORPHING_H +#define EIGEN_CXX11_TENSOR_TENSOR_MORPHING_H + +namespace Eigen { + +/** \class TensorReshaping + * \ingroup CXX11_Tensor_Module + * + * \brief Tensor reshaping class. + * + * + */ +namespace internal { +template +struct traits > : public traits +{ + typedef typename XprType::Scalar Scalar; + typedef traits XprTraits; + typedef typename XprTraits::StorageKind StorageKind; + typedef typename XprTraits::Index Index; + typedef typename XprType::Nested Nested; + typedef typename remove_reference::type _Nested; + static const int NumDimensions = array_size::value; + static const int Layout = XprTraits::Layout; +}; + +template +struct eval, Eigen::Dense> +{ + typedef const TensorReshapingOp& type; +}; + +template +struct nested, 1, typename eval >::type> +{ + typedef TensorReshapingOp type; +}; + +} // end namespace internal + + + +template +class TensorReshapingOp : public TensorBase, WriteAccessors> +{ + public: + typedef typename Eigen::internal::traits::Scalar Scalar; + typedef typename internal::remove_const::type CoeffReturnType; + typedef typename Eigen::internal::nested::type Nested; + typedef typename Eigen::internal::traits::StorageKind StorageKind; + typedef typename Eigen::internal::traits::Index Index; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorReshapingOp(const XprType& expr, const NewDimensions& dims) + : m_xpr(expr), m_dims(dims) {} + + EIGEN_DEVICE_FUNC + const NewDimensions& dimensions() const { return m_dims; } + + EIGEN_DEVICE_FUNC + const typename internal::remove_all::type& + expression() const { return m_xpr; } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE TensorReshapingOp& operator = (const TensorReshapingOp& other) + { + typedef TensorAssignOp Assign; + Assign assign(*this, other); + internal::TensorExecutor::run(assign, DefaultDevice()); + return *this; + } + + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE TensorReshapingOp& operator = (const OtherDerived& other) + { + typedef TensorAssignOp Assign; + Assign assign(*this, other); + internal::TensorExecutor::run(assign, DefaultDevice()); + return *this; + } + + protected: + typename XprType::Nested m_xpr; + const NewDimensions m_dims; +}; + + +// Eval as rvalue +template +struct TensorEvaluator, Device> +{ + typedef TensorReshapingOp XprType; + typedef NewDimensions Dimensions; + + enum { + IsAligned = TensorEvaluator::IsAligned, + PacketAccess = TensorEvaluator::PacketAccess, + Layout = TensorEvaluator::Layout, + CoordAccess = false, // to be implemented + RawAccess = TensorEvaluator::RawAccess + }; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorEvaluator(const XprType& op, const Device& device) + : m_impl(op.expression(), device), m_dimensions(op.dimensions()) + { + // The total size of the reshaped tensor must be equal to the total size + // of the input tensor. + eigen_assert(internal::array_prod(m_impl.dimensions()) == internal::array_prod(op.dimensions())); + } + + typedef typename XprType::Index Index; + typedef typename XprType::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + typedef typename PacketType::type PacketReturnType; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Dimensions& dimensions() const { return m_dimensions; } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(CoeffReturnType* data) { + return m_impl.evalSubExprsIfNeeded(data); + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void cleanup() { + m_impl.cleanup(); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const + { + return m_impl.coeff(index); + } + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packet(Index index) const + { + return m_impl.template packet(index); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost costPerCoeff(bool vectorized) const { + return m_impl.costPerCoeff(vectorized); + } + + EIGEN_DEVICE_FUNC Scalar* data() const { return const_cast(m_impl.data()); } + + EIGEN_DEVICE_FUNC const TensorEvaluator& impl() const { return m_impl; } + + protected: + TensorEvaluator m_impl; + NewDimensions m_dimensions; +}; + + +// Eval as lvalue +template + struct TensorEvaluator, Device> + : public TensorEvaluator, Device> + +{ + typedef TensorEvaluator, Device> Base; + typedef TensorReshapingOp XprType; + typedef NewDimensions Dimensions; + + enum { + IsAligned = TensorEvaluator::IsAligned, + PacketAccess = TensorEvaluator::PacketAccess, + Layout = TensorEvaluator::Layout, + CoordAccess = false, // to be implemented + RawAccess = TensorEvaluator::RawAccess + }; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorEvaluator(const XprType& op, const Device& device) + : Base(op, device) + { } + + typedef typename XprType::Index Index; + typedef typename XprType::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + typedef typename PacketType::type PacketReturnType; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType& coeffRef(Index index) + { + return this->m_impl.coeffRef(index); + } + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + void writePacket(Index index, const PacketReturnType& x) + { + this->m_impl.template writePacket(index, x); + } +}; + + +/** \class TensorSlicing + * \ingroup CXX11_Tensor_Module + * + * \brief Tensor slicing class. + * + * + */ +namespace internal { +template +struct traits > : public traits +{ + typedef typename XprType::Scalar Scalar; + typedef traits XprTraits; + typedef typename XprTraits::StorageKind StorageKind; + typedef typename XprTraits::Index Index; + typedef typename XprType::Nested Nested; + typedef typename remove_reference::type _Nested; + static const int NumDimensions = array_size::value; + static const int Layout = XprTraits::Layout; +}; + +template +struct eval, Eigen::Dense> +{ + typedef const TensorSlicingOp& type; +}; + +template +struct nested, 1, typename eval >::type> +{ + typedef TensorSlicingOp type; +}; + +} // end namespace internal + + + +template +class TensorSlicingOp : public TensorBase > +{ + public: + typedef typename Eigen::internal::traits::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + typedef typename Eigen::internal::nested::type Nested; + typedef typename Eigen::internal::traits::StorageKind StorageKind; + typedef typename Eigen::internal::traits::Index Index; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorSlicingOp(const XprType& expr, const StartIndices& indices, const Sizes& sizes) + : m_xpr(expr), m_indices(indices), m_sizes(sizes) {} + + EIGEN_DEVICE_FUNC + const StartIndices& startIndices() const { return m_indices; } + EIGEN_DEVICE_FUNC + const Sizes& sizes() const { return m_sizes; } + + EIGEN_DEVICE_FUNC + const typename internal::remove_all::type& + expression() const { return m_xpr; } + + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE TensorSlicingOp& operator = (const OtherDerived& other) + { + typedef TensorAssignOp Assign; + Assign assign(*this, other); + internal::TensorExecutor::run(assign, DefaultDevice()); + return *this; + } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE TensorSlicingOp& operator = (const TensorSlicingOp& other) + { + typedef TensorAssignOp Assign; + Assign assign(*this, other); + internal::TensorExecutor::run(assign, DefaultDevice()); + return *this; + } + + + protected: + typename XprType::Nested m_xpr; + const StartIndices m_indices; + const Sizes m_sizes; +}; + + +// Fixme: figure out the exact threshold +namespace { +template struct MemcpyTriggerForSlicing { + EIGEN_DEVICE_FUNC MemcpyTriggerForSlicing(const Device& device) : threshold_(2 * device.numThreads()) { } + EIGEN_DEVICE_FUNC bool operator ()(Index val) const { return val > threshold_; } + + private: + Index threshold_; +}; + +// It is very expensive to start the memcpy kernel on GPU: we therefore only +// use it for large copies. +#ifdef EIGEN_USE_GPU +template struct MemcpyTriggerForSlicing { + EIGEN_DEVICE_FUNC MemcpyTriggerForSlicing(const GpuDevice&) { } + EIGEN_DEVICE_FUNC bool operator ()(Index val) const { return val > 4*1024*1024; } +}; +#endif +} + +// Eval as rvalue +template +struct TensorEvaluator, Device> +{ + typedef TensorSlicingOp XprType; + static const int NumDims = internal::array_size::value; + + enum { + // Alignment can't be guaranteed at compile time since it depends on the + // slice offsets and sizes. + IsAligned = /*TensorEvaluator::IsAligned*/false, + PacketAccess = TensorEvaluator::PacketAccess, + Layout = TensorEvaluator::Layout, + CoordAccess = false, + RawAccess = false + }; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorEvaluator(const XprType& op, const Device& device) + : m_impl(op.expression(), device), m_device(device), m_dimensions(op.sizes()), m_offsets(op.startIndices()) + { + for (std::size_t i = 0; i < internal::array_size::value; ++i) { + eigen_assert(m_impl.dimensions()[i] >= op.sizes()[i] + op.startIndices()[i]); + } + + const typename TensorEvaluator::Dimensions& input_dims = m_impl.dimensions(); + const Sizes& output_dims = op.sizes(); + if (static_cast(Layout) == static_cast(ColMajor)) { + m_inputStrides[0] = 1; + for (int i = 1; i < NumDims; ++i) { + m_inputStrides[i] = m_inputStrides[i-1] * input_dims[i-1]; + } + + // Don't initialize m_fastOutputStrides[0] since it won't ever be accessed. + m_outputStrides[0] = 1; + for (int i = 1; i < NumDims; ++i) { + m_outputStrides[i] = m_outputStrides[i-1] * output_dims[i-1]; + m_fastOutputStrides[i] = internal::TensorIntDivisor(m_outputStrides[i]); + } + } else { + m_inputStrides[NumDims-1] = 1; + for (int i = NumDims - 2; i >= 0; --i) { + m_inputStrides[i] = m_inputStrides[i+1] * input_dims[i+1]; + } + + // Don't initialize m_fastOutputStrides[NumDims-1] since it won't ever be accessed. + m_outputStrides[NumDims-1] = 1; + for (int i = NumDims - 2; i >= 0; --i) { + m_outputStrides[i] = m_outputStrides[i+1] * output_dims[i+1]; + m_fastOutputStrides[i] = internal::TensorIntDivisor(m_outputStrides[i]); + } + } + } + + typedef typename XprType::Index Index; + typedef typename XprType::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + typedef typename PacketType::type PacketReturnType; + typedef Sizes Dimensions; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Dimensions& dimensions() const { return m_dimensions; } + + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(CoeffReturnType* data) { + m_impl.evalSubExprsIfNeeded(NULL); + if (!NumTraits::type>::RequireInitialization && data && m_impl.data()) { + Index contiguous_values = 1; + if (static_cast(Layout) == static_cast(ColMajor)) { + for (int i = 0; i < NumDims; ++i) { + contiguous_values *= dimensions()[i]; + if (dimensions()[i] != m_impl.dimensions()[i]) { + break; + } + } + } else { + for (int i = NumDims-1; i >= 0; --i) { + contiguous_values *= dimensions()[i]; + if (dimensions()[i] != m_impl.dimensions()[i]) { + break; + } + } + } + // Use memcpy if it's going to be faster than using the regular evaluation. + const MemcpyTriggerForSlicing trigger(m_device); + if (trigger(contiguous_values)) { + Scalar* src = (Scalar*)m_impl.data(); + for (int i = 0; i < internal::array_prod(dimensions()); i += contiguous_values) { + Index offset = srcCoeff(i); + m_device.memcpy((void*)(data+i), src+offset, contiguous_values * sizeof(Scalar)); + } + return false; + } + } + return true; + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void cleanup() { + m_impl.cleanup(); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const + { + return m_impl.coeff(srcCoeff(index)); + } + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packet(Index index) const + { + const int packetSize = internal::unpacket_traits::size; + EIGEN_STATIC_ASSERT((packetSize > 1), YOU_MADE_A_PROGRAMMING_MISTAKE) + eigen_assert(index+packetSize-1 < internal::array_prod(dimensions())); + + Index inputIndices[] = {0, 0}; + Index indices[] = {index, index + packetSize - 1}; + if (static_cast(Layout) == static_cast(ColMajor)) { + for (int i = NumDims - 1; i > 0; --i) { + const Index idx0 = indices[0] / m_fastOutputStrides[i]; + const Index idx1 = indices[1] / m_fastOutputStrides[i]; + inputIndices[0] += (idx0 + m_offsets[i]) * m_inputStrides[i]; + inputIndices[1] += (idx1 + m_offsets[i]) * m_inputStrides[i]; + indices[0] -= idx0 * m_outputStrides[i]; + indices[1] -= idx1 * m_outputStrides[i]; + } + inputIndices[0] += (indices[0] + m_offsets[0]); + inputIndices[1] += (indices[1] + m_offsets[0]); + } else { + for (int i = 0; i < NumDims - 1; ++i) { + const Index idx0 = indices[0] / m_fastOutputStrides[i]; + const Index idx1 = indices[1] / m_fastOutputStrides[i]; + inputIndices[0] += (idx0 + m_offsets[i]) * m_inputStrides[i]; + inputIndices[1] += (idx1 + m_offsets[i]) * m_inputStrides[i]; + indices[0] -= idx0 * m_outputStrides[i]; + indices[1] -= idx1 * m_outputStrides[i]; + } + inputIndices[0] += (indices[0] + m_offsets[NumDims-1]); + inputIndices[1] += (indices[1] + m_offsets[NumDims-1]); + } + if (inputIndices[1] - inputIndices[0] == packetSize - 1) { + PacketReturnType rslt = m_impl.template packet(inputIndices[0]); + return rslt; + } + else { + EIGEN_ALIGN_MAX typename internal::remove_const::type values[packetSize]; + values[0] = m_impl.coeff(inputIndices[0]); + values[packetSize-1] = m_impl.coeff(inputIndices[1]); + for (int i = 1; i < packetSize-1; ++i) { + values[i] = coeff(index+i); + } + PacketReturnType rslt = internal::pload(values); + return rslt; + } + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost costPerCoeff(bool vectorized) const { + return m_impl.costPerCoeff(vectorized) + TensorOpCost(0, 0, NumDims); + } + + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar* data() const { + Scalar* result = m_impl.data(); + if (result) { + Index offset = 0; + if (static_cast(Layout) == static_cast(ColMajor)) { + for (int i = 0; i < NumDims; ++i) { + if (m_dimensions[i] != m_impl.dimensions()[i]) { + offset += m_offsets[i] * m_inputStrides[i]; + for (int j = i+1; j < NumDims; ++j) { + if (m_dimensions[j] > 1) { + return NULL; + } + offset += m_offsets[j] * m_inputStrides[j]; + } + break; + } + } + } else { + for (int i = NumDims - 1; i >= 0; --i) { + if (m_dimensions[i] != m_impl.dimensions()[i]) { + offset += m_offsets[i] * m_inputStrides[i]; + for (int j = i-1; j >= 0; --j) { + if (m_dimensions[j] > 1) { + return NULL; + } + offset += m_offsets[j] * m_inputStrides[j]; + } + break; + } + } + } + return result + offset; + } + return NULL; + } + + protected: + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index srcCoeff(Index index) const + { + Index inputIndex = 0; + if (static_cast(Layout) == static_cast(ColMajor)) { + for (int i = NumDims - 1; i > 0; --i) { + const Index idx = index / m_fastOutputStrides[i]; + inputIndex += (idx + m_offsets[i]) * m_inputStrides[i]; + index -= idx * m_outputStrides[i]; + } + inputIndex += (index + m_offsets[0]); + } else { + for (int i = 0; i < NumDims - 1; ++i) { + const Index idx = index / m_fastOutputStrides[i]; + inputIndex += (idx + m_offsets[i]) * m_inputStrides[i]; + index -= idx * m_outputStrides[i]; + } + inputIndex += (index + m_offsets[NumDims-1]); + } + return inputIndex; + } + + array m_outputStrides; + array, NumDims> m_fastOutputStrides; + array m_inputStrides; + TensorEvaluator m_impl; + const Device& m_device; + Dimensions m_dimensions; + const StartIndices m_offsets; +}; + + +// Eval as lvalue +template +struct TensorEvaluator, Device> + : public TensorEvaluator, Device> +{ + typedef TensorEvaluator, Device> Base; + typedef TensorSlicingOp XprType; + static const int NumDims = internal::array_size::value; + + enum { + IsAligned = /*TensorEvaluator::IsAligned*/false, + PacketAccess = TensorEvaluator::PacketAccess, + Layout = TensorEvaluator::Layout, + CoordAccess = false, + RawAccess = false + }; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorEvaluator(const XprType& op, const Device& device) + : Base(op, device) + { } + + typedef typename XprType::Index Index; + typedef typename XprType::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + typedef typename PacketType::type PacketReturnType; + typedef Sizes Dimensions; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType& coeffRef(Index index) + { + return this->m_impl.coeffRef(this->srcCoeff(index)); + } + + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + void writePacket(Index index, const PacketReturnType& x) + { + const int packetSize = internal::unpacket_traits::size; + Index inputIndices[] = {0, 0}; + Index indices[] = {index, index + packetSize - 1}; + if (static_cast(Layout) == static_cast(ColMajor)) { + for (int i = NumDims - 1; i > 0; --i) { + const Index idx0 = indices[0] / this->m_fastOutputStrides[i]; + const Index idx1 = indices[1] / this->m_fastOutputStrides[i]; + inputIndices[0] += (idx0 + this->m_offsets[i]) * this->m_inputStrides[i]; + inputIndices[1] += (idx1 + this->m_offsets[i]) * this->m_inputStrides[i]; + indices[0] -= idx0 * this->m_outputStrides[i]; + indices[1] -= idx1 * this->m_outputStrides[i]; + } + inputIndices[0] += (indices[0] + this->m_offsets[0]); + inputIndices[1] += (indices[1] + this->m_offsets[0]); + } else { + for (int i = 0; i < NumDims - 1; ++i) { + const Index idx0 = indices[0] / this->m_fastOutputStrides[i]; + const Index idx1 = indices[1] / this->m_fastOutputStrides[i]; + inputIndices[0] += (idx0 + this->m_offsets[i]) * this->m_inputStrides[i]; + inputIndices[1] += (idx1 + this->m_offsets[i]) * this->m_inputStrides[i]; + indices[0] -= idx0 * this->m_outputStrides[i]; + indices[1] -= idx1 * this->m_outputStrides[i]; + } + inputIndices[0] += (indices[0] + this->m_offsets[NumDims-1]); + inputIndices[1] += (indices[1] + this->m_offsets[NumDims-1]); + } + if (inputIndices[1] - inputIndices[0] == packetSize - 1) { + this->m_impl.template writePacket(inputIndices[0], x); + } + else { + EIGEN_ALIGN_MAX CoeffReturnType values[packetSize]; + internal::pstore(values, x); + this->m_impl.coeffRef(inputIndices[0]) = values[0]; + this->m_impl.coeffRef(inputIndices[1]) = values[packetSize-1]; + for (int i = 1; i < packetSize-1; ++i) { + this->coeffRef(index+i) = values[i]; + } + } + } +}; + + + +namespace internal { +template +struct traits > : public traits +{ + typedef typename XprType::Scalar Scalar; + typedef traits XprTraits; + typedef typename XprTraits::StorageKind StorageKind; + typedef typename XprTraits::Index Index; + typedef typename XprType::Nested Nested; + typedef typename remove_reference::type _Nested; + static const int NumDimensions = array_size::value; + static const int Layout = XprTraits::Layout; +}; + +template +struct eval, Eigen::Dense> +{ + typedef const TensorStridingSlicingOp& type; +}; + +template +struct nested, 1, typename eval >::type> +{ + typedef TensorStridingSlicingOp type; +}; + +} // end namespace internal + + +template +class TensorStridingSlicingOp : public TensorBase > +{ + public: + typedef typename internal::traits::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + typedef typename internal::nested::type Nested; + typedef typename internal::traits::StorageKind StorageKind; + typedef typename internal::traits::Index Index; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorStridingSlicingOp( + const XprType& expr, const StartIndices& startIndices, + const StopIndices& stopIndices, const Strides& strides) + : m_xpr(expr), m_startIndices(startIndices), m_stopIndices(stopIndices), + m_strides(strides) {} + + EIGEN_DEVICE_FUNC + const StartIndices& startIndices() const { return m_startIndices; } + EIGEN_DEVICE_FUNC + const StartIndices& stopIndices() const { return m_stopIndices; } + EIGEN_DEVICE_FUNC + const StartIndices& strides() const { return m_strides; } + + EIGEN_DEVICE_FUNC + const typename internal::remove_all::type& + expression() const { return m_xpr; } + + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE TensorStridingSlicingOp& operator = (const TensorStridingSlicingOp& other) + { + typedef TensorAssignOp Assign; + Assign assign(*this, other); + internal::TensorExecutor::run( + assign, DefaultDevice()); + return *this; + } + + template + EIGEN_DEVICE_FUNC + EIGEN_STRONG_INLINE TensorStridingSlicingOp& operator = (const OtherDerived& other) + { + typedef TensorAssignOp Assign; + Assign assign(*this, other); + internal::TensorExecutor::run( + assign, DefaultDevice()); + return *this; + } + + protected: + typename XprType::Nested m_xpr; + const StartIndices m_startIndices; + const StopIndices m_stopIndices; + const Strides m_strides; +}; + +// Eval as rvalue +template +struct TensorEvaluator, Device> +{ + typedef TensorStridingSlicingOp XprType; + static const int NumDims = internal::array_size::value; + + enum { + // Alignment can't be guaranteed at compile time since it depends on the + // slice offsets and sizes. + IsAligned = false, + PacketAccess = false, + BlockAccess = false, + Layout = TensorEvaluator::Layout, + RawAccess = false + }; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorEvaluator(const XprType& op, const Device& device) + : m_impl(op.expression(), device), m_device(device), m_strides(op.strides()) + { + // Handle degenerate intervals by gracefully clamping and allowing m_dimensions to be zero + DSizes startIndicesClamped, stopIndicesClamped; + for (size_t i = 0; i < internal::array_size::value; ++i) { + eigen_assert(m_strides[i] != 0 && "0 stride is invalid"); + if(m_strides[i]>0){ + startIndicesClamped[i] = clamp(op.startIndices()[i], 0, m_impl.dimensions()[i]); + stopIndicesClamped[i] = clamp(op.stopIndices()[i], 0, m_impl.dimensions()[i]); + }else{ + /* implies m_strides[i]<0 by assert */ + startIndicesClamped[i] = clamp(op.startIndices()[i], -1, m_impl.dimensions()[i] - 1); + stopIndicesClamped[i] = clamp(op.stopIndices()[i], -1, m_impl.dimensions()[i] - 1); + } + m_startIndices[i] = startIndicesClamped[i]; + } + + const typename TensorEvaluator::Dimensions& input_dims = m_impl.dimensions(); + + // check for degenerate intervals and compute output tensor shape + bool degenerate = false;; + for(int i = 0; i < NumDims; i++){ + Index interval = stopIndicesClamped[i] - startIndicesClamped[i]; + if(interval == 0 || ((interval<0) != (m_strides[i]<0))){ + m_dimensions[i] = 0; + degenerate = true; + }else{ + m_dimensions[i] = interval / m_strides[i] + + (interval % m_strides[i] != 0 ? 1 : 0); + eigen_assert(m_dimensions[i] >= 0); + } + } + Strides output_dims = m_dimensions; + + if (static_cast(Layout) == static_cast(ColMajor)) { + m_inputStrides[0] = m_strides[0]; + m_offsets[0] = startIndicesClamped[0]; + Index previousDimProduct = 1; + for (int i = 1; i < NumDims; ++i) { + previousDimProduct *= input_dims[i-1]; + m_inputStrides[i] = previousDimProduct * m_strides[i]; + m_offsets[i] = startIndicesClamped[i] * previousDimProduct; + } + + // Don't initialize m_fastOutputStrides[0] since it won't ever be accessed. + m_outputStrides[0] = 1; + for (int i = 1; i < NumDims; ++i) { + m_outputStrides[i] = m_outputStrides[i-1] * output_dims[i-1]; + // NOTE: if tensor is degenerate, we send 1 to prevent TensorIntDivisor constructor crash + m_fastOutputStrides[i] = internal::TensorIntDivisor(degenerate ? 1 : m_outputStrides[i]); + } + } else { + m_inputStrides[NumDims-1] = m_strides[NumDims-1]; + m_offsets[NumDims-1] = startIndicesClamped[NumDims-1]; + Index previousDimProduct = 1; + for (int i = NumDims - 2; i >= 0; --i) { + previousDimProduct *= input_dims[i+1]; + m_inputStrides[i] = previousDimProduct * m_strides[i]; + m_offsets[i] = startIndicesClamped[i] * previousDimProduct; + } + + m_outputStrides[NumDims-1] = 1; + for (int i = NumDims - 2; i >= 0; --i) { + m_outputStrides[i] = m_outputStrides[i+1] * output_dims[i+1]; + // NOTE: if tensor is degenerate, we send 1 to prevent TensorIntDivisor constructor crash + m_fastOutputStrides[i] = internal::TensorIntDivisor(degenerate ? 1 : m_outputStrides[i]); + } + } + m_block_total_size_max = numext::maxi(static_cast(1), + device.lastLevelCacheSize() / + sizeof(Scalar)); + } + + typedef typename XprType::Index Index; + typedef typename XprType::Scalar Scalar; + typedef typename internal::remove_const::type ScalarNonConst; + typedef typename XprType::CoeffReturnType CoeffReturnType; + typedef typename PacketType::type PacketReturnType; + typedef Strides Dimensions; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Dimensions& dimensions() const { return m_dimensions; } + + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(CoeffReturnType*) { + m_impl.evalSubExprsIfNeeded(NULL); + return true; + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void cleanup() { + m_impl.cleanup(); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const + { + return m_impl.coeff(srcCoeff(index)); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost costPerCoeff(bool vectorized) const { + return m_impl.costPerCoeff(vectorized) + TensorOpCost(0, 0, NumDims); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar* data() const { + return NULL; + } + + protected: + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index srcCoeff(Index index) const + { + Index inputIndex = 0; + if (static_cast(Layout) == static_cast(ColMajor)) { + for (int i = NumDims - 1; i >= 0; --i) { + const Index idx = index / m_fastOutputStrides[i]; + inputIndex += idx * m_inputStrides[i] + m_offsets[i]; + index -= idx * m_outputStrides[i]; + } + } else { + for (int i = 0; i < NumDims; ++i) { + const Index idx = index / m_fastOutputStrides[i]; + inputIndex += idx * m_inputStrides[i] + m_offsets[i]; + index -= idx * m_outputStrides[i]; + } + } + return inputIndex; + } + + static EIGEN_STRONG_INLINE Index clamp(Index value, Index min, Index max) { + return numext::maxi(min, numext::mini(max,value)); + } + + array m_outputStrides; + array, NumDims> m_fastOutputStrides; + array m_inputStrides; + TensorEvaluator m_impl; + const Device& m_device; + DSizes m_startIndices; // clamped startIndices + DSizes m_dimensions; + DSizes m_offsets; // offset in a flattened shape + const Strides m_strides; + std::size_t m_block_total_size_max; +}; + +// Eval as lvalue +template +struct TensorEvaluator, Device> + : public TensorEvaluator, Device> +{ + typedef TensorEvaluator, Device> Base; + typedef TensorStridingSlicingOp XprType; + static const int NumDims = internal::array_size::value; + + enum { + IsAligned = false, + PacketAccess = false, + BlockAccess = false, + Layout = TensorEvaluator::Layout, + CoordAccess = TensorEvaluator::CoordAccess, + RawAccess = false + }; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorEvaluator(const XprType& op, const Device& device) + : Base(op, device) + { } + + typedef typename XprType::Index Index; + typedef typename XprType::Scalar Scalar; + typedef typename internal::remove_const::type ScalarNonConst; + typedef typename XprType::CoeffReturnType CoeffReturnType; + typedef typename PacketType::type PacketReturnType; + typedef Strides Dimensions; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType& coeffRef(Index index) + { + return this->m_impl.coeffRef(this->srcCoeff(index)); + } +}; + + +} // end namespace Eigen + +#endif // EIGEN_CXX11_TENSOR_TENSOR_MORPHING_H diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorPadding.h b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorPadding.h new file mode 100644 index 0000000000..647bcf1088 --- /dev/null +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorPadding.h @@ -0,0 +1,397 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Benoit Steiner +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CXX11_TENSOR_TENSOR_PADDING_H +#define EIGEN_CXX11_TENSOR_TENSOR_PADDING_H + +namespace Eigen { + +/** \class TensorPadding + * \ingroup CXX11_Tensor_Module + * + * \brief Tensor padding class. + * At the moment only padding with a constant value is supported. + * + */ +namespace internal { +template +struct traits > : public traits +{ + typedef typename XprType::Scalar Scalar; + typedef traits XprTraits; + typedef typename XprTraits::StorageKind StorageKind; + typedef typename XprTraits::Index Index; + typedef typename XprType::Nested Nested; + typedef typename remove_reference::type _Nested; + static const int NumDimensions = XprTraits::NumDimensions; + static const int Layout = XprTraits::Layout; +}; + +template +struct eval, Eigen::Dense> +{ + typedef const TensorPaddingOp& type; +}; + +template +struct nested, 1, typename eval >::type> +{ + typedef TensorPaddingOp type; +}; + +} // end namespace internal + + + +template +class TensorPaddingOp : public TensorBase, ReadOnlyAccessors> +{ + public: + typedef typename Eigen::internal::traits::Scalar Scalar; + typedef typename Eigen::NumTraits::Real RealScalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + typedef typename Eigen::internal::nested::type Nested; + typedef typename Eigen::internal::traits::StorageKind StorageKind; + typedef typename Eigen::internal::traits::Index Index; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorPaddingOp(const XprType& expr, const PaddingDimensions& padding_dims, const Scalar padding_value) + : m_xpr(expr), m_padding_dims(padding_dims), m_padding_value(padding_value) {} + + EIGEN_DEVICE_FUNC + const PaddingDimensions& padding() const { return m_padding_dims; } + EIGEN_DEVICE_FUNC + Scalar padding_value() const { return m_padding_value; } + + EIGEN_DEVICE_FUNC + const typename internal::remove_all::type& + expression() const { return m_xpr; } + + protected: + typename XprType::Nested m_xpr; + const PaddingDimensions m_padding_dims; + const Scalar m_padding_value; +}; + + +// Eval as rvalue +template +struct TensorEvaluator, Device> +{ + typedef TensorPaddingOp XprType; + typedef typename XprType::Index Index; + static const int NumDims = internal::array_size::value; + typedef DSizes Dimensions; + typedef typename XprType::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + typedef typename PacketType::type PacketReturnType; + static const int PacketSize = internal::unpacket_traits::size; + + enum { + IsAligned = true, + PacketAccess = TensorEvaluator::PacketAccess, + Layout = TensorEvaluator::Layout, + CoordAccess = true, + RawAccess = false + }; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorEvaluator(const XprType& op, const Device& device) + : m_impl(op.expression(), device), m_padding(op.padding()), m_paddingValue(op.padding_value()) + { + // The padding op doesn't change the rank of the tensor. Directly padding a scalar would lead + // to a vector, which doesn't make sense. Instead one should reshape the scalar into a vector + // of 1 element first and then pad. + EIGEN_STATIC_ASSERT((NumDims > 0), YOU_MADE_A_PROGRAMMING_MISTAKE); + + // Compute dimensions + m_dimensions = m_impl.dimensions(); + for (int i = 0; i < NumDims; ++i) { + m_dimensions[i] += m_padding[i].first + m_padding[i].second; + } + const typename TensorEvaluator::Dimensions& input_dims = m_impl.dimensions(); + if (static_cast(Layout) == static_cast(ColMajor)) { + m_inputStrides[0] = 1; + m_outputStrides[0] = 1; + for (int i = 1; i < NumDims; ++i) { + m_inputStrides[i] = m_inputStrides[i-1] * input_dims[i-1]; + m_outputStrides[i] = m_outputStrides[i-1] * m_dimensions[i-1]; + } + m_outputStrides[NumDims] = m_outputStrides[NumDims-1] * m_dimensions[NumDims-1]; + } else { + m_inputStrides[NumDims - 1] = 1; + m_outputStrides[NumDims] = 1; + for (int i = NumDims - 2; i >= 0; --i) { + m_inputStrides[i] = m_inputStrides[i+1] * input_dims[i+1]; + m_outputStrides[i+1] = m_outputStrides[i+2] * m_dimensions[i+1]; + } + m_outputStrides[0] = m_outputStrides[1] * m_dimensions[0]; + } + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Dimensions& dimensions() const { return m_dimensions; } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(Scalar*) { + m_impl.evalSubExprsIfNeeded(NULL); + return true; + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void cleanup() { + m_impl.cleanup(); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const + { + eigen_assert(index < dimensions().TotalSize()); + Index inputIndex = 0; + if (static_cast(Layout) == static_cast(ColMajor)) { + for (int i = NumDims - 1; i > 0; --i) { + const Index idx = index / m_outputStrides[i]; + if (isPaddingAtIndexForDim(idx, i)) { + return m_paddingValue; + } + inputIndex += (idx - m_padding[i].first) * m_inputStrides[i]; + index -= idx * m_outputStrides[i]; + } + if (isPaddingAtIndexForDim(index, 0)) { + return m_paddingValue; + } + inputIndex += (index - m_padding[0].first); + } else { + for (int i = 0; i < NumDims - 1; ++i) { + const Index idx = index / m_outputStrides[i+1]; + if (isPaddingAtIndexForDim(idx, i)) { + return m_paddingValue; + } + inputIndex += (idx - m_padding[i].first) * m_inputStrides[i]; + index -= idx * m_outputStrides[i+1]; + } + if (isPaddingAtIndexForDim(index, NumDims-1)) { + return m_paddingValue; + } + inputIndex += (index - m_padding[NumDims-1].first); + } + return m_impl.coeff(inputIndex); + } + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packet(Index index) const + { + if (static_cast(Layout) == static_cast(ColMajor)) { + return packetColMajor(index); + } + return packetRowMajor(index); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost costPerCoeff(bool vectorized) const { + TensorOpCost cost = m_impl.costPerCoeff(vectorized); + if (static_cast(Layout) == static_cast(ColMajor)) { + for (int i = 0; i < NumDims; ++i) + updateCostPerDimension(cost, i, i == 0); + } else { + for (int i = NumDims - 1; i >= 0; --i) + updateCostPerDimension(cost, i, i == NumDims - 1); + } + return cost; + } + + EIGEN_DEVICE_FUNC Scalar* data() const { return NULL; } + + private: + EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool isPaddingAtIndexForDim( + Index index, int dim_index) const { +#if defined(EIGEN_HAS_INDEX_LIST) + return (!internal::index_pair_first_statically_eq(dim_index, 0) && + index < m_padding[dim_index].first) || + (!internal::index_pair_second_statically_eq(dim_index, 0) && + index >= m_dimensions[dim_index] - m_padding[dim_index].second); +#else + return (index < m_padding[dim_index].first) || + (index >= m_dimensions[dim_index] - m_padding[dim_index].second); +#endif + } + + EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool isLeftPaddingCompileTimeZero( + int dim_index) const { +#if defined(EIGEN_HAS_INDEX_LIST) + return internal::index_pair_first_statically_eq(dim_index, 0); +#else + EIGEN_UNUSED_VARIABLE(dim_index); + return false; +#endif + } + + EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool isRightPaddingCompileTimeZero( + int dim_index) const { +#if defined(EIGEN_HAS_INDEX_LIST) + return internal::index_pair_second_statically_eq(dim_index, 0); +#else + EIGEN_UNUSED_VARIABLE(dim_index); + return false; +#endif + } + + + void updateCostPerDimension(TensorOpCost& cost, int i, bool first) const { + const double in = static_cast(m_impl.dimensions()[i]); + const double out = in + m_padding[i].first + m_padding[i].second; + if (out == 0) + return; + const double reduction = in / out; + cost *= reduction; + if (first) { + cost += TensorOpCost(0, 0, 2 * TensorOpCost::AddCost() + + reduction * (1 * TensorOpCost::AddCost())); + } else { + cost += TensorOpCost(0, 0, 2 * TensorOpCost::AddCost() + + 2 * TensorOpCost::MulCost() + + reduction * (2 * TensorOpCost::MulCost() + + 1 * TensorOpCost::DivCost())); + } + } + + protected: + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packetColMajor(Index index) const + { + EIGEN_STATIC_ASSERT((PacketSize > 1), YOU_MADE_A_PROGRAMMING_MISTAKE) + eigen_assert(index+PacketSize-1 < dimensions().TotalSize()); + + const Index initialIndex = index; + Index inputIndex = 0; + for (int i = NumDims - 1; i > 0; --i) { + const Index first = index; + const Index last = index + PacketSize - 1; + const Index lastPaddedLeft = m_padding[i].first * m_outputStrides[i]; + const Index firstPaddedRight = (m_dimensions[i] - m_padding[i].second) * m_outputStrides[i]; + const Index lastPaddedRight = m_outputStrides[i+1]; + + if (!isLeftPaddingCompileTimeZero(i) && last < lastPaddedLeft) { + // all the coefficient are in the padding zone. + return internal::pset1(m_paddingValue); + } + else if (!isRightPaddingCompileTimeZero(i) && first >= firstPaddedRight && last < lastPaddedRight) { + // all the coefficient are in the padding zone. + return internal::pset1(m_paddingValue); + } + else if ((isLeftPaddingCompileTimeZero(i) && isRightPaddingCompileTimeZero(i)) || (first >= lastPaddedLeft && last < firstPaddedRight)) { + // all the coefficient are between the 2 padding zones. + const Index idx = index / m_outputStrides[i]; + inputIndex += (idx - m_padding[i].first) * m_inputStrides[i]; + index -= idx * m_outputStrides[i]; + } + else { + // Every other case + return packetWithPossibleZero(initialIndex); + } + } + + const Index last = index + PacketSize - 1; + const Index first = index; + const Index lastPaddedLeft = m_padding[0].first; + const Index firstPaddedRight = (m_dimensions[0] - m_padding[0].second); + const Index lastPaddedRight = m_outputStrides[1]; + + if (!isLeftPaddingCompileTimeZero(0) && last < lastPaddedLeft) { + // all the coefficient are in the padding zone. + return internal::pset1(m_paddingValue); + } + else if (!isRightPaddingCompileTimeZero(0) && first >= firstPaddedRight && last < lastPaddedRight) { + // all the coefficient are in the padding zone. + return internal::pset1(m_paddingValue); + } + else if ((isLeftPaddingCompileTimeZero(0) && isRightPaddingCompileTimeZero(0)) || (first >= lastPaddedLeft && last < firstPaddedRight)) { + // all the coefficient are between the 2 padding zones. + inputIndex += (index - m_padding[0].first); + return m_impl.template packet(inputIndex); + } + // Every other case + return packetWithPossibleZero(initialIndex); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packetRowMajor(Index index) const + { + EIGEN_STATIC_ASSERT((PacketSize > 1), YOU_MADE_A_PROGRAMMING_MISTAKE) + eigen_assert(index+PacketSize-1 < dimensions().TotalSize()); + + const Index initialIndex = index; + Index inputIndex = 0; + + for (int i = 0; i < NumDims - 1; ++i) { + const Index first = index; + const Index last = index + PacketSize - 1; + const Index lastPaddedLeft = m_padding[i].first * m_outputStrides[i+1]; + const Index firstPaddedRight = (m_dimensions[i] - m_padding[i].second) * m_outputStrides[i+1]; + const Index lastPaddedRight = m_outputStrides[i]; + + if (!isLeftPaddingCompileTimeZero(i) && last < lastPaddedLeft) { + // all the coefficient are in the padding zone. + return internal::pset1(m_paddingValue); + } + else if (!isRightPaddingCompileTimeZero(i) && first >= firstPaddedRight && last < lastPaddedRight) { + // all the coefficient are in the padding zone. + return internal::pset1(m_paddingValue); + } + else if ((isLeftPaddingCompileTimeZero(i) && isRightPaddingCompileTimeZero(i)) || (first >= lastPaddedLeft && last < firstPaddedRight)) { + // all the coefficient are between the 2 padding zones. + const Index idx = index / m_outputStrides[i+1]; + inputIndex += (idx - m_padding[i].first) * m_inputStrides[i]; + index -= idx * m_outputStrides[i+1]; + } + else { + // Every other case + return packetWithPossibleZero(initialIndex); + } + } + + const Index last = index + PacketSize - 1; + const Index first = index; + const Index lastPaddedLeft = m_padding[NumDims-1].first; + const Index firstPaddedRight = (m_dimensions[NumDims-1] - m_padding[NumDims-1].second); + const Index lastPaddedRight = m_outputStrides[NumDims-1]; + + if (!isLeftPaddingCompileTimeZero(NumDims-1) && last < lastPaddedLeft) { + // all the coefficient are in the padding zone. + return internal::pset1(m_paddingValue); + } + else if (!isRightPaddingCompileTimeZero(NumDims-1) && first >= firstPaddedRight && last < lastPaddedRight) { + // all the coefficient are in the padding zone. + return internal::pset1(m_paddingValue); + } + else if ((isLeftPaddingCompileTimeZero(NumDims-1) && isRightPaddingCompileTimeZero(NumDims-1)) || (first >= lastPaddedLeft && last < firstPaddedRight)) { + // all the coefficient are between the 2 padding zones. + inputIndex += (index - m_padding[NumDims-1].first); + return m_impl.template packet(inputIndex); + } + // Every other case + return packetWithPossibleZero(initialIndex); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packetWithPossibleZero(Index index) const + { + EIGEN_ALIGN_MAX typename internal::remove_const::type values[PacketSize]; + for (int i = 0; i < PacketSize; ++i) { + values[i] = coeff(index+i); + } + PacketReturnType rslt = internal::pload(values); + return rslt; + } + + Dimensions m_dimensions; + array m_outputStrides; + array m_inputStrides; + TensorEvaluator m_impl; + PaddingDimensions m_padding; + + Scalar m_paddingValue; +}; + + + + +} // end namespace Eigen + +#endif // EIGEN_CXX11_TENSOR_TENSOR_PADDING_H diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorPatch.h b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorPatch.h new file mode 100644 index 0000000000..886a254f66 --- /dev/null +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorPatch.h @@ -0,0 +1,269 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Benoit Steiner +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CXX11_TENSOR_TENSOR_PATCH_H +#define EIGEN_CXX11_TENSOR_TENSOR_PATCH_H + +namespace Eigen { + +/** \class TensorPatch + * \ingroup CXX11_Tensor_Module + * + * \brief Tensor patch class. + * + * + */ +namespace internal { +template +struct traits > : public traits +{ + typedef typename XprType::Scalar Scalar; + typedef traits XprTraits; + typedef typename XprTraits::StorageKind StorageKind; + typedef typename XprTraits::Index Index; + typedef typename XprType::Nested Nested; + typedef typename remove_reference::type _Nested; + static const int NumDimensions = XprTraits::NumDimensions + 1; + static const int Layout = XprTraits::Layout; +}; + +template +struct eval, Eigen::Dense> +{ + typedef const TensorPatchOp& type; +}; + +template +struct nested, 1, typename eval >::type> +{ + typedef TensorPatchOp type; +}; + +} // end namespace internal + + + +template +class TensorPatchOp : public TensorBase, ReadOnlyAccessors> +{ + public: + typedef typename Eigen::internal::traits::Scalar Scalar; + typedef typename Eigen::NumTraits::Real RealScalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + typedef typename Eigen::internal::nested::type Nested; + typedef typename Eigen::internal::traits::StorageKind StorageKind; + typedef typename Eigen::internal::traits::Index Index; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorPatchOp(const XprType& expr, const PatchDim& patch_dims) + : m_xpr(expr), m_patch_dims(patch_dims) {} + + EIGEN_DEVICE_FUNC + const PatchDim& patch_dims() const { return m_patch_dims; } + + EIGEN_DEVICE_FUNC + const typename internal::remove_all::type& + expression() const { return m_xpr; } + + protected: + typename XprType::Nested m_xpr; + const PatchDim m_patch_dims; +}; + + +// Eval as rvalue +template +struct TensorEvaluator, Device> +{ + typedef TensorPatchOp XprType; + typedef typename XprType::Index Index; + static const int NumDims = internal::array_size::Dimensions>::value + 1; + typedef DSizes Dimensions; + typedef typename XprType::Scalar Scalar; + typedef typename XprType::CoeffReturnType CoeffReturnType; + typedef typename PacketType::type PacketReturnType; + static const int PacketSize = internal::unpacket_traits::size; + + + enum { + IsAligned = false, + PacketAccess = TensorEvaluator::PacketAccess, + Layout = TensorEvaluator::Layout, + CoordAccess = false, + RawAccess = false + }; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorEvaluator(const XprType& op, const Device& device) + : m_impl(op.expression(), device) + { + Index num_patches = 1; + const typename TensorEvaluator::Dimensions& input_dims = m_impl.dimensions(); + const PatchDim& patch_dims = op.patch_dims(); + if (static_cast(Layout) == static_cast(ColMajor)) { + for (int i = 0; i < NumDims-1; ++i) { + m_dimensions[i] = patch_dims[i]; + num_patches *= (input_dims[i] - patch_dims[i] + 1); + } + m_dimensions[NumDims-1] = num_patches; + + m_inputStrides[0] = 1; + m_patchStrides[0] = 1; + for (int i = 1; i < NumDims-1; ++i) { + m_inputStrides[i] = m_inputStrides[i-1] * input_dims[i-1]; + m_patchStrides[i] = m_patchStrides[i-1] * (input_dims[i-1] - patch_dims[i-1] + 1); + } + m_outputStrides[0] = 1; + for (int i = 1; i < NumDims; ++i) { + m_outputStrides[i] = m_outputStrides[i-1] * m_dimensions[i-1]; + } + } else { + for (int i = 0; i < NumDims-1; ++i) { + m_dimensions[i+1] = patch_dims[i]; + num_patches *= (input_dims[i] - patch_dims[i] + 1); + } + m_dimensions[0] = num_patches; + + m_inputStrides[NumDims-2] = 1; + m_patchStrides[NumDims-2] = 1; + for (int i = NumDims-3; i >= 0; --i) { + m_inputStrides[i] = m_inputStrides[i+1] * input_dims[i+1]; + m_patchStrides[i] = m_patchStrides[i+1] * (input_dims[i+1] - patch_dims[i+1] + 1); + } + m_outputStrides[NumDims-1] = 1; + for (int i = NumDims-2; i >= 0; --i) { + m_outputStrides[i] = m_outputStrides[i+1] * m_dimensions[i+1]; + } + } + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Dimensions& dimensions() const { return m_dimensions; } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(Scalar* /*data*/) { + m_impl.evalSubExprsIfNeeded(NULL); + return true; + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void cleanup() { + m_impl.cleanup(); + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const + { + Index output_stride_index = (static_cast(Layout) == static_cast(ColMajor)) ? NumDims - 1 : 0; + // Find the location of the first element of the patch. + Index patchIndex = index / m_outputStrides[output_stride_index]; + // Find the offset of the element wrt the location of the first element. + Index patchOffset = index - patchIndex * m_outputStrides[output_stride_index]; + Index inputIndex = 0; + if (static_cast(Layout) == static_cast(ColMajor)) { + for (int i = NumDims - 2; i > 0; --i) { + const Index patchIdx = patchIndex / m_patchStrides[i]; + patchIndex -= patchIdx * m_patchStrides[i]; + const Index offsetIdx = patchOffset / m_outputStrides[i]; + patchOffset -= offsetIdx * m_outputStrides[i]; + inputIndex += (patchIdx + offsetIdx) * m_inputStrides[i]; + } + } else { + for (int i = 0; i < NumDims - 2; ++i) { + const Index patchIdx = patchIndex / m_patchStrides[i]; + patchIndex -= patchIdx * m_patchStrides[i]; + const Index offsetIdx = patchOffset / m_outputStrides[i+1]; + patchOffset -= offsetIdx * m_outputStrides[i+1]; + inputIndex += (patchIdx + offsetIdx) * m_inputStrides[i]; + } + } + inputIndex += (patchIndex + patchOffset); + return m_impl.coeff(inputIndex); + } + + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packet(Index index) const + { + EIGEN_STATIC_ASSERT((PacketSize > 1), YOU_MADE_A_PROGRAMMING_MISTAKE) + eigen_assert(index+PacketSize-1 < dimensions().TotalSize()); + + Index output_stride_index = (static_cast(Layout) == static_cast(ColMajor)) ? NumDims - 1 : 0; + Index indices[2] = {index, index + PacketSize - 1}; + Index patchIndices[2] = {indices[0] / m_outputStrides[output_stride_index], + indices[1] / m_outputStrides[output_stride_index]}; + Index patchOffsets[2] = {indices[0] - patchIndices[0] * m_outputStrides[output_stride_index], + indices[1] - patchIndices[1] * m_outputStrides[output_stride_index]}; + + Index inputIndices[2] = {0, 0}; + if (static_cast(Layout) == static_cast(ColMajor)) { + for (int i = NumDims - 2; i > 0; --i) { + const Index patchIdx[2] = {patchIndices[0] / m_patchStrides[i], + patchIndices[1] / m_patchStrides[i]}; + patchIndices[0] -= patchIdx[0] * m_patchStrides[i]; + patchIndices[1] -= patchIdx[1] * m_patchStrides[i]; + + const Index offsetIdx[2] = {patchOffsets[0] / m_outputStrides[i], + patchOffsets[1] / m_outputStrides[i]}; + patchOffsets[0] -= offsetIdx[0] * m_outputStrides[i]; + patchOffsets[1] -= offsetIdx[1] * m_outputStrides[i]; + + inputIndices[0] += (patchIdx[0] + offsetIdx[0]) * m_inputStrides[i]; + inputIndices[1] += (patchIdx[1] + offsetIdx[1]) * m_inputStrides[i]; + } + } else { + for (int i = 0; i < NumDims - 2; ++i) { + const Index patchIdx[2] = {patchIndices[0] / m_patchStrides[i], + patchIndices[1] / m_patchStrides[i]}; + patchIndices[0] -= patchIdx[0] * m_patchStrides[i]; + patchIndices[1] -= patchIdx[1] * m_patchStrides[i]; + + const Index offsetIdx[2] = {patchOffsets[0] / m_outputStrides[i+1], + patchOffsets[1] / m_outputStrides[i+1]}; + patchOffsets[0] -= offsetIdx[0] * m_outputStrides[i+1]; + patchOffsets[1] -= offsetIdx[1] * m_outputStrides[i+1]; + + inputIndices[0] += (patchIdx[0] + offsetIdx[0]) * m_inputStrides[i]; + inputIndices[1] += (patchIdx[1] + offsetIdx[1]) * m_inputStrides[i]; + } + } + inputIndices[0] += (patchIndices[0] + patchOffsets[0]); + inputIndices[1] += (patchIndices[1] + patchOffsets[1]); + + if (inputIndices[1] - inputIndices[0] == PacketSize - 1) { + PacketReturnType rslt = m_impl.template packet(inputIndices[0]); + return rslt; + } + else { + EIGEN_ALIGN_MAX CoeffReturnType values[PacketSize]; + values[0] = m_impl.coeff(inputIndices[0]); + values[PacketSize-1] = m_impl.coeff(inputIndices[1]); + for (int i = 1; i < PacketSize-1; ++i) { + values[i] = coeff(index+i); + } + PacketReturnType rslt = internal::pload(values); + return rslt; + } + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost costPerCoeff(bool vectorized) const { + const double compute_cost = NumDims * (TensorOpCost::DivCost() + + TensorOpCost::MulCost() + + 2 * TensorOpCost::AddCost()); + return m_impl.costPerCoeff(vectorized) + + TensorOpCost(0, 0, compute_cost, vectorized, PacketSize); + } + + EIGEN_DEVICE_FUNC Scalar* data() const { return NULL; } + + protected: + Dimensions m_dimensions; + array m_outputStrides; + array m_inputStrides; + array m_patchStrides; + + TensorEvaluator m_impl; +}; + +} // end namespace Eigen + +#endif // EIGEN_CXX11_TENSOR_TENSOR_PATCH_H diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorRandom.h b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorRandom.h new file mode 100644 index 0000000000..1655a813e4 --- /dev/null +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorRandom.h @@ -0,0 +1,276 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2016 Benoit Steiner +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CXX11_TENSOR_TENSOR_RANDOM_H +#define EIGEN_CXX11_TENSOR_TENSOR_RANDOM_H + +namespace Eigen { +namespace internal { + +namespace { + +EIGEN_DEVICE_FUNC uint64_t get_random_seed() { +#ifdef __CUDA_ARCH__ + // We don't support 3d kernels since we currently only use 1 and + // 2d kernels. + assert(threadIdx.z == 0); + return clock64() + + blockIdx.x * blockDim.x + threadIdx.x + + gridDim.x * blockDim.x * (blockIdx.y * blockDim.y + threadIdx.y); + +#elif defined _WIN32 + // Use the current time as a baseline. + SYSTEMTIME st; + GetSystemTime(&st); + int time = st.wSecond + 1000 * st.wMilliseconds; + // Mix in a random number to make sure that we get different seeds if + // we try to generate seeds faster than the clock resolution. + // We need 2 random values since the generator only generate 16 bits at + // a time (https://msdn.microsoft.com/en-us/library/398ax69y.aspx) + int rnd1 = ::rand(); + int rnd2 = ::rand(); + uint64_t rnd = (rnd1 | rnd2 << 16) ^ time; + return rnd; + +#elif defined __APPLE__ + // Same approach as for win32, except that the random number generator + // is better (// https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man3/random.3.html#//apple_ref/doc/man/3/random). + uint64_t rnd = ::random() ^ mach_absolute_time(); + return rnd; + +#else + // Augment the current time with pseudo random number generation + // to ensure that we get different seeds if we try to generate seeds + // faster than the clock resolution. + timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + uint64_t rnd = ::random() ^ ts.tv_nsec; + return rnd; +#endif +} + +static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE unsigned PCG_XSH_RS_generator(uint64_t* state) { + // TODO: Unify with the implementation in the non blocking thread pool. + uint64_t current = *state; + // Update the internal state + *state = current * 6364136223846793005ULL + 0xda3e39cb94b95bdbULL; + // Generate the random output (using the PCG-XSH-RS scheme) + return static_cast((current ^ (current >> 22)) >> (22 + (current >> 61))); +} + +static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE uint64_t PCG_XSH_RS_state(uint64_t seed) { + seed = seed ? seed : get_random_seed(); + return seed * 6364136223846793005ULL + 0xda3e39cb94b95bdbULL; +} + +} // namespace + + +template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +T RandomToTypeUniform(uint64_t* state) { + unsigned rnd = PCG_XSH_RS_generator(state); + return static_cast(rnd); +} + + +template <> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +Eigen::half RandomToTypeUniform(uint64_t* state) { + Eigen::half result; + // Generate 10 random bits for the mantissa + unsigned rnd = PCG_XSH_RS_generator(state); + result.x = static_cast(rnd & 0x3ffu); + // Set the exponent + result.x |= (static_cast(15) << 10); + // Return the final result + return result - Eigen::half(1.0f); +} + + +template <> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +float RandomToTypeUniform(uint64_t* state) { + typedef union { + uint32_t raw; + float fp; + } internal; + internal result; + // Generate 23 random bits for the mantissa mantissa + const unsigned rnd = PCG_XSH_RS_generator(state); + result.raw = rnd & 0x7fffffu; + // Set the exponent + result.raw |= (static_cast(127) << 23); + // Return the final result + return result.fp - 1.0f; +} + +template <> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +double RandomToTypeUniform(uint64_t* state) { + typedef union { + uint64_t raw; + double dp; + } internal; + internal result; + result.raw = 0; + // Generate 52 random bits for the mantissa + // First generate the upper 20 bits + unsigned rnd1 = PCG_XSH_RS_generator(state) & 0xfffffu; + // The generate the lower 32 bits + unsigned rnd2 = PCG_XSH_RS_generator(state); + result.raw = (static_cast(rnd1) << 32) | rnd2; + // Set the exponent + result.raw |= (static_cast(1023) << 52); + // Return the final result + return result.dp - 1.0; +} + +template <> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +std::complex RandomToTypeUniform >(uint64_t* state) { + return std::complex(RandomToTypeUniform(state), + RandomToTypeUniform(state)); +} +template <> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +std::complex RandomToTypeUniform >(uint64_t* state) { + return std::complex(RandomToTypeUniform(state), + RandomToTypeUniform(state)); +} + +template class UniformRandomGenerator { + public: + static const bool PacketAccess = true; + + // Uses the given "seed" if non-zero, otherwise uses a random seed. + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE UniformRandomGenerator( + uint64_t seed = 0) { + m_state = PCG_XSH_RS_state(seed); + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE UniformRandomGenerator( + const UniformRandomGenerator& other) { + m_state = other.m_state; + } + + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + T operator()(Index i) const { + uint64_t local_state = m_state + i; + T result = RandomToTypeUniform(&local_state); + m_state = local_state; + return result; + } + + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Packet packetOp(Index i) const { + const int packetSize = internal::unpacket_traits::size; + EIGEN_ALIGN_MAX T values[packetSize]; + uint64_t local_state = m_state + i; + for (int j = 0; j < packetSize; ++j) { + values[j] = RandomToTypeUniform(&local_state); + } + m_state = local_state; + return internal::pload(values); + } + + private: + mutable uint64_t m_state; +}; + +template +struct functor_traits > { + enum { + // Rough estimate for floating point, multiplied by ceil(sizeof(T) / sizeof(float)). + Cost = 12 * NumTraits::AddCost * + ((sizeof(Scalar) + sizeof(float) - 1) / sizeof(float)), + PacketAccess = UniformRandomGenerator::PacketAccess + }; +}; + + + +template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +T RandomToTypeNormal(uint64_t* state) { + // Use the ratio of uniform method to generate numbers following a normal + // distribution. See for example Numerical Recipes chapter 7.3.9 for the + // details. + T u, v, q; + do { + u = RandomToTypeUniform(state); + v = T(1.7156) * (RandomToTypeUniform(state) - T(0.5)); + const T x = u - T(0.449871); + const T y = numext::abs(v) + T(0.386595); + q = x*x + y * (T(0.196)*y - T(0.25472)*x); + } while (q > T(0.27597) && + (q > T(0.27846) || v*v > T(-4) * numext::log(u) * u*u)); + + return v/u; +} + +template <> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +std::complex RandomToTypeNormal >(uint64_t* state) { + return std::complex(RandomToTypeNormal(state), + RandomToTypeNormal(state)); +} +template <> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE +std::complex RandomToTypeNormal >(uint64_t* state) { + return std::complex(RandomToTypeNormal(state), + RandomToTypeNormal(state)); +} + + +template class NormalRandomGenerator { + public: + static const bool PacketAccess = true; + + // Uses the given "seed" if non-zero, otherwise uses a random seed. + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE NormalRandomGenerator(uint64_t seed = 0) { + m_state = PCG_XSH_RS_state(seed); + } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE NormalRandomGenerator( + const NormalRandomGenerator& other) { + m_state = other.m_state; + } + + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + T operator()(Index i) const { + uint64_t local_state = m_state + i; + T result = RandomToTypeNormal(&local_state); + m_state = local_state; + return result; + } + + template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + Packet packetOp(Index i) const { + const int packetSize = internal::unpacket_traits::size; + EIGEN_ALIGN_MAX T values[packetSize]; + uint64_t local_state = m_state + i; + for (int j = 0; j < packetSize; ++j) { + values[j] = RandomToTypeNormal(&local_state); + } + m_state = local_state; + return internal::pload(values); + } + + private: + mutable uint64_t m_state; +}; + + +template +struct functor_traits > { + enum { + // On average, we need to generate about 3 random numbers + // 15 mul, 8 add, 1.5 logs + Cost = 3 * functor_traits >::Cost + + 15 * NumTraits::AddCost + 8 * NumTraits::AddCost + + 3 * functor_traits >::Cost / 2, + PacketAccess = NormalRandomGenerator::PacketAccess + }; +}; + + +} // end namespace internal +} // end namespace Eigen + +#endif // EIGEN_CXX11_TENSOR_TENSOR_RANDOM_H diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorReduction.h b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorReduction.h new file mode 100644 index 0000000000..41d0d0022f --- /dev/null +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorReduction.h @@ -0,0 +1,781 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Benoit Steiner +// Copyright (C) 2016 Mehdi Goli, Codeplay Software Ltd +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CXX11_TENSOR_TENSOR_REDUCTION_H +#define EIGEN_CXX11_TENSOR_TENSOR_REDUCTION_H + +namespace Eigen { + +/** \class TensorReduction + * \ingroup CXX11_Tensor_Module + * + * \brief Tensor reduction class. + * + */ + +namespace internal { + template class MakePointer_ > + struct traits > + : traits +{ + typedef traits XprTraits; + typedef typename XprTraits::Scalar Scalar; + typedef typename XprTraits::StorageKind StorageKind; + typedef typename XprTraits::Index Index; + typedef typename XprType::Nested Nested; + static const int NumDimensions = XprTraits::NumDimensions - array_size::value; + static const int Layout = XprTraits::Layout; + + template struct MakePointer { + // Intermediate typedef to workaround MSVC issue. + typedef MakePointer_ MakePointerT; + typedef typename MakePointerT::Type Type; + }; +}; + +template class MakePointer_> +struct eval, Eigen::Dense> +{ + typedef const TensorReductionOp& type; +}; + +template class MakePointer_> +struct nested, 1, typename eval >::type> +{ + typedef TensorReductionOp type; +}; + + +template struct DimInitializer { + template EIGEN_DEVICE_FUNC + static void run(const InputDims& input_dims, + const array::value>& reduced, + OutputDims* output_dims, ReducedDims* reduced_dims) { + const int NumInputDims = internal::array_size::value; + int outputIndex = 0; + int reduceIndex = 0; + for (int i = 0; i < NumInputDims; ++i) { + if (reduced[i]) { + (*reduced_dims)[reduceIndex] = input_dims[i]; + ++reduceIndex; + } else { + (*output_dims)[outputIndex] = input_dims[i]; + ++outputIndex; + } + } + } +}; + +template <> struct DimInitializer > { + template EIGEN_DEVICE_FUNC + static void run(const InputDims& input_dims, const array&, + Sizes<>*, array* reduced_dims) { + const int NumInputDims = internal::array_size::value; + for (int i = 0; i < NumInputDims; ++i) { + (*reduced_dims)[i] = input_dims[i]; + } + } +}; + + +template +struct are_inner_most_dims { + static const bool value = false; +}; +template +struct preserve_inner_most_dims { + static const bool value = false; +}; + +#if EIGEN_HAS_CONSTEXPR && EIGEN_HAS_VARIADIC_TEMPLATES +template +struct are_inner_most_dims{ + static const bool tmp1 = indices_statically_known_to_increase(); + static const bool tmp2 = index_statically_eq(0, 0); + static const bool tmp3 = index_statically_eq(array_size::value-1, array_size::value-1); + static const bool value = tmp1 & tmp2 & tmp3; +}; +template +struct are_inner_most_dims{ + static const bool tmp1 = indices_statically_known_to_increase(); + static const bool tmp2 = index_statically_eq(0, NumTensorDims - array_size::value); + static const bool tmp3 = index_statically_eq(array_size::value - 1, NumTensorDims - 1); + static const bool value = tmp1 & tmp2 & tmp3; + +}; +template +struct preserve_inner_most_dims{ + static const bool tmp1 = indices_statically_known_to_increase(); + static const bool tmp2 = index_statically_gt(0, 0); + static const bool value = tmp1 & tmp2; + +}; +template +struct preserve_inner_most_dims{ + static const bool tmp1 = indices_statically_known_to_increase(); + static const bool tmp2 = index_statically_lt(array_size::value - 1, NumTensorDims - 1); + static const bool value = tmp1 & tmp2; +}; +#endif + + +template +struct GenericDimReducer { + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reduce(const Self& self, typename Self::Index firstIndex, Op& reducer, typename Self::CoeffReturnType* accum) { + EIGEN_STATIC_ASSERT((DimIndex > 0), YOU_MADE_A_PROGRAMMING_MISTAKE); + for (int j = 0; j < self.m_reducedDims[DimIndex]; ++j) { + const typename Self::Index input = firstIndex + j * self.m_reducedStrides[DimIndex]; + GenericDimReducer::reduce(self, input, reducer, accum); + } + } +}; +template +struct GenericDimReducer<0, Self, Op> { + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reduce(const Self& self, typename Self::Index firstIndex, Op& reducer, typename Self::CoeffReturnType* accum) { + for (int j = 0; j < self.m_reducedDims[0]; ++j) { + const typename Self::Index input = firstIndex + j * self.m_reducedStrides[0]; + reducer.reduce(self.m_impl.coeff(input), accum); + } + } +}; +template +struct GenericDimReducer<-1, Self, Op> { + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reduce(const Self& self, typename Self::Index index, Op& reducer, typename Self::CoeffReturnType* accum) { + reducer.reduce(self.m_impl.coeff(index), accum); + } +}; + +template +struct InnerMostDimReducer { + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE typename Self::CoeffReturnType reduce(const Self& self, typename Self::Index firstIndex, typename Self::Index numValuesToReduce, Op& reducer) { + typename Self::CoeffReturnType accum = reducer.initialize(); + for (typename Self::Index j = 0; j < numValuesToReduce; ++j) { + reducer.reduce(self.m_impl.coeff(firstIndex + j), &accum); + } + return reducer.finalize(accum); + } +}; + +template +struct InnerMostDimReducer { + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE typename Self::CoeffReturnType reduce(const Self& self, typename Self::Index firstIndex, typename Self::Index numValuesToReduce, Op& reducer) { + const int packetSize = internal::unpacket_traits::size; + const typename Self::Index VectorizedSize = (numValuesToReduce / packetSize) * packetSize; + typename Self::PacketReturnType p = reducer.template initializePacket(); + for (typename Self::Index j = 0; j < VectorizedSize; j += packetSize) { + reducer.reducePacket(self.m_impl.template packet(firstIndex + j), &p); + } + typename Self::CoeffReturnType accum = reducer.initialize(); + for (typename Self::Index j = VectorizedSize; j < numValuesToReduce; ++j) { + reducer.reduce(self.m_impl.coeff(firstIndex + j), &accum); + } + return reducer.finalizeBoth(accum, p); + } +}; + +template +struct InnerMostDimPreserver { + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reduce(const Self&, typename Self::Index, Op&, typename Self::PacketReturnType*) { + eigen_assert(false && "should never be called"); + } +}; + +template +struct InnerMostDimPreserver { + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reduce(const Self& self, typename Self::Index firstIndex, Op& reducer, typename Self::PacketReturnType* accum) { + EIGEN_STATIC_ASSERT((DimIndex > 0), YOU_MADE_A_PROGRAMMING_MISTAKE); + for (typename Self::Index j = 0; j < self.m_reducedDims[DimIndex]; ++j) { + const typename Self::Index input = firstIndex + j * self.m_reducedStrides[DimIndex]; + InnerMostDimPreserver::reduce(self, input, reducer, accum); + } + } +}; + +template +struct InnerMostDimPreserver<0, Self, Op, true> { + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reduce(const Self& self, typename Self::Index firstIndex, Op& reducer, typename Self::PacketReturnType* accum) { + for (typename Self::Index j = 0; j < self.m_reducedDims[0]; ++j) { + const typename Self::Index input = firstIndex + j * self.m_reducedStrides[0]; + reducer.reducePacket(self.m_impl.template packet(input), accum); + } + } +}; +template +struct InnerMostDimPreserver<-1, Self, Op, true> { + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reduce(const Self&, typename Self::Index, Op&, typename Self::PacketReturnType*) { + eigen_assert(false && "should never be called"); + } +}; + +// Default full reducer +template +struct FullReducer { + static const bool HasOptimizedImplementation = false; + + static EIGEN_DEVICE_FUNC void run(const Self& self, Op& reducer, const Device&, typename Self::CoeffReturnType* output) { + const typename Self::Index num_coeffs = array_prod(self.m_impl.dimensions()); + *output = InnerMostDimReducer::reduce(self, 0, num_coeffs, reducer); + } +}; + + +#ifdef EIGEN_USE_THREADS +// Multithreaded full reducers +template +struct FullReducerShard { + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void run(const Self& self, typename Self::Index firstIndex, + typename Self::Index numValuesToReduce, Op& reducer, + typename Self::CoeffReturnType* output) { + *output = InnerMostDimReducer::reduce( + self, firstIndex, numValuesToReduce, reducer); + } +}; + +// Multithreaded full reducer +template +struct FullReducer { + static const bool HasOptimizedImplementation = !Op::IsStateful; + static const int PacketSize = + unpacket_traits::size; + + // launch one reducer per thread and accumulate the result. + static void run(const Self& self, Op& reducer, const ThreadPoolDevice& device, + typename Self::CoeffReturnType* output) { + typedef typename Self::Index Index; + const Index num_coeffs = array_prod(self.m_impl.dimensions()); + if (num_coeffs == 0) { + *output = reducer.finalize(reducer.initialize()); + return; + } + const TensorOpCost cost = + self.m_impl.costPerCoeff(Vectorizable) + + TensorOpCost(0, 0, internal::functor_traits::Cost, Vectorizable, + PacketSize); + const int num_threads = TensorCostModel::numThreads( + num_coeffs, cost, device.numThreads()); + if (num_threads == 1) { + *output = + InnerMostDimReducer::reduce(self, 0, num_coeffs, reducer); + return; + } + const Index blocksize = + std::floor(static_cast(num_coeffs) / num_threads); + const Index numblocks = blocksize > 0 ? num_coeffs / blocksize : 0; + eigen_assert(num_coeffs >= numblocks * blocksize); + + Barrier barrier(internal::convert_index(numblocks)); + MaxSizeVector shards(numblocks, reducer.initialize()); + for (Index i = 0; i < numblocks; ++i) { + device.enqueue_with_barrier(&barrier, &FullReducerShard::run, + self, i * blocksize, blocksize, reducer, + &shards[i]); + } + typename Self::CoeffReturnType finalShard; + if (numblocks * blocksize < num_coeffs) { + finalShard = InnerMostDimReducer::reduce( + self, numblocks * blocksize, num_coeffs - numblocks * blocksize, + reducer); + } else { + finalShard = reducer.initialize(); + } + barrier.Wait(); + + for (Index i = 0; i < numblocks; ++i) { + reducer.reduce(shards[i], &finalShard); + } + *output = reducer.finalize(finalShard); + } +}; + +#endif + + +// Default inner reducer +template +struct InnerReducer { + static const bool HasOptimizedImplementation = false; + + EIGEN_DEVICE_FUNC static bool run(const Self&, Op&, const Device&, typename Self::CoeffReturnType*, typename Self::Index, typename Self::Index) { + eigen_assert(false && "Not implemented"); + return true; + } +}; + +// Default outer reducer +template +struct OuterReducer { + static const bool HasOptimizedImplementation = false; + + EIGEN_DEVICE_FUNC static bool run(const Self&, Op&, const Device&, typename Self::CoeffReturnType*, typename Self::Index, typename Self::Index) { + eigen_assert(false && "Not implemented"); + return true; + } +}; + + +#if defined(EIGEN_USE_GPU) && defined(__CUDACC__) +template +__global__ void FullReductionKernel(R, const S, I, typename S::CoeffReturnType*, unsigned int*); + + +#ifdef EIGEN_HAS_CUDA_FP16 +template +__global__ void ReductionInitFullReduxKernelHalfFloat(R, const S, I, half2*); +template +__global__ void FullReductionKernelHalfFloat(R, const S, I, half*, half2*); +template +__global__ void InnerReductionKernelHalfFloat(R, const S, I, I, half*); + +#endif + +template +__global__ void InnerReductionKernel(R, const S, I, I, typename S::CoeffReturnType*); + +template +__global__ void OuterReductionKernel(R, const S, I, I, typename S::CoeffReturnType*); +#endif + +} // end namespace internal + + +template class MakePointer_> +class TensorReductionOp : public TensorBase, ReadOnlyAccessors> { + public: + typedef typename Eigen::internal::traits::Scalar Scalar; + typedef typename Eigen::NumTraits::Real RealScalar; + typedef typename internal::remove_const::type CoeffReturnType; + typedef typename Eigen::internal::nested::type Nested; + typedef typename Eigen::internal::traits::StorageKind StorageKind; + typedef typename Eigen::internal::traits::Index Index; + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + TensorReductionOp(const XprType& expr, const Dims& dims) : m_expr(expr), m_dims(dims) + { } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + TensorReductionOp(const XprType& expr, const Dims& dims, const Op& reducer) : m_expr(expr), m_dims(dims), m_reducer(reducer) + { } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const XprType& expression() const { return m_expr; } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const Dims& dims() const { return m_dims; } + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE + const Op& reducer() const { return m_reducer; } + + protected: + typename XprType::Nested m_expr; + const Dims m_dims; + const Op m_reducer; +}; + + +// Eval as rvalue +template class MakePointer_, typename Device> +struct TensorEvaluator, Device> +{ + typedef TensorReductionOp XprType; + typedef typename XprType::Index Index; + typedef ArgType ChildType; + typedef typename TensorEvaluator::Dimensions InputDimensions; + static const int NumInputDims = internal::array_size::value; + static const int NumReducedDims = internal::array_size::value; + static const int NumOutputDims = NumInputDims - NumReducedDims; + typedef typename internal::conditional, DSizes >::type Dimensions; + typedef typename XprType::Scalar Scalar; + typedef TensorEvaluator, Device> Self; + static const bool InputPacketAccess = TensorEvaluator::PacketAccess; + typedef typename internal::remove_const::type CoeffReturnType; + typedef typename PacketType::type PacketReturnType; + static const int PacketSize = internal::unpacket_traits::size; + + enum { + IsAligned = false, + PacketAccess = Self::InputPacketAccess && Op::PacketAccess, + Layout = TensorEvaluator::Layout, + CoordAccess = false, // to be implemented + RawAccess = false + }; + + static const bool ReducingInnerMostDims = internal::are_inner_most_dims::value; + static const bool PreservingInnerMostDims = internal::preserve_inner_most_dims::value; + static const bool RunningFullReduction = (NumOutputDims==0); + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorEvaluator(const XprType& op, const Device& device) + : m_impl(op.expression(), device), m_reducer(op.reducer()), m_result(NULL), m_device(device), m_xpr_dims(op.dims()) + { + EIGEN_STATIC_ASSERT((NumInputDims >= NumReducedDims), YOU_MADE_A_PROGRAMMING_MISTAKE); + EIGEN_STATIC_ASSERT((!ReducingInnerMostDims | !PreservingInnerMostDims | (NumReducedDims == NumInputDims)), + YOU_MADE_A_PROGRAMMING_MISTAKE); + + // Build the bitmap indicating if an input dimension is reduced or not. + for (int i = 0; i < NumInputDims; ++i) { + m_reduced[i] = false; + } + for (int i = 0; i < NumReducedDims; ++i) { + eigen_assert(op.dims()[i] >= 0); + eigen_assert(op.dims()[i] < NumInputDims); + m_reduced[op.dims()[i]] = true; + } + + const typename TensorEvaluator::Dimensions& input_dims = m_impl.dimensions(); + internal::DimInitializer::run(input_dims, m_reduced, &m_dimensions, &m_reducedDims); + + // Precompute output strides. + if (NumOutputDims > 0) { + if (static_cast(Layout) == static_cast(ColMajor)) { + m_outputStrides[0] = 1; + for (int i = 1; i < NumOutputDims; ++i) { + m_outputStrides[i] = m_outputStrides[i - 1] * m_dimensions[i - 1]; + } + } else { + m_outputStrides.back() = 1; + for (int i = NumOutputDims - 2; i >= 0; --i) { + m_outputStrides[i] = m_outputStrides[i + 1] * m_dimensions[i + 1]; + } + } + } + + // Precompute input strides. + if (NumInputDims > 0) { + array input_strides; + if (static_cast(Layout) == static_cast(ColMajor)) { + input_strides[0] = 1; + for (int i = 1; i < NumInputDims; ++i) { + input_strides[i] = input_strides[i-1] * input_dims[i-1]; + } + } else { + input_strides.back() = 1; + for (int i = NumInputDims - 2; i >= 0; --i) { + input_strides[i] = input_strides[i + 1] * input_dims[i + 1]; + } + } + + int outputIndex = 0; + int reduceIndex = 0; + for (int i = 0; i < NumInputDims; ++i) { + if (m_reduced[i]) { + m_reducedStrides[reduceIndex] = input_strides[i]; + ++reduceIndex; + } else { + m_preservedStrides[outputIndex] = input_strides[i]; + ++outputIndex; + } + } + } + + // Special case for full reductions + if (NumOutputDims == 0) { + m_preservedStrides[0] = internal::array_prod(input_dims); + } + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Dimensions& dimensions() const { return m_dimensions; } + + EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC bool evalSubExprsIfNeeded(typename MakePointer_::Type data) { + m_impl.evalSubExprsIfNeeded(NULL); + + // Use the FullReducer if possible. + if ((RunningFullReduction && RunningOnSycl) ||(RunningFullReduction && + internal::FullReducer::HasOptimizedImplementation && + ((RunningOnGPU && (m_device.majorDeviceVersion() >= 3)) || + !RunningOnGPU))) { + bool need_assign = false; + if (!data) { + m_result = static_cast(m_device.allocate(sizeof(CoeffReturnType))); + data = m_result; + need_assign = true; + } + Op reducer(m_reducer); + internal::FullReducer::run(*this, reducer, m_device, data); + return need_assign; + } + else if(RunningOnSycl){ + const Index num_values_to_reduce = internal::array_prod(m_reducedDims); + const Index num_coeffs_to_preserve = internal::array_prod(m_dimensions); + if (!data) { + data = static_cast(m_device.allocate(sizeof(CoeffReturnType) * num_coeffs_to_preserve)); + m_result = data; + } + Op reducer(m_reducer); + internal::InnerReducer::run(*this, reducer, m_device, data, num_values_to_reduce, num_coeffs_to_preserve); + return (m_result != NULL); + } + + // Attempt to use an optimized reduction. + else if (RunningOnGPU && (m_device.majorDeviceVersion() >= 3)) { + bool reducing_inner_dims = true; + for (int i = 0; i < NumReducedDims; ++i) { + if (static_cast(Layout) == static_cast(ColMajor)) { + reducing_inner_dims &= m_reduced[i]; + } else { + reducing_inner_dims &= m_reduced[NumInputDims - 1 - i]; + } + } + if (internal::InnerReducer::HasOptimizedImplementation && + (reducing_inner_dims || ReducingInnerMostDims)) { + const Index num_values_to_reduce = internal::array_prod(m_reducedDims); + const Index num_coeffs_to_preserve = internal::array_prod(m_dimensions); + if (!data) { + if (num_coeffs_to_preserve < 1024 && num_values_to_reduce > num_coeffs_to_preserve && num_values_to_reduce > 128) { + data = static_cast(m_device.allocate(sizeof(CoeffReturnType) * num_coeffs_to_preserve)); + m_result = data; + } + else { + return true; + } + } + Op reducer(m_reducer); + if (internal::InnerReducer::run(*this, reducer, m_device, data, num_values_to_reduce, num_coeffs_to_preserve)) { + if (m_result) { + m_device.deallocate(m_result); + m_result = NULL; + } + return true; + } else { + return (m_result != NULL); + } + } + + bool preserving_inner_dims = true; + for (int i = 0; i < NumReducedDims; ++i) { + if (static_cast(Layout) == static_cast(ColMajor)) { + preserving_inner_dims &= m_reduced[NumInputDims - 1 - i]; + } else { + preserving_inner_dims &= m_reduced[i]; + } + } + if (internal::OuterReducer::HasOptimizedImplementation && + preserving_inner_dims) { + const Index num_values_to_reduce = internal::array_prod(m_reducedDims); + const Index num_coeffs_to_preserve = internal::array_prod(m_dimensions); + if (!data) { + if (num_coeffs_to_preserve < 1024 && num_values_to_reduce > num_coeffs_to_preserve && num_values_to_reduce > 32) { + data = static_cast(m_device.allocate(sizeof(CoeffReturnType) * num_coeffs_to_preserve)); + m_result = data; + } + else { + return true; + } + } + Op reducer(m_reducer); + if (internal::OuterReducer::run(*this, reducer, m_device, data, num_values_to_reduce, num_coeffs_to_preserve)) { + if (m_result) { + m_device.deallocate(m_result); + m_result = NULL; + } + return true; + } else { + return (m_result != NULL); + } + } + } + return true; + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void cleanup() { + m_impl.cleanup(); + if (m_result) { + m_device.deallocate(m_result); + m_result = NULL; + } + } + + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const + { + if ((RunningOnSycl || RunningFullReduction || RunningOnGPU) && m_result) { + return *(m_result + index); + } + Op reducer(m_reducer); + if (ReducingInnerMostDims || RunningFullReduction) { + const Index num_values_to_reduce = + (static_cast(Layout) == static_cast(ColMajor)) ? m_preservedStrides[0] : m_preservedStrides[NumPreservedStrides - 1]; + return internal::InnerMostDimReducer::reduce(*this, firstInput(index), + num_values_to_reduce, reducer); + } else { + typename Self::CoeffReturnType accum = reducer.initialize(); + internal::GenericDimReducer::reduce(*this, firstInput(index), reducer, &accum); + return reducer.finalize(accum); + } + } + + // TODO(bsteiner): provide a more efficient implementation. + template + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packet(Index index) const + { + EIGEN_STATIC_ASSERT((PacketSize > 1), YOU_MADE_A_PROGRAMMING_MISTAKE) + eigen_assert(index + PacketSize - 1 < Index(internal::array_prod(dimensions()))); + + if (RunningOnGPU && m_result) { + return internal::pload(m_result + index); + } + + EIGEN_ALIGN_MAX typename internal::remove_const::type values[PacketSize]; + if (ReducingInnerMostDims) { + const Index num_values_to_reduce = + (static_cast(Layout) == static_cast(ColMajor)) ? m_preservedStrides[0] : m_preservedStrides[NumPreservedStrides - 1]; + const Index firstIndex = firstInput(index); + for (Index i = 0; i < PacketSize; ++i) { + Op reducer(m_reducer); + values[i] = internal::InnerMostDimReducer::reduce(*this, firstIndex + i * num_values_to_reduce, + num_values_to_reduce, reducer); + } + } else if (PreservingInnerMostDims) { + const Index firstIndex = firstInput(index); + const int innermost_dim = (static_cast(Layout) == static_cast(ColMajor)) ? 0 : NumOutputDims - 1; + // TBD: extend this the the n innermost dimensions that we preserve. + if (((firstIndex % m_dimensions[innermost_dim]) + PacketSize - 1) < m_dimensions[innermost_dim]) { + Op reducer(m_reducer); + typename Self::PacketReturnType accum = reducer.template initializePacket(); + internal::InnerMostDimPreserver::reduce(*this, firstIndex, reducer, &accum); + return reducer.finalizePacket(accum); + } else { + for (int i = 0; i < PacketSize; ++i) { + values[i] = coeff(index + i); + } + } + } else { + for (int i = 0; i < PacketSize; ++i) { + values[i] = coeff(index + i); + } + } + PacketReturnType rslt = internal::pload(values); + return rslt; + } + + // Must be called after evalSubExprsIfNeeded(). + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost costPerCoeff(bool vectorized) const { + if (RunningFullReduction && m_result) { + return TensorOpCost(sizeof(CoeffReturnType), 0, 0, vectorized, PacketSize); + } else { + const Index num_values_to_reduce = internal::array_prod(m_reducedDims); + const double compute_cost = num_values_to_reduce * internal::functor_traits::Cost; + return m_impl.costPerCoeff(vectorized) * num_values_to_reduce + + TensorOpCost(0, 0, compute_cost, vectorized, PacketSize); + } + } + + EIGEN_DEVICE_FUNC typename MakePointer_::Type data() const { return m_result; } + /// required by sycl in order to extract the accessor + const TensorEvaluator& impl() const { return m_impl; } + /// added for sycl in order to construct the buffer from the sycl device + const Device& device() const{return m_device;} + /// added for sycl in order to re-construct the reduction eval on the device for the sub-kernel + const Dims& xprDims() const {return m_xpr_dims;} + + + private: + template friend struct internal::GenericDimReducer; + template friend struct internal::InnerMostDimReducer; + template friend struct internal::InnerMostDimPreserver; + template friend struct internal::FullReducer; +#ifdef EIGEN_USE_THREADS + template friend struct internal::FullReducerShard; +#endif +#if defined(EIGEN_USE_GPU) && defined(__CUDACC__) + template friend void internal::FullReductionKernel(R, const S, I, typename S::CoeffReturnType*, unsigned int*); +#ifdef EIGEN_HAS_CUDA_FP16 + template friend void internal::ReductionInitFullReduxKernelHalfFloat(R, const S, I, half2*); + template friend void internal::FullReductionKernelHalfFloat(R, const S, I, half*, half2*); + template friend void internal::InnerReductionKernelHalfFloat(R, const S, I, I, half*); +#endif + template friend void internal::InnerReductionKernel(R, const S, I, I, typename S::CoeffReturnType*); + + template friend void internal::OuterReductionKernel(R, const S, I, I, typename S::CoeffReturnType*); +#endif + + template friend struct internal::InnerReducer; + + // Returns the Index in the input tensor of the first value that needs to be + // used to compute the reduction at output index "index". + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index firstInput(Index index) const { + if (ReducingInnerMostDims) { + if (static_cast(Layout) == static_cast(ColMajor)) { + return index * m_preservedStrides[0]; + } else { + return index * m_preservedStrides[NumPreservedStrides - 1]; + } + } + // TBD: optimize the case where we preserve the innermost dimensions. + Index startInput = 0; + if (static_cast(Layout) == static_cast(ColMajor)) { + for (int i = NumOutputDims - 1; i > 0; --i) { + // This is index_i in the output tensor. + const Index idx = index / m_outputStrides[i]; + startInput += idx * m_preservedStrides[i]; + index -= idx * m_outputStrides[i]; + } + if (PreservingInnerMostDims) { + eigen_assert(m_preservedStrides[0] == 1); + startInput += index; + } else { + startInput += index * m_preservedStrides[0]; + } + } else { + for (int i = 0; i < NumOutputDims - 1; ++i) { + // This is index_i in the output tensor. + const Index idx = index / m_outputStrides[i]; + startInput += idx * m_preservedStrides[i]; + index -= idx * m_outputStrides[i]; + } + if (PreservingInnerMostDims) { + eigen_assert(m_preservedStrides[NumPreservedStrides - 1] == 1); + startInput += index; + } else { + startInput += index * m_preservedStrides[NumPreservedStrides - 1]; + } + } + return startInput; + } + + // Bitmap indicating if an input dimension is reduced or not. + array m_reduced; + // Dimensions of the output of the operation. + Dimensions m_dimensions; + // Precomputed strides for the output tensor. + array m_outputStrides; + // Subset of strides of the input tensor for the non-reduced dimensions. + // Indexed by output dimensions. + static const int NumPreservedStrides = max_n_1::size; + array m_preservedStrides; + + // Subset of strides of the input tensor for the reduced dimensions. + // Indexed by reduced dimensions. + array m_reducedStrides; + // Size of the input dimensions that are reduced. + // Indexed by reduced dimensions. + array m_reducedDims; + + // Evaluator for the input expression. + TensorEvaluator m_impl; + + // Operation to apply for computing the reduction. + Op m_reducer; + + // For full reductions +#if defined(EIGEN_USE_GPU) && defined(__CUDACC__) + static const bool RunningOnGPU = internal::is_same::value; + static const bool RunningOnSycl = false; +#elif defined(EIGEN_USE_SYCL) +static const bool RunningOnSycl = internal::is_same::type, Eigen::SyclDevice>::value; +static const bool RunningOnGPU = false; +#else + static const bool RunningOnGPU = false; + static const bool RunningOnSycl = false; +#endif + typename MakePointer_::Type m_result; + + const Device& m_device; + const Dims& m_xpr_dims; +}; + +} // end namespace Eigen + +#endif // EIGEN_CXX11_TENSOR_TENSOR_REDUCTION_H diff --git a/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorReductionCuda.h b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorReductionCuda.h new file mode 100644 index 0000000000..65638b6a84 --- /dev/null +++ b/ground/gcs/src/libs/eigen/unsupported/Eigen/CXX11/src/Tensor/TensorReductionCuda.h @@ -0,0 +1,750 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2014 Benoit Steiner +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CXX11_TENSOR_TENSOR_REDUCTION_CUDA_H +#define EIGEN_CXX11_TENSOR_TENSOR_REDUCTION_CUDA_H + +namespace Eigen { +namespace internal { + + +#if defined(EIGEN_USE_GPU) && defined(__CUDACC__) +// Full reducers for GPU, don't vectorize for now + +// Reducer function that enables multiple cuda thread to safely accumulate at the same +// output address. It basically reads the current value of the output variable, and +// attempts to update it with the new value. If in the meantime another cuda thread +// updated the content of the output address it will try again. +template +__device__ EIGEN_ALWAYS_INLINE void atomicReduce(T* output, T accum, R& reducer) { +#if __CUDA_ARCH__ >= 300 + if (sizeof(T) == 4) + { + unsigned int oldval = *reinterpret_cast(output); + unsigned int newval = oldval; + reducer.reduce(accum, reinterpret_cast(&newval)); + if (newval == oldval) { + return; + } + unsigned int readback; + while ((readback = atomicCAS((unsigned int*)output, oldval, newval)) != oldval) { + oldval = readback; + newval = oldval; + reducer.reduce(accum, reinterpret_cast(&newval)); + if (newval == oldval) { + return; + } + } + } + else if (sizeof(T) == 8) { + unsigned long long oldval = *reinterpret_cast(output); + unsigned long long newval = oldval; + reducer.reduce(accum, reinterpret_cast(&newval)); + if (newval == oldval) { + return; + } + unsigned long long readback; + while ((readback = atomicCAS((unsigned long long*)output, oldval, newval)) != oldval) { + oldval = readback; + newval = oldval; + reducer.reduce(accum, reinterpret_cast(&newval)); + if (newval == oldval) { + return; + } + } + } + else { + assert(0 && "Wordsize not supported"); + } +#else + assert(0 && "Shouldn't be called on unsupported device"); +#endif +} + +// We extend atomicExch to support extra data types +template +__device__ inline Type atomicExchCustom(Type* address, Type val) { + return atomicExch(address, val); +} + +template <> +__device__ inline double atomicExchCustom(double* address, double val) { + unsigned long long int* address_as_ull = reinterpret_cast(address); + return __longlong_as_double(atomicExch(address_as_ull, __double_as_longlong(val))); +} + +#ifdef EIGEN_HAS_CUDA_FP16 +template

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 z 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 z V+wiB#)gRopo-ZP0E5zpy~_xMJQx)*qAV+g@G7BrLhk$>1=2>FbJtmZ~Q)%DSp zrail{C%$9$k)1oXnd?gKLhryK2Du{8KcX{ChWKbCR9}p_Di2oj4Vx^ z(Ay@;18m%RLhsNYnI!E(9!zL#Nbk}(zyqB3DG8&v;}E(EtE$w5xcWcb+%n;~k7y*C zrFYoBr>}7#2&+CZ+wCI55C#yKW0aD-s#@S2;c}1HCot@*7LGi~pnON4l-z9eZC&XTg>>2) z0~|V#p*24A5W_J?oT`X-&5A)h(Hj!j5r5cNG9#IMHG{*6@Iw7ZUto-Nr<^GsjDeA` zD`avXY`>nU?eqsYDV&>*tt2^5RdTtH)d7x=v=un$A0gOq0>McK4{l;LQ_t00+K+e_ zB_=hbuZb3dCu|(g zxXMXii7!;Pa4IW2Aq+`mL5LB?C5CxID=;Y%aqs3J_AYruwPM1>OxkgS$uNwYtail< z8PDsK`V9}yNG#=(JZ#>G$8NpRm1?AV3I|J)cgF%uU$7slTnu%Tv51OqFexFJt83i& zj0ZUz`?11;us%s4Q7lGC4>o`w*?O*I6%|WA17F4<8z|z?v|6c%|BUV2%8K$8t>5if zBBOWp&2FP+kDTAOSND3>AJhd4jI(2v)3a1HgR7rx>|6il=+afHE`&^#@S&uV8`diqKs?{vo} zKcHcP$x6QHZO*97LQJ$>bdA;X1?hij!Li$D*yhTr(+j-AJHvq`N?Fx^Aby~_N=Jt- zP%n(0gef86Dcx+f9A4n?&f10@5@thbB^QJyYD!08Oc4isBt2K8$)XvxC7TmG2vO0p znFij@`kIaVI6w*i3nlBcbzkkMcbirOHYy7mSxn6A=dQ2Wi#5SpGzom-nH%aEh$M)K zPJNsKK-JCfaZ`CP-Uq8?_>p1x-0zWinX+`#d4F&k^OVO{>=i)~MfAKj>L5V||U&zklnp04bQ_GzH+oY5}6KK03Uu^DmDl ziR;t%bbep^mgn9nVLtAKY5BgFd+MFA54iJzFHxBCcKgXPw9FSB@^*YvUa|91?#hW*QW;fn4I6ZfdjvQ`{|KYj#eocP7^c>2d14?g>Dr+4}e*R)CXp|5Ea zRTp5-Mfa?-Xi3;$Sx(X-la5tlE&EFAqW$3JT`NlvyWNS{XOD~4?YHgWf|yS_Z{PQc zPl@3t?Q_5RtG2Uw*1q!GZ(E7oUPm!o-`cR51jc92UGd#iHw$GElZ?Hvd&>$dYsP-_ z7tfxzZ4qxa1!;=OU#hJ71{1Z0n4kn6b{ocnw<3bS*EqD@X45Y0>{#va(23QRD-Vk~ z_k(4EB2aS?dps}Z>A2-HSXoOz;AcuqmkzW|Se;w4U)! zpu9{iBPLcVm0buVo)m(N_?#W}QWCmHLdv1l+XH8ScnaX{#QVhDat|1l#}XL6iDwA7 zPanio_KaBB5+c$Fvl7_YJYpnl?llR1Dph#^IqYp3#@kz@|rdAEQ2{r4(V% z&PuRBL6WE>7)Zb+p1Fj+6_z%kV5vOtT0BY0CSf|}Rv+mdjlp7~t9s3>GtCJd5_Yc8 zwQ8zu1GSBqye~J()|%w)TDxEegP1+!aWC;8L(oR>oVcMGWBcB4Mc+i|oeMr0k7d1@ z$NNRt7a2*ARv$=E%q0Z30Xvlo-V#s-YTIECsblDBb24UFuf{4*kcY7!)!J&VzIMKHKQX21qXv3GYNo4bVu}HE3dZcCd(s< zwU`(F@3(5!Q$9B9s$@{O1`_9P2rr(rpQhYunqR(;ENNzVc@5iAN6YiLHvoCU`bUK@{)0S3k0AwYvRU^I7reRiUK_5i_!Lh*?7P2Ev6hqI)Xm zcVB;A41e#Cz8P%7SKtRyU=I6PyWLx{*V||9waz(vwSC_14l3e@k`t*P9yVd}^7O}L zS=y8oUmHj^pe<&d8KJu}_P)}AMI|E~50avRbB|AoOff(g7M;V$vNv3{AHHzc#&}BM zJtnG}z(_B?$;uukyW!onNy%PmY`YS9GRCPFd|y29CoaF~hFgrqhr=vgx2z{8B)`xl z?=2sS_Fiw7^)1N~aaJL*DX=7OJthZo0e$wVvsW!0?fbo{`cALu8AfWtaY^|TUB?T| zW4KBt!8m=X)Uq?VwhiZ5$thFkK^QN22QOPTboN-n@Da%!@MDZy<7)@cg7D$|kg0 z@-RKaz>D0-b7DUel7iUSw4Ei#c!~mCx(1IsHrQju5%LQ%O+E=94MLn?z$Zrb0{jsC zrc=RI`S?SB0WmjJApb03$2SQF0!-1D7>0ZhFGWIR;pvP44sTNo-uF6b-!CGMypWHp zE@SU=4A}{dmDpn9lK}Lahp$WUO_gN{ODx8YY3>QDv0lz0ug_d8qTew%(_BJR(6>d& z<*YF9a1d$>?OC|z=*01ZxZm_8ead_Eb5!+ZV=){$FgEkO$qWNOZ4A7{@oAi}3PAa@ z9-lpC=Ly4ArA!0U|CDg{Gjah9WI)NOIH~nA&T<9nD zfI23Kg)3N!R<+ev7*~Us>8h*xSXA2k+VNL?h>S*^FlP6pCwbg()tC2}G@xJmV~w3e zQuwX@p&zB!uzF@C&B_p!EBwVU%w~)6WLABv_a*Z$B1!8EbWi+-5FkUTQ?ppgs=`6! z%j1sZN!1gmvEd&REF*mr!!Q#|j3pcy*tv)BZNR8R=#LToLZ}eolfyMCTws$&_Cy)m zbB9$sUm3eWH!l3EH@lWdCvBp7M>IyEJ;6Akr!cr@1XIxl^g4aULqv?G8Z$ZRgL+Tn zj6I~Lq8;qzWAmQADH^NBU*6oX8^=eEGiNGmzA@ef-D875i0|3eHOs}5uJe|q=N3wN z-?J)LD60Rbwp~g4YS@F`NVtyoXx91~kg=3xXu-DCta;xunQ`^zk$VHjFaiq$%elPm z)efyKoY+|@TQy&_`Jiien?p-!d{>Kv&k!CJOSYqWG#X8-5Bs*Zva0?|ss7M7(Ov1_ z#e7AeR8I(p7>77~P1RwQVp013Pl{YzNBz94<+=XzgO&w} zyeN!%la`M-N9 zW>5dbauY(*>CWT#V8tFxVZQKpI)&HoP=)}ZzBy^;>9Zhl9n`~(zTfaXER*Bu?~-r% zjQ36+al*Bpd$G$0C)fJpx55{e`AHPVW4*IPk&|aP1|9oCqm!0bET=>Y?o}3 z$XU00+ZMy2Gq_AP@670^E(HwXBU`pdH&-nw!Q!abvMbq&U9Ih_`DxqEWNoXuVs~%d zu*WxceAA2@H*Sg{Z%UyZ+B6xnLkSO8w%64U?7%* zU`h#<+ZKaFNb8FsVJJgD!4sIgC|d|d2s$jmWCKN>uZX!rmP?tyv(&?O=zGNO%S(!( z+?e2Yz%B|XqY{$q2S);vl%aS|Wpsp>s*Bp`o480Ig3$X03uC^Ghc$v%#CKwbDdORb zqKkKR)`iZvz1A$**N@BAmQcQy9Z2Y81`)4}ncy#2C=bdPF~Aa1z$z(1c1T#1P>sRz zGxwyVx7VyCK{pj&*!QgON!Uerj_RI{QeqMIViNA(YUS*GtHh^c{3d*6xjr!8FlI9^ z_zOQKlb*(L$(0Jsrg431puw-M_xfk0D6k87Au(|yIZNFbgLrzOj4ZQr|vusL_UtYp~e z5k-IGp*OBIhCb^|yuJ2R!af4GaFG=NMd3EF{eTlYWgiJYh&R38M}fll5cTqa3 z9Oyes?iRvDls>%07;`y|m$?MyLBDHJ;rhKs&5k69Qoo6WzTHt;Bz{<}`RtU@$?P@dmT;(1cs{*%i$gk4knU$35(0&Vuk zFYSqcENmqkweR2RSY}MzMUBz16oPic?zLLhOJ0(qzOWyEXwUwGE4S^*wIln1?d$g8 zjobFYja~cx&8xPPZ`&)iZJ{m%?srP3>vg)p%evq9T!0Ntzbn}kA&^V`OOsK{56W^Y&NtoGI>d5eNi!LUjb%G#9 zOUVh75j*d*UqwS@iC&9VW7u@QF1iT+gwqFK#zQe;FV)WJ+k%tBN>3!8oL3$G8%gjUMH_7$Ns)o3jotH+Z(wwC8C~te@Qa}p*$hJ!#V^;~GX{Pn-*;7${xN(r+pr$A)gy5s&PSV2zPauj@X1T?y|*|A!$+ z*R)4-C(_Ywi&Zym?I9z!l*bHOGMM zkX9bNK8Le}+Le*)J##}_MDnE@@?oZWH`J2?BbjbVK1JqbQ#ZWZa8|%uo$y$?EjcZr z_f>Z{$O-;}rF%K+ocHv$wfht0jYwXdx$NeS4}vX|{$5YjckG_Drt*;?#m_TLU?;56 zCA3`-@0M7&hz>Yku-{AI6d-v;I8R;h3TE;e?_=nQ%L3|$tons9hbJjsrtaOV4i1g> zYL-&e`-}XYaoXdhgDW5eoA-+i--q8}mT~Hy$E&2qWk9b1^Q{-|&Vjz=)dl;q( zkrPbHsBLcSCC+lv*bJRjW+Tx7Vi5+f8Rfn@iVQDd}8# zT|(_{z{qF|tH2X{-`oop4CVtH6a#Vl@U;&PcH0eLRYh zaoI>4eT&tDt!_tICbrkF+D<75TLn$*_WQP0sambuvek0Mo|L{jm0Y}5Dr)ddEepie zu95C_C4ZMzD(*;i^~Nnbv$|$+wfDmIwr_5~7)yx~Ek3ti@o!b~Njp<2*vlYw+V(NpO1hQ3>?H@$y1i#h9Qyka=Uz ztfaHP&k-0*sF>RaEn6$5Eh|_~38MmD3cw!jNY~9_#MVn$Ye_$+P144UeVqvDaa^kh z{eVGO-`hVtwxedtHa9nfqZ(VnlNG^-@kCtZ<5p8Nbt<`{DG$w=(HNhKAH_tRnAmG~+a3=Zye<_AwkAGwXYatO8|zk*PKj-S z4HwbHq5a)P+b2f~8PWNnsG)FSAU%aKmtY?$;m$;OTT0Q+wzZlajjxC`4i9WHY}#*k z&)F{>J!>y^$|@(oH`)~HoZ#k?jOmX~7-ULL+w>!!XHZ{x=vL3k*b-dyZBKe0$RxqL zL4MxTIc0LPJoxWa@;AbJ%WnoL82Let;G01@eO!Kz^OJW^=MSGRlXODp!=HQnwtY{v zEm}78Nk422tQKK>FpgS)!Ww(ChqZUnNFPsY5Dw{ zebQ6-&38M6bra5=ctD?|@T1?dX5VHyRYnM>B_INPTwd_aWmbd~m;{C&3_Kd&%LmGf zfJw%0S~VVo50@Y0(gzCf2e$&m=cu0#DqT}{hy*8yzg%!73AE1OL(39zTNbl z=6|=->F+PwAqF4&K39^2KUncbdk+um@; z9xd%zWYq8(+iH1T3@Kxq)m8iSm%nBozPN2Wo0n{B=d6vpb>G3ad30pk+bd#bSzksE zlgo*avk|~Z%G%jdRSH`$^O+R`fw_;=&v@C~sJHCnmoC^*``9)sYgQA{IqnWD!PdtT zwnwuOlD3`OK5w_)x@O68-ZylBiFNxu2@y%PUP2?ng9I>kxW#(`<0YOe2;?k9@|a~A zwOjWv7MF`iYKxpD|V5Zkr{*5=JB_!l;w%o}4NQ<0Y7hDAR2$L(IB>E8$B*B-g}bX36A0 zg6DiO5Ey`)7`(nc6Z1lVx;x0*wQkjwh|T;+OqzIcD2fu2BWZOzN}kJ zEa!7?6a8-Xs@9W0KbptwQlV~7mhS}$hTg*q2-Hckk)X5;2ZP?64=8 zN_qT+8;{zRa!qxOT5FoJdl=ngX&16n?sX*LT<{dMq%5#0Dey+&2n_wfEU@Ycs;b^` z^{)$x!jCh#k=^K|r98smQCMkL%+BTK_C$5zVI#&;EEW>vA&nfsf2TPBn6x|uV`6zq z@+|z}J}>IrpD*t*j>7w5uYUA52!eB=IjLZPhmcSM3AeQwjSB}Ly4*k~jfwSfdg zg1C&P3D19r%?aTTVc&RCDV%ca-|6)4d;{N0-;kC#4!*yeIIgjDQkWl@*ooUGwj1{I zH#VirN@mJ;?US2Ld#u#6ml_!>F1l7Nhz5%;-#gl~eJR+*wX^oYos?Zlv_(gl%#}hY zo>lMk#Sf?A=S*r&>@#~;tT|2VGvS#1of5P#OuTdYz3}{0{ZHTG8~)S9>DR(^I=?3_ zbkpyPHi=>e@JZR@D@XRzXTN6UWY@MbP5a{UIjd$y?#)6ht3=q055omKEhXCKh8_5=vSM(>==G)A!`7Q8>{799^6-3L$OPHKbr_!zISVx z&Y}Iip5&(iE6SpX;I4yU&}5R)d_q~@QAWB7V^LHv>W>H38{;9R?@Kmfav6Ss(#mFv z7)Y7ibdPMk@7~WdJg;>WZ$XA9L;yw-WHyX{^?`VZWc(HNn|ttz_h2A)KBD?#+|I>D zNFag)I#a^7(j7OZvC(frIs@MgjG*G9l2`uKoy&Hi)K>XpwHYHawE-r0-J*wJ^uvQX zA{h;SE*Kym>bt&24)3Ub34NQDXoP;l*a@r%Hxiu=j8GNhh3@NnePjcTB@}#&adZfq z`MTGmWCt7_D33VN6Uo^a2ibfKxZv%F!4YL0Z+nSecC(d|Os+nNq}*WXax%ENG`taZ z02z(^$d14joB*a6>~LZTLZnDu1N{WEuIj=bIYae7#@Apuxr@LmQibXQBPuw9!D%uc zJDiZ~z!z`>!_*Y{c8Yf?kQEKlyWkJTJ1#&%nc)JJch|e^0M+WrU-rG zv1C;)n`EyOA}1bf$eGc2p!7@<1EgM1J&5N{jN!oqPwAxc;b@VR-YB@c`BDFLex8S(T;lNgwJC)wjYe z#u?qk7-wP#T?8XN#h}}{H@WK1#`1(xVO)USK=8GrvYp8{>}XK7j;&Z>acucz$PQ?k z(<$X8%nXwwD#;Dqs+LaxML1E}Oc;s1*;FtaO%k?VVE>@L)!G;)W0ue7tkG%P!yDVS zCR(-Mu3KAUu%P=hePbvn7m9h`J7K+2wwt%^NdL^*l`}hnrQoD*;E{|iBBk-jWLhzk zlin>H9AFHcSfN@3(``q`LMCC=eBNGp^QK)quWw3T=N&>;WJJ4YPfEwB`lgV|+3xph^|ge?T26BMTyi`y%$YQq ztA2}dPjpV-5zGRr9IO-=3(s?^S4VpE-eJvFSF4sOWGtfh(Yx8q6rGx|nZN{|%OnmV zH-K}cT=KC}t*%(5P_SONXDeCh6vEn9ZrrnDbQZzls4f0hObZ4j+ix5TSDCz<+Ili$ zHxKuvD~+wPwqnD6&yEFGCKq@wu5mG&42(^QSEYaV-Ge%B2S-P?Lx_}_bZ2yY_4`a^ z5P}3}nyB#hPzcb9tlQtZ`+mD4d@}J5p}cSi%oPOmj=Gv=I6nlx{o*7AbkB{?V6Q*p z=o$S#o1eNI!81RG&%$f{NPeHBqu&c3EK_*zzT4pi@AC7C-=Eaqem^XqgP-dcKJ#+* z(>3&sFm09W!alsw7Y$0 z4bIqX;1h%^V^vXmG_juWZ93`MUwiEl`*L$fz=pO{53iVhr11D)A`kV2!jb2l@`v}y z8>aBy^2hh?`*B<40*|nNPSS(d-;LxI5T*JC4`|Z6{PD0oeq3H~^iJShhwz)a5AS_{ zbtd9ZP<-8|S|EG~xUjtY5;q>a8D4RY&k{|U)L?$o-afRr! zd`AaFGYApP=IPb8{n>|Z+a(DJEtU1;+PaNeZL5Ol%_BQ(_UvCAZAf5G37N$@92U!> zgb>fw*X>O9$a=_aA|}NAd9Giw>*E#sO#PfMyTqswyt91wq)q;3`TMsqeUtj1?hl7M z?O#|W5p3S~Qlnr$elBSjSBv)6QQcmvr|h}W_t>NPT`{qNH9KRgO;Xl6zGIK?Y}o3? zj(c7}$gl42+4+rCJAd|yEhJg6#D@(IKJ~FrS+gmIDyGF|0lh(2LXKG}U$pCccXiB( z$WO#vN>=Z-ts8R$KS#t(GfE#L-(wpurO& zkzyIElv2H)6Vv0JDuR{%k_L`{&ZyMLUMhCaU5eIUOa*iQoW9;q}rms5>O;~N9;(7@7Y|- zYQv=M_w%-$>)In#4E_=-hX@%d3Bn`yh-H%vl)TY|K_&rJFy8A)5mFuBXsy}f)vj%1 zdv>jvvonR6`f_Nisfa59Z2Fm(&=QR#j3sCDNkjEV8BI&@kRl?*y)K~vxYq{~X4L6; z^}^&4y03LoQlyi3$P8A+5G^?g}=!j8@)!eNxsW*Zqo zw=BH;RXSToBFO-spiP;bOR+hfHw&^>ih)eBnOsKc+D~Vh0oqg@1@`G z$r1hS(|0R5Z&ZP9fD8*>*k-0@uQ!W2pG&dIO7KtGFWe~FC$sWJl7`uXkPoA2)ZS`W><72^M4yHdUojH0x(YfM6YWh~dy*CZ4rGe% zgo#zXD?UtU1Y{H@>(Zjvzj5%GeQNuLef@Y%ifdS5svPyn=f8LLL%w%H(0mag9%jd)mX5eGf;{8t3)hg*{e1whygcH^OQli_k6MOYOkKF%}nrTvuVqSrlV{U`**y+>q#`<4XNNp z%qQ$I&iC}4sg%veIA^7#Wc6{zO7Xt8g$a1?Le<7`+jsCboR z6W~le34d|ePunJjN5K|5Dsm2l3Pr;;th*2j4|Ocqjd~e7upV9%JfTMxW@oP z-7!ehwfN|<*M_R$jt6mLx5}W8$4H&f z2^Y_lR2S>JhpMs*Hi0KLvaVk9no%Z=z|cAar`0ZxH9SH#)o2tP`?HwKqilj5i%IrK z%zR$N4YVqytM94zRSeDxlEYQ!2u6QB!;r|g5L}sv;CtW=Mq6U3;|UG!vY|Y%2epZf z4(L`SM`F5V0tMXUE0jfY zS~>#dv?O1q@vPQ=aAu%BBcI1d7Vhu@@W5y}5Kds+3&#K0Dg}(-f;VuWIXX`(Ka(_! z74RsDQBeI?$|k)|v|%otWv7%>J=I5xj9?X2Ig(k`Hek-AP7ofE&@te!^dxUOH7zx;1ses~0Q#Uj5h-g28G!ZxPALcMiIC)auxovzM*D zyK9qvU;1{-wzqcNfJZ;Q`o`-{58vFsXXhR{XWQkR`b&Czy>0zL&klC?ZJ_aa)UH{W zjpOzJ0RQw!L_t)&t2#-aW|F3u6OO1`Cu$&jCh(6*9Y*s=<9#D9Dl!;ZsZ>;bnTTKm zfAK(#X?<4kAG^oBhr}H8B}1&*UhT-vY;QU(&q~fO=ZZGbH&y8cLTD(0kz_N1q%-w8Q0)w8Vnsx$7}S~P3jP5{elr79h=DY_7`mz#O} zhr1uLm)a{rDiB#eA147GhcT9&uIuMF`RSD8hFXsL1qNuIFOQy<<7k;bxDBn-iDx4} zH^U4{C-+Et-_z+loS*)MDf})+-aGZovvO})hClL~`p++XSBcYE%D#8!(0=;dt~Gm- zZPbtBq4<>;@5b7yV3)UhwPTA*CP+&^BxFxtaK5s0(f0Q4*m3XJ29k;TqIE6d3LAD- z3Fo5zplVFgtqC7rY!yV4p@7tZk1y+R(w1+Qcy_v-Vczim>FeUc_M?wKB?dpSt9yHP0Z-@jiZkM)quX}p?p;xQ z2?_0BmQQCbQ!d$IqvOKtGiT1)y?R%~r)&8_T0#q(9!Lli zA!~NK))rBMnAIj?{@IFEB)D9vuGx*+fnBPs+g`V2XErwNi&x*0pxw8vwThUxgkSY9 zAvr>tnHK?M+~9#g-C0h9M|WF{sL|<4amq;8Tv)3&5R;RVl}xzNn9U2u9^te%#*jc9 zz>$<01Wb&HL%kodH#_I;Y@z2ce`Z4h#A0ZNJ-s7E<>9rgHF|;91-l|wBz-cAo|F)R zhcuhxu{ps(x8nj}N@JTiiYP!uF{4_KO+s>l_gD%^%o-AKFO+GY$``EgTw+rj#K>@| z56dVeK6xBCJW=YSq}}eMtT{>A=k7@CfM%fFkj)c91Beow`;lu>cwoFBbSw=7Os2W8 z;SY3=j^OBpGRDFbpjU_4U)0UJm@I`nl5sescJqcmgn;jb`vUWZ@5#B{?cQCWHY}^gyETAY# zpuXE2*h*T$Bolw5sLm4}|7$~IC@oxPx9UDJ|^98`mvW zsM@y5zSv}L}DhTwrGFv_D56@GMCaf9eRvSexxu{cpavoPD=vpciu6byylsMQ-3E&7--<3 z!SYr;*R%ONX@CCF-?05r+OBri>}XQ3Kf3dR4RoJ)rIRrDIACn^Ub+rhm5iDE6d3P!y?{);#n%^aJ;5s za(1VavDX{yqEBu09sMt7Bm)gG=FZi1`tWHP|5V$Y_ejS0-ZMAsvEr`kke1va*y}!< za3PameD%F4=0n6O)x#uXVb~JW5nQrvz-97%DI2KBVA*-F#QsjFXy=L@H6OVom?R}H zhFwGhJR}pTsP#m%F)m{iqA3{X!4uRaDvvkjNH1X0Lnp!W5%~Is;FhvfWEAjo)stnt zc!Rpv*i3a%nRtQwCUCk>h%Rw`l{>e+URimOFGiNtkx5tQ&-#ZUcF2AwDamGnV_;4U zo_U;P)mct) zl8l6mMg74)3d3;d6A-F1awg-^tqwZQ=JbQ~KtoHj!@yiwa;O3#@T^P5TzQ-WWCf1;k8!1({ym&Qp3K%zwDb;_7 zCp1RYz-fbUcHsV4@-Caq4JC&mPn9#0B{2SBL_oF_G*~H!41(Vxa0GUadrFwnF`|PJ zc*o)C4t!zjY@!&^31le7cO5Tc`UwY9cV{R=1+WeWECF8wHoN*+$@7qK(>vC7q(`XEL^o;w|-9KNq> zzU#UlAB*%}9l`iN4g!f>K6CwuLIVZeM3vNT{^0yio0hx5tGu>lTY|5pd zajM~~)IV6&$TQVhIP3kZ`!VTEZPCt_5QKNI~^OUPT6Fz zks&l`Al*Ng*K>`9WF}=pT*rk|bM-MHM$&2Nb*+|%V~Ggg3Dwe=h%c#bSGLXw2xhnT zc5QuS#fq7%)7iU+2i8}=K6B+!d-K*!^@s38-(v!-sy<~RVv&s4_1!(+Ln@v~+F`A! zE6L%CY!dzK)9khPRD)qrEo_Ia=X{l`0QIkxYg50|GW2|)a{H# z;!LlToPzjSa6^FbpM%R!onM3H5LpNs|M>w2UgAA2{JrIo1IY_nCTK}m=sPA}3d`Yl z`Z_$GPN(lJ&;4*JA2jUrYknQxAiu6P&L1gv?Gsf(+;-G6X=@M0;s+V=3|*;j`nry* z?IX2#tyH#&V18z8&9=5K+8b}YW{rMFe5zrCxag_I@1^x^+sqe5M-r}+UcGh8_S$tp zv19*p{YRWWfD8B46&s*emPS07mUX2c{PJ`j-dXnHH>73$?>L3!QTC}iewR|rp8i9B z`Q7>0>GvN55=hLc{sBw&AZvt>Vau4X@dWoS>9Iu;Y7@C`!B zEB5I-G5d;ys4um*t!sHZ8qf{|PO(jugJ4GrY890GROQ%;BI;LiJ^R(eP3w$#M--a& z+y?`WdY_j=c->$5e~Z)Ub_CD~k~emFM52W>SW$cB6SLL8q)^-DhAkxvVPzC|hh6!AvURD#Q>*kCE2n z(MlM?^Po|y*+9&O_{VbzXYS=8VVX7|Bo|;*YGYK^aGYIPmwHdh!!G9`-*6AYxU|dF2N?I)Q^sdXoKL8WvQoJS2yyO&JVnu29Zoq40PY1=t5`eERu^u}>V zZ5xRm5IRC%pyMNH>*)QQl-gXJ_;?avRrhEt>E0B0sG;bM)yKXpRX_gm>Rb#AZ{7Y> zP!?muyJkB#ut!S+`^473JyrIHDCYVMMup{Y@y$q~1x^o0Z$IP2S6eLUnJbO~c;3$M z_c-T0j;DT}S4S?F<$irv!ngXKP$t{?g|()_2`MFbfBW)c-k}`cpZ zyqk#M)*Q@)cT(Pl9pPcbYLl4W*Z7q}!!pD~LIPQ2XvIWCxD@pmeoU00DDM3BJF3WKmLh|ABOJoBTTQciv8L+@KUP!QW%{k=46) zI7r!z-l~0U?S>U%OxB85MJJL$MT_Tg@g?#5g?Ntc;RVMsc~<{GZ|CCq(y8sm+Ky;- z+Afvq;&-B(;?EdK+taKi#e>@;=x)HrFnG)s3CRn@>(saVXY5L0&pvbW5mgK?B#6Q2%ClpLOuPsw#2E@JjaF1#U*5O)I<{p=G2DBb$`ggLd2iZ_aH2L5aq z1}8>1gRba1#y&ijF&?tHaw@4Z@DNmfB0W=*W7Cl8?R?rMY)5%Mmap-hR z(oJCKgLh(3#S2;dLb5-xHklMpQl@GHPfDovOnzYao-9)CNlKF!sz3V)s0PZruv~I# zDb*W8@!o*FHxhOx*R)(rIV6*jSe*tQ^IZ(p*#vDBh~v7ieha*QF=Xp|f)~yM7^r|1 z25Vw7!)lNPks;i90o0;!Jsv zdMmp-RA3NNYmHdMe4p6EOdyQBADO^bJ9SR1?_4^F&5aS5@DJ)_>x+LUr4LXcoHI&k z!XZdro=Z;v4w9wtwxwV2dL<*qZ8yTI55P-|tVum%VjPD8+RQzl5LliAI^abpFE%R7 zBqg(}Eag^P1rNcOe(`)t0;ks-`OI(W`%IF!QBrBHc7YW$;hTz39+jhvzPY8o?6IeH z&AUi2Dq2ZLy_Zi+gUz#3efMZ*1))!3PzNCh`XCm31 za3}O1{py=Ks-A2Vjs1Y|Dj0PMxdJShWJ0_oyau5+T*Ly`^$p<43eSaPwjqcFJy6@T zlE>Nj&EcqTf$#KUI!1<8%9q7a2}-A&C^5}X7J z%412sNP?decBJ2*IX*0=WA7i}iYGRnuIfPLqhkrHBPy-3SeZX>eRs;6bLKfY`~O=f^YyKVss=!HgWW{!_wwe+bN1Q8+H0?Auf2A@RPwRFXum6c zc3V2@%xRqFPiLSuEN$2uT0L8~A&xleOICFH?Bo=s(azc}dwg-L1?zTC zgpU*PmXV-K4C=s=xui9FBb%t-mv3LOMy+I(nDj8|S3~LQjBzjxY;&_};}HgV>2(zj zCX`&SIxkcU_OLm$Q?-3C=sA5SCU;r7H(u2uogpSD;(ssP8*njr!M{Ft@787rdoRlJ(@-+FJ z6heYWJOeqIKkNHE;95B7{D6CuI{)5NdmVpPdA$AHSiPq_oB65zhnK&lF-BqKObqcv%~?YK5L%{KC|fC=b>3Rl zZ)p8UI8)6FU#4k$@Z_GIOgMLJY_DFtZn1Pp;F?;jov<%{>(`wRb9ggOjETy&eZG2N zfA&&nzp~#DsZ$#qwyP$2TD8%~Ao>~o;okXc|FKG3)8930R(ak7s}D-+yyw%ptY`24 zpi@-$$^iX?NV9jO8_WK1F9N31n-u6K8ZY)xA;ZBzr%yLN)#Yske&f48xaYg8OuE7#w z0)pseFCc28!!9c8-@Zh@ypyZXxiR!d`s0t5)|qZvdj8N(CwV(sY}!l3L%TP$;OTYdl+u7Q%=b!ti1;dfhVrn~k z*X`~7x9zOcwrMc7p6aVss}io__I9&nd-b|~>)^^wYpVmEKzuuUcqUl;5tGHj7Wb-h!F{&^HAah+f+Ef zZK}Q`RXy={d+HMh1rDq;F4=I-Hd+k0#68aW_QF7l0>a2h`9h6tdldSXLc(#l@T_)l z0Kg)ibE79-&nN|ckYS=>SIccH#9C^PlxHc;z^IZ#(VST?kPtI3*=d*)4DwdXn{5{) zoDaupSHT)N6bvzPF&g3-&ZXd&Q=#x9i_GHnRHe`o;-Qgl+tCnj3kg@^UlS?)4}uG7 z53r29m52>~p@^|LF69_+1w5(+PmMicU0~!0`}{*N-Juv4$^jk)IWa)u!(qrp zC2|A2-g~Y(v_E^L??UWbXIb$q6mylN5A~oq_yU*yMYF{x%hUT$)49v1dHkb7&gXOb zxK2^NsnP3|zp;pR;q-~e8Zg@BiMs^TpRCmg~klr2$ zFQn|Ukm24hfbl$t*9p2FU97&>iTm&O!iVX@^oJ!0|9uMZhwJrRA&HNSQ=;#AYh(gf z{yU=4-|BDJ|NPF>x`Vk@i;^dgo7N6`*6B5^FP^~J3>coeQYyqa?e9H#)rhM5l;*vs zj%O3?;Q4xPdgITIIPLUd88LsGZs;Hy=u&)e|=~Eln)T3Q5j>h*>2y zuv}d9o!F@2U&J}i>-Rr6_@rGd4(wMCFR6a$CUOVl6C)VyhK6D+SBH>8fGLgV6aCR& z{ZsyeWa^hI_YqZ$gJ<2#R9P^50TB2JGPBFe6vspFCk8mlMi{@P01~$rFYUZ|QGYCj zGKrV3Xs+HR1VJlIxnT(dBr*(PmB>Gt({BvE7;EtsjEr2w7v``s-;%#bOO}gyndHML zj|?)yz^R1XMEC?2(dn0mq*5MV@R%VFv7<*&5IlH=E^OrI;(y2oI2a^Ur^=Ab6<{!$ z;>@B$J>&(gx$K=oECY@ ziqbiv6d6P@>U)W5JI3FcNvBCjep8(+vLoZcZ;`3cSukc|4D(%SYByoi@Nku&V z6V+Kz;a$mrzz*jMj63u_qdp#u`KVTw#Zzc<*FPc(<6wk^`l{&&Y_LR3Gp#B=k!u zg-15#PT`*FVLaWd7I{G5YvU&J){=z?3`aPP0B`l(jflb*4j4wyuxM}Gu6=9lnQb1pCas5eV#?DCo$?5s=)4uT~^ zs@%XCMyiMqS+RjEJdu4OS9vvRp-i1AH z?<+TM*^`Gj@Nh6^#;WC_rNX6+yCcc-HS4vz_UQ4x=E%^_f}t%690s2<4y8QpH0|=m zi|&=&l)ij28(L@3w^FU_2JrfJ!*+LT)(K*E^ZKskB~LGf55(SP7cWNBdL=JhI$-E_D_$k z6S5;ky53mr?n}oNJP5IYrz#xxL2!|ty-^ITJPX_Ty0cs zCRh_5G7vqPbIz0Cuz!3go}#&fvy9qZC`r#PX02XiC+)y0m4co{`aR{dAU+xlZL?9g ze!p+!YDM~^$`nklY;D+5Fy5}zY^pqC@wPy;4V@o8vYE|GM@?BM-NbkDNC-H3^29D} z=k4`o(fGtu$;b7;jcL#Gljl8{hu2J?XctP`hB4_bywgd3aPI0JpIIr5~X$3>S?-zQszE%Q0>uU%P?;#sF z-JlHakzt+bM?d|54A5%;tkd@c1OQuIJ_Wcw4%`UX9+rdR{90v00sOf>p85P|UGHi@ z)@43@el9tJ>+|&X`rY+=df@e_PG_jPmQc!JD$z4M>lPBo684{brfD0wgjLcTHfnXm zc=OhL@P_3Up}jN8T6>zb*0LZ*B|$^4drd00LQE=QJBC5WdfFld01gCGX1myw-`s}^ zu8~pgaRPE4Ir%tD{%udIzD6BC_e~NU9VUDh_V(a{b(a#DHCDvp`&RdY-OlaX6}xY{ z*_Qo_&L^#GEql4#v~P9lRxU2A(>k%?FtlI!t>3iEyCtjSt9IqeZF{_b-v*<$UE8~1 zU-`~AER^uemZOi~dBNhN(BmY>vIVtfW}mox*)DEeu+u@;V@Acr6lM}itI3Ql$6`_% zI|MR>(Wc%@icsYm6+3>gFGi>SXdF+Pr_w+4dI(^&&6z);*4w+ zWXsTWmavQ48)Bwnng|48(srfD5l0VUEhW6ki(nRtWlf{#P(PR=@vtT+H-aFm+UX^S z=tObxI3+zNJWnLjb`+MRcm}Fk*e9VH<%sQ&0)*%l`{KPxqahw&mQ*ccC*^HZ#B1Vw>Y&+h0xB%D&0L$md3U|yeg)#lmvyI;Khpl z*u9-y=@7HP!#OX7jRPS8N_V1uTA((Y<)n0Sh*T|?*PIzxTK8Myq%|bib|!giNMWz% zq*$jV$Y>7IuVA?;SdVpuf~qzMzO5lj*~mR!G3s+jNn1i4UfwKVJnSVckt(}KE#B1i z+|usUh(@+l8^%_WbTD5`B*2bb;ET2cLSu*{nX||Jv6Ns0WKIaDEg}P|yCvMgh>C{- z+gnkrJZ`1(0efORYq}dZM5DA1NcQwE8!~do+ih ze)~U!E#-msk(I&YkLU4%q7Q#mCvhm-lcasTG4gH4|L95Hc5^ZNjnlO7UAU^xP;DZ< zH%ethe-rkLmzt_)Y)>Y2+Y=5TG#_a`VF2c&@WWBw?)KyM)swRQ+!e}R+F{?UtML-Z zyx(;xQYRy}Je%EWH0)&9SIKIBD(}XA;J-uIjFc2)ln3F&mInTQZ)qRd;NYpaJ?fd= zsU%c3u`VUtYtG`CUe972n7P7J&^+jdsxOz(cwuZvST79h-9cRQf*6uhyHb_Hqj|Gf zPOYV9`+9-6eb5EMC>4`|@LGa>W2V0036xM?27Cq3wJ`BCai8COqA`oo`RfnUhl#Yt z6L98yTHpVm=ReL#{aN#T67vTdCHfK>LgwNLS$lU_w7qiLZrA6QnD?b94((e9UF&Er zW>cXb=EMG-W{?)mh})Nruh=*H*K8xt0#jA=_1Dop%^ojWXi6EcDWlK$1nEB0FFqCE*W-0S&p zykQT!b$d7{iN?d5sS%zk(5?Cwc}wX5vh33ilS3c1(|fX#b0@R3-Kez1$1w~Orh@Pe zypIB{zQI5Ix89)$O3?**SmcDHMuti36XKov&LxHd#CQyUUAUpTFFfHo z@~czLvnGOQ)7 zE;+iCk^H9ugGF9ETJn&1Sh&oJw;?yJ4S~@@4u{Ec@R!3z-^h)GD#JKfPEUM1I9QGY zn|y2qCwju}w~XXpyt_HDZ!Z3*p|Kkq7!W-*zKM-JlYA)nsSdoA*+s>fC?2<2 zZH1>}{Nv-^>>5*x{(ZEkf2LqFAGn z0)-<fer9eEhL6Pnv{rUC;;r49q-~?1T*75H zs_7o^#LJe&gCz1kWvF~#&{w|(lZ-D`Ab*1E?1WIu-8Ms23S#$_=_eC#tHj}@9sGt3$5tyeYdq~mn!VwRR6PtE|k6{ zpfdizm_-Hf9HT0WK9ec9H4$zmZNWf8BL!3D2aYoso3pBSG#c7&x#H*d+}yih-+t{4 zpDU%j^ql(-?C_*%q4bz$uVZ)jA6O_|C%sp-M6qBOcD97G(lrJ7?Ml_dO-#ax>%nPv z?n>IlOBd}@zV6s@slMUyn>VGSzVUX`a^gXA!Rq3L9lKDiTRxt#gQFws5*9-`*WE`C zY?){02nTvguc{Q(ZqfB@%1Xt&z4qXNwbZVqe(!E>Sg9&KSNd}=P+hfxwfY0iW6fvv zox>FI!e^l`I+Q={XBFZ2gW(#uLsL2QJfm^WsqHvV0jJGI%|_$UI^BVtHJeUnFoySs z96B!fUoiJDLK@S}YEAlZsOyAX+T5{(#-Wl)+iyJ@*_G|A^*VhksC-QU_s%AuAVb*g z^#t>hO;StoDk}!m#Bww*6**%^LkeAuj?csLwJ3p^*emdwbv8hde8H(%i_0?##8jHm|fVD`3AHmEv{_+Ed`wbO6$ zXZ7qUj91s^;lsCIuJ51!kkK-|2PY{`%SZbUr`Gy-u*FHNf8Qo%54q zoo}7a-#`EEv%g9FUe|m6nGl(u{)+yfq)4XtBfA~@Sha1{v>1bs@&EOD+3r-tG$wuf zxyu>*uU;S8<@(GX_Y?MTzGlO3>LH0j{Lu?%_RpSd zs98K;wdpD1Jv+fjT%T|IAEva1$*TX1m4jwAcn}^vzmOZ+(I{h$Y-l^Vfj~R8S8Au0 zoQ~|C2*7XlpSO=Uj;%C(Xp`i&Jy#jpiz8;aQ$5<;5k!g6Ac zc$2W&j8VB04D92#ZrisXKeQaowIAB&ZrrqQ9v+BcN8Yw$5j;trmY2}76fwl|hEU;K z1QFa3vNdOj1SI)<#!9-!0!CIi7opHX!b2DdOnos;3SUT}5z_%wFq7e|VDI#| z?NghN#AMZEyoki4rOK#S!W2k!Q2AL2peDhLxXqaqE5=fClml-Nghk5o!+R1r2@ex1 zXE~&2V#KdoNcpEt%S6e(ae6^ab1CKbt_0w?HD`4z#D~_Mmej79l$t2c7Xmm&#V?+I z)CNJ``}pT?f62$WH%2f>N})j^KzW@>2^L#kwDgXIjhvLtX-GU%MVlh>M`}=RpdZ*&_)Bo0QnDnR`)%r zVbKGn^Y=eYe>l?`Klp$fYnBkzJ2NFiha9#&0ek@*u6f7B~9%@acG~H^7ZAjtMbLhPx`#J&WO!Rj8OPw4vcGuy+m=s`-S~)s1w#~Gj2Iy=B`I)CV;@(;LXdpdM>)p!Eh{$18aD0RdNjHO;8Ty(*}%)DpA)NH^L)Z z&}MJBo^eJ?N_;2c*%-eB9&c0J;z^Z(H>vVX=LtVJH*}*uyq0${JV#*~kg2GTL*i%+ zbJ(GTN4Dzs{3_E8k&<121qOcN`_e;b^XG#mz_k&7|2Vf14L%wgJdgITjO;(}1-@S#nA`lcjf>bKocr6Eiy-r>#+r z4gqIT9|;hzcn+7tBb%KE$S%w$La4FJ0K?i${m0-~N(DYQnD2}uV*6~SzH9s#cK4{( zy~v4TRjVgF)jRBz_n1?=ZRXLvMW6eX1u*}%* zMENzB@KglnXOchLLBh&8!Bcn)91>FeOKJ6w{;Dh%JF;pQ4k6$T__>_Ltu6XcN=v_y zEQryZIy35hSMz2gCp{0@R==IT%%*}7i&RmbX}lu%^o7qUwTU@Ln2NSF>LquMc-XGm zQINA=ynfdmgP1oh$@Un?FH|O)Zz_|4QWcDu$46IfGnJDPZuI&ii{%|U^m=3{R#v_WiS2hE&a+DO>AM110+ZDzCf-Tg;) zZEM?li?Q^~j6FF!1u5;7i`VS*^vtH?nLRi?v}(N~co%G=P!hZ*E;B!T{MbU#2EyNz z>P0*3v}}>CSw=GTi&t(~Ao=~c-?c|iPHpqTj%{z$ZAKjGTtTYuQu@@;GJ2Quits+} z4An-5S53NJ&K{l|JH9cl8dytI_ADrkv8eZE zwpFZIv!%Ay%62yBdpM9KG)gmx{1`pwqV>d|PHMh3`)w<6@TF))Fdd1$=CwTOojuV@Fsd>oq z8WWj(Q8vDu_vi|K<#)IVvPBn4l&p#Pp2R&qyuG~tx&iHr{zHy_dIjQ;1u7c+--?HIwY~Ok3 zHQ_;7I5f47-hRpc^MCo@+p>_hTbJ+HAUG2pj@!>(|E%48=dN}7hqinDs-2yj*naES z`kImd^^s(!xcHnCam`Q%ncC^&;4NCUeU-SRTko6BJ#ZLsp|ZUHelxmHa`>DdpL2Em z2&ErF2oBOYKz(3(HV?ngzkmMoeMjZ@nLePLb=3@}nCTzC*0lfCofCVhG_n8oz68!( z$!bBzp38Qulw8ZwfDtAe zO?%X8*;z2MaoDxW)@3_xH|_4(i5>O^c70Qdp77{Vn6TYy+WLWnSP4swdfiu5IYIqQ zOy7l9G4_lY-n)l~5~?y*VT-@Yol0n#Ng$F`>jEGLArgCUjzA>ADmqXvE(XH(Pn4aR z^?E}oJ9*Ass}|go|WJ)9GFXa%Hx@X*NO5<*g9kA1&*D30HV0!))s%LbW5n`OBF=ngr7a3Ev%dni70yS0&V1NC$Dg2dm*IM3mK2i?F8 zy&DoXQG`(zTES2_$f|b2ngb3~QZs;``c#oX$H6`*<#+;|21zRBF>6-w!ALEyS0IWW6_G zeI-Fy#c%Lx{^m*C_WL#aGuQX+K`&{;aBlx-|DxTh^{gO%11-Q448EIB6{L`g8mb&1 zRw~t{K+o)j@?ATbRK!n36mSsmr{@~*{ifv8Y^zM?!}@kKV;lhar5th>Xg9$laDuG!+RBvxoif569*n*SflZgS2hdF zB={UgxO7^$;q6(9x6h5(%!Kd4!xv*bo}(!H@O3xl#Zqclw9|~x6wv>f>PH+9>vAJ8 z9;fp-A)W*g4{1g#F&b-hF@OkS$hS$=>z=E?oOaV7@nyb|yUr$g$xo8i7LoCo+)q8p zDO7c1h$9q3yhyKGj5Q1bPUeCfYF|=bCV#J3xa#H$nP|%pB&gSm&@a31zfGKOi~ z*s+ilTyR7{_G94$qdp;E2>HSoc_c;MqI*~S+lRJF@w`Uf5{Q{0AL3jSSC}%GoRmkMU@=B^hm$t}S;YT3tY{N`<)6oV<{k!4 z)d@a?>c?x%x;3OXaSjSN4U{-!5wB?^Naik!1Jsvv!|lw&ti@9~+ssVVW)-UY7zPu_ zoLHJw7e+yz;k3eH4t@0o0Ve^7L!g%`1K5uQEsil{Y~$d5Hf0ALVtGfhD06C($l7sB z0;*t)r#^T^#t&-QlG2R)4EF>{Dg0=XJL`mU)WJq5~=N!k<)*S?TXQ4ThahW$UpV*z+ z$lhs}?JGxnR?A6OSw=Jq9b&6QM8$=TN1@egRn--GsJ>{yN3?$wNN?h79Pt9-XF`3& zBfd8btX9gqb4VZ^hDIQ7<2k$`o#~`=X7BX+_REi-x8EMzG%Kd;3zeBQENAVLGfP7P zRsNU*`7}&f#!PTWx6P>BMK)nKFJHBxblcHX&qo zg6cjxJ@cKI6XD*`Y0GKrf2c3c7h>3wY0tZrWz}nD_YiWbu=zx57*HVJ?Zqj zwsT?Ab<1v7_tZXU%}9JMD`MGARP3MKtJtr!p0l%gP3>TzOk=O{gmo_U9Z8ws;Cv@=o@`4he8mrv7seyq~_-Fr5j&$GVfdsWBN&j%#68(JLY z0V(wb(d5GE3E$jXWg%hL^K0c-r(Ui1eBr$pjK!l8wp*_IIF~j47aJGsVE@?m_aE8w zx9?a|{Hj0b*{{C-+t!p^w0B`kd@N?0(&ymA|LixvXq%fQ+o?9}^kGG%8?_E3a*L_)!;nRN7x%HS(&iT$Nt@HngrysBZdfn+2 zV1L)N9tiTTuh;4Oy}t(jGeH0SCNDzo`-j!@q*b$_y;SYlfB0Nz@vvaO@~wyVFGnv} zaoV$AIj-2Z#@k{bp$%h28%Tg;q92V4YK8;`@AeAeC|ijwfgryhs-g$cfgwC0lRh94 zlm00}J)6k)VfvkEJ?Ti#z{o)xJwq71Qs_!BVH>4{Cp)vEnDSPtZ~v-wM}%i;wPnYS z#(8T`r+xzObl9@y=@aX8`qmBtyM6nny>$B(`zOEoYxYw=@fizSZ3)R4-_BEzVA&o| zZQ5^IqfoN#azV;&PYhDRYNshduxb}-X=@J0wh$9N<$wk?EhJ8rgr0>2@-Zu{>P|d` zAR|^FeA(Nq*;GPIv)gmQ<=_;hBVD9up$vdtFebdWa>=xWnuQzF#^af9)xndP z5C|w8td1A3rU^DM<5?_komt(U%&th7h}proYWu^gZN^(RVAWpjAJeroMW*-A;g zqY*|?v1ayUykooB6A4=dALUAVWDPNkhl8r};EjWKDF-|(tTj?u62Cd<1?7&I(@P0! zMPk5VI37!pjE(e;kV0_C#fNT$50^RP)N2I0ij<`}_Iyc+gvUt=ek4MWVAu|&2&AOg zWF^FO0%c4Tt(ckFP-Q;}a+Xo~#6ET=r}t5WAt@LmF*aMA!}7q#K>eAjhZ6h*o$rm(U?V^(Fn9C+!DH!rxi-9 z*0>-{)YZ;UZ*}c@Ik5hW7{mzGY1_yP7V7V|7-cxsNC|#0GWt&#AjXXCo1WAepHk7U z=t3Wq6<`jYgu**F5bz964gkcYiM{yepX=Bcb`IUE`E(-sr%Z%;A#UHQM;vHq-aW}SYFaOi`Y3V9GM!!@oT zn*UQ5+nTErd(tWDorFz9%bGz^w0&rq#lZg2EnW24r>xq5sbkD<3eQNuWXqsrZ_)97lT60{subfa4 zw4<O|x{b+(WCi-6ejy!~;etXCKnLfI9<;s7qo~zSz8{-rU*p&=) zIbqdQSG);>lDMV#8#|ZC$otru$r~9;;nkRhgbL0FiJ`3aNr@*+81YW$F}xY^vRs{g z5gWV58jFv_nZ_u{c??M*6f#V($az0g>7>e#EFsxq5hu29R`0~ckMWiljTddF6YyN( zzq;I}YZQJAugDHA|A@aZ&KNc6zOzR42RQ&k7r#9ouW-xZ<{$A0@peCGP_Ukg&&@Gb zCfs5yJyzdp3&u+hOD?E?7-3-@a1UThTL>&!cA}wLzuek26mSh^a8u`xE~oT zFi1uQQ$nd_G@gS6;in>FuS;muuS$q{OubA+!irRqq4;86_*l2U`}S?CW|sDPPxDNA zRWQrgg^FZJjU6FCDr$3l8fq+%Ti7X@@bgnm_v1OVALE&cuzSeOd2(M3H!|Vezv0ri_AM4;*PQ<}2j? zx7rokD~vp}3lCA+=dE!)7hJx)G{v?b81Qj*uD)6F!-KrclY5Zwn}11W0DbVekQ@f9oy zgUB2Z?0n%$@3J!hCxk8``-Fq+h`_cWHN$1@&NwMv6*;L8elAD+Y4v0{&S-p8hjf#% z%DY|-?PJ>~!uOoy*T|8roQp~R6-+Tmi`HS(C!7d}y%YO+F`L+Mw6Iz&FFY3=6rDl_ z$H+DqMF;5h27-;+UXZ>~$w}@OP9=Mxjb@<**_wUj?25)@X8+!urqjh>FtVg{)y>9+ zsHOVC0sJG#$RO*`U898;ei#(Y4tl}^^KZs?`&G9-;+FDkjOppamxsv z7@>Qkz8&@^))T(mx_Z%q_L+4DLwk63D%fknBs50(jFqKRmn4^u)xUR+4y{tFsa2x6 z8Vg@Q^m#5>T{3<`<5Cekhtk`jC52+a!|p5uhlRfJZf5+G8XxEZp5b`67WF%o)7XiR zY}Cra0pXv>P`t)$zwHwzj3jf8cBo776w(vTu zxtzCGZ@gp&N5`TYL%VYIs*OfH`%3qgsuQn#51iI*5p4PPYqiVs@QG+O=X?CgYctW; zsXgdOrh#dLh)>h{TID>2$FoWI{r3Ak`_V`Vd-YHJjdjPP^z8NTHIaAy`Q6gGeA4;% z&VSD5dA~#+fd9LtbA92G*TnD*rC)=*Qy7Su4uwbw`$WBIf9+=5zI!IYaT>ROa6hzz z{4J}bMEJ%vJC<;TVF!cF8?B0cZu?Y%?Zoy<6A`tgZ(a25@gh2oQ2Nj1^4z3|WH+9z zKHi}3_xUh=aC#P2&)|%MFJ^~9+4dJZ_UZb4yFa@w#WZWXsbkwnw(Tpu+agE^=}UWa za?5Tmf7`Ofij_2;cSA8geGfaQ_WDC9a$6hLesXAg+hVF>*vnYbIuam0e(9pUbMV-9 z>NP38crM4>JD^^WASGtf9!Tjy8Oe%Ch~O;}k#}}c%m-r?r|`1f2<4I0epcSAV!R*= zg2nFEwk5<2d!3FIRmWHY4Z<5~Cc;@116+IKWHL!HKs`Va6FAuV*6uG%v{ZsE2k^k0 zC9pZs4Qwkvu}0#^J)QQ-pi?m>VD$~-OsMeRU{L4YRC?<7`GUnVLZgL6c*5o}?M zY*};95-9?Np+E_w4^s(Lc?sRjR~BG;lY~7P)isx*}ApKhVg8DJ`GAPmUy*O7Tz?xs(){*hCPHYmSy&AU+*pK%J;xcrzsJ z@u+I~RG=}**l3$vy0 zSSBr0TmGHhf&KJ_zWv;#j(ujUBl^{~&uj_dz-a--vZ`2p|Kf8Tqf8n{7<>MneR=bIlhmyDZQQow1SlpiTMgFy3DN+NL`uM{Dt)#rCbc>#I+P)lozl%n*iw1h0^+a zou2*uVfw?H&P~pziF?8&$CLA)AMr%9)l6&@>+7g{G5e{@6Z_x1+Oc2QdFW?5e0t;5 z4*N;_lQ$pQ&+WWrKY!(ky;OQ+U);ZCZ}l|MM2|Oe3;S!&e_aYZ1_^e!a8Mx&grc*W zodYQup_K5xXmLuk(__YpPH*N1_KnUZHzGz2I`<8M^xvzb_R(IZD#jJ)CI37;!)pF| z7x<>URe$`2mE!lF&pNH%^)Jd)R*^I3`K9F8E)~1trCnDV#f9w6-k#m>*X&>@S}A@J zUxqeXGorsiNKUgazUy7?Uyh&NN=g;DH1K-Y#auXLJvP2*$9O z_>6}uP#z3J7&_gMr-v#|G@JvyQsTWB(UNNS(ha;)2vnX6?=Ev-gvH|$zCeF4HhO3V z4T{GgR&()erXH6oMDwGb^A9lSTlKDS1jArttQN1;yBJ=hyn=w_9K525DeQ4##oyua zVoPc>WiaB*aJ2zIt8F~jTjE3Pwo*CBHU0Ud!qp zJKH?Au=2B;jCT5B19>IS;yBQr=IxDk-Hw8i{lz=)+VyhVu9do0l)Ti)v5=thm5&(8 zEYka8f%vr_WT-Y`DD?$xwcpFe0I2$Ce>{O9PxDfM#Q`0U(?0qZVPe!8jD(CWh6IhS zV1&1}`l$}$nVU$b)l2nF<>hh(chm@ip(P77$p)cS($N?a|Cqz8SyU*hc{G3_WSCj7 zAtZzV?B2T613ak%qm~~A7th;9I`E0fyl0AMlVGvl(~m+1gA@kHndEr2TlxitS3=Td zm+V%POd%PCor2(NHH$~S%3_>U1W?kYipL*%% z&pBQC9A5s@PQk-f)FkULg};4LwM(T)hJ|o(Q0T?NQ1eR# zs|>~sM*`ZtawH0RyKcvv*EDp+J!A9k1e2I%ocn#tw z#}{~RCz$#^m#`_Nk@F;fm-3pYLQHl*bP0kle5HAe4Tig^XvI`8$fF;rjIs2X{Xtc7 zU);WXlCgo6Y&#c7pO6fXoUQTA=d&K-ppeV>PUoidyxvg1^LgXILc)fygfWzSN}r~x zpPe+o7@P(da41S-vX%&Oe2Mr7Fh~n-gwY_}2D=zB^7aKtJeRY%l={QGXK@Ipq(C$= zZq2?~IU6l7`EHJh^pZ@`9Usa?!U1ALBP`_Dcfxi@F{^G?ZKn6z(ib^2kwaryWWe~$ zE>RBsCL{&1t)wXt(X}J+4~Mr2j}q`PqwyR!bD^pnGO}7q;y{y6632PhJxZH zVx!#Y`);<@*K27%c=hv;p<#5 zVIGY}(icTjrW(h|U}*V5R=O@SxNt;ckPw{lfF|}c25H~%s(P5Coblr!xrCb?;yMea z8Nmz>YR-A7sx0!Lw-HO4#Ssml@O|cCK77H2xtB^si5|&X0p`S_o=CRH zmkIT;uzEHx-8EsYk?PajZVHy{_(^0l*6a2xA^k6-@d!rHS`<7X7#S7rr(PG_{+~EfB1b8&wsZ(-!DD$E)DWqt8Z`MI?--A z&I8>SKe$uwSV=ezHzb~Sy;zbC$-&A=kHei4zv+rUc$glI+y1m`S1#;XDBWzcAp8+t z1may63d$?`%psJOT-m+j-+bpC=U=5l!XEUc*ohWD1sLDRMWm-~T>s_+{B>W~Z=J^N z|Mzw@AO_r{xo%*?*pyWrdS&&C+37)VyO2pf>LBu1_|-~PS&{6OLPVOjxI3AnDW`Cf|1FT|W2wmVNo1hxWOb zZu`n_Q;c=9RJD^q$F?#hRm+yc&>k(WTXJ+{iE&Q~odktM-jWLuHMKD(VRO8Y5CRjF z0DyNuwJ5ypPW7V0%F^1iNaF4B>VzLs5kcT<^!nfohyooPH zijexQXL#l)yE8ghp(Jc$>_oAyDPa>1f^#P0BA;%>Z7}M)LXZ?eCQmIZ z23+7eZubYCq)_{RWgBfHQx}(5gKSqHS7MucCj4V=e8bLYud1l;=;NTu*9#`mxOz2;Sq!& zl8J{dNOJ(ua+y`1<`S4-^2GDYSv57%+%37%d$&`O;5~E(j39e5ZdhHvQ6jrDjiu_} z%t??_Q_eKsG4SG%h4*wZJ#}x{BQgBJT=)_j+DP?b93M;BzuPHkoKk`rakDXOO3_ZE zLpSaZv^h^m6<(PjoX#tz<%cPz<%NKsTg!%+Y+2%>L?`%370H5VCcBt z)A&mf0e5Q>yvq^{5%LgpN`fmwzNUhd?Tqy$95e$7{3_@9n%R}|+>I^QgbVRFCuPI1 zL)$76(@qM4m~+k*MbYX-(rGhWOqr8-G4-W*<^)>=cTOyChH*O`NWhfVR+GRFeIE(_ zj|NEz{zHcqV@Qm@a58d_dc3SAv!tB`gin#uCIu3Y8a#JSdM)=B(`}mx|4OBT`ho#^ zX4Q&>{&C+ni+L%BQ#+Gj|6s7NS1%MTvuxXP(y@u!v{%50WcKgg3GK-+X@fwpMj&Kv zF$}Arh*C5TAEpmel->^)xCfs67$wJX+O5wT-yQd3_QJ-@{)6Y577p2pYPM74FjN!o z)%+2?VB0g|8V1D|s)zQC?gbICgnf4B$o4g_IRN!^CfTh&6Mw4MfARKnQXF!2XB#h3 zj7f3vUW`?IVqWHz>eyaCQaN#ECIrx_;_8}j8V8Iq(!oFdrvHtu^i;Ic-}3(G4>WZB z(7)HY*BxFz)RpqHxXC~NExw2HNX~1;jvJS*ms?Uap&bd^$PPsBruMbg6&t9py+zTD zFMs*Ym+ht6fo+PmZ7R>{xN2{8YOZ9h+l?HN5Ff?M6hj}p5kv1+kFMHbAYkK(%h=F| zbu%##v-l{Qi!;V%F0k7TDQ)GRWQ3)4B{QSS(qfctc*506V1N1cZ`do1Lwliq;tR`{ zD+4{87@?Ce#AGE0u)v6iFrLREv*IliwMp{SGG)P>1BUTw6)%+xh3DuXfM#nPlN{14 zxQSkKkZfn1u|jI>M#Lp=s1J035DT;ic|)AT`%@5K!O#S+#>fS)qRSrsKmbXn(keG8 zIZxnF+laGE?^y81*fpPx1v|ERWcs4LuHp4KBH$fMxHR}5WzE#C zWh^b8pf(7;RkfXi1BZfTA9+LY!B9!DcyfUw{b|nm(@eSu@qdvwaB83)jFntaw};r! zecHm9V2+?5Kip64o{8VOv0i!c!p3Ol3#>DZqUynL4jg!%maJ8lEc7q;FWH~CeBVC3 z(~*qFL66FhXSn(vvej9Y;bDzI9xrsf1l>p~9D_v*rB&YdWLH1zPZzX@kZ^t`i28tSNX*1O=(Qhv`Kvk1vgB_9FPsH zf<;GisnhL=1&CUaK5HNbZFu~Xf1Ztn2>33Z1TMD=FiY64>mkzewm|7IRunR!Q zq=pfyMzfB-st{n7&1r7YK7Cm1$P4zqGg0Ho0*rgPJ1*#*!O+tAyc;Y->1i3lt4a5Y zYhq4fIV(suq@OwIC|`L}u}|I*UP#WXrbm{Gj|3m#yx`|_PLLder_>`wY9!&9aBCQS zIYWT3hfx2iWO-&OhG|0V4ZA%zP-D=<@K{v)$HIGbvS?97awSGgApvtBqq*V>PXZF* z_n;7Y(Vn)1dCF(8D=S%lCY(PAN}5}uCCUe!gJszy6$@U1w`d!(Du!ndKNJ%Bp=`@= zDA!%&xJLtUVfr8jq>v3k4eseiOlSTLSn0=e4xmo8O{fyIvdF&tHmJ z^Q>!EclYe%xMdIa5A4p%*EKuh_TrUGc6xehhtegN>5?@>FAIsW?bM~C4g>2Cx<**M zelW6hHY2{IIj_2N`GVEA8&0PQK~dCPt!lExCxLWG(R=tV#9X;f@nfI^(#r)Lh>r#E07E)R;M`afHsm+c-pUC|x(L_Tjai z$19uAm*X&^@uE8e5tpIHUCOrRKIaLcr>QQD1EHH(a9fHNr~;dWBZn_LZu;zI7Ho@> z@w0kf6peuf%@bvJR;)EDKF>8(G|W@G|8SoXw~5{>svY%>hQ%{U+bmb4uR+shHqcyI zXpRKvAEFh1_ul8NwZH=#W(ZeJT0M``Tg>){Mf;hH$5yqL-Pl;#FWYn&nawm89n2VU;Kd5x-7NJ zulZhIlc@OnB>JH?vXka!iNkdZuFw17z8a4UjUB6DjF#d{-1fsk$A+R1ds~~rB+xC${#}^(B!gAEaHBcOQ zYXGf3=Mrt?mhkYG-;UcK-J9AcwkP(DQfHyor!BEN2_0?H6WvQx`H7h z^|Z;J)<4Mi2Z;n9rYJFX`ttE-+Z?N2_{NARFLez?_G}oc7WPtU-@ehhZGY^-w`|YO zBuK~YqqknP3m0$NY4h0LeEg1m^ZsLN)T&k!v%GxahIP9wd*|ednBJD1wN9+v55?4? z75&~)0;QNxtJRS*6|-Vv&)#jT&c)cSWR7f^BE~Rb5aw2aQH$BK63h0}U?62Ip00Gi&`3%pPG;LXY6a;XbXv zte)WjH}yfv7c0nLI=yAD)*o3h-gQCR4UvL*Cy+8D_*Ao;P#?E)E^B9j7_5}4hrOzZ z?SbA$fng)Ggta)v)ub5wSi*Bkf~}M!I-+~o%+h}C_<8&E)_rS-88>Jbk`sHUw zV_TV1I~dhHu4HRmvP)9dPXh^F>c?(Tf*J~+U_%`0Kti0veZe%;{7<_lNOxNBRqdkSvv|xfe_ANJL;>@5djr1E8m7H1t6{G2obrJl8k{|)XB$^!~A^VOZV7H zM!d=X1hoeNUiUS|(gm$Gn%jni;C3ishryH}g?BFAes~F$HKyo?6TvwdE7;%s&Za1q z-h~EIn(**Fq>ZVyOxmBk7TU)ehju8~}o~xq>ooTC-skf%j;OmUoOemsvM0qy8uFcmar)}G!14Rix99Sr*SuxSK-AYxxmQu#J3$8XBXkIVvoqpLK57PFfqrB!B zV&Q5OplQxiz?ctt%a3hx*HppOb=-uu5TO-63ag5Jy(TMojM$7mn>O z-`=<5Ud9Geij%p8g@dtpR6(>ga9)~ThISgeWcPXv`}SE?b?IHvFA-v=Us2K=L`D?N zcEiy5MkG-M295PVl);5+06EQkrBBeC!Y7l*_Io#y^2NLE>~K1yL4<12AlS1R1t3w z{S`f>VpmGVOIA(MM-RQZ2{#~DvtxUyaVj1>6)j$f59l3#I<>#`)@Pg#csyNb$tQw^!*-6rK<$ydkC)k5m=ll0!0n@{cHm4PnO|~^ zBcsYd55RMd^C}pJDL$F1kHv4y(6oca3)dYSK#{Q#!=00C#!%N7AMx&H>@cunkUE>@ zZ99ioujDZF3_ar&jJCYU*t_vhI5v`ec6ZB>qmwwS>lTs(bEbt>+kd*ojC=NhVoN*-Rp@-FqEj>td#h8(JtYv>g!5=#ru;*lX`ZhF;hOl8DncG`4A&HUReg%T-kOnU!lbcb?)v#U*n{gLQb)vwEG-4iO&X z_|hn3E$k=kKl$b*qF$&Car=*6_@?bjx7n*T?5(#R*g>~x&wccc+E%b(uWR*WR`Yx0 zG;42b!}j-&tx(GOF3!$qXzw02MFS-NSIbrrUhj9iVwW>3mrL$I71JE)Xkdrq$kTl& z-o3L~v!rw{Xe0*vtyQyV?6ln$y8kfuE-A=$^ zsRQAERX7uh{>8w-Zcn^H{6YP@bm@|ff{~BsM6k%m*&$lAFF#J%g%Ubm6wc`|e+UN^hnwRLDuEPmV9+FXg_CKgx?JoC6?5`=s;C+=<>@ zr}gE!37-B<4E~4dcP0&v{$n_tc??5t>4q5EIuSP!A!I}N(VP_QPi}oxLQr5AvpHuz z_fGqkO=s=WjiLTr(ljYGSu*@)q) zUSI!Jip2{gk&&zdNUc?lu2D4sBl#JCJe*vWRSCB>WY6OtT7za{)gP`KA`*p*U8V4k^W z3C7FOEU&hW-6)BIbR2A2DcMurE!)X;JcI;71O3TJ-jfosk!phlt)Tgk^>M@?p=hUj7JxT?4eY`_=A<8?77mS_=Umfh$4)_bwBIMc!Zvp@4!s%SF!q+DG1Ta!1VS z!DQ|p$)_XwErD5N77uQe?)zsmF;6^-*y<@I76DED^An(@NS1O%^$k&63YmVN_C~fL zWwfQKk<%P46SPy$njs4XF)4gw>!?0Zwx~Hb<pq=HL_;6>r2r|Jc|PRZb!5=tND@}*w1gjVaEfE9inAY7?MkAU7C9t5#3xiZ86cX zSuCabG_vDq)&B1NS2WiJX9@E!?+$G{*|dLtcujR_K1oLW>o0xNGE%5}5(4m;Efxwk zkrGVIcXm18@#>ydzc z^tko-`x~oE%Fs0#cwhga7Z`!~LAPG6o!WEd6Ke=I@H`aUh}z6WdsB9|zvITGlVRGv z-oB)6BM*z4uIK!Jv1sce<3 zYm{)j2cs?UEZ`D%7DE$!4cTa}cX22Q=8^$dp)A}>nQ;`%G3dBqO8Mw2JC{ZiyhRB! zp#jp^!=nhFL4AM)qawypJR=!Zyx53=JeQn6*{Rsr%O-E+lPP{hS-QfY86()J{)21e z04Cje(G6OC!I+S0EY2c&;I*Dj$6aP{-1o6yY-pO~K*>8S!qR%`K{f>DZj{ysn6OnH zuli*?ue_4$B4}SO$A6>Jb-g{!z)KEB*b+{7$7UO9_u*Jg=?^Mbo-Yf=J zi8~r&)k=GS6S9=vL!O~6#N(#h(IIr|cOv6+&tn&BF5>inPzKzak}2^}&gTk}3x$W1 zXfb0VS)fs?*kSX`L*W(5CF{2bmY4jTo)3L&IqM-ZOq*mjm8~{n0P=PTpYgV4(FAXC zymXNp3EhHWi*X!Cu9bA_GHV@oY3T#VUG5dFBGQ6CpvRjzCKO~WeeCofIR{4pH zCXz!K&+$a^n}iXJix{k!56l5@DVic01ImU72zKBw?WassVB`XS`)$sEwIKx4*u;7GFM!YhmnrfQw)6RpvB zyVs`XWH(^WT$9X)QwxUGSu(4!&0EkLT8h}g8oQF@P;hH0I!=7#Fjlnx@j=Z# zeX%Kd5&D->{n27os~@EIUE(!^!8g5|5x%4)gFX%r@j1!=fBBzWv_v7&Ez+9jf9b~8>?f|jXy5$KUExSzpML(feWf+9 znaaP=Xjnph9fg8Tv1Ir5TlT``iuz)9_u;(0E*QaxttW||4k6Nc{qvZ8US+GQh z;mjQI9_gAa@}#7*rv#UgXpm6EcVXu7M8@N~RI+xLc;A}ux`$UVJBb4^F6LM%D>{Q? zmS_N>ItZshI42x|(8&nrQqC;wZ+`ub+lhYh`Xj4Jr(;eio8xP=uppe)3|Xpu?y1k1 z3TJ>(yE72Y!ArVmr>9NPRN-2!WOM0|#OGdWJmwnjjgoLTnHQfU6jDwqd7!dlHVCC7 zjs{k%7sUS}J~SVl+24BmV}fncZq`S>>-IsfARSB{6`~Q&C9xP;M=}d(Z)0Xpx~q9C znogUU`#3{!Q|KW)kv^jF+0ISumA#35=~2!48oP+G(^-8%EuPxJqIaX@z1K(io+h53 z|9&=+m-fD2I$zGSY5flM@i||Herrtpea+$M7T;<6>$ktE@nZ2%^IY>Tr}5@s&kMB; z-H+RF*t0i|oA#-XK5xy#6XDO;y5qn$$`w85oT8#Ve0bOXMgO9`VXvwRmdaG0FS1jI z24`(!0!Gy9O<4DZAGDP`e6QP2;+bcD?=4T%L3z}(y7e?ElaI$5mR$4U`uoB62a(SA zi#pHs;b~guiST0;f`dkpas6=p`-lCZk)&sTuM_vyZ8_H=|Eb^py?O?6Y2fi5bq|Gk z(muX1wm(uk^i^{4KikWTC@ndLt{#=+v00+aHF6@THp7gumD`g)TeXYtH4>Bja@9WW z`!hb=`-6hvhoATVFlOtIehW`tsCMi#jkhf)hI*+yuyC2Ni@By1BqT}=ag>5_+$kQ~ zz^YOlOaxbqR$SxLH!j(=z01})x-X&AY(om_i??5~&dITzg%ZKiVzOc);`9=P6L#F{ zSg$`8BgsiHDv5cFT&Tzv*xs?U%ax1^*BLQY4q^+1uQ}geD&ntq@)Ah#B$?+cLM0BH zh{8Ucs@&Uq*F4_zS-b1+BqWS2B{)rpou+;k3q=VS6EWb>I1w3jm@pq0xJSX#vbmyV zR93xQaBl=+T5(VXM6;Tjig_j6QSTAtoM=ypHgm#hVH>0OKnM z{~@d%4<(FBk(!A}!!Xk+G0z1tmt!72A}7TWVJI!76(x(9jBF=uj`2lzr!H z+w$p!hA1z3khQnFJ8r}-CELE`7vlh1e%YS)Mt9F%ZX7u#afl8F69KF4B)g~-EMtry9nFJ0jgAv@mg)s&a*qAFAWRfQYFNs;1>LZ)^IHs5J) z2!3&wjxc0A4b*48^) zqMO};N)mO3wTQ1UT;xw@#VgZg`)KtoyW8LO&`W-DJp5->9>zO5z%TCc!Rwjd(K9~L z_4yC?*KOjLxT(HXG0*k(Q;gB?1;711hCC_d{iRJ-yR*-j<5P`vdEZvmP5&)X=)qyvru=%`1g7du8K^ zeRg->{+){t>{A;L?B)8gFEm4kC%$m1Hmgy1kB!DGF0!yb_fQ5La=2R<*{zBs@C+MU zF%(CA#=yWLB8#l-6ndwX6O9yaoy{bsvv?`E#Af1YES|!PF^o?Hd-W3dIz05g8xMgU ze154m;kBx97e8==z33-~az6-A^>O|J{0}%XW_YYEV07vP;UVZxwC#W8^(wv^!CW<{ zV8XRvRDddbJ>rk>ClYz0h2$ut80|tIWlVIbBz`1*JzbauR*wGj9Cq{Ur z_hXU)*x>_g!MC}}#TZCQnbgdZ;&lZU3zUHn2wu9r281O^V#tg7&p8IjZQKBczz^KQ z@QdNt!_TOJgrpeiUAFAIVShoqbb1+=d_`aMQHL=I?i9uUTid!n6(7vl*H0Vv;?B$s z&lv7FV*{^8jH!4wB3I{CE(y7b-FFy7fj4{`Ie-Ou77#E-V#vne!dRp=UK3(LGtPRS zor5egmsIFDl#DfDQD0-AHdALX34Ia1SSs7N*Rw*QZ0Y4t{Z5MKYdlm6GmGVVyczM7 z1%4QUqXV;nkNU0t(moazFj&l0?<7{T-JIa=#+_&}U@4g_GBmMJAqpaT20Ex{FPAoB zWMs!+Je{|iQe^h8}b^s#JMQMW)sl7#ja% zCU5;fu$m7=gM>4p_32sP7LqZOq6Im@(BqG%vo=$i)DP|vK87$29CCQr8Q3%t8I#d9 z8rh^ZG`J0DR}e`5GAorU(!D|}7g!Y49M+trYz*M+-b)Ivi8VeKPIH(gPC|M0+he!W zd%`j0#h{T(D?3@5hRNZFHCS8(ZjxD6tO_qrX;AIaSX>A8ixJA)h@o?0Sb zwFZki(&IwGtk)abhQX+3!ziN zeJ0+3k($tVXYG!FofZy?P70>zF&y4bNFbUfNyuLHJye}Ligr6LcI7~`E6s^iir%NU?Rx1#?$*kY)TBB02 zzHqSJ62I2mt2H*Q-E2p2?2hfL?W^{}R^L9hd1U|M@kJYGoFj)N4nH^hk3aghy|5eD z=dYgGC40j@enos#^zCFI9+8*{KFY6oF2({O&=+(~wu)Y0a+80Z$oK4rM85TJFW{NaI-UQ0{+rLU_3%YmO7w|)>SHN0 zvr1C5L+yjdq(t-JIoq`zd+_*?aJ+Ay`}nKYJvy~|rD`Xq!e0^78&|JeMuOotAG~dU zyZ1+}X`3oDRMV-K6#*5ripw1}iMqMw$EqEkR&9Iw{eDUC;5~nL{aKau6jZDG)U&S3 z6Zh9i_k29LUgiHie@K*her(Qv*7fmR3Bx$I-;B1VV6#}-mBlKtaHYrw3kmur;ZKDSm$;B7%*fa{ zfX%}csJ#f>Y*)&`^zh)0b5H{Z$gvGkN`l6%m_!kt+oR#OVAa?C$Y6`t08cLfep1y;l;`Nr(3BQwfSohIX%0vW;xpzIt-i zCX1}@F74fR&9=)UwGYqljD+N=Z50;o4TX|(64rH3*CGo%TP_3p#_46zn4)ziS$nse zx4j}tH^QeBA_=cCwkJ!O?FMrx7iAxw5&n6o8h1EHz0|y}~{{;y;sZ>@%L|kJfJdxlGSvwt> zlzD^>6lw|R8uLytlh8HNy^LKbAcUvvK$sF?8PzqxnGzIIZvyWOnnmM|$gO&rJ_ z3Gv566`=kXCCDK_mxO2%`zk8V@&FhjMZi4}VxQZbwAnL#WabD#=K1@II z>BDjQzyxSSTi|*9X~MV65@x5CX}M8Ej8pVPd`WbtEUhsl~be6yLx@%R?$a{8qBy zSPcngn%~)pz17*#J?iE;Poa~TjnzOe-*0*q{?Sj2a$NJy`rbM#{K)@_w)?|)WE{d! z=+D(g+KJ6cK%y4O6*2pz%XgI>4=pLVv#b?3^j2kHOeLQ2M6%7b+Q2@u{m5>WPsJDe zqStH<&A1VRI>Wi>Z`#}#S`fc1h@L_3a^lNBv-gH*+=*yfAo|0iCFaPq8`_wK0y^wxBDhy9&(u%Bm>8BAjPYC@3BH-6_?=+R0ZI-d z&xS&cK|3i}5VK#u)slk7+`|UZxyz3kr9LV%cfB|Mur{!o4oH^JCy ztT7~zhf;Y511nA`dD^Hf(P9FP!2lfXf^q|zeqeA$Zt%n2gfIG18>8*aEDo?3zg{$; z96X5eEGxeF*YAY*A4YRLZT(#;ra$@tUQlb?Wq`4LE1}@iN9Mu@8J~uijA0CHH ziG<`$n+J9ye{5eqz3Atx{OsOi^-uFe<2#c~h;e&5)}+-~5EGSzj5-`^Ug{h9jQ04v zLAKCy#!V1&nBwiM$9kr5z@t<1k1z}vvqQnQC|NX6T^u0Hc;p1jh1%v}+Eo9=yN8%z#8YNR zC(|6SXyzkja}cJ;r^5s(c&Tz3>9WQuslIT?-s5i93bne2W}6NI_nZa~`vTHY^UO{= zEat?lT+LZYllJJit?^h|TT_CtC{TE4B%wcgx*v%C(aunfOG@rd%tnFrL=8o+-jAo^fu{WA#_xdemrM8(g8POBfERIY5&jH zcWsca`(nbMy3w@#?%e*zZE(`IM@K9=4y4B| zG=5`Ct6V~$oauK;V_KB#yIHLXT54}seP=gBHgBa$)^?>!$2C5~;n2Fnku`{|t9gu} zJCEbj&bIfV)f?HRM&1q%4lNu=Ul+Vn`Mm8bU#(QKnPh(!v>=w<5l$&AT(ZEHanEbU z3lC%7V@yNA6{A19Tsd47-H$lGc+z8(FRE@rtblh@Jalt2{ zIfEX?0viih1y*{*lQOBCbcfIaDah@1&o1rm*wMoS+dn$8O1)~ejfyW2#Fk^LZ*1D* zGwH>-f^Fm%_KDrT#l|grGOmfPr0mbXa41|E`?(DLe&0I1zGW+QOK4thP2aXra>I`L z=>2LB6J9W*yIcZd&Jo%lH1x~tVXr7Sr~_&%&PUK5XqYGcjszKfll+U>em-$?mH&67 z)qDONYWhLx*)rDG=igsn>wA6aZQ*xR_DK5e$Lp;KH-vNO%2SP57-()BJ+jY#^b>af zo%=46JUKnq{HB!?sL6v%eu_%96PU5Lnj{-P!bgnp#o@sxdLb7a>FV<{MB z|KNDr9tFhuQ$4`nfwHbgA4iOJT0i5GvZKrB;{4~?cRox%x@kRLtFaT&c|6>7L3%W;TRO9}=gKKRCg$Bo z4-D_mSc((dF%tLfbU3#=H!oYPePW>vMBH)`^izI9Z(6c?qPQo)HndhZu%O@eEmJ6N z6SXNV!7Gr!T_RC0MSZ&u~!R+2!DcLSce^)w1rL5w=1zDTeZ z)AG~P;|0}Kv_f10NWftL60$TG5k?tZa%;->^`1pn<^+v>TY zhi|xEI&nbcFxx9}YO@4$1R@D^#B#0*zjn%a`AA5J57a{9CXWPD zJh@elgq8VHLQy#aREBuC^EC0_k!cr*|w1XEYMBIN{Oq?(=Cm3-6c z1+`xfFbs7hTqY7(``U5dzTJ`%B|ND};U;WKqp+|qKCaqkwr`)^8Q7*BGkxyCkgJTQ(2an;L$M8@Y{89{v-SgpVTLvg!QPD*Lva7VoH z=GGpeJ`neMAq73FvgURcVj#c^CS%oH+Qx$E7$FM-fX2Kzj;mcodv&90AKe(JZ!>$` zOK5CkwwLKyIT6~4^5o)pa%Jt6?UD@#9ecOc(U7PB)y-D^xaJx05$P8(2!HD+XK&4( zvtU`Wzxa`&{e>4LEDu^Lry!-J<(^h7*6cT%_S)&Dl}j=E!pGFE zzd(C9L<}P^3r6ff;6T-w6sjoJZCt#a1A7v78X^NyCUtYMg7-Y~z;wZxkKV85ruNas zp?F5dz1|2_6_Z@)e3V5i@#1LVE#aPj6m>F*4gb`}U_VziuC|9oR4Iy)8bLx66f&y;MK8 zokCx<7;jd>8|7?>cQ%b&vaNn8c+ro9^Gq6#@;#M?IhdrJo|dvxUl7jd{#<=!x5(8( z)3#OqaFQ3zlo}q74B&(qz{9Q=CTuCVv%3pE08gPVw(^SXdG9c`&L&gINjU)}GNR(4 zR>c!c%Jy&)ZSlugtLAGgm*V+jl_{EK`E#)1?2RIY93j?pmfQ|;k^AqzMk9EeCgN%{KV&bcw0n3}-M=|GJ zcKXmihTkzj<#K*UOc~gH1&mmjjU|L{OFTdI1up1acrAuF!gIxdi}KM<>cNwmtAy7V z;R=W9qS#{C=QlDFF!NZ-^k2M;-CB5Y@sdOiON#f?m!#T7`Lq>0;u_}wA0Nql&c}Hs zIU-o#nTvrZGAz!^KP$fuWXz-j4|R98U=$S z_>dM(Win}ZoWP)i5vY>Sxy(e{@!+H{i<$BwONsZX6gOg%(wVHc9m5`og@GC)>m-&| z88a*7i#E}mb=si%x*lqyWSJ~-^uU$@hi*p)RRS-z&5wl`)SXv3zyKp4Q=M4gIl-9u zlFu;qYLn0jBWFhMvI7kWkLPi#NcOr0jAT z!!hHPv~odmgm6El3NXMEdJh>FSpj378+cUoZjl|3sz_3=8{YI?6mS_wykqG%vPBez z27_}H;sQB``pKvNk~I<@_M@c!bI&ma{1xnpd8+DE)>3mIuD-LAPw(kDJG=-j!{U!G z_US%hiHbRP7YpXXi5b>ZWc9do0g05%RlIULvuM$uG{K8nZDmJa%*)YD$x|_v>x)17 z$s!h`&-{(&imnTUG+uNkz8tH}gbme?lrl@(umlFpaOSu{eC7ua53E$L*hq4pvbs!H ztQG|m;km}-#zxXwlccwIDmjmN9L=AF4Kx-kfMEnJs!HYnwB%B`CdxVU-D$|r`Fh=& zdcRUHSx&$AqQhg?5&@5aCrb(+5IUH4EE_fxS*Wo0x+o)JpysVG$OF-}S zM!pzQ5x#BY2;ZSH7HO-+1C6s}TE<&S!_{KnzI#@(isbilDGF<{6fXp~;21b?cnBhm zKZdlWaJi@cz^-`4j-iHR>i_GP%l7NzPuf7dj`Znm=_0)Y>6meA9Y3_Yj~?6SKl`#B zh&OZwBiq(o>S%r)woa{B%iG3AUGR$ARt;IVFBy9x^w)T4Tsy(S9vroWqIu!>(k@i9 zelQ~XA91TsPmV1wI9=J3-ZmS1n7u|NZ`oqm9zH&D$Bbaub6SS8R!h1pw2n|FTV>#U zW?9W^b|#HP9umSGcFJZ2>vk})Qb~M9G=yE1-4S7KM7_}?^?WFp#zl)yq-U^T5^!!3 zi(RpV4TLZ36lQm%rmNruACB-9novcLN>*&ID*BKG|Aj}Lo_JkCI)1_re1xw-yR*W5 z72}IkEReCwcrY4?UItN!y&ev33&D15W9c-tYDLpP`XP>MBF2M}+NJW@;ath)taW(o zGS6Ieu$WJKOlzojI+wG<~y{!b9BLFRc6@efn>(8}>JIIV=DyR-t*vd%=dn9Fcf+1FHmaJt;(5cW zx=WeBBq}$mhdR|3;N*8_^`^9TxyOJH)S6X@d<)gZNbHJeon*HASa|KZL`g6VxPv@^m zT(1Xnoz~a?x-j`L{lO-Up%cp0xJlUfcJG#Lr_O9AdE{OhZ--Z;sKJCIV<$N!AK2qy z)2^o<*)Ud@a5c0?QxV>H!M3xZ^#(n=e(9R%a?S>wQ~SwJ{-k~DTfb%-mtOS47h3&} zRmD6wh|fJ^CAcioV%QSwi>a;!qnQX@Moc?&!4a>8QZ6GV8y6E4)0I#g1U(7mIrkpn zq~*i2j^&bK4r1gg(o2<>AVZ7{^W-(J`lx*~hAIJQ@}%n$kjS1#rm z^O;?caQ(P5lK_hmB05$4pi8J4l^q*K2foCodJluLSw(n-ki6f+Tax(Dc&3LIOi||b zj@r}<@CM}I!=>OaVLYYrSPAESH&Uyh<;+e6x7H->@Ir7Qtjk6r5*VA~yyh{7BF@wf zDYl|1L(LUDGSY%YsP7XA`z^LV1N3i=Huwh z9<|P_x0qOKG_<)U6x&lVxZ_=Tb1!d=%)tANfny^(v74oqU8!X3tH&6k!Phm<`oo^0 zIq38BJ)a+?w4x*b){obEEY|7SvH5_cY?vXYqTAzH-!6&%ey3Toy`t!)9{bzEc?^^3 zINOu4ONlm#w-I88ZMBaFQdWm07Lok~e9>RLa`FD-u-i{I9@y*MOKyyU^hb+8qK0cDqkfUt z>W(I+ov1*_ES3#Z7b6?4zZ0% zv4-CaW+~CjpA5m`c{ghxt&FnN%<+{e8hxamvl$}j- z?o~*eoD52C@o*EOH^?WUlur5tzrmo%qAJx9vI>7n;@Z+HXSMK1^@n>XNt$iG zQf5^bu_Xz6hC!Gz-4j(*5#En6OYBkQqWmj6Wvf1hj_2^fKunc3IS&(!b!gHz$s-tE zxVI30#ju12HlD`7#N`MT>U|Whh-~W}WEM4=KI?+=IR^oJ;+maB95M(WqcyzifAtQ# zXUIor1>`sk75cft6ZJ*EF<2791cN$eOWL?L{K0?0i7C5o+^8Jk3r20QLyy!?WH;)}sN)!AXy;PpEY%-kW8%bcwcNK~eX=dyG_|7eqSK$-yTOL- z6-K@rkGaHlbPUWz4KlsO=!o%}adZ4sc`TMQw+Ub2+tbZO%w0M3zPNV4;L^ zILHgtkhs?Do=W73mY8!-We9+kl*UzZgtFOnkp!G7z>}=%Lykq>p$~Y&BkK?vLH}Le z1o`;q^H<}6c!*O%tm7yNv_Qoa&|Tx zTRs+AXNKM(oDWvCLiJ-vBu4X6v@jvuOU=fT!zQA4V-F>f68taMYBuWNJQTQbc5i#j zorNycYxd1YPdwy9HJ!AQ5a`lo-MYQLUEA8Ss(#NWV=GG7ZVyNH+}^HjijT~O(kTTS z4pRgsBaJn_JnUpZGo5H$n8nH2#OY35I%qnrG0<<~mJ^#C`br2!#-4Fx{%;ioXUY0w zbSL$xs&`I1Y5T9=+^~<`tlEQKq^~SBwqu4rU$8&2dt~uq-LC93?D)7RoM*hrGqZlb zXM0!nM1#yu+o5=5(ptUHM(AO}6Q~3SEaFhrC})L7;wQS_3x&rj2fl!p_eP`YZM^s7 z)cS%Si++{OEo+^&tX40HzK^Y5t=ds%;9(}yq7@mHii zb4j?LDrjyB8ASUyEU;XuiJu7Xp*up7tne24Q6rAFvQ6V<;~+`j2}xOckHwN`*MjDl zl*b}uReeLx0o~b&f?fwf-K>>FqtMwU-zS9Q=xq=Pz0YDoS$qypY7EgkCF%dAqRS?P zK*{8@wp%IK=0@EYOWff^c+u9#f1d24el`Z`pDMLRXOSg?3>9J31=D#GK8rxVS=j=j3k z5}gF6mUc8M*q^&5`D61~yl-jOH=z}RkNWkfi_ukmRAPbD$sR-m_78M;R1y{`31y-iYY(Y2x0qaQZO)=%&@!Kb=5x z>s#3_Cl759%iBwZ$96nxh>7NeU+b}!(j=wfozYd{l$bk)O%bAUykkY{T2BJdb|GUQ zxqidG`_AijcyeH0_?cg_Z+_*U+n@U*U$B^jjFaimSB5#jD9_4h*tO)eE1?`ADl2@R z`Kl)bk3*B#mWqJOp)Mmy$3+RM&?B}+iS8leSuh&dR&~d2?d;hnpLY}jtOZPkpRhL9|pfH51RD2g<3q45G63Pvaotfb#0VpjYi5QHk zUcw}?Pf^Iysk{VBDK>Mwp*1S=j$n<(GW@n!vo4P z|Jdq?Qoj)F*(?cv{d()R{e>Iv+AGxq`-O`wDQ;bBPKpweBO&c*l=AQvhohum$yViz zeQc|z@fiyaX}eI$={|>2DmTciw!P6Q*b8-yn{Y6%{uU)+v(Pb?a7Wzz0|}9g^}d9w ztwPLNnnP@l0>^}UQf%>d#4B8F#OR{_^)=tZdEO3(bN{|vW_-XCvvx4H>k{62;ll8P z-z#Q?>q`l+3+v7DwpoyHC>RhUEu4?-QCt0*>V9tMMs#AzH3t(n4uLNT8we-Tkw;5T zG(&WyF1%zhMY_8c^CgYP+*+f+L)6TLtAQl;PIn|BGiF;mn^Jc1SeKG+C)SYw-%qAW&qPz&BPoL7$?Tw+ zXwJ-~jN@S`GU1`G+TGA{i(`9zcuO~6pp+XGeAuhoc5!O|{`E(;HGbEA?sihVs41R8 z{Q1bhipM3PtB9}3)^`#{OK4{bgOKKUOd9MUOxfH0ZO!?ND56w#@iz{6#ZMYsdFo}z zN4x{0sT(k9C;#*X*VBSKkB%(KOKwYLPYwN>p@*E{31Z4{tc`k@=dgoHl;1L{LrXJM3GSQu3!!>^tQUc}-?*}wpoWT8O( z8&5pq_yPgFrZ2rG`C&Cks+Y3pgZPokVZq$bcF}V@bb&0!H;fv_k) zTls;p0HVGqlfD=w+Nn2nixSrLAj2?TczkAcoe@vyhH1$sQ>Xor2QG#}@``VW=F)HX zURN3X#z@FLW!E(h1u9Ft0`FPsLB@*-ZZwziWrq>t2mf5-241YZ5A2cu@Tw)zHpUIl zR}$@si~_2cHbh-i9SIZmOR)|GU*yWj(8M!#Tlv9*`ptOx&Oh-V;`f4w>?8`X@L}9z ztRy(pvnpH9@HF&AaJ2`IY8B!J?EbP~_xfe!S=uMII+8OIl8MY3)uQd?0yj1j{=@qr zIOCY%A;YFi>xw_K9Uhp`Hg&r zW$*Npem2H(Jod%%-0A>AyuhD?3CRYbJBiRn^>0BsN;1kyi2K{QA}## zrpkv`lyt43_W47&142{aFjLpKWvf*WZ_#Tu)pzmVWZE5jh$Rl)EOSng^t+iG*Uio( z$LC5L>fh3a%>$3kJrImXv#f141doO2$*^m=oam%IJOEN&zcV+QEEH- zpxMQW=G`JE(MWSRQ4%iXJf?hpab`hm!#a{{luh)K^MIym53+^y_Cd~0qyx^>1_42B zg-!|wb*(GC!OSHwTI~CFuJ4k?Z9o{m}i*bl*18J%<^K zp%ck0MU6pO`f)m+wUOom3um1~)`p!U`>o)PeX)1PzI1w1;}zN%noE6xL(~n*jlQ1t z8(xV(L!PH?ejk|7&Zi9}t-sIT`=IpfbIRx5>b@7D>vd7*f2(br4S@ZFF%&vSuk(!b zG{67)pO{q0({j+KJqGmonh@{Kf4^VN-s;uo*=N7U^vtV_k>8+NdaviNR0p<~=(rJP ztf^kem~E#5`@g)lVcmE^*(K$;)TPh*8=$T~Kaiv{-;>@4aXw5x9?9{7mCTGiobK66 zxp#egPJdAqW8*}7p&!G&MjbIswj&+|W$Vpy)<||ts;z{!j2%hv`TCo0+x6{+{rpe= z89O^YmNGiD{lk454UX;M!I9OswtaQ{_~h7LxOCl?5>78)*p&d1kbp80LylXyC}KXI zSXDyKS*vYZTbma2&LmWATCdlVGHsTZP?i-FW(yK0fd>+FFxuX^@`Al^{kpxdch&yI zYrkb9y|=ZqV_$!;Zw=Mmmk^YcR9VaCtd`1JIbX7SPY!J%;d>&6hrm5oAK40v#{-_a zMF~O!G0N5;w2e&Qpx{s#mrm6N6akb>6cW5Ic*Klg>mW=z??Mrt9Ffux7vaVLSH%*m zA~@)X?a~PAl;K-V)ectrC0@D!(hMYcaKMHHhK+pHu2eV)I$@=Rgf!jHNhlD%aA6-M zh10|bc#TdbY6l9r7^xUErw9{zfkQan9bUAXr33pX2QSzsH=lTj4GgAlbvErYTkmSD zm-a&Sz*<4UUT<9#O@%@$i?P-l~&NLAan)djP(_+iG|NNlZCd|-DwHCNuU@u7RuA`DMmz{%SK zDS4%2S0pkgVSV6UDWMfz(d?=I*m9)iCY+fPbDMa`9&SQ-JzGxQD9dsHN-&2ixmS(K zhYb+ggCPzj_=Qpu##1Rh@xXrjWY_xBxIG@Ah>q=Zn}_yRukK?g$=1%skykp3E=F_& zmz$NYd$6;rjCb`xU(c02roM`ms~+Kr1jyr&+9?4RV+O_%6veGV(mE2BYJ`YUd4cLC z_IO%~Tu%5oP-Z-a*anFQ-5?nGTu4eF$Ed&(Wta*wX!|xP9;oD-0PVI ziUP`FLc*m4XZoFRqZ7<`VOtVVQ_HUAy#&4q+e@bs){^$^X4$&ajC*SL$Aop!9KoGx zA?2}{x06mw6ZWbFnRhx z!$Ju9A$)(I33vgw^XVA{;r$Y?If;=1JW1Mr{Ni_{OrAvsgmGZ)S;a1vrG(>UCq)yF zBIX@58M?$FM`w#oyW8V{7)jL7aR{8g|MZP_?Hk7h8&0!!V?*?HA|+M|Tu<{0V~2Ya zDmw>j;em?b3@;FU?T02eI|vK813I{Jm8jYlQ?8INUlyWl}hTw#$v^#h}2WCW%>+KAU=3LYic zComifrfzVaO{~j7#wtTul~*!^#uL6611VV&f+NsJCu3f zS>r+%3J`{1457#(7}_v!M}23Z6oVZ-a-*-y7#L(RKu5+ah#($X?zyZ^;7JQ?@ebx0 zVJYCbD%cgwsuXaFXTaQ`OZ{pG_0n&QwOn(T`r&Ue zU`bo_Oj4VkN!C%lgxzpMwCcmN7{em)0p7r#@_+&TX5kfi2(MSXS266dyDJl$*}`!O zqYmQ=FNi$1nOSb2)3}0Xj46g~4AsD>kjr@e7$jM&#%MN?43ib!vmi}dF^Xa s) zOqdqt4&KPbKkpKIRCQtm%q&Cu)h7+{#f9B0vnZN$kJ+s}@|^fTd`bOaOmSSmxQTHF zqd42kX){X-8Qm}B@{&U_mg}AXrYe0*7(TS(yxNGtdn{b!058uF7mrpSv%;@nva~Jn z*qFu@uS3G#<#<&vDl5-mp0XV&+UkO20So@O-D+seeYC+-{;G}Q>n+KQ70GFY2%8HRr}L_o$7lz9K(>DZk5#79`$p! zkwwOe7W2BCl~V{K_y~?HFk$$_+rKC}NxWUW+9BdTAM}zhlsIT4Hw&tjjPP7Iq^|28 zZCBmuH@jY-zwD61TeLUmTRxkMjCsoA2NWtlp7$<8>Gv?y995k&$^X<=5P{0)vz94U z-LYXBOWSdKXoszdJ!%#$864Z$U}mA@!AYp`k?w_uHQ_RE8d?_x!?)$HiW zndJ(3%Sn!7*Tir%wqB=iNy%y)QirVD)^|KtwvP0$F$*(+bSdU<7-$|OZL?GqolwW7 zOFP{^1|rr9=XR%_lb)BhB!*7S$51%ZI_pY@$!Q$K?*L3Hv*vUU&Sx9D$HTEcNNVZYq^ggxk_?45R1@J(7nvg{WwJ+SAheM^_O z?AB((PF3$xa|LhEt(tVxVc%g|s}vbY%{}JN#7axGGhWj?Q~4UBF7cGr)*&HzG`@vm zNiZ3UTQj3p<+>q#uYjrNtXHXB?+B7Wo+AFH$~_a?Ej!DLb9> zB6ci7ItNi+4vgnCBktf_lyRCW+NOD&$&{Rz%+QI{o|5GKqIBd^AtRoNBTL3^hg4L z&t-k-o87-r;s)RR@r!fc@0Y&cv+tL9kBM>qeXifHJl#VtUtgd5aG3mV@<@CoXQg7< z;mA&zIE!ZLceC5ET(x4qcDif7Hhk4ui*iJ-Boh&$lh7`n0D_mv!&TxZf2iB9&pnH7 z{LUm=xS@@g_P$@q5U6T5zWi=?NN}{Jcb{@=a4(r zZHm5rZ)w%`rytU)5zxR@Sqb~dpZFUQ@BrjGBj4-aJX_^{n)ppY0EU4jAHVf+Kq=8^ zkaGQd^@@McG+gG*~%#OpO>-wm$YPNHSI=@UDcZA%CP&%oz3F(pN~78jv^zHr~( z2yfW+;+dUH$|6*VIx{;t()~BTWBa|K{oGIdq!i?Z)hh+77IIcu#O<`xw&85#E6WIH zhs{%G0`W=U9tdj&%Zh$WWw6@JY086sPpB;>Ev70yWGzV?xnjW|Sj7Y#E}kzg;OTuc+;A7_iU=44SqsIMZc_YxHxN(eq#35jgoMd@LiWfEmw(=(qE zql5{IK4c|ml~s1Fn0C)y;vPe3iYb)Bl9bfBT`B4vG3!LCVwX#JUrSkbZ|J4qNR4>O zqC`o+b%|E>VW7@trNnTMUD5?QiE}O#^(Ew$?a){6FP0}(W1F)CmKSSJ?Ay&7cDZ~S z8ICp1JNd2@6+DV7YCo#AK&JbT+PikAb|S$-bzO61j|@xB?+fKZc-{Z5TxpdPN8^14c1-!oHmSC%iKo7t?m5M-su(WtH)(2UK$4>6^EH51h>;*BwU|sPDq&2`;Xh2FB;Fy zqC{xnH8HMx66WzfD5!nJAk0g$4s18A=Q$`UVPz>z_j`Czr=-*l zT;Mzz1j>(5IuaO}FKqE;Ji$w1rf%kwQcMtjqj>QgdQvMDgflFppm<7|&)}(**4R%Z zyb7|aJEpRF1HnOMZ51l6+>Z1d!+9(rr7$12Z#E?*3MLUBjOdkq=<|m)(f1!l|9@EJ z{@b3`_z0!{UEoL7bKw(3%#iiUsLM`~wI>z3ka3HOqeA|^hQ zt45DH2~mad*-d2PRTv@p&^8Q2Y0>xoB;^b9;0ehO|5bl5hOTi0Xeg`K0c^+YxRL(j z+p(1hDT4ljVVrsiO@Q2jp%>XpRjUO4MG0duaKw1wIVD4dDzAo-P?>?x#PX6Qrv5IN z&$waWhJSJJ98Lwkz@hrwyFJ71G8O=$9dEr*@43@KQoM`auKqc0@~*~102KrUYZiA@ zCq_m3uZJvLe64fEHggmE_-0qUPy9-mnI|knFz@gVrq6hN(mNIfz)NHrH~gwh93W`p zXcBt8cs+wRj7nsnR^OJAHw1HbeBnK-LX}5zQoOUv0fUmK;i9rbaj9tI&b-p7^DaU<1$fK;*#&_!&GnPli;hy7T&Jfh_%`Zl2(yQJD^VvJK^wT zAsLy42ml{iBAL~<=+k^={TXu~_<%!#sqTRbEX`0XawZ|x+)*N!+pY4*4cYEQBDqa1 z5>C&27n?+Ibulh^m<4)`nS^zW))>ef$JGzuOy9Ti6JLx0O68o{bCtjsZ>s9!Lb%1D z;Lu49Tz}jr#xx6G^ha{8`t3we<4-t^gyc402WENbBK2XU#dfRV2ttjc0I9M78?kK(0dll|Z0USP<36!UF>j*| zM)Rp1s*X&d=$@l7(R!RSs)fAmN{9LOy?1S#D+-r2=Q>?CHs^{Mx94_rCY?>PTBTmG zbfIk783$LZjlu(rdNbi&zEqaHn78dp(Vn}sWsPD{dLPd;MvJk_3chmiCI-O_21Dr^MAY9*&fG)0C#p7ziM|S! z(@{^jn6Te|oV0)Tmv1`Zn@#44aBjp3TP($|=4#cPS&i<(#wOTHN zmNz%;=(wqQ8S|Y4goYqqGYgR8SlI?vvzmC{RQNLp$G!lAvk7D^C%AIX5}~Wkx&tFb zMJ%1M)?j3H$@Qgj$x_9#AH>IkUqc8*=#&`om~$E zP4SzQ#&+qkklTVOczPyft6a+4Wx=#{bnLQ#(`&&BD%$D~1uJv_b`+&;FbHi1oe*9& z`+*R3DSdk+8iBVmhl`8;EeF;bbC5j;+cS@yLP)1&!AotF4#0v5`UHBi@B9(X@SO&t zLrdjnfe{+0ihLIn^N$6jv~+iHn0X72*xRi8!uqgvW}#r06~4faGQ#naa2bcDA_p)F zS7xHw$R6ki$(eMIg6M;E?NIam;p0>5s5=)gUbKSd;wmqSq8%($uwW{9 z7BpSbd3)RxjT!fypB9&Gdv~-WStemG@3o!QK>L$=rs-*U@%QgE>mEiC63K^MG?07$ zO@cZ4OkJn-gC9m(*R!sJ-_O>!&O^IM>)+Dd##OtVZCXz9-%@jIISl=9%B*m{H5^!i zoe15Q{pRR-jTAHo$m@LwIn}H`p4R1(xJkbA_ek7dx8r@1m&H4}c=|5o@W3Db>!)X5 zr%V+My?hd+?7zRCwXdFOE>2>$EtRr6)??U)zewL{&$>;~yHDH3^}2k&=Fb`r*3Z`& zxX-obfO|kceL1@My|m7#4;Z$th~(FL{xtjgx4y+B?=z=X;aJR! zZTlrL-h+qV7PHMtNJ!hHKe4+<`_|albV0GwsQT(MiV|LTZgLPb^rt%N6xTsa9(88MDPLi){}x;;5JGNQh7DL`uFC|1sK*^Viwp*@RLPYk>!xPJuD&o6R-X&Q1wk|Pt1oIMWJnH&P zg2`eop+n$6pg^%Hh(V)7`$^mShp`o<)(rt-Qmpi|%{7J6DaKV0lZQcZVl;xK^$laOt_g24pAQB1x#nG3?Z^8(rgjov zTVp4@#6t$vu^@qcF&?OX4*tWdMlhX@tR-bLK9`WkLW^JnoYGS8P<(2|k`&;va6Yun zswA`J%q|xCwo_&dF`j^LfqPk&q@`_T2D+cJ2feh1O+gU_zemD@vy~?Xb7CYs$AbYc z6&GMMXEMU^gz%LG1iX282P1bQUlcs0PzEE5B?W)A6~kIdbYL{ktBj#_@YvRPu|PyT zy?T~0%-YFF9Yy+QaDQz0BJkjw^z5_$DW7$Ezh^(F4+(gmhxN0+Km0@=()-5bTv;R-XvvyDy1(e+9M@1He*K-1~2iD+|<5!eB0h_ zuVNKaCPPE{E>Y`yp0F?6XxWXL%28Q_DPn8vc&7O!I>LNq{u0gsT8;;_d)4w>WkSp=cPM zP_7B9CG?04w5k^#N!h^Gt*8312#8m#hj4JO^ut(zmqxT+zRh+JH<}lU&`D5J9K_4AXe*F2P^b zzXb5g!#_N@F(OTbix`!FTP4k*o`h8c_&9yUY^ZnUlIQ%uK)rLRIJGK=T|0d-t7gG} zx5j#x^Ffe%0?n~< zR_zxcF!Uo+cnoV@b0{>s!;r%XyO0r_iJ#3v6QjjkW>La0;0n0San?g-EcCl1JlGFY z?$Mc5|L|1_my#DHCxc5IfT`yDVo@Nu4%|xH$irx0R3@yd@GURu`oobvk{^<#K)~WcTDuZ5~^$S{5EMmT7zUt$UU%NnXn*?4x_qg*1MR%)*XE zRC4vYb&rp%EqyLoD!K9a!J|i(Xq4Q@dwRCCJ>}V}=53>_c1!OWsvRt*WpYK~LRx%B zc&a|{`Sy`7qEZg060)ak*Y15o#QJW8u5TG9mqKG77A?we7KwiAz2ihwhQSOl3u1 zq*IOt&I?%lA|y~ja(;A>pl0EGsxsJ}D7+*V@-k^zjVlf|!CBL?(qYlxo85tJNLHUt z*@-CnDqZ97wB-jw<_jh3bbD?vCtOmA_}#)V4BE^coVAwv_(BeJM0k|W5$aKVLvw^h z<^uF9HFjQJFVAf#JqIslb`>K+;Az~OsBGa7^d=PSJ;t)01>!A)BEl%m!s=AtW${cx zr-1J4p5m+{b~QuC*abZv4mECht5gc&5utnM`_9a6$KHPTu^qP0q^CklA|pRW_FO(~ z{juh!=moTTXQN`9nWdc^?5mHVV9^j>MLefit-9BFx78K?C52Oxd3tS)N7D9oE1qwb z-m=3%$u3p*pCPCwBL&WWRm3ss6$M)DR^+!Sy5hM7NaI_n_44>)-9e zL|CT}dXE&*v+pIY&%aAr=jT4(l*c7w#Wx>46Hfw;S2CxXQyP1J z*u5@$lU8lv^EBy)U`5ytWHpl&F!)X(@$&->{5DY|FE@VuWn84)$&kE zbX-DD-1-vaj)Sy45%Y^W92M^?=KSz`D+Kcf^Wj=wo}ONOm_AIu#{|v@kH9fUAO3J1 z;o4xHx4Xdw`-#dMb}!t~v-PCnIr;g?Z!vexfzz<+1~d)@TPAZ7j1sn8n%hg81>4!W zZubxF+n@gFU$me8iJ!A>ziYjA({kH4t$TQ1Q)g*i7^eh;X&j@Wgl|<7moSWxnp2ts zNq@_^l4^lw@L;;I&D!&+Lv)6a;$^A~tlG%d2-J00h@jVIIC427rExUW~O?xsc z+c&=T6?^{Do|KiM81;tQGO%yG{gxd|aN-o>okC7b3*~MiL2)8xFX>6}V4Gzy!7wR7 zibEFE^@;=mlr9$m)!yS_$?v2HuPf*x==@G;uA@XSl`$Br^0MPq}4^#v`C&G`P68#{Z}Gav>#QY(je|F`iN3~e zVuM-Q2GhL5i2NS=TZ%RZ8NN{O>6wJtS=K($II_Ls$g=5_<1Ki#Q%tD+>W%QXkm$O1 zH3Ih}*3i8H5OTaY74EZm6OZMjNTZTyZlrQ52SFjP_Qy4z^b19HVXZb>6_eJH(peVF z1`^ul!smcK3C6&>+3VR^C}mTEbG|6y0^_h?7Q^T-xU+?@6LN4;+$O>s;?LpO*7jK4 z2(5vg^;MGKA~jlqqUy{>r@wDz=k~Zi6%J_(S9If&8Und!jpnvjK_L?^3P&)OrxVJh zpJ##Qg60p3ghX^#(s^Cr6yB)qv%r;&;V86>lw`b?E|eP*7DqOaFuz;X{4HwMsh|IN zzb?ENK2Z;YBYat1{1_zK`h!kCj5421)bT8wf1Kd{2bq3J_gl-$T*rdR!4FvSn!6J7o*H@@bEG?d>o+wsMBFv5qk%L3>?DAyz%g3!Nssk@FGd!q^g*az9=`siK`P@F~25F??Zkpl)~_^dEyfJX9_B zwqtxA&-7dMdOv8nV1q2gI~?s$$Y7L=!X&8zALGcw8Ez}yuDpZ+$*1RPFW$fr9Duzq zhN@5u?e1L;Cq(IY4@^B1-Np-*uu+s1!9-&ysI!GuQitd;p%>_v=r}Z4vJdS?WTgGT zz!$^CbC5ldaok8Nc)^?S&}Mv=lqo)0$w22(upG2B&+&kTYr;I>bq&oYj0(>vhs0Q7 z#AOa3-;4zV#(|w&g(SO((4)wY3+V28;MVrCBx7Nq#EQz zLVXZ|4LO03HXQ!wMhwXWoZ-RHalQ}6VT{i+4Hkw;~laM7{j}=VDW5G%7E2tcC zPOpoyiC@kxDRvMRCClJljqFDlv7GvpRbPP-vP!ThSR+liG~t%!GGVTw0~y6fC3Lad zNkCA0RJU*^7GrMke!{9*m+~o9{fdqfXoIx8`=~;+FMKPpn!iT3&imV$`?NBDCi(H!P#E z81*Ex7Bwe^9S=cqrCzg(I0mUtSlJ1c2dyQ>FH25R+-(22YfnUnKXd1rovCbi7l)Nr z^JUG&yl^jLjdI#jGs&tNv#nCqQaB)~|HJmsDw-!7>fc|DfRzn?@xm*%dY!QY~6XD?;CT@%9?-z3M0V= zKoS%wvPDXk6q33Xvb*UIO-H-!aD*LUN7$ceJHn3s;P4pT3fpa29cs4Zo}{4NlthUd zD1jh|v49#-RXOLI?>wDzXa9feyqkEHs3JfVCW*N-@4M%ov(FyZUVBY@?X@TN>mR;t zJH-g+$1GyyDz>%Tw1F5*ptcnyYu>oJBY4j(q4reD1-r6c^{{bxpmP=phYXG|l8P^Q z9PfP5I=#@?pB`wAEJD#j!aR)5EF;{S6sp$kwk;8kEu(RPCJ`nD8V(Jtl%=-_Cv%!l z?8eX(cf4ODix!9$4<)bXN?D)JYh|2I#+I5*t+cge)5*x^MX9K~!PE~XB<3{UymuOXu&r>q|hJ=X`j6 z{;lzFX6%Xkj~jNLHqSQcV%{jsra)lkv$_5?_w@K*Dby?kCnC{+06(98@B~AsuZMW0mxyLg>r6 zz{cy0-KwnZvyGk$7XQ<0x233y=%fnPBhHcL9zxsMEa6*QUKpM@=pPVF|@CgQPJc%Qy4N1El;H|Hp z?;tWyn_;3acG_8w(Tb#SU8$mC?VlCjo`^+LVMlO%%z?7F$fMKO%o# z3^}DwT61Y?bt%Y`-l3*z+6twL%||`E(`wsGJ9+#0Pye$0v)A9YdygL2E3bdiZth>Q zo6kJwapYdQdfkd**l7uhQrq0%j3E+_)p{W#I*_)e1RZfosJ84{v18AcqHrDe##Q@p^HA^N z(cv<-vql6fw%KCf##o5g23{j5m?%GNm_?ak1zVkUVS{$hmT6z{CqxFJ8Zv?b9s!I8 z!p>6T5yhEGNRR*#A}_f{o|uOylAJV6-GZY8YZO(yrU<1HELG+@kn)t1@QAlTO3Xl1 zUvNY*#o*i@kG(B53B=(dZWAftEV3Xx;pK*@0*~(-6|)0 z!s-)!nW)R7*+L8p-ZA%G0eEChB`7b0z;+~<;R!sQOCS>-;eo`KI>M;*!i>jEuPG1s zo6@{%OEB$f9&uO?Lfk4@wcGu?Z=c0Ou9V4GSLG7QhOMKFUx|5=lF}x4){8lfwc00~ zB2F5xuIH12FX2RlPntt4lJvuw^Y57}yzVlw`$^7I6&Kvmh*}(m2`o5BbAA?oQ>Dwpw z@B&(i|IBQpc`?JIO?(5-Pv-YS(c<4ee#ySrdd>}>y(wGy;T2L4eTekO6`{E3Tf+W_ zFMiE_rvA2-;$!O%Ln(O)Ym^F_yOHsEIF`aC8iNG~59?B~WWzzvX$J=ZLm${?&N3pr zk`Pb`)xK?Cd}B0ATW4Of-+cR%qOTYy_1v3);YH2S`w_EXu_|dhxrzPq&g<5mN-186 zHqEl)i=0uxZ{jnH$BQ4Vbe&CMEW$HU3M;fi#0A45bOrCHsfYmjYfSW%P)`_;IJk-3 z9T;s0rI1kD;du%1VKxI}Or0#G2tf0>qqe1DqS33B^WLm@Fa{<%A@(gkw)T2ejQIc3 zcPX)T)yGVE*cuKWN-2+8Ejk7-)nj0!e=JgCoTErrIegCeW5aVV3ST5Xu#iG81wM+0 z48V9t?bmN~6pR`0n)pgQQjd8?d6C{i+2UL3H}F7KaG;ByV1s4h0^>GIlYD3+o_M}F zT74%LCeq+!Q4rl{TR8)Vr={c<@g?>zvF#f8P#s2E_n@N zgpP;|y{bX&@NL@4=Y~h!W6bajCWMD46~p@&4mn(k&f%HMo+`}yZj{$Qdgvb3s?R<8 z^gAIrVX6MnfA=`XIC7qEvP_9*sU51z-v_pONPCF6%Yc9{?7pewlJ?dhFWF$_i{694 z?AiLty`NsFP3Wd^AQtZw^e(cW3iNvDqkF0A8MpC-U9zyDRwX6BdELN5b4jQy`9|+7 z7MdQkRQdU)ErJ`KreRF;Qsr_;F~%zvtT|Mh1?6HUYyFvcr}}{0gsg)Bngaz(%5xmV z>@+M`Ikj+)^pa#EpiKK$SesRz$2eD;sUKqzP!@ZR@@bCI9NG)d=cyZ^gtvs0zzEFN zexy@@mBxF1WXVAA&azuhW8$;}uXK$QbwQ(W1`tN6MDd@;?9(=JX6(laEF2-3_tl`Py)+3eV0p0SX{Sh*Ok#PbaE zR-dCVWhKpPWMd|5Q7?j@^ow1}x^%f6uXbb)4qs*>auD{lD)IEE9v3<*dCPYv2nNg# z>eK6z4Wk9H@q(~{82Mv161l4nTuT)*LSz9DP3T<+4P;8apCjf!I7owb+ut-d9{tub9n3~ z)yH~c%TCTtY^Tw%ez3HosoL8cSVlOzzgM@@!ANj2d-dK!wQX(pPR{JP-CdKK=HA4Y zOIfRyBp(X)m$s|+>1$2<;%jf&*5!S>q_%)_56+G?((EcA%tFTUg|d|;2Tp^r#U*bC zVl*5yJq|_oEn=_q4g>+IR@J!;xl zx-S_!T0z`jd+DM05<4eF4K)ASCx_Osv4$&Ud#SnY?C;o8_}r6D#sXRheyWcH^>t5k zzp4o^RsWVr&ApW5=@pJ7#Hen&$8lQvC`R;RwP3@}iCwDJtX-(s@bttInSvDsk5D=W zjzq*;XE7rwyzT^Z%Lx9nSl02Pn<(1ZP%``?u$B6|ThIGK6pMb7LEoCSvW3!lrxU?K zx*WR-M=Fu|pM@YbxbfW%fEZIk6C%lGF+`I zNIGNzCmT)Sb!jo?tU?}ue7!w(to@F9% z|NIdf@ju#F*dLsT&*&X&7j=mggx}n}4WFweMb|JuKR$#IpsHXH9q&B+_D&XgYt1v7 zR2X@d_Vr%guIEPfw;$B)?NP}OregIA=Cx^O^hX0BM&{R=WZ%X~{iY-2{h_4`6X0oj zn!Y1}mm6d~N5scC34ZG1kGSTW55$Gv=!=wXT)GwZGXjn>gA7%`JdRWOV3(eg2U?wLRl%eVhZVE*@hF%I4LSAG4Ea| zVMNSlEQX6hitxvl%bb|KL{Oifqfyu53o$r7$2*6uet2PA+uF6G!NgZePfqXHU--<= z+S|t`cJKI+^}8+WwGQpWAAH%q_28kE3wh0RF>DE8r@_d#=MZ0un6zw*WG*4JEY#;D zMmPOKh+RwgVym0@rW?dI@FNbK!;7|vNpqVRczBi|xC25Iuxv)k4+^u&XEhk(G+So7 zVs!Cj&h`ru#wDC0)GND}3)o@i&^!bOPR?Gdjl7HZ6aqUlUnN^_ma?s^1O?q2sT&;$ zwyXeidN2p&Aw1*3x|Qlm&?wr86q9z4xBH`}JqYTefr7h)_i8$jm`rTZq#caw62=Dh z)7$s#o83LTl1MUqZ_;WB01_M9kU$nZfz7j(mKCoJ`g*=KMolfVZ zZAf5FmW7`ZiUlXUCNSWD;FN`qgEv@1c<`Wy*Nc?N6m?ClDELh9d{C#hB^)sa2=}p- zTiVS++rBCoxYDY2b!U0|#Y;zaJk+?XXYSps=6D_OF%-?6vV>9&3{zWB>=MFlHPFX3 zpFya@fDjq!@xVvnY6l?O%9_H5C?tvSRDvyGE5N&Etzs=H<_Wg$sWW&C;Q_Z4o>bB^ zDG&|2S{20A28=CVJFBT~3DJV>qha1Yd9`2-F~aPsYr$kJL2V@Ae(dq|s5hxLNGc4r^l8Ppwj9GG0>M1)>nd$s<#`>s`?e$B?+4tmoRetjn{VVzk24oe$dAhgYqTnA-0j7wuN*$fmQv4Owpnm-SX$3UI=D{l2BL z1>*oAY=YxOR*L_^IGBh#V2c={Fc=ep z2%7k_J9q4v;+Y)9DcGMZR`XILQRb}7EeyYOA{9%!$asVl^U!eZMy zZO79M;{aw%EO08u^#hF9keZ_CA!li@a7h^$@>n=z8JdF{kxSe-EPBlQQ^^o96mS0N zJ_bLGVel?IsAv!Th(or#8QA*RIxI~1m$WaOHLM2DudHpSAZ1cxPTMiU;C))q+`s{Wv11398$Ci0yF%E3|L{q;7o{ZW~f5VWoA0$spYi6M%1m-T4 z>RR(IpO^_>1sCOIK6q$3!E2zhIIvO0O3o54grUl0*IP7a7Lu7fga{a>_ubf~F(B?L zp4vUp4fKMk3ed<2KFGi-AN*4p6U`|W@Y#_7qOvF<@kg+O)(|d;@yD>QxhR;@2j(S4 zf9OC$bC0uDXb*=>iuC!Uh~_f+BH5fVaJ(cVxTwrks(tHV`U^i{H9zokBCEZh@0ZM%X$yCR#H zcQyA`lH7%V8mr6AlG;DBe63**4h{q~(TQMeDfR1$V6aqMtHRxX_QpfCKcluS?f9T; zk6Jw|)XSp5eH*Tc;hdFTGPYOVeB17haDE6aRxH`6bb#V^%@%}B+^Sh~XU8g)s%YZc zcK6xQnsYkx`NOikHhs=s?_RM7<82!Ym!8=&`{-`le(uVFeRk)*&BBSGFWLX-#0nPL zv)dJ0W$Kczmo{T)(!I^YHa;)fGZVf#ZuaitXjOA@4*s$=M zo=)t>Ufm6|jcUpDKlp{sCU$kJWC5@ej2FsZ7L4PWtm6TEBF|1JVx_B}N#Q2+Y%%Iv zp;osb2wd(yYa3ucDjw)yw%X{de&_B&C;ftuH^25!TrQkEWi%Q~+ z&{je-K_f6Uvs;Q-*lE4r$YZ2t7XvVZbg)>evZ3`Fv%|LVB(74CBLcNq_!~^|z@A#U zQjF%iZ~#4yvwC`h>-B3_H0Bu_b$ix=k4u*=RkzhoLI);Qj_^|Y>QXePJ3+@|p;`BG zMLX+BPu2Lq-}9xCE!B4%o!UW0JX9DVk~fQ&1k0J|QbqF6HR&|E4n)t_IlEdOs=w07 z)Q6PDoWAwNgSr6`3y>~f*`^6HSRqca~iE)W`KDu zs^{B{di+~|ykY0b?_c=+N2X0--)ka2AJPUno~Ebi$+W>KzMn)`ef&1xTs)B+z4V7? zo@Z_MhE?mW8&Y6<9>o7_FtC@dUX#$v_E57&2Pak*BY*X+ui2md<$u?Opl{uO#cK5( z`_MBt?03HYz&^TPx3`bZ?D z_K&~vRhtD<8w@+Pn`_wFs3S%z;t;N-)TS&gp|&ihgHVcr7)D#>o&JwXZ{7tq%Kp>AmPZdT>+BTK97 zqW#;?ylp%Akv&sBw9YhdH)<$|gd~ZSd2ktz4irIRWus$E7ZZ(n&Ip6i7H*%7r`8Jd zK4u7d6ODN}!=@4pJNn zoIx!fCZM$jeLuu(Cw*uYmG{cvrWNgh9k)-c8)}~AbB-U)YDMtSxQ1ilYf3`kQn(+N zP!>qpTiZbM69e;9FvU|E?;qbHui>Zdj1%#n8K>?DWn4J0=5Vuxo%Vay)f{}j-c);+ z68I#2)_9{|rt!ZC8Y1o%~SM2ZI-m*9PS^KZv+_9g&9@?*e;>@n( z+Tz7|tJ%o@@T}tV%W0S=E@%;nne~HCl)b6!;`L8L`fhD`x91n{z1REP|88YJP47Fw zV>O?8(wiOxIr~ZV&6C(K+SOL}NA7heLnfby&{vpLwDG;XH1Kqk_N7 z!q8itT|1sv?2GNoc6U^>e{%K_`{iqQt(KW+zT!ccc7=-=vlukl5s}h8==>s4wyK)p zhtRIYBSjksCGnxH6Wc9>c6TU6Uv=XBMB~5#N#}#=5xyxvNjsSdoXM+ z+)&20b`)voBnB*ulNgENvlv4onon%#g4NjkL>qJ;)q=*62SXgnwR?80MX^*i3yr}7 z!)wym@j{p-%6Egi;OFY8__eBW`2t172Sn}0Qxg79BEGD9zv@5Xx~3Qx#J7`JXyK#h z<48N^YFr@|d4$5T+zXkp68zj-Q?FoP^WyX_9u85j5g#thgxix(Jeu_qE! z9D^)<)=xLU({>J|qav=sSC;1^Z(CwHtB1NxxCuOpsw@zwm5;rs)o9L6ps&bA6uiQq zE1tO)&Md`GS-5C&=y8Tx8IQ;?j(o$wfU6i$A~ypwLMHyFZ|vG%dbV#{!gH5Dgp`bt z$I=$uBS@*wsu-LAz`z#ITz0CFkk`Ca+A5w$e&EoT0!j!v43dGAQUpN{@lCi>&U1w^a>d(aR;MG`Yo)bc#tSVL+ z$<2Z-#%4+a_k@BD3qC9!AX8Z^V_6McXD%5=8HF9bz>-P|#_DSnS_e;j`mM2$%*t*& z4m4z;1*0h;eU`#?h65bMplr*Tho7uvMMp$~s^as)O1-0bB>1sY4lnzx#xtW@34az& zSCZS9U(gc5A&6$Eohju*PhbgxzOc{*>g4f?l>9*$0$;S5OG?w+caL;+mIV|Revs!G z3&w>;`u2auQ-x(!5V71_3%n^sOY| zHCOa9uGe$+P=ed@dsXWX#_AJueQi5CP5aij?%B>()s7BNY}_4Mqm;HKMo#rRDY@>Y zmu^|3l9${!wMUbwUD_>bOh&eUxo-VbUT~ZG0e5l9sMUH}csBE~t(7uXAQA((tp1*M z1C5Dfdvqw_-Tijo9t@{;EI~V7E?H8t-QJabyMH>c#!lUC?rr&QoAE4ZFKkOzl^(b1 z5A7dJpSRySdfxu(hgWu`l(%WGZxUp!EciWxk+;>hcB^BVeBQ2>3l``d@a|7Nled>k z2lm;$2lmOz9sBdoPwZ38vBkR&tkWM!FO>YL@jN=4*v~w_B^e$Bsfhl}JnRE-t0mVS zf#}}V#)Dp6^v}FTC_FBcHxs{vfkg>$%#GJEZRI@vxIPu z-AnUf*K*Q55`~=ROGJwkLEnmkBVkce()A=wt8Ggwix-vDrfFrK^9@m@Ap-f2;ehy>9xXf z7X37{?OJteUpd?oyf@5JiSKiofBxhAL)zRYL9I6TFDCAjHqSQsE|lY68ejkB59KN! zjrDZl-X{5_?mvF#{M%{Ic^%TPKUC@3yxaC&Bd<0ibmr4V)|~szo&Fwc2s$E>4`=?d2f@v!RH^+_f_%J z^d~B9@QiekI0|>(LCiMa%Ksf`r5l=%b16x+R7=8hUznKo?OCnvsju>W?e#BPZWY)c zy#AVf;QCej*8STaKlXq5Kl|U>zx@2~*@tdkvlnhWCjl>QdlHTdl9q2DJhCgz9Xped z0RzLcrrYgH@DY;~;~tJAP&Mk-J!?sM6{D0;Fc?c1T=v9_7Pfoirrp2urfnAz)(WJ= z56-MoDB6|1>((q6?X`P%B>d0q@bJ)X>~7mI7+9(-!D}L+MuK9ZP!S*DSU(YoX(ZI4 z2(bcNL|~Vq%YhAxDM}lLHwm6FeSrvJ9R&oh8UzRgeGG47^+AQ$T*4ZPJqJS|5aR*D z!4wGzKzN{~l;_?^%E?>`eUjK&kTL{Uvom7GyKt{NOnFs?;^{dw6eyh=1xR9-9;+S7 zmXLrElkn0NGpQA&(BhpT0Sd7_CT3sF&h62-X1n>owz6Y8p5!ePpI9wJEKc=L`CI{1 zIe6?y?GaydbiyDq}e1x*+L#t-j(NH(KQNJG7H=S;9|*MuCKZVk&Si z*R6C<0yWzaF~BcuvdGz^aLW}JRCg}e7KtI0t)Cu}BtggxLUP32y9N(i;8{%1{lsm; zr=TPdrUIRf1HIN76GAs&0O(JpFzH@6m0(=R7>6bLbB*O<#rAUvW*T?4ptU6|4T&+Q zzW0Nfg{!<(ge*^Rv+DDYaB{Cs_g({z49dp#e(3gajfPv zpCsflk2s`|&3$-7!ML{-MenDp4No-X`68Bh)U@ThyU#J9lKfX zx=`CyJ(o&T`@g?(Lv0ZtT>um?J@L(Ze12GIQ}(8=pM>;Y?byKLy`BTR_j>-_-hG;W z;0cs^jLu9FO)k+rC;rHw7l-0qhs9r1I)8X!_|Tton#=$5PyD|9-0ofbRO7&|lzaBM zy*oZZ7=Ar${rMGM^FXdePppcqcDT8qbBkHE3&|ugY#-x?CXJz+}W-&6ATv<=b zt~jN8P9Ym$bVk8N(Hw|AvF(^`#vEcan_|?Oie5ou#c#6W0cvllfbm`s72n87@#TP9 z=st=%`UHk3c3pKPJ8(_|9@!Y%*iMhvDBg1LdsuKbmGQFJ{!i!)6mqs8vpDMExkOV@ z$0MUE3OSz9(0lbqkXV$1FRvdPGNG-yC)$Xy5MzOZN_ld`$e!U9tbVEl z>Odawg>n^07$e3UHpBpT6g`)s(Vx*uP_ed7)$IwP&37rruBO~f`!TAGg zBla~1$5zw^VnyRQ=&`0%He<;_c;FYtS9bEymyHK^WRMV_ar}x5v{9%IUn)gRa#+A` z@tWm8$f%{rAhgqLBp7o*rOO-|zq-cJ%h5REMa$rvh6!utV;<6~q)w*9o$+v2Bh<|E z{*qU}Fg{?U!~g|OFukx-59V24tku9fKco(Z6)a>dc-v!!i)RwgnKKty4xqK*pJ!HE zz*YJT|BP!MAI@^NtvN#&x1#zdal$gpZ)Ilzg1mUOdV4k5hyhH$6B+m;#!yV|%1-$j z=j3YcMl?c_lqfHimLwG&8n}*Utyn0zXDw%~Fn1lATnp!!zw`y8EY}`8d#*XAF|SEk zW;{7`IKpAot-ho*FUW@+3|{5c_vO+#y80-*(Y=i3#%9+aVQx0N9~wE$C(UmbnQ@?? zT*fV-GH_40+l2@!l5FiYv7~u^BNb)G8n;-{f-04Z^8v|E-P8C-Rjyb5Im}7 z3ngdZbq}8T!j|3#x4>^a)7-nBzH2_RAQLSbK=Xu~`Yy!hb~MjOM#X6W&ow+dCF|-l z6wL`{OPdRKIp8s`dOUPkzyb_&(j?RCx$+V>{^+#lyEup4fvpo9q$jywG>#a@i}656 z60>GWW0c8zn|0e4EL6NENzNTd)FG=9K4BV29vgZ%gQLTaZI{YcX;!RSBt$`A`9eY0 zb?dO>vwLPm={>ubcdfZqvtq3xT|l%{wDU}|?(WuQD<+D9O~N|ExpjvF+bZVWvEc1R z(t>nNd4>NPuZ-wvPckru-M-{|@IIba1Jz&RomUEye?>Pc!nF@w+O^lEYyGJYe@M+9 zTeVcOaj$1bCr6UG#Y;r1=Yki`EC0>I9nI0H{rTr+_N_;!b}$SqDS2_LTJ_k(_%QF( zYqlN}wnMV9@QW}AR&CG=XQT(;qOVRr^I3xsEdobCzXYs|C!p2dQZ70OvlhkeJn zLLqN^&9bcp@3H1dAQ>Nia#_41E%?Q7Z{f6h$9) z_pKGns*lnmRql##Cb^<}^v;A^MZu;ZSgwV`L&^IXe{-%@vK+Zc$}x?y@*Zc)^k2 z4xiuz4^y9tDdwGMrJ4ub+1;uO zmq!|px$lmwG&Hc{fS-1Yf^LeZrk@ zKjz-1%+1YQ1gv*{~*P8cIt@j;SuCg%Ch zbLuzjWwJ=PBPG}1*trMvc`pBW_Ve#e7HWpKS2;7#J* z#rH0z&9gr$&(riYZPEr$z_lmwY?CfNJI6_Vp-6Czk*%4T*vr)uDVBHaaK3F{=)WkY zB_%CWlmL+N)p`t)@7Qm@er#`i>F?WzUjAtbcyW8-g^ycY%=*F6 zZJUa@oesOwvtu@turicjMo0_<+N_vf&>dM>O#AHk%+?YN>Jq5#-+gE$F_KvaM<&g`=v{j`L>z>dU3-oF398s(}r#Egq&32+h+ zrxIv75=IcFlVV2rVz6pGnTfedC||A;Vssq7BE?*F0ug3$MvN&UGLbOL0VR?|EYQ0M zWC*=5H(q4d)$G`Ivn}<9?cE&o5cQ3^5bE)2=3u&=+{nGC zYUzoUQ-ShGfXql}a6@|F-YskeFQkcwCP7%`>|{pDr!kMS*K+T2aeiJTTt>5kh|lF1WAn35+g-LDUDYTo)kj~kLpvR@51}( zv}V`K6TvF9iQaKTh42o+ZW#(NarUvVY%r8^o{hY+j=M9<=cT+#L7HK(o`kj(JP=qX z(wxB0oCI#vILz|Ib7etlwGysK>B&o>TT5ss4mt}OY*(*Kc|nN$FYbTD?sal{F67o6 z^9~{eX^y_QwX(l(^~6erqUt0jZruLntNXe?x0A8vivxoRqYD?D{AF(b5YokRH+B6u z6K&vgF?}y>`eDN8Y5LBzk@?;YXD-Ntn@5}Bx%k`DX1w369Ma|`J@+iSW?qPv+-ijO zAH4W4Em(?YH9c7J0>oZwgw6jKB zXZPA&wbNhKU**AYO6UdP!E<6= z`r(9(j@pKtz&K$5{zhj@ZCzV4zqF$IH&MSZuw#f91Sr(Y+r)0hpn<#qY~9eO=NJH~ z4Yp8NBb(iJW@{>bCebJY!S3xj`CUUQ+!W+Q#DeNVvQ!9HHNFjms3? zrE(aHY+`O_qm<;Plz1)%L3p9c@IJyN1Vgn#*&YAfJ5S?FxCe|AgK63x_SJH=X-7DY z0iH3!OLd{=9#%vRj4jsGS)0;fLTg@}e7x zl!?AFCX5zs_QQEG(5ny}0HSB0sQRpDw1qnuse$iUvMoCoR`bBUsF6u9-eTxnV>nj3 z;M3qBvH?aT@C0Kt3ARb75EjM3N)9UnMryJVi<-L_ZfEnE8;l5>HIrqK6~lDj@(v?_bQeB}ak_$c(Mo(kg@+6CSNpMr4RnSsE)2RByL? z4r81`2B&S?tCof1NxODsPq51fXN4D~qICyj%Zp}>2OKb+ve9s2-C%C%YR$sw)Z2!R zLSI(vnVqRGw;xC@Qr+koiP_2?9z1eG-OcB3x~v$_mfXYtUT0wA1!Kf6zLd=#-t&0H zi~gzYSZHByY#rq(h&IiRTecjI{17;d;3pcFSweLRA3Mso6mDFvHZ*rayLs)Z-M;_O zsx`^D)4<-mecy^ZyLNhdW>>0JESi#Ahn6j7ETcY_%lkGLO|9iq_P5^Jvj5emThj0P zc5ley;=+crh3{59?DjmY1ZTC(Sme-nK9p{llKxOAmaMY1E8Gtyi*rta<{h5KOB^+% zGl>`@MyAs&>PVN7E;&o2tS5Q&sIPvuhZ4K{8rPN8%LOBJiX?O4Q7C>D7rZcTM&UWc z2?cA-d*K#mdDV!QEgIhupBartJ|6>&!opc_3TGR1SH>$8{8yTP3C-`ScnJ$pX}w!m zPQ+t0Z*w`zt1q3_nF$MRXM5W{l3A=f>IK$swd~4n-O|$EFpj5YqDQ4&3rA-bi2toL z=fPj-!c+sx{7a{!^B{cd*b#Rg zCoecQvOGF(CnUT8{KM4Wm~9pHi+XeqdV<2qE)ni{hsE&=AH1C9Rql<52SOI>wET*=eBJzJh4ZIEq9bjYtAGD@8h$!=!+cXu7LyDf`vu+g6MV*P)l9-OySVxoXv-z189{Lf*KTfW+o=F>UUV z|Gl1VKBP^)P5BW_J^9y#`|tQo+T_(ezWj5}fRr*K^)F@)?KG@et+=#byxg+GNzVTH z$t7E;j~XrIk7##P7Ul4*6cuqHoj=Er4fF7{sq`l$J=vBgf1mfw)4Sz;w-4#U@5g-? zoHvg>iNijAEI!D!;N`X=z-qtt*P}Nz0X@Ad5V?1;k?)o^@4Z*z`NeW5do#$JdY=6K zG(Al}tOTyT7fxS%2F~g?U#`4FINV5$>@RM8-ujb-6wGt3 zQcf0Z{uZ73d~pnV<> z-b?m&Yv2Cu=e}ZBihVnqaF`w|=o9JA`Nji#zI5bylWe6HdawnG4*Rx33Hy^} zR>HW1e)Wd~ve>>&{6<1*Y-NV7K(g5>SfzaheL+731NU@M5qM5l(?c82^Mak=Amu49 zxZ`CKkA*5LFNIY?+Ik|vAmfTV0@qxE8^-@cY$>=)SwQ%aieXy-0RQw!L_t&o57oAE zF>k|h;D`3@Nl?a%Vz!*AJUqVAZdk?}YA_jl47igq@Q|<$-b(o>Wbv}vYy(Hxj1sYRn*2pJ)3`P?2fCa1jB?-U@^=lMjkO*zMk^m-!B`26_s3hb`5L_2rX>N}~-|~xk zmP}^tcOO*k7cM{0+i5%PPuz9SJFB5+w6EUqoW-Ga+19tij8lLy$0#w8OH-DG(lxz0WA0)x7W| zJ-2VPx9oQxvGNY>(Z~6)8VI20N&DDd%RbdSw42*|7HA$zthN8mA6%0lThQ34pGz43 zhEAOih|@62_+cm7{3I=<4Se2<#%>bt(#H4O&P|^;-#>^l|0Jd#)OfsC+TaE0y>N!l zcf;LH8JoOMri;&&=$7cyFJ3>eKfV7@b5A@gSF~O~5N+t#-+lCgy*=I*JxJN*O3${l zLn~y=zI3)P8kV%5-@RuK##MW}O`JxRNqPKng(dR#;}fRAgy`_XDtRe{Qk({(z-m%TXEQ0$;sb2s&c*R= zlw#c*T1v_{ydPeZ&g3iAu~2kHl+YP? zZM9F@HXVnSFJ(NweJUnDQ#YW2SEwqemK>Zop!T@I|s8p6yYr zV8DwEMe%sQ>Z3Bn+5KI{WEF+}Vqq`UrkX35B!E*S3t(&nmdG$-$HH;ON#mye zFd7j~$6Qtew!nwJVt8yX({?!>+TXgfXMgF&iTBsf2?6#DnQmaj)z9%eSe!_@4Z;_Eln(7>>Igpv~A8WN2 zIgdGshj1=mRQtg-9}b@z82&=lk0U8_l5xvqklXP%XP$wt%$ajsk=*WZrPKP|o?w_l z29#V!SPH?PwXkF?Fb?J8faqEdCzX|COtnMO>_qY?*vp}>c-=B5a=DUChFza4jY3JX z`pA;$oSmF?tg*LmMfH(`RJRKSd*i_)OroNXN$U!xm-co98w~d|m*@MsUr)s&qqdZh zrt}pS;d%o>z1Ne>mbA2VmtYYcM!gtMRhGtlGSXP8&1zdbxwJQey8Y(Cp8buVy=Ps~ zU}yk%Smw}o!hkHKvyCVA2q&0wRkCWravC#WetoOyak=lGwM4fxw)v_R;}gqD*UL&) zQ!x%p779AT2M+3+wc1uHXYKF5^1vQeUbg@4wL`mo)Um~MVvAH(V=BB6ozIl_)KAIe zlBdxF0_lw${zrJ3e6eDW9vxaCwYL36Nu$W@(_G0{ERONMRIonh0TpV3VQAx#h+vU-<5D8jF0fV5fu{(RVSIvSz(*?QTyn%vxuFqm1$gGpkmMYG2l# zyRv7khX;@f;q<@`TPzDYden&+Fed491B68A|FY#-lOpQHLV_cr-A zN%uF8N#y4Sgq1|G+?!|YfBeb&cKfZn_DbwSc0g!0jOh?dPh#+%C{G{1f3Z)S#BaUl zc`o*w&rfm!NE<+1?9XNl_>jbGzNh4X)#n@@??~c_=i~7BiGFf$Wx_u4=gvcL@cGUc z-}(Lhq)o#}Q6s*co-FtM)blhwO@Ey9N8#GLJaZ}T{9FHnWyZeJ|Df%bLc38KS|GtD zH+g8a_?eZ12NFQ0Rw{}iV9e5-9;chumLPBAj=dcud@Ej60)H)2vOoOR*X=L=oBx)S z;gRYYZw4i?`1|PS+guSrSvBTj&%vOw56%6~Vu9s}J z2>tZjThH9I&wu&%{ji2wdSx$NyJB|^Pi>WDJ7V5iXD1Tq^I~90J62hE2q9p!h9k@7 z#c-wU77E176O)p_kP{OwN)W&+ge^tu#l(hq<%UVyDxhdc@PujW`8=7&j%O*hOG!aQ zz`+oSP=i4@ok&Z-Bo5u$g-t?8aOypZ(^|}&@DNU~R2BlV__(Nugh1R}83Gj!sY3B! zr8a|5t~TKTla~OB=ZAD>31$fiijjdGrDC*9O3}bW6+uJ7J&OVo@)HtLJf^mUBm}W+ zVr{Rt_wCi*mVIjH$POk2_jqSpWGOSYtEGa9uG1=of_%!=v{ij*saDw}rV zC7A%^gT4Odkc%ovl2l<3h^b2l%gU*#sHY*aG9Eoq|=oRc7@`NEdH zT9yS8jic(Vq{qJHo|DB{kSOPp_GnbH|NN~F*qttidcZ67aoi{ALi3@Ro!h_n@|mRz zyCMlAJL(0R<@?ti-<`d-5qV)pO9^oBj3e`x>U!M=U1UA3c$ zc+~2|PL>V(y~A4ov_MP0%8L<=LuJ!?R<;MDvfdV56V16Zs8~mQJ38=CWn!_?Cl-^6 zskyv4+|E59rQCdC=g{eM48xbp^rBhbB>sr6NtuHVvmlE1EBv!9mV&}NpQ4QCY$V!- z$1KK14iID~(sDKy?G!y)*WAcatCq#DGuChStXLEe68~DvA_M9~?+>KZZa0cfyIAxc zOJ=~R#zLj@KFJRQRxVe>kCh)IhWI}Vp@fej!Q=J1=vHJdA9m4pEe&pG1KVytFsH!_Dt$PHr{;xVu}uRCuK zi-T?`#t^7{#Hi(G97-Jv@k$O9gkN??p?#^d zZCh!=QLH7a#*8?`aC3^M&3I@79~Sfdph4YZL4oItF`lo81@Khxo*WZFi1^AMuH!|I zyr+*phYtfg$#yCisnHz`)NYLM{#$c_7PwJVV+M}nl}wy+|j3i1G|7faKLH6liryLXOZ;?KcSBJJpsnU-|;&E9*SmYgfzZMH}Y2m`v_ zlnG{{Qw7^8rtRN*`&0I%@wQFlIs0a>Y@cc*>_)k$US%vMnI5%msCn3|lbJPtE)i07f^iEuHlal`8!dXi8d!2=vDwyFhNmA5p{XRc!v ziUpemfvq&wT?wA2RuoGUZs64{opLBybhx5!@e$$nSg;NUeTxNS^&@MAdQCJ%<1M}r z%j7Mm{@~aHdxKZCyF=l1#y)&~*T>W8CR9)OS7C>%@NS-K2)gAo0aYn)x*@n!>j+uZhw(9&=6V2%e^|%+b>VZbBbU&ds`|cg}g_d9x#}Q^C z9i87R7KnyP+? z36!M!ayT#NEZyAIywDtB@iBeAz)XB<4ARqn$IpmZELko|S~ESdFST~nX80W#D`*G? z5JMKmKe)>oK2u9%3ywpb(~fxJ)Lt9z_<|()`0s?pKm5=)bP`79$ulTX?!~luhon3{ zXy-p4U+{hY@$&dQ&ZM+?PNMwt^87aC>B7quEfoFwHyUU5+1fX4HE!8|(fK*e3Go=| z!Yo!iE}#DM9@kzp_etmX9@lrCJg;AzfB&SX^L{?=%f%1r;`R5E$h(0N>HJ;CBmH9T z3%1Cz?6}!vjoGjL$C|;OLw}U%aY0Wa%KJ&1hW&9m^fWz9Kg#sS!O`=1vWnT&q8Ma2 zv=?#@{7|BG&==!vS{RIc+h49$b|qpGF6^!K%eI?t*_NHDgoN!S0(*UsvCm#Eh><4j zpmk)Q{OC{HtFOOirCid=#fpii+n4U&wJTRI+u_3pw!baKQ;h26oBQ_Ga3&#RYHz>x zrsb}D(Dw3U%jBwd^5~(Tczb&9p&wlEnUCJIZ+`PF+izCvpuez>UfC9tE7^miW9to1 zB>2_Dh$V1Iuz1iqw4LUjy?Os_D^&AV6{FuS=4_wsUXm)N5|oMWOxOjsb}l3YV2I57 z7C{NZcpSKEu~`ckuoXeQmwG4KF=jY&)oZG6K@-%W;U*SYW+@r;U2|HJi`RH zhr_D9+P`k))W|+iy>I2jPzra>`qQMs|PM|GmU;}esL5hoST zWR)$53Tvzt!2DTRPfPJw2=2PC-)vV~NkAWl7{HfSme4+);TcBRNh$Bqmbp*@KQN1} zB8N7QRu2RWDealH zdmbbUO$q2j39$m4>MUh5_D>HkTNtlN=>W&m8hh|dA2;-p7-!t2B*Z2NR*0oU!i%yv zBKk)OWi3Cm?M%;(f{J_bNVeBl&}WofyzRtig#-T1ruYpl;!Ak-Yactb=gKNyf^%1j z*#GO*9h)R~rNp=F^=?JuCP7|p1OAWeKQF@5rd;kluHy%psF!qJ_d61mUaa_s(ttlf zX#;E0`;pN$Y|x{^UaSb z6M6JOL84Gsj8Q(kgs3k6ak0`(o0MEuKL5=ZLbmGhwrg(x%#9QK+1-1hW4fg_U<~qh ziH5T92+d<*5F=S2r50X@(RiIKStd4dFJ@v*WAvgf6iK`)7qie#gOc6aFY0<^eLvh@ z3NExgFFKXvurwBD=hhz1t(M2oopL_qJQYPdQxX}G0>7S$FJjCS&r!28S-cbHs&^t- zDYwd5VB`^*n=Z4~ET=r&6`)%!L+7#3e(J(VhbL*LHFhKTa4@u5oyBd8spbp6Y2|}| z<5?x`-j>SG7^S5&W57-eCM>{8I8Z(nEZE>Fit!SD26vf?&|!?`H(A&oO_?6DKs-Am zVJW4yxUp6+SqQdxl4I12lpIN2>f4H!)h@;XGcd{HFsnU&h_b#pL=723(DZBGI}SPM z4sxHgn9g~J!Vo)PX6FS|dU3U&!MWOFV=D1L;I9+*;(FW9S%ya$Jc7xrgq z@q1((PzkT`m3THs(g{Z#w^nXY#h}4AGE--o68u(@-D1|rVQfqax5Nh-IK3Ax<90Gy z+qHt=BV52!5sz8IJ7m-k47To_4oLJVs_kDpmO`$vd$}C#)Y=>z=SE!cP<(o=!N>5+ zZ$Jx<>&wegp`I7xB|nj|29le~E=!ml&C|9onTNwOnS0Cw`s8Dy0$6MSMi{pUEwa-4 ze*Ok+W}CeF=Qt`2G*{|F1ff)5RYx@bY-Qy4BKi?G;FS-^?$PH6tj zR2E~7w>-uwjMT`d>ap+)IZF5@T*hdOhc4%FAon>9QJqu5l;K+}8As^-xX&C49v5u- z5^bwF=2=4Wmf$Twu!x1R9GqZ8_(r}Sk1={BHI|avvN%Hs&W;ypTTN7lWOf#CT-H`! zp)>3VV6g%Cu^3b;7M(uPKI#HM)W@8g$FhR!RQRVptOBc+b9T@Zty)dpW0`on4-Q(A z`SL1*&;tc4UD~&A-hN;oe(@#i^n0QueLq9w%I==^jvgpa)AGxV=o=0&GWObS0}E(oHy|E<1c)ja2z;NcwF(s#79ESpLD&XQHSWc{-v%VFZr z>9@upDOipABU?yTWx|d$PWjl(a@D#G#-TOh;v0jpg{izHrQ>n1{Z?5tS#%xwm3ZOk zaHGM*W!{1Crci5oNQmK}=i%KJlcCyK1G)V0!-8Nuk=&WnJv^$L^|B2+9S!u0TocO(Phu)tw>^R9%;|)9%W4sd|!Nbtp@zmUuO*$7qX z;0rv+h3hN|x_7zeAat8upoEBo4?`y)Q2lw%nrZ1Hnw1%i4_@c9$;cg3ki((*6oavsc-A<(RHf4dSgx7{(mlkpScqZ4rJ{q|^IK!yIcr;{l(%B3EWIafXYIDf$Y#+XRmcfnSWIGv_td)z)8`|KbS;W zKgjZ)rl;u#oi>x_d&Sdeo)F)6u&&yj*)1s%aTFt)v)|+CY6I+NmRzx`u27#Yu zOS$5N_G(KCs2Kmr!J!1Dg8kA*w(QSgomOHI$i5veEz^S3r~ACmO%UR^{e*v z2S;|RS+V;^hgPdr?bWy5wwpJv+d|s%cslZ!T_`GpiG+w;(v^Xklw-`HeSLSuh*y#- z($W|dcgKK39JaM9J+!s zl*4mJiRY|@`@w#YEfFdXe!v3@FATi6P%xcYzzg&oL#Pjj?z6Jq7NdWNcSHtHlc)?Y z3*}D?%U7Bc85gXldXEEzIMfa!ECxchrp03@X9=sPBxkKSC?aXSdD4o>sXvEN`xZp? z8=<$DQTx;nP7mj>zdVQN5jsWuaVF)9n#<{__*&Y=thkC27c&dXC-L-BS?V)}SPmrI z%0yeSaFW7%jDtM{P}Q5T*ZP;OlAhS%sNqWJl~UIY19)l8RDV(mP7044!H?7U3z?iN zw9VW^%9 z22#v4j>KA?Oa>BMIaGrMl|YJ2!8#Ja{@%gIY^?Tk+PtgOEEuRgF^{9Fj=EA8v!B0m z*M4sA8y@PTmY+!QQ@;hE=^PI)v=fdT3VoM_YL^M2Ci{hy#dI>^-?=!<{r zL-YJ6zj;o^KPp9;h_g?a1m@RUy|TU8tJ~K*`5?_G6vKxm(>--R8DWibgy>kUR>>{$1sXfG#1Dl`Y^KU2*%I^1X}knf@A39tcFT<<(}GuS;n@q zq4EPuQ`-m+w$wP}{E$ezh%q>MSSRIS5xJ1nn1Bx|n>M;arn1@VG}8Eo!lh;okXx$l`n$%)uSnM_C?!S(g~cD`L4d^@Z)+{b@q{hW$o@i=JcPT&|Hk#P20Pc*rcl z7$Yaov0yUZ7*sKyA%n%2fql8xu+MFGEtEV0zIwO{We4u6UN{utHLypPz$w7vfa@7! z4kFMtl3rI5zJPP*&xL^+AI9#yPZ(?b4d5S*LsIxdxzx*|3ds*3RGT9&>6kA7AX@?q zen$%rc1aGz^lMfj9g8Jt%~LF+}KqcAR-bGkPo2Dj!R z_h!M+lERgGF=>^ObP~=)DM}8`YA)sC_TZ>zdyTTy&}*OtYDXhmcDMkitJN)=b|+Se zXDty37d0nNkB)34J>|;fn>L%^SzWX(z5mSqCEL4Hw`#dyW66faLepM(MA%e;p;V19Fm;C{1)UET=u#!d)EdMW)1 z{ernZkPMwKl`S0f?AlhvihGxAHt1Ww*Rrz8n`k@=qQBtyNM$g-8PSFyoO_t2NlZHE z;RCyzM|a6terMZh^J3DI3@;p91vVRUK=;zd!cPsBm1{*0)ltZ2G##K*(gX08m3*5i zR`s6xrTLG6pZNa;>7-5dxmhe*_w-bAATs{1$CD_=Ibk5{`!*k*SwT7mp2B$KLMxyV zU<*4ep!rqlNT1to+sB(Y^5oqMpShot+|GP-k|8*87#|Brt^U-?<*L=y=BZ$vfR<#k z0>9>g>LOf9O!JfwLW9v*{6+YzX~fw=iB#6-<~*FZCpo(}L+LyT^>eBD0i4)Pxz^m~ z8~}EdvO5vJL}(3mhNgAR?f~XlAUZ&JrOq^Gl~feo2fD|ZL`e}ctKmcou1_?6^-l48p7LjCT~Y4Ex{EyNVm>q?Q9_3qFV3;h@o`)m_(80 zR#ouGT7ekq(y{;kgIji^I*|^5BiPKtWnqv`3(uL)EZRYXW}2HUDq(z1iqOr~?_d&I zXnFg>=_So=!5rADFXx@I>y4>hEe)*OCDd0+ZDgnK+#SuD*}2`B6pX`wA*hfkz3A6b z8GggZ*2@zP__NJ}$7%DM_xQf}{K>peCZ2D~yqK4|pjB(TTwF=lM3#&A_%}!UwtzMY zk9-%b@_5=5Me?Hb$BX`s2amrlTqtewTuij%$C13@(dCaUU4#?;=6BQvm#q+X_1k4) z-R4QcKJsVJ4;#VfG4a$16W`$Y!n*5i>&(T_<5EsiT^AaO zfyJt4PKs=Nb|8UaWv>iwSU$b9etgHOi~ABrXZFlD>M=|71Z(unwi&AY%!dhULwizZ5=62S1%RCoC7hpfmJFff@Ym|PYhO!SV91bY)|jUB-CIe&A7J}23f$5$3<4cI@HKXnV16yi}1@m+C--?TqFD@Bv@c1L{V{eqr51k9PU^@ zUwU_%r~3#6R54y+2BYlA&!aBmFu?Ql}DYo)fGg$2PbaF3M3plY?Wgps8LyYy7BTIo9H z2KP)-f}cLb%w{VPT}{QNF36)wAw1&b)(Z31n-%FsfJNJ@Cyv*|o$hoih;FxET5CH0Ls=@@BQm{`V( zR?SGTO>ro)A`ovRY~ zSN5^`J^NszZ=c-j+RIxf5-w+Ue^?etKrqvrc*c`1^5l(x#^*bdD%O7#z`u0sktHSr z&E=JK`Xg6JKD*ynQE|I}8rW;&hCL9jL4yhssBY9o_H0!OgZg$UKeVF>TNj0&oBBxa zTIU}(IdCqd_bT+fUZ<6OzSsAD64Fm{+kOz~C#-+SprSJyG{H0SF}iG;`rVrBax9B} z=Px?mQyAAytfS8+ZLazDSK!$z(F{WLr0kcj+_qoXf7^a`=WY9Z>v_##6c_jtihbPv z%*_Y(OS@mUjA5t=L?@wx6elXoqMa8R%|DDZu>{5$^-J|(YjPu&o^i%NsURg$N`Dpw zSoE8?!5lV44B`~V@33!^(ZD$PESFUqMDM1e)9f`ov|fn*5T7{O!kraA8|*Bx7AhqrR2{f2lYm-lqWMBgoY_6 zu6CrvvoPD35q<=2ms9u$U5sf}XN)ko|WDICN5YRpGowE43IIf+{3U+r;@xzJ<=}^tH zVx{ID;z1^LX^8k7h8XWCM~zM=&g`l^Z;U&=)OV%%Ab0iGDEfDnBl5yFIp z5yH%*5@}6CJaMCOra7=h`oI`0B?o{XjB#`zv*x)P(4MCK;77cY373YPI}pyXh=V~Z z%VPhWdhnoDX~NNf-3)pk<1xFlXg5309M2d-mCJ~+bAX)=7_@=y)Z_eu7Y+pV3Helo zDiME`z5> zjDhkDZ*G-?98Apg`5d`S@|Es+$PdAtg(Ku3o6M=X7Xyk4AQQ+I8Gf$(F5EEh&0D4nm9NH6Ch5kWX5V{tJd@M;*Jg zv*mM>a*DcNFXcra7dDoz!@+odP`1WqfuUM3*~eSBKlBB^PN!>?t-6iEv5);+a&1B5 z!Fay@#vNnFUo9&hAo`pD#{|PfG3N$sb`Bgpcw{l*OALn+(Z_4Ip0`P^Zp&$3x>eea zPdb*UY)R&h<`C$B+z;Jj_HbrRTk<5{!s#sGQ36|r6U&rThNf#NpS8V8(GE^d?egBP zrG#(`!Q$}fP_m_-Yn<7QQjzi(5WBdxD|}vBQS*fJfWUipNifea>@KAjmIY7RLYOHI z{7#FvXc|ec5zdMJp##puo1AV4(R;#~WTtG_8U@Mzp&N16;>m0A#i`m-P@4+EvAO0w zunzQ%-s54Q3VDmCqEL_{;X*o>wVCDu{D_5xI69E#8Z#Z*%pwhj;IWiL^br=8NbtM_ zv7*%%yrlEWGecL3&ut=I3z|wuzP0#EKa5#59XTSgpjeW^20z1Ki;j!;E#a;RokA## za-*jC&%&$tgYvanEzNiF?qb2hv2>GMPT+S!)Vdmk{D!Sqqt z*J^9q$+RqAsk!X|!)+dqXEk(lZ&wd@i~c#G_3!A3IuTv_eZKj# zY3C+W)aS?W^R)T?Q778D>DZ5|4d*c1z+uw{-Exm-;hxJsrIUGWnn#NnwaJp0&#Cu6yLNm90IIV9MbL`W`GeS=xMy8X|U1^>1IkVu$zd z`4+5_l+F6yj`bu^b8W*#T7uKux2hpju;Ps{2-D@XU_4VU=i2tA_A_?9)UjuaNA_BOUjoTg z3SeHaok_tAtToM9Jv+5tpm)TWF|HElIhRr`f&raPsl5o9wAZ~^#Ow*%ARWNAa$~z( z97$*xsGh#{CgT0dPh3z85^Oh(Ug$u7Z#+1XaF#HpGV>HjGUonr{$JSih%viA^LaAg$$LlJCLwOv?OCR=WlIT~j6+89 zb56qaPBye>t9|=GwSBIH#_Xqe&jhcSy|gv3mujb)yD2*!iGZ9}@&40!dlAYga3ice zP8a&~j&Jg9(v#1A($Y_AyM7pHGcG^wKGP0;oTpyAK2MuV9=)Tf7xC@FJN_jcvKytIJyY%3)xyZiiHYdYQujK}?@%!D z80`d7e5K$dZLax>3*0Q!N%4oz!jCD7*Ke`pPbyN^+t)GxpmLuG&{xP5T!|+xFSLj_PA;H|h zi1(|^$nzGs3V+pZ5}woSf@1Lm`~o&iHPF+;t$-tX1#>-H$-Ot=+5#i=%pQdWt4S_O zsW=YrWn9vF?u+g&V|g_`XK-S`L(&gqRG!VDMpO{j*e!qwhJPhw(#R=6@~dP7Ke&+h zoUaR?mLUUE}^_sQ-|kOz%lwnskO%Xg2NOsAp?EXCZ6%(yny8vgIpP(cF{`dLx^i9#~Psa(vdc zOl4PNOo)%71q;c#lI7XSIcA4zwrCyUKx`&ix+on}*EZ?fbI(6({qe+k!*nG0kH>0% z-r5{WFFH*KIL%JMvLyUlT4otqFi%)+XJ7pvS$x=!7C!_Ba1Oe{j#hLHVlW57GeQap zIjt<5EeHloKn#=tAxMO)%%#FAus>)Q?8Cy5L_BK)!Kf=;0#AJC35(0H-$z$n-VPK~xZHuYR!_$@(s@2B}pm3!NGM)EWJZM)l+?z+0Di*4T3x8J*P z?dkkEUw%)2{F*-`Za#h(CG|Oa&gY4C{m2vTy3n>CdfLEc^G!N$!(*87OE{`|p_wnN z_{gvRh7Xt{&iMfRKpMU&HZkP9( zHfkSxEMK;tjKhhQ>kaF$rAmx8qj&Lwn2Fh;Bz*YlEjvCuwz1xoNNI(jX6k zK@+<>*>giQo@;5FXsjgLsLg4cDnB0867;3`o=OSJs6QU}3?WNG0LoG}7Fe*7pc9*_ zZoyH44`bsBa6&@9u|-gdLR`I)U;#nrFpZVkNmvb(o2+mMIC`iPji*F4m5t$Hsk$P= zHvKP3C=}>zyhwQ*&asqqluF)F%T$k`t@2UGIf!v3e8l^ia2;%A9)@^x$809N=WxSH zAtQm3!!qzDLOsDS!qzt_;Zl0QC5$CaDFuY^@WY#Y>PV26av*t60;=#x$^}LawzQ^W z#M8rQ4=#|IFTFIFDfPw%(vg=$+u=hRMT zHMLD|sO`kbJW?62bZ*#d6679@%MySwI4tc_ab)*~HHQVwe)n|#zy&8=FXHx#&yMWt zrzYW6ZI|*J&uLFpFvQ4+@RfCGp&$9fiF3v1kDv&3HO-7cXX%RA?SXx@YJ$f9J-X_b=~8nd<@$eDa{y4 z37x@k;CV(U0~GRbJaU5+<>L_z?Pm833*;OmH zJa{F#-#YEspgT~$a|7#Cv~E7PO0_JGk#rbfbYpQ3#W^oPz~=|UiQbP4YaSXvO1LGE zD}*yB-oTqtQTs6|x(BMmUD*UbYi~Gr@d-}cpgSX+C*CjhlL@ZF~LI^ zenuYRI48wV36mi4$+z84W^^+)&eDGt|D{pt_KO~w?@Y@RV5&;$2=SHieTT^<@n->IZz9N`jPz#dLR ztwr=C)EYYqkfGeW-(e_OLG|_pcMj4!36p+sFgO5ilr=_cm95C64_=3?0#MC#>@aP2=)TgGa{oo)D z5h__gXI`bV8K2)6i<{tbs3c%8m277ePv8 zOHRZ&1Nj-}gb>FO(HQ~7%ja+8iLEQ;VPVEY$E+pqX?`Ccx0GpNQ+BXPhj?%@wcGuI z&2u}JDOGK&Ra(zVEE!w$5@TlAJGFYTYTZ`bx+9FwqTg4pxID|*C>VD?_R>x3u1i);A;U^XlV0+f z7j`u}688TbJZIzDGxqPi+%!#Ld-TR#YiNMkS$QITh(0u%b&ZAep;0ItNn0;G^+kaRY~nk!WQw*Ek6Hd)p<;6!U&wOukaK zc`y*2TH56+O~-9w_rePb`Ly*ZQ};5`^;p2jNbVQOupm|O1IKe2WOf#2L}#Ek8q<;F zbg*GSs3*~bLLqOGI0$}2cb8MqY3UPS zv;Whb>-P5^J!5;Bk!0P8;48W%I+4n#hr;PnMy0Rj!UgeYUnEp}a-u!Vb>W}y-W1*@ z3k6FlUx83YD!<$7X-)_yRX^`B=inDp@28#znpvr=FZ|(6&CUc(4}l)~nYNtsDd1{0 zi=}M{Px6pU3qd1tOyV4%xCLtC!X660>p65X4ucmj5YNNGYbHIN1t|@UhjIzQU5)!x z`Z2t9d#kEGsQscneyFVQrQW~@y|&3{qB=F6f*YRHg!m&2Xj6I)jx#0ArRiWSUYU2V zdO~DX>Lp)zXl`$bCkSTcqUKD>cR1z52fp6kvrb5v;`J(5)I$F?XtRX<(hFz4z&uwQ zpke>X*FI`zR&$gr4-}S5E@?X?mLeq$h}0 zG>Lrj_`KN6ktfsneSNW&2QM8~O9|fe$?9FZZm-*Pkus@xVkn_4C1k|6Ua;=GVBZY( zB;e=l-@W=pG3dOV9G%%-b=&&wmR)U@?DyV!WY>0Uw#6#Egos17?BuhSp9WUju2Z26 z#4I@AXQ}sxtuw3dT(*Lg>sE=n@Wy-v#rBp&)c8B_sx7q6pRqZmL$o zm6RGJB$r2|EaxOJ=oN|7Dr;?i2#jbM!VpYhECHIWoCPV-{i$HFoZC?El_gjZe-fn! zfrxFsyfc=vK)Yxn#>T0HY2py~F|Mlb?q#NjC>WDP&bPV}?>Sf`?Rw$R4X1dfjb?Fs zbI`Qs%ct&S3zOCoc)!xRWP91b3aP$?HoSNQN8vdh&3FMW^*#Vf zEF+JZNcCD8TdDCn!gzf=z<>Z6aM0kwiV~Q5LDCm(P|fia0vL=5#tjZxM7h>bt7w#7 zvwje*r6Sxm%Q-iQC#4*52n{j#@UrIcrPU&|!{rrwE4;2c;wq2BmDcurV`R@%hPGcA z*|^_VyOY-L4}2Rw-Z+U|!6p*saw=yQO6bhSrAU@NHS4v;8dtuzRnmcy)Xl&12s#r2?+uZ?5r?O>Gt}!xb zKB$k^n++RE5qLDuOBhW`+0;0y$TzxGyFIK+SXM_6jA)AsNbe{4#EdQ<_l4hFU;NF- zXWzS|i)CyQxJ7!u?fawBlkNUjEnS4$23{oYZ+>rJPuh&h<~i5kuGsW6ehlRM1}$H0NI!x+oH6#bPA%$_-i2E%B4V6vIr$c8a1!YBL5U zjAu|Ty!`S~Krs}o^ezjq>|k1nN42C7Hbhe=3wDA?PEaN88LejZ^&ZAbl;Lolx7}La zxAx+Y=kU>g4j3bjvwIx4)q-SJbapKsV9ulPY{W1UTM|A)(!x?S zRZ2ddSe0V5)gQWzaSl6K5YS(N5o4|B&}ZoMcLMGVR+qSvNACE>3li4J+iWKo+G`BDy4rb9t-HB!M;xB4LHYJ88 zm=g}khkg}G*2p^T?gSaDrbMsByYLi-_h5v_(9hzrqmK_-gaQ~w1N9Yg1TXe_I#Brn zG|7b!6P-sUh`DDP@u}UgA~@m^O1x*{n^r}4fjwTQ9g%_5yQ2d@v7Zh5JMM+R6@xVi$$Bw#OrA~Wg!ul*=i%6!x+Te(48!ZOh_h?Y{=q_J3N3-`kYF<>Wd8A zDucf)CPa$}ERF$ZWEBoo!z*}>VMa~xuoyxoy!+jAUHx-IuaFQpF|QD8eX$&aKDa6w z2MqLZE9%EwvJHHH7Q=CX&@PgyC`+9Iw+Q)wkqa36!HU974hW4rm=mgdDmsyj92)d4 zv5Jwc3CEGlYK{l&3W)mRvi2IIJv%9An_#E!qVxvf&AA$?TH}q8GkUjFE(pKJUO!_) zTX9q&zBK(2GT9>8blqb|a^vw?#{v#0WrWg2&r=k>e*P$LcaB5*D=#msE&XS2f7@D` z1B*q;E|*L8_U(ICC}?~nH`gk4>qr;6w7V@DB%CgmMe>Heo1#&#TQZlmj>_nsN{`xY zT1;>|l-#)`#N~juS}AWUKVVyPzfrKSjMDbm{j424It zP;-oa16xLE&>#81)wky*`?>AFj(ZcQ8^Drr;VhSWvtrZn#6~00@Iu~l73f;mRubBa z1r`sM);&J4QW3mK__q+nR>DC6(*`SzbvUu~5>H*hRInxdTt7@$y;g8K1ARK{Pc)9w zkMhz3CCe5G4-(J%&RSm>5uVOMjf;51a6GiF?VV@`i|946s^g*wdFbn6W`lKFG+lV0 zdUBd0W3@k(uUK|1eg(zXJK;b)Lw$u-phJOc2~9#4L708)qNu8`9rd*=m~vhVbEHrx zSzNj%x*#G5YcdQl{oTO8LdK2-8Q0-xN1PAdkKcR1P;Ux5XqB*!w zJqyX{W$CR$@zDNQut5(IJZ7R*sY21`NmAu$viZ2g^^6@vgW*DahcgpIJ0Qv~w=%9! z1L;G|GxZ6_D;AD0a-5yaYj|vO)p2%sVjueOi_-s3{eWS@)6|-EJ5xJg(`B{gKY#5R>q;N`wsDq89kY*J z4(%5%-!sdU?cm-$(VVLNmv=uTIwX2V3xOj^WAyS?$G(16xljg4<&Z~Xq=AUOy=Thf zzsa*nJ}BqkJb1^$ClYnMM;@o4x-VR*XzJW5P3+5OCEep4ef$;vZ0g~gMBNt?_czZj z4l3)JU!4ttKX213yo!{Ye@x>9mRa;K__ERr?R18PT$k8JSZYP$jR_wSvvc0Sb?eovt?T3dF z0G4*;`c?blm%gFr+g3^iHdfuqHF4d<&=U>2oES>5l_I3NQ)=#6r)8O3)oK!e3YCIA zxO3NIJQMz+A!hbWwPp``EeXX7dv2#DW}L91xEEUxeH)cHV+?^=0!2a!x(n}O1bA8C zjZKWNNW_!?%PKG7H^f|1%8LRD417z57(d=YDDuunBp~`fF%+1-R4CO2EcKD_MI1i7 zG4R-8MVnPx^cy@K@Kjz(5k!ROhAXRz8L{~aFN(1Q^Sl^0VG8hyUU1lp>PJzLoZ&(v zYLBw29Rh-wK7v&*V7rzCZ!vC^amHfgb>Ph)#a`{_9fWOSoB;!IYYAZsj|F`cG#4z?zg%K&vsFqkXPe~Q+T)A`@v@CpC2LL6 zb`b0fPrD-mz$tM~C3o;fRP&+8JtQjP~#b7vB+1BWF-7M{** z5j`6WrFf;RJuBJYf9n&rQ#-alck`}|L*WF6YDu9&xGNX3?(yL|x29??KC`b)K4fo> zx16&*U+LM$wg*;E^)#-L*FS<(7S9L`B4K4P;$ZA3NI~pQ&J}sVYps401Ma^*{&`=d zAikrI^<$RFMKmUl699-V&Oa9tkCgXUt{>a|e!?ylL)(g-ShHER&UkIxS#?6f?5PxX zw&A5LP#ag)ELGjO!y*@oULvD8?u#sHW1=9KhAMAqUueHzH%eW5t{&Ro`o<-pq}ukr z)22V0#P28jwz>CSiFWY(Vp&g?@qcI$OQH_SE1|NQlbcBL?sf->>NId+}cid`gYU+nuA zC%5c#`*$?oN>)w|tu-y#tx88#Vo+h>b8f`5b7Qo4PdbGm2%5p7B<34&R}^7i0Rv{LVsN;#(k)lx-eOTirv-JnY>OpI%ULxP?YHUmT7bOvvUz*Eey zkStypOG|MlhHKJh9C(%HWPA>HWoz)B)Fv<#NIKF7g6iv^jPK#aQf=Ou!u}#$udN36Wh9qXr=uG`=(fT+%gXD)^2gm4&gJh4rr5ChqL=K}O~8 zm)I(<4yie?emAhIc#M%4pzw%>Bv1!37J#}vCY;35cJpSPsrXzlve!mMd%iYP+cAVL zg{vvc>wSUWjYpBeJ+Af>KbS4}%z+4ZsbI6H;oiUcjlASxAS7#HAfsFK&kfMRr_m~D zhvTH(EQ}1#y(oNz@JH>YEDYGwMX2|px?NV(d}5v>UjU~W#y7@?veiGv5*TDycvrg^ zo0a;LPGp4BglP~Qg`dc*@J}~vt8Nc#pN7B6 z%#ee?Y5Ikc9fLm}))KA!o=Aq^Bpd^}z+GR%(ZoYRMCW`&edIA=7Ld7}KBZE&4ws^1 zI6tu6Kkf8^cib57?U&4^`qed|qsoEsF}E2*wMC+%dp1KyKoV#o{oQ!2QwBIEEYQ39 zC{HRKw}SfikM1??XZBkbn=5ZxGK>Dr)tA9=>|q}WxiLsK)W)Gbd#!1Qgsw1%MSV+h+*mlESu_YHYD>{xyi~Gam9^WizGhcL*%kY1M8_%9`+Np2QCuRKY{bC1;|S(p8eBh6U|oE9;%5XzTImz+(m7hZ;|nE!-Q69R?s}Wr`1l^MdG$oh}oT>ZtL-} z6)Sl+{4+mPtd{*RZ#b7WUhZUe-WDTUC+X zg~sxIr8KfXwez~wclK=FKCu7j&Ch6f&yCOe@5%F<_~puR%aap35*R`Te)H`7K7@+< z{-yhm^Pj)}e$sh+xNv@;F^q1W*T)}zLV(}ViB0>sx4FM*7r!_8&+|g}K%nnPo4!6x z5v(?FdzU0UNZ3dI+;4n41K*p^)ATewO;LJsevmHC5hmFtasS)I3F9O}G;|Q*e7MNl z&HBRLSifvv=w7pjeF*^)BJR$v*n{D=-3x2>>E?agsj+>vYgs9A3o*`=7~+dJZ@KZg zCFLw7W?#VrLd>pKDj0E#Plf|AY%xg*9SPk}RvIqUvU(oJJ1LQ~t-{Q19|i=JwxR?* z7~G%wj0DSq zy*=EqN8^SKJ)V{NjN+n?VWV2PQjX^vvMI@F} z{Zf1cC%o736kf&gAeLY+WeI!&z8o%;NU#!*!A0LCi#>|V=0+q`2h zHG2}sdQvLW*6((#;NB644s0PG*-T0fixQ!Papq56%0@UIdc4A~_HNjh`!Be1>cg&l zE{Yh0F6m^HODj|59LzDq}9(TMDmYudEwiFWzVi}yF_$=??f-lZ|ii3Z&&oVfR1Mhe|T ziY>;|mFN$ijO-G6xp69TI+Kz-6g|fn*H_Vko%0Y;KhYnQe7q6eYf^L0cRI1d#|=2t zr#UIUfng1fBktrhE?A1!iI#B)G2XP}DSQ^MKhZk<=45~3CKGouFLFlcq0vHgRD36t zj<^tC>z=hNT`pTmG^^9;scw}go?I%5M~jzFXJb1$?Yjb9D3?TcSpcN%7{JA2W`uQu z1}D4?gt+QYiB&8bKV4cbFW#C6ogT9gIf0N0ej_Q=qyETxBlTB2Hj&AT-lT055ObI% zX3=<+Kkl}yS}(XkmV=7t;wKmn3DZ@tSM1TFW6|4;UAnxdHi*xu?eO8Mlyknjy^$5t zqNr-$LUbLTRWA{iOv?3yvm?Z#1oNR3>sqy9eaR#!)>F}E_{54s+Jx(Vu%KW;{9+Dq z%g3dFOKGq8`m129woh5y)!0P4)bvL%BX%-lIGk&&gd-T%IIloMEPe@x;Pprr!Kg#R zSm~baj-rxL+}MhFB5v2q@cp^!UE9&LZ2Ni1X6hR>976>LZFU3UVU6JdBO}IK7URJu z`Wp&%EG`$+cH${lB_A-pgE=9fQZ`uejOmig#Ggq5lj@<3E30Q`_8-1--9EK5 zv2EcW#_Aj)!qkqdc?>ziS70I@aT>(z;WQ;YO;}aWG3Z30FOV?6Sg5WF8LkOvH3w zILaKs12d=l^erd3l(A$SNf@!?l2_`Ls@I3dswz;QSu{|)!8wezdY1(%3{9|GJdyp- zFO3a{k&>5ZIpkpFEsBq`pdZ)VU+bBN1(D2)kr28~ze$jGjPdjdT!EHg;7_?Xtne;{ z>?|s_n0ou5SH#|BM;Pa;IcS7@MoP;yXJ=)4MFq3g-J3lut z>fkoQLIIhh&?bzNBfpOs`FuPV;Dy@ddDnKoo7Oy7*;$x#nLo3}lXPK8;qX$h9#DykpXuU=OFa7xM8VA!&6q@J^Z?fRD zO81$L`!>=0w{G3EW9VwN#6Tw90oCS&P#HH%F~mJyB26O1 z#RnEKIS{d$QC*r7Yr!j~XPRcV*DTslyla#$+tn@gb4@JxxZNr(tScC?bAWIv3F#l; zH8j|HuJAb{9LcE7;ND7j1$CPW|IwkkgP|3qI}oPHoq2?->vT?V9qXC}J@Ey>&UaS; zC-sMj9ux6q=m;uA1>PpU#6gHz^_8<;m`CcaaF+P~ns4Go?8Id8rY9Km1N0hpt^~GH z2cgl>kF?D#h!-ri9N5TeR>I>;_q%6pt2Qcv7c^J6SSf4%2fnBUO=AZs`qO-wwBAgx zm!8>OR&6^wQCp@)9DisMn#Vw6St&*bTgHXc?0{x&GyidFTWTEB!lP_9={rK%DN`sW z?W7gh@18s>d}W>s7M>u$e2KS=b5^P5>`Jb0Z=GiC&EB>KSncPzr}Jx#jfWV7aDecR z2~j`&-nU;+x^NA@-IU?!V!rPqQIv|n&O%xIeViT_eX-7q^!{r58+xX6 zF^i|~xbY`A0gET$ap9iEDPbS^v%hivOP_ZG{L}O_Jx$S^fOu`vMPhXE+2%LtoCxYC zr?z9HBj4xhuiEqJH|*m(L*JH^kw}Gd@PVCyHPbU2O5ZykXY2#}D;rN{F8tvE!S<+e zyJc-D%7GZ(cq(R_soJHzD^`-yRmzs6luF3yb*#P2T2uKC4j$O8%a^1i4(#TohDq*} zFq5?h!H#7X9rwgSxL|ATLJXmvOZj&}bq1NMR$O-A+m@2%69iJqD|KrPI<}S1NN|y0 zt-SQim1=QsydqFG$1^c?)cM80?mj%Sa5T2DgaS_3Pe>42i76rs;JFf8&OJ;*09Akrbe@1dndG);H>VQUYE^OkB#?5{9=D<2MPi2oE{yNT)uYNhn=OAr6Ztvlpo(J zD&Zn8hK#2;BmK>8!~U>!O>HUJ)nZQq2xUY;dg%E>>s&^rWw&U5yVniz8J#tua=;K0t0XFls z@=K|yW5KqXj|4vYO?*nc(GX6BU3RG=SjW_sMJPoQ zJenABuMzSlQYa&@C2&rC6~2=P;|^Q$vKmeVIbv?(MNpEIo|RkoWOf&Dn)@f<)Qk+!Gy22s&+5&5lQ-_%axA68;mwWaXuD@#68-g-Ji-PM4;o7!x z8bjstn0^|wYZYJ@w|k?UrPpJhM<=0RrsvIq#zXzNQcu}~?%Lk!mF=G#y=c!j#+Fad zts6+nCS7RScP1V_ZtVA&o_N<`f#3#gHf3+V-%mY%oV2OyNx}I0O&hxZ!%nmnSdlKY z+rf9<2A}-E)_+9Tp5Ei#ciexkbTR*rGtrLs`Zy5uxtKQNvU!H#O!Ivuo+M=x1KyQf z+l|JWGERe_br>4MIkXVNForOdB!xFR{5CSK`A!+Vgl8%S9}IqM)AsO2@D1wIe>^bp z9)#auc$1DUzB84=sCU*&KLI}{!WE0*ofTLpx|G6WOT5?V>SFFRmIIMy`p%^@Htvrs ztG36*>&2;64?K2Z74hf(M2dH>r}{ZWSjuBQWvls2(@s2EWnz45PcS;Oz{(c(6k73QROzOMK|ykC0i6L729p(-G~BR9u5Yg^@3fh?0h!V zd-ba15YczBTw^^pCm5%tu$Lu|33fd z2A=WOCInW$HV$na9 z&B2Xb$tElYvlvlJFMZd|Zfa(K(9PJbir^yn?d%tU`A3jjmkDJd9X^yb~gRI^2Z zX8DUYAe-YMsvfDE!fo{#`o-BVz!;b!|3qHTszGgl#tBLSZRAbPJVFjraXuE|JoInm z5&BPmJT|&u&F--UxT?|_e?r6Hefrv{Z2#r`rv2T6s(qY_R@>D{2v!q&bG^?vL0On5GNwOX(*FShIpt&Dx*O36NbDQAD>8`mYHX6%z& z>LYMa8>E6+I#;x#R>u!NRK+TPWu3{u@~U$r0`=hN)T)iD;~TWCMMxykBEmZa(tAeZ zk&VuJw%4fJIuzWbw@vyT+uyBOnYho{f}M1F)+pyS7eyh zrvrqEf?jhbPM}X1Xnsmomn1Iyi0eJkBf;!!sCTnjt4bd2Ns%iGW;l{ z?hWQQ3oP|1G|zgowN+FmPFI{^Fp?t1VXK*ZQS?YSpJUOI`GFo2#fgSK zfXYa~;6MQ#N55*q4|p=P!53~choA>6x_MYg4Bh$-{a7duGDAV_@Q{~k6T49~z4bnN za5^%2&q5D_rKu>oAL%5kaBQ<+Z2OlR8dJ>;jSb;7#=WlUDcN8a?ZBMRleSyX`)X)0 zyNaBDrf067`3_t4RV3MU7#2U-A&Mt@L;S8U+-pk?U^nPo`pvcLm#y9ITUT?2gFIvF zfxUTFw%=)e#vRFgl16`gj-OxXKL^*x?PHAx_FIoWU=#IYlP$VX<2{|10b$^t;PCBy zPVJ&g60eYNbBp=(IBn|wepAe98FrUxj5lRb{^RO(!JK~l@BGo@=NIee=B90%>nH9# ze(z~|@3es%={o^-!2nI#0GIR>x=+*7^j(t#`H1k6_`XP>bS;98M^p5SzfuyH1-nt` z*kC-h+`MbIs%a~&PAoe-vT65@<;qoyrwUeypGoM#Dqq7B@|-Zl7gx_ zCSqi)5_^2TRVYDiZvUix)3(=d+jg@lhBvd41QEOudcD3aScMkTMN!1FnS}Dv!jno0 zTmJmy{)rfATnv61&-yz92@UPDV>qW3#GKg{RW6on6oe9jXMPgsBw>NWIp&Lzl;WygQU6O)u=a~F2~U9pinRTI9_-tvwg=8qqU~1E zwpk3(87b{}WFu4~1R!j$BqWz}5=c^0TT7s3m0nquFH*eDeVQG{Y>kReW7pVfSYc^v z_4#PpuuJ)|efH9c$JAt7G>RF9c2Ez8 zfdj-%L(d=2B)mxqLs1$^ahLwAW-Kk#{d7_SVN$|+DCuN9^Kd2{M7U8|*=kA*)KGYb zA~&5y-sHZOPC_`!6*z&iD?=$|89O~ZQXiLs-;Px^2mX7v z-m*b3m4YGxSAbrs?`-w-7>yD(`4me9#}B+9b}KR4DNb!C)3bkk@{%1bZc2%b77t#o zAKU44M|D!h`P@d^+X!IMoyUps(X>3z3r+C5{E5Ca20yiXXur^W%PN(UttFuLJ8dbz znwwG-Sbm9VPSUQd=EF`-?T$|)!Bw!?ua_ifj%}}u;H5DUd<(+0e|{%!x0-YNJFh%v z|G}s3*m^RyFPurUf-aFRHu7B)`OfotX0E^MOHZT=?>wfHN`A>7KAUK3g z0a3g{Ki!)c`h*F`x2CFWJpNd?;^5eIGH1lG_i$69UFbwE zxpg~T8+6;YdudB`<;Ab(;+sR!i;3!r*>W~gxp`}5rp{lLNlI$Uy~I$GLkvpdn`dJw z$)Y1D%*!~3C=m-1gD?laCM^in50=G6x7l($=m$0!4BhaHk+nCF5I6KxHSt2^`9_W8QT?o zV;F!jhF2_efCi5?V28nPGM-sX&uUwBoAkTl*Wy{}toR~)WU2lN1mazU7{Sns!ChT; z8DJ*9SV%54){zmCYZO<)W~Iar2p@$Jjd3oe2}!lKtnOu!3+qiYY6IJ^BhO`8iILA2 zBGhmA{Cb6ff9*zLcHkgp36NG0u<)SV$`e*(CEkNkkYS?larZ6+{|FU=0f)sz77IWz zF%K`lSYWqOWK=~4p+D>t;()@eh1QzqEh}DuYzHignYI1(Z|>SqxY%Fh?6bRlwMj!H zUgR-N)p}x<6I&cuvrs_{Z=sy}owRMqTYuQsm}SiBX~KaZGpRm(kcwECA>;+dI=pvD zz=Jr*ln;!75oT8mE1pksQy>_X@xorlo!@Va)Wk1#Z(8MZBeJe34+AOh3(9&wVYyt! z%OU&#aZS?_Mu`)2VnZ=a4LgT;#=2#zHx51b*e#|yGsvLA8BJH!hk+b9Q}ly{FTD<3fd&CbjNxqgrw)wJ7^?9QG}VjwRT3O?@=!e`hLq3d2Mnf-UJ4()&NY{x2^cYphS&Hl4jFWF1mr#2HD zcJf8{2H%q`Rw~wg7hAP>*>Mv<=~j8ct(wcJtfiGS7+3c9tTX7@ z5JS1%+iuitHSAkPZJQ<1wiu4oZ@lA0H`Hc!3uJ`Pi@`|xn0Th>1cvN&Dl53NKr1}R zm#n0UsDs6uqUc4gsQKiF?+G{5r7{3)bn_TT^gXRMOt z`~?<6Ss2kY5DpR|4|F7L7t#{>MPG!A3%I!EHV6IF9&|6lEiTn&^xpytnbJWMs)yIv z*}%eXQn2Klo~-yH^UM$1Q=gM+JBwD#f9NlV2%>Q*y9f;WUtD}}q`AiqAIays*Cf?=^UOHE|gS<_~9=^o zQ_?l`?;ZL1_JaM__nlNEe4C4@;O517k=!Hchb}j=+v9uh=+EPqp7`G6S35xf-totq zJWtcRrwed?4_GDaBfs(+QO31leJNEhaa6R?Y)&9lw5zTuwd`4MeLCLv1< zv6k#xe=xPtY$icrVRw(jC@wuO<|w5!p0R2=6mJzX5z*e=Zb9A^<+2`@pe#Y*s5cOURog2C7jCnvj{_P;;o8oEwe8ol zRwzm7#G5P5Hex9ksg-RNQx;!HXhRT56m2SnfY1=*dD1$nZn8=mk$`7n=s&a7vto>G zgT$W{Ly@qLk(+Hqcm=U#Zz$nzm1){;ekLV+=7L6mkRZly5_n2t;0Hn89*&YWSfuRj zF7eEy;2=n=kA4t~gmnZ7A0zQdysS7lP~Z~GP}mpF8Y4wd-x35cARxRToCksfUb%Rw zqBQPh+9IfP>x?yK#A}|G^jkg9yBIq$2%zBUzk4!cv{kcJ7K*1H&j$9em9T%_`jCBf z{876*y=I*ihf5+H&F$fMJ8Cadt%Me}(s?4y=MQ-DIO!5r%Xfb%oQWY!#_cnWue!oX zB4`JSHH#v=N?-6&N$W?XT;f(7DbRSPVNO{~iF4xxo(Twz%Y}vOf`t3HwZfdnEN=R|wn?)1PHk9{AgM*t^sqfgIxpdo(2P^l!OSsa7K|(!L zaUomg1dB$aX5C)jvM5rzuck;Tm2kcq+pYT0KH0c!*YiipxwhXseNKvqa7}sg(%kWe zm&`3#Mez2|`2~iGy#j4cxsgacJs&U6be?T(omt6J>#=?7G;LovY1o%X&)7dZ+OzvX z!w$wpyFV`3oes*l+2S9>y;f2OX3X`yFaYjH#%4B^X+S*g`$;n@kddpOnfFjCEg}jLs#7p zqyjKlLN749KtC|_Ks%x97;RAa0+k`kCi(=WTX=0(q34HjL^W>a=~e@nEM1CKBmihmAgmakT9B|1|qH&t@nzTUfT zgLTffbD>QMsW4so_TWq+YyIBDDpF)e{Xh!)%1%y4R*FqL7H9$wGO?*})VG~V#X6^l z7MqJVslKduFN|y~{_lrSiO&)Xx>U+ruRl_majRtMABHb+rqog}R2Nc$3k+~7sV7C~ zr;Jr{aXpi)l22K^lC@$wW^W93ttOt$0`St6@}+2Ov@-`oBMXBV^k#Ei3mzB`Mx(%E z@!~P(hiQp^Gd6HGV1%rIagMVZpy@1r*0aPx72QsY7c-9V48b3sz=8lYI-@ayuOKHd zS|q|)K<`uHL4yS$&oK6-G&UMrjE~AgH^Gmb+Ga5hqcZ!)j~aHnpR>bp!R`$5_BUVK zvY*-yt)xCy_)4xAo)-&VZLxkSSgeCK9d&@%Z2ca#gBZcq&nhW7DjN|$3cRTSF+mfbeC}!WHi;z;C2@Au4e|Qw*Nr~(PW)BAV)4|moeqz&_tkKTpu&5-RhUbKtwA-Mu^-p?fOCu}-l zkwEt(&-+}{tQl*bJtKYPuYF);Kf7~e)spm;lKP;o<8`v# ze6ilNmS_bu=GQNGEhCxmzy1B!9R|%>&AxaPTBvqjYve4@Bt{3>zk0`C>_9EuJA7T&fVWaq9RE{;=r4xi~A$2gn%&7#0+Cjfm)# zFKp-@^NKJy?7;oGy{Wxao!C&nnP<#HaDOH}iaE=o0O95a-)ZK9?k%Nb=Aos6CZUQ_(8yKJYFQC#wGqQDvOEq$9KtH10Wt~>^N4<>q4t{S z!W$f#s->bE$5}vR?#(1QIL!1uAyzPE=kk%9&G{2mfoQytPA)z-S>P#7S)%95xY{sv z+Kxe;P>IpvW|ZI$nsJU3EV!`~$IqwH7%=}?*Z@y@y`JlK9Kw3#%GHQQQjTEFu8gh1 z%3c{rT>X-T)75?r?uo0=XKYR1O9US)ok8~(>QOW}wN!;BOz%?HwZn>_&58V?T zjjow}{_y;J^Z7p0rWnfCHM^PE*&E%{jSXSm)Zt&;*M-I_dVVpT=X=LDpNsi;_la_! zruRti1)~lAFq?kuuRl2oPt()%G`;V{wAv6VeLE4>2L>l5c%w46Pv?J6Osi<^_P`P= zT{U(su^x$`7HyH-vMYtIwWTPEGfEJX5WPycw@+nv$Cax5JZmp*vlVY?^>SJQRJ46Z z+*WfO#2Psc$A&E}r1XCoGg+QxRDNJNq>p|-3fWDi5O>`GwJd*wtRK`805 zpYecQpU2?@FP4e4gtbtRm7q56+wYux+)mdw^hk;mMA{kshJb@Z`jQZ(#@Vl4d(Gc zrSKB3>{41nz1od8mkUK2m$8%_)b}u+)7Z_e6XtBUgwiUZMh(FWU^JJ4B!NJ0xuC@s z@4+-DI4|w(;g-EvexzOq3j_~qg7?SkH>wXB@Pda{(DAY`nJc7~-%Y zymuzy;@nVyryE|^p(~MWOD&g+7D$*Q{`c>keB92)s@KOwI0_E=C4U$oeKXf}jfdOE zn@9H5&Lv+&@vXw7^K1yQkG-NvKDN4c0f%qCD36CET{D!tA_39V_I$?FRw+Z8L;t(a zylVfyw+eO~6zphPwbmqKzxKhmZ9CET?b+K!!Fn3l|Ng5lMIr#@f7f*0mdz!Co2N~q z-mQ?$GkyEq-{9XSFVDRb`dqxXx&EFS_OD^uz-^O&gJ9&mV*@i_dJZ4IcbI&t*|J=W@K*|hP$QcF=3~TVXqcCl^s*+0xVW8g_m1yBX`Gq%dN#9WgpH{!z zgE1vsN+#Seh2f|-T?x11_If)j*>U8?+JR(|U=BZv+tsr8pg;w$=MZKO(*f)#S3Hz+ z1Q<)aYmp6*6Onr`u3-e3F2(=clTq@V-b6$JFECD$vcl_oF1y}}b%JpI+4*$Zkn;m#r%EZU6}7eB{H8cZk7 z=P)V}@0$=Bc#YzXPdsPn8wc)TaN*;-mZc=+%q4jVR*;*j4XjH zWH%Bx4z5G;-54%7rZrB;%U+h= z0Z$2k!NP$b^r?AA+gFlN2_N7wVUyAmpe>?b7}Oc|AVAKwEZ}HPihh8{;C|G{ zg&Vl03l2dPt;3Kg*x{t$F|RfD3C$^XYS1o8d)8-xOLXmnAAVMIwjkV$S-01-TD4?n zXJh}kq z-M4Z{^4+{Ecw{{6UsL5YL`(9L`;HzS*)un;I2;1eF%PvP=~qCJ?k4%TP`0UXz7q^> zqVY&&^LBQ0>@p>?EsJ&FTC-7eyt=PCYo(ga!jbZ3EiJ;ZwYP7te)Cnkdi9EE?IYW+ zm0jj7WI3cyb6xNK|JnP~V9Ao~JP`Y0y*J{?;JmVJkEZi2}AL2Vc2oN{!Qks zi2}ukmrSuf!nP9s9Z;XUeEBjO)GaN3II*qx*I?iquaACZ_&dH73z(*#uCcd(IEm_W*Iy_4g1%xC3n zqZJ;S{FMGV=5x`c%N#Y4F+-T`F%r+@xC*fz;u-P~ACevc$J9zCM|x4dQhx;XJ?W+j z?ZsEJEjT*(F0DLO)f8GI@38Io9+HZ@gnf(sS9O=(rG18a^Y|iGI_qq@n(+gL(Q(nC zoKpxP@s~Wu)bVi*UN&t!NU@)-{>(EO9bvy2$N$p*PL^pg?pdMVJMkUTwg1j5Z&RP5 z{ypuY72d`_e{Gc)_%gnKd85d!kSELEmhtIfah*Mqb$FfT`f;!>%<9OWUQ4Ji#CKv z5roME+aC~cu$=Y2>cDdZ3<7z*sf+hIoA}o9ZM$!z_>sKkMHIhLO~QAvp7IRNM0&Va zPvTcQpCDKekQ+0vfWm)*K9v&dHdZzssA#^pR>Q}0@8Vu7fnVJJB=2WsdA}VWrA7af zvZ*AnvJk}l5N!RmCw`r6I6^F$F-24p3!;Gfij?5_sTcT+z$YG-2QxvT33P%l(n!rF z&*dPJM>b4=D`G~ZphQ?lwhQYj?=@GMgs3F&sEugk*`RoAQr1PMD718(ZOlB?_KNp8 zV?Wa-CNd-he6Q%HrIRY2CKzPw(2~~(>nkNr#v6U)K`|Qi3D_Lmihmov?-GI8WXC)W zefF6-!KgNIN_YuOhCPDVBnOL6M;#V>9o1tKPu__ z@0FO<^t?g^$G4evn zW5hEU^)wM2v*q5clPVSd6nR`6?O}kpn=(&XP0UUxM{Bh%<#HdTbOe=^vQ0b>$)j$c z%yGF${z-n=I6C3^0Eu)S&UAzel~u}r7hkyj5HDT3h^rT##HWAd)A-aYub|oPW3#+! z6MORH>UJ9F`aNVFkN4k1qL^PS-%YrtKx)FT(>OxRQ(XUrN4Dsu`YA51ENj}tSmlu6 zz0+oSLq$AQ7(;RUdsD|Ygq32ei9@XOV;$eZRCi7 z+QdHTOp-i*v{->fC0v*x9(Qnm=fq@@mYjQ;6mbCCh_WP1gON{wmO;W4PWr$TzVVzk=$#AX8Iqb$zcE*NLtle2w8GW_q z!d^FlqacfKU$0>>;sdOs-lH#OURXd4-cOmRNojtUF)!_~{KOqU|Da@^hAEcmMwNYx z((;|Ui;LL_{@j%VGRVT!>xya;bLisEXaHn8iojW$|t zAC847lauHY^QO{S_#9*AwM`l*_O<%gEFyVMO0X=N3>s@vN0^w{MF!|>CdWS7F{7Hi zm?hgIj%cgC%^Lu4Wv=lew=zKgWfq>{=kL!i8OWeggSZzz<8%eu>1Lvfco{s5_X z0&&u2==)}Xv``=9FY%0P#;=q--r3iO