Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 28 additions & 2 deletions src/core/meade/MeadeParserSet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,32 @@ bool readLongitude(Cursor &c, MeadeLongitude &out)
return true;
}

// Format: "[+-]H[H]", with anything after the hours left unconsumed, so the
// ":SG+7.0#" that INDI sends on connect parses as +7 -- as it did before the
// refactor, when the handler ran toInt() over "+7.". Requiring a sign and
// exactly two digits makes INDI's UTC-offset push fail with "0" and leaves the
// site offset unset.
bool readUtcOffset(Cursor &c, int &out)
{
const bool negative = c.match('-');
if (!negative)
{
c.match('+'); // Optional; an unsigned offset is positive.
}
unsigned hh;
if (!c.digits(1, hh))
{
return false;
}
unsigned secondDigit;
if (c.digits(1, secondDigit))
{
hh = hh * 10 + secondDigit;
}
out = negative ? -static_cast<int>(hh) : static_cast<int>(hh);
return true;
}

// Set ack: "1" on success, "0" on failure. No framing terminator.
void writeSetAck(MeadeResponse &r, bool ok)
{
Expand Down Expand Up @@ -222,9 +248,9 @@ void handleMeadeSet(MeadeResponse &r, const char *s, IMeadeSetHandlers &h)

case 'G':
{
// G<sign><DD>
// G[<sign>]<H[H]>
int hours;
if (!c.signed2(hours))
if (!readUtcOffset(c, hours))
{
writeChar(r, '0');
return;
Expand Down
9 changes: 6 additions & 3 deletions src/core/meade/MeadeProtocol.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -348,10 +348,13 @@
// Information:
// This sets the offset of the timezone in which the mount is in hours from UTC.
// Returns:
// "1"
// "1" if successfully set
// "0" otherwise
// Parameters:
// "s" is the sign
// "HH" is the number of hours
// "s" (optional) is the sign, an unsigned offset being positive
// "HH" is the number of hours, one or two digits
// Remarks:
// Anything following the hours is ignored, so the ":SG+7.0#" that INDI sends is read as +7. The offset is whole hours only, so half-hour zones such as India and Newfoundland cannot be expressed.
//
// :SLHH:MM:SS#
// Description:
Expand Down
73 changes: 71 additions & 2 deletions unit_tests/test_core/meade/test_MeadeSet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -318,10 +318,79 @@ TEST(MeadeSet, utc_offset_negative)
EXPECT_EQ(-8, h.utc);
}

TEST(MeadeSet, utc_offset_malformed_length_does_not_call_handler)
// The exact bytes INDI puts on the wire when it pushes the site on connect.
TEST(MeadeSet, utc_offset_indi_fractional_form)
{
FakeHandlers h;
EXPECT_STREQ("0", dispatch("G+5", h));
EXPECT_STREQ("1", dispatch("G+7.0", h));
EXPECT_STREQ("utc", h.lastCall);
EXPECT_EQ(7, h.utc);
}

TEST(MeadeSet, utc_offset_single_digit_positive)
{
FakeHandlers h;
EXPECT_STREQ("1", dispatch("G+5", h));
EXPECT_EQ(5, h.utc);
}

TEST(MeadeSet, utc_offset_single_digit_negative)
{
FakeHandlers h;
EXPECT_STREQ("1", dispatch("G-3", h));
EXPECT_EQ(-3, h.utc);
}

TEST(MeadeSet, utc_offset_unsigned_is_positive)
{
FakeHandlers h;
EXPECT_STREQ("1", dispatch("G07", h));
EXPECT_EQ(7, h.utc);
}

// Half-hour zones (India, Newfoundland) are unrepresentable: onSetUtcOffset takes
// whole hours, so ".5" is left unconsumed and the site lands 30 minutes out.
// Pinned here so the limitation is documented rather than discovered in the field.
TEST(MeadeSet, utc_offset_half_hour_zone_drops_the_fraction)
{
FakeHandlers h;
EXPECT_STREQ("1", dispatch("G+5.5", h));
EXPECT_EQ(5, h.utc);
}

// Nothing range-checks the hours. "+13" is a real offset (Tonga); "-15" is not,
// and is taken all the same. Both pin the current permissive behaviour --
// whether to reject impossible offsets is deliberately left to a follow-up.
// Note that IMeadeSetHandlers::onSetUtcOffset documents "@param hours Signed
// wire value (-12..+14)"; that range is stated but has never been enforced,
// here or before this parser accepted the unsigned and single-digit forms.
TEST(MeadeSet, utc_offset_two_digit_high_value)
{
FakeHandlers h;
EXPECT_STREQ("1", dispatch("G+13", h));
EXPECT_STREQ("utc", h.lastCall);
EXPECT_EQ(13, h.utc);
}

TEST(MeadeSet, utc_offset_impossible_value_is_accepted)
{
FakeHandlers h;
EXPECT_STREQ("1", dispatch("G-15", h));
EXPECT_STREQ("utc", h.lastCall);
EXPECT_EQ(-15, h.utc);
}

TEST(MeadeSet, utc_offset_sign_without_digits_does_not_call_handler)
{
FakeHandlers h;
EXPECT_STREQ("0", dispatch("G+", h));
EXPECT_EQ(nullptr, h.lastCall);
}

TEST(MeadeSet, utc_offset_non_numeric_does_not_call_handler)
{
FakeHandlers h;
EXPECT_STREQ("0", dispatch("Gx", h));
EXPECT_EQ(nullptr, h.lastCall);
}

Expand Down