Skip to content

Instantly share code, notes, and snippets.

@ilomon10
Created June 26, 2025 03:17
Show Gist options
  • Save ilomon10/616026ac915911e799aa522bd38aa54c to your computer and use it in GitHub Desktop.
Save ilomon10/616026ac915911e799aa522bd38aa54c to your computer and use it in GitHub Desktop.
quectel ril library client
// qlril_gnss_client.ts
// OOP wrapper for Quectel QLRIL GNSS one-shot NMEA location in Deno
export interface Location {
latitude: number;
longitude: number;
}
const symbols: Record<string, Deno.ForeignFunction> = {
QLRIL_Init: { parameters: ["pointer"], result: "i32" },
QLRIL_Exit: { parameters: ["pointer"], result: "i32" },
QLRIL_GNSS_CLIENT_OPEN: { parameters: ["pointer"], result: "i32" },
QLRIL_GNSS_CLIENT_CLOSE: { parameters: ["pointer"], result: "i32" },
QLRIL_GNSS_NEMA_TYPE: { parameters: ["pointer", "i32"], result: "i32" },
QLRIL_GNSS_NEMA_GetLocation: {
parameters: [
"pointer", // handle
"pointer", // int* longitude
"pointer", // int* latitude
"i32", // timeout seconds
],
result: "i32",
},
};
export class QlrilGnssClient {
private lib: Deno.DynamicLibrary<typeof symbols>;
private handleBuf: BigUint64Array;
private handlePtr: Deno.PointerValue;
private closed = false;
constructor(soPath: string = "libql_ril.so") {
this.lib = Deno.dlopen(soPath, symbols);
this.handleBuf = new BigUint64Array(1);
this.handlePtr = Deno.UnsafePointer.of(this.handleBuf);
}
async init(): Promise<void> {
const rc = this.lib.symbols.QLRIL_Init(this.handlePtr);
if (rc !== 0) {
throw new Error(`QLRIL_Init failed: ${rc}`);
}
}
async openClient(nmeaMode: number = 1): Promise<void> {
let rc = this.lib.symbols.QLRIL_GNSS_CLIENT_OPEN(this.handlePtr);
if (rc !== 0) throw new Error(`GNSS_CLIENT_OPEN failed: ${rc}`);
rc = this.lib.symbols.QLRIL_GNSS_NEMA_TYPE(this.handlePtr, nmeaMode);
if (rc !== 0) console.warn(`NEMA_TYPE returned warning code: ${rc}`);
}
async getOneShotLocation(timeoutSec: number = 90): Promise<Location> {
// allocate buffers
const lonBuf = new Int32Array(1);
const latBuf = new Int32Array(1);
const lonPtr = Deno.UnsafePointer.of(lonBuf);
const latPtr = Deno.UnsafePointer.of(latBuf);
const rc = this.lib.symbols.QLRIL_GNSS_NEMA_GetLocation(
this.handlePtr,
lonPtr,
latPtr,
timeoutSec
);
if (rc !== 0) {
throw new Error(`NEMA_GetLocation failed: ${rc}`);
}
// scale by 1e-6
return {
longitude: lonBuf[0] / 1e6,
latitude: latBuf[0] / 1e6,
};
}
async close(): Promise<void> {
if (this.closed) return;
this.lib.symbols.QLRIL_GNSS_CLIENT_CLOSE(this.handlePtr);
this.lib.symbols.QLRIL_Exit(this.handlePtr);
this.lib.close();
this.closed = true;
}
}
// example usage
if (import.meta.main) {
(async () => {
const client = new QlrilGnssClient();
try {
await client.init();
await client.openClient();
console.log("๐Ÿ”„ Acquiring one-shot NMEA location...");
const loc = await client.getOneShotLocation(90);
console.log(
`๐Ÿ“ Latitude: ${loc.latitude.toFixed(
6
)}, Longitude: ${loc.longitude.toFixed(6)}`
);
} catch (err) {
console.error(err);
} finally {
await client.close();
}
})();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment