Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
rcguserIop.c 17.08 KiB
///	@file rcguserIop.c
///	@brief File contains startup routines for IOP running in user space.

#include <unistd.h>
#include <ctype.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/file.h>
#include <stdio.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <errno.h>
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>

// These externs and "16" need to go to a header file (mbuf.h)
extern int   fe_start_iop_user( );
extern char  daqArea[ 2 * DAQ_DCU_SIZE ]; // Space allocation for daqLib buffers
extern char* addr;
extern int   cycleOffset;

// Scan a double
#if 0
double
simple_strtod(char *start, char **end) {
	int integer;
	if (*start != '.') {
		integer = simple_strtol(start, end, 10);
        	if (*end == start) return 0.0;
		start = *end;
	} else integer = 0;
	if (*start != '.') return integer;
	else {
		start++;
		double frac = simple_strtol(start, end, 10);
        	if (*end == start) return integer;
		int i;
		for (i = 0; i < (*end - start); i++) frac /= 10.0;
		return ((double)integer) + frac;
	}
	// Never reached
}
#endif

void
usage( )
{
    fprintf( stderr, "Usage: rcgUser -m system_name \n" );
    fprintf( stderr, "-h - help\n" );
}

/// Startup function for initialization of kernel module.
int
main( int argc, char** argv )
{
    int  status;
    int  ii, jj, kk, mm; /// @param ii,jj,kk default loop counters
    char fname[ 128 ]; /// @param fname[128] Name of shared mem area to allocate
                       /// for DAQ data
    int cards; /// @param cards Number of PCIe cards found on bus
    int adcCnt; /// @param adcCnt Number of ADC cards found by slave model.
    int dacCnt; /// @param dacCnt Number of 16bit DAC cards found by slave
                /// model.
    int dac18Cnt; /// @param dac18Cnt Number of 18bit DAC cards found by slave
                  /// model.
    int doCnt; /// @param doCnt Total number of digital I/O cards found by slave
               /// model.
    int do32Cnt; /// @param do32Cnt Total number of Contec 32 bit DIO cards
                 /// found by slave model.
    int doIIRO16Cnt; /// @param doIIRO16Cnt Total number of Acces I/O 16 bit
                     /// relay cards found by slave model.
    int doIIRO8Cnt; /// @param doIIRO8Cnt Total number of Acces I/O 8 bit relay
                    /// cards found by slave model.
    int cdo64Cnt; /// @param cdo64Cnt Total number of Contec 6464 DIO card 32bit
                  /// output sections mapped by slave model.
    int cdi64Cnt; /// @param cdo64Cnt Total number of Contec 6464 DIO card 32bit
                  /// input sections mapped by slave model.
    int ret; /// @param ret Return value from various Malloc calls to allocate
             /// memory.
    int   cnt;
    char* sysname;
    char  shm_name[ 64 ];
    int   c;
    char* modelname;

    cycleOffset = 0;

    while ( ( c = getopt( argc, argv, "m:t:help" ) ) != EOF )
        switch ( c )
        {
        case 'm':
            sysname = optarg;
            printf( "sysname = %s\n", sysname );
            break;
        case 't':
            cycleOffset = atoi( optarg );
            printf( "cycle offset = %d\n", cycleOffset );
            break;
        case 'help':
        default:
            usage( );
            exit( 1 );
        }

    kk = 0;

    jj = 0;
    int   i = 0;
    char* p = strtok( argv[ 0 ], "/" );
    char* array[ 5 ];

    while ( p != NULL )
    {
        array[ i++ ] = p;
        p = strtok( NULL, "/" );
    }
    modelname = array[ i - 1 ];
    sysname = array[ i - 1 ];

    printf( "model name is %s \n", sysname );

    sprintf( shm_name, "%s", sysname );
    findSharedMemory( sysname );
    _epics_shm = (char*)addr;
    ;
    if ( _epics_shm < 0 )
    {
        printf( "mbuf_allocate_area() failed; ret = %d\n", _epics_shm );
        return -1;
    }
    printf( "EPICSM at 0x%lx\n", (long)_epics_shm );

    sprintf( shm_name, "%s", "ipc" );
    findSharedMemory( "ipc" );
    _ipc_shm = (char*)addr;
    if ( _ipc_shm < 0 )
    {
        printf( "mbuf_allocate_area(ipc) failed; ret = %d\n", _ipc_shm );
        return -1;
    }

    printf( "IPC    at 0x%lx\n", (long)_ipc_shm );
    ioMemData = (volatile IO_MEM_DATA*)( ( (char*)_ipc_shm ) + 0x4000 );
    printf(
        "IOMEM  at 0x%lx size 0x%x\n", (long)ioMemData, sizeof( IO_MEM_DATA ) );
    printf( "%d PCI cards found\n", ioMemData->totalCards );

    // If DAQ is via shared memory (Framebuilder code running on same machine or
    // MX networking is used) attach DAQ shared memory location.
    sprintf( shm_name, "%s_daq", sysname );
    findSharedMemory( shm_name );
    _daq_shm = (char*)addr;
    if ( _daq_shm < 0 )
    {
        printf( "mbuf_allocate_area() failed; ret = %d\n", _daq_shm );
        return -1;
    }
    // printf("Allocated daq shmem; set at 0x%x\n", _daq_shm);
    printf( "DAQSM at 0x%lx\n", _daq_shm );
    daqPtr = (struct rmIpcStr*)_daq_shm;

    // Open new IO shared memory in support of no hardware I/O
    sprintf( shm_name, "%s_io_space", sysname );
    findSharedMemory( shm_name );
    _io_shm = (char*)addr;
    if ( _io_shm < 0 )
    {
        printf( "mbuf_allocate_area() failed; ret = %d\n", _io_shm );
        return -1;
    }
    printf( "IO SPACE at 0x%lx\n", _io_shm );
    ioMemDataIop = (volatile IO_MEM_DATA_IOP*)( ( (char*)_io_shm ) );

    // Find and initialize all PCI I/O modules
    // ******************************************************* Following I/O
    // card info is from feCode
    cards = sizeof( cards_used ) / sizeof( cards_used[ 0 ] );
    printf( "configured to use %d cards\n", cards );
    cdsPciModules.cards = cards;
    cdsPciModules.cards_used = cards_used;
    // return -1;
    printf( "Initializing PCI Modules for IOP\n" );
    for ( jj = 0; jj < cards; jj++ )
        printf(
            "Card %d type = %d\n", jj, cdsPciModules.cards_used[ jj ].type );
    cdsPciModules.adcCount = 0;
    cdsPciModules.dacCount = 0;
    cdsPciModules.dioCount = 0;
    cdsPciModules.doCount = 0;

    // If running as a slave process, I/O card information is via ipc shared
    // memory
    printf( "%d PCI cards found\n", cards );
    status = 0;
    adcCnt = 0;
    dacCnt = 0;
    dac18Cnt = 0;
    doCnt = 0;
    do32Cnt = 0;
    cdo64Cnt = 0;
    cdi64Cnt = 0;
    doIIRO16Cnt = 0;
    doIIRO8Cnt = 0;

    ioMemData->totalCards = cards;
    // Have to search thru all cards and find desired instance for application
    // Master will map ADC cards first, then DAC and finally DIO
    for ( jj = 0; jj < cards; jj++ )
    {
        /*
        printf("Model %d = %d, type = %d, instance = %d, dacCnt = %d \n",
                ii,ioMemData->model[ii],
                cdsPciModules.cards_used[jj].type,
                cdsPciModules.cards_used[jj].instance,
                dacCnt);
                */
        switch ( cdsPciModules.cards_used[ jj ].type )
        {
        case GSC_16AI64SSA:
            kk = cdsPciModules.adcCount;
            cdsPciModules.adcType[ kk ] = GSC_16AI64SSA;
            cdsPciModules.adcCount++;
            status++;
            break;
        case GSC_16AO16:
            kk = cdsPciModules.dacCount;
            cdsPciModules.dacType[ kk ] = GSC_16AO16;
            cdsPciModules.dacCount++;
            status++;
            break;
        case GSC_18AO8:
            kk = cdsPciModules.dacCount;
            cdsPciModules.dacType[ kk ] = GSC_18AO8;
            cdsPciModules.dacCount++;
            status++;
            break;
        case CON_6464DIO:
            kk = cdsPciModules.doCount;
            cdsPciModules.doType[ kk ] = CON_6464DIO;
            cdsPciModules.doCount++;
            cdsPciModules.cDio6464lCount++;
            // cdsPciModules.doInstance[kk] = cDio6464lCount;
            status += 2;
            break;
        case CON_32DO:
            kk = cdsPciModules.doCount;
            cdsPciModules.doType[ kk ] = CON_32DO;
            cdsPciModules.doCount++;
            cdsPciModules.cDo32lCount++;
            cdsPciModules.doInstance[ kk ] = do32Cnt;
            status++;
            break;
        case ACS_16DIO:
            kk = cdsPciModules.doCount;
            cdsPciModules.doCount++;
            cdsPciModules.iiroDio1Count++;
            cdsPciModules.doInstance[ kk ] = doIIRO16Cnt;
            status++;
            break;
        case ACS_8DIO:
            kk = cdsPciModules.doCount;
            cdsPciModules.doCount++;
            cdsPciModules.iiroDioCount++;
            cdsPciModules.doInstance[ kk ] = doIIRO8Cnt;
            status++;
            break;
        default:
            break;
        }
    }
    // If no ADC cards were found, then SLAVE cannot run
    if ( !cdsPciModules.adcCount )
    {
        printf( "No ADC cards found - exiting\n" );
        return -1;
    }
    // This did not quite work for some reason
    // Need to find a way to handle skipped DAC cards in slaves
    // cdsPciModules.dacCount = ioMemData->dacCount;

    printf( "%d PCI cards found \n", status );
    if ( status < cards )
    {
        printf( " ERROR **** Did not find correct number of cards! Expected %d "
                "and Found %d\n",
                cards,
                status );
        cardCountErr = 1;
    }

    // Print out all the I/O information
    printf( "******************************************************************"
            "*********\n" );
    // Master send module counds to SLAVE via ipc shm
    ioMemData->totalCards = status;
    ioMemData->adcCount = cdsPciModules.adcCount;
    ioMemData->dacCount = cdsPciModules.dacCount;
    ioMemData->bioCount = cdsPciModules.doCount;
    // kk will act as ioMem location counter for mapping modules
    kk = cdsPciModules.adcCount;
    printf( "%d ADC cards found\n", cdsPciModules.adcCount );
    for ( ii = 0; ii < cdsPciModules.adcCount; ii++ )
    {
        // MASTER maps ADC modules first in ipc shm for SLAVES
        ioMemData->model[ ii ] = cdsPciModules.adcType[ ii ];
        ioMemData->ipc[ ii ] =
            ii; // ioData memory buffer location for SLAVE to use
        ioMemDataIop->model[ ii ] = cdsPciModules.adcType[ ii ];
        ioMemDataIop->ipc[ ii ] =
            ii; // ioData memory buffer location for SLAVE to use
        for ( jj = 0; jj < 65536; jj++ )
        {
            for ( mm = 0; mm < 32; mm++ )
            {
                ioMemDataIop->iodata[ ii ][ jj ].data[ mm ] = jj - 32767;
            }
        }
        if ( cdsPciModules.adcType[ ii ] == GSC_18AISS6C )
        {
            printf( "\tADC %d is a GSC_18AISS6C module\n", ii );
            printf( "\t\tChannels = 6 \n" );
            printf( "\t\tFirmware Rev = %d \n\n",
                    ( cdsPciModules.adcConfig[ ii ] & 0xfff ) );
        }
        if ( cdsPciModules.adcType[ ii ] == GSC_16AI64SSA )
        {
            printf( "\tADC %d is a GSC_16AI64SSA module\n", ii );
            if ( ( cdsPciModules.adcConfig[ ii ] & 0x10000 ) > 0 )
                jj = 32;
            else
                jj = 64;
            printf( "\t\tChannels = %d \n", jj );
            printf( "\t\tFirmware Rev = %d \n\n",
                    ( cdsPciModules.adcConfig[ ii ] & 0xfff ) );
        }
    }
    printf( "******************************************************************"
            "*********\n" );
    printf( "%d DAC cards found\n", cdsPciModules.dacCount );
    for ( ii = 0; ii < cdsPciModules.dacCount; ii++ )
    {
        if ( cdsPciModules.dacType[ ii ] == GSC_18AO8 )
        {
            printf( "\tDAC %d is a GSC_18AO8 module\n", ii );
        }
        if ( cdsPciModules.dacType[ ii ] == GSC_16AO16 )
        {
            printf( "\tDAC %d is a GSC_16AO16 module\n", ii );
            if ( ( cdsPciModules.dacConfig[ ii ] & 0x10000 ) == 0x10000 )
                jj = 8;
            if ( ( cdsPciModules.dacConfig[ ii ] & 0x20000 ) == 0x20000 )
                jj = 12;
            if ( ( cdsPciModules.dacConfig[ ii ] & 0x30000 ) == 0x30000 )
                jj = 16;
            printf( "\t\tChannels = %d \n", jj );
            if ( ( cdsPciModules.dacConfig[ ii ] & 0xC0000 ) == 0x0000 )
            {
                printf( "\t\tFilters = None\n" );
            }
            if ( ( cdsPciModules.dacConfig[ ii ] & 0xC0000 ) == 0x40000 )
            {
                printf( "\t\tFilters = 10kHz\n" );
            }
            if ( ( cdsPciModules.dacConfig[ ii ] & 0xC0000 ) == 0x80000 )
            {
                printf( "\t\tFilters = 100kHz\n" );
            }
            if ( ( cdsPciModules.dacConfig[ ii ] & 0x100000 ) == 0x100000 )
            {
                printf( "\t\tOutput Type = Differential\n" );
            }
            printf( "\t\tFirmware Rev = %d \n\n",
                    ( cdsPciModules.dacConfig[ ii ] & 0xfff ) );
        }
        // Pass DAC info to SLAVE processes
        ioMemData->model[ kk ] = cdsPciModules.dacType[ ii ];
        ioMemData->ipc[ kk ] = kk;
        // Following used by MASTER to point to ipc memory for inputting DAC
        // data from SLAVES
        cdsPciModules.dacConfig[ ii ] = kk;
        printf( "MASTER DAC SLOT %d %d\n", ii, cdsPciModules.dacConfig[ ii ] );
        kk++;
    }
    printf( "******************************************************************"
            "*********\n" );
    printf( "%d DIO cards found\n", cdsPciModules.dioCount );
    printf( "******************************************************************"
            "*********\n" );
    printf( "%d IIRO-8 Isolated DIO cards found\n",
            cdsPciModules.iiroDioCount );
    printf( "******************************************************************"
            "*********\n" );
    printf( "%d IIRO-16 Isolated DIO cards found\n",
            cdsPciModules.iiroDio1Count );
    printf( "******************************************************************"
            "*********\n" );
    printf( "%d Contec 32ch PCIe DO cards found\n", cdsPciModules.cDo32lCount );
    printf( "%d Contec PCIe DIO1616 cards found\n",
            cdsPciModules.cDio1616lCount );
    printf( "%d Contec PCIe DIO6464 cards found\n",
            cdsPciModules.cDio6464lCount );
    printf( "%d DO cards found\n", cdsPciModules.doCount );
    // MASTER sends DIO module information to SLAVES
    // Note that for DIO, SLAVE modules will perform the I/O directly and
    // therefore need to know the PCIe address of these modules.
    ioMemData->bioCount = cdsPciModules.doCount;
    for ( ii = 0; ii < cdsPciModules.doCount; ii++ )
    {
        // MASTER needs to find Contec 1616 I/O card to control timing slave.
        if ( cdsPciModules.doType[ ii ] == CON_1616DIO )
        {
            tdsControl[ tdsCount ] = ii;
            printf( "TDS controller %d is at %d\n", tdsCount, ii );
            tdsCount++;
        }
        ioMemData->model[ kk ] = cdsPciModules.doType[ ii ];
        // Unlike ADC and DAC, where a memory buffer number is passed, a PCIe
        // address is passed for DIO cards.
        ioMemData->ipc[ kk ] = kk;
        kk++;
    }
    printf( "Total of %d I/O modules found and mapped\n", kk );
    printf( "******************************************************************"
            "*********\n" );
    // Following section maps Reflected Memory, both VMIC hardware style and
    // Dolphin PCIe network style. Slave units will perform I/O transactions
    // with RFM directly ie MASTER does not do RFM I/O. Master unit only maps
    // the RFM I/O space and passes pointers to SLAVES.

    printf( "%d RFM cards found\n", cdsPciModules.rfmCount );
    ioMemData->rfmCount = cdsPciModules.rfmCount;
    for ( ii = 0; ii < cdsPciModules.rfmCount; ii++ )
    {
        printf( "\tRFM %d is a VMIC_%x module with Node ID %d\n",
                ii,
                cdsPciModules.rfmType[ ii ],
                cdsPciModules.rfmConfig[ ii ] );
        printf( "address is 0x%lx\n", cdsPciModules.pci_rfm[ ii ] );
        // Master sends RFM memory pointers to SLAVES
        ioMemData->pci_rfm[ ii ] = cdsPciModules.pci_rfm[ ii ];
        ioMemData->pci_rfm_dma[ ii ] = cdsPciModules.pci_rfm_dma[ ii ];
    }
    // ioMemData->dolphinCount = 0;
#ifdef DOLPHIN_TEST
    ioMemData->dolphinCount = cdsPciModules.dolphinCount;
    ioMemData->dolphinRead[ 0 ] = cdsPciModules.dolphinRead[ 0 ];
    ioMemData->dolphinWrite[ 0 ] = cdsPciModules.dolphinWrite[ 0 ];

#else
    // Clear Dolphin pointers so the slave sees NULLs
    ioMemData->dolphinCount = 0;
    ioMemData->dolphinRead[ 0 ] = 0;
    ioMemData->dolphinWrite[ 0 ] = 0;
#endif
    printf( "******************************************************************"
            "*********\n" );
    if ( cdsPciModules.gps )
    {
        printf( "IRIG-B card found %d\n", cdsPciModules.gpsType );
        printf( "**************************************************************"
                "*************\n" );
    }

    // Initialize buffer for daqLib.c code
    printf( "Initializing space for daqLib buffers\n" );
    daqBuffer = (long)&daqArea[ 0 ];

    pLocalEpics = (CDS_EPICS*)&( (RFM_FE_COMMS*)_epics_shm )->epicsSpace;
    for ( cnt = 0; cnt < 10 && pLocalEpics->epicsInput.burtRestore == 0; cnt++ )
    {
        printf( "Epics burt restore is %d\n",
                pLocalEpics->epicsInput.burtRestore );
        usleep( 1000000 );
    }
    if ( cnt == 10 )
    {
        return -1;
    }

    pLocalEpics->epicsInput.vmeReset = 0;
    fe_start_iop_user( );

    return 0;
}