diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000000000000000000000000000000000000..827c89b435020ccdca9a15eb06a972ac5947c742 --- /dev/null +++ b/.clang-format @@ -0,0 +1,13 @@ +{ + BasedOnStyle: Google, + AccessModifierOffset: -4, + AlignConsecutiveAssignments: true, + AllowShortIfStatementsOnASingleLine: false, + AllowShortLoopsOnASingleLine: false, + BreakBeforeBraces: Allman, + ColumnLimit: 80, + ConstructorInitializerAllOnOneLineOrOnePerLine: false, + IndentCaseLabels: true, + IndentWidth: 4, + KeepEmptyLinesAtTheStartOfBlocks: true, +} diff --git a/.gitignore b/.gitignore index 259148fa18f9fb7ef58563f4ff15fc7b172339fb..45f7d5708d689f77c2f325da11361bb2cbfbaf8e 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,7 @@ *.exe *.out *.app + +# ide folder & virtual environments +.venv/ +.vscode \ No newline at end of file diff --git a/utils/BitPacker.h b/bitpacking/BitPacker.h similarity index 100% rename from utils/BitPacker.h rename to bitpacking/BitPacker.h diff --git a/bitpacking/generator.py b/bitpacking/generator.py new file mode 100644 index 0000000000000000000000000000000000000000..d79917b8b6e80c3e8af68d9d212700ffef7be44b --- /dev/null +++ b/bitpacking/generator.py @@ -0,0 +1,344 @@ +#!/usr/bin/python3 + +# Copyright (c) 2018 Skyward Experimental Rocketry +# Authors: Luca Erbetta +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# + +from googleapiclient.discovery import build +from httplib2 import Http +from oauth2client import file, client, tools + +import math +import re +import datetime +import sys +from os.path import join +import os +from string import Template + +SCOPES = "https://www.googleapis.com/auth/spreadsheets.readonly" + +service = None + +# Spreadsheet file used to generate the events. The can be found in the link +# to the spreadsheet, for example: +# https://docs.google.com/spreadsheets/d/184kR2OAD7yWV0fYJdiGUDmHmy5_prY3nr-XgNA0Uge0/ +# --> +# 184kR2OAD7yWV0fYJdiGUDmHmy5_prY3nr-XgNA0Uge0 +spreadsheet_id = "1D5m5WrNXxAL8XA6CKyfe5JcQ5IRnpNHg5ZG5bzt5G4I" +output_folder = "hermes/" + +RANGE_FIELD_NAME = "{sheet_name}!A2:A" +RANGE_FIELD_TYPE = "{sheet_name}!B2:B" +RANGE_FIELD_SIZE = "{sheet_name}!C2:C" +RANGE_FIELD_MIN = "{sheet_name}!D2:D" +RANGE_FIELD_MAX = "{sheet_name}!E2:E" +RANGE_REPEAT_NUM = "{sheet_name}!J1" +RANGE_MAV_NAME = "{sheet_name}!J2" + +with open("templates/TelemetryPacker.h.template", "r") as template_file: + tm_packer_template = Template(template_file.read()) +with open("templates/packFunction.cpp.template", "r") as template_file: + pack_fun_template = Template(template_file.read()) +with open("templates/unpackFunction.cpp.template", "r") as template_file: + unpack_fun_template = Template(template_file.read()) +with open("templates/ConversionFunctions.h.template", "r") as template_file: + convfuns_template = Template(template_file.read()) + + +def auth(): + try: + store = file.Storage("store.json") + creds = store.get() + if not creds or creds.invalid: + flow = client.flow_from_clientsecrets("credentials.json", SCOPES) + creds = tools.run_flow(flow, store) + + global service + service = build("sheets", "v4", http=creds.authorize(Http())) + return True + except: + print("Authentication error:", sys.exc_info()[0]) + return False + + +def listSheets(): + result = service.spreadsheets().get(spreadsheetId=spreadsheet_id).execute() + + return [x["properties"]["title"] for x in result["sheets"]] + + +def loadPacketFromSheet(packet_name: str): + # Strip 'Packet' at the end + packet = {"name": packet_name[0:-6]} + + result = ( + service.spreadsheets() + .values() + .get( + spreadsheetId=spreadsheet_id, + range=RANGE_FIELD_NAME.format(sheet_name=packet_name), + ) + .execute() + ) + fields = [x[0] for x in result["values"]] + + result = ( + service.spreadsheets() + .values() + .get( + spreadsheetId=spreadsheet_id, + range=RANGE_FIELD_SIZE.format(sheet_name=packet_name), + ) + .execute() + ) + sizes = [int(x[0]) for x in result["values"]] + + result = ( + service.spreadsheets() + .values() + .get( + spreadsheetId=spreadsheet_id, + range=RANGE_FIELD_TYPE.format(sheet_name=packet_name), + ) + .execute() + ) + types = [x[0] for x in result["values"]] + + result = ( + service.spreadsheets() + .values() + .get( + spreadsheetId=spreadsheet_id, + range=RANGE_FIELD_MIN.format(sheet_name=packet_name), + ) + .execute() + ) + rmins = [float(x[0]) for x in result["values"]] + + result = ( + service.spreadsheets() + .values() + .get( + spreadsheetId=spreadsheet_id, + range=RANGE_FIELD_MAX.format(sheet_name=packet_name), + ) + .execute() + ) + rmaxs = [float(x[0]) for x in result["values"]] + + + + result = ( + service.spreadsheets() + .values() + .get( + spreadsheetId=spreadsheet_id, + range=RANGE_REPEAT_NUM.format(sheet_name=packet_name), + ) + .execute() + ) + + indices = [0] + for i in range(1, len(sizes)): + indices += [indices[i - 1] + sizes[i - 1]] + + packet["repeat"] = int(result["values"][0][0]) + + result = ( + service.spreadsheets() + .values() + .get( + spreadsheetId=spreadsheet_id, + range=RANGE_MAV_NAME.format(sheet_name=packet_name), + ) + .execute() + ) + + indices = [0] + for i in range(1, len(sizes)): + indices += [indices[i - 1] + sizes[i - 1]] + + packet["mav_tm_name"] = result["values"][0][0] + + packet["fields"] = [ + {"name": f, "size": s, "index": i, "type": t, "range": (rmin, rmax)} + for f, s, i, t, rmin, rmax in zip(fields, sizes, indices, types, rmins, rmaxs) + ] + packet["partial_size"] = sum(sizes) + packet["total_size"] = math.ceil((sum(sizes) * packet["repeat"]) / 8) + return packet + + +def generatePackFunction(packet_data, field): + convert_fun_template = Template( + "${telemetry_name}Conversion::${field_name_ccase}ToBits" + ) + + subs = {} + + subs["max_index"] = packet_data["repeat"] + + subs["type"] = field["type"] + name = field["name"].replace("_", " ").title().replace(" ", "") + name = name[0].lower() + name[1:] + subs["convert_fun"] = convert_fun_template.substitute( + telemetry_name=packet_data["name"], field_name_ccase=name, + ) + subs["field_name_lcase"] = field["name"].lower() + subs["field_name_ccase"] = field["name"].replace("_", " ").title().replace(" ", "") + subs["field_name_ucase"] = field["name"].upper() + subs["mav_tm_name"] = packet_data["mav_tm_name"] + + return pack_fun_template.substitute(**subs) + + +def generateUnpackFunction(packet_data, field): + convert_fun_template = Template( + "${telemetry_name}Conversion::bitsTo${field_name_ccase}" + ) + + subs = {} + subs["max_index"] = packet_data["repeat"] + + subs["type"] = field["type"] + subs["convert_fun"] = convert_fun_template.substitute( + telemetry_name=packet_data["name"], + field_name_ccase=field["name"].replace("_", " ").title().replace(" ", ""), + ) + subs["field_name_lcase"] = field["name"].lower() + subs["field_name_ccase"] = field["name"].replace("_", " ").title().replace(" ", "") + subs["field_name_ucase"] = field["name"].upper() + subs["mav_tm_name"] = packet_data["mav_tm_name"] + + return unpack_fun_template.substitute(**subs) + + +def generatePackerClass(packet_data, output_folder): + index_template = Template(" INDEX_$field_name = $index") + size_template = Template(" SIZE_$field_name = $size") + + indices = "" + sizes = "" + pack_funcs = "" + unpack_funcs = "" + for f in packet_data["fields"]: + indices += index_template.substitute(field_name=f["name"].upper(), index=f["index"]) + sizes += size_template.substitute(field_name=f["name"].upper(), size=f["size"]) + + if f != packet_data["fields"][-1]: + indices += ",\n" + sizes += ",\n" + + pack_funcs += generatePackFunction(packet_data, f) + unpack_funcs += generateUnpackFunction(packet_data, f) + + out = tm_packer_template.substitute( + mav_tm_name=packet_data["mav_tm_name"], + telemetry_name_ccase=packet_data["name"], + tm_total_size=packet_data["total_size"], + tm_partial_size=packet_data["partial_size"], + field_indices=indices, + field_sizes=sizes, + pack_functions=pack_funcs, + unpack_functions=unpack_funcs, + ) + + with open(join(output_folder, packet_data["name"] + "Packer.h"), "w") as out_file: + out_file.write(out) + + +def generateConversionFunctions(packet_data): + class_template = Template( + "\nclass ${telemetry_name_ccase}Conversion\n{\npublic:\n $functions\n};\n\n\n" + ) + + frombits_template = Template( + "\n static $type bitsTo${field_name_ccase}(uint64_t bits)\n " + + "{\n return ($type)bits;\n }\n" + ) + + tobits_template = Template( + "\n static uint64_t ${field_name_ccase}ToBits($type $field_name_lcase)" + + "\n {\n return (uint64_t)$field_name_lcase;\n }\n\n" + ) + + frombits_template_ranged = Template( + "\n static $type bitsTo${field_name_ccase}(uint64_t bits)\n " + + "{\n return undiscretizeRange<$type>(bits, $rmin, $rmax, $res);\n }\n" + ) + + tobits_template_ranged = Template( + "\n static uint64_t ${field_name_ccase}ToBits($type $field_name_lcase)" + + "\n {\n return discretizeRange<$type>($field_name_lcase, $rmin, $rmax, $res);\n }\n\n" + ) + + funs = "" + for field in packet_data["fields"]: + subs = {} + subs["type"] = field["type"] + subs["field_name_lcase"] = field["name"].lower() + subs["field_name_ccase"] = field["name"].replace("_", " ").title().replace(" ", "") + subs["field_name_ucase"] = field["name"].upper() + subs["rmin"] = field["range"][0] + subs["rmax"] = field["range"][1] + subs["res"] = 2**field["size"] + if subs["rmax"] - subs["rmin"] != 0: + funs += frombits_template_ranged.substitute(**subs) + + subs["field_name_ccase"] = ( + subs["field_name_ccase"][0].lower() + subs["field_name_ccase"][1:] + ) + funs += tobits_template_ranged.substitute(**subs) + else: + funs += frombits_template.substitute(**subs) + + subs["field_name_ccase"] = ( + subs["field_name_ccase"][0].lower() + subs["field_name_ccase"][1:] + ) + funs += tobits_template.substitute(**subs) + + return class_template.substitute( + functions=funs, telemetry_name_ccase=packet_data["name"] + ) + + +print("Skyward telemetry packet generator") +print("Google sheets API auth in progress...") + +if auth(): + print("Auth successfull.") +else: + print("Authentication failed.") + exit() + +sheets = listSheets() +packet_sheets = [x for x in sheets if x.endswith("Packet")] + +conversion_classes = "" +for p in packet_sheets: + data = loadPacketFromSheet(p) + generatePackerClass(data, output_folder) + conversion_classes += generateConversionFunctions(data) + +with open(join(output_folder, "ConversionFuncions_generated.h"), "w") as out_file: + out_file.write(convfuns_template.substitute(classes=conversion_classes)) + diff --git a/bitpacking/hermes/ConversionFunctions.h b/bitpacking/hermes/ConversionFunctions.h new file mode 100644 index 0000000000000000000000000000000000000000..03284ea516c5be4e07a2e214564fa8528f02de5d --- /dev/null +++ b/bitpacking/hermes/ConversionFunctions.h @@ -0,0 +1,533 @@ +/** + * Copyright (c) 2019 Skyward Experimental Rocketry + * Authors: Luca Erbetta + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once +#include <cstdint> +#include <type_traits> + +template<typename T> +inline uint64_t discretizeRange(T value, T min, T max, unsigned int resolution) +{ + static_assert(std::is_arithmetic<T>::value); + + if (value < min) + { + return 0; + } + else if (value > max) + { + return resolution - 1; + } + + return (uint64_t)((value - min) * resolution / (max - min)); + +} + +template <typename T> +inline T undiscretizeRange(uint64_t value, T min, T max, + unsigned int resolution) +{ + static_assert(std::is_arithmetic<T>::value); + + return value * (max - min) / resolution + min; +} + + + +class HighRateTMConversion +{ +public: + + static long long bitsToTimestamp(uint64_t bits) + { + return (long long)bits; + } + + static uint64_t timestampToBits(long long timestamp) + { + return (uint64_t)timestamp; + } + + + static float bitsToPressureAda(uint64_t bits) + { + return undiscretizeRange<float>(bits, 50000.0, 105000.0, 4096); + } + + static uint64_t pressureAdaToBits(float pressure_ada) + { + return discretizeRange<float>(pressure_ada, 50000.0, 105000.0, 4096); + } + + + static float bitsToPressureDigi(uint64_t bits) + { + return undiscretizeRange<float>(bits, 50000.0, 105000.0, 8192); + } + + static uint64_t pressureDigiToBits(float pressure_digi) + { + return discretizeRange<float>(pressure_digi, 50000.0, 105000.0, 8192); + } + + + static float bitsToMslAltitude(uint64_t bits) + { + return (float)bits; + } + + static uint64_t mslAltitudeToBits(float msl_altitude) + { + return (uint64_t)msl_altitude; + } + + + static float bitsToAglAltitude(uint64_t bits) + { + return undiscretizeRange<float>(bits, -500.0, 3000.0, 512); + } + + static uint64_t aglAltitudeToBits(float agl_altitude) + { + return discretizeRange<float>(agl_altitude, -500.0, 3000.0, 512); + } + + + static float bitsToVertSpeed(uint64_t bits) + { + return undiscretizeRange<float>(bits, -512.0, 512.0, 1024); + } + + static uint64_t vertSpeedToBits(float vert_speed) + { + return discretizeRange<float>(vert_speed, -512.0, 512.0, 1024); + } + + + static float bitsToVertSpeed2(uint64_t bits) + { + return undiscretizeRange<float>(bits, -512.0, 512.0, 1024); + } + + static uint64_t vertSpeed2ToBits(float vert_speed_2) + { + return discretizeRange<float>(vert_speed_2, -512.0, 512.0, 1024); + } + + + static float bitsToAccX(uint64_t bits) + { + return undiscretizeRange<float>(bits, -16.0, 16.0, 2048); + } + + static uint64_t accXToBits(float acc_x) + { + return discretizeRange<float>(acc_x, -16.0, 16.0, 2048); + } + + + static float bitsToAccY(uint64_t bits) + { + return undiscretizeRange<float>(bits, -16.0, 16.0, 2048); + } + + static uint64_t accYToBits(float acc_y) + { + return discretizeRange<float>(acc_y, -16.0, 16.0, 2048); + } + + + static float bitsToAccZ(uint64_t bits) + { + return undiscretizeRange<float>(bits, -16.0, 16.0, 2048); + } + + static uint64_t accZToBits(float acc_z) + { + return discretizeRange<float>(acc_z, -16.0, 16.0, 2048); + } + + + static float bitsToGyroX(uint64_t bits) + { + return undiscretizeRange<float>(bits, -2000.0, 2000.0, 2048); + } + + static uint64_t gyroXToBits(float gyro_x) + { + return discretizeRange<float>(gyro_x, -2000.0, 2000.0, 2048); + } + + + static float bitsToGyroY(uint64_t bits) + { + return undiscretizeRange<float>(bits, -2000.0, 2000.0, 2048); + } + + static uint64_t gyroYToBits(float gyro_y) + { + return discretizeRange<float>(gyro_y, -2000.0, 2000.0, 2048); + } + + + static float bitsToGyroZ(uint64_t bits) + { + return undiscretizeRange<float>(bits, -2000.0, 2000.0, 2048); + } + + static uint64_t gyroZToBits(float gyro_z) + { + return discretizeRange<float>(gyro_z, -2000.0, 2000.0, 2048); + } + + + static float bitsToGpsLat(uint64_t bits) + { + return (float)bits; + } + + static uint64_t gpsLatToBits(float gps_lat) + { + return (uint64_t)gps_lat; + } + + + static float bitsToGpsLon(uint64_t bits) + { + return (float)bits; + } + + static uint64_t gpsLonToBits(float gps_lon) + { + return (uint64_t)gps_lon; + } + + + static float bitsToGpsAlt(uint64_t bits) + { + return undiscretizeRange<float>(bits, 0.0, 5120.0, 1024); + } + + static uint64_t gpsAltToBits(float gps_alt) + { + return discretizeRange<float>(gps_alt, 0.0, 5120.0, 1024); + } + + + static uint8_t bitsToFmmState(uint64_t bits) + { + return (uint8_t)bits; + } + + static uint64_t fmmStateToBits(uint8_t fmm_state) + { + return (uint64_t)fmm_state; + } + + + static uint8_t bitsToDplState(uint64_t bits) + { + return (uint8_t)bits; + } + + static uint64_t dplStateToBits(uint8_t dpl_state) + { + return (uint64_t)dpl_state; + } + + + static uint8_t bitsToPinLaunch(uint64_t bits) + { + return (uint8_t)bits; + } + + static uint64_t pinLaunchToBits(uint8_t pin_launch) + { + return (uint64_t)pin_launch; + } + + + static uint8_t bitsToPinDetach(uint64_t bits) + { + return (uint8_t)bits; + } + + static uint64_t pinDetachToBits(uint8_t pin_detach) + { + return (uint64_t)pin_detach; + } + + + static uint8_t bitsToGpsFix(uint64_t bits) + { + return (uint8_t)bits; + } + + static uint64_t gpsFixToBits(uint8_t gps_fix) + { + return (uint64_t)gps_fix; + } + + +}; + + + +class LowRateTMConversion +{ +public: + + static long long bitsToLiftoffTs(uint64_t bits) + { + return (long long)bits; + } + + static uint64_t liftoffTsToBits(long long liftoff_ts) + { + return (uint64_t)liftoff_ts; + } + + + static long long bitsToLiftoffMaxAccTs(uint64_t bits) + { + return (long long)bits; + } + + static uint64_t liftoffMaxAccTsToBits(long long liftoff_max_acc_ts) + { + return (uint64_t)liftoff_max_acc_ts; + } + + + static float bitsToLiftoffMaxAcc(uint64_t bits) + { + return undiscretizeRange<float>(bits, -16.0, 16.0, 2048); + } + + static uint64_t liftoffMaxAccToBits(float liftoff_max_acc) + { + return discretizeRange<float>(liftoff_max_acc, -16.0, 16.0, 2048); + } + + + static long long bitsToMaxZspeedTs(uint64_t bits) + { + return (long long)bits; + } + + static uint64_t maxZspeedTsToBits(long long max_zspeed_ts) + { + return (uint64_t)max_zspeed_ts; + } + + + static float bitsToMaxZspeed(uint64_t bits) + { + return undiscretizeRange<float>(bits, -512.0, 512.0, 1024); + } + + static uint64_t maxZspeedToBits(float max_zspeed) + { + return discretizeRange<float>(max_zspeed, -512.0, 512.0, 1024); + } + + + static float bitsToMaxSpeedAltitude(uint64_t bits) + { + return (float)bits; + } + + static uint64_t maxSpeedAltitudeToBits(float max_speed_altitude) + { + return (uint64_t)max_speed_altitude; + } + + + static long long bitsToApogeeTs(uint64_t bits) + { + return (long long)bits; + } + + static uint64_t apogeeTsToBits(long long apogee_ts) + { + return (uint64_t)apogee_ts; + } + + + static float bitsToNxpMinPressure(uint64_t bits) + { + return undiscretizeRange<float>(bits, 50000.0, 100000.0, 4096); + } + + static uint64_t nxpMinPressureToBits(float nxp_min_pressure) + { + return discretizeRange<float>(nxp_min_pressure, 50000.0, 100000.0, 4096); + } + + + static float bitsToHwMinPressure(uint64_t bits) + { + return undiscretizeRange<float>(bits, 50000.0, 100000.0, 4096); + } + + static uint64_t hwMinPressureToBits(float hw_min_pressure) + { + return discretizeRange<float>(hw_min_pressure, 50000.0, 100000.0, 4096); + } + + + static float bitsToKalmanMinPressure(uint64_t bits) + { + return undiscretizeRange<float>(bits, 50000.0, 100000.0, 4096); + } + + static uint64_t kalmanMinPressureToBits(float kalman_min_pressure) + { + return discretizeRange<float>(kalman_min_pressure, 50000.0, 100000.0, 4096); + } + + + static float bitsToDigitalMinPressure(uint64_t bits) + { + return undiscretizeRange<float>(bits, 50000.0, 100000.0, 8192); + } + + static uint64_t digitalMinPressureToBits(float digital_min_pressure) + { + return discretizeRange<float>(digital_min_pressure, 50000.0, 100000.0, 8192); + } + + + static float bitsToBaroMaxAltitutde(uint64_t bits) + { + return (float)bits; + } + + static uint64_t baroMaxAltitutdeToBits(float baro_max_altitutde ) + { + return (uint64_t)baro_max_altitutde ; + } + + + static float bitsToGpsMaxAltitude(uint64_t bits) + { + return (float)bits; + } + + static uint64_t gpsMaxAltitudeToBits(float gps_max_altitude) + { + return (uint64_t)gps_max_altitude; + } + + + static float bitsToApogeeLat(uint64_t bits) + { + return (float)bits; + } + + static uint64_t apogeeLatToBits(float apogee_lat) + { + return (uint64_t)apogee_lat; + } + + + static float bitsToApogeeLon(uint64_t bits) + { + return (float)bits; + } + + static uint64_t apogeeLonToBits(float apogee_lon) + { + return (uint64_t)apogee_lon; + } + + + static long long bitsToDrogueDplTs(uint64_t bits) + { + return (long long)bits; + } + + static uint64_t drogueDplTsToBits(long long drogue_dpl_ts) + { + return (uint64_t)drogue_dpl_ts; + } + + + static float bitsToDrogueDplMaxAcc(uint64_t bits) + { + return undiscretizeRange<float>(bits, -16.0, 16.0, 2048); + } + + static uint64_t drogueDplMaxAccToBits(float drogue_dpl_max_acc) + { + return discretizeRange<float>(drogue_dpl_max_acc, -16.0, 16.0, 2048); + } + + + static long long bitsToMainDplTs(uint64_t bits) + { + return (long long)bits; + } + + static uint64_t mainDplTsToBits(long long main_dpl_ts) + { + return (uint64_t)main_dpl_ts; + } + + + static float bitsToMainDplAltitude(uint64_t bits) + { + return (float)bits; + } + + static uint64_t mainDplAltitudeToBits(float main_dpl_altitude) + { + return (uint64_t)main_dpl_altitude; + } + + + static float bitsToMainDplZspeed(uint64_t bits) + { + return undiscretizeRange<float>(bits, -512.0, 512.0, 1024); + } + + static uint64_t mainDplZspeedToBits(float main_dpl_zspeed) + { + return discretizeRange<float>(main_dpl_zspeed, -512.0, 512.0, 1024); + } + + + static float bitsToMainDplAcc(uint64_t bits) + { + return undiscretizeRange<float>(bits, -16.0, 16.0, 2048); + } + + static uint64_t mainDplAccToBits(float main_dpl_acc) + { + return discretizeRange<float>(main_dpl_acc, -16.0, 16.0, 2048); + } + + +}; + + diff --git a/bitpacking/hermes/HermesPackets.h b/bitpacking/hermes/HermesPackets.h new file mode 100644 index 0000000000000000000000000000000000000000..7e2d4c967697b383d424fcdffbfa15e108b0837c --- /dev/null +++ b/bitpacking/hermes/HermesPackets.h @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2019 Skyward Experimental Rocketry + * Authors: Luca Erbetta + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once + +#include "HighRateTMPacker.h" +#include "LowRateTMPacker.h" \ No newline at end of file diff --git a/bitpacking/hermes/HighRateTMPacker.h b/bitpacking/hermes/HighRateTMPacker.h new file mode 100644 index 0000000000000000000000000000000000000000..acb8b57de4c0910f7e90a80d11b1b00636d3873f --- /dev/null +++ b/bitpacking/hermes/HighRateTMPacker.h @@ -0,0 +1,943 @@ +/** + * Copyright (c) 2019 Skyward Experimental Rocketry + * Authors: Luca Conterio, Luca Erbetta + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once + +#include "BitPacker.h" +#include "mavlink_lib/hermes/mavlink.h" +#include "ConversionFunctions.h" + +class HighRateTMPacker +{ +public: + static constexpr int HR_TM_PACKET_SIZE = 100; + static constexpr int HR_TM_SINGLE_PACKET_SIZE_BITS = 200; + + static_assert(MAVLINK_MSG_HR_TM_FIELD_PAYLOAD_LEN == HR_TM_PACKET_SIZE, + "Payload size mismatch! Mavlnk payload size differes from declared size. Maybe your mavlink definitions are outdated?"); + + + + + HighRateTMPacker(uint8_t *packet) : packet(packet), bitpacker(packet, HR_TM_PACKET_SIZE) + { + } + + + bool packTimestamp(long long timestamp, size_t packet_index) + { + if(packet_index >= 4) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits = HighRateTMConversion::timestampToBits(timestamp); + + return bitpacker.pack( + INDEX_TIMESTAMP + packet_index * HR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_TIMESTAMP, bits); + } + + bool packPressureAda(float pressure_ada, size_t packet_index) + { + if(packet_index >= 4) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits = HighRateTMConversion::pressureAdaToBits(pressure_ada); + + return bitpacker.pack( + INDEX_PRESSURE_ADA + packet_index * HR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_PRESSURE_ADA, bits); + } + + bool packPressureDigi(float pressure_digi, size_t packet_index) + { + if(packet_index >= 4) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits = HighRateTMConversion::pressureDigiToBits(pressure_digi); + + return bitpacker.pack( + INDEX_PRESSURE_DIGI + packet_index * HR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_PRESSURE_DIGI, bits); + } + + bool packMslAltitude(float msl_altitude, size_t packet_index) + { + if(packet_index >= 4) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits = HighRateTMConversion::mslAltitudeToBits(msl_altitude); + + return bitpacker.pack( + INDEX_MSL_ALTITUDE + packet_index * HR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_MSL_ALTITUDE, bits); + } + + bool packAglAltitude(float agl_altitude, size_t packet_index) + { + if(packet_index >= 4) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits = HighRateTMConversion::aglAltitudeToBits(agl_altitude); + + return bitpacker.pack( + INDEX_AGL_ALTITUDE + packet_index * HR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_AGL_ALTITUDE, bits); + } + + bool packVertSpeed(float vert_speed, size_t packet_index) + { + if(packet_index >= 4) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits = HighRateTMConversion::vertSpeedToBits(vert_speed); + + return bitpacker.pack( + INDEX_VERT_SPEED + packet_index * HR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_VERT_SPEED, bits); + } + + bool packVertSpeed2(float vert_speed_2, size_t packet_index) + { + if(packet_index >= 4) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits = HighRateTMConversion::vertSpeed2ToBits(vert_speed_2); + + return bitpacker.pack( + INDEX_VERT_SPEED_2 + packet_index * HR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_VERT_SPEED_2, bits); + } + + bool packAccX(float acc_x, size_t packet_index) + { + if(packet_index >= 4) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits = HighRateTMConversion::accXToBits(acc_x); + + return bitpacker.pack( + INDEX_ACC_X + packet_index * HR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_ACC_X, bits); + } + + bool packAccY(float acc_y, size_t packet_index) + { + if(packet_index >= 4) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits = HighRateTMConversion::accYToBits(acc_y); + + return bitpacker.pack( + INDEX_ACC_Y + packet_index * HR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_ACC_Y, bits); + } + + bool packAccZ(float acc_z, size_t packet_index) + { + if(packet_index >= 4) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits = HighRateTMConversion::accZToBits(acc_z); + + return bitpacker.pack( + INDEX_ACC_Z + packet_index * HR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_ACC_Z, bits); + } + + bool packGyroX(float gyro_x, size_t packet_index) + { + if(packet_index >= 4) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits = HighRateTMConversion::gyroXToBits(gyro_x); + + return bitpacker.pack( + INDEX_GYRO_X + packet_index * HR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_GYRO_X, bits); + } + + bool packGyroY(float gyro_y, size_t packet_index) + { + if(packet_index >= 4) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits = HighRateTMConversion::gyroYToBits(gyro_y); + + return bitpacker.pack( + INDEX_GYRO_Y + packet_index * HR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_GYRO_Y, bits); + } + + bool packGyroZ(float gyro_z, size_t packet_index) + { + if(packet_index >= 4) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits = HighRateTMConversion::gyroZToBits(gyro_z); + + return bitpacker.pack( + INDEX_GYRO_Z + packet_index * HR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_GYRO_Z, bits); + } + + bool packGpsLat(float gps_lat, size_t packet_index) + { + if(packet_index >= 4) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits = HighRateTMConversion::gpsLatToBits(gps_lat); + + return bitpacker.pack( + INDEX_GPS_LAT + packet_index * HR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_GPS_LAT, bits); + } + + bool packGpsLon(float gps_lon, size_t packet_index) + { + if(packet_index >= 4) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits = HighRateTMConversion::gpsLonToBits(gps_lon); + + return bitpacker.pack( + INDEX_GPS_LON + packet_index * HR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_GPS_LON, bits); + } + + bool packGpsAlt(float gps_alt, size_t packet_index) + { + if(packet_index >= 4) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits = HighRateTMConversion::gpsAltToBits(gps_alt); + + return bitpacker.pack( + INDEX_GPS_ALT + packet_index * HR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_GPS_ALT, bits); + } + + bool packFmmState(uint8_t fmm_state, size_t packet_index) + { + if(packet_index >= 4) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits = HighRateTMConversion::fmmStateToBits(fmm_state); + + return bitpacker.pack( + INDEX_FMM_STATE + packet_index * HR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_FMM_STATE, bits); + } + + bool packDplState(uint8_t dpl_state, size_t packet_index) + { + if(packet_index >= 4) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits = HighRateTMConversion::dplStateToBits(dpl_state); + + return bitpacker.pack( + INDEX_DPL_STATE + packet_index * HR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_DPL_STATE, bits); + } + + bool packPinLaunch(uint8_t pin_launch, size_t packet_index) + { + if(packet_index >= 4) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits = HighRateTMConversion::pinLaunchToBits(pin_launch); + + return bitpacker.pack( + INDEX_PIN_LAUNCH + packet_index * HR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_PIN_LAUNCH, bits); + } + + bool packPinDetach(uint8_t pin_detach, size_t packet_index) + { + if(packet_index >= 4) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits = HighRateTMConversion::pinDetachToBits(pin_detach); + + return bitpacker.pack( + INDEX_PIN_DETACH + packet_index * HR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_PIN_DETACH, bits); + } + + bool packGpsFix(uint8_t gps_fix, size_t packet_index) + { + if(packet_index >= 4) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits = HighRateTMConversion::gpsFixToBits(gps_fix); + + return bitpacker.pack( + INDEX_GPS_FIX + packet_index * HR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_GPS_FIX, bits); + } + + + + bool unpackTimestamp(long long* timestamp, size_t packet_index) + { + if(packet_index >= 4) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits; + + bool success = bitpacker.unpack( + INDEX_TIMESTAMP + packet_index * HR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_TIMESTAMP, &bits); + + if(success) + { + *timestamp = HighRateTMConversion::bitsToTimestamp(bits); + return true; + }else + { + return false; + } + + } + + bool unpackPressureAda(float* pressure_ada, size_t packet_index) + { + if(packet_index >= 4) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits; + + bool success = bitpacker.unpack( + INDEX_PRESSURE_ADA + packet_index * HR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_PRESSURE_ADA, &bits); + + if(success) + { + *pressure_ada = HighRateTMConversion::bitsToPressureAda(bits); + return true; + }else + { + return false; + } + + } + + bool unpackPressureDigi(float* pressure_digi, size_t packet_index) + { + if(packet_index >= 4) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits; + + bool success = bitpacker.unpack( + INDEX_PRESSURE_DIGI + packet_index * HR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_PRESSURE_DIGI, &bits); + + if(success) + { + *pressure_digi = HighRateTMConversion::bitsToPressureDigi(bits); + return true; + }else + { + return false; + } + + } + + bool unpackMslAltitude(float* msl_altitude, size_t packet_index) + { + if(packet_index >= 4) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits; + + bool success = bitpacker.unpack( + INDEX_MSL_ALTITUDE + packet_index * HR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_MSL_ALTITUDE, &bits); + + if(success) + { + *msl_altitude = HighRateTMConversion::bitsToMslAltitude(bits); + return true; + }else + { + return false; + } + + } + + bool unpackAglAltitude(float* agl_altitude, size_t packet_index) + { + if(packet_index >= 4) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits; + + bool success = bitpacker.unpack( + INDEX_AGL_ALTITUDE + packet_index * HR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_AGL_ALTITUDE, &bits); + + if(success) + { + *agl_altitude = HighRateTMConversion::bitsToAglAltitude(bits); + return true; + }else + { + return false; + } + + } + + bool unpackVertSpeed(float* vert_speed, size_t packet_index) + { + if(packet_index >= 4) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits; + + bool success = bitpacker.unpack( + INDEX_VERT_SPEED + packet_index * HR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_VERT_SPEED, &bits); + + if(success) + { + *vert_speed = HighRateTMConversion::bitsToVertSpeed(bits); + return true; + }else + { + return false; + } + + } + + bool unpackVertSpeed2(float* vert_speed_2, size_t packet_index) + { + if(packet_index >= 4) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits; + + bool success = bitpacker.unpack( + INDEX_VERT_SPEED_2 + packet_index * HR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_VERT_SPEED_2, &bits); + + if(success) + { + *vert_speed_2 = HighRateTMConversion::bitsToVertSpeed2(bits); + return true; + }else + { + return false; + } + + } + + bool unpackAccX(float* acc_x, size_t packet_index) + { + if(packet_index >= 4) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits; + + bool success = bitpacker.unpack( + INDEX_ACC_X + packet_index * HR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_ACC_X, &bits); + + if(success) + { + *acc_x = HighRateTMConversion::bitsToAccX(bits); + return true; + }else + { + return false; + } + + } + + bool unpackAccY(float* acc_y, size_t packet_index) + { + if(packet_index >= 4) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits; + + bool success = bitpacker.unpack( + INDEX_ACC_Y + packet_index * HR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_ACC_Y, &bits); + + if(success) + { + *acc_y = HighRateTMConversion::bitsToAccY(bits); + return true; + }else + { + return false; + } + + } + + bool unpackAccZ(float* acc_z, size_t packet_index) + { + if(packet_index >= 4) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits; + + bool success = bitpacker.unpack( + INDEX_ACC_Z + packet_index * HR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_ACC_Z, &bits); + + if(success) + { + *acc_z = HighRateTMConversion::bitsToAccZ(bits); + return true; + }else + { + return false; + } + + } + + bool unpackGyroX(float* gyro_x, size_t packet_index) + { + if(packet_index >= 4) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits; + + bool success = bitpacker.unpack( + INDEX_GYRO_X + packet_index * HR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_GYRO_X, &bits); + + if(success) + { + *gyro_x = HighRateTMConversion::bitsToGyroX(bits); + return true; + }else + { + return false; + } + + } + + bool unpackGyroY(float* gyro_y, size_t packet_index) + { + if(packet_index >= 4) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits; + + bool success = bitpacker.unpack( + INDEX_GYRO_Y + packet_index * HR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_GYRO_Y, &bits); + + if(success) + { + *gyro_y = HighRateTMConversion::bitsToGyroY(bits); + return true; + }else + { + return false; + } + + } + + bool unpackGyroZ(float* gyro_z, size_t packet_index) + { + if(packet_index >= 4) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits; + + bool success = bitpacker.unpack( + INDEX_GYRO_Z + packet_index * HR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_GYRO_Z, &bits); + + if(success) + { + *gyro_z = HighRateTMConversion::bitsToGyroZ(bits); + return true; + }else + { + return false; + } + + } + + bool unpackGpsLat(float* gps_lat, size_t packet_index) + { + if(packet_index >= 4) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits; + + bool success = bitpacker.unpack( + INDEX_GPS_LAT + packet_index * HR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_GPS_LAT, &bits); + + if(success) + { + *gps_lat = HighRateTMConversion::bitsToGpsLat(bits); + return true; + }else + { + return false; + } + + } + + bool unpackGpsLon(float* gps_lon, size_t packet_index) + { + if(packet_index >= 4) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits; + + bool success = bitpacker.unpack( + INDEX_GPS_LON + packet_index * HR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_GPS_LON, &bits); + + if(success) + { + *gps_lon = HighRateTMConversion::bitsToGpsLon(bits); + return true; + }else + { + return false; + } + + } + + bool unpackGpsAlt(float* gps_alt, size_t packet_index) + { + if(packet_index >= 4) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits; + + bool success = bitpacker.unpack( + INDEX_GPS_ALT + packet_index * HR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_GPS_ALT, &bits); + + if(success) + { + *gps_alt = HighRateTMConversion::bitsToGpsAlt(bits); + return true; + }else + { + return false; + } + + } + + bool unpackFmmState(uint8_t* fmm_state, size_t packet_index) + { + if(packet_index >= 4) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits; + + bool success = bitpacker.unpack( + INDEX_FMM_STATE + packet_index * HR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_FMM_STATE, &bits); + + if(success) + { + *fmm_state = HighRateTMConversion::bitsToFmmState(bits); + return true; + }else + { + return false; + } + + } + + bool unpackDplState(uint8_t* dpl_state, size_t packet_index) + { + if(packet_index >= 4) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits; + + bool success = bitpacker.unpack( + INDEX_DPL_STATE + packet_index * HR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_DPL_STATE, &bits); + + if(success) + { + *dpl_state = HighRateTMConversion::bitsToDplState(bits); + return true; + }else + { + return false; + } + + } + + bool unpackPinLaunch(uint8_t* pin_launch, size_t packet_index) + { + if(packet_index >= 4) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits; + + bool success = bitpacker.unpack( + INDEX_PIN_LAUNCH + packet_index * HR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_PIN_LAUNCH, &bits); + + if(success) + { + *pin_launch = HighRateTMConversion::bitsToPinLaunch(bits); + return true; + }else + { + return false; + } + + } + + bool unpackPinDetach(uint8_t* pin_detach, size_t packet_index) + { + if(packet_index >= 4) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits; + + bool success = bitpacker.unpack( + INDEX_PIN_DETACH + packet_index * HR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_PIN_DETACH, &bits); + + if(success) + { + *pin_detach = HighRateTMConversion::bitsToPinDetach(bits); + return true; + }else + { + return false; + } + + } + + bool unpackGpsFix(uint8_t* gps_fix, size_t packet_index) + { + if(packet_index >= 4) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits; + + bool success = bitpacker.unpack( + INDEX_GPS_FIX + packet_index * HR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_GPS_FIX, &bits); + + if(success) + { + *gps_fix = HighRateTMConversion::bitsToGpsFix(bits); + return true; + }else + { + return false; + } + + } + + +private: + enum FieldIndex + { + INDEX_TIMESTAMP = 0, + INDEX_PRESSURE_ADA = 25, + INDEX_PRESSURE_DIGI = 37, + INDEX_MSL_ALTITUDE = 50, + INDEX_AGL_ALTITUDE = 62, + INDEX_VERT_SPEED = 71, + INDEX_VERT_SPEED_2 = 81, + INDEX_ACC_X = 91, + INDEX_ACC_Y = 102, + INDEX_ACC_Z = 113, + INDEX_GYRO_X = 124, + INDEX_GYRO_Y = 135, + INDEX_GYRO_Z = 146, + INDEX_GPS_LAT = 157, + INDEX_GPS_LON = 168, + INDEX_GPS_ALT = 179, + INDEX_FMM_STATE = 189, + INDEX_DPL_STATE = 194, + INDEX_PIN_LAUNCH = 197, + INDEX_PIN_DETACH = 198, + INDEX_GPS_FIX = 199 + }; + + enum FieldSize + { + SIZE_TIMESTAMP = 25, + SIZE_PRESSURE_ADA = 12, + SIZE_PRESSURE_DIGI = 13, + SIZE_MSL_ALTITUDE = 12, + SIZE_AGL_ALTITUDE = 9, + SIZE_VERT_SPEED = 10, + SIZE_VERT_SPEED_2 = 10, + SIZE_ACC_X = 11, + SIZE_ACC_Y = 11, + SIZE_ACC_Z = 11, + SIZE_GYRO_X = 11, + SIZE_GYRO_Y = 11, + SIZE_GYRO_Z = 11, + SIZE_GPS_LAT = 11, + SIZE_GPS_LON = 11, + SIZE_GPS_ALT = 10, + SIZE_FMM_STATE = 5, + SIZE_DPL_STATE = 3, + SIZE_PIN_LAUNCH = 1, + SIZE_PIN_DETACH = 1, + SIZE_GPS_FIX = 1 + }; + + uint8_t *packet; + BitPacker bitpacker; +}; \ No newline at end of file diff --git a/bitpacking/hermes/LowRateTMPacker.h b/bitpacking/hermes/LowRateTMPacker.h new file mode 100644 index 0000000000000000000000000000000000000000..2e1febfae026105b4512ebc60d0c4223d011ba6b --- /dev/null +++ b/bitpacking/hermes/LowRateTMPacker.h @@ -0,0 +1,943 @@ +/** + * Copyright (c) 2019 Skyward Experimental Rocketry + * Authors: Luca Conterio, Luca Erbetta + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once + +#include "BitPacker.h" +#include "mavlink_lib/hermes/mavlink.h" +#include "ConversionFunctions.h" + +class LowRateTMPacker +{ +public: + static constexpr int LR_TM_PACKET_SIZE = 40; + static constexpr int LR_TM_SINGLE_PACKET_SIZE_BITS = 319; + + static_assert(MAVLINK_MSG_LR_TM_FIELD_PAYLOAD_LEN == LR_TM_PACKET_SIZE, + "Payload size mismatch! Mavlnk payload size differes from declared size. Maybe your mavlink definitions are outdated?"); + + + + + LowRateTMPacker(uint8_t *packet) : packet(packet), bitpacker(packet, LR_TM_PACKET_SIZE) + { + } + + + bool packLiftoffTs(long long liftoff_ts, size_t packet_index) + { + if(packet_index >= 1) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits = LowRateTMConversion::liftoffTsToBits(liftoff_ts); + + return bitpacker.pack( + INDEX_LIFTOFF_TS + packet_index * LR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_LIFTOFF_TS, bits); + } + + bool packLiftoffMaxAccTs(long long liftoff_max_acc_ts, size_t packet_index) + { + if(packet_index >= 1) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits = LowRateTMConversion::liftoffMaxAccTsToBits(liftoff_max_acc_ts); + + return bitpacker.pack( + INDEX_LIFTOFF_MAX_ACC_TS + packet_index * LR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_LIFTOFF_MAX_ACC_TS, bits); + } + + bool packLiftoffMaxAcc(float liftoff_max_acc, size_t packet_index) + { + if(packet_index >= 1) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits = LowRateTMConversion::liftoffMaxAccToBits(liftoff_max_acc); + + return bitpacker.pack( + INDEX_LIFTOFF_MAX_ACC + packet_index * LR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_LIFTOFF_MAX_ACC, bits); + } + + bool packMaxZspeedTs(long long max_zspeed_ts, size_t packet_index) + { + if(packet_index >= 1) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits = LowRateTMConversion::maxZspeedTsToBits(max_zspeed_ts); + + return bitpacker.pack( + INDEX_MAX_ZSPEED_TS + packet_index * LR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_MAX_ZSPEED_TS, bits); + } + + bool packMaxZspeed(float max_zspeed, size_t packet_index) + { + if(packet_index >= 1) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits = LowRateTMConversion::maxZspeedToBits(max_zspeed); + + return bitpacker.pack( + INDEX_MAX_ZSPEED + packet_index * LR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_MAX_ZSPEED, bits); + } + + bool packMaxSpeedAltitude(float max_speed_altitude, size_t packet_index) + { + if(packet_index >= 1) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits = LowRateTMConversion::maxSpeedAltitudeToBits(max_speed_altitude); + + return bitpacker.pack( + INDEX_MAX_SPEED_ALTITUDE + packet_index * LR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_MAX_SPEED_ALTITUDE, bits); + } + + bool packApogeeTs(long long apogee_ts, size_t packet_index) + { + if(packet_index >= 1) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits = LowRateTMConversion::apogeeTsToBits(apogee_ts); + + return bitpacker.pack( + INDEX_APOGEE_TS + packet_index * LR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_APOGEE_TS, bits); + } + + bool packNxpMinPressure(float nxp_min_pressure, size_t packet_index) + { + if(packet_index >= 1) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits = LowRateTMConversion::nxpMinPressureToBits(nxp_min_pressure); + + return bitpacker.pack( + INDEX_NXP_MIN_PRESSURE + packet_index * LR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_NXP_MIN_PRESSURE, bits); + } + + bool packHwMinPressure(float hw_min_pressure, size_t packet_index) + { + if(packet_index >= 1) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits = LowRateTMConversion::hwMinPressureToBits(hw_min_pressure); + + return bitpacker.pack( + INDEX_HW_MIN_PRESSURE + packet_index * LR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_HW_MIN_PRESSURE, bits); + } + + bool packKalmanMinPressure(float kalman_min_pressure, size_t packet_index) + { + if(packet_index >= 1) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits = LowRateTMConversion::kalmanMinPressureToBits(kalman_min_pressure); + + return bitpacker.pack( + INDEX_KALMAN_MIN_PRESSURE + packet_index * LR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_KALMAN_MIN_PRESSURE, bits); + } + + bool packDigitalMinPressure(float digital_min_pressure, size_t packet_index) + { + if(packet_index >= 1) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits = LowRateTMConversion::digitalMinPressureToBits(digital_min_pressure); + + return bitpacker.pack( + INDEX_DIGITAL_MIN_PRESSURE + packet_index * LR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_DIGITAL_MIN_PRESSURE, bits); + } + + bool packBaroMaxAltitutde(float baro_max_altitutde , size_t packet_index) + { + if(packet_index >= 1) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits = LowRateTMConversion::baroMaxAltitutdeToBits(baro_max_altitutde ); + + return bitpacker.pack( + INDEX_BARO_MAX_ALTITUTDE + packet_index * LR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_BARO_MAX_ALTITUTDE , bits); + } + + bool packGpsMaxAltitude(float gps_max_altitude, size_t packet_index) + { + if(packet_index >= 1) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits = LowRateTMConversion::gpsMaxAltitudeToBits(gps_max_altitude); + + return bitpacker.pack( + INDEX_GPS_MAX_ALTITUDE + packet_index * LR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_GPS_MAX_ALTITUDE, bits); + } + + bool packApogeeLat(float apogee_lat, size_t packet_index) + { + if(packet_index >= 1) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits = LowRateTMConversion::apogeeLatToBits(apogee_lat); + + return bitpacker.pack( + INDEX_APOGEE_LAT + packet_index * LR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_APOGEE_LAT, bits); + } + + bool packApogeeLon(float apogee_lon, size_t packet_index) + { + if(packet_index >= 1) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits = LowRateTMConversion::apogeeLonToBits(apogee_lon); + + return bitpacker.pack( + INDEX_APOGEE_LON + packet_index * LR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_APOGEE_LON, bits); + } + + bool packDrogueDplTs(long long drogue_dpl_ts, size_t packet_index) + { + if(packet_index >= 1) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits = LowRateTMConversion::drogueDplTsToBits(drogue_dpl_ts); + + return bitpacker.pack( + INDEX_DROGUE_DPL_TS + packet_index * LR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_DROGUE_DPL_TS, bits); + } + + bool packDrogueDplMaxAcc(float drogue_dpl_max_acc, size_t packet_index) + { + if(packet_index >= 1) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits = LowRateTMConversion::drogueDplMaxAccToBits(drogue_dpl_max_acc); + + return bitpacker.pack( + INDEX_DROGUE_DPL_MAX_ACC + packet_index * LR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_DROGUE_DPL_MAX_ACC, bits); + } + + bool packMainDplTs(long long main_dpl_ts, size_t packet_index) + { + if(packet_index >= 1) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits = LowRateTMConversion::mainDplTsToBits(main_dpl_ts); + + return bitpacker.pack( + INDEX_MAIN_DPL_TS + packet_index * LR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_MAIN_DPL_TS, bits); + } + + bool packMainDplAltitude(float main_dpl_altitude, size_t packet_index) + { + if(packet_index >= 1) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits = LowRateTMConversion::mainDplAltitudeToBits(main_dpl_altitude); + + return bitpacker.pack( + INDEX_MAIN_DPL_ALTITUDE + packet_index * LR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_MAIN_DPL_ALTITUDE, bits); + } + + bool packMainDplZspeed(float main_dpl_zspeed, size_t packet_index) + { + if(packet_index >= 1) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits = LowRateTMConversion::mainDplZspeedToBits(main_dpl_zspeed); + + return bitpacker.pack( + INDEX_MAIN_DPL_ZSPEED + packet_index * LR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_MAIN_DPL_ZSPEED, bits); + } + + bool packMainDplAcc(float main_dpl_acc, size_t packet_index) + { + if(packet_index >= 1) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits = LowRateTMConversion::mainDplAccToBits(main_dpl_acc); + + return bitpacker.pack( + INDEX_MAIN_DPL_ACC + packet_index * LR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_MAIN_DPL_ACC, bits); + } + + + + bool unpackLiftoffTs(long long* liftoff_ts, size_t packet_index) + { + if(packet_index >= 1) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits; + + bool success = bitpacker.unpack( + INDEX_LIFTOFF_TS + packet_index * LR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_LIFTOFF_TS, &bits); + + if(success) + { + *liftoff_ts = LowRateTMConversion::bitsToLiftoffTs(bits); + return true; + }else + { + return false; + } + + } + + bool unpackLiftoffMaxAccTs(long long* liftoff_max_acc_ts, size_t packet_index) + { + if(packet_index >= 1) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits; + + bool success = bitpacker.unpack( + INDEX_LIFTOFF_MAX_ACC_TS + packet_index * LR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_LIFTOFF_MAX_ACC_TS, &bits); + + if(success) + { + *liftoff_max_acc_ts = LowRateTMConversion::bitsToLiftoffMaxAccTs(bits); + return true; + }else + { + return false; + } + + } + + bool unpackLiftoffMaxAcc(float* liftoff_max_acc, size_t packet_index) + { + if(packet_index >= 1) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits; + + bool success = bitpacker.unpack( + INDEX_LIFTOFF_MAX_ACC + packet_index * LR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_LIFTOFF_MAX_ACC, &bits); + + if(success) + { + *liftoff_max_acc = LowRateTMConversion::bitsToLiftoffMaxAcc(bits); + return true; + }else + { + return false; + } + + } + + bool unpackMaxZspeedTs(long long* max_zspeed_ts, size_t packet_index) + { + if(packet_index >= 1) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits; + + bool success = bitpacker.unpack( + INDEX_MAX_ZSPEED_TS + packet_index * LR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_MAX_ZSPEED_TS, &bits); + + if(success) + { + *max_zspeed_ts = LowRateTMConversion::bitsToMaxZspeedTs(bits); + return true; + }else + { + return false; + } + + } + + bool unpackMaxZspeed(float* max_zspeed, size_t packet_index) + { + if(packet_index >= 1) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits; + + bool success = bitpacker.unpack( + INDEX_MAX_ZSPEED + packet_index * LR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_MAX_ZSPEED, &bits); + + if(success) + { + *max_zspeed = LowRateTMConversion::bitsToMaxZspeed(bits); + return true; + }else + { + return false; + } + + } + + bool unpackMaxSpeedAltitude(float* max_speed_altitude, size_t packet_index) + { + if(packet_index >= 1) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits; + + bool success = bitpacker.unpack( + INDEX_MAX_SPEED_ALTITUDE + packet_index * LR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_MAX_SPEED_ALTITUDE, &bits); + + if(success) + { + *max_speed_altitude = LowRateTMConversion::bitsToMaxSpeedAltitude(bits); + return true; + }else + { + return false; + } + + } + + bool unpackApogeeTs(long long* apogee_ts, size_t packet_index) + { + if(packet_index >= 1) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits; + + bool success = bitpacker.unpack( + INDEX_APOGEE_TS + packet_index * LR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_APOGEE_TS, &bits); + + if(success) + { + *apogee_ts = LowRateTMConversion::bitsToApogeeTs(bits); + return true; + }else + { + return false; + } + + } + + bool unpackNxpMinPressure(float* nxp_min_pressure, size_t packet_index) + { + if(packet_index >= 1) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits; + + bool success = bitpacker.unpack( + INDEX_NXP_MIN_PRESSURE + packet_index * LR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_NXP_MIN_PRESSURE, &bits); + + if(success) + { + *nxp_min_pressure = LowRateTMConversion::bitsToNxpMinPressure(bits); + return true; + }else + { + return false; + } + + } + + bool unpackHwMinPressure(float* hw_min_pressure, size_t packet_index) + { + if(packet_index >= 1) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits; + + bool success = bitpacker.unpack( + INDEX_HW_MIN_PRESSURE + packet_index * LR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_HW_MIN_PRESSURE, &bits); + + if(success) + { + *hw_min_pressure = LowRateTMConversion::bitsToHwMinPressure(bits); + return true; + }else + { + return false; + } + + } + + bool unpackKalmanMinPressure(float* kalman_min_pressure, size_t packet_index) + { + if(packet_index >= 1) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits; + + bool success = bitpacker.unpack( + INDEX_KALMAN_MIN_PRESSURE + packet_index * LR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_KALMAN_MIN_PRESSURE, &bits); + + if(success) + { + *kalman_min_pressure = LowRateTMConversion::bitsToKalmanMinPressure(bits); + return true; + }else + { + return false; + } + + } + + bool unpackDigitalMinPressure(float* digital_min_pressure, size_t packet_index) + { + if(packet_index >= 1) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits; + + bool success = bitpacker.unpack( + INDEX_DIGITAL_MIN_PRESSURE + packet_index * LR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_DIGITAL_MIN_PRESSURE, &bits); + + if(success) + { + *digital_min_pressure = LowRateTMConversion::bitsToDigitalMinPressure(bits); + return true; + }else + { + return false; + } + + } + + bool unpackBaroMaxAltitutde(float* baro_max_altitutde , size_t packet_index) + { + if(packet_index >= 1) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits; + + bool success = bitpacker.unpack( + INDEX_BARO_MAX_ALTITUTDE + packet_index * LR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_BARO_MAX_ALTITUTDE , &bits); + + if(success) + { + *baro_max_altitutde = LowRateTMConversion::bitsToBaroMaxAltitutde(bits); + return true; + }else + { + return false; + } + + } + + bool unpackGpsMaxAltitude(float* gps_max_altitude, size_t packet_index) + { + if(packet_index >= 1) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits; + + bool success = bitpacker.unpack( + INDEX_GPS_MAX_ALTITUDE + packet_index * LR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_GPS_MAX_ALTITUDE, &bits); + + if(success) + { + *gps_max_altitude = LowRateTMConversion::bitsToGpsMaxAltitude(bits); + return true; + }else + { + return false; + } + + } + + bool unpackApogeeLat(float* apogee_lat, size_t packet_index) + { + if(packet_index >= 1) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits; + + bool success = bitpacker.unpack( + INDEX_APOGEE_LAT + packet_index * LR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_APOGEE_LAT, &bits); + + if(success) + { + *apogee_lat = LowRateTMConversion::bitsToApogeeLat(bits); + return true; + }else + { + return false; + } + + } + + bool unpackApogeeLon(float* apogee_lon, size_t packet_index) + { + if(packet_index >= 1) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits; + + bool success = bitpacker.unpack( + INDEX_APOGEE_LON + packet_index * LR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_APOGEE_LON, &bits); + + if(success) + { + *apogee_lon = LowRateTMConversion::bitsToApogeeLon(bits); + return true; + }else + { + return false; + } + + } + + bool unpackDrogueDplTs(long long* drogue_dpl_ts, size_t packet_index) + { + if(packet_index >= 1) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits; + + bool success = bitpacker.unpack( + INDEX_DROGUE_DPL_TS + packet_index * LR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_DROGUE_DPL_TS, &bits); + + if(success) + { + *drogue_dpl_ts = LowRateTMConversion::bitsToDrogueDplTs(bits); + return true; + }else + { + return false; + } + + } + + bool unpackDrogueDplMaxAcc(float* drogue_dpl_max_acc, size_t packet_index) + { + if(packet_index >= 1) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits; + + bool success = bitpacker.unpack( + INDEX_DROGUE_DPL_MAX_ACC + packet_index * LR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_DROGUE_DPL_MAX_ACC, &bits); + + if(success) + { + *drogue_dpl_max_acc = LowRateTMConversion::bitsToDrogueDplMaxAcc(bits); + return true; + }else + { + return false; + } + + } + + bool unpackMainDplTs(long long* main_dpl_ts, size_t packet_index) + { + if(packet_index >= 1) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits; + + bool success = bitpacker.unpack( + INDEX_MAIN_DPL_TS + packet_index * LR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_MAIN_DPL_TS, &bits); + + if(success) + { + *main_dpl_ts = LowRateTMConversion::bitsToMainDplTs(bits); + return true; + }else + { + return false; + } + + } + + bool unpackMainDplAltitude(float* main_dpl_altitude, size_t packet_index) + { + if(packet_index >= 1) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits; + + bool success = bitpacker.unpack( + INDEX_MAIN_DPL_ALTITUDE + packet_index * LR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_MAIN_DPL_ALTITUDE, &bits); + + if(success) + { + *main_dpl_altitude = LowRateTMConversion::bitsToMainDplAltitude(bits); + return true; + }else + { + return false; + } + + } + + bool unpackMainDplZspeed(float* main_dpl_zspeed, size_t packet_index) + { + if(packet_index >= 1) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits; + + bool success = bitpacker.unpack( + INDEX_MAIN_DPL_ZSPEED + packet_index * LR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_MAIN_DPL_ZSPEED, &bits); + + if(success) + { + *main_dpl_zspeed = LowRateTMConversion::bitsToMainDplZspeed(bits); + return true; + }else + { + return false; + } + + } + + bool unpackMainDplAcc(float* main_dpl_acc, size_t packet_index) + { + if(packet_index >= 1) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits; + + bool success = bitpacker.unpack( + INDEX_MAIN_DPL_ACC + packet_index * LR_TM_SINGLE_PACKET_SIZE_BITS, + SIZE_MAIN_DPL_ACC, &bits); + + if(success) + { + *main_dpl_acc = LowRateTMConversion::bitsToMainDplAcc(bits); + return true; + }else + { + return false; + } + + } + + +private: + enum FieldIndex + { + INDEX_LIFTOFF_TS = 0, + INDEX_LIFTOFF_MAX_ACC_TS = 25, + INDEX_LIFTOFF_MAX_ACC = 50, + INDEX_MAX_ZSPEED_TS = 61, + INDEX_MAX_ZSPEED = 86, + INDEX_MAX_SPEED_ALTITUDE = 96, + INDEX_APOGEE_TS = 108, + INDEX_NXP_MIN_PRESSURE = 133, + INDEX_HW_MIN_PRESSURE = 145, + INDEX_KALMAN_MIN_PRESSURE = 157, + INDEX_DIGITAL_MIN_PRESSURE = 169, + INDEX_BARO_MAX_ALTITUTDE = 182, + INDEX_GPS_MAX_ALTITUDE = 194, + INDEX_APOGEE_LAT = 204, + INDEX_APOGEE_LON = 214, + INDEX_DROGUE_DPL_TS = 224, + INDEX_DROGUE_DPL_MAX_ACC = 249, + INDEX_MAIN_DPL_TS = 260, + INDEX_MAIN_DPL_ALTITUDE = 285, + INDEX_MAIN_DPL_ZSPEED = 298, + INDEX_MAIN_DPL_ACC = 308 + }; + + enum FieldSize + { + SIZE_LIFTOFF_TS = 25, + SIZE_LIFTOFF_MAX_ACC_TS = 25, + SIZE_LIFTOFF_MAX_ACC = 11, + SIZE_MAX_ZSPEED_TS = 25, + SIZE_MAX_ZSPEED = 10, + SIZE_MAX_SPEED_ALTITUDE = 12, + SIZE_APOGEE_TS = 25, + SIZE_NXP_MIN_PRESSURE = 12, + SIZE_HW_MIN_PRESSURE = 12, + SIZE_KALMAN_MIN_PRESSURE = 12, + SIZE_DIGITAL_MIN_PRESSURE = 13, + SIZE_BARO_MAX_ALTITUTDE = 12, + SIZE_GPS_MAX_ALTITUDE = 10, + SIZE_APOGEE_LAT = 10, + SIZE_APOGEE_LON = 10, + SIZE_DROGUE_DPL_TS = 25, + SIZE_DROGUE_DPL_MAX_ACC = 11, + SIZE_MAIN_DPL_TS = 25, + SIZE_MAIN_DPL_ALTITUDE = 13, + SIZE_MAIN_DPL_ZSPEED = 10, + SIZE_MAIN_DPL_ACC = 11 + }; + + uint8_t *packet; + BitPacker bitpacker; +}; \ No newline at end of file diff --git a/bitpacking/requirements.txt b/bitpacking/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..b4e01569861fa5001ba712bfb61688ed45a3f451 --- /dev/null +++ b/bitpacking/requirements.txt @@ -0,0 +1,20 @@ +cachetools==3.1.0 +certifi==2019.3.9 +chardet==3.0.4 +google-api-python-client==1.7.8 +google-auth==1.6.3 +google-auth-httplib2==0.0.3 +google-auth-oauthlib==0.3.0 +httplib2==0.12.3 +idna==2.8 +oauth2client==4.1.3 +oauthlib==3.0.1 +pkg-resources==0.0.0 +pyasn1==0.4.5 +pyasn1-modules==0.2.5 +requests==2.21.0 +requests-oauthlib==1.2.0 +rsa==4.0 +six==1.12.0 +uritemplate==3.0.0 +urllib3==1.24.2 diff --git a/bitpacking/store.json b/bitpacking/store.json new file mode 100644 index 0000000000000000000000000000000000000000..8baac9df5268f3b5ef31dccd6735112edacb87b5 --- /dev/null +++ b/bitpacking/store.json @@ -0,0 +1 @@ +{"access_token": "ya29.ImGpB0kQ2N9LHGFRjUZpe8EQ35iCmsjt19OAmFQxg_gOqN-oIWhPDkZH-Htg6m6tXHZCujHjuVTZdK4WtMluYzAddhRmhxece9N-xjgIPYxSIVolAJQp90U1JWgYjeBeplRs", "client_id": "1025168905991-tv31etsgm3lecodc5c798shqciekad40.apps.googleusercontent.com", "client_secret": "Yhaf67HuHR4DyXZKNXWu2lre", "refresh_token": "1/GVZfj7UPkTTZg9juq5hDEvwprbaeD8UbHjyrphyuFR4", "token_expiry": "2019-10-29T22:10:15Z", "token_uri": "https://www.googleapis.com/oauth2/v3/token", "user_agent": null, "revoke_uri": "https://oauth2.googleapis.com/revoke", "id_token": null, "id_token_jwt": null, "token_response": {"access_token": "ya29.ImGpB0kQ2N9LHGFRjUZpe8EQ35iCmsjt19OAmFQxg_gOqN-oIWhPDkZH-Htg6m6tXHZCujHjuVTZdK4WtMluYzAddhRmhxece9N-xjgIPYxSIVolAJQp90U1JWgYjeBeplRs", "expires_in": 3600, "scope": "https://www.googleapis.com/auth/spreadsheets.readonly", "token_type": "Bearer"}, "scopes": ["https://www.googleapis.com/auth/spreadsheets.readonly"], "token_info_uri": "https://oauth2.googleapis.com/tokeninfo", "invalid": false, "_class": "OAuth2Credentials", "_module": "oauth2client.client"} \ No newline at end of file diff --git a/bitpacking/templates/ConversionFunctions.h.template b/bitpacking/templates/ConversionFunctions.h.template new file mode 100644 index 0000000000000000000000000000000000000000..ab87ada1f579d07f3a11e6d34b8108382363960f --- /dev/null +++ b/bitpacking/templates/ConversionFunctions.h.template @@ -0,0 +1,56 @@ +/** + * Copyright (c) 2019 Skyward Experimental Rocketry + * Authors: Luca Erbetta + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once +#include <cstdint> +#include <type_traits> + +template<typename T> +inline uint64_t discretizeRange(T value, T min, T max, unsigned int resolution) +{ + static_assert(std::is_arithmetic<T>::value); + + if (value < min) + { + return 0; + } + else if (value > max) + { + return resolution - 1; + } + + return (uint64_t)((value - min) * resolution / (max - min)); + +} + +template <typename T> +inline T undiscretizeRange(uint64_t value, T min, T max, + unsigned int resolution) +{ + static_assert(std::is_arithmetic<T>::value); + + return value * (max - min) / resolution + min; +} + + +$classes \ No newline at end of file diff --git a/bitpacking/templates/Packer.h.template b/bitpacking/templates/Packer.h.template new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/bitpacking/templates/TelemetryPacker.h.template b/bitpacking/templates/TelemetryPacker.h.template new file mode 100644 index 0000000000000000000000000000000000000000..17476f47ec8bae9485434a0b8bd628221832b51a --- /dev/null +++ b/bitpacking/templates/TelemetryPacker.h.template @@ -0,0 +1,63 @@ +/** + * Copyright (c) 2019 Skyward Experimental Rocketry + * Authors: Luca Conterio, Luca Erbetta + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once + +#include "BitPacker.h" +#include "mavlink_lib/hermes/mavlink.h" +#include "ConversionFunctions.h" + +class ${telemetry_name_ccase}Packer +{ +public: + static constexpr int ${mav_tm_name}_PACKET_SIZE = $tm_total_size; + static constexpr int ${mav_tm_name}_SINGLE_PACKET_SIZE_BITS = $tm_partial_size; + + static_assert(MAVLINK_MSG_${mav_tm_name}_FIELD_PAYLOAD_LEN == ${mav_tm_name}_PACKET_SIZE, + "Payload size mismatch! Mavlnk payload size differes from declared size. Maybe your mavlink definitions are outdated?"); + + + + + ${telemetry_name_ccase}Packer(uint8_t *packet) : packet(packet), bitpacker(packet, ${mav_tm_name}_PACKET_SIZE) + { + } + + $pack_functions + + $unpack_functions + +private: + enum FieldIndex + { +$field_indices + }; + + enum FieldSize + { +$field_sizes + }; + + uint8_t *packet; + BitPacker bitpacker; +}; \ No newline at end of file diff --git a/bitpacking/templates/packFunction.cpp.template b/bitpacking/templates/packFunction.cpp.template new file mode 100644 index 0000000000000000000000000000000000000000..d8cfd768f48f433916f39891029b048794c1b671 --- /dev/null +++ b/bitpacking/templates/packFunction.cpp.template @@ -0,0 +1,15 @@ + + bool pack${field_name_ccase}($type $field_name_lcase, size_t packet_index) + { + if(packet_index >= $max_index) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits = $convert_fun($field_name_lcase); + + return bitpacker.pack( + INDEX_$field_name_ucase + packet_index * ${mav_tm_name}_SINGLE_PACKET_SIZE_BITS, + SIZE_$field_name_ucase, bits); + } diff --git a/bitpacking/templates/unpackFunction.cpp.template b/bitpacking/templates/unpackFunction.cpp.template new file mode 100644 index 0000000000000000000000000000000000000000..ecdb4b65d606db04c9704e0bfe42da38d12b7bed --- /dev/null +++ b/bitpacking/templates/unpackFunction.cpp.template @@ -0,0 +1,25 @@ + + bool unpack${field_name_ccase}($type* $field_name_lcase, size_t packet_index) + { + if(packet_index >= $max_index) + { + return false; + } + + // Convert data to a suitable format and store in an unsigned int + uint64_t bits; + + bool success = bitpacker.unpack( + INDEX_$field_name_ucase + packet_index * ${mav_tm_name}_SINGLE_PACKET_SIZE_BITS, + SIZE_$field_name_ucase, &bits); + + if(success) + { + *$field_name_lcase = $convert_fun(bits); + return true; + }else + { + return false; + } + + } diff --git a/utils/tests/Makefile b/bitpacking/tests/Makefile similarity index 68% rename from utils/tests/Makefile rename to bitpacking/tests/Makefile index 753796148abf9f5c6dcd299dfce2fcb68cc62424..2ef8853080508ff8ef5ab7633846ba6bda78c35a 100644 --- a/utils/tests/Makefile +++ b/bitpacking/tests/Makefile @@ -9,5 +9,7 @@ test-bitpacker: test-bitpacker.cpp include/catch.hpp manual-test-bitpacker: manual-test-bitpacker.cpp g++ -O2 -o manual-test-bitpacker manual-test-bitpacker.cpp +test-telemetry: test-telemetry.cpp $(wildcard ../hermes/*.h) + g++ -O2 -o test-telemetry test-telemetry.cpp -I../ -I../../ clean: - rm test-bitpacker manual-test-bitpacker + rm -rvf test-bitpacker manual-test-bitpacker test-telemetry diff --git a/utils/tests/include/catch.hpp b/bitpacking/tests/include/catch.hpp similarity index 100% rename from utils/tests/include/catch.hpp rename to bitpacking/tests/include/catch.hpp diff --git a/utils/tests/manual-test-bitpacker.cpp b/bitpacking/tests/manual-test-bitpacker.cpp similarity index 100% rename from utils/tests/manual-test-bitpacker.cpp rename to bitpacking/tests/manual-test-bitpacker.cpp diff --git a/utils/tests/test-bitpacker.cpp b/bitpacking/tests/test-bitpacker.cpp similarity index 100% rename from utils/tests/test-bitpacker.cpp rename to bitpacking/tests/test-bitpacker.cpp diff --git a/bitpacking/tests/test-telemetry b/bitpacking/tests/test-telemetry new file mode 100755 index 0000000000000000000000000000000000000000..1a19f624d87a85379c4a2266736608ec73f5d636 Binary files /dev/null and b/bitpacking/tests/test-telemetry differ diff --git a/bitpacking/tests/test-telemetry.cpp b/bitpacking/tests/test-telemetry.cpp new file mode 100644 index 0000000000000000000000000000000000000000..197225b50d0042aaebff4ae5fed2beb70f6deb81 --- /dev/null +++ b/bitpacking/tests/test-telemetry.cpp @@ -0,0 +1,26 @@ +#define CATCH_CONFIG_MAIN +#include "include/catch.hpp" + +#include <cstdio> +#include "hermes/HermesPackets.h" + +uint8_t buf[HighRateTMPacker::HR_TM_PACKET_SIZE]; + +TEST_CASE("Test HR_TELEMETRY") +{ + HighRateTMPacker packer{buf}; + packer.packTimestamp(12345678, 0); + packer.packTimestamp(123, 1); + packer.packTimestamp(1111111, 2); + + long long ts; + REQUIRE(packer.unpackTimestamp(&ts, 0)); + REQUIRE(ts == 12345678); + + REQUIRE(packer.unpackTimestamp(&ts, 1)); + REQUIRE(ts == 123); + + REQUIRE(packer.unpackTimestamp(&ts, 2)); + REQUIRE(ts == 1111111); + +} \ No newline at end of file