├── .gitignore ├── gareth-hackrf-node-success.jpg ├── gareth.png ├── gareth.raw ├── image-transfer.js ├── package.json ├── readme.md └── test-data.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 18 | .grunt 19 | 20 | # node-waf configuration 21 | .lock-wscript 22 | 23 | # Compiled binary addons (http://nodejs.org/api/addons.html) 24 | build/Release 25 | 26 | # Dependency directory 27 | # https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git 28 | node_modules 29 | -------------------------------------------------------------------------------- /gareth-hackrf-node-success.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gyaresu/hackrf-node-stuff/2602cc3ab7533d8d37fd6bc5da075c300142b8a5/gareth-hackrf-node-success.jpg -------------------------------------------------------------------------------- /gareth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gyaresu/hackrf-node-stuff/2602cc3ab7533d8d37fd6bc5da075c300142b8a5/gareth.png -------------------------------------------------------------------------------- /gareth.raw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gyaresu/hackrf-node-stuff/2602cc3ab7533d8d37fd6bc5da075c300142b8a5/gareth.raw -------------------------------------------------------------------------------- /image-transfer.js: -------------------------------------------------------------------------------- 1 | var devices = require('hackrf-stream') 2 | var fs = require('fs') 3 | 4 | var radio = devices(0).open(0) 5 | 6 | radio.setFrequency(9.15e8) 7 | 8 | radio.setSampleRate(3.7e6) 9 | 10 | var tx = radio.createWriteStream() 11 | 12 | fs.readFile('./gareth.raw', function (err, data) { 13 | if (err) { 14 | throw err 15 | } 16 | tx.write(data) 17 | }) 18 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hackrf-node-stuff", 3 | "version": "1.0.0", 4 | "description": "Folks were playing around with [Hellschreiber](https://en.wikipedia.org/wiki/Hellschreiber) encoding in the #hackrf channel on Freenode last week using `hackrf_transfer`", 5 | "main": "image-transfer.js", 6 | "dependencies": { 7 | "hackrf": "^3.0.1", 8 | "hackrf-stream": "^1.0.1" 9 | }, 10 | "devDependencies": {}, 11 | "scripts": { 12 | "test": "echo \"Error: no test specified\" && exit 1" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "git+https://github.com/gyaresu/hackrf-node-stuff.git" 17 | }, 18 | "keywords": [], 19 | "author": "", 20 | "license": "ISC", 21 | "bugs": { 22 | "url": "https://github.com/gyaresu/hackrf-node-stuff/issues" 23 | }, 24 | "homepage": "https://github.com/gyaresu/hackrf-node-stuff#readme" 25 | } 26 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ## HackRF Node Stream Spectrum Painter 2 | 3 | Folks were playing around with [Hellschreiber](https://en.wikipedia.org/wiki/Hellschreiber) encoding in the #hackrf channel on Freenode last week using `hackrf_transfer` 4 | 5 |

HackRF's tx/rx'ing images in waterfall plots using http://t.co/Lyijkr63QP http://t.co/JwLsO29dqC #SDR #HackRF pic.twitter.com/aAKk4eLBgV

— ☞ Gareth (@gyaresu) August 21, 2015
6 | 7 | 8 | 9 | Which then made me remember a tweet from @maxogden playing around with a `hackrf` `node` module at the [CCC](https://www.ccc.de/en/) 2015 camp last week. 10 | 11 | And using a `hackrf` via `node` is something I've wanted since before it was even a `thing`. 12 | 13 | ### Spectrum Painter 14 | 15 | ##### Use [Spectrum Painter](https://github.com/polygon/spectrum_painter) to create an IQ stream: 16 | 17 | ```bash 18 | python spectrum_painter/img2iqstream.py examples/gareth.png --samplerate 8000000 --format hackrf > gareth.raw 19 | ``` 20 | 21 | ##### Then test with `hackrf_transfer`: 22 | ```bash 23 | hackrf_transfer -f 915000000 -s 3700000 -t gareth.raw -x 20 -a 1 24 | ``` 25 | 26 | ##### Show the transmission on a second machine with `gqrx`: 27 | [GQRX](http://gqrx.dk) is a multi-platform software reciever with waterfall plot. 28 | 29 | You might need to tweak some of the sample rate / fft settings in both `hackrf_transfer` & `gqrx` to get the correct aspect ratio but it's not difficult. 30 | 31 | ``` 32 | FFT: 8192 33 | Rate: 50fps 34 | Filter Width: Normal 35 | Filter Shape: Normal 36 | Mode: Narrow/FM 37 | AGC: Fast 38 | ``` 39 | 40 | ### HackRF for Node 41 | 42 | ##### So I wrote something straight from my brain using [hackrf-stream](https://github.com/mappum/hackrf-stream)... 43 | 44 | 45 | ```node 46 | var devices = require('hackrf-stream') 47 | var fs = require('fs') 48 | 49 | var radio = devices(0).open(0) 50 | 51 | radio.setFrequency(9.15e8) 52 | 53 | radio.setSampleRate(3.7e6) 54 | 55 | var tx = radio.createWriteStream() 56 | 57 | fs.readFile('./gareth.raw', function (err, data) { 58 | if (err) { 59 | throw err 60 | } 61 | tx.write(data) 62 | }) 63 | ``` 64 | ##### ... and it worked. 65 | 66 | ![First test](./gareth-hackrf-node-success.jpg) 67 | _I managed to capture the very first code test. While in utter shock it actually worked!_ 68 | -------------------------------------------------------------------------------- /test-data.js: -------------------------------------------------------------------------------- 1 | var devices = require('hackrf-stream') 2 | var fs = require('fs') 3 | 4 | var radio = devices(0).open(0) 5 | 6 | radio.setFrequency(9.15e8) 7 | 8 | radio.setSampleRate(3.7e6) 9 | 10 | var tx = radio.createWriteStream() 11 | 12 | fs.readFile('./gareth.raw', function (err, data) { 13 | if (err) { 14 | throw err 15 | } 16 | var img = data 17 | 18 | while (true) { 19 | tx.write(img) 20 | } 21 | }) 22 | --------------------------------------------------------------------------------