Programming Guide¶
This guide demonstrates how to use the qt-test application components in your own applications to communicate with SitePoint GPS devices.
The examples follow a progressive approach: starting with basic device connection, then adding NTRIP corrections, and finally accessing configuration data.
Basic BLE Connection¶
The BLEManager class provides the complete Bluetooth Low Energy interface to SitePoint GPS receivers.
Minimal Connection Example¶
This example shows the minimum code needed to connect to a SitePoint device and receive GPS position updates:
#include "BLEManager.h"
#include <QCoreApplication>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
// Create BLE manager instance
BLEManager *bleManager = new BLEManager(&app);
// Connect to device discovery signal
QObject::connect(bleManager, &BLEManager::deviceDiscovered,
[bleManager](const QString &name, const QString &address) {
qDebug() << "Discovered:" << name << "at" << address;
// Auto-connect to first SitePoint device
if (name.contains("SitePoint")) {
bleManager->connectToDevice(address);
}
});
// Connect to connection status signal
QObject::connect(bleManager, &BLEManager::deviceConnected, []() {
qDebug() << "Connected successfully";
});
// Connect to position data signal
QObject::connect(bleManager, &BLEManager::llaDataChanged,
[bleManager]() {
SqspLla_t lla = bleManager->getLlaData();
qDebug() << "Position:" << lla.latitude << ","
<< lla.longitude << "Alt:" << lla.hMSL << "m";
});
// Start scanning
bleManager->startScan();
return app.exec();
}
Output:
Discovered: "SitePoint-1234" at "12:34:56:78:9A:BC"
Connected successfully
Position: 37.7749 , -122.4194 Alt: 15.2 m
Position: 37.7749 , -122.4194 Alt: 15.3 m
Key Concepts¶
- Signal-Driven Architecture:
The BLEManager uses Qt signals to notify your application of events. Connect to the signals you need and ignore the rest.
- Change Detection:
Position data arrives at 8-10 Hz, but
llaDataChanged()only fires when the data actually changes (see Theory of Operation for details).- Asynchronous Connection:
connectToDevice()is asynchronous. UsedeviceConnected()signal to know when connection is ready.
Adding NTRIP Corrections¶
For RTK positioning, the device needs correction data from an NTRIP caster. The NTRIPManager class handles the network connection, and BLEManager transmits the corrections to the device.
Complete NTRIP Example¶
#include "BLEManager.h"
#include "NTRIPManager.h"
#include <QCoreApplication>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
BLEManager *bleManager = new BLEManager(&app);
NTRIPManager *ntripManager = new NTRIPManager(&app);
// Configure NTRIP connection
QString host = "rtk.example.com";
quint16 port = 2101;
QString mountpoint = "RTCM3";
QString username = "user";
QString password = "pass";
// Connect NTRIP data to BLE transmission
QObject::connect(ntripManager, &NTRIPManager::rtcmDataReceived,
[bleManager](const QByteArray &rtcmData) {
bleManager->queueRTCMMessage(rtcmData);
});
// Monitor NTRIP connection status
QObject::connect(ntripManager, &NTRIPManager::connectionStatusChanged,
[](bool connected) {
qDebug() << "NTRIP" << (connected ? "connected" : "disconnected");
});
// Monitor device status for correction age
QObject::connect(bleManager, &BLEManager::statusDataChanged,
[bleManager]() {
SqspStatus_t status = bleManager->getStatusData();
qDebug() << "Satellites:" << status.numSatellites
<< "Correction age:" << status.correctionAge << "ms";
// Check if RTK corrections are active
if (status.aidingBins & (1 << 4)) {
qDebug() << "RTK corrections active";
}
});
// Start BLE scan
bleManager->startScan();
// Auto-connect to NTRIP when device is connected
QObject::connect(bleManager, &BLEManager::deviceConnected,
[ntripManager, host, port, mountpoint, username, password]() {
ntripManager->connectToNtrip(host, port, mountpoint,
username, password);
});
return app.exec();
}
Understanding RTCM Transmission¶
RTCM messages are queued and transmitted automatically by the BLEManager:
NTRIP caster sends RTCM v3 messages (typically 1 Hz)
NTRIPManagerreceives and emitsrtcmDataReceived()signalYour code calls
queueRTCMMessage()to add message to transmission queueBLEManager’s FSM paces transmission to match BLE connection interval
Messages are fragmented if they exceed MTU size
GPS device receives corrections and improves position accuracy
Important: The RTCM queue has a capacity of 50 messages. For typical NTRIP streams, this provides ample buffering. If messages are dropped, reduce the correction data rate at the caster.
Device Configuration and Modes¶
The GPS device can operate in several modes, each optimized for different use cases.
Changing Device Mode¶
#include "BLEManager.h"
#include "sqsp.h" // For DEVICE_MODE_* constants
// Set device to rover mode with NTRIP corrections
bleManager->sendModeChangeCommand(DEVICE_MODE_ROVER_NTRIP);
// Set device to fixed base station mode
bleManager->sendModeChangeCommand(DEVICE_MODE_FIXED_BASE);
Available Modes:
DEVICE_MODE_ROVER- Standard rover, no corrections, ~2m accuracyDEVICE_MODE_ROVER_NTRIP- Rover with NTRIP corrections via BLE, ~2cm accuracyDEVICE_MODE_ROVER_NEAREST- Rover with Tripod network corrections, ~2cm accuracyDEVICE_MODE_FIXED_BASE- Fixed base station, broadcasts correctionsDEVICE_MODE_FIXED_BASE_BROADCAST- Fixed base with wider broadcast range
See Device Configuration for detailed mode descriptions and use cases.
Accessing Configuration Data¶
The device configuration includes base station position and survey duration:
QObject::connect(bleManager, &BLEManager::configDataChanged,
[bleManager]() {
SqspLbConfig_t config = bleManager->getConfigData();
qDebug() << "Base station position:";
qDebug() << " Latitude:" << config.latitude;
qDebug() << " Longitude:" << config.longitude;
qDebug() << " Height MSL:" << config.hMSL << "m";
qDebug() << " Survey duration:" << config.duration << "seconds";
});
Working with Position Data¶
The SqspLla_t structure contains comprehensive position and accuracy information.
Accessing Position Fields¶
SqspLla_t lla = bleManager->getLlaData();
// Position in degrees
double latitude = lla.latitude; // -90 to +90
double longitude = lla.longitude; // -180 to +180
// Height measurements in meters
double heightWGS84 = lla.height; // Height above WGS84 ellipsoid
double heightMSL = lla.hMSL; // Height above mean sea level
// Accuracy estimates in meters
float horizontalAccuracy = lla.hAcc; // Horizontal accuracy
float verticalAccuracy = lla.vAcc; // Vertical accuracy
// Solution quality indicator
uint8_t quality = lla.solutionType;
Solution Type Values:
0 - No fix
1 - Autonomous GPS (no corrections)
2 - DGPS / SBAS
4 - RTK Fixed (cm-level accuracy)
5 - RTK Float (dm-level accuracy)
High-Performance Data Access¶
For applications that need high-frequency position access (e.g., real-time mapping at 8-10 Hz), use direct extern access to avoid function call overhead:
#include "sqsp.h"
// Declare extern global (defined in BLEManager.cpp)
extern SqspLla_t myLla;
// Direct access - no function call overhead
double lat = myLla.latitude;
double lon = myLla.longitude;
float acc = myLla.hAcc;
Performance Comparison:
Function call:
bleManager->getLlaData()- Returns copy, ~100ns overheadDirect access:
myLla.latitude- Direct memory access, ~5ns
For 8-10 Hz updates in performance-critical code (rendering, logging), use direct access. For occasional access (UI updates, user queries), use the function call for better encapsulation.
Working with Status Data¶
The SqspStatus_t structure provides real-time device status information.
Monitoring Satellite Tracking¶
SqspStatus_t status = bleManager->getStatusData();
qDebug() << "Satellites tracked:" << status.numSatellites;
qDebug() << "HDOP:" << status.hdop; // Horizontal dilution of precision
qDebug() << "VDOP:" << status.vdop; // Vertical dilution of precision
HDOP/VDOP Interpretation:
< 2.0 - Excellent geometry
2.0 - 5.0 - Good geometry
5.0 - 10.0 - Moderate geometry
> 10.0 - Poor geometry
Checking Correction Status¶
SqspStatus_t status = bleManager->getStatusData();
// Correction age in milliseconds
uint32_t age = status.correctionAge;
if (age < 30000) {
qDebug() << "Corrections fresh:" << age << "ms";
} else {
qDebug() << "Corrections stale:" << age << "ms";
}
// Check aiding data availability
uint32_t aiding = status.aidingBins;
if (aiding & (1 << 0)) qDebug() << "Ephemeris available";
if (aiding & (1 << 1)) qDebug() << "Almanac available";
if (aiding & (1 << 2)) qDebug() << "UTC model available";
if (aiding & (1 << 3)) qDebug() << "Ionosphere model available";
if (aiding & (1 << 4)) qDebug() << "RTCM corrections active";
Correction Age Guidelines:
< 10 seconds - Optimal RTK performance
10-30 seconds - Good RTK performance
> 30 seconds - Degraded RTK performance
> 60 seconds - RTK solution may drop to float
Error Handling¶
Handling Connection Errors¶
QObject::connect(bleManager, &BLEManager::errorOccurred,
[](const QString &errorMessage) {
qCritical() << "BLE Error:" << errorMessage;
// Common errors:
// - "Bluetooth adapter not available"
// - "Device not found"
// - "Connection timeout"
// - "Service discovery failed"
});
QObject::connect(bleManager, &BLEManager::deviceDisconnected,
[bleManager]() {
qWarning() << "Device disconnected unexpectedly";
// Attempt reconnection after delay
QTimer::singleShot(5000, bleManager, &BLEManager::reconnectToLastDevice);
});
Handling NTRIP Errors¶
QObject::connect(ntripManager, &NTRIPManager::errorOccurred,
[](const QString &errorMessage) {
qCritical() << "NTRIP Error:" << errorMessage;
// Common errors:
// - "Network unreachable"
// - "Authentication failed"
// - "Invalid mountpoint"
// - "Connection timeout"
});
Complete Application Example¶
This complete example demonstrates a full RTK GPS application with error handling, status monitoring, and data logging:
#include <QCoreApplication>
#include <QTimer>
#include <QFile>
#include <QTextStream>
#include <QDebug>
#include "BLEManager.h"
#include "NTRIPManager.h"
class RTKLogger : public QObject
{
Q_OBJECT
public:
RTKLogger(QObject *parent = nullptr) : QObject(parent)
{
bleManager = new BLEManager(this);
ntripManager = new NTRIPManager(this);
setupConnections();
openLogFile();
}
private slots:
void onDeviceDiscovered(const QString &name, const QString &address)
{
if (name.contains("SitePoint") && targetAddress.isEmpty()) {
qDebug() << "Found SitePoint device:" << address;
targetAddress = address;
bleManager->connectToDevice(address);
}
}
void onDeviceConnected()
{
qDebug() << "Device connected, starting NTRIP...";
ntripManager->connectToNtrip("rtk.example.com", 2101, "RTCM3",
"user", "pass");
}
void onLlaDataChanged()
{
SqspLla_t lla = bleManager->getLlaData();
SqspStatus_t status = bleManager->getStatusData();
// Log position with timestamp
QString logLine = QString("%1,%2,%3,%4,%5,%6\n")
.arg(QDateTime::currentDateTime().toString(Qt::ISODate))
.arg(lla.latitude, 0, 'f', 8)
.arg(lla.longitude, 0, 'f', 8)
.arg(lla.hMSL, 0, 'f', 3)
.arg(lla.hAcc, 0, 'f', 3)
.arg(status.numSatellites);
if (logFile.isOpen()) {
QTextStream stream(&logFile);
stream << logLine;
stream.flush();
}
qDebug() << "Logged position:" << lla.latitude << ","
<< lla.longitude << "Sats:" << status.numSatellites;
}
void onRtcmDataReceived(const QByteArray &rtcmData)
{
bleManager->queueRTCMMessage(rtcmData);
rtcmMessageCount++;
if (rtcmMessageCount % 10 == 0) {
qDebug() << "RTCM messages transmitted:" << rtcmMessageCount;
}
}
private:
void setupConnections()
{
connect(bleManager, &BLEManager::deviceDiscovered,
this, &RTKLogger::onDeviceDiscovered);
connect(bleManager, &BLEManager::deviceConnected,
this, &RTKLogger::onDeviceConnected);
connect(bleManager, &BLEManager::llaDataChanged,
this, &RTKLogger::onLlaDataChanged);
connect(ntripManager, &NTRIPManager::rtcmDataReceived,
this, &RTKLogger::onRtcmDataReceived);
connect(bleManager, &BLEManager::errorOccurred,
[](const QString &error) {
qCritical() << "BLE Error:" << error;
});
connect(ntripManager, &NTRIPManager::errorOccurred,
[](const QString &error) {
qCritical() << "NTRIP Error:" << error;
});
}
void openLogFile()
{
QString filename = QString("rtk_log_%1.csv")
.arg(QDateTime::currentDateTime().toString("yyyyMMdd_hhmmss"));
logFile.setFileName(filename);
if (logFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
QTextStream stream(&logFile);
stream << "Timestamp,Latitude,Longitude,Height(m),Accuracy(m),Satellites\n";
qDebug() << "Logging to:" << filename;
}
}
BLEManager *bleManager;
NTRIPManager *ntripManager;
QFile logFile;
QString targetAddress;
int rtcmMessageCount = 0;
};
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
RTKLogger logger;
logger.bleManager->startScan();
return app.exec();
}
#include "main.moc"
Using DataManager for Formatted Display¶
The DataManager provides pre-formatted GPS data strings optimized for QML display. Instead of formatting coordinates in QML (which would happen every frame), DataManager formats once in C++ and caches the results.
Accessing Formatted Data in C++¶
#include "DataManager.h"
#include "BLEManager.h"
#include <QCoreApplication>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
BLEManager *bleManager = new BLEManager(&app);
DataManager *dataManager = new DataManager(&app);
// Connect DataManager to BLEManager signals
QObject::connect(bleManager, &BLEManager::llaDataChanged,
dataManager, &DataManager::onLlaDataChanged);
QObject::connect(bleManager, &BLEManager::statusDataChanged,
dataManager, &DataManager::onStatusDataChanged);
QObject::connect(bleManager, &BLEManager::configDataChanged,
dataManager, &DataManager::onConfigDataChanged);
// Access formatted data through QVariantMap
QObject::connect(dataManager, &DataManager::dataChanged,
[dataManager]() {
QVariantMap lla = dataManager->llaData();
// All strings are pre-formatted with proper precision
qDebug() << "Latitude:" << lla["latitude"].toString(); // "43.641130095°"
qDebug() << "Longitude:" << lla["longitude"].toString(); // "-72.253870594°"
qDebug() << "Height:" << lla["height"].toString(); // "123.4567m"
qDebug() << "H Accuracy:" << lla["hAcc"].toString(); // "0.0234m"
});
// Access status data
QObject::connect(dataManager, &DataManager::statusDataChanged,
[dataManager]() {
QVariantMap status = dataManager->statusData();
qDebug() << "Satellites:" << status["numSV"].toString(); // "12 satellites"
qDebug() << "Solution:" << status["solType"].toString(); // "RTK Fixed"
qDebug() << "Battery:" << status["battery"].toString(); // "87%"
qDebug() << "GPS Fix OK:" << status["gpsFixOk"].toString(); // "Yes"
});
// Start BLE connection
bleManager->startScan();
return app.exec();
}
Understanding Batched Properties¶
Why Batched Properties Are Faster:
Traditional approach (slow):
// Would require 15+ separate Q_PROPERTY declarations
Q_PROPERTY(QString latitude READ latitude NOTIFY latitudeChanged)
Q_PROPERTY(QString longitude READ longitude NOTIFY longitudeChanged)
Q_PROPERTY(QString height READ height NOTIFY heightChanged)
// ... 12 more properties ...
// Results in 15+ signal emissions per GPS update
emit latitudeChanged();
emit longitudeChanged();
emit heightChanged();
// ... 12 more signals ...
Batched approach (fast):
// Single Q_PROPERTY with all related data
Q_PROPERTY(QVariantMap llaData READ llaData NOTIFY dataChanged)
// Results in 1 signal emission per GPS update
emit dataChanged();
Performance Impact at 8-10 Hz:
Traditional: 120-150 signal emissions/second (15 signals × 8-10 Hz)
Batched: 8-10 signal emissions/second (1 signal × 8-10 Hz)
90% reduction in Qt signal routing overhead
Changing Device Mode¶
Use DataManager’s setDeviceMode() method to change operational modes:
// Change to rover with NTRIP corrections
dataManager->setDeviceMode("ROVER NTRIP");
// Change to fixed base station
dataManager->setDeviceMode("FIXED BASE");
// Change to fixed base with broadcast
dataManager->setDeviceMode("FIXED BASE BROADCAST");
Supported Mode Strings:
"ROVER"- Standard rover, no corrections"ROVER NTRIP"- Rover with NTRIP corrections via BLE"ROVER NEAREST"- Rover with Tripod network corrections"FIXED BASE"- Fixed base station"FIXED BASE BROADCAST"- Fixed base with broadcast
Real-Time Map Display with MapManager¶
The MapManager provides the fastest path to GPS coordinates for real-time map rendering. It’s designed specifically for QtLocation’s Map component.
Basic Map Integration¶
#include "MapManager.h"
#include "BLEManager.h"
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
// Create managers
BLEManager *bleManager = new BLEManager(&app);
MapManager *mapManager = new MapManager(&app);
// Connect MapManager to BLEManager
QObject::connect(bleManager, &BLEManager::llaDataChanged,
mapManager, &MapManager::onLlaDataChanged);
// Register for QML access
engine.rootContext()->setContextProperty("bleManager", bleManager);
engine.rootContext()->setContextProperty("mapManager", mapManager);
// Load QML
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
}
Corresponding QML (MapWindow.qml):
import QtQuick
import QtLocation
import QtPositioning
Window {
width: 800
height: 600
title: mapManager.formattedTitle // Live title with coordinates
Map {
anchors.fill: parent
plugin: Plugin { name: "osm" } // OpenStreetMap
// Live GPS position binding - updates at 8-10 Hz
center: QtPositioning.coordinate(mapManager.lat, mapManager.lon)
zoomLevel: 16
// Device position marker
MapCircle {
center: QtPositioning.coordinate(mapManager.lat, mapManager.lon)
radius: 5 // 5 meters
color: "red"
border.color: "darkred"
border.width: 2
}
}
// Center on GPS button
Rectangle {
anchors.top: parent.top
anchors.right: parent.right
anchors.margins: 10
width: 120
height: 40
Text {
anchors.centerIn: parent
text: "Center on GPS"
}
MouseArea {
anchors.fill: parent
onClicked: {
map.center = QtPositioning.coordinate(
mapManager.lat, mapManager.lon
)
}
}
}
}
Understanding MapManager Performance¶
MapManager is optimized for zero-overhead coordinate access:
// MapManager.cpp - Direct extern access
double MapManager::lat() const {
return myLla.lat; // ~5ns, no function call overhead
}
Why This Matters:
At 8-10 Hz update rate with 60 FPS rendering:
QML Map re-reads coordinates 60 times per second
Each coordinate access: ~5ns
Total overhead: ~300ns per frame
Map rendering: ~16ms per frame
Coordinate access overhead is 0.002% of total frame time, ensuring smooth real-time map updates.
Contrast with DataManager:
DataManager formats strings for display (expensive operation), so it caches results. MapManager returns raw doubles (cheap operation), so no caching needed.
QML User Interface Components¶
The application provides four main QML components that integrate with the Manager classes.
Main.qml - Application Structure¶
Purpose: Main application window with BLE device list and NTRIP client.
Key Features:
Device discovery and connection list
NTRIP connection configuration (NTRIPClient.qml component)
Window management (shows DeviceDataWindow and MapWindow)
Device connection state management
Manager Integration:
// Registered context properties in main.cpp
property var bleManager: bleManager
property var ntripManager: ntripManager
// Device discovery connection
Connections {
target: bleManager
function onDeviceDiscovered(deviceName, deviceAddress) {
deviceModel.append({
deviceName: deviceName,
deviceAddress: deviceAddress,
connected: false
})
}
}
// Connect to selected device
MouseArea {
onClicked: {
bleManager.connectToDevice(model.deviceAddress)
}
}
DeviceDataWindow.qml - Live Data Display¶
Purpose: Real-time display of GPS data with configuration editing.
Key Features:
Three data sections: LLA, Status, Config
Batched property binding for performance
Device mode selection (ComboBox)
Correction source selection (RadioButtons)
Configuration editing with validation
Manager Integration - Batched Properties:
// Batched property bindings - single signal per category
property var lla: dataManager.llaData
property var status: dataManager.statusData
property var config: dataManager.configData
// Display formatted strings from DataManager
GridLayout {
Text { text: "Latitude" }
Text { text: lla.latitude } // "43.641130095°"
Text { text: "Longitude" }
Text { text: lla.longitude } // "-72.253870594°"
Text { text: "Height" }
Text { text: lla.height } // "123.4567m"
}
Device Mode Control:
ComboBox {
model: ["ROVER", "FIXED BASE", "FIXED BASE BROADCAST"]
currentIndex: {
switch(dataManager.deviceStatus.deviceMode) {
case "ROVER": return 0
case "FIXED BASE": return 1
case "FIXED BASE BROADCAST": return 2
default: return 0
}
}
onActivated: {
dataManager.setDeviceMode(currentText)
}
}
Performance Note: Using batched properties (lla.latitude) instead of
individual properties reduces QML property binding overhead by ~90%.
NTRIPClient.qml - NTRIP Configuration¶
Purpose: Collapsible NTRIP connection configuration panel.
Key Features:
Server configuration (host, port, mountpoint, credentials)
Bidirectional property binding with ntripManager
Connection status display with color coding
Collapsible UI (Show/Hide button)
Manager Integration - Bidirectional Binding:
TextField {
id: hostField
text: ntripManager.serverHost // QML ← C++
onTextChanged: {
if (text !== ntripManager.serverHost)
ntripManager.serverHost = text // QML → C++
}
}
Button {
text: ntripManager.connected ? "Disconnect" : "Connect"
onClicked: {
if (ntripManager.connected)
ntripManager.disconnectFromServer()
else
ntripManager.connectToServer()
}
}
Text {
text: ntripManager.connectionStatus
color: ntripManager.connected ? "green" :
ntripManager.connectionStatus.includes("Error") ? "red" : "black"
}
Collapsible Pattern:
Rectangle {
property bool expanded: true
states: [
State {
name: "collapsed"
when: !expanded
PropertyChanges { target: ntripClient; height: 50 }
},
State {
name: "expanded"
when: expanded
PropertyChanges { target: ntripClient; height: 350 }
}
]
Behavior on height {
NumberAnimation { duration: 300; easing.type: Easing.OutCubic }
}
}
MapWindow.qml - Real-Time GPS Map¶
Purpose: OpenStreetMap display with live GPS tracking.
Key Features:
Real-time map center binding to GPS coordinates
Device position marker (red circle)
Interactive controls (pinch, drag, zoom)
Live title with coordinates and update counter
“Center on GPS” button
Manager Integration - Direct Coordinate Binding:
Window {
// Live window title
title: mapManager.formattedTitle
// "43.641130095°, -72.253870594°, 123.4567m - Center Updates: 47"
Map {
// Live center binding - updates at 8-10 Hz
center: QtPositioning.coordinate(mapManager.lat, mapManager.lon)
// Device marker - also updates at 8-10 Hz
MapCircle {
center: QtPositioning.coordinate(mapManager.lat, mapManager.lon)
radius: 5
color: "red"
}
}
}
Performance: Direct coordinate binding with no intermediate formatting ensures smooth map updates. The Map component automatically throttles rendering to 60 FPS, while coordinate reads happen at the full 8-10 Hz rate.
Interactive Controls (from Qt examples):
// Pinch to zoom
PinchHandler {
onScaleChanged: (delta) => {
map.zoomLevel += Math.log2(delta)
}
}
// Drag to pan
DragHandler {
onTranslationChanged: (delta) => map.pan(-delta.x, -delta.y)
}
// Mouse wheel zoom
WheelHandler {
property: "zoomLevel"
}
Next Steps¶
Review API Reference for complete API documentation
See Device Configuration for detailed device mode information
Consult Theory of Operation for protocol and architecture details
Check BLE Communication with SitePoint GPS Devices for BLE implementation specifics