Implement bfebbx: Betaflight blackbox extractor
Cross-platform (macOS + Linux) C++17 CLI that extracts a Betaflight FC's blackbox log in one command: auto-detect the serial port, read craft_name over the Betaflight CLI, send `msc` to reboot into USB mass storage, wait for the volume to mount, copy btfl_all.bbl to <craft_name>_<YYYYMMDD>_<HHMMSS>.bbl, and eject. Native throughout (termios serial, getmntinfo/proc-mounts mount detection, DiskArbitration/umount eject); the only subprocess is the Linux udisksctl eject fallback. Includes CMake/ctest build, unit tests for the pure logic (naming, craft_name parsing, mount diff, serial via pty, CLI parsing), README with a manual hardware integration procedure, and design/plan docs. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
73
tests/test_cli.cpp
Normal file
73
tests/test_cli.cpp
Normal file
@@ -0,0 +1,73 @@
|
||||
#include "../src/cli.h"
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <unistd.h> // mkdtemp
|
||||
|
||||
int main() {
|
||||
using namespace bfebbx;
|
||||
|
||||
// parseArgs
|
||||
{
|
||||
const char* argv[] = {"bfebbx", "--port", "/dev/ttyACM0",
|
||||
"--output", "/tmp/out", "--craft-name", "Vroom",
|
||||
"--timeout", "45", "-v"};
|
||||
Options o = parseArgs(10, const_cast<char**>(argv));
|
||||
assert(o.port == "/dev/ttyACM0");
|
||||
assert(o.output == "/tmp/out");
|
||||
assert(o.craftName == "Vroom");
|
||||
assert(o.timeoutSec == 45);
|
||||
assert(o.verbose);
|
||||
}
|
||||
{
|
||||
const char* argv[] = {"bfebbx"};
|
||||
Options o = parseArgs(1, const_cast<char**>(argv));
|
||||
assert(o.output == ".");
|
||||
assert(o.timeoutSec == 30);
|
||||
assert(!o.verbose);
|
||||
}
|
||||
{
|
||||
const char* argv[] = {"bfebbx", "--bogus"};
|
||||
bool threw = false;
|
||||
try { parseArgs(2, const_cast<char**>(argv)); }
|
||||
catch (const std::exception&) { threw = true; }
|
||||
assert(threw);
|
||||
}
|
||||
{
|
||||
const char* argv[] = {"bfebbx", "--timeout", "45abc"};
|
||||
bool threw = false;
|
||||
try { parseArgs(3, const_cast<char**>(argv)); }
|
||||
catch (const std::exception&) { threw = true; }
|
||||
assert(threw);
|
||||
}
|
||||
{
|
||||
const char* argv[] = {"bfebbx", "--timeout", "-5"};
|
||||
bool threw = false;
|
||||
try { parseArgs(3, const_cast<char**>(argv)); }
|
||||
catch (const std::exception&) { threw = true; }
|
||||
assert(threw);
|
||||
}
|
||||
{
|
||||
const char* argv[] = {"bfebbx", "--timeout", "45"};
|
||||
Options o = parseArgs(3, const_cast<char**>(argv));
|
||||
assert(o.timeoutSec == 45);
|
||||
}
|
||||
|
||||
// scanPorts against a temp directory
|
||||
{
|
||||
char tmpl[] = "/tmp/bfebbxXXXXXX";
|
||||
char* dir = mkdtemp(tmpl);
|
||||
assert(dir != nullptr);
|
||||
std::string d = dir;
|
||||
for (const char* n : {"ttyACM0", "ttyACM1", "ttyS0", "random"}) {
|
||||
std::ofstream(d + "/" + n).put('x');
|
||||
}
|
||||
auto ports = scanPorts(d, "ttyACM");
|
||||
assert(ports.size() == 2);
|
||||
assert(ports[0] == d + "/ttyACM0");
|
||||
assert(ports[1] == d + "/ttyACM1");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user