Ejemplo n.º 1
0
/**  This function runs as a polling task at the system clock rate if there is no interrupt driver (such as Ip-Unidig) being used */
void drvAPS_EM::pollerThread()
{
    while(1) { /* Do forever */
        if (acquiring_) callbackFunc(0);
        epicsThreadSleep(epicsThreadSleepQuantum());
    }
}
Ejemplo n.º 2
0
/*
 * Ensure func() is run only once.
 */
void epicsThreadOnce(epicsThreadOnceId *id, void(*func)(void *), void *arg)
{
    #define EPICS_THREAD_ONCE_DONE (epicsThreadId) 1

    if (!initialized) epicsThreadInit();
    epicsMutexMustLock(onceMutex);
    if (*id != EPICS_THREAD_ONCE_DONE) {
        if (*id == EPICS_THREAD_ONCE_INIT) { /* first call */
            *id = epicsThreadGetIdSelf();    /* mark active */
            epicsMutexUnlock(onceMutex);
            func(arg);
            epicsMutexMustLock(onceMutex);
            *id = EPICS_THREAD_ONCE_DONE;    /* mark done */
        } else if (*id == epicsThreadGetIdSelf()) {
            epicsMutexUnlock(onceMutex);
            cantProceed("Recursive epicsThreadOnce() initialization\n");
        } else
            while (*id != EPICS_THREAD_ONCE_DONE) {
                /* Another thread is in the above func(arg) call. */
                epicsMutexUnlock(onceMutex);
                epicsThreadSleep(epicsThreadSleepQuantum());
                epicsMutexMustLock(onceMutex);
            }
    }
    epicsMutexUnlock(onceMutex);
}
Ejemplo n.º 3
0
static void initPeriodic(void)
{
    dbMenu *pmenu = dbFindMenu(pdbbase, "menuScan");
    double quantum = epicsThreadSleepQuantum();
    int i;

    if (!pmenu) {
        errlogPrintf("initPeriodic: menuScan not present\n");
        return;
    }
    nPeriodic = pmenu->nChoice - SCAN_1ST_PERIODIC;
    papPeriodic = dbCalloc(nPeriodic, sizeof(periodic_scan_list*));
    periodicTaskId = dbCalloc(nPeriodic, sizeof(void *));
    for (i = 0; i < nPeriodic; i++) {
        periodic_scan_list *ppsl = dbCalloc(1, sizeof(periodic_scan_list));
        const char *choice = pmenu->papChoiceValue[i + SCAN_1ST_PERIODIC];
        double number;
        char *unit;
        int status = epicsParseDouble(choice, &number, &unit);

        ppsl->scan_list.lock = epicsMutexMustCreate();
        ellInit(&ppsl->scan_list.list);
        ppsl->name = choice;
        if (status || number == 0) {
            errlogPrintf("initPeriodic: Bad menuScan choice '%s'\n", choice);
            ppsl->period = i;
        }
        else if (!*unit ||
                 !epicsStrCaseCmp(unit, "second") ||
                 !epicsStrCaseCmp(unit, "seconds")) {
            ppsl->period = number;
        }
        else if (!epicsStrCaseCmp(unit, "minute") ||
                 !epicsStrCaseCmp(unit, "minutes")) {
            ppsl->period = number * 60;
        }
        else if (!epicsStrCaseCmp(unit, "hour") ||
                 !epicsStrCaseCmp(unit, "hours")) {
            ppsl->period = number * 60 * 60;
        }
        else if (!epicsStrCaseCmp(unit, "Hz") ||
                 !epicsStrCaseCmp(unit, "Hertz")) {
            ppsl->period = 1 / number;
        }
        else {
            errlogPrintf("initPeriodic: Bad menuScan choice '%s'\n", choice);
            ppsl->period = i;
        }
        number = ppsl->period / quantum;
        if ((ppsl->period < 2 * quantum) ||
            (number / floor(number) > 1.1)) {
            errlogPrintf("initPeriodic: Scan rate '%s' is not achievable.\n",
                choice);
        }
        ppsl->scanCtl = ctlPause;
        ppsl->loopEvent = epicsEventMustCreate(epicsEventEmpty);

        papPeriodic[i] = ppsl;
    }
}
timerQueueActive ::
    timerQueueActive ( RefMgr & refMgr, 
        bool okToShareIn, unsigned priority ) :
    _refMgr ( refMgr ), queue ( *this ), thread ( *this, "timerQueue", 
        epicsThreadGetStackSize ( epicsThreadStackMedium ), priority ),
    sleepQuantum ( epicsThreadSleepQuantum() ), okToShare ( okToShareIn ), 
    exitFlag ( false ), terminateFlag ( false )
{
}
Ejemplo n.º 5
0
/** Report  parameters 
  * \param[in] fp The file pointer to write to
  * \param[in] details The level of detail requested
  */
void drvAPS_EM::report(FILE *fp, int details)
{
    fprintf(fp, "Port: %s, address %p\n", portName, baseAddress_);
    if (details >= 1) {
        if (pUInt32DigitalPvt_) {
           fprintf(fp, "    Using digital I/O interrupts\n");
        } else {
           fprintf(fp, "    Not using interrupts, scan time=%f\n", epicsThreadSleepQuantum());
        }
    }
    drvQuadEM::report(fp, details);
}
Ejemplo n.º 6
0
/* Some sample loads on MVME167:
*
*	-> sp jbk_artificial_load, 100000000, 10000, 1
*		Load average: 69%
*	-> sp jbk_artificial_load, 100000000, 100000, 1
*		Load average: 95%
*	-> sp jbk_artificial_load, 100000000, 25000, 1
*		Load average: 88%
*/
int jbk_artificial_load(unsigned long iter,unsigned long often,unsigned long tick_delay)
{
    volatile unsigned long i;
    double   delay = (double)tick_delay * epicsThreadSleepQuantum();

    if(iter==0)
    {
        printf("Usage: jbk_artificial_load(num_iterations,iter_betwn_delays,tick_delay)\n");
        return 0;
    }

    for(i=0; i<iter; i++)
    {
        if(i%often==0)
            epicsThreadSleep(delay);
    }

    return 0;
}
Ejemplo n.º 7
0
void SimADC::run()
{
    const double min_sleep = epicsThreadSleepQuantum();

    sim_global_type::guard_t G(mutex);

    while(true) {
        {
            double zzz = rate.value>0.0 ? 1.0/rate.value : min_sleep;
            sim_global_type::unguard_t U(G);
            epicsThreadSleep(zzz);
        }
        if(runner_stop)
            break;

        cycle();
    }
    printf("SimADC shutdown\n");
}
Ejemplo n.º 8
0
epicsShareFunc void epicsShareAPI epicsThreadOnce(epicsThreadOnceId *id, void (*func)(void *), void *arg)
{
    static struct epicsThreadOSD threadOnceComplete;
    #define EPICS_THREAD_ONCE_DONE &threadOnceComplete
    int status;

    epicsThreadInit();
    status = mutexLock(&onceLock);
    if(status) {
        fprintf(stderr,"epicsThreadOnce: pthread_mutex_lock returned %s.\n",
            strerror(status));
        exit(-1);
    }

    if (*id != EPICS_THREAD_ONCE_DONE) {
        if (*id == EPICS_THREAD_ONCE_INIT) { /* first call */
            *id = epicsThreadGetIdSelf();    /* mark active */
            status = pthread_mutex_unlock(&onceLock);
            checkStatusQuit(status,"pthread_mutex_unlock", "epicsThreadOnce");
            func(arg);
            status = mutexLock(&onceLock);
            checkStatusQuit(status,"pthread_mutex_lock", "epicsThreadOnce");
            *id = EPICS_THREAD_ONCE_DONE;    /* mark done */
        } else if (*id == epicsThreadGetIdSelf()) {
            status = pthread_mutex_unlock(&onceLock);
            checkStatusQuit(status,"pthread_mutex_unlock", "epicsThreadOnce");
            cantProceed("Recursive epicsThreadOnce() initialization\n");
        } else
            while (*id != EPICS_THREAD_ONCE_DONE) {
                /* Another thread is in the above func(arg) call. */
                status = pthread_mutex_unlock(&onceLock);
                checkStatusQuit(status,"pthread_mutex_unlock", "epicsThreadOnce");
                epicsThreadSleep(epicsThreadSleepQuantum());
                status = mutexLock(&onceLock);
                checkStatusQuit(status,"pthread_mutex_lock", "epicsThreadOnce");
            }
    }
    status = pthread_mutex_unlock(&onceLock);
    checkStatusQuit(status,"pthread_mutex_unlock","epicsThreadOnce");
}
Ejemplo n.º 9
0
/** Reads the settings back from the electrometer.
  * On the APS_EM this just computes the SampleTime based on the IntegrationTime and valuesPerRead. 
  */
asynStatus drvAPS_EM::readStatus() 
{
    double integrationTime, sampleTime, averagingTime;
    int numAverage;
    
    getDoubleParam(P_IntegrationTime, &integrationTime);
    /* If we are using the interrupts then this is the scan rate
     * except that we only get interrupts after every other cycle
     * because of ping/pong, so we multiply by 2. */
    if (pUInt32DigitalPvt_ != NULL) {
        sampleTime = 2. * integrationTime;
    } else {
        sampleTime = epicsThreadSleepQuantum();
    }
    sampleTime = sampleTime * valuesPerRead_;
    setDoubleParam(P_SampleTime, sampleTime);

    // Compute the number of values that will be accumulated in the ring buffer before averaging
    getDoubleParam(P_AveragingTime, &averagingTime);
    numAverage = (int)((averagingTime / sampleTime) + 0.5);
    setIntegerParam(P_NumAverage, numAverage);

    return asynSuccess;
}
Ejemplo n.º 10
0
/** This thread is woken up by an interrupt or a request to read status
  * It loops calling readFIFO until acquiring_ goes to false.
  * readFIFO only reads a limited amount of FIFO data at once in order
  * to avoid blocking the device support threads. */
void drvSIS3801::readFIFOThread()
{
  int count;
  int signal;
  int chan;
  int nChans;
  int status;
  int i;
  bool acquiring;  // We have a separate flag because we need to continue processing one last
                   // time even if acquiring_ goes to false because acquisition was manually stopped
  epicsUInt32 scalerPresets[SIS38XX_MAX_SIGNALS];
  epicsUInt32 *pOut=NULL;
  epicsTimeStamp t1, t2;
  static const char* functionName="readFIFOThread";

  while(true)
  {
    epicsEventWait(readFIFOEventId_);
    // We got an event, which can come from acquisition starting, or FIFO full interrupt
    asynPrint(pasynUserSelf, ASYN_TRACE_FLOW,
              "%s:%s: got readFIFOEvent, eventType=%d, interrupt status=0x%8.8x\n",
              driverName, functionName, eventType_, registers_->csr_reg & 0xFFF00000);
    lock();
    acquiring = acquiring_;
    unlock();
    while (acquiring) {
      lock();
      for (i=0; i<maxSignals_; i++) 
        getIntegerParam(i, scalerPresets_, (int *)&scalerPresets[i]);
      getIntegerParam(mcaNumChannels_, &nChans);
      asynPrint(pasynUserSelf, ASYN_TRACE_FLOW,
                "%s:%s: scaler presets[0]=%d, scalerData[0]=%d\n",
                driverName, functionName, scalerPresets[0], scalerData_[0]);
      signal = nextSignal_;
      chan = nextChan_;
      count = 0;
      // This block of code can be slow and does not require the asynPortDriver lock because we are not
      // accessing object data that could change.  
      // It does require the FIFO lock so no one resets the FIFO while it executes
      epicsMutexLock(fifoLockId_);
      unlock();
      epicsTimeGetCurrent(&t1);

      /* Read out FIFO. It would be more efficient not to check the empty
       * flag on each transfer, using the almost empty flag.  But this has gotten
       * too complex, and is unlikely to save time on new boards with lots of
       * memory.
       */
      if (acquireMode_== ACQUIRE_MODE_MCS) {
        // Copy the data from the FIFO to the mcsBuffer
        pOut = mcsData_ + signal*maxChans_ + chan;
        asynPrint(pasynUserSelf, ASYN_TRACE_FLOW,
                  "%s:%s: pOut=%p, signal=%d, chan=%d\n",
                  driverName, functionName, pOut, signal, chan);
        while (((registers_->csr_reg & STATUS_M_FIFO_FLAG_EMPTY)==0) && (chan < nChans) && acquiring_) {
          *pOut = registers_->fifo_reg;
          signal++;
          count++;
          if (signal >= maxSignals_) {
            signal = 0;
            chan++;
            pOut = mcsData_ + chan;
          } else {
            pOut += maxChans_;
          }
        }
      } else if (acquireMode_ == ACQUIRE_MODE_SCALER) {
        while ((registers_->csr_reg & STATUS_M_FIFO_FLAG_EMPTY)==0 && acquiring_) {
          scalerData_[signal] += registers_->fifo_reg;
          signal++;
          count++;
          if (signal >= maxSignals_) {
            for (i=0; i<maxSignals_; i++) {
              if ((scalerPresets[i] != 0) && 
                  (scalerData_[i] >= scalerPresets[i]))
                acquiring = false;
            }
            asynPrintIO(pasynUserSelf, ASYN_TRACEIO_DRIVER, 
                      (const char*)scalerData_, maxSignals_*sizeof(epicsUInt32), 
                      "%s:%s:\n",
                      driverName, functionName);
            if (!acquiring) break;
            signal = 0;
          }
        }
      }
      epicsTimeGetCurrent(&t2);

      asynPrint(pasynUserSelf, ASYN_TRACE_FLOW, 
                "%s:%s: read FIFO (%d) in %fs, acquiring=%d\n",
                driverName, functionName, count, epicsTimeDiffInSeconds(&t2, &t1), acquiring_);
      // Release the FIFO lock, we are done accessing the FIFO
      epicsMutexUnlock(fifoLockId_);
      
      // Take the lock since we are now changing object data
      lock();
      nextChan_ = chan;
      nextSignal_ = signal;
      if (acquireMode_ == ACQUIRE_MODE_MCS) {
        asynPrint(pasynUserSelf, ASYN_TRACE_FLOW,
                  "%s:%s: pOut=%p,signal=%d, chan=%d\n",
                  driverName, functionName, pOut, signal, chan);
        checkMCSDone();
      } else if (acquireMode_ == ACQUIRE_MODE_SCALER) {
        if (!acquiring) acquiring_ = false;
        if (!acquiring_) {
          asynPrint(pasynUserSelf, ASYN_TRACE_FLOW,
                    "%s:%s: scaler done, doing callbacks\n",
                    driverName, functionName);
          stopScaler();
          setIntegerParam(scalerDone_, 1);
          callParamCallbacks();
        }
      }
      /* Reenable interrupts in case we were woken up by an interrupt for FIFO almost full */
      enableInterrupts();
      acquiring = acquiring_;
      // Release the lock
      unlock();
      // If we are still acquiring then sleep for a short time, but wake up if there is an interrupt
      if (acquiring) {
        status = epicsEventWaitWithTimeout(readFIFOEventId_, epicsThreadSleepQuantum());
        if (status == epicsEventWaitOK) 
          asynPrint(pasynUserSelf, ASYN_TRACE_FLOW,
                    "%s:%s: got interrupt in epicsEventWaitWithTimeout, eventType=%d\n",
                    driverName, functionName, eventType_);
      }
    }  
  }
}
Ejemplo n.º 11
0
/**
 * read just one line of input
 */
asynStatus omsMAXv::sendReceive(const char *outputBuff, char *inputBuff, unsigned int inputSize)
{
    static const char* functionName = "sendReceive";

    STATUS1 flag1;
    epicsUInt16 getIndex, putIndex;
    size_t bufsize;
    size_t usedSpace = 0;
    char *start, *end;
    int itera = 0;
    asynStatus status;

    if (!enabled) return asynError;

    status = sendOnly(outputBuff);
    if (status != asynSuccess) return status;

    if (inputSize <= 0) return status;

    *inputBuff = '\0';

    double time = 0.0;
    double timeout = 0.1;
    // skip busy-waiting for small epicsThreadSleepQuantum
    if (epicsThreadSleepQuantum() <= 0.01) itera = 2001;
    while ((pmotor->status1_flag.Bits.text_response == 0) && (time < timeout)){
        Debug(32, "%s:%s:%s: Waiting for reponse, itera:%d\n",
                driverName, functionName, portName, itera);
        //  busy-waiting but not more than 2000 times
        if (itera > 2000){
            time += epicsThreadSleepQuantum();
            epicsThreadSleep(epicsThreadSleepQuantum());
        }
        itera++;
    }

    if (pmotor->status1_flag.Bits.text_response == 0)
    {
        Debug(1, "%s:%s:%s: Timeout occurred , %s\n",
        		driverName, functionName, portName, outputBuff);
        return asynTimeout;
    }

    getIndex = (epicsUInt16) pmotor->inGetIndex;
    putIndex = (epicsUInt16) pmotor->inPutIndex;
    bufsize  = putIndex - getIndex;
    start  = (char *) &pmotor->inBuffer[getIndex];
    end    = (char *) &pmotor->inBuffer[putIndex];

    if (start < end) {   /* Test for message wraparound in buffer. */
    	usedSpace = MIN(bufsize, inputSize);
        memcpy(inputBuff, start, usedSpace);
    }
    else
    {
        bufsize += BUFFER_SIZE;
        size_t firstPart = ((char *) &pmotor->inBuffer[BUFFER_SIZE]) - start;

        usedSpace = MIN(firstPart, inputSize);
        memcpy(inputBuff, start, usedSpace);
        size_t copySize = MIN(bufsize - firstPart, inputSize - usedSpace);
        memcpy((inputBuff + usedSpace), (const char *) &pmotor->inBuffer[0], copySize);
        usedSpace += copySize;
    }

    inputBuff[usedSpace - 1]= '\0';

    getIndex += bufsize;
    if (getIndex >= BUFFER_SIZE)
        getIndex -= BUFFER_SIZE;

    while (getIndex != (epicsUInt16)pmotor->inPutIndex)
    {
        Debug(2, "readbuf(): flushed - %d\n", pmotor->inBuffer[getIndex]);
        if (++getIndex > BUFFER_SIZE)
            getIndex = 0;
    }
    pmotor->status1_flag.Bits.text_response = 0;

    pmotor->inGetIndex = (epicsUInt32) getIndex;
    flag1.All = pmotor->status1_flag.All;
    pmotor->status1_flag.All = flag1.All;
    pmotor->msg_semaphore=0;

    Debug(16, "omsMAXv::sendReceive: received %s\n", inputBuff);
    return asynSuccess;
}
Ejemplo n.º 12
0
asynStatus omsMAXv::sendOnly(const char *outputBuff)
{
    STATUS1 flag1;
    const char* functionName = "sendOnly";
    int len = strlen(outputBuff);
    double timeout = 0.01;
    epicsUInt16 getIndex, putIndex;

    if (!enabled) return asynError;
    Debug(16, "omsMAXv::send: sending: %s \n", outputBuff);

    if (len > (BUFFER_SIZE-1))
    {
        errlogPrintf("%s:%s:%s: message too long: %d character\n",
                        driverName, functionName, portName, len);
        return asynError;
    }

    /* see if junk at input port - should not be any data available */
    int flushTime = 0;
    while (((epicsUInt16) pmotor->inGetIndex != (epicsUInt16) pmotor->inPutIndex) && (flushTime < 100))
    {
        // flush cards response Buffer
#ifdef DEBUG
        int deltaIndex = ((epicsUInt16)pmotor->inPutIndex) - ((epicsUInt16)pmotor->inGetIndex);
        Debug(32, "%s:%s:%s: flushing %d characters\n",
                driverName, functionName, portName, (((deltaIndex < 0) ? BUFFER_SIZE +
                        deltaIndex : deltaIndex)));
#endif
        putIndex = (epicsUInt16) pmotor->inPutIndex;
        pmotor->inGetIndex = putIndex;
        pmotor->status1_flag.Bits.text_response = 0;
        flag1.All = pmotor->status1_flag.All;
        pmotor->status1_flag.All = flag1.All;
        pmotor->msg_semaphore=0;
        epicsThreadSleep(timeout);
        flushTime++;
        if (flushTime == 100 ) {
        	Debug(1, "%s:%s:%s: unable to flush more than 100 strings\n", driverName, functionName, portName);
        	return asynError;
        }
    }

    putIndex = (epicsUInt16) pmotor->outPutIndex;
    getIndex = (epicsUInt16) pmotor->outGetIndex;

    for (int i = 0; (i < len); i++) {
        pmotor->outBuffer[putIndex++]= outputBuff[i];
        if (putIndex >= BUFFER_SIZE) putIndex = 0;
    }

    pmotor->outPutIndex = putIndex;    /* Message Sent */

    int count = 0, prevdeltaIndex = 0, index = 0;
    int maxcount = (int)(0.1 / epicsThreadSleepQuantum());
    // skip busy-waiting for small epicsThreadSleepQuantum
    if (epicsThreadSleepQuantum() <= 0.01) index = 100;
    int deltaIndex = ((epicsUInt16)pmotor->outPutIndex) - ((epicsUInt16)pmotor->outGetIndex);
    while ((deltaIndex != 0) && (count <= maxcount))
    {
        deltaIndex  = ((epicsUInt16)pmotor->outPutIndex) - ((epicsUInt16)pmotor->outGetIndex);
        //  do busy-waiting but not more than 100 times
        while ((index < 100) && (deltaIndex != 0)){
            deltaIndex  = ((epicsUInt16)pmotor->outPutIndex) - ((epicsUInt16)pmotor->outGetIndex);
            ++index;
        }
        if ((index >= 100) && (deltaIndex != 0)) epicsThreadSleep(timeout);
        if (deltaIndex == prevdeltaIndex)
            ++count;
        else
            count = 0;
        prevdeltaIndex = deltaIndex;
    };

    if (deltaIndex != 0) {
        Debug(1, "%s:%s:%s: Timeout\n", driverName, functionName, portName);
        return asynTimeout;
    }

    Debug(64, "omsMAXv::send: done\n");

    return asynSuccess;
}
Ejemplo n.º 13
0
/* Scan task, one per PLC */
static void PLC_scan_task(PLC *plc)
{
    ScanList *list;
    epicsTimeStamp    next_schedule, start_time, end_time;
    double            timeout, delay, quantum;
    eip_bool          transfer_ok, reset_next_schedule;

    quantum = epicsThreadSleepQuantum();
    timeout = (double)ETHERIP_TIMEOUT/1000.0;
scan_loop: /* --------- The Scan Loop for one PLC -------- */
    if (epicsMutexLock(plc->lock) != epicsMutexLockOK)
    {
        EIP_printf_time(1, "drvEtherIP scan task for PLC '%s'"
                   " cannot take plc->lock\n", plc->name);
        return;
    }
    if (!assert_PLC_connect(plc))
    {   /* don't rush since connection takes network bandwidth */
        epicsMutexUnlock(plc->lock);
        EIP_printf_time(2, "drvEtherIP: PLC '%s' is disconnected\n", plc->name);
        epicsThreadSleep(timeout);
        goto scan_loop;
    }
    EIP_printf_time(10, "drvEtherIP scan PLC '%s'\n", plc->name);
    reset_next_schedule = true;
    epicsTimeGetCurrent(&start_time);
    for (list = DLL_first(ScanList,&plc->scanlists);
         list;  list = DLL_next(ScanList,list))
    {
        if (! list->enabled)
            continue;
        if (epicsTimeLessThanEqual(&list->scheduled_time, &start_time))
        {
            epicsTimeGetCurrent(&list->scan_time);
            transfer_ok = process_ScanList(plc->connection, list);
            epicsTimeGetCurrent(&end_time);
            list->last_scan_time =
                epicsTimeDiffInSeconds(&end_time, &list->scan_time);
            /* update statistics */
            if (list->last_scan_time > list->max_scan_time)
                list->max_scan_time = list->last_scan_time;
            if (list->last_scan_time < list->min_scan_time  ||
                list->min_scan_time == 0.0)
                list->min_scan_time = list->last_scan_time;
            if (transfer_ok) /* re-schedule exactly */
            {
                list->scheduled_time = list->scan_time;
                epicsTimeAddSeconds(&list->scheduled_time, list->period);
            }
            else
            {  	/* end_time+fixed delay, ignore extra due to error */
                list->scheduled_time = end_time;
                epicsTimeAddSeconds(&list->scheduled_time, timeout);
                ++list->list_errors;
                ++plc->plc_errors;
                disconnect_PLC(plc);
                epicsMutexUnlock(plc->lock);
                goto scan_loop;
            }
        }
        /* Update time for list that's due next */
        if (reset_next_schedule ||
            epicsTimeLessThan(&list->scheduled_time, &next_schedule))
        {
            reset_next_schedule = false;
            next_schedule = list->scheduled_time;
        }
    }
    epicsMutexUnlock(plc->lock);
    /* fallback for empty/degenerate scan list */
    if (reset_next_schedule)
        delay = EIP_MIN_TIMEOUT;
    else
    {
        epicsTimeGetCurrent(&start_time);
        delay = epicsTimeDiffInSeconds(&next_schedule, &start_time);
        if (delay > 60.0)
        {
            char      tsString[50];
            printf("Scanlist %g secs has scheduling problem, delay = %g sec\n",
                  list->period, delay);
            epicsTimeToStrftime(tsString, sizeof(tsString),
                                "%Y/%m/%d %H:%M:%S.%04f", &list->scan_time);
            printf("  'Scan time'    : %s\n", tsString);
            epicsTimeToStrftime(tsString, sizeof(tsString),
                                "%Y/%m/%d %H:%M:%S.%04f", &start_time);
            printf("  'Current time' : %s\n", tsString);
            epicsTimeToStrftime(tsString, sizeof(tsString),
                                "%Y/%m/%d %H:%M:%S.%04f", &next_schedule);
            printf("  'Next    time' : %s\n", tsString);
            /* Attempt to hack around this by waiting a minute,
             * hoping that the clock looks better by then.
             * Also resetting the scheduled time to 'now'.
             */
            delay = 60.0;
            list->scheduled_time = start_time;
            ++list->sched_errors;
        }
    }
    /* Sleep until next turn. */
    if (delay > 0.0)
        epicsThreadSleep(delay);
    else if (delay <= -quantum)
    {
        EIP_printf(8, "drvEtherIP scan task slow, %g sec delay\n", delay);
        ++plc->slow_scans; /* hmm, "plc" not locked... */
    }
    goto scan_loop;
}
Ejemplo n.º 14
0
/** This thread is woken up by an interrupt or a request to read status
  * It loops calling readFIFO until acquiring_ goes to false.
  * readFIFO only reads a limited amount of FIFO data at once in order
  * to avoid blocking the device support threads. */
void drvSIS3820::readFIFOThread()
{
  int status;
  int count;
  int signal;
  int chan;
  int i;
  bool acquiring;
  epicsUInt32 *pIn, *pOut;
  epicsTimeStamp t1, t2, t3;
  static const char* functionName="readFIFOThread";

  while(true)
  {
    asynPrint(pasynUserSelf, ASYN_TRACE_FLOW, 
              "%s:%s: waiting for readFIFOEvent\n",
              driverName, functionName);
    enableInterrupts();
    (void)epicsEventWait(readFIFOEventId_);
    asynPrint(pasynUserSelf, ASYN_TRACE_FLOW, 
              "%s:%s: got readFIFOEvent, eventType=%d\n",
              driverName, functionName, eventType_);
    // We got an event.  This can come from:
    //  Acquisition complete in scaler mode
    //  FIFO full in MCS mode
    //  Acquisition start in MCS mode
    // For scaler mode we just do callbacks
    lock();
    // Do callbacks on acquiring status when acquisition completes
    if ((acquiring_ == false) && (acquireMode_ == ACQUIRE_MODE_SCALER)) {
      asynPrint(pasynUserSelf, ASYN_TRACE_FLOW, 
                "%s:%s: doing callbacks on scalerDone\n",
                driverName, functionName);
      setIntegerParam(scalerDone_, 1);
      callParamCallbacks();
      unlock();
      continue;
    }
    acquiring = acquiring_;
    unlock();
    // MCS mode
    while (acquiring && (acquireMode_ == ACQUIRE_MODE_MCS)) {
      lock();
      signal = nextSignal_;
      chan = nextChan_;
      // This block of code can be slow and does not require the asynPortDriver lock because we are not
      // accessing object data that could change.  
      // It does require the FIFO lock so no one resets the FIFO while it executes
      epicsMutexLock(fifoLockId_);
      unlock();
      count = registers_->fifo_word_count_reg;
      if (count > fifoBufferWords_) count = fifoBufferWords_;
      epicsTimeGetCurrent(&t1);
      if (useDma_ && (count >= MIN_DMA_TRANSFERS)) {
        asynPrint(pasynUserSelf, ASYN_TRACE_FLOW, 
                  "%s:%s: doing DMA transfer, fifoBuffer=%p, fifoBaseVME_=%p, count=%d\n",
                  driverName, functionName, fifoBuffer_, fifoBaseVME_, count);
        status = sysDmaFromVme(dmaId_, fifoBuffer_, (int)fifoBaseVME_, VME_AM_EXT_SUP_D64BLT, (count)*sizeof(int), 8);
        if (status) {
          asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, 
                    "%s:%s: doing DMA transfer, error calling sysDmaFromVme, status=%d, error=%d, buff=%p, fifoBaseVME_=%p, count=%d\n",
                    driverName, functionName, status, errno, fifoBuffer_, fifoBaseVME_, count);
        } 
        else {
          (void)epicsEventWait(dmaDoneEventId_);
          status = sysDmaStatus(dmaId_);
          if (status)
             asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, 
                       "%s:%s: DMA error, errno=%d, message=%s\n",
                       driverName, functionName, errno, strerror(errno));
        }
      } else {    
        asynPrint(pasynUserSelf, ASYN_TRACE_FLOW, 
                  "%s:%s: programmed transfer, count=%d\n",
                  driverName, functionName, count);
        // Note: we were previously using memcpy here.  But that is not guaranteed to do a word transfer, which the
        // SIS3820 requires for reading the FIFO.  In fact if the word count was 1 then a memcpy of 4 bytes was clearly
        // not doing a word transfer on vxWorks, and was generating bus errors.
        for (i=0; i<count; i++)
          fifoBuffer_[i] = fifoBaseCPU_[i];
      }
      epicsTimeGetCurrent(&t2);

      asynPrint(pasynUserSelf, ASYN_TRACE_FLOW, 
                "%s:%s: read FIFO (%d) in %fs, fifo word count after=%d, fifoBuffer_=%p, fifoBaseCPU_=%p\n",
                driverName, functionName, count, epicsTimeDiffInSeconds(&t2, &t1), registers_->fifo_word_count_reg, fifoBuffer_, fifoBaseCPU_);
      // Release the FIFO lock, we are done accessing the FIFO
      epicsMutexUnlock(fifoLockId_);
      
      // Copy the data from the FIFO buffer to the mcsBuffer
      pOut = mcsData_ + signal*maxChans_ + chan;
      pIn = fifoBuffer_;
      for (i=0; i<count; i++) {
        *pOut = *pIn++;
        signal++;
        if (signal == maxSignals_) {
          signal = 0;
          chan++;
          pOut = mcsData_ + chan;
        } else {
          pOut += maxChans_;
        }
      }
      
      epicsTimeGetCurrent(&t2);
      // Take the lock since we are now changing object data
      lock();
      nextChan_ = chan;
      nextSignal_ = signal;
      asynPrint(pasynUserSelf, ASYN_TRACE_FLOW, 
                "%s:%s: copied data to mcsBuffer in %fs, nextChan=%d, nextSignal=%d\n",
                driverName, functionName, epicsTimeDiffInSeconds(&t3, &t3), nextChan_, nextSignal_);

      checkMCSDone();
      acquiring = acquiring_;
      /* Re-enable FIFO threshold and FIFO almost full interrupts */
      /* NOTE: WE ARE NOT USING FIFO THRESHOLD INTERRUPTS FOR NOW */
      /* registers_->irq_control_status_reg = SIS3820_IRQ_SOURCE1_ENABLE; */
      registers_->irq_control_status_reg = SIS3820_IRQ_SOURCE4_ENABLE;

      // Release the lock 
      unlock();
      enableInterrupts();
      // If we are still acquiring sleep for a short time but wake up on interrupt
      if (acquiring) {
        status = epicsEventWaitWithTimeout(readFIFOEventId_, epicsThreadSleepQuantum());
        if (status == epicsEventWaitOK) 
          asynPrint(pasynUserSelf, ASYN_TRACE_FLOW,
                    "%s:%s: got interrupt in epicsEventWaitWithTimeout, eventType=%d\n",
                    driverName, functionName, eventType_);
      }
    }
  }
}