Beispiel #1
0
void AlsaPMO::WorkerThread(void)
{
   void                      *pBuffer;
   Error                      eErr;
   int                        iRet = -1;
   Event                     *pEvent;
   snd_pcm_channel_status_t  ainfo;

   // Don't do anything until resume is called.
   m_pPauseSem->Wait();

   // Sleep for a pre buffer period
   PreBuffer();

   // The following should be abstracted out into the general thread
   // classes:
#ifdef __linux__
   struct sched_param sParam;

   sParam.sched_priority = sched_get_priority_max(SCHED_OTHER);
   pthread_setschedparam(pthread_self(), SCHED_OTHER, &sParam);
#endif

   ainfo.channel = SND_PCM_CHANNEL_PLAYBACK;
   for(; !m_bExit;)
   {
      if (m_bPause)
      {
          m_pPauseSem->Wait();
          continue;
      }

      // Loop until we get an Init event from the LMC
      if (!m_properlyInitialized)
      {
          pEvent = ((EventBuffer *)m_pInputBuffer)->GetEvent();

          if (pEvent == NULL)
          {
              m_pLmc->Wake();
              WasteTime();

              continue;
          }

          if (pEvent->Type() == PMO_Init)
          {
              if (IsError(Init(((PMOInitEvent *)pEvent)->GetInfo())))
              {
                  delete pEvent;
                  break;
              }
          }
          delete pEvent;

          continue;
      }

      // Set up reading a block from the buffer. If not enough bytes are
      // available, sleep for a little while and try again.
      for(;;)
      {
          eErr = ((EventBuffer *)m_pInputBuffer)->BeginRead(pBuffer, 
                                                             m_iDataSize);
          if (eErr == kError_EndOfStream || eErr == kError_Interrupt)
             break;

          if (eErr == kError_NoDataAvail)
          {
              m_pLmc->Wake();
              CheckForBufferUp();

              WasteTime();
              continue;
          }

          // Is there an event pending that we need to take care of
          // before we play this block of samples?
          if (eErr == kError_EventPending)
          {
              pEvent = ((EventBuffer *)m_pInputBuffer)->PeekEvent();
			  if (pEvent == NULL)
				  continue;
                  
              if (pEvent->Type() == PMO_Quit && 
                  ((EventBuffer *)m_pInputBuffer)->GetNumBytesInBuffer() > 0) 
              {
                  if (WaitForDrain())
				  {
                     Reset(true);
                     m_pTarget->AcceptEvent(new Event(INFO_DoneOutputting));
                     return;
				  }
                  continue;
              }
              
              pEvent = ((EventBuffer *)m_pInputBuffer)->GetEvent();

              if (pEvent->Type() == PMO_Init)
                  Init(((PMOInitEvent *)pEvent)->GetInfo());
    
              if (pEvent->Type() == PMO_Reset)
                  Reset(false);
    
              if (pEvent->Type() == PMO_Info) 
                  HandleTimeInfoEvent((PMOTimeInfoEvent *)pEvent);
    
              if (pEvent->Type() == PMO_Quit) 
              {
                  delete pEvent;
                  m_pTarget->AcceptEvent(new Event(INFO_DoneOutputting));
                  return;
              }
 
              delete pEvent;
    
              continue;
          }
          
          if (IsError(eErr))
          {
              ReportError("Internal error occured.");
              m_pContext->log->Error("Cannot read from buffer in PMO "
                                    "worker tread: %d\n", eErr);
              break;
          }
          break;
      }

      // Now write the block to the audio device. If the block doesn't
      // all fit, pause and loop until the entire block has been played.
      // This loop could be written using non-blocking io...
      for(;!m_bExit && !m_bPause;)
      {
          iRet = snd_pcm_write(m_handle,pBuffer,m_iDataSize);
          if (iRet == -EAGAIN)
          {
               CheckForBufferUp();
               WasteTime();
               continue;
          }
          if (iRet == -EIO)
          {
               snd_pcm_channel_prepare(m_handle, SND_PCM_CHANNEL_PLAYBACK);
               continue;
          }
          break;
      }
      if (m_bExit)
      {
          m_pInputBuffer->EndRead(0);
          return;
      }

      if (m_bPause)
      {
         if (iRet == -EAGAIN)
             m_pInputBuffer->EndRead(0);
         else
         {
             m_pInputBuffer->EndRead(iRet);
             UpdateBufferStatus();
         }
         continue;   
      }

      if (iRet < 0)
      {
         m_pInputBuffer->EndRead(0);
         ReportError("Could not write sound data to the soundcard.");
         m_pContext->log->Error("Failed to write to the soundcard: %s\n", 
                               strerror(errno));
         break;
      }

      m_pInputBuffer->EndRead(iRet);
      m_pLmc->Wake();
      UpdateBufferStatus();
   }
}
Beispiel #2
0
void SoundCardPMO::WorkerThread(void)
{
   void       *pBuffer;
   Error       eErr;
   size_t      iRet;
   Event      *pEvent;
   //   audio_info info;
   bool        bPerfWarn = false;

   // Don't do anything until resume is called.
   m_pPauseSem->Wait();

   // Wait a specified prebuffer time... 
   PreBuffer();

   // The following should be abstracted out into the general thread
   // classes:
#ifdef __linux__
   struct sched_param sParam;

   sParam.sched_priority = sched_get_priority_max(SCHED_OTHER);
   pthread_setschedparam(pthread_self(), SCHED_OTHER, &sParam);
#endif

   for(; !m_bExit;)
   {
      if (m_bPause)
      {
          m_pPauseSem->Wait();
          continue;
      }

      // Loop until we get an Init event from the LMC
      if (!m_properlyInitialized)
      {
          pEvent = ((EventBuffer *)m_pInputBuffer)->GetEvent();

          if (pEvent == NULL)
          {
              m_pLmc->Wake();
              WasteTime();

              continue;
          }

          if (pEvent->Type() == PMO_Init)
          {
              if (IsError(Init(((PMOInitEvent *)pEvent)->GetInfo())))
              {
                  delete pEvent;
                  break;
              }
          }
          delete pEvent;

          continue;
      }

      // Set up reading a block from the buffer. If not enough bytes are
      // available, sleep for a little while and try again.
      for(;;)
      {
          eErr = ((EventBuffer *)m_pInputBuffer)->BeginRead(pBuffer, 
                                                             m_iDataSize);
          if (eErr == kError_EndOfStream || eErr == kError_Interrupt)
             break;

          if (eErr == kError_NoDataAvail)
          {
              m_pLmc->Wake();

              if (!bPerfWarn)
              {
                  time_t t;
    
                  time(&t);
                  m_pContext->log->Log(LogPerf, "Output buffer underflow: %s", 
                             ctime(&t));
                  bPerfWarn = true;
              }
    
              WasteTime();
              continue;
          }

          // Is there an event pending that we need to take care of
          // before we play this block of samples?
          if (eErr == kError_EventPending)
          {
              pEvent = ((EventBuffer *)m_pInputBuffer)->GetEvent();

              if (pEvent->Type() == PMO_Init)
                  Init(((PMOInitEvent *)pEvent)->GetInfo());
    
              if (pEvent->Type() == PMO_Reset)
                  Reset(false);
    
              if (pEvent->Type() == PMO_Info) 
                  HandleTimeInfoEvent((PMOTimeInfoEvent *)pEvent);
    
              if (pEvent->Type() == PMO_Quit) 
              {
                  delete pEvent;
                  if (WaitForDrain())
                     m_pTarget->AcceptEvent(new Event(INFO_DoneOutputting));

                  return;
              }
 
              delete pEvent;
    
              continue;
          }
          
          if (IsError(eErr))
          {
              ReportError("Internal error occured.");
              m_pContext->log->Error("Cannot read from buffer in PMO "
                                    "worker tread: %d\n", eErr);
              break;
          }
          bPerfWarn = false;
          break;
      }

      // Now write the block to the audio device. If the block doesn't
      // all fit, pause and loop until the entire block has been played.
      // This loop could be written using non-blocking io...
      for(;;)
      {
          if (m_bExit || m_bPause)
              break;

	  //          ioctl(audio_fd, AUDIO_GETINFO, &info);
          if (0) //((unsigned)(info.fragments * info.fragsize) < m_iDataSize)
          {
              WasteTime();
              continue;
          }
          break;
      }        
      if (m_bExit || m_bPause)
      {
          m_pInputBuffer->EndRead(0);
          continue;
      }

      iRet = write(audio_fd, pBuffer, m_iDataSize);
      // write(audio_fd, pBuffer, 0); // for WaitForDrain(), maybe?
      if (iRet < 0)
      {
         m_pInputBuffer->EndRead(0);
         ReportError("Could not write sound data to the soundcard.");
         m_pContext->log->Error("Failed to write to the soundcard: %s\n", 
                               strerror(errno));
         break;
      }

      m_iTotalBytesWritten += iRet;
      m_pInputBuffer->EndRead(iRet);
      m_pLmc->Wake();
      UpdateBufferStatus();
   }
}
Beispiel #3
0
/* individual buffers                               */
void PushFrame(unsigned short* in_frame)
{
  static int discard_me = 1; /* we discard the first slow frame, since it's
                                probably a partial */
  unsigned int i_in, i_out;
  int i, j, k, curr_index;
  int write_ok;
#if DAS_CARDS > 0
  unsigned B0, B1;
#endif
  int range, first, c;
  unsigned short *frame;

  first = PreBuffer(in_frame);
  if (first == -1)
    return;

  range = first >> 8;
  first &= 0xff;

  /* Wait for dirfile initialisation */
  while (!ri.dirfile_init)
    usleep(10000);

  for (c = 0; c < range; ++c) {
    if (c != range - 1)
      defile_flags |= DEFILE_FLAG_INSERTED_FRAME;

    frame = pre_buffer[(first + c) % FAST_PER_SLOW];

#ifdef DEBUG_FASTSAMP
    printf("Fastsamp push: %lu\n", *(unsigned long*)(&frame[1]));
#endif

    /* slow data */
    curr_index = frame[3];
#ifdef DEBUG_SEQUENCING
    static int next_j = -1;
    if (next_j > -1 && next_j != curr_index)
      printf("frame %lli sequencing error: expected %i but got %i\n", fc,
          next_j, curr_index);
    next_j = (curr_index + 1) % FAST_PER_SLOW;
#endif

    if (curr_index < FAST_PER_SLOW)
      for (i = 0; i < slowsPerBi0Frame; i++)
        slow_data[curr_index][i] = frame[slow_fields[curr_index][i].i0];

    /* defile flags */
    defile_flag_buf[curr_index] = defile_flags;
    defile_flags = 0;

    /* fast data */
    memcpy(fast_frame[curr_index], frame, DiskFrameSize);

    /* do while loop blocks until sufficient buffers empty */
    do {
      write_ok = 1;
      /* ****************************************************************** */
      /* First make sure there is enough space in ALL the buffers           */
      /* We need to do it first and all at once to maintain synchronization */
      /* We discard the full frame id there is no space                     */
      /* ****************************************************************** */

      /************************************/
      /* Check buffer space in slow field */
      /************************************/
      for (i = 0; write_ok && i < slowsPerBi0Frame; i++)
        for (j = 0; write_ok && j < FAST_PER_SLOW; j++) {
          i_in = (slow_fields[j][i].i_in + 1) % MAXBUF;
          if(i_in == slow_fields[j][i].i_out)
            write_ok = 0;
        }

      /* Check buffer space in defile_field */
      if (write_ok) {
        i_out = defile_field.i_out;
        i_in = defile_field.i_in;

        if (i_out <= i_in)
          i_out += MAXBUF;

        if (i_in + FAST_PER_SLOW >= i_out)
          write_ok = 0;
      }

      /******************************************
       * Check buffer space in normal fast data *
       *****************************************/
      if (write_ok)
        for (j = 0; write_ok && j < n_fast; j++) {
          i_out = normal_fast[j].i_out;
          i_in = normal_fast[j].i_in;

          if (i_out <= i_in)
            i_out += MAXBUF;

          if(i_in + FAST_PER_SLOW >= i_out)
            write_ok = 0;
        }

#if DAS_CARDS > 0
      /*******************************************
       * Check buffer space in  fast bolo data   *
       *******************************************/
      if (write_ok)
        for (i = 0; write_ok && i < DAS_CARDS; i++)
          for (j = 0; write_ok && j < DAS_CHS; j += 2) {
            i_out = bolo_fields[i][j].i_out;
            i_in = bolo_fields[i][j].i_in;

            if (i_out <= i_in)
              i_out += MAXBUF;

            if(i_in + FAST_PER_SLOW >= i_out)
              write_ok = 0;
          }
#endif

      if (!write_ok)
        usleep(10000);
    } while (!write_ok);

    /*************************/
    /* PUSH RX FRAME TO DISK */
    /*************************/

    /* push if we're at the end of a frame... */
    if (curr_index == FAST_PER_SLOW - 1) {
      if (discard_me) /* discard the first frame */
        discard_me = 0;
      else {
        /* Slow Data */
        for (i = 0; i < slowsPerBi0Frame; i++) {
          for (j = 0; j < FAST_PER_SLOW; j++) {
            i_in = slow_fields[j][i].i_in;
            ((unsigned short*)slow_fields[j][i].b)[i_in] = slow_data[j][i];

            if (++i_in >= MAXBUF)
              i_in = 0;
            slow_fields[j][i].i_in = i_in;
          }
        }

        for (k = 0; k < FAST_PER_SLOW; ++k) {
          /* defile_field */
          i_in = defile_field.i_in;
          ((unsigned short*)defile_field.b)[i_in] = defile_flag_buf[k];

          defile_field.i_in = (i_in + 1) % MAXBUF;

          /********************/
          /* normal fast data */
          /********************/

          for (j = 0; j < n_fast; j++) {
            i_in = normal_fast[j].i_in;
            if (normal_fast[j].size == 2)
              ((unsigned*)normal_fast[j].b)[i_in] =
                *((unsigned*)(fast_frame[k] + normal_fast[j].i0));
            else 
              ((unsigned short*)normal_fast[j].b)[i_in] =
                fast_frame[k][normal_fast[j].i0];

            normal_fast[j].i_in = (i_in + 1) % MAXBUF;
          }

#if DAS_CARDS > 0
          /********************/
          /* fast bolo data   */
          /********************/
          for (i = 0; i < DAS_CARDS; i++) {
            for (j = 0; j < DAS_CHS; j += 2) {
              B0 = (unsigned)fast_frame[k][boloIndex[i][j][0] + BoloBaseIndex] +
                (((unsigned)fast_frame[k][boloIndex[i][j][1] + BoloBaseIndex] &
                  0xff00) << 8);
              B1 = fast_frame[k][boloIndex[i][j + 1][0] + BoloBaseIndex] +
                ((fast_frame[k][boloIndex[i][j + 1][1] + BoloBaseIndex] &
                  0x00ff) << 16);

              i_in = bolo_fields[i][j].i_in;
              ((unsigned*)bolo_fields[i][j].b)[i_in] = B0;
              ((unsigned*)bolo_fields[i][j + 1].b)[i_in] = B1;

              bolo_fields[i][j].i_in = bolo_fields[i][j + 1].i_in =
                (i_in + 1) % MAXBUF;
            }
          }
#endif
        }
      }
    }
  }
}
Beispiel #4
0
void SoundCardPMO::WorkerThread(void)
{
   void       *pBuffer;
   Error       eErr;
   size_t      iRet;
   Event      *pEvent;
   audio_buf_info info;
   bool        bPerfWarn = false;

   // Don't do anything until resume is called.
   m_pPauseSem->Wait();

   //CheckForBufferUp();

   // Wait a specified prebuffer time...
   PreBuffer();

   for(; !m_bExit;)
   {
      if (m_bPause)
      {
          m_pPauseSem->Wait();
          continue;
      }

      // Loop until we get an Init event from the LMC
      if (!m_properlyInitialized)
      {
          pEvent = ((EventBuffer *)m_pInputBuffer)->GetEvent();

          if (pEvent == NULL)
          {
              m_pLmc->Wake();
              WasteTime();

              continue;
          }

          if (pEvent->Type() == PMO_Init)
          {
              if (IsError(Init(((PMOInitEvent *)pEvent)->GetInfo())))
              {
                  delete pEvent;
                  break;
              }
          }
          delete pEvent;
          continue;
      }

      // Set up reading a block from the buffer. If not enough bytes are
      // available, sleep for a little while and try again.
      for(;;)
      {
          eErr = ((EventBuffer *)m_pInputBuffer)->BeginRead(pBuffer, 
                                                             m_iDataSize);
          if (eErr == kError_EndOfStream || eErr == kError_Interrupt)
             break;

          if (eErr == kError_NoDataAvail)
          {
              m_pLmc->Wake();
              CheckForBufferUp();

              if (!bPerfWarn)
              {
                  time_t t;
    
                  time(&t);
                  m_pContext->log->Log(LogPerf, "Output buffer underflow: %s", 
                             ctime(&t));
                  bPerfWarn = true;
              }
    
              WasteTime();
              continue;
          }

          // Is there an event pending that we need to take care of
          // before we play this block of samples?
          if (eErr == kError_EventPending)
          {
              pEvent = ((EventBuffer *)m_pInputBuffer)->PeekEvent();
              if (pEvent == NULL)
                  continue;

              if (pEvent->Type() == PMO_Quit &&
                  ((EventBuffer *)m_pInputBuffer)->GetNumBytesInBuffer() > 0)
              {
                  if (WaitForDrain())
                  {
                     m_pTarget->AcceptEvent(new Event(INFO_DoneOutputting));
                     return;
                  }
                  continue;
              }  

              pEvent = ((EventBuffer *)m_pInputBuffer)->GetEvent();

              if (pEvent->Type() == PMO_Init)
                  Init(((PMOInitEvent *)pEvent)->GetInfo());
    
              if (pEvent->Type() == PMO_Reset)
                  Reset(false);
    
              if (pEvent->Type() == PMO_Info) 
                  HandleTimeInfoEvent((PMOTimeInfoEvent *)pEvent);

              if (pEvent->Type() == PMO_Quit) 
              {
                  delete pEvent;
                  m_pTarget->AcceptEvent(new Event(INFO_DoneOutputting));
                  return;
              }
 
              delete pEvent;
    
              continue;
          }
          
          if (IsError(eErr))
          {
              ReportError("Internal error occured.");
              m_pContext->log->Error("Cannot read from buffer in PMO "
                                    "worker tread: %d\n", eErr);
              break;
          }
          bPerfWarn = false;
          break;
      }

      if (m_bExit || m_bPause)
      {
          m_pInputBuffer->EndRead(0);
          continue;
      }

      iRet = ALwritesamps(outaudioport, pBuffer, m_iDataSize);
      if ((int)iRet < 0)
      {
         m_pInputBuffer->EndRead(0);
         ReportError("Could not write sound data to the soundcard.");
         m_pContext->log->Error("Failed to write to the soundcard: %s\n", 
                               strerror(errno));
         break;
      }

      m_iTotalBytesWritten += iRet;
      m_pInputBuffer->EndRead(iRet);
      m_pLmc->Wake();
      UpdateBufferStatus();
   }
}
Beispiel #5
0
/* Initialise dirfile */
void InitialiseDirFile(int reset, unsigned long offset)
{
  dtrace("%i, %lu", reset, offset);
  FILE* fp;
  int fd;
  int j, i, is_bolo = 0;
#if DAS_CARDS > 0
  char field[FIELD_LEN];
  int bolo_node;
  char first_bolo_buf[16];
#endif
  char gpb[GPB_LEN];
  char ext[4] = "";

  fc = 0;

#ifdef HAVE_LIBZ
  if (rc.gzip_output) {
    defileclose = &gzclose;
    strcpy(ext, ".gz");
  } else
#endif
    defileclose = &close;

  rc.resume_at = -1;

  if (mkdir(rc.dirfile, 00755) < 0)
    if (!CheckWriteAllow(errno))
      berror(fatal, "cannot create dirfile `%s'", rc.dirfile);

  bprintf(info, "\nWriting to dirfile `%s'\n", rc.dirfile);

  rc.dirname = strdup(rc.dirfile);
  snprintf(rc.dirname, strlen(rc.dirfile), "%s", basename(rc.dirfile));

  for (i = 0; i < FAST_PER_SLOW + 10; ++i) {
    pre_buffer[i] = balloc(fatal, DiskFrameSize);
    pre_buffer[i][3] = i;
  }

  /* Reset the PreBuffer */
  PreBuffer(NULL);

  for (i = 0; i < FAST_PER_SLOW; ++i)
    fast_frame[i] = balloc(fatal, DiskFrameSize);

  /***********************************
   * create and fill the format file *
   ***********************************/
  sprintf(gpb, "%s/format", rc.dirfile);

  if ((fd = creat(gpb, 0666)) < 0)
    berror(fatal, "cannot create format file `%s/format'", rc.dirfile);

  PathSplit_r(rc.dirfile, NULL, gpb);

  WriteFormatFile(fd, atoi(gpb), offset / FAST_PER_SLOW);

#ifdef __SPIDER__
  if (rc.extra_format) {
    sprintf(gpb, "/INCLUDE /data/etc/spider/format.mce_mplex\n"
        "/INCLUDE /data/etc/spider/format.bolo_stats\n");
    if (write(fd, gpb, strlen(gpb)) < 0)
      berror(err, "Error writing to format file\n");
  }
#else
  /* no extra format for BLAST */
#endif

  if (close(fd) < 0)
    berror(fatal, "Error while closing format file");

  /* DEFILE_FLAGS */
  sprintf(gpb, "%s/DEFILE_FLAGS%s", rc.dirfile, ext);
  defile_field.size = 1;
  defile_field.fp = OpenField(1, 1, gpb);
  defile_field.i0 = 1;
  if (reset) {
    if (rc.resume_at > 0)
      defile_field.nw = rc.resume_at;
    else
      defile_field.nw = 0;
  }
  defile_field.i_in = defile_field.i_out = 0;
  defile_field.b = balloc(fatal, MAXBUF * sizeof(unsigned short));

  /* FASTSAMP */
  sprintf(gpb, "%s/FASTSAMP%s", rc.dirfile, ext);
  normal_fast[0].size = 2;

  normal_fast[0].fp = OpenField(1, 2, gpb);
  normal_fast[0].i0 = 1;
  if (reset) {
    if (rc.resume_at > 0)
      normal_fast[0].nw = rc.resume_at;
    else
      normal_fast[0].nw = 0;
  }

  normal_fast[0].i_in = normal_fast[0].i_out = 0;
  normal_fast[0].b = balloc(fatal, MAXBUF * sizeof(unsigned int));

  n_fast = 1;  //original form

  /* slow chs */
  for (i = 0; i < slowsPerBi0Frame; i++) {
    for (j = 0; j < FAST_PER_SLOW; j++) {
      if (strlen(SlowChList[i][j].field) > 0) {
        slow_fields[j][i].size = FieldSize(SlowChList[i][j].type,
            SlowChList[i][j].field);

        sprintf(gpb, "%s/%s%s", rc.dirfile, SlowChList[i][j].field, ext);
        slow_fields[j][i].fp = OpenField(0, slow_fields[j][i].size, gpb);
      } else
        slow_fields[j][i].fp = -1;

      slow_fields[j][i].i_in = slow_fields[j][i].i_out = 0;
      if (reset) {
        if (rc.resume_at > 0)
          slow_fields[j][i].nw = rc.resume_at / FAST_PER_SLOW;
        else
          slow_fields[j][i].nw = 0;
      }

      slow_fields[j][i].b = balloc(fatal, 2 * MAXBUF);

      slow_fields[j][i].i0 = SLOW_OFFSET + i;
    }
  }

  /* normal fast chs */

#if DAS_CARDS > 0
  sprintf(first_bolo_buf, "n%02dc00lo", DAS_START+1);
#endif
  for (i = 0; i < ccFast + ccWideFast; i++) {
#if DAS_CARDS > 0
    if (strcmp(FastChList[i].field, first_bolo_buf) == 0) {
      bolo_i0 = i + SLOW_OFFSET + slowsPerBi0Frame;
      is_bolo = 1;
    } else if (ccDecom > 0 && strcmp(FastChList[i].field,
          DecomChannels[0].field) == 0) {
      is_bolo = 0;
    }
#endif

    if (!is_bolo && strlen(FastChList[i].field) > 0) {
      normal_fast[n_fast].size = FieldSize(FastChList[i].type,
          FastChList[i].field);
      sprintf(gpb, "%s/%s%s", rc.dirfile, FastChList[i].field, ext);

      normal_fast[n_fast].fp = OpenField(1, normal_fast[n_fast].size, gpb);
      normal_fast[n_fast].i0 = i + SLOW_OFFSET + slowsPerBi0Frame;
      normal_fast[n_fast].i_in = normal_fast[n_fast].i_out = 0;
      if (reset) {
        if (rc.resume_at > 0)
          normal_fast[n_fast].nw = rc.resume_at;
        else
          normal_fast[n_fast].nw = 0;
      }

      normal_fast[n_fast].b = balloc(fatal, MAXBUF * 2 *
          normal_fast[n_fast].size);

      n_fast++;
    }
  }

#if DAS_CARDS > 0
  /* special (bolo) fast chs */
  bolo_node = DAS_START;
  for (i = 0; i < DAS_CARDS; i++) {
    bolo_node++;
    if (bolo_node%4 == 0) bolo_node++;
    for (j = 0; j < DAS_CHS; j++) {
      bolo_fields[i][j].size = 2;
      sprintf(field, "n%02dc%02d", bolo_node, j);
      sprintf(gpb, "%s/%s%s", rc.dirfile, field, ext);

      bolo_fields[i][j].fp = OpenField(1, 2, gpb);
      bolo_fields[i][j].i_in = bolo_fields[i][j].i_out = 0;

      if (reset) {
        if (rc.resume_at > 0)
          bolo_fields[i][j].nw = rc.resume_at;
        else
          bolo_fields[i][j].nw = 0;
      }

      bolo_fields[i][j].b = balloc(fatal, MAXBUF * 4);

      bolo_fields[i][j].i0 = bolo_i0 + i * (DAS_CARDS * 3 / 2) + j;
    }
  }
#endif

  if (rc.write_curfile) {
    // create the link file
    char lnkfile[1024];
    char curfile[1024];

    strncpy(curfile, rc.output_curfile, 1018);
    strcat(curfile, ".cur");

    strncpy(lnkfile, rc.output_curfile, 1018);
    strcat(lnkfile, ".lnk");
    unlink(lnkfile);
    if (symlink(rc.dirfile, lnkfile)<0) {
      berror(fatal, "could not create link from `%s' to `%s'",
             rc.dirfile, lnkfile);
    }
    // create the cur file
    if ((fp = fopen(curfile, "w")) == NULL)
      berror(fatal, "cannot create curfile `%s'", curfile);

    fprintf(fp, "%s\n", rc.dirfile);

    if (fclose(fp) < 0)
      berror(fatal, "cannot close curfile `%s'", curfile);
  }

  ri.dirfile_init = 1;
}