From e657721c270833df7a24c67e21c3369fedbdd26d Mon Sep 17 00:00:00 2001 From: Charlie Bailly Date: Mon, 31 Jan 2022 14:09:22 +0100 Subject: [PATCH 01/17] Docker: Add configs and script to access the rfcat device using docker Docker: Now copy files from folder instead of cloning repo --- Dockerfile | 11 +++++++++++ docker-compose.yml | 6 ++++++ run_rfcat_docker.sh | 1 + 3 files changed, 18 insertions(+) create mode 100644 Dockerfile create mode 100644 docker-compose.yml create mode 100644 run_rfcat_docker.sh diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..aede72f --- /dev/null +++ b/Dockerfile @@ -0,0 +1,11 @@ +FROM python:3.9.10 + +WORKDIR /pandwarf + +COPY . ./rfcat + +RUN apt update && apt install -y usbutils + +RUN cd rfcat && python setup.py install + +CMD [ "bash" ] diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..88c260b --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,6 @@ +version: "3.3" + +services: + rfcat_image: + build: . + privileged: true diff --git a/run_rfcat_docker.sh b/run_rfcat_docker.sh new file mode 100644 index 0000000..398b9b0 --- /dev/null +++ b/run_rfcat_docker.sh @@ -0,0 +1 @@ +docker-compose run rfcat_image bash \ No newline at end of file From 8d90b2118e3aea4f73c0247dc78fe465d2a97e3d Mon Sep 17 00:00:00 2001 From: Charlie Bailly Date: Mon, 31 Jan 2022 15:08:08 +0100 Subject: [PATCH 02/17] Docker: Now unpluging and replugging usb does not break access to the dongle --- docker-compose.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docker-compose.yml b/docker-compose.yml index 88c260b..6c77dcd 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,4 +3,7 @@ version: "3.3" services: rfcat_image: build: . + volumes: + - /dev/bus/usb:/dev/bus/usb privileged: true + From ad43e4f6d519cfd458c2c6d7428dc5f9006901be Mon Sep 17 00:00:00 2001 From: Charlie Bailly Date: Mon, 7 Feb 2022 11:33:47 +0100 Subject: [PATCH 03/17] RfCat: Implement a first version of PandwaRF and PandwaRF Rogue --- rflib/chipcon_gollum.py | 736 ++++++++++++++++++++++++++++++++++++++++ rflib/const_gollum.py | 246 ++++++++++++++ rflib/utils_gollum.py | 26 ++ 3 files changed, 1008 insertions(+) create mode 100644 rflib/chipcon_gollum.py create mode 100644 rflib/const_gollum.py create mode 100644 rflib/utils_gollum.py diff --git a/rflib/chipcon_gollum.py b/rflib/chipcon_gollum.py new file mode 100644 index 0000000..11612a4 --- /dev/null +++ b/rflib/chipcon_gollum.py @@ -0,0 +1,736 @@ +#!/usr/bin/env ipython +import struct +from typing import Optional +from . import RfCat + +from rflib.ccspecan import SPECAN_QUEUE + +from .utils_gollum import Tools + +from .chipcon_usb import ChipconUsbTimeoutException, keystop +from .chipcondefs import RFST_SIDLE +from .const import MOD_ASK_OOK, SYNCM_CARRIER, USB_RX_WAIT +from .const_gollum import * + +# PandwaRF/PandwaRF Rogue specific methods +class PandwaRF(RfCat): + + def __init__(self, idx=0, debug=False, copyDongle=None, RfMode=RFST_SIDLE, safemode=False): + super().__init__(idx, debug, copyDongle, RfMode, safemode) + self.endec = None + self._initPandwaRf() + + def recv(self, app, cmd=None, wait=USB_RX_WAIT): + # Override recv to replace some commands (e.g specan) + if app == APP_SPECAN: + if cmd == SPECAN_QUEUE: + cmd = CMD_SPECAN_QUEUE + + r, t = super().recv(app, cmd, wait) + return r, t + + # RECV / SEND COMMANDS (Low Level) + + # APP_SYSTEM_GOLLUM + + def _sendAppSystemGollum(self, cmd: int): + return self.send(APP_SYSTEM_GOLLUM, cmd, b'') + + def _sendGetFwVersion(self): + return self._sendAppSystemGollum(CMD_GET_FW_VERSION) + + def _sendGetSerialNumber(self): + return self._sendAppSystemGollum(CMD_DEVICE_SERIAL_NUMBER_GOLLUM) + + # APP_NIC + + def _sendAppNic(self, cmd: int, payload: bytes): + return self.send(APP_NIC, cmd, payload) + + def _recvAppNic(self, cmd: int, wait=USB_RX_WAIT): + return self.recv(APP_NIC, cmd, wait) + + def _sendEncodingMode(self, compressionMode: bool): + _data = struct.pack("B", compressionMode) + return self._sendAppNic(CMD_NIC_ENCODING_MODE, _data) + + def _sendRecvInfiniteMode(self, rxInfiniteMode: bool): + _data = struct.pack("B", rxInfiniteMode) + return self._sendAppNic(CMD_NIC_RECV_INFINITE_MODE, _data) + + def _recv(self): + return self._recvAppNic(CMD_NIC_RECV) + + def _recvRle(self): + return self._recvAppNic(CMD_NIC_RECV_RLE) + + def _sendRequestRemainingData(self): + return self._sendAppNic(CMD_NIC_ENCODING_MODE, b"") + + def _recvRemainingData(self): + return self._recvAppNic(CMD_NIC_RECV_REMAINING_DATA) + + def _recvRemainingDataRle(self): + return self._recvAppNic(CMD_NIC_RECV_REMAINING_DATA_RLE) + + def _sendXmitInfiniteMode(self, enqueueMode: bool, expectedBlockSize: int): + _data = struct.pack(" bytes: + r, t = self._sendGetFwVersion() + return r + + def _getSerialNumber(self) -> bytes: + r, t = self._sendGetSerialNumber() + return r + + def _initPandwaRf(self) -> None: + self.setAmpMode(RF_POWER_AMPLIFIERS_ACTION_ALL_OFF) + + + # Overloading functions + + def getPartNum(self) -> int: + return 0x11 + + def reprHardwareConfig(self): + output= [] + hardware = self.getBuildInfo() + output.append("Dongle: %s" % hardware.split(b' ')[0]) + + fwVersion = self._getFirmwareVersion() + output.append("Firmware rev: %s" % fwVersion) + + # see if we have a bootloader by loooking for it's recognition semaphores + # in SFR I2SCLKF0 & I2SCLKF1 + if(self.peek(0xDF46,1) == b'\xF0' and self.peek(0xDF47,1) == b'\x0D'): + output.append("Bootloader: CC-Bootloader") + elif(self.peek(0xDF46,1) == b'\xCC' and self.peek(0xDF47,1) == b'\x01'): + output.append("Bootloader: Gollum CCTL v1") + elif(self.peek(0xDF46,1) == b'\xCC' and self.peek(0xDF47,1) == b'\x02'): + output.append("Bootloader: GollumCCTL v2") + elif(b"CCtl" in hardware): + output.append("Bootloader: Gollum CCTL") + else: + output.append("Bootloader: Not installed") + return "\n".join(output) + + def reprRadioConfig(self) -> str: + output = [] + output.append(super().reprRadioConfig()) + + output.append("\n== PandwaRF Specific ==") + output.append(f"Amplification Mode: {self.reprAmpMode()}") + + return '\n'.join(output) + + + # User functions + + def setFreq(self, freq: int) -> None: + """ + Modify carrier's frequency. + + :param freq: New frequency + :return: + """ + if type(freq) is float: + freq = int(freq) # Because the specan calls setFreq with a float + self._sendRfSetFreq(freq) + + def setPower(self, power: int, pset: bool = True, invert: bool = False) -> None: + """ + Modify output power. + + :param power: New output power + :param pset: If false, OOK modulation is used, the logic 0 and logic 1 power levels shall be + programmed to index 0 and 1 respectively, i.e. PA_TABLE0 and PA_TABLE1. + :param invert: Invert parameter for power + :return: + """ + self._sendRfSetPower(invert, pset, power) + + def setMdmModulation(self, modulation: int, invert: bool = False) -> None: + """ + Modify modulation format. + + :param modulation: Modulation type + :param invert: Invert parameter for modulation + :return: + """ + self._sendRfSetModulation(invert, modulation) + + def setMdmDRate(self, datarate: int) -> None: + """ + Modify data rate. + + :param datarate: New data rate + :return: + """ + self._sendRfSetDatarate(datarate) + + def setMaxPower(self, invert: bool = False) -> None: + """ + Set power to max. + + :param invert: Invert parameter + :return: + """ + self._sendRfSetMaxPower(invert) + + def setRxFilterBw(self, bandwidth: int) -> None: + """ + Modify RX filter bandwidth. + + :param bandwidth: New RX filter bandwidth + :return: + """ + self._sendRfSetRxFilterBw(bandwidth) + + def makePktFLEN(self, packetLength: int) -> None: + """ + Modify packet length. + + :param packetLength: New packet length + :return: + """ + self._sendRfSetPacketFlen(packetLength) + + def setMdmSyncMode(self, syncMode: int) -> None: + """ + Modify sync mode. + + :param syncMode: New sync mode + :return: + """ + self._sendRfSetSyncmode(syncMode) + + + def setEnablePktCRC(self, crcMode: bool) -> None: + """ + Modify packet CRC state. + + :param crcMode: New packet CRC state + :return: + """ + self._sendRfSetPktCrc(crcMode) + + def setMdmChanSpc(self, channelSpacing: int) -> None: + """ + Modify channel spacing. + + :param channelSpacing: New channel spacing + :return: + """ + if type(channelSpacing) is float: + channelSpacing = int(channelSpacing) # Because the specan calls setFreq with a float + self._sendRfSetChanSpc(channelSpacing) + + def stopAllRf(self) -> None: + """ + Stop all RF activity by setting Mac state Idle directly. + """ + self._sendRfStopAll() + + def getAmpMode(self) -> bytes: + ''' + get the amplifier mode (RF amp external to CC1111) + ''' + r, t = self._sendRfGetTxRxPowerAmpMode() + return r + + def reprAmpMode(self) -> str: + ampMode = int.from_bytes(self.getAmpMode(), 'little') + if ampMode == RF_POWER_AMPLIFIERS_ACTION_ALL_OFF: + return "Amplifiers OFF" + elif ampMode == RF_TX_POWER_AMPLIFIER_ACTION_ON: + return "TX Amplifier only" + elif ampMode == RF_RX_POWER_AMPLIFIER_ACTION_ON: + return "RX Amplifier only" + elif ampMode == RF_TX_RX_POWER_AMPLIFIER_ACTION_ON: + return "TX & RX Amplifiers ON" + elif ampMode == RF_TX_POWER_AMPLIFIER_ACTION_ON_TX: + return "TX Amplifier only when transmitting" + elif ampMode == RF_RX_POWER_AMPLIFIER_ACTION_ON_RX: + return "RX Amplifier only when receiving" + elif ampMode == RF_TX_RX_POWER_AMPLIFIER_ACTION_ON_TX_RX: + return "TX & RX Amplifiers only when transmitting & receiving" + elif ampMode == RF_ANT_POWER_ENABLE: + return "Antenna power enabled" + elif ampMode == RF_ANT_POWER_DISABLE: + return "Antenna power disabled" + else: + return "Unknown amplification mode" + + def rxSetup(self, + frequency: int, + modulation: int, + datarate: int, + packetLength: int = 200, + filterBandwidth: int = 0) -> None: + """ + Initial configuration for Rx. + + :param frequency: Frequency + :param modulation: Modulation + :param datarate: Data rate + :param packetLength: Packet length + :param filterBandwidth: Rx filter bandwidth + :return: + """ + + self.setMdmModulation(modulation) + self.setFreq(frequency) + self.setMdmDRate(datarate) + self.setMdmSyncMode(RfUtils.SYNC_MODE_NO_PRE_CS) + + # This command writes to the register PKTCTRL1, setting to zero APPEND_STATUS and ADR_CHK + self.setPktPQT(0) + self.makePktFLEN(packetLength) + # This command writes to the register PKTCTRL0, setting to zero PKT_FORMAT, CRC_EN and LENGTH_CONFIG + self.setEnablePktDataWhitening(False) + # This command writes to the register MDMCFG1, setting to zero NUM_PREAMBLE and CHANSPC_E + self.setEnableMdmFEC(False) + self.setEnablePktCRC(False) + + if not filterBandwidth: + filterBandwidth = Tools.get_minimum_rx_filter_bandwidth(frequency, datarate) + + self.setRxFilterBw(filterBandwidth) + + def txSetup(self, + frequency: int, + modulation: int, + datarate: int,) -> None: + """ + Initial configuration for Tx. + + :param frequency: Frequency + :param modulation: Modulation + :param datarate: Data rate + :return: + """ + + self.setMdmModulation(modulation) + self.setFreq(frequency) + self.setMdmDRate(datarate) + self.setMaxPower() + + def configSpecan(self, freq: int, channel_spacing: int, rx_bandwidth) -> None: + """ + Initial configure before starting SpecAn. + + :param freq: Frequency + :param channel_spacing: Space between channels + :param rx_bandwidth: Rx Bandwidth + :return: + """ + + self.setFreq(freq) + self.setMdmChanSpc(channel_spacing) + self.setRxFilterBw(rx_bandwidth) + + def doFreqFinder(self) -> Optional[int]: + self._sendFreqfinderStart() + freq = None + print("Waiting for signal....") + print("(press Enter to stop)") + while not keystop() and not freq: + try: + r, t = self._recvFreqfinderResult() + freq = int.from_bytes(r, 'little') + except: + pass + return freq + + def RFxmitRle(self, data: bytes, repeat: int, offset: int) -> None: + """ + Transmit frame (RLE encoded). + + :param data: Data to transmit + :param repeat: Times to repeat + :param offset: Offset + :return: + """ + dataLength = len(data) + self._sendXmitRle(dataLength, repeat, offset, data) + + def setAmpMode(self, amplifierMode: int = 0) -> None: + ''' + set the amplifier mode (RF amp external to CC1111) + 0x00 turn off amplifiers + 0x01 turn on TX amplifier only + 0x02 turn on RX amplifier only + 0x05 turn on TX & RX amplifiers (not supported by rev. E) + 0x06 turn on TX amplifier only when transmitting + 0x07 turn on RX amplifier only when receiving + 0x08 turn on TX & RX amplifiers only when transmitting & receiving + 0x03 enable antenna power + 0x04 disable antenna power + ''' + self._sendRfSetTxRxPowerAmpMode(amplifierMode) + + def doDataRateDetect(self, freq: int, modulation: int, deviation: int = 0, occurenceThreshold=DATARATE_MEAS_OCC_THRESHOLD_DEFAULT): + ''' + starts the Data rate measurement procedure. Frequency needs to be setup first. + ''' + print("Entering data rate measurement mode... measured data rates arriving will be displayed on the screen") + print("(press Enter to stop)") + + self.setFreq(freq) + self.setMdmModulation(modulation) + if deviation > 0: + self.setMdmDeviatn(deviation) + self.setMdmDRate(100000) + self.setMdmSyncMode(SYNCM_CARRIER) + self.setPktPQT(0) + self.makePktFLEN(250) + self.setEnablePktDataWhitening(0) + self.setEnableMdmFEC(0) + self.setEnablePktCRC(False) + self.setMdmChanBW(125000) + self.setAmpMode(RF_POWER_AMPLIFIERS_ACTION_ALL_OFF) + self._sendStartDatarateDetection(occurenceThreshold) + + while not keystop(): + # check for SYS_CMD_NIC_DATARATE_DETECTED + try: + (y, t) = self._recvDatarateDetected() + dr, = struct.unpack(" None: + """ + Performs a jamming, either around one frequency (startFrequency) or + between 2 frequencies (startFrequency and stopFrequency) + + :param startFrequency: Center Frequency to Jam or start frequency if stopFrequency is set + :type startFrequency: int + :param dataRate: Datarate is equivalent to "Spectrum Wideness" here: More datarate => wider is the jamming spectrum + :type dataRate: int + :param stopFrequency: Stop frequency, defaults to -1 + :type stopFrequency: int, optional + """ + print("Entering RF jamming mode...") + if not stopFrequency: + stopFrequency = startFrequency + + self._sendRfStartJamming(startFrequency, dataRate, MOD_ASK_OOK, stopFrequency) + + input("press Enter to stop") + + self._sendRfStopJamming() + + def doBruteForceLegacy(self): + pass + + + +class PandwaRFRogue(PandwaRF): + + # RECV / SEND COMMANDS (Low Level) + + # APP_RF + + def _sendRfBruteForceSetupLongSymbol(self, + delay: int, + symbolLength: int, + encSymbol0: int, + encSymbol1: int, + encSymbol2: int, + encSymbol3: int): + _data = struct.pack("BB", delay, symbolLength) + endianess = 'big' + _data += int.to_bytes(encSymbol0, symbolLength, endianess) + _data += int.to_bytes(encSymbol1, symbolLength, endianess) + _data += int.to_bytes(encSymbol2, symbolLength, endianess) + _data += int.to_bytes(encSymbol3, symbolLength, endianess) + return self._sendAppRf(CMD_RF_BRUTE_FORCE_SETUP_LONG_SYMBOL, _data) + + def _sendRfBruteForceStartSyncCodeTail(self, + syncWordSize: int, + tailWordSize: int, + codeLength: int, + startValue: int, + stopValue: int, + frameRepeat: int, + littleEndian: bool, + syncWord: int, + tailWord: int): + _data = struct.pack(" to stop") + + self._sendRfBruteForceStop() diff --git a/rflib/const_gollum.py b/rflib/const_gollum.py new file mode 100644 index 0000000..59893ec --- /dev/null +++ b/rflib/const_gollum.py @@ -0,0 +1,246 @@ +APP_SYSTEM_GOLLUM = 0xF1 +APP_NIC = 0x42 +APP_SPECAN = 0x43 +APP_FREQFINDER = 0x44 +APP_RF = 0xBF + +# APP_SYSTEM_GOLLUM +CMD_PM_SLEEP = 0x8A +CMD_GET_FW_VERSION = 0x90 +CMD_DEVICE_SERIAL_NUMBER_GOLLUM = 0x92 + +# APP_NIC +CMD_NIC_ENCODING_MODE = 0x13 +CMD_NIC_RECV_INFINITE_MODE = 0x0E +CMD_NIC_RECV = 0x01 +CMD_NIC_RECV_RLE = 0x01 +CMD_NIC_REQUEST_REMAINING_DATA = 0x20 +CMD_NIC_RECV_REMAINING_DATA = 0x21 +CMD_NIC_RECV_REMAINING_DATA_RLE = 0x22 +CMD_NIC_XMIT_INFINITE_MODE = 0x12 +CMD_NIC_XMIT = 0x02 +CMD_NIC_XMIT_RLE = 0x04 +CMD_NIC_START_DATARATE_DETECTION = 0x0A +CMD_NIC_STOP_DATARATE_DETECTION = 0x0B +CMD_NIC_DATARATE_DETECTED = 0x0C +CMD_NIC_DATARATE_DETECTED_END = 0x0D +CMD_NIC_RECV_ASYNC_MODE = 0x0F +CMD_NIC_RECV_ASYNC_PROCESSING_ENABLED = 0x10 +CMD_NIC_RECV_ASYNC_DATA_NORDIC = 0xF1 +CMD_NIC_RECV_ASYNC_DATA_CC1111 = 0xF2 + +# APP_RF +CMD_RF_SEND_CONFIG = 0x50 +CMD_RF_TRANSMIT_DATA = 0x51 +CMD_RF_SET_FREQ = 0x52 +CMD_RF_SET_POWER = 0x53 +CMD_RF_SET_MODULATION = 0x54 +CMD_RF_SET_DATARATE = 0x55 +CMD_RF_SET_MAXPOWER = 0x56 +CMD_RF_SET_RXFILTERBW = 0x57 +CMD_RF_SET_PACKETFLEN = 0x58 +CMD_RF_SET_SYNCMODE = 0x59 +CMD_RF_SET_PKTCRC = 0x60 +CMD_RF_SET_CHANSPC = 0x61 +CMD_RF_START_JAMMING = 0x62 +CMD_RF_STOP_JAMMING = 0x63 +CMD_RF_BRUTE_FORCE_SETUP = 0x68 # Gouv custom +CMD_RF_BRUTE_FORCE_SETUP_LONG_SYMBOL = 0x7B +CMD_RF_BRUTE_FORCE_SETUP_FUNCTION = 0x7A +CMD_RF_BRUTE_FORCE_START = 0x64 +CMD_RF_BRUTE_FORCE_START_SYNC_CODE_TAIL = 0x69 # Gouv custom +CMD_RF_BRUTE_FORCE_STOP = 0x65 +CMD_RF_BRUTE_FORCE_STATUS_UPDATE = 0x66 +CMD_RF_SET_TXRX_POWER_AMP_MODE = 0x67 +CMD_RF_GET_TXRX_POWER_AMP_MODE = 0x70 +CMD_RF_SET_RX_MODE_AUTO = 0x5A +CMD_RF_STOP_ALL = 0x71 + +# APP_SPECAN +CMD_RFCAT_START_SPECAN = 0x40 +CMD_RFCAT_STOP_SPECAN = 0x41 +CMD_SPECAN_PKT_DELAY = 0x42 +CMD_SPECAN_QUEUE = 0x43 + +# APP_FREQFINDER + +CMD_FREQFINDER_START = 0xA0 +CMD_FREQFINDER_RESULT = 0xA1 +CMD_FREQFINDER_STOP = 0xA2 + +# RF power amplifiers +RF_POWER_AMPLIFIERS_ACTION_ALL_OFF = 0x00 # action turn off amplifiers +RF_TX_POWER_AMPLIFIER_ACTION_ON = 0x01 # action turn on TX amplifier +RF_RX_POWER_AMPLIFIER_ACTION_ON = 0x02 # action turn on RX amplifier +RF_TX_RX_POWER_AMPLIFIER_ACTION_ON = 0x05 # action turn on TX & RX amplifiers (not supported by rev. E) +RF_TX_POWER_AMPLIFIER_ACTION_ON_TX = 0x06 # action turn on TX amplifier only when transmitting +RF_RX_POWER_AMPLIFIER_ACTION_ON_RX = 0x07 # action turn on RX amplifier only when receiving +RF_TX_RX_POWER_AMPLIFIER_ACTION_ON_TX_RX = 0x08 # action turn on TX & RX amplifiers only when transmitting & receiving +RF_ANT_POWER_ENABLE = 0x03 # action enable antenna power +RF_ANT_POWER_DISABLE = 0x04 # action disable antenna power + +# Data rate measurement +USB_DATARATE_MEAS_WAIT_MS = 100 +DATARATE_MEAS_OCC_THRESHOLD_DEFAULT = 100 + +# Brute Force +USB_BRUTEFORCE_STATUS_WAIT_MS = 5000 +STATE_BRUTEFORCE_UNKNOWN = 0 +STATE_BRUTEFORCE_NOT_STARTED = 1 +STATE_BRUTEFORCE_ONGOING = 2 +STATE_BRUTEFORCE_FINISHED = 3 + + +# Registers + +class Registers: + """ + CC1111 common registers defines. + """ + + # Frequency registers + FREQ2 = 0xDF09 + FREQ1 = 0xDF0A + FREQ0 = 0xDF0B + + # Deviation register + DEVIATN = 0xDF11 + + # Sync Word registers + SYNC_H = 0xDF00 + SYNC_L = 0xDF01 + + # Packet Length register + PKTLEN = 0xDF02 + + # Packet Automation Control registers + PKTCTRL0 = 0xDF04 + PKTCTRL1 = 0xDF03 + + # Modem Configuration register + MDMCFG1 = 0xDF0F + MDMCFG2 = 0xDF0E + +class RfUtils: + """ + Utils defines for RF configuration. + """ + + # Frequency + FREQ_LOW_MIN = 300000000 + FREQ_315 = 315000000 + FREQ_LOW_MAX = 348000000 + FREQ_MID_MIN = 391000000 + FREQ_434 = 434000000 + FREQ_MID_MAX = 464000000 + FREQ_HIGH_MIN = 782000000 + FREQ_867 = 867000000 + FREQ_868 = 868000000 + FREQ_869 = 869000000 + FREQ_HIGH_MAX = 928000000 + FREQ_DEFAULT = 433000000 + FREQ_REMOTE_1 = 433875000 + FREQ_REMOTE_2 = 868200000 + FREQ_915 = 915000000 + PLATFORM_CLOCK_FREQ = 24 + FREQ_REGISTERS_TO_REAL_FREQ_CONST = 1000000 / 0x10000 + + FREQUENCY_VALUES = { + #FREQ_LOW_MIN: FREQ_LOW_MIN, + FREQ_315: FREQ_315, + FREQ_DEFAULT: FREQ_DEFAULT, + #FREQ_LOW_MAX: FREQ_LOW_MAX, + #FREQ_MID_MIN: FREQ_MID_MIN, + FREQ_434: FREQ_434, + #FREQ_MID_MAX: FREQ_MID_MAX, + #FREQ_HIGH_MIN: FREQ_HIGH_MIN, + FREQ_867: FREQ_867, + FREQ_868: FREQ_868, + FREQ_869: FREQ_869, + FREQ_915: FREQ_915, + #FREQ_HIGH_MAX: FREQ_HIGH_MAX, + FREQ_REMOTE_1: FREQ_REMOTE_1, + FREQ_REMOTE_2: FREQ_REMOTE_2 + } + + Frequency_list = [FREQ_315, FREQ_434, FREQ_DEFAULT, FREQ_867, FREQ_868, FREQ_869, FREQ_915] + + # Max and min data rate in BAUD + DATA_RATE_MAX = 500000 + DATA_RATE_MIN = 23 + + # Max and min Rx filter bandwidth in Hz + RX_FILTER_BANDWIDTH_MAX = 750000 + RX_FILTER_BANDWIDTH_MIN = 54000 + RX_DEFAULT_FILTER_BANDWIDTH = 150000 + + RX_FILTER_BANDWIDTH_VALUES = { + RX_FILTER_BANDWIDTH_MIN, + 63000, 75000, 94000, + 107000, 125000, 150000, + 188000, 214000, 250000, + 300000, 375000, 429000, + 500000, 600000, RX_FILTER_BANDWIDTH_MAX, + RX_DEFAULT_FILTER_BANDWIDTH + } + + # Max and min channel spacing in Hz + CHANSPC_MAX = 374268 + CHANSPC_MIN = 23436 + + # Power Amplifier Modes + RF_POWER_AMPLIFIERS_ACTION_ALL_OFF = 0x00 + RF_TX_POWER_AMPLIFIER_ACTION_ON = 0x01 + RF_RX_POWER_AMPLIFIER_ACTION_ON = 0x02 + RF_TX_RX_POWER_AMPLIFIER_ACTION_ON = 0x05 + RF_TX_RX_POWER_AMPLIFIER_ACTION_ON_TX_RX = 0x08 + RF_ANT_POWER_ENABLE = 0x80 + RF_ANT_POWER_DISABLE = 0x00 + + amp_modes = [ + RF_POWER_AMPLIFIERS_ACTION_ALL_OFF, + RF_TX_POWER_AMPLIFIER_ACTION_ON, + RF_RX_POWER_AMPLIFIER_ACTION_ON + ] + + # Deviation + CC1111_DEVIATION_MAX = 374268 + CC1111_DEVIATION_MIN = 23436 + + # Modulation + # MSK is only supported for data rates above 26 kBaud and cannot be used with Manchester enc/dec enabled. + # GFSK, ASK and OOK is only supported for data rate up until 250 kBaud + MOD_FORMAT_2_FSK = 0x00 + MOD_FORMAT_GFSK = 0x10 + MOD_FORMAT_ASK_OOK = 0x30 + MOD_FORMAT_MSK = 0x70 + MOD_INVERT = True + MOD_NOT_INVERT = False + + mod_to_set = [ + MOD_FORMAT_2_FSK, + MOD_FORMAT_ASK_OOK, + MOD_FORMAT_GFSK, + MOD_FORMAT_MSK + ] + + # Sync Mode + SYNC_MODE_NO_PRE = 0x00 + SYNC_MODE_15_16 = 0x01 + SYNC_MODE_16_16 = 0x02 + SYNC_MODE_30_32 = 0x03 + SYNC_MODE_NO_PRE_CS = 0x04 + SYNC_MODE_15_16_CS = 0x05 + SYNC_MODE_16_16_CS = 0x06 + SYNC_MODE_30_32_CS = 0x07 + + sync_mode_to_set = [ + SYNC_MODE_NO_PRE, + SYNC_MODE_NO_PRE_CS, + SYNC_MODE_15_16, + SYNC_MODE_15_16_CS, + SYNC_MODE_16_16, + SYNC_MODE_16_16_CS, + SYNC_MODE_30_32, + SYNC_MODE_30_32_CS + ] \ No newline at end of file diff --git a/rflib/utils_gollum.py b/rflib/utils_gollum.py new file mode 100644 index 0000000..6c0b32d --- /dev/null +++ b/rflib/utils_gollum.py @@ -0,0 +1,26 @@ +from .const_gollum import RfUtils + +class Tools: + """ + General tools for Gollum CC1111. + """ + + @classmethod + def get_minimum_rx_filter_bandwidth(cls, freq: int, data_rate: int) -> int: + """ + Calculate the minimum Rx filter bandwidth for a given frequency and data rate value. + + :param freq: Frequency + :param data_rate: Data rate + :return: Minimum filter bandwidth + """ + + freq_uncertainty = 20e-6 * freq * 2 + min_bw = data_rate + freq_uncertainty + + for bw_val in RfUtils.RX_FILTER_BANDWIDTH_VALUES: + if bw_val > min_bw: + return bw_val + +if __name__ == '__main__': + pass From 31e22342b02ee48c79a3374f918771275f7d2f36 Mon Sep 17 00:00:00 2001 From: Charlie Bailly Date: Mon, 7 Feb 2022 11:35:10 +0100 Subject: [PATCH 04/17] RfCat: Add PandwaRF example scripts --- rflib/gollum_examples/simple_bruteforce.py | 31 +++++++++++++++++++ .../simple_datarate_measurement.py | 8 +++++ rflib/gollum_examples/simple_freqfinder.py | 8 +++++ rflib/gollum_examples/simple_jamming.py | 9 ++++++ rflib/gollum_examples/simple_rx.py | 17 ++++++++++ rflib/gollum_examples/simple_tx.py | 12 +++++++ 6 files changed, 85 insertions(+) create mode 100644 rflib/gollum_examples/simple_bruteforce.py create mode 100644 rflib/gollum_examples/simple_datarate_measurement.py create mode 100644 rflib/gollum_examples/simple_freqfinder.py create mode 100644 rflib/gollum_examples/simple_jamming.py create mode 100644 rflib/gollum_examples/simple_rx.py create mode 100644 rflib/gollum_examples/simple_tx.py diff --git a/rflib/gollum_examples/simple_bruteforce.py b/rflib/gollum_examples/simple_bruteforce.py new file mode 100644 index 0000000..b41f386 --- /dev/null +++ b/rflib/gollum_examples/simple_bruteforce.py @@ -0,0 +1,31 @@ +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 + + 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, encSymbolZero, encSymbolOne, encSymbolTwo, encSymbolThree, syncWordSize, syncWord, tailWordSize, tailWord, functionSize, functionMask, functionValue) + + d.setModeIDLE() \ No newline at end of file diff --git a/rflib/gollum_examples/simple_datarate_measurement.py b/rflib/gollum_examples/simple_datarate_measurement.py new file mode 100644 index 0000000..04e07e0 --- /dev/null +++ b/rflib/gollum_examples/simple_datarate_measurement.py @@ -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() diff --git a/rflib/gollum_examples/simple_freqfinder.py b/rflib/gollum_examples/simple_freqfinder.py new file mode 100644 index 0000000..c04a13d --- /dev/null +++ b/rflib/gollum_examples/simple_freqfinder.py @@ -0,0 +1,8 @@ +from rflib.chipcon_gollum import * + +if __name__ == "__main__": + d = PandwaRF() + d.setModeIDLE() + freq = d.doFreqFinder() + print(f"Found frequency : {freq} Hz") + d.setModeIDLE() diff --git a/rflib/gollum_examples/simple_jamming.py b/rflib/gollum_examples/simple_jamming.py new file mode 100644 index 0000000..c9bd66c --- /dev/null +++ b/rflib/gollum_examples/simple_jamming.py @@ -0,0 +1,9 @@ +from rflib.chipcon_gollum import * + +if __name__ == "__main__": + d = PandwaRF() + d.setModeIDLE() + FREQ = 433_920_000 + DATARATE = 10_000 # Equivalent to spectrum wideness of the jamming + d.doJamming(FREQ, DATARATE) + d.setModeIDLE() diff --git a/rflib/gollum_examples/simple_rx.py b/rflib/gollum_examples/simple_rx.py new file mode 100644 index 0000000..2033fad --- /dev/null +++ b/rflib/gollum_examples/simple_rx.py @@ -0,0 +1,17 @@ +from rflib.chipcon_gollum import * +import time + +if __name__ == "__main__": + d = PandwaRF() + FREQ = 433920000 + DATARATE = 2500 + 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) + print("Data received :") + print(d.RFrecv()) + d.setModeIDLE() + \ No newline at end of file diff --git a/rflib/gollum_examples/simple_tx.py b/rflib/gollum_examples/simple_tx.py new file mode 100644 index 0000000..7c6ef52 --- /dev/null +++ b/rflib/gollum_examples/simple_tx.py @@ -0,0 +1,12 @@ +from rflib.chipcon_gollum import * + +if __name__ == "__main__": + d = PandwaRF() + FREQ = 433920000 + DATARATE = 2500 + d.setModeIDLE() + d.txSetup(FREQ, MOD_ASK_OOK, DATARATE) + d.setAmpMode(RF_TX_POWER_AMPLIFIER_ACTION_ON) + d.setModeTX() + d.RFxmit(b"HALLO") + d.setModeIDLE() From fb117698a3df43d62d5c28332ad9bf7b330ddb96 Mon Sep 17 00:00:00 2001 From: Charlie Bailly Date: Mon, 7 Feb 2022 12:23:30 +0100 Subject: [PATCH 05/17] RfCat: Fix specan --- rflib/chipcon_gollum.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/rflib/chipcon_gollum.py b/rflib/chipcon_gollum.py index 11612a4..4fa2cea 100644 --- a/rflib/chipcon_gollum.py +++ b/rflib/chipcon_gollum.py @@ -1,7 +1,7 @@ #!/usr/bin/env ipython import struct from typing import Optional -from . import RfCat +from . import RFCAT_START_SPECAN, RFCAT_STOP_SPECAN, RfCat from rflib.ccspecan import SPECAN_QUEUE @@ -9,7 +9,7 @@ from .chipcon_usb import ChipconUsbTimeoutException, keystop from .chipcondefs import RFST_SIDLE -from .const import MOD_ASK_OOK, SYNCM_CARRIER, USB_RX_WAIT +from .const import MOD_ASK_OOK, SYNCM_CARRIER, USB_RX_WAIT, USB_TX_WAIT from .const_gollum import * # PandwaRF/PandwaRF Rogue specific methods @@ -29,6 +29,15 @@ def recv(self, app, cmd=None, wait=USB_RX_WAIT): r, t = super().recv(app, cmd, wait) return r, t + def send(self, app, cmd, buf, wait=USB_TX_WAIT): + # Override send to replace some commands (e.g specan) + if app == APP_NIC: + if cmd in [RFCAT_START_SPECAN, RFCAT_STOP_SPECAN]: + app = APP_SPECAN + + r, t = super().send(app, cmd, buf, wait) + return r, t + # RECV / SEND COMMANDS (Low Level) # APP_SYSTEM_GOLLUM @@ -209,7 +218,7 @@ def _sendRfSetPktCrc(self, crcMode: bool): return self._sendAppRf(CMD_RF_SET_PKTCRC, _data) def _sendRfSetChanSpc(self, channelSpacing: int): - _data = struct.pack("B", channelSpacing) + _data = struct.pack(" str: return '\n'.join(output) + def _stopSpecAn(self): + # Overload because it is wrongly implemented in rfcat + self._sendRfcatStopSpecan() + # User functions From b76c6008f3b70127438d490807fd4acbc58b0890 Mon Sep 17 00:00:00 2001 From: Charlie Bailly Date: Mon, 7 Feb 2022 13:09:47 +0100 Subject: [PATCH 06/17] USB Device List: Add the PandwaRF and PandwaRF Rogue product ids and auto detect device when doing rfcat -r --- rfcat | 27 +++++++++++++++++++++++---- rflib/chipcon_usb.py | 10 +++++++++- rflib/const_gollum.py | 5 +++++ 3 files changed, 37 insertions(+), 5 deletions(-) diff --git a/rfcat b/rfcat index 7f2bcbb..3b14736 100755 --- a/rfcat +++ b/rfcat @@ -6,6 +6,9 @@ import sys import logging import readline import rlcompleter + +from rflib.chipcon_gollum import PandwaRF, PandwaRFRogue +from rflib.const_gollum import GOLLUM_VENDOR_ID readline.parse_and_bind("tab: complete") from rflib import * @@ -30,6 +33,20 @@ you interact with the rfcat dongle: """ +def getDongleClass(idx: int): + dongle = getRfCatDevices()[idx] + if dongle.idVendor == GOLLUM_VENDOR_ID: + if dongle.idProduct == PANDWARF_ROGUE_PRODUCT_ID: + print("PandwaRF Rogue Detected") + return PandwaRFRogue + elif dongle.idProduct == PANDWARF_PRODUCT_ID: + print("PandwaRF (non Rogue) Detected") + return PandwaRF + + print("Dongle is not a PandwaRF") + return RfCat + + if __name__ == "__main__": import argparse @@ -46,23 +63,25 @@ if __name__ == "__main__": ifo = parser.parse_args() + DongleClass = getDongleClass(ifo.index) + if ifo.bootloader: if not ifo.force: print("Protecting you from yourself. If you want to trigger Bootloader mode (you will then *have* to flash a new RfCat image on it) use the --force argument as well") exit(-1) print("Entering RfCat Bootloader mode, ready for new image...") - RfCat(ifo.index, safemode=ifo.safemode).bootloader() + DongleClass(ifo.index, safemode=ifo.safemode).bootloader() exit(0) elif ifo.specan: - RfCat(ifo.index).specan(ifo.centfreq,ifo.inc,ifo.specchans) + DongleClass(ifo.index).specan(ifo.centfreq,ifo.inc,ifo.specchans) elif ifo.research: - interactive(ifo.index, DongleClass=RfCat, intro=intro, safemode=ifo.safemode) + interactive(ifo.index, DongleClass=DongleClass, intro=intro, safemode=ifo.safemode) else: # do the full-rfcat thing - d = RfCat(ifo.index, debug=False) + d = DongleClass(ifo.index, debug=False) d.rf_redirection((sys.stdin, sys.stdout)) diff --git a/rflib/chipcon_usb.py b/rflib/chipcon_usb.py index 38bc015..e8a693c 100644 --- a/rflib/chipcon_usb.py +++ b/rflib/chipcon_usb.py @@ -19,6 +19,8 @@ import threading from binascii import hexlify +from rflib.const_gollum import PANDWARF_PRODUCT_ID, PANDWARF_ROGUE_PRODUCT_ID + from . import bits from .bits import correctbytes, ord23 from .const import * @@ -41,7 +43,13 @@ def getRfCatDevices(): for bus in usb.busses(): for dev in bus.devices: # OpenMoko assigned or Legacy TI - if (dev.idVendor == 0x0451 and dev.idProduct == 0x4715) or (dev.idVendor == 0x1d50 and (dev.idProduct == 0x6047 or dev.idProduct == 0x6048 or dev.idProduct == 0x605b or dev.idProduct == 0xecc1)): + if (dev.idVendor == 0x0451 and dev.idProduct == 0x4715) or \ + (dev.idVendor == 0x1d50 and (dev.idProduct == 0x6047 or + dev.idProduct == 0x6048 or + dev.idProduct == 0x605b or + dev.idProduct == 0xecc1 or + dev.idProduct == PANDWARF_PRODUCT_ID or + dev.idProduct == PANDWARF_ROGUE_PRODUCT_ID)): rfcats.append(dev) elif (dev.idVendor == 0x1d50 and (dev.idProduct == 0x6049 or dev.idProduct == 0x604a or dev.idProduct == 0xecc0)): diff --git a/rflib/const_gollum.py b/rflib/const_gollum.py index 59893ec..1349096 100644 --- a/rflib/const_gollum.py +++ b/rflib/const_gollum.py @@ -90,6 +90,11 @@ STATE_BRUTEFORCE_ONGOING = 2 STATE_BRUTEFORCE_FINISHED = 3 +# VENDOR / PRODUCT ID + +GOLLUM_VENDOR_ID = 0x1d50 +PANDWARF_PRODUCT_ID = 0x60FF +PANDWARF_ROGUE_PRODUCT_ID = 0x60FE # Registers From b069590bde506653e977ac7207314e08d73b4d9c Mon Sep 17 00:00:00 2001 From: Charlie Bailly Date: Mon, 7 Feb 2022 13:27:17 +0100 Subject: [PATCH 07/17] USB non-root: Add PandwaRF vendor/device id to udev rules --- etc/udev/rules.d/20-rfcat.rules | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/etc/udev/rules.d/20-rfcat.rules b/etc/udev/rules.d/20-rfcat.rules index 9aa71e3..25e7d4d 100644 --- a/etc/udev/rules.d/20-rfcat.rules +++ b/etc/udev/rules.d/20-rfcat.rules @@ -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" From a4badec9ba3a2b27036dde5fe7c1757918b8f754 Mon Sep 17 00:00:00 2001 From: Charlie Bailly Date: Mon, 7 Feb 2022 14:45:05 +0100 Subject: [PATCH 08/17] RfCat: Update bruteforce method and example script --- rflib/chipcon_gollum.py | 48 +++++++++++----------- rflib/gollum_examples/simple_bruteforce.py | 3 +- 2 files changed, 27 insertions(+), 24 deletions(-) diff --git a/rflib/chipcon_gollum.py b/rflib/chipcon_gollum.py index 4fa2cea..94c2267 100644 --- a/rflib/chipcon_gollum.py +++ b/rflib/chipcon_gollum.py @@ -651,8 +651,29 @@ def doJamming(self, startFrequency: int, dataRate: int, stopFrequency: int = Non self._sendRfStopJamming() - def doBruteForceLegacy(self): + def _doBruteForceReceive(self, stopValue: int): + status = 0 + while (not keystop() and (status <= stopValue)): + # check for SYS_CMD_RF_BRUTE_FORCE_STATUS_UPDATE + try: + (y, t) = self._recvRfBruteForceStatusUpdate() + status, state = struct.unpack(" to stop") + @@ -704,6 +725,7 @@ def doBruteForce(self, codeLength: int, repeat: int, delay: int, + symbolLength: int, encSymbol0: int, encSymbol1: int, encSymbol2: int, @@ -720,30 +742,10 @@ def doBruteForce(self, print("(press Enter to stop)") self.txSetup(frequency, modulation, datarate) - self._sendRfBruteForceSetupLongSymbol(delay, 3, encSymbol0, encSymbol1, encSymbol2, encSymbol3) + self._sendRfBruteForceSetupLongSymbol(delay, symbolLength, encSymbol0, encSymbol1, encSymbol2, encSymbol3) self._sendRfBruteForceSetupFunction(functionSize, functionMask, functionValue) self._sendRfBruteForceStartSyncCodeTail(syncWordSize, tailWordSize, codeLength, startValue, stopValue, repeat, littleEndian, syncWord, tailWord) - status = 0 - while (not keystop() and (status <= stopValue)): - # check for SYS_CMD_RF_BRUTE_FORCE_STATUS_UPDATE - try: - (y, t) = self._recvRfBruteForceStatusUpdate() - status, state = struct.unpack(" to stop") + self._doBruteForceReceive(stopValue) self._sendRfBruteForceStop() diff --git a/rflib/gollum_examples/simple_bruteforce.py b/rflib/gollum_examples/simple_bruteforce.py index b41f386..ce90bf1 100644 --- a/rflib/gollum_examples/simple_bruteforce.py +++ b/rflib/gollum_examples/simple_bruteforce.py @@ -14,6 +14,7 @@ repeat = 6 delayMs = 30 + symbolLength = 3 encSymbolZero = 0xFF0000 encSymbolOne = 0xFF00FF encSymbolTwo = 0x000000 @@ -26,6 +27,6 @@ functionMask = 0xFFFFFFFFFFFFFFFFFFFF0000 functionValue= 0x000000000000000000000001 - d.doBruteForce(FREQ, MOD, DATARATE, startValue, stopValue, codeLength, repeat, delayMs, encSymbolZero, encSymbolOne, encSymbolTwo, encSymbolThree, syncWordSize, syncWord, tailWordSize, tailWord, functionSize, functionMask, functionValue) + d.doBruteForce(FREQ, MOD, DATARATE, startValue, stopValue, codeLength, repeat, delayMs, symbolLength, encSymbolZero, encSymbolOne, encSymbolTwo, encSymbolThree, syncWordSize, syncWord, tailWordSize, tailWord, functionSize, functionMask, functionValue) d.setModeIDLE() \ No newline at end of file From 43eea214abe8a2eca161566c190ff95614d93ecc Mon Sep 17 00:00:00 2001 From: Charlie Bailly Date: Mon, 7 Feb 2022 17:34:18 +0100 Subject: [PATCH 09/17] RfCat: Add bruteforce legacy with example script --- rflib/chipcon_gollum.py | 30 ++++++++++++++++++- .../simple_bruteforce_legacy.py | 30 +++++++++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 rflib/gollum_examples/simple_bruteforce_legacy.py diff --git a/rflib/chipcon_gollum.py b/rflib/chipcon_gollum.py index 94c2267..a729731 100644 --- a/rflib/chipcon_gollum.py +++ b/rflib/chipcon_gollum.py @@ -264,7 +264,7 @@ def _sendRfBruteForceStart(self, syncWordSize: int, syncWord: int): _data = struct.pack(" to stop") + + def doBruteForceLegacy(self, + frequency: int, + modulation: int, + datarate: int, + startValue: int, + stopValue: int, + codeLength: int, + repeat: int, + delay: int, + encSymbol0: int, + encSymbol1: int, + encSymbol2: int, + encSymbol3: int, + syncWordSize: int, + syncWord: int, + functionSize: int, + functionMask: int, + functionValue: int, + littleEndian=False): + print("Entering brute force mode... status arriving will be displayed on the screen") + print("(press Enter to stop)") + + self.txSetup(frequency, modulation, datarate) + self._sendRfBruteForceSetupFunction(functionSize, functionMask, functionValue) + self._sendRfBruteForceStart(codeLength, startValue, stopValue, repeat, littleEndian, delay, encSymbol0, encSymbol1, encSymbol2, encSymbol3, syncWordSize, syncWord) + self._doBruteForceReceive(stopValue) + self._sendRfBruteForceStop() diff --git a/rflib/gollum_examples/simple_bruteforce_legacy.py b/rflib/gollum_examples/simple_bruteforce_legacy.py new file mode 100644 index 0000000..204e08f --- /dev/null +++ b/rflib/gollum_examples/simple_bruteforce_legacy.py @@ -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() \ No newline at end of file From 7d2a37bebcc872e14a225f01d9f5a22bb37a086e Mon Sep 17 00:00:00 2001 From: Charlie Bailly Date: Tue, 8 Feb 2022 11:09:26 +0100 Subject: [PATCH 10/17] Doc: Update Readme on how to install and use rfcat (with/without docker) --- README.md | 84 ++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 68 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 80e820b..2d9508a 100644 --- a/README.md +++ b/README.md @@ -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`. +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 +``` + +## 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 [rflib/gollum_examples](./rflib/gollum_examples). +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) ## GOALS From f938577d7a265e1f89236871328e5a5c661ecb33 Mon Sep 17 00:00:00 2001 From: Charlie Bailly Date: Tue, 8 Feb 2022 11:27:12 +0100 Subject: [PATCH 11/17] RfCat: Minor fixes --- rfcat | 5 ++++- rflib/chipcon_gollum.py | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/rfcat b/rfcat index 3b14736..befa9cf 100755 --- a/rfcat +++ b/rfcat @@ -34,7 +34,10 @@ you interact with the rfcat dongle: """ def getDongleClass(idx: int): - dongle = getRfCatDevices()[idx] + dongles = getRfCatDevices() + if idx >= len(dongles): + return RfCat + dongle = dongles[idx] if dongle.idVendor == GOLLUM_VENDOR_ID: if dongle.idProduct == PANDWARF_ROGUE_PRODUCT_ID: print("PandwaRF Rogue Detected") diff --git a/rflib/chipcon_gollum.py b/rflib/chipcon_gollum.py index a729731..280b109 100644 --- a/rflib/chipcon_gollum.py +++ b/rflib/chipcon_gollum.py @@ -670,7 +670,7 @@ def _doBruteForceReceive(self, stopValue: int): except ChipconUsbTimeoutException: # print "Timeout Brute force status update" - pass + pass except KeyboardInterrupt: print("Please press to stop") From cc2550d83fb14722196518cb0125414ae3c5bbfb Mon Sep 17 00:00:00 2001 From: Charlie Bailly Date: Tue, 8 Feb 2022 11:27:37 +0100 Subject: [PATCH 12/17] Docker: Make it work on windows --- Dockerfile | 5 ++--- run_rfcat_docker.bat | 1 + 2 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 run_rfcat_docker.bat diff --git a/Dockerfile b/Dockerfile index aede72f..c4248d8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,10 +2,9 @@ FROM python:3.9.10 WORKDIR /pandwarf -COPY . ./rfcat - -RUN apt update && apt install -y usbutils +RUN apt update && apt install -y usbutils ffmpeg && pip install pyside2 +COPY . ./rfcat RUN cd rfcat && python setup.py install CMD [ "bash" ] diff --git a/run_rfcat_docker.bat b/run_rfcat_docker.bat new file mode 100644 index 0000000..398b9b0 --- /dev/null +++ b/run_rfcat_docker.bat @@ -0,0 +1 @@ +docker-compose run rfcat_image bash \ No newline at end of file From 4e3274a3693aee04291521b9c69f5661d0775260 Mon Sep 17 00:00:00 2001 From: Charlie Bailly Date: Tue, 8 Feb 2022 17:23:47 +0100 Subject: [PATCH 13/17] RfCat: Add example script to interact with Kaiju and PandwaRF --- rflib/gollum_examples/kaiju_analysis.py | 55 ++++++++++++++ .../kaiju_generate_rolling_code.py | 74 +++++++++++++++++++ 2 files changed, 129 insertions(+) create mode 100644 rflib/gollum_examples/kaiju_analysis.py create mode 100644 rflib/gollum_examples/kaiju_generate_rolling_code.py diff --git a/rflib/gollum_examples/kaiju_analysis.py b/rflib/gollum_examples/kaiju_analysis.py new file mode 100644 index 0000000..f3234f8 --- /dev/null +++ b/rflib/gollum_examples/kaiju_analysis.py @@ -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)) diff --git a/rflib/gollum_examples/kaiju_generate_rolling_code.py b/rflib/gollum_examples/kaiju_generate_rolling_code.py new file mode 100644 index 0000000..127499d --- /dev/null +++ b/rflib/gollum_examples/kaiju_generate_rolling_code.py @@ -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": 1435, + "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() From f46e2f691a0a29890fd77e4d73a026a28b532185 Mon Sep 17 00:00:00 2001 From: Charlie Bailly Date: Tue, 8 Feb 2022 17:37:15 +0100 Subject: [PATCH 14/17] RfCat: Add another example script to generate and send rolling code --- .../kaiju_generate_rolling_code_2.py | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 rflib/gollum_examples/kaiju_generate_rolling_code_2.py diff --git a/rflib/gollum_examples/kaiju_generate_rolling_code_2.py b/rflib/gollum_examples/kaiju_generate_rolling_code_2.py new file mode 100644 index 0000000..2e9e663 --- /dev/null +++ b/rflib/gollum_examples/kaiju_generate_rolling_code_2.py @@ -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() From a7e989124ba3b204be21bc6d996fdcc7580187dc Mon Sep 17 00:00:00 2001 From: Charlie Bailly Date: Tue, 8 Feb 2022 18:01:58 +0100 Subject: [PATCH 15/17] Docker: Move dependencies to requirements.txt --- Dockerfile | 10 ++++------ requirements.txt | 2 ++ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Dockerfile b/Dockerfile index c4248d8..cc01fd4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,10 +1,8 @@ FROM python:3.9.10 -WORKDIR /pandwarf - -RUN apt update && apt install -y usbutils ffmpeg && pip install pyside2 - -COPY . ./rfcat -RUN cd rfcat && python setup.py install +WORKDIR /pandwarf/rfcat +COPY . . +RUN apt update && apt install -y usbutils ffmpeg && pip install -r requirements.txt +RUN python setup.py install CMD [ "bash" ] diff --git a/requirements.txt b/requirements.txt index 1a10931..291cd06 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,3 +3,5 @@ future ipython pyserial numpy +requests +pyside2 \ No newline at end of file From 7da98574a2816967ea6b8dd63eebefd72f3632c7 Mon Sep 17 00:00:00 2001 From: Charlie Bailly Date: Wed, 9 Feb 2022 09:55:46 +0100 Subject: [PATCH 16/17] Move example scripts --- README.md | 2 +- {rflib/gollum_examples => examples}/kaiju_analysis.py | 0 .../gollum_examples => examples}/kaiju_generate_rolling_code.py | 2 +- .../kaiju_generate_rolling_code_2.py | 0 {rflib/gollum_examples => examples}/simple_bruteforce.py | 0 {rflib/gollum_examples => examples}/simple_bruteforce_legacy.py | 0 .../gollum_examples => examples}/simple_datarate_measurement.py | 0 {rflib/gollum_examples => examples}/simple_freqfinder.py | 0 {rflib/gollum_examples => examples}/simple_jamming.py | 0 {rflib/gollum_examples => examples}/simple_rx.py | 0 {rflib/gollum_examples => examples}/simple_tx.py | 0 11 files changed, 2 insertions(+), 2 deletions(-) rename {rflib/gollum_examples => examples}/kaiju_analysis.py (100%) rename {rflib/gollum_examples => examples}/kaiju_generate_rolling_code.py (98%) rename {rflib/gollum_examples => examples}/kaiju_generate_rolling_code_2.py (100%) rename {rflib/gollum_examples => examples}/simple_bruteforce.py (100%) rename {rflib/gollum_examples => examples}/simple_bruteforce_legacy.py (100%) rename {rflib/gollum_examples => examples}/simple_datarate_measurement.py (100%) rename {rflib/gollum_examples => examples}/simple_freqfinder.py (100%) rename {rflib/gollum_examples => examples}/simple_jamming.py (100%) rename {rflib/gollum_examples => examples}/simple_rx.py (100%) rename {rflib/gollum_examples => examples}/simple_tx.py (100%) diff --git a/README.md b/README.md index 2d9508a..b4c25d2 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ sudo udevadm control --reload-rules ## 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 [rflib/gollum_examples](./rflib/gollum_examples). +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. diff --git a/rflib/gollum_examples/kaiju_analysis.py b/examples/kaiju_analysis.py similarity index 100% rename from rflib/gollum_examples/kaiju_analysis.py rename to examples/kaiju_analysis.py diff --git a/rflib/gollum_examples/kaiju_generate_rolling_code.py b/examples/kaiju_generate_rolling_code.py similarity index 98% rename from rflib/gollum_examples/kaiju_generate_rolling_code.py rename to examples/kaiju_generate_rolling_code.py index 127499d..47a30cc 100644 --- a/rflib/gollum_examples/kaiju_generate_rolling_code.py +++ b/examples/kaiju_generate_rolling_code.py @@ -15,7 +15,7 @@ "brand": "MHouse", "model": "GTX", "serialNumberHex": "0x041170E", - "syncCounter": 1435, + "syncCounter": 1440, "button": 1, "seed": "", "numCodesRequested": 2 diff --git a/rflib/gollum_examples/kaiju_generate_rolling_code_2.py b/examples/kaiju_generate_rolling_code_2.py similarity index 100% rename from rflib/gollum_examples/kaiju_generate_rolling_code_2.py rename to examples/kaiju_generate_rolling_code_2.py diff --git a/rflib/gollum_examples/simple_bruteforce.py b/examples/simple_bruteforce.py similarity index 100% rename from rflib/gollum_examples/simple_bruteforce.py rename to examples/simple_bruteforce.py diff --git a/rflib/gollum_examples/simple_bruteforce_legacy.py b/examples/simple_bruteforce_legacy.py similarity index 100% rename from rflib/gollum_examples/simple_bruteforce_legacy.py rename to examples/simple_bruteforce_legacy.py diff --git a/rflib/gollum_examples/simple_datarate_measurement.py b/examples/simple_datarate_measurement.py similarity index 100% rename from rflib/gollum_examples/simple_datarate_measurement.py rename to examples/simple_datarate_measurement.py diff --git a/rflib/gollum_examples/simple_freqfinder.py b/examples/simple_freqfinder.py similarity index 100% rename from rflib/gollum_examples/simple_freqfinder.py rename to examples/simple_freqfinder.py diff --git a/rflib/gollum_examples/simple_jamming.py b/examples/simple_jamming.py similarity index 100% rename from rflib/gollum_examples/simple_jamming.py rename to examples/simple_jamming.py diff --git a/rflib/gollum_examples/simple_rx.py b/examples/simple_rx.py similarity index 100% rename from rflib/gollum_examples/simple_rx.py rename to examples/simple_rx.py diff --git a/rflib/gollum_examples/simple_tx.py b/examples/simple_tx.py similarity index 100% rename from rflib/gollum_examples/simple_tx.py rename to examples/simple_tx.py From a9338c07c77332cc1fc63bdedce7b7b2c2f3d6f3 Mon Sep 17 00:00:00 2001 From: Charlie Bailly Date: Wed, 9 Feb 2022 10:36:38 +0100 Subject: [PATCH 17/17] RfCat: Update init message --- rfcat | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/rfcat b/rfcat index befa9cf..5a846c2 100755 --- a/rfcat +++ b/rfcat @@ -18,18 +18,24 @@ logger = logging.getLogger(__name__) intro = """'RfCat, the greatest thing since Frequency Hopping!' - +Modified version for PandwaRF ! Research Mode: enjoy the raw power of rflib currently your environment has an object called "d" for dongle. this is how you interact with the rfcat dongle: - >>> d.ping() - >>> d.setFreq(433000000) - >>> d.setMdmModulation(MOD_ASK_OOK) - >>> d.makePktFLEN(250) - >>> d.RFxmit("HALLO") - >>> d.RFrecv() - >>> print(d.reprRadioConfig()) + +d.ping() +d.setModeIDLE() +d.setFreq(433920000) +d.setMdmModulation(MOD_ASK_OOK) +d.setMdmDRate(10_000) +d.makePktFLEN(250) +d.setModeTX() +d.RFxmit(b"HALLO") +d.setModeRX() +d.RFrecv() +print(d.reprRadioConfig()) +d.setModeIDLE() """