diff --git a/Makefile b/Makefile index 32cdb2da3..667aeb622 100644 --- a/Makefile +++ b/Makefile @@ -865,6 +865,7 @@ help: @$(ECHO) " mingw_install - Install the MinGW toolchain (Windows only)" @$(ECHO) " python_install - Install the Python interpreter (Windows only)" @$(ECHO) " nsis_install - Install the NSIS Unicode (Windows only)" + @$(ECHO) " openssl_install - Install the OpenSSL libraries (Windows only)" @$(ECHO) " uncrustify_install - Install the Uncrustify source code beautifier" @$(ECHO) " doxygen_install - Install the Doxygen documentation generator" @$(ECHO) " gtest_install - Install the GoogleTest framework" diff --git a/WHATSNEW.txt b/WHATSNEW.txt index 236577e43..f1d379956 100644 --- a/WHATSNEW.txt +++ b/WHATSNEW.txt @@ -1,3 +1,22 @@ +--- RELEASE-13.06.04 --- +This maintenance release includes the following fixes missing in (previously not released to public) RELEASE-13.06.03. +- Fixed issues with Google Maps; +- Includes new signed version of CDC drivers for Windows platforms; + +JIRA issues addressed in this maintenance release: +OP-1044, OP-1070, OP-1072 +Use the following link for a comprehensive list of issues addressed by this release +http://progress.openpilot.org/browse/OP-1070 + +--- RELEASE-13.06.03 --- + +This maintenance release addresses the following issues: +- Fixed CC3D attitude estimation failure after multiple settings changes and reboots. +- Fixed OPLink crashes when erasing settings + +JIRA issues addressed in this maintenance release: +OP-1049, OP-1050 + --- RELEASE-13.06.02 --- Refactoring of OPLink radio driver. Auto-configuration was removed, and a diff --git a/artwork/PFD/pfd.svg b/artwork/PFD/pfd.svg new file mode 100644 index 000000000..d6c1f8278 --- /dev/null +++ b/artwork/PFD/pfd.svg @@ -0,0 +1,3811 @@ + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + 10 + 10 + + + 20 + 20 + + + 20 + 20 + + + 10 + 10 + + + 30 + 30 + + + 40 + 40 + + + 50 + 50 + + + 60 + 60 + + + 70 + 70 + + + 80 + 80 + + + 90 + 90 + + + 40 + 40 + + + 30 + 30 + + + 60 + 60 + + + 50 + 50 + + + 80 + 80 + + + 70 + 70 + + + 90 + 90 + + + + + + + + ETA + DIST + HOME + + HDG + + + + 00:00:00 + + + 0000000 + 000 + + + + + + + + + + + + + + GPS + Sats + Tx + Rx + Throttle + + + + + mA + + V + + WPT + HDG + DIST + MODE + ETA + + + + + + 99999 + + + 12.60 + + + + + + + + + + + + + + + + + 00:00:00 + + + 00000000 + + + 000 + + + Drive Circle Right + + + description or # + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3D + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + N + 33 + 30 + W + 24 + 21 + S + 15 + 12 + E + 6 + 3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + m/s + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 00000 + + + + + m + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 00000 + + + + + ft/s + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AUTOPILOT + + + + + + MASTER CAUTION + + + + + + RC INPUT + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/flight/Project/Windows USB/OpenPilot-CDC.inf b/flight/Project/Windows USB/OpenPilot-CDC.inf index 17ea68f15..cb81d5239 100644 --- a/flight/Project/Windows USB/OpenPilot-CDC.inf +++ b/flight/Project/Windows USB/OpenPilot-CDC.inf @@ -3,7 +3,9 @@ Signature = "$Windows NT$" Class = Ports ClassGuid = {4D36E978-E325-11CE-BFC1-08002BE10318} Provider = %ProviderName% -DriverVer = 10/15/2009,1.0.0.0 +DriverVer=02/22/2013,2.0.0.0 +CatalogFile.NTx86 = OpenPilot-CDC_x86.cat +CatalogFile.NTamd64 = OpenPilot-CDC_amd64.cat [MANUFACTURER] %ProviderName% = DeviceList, NTx86, NTamd64 diff --git a/flight/Project/Windows USB/openpilot-cdc_amd64.cat b/flight/Project/Windows USB/openpilot-cdc_amd64.cat new file mode 100644 index 000000000..a0ad8ffe6 Binary files /dev/null and b/flight/Project/Windows USB/openpilot-cdc_amd64.cat differ diff --git a/flight/Project/Windows USB/openpilot-cdc_x86.cat b/flight/Project/Windows USB/openpilot-cdc_x86.cat new file mode 100644 index 000000000..4fa87a3dc Binary files /dev/null and b/flight/Project/Windows USB/openpilot-cdc_x86.cat differ diff --git a/flight/libraries/printf-stdarg.c b/flight/libraries/printf-stdarg.c index e4c01552d..c0bbd31f6 100644 --- a/flight/libraries/printf-stdarg.c +++ b/flight/libraries/printf-stdarg.c @@ -54,9 +54,9 @@ static void printchar(char * *str, int c) #define PAD_RIGHT 1 #define PAD_ZERO 2 -static int prints(char * *out, const char *string, int width, int pad) +static int prints(char * *out, const char *string, int width, int pad, int limit) { - register int pc = 0, padchar = ' '; + register int pc = limit, padchar = ' '; if (width > 0) { register int len = 0; @@ -74,37 +74,37 @@ static int prints(char * *out, const char *string, int width, int pad) } } if (!(pad & PAD_RIGHT)) { - for (; width > 0; --width) { + for (; width > 0 && pc; --width) { printchar(out, padchar); - ++pc; + --pc; } } - for (; *string; ++string) { + for (; *string && pc; ++string) { printchar(out, *string); - ++pc; + --pc; } - for (; width > 0; --width) { + for (; width > 0 && pc; --width) { printchar(out, padchar); - ++pc; + --pc; } - return pc; + return limit - pc; } /* the following should be enough for 32 bit int */ #define PRINT_BUF_LEN 12 -static int printi(char * *out, int i, int b, int sg, int width, int pad, int letbase) +static int printi(char * *out, int i, int b, int sg, int width, int pad, int letbase, int limit) { char print_buf[PRINT_BUF_LEN]; register char *s; - register int t, neg = 0, pc = 0; + register int t, neg = 0, pc = limit; register unsigned int u = i; if (i == 0) { print_buf[0] = '0'; print_buf[1] = '\0'; - return prints(out, print_buf, width, pad); + return prints(out, print_buf, width, pad, limit); } if (sg && b == 10 && i < 0) { @@ -124,26 +124,26 @@ static int printi(char * *out, int i, int b, int sg, int width, int pad, int let u /= b; } - if (neg) { + if (neg && pc) { if (width && (pad & PAD_ZERO)) { printchar(out, '-'); - ++pc; + --pc; --width; } else { *--s = '-'; } } - return pc + prints(out, s, width, pad); + return (limit - pc) + prints(out, s, width, pad, pc); } -static int print(char * *out, const char *format, va_list args) +static int print(int limit, char * *out, const char *format, va_list args) { register int width, pad; - register int pc = 0; + register int pc = limit; char scr[2]; - for (; *format != 0; ++format) { + for (; *format != 0 && pc; ++format) { if (*format == '%') { ++format; width = pad = 0; @@ -167,43 +167,43 @@ static int print(char * *out, const char *format, va_list args) } if (*format == 's') { register char *s = (char *)va_arg(args, int); - pc += prints(out, s ? s : "(null)", width, pad); + pc -= prints(out, s ? s : "(null)", width, pad, pc); continue; } if (*format == 'd') { - pc += printi(out, va_arg(args, int), 10, 1, width, pad, 'a'); + pc -= printi(out, va_arg(args, int), 10, 1, width, pad, 'a', pc); continue; } if (*format == 'x') { - pc += printi(out, va_arg(args, int), 16, 0, width, pad, 'a'); + pc -= printi(out, va_arg(args, int), 16, 0, width, pad, 'a', pc); continue; } if (*format == 'X') { - pc += printi(out, va_arg(args, int), 16, 0, width, pad, 'A'); + pc -= printi(out, va_arg(args, int), 16, 0, width, pad, 'A', pc); continue; } if (*format == 'u') { - pc += printi(out, va_arg(args, int), 10, 0, width, pad, 'a'); + pc -= printi(out, va_arg(args, int), 10, 0, width, pad, 'a', pc); continue; } if (*format == 'c') { /* char are converted to int then pushed on the stack */ scr[0] = (char)va_arg(args, int); scr[1] = '\0'; - pc += prints(out, scr, width, pad); + pc -= prints(out, scr, width, pad, pc); continue; } } else { out: printchar(out, *format); - ++pc; + --pc; } } if (out) { **out = '\0'; } va_end(args); - return pc; + return limit - pc; } int printf(const char *format, ...) @@ -211,13 +211,13 @@ int printf(const char *format, ...) va_list args; va_start(args, format); - return print(0, format, args); + return print(-1, 0, format, args); } // TK: added for alternative parameter passing int vprintf(const char *format, va_list args) { - return print(0, format, args); + return print(-1, 0, format, args); } int sprintf(char *out, const char *format, ...) @@ -225,7 +225,7 @@ int sprintf(char *out, const char *format, ...) va_list args; va_start(args, format); - return print(&out, format, args); + return print(-1, &out, format, args); } // TK: added for alternative parameter passing @@ -234,17 +234,22 @@ int vsprintf(char *out, const char *format, va_list args) char *_out; _out = out; - return print(&_out, format, args); + return print(-1, &_out, format, args); } int snprintf(char *buf, size_t count, const char *format, ...) { va_list args; - (void)count; va_start(args, format); - return print(&buf, format, args); + return print(count, &buf, format, args); +} + +// TK: added for alternative parameter passing +int vsnprintf(char *buf, size_t count, const char *format, va_list args) +{ + return print(count, &buf, format, args); } /** diff --git a/flight/modules/Logging/Logging.c b/flight/modules/Logging/Logging.c new file mode 100644 index 000000000..504b58abf --- /dev/null +++ b/flight/modules/Logging/Logging.c @@ -0,0 +1,145 @@ +/** + ****************************************************************************** + * @addtogroup OpenPilotModules OpenPilot Modules + * @{ + * @addtogroup LoggingModule Logging Module + * @brief Features for on board logging + * @{ + * + * @file Logging.c + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2013. + * @brief Logging module, provides features for on board logging + * @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 "openpilot.h" +#include "debuglogsettings.h" +#include "debuglogcontrol.h" +#include "debuglogstatus.h" +#include "debuglogentry.h" +#include "flightstatus.h" + +// private variables +static DebugLogSettingsData settings; +static DebugLogControlData control; +static DebugLogStatusData status; +static FlightStatusData flightstatus; +static DebugLogEntryData *entry; // would be better on stack but event dispatcher stack might be insufficient + +// private functions +static void SettingsUpdatedCb(UAVObjEvent *ev); +static void ControlUpdatedCb(UAVObjEvent *ev); +static void StatusUpdatedCb(UAVObjEvent *ev); +static void FlightStatusUpdatedCb(UAVObjEvent *ev); + +int32_t LoggingInitialize(void) +{ + DebugLogSettingsInitialize(); + DebugLogControlInitialize(); + DebugLogStatusInitialize(); + DebugLogEntryInitialize(); + FlightStatusInitialize(); + PIOS_DEBUGLOG_Initialize(); + entry = pvPortMalloc(sizeof(DebugLogEntryData)); + if (!entry) { + return -1; + } + + return 0; +} + +int32_t LoggingStart(void) +{ + DebugLogSettingsConnectCallback(SettingsUpdatedCb); + DebugLogControlConnectCallback(ControlUpdatedCb); + FlightStatusConnectCallback(FlightStatusUpdatedCb); + SettingsUpdatedCb(DebugLogSettingsHandle()); + + UAVObjEvent ev = { .obj = DebugLogSettingsHandle(), .instId = 0, .event = EV_UPDATED_PERIODIC }; + EventPeriodicCallbackCreate(&ev, StatusUpdatedCb, 1000); + // invoke a periodic dispatcher callback - the event struct is a dummy, it could be filled with anything! + StatusUpdatedCb(&ev); + + return 0; +} +MODULE_INITCALL(LoggingInitialize, LoggingStart); + +static void StatusUpdatedCb(__attribute__((unused)) UAVObjEvent *ev) +{ + PIOS_DEBUGLOG_Info(&status.Flight, &status.Entry, &status.FreeSlots, &status.UsedSlots); + DebugLogStatusSet(&status); +} + +static void FlightStatusUpdatedCb(__attribute__((unused)) UAVObjEvent *ev) +{ + FlightStatusGet(&flightstatus); + if (settings.LoggingEnabled == DEBUGLOGSETTINGS_LOGGINGENABLED_ONLYWHENARMED) { + if (flightstatus.Armed != FLIGHTSTATUS_ARMED_ARMED) { + PIOS_DEBUGLOG_Printf("FlightStatus Disarmed: On board Logging disabled."); + PIOS_DEBUGLOG_Enable(0); + } else { + PIOS_DEBUGLOG_Enable(1); + PIOS_DEBUGLOG_Printf("FlightStatus Armed: On board logging enabled."); + } + } +} + +static void SettingsUpdatedCb(__attribute__((unused)) UAVObjEvent *ev) +{ + DebugLogSettingsGet(&settings); + if (settings.LoggingEnabled == DEBUGLOGSETTINGS_LOGGINGENABLED_ALWAYS) { + PIOS_DEBUGLOG_Enable(1); + PIOS_DEBUGLOG_Printf("On board logging enabled."); + } else if (settings.LoggingEnabled == DEBUGLOGSETTINGS_LOGGINGENABLED_DISABLED) { + PIOS_DEBUGLOG_Printf("On board logging disabled."); + PIOS_DEBUGLOG_Enable(0); + } else { + FlightStatusUpdatedCb(NULL); + } +} + +static void ControlUpdatedCb(__attribute__((unused)) UAVObjEvent *ev) +{ + DebugLogControlGet(&control); + if (control.Operation == DEBUGLOGCONTROL_OPERATION_RETRIEVE) { + memset(entry, 0, sizeof(DebugLogEntryData)); + if (PIOS_DEBUGLOG_Read(entry, control.Flight, control.Entry) != 0) { + // reading from log failed, mark as non existent in output + entry->Flight = control.Flight; + entry->Entry = control.Entry; + entry->Type = DEBUGLOGENTRY_TYPE_EMPTY; + } + DebugLogEntrySet(entry); + } else if (control.Operation == DEBUGLOGCONTROL_OPERATION_FORMATFLASH) { + uint8_t armed; + FlightStatusArmedGet(&armed); + if (armed == FLIGHTSTATUS_ARMED_DISARMED) { + PIOS_DEBUGLOG_Format(); + } + } + StatusUpdatedCb(ev); +} + + +/** + * @} + * @} + */ diff --git a/flight/modules/OPLink/oplinkmod.c b/flight/modules/OPLink/oplinkmod.c index a1a4a3442..994e0d5d9 100644 --- a/flight/modules/OPLink/oplinkmod.c +++ b/flight/modules/OPLink/oplinkmod.c @@ -118,6 +118,9 @@ static void systemTask(__attribute__((unused)) void *parameters) /* create all modules thread */ MODULE_TASKCREATE_ALL; + /* start the delayed callback scheduler */ + CallbackSchedulerStart(); + if (mallocFailed) { /* We failed to malloc during task creation, * system behaviour is undefined. Reset and let diff --git a/flight/modules/Telemetry/telemetry.c b/flight/modules/Telemetry/telemetry.c index 2ddb3f5aa..c43cddff7 100644 --- a/flight/modules/Telemetry/telemetry.c +++ b/flight/modules/Telemetry/telemetry.c @@ -88,6 +88,7 @@ static int32_t transmitData(uint8_t *data, int32_t length); static void registerObject(UAVObjHandle obj); static void updateObject(UAVObjHandle obj, int32_t eventType); static int32_t setUpdatePeriod(UAVObjHandle obj, int32_t updatePeriodMs); +static int32_t setLoggingPeriod(UAVObjHandle obj, int32_t updatePeriodMs); static void processObjEvent(UAVObjEvent *ev); static void updateTelemetryStats(); static void gcsTelemetryStatsUpdated(); @@ -180,22 +181,16 @@ static void registerObject(UAVObjHandle obj) UAVObjConnectQueue(obj, priorityQueue, EV_MASK_ALL_UPDATES); return; } else { - UAVObjMetadata metadata; - UAVObjUpdateMode updateMode; - UAVObjGetMetadata(obj, &metadata); - updateMode = UAVObjGetTelemetryUpdateMode(&metadata); + // Setup object for periodic updates + UAVObjEvent ev = { + .obj = obj, + .instId = UAVOBJ_ALL_INSTANCES, + .event = EV_UPDATED_PERIODIC, + }; + EventPeriodicQueueCreate(&ev, queue, 0); + ev.event = EV_LOGGING_PERIODIC; + EventPeriodicQueueCreate(&ev, queue, 0); - /* Only create a periodic event for objects that are periodic */ - if ((updateMode == UPDATEMODE_PERIODIC) || - (updateMode == UPDATEMODE_THROTTLED)) { - // Setup object for periodic updates - UAVObjEvent ev = { - .obj = obj, - .instId = UAVOBJ_ALL_INSTANCES, - .event = EV_UPDATED_PERIODIC, - }; - EventPeriodicQueueCreate(&ev, queue, 0); - } // Setup object for telemetry updates updateObject(obj, EV_NONE); @@ -209,7 +204,7 @@ static void registerObject(UAVObjHandle obj) static void updateObject(UAVObjHandle obj, int32_t eventType) { UAVObjMetadata metadata; - UAVObjUpdateMode updateMode; + UAVObjUpdateMode updateMode, loggingMode; int32_t eventMask; if (UAVObjIsMetaobject(obj)) { @@ -222,46 +217,78 @@ static void updateObject(UAVObjHandle obj, int32_t eventType) // Get metadata UAVObjGetMetadata(obj, &metadata); - updateMode = UAVObjGetTelemetryUpdateMode(&metadata); + updateMode = UAVObjGetTelemetryUpdateMode(&metadata); + loggingMode = UAVObjGetLoggingUpdateMode(&metadata); // Setup object depending on update mode + eventMask = 0; switch (updateMode) { case UPDATEMODE_PERIODIC: // Set update period setUpdatePeriod(obj, metadata.telemetryUpdatePeriod); // Connect queue - eventMask = EV_UPDATED_PERIODIC | EV_UPDATED_MANUAL | EV_UPDATE_REQ; - UAVObjConnectQueue(obj, priorityQueue, eventMask); + eventMask |= EV_UPDATED_PERIODIC | EV_UPDATED_MANUAL | EV_UPDATE_REQ; break; case UPDATEMODE_ONCHANGE: // Set update period setUpdatePeriod(obj, 0); // Connect queue - eventMask = EV_UPDATED | EV_UPDATED_MANUAL | EV_UPDATE_REQ; - UAVObjConnectQueue(obj, priorityQueue, eventMask); + eventMask |= EV_UPDATED | EV_UPDATED_MANUAL | EV_UPDATE_REQ; break; case UPDATEMODE_THROTTLED: if ((eventType == EV_UPDATED_PERIODIC) || (eventType == EV_NONE)) { // If we received a periodic update, we can change back to update on change - eventMask = EV_UPDATED | EV_UPDATED_MANUAL | EV_UPDATE_REQ; + eventMask |= EV_UPDATED | EV_UPDATED_MANUAL | EV_UPDATE_REQ; // Set update period on initialization and metadata change if (eventType == EV_NONE) { setUpdatePeriod(obj, metadata.telemetryUpdatePeriod); } } else { // Otherwise, we just received an object update, so switch to periodic for the timeout period to prevent more updates - eventMask = EV_UPDATED_PERIODIC | EV_UPDATED_MANUAL | EV_UPDATE_REQ; + eventMask |= EV_UPDATED_PERIODIC | EV_UPDATED_MANUAL | EV_UPDATE_REQ; } - UAVObjConnectQueue(obj, priorityQueue, eventMask); break; case UPDATEMODE_MANUAL: // Set update period setUpdatePeriod(obj, 0); // Connect queue - eventMask = EV_UPDATED_MANUAL | EV_UPDATE_REQ; - UAVObjConnectQueue(obj, priorityQueue, eventMask); + eventMask |= EV_UPDATED_MANUAL | EV_UPDATE_REQ; break; } + switch (loggingMode) { + case UPDATEMODE_PERIODIC: + // Set update period + setLoggingPeriod(obj, metadata.loggingUpdatePeriod); + // Connect queue + eventMask |= EV_LOGGING_PERIODIC | EV_LOGGING_MANUAL; + break; + case UPDATEMODE_ONCHANGE: + // Set update period + setLoggingPeriod(obj, 0); + // Connect queue + eventMask |= EV_UPDATED | EV_LOGGING_MANUAL; + break; + case UPDATEMODE_THROTTLED: + if ((eventType == EV_LOGGING_PERIODIC) || (eventType == EV_NONE)) { + // If we received a periodic update, we can change back to update on change + eventMask |= EV_UPDATED | EV_LOGGING_MANUAL; + // Set update period on initialization and metadata change + if (eventType == EV_NONE) { + setLoggingPeriod(obj, metadata.loggingUpdatePeriod); + } + } else { + // Otherwise, we just received an object update, so switch to periodic for the timeout period to prevent more updates + eventMask |= EV_LOGGING_PERIODIC | EV_LOGGING_MANUAL; + } + break; + case UPDATEMODE_MANUAL: + // Set update period + setLoggingPeriod(obj, 0); + // Connect queue + eventMask |= EV_LOGGING_MANUAL; + break; + } + UAVObjConnectQueue(obj, priorityQueue, eventMask); } /** @@ -288,7 +315,7 @@ static void processObjEvent(UAVObjEvent *ev) // Act on event retries = 0; success = -1; - if (ev->event == EV_UPDATED || ev->event == EV_UPDATED_MANUAL || ((ev->event == EV_UPDATED_PERIODIC) && (updateMode != UPDATEMODE_THROTTLED))) { + if ((ev->event == EV_UPDATED && (updateMode == UPDATEMODE_ONCHANGE || updateMode == UPDATEMODE_THROTTLED)) || ev->event == EV_UPDATED_MANUAL || ((ev->event == EV_UPDATED_PERIODIC) && (updateMode != UPDATEMODE_THROTTLED))) { // Send update to GCS (with retries) while (retries < MAX_RETRIES && success == -1) { success = UAVTalkSendObject(uavTalkCon, ev->obj, ev->instId, UAVObjGetTelemetryAcked(&metadata), REQ_TIMEOUT_MS); // call blocks until ack is received or timeout @@ -321,6 +348,24 @@ static void processObjEvent(UAVObjEvent *ev) } } } + // Log UAVObject if necessary + if (ev->obj) { + updateMode = UAVObjGetLoggingUpdateMode(&metadata); + if ((ev->event == EV_UPDATED && (updateMode == UPDATEMODE_ONCHANGE || updateMode == UPDATEMODE_THROTTLED)) || ev->event == EV_LOGGING_MANUAL || ((ev->event == EV_LOGGING_PERIODIC) && (updateMode != UPDATEMODE_THROTTLED))) { + if (ev->instId == UAVOBJ_ALL_INSTANCES) { + success = UAVObjGetNumInstances(ev->obj); + for (retries = 0; retries < success; retries++) { + UAVObjInstanceWriteToLog(ev->obj, retries); + } + } else { + UAVObjInstanceWriteToLog(ev->obj, ev->instId); + } + } + if (updateMode == UPDATEMODE_THROTTLED) { + // If this is UPDATEMODE_THROTTLED, the event mask changes on every event. + updateObject(ev->obj, ev->event); + } + } } /** @@ -447,6 +492,24 @@ static int32_t setUpdatePeriod(UAVObjHandle obj, int32_t updatePeriodMs) return EventPeriodicQueueUpdate(&ev, queue, updatePeriodMs); } +/** + * Set logging update period of object (it must be already setup for periodic updates) + * \param[in] obj The object to update + * \param[in] updatePeriodMs The update period in ms, if zero then periodic updates are disabled + * \return 0 Success + * \return -1 Failure + */ +static int32_t setLoggingPeriod(UAVObjHandle obj, int32_t updatePeriodMs) +{ + UAVObjEvent ev; + + // Add object for periodic updates + ev.obj = obj; + ev.instId = UAVOBJ_ALL_INSTANCES; + ev.event = EV_LOGGING_PERIODIC; + return EventPeriodicQueueUpdate(&ev, queue, updatePeriodMs); +} + /** * Called each time the GCS telemetry stats object is updated. * Trigger a flight telemetry stats update if a connection is not diff --git a/flight/pios/common/pios_debuglog.c b/flight/pios/common/pios_debuglog.c new file mode 100644 index 000000000..167e33329 --- /dev/null +++ b/flight/pios/common/pios_debuglog.c @@ -0,0 +1,225 @@ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @defgroup PIOS_DEBUGLOG Flash log debugging Functions + * @brief Debugging functionality + * @{ + * + * @file pios_debuglog.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 + */ + +/* Project Includes */ +#include "pios.h" +#include "uavobjectmanager.h" +#include "debuglogentry.h" + +// global definitions + + +// Global variables +extern uintptr_t pios_user_fs_id; // flash filesystem for logging + +#if defined(PIOS_INCLUDE_FREERTOS) +static xSemaphoreHandle mutex = 0; +#define mutexlock() xSemaphoreTakeRecursive(mutex, portMAX_DELAY) +#define mutexunlock() xSemaphoreGiveRecursive(mutex) +#else +#define mutexlock() +#define mutexunlock() +#endif + +static bool logging_enabled = false; +static uint16_t flightnum = 0; +static uint16_t lognum = 0; +static DebugLogEntryData *buffer = 0; +#if !defined(PIOS_INCLUDE_FREERTOS) +static DebugLogEntryData staticbuffer; +#endif + +/* Private Function Prototypes */ + +/** + * @brief Initialize the log facility + */ +void PIOS_DEBUGLOG_Initialize() +{ +#if defined(PIOS_INCLUDE_FREERTOS) + if (!mutex) { + mutex = xSemaphoreCreateRecursiveMutex(); + buffer = pvPortMalloc(sizeof(DebugLogEntryData)); + } +#else + buffer = &staticbuffer; +#endif + if (!buffer) { + return; + } + mutexlock(); + lognum = 0; + flightnum = 0; + while (PIOS_FLASHFS_ObjLoad(pios_user_fs_id, flightnum * 256, lognum, (uint8_t *)buffer, sizeof(DebugLogEntryData)) == 0) { + flightnum++; + } + mutexunlock(); +} + + +/** + * @brief Enables or Disables logging globally + * @param[in] enable or disable logging + */ +void PIOS_DEBUGLOG_Enable(uint8_t enabled) +{ + logging_enabled = enabled; +} + +/** + * @brief Write a debug log entry with a uavobject + * @param[in] objectid + * @param[in] instanceid + * @param[in] instanceid + * @param[in] size of object + * @param[in] data buffer + */ +void PIOS_DEBUGLOG_UAVObject(uint32_t objid, uint16_t instid, size_t size, uint8_t *data) +{ + if (!logging_enabled || !buffer) { + return; + } + mutexlock(); + buffer->Flight = flightnum; +#if defined(PIOS_INCLUDE_FREERTOS) + buffer->FlightTime = xTaskGetTickCount() * portTICK_RATE_MS; +#else + buffer->FlightTime = 0; +#endif + buffer->Entry = lognum; + buffer->Type = DEBUGLOGENTRY_TYPE_UAVOBJECT; + buffer->ObjectID = objid; + buffer->InstanceID = instid; + if (size > sizeof(buffer->Data)) { + size = sizeof(buffer->Data); + } + buffer->Size = size; + memset(buffer->Data, 0xff, sizeof(buffer->Data)); + memcpy(buffer->Data, data, size); + + if (PIOS_FLASHFS_ObjSave(pios_user_fs_id, flightnum * 256, lognum, (uint8_t *)buffer, sizeof(DebugLogEntryData)) == 0) { + lognum++; + } + mutexunlock(); +} +/** + * @brief Write a debug log entry with text + * @param[in] format - as in printf + * @param[in] variable arguments for printf + * @param... + */ +void PIOS_DEBUGLOG_Printf(char *format, ...) +{ + if (!logging_enabled || !buffer) { + return; + } + va_list args; + va_start(args, format); + mutexlock(); + memset(buffer->Data, 0xff, sizeof(buffer->Data)); + vsnprintf((char *)buffer->Data, sizeof(buffer->Data), (char *)format, args); + buffer->Flight = flightnum; +#if defined(PIOS_INCLUDE_FREERTOS) + buffer->FlightTime = xTaskGetTickCount() * portTICK_RATE_MS; +#else + buffer->FlightTime = 0; +#endif + buffer->Entry = lognum; + buffer->Type = DEBUGLOGENTRY_TYPE_TEXT; + buffer->ObjectID = 0; + buffer->InstanceID = 0; + buffer->Size = strlen((const char *)buffer->Data); + + if (PIOS_FLASHFS_ObjSave(pios_user_fs_id, flightnum * 256, lognum, (uint8_t *)buffer, sizeof(DebugLogEntryData)) == 0) { + lognum++; + } + mutexunlock(); +} + + +/** + * @brief Load one object instance from the filesystem + * @param[out] buffer where to store the uavobject + * @param[in] log entry from which flight + * @param[in] log entry sequence number + * @return 0 if success or error code + * @retval -1 if fs_id is not a valid filesystem instance + * @retval -2 if failed to start transaction + * @retval -3 if object not found in filesystem + * @retval -4 if object size in filesystem does not exactly match buffer size + * @retval -5 if reading the object data from flash fails + */ +int32_t PIOS_DEBUGLOG_Read(void *mybuffer, uint16_t flight, uint16_t inst) +{ + PIOS_Assert(mybuffer); + return PIOS_FLASHFS_ObjLoad(pios_user_fs_id, flight * 256, inst, (uint8_t *)mybuffer, sizeof(DebugLogEntryData)); +} + +/** + * @brief Retrieve run time info of logging system + * @param[out] current flight number + * @param[out] next entry number + * @param[out] free slots in filesystem + * @param[out] used slots in filesystem + */ +void PIOS_DEBUGLOG_Info(uint16_t *flight, uint16_t *entry, uint16_t *free, uint16_t *used) +{ + if (flight) { + *flight = flightnum; + } + if (entry) { + *entry = lognum; + } + struct PIOS_FLASHFS_Stats stats = { 0, 0 }; + PIOS_FLASHFS_GetStats(pios_user_fs_id, &stats); + if (free) { + *free = stats.num_free_slots; + } + if (used) { + *used = stats.num_active_slots; + } +} + +/** + * @brief Format entire flash memory!!! + */ +void PIOS_DEBUGLOG_Format(void) +{ + mutexlock(); + PIOS_FLASHFS_Format(pios_user_fs_id); + lognum = 0; + flightnum = 0; + mutexunlock(); +} + +/** + * @} + * @} + */ diff --git a/flight/pios/common/pios_dosfs_logfs.c b/flight/pios/common/pios_dosfs_logfs.c new file mode 100644 index 000000000..0b627e542 --- /dev/null +++ b/flight/pios/common/pios_dosfs_logfs.c @@ -0,0 +1,261 @@ +/** + ****************************************************************************** + * @file pios_dosfs_logfs.c + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2013. + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @brief Log Structured Filesystem wrapper implemented using dosfs + *****************************************************************************/ +/* + * 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_USE_SETTINGS_ON_SDCARD + +#include + +#if defined(PIOS_INCLUDE_FREERTOS) +static xSemaphoreHandle mutex = 0; +#endif + +struct flashfs_logfs_cfg; + + +/** + * Get an 8 character (plus extension) filename for the object. + * @param[in] obj The object handle. + * @param[in] instId The instance ID + * @param[in] file Filename string pointer -- must be 14 bytes long and allocated + */ +static void objectFilename(uint32_t obj_id, uint16_t obj_inst_id, uint8_t *filename) +{ + uint32_t prefix = obj_id + (obj_inst_id / 256) * 16; // put upper 8 bit of instance id into object id modification, + // skip least sig nibble since that is used for meta object id + uint8_t suffix = obj_inst_id & 0xff; + + snprintf((char *)filename, 13, "%08X.o%02X", prefix, suffix); +} + + +/** + * @brief Initialize the flash object setting FS + * @return 0 if success, -1 if failure + */ +int32_t PIOS_FLASHFS_Logfs_Init(__attribute__((unused)) uintptr_t *fs_id, __attribute__((unused)) const struct flashfs_logfs_cfg *cfg, __attribute__((unused)) const struct pios_flash_driver *driver, __attribute__((unused)) uintptr_t flash_id) +{ +#if defined(PIOS_INCLUDE_FREERTOS) + if (!mutex) { + mutex = xSemaphoreCreateRecursiveMutex(); + } +#endif + return 0; +} + +int32_t PIOS_FLASHFS_Logfs_Destroy(__attribute__((unused)) uintptr_t fs_id) +{ + // stub, only wrapper for dosfs, does not need destroying + return 0; +} + +/********************************** + * + * Provide a PIOS_FLASHFS_* driver + * + *********************************/ +#include "pios_flashfs.h" /* API for flash filesystem */ + +/** + * @brief Saves one object instance to the filesystem + * @param[in] fs_id The filesystem to use for this action + * @param[in] obj UAVObject ID of the object to save + * @param[in] obj_inst_id The instance number of the object being saved + * @param[in] obj_data Contents of the object being saved + * @param[in] obj_size Size of the object being saved + * @return 0 if success or error code + * @retval -1 if fs_id is not a valid filesystem instance + * @retval -2 if failed to start transaction + * @retval -3 if failure to delete any previous versions of the object + * @retval -4 if filesystem is entirely full and garbage collection won't help + * @retval -5 if garbage collection failed + * @retval -6 if filesystem is full even after garbage collection should have freed space + * @retval -7 if writing the new object to the filesystem failed + */ +int32_t PIOS_FLASHFS_ObjSave(__attribute__((unused)) uintptr_t fs_id, uint32_t obj_id, uint16_t obj_inst_id, uint8_t *obj_data, uint16_t obj_size) +{ + FILEINFO file; + uint8_t filename[14]; + + if (PIOS_SDCARD_IsMounted() == 0) { + return -1; + } + + // Lock + +#if defined(PIOS_INCLUDE_FREERTOS) + xSemaphoreTakeRecursive(mutex, portMAX_DELAY); +#endif + + // Get filename + objectFilename(obj_id, obj_inst_id, filename); + + // Open file + if (PIOS_FOPEN_WRITE(filename, file)) { +#if defined(PIOS_INCLUDE_FREERTOS) + xSemaphoreGiveRecursive(mutex); +#endif + return -2; + } + // Append object + uint32_t bytes_written = 0; + PIOS_FWRITE(&file, obj_data, obj_size, &bytes_written); + + // Done, close file and unlock + PIOS_FCLOSE(file); +#if defined(PIOS_INCLUDE_FREERTOS) + xSemaphoreGiveRecursive(mutex); +#endif + + if (bytes_written != obj_size) { + return -7; + } + + return 0; +} + +/** + * @brief Load one object instance from the filesystem + * @param[in] fs_id The filesystem to use for this action + * @param[in] obj UAVObject ID of the object to load + * @param[in] obj_inst_id The instance of the object to load + * @param[in] obj_data Buffer to hold the contents of the loaded object + * @param[in] obj_size Size of the object to be loaded + * @return 0 if success or error code + * @retval -1 if fs_id is not a valid filesystem instance + * @retval -2 if failed to start transaction + * @retval -3 if object not found in filesystem + * @retval -4 if object size in filesystem does not exactly match buffer size + * @retval -5 if reading the object data from flash fails + */ +int32_t PIOS_FLASHFS_ObjLoad(__attribute__((unused)) uintptr_t fs_id, uint32_t obj_id, uint16_t obj_inst_id, uint8_t *obj_data, uint16_t obj_size) +{ + FILEINFO file; + uint8_t filename[14]; + + // Check for file system availability + if (PIOS_SDCARD_IsMounted() == 0) { + return -1; + } + +#if defined(PIOS_INCLUDE_FREERTOS) + // Lock + xSemaphoreTakeRecursive(mutex, portMAX_DELAY); +#endif + // Get filename + objectFilename(obj_id, obj_inst_id, filename); + + // Open file + if (PIOS_FOPEN_READ(filename, file)) { +#if defined(PIOS_INCLUDE_FREERTOS) + xSemaphoreGiveRecursive(mutex); +#endif + return -1; + } + // Load object + uint32_t bytes_read = 0; + uint32_t result = PIOS_FREAD(&file, obj_data, obj_size, &bytes_read); + + // Done, close file and unlock + PIOS_FCLOSE(file); +#if defined(PIOS_INCLUDE_FREERTOS) + xSemaphoreGiveRecursive(mutex); +#endif + if (result != 0) { + return -1; + } + return 0; +} + +/** + * @brief Delete one instance of an object from the filesystem + * @param[in] fs_id The filesystem to use for this action + * @param[in] obj UAVObject ID of the object to delete + * @param[in] obj_inst_id The instance of the object to delete + * @return 0 if success or error code + * @retval -1 if fs_id is not a valid filesystem instance + * @retval -2 if failed to start transaction + * @retval -3 if failed to delete the object from the filesystem + */ +int32_t PIOS_FLASHFS_ObjDelete(__attribute__((unused)) uintptr_t fs_id, uint32_t obj_id, uint16_t obj_inst_id) +{ + uint8_t filename[14]; + + // Check for file system availability + if (PIOS_SDCARD_IsMounted() == 0) { + return -1; + } +#if defined(PIOS_INCLUDE_FREERTOS) + // Lock + xSemaphoreTakeRecursive(mutex, portMAX_DELAY); +#endif + // Get filename + objectFilename(obj_id, obj_inst_id, filename); + + // Delete file + PIOS_FUNLINK(filename); + + // Done +#if defined(PIOS_INCLUDE_FREERTOS) + xSemaphoreGiveRecursive(mutex); +#endif + return 0; +} + +/** + * @brief Erases all filesystem arenas and activate the first arena + * @param[in] fs_id The filesystem to use for this action + * @return 0 if success or error code + * @retval -1 if fs_id is not a valid filesystem instance + * @retval -2 if failed to start transaction + * @retval -3 if failed to erase all arenas + * @retval -4 if failed to activate arena 0 + * @retval -5 if failed to mount arena 0 + */ +int32_t PIOS_FLASHFS_Format(__attribute__((unused)) uintptr_t fs_id) +{ + /* stub - not implemented */ + return -1; +} + +/** + * @brief Returs stats for the filesystems + * @param[in] fs_id The filesystem to use for this action + * @return 0 if success or error code + * @retval -1 if fs_id is not a valid filesystem instance + */ +int32_t PIOS_FLASHFS_GetStats(__attribute__((unused)) uintptr_t fs_id, __attribute__((unused)) struct PIOS_FLASHFS_Stats *stats) +{ + /* stub - not implemented */ + return 0; +} + +#endif /* PIOS_USE_SETTINGS_ON_SDCARD */ + +/** + * @} + * @} + */ diff --git a/flight/pios/common/pios_mpu6000.c b/flight/pios/common/pios_mpu6000.c index 371068e0c..5ea27f0c8 100644 --- a/flight/pios/common/pios_mpu6000.c +++ b/flight/pios/common/pios_mpu6000.c @@ -64,7 +64,13 @@ 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); -#define GRAV 9.81f +#define GRAV 9.81f + +#ifdef PIOS_MPU6000_ACCEL +#define PIOS_MPU6000_SAMPLES_BYTES 14 +#else +#define PIOS_MPU6000_SAMPLES_BYTES 8 +#endif /** * @brief Allocate a new device @@ -489,6 +495,62 @@ int32_t PIOS_MPU6000_Test(void) return 0; } +/** + * @brief Reads the contents of the MPU6000 Interrupt Status register from an ISR + * @return The register value or -1 on failure to claim the bus + */ +static int32_t PIOS_MPU6000_GetInterruptStatusRegISR(bool *woken) +{ + /* Interrupt Status register can be read at high SPI clock speed */ + uint8_t data; + + if (PIOS_MPU6000_ClaimBusISR(woken) != 0) { + return -1; + } + PIOS_SPI_TransferByte(dev->spi_id, (0x80 | PIOS_MPU6000_INT_STATUS_REG)); + data = PIOS_SPI_TransferByte(dev->spi_id, 0); + PIOS_MPU6000_ReleaseBusISR(woken); + return data; +} + +/** + * @brief Resets the MPU6000 FIFO from an ISR + * @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 operation was successful + * @return -1 if unable to claim SPI bus + * @return -2 if write to the device failed + */ +static int32_t PIOS_MPU6000_ResetFifoISR(bool *woken) +{ + int32_t result = 0; + + /* Register writes must be at < 1MHz SPI clock. + * Speed can only be changed when SPI bus semaphore is held, but + * device chip select must not be enabled, so we use the direct + * SPI bus claim call here */ + if (PIOS_SPI_ClaimBusISR(dev->spi_id, woken) != 0) { + return -1; + } + /* Reduce SPI clock speed. */ + PIOS_SPI_SetClockSpeed(dev->spi_id, PIOS_SPI_PRESCALER_256); + /* Enable chip select */ + PIOS_SPI_RC_PinSet(dev->spi_id, dev->slave_num, 0); + /* Reset FIFO. */ + if (PIOS_SPI_TransferByte(dev->spi_id, 0x7f & PIOS_MPU6000_USER_CTRL_REG) != 0) { + result = -2; + } else if (PIOS_SPI_TransferByte(dev->spi_id, (dev->cfg->User_ctl | PIOS_MPU6000_USERCTL_FIFO_RST)) != 0) { + result = -2; + } + /* Disable chip select. */ + PIOS_SPI_RC_PinSet(dev->spi_id, dev->slave_num, 1); + /* Increase SPI clock speed. */ + PIOS_SPI_SetClockSpeed(dev->spi_id, PIOS_SPI_PRESCALER_16); + /* Release the SPI bus semaphore. */ + PIOS_SPI_ReleaseBusISR(dev->spi_id, woken); + return result; +} + /** * @brief Obtains the number of bytes in the FIFO. Call from ISR only. * @return the number of bytes in the FIFO @@ -542,8 +604,29 @@ bool PIOS_MPU6000_IRQHandler(void) return false; } + /* Temporary fix for OP-1049. Expected to be superceded for next major release + * by code changes for OP-1039. + * Read interrupt status register to check for FIFO overflow. Must be the + * first read after interrupt, in case the device is configured so that + * any read clears in the status register (PIOS_MPU6000_INT_CLR_ANYRD set in + * interrupt config register) */ + int32_t result; + if ((result = PIOS_MPU6000_GetInterruptStatusRegISR(&woken)) < 0) { + return woken; + } + if (result & PIOS_MPU6000_INT_STATUS_FIFO_OVERFLOW) { + /* The FIFO has overflowed, so reset it, + * to enable sample sync to be recovered. + * If the reset fails, we are in trouble, but + * we keep trying on subsequent interrupts. */ + PIOS_MPU6000_ResetFifoISR(&woken); + /* Return and wait for the next new sample. */ + return woken; + } + + /* Usual case - FIFO has not overflowed. */ mpu6000_count = PIOS_MPU6000_FifoDepthISR(&woken); - if (mpu6000_count < (int32_t)sizeof(struct pios_mpu6000_data)) { + if (mpu6000_count < PIOS_MPU6000_SAMPLES_BYTES) { return woken; } @@ -551,8 +634,8 @@ bool PIOS_MPU6000_IRQHandler(void) return woken; } - static uint8_t mpu6000_send_buf[1 + sizeof(struct pios_mpu6000_data)] = { PIOS_MPU6000_FIFO_REG | 0x80, 0, 0, 0, 0, 0, 0, 0, 0 }; - static uint8_t mpu6000_rec_buf[1 + sizeof(struct pios_mpu6000_data)]; + static uint8_t mpu6000_send_buf[1 + PIOS_MPU6000_SAMPLES_BYTES] = { PIOS_MPU6000_FIFO_REG | 0x80 }; + static uint8_t mpu6000_rec_buf[1 + PIOS_MPU6000_SAMPLES_BYTES]; if (PIOS_SPI_TransferBlock(dev->spi_id, &mpu6000_send_buf[0], &mpu6000_rec_buf[0], sizeof(mpu6000_send_buf), NULL) < 0) { PIOS_MPU6000_ReleaseBusISR(&woken); @@ -565,7 +648,7 @@ bool PIOS_MPU6000_IRQHandler(void) static struct pios_mpu6000_data data; // In the case where extras samples backed up grabbed an extra - if (mpu6000_count >= (int32_t)(sizeof(data) * 2)) { + if (mpu6000_count >= PIOS_MPU6000_SAMPLES_BYTES * 2) { mpu6000_fifo_backup++; if (PIOS_MPU6000_ClaimBusISR(&woken) != 0) { return woken; diff --git a/flight/pios/inc/pios_debuglog.h b/flight/pios/inc/pios_debuglog.h new file mode 100644 index 000000000..62023dc4d --- /dev/null +++ b/flight/pios/inc/pios_debuglog.h @@ -0,0 +1,97 @@ +/** + ****************************************************************************** + * @addtogroup PIOS PIOS Core hardware abstraction layer + * @{ + * @defgroup PIOS_DEBUGLOG Flash log debugging Functions + * @brief Debugging functionality + * @{ + * + * @file pios_debuglog.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 + */ + +#ifndef PIOS_DEBUGLOG_H +#define PIOS_DEBUGLOG_H + + +/** + * @brief Initialize the log facility + */ +void PIOS_DEBUGLOG_Initialize(); + +/** + * @brief Enables or Disables logging globally + * @param[in] enable or disable logging + */ +void PIOS_DEBUGLOG_Enable(uint8_t enabled); + +/** + * @brief Write a debug log entry with a uavobject + * @param[in] objectid + * @param[in] instanceid + * @param[in] instanceid + * @param[in] size of object + * @param[in] data buffer + */ +void PIOS_DEBUGLOG_UAVObject(uint32_t objid, uint16_t instid, size_t size, uint8_t *data); + +/** + * @brief Write a debug log entry with text + * @param[in] format - as in printf + * @param[in] variable arguments for printf + * @param... + */ +void PIOS_DEBUGLOG_Printf(char *format, ...); + +/** + * @brief Load one object instance from the filesystem + * @param[out] buffer where to store the uavobject + * @param[in] log entry from which flight + * @param[in] log entry sequence number + * @return 0 if success or error code + * @retval -1 if fs_id is not a valid filesystem instance + * @retval -2 if failed to start transaction + * @retval -3 if object not found in filesystem + * @retval -4 if object size in filesystem does not exactly match buffer size + * @retval -5 if reading the object data from flash fails + */ +int32_t PIOS_DEBUGLOG_Read(void *buffer, uint16_t flight, uint16_t inst); + +/** + * @brief Retrieve run time info of logging system + * @param[out] current flight number + * @param[out] next entry number + * @param[out] free slots in filesystem + * @param[out] used slots in filesystem + */ +void PIOS_DEBUGLOG_Info(uint16_t *flight, uint16_t *entry, uint16_t *free, uint16_t *used); + +/** + * @brief Format entire flash memory!!! + */ +void PIOS_DEBUGLOG_Format(void); + +#endif // ifndef PIOS_DEBUGLOG_H + +/** + * @} + * @} + */ diff --git a/flight/pios/inc/pios_mpu6000.h b/flight/pios/inc/pios_mpu6000.h index 91ea89d3e..cda019edf 100644 --- a/flight/pios/inc/pios_mpu6000.h +++ b/flight/pios/inc/pios_mpu6000.h @@ -33,71 +33,72 @@ #define PIOS_MPU6000_H /* MPU6000 Addresses */ -#define PIOS_MPU6000_SMPLRT_DIV_REG 0X19 -#define PIOS_MPU6000_DLPF_CFG_REG 0X1A -#define PIOS_MPU6000_GYRO_CFG_REG 0X1B -#define PIOS_MPU6000_ACCEL_CFG_REG 0X1C -#define PIOS_MPU6000_FIFO_EN_REG 0x23 -#define PIOS_MPU6000_INT_CFG_REG 0x37 -#define PIOS_MPU6000_INT_EN_REG 0x38 -#define PIOS_MPU6000_INT_STATUS_REG 0x3A -#define PIOS_MPU6000_ACCEL_X_OUT_MSB 0x3B -#define PIOS_MPU6000_ACCEL_X_OUT_LSB 0x3C -#define PIOS_MPU6000_ACCEL_Y_OUT_MSB 0x3D -#define PIOS_MPU6000_ACCEL_Y_OUT_LSB 0x3E -#define PIOS_MPU6000_ACCEL_Z_OUT_MSB 0x3F -#define PIOS_MPU6000_ACCEL_Z_OUT_LSB 0x40 -#define PIOS_MPU6000_TEMP_OUT_MSB 0x41 -#define PIOS_MPU6000_TEMP_OUT_LSB 0x42 -#define PIOS_MPU6000_GYRO_X_OUT_MSB 0x43 -#define PIOS_MPU6000_GYRO_X_OUT_LSB 0x44 -#define PIOS_MPU6000_GYRO_Y_OUT_MSB 0x45 -#define PIOS_MPU6000_GYRO_Y_OUT_LSB 0x46 -#define PIOS_MPU6000_GYRO_Z_OUT_MSB 0x47 -#define PIOS_MPU6000_GYRO_Z_OUT_LSB 0x48 -#define PIOS_MPU6000_USER_CTRL_REG 0x6A -#define PIOS_MPU6000_PWR_MGMT_REG 0x6B -#define PIOS_MPU6000_FIFO_CNT_MSB 0x72 -#define PIOS_MPU6000_FIFO_CNT_LSB 0x73 -#define PIOS_MPU6000_FIFO_REG 0x74 -#define PIOS_MPU6000_WHOAMI 0x75 +#define PIOS_MPU6000_SMPLRT_DIV_REG 0X19 +#define PIOS_MPU6000_DLPF_CFG_REG 0X1A +#define PIOS_MPU6000_GYRO_CFG_REG 0X1B +#define PIOS_MPU6000_ACCEL_CFG_REG 0X1C +#define PIOS_MPU6000_FIFO_EN_REG 0x23 +#define PIOS_MPU6000_INT_CFG_REG 0x37 +#define PIOS_MPU6000_INT_EN_REG 0x38 +#define PIOS_MPU6000_INT_STATUS_REG 0x3A +#define PIOS_MPU6000_ACCEL_X_OUT_MSB 0x3B +#define PIOS_MPU6000_ACCEL_X_OUT_LSB 0x3C +#define PIOS_MPU6000_ACCEL_Y_OUT_MSB 0x3D +#define PIOS_MPU6000_ACCEL_Y_OUT_LSB 0x3E +#define PIOS_MPU6000_ACCEL_Z_OUT_MSB 0x3F +#define PIOS_MPU6000_ACCEL_Z_OUT_LSB 0x40 +#define PIOS_MPU6000_TEMP_OUT_MSB 0x41 +#define PIOS_MPU6000_TEMP_OUT_LSB 0x42 +#define PIOS_MPU6000_GYRO_X_OUT_MSB 0x43 +#define PIOS_MPU6000_GYRO_X_OUT_LSB 0x44 +#define PIOS_MPU6000_GYRO_Y_OUT_MSB 0x45 +#define PIOS_MPU6000_GYRO_Y_OUT_LSB 0x46 +#define PIOS_MPU6000_GYRO_Z_OUT_MSB 0x47 +#define PIOS_MPU6000_GYRO_Z_OUT_LSB 0x48 +#define PIOS_MPU6000_USER_CTRL_REG 0x6A +#define PIOS_MPU6000_PWR_MGMT_REG 0x6B +#define PIOS_MPU6000_FIFO_CNT_MSB 0x72 +#define PIOS_MPU6000_FIFO_CNT_LSB 0x73 +#define PIOS_MPU6000_FIFO_REG 0x74 +#define PIOS_MPU6000_WHOAMI 0x75 /* FIFO enable for storing different values */ -#define PIOS_MPU6000_FIFO_TEMP_OUT 0x80 -#define PIOS_MPU6000_FIFO_GYRO_X_OUT 0x40 -#define PIOS_MPU6000_FIFO_GYRO_Y_OUT 0x20 -#define PIOS_MPU6000_FIFO_GYRO_Z_OUT 0x10 -#define PIOS_MPU6000_ACCEL_OUT 0x08 +#define PIOS_MPU6000_FIFO_TEMP_OUT 0x80 +#define PIOS_MPU6000_FIFO_GYRO_X_OUT 0x40 +#define PIOS_MPU6000_FIFO_GYRO_Y_OUT 0x20 +#define PIOS_MPU6000_FIFO_GYRO_Z_OUT 0x10 +#define PIOS_MPU6000_ACCEL_OUT 0x08 /* Interrupt Configuration */ -#define PIOS_MPU6000_INT_ACTL 0x80 -#define PIOS_MPU6000_INT_OPEN 0x40 -#define PIOS_MPU6000_INT_LATCH_EN 0x20 -#define PIOS_MPU6000_INT_CLR_ANYRD 0x10 +#define PIOS_MPU6000_INT_ACTL 0x80 +#define PIOS_MPU6000_INT_OPEN 0x40 +#define PIOS_MPU6000_INT_LATCH_EN 0x20 +#define PIOS_MPU6000_INT_CLR_ANYRD 0x10 -#define PIOS_MPU6000_INTEN_OVERFLOW 0x10 -#define PIOS_MPU6000_INTEN_DATA_RDY 0x01 +#define PIOS_MPU6000_INTEN_OVERFLOW 0x10 +#define PIOS_MPU6000_INTEN_DATA_RDY 0x01 /* Interrupt status */ -#define PIOS_MPU6000_INT_STATUS_FIFO_FULL 0x80 -#define PIOS_MPU6000_INT_STATUS_IMU_RDY 0X04 -#define PIOS_MPU6000_INT_STATUS_DATA_RDY 0X01 +#define PIOS_MPU6000_INT_STATUS_FIFO_FULL 0x80 +#define PIOS_MPU6000_INT_STATUS_FIFO_OVERFLOW 0x10 +#define PIOS_MPU6000_INT_STATUS_IMU_RDY 0X04 +#define PIOS_MPU6000_INT_STATUS_DATA_RDY 0X01 /* User control functionality */ -#define PIOS_MPU6000_USERCTL_FIFO_EN 0X40 -#define PIOS_MPU6000_USERCTL_I2C_MST_EN 0x20 -#define PIOS_MPU6000_USERCTL_DIS_I2C 0X10 -#define PIOS_MPU6000_USERCTL_FIFO_RST 0X04 -#define PIOS_MPU6000_USERCTL_SIG_COND 0X02 -#define PIOS_MPU6000_USERCTL_GYRO_RST 0X01 +#define PIOS_MPU6000_USERCTL_FIFO_EN 0X40 +#define PIOS_MPU6000_USERCTL_I2C_MST_EN 0x20 +#define PIOS_MPU6000_USERCTL_DIS_I2C 0X10 +#define PIOS_MPU6000_USERCTL_FIFO_RST 0X04 +#define PIOS_MPU6000_USERCTL_SIG_COND 0X02 +#define PIOS_MPU6000_USERCTL_GYRO_RST 0X01 /* Power management and clock selection */ -#define PIOS_MPU6000_PWRMGMT_IMU_RST 0X80 -#define PIOS_MPU6000_PWRMGMT_INTERN_CLK 0X00 -#define PIOS_MPU6000_PWRMGMT_PLL_X_CLK 0X01 -#define PIOS_MPU6000_PWRMGMT_PLL_Y_CLK 0X02 -#define PIOS_MPU6000_PWRMGMT_PLL_Z_CLK 0X03 -#define PIOS_MPU6000_PWRMGMT_STOP_CLK 0X07 +#define PIOS_MPU6000_PWRMGMT_IMU_RST 0X80 +#define PIOS_MPU6000_PWRMGMT_INTERN_CLK 0X00 +#define PIOS_MPU6000_PWRMGMT_PLL_X_CLK 0X01 +#define PIOS_MPU6000_PWRMGMT_PLL_Y_CLK 0X02 +#define PIOS_MPU6000_PWRMGMT_PLL_Z_CLK 0X03 +#define PIOS_MPU6000_PWRMGMT_STOP_CLK 0X07 enum pios_mpu6000_range { PIOS_MPU6000_SCALE_250_DEG = 0x00, diff --git a/flight/pios/pios.h b/flight/pios/pios.h index 1a566627d..6ba15b104 100644 --- a/flight/pios/pios.h +++ b/flight/pios/pios.h @@ -69,6 +69,7 @@ /* #define DEBUG_LEVEL 0 */ /* #define PIOS_ENABLE_DEBUG_PINS */ #include +#include /* PIOS common functions */ #include diff --git a/flight/pios/pios_sim_posix.h b/flight/pios/pios_sim_posix.h index 642c0b6e9..84fd5440a 100644 --- a/flight/pios/pios_sim_posix.h +++ b/flight/pios/pios_sim_posix.h @@ -78,8 +78,11 @@ extern void PIOS_LED_Init(void); #include #include #include +#include #include #include +#include +#include #if defined(PIOS_INCLUDE_IAP) #include diff --git a/flight/targets/boards/coptercontrol/firmware/inc/pios_config.h b/flight/targets/boards/coptercontrol/firmware/inc/pios_config.h index 09f9b0b51..a8970239b 100644 --- a/flight/targets/boards/coptercontrol/firmware/inc/pios_config.h +++ b/flight/targets/boards/coptercontrol/firmware/inc/pios_config.h @@ -157,7 +157,7 @@ #define PIOS_MANUAL_STACK_SIZE 800 #define PIOS_SYSTEM_STACK_SIZE 660 #define PIOS_STABILIZATION_STACK_SIZE 524 -#define PIOS_TELEM_STACK_SIZE 500 +#define PIOS_TELEM_STACK_SIZE 800 #define PIOS_EVENTDISPATCHER_STACK_SIZE 130 /* This can't be too high to stop eventdispatcher thread overflowing */ diff --git a/flight/targets/boards/oplinkmini/firmware/inc/pios_config.h b/flight/targets/boards/oplinkmini/firmware/inc/pios_config.h index 97f307cb5..ef965b0af 100644 --- a/flight/targets/boards/oplinkmini/firmware/inc/pios_config.h +++ b/flight/targets/boards/oplinkmini/firmware/inc/pios_config.h @@ -157,7 +157,7 @@ #define PIOS_MANUAL_STACK_SIZE 724 #define PIOS_SYSTEM_STACK_SIZE 460 #define PIOS_STABILIZATION_STACK_SIZE 524 -#define PIOS_TELEM_STACK_SIZE 500 +#define PIOS_TELEM_STACK_SIZE 800 #define PIOS_EVENTDISPATCHER_STACK_SIZE 130 /* This can't be too high to stop eventdispatcher thread overflowing */ diff --git a/flight/targets/boards/oplinkmini/firmware/pios_board.c b/flight/targets/boards/oplinkmini/firmware/pios_board.c index ce097f581..85b3a9939 100644 --- a/flight/targets/boards/oplinkmini/firmware/pios_board.c +++ b/flight/targets/boards/oplinkmini/firmware/pios_board.c @@ -127,6 +127,10 @@ void PIOS_Board_Init(void) PIOS_RTC_Init(&pios_rtc_main_cfg); #endif /* PIOS_INCLUDE_RTC */ +#if defined(PIOS_INCLUDE_LED) + PIOS_LED_Init(&pios_led_cfg); +#endif /* PIOS_INCLUDE_LED */ + /* IAP System Setup */ PIOS_IAP_Init(); // check for safe mode commands from gcs @@ -144,9 +148,6 @@ void PIOS_Board_Init(void) OPLinkStatusInitialize(); #endif /* PIOS_INCLUDE_RFM22B */ -#if defined(PIOS_INCLUDE_LED) - PIOS_LED_Init(&pios_led_cfg); -#endif /* PIOS_INCLUDE_LED */ #if defined(PIOS_INCLUDE_TIM) /* Set up pulse timers */ diff --git a/flight/targets/boards/osd/firmware/Makefile b/flight/targets/boards/osd/firmware/Makefile index 70ec0624f..90bc9618e 100644 --- a/flight/targets/boards/osd/firmware/Makefile +++ b/flight/targets/boards/osd/firmware/Makefile @@ -68,7 +68,6 @@ ifndef TESTAPP #endif ## Misc library functions - SRC += $(FLIGHTLIB)/printf2.c SRC += $(FLIGHTLIB)/WorldMagModel.c ## UAVObjects diff --git a/flight/targets/boards/osd/pios_board.h b/flight/targets/boards/osd/pios_board.h index 16dafb34f..9b88a5e3b 100644 --- a/flight/targets/boards/osd/pios_board.h +++ b/flight/targets/boards/osd/pios_board.h @@ -102,7 +102,7 @@ // TELEMETRY // ------------------------ #define TELEM_QUEUE_SIZE 20 -#define PIOS_TELEM_STACK_SIZE 624 +#define PIOS_TELEM_STACK_SIZE 800 // ***************************************************************** // Interrupt Priorities diff --git a/flight/targets/boards/revolution/board_hw_defs.c b/flight/targets/boards/revolution/board_hw_defs.c index 6ecec9522..78d106cbc 100644 --- a/flight/targets/boards/revolution/board_hw_defs.c +++ b/flight/targets/boards/revolution/board_hw_defs.c @@ -682,12 +682,12 @@ const struct pios_rfm22b_cfg *PIOS_BOARD_HW_DEFS_GetRfm22Cfg(uint32_t board_revi #include "pios_flash_internal_priv.h" static const struct flashfs_logfs_cfg flashfs_external_user_cfg = { - .fs_magic = 0x99abcdef, + .fs_magic = 0x99abceff, .total_fs_size = 0x001C0000, /* 2M bytes (32 sectors = entire chip) */ - .arena_size = 0x00010000, /* 256 * slot size */ + .arena_size = 0x000E0000, /* biggest possible arena size fssize/2 */ .slot_size = 0x00000100, /* 256 bytes */ - .start_offset = 0x40000, /* start offset */ + .start_offset = 0x00040000, /* start offset */ .sector_size = 0x00010000, /* 64K bytes */ .page_size = 0x00000100, /* 256 bytes */ }; diff --git a/flight/targets/boards/revolution/firmware/Makefile b/flight/targets/boards/revolution/firmware/Makefile index 07aed3b52..3202b2e1e 100644 --- a/flight/targets/boards/revolution/firmware/Makefile +++ b/flight/targets/boards/revolution/firmware/Makefile @@ -47,6 +47,7 @@ MODULES += Radio MODULES += PathPlanner MODULES += FixedWingPathFollower MODULES += Osd/osdoutout +MODULES += Logging MODULES += Telemetry OPTMODULES += ComUsbBridge diff --git a/flight/targets/boards/revolution/firmware/UAVObjects.inc b/flight/targets/boards/revolution/firmware/UAVObjects.inc index 27563043b..7a63dc9f2 100644 --- a/flight/targets/boards/revolution/firmware/UAVObjects.inc +++ b/flight/targets/boards/revolution/firmware/UAVObjects.inc @@ -36,6 +36,10 @@ UAVOBJSRCFILENAMES += barosensor UAVOBJSRCFILENAMES += airspeedsensor UAVOBJSRCFILENAMES += airspeedsettings UAVOBJSRCFILENAMES += airspeedstate +UAVOBJSRCFILENAMES += debuglogsettings +UAVOBJSRCFILENAMES += debuglogcontrol +UAVOBJSRCFILENAMES += debuglogstatus +UAVOBJSRCFILENAMES += debuglogentry UAVOBJSRCFILENAMES += flightbatterysettings UAVOBJSRCFILENAMES += firmwareiapobj UAVOBJSRCFILENAMES += flightbatterystate diff --git a/flight/targets/boards/revolution/pios_board.h b/flight/targets/boards/revolution/pios_board.h index d6843c7e6..de47db80a 100644 --- a/flight/targets/boards/revolution/pios_board.h +++ b/flight/targets/boards/revolution/pios_board.h @@ -177,7 +177,7 @@ extern uint32_t pios_packet_handler; // TELEMETRY // ------------------------ #define TELEM_QUEUE_SIZE 80 -#define PIOS_TELEM_STACK_SIZE 624 +#define PIOS_TELEM_STACK_SIZE 800 // ------------------------- // System Settings diff --git a/flight/targets/boards/revoproto/pios_board.h b/flight/targets/boards/revoproto/pios_board.h index 2c3dd65cb..6da2bbd9c 100644 --- a/flight/targets/boards/revoproto/pios_board.h +++ b/flight/targets/boards/revoproto/pios_board.h @@ -139,7 +139,7 @@ extern uint32_t pios_com_hkosd_id; // TELEMETRY // ------------------------ #define TELEM_QUEUE_SIZE 80 -#define PIOS_TELEM_STACK_SIZE 624 +#define PIOS_TELEM_STACK_SIZE 800 // ------------------------- // System Settings diff --git a/flight/targets/boards/simposix/board_hw_defs.c b/flight/targets/boards/simposix/board_hw_defs.c index 9971a8d30..6c78422f9 100644 --- a/flight/targets/boards/simposix/board_hw_defs.c +++ b/flight/targets/boards/simposix/board_hw_defs.c @@ -69,3 +69,7 @@ const struct pios_udp_cfg pios_udp_aux_cfg = { #include #endif /* PIOS_INCLUDE_COM */ + +#if defined(PIOS_INCLUDE_FLASH) +#include "pios_flashfs_logfs_priv.h" +#endif diff --git a/flight/targets/boards/simposix/firmware/Makefile b/flight/targets/boards/simposix/firmware/Makefile index 76524166e..c9d719334 100644 --- a/flight/targets/boards/simposix/firmware/Makefile +++ b/flight/targets/boards/simposix/firmware/Makefile @@ -37,6 +37,7 @@ MODULES += FixedWingPathFollower MODULES += VtolPathFollower MODULES += CameraStab MODULES += Telemetry +MODULES += Logging MODULES += FirmwareIAP MODULES += StateEstimation #MODULES += Sensors/simulated/Sensors @@ -97,6 +98,8 @@ SRC += $(MATHLIB)/sin_lookup.c SRC += $(MATHLIB)/pid.c SRC += $(PIOSCORECOMMON)/pios_task_monitor.c +SRC += $(PIOSCORECOMMON)/pios_dosfs_logfs.c +SRC += $(PIOSCORECOMMON)/pios_debuglog.c ## PIOS Hardware include $(PIOS)/posix/library.mk diff --git a/flight/targets/boards/simposix/firmware/UAVObjects.inc b/flight/targets/boards/simposix/firmware/UAVObjects.inc index 4cdf923a3..be99363d3 100644 --- a/flight/targets/boards/simposix/firmware/UAVObjects.inc +++ b/flight/targets/boards/simposix/firmware/UAVObjects.inc @@ -42,6 +42,10 @@ UAVOBJSRCFILENAMES += barosensor UAVOBJSRCFILENAMES += airspeedsensor UAVOBJSRCFILENAMES += airspeedsettings UAVOBJSRCFILENAMES += airspeedstate +UAVOBJSRCFILENAMES += debuglogsettings +UAVOBJSRCFILENAMES += debuglogcontrol +UAVOBJSRCFILENAMES += debuglogstatus +UAVOBJSRCFILENAMES += debuglogentry UAVOBJSRCFILENAMES += flightbatterysettings UAVOBJSRCFILENAMES += firmwareiapobj UAVOBJSRCFILENAMES += flightbatterystate diff --git a/flight/targets/boards/simposix/firmware/pios_board.c b/flight/targets/boards/simposix/firmware/pios_board.c index 9645c753d..d3dcc3f17 100644 --- a/flight/targets/boards/simposix/firmware/pios_board.c +++ b/flight/targets/boards/simposix/firmware/pios_board.c @@ -75,6 +75,7 @@ uint32_t pios_com_telem_rf_id = 0; uint32_t pios_com_bridge_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 of -1 make the port rx only @@ -118,6 +119,13 @@ void PIOS_Board_Init(void) /* Delay system */ PIOS_DELAY_Init(); + // Initialize dosfs fake flash logfs + if (PIOS_FLASHFS_Logfs_Init(&pios_uavo_settings_fs_id, NULL, NULL, 0)) { + PIOS_DEBUG_Assert(0); + } + pios_user_fs_id = pios_uavo_settings_fs_id; + + /* Initialize the task monitor */ if (PIOS_TASK_MONITOR_Initialize(TASKINFO_RUNNING_NUMELEM)) { PIOS_Assert(0); diff --git a/flight/uavobjects/inc/uavobject.h.template b/flight/uavobjects/inc/uavobject.h.template index 572317f01..599ba4fb8 100644 --- a/flight/uavobjects/inc/uavobject.h.template +++ b/flight/uavobjects/inc/uavobject.h.template @@ -79,6 +79,8 @@ static inline void $(NAME)RequestUpdate() { UAVObjRequestUpdate($(NAME)Handle()) static inline void $(NAME)RequestInstUpdate(uint16_t instId) { UAVObjRequestInstanceUpdate($(NAME)Handle(), instId); } static inline void $(NAME)Updated() { UAVObjUpdated($(NAME)Handle()); } static inline void $(NAME)InstUpdated(uint16_t instId) { UAVObjInstanceUpdated($(NAME)Handle(), instId); } +static inline void $(NAME)Logging() { UAVObjLogging($(NAME)Handle()); } +static inline void $(NAME)InstLogging(uint16_t instId) { UAVObjInstanceLogging($(NAME)Handle(), instId); } static inline int32_t $(NAME)GetMetadata(UAVObjMetadata *dataOut) { return UAVObjGetMetadata($(NAME)Handle(), dataOut); } static inline int32_t $(NAME)SetMetadata(const UAVObjMetadata *dataIn) { return UAVObjSetMetadata($(NAME)Handle(), dataIn); } static inline int8_t $(NAME)ReadOnly() { return UAVObjReadOnly($(NAME)Handle()); } diff --git a/flight/uavobjects/inc/uavobjectmanager.h b/flight/uavobjects/inc/uavobjectmanager.h index 202c17f2e..349d7c3dd 100644 --- a/flight/uavobjects/inc/uavobjectmanager.h +++ b/flight/uavobjects/inc/uavobjectmanager.h @@ -44,6 +44,7 @@ #define UAVOBJ_GCS_TELEMETRY_ACKED_SHIFT 3 #define UAVOBJ_TELEMETRY_UPDATE_MODE_SHIFT 4 #define UAVOBJ_GCS_TELEMETRY_UPDATE_MODE_SHIFT 6 +#define UAVOBJ_LOGGING_UPDATE_MODE_SHIFT 8 #define UAVOBJ_UPDATE_MODE_MASK 0x3 typedef void *UAVObjHandle; @@ -73,9 +74,10 @@ typedef enum { * 3 gcsTelemetryAcked Defines if an ack is required for the transactions of this object (1:acked, 0:not acked) * 4-5 telemetryUpdateMode Update mode used by the telemetry module (UAVObjUpdateMode) * 6-7 gcsTelemetryUpdateMode Update mode used by the GCS (UAVObjUpdateMode) + * 8-9 loggingUpdateMode Update mode used by the logging module (UAVObjUpdateMode) */ typedef struct { - uint8_t flags; /** Defines flags for update and logging modes and whether an update should be ACK'd (bits defined above) */ + uint16_t flags; /** Defines flags for update and logging modes and whether an update should be ACK'd (bits defined above) */ uint16_t telemetryUpdatePeriod; /** Update period used by the telemetry module (only if telemetry mode is PERIODIC) */ uint16_t gcsTelemetryUpdatePeriod; /** Update period used by the GCS (only if telemetry mode is PERIODIC) */ uint16_t loggingUpdatePeriod; /** Update period used by the logging module (only if logging mode is PERIODIC) */ @@ -85,19 +87,21 @@ typedef struct { * Event types generated by the objects. */ typedef enum { - EV_NONE = 0x00, /** No event */ - EV_UNPACKED = 0x01, /** Object data updated by unpacking */ - EV_UPDATED = 0x02, /** Object data updated by changing the data structure */ + EV_NONE = 0x00, /** No event */ + EV_UNPACKED = 0x01, /** Object data updated by unpacking */ + EV_UPDATED = 0x02, /** Object data updated by changing the data structure */ EV_UPDATED_MANUAL = 0x04, /** Object update event manually generated */ EV_UPDATED_PERIODIC = 0x08, /** Object update from periodic event */ - EV_UPDATE_REQ = 0x10 /** Request to update object data */ + EV_LOGGING_MANUAL = 0x10, /** Object update event manually generated */ + EV_LOGGING_PERIODIC = 0x20, /** Object update from periodic event */ + EV_UPDATE_REQ = 0x40 /** Request to update object data */ } UAVObjEventType; /** * Helper macros for event masks */ #define EV_MASK_ALL 0 -#define EV_MASK_ALL_UPDATES (EV_UNPACKED | EV_UPDATED | EV_UPDATED_MANUAL | EV_UPDATED_PERIODIC) +#define EV_MASK_ALL_UPDATES (EV_UNPACKED | EV_UPDATED | EV_UPDATED_MANUAL | EV_UPDATED_PERIODIC | EV_LOGGING_MANUAL | EV_LOGGING_PERIODIC) /** * Access types @@ -190,6 +194,8 @@ UAVObjUpdateMode UAVObjGetTelemetryUpdateMode(const UAVObjMetadata *dataOut); void UAVObjSetTelemetryUpdateMode(UAVObjMetadata *dataOut, UAVObjUpdateMode val); UAVObjUpdateMode UAVObjGetGcsTelemetryUpdateMode(const UAVObjMetadata *dataOut); void UAVObjSetTelemetryGcsUpdateMode(UAVObjMetadata *dataOut, UAVObjUpdateMode val); +UAVObjUpdateMode UAVObjGetLoggingUpdateMode(const UAVObjMetadata *dataOut); +void UAVObjSetLoggingUpdateMode(UAVObjMetadata *dataOut, UAVObjUpdateMode val); int8_t UAVObjReadOnly(UAVObjHandle obj); int32_t UAVObjConnectQueue(UAVObjHandle obj_handle, xQueueHandle queue, uint8_t eventMask); int32_t UAVObjDisconnectQueue(UAVObjHandle obj_handle, xQueueHandle queue); @@ -199,7 +205,10 @@ void UAVObjRequestUpdate(UAVObjHandle obj); void UAVObjRequestInstanceUpdate(UAVObjHandle obj_handle, uint16_t instId); void UAVObjUpdated(UAVObjHandle obj); void UAVObjInstanceUpdated(UAVObjHandle obj_handle, uint16_t instId); +void UAVObjLogging(UAVObjHandle obj); +void UAVObjInstanceLogging(UAVObjHandle obj_handle, uint16_t instId); void UAVObjIterate(void (*iterator)(UAVObjHandle obj)); +void UAVObjInstanceWriteToLog(UAVObjHandle obj_handle, uint16_t instId); #endif // UAVOBJECTMANAGER_H diff --git a/flight/uavobjects/uavobject.c.template b/flight/uavobjects/uavobject.c.template index f7e37723f..b9f45b5ae 100644 --- a/flight/uavobjects/uavobject.c.template +++ b/flight/uavobjects/uavobject.c.template @@ -94,7 +94,8 @@ $(INITFIELDS) $(FLIGHTTELEM_ACKED) << UAVOBJ_TELEMETRY_ACKED_SHIFT | $(GCSTELEM_ACKED) << UAVOBJ_GCS_TELEMETRY_ACKED_SHIFT | $(FLIGHTTELEM_UPDATEMODE) << UAVOBJ_TELEMETRY_UPDATE_MODE_SHIFT | - $(GCSTELEM_UPDATEMODE) << UAVOBJ_GCS_TELEMETRY_UPDATE_MODE_SHIFT; + $(GCSTELEM_UPDATEMODE) << UAVOBJ_GCS_TELEMETRY_UPDATE_MODE_SHIFT | + $(LOGGING_UPDATEMODE) << UAVOBJ_LOGGING_UPDATE_MODE_SHIFT; metadata.telemetryUpdatePeriod = $(FLIGHTTELEM_UPDATEPERIOD); metadata.gcsTelemetryUpdatePeriod = $(GCSTELEM_UPDATEPERIOD); metadata.loggingUpdatePeriod = $(LOGGING_UPDATEPERIOD); diff --git a/flight/uavobjects/uavobjectmanager.c b/flight/uavobjects/uavobjectmanager.c index 0ed0e1cfe..66117a1da 100644 --- a/flight/uavobjects/uavobjectmanager.c +++ b/flight/uavobjects/uavobjectmanager.c @@ -184,15 +184,6 @@ static int32_t connectObj(UAVObjHandle obj_handle, xQueueHandle queue, static int32_t disconnectObj(UAVObjHandle obj_handle, xQueueHandle queue, UAVObjEventCallback cb); -#if defined(PIOS_USE_SETTINGS_ON_SDCARD) && defined(PIOS_INCLUDE_FLASH_LOGFS_SETTINGS) -#error Both PIOS_USE_SETTINGS_ON_SDCARD and PIOS_INCLUDE_FLASH_LOGFS_SETTINGS. Only one settings storage allowed. -#endif - -#if defined(PIOS_USE_SETTINGS_ON_SDCARD) -static void objectFilename(UAVObjHandle obj_handle, uint8_t *filename); -static void customSPrintf(uint8_t *buffer, uint8_t *format, ...); -#endif - // Private variables static xSemaphoreHandle mutex; static const UAVObjMetadata defMetadata = { @@ -713,82 +704,43 @@ unlock_exit: return rc; } -#if defined(PIOS_USE_SETTINGS_ON_SDCARD) + /** - * Save the data of the specified object instance to the file system (SD card). - * The object will be appended and the file will not be closed. - * The object data can be restored using the UAVObjLoad function. - * @param[in] obj The object handle. - * @param[in] instId The instance ID - * @param[in] file File to append to - * @return 0 if success or -1 if failure + * Actually write the object's data to the logfile + * \param[in] obj The object handle + * \param[in] instId The object instance ID */ -int32_t UAVObjSaveToFile(UAVObjHandle obj_handle, uint16_t instId, - FILEINFO *file) +void UAVObjInstanceWriteToLog(UAVObjHandle obj_handle, uint16_t instId) { PIOS_Assert(obj_handle); - uint32_t bytesWritten; - // Check for file system availability - if (PIOS_SDCARD_IsMounted() == 0) { - return -1; - } // Lock xSemaphoreTakeRecursive(mutex, portMAX_DELAY); if (UAVObjIsMetaobject(obj_handle)) { - // Get the instance information if (instId != 0) { - xSemaphoreGiveRecursive(mutex); - return -1; - } - // Write the object ID - uint32_t objId = UAVObjGetID(obj_handle); - PIOS_FWRITE(file, &objId, sizeof(objId), - &bytesWritten); - - // Write the data and check that the write was successful - PIOS_FWRITE(file, MetaDataPtr((struct UAVOMeta *)obj_handle), MetaNumBytes, - &bytesWritten); - if (bytesWritten != MetaNumBytes) { - xSemaphoreGiveRecursive(mutex); - return -1; + goto unlock_exit; } + PIOS_DEBUGLOG_UAVObject(UAVObjGetID(obj_handle), instId, MetaNumBytes, (uint8_t *)MetaDataPtr((struct UAVOMeta *)obj_handle)); } else { - struct UAVOData *uavo; + struct UAVOData *obj; InstanceHandle instEntry; - // Cast to object - uavo = (struct UAVOData *)obj_handle; + // Cast handle to object + obj = (struct UAVOData *)obj_handle; - // Get the instance information - instEntry = getInstance(uavo, instId); + // Get the instance + instEntry = getInstance(obj, instId); if (instEntry == NULL) { - xSemaphoreGiveRecursive(mutex); - return -1; - } - // Write the object ID - PIOS_FWRITE(file, &uavo->id, sizeof(uavo->id), - &bytesWritten); - - // Write the instance ID - if (!UAVObjIsSingleInstance(obj_handle)) { - PIOS_FWRITE(file, &instId, - sizeof(instId), &bytesWritten); - } - // Write the data and check that the write was successful - PIOS_FWRITE(file, InstanceData(instEntry), uavo->instance_size, - &bytesWritten); - if (bytesWritten != uavo->instance_size) { - xSemaphoreGiveRecursive(mutex); - return -1; + goto unlock_exit; } + // Pack data + PIOS_DEBUGLOG_UAVObject(UAVObjGetID(obj_handle), instId, obj->instance_size, (uint8_t *)InstanceData(instEntry)); } - // Done + +unlock_exit: xSemaphoreGiveRecursive(mutex); - return 0; } -#endif /* PIOS_USE_SETTINGS_ON_SDCARD */ /** * Save the data of the specified object to the file system (SD card). @@ -797,14 +749,12 @@ int32_t UAVObjSaveToFile(UAVObjHandle obj_handle, uint16_t instId, * The object data can be restored using the UAVObjLoad function. * @param[in] obj The object handle. * @param[in] instId The instance ID - * @param[in] file File to append to * @return 0 if success or -1 if failure */ -int32_t UAVObjSave(UAVObjHandle obj_handle, __attribute__((unused)) uint16_t instId) +int32_t UAVObjSave(UAVObjHandle obj_handle, uint16_t instId) { PIOS_Assert(obj_handle); -#if defined(PIOS_INCLUDE_FLASH_LOGFS_SETTINGS) if (UAVObjIsMetaobject(obj_handle)) { if (instId != 0) { return -1; @@ -828,131 +778,9 @@ int32_t UAVObjSave(UAVObjHandle obj_handle, __attribute__((unused)) uint16_t ins return -1; } } -#endif /* if defined(PIOS_INCLUDE_FLASH_LOGFS_SETTINGS) */ -#if defined(PIOS_USE_SETTINGS_ON_SDCARD) - FILEINFO file; - uint8_t filename[14]; - - // Check for file system availability - if (PIOS_SDCARD_IsMounted() == 0) { - return -1; - } - // Lock - xSemaphoreTakeRecursive(mutex, portMAX_DELAY); - - // Get filename - objectFilename(obj_handle, filename); - - // Open file - if (PIOS_FOPEN_WRITE(filename, file)) { - xSemaphoreGiveRecursive(mutex); - return -1; - } - // Append object - if (UAVObjSaveToFile(obj_handle, instId, &file) == -1) { - PIOS_FCLOSE(file); - xSemaphoreGiveRecursive(mutex); - return -1; - } - // Done, close file and unlock - PIOS_FCLOSE(file); - xSemaphoreGiveRecursive(mutex); -#endif /* PIOS_USE_SETTINGS_ON_SDCARD */ return 0; } -#if defined(PIOS_USE_SETTINGS_ON_SDCARD) -/** - * Load an object from the file system (SD card). - * @param[in] obj The object handle. - * @param[in] file File to read from - * @return 0 if success or -1 if failure - */ -int32_t UAVObjLoadFromFile(UAVObjHandle obj_handle, FILEINFO *file) -{ - uint32_t bytesRead; - struct UAVOBase *objEntry; - InstanceHandle instEntry; - uint32_t objId; - uint16_t instId; - - // Check for file system availability - if (PIOS_SDCARD_IsMounted() == 0) { - return -1; - } - // Get the object - if (obj_handle == 0) { - return -1; - } - objEntry = (struct UAVOBase *)obj_handle; - - // Lock - xSemaphoreTakeRecursive(mutex, portMAX_DELAY); - - // Read the object ID - if (PIOS_FREAD(file, &objId, sizeof(objId), &bytesRead)) { - xSemaphoreGiveRecursive(mutex); - return -1; - } - - // Check that the IDs match - if (objId != UAVObjGetID(obj_handle)) { - xSemaphoreGiveRecursive(mutex); - return -1; - } - - // Get the instance ID - instId = 0; - if (!UAVObjIsSingleInstance(obj_handle)) { - if (PIOS_FREAD - (file, &instId, sizeof(instId), &bytesRead)) { - xSemaphoreGiveRecursive(mutex); - return -1; - } - } - - if (UAVObjIsMetaobject(obj_handle)) { - // If the instance does not exist create it and any other instances before it - if (instId != 0) { - // Error, unlock and return - xSemaphoreGiveRecursive(mutex); - return -1; - } - // Read the instance data - if (PIOS_FREAD - (file, MetaDataPtr((struct UAVOMeta *)obj_handle), MetaNumBytes, &bytesRead)) { - xSemaphoreGiveRecursive(mutex); - return -1; - } - } else { - // Get the instance information - instEntry = getInstance((struct UAVOData *)objEntry, instId); - - // If the instance does not exist create it and any other instances before it - if (instEntry == NULL) { - instEntry = createInstance((struct UAVOData *)objEntry, instId); - if (instEntry == NULL) { - // Error, unlock and return - xSemaphoreGiveRecursive(mutex); - return -1; - } - } - // Read the instance data - if (PIOS_FREAD - (file, InstanceData(instEntry), ((struct UAVOData *)objEntry)->instance_size, &bytesRead)) { - xSemaphoreGiveRecursive(mutex); - return -1; - } - } - - // Fire event - sendEvent(objEntry, instId, EV_UNPACKED); - - // Unlock - xSemaphoreGiveRecursive(mutex); - return 0; -} -#endif /* PIOS_USE_SETTINGS_ON_SDCARD */ /** * Load an object from the file system (SD card). @@ -962,11 +790,10 @@ int32_t UAVObjLoadFromFile(UAVObjHandle obj_handle, FILEINFO *file) * @param[in] instId The object instance * @return 0 if success or -1 if failure */ -int32_t UAVObjLoad(UAVObjHandle obj_handle, __attribute__((unused)) uint16_t instId) +int32_t UAVObjLoad(UAVObjHandle obj_handle, uint16_t instId) { PIOS_Assert(obj_handle); -#if defined(PIOS_INCLUDE_FLASH_LOGFS_SETTINGS) if (UAVObjIsMetaobject(obj_handle)) { if (instId != 0) { return -1; @@ -993,37 +820,7 @@ int32_t UAVObjLoad(UAVObjHandle obj_handle, __attribute__((unused)) uint16_t ins } } -#endif /* if defined(PIOS_INCLUDE_FLASH_LOGFS_SETTINGS) */ -#if defined(PIOS_USE_SETTINGS_ON_SDCARD) - FILEINFO file; - uint8_t filename[14]; - - // Check for file system availability - if (PIOS_SDCARD_IsMounted() == 0) { - return -1; - } - // Lock - xSemaphoreTakeRecursive(mutex, portMAX_DELAY); - - // Get filename - objectFilename(obj_handle, filename); - - // Open file - if (PIOS_FOPEN_READ(filename, file)) { - xSemaphoreGiveRecursive(mutex); - return -1; - } - // Load object - if (UAVObjLoadFromFile(obj_handle, &file) != 0) { - PIOS_FCLOSE(file); - xSemaphoreGiveRecursive(mutex); - return -1; - } - // Done, close file and unlock - PIOS_FCLOSE(file); - xSemaphoreGiveRecursive(mutex); -#endif /* PIOS_USE_SETTINGS_ON_SDCARD */ return 0; } @@ -1033,31 +830,10 @@ int32_t UAVObjLoad(UAVObjHandle obj_handle, __attribute__((unused)) uint16_t ins * @param[in] instId The object instance * @return 0 if success or -1 if failure */ -int32_t UAVObjDelete(UAVObjHandle obj_handle, __attribute__((unused)) uint16_t instId) +int32_t UAVObjDelete(UAVObjHandle obj_handle, uint16_t instId) { PIOS_Assert(obj_handle); -#if defined(PIOS_INCLUDE_FLASH_LOGFS_SETTINGS) PIOS_FLASHFS_ObjDelete(pios_uavo_settings_fs_id, UAVObjGetID(obj_handle), instId); -#endif -#if defined(PIOS_USE_SETTINGS_ON_SDCARD) - uint8_t filename[14]; - - // Check for file system availability - if (PIOS_SDCARD_IsMounted() == 0) { - return -1; - } - // Lock - xSemaphoreTakeRecursive(mutex, portMAX_DELAY); - - // Get filename - objectFilename(obj_handle, filename); - - // Delete file - PIOS_FUNLINK(filename); - - // Done - xSemaphoreGiveRecursive(mutex); -#endif /* PIOS_USE_SETTINGS_ON_SDCARD */ return 0; } @@ -1683,6 +1459,28 @@ void UAVObjSetGcsTelemetryUpdateMode(UAVObjMetadata *metadata, UAVObjUpdateMode SET_BITS(metadata->flags, UAVOBJ_GCS_TELEMETRY_UPDATE_MODE_SHIFT, val, UAVOBJ_UPDATE_MODE_MASK); } +/** + * Get the UAVObject metadata logging update mode + * \param[in] metadata The metadata object + * \return the GCS telemetry update mode + */ +UAVObjUpdateMode UAVObjGetLoggingUpdateMode(const UAVObjMetadata *metadata) +{ + PIOS_Assert(metadata); + return (metadata->flags >> UAVOBJ_LOGGING_UPDATE_MODE_SHIFT) & UAVOBJ_UPDATE_MODE_MASK; +} + +/** + * Set the UAVObject metadata logging update mode member + * \param[in] metadata The metadata object + * \param[in] val The GCS telemetry update mode + */ +void UAVObjSetLoggingUpdateMode(UAVObjMetadata *metadata, UAVObjUpdateMode val) +{ + PIOS_Assert(metadata); + SET_BITS(metadata->flags, UAVOBJ_LOGGING_UPDATE_MODE_SHIFT, val, UAVOBJ_UPDATE_MODE_MASK); +} + /** * Check if an object is read only @@ -1819,6 +1617,28 @@ void UAVObjInstanceUpdated(UAVObjHandle obj_handle, uint16_t instId) xSemaphoreGiveRecursive(mutex); } +/** + * Log the object's data (triggers a EV_LOGGING_MANUAL event on this object). + * \param[in] obj The object handle + */ +void UAVObjLogging(UAVObjHandle obj_handle) +{ + UAVObjInstanceLogging(obj_handle, UAVOBJ_ALL_INSTANCES); +} + +/** + * Log the object's data (triggers a EV_LOGGING_MANUAL event on this object). + * \param[in] obj The object handle + * \param[in] instId The object instance ID + */ +void UAVObjInstanceLogging(UAVObjHandle obj_handle, uint16_t instId) +{ + PIOS_Assert(obj_handle); + xSemaphoreTakeRecursive(mutex, portMAX_DELAY); + sendEvent((struct UAVOBase *)obj_handle, instId, EV_LOGGING_MANUAL); + xSemaphoreGiveRecursive(mutex); +} + /** * Iterate through all objects in the list. * \param iterator This function will be called once for each object, @@ -2043,24 +1863,3 @@ static int32_t disconnectObj(UAVObjHandle obj_handle, xQueueHandle queue, // If this point is reached the queue was not found return -1; } - -#if defined(PIOS_USE_SETTINGS_ON_SDCARD) -/** - * Wrapper for the sprintf function - */ -static void customSPrintf(uint8_t *buffer, uint8_t *format, ...) -{ - va_list args; - - va_start(args, format); - vsprintf((char *)buffer, (char *)format, args); -} - -/** - * Get an 8 character (plus extension) filename for the object. - */ -static void objectFilename(UAVObjHandle obj_handle, uint8_t *filename) -{ - customSPrintf(filename, (uint8_t *)"%X.obj", UAVObjGetID(obj_handle)); -} -#endif /* PIOS_USE_SETTINGS_ON_SDCARD */ diff --git a/ground/openpilotgcs/copydata.pro b/ground/openpilotgcs/copydata.pro index 0f30ae9fc..a0f25f204 100644 --- a/ground/openpilotgcs/copydata.pro +++ b/ground/openpilotgcs/copydata.pro @@ -31,6 +31,9 @@ equals(copydata, 1) { Qt5SerialPort$${DS}.dll \ Qt5Multimedia$${DS}.dll \ Qt5MultimediaWidgets$${DS}.dll \ + Qt5Quick$${DS}.dll \ + Qt5Qml$${DS}.dll \ + Qt5V8$${DS}.dll \ icuin51.dll \ icudt51.dll \ icuuc51.dll @@ -67,12 +70,85 @@ equals(copydata, 1) { data_copy.commands += $(COPY_FILE) $$targetPath(\"$$[QT_INSTALL_PLUGINS]/$$dll\") $$targetPath(\"$$GCS_APP_PATH/$$dll\") $$addNewline() } + # create QtQuick2 plugin directories + QT_QUICK2_DIRS = qtquick \ + qtquick.2 \ + qtquick/layouts \ + qtquick/localstorage \ + qtquick/particles.2 \ + qtquick/privatewidgets \ + qtquick/window.2 \ + qtquick/xmllistmodel + for(dir, QT_QUICK2_DIRS) { + data_copy.commands += -@$(MKDIR) $$targetPath(\"$$GCS_APP_PATH/$$dir\") $$addNewline() + } + + # Copy QtQuick2 complete directories + # These directories have a lot of files + # Easier to copy everything + QTQ_WHOLE_DIRS = qtquick/controls \ + qtquick/dialogs + for(dir, QTQ_WHOLE_DIRS) { + data_copy.commands += $(COPY_DIR) $$targetPath(\"$$[QT_INSTALL_QML]/$$dir\") $$targetPath(\"$$GCS_APP_PATH/$$dir\") $$addNewline() + } + + # Remove the few unwanted DDLs after whole dir copy + QT_QUICK2_DELS = qtquick/controls/qtquickcontrolsplugin \ + qtquick/controls/private/qtquickcontrolsprivateplugin \ + qtquick/dialogs/dialogplugin + + CONFIG(debug, debug|release) { + for(delfile, QT_QUICK2_DELS) { + data_copy.commands += $(DEL_FILE) $$targetPath(\"$$GCS_APP_PATH/$${delfile}.dll\") $$addNewline() + } + } + CONFIG(release, debug|release) { + for(delfile, QT_QUICK2_DELS) { + data_copy.commands += $(DEL_FILE) $$targetPath(\"$$GCS_APP_PATH/$${delfile}d.dll\") $$addNewline() + } + } + + # Remaining QtQuick plugin DLLs + QT_QUICK2_DLLS = QtQuick.2/qtquick2plugin$${DS}.dll \ + QtQuick.2/plugins.qmltypes \ + QtQuick.2/qmldir \ + qtquick/layouts/qquicklayoutsplugin$${DS}.dll \ + qtquick/layouts/plugins.qmltypes \ + qtquick/layouts/qmldir \ + qtquick/localstorage/qmllocalstorageplugin$${DS}.dll \ + qtquick/localstorage/plugins.qmltypes \ + qtquick/localstorage/qmldir \ + qtquick/particles.2/particlesplugin$${DS}.dll \ + qtquick/particles.2/plugins.qmltypes \ + qtquick/particles.2/qmldir \ + qtquick/privatewidgets/widgetsplugin$${DS}.dll \ + qtquick/privatewidgets/plugins.qmltypes \ + qtquick/privatewidgets/qmldir \ + qtquick/window.2/windowplugin$${DS}.dll \ + qtquick/window.2/plugins.qmltypes \ + qtquick/window.2/qmldir \ + qtquick/XmlListModel/qmlxmllistmodelplugin$${DS}.dll \ + qtquick/XmlListModel/plugins.qmltypes \ + qtquick/XmlListModel/qmldir + + for(dll, QT_QUICK2_DLLS) { + data_copy.commands += $(COPY_FILE) $$targetPath(\"$$[QT_INSTALL_QML]/$$dll\") $$targetPath(\"$$GCS_APP_PATH/$$dll\") $$addNewline() + } + # copy MinGW DLLs MINGW_DLLS = SDL.dll for(dll, MINGW_DLLS) { data_copy.commands += $(COPY_FILE) $$targetPath(\"$$(QTMINGW)/$$dll\") $$targetPath(\"$$GCS_APP_PATH/$$dll\") $$addNewline() } + # copy OpenSSL DLLs + OPENSSL_DLLS = \ + ssleay32.dll \ + libeay32.dll + for(dll, OPENSSL_DLLS) { + data_copy.commands += $(COPY_FILE) $$targetPath(\"$$(OPENSSL)/$$dll\") $$targetPath(\"$$GCS_APP_PATH/$$dll\") $$addNewline() + } + data_copy.target = FORCE QMAKE_EXTRA_TARGETS += data_copy } diff --git a/ground/openpilotgcs/share/openpilotgcs/default_configurations/OpenPilotGCS.xml b/ground/openpilotgcs/share/openpilotgcs/default_configurations/OpenPilotGCS.xml index cb6d21ffb..827ea2a1c 100644 --- a/ground/openpilotgcs/share/openpilotgcs/default_configurations/OpenPilotGCS.xml +++ b/ground/openpilotgcs/share/openpilotgcs/default_configurations/OpenPilotGCS.xml @@ -2491,6 +2491,17 @@ + + + + true + 0.0.0 + + + %%DATAPATH%%diagrams/default/system-health.svg + + + diff --git a/ground/openpilotgcs/share/openpilotgcs/pfd/default/AltitudeScale.qml b/ground/openpilotgcs/share/openpilotgcs/pfd/default/AltitudeScale.qml index 05a701f35..18df7808e 100644 --- a/ground/openpilotgcs/share/openpilotgcs/pfd/default/AltitudeScale.qml +++ b/ground/openpilotgcs/share/openpilotgcs/pfd/default/AltitudeScale.qml @@ -1,16 +1,16 @@ -import Qt 4.7 +import QtQuick 2.0 Item { id: sceneItem property variant sceneSize SvgElementImage { - id: altitude_bg - elementName: "altitude-bg" + id: altitude_window + elementName: "altitude-window" sceneSize: sceneItem.sceneSize clip: true - property variant scaledBounds: svgRenderer.scaledElementBounds("pfd.svg", "altitude-bg") + property variant scaledBounds: svgRenderer.scaledElementBounds("pfd.svg", "altitude-window") x: Math.floor(scaledBounds.x * sceneItem.width) y: Math.floor(scaledBounds.y * sceneItem.height) @@ -35,7 +35,7 @@ Item { model: 7 Item { height: altitude_scale.height / 6 - width: altitude_bg.width + width: altitude_window.width Text { text: altitude_scale.topNumber - index*5 @@ -50,16 +50,39 @@ Item { } } } + + SvgElementImage { + id: altitude_vector + elementName: "altitude-vector" + sceneSize: sceneItem.sceneSize + + height: -NedAccel.Down * altitude_scale.height/30 + + anchors.left: parent.left + anchors.bottom: parent.verticalCenter + } + + SvgElementImage { + id: altitude_waypoint + elementName: "altitude-waypoint" + sceneSize: sceneItem.sceneSize + visible: PathDesired.End_Down !== 0.0 + + anchors.left: parent.left + anchors.verticalCenter: parent.verticalCenter + + anchors.verticalCenterOffset: -altitude_scale.height/30 * (PositionState.Down - PathDesired.End_Down) + } } SvgElementImage { - id: altitude_window + id: altitude_box clip: true - elementName: "altitude-window" + elementName: "altitude-box" sceneSize: sceneItem.sceneSize - property variant scaledBounds: svgRenderer.scaledElementBounds("pfd.svg", "altitude-window") + property variant scaledBounds: svgRenderer.scaledElementBounds("pfd.svg", "altitude-box") x: scaledBounds.x * sceneItem.width y: scaledBounds.y * sceneItem.height @@ -72,31 +95,22 @@ Item { color: "white" font { family: "Arial" - pixelSize: parent.height * 0.6 + pixelSize: parent.height * 0.4 } anchors.centerIn: parent } } - SvgElementImage { - id: altitude_unit - elementName: "altitude-unit" - sceneSize: sceneItem.sceneSize - clip: true - - x: Math.floor(scaledBounds.x * sceneItem.width) - y: Math.floor(scaledBounds.y * sceneItem.height) - - Text { - id: altitude_unit_text - text: qmlWidget.altitudeUnit - color: "white" - font { - family: "Arial" - pixelSize: parent.height - } - anchors.right: parent.right + Text { + id: altitude_unit_text + text: qmlWidget.altitudeUnit + color: "white" + font { + family: "Arial" + pixelSize: sceneSize.height * 0.025 } + anchors.top: altitude_window.bottom + anchors.right: altitude_window.right + anchors.margins: font.pixelSize * 0.3 } - } diff --git a/ground/openpilotgcs/share/openpilotgcs/pfd/default/Compass.qml b/ground/openpilotgcs/share/openpilotgcs/pfd/default/Compass.qml index db2ba4d65..198b9502c 100644 --- a/ground/openpilotgcs/share/openpilotgcs/pfd/default/Compass.qml +++ b/ground/openpilotgcs/share/openpilotgcs/pfd/default/Compass.qml @@ -1,4 +1,4 @@ -import Qt 4.7 +import QtQuick 2.0 import "." Item { @@ -6,32 +6,57 @@ Item { property variant sceneSize SvgElementImage { - id: compass - elementName: "compass" + id: compass_fixed + elementName: "compass-fixed" sceneSize: sceneItem.sceneSize - clip: true - x: Math.floor(scaledBounds.x * sceneItem.width) y: Math.floor(scaledBounds.y * sceneItem.height) - //anchors.horizontalCenter: parent.horizontalCenter + } - //split compass band to 8 parts to ensure it doesn't exceed the max texture size - Row { - anchors.centerIn: parent - //the band is 540 degrees wide, AttitudeState.Yaw is converted to -180..180 range - anchors.horizontalCenterOffset: -1*((AttitudeState.Yaw+180+720) % 360 - 180)/540*width + SvgElementImage { + id: compass_plane + elementName: "compass-plane" + sceneSize: sceneItem.sceneSize - Repeater { - model: 5 - SvgElementImage { - id: compass_band - elementName: "compass-band" - sceneSize: background.sceneSize - hSliceCount: 5 - hSlice: index - } + x: Math.floor(scaledBounds.x * sceneItem.width) + y: Math.floor(scaledBounds.y * sceneItem.height) + } + + SvgElementImage { + id: compass_wheel + elementName: "compass-wheel" + sceneSize: sceneItem.sceneSize + + x: Math.floor(scaledBounds.x * sceneItem.width) + y: Math.floor(scaledBounds.y * sceneItem.height) + + rotation: -AttitudeState.Yaw + transformOrigin: Item.Center + + smooth: true + } + + Item { + id: compass_text_box + + property variant scaledBounds: svgRenderer.scaledElementBounds("pfd.svg", "compass-text") + + x: scaledBounds.x * sceneItem.width + y: scaledBounds.y * sceneItem.height + width: scaledBounds.width * sceneItem.width + height: scaledBounds.height * sceneItem.height + + Text { + id: compass_text + text: Math.floor(AttitudeState.Yaw).toFixed() + color: "white" + font { + family: "Arial" + pixelSize: parent.height * 1.2 } + anchors.centerIn: parent } } + } diff --git a/ground/openpilotgcs/share/openpilotgcs/pfd/default/HorizontCenter.qml b/ground/openpilotgcs/share/openpilotgcs/pfd/default/HorizontCenter.qml new file mode 100644 index 000000000..c5f7c36f1 --- /dev/null +++ b/ground/openpilotgcs/share/openpilotgcs/pfd/default/HorizontCenter.qml @@ -0,0 +1,25 @@ +import QtQuick 2.0 + +Item { + id: sceneItem + property variant sceneSize + property real horizontCenter : world_center.y + world_center.height/2 + + SvgElementImage { + id: world_center + elementName: "center-arrows" + sceneSize: background.sceneSize + + x: Math.floor(scaledBounds.x * sceneItem.width) + y: Math.floor(scaledBounds.y * sceneItem.height) + } + + SvgElementImage { + id: world_center_plane + elementName: "center-plane" + sceneSize: background.sceneSize + + x: Math.floor(scaledBounds.x * sceneItem.width) + y: Math.floor(scaledBounds.y * sceneItem.height) + } +} diff --git a/ground/openpilotgcs/share/openpilotgcs/pfd/default/Info.qml b/ground/openpilotgcs/share/openpilotgcs/pfd/default/Info.qml new file mode 100644 index 000000000..2697019a6 --- /dev/null +++ b/ground/openpilotgcs/share/openpilotgcs/pfd/default/Info.qml @@ -0,0 +1,40 @@ +import QtQuick 2.0 + +Item { + id: info + property variant sceneSize + + SvgElementImage { + id: info_bg + elementName: "info-bg" + sceneSize: info.sceneSize + } + + Repeater { + id: satNumberBar + + // hack, qml/js treats qint8 as a char, necessary to convert it back to integer value + property int satNumber : String(GPSPositionSensor.Satellites).charCodeAt(0) + + model: 10 + SvgElementImage { + property int minSatNumber : index+1 + elementName: "gps" + minSatNumber + sceneSize: info.sceneSize + visible: satNumberBar.satNumber >= minSatNumber + } + } + + SvgElementPositionItem { + sceneSize: info.sceneSize + elementName: "gps-mode-text" + + Text { + text: ["No GPS", "No Fix", "Fix2D", "Fix3D"][GPSPositionSensor.Status] + + anchors.centerIn: parent + font.pixelSize: parent.height*1.2 + color: "white" + } + } +} diff --git a/ground/openpilotgcs/share/openpilotgcs/pfd/default/Pfd.qml b/ground/openpilotgcs/share/openpilotgcs/pfd/default/Pfd.qml index e03a20e02..0670e1f36 100644 --- a/ground/openpilotgcs/share/openpilotgcs/pfd/default/Pfd.qml +++ b/ground/openpilotgcs/share/openpilotgcs/pfd/default/Pfd.qml @@ -1,12 +1,11 @@ -import Qt 4.7 -import "." +import QtQuick 2.0 Rectangle { color: "#666666" SvgElementImage { id: background - elementName: "background" + elementName: "pfd-window" fillMode: Image.PreserveAspectFit anchors.fill: parent @@ -14,6 +13,8 @@ Rectangle { Item { id: sceneItem + property variant viewportSize : Qt.size(width, height) + width: parent.paintedWidth height: parent.paintedHeight anchors.centerIn: parent @@ -25,25 +26,23 @@ Rectangle { source: qmlWidget.terrainEnabled ? "PfdTerrainView.qml" : "PfdWorldView.qml" } - SvgElementImage { - id: rollscale - elementName: "rollscale" - sceneSize: background.sceneSize + HorizontCenter { + id: horizontCenterItem + sceneSize: sceneItem.viewportSize + anchors.fill: parent + } - smooth: true - anchors.centerIn: parent - //rotate it around the center of scene - transform: Rotation { - angle: -AttitudeState.Roll - origin.x : sceneItem.width/2 - x - origin.y : sceneItem.height/2 - y - } + RollScale { + id: rollscale + sceneSize: sceneItem.viewportSize + horizontCenter: horizontCenterItem.horizontCenter + anchors.fill: parent } SvgElementImage { id: foreground elementName: "foreground" - sceneSize: background.sceneSize + sceneSize: sceneItem.viewportSize anchors.centerIn: parent } @@ -51,7 +50,7 @@ Rectangle { SvgElementImage { id: side_slip elementName: "sideslip" - sceneSize: background.sceneSize + sceneSize: sceneItem.viewportSize smooth: true property real sideSlip: AccelState.y @@ -72,27 +71,37 @@ Rectangle { Compass { anchors.fill: parent - sceneSize: background.sceneSize + sceneSize: sceneItem.viewportSize } SpeedScale { anchors.fill: parent - sceneSize: background.sceneSize + sceneSize: sceneItem.viewportSize } AltitudeScale { anchors.fill: parent - sceneSize: background.sourceSize + sceneSize: sceneItem.viewportSize } VsiScale { anchors.fill: parent - sceneSize: background.sourceSize + sceneSize: sceneItem.viewportSize } PfdIndicators { anchors.fill: parent - sceneSize: background.sourceSize + sceneSize: sceneItem.viewportSize + } + + Info { + anchors.fill: parent + sceneSize: sceneItem.viewportSize + } + + Warnings { + anchors.fill: parent + sceneSize: sceneItem.viewportSize } } } diff --git a/ground/openpilotgcs/share/openpilotgcs/pfd/default/PfdIndicators.qml b/ground/openpilotgcs/share/openpilotgcs/pfd/default/PfdIndicators.qml index 641bbbb2e..a254f231e 100644 --- a/ground/openpilotgcs/share/openpilotgcs/pfd/default/PfdIndicators.qml +++ b/ground/openpilotgcs/share/openpilotgcs/pfd/default/PfdIndicators.qml @@ -1,4 +1,4 @@ -import Qt 4.7 +import QtQuick 2.0 Item { id: sceneItem diff --git a/ground/openpilotgcs/share/openpilotgcs/pfd/default/PfdTerrainView.qml b/ground/openpilotgcs/share/openpilotgcs/pfd/default/PfdTerrainView.qml index 2beebf05f..21355d16f 100644 --- a/ground/openpilotgcs/share/openpilotgcs/pfd/default/PfdTerrainView.qml +++ b/ground/openpilotgcs/share/openpilotgcs/pfd/default/PfdTerrainView.qml @@ -1,4 +1,4 @@ -import Qt 4.7 +import QtQuick 2.0 import org.OpenPilot 1.0 OsgEarth { diff --git a/ground/openpilotgcs/share/openpilotgcs/pfd/default/PfdWorldView.qml b/ground/openpilotgcs/share/openpilotgcs/pfd/default/PfdWorldView.qml index 4ce07956b..5fa6f764d 100644 --- a/ground/openpilotgcs/share/openpilotgcs/pfd/default/PfdWorldView.qml +++ b/ground/openpilotgcs/share/openpilotgcs/pfd/default/PfdWorldView.qml @@ -1,29 +1,36 @@ -import Qt 4.7 +import QtQuick 2.0 Item { id: worldView + property real horizontCenter : horizontCenterItem.horizontCenter Rectangle { + // using rectange instead of svg rendered to pixmap + // as it's much more memory efficient id: world smooth: true - property variant scaledBounds: svgRenderer.scaledElementBounds("pfd.svg", "world") + property variant scaledBounds: svgRenderer.scaledElementBounds("pfd.svg", "horizon") width: Math.round(sceneItem.width*scaledBounds.width/2)*2 height: Math.round(sceneItem.height*scaledBounds.height/2)*2 + property double pitch1DegScaledHeight: (svgRenderer.scaledElementBounds("pfd.svg", "pitch-90").y - + svgRenderer.scaledElementBounds("pfd.svg", "pitch90").y)/180.0 + + property double pitch1DegHeight: sceneItem.height*pitch1DegScaledHeight + gradient: Gradient { - GradientStop { position: 0.3; color: "#6589E2" } - GradientStop { position: 0.4999; color: "#AFC2F0" } - GradientStop { position: 0.5; color: "#A46933" } - GradientStop { position: 0.8; color: "black" } + GradientStop { position: 0.4999; color: "#0164CC" } + GradientStop { position: 0.5001; color: "#653300" } } transform: [ Translate { id: pitchTranslate x: Math.round((world.parent.width - world.width)/2) - y: Math.round((world.parent.height - world.height)/2 + - AttitudeState.Pitch*world.parent.height/94) + // y is centered around world_center element + y: Math.round(horizontCenter - world.height/2 + + AttitudeState.Pitch*world.pitch1DegHeight) }, Rotation { angle: -AttitudeState.Roll @@ -32,20 +39,11 @@ Item { } ] - SvgElementImage { - id: pitch_scale - elementName: "pitch_scale" - //worldView is loaded with Loader, so background element is visible - sceneSize: background.sceneSize - anchors.centerIn: parent - border: 64 //sometimes numbers are excluded from bounding rect - - smooth: true - } - SvgElementImage { id: horizont_line - elementName: "world-centerline" + //elementName: "world-centerline" + // TODO: rename the centerline element in svg file + elementName: "path4731" //worldView is loaded with Loader, so background element is visible sceneSize: background.sceneSize anchors.centerIn: parent @@ -53,4 +51,34 @@ Item { smooth: true } } + + Item { + id: pitch_window + property variant scaledBounds: svgRenderer.scaledElementBounds("pfd.svg", "pitch-window") + + x: Math.floor(scaledBounds.x * sceneItem.width) + y: Math.floor(scaledBounds.y * sceneItem.height) + width: Math.floor(scaledBounds.width * sceneItem.width) + height: Math.floor(scaledBounds.height * sceneItem.height) + + rotation: -AttitudeState.Roll + transformOrigin: Item.Center + + smooth: true + clip: true + + SvgElementImage { + id: pitch_scale + elementName: "pitch-scale" + //worldView is loaded with Loader, so background element is visible + sceneSize: background.sceneSize + anchors.centerIn: parent + //see comment for world transform + anchors.verticalCenterOffset: AttitudeState.Pitch*world.pitch1DegHeight + border: 64 //sometimes numbers are excluded from bounding rect + + smooth: true + } + } + } diff --git a/ground/openpilotgcs/share/openpilotgcs/pfd/default/RollScale.qml b/ground/openpilotgcs/share/openpilotgcs/pfd/default/RollScale.qml new file mode 100644 index 000000000..66263efd6 --- /dev/null +++ b/ground/openpilotgcs/share/openpilotgcs/pfd/default/RollScale.qml @@ -0,0 +1,28 @@ +import QtQuick 2.0 +import "." + +Item { + id: sceneItem + property variant sceneSize + property real horizontCenter + + onHorizontCenterChanged: console.log("horizont center:"+horizontCenter) + + SvgElementImage { + id: rollscale + elementName: "roll-scale" + sceneSize: sceneItem.sceneSize + + x: Math.floor(scaledBounds.x * sceneItem.width) + y: Math.floor(scaledBounds.y * sceneItem.height) + + smooth: true + + //rotate it around the center of horizon + transform: Rotation { + angle: -AttitudeState.Roll + origin.y : sceneItem.horizontCenter - rollscale.height/2 + origin.x : rollscale.width/2 + } + } +} diff --git a/ground/openpilotgcs/share/openpilotgcs/pfd/default/SpeedScale.qml b/ground/openpilotgcs/share/openpilotgcs/pfd/default/SpeedScale.qml index bbb7d50e2..e0b971afa 100644 --- a/ground/openpilotgcs/share/openpilotgcs/pfd/default/SpeedScale.qml +++ b/ground/openpilotgcs/share/openpilotgcs/pfd/default/SpeedScale.qml @@ -1,4 +1,4 @@ -import Qt 4.7 +import QtQuick 2.0 Item { id: sceneItem @@ -7,8 +7,8 @@ Item { Math.pow(VelocityState.East,2)) SvgElementImage { - id: speed_bg - elementName: "speed-bg" + id: speed_window + elementName: "speed-window" sceneSize: sceneItem.sceneSize clip: true @@ -31,14 +31,14 @@ Item { // speed numbers Column { - width: speed_bg.width + width: speed_window.width anchors.right: speed_scale.right Repeater { model: 7 Item { height: speed_scale.height / 6 - width: speed_bg.width + width: speed_window.width Text { //don't show negative numbers @@ -56,13 +56,25 @@ Item { } } } + + SvgElementImage { + id: speed_waypoint + elementName: "speed-waypoint" + sceneSize: sceneItem.sceneSize + visible: PathDesired.EndingVelocity !== 0.0 + + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + + anchors.verticalCenterOffset: speed_scale.height/30 * (sceneItem.groundSpeed - PathDesired.EndingVelocity) + } } SvgElementImage { - id: speed_window + id: speed_box clip: true - elementName: "speed-window" + elementName: "speed-box" sceneSize: sceneItem.sceneSize x: scaledBounds.x * sceneItem.width @@ -76,30 +88,22 @@ Item { color: "white" font { family: "Arial" - pixelSize: parent.height * 0.6 + pixelSize: parent.height * 0.4 } anchors.centerIn: parent } } - SvgElementImage { - id: speed_unit - elementName: "speed-unit" - sceneSize: sceneItem.sceneSize - clip: true - - x: Math.floor(scaledBounds.x * sceneItem.width) - y: Math.floor(scaledBounds.y * sceneItem.height) - - Text { - id: speed_unit_text - text: qmlWidget.speedUnit - color: "white" - font { - family: "Arial" - pixelSize: parent.height - } - anchors.right: parent.right + Text { + id: speed_unit_text + text: qmlWidget.speedUnit + color: "white" + font { + family: "Arial" + pixelSize: sceneSize.height * 0.025 } + anchors.top: speed_window.bottom + anchors.right: speed_window.right + anchors.margins: font.pixelSize * 0.3 } } diff --git a/ground/openpilotgcs/share/openpilotgcs/pfd/default/SvgElementImage.qml b/ground/openpilotgcs/share/openpilotgcs/pfd/default/SvgElementImage.qml index ea9d54626..6006380f0 100644 --- a/ground/openpilotgcs/share/openpilotgcs/pfd/default/SvgElementImage.qml +++ b/ground/openpilotgcs/share/openpilotgcs/pfd/default/SvgElementImage.qml @@ -1,4 +1,4 @@ -import Qt 4.7 +import QtQuick 2.0 Image { id: sceneItem @@ -17,7 +17,14 @@ Image { sourceSize.width: Math.round(sceneSize.width*scaledBounds.width) sourceSize.height: Math.round(sceneSize.height*scaledBounds.height) - Component.onCompleted: { + x: Math.floor(scaledBounds.x * sceneSize.width) + y: Math.floor(scaledBounds.y * sceneSize.height) + + Component.onCompleted: reloadImage() + onElementNameChanged: reloadImage() + onSceneSizeChanged: reloadImage() + + function reloadImage() { var params = "" if (hSliceCount > 1) params += "hslice="+hSlice+":"+hSliceCount+";" @@ -30,5 +37,6 @@ Image { params = "?" + params source = "image://svg/"+svgFileName+"!"+elementName+params + scaledBounds = svgRenderer.scaledElementBounds(svgFileName, elementName) } } diff --git a/ground/openpilotgcs/share/openpilotgcs/pfd/default/SvgElementPositionItem.qml b/ground/openpilotgcs/share/openpilotgcs/pfd/default/SvgElementPositionItem.qml new file mode 100644 index 000000000..cc43a024b --- /dev/null +++ b/ground/openpilotgcs/share/openpilotgcs/pfd/default/SvgElementPositionItem.qml @@ -0,0 +1,14 @@ +import QtQuick 2.0 + +Item { + id: sceneItem + property variant sceneSize + property string elementName + property string svgFileName: "pfd.svg" + property variant scaledBounds: svgRenderer.scaledElementBounds(svgFileName, elementName) + + x: Math.floor(scaledBounds.x * sceneSize.width) + y: Math.floor(scaledBounds.y * sceneSize.height) + width: Math.floor(scaledBounds.width * sceneSize.width) + height: Math.floor(scaledBounds.height * sceneSize.height) +} diff --git a/ground/openpilotgcs/share/openpilotgcs/pfd/default/VsiScale.qml b/ground/openpilotgcs/share/openpilotgcs/pfd/default/VsiScale.qml index dbcf6aa63..c40591424 100644 --- a/ground/openpilotgcs/share/openpilotgcs/pfd/default/VsiScale.qml +++ b/ground/openpilotgcs/share/openpilotgcs/pfd/default/VsiScale.qml @@ -1,27 +1,30 @@ -import Qt 4.7 +import QtQuick 2.0 Item { id: sceneItem property variant sceneSize SvgElementImage { - id: vsi_bg - elementName: "vsi-bg" + id: vsi_window + elementName: "vsi-window" sceneSize: sceneItem.sceneSize clip: true x: Math.floor(scaledBounds.x * sceneItem.width) y: Math.floor(scaledBounds.y * sceneItem.height) + property double scaleSteps : 8 + property double scaleStepValue : 1000 + property double scaleStepHeight : height/scaleSteps + SvgElementImage { id: vsi_bar elementName: "vsi-bar" sceneSize: sceneItem.sceneSize - //the scale in 1000 ft/min with height == 5200 ft/min - height: (-VelocityState.Down*3.28*60/1000)*(vsi_scale.height/5.2) - + //the scale in 1000 ft/min, convert from VelocityState.Down value in m/s + height: (-VelocityState.Down*3.28*60/vsi_window.scaleStepValue)*vsi_window.scaleStepHeight anchors.bottom: parent.verticalCenter anchors.left: parent.left @@ -42,16 +45,16 @@ Item { anchors.left: parent.right Repeater { - model: [2, 1, 0, 1, 2] + model: [3, 2, 1, 0, 1, 2, 3] Item { - height: vsi_scale.height / 5.2 //the scale height is 5200 - width: vsi_bg.width - vsi_scale.width //fill area right to scale + height: vsi_window.scaleStepHeight + width: vsi_window.width - vsi_scale.width //fill area right to scale Text { text: modelData visible: modelData !== 0 //hide "0" label color: "white" - font.pixelSize: parent.height / 4 + font.pixelSize: parent.height * 0.5 font.family: "Arial" anchors.centerIn: parent @@ -64,14 +67,28 @@ Item { SvgElementImage { - id: vsi_window + id: vsi_centerline clip: true smooth: true - elementName: "vsi-window" + elementName: "vsi-centerline" sceneSize: sceneItem.sceneSize x: Math.floor(scaledBounds.x * sceneItem.width) y: Math.floor(scaledBounds.y * sceneItem.height) } + + Text { + id: vsi_unit_text + text: "ft / m" + + color: "white" + font { + family: "Arial" + pixelSize: sceneSize.height * 0.02 + } + anchors.top: vsi_window.bottom + anchors.left: vsi_window.left + anchors.margins: font.pixelSize * 0.5 + } } diff --git a/ground/openpilotgcs/share/openpilotgcs/pfd/default/Warnings.qml b/ground/openpilotgcs/share/openpilotgcs/pfd/default/Warnings.qml new file mode 100644 index 000000000..0f86755e0 --- /dev/null +++ b/ground/openpilotgcs/share/openpilotgcs/pfd/default/Warnings.qml @@ -0,0 +1,115 @@ +import QtQuick 2.0 + +Item { + id: warnings + property variant sceneSize + // Uninitialised, OK, Warning, Error, Critical + property variant statusColors : ["gray", "green", "red", "red", "red"] + + SvgElementImage { + id: warning_bg + elementName: "warnings-bg" + sceneSize: warnings.sceneSize + } + + SvgElementPositionItem { + id: warning_rc_input + sceneSize: parent.sceneSize + elementName: "warning-rc-input" + + Rectangle { + anchors.fill: parent + color: warnings.statusColors[SystemAlarms.Alarm_ManualControl] + + Text { + anchors.centerIn: parent + text: "RC INPUT" + font { + family: "Arial" + pixelSize: parent.height * 0.8 + weight: Font.DemiBold + } + } + } + } + + SvgElementPositionItem { + id: warning_master_caution + sceneSize: parent.sceneSize + elementName: "warning-master-caution" + + property bool warningActive: (SystemAlarms.Alarm_BootFault > 1 || + SystemAlarms.Alarm_OutOfMemory > 1 || + SystemAlarms.Alarm_StackOverflow > 1 || + SystemAlarms.Alarm_CPUOverload > 1 || + SystemAlarms.Alarm_EventSystem > 1) + Rectangle { + anchors.fill: parent + color: parent.warningActive ? "red" : "red" + opacity: parent.warningActive ? 1.0 : 0.15 + + Text { + anchors.centerIn: parent + text: "MASTER CAUTION" + font { + family: "Arial" + pixelSize: parent.height * 0.8 + weight: Font.DemiBold + } + } + } + } + + SvgElementPositionItem { + id: warning_autopilot + sceneSize: parent.sceneSize + elementName: "warning-autopilot" + + Rectangle { + anchors.fill: parent + color: warnings.statusColors[SystemAlarms.Alarm_Guidance] + + Text { + anchors.centerIn: parent + text: "AUTOPILOT" + font { + family: "Arial" + pixelSize: parent.height * 0.8 + weight: Font.DemiBold + } + } + } + } + + SvgElementImage { + id: warning_gps + elementName: "warning-gps" + sceneSize: warnings.sceneSize + + visible: SystemAlarms.Alarm_GPS > 1 + } + + SvgElementImage { + id: warning_telemetry + elementName: "warning-telemetry" + sceneSize: warnings.sceneSize + + visible: SystemAlarms.Alarm_Telemetry > 1 + } + + SvgElementImage { + id: warning_battery + elementName: "warning-battery" + sceneSize: warnings.sceneSize + + visible: SystemAlarms.Alarm_Battery > 1 + } + + SvgElementImage { + id: warning_attitude + elementName: "warning-attitude" + sceneSize: warnings.sceneSize + + visible: SystemAlarms.Alarm_Attitude > 1 + } +} diff --git a/ground/openpilotgcs/share/openpilotgcs/pfd/default/pfd.svg b/ground/openpilotgcs/share/openpilotgcs/pfd/default/pfd.svg index 2b7ff19bd..2aa980b78 100644 --- a/ground/openpilotgcs/share/openpilotgcs/pfd/default/pfd.svg +++ b/ground/openpilotgcs/share/openpilotgcs/pfd/default/pfd.svg @@ -7,1607 +7,19 @@ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" - xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="1038.8931" - height="707.56323" + width="640" + height="480" id="svg2" version="1.1" - inkscape:version="0.48.4 r9939" - sodipodi:docname="pfd.svg" - style="display:inline" - inkscape:export-filename="C:\Users\Nuno\Desktop\OpenPilot\PFD\PFD-4.png" - inkscape:export-xdpi="71.993568" - inkscape:export-ydpi="71.993568"> + inkscape:version="0.48.2 r9819" + sodipodi:docname="pfd-2.svg" + inkscape:export-filename="/Users/muralha/Desktop/new PFD ideas/pfd/test2.png" + inkscape:export-xdpi="72" + inkscape:export-ydpi="72"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + id="defs4" /> - - - - - - - - + inkscape:guide-bbox="true"> + position="320,275.14994" + id="guide4799" /> - + position="299.42715,305" + id="guide7549" /> + position="215.3671,225.48102" + id="guide8295" /> - - - - - - + position="273.07596,436.08863" + id="guide8297" /> + position="328.00768,112" + id="guide8892" /> @@ -1721,2990 +73,4482 @@ image/svg+xml - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + inkscape:groupmode="layer" + id="layer25" + inkscape:label="home-bg" + style="display:inline"> + id="home-bg" + inkscape:label="#g4876"> - + y="404.5" + x="551.5" + height="59" + width="89" + id="rect4746" + style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.99999982;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" /> + + + + + + + + + + + + + + + + + + + + + + + - + + - - 10 - - - 10 - - - 20 - - - 20 - - - -10 - - - -10 - - - -20 - - - -20 - + style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#00ffff;fill-opacity:1;stroke:none;display:inline;font-family:Sans" + id="home-eta-text"> + d="m 585.61493,452.36133 c -0.60938,10e-6 -1.06836,0.30079 -1.37695,0.90234 -0.30469,0.59766 -0.45704,1.49805 -0.45704,2.70117 0,1.19923 0.15235,2.09962 0.45704,2.70118 0.30859,0.59765 0.76757,0.89648 1.37695,0.89648 0.61328,0 1.07226,-0.29883 1.37695,-0.89648 0.30859,-0.60156 0.46289,-1.50195 0.46289,-2.70118 0,-1.20312 -0.1543,-2.10351 -0.46289,-2.70117 -0.30469,-0.60155 -0.76367,-0.90233 -1.37695,-0.90234 m 0,-0.9375 c 0.98046,10e-6 1.72851,0.38868 2.24414,1.16601 0.51952,0.77345 0.77929,1.89845 0.7793,3.375 -10e-6,1.47266 -0.25978,2.59766 -0.7793,3.375 -0.51563,0.77344 -1.26368,1.16016 -2.24414,1.16016 -0.98047,0 -1.73047,-0.38672 -2.25,-1.16016 -0.51563,-0.77734 -0.77344,-1.90234 -0.77344,-3.375 0,-1.47655 0.25781,-2.60155 0.77344,-3.375 0.51953,-0.77733 1.26953,-1.166 2.25,-1.16601" + style="font-size:12px;fill:#00ffff" + id="path6552" + inkscape:connector-curvature="0" /> + d="m 593.25555,452.36133 c -0.60937,10e-6 -1.06836,0.30079 -1.37695,0.90234 -0.30469,0.59766 -0.45703,1.49805 -0.45703,2.70117 0,1.19923 0.15234,2.09962 0.45703,2.70118 0.30859,0.59765 0.76758,0.89648 1.37695,0.89648 0.61328,0 1.07226,-0.29883 1.37696,-0.89648 0.30859,-0.60156 0.46288,-1.50195 0.46289,-2.70118 -1e-5,-1.20312 -0.1543,-2.10351 -0.46289,-2.70117 -0.3047,-0.60155 -0.76368,-0.90233 -1.37696,-0.90234 m 0,-0.9375 c 0.98047,10e-6 1.72851,0.38868 2.24414,1.16601 0.51953,0.77345 0.77929,1.89845 0.7793,3.375 -10e-6,1.47266 -0.25977,2.59766 -0.7793,3.375 -0.51563,0.77344 -1.26367,1.16016 -2.24414,1.16016 -0.98047,0 -1.73047,-0.38672 -2.25,-1.16016 -0.51562,-0.77734 -0.77343,-1.90234 -0.77343,-3.375 0,-1.47655 0.25781,-2.60155 0.77343,-3.375 0.51953,-0.77733 1.26953,-1.166 2.25,-1.16601" + style="font-size:12px;fill:#00ffff" + id="path6554" + inkscape:connector-curvature="0" /> + d="m 598.48798,458.8418 1.23632,0 0,1.48828 -1.23632,0 0,-1.48828 m 0,-4.7168 1.23632,0 0,1.48828 -1.23632,0 0,-1.48828" + style="font-size:12px;fill:#00ffff" + id="path6556" + inkscape:connector-curvature="0" /> + d="m 604.95087,452.36133 c -0.60938,10e-6 -1.06837,0.30079 -1.37696,0.90234 -0.30469,0.59766 -0.45703,1.49805 -0.45703,2.70117 0,1.19923 0.15234,2.09962 0.45703,2.70118 0.30859,0.59765 0.76758,0.89648 1.37696,0.89648 0.61327,0 1.07226,-0.29883 1.37695,-0.89648 0.30859,-0.60156 0.46288,-1.50195 0.46289,-2.70118 -10e-6,-1.20312 -0.1543,-2.10351 -0.46289,-2.70117 -0.30469,-0.60155 -0.76368,-0.90233 -1.37695,-0.90234 m 0,-0.9375 c 0.98046,10e-6 1.72851,0.38868 2.24414,1.16601 0.51952,0.77345 0.77929,1.89845 0.77929,3.375 0,1.47266 -0.25977,2.59766 -0.77929,3.375 -0.51563,0.77344 -1.26368,1.16016 -2.24414,1.16016 -0.98047,0 -1.73047,-0.38672 -2.25,-1.16016 -0.51563,-0.77734 -0.77344,-1.90234 -0.77344,-3.375 0,-1.47655 0.25781,-2.60155 0.77344,-3.375 0.51953,-0.77733 1.26953,-1.166 2.25,-1.16601" + style="font-size:12px;fill:#00ffff" + id="path6558" + inkscape:connector-curvature="0" /> + d="m 612.59149,452.36133 c -0.60938,10e-6 -1.06836,0.30079 -1.37695,0.90234 -0.30469,0.59766 -0.45703,1.49805 -0.45703,2.70117 0,1.19923 0.15234,2.09962 0.45703,2.70118 0.30859,0.59765 0.76757,0.89648 1.37695,0.89648 0.61328,0 1.07226,-0.29883 1.37695,-0.89648 0.30859,-0.60156 0.46289,-1.50195 0.4629,-2.70118 -10e-6,-1.20312 -0.15431,-2.10351 -0.4629,-2.70117 -0.30469,-0.60155 -0.76367,-0.90233 -1.37695,-0.90234 m 0,-0.9375 c 0.98047,10e-6 1.72851,0.38868 2.24414,1.16601 0.51953,0.77345 0.77929,1.89845 0.7793,3.375 -10e-6,1.47266 -0.25977,2.59766 -0.7793,3.375 -0.51563,0.77344 -1.26367,1.16016 -2.24414,1.16016 -0.98047,0 -1.73047,-0.38672 -2.25,-1.16016 -0.51562,-0.77734 -0.77344,-1.90234 -0.77344,-3.375 0,-1.47655 0.25782,-2.60155 0.77344,-3.375 0.51953,-0.77733 1.26953,-1.166 2.25,-1.16601" + style="font-size:12px;fill:#00ffff" + id="path6560" + inkscape:connector-curvature="0" /> + d="m 617.82391,458.8418 1.23633,0 0,1.48828 -1.23633,0 0,-1.48828 m 0,-4.7168 1.23633,0 0,1.48828 -1.23633,0 0,-1.48828" + style="font-size:12px;fill:#00ffff" + id="path6562" + inkscape:connector-curvature="0" /> + d="m 624.2868,452.36133 c -0.60937,10e-6 -1.06836,0.30079 -1.37695,0.90234 -0.30469,0.59766 -0.45703,1.49805 -0.45703,2.70117 0,1.19923 0.15234,2.09962 0.45703,2.70118 0.30859,0.59765 0.76758,0.89648 1.37695,0.89648 0.61328,0 1.07226,-0.29883 1.37696,-0.89648 0.30859,-0.60156 0.46288,-1.50195 0.46289,-2.70118 -1e-5,-1.20312 -0.1543,-2.10351 -0.46289,-2.70117 -0.3047,-0.60155 -0.76368,-0.90233 -1.37696,-0.90234 m 0,-0.9375 c 0.98047,10e-6 1.72851,0.38868 2.24414,1.16601 0.51953,0.77345 0.77929,1.89845 0.7793,3.375 -10e-6,1.47266 -0.25977,2.59766 -0.7793,3.375 -0.51563,0.77344 -1.26367,1.16016 -2.24414,1.16016 -0.98047,0 -1.73047,-0.38672 -2.25,-1.16016 -0.51562,-0.77734 -0.77343,-1.90234 -0.77343,-3.375 0,-1.47655 0.25781,-2.60155 0.77343,-3.375 0.51953,-0.77733 1.26953,-1.166 2.25,-1.16601" + style="font-size:12px;fill:#00ffff" + id="path6564" + inkscape:connector-curvature="0" /> + d="m 631.92743,452.36133 c -0.60938,10e-6 -1.06836,0.30079 -1.37695,0.90234 -0.30469,0.59766 -0.45704,1.49805 -0.45704,2.70117 0,1.19923 0.15235,2.09962 0.45704,2.70118 0.30859,0.59765 0.76757,0.89648 1.37695,0.89648 0.61328,0 1.07226,-0.29883 1.37695,-0.89648 0.30859,-0.60156 0.46289,-1.50195 0.46289,-2.70118 0,-1.20312 -0.1543,-2.10351 -0.46289,-2.70117 -0.30469,-0.60155 -0.76367,-0.90233 -1.37695,-0.90234 m 0,-0.9375 c 0.98046,10e-6 1.72851,0.38868 2.24414,1.16601 0.51952,0.77345 0.77929,1.89845 0.7793,3.375 -10e-6,1.47266 -0.25978,2.59766 -0.7793,3.375 -0.51563,0.77344 -1.26368,1.16016 -2.24414,1.16016 -0.98047,0 -1.73047,-0.38672 -2.25,-1.16016 -0.51563,-0.77734 -0.77344,-1.90234 -0.77344,-3.375 0,-1.47655 0.25781,-2.60155 0.77344,-3.375 0.51953,-0.77733 1.26953,-1.166 2.25,-1.16601" + style="font-size:12px;fill:#00ffff" + id="path6566" + inkscape:connector-curvature="0" /> + + + + + d="m 585.61493,439.36133 c -0.60938,10e-6 -1.06836,0.30079 -1.37695,0.90234 -0.30469,0.59766 -0.45704,1.49805 -0.45704,2.70117 0,1.19923 0.15235,2.09962 0.45704,2.70118 0.30859,0.59765 0.76757,0.89648 1.37695,0.89648 0.61328,0 1.07226,-0.29883 1.37695,-0.89648 0.30859,-0.60156 0.46289,-1.50195 0.46289,-2.70118 0,-1.20312 -0.1543,-2.10351 -0.46289,-2.70117 -0.30469,-0.60155 -0.76367,-0.90233 -1.37695,-0.90234 m 0,-0.9375 c 0.98046,10e-6 1.72851,0.38868 2.24414,1.16601 0.51952,0.77345 0.77929,1.89845 0.7793,3.375 -10e-6,1.47266 -0.25978,2.59766 -0.7793,3.375 -0.51563,0.77344 -1.26368,1.16016 -2.24414,1.16016 -0.98047,0 -1.73047,-0.38672 -2.25,-1.16016 -0.51563,-0.77734 -0.77344,-1.90234 -0.77344,-3.375 0,-1.47655 0.25781,-2.60155 0.77344,-3.375 0.51953,-0.77733 1.26953,-1.166 2.25,-1.16601" + style="font-size:12px;fill:#00ffff" + id="path6537" + inkscape:connector-curvature="0" /> + d="m 593.25555,439.36133 c -0.60937,10e-6 -1.06836,0.30079 -1.37695,0.90234 -0.30469,0.59766 -0.45703,1.49805 -0.45703,2.70117 0,1.19923 0.15234,2.09962 0.45703,2.70118 0.30859,0.59765 0.76758,0.89648 1.37695,0.89648 0.61328,0 1.07226,-0.29883 1.37696,-0.89648 0.30859,-0.60156 0.46288,-1.50195 0.46289,-2.70118 -1e-5,-1.20312 -0.1543,-2.10351 -0.46289,-2.70117 -0.3047,-0.60155 -0.76368,-0.90233 -1.37696,-0.90234 m 0,-0.9375 c 0.98047,10e-6 1.72851,0.38868 2.24414,1.16601 0.51953,0.77345 0.77929,1.89845 0.7793,3.375 -10e-6,1.47266 -0.25977,2.59766 -0.7793,3.375 -0.51563,0.77344 -1.26367,1.16016 -2.24414,1.16016 -0.98047,0 -1.73047,-0.38672 -2.25,-1.16016 -0.51562,-0.77734 -0.77343,-1.90234 -0.77343,-3.375 0,-1.47655 0.25781,-2.60155 0.77343,-3.375 0.51953,-0.77733 1.26953,-1.166 2.25,-1.16601" + style="font-size:12px;fill:#00ffff" + id="path6539" + inkscape:connector-curvature="0" /> + d="m 600.89618,439.36133 c -0.60938,10e-6 -1.06836,0.30079 -1.37695,0.90234 -0.30469,0.59766 -0.45704,1.49805 -0.45704,2.70117 0,1.19923 0.15235,2.09962 0.45704,2.70118 0.30859,0.59765 0.76757,0.89648 1.37695,0.89648 0.61328,0 1.07226,-0.29883 1.37695,-0.89648 0.30859,-0.60156 0.46289,-1.50195 0.46289,-2.70118 0,-1.20312 -0.1543,-2.10351 -0.46289,-2.70117 -0.30469,-0.60155 -0.76367,-0.90233 -1.37695,-0.90234 m 0,-0.9375 c 0.98046,10e-6 1.72851,0.38868 2.24414,1.16601 0.51952,0.77345 0.77929,1.89845 0.7793,3.375 -10e-6,1.47266 -0.25978,2.59766 -0.7793,3.375 -0.51563,0.77344 -1.26368,1.16016 -2.24414,1.16016 -0.98047,0 -1.73047,-0.38672 -2.25,-1.16016 -0.51563,-0.77734 -0.77344,-1.90234 -0.77344,-3.375 0,-1.47655 0.25781,-2.60155 0.77344,-3.375 0.51953,-0.77733 1.26953,-1.166 2.25,-1.16601" + style="font-size:12px;fill:#00ffff" + id="path6541" + inkscape:connector-curvature="0" /> + d="m 608.5368,439.36133 c -0.60937,10e-6 -1.06836,0.30079 -1.37695,0.90234 -0.30469,0.59766 -0.45703,1.49805 -0.45703,2.70117 0,1.19923 0.15234,2.09962 0.45703,2.70118 0.30859,0.59765 0.76758,0.89648 1.37695,0.89648 0.61328,0 1.07226,-0.29883 1.37696,-0.89648 0.30859,-0.60156 0.46288,-1.50195 0.46289,-2.70118 -1e-5,-1.20312 -0.1543,-2.10351 -0.46289,-2.70117 -0.3047,-0.60155 -0.76368,-0.90233 -1.37696,-0.90234 m 0,-0.9375 c 0.98047,10e-6 1.72851,0.38868 2.24414,1.16601 0.51953,0.77345 0.77929,1.89845 0.7793,3.375 -10e-6,1.47266 -0.25977,2.59766 -0.7793,3.375 -0.51563,0.77344 -1.26367,1.16016 -2.24414,1.16016 -0.98047,0 -1.73047,-0.38672 -2.25,-1.16016 -0.51562,-0.77734 -0.77343,-1.90234 -0.77343,-3.375 0,-1.47655 0.25781,-2.60155 0.77343,-3.375 0.51953,-0.77733 1.26953,-1.166 2.25,-1.16601" + style="font-size:12px;fill:#00ffff" + id="path6543" + inkscape:connector-curvature="0" /> + + + + + + + + + + + transform="translate(0,-4)" + sodipodi:insensitive="true"> - - Link + inkscape:groupmode="layer" + id="layer48" + inkscape:label="info-bg"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - Bat. + inkscape:groupmode="layer" + id="layer64" + inkscape:label="battery" + style="display:inline"> + + + + + + + + + + + + + + + + + + - - GPS - - - - - - + inkscape:groupmode="layer" + id="layer63" + inkscape:label="throttle" + style="display:inline"> - - - + id="eng1" + d="m 469,34.5 0,-11.082914" + style="fill:none;stroke:#008000;stroke-width:6;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline" /> + - + id="eng3" + d="m 485,34.5 0,-11.082914" + style="fill:none;stroke:#008000;stroke-width:6;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline" /> - - - - - - - - - - - - - - - - - - - - - - - - SPD - - ALT - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 2 - 1 - 2 - 1 - - - - ft/s - VSI - - - - - - - - - + id="eng5" + d="m 501,34.5 0,-11.082914" + style="fill:none;stroke:#008000;stroke-width:6;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline" /> - + + + + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + id="compass-fixed" + inkscape:label="#g9078"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + inkscape:transform-center-y="-72.696228" + style="font-size:33.9886322px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;display:inline;font-family:Sans" + id="compass-0"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + id="speed-scale" + inkscape:label="#g8377" + transform="translate(84,10)"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ground/openpilotgcs/src/libs/juavobjects/templates/uavobject.java.template b/ground/openpilotgcs/src/libs/juavobjects/templates/uavobject.java.template index 2944f1270..d720bf898 100644 --- a/ground/openpilotgcs/src/libs/juavobjects/templates/uavobject.java.template +++ b/ground/openpilotgcs/src/libs/juavobjects/templates/uavobject.java.template @@ -81,6 +81,7 @@ $(FIELDSINIT) $(GCSTELEM_ACKED) << UAVOBJ_GCS_TELEMETRY_ACKED_SHIFT | UAVObject.Metadata.UpdateModeNum(UAVObject.UpdateMode.$(FLIGHTTELEM_UPDATEMODE)) << UAVOBJ_TELEMETRY_UPDATE_MODE_SHIFT | UAVObject.Metadata.UpdateModeNum(UAVObject.UpdateMode.$(GCSTELEM_UPDATEMODE)) << UAVOBJ_GCS_TELEMETRY_UPDATE_MODE_SHIFT; + UAVObject.Metadata.UpdateModeNum(UAVObject.UpdateMode.$(LOGGING_UPDATEMODE)) << UAVOBJ_LOGGING_UPDATE_MODE_SHIFT; metadata.flightTelemetryUpdatePeriod = $(FLIGHTTELEM_UPDATEPERIOD); metadata.gcsTelemetryUpdatePeriod = $(GCSTELEM_UPDATEPERIOD); metadata.loggingUpdatePeriod = $(LOGGING_UPDATEPERIOD); diff --git a/ground/openpilotgcs/src/plugins/logging/logfile.cpp b/ground/openpilotgcs/src/libs/utils/logfile.cpp similarity index 51% rename from ground/openpilotgcs/src/plugins/logging/logfile.cpp rename to ground/openpilotgcs/src/libs/utils/logfile.cpp index 2b1647139..4c20b413f 100644 --- a/ground/openpilotgcs/src/plugins/logging/logfile.cpp +++ b/ground/openpilotgcs/src/libs/utils/logfile.cpp @@ -4,12 +4,14 @@ LogFile::LogFile(QObject *parent) : QIODevice(parent), - lastTimeStamp(0), - lastPlayed(0), - timeOffset(0), - playbackSpeed(1.0) + m_lastTimeStamp(0), + m_lastPlayed(0), + m_timeOffset(0), + m_playbackSpeed(1.0), + m_nextTimeStamp(0), + m_useProvidedTimeStamp(false) { - connect(&timer, SIGNAL(timeout()), this, SLOT(timerFired())); + connect(&m_timer, SIGNAL(timeout()), this, SLOT(timerFired())); } /** @@ -20,8 +22,8 @@ LogFile::LogFile(QObject *parent) : bool LogFile::open(OpenMode mode) { // start a timer for playback - myTime.restart(); - if (file.isOpen()) { + m_myTime.restart(); + if (m_file.isOpen()) { // We end up here when doing a replay, because the connection // manager will also try to open the QIODevice, even though we just // opened it after selecting the file, which happens before the @@ -29,8 +31,8 @@ bool LogFile::open(OpenMode mode) return true; } - if (file.open(mode) == false) { - qDebug() << "Unable to open " << file.fileName() << " for logging"; + if (m_file.open(mode) == false) { + qDebug() << "Unable to open " << m_file.fileName() << " for logging"; return false; } @@ -49,25 +51,27 @@ void LogFile::close() { emit aboutToClose(); - if (timer.isActive()) { - timer.stop(); + if (m_timer.isActive()) { + m_timer.stop(); } - file.close(); + m_file.close(); QIODevice::close(); } qint64 LogFile::writeData(const char *data, qint64 dataSize) { - if (!file.isWritable()) { + if (!m_file.isWritable()) { return dataSize; } - quint32 timeStamp = myTime.elapsed(); + // If m_nextTimeStamp != -1 then use this timestamp instead of the timer + // This is used when saving logs from on-board logging + quint32 timeStamp = m_useProvidedTimeStamp ? m_nextTimeStamp : m_myTime.elapsed(); - file.write((char *)&timeStamp, sizeof(timeStamp)); - file.write((char *)&dataSize, sizeof(dataSize)); + m_file.write((char *)&timeStamp, sizeof(timeStamp)); + m_file.write((char *)&dataSize, sizeof(dataSize)); - qint64 written = file.write(data, dataSize); + qint64 written = m_file.write(data, dataSize); if (written != -1) { emit bytesWritten(written); } @@ -77,36 +81,36 @@ qint64 LogFile::writeData(const char *data, qint64 dataSize) qint64 LogFile::readData(char *data, qint64 maxSize) { - QMutexLocker locker(&mutex); - qint64 toRead = qMin(maxSize, (qint64)dataBuffer.size()); + QMutexLocker locker(&m_mutex); + qint64 toRead = qMin(maxSize, (qint64)m_dataBuffer.size()); - memcpy(data, dataBuffer.data(), toRead); - dataBuffer.remove(0, toRead); + memcpy(data, m_dataBuffer.data(), toRead); + m_dataBuffer.remove(0, toRead); return toRead; } qint64 LogFile::bytesAvailable() const { - return dataBuffer.size(); + return m_dataBuffer.size(); } void LogFile::timerFired() { qint64 dataSize; - if (file.bytesAvailable() > 4) { + if (m_file.bytesAvailable() > 4) { int time; - time = myTime.elapsed(); + time = m_myTime.elapsed(); // TODO: going back in time will be a problem - while ((lastPlayed + ((time - timeOffset) * playbackSpeed) > lastTimeStamp)) { - lastPlayed += ((time - timeOffset) * playbackSpeed); - if (file.bytesAvailable() < sizeof(dataSize)) { + while ((m_lastPlayed + ((time - m_timeOffset) * m_playbackSpeed) > m_lastTimeStamp)) { + m_lastPlayed += ((time - m_timeOffset) * m_playbackSpeed); + if (m_file.bytesAvailable() < sizeof(dataSize)) { stopReplay(); return; } - file.read((char *)&dataSize, sizeof(dataSize)); + m_file.read((char *)&dataSize, sizeof(dataSize)); if (dataSize < 1 || dataSize > (1024 * 1024)) { qDebug() << "Error: Logfile corrupted! Unlikely packet size: " << dataSize << "\n"; @@ -114,34 +118,34 @@ void LogFile::timerFired() return; } - if (file.bytesAvailable() < dataSize) { + if (m_file.bytesAvailable() < dataSize) { stopReplay(); return; } - mutex.lock(); - dataBuffer.append(file.read(dataSize)); - mutex.unlock(); + m_mutex.lock(); + m_dataBuffer.append(m_file.read(dataSize)); + m_mutex.unlock(); emit readyRead(); - if (file.bytesAvailable() < sizeof(lastTimeStamp)) { + if (m_file.bytesAvailable() < sizeof(m_lastTimeStamp)) { stopReplay(); return; } - int save = lastTimeStamp; - file.read((char *)&lastTimeStamp, sizeof(lastTimeStamp)); + int save = m_lastTimeStamp; + m_file.read((char *)&m_lastTimeStamp, sizeof(m_lastTimeStamp)); // some validity checks - if (lastTimeStamp < save // logfile goes back in time - || (lastTimeStamp - save) > (60 * 60 * 1000)) { // gap of more than 60 minutes) - qDebug() << "Error: Logfile corrupted! Unlikely timestamp " << lastTimeStamp << " after " << save << "\n"; + 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"; stopReplay(); return; } - timeOffset = time; - time = myTime.elapsed(); + m_timeOffset = time; + time = m_myTime.elapsed(); } } else { stopReplay(); @@ -150,13 +154,13 @@ void LogFile::timerFired() bool LogFile::startReplay() { - dataBuffer.clear(); - myTime.restart(); - timeOffset = 0; - lastPlayed = 0; - file.read((char *)&lastTimeStamp, sizeof(lastTimeStamp)); - timer.setInterval(10); - timer.start(); + m_dataBuffer.clear(); + m_myTime.restart(); + m_timeOffset = 0; + m_lastPlayed = 0; + m_file.read((char *)&m_lastTimeStamp, sizeof(m_lastTimeStamp)); + m_timer.setInterval(10); + m_timer.start(); emit replayStarted(); return true; } @@ -170,11 +174,11 @@ bool LogFile::stopReplay() void LogFile::pauseReplay() { - timer.stop(); + m_timer.stop(); } void LogFile::resumeReplay() { - timeOffset = myTime.elapsed(); - timer.start(); + m_timeOffset = m_myTime.elapsed(); + m_timer.start(); } diff --git a/ground/openpilotgcs/src/plugins/logging/logfile.h b/ground/openpilotgcs/src/libs/utils/logfile.h similarity index 51% rename from ground/openpilotgcs/src/plugins/logging/logfile.h rename to ground/openpilotgcs/src/libs/utils/logfile.h index ae936a7c4..26e0f86ca 100644 --- a/ground/openpilotgcs/src/plugins/logging/logfile.h +++ b/ground/openpilotgcs/src/libs/utils/logfile.h @@ -7,22 +7,22 @@ #include #include #include -#include "uavobjectmanager.h" -#include +#include +#include "utils_global.h" -class LogFile : public QIODevice { +class QTCREATOR_UTILS_EXPORT LogFile : public QIODevice { Q_OBJECT public: explicit LogFile(QObject *parent = 0); qint64 bytesAvailable() const; qint64 bytesToWrite() { - return file.bytesToWrite(); + return m_file.bytesToWrite(); }; bool open(OpenMode mode); void setFileName(QString name) { - file.setFileName(name); + m_file.setFileName(name); }; void close(); qint64 writeData(const char *data, qint64 dataSize); @@ -30,12 +30,21 @@ public: bool startReplay(); bool stopReplay(); + void useProvidedTimeStamp(bool useProvidedTimeStamp) + { + m_useProvidedTimeStamp = useProvidedTimeStamp; + } + + void setNextTimeStamp(quint32 nextTimestamp) + { + m_nextTimeStamp = nextTimestamp; + } public slots: void setReplaySpeed(double val) { - playbackSpeed = val; - qDebug() << "Playback speed is now" << playbackSpeed; + m_playbackSpeed = val; + qDebug() << "Playback speed is now" << m_playbackSpeed; }; void pauseReplay(); void resumeReplay(); @@ -49,17 +58,21 @@ signals: void replayFinished(); protected: - QByteArray dataBuffer; - QTimer timer; - QTime myTime; - QFile file; - qint32 lastTimeStamp; - qint32 lastPlayed; - QMutex mutex; + QByteArray m_dataBuffer; + QTimer m_timer; + QTime m_myTime; + QFile m_file; + qint32 m_lastTimeStamp; + qint32 m_lastPlayed; + QMutex m_mutex; - int timeOffset; - double playbackSpeed; + int m_timeOffset; + double m_playbackSpeed; + +private: + quint32 m_nextTimeStamp; + bool m_useProvidedTimeStamp; }; #endif // LOGFILE_H diff --git a/ground/openpilotgcs/src/libs/utils/mytabbedstackwidget.cpp b/ground/openpilotgcs/src/libs/utils/mytabbedstackwidget.cpp index 1a521c10d..ed094d16f 100644 --- a/ground/openpilotgcs/src/libs/utils/mytabbedstackwidget.cpp +++ b/ground/openpilotgcs/src/libs/utils/mytabbedstackwidget.cpp @@ -78,6 +78,7 @@ void MyTabbedStackWidget::insertTab(const int index, QWidget *tab, const QIcon & tab->setContentsMargins(0, 0, 0, 0); m_stackWidget->insertWidget(index, tab); QListWidgetItem *item = new QListWidgetItem(icon, label); + item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable); item->setTextAlignment(Qt::AlignHCenter | Qt::AlignBottom); item->setToolTip(label); m_listWidget->insertItem(index, item); diff --git a/ground/openpilotgcs/src/libs/utils/svgimageprovider.cpp b/ground/openpilotgcs/src/libs/utils/svgimageprovider.cpp index 2b9a8c79a..14804dbc5 100644 --- a/ground/openpilotgcs/src/libs/utils/svgimageprovider.cpp +++ b/ground/openpilotgcs/src/libs/utils/svgimageprovider.cpp @@ -32,7 +32,7 @@ SvgImageProvider::SvgImageProvider(const QString &basePath) : QObject(), - QDeclarativeImageProvider(QDeclarativeImageProvider::Image), + QQuickImageProvider(QQuickImageProvider::Image), m_basePath(basePath) {} diff --git a/ground/openpilotgcs/src/libs/utils/svgimageprovider.h b/ground/openpilotgcs/src/libs/utils/svgimageprovider.h index e24f51e5a..a58b312b5 100644 --- a/ground/openpilotgcs/src/libs/utils/svgimageprovider.h +++ b/ground/openpilotgcs/src/libs/utils/svgimageprovider.h @@ -29,13 +29,13 @@ #define SVGIMAGEPROVIDER_H_ #include -#include +#include #include #include #include "utils_global.h" -class QTCREATOR_UTILS_EXPORT SvgImageProvider : public QObject, public QDeclarativeImageProvider { +class QTCREATOR_UTILS_EXPORT SvgImageProvider : public QObject, public QQuickImageProvider { Q_OBJECT public: SvgImageProvider(const QString &basePath); diff --git a/ground/openpilotgcs/src/libs/utils/utils.pro b/ground/openpilotgcs/src/libs/utils/utils.pro index aff6db1e0..311212891 100644 --- a/ground/openpilotgcs/src/libs/utils/utils.pro +++ b/ground/openpilotgcs/src/libs/utils/utils.pro @@ -6,7 +6,7 @@ QT += gui \ xml \ svg \ opengl \ - declarative \ + qml quick \ widgets DEFINES += QTCREATOR_UTILS_LIB @@ -54,7 +54,8 @@ SOURCES += reloadpromptutils.cpp \ mytabwidget.cpp \ cachedsvgitem.cpp \ svgimageprovider.cpp \ - hostosinfo.cpp + hostosinfo.cpp \ + logfile.cpp SOURCES += xmlconfig.cpp @@ -111,7 +112,8 @@ HEADERS += utils_global.h \ mytabwidget.h \ cachedsvgitem.h \ svgimageprovider.h \ - hostosinfo.h + hostosinfo.h \ + logfile.h HEADERS += xmlconfig.h diff --git a/ground/openpilotgcs/src/plugins/config/twostep.cpp b/ground/openpilotgcs/src/plugins/config/twostep.cpp index e1562af29..014fb18ae 100644 --- a/ground/openpilotgcs/src/plugins/config/twostep.cpp +++ b/ground/openpilotgcs/src/plugins/config/twostep.cpp @@ -126,7 +126,7 @@ Vector3f twostep_bias_only(const Vector3f samples[], const float noise) { // \tilde{H} - Vector3f centeredSamples[n_samples]; + Vector3f *centeredSamples = new Vector3f[n_samples]; // z_k float sampleDeltaMag[n_samples]; // eq 7 and 8 applied to samples @@ -172,6 +172,7 @@ Vector3f twostep_bias_only(const Vector3f samples[], // Note that the negative has been done twice estimate += neg_increment; } + delete[] centeredSamples; return estimate; } diff --git a/ground/openpilotgcs/src/plugins/coreplugin/authorsdialog.cpp b/ground/openpilotgcs/src/plugins/coreplugin/aboutdialog.cpp similarity index 54% rename from ground/openpilotgcs/src/plugins/coreplugin/authorsdialog.cpp rename to ground/openpilotgcs/src/plugins/coreplugin/aboutdialog.cpp index c4f94d6aa..d72c7c412 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/authorsdialog.cpp +++ b/ground/openpilotgcs/src/plugins/coreplugin/aboutdialog.cpp @@ -1,14 +1,9 @@ /** ****************************************************************************** * - * @file authorsdialog.cpp + * @file aboutdialog.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 @@ -26,58 +21,37 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "authorsdialog.h" +#include "aboutdialog.h" #include "version_info/version_info.h" #include "coreconstants.h" #include "icore.h" -#include - #include #include #include +#include +#include +#include -#include -#include -#include -#include -#include +#include +#include +#include +#include -#include -#include -#include -#include - -using namespace Core; -using namespace Core::Internal; using namespace Core::Constants; -AuthorsDialog::AuthorsDialog(QWidget *parent) - : QDialog(parent) +AboutDialog::AboutDialog(QWidget *parent) : + QDialog(parent) { - // We need to set the window icon explicitly here since for some reason the - // application icon isn't used when the size of the dialog is fixed (at least not on X11/GNOME) - setWindowIcon(QIcon(":/core/images/openpilot_logo_32.png")); setWindowTitle(tr("About OpenPilot")); setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); - // This loads a QML doc containing a Tabbed view - QDeclarativeView *view = new QDeclarativeView(this); - view->setSource(QUrl("qrc:/core/qml/AboutDialog.qml")); - - - QString version = QLatin1String(GCS_VERSION_LONG); - version += QDate(2007, 25, 10).toString(Qt::SystemLocaleDate); - - QString ideRev; - - // : This gets conditionally inserted as argument %8 into the description string. - ideRev = tr("From revision %1
").arg(VersionInfo::revision().left(10)); + setMinimumSize(600, 400); + setMaximumSize(800, 600); const QString description = tr( - "

OpenPilot Ground Control Station

" - "GCS Revision: %1
" + "Revision: %1
" "UAVO Hash: %2
" "
" "Built from %3
" @@ -85,15 +59,6 @@ AuthorsDialog::AuthorsDialog(QWidget *parent) "Based on Qt %6 (%7 bit)
" "
" "© %8, 2010-%9. All rights reserved.
" - "
" - "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.
" - "
" - "The program is provided AS IS with NO WARRANTY OF ANY KIND, " - "INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A " - "PARTICULAR PURPOSE.
" ).arg( VersionInfo::revision().left(60), // %1 VersionInfo::uavoHash().left(8), // %2 @@ -105,6 +70,27 @@ AuthorsDialog::AuthorsDialog(QWidget *parent) QLatin1String(GCS_AUTHOR), // %8 VersionInfo::year() // %9 ); - // Expose the version description to the QML doc + + QQuickView *view = new QQuickView(); + view->rootContext()->setContextProperty("dialog", this); view->rootContext()->setContextProperty("version", description); + view->setResizeMode(QQuickView::SizeRootObjectToView); + view->setSource(QUrl("qrc:/core/qml/AboutDialog.qml")); + + QWidget *container = QWidget::createWindowContainer(view); + container->setMinimumSize(600, 400); + container->setMaximumSize(800, 600); + container->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + QVBoxLayout *lay = new QVBoxLayout(); + lay->setContentsMargins(0, 0, 0, 0); + setLayout(lay); + layout()->addWidget(container); } + +void AboutDialog::openUrl(const QString &url) +{ + QDesktopServices::openUrl(QUrl(url)); +} + +AboutDialog::~AboutDialog() +{} diff --git a/ground/openpilotgcs/src/plugins/coreplugin/authorsdialog.h b/ground/openpilotgcs/src/plugins/coreplugin/aboutdialog.h similarity index 74% rename from ground/openpilotgcs/src/plugins/coreplugin/authorsdialog.h rename to ground/openpilotgcs/src/plugins/coreplugin/aboutdialog.h index 7c88cdf0e..a023354d5 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/authorsdialog.h +++ b/ground/openpilotgcs/src/plugins/coreplugin/aboutdialog.h @@ -1,14 +1,9 @@ /** ****************************************************************************** * - * @file authors.h + * @file aboutdialog.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 @@ -26,19 +21,20 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef AUTHORSDIALOG_H -#define AUTHORSDIALOG_H +#ifndef ABOUTDIALOG_H +#define ABOUTDIALOG_H #include -namespace Core { -namespace Internal { -class AuthorsDialog : public QDialog { +class AboutDialog : public QDialog { Q_OBJECT -public: - explicit AuthorsDialog(QWidget *parent); -}; -} // namespace Internal -} // namespace Core -#endif // AUTHORSDIALOG_H +public: + explicit AboutDialog(QWidget *parent = 0); + ~AboutDialog(); + +public slots: + void openUrl(const QString &url); +}; + +#endif // ABOUTDIALOG_H diff --git a/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.cpp b/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.cpp index b2db517dc..8de9e66e0 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.cpp +++ b/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.cpp @@ -48,9 +48,6 @@ ConnectionManager::ConnectionManager(Internal::MainWindow *mainWindow) : polling(true), m_mainWindow(mainWindow) { - // monitor widget - m_monitorWidget = new TelemetryMonitorWidget(this); - // device list m_availableDevList = new QComboBox; m_availableDevList->setMinimumWidth(120); @@ -64,15 +61,14 @@ ConnectionManager::ConnectionManager(Internal::MainWindow *mainWindow) : // put everything together QHBoxLayout *layout = new QHBoxLayout; layout->setSpacing(5); - layout->setContentsMargins(5, 2, 5, 2); + // cheat a bit with the margin to "nicely" center things vertically + layout->setContentsMargins(5, 0, 5, 4); + setLayout(layout); - layout->addWidget(m_monitorWidget, 0, Qt::AlignVCenter); layout->addWidget(new QLabel(tr("Connections:")), 0, Qt::AlignVCenter); layout->addWidget(m_availableDevList, 0, Qt::AlignVCenter); layout->addWidget(m_connectBtn, 0, Qt::AlignVCenter); - setLayout(layout); - QObject::connect(m_connectBtn, SIGNAL(clicked()), this, SLOT(onConnectClicked())); QObject::connect(m_availableDevList, SIGNAL(currentIndexChanged(int)), this, SLOT(onDeviceSelectionChanged(int))); @@ -87,9 +83,6 @@ ConnectionManager::~ConnectionManager() { disconnectDevice(); suspendPolling(); - if (m_monitorWidget) { - delete m_monitorWidget; - } } void ConnectionManager::init() @@ -100,6 +93,15 @@ void ConnectionManager::init() QObject::connect(ExtensionSystem::PluginManager::instance(), SIGNAL(aboutToRemoveObject(QObject *)), this, SLOT(aboutToRemoveObject(QObject *))); } + +// TODO needs documentation? +void ConnectionManager::addWidget(QWidget *widget) +{ + QHBoxLayout *l = (QHBoxLayout *)layout(); + + l->insertWidget(0, widget, 0, Qt::AlignVCenter); +} + /** * Method called when the user clicks the "Connect" button */ @@ -133,11 +135,9 @@ bool ConnectionManager::connectDevice(DevListItem device) // signal interested plugins that we connected to the device emit deviceConnected(io_dev); - m_connectBtn->setText("Disconnect"); - m_availableDevList->setEnabled(false); - // tell the monitorwidget we're conneced - m_monitorWidget->connect(); + m_connectBtn->setText(tr("Disconnect")); + m_availableDevList->setEnabled(false); return true; } @@ -148,9 +148,6 @@ bool ConnectionManager::connectDevice(DevListItem device) */ bool ConnectionManager::disconnectDevice() { - // tell the monitor widget we're disconnected - m_monitorWidget->disconnect(); - if (!m_ioDev) { // apparently we are already disconnected: this can // happen if a plugin tries to force a disconnect whereas @@ -182,8 +179,10 @@ bool ConnectionManager::disconnectDevice() m_connectionDevice.connection = NULL; m_ioDev = NULL; + // signal interested plugins that we disconnected from the device emit deviceDisconnected(); - m_connectBtn->setText("Connect"); + + m_connectBtn->setText(tr("Connect")); m_availableDevList->setEnabled(true); return true; @@ -278,9 +277,6 @@ void ConnectionManager::telemetryConnected() if (reconnectCheck->isActive()) { reconnectCheck->stop(); } - - // tell the monitor we're connected - m_monitorWidget->connect(); } /** @@ -297,17 +293,6 @@ void ConnectionManager::telemetryDisconnected() } } } - - // tell the monitor we're disconnected - m_monitorWidget->disconnect(); -} - -/** - * Slot called when the telemetry rates are updated - */ -void ConnectionManager::telemetryUpdated(double txRate, double rxRate) -{ - m_monitorWidget->updateTelemetry(txRate, rxRate); } void ConnectionManager::reconnectSlot() diff --git a/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.h b/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.h index be1ec45a1..0d72cb71d 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.h +++ b/ground/openpilotgcs/src/plugins/coreplugin/connectionmanager.h @@ -31,7 +31,6 @@ #include "mainwindow.h" #include "generalsettings.h" -#include "telemetrymonitorwidget.h" #include #include #include @@ -104,6 +103,8 @@ public: return m_ioDev != 0; } + void addWidget(QWidget *widget); + bool connectDevice(DevListItem device); bool disconnectDevice(); void suspendPolling(); @@ -123,7 +124,6 @@ signals: public slots: void telemetryConnected(); void telemetryDisconnected(); - void telemetryUpdated(double txRate, double rxRate); private slots: void objectAdded(QObject *obj); @@ -144,9 +144,6 @@ protected: QLinkedList m_devList; QList m_connectionsList; - // tx/rx telemetry monitor - TelemetryMonitorWidget *m_monitorWidget; - // currently connected connection plugin DevListItem m_connectionDevice; diff --git a/ground/openpilotgcs/src/plugins/coreplugin/core.qrc b/ground/openpilotgcs/src/plugins/coreplugin/core.qrc index 8a4418c53..61d0155d8 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/core.qrc +++ b/ground/openpilotgcs/src/plugins/coreplugin/core.qrc @@ -60,10 +60,7 @@ images/cog.png images/helpicon.svg images/cpu.png - images/tx-rx.svg qml/images/tab.png - qml/ScrollDecorator.qml - qml/TabWidget.qml qml/AboutDialog.qml ../../../../../build/openpilotgcs-synthetics/AuthorsModel.qml diff --git a/ground/openpilotgcs/src/plugins/coreplugin/coreplugin.pro b/ground/openpilotgcs/src/plugins/coreplugin/coreplugin.pro index 1631fda8f..40fb468ea 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/coreplugin.pro +++ b/ground/openpilotgcs/src/plugins/coreplugin/coreplugin.pro @@ -2,7 +2,8 @@ TEMPLATE = lib TARGET = Core DEFINES += CORE_LIBRARY -QT += declarative \ +QT += qml \ + quick \ xml \ network \ script \ @@ -32,7 +33,6 @@ SOURCES += mainwindow.cpp \ uniqueidmanager.cpp \ messagemanager.cpp \ messageoutputwindow.cpp \ - versiondialog.cpp \ iuavgadget.cpp \ uavgadgetmanager/uavgadgetmanager.cpp \ uavgadgetmanager/uavgadgetview.cpp \ @@ -70,8 +70,7 @@ SOURCES += mainwindow.cpp \ uavgadgetdecorator.cpp \ workspacesettings.cpp \ uavconfiginfo.cpp \ - authorsdialog.cpp \ - telemetrymonitorwidget.cpp + aboutdialog.cpp \ HEADERS += mainwindow.h \ tabpositionindicator.h \ @@ -105,7 +104,6 @@ HEADERS += mainwindow.h \ iversioncontrol.h \ iview.h \ icorelistener.h \ - versiondialog.h \ core_global.h \ basemode.h \ baseview.h \ @@ -133,7 +131,7 @@ HEADERS += mainwindow.h \ uavconfiginfo.h \ authorsdialog.h \ iconfigurableplugin.h \ - telemetrymonitorwidget.h + aboutdialog.h FORMS += dialogs/settingsdialog.ui \ dialogs/shortcutsettings.ui \ diff --git a/ground/openpilotgcs/src/plugins/coreplugin/images/tx-rx.svg b/ground/openpilotgcs/src/plugins/coreplugin/images/tx-rx.svg deleted file mode 100644 index e69e36e19..000000000 --- a/ground/openpilotgcs/src/plugins/coreplugin/images/tx-rx.svg +++ /dev/null @@ -1,399 +0,0 @@ - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - Tx - Tx - Rx - - - - - - - - - - - - 0 b/s - - - - - - - - - - 0 b/s - - diff --git a/ground/openpilotgcs/src/plugins/coreplugin/mainwindow.cpp b/ground/openpilotgcs/src/plugins/coreplugin/mainwindow.cpp index 7a09f1403..f84e0c3b3 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/mainwindow.cpp +++ b/ground/openpilotgcs/src/plugins/coreplugin/mainwindow.cpp @@ -45,7 +45,7 @@ #include "uavgadgetinstancemanager.h" #include "workspacesettings.h" -#include "authorsdialog.h" +#include "aboutdialog.h" #include "baseview.h" #include "ioutputpane.h" #include "icorelistener.h" @@ -56,7 +56,6 @@ #include "threadmanager.h" #include "uniqueidmanager.h" #include "variablemanager.h" -#include "versiondialog.h" #include #include @@ -114,8 +113,7 @@ MainWindow::MainWindow() : m_modeManager(0), m_connectionManager(0), m_mimeDatabase(new MimeDatabase), - m_versionDialog(0), - m_authorsDialog(0), + m_aboutDialog(0), m_activeContext(0), m_generalSettings(new GeneralSettings), m_shortcutSettings(new ShortcutSettings), @@ -790,7 +788,7 @@ void MainWindow::registerDefaultActions() #ifdef Q_WS_MAC cmd->action()->setMenuRole(QAction::ApplicationSpecificRole); #endif - connect(tmpaction, SIGNAL(triggered()), this, SLOT(aboutOpenPilotAuthors())); + connect(tmpaction, SIGNAL(triggered()), this, SLOT(showAboutDialog())); } void MainWindow::newFile() @@ -799,42 +797,6 @@ void MainWindow::newFile() void MainWindow::openFile() {} -/*static QList getNonEditorFileFactories() - { - QList tmp; - return tmp; - } - - static IFileFactory *findFileFactory(const QList &fileFactories, - const MimeDatabase *db, - const QFileInfo &fi) - { - if (const MimeType mt = db->findByFile(fi)) { - const QString type = mt.type(); - foreach (IFileFactory *factory, fileFactories) { - if (factory->mimeTypes().contains(type)) - return factory; - } - } - return 0; - } - - // opens either an editor or loads a project - void MainWindow::openFiles(const QStringList &fileNames) - { - QList nonEditorFileFactories = getNonEditorFileFactories(); - - foreach (const QString &fileName, fileNames) { - const QFileInfo fi(fileName); - const QString absoluteFilePath = fi.absoluteFilePath(); - if (IFileFactory *fileFactory = findFileFactory(nonEditorFileFactories, mimeDatabase(), fi)) { - fileFactory->open(absoluteFilePath); - } else { - - } - } - }*/ - void MainWindow::setFocusToEditor() {} @@ -1401,43 +1363,24 @@ void MainWindow::openRecentFile() if (!fileName.isEmpty()) {} } -void MainWindow::aboutOpenPilotGCS() +void MainWindow::showAboutDialog() { - if (!m_versionDialog) { - m_versionDialog = new VersionDialog(this); - connect(m_versionDialog, SIGNAL(finished(int)), - this, SLOT(destroyVersionDialog())); + if (!m_aboutDialog) { + m_aboutDialog = new AboutDialog(this); + connect(m_aboutDialog, SIGNAL(finished(int)), + this, SLOT(destroyAboutDialog())); } - m_versionDialog->show(); + m_aboutDialog->show(); } -void MainWindow::destroyVersionDialog() +void MainWindow::destroyAboutDialog() { - if (m_versionDialog) { - m_versionDialog->deleteLater(); - m_versionDialog = 0; + if (m_aboutDialog) { + m_aboutDialog->deleteLater(); + m_aboutDialog = 0; } } -void MainWindow::aboutOpenPilotAuthors() -{ - if (!m_authorsDialog) { - m_authorsDialog = new AuthorsDialog(this); - connect(m_authorsDialog, SIGNAL(finished(int)), - this, SLOT(destroyAuthorsDialog())); - } - m_authorsDialog->show(); -} - -void MainWindow::destroyAuthorsDialog() -{ - if (m_authorsDialog) { - m_authorsDialog->deleteLater(); - m_authorsDialog = 0; - } -} - - void MainWindow::aboutPlugins() { PluginDialog dialog(this); @@ -1453,12 +1396,8 @@ void MainWindow::setFullScreen(bool on) if (on) { setWindowState(windowState() | Qt::WindowFullScreen); - // statusBar()->hide(); - // menuBar()->hide(); } else { setWindowState(windowState() & ~Qt::WindowFullScreen); - // menuBar()->show(); - // statusBar()->show(); } } diff --git a/ground/openpilotgcs/src/plugins/coreplugin/mainwindow.h b/ground/openpilotgcs/src/plugins/coreplugin/mainwindow.h index a1aa1f508..c19903424 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/mainwindow.h +++ b/ground/openpilotgcs/src/plugins/coreplugin/mainwindow.h @@ -43,6 +43,8 @@ class QToolButton; class MyTabWidget; QT_END_NAMESPACE +class AboutDialog; + namespace Core { class ActionManager; class BaseMode; @@ -72,8 +74,6 @@ class FancyTabWidget; class GeneralSettings; class ShortcutSettings; class WorkspaceSettings; -class VersionDialog; -class AuthorsDialog; class CORE_EXPORT MainWindow : public EventFilteringMainWindow { Q_OBJECT @@ -154,12 +154,10 @@ private slots: void openRecentFile(); void setFocusToEditor(); void saveAll(); - void aboutOpenPilotGCS(); + void showAboutDialog(); + void destroyAboutDialog(); void aboutPlugins(); - void aboutOpenPilotAuthors(); void updateFocusWidget(QWidget *old, QWidget *now); - void destroyVersionDialog(); - void destroyAuthorsDialog(); void modeChanged(Core::IMode *mode); void showUavGadgetMenus(bool show, bool hasSplitter); void applyTabBarSettings(QTabWidget::TabPosition pos, bool movable); @@ -191,8 +189,7 @@ private: MimeDatabase *m_mimeDatabase; MyTabWidget *m_modeStack; Core::BaseView *m_outputView; - VersionDialog *m_versionDialog; - AuthorsDialog *m_authorsDialog; + AboutDialog *m_aboutDialog; IContext *m_activeContext; diff --git a/ground/openpilotgcs/src/plugins/coreplugin/qml/AboutDialog.qml b/ground/openpilotgcs/src/plugins/coreplugin/qml/AboutDialog.qml index 9e1d64f20..bd3d9c9e6 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/qml/AboutDialog.qml +++ b/ground/openpilotgcs/src/plugins/coreplugin/qml/AboutDialog.qml @@ -1,110 +1,140 @@ - /**************************************************************************** - ** - ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). - ** All rights reserved. - ** Contact: Nokia Corporation (qt-info@nokia.com) - ** - ** This file is part of the examples of the Qt Toolkit. - ** - ** $QT_BEGIN_LICENSE:BSD$ - ** You may use this file under the terms of the BSD license as follows: - ** - ** "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 Nokia Corporation and its Subsidiary(-ies) 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." - ** $QT_END_LICENSE$ - ** - ****************************************************************************/ +/** + ****************************************************************************** + * + * @file aboutdialog.qml + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2013. + * + *****************************************************************************/ +/* + * 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 + */ +import QtQuick 2.1 +import QtQuick.Layouts 1.0 +import QtQuick.Controls 1.0 - import QtQuick 1.1 - - // This is a tabbed pane element. Add a nested Rectangle to add a tab. - TabWidget { - // Define AuthorsModel as type - property AuthorsModel authors: AuthorsModel {} - - id: tabs - width: 640; height: 480 - // This tab is for the GCS version information - Rectangle { - property string title: "OpenPilot GCS" - anchors.fill: parent - color: "#e3e3e3" - - Rectangle { - anchors.fill: parent; anchors.margins: 20 - color: "#e3e3e3" - Image { - source: "../images/openpilot_logo_128.png" - x: 0; y: 0; z: 100 - fillMode: Image.PreserveAspectFit - } - Flickable { - anchors.fill: parent - anchors.centerIn: parent - Text { - id: versionLabel - x: 156; y: 0 - width: 430; height: 379 - horizontalAlignment: Qt.AlignLeft - font.pixelSize: 12 - wrapMode: Text.WordWrap - // @var version exposed in authorsdialog.cpp - text: version - } +Rectangle { + id: container + width: 600 + height: 400 + + property AuthorsModel authors: AuthorsModel {} + + ColumnLayout { + id: columnLayout1 + anchors.fill: parent + spacing: 10 + RowLayout { + id: rowLayout1 + opacity: 1 + Image { + id: logo + anchors.left: parent.left + anchors.leftMargin: 10 + anchors.top: parent.top + anchors.topMargin: 10 + source: "../images/openpilot_logo_128.png" + z: 100 + fillMode: Image.PreserveAspectFit + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + onClicked: { + dialog.openUrl("http://www.openpilot.org") + } + } + } + + Rectangle { + anchors.left: logo.right + anchors.margins: 10 + anchors.right: parent.right + anchors.top: parent.top + Layout.fillHeight: true + Layout.fillWidth: true + anchors.bottom: parent.bottom + color: "transparent" + + ColumnLayout { + anchors.fill: parent + Text { + id: headerLabel + text: qsTr("OpenPilot Ground Control Station") + Layout.fillWidth: true + font.pixelSize: 14 + font.bold: true + + } + Text { + id: versionLabel + Layout.fillWidth: true + font.pixelSize: 12 + wrapMode: Text.WordWrap + text: version + } + Text { + id: licenseLabel + Layout.fillWidth: true + font.pixelSize: 9 + wrapMode: Text.WordWrap + text: qsTr("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.\n" + + "The program is provided AS IS with NO WARRANTY OF ANY KIND, " + + "INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.") + } + + Text { + id: contributorLabel + text: qsTr("Contributors") + Layout.fillWidth: true + font.pixelSize: 14 + font.bold: true + + } + ScrollView { + Layout.fillWidth: true + Layout.fillHeight: true + frameVisible: true + ListView { + id: authorsView + anchors.fill: parent + + spacing: 3 + model: authors + delegate: Text { + font.pixelSize: 12 + text: name + } + clip: true + } + } } } } - // This tab is for the authors/contributors/credits - Rectangle { - property string title: "Contributors" - anchors.fill: parent; color: "#e3e3e3" - Rectangle { - anchors.fill: parent; anchors.margins: 20 - color: "#e3e3e3" - Text { - id: description - text: "

These people have been key contributors to the OpenPilot project. Without the work of the people in this list, OpenPilot would not be what it is today.

This list is sorted alphabetically by name

" - width: 600 - wrapMode: Text.WordWrap - - } - ListView { - id: authorsView - y: description.y + description.height + 20 - width: parent.width; height: parent.height - description.height - 20 - spacing: 3 - model: authors - delegate: Text { - text: name - } - clip: true - } - ScrollDecorator { - flickableItem: authorsView - } - } - } + Button { + id: button + text: qsTr("Ok") + activeFocusOnPress: true + anchors.right: parent.right + anchors.rightMargin: 10 + anchors.bottom: parent.bottom + anchors.bottomMargin: 10 + onClicked: dialog.close() + } + } } diff --git a/ground/openpilotgcs/src/plugins/coreplugin/qml/AuthorsModel.qml.template b/ground/openpilotgcs/src/plugins/coreplugin/qml/AuthorsModel.qml.template index 63d7e45cc..8bbabc0ab 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/qml/AuthorsModel.qml.template +++ b/ground/openpilotgcs/src/plugins/coreplugin/qml/AuthorsModel.qml.template @@ -1,7 +1,7 @@ /* This list model was created for the AuthorsDialog. */ -import QtQuick 1.1 +import QtQuick 2.0 ListModel { ${LIST_ELEMENTS} diff --git a/ground/openpilotgcs/src/plugins/coreplugin/qml/ScrollDecorator.qml b/ground/openpilotgcs/src/plugins/coreplugin/qml/ScrollDecorator.qml deleted file mode 100644 index 24c79c927..000000000 --- a/ground/openpilotgcs/src/plugins/coreplugin/qml/ScrollDecorator.qml +++ /dev/null @@ -1,40 +0,0 @@ -import QtQuick 1.1 - -Rectangle { - id: scrollDecorator - - property Flickable flickableItem: null - - Loader { - id: scrollLoader - sourceComponent: scrollDecorator.flickableItem ? scrollBar : undefined - } - - Component.onDestruction: scrollLoader.sourceComponent = undefined - - Component { - id: scrollBar - Rectangle { - property Flickable flickable: scrollDecorator.flickableItem - - parent: flickable - anchors.right: parent.right - - smooth: true - radius: 2 - color: "gray" - border.color: "lightgray" - border.width: 1.0 - opacity: flickable.moving ? 0.8 : 0.4 - - Behavior on opacity { - NumberAnimation { duration: 500 } - } - - width: 4 - height: flickable.height * (flickable.height / flickable.contentHeight) - y: flickable.height * (flickable.contentY / flickable.contentHeight) - visible: flickable.height < flickable.contentHeight - } - } -} diff --git a/ground/openpilotgcs/src/plugins/coreplugin/qml/TabWidget.qml b/ground/openpilotgcs/src/plugins/coreplugin/qml/TabWidget.qml deleted file mode 100644 index b6ce6bd41..000000000 --- a/ground/openpilotgcs/src/plugins/coreplugin/qml/TabWidget.qml +++ /dev/null @@ -1,102 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the examples of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: -** -** "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 Nokia Corporation and its Subsidiary(-ies) 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." -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 1.1 - -Item { - id: tabWidget - - // Setting the default property to stack.children means any child items - // of the TabWidget are actually added to the 'stack' item's children. - // See the "Property Binding" - // documentation for details on default properties. - default property alias content: stack.children - - property int current: 0 - - onCurrentChanged: setOpacities() - Component.onCompleted: setOpacities() - - function setOpacities() { - for (var i = 0; i < stack.children.length; ++i) { - stack.children[i].opacity = (i == current ? 1 : 0) - } - } - - Row { - id: header - - Repeater { - model: stack.children.length - delegate: Rectangle { - width: tabWidget.width / stack.children.length; height: 36 - - Rectangle { - width: parent.width; height: 1 - anchors { bottom: parent.bottom; bottomMargin: 1 } - color: "#acb2c2" - } - BorderImage { - anchors { fill: parent; leftMargin: 2; topMargin: 5; rightMargin: 1 } - border { left: 7; right: 7 } - source: "images/tab.png" - visible: tabWidget.current == index - } - Text { - horizontalAlignment: Qt.AlignHCenter; verticalAlignment: Qt.AlignVCenter - anchors.fill: parent - text: stack.children[index].title - elide: Text.ElideRight - font.bold: tabWidget.current == index - } - MouseArea { - anchors.fill: parent - onClicked: tabWidget.current = index - } - } - } - } - - Item { - id: stack - width: tabWidget.width - anchors.top: header.bottom; anchors.bottom: tabWidget.bottom - } -} \ No newline at end of file diff --git a/ground/openpilotgcs/src/plugins/coreplugin/telemetrymonitorwidget.cpp b/ground/openpilotgcs/src/plugins/coreplugin/telemetrymonitorwidget.cpp deleted file mode 100644 index 1307bbb4e..000000000 --- a/ground/openpilotgcs/src/plugins/coreplugin/telemetrymonitorwidget.cpp +++ /dev/null @@ -1,176 +0,0 @@ -#include "telemetrymonitorwidget.h" - -#include -#include -#include -#include - -TelemetryMonitorWidget::TelemetryMonitorWidget(QWidget *parent) : QGraphicsView(parent) -{ - setMinimumSize(180, 25); // From 100->25 to shorten the qwidget. - setMaximumSize(180, 25); // as above. - setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - setAlignment(Qt::AlignCenter); - setFrameStyle(QFrame::NoFrame); - setStyleSheet("background:transparent;"); - setAttribute(Qt::WA_TranslucentBackground); - setWindowFlags(Qt::FramelessWindowHint); - - QGraphicsScene *scene = new QGraphicsScene(0, 0, 180, 25, this); // keeping the scene in line with the widget for testing. - - QSvgRenderer *renderer = new QSvgRenderer(); - if (renderer->load(QString(":/core/images/tx-rx.svg"))) { - graph = new QGraphicsSvgItem(); - graph->setSharedRenderer(renderer); - graph->setElementId("txrxBackground"); - - QString name; - QGraphicsSvgItem *pt; - - for (int i = 0; i < NODE_NUMELEM; i++) { - name = QString("tx%0").arg(i); - if (renderer->elementExists(name)) { - pt = new QGraphicsSvgItem(); - pt->setSharedRenderer(renderer); - pt->setElementId(name); - pt->setParentItem(graph); - txNodes.append(pt); - } - - name = QString("rx%0").arg(i); - if (renderer->elementExists(name)) { - pt = new QGraphicsSvgItem(); - pt->setSharedRenderer(renderer); - pt->setElementId(name); - pt->setParentItem(graph); - rxNodes.append(pt); - } - } - - scene->addItem(graph); - - txSpeed = new QGraphicsTextItem(); - txSpeed->setDefaultTextColor(Qt::white); - txSpeed->setFont(QFont("Helvetica", 22, 2)); - txSpeed->setParentItem(graph); - scene->addItem(txSpeed); - - rxSpeed = new QGraphicsTextItem(); - rxSpeed->setDefaultTextColor(Qt::white); - rxSpeed->setFont(QFont("Helvetica", 22, 2)); - rxSpeed->setParentItem(graph); - scene->addItem(rxSpeed); - - scene->setSceneRect(graph->boundingRect()); - setScene(scene); - } - - connected = false; - txValue = 0.0; - rxValue = 0.0; - - setMin(0.0); - setMax(1200.0); - - showTelemetry(); -} - -TelemetryMonitorWidget::~TelemetryMonitorWidget() -{ - while (!txNodes.isEmpty()) { - delete txNodes.takeFirst(); - } - - while (!rxNodes.isEmpty()) { - delete rxNodes.takeFirst(); - } -} - -void TelemetryMonitorWidget::connect() -{ - connected = true; - - // flash the lights - updateTelemetry(maxValue, maxValue); -} - -void TelemetryMonitorWidget::disconnect() -{ - // flash the lights - updateTelemetry(maxValue, maxValue); - - connected = false; - updateTelemetry(0.0, 0.0); -} -/*! - \brief Called by the UAVObject which got updated - - Updates the numeric value and/or the icon if the dial wants this. - */ -void TelemetryMonitorWidget::updateTelemetry(double txRate, double rxRate) -{ - txValue = txRate; - rxValue = rxRate; - - showTelemetry(); -} - -// Converts the value into an percentage: -// this enables smooth movement in moveIndex below -void TelemetryMonitorWidget::showTelemetry() -{ - txIndex = (txValue - minValue) / (maxValue - minValue) * NODE_NUMELEM; - rxIndex = (rxValue - minValue) / (maxValue - minValue) * NODE_NUMELEM; - - if (connected) { - this->setToolTip(QString("Tx: %0 bytes/sec\nRx: %1 bytes/sec").arg(txValue).arg(rxValue)); - } else { - this->setToolTip(QString("Disconnected")); - } - - int i; - int nodeMargin = 8; - int leftMargin = 60; - QGraphicsItem *node; - - for (i = 0; i < txNodes.count(); i++) { - node = txNodes.at(i); - node->setPos((i * (node->boundingRect().width() + nodeMargin)) + leftMargin, (node->boundingRect().height() / 2) - 2); - node->setVisible(connected && i < txIndex); - node->update(); - } - - for (i = 0; i < rxNodes.count(); i++) { - node = rxNodes.at(i); - node->setPos((i * (node->boundingRect().width() + nodeMargin)) + leftMargin, (node->boundingRect().height() * 2) - 2); - node->setVisible(connected && i < rxIndex); - node->update(); - } - - QRectF rect = graph->boundingRect(); - txSpeed->setPos(rect.right() - 110, rect.top()); - txSpeed->setPlainText(QString("%0").arg(txValue)); - txSpeed->setVisible(connected); - - rxSpeed->setPos(rect.right() - 110, rect.top() + (rect.height() / 2)); - rxSpeed->setPlainText(QString("%0").arg(rxValue)); - rxSpeed->setVisible(connected); - - update(); -} - -void TelemetryMonitorWidget::showEvent(QShowEvent *event) -{ - Q_UNUSED(event); - - fitInView(graph, Qt::KeepAspectRatio); -} - -void TelemetryMonitorWidget::resizeEvent(QResizeEvent *event) -{ - Q_UNUSED(event); - - fitInView(graph, Qt::KeepAspectRatio); -} diff --git a/ground/openpilotgcs/src/plugins/coreplugin/versiondialog.cpp b/ground/openpilotgcs/src/plugins/coreplugin/versiondialog.cpp deleted file mode 100644 index 6887239fe..000000000 --- a/ground/openpilotgcs/src/plugins/coreplugin/versiondialog.cpp +++ /dev/null @@ -1,109 +0,0 @@ -/** - ****************************************************************************** - * - * @file versiondialog.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 "versiondialog.h" -#include "version_info/version_info.h" -#include "coreconstants.h" -#include "icore.h" - -#include - -#include -#include -#include - -#include -#include -#include -#include -#include - -using namespace Core; -using namespace Core::Internal; -using namespace Core::Constants; - -VersionDialog::VersionDialog(QWidget *parent) - : QDialog(parent) -{ - // We need to set the window icon explicitly here since for some reason the - // application icon isn't used when the size of the dialog is fixed (at least not on X11/GNOME) - setWindowIcon(QIcon(":/core/images/openpilot_logo_32.png")); - - setWindowTitle(tr("About OpenPilot GCS")); - setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); - QGridLayout *layout = new QGridLayout(this); - layout->setSizeConstraint(QLayout::SetFixedSize); - - const QString description = tr( - "

OpenPilot Ground Control Station

" - "GCS Revision: %1
" - "UAVO Hash: %2
" - "
" - "Built from %3
" - "Built on %4 at %5
" - "Based on Qt %6 (%7 bit)
" - "
" - "© %8, 2010-%9. All rights reserved.
" - "
" - "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.
" - "
" - "The program is provided AS IS with NO WARRANTY OF ANY KIND, " - "INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A " - "PARTICULAR PURPOSE.
" - ).arg( - VersionInfo::revision().left(60), // %1 - VersionInfo::uavoHash().left(8), // %2 - VersionInfo::origin(), // $3 - QLatin1String(__DATE__), // %4 - QLatin1String(__TIME__), // %5 - QLatin1String(QT_VERSION_STR), // %6 - QString::number(QSysInfo::WordSize), // %7 - QLatin1String(GCS_AUTHOR), // %8 - VersionInfo::year() // %9 - ); - - QLabel *copyRightLabel = new QLabel(description); - copyRightLabel->setWordWrap(true); - copyRightLabel->setOpenExternalLinks(true); - copyRightLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); - - QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close); - QPushButton *closeButton = buttonBox->button(QDialogButtonBox::Close); - QTC_ASSERT(closeButton, /**/); - buttonBox->addButton(closeButton, QDialogButtonBox::ButtonRole(QDialogButtonBox::RejectRole | QDialogButtonBox::AcceptRole)); - connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); - - QLabel *logoLabel = new QLabel; - logoLabel->setPixmap(QPixmap(QLatin1String(":/core/images/openpilot_logo_128.png"))); - layout->addWidget(logoLabel, 0, 0, 1, 1); - layout->addWidget(copyRightLabel, 0, 1, 4, 4); - layout->addWidget(buttonBox, 4, 0, 1, 5); -} diff --git a/ground/openpilotgcs/src/plugins/flightlog/FlightLog.pluginspec b/ground/openpilotgcs/src/plugins/flightlog/FlightLog.pluginspec new file mode 100644 index 000000000..8baef7f37 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/flightlog/FlightLog.pluginspec @@ -0,0 +1,10 @@ + + The OpenPilot Project + (C) 2013 OpenPilot Project + The GNU Public License (GPL) Version 3 + A plugin to manage flight side logs, viewing and downloading. + http://www.openpilot.org + + + + diff --git a/ground/openpilotgcs/src/plugins/flightlog/FlightLogDialog.qml b/ground/openpilotgcs/src/plugins/flightlog/FlightLogDialog.qml new file mode 100644 index 000000000..9f33efebd --- /dev/null +++ b/ground/openpilotgcs/src/plugins/flightlog/FlightLogDialog.qml @@ -0,0 +1,189 @@ +import QtQuick 2.1 +import QtQuick.Controls 1.0 +import QtQuick.Layouts 1.0 + +import org.openpilot 1.0 + +import "functions.js" as Functions + +Rectangle { + width: 600 + height: 400 + + ColumnLayout { + anchors.fill: parent + anchors.margins: 10 + spacing: 10 + Rectangle { + Layout.fillWidth: true + Layout.fillHeight: true + border.width: 1 + radius: 4 + ColumnLayout { + anchors.margins: 10 + anchors.fill: parent + Text { + Layout.fillWidth: true + text: "" + qsTr("Log entries") + "" + font.pixelSize: 12 + } + TableView { + Layout.fillWidth: true + Layout.fillHeight: true + model: logManager.logEntries + + itemDelegate: Text { + anchors.fill: parent + anchors.margins: 2 + anchors.leftMargin: 5 + font.pixelSize: 12 + text: styleData.value + } + + TableViewColumn { + role: "Flight"; title: qsTr("Flight"); width: 50; + delegate: + Text { + anchors.fill: parent + anchors.margins: 2 + anchors.leftMargin: 5 + font.pixelSize: 12 + text: styleData.value + 1 + } + + } + TableViewColumn { + role: "FlightTime"; title: qsTr("Time"); width: 80; + delegate: + Text { + anchors.fill: parent + anchors.margins: 2 + anchors.leftMargin: 5 + font.pixelSize: 12 + text: Functions.millisToTime(styleData.value) + } + } + TableViewColumn { + role: "Type"; title: "Type"; width: 50; + delegate: + Text { + anchors.fill: parent + anchors.margins: 2 + anchors.leftMargin: 5 + font.pixelSize: 12 + text: { + switch(styleData.value) { + case 0 : text: qsTr("Empty"); break; + case 1 : text: qsTr("Text"); break; + case 2 : text: qsTr("UAVO"); break; + default: text: qsTr("Unknown"); break; + } + } + } + + } + TableViewColumn { role: "LogString"; title: qsTr("Data"); width: 280} + } + + RowLayout { + anchors.margins: 10 + spacing: 10 + ColumnLayout { + spacing: 10 + Text { + id: totalFlights + font.pixelSize: 12 + text: "" + qsTr("Flights recorded: ") + "" + (logStatus.Flight + 1) + } + Text { + id: totalEntries + font.pixelSize: 12 + text: "" + qsTr("Entries logged (free): ") + "" + + logStatus.UsedSlots + " (" + logStatus.FreeSlots + ")" + } + } + Rectangle { + Layout.fillWidth: true + } + ColumnLayout { + spacing: 10 + RowLayout { + Rectangle { + Layout.fillWidth: true + } + Text { + font.pixelSize: 12 + text: "" + qsTr("Flight to download:") + "" + } + + ComboBox { + id: flightCombo + enabled: !logManager.disableControls + model: logManager.flightEntries + } + } + RowLayout { + Layout.fillWidth: true + Layout.fillHeight: true + Rectangle { + Layout.fillWidth: true + } + Button { + text: qsTr("Download logs") + enabled: !logManager.disableControls + activeFocusOnPress: true + onClicked: logManager.retrieveLogs(flightCombo.currentIndex - 1) + } + } + } + } + } + } + + RowLayout { + Layout.fillWidth: true + height: 40 + Button { + id: exportButton + enabled: !logManager.disableControls && !logManager.disableExport + text: qsTr("Export...") + activeFocusOnPress: true + onClicked: logManager.exportLogs() + } + CheckBox { + id: exportRelativeTimeCB + enabled: !logManager.disableControls && !logManager.disableExport + text: qsTr("Adjust timestamps") + activeFocusOnPress: true + checked: logManager.adjustExportedTimestamps + onCheckedChanged: logManager.setAdjustExportedTimestamps(checked) + } + + Button { + id: clearButton + enabled: !logManager.disableControls + text: qsTr("Clear all logs") + activeFocusOnPress: true + onClicked: logManager.clearAllLogs() + } + Rectangle { + Layout.fillWidth: true + } + Button { + id: cancelButton + enabled: logManager.disableControls + text: qsTr("Cancel") + activeFocusOnPress: true + onClicked: logManager.cancelExportLogs() + } + Button { + id: okButton + enabled: !logManager.disableControls + text: qsTr("OK") + isDefault: true + activeFocusOnPress: true + onClicked: dialog.close() + } + } + } +} diff --git a/ground/openpilotgcs/src/plugins/flightlog/flightLog.qrc b/ground/openpilotgcs/src/plugins/flightlog/flightLog.qrc new file mode 100644 index 000000000..4283127f5 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/flightlog/flightLog.qrc @@ -0,0 +1,6 @@ + + + FlightLogDialog.qml + functions.js + + diff --git a/ground/openpilotgcs/src/plugins/flightlog/flightlog.pro b/ground/openpilotgcs/src/plugins/flightlog/flightlog.pro new file mode 100644 index 000000000..dfae3248b --- /dev/null +++ b/ground/openpilotgcs/src/plugins/flightlog/flightlog.pro @@ -0,0 +1,25 @@ +TEMPLATE = lib +TARGET = FlightLog + +QT += qml quick + +include(../../openpilotgcsplugin.pri) +include(../../plugins/coreplugin/coreplugin.pri) +include(../../plugins/uavobjects/uavobjects.pri) +include(../../plugins/uavtalk/uavtalk.pri) + +HEADERS += flightlogplugin.h \ + flightlogmanager.h \ + flightlogdialog.h +SOURCES += flightlogplugin.cpp \ + flightlogmanager.cpp \ + flightlogdialog.cpp + +OTHER_FILES += Flightlog.pluginspec \ + FlightLogDialog.qml \ + functions.js + +FORMS += + +RESOURCES += \ + flightLog.qrc diff --git a/ground/openpilotgcs/src/plugins/flightlog/flightlogdialog.cpp b/ground/openpilotgcs/src/plugins/flightlog/flightlogdialog.cpp new file mode 100644 index 000000000..65f04f575 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/flightlog/flightlogdialog.cpp @@ -0,0 +1,66 @@ +/** + ****************************************************************************** + * + * @file flightlogdialog.cpp + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012. + * @addtogroup [Group] + * @{ + * @addtogroup FlightLogDialog + * @{ + * @brief [Brief] + *****************************************************************************/ +/* + * 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 "flightlogdialog.h" + +#include + +#include +#include +#include +#include + +#include "flightlogmanager.h" + +FlightLogDialog::FlightLogDialog(QWidget *parent, FlightLogManager *flightLogManager) : + QDialog(parent) +{ + qmlRegisterType("org.openpilot", 1, 0, "DebugLogEntry"); + + setWindowIcon(QIcon(":/core/images/openpilot_logo_32.png")); + setWindowTitle(tr("Manage flight side logs")); + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + setMinimumSize(600, 400); + + QQuickView *view = new QQuickView(); + view->rootContext()->setContextProperty("dialog", this); + view->rootContext()->setContextProperty("logStatus", flightLogManager->flightLogStatus()); + view->rootContext()->setContextProperty("logManager", flightLogManager); + view->setResizeMode(QQuickView::SizeRootObjectToView); + view->setSource(QUrl("qrc:/flightlog/FlightLogDialog.qml")); + + QWidget *container = QWidget::createWindowContainer(view); + container->setMinimumSize(600, 400); + container->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + QVBoxLayout *lay = new QVBoxLayout(); + lay->setContentsMargins(0, 0, 0, 0); + setLayout(lay); + layout()->addWidget(container); +} + +FlightLogDialog::~FlightLogDialog() +{} diff --git a/ground/openpilotgcs/src/plugins/flightlog/flightlogdialog.h b/ground/openpilotgcs/src/plugins/flightlog/flightlogdialog.h new file mode 100644 index 000000000..d1b2fd18e --- /dev/null +++ b/ground/openpilotgcs/src/plugins/flightlog/flightlogdialog.h @@ -0,0 +1,15 @@ +#ifndef FLIGHTLOGDIALOG_H +#define FLIGHTLOGDIALOG_H + +#include +#include "flightlogmanager.h" + +class FlightLogDialog : public QDialog { + Q_OBJECT + +public: + explicit FlightLogDialog(QWidget *parent, FlightLogManager *flightLogManager); + ~FlightLogDialog(); +}; + +#endif // FLIGHTLOGDIALOG_H diff --git a/ground/openpilotgcs/src/plugins/flightlog/flightlogmanager.cpp b/ground/openpilotgcs/src/plugins/flightlog/flightlogmanager.cpp new file mode 100644 index 000000000..60578532a --- /dev/null +++ b/ground/openpilotgcs/src/plugins/flightlog/flightlogmanager.cpp @@ -0,0 +1,310 @@ +/** + ****************************************************************************** + * + * @file flightlogmanager.cpp + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012. + * @addtogroup [Group] + * @{ + * @addtogroup FlightLogManager + * @{ + * @brief [Brief] + *****************************************************************************/ +/* + * 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 "flightlogmanager.h" +#include "extensionsystem/pluginmanager.h" + +#include +#include + +#include "debuglogcontrol.h" +#include "uavobjecthelper.h" +#include "uavtalk/uavtalk.h" +#include "utils/logfile.h" + +FlightLogManager::FlightLogManager(QObject *parent) : + QObject(parent), m_disableControls(false), + m_disableExport(true), m_cancelDownload(false), + m_adjustExportedTimestamps(true) +{ + ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); + + m_objectManager = pm->getObject(); + Q_ASSERT(m_objectManager); + + m_flightLogControl = DebugLogControl::GetInstance(m_objectManager); + Q_ASSERT(m_flightLogControl); + + m_flightLogStatus = DebugLogStatus::GetInstance(m_objectManager); + Q_ASSERT(m_flightLogStatus); + connect(m_flightLogStatus, SIGNAL(FlightChanged(quint16)), this, SLOT(updateFlightEntries(quint16))); + + m_flightLogEntry = DebugLogEntry::GetInstance(m_objectManager); + Q_ASSERT(m_flightLogEntry); + + updateFlightEntries(m_flightLogStatus->getFlight()); +} + +FlightLogManager::~FlightLogManager() +{ + while (!m_logEntries.isEmpty()) { + delete m_logEntries.takeFirst(); + } +} + +void addLogEntries(QQmlListProperty *list, ExtendedDebugLogEntry *entry) +{ + Q_UNUSED(list); + Q_UNUSED(entry); +} + +int countLogEntries(QQmlListProperty *list) +{ + return static_cast< QList *>(list->data)->size(); +} + +ExtendedDebugLogEntry *logEntryAt(QQmlListProperty *list, int index) +{ + return static_cast< QList *>(list->data)->at(index); +} + +void clearLogEntries(QQmlListProperty *list) +{ + return static_cast< QList *>(list->data)->clear(); +} + +QQmlListProperty FlightLogManager::logEntries() +{ + return QQmlListProperty(this, &m_logEntries, &addLogEntries, &countLogEntries, &logEntryAt, &clearLogEntries); +} + +QStringList FlightLogManager::flightEntries() +{ + return m_flightEntries; +} + +void FlightLogManager::clearAllLogs() +{ + setDisableControls(true); + QApplication::setOverrideCursor(Qt::WaitCursor); + + // Clear on flight side + UAVObjectUpdaterHelper updateHelper; + + m_flightLogControl->setFlight(0); + m_flightLogControl->setEntry(0); + m_flightLogControl->setOperation(DebugLogControl::OPERATION_FORMATFLASH); + if (updateHelper.doObjectAndWait(m_flightLogControl, UAVTALK_TIMEOUT) == UAVObjectUpdaterHelper::SUCCESS) { + // Then empty locally + clearLogList(); + } + + QApplication::restoreOverrideCursor(); + setDisableControls(false); +} + +void FlightLogManager::clearLogList() +{ + QList tmpList(m_logEntries); + m_logEntries.clear(); + + emit logEntriesChanged(); + setDisableExport(true); + + while (!tmpList.isEmpty()) { + delete tmpList.takeFirst(); + } +} + +void FlightLogManager::retrieveLogs(int flightToRetrieve) +{ + setDisableControls(true); + QApplication::setOverrideCursor(Qt::WaitCursor); + m_cancelDownload = false; + UAVObjectUpdaterHelper updateHelper; + UAVObjectRequestHelper requestHelper; + + clearLogList(); + + // Set up what to retrieve + int startFlight = (flightToRetrieve == -1) ? 0 : flightToRetrieve; + int endFlight = (flightToRetrieve == -1) ? m_flightLogStatus->getFlight() : flightToRetrieve; + + // Prepare to send request for event retrieval + m_flightLogControl->setOperation(DebugLogControl::OPERATION_RETRIEVE); + for (int flight = startFlight; flight <= endFlight; flight++) { + m_flightLogControl->setFlight(flight); + bool gotLast = false; + int entry = 0; + while (!gotLast) { + // Send request for loading flight entry on flight side and wait for ack/nack + m_flightLogControl->setEntry(entry); + + if (updateHelper.doObjectAndWait(m_flightLogControl, UAVTALK_TIMEOUT) == UAVObjectUpdaterHelper::SUCCESS && + requestHelper.doObjectAndWait(m_flightLogEntry, UAVTALK_TIMEOUT) == UAVObjectUpdaterHelper::SUCCESS) { + if (m_flightLogEntry->getType() != DebugLogEntry::TYPE_EMPTY) { + // Ok, we retrieved the entry, and it was the correct one. clone it and add it to the list + ExtendedDebugLogEntry *logEntry = new ExtendedDebugLogEntry(); + logEntry->setData(m_flightLogEntry->getData(), m_objectManager); + m_logEntries << logEntry; + + // Increment to get next entry from flight side + entry++; + } else { + // We are done, not more entries on this flight + gotLast = true; + } + } else { + // We failed for some reason + break; + } + if (m_cancelDownload) { + break; + } + } + if (m_cancelDownload) { + break; + } + } + + if (m_cancelDownload) { + clearLogList(); + m_cancelDownload = false; + } + + emit logEntriesChanged(); + setDisableExport(m_logEntries.count() == 0); + + QApplication::restoreOverrideCursor(); + setDisableControls(false); +} + +void FlightLogManager::exportLogs() +{ + if (m_logEntries.isEmpty()) { + return; + } + + setDisableControls(true); + QApplication::setOverrideCursor(Qt::WaitCursor); + + QString fileName = QFileDialog::getSaveFileName(NULL, tr("Save Log"), + tr("OP-%0.opl").arg(QDateTime::currentDateTime().toString("yyyy-MM-dd_hh-mm-ss")), + tr("OpenPilot Log (*.opl)")); + if (!fileName.isEmpty()) { + // Loop and create a new file for each flight. + fileName = fileName.replace(QString(".opl"), QString("%1.opl")); + int currentEntry = 0; + int currentFlight = 0; + quint32 adjustedBaseTime = 0; + // Continue until all entries are exported + while (currentEntry < m_logEntries.count()) { + if (m_adjustExportedTimestamps) { + adjustedBaseTime = m_logEntries[currentEntry]->getFlightTime(); + } + + // Get current flight + currentFlight = m_logEntries[currentEntry]->getFlight(); + + LogFile logFile; + logFile.useProvidedTimeStamp(true); + + // Set the file name to contain flight number + logFile.setFileName(fileName.arg(tr("_flight-%1").arg(currentFlight + 1))); + logFile.open(QIODevice::WriteOnly); + UAVTalk uavTalk(&logFile, m_objectManager); + + // Export entries until no more available or flight changes + while (currentEntry < m_logEntries.count() && m_logEntries[currentEntry]->getFlight() == currentFlight) { + ExtendedDebugLogEntry *entry = m_logEntries[currentEntry]; + + // Only log uavobjects + if (entry->getType() == ExtendedDebugLogEntry::TYPE_UAVOBJECT) { + // Set timestamp that should be logged for this entry + logFile.setNextTimeStamp(entry->getFlightTime() - adjustedBaseTime); + + // Use UAVTalk to log complete message to file + uavTalk.sendObject(entry->uavObject(), false, false); + qDebug() << entry->getFlightTime() - adjustedBaseTime << "=" << entry->toStringBrief(); + } + currentEntry++; + } + + logFile.close(); + } + } + + QApplication::restoreOverrideCursor(); + setDisableControls(false); +} + +void FlightLogManager::cancelExportLogs() +{ + m_cancelDownload = true; +} + +void FlightLogManager::updateFlightEntries(quint16 currentFlight) +{ + Q_UNUSED(currentFlight); + + int flights = m_flightLogStatus->getFlight(); + if (m_flightEntries.count() == 0 || (m_flightEntries.count() - 1 != flights)) { + m_flightEntries.clear(); + + m_flightEntries << tr("All"); + for (int i = 0; i <= flights; i++) { + m_flightEntries << QString::number(i + 1); + } + + emit flightEntriesChanged(); + } +} + +ExtendedDebugLogEntry::ExtendedDebugLogEntry() : DebugLogEntry(), + m_object(0) +{} + +ExtendedDebugLogEntry::~ExtendedDebugLogEntry() +{ + if (m_object) { + delete m_object; + m_object = 0; + } +} + +QString ExtendedDebugLogEntry::getLogString() +{ + if (getType() == DebugLogEntry::TYPE_TEXT) { + return QString((const char *)getData().Data); + } else if (getType() == DebugLogEntry::TYPE_UAVOBJECT) { + return m_object->toString().replace("\n", " ").replace("\t", " "); + } else { + return ""; + } +} + +void ExtendedDebugLogEntry::setData(const DebugLogEntry::DataFields &data, UAVObjectManager *objectManager) +{ + DebugLogEntry::setData(data); + + if (getType() == DebugLogEntry::TYPE_UAVOBJECT) { + UAVDataObject *object = (UAVDataObject *)objectManager->getObject(getObjectID(), getInstanceID()); + Q_ASSERT(object); + m_object = object->clone(getInstanceID()); + m_object->unpack(getData().Data); + } +} diff --git a/ground/openpilotgcs/src/plugins/flightlog/flightlogmanager.h b/ground/openpilotgcs/src/plugins/flightlog/flightlogmanager.h new file mode 100644 index 000000000..af01dd7e7 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/flightlog/flightlogmanager.h @@ -0,0 +1,162 @@ +/** + ****************************************************************************** + * + * @file flightlogmanager.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012. + * @addtogroup [Group] + * @{ + * @addtogroup FlightLogManager + * @{ + * @brief [Brief] + *****************************************************************************/ +/* + * 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 FLIGHTLOGMANAGER_H +#define FLIGHTLOGMANAGER_H + +#include +#include +#include +#include + +#include "uavobjectmanager.h" +#include "debuglogentry.h" +#include "debuglogstatus.h" +#include "debuglogcontrol.h" + +class ExtendedDebugLogEntry : public DebugLogEntry { + Q_OBJECT Q_PROPERTY(QString LogString READ getLogString WRITE setLogString NOTIFY LogStringUpdated) + +public: + explicit ExtendedDebugLogEntry(); + ~ExtendedDebugLogEntry(); + + QString getLogString(); + UAVDataObject *uavObject() + { + return m_object; + } + + void setData(const DataFields & data, UAVObjectManager *objectManager); + +public slots: + void setLogString(QString arg) + { + Q_UNUSED(arg); + } + +signals: + void LogStringUpdated(QString arg); + +private: + UAVDataObject *m_object; +}; + +class FlightLogManager : public QObject { + Q_OBJECT Q_PROPERTY(DebugLogStatus *flightLogStatus READ flightLogStatus) + Q_PROPERTY(QQmlListProperty logEntries READ logEntries NOTIFY logEntriesChanged) + Q_PROPERTY(QStringList flightEntries READ flightEntries NOTIFY flightEntriesChanged) + Q_PROPERTY(bool disableControls READ disableControls WRITE setDisableControls NOTIFY disableControlsChanged) + Q_PROPERTY(bool disableExport READ disableExport WRITE setDisableExport NOTIFY disableExportChanged) + Q_PROPERTY(bool adjustExportedTimestamps READ adjustExportedTimestamps WRITE setAdjustExportedTimestamps NOTIFY adjustExportedTimestampsChanged) + +public: + explicit FlightLogManager(QObject *parent = 0); + ~FlightLogManager(); + + QQmlListProperty logEntries(); + QStringList flightEntries(); + + DebugLogStatus *flightLogStatus() const + { + return m_flightLogStatus; + } + + bool disableControls() const + { + return m_disableControls; + } + + bool disableExport() const + { + return m_disableExport; + } + + void clearLogList(); + + bool adjustExportedTimestamps() const + { + return m_adjustExportedTimestamps; + } + +signals: + void logEntriesChanged(); + void flightEntriesChanged(); + void disableControlsChanged(bool arg); + void disableExportChanged(bool arg); + + void adjustExportedTimestampsChanged(bool arg); + +public slots: + void clearAllLogs(); + void retrieveLogs(int flightToRetrieve = -1); + void exportLogs(); + void cancelExportLogs(); + + void setDisableControls(bool arg) + { + if (m_disableControls != arg) { + m_disableControls = arg; + emit disableControlsChanged(arg); + } + } + + void setDisableExport(bool arg) + { + if (m_disableExport != arg) { + m_disableExport = arg; + emit disableExportChanged(arg); + } + } + + void setAdjustExportedTimestamps(bool arg) + { + if (m_adjustExportedTimestamps != arg) { + m_adjustExportedTimestamps = arg; + emit adjustExportedTimestampsChanged(arg); + } + } + +private slots: + void updateFlightEntries(quint16 currentFlight); + +private: + UAVObjectManager *m_objectManager; + DebugLogControl *m_flightLogControl; + DebugLogStatus *m_flightLogStatus; + DebugLogEntry *m_flightLogEntry; + QList m_logEntries; + QStringList m_flightEntries; + + static const int UAVTALK_TIMEOUT = 4000; + bool m_disableControls; + bool m_disableExport; + bool m_cancelDownload; + bool m_adjustExportedTimestamps; +}; + +#endif // FLIGHTLOGMANAGER_H diff --git a/ground/openpilotgcs/src/plugins/flightlog/flightlogplugin.cpp b/ground/openpilotgcs/src/plugins/flightlog/flightlogplugin.cpp new file mode 100644 index 000000000..5b8e9def6 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/flightlog/flightlogplugin.cpp @@ -0,0 +1,98 @@ +/** + ****************************************************************************** + * + * @file flightlogplugin.cpp + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @addtogroup GCSPlugins GCS Plugins + * @brief A plugin to view and download flight side logs. + *****************************************************************************/ +/* + * 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 "flightlogplugin.h" +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "flightlogdialog.h" + +FlightLogPlugin::FlightLogPlugin() : m_logDialog(0) +{} + +FlightLogPlugin::~FlightLogPlugin() +{ + shutdown(); +} + +bool FlightLogPlugin::initialize(const QStringList & args, QString *errMsg) +{ + Q_UNUSED(args); + Q_UNUSED(errMsg); + + // Add Menu entry + Core::ActionManager *am = Core::ICore::instance()->actionManager(); + Core::ActionContainer *ac = am->actionContainer(Core::Constants::M_TOOLS); + + Core::Command *cmd = am->registerAction(new QAction(this), + "FlightLogPlugin.ShowFlightLogDialog", + QList() << + Core::Constants::C_GLOBAL_ID); + cmd->setDefaultKeySequence(QKeySequence("Ctrl+F")); + cmd->action()->setText(tr("Manage flight side logs...")); + + Core::ModeManager::instance()->addAction(cmd, 1); + + ac->menu()->addSeparator(); + ac->appendGroup("FlightLogs"); + ac->addAction(cmd, "FlightLogs"); + + connect(cmd->action(), SIGNAL(triggered(bool)), this, SLOT(ShowLogManagementDialog())); + return true; +} + +void FlightLogPlugin::ShowLogManagementDialog() +{ + if (!m_logDialog) { + m_logDialog = new FlightLogDialog(0, new FlightLogManager()); + connect(m_logDialog, SIGNAL(finished(int)), this, SLOT(LogManagementDialogClosed())); + m_logDialog->show(); + } +} + +void FlightLogPlugin::LogManagementDialogClosed() +{ + if (m_logDialog) { + m_logDialog->deleteLater(); + m_logDialog = 0; + } +} + +void FlightLogPlugin::extensionsInitialized() +{} + +void FlightLogPlugin::shutdown() +{ + if (m_logDialog) { + m_logDialog->close(); + LogManagementDialogClosed(); + } +} diff --git a/ground/openpilotgcs/src/plugins/flightlog/flightlogplugin.h b/ground/openpilotgcs/src/plugins/flightlog/flightlogplugin.h new file mode 100644 index 000000000..b78c58836 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/flightlog/flightlogplugin.h @@ -0,0 +1,53 @@ +/** + ****************************************************************************** + * + * @file flightlogplugin.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @addtogroup GCSPlugins GCS Plugins + * @{ + * @brief A plugin to view and download flight side logs. + *****************************************************************************/ +/* + * 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 FLIGHTLOGPLUGIN_H_ +#define FLIGHTLOGPLUGIN_H_ + +#include +#include "flightlogmanager.h" +#include "flightlogdialog.h" + +class FlightLogPlugin : public ExtensionSystem::IPlugin { + Q_OBJECT + Q_PLUGIN_METADATA(IID "OpenPilot.FlightLog") + +public: + FlightLogPlugin(); + ~FlightLogPlugin(); + + void extensionsInitialized(); + bool initialize(const QStringList & arguments, QString *errorString); + void shutdown(); + +private slots: + void ShowLogManagementDialog(); + void LogManagementDialogClosed(); + +private: + FlightLogDialog *m_logDialog; +}; + +#endif /* FLIGHTLOGPLUGIN_H_ */ diff --git a/ground/openpilotgcs/src/plugins/flightlog/functions.js b/ground/openpilotgcs/src/plugins/flightlog/functions.js new file mode 100644 index 000000000..47884432b --- /dev/null +++ b/ground/openpilotgcs/src/plugins/flightlog/functions.js @@ -0,0 +1,20 @@ +.pragma library + +function millisToTime(ms) { + var secs = Math.floor(ms / 1000); + var msleft = ms % 1000; + var hours = Math.floor(secs / (60 * 60)); + var divisor_for_minutes = secs % (60 * 60); + var minutes = Math.floor(divisor_for_minutes / 60); + var divisor_for_seconds = divisor_for_minutes % 60; + var seconds = Math.ceil(divisor_for_seconds); + return pad(hours, 2) + ":" + pad(minutes, 2) + ":" + pad(seconds, 2) + ":" + pad(msleft, 3); +} + +function pad(number, length) { + var str = '' + number; + while (str.length < length) { + str = '0' + str; + } + return str; +} diff --git a/ground/openpilotgcs/src/plugins/logging/logging.pro b/ground/openpilotgcs/src/plugins/logging/logging.pro index 8d10d54a3..5514f4034 100644 --- a/ground/openpilotgcs/src/plugins/logging/logging.pro +++ b/ground/openpilotgcs/src/plugins/logging/logging.pro @@ -1,25 +1,22 @@ TEMPLATE = lib + TARGET = LoggingGadget DEFINES += LOGGING_LIBRARY QT += svg + include(../../openpilotgcsplugin.pri) include(logging_dependencies.pri) HEADERS += loggingplugin.h \ - logfile.h \ logginggadgetwidget.h \ logginggadget.h \ logginggadgetfactory.h -# logginggadgetconfiguration.h -# logginggadgetoptionspage.h SOURCES += loggingplugin.cpp \ - logfile.cpp \ logginggadgetwidget.cpp \ logginggadget.cpp \ logginggadgetfactory.cpp -# logginggadgetconfiguration.cpp \ -# logginggadgetoptionspage.cpp + OTHER_FILES += LoggingGadget.pluginspec + FORMS += logging.ui -# logginggadgetwidget.ui \ -# loggingdialog.ui + diff --git a/ground/openpilotgcs/src/plugins/logging/loggingplugin.cpp b/ground/openpilotgcs/src/plugins/logging/loggingplugin.cpp index fc88cbe98..74239e5c6 100644 --- a/ground/openpilotgcs/src/plugins/logging/loggingplugin.cpp +++ b/ground/openpilotgcs/src/plugins/logging/loggingplugin.cpp @@ -323,7 +323,7 @@ bool LoggingPlugin::initialize(const QStringList & args, QString *errMsg) QList() << Core::Constants::C_GLOBAL_ID); cmd->setDefaultKeySequence(QKeySequence("Ctrl+L")); - cmd->action()->setText("Start logging..."); + cmd->action()->setText(tr("Start logging...")); ac->menu()->addSeparator(); ac->appendGroup("Logging"); diff --git a/ground/openpilotgcs/src/plugins/logging/loggingplugin.h b/ground/openpilotgcs/src/plugins/logging/loggingplugin.h index ed697714e..7c2ed7406 100644 --- a/ground/openpilotgcs/src/plugins/logging/loggingplugin.h +++ b/ground/openpilotgcs/src/plugins/logging/loggingplugin.h @@ -35,7 +35,7 @@ #include "uavobjectmanager.h" #include "gcstelemetrystats.h" #include -#include +#include #include #include diff --git a/ground/openpilotgcs/src/plugins/ophid/src/ophid.cpp b/ground/openpilotgcs/src/plugins/ophid/src/ophid.cpp index afcc28446..447fa2f98 100644 --- a/ground/openpilotgcs/src/plugins/ophid/src/ophid.cpp +++ b/ground/openpilotgcs/src/plugins/ophid/src/ophid.cpp @@ -205,6 +205,8 @@ qint64 RawHIDReadThread::getBytesAvailable() return m_readBuffer.size(); } +// ********************************************************************************* + RawHIDWriteThread::RawHIDWriteThread(RawHID *hid) : m_hid(hid), hiddev(&hid->dev), @@ -212,8 +214,6 @@ RawHIDWriteThread::RawHIDWriteThread(RawHID *hid) m_running(true) {} -// ********************************************************************************* - RawHIDWriteThread::~RawHIDWriteThread() { m_running = false; @@ -227,29 +227,31 @@ void RawHIDWriteThread::run() { while (m_running) { char buffer[WRITE_SIZE] = { 0 }; + int size; - m_writeBufMtx.lock(); - int size = qMin(WRITE_SIZE - 2, m_writeBuffer.size()); - while (size <= 0) { - // wait on new data to write condition, the timeout - // enable the thread to shutdown properly - m_newDataToWrite.wait(&m_writeBufMtx, 200); - if (!m_running) { - return; + { + QMutexLocker lock(&m_writeBufMtx); + size = qMin(WRITE_SIZE - 2, m_writeBuffer.size()); + while (size <= 0) { + // wait on new data to write condition, the timeout + // enable the thread to shutdown properly + m_newDataToWrite.wait(&m_writeBufMtx, 200); + if (!m_running) { + return; + } + + size = m_writeBuffer.size(); } - size = m_writeBuffer.size(); + // NOTE: data size is limited to 2 bytes less than the + // usb packet size (64 bytes for interrupt) to make room + // for the reportID and valid data length + size = qMin(WRITE_SIZE - 2, m_writeBuffer.size()); + memcpy(&buffer[2], m_writeBuffer.constData(), size); + buffer[1] = size; // valid data length + buffer[0] = 2; // reportID } - // NOTE: data size is limited to 2 bytes less than the - // usb packet size (64 bytes for interrupt) to make room - // for the reportID and valid data length - size = qMin(WRITE_SIZE - 2, m_writeBuffer.size()); - memcpy(&buffer[2], m_writeBuffer.constData(), size); - buffer[1] = size; // valid data length - buffer[0] = 2; // reportID - m_writeBufMtx.unlock(); - // must hold lock through the send to know how much was sent int ret = hiddev->send(hidno, buffer, WRITE_SIZE, WRITE_TIMEOUT); diff --git a/ground/openpilotgcs/src/plugins/pfdqml/pfdqml.pro b/ground/openpilotgcs/src/plugins/pfdqml/pfdqml.pro index 55f15b4d2..0d7da9e26 100644 --- a/ground/openpilotgcs/src/plugins/pfdqml/pfdqml.pro +++ b/ground/openpilotgcs/src/plugins/pfdqml/pfdqml.pro @@ -2,7 +2,7 @@ TEMPLATE = lib TARGET = PfdQml QT += svg QT += opengl -QT += declarative +QT += qml quick OSG { DEFINES += USE_OSG } diff --git a/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadget.cpp b/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadget.cpp index 365a323b7..e28257ff5 100644 --- a/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadget.cpp +++ b/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadget.cpp @@ -21,7 +21,10 @@ PfdQmlGadget::PfdQmlGadget(QString classId, PfdQmlGadgetWidget *widget, QWidget *parent) : IUAVGadget(classId, parent), m_widget(widget) -{} +{ + m_container = NULL; + m_parent = parent; +} PfdQmlGadget::~PfdQmlGadget() { diff --git a/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadget.h b/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadget.h index b6525007f..f36bbb6fe 100644 --- a/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadget.h +++ b/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadget.h @@ -35,11 +35,18 @@ public: QWidget *widget() { - return m_widget; + if (!m_container) { + m_container = QWidget::createWindowContainer(m_widget, m_parent); + m_container->setMinimumSize(64, 64); + m_container->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); + } + return m_container; } void loadConfiguration(IUAVGadgetConfiguration *config); private: + QWidget *m_container; + QWidget *m_parent; PfdQmlGadgetWidget *m_widget; }; diff --git a/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetfactory.cpp b/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetfactory.cpp index f7d6b1f66..197f1929d 100644 --- a/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetfactory.cpp +++ b/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetfactory.cpp @@ -31,7 +31,7 @@ PfdQmlGadgetFactory::~PfdQmlGadgetFactory() Core::IUAVGadget *PfdQmlGadgetFactory::createGadget(QWidget *parent) { - PfdQmlGadgetWidget *gadgetWidget = new PfdQmlGadgetWidget(parent); + PfdQmlGadgetWidget *gadgetWidget = new PfdQmlGadgetWidget(); return new PfdQmlGadget(QString("PfdQmlGadget"), gadgetWidget, parent); } diff --git a/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetwidget.cpp b/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetwidget.cpp index aa6879b7e..96fa900a4 100644 --- a/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetwidget.cpp +++ b/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetwidget.cpp @@ -27,13 +27,13 @@ #include #include #include +#include -#include -#include -#include +#include +#include -PfdQmlGadgetWidget::PfdQmlGadgetWidget(QWidget *parent) : - QDeclarativeView(parent), +PfdQmlGadgetWidget::PfdQmlGadgetWidget(QWindow *parent) : + QQuickView(parent), m_openGLEnabled(false), m_terrainEnabled(false), m_actualPositionUsed(false), @@ -45,14 +45,13 @@ PfdQmlGadgetWidget::PfdQmlGadgetWidget(QWidget *parent) : m_altitudeUnit("m"), m_altitudeFactor(1.0) { - setMinimumSize(64, 64); - setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); setResizeMode(SizeRootObjectToView); // setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers))); QStringList objectsToExport; - objectsToExport << "VelocityState" << + objectsToExport << + "VelocityState" << "PositionState" << "AttitudeState" << "AccelState" << @@ -61,6 +60,8 @@ PfdQmlGadgetWidget::PfdQmlGadgetWidget(QWidget *parent) : "AltitudeHoldDesired" << "GPSPositionSensor" << "GCSTelemetryStats" << + "SystemAlarms" << + "NedAccel" << "FlightBatteryState"; ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); @@ -94,6 +95,8 @@ void PfdQmlGadgetWidget::setQmlFile(QString fn) SvgImageProvider *svgProvider = new SvgImageProvider(fn); engine()->addImageProvider("svg", svgProvider); + engine()->clearComponentCache(); + // it's necessary to allow qml side to query svg element position engine()->rootContext()->setContextProperty("svgRenderer", svgProvider); engine()->setBaseUrl(QUrl::fromLocalFile(fn)); @@ -101,7 +104,7 @@ void PfdQmlGadgetWidget::setQmlFile(QString fn) qDebug() << Q_FUNC_INFO << fn; setSource(QUrl::fromLocalFile(fn)); - foreach(const QDeclarativeError &error, errors()) { + foreach(const QQmlError &error, errors()) { qDebug() << error.description(); } } @@ -159,19 +162,7 @@ void PfdQmlGadgetWidget::setAltitudeFactor(double factor) void PfdQmlGadgetWidget::setOpenGLEnabled(bool arg) { - if (m_openGLEnabled != arg) { - m_openGLEnabled = arg; - - qDebug() << Q_FUNC_INFO << "Set OPENGL" << m_openGLEnabled; - if (m_openGLEnabled) { - setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers))); - } else { - setViewport(new QWidget); - } - - // update terrainEnabled status with opengl status chaged - setTerrainEnabled(m_terrainEnabled); - } + setTerrainEnabled(m_terrainEnabled); } // Switch between PositionState UAVObject position @@ -184,6 +175,16 @@ void PfdQmlGadgetWidget::setActualPositionUsed(bool arg) } } +void PfdQmlGadgetWidget::mouseReleaseEvent(QMouseEvent *event) +{ + // Reload the schene on the middle mouse button click. + if (event->button() == Qt::MiddleButton) { + setQmlFile(m_qmlFileName); + } + + QQuickView::mouseReleaseEvent(event); +} + void PfdQmlGadgetWidget::setLatitude(double arg) { // not sure qFuzzyCompare is accurate enough for geo coordinates diff --git a/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetwidget.h b/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetwidget.h index 46d540345..222fb8ce4 100644 --- a/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetwidget.h +++ b/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetwidget.h @@ -18,9 +18,9 @@ #define PFDQMLGADGETWIDGET_H_ #include "pfdqmlgadgetconfiguration.h" -#include +#include -class PfdQmlGadgetWidget : public QDeclarativeView { +class PfdQmlGadgetWidget : public QQuickView { Q_OBJECT Q_PROPERTY(QString earthFile READ earthFile WRITE setEarthFile NOTIFY earthFileChanged) Q_PROPERTY(bool terrainEnabled READ terrainEnabled WRITE setTerrainEnabled NOTIFY terrainEnabledChanged) @@ -37,7 +37,7 @@ class PfdQmlGadgetWidget : public QDeclarativeView { Q_PROPERTY(double altitude READ altitude WRITE setAltitude NOTIFY altitudeChanged) public: - PfdQmlGadgetWidget(QWidget *parent = 0); + PfdQmlGadgetWidget(QWindow *parent = 0); ~PfdQmlGadgetWidget(); void setQmlFile(QString fn); @@ -115,6 +115,9 @@ signals: void altitudeUnitChanged(QString arg); void altitudeFactorChanged(double arg); +protected: + void mouseReleaseEvent(QMouseEvent *event); + private: QString m_qmlFileName; QString m_earthFile; diff --git a/ground/openpilotgcs/src/plugins/plugins.pro b/ground/openpilotgcs/src/plugins/plugins.pro index 73bea8c59..c09d5567d 100644 --- a/ground/openpilotgcs/src/plugins/plugins.pro +++ b/ground/openpilotgcs/src/plugins/plugins.pro @@ -49,6 +49,12 @@ plugin_uavtalk.subdir = uavtalk plugin_uavtalk.depends = plugin_uavobjects plugin_uavtalk.depends += plugin_coreplugin +# Telemetry plugin +SUBDIRS += plugin_telemetry +plugin_telemetry.subdir = telemetry +plugin_telemetry.depends += plugin_uavtalk +plugin_telemetry.depends += plugin_coreplugin + # OPMap UAVGadget plugin_opmap.subdir = opmap plugin_opmap.depends = plugin_coreplugin @@ -238,3 +244,10 @@ plugin_setupwizard.depends += plugin_config plugin_setupwizard.depends += plugin_uploader SUBDIRS += plugin_setupwizard +# Flight Logs plugin +plugin_flightlog.subdir = flightlog +plugin_flightlog.depends = plugin_coreplugin +plugin_flightlog.depends += plugin_uavobjects +plugin_flightlog.depends += plugin_uavtalk +SUBDIRS += plugin_flightlog + diff --git a/ground/openpilotgcs/src/plugins/qmlview/qmlview.pro b/ground/openpilotgcs/src/plugins/qmlview/qmlview.pro index c2897f3a0..de95a7218 100644 --- a/ground/openpilotgcs/src/plugins/qmlview/qmlview.pro +++ b/ground/openpilotgcs/src/plugins/qmlview/qmlview.pro @@ -2,7 +2,7 @@ TEMPLATE = lib TARGET = QMLView QT += svg QT += opengl -QT += declarative +QT += qml quick include(../../openpilotgcsplugin.pri) include(../../plugins/coreplugin/coreplugin.pri) diff --git a/ground/openpilotgcs/src/plugins/qmlview/qmlviewgadget.cpp b/ground/openpilotgcs/src/plugins/qmlview/qmlviewgadget.cpp index d5aa1749c..0bc9eca42 100644 --- a/ground/openpilotgcs/src/plugins/qmlview/qmlviewgadget.cpp +++ b/ground/openpilotgcs/src/plugins/qmlview/qmlviewgadget.cpp @@ -33,7 +33,10 @@ QmlViewGadget::QmlViewGadget(QString classId, QmlViewGadgetWidget *widget, QWidget *parent) : IUAVGadget(classId, parent), m_widget(widget) -{} +{ + m_container = NULL; + m_parent = parent; +} QmlViewGadget::~QmlViewGadget() { diff --git a/ground/openpilotgcs/src/plugins/qmlview/qmlviewgadget.h b/ground/openpilotgcs/src/plugins/qmlview/qmlviewgadget.h index 152c58042..076cd8d99 100644 --- a/ground/openpilotgcs/src/plugins/qmlview/qmlviewgadget.h +++ b/ground/openpilotgcs/src/plugins/qmlview/qmlviewgadget.h @@ -46,11 +46,18 @@ public: QWidget *widget() { - return m_widget; + if (!m_container) { + m_container = QWidget::createWindowContainer(m_widget, m_parent); + m_container->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); + m_container->setMinimumSize(64, 64); + } + return m_container; } void loadConfiguration(IUAVGadgetConfiguration *config); private: + QWidget *m_container; + QWidget *m_parent; QmlViewGadgetWidget *m_widget; }; diff --git a/ground/openpilotgcs/src/plugins/qmlview/qmlviewgadgetfactory.cpp b/ground/openpilotgcs/src/plugins/qmlview/qmlviewgadgetfactory.cpp index 20b7693bb..619f15179 100644 --- a/ground/openpilotgcs/src/plugins/qmlview/qmlviewgadgetfactory.cpp +++ b/ground/openpilotgcs/src/plugins/qmlview/qmlviewgadgetfactory.cpp @@ -42,7 +42,7 @@ QmlViewGadgetFactory::~QmlViewGadgetFactory() Core::IUAVGadget *QmlViewGadgetFactory::createGadget(QWidget *parent) { - QmlViewGadgetWidget *gadgetWidget = new QmlViewGadgetWidget(parent); + QmlViewGadgetWidget *gadgetWidget = new QmlViewGadgetWidget(); return new QmlViewGadget(QString("QmlViewGadget"), gadgetWidget, parent); } diff --git a/ground/openpilotgcs/src/plugins/qmlview/qmlviewgadgetwidget.cpp b/ground/openpilotgcs/src/plugins/qmlview/qmlviewgadgetwidget.cpp index 9abbb4b23..808cf3e80 100644 --- a/ground/openpilotgcs/src/plugins/qmlview/qmlviewgadgetwidget.cpp +++ b/ground/openpilotgcs/src/plugins/qmlview/qmlviewgadgetwidget.cpp @@ -38,14 +38,12 @@ #include #include -#include -#include +#include +#include -QmlViewGadgetWidget::QmlViewGadgetWidget(QWidget *parent) : - QDeclarativeView(parent) +QmlViewGadgetWidget::QmlViewGadgetWidget(QWindow *parent) : + QQuickView(parent) { - setMinimumSize(64, 64); - setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); setResizeMode(SizeRootObjectToView); QStringList objectsToExport; @@ -90,7 +88,7 @@ void QmlViewGadgetWidget::setQmlFile(QString fn) qDebug() << Q_FUNC_INFO << fn; setSource(QUrl::fromLocalFile(fn)); - foreach(const QDeclarativeError &error, errors()) { + foreach(const QQmlError &error, errors()) { qDebug() << error.description(); } } @@ -100,9 +98,5 @@ void QmlViewGadgetWidget::setQmlFile(QString fn) */ void QmlViewGadgetWidget::enableOpenGL(bool flag) { - if (flag) { - setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers))); - } else { - setViewport(new QWidget); - } + Q_UNUSED(flag) } diff --git a/ground/openpilotgcs/src/plugins/qmlview/qmlviewgadgetwidget.h b/ground/openpilotgcs/src/plugins/qmlview/qmlviewgadgetwidget.h index 783cc963e..ef54fcf1b 100644 --- a/ground/openpilotgcs/src/plugins/qmlview/qmlviewgadgetwidget.h +++ b/ground/openpilotgcs/src/plugins/qmlview/qmlviewgadgetwidget.h @@ -30,7 +30,7 @@ #include "qmlviewgadgetconfiguration.h" -#include +#include #include #include @@ -40,11 +40,11 @@ class UAVObject; -class QmlViewGadgetWidget : public QDeclarativeView { +class QmlViewGadgetWidget : public QQuickView { Q_OBJECT public: - QmlViewGadgetWidget(QWidget *parent = 0); + QmlViewGadgetWidget(QWindow *parent = 0); ~QmlViewGadgetWidget(); void setQmlFile(QString fn); diff --git a/ground/openpilotgcs/src/plugins/setupwizard/pages/multipage.ui b/ground/openpilotgcs/src/plugins/setupwizard/pages/multipage.ui index b4da7c0a7..0883ec4d5 100644 --- a/ground/openpilotgcs/src/plugins/setupwizard/pages/multipage.ui +++ b/ground/openpilotgcs/src/plugins/setupwizard/pages/multipage.ui @@ -21,7 +21,7 @@ <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:12pt; font-weight:600;">OpenPilot multirotor configuration</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:12pt; font-weight:600;">OpenPilot Multirotor Configuration</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:12pt; font-weight:600;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">This part of the wizard will set up the OpenPilot controller for use with a flying platform utilizing multiple rotors. The wizard supports the most common types of multirotors. Other variants of multirotors can be configured by using custom configuration options in the Configuration plugin in the GCS.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt;"><br /></p> diff --git a/ground/openpilotgcs/src/plugins/setupwizard/pages/outputcalibrationpage.ui b/ground/openpilotgcs/src/plugins/setupwizard/pages/outputcalibrationpage.ui index 6699ad531..0f0dd1707 100644 --- a/ground/openpilotgcs/src/plugins/setupwizard/pages/outputcalibrationpage.ui +++ b/ground/openpilotgcs/src/plugins/setupwizard/pages/outputcalibrationpage.ui @@ -66,7 +66,7 @@ p, li { white-space: pre-wrap; } - <html><head/><body><p>In this step we will set the neutral rate for the motor highlighted in the illustration to the right. <br/>Plase pay attention to the details and in particular the motors position and its rotation direction.</p><p>To find the neutral rate for this engine, press the Start button below and slide the slider to the right until the engine just starts to spin stably. <br/><br/>When done press button again to stop.</p></body></html> + <html><head/><body><p>In this step we will set the neutral rate for the motor highlighted in the illustration to the right. <br/>Please pay attention to the details and in particular the motors position and its rotation direction. Ensure the motors are spinning in the correct direction as shown in the diagram. Swap any 2 motor wires to change the direction of a motor. </p><p>To find the neutral rate for this engine, press the Start button below and slide the slider to the right until the engine just starts to spin stable. <br/><br/>When done press button again to stop.</p></body></html> Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop diff --git a/ground/openpilotgcs/src/plugins/telemetry/Telemetry.pluginspec b/ground/openpilotgcs/src/plugins/telemetry/Telemetry.pluginspec new file mode 100644 index 000000000..0a003600e --- /dev/null +++ b/ground/openpilotgcs/src/plugins/telemetry/Telemetry.pluginspec @@ -0,0 +1,11 @@ + + The OpenPilot Project + (C) 2010 OpenPilot Project + The GNU Public License (GPL) Version 3 + UAVTalk telemetry protocol + http://www.openpilot.org + + + + + diff --git a/ground/openpilotgcs/src/plugins/telemetry/images/tx-rx.svg b/ground/openpilotgcs/src/plugins/telemetry/images/tx-rx.svg new file mode 100644 index 000000000..babda9af1 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/telemetry/images/tx-rx.svg @@ -0,0 +1,397 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + transform="translate(0,0)" + + + Tx + + + + + + + + Rx + + + + + + + + + + + + inkscape:label="txSpeed" /> + + inkscape:label="rxSpeed" /> + + + + + + + + + + + + + + + + + + + + diff --git a/ground/openpilotgcs/src/plugins/telemetry/monitorgadget.cpp b/ground/openpilotgcs/src/plugins/telemetry/monitorgadget.cpp new file mode 100644 index 000000000..e23591da2 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/telemetry/monitorgadget.cpp @@ -0,0 +1,52 @@ +/** + ****************************************************************************** + * + * @file monitorgadget.cpp + * @author Philippe Renon + * @addtogroup GCSPlugins GCS Plugins + * @{ + * @addtogroup MonitorPlugin Telemetry Plugin + * @{ + * @brief The Telemetry Monitor gadget + *****************************************************************************/ +/* + * 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 "monitorgadget.h" +#include "monitorgadgetconfiguration.h" +#include "monitorwidget.h" + +MonitorGadget::MonitorGadget(QString classId, MonitorWidget *widget, QWidget *parent) : + IUAVGadget(classId, parent), m_widget(widget) +{} + +MonitorGadget::~MonitorGadget() +{ + delete m_widget; +} + +/* + This is called when a configuration is loaded, and updates the plugin's settings. + Careful: the plugin is already drawn before the loadConfiguration method is called the + first time, so you have to be careful not to assume all the plugin values are initialized + the first time you use them + */ +void MonitorGadget::loadConfiguration(IUAVGadgetConfiguration *config) +{ + // MonitorGadgetConfiguration *m = qobject_cast(config); + + // m_widget->setSystemFile(m->getSystemFile()); // Triggers widget repaint +} diff --git a/ground/openpilotgcs/src/plugins/telemetry/monitorgadget.h b/ground/openpilotgcs/src/plugins/telemetry/monitorgadget.h new file mode 100644 index 000000000..e85c15ade --- /dev/null +++ b/ground/openpilotgcs/src/plugins/telemetry/monitorgadget.h @@ -0,0 +1,58 @@ +/** + ****************************************************************************** + * + * @file monitorgadget.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief + * @see The GNU Public License (GPL) Version 3 + * @defgroup telemetry + * @{ + * + *****************************************************************************/ +/* + * 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 MONITORGADGET_H +#define MONITORGADGET_H + +#include +#include "monitorwidget.h" + +// class IUAVGadget; +// class QWidget; +// class QString; +// class NotifyPluginGadgetWidget; + +using namespace Core; + +class MonitorGadget : public IUAVGadget { + Q_OBJECT +public: + MonitorGadget(QString classId, MonitorWidget *widget, QWidget *parent = 0); + ~MonitorGadget(); + + QWidget *widget() + { + return m_widget; + } + + void loadConfiguration(IUAVGadgetConfiguration *config); + +private: + MonitorWidget *m_widget; +}; + +#endif // MONITORGADGET_H diff --git a/ground/openpilotgcs/src/plugins/telemetry/monitorgadgetconfiguration.cpp b/ground/openpilotgcs/src/plugins/telemetry/monitorgadgetconfiguration.cpp new file mode 100644 index 000000000..6a69905af --- /dev/null +++ b/ground/openpilotgcs/src/plugins/telemetry/monitorgadgetconfiguration.cpp @@ -0,0 +1,53 @@ +/** + ****************************************************************************** + * + * @file monitorgadgetconfiguration.cpp + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @addtogroup GCSPlugins GCS Plugins + * @{ + * @addtogroup TelemetryPlugin Telemetry Plugin + * @{ + * @brief A gadget that displays a 3D representation of the UAV + *****************************************************************************/ +/* + * 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 "monitorgadgetconfiguration.h" + +MonitorGadgetConfiguration::MonitorGadgetConfiguration(QString classId, QSettings *qSettings, QObject *parent) : + IUAVGadgetConfiguration(classId, parent) +{ + // if a saved configuration exists load it + if (qSettings != 0) {} +} + +IUAVGadgetConfiguration *MonitorGadgetConfiguration::clone() +{ + MonitorGadgetConfiguration *mv = new MonitorGadgetConfiguration(this->classId()); + + return mv; +} + +/** + * Saves a configuration. + * + */ +void MonitorGadgetConfiguration::saveConfig(QSettings *qSettings) const +{ +// qSettings->setValue("acFilename", Utils::PathUtils().RemoveDataPath(m_acFilename)); +// qSettings->setValue("bgFilename", Utils::PathUtils().RemoveDataPath(m_bgFilename)); +// qSettings->setValue("enableVbo", m_enableVbo); +} diff --git a/ground/openpilotgcs/src/plugins/telemetry/monitorgadgetconfiguration.h b/ground/openpilotgcs/src/plugins/telemetry/monitorgadgetconfiguration.h new file mode 100644 index 000000000..20c570a78 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/telemetry/monitorgadgetconfiguration.h @@ -0,0 +1,44 @@ +/** + ****************************************************************************** + * + * @file monitorgadgetconfiguration.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @addtogroup GCSPlugins GCS Plugins + * @{ + * @addtogroup TelemetryPlugin Telemetry Plugin + * @{ + * @brief A gadget that displays telemetry connection speed monitoring + *****************************************************************************/ +/* + * 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 MONITORGADGETCONFIGURATION_H +#define MONITORGADGETCONFIGURATION_H + +#include + +using namespace Core; + +class MonitorGadgetConfiguration : public IUAVGadgetConfiguration { + Q_OBJECT +public: + explicit MonitorGadgetConfiguration(QString classId, QSettings *qSettings = 0, QObject *parent = 0); + + void saveConfig(QSettings *settings) const; + IUAVGadgetConfiguration *clone(); +}; + +#endif // MONITORGADGETCONFIGURATION_H diff --git a/ground/openpilotgcs/src/plugins/telemetry/monitorgadgetfactory.cpp b/ground/openpilotgcs/src/plugins/telemetry/monitorgadgetfactory.cpp new file mode 100644 index 000000000..94faf597a --- /dev/null +++ b/ground/openpilotgcs/src/plugins/telemetry/monitorgadgetfactory.cpp @@ -0,0 +1,84 @@ +/** + ****************************************************************************** + * + * @file monitorgadgetfactory.cpp + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief + * @see The GNU Public License (GPL) Version 3 + * @defgroup telemetryplugin + * @{ + * + *****************************************************************************/ +/* + * 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 "monitorgadgetfactory.h" +#include "uavtalk/telemetrymanager.h" +#include "extensionsystem/pluginmanager.h" +#include "monitorgadgetconfiguration.h" +#include "monitorgadget.h" +#include "monitorgadgetoptionspage.h" + +#include +#include + +MonitorGadgetFactory::MonitorGadgetFactory(QObject *parent) : + IUAVGadgetFactory(QString("TelemetryMonitorGadget"), tr("Telemetry Monitor"), parent) +{} + +MonitorGadgetFactory::~MonitorGadgetFactory() +{} + +Core::IUAVGadget *MonitorGadgetFactory::createGadget(QWidget *parent) +{ + MonitorWidget *widget = createMonitorWidget(parent); + + return new MonitorGadget(QString("TelemetryMonitorGadget"), widget, parent); +} + +MonitorWidget *MonitorGadgetFactory::createMonitorWidget(QWidget *parent) +{ + MonitorWidget *widget = new MonitorWidget(parent); + + // connect widget to telemetry manager + ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); + TelemetryManager *tm = pm->getObject(); + + connect(tm, SIGNAL(connected()), widget, SLOT(telemetryConnected())); + connect(tm, SIGNAL(disconnected()), widget, SLOT(telemetryDisconnected())); + connect(tm, SIGNAL(telemetryUpdated(double, double)), widget, SLOT(telemetryUpdated(double, double))); + + // and connect widget to connection manager (for retro compatibility) + Core::ConnectionManager *cm = Core::ICore::instance()->connectionManager(); + + connect(cm, SIGNAL(deviceConnected(QIODevice *)), widget, SLOT(telemetryConnected())); + connect(cm, SIGNAL(deviceDisconnected()), widget, SLOT(telemetryDisconnected())); + + if (tm->isConnected()) { + widget->telemetryConnected(); + } + + return widget; +} + +IUAVGadgetConfiguration *MonitorGadgetFactory::createConfiguration(QSettings *qSettings) +{ + return new MonitorGadgetConfiguration(QString("TelemetryMonitorGadget"), qSettings); +} + +IOptionsPage *MonitorGadgetFactory::createOptionsPage(IUAVGadgetConfiguration *config) +{ + return new MonitorGadgetOptionsPage(qobject_cast(config)); +} diff --git a/ground/openpilotgcs/src/plugins/telemetry/monitorgadgetfactory.h b/ground/openpilotgcs/src/plugins/telemetry/monitorgadgetfactory.h new file mode 100644 index 000000000..0b44e8b53 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/telemetry/monitorgadgetfactory.h @@ -0,0 +1,55 @@ +/** + ****************************************************************************** + * + * @file monitorgadgetfactory.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief + * @see The GNU Public License (GPL) Version 3 + * @defgroup monitorgadget + * @{ + * + *****************************************************************************/ +/* + * 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 MONITORGADGETFACTORY_H +#define MONITORGADGETFACTORY_H + +#include "monitorwidget.h" +#include + + +namespace Core { +class IUAVGadget; +class IUAVGadgetFactory; +} + +using namespace Core; + +class MonitorGadgetFactory : public IUAVGadgetFactory { + Q_OBJECT +public: + MonitorGadgetFactory(QObject *parent = 0); + ~MonitorGadgetFactory(); + + Core::IUAVGadget *createGadget(QWidget *parent); + IUAVGadgetConfiguration *createConfiguration(QSettings *qSettings); + IOptionsPage *createOptionsPage(IUAVGadgetConfiguration *config); + + MonitorWidget *createMonitorWidget(QWidget *parent); +}; + +#endif // MONITORGADGETFACTORY_H diff --git a/ground/openpilotgcs/src/plugins/telemetry/monitorgadgetoptionspage.cpp b/ground/openpilotgcs/src/plugins/telemetry/monitorgadgetoptionspage.cpp new file mode 100644 index 000000000..6601efd54 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/telemetry/monitorgadgetoptionspage.cpp @@ -0,0 +1,104 @@ +/** + ****************************************************************************** + * + * @file monitorgadgetoptionspage.cpp + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief Telemetry Gadget options page + * @see The GNU Public License (GPL) Version 3 + * @defgroup monitorgadget + * @{ + * + *****************************************************************************/ +/* + * 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 "monitorgadgetoptionspage.h" +#include +// #include "ui_telemetrypluginoptionspage.h" +#include "extensionsystem/pluginmanager.h" + +MonitorGadgetOptionsPage::MonitorGadgetOptionsPage(MonitorGadgetConfiguration *config, QObject *parent) + : IOptionsPage(parent) +{} + +MonitorGadgetOptionsPage::~MonitorGadgetOptionsPage() +{} + +QWidget *MonitorGadgetOptionsPage::createPage(QWidget * /* parent */) +{ +// _optionsPage.reset(new Ui::TelemetryPluginOptionsPage()); +//// main widget +// QWidget *optionsPageWidget = new QWidget; +// _dynamicFieldWidget = NULL; +// _dynamicFieldCondition = NULL; +// resetFieldType(); +//// save ref to form, needed for binding dynamic fields in future +// _form = optionsPageWidget; +//// main layout +// _optionsPage->setupUi(optionsPageWidget); +// +// _optionsPage->SoundDirectoryPathChooser->setExpectedKind(Utils::PathChooser::Directory); +// _optionsPage->SoundDirectoryPathChooser->setPromptDialogTitle(tr("Choose sound collection directory")); +// +// connect(_optionsPage->SoundDirectoryPathChooser, SIGNAL(changed(const QString &)), +// this, SLOT(on_clicked_buttonSoundFolder(const QString &))); +// connect(_optionsPage->SoundCollectionList, SIGNAL(currentIndexChanged(int)), +// this, SLOT(on_changedIndex_soundLanguage(int))); +// +// connect(this, SIGNAL(updateNotifications(QList)), +// _owner, SLOT(updateNotificationList(QList))); +//// connect(this, SIGNAL(resetNotification()),owner, SLOT(resetNotification())); +// +// _privListNotifications = _owner->getListNotifications(); +// +// +//// [1] +// setSelectedNotification(_owner->getCurrentNotification()); +// addDynamicFieldLayout(); +//// [2] +// updateConfigView(_selectedNotification); +// +// initRulesTable(); +// initButtons(); +// initPhononPlayer(); +// +// int curr_row = _privListNotifications.indexOf(_selectedNotification); +// _telemetryRulesSelection->setCurrentIndex(_telemetryRulesModel->index(curr_row, 0, QModelIndex()), +// QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); +// +// return optionsPageWidget; + return NULL; +} + +void MonitorGadgetOptionsPage::apply() +{ +// getOptionsPageValues(_owner->getCurrentNotification()); +// _owner->setEnableSound(_optionsPage->chkEnableSound->isChecked()); +// emit updateNotifications(_privListNotifications); +} + +void MonitorGadgetOptionsPage::finish() +{ +// disconnect(_optionsPage->UAVObjectField, SIGNAL(currentIndexChanged(QString)), +// this, SLOT(on_changedIndex_UAVField(QString))); +// +// disconnect(_testSound.data(), SIGNAL(stateChanged(Phonon::State, Phonon::State)), +// this, SLOT(on_changed_playButtonText(Phonon::State, Phonon::State))); +// if (_testSound) { +// _testSound->stop(); +// _testSound->clear(); +// } +} diff --git a/ground/openpilotgcs/src/plugins/telemetry/monitorgadgetoptionspage.h b/ground/openpilotgcs/src/plugins/telemetry/monitorgadgetoptionspage.h new file mode 100644 index 000000000..107e83fc8 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/telemetry/monitorgadgetoptionspage.h @@ -0,0 +1,61 @@ +/** + ****************************************************************************** + * + * @file monitorgadgetoptionspage.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief Telemetry Gadget options page header + * @see The GNU Public License (GPL) Version 3 + * @defgroup telemetry + * @{ + * + *****************************************************************************/ +/* + * 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 MONITORGADGETOPTIONSPAGE_H +#define MONITORGADGETOPTIONSPAGE_H + +#include "coreplugin/dialogs/ioptionspage.h" +#include "uavobjectmanager.h" +#include "uavobject.h" + +#include "QString" +#include +#include + +namespace Ui { +class MonitorGadgetOptionsPage; +}; + +class MonitorGadgetConfiguration; + +using namespace Core; + +class MonitorGadgetOptionsPage : public IOptionsPage { + Q_OBJECT + +public: + MonitorGadgetOptionsPage(MonitorGadgetConfiguration *config, QObject *parent = 0); + ~MonitorGadgetOptionsPage(); + + QWidget *createPage(QWidget *parent); + void apply(); + void finish(); + +private: +}; + +#endif // MONITORGADGETOPTIONSPAGE_H diff --git a/ground/openpilotgcs/src/plugins/telemetry/monitorwidget.cpp b/ground/openpilotgcs/src/plugins/telemetry/monitorwidget.cpp new file mode 100644 index 000000000..722869652 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/telemetry/monitorwidget.cpp @@ -0,0 +1,300 @@ +#include "monitorwidget.h" + +#include + +#include +#include +#include + +namespace { +/** + * Create an SVG item and connect it to an element of the SVG file previously loaded into the parent item. + * This then allows to show, hide, move, scale and rotate the element. + * Opacity can also be changed. + * Other characteristics (color, ...) of the element cannot be modified. + */ +// TODO move to some utility class that can be reused by other SVG manipulating code +QGraphicsSvgItem *createSvgItem(QGraphicsSvgItem *parent, QString elementId) +{ + QGraphicsSvgItem *item = new QGraphicsSvgItem(parent); + + QSvgRenderer *renderer = parent->renderer(); + + // connect item to its corresponding element + item->setSharedRenderer(renderer); + item->setElementId(elementId); + + // move item to its location + QMatrix elementMatrix = renderer->matrixForElement(elementId); + QRectF elementRect = elementMatrix.mapRect(renderer->boundsOnElement(elementId)); + item->setPos(elementRect.x(), elementRect.y()); + + return item; +} + +/** + * Create a text item based on a svg rectangle. + * The rectangle must be in the correct location (hint: use a "text" layer on top of the "background layer") + * The font size will be set to match as well as possible the rectangle height but it is not guaranteed. + * + * It is possible to show the text rectangle to help understand layout issues. + * + */ +// TODO move to some utility class that can be reused by other SVG manipulating code +QGraphicsTextItem *createTextItem(QGraphicsSvgItem *parent, QString elementId, QString fontName, + bool showRect = false) +{ + if (showRect) { + // create and display the text rectangle + // needs to be done first otherwise the rectangle will blank out the text. + createSvgItem(parent, elementId); + } + + QGraphicsTextItem *item = new QGraphicsTextItem(); + + QSvgRenderer *renderer = parent->renderer(); + + // move new text item to location of rectangle element + QMatrix elementMatrix = renderer->matrixForElement(elementId); + QRectF elementRect = elementMatrix.mapRect(renderer->boundsOnElement(elementId)); + + qreal fontPointSizeF = elementRect.height(); + + QTransform matrix; + matrix.translate(elementRect.x(), elementRect.y() - (fontPointSizeF / 2.0)); + + item->setParentItem(parent); + item->setTransform(matrix, false); + // to right align or center text we must provide a text width + // item->setTextWidth(elementRect.width()); + + // create font to match the rectangle height + // there is not guaranteed that all fonts will play well... + QFont font(fontName); + // not sure if PreferMatch helps to get the correct font size (i.e. that fits the text rectangle nicely) + font.setStyleStrategy(QFont::PreferMatch); + font.setPointSizeF(fontPointSizeF); + + item->setFont(font); + +#ifdef DEBUG_FONT + // just in case + qDebug() << "Font point size: " << fontPointSizeF; + qDebug() << "Font pixel size: " << font.pixelSize(); + qDebug() << "Font point size: " << font.pointSize(); + qDebug() << "Font point size F: " << font.pointSizeF(); + qDebug() << "Font exact match: " << font.exactMatch(); + + QFontInfo fontInfo(font); + qDebug() << "Font info pixel size: " << fontInfo.pixelSize(); + qDebug() << "Font info point size: " << fontInfo.pointSize(); + qDebug() << "Font info point size F: " << fontInfo.pointSizeF(); + qDebug() << "Font info exact match: " << fontInfo.exactMatch(); +#endif + return item; +} +} // anonymous namespace + +MonitorWidget::MonitorWidget(QWidget *parent) : + QGraphicsView(parent), aspectRatioMode(Qt::KeepAspectRatio) +{ + // setMinimumWidth(180); + + QGraphicsScene *scene = new QGraphicsScene(); + + setScene(scene); + + setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding); + + // no scroll bars + setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + + setBackgroundBrush(QBrush(Utils::StyleHelper::baseColor())); + + setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing); + + QSvgRenderer *renderer = new QSvgRenderer(); + + if (renderer->load(QString(":/telemetry/images/tx-rx.svg"))) { + // create graph + graph = new QGraphicsSvgItem(); + graph->setSharedRenderer(renderer); + graph->setElementId("background"); + + graph->setFlags(QGraphicsItem::ItemClipsChildrenToShape | QGraphicsItem::ItemClipsToShape); + + scene->addItem(graph); + + int i; + + // create tx nodes + i = 0; + while (true) { + QString id = QString("tx%0").arg(i); + QString bgId = QString("tx_bg%0").arg(i); + if (!renderer->elementExists(id) || !renderer->elementExists(bgId)) { + break; + } + QGraphicsSvgItem *item = createSvgItem(graph, bgId); + item->setElementId(id); + txNodes.append(item); + i++; + } + + // create rx nodes + i = 0; + while (true) { + QString id = QString("rx%0").arg(i); + QString bgId = QString("rx_bg%0").arg(i); + if (!renderer->elementExists(id) || !renderer->elementExists(bgId)) { + break; + } + QGraphicsSvgItem *item = createSvgItem(graph, bgId); + item->setElementId(id); + rxNodes.append(item); + i++; + } + + if (renderer->elementExists("txSpeed")) { + txSpeed = createTextItem(graph, "txSpeed", "Helvetica"); + txSpeed->setDefaultTextColor(Qt::white); + } else { + txSpeed = NULL; + } + + if (renderer->elementExists("rxSpeed")) { + rxSpeed = createTextItem(graph, "rxSpeed", "Helvetica"); + rxSpeed->setDefaultTextColor(Qt::white); + } else { + rxSpeed = NULL; + } + // scene->setSceneRect(graph->boundingRect()); + } + + connected = false; + + setMin(0.0); + setMax(1200.0); + + telemetryUpdated(0.0, 0.0); +} + +MonitorWidget::~MonitorWidget() +{ + while (!txNodes.isEmpty()) { + delete txNodes.takeFirst(); + } + while (!rxNodes.isEmpty()) { + delete rxNodes.takeFirst(); + } + if (txSpeed) { + delete txSpeed; + } + if (rxSpeed) { + delete rxSpeed; + } +} + +/*! + \brief Enables/Disables OpenGL + */ +// void LineardialGadgetWidget::enableOpenGL(bool flag) +// { +// if (flag) { +// setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers))); +// } else { +// setViewport(new QWidget); +// } +// } + +void MonitorWidget::telemetryConnected() +{ + qDebug() << "telemetry connected"; + if (!connected) { + // flash the lights + setToolTip(tr("Connected")); + telemetryUpdated(maxValue, maxValue); + connected = true; + } +} + +void MonitorWidget::telemetryDisconnected() +{ + qDebug() << "telemetry disconnected"; + if (connected) { + connected = false; + + setToolTip(tr("Disconnected")); + + // flash the lights??? + telemetryUpdated(maxValue, maxValue); + + telemetryUpdated(0.0, 0.0); + } +} + +/*! + \brief Called by the UAVObject which got updated + + Updates the numeric value and/or the icon if the dial wants this. + */ +void MonitorWidget::telemetryUpdated(double txRate, double rxRate) +{ + double txIndex = (txRate - minValue) / (maxValue - minValue) * txNodes.count(); + double rxIndex = (rxRate - minValue) / (maxValue - minValue) * rxNodes.count(); + + if (connected) { + this->setToolTip(QString("Tx: %0 bytes/s, Rx: %1 bytes/s").arg(txRate).arg(rxRate)); + } + + for (int i = 0; i < txNodes.count(); i++) { + QGraphicsItem *node = txNodes.at(i); + bool visible = ( /*connected &&*/ (i < txIndex)); + if (visible != node->isVisible()) { + node->setVisible(visible); + node->update(); + } + } + + for (int i = 0; i < rxNodes.count(); i++) { + QGraphicsItem *node = rxNodes.at(i); + bool visible = ( /*connected &&*/ (i < rxIndex)); + if (visible != node->isVisible()) { + node->setVisible(visible); + node->update(); + } + } + + if (txSpeed) { + if (connected) { + txSpeed->setPlainText(QString("%0").arg(txRate)); + } + txSpeed->setVisible(connected); + txSpeed->update(); + } + + if (rxSpeed) { + if (connected) { + rxSpeed->setPlainText(QString("%0").arg(rxRate)); + } + rxSpeed->setVisible(connected); + rxSpeed->update(); + } + + update(); +} + +void MonitorWidget::showEvent(QShowEvent *event) +{ + Q_UNUSED(event); + + fitInView(graph, aspectRatioMode); +} + +void MonitorWidget::resizeEvent(QResizeEvent *event) +{ + Q_UNUSED(event); + + fitInView(graph, aspectRatioMode); +} diff --git a/ground/openpilotgcs/src/plugins/coreplugin/telemetrymonitorwidget.h b/ground/openpilotgcs/src/plugins/telemetry/monitorwidget.h similarity index 59% rename from ground/openpilotgcs/src/plugins/coreplugin/telemetrymonitorwidget.h rename to ground/openpilotgcs/src/plugins/telemetry/monitorwidget.h index b157d734d..729d25775 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/telemetrymonitorwidget.h +++ b/ground/openpilotgcs/src/plugins/telemetry/monitorwidget.h @@ -1,5 +1,5 @@ -#ifndef TELEMETRYMONITORWIDGET_H -#define TELEMETRYMONITORWIDGET_H +#ifndef MONITORWIDGET_H +#define MONITORWIDGET_H #include #include @@ -8,59 +8,56 @@ #include #include -class TelemetryMonitorWidget : public QGraphicsView { +class MonitorWidget : public QGraphicsView { Q_OBJECT public: - explicit TelemetryMonitorWidget(QWidget *parent = 0); - ~TelemetryMonitorWidget(); + explicit MonitorWidget(QWidget *parent = 0); + ~MonitorWidget(); void setMin(double min) { minValue = min; } + double getMin() { return minValue; } + void setMax(double max) { maxValue = max; } + double getMax() { return maxValue; } - // number of tx/rx nodes in the graph - static const int NODE_NUMELEM = 7; - -signals: - public slots: - void connect(); - void disconnect(); - - void updateTelemetry(double txRate, double rxRate); - void showTelemetry(); + void telemetryConnected(); + void telemetryDisconnected(); + void telemetryUpdated(double txRate, double rxRate); protected: void showEvent(QShowEvent *event); void resizeEvent(QResizeEvent *event); private: + bool connected; + + double minValue; + double maxValue; + QGraphicsSvgItem *graph; + QPointer txSpeed; QPointer rxSpeed; + QList txNodes; QList rxNodes; - bool connected; - double txIndex; - double txValue; - double rxIndex; - double rxValue; - double minValue; - double maxValue; + Qt::AspectRatioMode aspectRatioMode; }; -#endif // TELEMETRYMONITORWIDGET_H +#endif // MONITORWIDGET_H diff --git a/ground/openpilotgcs/src/plugins/telemetry/telemetry.pri b/ground/openpilotgcs/src/plugins/telemetry/telemetry.pri new file mode 100644 index 000000000..c5054c34f --- /dev/null +++ b/ground/openpilotgcs/src/plugins/telemetry/telemetry.pri @@ -0,0 +1,3 @@ +include(telemetry_dependencies.pri) + +LIBS *= -l$$qtLibraryName(Telemetry) diff --git a/ground/openpilotgcs/src/plugins/telemetry/telemetry.pro b/ground/openpilotgcs/src/plugins/telemetry/telemetry.pro new file mode 100644 index 000000000..f8e4d2331 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/telemetry/telemetry.pro @@ -0,0 +1,29 @@ +TEMPLATE = lib +TARGET = Telemetry + +QT += svg + +include(../../openpilotgcsplugin.pri) +include(../../plugins/coreplugin/coreplugin.pri) +include(telemetry_dependencies.pri) + +HEADERS += telemetry_global.h \ + telemetryplugin.h \ + monitorwidget.h \ + monitorgadgetconfiguration.h \ + monitorgadget.h \ + monitorgadgetfactory.h \ + monitorgadgetoptionspage.h + +SOURCES += telemetryplugin.cpp \ + monitorwidget.cpp \ + monitorgadgetconfiguration.cpp \ + monitorgadget.cpp \ + monitorgadgetfactory.cpp \ + monitorgadgetoptionspage.cpp + +DEFINES += TELEMETRY_LIBRARY + +RESOURCES += telemetry.qrc + +OTHER_FILES += Telemetry.pluginspec diff --git a/ground/openpilotgcs/src/plugins/telemetry/telemetry.qrc b/ground/openpilotgcs/src/plugins/telemetry/telemetry.qrc new file mode 100644 index 000000000..a21691073 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/telemetry/telemetry.qrc @@ -0,0 +1,5 @@ + + + images/tx-rx.svg + + diff --git a/ground/openpilotgcs/src/plugins/telemetry/telemetry_dependencies.pri b/ground/openpilotgcs/src/plugins/telemetry/telemetry_dependencies.pri new file mode 100644 index 000000000..883e47127 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/telemetry/telemetry_dependencies.pri @@ -0,0 +1,3 @@ +include(../../plugins/uavtalk/uavtalk.pri) +include(../../plugins/uavobjects/uavobjects.pri) + diff --git a/ground/openpilotgcs/src/plugins/coreplugin/versiondialog.h b/ground/openpilotgcs/src/plugins/telemetry/telemetry_global.h similarity index 68% rename from ground/openpilotgcs/src/plugins/coreplugin/versiondialog.h rename to ground/openpilotgcs/src/plugins/telemetry/telemetry_global.h index 58fd217b7..ee868c9e5 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/versiondialog.h +++ b/ground/openpilotgcs/src/plugins/telemetry/telemetry_global.h @@ -1,14 +1,13 @@ /** ****************************************************************************** * - * @file versiondialog.h + * @file telemetry_global.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 + * @addtogroup TelemetryPlugin Telemetry Plugin * @{ - * @brief The Core GCS plugin + * @brief The Telemetry plugin *****************************************************************************/ /* * This program is free software; you can redistribute it and/or modify @@ -26,19 +25,15 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef VERSIONDIALOG_H -#define VERSIONDIALOG_H +#ifndef TELEMETRY_GLOBAL_H +#define TELEMETRY_GLOBAL_H -#include +#include -namespace Core { -namespace Internal { -class VersionDialog : public QDialog { - Q_OBJECT -public: - explicit VersionDialog(QWidget *parent); -}; -} // namespace Internal -} // namespace Core +#if defined(TELEMETRY_LIBRARY) +# define TELEMETRY_EXPORT Q_DECL_EXPORT +#else +# define TELEMETRY_EXPORT Q_DECL_IMPORT +#endif -#endif // VERSIONDIALOG_H +#endif // TELEMETRY_GLOBAL_H diff --git a/ground/openpilotgcs/src/plugins/telemetry/telemetryplugin.cpp b/ground/openpilotgcs/src/plugins/telemetry/telemetryplugin.cpp new file mode 100644 index 000000000..4a68a2734 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/telemetry/telemetryplugin.cpp @@ -0,0 +1,246 @@ +/** + ****************************************************************************** + * + * @file telemetryplugin.cpp + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief + * @see The GNU Public License (GPL) Version 3 + * @defgroup telemetryplugin + * @{ + * + *****************************************************************************/ +/* + * 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 "telemetryplugin.h" +#include "monitorgadgetfactory.h" + +#include "extensionsystem/pluginmanager.h" +#include "uavobjectmanager.h" +#include "uavobject.h" +#include "coreplugin/icore.h" +#include "coreplugin/connectionmanager.h" + +#include +#include +#include + +#include +#include +#include + +TelemetryPlugin::TelemetryPlugin() +{} + +TelemetryPlugin::~TelemetryPlugin() +{ +// Core::ICore::instance()->saveSettings(this); +} + +bool TelemetryPlugin::initialize(const QStringList & args, QString *errMsg) +{ + Q_UNUSED(args); + Q_UNUSED(errMsg); + + MonitorGadgetFactory *mf = new MonitorGadgetFactory(this); + addAutoReleasedObject(mf); + + // mop = new TelemetryPluginOptionsPage(this); + // addAutoReleasedObject(mop); + + // TODO not so good... g is probalby leaked... + MonitorWidget *w = mf->createMonitorWidget(NULL); + w->setMaximumWidth(180); + + // + // setAlignment(Qt::AlignCenter); + + // no border + w->setFrameStyle(QFrame::NoFrame); + w->setWindowFlags(Qt::FramelessWindowHint); + + // set svg background translucent + w->setStyleSheet("background:transparent;"); + // set widget background translucent + w->setAttribute(Qt::WA_TranslucentBackground); + + w->setBackgroundBrush(Qt::NoBrush); + + // add monitor widget to connection manager + Core::ConnectionManager *cm = Core::ICore::instance()->connectionManager(); +// connect(cm, SIGNAL(deviceConnected(QIODevice *)), w, SLOT(telemetryConnected())); +// connect(cm, SIGNAL(deviceDisconnected()), w, SLOT(telemetryDisconnected())); + + cm->addWidget(w); + + return true; +} + +void TelemetryPlugin::extensionsInitialized() +{ +// Core::ICore::instance()->readSettings(this); + + // ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); + +// connect(pm, SIGNAL(objectAdded(QObject *)), this, SLOT(onTelemetryManagerAdded(QObject *))); +// _toRemoveNotifications.clear(); +// connectNotifications(); +} + +// void TelemetryPlugin::saveConfig(QSettings *settings, UAVConfigInfo *configInfo) +// { +// configInfo->setVersion(VERSION); +// +// settings->beginWriteArray("Current"); +// settings->setArrayIndex(0); +// currentNotification.saveState(settings); +// settings->endArray(); +// +// settings->beginGroup("listNotifies"); +// settings->remove(""); +// settings->endGroup(); +// +// settings->beginWriteArray("listNotifies"); +// for (int i = 0; i < _notificationList.size(); i++) { +// settings->setArrayIndex(i); +// _notificationList.at(i)->saveState(settings); +// } +// settings->endArray(); +// settings->setValue(QLatin1String("Enable"), enable); +// } + +// void TelemetryPlugin::readConfig(QSettings *settings, UAVConfigInfo * /* configInfo */) +// { +//// Just for migration to the new format. +//// Q_ASSERT(configInfo->version() == UAVConfigVersion()); +// +// settings->beginReadArray("Current"); +// settings->setArrayIndex(0); +// currentNotification.restoreState(settings); +// settings->endArray(); +// +//// read list of notifications from settings +// int size = settings->beginReadArray("listNotifies"); +// for (int i = 0; i < size; ++i) { +// settings->setArrayIndex(i); +// NotificationItem *notification = new NotificationItem; +// notification->restoreState(settings); +// _notificationList.append(notification); +// } +// settings->endArray(); +// setEnable(settings->value(QLatin1String("Enable"), 0).toBool()); +// } + +// void TelemetryPlugin::onTelemetryManagerAdded(QObject *obj) +// { +// telMngr = qobject_cast(obj); +// if (telMngr) { +// connect(telMngr, SIGNAL(disconnected()), this, SLOT(onAutopilotDisconnect())); +// } +// } + +void TelemetryPlugin::shutdown() +{ + // Do nothing +} + +// void TelemetryPlugin::onAutopilotDisconnect() +// { +// connectNotifications(); +// } + +///*! +// clear any telemetry timers from previous flight; +// reset will be perform on start of option page +// */ +// void TelemetryPlugin::resetNotification(void) +// { +//// first, reject empty args and unknown fields. +// foreach(NotificationItem * ntf, _notificationList) { +// ntf->disposeTimer(); +// disconnect(ntf->getTimer(), SIGNAL(timeout()), this, SLOT(on_timerRepeated_Notification())); +// ntf->disposeExpireTimer(); +// disconnect(ntf->getExpireTimer(), SIGNAL(timeout()), this, SLOT(on_timerRepeated_Notification())); +// } +// } + +// void TelemetryPlugin::connectNotifications() +// { +// foreach(UAVDataObject * obj, lstNotifiedUAVObjects) { +// if (obj != NULL) { +// disconnect(obj, SIGNAL(objectUpdated(UAVObject *)), this, SLOT(on_arrived_Notification(UAVObject *))); +// } +// } +// if (phonon.mo != NULL) { +// delete phonon.mo; +// phonon.mo = NULL; +// } +// +// if (!enable) { +// return; +// } +// +// ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); +// UAVObjectManager *objManager = pm->getObject(); +// +// lstNotifiedUAVObjects.clear(); +// _pendingNotifications.clear(); +// _notificationList.append(_toRemoveNotifications); +// _toRemoveNotifications.clear(); +// +//// first, reject empty args and unknown fields. +// foreach(NotificationItem * telemetry, _notificationList) { +// telemetry->_isPlayed = false; +// telemetry->isNowPlaying = false; +// +// if (telemetry->mute()) { +// continue; +// } +//// check is all sounds presented for notification, +//// if not - we must not subscribe to it at all +// if (telemetry->toList().isEmpty()) { +// continue; +// } +// +// UAVDataObject *obj = dynamic_cast(objManager->getObject(telemetry->getDataObject())); +// if (obj != NULL) { +// if (!lstNotifiedUAVObjects.contains(obj)) { +// lstNotifiedUAVObjects.append(obj); +// +// connect(obj, SIGNAL(objectUpdated(UAVObject *)), +// this, SLOT(on_arrived_Notification(UAVObject *)), +// Qt::QueuedConnection); +// } +// } else { +// qTelemetryDebug() << "Error: Object is unknown (" << telemetry->getDataObject() << ")."; +// } +// } +// +// if (_notificationList.isEmpty()) { +// return; +// } +//// set notification message to current event +// phonon.mo = Phonon::createPlayer(Phonon::NotificationCategory); +// phonon.mo->clearQueue(); +// phonon.firstPlay = true; +// QList audioOutputDevices = +// Phonon::BackendCapabilities::availableAudioOutputDevices(); +// foreach(Phonon::AudioOutputDevice dev, audioOutputDevices) { +// qTelemetryDebug() << "Telemetry: Audio Output device: " << dev.name() << " - " << dev.description(); +// } +// connect(phonon.mo, SIGNAL(stateChanged(Phonon::State, Phonon::State)), +// this, SLOT(stateChanged(Phonon::State, Phonon::State))); +// } diff --git a/ground/openpilotgcs/src/plugins/telemetry/telemetryplugin.h b/ground/openpilotgcs/src/plugins/telemetry/telemetryplugin.h new file mode 100644 index 000000000..300c08ad7 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/telemetry/telemetryplugin.h @@ -0,0 +1,51 @@ +/** + ****************************************************************************** + * + * @file telemetryplugin.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. + * @brief + * @see The GNU Public License (GPL) Version 3 + * @defgroup telemetryplugin + * @{ + * + *****************************************************************************/ +/* + * 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 TELEMETRYPLUGIN_H +#define TELEMETRYPLUGIN_H + +#include + +class MonitorGadgetFactory; + +class TelemetryPlugin : public ExtensionSystem::IPlugin { + Q_OBJECT + Q_PLUGIN_METADATA(IID "OpenPilot.Telemetry") + + +public: + TelemetryPlugin(); + ~TelemetryPlugin(); + + void extensionsInitialized(); + bool initialize(const QStringList &arguments, QString *errorString); + void shutdown(); + +private: + MonitorGadgetFactory *mf; +}; + +#endif // TELEMETRYPLUGIN_H diff --git a/ground/openpilotgcs/src/plugins/uavobjectbrowser/fieldtreeitem.h b/ground/openpilotgcs/src/plugins/uavobjectbrowser/fieldtreeitem.h index cbdab0cb5..31cf9ecb3 100644 --- a/ground/openpilotgcs/src/plugins/uavobjectbrowser/fieldtreeitem.h +++ b/ground/openpilotgcs/src/plugins/uavobjectbrowser/fieldtreeitem.h @@ -115,6 +115,8 @@ public: { QComboBox *editor = new QComboBox(parent); + // Setting ClickFocus lets the ComboBox stay open on Mac OSX. + editor->setFocusPolicy(Qt::ClickFocus); foreach(QString option, m_enumOptions) editor->addItem(option); return editor; diff --git a/ground/openpilotgcs/src/plugins/uavobjects/uavmetaobject.cpp b/ground/openpilotgcs/src/plugins/uavobjects/uavmetaobject.cpp index 92c6d8c3b..80e4d5ed6 100644 --- a/ground/openpilotgcs/src/plugins/uavobjects/uavmetaobject.cpp +++ b/ground/openpilotgcs/src/plugins/uavobjects/uavmetaobject.cpp @@ -39,7 +39,7 @@ UAVMetaObject::UAVMetaObject(quint32 objID, const QString & name, UAVObject *par UAVObject::MetadataInitialize(ownMetadata); // Setup fields QStringList modesBitField; - modesBitField << tr("FlightReadOnly") << tr("GCSReadOnly") << tr("FlightTelemetryAcked") << tr("GCSTelemetryAcked") << tr("FlightUpdatePeriodic") << tr("FlightUpdateOnChange") << tr("GCSUpdatePeriodic") << tr("GCSUpdateOnChange"); + modesBitField << tr("FlightReadOnly") << tr("GCSReadOnly") << tr("FlightTelemetryAcked") << tr("GCSTelemetryAcked") << tr("FlightUpdatePeriodic") << tr("FlightUpdateOnChange") << tr("GCSUpdatePeriodic") << tr("GCSUpdateOnChange") << tr("LoggingUpdatePeriodic") << tr("LoggingUpdateOnChange"); QList fields; fields.append(new UAVObjectField(tr("Modes"), tr("boolean"), UAVObjectField::BITFIELD, modesBitField, QStringList())); fields.append(new UAVObjectField(tr("Flight Telemetry Update Period"), tr("ms"), UAVObjectField::UINT16, 1, QStringList())); diff --git a/ground/openpilotgcs/src/plugins/uavobjects/uavobject.cpp b/ground/openpilotgcs/src/plugins/uavobjects/uavobject.cpp index d795e8cb3..7f6c02a15 100644 --- a/ground/openpilotgcs/src/plugins/uavobjects/uavobject.cpp +++ b/ground/openpilotgcs/src/plugins/uavobjects/uavobject.cpp @@ -36,6 +36,7 @@ #define UAVOBJ_GCS_TELEMETRY_ACKED_SHIFT 3 #define UAVOBJ_TELEMETRY_UPDATE_MODE_SHIFT 4 #define UAVOBJ_GCS_TELEMETRY_UPDATE_MODE_SHIFT 6 +#define UAVOBJ_LOGGING_UPDATE_MODE_SHIFT 8 #define UAVOBJ_UPDATE_MODE_MASK 0x3 // Macros @@ -498,7 +499,8 @@ void UAVObject::MetadataInitialize(UAVObject::Metadata & metadata) 1 << UAVOBJ_TELEMETRY_ACKED_SHIFT | 1 << UAVOBJ_GCS_TELEMETRY_ACKED_SHIFT | UPDATEMODE_ONCHANGE << UAVOBJ_TELEMETRY_UPDATE_MODE_SHIFT | - UPDATEMODE_ONCHANGE << UAVOBJ_GCS_TELEMETRY_UPDATE_MODE_SHIFT; + UPDATEMODE_ONCHANGE << UAVOBJ_GCS_TELEMETRY_UPDATE_MODE_SHIFT | + UPDATEMODE_ONCHANGE << UAVOBJ_LOGGING_UPDATE_MODE_SHIFT; metadata.flightTelemetryUpdatePeriod = 0; metadata.gcsTelemetryUpdatePeriod = 0; metadata.loggingUpdatePeriod = 0; diff --git a/ground/openpilotgcs/src/plugins/uavobjects/uavobject.cpp.template b/ground/openpilotgcs/src/plugins/uavobjects/uavobject.cpp.template index df78735bb..a91754136 100644 --- a/ground/openpilotgcs/src/plugins/uavobjects/uavobject.cpp.template +++ b/ground/openpilotgcs/src/plugins/uavobjects/uavobject.cpp.template @@ -71,7 +71,8 @@ UAVObject::Metadata $(NAME)::getDefaultMetadata() $(FLIGHTTELEM_ACKED) << UAVOBJ_TELEMETRY_ACKED_SHIFT | $(GCSTELEM_ACKED) << UAVOBJ_GCS_TELEMETRY_ACKED_SHIFT | $(FLIGHTTELEM_UPDATEMODE) << UAVOBJ_TELEMETRY_UPDATE_MODE_SHIFT | - $(GCSTELEM_UPDATEMODE) << UAVOBJ_GCS_TELEMETRY_UPDATE_MODE_SHIFT; + $(GCSTELEM_UPDATEMODE) << UAVOBJ_GCS_TELEMETRY_UPDATE_MODE_SHIFT | + $(LOGGING_UPDATEMODE) << UAVOBJ_LOGGING_UPDATE_MODE_SHIFT; metadata.flightTelemetryUpdatePeriod = $(FLIGHTTELEM_UPDATEPERIOD); metadata.gcsTelemetryUpdatePeriod = $(GCSTELEM_UPDATEPERIOD); metadata.loggingUpdatePeriod = $(LOGGING_UPDATEPERIOD); diff --git a/ground/openpilotgcs/src/plugins/uavobjects/uavobject.h b/ground/openpilotgcs/src/plugins/uavobjects/uavobject.h index 882378e7a..c7d9941d2 100644 --- a/ground/openpilotgcs/src/plugins/uavobjects/uavobject.h +++ b/ground/openpilotgcs/src/plugins/uavobjects/uavobject.h @@ -45,6 +45,7 @@ #define UAVOBJ_GCS_TELEMETRY_ACKED_SHIFT 3 #define UAVOBJ_TELEMETRY_UPDATE_MODE_SHIFT 4 #define UAVOBJ_GCS_TELEMETRY_UPDATE_MODE_SHIFT 6 +#define UAVOBJ_LOGGING_UPDATE_MODE_SHIFT 8 #define UAVOBJ_UPDATE_MODE_MASK 0x3 class UAVObjectField; @@ -87,9 +88,10 @@ public: * 3 gcsTelemetryAcked Defines if an ack is required for the transactions of this object (1:acked, 0:not acked) * 4-5 telemetryUpdateMode Update mode used by the telemetry module (UAVObjUpdateMode) * 6-7 gcsTelemetryUpdateMode Update mode used by the GCS (UAVObjUpdateMode) + * 8-9 loggingUpdateMode Update mode used by the logging module (UAVObjUpdateMode) */ typedef struct { - quint8 flags; /** Defines flags for update and logging modes and whether an update should be ACK'd (bits defined above) */ + quint16 flags; /** Defines flags for update and logging modes and whether an update should be ACK'd (bits defined above) */ quint16 flightTelemetryUpdatePeriod; /** Update period used by the telemetry module (only if telemetry mode is PERIODIC) */ quint16 gcsTelemetryUpdatePeriod; /** Update period used by the GCS (only if telemetry mode is PERIODIC) */ quint16 loggingUpdatePeriod; /** Update period used by the logging module (only if logging mode is PERIODIC) */ diff --git a/ground/openpilotgcs/src/plugins/uavobjects/uavobjecthelper.cpp b/ground/openpilotgcs/src/plugins/uavobjects/uavobjecthelper.cpp new file mode 100644 index 000000000..25ff5f805 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/uavobjects/uavobjecthelper.cpp @@ -0,0 +1,100 @@ +/** + ****************************************************************************** + * + * @file uavobjecthelper.cpp + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012. + * @addtogroup [Group] + * @{ + * @addtogroup UAVObjectHelper + * @{ + * @brief [Brief] + *****************************************************************************/ +/* + * 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 "uavobjecthelper.h" +#include + +AbstractUAVObjectHelper::AbstractUAVObjectHelper(QObject *parent) : + QObject(parent), m_transactionResult(false), m_transactionCompleted(false) +{} + +AbstractUAVObjectHelper::Result AbstractUAVObjectHelper::doObjectAndWait(UAVObject *object, int timeout) +{ + // Lock, we can't call this twice from different threads + QMutexLocker locker(&m_mutex); + + m_object = object; + + // Reset variables + m_transactionResult = false; + m_transactionCompleted = false; + + // Create timer and connect it, connect object tx completed to local slot + QTimer timeoutTimer; + timeoutTimer.setSingleShot(true); + connect(&timeoutTimer, SIGNAL(timeout()), &m_eventLoop, SLOT(quit())); + connect(object, SIGNAL(transactionCompleted(UAVObject *, bool)), this, SLOT(transactionCompleted(UAVObject *, bool))); + + // Start timeout timer + timeoutTimer.start(timeout); + + // Call the actual implementation in concrete subclass + doObjectAndWaitImpl(); + + // Wait if not completed + if (!m_transactionCompleted) { + m_eventLoop.exec(); + } + timeoutTimer.stop(); + + // Disconnect + disconnect(object, SIGNAL(transactionCompleted(UAVObject *, bool)), this, SLOT(transactionCompleted(UAVObject *, bool))); + disconnect(&timeoutTimer, SIGNAL(timeout()), &m_eventLoop, SLOT(quit())); + + // Return result + if (!m_transactionCompleted) { + return TIMEOUT; + } else { + return m_transactionResult ? SUCCESS : FAIL; + } +} + +void AbstractUAVObjectHelper::transactionCompleted(UAVObject *object, bool success) +{ + Q_UNUSED(object) + + // Set variables and quit event loop + m_transactionResult = success; + m_transactionCompleted = true; + m_eventLoop.quit(); +} + +UAVObjectUpdaterHelper::UAVObjectUpdaterHelper(QObject *parent) : AbstractUAVObjectHelper(parent) +{} + +void UAVObjectUpdaterHelper::doObjectAndWaitImpl() +{ + m_object->updated(); +} + +UAVObjectRequestHelper::UAVObjectRequestHelper(QObject *parent) : AbstractUAVObjectHelper(parent) +{} + +void UAVObjectRequestHelper::doObjectAndWaitImpl() +{ + m_object->requestUpdate(); +} diff --git a/ground/openpilotgcs/src/plugins/uavobjects/uavobjecthelper.h b/ground/openpilotgcs/src/plugins/uavobjects/uavobjecthelper.h new file mode 100644 index 000000000..bf2739e09 --- /dev/null +++ b/ground/openpilotgcs/src/plugins/uavobjects/uavobjecthelper.h @@ -0,0 +1,78 @@ +/** + ****************************************************************************** + * + * @file uavobjecthelper.h + * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012. + * @addtogroup [Group] + * @{ + * @addtogroup UAVObjectHelper + * @{ + * @brief [Brief] + *****************************************************************************/ +/* + * 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 UAVOBJECTHELPER_H +#define UAVOBJECTHELPER_H + +#include +#include +#include +#include + +#include "uavobject.h" + +class UAVOBJECTS_EXPORT AbstractUAVObjectHelper : public QObject { + Q_OBJECT +public: + explicit AbstractUAVObjectHelper(QObject *parent = 0); + + enum Result { SUCCESS, FAIL, TIMEOUT }; + Result doObjectAndWait(UAVObject *object, int timeout); + +protected: + virtual void doObjectAndWaitImpl() = 0; + UAVObject *m_object; + +private slots: + void transactionCompleted(UAVObject *object, bool success); + +private: + QMutex m_mutex; + QEventLoop m_eventLoop; + bool m_transactionResult; + bool m_transactionCompleted; +}; + +class UAVOBJECTS_EXPORT UAVObjectUpdaterHelper : public AbstractUAVObjectHelper { + Q_OBJECT +public: + explicit UAVObjectUpdaterHelper(QObject *parent = 0); + +protected: + virtual void doObjectAndWaitImpl(); +}; + +class UAVOBJECTS_EXPORT UAVObjectRequestHelper : public AbstractUAVObjectHelper { + Q_OBJECT +public: + explicit UAVObjectRequestHelper(QObject *parent = 0); + +protected: + virtual void doObjectAndWaitImpl(); +}; + +#endif // UAVOBJECTHELPER_H diff --git a/ground/openpilotgcs/src/plugins/uavobjects/uavobjects.pro b/ground/openpilotgcs/src/plugins/uavobjects/uavobjects.pro index 44b96a580..d1b002994 100644 --- a/ground/openpilotgcs/src/plugins/uavobjects/uavobjects.pro +++ b/ground/openpilotgcs/src/plugins/uavobjects/uavobjects.pro @@ -11,14 +11,16 @@ HEADERS += uavobjects_global.h \ uavdataobject.h \ uavobjectfield.h \ uavobjectsinit.h \ - uavobjectsplugin.h + uavobjectsplugin.h \ + uavobjecthelper.h SOURCES += uavobject.cpp \ uavmetaobject.cpp \ uavobjectmanager.cpp \ uavdataobject.cpp \ uavobjectfield.cpp \ - uavobjectsplugin.cpp + uavobjectsplugin.cpp \ + uavobjecthelper.cpp OTHER_FILES += UAVObjects.pluginspec @@ -34,6 +36,10 @@ HEADERS += $$UAVOBJECT_SYNTHETICS/accessorydesired.h \ $$UAVOBJECT_SYNTHETICS/altitudeholddesired.h \ $$UAVOBJECT_SYNTHETICS/altitudeholdsettings.h \ $$UAVOBJECT_SYNTHETICS/altitudefiltersettings.h \ + $$UAVOBJECT_SYNTHETICS/debuglogsettings.h \ + $$UAVOBJECT_SYNTHETICS/debuglogcontrol.h \ + $$UAVOBJECT_SYNTHETICS/debuglogstatus.h \ + $$UAVOBJECT_SYNTHETICS/debuglogentry.h \ $$UAVOBJECT_SYNTHETICS/ekfconfiguration.h \ $$UAVOBJECT_SYNTHETICS/ekfstatevariance.h \ $$UAVOBJECT_SYNTHETICS/revocalibration.h \ @@ -120,6 +126,10 @@ SOURCES += $$UAVOBJECT_SYNTHETICS/accessorydesired.cpp \ $$UAVOBJECT_SYNTHETICS/altholdsmoothed.cpp \ $$UAVOBJECT_SYNTHETICS/altitudeholddesired.cpp \ $$UAVOBJECT_SYNTHETICS/altitudeholdsettings.cpp \ + $$UAVOBJECT_SYNTHETICS/debuglogsettings.cpp \ + $$UAVOBJECT_SYNTHETICS/debuglogcontrol.cpp \ + $$UAVOBJECT_SYNTHETICS/debuglogstatus.cpp \ + $$UAVOBJECT_SYNTHETICS/debuglogentry.cpp \ $$UAVOBJECT_SYNTHETICS/altitudefiltersettings.cpp \ $$UAVOBJECT_SYNTHETICS/ekfconfiguration.cpp \ $$UAVOBJECT_SYNTHETICS/ekfstatevariance.cpp \ diff --git a/ground/openpilotgcs/src/plugins/uavtalk/telemetrymanager.cpp b/ground/openpilotgcs/src/plugins/uavtalk/telemetrymanager.cpp index 008e3af73..3eeb7e5a8 100644 --- a/ground/openpilotgcs/src/plugins/uavtalk/telemetrymanager.cpp +++ b/ground/openpilotgcs/src/plugins/uavtalk/telemetrymanager.cpp @@ -64,9 +64,9 @@ void TelemetryManager::onStart() telemetryMon = new TelemetryMonitor(objMngr, telemetry); connect(telemetryMon, SIGNAL(connected()), this, SLOT(onConnect())); connect(telemetryMon, SIGNAL(disconnected()), this, SLOT(onDisconnect())); + connect(telemetryMon, SIGNAL(telemetryUpdated(double, double)), this, SLOT(onTelemetryUpdate(double, double))); } - void TelemetryManager::stop() { emit myStop(); @@ -92,3 +92,8 @@ void TelemetryManager::onDisconnect() autopilotConnected = false; emit disconnected(); } + +void TelemetryManager::onTelemetryUpdate(double txRate, double rxRate) +{ + emit telemetryUpdated(txRate, rxRate); +} diff --git a/ground/openpilotgcs/src/plugins/uavtalk/telemetrymanager.h b/ground/openpilotgcs/src/plugins/uavtalk/telemetrymanager.h index c4e7301ec..be956bf4f 100644 --- a/ground/openpilotgcs/src/plugins/uavtalk/telemetrymanager.h +++ b/ground/openpilotgcs/src/plugins/uavtalk/telemetrymanager.h @@ -50,12 +50,14 @@ public: signals: void connected(); void disconnected(); + void telemetryUpdated(double txRate, double rxRate); void myStart(); void myStop(); private slots: void onConnect(); void onDisconnect(); + void onTelemetryUpdate(double txRate, double rxRate); void onStart(); void onStop(); diff --git a/ground/openpilotgcs/src/plugins/uavtalk/telemetrymonitor.cpp b/ground/openpilotgcs/src/plugins/uavtalk/telemetrymonitor.cpp index 9bfe7cf7d..8342d5001 100644 --- a/ground/openpilotgcs/src/plugins/uavtalk/telemetrymonitor.cpp +++ b/ground/openpilotgcs/src/plugins/uavtalk/telemetrymonitor.cpp @@ -49,11 +49,6 @@ TelemetryMonitor::TelemetryMonitor(UAVObjectManager *objMngr, Telemetry *tel) : // Start update timer connect(statsTimer, SIGNAL(timeout()), this, SLOT(processStatsUpdates())); statsTimer->start(STATS_CONNECT_PERIOD_MS); - - Core::ConnectionManager *cm = Core::ICore::instance()->connectionManager(); - connect(this, SIGNAL(connected()), cm, SLOT(telemetryConnected())); - connect(this, SIGNAL(disconnected()), cm, SLOT(telemetryDisconnected())); - connect(this, SIGNAL(telemetryUpdated(double, double)), cm, SLOT(telemetryUpdated(double, double))); } TelemetryMonitor::~TelemetryMonitor() diff --git a/ground/openpilotgcs/src/plugins/uavtalk/uavtalk.pro b/ground/openpilotgcs/src/plugins/uavtalk/uavtalk.pro index 731cdf0ed..64fd2289e 100644 --- a/ground/openpilotgcs/src/plugins/uavtalk/uavtalk.pro +++ b/ground/openpilotgcs/src/plugins/uavtalk/uavtalk.pro @@ -1,18 +1,24 @@ -QT += network TEMPLATE = lib TARGET = UAVTalk + +QT += network + include(../../openpilotgcsplugin.pri) include(uavtalk_dependencies.pri) + HEADERS += uavtalk.h \ uavtalkplugin.h \ telemetrymonitor.h \ telemetrymanager.h \ uavtalk_global.h \ telemetry.h + SOURCES += uavtalk.cpp \ uavtalkplugin.cpp \ telemetrymonitor.cpp \ telemetrymanager.cpp \ telemetry.cpp + DEFINES += UAVTALK_LIBRARY + OTHER_FILES += UAVTalk.pluginspec diff --git a/ground/openpilotgcs/src/plugins/welcome/qml/ActivityPanel.qml b/ground/openpilotgcs/src/plugins/welcome/qml/ActivityPanel.qml index 111c4d7e9..fdc258500 100644 --- a/ground/openpilotgcs/src/plugins/welcome/qml/ActivityPanel.qml +++ b/ground/openpilotgcs/src/plugins/welcome/qml/ActivityPanel.qml @@ -1,4 +1,5 @@ -import QtQuick 1.1 +import QtQuick 2.0 +import QtQuick.XmlListModel 2.0 Item { id: container diff --git a/ground/openpilotgcs/src/plugins/welcome/qml/CommunityPanel.qml b/ground/openpilotgcs/src/plugins/welcome/qml/CommunityPanel.qml index caa3678b2..20f19fd70 100644 --- a/ground/openpilotgcs/src/plugins/welcome/qml/CommunityPanel.qml +++ b/ground/openpilotgcs/src/plugins/welcome/qml/CommunityPanel.qml @@ -1,5 +1,5 @@ // import QtQuick 1.0 // to target S60 5th Edition or Maemo 5 -import QtQuick 1.1 +import QtQuick 2.0 Item { property alias sourceSize: background.sourceSize diff --git a/ground/openpilotgcs/src/plugins/welcome/qml/NewsPanel.qml b/ground/openpilotgcs/src/plugins/welcome/qml/NewsPanel.qml index 6d794b210..0e6a8ef99 100644 --- a/ground/openpilotgcs/src/plugins/welcome/qml/NewsPanel.qml +++ b/ground/openpilotgcs/src/plugins/welcome/qml/NewsPanel.qml @@ -1,5 +1,6 @@ // import QtQuick 1.0 // to target S60 5th Edition or Maemo 5 -import QtQuick 1.1 +import QtQuick 2.0 +import QtQuick.XmlListModel 2.0 Item { id: container diff --git a/ground/openpilotgcs/src/plugins/welcome/qml/ScrollDecorator.qml b/ground/openpilotgcs/src/plugins/welcome/qml/ScrollDecorator.qml index 24c79c927..5e4e7e8d9 100644 --- a/ground/openpilotgcs/src/plugins/welcome/qml/ScrollDecorator.qml +++ b/ground/openpilotgcs/src/plugins/welcome/qml/ScrollDecorator.qml @@ -1,4 +1,4 @@ -import QtQuick 1.1 +import QtQuick 2.0 Rectangle { id: scrollDecorator diff --git a/ground/openpilotgcs/src/plugins/welcome/qml/SitesPanel.qml b/ground/openpilotgcs/src/plugins/welcome/qml/SitesPanel.qml index c94f243e2..00f2e3664 100644 --- a/ground/openpilotgcs/src/plugins/welcome/qml/SitesPanel.qml +++ b/ground/openpilotgcs/src/plugins/welcome/qml/SitesPanel.qml @@ -1,5 +1,5 @@ // import QtQuick 1.0 // to target S60 5th Edition or Maemo 5 -import QtQuick 1.1 +import QtQuick 2.0 Item { id: container diff --git a/ground/openpilotgcs/src/plugins/welcome/qml/WelcomePageButton.qml b/ground/openpilotgcs/src/plugins/welcome/qml/WelcomePageButton.qml index 9e5c1a74f..618baee73 100644 --- a/ground/openpilotgcs/src/plugins/welcome/qml/WelcomePageButton.qml +++ b/ground/openpilotgcs/src/plugins/welcome/qml/WelcomePageButton.qml @@ -1,5 +1,5 @@ // import QtQuick 1.0 // to target S60 5th Edition or Maemo 5 -import QtQuick 1.1 +import QtQuick 2.0 Item { id: welcomeButton diff --git a/ground/openpilotgcs/src/plugins/welcome/qml/main.qml b/ground/openpilotgcs/src/plugins/welcome/qml/main.qml index 82e7b1064..7a58a8fa3 100644 --- a/ground/openpilotgcs/src/plugins/welcome/qml/main.qml +++ b/ground/openpilotgcs/src/plugins/welcome/qml/main.qml @@ -1,4 +1,4 @@ -import QtQuick 1.1 +import QtQuick 2.0 Rectangle { id: container diff --git a/ground/openpilotgcs/src/plugins/welcome/welcome.pro b/ground/openpilotgcs/src/plugins/welcome/welcome.pro index eb44bc8da..40eba229c 100644 --- a/ground/openpilotgcs/src/plugins/welcome/welcome.pro +++ b/ground/openpilotgcs/src/plugins/welcome/welcome.pro @@ -1,6 +1,6 @@ TEMPLATE = lib TARGET = Welcome -QT += network declarative +QT += network qml quick include(../../openpilotgcsplugin.pri) include(welcome_dependencies.pri) diff --git a/ground/openpilotgcs/src/plugins/welcome/welcomemode.cpp b/ground/openpilotgcs/src/plugins/welcome/welcomemode.cpp index 501c4ba7a..381fd226a 100644 --- a/ground/openpilotgcs/src/plugins/welcome/welcomemode.cpp +++ b/ground/openpilotgcs/src/plugins/welcome/welcomemode.cpp @@ -45,10 +45,10 @@ #include #include -#include -#include -#include -#include +#include +#include +#include +#include #include @@ -59,7 +59,7 @@ namespace Welcome { struct WelcomeModePrivate { WelcomeModePrivate(); - QDeclarativeView *declarativeView; + QQuickView *quickView; }; WelcomeModePrivate::WelcomeModePrivate() @@ -70,15 +70,16 @@ WelcomeMode::WelcomeMode() : m_d(new WelcomeModePrivate), m_priority(Core::Constants::P_MODE_WELCOME) { - m_d->declarativeView = new QDeclarativeView; - m_d->declarativeView->setResizeMode(QDeclarativeView::SizeRootObjectToView); - m_d->declarativeView->engine()->rootContext()->setContextProperty("welcomePlugin", this); - m_d->declarativeView->setSource(QUrl("qrc:/welcome/qml/main.qml")); + m_d->quickView = new QQuickView; + m_d->quickView->setResizeMode(QQuickView::SizeRootObjectToView); + m_d->quickView->engine()->rootContext()->setContextProperty("welcomePlugin", this); + m_d->quickView->setSource(QUrl("qrc:/welcome/qml/main.qml")); + m_container = NULL; } WelcomeMode::~WelcomeMode() { - delete m_d->declarativeView; + delete m_d->quickView; delete m_d; } @@ -99,7 +100,12 @@ int WelcomeMode::priority() const QWidget *WelcomeMode::widget() { - return m_d->declarativeView; + if (!m_container) { + m_container = QWidget::createWindowContainer(m_d->quickView); + m_container->setMinimumSize(64, 64); + m_container->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); + } + return m_container; } const char *WelcomeMode::uniqueModeName() const diff --git a/ground/openpilotgcs/src/plugins/welcome/welcomemode.h b/ground/openpilotgcs/src/plugins/welcome/welcomemode.h index fa3f22856..b6e837cc9 100644 --- a/ground/openpilotgcs/src/plugins/welcome/welcomemode.h +++ b/ground/openpilotgcs/src/plugins/welcome/welcomemode.h @@ -72,6 +72,7 @@ public slots: void triggerAction(const QString &actionId); private: + QWidget *m_container; WelcomeModePrivate *m_d; int m_priority; }; diff --git a/ground/uavobjgenerator/generators/gcs/uavobjectgeneratorgcs.cpp b/ground/uavobjgenerator/generators/gcs/uavobjectgeneratorgcs.cpp index 2b1eb5d14..7265d411a 100644 --- a/ground/uavobjgenerator/generators/gcs/uavobjectgeneratorgcs.cpp +++ b/ground/uavobjgenerator/generators/gcs/uavobjectgeneratorgcs.cpp @@ -127,6 +127,9 @@ bool UAVObjectGeneratorGCS::process_object(ObjectInfo *info) type = fieldTypeStrCPP[field->type]; // Append field if (field->numElements > 1) { + // add both field(elementIndex)/setField(elemntIndex,value) and field_element properties + // field_element is more convenient if only certain element is used + // and much easier to use from the qml side propertyGetters += QString(" Q_INVOKABLE %1 get%2(quint32 index) const;\n") .arg(type).arg(field->name); @@ -153,6 +156,42 @@ bool UAVObjectGeneratorGCS::process_object(ObjectInfo *info) propertyNotifications += QString(" void %1Changed(quint32 index, %2 value);\n") .arg(field->name).arg(type); + + for (int elementIndex = 0; elementIndex < field->numElements; elementIndex++) { + QString elementName = field->elementNames[elementIndex]; + properties += QString(" Q_PROPERTY(%1 %2 READ get%2 WRITE set%2 NOTIFY %2Changed);\n") + .arg(type).arg(field->name + "_" + elementName); + propertyGetters += + QString(" Q_INVOKABLE %1 get%2_%3() const;\n") + .arg(type).arg(field->name).arg(elementName); + propertiesImpl += + QString("%1 %2::get%3_%4() const\n" + "{\n" + " QMutexLocker locker(mutex);\n" + " return data.%3[%5];\n" + "}\n") + .arg(type).arg(info->name).arg(field->name).arg(elementName).arg(elementIndex); + propertySetters += + QString(" void set%1_%2(%3 value);\n") + .arg(field->name).arg(elementName).arg(type); + propertiesImpl += + QString("void %1::set%2_%3(%4 value)\n" + "{\n" + " mutex->lock();\n" + " bool changed = data.%2[%5] != value;\n" + " data.%2[%5] = value;\n" + " mutex->unlock();\n" + " if (changed) emit %2_%3Changed(value);\n" + "}\n\n") + .arg(info->name).arg(field->name).arg(elementName).arg(type).arg(elementIndex); + propertyNotifications += + QString(" void %1_%2Changed(%3 value);\n") + .arg(field->name).arg(elementName).arg(type); + propertyNotificationsImpl += + QString(" //if (data.%1[%2] != oldData.%1[%2])\n" + " emit %1_%3Changed(data.%1[%2]);\n") + .arg(field->name).arg(elementIndex).arg(elementName); + } } else { properties += QString(" Q_PROPERTY(%1 %2 READ get%2 WRITE set%2 NOTIFY %2Changed);\n") .arg(type).arg(field->name); diff --git a/make/apps-defs.mk b/make/apps-defs.mk index 54e2e991e..b326b218d 100644 --- a/make/apps-defs.mk +++ b/make/apps-defs.mk @@ -81,6 +81,7 @@ SRC += $(PIOSCOMMON)/pios_com_msg.c SRC += $(PIOSCOMMON)/pios_crc.c SRC += $(PIOSCOMMON)/pios_flashfs_logfs.c SRC += $(PIOSCOMMON)/pios_flash_jedec.c +SRC += $(PIOSCOMMON)/pios_debuglog.c SRC += $(PIOSCOMMON)/pios_rcvr.c SRC += $(PIOSCOMMON)/pios_rfm22b.c SRC += $(PIOSCOMMON)/pios_rfm22b_com.c @@ -102,6 +103,7 @@ SRC += $(FLIGHTLIB)/sanitycheck.c SRC += $(FLIGHTLIB)/CoordinateConversions.c SRC += $(MATHLIB)/sin_lookup.c SRC += $(MATHLIB)/pid.c +SRC += $(FLIGHTLIB)/printf-stdarg.c ## Modules SRC += $(foreach mod, $(MODULES), $(sort $(wildcard $(OPMODULEDIR)/$(mod)/*.c))) diff --git a/make/tools.mk b/make/tools.mk index 806365e9b..addc6ef61 100644 --- a/make/tools.mk +++ b/make/tools.mk @@ -12,6 +12,7 @@ # mingw_install (Windows only - NOT USED for Qt-5.1.x) # python_install (Windows only - NOT USED for Qt-5.1.x) # nsis_install (Windows only) +# openssl_install (Windows only) # uncrustify_install # doxygen_install # gtest_install @@ -77,6 +78,7 @@ else ifeq ($(UNAME), Windows) ARM_SDK_URL := http://wiki.openpilot.org/download/attachments/18612236/gcc-arm-none-eabi-4_7-2013q1-20130313-windows.tar.bz2 QT_SDK_URL := http://wiki.openpilot.org/download/attachments/18612236/qt-5.1.1-windows.tar.bz2 NSIS_URL := http://wiki.openpilot.org/download/attachments/18612236/nsis-2.46-unicode.tar.bz2 + OPENSSL_URL := http://wiki.openpilot.org/download/attachments/18612236/openssl-1.0.1e-win32.tar.bz2 UNCRUSTIFY_URL := http://wiki.openpilot.org/download/attachments/18612236/uncrustify-0.60-windows.tar.bz2 DOXYGEN_URL := http://wiki.openpilot.org/download/attachments/18612236/doxygen-1.8.3.1-windows.tar.bz2 endif @@ -89,11 +91,13 @@ QT_SDK_DIR := $(TOOLS_DIR)/qt-5.1.1 MINGW_DIR := $(QT_SDK_DIR)/Tools/mingw48_32 PYTHON_DIR := $(QT_SDK_DIR)/Tools/mingw48_32/opt/bin NSIS_DIR := $(TOOLS_DIR)/nsis-2.46-unicode +OPENSSL_DIR := $(TOOLS_DIR)/openssl-1.0.1e-win32 UNCRUSTIFY_DIR := $(TOOLS_DIR)/uncrustify-0.60 DOXYGEN_DIR := $(TOOLS_DIR)/doxygen-1.8.3.1 GTEST_DIR := $(TOOLS_DIR)/gtest-1.6.0 QT_SDK_PREFIX := $(QT_SDK_DIR) + ############################## # # Build only and all toolchains available for the platform @@ -102,7 +106,7 @@ QT_SDK_PREFIX := $(QT_SDK_DIR) BUILD_SDK_TARGETS := arm_sdk qt_sdk ifeq ($(UNAME), Windows) - BUILD_SDK_TARGETS += mingw python nsis + BUILD_SDK_TARGETS += mingw python nsis openssl endif ALL_SDK_TARGETS := $(BUILD_SDK_TARGETS) gtest uncrustify doxygen @@ -223,6 +227,7 @@ endif # $(2) = string compare operator, e.g. = or != # ############################## + define MD5_CHECK_TEMPLATE "`test -f \"$(1)\" && $(OPENSSL) dgst -md5 \"$(1)\" | $(CUT) -f2 -d' '`" $(2) "`$(CUT) -f1 -d' ' < \"$(1).md5\"`" endef @@ -526,7 +531,7 @@ python_version: ############################## # -# NSIS Unicode +# NSIS Unicode (Windows only) # ############################## @@ -548,6 +553,25 @@ nsis_version: endif +############################## +# +# OpenSSL (Windows only) +# +############################## + +ifeq ($(UNAME), Windows) + +$(eval $(call TOOL_INSTALL_TEMPLATE,openssl,$(OPENSSL_DIR),$(OPENSSL_URL),$(notdir $(OPENSSL_URL)))) + +ifeq ($(shell [ -d "$(OPENSSL_DIR)" ] && $(ECHO) "exists"), exists) + export OPENSSL := $(OPENSSL_DIR) +else + # not installed, hope it's in the path... + # $(info $(EMPTY) WARNING $(call toprel, $(OPENSSL_DIR)) not found (make openssl_install), using system PATH) +endif + +endif + ############################## # # Uncrustify diff --git a/make/winx86/README.txt b/make/winx86/README.txt index 3bc070ee1..1dc0a1668 100644 --- a/make/winx86/README.txt +++ b/make/winx86/README.txt @@ -27,7 +27,7 @@ OpenPilot. ------------------ Fortunately, it requires only few small text files since all others components should already be installed on your system as parts of msysGit, QtSDK and -CodeSourcery G++ packages required to build the OpenPilot. +Arm compiler packages required to build the OpenPilot. It is expected that you have the following tools installed into the listed locations (but any other locations are fine as well): @@ -39,8 +39,8 @@ locations (but any other locations are fine as well): - Unicode NSIS in %ProgramFiles%\NSIS\Unicode - OpenOCD in C:\OpenOCD\0.4.0\bin (optional) -The SDL library and headers should be installed into Qt directories to build -the GCS. Check the wiki or ground/openpilotgcs/copydata.pro for details. +The SDL and SSL libraries and headers should be installed into Qt directories to +build the GCS. Check the wiki or ground/openpilotgcs/copydata.pro for details. Also it is assumed that you have the C:\Program Files\Git\cmd\ directory in the PATH. Usually this is the case for msysGit installation if you have chosen diff --git a/package/linux/45-openpilot-permissions.rules b/package/linux/45-openpilot-permissions.rules index 74e415c39..9015612a6 100644 --- a/package/linux/45-openpilot-permissions.rules +++ b/package/linux/45-openpilot-permissions.rules @@ -5,6 +5,15 @@ SUBSYSTEM=="usb", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="415b", MODE="0664", GROUP="plugdev" # OpenPilot OPLink Mini radio modem board SUBSYSTEM=="usb", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="415c", MODE="0664", GROUP="plugdev" + # OpenPilot Revolution board + SUBSYSTEM=="usb", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="415e", MODE="0664", GROUP="plugdev" + + # Other OpenPilot reserved pids + SUBSYSTEM=="usb", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="415d", MODE="0664", GROUP="plugdev" + SUBSYSTEM=="usb", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="4194", MODE="0664", GROUP="plugdev" + SUBSYSTEM=="usb", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="4195", MODE="0664", GROUP="plugdev" + + # unprogrammed openpilot flight control board SUBSYSTEM=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="5750", MODE="0664", GROUP="plugdev" # FTDI FT2232C Dual USB-UART/FIFO IC diff --git a/package/winx86/openpilotgcs.nsi b/package/winx86/openpilotgcs.nsi index df5d34152..c0ffdb797 100644 --- a/package/winx86/openpilotgcs.nsi +++ b/package/winx86/openpilotgcs.nsi @@ -238,7 +238,7 @@ SectionEnd ; Copy driver files Section "-Drivers" InSecDrivers SetOutPath "$INSTDIR\drivers" - File "${PROJECT_ROOT}\flight\Project\Windows USB\OpenPilot-CDC.inf" + File /r "${PROJECT_ROOT}\flight\Project\Windows USB\*" SectionEnd ; Preinstall OpenPilot CDC driver @@ -368,8 +368,8 @@ Section "un.Maps cache" UnSecCache RMDir /r /rebootok "$APPDATA\OpenPilot\mapscache" SectionEnd -Section /o "un.Configuration" UnSecConfig - ; Remove configuration +Section "un.GCS Layout" UnSecConfig + ; Remove GCS configuration files SetShellVarContext current Delete /rebootok "$APPDATA\OpenPilot\OpenPilotGCS*.db" Delete /rebootok "$APPDATA\OpenPilot\OpenPilotGCS*.xml" diff --git a/package/winx86/translations/strings_en.nsh b/package/winx86/translations/strings_en.nsh index e8aa794b0..efa553d3e 100644 --- a/package/winx86/translations/strings_en.nsh +++ b/package/winx86/translations/strings_en.nsh @@ -42,4 +42,4 @@ LangString DESC_UnSecProgram ${LANG_ENGLISH} "OpenPilot GCS application and all components." LangString DESC_UnSecCache ${LANG_ENGLISH} "OpenPilot GCS cached maps data." - LangString DESC_UnSecConfig ${LANG_ENGLISH} "OpenPilot GCS configuration files." + LangString DESC_UnSecConfig ${LANG_ENGLISH} "OpenPilot GCS layout files." diff --git a/shared/uavobjectdefinition/airspeedstate.xml b/shared/uavobjectdefinition/airspeedstate.xml index 3a7db51d9..f38473bae 100644 --- a/shared/uavobjectdefinition/airspeedstate.xml +++ b/shared/uavobjectdefinition/airspeedstate.xml @@ -6,6 +6,6 @@ - + diff --git a/shared/uavobjectdefinition/altitudeholddesired.xml b/shared/uavobjectdefinition/altitudeholddesired.xml index cf056cfa0..af2dafe94 100644 --- a/shared/uavobjectdefinition/altitudeholddesired.xml +++ b/shared/uavobjectdefinition/altitudeholddesired.xml @@ -8,6 +8,6 @@ - + diff --git a/shared/uavobjectdefinition/debuglogcontrol.xml b/shared/uavobjectdefinition/debuglogcontrol.xml new file mode 100644 index 000000000..2a4b5a84a --- /dev/null +++ b/shared/uavobjectdefinition/debuglogcontrol.xml @@ -0,0 +1,20 @@ + + + Log Control Object - Used to issue commands to the on board logging system + + + + + + + + + + diff --git a/shared/uavobjectdefinition/debuglogentry.xml b/shared/uavobjectdefinition/debuglogentry.xml new file mode 100644 index 000000000..9a9acda83 --- /dev/null +++ b/shared/uavobjectdefinition/debuglogentry.xml @@ -0,0 +1,17 @@ + + + Log Entry in Flash + + + + + + + + + + + + + + diff --git a/shared/uavobjectdefinition/debuglogsettings.xml b/shared/uavobjectdefinition/debuglogsettings.xml new file mode 100644 index 000000000..cb5fef6ed --- /dev/null +++ b/shared/uavobjectdefinition/debuglogsettings.xml @@ -0,0 +1,11 @@ + + + Configure On Board Logging Facilities + + + + + + + + diff --git a/shared/uavobjectdefinition/debuglogstatus.xml b/shared/uavobjectdefinition/debuglogstatus.xml new file mode 100644 index 000000000..0d510a332 --- /dev/null +++ b/shared/uavobjectdefinition/debuglogstatus.xml @@ -0,0 +1,13 @@ + + + Log Status Object, contains log partition status information + + + + + + + + + + diff --git a/shared/uavobjectdefinition/flighttelemetrystats.xml b/shared/uavobjectdefinition/flighttelemetrystats.xml index 352bb7de0..2e371b7de 100644 --- a/shared/uavobjectdefinition/flighttelemetrystats.xml +++ b/shared/uavobjectdefinition/flighttelemetrystats.xml @@ -10,6 +10,6 @@ - + diff --git a/shared/uavobjectdefinition/gpspositionsensor.xml b/shared/uavobjectdefinition/gpspositionsensor.xml index 8686a76ef..cfaba9db0 100644 --- a/shared/uavobjectdefinition/gpspositionsensor.xml +++ b/shared/uavobjectdefinition/gpspositionsensor.xml @@ -15,6 +15,6 @@ - + diff --git a/shared/uavobjectdefinition/gpssatellites.xml b/shared/uavobjectdefinition/gpssatellites.xml index 47c4c0f56..8d3ecb8e3 100644 --- a/shared/uavobjectdefinition/gpssatellites.xml +++ b/shared/uavobjectdefinition/gpssatellites.xml @@ -9,6 +9,6 @@ - + diff --git a/shared/uavobjectdefinition/gpstime.xml b/shared/uavobjectdefinition/gpstime.xml index ab93d4e9c..1408ba2d8 100644 --- a/shared/uavobjectdefinition/gpstime.xml +++ b/shared/uavobjectdefinition/gpstime.xml @@ -10,6 +10,6 @@ - + diff --git a/shared/uavobjectdefinition/gpsvelocitysensor.xml b/shared/uavobjectdefinition/gpsvelocitysensor.xml index c94474ca2..a9fa3ce2b 100644 --- a/shared/uavobjectdefinition/gpsvelocitysensor.xml +++ b/shared/uavobjectdefinition/gpsvelocitysensor.xml @@ -7,6 +7,6 @@ - + diff --git a/shared/uavobjectdefinition/i2cstats.xml b/shared/uavobjectdefinition/i2cstats.xml index 3e79d79ea..f5cc5318a 100644 --- a/shared/uavobjectdefinition/i2cstats.xml +++ b/shared/uavobjectdefinition/i2cstats.xml @@ -14,6 +14,6 @@ - + diff --git a/shared/uavobjectdefinition/mixerstatus.xml b/shared/uavobjectdefinition/mixerstatus.xml index c7491a92e..0c33d7f24 100644 --- a/shared/uavobjectdefinition/mixerstatus.xml +++ b/shared/uavobjectdefinition/mixerstatus.xml @@ -16,6 +16,6 @@ - + diff --git a/shared/uavobjectdefinition/oplinkstatus.xml b/shared/uavobjectdefinition/oplinkstatus.xml index a0d2fded5..bcceb3751 100644 --- a/shared/uavobjectdefinition/oplinkstatus.xml +++ b/shared/uavobjectdefinition/oplinkstatus.xml @@ -31,6 +31,6 @@ - + diff --git a/shared/uavobjectdefinition/overosyncsettings.xml b/shared/uavobjectdefinition/overosyncsettings.xml index 2d884bc1a..9c70d47bb 100644 --- a/shared/uavobjectdefinition/overosyncsettings.xml +++ b/shared/uavobjectdefinition/overosyncsettings.xml @@ -5,6 +5,6 @@ - + diff --git a/shared/uavobjectdefinition/overosyncstats.xml b/shared/uavobjectdefinition/overosyncstats.xml index de069e38c..ce87c306d 100644 --- a/shared/uavobjectdefinition/overosyncstats.xml +++ b/shared/uavobjectdefinition/overosyncstats.xml @@ -11,6 +11,6 @@ - + diff --git a/shared/uavobjectdefinition/pathaction.xml b/shared/uavobjectdefinition/pathaction.xml index 983863650..16ed7a569 100644 --- a/shared/uavobjectdefinition/pathaction.xml +++ b/shared/uavobjectdefinition/pathaction.xml @@ -25,6 +25,6 @@ - + diff --git a/shared/uavobjectdefinition/pathstatus.xml b/shared/uavobjectdefinition/pathstatus.xml index 746d15c47..52352dc4a 100644 --- a/shared/uavobjectdefinition/pathstatus.xml +++ b/shared/uavobjectdefinition/pathstatus.xml @@ -11,6 +11,6 @@ - + diff --git a/shared/uavobjectdefinition/poilocation.xml b/shared/uavobjectdefinition/poilocation.xml index 6ab6f0273..52298f017 100644 --- a/shared/uavobjectdefinition/poilocation.xml +++ b/shared/uavobjectdefinition/poilocation.xml @@ -7,6 +7,6 @@ - + diff --git a/shared/uavobjectdefinition/positionstate.xml b/shared/uavobjectdefinition/positionstate.xml index f6d689741..2a054a648 100644 --- a/shared/uavobjectdefinition/positionstate.xml +++ b/shared/uavobjectdefinition/positionstate.xml @@ -7,6 +7,6 @@ - + diff --git a/shared/uavobjectdefinition/ratedesired.xml b/shared/uavobjectdefinition/ratedesired.xml index 5d68597ee..6c297c3e5 100644 --- a/shared/uavobjectdefinition/ratedesired.xml +++ b/shared/uavobjectdefinition/ratedesired.xml @@ -7,6 +7,6 @@ - + diff --git a/shared/uavobjectdefinition/systemalarms.xml b/shared/uavobjectdefinition/systemalarms.xml index faa1cc9b1..34c353d64 100644 --- a/shared/uavobjectdefinition/systemalarms.xml +++ b/shared/uavobjectdefinition/systemalarms.xml @@ -43,6 +43,6 @@ - + diff --git a/shared/uavobjectdefinition/systemstats.xml b/shared/uavobjectdefinition/systemstats.xml index e09c817a4..4d305a471 100644 --- a/shared/uavobjectdefinition/systemstats.xml +++ b/shared/uavobjectdefinition/systemstats.xml @@ -16,6 +16,6 @@ - + diff --git a/shared/uavobjectdefinition/taskinfo.xml b/shared/uavobjectdefinition/taskinfo.xml index 1886967fc..7dc843c0a 100644 --- a/shared/uavobjectdefinition/taskinfo.xml +++ b/shared/uavobjectdefinition/taskinfo.xml @@ -113,6 +113,6 @@ - + diff --git a/shared/uavobjectdefinition/velocitydesired.xml b/shared/uavobjectdefinition/velocitydesired.xml index d20f43cb6..957c09b1a 100644 --- a/shared/uavobjectdefinition/velocitydesired.xml +++ b/shared/uavobjectdefinition/velocitydesired.xml @@ -7,6 +7,6 @@ - + diff --git a/shared/uavobjectdefinition/velocitystate.xml b/shared/uavobjectdefinition/velocitystate.xml index 90a89a4dd..9b922f6a9 100644 --- a/shared/uavobjectdefinition/velocitystate.xml +++ b/shared/uavobjectdefinition/velocitystate.xml @@ -7,6 +7,6 @@ - + diff --git a/shared/uavobjectdefinition/watchdogstatus.xml b/shared/uavobjectdefinition/watchdogstatus.xml index 2adef2c87..8bbc275e5 100644 --- a/shared/uavobjectdefinition/watchdogstatus.xml +++ b/shared/uavobjectdefinition/watchdogstatus.xml @@ -6,6 +6,6 @@ - + diff --git a/shared/uavobjectdefinition/waypoint.xml b/shared/uavobjectdefinition/waypoint.xml index 2a27f7fd5..e2c5b944a 100644 --- a/shared/uavobjectdefinition/waypoint.xml +++ b/shared/uavobjectdefinition/waypoint.xml @@ -7,6 +7,6 @@ - + diff --git a/shared/uavobjectdefinition/waypointactive.xml b/shared/uavobjectdefinition/waypointactive.xml index 3343715b5..d38b82713 100644 --- a/shared/uavobjectdefinition/waypointactive.xml +++ b/shared/uavobjectdefinition/waypointactive.xml @@ -5,6 +5,6 @@ - +