diff --git a/.github/workflows/node-packaging.yml b/.github/workflows/node-packaging.yml new file mode 100644 index 0000000..f8b3ed4 --- /dev/null +++ b/.github/workflows/node-packaging.yml @@ -0,0 +1,217 @@ +name: Node.js Builds +env: + DEBUG: napi:* + ARTIFACT_PATH: rf24-node/rf24.*.node + MACOSX_DEPLOYMENT_TARGET: '10.13' +on: + push: + branches: [main] + tags: ['v*'] + paths: + - 'lib/src/**' + - 'rf24-node/**' + - '!**/*.md' + pull_request: + branches: [main] +jobs: + build: + strategy: + fail-fast: false + matrix: + settings: + - host: macos-latest + target: x86_64-apple-darwin + build: yarn build --target x86_64-apple-darwin + - host: windows-latest + build: yarn build --target x86_64-pc-windows-msvc + target: x86_64-pc-windows-msvc + - host: windows-latest + build: yarn build --target i686-pc-windows-msvc + target: i686-pc-windows-msvc + - host: ubuntu-latest + target: x86_64-unknown-linux-gnu + docker: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian + build: yarn build --target x86_64-unknown-linux-gnu + - host: ubuntu-latest + target: x86_64-unknown-linux-musl + docker: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-alpine + build: yarn build --target x86_64-unknown-linux-musl + - host: macos-latest + target: aarch64-apple-darwin + build: yarn build --target aarch64-apple-darwin + - host: ubuntu-latest + target: aarch64-unknown-linux-gnu + docker: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian-aarch64 + build: yarn build --target aarch64-unknown-linux-gnu + - host: ubuntu-latest + target: armv7-unknown-linux-gnueabihf + setup: | + sudo apt-get update + sudo apt-get install gcc-arm-linux-gnueabihf -y + build: yarn build --target armv7-unknown-linux-gnueabihf + - host: ubuntu-latest + target: armv7-unknown-linux-musleabihf + build: yarn build --target armv7-unknown-linux-musleabihf + - host: ubuntu-latest + target: aarch64-linux-android + build: yarn build --target aarch64-linux-android + - host: ubuntu-latest + target: armv7-linux-androideabi + build: yarn build --target armv7-linux-androideabi + - host: ubuntu-latest + target: aarch64-unknown-linux-musl + docker: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-alpine + build: |- + set -e && + rustup target add aarch64-unknown-linux-musl && + yarn build --target aarch64-unknown-linux-musl + - host: windows-latest + target: aarch64-pc-windows-msvc + build: yarn build --target aarch64-pc-windows-msvc + - host: ubuntu-latest + target: riscv64gc-unknown-linux-gnu + setup: | + sudo apt-get update + sudo apt-get install gcc-riscv64-linux-gnu -y + build: yarn build --target riscv64gc-unknown-linux-gnu + name: stable - ${{ matrix.settings.target }} - node@20 + runs-on: ${{ matrix.settings.host }} + steps: + - uses: actions/checkout@v4 + - name: Setup node + uses: actions/setup-node@v4 + if: ${{ !matrix.settings.docker }} + with: + node-version: 20 + cache: yarn + - name: Install + uses: dtolnay/rust-toolchain@stable + if: ${{ !matrix.settings.docker }} + with: + toolchain: stable + targets: ${{ matrix.settings.target }} + - name: Cache cargo + uses: actions/cache@v4 + with: + path: | + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + .cargo-cache + target/ + key: ${{ matrix.settings.target }}-cargo-${{ matrix.settings.host }} + - uses: goto-bus-stop/setup-zig@v2 + if: ${{ matrix.settings.target == 'armv7-unknown-linux-gnueabihf' || matrix.settings.target == 'armv7-unknown-linux-musleabihf' }} + with: + version: 0.13.0 + - name: Setup toolchain + run: ${{ matrix.settings.setup }} + if: ${{ matrix.settings.setup }} + shell: bash + - name: Setup node x86 + if: matrix.settings.target == 'i686-pc-windows-msvc' + run: yarn config set supportedArchitectures.cpu "ia32" + shell: bash + - name: Install dependencies + run: yarn install + - name: Setup node x86 + uses: actions/setup-node@v4 + if: matrix.settings.target == 'i686-pc-windows-msvc' + with: + node-version: 20 + cache: yarn + architecture: x86 + - name: Build in docker + uses: addnab/docker-run-action@v3 + if: ${{ matrix.settings.docker }} + with: + image: ${{ matrix.settings.docker }} + options: '--user 0:0 -v ${{ github.workspace }}/.cargo-cache/git/db:/usr/local/cargo/git/db -v ${{ github.workspace }}/.cargo/registry/cache:/usr/local/cargo/registry/cache -v ${{ github.workspace }}/.cargo/registry/index:/usr/local/cargo/registry/index -v ${{ github.workspace }}:/build -w /build' + run: ${{ matrix.settings.build }} + - name: Build + run: ${{ matrix.settings.build }} + if: ${{ !matrix.settings.docker }} + shell: bash + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: bindings-${{ matrix.settings.target }} + path: ${{ env.ARTIFACT_PATH }} + if-no-files-found: error + + universal-macOS: + name: Build universal macOS binary + needs: + - build + runs-on: macos-latest + steps: + - uses: actions/checkout@v4 + - name: Setup node + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: yarn + - name: Install dependencies + run: yarn install + - name: Download macOS x64 artifact + uses: actions/download-artifact@v4 + with: + name: bindings-x86_64-apple-darwin + path: rf24-node/artifacts + - name: Download macOS arm64 artifact + uses: actions/download-artifact@v4 + with: + name: bindings-aarch64-apple-darwin + path: rf24-node/artifacts + - name: Combine binaries + run: yarn universal + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: bindings-universal-apple-darwin + path: ${{ env.ARTIFACT_PATH }} + if-no-files-found: error + publish: + name: Publish + runs-on: ubuntu-latest + permissions: + contents: write + id-token: write + needs: + - build + - universal-macOS + steps: + - uses: actions/checkout@v4 + - name: Setup node + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: yarn + - name: Install dependencies + run: yarn install + - name: Download all artifacts + uses: actions/download-artifact@v4 + with: + path: rf24-node/artifacts + - name: Move artifacts + run: yarn artifacts + - name: List packages + run: ls -R ./rf24-node/npm + shell: bash + - name: Publish + run: | + npm config set provenance true + if git log -1 --pretty=%B | grep "^[0-9]\+\.[0-9]\+\.[0-9]\+$"; + then + echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" >> ~/.npmrc + npm publish --access public + elif git log -1 --pretty=%B | grep "^[0-9]\+\.[0-9]\+\.[0-9]\+"; + then + echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" >> ~/.npmrc + npm publish --tag next --access public + else + echo "Not a release, skipping publish" + fi + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.gitignore b/.gitignore index 6b1af17..cd5f6fb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,145 @@ -# Created by https://www.toptal.com/developers/gitignore/api/rust,python -# Edit at https://www.toptal.com/developers/gitignore?templates=rust,python +# Created by https://www.toptal.com/developers/gitignore/api/rust,python,node,yarn +# Edit at https://www.toptal.com/developers/gitignore?templates=rust,python,node,yarn + +### Node ### +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional stylelint cache +.stylelintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# vuepress v2.x temp and cache directory +.temp + +# Docusaurus cache and generated files +.docusaurus + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + +### Node Patch ### +# Serverless Webpack directories +.webpack/ + +# Optional stylelint cache + +# SvelteKit build / generate output +.svelte-kit ### Python ### # Byte-compiled / optimized / DLL files @@ -46,7 +186,6 @@ htmlcov/ .nox/ .coverage .coverage.* -.cache nosetests.xml coverage.xml *.cover @@ -60,7 +199,6 @@ cover/ *.pot # Django stuff: -*.log local_settings.py db.sqlite3 db.sqlite3-journal @@ -124,7 +262,6 @@ celerybeat.pid *.sage.py # Environments -.env .venv env/ venv/ @@ -188,7 +325,24 @@ Cargo.lock # MSVC Windows builds of rustc generate these, which store debugging information *.pdb -# End of https://www.toptal.com/developers/gitignore/api/rust,python +### yarn ### +# https://yarnpkg.com/getting-started/qa#which-files-should-be-gitignored + +.yarn/* +!.yarn/releases +!.yarn/patches +!.yarn/plugins +!.yarn/sdks +!.yarn/versions + +# if you are NOT using Zero-installs, then: +# comment the following lines +# !.yarn/cache + +# and uncomment the following lines +# .pnp.* + +# End of https://www.toptal.com/developers/gitignore/api/rust,python,node,yarn # .vscode settings .vscode/ diff --git a/Cargo.toml b/Cargo.toml index c898417..10a6295 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["lib", "examples", "rf24-py"] +members = ["lib", "examples", "rf24-py", "rf24-node"] default-members = ["lib"] resolver = "2" @@ -10,3 +10,7 @@ homepage = "https://nRF24.github.io/rf24-rs" edition = "2021" rust-version = "1.70" license-file = "LICENSE" + +[profile.release] +lto = true +strip = "symbols" diff --git a/cspell.config.yml b/cspell.config.yml index 743c8fa..988829c 100644 --- a/cspell.config.yml +++ b/cspell.config.yml @@ -1,10 +1,16 @@ version: "0.2" words: + - aarch + - androideabi + - armv + - bindgen - bytearray - Cdev - Doherty - DYNPD + - eabi - fontawesome + - gnueabihf - gpio - gpiochip - inlinehilite @@ -13,11 +19,15 @@ words: - Mbps - milliwatts - mkdocs + - msvc + - musleabihf + - napi - pyclass - pymdownx - pymethods - pymodule - RETR + - riscv - rustc - RXADDR - Spidev diff --git a/package.json b/package.json new file mode 100644 index 0000000..9567963 --- /dev/null +++ b/package.json @@ -0,0 +1,16 @@ +{ + "private": true, + "workspaces": [ + "rf24-node" + ], + "scripts": { + "artifacts": "cd rf24-node && yarn artifacts", + "build": "cd rf24-node && yarn build", + "build:debug": "cd rf24-node && yarn build:debug", + "prepublishOnly": "cd rf24-node && yarn prepublishOnly", + "universal": "cd rf24-node && yarn universal", + "version": "cd rf24-node && yarn version" + }, + "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e", + "version": "0.1.0" +} diff --git a/rf24-node/.cargo/config.toml b/rf24-node/.cargo/config.toml new file mode 100644 index 0000000..0651654 --- /dev/null +++ b/rf24-node/.cargo/config.toml @@ -0,0 +1,5 @@ +[target.aarch64-unknown-linux-musl] +linker = "aarch64-linux-musl-gcc" +rustflags = ["-C", "target-feature=-crt-static"] +[target.x86_64-pc-windows-msvc] +rustflags = ["-C", "target-feature=+crt-static"] \ No newline at end of file diff --git a/rf24-node/.gitignore b/rf24-node/.gitignore new file mode 100644 index 0000000..a2b5be1 --- /dev/null +++ b/rf24-node/.gitignore @@ -0,0 +1,197 @@ +# Created by https://www.toptal.com/developers/gitignore/api/node +# Edit at https://www.toptal.com/developers/gitignore?templates=node + +### Node ### +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# TypeScript v1 declaration files +typings/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.test + +# parcel-bundler cache (https://parceljs.org/) +.cache + +# Next.js build output +.next + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# End of https://www.toptal.com/developers/gitignore/api/node + +# Created by https://www.toptal.com/developers/gitignore/api/macos +# Edit at https://www.toptal.com/developers/gitignore?templates=macos + +### macOS ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### macOS Patch ### +# iCloud generated files +*.icloud + +# End of https://www.toptal.com/developers/gitignore/api/macos + +# Created by https://www.toptal.com/developers/gitignore/api/windows +# Edit at https://www.toptal.com/developers/gitignore?templates=windows + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# End of https://www.toptal.com/developers/gitignore/api/windows + +#Added by cargo + +/target +Cargo.lock + +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/sdks +!.yarn/versions + +*.node diff --git a/rf24-node/.npmignore b/rf24-node/.npmignore new file mode 100644 index 0000000..ec144db --- /dev/null +++ b/rf24-node/.npmignore @@ -0,0 +1,13 @@ +target +Cargo.lock +.cargo +.github +npm +.eslintrc +.prettierignore +rustfmt.toml +yarn.lock +*.node +.yarn +__test__ +renovate.json diff --git a/rf24-node/.yarnrc.yml b/rf24-node/.yarnrc.yml new file mode 100644 index 0000000..3186f3f --- /dev/null +++ b/rf24-node/.yarnrc.yml @@ -0,0 +1 @@ +nodeLinker: node-modules diff --git a/rf24-node/Cargo.toml b/rf24-node/Cargo.toml new file mode 100644 index 0000000..a135875 --- /dev/null +++ b/rf24-node/Cargo.toml @@ -0,0 +1,19 @@ +[package] +edition = "2021" +name = "rf24_rf24" +version = "0.0.0" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +# Default enable napi4 feature, see https://nodejs.org/api/n-api.html#node-api-version-matrix +napi = { version = "2.12.2", default-features = false, features = ["napi4"] } +napi-derive = "2.12.2" + +[build-dependencies] +napi-build = "2.0.1" + +[target.'cfg(target_os = "linux")'.dependencies] +linux-embedded-hal = "0.4.0" +rf24-rs = { path = "../lib" } diff --git a/rf24-node/build.rs b/rf24-node/build.rs new file mode 100644 index 0000000..9fc2367 --- /dev/null +++ b/rf24-node/build.rs @@ -0,0 +1,5 @@ +extern crate napi_build; + +fn main() { + napi_build::setup(); +} diff --git a/rf24-node/index.d.ts b/rf24-node/index.d.ts new file mode 100644 index 0000000..343e5db --- /dev/null +++ b/rf24-node/index.d.ts @@ -0,0 +1,132 @@ +/* tslint:disable */ +/* eslint-disable */ + +/* auto-generated by NAPI-RS */ + +/** The return type for `RF24.getStatusFlags()` */ +export interface StatusFlags { + rxDr: boolean + txDs: boolean + txDf: boolean +} +/** The return type for `RF24.availablePipe()` */ +export interface AvailablePipe { + available: boolean + pipe: number +} +/** + * Power Amplifier level. The units dBm (decibel-milliwatts or dBmW) + * represents a logarithmic signal loss. + */ +export const enum PaLevel { + /** + * | nRF24L01 | Si24R1 with
LNA Enabled | Si24R1 with
LNA Disabled | + * | :-------:|:--------------------------:|:---------------------------:| + * | -18 dBm | -6 dBm | -12 dBm | + */ + MIN = 0, + /** + * | nRF24L01 | Si24R1 with
LNA Enabled | Si24R1 with
LNA Disabled | + * | :-------:|:--------------------------:|:---------------------------:| + * | -12 dBm | 0 dBm | -4 dBm | + */ + LOW = 1, + /** + * | nRF24L01 | Si24R1 with
LNA Enabled | Si24R1 with
LNA Disabled | + * | :-------:|:--------------------------:|:---------------------------:| + * | -6 dBm | 3 dBm | 1 dBm | + */ + HIGH = 2, + /** + * | nRF24L01 | Si24R1 with
LNA Enabled | Si24R1 with
LNA Disabled | + * | :-------:|:--------------------------:|:---------------------------:| + * | 0 dBm | 7 dBm | 4 dBm | + */ + MAX = 3 +} +/** How fast data moves through the air. Units are in bits per second (bps). */ +export const enum DataRate { + /** represents 1 Mbps */ + Mbps1 = 0, + /** represents 2 Mbps */ + Mbps2 = 1, + /** represents 250 Kbps */ + Kbps250 = 2 +} +/** + * The length of a CRC checksum that is used (if any). + * + * Cyclical Redundancy Checking (CRC) is commonly used to ensure data integrity. + */ +export const enum CrcLength { + /** represents no CRC checksum is used */ + DISABLED = 0, + /** represents CRC 8 bit checksum is used */ + BIT8 = 1, + /** represents CRC 16 bit checksum is used */ + BIT16 = 2 +} +/** The possible states of a FIFO. */ +export const enum FifoState { + /** Represent the state of a FIFO when it is full. */ + Full = 0, + /** Represent the state of a FIFO when it is empty. */ + Empty = 1, + /** Represent the state of a FIFO when it is not full but not empty either. */ + Occupied = 2 +} +export type NodeRF24 = RF24 +export declare class RF24 { + constructor(cePin: number, csPin: number, devGpioChip: number, devSpiBus: number, spiSpeed: number) + begin(): void + startListening(): void + stopListening(): void + send(buf: Uint8Array, askNoAck: boolean): boolean + write(buf: Uint8Array, askNoAck: boolean, startTx: boolean): boolean + read(len: number): Buffer + resend(): boolean + rewrite(): void + getLastArc(): number + isPlusVariant(): boolean + testRpd(): boolean + startCarrierWave(level: PaLevel, channel: number): void + stopCarrierWave(): void + setLna(enable: boolean): void + allowAckPayloads(enable: boolean): void + setAutoAck(enable: boolean): void + setAutoAckPipe(enable: boolean, pipe: number): void + allowAskNoAck(enable: boolean): void + writeAckPayload(pipe: number, buf: Uint8Array): boolean + setAutoRetries(delay: number, count: number): void + setChannel(channel: number): void + getChannel(): number + getCrcLength(): CrcLength + setCrcLength(crcLength: CrcLength): void + getDataRate(): DataRate + setDataRate(dataRate: DataRate): void + available(): boolean + availablePipe(): AvailablePipe + /** Use this to discard all 3 layers in the radio's RX FIFO. */ + flushRx(): void + /** Use this to discard all 3 layers in the radio's TX FIFO. */ + flushTx(): void + getFifoState(aboutTx: boolean): FifoState + getPaLevel(): PaLevel + setPaLevel(paLevel: PaLevel): void + setPayloadLength(length: number): void + getPayloadLength(): number + setDynamicPayloads(enable: boolean): void + getDynamicPayloadLength(): number + openRxPipe(pipe: number, address: Uint8Array): void + openTxPipe(address: Uint8Array): void + /** If the given `pipe` number is not in range [0, 5], then this function does nothing. */ + closeRxPipe(pipe: number): void + setAddressLength(length: number): void + getAddressLength(): number + powerDown(): void + powerUp(delay?: number | undefined | null): void + setStatusFlags(rxDr: boolean, txDs: boolean, txDf: boolean): void + clearStatusFlags(rxDr: boolean, txDs: boolean, txDf: boolean): void + update(): void + getStatusFlags(): StatusFlags +} diff --git a/rf24-node/index.js b/rf24-node/index.js new file mode 100644 index 0000000..88e2b44 --- /dev/null +++ b/rf24-node/index.js @@ -0,0 +1,319 @@ +/* tslint:disable */ +/* eslint-disable */ +/* prettier-ignore */ + +/* auto-generated by NAPI-RS */ + +const { existsSync, readFileSync } = require('fs') +const { join } = require('path') + +const { platform, arch } = process + +let nativeBinding = null +let localFileExisted = false +let loadError = null + +function isMusl() { + // For Node 10 + if (!process.report || typeof process.report.getReport !== 'function') { + try { + const lddPath = require('child_process').execSync('which ldd').toString().trim() + return readFileSync(lddPath, 'utf8').includes('musl') + } catch (e) { + return true + } + } else { + const { glibcVersionRuntime } = process.report.getReport().header + return !glibcVersionRuntime + } +} + +switch (platform) { + case 'android': + switch (arch) { + case 'arm64': + localFileExisted = existsSync(join(__dirname, 'rf24.android-arm64.node')) + try { + if (localFileExisted) { + nativeBinding = require('./rf24.android-arm64.node') + } else { + nativeBinding = require('@rf24/rf24-android-arm64') + } + } catch (e) { + loadError = e + } + break + case 'arm': + localFileExisted = existsSync(join(__dirname, 'rf24.android-arm-eabi.node')) + try { + if (localFileExisted) { + nativeBinding = require('./rf24.android-arm-eabi.node') + } else { + nativeBinding = require('@rf24/rf24-android-arm-eabi') + } + } catch (e) { + loadError = e + } + break + default: + throw new Error(`Unsupported architecture on Android ${arch}`) + } + break + case 'win32': + switch (arch) { + case 'x64': + localFileExisted = existsSync( + join(__dirname, 'rf24.win32-x64-msvc.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./rf24.win32-x64-msvc.node') + } else { + nativeBinding = require('@rf24/rf24-win32-x64-msvc') + } + } catch (e) { + loadError = e + } + break + case 'ia32': + localFileExisted = existsSync( + join(__dirname, 'rf24.win32-ia32-msvc.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./rf24.win32-ia32-msvc.node') + } else { + nativeBinding = require('@rf24/rf24-win32-ia32-msvc') + } + } catch (e) { + loadError = e + } + break + case 'arm64': + localFileExisted = existsSync( + join(__dirname, 'rf24.win32-arm64-msvc.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./rf24.win32-arm64-msvc.node') + } else { + nativeBinding = require('@rf24/rf24-win32-arm64-msvc') + } + } catch (e) { + loadError = e + } + break + default: + throw new Error(`Unsupported architecture on Windows: ${arch}`) + } + break + case 'darwin': + localFileExisted = existsSync(join(__dirname, 'rf24.darwin-universal.node')) + try { + if (localFileExisted) { + nativeBinding = require('./rf24.darwin-universal.node') + } else { + nativeBinding = require('@rf24/rf24-darwin-universal') + } + break + } catch {} + switch (arch) { + case 'x64': + localFileExisted = existsSync(join(__dirname, 'rf24.darwin-x64.node')) + try { + if (localFileExisted) { + nativeBinding = require('./rf24.darwin-x64.node') + } else { + nativeBinding = require('@rf24/rf24-darwin-x64') + } + } catch (e) { + loadError = e + } + break + case 'arm64': + localFileExisted = existsSync( + join(__dirname, 'rf24.darwin-arm64.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./rf24.darwin-arm64.node') + } else { + nativeBinding = require('@rf24/rf24-darwin-arm64') + } + } catch (e) { + loadError = e + } + break + default: + throw new Error(`Unsupported architecture on macOS: ${arch}`) + } + break + case 'freebsd': + if (arch !== 'x64') { + throw new Error(`Unsupported architecture on FreeBSD: ${arch}`) + } + localFileExisted = existsSync(join(__dirname, 'rf24.freebsd-x64.node')) + try { + if (localFileExisted) { + nativeBinding = require('./rf24.freebsd-x64.node') + } else { + nativeBinding = require('@rf24/rf24-freebsd-x64') + } + } catch (e) { + loadError = e + } + break + case 'linux': + switch (arch) { + case 'x64': + if (isMusl()) { + localFileExisted = existsSync( + join(__dirname, 'rf24.linux-x64-musl.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./rf24.linux-x64-musl.node') + } else { + nativeBinding = require('@rf24/rf24-linux-x64-musl') + } + } catch (e) { + loadError = e + } + } else { + localFileExisted = existsSync( + join(__dirname, 'rf24.linux-x64-gnu.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./rf24.linux-x64-gnu.node') + } else { + nativeBinding = require('@rf24/rf24-linux-x64-gnu') + } + } catch (e) { + loadError = e + } + } + break + case 'arm64': + if (isMusl()) { + localFileExisted = existsSync( + join(__dirname, 'rf24.linux-arm64-musl.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./rf24.linux-arm64-musl.node') + } else { + nativeBinding = require('@rf24/rf24-linux-arm64-musl') + } + } catch (e) { + loadError = e + } + } else { + localFileExisted = existsSync( + join(__dirname, 'rf24.linux-arm64-gnu.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./rf24.linux-arm64-gnu.node') + } else { + nativeBinding = require('@rf24/rf24-linux-arm64-gnu') + } + } catch (e) { + loadError = e + } + } + break + case 'arm': + if (isMusl()) { + localFileExisted = existsSync( + join(__dirname, 'rf24.linux-arm-musleabihf.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./rf24.linux-arm-musleabihf.node') + } else { + nativeBinding = require('@rf24/rf24-linux-arm-musleabihf') + } + } catch (e) { + loadError = e + } + } else { + localFileExisted = existsSync( + join(__dirname, 'rf24.linux-arm-gnueabihf.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./rf24.linux-arm-gnueabihf.node') + } else { + nativeBinding = require('@rf24/rf24-linux-arm-gnueabihf') + } + } catch (e) { + loadError = e + } + } + break + case 'riscv64': + if (isMusl()) { + localFileExisted = existsSync( + join(__dirname, 'rf24.linux-riscv64-musl.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./rf24.linux-riscv64-musl.node') + } else { + nativeBinding = require('@rf24/rf24-linux-riscv64-musl') + } + } catch (e) { + loadError = e + } + } else { + localFileExisted = existsSync( + join(__dirname, 'rf24.linux-riscv64-gnu.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./rf24.linux-riscv64-gnu.node') + } else { + nativeBinding = require('@rf24/rf24-linux-riscv64-gnu') + } + } catch (e) { + loadError = e + } + } + break + case 's390x': + localFileExisted = existsSync( + join(__dirname, 'rf24.linux-s390x-gnu.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./rf24.linux-s390x-gnu.node') + } else { + nativeBinding = require('@rf24/rf24-linux-s390x-gnu') + } + } catch (e) { + loadError = e + } + break + default: + throw new Error(`Unsupported architecture on Linux: ${arch}`) + } + break + default: + throw new Error(`Unsupported OS: ${platform}, architecture: ${arch}`) +} + +if (!nativeBinding) { + if (loadError) { + throw loadError + } + throw new Error(`Failed to load native binding`) +} + +const { PaLevel, DataRate, CrcLength, FifoState, RF24 } = nativeBinding + +module.exports.PaLevel = PaLevel +module.exports.DataRate = DataRate +module.exports.CrcLength = CrcLength +module.exports.FifoState = FifoState +module.exports.RF24 = RF24 diff --git a/rf24-node/npm/android-arm-eabi/README.md b/rf24-node/npm/android-arm-eabi/README.md new file mode 100644 index 0000000..87134de --- /dev/null +++ b/rf24-node/npm/android-arm-eabi/README.md @@ -0,0 +1,3 @@ +# `@rf24/rf24-android-arm-eabi` + +This is the **armv7-linux-androideabi** binary for `@rf24/rf24` diff --git a/rf24-node/npm/android-arm-eabi/package.json b/rf24-node/npm/android-arm-eabi/package.json new file mode 100644 index 0000000..e3051e2 --- /dev/null +++ b/rf24-node/npm/android-arm-eabi/package.json @@ -0,0 +1,18 @@ +{ + "name": "@rf24/rf24-android-arm-eabi", + "version": "0.1.0", + "os": [ + "android" + ], + "cpu": [ + "arm" + ], + "main": "rf24.android-arm-eabi.node", + "files": [ + "rf24.android-arm-eabi.node" + ], + "license": "MIT", + "engines": { + "node": ">= 10" + } +} \ No newline at end of file diff --git a/rf24-node/npm/android-arm64/README.md b/rf24-node/npm/android-arm64/README.md new file mode 100644 index 0000000..27eb5bb --- /dev/null +++ b/rf24-node/npm/android-arm64/README.md @@ -0,0 +1,3 @@ +# `@rf24/rf24-android-arm64` + +This is the **aarch64-linux-android** binary for `@rf24/rf24` diff --git a/rf24-node/npm/android-arm64/package.json b/rf24-node/npm/android-arm64/package.json new file mode 100644 index 0000000..1849106 --- /dev/null +++ b/rf24-node/npm/android-arm64/package.json @@ -0,0 +1,18 @@ +{ + "name": "@rf24/rf24-android-arm64", + "version": "0.1.0", + "os": [ + "android" + ], + "cpu": [ + "arm64" + ], + "main": "rf24.android-arm64.node", + "files": [ + "rf24.android-arm64.node" + ], + "license": "MIT", + "engines": { + "node": ">= 10" + } +} \ No newline at end of file diff --git a/rf24-node/npm/darwin-arm64/README.md b/rf24-node/npm/darwin-arm64/README.md new file mode 100644 index 0000000..05d31cd --- /dev/null +++ b/rf24-node/npm/darwin-arm64/README.md @@ -0,0 +1,3 @@ +# `@rf24/rf24-darwin-arm64` + +This is the **aarch64-apple-darwin** binary for `@rf24/rf24` diff --git a/rf24-node/npm/darwin-arm64/package.json b/rf24-node/npm/darwin-arm64/package.json new file mode 100644 index 0000000..083932e --- /dev/null +++ b/rf24-node/npm/darwin-arm64/package.json @@ -0,0 +1,18 @@ +{ + "name": "@rf24/rf24-darwin-arm64", + "version": "0.1.0", + "os": [ + "darwin" + ], + "cpu": [ + "arm64" + ], + "main": "rf24.darwin-arm64.node", + "files": [ + "rf24.darwin-arm64.node" + ], + "license": "MIT", + "engines": { + "node": ">= 10" + } +} \ No newline at end of file diff --git a/rf24-node/npm/darwin-universal/README.md b/rf24-node/npm/darwin-universal/README.md new file mode 100644 index 0000000..a6a9f15 --- /dev/null +++ b/rf24-node/npm/darwin-universal/README.md @@ -0,0 +1,3 @@ +# `@rf24/rf24-darwin-universal` + +This is the **universal-apple-darwin** binary for `@rf24/rf24` diff --git a/rf24-node/npm/darwin-universal/package.json b/rf24-node/npm/darwin-universal/package.json new file mode 100644 index 0000000..6a73fec --- /dev/null +++ b/rf24-node/npm/darwin-universal/package.json @@ -0,0 +1,15 @@ +{ + "name": "@rf24/rf24-darwin-universal", + "version": "0.1.0", + "os": [ + "darwin" + ], + "main": "rf24.darwin-universal.node", + "files": [ + "rf24.darwin-universal.node" + ], + "license": "MIT", + "engines": { + "node": ">= 10" + } +} \ No newline at end of file diff --git a/rf24-node/npm/darwin-x64/README.md b/rf24-node/npm/darwin-x64/README.md new file mode 100644 index 0000000..5c71d9f --- /dev/null +++ b/rf24-node/npm/darwin-x64/README.md @@ -0,0 +1,3 @@ +# `@rf24/rf24-darwin-x64` + +This is the **x86_64-apple-darwin** binary for `@rf24/rf24` diff --git a/rf24-node/npm/darwin-x64/package.json b/rf24-node/npm/darwin-x64/package.json new file mode 100644 index 0000000..ccfc9e9 --- /dev/null +++ b/rf24-node/npm/darwin-x64/package.json @@ -0,0 +1,18 @@ +{ + "name": "@rf24/rf24-darwin-x64", + "version": "0.1.0", + "os": [ + "darwin" + ], + "cpu": [ + "x64" + ], + "main": "rf24.darwin-x64.node", + "files": [ + "rf24.darwin-x64.node" + ], + "license": "MIT", + "engines": { + "node": ">= 10" + } +} \ No newline at end of file diff --git a/rf24-node/npm/linux-arm-gnueabihf/README.md b/rf24-node/npm/linux-arm-gnueabihf/README.md new file mode 100644 index 0000000..a47c6dd --- /dev/null +++ b/rf24-node/npm/linux-arm-gnueabihf/README.md @@ -0,0 +1,3 @@ +# `@rf24/rf24-linux-arm-gnueabihf` + +This is the **armv7-unknown-linux-gnueabihf** binary for `@rf24/rf24` diff --git a/rf24-node/npm/linux-arm-gnueabihf/package.json b/rf24-node/npm/linux-arm-gnueabihf/package.json new file mode 100644 index 0000000..09870c8 --- /dev/null +++ b/rf24-node/npm/linux-arm-gnueabihf/package.json @@ -0,0 +1,18 @@ +{ + "name": "@rf24/rf24-linux-arm-gnueabihf", + "version": "0.1.0", + "os": [ + "linux" + ], + "cpu": [ + "arm" + ], + "main": "rf24.linux-arm-gnueabihf.node", + "files": [ + "rf24.linux-arm-gnueabihf.node" + ], + "license": "MIT", + "engines": { + "node": ">= 10" + } +} \ No newline at end of file diff --git a/rf24-node/npm/linux-arm-musleabihf/README.md b/rf24-node/npm/linux-arm-musleabihf/README.md new file mode 100644 index 0000000..bf6e814 --- /dev/null +++ b/rf24-node/npm/linux-arm-musleabihf/README.md @@ -0,0 +1,3 @@ +# `@rf24/rf24-linux-arm-musleabihf` + +This is the **armv7-unknown-linux-musleabihf** binary for `@rf24/rf24` diff --git a/rf24-node/npm/linux-arm-musleabihf/package.json b/rf24-node/npm/linux-arm-musleabihf/package.json new file mode 100644 index 0000000..9fd4f1b --- /dev/null +++ b/rf24-node/npm/linux-arm-musleabihf/package.json @@ -0,0 +1,18 @@ +{ + "name": "@rf24/rf24-linux-arm-musleabihf", + "version": "0.1.0", + "os": [ + "linux" + ], + "cpu": [ + "arm" + ], + "main": "rf24.linux-arm-musleabihf.node", + "files": [ + "rf24.linux-arm-musleabihf.node" + ], + "license": "MIT", + "engines": { + "node": ">= 10" + } +} \ No newline at end of file diff --git a/rf24-node/npm/linux-arm64-gnu/README.md b/rf24-node/npm/linux-arm64-gnu/README.md new file mode 100644 index 0000000..b7bb154 --- /dev/null +++ b/rf24-node/npm/linux-arm64-gnu/README.md @@ -0,0 +1,3 @@ +# `@rf24/rf24-linux-arm64-gnu` + +This is the **aarch64-unknown-linux-gnu** binary for `@rf24/rf24` diff --git a/rf24-node/npm/linux-arm64-gnu/package.json b/rf24-node/npm/linux-arm64-gnu/package.json new file mode 100644 index 0000000..9f044ce --- /dev/null +++ b/rf24-node/npm/linux-arm64-gnu/package.json @@ -0,0 +1,21 @@ +{ + "name": "@rf24/rf24-linux-arm64-gnu", + "version": "0.1.0", + "os": [ + "linux" + ], + "cpu": [ + "arm64" + ], + "main": "rf24.linux-arm64-gnu.node", + "files": [ + "rf24.linux-arm64-gnu.node" + ], + "license": "MIT", + "engines": { + "node": ">= 10" + }, + "libc": [ + "glibc" + ] +} \ No newline at end of file diff --git a/rf24-node/npm/linux-arm64-musl/README.md b/rf24-node/npm/linux-arm64-musl/README.md new file mode 100644 index 0000000..68400d6 --- /dev/null +++ b/rf24-node/npm/linux-arm64-musl/README.md @@ -0,0 +1,3 @@ +# `@rf24/rf24-linux-arm64-musl` + +This is the **aarch64-unknown-linux-musl** binary for `@rf24/rf24` diff --git a/rf24-node/npm/linux-arm64-musl/package.json b/rf24-node/npm/linux-arm64-musl/package.json new file mode 100644 index 0000000..c1f066a --- /dev/null +++ b/rf24-node/npm/linux-arm64-musl/package.json @@ -0,0 +1,21 @@ +{ + "name": "@rf24/rf24-linux-arm64-musl", + "version": "0.1.0", + "os": [ + "linux" + ], + "cpu": [ + "arm64" + ], + "main": "rf24.linux-arm64-musl.node", + "files": [ + "rf24.linux-arm64-musl.node" + ], + "license": "MIT", + "engines": { + "node": ">= 10" + }, + "libc": [ + "musl" + ] +} \ No newline at end of file diff --git a/rf24-node/npm/linux-riscv64-gnu/README.md b/rf24-node/npm/linux-riscv64-gnu/README.md new file mode 100644 index 0000000..4c3a47d --- /dev/null +++ b/rf24-node/npm/linux-riscv64-gnu/README.md @@ -0,0 +1,3 @@ +# `@rf24/rf24-linux-riscv64-gnu` + +This is the **riscv64gc-unknown-linux-gnu** binary for `@rf24/rf24` diff --git a/rf24-node/npm/linux-riscv64-gnu/package.json b/rf24-node/npm/linux-riscv64-gnu/package.json new file mode 100644 index 0000000..cc87a60 --- /dev/null +++ b/rf24-node/npm/linux-riscv64-gnu/package.json @@ -0,0 +1,21 @@ +{ + "name": "@rf24/rf24-linux-riscv64-gnu", + "version": "0.1.0", + "os": [ + "linux" + ], + "cpu": [ + "riscv64" + ], + "main": "rf24.linux-riscv64-gnu.node", + "files": [ + "rf24.linux-riscv64-gnu.node" + ], + "license": "MIT", + "engines": { + "node": ">= 10" + }, + "libc": [ + "glibc" + ] +} \ No newline at end of file diff --git a/rf24-node/npm/linux-x64-gnu/README.md b/rf24-node/npm/linux-x64-gnu/README.md new file mode 100644 index 0000000..98d2d6d --- /dev/null +++ b/rf24-node/npm/linux-x64-gnu/README.md @@ -0,0 +1,3 @@ +# `@rf24/rf24-linux-x64-gnu` + +This is the **x86_64-unknown-linux-gnu** binary for `@rf24/rf24` diff --git a/rf24-node/npm/linux-x64-gnu/package.json b/rf24-node/npm/linux-x64-gnu/package.json new file mode 100644 index 0000000..5f49ddc --- /dev/null +++ b/rf24-node/npm/linux-x64-gnu/package.json @@ -0,0 +1,21 @@ +{ + "name": "@rf24/rf24-linux-x64-gnu", + "version": "0.1.0", + "os": [ + "linux" + ], + "cpu": [ + "x64" + ], + "main": "rf24.linux-x64-gnu.node", + "files": [ + "rf24.linux-x64-gnu.node" + ], + "license": "MIT", + "engines": { + "node": ">= 10" + }, + "libc": [ + "glibc" + ] +} \ No newline at end of file diff --git a/rf24-node/npm/linux-x64-musl/README.md b/rf24-node/npm/linux-x64-musl/README.md new file mode 100644 index 0000000..a8e0c9d --- /dev/null +++ b/rf24-node/npm/linux-x64-musl/README.md @@ -0,0 +1,3 @@ +# `@rf24/rf24-linux-x64-musl` + +This is the **x86_64-unknown-linux-musl** binary for `@rf24/rf24` diff --git a/rf24-node/npm/linux-x64-musl/package.json b/rf24-node/npm/linux-x64-musl/package.json new file mode 100644 index 0000000..b8fc6e6 --- /dev/null +++ b/rf24-node/npm/linux-x64-musl/package.json @@ -0,0 +1,21 @@ +{ + "name": "@rf24/rf24-linux-x64-musl", + "version": "0.1.0", + "os": [ + "linux" + ], + "cpu": [ + "x64" + ], + "main": "rf24.linux-x64-musl.node", + "files": [ + "rf24.linux-x64-musl.node" + ], + "license": "MIT", + "engines": { + "node": ">= 10" + }, + "libc": [ + "musl" + ] +} \ No newline at end of file diff --git a/rf24-node/npm/win32-arm64-msvc/README.md b/rf24-node/npm/win32-arm64-msvc/README.md new file mode 100644 index 0000000..a6252c5 --- /dev/null +++ b/rf24-node/npm/win32-arm64-msvc/README.md @@ -0,0 +1,3 @@ +# `@rf24/rf24-win32-arm64-msvc` + +This is the **aarch64-pc-windows-msvc** binary for `@rf24/rf24` diff --git a/rf24-node/npm/win32-arm64-msvc/package.json b/rf24-node/npm/win32-arm64-msvc/package.json new file mode 100644 index 0000000..6dcc0ca --- /dev/null +++ b/rf24-node/npm/win32-arm64-msvc/package.json @@ -0,0 +1,18 @@ +{ + "name": "@rf24/rf24-win32-arm64-msvc", + "version": "0.1.0", + "os": [ + "win32" + ], + "cpu": [ + "arm64" + ], + "main": "rf24.win32-arm64-msvc.node", + "files": [ + "rf24.win32-arm64-msvc.node" + ], + "license": "MIT", + "engines": { + "node": ">= 10" + } +} \ No newline at end of file diff --git a/rf24-node/npm/win32-ia32-msvc/README.md b/rf24-node/npm/win32-ia32-msvc/README.md new file mode 100644 index 0000000..ed5b6b6 --- /dev/null +++ b/rf24-node/npm/win32-ia32-msvc/README.md @@ -0,0 +1,3 @@ +# `@rf24/rf24-win32-ia32-msvc` + +This is the **i686-pc-windows-msvc** binary for `@rf24/rf24` diff --git a/rf24-node/npm/win32-ia32-msvc/package.json b/rf24-node/npm/win32-ia32-msvc/package.json new file mode 100644 index 0000000..0c0da04 --- /dev/null +++ b/rf24-node/npm/win32-ia32-msvc/package.json @@ -0,0 +1,18 @@ +{ + "name": "@rf24/rf24-win32-ia32-msvc", + "version": "0.1.0", + "os": [ + "win32" + ], + "cpu": [ + "ia32" + ], + "main": "rf24.win32-ia32-msvc.node", + "files": [ + "rf24.win32-ia32-msvc.node" + ], + "license": "MIT", + "engines": { + "node": ">= 10" + } +} \ No newline at end of file diff --git a/rf24-node/npm/win32-x64-msvc/README.md b/rf24-node/npm/win32-x64-msvc/README.md new file mode 100644 index 0000000..1b6768f --- /dev/null +++ b/rf24-node/npm/win32-x64-msvc/README.md @@ -0,0 +1,3 @@ +# `@rf24/rf24-win32-x64-msvc` + +This is the **x86_64-pc-windows-msvc** binary for `@rf24/rf24` diff --git a/rf24-node/npm/win32-x64-msvc/package.json b/rf24-node/npm/win32-x64-msvc/package.json new file mode 100644 index 0000000..5bcea6a --- /dev/null +++ b/rf24-node/npm/win32-x64-msvc/package.json @@ -0,0 +1,18 @@ +{ + "name": "@rf24/rf24-win32-x64-msvc", + "version": "0.1.0", + "os": [ + "win32" + ], + "cpu": [ + "x64" + ], + "main": "rf24.win32-x64-msvc.node", + "files": [ + "rf24.win32-x64-msvc.node" + ], + "license": "MIT", + "engines": { + "node": ">= 10" + } +} \ No newline at end of file diff --git a/rf24-node/package.json b/rf24-node/package.json new file mode 100644 index 0000000..069c5f2 --- /dev/null +++ b/rf24-node/package.json @@ -0,0 +1,46 @@ +{ + "name": "@rf24/rf24", + "version": "0.1.0", + "main": "index.js", + "types": "index.d.ts", + "napi": { + "name": "rf24", + "triples": { + "additional": [ + "aarch64-apple-darwin", + "aarch64-linux-android", + "aarch64-unknown-linux-gnu", + "aarch64-unknown-linux-musl", + "aarch64-pc-windows-msvc", + "armv7-unknown-linux-gnueabihf", + "armv7-unknown-linux-musleabihf", + "x86_64-unknown-linux-musl", + "x86_64-unknown-freebsd", + "i686-pc-windows-msvc", + "armv7-linux-androideabi", + "universal-apple-darwin", + "riscv64gc-unknown-linux-gnu" + ] + } + }, + "license": "MIT", + "devDependencies": { + "@napi-rs/cli": "^2.18.4", + "@types/node": "^22.7.5" + }, + "ava": { + "timeout": "3m" + }, + "engines": { + "node": ">= 10" + }, + "scripts": { + "artifacts": "napi artifacts", + "build": "napi build --platform --release", + "build:debug": "napi build --platform", + "prepublishOnly": "napi prepublish -t npm", + "universal": "napi universal", + "version": "napi version" + }, + "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e" +} diff --git a/rf24-node/src/enums.rs b/rf24-node/src/enums.rs new file mode 100644 index 0000000..a9e3522 --- /dev/null +++ b/rf24-node/src/enums.rs @@ -0,0 +1,152 @@ +#[cfg(target_os = "linux")] +use rf24_rs::{CrcLength, DataRate, FifoState, PaLevel}; + +/// The return type for `RF24.getStatusFlags()` +#[napi(object)] +pub struct StatusFlags { + pub rx_dr: bool, + pub tx_ds: bool, + pub tx_df: bool, +} + +/// The return type for `RF24.availablePipe()` +#[napi(object)] +pub struct AvailablePipe { + pub available: bool, + pub pipe: u8, +} + +/// Power Amplifier level. The units dBm (decibel-milliwatts or dBmW) +/// represents a logarithmic signal loss. +#[napi(js_name = "PaLevel")] +#[derive(Debug, PartialEq)] +pub enum NodePaLevel { + /// | nRF24L01 | Si24R1 with
LNA Enabled | Si24R1 with
LNA Disabled | + /// | :-------:|:--------------------------:|:---------------------------:| + /// | -18 dBm | -6 dBm | -12 dBm | + MIN, + /// | nRF24L01 | Si24R1 with
LNA Enabled | Si24R1 with
LNA Disabled | + /// | :-------:|:--------------------------:|:---------------------------:| + /// | -12 dBm | 0 dBm | -4 dBm | + LOW, + /// | nRF24L01 | Si24R1 with
LNA Enabled | Si24R1 with
LNA Disabled | + /// | :-------:|:--------------------------:|:---------------------------:| + /// | -6 dBm | 3 dBm | 1 dBm | + HIGH, + /// | nRF24L01 | Si24R1 with
LNA Enabled | Si24R1 with
LNA Disabled | + /// | :-------:|:--------------------------:|:---------------------------:| + /// | 0 dBm | 7 dBm | 4 dBm | + MAX, +} + +#[cfg(target_os = "linux")] +impl NodePaLevel { + pub fn into_inner(self) -> PaLevel { + match self { + NodePaLevel::MIN => PaLevel::MIN, + NodePaLevel::LOW => PaLevel::LOW, + NodePaLevel::HIGH => PaLevel::HIGH, + NodePaLevel::MAX => PaLevel::MAX, + } + } + pub fn from_inner(other: PaLevel) -> NodePaLevel { + match other { + PaLevel::MIN => NodePaLevel::MIN, + PaLevel::LOW => NodePaLevel::LOW, + PaLevel::HIGH => NodePaLevel::HIGH, + PaLevel::MAX => NodePaLevel::MAX, + } + } +} + +/// How fast data moves through the air. Units are in bits per second (bps). +#[napi(js_name = "DataRate")] +#[derive(Debug, PartialEq)] +pub enum NodeDataRate { + /// represents 1 Mbps + Mbps1, + /// represents 2 Mbps + Mbps2, + /// represents 250 Kbps + Kbps250, +} + +#[cfg(target_os = "linux")] +impl NodeDataRate { + pub fn into_inner(self) -> DataRate { + match self { + NodeDataRate::Mbps1 => DataRate::Mbps1, + NodeDataRate::Mbps2 => DataRate::Mbps2, + NodeDataRate::Kbps250 => DataRate::Kbps250, + } + } + pub fn from_inner(other: DataRate) -> NodeDataRate { + match other { + DataRate::Mbps1 => NodeDataRate::Mbps1, + DataRate::Mbps2 => NodeDataRate::Mbps2, + DataRate::Kbps250 => NodeDataRate::Kbps250, + } + } +} + +/// The length of a CRC checksum that is used (if any). +/// +/// Cyclical Redundancy Checking (CRC) is commonly used to ensure data integrity. +#[napi(js_name = "CrcLength")] +#[derive(Debug, PartialEq)] +pub enum NodeCrcLength { + /// represents no CRC checksum is used + DISABLED, + /// represents CRC 8 bit checksum is used + BIT8, + /// represents CRC 16 bit checksum is used + BIT16, +} + +#[cfg(target_os = "linux")] +impl NodeCrcLength { + pub fn into_inner(self) -> CrcLength { + match self { + NodeCrcLength::DISABLED => CrcLength::DISABLED, + NodeCrcLength::BIT8 => CrcLength::BIT8, + NodeCrcLength::BIT16 => CrcLength::BIT16, + } + } + pub fn from_inner(other: CrcLength) -> NodeCrcLength { + match other { + CrcLength::DISABLED => NodeCrcLength::DISABLED, + CrcLength::BIT8 => NodeCrcLength::BIT8, + CrcLength::BIT16 => NodeCrcLength::BIT16, + } + } +} + +/// The possible states of a FIFO. +#[napi(js_name = "FifoState")] +#[derive(Debug, PartialEq)] +pub enum NodeFifoState { + /// Represent the state of a FIFO when it is full. + Full, + /// Represent the state of a FIFO when it is empty. + Empty, + /// Represent the state of a FIFO when it is not full but not empty either. + Occupied, +} + +#[cfg(target_os = "linux")] +impl NodeFifoState { + pub fn into_inner(self) -> FifoState { + match self { + NodeFifoState::Full => FifoState::Full, + NodeFifoState::Empty => FifoState::Empty, + NodeFifoState::Occupied => FifoState::Occupied, + } + } + pub fn from_inner(other: FifoState) -> NodeFifoState { + match other { + FifoState::Full => NodeFifoState::Full, + FifoState::Empty => NodeFifoState::Empty, + FifoState::Occupied => NodeFifoState::Occupied, + } + } +} diff --git a/rf24-node/src/lib.rs b/rf24-node/src/lib.rs new file mode 100644 index 0000000..1947909 --- /dev/null +++ b/rf24-node/src/lib.rs @@ -0,0 +1,6 @@ +mod enums; +#[cfg(target_os = "linux")] +mod radio; + +#[macro_use] +extern crate napi_derive; diff --git a/rf24-node/src/radio.rs b/rf24-node/src/radio.rs new file mode 100644 index 0000000..122e1aa --- /dev/null +++ b/rf24-node/src/radio.rs @@ -0,0 +1,454 @@ +#![cfg(target_os = "linux")] + +use crate::enums::{ + AvailablePipe, NodeCrcLength, NodeDataRate, NodeFifoState, NodePaLevel, StatusFlags, +}; +use linux_embedded_hal::{ + gpio_cdev::{chips, LineRequestFlags}, + spidev::{SpiModeFlags, SpidevOptions}, + CdevPin, Delay, SpidevDevice, +}; +use napi::{bindgen_prelude::Buffer, Error, Result, Status}; + +use rf24_rs::radio::{prelude::*, RF24}; + +#[napi(js_name = "RF24")] +pub struct NodeRF24 { + inner: RF24, + read_buf: [u8; 32], +} + +#[napi] +impl NodeRF24 { + #[napi(constructor)] + pub fn new( + ce_pin: u32, + cs_pin: u8, + dev_gpio_chip: u8, + dev_spi_bus: u8, + spi_speed: u32, + ) -> Result { + // get the desired "/dev/gpiochip{dev_gpio_chip}" + let mut dev_gpio = chips() + .map_err(|_| { + Error::new( + Status::GenericFailure, + "Failed to get list of GPIO chips for the system", + ) + })? + .find(|chip| { + if let Ok(chip) = chip { + if chip + .path() + .to_string_lossy() + .ends_with(&dev_gpio_chip.to_string()) + { + return true; + } + } + false + }) + .ok_or(Error::new( + Status::InvalidArg, + format!("Could not find specified dev/gpiochip{dev_gpio_chip} for this system."), + ))? + .map_err(|e| { + Error::new( + Status::InvalidArg, + format!("Could not open GPIO chip dev/gpiochip{dev_gpio_chip}: {e:?}"), + ) + })?; + let ce_line = dev_gpio.get_line(ce_pin).map_err(|e| { + Error::new( + Status::InvalidArg, + format!("GPIO{ce_pin} is unavailable: {e:?}"), + ) + })?; + let ce_line_handle = ce_line + .request(LineRequestFlags::OUTPUT, 0, "rf24-rs") + .map_err(|e| { + Error::new( + Status::InvalidArg, + format!("GPIO{ce_pin} is already in use: {e:?}"), + ) + })?; + let ce_pin = CdevPin::new(ce_line_handle) + .map_err(|e| Error::new(Status::GenericFailure, format!("{e:?}")))?; + + let mut spi = + SpidevDevice::open(format!("/dev/spidev{dev_spi_bus}.{cs_pin}")).map_err(|_| { + Error::new(Status::InvalidArg, format!( + "SPI bus {dev_spi_bus} with CS pin option {cs_pin} is not available in this system" + ) + ) + })?; + let config = SpidevOptions::new() + .max_speed_hz(spi_speed) + .mode(SpiModeFlags::SPI_MODE_0) + .bits_per_word(8) + .build(); + spi.configure(&config) + .map_err(|e| Error::new(Status::GenericFailure, format!("{e:?}")))?; + + Ok(Self { + inner: RF24::new(ce_pin, spi, Delay), + read_buf: [0u8; 32], + }) + } + + #[napi] + pub fn begin(&mut self) -> Result<()> { + self.inner + .init() + .map_err(|e| Error::new(Status::GenericFailure, format!("{e:?}"))) + } + + #[napi] + pub fn start_listening(&mut self) -> Result<()> { + self.inner + .start_listening() + .map_err(|e| Error::new(Status::GenericFailure, format!("{e:?}"))) + } + + #[napi] + pub fn stop_listening(&mut self) -> Result<()> { + self.inner + .stop_listening() + .map_err(|e| Error::new(Status::GenericFailure, format!("{e:?}"))) + } + + #[napi] + pub fn send(&mut self, buf: &[u8], ask_no_ack: bool) -> Result { + self.inner + .send(buf, ask_no_ack) + .map_err(|e| Error::new(Status::GenericFailure, format!("{e:?}"))) + } + + #[napi] + pub fn write(&mut self, buf: &[u8], ask_no_ack: bool, start_tx: bool) -> Result { + self.inner + .write(buf, ask_no_ack, start_tx) + .map_err(|e| Error::new(Status::GenericFailure, format!("{e:?}"))) + } + + #[napi] + pub fn read(&mut self, len: u8) -> Result { + self.inner + .read(&mut self.read_buf, len) + .map_err(|e| Error::new(Status::GenericFailure, format!("{e:?}")))?; + Ok(Buffer::from(&self.read_buf[0..len as usize])) + } + + #[napi] + pub fn resend(&mut self) -> Result { + self.inner + .resend() + .map_err(|e| Error::new(Status::GenericFailure, format!("{e:?}"))) + } + + #[napi] + pub fn rewrite(&mut self) -> Result<()> { + self.inner + .rewrite() + .map_err(|e| Error::new(Status::GenericFailure, format!("{e:?}"))) + } + + #[napi] + pub fn get_last_arc(&mut self) -> Result { + self.inner + .get_last_arc() + .map_err(|e| Error::new(Status::GenericFailure, format!("{e:?}"))) + } + + #[napi] + pub fn is_plus_variant(&self) -> bool { + self.inner.is_plus_variant() + } + + #[napi] + pub fn test_rpd(&mut self) -> Result { + self.inner + .test_rpd() + .map_err(|e| Error::new(Status::GenericFailure, format!("{e:?}"))) + } + + #[napi] + pub fn start_carrier_wave(&mut self, level: NodePaLevel, channel: u8) -> Result<()> { + self.inner + .start_carrier_wave(level.into_inner(), channel) + .map_err(|e| Error::new(Status::GenericFailure, format!("{e:?}"))) + } + + #[napi] + pub fn stop_carrier_wave(&mut self) -> Result<()> { + self.inner + .stop_carrier_wave() + .map_err(|e| Error::new(Status::GenericFailure, format!("{e:?}"))) + } + + #[napi] + pub fn set_lna(&mut self, enable: bool) -> Result<()> { + self.inner + .set_lna(enable) + .map_err(|e| Error::new(Status::GenericFailure, format!("{e:?}"))) + } + + #[napi] + pub fn allow_ack_payloads(&mut self, enable: bool) -> Result<()> { + self.inner + .allow_ack_payloads(enable) + .map_err(|e| Error::new(Status::GenericFailure, format!("{e:?}"))) + } + + #[napi] + pub fn set_auto_ack(&mut self, enable: bool) -> Result<()> { + self.inner + .set_auto_ack(enable) + .map_err(|e| Error::new(Status::GenericFailure, format!("{e:?}"))) + } + + #[napi] + pub fn set_auto_ack_pipe(&mut self, enable: bool, pipe: u8) -> Result<()> { + self.inner + .set_auto_ack_pipe(enable, pipe) + .map_err(|e| Error::new(Status::GenericFailure, format!("{e:?}"))) + } + + #[napi] + pub fn allow_ask_no_ack(&mut self, enable: bool) -> Result<()> { + self.inner + .allow_ask_no_ack(enable) + .map_err(|e| Error::new(Status::GenericFailure, format!("{e:?}"))) + } + + #[napi] + pub fn write_ack_payload(&mut self, pipe: u8, buf: &[u8]) -> Result { + self.inner + .write_ack_payload(pipe, buf) + .map_err(|e| Error::new(Status::GenericFailure, format!("{e:?}"))) + } + + #[napi] + pub fn set_auto_retries(&mut self, delay: u8, count: u8) -> Result<()> { + self.inner + .set_auto_retries(delay, count) + .map_err(|e| Error::new(Status::GenericFailure, format!("{e:?}"))) + } + + #[napi] + pub fn set_channel(&mut self, channel: u8) -> Result<()> { + self.inner + .set_channel(channel) + .map_err(|e| Error::new(Status::GenericFailure, format!("{e:?}"))) + } + + #[napi] + pub fn get_channel(&mut self) -> Result { + self.inner + .get_channel() + .map_err(|e| Error::new(Status::GenericFailure, format!("{e:?}"))) + } + + #[napi] + pub fn get_crc_length(&mut self) -> Result { + self.inner + .get_crc_length() + .map_err(|e| Error::new(Status::GenericFailure, format!("{e:?}"))) + .map(|e| NodeCrcLength::from_inner(e)) + } + + #[napi] + pub fn set_crc_length(&mut self, crc_length: NodeCrcLength) -> Result<()> { + self.inner + .set_crc_length(crc_length.into_inner()) + .map_err(|e| Error::new(Status::GenericFailure, format!("{e:?}"))) + } + + #[napi] + pub fn get_data_rate(&mut self) -> Result { + self.inner + .get_data_rate() + .map_err(|e| Error::new(Status::GenericFailure, format!("{e:?}"))) + .map(|e| NodeDataRate::from_inner(e)) + } + + #[napi] + pub fn set_data_rate(&mut self, data_rate: NodeDataRate) -> Result<()> { + self.inner + .set_data_rate(data_rate.into_inner()) + .map_err(|e| Error::new(Status::GenericFailure, format!("{e:?}"))) + } + + #[napi] + pub fn available(&mut self) -> Result { + self.inner + .available() + .map_err(|e| Error::new(Status::GenericFailure, format!("{e:?}"))) + } + + #[napi] + pub fn available_pipe(&mut self) -> Result { + let mut pipe = Some(0u8); + let result = self + .inner + .available_pipe(&mut pipe) + .map_err(|e| Error::new(Status::GenericFailure, format!("{e:?}")))?; + Ok(AvailablePipe { + available: result, + pipe: pipe.expect("`pipe` should be a number"), + }) + } + + /// Use this to discard all 3 layers in the radio's RX FIFO. + #[napi] + pub fn flush_rx(&mut self) -> Result<()> { + self.inner + .flush_rx() + .map_err(|e| Error::new(Status::GenericFailure, format!("{e:?}"))) + } + + /// Use this to discard all 3 layers in the radio's TX FIFO. + #[napi] + pub fn flush_tx(&mut self) -> Result<()> { + self.inner + .flush_tx() + .map_err(|e| Error::new(Status::GenericFailure, format!("{e:?}"))) + } + + #[napi] + pub fn get_fifo_state(&mut self, about_tx: bool) -> Result { + self.inner + .get_fifo_state(about_tx) + .map_err(|e| Error::new(Status::GenericFailure, format!("{e:?}"))) + .map(|e| NodeFifoState::from_inner(e)) + } + + #[napi] + pub fn get_pa_level(&mut self) -> Result { + self.inner + .get_pa_level() + .map_err(|e| Error::new(Status::GenericFailure, format!("{e:?}"))) + .map(|e| NodePaLevel::from_inner(e)) + } + + #[napi] + pub fn set_pa_level(&mut self, pa_level: NodePaLevel) -> Result<()> { + self.inner + .set_pa_level(pa_level.into_inner()) + .map_err(|e| Error::new(Status::GenericFailure, format!("{e:?}"))) + } + + #[napi] + pub fn set_payload_length(&mut self, length: u8) -> Result<()> { + self.inner + .set_payload_length(length) + .map_err(|e| Error::new(Status::GenericFailure, format!("{e:?}"))) + } + + #[napi] + pub fn get_payload_length(&mut self) -> Result { + self.inner + .get_payload_length() + .map_err(|e| Error::new(Status::GenericFailure, format!("{e:?}"))) + } + + #[napi] + pub fn set_dynamic_payloads(&mut self, enable: bool) -> Result<()> { + self.inner + .set_dynamic_payloads(enable) + .map_err(|e| Error::new(Status::GenericFailure, format!("{e:?}"))) + } + + #[napi] + pub fn get_dynamic_payload_length(&mut self) -> Result { + self.inner + .get_dynamic_payload_length() + .map_err(|e| Error::new(Status::GenericFailure, format!("{e:?}"))) + } + + #[napi] + pub fn open_rx_pipe(&mut self, pipe: u8, address: &[u8]) -> Result<()> { + self.inner + .open_rx_pipe(pipe, address) + .map_err(|e| Error::new(Status::GenericFailure, format!("{e:?}"))) + } + + #[napi] + pub fn open_tx_pipe(&mut self, address: &[u8]) -> Result<()> { + self.inner + .open_tx_pipe(address) + .map_err(|e| Error::new(Status::GenericFailure, format!("{e:?}"))) + } + + /// If the given `pipe` number is not in range [0, 5], then this function does nothing. + #[napi] + pub fn close_rx_pipe(&mut self, pipe: u8) -> Result<()> { + self.inner + .close_rx_pipe(pipe) + .map_err(|e| Error::new(Status::GenericFailure, format!("{e:?}"))) + } + + #[napi] + pub fn set_address_length(&mut self, length: u8) -> Result<()> { + self.inner + .set_address_length(length) + .map_err(|e| Error::new(Status::GenericFailure, format!("{e:?}"))) + } + + #[napi] + pub fn get_address_length(&mut self) -> Result { + self.inner + .get_address_length() + .map_err(|e| Error::new(Status::GenericFailure, format!("{e:?}"))) + } + + #[napi] + pub fn power_down(&mut self) -> Result<()> { + self.inner + .power_down() + .map_err(|e| Error::new(Status::GenericFailure, format!("{e:?}"))) + } + + #[napi] + pub fn power_up(&mut self, delay: Option) -> Result<()> { + self.inner + .power_up(delay) + .map_err(|e| Error::new(Status::GenericFailure, format!("{e:?}"))) + } + + #[napi] + pub fn set_status_flags(&mut self, rx_dr: bool, tx_ds: bool, tx_df: bool) -> Result<()> { + self.inner + .set_status_flags(rx_dr, tx_ds, tx_df) + .map_err(|e| Error::new(Status::GenericFailure, format!("{e:?}"))) + } + + #[napi] + pub fn clear_status_flags(&mut self, rx_dr: bool, tx_ds: bool, tx_df: bool) -> Result<()> { + self.inner + .clear_status_flags(rx_dr, tx_ds, tx_df) + .map_err(|e| Error::new(Status::GenericFailure, format!("{e:?}"))) + } + + #[napi] + pub fn update(&mut self) -> Result<()> { + self.inner + .update() + .map_err(|e| Error::new(Status::GenericFailure, format!("{e:?}"))) + } + + #[napi] + pub fn get_status_flags(&mut self) -> Result { + let mut rx_dr = Some(false); + let mut tx_ds = Some(false); + let mut tx_df = Some(false); + self.inner + .get_status_flags(&mut rx_dr, &mut tx_ds, &mut tx_df) + .map_err(|e| Error::new(Status::GenericFailure, format!("{e:?}")))?; + Ok(StatusFlags { + rx_dr: rx_dr.unwrap(), + tx_ds: tx_ds.unwrap(), + tx_df: tx_df.unwrap(), + }) + } +} diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000..881d869 --- /dev/null +++ b/yarn.lock @@ -0,0 +1,20 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@napi-rs/cli@^2.18.4": + version "2.18.4" + resolved "https://registry.yarnpkg.com/@napi-rs/cli/-/cli-2.18.4.tgz#12bebfb7995902fa7ab43cc0b155a7f5a2caa873" + integrity sha512-SgJeA4df9DE2iAEpr3M2H0OKl/yjtg1BnRI5/JyowS71tUWhrfSu2LT0V3vlHET+g1hBVlrO60PmEXwUEKp8Mg== + +"@types/node@^22.7.5": + version "22.7.5" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.7.5.tgz#cfde981727a7ab3611a481510b473ae54442b92b" + integrity sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ== + dependencies: + undici-types "~6.19.2" + +undici-types@~6.19.2: + version "6.19.8" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" + integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==