Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add pandwarf support #119

Open
wants to merge 17 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
FROM python:3.9.10

WORKDIR /pandwarf/rfcat
COPY . .
RUN apt update && apt install -y usbutils ffmpeg && pip install -r requirements.txt
RUN python setup.py install

CMD [ "bash" ]
84 changes: 68 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,75 @@
Welcome to the official rfcat project that works for `PandwaRF` and `PandwaRF Rogue`, modified to also work with legacy rfcat dongles such as `Yard Stick One`.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looking through the PR, the README.md is probably the most problematic for merge :)
since this is the official RfCat repo, too much emphasis on PandwaRF over other dongles may be considered inappropriate. ;)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes sure, this is not the PandwaRF repo. So feel free to to treat PandwaRF as any other compatible dongle

See the legacy readme [here](#legacy-readme).

## How to install RfCat python

There are multiple ways to install rfcat, including a docker way, but for now, if you are using docker, you won't be able to use the `rfcat -s` feature (the Spectrum Analyser) since it require a GUI (Graphical User Interface).

### On Linux

- (Recommended) Install using docker and our custom image by simply running `./run_rfcat_docker.sh`
- Install using the [legacy install](#installing-client)

### On Windows

On windows you can use rfcat with `WSL 2` and the `Ubuntu distribution for WSL 2`. You can :
- (Recommended) Install using `Docker Desktop` by simply running `run_rfcat_docker.bat`
- Install using the [legacy install](#installing-client) of rfcat inside `WSL 2`.

In both cases, after installation, you will need to follow this [guide](https://devblogs.microsoft.com/commandline/connecting-usb-devices-to-wsl/) to expose your PandwaRF / Yard Stick One USB Dongle to the `WSL 2 / Docker instance`. The guide is working on `Windows 10` even if it says you need `Windows 11`.

## How to use RfCat python without root permissions

(You don't need to do this if you are using the docker method)

You may have tried to run `rfcat -r` and saw a `Permission Denied` error, and then simply did `sudo rfcat -r` to make it work, but you can avoid the `sudo` by allowing user access to the RfCat USB Dongles by doing the following:

```bash
sudo cp etc/udev/rules.d/20-rfcat.rules /etc/udev/rules.d
sudo udevadm control --reload-rules
# Then you may need to reboot to apply changes
atlas0fd00m marked this conversation as resolved.
Show resolved Hide resolved
```

## How to use RfCat python

After having followed the above guide on how to install the rfcat python client, you can simply type `rfcat -r` to interact with the Dongle. You can also create scripts to use the Dongle, and some example script for the `PandwaRF` are provided in the [examples](./examples/) folder.
You can also check the [legacy Using rfcat](#using-rfcat) for additional info.




# Legacy Readme

Welcome to the rfcat project

## Table of Contents

* [Goals](#goals)
* [Requirements](#requirements)
* [Other requirements](#other-requirements)
* [Build requirements](#build-requirements)
* [Development](#development)
* ["Gotchas"](#gotchas)
* [Installing on hardware](#installing-on-hardware)
* [Allowing non-root dongle access](#allowing-non-root-dongle-access)
* [Supported dongles](#supported-dongles)
* [Your build environment](#your-build-environment)
* [Installing with bootloader](#installing-with-bootloader)
* [To install](#to-install)
* [Installing client](#installing-client)
* [Using RfCat](#using-rfcat)
* [Cool Projects Using RfCat](#external-projects)
* [Epilogue](#epilogue)
- [Legacy Readme](#legacy-readme)
- [Table of Contents](#table-of-contents)
- [GOALS](#goals)
- [REQUIREMENTS](#requirements)
- [Other requirements](#other-requirements)
- [Build requirements](#build-requirements)
- [DEVELOPMENT](#development)
- [Gotchas](#gotchas)
- [INSTALLING ON HARDWARE](#installing-on-hardware)
- [allowing non-root dongle access](#allowing-non-root-dongle-access)
- [supported dongles](#supported-dongles)
- [GoodFET](#goodfet)
- [Chronos Dongle](#chronos-dongle)
- [EMK Dongle](#emk-dongle)
- [YARD Stick One](#yard-stick-one)
- [INSTALLING WITH BOOTLOADER](#installing-with-bootloader)
- [Steps required for all firmware installs and updates](#steps-required-for-all-firmware-installs-and-updates)
- [Steps for bootloader + firmware installs via hardware debugger](#steps-for-bootloader--firmware-installs-via-hardware-debugger)
- [Steps for firmware updates via USB port](#steps-for-firmware-updates-via-usb-port)
- [Installing client](#installing-client)
- [Dependencies](#dependencies)
- [Installation](#installation)
- [Installation with pip](#installation-with-pip)
- [Using rfcat](#using-rfcat)
- [External Projects](#external-projects)
- [Epilogue](#epilogue)

Comment on lines +47 to 73
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i like the improved TOC.
i'd like to incorporate PandwaRF into the official RfCat core, which means that i'd like to include it in the "legacy" docs, if that works for you.

would you be willing to migrate the information into the "Legacy" README?

  • add the PandwaRF and Rogue into the Supported Dongles section
  • insert Docker information alongside the standard Python install (docker's a nice touch, btw!)
  • touch up any other sections you've improved upon in the top section

thanks!

## GOALS

Expand Down
9 changes: 9 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
version: "3.3"

services:
rfcat_image:
build: .
volumes:
- /dev/bus/usb:/dev/bus/usb
privileged: true

5 changes: 5 additions & 0 deletions etc/udev/rules.d/20-rfcat.rules
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,8 @@ SUBSYSTEM=="tty", SUBSYSTEMS=="usb", ATTRS{idVendor}=="1d50", ATTRS{idProduct}==
SUBSYSTEM=="tty", SUBSYSTEMS=="usb", ATTRS{idVendor}=="1d50", ATTRS{idProduct}=="604a", MODE:="0660", SYMLINK+="RFCAT_BL_D", ENV{ID_MM_DEVICE_IGNORE}="1", GROUP="dialout"
SUBSYSTEM=="tty", SUBSYSTEMS=="usb", ATTRS{idVendor}=="1d50", ATTRS{idProduct}=="605c", MODE:="0660", SYMLINK+="RFCAT_BL_YS1", ENV{ID_MM_DEVICE_IGNORE}="1", GROUP="dialout"
SUBSYSTEM=="tty", SUBSYSTEMS=="usb", ATTRS{idVendor}=="1d50", ATTRS{idProduct}=="ecc0", MODE:="0660", SYMLINK+="RFCAT_BL_SRF", ENV{ID_MM_DEVICE_IGNORE}="1", GROUP="dialout"

# PandwaRF devices

SUBSYSTEMS=="usb", ATTRS{idVendor}=="1d50", ATTRS{idProduct}=="60fe", MODE:="0660", SYMLINK+="RFCAT%n", GROUP="dialout"
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1d50", ATTRS{idProduct}=="60ff", MODE:="0660", SYMLINK+="RFCAT%n", GROUP="dialout"
55 changes: 55 additions & 0 deletions examples/kaiju_analysis.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import json
from rflib.chipcon_gollum import *
import time, requests

if __name__ == "__main__":
d = PandwaRF()
FREQ = 433_920_000
DATARATE = 10_000
# Your token can be found on https://rolling.pandwarf.com/profile-user
# It is the 'API token'
KAIJU_API_TOKEN = "YOUR_KAIJU_API_TOKEN_HERE"

d.setModeIDLE()
d.rxSetup(FREQ, MOD_ASK_OOK, DATARATE)
d.setAmpMode(RF_RX_POWER_AMPLIFIER_ACTION_ON)
d.setModeRX()
print("Please send some data...")
time.sleep(5)
data, _ = d.RFrecv()
print(f"Data received : {data.hex()}")
d.setModeIDLE()
print("Analysing data with Kaiju...")

base_url = "https://rolling.pandwarf.com/api/v1"
s = requests.Session()
s.headers.update({
'Authorization': f'Token {KAIJU_API_TOKEN}'
})

payload = {
"rawHexStream": data.hex()
}
payload = json.dumps(payload)
response = s.post(f"{base_url}/analyze/detailed", data=payload)

result = response.json()
if "progress" not in result.keys():
print(json.dumps(result, indent=2))
d.setModeIDLE()
exit()
# Now polling server every 1 seconds until processing is finished
progress = result["progress"]
taskId = result["id"]
while progress != 100:
r = s.get(f"{base_url}/task/{taskId}")
result = r.json()
progress = result["progress"]
print(f"Progress: {progress}/100")
time.sleep(1)

print("Processing done, now retrieving the result :")
r = s.get(f"{base_url}/remote/{taskId}")
result = r.json()
remoteData = result["remoteData"]
print(json.dumps(remoteData, indent=2))
74 changes: 74 additions & 0 deletions examples/kaiju_generate_rolling_code.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import json
from rflib.chipcon_gollum import *
import time, requests

if __name__ == "__main__":
d = PandwaRF()
FREQ = 433_920_000
DATARATE = 2_500
# Your token can be found on https://rolling.pandwarf.com/profile-user
# It is the 'API token'
KAIJU_API_TOKEN = "YOUR_KAIJU_API_TOKEN_HERE"
REMOTE_INFO = {
"rollingCodeRequest": {
"type": "Gate Opener",
"brand": "MHouse",
"model": "GTX",
"serialNumberHex": "0x041170E",
"syncCounter": 1440,
"button": 1,
"seed": "",
"numCodesRequested": 2
}
}
# We will generate 2 rolling codes and send them using the PandwaRF
base_url = "https://rolling.pandwarf.com/api/v1"
s = requests.Session()
s.headers.update({
'Authorization': f'Token {KAIJU_API_TOKEN}'
})

payload = json.dumps(REMOTE_INFO)
print("Asking Kaiju for rolling codes")
response = s.post(f"{base_url}/generate/param", data=payload)
result = response.json()
if "progress" not in result.keys():
print(json.dumps(result, indent=2))
d.setModeIDLE()
exit()
# Now polling server every 1 seconds until processing is finished
progress = result["progress"]
taskId = result["id"]
while progress != 100:
r = s.get(f"{base_url}/task/{taskId}")
result = r.json()
progress = result["progress"]
print(f"Progress: {progress}/100")
time.sleep(1)

print("Processing done, now retrieving the rolling codes :")
r = s.get(f"{base_url}/remote/{taskId}")
result = r.json()
rollingCodes = result["remoteData"]["rollingCodes"]

print("Preparing PandwaRF for TX")
d.setModeIDLE()
d.txSetup(FREQ, MOD_ASK_OOK, DATARATE)
d.setAmpMode(RF_TX_POWER_AMPLIFIER_ACTION_ON)
d.setModeTX()

for rollingCode in rollingCodes:
syncCounter = rollingCode["syncCounter"]
button = rollingCode["button"]
dataHex = rollingCode["dataHex"]
fullMsgHex = rollingCode["fullMsgHex"]
data = dataHex
if not data:
data = fullMsgHex

data = bytes.fromhex(data)
print(f"Sending rolling code {syncCounter} of button {button}")
d.RFxmit(data)
time.sleep(2)

d.setModeIDLE()
72 changes: 72 additions & 0 deletions examples/kaiju_generate_rolling_code_2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import json
from rflib.chipcon_gollum import *
import time, requests

if __name__ == "__main__":
d = PandwaRF()
FREQ = 433_920_000
DATARATE = 2_500
# Your token can be found on https://rolling.pandwarf.com/profile-user
# It is the 'API token'
KAIJU_API_TOKEN = "YOUR_KAIJU_API_TOKEN_HERE"
ROLLING_INFO = {
"numCodesRequested": 2,
"rxTxConfig": {
"rawBitStream": "10101010101010101010101000000000001101001001001001001001101101101001001001101001001101101001101101101001101101101001101001001101101101001001001101101101101001001001101001101101101001101101101101101001101101101101101101001101101101"
}
}
# We will generate 2 rolling codes and send them using the PandwaRF
base_url = "https://rolling.pandwarf.com/api/v1"
s = requests.Session()
s.headers.update({
'Authorization': f'Token {KAIJU_API_TOKEN}'
})

payload = json.dumps(ROLLING_INFO)
print("Asking Kaiju for rolling codes")
response = s.post(f"{base_url}/generate/capture", data=payload)
result = response.json()
if "progress" not in result.keys():
print(json.dumps(result, indent=2))
d.setModeIDLE()
exit()
# Now polling server every 1 seconds until processing is finished
progress = result["progress"]
taskId = result["id"]
while progress != 100:
r = s.get(f"{base_url}/task/{taskId}")
result = r.json()
progress = result["progress"]
print(f"Progress: {progress}/100")
time.sleep(1)

print("Processing done, now retrieving the rolling codes :")
r = s.get(f"{base_url}/remote/{taskId}")
result = r.json()

rollingCodes = result["remoteData"]["rollingCodes"]

print("Preparing PandwaRF for TX")
d.setModeIDLE()
d.txSetup(FREQ, MOD_ASK_OOK, DATARATE)
d.setAmpMode(RF_TX_POWER_AMPLIFIER_ACTION_ON)
d.setModeTX()

for rollingCode in rollingCodes:
syncCounter = rollingCode["syncCounter"]
button = rollingCode["button"]
dataHex = rollingCode["dataHex"]
fullMsgHex = rollingCode["fullMsgHex"]
data = dataHex
if not data:
data = fullMsgHex

data = bytes.fromhex(data)
print(f"Sending rolling code {syncCounter} of button {button}")
d.RFxmit(data)
time.sleep(2)

if rollingCodes == []:
print("Unable to generate rolling code")

d.setModeIDLE()
32 changes: 32 additions & 0 deletions examples/simple_bruteforce.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from rflib.chipcon_gollum import *

if __name__ == "__main__":
# This bruteforce is only available on PandwaRF Rogue
# See bruteforce legacy for the PandwaRF (non Rogue)
d = PandwaRFRogue()
d.setModeIDLE()
FREQ = 433_920_000
DATARATE = 24_536
MOD = MOD_ASK_OOK
codeLength = 12
startValue = 3190
stopValue = 3300
repeat = 6
delayMs = 30

symbolLength = 3
encSymbolZero = 0xFF0000
encSymbolOne = 0xFF00FF
encSymbolTwo = 0x000000
encSymbolThree = 0x000000
syncWordSize = 40
syncWord = 0
tailWordSize = 8
tailWord = 0xFF00000000000000
functionSize = 12
functionMask = 0xFFFFFFFFFFFFFFFFFFFF0000
functionValue= 0x000000000000000000000001

d.doBruteForce(FREQ, MOD, DATARATE, startValue, stopValue, codeLength, repeat, delayMs, symbolLength, encSymbolZero, encSymbolOne, encSymbolTwo, encSymbolThree, syncWordSize, syncWord, tailWordSize, tailWord, functionSize, functionMask, functionValue)

d.setModeIDLE()
30 changes: 30 additions & 0 deletions examples/simple_bruteforce_legacy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
from rflib.chipcon_gollum import *

if __name__ == "__main__":
# If you have a PandwaRF Rogue, it is better to use the
# other version of bruteforce (non-legacy)
d = PandwaRF()
d.setModeIDLE()
FREQ = 433_890_000
DATARATE = 5_320
MOD = MOD_ASK_OOK
codeLength = 8
startValue = 0
stopValue = 6560
repeat = 10
delayMs = 0x64

encSymbolZero = 0x8E
encSymbolOne = 0xEE
encSymbolTwo = 0xE8
encSymbolThree = 0x00
syncWordSize = 2
syncWord = 0x0008

functionSize = 8
functionMask = 0xFFFFFF0000FFFFFF
functionValue= 0x000000EEE8000000

d.doBruteForceLegacy(FREQ, MOD, DATARATE, startValue, stopValue, codeLength, repeat, delayMs, encSymbolZero, encSymbolOne, encSymbolTwo, encSymbolThree, syncWordSize, syncWord, functionSize, functionMask, functionValue)

d.setModeIDLE()
8 changes: 8 additions & 0 deletions examples/simple_datarate_measurement.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from rflib.chipcon_gollum import *

if __name__ == "__main__":
d = PandwaRF()
d.setModeIDLE()
FREQ = 433920000
d.doDataRateDetect(FREQ, MOD_ASK_OOK)
d.setModeIDLE()
Loading