SDK reference
This page is the API map to keep open next to your editor: every public method of the Nextwaves SDK 1.0.0, arranged by job. If this is your first pass through the documentation, start with the quickstart and reading tags and come back here. All five packages share one set of concepts; method names follow each language's conventions.
Reader states
Nearly every "when may I call this" rule on this page reduces to one diagram:
The reader only accepts configuration commands while idle. To change configuration mid-inventory, stop first, then change, detailed in reading tags and deduplication.
Creating a reader
| Language | Constructor | Notes |
|---|---|---|
| Python | create_reader(port, baudrate=115200, timeout=0.5, log_level=logging.INFO) | Returns a configured NRNReader; the direct form is NRNReader(port, baudrate, timeout, logger) |
| TypeScript | createNRNReader({ baudrate, timeout, onLog }) | Returns NRNWebSerial; no port parameter since the browser picks the port |
| Go | nrn.NewNRNReader(portName, baudrate) | NewNRNReaderWithTransport accepts any io.ReadWriteCloser with SetReadTimeout and ResetInputBuffer, handy for test doubles |
| Rust | NRNReader::new(port_name, baudrate) | Returns Result<NRNReader> |
| C++ | nrn::NRNReader(port, baudrate = 115200, timeout_ms = 500) | Call open() before use |
Connecting
| Job | Python | TypeScript | Go | Rust | C++ |
|---|---|---|---|---|---|
| Open the port | open() | connect() | opens in the constructor | opens in the constructor | open() |
| Handshake | Connect_Reader_And_Initialize() | connect() | ConnectAndInitialize() | connect_and_initialize() | connect_and_initialize() |
| Close | close() | disconnect() | Close() | closes on drop | close() |
| Port status | uart.is_open() | getReaderInfo().isConnected | errors on the next write | errors on the next write | is_open() |
NRNWebSerial.connect() opens the port and performs the handshake in one call. NRNWebSerial.isSupported() reports whether the browser has the Web Serial API.
Reader identity and abilities
info = reader.Query_Reader_Information()
ability = reader.query_rfid_ability()info carries serial_number, power_on_time_sec, baseband_compile_time, app_version, os_version, and app_compile_time. ability carries min_power_dbm, max_power_dbm, antenna_count, frequencies, and rfid_protocols.
Equivalents: queryReaderInformation() (TypeScript), QueryReaderInformation() and QueryRFIDAbility() (Go), query_reader_information() and query_rfid_ability() (Rust and C++). Query abilities before setting power: the reader declares its own valid range, and the values you set should sit inside it.
Inventory
reader.start_inventory_with_mode(antenna_mask=[1, 2], callback=on_tag)
reader.stop_inventory()
reader.is_inventory_running()| Language | Start | Antenna parameter | Stop |
|---|---|---|---|
| Python | start_inventory_with_mode(antenna_mask, callback) | port list counted from 1 | stop_inventory() |
| TypeScript | startInventory(antennaMask, callback) | port array counted from 1 | stopInventory() |
| Go | StartInventory(antennaMask, callback) | 32-bit mask, built with BuildAntennaMask | StopInventory() |
| Rust | start_inventory(antenna_mask, callback) | 32-bit mask, built with build_antenna_mask | stop_inventory() |
| C++ | start_inventory(antenna_mask, callback, include_tid) | 32-bit mask, built with build_antenna_mask | stop_inventory() |
Python and Web Serial deliver tags through the callback with their built-in read loop; for Go, Rust, and C++, add the receive loop from the appendix when you need continuous inventory.
Tag data
interface TagData {
epc: string;
pc: string;
antenna_id: number;
rssi: number | null;
tid?: string;
phase?: number;
frequency?: number;
}epc: the EPC bank contents as an uppercase hex string.pc: the Protocol Control word in hex, see the glossary.antenna_id: the antenna port that read the tag, counted from 1. Keep this field throughout so every read maps to an area.rssi: signal strength in dBm, already converted from the raw byte by the SDK. Absent when the reader omits the RSSI parameter.tid: the TID bank contents in hex, present only when TID reading was requested.phase: the tag's phase in radians, converted from the raw 0 to 128 value.frequency: the channel frequency in MHz.
Go uses TagData{EPC, PC, AntennaID, RSSI, TID, Phase, Frequency} with optional fields as pointers; Rust and C++ use Option<T> and std::optional<T>. Python returns a dict with exactly the TypeScript interface's keys.
A tag sitting in the read zone produces a notification on every scan round, so before turning reads into business events, apply your deduplication window per reading tags and deduplication.
Power
reader.configure_reader_power({1: 30, 2: 25}, persistence=True)
powers = reader.query_reader_power()query_reader_power returns a port-to-dBm map, for example {1: 30, 2: 25, 3: 30, 4: 30}. persistence=True stores the setting across power cycles. Go, Rust, and C++ pair up as ConfigurePower(powers, persist) / QueryPower() and configure_power / query_power.
Antennas
mask = reader.build_antenna_mask([1, 4, 7, 32]) # 0x80000049
reader.enable_ant(4, save=True)
reader.disable_ant(2, save=True)
reader.query_enabled_ant_mask()
reader.save_antenna_mask(mask)The mask is a 32-bit bitmask with antenna n at bit n - 1. The free functions BuildAntennaMask (Go) and build_antenna_mask (Rust, C++) perform the same conversion. Web Serial converts internally: just pass the port array to startInventory.
RF band, frequency, and baseband
This method group belongs to the Python package. The clean deployment pattern for browser clients: configure the reader once from Python or the vendor tool, save with persist, and let the Web Serial client only run inventory.
| Method | Purpose |
|---|---|
query_rf_band() / set_rf_band(band_code, persist) | Read and set the regional band |
query_working_frequency() | Read the active channel list |
select_profile(profile_id) / get_profile() | Baseband profile, RF_PROFILES holds ids 0, 1, 2 |
configure_baseband(...) / query_baseband_profile() | Session, Q, inventory flag, and profile, see the glossary |
get_session() | The current Gen2 session |
set_filter_settings(repeated_time_ms, rssi_threshold) / query_filter_settings() | The reader-side dedup window and RSSI threshold |
The SDK transmits exactly the configuration you set, so choosing the band and channels legal at the site is the design's responsibility; the final check list lives in the production checklist.
Writing EPCs
The Python package has three writing paths and one verification step:
reader.write_epc_tag(...) # explicit write
reader.write_epc_tag_auto(target_tag_epc=..., new_epc_hex=...)
reader.write_epc_to_target_auto(...) # select a tag, then write
reader.check_write_epc(epc_hex) # read back and comparevalidate_epc_hex(epc_hex) rejects malformed input before a write is attempted. Always read back after writing, and only write once the encoded value and the physical target item are independently verified; the full procedure is in EPC encoding.
GPIO
ConfigureGPO(gpoID, state) and QueryGPI(gpiID) exist in Go; configure_gpo / query_gpi in Rust and C++, for readers with GPIO ports, say to light a lamp or open a barrier. The Python and Web Serial packages will add GPIO methods in a later release; until then, run the GPIO part through a small Go, Rust, or C++ process.
Beeper
reader.set_beeper(BEEPER_MODES["BEEP_AFTER_TAG"])
reader.get_beeper()BEEPER_MODES holds QUIET (0x00), BEEP_AFTER_INVENTORY (0x01), and BEEP_AFTER_TAG (0x02). Beep-per-tag gives instant feedback to whoever holds a handheld reader.
Errors
Python and TypeScript ship a typed exception hierarchy:
from nrn import (
NextwavesSDKError, # the root class
ConnectionError, # opening the port, losing the port
ProtocolError, # invalid data on the wire
ConfigurationError, # invalid power, mask, band
TagOperationError, # write or lock failed
)TypeScript mirrors the structure with the root class NRNWebSerialError and four matching subclasses. Rust returns Result<T, NRNError>, Go returns wrapped error values, and C++ reports through bool returns and empty result structs.
Catch ConnectionError on every reconnect path: a USB reader yanked mid-inventory surfaces there, not in the tag callback.
Logging
reader.set_log_level(logging.DEBUG)TypeScript takes an onLog(level, message) callback in the constructor options, C++ uses set_log_callback. Go uses the standard log package, Rust the log crate facade. Debug-level logging records the raw data of every read, so enable it only while debugging and keep it off in production, where logs may carry product and customer identifiers.
The low-level utilities for building and dissecting data, for tool authors and receive loop writers, live in the NRN reader protocol appendix.
SDK information
NRNReader.get_sdk_info() (Python) and NRNWebSerial.getSDKInfo() (TypeScript) return the SDK's name and version. Log the value at session start, so every support ticket carries the SDK build next to the reader's firmware.
Read next
- Reading tags and deduplication: turning these methods into a complete pipeline.
- Appendix: NRN reader protocol: the frame layer and its utilities.
- RFID glossary for developers: session, Q, TID, and the concepts in the tables above.

