pamoja for TypeScript - v0.1.18
    Preparing search index...

    Module @pamoja/radios

    Ergonomic facade over the generated LoRa radio binding.

    @pamoja/lora works out what a link costs and how far it reaches; this puts a radio chip on the air to match. For the Semtech SX1261, SX1262, and LLCC68 it builds the bytes of every command and decodes every answer, and for the SX1276 family it gives the register values and decodes the readings. It chooses the amplifier setting a regional EIRP ceiling allows behind an antenna, and holds the radio silent for the off time a duty-cycle limit owes after each frame.

    @pamoja/radios

    The Semtech SX126x and SX127x LoRa radios: their commands, registers, and decoders, the amplifier setting a regional EIRP ceiling allows, and a duty-cycle guard. One capability of pamoja, one memory-safe Rust core with bindings for TypeScript, Python, and C#.

    read the guide documentation API reference

    npm install @pamoja/radios
    

    This pulls in @pamoja/native, the compiled engine. npm install pamoja is the whole framework in one package.

    The test that runs in CI, spliced here as it ran.

    From bindings/node/guides/radios.ts:

    import { LoraRegion, airtimeUs, linkBudget, planFor } from '@pamoja/lora'
    import { DutyCycle, sx126x } from '@pamoja/radios'

    const hex = (bytes: Uint8Array): string =>
    Array.from(bytes, (byte) => byte.toString(16).padStart(2, '0')).join(' ')

    // An SX1262 node sends a ten-byte reading on 868.1 MHz at DR3, SF9 at 125 kHz, through a
    // 2.15 dBi whip on half a decibel of pigtail. The plan caps the EIRP there, and the antenna
    // and pigtail decide how hard the amplifier may drive under that cap.
    const eu868 = planFor(LoraRegion.Eu868)
    const frequency = 868_100_000
    const link = eu868.linkSettings(3)!
    const whip = linkBudget({ transmitAntennaGainDbi: 2.15, transmitCableLossDb: 0.5 })
    const ceiling = eu868.maxEirpDbm(frequency)
    const power = sx126x.txPowerUnderCeiling(sx126x.Amplifier.HighPower, whip, ceiling)
    console.log(`power ${power.settingDbm} dBm under a ${ceiling} dBm EIRP ceiling`)

    // The commands in the order section 14.2 of the datasheet gives, each sent in its own SPI
    // transaction once BUSY is low. The chip gives up on the frame a second after its airtime.
    const airtime = airtimeUs(link, 10)
    const events = sx126x.Irq.TxDone | sx126x.Irq.Timeout
    const commands: [string, Uint8Array][] = [
    ['standby', sx126x.setStandby()],
    ['packet type', sx126x.setPacketTypeLora()],
    ['frequency', sx126x.setRfFrequency(frequency)],
    ['pa config', sx126x.setPaConfig(power)],
    ['tx params', sx126x.setTxParams(power, 40)],
    ['modulation', sx126x.setLoraModulationParams(link)],
    ['packet', sx126x.setLoraPacketParams(link, 10, false)],
    ['irq', sx126x.setDioIrqParams(events, events)],
    ['tx', sx126x.setTx(airtime + 1_000_000)],
    ]
    for (const [name, bytes] of commands) {
    console.log(`${name.padEnd(12)}${hex(bytes)}`)
    }

    // Once the frame has left, GetIrqStatus answers with TxDone, and the status byte shows the
    // chip back in standby.
    const irq = sx126x.irq(Buffer.from([0x00, 0x01]))
    const sent = (irq & sx126x.Irq.TxDone) !== 0
    const timedOut = (irq & sx126x.Irq.Timeout) !== 0
    console.log(`sent tx done ${sent}, timed out ${timedOut}`)
    const status = sx126x.status(0x2c)
    console.log(`status ${status.chipMode}, ${status.commandStatus}`)

    // A frame that arrives later comes with the signal levels it was heard at.
    const heard = sx126x.packetStatus(Buffer.from([0xdb, 0xf6, 0xe0]))
    console.log(`received RSSI ${heard.rssiDbm} dBm, SNR ${heard.snrDb} dB`)

    // The sub-band that holds 868.1 MHz allows 1% of the time, so the frame's airtime buys
    // ninety-nine times as long in silence before the next.
    const guard = new DutyCycle(eu868.dutyCyclePermille(frequency)!)
    const held = guard.transmitted(0, link, 10)
    console.log(`airtime ${held} us, next frame after ${guard.waitUs(0)} us`)
    Language Package Reference
    Rust pamoja-radios reference, docs.rs, install
    TypeScript @pamoja/radios reference, install
    Python pamoja-radios reference, install
    C# Pamoja.Radios reference, install

    MIT

    sx126x
    sx127x
    DutyCycle