├── telemetry ├── pnpm-workspace.yaml ├── packages │ ├── ui │ │ ├── app │ │ │ ├── vite-env.d.ts │ │ │ ├── components │ │ │ │ ├── views │ │ │ │ │ ├── state-machine │ │ │ │ │ │ ├── styles.css │ │ │ │ │ │ ├── nodes │ │ │ │ │ │ │ ├── styles.ts │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ ├── neutral-node.tsx │ │ │ │ │ │ │ ├── passive-node.tsx │ │ │ │ │ │ │ ├── failure-node.tsx │ │ │ │ │ │ │ └── active-node.tsx │ │ │ │ │ │ ├── types.ts │ │ │ │ │ │ └── utils.ts │ │ │ │ │ └── openmct.tsx │ │ │ │ ├── ui │ │ │ │ │ ├── label.tsx │ │ │ │ │ ├── textarea.tsx │ │ │ │ │ ├── input.tsx │ │ │ │ │ ├── switch.tsx │ │ │ │ │ └── tooltip.tsx │ │ │ │ └── shared │ │ │ │ │ ├── logo.tsx │ │ │ │ │ └── latency-chart.tsx │ │ │ ├── types │ │ │ │ ├── mqtt.ts │ │ │ │ ├── PodConnectionStatus.ts │ │ │ │ └── MQTTConnectionStatus.ts │ │ │ ├── index.html │ │ │ ├── lib │ │ │ │ ├── utils.ts │ │ │ │ ├── logger.ts │ │ │ │ └── controls.ts │ │ │ ├── providers.tsx │ │ │ ├── main.tsx │ │ │ ├── views.tsx │ │ │ └── App.tsx │ │ ├── openmct │ │ │ ├── types │ │ │ │ ├── Unpacked.ts │ │ │ │ ├── ObjectIdentifier.ts │ │ │ │ ├── RealtimeFaultsListenerCallback.ts │ │ │ │ ├── Datum.ts │ │ │ │ ├── MeasurementReading.ts │ │ │ │ ├── RealtimeTelemetryListenerCallback.ts │ │ │ │ └── AugmentedDomainObject.ts │ │ │ ├── core │ │ │ │ ├── config.ts │ │ │ │ └── http.ts │ │ │ ├── plugins │ │ │ │ ├── faults-plugin │ │ │ │ │ ├── constants.ts │ │ │ │ │ └── historical-faults-provider.ts │ │ │ │ ├── utils │ │ │ │ │ └── convertNamespaceToPodId.ts │ │ │ │ └── data │ │ │ │ │ ├── object-types-data.ts │ │ │ │ │ └── pods-data.ts │ │ │ └── index.html │ │ ├── mqtt.d.ts │ │ ├── public │ │ │ └── images │ │ │ │ └── pod.png │ │ ├── postcss.config.cjs │ │ ├── .eslintrc.cjs │ │ ├── .env.docker │ │ ├── .env.example │ │ ├── .gitignore │ │ ├── components.json │ │ ├── tsconfig.json │ │ ├── index.html │ │ └── vite.config.ts │ ├── types │ │ ├── src │ │ │ ├── utils │ │ │ │ └── Unpacked.ts │ │ │ ├── openmct │ │ │ │ ├── openmct-object-types.types.ts │ │ │ │ ├── openmct-fault.types.ts │ │ │ │ └── openmct-dictionary.types.ts │ │ │ ├── index.ts │ │ │ ├── server │ │ │ │ └── responses.ts │ │ │ └── pods │ │ │ │ └── pods.types.ts │ │ ├── tsconfig.json │ │ ├── .eslintrc.js │ │ └── package.json │ ├── public-app │ │ ├── .env.docker │ │ ├── .env.example │ │ ├── app │ │ │ ├── favicon.ico │ │ │ ├── globals.css │ │ │ ├── providers.tsx │ │ │ ├── layout.tsx │ │ │ ├── page.tsx │ │ │ └── loading-screen.tsx │ │ ├── postcss.config.js │ │ ├── public │ │ │ ├── hyped-dark.png │ │ │ └── hyped-light.png │ │ ├── .eslintrc.json │ │ ├── next.config.js │ │ ├── tsconfig.json │ │ ├── .gitignore │ │ ├── components │ │ │ ├── theme-switch.tsx │ │ │ └── launch-time.tsx │ │ ├── package.json │ │ └── README.md │ ├── tsconfig │ │ ├── package.json │ │ └── base.json │ ├── e2e-tests │ │ ├── .gitignore │ │ ├── tsconfig.json │ │ ├── package.json │ │ └── tests │ │ │ └── example.spec.ts │ ├── eslint-config │ │ ├── README.md │ │ ├── react.js │ │ ├── package.json │ │ └── basic.js │ ├── server │ │ ├── src │ │ │ ├── modules │ │ │ │ ├── common │ │ │ │ │ ├── types │ │ │ │ │ │ └── InfluxRow.ts │ │ │ │ │ └── utils │ │ │ │ │ │ ├── toUnixTimestamp.ts │ │ │ │ │ │ └── zodEnumFromObjKeys.ts │ │ │ │ ├── influx │ │ │ │ │ ├── errors │ │ │ │ │ │ └── InfluxServiceError.ts │ │ │ │ │ └── Influx.module.ts │ │ │ │ ├── logger │ │ │ │ │ └── Logger.decorator.ts │ │ │ │ ├── mqtt │ │ │ │ │ ├── ingestion │ │ │ │ │ │ ├── errors │ │ │ │ │ │ │ └── MqttIngestionError.ts │ │ │ │ │ │ └── MqttIngestion.module.ts │ │ │ │ │ └── client │ │ │ │ │ │ └── MqttClientModule.ts │ │ │ │ ├── state │ │ │ │ │ ├── errors │ │ │ │ │ │ └── MeasurementReadingValidationError.ts │ │ │ │ │ ├── utils │ │ │ │ │ │ └── isValidState.ts │ │ │ │ │ ├── State.module.ts │ │ │ │ │ └── StateUpdate.types.ts │ │ │ │ ├── measurement │ │ │ │ │ ├── errors │ │ │ │ │ │ └── MeasurementReadingValidationError.ts │ │ │ │ │ ├── Measurement.module.ts │ │ │ │ │ └── utils │ │ │ │ │ │ └── doesMeasurementBreachLimits.ts │ │ │ │ ├── warnings │ │ │ │ │ ├── Warnings.module.ts │ │ │ │ │ ├── Warnings.controller.ts │ │ │ │ │ └── Warnings.service.ts │ │ │ │ ├── remote-logs │ │ │ │ │ ├── RemoteLogs.module.ts │ │ │ │ │ ├── RemoteLogs.controller.ts │ │ │ │ │ └── RemoteLogs.service.ts │ │ │ │ ├── controls │ │ │ │ │ ├── PodControls.module.ts │ │ │ │ │ └── PodControls.controller.ts │ │ │ │ ├── openmct │ │ │ │ │ ├── object-types │ │ │ │ │ │ ├── ObjectTypes.controller.ts │ │ │ │ │ │ └── ObjectTypes.service.ts │ │ │ │ │ ├── OpenMCT.module.ts │ │ │ │ │ ├── data │ │ │ │ │ │ ├── OpenMCTData.module.ts │ │ │ │ │ │ └── historical │ │ │ │ │ │ │ └── HistoricalTelemetryData.controller.ts │ │ │ │ │ ├── faults │ │ │ │ │ │ ├── Fault.module.ts │ │ │ │ │ │ ├── Fault.controller.ts │ │ │ │ │ │ ├── data │ │ │ │ │ │ │ └── historical │ │ │ │ │ │ │ │ └── HistoricalFaultData.controller.ts │ │ │ │ │ │ └── utils │ │ │ │ │ │ │ └── convertToOpenMctFault.ts │ │ │ │ │ └── dictionary │ │ │ │ │ │ ├── Dictionary.controller.ts │ │ │ │ │ │ └── utils │ │ │ │ │ │ └── mapMeasurementToOpenMct.ts │ │ │ │ ├── live-logs │ │ │ │ │ ├── LiveLogs.gateway.ts │ │ │ │ │ └── LiveLogsTransport.ts │ │ │ │ ├── public-data │ │ │ │ │ └── PublicData.module.ts │ │ │ │ └── core │ │ │ │ │ └── config.ts │ │ │ ├── app.service.ts │ │ │ ├── app.controller.ts │ │ │ ├── main.ts │ │ │ └── app.module.ts │ │ ├── .env.example │ │ ├── .env.docker │ │ ├── nest-cli.json │ │ ├── test │ │ │ ├── jest-e2e.json │ │ │ └── app.e2e-spec.ts │ │ ├── .eslintrc.js │ │ └── tsconfig.json │ ├── constants │ │ ├── src │ │ │ ├── socket │ │ │ │ ├── getMeasurementRoomName.ts │ │ │ │ └── index.ts │ │ │ ├── faults │ │ │ │ └── levels.ts │ │ │ ├── index.ts │ │ │ ├── pods │ │ │ │ └── modes.ts │ │ │ └── openmct │ │ │ │ └── object-types │ │ │ │ └── object-types.ts │ │ ├── .eslintrc.js │ │ ├── tsconfig.json │ │ └── package.json │ └── fake │ │ ├── .eslintrc.js │ │ ├── tsconfig.json │ │ ├── package.json │ │ └── src │ │ ├── types.ts │ │ ├── sensors │ │ ├── index.ts │ │ ├── magnetism.ts │ │ └── resistance.ts │ │ └── index.ts ├── influxdb │ └── scripts │ │ └── setup.sh ├── .prettierrc ├── entry.sh ├── mosquitto │ └── config │ │ └── mosquitto.conf ├── docker-compose.mqtt.yml ├── .gitignore ├── mqtt │ └── latency.ts ├── patches │ ├── nest-mqtt@0.2.0.patch │ └── @nestjs__common@9.4.2.patch ├── turbo.json ├── package.json └── Dockerfile ├── scripts ├── setup ├── hooks │ └── pre-commit └── format.sh ├── src ├── CMakeLists.txt ├── debugger │ ├── CMakeLists.txt │ └── main.cpp └── pod │ └── CMakeLists.txt ├── lib ├── motors │ ├── config │ │ ├── time_frequency.json │ │ └── coefficients.json │ ├── frequency_calculator.hpp │ ├── CMakeLists.txt │ ├── constant_frequency_calculator.cpp │ ├── can_processor.hpp │ ├── can_messages.hpp │ ├── constant_frequency_calculator.hpp │ ├── velocity_frequency_calculator.hpp │ ├── time_frequency_calculator.hpp │ └── pid_controller.hpp ├── navigation │ ├── CMakeLists.txt │ ├── filtering │ │ ├── CMakeLists.txt │ │ └── kalman_filter.hpp │ ├── preprocessing │ │ ├── preprocess_optical.hpp │ │ ├── CMakeLists.txt │ │ ├── preprocess_optical.cpp │ │ ├── preprocess_keyence.hpp │ │ └── preprocess_keyence.cpp │ └── control │ │ ├── CMakeLists.txt │ │ └── consts.hpp ├── utils │ ├── dummy_adc.cpp │ ├── dummy_logger.cpp │ ├── dummy_adc.hpp │ ├── dummy_logger.hpp │ ├── CMakeLists.txt │ ├── dummy_uart.cpp │ ├── dummy_mqtt.hpp │ ├── manual_time.hpp │ ├── dummy_mqtt.cpp │ ├── dummy_spi.cpp │ ├── dummy_uart.hpp │ ├── manual_time.cpp │ ├── dummy_spi.hpp │ ├── dummy_i2c.cpp │ ├── dummy_i2c.hpp │ └── dummy_gpio.cpp ├── core │ ├── wall_clock.cpp │ ├── host_information.hpp │ ├── wall_clock.hpp │ ├── CMakeLists.txt │ ├── timer.hpp │ ├── mqtt_logger.hpp │ ├── time.hpp │ ├── timer.cpp │ ├── host_information.cpp │ ├── mqtt_logger.cpp │ ├── scheduler.cpp │ ├── types.hpp │ └── scheduler.hpp ├── CMakeLists.txt ├── io │ ├── adc.hpp │ ├── CMakeLists.txt │ ├── uart.hpp │ ├── spi.hpp │ ├── gpio.hpp │ ├── hardware_adc.hpp │ └── i2c.hpp ├── sensors │ ├── CMakeLists.txt │ ├── adc_mux.hpp │ ├── optical_flow.py │ ├── keyence.hpp │ ├── keyence_node.hpp │ ├── accelerometer_node.hpp │ ├── low_power_current.cpp │ ├── low_power_current.hpp │ └── keyence.cpp ├── state_machine │ ├── CMakeLists.txt │ ├── state.hpp │ └── types.hpp └── debug │ ├── CMakeLists.txt │ ├── commands │ ├── temperature_commands.hpp │ ├── accelerometer_commands.hpp │ ├── i2c_commands.hpp │ ├── adc_commands.hpp │ ├── pwm_commands.hpp │ ├── can_commands.hpp │ ├── gpio_commands.hpp │ ├── spi_commands.hpp │ ├── uart_commands.hpp │ ├── keyence_commands.hpp │ └── command.hpp │ └── repl_logger.hpp ├── test ├── utils │ ├── dummy_adc.cpp │ ├── dummy_i2c.cpp │ ├── dummy_spi.cpp │ ├── dummy_uart.cpp │ ├── CMakeLists.txt │ └── manual_time.cpp ├── CMakeLists.txt ├── motors │ └── CMakeLists.txt ├── sensors │ ├── CMakeLists.txt │ └── i2c_mux.cpp ├── state_machine │ └── CMakeLists.txt ├── core │ ├── CMakeLists.txt │ └── libraries.cpp └── navigation │ ├── accelerometer_preprocessing.cpp │ ├── CMakeLists.txt │ └── navigation.cpp ├── tools └── pi_manager │ ├── pi_manager.service │ ├── install.sh │ └── pi_manager ├── CODEOWNERS ├── .github └── workflows │ ├── build.yml │ └── telemetry.yml ├── .clang-tidy ├── entry.sh ├── .gitignore ├── config ├── pod.toml └── debug.toml ├── cc └── Dockerfile.crosscompile └── Dockerfile /telemetry/pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - "packages/*" -------------------------------------------------------------------------------- /scripts/setup: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | git config core.hooksPath scripts/hooks/ -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(pod) 2 | add_subdirectory(debugger) 3 | -------------------------------------------------------------------------------- /telemetry/packages/ui/app/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /lib/motors/config/time_frequency.json: -------------------------------------------------------------------------------- 1 | { 2 | "times": [], 3 | "frequencies": [] 4 | } -------------------------------------------------------------------------------- /telemetry/influxdb/scripts/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | influx bucket create -n faults -------------------------------------------------------------------------------- /telemetry/packages/types/src/utils/Unpacked.ts: -------------------------------------------------------------------------------- 1 | export type Unpacked = T extends (infer U)[] ? U : T; 2 | -------------------------------------------------------------------------------- /telemetry/packages/ui/openmct/types/Unpacked.ts: -------------------------------------------------------------------------------- 1 | export type Unpacked = T extends (infer U)[] ? U : T; 2 | -------------------------------------------------------------------------------- /telemetry/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "all", 4 | "endOfLine": "lf" 5 | } 6 | -------------------------------------------------------------------------------- /lib/navigation/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(filtering) 2 | add_subdirectory(preprocessing) 3 | add_subdirectory(control) 4 | -------------------------------------------------------------------------------- /telemetry/packages/public-app/.env.docker: -------------------------------------------------------------------------------- 1 | NEXT_PUBLIC_TELEMETRY_SERVER="http://localhost:3000" 2 | NEXT_PUBLIC_POD_ID="pod_2024" -------------------------------------------------------------------------------- /telemetry/packages/public-app/.env.example: -------------------------------------------------------------------------------- 1 | NEXT_PUBLIC_TELEMETRY_SERVER="http://localhost:3000" 2 | NEXT_PUBLIC_POD_ID="pod_2024" -------------------------------------------------------------------------------- /telemetry/packages/ui/mqtt.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'mqtt/dist/mqtt' { 2 | import MQTT from 'mqtt'; 3 | export = MQTT; 4 | } 5 | -------------------------------------------------------------------------------- /telemetry/packages/tsconfig/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@hyped/tsconfig", 3 | "version": "0.0.0", 4 | "private": true 5 | } 6 | -------------------------------------------------------------------------------- /telemetry/packages/e2e-tests/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | /test-results/ 3 | /playwright-report/ 4 | /blob-report/ 5 | /playwright/.cache/ 6 | -------------------------------------------------------------------------------- /telemetry/packages/eslint-config/README.md: -------------------------------------------------------------------------------- 1 | # HYPED ESLint Config 2 | 3 | This package contains the ESLint configuration used by HYPED. 4 | -------------------------------------------------------------------------------- /telemetry/packages/public-app/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hyp-ed/hyped-2024/HEAD/telemetry/packages/public-app/app/favicon.ico -------------------------------------------------------------------------------- /telemetry/packages/ui/public/images/pod.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hyp-ed/hyped-2024/HEAD/telemetry/packages/ui/public/images/pod.png -------------------------------------------------------------------------------- /telemetry/packages/ui/openmct/types/ObjectIdentifier.ts: -------------------------------------------------------------------------------- 1 | export type ObjectIdentitifer = { 2 | namespace: string; 3 | key: string; 4 | }; 5 | -------------------------------------------------------------------------------- /telemetry/packages/ui/postcss.config.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /telemetry/packages/public-app/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /telemetry/packages/ui/openmct/types/RealtimeFaultsListenerCallback.ts: -------------------------------------------------------------------------------- 1 | export type RealtimeFaultsListenerCallback = (data: { type: string }) => void; 2 | -------------------------------------------------------------------------------- /telemetry/packages/public-app/public/hyped-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hyp-ed/hyped-2024/HEAD/telemetry/packages/public-app/public/hyped-dark.png -------------------------------------------------------------------------------- /telemetry/packages/public-app/public/hyped-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hyp-ed/hyped-2024/HEAD/telemetry/packages/public-app/public/hyped-light.png -------------------------------------------------------------------------------- /lib/motors/config/coefficients.json: -------------------------------------------------------------------------------- 1 | { 2 | "coefficients": [ 3 | 0.0, 4 | 0.0, 5 | 0.0, 6 | 0.0, 7 | 10.0 8 | ] 9 | } -------------------------------------------------------------------------------- /telemetry/packages/e2e-tests/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@hyped/tsconfig/base.json", 3 | "compilerOptions": { 4 | "jsx": "react", 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /telemetry/packages/server/src/modules/common/types/InfluxRow.ts: -------------------------------------------------------------------------------- 1 | export interface InfluxRow { 2 | _time: string; 3 | _value: string; 4 | podId: string; 5 | } 6 | -------------------------------------------------------------------------------- /telemetry/packages/server/src/modules/common/utils/toUnixTimestamp.ts: -------------------------------------------------------------------------------- 1 | export function toUnixTimestamp(date: Date) { 2 | return Math.floor(date.getTime() / 1000); 3 | } 4 | -------------------------------------------------------------------------------- /telemetry/packages/server/.env.example: -------------------------------------------------------------------------------- 1 | INFLUX_URL= 2 | INFLUX_TOKEN= 3 | INFLUX_ORG=hyped 4 | INFLUX_TELEMETRY_BUCKET=telemetry 5 | INFLUX_FAULTS_BUCKET=faults 6 | MQTT_BROKER_HOST= -------------------------------------------------------------------------------- /telemetry/packages/ui/app/components/views/state-machine/styles.css: -------------------------------------------------------------------------------- 1 | .react-flow__attribution { 2 | display: none; 3 | } 4 | 5 | .border-blue { 6 | border-color: #569fff; 7 | } -------------------------------------------------------------------------------- /telemetry/packages/ui/openmct/types/Datum.ts: -------------------------------------------------------------------------------- 1 | export type Datum = { 2 | id: string; 3 | mctLimitState: string | undefined; 4 | timestamp: number; 5 | value: number; 6 | }; 7 | -------------------------------------------------------------------------------- /telemetry/packages/ui/openmct/types/MeasurementReading.ts: -------------------------------------------------------------------------------- 1 | export type MeasurementReading = { 2 | podId: string; 3 | measurementKey: string; 4 | value: number; 5 | timestamp: number; 6 | }; 7 | -------------------------------------------------------------------------------- /telemetry/packages/server/src/app.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | 3 | @Injectable() 4 | export class AppService { 5 | getPing(): string { 6 | return 'pong'; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /telemetry/packages/ui/app/components/views/state-machine/nodes/styles.ts: -------------------------------------------------------------------------------- 1 | export const BASE_NODE_STYLES = 2 | 'w-48 flex justify-center text-center px-4 py-3 text-sm text-black rounded-md uppercase' as const; 3 | -------------------------------------------------------------------------------- /telemetry/packages/ui/openmct/types/RealtimeTelemetryListenerCallback.ts: -------------------------------------------------------------------------------- 1 | export type RealtimeTelemetryListenerCallback = (data: { 2 | id: string; 3 | value: number; 4 | timestamp: number; 5 | }) => void; 6 | -------------------------------------------------------------------------------- /telemetry/packages/server/.env.docker: -------------------------------------------------------------------------------- 1 | INFLUX_URL=http://influxdb:8086 2 | INFLUX_TOKEN=edinburgh 3 | INFLUX_ORG=hyped 4 | INFLUX_TELEMETRY_BUCKET=telemetry 5 | INFLUX_FAULTS_BUCKET=faults 6 | MQTT_BROKER_HOST=mosquitto -------------------------------------------------------------------------------- /lib/utils/dummy_adc.cpp: -------------------------------------------------------------------------------- 1 | #include "dummy_adc.hpp" 2 | 3 | namespace hyped::utils { 4 | 5 | std::optional DummyAdc::readValue() 6 | { 7 | return std::nullopt; 8 | } 9 | 10 | } // namespace hyped::utils -------------------------------------------------------------------------------- /scripts/hooks/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | FILES=$(git diff --cached --name-only | grep "*.[ch]pp$") 4 | clang-format -Werror --dry-run $FILES 5 | 6 | cmake -S . -B build 7 | cmake --build build -j 8 | ctest --test-dir build -j -------------------------------------------------------------------------------- /lib/core/wall_clock.cpp: -------------------------------------------------------------------------------- 1 | #include "wall_clock.hpp" 2 | 3 | namespace hyped::core { 4 | 5 | TimePoint WallClock::now() const 6 | { 7 | return std::chrono::system_clock::now(); 8 | } 9 | 10 | } // namespace hyped::core 11 | -------------------------------------------------------------------------------- /lib/utils/dummy_logger.cpp: -------------------------------------------------------------------------------- 1 | #include "dummy_logger.hpp" 2 | 3 | namespace hyped::utils { 4 | 5 | void DummyLogger::log(const core::LogLevel level, const char *format, ...) 6 | { 7 | } 8 | 9 | } // namespace hyped::utils 10 | -------------------------------------------------------------------------------- /telemetry/packages/constants/src/socket/getMeasurementRoomName.ts: -------------------------------------------------------------------------------- 1 | export function getMeasurementRoomName( 2 | podId: string, 3 | measurementKey: string, 4 | ): string { 5 | return `${podId}/measurement/${measurementKey}`; 6 | } 7 | -------------------------------------------------------------------------------- /telemetry/packages/ui/openmct/core/config.ts: -------------------------------------------------------------------------------- 1 | export const HTTP_DEBUG = import.meta.env.VITE_HTTP_DEBUG === 'true'; 2 | export const SERVER_ENDPOINT = import.meta.env.VITE_SERVER_ENDPOINT as string; // TODOLater: add validation to this 3 | -------------------------------------------------------------------------------- /telemetry/packages/server/nest-cli.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/nest-cli", 3 | "collection": "@nestjs/schematics", 4 | "sourceRoot": "src", 5 | "compilerOptions": { 6 | "deleteOutDir": true 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /telemetry/packages/server/src/modules/influx/errors/InfluxServiceError.ts: -------------------------------------------------------------------------------- 1 | export class InfluxServiceError extends Error { 2 | constructor(message: string) { 3 | super(message); 4 | this.name = 'InfluxServiceError'; 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /telemetry/packages/ui/openmct/plugins/faults-plugin/constants.ts: -------------------------------------------------------------------------------- 1 | export const FAULT_MANAGEMENT_DOMAIN_TYPE = 'faultManagement'; 2 | export const FAULT_MANAGEMENT_TYPES = { 3 | global: 'global-alarm-status', 4 | individual: 'alarms', 5 | }; 6 | -------------------------------------------------------------------------------- /telemetry/packages/public-app/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "extends": ["next/core-web-vitals", "@hyped/eslint-config/react.js"], 4 | "parserOptions": { 5 | "project": true, 6 | "tsconfigRootDir": "__dirname" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /telemetry/packages/server/src/modules/logger/Logger.decorator.ts: -------------------------------------------------------------------------------- 1 | import { Inject } from '@nestjs/common'; 2 | import { WINSTON_MODULE_NEST_PROVIDER } from 'nest-winston'; 3 | 4 | export const Logger = () => Inject(WINSTON_MODULE_NEST_PROVIDER); 5 | -------------------------------------------------------------------------------- /telemetry/packages/server/src/modules/mqtt/ingestion/errors/MqttIngestionError.ts: -------------------------------------------------------------------------------- 1 | export class MqttIngestionError extends Error { 2 | constructor(message: string) { 3 | super(message); 4 | this.name = 'MqttIngestionError'; 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /lib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(core) 2 | add_subdirectory(debug) 3 | add_subdirectory(io) 4 | add_subdirectory(motors) 5 | add_subdirectory(navigation) 6 | add_subdirectory(sensors) 7 | add_subdirectory(utils) 8 | add_subdirectory(state_machine) 9 | -------------------------------------------------------------------------------- /telemetry/packages/constants/src/faults/levels.ts: -------------------------------------------------------------------------------- 1 | export const FAULT_LEVEL = { 2 | WATCH: 'WATCH', 3 | WARNING: 'WARNING', 4 | CRITICAL: 'CRITICAL', 5 | } as const; 6 | 7 | export type FaultLevel = (typeof FAULT_LEVEL)[keyof typeof FAULT_LEVEL]; 8 | -------------------------------------------------------------------------------- /telemetry/packages/types/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@hyped/tsconfig/base.json", 3 | "compilerOptions": { 4 | "outDir": "./dist", 5 | "noEmit": false, 6 | }, 7 | "include": ["src"], 8 | "exclude": ["node_modules"] 9 | } 10 | -------------------------------------------------------------------------------- /telemetry/packages/types/src/openmct/openmct-object-types.types.ts: -------------------------------------------------------------------------------- 1 | export type OpenMctObjectType = { 2 | id: string; 3 | name: string; 4 | description?: string; 5 | icon: string; 6 | }; 7 | 8 | export type OpenMctObjectTypes = OpenMctObjectType[]; 9 | -------------------------------------------------------------------------------- /test/utils/dummy_adc.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace hyped::test { 6 | 7 | TEST(DummyAdc, construction) 8 | { 9 | utils::DummyAdc dummy_adc; 10 | } 11 | 12 | } // namespace hyped::test 13 | -------------------------------------------------------------------------------- /test/utils/dummy_i2c.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace hyped::test { 6 | 7 | TEST(DummyI2c, construction) 8 | { 9 | utils::DummyI2c dummy_i2c; 10 | } 11 | 12 | } // namespace hyped::test 13 | -------------------------------------------------------------------------------- /test/utils/dummy_spi.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace hyped::test { 6 | 7 | TEST(DummySpi, construction) 8 | { 9 | utils::DummySpi dummy_spi; 10 | } 11 | 12 | } // namespace hyped::test 13 | -------------------------------------------------------------------------------- /test/utils/dummy_uart.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace hyped::test { 6 | 7 | TEST(DummyUart, construction) 8 | { 9 | utils::DummyUart dummy_uart; 10 | } 11 | 12 | } // namespace hyped::test 13 | -------------------------------------------------------------------------------- /telemetry/packages/server/src/modules/state/errors/MeasurementReadingValidationError.ts: -------------------------------------------------------------------------------- 1 | export class StateUpdateValidationError extends Error { 2 | constructor(message: string) { 3 | super(message); 4 | this.name = 'StateUpdateValidationError'; 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /telemetry/packages/server/test/jest-e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "moduleFileExtensions": ["js", "json", "ts"], 3 | "rootDir": ".", 4 | "testEnvironment": "node", 5 | "testRegex": ".e2e-spec.ts$", 6 | "transform": { 7 | "^.+\\.(t|j)s$": "ts-jest" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /telemetry/packages/ui/app/components/views/state-machine/nodes/index.ts: -------------------------------------------------------------------------------- 1 | export { PassiveNode } from './passive-node'; 2 | export { FailureNode } from './failure-node'; 3 | export { ActiveNode } from './active-node'; 4 | export { NeutralNode } from './neutral-node'; 5 | -------------------------------------------------------------------------------- /lib/utils/dummy_adc.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace hyped::utils { 6 | 7 | class DummyAdc : public io::IAdc { 8 | public: 9 | std::optional readValue() override; 10 | }; 11 | 12 | } // namespace hyped::utils 13 | -------------------------------------------------------------------------------- /telemetry/packages/server/src/modules/state/utils/isValidState.ts: -------------------------------------------------------------------------------- 1 | import { ALL_POD_STATES } from '@hyped/telemetry-constants'; 2 | 3 | export const isValidState = (state: string) => { 4 | return ALL_POD_STATES[state as keyof typeof ALL_POD_STATES] !== undefined; 5 | }; 6 | -------------------------------------------------------------------------------- /telemetry/packages/fake/.eslintrc.js: -------------------------------------------------------------------------------- 1 | /** @type {import("eslint").Linter.Config} */ 2 | module.exports = { 3 | root: true, 4 | extends: ['@hyped/eslint-config/basic.js'], 5 | parserOptions: { 6 | project: true, 7 | tsconfigRootDir: __dirname, 8 | }, 9 | }; 10 | -------------------------------------------------------------------------------- /telemetry/packages/server/.eslintrc.js: -------------------------------------------------------------------------------- 1 | /** @type {import("eslint").Linter.Config} */ 2 | module.exports = { 3 | root: true, 4 | extends: ['@hyped/eslint-config/basic.js'], 5 | parserOptions: { 6 | project: true, 7 | tsconfigRootDir: __dirname, 8 | }, 9 | }; 10 | -------------------------------------------------------------------------------- /telemetry/packages/server/src/modules/influx/Influx.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { InfluxService } from './Influx.service'; 3 | 4 | @Module({ 5 | providers: [InfluxService], 6 | exports: [InfluxService], 7 | }) 8 | export class InfluxModule {} 9 | -------------------------------------------------------------------------------- /telemetry/packages/types/.eslintrc.js: -------------------------------------------------------------------------------- 1 | /** @type {import("eslint").Linter.Config} */ 2 | module.exports = { 3 | root: true, 4 | extends: ['@hyped/eslint-config/basic.js'], 5 | parserOptions: { 6 | project: true, 7 | tsconfigRootDir: __dirname, 8 | }, 9 | }; 10 | -------------------------------------------------------------------------------- /telemetry/packages/constants/.eslintrc.js: -------------------------------------------------------------------------------- 1 | /** @type {import("eslint").Linter.Config} */ 2 | module.exports = { 3 | root: true, 4 | extends: ['@hyped/eslint-config/basic.js'], 5 | parserOptions: { 6 | project: true, 7 | tsconfigRootDir: __dirname, 8 | }, 9 | }; 10 | -------------------------------------------------------------------------------- /telemetry/packages/server/src/modules/measurement/errors/MeasurementReadingValidationError.ts: -------------------------------------------------------------------------------- 1 | export class MeasurementReadingValidationError extends Error { 2 | constructor(message: string) { 3 | super(message); 4 | this.name = 'MeasurementReadingValidationError'; 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /telemetry/packages/public-app/app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | .fade-in-image { 6 | animation: fadeIn 6s; 7 | } 8 | 9 | @keyframes fadeIn { 10 | 0% { 11 | opacity: 0; 12 | } 13 | 100% { 14 | opacity: 1; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/utils/dummy_logger.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace hyped::utils { 6 | 7 | class DummyLogger : public core::ILogger { 8 | public: 9 | void log(const core::LogLevel level, const char *format...) override; 10 | }; 11 | 12 | } // namespace hyped::utils 13 | -------------------------------------------------------------------------------- /tools/pi_manager/pi_manager.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=HYPED Raspberry Pi Manager 3 | After=network.target 4 | StartLimitIntervalSec=0 5 | 6 | [Service] 7 | Type=simple 8 | Restart=always 9 | RestartSec=1 10 | User=hyped 11 | ExecStart=pi_manager 12 | 13 | [Install] 14 | WantedBy=multi-user.target -------------------------------------------------------------------------------- /telemetry/packages/ui/openmct/types/AugmentedDomainObject.ts: -------------------------------------------------------------------------------- 1 | import { Limits } from '@hyped/telemetry-types/dist/pods/pods.types'; 2 | import { DomainObject } from 'openmct/dist/src/api/objects/ObjectAPI'; 3 | 4 | export type AugmentedDomainObject = DomainObject & { 5 | podId: string; 6 | limits?: Limits; 7 | }; 8 | -------------------------------------------------------------------------------- /telemetry/entry.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e # Exit with nonzero exit code if anything fails 3 | 4 | # Use docker env files 5 | cp /usr/src/app/packages/server/.env.docker /usr/src/app/packages/server/.env 6 | 7 | cp /usr/src/app/packages/ui/.env.docker /usr/src/app/packages/ui/.env 8 | 9 | pnpm run $PNPM_SCRIPT 10 | -------------------------------------------------------------------------------- /lib/core/host_information.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace hyped::core { 7 | class HostInformation { 8 | public: 9 | static std::optional getName(); 10 | static std::optional getIp(); 11 | }; 12 | 13 | } // namespace hyped::core 14 | -------------------------------------------------------------------------------- /lib/motors/frequency_calculator.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | namespace hyped::motors { 8 | 9 | class IFrequencyCalculator { 10 | public: 11 | virtual std::uint32_t calculateFrequency(core::Float velocity) = 0; 12 | }; 13 | 14 | } // namespace hyped::motors -------------------------------------------------------------------------------- /telemetry/packages/ui/app/components/views/openmct.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * OpenMCT view. Creates the `iframe` for loading the OpenMCT dashboard. 3 | */ 4 | export const OpenMCT = () => ( 5 | 10 | ); 11 | -------------------------------------------------------------------------------- /telemetry/packages/ui/openmct/plugins/utils/convertNamespaceToPodId.ts: -------------------------------------------------------------------------------- 1 | export function convertNamespaceToPodId(namespace: string) { 2 | const possiblePodId = namespace.split('.')[1]; 3 | 4 | if (!possiblePodId) { 5 | throw new Error(`Invalid namespace: ${namespace}`); 6 | } 7 | 8 | return possiblePodId; 9 | } 10 | -------------------------------------------------------------------------------- /telemetry/packages/ui/app/types/mqtt.ts: -------------------------------------------------------------------------------- 1 | export type QoS = 0 | 1 | 2; 2 | 3 | export type MqttPublish = ( 4 | topic: string, 5 | payload: string, 6 | podId: string, 7 | ) => void; 8 | export type MqttSubscribe = (topic: string, podId: string) => void; 9 | export type MqttUnsubscribe = (topic: string, podId: string) => void; 10 | -------------------------------------------------------------------------------- /telemetry/packages/constants/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@hyped/tsconfig/base.json", 3 | "compilerOptions": { 4 | "outDir": "./dist", 5 | "lib": ["esnext"], 6 | "importHelpers": true, 7 | "sourceMap": true, 8 | "rootDir": "./src" 9 | }, 10 | "include": ["src"], 11 | "exclude": ["node_modules"] 12 | } 13 | -------------------------------------------------------------------------------- /telemetry/packages/ui/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | /** @type {import("eslint").Linter.Config} */ 2 | module.exports = { 3 | root: true, 4 | extends: ['@hyped/eslint-config/react.js'], 5 | parserOptions: { 6 | project: true, 7 | tsconfigRootDir: __dirname, 8 | }, 9 | ignorePatterns: ['vite.config.ts', 'app/components/ui/**'], 10 | }; 11 | -------------------------------------------------------------------------------- /telemetry/packages/ui/app/types/PodConnectionStatus.ts: -------------------------------------------------------------------------------- 1 | export const POD_CONNECTION_STATUS = { 2 | CONNECTED: 'CONNECTED', 3 | DISCONNECTED: 'DISCONNECTED', 4 | ERROR: 'ERROR', 5 | UNKNOWN: 'UNKNOWN', 6 | } as const; 7 | 8 | export type PodConnectionStatusType = 9 | (typeof POD_CONNECTION_STATUS)[keyof typeof POD_CONNECTION_STATUS]; 10 | -------------------------------------------------------------------------------- /telemetry/mosquitto/config/mosquitto.conf: -------------------------------------------------------------------------------- 1 | # mqtt protocol 2 | listener 1883 3 | protocol mqtt 4 | 5 | # websockets protocol (for GUI) 6 | listener 8080 7 | protocol websockets 8 | 9 | allow_anonymous true 10 | 11 | # persistence & logs 12 | persistence true 13 | persistence_location /mosquitto/data/ 14 | log_dest file /mosquitto/log/mosquitto.log -------------------------------------------------------------------------------- /test/utils/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(target hyped_test_utils) 2 | file(GLOB code "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp") 3 | add_executable(${target} ${code}) 4 | target_include_directories( 5 | ${target} PRIVATE "${CMAKE_SOURCE_DIR}/lib" "${CMAKE_CURRENT_SOURCE_DIR}" 6 | ) 7 | target_link_libraries(${target} GTest::gtest_main hyped_utils) 8 | gtest_discover_tests(${target}) 9 | -------------------------------------------------------------------------------- /telemetry/packages/ui/.env.docker: -------------------------------------------------------------------------------- 1 | VITE_SERVER_ENDPOINT=http://localhost:3000 2 | VITE_MQTT_BROKER=ws://localhost:8080 3 | VITE_MQTT_QOS=0 # one of 0, 1, 2 4 | HOST='0.0.0.0' 5 | 6 | # Optional 7 | VITE_DISABLE_POD_DISCONNECTED_ERROR=true # default: false 8 | VITE_HTTP_DEBUG=false # default: true 9 | VITE_EXTENDED_DEBUGGING_TOOLS=true # default: false 10 | -------------------------------------------------------------------------------- /lib/io/adc.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | namespace hyped::io { 8 | 9 | class IAdc { 10 | public: 11 | /** 12 | * @brief reads AIN value 13 | * @return a voltage value from 0 to 1.8V 14 | */ 15 | virtual std::optional readValue() = 0; 16 | }; 17 | 18 | } // namespace hyped::io 19 | -------------------------------------------------------------------------------- /telemetry/packages/server/src/modules/state/State.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { StateService } from './State.service'; 3 | import { InfluxModule } from '../influx/Influx.module'; 4 | 5 | @Module({ 6 | imports: [InfluxModule], 7 | providers: [StateService], 8 | exports: [StateService], 9 | }) 10 | export class StateModule {} 11 | -------------------------------------------------------------------------------- /telemetry/packages/server/src/modules/warnings/Warnings.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { WarningsController } from './Warnings.controller'; 3 | import { WarningsService } from './Warnings.service'; 4 | 5 | @Module({ 6 | controllers: [WarningsController], 7 | providers: [WarningsService], 8 | }) 9 | export class WarningsModule {} 10 | -------------------------------------------------------------------------------- /telemetry/packages/server/src/app.controller.ts: -------------------------------------------------------------------------------- 1 | import { Controller, Get } from '@nestjs/common'; 2 | import { AppService } from './app.service'; 3 | 4 | @Controller() 5 | export class AppController { 6 | constructor(private readonly appService: AppService) {} 7 | 8 | @Get('ping') 9 | getPing(): string { 10 | return this.appService.getPing(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /telemetry/packages/ui/.env.example: -------------------------------------------------------------------------------- 1 | VITE_SERVER_ENDPOINT=http://localhost:3000 2 | VITE_MQTT_BROKER=ws://localhost:8080 3 | VITE_MQTT_QOS=0 # one of 0, 1, 2 4 | HOST= # for docker 5 | 6 | # Optional 7 | VITE_DISABLE_POD_DISCONNECTED_ERROR=false # default: false 8 | VITE_HTTP_DEBUG=true # default: true 9 | VITE_EXTENDED_DEBUGGING_TOOLS=false # default: false 10 | -------------------------------------------------------------------------------- /lib/core/wall_clock.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "time.hpp" 4 | 5 | namespace hyped::core { 6 | 7 | /** 8 | * @brief Wrapper around std::chrono::high_resultion_clock in order to work with 9 | * the ITimeSource interface. 10 | */ 11 | class WallClock : public ITimeSource { 12 | public: 13 | TimePoint now() const override; 14 | }; 15 | 16 | } // namespace hyped::core 17 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @TomLonergan03 2 | lib/sensors @licornes-fluos 3 | test/sensors @licornes-fluos 4 | lib/io @licornes-fluos 5 | test/io @licornes-fluos 6 | lib/navigation @misha7b 7 | test/navigation @misha7b 8 | telemetry @davidbeechey 9 | lib/motors @lsalhani 10 | test/motors @lsalhani 11 | lib/io/*can* @lsalhani 12 | lib/state_machine @DylanCavers 13 | test/state_machine @DylanCavers 14 | -------------------------------------------------------------------------------- /lib/core/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(target hyped_core) 2 | file(GLOB headers "${CMAKE_CURRENT_SOURCE_DIR}/*.hpp") 3 | file(GLOB code "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp") 4 | add_library(${target} STATIC ${headers} ${code}) 5 | target_include_directories( 6 | ${target} INTERFACE "${CMAKE_SOURCE_DIR}/lib" ${rapidjson_SOURCE_DIR}/include 7 | ) 8 | target_link_libraries(${target} PahoMqttCpp::paho-mqttpp3) 9 | -------------------------------------------------------------------------------- /lib/io/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(target hyped_io) 2 | file(GLOB headers "${CMAKE_CURRENT_SOURCE_DIR}/*.hpp") 3 | file(GLOB code "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp") 4 | add_library(${target} STATIC ${headers} ${code}) 5 | include_directories( 6 | ${target} 7 | INTERFACE 8 | "${CMAKE_SOURCE_DIR}/lib" 9 | "${CMAKE_CURRENT_SOURCE_DIR}" 10 | ) 11 | target_link_libraries(${target} gpiodcxx) 12 | -------------------------------------------------------------------------------- /telemetry/packages/server/src/modules/remote-logs/RemoteLogs.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { RemoteLogsController } from './RemoteLogs.controller'; 3 | import { RemoteLogsService } from './RemoteLogs.service'; 4 | 5 | @Module({ 6 | controllers: [RemoteLogsController], 7 | providers: [RemoteLogsService], 8 | }) 9 | export class RemoteLogsModule {} 10 | -------------------------------------------------------------------------------- /telemetry/packages/server/src/modules/controls/PodControls.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { PodControlsController } from './PodControls.controller'; 3 | import { PodControlsService } from './PodControls.service'; 4 | 5 | @Module({ 6 | controllers: [PodControlsController], 7 | providers: [PodControlsService], 8 | }) 9 | export class PodControlsModule {} 10 | -------------------------------------------------------------------------------- /telemetry/packages/ui/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /lib/utils/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(target hyped_utils) 2 | file(GLOB headers "${CMAKE_CURRENT_SOURCE_DIR}/*.hpp") 3 | file(GLOB code "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp") 4 | add_library(${target} STATIC ${headers} ${code}) 5 | include_directories( 6 | ${target} 7 | INTERFACE 8 | "${CMAKE_SOURCE_DIR}/lib" 9 | "${CMAKE_CURRENT_SOURCE_DIR}" 10 | ) 11 | target_link_libraries(${target} hyped_core) 12 | -------------------------------------------------------------------------------- /lib/utils/dummy_uart.cpp: -------------------------------------------------------------------------------- 1 | #include "dummy_uart.hpp" 2 | 3 | namespace hyped::utils { 4 | 5 | core::Result DummyUart::sendBytes(const char *tx, const std::uint8_t length) 6 | { 7 | return core::Result::kFailure; 8 | } 9 | 10 | core::Result DummyUart::readBytes(unsigned char *rx, const std::uint8_t length) 11 | { 12 | return core::Result::kFailure; 13 | } 14 | 15 | } // namespace hyped::utils -------------------------------------------------------------------------------- /telemetry/packages/fake/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@hyped/tsconfig/base.json", 3 | "compilerOptions": { 4 | "outDir": "./dist", 5 | "lib": ["esnext"], 6 | "importHelpers": true, 7 | "sourceMap": true, 8 | "rootDir": "./src", 9 | "strictPropertyInitialization": false, 10 | }, 11 | "include": ["src", "src/config.ts"], 12 | "exclude": ["node_modules"], 13 | } 14 | -------------------------------------------------------------------------------- /telemetry/packages/ui/app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | HYPED24 | Telemetry 7 | 8 | 9 |
10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: push 4 | 5 | jobs: 6 | build: 7 | name: Build and lint 8 | runs-on: [ubuntu-latest] 9 | 10 | steps: 11 | - uses: actions/checkout@v2 12 | 13 | # Setup Docker Buildx 14 | - name: Setup Docker Buildx 15 | uses: docker/setup-buildx-action@v3 16 | 17 | - name: Run build 18 | run: ./docker.sh -r -c -b -l 19 | -------------------------------------------------------------------------------- /telemetry/packages/public-app/app/providers.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import { QueryClient, QueryClientProvider } from 'react-query'; 4 | 5 | // Create a client 6 | const queryClient = new QueryClient(); 7 | 8 | export default function Providers({ children }: { children: React.ReactNode }) { 9 | return ( 10 | {children} 11 | ); 12 | } 13 | -------------------------------------------------------------------------------- /telemetry/packages/ui/app/types/MQTTConnectionStatus.ts: -------------------------------------------------------------------------------- 1 | export const MQTT_CONNECTION_STATUS = { 2 | CONNECTED: 'CONNECTED', 3 | DISCONNECTED: 'DISCONNECTED', 4 | CONNECTING: 'CONNECTING', 5 | ERROR: 'ERROR', 6 | RECONNECTING: 'RECONNECTING', 7 | UNKNOWN: 'UNKNOWN', 8 | } as const; 9 | 10 | export type MQTTConnectionStatusType = 11 | (typeof MQTT_CONNECTION_STATUS)[keyof typeof MQTT_CONNECTION_STATUS]; 12 | -------------------------------------------------------------------------------- /lib/motors/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(target hyped_motors) 2 | file(GLOB headers "${CMAKE_CURRENT_SOURCE_DIR}/*.hpp") 3 | file(GLOB code "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp") 4 | add_library(${target} STATIC ${headers} ${code}) 5 | include_directories( 6 | ${target} 7 | INTERFACE 8 | "${CMAKE_SOURCE_DIR}/lib" 9 | "${CMAKE_CURRENT_SOURCE_DIR}" 10 | ) 11 | target_include_directories(${target} PUBLIC ${rapidjson_SOURCE_DIR}/include) 12 | -------------------------------------------------------------------------------- /lib/sensors/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(target hyped_sensors) 2 | file(GLOB headers "${CMAKE_CURRENT_SOURCE_DIR}/*.hpp") 3 | file(GLOB code "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp") 4 | add_library(${target} STATIC ${headers} ${code}) 5 | include_directories( 6 | ${target} 7 | INTERFACE 8 | "${CMAKE_SOURCE_DIR}/lib" 9 | "${CMAKE_CURRENT_SOURCE_DIR}" 10 | ) 11 | target_link_libraries(${target} PUBLIC tomlplusplus::tomlplusplus hyped_io) 12 | -------------------------------------------------------------------------------- /telemetry/packages/server/src/modules/mqtt/client/MqttClientModule.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { MqttModule } from 'nest-mqtt'; 3 | import { MQTT_BROKER_HOST } from 'src/modules/core/config'; 4 | 5 | const mqttClient = MqttModule.forRoot({ 6 | host: MQTT_BROKER_HOST, 7 | }); 8 | 9 | @Module({ 10 | imports: [mqttClient], 11 | exports: [mqttClient], 12 | }) 13 | export class MqttClientModule {} 14 | -------------------------------------------------------------------------------- /lib/navigation/filtering/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(target hyped_navigation_filters) 2 | file(GLOB headers "${CMAKE_CURRENT_SOURCE_DIR}/*.hpp") 3 | file(GLOB code "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp") 4 | add_library(${target} STATIC ${headers} ${code}) 5 | include_directories( 6 | ${target} 7 | INTERFACE 8 | "${CMAKE_SOURCE_DIR}/lib" 9 | "${CMAKE_CURRENT_SOURCE_DIR}" 10 | ) 11 | target_link_libraries(${target} PUBLIC Eigen3::Eigen) 12 | -------------------------------------------------------------------------------- /lib/navigation/preprocessing/preprocess_optical.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace hyped::navigation { 8 | 9 | class OpticalPreprocessor { 10 | public: 11 | static std::optional> processData( 12 | const core::OpticalData raw_optical_data); 13 | }; 14 | 15 | } // namespace hyped::navigation 16 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include(FetchContent) 2 | FetchContent_Declare( 3 | googletest GIT_REPOSITORY https://github.com/google/googletest.git 4 | GIT_TAG release-1.12.1 5 | ) 6 | FetchContent_MakeAvailable(googletest) 7 | include(GoogleTest) 8 | 9 | add_subdirectory(utils) 10 | add_subdirectory(navigation) 11 | add_subdirectory(core) 12 | add_subdirectory(sensors) 13 | add_subdirectory(state_machine) 14 | add_subdirectory(motors) 15 | -------------------------------------------------------------------------------- /test/motors/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(target hyped_test_motors) 2 | file(GLOB code "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp") 3 | add_executable(${target} ${code}) 4 | target_include_directories( 5 | ${target} PRIVATE "${CMAKE_SOURCE_DIR}/lib" "${CMAKE_CURRENT_SOURCE_DIR}" 6 | ) 7 | target_link_libraries( 8 | ${target} 9 | GTest::gtest_main 10 | hyped_motors 11 | hyped_utils 12 | hyped_core 13 | ) 14 | gtest_discover_tests(${target}) 15 | -------------------------------------------------------------------------------- /test/sensors/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(target hyped_test_sensors) 2 | file(GLOB code "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp") 3 | add_executable(${target} ${code}) 4 | target_include_directories( 5 | ${target} PRIVATE "${CMAKE_SOURCE_DIR}/lib" "${CMAKE_CURRENT_SOURCE_DIR}" 6 | ) 7 | target_link_libraries( 8 | ${target} 9 | GTest::gtest_main 10 | hyped_sensors 11 | hyped_utils 12 | hyped_core 13 | ) 14 | gtest_discover_tests(${target}) 15 | -------------------------------------------------------------------------------- /test/state_machine/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(target hyped_test_statemachine) 2 | file(GLOB code "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp") 3 | add_executable(${target} ${code}) 4 | target_include_directories( 5 | ${target} PRIVATE "${CMAKE_SOURCE_DIR}/lib" "${CMAKE_CURRENT_SOURCE_DIR}" 6 | ) 7 | target_link_libraries( 8 | ${target} 9 | GTest::gtest_main 10 | hyped_statemachine 11 | hyped_utils 12 | ) 13 | gtest_discover_tests(${target}) 14 | -------------------------------------------------------------------------------- /lib/state_machine/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(target hyped_statemachine) 2 | file(GLOB headers "${CMAKE_CURRENT_SOURCE_DIR}/*.hpp") 3 | file(GLOB code "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp") 4 | add_library(${target} STATIC ${headers} ${code}) 5 | include_directories( 6 | ${target} 7 | INTERFACE 8 | "${CMAKE_SOURCE_DIR}/lib" 9 | "${CMAKE_CURRENT_SOURCE_DIR}" 10 | ) 11 | target_link_libraries(${target} Boost::boost tomlplusplus::tomlplusplus) 12 | -------------------------------------------------------------------------------- /lib/navigation/preprocessing/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(target hyped_navigation_preprocessing) 2 | file(GLOB headers "${CMAKE_CURRENT_SOURCE_DIR}/*.hpp") 3 | file(GLOB code "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp") 4 | add_library(${target} STATIC ${headers} ${code}) 5 | include_directories( 6 | ${target} 7 | INTERFACE 8 | "${CMAKE_SOURCE_DIR}/lib" 9 | "${CMAKE_CURRENT_SOURCE_DIR}" 10 | ) 11 | target_link_libraries(${target} PUBLIC Eigen3::Eigen) 12 | -------------------------------------------------------------------------------- /telemetry/packages/public-app/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | webpack: (config, context) => { 4 | // Enable polling based on env variable being set 5 | if (true) { 6 | config.watchOptions = { 7 | poll: 500, 8 | aggregateTimeout: 300, 9 | }; 10 | } 11 | return config; 12 | }, 13 | }; 14 | 15 | module.exports = nextConfig; 16 | // next.config.js 17 | -------------------------------------------------------------------------------- /telemetry/packages/ui/components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "default", 4 | "rsc": false, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "tailwind.config.cjs", 8 | "css": "app/globals.css", 9 | "baseColor": "slate", 10 | "cssVariables": true, 11 | "prefix": "" 12 | }, 13 | "aliases": { 14 | "components": "@/components", 15 | "utils": "@/lib/utils" 16 | } 17 | } -------------------------------------------------------------------------------- /test/core/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(target hyped_test_core) 2 | file(GLOB code "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp") 3 | add_executable(${target} ${code}) 4 | target_include_directories( 5 | ${target} PRIVATE "${CMAKE_SOURCE_DIR}/lib" "${CMAKE_CURRENT_SOURCE_DIR}" 6 | ) 7 | target_link_libraries( 8 | ${target} 9 | GTest::gtest_main 10 | hyped_core 11 | hyped_utils 12 | Eigen3::Eigen 13 | Boost::boost 14 | ) 15 | gtest_discover_tests(${target}) 16 | -------------------------------------------------------------------------------- /.clang-tidy: -------------------------------------------------------------------------------- 1 | Checks: "clang-analyzer-*, clang-diagnostic-*, google-*, modernize-*, performance-*, readability-*, -modernize-use-trailing-return-type, -readability-magic-numbers, -google-readability-todo, -readability-avoid-const-params-in-decls, -readability-identifier-length, -modernize-use-nodiscard, -modernize-use-std-numbers" 2 | WarningsAsErrors: "clang-analyzer-*, clang-diagnostic-*, google-*, modernize-*, performance-*, readability-*" 3 | UseColor: true 4 | 5 | -------------------------------------------------------------------------------- /src/debugger/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(target hyped_debugger) 2 | file(GLOB headers "${CMAKE_CURRENT_SOURCE_DIR}/*.hpp") 3 | file(GLOB code "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp") 4 | add_executable(${target} ${headers} ${code}) 5 | target_include_directories( 6 | ${target} INTERFACE "${CMAKE_SOURCE_DIR}/lib" "${CMAKE_CURRENT_SOURCE_DIR}" 7 | ) 8 | target_link_libraries( 9 | ${target} 10 | hyped_core 11 | hyped_io 12 | hyped_utils 13 | hyped_debug 14 | ) 15 | -------------------------------------------------------------------------------- /telemetry/packages/ui/openmct/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | OpenMCT 5 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /test/navigation/accelerometer_preprocessing.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace hyped::test { 9 | 10 | // TODOLater: Revert this file to commit hash 2764a99cca274496995ce6b866c7f61f75ea20b6 as soon as we 11 | // go back to 4 accelerometers 12 | 13 | } // namespace hyped::test 14 | -------------------------------------------------------------------------------- /entry.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eu 4 | 5 | echo "Building..." 6 | 7 | # Fix for git 8 | git config --global --add safe.directory '*' 9 | 10 | cd $DIR 11 | 12 | if [[ -d "build" && $CLEAN = true ]]; then 13 | rm -r build 14 | mkdir build 15 | elif [ ! -d "build" ]; then 16 | mkdir build 17 | fi 18 | 19 | cd build 20 | if [[ $LINT = true ]]; then 21 | cmake .. -DLINT=ON 22 | else 23 | cmake .. 24 | fi 25 | 26 | make -j$(nproc) 27 | make test 28 | -------------------------------------------------------------------------------- /telemetry/docker-compose.mqtt.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | mosquitto: 5 | container_name: mosquitto 6 | image: eclipse-mosquitto:2.0.18 7 | ports: 8 | - 1883:1883 9 | - 8080:8080 10 | volumes: 11 | - ./mosquitto/config:/mosquitto/config 12 | - ./mosquitto/data:/mosquitto/data 13 | - ./mosquitto/log:/mosquitto/log 14 | restart: always 15 | networks: 16 | - telemetry 17 | 18 | volumes: 19 | mosquitto: 20 | -------------------------------------------------------------------------------- /lib/utils/dummy_mqtt.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace hyped::utils { 6 | 7 | class MockMqtt : public core::IMqtt { 8 | public: 9 | void publish(const core::MqttMessage &message, const core::MqttMessageQos qos) override; 10 | core::Result subscribe(const core::MqttTopic topic) override; 11 | core::Result consume() override; 12 | std::optional getMessage() override; 13 | }; 14 | 15 | } // namespace hyped::utils 16 | -------------------------------------------------------------------------------- /telemetry/packages/constants/src/socket/index.ts: -------------------------------------------------------------------------------- 1 | export const MEASUREMENT_EVENT = 'Measurement'; 2 | export const FAULT_EVENT = 'Fault'; 3 | 4 | export const EVENTS = { 5 | SUBSCRIBE_TO_MEASUREMENT: 'SubscribeToMeasurement', 6 | UNSUBSCRIBE_FROM_MEASUREMENT: 'UnsubscribeFromMeasurement', 7 | SUBSCRIBE_TO_FAULTS: 'SubscribeToFaults', 8 | UNSUBSCRIBE_FROM_FAULTS: 'UnsubscribeFromFaults', 9 | }; 10 | 11 | export { getMeasurementRoomName } from './getMeasurementRoomName'; 12 | -------------------------------------------------------------------------------- /lib/utils/manual_time.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace hyped::utils { 6 | 7 | class ManualTime : public core::ITimeSource { 8 | public: 9 | ManualTime(); 10 | core::TimePoint now() const override; 11 | 12 | void set_time(const core::TimePoint time_point); 13 | void set_seconds_since_epoch(const std::uint64_t seconds_since_epoch); 14 | 15 | private: 16 | core::TimePoint current_time_; 17 | }; 18 | 19 | } // namespace hyped::utils 20 | -------------------------------------------------------------------------------- /telemetry/packages/server/src/modules/mqtt/ingestion/MqttIngestion.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { MqttIngestionService } from './MqttIngestion.service'; 3 | import { MeasurementModule } from 'src/modules/measurement/Measurement.module'; 4 | import { StateModule } from '@/modules/state/State.module'; 5 | 6 | @Module({ 7 | imports: [MeasurementModule, StateModule], 8 | providers: [MqttIngestionService], 9 | }) 10 | export class MqttIngestionModule {} 11 | -------------------------------------------------------------------------------- /telemetry/packages/server/src/modules/openmct/object-types/ObjectTypes.controller.ts: -------------------------------------------------------------------------------- 1 | import { Controller, Get } from '@nestjs/common'; 2 | import { ObjectTypesService as ObjectTypesService } from './ObjectTypes.service'; 3 | 4 | @Controller('openmct/object-types') 5 | export class ObjectTypesController { 6 | constructor(private objectTypesService: ObjectTypesService) {} 7 | 8 | @Get() 9 | getObjectTypes() { 10 | return this.objectTypesService.getObjectTypes(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /telemetry/packages/server/src/modules/warnings/Warnings.controller.ts: -------------------------------------------------------------------------------- 1 | import { Controller, Param, Post } from '@nestjs/common'; 2 | import { WarningsService } from './Warnings.service'; 3 | 4 | @Controller('pods/:podId/warnings') 5 | export class WarningsController { 6 | constructor(private warningsService: WarningsService) {} 7 | 8 | @Post('latency') 9 | createLatencyWarning(@Param('podId') podId: string) { 10 | this.warningsService.createLatencyWarning(podId); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/sensors/i2c_mux.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace hyped::test { 11 | 12 | TEST(I2cMux, construction) 13 | { 14 | const auto i2c = std::make_shared(); 15 | utils::DummyLogger logger; 16 | sensors::I2cMux mux(logger, i2c, sensors::kDefaultMuxAddress, 0); 17 | } 18 | 19 | } // namespace hyped::test 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | build 35 | .vscode 36 | .cache 37 | tags 38 | .DS_Store 39 | 40 | # Telemetry 41 | .env -------------------------------------------------------------------------------- /lib/debug/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(target hyped_debug) 2 | file(GLOB_RECURSE headers "${CMAKE_CURRENT_SOURCE_DIR}/*.hpp") 3 | file(GLOB_RECURSE code "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp") 4 | add_library(${target} STATIC ${headers} ${code}) 5 | include_directories( 6 | ${target} "${CMAKE_SOURCE_DIR}/lib" "${CMAKE_CURRENT_SOURCE_DIR}" 7 | ) 8 | target_link_libraries( 9 | ${target} 10 | hyped_core 11 | hyped_io 12 | hyped_sensors 13 | hyped_motors 14 | ${CURSES_LIBRARIES} 15 | tomlplusplus::tomlplusplus 16 | ) 17 | -------------------------------------------------------------------------------- /lib/state_machine/state.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace hyped::state_machine { 4 | 5 | enum class State { 6 | kIdle, 7 | kCalibrate, 8 | kPrecharge, 9 | kReadyForLevitation, 10 | kBeginLevitation, 11 | kLevitating, 12 | kReady, 13 | kAccelerate, 14 | kLimBrake, 15 | kFrictionBrake, 16 | kStopLevitation, 17 | kStopped, 18 | kBatteryRecharge, 19 | kCapacitorDischarge, 20 | kFailureBrake, 21 | kFailure, 22 | kSafe, 23 | kShutdown 24 | }; 25 | 26 | } // namespace hyped::state_machine -------------------------------------------------------------------------------- /test/navigation/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(target hyped_test_navigation) 2 | file(GLOB code "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp") 3 | add_executable(${target} ${code}) 4 | target_include_directories( 5 | ${target} PRIVATE "${CMAKE_SOURCE_DIR}/lib" "${CMAKE_CURRENT_SOURCE_DIR}" 6 | ) 7 | target_link_libraries( 8 | ${target} 9 | GTest::gtest_main 10 | hyped_core 11 | hyped_navigation_filters 12 | hyped_navigation_control 13 | hyped_navigation_preprocessing 14 | hyped_utils 15 | ) 16 | gtest_discover_tests(${target}) 17 | -------------------------------------------------------------------------------- /lib/motors/constant_frequency_calculator.cpp: -------------------------------------------------------------------------------- 1 | #include "constant_frequency_calculator.hpp" 2 | 3 | namespace hyped::motors { 4 | 5 | ConstantFrequencyCalculator::ConstantFrequencyCalculator(core::ILogger &logger) : logger_(logger) 6 | { 7 | } 8 | 9 | std::uint32_t ConstantFrequencyCalculator::calculateFrequency(core::Float velocity) 10 | { 11 | return frequency_; 12 | } 13 | 14 | void ConstantFrequencyCalculator::setFrequency(std::uint16_t frequency) 15 | { 16 | frequency_ = frequency; 17 | } 18 | 19 | } // namespace hyped::motors -------------------------------------------------------------------------------- /telemetry/packages/server/src/modules/warnings/Warnings.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, LoggerService } from '@nestjs/common'; 2 | import { Logger } from '@/modules/logger/Logger.decorator'; 3 | 4 | @Injectable() 5 | export class WarningsService { 6 | constructor( 7 | @Logger() 8 | private readonly logger: LoggerService, 9 | ) {} 10 | 11 | createLatencyWarning(podId: string) { 12 | this.logger.log( 13 | `Creating latency warning for pod ${podId}`, 14 | WarningsService.name, 15 | ); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /telemetry/packages/server/src/main.ts: -------------------------------------------------------------------------------- 1 | import * as dotenv from 'dotenv'; 2 | dotenv.config(); 3 | 4 | import { NestFactory } from '@nestjs/core'; 5 | import { AppModule } from './app.module'; 6 | import { WINSTON_MODULE_NEST_PROVIDER } from 'nest-winston'; 7 | 8 | async function bootstrap() { 9 | const app = await NestFactory.create(AppModule, { 10 | bufferLogs: true, 11 | }); 12 | app.enableCors(); 13 | app.useLogger(app.get(WINSTON_MODULE_NEST_PROVIDER)); 14 | 15 | await app.listen(3000); 16 | } 17 | 18 | void bootstrap(); 19 | -------------------------------------------------------------------------------- /telemetry/packages/types/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@hyped/telemetry-types", 3 | "private": true, 4 | "version": "0.0.0", 5 | "types": "dist/index.d.ts", 6 | "scripts": { 7 | "build": "tsc", 8 | "watch": "tsc -w", 9 | "lint": "eslint --ext .ts src --max-warnings 0 --report-unused-disable-directives", 10 | "lint:fix": "eslint --ext .ts src --fix" 11 | }, 12 | "dependencies": { 13 | "@hyped/eslint-config": "workspace:*", 14 | "@hyped/tsconfig": "workspace:*", 15 | "typescript": "^5.3.3" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /telemetry/packages/server/src/modules/openmct/object-types/ObjectTypes.service.ts: -------------------------------------------------------------------------------- 1 | import { openMctObjectTypes } from '@hyped/telemetry-constants'; 2 | import { OpenMctObjectTypes } from '@hyped/telemetry-types'; 3 | import { Injectable } from '@nestjs/common'; 4 | 5 | @Injectable() 6 | export class ObjectTypesService { 7 | /** 8 | * Get the object types for Open MCT. 9 | * @returns The object types for Open MCT from the constants. 10 | */ 11 | getObjectTypes(): OpenMctObjectTypes { 12 | return openMctObjectTypes; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/core/libraries.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | TEST(Libraries, Eigen) 7 | { 8 | Eigen::Matrix3d m; 9 | m << 1, 2, 3, 4, 5, 6, 7, 8, 9; 10 | Eigen::Vector3d v(1, 2, 3); 11 | Eigen::Vector3d result = m * v; 12 | ASSERT_EQ(result(0), 14); 13 | ASSERT_EQ(result(1), 32); 14 | ASSERT_EQ(result(2), 50); 15 | } 16 | 17 | TEST(Libraries, Boost) 18 | { 19 | std::string s = "Hello World"; 20 | boost::to_upper(s); 21 | ASSERT_EQ(s, "HELLO WORLD"); 22 | } 23 | -------------------------------------------------------------------------------- /lib/debug/commands/temperature_commands.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "command.hpp" 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | namespace hyped::debug { 11 | 12 | class TemperatureCommands { 13 | public: 14 | static core::Result addCommands(core::ILogger &logger, 15 | const std::shared_ptr &repl, 16 | toml::v3::node_view config); 17 | }; 18 | 19 | } // namespace hyped::debug 20 | -------------------------------------------------------------------------------- /lib/utils/dummy_mqtt.cpp: -------------------------------------------------------------------------------- 1 | #include "dummy_mqtt.hpp" 2 | 3 | namespace hyped::utils { 4 | 5 | void MockMqtt::publish(const core::MqttMessage &message, const core::MqttMessageQos qos) 6 | { 7 | } 8 | 9 | core::Result MockMqtt::subscribe(const core::MqttTopic topic) 10 | { 11 | return core::Result::kSuccess; 12 | } 13 | 14 | core::Result MockMqtt::consume() 15 | { 16 | return core::Result::kSuccess; 17 | } 18 | 19 | std::optional MockMqtt::getMessage() 20 | { 21 | return std::nullopt; 22 | } 23 | 24 | } // namespace hyped::utils 25 | -------------------------------------------------------------------------------- /scripts/format.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Formats all C++ and CMakeLists.txt files in the repository 3 | # Requires git-clang-format and cmake-format 4 | # Usage: ./scripts/format.sh [path] 5 | # Path is relative to the root of the repository, if not specified, the entire repository is formatted 6 | 7 | path="$(git rev-parse --show-toplevel)" 8 | git add "$path/$argv" 9 | git clang-format --extensions c,h,cpp,hpp 10 | find "$path/$argv" \( -name 'CMakeLists.txt' -not -path "./build/*" -not -path "./telemetry/*" \) -exec cmake-format -i {} + 11 | git add "$path/$argv" -------------------------------------------------------------------------------- /telemetry/packages/ui/openmct/plugins/data/object-types-data.ts: -------------------------------------------------------------------------------- 1 | import { OpenMctObjectTypes } from '@hyped/telemetry-types'; 2 | import { http } from '../../core/http'; 3 | 4 | /** 5 | * Fetches all object types from the server. 6 | * These object types define the different types of objects (a.k.a measurements) that can be displayed in Open MCT (e.g. velocity, acceleration, etc.) 7 | * @returns The object types (in our own format). 8 | */ 9 | export const fetchObjectTypes = async () => 10 | http.get('openmct/object-types').json(); 11 | -------------------------------------------------------------------------------- /telemetry/packages/public-app/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@hyped/tsconfig/base.json", 3 | "compilerOptions": { 4 | "target": "es5", 5 | "lib": ["dom", "dom.iterable", "esnext"], 6 | "moduleResolution": "bundler", 7 | "jsx": "preserve", 8 | "plugins": [ 9 | { 10 | "name": "next", 11 | }, 12 | ], 13 | "paths": { 14 | "@/*": ["./*"], 15 | }, 16 | "allowJs": true, 17 | }, 18 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 19 | "exclude": ["node_modules"], 20 | } 21 | -------------------------------------------------------------------------------- /telemetry/packages/public-app/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | # local env files 28 | .env*.local 29 | 30 | # vercel 31 | .vercel 32 | 33 | # typescript 34 | *.tsbuildinfo 35 | next-env.d.ts 36 | -------------------------------------------------------------------------------- /telemetry/packages/server/src/modules/state/StateUpdate.types.ts: -------------------------------------------------------------------------------- 1 | import { ALL_POD_STATES, pods } from '@hyped/telemetry-constants'; 2 | import { 3 | zodEnumFromObjKeys, 4 | zodEnumFromObjValues, 5 | } from '@/modules/common/utils/zodEnumFromObjKeys'; 6 | import { z } from 'zod'; 7 | 8 | export const StateUpdateSchema = z.object({ 9 | podId: zodEnumFromObjKeys(pods), 10 | timestamp: z.string(), // to handle nanoseconds timestamp 11 | value: zodEnumFromObjValues(ALL_POD_STATES), 12 | }); 13 | 14 | export type StateUpdate = z.infer; 15 | -------------------------------------------------------------------------------- /lib/utils/dummy_spi.cpp: -------------------------------------------------------------------------------- 1 | #include "dummy_spi.hpp" 2 | 3 | namespace hyped::utils { 4 | 5 | core::Result DummySpi::read(const std::uint8_t addr, 6 | const std::uint8_t *rx, 7 | const std::uint16_t len) 8 | { 9 | return core::Result::kFailure; 10 | } 11 | 12 | core::Result DummySpi::write(const std::uint8_t addr, 13 | const std::uint8_t *tx, 14 | const std::uint16_t len) 15 | { 16 | return core::Result::kFailure; 17 | } 18 | 19 | } // namespace hyped::utils -------------------------------------------------------------------------------- /telemetry/packages/e2e-tests/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@hyped/e2e-tests", 3 | "version": "1.0.0", 4 | "description": "End-to-end tests for HYPED Telemetry", 5 | "main": "index.js", 6 | "scripts": { 7 | "e2e:test": "playwright test" 8 | }, 9 | "dependencies": { 10 | "@hyped/telemetry-server": "workspace:*", 11 | "@hyped/telemetry-ui": "workspace:*", 12 | "mqtt": "^5.5.0" 13 | }, 14 | "devDependencies": { 15 | "@hyped/tsconfig": "workspace:*", 16 | "@playwright/test": "^1.42.1", 17 | "@types/node": "^20.11.28" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /telemetry/packages/eslint-config/react.js: -------------------------------------------------------------------------------- 1 | /** @type {import("eslint").Linter.Config} */ 2 | module.exports = { 3 | extends: [ 4 | './basic.js', 5 | 'plugin:react/recommended', 6 | 'plugin:react-hooks/recommended', 7 | ], 8 | plugins: ['react', 'react-hooks'], 9 | parserOptions: { 10 | ecmaFeatures: { 11 | jsx: true, 12 | }, 13 | }, 14 | settings: { 15 | react: { 16 | version: 'detect', 17 | }, 18 | }, 19 | rules: { 20 | 'react/react-in-jsx-scope': 'off', 21 | 'react/jsx-uses-react': 'off', 22 | }, 23 | }; 24 | -------------------------------------------------------------------------------- /lib/debug/commands/accelerometer_commands.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace hyped::debug { 11 | 12 | class AccelerometerCommands { 13 | public: 14 | static core::Result addCommands(core::ILogger &logger, 15 | const std::shared_ptr &repl, 16 | toml::v3::node_view config); 17 | }; 18 | 19 | } // namespace hyped::debug 20 | -------------------------------------------------------------------------------- /telemetry/packages/server/src/modules/live-logs/LiveLogs.gateway.ts: -------------------------------------------------------------------------------- 1 | import { 2 | SubscribeMessage, 3 | WebSocketGateway, 4 | WebSocketServer, 5 | } from '@nestjs/websockets'; 6 | import { Server, Socket } from 'socket.io'; 7 | 8 | @WebSocketGateway({ 9 | path: '/live-logs', 10 | cors: { 11 | origin: '*', 12 | }, 13 | }) 14 | export class LiveLogsGateway { 15 | @WebSocketServer() 16 | socket: Server; 17 | 18 | @SubscribeMessage('send-log') 19 | handleMessage(_client: Socket, payload: unknown) { 20 | this.socket.emit('log', payload); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /telemetry/packages/ui/app/lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { clsx, type ClassValue } from 'clsx'; 2 | import { twMerge } from 'tailwind-merge'; 3 | 4 | export const cn = (...inputs: ClassValue[]) => { 5 | return twMerge(clsx(inputs)); 6 | }; 7 | 8 | /** 9 | * Gets the full MQTT topic name for a given partial topic and podId 10 | * @param topic The partial topic name (will be prefixed with ```hyped/${podId}/```) 11 | * @param podId The podId to use in the topic 12 | * @returns 13 | */ 14 | export const getTopic = (topic: string, podId: string) => 15 | `hyped/${podId}/${topic}`; 16 | -------------------------------------------------------------------------------- /lib/debug/commands/i2c_commands.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | namespace hyped::debug { 10 | 11 | class I2cCommands { 12 | public: 13 | /** 14 | * @brief Add commands to the REPL for reading from and writing to I2C devices 15 | * 16 | * @param logger 17 | * @param repl 18 | * @return core::Result 19 | */ 20 | static core::Result addCommands(core::ILogger &logger, std::shared_ptr &repl); 21 | }; 22 | 23 | } // namespace hyped::debug 24 | -------------------------------------------------------------------------------- /telemetry/packages/eslint-config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@hyped/eslint-config", 3 | "version": "0.0.0", 4 | "private": true, 5 | "files": [ 6 | "basic.js", 7 | "react.js" 8 | ], 9 | "dependencies": { 10 | "@typescript-eslint/eslint-plugin": "^6.21.0", 11 | "@typescript-eslint/parser": "^6.21.0", 12 | "eslint": "^8.57.0", 13 | "eslint-config-prettier": "^9.1.0", 14 | "eslint-config-turbo": "^1.12.5", 15 | "eslint-plugin-only-warn": "^1.1.0", 16 | "eslint-plugin-react-hooks": "^4.6.0", 17 | "typescript": "^5.4.2" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /telemetry/packages/server/src/modules/common/utils/zodEnumFromObjKeys.ts: -------------------------------------------------------------------------------- 1 | import { z } from 'zod'; 2 | 3 | export function zodEnumFromObjKeys( 4 | obj: Record, 5 | ): z.ZodEnum<[K, ...K[]]> { 6 | const [firstKey, ...otherKeys] = Object.keys(obj) as K[]; 7 | return z.enum([firstKey, ...otherKeys]); 8 | } 9 | 10 | export function zodEnumFromObjValues( 11 | obj: Record, 12 | ): z.ZodEnum<[V, ...V[]]> { 13 | const [firstValue, ...otherValues] = Object.values(obj); 14 | return z.enum([firstValue, ...otherValues]); 15 | } 16 | -------------------------------------------------------------------------------- /telemetry/.gitignore: -------------------------------------------------------------------------------- 1 | # compiled output 2 | dist 3 | node_modules 4 | 5 | # Logs 6 | logs 7 | *.log 8 | npm-debug.log* 9 | pnpm-debug.log* 10 | yarn-debug.log* 11 | yarn-error.log* 12 | lerna-debug.log* 13 | 14 | # OS 15 | .DS_Store 16 | 17 | # Tests 18 | /coverage 19 | /.nyc_output 20 | 21 | # IDEs and editors 22 | /.idea 23 | .project 24 | .classpath 25 | .c9/ 26 | *.launch 27 | .settings/ 28 | *.sublime-workspace 29 | .turbo 30 | 31 | # .env files 32 | .env 33 | 34 | # influx 35 | influxdb/config 36 | influxdb/data 37 | 38 | # mosquitto persistence & logs 39 | mosquitto/data 40 | mosquitto/log -------------------------------------------------------------------------------- /config/pod.toml: -------------------------------------------------------------------------------- 1 | [hostnames] 2 | raspberry = "192.168.1.0" 3 | banoffee = "192.168.1.1" 4 | pumpkin = "192.168.1.2" 5 | rhubarb = "192.168.1.3" 6 | 7 | [mqtt] 8 | host = "192.168.1.0" 9 | port = 4556 10 | 11 | [raspberry] 12 | nodes = ["state_machine", "mqtt_broker", "navigator", "accelerometer", "keyence", "optical_flow"] 13 | 14 | [state_machine] 15 | # Possible transition tables are "full_run", 16 | # "no_levitation", "levitation_only" 17 | transition_table = "full_run" 18 | 19 | [navigator] 20 | maxVelocity = 10 21 | 22 | [accelerometer] 23 | mux_channel = 3 24 | 25 | [keyence] 26 | pin = 4 27 | -------------------------------------------------------------------------------- /telemetry/packages/server/src/modules/measurement/Measurement.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { MeasurementService } from './Measurement.service'; 3 | import { InfluxModule } from '@/modules/influx/Influx.module'; 4 | import { OpenMCTDataModule } from '@/modules/openmct/data/OpenMCTData.module'; 5 | import { FaultModule } from '@/modules/openmct/faults/Fault.module'; 6 | 7 | @Module({ 8 | imports: [InfluxModule, OpenMCTDataModule, FaultModule], 9 | providers: [MeasurementService], 10 | exports: [MeasurementService], 11 | }) 12 | export class MeasurementModule {} 13 | -------------------------------------------------------------------------------- /lib/navigation/control/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(target hyped_navigation_control) 2 | file(GLOB headers "${CMAKE_CURRENT_SOURCE_DIR}/*.hpp") 3 | file(GLOB code "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp") 4 | add_library(${target} STATIC ${headers} ${code}) 5 | include_directories( 6 | ${target} 7 | INTERFACE 8 | "${CMAKE_SOURCE_DIR}/lib" 9 | "${CMAKE_CURRENT_SOURCE_DIR}" 10 | "${CMAKE_SOURCE_DIR}/lib/navigation" 11 | ) 12 | target_link_libraries( 13 | ${target} 14 | Eigen3::Eigen 15 | hyped_core 16 | tomlplusplus::tomlplusplus 17 | hyped_navigation_filters 18 | hyped_navigation_preprocessing 19 | ) 20 | -------------------------------------------------------------------------------- /lib/sensors/adc_mux.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace hyped::sensors { 6 | 7 | constexpr std::uint8_t kAdcMuxAddress = 0x1D; 8 | constexpr std::uint8_t kAdcMuxChannel1 = 0x20; 9 | constexpr std::uint8_t kAdcMuxChannel2 = 0x21; 10 | constexpr std::uint8_t kAdcMuxChannel3 = 0x22; 11 | constexpr std::uint8_t kAdcMuxChannel4 = 0x23; 12 | constexpr std::uint8_t kAdcMuxChannel5 = 0x24; 13 | constexpr std::uint8_t kAdcMuxChannel6 = 0x25; 14 | constexpr std::uint8_t kAdcMuxChannel7 = 0x26; 15 | constexpr std::uint8_t kAdcMuxChannel0 = 0x27; 16 | 17 | } // namespace hyped::sensors 18 | -------------------------------------------------------------------------------- /lib/utils/dummy_uart.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace hyped::utils { 6 | 7 | /** 8 | * A basic implementation of Uart that does not require any hardware. This allow us to 9 | * 10 | * 1. demonstrate how to implement the IUart interface, and 11 | * 2. allow for quick test implementations. 12 | */ 13 | class DummyUart : public io::IUart { 14 | public: 15 | core::Result sendBytes(const char *tx, const std::uint8_t length) override; 16 | core::Result readBytes(unsigned char *rx, const std::uint8_t length) override; 17 | }; 18 | 19 | } // namespace hyped::utils 20 | -------------------------------------------------------------------------------- /src/pod/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(target hyped_pod) 2 | file(GLOB headers "${CMAKE_CURRENT_SOURCE_DIR}/*.hpp") 3 | file(GLOB code "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp") 4 | add_executable(${target} ${headers} ${code}) 5 | target_include_directories( 6 | ${target} INTERFACE "${CMAKE_SOURCE_DIR}/lib" "${CMAKE_CURRENT_SOURCE_DIR}" 7 | ) 8 | target_link_libraries( 9 | ${target} 10 | hyped_core 11 | hyped_io 12 | hyped_utils 13 | hyped_statemachine 14 | hyped_navigation_control 15 | hyped_navigation_filters 16 | hyped_navigation_preprocessing 17 | hyped_sensors 18 | tomlplusplus::tomlplusplus 19 | ) 20 | -------------------------------------------------------------------------------- /lib/debug/commands/adc_commands.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | namespace hyped::debug { 10 | 11 | class AdcCommands { 12 | public: 13 | /** 14 | * @brief Add commands to the REPL for reading from ADC pins 15 | * 16 | * @param logger 17 | * @param repl 18 | * @return core::Result kSuccess if commands were added successfully, kFailure otherwise 19 | */ 20 | static core::Result addCommands(core::ILogger &logger, std::shared_ptr &repl); 21 | }; 22 | 23 | } // namespace hyped::debug 24 | -------------------------------------------------------------------------------- /telemetry/mqtt/latency.ts: -------------------------------------------------------------------------------- 1 | // connect to mqtt 2 | 3 | import { connect, MqttClient } from 'mqtt'; 4 | 5 | // connect to mqtt 6 | const client: MqttClient = connect('mqtt://localhost:1883'); 7 | 8 | // subscribe to topic 9 | client.subscribe('hyped/pod_1/latency/request'); 10 | 11 | // on message 12 | client.on('message', async (topic: string, message: Buffer) => { 13 | console.log(`Received message from ${topic}: ${message.toString()}`); 14 | // sleep for 100ms 15 | // await new Promise((resolve) => setTimeout(resolve, 50)); 16 | // publish to topic 17 | client.publish('hyped/pod_1/latency/response', message); 18 | }); 19 | -------------------------------------------------------------------------------- /telemetry/packages/server/src/modules/public-data/PublicData.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { PublicDataController } from './PublicData.controller'; 3 | import { PublicDataService } from './PublicData.service'; 4 | import { HistoricalTelemetryDataService } from '@/modules/openmct/data/historical/HistoricalTelemetryData.service'; 5 | import { InfluxModule } from '@/modules/influx/Influx.module'; 6 | 7 | @Module({ 8 | imports: [InfluxModule], 9 | controllers: [PublicDataController], 10 | providers: [PublicDataService, HistoricalTelemetryDataService], 11 | }) 12 | export class PublicDataModule {} 13 | -------------------------------------------------------------------------------- /telemetry/packages/ui/openmct/core/http.ts: -------------------------------------------------------------------------------- 1 | import ky from 'ky'; 2 | import { HTTP_DEBUG, SERVER_ENDPOINT } from './config'; 3 | 4 | export const http = ky.create({ 5 | prefixUrl: SERVER_ENDPOINT, 6 | hooks: { 7 | beforeRequest: [ 8 | (request) => { 9 | // eslint-disable-next-line no-console 10 | if (HTTP_DEBUG) console.log('Request:', request); 11 | }, 12 | ], 13 | afterResponse: [ 14 | (request, options, response) => { 15 | // eslint-disable-next-line no-console 16 | if (HTTP_DEBUG) console.log('Response:', response); 17 | }, 18 | ], 19 | }, 20 | }); 21 | -------------------------------------------------------------------------------- /lib/debug/commands/pwm_commands.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | namespace hyped::debug { 10 | 11 | class PwmCommands { 12 | public: 13 | /** 14 | * @brief Add commands to the REPL for starting and stopping PWM signals 15 | * 16 | * @param logger 17 | * @param repl 18 | * @return core::Result kSuccess if commands were added successfully, kFailure otherwise 19 | */ 20 | static core::Result addCommands(core::ILogger &logger, std::shared_ptr &repl); 21 | }; 22 | 23 | } // namespace hyped::debug 24 | -------------------------------------------------------------------------------- /lib/debug/commands/can_commands.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | namespace hyped::debug { 10 | 11 | class CanCommands { 12 | public: 13 | /** 14 | * @brief Add commands to the REPL for reading from and writing to CAN buses 15 | * 16 | * @param logger 17 | * @param repl 18 | * @return core::Result kSuccess if commands were added successfully, kFailure otherwise 19 | */ 20 | static core::Result addCommands(core::ILogger &logger, std::shared_ptr &repl); 21 | }; 22 | 23 | } // namespace hyped::debug 24 | -------------------------------------------------------------------------------- /tools/pi_manager/install.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bash 2 | 3 | # Must be run as root 4 | if [ "$EUID" -ne 0 ] 5 | then echo "This script must be run as root" 6 | exit 1 7 | fi 8 | 9 | # Install the pi_manager service 10 | rm /etc/systemd/system/pi_manager.service 11 | cp pi_manager.service /etc/systemd/system/ 12 | rm /usr/bin/pi_manager 13 | cp pi_manager /usr/bin/ 14 | chmod +x /usr/bin/pi_manager 15 | chown root:root /usr/bin/pi_manager 16 | chown root:root /etc/systemd/system/pi_manager.service 17 | systemctl daemon-reload 18 | systemctl enable pi_manager 19 | systemctl start pi_manager 20 | echo "pi_manager service installed and started" 21 | -------------------------------------------------------------------------------- /lib/debug/commands/gpio_commands.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | namespace hyped::debug { 10 | 11 | class GpioCommands { 12 | public: 13 | /** 14 | * @brief Add commands to the REPL for reading from and writing to GPIO pins 15 | * 16 | * @param logger 17 | * @param repl 18 | * @return core::Result kSuccess if commands were added successfully, kFailure otherwise 19 | */ 20 | static core::Result addCommands(core::ILogger &logger, std::shared_ptr &repl); 21 | }; 22 | 23 | } // namespace hyped::debug 24 | -------------------------------------------------------------------------------- /lib/debug/commands/spi_commands.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | namespace hyped::debug { 10 | 11 | class SpiCommands { 12 | public: 13 | /** 14 | * @brief Add commands to the REPL for reading from and writing to SPI devices 15 | * 16 | * @param logger 17 | * @param repl 18 | * @return core::Result kSuccess if commands were added successfully, kFailure otherwise 19 | */ 20 | static core::Result addCommands(core::ILogger &logger, std::shared_ptr &repl); 21 | }; 22 | 23 | } // namespace hyped::debug 24 | -------------------------------------------------------------------------------- /lib/debug/commands/uart_commands.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | namespace hyped::debug { 10 | 11 | class UartCommands { 12 | public: 13 | /** 14 | * @brief Add commands to the REPL for reading from and writing to UART buses 15 | * 16 | * @param logger 17 | * @param repl 18 | * @return core::Result kSuccess if commands were added successfully, kFailure otherwise 19 | */ 20 | static core::Result addCommands(core::ILogger &logger, std::shared_ptr &repl); 21 | }; 22 | 23 | } // namespace hyped::debug 24 | -------------------------------------------------------------------------------- /telemetry/patches/nest-mqtt@0.2.0.patch: -------------------------------------------------------------------------------- 1 | diff --git a/package.json b/package.json 2 | index d618c5b39872a64b809eac6c27402241d77f79f7..0ce26cf2e52786645c5b8fe528df38cda55f969d 100644 3 | --- a/package.json 4 | +++ b/package.json 5 | @@ -32,8 +32,8 @@ 6 | "test:e2e": "jest --config ./test/jest-e2e.json" 7 | }, 8 | "peerDependencies": { 9 | - "@nestjs/common": "^6.10.11 || ^7.0.0 || ^8.0.0", 10 | - "@nestjs/core": "^6.10.11 || ^7.0.0 || ^8.0.0", 11 | + "@nestjs/common": "^6.10.11 || ^7.0.0 || ^8.0.0 || ^9.0.0", 12 | + "@nestjs/core": "^6.10.11 || ^7.0.0 || ^8.0.0 || ^9.0.0", 13 | "mqtt": "^3.0.0" 14 | }, 15 | "devDependencies": { -------------------------------------------------------------------------------- /lib/core/timer.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "time.hpp" 4 | #include "types.hpp" 5 | 6 | #include 7 | 8 | namespace hyped::core { 9 | 10 | constexpr std::uint32_t kOneSecond = 1'000'000'000; 11 | 12 | class Timer { 13 | public: 14 | explicit Timer(const ITimeSource &time); 15 | 16 | Duration measureExecutionTime(const std::function &task); 17 | 18 | static Duration elapsed(const TimePoint current_timepoint, const TimePoint previous_timepoint); 19 | 20 | static Float elapsedTimeInSeconds(const Duration time_elapsed); 21 | 22 | private: 23 | const ITimeSource &time_; 24 | }; 25 | 26 | } // namespace hyped::core 27 | -------------------------------------------------------------------------------- /telemetry/packages/ui/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@hyped/tsconfig/base.json", 3 | "compilerOptions": { 4 | "target": "ESNext", 5 | "useDefineForClassFields": true, 6 | "lib": ["DOM", "DOM.Iterable", "ESNext"], 7 | "allowSyntheticDefaultImports": true, 8 | "jsx": "react-jsx", 9 | "baseUrl": ".", 10 | "paths": { 11 | "@/*": ["./app/*"], 12 | }, 13 | }, 14 | "tsc-alias": { 15 | "replacers": { 16 | "base-url": { 17 | "enabled": false, 18 | }, 19 | }, 20 | }, 21 | "include": ["app", "vite.config.ts", "openmct", "mqtt.d.ts", "app/config.ts"], 22 | "exclude": ["node_modules", "dist"], 23 | } 24 | -------------------------------------------------------------------------------- /lib/navigation/preprocessing/preprocess_optical.cpp: -------------------------------------------------------------------------------- 1 | #include "preprocess_optical.hpp" 2 | 3 | namespace hyped::navigation { 4 | 5 | std::optional> OpticalPreprocessor::processData( 6 | const core::OpticalData raw_optical_data) 7 | { 8 | // Take magnitude 9 | std::array optical_data; 10 | for (std::size_t i = 0; i < core::kNumOptical; ++i) { 11 | core::Float magnitude = 0; 12 | for (std::size_t j = 0; j < 2; ++j) { 13 | magnitude += std::pow(raw_optical_data.at(i).at(j), 2); 14 | } 15 | optical_data.at(i) = std::sqrt(magnitude); 16 | } 17 | 18 | return optical_data; 19 | } 20 | 21 | } // namespace hyped::navigation 22 | -------------------------------------------------------------------------------- /telemetry/packages/server/src/modules/openmct/OpenMCT.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { DictionaryController } from './dictionary/Dictionary.controller'; 3 | import { DictionaryService } from './dictionary/Dictionary.service'; 4 | import { ObjectTypesController } from './object-types/ObjectTypes.controller'; 5 | import { ObjectTypesService } from './object-types/ObjectTypes.service'; 6 | import { OpenMCTDataModule } from './data/OpenMCTData.module'; 7 | 8 | @Module({ 9 | imports: [OpenMCTDataModule], 10 | controllers: [DictionaryController, ObjectTypesController], 11 | providers: [DictionaryService, ObjectTypesService], 12 | }) 13 | export class OpenMCTModule {} 14 | -------------------------------------------------------------------------------- /lib/state_machine/types.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "state.hpp" 4 | 5 | #include 6 | 7 | namespace hyped::state_machine { 8 | struct SourceAndTarget { 9 | State source; 10 | State target; 11 | 12 | bool operator==(const SourceAndTarget &key) const 13 | { 14 | return key.source == source && key.target == target; 15 | } 16 | }; 17 | 18 | struct source_and_target_hash { 19 | std::size_t operator()(SourceAndTarget const &key) const 20 | { 21 | std::size_t seed = 0; 22 | boost::hash_combine(seed, key.source); 23 | boost::hash_combine(seed, key.target); 24 | return seed; 25 | } 26 | }; 27 | 28 | } // namespace hyped::state_machine 29 | -------------------------------------------------------------------------------- /telemetry/packages/public-app/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import './globals.css'; 2 | import type { Metadata } from 'next'; 3 | import { Inter } from 'next/font/google'; 4 | import Providers from './providers'; 5 | 6 | const inter = Inter({ subsets: ['latin'] }); 7 | 8 | export const metadata: Metadata = { 9 | title: 'HYPED | Public App', 10 | description: 'Public app for HYPED Telemetry', 11 | }; 12 | 13 | export default function RootLayout({ 14 | children, 15 | }: { 16 | children: React.ReactNode; 17 | }) { 18 | return ( 19 | 20 | 21 | {children} 22 | 23 | 24 | ); 25 | } 26 | -------------------------------------------------------------------------------- /lib/core/mqtt_logger.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "logger.hpp" 4 | #include "mqtt.hpp" 5 | #include "time.hpp" 6 | 7 | namespace hyped::core { 8 | class MqttLogger : public ILogger { 9 | public: 10 | MqttLogger(const char *const label, 11 | const LogLevel level, 12 | const core::ITimeSource &timer, 13 | ILogger &logger, 14 | std::shared_ptr mqtt); 15 | void log(const LogLevel level, const char *format, ...) override; 16 | 17 | private: 18 | const char *const label_; 19 | const LogLevel level_; 20 | const core::ITimeSource &time_source_; 21 | ILogger &logger_; 22 | std::shared_ptr mqtt_; 23 | }; 24 | } // namespace hyped::core 25 | -------------------------------------------------------------------------------- /lib/sensors/optical_flow.py: -------------------------------------------------------------------------------- 1 | from pmw3901 import PMW3901 2 | import paho.mqtt.client as mqtt 3 | import tomllib 4 | import json 5 | import time 6 | 7 | file = open('pod.toml', 'rb') 8 | config = tomllib.load(file) 9 | mqttc = mqtt.Client() 10 | mqttc.connect(config['mqtt']['host'], config['mqtt']['port']) 11 | 12 | 13 | sensor = PMW3901(spi_cs=0) 14 | mqttc = mqtt.Client() 15 | 16 | while True: 17 | (x, y) = sensor.get_motion() 18 | measurement = {'header': {'timestamp': time.time(), 'priority': 1 19 | }, 'payload': {'x': x, 'y': y}} 20 | mqttc.publish('hyped/cart_2024/measurement/optical_flow', 21 | json.dumps(measurement)) 22 | time.sleep(0.05) 23 | -------------------------------------------------------------------------------- /lib/core/time.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | namespace hyped::core { 5 | 6 | /** 7 | * @brief Absolute point in time; nanosecond precision. 8 | */ 9 | using TimePoint = std::chrono::system_clock::time_point; 10 | 11 | /** 12 | * @brief Difference between points in time; nanosecond precision. 13 | */ 14 | using Duration = std::chrono::system_clock::duration; 15 | 16 | /** 17 | * @brief Time provider allowing the user to obtain the current time of the 18 | * system. We abtract this away instead of using `WallClock` directly in order to 19 | * allow testability. 20 | */ 21 | class ITimeSource { 22 | public: 23 | virtual TimePoint now() const = 0; 24 | }; 25 | 26 | } // namespace hyped::core 27 | -------------------------------------------------------------------------------- /lib/utils/manual_time.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "manual_time.hpp" 3 | 4 | #include 5 | 6 | #include 7 | 8 | namespace hyped::utils { 9 | 10 | ManualTime::ManualTime() : current_time_{std::chrono::system_clock::from_time_t(0)} 11 | { 12 | } 13 | 14 | core::TimePoint ManualTime::now() const 15 | { 16 | return current_time_; 17 | } 18 | 19 | void ManualTime::set_time(const core::TimePoint time_point) 20 | { 21 | current_time_ = time_point; 22 | } 23 | 24 | void ManualTime::set_seconds_since_epoch(const std::uint64_t seconds_since_epoch) 25 | { 26 | current_time_ = std::chrono::system_clock::time_point(std::chrono::seconds(seconds_since_epoch)); 27 | } 28 | 29 | } // namespace hyped::utils 30 | -------------------------------------------------------------------------------- /telemetry/packages/public-app/components/theme-switch.tsx: -------------------------------------------------------------------------------- 1 | import { Switch } from '@tremor/react'; 2 | import { useEffect, useState } from 'react'; 3 | 4 | function ThemeSwitch() { 5 | const [theme, setTheme] = useState('dark'); 6 | 7 | useEffect(() => { 8 | document.body.classList.remove('light', 'dark'); 9 | document.body.classList.add(theme); 10 | }, [theme]); 11 | 12 | const [enabled, setEnabled] = useState(theme == 'dark'); 13 | 14 | const handleThemeChange = (enabled: boolean) => { 15 | setTheme(enabled ? 'dark' : 'light'); 16 | setEnabled(enabled); 17 | }; 18 | 19 | return ; 20 | } 21 | 22 | export default ThemeSwitch; 23 | -------------------------------------------------------------------------------- /lib/utils/dummy_spi.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace hyped::utils { 6 | 7 | /** 8 | * Provides a basic implementation of the ISpi interface. 9 | * This implementation does not actually communicate with any hardware. 10 | * It is intended to be used in unit tests. 11 | */ 12 | class DummySpi : public io::ISpi { 13 | public: 14 | core::Result read(const std::uint8_t addr, 15 | const std::uint8_t *rx, 16 | const std::uint16_t len) override; 17 | core::Result write(const std::uint8_t addr, 18 | const std::uint8_t *tx, 19 | const std::uint16_t len) override; 20 | }; 21 | 22 | } // namespace hyped::utils 23 | -------------------------------------------------------------------------------- /telemetry/packages/server/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@hyped/tsconfig/base.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "removeComments": true, 6 | "emitDecoratorMetadata": true, 7 | "experimentalDecorators": true, 8 | "allowSyntheticDefaultImports": true, 9 | "target": "es2017", 10 | "sourceMap": true, 11 | "outDir": "./dist", 12 | "baseUrl": "./", 13 | "noEmit": false, 14 | "strictBindCallApply": true, 15 | "strictPropertyInitialization": false, 16 | "paths": { 17 | "@/modules/*": ["src/modules/*"], 18 | "@/core/*": ["src/modules/core/*"], 19 | }, 20 | }, 21 | "exclude": ["node_modules", "test", "dist", "**/*spec.ts"], 22 | } 23 | -------------------------------------------------------------------------------- /config/debug.toml: -------------------------------------------------------------------------------- 1 | [io] 2 | [io.adc] 3 | enabled = false 4 | 5 | [io.can] 6 | enabled = false 7 | 8 | [io.gpio] 9 | enabled = false 10 | 11 | [io.i2c] 12 | enabled = false 13 | 14 | [io.pwm] 15 | enabled = false 16 | 17 | [io.spi] 18 | enabled = false 19 | 20 | [io.uart] 21 | enabled = false 22 | 23 | [sensors] 24 | [sensors.accelerometer] 25 | enabled = false 26 | bus = 2 27 | address = 29 28 | mux_channel = 0 29 | 30 | [sensors.temperature] 31 | enabled = false 32 | bus = 1 33 | address = 0x38 34 | 35 | [sensors.bms] 36 | enabled = false 37 | bus = "can1" 38 | 39 | [sensors.keyence] 40 | enabled = false 41 | pin = 1 42 | 43 | [motors] 44 | enabled = false 45 | bus = "can1" 46 | 47 | [aliases] 48 | "example" = "help" 49 | -------------------------------------------------------------------------------- /telemetry/packages/constants/src/index.ts: -------------------------------------------------------------------------------- 1 | export { pods, POD_IDS } from './pods/pods'; 2 | export type { PodId, Pods } from './pods/pods'; 3 | export { 4 | ALL_POD_STATES, 5 | PASSIVE_STATES, 6 | ACTIVE_STATES, 7 | NULL_STATES, 8 | FAILURE_STATES, 9 | getStateType, 10 | } from './pods/states'; 11 | export type { PodStateType, PodStateCategoryType } from './pods/states'; 12 | export { MODES, MODE_EXCLUDED_STATES } from './pods/modes'; 13 | export type { ModeType } from './pods/modes'; 14 | export { openMctObjectTypes } from './openmct/object-types/object-types'; 15 | 16 | export * as socket from './socket'; 17 | 18 | export { FAULT_LEVEL } from './faults/levels'; 19 | export type { FaultLevel } from './faults/levels'; 20 | -------------------------------------------------------------------------------- /lib/motors/can_processor.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "controller.hpp" 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | namespace hyped::motors { 12 | 13 | constexpr std::uint32_t kEmgyId = 0x80; 14 | constexpr std::uint32_t kSdoId = 0x580; 15 | constexpr std::uint32_t kNmtId = 0x700; 16 | 17 | class CanProcessor : public io::ICanProcessor { 18 | public: 19 | CanProcessor(core::Logger &logger, std::shared_ptr controller); 20 | core::Result processMessage(const io::CanFrame &frame) override; 21 | 22 | private: 23 | core::Logger &logger_; 24 | std::shared_ptr controller_; 25 | }; 26 | 27 | } // namespace hyped::motors 28 | -------------------------------------------------------------------------------- /lib/debug/repl_logger.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "terminal.hpp" 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | namespace hyped::debug { 10 | 11 | class ReplLogger : public core::ILogger { 12 | public: 13 | ReplLogger(const char *label, 14 | const core::LogLevel level, 15 | const core::ITimeSource &time_source_, 16 | Terminal &terminal); 17 | void log(core::LogLevel level, const char *format, ...) override; 18 | 19 | private: 20 | void printHead(const char *title); 21 | const char *const label_; 22 | const core::LogLevel level_; 23 | const core::ITimeSource &time_source_; 24 | Terminal &terminal_; 25 | }; 26 | 27 | } // namespace hyped::debug -------------------------------------------------------------------------------- /telemetry/packages/server/src/modules/core/config.ts: -------------------------------------------------------------------------------- 1 | import * as env from 'env-var'; 2 | 3 | export const ENV = env.get('ENV').default('development').asString(); 4 | 5 | export const INFLUX_URL = env.get('INFLUX_URL').required().asUrlString(); 6 | export const INFLUX_TOKEN = env.get('INFLUX_TOKEN').required().asString(); 7 | export const INFLUX_ORG = env.get('INFLUX_ORG').required().asString(); 8 | export const INFLUX_TELEMETRY_BUCKET = env 9 | .get('INFLUX_TELEMETRY_BUCKET') 10 | .required() 11 | .asString(); 12 | export const INFLUX_FAULTS_BUCKET = env 13 | .get('INFLUX_FAULTS_BUCKET') 14 | .required() 15 | .asString(); 16 | 17 | export const MQTT_BROKER_HOST = env 18 | .get('MQTT_BROKER_HOST') 19 | .required() 20 | .asString(); 21 | -------------------------------------------------------------------------------- /telemetry/packages/server/src/modules/openmct/data/OpenMCTData.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { HistoricalTelemetryDataController } from './historical/HistoricalTelemetryData.controller'; 3 | import { HistoricalTelemetryDataService } from './historical/HistoricalTelemetryData.service'; 4 | import { InfluxModule } from 'src/modules/influx/Influx.module'; 5 | import { RealtimeTelemetryDataGateway } from './realtime/RealtimeTelemetryData.gateway'; 6 | 7 | @Module({ 8 | imports: [InfluxModule], 9 | controllers: [HistoricalTelemetryDataController], 10 | providers: [HistoricalTelemetryDataService, RealtimeTelemetryDataGateway], 11 | exports: [RealtimeTelemetryDataGateway], 12 | }) 13 | export class OpenMCTDataModule {} 14 | -------------------------------------------------------------------------------- /telemetry/packages/types/src/index.ts: -------------------------------------------------------------------------------- 1 | export type { 2 | Measurement, 3 | RangeMeasurement, 4 | Limits, 5 | Pod, 6 | } from './pods/pods.types'; 7 | export type { 8 | OpenMctDictionary, 9 | OpenMctPod, 10 | OpenMctMeasurement, 11 | } from './openmct/openmct-dictionary.types'; 12 | export type { 13 | OpenMctObjectTypes, 14 | OpenMctObjectType, 15 | } from './openmct/openmct-object-types.types'; 16 | export type { OpenMctFault } from './openmct/openmct-fault.types'; 17 | export type { Unpacked } from './utils/Unpacked'; 18 | export type { 19 | RawLevitationHeight, 20 | LevitationHeight, 21 | LevitationHeightResponse, 22 | LaunchTimeResponse, 23 | StateResponse, 24 | HistoricalValueResponse, 25 | } from './server/responses'; 26 | -------------------------------------------------------------------------------- /telemetry/packages/server/src/modules/remote-logs/RemoteLogs.controller.ts: -------------------------------------------------------------------------------- 1 | import { Body, Controller, Param, Post } from '@nestjs/common'; 2 | import { RemoteLogsService } from './RemoteLogs.service'; 3 | 4 | @Controller('logs') 5 | export class RemoteLogsController { 6 | constructor(private remoteLogsService: RemoteLogsService) {} 7 | 8 | @Post() 9 | logUIMessage(@Body() body: { message: string }) { 10 | return this.remoteLogsService.logRemoteMessage(body.message); 11 | } 12 | 13 | @Post(':podId') 14 | logUIMessageWithPodID( 15 | @Param('podId') podId: string, 16 | @Body() body: { message: string }, 17 | ) { 18 | return this.remoteLogsService.logRemoteMessageWithPodID( 19 | podId, 20 | body.message, 21 | ); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /telemetry/packages/server/test/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { INestApplication } from '@nestjs/common'; 3 | import * as request from 'supertest'; 4 | import { AppModule } from './../src/app.module'; 5 | 6 | describe('AppController (e2e)', () => { 7 | let app: INestApplication; 8 | 9 | beforeEach(async () => { 10 | const moduleFixture: TestingModule = await Test.createTestingModule({ 11 | imports: [AppModule], 12 | }).compile(); 13 | 14 | app = moduleFixture.createNestApplication(); 15 | await app.init(); 16 | }); 17 | 18 | it('/ (GET)', () => { 19 | return request(app.getHttpServer()) 20 | .get('/') 21 | .expect(200) 22 | .expect('Hello World!'); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /telemetry/packages/ui/app/providers.tsx: -------------------------------------------------------------------------------- 1 | import { LiveLogsProvider } from './context/live-logs'; 2 | import { MQTTProvider } from './context/mqtt'; 3 | import { PodsProvider } from './context/pods'; 4 | import { config } from './config'; 5 | import { QoS } from './types/mqtt'; 6 | import { ErrorProvider } from './context/errors'; 7 | 8 | /** 9 | * Provider for all the contexts. 10 | * @param children The children to render 11 | */ 12 | export const Providers = ({ children }: { children: React.ReactNode }) => ( 13 | 14 | 15 | 16 | {children} 17 | 18 | 19 | 20 | ); 21 | -------------------------------------------------------------------------------- /telemetry/packages/fake/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@hyped/telemetry-fake", 3 | "private": true, 4 | "version": "0.0.1", 5 | "scripts": { 6 | "dev:test": "node dist/index.js", 7 | "build": "tsdx build", 8 | "build:fake": "tsdx build", 9 | "lint": "eslint \"src/**/*.ts\" --max-warnings 0 --report-unused-disable-directives", 10 | "lint:fix": "eslint \"src/**/*.ts\" --fix" 11 | }, 12 | "dependencies": { 13 | "@hyped/telemetry-constants": "workspace:*", 14 | "mqtt": "^5.3.6", 15 | "tslib": "^2.5.3" 16 | }, 17 | "devDependencies": { 18 | "@hyped/eslint-config": "workspace:*", 19 | "@hyped/telemetry-types": "workspace:*", 20 | "@hyped/tsconfig": "workspace:*", 21 | "tsdx": "^0.14.1", 22 | "typescript": "^5.3.3" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lib/sensors/keyence.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | namespace hyped::sensors { 10 | class Keyence { 11 | public: 12 | static std::optional> create( 13 | core::ILogger &logger, const std::shared_ptr &gpio, const std::uint8_t pin); 14 | 15 | Keyence(core::ILogger &logger, std::shared_ptr gpio_reader); 16 | 17 | std::uint8_t getStripeCount() const; 18 | core::Result updateStripeCount(); 19 | 20 | private: 21 | std::uint8_t stripe_count_; 22 | std::shared_ptr gpio_reader_; 23 | core::ILogger &logger_; 24 | core::DigitalSignal last_signal_; 25 | }; 26 | 27 | } // namespace hyped::sensors 28 | -------------------------------------------------------------------------------- /telemetry/packages/fake/src/types.ts: -------------------------------------------------------------------------------- 1 | import type { RangeMeasurement } from '@hyped/telemetry-types'; 2 | /** 3 | * Unique variable readinfgs each sensor provides 4 | * E.g. accelerometers generate values for acceleration, displacement and velocity 5 | */ 6 | export type LiveReading = RangeMeasurement & { readings: Readings }; 7 | 8 | export type SensorData = Record; 9 | 10 | /** 11 | * Sensor property containing values for each of its measured quantities 12 | */ 13 | export type Readings = { 14 | [measurement: string]: number; 15 | }; 16 | 17 | /** 18 | * Return type for sensor class instantiation 19 | */ 20 | export type BaseSensor = { 21 | getData: (t: number) => Readings; 22 | getRandomData: (prevValue: number, readings: Readings) => Readings; 23 | }; 24 | -------------------------------------------------------------------------------- /telemetry/packages/server/src/modules/controls/PodControls.controller.ts: -------------------------------------------------------------------------------- 1 | import { Controller, Param, Post, Query } from '@nestjs/common'; 2 | import { PodControlsService } from './PodControls.service'; 3 | 4 | @Controller('pods/:podId/controls') 5 | export class PodControlsController { 6 | constructor(private podControlsService: PodControlsService) {} 7 | 8 | @Post('levitation-height') 9 | setLevitationHeight( 10 | @Param('podId') podId: string, 11 | @Query('height') height: number, 12 | ) { 13 | return this.podControlsService.setLevitationHeight(height, podId); 14 | } 15 | 16 | @Post(':control') 17 | controlPod(@Param('control') control: string, @Param('podId') podId: string) { 18 | return this.podControlsService.sendControlMessage(control, podId); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /telemetry/patches/@nestjs__common@9.4.2.patch: -------------------------------------------------------------------------------- 1 | diff --git a/services/logger.service.d.ts b/services/logger.service.d.ts 2 | index 8e52c6852b6f4be2d3bbe39ea0296aff95c6808d..89ab4f1a9ad0c8641736d1f9610d79a6b55c8b40 100644 3 | --- a/services/logger.service.d.ts 4 | +++ b/services/logger.service.d.ts 5 | @@ -21,11 +21,11 @@ export interface LoggerService { 6 | /** 7 | * Write a 'debug' level log. 8 | */ 9 | - debug?(message: any, ...optionalParams: any[]): any; 10 | + debug(message: any, ...optionalParams: any[]): any; 11 | /** 12 | * Write a 'verbose' level log. 13 | */ 14 | - verbose?(message: any, ...optionalParams: any[]): any; 15 | + verbose(message: any, ...optionalParams: any[]): any; 16 | /** 17 | * Set log levels. 18 | * @param levels log levels -------------------------------------------------------------------------------- /telemetry/packages/constants/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@hyped/telemetry-constants", 3 | "private": true, 4 | "version": "1.0.0", 5 | "main": "dist/index.js", 6 | "types": "dist/index.d.ts", 7 | "module": "dist/telemetry-constants.esm.js", 8 | "files": [ 9 | "dist", 10 | "src" 11 | ], 12 | "scripts": { 13 | "start": "tsdx watch", 14 | "build": "tsdx build", 15 | "lint": "eslint \"src/**/*.ts\" --max-warnings 0 --report-unused-disable-directives", 16 | "lint:fix": "eslint \"src/**/*.ts\" --fix" 17 | }, 18 | "devDependencies": { 19 | "@hyped/telemetry-types": "workspace:*", 20 | "@hyped/eslint-config": "workspace:*", 21 | "@hyped/tsconfig": "workspace:*", 22 | "tsdx": "^0.14.1", 23 | "tslib": "^2.5.3", 24 | "typescript": "^5.3.3" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /telemetry/packages/ui/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HYPED24 | Telemetry 6 | 23 | 24 | 25 |
26 | 32 |
33 | 34 | 35 | -------------------------------------------------------------------------------- /lib/io/uart.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | namespace hyped::io { 8 | 9 | // TODOLater: make both these methods not be pointers 10 | class IUart { 11 | public: 12 | /** 13 | * @brief Sends a byte array over the UART bus. 14 | * @param tx Pointer to the byte array to be sent. 15 | * @param length Length of the byte array. 16 | */ 17 | virtual core::Result sendBytes(const char *tx, const std::uint8_t length) = 0; 18 | 19 | /** 20 | * @brief Receives a byte array over the UART bus. 21 | * @param rx Pointer to the byte array to be received. 22 | * @param length Length of the byte array. 23 | */ 24 | virtual core::Result readBytes(unsigned char *rx, const std::uint8_t length) = 0; 25 | }; 26 | 27 | } // namespace hyped::io 28 | -------------------------------------------------------------------------------- /telemetry/packages/constants/src/pods/modes.ts: -------------------------------------------------------------------------------- 1 | import { ACTIVE_STATES, PodStateType } from './states'; 2 | 3 | export const MODES = { 4 | ALL_SYSTEMS_ON: 'ALL_SYSTEMS_ON', 5 | LEVITATION_ONLY: 'LEVITATION_ONLY', 6 | LIM_ONLY: 'LIM_ONLY', 7 | }; 8 | 9 | export type ModeType = keyof typeof MODES; 10 | 11 | type ModeStates = Record; 12 | 13 | export const MODE_EXCLUDED_STATES: ModeStates = { 14 | ALL_SYSTEMS_ON: [], 15 | LEVITATION_ONLY: [ 16 | ACTIVE_STATES.READY_FOR_LAUNCH, 17 | ACTIVE_STATES.ACCELERATE, 18 | ACTIVE_STATES.LIM_BRAKE, 19 | ACTIVE_STATES.FRICTION_BRAKE, 20 | ACTIVE_STATES.BATTERY_RECHARGE, 21 | ], 22 | LIM_ONLY: [ 23 | ACTIVE_STATES.READY_FOR_LEVITATION, 24 | ACTIVE_STATES.BEGIN_LEVITATION, 25 | ACTIVE_STATES.STOP_LEVITATION, 26 | ], 27 | }; 28 | -------------------------------------------------------------------------------- /.github/workflows/telemetry.yml: -------------------------------------------------------------------------------- 1 | name: Telemetry 2 | 3 | on: push 4 | 5 | defaults: 6 | run: 7 | working-directory: telemetry 8 | 9 | jobs: 10 | telemetry: 11 | name: Telemetry build and lint 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v3 15 | 16 | - name: Docker 17 | uses: docker/setup-buildx-action@v3 18 | 19 | - name: Build, lint and test 20 | run: ./telemetry.sh ci -m 21 | 22 | telemetry-formatting: 23 | name: Telemetry formatting 24 | runs-on: ubuntu-latest 25 | steps: 26 | - uses: actions/checkout@v3 27 | 28 | - name: Install pnpm and Prettier 29 | run: | 30 | npm install -g pnpm 31 | npm install -g prettier@3.2.4 32 | 33 | - name: Check Formatting 34 | run: pnpm run format:check 35 | -------------------------------------------------------------------------------- /cc/Dockerfile.crosscompile: -------------------------------------------------------------------------------- 1 | FROM arm64v8/ubuntu:latest 2 | ARG DEBIAN_FRONTEND=noninteractive 3 | 4 | # Install dependencies 5 | RUN apt-get update && \ 6 | apt-get install -y git clang libboost-all-dev libeigen3-dev rapidjson-dev build-essential gcc make cmake libssl-dev libncurses5-dev libncursesw5-dev sudo 7 | 8 | # Install Paho C++ 9 | WORKDIR /home 10 | RUN git clone --recurse-submodules https://github.com/eclipse/paho.mqtt.cpp.git 11 | WORKDIR /home/paho.mqtt.cpp 12 | RUN git checkout v1.3.2 13 | RUN cmake -Bbuild -H. -DPAHO_WITH_MQTT_C=ON -DPAHO_BUILD_STATIC=ON -DPAHO_BUILD_DOCUMENTATION=OFF -DPAHO_BUILD_SAMPLES=OFF 14 | RUN sudo cmake --build build/ --target install 15 | RUN sudo ldconfig 16 | 17 | WORKDIR /home/hyped_entrypoint 18 | 19 | COPY entry.sh ./ 20 | 21 | ENTRYPOINT [ "/home/hyped_entrypoint/entry.sh" ] 22 | CMD ["bash"] -------------------------------------------------------------------------------- /telemetry/packages/ui/app/main.tsx: -------------------------------------------------------------------------------- 1 | import '@fontsource/ibm-plex-mono'; 2 | import '@fontsource/raleway'; 3 | import * as React from 'react'; 4 | import ReactDOM from 'react-dom/client'; 5 | import { Toaster } from 'react-hot-toast'; 6 | import 'victormono'; 7 | import { App } from './App'; 8 | import './globals.css'; 9 | import { Providers } from './providers'; 10 | import { Error } from './components/error'; 11 | 12 | ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( 13 | 14 | 15 | 16 | 23 | 24 | 25 | , 26 | ); 27 | -------------------------------------------------------------------------------- /lib/debug/commands/keyence_commands.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | namespace hyped::debug { 10 | 11 | class KeyenceCommands { 12 | public: 13 | /** 14 | * @brief Add commands to the REPL for reading from keyence stripe counters 15 | * 16 | * @param logger 17 | * @param repl 18 | * @param config 19 | * @return core::Result kSuccess if commands were added successfully, kFailure otherwise 20 | */ 21 | static core::Result addCommands(core::ILogger &logger, 22 | std::shared_ptr &repl, 23 | core::ITimeSource &time, 24 | toml::v3::node_view config); 25 | }; 26 | 27 | } // namespace hyped::debug 28 | -------------------------------------------------------------------------------- /lib/core/timer.cpp: -------------------------------------------------------------------------------- 1 | #include "timer.hpp" 2 | 3 | namespace hyped::core { 4 | 5 | Timer::Timer(const ITimeSource &time) : time_(time) 6 | { 7 | } 8 | 9 | Duration Timer::measureExecutionTime(const std::function &task) 10 | { 11 | const auto before = time_.now(); 12 | task(); 13 | const auto after = time_.now(); 14 | return after - before; 15 | } 16 | 17 | Duration Timer::elapsed(const TimePoint current_timepoint, const TimePoint previous_timepoint) 18 | { 19 | return current_timepoint - previous_timepoint; 20 | } 21 | 22 | Float Timer::elapsedTimeInSeconds(const Duration time_elapsed) 23 | { 24 | const std::uint64_t nanoseconds_elapsed 25 | = std::chrono::duration_cast(time_elapsed).count(); 26 | return static_cast(nanoseconds_elapsed) / kOneSecond; 27 | } 28 | 29 | } // namespace hyped::core 30 | -------------------------------------------------------------------------------- /telemetry/packages/tsconfig/base.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "display": "Base", 4 | "compilerOptions": { 5 | "composite": false, 6 | "declaration": true, 7 | "declarationMap": true, 8 | "esModuleInterop": true, 9 | "forceConsistentCasingInFileNames": true, 10 | "inlineSources": false, 11 | "isolatedModules": true, 12 | "module": "ESNext", 13 | "moduleResolution": "node", 14 | "noUnusedLocals": false, 15 | "noUnusedParameters": false, 16 | "preserveWatchOutput": true, 17 | "skipLibCheck": true, 18 | "strict": true, 19 | "noEmit": true, 20 | "strictNullChecks": true, 21 | "resolveJsonModule": true, 22 | "noFallthroughCasesInSwitch": true, 23 | "noImplicitAny": true, 24 | "incremental": true 25 | }, 26 | "exclude": ["node_modules"] 27 | } 28 | -------------------------------------------------------------------------------- /telemetry/packages/ui/app/components/views/state-machine/types.ts: -------------------------------------------------------------------------------- 1 | import { Node, Position, Edge, SmoothStepPathOptions } from 'reactflow'; 2 | 3 | /** 4 | * Data passed to custom nodes 5 | */ 6 | export type NodeDataType = { 7 | label: string; 8 | sourcePositions?: { 9 | position: Position; 10 | id: string; 11 | }[]; 12 | targetPositions?: { 13 | position: Position; 14 | id: string; 15 | }[]; 16 | active?: boolean; 17 | }; 18 | 19 | export type CustomNodeType = Omit & { 20 | data: NodeDataType & { 21 | sourcePositions: { 22 | position: Position; 23 | id: string; 24 | }[]; 25 | }; 26 | }; 27 | 28 | export type CustomEdgeType = Omit & { 29 | sourceHandle: string; 30 | targetHandle: string; 31 | } & { 32 | pathOptions?: SmoothStepPathOptions; 33 | }; 34 | -------------------------------------------------------------------------------- /telemetry/packages/server/src/modules/openmct/data/historical/HistoricalTelemetryData.controller.ts: -------------------------------------------------------------------------------- 1 | import { Controller, Get, Param, Query } from '@nestjs/common'; 2 | import { HistoricalTelemetryDataService } from './HistoricalTelemetryData.service'; 3 | 4 | @Controller('openmct/data/historical') 5 | export class HistoricalTelemetryDataController { 6 | constructor(private historicalDataService: HistoricalTelemetryDataService) {} 7 | 8 | @Get('pods/:podId/measurements/:measurementKey') 9 | getHistoricalReading( 10 | @Param('podId') podId: string, 11 | @Param('measurementKey') measurementKey: string, 12 | @Query('start') start: string, 13 | @Query('end') end: string, 14 | ) { 15 | return this.historicalDataService.getHistoricalReading( 16 | podId, 17 | measurementKey, 18 | start, 19 | end, 20 | ); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /telemetry/turbo.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://turborepo.org/schema.json", 3 | "pipeline": { 4 | "start": { 5 | "cache": false, 6 | "persistent": true 7 | }, 8 | "dev": { 9 | "dependsOn": ["^build"], 10 | "cache": false, 11 | "persistent": true 12 | }, 13 | "dev:test": { 14 | "dependsOn": ["^build"], 15 | "cache": false, 16 | "persistent": true 17 | }, 18 | "e2e:test": { 19 | "dependsOn": ["^build"], 20 | "cache": false, 21 | "persistent": true 22 | }, 23 | "lint": { 24 | "dependsOn": ["^build"] 25 | }, 26 | "lint:fix": { 27 | "dependsOn": ["^build"] 28 | }, 29 | "build": { 30 | "outputs": ["dist/**"], 31 | "dependsOn": ["^build"] 32 | }, 33 | "build:fake": { 34 | "dependsOn": ["^build"] 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /telemetry/packages/server/src/modules/openmct/faults/Fault.module.ts: -------------------------------------------------------------------------------- 1 | import { InfluxModule } from '@/modules/influx/Influx.module'; 2 | import { Module } from '@nestjs/common'; 3 | import { FaultService } from './Fault.service'; 4 | import { HistoricalFaultDataService } from './data/historical/HistoricalFaultData.service'; 5 | import { RealtimeFaultDataGateway } from './data/realtime/RealtimeFaultData.gateway'; 6 | import { HistoricalFaultsDataController } from './data/historical/HistoricalFaultData.controller'; 7 | import { FaultsController } from './Fault.controller'; 8 | 9 | @Module({ 10 | imports: [InfluxModule], 11 | controllers: [FaultsController, HistoricalFaultsDataController], 12 | providers: [ 13 | FaultService, 14 | HistoricalFaultDataService, 15 | RealtimeFaultDataGateway, 16 | ], 17 | exports: [FaultService], 18 | }) 19 | export class FaultModule {} 20 | -------------------------------------------------------------------------------- /telemetry/packages/ui/app/lib/logger.ts: -------------------------------------------------------------------------------- 1 | import { http } from 'openmct/core/http'; 2 | 3 | /** 4 | * Logs a message to the UI log 5 | * @param message The message to log 6 | * @param podId The pod ID to log with (optional) 7 | */ 8 | export const log = (message: string, podId?: string) => { 9 | if (podId) { 10 | // eslint-disable-next-line no-console 11 | console.log(`[LOG] (${podId}) ${message}`); 12 | void http.post(`logs/${podId}`, { 13 | body: JSON.stringify({ message }), 14 | headers: { 15 | 'content-type': 'application/json', 16 | }, 17 | }); 18 | } else { 19 | // eslint-disable-next-line no-console 20 | console.log(`[LOG] ${message}`); 21 | void http.post(`logs`, { 22 | body: JSON.stringify({ message }), 23 | headers: { 24 | 'content-type': 'application/json', 25 | }, 26 | }); 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /telemetry/packages/e2e-tests/tests/example.spec.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from '@playwright/test'; 2 | import { client, validateMqttMessage } from '../lib/mqtt'; 3 | 4 | test('has title', async ({ page }) => { 5 | await page.goto('http://localhost:5173'); 6 | 7 | await expect(page).toHaveTitle('HYPED24 | Telemetry'); 8 | }); 9 | 10 | test('example mqtt test', async () => { 11 | await validateMqttMessage( 12 | // Pass in the function which will trigger the MQTT message to be sent. 13 | // For example, this could be pushing a button on the GUI. 14 | () => { 15 | client.publish('hello', 'world'); 16 | }, 17 | // The validation function. Here you can validate that the topic and message body received is as expected. 18 | (topic, message) => { 19 | expect(topic).toBe('hello'); 20 | expect(message.toString()).toBe('world'); 21 | }, 22 | ); 23 | }); 24 | -------------------------------------------------------------------------------- /telemetry/packages/ui/app/components/ui/label.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import * as LabelPrimitive from '@radix-ui/react-label'; 3 | import { cva, type VariantProps } from 'class-variance-authority'; 4 | 5 | import { cn } from '@/lib/utils'; 6 | 7 | const labelVariants = cva( 8 | 'font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70', 9 | ); 10 | 11 | const Label = React.forwardRef< 12 | React.ElementRef, 13 | React.ComponentPropsWithoutRef & 14 | VariantProps 15 | >(({ className, ...props }, ref) => ( 16 | // @ts-ignore 17 | 23 | )); 24 | Label.displayName = LabelPrimitive.Root.displayName; 25 | 26 | export { Label }; 27 | -------------------------------------------------------------------------------- /lib/sensors/keyence_node.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "keyence.hpp" 4 | 5 | #include "core/mqtt.hpp" 6 | #include "core/types.hpp" 7 | #include 8 | 9 | namespace hyped::sensors { 10 | 11 | class KeyenceNode { 12 | public: 13 | static core::Result startNode(toml::v3::node_view config, 14 | const std::string &mqtt_ip, 15 | const std::uint32_t mqtt_port); 16 | KeyenceNode(core::Logger &logger, 17 | core::ITimeSource &time, 18 | std::shared_ptr mqtt, 19 | std::shared_ptr keyence); 20 | void run(); 21 | 22 | private: 23 | void requestFailure(); 24 | 25 | core::Logger logger_; 26 | core::ITimeSource &time_; 27 | std::shared_ptr mqtt_; 28 | std::shared_ptr keyence_; 29 | }; 30 | 31 | } // namespace hyped::sensors 32 | -------------------------------------------------------------------------------- /telemetry/packages/ui/app/components/ui/textarea.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | import { cn } from '@/lib/utils'; 4 | 5 | export interface TextareaProps 6 | extends React.TextareaHTMLAttributes {} 7 | 8 | const Textarea = React.forwardRef( 9 | ({ className, ...props }, ref) => { 10 | return ( 11 |