Public Access
`r` in the GNSS App (or `gnss track start|stop`) records a Track to /gnss/tracks/YYYYMMDD-HHMMSS.gpx: a point every 5 s once moved 5 m (lib/gnss/track, 7 tests: haversine, the rule, GPX text, the file name). It keeps recording with the App closed, shows REC in the Status Bar, and announces start and stop with a Toast. It needs a card and the time; switching GNSS off stops it. Tracks are written like Captures: past 90 % card usage, until full. Storage Clean-up gets a GNSS tracks category. A Track cut short by a reset or power loss has no GPX footer; the GNSS Service closes such files at the next boot. Verified on the device: a recorded Track and one interrupted by a reset both parse as GPX 1.1 on the PC. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EhqxQ49eCju4CzKYNjZzwT
79 lines
3.1 KiB
C++
79 lines
3.1 KiB
C++
#include <unity.h>
|
|
|
|
#include <string>
|
|
|
|
#include "track.h"
|
|
|
|
using namespace roro::gnss;
|
|
|
|
void setUp() {}
|
|
void tearDown() {}
|
|
|
|
void test_distance_is_haversine() {
|
|
// One minute of latitude is one nautical mile.
|
|
TEST_ASSERT_FLOAT_WITHIN(2.0, 1852.0, distanceMeters(50.0, 4.0, 50.0 + 1.0 / 60, 4.0));
|
|
TEST_ASSERT_FLOAT_WITHIN(0.01, 0.0, distanceMeters(50.0, 4.0, 50.0, 4.0));
|
|
// A degree of longitude shrinks with latitude: cos(60°) = 0.5.
|
|
TEST_ASSERT_FLOAT_WITHIN(60.0, 55597.0, distanceMeters(60.0, 0.0, 60.0, 1.0));
|
|
}
|
|
|
|
void test_first_point_is_always_recorded() {
|
|
TrackRule rule;
|
|
TEST_ASSERT_TRUE(rule.due(1000, 50.0, 4.0));
|
|
}
|
|
|
|
void test_a_point_needs_5_seconds_and_5_metres() {
|
|
TrackRule rule;
|
|
rule.due(0, 50.0, 4.0);
|
|
double tenMetres = 10.0 / 111195.0; // degrees of latitude
|
|
TEST_ASSERT_FALSE(rule.due(4999, 50.0 + tenMetres, 4.0)); // too soon
|
|
TEST_ASSERT_FALSE(rule.due(5000, 50.0 + 1e-6, 4.0)); // too close (standing still)
|
|
TEST_ASSERT_TRUE(rule.due(5000, 50.0 + tenMetres, 4.0));
|
|
TEST_ASSERT_FALSE(rule.due(6000, 50.0 + 3 * tenMetres, 4.0)); // 5 s from the last point
|
|
TEST_ASSERT_TRUE(rule.due(10000, 50.0 + 3 * tenMetres, 4.0));
|
|
}
|
|
|
|
void test_reset_starts_over() {
|
|
TrackRule rule;
|
|
rule.due(0, 50.0, 4.0);
|
|
rule.reset();
|
|
TEST_ASSERT_TRUE(rule.due(100, 50.0, 4.0));
|
|
}
|
|
|
|
void test_file_name_from_utc() {
|
|
TEST_ASSERT_EQUAL_STRING("/gnss/tracks/20261004-203447.gpx", trackPath(1791146087LL).c_str()); // 20:34:47 UTC
|
|
}
|
|
|
|
void test_gpx_header_point_and_footer() {
|
|
std::string h = gpx::header("20261004-203447");
|
|
TEST_ASSERT_TRUE(h.find("<?xml version=\"1.0\" encoding=\"UTF-8\"?>") == 0);
|
|
TEST_ASSERT_TRUE(h.find("<gpx version=\"1.1\" creator=\"roro9stack\"") != std::string::npos);
|
|
TEST_ASSERT_TRUE(h.find("<name>20261004-203447</name>") != std::string::npos);
|
|
TEST_ASSERT_TRUE(h.find("<trkseg>") != std::string::npos);
|
|
TEST_ASSERT_EQUAL_STRING(
|
|
"<trkpt lat=\"50.8692030\" lon=\"-4.2535070\"><ele>42.5</ele><time>2026-10-04T20:34:47Z</time></trkpt>",
|
|
gpx::point(50.869203, -4.253507, true, 42.5f, 1791146087LL).c_str());
|
|
TEST_ASSERT_EQUAL_STRING("<trkpt lat=\"50.8692030\" lon=\"4.2535070\"><time>2026-10-04T20:34:47Z</time></trkpt>",
|
|
gpx::point(50.869203, 4.253507, false, 0, 1791146087LL).c_str());
|
|
TEST_ASSERT_EQUAL_STRING("</trkseg></trk></gpx>", gpx::footer().c_str());
|
|
}
|
|
|
|
void test_an_unfinished_file_is_recognised() {
|
|
TEST_ASSERT_TRUE(gpx::finished("...<time>x</time></trkpt>\n</trkseg></trk></gpx>\n"));
|
|
TEST_ASSERT_TRUE(gpx::finished("</trkseg></trk></gpx>"));
|
|
TEST_ASSERT_FALSE(gpx::finished("...<time>x</time></trkpt>\n"));
|
|
TEST_ASSERT_FALSE(gpx::finished(""));
|
|
}
|
|
|
|
int main() {
|
|
UNITY_BEGIN();
|
|
RUN_TEST(test_distance_is_haversine);
|
|
RUN_TEST(test_first_point_is_always_recorded);
|
|
RUN_TEST(test_a_point_needs_5_seconds_and_5_metres);
|
|
RUN_TEST(test_reset_starts_over);
|
|
RUN_TEST(test_file_name_from_utc);
|
|
RUN_TEST(test_gpx_header_point_and_footer);
|
|
RUN_TEST(test_an_unfinished_file_is_recognised);
|
|
return UNITY_END();
|
|
}
|