void record_manager::start()
{
    // Critical Section
    ///////////////////////////////////////////////////////////////////////////
    ALLOCATE_WRITE(mutex_);

    read_count();
    const auto minimum = header_size_ + record_to_position(record_count_);

    if (minimum > file_.size())
        throw std::runtime_error("Records size exceeds file size.");
    ///////////////////////////////////////////////////////////////////////////
}
Пример #2
0
/***    void forceIdleState(void)
 *
 *    Parameters:
 *          None
 *              
 *    Return Values:
 *          None
 *
 *    Description: 
 *      This put the controller and state machine back to the Idle state
 *      to either the Master or Slave state machines
 *    
 * ------------------------------------------------------------ */
void DTWI::forceIdleState(void)
{
        uint32_t tStart     = 0;
        uint32_t tCur       = 0;
        uint32_t IEFlags    = pregIec->reg & bitMASK;

        // disable interrupts
        pregIec->clr    = bitMASK;

        // if we are going to turn off the controller
        // nothing in the interrupt flags is going to make sense
        // just clear them
        pregIfs->clr    = bitMASK;

        // go back to the idle state
        curState        = I2C_IDLE;

        // toggle the controller.... very ugly!
        ptwi->i2cCon.ON = 0;

        // let the controller settle
        read_count(tStart);
        do {
            read_count(tCur);
        } while(tCur - tStart < CORETIMER_TICKS_PER_MICROSECOND);

        // turn the controller back on
        ptwi->i2cCon.ON = 1;

        // let the controller settle
        read_count(tStart);
        do {
            read_count(tCur);
        } while(tCur - tStart < CORETIMER_TICKS_PER_MICROSECOND);

        // go back to where we were with interrupts
        pregIec->set    = IEFlags;
}
Пример #3
0
int pcf_getcount(const char *filename, unsigned long *count)
{
  FILE *f;

  /* Should we use a page count file? */
  if (filename == NULL || *filename == '\0') return 0;

  /* If the file does not exist, the page count is taken to be zero. */
  if (access(filename, F_OK) != 0) {
    *count = 0;
    return 0;
  }

  /* Open the file */
  if ((f = fopen(filename, "r")) == NULL) {
    fprintf(stderr, ERRPREFIX "Cannot open page count file `%s': %s.\n",
      filename, strerror(errno));
    return -1;
  }

  /* Lock the file for reading (shared lock) */
  if (lock_file(filename, f, F_RDLCK) != 0) {
    fclose(f);
    return 1;
  }

  /* Read the contents */
  if (read_count(filename, f, count) != 0) {
    fclose(f);
    return -1;
  }

  /* Close the file, releasing the lock */
  fclose(f);

  return 0;
}
Пример #4
0
/***    bool stopMaster(void)
 *
 *    Parameters:
 *          None
 *              
 *    Return Values:
 *          True if the a stop condition was asserted on the bus, false if still writing data or
 *          reading data. If true, the I2C interrupts are disabled. If false, continue calling stopMaster() until it succeeds.
 *
 *    Description: 
 *      Assert a stop condition on the I2C bus
 *      You may not be done transimitting data, so call this until it succeeds and you know your data went out.
 * ------------------------------------------------------------ */
bool DTWI::stopMaster(void)
{

    // if not in master mode or not enabled, Master is stopped
    if(!fMasterMode || !ptwi->i2cCon.ON)
    {
        return(true);
    }

    fStop = true;

    // kick off the state machine and get things writing
    primeMasterSlave();

    // assert the stop condition
    if(curState == I2C_WAIT)
    {
        // put the state machine in the idle state
        curState = I2C_IDLE;

        // the lower 5 bits must be set to zero
        while(ptwi->i2cStat.TRSTAT || (ptwi->ixCon.reg & 0b11111));

        // assert the stop condition
#if defined(__PIC32MZXX__)
  
        if(ptwi->i2cStat.ACKSTAT)
        {

            // assert the stop condition
            ptwi->i2cCon.PEN = 1;
        }
        else
        {
            uint32_t        tStart  = 0;
            uint32_t        tCur    = 0;
            uint8_t         port    = digitalPinToPort(pinSDA);
            p32_ioport *	iop     =  (p32_ioport *)portRegisters(port);
            uint32_t        bit     = digitalPinToBitMask(pinSDA);

            iop->lat.clr  = bit;	// put a zero in the latch		
            iop->tris.clr = bit;	// make it an output

            // turn off the I2C controller
            // the low value of the latch will pull
            // the SDA low (hold it low).
            ptwi->i2cCon.ON = 0;

            // wait some time
            read_count(tStart);
            do {
                read_count(tCur);
            } while(tCur - tStart < 5 * CORETIMER_TICKS_PER_MICROSECOND);

            // tri-state the SDA, let the pull up 
            // resistor pull it up
            iop->tris.set = bit;	

            // we have to put some time on the stop condtion
            read_count(tStart);
            do {
                read_count(tCur);
            } while(tCur - tStart < 10 * CORETIMER_TICKS_PER_MICROSECOND);

            // this will clear the controller
            forceIdleState();
        }

#else
        // assert the stop condition
        ptwi->i2cCon.PEN = 1;
#endif

    }

    // if the stop condition has completed or bus error; disable interrupts
    else if(!(ptwi->ixCon.reg & 0b11111) && (curState == I2C_IDLE || curState == I2C_BUS_ERROR))
    {        
        // turn off interrupts
        pregIec->clr    = bitMASK;
        pregIfs->clr    = bitMASK;

        addr            = addrGenCall;
        forceIdleState();

        return(true);
    }

    return(false);
}
Пример #5
0
/***    bool startMaster(uint8_t addrSlave, uint32_t cbRead, bool fRead)
 *
 *    Parameters:
 *          addrSlave:  The Slave address the Master wishes to talk too.
 *          cbRead:     How many bytes to read before sending a Nak, this can be changed by setNAK
 *          fRead:      True if we want to start a read from the slave, false if we want to write to the slave.
 *              
 *    Return Values:
 *          True if we got the bus and the slave responded, False if we did not get the connection with the slave
 *
 *    Description: 
 *      Asserts a START condition on the I2C bus, puts the address out AND sets the R /W bit and enables the I2C interrupts
 *      startMaster() can be called before stopMaster(); and if done this way while the application own the bus, it will cause a repeated start condition to be asserted on the bus
 *      If this call fails, someone else may have the bus, or a previous startMaster() may be finishing up writing out the tranmit buffer, continue to call startMaster() until it passes
 *      however, be careful as if someone else has the bus, this may never return true as the bus never becomes available.
 *      If the applicaiton currently does not own the bus, and this call fails, the I2C interrupts will be disabled.
 *      This call is used to implement both  
 *          startMasterRead   
 *          startMasterWrite
 * ------------------------------------------------------------ */
bool DTWI::startMaster(uint8_t addrSlave, uint32_t cbRead, bool fRead)
{
    uint8_t volatile rcvB;  // make volatile so the compiler will actually read the recv buffer and not opt out
    uint32_t    tCur = 0;
    uint32_t    tStart = 0;

    // Not in Master mode, or we still have stuff to transmit, or we initiated a stop condition
    if(!fMasterMode || ptwi->i2cStat.TRSTAT || (ptwi->ixCon.reg & 0b11111))
    {
        return(false);
    }

    // we don't want to take an interrupt right now
    // we want to manually poll that the addr was accepted
    pregIec->clr = bitMASK;
    pregIfs->clr = bitMASK;

    // if we have something in the read buffer, just get it out
    rcvB = ptwi->ixRcv.reg;

    // clear error flags
    ptwi->ixStat.reg = 0;

    // If there is a start condition on the bus and we own the bus
    // we need to do a repeat start
    if(ptwi->i2cStat.S && curState != I2C_IDLE)
    {
        // go back to the idle state
        curState = I2C_IDLE;

        // the lower 5 bits must be set to zero
        while(ptwi->ixCon.reg & 0b11111);

        ptwi->i2cCon.RSEN = 1;

        // wait repeat start to complete
        while(ptwi->i2cCon.RSEN);
    }

    // if there is no start condition on the bus
    else if(!ptwi->i2cStat.S)
    {
        // force an idle state
        curState = I2C_IDLE;

        // the lower 5 bits must be set to zero
        while(ptwi->ixCon.reg & 0b11111);

        // set the start event
        ptwi->i2cCon.SEN = 1;

        // wait for the start condition to complete
        while(ptwi->i2cCon.SEN);
    }

    // someone else has the bus
    else
    {
        return(false);
    }

    // someone else has the bus, it could be a client had SDA held low
    if(ptwi->i2cStat.BCL)
    {
        return(false);
    }

    fStop = false;

    // Write out the address and R/W bit
    ptwi->ixTrn.reg = (addrSlave << 1) | fRead;

    // required settling time on the transmit buffer
    read_count(tStart);
    do {
        read_count(tCur);
    } while(tCur - tStart < (CORETIMER_TICKS_PER_MICROSECOND / 4));

    // release the stretch so we will transmit the byte
//    ptwi->i2cCon.SCLREL = 1;

    // quit if we get a bus conflict OR the transmit compiletes
    // if the TRSTAT get set, we know we got the ACK/NAK
    while(ptwi->i2cStat.BCL == 0 && ptwi->i2cStat.TRSTAT);

    // got a bus collision; we are done and don't have the bus
    if(ptwi->i2cStat.BCL)
    {
        return(false);
    }

    // we got the bus, but the address failed to NAK
    // there is no device so we want to release the bus and get out
    else if(ptwi->i2cStat.ACKSTAT)
    {
        // the lower 5 bits must be set to zero
        while(ptwi->ixCon.reg & 0b11111);
        
        // assert the stop condition
        ptwi->i2cCon.PEN = 1;

        return(false);
    }

    // all is good!
    addr = addrSlave;
    iSession++;

    // if this is a MASTER READ
    if(fRead)
    {
        // how many bytes to read before the NAK
        cbToNAK = cbRead;

        // say we are recieving data
        curState = I2C_DATA_READ;

        // enable recieving data from the slave
        ptwi->i2cCon.RCEN = 1;
    }

    // if this is a MASTER WRITE
    else
    {
        // say we are recieving data
        curState = I2C_DATA_WRITE;
    }

    // re-enable the interrupts
    pregIfs->clr = bitMASK;
    pregIec->set = bitMASK;

    // see if we got the ACK, or NAK or bus collision
    return(true);
}
Пример #6
0
/***    slaveMachine
 *
 *    Parameters:
 *          None
 *              
 *    Return Values:
 *          None
 *
 *    Description: 
 *          This is the slave state machine called by the interrupt routine.
 *    
 * ------------------------------------------------------------ */
void __attribute__((nomips16)) DTWI::slaveMachine(void)
{
    I2C_STATE passState;

    // we must loop because we my need to transmit after the address
    // so keep looping until the state is repeated
    do
    {
        passState = curState;
        switch(curState)
        {

            case I2C_IDLE:

                if(ptwi->i2cStat.RBF)
                {
                    // what we are expecting is and address being sent
                    if(!ptwi->i2cStat.D_A)
                    {
                        uint8_t rcvB = ptwi->ixRcv.reg;

                        // save the address away, this might be different than the init addr
                        // if we enabled the fGenCall, it might be the general call address
                        // remember to shift off the R/W bit
                        addr = rcvB >> 1;
                        iSession++;           // say we saw a start condition

                        // see if this is a Read or Write from the Master perspective
                        // or Write or Read from the slave perspective
                        if(ptwi->i2cStat.R_W)
                        {
                            curState = I2C_DATA_WRITE;      // Master R, slave W
                            ptwi->i2cStat.IWCOL = 0;         // clear write collisions
                        }

                        // we are not excepting data
                        else if(cbToNAK == 0)
                        {
                            curState            = I2C_IDLE; // we are not doing reads
                            ptwi->i2cStat.I2COV  = 1;        // make it so we NAK
                        }
                 
                        else
                        {
                            curState = I2C_DATA_READ;   // Master W, slave R
                            ptwi->i2cStat.I2COV = 0;     // clear overflow 

                            // not needed on an MX as this is auto released on an address
                            // read, not so on an MZ. we need to release it
                            // buffer because
                            ptwi->i2cCon.SCLREL = 1;     // release the clk stretching 
                        }
                    }
                }

                // I just don't know what this is
                // in the idle state I need to get an address... or I just don't know what to do with it
                // Just get rid of it...
                else
                {
                    uint8_t rcvB = ptwi->ixRcv.reg;
                    ptwi->i2cStat.I2COV = 0;     // clear overflow
                    ptwi->i2cCon.SCLREL = 1;     // release the clk stretching 
                }

                break;

            case I2C_DATA_READ:
                if(ptwi->i2cStat.RBF && iReadLast - iReadNext < sizeof(rgbIn))
                {
                    rgbIn[iReadLast % sizeof(rgbIn)] = ptwi->ixRcv.reg;
                    iReadLast++;

                    if(cbToNAK != recvInfinite && cbToNAK != 0)
                    {
                        cbToNAK--;
                    }
         
                    // if we are done reading data, release the clk and go
                    // to an I2C_WAIT state
                    if(cbToNAK == 0)
                    {
                        curState = I2C_WAIT;        // we are done with the reads
                    }

                    ptwi->i2cCon.SCLREL = 1;     // release the clk stretching 
                }
                break;

            case I2C_DATA_WRITE:

                // get a NAK from the other side
                // I really don't know what to do because
                // the master is clocking me, but he asked me to stop
                // transmitting. So just release the clock and quit
                if(ptwi->i2cStat.ACKSTAT)
                {
                    curState = I2C_IDLE;
                }

                // normal case, the write register is open
                else if(!ptwi->i2cStat.TBF)
                {

                    // we have something to write
                    if(iWriteNext < iWriteLast)
                    {
                        uint32_t tStart;
                        uint32_t tCur;

                        // load the buffer
                        ptwi->ixTrn.reg = rgbOut[iWriteNext % sizeof(rgbOut)];
                        
                        // we need 250ns (1/4 usec) for setup time
                        read_count(tStart);

                        // update the next pointer
                        // it is okay to go beyond the buffer
                        // because we use the modulo, and the write
                        // funciton will adjust the index down
                        iWriteNext++;

                        // required settling time on the transmit buffer
                        do {
                            read_count(tCur);
                        } while(tCur - tStart < (CORETIMER_TICKS_PER_MICROSECOND / 4));

                        // release the stretch so we will transmit the byte
                        ptwi->i2cCon.SCLREL = 1;
                    }

                    // if we are to stop
                    else if(fStop)
                    {
                        curState = I2C_WAIT;
                    }
                }
                break;

            case I2C_WAIT:
                ptwi->i2cStat.I2COV  = 1;    // Cause a NAK
                ptwi->i2cCon.SCLREL  = 1;    // release the clk
                curState = I2C_IDLE;
                break;

            case I2C_BUS_ERROR:
            default:
                break;
        }
Пример #7
0
/***    masterMachine
 *
 *    Parameters:
 *          None
 *              
 *    Return Values:
 *          None
 *
 *    Description: 
 *          This is the master state machine called by the interrupt service routine
 *    
 * ------------------------------------------------------------ */
void __attribute__((nomips16)) DTWI::masterMachine(void)
{
    switch(curState)
    {
         case I2C_ACK:

            // if it was a NAK we are done, just wait
            if(ptwi->i2cStat.ACKSTAT || fStop)
            {
                curState = I2C_WAIT;
            }

            // otherwise initiate for another read
            // if we have room for another byte, lets recieve it
            // otherwise we will just halt the clock until we can read
            // some more data.
            else if((iReadLast - iReadNext) < sizeof(rgbIn))
            {
                // the lower 5 bits must be set to zero
                while(ptwi->ixCon.reg & 0b11111);

                curState = I2C_DATA_READ;
                ptwi->i2cCon.RCEN = 1;
            }
            break;

        // got a read
        case I2C_DATA_READ:
            if(ptwi->i2cStat.RBF)
            {
                rgbIn[iReadLast % sizeof(rgbIn)] = ptwi->ixRcv.reg;
                iReadLast++;

                if(cbToNAK != recvInfinite)
                {
                    cbToNAK--;
                }
                curState = I2C_ACK;
         
                ptwi->i2cCon.ACKDT = (cbToNAK == 0 || fStop);  // /ACK NAK value
                ptwi->i2cCon.ACKEN = 1;  //send the ACK
            }

            // we are told to finish
            else if(fStop)
            {
                curState = I2C_WAIT;
            }
            break;

        // if we have a write
        case I2C_DATA_WRITE:

            // only if the transmit engine is idle
            if(!ptwi->i2cStat.TRSTAT && !ptwi->i2cStat.TBF)
            {
                // get a NAK from the other side, or asked to stop by user
                if(ptwi->i2cStat.ACKSTAT || (fStop && iWriteNext == iWriteLast))
                {
                    curState = I2C_WAIT;
                }

                // otherwise keep writing data out
                else if(iWriteNext < iWriteLast)
                {
                    uint32_t tStart;
                    uint32_t tCur;

                    ptwi->ixTrn.reg = rgbOut[iWriteNext % sizeof(rgbOut)];
 
                    // we need 250ns (1/4 usec) for setup time
                    read_count(tStart);

                    // update the next pointer
                    // it is okay to go beyond the buffer
                    // because we use the modulo, and the write
                    // funciton will adjust the index down
                    iWriteNext++;

                    // required settling time on the transmit buffer
                    do {
                        read_count(tCur);
                    } while(tCur - tStart < (CORETIMER_TICKS_PER_MICROSECOND / 4));

                    // release the stretch so we will transmit the byte
 //                   ptwi->i2cCon.SCLREL = 1;

                }
            }
            break;

        case I2C_WAIT:
        case I2C_IDLE:
        case I2C_BUS_ERROR:
        default:
            break;
       
    }
}
Пример #8
0
int pcf_inccount(const char *filename, unsigned long by)
{
  FILE *f;
  int rc;
  unsigned long count;

  /* Should we use a page count file? */
  if (filename == NULL || *filename == '\0') return 0;

  /* Open the file. We need to access the old contents: this excludes the "w",
     "a" and "w+" modes. The operation should create the file if it doesn't
     exist: this excludes the "r" and "r+" modes. Hence the only choice is "a+".
     Note that this procedure makes it unavoidable to accept an empty file as
     being valid. This is, however, anyway necessary because of the fopen() and
     fcntl() calls being not in one transaction.
  */
  if ((f = fopen(filename, "a+")) == NULL) {
    fprintf(stderr, ERRPREFIX "Cannot open page count file `%s': %s.\n",
      filename, strerror(errno));
    return 1;
  }

  /* Lock the file for writing (exclusively) */
  if (lock_file(filename, f, F_WRLCK) != 0) {
    fclose(f);
    return 1;
  }

  /* Reposition on the beginning. fopen() with "a" as above opens the file at
     EOF. */
  if (fseek(f, 0L, SEEK_SET) != 0) {
    fprintf(stderr, ERRPREFIX "fseek() failed on `%s': %s.\n",
      filename, strerror(errno));
    fclose(f);
    return 1;
  }

  /* Read the contents */
  if (read_count(filename, f, &count) != 0) {
    fclose(f);
    return -1;
  }

  /* Rewrite the file */
  rc = 0;
  {
    FILE *f1 = fopen(filename, "w");

    if (f1 == NULL) {
      fprintf(stderr, ERRPREFIX 
	"Error opening page count file `%s' a second time: %s.\n",
	filename, strerror(errno));
      rc = 1;
    }
    else {
      if (fprintf(f1, "%lu\n", count + by) < 0) {
	fprintf(stderr, ERRPREFIX "Error writing to `%s': %s.\n",
	  filename, strerror(errno));
	rc = -1;
      }
      if (fclose(f1) != 0) {
	fprintf(stderr,
	  ERRPREFIX "Error closing `%s' after writing: %s.\n",
	  filename, strerror(errno));
	rc = -1;
      }
    }
  }

  /* Close the file (this releases the lock) */
  if (fclose(f) != 0)
    fprintf(stderr, WARNPREFIX "Error closing `%s': %s.\n",
      filename, strerror(errno));

  return rc;
}
Пример #9
0
/***    InitWS2812(uint8_t * pPatternBuffer, uint32_t cbPatternBuffer, uint32_t fInvert)
 *
 *    Parameters:
 *          pPatternBuffer: A pointer to the pattern buffer for the DMA to use
 *                          The application allocates this and should be 
 *                          CBWS2812PATBUF(__cDevices) bytes long.
 *
 *          cbPatternBuffer: This should be CBWS2812PATBUF(__cDevices) or larger
 *
 *          fInvert:        Because the WS2812 does not have a VinH <= 3.3 when Vcc >= 4.7v
 *                          External hardware may be needed to level shift the 3.3v SDO output
 *                          to a higher Data in signal to the WS2812. This level shifter may
 *                          be a simple transistor tied to 5v - 7v. The transistor will invert
 *                          the SDO output signal and to maintain the correct signal polarity
 *                          to the WS2812 you would need to invert the signal coming out of SDO.
 *                          If fInvert is true, the SDO output signal will be inverted from what
 *                          the WS2812 would normally take. By default, the is "false".
 *
 *    Return Values:
 *          True if the core timer can be aquired and initialization succeeded.
 *
 *    Description:
 *
 *      Initialize the SPI to 20MHz which is a 50ns clock
 *      This will enable .35us pattern resolution in the SPI
 *      shift register.
 *
 *      Also, initialize 2 DMA channels, one to shift out
 *      the pattern buffer, the other to maintain zeros
 *      for the restart / reset patteren (RES).
 *
 * ------------------------------------------------------------ */
uint32_t InitWS2812(uint8_t * pPatternBuffer, uint32_t cbPatternBuffer, uint32_t fInvert)
{
    // Disable SPI and DMA
    SPI2CON             = 0;
    DMACON              = 0;

    // set up SPI2
    SPI2CONbits.MSTEN   = 1;    // SPI in master mode
    SPI2CONbits.ENHBUF  = 1;    // enable 16 byte transfer buffer
    SPI2CONbits.STXISEL = 0b10; // trigger DMA event when the ENBUF is half empty
//    SPI2CONbits.DISSDI  = 1;  // Disable the SDI pin, allow it to be used for GPIO (not implemented on an MX6)
    SPI2STAT            = 0;    // clear status register
    SPI2BRG             = (__PIC32_pbClk / (2 * 20000000)) - 1;  // 20MHz, 50ns

    IEC1bits.SPI2RXIE   = 0;    // disable SPI interrupts
    IEC1bits.SPI2TXIE   = 0;    // disable SPI interrupts
    IEC1bits.SPI2EIE    = 0;    // disable SPI interrupts
    IFS1bits.SPI2RXIF   = 0;    // disable SPI interrupts
    IFS1bits.SPI2TXIF   = 0;    // disable SPI interrupts
    IFS1bits.SPI2EIF    = 0;    // disable SPI interrupts

    IEC1bits.DMA0IE     = 0;
    IFS1bits.DMA0IF     = 0;

    IEC1bits.DMA1IE     = 0;
    IFS1bits.DMA1IF     = 0;

    DMACONbits.ON       = 1;    // turn on the DMA controller
    IEC1CLR=0x00010000;         // disable DMA channel 0 interrupts
    IFS1CLR=0x00010000;         // clear existing DMA channel 0 interrupt flag

    // Set up DMA channel 0
    DCH0CON             = 0;    // clear it
    DCH0CONbits.CHAED   = 0;    // do not allow events to be remembered when disabled
    DCH0CONbits.CHAEN   = 0;    // do not Allow continuous operation
    DCH0CONbits.CHPRI   = 0b11; // highest priority

    DCH0ECON            = 0;    // clear it
    DCH0ECONbits.CHSIRQ = _SPI2_TX_IRQ;   // SPI2TX 1/2 empty notification
    DCH0ECONbits.SIRQEN = 1;    // enable IRQ transfer enables

    DCH0INT             = 0;    // do not trigger any events
    DCH0INTbits.CHBCIF  = 0;    // clear IF bit
    IPC9bits.DMA0IP     = 7;    // priority 7
    IPC9bits.DMA1IS     = 0;    // sub priority 0

    DCH0SSA             = KVA_2_PA(pPatternBuffer); // source address of transfer
    DCH0SSIZ            = cbPatternBuffer;          // number of bytes in source
    DCH0DSA             = KVA_2_PA(&SPI2BUF);       // destination address is the SPI2 buffer
    DCH0DSIZ            = 1;                        // 1 byte at the destination
    DCH0CSIZ            = 1;                        // only transfer 1 byte per event

    // Set up DMA channel 1
    DCH1CON             = 0;    // clear it
    DCH1CONbits.CHCHNS  = 0;    // allow chaining to the next higher priority DMA channel 0
    DCH1CONbits.CHCHN   = 1;    // Turn on chaining
    DCH1CONbits.CHAED   = 0;    // do not allow events to be remembered when disabled
    DCH1CONbits.CHAEN   = 1;    // turn on continuous operation
    DCH1CONbits.CHPRI   = 0b11; // highest priority

    DCH1ECON            = 0;    // clear it
    DCH1ECONbits.CHSIRQ = _SPI2_TX_IRQ;   // SPI2TX 1/2 empty notification
    DCH1ECONbits.SIRQEN = 1;    // enable IRQ transfer enables

    DCH1INT             = 0;    // do not trigger any events

    if(fInvert)
    {
        DCH1SSA         = KVA_2_PA(&ones);     // refresh cycle is inverted streaming 1s
    }
    else
    {
        DCH1SSA         = KVA_2_PA(&zeros);     // normal refresh cycle streaming 0s
    }
    DCH1SSIZ            = 1;                    // number of bytes in source

    DCH1DSA             = KVA_2_PA(&SPI2BUF);   // destination address is the SPI2 buffer
    DCH1DSIZ            = 1;                    // 1 byte at the destination
    DCH1CSIZ            = 1;                    // only transfer 1 byte per event

    // initial time for the core serivce routine
    read_count(tWS2812LastRun);

    // attach the core service routine
    if(attachCoreTimerService(WS2812TimerService))
    {
        // Enable DMA channel 1 and SPI 2
        // we enable in the refresh cycle until a pattern
        // is loaded in the main sketch.
        fWS2812Updating = true;
        IFS1bits.DMA0IF     = 0;
        IEC1bits.DMA0IE     = 1;
        DCH1CONbits.CHEN    = 1;    // turn DMA channel 1 ON; just zero output
        SPI2CONbits.ON      = 1;
        return(1);                  // success
    }

    // Things are not good, disable SPI and DMA
    SPI2CON             = 0;
    DMACON              = 0;

    // error out
    return(0);
}
Пример #10
0
// execution begins here
int UltraMain(void) {
    struct display_context * dc;
    struct controller_data cd;

    int lasty=0,lastx=0;
    int d=0;

    // buffer for rendering text strings (only sprintf works at the moment)
    char buf[1024]; 

    // offset for the scrolling waveform
    float offs=0;

    // used to keep track of how many cycles various processes take
    unsigned long time,rendertime,lastrendertime,waittime,lastwaittime;

    // enable MI interrupts (on the CPU)
    set_MI_interrupt(1);

    initDisplay();
    initAudio();

    registerAIhandler(AIcallback);
    registerVIhandler(VIcallback);
   
    while (1) {
	short * sb;
	int sbsize;
	// Mark the value of the COUNT register (increments at half the CPU
	// rate) at the start of the main loop.
	time=read_count();

	while (! (dc=lockDisplay())) ;

	// Mark the time after waiting.
	waittime=time;
	waittime=((time=read_count())-waittime)*2;

	sb=getbuf();
	sbsize=getbufsize();

	for (int c=0;c<sbsize;c++,d++) {
       	    sb[c*2]=sin((d%22050)/22050.0*M_TWOPI*1000.0)*100*((cd.c[0].y-lasty)*c/sbsize+lasty)*(((cd.c[0].x-lastx)*c/sbsize+lastx)/128.0-1.0);
	    sb[c*2+1]=sin((d%22050)/22050.0*M_TWOPI*1000.0)*100*((cd.c[0].y-lasty)*c/sbsize+lasty)*(((cd.c[0].x-lastx)*c/sbsize+lastx)/128.0+1.0);
	}
	writebuffer(sb);

	lastx=cd.c[0].x;
	lasty=cd.c[0].y;

	// this is what really marks the beginning of the current frame

	// read controller data
	controller_Read(&cd);

	// start drawing on the other frame buffer, clear the screen (uses red
	// when the start button on controller 1 is pressed, black otherwise)
	VI_FillScreen(&dc->conf,cd.c[0].err?0:(cd.c[0].start?0xf800:0));

	// print a little info for each controller
	for (int c=0; c < 4; c++) {
	    if (cd.c[c].err) // if controller not present
		sprintf(buf,"controller %d not present",c+1);
	    else {
		sprintf(buf,"controller %d present\nbuttons=0x%04X x=%4d y=%4d",c+1,
		    	cd.c[c].buttons,
		     	cd.c[c].x,
		      	cd.c[c].y);
	    }

	    VI_DrawText(&dc->conf,50,58+2*8*c,buf);
	}

	// draw a waveform
	for (float x=50; x < 250; x++) {
	    VI_DrawPixel(&dc->conf,x,cbrt(sin((x-50)/200*M_TWOPI*4+offs))*250.0/8+175,0x7c0);
	}

	// the waveform can be scrolled by the x axis of the first controller
	if (!cd.c[0].err) offs-=(cd.c[0].x/2*2)/32.0;

	// print up some informative text, and report how long we waited for
	// this frame, and how long the last frame took to render
	sprintf(buf,"buffers: %5d frames: %5d\n%8lu cycles last frame\n%8lu cycles waiting\n%4.2f FPS",buffercount,framecount,lastrendertime,lastwaittime,100000000.0/(lastwaittime+lastrendertime));
	VI_DrawText(&dc->conf,50,26,buf);

	// calculate how many cycles this frame took to render
	rendertime=(read_count()-time)*2;
	lastwaittime=waittime;
	lastrendertime=rendertime;

	showDisplay(dc);
	dc=0;
    }

    return 0;
}