mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2025-08-13 14:55:29 +00:00
Adding simple FSK Rx Processor. Can be used with New Apps. (#2716)
* Work to allow for unique beacon parsing functions. * Fixing pull. * Changes. * Formatting. * Fix Copyright * Update firmware/application/apps/ble_rx_app.cpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update firmware/baseband/proc_btlerx.cpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * PR suggestions. * Fix String. * FSK Rx Improvements. Works for my custom protocol. * Fix buffer size. * Refactor * Formatting. * Formatting. * Fixing compiling, and BLE Rx UI/Performance. * More improvements. * Fixing stuck state. * More stuck parsing fix. * Combining PR changes. * Improvements from previous PR. * Fix dbM calculation relative to device RSSI. * Formatting. --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: TJ <tj.baginski@cognosos.com>
This commit is contained in:
@@ -57,95 +57,6 @@ std::string pad_string_with_spaces(int snakes) {
|
||||
return paddedStr;
|
||||
}
|
||||
|
||||
struct GainEntry {
|
||||
uint8_t lna;
|
||||
uint8_t vga;
|
||||
uint8_t gain;
|
||||
};
|
||||
|
||||
// Only LNA with VGA 0-4 is tested to be accurate. Max zeroized gain tested to be 16dBm.
|
||||
// Beyond that it is hard to tell distance to transmitting device.
|
||||
// Test was conducted within a few inches of the device.
|
||||
// Device was transmitting at 0dBm.
|
||||
constexpr GainEntry gain_table[] =
|
||||
{
|
||||
{40, 0, 19},
|
||||
{32, 0, 18},
|
||||
{24, 0, 15},
|
||||
{16, 0, 8},
|
||||
{8, 0, 2},
|
||||
{0, 0, 0},
|
||||
{40, 2, 20},
|
||||
{32, 2, 22},
|
||||
{24, 2, 14},
|
||||
{16, 2, 8},
|
||||
{8, 2, 2},
|
||||
{0, 2, 0},
|
||||
{40, 4, 21},
|
||||
{32, 4, 22},
|
||||
{24, 4, 15},
|
||||
{16, 4, 10},
|
||||
{8, 4, 3},
|
||||
{0, 4, 0},
|
||||
{40, 6, 26},
|
||||
{32, 6, 22},
|
||||
{24, 6, 15},
|
||||
{16, 6, 10},
|
||||
{8, 6, 4},
|
||||
{0, 6, 0},
|
||||
{40, 8, 26},
|
||||
{32, 8, 26},
|
||||
{24, 8, 18},
|
||||
{16, 8, 12},
|
||||
{8, 8, 6},
|
||||
{0, 8, 1},
|
||||
{40, 10, 26},
|
||||
{32, 10, 26},
|
||||
{24, 10, 20},
|
||||
{16, 10, 15},
|
||||
{8, 10, 8},
|
||||
{0, 10, 3},
|
||||
{40, 12, 26},
|
||||
{32, 12, 26},
|
||||
{24, 12, 23},
|
||||
{16, 12, 17},
|
||||
{8, 12, 10},
|
||||
{0, 12, 4},
|
||||
{40, 14, 26},
|
||||
{32, 14, 26},
|
||||
{24, 14, 25},
|
||||
{16, 14, 19},
|
||||
{8, 14, 12},
|
||||
{0, 14, 6},
|
||||
{40, 16, 26},
|
||||
{32, 16, 26},
|
||||
{24, 16, 26},
|
||||
{16, 16, 20},
|
||||
{8, 16, 13},
|
||||
{0, 16, 7},
|
||||
{40, 18, 26},
|
||||
{32, 18, 26},
|
||||
{24, 18, 26},
|
||||
{16, 18, 21},
|
||||
{8, 18, 14},
|
||||
{0, 18, 8},
|
||||
{40, 20, 26},
|
||||
{32, 20, 26},
|
||||
{24, 20, 26},
|
||||
{16, 20, 23},
|
||||
{8, 20, 16},
|
||||
{0, 20, 10},
|
||||
};
|
||||
|
||||
uint8_t get_total_gain(uint8_t lna, uint8_t vga) {
|
||||
for (const auto& entry : gain_table) {
|
||||
if (entry.lna == lna && entry.vga == vga)
|
||||
return entry.gain;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t copy_mac_address_to_uint64(const uint8_t* macAddress) {
|
||||
uint64_t result = 0;
|
||||
|
||||
@@ -275,10 +186,10 @@ void RecentEntriesTable<BleRecentEntries>::draw(
|
||||
if (!entry.nameString.empty() && entry.include_name) {
|
||||
line = entry.nameString;
|
||||
|
||||
if (line.length() < 10) {
|
||||
line += pad_string_with_spaces(10 - line.length());
|
||||
if (line.length() < 17) {
|
||||
line += pad_string_with_spaces(17 - line.length());
|
||||
} else {
|
||||
line = truncate(line, 10);
|
||||
line = truncate(line, 17);
|
||||
}
|
||||
} else {
|
||||
line = to_string_mac_address(entry.packetData.macAddress, 6, false);
|
||||
@@ -289,12 +200,12 @@ void RecentEntriesTable<BleRecentEntries>::draw(
|
||||
if (!entry.informationString.empty()) {
|
||||
hitsStr = entry.informationString;
|
||||
} else {
|
||||
hitsStr = "Hits: " + to_string_dec_int(entry.numHits);
|
||||
hitsStr = to_string_dec_int(entry.numHits);
|
||||
}
|
||||
|
||||
// Pushing single digit values down right justified.
|
||||
int hitsDigits = hitsStr.length();
|
||||
uint8_t hits_spacing = 14 - hitsDigits;
|
||||
uint8_t hits_spacing = 8 - hitsDigits;
|
||||
|
||||
// Pushing single digit values down right justified.
|
||||
std::string dbStr = to_string_dec_int(entry.dbValue);
|
||||
@@ -879,17 +790,29 @@ void BLERxView::on_data(BlePacketData* packet) {
|
||||
// Start of Packet stuffing.
|
||||
// Masking off the top 2 bytes to avoid invalid keys.
|
||||
|
||||
BleRecentEntry tempEntry;
|
||||
uint64_t key = macAddressEncoded & 0xFFFFFFFFFFFF;
|
||||
bool packetExists = false;
|
||||
|
||||
if (updateEntry(packet, tempEntry, (ADV_PDU_TYPE)packet->type)) {
|
||||
auto& entry = ::on_packet(recent, macAddressEncoded & 0xFFFFFFFFFFFF);
|
||||
// If found store into tempEntry to modify.
|
||||
auto it = find(recent, key);
|
||||
if (it != recent.end()) {
|
||||
recent.push_front(*it);
|
||||
recent.erase(it);
|
||||
updateEntry(packet, recent.front(), (ADV_PDU_TYPE)packet->type);
|
||||
packetExists = true;
|
||||
} else {
|
||||
recent.emplace_front(key);
|
||||
truncate_entries(recent);
|
||||
|
||||
// Preserve exisisting data from entry.
|
||||
tempEntry.macAddress = macAddressEncoded;
|
||||
tempEntry.numHits = ++entry.numHits;
|
||||
packetExists = updateEntry(packet, recent.front(), (ADV_PDU_TYPE)packet->type);
|
||||
|
||||
entry = tempEntry;
|
||||
// If parsing failed, remove entry.
|
||||
if (!packetExists) {
|
||||
recent.erase(recent.begin());
|
||||
}
|
||||
}
|
||||
|
||||
if (packetExists) {
|
||||
handle_filter_options(options_filter.selected_index());
|
||||
handle_entries_sort(options_sort.selected_index());
|
||||
|
||||
@@ -899,7 +822,7 @@ void BLERxView::on_data(BlePacketData* packet) {
|
||||
while (it != searchList.end()) {
|
||||
std::string searchStr = (std::string)*it;
|
||||
|
||||
if (entry.dataString.find(searchStr) != std::string::npos) {
|
||||
if (recent.front().dataString.find(searchStr) != std::string::npos) {
|
||||
searchList.erase(it);
|
||||
found_count++;
|
||||
break;
|
||||
@@ -1000,13 +923,10 @@ void BLERxView::on_timer() {
|
||||
timer_count = 0;
|
||||
|
||||
if (auto_channel) {
|
||||
int min = 37;
|
||||
int max = 39;
|
||||
field_frequency.set_value(get_freq_by_channel_number(channel_number));
|
||||
baseband::set_btlerx(channel_number);
|
||||
|
||||
int randomChannel = min + std::rand() % (max - min + 1);
|
||||
|
||||
field_frequency.set_value(get_freq_by_channel_number(randomChannel));
|
||||
baseband::set_btlerx(randomChannel);
|
||||
channel_number = (channel_number < 39) ? channel_number + 1 : 37;
|
||||
}
|
||||
}
|
||||
if (ble_rx_error != BLE_RX_NO_ERROR) {
|
||||
@@ -1093,7 +1013,7 @@ bool BLERxView::updateEntry(const BlePacketData* packet, BleRecentEntry& entry,
|
||||
data_string += to_string_hex(packet->data[i], 2);
|
||||
}
|
||||
|
||||
entry.dbValue = 2 * (packet->max_dB - get_total_gain(receiver_model.lna(), receiver_model.vga()));
|
||||
entry.dbValue = packet->max_dB - (receiver_model.lna() + receiver_model.vga() + (receiver_model.rf_amp() ? 14 : 0));
|
||||
entry.timestamp = to_string_timestamp(rtc_time::now());
|
||||
entry.dataString = data_string;
|
||||
|
||||
@@ -1111,6 +1031,7 @@ bool BLERxView::updateEntry(const BlePacketData* packet, BleRecentEntry& entry,
|
||||
|
||||
entry.pduType = pdu_type;
|
||||
entry.channelNumber = channel_number;
|
||||
entry.numHits++;
|
||||
|
||||
if (entry.vendor_status == MAC_VENDOR_UNKNOWN) {
|
||||
std::string vendor_name;
|
||||
@@ -1125,8 +1046,7 @@ bool BLERxView::updateEntry(const BlePacketData* packet, BleRecentEntry& entry,
|
||||
entry.include_name = check_name.value();
|
||||
|
||||
// Only parse name for advertisment packets and empty name entries
|
||||
if (pdu_type == ADV_IND || pdu_type == ADV_NONCONN_IND) // || pdu_type == SCAN_RSP || pdu_type == ADV_SCAN_IND)
|
||||
{
|
||||
if (pdu_type == ADV_IND || pdu_type == ADV_NONCONN_IND || pdu_type == SCAN_RSP || pdu_type == ADV_SCAN_IND) {
|
||||
if (uniqueParsing) {
|
||||
// Add your unique beacon parsing function here.
|
||||
}
|
||||
@@ -1145,6 +1065,7 @@ bool BLERxView::updateEntry(const BlePacketData* packet, BleRecentEntry& entry,
|
||||
|
||||
bool BLERxView::parse_beacon_data(const uint8_t* data, uint8_t length, std::string& nameString, std::string& informationString) {
|
||||
uint8_t currentByte, currentLength, currentType = 0;
|
||||
std::string tempName = "";
|
||||
|
||||
for (currentByte = 0; currentByte < length;) {
|
||||
currentLength = data[currentByte++];
|
||||
@@ -1154,18 +1075,25 @@ bool BLERxView::parse_beacon_data(const uint8_t* data, uint8_t length, std::stri
|
||||
for (int i = 0; ((i < currentLength - 1) && (currentByte < length)); i++) {
|
||||
// parse the name of bluetooth device: 0x08->Shortened Local Name; 0x09->Complete Local Name
|
||||
if (currentType == 0x08 || currentType == 0x09) {
|
||||
nameString += (char)data[currentByte];
|
||||
tempName += (char)data[currentByte];
|
||||
}
|
||||
currentByte++;
|
||||
}
|
||||
}
|
||||
|
||||
if (nameString.empty()) {
|
||||
nameString = "None";
|
||||
if (!tempName.empty()) {
|
||||
nameString = tempName;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
informationString = "";
|
||||
|
||||
if (!informationString.empty()) {
|
||||
// Option to change title of Hits Column.
|
||||
// Setting to default for now.
|
||||
columns.set(1, "Hits", 7);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@@ -267,7 +267,7 @@ class BLERxView : public View {
|
||||
bool auto_channel = false;
|
||||
|
||||
int16_t timer_count{0};
|
||||
int16_t timer_period{6}; // 100ms
|
||||
int16_t timer_period{2}; // 25ms
|
||||
|
||||
std::string filterBuffer{};
|
||||
std::string listFileBuffer{};
|
||||
@@ -386,9 +386,9 @@ class BLERxView : public View {
|
||||
BleRecentEntries recent{};
|
||||
BleRecentEntries tempList{};
|
||||
|
||||
const RecentEntriesColumns columns{{
|
||||
{"Name", 10},
|
||||
{"Information", 13},
|
||||
RecentEntriesColumns columns{{
|
||||
{"Name", 17},
|
||||
{"Hits", 7},
|
||||
{"dBm", 4},
|
||||
}};
|
||||
|
||||
|
@@ -186,13 +186,14 @@ void set_nrf(const uint32_t baudrate, const uint32_t word_length, const uint32_t
|
||||
send_message(&message);
|
||||
}
|
||||
|
||||
void set_fsk(const size_t deviation) {
|
||||
void set_fsk(const uint8_t samplesPerSymbol, const uint32_t syncWord, const uint8_t syncWordLength, const uint32_t preamble, const uint8_t preambleLength, uint16_t numDataBytes) {
|
||||
const FSKRxConfigureMessage message{
|
||||
taps_200k_decim_0,
|
||||
taps_16k0_decim_1,
|
||||
taps_11k0_channel,
|
||||
2,
|
||||
deviation};
|
||||
samplesPerSymbol,
|
||||
syncWord,
|
||||
syncWordLength,
|
||||
preamble,
|
||||
preambleLength,
|
||||
numDataBytes};
|
||||
|
||||
send_message(&message);
|
||||
}
|
||||
|
@@ -80,7 +80,7 @@ void set_pitch_rssi(int32_t avg, bool enabled);
|
||||
void set_afsk_data(const uint32_t afsk_samples_per_bit, const uint32_t afsk_phase_inc_mark, const uint32_t afsk_phase_inc_space, const uint8_t afsk_repeat, const uint32_t afsk_bw, const uint8_t symbol_count);
|
||||
void kill_afsk();
|
||||
void set_afsk(const uint32_t baudrate, const uint32_t word_length, const uint32_t trigger_value, const bool trigger_word);
|
||||
void set_fsk(const size_t deviation);
|
||||
void set_fsk(const uint32_t samplesPerSymbol, const uint32_t syncWord, const uint8_t syncWordLength, const uint32_t preamble, const uint8_t preambleLength, uint16_t numDataBytes);
|
||||
void set_aprs(const uint32_t baudrate);
|
||||
|
||||
void set_btlerx(uint8_t channel_number);
|
||||
|
@@ -24,7 +24,7 @@
|
||||
namespace ui {
|
||||
|
||||
RecentEntriesColumns::RecentEntriesColumns(
|
||||
const std::initializer_list<RecentEntriesColumn> columns)
|
||||
std::initializer_list<RecentEntriesColumn> columns)
|
||||
: _columns{columns} {
|
||||
}
|
||||
|
||||
|
@@ -133,14 +133,27 @@ class RecentEntriesColumns {
|
||||
public:
|
||||
using ContainerType = std::vector<RecentEntriesColumn>;
|
||||
|
||||
RecentEntriesColumns(
|
||||
const std::initializer_list<RecentEntriesColumn> columns);
|
||||
RecentEntriesColumns(std::initializer_list<RecentEntriesColumn> columns);
|
||||
|
||||
ContainerType::const_iterator begin() const { return std::begin(_columns); }
|
||||
ContainerType::const_iterator end() const { return std::end(_columns); }
|
||||
ContainerType::iterator begin() { return _columns.begin(); }
|
||||
ContainerType::iterator end() { return _columns.end(); }
|
||||
ContainerType::const_iterator begin() const { return _columns.begin(); }
|
||||
ContainerType::const_iterator end() const { return _columns.end(); }
|
||||
|
||||
void set(size_t index, const std::string& name, size_t width) {
|
||||
if (index < _columns.size()) {
|
||||
_columns[index] = {name, width};
|
||||
}
|
||||
}
|
||||
|
||||
const RecentEntriesColumn& at(size_t index) const {
|
||||
return _columns.at(index);
|
||||
}
|
||||
|
||||
size_t size() const { return _columns.size(); }
|
||||
|
||||
private:
|
||||
const ContainerType _columns;
|
||||
ContainerType _columns;
|
||||
};
|
||||
|
||||
class RecentEntriesHeader : public Widget {
|
||||
|
Reference in New Issue
Block a user