# This program loads the two PRU programs into the PRU-ICSS transfers the configuration
# to the PRU memory spaces and starts the execution of both PRU programs.
# pressed. By Derek Molloy, for the book Exploring BeagleBone. Please see:
#      www.exploringbeaglebone.com/chapter13
# for a full description of this code example and the associated programs.

# include <stdio.h>
# include <stdlib.h>
# include <prussdrv.h>
# include <pruss_intc_mapping.h>

import os

ADC_PRU_NUM = 0  # using PRU0 for the ADC capture
CLK_PRU_NUM = 1  # using PRU1 for the sample clock
MMAP0_LOC = "/sys/class/uio/uio0/maps/map0/"
MMAP1_LOC = "/sys/class/uio/uio0/maps/map1/"

# enum FREQUENCY {    // measured and calibrated, but can be calculated
# 	FREQ_12_5MHz =  1,
# 	FREQ_6_25MHz =  5,
# 	FREQ_5MHz    =  7,
# 	FREQ_3_85MHz = 10,
# 	FREQ_1MHz   =  45,
# 	FREQ_500kHz =  95,
# 	FREQ_250kHz = 245,
# 	FREQ_100kHz = 495,
# 	FREQ_25kHz = 1995,
# 	FREQ_10kHz = 4995,
# 	FREQ_5kHz =  9995,
# 	FREQ_2kHz = 24995,
# 	FREQ_1kHz = 49995
# };

# enum CONTROL {
# 	PAUSED = 0,
# 	RUNNING = 1,
# 	UPDATE = 3
# };


class PRUMemory:
    def __init__(self, pru_number: int):
        assert pru_number in (0, 1), pru_number
        self._pru_number = pru_number
        self._mem_path = "/sys/class/uio/uio0/maps/map" + str(self._pru_number)

    def _read_hex_file_to_int(self, path: str):
        assert os.path.exists(path), path
        return int(open(path, "rb").read(4), base=16)

    def _mmap_location(self) -> tuple:
        address = self._read_hex_file_to_int(os.path.join(self._mem_path, "addr"))
        size = self._read_hex_file_to_int(os.path.join(self._mem_path, "size"))
        return address, size

    def get_memory(self) -> memoryview:
        pass

# int main (void)
# {
#    if(getuid()!=0){
#       printf("You must run this program as root. Exiting.\n");
#       exit(EXIT_FAILURE);
#    }
#    // Initialize structure used by prussdrv_pruintc_intc
#    // PRUSS_INTC_INITDATA is found in pruss_intc_mapping.h
#    tpruss_intc_initdata pruss_intc_initdata = PRUSS_INTC_INITDATA;

#    // Read in the location and address of the shared memory. This value changes
#    // each time a new block of memory is allocated.
#    unsigned int timerData[2];
#    timerData[0] = FREQ_100kHz;
#    timerData[1] = RUNNING;
#    printf("The PRU clock state is set as period: %d (0x%x) and state: %d\n", timerData[0], timerData[0], timerData[1]);
#    unsigned int PRU_data_addr = readFileValue(MMAP0_LOC "addr");
#    printf("-> the PRUClock memory is mapped at the base address: %x\n", (PRU_data_addr + 0x2000));
#    printf("-> the PRUClock on/off state is mapped at address: %x\n", (PRU_data_addr + 0x10000));

#    // data for PRU0 based on the MCPXXXX datasheet
#    unsigned int spiData[3];
#    spiData[0] = 0x01800000;
#    spiData[1] = readFileValue(MMAP1_LOC "addr");
#    spiData[2] = readFileValue(MMAP1_LOC "size");
#    printf("Sending the SPI Control Data: 0x%x\n", spiData[0]);
#    printf("The DDR External Memory pool has location: 0x%x and size: 0x%x bytes\n", spiData[1], spiData[2]);
#    int numberSamples = spiData[2]/2;
#    printf("-> this space has capacity to store %d 16-bit samples (max)\n", numberSamples);

#    // Allocate and initialize memory
#    prussdrv_init ();
#    prussdrv_open (PRU_EVTOUT_0);

#    // Write the address and size into PRU0 Data RAM0. You can edit the value to
#    // PRUSS0_PRU1_DATARAM if you wish to write to PRU1
#    prussdrv_pru_write_memory(PRUSS0_PRU0_DATARAM, 0, spiData, 12);  // spi code
#    prussdrv_pru_write_memory(PRUSS0_PRU1_DATARAM, 0, timerData, 8); // sample clock

#    // Map the PRU's interrupts
#    prussdrv_pruintc_init(&pruss_intc_initdata);

#    // Load and execute the PRU program on the PRU
#    prussdrv_exec_program (ADC_PRU_NUM, "./PRUADC.bin");
#    prussdrv_exec_program (CLK_PRU_NUM, "./PRUClock.bin");
#    printf("EBBClock PRU1 program now running (%d)\n", timerData[0]);

#    // Wait for event completion from PRU, returns the PRU_EVTOUT_0 number
#    int n = prussdrv_pru_wait_event (PRU_EVTOUT_0);
#    printf("EBBADC PRU0 program completed, event number %d.\n", n);

# // Disable PRU and close memory mappings 
#    prussdrv_pru_disable(ADC_PRU_NUM);
#    prussdrv_pru_disable(CLK_PRU_NUM);

#    prussdrv_exit ();
#    return EXIT_SUCCESS;
# }