mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2026-09-15 11:02:58 +00:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5a0066963e | |||
| 99d8fbdff0 | |||
| 09c2c43be0 | |||
| b9771b2350 |
@@ -133,7 +133,6 @@ file(GLOB I2CDEV_SOURCES ${COMMON}/i2cdev_*.cpp)
|
||||
set(CPPSRC
|
||||
main.cpp
|
||||
shell.cpp
|
||||
${COMMON}/acars_packet.cpp
|
||||
${COMMON}/adsb.cpp
|
||||
${COMMON}/adsb_frame.cpp
|
||||
${COMMON}/ais_baseband.cpp
|
||||
@@ -269,7 +268,6 @@ set(CPPSRC
|
||||
ui/ui_tone_key.cpp
|
||||
ui/ui_transmitter.cpp
|
||||
ui/ui_bmpview.cpp
|
||||
apps/acars_app.cpp
|
||||
apps/ais_app.cpp
|
||||
apps/analog_audio_app.cpp
|
||||
# apps/analog_tv_app.cpp
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 Furrtek
|
||||
* Copyright (C) 2024 HTotoo
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
@@ -43,86 +44,87 @@ void BattinfoView::on_timer() {
|
||||
}
|
||||
}
|
||||
|
||||
void BattinfoView::update_results_ads1110(i2cdev::I2cDev_ADS1110* dev) {
|
||||
bool uichg = false;
|
||||
auto voltage = dev->readVoltage();
|
||||
auto percent = battery::BatteryManagement::calc_percent_voltage(voltage);
|
||||
if (percent <= 100)
|
||||
text_percent.set(to_string_dec_uint(percent) + " %");
|
||||
else
|
||||
void BattinfoView::update_result() {
|
||||
if (!battery::BatteryManagement::isDetected()) {
|
||||
text_percent.set("UNKNOWN");
|
||||
if (voltage > 1) {
|
||||
text_voltage.set(to_string_decimal(voltage / 1000.0, 3) + " V");
|
||||
} else {
|
||||
text_voltage.set("UNKNOWN");
|
||||
text_current.set("-");
|
||||
text_charge.set("-");
|
||||
text_cycles.set("-");
|
||||
text_ttef.set("-");
|
||||
text_method.set("-");
|
||||
text_warn.set("");
|
||||
return;
|
||||
}
|
||||
|
||||
// ui hide:
|
||||
if (!labels_opt.hidden()) uichg = true;
|
||||
labels_opt.hidden(true);
|
||||
text_current.hidden(true);
|
||||
text_charge.hidden(true);
|
||||
labels_opt.hidden(true);
|
||||
text_ttef.hidden(true);
|
||||
text_cycles.hidden(true);
|
||||
text_warn.set("");
|
||||
text_ttef.hidden(true);
|
||||
text_method.set("Voltage");
|
||||
button_mode.set_text("Voltage");
|
||||
if (uichg) set_dirty();
|
||||
BatteryStateMessage msg{1, percent, false, voltage};
|
||||
EventDispatcher::send_message(msg);
|
||||
}
|
||||
|
||||
void BattinfoView::update_results_max17055(i2cdev::I2cDev_MAX17055* dev) {
|
||||
bool uichg = false;
|
||||
uint8_t valid_mask = 0;
|
||||
dev->getBatteryInfo(valid_mask, percent, voltage, current);
|
||||
battery::BatteryManagement::getBatteryInfo(valid_mask, percent, voltage, current);
|
||||
// update text fields
|
||||
if (percent <= 100)
|
||||
if (percent <= 100 && (valid_mask & battery::BatteryManagement::BATT_VALID_VOLTAGE) == battery::BatteryManagement::BATT_VALID_VOLTAGE)
|
||||
text_percent.set(to_string_dec_uint(percent) + " %");
|
||||
else
|
||||
text_percent.set("UNKNOWN");
|
||||
if (voltage > 1) {
|
||||
if (voltage > 1 && (valid_mask & battery::BatteryManagement::BATT_VALID_VOLTAGE) == battery::BatteryManagement::BATT_VALID_VOLTAGE) {
|
||||
text_voltage.set(to_string_decimal(voltage / 1000.0, 3) + " V");
|
||||
} else {
|
||||
text_voltage.set("UNKNOWN");
|
||||
}
|
||||
if (labels_opt.hidden()) uichg = true;
|
||||
labels_opt.hidden(false);
|
||||
text_current.hidden(false);
|
||||
text_charge.hidden(false);
|
||||
text_current.set(to_string_dec_int(current) + " mA");
|
||||
text_charge.set(current >= 0 ? "Charging" : "Discharging");
|
||||
labels_opt.hidden(false);
|
||||
text_ttef.hidden(false);
|
||||
// cycles
|
||||
text_cycles.hidden(false);
|
||||
uint16_t cycles = (uint16_t)dev->getValue("Cycles");
|
||||
if (cycles < 2)
|
||||
text_warn.set("SoC improves after 2 cycles");
|
||||
else
|
||||
text_warn.set("");
|
||||
text_cycles.set(to_string_dec_uint(cycles));
|
||||
// ttef
|
||||
text_ttef.hidden(false);
|
||||
float ttef = 0;
|
||||
if (current <= 0) {
|
||||
ttef = dev->getValue("TTE");
|
||||
if ((valid_mask & battery::BatteryManagement::BATT_VALID_CURRENT) == battery::BatteryManagement::BATT_VALID_CURRENT) {
|
||||
if (labels_opt.hidden()) uichg = true;
|
||||
labels_opt.hidden(false);
|
||||
text_current.hidden(false);
|
||||
text_charge.hidden(false);
|
||||
text_current.set(to_string_dec_int(current) + " mA");
|
||||
text_charge.set(current >= 0 ? "Charging" : "Discharging");
|
||||
labels_opt.hidden(false);
|
||||
|
||||
text_ttef.hidden(false);
|
||||
} else {
|
||||
ttef = dev->getValue("TTF");
|
||||
if (!labels_opt.hidden()) uichg = true;
|
||||
labels_opt.hidden(true);
|
||||
text_current.hidden(true);
|
||||
text_charge.hidden(true);
|
||||
text_cycles.hidden(true);
|
||||
text_ttef.hidden(true);
|
||||
text_warn.set("");
|
||||
}
|
||||
// Convert ttef to hours and minutes
|
||||
uint8_t hours = static_cast<uint8_t>(ttef);
|
||||
uint8_t minutes = static_cast<uint8_t>((ttef - hours) * 60 + 0.5); // +0.5 for rounding
|
||||
// Create the formatted string
|
||||
std::string formatted_time;
|
||||
if (hours > 0) {
|
||||
formatted_time += to_string_dec_uint(hours) + "h ";
|
||||
if ((valid_mask & battery::BatteryManagement::BATT_VALID_CYCLES) == battery::BatteryManagement::BATT_VALID_CYCLES) {
|
||||
text_cycles.hidden(false);
|
||||
uint16_t cycles = battery::BatteryManagement::get_cycles();
|
||||
if (cycles < 2)
|
||||
text_warn.set("SoC improves after 2 cycles");
|
||||
else
|
||||
text_warn.set("");
|
||||
text_cycles.set(to_string_dec_uint(cycles));
|
||||
} else {
|
||||
text_cycles.hidden(true);
|
||||
text_warn.set("");
|
||||
}
|
||||
formatted_time += to_string_dec_uint(minutes) + "m";
|
||||
text_ttef.set(formatted_time);
|
||||
if (!battery::BatteryManagement::calcOverride) {
|
||||
if ((valid_mask & battery::BatteryManagement::BATT_VALID_TTEF) == battery::BatteryManagement::BATT_VALID_TTEF) {
|
||||
text_ttef.hidden(false);
|
||||
float ttef = 0;
|
||||
if (current <= 0) {
|
||||
ttef = battery::BatteryManagement::get_tte();
|
||||
} else {
|
||||
ttef = battery::BatteryManagement::get_ttf();
|
||||
}
|
||||
|
||||
// Convert ttef to hours and minutes
|
||||
uint8_t hours = static_cast<uint8_t>(ttef);
|
||||
uint8_t minutes = static_cast<uint8_t>((ttef - hours) * 60 + 0.5); // +0.5 for rounding
|
||||
|
||||
// Create the formatted string
|
||||
std::string formatted_time;
|
||||
if (hours > 0) {
|
||||
formatted_time += to_string_dec_uint(hours) + "h ";
|
||||
}
|
||||
formatted_time += to_string_dec_uint(minutes) + "m";
|
||||
|
||||
text_ttef.set(formatted_time);
|
||||
} else {
|
||||
text_ttef.hidden(true);
|
||||
}
|
||||
if ((valid_mask & battery::BatteryManagement::BATT_VALID_PERCENT) == battery::BatteryManagement::BATT_VALID_PERCENT) {
|
||||
text_method.set("IC");
|
||||
button_mode.set_text("Volt");
|
||||
} else {
|
||||
@@ -135,30 +137,6 @@ void BattinfoView::update_results_max17055(i2cdev::I2cDev_MAX17055* dev) {
|
||||
EventDispatcher::send_message(msg);
|
||||
}
|
||||
|
||||
void BattinfoView::update_result() {
|
||||
auto dev = i2cdev::I2CDevManager::get_dev_by_model(I2CDEVMDL_MAX17055);
|
||||
if (dev) {
|
||||
update_results_max17055((i2cdev::I2cDev_MAX17055*)dev);
|
||||
return;
|
||||
}
|
||||
|
||||
dev = i2cdev::I2CDevManager::get_dev_by_model(I2CDEVMDL_ADS1110);
|
||||
if (dev) {
|
||||
update_results_ads1110((i2cdev::I2cDev_ADS1110*)dev);
|
||||
return;
|
||||
}
|
||||
|
||||
// no dev found
|
||||
text_percent.set("UNKNOWN");
|
||||
text_voltage.set("UNKNOWN");
|
||||
text_current.set("-");
|
||||
text_charge.set("-");
|
||||
text_cycles.set("-");
|
||||
text_ttef.set("-");
|
||||
text_method.set("-");
|
||||
text_warn.set("");
|
||||
}
|
||||
|
||||
BattinfoView::BattinfoView(NavigationView& nav)
|
||||
: nav_{nav} {
|
||||
add_children({&labels,
|
||||
@@ -208,4 +186,4 @@ BattinfoView::~BattinfoView() {
|
||||
thread = nullptr;
|
||||
}
|
||||
}
|
||||
} // namespace ui
|
||||
} // namespace ui
|
||||
@@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 Furrtek
|
||||
* Copyright (C) 2024 HTotoo
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
@@ -28,8 +29,6 @@
|
||||
#include "ui_navigation.hpp"
|
||||
#include "string_format.hpp"
|
||||
#include "i2cdevmanager.hpp"
|
||||
#include "i2cdev_max17055.hpp"
|
||||
#include "i2cdev_ads1110.hpp"
|
||||
|
||||
namespace ui {
|
||||
class BattinfoView : public View {
|
||||
@@ -46,8 +45,6 @@ class BattinfoView : public View {
|
||||
|
||||
private:
|
||||
void update_result();
|
||||
void update_results_max17055(i2cdev::I2cDev_MAX17055* dev);
|
||||
void update_results_ads1110(i2cdev::I2cDev_ADS1110* dev);
|
||||
void on_timer();
|
||||
NavigationView& nav_;
|
||||
uint16_t timer_period = 60;
|
||||
@@ -109,4 +106,4 @@ class BattinfoView : public View {
|
||||
|
||||
} /* namespace ui */
|
||||
|
||||
#endif /*__UI_BATTINFO__*/
|
||||
#endif /*__UI_BATTINFO__*/
|
||||
@@ -14,7 +14,7 @@ class BatteryCapacityView : public View {
|
||||
public:
|
||||
BatteryCapacityView(NavigationView& nav);
|
||||
void focus() override;
|
||||
std::string title() const override { return "MAX17055 Registers"; }
|
||||
std::string title() const override { return "Battery Registers"; }
|
||||
|
||||
bool on_encoder(const EncoderEvent delta) override;
|
||||
|
||||
|
||||
Vendored
+34
-47
@@ -20,45 +20,26 @@
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "acars_app.hpp"
|
||||
|
||||
#include "baseband_api.hpp"
|
||||
#include "portapack_persistent_memory.hpp"
|
||||
#include "file_path.hpp"
|
||||
#include "audio.hpp"
|
||||
|
||||
#include "acars_app.hpp"
|
||||
using namespace portapack;
|
||||
using namespace acars;
|
||||
|
||||
#include "string_format.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
void ACARSLogger::log_raw_data(const acars::Packet& packet, const uint32_t frequency) {
|
||||
(void)frequency;
|
||||
std::string entry{}; //= "Raw: F:" + to_string_dec_uint(frequency) + "Hz ";
|
||||
entry.reserve(256);
|
||||
namespace ui::external_app::acars_rx {
|
||||
|
||||
// Raw hex dump of all the bytes
|
||||
// for (size_t c = 0; c < packet.length(); c += 32)
|
||||
// entry += to_string_hex(packet.read(c, 32), 8) + " ";
|
||||
|
||||
for (size_t c = 0; c < 256; c += 32)
|
||||
entry += to_string_bin(packet.read(c, 32), 32);
|
||||
|
||||
log_file.write_entry(packet.received_at(), entry);
|
||||
void ACARSLogger::log_str(std::string msg) {
|
||||
log_file.write_entry(msg);
|
||||
}
|
||||
|
||||
/*void ACARSLogger::log_decoded(
|
||||
const acars::Packet& packet,
|
||||
const std::string text) {
|
||||
|
||||
log_file.write_entry(packet.timestamp(), text);
|
||||
}*/
|
||||
|
||||
namespace ui {
|
||||
|
||||
ACARSAppView::ACARSAppView(NavigationView& nav)
|
||||
: nav_{nav} {
|
||||
baseband::run_image(portapack::spi_flash::image_tag_acars);
|
||||
baseband::run_prepared_image(portapack::memory::map::m4_code.base());
|
||||
|
||||
add_children({&rssi,
|
||||
&channel,
|
||||
@@ -66,6 +47,7 @@ ACARSAppView::ACARSAppView(NavigationView& nav)
|
||||
&field_lna,
|
||||
&field_vga,
|
||||
&field_frequency,
|
||||
&field_volume,
|
||||
&check_log,
|
||||
&console});
|
||||
|
||||
@@ -79,6 +61,9 @@ ACARSAppView::ACARSAppView(NavigationView& nav)
|
||||
logger = std::make_unique<ACARSLogger>();
|
||||
if (logger)
|
||||
logger->append(logs_dir / u"ACARS.TXT");
|
||||
|
||||
audio::set_rate(audio::Rate::Hz_24000);
|
||||
audio::output::start();
|
||||
}
|
||||
|
||||
ACARSAppView::~ACARSAppView() {
|
||||
@@ -90,29 +75,31 @@ void ACARSAppView::focus() {
|
||||
field_frequency.focus();
|
||||
}
|
||||
|
||||
void ACARSAppView::on_packet(const acars::Packet& packet) {
|
||||
void ACARSAppView::on_packet(const ACARSPacketMessage* packet) {
|
||||
std::string console_info;
|
||||
|
||||
/*if (!packet.is_valid()) {
|
||||
console_info = to_string_datetime(packet.received_at(), HMS);
|
||||
console_info += " INVALID";
|
||||
|
||||
console.writeln(console_info);
|
||||
} else {
|
||||
console_info = to_string_datetime(packet.received_at(), HMS);
|
||||
console_info += ":" + to_string_bin(packet.read(0, 32), 32);
|
||||
//console_info += " REG:" + packet.registration_number();
|
||||
|
||||
console.writeln(console_info);
|
||||
}*/
|
||||
|
||||
packet_counter++;
|
||||
if (packet_counter % 10 == 0)
|
||||
console.writeln("Block #" + to_string_dec_uint(packet_counter));
|
||||
|
||||
// Log raw data whatever it contains
|
||||
if (logger && logging)
|
||||
logger->log_raw_data(packet, receiver_model.target_frequency());
|
||||
if (packet->state == 255) {
|
||||
// got a packet, parse it, and display
|
||||
rtc::RTC datetime;
|
||||
rtc_time::now(datetime);
|
||||
// todo parity error recovery
|
||||
console_info = to_string_datetime(datetime, HMS);
|
||||
console_info += ": ";
|
||||
console_info += packet->message;
|
||||
console.writeln(console_info);
|
||||
// Log raw data whatever it contains
|
||||
if (logger && logging)
|
||||
logger->log_str(console_info);
|
||||
} else {
|
||||
// debug message arrived
|
||||
console_info = "State: ";
|
||||
console_info += to_string_dec_int(packet->state);
|
||||
console_info += " lastbyte: ";
|
||||
console_info += to_string_dec_uint(packet->message[0]);
|
||||
console.writeln(console_info);
|
||||
if (logger && logging)
|
||||
logger->log_str(console_info);
|
||||
}
|
||||
}
|
||||
|
||||
} /* namespace ui */
|
||||
} // namespace ui::external_app::acars_rx
|
||||
Vendored
+12
-14
@@ -31,23 +31,19 @@
|
||||
#include "ui_rssi.hpp"
|
||||
#include "log_file.hpp"
|
||||
|
||||
#include "acars_packet.hpp"
|
||||
namespace ui::external_app::acars_rx {
|
||||
|
||||
class ACARSLogger {
|
||||
public:
|
||||
Optional<File::Error> append(const std::filesystem::path& filename) {
|
||||
return log_file.append(filename);
|
||||
}
|
||||
|
||||
void log_raw_data(const acars::Packet& packet, const uint32_t frequency);
|
||||
// void log_decoded(const acars::Packet& packet, const std::string text);
|
||||
void log_str(std::string msg);
|
||||
|
||||
private:
|
||||
LogFile log_file{};
|
||||
};
|
||||
|
||||
namespace ui {
|
||||
|
||||
class ACARSAppView : public View {
|
||||
public:
|
||||
ACARSAppView(NavigationView& nav);
|
||||
@@ -55,12 +51,12 @@ class ACARSAppView : public View {
|
||||
|
||||
void focus() override;
|
||||
|
||||
std::string title() const override { return "ACARS (WIP)"; };
|
||||
std::string title() const override { return "ACARS"; };
|
||||
|
||||
private:
|
||||
NavigationView& nav_;
|
||||
RxRadioState radio_state_{
|
||||
131550000 /* frequency */,
|
||||
131825000 /* frequency */,
|
||||
1750000 /* bandwidth */,
|
||||
2457600 /* sampling rate */
|
||||
};
|
||||
@@ -85,7 +81,7 @@ class ACARSAppView : public View {
|
||||
{0 * 8, 0 * 8},
|
||||
nav_};
|
||||
Checkbox check_log{
|
||||
{22 * 8, 21},
|
||||
{16 * 8, 1 * 16},
|
||||
3,
|
||||
"LOG",
|
||||
true};
|
||||
@@ -93,19 +89,21 @@ class ACARSAppView : public View {
|
||||
Console console{
|
||||
{0, 3 * 16, 240, 256}};
|
||||
|
||||
AudioVolumeField field_volume{
|
||||
{28 * 8, 1 * 16}};
|
||||
|
||||
std::unique_ptr<ACARSLogger> logger{};
|
||||
|
||||
void on_packet(const acars::Packet& packet);
|
||||
void on_packet(const ACARSPacketMessage* packet);
|
||||
|
||||
MessageHandlerRegistration message_handler_packet{
|
||||
Message::ID::ACARSPacket,
|
||||
[this](Message* const p) {
|
||||
const auto message = static_cast<const ACARSPacketMessage*>(p);
|
||||
const acars::Packet packet{message->packet};
|
||||
this->on_packet(packet);
|
||||
this->on_packet(message);
|
||||
}};
|
||||
};
|
||||
|
||||
} /* namespace ui */
|
||||
} // namespace ui::external_app::acars_rx
|
||||
|
||||
#endif /*__ACARS_APP_H__*/
|
||||
#endif /*__ACARS_APP_H__*/
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Bernd Herzog
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "ui.hpp"
|
||||
#include "acars_app.hpp"
|
||||
#include "ui_navigation.hpp"
|
||||
#include "external_app.hpp"
|
||||
|
||||
namespace ui::external_app::acars_rx {
|
||||
void initialize_app(ui::NavigationView& nav) {
|
||||
nav.push<ACARSAppView>();
|
||||
}
|
||||
} // namespace ui::external_app::acars_rx
|
||||
|
||||
extern "C" {
|
||||
|
||||
__attribute__((section(".external_app.app_acars_rx.application_information"), used)) application_information_t _application_information_acars_rx = {
|
||||
/*.memory_location = */ (uint8_t*)0x00000000,
|
||||
/*.externalAppEntry = */ ui::external_app::acars_rx::initialize_app,
|
||||
/*.header_version = */ CURRENT_HEADER_VERSION,
|
||||
/*.app_version = */ VERSION_MD5,
|
||||
|
||||
/*.app_name = */ "ACARS",
|
||||
/*.bitmap_data = */ {
|
||||
0x80,
|
||||
0x01,
|
||||
0xC0,
|
||||
0x03,
|
||||
0xC0,
|
||||
0x03,
|
||||
0xC0,
|
||||
0x03,
|
||||
0xC0,
|
||||
0x03,
|
||||
0xE0,
|
||||
0x07,
|
||||
0xF8,
|
||||
0x1F,
|
||||
0xFE,
|
||||
0x7F,
|
||||
0xFF,
|
||||
0xFF,
|
||||
0xFF,
|
||||
0xFF,
|
||||
0xC0,
|
||||
0x03,
|
||||
0xC0,
|
||||
0x03,
|
||||
0xC0,
|
||||
0x03,
|
||||
0xE0,
|
||||
0x07,
|
||||
0xF0,
|
||||
0x0F,
|
||||
0xF8,
|
||||
0x1F,
|
||||
},
|
||||
/*.icon_color = */ ui::Color::orange().v,
|
||||
/*.menu_location = */ app_location_t::RX,
|
||||
|
||||
/*.m4_app_tag = portapack::spi_flash::image_tag_acars */ {'P', 'A', 'C', 'A'},
|
||||
/*.m4_app_offset = */ 0x00000000, // will be filled at compile time
|
||||
};
|
||||
}
|
||||
@@ -102,6 +102,11 @@ set(EXTCPPSRC
|
||||
external/random_password/ui_random_password.cpp
|
||||
external/random_password/sha512.cpp
|
||||
external/random_password/sha512.h
|
||||
|
||||
#acars
|
||||
external/acars_rx/main.cpp
|
||||
external/acars_rx/acars_app.cpp
|
||||
|
||||
)
|
||||
|
||||
set(EXTAPPLIST
|
||||
@@ -129,4 +134,5 @@ set(EXTAPPLIST
|
||||
morse_tx
|
||||
sstvtx
|
||||
random_password
|
||||
#acars_rx
|
||||
)
|
||||
|
||||
+10
@@ -47,6 +47,7 @@ MEMORY
|
||||
ram_external_app_morse_tx(rwx) : org = 0xADC60000, len = 32k
|
||||
ram_external_app_sstvtx(rwx) : org = 0xADC70000, len = 32k
|
||||
ram_external_app_random_password(rwx) : org = 0xADC80000, len = 32k
|
||||
ram_external_app_acars_rx(rwx) : org = 0xADC90000, len = 32k
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
@@ -197,4 +198,13 @@ SECTIONS
|
||||
*(*ui*external_app*random_password*);
|
||||
} > ram_external_app_random_password
|
||||
|
||||
.external_app_acars_rx : ALIGN(4) SUBALIGN(4)
|
||||
{
|
||||
KEEP(*(.external_app.app_acars_rx.application_information));
|
||||
*(*ui*external_app*acars_rx*);
|
||||
} > ram_external_app_acars_rx
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -31,8 +31,10 @@ using namespace std::literals;
|
||||
|
||||
const std::string_view filetype_name = "Filetype"sv;
|
||||
const std::string_view frequency_name = "Frequency"sv;
|
||||
const std::string_view latitude_name = "Latitute"sv;
|
||||
const std::string_view longitude_name = "Longitude"sv;
|
||||
const std::string_view latitude_name_old = "Latitute"sv;
|
||||
const std::string_view longitude_name_old = "Longitude"sv;
|
||||
const std::string_view latitude_name = "Lat"sv;
|
||||
const std::string_view longitude_name = "Lon"sv;
|
||||
const std::string_view protocol_name = "Protocol"sv;
|
||||
const std::string_view preset_name = "Preset"sv;
|
||||
const std::string_view te_name = "TE"sv; // only in BinRAW
|
||||
@@ -93,6 +95,10 @@ Optional<flippersub_metadata> read_flippersub_file(const fs::path& path) {
|
||||
parse_float_meta(fixed, metadata.latitude);
|
||||
else if (cols[0] == longitude_name)
|
||||
parse_float_meta(fixed, metadata.longitude);
|
||||
else if (cols[0] == latitude_name_old)
|
||||
parse_float_meta(fixed, metadata.latitude);
|
||||
else if (cols[0] == longitude_name_old)
|
||||
parse_float_meta(fixed, metadata.longitude);
|
||||
else if (cols[0] == protocol_name) {
|
||||
if (fixed == "RAW") metadata.protocol = FLIPPER_PROTO_RAW;
|
||||
if (fixed == "BinRAW") metadata.protocol = FLIPPER_PROTO_BINRAW;
|
||||
|
||||
@@ -86,7 +86,6 @@
|
||||
#include "ui_battinfo.hpp"
|
||||
#include "ui_external_items_menu_loader.hpp"
|
||||
|
||||
// #include "acars_app.hpp"
|
||||
#include "ais_app.hpp"
|
||||
#include "analog_audio_app.hpp"
|
||||
// #include "analog_tv_app.hpp" //moved to ext
|
||||
@@ -157,7 +156,6 @@ const NavigationView::AppList NavigationView::appList = {
|
||||
{nullptr, "Debug", HOME, Color::light_grey(), &bitmap_icon_debug, new ViewFactory<DebugMenuView>()},
|
||||
//{"about", "About", HOME, Color::cyan(), nullptr, new ViewFactory<AboutView>()},
|
||||
/* RX ********************************************************************/
|
||||
//{"acars", "ACARS", RX, Color::yellow(), &bitmap_icon_adsb, new ViewFactory<ACARSAppView>()},
|
||||
{"adsbrx", "ADS-B", RX, Color::green(), &bitmap_icon_adsb, new ViewFactory<ADSBRxView>()},
|
||||
{"ais", "AIS Boats", RX, Color::green(), &bitmap_icon_ais, new ViewFactory<AISAppView>()},
|
||||
{"aprsrx", "APRS", RX, Color::green(), &bitmap_icon_aprs, new ViewFactory<APRSRXView>()},
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
#include "sd_card.hpp"
|
||||
#include "external_app.hpp"
|
||||
#include "view_factory.hpp"
|
||||
#include "battery.hpp"
|
||||
|
||||
// for incrementing fake date when RTC battery is dead
|
||||
#define DATE_FILEFLAG u"/SETTINGS/DATE_FILEFLAG"
|
||||
|
||||
@@ -47,10 +47,8 @@ class UsbSerialAsyncmsg {
|
||||
};
|
||||
|
||||
/*Notes:
|
||||
* - Don't use MayhemHub since it currently not support real time serial output
|
||||
* - If you don't use this class linker will drop it so it won't use any space
|
||||
* - so delete all debug things before you push your code to production
|
||||
* - use this client to filter only PP devices: https://github.com/zxkmm/Pyserial-Demo-portapack
|
||||
* - Don't use MayhemHub since it's currently not supporting real time serial output (it's hiding some instructions to support some features like screenshot, and it's filtering out answers by response type)
|
||||
* - use this client to debug with serial: https://github.com/portapack-mayhem/mayhem-cli
|
||||
* - usage:
|
||||
* portapack::async_tx_enabled = true; // note that use this when debugging, unless the msg would be forbidden. but don't use this in production, since it's not real async and multiple serial transmittions will broken each other. if this class is used in other scene in the future, just use command to cover (protect your serial tramsnitton) in your extern thing: asyncmsg enable --- your cmd --- asyncmsg disable
|
||||
* #include "usb_serial_asyncmsg.hpp"
|
||||
|
||||
@@ -314,12 +314,6 @@ endmacro()
|
||||
|
||||
set(add_to_firmware TRUE)
|
||||
|
||||
### ACARS RX
|
||||
|
||||
set(MODE_CPPSRC
|
||||
proc_acars.cpp
|
||||
)
|
||||
DeclareTargets(PACA acars)
|
||||
|
||||
### ADS-B RX
|
||||
|
||||
@@ -579,6 +573,15 @@ DeclareTargets(PUSB sd_over_usb)
|
||||
### Place external app and disabled images below so they don't get added to the firmware
|
||||
set(add_to_firmware FALSE)
|
||||
|
||||
|
||||
### ACARS RX
|
||||
|
||||
set(MODE_CPPSRC
|
||||
proc_acars.cpp
|
||||
)
|
||||
DeclareTargets(PACA acars)
|
||||
|
||||
|
||||
### AFSK RX
|
||||
|
||||
set(MODE_CPPSRC
|
||||
|
||||
@@ -20,18 +20,27 @@
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "proc_acars.hpp"
|
||||
|
||||
#include "portapack_shared_memory.hpp"
|
||||
|
||||
#include "proc_acars.hpp"
|
||||
#include "dsp_fir_taps.hpp"
|
||||
#include "audio_dma.hpp"
|
||||
|
||||
#include "event_m4.hpp"
|
||||
|
||||
#define SYN 0x16
|
||||
#define SOH 0x01
|
||||
#define STX 0x02
|
||||
#define ETX 0x83
|
||||
#define ETB 0x97
|
||||
#define DLE 0x7f
|
||||
|
||||
ACARSProcessor::ACARSProcessor() {
|
||||
audio::dma::init_audio_out();
|
||||
decim_0.configure(taps_11k0_decim_0.taps);
|
||||
decim_1.configure(taps_11k0_decim_1.taps);
|
||||
packet.clear();
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
audio_output.configure(false);
|
||||
baseband_thread.start();
|
||||
}
|
||||
|
||||
@@ -45,6 +54,9 @@ void ACARSProcessor::execute(const buffer_c8_t& buffer) {
|
||||
/* 38.4kHz, 32 samples */
|
||||
feed_channel_stats(decimator_out);
|
||||
|
||||
auto audio = demod.execute(decimator_out, audio_buffer);
|
||||
audio_output.write(audio);
|
||||
|
||||
for (size_t i = 0; i < decimator_out.count; i++) {
|
||||
if (mf.execute_once(decimator_out.p[i])) {
|
||||
clock_recovery(mf.get_output());
|
||||
@@ -52,24 +64,134 @@ void ACARSProcessor::execute(const buffer_c8_t& buffer) {
|
||||
}
|
||||
}
|
||||
|
||||
void ACARSProcessor::consume_symbol(
|
||||
const float raw_symbol) {
|
||||
const uint_fast8_t sliced_symbol = (raw_symbol >= 0.0f) ? 1 : 0;
|
||||
// const auto decoded_symbol = acars_decode(sliced_symbol);
|
||||
|
||||
// DEBUG
|
||||
packet.add(sliced_symbol);
|
||||
if (packet.size() == 256) {
|
||||
payload_handler(packet);
|
||||
packet.clear();
|
||||
}
|
||||
|
||||
// packet_builder.execute(decoded_symbol);
|
||||
void ACARSProcessor::add_bit(uint8_t bit) {
|
||||
decode_data = decode_data << 1 | bit;
|
||||
decode_count_bit++;
|
||||
}
|
||||
|
||||
void ACARSProcessor::payload_handler(
|
||||
const baseband::Packet& packet) {
|
||||
const ACARSPacketMessage message{packet};
|
||||
uint16_t ACARSProcessor::update_crc(uint8_t dataByte) {
|
||||
(void)dataByte;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ACARSProcessor::sendDebug() {
|
||||
// if (curr_state <= 1) return;
|
||||
message.state = curr_state;
|
||||
shared_memory.application_queue.push(message);
|
||||
}
|
||||
|
||||
void ACARSProcessor::reset() {
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
curr_state = WSYN;
|
||||
message.msg_len = 0;
|
||||
memset(message.message, 0, 250);
|
||||
message.crc[0] = 0;
|
||||
message.crc[1] = 0;
|
||||
parity_errors = 0;
|
||||
}
|
||||
|
||||
void ACARSProcessor::consume_symbol(const float raw_symbol) {
|
||||
const uint_fast8_t sliced_symbol = (raw_symbol >= 0.0f) ? 1 : 0;
|
||||
|
||||
add_bit(sliced_symbol);
|
||||
if (curr_state == WSYN && decode_count_bit == 8) {
|
||||
if ((decode_data & 0xff) == SYN) {
|
||||
curr_state = SYN2;
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
} else {
|
||||
decode_count_bit -= 1; // just drop the first bit
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (curr_state == SYN2 && decode_count_bit == 8) {
|
||||
if ((decode_data & 0xff) == SYN) {
|
||||
curr_state = SOH1;
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
sendDebug();
|
||||
return;
|
||||
}
|
||||
// here i don't have the right packets. so reset
|
||||
reset();
|
||||
}
|
||||
if (curr_state == SOH1 && decode_count_bit == 8) {
|
||||
if ((decode_data & 0xff) == SOH) {
|
||||
reset();
|
||||
curr_state = TXT;
|
||||
sendDebug();
|
||||
return;
|
||||
}
|
||||
message.message[0] = (decode_data & 0xff); // debug
|
||||
reset();
|
||||
sendDebug();
|
||||
}
|
||||
if (curr_state == TXT && decode_count_bit == 8) {
|
||||
uint8_t ch = (decode_data & 0xff);
|
||||
message.message[message.msg_len++] = ch;
|
||||
|
||||
if (!ParityCheck::parity_check(ch)) {
|
||||
// parity error
|
||||
parity_errors++;
|
||||
if (parity_errors > 4) {
|
||||
reset(); // too many parity errors, skip packet
|
||||
sendDebug();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (ch == ETX || ch == ETB) {
|
||||
curr_state = CRC1;
|
||||
sendDebug();
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
return;
|
||||
}
|
||||
if (message.msg_len > 240) {
|
||||
reset();
|
||||
sendDebug();
|
||||
}
|
||||
if (message.msg_len > 20 && ch == DLE) {
|
||||
message.msg_len -= 3;
|
||||
message.crc[0] = message.message[message.msg_len];
|
||||
message.crc[1] = message.message[message.msg_len + 1];
|
||||
curr_state = CRC2;
|
||||
sendDebug();
|
||||
// to hack the path:
|
||||
decode_data = message.crc[1];
|
||||
} else {
|
||||
decode_count_bit = 0;
|
||||
decode_data = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (curr_state == CRC1 && decode_count_bit == 8) {
|
||||
message.crc[0] = (decode_data & 0xff);
|
||||
curr_state = CRC2;
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
sendDebug();
|
||||
}
|
||||
|
||||
if (curr_state == CRC2 && decode_count_bit == 8) {
|
||||
message.crc[1] = (decode_data & 0xff);
|
||||
// send it to app cpu, and it'll take care of the rest
|
||||
payload_handler();
|
||||
reset();
|
||||
curr_state = END;
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
sendDebug();
|
||||
}
|
||||
if (curr_state == END && decode_count_bit == 8) {
|
||||
reset();
|
||||
sendDebug();
|
||||
}
|
||||
}
|
||||
|
||||
void ACARSProcessor::payload_handler() {
|
||||
message.state = 255; // to indicate this is an actual payload, not a debug packet
|
||||
shared_memory.application_queue.push(message);
|
||||
}
|
||||
|
||||
@@ -77,4 +199,4 @@ int main() {
|
||||
EventDispatcher event_dispatcher{std::make_unique<ACARSProcessor>()};
|
||||
event_dispatcher.run();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -46,11 +46,15 @@
|
||||
#include "baseband_packet.hpp"
|
||||
|
||||
#include "message.hpp"
|
||||
#include "dsp_demodulate.hpp"
|
||||
#include "audio_output.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <bitset>
|
||||
|
||||
#include "crc.hpp"
|
||||
|
||||
// AIS:
|
||||
// IN: 2457600/8/8 = 38400
|
||||
// Offset: 2457600/4 = 614400 (614400/8/8 = 9600)
|
||||
@@ -101,6 +105,14 @@ constexpr std::array<std::complex<float>, 16> rect_taps_38k4_4k8_1t_2k4_p{{
|
||||
{4.4194173824e-02f, -4.4194173824e-02f},
|
||||
}};
|
||||
|
||||
typedef enum { WSYN,
|
||||
SYN2,
|
||||
SOH1,
|
||||
TXT,
|
||||
CRC1,
|
||||
CRC2,
|
||||
END } Acarsstate;
|
||||
|
||||
class ACARSProcessor : public BasebandProcessor {
|
||||
public:
|
||||
ACARSProcessor();
|
||||
@@ -124,24 +136,32 @@ class ACARSProcessor : public BasebandProcessor {
|
||||
2400,
|
||||
{0.0555f},
|
||||
[this](const float symbol) { this->consume_symbol(symbol); }};
|
||||
symbol_coding::ACARSDecoder acars_decode{};
|
||||
/*PacketBuilder<BitPattern, NeverMatch, FixedLength> packet_builder {
|
||||
{ 0b011010000110100010000000, 24, 1 }, // SYN, SYN, SOH
|
||||
{ },
|
||||
{ 128 },
|
||||
[this](const baseband::Packet& packet) {
|
||||
this->payload_handler(packet);
|
||||
}
|
||||
};*/
|
||||
baseband::Packet packet{};
|
||||
|
||||
uint16_t update_crc(uint8_t dataByte);
|
||||
void consume_symbol(const float symbol);
|
||||
void payload_handler();
|
||||
void add_bit(uint8_t bit);
|
||||
void reset();
|
||||
void sendDebug();
|
||||
|
||||
std::array<float, 32> audio{};
|
||||
const buffer_f32_t audio_buffer{
|
||||
audio.data(),
|
||||
audio.size()};
|
||||
dsp::demodulate::AM demod{};
|
||||
AudioOutput audio_output{};
|
||||
|
||||
Acarsstate curr_state = WSYN;
|
||||
|
||||
uint32_t decode_data = 0;
|
||||
uint8_t decode_count_bit = 0;
|
||||
ACARSPacketMessage message{};
|
||||
uint8_t parity_errors = 0;
|
||||
|
||||
/* NB: Threads should be the last members in the class definition. */
|
||||
BasebandThread baseband_thread{
|
||||
baseband_fs, this, baseband::Direction::Receive, /*auto_start*/ false};
|
||||
RSSIThread rssi_thread{};
|
||||
|
||||
void consume_symbol(const float symbol);
|
||||
void payload_handler(const baseband::Packet& packet);
|
||||
};
|
||||
|
||||
#endif /*__PROC_ACARS_H__*/
|
||||
#endif /*__PROC_ACARS_H__*/
|
||||
@@ -1,107 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2018 Furrtek
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "acars_packet.hpp"
|
||||
|
||||
#include "crc.hpp"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
namespace acars {
|
||||
|
||||
size_t Packet::length() const {
|
||||
return packet_.size();
|
||||
}
|
||||
|
||||
bool Packet::is_valid() const {
|
||||
return true; // length_valid() && crc_ok();
|
||||
}
|
||||
|
||||
Timestamp Packet::received_at() const {
|
||||
return packet_.timestamp();
|
||||
}
|
||||
|
||||
uint8_t Packet::block_id() const {
|
||||
return field_.read(96, 8);
|
||||
}
|
||||
|
||||
std::string Packet::registration_number() const {
|
||||
std::string result;
|
||||
result.reserve(7);
|
||||
|
||||
const size_t character_length = 8;
|
||||
for (size_t i = 16; i < (16 + 7 * character_length); i += character_length) {
|
||||
result += (field_.read(i, character_length) & 0x7F);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t Packet::read(const size_t start_bit, const size_t length) const {
|
||||
return field_.read(start_bit, length);
|
||||
}
|
||||
|
||||
/*std::string Packet::text(
|
||||
const size_t start_bit,
|
||||
const size_t character_count
|
||||
) const {
|
||||
std::string result;
|
||||
result.reserve(character_count);
|
||||
|
||||
const size_t character_length = 6;
|
||||
const size_t end_bit = start_bit + character_count * character_length;
|
||||
for(size_t i=start_bit; i<end_bit; i+=character_length) {
|
||||
result += char_to_ascii(field_.read(i, character_length));
|
||||
}
|
||||
|
||||
return result;
|
||||
}*/
|
||||
|
||||
bool Packet::crc_ok() const {
|
||||
CRCReader field_crc{packet_};
|
||||
CRC<16> acars_fcs{0x1021, 0x0000, 0x0000};
|
||||
|
||||
for (size_t i = 0; i < data_length(); i += 8) {
|
||||
acars_fcs.process_byte(field_crc.read(i, 8));
|
||||
}
|
||||
|
||||
return (acars_fcs.checksum() == (unsigned)field_crc.read(data_length(), fcs_length));
|
||||
}
|
||||
|
||||
size_t Packet::data_and_fcs_length() const {
|
||||
return length() - 8;
|
||||
}
|
||||
|
||||
size_t Packet::data_length() const {
|
||||
return data_and_fcs_length() - fcs_length;
|
||||
}
|
||||
|
||||
bool Packet::length_valid() const {
|
||||
const size_t extra_bits = data_and_fcs_length() & 7;
|
||||
if (extra_bits != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace acars
|
||||
@@ -1,74 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2018 Furrtek
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __ACARS_PACKET_H__
|
||||
#define __ACARS_PACKET_H__
|
||||
|
||||
#include "baseband_packet.hpp"
|
||||
#include "field_reader.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
|
||||
namespace acars {
|
||||
|
||||
class Packet {
|
||||
public:
|
||||
constexpr Packet(
|
||||
const baseband::Packet& packet)
|
||||
: packet_{packet},
|
||||
field_{packet_} {
|
||||
}
|
||||
|
||||
size_t length() const;
|
||||
|
||||
bool is_valid() const;
|
||||
|
||||
Timestamp received_at() const;
|
||||
|
||||
uint8_t block_id() const;
|
||||
std::string registration_number() const;
|
||||
|
||||
uint32_t read(const size_t start_bit, const size_t length) const;
|
||||
// std::string text(const size_t start_bit, const size_t character_count) const;
|
||||
|
||||
bool crc_ok() const;
|
||||
|
||||
private:
|
||||
using Reader = FieldReader<baseband::Packet, BitRemapByteReverse>;
|
||||
using CRCReader = FieldReader<baseband::Packet, BitRemapNone>;
|
||||
|
||||
const baseband::Packet packet_;
|
||||
const Reader field_;
|
||||
|
||||
const size_t fcs_length = 16;
|
||||
|
||||
size_t data_and_fcs_length() const;
|
||||
size_t data_length() const;
|
||||
|
||||
bool length_valid() const;
|
||||
};
|
||||
|
||||
} /* namespace acars */
|
||||
|
||||
#endif /*__ACARS_PACKET_H__*/
|
||||
@@ -1,6 +1,8 @@
|
||||
#include "battery.hpp"
|
||||
#include "portapack.hpp"
|
||||
#include "i2cdevmanager.hpp"
|
||||
#include "i2cdev_max17055.hpp"
|
||||
#include "i2cdev_ads1110.hpp"
|
||||
|
||||
namespace battery {
|
||||
|
||||
bool BatteryManagement::calcOverride = false;
|
||||
@@ -27,4 +29,49 @@ uint8_t BatteryManagement::calc_percent_voltage(uint16_t voltage) {
|
||||
return batteryPercentage;
|
||||
}
|
||||
|
||||
// helper function to get data from ANY batt management ic
|
||||
void BatteryManagement::getBatteryInfo(uint8_t& valid_mask, uint8_t& percent, uint16_t& voltage, int32_t& current) {
|
||||
auto dev = i2cdev::I2CDevManager::get_dev_by_model(I2CDEVMDL_MAX17055);
|
||||
if (dev) {
|
||||
((i2cdev::I2cDev_MAX17055*)dev)->getBatteryInfo(valid_mask, percent, voltage, current);
|
||||
return;
|
||||
}
|
||||
dev = i2cdev::I2CDevManager::get_dev_by_model(I2CDEVMDL_ADS1110);
|
||||
if (dev) {
|
||||
voltage = ((i2cdev::I2cDev_ADS1110*)dev)->readVoltage();
|
||||
percent = calc_percent_voltage(voltage);
|
||||
valid_mask = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
valid_mask = 0;
|
||||
}
|
||||
|
||||
// helper function to get data from ANY batt management ic
|
||||
uint16_t BatteryManagement::get_cycles() {
|
||||
auto dev = i2cdev::I2CDevManager::get_dev_by_model(I2CDEVMDL_MAX17055);
|
||||
if (dev) {
|
||||
return ((i2cdev::I2cDev_MAX17055*)dev)->getValue("Cycles");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// helper function to get data from ANY batt management ic
|
||||
float BatteryManagement::get_tte() {
|
||||
auto dev = i2cdev::I2CDevManager::get_dev_by_model(I2CDEVMDL_MAX17055);
|
||||
if (dev) {
|
||||
return ((i2cdev::I2cDev_MAX17055*)dev)->getValue("TTE");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// helper function to get data from ANY batt management ic
|
||||
float BatteryManagement::get_ttf() {
|
||||
auto dev = i2cdev::I2CDevManager::get_dev_by_model(I2CDEVMDL_MAX17055);
|
||||
if (dev) {
|
||||
return ((i2cdev::I2cDev_MAX17055*)dev)->getValue("TTF");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace battery
|
||||
@@ -45,6 +45,11 @@ class BatteryManagement {
|
||||
static void set_calc_override(bool override);
|
||||
static uint8_t calc_percent_voltage(uint16_t); // calculates battery percentage from the voltage
|
||||
static bool calcOverride; // if set to true, it'll override the battery percent calculation based on current voltage.
|
||||
static void getBatteryInfo(uint8_t& valid_mask, uint8_t& percent, uint16_t& voltage, int32_t& current);
|
||||
static uint16_t get_cycles();
|
||||
static float get_tte();
|
||||
static float get_ttf();
|
||||
|
||||
private:
|
||||
};
|
||||
}; // namespace battery
|
||||
|
||||
@@ -190,4 +190,21 @@ class Adler32 {
|
||||
}
|
||||
};
|
||||
|
||||
static const unsigned char parity_numbits[256] = {
|
||||
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
|
||||
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
||||
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
|
||||
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
|
||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
|
||||
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8};
|
||||
|
||||
class ParityCheck {
|
||||
public:
|
||||
static bool parity_check(uint8_t ch, uint8_t pbitpos = 1) {
|
||||
return ((parity_numbits[ch] & pbitpos) != 0);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /*__CRC_H__*/
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
|
||||
#include "baseband_packet.hpp"
|
||||
|
||||
#include "acars_packet.hpp"
|
||||
#include "adsb_frame.hpp"
|
||||
#include "ert_packet.hpp"
|
||||
#include "pocsag_packet.hpp"
|
||||
@@ -379,13 +378,12 @@ class POCSAGStatsMessage : public Message {
|
||||
|
||||
class ACARSPacketMessage : public Message {
|
||||
public:
|
||||
constexpr ACARSPacketMessage(
|
||||
const baseband::Packet& packet)
|
||||
: Message{ID::ACARSPacket},
|
||||
packet{packet} {
|
||||
}
|
||||
|
||||
baseband::Packet packet;
|
||||
constexpr ACARSPacketMessage()
|
||||
: Message{ID::ACARSPacket} {}
|
||||
uint8_t msg_len = 0;
|
||||
char message[250] = {0}; // contains the whole packet
|
||||
uint8_t crc[2] = {0};
|
||||
uint8_t state = 0; // for debug
|
||||
};
|
||||
|
||||
class ADSBFrameMessage : public Message {
|
||||
|
||||
Reference in New Issue
Block a user