import spidev
import time
import json
 
# Initialize SPI
global spi 
global init_data
# global regs_data
global CONFIG_REGS
global STROBES
global STATUS
global MEMORY
global MASKS
global ACCESS

def asb (a):
    return int(a,16)

def strobe(command):
    """Send a command strobe to CC2500"""
    spi.xfer2([command])

def write_reg(addr, value):
    """Write single byte to a register"""
    spi.xfer2([addr, value])

def burst_write(addr, data):
    """Write multiple bytes to FIFO or registers"""
    BURST = 0x40
    spi.xfer2([addr | BURST] + data)

def burst_read(addr, length):
    """Read multiple bytes"""
    READ_SINGLE = ACCESS["READ_SINGLE"]["dec"]
    READ_BURST = ACCESS["READ_BURST"]["dec"]
    return spi.xfer2([addr | READ_SINGLE | READ_BURST] + [0x00] * length)

def read_fifo():
    # Burst read RX FIFO
    READ_BURST = ACCESS["READ_BURST"]["dec"]
    RXFIFO = MEMORY["RXFIFI"]["dec"]
    fifo = spi.xfer2([RXFIFO | READ_BURST] + [0x00]*64)  # Max 64 bytes
    return fifo[1:]


def read_register(addr):
    READ_SINGLE = ACCESS["READ_SINGLE"]["dec"]
    # Send address | 0x80 (read), then 0x00 dummy to clock in response
    response = spi.xfer2([READ_SINGLE | addr, 0x00])
    return response[1]

def send_packet(data):
    # Flush TX FIFO
    strobe(0x3B)  # SFTX

    # Load data to TX FIFO (fixed length)
    burst_write(0x3F, data)  # 0x3F = TX FIFO

    # Strobe STX to transmit
    strobe(0x35)  # STX

    print(f"Sent: {data}")


def receive_packet():
    # Flush RX FIFO
    SFRX = STROBES["SFRX"]["dec"]
    strobe(SFRX)  # SFRX

    SRX = STROBES["SRX"]["dec"]
    # Go into RX mode
    strobe(SRX)  # SRX

    # Wait for data (use GDO0 in real app)
    time.sleep(0.5)

    # Check RXBYTES
    RXBYTES = STATUS["RXBYTES"]["dec"]
    rx_bytes = read_register(RXBYTES) & 0x7F
    if rx_bytes == 0:
        print("No data received.")
        return None

    # Read data
    RXFIFO = MEMORY["RXFIFO"]["dec"]
    data = read_fifo()  # 0x3F = RX FIFO
    print(f"Received: {data}")
    return data

def test_read_write_reg():
    FIFOTHR = CONFIG_REGS["FIFOTHR"]["dec"]
    print("reg ", hex(FIFOTHR))
    initial_val = read_register(FIFOTHR)
    test_value = initial_val + 1
    write_reg(FIFOTHR, test_value)
    check = read_register(FIFOTHR)
    write_reg(FIFOTHR, initial_val)
    print("initial value ", initial_val)
    print("test value ", test_value)
    print("check ",check)
    return check == test_value

def disable_crc():
    spi.xfer2([CONFIG_REGS["PKTCTRL0"]["dec"], 0x01])

def dump_reg():
    for reg_name_group, regs in regs_data.items():
        for reg_name, reg_loc in regs.items():
            addr = reg_loc['dec']
            reg_value = read_register(addr)
            print(reg_name + ":"+str(reg_value))

if __name__ == "__main__":
    spi = spidev.SpiDev()
    spi.open(0, 0)  # Bus 0, CE0 (Pin 24)
    spi.max_speed_hz = 2000000  # Safe start speed
    spi.mode = 0b00  # SPI mode 0
    
    
    with open("cc2500_init.json", "r") as f:
        init_data = json.load(f)
    with open("cc2500_regs.json", "r") as f:
        regs_data = json.load(f)
    CONFIG_REGS = regs_data["CONFIG_REGS"]
    STROBES = regs_data["STROBES"]
    STATUS = regs_data["STATUS"]
    MEMORY = regs_data["MEMORY"]
    MASKS = regs_data["MASKS"]
    ACCESS = regs_data["ACCESS"]

    SRES = STROBES["SRES"]["dec"]
    SNOP = STROBES["SNOP"]["dec"]
    VERSION = STATUS["VERSION"]["dec"]

    print("Sending SRES (reset)...")
    spi.xfer2([SRES])
    time.sleep(0.1)

    print("Sending SNOP (no-op)...")
    status = spi.xfer2([SNOP])[0]
    print(f"Status byte: 0x{status:02X}")

    print("Reading VERSION register...")
    version = read_register(VERSION)
    print(f"CC2500 VERSION register: 0x{version:02X}")  

    # dump_reg()

    for reg_name, values in init_data.items():
        addr_dec = regs_data["CONFIG_REGS"][reg_name]["dec"]
        addr_hex = regs_data["CONFIG_REGS"][reg_name]["hex"]
        value_hex = values["hex"]
        value_dec = values["dec"]
        # print(addr)
        # print(values["hex"])
        # print("writing "+str(addr_hex) + " to "+str(addr_dec))
        write_reg(addr_dec, value_dec)
    disable_crc()
    time.sleep(2)
    # dump_reg()
    print("Read + Write test ", test_read_write_reg())
    try:
        while True:
            receive_packet()
            time.sleep(1)
    finally:
        spi.close()
