├── deploy ├── windows │ ├── resources │ │ ├── info.rc │ │ └── icon.ico │ └── nsis │ │ ├── readme.txt │ │ ├── license.txt │ │ └── setup.nsi ├── mac-osx │ ├── icon.icns │ └── info.plist └── linux │ ├── cansat-gss.png │ └── cansat-gss.desktop ├── assets ├── translations │ ├── en.qm │ ├── es.qm │ ├── translations.qrc │ ├── en.ts │ └── es.ts ├── images │ ├── background.jpg │ ├── images.qrc │ ├── kaansat.svg │ └── unaq.svg ├── fonts │ ├── source-code-pro.ttf │ └── fonts.qrc ├── icons │ ├── fullscreen.svg │ ├── fullscreen-exit.svg │ ├── icons.qrc │ ├── exit.svg │ ├── csv.svg │ ├── mexico.svg │ ├── location.svg │ └── united-states.svg └── qml │ ├── qml.qrc │ ├── Components │ ├── Terminal.qml │ ├── DataLabel.qml │ ├── GPS.qml │ └── DataGrid.qml │ ├── Modules │ └── Dashboard.qml │ ├── main.qml │ └── UI.qml ├── README.md ├── LICENSE.md ├── src ├── AppInfo.h ├── AppQuiter.h ├── crc32.h ├── Translator.h ├── Constants.h ├── Translator.cpp ├── main.cpp ├── SerialManager.h ├── crc32.c ├── DataParser.h ├── SerialManager.cpp └── DataParser.cpp └── CanSat-GSS.pro /deploy/windows/resources/info.rc: -------------------------------------------------------------------------------- 1 | IDI_ICON1 ICON DISCARDABLE "icon.ico" 2 | -------------------------------------------------------------------------------- /deploy/mac-osx/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kaan-Sat/CanSat-GSS-2019/HEAD/deploy/mac-osx/icon.icns -------------------------------------------------------------------------------- /assets/translations/en.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kaan-Sat/CanSat-GSS-2019/HEAD/assets/translations/en.qm -------------------------------------------------------------------------------- /assets/translations/es.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kaan-Sat/CanSat-GSS-2019/HEAD/assets/translations/es.qm -------------------------------------------------------------------------------- /assets/images/background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kaan-Sat/CanSat-GSS-2019/HEAD/assets/images/background.jpg -------------------------------------------------------------------------------- /deploy/linux/cansat-gss.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kaan-Sat/CanSat-GSS-2019/HEAD/deploy/linux/cansat-gss.png -------------------------------------------------------------------------------- /assets/fonts/source-code-pro.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kaan-Sat/CanSat-GSS-2019/HEAD/assets/fonts/source-code-pro.ttf -------------------------------------------------------------------------------- /deploy/windows/resources/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kaan-Sat/CanSat-GSS-2019/HEAD/deploy/windows/resources/icon.ico -------------------------------------------------------------------------------- /assets/fonts/fonts.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | source-code-pro.ttf 4 | 5 | 6 | -------------------------------------------------------------------------------- /assets/translations/translations.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | en.qm 4 | es.qm 5 | 6 | 7 | -------------------------------------------------------------------------------- /assets/images/images.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | kaansat.svg 4 | background.jpg 5 | unaq.svg 6 | 7 | 8 | -------------------------------------------------------------------------------- /assets/icons/fullscreen.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/icons/fullscreen-exit.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /deploy/linux/cansat-gss.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Name=Ka'an Sat Ground Station Software 3 | Comment=Software for receiving and managing CanSat packets 4 | Exec=cansat-gss 5 | Terminal=false 6 | Type=Application 7 | StartupNotify=true 8 | Categories=Electronics;Engineering;Science; 9 | Icon=cansat-gss 10 | -------------------------------------------------------------------------------- /assets/icons/icons.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | csv.svg 4 | location.svg 5 | exit.svg 6 | fullscreen-exit.svg 7 | fullscreen.svg 8 | mexico.svg 9 | united-states.svg 10 | 11 | 12 | -------------------------------------------------------------------------------- /assets/qml/qml.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | UI.qml 4 | main.qml 5 | Components/Terminal.qml 6 | Components/DataGrid.qml 7 | Modules/Dashboard.qml 8 | Components/DataLabel.qml 9 | Components/GPS.qml 10 | 11 | 12 | -------------------------------------------------------------------------------- /assets/icons/exit.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 13 | 14 | -------------------------------------------------------------------------------- /deploy/windows/nsis/readme.txt: -------------------------------------------------------------------------------- 1 | STEPS 2 | ----- 3 | 4 | * Assuming you have downloaded NSIS (http://nsis.sf.net) 5 | 6 | 1. Compile the application 7 | 2. Run "windeployqt" 8 | 3. Place the output files in a folder named "bin" 9 | 4. Create a new folder with the application name 10 | 5. Place the "bin" folder in the application folder 11 | 6. Place the files in the "goodies" folder in the application folder 12 | 7. Copy the script and place it one directory above the application folder 13 | 8. Copy the license.txt and place it one directory above the application folder 14 | 9. Compile the script, do not release it if you have any warning -------------------------------------------------------------------------------- /assets/icons/csv.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 13 | 16 | 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GSS-2019 2 | 3 | Software de Estación Terrena utilizado durante la competencia CanSat CUCEI 2019. El software esta desarrollado con Qt para proveer soporte multiplataforma y reducir las dependencias durante una eventual instalación. 4 | 5 | ## Compilación 6 | 7 | Para compilar el proyecto, se necesita descargar e instalar [Qt](https://qt.io/download). Una vez que se haya instalado Qt, abra el archivo `CanSat-GSS.pro` en Qt Creator, seleccione el kit apropiado y presione el botón de compilar. 8 | 9 | Alternativamente, abra una terminal (Linux/macOS) y ejecute los siguientes comandos: 10 | 11 | mkdir build 12 | cd build 13 | qmake ../ 14 | make -j4 15 | 16 | ## Autores 17 | 18 | - [Alex Spataru](https://github.com/alex-spataru) 19 | 20 | ## Licencia 21 | 22 | Este proyecto esta distribuido bajo los terminos y condiciones de la licencia MIT, para más información, haga clic [aquí](LICENSE.md). 23 | -------------------------------------------------------------------------------- /deploy/mac-osx/info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | cansat-gss 9 | CFBundleGetInfoString 10 | Copyright © 2018-2019 Ka'an Sat 11 | CFBundleIconFile 12 | icon 13 | CFBundleIdentifier 14 | org.kaansat.gss 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundleName 18 | CanSat Ground Station Software 19 | CFBundlePackageType 20 | APPL 21 | CFBundleShortVersionString 22 | 2.0 23 | LSHasLocalizedDisplayName 24 | 25 | NSPrincipalClass 26 | NSApplication 27 | NSSupportsSuddenTermination 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # License 2 | 3 | Copyright (c) 2018-2020 the Ka'an Sat Team. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /deploy/windows/nsis/license.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018 Ka'an Sat 2 | 3 | Se concede permiso, libre de cargos, a cualquier persona que obtenga una copia 4 | de este software y de los archivos de documentación asociados (el "Software"), 5 | para utilizar el Software sin restricción, incluyendo sin limitación los 6 | derechos a usar, copiar, modificar, fusionar, publicar, distribuir, 7 | sublicenciar, y/o vender copias del Software, y a permitir a las personas a las 8 | que se les proporcione el Software a hacer lo mismo, sujeto a las siguientes 9 | condiciones: 10 | 11 | El aviso de copyright anterior y este aviso de permiso se incluirán en todas 12 | las copias o partes sustanciales del Software. 13 | 14 | EL SOFTWARE SE PROPORCIONA "TAL CUAL", SIN GARANTÍA DE NINGÚN TIPO, EXPRESA O 15 | IMPLÍCITA, INCLUYENDO PERO NO LIMITADA A GARANTÍAS DE COMERCIALIZACIÓN, 16 | IDONEIDAD PARA UN PROPÓSITO PARTICULAR Y NO INFRACCIÓN. EN NINGÚN CASO LOS 17 | AUTORES O PROPIETARIOS DE LOS DERECHOS DE AUTOR SERÁN RESPONSABLES DE NINGUNA 18 | RECLAMACIÓN, DAÑOS U OTRAS RESPONSABILIDADES, YA SEA EN UNA ACCIÓN DE CONTRATO, 19 | AGRAVIO O CUALQUIER OTRO MOTIVO, DERIVADAS DE, FUERA DE O EN CONEXIÓN CON EL 20 | SOFTWARE O SU USO U OTRO TIPO DE ACCIONES EN EL SOFTWARE. 21 | -------------------------------------------------------------------------------- /src/AppInfo.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Kaan-Sat 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #ifndef APP_INFO_H 24 | #define APP_INFO_H 25 | 26 | #define APP_NAME "CanSat Ground Station Software" 27 | #define APP_VERSION "2.0 RC" 28 | #define ORGANIZATION_NAME "Ka'an Sat" 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /assets/icons/mexico.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9 | 11 | 12 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /src/AppQuiter.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Kaan-Sat 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #ifndef APPQUITER_H 24 | #define APPQUITER_H 25 | 26 | #include 27 | #include 28 | 29 | /** 30 | * Used to allow the QML app to force the application to quit (thus ignoring 31 | * the Window's attempt to block the application exit). 32 | */ 33 | class AppQuiter : public QObject { 34 | Q_OBJECT 35 | 36 | public slots: 37 | void closeApplication() { 38 | qApp->quit(); 39 | } 40 | }; 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /assets/icons/location.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 13 | 14 | -------------------------------------------------------------------------------- /assets/qml/Components/Terminal.qml: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Kaan-Sat 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | import QtQuick 2.0 24 | import QtQuick.Layouts 1.0 25 | import QtQuick.Controls 2.4 26 | import QtQuick.Controls.Universal 2.0 27 | 28 | Item { 29 | // 30 | // Text display 31 | // 32 | TextArea { 33 | id: textArea 34 | readOnly: true 35 | color: "#72d5a3" 36 | font.pixelSize: 12 37 | anchors.fill: parent 38 | font.family: app.monoFont 39 | textFormat: Text.PlainText 40 | wrapMode: Text.WrapAtWordBoundaryOrAnywhere 41 | placeholderText: qsTr("No data received so far") + "..." + Translator.dummy 42 | } 43 | 44 | // 45 | // Display serial data 46 | // 47 | Connections { 48 | target: CSerialManager 49 | } 50 | 51 | // 52 | // Mouse area to stop user from interacting with console 53 | // 54 | MouseArea { 55 | enabled: true 56 | hoverEnabled: true 57 | anchors.fill: parent 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /assets/qml/Components/DataLabel.qml: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Kaan-Sat 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | import QtQuick 2.0 24 | import QtQuick.Layouts 1.0 25 | import QtQuick.Controls 2.0 26 | 27 | RowLayout { 28 | property string title: "" 29 | property string units: "" 30 | property string dataset: "" 31 | 32 | spacing: app.spacing 33 | Layout.fillWidth: true 34 | Layout.fillHeight: true 35 | 36 | Item { 37 | Layout.fillWidth: true 38 | } 39 | 40 | Label { 41 | font.bold: true 42 | color: "#72d5a3" 43 | text: title + ":" 44 | font.pixelSize: 13 45 | Layout.fillWidth: false 46 | Layout.fillHeight: true 47 | font.family: app.monoFont 48 | horizontalAlignment: Label.AlignRight 49 | } 50 | 51 | Label { 52 | opacity: 0.85 53 | color: "#72d5a3" 54 | font.pixelSize: 13 55 | Layout.fillWidth: false 56 | Layout.fillHeight: true 57 | font.family: app.monoFont 58 | textFormat: Text.RichText 59 | horizontalAlignment: Label.AlignHCenter 60 | Layout.minimumWidth: font.pixelSize * 5 61 | text: CSerialManager.connected ? dataset + " " + units : "--.--" 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /assets/icons/united-states.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9 | 10 | 12 | 13 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /src/crc32.h: -------------------------------------------------------------------------------- 1 | /* 2 | * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or 3 | * code or tables extracted from it, as desired without restriction. 4 | * 5 | * First, the polynomial itself and its table of feedback terms. The 6 | * polynomial is 7 | * X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 8 | * 9 | * Note that we take it "backwards" and put the highest-order term in 10 | * the lowest-order bit. The X^32 term is "implied"; the LSB is the 11 | * X^31 term, etc. The X^0 term (usually shown as "+1") results in 12 | * the MSB being 1 13 | * 14 | * Note that the usual hardware shift register implementation, which 15 | * is what we're using (we're merely optimizing it by doing eight-bit 16 | * chunks at a time) shifts bits into the lowest-order term. In our 17 | * implementation, that means shifting towards the right. Why do we 18 | * do it this way? Because the calculated CRC must be transmitted in 19 | * order from highest-order term to lowest-order term. UARTs transmit 20 | * characters in order from LSB to MSB. By storing the CRC this way 21 | * we hand it to the UART in the order low-byte to high-byte; the UART 22 | * sends each low-bit to hight-bit; and the result is transmission bit 23 | * by bit from highest- to lowest-order term without requiring any bit 24 | * shuffling on our part. Reception works similarly 25 | * 26 | * The feedback terms table consists of 256, 32-bit entries. Notes 27 | * 28 | * The table can be generated at runtime if desired; code to do so 29 | * is shown later. It might not be obvious, but the feedback 30 | * terms simply represent the results of eight shift/xor opera 31 | * tions for all combinations of data and CRC register values 32 | * 33 | * The values must be right-shifted by eight bits by the "updcrc 34 | * logic; the shift must be unsigned (bring in zeroes). On some 35 | * hardware you could probably optimize the shift in assembler by 36 | * using byte-swap instructions 37 | * polynomial $edb88320 38 | * 39 | * 40 | * CRC32 code derived from work by Gary S. Brown. 41 | */ 42 | 43 | #ifndef CRC32_H 44 | #define CRC32_H 45 | 46 | #ifdef __cplusplus 47 | extern "C" { 48 | #endif 49 | 50 | #include 51 | #include 52 | #include 53 | 54 | extern uint32_t CRC32 (const void* buf, size_t size); 55 | 56 | #ifdef __cplusplus 57 | } 58 | #endif 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /src/Translator.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Alex Spataru 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #ifndef _TRANSLATOR_H 24 | #define _TRANSLATOR_H 25 | 26 | #include 27 | #include 28 | 29 | #ifdef QT_QML_LIB 30 | #include 31 | #endif 32 | 33 | class Translator : public QObject 34 | { 35 | Q_OBJECT 36 | 37 | #ifdef QT_QML_LIB 38 | Q_PROPERTY (int language 39 | READ language 40 | WRITE setLanguage 41 | NOTIFY languageChanged) 42 | Q_PROPERTY (QString dummy 43 | READ dummyString 44 | NOTIFY languageChanged) 45 | Q_PROPERTY (QStringList availableLanguages 46 | READ availableLanguages 47 | CONSTANT) 48 | #endif 49 | 50 | signals: 51 | void languageChanged(); 52 | 53 | public: 54 | explicit Translator(); 55 | 56 | int language() const; 57 | int systemLanguage() const; 58 | QStringList availableLanguages() const; 59 | 60 | QString dummyString() const 61 | { 62 | return ""; 63 | } 64 | 65 | static void DeclareQML() 66 | { 67 | #ifdef QT_QML_LIB 68 | qmlRegisterType ("Translator", 1, 0, "CTranslator"); 69 | #endif 70 | } 71 | 72 | public slots: 73 | void setLanguage (const int language); 74 | 75 | private: 76 | int m_language; 77 | QTranslator m_translator; 78 | }; 79 | 80 | #endif 81 | -------------------------------------------------------------------------------- /src/Constants.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Kaan-Sat 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #ifndef CONSTANTS_H 24 | #define CONSTANTS_H 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | #include 31 | 32 | /** 33 | * Defines what the last character of a packet generated by the 34 | * CanSAT should be. 35 | * 36 | * This is used to determine when we have received a full packet from the 37 | * CanSat. 38 | */ 39 | static const QChar EOT_PRIMARY = QChar('\n'); 40 | 41 | /** 42 | * Defines the next-to-last character of each packet. 43 | * Using two characters to separate packets gives us the following benefits: 44 | * - If we need to process more than one packet, we can do it by creating 45 | * an array of packets (using @c EOT_CHAR) 46 | * - We can detect and manage incomplete packets (using @c EOT_CHAR_SECONDARY) 47 | */ 48 | static const QChar EOT_SECONDARY = QChar('\r'); 49 | 50 | /** 51 | * Define data separator character 52 | */ 53 | static const QChar DATA_SEPARATOR = QChar(','); 54 | 55 | /** 56 | * Defines the characters that each packet generated by the CanSat should 57 | * begin with. This information is used as an additional packet 58 | * validation method. 59 | */ 60 | static const QByteArray HEADER_CODE = "KAANSATQRO"; 61 | 62 | /** 63 | * Set maximum buffer size of 10 Kilobytes 64 | */ 65 | static const int MAX_BUFFER_SIZE = 10 * 1024; 66 | 67 | /** 68 | * Packet validation options 69 | */ 70 | static const bool ENABLE_CRC32 = false; 71 | static const bool ENABLE_PACKET_CHECK = true; 72 | 73 | /** 74 | * Rounds the given @a number to two decimal places 75 | */ 76 | static inline double RoundDbl(const double n) { 77 | return floorl(n * 100.0) / 100.0; 78 | } 79 | 80 | #endif 81 | -------------------------------------------------------------------------------- /src/Translator.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Alex Spataru 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | 26 | #include "Translator.h" 27 | 28 | Translator::Translator() : m_language (0) 29 | { 30 | QSettings settings (qApp->organizationName(), qApp->applicationName()); 31 | setLanguage (settings.value ("language", systemLanguage()).toInt()); 32 | } 33 | 34 | int Translator::language() const 35 | { 36 | return m_language; 37 | } 38 | 39 | int Translator::systemLanguage() const 40 | { 41 | int lang = 0; 42 | 43 | switch (QLocale::system().language()) { 44 | case QLocale::English: 45 | lang = 0; 46 | break; 47 | case QLocale::Spanish: 48 | lang = 1; 49 | break; 50 | default: 51 | lang = 0; 52 | break; 53 | } 54 | 55 | return lang; 56 | } 57 | 58 | QStringList Translator::availableLanguages() const 59 | { 60 | return QStringList { 61 | "English", 62 | "Español" 63 | }; 64 | } 65 | 66 | void Translator::setLanguage (const int language) 67 | { 68 | /* Get translation file base name */ 69 | QString file; 70 | QLocale locale; 71 | switch (language) { 72 | case 0: 73 | file = "en"; 74 | locale = QLocale (QLocale::English); 75 | break; 76 | case 1: 77 | file = "es"; 78 | locale = QLocale (QLocale::Spanish); 79 | break; 80 | default: 81 | file = "en"; 82 | locale = QLocale (QLocale::English); 83 | break; 84 | } 85 | 86 | /* Load translation file */ 87 | qApp->removeTranslator (&m_translator); 88 | m_translator.load (locale, ":/translations/" + file + ".qm"); 89 | qApp->installTranslator (&m_translator); 90 | 91 | /* Save settings */ 92 | QSettings settings (qApp->organizationName(), qApp->applicationName()); 93 | settings.setValue ("language", language); 94 | 95 | /* Update internal variables & notify application */ 96 | m_language = language; 97 | emit languageChanged(); 98 | } 99 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Kaan-Sat 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include "AppInfo.h" 29 | #include "AppQuiter.h" 30 | #include "DataParser.h" 31 | #include "Translator.h" 32 | #include "SerialManager.h" 33 | 34 | /** 35 | * @brief Entry-point function of the application 36 | * 37 | * @param argc argument count 38 | * @param argv argument string array 39 | * 40 | * @returns the exit status of the @c qApp event loop 41 | */ 42 | int main(int argc, char** argv) { 43 | // Configure application flags 44 | QGuiApplication::setApplicationName(APP_NAME); 45 | QGuiApplication::setApplicationVersion(APP_VERSION); 46 | QGuiApplication::setOrganizationName(ORGANIZATION_NAME); 47 | QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling); 48 | 49 | // Create application controller 50 | QGuiApplication app(argc, argv); 51 | 52 | // Create application modules 53 | DataParser parser; 54 | AppQuiter appQuiter; 55 | Translator translator; 56 | QQmlApplicationEngine engine; 57 | QQuickStyle::setStyle("Universal"); 58 | 59 | // Register QML modules 60 | Translator::DeclareQML(); 61 | 62 | // Enable file logging for CSV and serial data 63 | parser.enableCsvLogging(true); 64 | SerialManager::getInstance()->enableFileLogging(true); 65 | 66 | // Configure QML engine context properties 67 | engine.rootContext()->setContextProperty("AppName", app.applicationName()); 68 | engine.rootContext()->setContextProperty("AppCompany", app.organizationName()); 69 | engine.rootContext()->setContextProperty("AppVersion", app.applicationVersion()); 70 | engine.rootContext()->setContextProperty("CDataParser", &parser); 71 | engine.rootContext()->setContextProperty("CAppQuiter", &appQuiter); 72 | engine.rootContext()->setContextProperty ("Translator", &translator); 73 | engine.rootContext()->setContextProperty("CSerialManager", SerialManager::getInstance()); 74 | engine.load(QUrl(QStringLiteral("qrc:/qml/main.qml"))); 75 | 76 | // Exit if QML interface contains errors 77 | if (engine.rootObjects().isEmpty()) 78 | return EXIT_FAILURE; 79 | 80 | // Enter application event loop 81 | return app.exec(); 82 | } 83 | -------------------------------------------------------------------------------- /src/SerialManager.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Kaan-Sat 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #ifndef SERIAL_MANAGER_H 24 | #define SERIAL_MANAGER_H 25 | 26 | #include 27 | #include 28 | 29 | class QSerialPort; 30 | class SerialManager : public QObject { 31 | Q_OBJECT 32 | Q_PROPERTY(bool connected 33 | READ connected 34 | NOTIFY connectionChanged) 35 | Q_PROPERTY(bool fileLoggingEnabled 36 | READ fileLoggingEnabled 37 | WRITE enableFileLogging 38 | NOTIFY fileLoggingEnabledChanged) 39 | Q_PROPERTY(QString receivedBytes 40 | READ receivedBytes 41 | NOTIFY packetReceived) 42 | Q_PROPERTY(QStringList serialDevices 43 | READ serialDevices 44 | NOTIFY serialDevicesChanged) 45 | Q_PROPERTY(int baudRate 46 | READ baudRate 47 | WRITE setBaudRate 48 | NOTIFY baudRateChanged) 49 | 50 | signals: 51 | void baudRateChanged(); 52 | void connectionChanged(); 53 | void serialDevicesChanged(); 54 | void fileLoggingEnabledChanged(); 55 | void packetLogged(const QString& data); 56 | void packetReceived(const QByteArray& data); 57 | void connectionError(const QString& deviceName); 58 | void connectionSuccess(const QString& deviceName); 59 | 60 | private: 61 | SerialManager(); 62 | ~SerialManager(); 63 | 64 | public: 65 | static SerialManager* getInstance(); 66 | 67 | int baudRate() const; 68 | bool connected() const; 69 | bool fileLoggingEnabled() const; 70 | 71 | QString deviceName() const; 72 | QString receivedBytes() const; 73 | QStringList serialDevices() const; 74 | 75 | public slots: 76 | void openLogFile(); 77 | void setBaudRate(const int rate); 78 | void startComm(const int device); 79 | void enableFileLogging(const bool enabled); 80 | 81 | private slots: 82 | void onDataReceived(); 83 | void disconnectDevice(); 84 | void configureLogFile(); 85 | void refreshSerialDevices(); 86 | void formatReceivedPacket(const QByteArray& data); 87 | 88 | private: 89 | bool packetLogAvailable() const; 90 | QString sizeStr(const qint64 bytes) const; 91 | 92 | private: 93 | int m_baudRate; 94 | QFile m_packetLog; 95 | qint64 m_dataLen; 96 | QByteArray m_buffer; 97 | QSerialPort* m_port; 98 | QStringList m_serialDevices; 99 | 100 | bool m_enableFileLogging; 101 | }; 102 | 103 | #endif 104 | -------------------------------------------------------------------------------- /assets/qml/Modules/Dashboard.qml: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Kaan-Sat 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | import QtQuick 2.0 24 | import QtQuick.Layouts 1.0 25 | import QtQuick.Controls 2.4 26 | import QtQuick.Controls.Universal 2.0 27 | 28 | import "../Components" 29 | 30 | Rectangle { 31 | color: "transparent" 32 | border { 33 | width: 2 34 | color: "#646464" 35 | } 36 | 37 | // 38 | // Background rectangle 39 | // 40 | Rectangle { 41 | opacity: 0.75 42 | anchors.fill: parent 43 | color: Universal.background 44 | anchors.margins: parent.border.width 45 | } 46 | 47 | // 48 | // Main layout 49 | // 50 | RowLayout { 51 | spacing: app.spacing 52 | 53 | // 54 | // Anchors 55 | // 56 | anchors { 57 | fill: parent 58 | margins: app.spacing 59 | } 60 | 61 | // 62 | // GPS Map & Terminal 63 | // 64 | ColumnLayout { 65 | Layout.fillWidth: true 66 | Layout.fillHeight: true 67 | Layout.margins: app.spacing 68 | 69 | GroupBox { 70 | Layout.margins: 0 71 | Layout.fillWidth: true 72 | Layout.fillHeight: true 73 | font.family: app.monoFont 74 | title: "// " + qsTr("GPS Map & Raw Frame Data") + Translator.dummy 75 | 76 | background: Rectangle { 77 | color: "#000" 78 | opacity: 0.75 79 | border.width: 2 80 | anchors.fill: parent 81 | anchors.topMargin: 32 82 | border.color: "#646464" 83 | } 84 | 85 | ColumnLayout { 86 | anchors.fill: parent 87 | spacing: app.spacing 88 | 89 | GPS { 90 | Layout.fillWidth: true 91 | Layout.fillHeight: true 92 | } 93 | 94 | Terminal { 95 | opacity: 0.75 96 | Layout.margins: 0 97 | Layout.fillWidth: true 98 | Layout.minimumHeight: 196 99 | } 100 | } 101 | } 102 | } 103 | 104 | // 105 | // Sensor readings 106 | // 107 | DataGrid { 108 | Layout.fillWidth: false 109 | Layout.fillHeight: true 110 | Layout.margins: app.spacing 111 | } 112 | } 113 | } 114 | 115 | -------------------------------------------------------------------------------- /CanSat-GSS.pro: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2018 Kaan-Sat 3 | # 4 | # Permission is hereby granted, free of charge, to any person obtaining a copy 5 | # of this software and associated documentation files (the "Software"), to deal 6 | # in the Software without restriction, including without limitation the rights 7 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | # copies of the Software, and to permit persons to whom the Software is 9 | # furnished to do so, subject to the following conditions: 10 | # 11 | # The above copyright notice and this permission notice shall be included in 12 | # all copies or substantial portions of the Software. 13 | # 14 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | # THE SOFTWARE. 21 | # 22 | 23 | #------------------------------------------------------------------------------- 24 | # Make options 25 | #------------------------------------------------------------------------------- 26 | 27 | UI_DIR = uic 28 | MOC_DIR = moc 29 | RCC_DIR = qrc 30 | OBJECTS_DIR = obj 31 | 32 | CONFIG += c++11 33 | 34 | #------------------------------------------------------------------------------- 35 | # Qt configuration 36 | #------------------------------------------------------------------------------- 37 | 38 | TEMPLATE = app 39 | TARGET = cansat-gss 40 | 41 | CONFIG += qtc_runnable 42 | CONFIG += resources_big 43 | 44 | QT += xml 45 | QT += svg 46 | QT += sql 47 | QT += core 48 | QT += quick 49 | QT += location 50 | QT += concurrent 51 | QT += serialport 52 | QT += positioning 53 | QT += quickcontrols2 54 | 55 | QTPLUGIN += qsvg 56 | 57 | #------------------------------------------------------------------------------- 58 | # Translations 59 | #------------------------------------------------------------------------------- 60 | 61 | TRANSLATIONS += \ 62 | assets/translations/en.ts \ 63 | assets/translations/es.ts 64 | 65 | #------------------------------------------------------------------------------- 66 | # Deploy options 67 | #------------------------------------------------------------------------------- 68 | 69 | win32* { 70 | RC_FILE = deploy/windows/resources/info.rc 71 | } 72 | 73 | macx* { 74 | ICON = deploy/mac-osx/icon.icns 75 | RC_FILE = deploy/mac-osx/icon.icns 76 | QMAKE_INFO_PLIST = deploy/mac-osx/info.plist 77 | QMAKE_POST_LINK = macdeployqt cansat-gss.app -qmldir=$$PWD/assets/qml 78 | } 79 | 80 | linux:!android { 81 | target.path = /usr/bin 82 | icon.path = /usr/share/pixmaps 83 | desktop.path = /usr/share/applications 84 | icon.files += deploy/linux/cansat-gss.png 85 | desktop.files += deploy/linux/cansat-gss.desktop 86 | 87 | INSTALLS += target desktop icon 88 | } 89 | 90 | #------------------------------------------------------------------------------- 91 | # Import source code 92 | #------------------------------------------------------------------------------- 93 | 94 | HEADERS += \ 95 | src/AppInfo.h \ 96 | src/DataParser.h \ 97 | src/SerialManager.h \ 98 | src/crc32.h \ 99 | src/Constants.h \ 100 | src/AppQuiter.h \ 101 | src/Translator.h 102 | 103 | SOURCES += \ 104 | src/DataParser.cpp \ 105 | src/main.cpp \ 106 | src/SerialManager.cpp \ 107 | src/crc32.c \ 108 | src/Translator.cpp 109 | 110 | DISTFILES += \ 111 | assets/qml/Components/ComConsole.qml \ 112 | assets/qml/Components/DataGrid.qml \ 113 | assets/qml/Components/Overview.qml \ 114 | assets/qml/Components/Terminal.qml \ 115 | assets/qml/Modules/Configuration.qml \ 116 | assets/qml/Modules/CsvData.qml \ 117 | assets/qml/Modules/Logger.qml \ 118 | assets/qml/main.qml \ 119 | assets/qml/UI.qml \ 120 | assets/qml/Modules/Dashboard.qml \ 121 | assets/qml/Modules/GpsMap.qml \ 122 | assets/qml/Components/DataLabel.qml 123 | 124 | RESOURCES += \ 125 | assets/qml/qml.qrc \ 126 | assets/images/images.qrc \ 127 | assets/icons/icons.qrc \ 128 | assets/fonts/fonts.qrc \ 129 | assets/translations/translations.qrc 130 | -------------------------------------------------------------------------------- /assets/qml/main.qml: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Kaan-Sat 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | import QtQuick 2.0 24 | import QtQuick.Window 2.0 25 | import QtQuick.Controls 2.3 26 | import QtQuick.Controls.Material 2.0 27 | import QtQuick.Controls.Universal 2.0 28 | 29 | import Qt.labs.settings 1.0 30 | 31 | ApplicationWindow { 32 | id: app 33 | 34 | // 35 | // Application constants 36 | // 37 | readonly property int spacing: 8 38 | readonly property string invalidData: "--.--" 39 | readonly property string monoFont: { 40 | if (Qt.platform.os == "osx") 41 | return "Menlo" 42 | 43 | return loader.name 44 | } 45 | 46 | // 47 | // Window options 48 | // 49 | x: 100 50 | y: 100 51 | title: AppName 52 | minimumWidth: 1222 53 | minimumHeight: 580 54 | width: minimumWidth 55 | height: minimumHeight 56 | 57 | // 58 | // Show application window 59 | // 60 | Component.onCompleted: ui.fullscreen ? app.showFullScreen() : 61 | app.showNormal() 62 | 63 | // 64 | // Save window size on exit 65 | // 66 | Settings { 67 | property alias _x: app.x 68 | property alias _y: app.y 69 | property alias _w: app.width 70 | property alias _h: app.height 71 | property alias _l: ui.language 72 | property alias _f: ui.fullscreen 73 | } 74 | 75 | // 76 | // Ask user if he/she wants to exit app 77 | // 78 | onClosing: { 79 | close.accepted = false 80 | dialog.open() 81 | } 82 | 83 | // 84 | // Theme options 85 | // 86 | Material.theme: Material.Dark 87 | Universal.theme: Universal.Dark 88 | Universal.accent: Universal.Amber 89 | 90 | // 91 | // Background 92 | // 93 | background: Image { 94 | opacity: 0.72 95 | fillMode: Image.PreserveAspectCrop 96 | source: "qrc:/images/background.jpg" 97 | } 98 | 99 | // 100 | // Mono font loader 101 | // 102 | FontLoader { 103 | id: loader 104 | source: "qrc:/fonts/source-code-pro.ttf" 105 | } 106 | 107 | // 108 | // UI module 109 | // 110 | UI { 111 | id: ui 112 | anchors.fill: parent 113 | anchors.margins: app.spacing 114 | } 115 | 116 | // 117 | // Logo UNAQ 118 | // 119 | Image { 120 | sourceSize.width: 120 121 | source: "qrc:/images/unaq.svg" 122 | 123 | anchors { 124 | top: parent.top 125 | margins: app.spacing 126 | horizontalCenter: parent.horizontalCenter 127 | } 128 | } 129 | 130 | // 131 | // Connection status dialog 132 | // 133 | Dialog { 134 | id: dialog 135 | 136 | // 137 | // Only close the dialog when the user 138 | // presses on the 'OK' button 139 | // 140 | modal: true 141 | closePolicy: Dialog.NoAutoClose 142 | standardButtons: Dialog.Yes | Dialog.No 143 | 144 | // 145 | // Close the application when user clicks on 'yes' button 146 | // 147 | onAccepted: CAppQuiter.closeApplication() 148 | 149 | // 150 | // Center dialog on app window 151 | // 152 | x: (parent.width - width) / 2 153 | y: (parent.height - height) / 2 154 | 155 | // 156 | // Set min. width to 320 pixels 157 | // 158 | width: Math.max(implicitWidth, 320) 159 | 160 | // 161 | // Message description 162 | // 163 | title: qsTr("Exit confirmation") + Translator.dummy 164 | Label { 165 | anchors.fill: parent 166 | verticalAlignment: Qt.AlignTop 167 | horizontalAlignment: Qt.AlignLeft 168 | text: qsTr("Are you sure you want to exit %1?").arg(AppName) + Translator.dummy 169 | } 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /assets/images/kaansat.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 22 | 23 | 25 | image/svg+xml 26 | 28 | 29 | 30 | 31 | 32 | 34 | 39 | 40 | -------------------------------------------------------------------------------- /assets/translations/en.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Dashboard 6 | 7 | GPS Map & Raw Frame Data 8 | 9 | 10 | 11 | 12 | DataGrid 13 | 14 | Mission Status 15 | 16 | 17 | 18 | Mission Time 19 | 20 | 21 | 22 | Team ID 23 | 24 | 25 | 26 | Parachute Status 27 | 28 | 29 | 30 | Open 31 | 32 | 33 | 34 | Closed 35 | 36 | 37 | 38 | Checksum 39 | 40 | 41 | 42 | Sensor Readings 43 | 44 | 45 | 46 | Altitude 47 | 48 | 49 | 50 | Pressure 51 | 52 | 53 | 54 | Internal Temperature 55 | 56 | 57 | 58 | External Temperature 59 | 60 | 61 | 62 | Air Quality 63 | 64 | 65 | 66 | Carbon Monoxide 67 | 68 | 69 | 70 | Accelerometer 71 | 72 | 73 | 74 | Magnetometer 75 | 76 | 77 | 78 | GPS Data 79 | 80 | 81 | 82 | Latitude 83 | 84 | 85 | 86 | Longitude 87 | 88 | 89 | 90 | Satellites 91 | 92 | 93 | 94 | GPS Time 95 | 96 | 97 | 98 | Satellite Health 99 | 100 | 101 | 102 | Voltage 103 | 104 | 105 | 106 | Resets 107 | 108 | 109 | 110 | Packet Errors 111 | 112 | 113 | 114 | Packets Parsed 115 | 116 | 117 | 118 | 119 | DataParser 120 | 121 | CSV File Error 122 | 123 | 124 | 125 | Cannot open CSV file for writing! 126 | 127 | 128 | 129 | 130 | GPS 131 | 132 | Re-center 133 | 134 | 135 | 136 | 137 | SerialManager 138 | 139 | bytes 140 | 141 | 142 | 143 | Select Port 144 | 145 | 146 | 147 | KB 148 | 149 | 150 | 151 | MB 152 | 153 | 154 | 155 | 156 | Terminal 157 | 158 | No data received so far 159 | 160 | 161 | 162 | 163 | UI 164 | 165 | Warning 166 | 167 | 168 | 169 | Disconnected from "%1" 170 | 171 | 172 | 173 | 174 | main 175 | 176 | Exit confirmation 177 | 178 | 179 | 180 | Are you sure you want to exit %1? 181 | 182 | 183 | 184 | 185 | -------------------------------------------------------------------------------- /deploy/windows/nsis/setup.nsi: -------------------------------------------------------------------------------- 1 | ; 2 | ; Copyright (c) 2017 Alex Spataru 3 | ; 4 | ; Se concede permiso, libre de cargos, a cualquier persona que obtenga una copia 5 | ; de este software y de los archivos de documentación asociados (el "Software"), 6 | ; para utilizar el Software sin restricción, incluyendo sin limitación los 7 | ; derechos a usar, copiar, modificar, fusionar, publicar, distribuir, 8 | ; sublicenciar, y/o vender copias del Software, y a permitir a las personas a 9 | ; las que se les proporcione el Software a hacer lo mismo, sujeto a las 10 | ; siguientes condiciones: 11 | ; 12 | ; El aviso de copyright anterior y este aviso de permiso se incluirán en todas 13 | ; las copias o partes sustanciales del Software. 14 | ; 15 | ; EL SOFTWARE SE PROPORCIONA "TAL CUAL", SIN GARANTÍA DE NINGÚN TIPO, EXPRESA O 16 | ; IMPLÍCITA, INCLUYENDO PERO NO LIMITADA A GARANTÍAS DE COMERCIALIZACIÓN, 17 | ; IDONEIDAD PARA UN PROPÓSITO PARTICULAR Y NO INFRACCIÓN. EN NINGÚN CASO LOS 18 | ; AUTORES O PROPIETARIOS DE LOS DERECHOS DE AUTOR SERÁN RESPONSABLES DE NINGUNA 19 | ; RECLAMACIÓN, DAÑOS U OTRAS RESPONSABILIDADES, YA SEA EN UNA ACCIÓN DE 20 | ; CONTRATO, AGRAVIO O CUALQUIER OTRO MOTIVO, DERIVADAS DE, FUERA DE O EN 21 | ; CONEXIÓN CON EL SOFTWARE O SU USO U OTRO TIPO DE ACCIONES EN EL SOFTWARE. 22 | ; 23 | 24 | !include "MUI2.nsh" 25 | !include "LogicLib.nsh" 26 | 27 | !define APPNAME "Ground Station Software" 28 | !define UNIXNAME "cansat-gss" 29 | !define COMPANYNAME "Ka'an Sat" 30 | !define DESCRIPTION "Software de la estación terrena" 31 | !define VERSIONMAJOR 0 32 | !define VERSIONMINOR 1 33 | !define VERSIONBUILD 0 34 | !define ESTIMATED_SIZE 60000 35 | !define MUI_ABORTWARNING 36 | !define INSTALL_DIR "$PROGRAMFILES\${APPNAME}" 37 | !define MUI_FINISHPAGE_RUN 38 | !define MUI_FINISHPAGE_RUN_TEXT "Run ${APPNAME}" 39 | !define MUI_FINISHPAGE_RUN_FUNCTION "RunApplication" 40 | !define MUI_FINISHPAGE_LINK "Visitar página web" 41 | !define MUI_FINISHPAGE_LINK_LOCATION "http://unaq.com.mx" 42 | !define MUI_WELCOMEPAGE_TITLE "Bienvenido/a al instalador del ${APPNAME}!" 43 | 44 | !insertmacro MUI_PAGE_WELCOME 45 | !insertmacro MUI_PAGE_LICENSE "license.txt" 46 | !insertmacro MUI_PAGE_DIRECTORY 47 | !insertmacro MUI_PAGE_INSTFILES 48 | !insertmacro MUI_PAGE_FINISH 49 | !insertmacro MUI_UNPAGE_WELCOME 50 | !insertmacro MUI_UNPAGE_CONFIRM 51 | !insertmacro MUI_UNPAGE_INSTFILES 52 | !insertmacro MUI_LANGUAGE "Spanish" 53 | 54 | !macro VerifyUserIsAdmin 55 | UserInfo::GetAccountType 56 | pop $0 57 | ${If} $0 != "admin" 58 | messageBox mb_iconstop "Se requieren derechos de administrador!" 59 | setErrorLevel 740 60 | quit 61 | ${EndIf} 62 | !macroend 63 | 64 | Name "${APPNAME}" 65 | ManifestDPIAware true 66 | InstallDir "${INSTALL_DIR}" 67 | RequestExecutionLevel admin 68 | OutFile "${UNIXNAME}-${VERSIONMAJOR}.${VERSIONMINOR}${VERSIONBUILD}-setup.exe" 69 | 70 | Function .onInit 71 | setShellVarContext all 72 | !insertmacro VerifyUserIsAdmin 73 | FunctionEnd 74 | 75 | Section "${APPNAME} (required)" SecDummy 76 | SectionIn RO 77 | SetOutPath "${INSTALL_DIR}" 78 | File /r "${APPNAME}\*" 79 | DeleteRegKey HKCU "Software\${COMPANYNAME}\${APPNAME}" 80 | DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" 81 | 82 | WriteUninstaller "${INSTALL_DIR}\uninstall.exe" 83 | WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "DisplayName" "${APPNAME}" 84 | WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "UninstallString" "${INSTALL_DIR}\uninstall.exe" 85 | WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "InstallLocation" "${INSTALL_DIR}" 86 | WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "Publisher" "${COMPANYNAME}" 87 | WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "DisplayIcon" "${INSTALL_DIR}\bin\${APPNAME}.exe" 88 | WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "DisplayVersion" ${VERSIONMAJOR}.${VERSIONMINOR}${VERSIONBUILD} 89 | WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "VersionMajor" ${VERSIONMAJOR} 90 | WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "VersionMinor" ${VERSIONMINOR} 91 | WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "NoModify" 1 92 | WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "NoRepair" 1 93 | WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" "EstimatedSize" ${ESTIMATED_SIZE} 94 | 95 | SectionEnd 96 | 97 | Section "Start Menu Shortcuts" 98 | CreateShortCut "$SMPROGRAMS\${APPNAME}.lnk" "${INSTALL_DIR}\bin\${APPNAME}.exe" "" "${INSTALL_DIR}\bin\${APPNAME}.exe" 0 99 | SectionEnd 100 | 101 | Function RunApplication 102 | ExecShell "" "${INSTALL_DIR}\bin\${APPNAME}.exe" 103 | FunctionEnd 104 | 105 | Function un.onInit 106 | SetShellVarContext all 107 | MessageBox MB_OKCANCEL|MB_ICONQUESTION "Realmente quiere desinstalar ${APPNAME}?" IDOK next 108 | Abort 109 | next: 110 | !insertmacro VerifyUserIsAdmin 111 | FunctionEnd 112 | 113 | Section "Uninstall" 114 | RMDir /r "${INSTALL_DIR}" 115 | RMDir /r "$SMPROGRAMS\${APPNAME}.lnk" 116 | DeleteRegKey HKCU "Software\${COMPANYNAME}\${APPNAME}" 117 | DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANYNAME} ${APPNAME}" 118 | SectionEnd 119 | -------------------------------------------------------------------------------- /assets/translations/es.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Dashboard 6 | 7 | GPS Map & Raw Frame Data 8 | Mapa GPS y Datos de Trama 9 | 10 | 11 | 12 | DataGrid 13 | 14 | Mission Status 15 | Estado de la Misión 16 | 17 | 18 | Mission Time 19 | Tiempo de Misión 20 | 21 | 22 | Team ID 23 | ID de Equipo 24 | 25 | 26 | Parachute Status 27 | Estatus de Paracaídas 28 | 29 | 30 | Open 31 | Abierto 32 | 33 | 34 | Closed 35 | Cerrado 36 | 37 | 38 | Checksum 39 | Código de Verificación 40 | 41 | 42 | Sensor Readings 43 | Lecturas de Sensor 44 | 45 | 46 | Altitude 47 | Altitud 48 | 49 | 50 | Pressure 51 | Presión 52 | 53 | 54 | Internal Temperature 55 | Temperatura Interna 56 | 57 | 58 | External Temperature 59 | Temperatura Externa 60 | 61 | 62 | Air Quality 63 | Calidad del Aire 64 | 65 | 66 | Carbon Monoxide 67 | Monóxido de Carbono 68 | 69 | 70 | Accelerometer 71 | Acelerómetro 72 | 73 | 74 | Magnetometer 75 | Magnetómetro 76 | 77 | 78 | GPS Data 79 | Datos GPS 80 | 81 | 82 | Latitude 83 | Latitud 84 | 85 | 86 | Longitude 87 | Longitud 88 | 89 | 90 | Satellites 91 | Satélites 92 | 93 | 94 | GPS Time 95 | Tiempo GPS 96 | 97 | 98 | Satellite Health 99 | Estado del Satélite 100 | 101 | 102 | Voltage 103 | Voltaje 104 | 105 | 106 | Resets 107 | Reinicios 108 | 109 | 110 | Packet Errors 111 | Tramas Corruptas 112 | 113 | 114 | Packets Parsed 115 | Tramas Analizadas 116 | 117 | 118 | 119 | DataParser 120 | 121 | CSV File Error 122 | Error del archivo CSV 123 | 124 | 125 | Cannot open CSV file for writing! 126 | No se puede abrir el archivo CSV para escritura! 127 | 128 | 129 | 130 | GPS 131 | 132 | Re-center 133 | Centrar 134 | 135 | 136 | 137 | SerialManager 138 | 139 | bytes 140 | 141 | 142 | 143 | Select Port 144 | Seleccionar Puerto 145 | 146 | 147 | KB 148 | 149 | 150 | 151 | MB 152 | 153 | 154 | 155 | 156 | Terminal 157 | 158 | No data received so far 159 | No se han recibido datos hasta el momento 160 | 161 | 162 | 163 | UI 164 | 165 | Warning 166 | Advertencia 167 | 168 | 169 | Disconnected from "%1" 170 | Desconectado de "%1" 171 | 172 | 173 | 174 | main 175 | 176 | Exit confirmation 177 | Confirmación de Salida 178 | 179 | 180 | Are you sure you want to exit %1? 181 | ¿Estas seguro que quieres salir de %1? 182 | 183 | 184 | 185 | -------------------------------------------------------------------------------- /src/crc32.c: -------------------------------------------------------------------------------- 1 | /* 2 | * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or 3 | * code or tables extracted from it, as desired without restriction. 4 | * 5 | * First, the polynomial itself and its table of feedback terms. The 6 | * polynomial is 7 | * X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 8 | * 9 | * Note that we take it "backwards" and put the highest-order term in 10 | * the lowest-order bit. The X^32 term is "implied"; the LSB is the 11 | * X^31 term, etc. The X^0 term (usually shown as "+1") results in 12 | * the MSB being 1 13 | * 14 | * Note that the usual hardware shift register implementation, which 15 | * is what we're using (we're merely optimizing it by doing eight-bit 16 | * chunks at a time) shifts bits into the lowest-order term. In our 17 | * implementation, that means shifting towards the right. Why do we 18 | * do it this way? Because the calculated CRC must be transmitted in 19 | * order from highest-order term to lowest-order term. UARTs transmit 20 | * characters in order from LSB to MSB. By storing the CRC this way 21 | * we hand it to the UART in the order low-byte to high-byte; the UART 22 | * sends each low-bit to hight-bit; and the result is transmission bit 23 | * by bit from highest- to lowest-order term without requiring any bit 24 | * shuffling on our part. Reception works similarly 25 | * 26 | * The feedback terms table consists of 256, 32-bit entries. Notes 27 | * 28 | * The table can be generated at runtime if desired; code to do so 29 | * is shown later. It might not be obvious, but the feedback 30 | * terms simply represent the results of eight shift/xor opera 31 | * tions for all combinations of data and CRC register values 32 | * 33 | * The values must be right-shifted by eight bits by the "updcrc 34 | * logic; the shift must be unsigned (bring in zeroes). On some 35 | * hardware you could probably optimize the shift in assembler by 36 | * using byte-swap instructions 37 | * polynomial $edb88320 38 | * 39 | * 40 | * CRC32 code derived from work by Gary S. Brown. 41 | */ 42 | 43 | #include "crc32.h" 44 | 45 | static uint32_t crc32_tab[] = { 46 | 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 47 | 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 48 | 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 49 | 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 50 | 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 51 | 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 52 | 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 53 | 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 54 | 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 55 | 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 56 | 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 57 | 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 58 | 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 59 | 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 60 | 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 61 | 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 62 | 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 63 | 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 64 | 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 65 | 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 66 | 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 67 | 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 68 | 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 69 | 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 70 | 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 71 | 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 72 | 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 73 | 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 74 | 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 75 | 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 76 | 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 77 | 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 78 | 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 79 | 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 80 | 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 81 | 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 82 | 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 83 | 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 84 | 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 85 | 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 86 | 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 87 | 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 88 | 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d 89 | }; 90 | 91 | uint32_t CRC32 (const void* buf, size_t size) 92 | { 93 | assert (buf); 94 | 95 | const uint8_t* p; 96 | uint32_t crc = 0xFFFFFFFFUL; 97 | 98 | p = buf; 99 | 100 | while (size--) 101 | crc = crc32_tab [(crc ^ *p++) & 0xFF] ^ (crc >> 8); 102 | 103 | return crc ^ 0xFFFFFFFFUL; 104 | } 105 | -------------------------------------------------------------------------------- /assets/qml/Components/GPS.qml: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Kaan-Sat 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | import QtQuick 2.0 24 | import QtLocation 5.11 25 | import QtPositioning 5.11 26 | import QtQuick.Layouts 1.0 27 | import QtQuick.Controls 2.0 28 | import QtQuick.Controls.Universal 2.0 29 | 30 | import Qt.labs.settings 1.0 31 | 32 | ColumnLayout { 33 | spacing: app.spacing 34 | Component.onCompleted: centerMap() 35 | 36 | // 37 | // Real-time GPS coordinates components 38 | // 39 | property real latitude: CDataParser.gpsLatitude 40 | property real longitude: CDataParser.gpsLongitude 41 | 42 | // 43 | // Will be true if GPS coordinates are different from (0,0) 44 | // 45 | readonly property bool gpsWorking: latitude != 0 || longitude != 0 46 | 47 | // 48 | // Location of Queretaro 49 | // 50 | readonly property var qroCoordinates: QtPositioning.coordinate(20.5846129, -100.385372) 51 | 52 | // 53 | // Used to know if we need to center the map 54 | // 55 | property var oldCoordinates: QtPositioning.coordinate(0,0) 56 | 57 | // 58 | // Real-time position 59 | // 60 | readonly property var gpsCoordinates: QtPositioning.coordinate(latitude, longitude) 61 | 62 | // 63 | // Center map when connecting with CanSat 64 | // 65 | Connections { 66 | target: CDataParser 67 | onDataParsed: { 68 | if (oldCoordinates === QtPositioning.coordinate(0,0)) { 69 | map.center = gpsCoordinates 70 | oldCoordinates = gpsCoordinates 71 | } 72 | } 73 | } Connections { 74 | target: CSerialManager 75 | onConnectionSuccess: oldCoordinates = QtPositioning.coordinate(0,0) 76 | } 77 | 78 | // 79 | // Centers the map to Queretaro if the GPS is not working, 80 | // otherwise, centers the map to the CanSat's position 81 | // 82 | function centerMap() { 83 | // GPS not responding, go to QRO 84 | if (!gpsWorking) 85 | map.center = qroCoordinates 86 | 87 | // Show GPS position 88 | else 89 | map.center = gpsCoordinates 90 | } 91 | 92 | // 93 | // Save settings between runs 94 | // 95 | Settings { 96 | property alias mapType: mapTypeSelector.currentIndex 97 | } 98 | 99 | // 100 | // Controls 101 | // 102 | RowLayout { 103 | spacing: app.spacing 104 | Layout.fillWidth: true 105 | 106 | ComboBox { 107 | id: mapTypeSelector 108 | textRole: "description" 109 | Layout.fillWidth: true 110 | Layout.preferredWidth: 340 111 | model: map.supportedMapTypes 112 | onCurrentIndexChanged: map.activeMapType = map.supportedMapTypes[currentIndex] 113 | } 114 | 115 | Button { 116 | text: qsTr("Re-center") + Translator.dummy 117 | icon.source: "qrc:/icons/location.svg" 118 | onClicked: centerMap() 119 | } 120 | } 121 | 122 | // 123 | // Map 124 | // 125 | Rectangle { 126 | Layout.fillWidth: true 127 | Layout.fillHeight: true 128 | color: Universal.background 129 | 130 | border { 131 | width: 2 132 | color: "#646464" 133 | } 134 | 135 | Map { 136 | id: map 137 | anchors.fill: parent 138 | copyrightsVisible: false 139 | color: Universal.background 140 | anchors.margins: parent.border.width 141 | zoomLevel: (map.minimumZoomLevel + map.maximumZoomLevel) / 2 142 | 143 | MapQuickItem { 144 | sourceItem: Rectangle { 145 | id: dot 146 | width: 20 147 | height: 20 148 | opacity: 0.1 149 | color: "#f00" 150 | border.width: 2 151 | radius: width / 2 152 | border.color: "#fff" 153 | 154 | Connections { 155 | target: CSerialManager 156 | onPacketReceived: { 157 | timer.restart() 158 | dot.opacity = 0.8 159 | } 160 | } 161 | 162 | Behavior on opacity { NumberAnimation { duration: 500 } } 163 | 164 | Timer { 165 | id: timer 166 | repeat: true 167 | interval: 500 168 | Component.onCompleted: start() 169 | onTriggered: dot.opacity = CSerialManager.connected ? 0.25 : 0.1 170 | } 171 | } 172 | 173 | coordinate: gpsWorking ? gpsCoordinates : qroCoordinates 174 | anchorPoint: Qt.point(sourceItem.width / 2, 175 | sourceItem.height/ 2) 176 | } 177 | 178 | plugin: Plugin { 179 | name: "mapboxgl" 180 | } 181 | } 182 | } 183 | } 184 | 185 | -------------------------------------------------------------------------------- /src/DataParser.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Kaan-Sat 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #ifndef DATA_PARSER_H 24 | #define DATA_PARSER_H 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #include "Constants.h" 35 | 36 | class DataParser : public QObject { 37 | Q_OBJECT 38 | Q_PROPERTY(int teamId 39 | READ teamId 40 | NOTIFY dataParsed) 41 | Q_PROPERTY(int packetCount 42 | READ packetCount 43 | NOTIFY dataParsed) 44 | Q_PROPERTY(quint64 missionTime 45 | READ missionTime 46 | NOTIFY dataParsed) 47 | Q_PROPERTY(double altitude 48 | READ altitude 49 | NOTIFY dataParsed) 50 | Q_PROPERTY(double voltage 51 | READ batteryVoltage 52 | NOTIFY dataParsed) 53 | Q_PROPERTY(double intTemperature 54 | READ intTemperature 55 | NOTIFY dataParsed) 56 | Q_PROPERTY(double extTemperature 57 | READ extTemperature 58 | NOTIFY dataParsed) 59 | Q_PROPERTY(double atmosphericPressure 60 | READ atmosphericPressure 61 | NOTIFY dataParsed) 62 | Q_PROPERTY(QString gpsTime 63 | READ gpsTime 64 | NOTIFY dataParsed) 65 | Q_PROPERTY(double gpsAltitude 66 | READ gpsAltitude 67 | NOTIFY dataParsed) 68 | Q_PROPERTY(double gpsLongitude 69 | READ gpsLongitude 70 | NOTIFY dataParsed) 71 | Q_PROPERTY(double gpsLatitude 72 | READ gpsLatitude 73 | NOTIFY dataParsed) 74 | Q_PROPERTY(int gpsSatelliteCount 75 | READ gpsSatelliteCount 76 | NOTIFY dataParsed) 77 | Q_PROPERTY(QVector3D magnetometer 78 | READ magnetomerData 79 | NOTIFY dataParsed) 80 | Q_PROPERTY(QVector3D accelerometer 81 | READ accelerometerData 82 | NOTIFY dataParsed) 83 | Q_PROPERTY(bool parachuteStatus 84 | READ parachuteStatus 85 | NOTIFY dataParsed) 86 | Q_PROPERTY(double airQuality 87 | READ airQuality 88 | NOTIFY dataParsed) 89 | Q_PROPERTY(double carbonMonoxide 90 | READ carbonMonoxide 91 | NOTIFY dataParsed) 92 | Q_PROPERTY(quint32 checksum 93 | READ checksum 94 | NOTIFY dataParsed) 95 | Q_PROPERTY(bool csvLoggingEnabled 96 | READ csvLoggingEnabled 97 | WRITE enableCsvLogging 98 | NOTIFY csvLoggingEnabledChanged) 99 | Q_PROPERTY(int errorCount 100 | READ errorCount 101 | NOTIFY packetError) 102 | Q_PROPERTY(int resetCount 103 | READ resetCount 104 | NOTIFY satelliteReset) 105 | Q_PROPERTY(int successCount 106 | READ successCount 107 | NOTIFY dataParsed) 108 | 109 | public: 110 | enum DataPosition { 111 | kHeader, 112 | kTeamID, 113 | kPacketCount, 114 | kAltitude, 115 | kAtmPressure, 116 | kBatteryVoltage, 117 | kIntTemperature, 118 | kExtTemperature, 119 | kAirQuality, 120 | kCarbonMonoxide, 121 | kGpsTime, 122 | kGpsLongitudeDeg, 123 | kGpsLongitudeMin, 124 | kGpsLatitudeDeg, 125 | kGpsLatitudeMin, 126 | kGpsAltitude, 127 | kGpsSatelliteCount, 128 | kAccelerometerX, 129 | kAccelerometerY, 130 | kAccelerometerZ, 131 | kMagnetometerX, 132 | kMagnetometerY, 133 | kMagnetometerZ, 134 | kMisionTime, 135 | kParachute, 136 | kChecksumCode 137 | }; 138 | Q_ENUM(DataPosition); 139 | 140 | signals: 141 | void dataParsed(); 142 | void packetError(); 143 | void satelliteReset(); 144 | void csvLoggingEnabledChanged(); 145 | 146 | public: 147 | DataParser(); 148 | ~DataParser(); 149 | 150 | int resetCount() const; 151 | int errorCount() const; 152 | int successCount() const; 153 | 154 | int teamId() const; 155 | int packetCount() const; 156 | quint64 missionTime() const; 157 | 158 | double altitude() const; 159 | double airQuality() const; 160 | double carbonMonoxide() const; 161 | double intTemperature() const; 162 | double extTemperature() const; 163 | double batteryVoltage() const; 164 | double atmosphericPressure() const; 165 | 166 | bool parachuteStatus() const; 167 | 168 | QString gpsTime() const; 169 | double gpsAltitude() const; 170 | double gpsLatitude() const; 171 | double gpsLongitude() const; 172 | int gpsSatelliteCount() const; 173 | 174 | QVector3D magnetomerData() const; 175 | QVector3D accelerometerData() const; 176 | 177 | quint32 checksum() const; 178 | bool csvLoggingEnabled() const; 179 | 180 | public slots: 181 | void resetData(); 182 | void openCsvFile(); 183 | void enableCsvLogging(const bool enabled); 184 | 185 | private slots: 186 | void saveCsvData(); 187 | void onPacketError(); 188 | void onPacketParsed(); 189 | void onSatelliteReset(); 190 | void parsePacket(const QByteArray &data); 191 | 192 | private: 193 | QFile m_csvFile; 194 | quint32 m_crc32; 195 | int m_resetCount; 196 | int m_errorCount; 197 | int m_successCount; 198 | QVector m_data; 199 | bool m_csvLoggingEnabled; 200 | }; 201 | 202 | #endif 203 | -------------------------------------------------------------------------------- /assets/qml/UI.qml: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Kaan-Sat 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | import QtQuick 2.0 24 | import QtQuick.Layouts 1.0 25 | import QtQuick.Controls 2.3 26 | import QtQuick.Controls.Universal 2.0 27 | 28 | import "Modules" 29 | 30 | ColumnLayout { 31 | id: ui 32 | spacing: app.spacing 33 | property alias language: langBt.checked 34 | property alias fullscreen: fullscreenBt.checked 35 | 36 | // 37 | // Toolbar 38 | // 39 | RowLayout { 40 | spacing: 0 41 | Layout.fillWidth: true 42 | 43 | // 44 | // Logo 45 | // 46 | ColumnLayout { 47 | spacing: app.spacing 48 | 49 | Image { 50 | opacity: 0.8 51 | sourceSize.width: 240 52 | source: "qrc:/images/kaansat.svg" 53 | Layout.alignment: Qt.AlignVCenter 54 | } 55 | 56 | Label { 57 | opacity: 0.6 58 | font.pixelSize: 10 59 | text: AppName + " v" + AppVersion 60 | } 61 | } 62 | 63 | // 64 | // Spacer 65 | // 66 | Item { 67 | Layout.fillWidth: true 68 | } 69 | 70 | // 71 | // Serial port selector 72 | // 73 | ComboBox { 74 | id: devices 75 | Layout.preferredWidth: 196 76 | model: CSerialManager.serialDevices 77 | enabled: CSerialManager.serialDevices.length > 1 78 | onCurrentIndexChanged: CSerialManager.startComm(currentIndex) 79 | } 80 | 81 | // 82 | // Spacer 83 | // 84 | Item { 85 | width: app.spacing 86 | } 87 | 88 | // 89 | // Baud rate selector 90 | // 91 | ComboBox { 92 | id: baudRate 93 | currentIndex: 3 94 | enabled: CSerialManager.serialDevices.length > 1 95 | onCurrentIndexChanged: CSerialManager.setBaudRate(model[currentIndex]) 96 | 97 | model: [ 98 | 1200, 99 | 2400, 100 | 4800, 101 | 9600, 102 | 19200, 103 | 38400, 104 | 57600, 105 | 15200, 106 | ] 107 | } 108 | 109 | // 110 | // Spacer 111 | // 112 | Item { 113 | width: 2 * app.spacing 114 | } 115 | 116 | // 117 | // Language button 118 | // 119 | MouseArea { 120 | width: 32 121 | height: 32 122 | 123 | id: langBt 124 | property bool checked: Translator.language == 1 125 | 126 | onClicked: { 127 | checked = !checked 128 | Translator.setLanguage(checked ? 1 : 0) 129 | } 130 | 131 | Image { 132 | sourceSize.width: 32 133 | anchors.centerIn: parent 134 | source: parent.checked ? "qrc:/icons/mexico.svg" : 135 | "qrc:/icons/united-states.svg" 136 | } 137 | } 138 | 139 | // 140 | // Spacer 141 | // 142 | Item { 143 | width: 2 * app.spacing 144 | } 145 | 146 | // 147 | // CSV table button 148 | // 149 | Button { 150 | background: Item {} 151 | 152 | Rectangle { 153 | width: 32 154 | height: 32 155 | radius: width / 2 156 | anchors.centerIn: parent 157 | color: Qt.rgba(35/255, 209/255, 75/255, 1) 158 | 159 | border.width: 1 160 | border.color: Qt.rgba(0, 0, 0, 0.21) 161 | } 162 | 163 | icon.source: "qrc:/icons/csv.svg" 164 | icon.color: Qt.rgba(0, 0, 0, 0.42) 165 | onClicked: CDataParser.openCsvFile() 166 | } 167 | 168 | // 169 | // Spacer 170 | // 171 | Item { 172 | width: app.spacing 173 | } 174 | 175 | // 176 | // Full screen button 177 | // 178 | Button { 179 | id: fullscreenBt 180 | background: Item {} 181 | 182 | Rectangle { 183 | width: 32 184 | height: 32 185 | radius: width / 2 186 | anchors.centerIn: parent 187 | color: Qt.rgba(229/255, 193/255, 58/255, 1) 188 | 189 | border.width: 1 190 | border.color: Qt.rgba(0, 0, 0, 0.21) 191 | } 192 | 193 | checkable: true 194 | icon.color: Qt.rgba(0, 0, 0, 0.42) 195 | onClicked: checked ? app.showFullScreen() : app.showNormal() 196 | icon.source: checked ? "qrc:/icons/fullscreen-exit.svg" : 197 | "qrc:/icons/fullscreen.svg" 198 | } 199 | 200 | // 201 | // Spacer 202 | // 203 | Item { 204 | width: app.spacing 205 | } 206 | 207 | // 208 | // Close button 209 | // 210 | Button { 211 | background: Item {} 212 | 213 | Rectangle { 214 | width: 32 215 | height: 32 216 | radius: width / 2 217 | anchors.centerIn: parent 218 | color: Qt.rgba(246/255, 82/255, 82/255, 1) 219 | 220 | border.width: 1 221 | border.color: Qt.rgba(0, 0, 0, 0.21) 222 | } 223 | 224 | onClicked: app.close() 225 | icon.source: "qrc:/icons/exit.svg" 226 | icon.color: Qt.rgba(0, 0, 0, 0.42) 227 | } 228 | } 229 | 230 | // 231 | // Dashboard 232 | // 233 | Dashboard { 234 | id: dashboard 235 | Layout.fillWidth: true 236 | Layout.fillHeight: true 237 | } 238 | 239 | // 240 | // Connection status dialog 241 | // 242 | Dialog { 243 | id: dialog 244 | 245 | // 246 | // Only close the dialog when the user 247 | // presses on the 'OK' button 248 | // 249 | modal: true 250 | standardButtons: Dialog.Ok 251 | closePolicy: Dialog.NoAutoClose 252 | 253 | // 254 | // Center dialog on app window 255 | // 256 | x: (parent.width - width) / 2 257 | y: (parent.height - height) / 2 258 | 259 | // 260 | // Set min. width to 320 pixels 261 | // 262 | width: Math.max(implicitWidth, 320) 263 | 264 | // 265 | // Used to select after the user closes 266 | // this dialog (only in the case that we could not 267 | // connect to the serial device) 268 | // 269 | property bool error: false 270 | onAccepted: { 271 | if (error) 272 | devices.currentIndex = 0 273 | } 274 | 275 | // 276 | // Message description 277 | // 278 | Label { 279 | id: description 280 | anchors.fill: parent 281 | verticalAlignment: Qt.AlignTop 282 | horizontalAlignment: Qt.AlignLeft 283 | } 284 | 285 | // 286 | // Show dialog when serial device connection status changes 287 | // 288 | Connections { 289 | target: CSerialManager 290 | 291 | onConnectionError: { 292 | dialog.error = true 293 | dialog.title = qsTr("Warning") + Translator.dummy 294 | description.text = qsTr("Disconnected from \"%1\"").arg(deviceName) + Translator.dummy 295 | dialog.open() 296 | } 297 | } 298 | } 299 | } 300 | 301 | -------------------------------------------------------------------------------- /assets/images/unaq.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /assets/qml/Components/DataGrid.qml: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Kaan-Sat 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | import QtQuick 2.0 24 | import QtQuick.Layouts 1.0 25 | import QtQuick.Controls 2.0 26 | 27 | GridLayout { 28 | id: dataGrid 29 | 30 | columns: 2 31 | rowSpacing: app.spacing * 2 32 | columnSpacing: app.spacing 33 | 34 | // 35 | // Mission status 36 | // 37 | GroupBox { 38 | font.family: app.monoFont 39 | title: "// " + qsTr("Mission Status") + Translator.dummy 40 | Layout.fillWidth: true 41 | Layout.fillHeight: true 42 | 43 | background: Rectangle { 44 | color: "#000" 45 | opacity: 0.75 46 | border.width: 2 47 | anchors.fill: parent 48 | anchors.topMargin: 32 49 | border.color: "#646464" 50 | } 51 | 52 | ColumnLayout { 53 | spacing: app.spacing 54 | anchors.centerIn: parent 55 | 56 | DataLabel { 57 | title: qsTr("Mission Time") + Translator.dummy 58 | dataset: { 59 | function pad(n) { 60 | return (n < 10) ? ("0" + n) : n; 61 | } 62 | 63 | var milliseconds = CDataParser.missionTime 64 | var seconds = (milliseconds / 1000) 65 | var minutes = (seconds / 60) % 60 66 | 67 | seconds = seconds % 60 68 | milliseconds = milliseconds % 1000 69 | 70 | seconds = Math.round(seconds) 71 | minutes = Math.round(minutes) 72 | milliseconds = Math.round(milliseconds) 73 | 74 | return pad(minutes) + ":" 75 | + pad(seconds) + "." 76 | + milliseconds.toString()[0] 77 | } 78 | } 79 | 80 | DataLabel { 81 | title: qsTr("Team ID") + Translator.dummy 82 | dataset: CDataParser.teamId 83 | } 84 | 85 | DataLabel { 86 | title: qsTr("Parachute Status") + Translator.dummy 87 | dataset: (CDataParser.parachuteStatus ? qsTr("Open") : qsTr("Closed")) + Translator.dummy 88 | } 89 | 90 | DataLabel { 91 | title: qsTr("Checksum") + Translator.dummy 92 | dataset: (CDataParser.checksum).toString(16) 93 | } 94 | } 95 | } 96 | 97 | // 98 | // Misc. sensors 99 | // 100 | GroupBox { 101 | font.family: app.monoFont 102 | title: "// " + qsTr("Sensor Readings") + Translator.dummy 103 | Layout.fillWidth: true 104 | Layout.fillHeight: true 105 | 106 | background: Rectangle { 107 | color: "#000" 108 | opacity: 0.75 109 | border.width: 2 110 | anchors.fill: parent 111 | anchors.topMargin: 32 112 | border.color: "#646464" 113 | } 114 | 115 | ColumnLayout { 116 | anchors.centerIn: parent 117 | 118 | DataLabel { 119 | units: "m" 120 | title: qsTr("Altitude") + Translator.dummy 121 | dataset: CDataParser.altitude 122 | } 123 | 124 | DataLabel { 125 | units: "KPa" 126 | title: qsTr("Pressure") + Translator.dummy 127 | dataset: CDataParser.atmosphericPressure / 1000.0 128 | } 129 | 130 | DataLabel { 131 | units: "°C" 132 | title: qsTr("Internal Temperature") + Translator.dummy 133 | dataset: CDataParser.intTemperature 134 | } 135 | 136 | DataLabel { 137 | units: "°C" 138 | title: qsTr("External Temperature") + Translator.dummy 139 | dataset: CDataParser.extTemperature 140 | } 141 | 142 | DataLabel { 143 | units: "%" 144 | title: qsTr("Air Quality") + Translator.dummy 145 | dataset: CDataParser.airQuality 146 | } 147 | 148 | DataLabel { 149 | units: "%" 150 | title: qsTr("Carbon Monoxide") + Translator.dummy 151 | dataset: CDataParser.carbonMonoxide 152 | } 153 | } 154 | } 155 | 156 | // 157 | // Accelerometer 158 | // 159 | GroupBox { 160 | font.family: app.monoFont 161 | title: "// " + qsTr("Accelerometer") + Translator.dummy 162 | Layout.fillWidth: true 163 | Layout.fillHeight: true 164 | 165 | background: Rectangle { 166 | color: "#000" 167 | opacity: 0.75 168 | border.width: 2 169 | anchors.fill: parent 170 | anchors.topMargin: 32 171 | border.color: "#646464" 172 | } 173 | 174 | ColumnLayout { 175 | spacing: app.spacing 176 | anchors.centerIn: parent 177 | 178 | DataLabel { 179 | title: "X" 180 | units: "m/s2" 181 | dataset: CDataParser.accelerometer.x 182 | } 183 | 184 | DataLabel { 185 | title: "Y" 186 | units: "m/s2" 187 | dataset: CDataParser.accelerometer.y 188 | } 189 | 190 | DataLabel { 191 | title: "Z" 192 | units: "m/s2" 193 | dataset: CDataParser.accelerometer.z 194 | } 195 | } 196 | } 197 | 198 | // 199 | // Magnetometer 200 | // 201 | GroupBox { 202 | font.family: app.monoFont 203 | title: "// " + qsTr("Magnetometer") + Translator.dummy 204 | Layout.fillWidth: true 205 | Layout.fillHeight: true 206 | 207 | background: Rectangle { 208 | color: "#000" 209 | opacity: 0.75 210 | border.width: 2 211 | anchors.fill: parent 212 | anchors.topMargin: 32 213 | border.color: "#646464" 214 | } 215 | 216 | ColumnLayout { 217 | spacing: app.spacing 218 | anchors.centerIn: parent 219 | 220 | DataLabel { 221 | title: "X" 222 | units: "μT" 223 | dataset: CDataParser.magnetometer.x 224 | } 225 | 226 | DataLabel { 227 | title: "Y" 228 | units: "μT" 229 | dataset: CDataParser.magnetometer.y 230 | } 231 | 232 | DataLabel { 233 | title: "Z" 234 | units: "μT" 235 | dataset: CDataParser.magnetometer.z 236 | } 237 | } 238 | } 239 | 240 | // 241 | // GPS 242 | // 243 | GroupBox { 244 | font.family: app.monoFont 245 | title: "// " + qsTr("GPS Data") + Translator.dummy 246 | Layout.fillWidth: true 247 | Layout.fillHeight: true 248 | 249 | background: Rectangle { 250 | color: "#000" 251 | opacity: 0.75 252 | border.width: 2 253 | anchors.fill: parent 254 | anchors.topMargin: 32 255 | border.color: "#646464" 256 | } 257 | 258 | ColumnLayout { 259 | spacing: app.spacing 260 | anchors.centerIn: parent 261 | 262 | DataLabel { 263 | units: "m" 264 | title: qsTr("Altitude") + Translator.dummy 265 | dataset: CDataParser.gpsAltitude 266 | } 267 | 268 | DataLabel { 269 | title: qsTr("Latitude") + Translator.dummy 270 | dataset: CDataParser.gpsLatitude 271 | } 272 | 273 | DataLabel { 274 | title: qsTr("Longitude") + Translator.dummy 275 | dataset: CDataParser.gpsLongitude 276 | } 277 | 278 | DataLabel { 279 | title: qsTr("Satellites") + Translator.dummy 280 | dataset: CDataParser.gpsSatelliteCount 281 | } 282 | 283 | DataLabel { 284 | title: qsTr("GPS Time") + Translator.dummy 285 | dataset: CDataParser.gpsTime 286 | } 287 | } 288 | } 289 | 290 | // 291 | // Satellite health & comm. status 292 | // 293 | GroupBox { 294 | font.family: app.monoFont 295 | title: "// " + qsTr("Satellite Health") + Translator.dummy 296 | Layout.fillWidth: true 297 | Layout.fillHeight: true 298 | 299 | background: Rectangle { 300 | color: "#000" 301 | opacity: 0.75 302 | border.width: 2 303 | anchors.fill: parent 304 | anchors.topMargin: 32 305 | border.color: "#646464" 306 | } 307 | 308 | ColumnLayout { 309 | spacing: app.spacing 310 | anchors.centerIn: parent 311 | 312 | DataLabel { 313 | units: "V" 314 | title: qsTr("Voltage") + Translator.dummy 315 | dataset: CDataParser.voltage 316 | } 317 | 318 | DataLabel { 319 | title: qsTr("Resets") + Translator.dummy 320 | dataset: CDataParser.resetCount 321 | } 322 | 323 | DataLabel { 324 | title: qsTr("Packet Errors") + Translator.dummy 325 | dataset: CDataParser.errorCount 326 | } 327 | 328 | DataLabel { 329 | title: qsTr("Packets Parsed") + Translator.dummy 330 | dataset: CDataParser.successCount 331 | } 332 | } 333 | } 334 | } 335 | 336 | -------------------------------------------------------------------------------- /src/SerialManager.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Kaan-Sat 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | #include 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #include "Constants.h" 34 | #include "SerialManager.h" 35 | 36 | /** 37 | * @brief Pointer to the only instance of this class. 38 | * 39 | * We need to use a single-instance approach so that all application modules 40 | * and classes can communicate and use the current serial device without dealing 41 | * with permission and/or race issues. 42 | */ 43 | static SerialManager* instance = Q_NULLPTR; 44 | 45 | /** 46 | * @brief Constructor for the @a SerialManager class 47 | */ 48 | SerialManager::SerialManager() : 49 | m_baudRate(9600), 50 | m_dataLen(-1), 51 | m_port(Q_NULLPTR), 52 | m_enableFileLogging(false) 53 | { 54 | connect(this, &SerialManager::packetReceived, 55 | this, &SerialManager::formatReceivedPacket); 56 | connect(this, &SerialManager::connectionChanged, 57 | this, &SerialManager::configureLogFile); 58 | 59 | QTimer::singleShot(500, this, &SerialManager::refreshSerialDevices); 60 | } 61 | 62 | /** 63 | * @brief Closes the comm. channels with the current device and closes 64 | * the current log file 65 | */ 66 | SerialManager::~SerialManager() { 67 | if (m_port != Q_NULLPTR) 68 | m_port->close(); 69 | 70 | if (m_packetLog.isOpen()) 71 | m_packetLog.close(); 72 | } 73 | 74 | /** 75 | * @returns The only instance of the @c SerialManager class, we need 76 | * to have only one instance for every application module to 77 | * interface with the same serial device without getting into 78 | * permission issues or using additional resources 79 | */ 80 | SerialManager* SerialManager::getInstance() { 81 | if (instance == Q_NULLPTR) 82 | instance = new SerialManager(); 83 | 84 | return instance; 85 | } 86 | 87 | /** 88 | * @returns the baud rate used to communicate with the serial device 89 | */ 90 | int SerialManager::baudRate() const { 91 | return m_baudRate; 92 | } 93 | 94 | /** 95 | * @returns @c true if the application is connected to any serial 96 | * device, otherwise, this function shall return @c false 97 | */ 98 | bool SerialManager::connected() const { 99 | if (m_port != Q_NULLPTR) 100 | return m_port->isOpen(); 101 | 102 | return false; 103 | } 104 | 105 | /** 106 | * @returns @c true if the class will save all inconming data in a nice HTML 107 | * formatted file with received data and timestamps 108 | */ 109 | bool SerialManager::fileLoggingEnabled() const { 110 | return m_enableFileLogging; 111 | } 112 | 113 | /** 114 | * @brief SerialManager::deviceName 115 | * @return 116 | */ 117 | QString SerialManager::deviceName() const { 118 | if (m_port) 119 | return m_port->portName(); 120 | 121 | return "Undefined"; 122 | } 123 | 124 | /** 125 | * @returns An user-friendly string that represents the number of bytes 126 | * received from the current serial device. 127 | */ 128 | QString SerialManager::receivedBytes() const { 129 | if (m_port != Q_NULLPTR && m_dataLen >= 0) 130 | return sizeStr(m_dataLen); 131 | 132 | return "0 " + tr("bytes"); 133 | } 134 | 135 | /** 136 | * @returns A list with the port names (such as COM1, COM2, ttyACMO) of the 137 | * ports that have any serial device connected to them 138 | */ 139 | QStringList SerialManager::serialDevices() const { 140 | return m_serialDevices; 141 | } 142 | 143 | void SerialManager::openLogFile() { 144 | if (packetLogAvailable()) 145 | QDesktopServices::openUrl(QUrl::fromLocalFile(m_packetLog.fileName())); 146 | } 147 | 148 | /** 149 | * Changes the baud @a rate used to communicate with the serial device 150 | */ 151 | void SerialManager::setBaudRate(const int rate) { 152 | if (rate > 0) { 153 | m_baudRate = rate; 154 | 155 | if (m_port) 156 | m_port->setBaudRate(baudRate()); 157 | 158 | emit baudRateChanged(); 159 | } 160 | } 161 | 162 | /** 163 | * @brief SerialManager::startComm 164 | * @param device 165 | */ 166 | void SerialManager::startComm(const int device) { 167 | // Disconnect current serial port device 168 | disconnectDevice(); 169 | 170 | // Ignore the