Merge pull request 'dev' (#1) from dev into main

Reviewed-on: https://git.dwestgate.us/david/cat-tracker/pulls/1
This commit is contained in:
david 2025-04-28 14:20:45 -07:00
commit f89da50a5d
21 changed files with 755 additions and 1 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
saved_packets/*
src/__pycache__

3
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"python.analysis.stubPath": "./typings"
}

108
README.md
View File

@ -1,3 +1,109 @@
# cat-tracker # cat-tracker
A multi-function application designed to run on a pi node. When used in a mesh network, this app will help track your cat with a CC2500 based radio collar, using complementary CC2500 based radio modules interfaced with your Pi. A multi-function application designed to run on a pi node. When used in a mesh network, this app will help track your cat with a CC2500 based radio collar, using complementary CC2500 based radio modules interfaced with your Pi.
The implementation here uses CC2500 register values which intend to mimic my [Girafus M07A](https://www.girafus.com/en-en/collections/peilsender/products/ersatzteil-basismodul-fur-girafus%C2%AE-pro-track-tor-katzen-hunde-haustier-kleintier-sucher) unit. This unit is paired with my associated [tracker](https://www.girafus.com/en-en/collections/peilsender/products/extra-sender-tag-fur-den-girafus%C2%AE-pro-track-tor-haustier-hund-katze-kleintier-finder-sucher-ortung)
## Links
* [Arduion Forum Port](https://forum.arduino.cc/t/replicating-a-signal-from-a-locating-device-2-4ghz-to-locate-tag/321993/2)
* [cc2500 data sheet](./cc2500.pdf)
* [C Code transciever example](https://github.com/alexbirkett/cc2500-raspberry-pi)
## CC2500 to Raspberry Pi GPIO Pin Mapping
| CC2500 Pin | Function Description | Raspberry Pi GPIO Pin | GPIO Number |
|------------|------------------------------------------------------|-------------------------------|-------------|
| GND | Ground | Pin 6 | - |
| VCC | 3.3V Power (⚠️ **Do not use 5V**) | Pin 1 or Pin 17 | - |
### SPI Connections
| CC2500 Pin | Function | Raspberry Pi GPIO Pin | GPIO Number |
|------------|----------|-------------------------------|-------------|
| SI | MOSI | Pin 19 | GPIO 10 |
| SCK | SCLK | Pin 23 | GPIO 11 |
| CSN | CE0 (Chip Select) | Pin 24 | GPIO 8 |
| SO | MISO | Pin 21 | GPIO 9 |
### Interrupt Pins
| CC2500 Pin | Function | Raspberry Pi GPIO Pin | GPIO Number |
|------------|-------------------------------------------|-------------------------------|-------------|
| GDO0 | Interrupt/Data Ready | Pin 11 | GPIO 17 |
| GDO2 | Additional Interrupt/Data Line | Pin 23 | GPIO 27 |
### Power Amplifier Pins (If Applicable)
| CC2500 Pin | Function | Raspberry Pi GPIO Pin | Notes |
|------------|-------------------------------------------|-------------------------------|----------------------------------------|
| PA_EN | Control Power Amplifier (Optional) | Any GPIO Pin | Connect if amplifier control is needed |
| PA_EX | Reserved | Not Connected | Only connect if required |
## Reverse Engineering the Registers
### SmartRF Studio
#### Install
[SmartRF Studio](https://www.ti.com/tool/SMARTRFTM-STUDIO#downloads) will automatically generate a configuration for the CC2500 Radio based on some RF parameters
* A free registration and login is required to download this app from Texas Instruments
* The app seems to run well via `wine` on linux. I chose to install it on an actual Windows OS, then copy the binaries.
#### Copy Register JSON template
When this is installed, copy the code export json file to help export the initial register configuration in a JSON format
```bash
cp srfexp_json.xml "~/Documents/Texas Instruments/SmartRF Studio v7/codeexport/."
# Example copy command for linux+wine
```
#### Understanding necessary RF Parameters
In SmartRF Studio, open the CC2500 Device Controller under the 2.4 GHZ list.
At the time of writing, it is believed this device uses 250 kBaud MSK encoding. We will choose this option.
Next we need to figure out the Base Frequency, Channel numbers, and Channel Spacing
![smart_rf](./images/smart_rf.png)
### Singal Capture
I have captured the initial signal emitted by the handheld unit when it is first powered on. To do this, I have used a HackRF SDR + gqrx application on linux.
The known frequency range is 2400 2483.5 MHz, and my SDR has a 20 MHZ bandwidth. I choose sweep for signals by tuning the following frequencies
| Sweep # | Center Frequency | Center Frequency (kHz) | Approx. Coverage (MHz) | Approx. Coverage (kHz) |
|---------|------------------|-------------------------|-------------------------|-----------------------------|
| 1 | 2410 MHz | 2,410,000 kHz | 2400 2420 MHz | 2,400,000 2,420,000 kHz |
| 2 | 2430 MHz | 2,430,000 kHz | 2420 2440 MHz | 2,420,000 2,440,000 kHz |
| 3 | 2450 MHz | 2,450,000 kHz | 2440 2460 MHz | 2,440,000 2,460,000 kHz |
| 4 | 2470 MHz | 2,470,000 kHz | 2460 2480 MHz | 2,460,000 2,480,000 kHz |
| 5 | 2483.5 MHz | 2,483,500 kHz | 2473.5 2483.5 MHz | 2,473,500 2,483,500 kHz |
#### Signal 00
2.423257000 GHz | 2423.257000 MHz | 2423257.000 kHz |
![signal_00](./images/signals/signal00.png)
#### Signal 0
2.431258000 GHz | 2431.258000 MHz| 2431258.000 kHz
![signal_0](./images/signals/signal0.png)
#### Signal 1
2.447257000 GHz | 2447.257000 MHz | 2447257.000 kHz
![signal_1](./images/signals/signal1.png)
#### Signal 2
2.450225000 GHz | 2450.225000 MHz | 2450225.000 kHz
![signal_2](./images/signals/signal2.png)
#### Signal 3
2.471275000 GHz | 2471.275000 MHz | 2471275.000 kHz
![signal_3](./images/signals/signal3.png)
#### Signal Summary
* Base frequency: ? MHz
* Date Rate ? Baud
* Channel spacing: ? kHz
* Signal channels:
* Signal 00 → Channel ?
* Signal 0 → Channel ?
* Signal 1 → Channel ?
* Signal 2 → Channel ?
* Signal 3 → Channel ?
## Run
`python3 -m src.main`

BIN
cc2500.pdf Normal file

Binary file not shown.

BIN
images/signals/signal0.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 401 KiB

BIN
images/signals/signal00.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 410 KiB

BIN
images/signals/signal1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 930 KiB

BIN
images/signals/signal2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 560 KiB

BIN
images/signals/signal3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 385 KiB

BIN
images/smart_rf.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

0
src/__init__.py Normal file
View File

110
src/common.py Normal file
View File

@ -0,0 +1,110 @@
from spidev import SpiDev
import RPi.GPIO as GPIO
from .util import sleep, get_addr
from .init_regs_value import init_regs_value
from .regs_addr import regs_addr
CONFIG_REGS = regs_addr["CONFIG_REGS"]
STROBES = regs_addr["STROBES"]
STATUS = regs_addr["STATUS"]
MEMORY = regs_addr["MEMORY"]
MASKS = regs_addr["MASKS"]
ACCESS = regs_addr["ACCESS"]
SRES = STROBES["SRES"]
SNOP = STROBES["SNOP"]
VERSION = STATUS["VERSION"]
MARCSTATE = STATUS["MARCSTATE"]
def write_reg(spi: SpiDev, addr: int, value: int):
"""Write single byte to a register"""
spi.xfer2([addr, value])
sleep(0.1)
def read_register(spi: SpiDev, addr: int):
READ_SINGLE = get_addr("READ_SINGLE")
# Send address | 0x80 (read), then 0x00 dummy to clock in response
response = spi.xfer2([READ_SINGLE | addr, 0x00])
# sleep(0.1)
return response[1]
def write_burst(spi: SpiDev, addr: int, data):
"""Write multiple bytes using burst write"""
WRITE_BURST = get_addr("WRITE_BURST")
tbuf = [addr | WRITE_BURST] + data
spi.xfer2(tbuf)
sleep(0.1)
def read_burst(spi: SpiDev, addr: int, length):
"""Read multiple bytes using burst read"""
READ_BURST = get_addr("READ_BURST")
rbuf = [addr | READ_BURST] + [0x00] * length
response = spi.xfer2(rbuf)
sleep(0.1)
return response[1:] # Skip status byte
def strobe(spi: SpiDev, command: int):
"""Send a command strobe to CC2500"""
spi.xfer2([command])
sleep(0.1)
def init_cc_2500(spi: SpiDev):
for reg_name, value in init_regs_value.items():
addr = get_addr(reg_name)
write_reg(spi, addr, value)
def setup_spi():
spi = SpiDev()
spi.open(0, 0) # Bus 0, CE0 (Pin 24)
spi.max_speed_hz = 100_000 # Safe start speed
spi.mode = 0b00 # SPI mode 0
return spi
def setup_gpio(GDO0_PIN=17, GDO2_PIN=27):
GPIO.setmode(GPIO.BCM)
GPIO.setup(GDO0_PIN, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.setup(GDO2_PIN, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
sleep(0.1)
def reset(spi: SpiDev):
# print("Sending SRES (reset)...")
spi.xfer2([SRES])
sleep(0.5)
# print("Sending SNOP (no-op)...")
status = spi.xfer2([SNOP])[0]
print(f"Status byte: 0x{status:02X}")
# print("Reading MARCSTATE...")
marc = spi.xfer2([MARCSTATE | 0x80, 0x00])[0]
print(f"Marcstate byte: 0x{marc:02X}")
print("Reading VERSION register...")
version = read_register(spi, VERSION)
print(f"CC2500 VERSION register: 0x{version:02X}")
# if version != 0x2F:
# raise Exception("Expected Version was 0x2F!! Quitting")
def test_read_write_reg(spi: SpiDev, dbg=False):
FIFOTHR = get_addr("FIFOTHR")
initial_val = read_register(spi, FIFOTHR)
test_value = initial_val + 1
write_reg(spi, FIFOTHR, test_value)
check = read_register(spi, FIFOTHR)
write_reg(spi, FIFOTHR, initial_val)
if (check != test_value) or dbg:
print("initial value ", initial_val)
print("test value ", test_value)
print("check ", check)
if not dbg:
raise Exception("Test Read+Write failed")
return check == test_value

43
src/init_regs_value.py Normal file
View File

@ -0,0 +1,43 @@
# Address Config = No address check
# Base Frequency = 2447.256836
# CRC Autoflush = false
# CRC Enable = true
# Carrier Frequency = 2447.256836
# Channel Number = 0
# Channel Spacing = 199.951172
# Data Format = Normal mode
# Data Rate = 249.939
# Device Address = 0
# Manchester Enable = false
# Modulated = true
# Modulation Format = MSK
# Packet Length = 255
# Packet Length Mode = Variable packet length mode. Packet length configured by the first byte after sync word
# Phase Transition Time = 0
# Preamble Count = 4
# RX Filter BW = 541.666667
# Sync Word Qualifier Mode = 30/32 sync word bits detected
# TX Power = 0
# Whitening = false
init_regs_value = {
"IOCFG0" : 0x06, # 6 - GDO0OUTPUT PIN CONFIGURATION
"PKTCTRL0": 0b00000001,# 5 - PACKET AUTOMATION CONTROL
"PKTCTRL1": 0b00000100,# 4 - PACKET AUTOMATION CONTROL
"FSCTRL1" : 0x12, # 18 - FREQUENCY SYNTHESIZER CONTROL
"FREQ1" : 0x20, # 32 - FREQUENCY CONTROL WORD, MIDDLE BYTE
"FREQ0" : 0x11, # 17 - FREQUENCY CONTROL WORD, LOW BYTE
"MDMCFG4" : 0x2D, # 45 - MODEM CONFIGURATION
"MDMCFG3" : 0x3B, # 59 - MODEM CONFIGURATION
"MDMCFG2" : 0xF3, # 243 - MODEM CONFIGURATION
"DEVIATN" : 0x00, # 0 - MODEM DEVIATION SETTING
"MCSM0" : 0x18, # 24 - MAIN RADIO CONTROL STATE MACHINE CONFIGURATION
"FOCCFG" : 0x1D, # 29 - FREQUENCY OFFSET COMPENSATION CONFIGURATION
"BSCFG" : 0x1C, # 28 - BIT SYNCHRONIZATION CONFIGURATION
"AGCCTRL2": 0xC7, # 199 - AGC CONTROL
"AGCCTRL1": 0x00, # 0 - AGC CONTROL
"AGCCTRL0": 0xB0, # 176 - AGC CONTROL
"FREND1" : 0xB6, # 182 - FRONT END RX CONFIGURATION
"FSCAL3" : 0xEA, # 234 - FREQUENCY SYNTHESIZER CALIBRATION
"FSCAL1" : 0x00, # 0 - FREQUENCY SYNTHESIZER CALIBRATION
"FSCAL0" : 0x11, # 17 - FREQUENCY SYNTHESIZER CALIBRATION
}

87
src/main.py Normal file
View File

@ -0,0 +1,87 @@
import spidev
from .util import print_gdo_state, sleep, get_addr, dump_regs, debug, GDO0_PIN, GDO2_PIN
from .receive import rx_data_rf
from .transmit import transmit_packet
from .common import (
reset,
setup_spi,
setup_gpio,
read_register,
test_read_write_reg,
init_cc_2500,
write_reg,
SRES,
SNOP,
MARCSTATE,
VERSION,
)
def menu():
print("\nMenu")
print("1: Read Reg by name")
print("2: Write reg hex value by name")
print("3: Dump registers")
print("4: rx_data_rf")
print("5: transmit_packet")
print("6: Run Read+Write test")
print("7: Print GDO state")
print("0: Quit")
if __name__ == "__main__":
setup_gpio(GDO0_PIN, GDO2_PIN)
print_gdo_state(GDO0_PIN, GDO2_PIN)
spi = setup_spi()
reg_name = ""
reg_hex_val = ""
try:
reset(spi)
test_read_write_reg(spi)
init_cc_2500(spi)
stop = False
while not stop:
menu()
cmd = int(input("$: "))
if cmd == 0:
stop = True
elif cmd == 1:
reg_name = input("Register name: ")
addr = get_addr(reg_name)
value = read_register(spi, addr)
print(
"Address: "
+ hex(addr)
+ ", Value: "
+ hex(value)
+ " == "
+ str(value)
)
elif cmd == 2:
reg_name = input("Register name: ")
addr = get_addr(reg_name)
value = int(input("New Register value (hex): "), 16)
write_reg(spi, addr, value)
sleep(0.1)
value_check = read_register(spi, addr)
print("Updated Value: " + hex(value) + " == " + str(value))
elif cmd == 3:
dump_regs(spi, True)
elif cmd == 4:
while True:
rx_data_rf(spi)
elif cmd == 5:
transmit_packet(spi)
elif cmd == 6:
res = test_read_write_reg(spi, True)
print("Test result : " + str(res))
elif cmd == 7:
print_gdo_state(GDO0_PIN, GDO2_PIN)
else:
print("Invalid command")
finally:
print("Closing SPI...")
sleep(0.1)
spi.close()
sleep(0.1)

93
src/receive.py Normal file
View File

@ -0,0 +1,93 @@
from datetime import datetime
from pathlib import Path
from spidev import SpiDev
from .util import sleep, get_addr, digital_read, GDO0_PIN, GDO2_PIN, debug, delay
from .common import strobe, read_register
SIDLE = get_addr("SIDLE")
SFRX = get_addr("SFRX")
SRX = get_addr("SRX")
RXFIFO = get_addr("RXFIFO")
RSSI = get_addr("RSSI")
def print_packet(spi: SpiDev, packet_length):
for i in range(packet_length):
print(f", byte: {0}: 0x{1}", i, read_register(spi, RXFIFO))
# Save packet to a timestamped binary file
def save_packet(packet: list[int]):
# Create directory to store packets if it doesn't exist
packet_dir = Path("saved_packets")
packet_dir.mkdir(parents=True, exist_ok=True)
# Create timestamped filename
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
filename = packet_dir / f"packet_{timestamp}.bin"
# Save packet as binary data
with open(filename, "wb") as f:
f.write(bytearray(packet))
print(f"Packet saved to {filename}")
def get_rssi_from_pkt(packet: list[int]):
if len(packet) < 2:
raise ValueError("Packet too short to contain RSSI and status bytes.")
rssi_raw = packet[-2] # Second-to-last byte is RSSI
return rssi_raw
def get_rssi_from_reg(spi: SpiDev):
return read_register(spi, RSSI)
def get_signal_strength_rssi_raw(rssi_raw: int) -> float:
if rssi_raw >= 128:
rssi_dec = rssi_raw - 256
else:
rssi_dec = rssi_raw
return rssi_dec / 2.0 - 74 # According to CC2500 datasheet
def flush_rx(spi: SpiDev):
# Make sure that the radio is in IDLE state before flushing the FIFO
# (Unless RXOFF_MODE has been changed, the radio should be in IDLE state at this point)
delay(10)
strobe(spi, SIDLE)
delay(10)
# Flush RX FIFO
strobe(spi, SFRX)
delay(10)
def rx_data_rf(spi: SpiDev):
strobe(spi, SRX)
gdo2_state = False
count = 0
strength = 0
while gdo2_state == False:
gdo2_state = digital_read(GDO2_PIN)
delay(1)
count = count + 1
if count > 1000:
flush_rx(spi)
# print("ERR NO DATA")
return
while gdo2_state == True:
gdo2_state = digital_read(GDO2_PIN)
delay(100)
packet_length: int = read_register(spi, RXFIFO)
packet: list[int] = [read_register(spi, RXFIFO) for _ in range(packet_length)]
rssi_raw = get_rssi_from_pkt(packet)
strength = get_signal_strength_rssi_raw(rssi_raw)
print("Length: {0} bytes\t Signal: {1} dBm".format(packet_length, strength))
save_packet(packet)
# Make sure that the radio is in IDLE state before flushing the FIFO
# (Unless RXOFF_MODE has been changed, the radio should be in IDLE state at this point)
strobe(spi, SIDLE)
# Flush RX FIFO
strobe(spi, SFRX)

197
src/regs_addr.py Normal file
View File

@ -0,0 +1,197 @@
from typing import TypedDict
class ConfigRegs(TypedDict):
IOCFG2: int
IOCFG1: int
IOCFG0: int
FIFOTHR: int
SYNC1: int
SYNC0: int
PKTLEN: int
PKTCTRL1: int
PKTCTRL0: int
ADDR: int
CHANNR: int
FSCTRL1: int
FSCTRL0: int
FREQ2: int
FREQ1: int
FREQ0: int
MDMCFG4: int
MDMCFG3: int
MDMCFG2: int
MDMCFG1: int
MDMCFG0: int
DEVIATN: int
MCSM2: int
MCSM1: int
MCSM0: int
FOCCFG: int
BSCFG: int
AGCCTRL2: int
AGCCTRL1: int
AGCCTRL0: int
WOREVT1: int
WOREVT0: int
WORCTRL: int
FREND1: int
FREND0: int
FSCAL3: int
FSCAL2: int
FSCAL1: int
FSCAL0: int
RCCTRL1: int
RCCTRL0: int
FSTEST: int
PTEST: int
AGCTEST: int
TEST2: int
TEST1: int
TEST0: int
class Strobes(TypedDict):
SRES: int
SFSTXON: int
SXOFF: int
SCAL: int
SRX: int
STX: int
SIDLE: int
SAFC: int
SWOR: int
SPWD: int
SFRX: int
SFTX: int
SWORRST: int
SNOP: int
class Status(TypedDict):
PARTNUM: int
VERSION: int
FREQEST: int
LQI: int
RSSI: int
MARCSTATE: int
WORTIME1: int
WORTIME0: int
PKTSTATUS: int
VCO_VC_DAC: int
TXBYTES: int
RXBYTES: int
NUM_RXBYTES: int
class Memory(TypedDict):
PATABLE: int
TXFIFO: int
RXFIFO: int
class Masks(TypedDict):
LQI_RX: int
CRC_OK: int
class Access(TypedDict):
WRITE_BURST: int
READ_SINGLE: int
READ_BURST: int
class RegsAddr(TypedDict):
CONFIG_REGS: ConfigRegs
STROBES: Strobes
STATUS: Status
MEMORY: Memory
MASKS: Masks
ACCESS: Access
regs_addr: RegsAddr = {
"CONFIG_REGS": {
"IOCFG2": 0x00,
"IOCFG1": 0x01,
"IOCFG0": 0x02,
"FIFOTHR": 0x03,
"SYNC1": 0x04,
"SYNC0": 0x05,
"PKTLEN": 0x06,
"PKTCTRL1": 0x07,
"PKTCTRL0": 0x08,
"ADDR": 0x09,
"CHANNR": 0x0A,
"FSCTRL1": 0x0B,
"FSCTRL0": 0x0C,
"FREQ2": 0x0D,
"FREQ1": 0x0E,
"FREQ0": 0x0F,
"MDMCFG4": 0x10,
"MDMCFG3": 0x11,
"MDMCFG2": 0x12,
"MDMCFG1": 0x13,
"MDMCFG0": 0x14,
"DEVIATN": 0x15,
"MCSM2": 0x16,
"MCSM1": 0x17,
"MCSM0": 0x18,
"FOCCFG": 0x19,
"BSCFG": 0x1A,
"AGCCTRL2": 0x1B,
"AGCCTRL1": 0x1C,
"AGCCTRL0": 0x1D,
"WOREVT1": 0x1E,
"WOREVT0": 0x1F,
"WORCTRL": 0x20,
"FREND1": 0x21,
"FREND0": 0x22,
"FSCAL3": 0x23,
"FSCAL2": 0x24,
"FSCAL1": 0x25,
"FSCAL0": 0x26,
"RCCTRL1": 0x27,
"RCCTRL0": 0x28,
"FSTEST": 0x29,
"PTEST": 0x2A,
"AGCTEST": 0x2B,
"TEST2": 0x2C,
"TEST1": 0x2D,
"TEST0": 0x2E,
},
"STROBES": {
"SRES": 0x30,
"SFSTXON": 0x31,
"SXOFF": 0x32,
"SCAL": 0x33,
"SRX": 0x34,
"STX": 0x35,
"SIDLE": 0x36,
"SAFC": 0x37,
"SWOR": 0x38,
"SPWD": 0x39,
"SFRX": 0x3A,
"SFTX": 0x3B,
"SWORRST": 0x3C,
"SNOP": 0x3D,
},
"STATUS": {
"PARTNUM": 0x30,
"VERSION": 0x31,
"FREQEST": 0x32,
"LQI": 0x33,
"RSSI": 0x34,
"MARCSTATE": 0x35,
"WORTIME1": 0x36,
"WORTIME0": 0x37,
"PKTSTATUS": 0x38,
"VCO_VC_DAC": 0x39,
"TXBYTES": 0x3A,
"RXBYTES": 0x3B,
"NUM_RXBYTES": 0x7F,
},
"MEMORY": {"PATABLE": 0x3E, "TXFIFO": 0x3F, "RXFIFO": 0x3F},
"MASKS": {"LQI_RX": 0x01, "CRC_OK": 0x80},
"ACCESS": {"WRITE_BURST": 0x40, "READ_SINGLE": 0x80, "READ_BURST": 0xC0},
}

21
src/transmit.py Normal file
View File

@ -0,0 +1,21 @@
from .common import strobe, write_burst
from .util import get_addr
SIDLE = get_addr("SIDLE")
SFTX = get_addr("SFTX")
STX = get_addr("STX")
WRITE_BURST = get_addr("WRITE_BURST")
TXFIFO_BURST = 0x7F
def transmit_packet(spi):
strobe(spi, SIDLE)
strobe(spi, SFTX)
data = [0] * 5
data[0] = 5
data[1] = 1
data[2] = 2
data[3] = 3
data[4] = 4
write_burst(spi, TXFIFO_BURST, data)

72
src/util.py Normal file
View File

@ -0,0 +1,72 @@
from spidev import SpiDev
from .regs_addr import regs_addr
import RPi.GPIO as GPIO
import time
debug = True
GDO0_PIN = 17
GDO2_PIN = 27
def rr(spi: SpiDev, addr):
READ_SINGLE = get_addr("READ_SINGLE")
# Send address | 0x80 (read), then 0x00 dummy to clock in response
response = spi.xfer2([READ_SINGLE | addr, 0x00])
sleep(0.1)
return response[1]
def print_gdo_state(GDO0_PIN=17, GDO2_PIN=27):
gdo0 = GPIO.input(GDO0_PIN) # Reads 1 or 0
gdo2 = GPIO.input(GDO2_PIN)
print(f"GDO0 (GPIO{GDO0_PIN}): {gdo0}, GDO2 (GPIO{GDO2_PIN}): {gdo2}")
sleep(0.1)
def digital_read(GDO_PIN: int):
return GPIO.input(GDO_PIN)
def get_addr(name: str):
addr = 0x00
stop = False
for reg_type, reg_data in regs_addr.items():
for reg_name, reg_addr in reg_data.items():
if reg_name == name:
stop = True
addr = int(reg_addr)
if stop == False:
raise Exception("Failed to find address for " + name)
return addr
def dump_regs(spi: SpiDev, cfgonly=False):
if cfgonly:
for reg_name, reg_addr in regs_addr["CONFIG_REGS"].items():
name: str = reg_name
value = rr(spi, reg_addr)
print((name + ":").ljust(15) + hex(value).ljust(4) + "\t" + str(value))
else:
for reg_type, reg_data in regs_addr.items():
for reg_name, reg_addr in reg_data.items():
name: str = reg_name
value = rr(spi, reg_addr)
print((name + ":").ljust(15) + hex(value).ljust(4) + "\t" + str(value))
# def disable_crc(spi):
# spi.xfer2([CONFIG_REGS["PKTCTRL0"], 0x01])
def sleep(t):
return time.sleep(t)
def delay(t):
"""Delay for t milliseconds."""
time.sleep(t / 1000.0)
def delayMicroseconds(t):
"""Delay for t microseconds."""
time.sleep(t / 1_000_000.0)

14
srfexp_json.xml Normal file
View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<registerexporttemplate>
<name><![CDATA[JSON]]></name>
<commentStart><![CDATA[//]]></commentStart>
<commentEnd><![CDATA[]]></commentEnd>
<paramSummary><![CDATA[0]]></paramSummary>
<paTable><![CDATA[0]]></paTable>
<header><![CDATA[{
]]></header>
<registers><![CDATA[ "@RN@"@<<@: @<<@{ "hex":"0x@VH@", "dec":@VD@},]]></registers>
<footer><![CDATA[}]]></footer>
<filename><![CDATA[@CHIPID@_simple_link_reg_config.json]]></filename>
<devices><![CDATA[]]></devices>
</registerexporttemplate>

0
tx_packets/activate.bin Normal file
View File

View File

@ -0,0 +1,6 @@
class SpiDev:
def open(self, bus: int, device: int) -> None: ...
def close(self) -> None: ...
def xfer2(self, data: list[int]) -> list[int]: ...
max_speed_hz: int
mode: int