Repository navigation
fix(meade): accept the unsigned site longitude INDI sends - #304
ClutchplateDude merged 1 commit into
Conversation
ClutchplateDude
left a comment
There was a problem hiding this comment.
The Meade protocol docs are contradictory with longitude, especially getter vs. setter.
The setter is defined as :SgDDD*MM and so does NOT accept a sign (it also give no indication what numbers are returned).
The getter is defined as :Gg# and is documented as returning sDDD*MM#, where East is negative.
I think we should have :Sg accept a (optional) sign.
3648272 to
6bd9591
Compare
Agreed, and it makes the change smaller rather than bigger. Under east-negative the signed and unsigned forms turn out to be the same mapping, so the two branches collapse into one reader with an optional sign, and the old 0..360 westward count is just the case where the sign is That also gets rid of the sub-degree limitation I flagged in the description, since the sign now lives in I had to flip the getter in the same commit.
Two things that probably want a release note, since east-positive is in released firmware (v1.13.20) and not just develop:
One other thing: #296 shouldn't merge alongside this. It flips the sign in Rebased onto #305 and marked ready for review. |
|
@ClutchplateDude |
MeadeProtocol.hpp documents :Sg and :Gg as east-negative -- zero at Greenwich, negative coordinates going east. OpenAstroTech#291 dropped the negation on both sides at once, so the wire convention silently inverted while every readback still round-tripped perfectly. Restore it on both sides in one commit. readLongitude negates into the east-positive struct; writeLongitude negates back out. Moving only one side would be worse than either convention: a client would set its site, read back the mirror, and push the mirror in on the next connect, where it persists to EEPROM. Under east-negative the signed and the unsigned forms are the same mapping -- east = wrap(-value) either way -- so the two branches collapse into one reader with an optional sign, and the legacy 0..360 westward count INDI sends is just the sign == '+' case. That also retires the sub-degree-west limitation: the sign now travels in MeadeLongitude's `negative` field rather than in `degrees`, so "000*30" (30' west) and "359*30" (30' east) are no longer the same struct. Greenwich goes out as "+000*00#": it is on neither side, and "-000*00" reads as a negative zero. The struct comment now records which convention the value is in. Nothing in the type could show it before, which is how a flip on both sides at once went unnoticed. NOTE: this changes released behaviour. Firmware through v1.13.20 replies to :Gg east-positive, so a client that adapted to that will mirror its site once. A mount whose site was set under that firmware also holds the mirrored value in EEPROM, which this does not correct -- the site has to be pushed again. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01StH2aGiQEj3qvMWJ58CSWz
6bd9591 to
4ae0f3f
Compare
Regression from #291. INDI's site push is silently ignored, so every INDI/KStars session runs with whatever longitude the mount already had. The PR originally raised a protocol-convention question for maintainers; the history settles it (see The signed form and The convention question, resolved) and the code below implements the answer.
The defect
readLongitude()usesCursor::signed3(), which makes the sign mandatory. INDI sends:Sg121*53#unsigned for a site 121°53′ west, so the command is answered0and the mount silently keeps whatever longitude it had.Captured off the wire on an INDI connect to an OpenAstroExplorer:
An unsigned Meade site longitude is the legacy count running westward from Greenwich, so it folds into the east-positive range the mount stores by negating modulo a full circle.
Not by
180 - value. That is the other reflection — the one that puts Greenwich at 180 — and it is what the (now dead)Longitude::ParseFromMeadecomputes and whatMeadeProtocol.hppdescribed. It turns a 121°53′ west site into 58°07′ east: exactly 180°, i.e. 12 hours of local sidereal time, from where it belongs, which mispoints every subsequent GOTO.None of this is visible in readback —
:Gg#applies the inverse of whatever the setter did, so a wrong convention round-trips perfectly. It was verified instead by comparing:XGL#against an independently computed LST.Also fixed
Range validation.
digits(3, …)accepted 0..999 and the wrap was a singleif, not a loop, so:Sg600*00#yielded −240°. Nothing downstream caught it:core::Longitude(int, int, int)never callscheckHours(), andEEPROMStore::storeLongitudeclampsdegrees * 100into anint16(±327.67°) — that clamp destroys the mod-360 equivalence and persists a genuinely wrong site across reboots. Values outside one full circle, and minutes above 59, are now refused.Signed overflow on AVR. The arcminute arithmetic is widened to
long.intis 16-bit on ATmega2560, sodeg * 60 + mmexceededINT16_MAXfrom:Sg545*69#onward — undefined behaviour in an-O2build, and it did diverge between 16- and 32-bit targets. The range check also prevents reaching it; both are in.The signed form — restored, not passed through
An earlier draft of this change passed signed values through as
develophad them. What landed instead restores the pre-#291 convention:Longitude::ParseFromMeadenegated the signed form —result.totalSeconds = -dt.getTotalSeconds(), with a comment citing LX200 spec 2010.10 ("if a sign is present it is straight up longitude with east as negative") — andLongitude::formatStringForMeadenegated again on the way out. The wire was east-negative on both sides.core::Longitudehas been east-positive throughout ("negative going west, positive going east"); only the wire mapping flipped.readLongitudetherefore folds the signed form through the same westward mapping as the unsigned one —+121*53and121*53are the same meridian — andwriteLongitudeflips the sign back on the way out. The struct-level assertions (site_longitude_signed_negative_is_east) pin the hemisphere on the struct rather than the wire, so a future flip on one side alone cannot hide behind a clean round trip the way #291's did.#296 asserts the opposite convention for the signed form; merging this supersedes that half of it.
The sub-degree sign — fixed by the stack
An earlier draft still lost the sign of a west longitude under one degree, because
MeadeLongitudethen carried the sign only in the sign bit ofdegreesand-0is unrepresentable. #305 (merged) gave the struct a separatenegativefield and this PR's reader uses it:000*30(30′ west) and359*30(30′ east) now decode to different sites, pinned bysite_longitude_unsigned_sub_degree_west_keeps_its_sign.The convention question — resolved
MeadeProtocol.hppdocumented the unsigned form as "0 to 360 going WEST with 180 at Greenwich. So 369 is 179W and 1 is 179E." No live code implements that, and it disagrees with what INDI puts on the wire: the pre-#291 code itself pointed at the INDI driver's definition (0..360 westward), and the captured traffic matches it. This PR updates that block to match observed client behaviour and the pre-#291 signed behaviour; the maintainer merge of this stack ratifies it.Verification
pio test -e native: 281 pass at the original stacked tip (269 on then-develop+ 12 added, none removed or weakened). After the post-#305 rebase, CI on the single-commit branch reports 323/323 native test cases passing. An exhaustive sweep of all 21,600 unsigned wire values decodes exactly. Builds clean under-Werrorforoaeboardv1andramps;avr-g++ -mmcu=atmega2560 -Werror -Wconversionclean on the parser.Rebase note
Originally stacked on #305. After #305 merged, rebased onto
developas a single commit containing only the:Sgchanges. #303 (:SG) stacks on top of this and needs the same one-commit rebase before it merges.