Skip to content

Commit 093751a

Browse files
committed
Add support for mosaic-X5 ChannelStatus SV tracking
1 parent 87e1188 commit 093751a

File tree

3 files changed

+114
-4
lines changed

3 files changed

+114
-4
lines changed

Firmware/RTK_Everywhere/GNSS.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ class GNSS
5454

5555
public:
5656
// Constructor
57-
GNSS() : _leapSeconds(18), _pvtArrivalMillis(0), _pvtUpdated(0)
57+
GNSS() : _leapSeconds(18), _pvtArrivalMillis(0), _pvtUpdated(0), _satellitesInView(0)
5858
{
5959
}
6060

Firmware/RTK_Everywhere/GNSS_Mosaic.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ typedef struct {
1818

1919
const mosaicExpectedID mosaicExpectedIDs[] = {
2020
{ 4007, true, 96, "PVTGeodetic" },
21+
{ 4013, false, 0, "ChannelStatus" },
2122
{ 4090, false, 0, "InputLink" },
2223
{ 4097, false, 0, "EncapsulatedOutput" },
2324
{ 5914, true, 24, "ReceiverTime" },
@@ -46,6 +47,10 @@ const mosaicExpectedID mosaicExpectedIDs[] = {
4647
// This indicates if RTCM corrections are being received - on COM2
4748
#define MOSAIC_SBF_INPUTLINK_STREAM (MOSAIC_SBF_EXTEVENT_STREAM + 1)
4849

50+
// Output SBF ChannelStatus messages on this stream - on COM1 only
51+
// These provide the count of satellites being tracked
52+
#define MOSAIC_SBF_CHANNELSTATUS_STREAM (MOSAIC_SBF_INPUTLINK_STREAM + 1)
53+
4954
// TODO: allow the user to define their own SBF stream for logging to DSK1 - through the menu / web config
5055
// But, in the interim, the user can define their own SBF stream (>= Stream3) via the X5 web page over USB-C
5156
// The updated configuration can be saved by entering and exiting the main menu, or by:
@@ -575,13 +580,17 @@ class GNSS_MOSAIC : GNSS
575580
float _latStdDev;
576581
float _lonStdDev;
577582
bool _receiverSetupSeen;
583+
std::vector<uint8_t> svInTracking;
584+
//std::vector<uint8_t> svInPVT;
578585

579586
// Constructor
580587
GNSS_MOSAIC() : _determiningFixedPosition(true), _clkBias_ms(0),
581588
_latStdDev(999.9), _lonStdDev(999.9), _receiverSetupSeen(false),
582589
_radioExtBytesReceived_millis(0),
583590
GNSS()
584591
{
592+
svInTracking.clear();
593+
//svInPVT.clear();
585594
}
586595

587596
// If we have decryption keys, configure module
@@ -1016,6 +1025,9 @@ class GNSS_MOSAIC : GNSS
10161025
// Save the data from the SBF Block 4007
10171026
void storeBlock4007(SEMP_PARSE_STATE *parse);
10181027

1028+
// Save the data from the SBF Block 4013
1029+
void storeBlock4013(SEMP_PARSE_STATE *parse);
1030+
10191031
// Save the data from the SBF Block 4090
10201032
void storeBlock4090(SEMP_PARSE_STATE *parse);
10211033

Firmware/RTK_Everywhere/GNSS_Mosaic.ino

Lines changed: 101 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,11 @@ bool GNSS_MOSAIC::configureOnce()
579579
setting = String("sso,Stream" + String(MOSAIC_SBF_INPUTLINK_STREAM) + ",COM1,InputLink,sec1\n\r");
580580
response &= sendWithResponse(setting, "SBFOutput");
581581

582+
// Output SBF ChannelStatus on its own stream - at 0.5Hz - on COM1 only
583+
// OnChange is too often. The message is typically 1000 bytes in size.
584+
setting = String("sso,Stream" + String(MOSAIC_SBF_CHANNELSTATUS_STREAM) + ",COM1,ChannelStatus,sec2\n\r");
585+
response &= sendWithResponse(setting, "SBFOutput");
586+
582587
response &= setElevation(settings.minElev);
583588

584589
response &= setMinCnoRadio(settings.minCNO);
@@ -2367,16 +2372,105 @@ void GNSS_MOSAIC::storeBlock4007(SEMP_PARSE_STATE *parse)
23672372
_longitude = sempSbfGetF8(parse, 24) * 180.0 / PI;
23682373
_altitude = (float)sempSbfGetF8(parse, 32);
23692374
_horizontalAccuracy = ((float)sempSbfGetU2(parse, 90)) / 100.0; // Convert from cm to m
2370-
_satellitesInView = sempSbfGetU1(parse, 74);
2371-
if (_satellitesInView == 255) // 255 indicates "Do-Not-Use"
2372-
_satellitesInView = 0;
2375+
2376+
// NrSV is the total number of satellites used in the PVT computation.
2377+
//_satellitesInView = sempSbfGetU1(parse, 74);
2378+
//if (_satellitesInView == 255) // 255 indicates "Do-Not-Use"
2379+
// _satellitesInView = 0;
2380+
23732381
_fixType = sempSbfGetU1(parse, 14) & 0x0F;
23742382
_determiningFixedPosition = (sempSbfGetU1(parse, 14) >> 6) & 0x01;
23752383
_clkBias_ms = sempSbfGetF8(parse, 60);
23762384
_pvtArrivalMillis = millis();
23772385
_pvtUpdated = true;
23782386
}
23792387

2388+
//----------------------------------------
2389+
// Save the data from the SBF Block 4013
2390+
//----------------------------------------
2391+
void GNSS_MOSAIC::storeBlock4013(SEMP_PARSE_STATE *parse)
2392+
{
2393+
uint16_t N = (uint16_t)sempSbfGetU1(parse, 14);
2394+
uint16_t SB1Length = (uint16_t)sempSbfGetU1(parse, 15);
2395+
uint16_t SB2Length = (uint16_t)sempSbfGetU1(parse, 16);
2396+
uint16_t ChannelInfoBytes = 0;
2397+
for (uint16_t i = 0; i < N; i++)
2398+
{
2399+
uint8_t SVID = sempSbfGetU1(parse, 20 + ChannelInfoBytes + 0);
2400+
2401+
uint16_t N2 = (uint16_t)sempSbfGetU1(parse, 20 + ChannelInfoBytes + 9);
2402+
2403+
for (uint16_t j = 0; j < N2; j++)
2404+
{
2405+
uint16_t TrackingStatus = sempSbfGetU2(parse, 20 + ChannelInfoBytes + SB1Length + (j * SB2Length) + 2);
2406+
2407+
bool Tracking = false;
2408+
for (uint16_t shift = 0; shift < 16; shift += 2) // Step through each 2-bit status field
2409+
{
2410+
if ((TrackingStatus & (0x0003 << shift)) == (0x0003 << shift)) // 3 : Tracking
2411+
{
2412+
Tracking = true;
2413+
}
2414+
}
2415+
2416+
if (Tracking)
2417+
{
2418+
// SV is being tracked. If it is not in svInTracking, add it
2419+
std::vector<uint8_t>::iterator pos =
2420+
std::find(svInTracking.begin(), svInTracking.end(), SVID);
2421+
if (pos == svInTracking.end())
2422+
svInTracking.push_back(SVID);
2423+
}
2424+
else
2425+
{
2426+
// SV is not being tracked. If it is in svInTracking, remove it
2427+
std::vector<uint8_t>::iterator pos =
2428+
std::find(svInTracking.begin(), svInTracking.end(), SVID);
2429+
if (pos != svInTracking.end())
2430+
svInTracking.erase(pos);
2431+
}
2432+
2433+
// uint16_t PVTStatus = sempSbfGetU2(parse, 20 + ChannelInfoBytes + SB1Length + (j * SB2Length) + 4);
2434+
2435+
// bool Used = false;
2436+
// for (uint16_t shift = 0; shift < 16; shift += 2) // Step through each 2-bit status field
2437+
// {
2438+
// if ((PVTStatus & (0x0003 << shift)) == (0x0002 << shift)) // 2 : Used
2439+
// {
2440+
// Used = true;
2441+
// }
2442+
// }
2443+
2444+
// if (Used)
2445+
// {
2446+
// // SV is being used for PVT. If it is not in svInPVT, add it
2447+
// std::vector<uint8_t>::iterator pos =
2448+
// std::find(svInPVT.begin(), svInPVT.end(), SVID);
2449+
// if (pos == svInPVT.end())
2450+
// svInPVT.push_back(SVID);
2451+
// }
2452+
// else
2453+
// {
2454+
// // SV is not being used for PVT. If it is in svInPVT, remove it
2455+
// std::vector<uint8_t>::iterator pos =
2456+
// std::find(svInPVT.begin(), svInPVT.end(), SVID);
2457+
// if (pos != svInPVT.end())
2458+
// svInPVT.erase(pos);
2459+
// }
2460+
2461+
}
2462+
2463+
ChannelInfoBytes += SB1Length + (N2 * SB2Length);
2464+
}
2465+
2466+
_satellitesInView = (uint8_t)std::distance(svInTracking.begin(), svInTracking.end());
2467+
2468+
//uint8_t _inPVT = (uint8_t)std::distance(svInPVT.begin(), svInPVT.end());
2469+
2470+
//systemPrintf("%d %d %d %d %d %d\r\n", N, SB1Length, SB2Length, ChannelInfoBytes, _satellitesInView, _inPVT);
2471+
2472+
}
2473+
23802474
//----------------------------------------
23812475
// Save the data from the SBF Block 4090
23822476
//----------------------------------------
@@ -2726,6 +2820,10 @@ void processUart1SBF(SEMP_PARSE_STATE *parse, uint16_t type)
27262820
if (sempSbfGetBlockNumber(parse) == 4007)
27272821
mosaic->storeBlock4007(parse);
27282822

2823+
// If this is ChannelStatus, extract some data
2824+
if (sempSbfGetBlockNumber(parse) == 4013)
2825+
mosaic->storeBlock4013(parse);
2826+
27292827
// If this is InputLink, extract some data
27302828
if (sempSbfGetBlockNumber(parse) == 4090)
27312829
mosaic->storeBlock4090(parse);

0 commit comments

Comments
 (0)