Rename kamil_adc to rph_radar and fix its data path

This commit is contained in:
Ayzen
2026-10-06 18:15:18 +03:00
parent aef549ea76
commit a185e61495
94 changed files with 2851 additions and 9485 deletions
@@ -1,4 +1,3 @@
#include "capture_file_writer.h"
#include "channel_bundle_support.hpp"
#include "data_preprocessor.hpp"
#include "locator/tcp_server.hpp"
@@ -7,6 +6,8 @@
#include "runtime_wait.hpp"
#include "shm_ring.hpp"
#include "tty_protocol_writer.h"
#include "switch_sequencer.h"
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/socket.h>
@@ -307,40 +308,6 @@ void test_cosine_notch_taper() {
}
}
void test_csv_failures(const Workspace& workspace) {
const auto csv = workspace.path / "capture.csv";
const auto spool = workspace.path / "capture.capture_spool.bin";
CaptureFileWriter writer(csv.string(), (workspace.path / "capture.svg").string(), "", "");
writer.initialize_csv(2, false);
CapturePacket packet{.ch1 = {1, 2}, .ch2 = {3, 4}, .di1 = {}};
auto invalid_packet = packet;
invalid_packet.ch2.pop_back();
expect_error([&] { writer.append_csv_packet(invalid_packet); });
require(std::filesystem::file_size(spool) == 16, "invalid packet partially changed the spool");
writer.append_csv_packet(packet);
std::filesystem::remove(csv);
std::filesystem::create_symlink("/dev/full", csv);
expect_error([&] { writer.write({packet}, 1000, 10); });
require(std::filesystem::file_size(spool) > 16, "failed CSV write deleted the recovery spool");
std::filesystem::remove(csv);
writer.write({packet}, 1000, 10);
require(!std::filesystem::exists(spool), "successful CSV export retained the spool");
std::ifstream csv_input(csv);
const std::string csv_text((std::istreambuf_iterator<char>(csv_input)), {});
require(csv_text.find("1.000000000,3.000000000") != std::string::npos,
"CSV retry lost channel samples");
writer.initialize_csv(2, false);
std::ofstream(spool, std::ios::binary | std::ios::app).put('x');
expect_error([&] { writer.write({}, 1000, 10); });
require(std::filesystem::exists(spool), "truncated packet header deleted the spool");
writer.initialize_csv(2, false);
const std::array<std::uint64_t, 4> corrupt_packet{0, 2, 0xffffffffffffffffULL, 0};
std::ofstream(spool, std::ios::binary | std::ios::app).write(
reinterpret_cast<const char*>(corrupt_packet.data()), sizeof(corrupt_packet));
expect_error([&] { writer.write({}, 1000, 10); });
require(std::filesystem::exists(spool), "oversized packet count deleted the spool");
}
void test_asset_reload_preserves_data(const Workspace& workspace) {
const auto save = [&](const char* name, float sample) {
return save_bundle(workspace, name, {.traces = {
@@ -497,10 +464,77 @@ void test_locator_packet_errors() {
for (unsigned iteration = 0; iteration < 30; ++iteration) { server.start(); server.stop(); }
}
void test_tty_sweep_overflow(const Workspace& workspace) {
TtyProtocolWriter writer((workspace.path / "overflow_tty").string(), 32'096);
const int fd = ::open(writer.path().c_str(), O_RDONLY | O_NONBLOCK);
require(fd >= 0, "Cannot open test PTY");
std::vector<std::uint16_t> words(8'000, 42);
for (std::uint64_t id = 1; id <= 100; ++id) {
writer.enqueue_sweep(words, {id, id, id * 100, id * 100 + 50, 1, 2, false});
}
require(writer.stats().ring_overflows > 0, "test did not overflow the queue");
std::vector<std::uint8_t> received;
std::uint64_t last_id = 0;
const auto deadline = std::chrono::steady_clock::now() + std::chrono::seconds(2);
while (last_id < 100 && std::chrono::steady_clock::now() < deadline) {
std::array<std::uint8_t, 8192> chunk{};
const auto n = ::read(fd, chunk.data(), chunk.size());
if (n > 0) { received.insert(received.end(), chunk.begin(), chunk.begin() + n); }
while (received.size() >= 16'048) {
require(std::memcmp(received.data(), "RPH1", 4) == 0, "overflow truncated a sweep header");
const auto value = [&](std::size_t at, unsigned size) {
std::uint64_t result = 0;
for (unsigned i = 0; i < size; ++i) { result |= std::uint64_t{received[at + i]} << (8U * i); }
return result;
};
require(value(4, 4) == 16'000 && value(8, 8) > last_id, "lost framing or source order");
last_id = value(8, 8);
require(value(16, 8) == last_id && value(24, 8) == last_id * 100 &&
value(32, 8) == last_id * 100 + 50 && value(40, 2) == 1 && value(42, 2) == 2,
"sweep lost source identity, timing, or combo");
require(received[48] == 42 && received[16'047] == 0, "corrupt point payload");
received.erase(received.begin(), received.begin() + 16'048);
}
if (n <= 0) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); }
}
::close(fd);
require(last_id == 100 && received.empty(), "latest complete sweep did not arrive");
}
void test_switch_backlog() {
drivers::H7992MinimalDriverSettings settings{.mode = config::DriverMode::Mock};
rph::SwitchSequencer sequencer({.combos = {{0, 0}, {0, 1}}},
std::make_unique<drivers::H7992MinimalDriver>(settings),
std::make_unique<drivers::H7992MinimalDriver>(settings));
sequencer.open();
sequencer.session_started();
require(!sequencer.on_sweep_end(false), "duration limit requested a new session");
require(sequencer.current_combo().output_pos == 0 && sequencer.cycle_id() == 1,
"duration limit switched hardware before the physical sweep ended");
require(sequencer.on_sweep_end(), "GPIO change must request a new source session");
for (unsigned i = 0; i < 10; ++i) {
require(sequencer.current_dirty(), "queued pre-switch sweep incorrectly clean");
require(!sequencer.on_sweep_end(), "dirty backlog requested another session");
require(sequencer.current_combo().output_pos == 1 && sequencer.cycle_id() == 1,
"dirty backlog advanced the combo or cycle");
}
sequencer.session_started();
require(!sequencer.current_dirty(), "new source session must permit a complete sweep");
sequencer.on_sweep_end();
require(sequencer.current_combo().output_pos == 0 && sequencer.cycle_id() == 2,
"clean cycle did not advance");
rph::SwitchSequencer single({.combos = {{0, 0}}},
std::make_unique<drivers::H7992MinimalDriver>(settings),
std::make_unique<drivers::H7992MinimalDriver>(settings));
single.open(); single.session_started();
require(!single.on_sweep_end() && single.cycle_id() == 2 && !single.current_dirty(),
"unchanged combination restarted its source or stopped advancing cycles");
}
void test_unread_tty_shutdown(const Workspace& workspace) {
TtyProtocolWriter writer((workspace.path / "tty").string(), 160'000);
TtyProtocolWriter writer((workspace.path / "tty").string(), 160'048);
const std::vector<std::uint16_t> words(80'000, 42);
writer.enqueue_encoded_frames(words.data(), words.size() / 4U);
writer.enqueue_sweep(words, {1, 1, 100, 200});
std::this_thread::sleep_for(std::chrono::milliseconds(50));
const auto start = std::chrono::steady_clock::now();
writer.shutdown();
@@ -524,9 +558,10 @@ int main(int argc, char** argv) {
test_acquisition_identity();
test_interruptible_wait();
test_cosine_notch_taper();
test_csv_failures(workspace);
test_locator_packet_errors();
test_tty_sweep_overflow(workspace);
test_switch_backlog();
test_unread_tty_shutdown(workspace);
test_locator_packet_errors();
std::cout << "native regressions passed (10,000 decoder mutations; 20,000 concurrent ring frames)\n";
} catch (const std::exception& error) {
std::cerr << "native regression failed: " << error.what() << '\n';