mirror of
https://github.com/RfidResearchGroup/mayhem-firmware.git
synced 2026-05-12 11:27:21 -07:00
Merge branch 'next' into feature/disableTouch
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
raw_git = os.popen('git log next --since="24 hours" --pretty=format:"- %h - {USERNAME}*+%al-%an*: %s"').read()
|
||||
|
||||
|
||||
def compute_username(line):
|
||||
stripped = re.search(r'(?<=\*)(.*?)(?=\*)', line).group(0)
|
||||
|
||||
pattern = re.compile("[$@+&?].*[$@+&?]")
|
||||
if pattern.match(stripped):
|
||||
stripped = re.sub("[$@+&?].*[$@+&?]", "", stripped)
|
||||
stripped = re.match(r'.+?(?=-)', stripped).group(0)
|
||||
else:
|
||||
stripped = re.sub(r'^.*?-', "", stripped)
|
||||
return "@" + stripped
|
||||
|
||||
|
||||
def compile_line(line):
|
||||
username = compute_username(line)
|
||||
line = re.sub(r'[*].*[*]', "", line)
|
||||
line = line.replace("{USERNAME}", username)
|
||||
return line
|
||||
|
||||
|
||||
for row in raw_git.splitlines():
|
||||
print(compile_line(row))
|
||||
@@ -0,0 +1,99 @@
|
||||
name: Nightly Release
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 0 * * *"
|
||||
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
check_date:
|
||||
runs-on: ubuntu-latest
|
||||
name: Check latest commit
|
||||
outputs:
|
||||
should_run: ${{ steps.should_run.outputs.should_run }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: print latest_commit
|
||||
run: echo ${{ github.sha }}
|
||||
|
||||
- name: check latest commit is less than a day
|
||||
id: should_run
|
||||
continue-on-error: true
|
||||
run: test -z $(git rev-list --after="24 hours" ${{ github.sha }}) && echo "::set-output name=should_run::false"
|
||||
build:
|
||||
needs: check_date
|
||||
if: ${{ needs.check_date.outputs.should_run != 'false' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Get current date
|
||||
id: date
|
||||
run: echo "::set-output name=date::$(date +'%Y-%m-%d')"
|
||||
- name: Get version date
|
||||
id: version_date
|
||||
run: echo "::set-output name=date::n_$(date +'%y%m%d')"
|
||||
- name: Checkout
|
||||
uses: actions/checkout@master
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: next
|
||||
submodules: true
|
||||
- name: Git Sumbodule Update
|
||||
run: |
|
||||
git submodule update --init --recursive
|
||||
- name: Build the Docker image
|
||||
run: docker build -t portapack-dev -f dockerfile-nogit . --tag my-image-name:$(date +%s)
|
||||
- name: Make build folder
|
||||
run: mkdir ${{ github.workspace }}/build
|
||||
- name: Run the Docker image
|
||||
run: docker run -e VERSION_STRING=${{ steps.version_date.outputs.date }} -i -v ${{ github.workspace }}:/havoc portapack-dev
|
||||
- name: Create Firmware ZIP
|
||||
run: |
|
||||
zip -j firmware.zip build/firmware/portapack-h1_h2-mayhem.bin && cd flashing && zip -r ../firmware.zip *
|
||||
- name: Create SD Card ZIP
|
||||
run: |
|
||||
zip -r sdcard.zip sdcard
|
||||
- name: Create changelog
|
||||
run: |
|
||||
CHANGELOG=$(python3 .github/workflows/changelog.py)
|
||||
CHANGELOG="${CHANGELOG//'%'/'%25'}"
|
||||
CHANGELOG="${CHANGELOG//$'\n'/'%0A'}"
|
||||
CHANGELOG="${CHANGELOG//$'\r'/'%0D'}"
|
||||
echo "::set-output name=content::$CHANGELOG"
|
||||
id: changelog
|
||||
- name: Create Release
|
||||
id: create_release
|
||||
uses: actions/create-release@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: nightly-tag-${{ steps.date.outputs.date }}
|
||||
release_name: Nightly Release - ${{ steps.date.outputs.date }}
|
||||
body: |
|
||||
**Nightly release - ${{ steps.date.outputs.date }}**
|
||||
This build is the latest and greatest, although may not be the most stable as this is a nightly release.
|
||||
## Release notes
|
||||
### Revision (${{ steps.version_date.outputs.date }}):
|
||||
${{ steps.changelog.outputs.content }}
|
||||
draft: false
|
||||
prerelease: true
|
||||
- name: Upload Firmware Asset
|
||||
id: upload-firmware-asset
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: ./firmware.zip
|
||||
asset_name: mayhem_nightly_${{ steps.version_date.outputs.date }}_FIRMWARE.zip
|
||||
asset_content_type: application/zip
|
||||
- name: Upload SD Card Assets
|
||||
id: upload-sd-card-asset
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: ./sdcard.zip
|
||||
asset_name: mayhem_nightly_${{ steps.version_date.outputs.date }}_COPY_TO_SDCARD.zip
|
||||
asset_content_type: application/zip
|
||||
@@ -39,7 +39,6 @@
|
||||
*.lib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
/firmware/baseband/*.bin
|
||||
|
||||
+3
-3
@@ -25,8 +25,8 @@ set(CMAKE_TOOLCHAIN_FILE ${CMAKE_CURRENT_LIST_DIR}/firmware/toolchain-arm-cortex
|
||||
|
||||
project(portapack-h1)
|
||||
|
||||
#set(VERSION "")
|
||||
if (NOT DEFINED VERSION)
|
||||
set(VERSION "$ENV{VERSION_STRING}")
|
||||
if ("$ENV{VERSION_STRING}" STREQUAL "")
|
||||
execute_process(
|
||||
COMMAND git log -n 1 --format=%h
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
|
||||
@@ -38,7 +38,7 @@ if (NOT DEFINED VERSION)
|
||||
if (GIT_VERSION_FOUND)
|
||||
set(VERSION "unknown")
|
||||
else (GIT_VERSION_FOUND)
|
||||
set(VERSION "local-${GIT_VERSION}")
|
||||
set(VERSION "${GIT_VERSION}")
|
||||
endif (GIT_VERSION_FOUND)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -26,7 +26,9 @@ To support the people behind the hardware, please buy a genuine [HackRF](https:/
|
||||
|
||||
## Where is the latest firmware?
|
||||
|
||||
The current stable release is on the [](https://github.com/eried/portapack-mayhem/releases/latest) page. Follow the instructions you can find in the release description.
|
||||
The **latest (nightly) release** can be found [here](https://github.com/eried/portapack-mayhem/releases/).
|
||||
|
||||
The current **stable release** is on the [](https://github.com/eried/portapack-mayhem/releases/latest) page. Follow the instructions you can find in the release description.
|
||||
|
||||
## Is this the newest firmware for my PortaPack?
|
||||
Most probably: **YES**. *If you find new features somewhere else, please [suggest](https://github.com/eried/portapack-mayhem/issues/new/choose) them*.
|
||||
|
||||
@@ -159,6 +159,7 @@ set(CPPSRC
|
||||
capture_thread.cpp
|
||||
clock_manager.cpp
|
||||
core_control.cpp
|
||||
database.cpp
|
||||
de_bruijn.cpp
|
||||
#emu_cc1101.cpp
|
||||
rfm69.cpp
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "ais_app.hpp"
|
||||
|
||||
#include "string_format.hpp"
|
||||
#include "database.hpp"
|
||||
|
||||
#include "baseband_api.hpp"
|
||||
|
||||
@@ -62,6 +63,25 @@ static std::string mmsi(
|
||||
return to_string_dec_uint(mmsi, 9, '0'); // MMSI is always is always 9 characters pre-padded with zeros
|
||||
}
|
||||
|
||||
|
||||
static std::string mid(
|
||||
const ais::MMSI& mmsi
|
||||
) {
|
||||
std::database db;
|
||||
std::string mid_code = "";
|
||||
std::database::MidDBRecord mid_record = {};
|
||||
int return_code = 0;
|
||||
|
||||
// Try getting the country name from mids.db using MID code for given MMSI
|
||||
mid_code = to_string_dec_uint(mmsi, 9, ' ').substr(0, 3);
|
||||
return_code = db.retrieve_mid_record(&mid_record, mid_code);
|
||||
switch(return_code) {
|
||||
case DATABASE_RECORD_FOUND: return mid_record.country;
|
||||
case DATABASE_NOT_FOUND: return "No mids.db file";
|
||||
default: return "";
|
||||
}
|
||||
}
|
||||
|
||||
static std::string navigational_status(const unsigned int value) {
|
||||
switch(value) {
|
||||
case 0: return "under way w/engine";
|
||||
@@ -271,6 +291,7 @@ void AISRecentEntryDetailView::paint(Painter& painter) {
|
||||
auto field_rect = Rect { rect.left(), rect.top() + 16, rect.width(), 16 };
|
||||
|
||||
field_rect = draw_field(painter, field_rect, s, "MMSI", ais::format::mmsi(entry_.mmsi));
|
||||
field_rect = draw_field(painter, field_rect, s, "Ctry", ais::format::mid(entry_.mmsi));
|
||||
field_rect = draw_field(painter, field_rect, s, "Name", entry_.name);
|
||||
field_rect = draw_field(painter, field_rect, s, "Call", entry_.call_sign);
|
||||
field_rect = draw_field(painter, field_rect, s, "Dest", entry_.destination);
|
||||
@@ -307,8 +328,13 @@ AISAppView::AISAppView(NavigationView& nav) : nav_ { nav } {
|
||||
recent_entry_detail_view.hidden(true);
|
||||
|
||||
target_frequency_ = initial_target_frequency;
|
||||
|
||||
receiver_model.set_tuning_frequency(tuning_frequency());
|
||||
receiver_model.set_sampling_rate(sampling_rate);
|
||||
receiver_model.set_baseband_bandwidth(baseband_bandwidth);
|
||||
receiver_model.enable(); // Before using radio::enable(), but not updating Ant.DC-Bias.
|
||||
|
||||
radio::enable({
|
||||
/* radio::enable({ // this can be removed, previous version,no DC-bias control.
|
||||
tuning_frequency(),
|
||||
sampling_rate,
|
||||
baseband_bandwidth,
|
||||
@@ -316,8 +342,8 @@ AISAppView::AISAppView(NavigationView& nav) : nav_ { nav } {
|
||||
receiver_model.rf_amp(),
|
||||
static_cast<int8_t>(receiver_model.lna()),
|
||||
static_cast<int8_t>(receiver_model.vga()),
|
||||
});
|
||||
|
||||
}); */
|
||||
|
||||
options_channel.on_change = [this](size_t, OptionsField::value_t v) {
|
||||
this->on_frequency_changed(v);
|
||||
};
|
||||
@@ -337,7 +363,8 @@ AISAppView::AISAppView(NavigationView& nav) : nav_ { nav } {
|
||||
}
|
||||
|
||||
AISAppView::~AISAppView() {
|
||||
radio::disable();
|
||||
/* radio::disable(); */
|
||||
receiver_model.disable(); // to switch off all, including DC bias.
|
||||
|
||||
baseband::shutdown();
|
||||
}
|
||||
|
||||
@@ -131,11 +131,11 @@ private:
|
||||
AISRecentEntry entry_ { };
|
||||
|
||||
Button button_done {
|
||||
{ 125, 216, 96, 24 },
|
||||
{ 125, 224, 96, 24 },
|
||||
"Done"
|
||||
};
|
||||
Button button_see_map {
|
||||
{ 19, 216, 96, 24 },
|
||||
{ 19, 224, 96, 24 },
|
||||
"See on map"
|
||||
};
|
||||
GeoMapView* geomap_view { nullptr };
|
||||
@@ -169,6 +169,7 @@ private:
|
||||
static constexpr uint32_t initial_target_frequency = 162025000;
|
||||
static constexpr uint32_t sampling_rate = 2457600;
|
||||
static constexpr uint32_t baseband_bandwidth = 1750000;
|
||||
|
||||
NavigationView& nav_;
|
||||
|
||||
AISRecentEntries recent { };
|
||||
|
||||
@@ -129,6 +129,9 @@ AnalogAudioView::AnalogAudioView(
|
||||
&waterfall
|
||||
});
|
||||
|
||||
//Filename Datetime and Frequency
|
||||
record_view.set_filename_date_frequency(true);
|
||||
|
||||
field_frequency.set_value(receiver_model.tuning_frequency());
|
||||
field_frequency.set_step(receiver_model.frequency_step());
|
||||
field_frequency.on_change = [this](rf::Frequency f) {
|
||||
|
||||
@@ -28,11 +28,11 @@
|
||||
#include "ui_receiver.hpp"
|
||||
#include "ui_spectrum.hpp"
|
||||
#include "ui_record_view.hpp"
|
||||
|
||||
#include "ui_font_fixed_8x16.hpp"
|
||||
|
||||
#include "tone_key.hpp"
|
||||
|
||||
|
||||
namespace ui {
|
||||
|
||||
constexpr Style style_options_group {
|
||||
@@ -216,7 +216,10 @@ private:
|
||||
|
||||
RecordView record_view {
|
||||
{ 0 * 8, 2 * 16, 30 * 8, 1 * 16 },
|
||||
u"AUD_????", RecordView::FileType::WAV, 4096, 4
|
||||
u"AUD",
|
||||
RecordView::FileType::WAV,
|
||||
4096,
|
||||
4
|
||||
};
|
||||
|
||||
spectrum::WaterfallWidget waterfall { true };
|
||||
|
||||
@@ -75,8 +75,8 @@ CaptureAppView::CaptureAppView(NavigationView& nav) {
|
||||
option_bandwidth.on_change = [this](size_t, uint32_t base_rate) {
|
||||
sampling_rate = 8 * base_rate; // Decimation by 8 done on baseband side
|
||||
/* base_rate is used for FFT calculation and display LCD, and also in recording writing SD Card rate. */
|
||||
/* ex. sampling_rate values, 4Mhz, when recording 500 khz (BW) and fs 8 Mhz , when selected 1 Mhz BW ...*/
|
||||
/* ex. recording 500khz BW to .C16 file, base_rate clock 500khz x2(I,Q) x 2 bytes (int signed) =2MB/sec rate SD Card */
|
||||
/* ex. sampling_rate values, 4Mhz, when recording 500 kHz (BW) and fs 8 Mhz , when selected 1 Mhz BW ...*/
|
||||
/* ex. recording 500kHz BW to .C16 file, base_rate clock 500kHz x2(I,Q) x 2 bytes (int signed) =2MB/sec rate SD Card */
|
||||
|
||||
waterfall.on_hide();
|
||||
record_view.set_sampling_rate(sampling_rate);
|
||||
@@ -85,12 +85,12 @@ CaptureAppView::CaptureAppView(NavigationView& nav) {
|
||||
|
||||
switch(sampling_rate) { // we use the var fs (sampling_rate) , to set up BPF aprox < fs_max/2 by Nyquist theorem.
|
||||
|
||||
case 0 ... 2000000: // BW Captured range (0 <= 250Khz max ) fs = 8 x 250 Khz
|
||||
case 0 ... 2000000: // BW Captured range (0 <= 250kHz max ) fs = 8 x 250 kHz
|
||||
anti_alias_baseband_bandwidth_filter = 1750000; // Minimum BPF MAX2837 for all those lower BW options.
|
||||
break;
|
||||
|
||||
case 4000000 ... 6000000: // BW capture range (500k ... 750Khz max ) fs_max = 8 x 750Khz = 6Mhz
|
||||
// BW 500k ... 750khz , ex. 500khz (fs = 8*BW = 4Mhz) , BW 600Khz (fs = 4,8Mhz) , BW 750 Khz (fs = 6Mhz)
|
||||
case 4000000 ... 6000000: // BW capture range (500k ... 750kHz max ) fs_max = 8 x 750kHz = 6Mhz
|
||||
// BW 500k ... 750kHz , ex. 500kHz (fs = 8*BW = 4Mhz) , BW 600kHz (fs = 4,8Mhz) , BW 750 kHz (fs = 6Mhz)
|
||||
anti_alias_baseband_bandwidth_filter = 2500000; // in some IC MAX2837 appear 2250000 , but both works similar.
|
||||
break;
|
||||
|
||||
@@ -123,7 +123,7 @@ CaptureAppView::CaptureAppView(NavigationView& nav) {
|
||||
waterfall.on_show();
|
||||
};
|
||||
|
||||
option_bandwidth.set_selected_index(7); // 500k, Preselected starting default option 500khz
|
||||
option_bandwidth.set_selected_index(7); // 500k, Preselected starting default option 500kHz
|
||||
|
||||
receiver_model.set_modulation(ReceiverModel::Mode::Capture);
|
||||
receiver_model.enable();
|
||||
|
||||
@@ -140,13 +140,24 @@ void GpsSimAppView::start() {
|
||||
}
|
||||
);
|
||||
}
|
||||
field_rfgain.on_change = [this](int32_t v) {
|
||||
tx_gain = v;
|
||||
};
|
||||
field_rfgain.set_value(tx_gain);
|
||||
receiver_model.set_tx_gain(tx_gain);
|
||||
|
||||
|
||||
field_rfamp.on_change = [this](int32_t v) {
|
||||
rf_amp = (bool)v;
|
||||
};
|
||||
field_rfamp.set_value(rf_amp ? 14 : 0);
|
||||
|
||||
radio::enable({
|
||||
receiver_model.tuning_frequency(),
|
||||
sample_rate ,
|
||||
baseband_bandwidth,
|
||||
rf::Direction::Transmit,
|
||||
receiver_model.rf_amp(),
|
||||
rf_amp, // previous code line : "receiver_model.rf_amp()," was passing the same rf_amp of all Receiver Apps
|
||||
static_cast<int8_t>(receiver_model.lna()),
|
||||
static_cast<int8_t>(receiver_model.vga())
|
||||
});
|
||||
@@ -181,6 +192,9 @@ GpsSimAppView::GpsSimAppView(
|
||||
NavigationView& nav
|
||||
) : nav_ (nav)
|
||||
{
|
||||
tx_gain = 35;field_rfgain.set_value(tx_gain); // Initial default value (-12 dB's max 47dBs ).
|
||||
field_rfamp.set_value(rf_amp ? 14 : 0); // Initial default value True. (TX RF amp on , +14dB's)
|
||||
|
||||
baseband::run_image(portapack::spi_flash::image_tag_gps);
|
||||
|
||||
add_children({
|
||||
@@ -191,8 +205,8 @@ GpsSimAppView::GpsSimAppView(
|
||||
&text_duration,
|
||||
&progressbar,
|
||||
&field_frequency,
|
||||
&field_lna,
|
||||
&field_rf_amp,
|
||||
&field_rfgain,
|
||||
&field_rfamp, // let's not use common persistent rf_amp , local rfamp is enough
|
||||
&check_loop,
|
||||
&button_play,
|
||||
&waterfall,
|
||||
|
||||
@@ -52,6 +52,8 @@ private:
|
||||
static constexpr ui::Dim header_height = 3 * 16;
|
||||
|
||||
uint32_t sample_rate = 0;
|
||||
int32_t tx_gain { 47 };
|
||||
bool rf_amp { true }; // aux private var to store temporal, same as Replay App rf_amp user selection.
|
||||
static constexpr uint32_t baseband_bandwidth = 3000000; //filter bandwidth
|
||||
const size_t read_size { 16384 };
|
||||
const size_t buffer_count { 3 };
|
||||
@@ -76,7 +78,7 @@ private:
|
||||
bool ready_signal { false };
|
||||
|
||||
Labels labels {
|
||||
{ { 10 * 8, 2 * 16 }, "LNA: A:", Color::light_grey() }
|
||||
{ { 10 * 8, 2 * 16 }, "GAIN A:", Color::light_grey() }
|
||||
};
|
||||
|
||||
Button button_open {
|
||||
@@ -104,11 +106,19 @@ private:
|
||||
FrequencyField field_frequency {
|
||||
{ 0 * 8, 2 * 16 },
|
||||
};
|
||||
LNAGainField field_lna {
|
||||
{ 14 * 8, 2 * 16 }
|
||||
NumberField field_rfgain {
|
||||
{ 14 * 8, 2 * 16 },
|
||||
2,
|
||||
{ 0, 47 },
|
||||
1,
|
||||
' '
|
||||
};
|
||||
RFAmpField field_rf_amp {
|
||||
{ 19 * 8, 2 * 16 }
|
||||
NumberField field_rfamp { // previously we were using "RFAmpField field_rf_amp" but that is general Receiver amp setting.
|
||||
{ 19 * 8, 2 * 16 },
|
||||
2,
|
||||
{ 0, 14 }, // this time we will display GUI , 0 or 14 dBs same as Mic and Replay App
|
||||
14,
|
||||
' '
|
||||
};
|
||||
Checkbox check_loop {
|
||||
{ 21 * 8, 2 * 16 },
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc.
|
||||
* Copyright (C) 2016 Furrtek
|
||||
* Copyleft (ↄ) 2022 NotPike
|
||||
*
|
||||
* This file is part of PortaPack.
|
||||
*
|
||||
@@ -121,6 +122,7 @@ void ReplayAppView::start() {
|
||||
auto open_error = p->open(file_path);
|
||||
if( open_error.is_valid() ) {
|
||||
file_error();
|
||||
return; // Fixes TX bug if there's a file error
|
||||
} else {
|
||||
reader = std::move(p);
|
||||
}
|
||||
@@ -150,17 +152,19 @@ void ReplayAppView::start() {
|
||||
rf_amp = (bool)v;
|
||||
};
|
||||
field_rfamp.set_value(rf_amp ? 14 : 0);
|
||||
|
||||
//Enable Bias Tee if selected
|
||||
radio::set_antenna_bias(portapack::get_antenna_bias());
|
||||
|
||||
radio::enable({
|
||||
receiver_model.tuning_frequency(),
|
||||
sample_rate * 8 ,
|
||||
sample_rate * 8,
|
||||
baseband_bandwidth,
|
||||
rf::Direction::Transmit,
|
||||
rf_amp, // previous code line : "receiver_model.rf_amp()," was passing the same rf_amp of all Receiver Apps
|
||||
static_cast<int8_t>(receiver_model.lna()),
|
||||
static_cast<int8_t>(receiver_model.vga())
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
void ReplayAppView::stop(const bool do_loop) {
|
||||
@@ -170,6 +174,7 @@ void ReplayAppView::stop(const bool do_loop) {
|
||||
if (do_loop && check_loop.value()) {
|
||||
start();
|
||||
} else {
|
||||
radio::set_antenna_bias(false); //Turn off Bias Tee
|
||||
radio::disable();
|
||||
button_play.set_bitmap(&bitmap_play);
|
||||
}
|
||||
|
||||
@@ -34,6 +34,8 @@ namespace tpms {
|
||||
|
||||
namespace format {
|
||||
|
||||
static bool use_kpa = true;
|
||||
|
||||
std::string type(Reading::Type type) {
|
||||
return to_string_dec_uint(toUType(type), 2);
|
||||
}
|
||||
@@ -43,7 +45,11 @@ std::string id(TransponderID id) {
|
||||
}
|
||||
|
||||
std::string pressure(Pressure pressure) {
|
||||
return to_string_dec_int(pressure.kilopascal(), 3);
|
||||
if(use_kpa){
|
||||
return to_string_dec_int(pressure.kilopascal(), 3);
|
||||
}
|
||||
return to_string_dec_int(pressure.psi(), 3);
|
||||
|
||||
}
|
||||
|
||||
std::string temperature(Temperature temperature) {
|
||||
@@ -142,7 +148,7 @@ TPMSAppView::TPMSAppView(NavigationView&) {
|
||||
&field_rf_amp,
|
||||
&field_lna,
|
||||
&field_vga,
|
||||
&recent_entries_view,
|
||||
&options_type,
|
||||
});
|
||||
|
||||
radio::enable({
|
||||
@@ -160,6 +166,17 @@ TPMSAppView::TPMSAppView(NavigationView&) {
|
||||
};
|
||||
options_band.set_by_value(target_frequency());
|
||||
|
||||
options_type.on_change = [this](size_t, int32_t i) {
|
||||
if (i == 0){
|
||||
tpms::format::use_kpa = true;
|
||||
} else if (i == 1){
|
||||
tpms::format::use_kpa = false;
|
||||
}
|
||||
update_type();
|
||||
};
|
||||
|
||||
options_type.set_selected_index(0, true);
|
||||
|
||||
logger = std::make_unique<TPMSLogger>();
|
||||
if( logger ) {
|
||||
logger->append(u"tpms.txt");
|
||||
@@ -176,9 +193,24 @@ void TPMSAppView::focus() {
|
||||
options_band.focus();
|
||||
}
|
||||
|
||||
void TPMSAppView::update_type() {
|
||||
if (tpms::format::use_kpa){
|
||||
remove_child(&recent_entries_view_psi);
|
||||
add_child(&recent_entries_view_kpa);
|
||||
recent_entries_view_kpa.set_parent_rect(view_normal_rect);
|
||||
} else {
|
||||
remove_child(&recent_entries_view_kpa);
|
||||
add_child(&recent_entries_view_psi);
|
||||
recent_entries_view_psi.set_parent_rect(view_normal_rect);
|
||||
}
|
||||
}
|
||||
|
||||
void TPMSAppView::set_parent_rect(const Rect new_parent_rect) {
|
||||
View::set_parent_rect(new_parent_rect);
|
||||
recent_entries_view.set_parent_rect({ 0, header_height, new_parent_rect.width(), new_parent_rect.height() - header_height });
|
||||
|
||||
view_normal_rect = { 0, header_height, new_parent_rect.width(), new_parent_rect.height() - header_height };
|
||||
|
||||
update_type();
|
||||
}
|
||||
|
||||
void TPMSAppView::on_packet(const tpms::Packet& packet) {
|
||||
@@ -191,13 +223,23 @@ void TPMSAppView::on_packet(const tpms::Packet& packet) {
|
||||
const auto reading = reading_opt.value();
|
||||
auto& entry = ::on_packet(recent, TPMSRecentEntry::Key { reading.type(), reading.id() });
|
||||
entry.update(reading);
|
||||
recent_entries_view.set_dirty();
|
||||
|
||||
if(tpms::format::use_kpa){
|
||||
recent_entries_view_kpa.set_dirty();
|
||||
} else {
|
||||
recent_entries_view_psi.set_dirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TPMSAppView::on_show_list() {
|
||||
recent_entries_view.hidden(false);
|
||||
recent_entries_view.focus();
|
||||
if(tpms::format::use_kpa){
|
||||
recent_entries_view_kpa.hidden(false);
|
||||
recent_entries_view_kpa.focus();
|
||||
} else {
|
||||
recent_entries_view_psi.hidden(false);
|
||||
recent_entries_view_psi.focus();
|
||||
}
|
||||
}
|
||||
|
||||
void TPMSAppView::on_band_changed(const uint32_t new_band_frequency) {
|
||||
|
||||
@@ -121,6 +121,8 @@ private:
|
||||
|
||||
static constexpr ui::Dim header_height = 1 * 16;
|
||||
|
||||
ui::Rect view_normal_rect { };
|
||||
|
||||
RSSI rssi {
|
||||
{ 21 * 8, 0, 6 * 8, 4 },
|
||||
};
|
||||
@@ -134,7 +136,16 @@ private:
|
||||
3,
|
||||
{
|
||||
{ "315", 315000000 },
|
||||
{ "434", 433920000 },
|
||||
{ "433", 433920000 },
|
||||
}
|
||||
};
|
||||
|
||||
OptionsField options_type {
|
||||
{ 5 * 8, 0 * 16 },
|
||||
3,
|
||||
{
|
||||
{ "kPa", 0 },
|
||||
{ "PSI", 1 }
|
||||
}
|
||||
};
|
||||
|
||||
@@ -153,7 +164,7 @@ private:
|
||||
TPMSRecentEntries recent { };
|
||||
std::unique_ptr<TPMSLogger> logger { };
|
||||
|
||||
const RecentEntriesColumns columns { {
|
||||
const RecentEntriesColumns columns_kpa { {
|
||||
{ "Tp", 2 },
|
||||
{ "ID", 8 },
|
||||
{ "kPa", 3 },
|
||||
@@ -161,12 +172,23 @@ private:
|
||||
{ "Cnt", 3 },
|
||||
{ "Fl", 2 },
|
||||
} };
|
||||
TPMSRecentEntriesView recent_entries_view { columns, recent };
|
||||
TPMSRecentEntriesView recent_entries_view_kpa { columns_kpa, recent };
|
||||
|
||||
const RecentEntriesColumns columns_psi { {
|
||||
{ "Tp", 2 },
|
||||
{ "ID", 8 },
|
||||
{ "PSI", 3 },
|
||||
{ "C", 3 },
|
||||
{ "Cnt", 3 },
|
||||
{ "Fl", 2 },
|
||||
} };
|
||||
TPMSRecentEntriesView recent_entries_view_psi { columns_psi, recent };
|
||||
|
||||
uint32_t target_frequency_ = initial_target_frequency;
|
||||
|
||||
void on_packet(const tpms::Packet& packet);
|
||||
void on_show_list();
|
||||
void update_type();
|
||||
|
||||
void on_band_changed(const uint32_t new_band_frequency);
|
||||
|
||||
|
||||
@@ -37,7 +37,8 @@ namespace ui
|
||||
console.writeln("vXxOinvizioNxX,teixeluis");
|
||||
console.writeln("Brumi-2021,texasyojimbo");
|
||||
console.writeln("heurist1,intoxsick,ckuethe");
|
||||
console.writeln("notpike");
|
||||
console.writeln("notpike,jLynx,zigad");
|
||||
console.writeln("MichalLeonBorsuk");
|
||||
console.writeln("");
|
||||
break;
|
||||
|
||||
|
||||
@@ -107,11 +107,7 @@ ADSBRxAircraftDetailsView::ADSBRxAircraftDetailsView(
|
||||
const std::function<void(void)> on_close
|
||||
) : entry_copy(entry),
|
||||
on_close_(on_close)
|
||||
{
|
||||
char file_buffer[32] { 0 };
|
||||
bool found = false;
|
||||
size_t number_of_icao_codes = 0;
|
||||
std::string icao_code;
|
||||
{
|
||||
|
||||
add_children({
|
||||
&labels,
|
||||
@@ -130,46 +126,22 @@ ADSBRxAircraftDetailsView::ADSBRxAircraftDetailsView(
|
||||
std::unique_ptr<ADSBLogger> logger { };
|
||||
//update(entry_copy);
|
||||
|
||||
|
||||
icao_code = to_string_hex(entry_copy.ICAO_address, 6);
|
||||
text_icao_address.set(to_string_hex(entry_copy.ICAO_address, 6));
|
||||
|
||||
|
||||
// Try getting the aircraft information from icao24.db
|
||||
auto result = db_file.open("ADSB/icao24.db");
|
||||
if (!result.is_valid()) {
|
||||
// determine number of ICAO24 codes in file, total size / (single index + record size)
|
||||
number_of_icao_codes = (db_file.size() / 153);
|
||||
icao_code = to_string_hex(entry_copy.ICAO_address, 6);
|
||||
|
||||
// binary search
|
||||
int first = 0, // First search element
|
||||
last = number_of_icao_codes - 1, // Last search element
|
||||
middle, // Mid point of search
|
||||
position = -1; // Position of search value
|
||||
while (!found && first <= last) {
|
||||
middle = (first + last) / 2; // Calculate mid point
|
||||
db_file.seek(middle * 7);
|
||||
db_file.read(file_buffer, 6);
|
||||
if (file_buffer == icao_code) { // If value is found at mid
|
||||
found = true;
|
||||
position = middle;
|
||||
}
|
||||
else if (file_buffer > icao_code) // If value is in lower half
|
||||
last = middle - 1;
|
||||
else
|
||||
first = middle + 1; // If value is in upper half
|
||||
}
|
||||
|
||||
if (position > -1) {
|
||||
db_file.seek((number_of_icao_codes * 7) + (position * 146)); // seek starting after index
|
||||
db_file.read(file_buffer, 9);
|
||||
text_registration.set(file_buffer);
|
||||
db_file.read(file_buffer, 33);
|
||||
text_manufacturer.set(file_buffer);
|
||||
db_file.read(file_buffer, 33);
|
||||
text_model.set(file_buffer);
|
||||
db_file.read(file_buffer, 5); // ICAO type decripton
|
||||
if(strlen(file_buffer) == 3) {
|
||||
switch(file_buffer[0]) {
|
||||
return_code = db.retrieve_aircraft_record(&aircraft_record, icao_code);
|
||||
switch(return_code) {
|
||||
case DATABASE_RECORD_FOUND:
|
||||
text_registration.set(aircraft_record.aircraft_registration);
|
||||
text_manufacturer.set(aircraft_record.aircraft_manufacturer);
|
||||
text_model.set(aircraft_record.aircraft_model);
|
||||
text_owner.set(aircraft_record.aircraft_owner);
|
||||
text_operator.set(aircraft_record.aircraft_operator);
|
||||
// Check for ICAO type, e.g. L2J
|
||||
if(strlen(aircraft_record.icao_type) == 3) {
|
||||
switch(aircraft_record.icao_type[0]) {
|
||||
case 'L':
|
||||
text_type.set("Landplane");
|
||||
break;
|
||||
@@ -189,8 +161,8 @@ ADSBRxAircraftDetailsView::ADSBRxAircraftDetailsView(
|
||||
text_type.set("Tilt-wing aircraft");
|
||||
break;
|
||||
}
|
||||
text_number_of_engines.set(std::string(1, file_buffer[1]));
|
||||
switch(file_buffer[2]) {
|
||||
text_number_of_engines.set(std::string(1, aircraft_record.icao_type[1]));
|
||||
switch(aircraft_record.icao_type[2]) {
|
||||
case 'P':
|
||||
text_engine_type.set("Piston engine");
|
||||
break;
|
||||
@@ -206,30 +178,22 @@ ADSBRxAircraftDetailsView::ADSBRxAircraftDetailsView(
|
||||
}
|
||||
|
||||
}
|
||||
// check for ICAO type designator
|
||||
else if(strlen(file_buffer) == 4) {
|
||||
if(strcmp(file_buffer,"SHIP") == 0) text_type.set("Airship");
|
||||
else if(strcmp(file_buffer,"BALL") == 0) text_type.set("Balloon");
|
||||
else if(strcmp(file_buffer,"GLID") == 0) text_type.set("Glider / sailplane");
|
||||
else if(strcmp(file_buffer,"ULAC") == 0) text_type.set("Micro/ultralight aircraft");
|
||||
else if(strcmp(file_buffer,"GYRO") == 0) text_type.set("Micro/ultralight autogyro");
|
||||
else if(strcmp(file_buffer,"UHEL") == 0) text_type.set("Micro/ultralight helicopter");
|
||||
else if(strcmp(file_buffer,"SHIP") == 0) text_type.set("Airship");
|
||||
else if(strcmp(file_buffer,"PARA") == 0) text_type.set("Powered parachute/paraplane");
|
||||
}
|
||||
db_file.read(file_buffer, 33);
|
||||
text_owner.set(file_buffer);
|
||||
db_file.read(file_buffer, 33);
|
||||
text_operator.set(file_buffer);
|
||||
} else {
|
||||
text_registration.set("Unknown");
|
||||
text_manufacturer.set("Unknown");
|
||||
}
|
||||
} else {
|
||||
text_manufacturer.set("No icao24.db file");
|
||||
// Check for ICAO type designator
|
||||
else if(strlen(aircraft_record.icao_type) == 4) {
|
||||
if(strcmp(aircraft_record.icao_type,"SHIP") == 0) text_type.set("Airship");
|
||||
else if(strcmp(aircraft_record.icao_type,"BALL") == 0) text_type.set("Balloon");
|
||||
else if(strcmp(aircraft_record.icao_type,"GLID") == 0) text_type.set("Glider / sailplane");
|
||||
else if(strcmp(aircraft_record.icao_type,"ULAC") == 0) text_type.set("Micro/ultralight aircraft");
|
||||
else if(strcmp(aircraft_record.icao_type,"GYRO") == 0) text_type.set("Micro/ultralight autogyro");
|
||||
else if(strcmp(aircraft_record.icao_type,"UHEL") == 0) text_type.set("Micro/ultralight helicopter");
|
||||
else if(strcmp(aircraft_record.icao_type,"SHIP") == 0) text_type.set("Airship");
|
||||
else if(strcmp(aircraft_record.icao_type,"PARA") == 0) text_type.set("Powered parachute/paraplane");
|
||||
}
|
||||
break;
|
||||
case DATABASE_NOT_FOUND:
|
||||
text_manufacturer.set("No icao24.db file");
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
button_close.on_select = [&nav](Button&){
|
||||
nav.pop();
|
||||
};
|
||||
@@ -275,11 +239,7 @@ ADSBRxDetailsView::ADSBRxDetailsView(
|
||||
) : entry_copy(entry),
|
||||
on_close_(on_close)
|
||||
{
|
||||
char file_buffer[32] { 0 };
|
||||
bool found = false;
|
||||
size_t number_of_airlines = 0;
|
||||
std::string airline_code;
|
||||
|
||||
|
||||
add_children({
|
||||
&labels,
|
||||
&text_icao_address,
|
||||
@@ -300,46 +260,19 @@ ADSBRxDetailsView::ADSBRxDetailsView(
|
||||
|
||||
// The following won't (shouldn't !) change for a given airborne aircraft
|
||||
// Try getting the airline's name from airlines.db
|
||||
auto result = db_file.open("ADSB/airlines.db");
|
||||
if (!result.is_valid()) {
|
||||
// Search for 3-letter code
|
||||
number_of_airlines = (db_file.size() / 68); // determine number of airlines in file
|
||||
airline_code = entry_copy.callsign.substr(0, 3);
|
||||
|
||||
// binary search
|
||||
int first = 0, // First search element
|
||||
last = number_of_airlines - 1, // Last search element
|
||||
middle, // Mid point of search
|
||||
position = -1; // Position of search value
|
||||
while (!found && first <= last) {
|
||||
middle = (first + last) / 2; // Calculate mid point
|
||||
db_file.seek(middle * 4);
|
||||
db_file.read(file_buffer, 3);
|
||||
if (file_buffer == airline_code) { // If value is found at mid
|
||||
found = true;
|
||||
position = middle;
|
||||
}
|
||||
else if (file_buffer > airline_code) // If value is in lower half
|
||||
last = middle - 1;
|
||||
else
|
||||
first = middle + 1; // If value is in upper half
|
||||
}
|
||||
|
||||
if (position > -1) {
|
||||
db_file.seek((number_of_airlines * 4) + (position << 6)); // seek starting after index
|
||||
db_file.read(file_buffer, 32);
|
||||
text_airline.set(file_buffer);
|
||||
db_file.read(file_buffer, 32);
|
||||
text_country.set(file_buffer);
|
||||
} else {
|
||||
text_airline.set("Unknown");
|
||||
text_country.set("Unknown");
|
||||
}
|
||||
} else {
|
||||
text_airline.set("No airlines.db file");
|
||||
text_country.set("No airlines.db file");
|
||||
airline_code = entry_copy.callsign.substr(0, 3);
|
||||
return_code = db.retrieve_airline_record(&airline_record, airline_code);
|
||||
switch(return_code) {
|
||||
case DATABASE_RECORD_FOUND:
|
||||
text_airline.set(airline_record.airline);
|
||||
text_country.set(airline_record.country);
|
||||
break;
|
||||
case DATABASE_NOT_FOUND:
|
||||
text_airline.set("No airlines.db file");
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
|
||||
text_callsign.set(entry_copy.callsign);
|
||||
text_icao_address.set(to_string_hex(entry_copy.ICAO_address, 6));
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "ui_font_fixed_8x16.hpp"
|
||||
|
||||
#include "file.hpp"
|
||||
#include "database.hpp"
|
||||
#include "recent_entries.hpp"
|
||||
#include "log_file.hpp"
|
||||
#include "adsb.hpp"
|
||||
@@ -176,13 +177,17 @@ public:
|
||||
std::string title() const override { return "AC Details"; };
|
||||
|
||||
AircraftRecentEntry get_current_entry() { return entry_copy; }
|
||||
|
||||
std::database::AircraftDBRecord aircraft_record = {};
|
||||
|
||||
private:
|
||||
AircraftRecentEntry entry_copy { 0 };
|
||||
std::function<void(void)> on_close_ { };
|
||||
bool send_updates { false };
|
||||
File db_file { };
|
||||
|
||||
AircraftRecentEntry entry_copy { 0 };
|
||||
std::function<void(void)> on_close_ { };
|
||||
bool send_updates { false };
|
||||
std::database db;
|
||||
std::string icao_code = "";
|
||||
int return_code = 0;
|
||||
|
||||
Labels labels {
|
||||
{ { 0 * 8, 1 * 16 }, "ICAO:", Color::light_grey() },
|
||||
{ { 0 * 8, 2 * 16 }, "Registration:", Color::light_grey() },
|
||||
@@ -264,14 +269,19 @@ public:
|
||||
std::string title() const override { return "Details"; };
|
||||
|
||||
AircraftRecentEntry get_current_entry() { return entry_copy; }
|
||||
|
||||
|
||||
std::database::AirlinesDBRecord airline_record = {};
|
||||
|
||||
private:
|
||||
AircraftRecentEntry entry_copy { 0 };
|
||||
std::function<void(void)> on_close_ { };
|
||||
GeoMapView* geomap_view { nullptr };
|
||||
ADSBRxAircraftDetailsView* aircraft_details_view { nullptr };
|
||||
bool send_updates { false };
|
||||
File db_file { };
|
||||
AircraftRecentEntry entry_copy { 0 };
|
||||
std::function<void(void)> on_close_ { };
|
||||
GeoMapView* geomap_view { nullptr };
|
||||
ADSBRxAircraftDetailsView* aircraft_details_view { nullptr };
|
||||
bool send_updates { false };
|
||||
std::database db;
|
||||
std::string airline_code = "";
|
||||
int return_code = 0;
|
||||
|
||||
Labels labels {
|
||||
{ { 0 * 8, 1 * 16 }, "ICAO:", Color::light_grey() },
|
||||
|
||||
@@ -108,12 +108,12 @@ APRSRxView::APRSRxView(NavigationView& nav, Rect parent_rect) : View(parent_rect
|
||||
options_region.on_change = [this](size_t, int32_t i) {
|
||||
if (i == 0){
|
||||
field_frequency.set_value(144390000);
|
||||
}
|
||||
if(i == 1){
|
||||
} else if(i == 1){
|
||||
field_frequency.set_value(144800000);
|
||||
}
|
||||
if(i == 2){
|
||||
} else if(i == 2){
|
||||
field_frequency.set_value(145175000);
|
||||
} else if(i == 3){
|
||||
field_frequency.set_value(144575000);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user