/*!
 * \brief Listen for incoming data from a master.
 *
 * If this function returns without error, the bus is blocked. The caller
 * must immediately process the request and return a response by calling
 * TwSlaveRespond().
 *
 * \note This function is only available on ATmega128 systems. The
 *       function is not reentrant.
 *
 * \param sla    Points to a byte variable, which receives the slave
 *               address sent by the master. This can be used by the
 *               caller to determine whether the the interface has been
 *               addressed by a general call or its individual address.
 * \param rxdata Points to a data buffer where the received data bytes
 *               are stored.
 * \param rxsiz  Specifies the maximum number of data bytes to receive.
 * \param tmo	 Timeout in milliseconds. To disable timeout,
 *               set this parameter to NUT_WAIT_INFINITE.
 *
 * \return The number of bytes received, -1 in case of an error or timeout.
 */
int TwSlaveListen(u_char * sla, void *rxdata, u_short rxsiz, u_long tmo)
{
#ifndef __AVR_ENHANCED__
    return -1;
#else
    int rc = -1;

    NutEnterCritical();

    /* Initialize parameters for slave receive. */
    tw_sm_err = 0;
    tw_sr_siz = rxsiz;
    tw_sr_buf = rxdata;

    /*
     * If the interface is currently not busy then enable it for
     * address recognition.
     */
    if(tw_if_bsy == 0) {
        u_char twsr = inb(TWSR);
        if((twsr & 0xF8) == TW_NO_INFO) {
            if(tw_mt_len || tw_mr_siz)
                outb(TWCR, _BV(TWEA) | _BV(TWEN) | _BV(TWIE) | _BV(TWSTA));
            else
                outb(TWCR, _BV(TWEA) | _BV(TWEN) | _BV(TWIE));
        }
    }

    /* Clear the queue. */
    //*broken?! NutEventBroadcastAsync(&tw_sr_que);
    if (tw_sr_que == SIGNALED) {
        tw_sr_que = 0;
    }

    /* Wait for a frame on the slave mode queue. */
    if (NutEventWait(&tw_sr_que, tmo)) {
        NutEnterCritical();
        tw_sm_err = TWERR_TIMEOUT;
        tw_sr_siz = 0;
        NutExitCritical();
    }
    NutExitCritical();

    /*
     * Return the number of bytes received and the destination slave
     * address, if no slave error occured. In this case the bus is
     * blocked.
     */
    if(tw_sm_err == 0) {
        rc = tw_sr_idx;
        *sla = tw_sm_sla;
    }
    return rc;
#endif /* __AVR_ENHANCED__ */
}
/*!
 * \brief Execute flash controller command.
 *
 */
int Avr32FlashcCmd(unsigned int cmd, uint32_t tmo)
{
    int rc = 0;

    /* Make sure that the previous command has finished. */
    while (!flashc_is_ready()) {
        if (tmo && --tmo < 1) {
            return -1;
        }
    }

    /* IRQ handlers are located in flash. Disable them. */
    NutEnterCritical();

    /* Write command. */
    outr(AVR32_FLASHC.fcmd, AVR32_FLASHC_FCMD_KEY_KEY | cmd);

    /* Wait for ready flag set. */
    while (!flashc_is_ready()) {
        if (tmo && --tmo < 1) {
            rc = -1;
            break;
        }
    }

    /* Flash command finished. Re-enable IRQ handlers. */
    NutExitCritical();

    /* Check result. */
    if (AVR32_FLASHC.fsr & (AVR32_FLASHC_FSR_LOCKE_MASK | AVR32_FLASHC_FSR_PROGE_MASK)) {
        rc = -1;
    }
    return rc;
}
/*!
 * \brief Register an interrupt handler.
 *
 * This function is typically called by device drivers.
 *
 * \param irq     Interrupt number to be associated with this handler.
 * \param handler This routine will be called by Nut/OS, when the
 *                specified interrupt occurs.
 * \param arg     Argument to be passed to the interrupt handler.
 *
 * \return 0 on success, -1 otherwise.
 */
int NutRegisterIrqHandler(uint8_t irq, void (*handler) (void *), void *arg)
{
    if (irq >= IRQ_MAX)
        return -1;

    NutEnterCritical();

    irq_handlers[irq].ir_arg = arg;
    irq_handlers[irq].ir_handler = handler;

    NutExitCritical();

    return 0;
}
Example #4
0
uint32_t NutGetTickCount(void)
{
    uint32_t rc;

#ifdef __NUT_EMULATION__
    struct timeval   timeNow;
    gettimeofday( &timeNow, NULL );
    rc = (timeNow.tv_sec - timeStart.tv_sec) * 1000;
    rc += (timeNow.tv_usec - timeStart.tv_usec) / 1000;
#else
    NutEnterCritical();
    rc = nut_ticks;
    NutExitCritical();
#endif

    return rc;
}
/*
 * \return 0 on success, -1 in case of any errors.
 */
static int SendRawByte(AHDLCDCB * dcb, uint8_t ch, uint8_t flush)
{
    /*
       * If transmit buffer is full, wait until interrupt routine
       * signals an empty buffer or until a timeout occurs.
     */
    while ((uint8_t) (dcb->dcb_wr_idx + 1) == dcb->dcb_tx_idx) {
        if (NutEventWait(&dcb->dcb_tx_rdy, dcb->dcb_wtimeout))
            break;
    }

    /*
     * If transmit buffer is still full, we have a write timeout.
     */
    if ((uint8_t) (dcb->dcb_wr_idx + 1) == dcb->dcb_tx_idx) {
        return -1;
    }

    /*
     * Buffer has room for more data. Put the byte in the buffer
     * and increment the write index.
     */
    dcb->dcb_tx_buf[dcb->dcb_wr_idx] = ch;
    dcb->dcb_wr_idx++;

    /*
     * If transmit buffer has become full and the transmitter
     * is not active, then activate it.
     */
    if (flush || (uint8_t) (dcb->dcb_wr_idx + 1) == dcb->dcb_tx_idx) {

        NutEnterCritical();

        outr(US1_IER, US_TXRDY);

        NutExitCritical();
    }
    return 0;
}
/*!
 * \brief Send response to a master.
 *
 * This function must be called as soon as possible after TwSlaveListen()
 * returned successfully, even if no data needs to be returned. Not doing
 * so will completely block the bus.
 *
 * \note This function is only available on ATmega128 systems.
 *
 * \param txdata Points to the data to transmit. Ignored, if the
 *      		 number of bytes to transmit is zero.
 * \param txlen  Number of data bytes to transmit.
 * \param tmo	 Timeout in milliseconds. To disable timeout,
 *               set this parameter to NUT_WAIT_INFINITE.
 *
 * \return The number of bytes transmitted, -1 in case of an error or timeout.
 */
int TwSlaveRespond(void *txdata, u_short txlen, u_long tmo)
{
    int rc = -1;
#ifdef __AVR_ENHANCED__

    /* The bus is blocked. No critical section required. */
    tw_st_buf = txdata;
    tw_st_len = txlen;

    /*
     * If there is anything to transmit, start the interface.
     */
    if (txlen) {
        NutEnterCritical();
        /* Clear the queue. */
        //*broken?! NutEventBroadcastAsync(&tw_st_que);
        if (tw_st_que == SIGNALED) {
            tw_st_que = 0;
        }

        /* Release the bus, accepting SLA+R. */
        outb(TWCR, TWGO | _BV(TWEA));

        NutExitCritical();
        if (NutEventWait(&tw_st_que, tmo)) {
            tw_sm_err = TWERR_TIMEOUT;
        }

        NutEnterCritical();
        tw_st_len = 0;
        if (tw_sm_err) {
            tw_sm_error = tw_sm_err;
        } else {
            rc = tw_st_idx;
        }
        NutExitCritical();
    }

    /*
     * Nothing to transmit.
     */
    else {
        u_char twcr;
        u_char twsr;
        rc = 0;
        /* Release the bus, not accepting SLA+R. */

        NutEnterCritical();
        twcr = inb(TWCR);
        twsr = inb(TWSR);
        /* Transmit start condition, if a master transfer is waiting. */
        if (tw_mt_len || tw_mr_siz) {
            outb(TWCR, TWGO | _BV(TWSTA));
        }
        /* Otherwise enter idle state. */
        else {
            tw_if_bsy = 0;
            outb(TWCR, TWGO);
        }

        NutExitCritical();
    }
#endif /* __AVR_ENHANCED__ */
    return rc;
}
/*!
 * \brief Transmit and/or receive data as a master.
 *
 * The two-wire serial interface must have been initialized by calling
 * TwInit() before this function can be used.
 *
 * \note This function is only available on ATmega128 systems.
 *
 * \param sla    Slave address of the destination. This slave address
 *               must be specified as a 7-bit address. For example, the
 *               PCF8574A may be configured to slave addresses from 0x38
 *               to 0x3F.
 * \param txdata Points to the data to transmit. Ignored, if the number
 *               of data bytes to transmit is zero.
 * \param txlen  Number of data bytes to transmit. If zero, then the
 *               interface will not send any data to the slave device
 *               and will directly enter the master receive mode.
 * \param rxdata Points to a buffer, where the received data will be
 *               stored. Ignored, if the maximum number of bytes to
 *               receive is zero.
 * \param rxsiz  Maximum number of bytes to receive. Set to zero, if
 *               no bytes are expected from the slave device.
 * \param tmo    Timeout in milliseconds. To disable timeout, set this
 *               parameter to NUT_WAIT_INFINITE.
 *
 * \return The number of bytes received, -1 in case of an error or timeout.
 */
int TwMasterTransact(u_char sla, CONST void *txdata, u_short txlen, void *rxdata, u_short rxsiz, u_long tmo)
{
    int rc = -1;

#ifdef __AVR_ENHANCED__
    /* This routine is marked reentrant, so lock the interface. */
    if(NutEventWait(&tw_mm_mutex, 500)) {
        tw_mm_err = TWERR_IF_LOCKED;
        NutEventPost(&tw_mm_mutex);
        return -1;
    }

    while(tw_if_bsy) {
        NutSleep(63);
    }
    NutEnterCritical();
    /*
     * Set all parameters for master mode.
     */
    tw_mm_sla = sla << 1;
    tw_mm_err = 0;
    tw_mt_len = txlen;
    tw_mt_buf = txdata;
    tw_mr_siz = rxsiz;
    tw_mr_buf = rxdata;

    /*
     * Send a start condition if the interface is idle. If busy, then
     * the interrupt routine will automatically initiate the transfer
     * as soon as the interface becomes ready again.
     */
    if(tw_if_bsy == 0) {
        u_char twcr = inb(TWCR);
        u_char twsr = inb(TWSR);
        if((twsr & 0xF8) == TW_NO_INFO) {
            if(tw_sr_siz) {
                outb(TWCR, _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWSTA) | (twcr & _BV(TWSTO)));
            }
            else {
                outb(TWCR, _BV(TWEN) | _BV(TWIE) | _BV(TWSTA) | (twcr & _BV(TWSTO)));
            }
        }
    }

    /* Clear the queue. */
    //*broken?! NutEventBroadcastAsync(&tw_mm_que);
    if (tw_mm_que == SIGNALED) {
        tw_mm_que = 0;
    }
    NutExitCritical();

    /*
     * Wait for master transmission done.
     */
    rc = -1;
    if (NutEventWait(&tw_mm_que, tmo)) {
        tw_mm_error = TWERR_TIMEOUT;
    } else {
        NutEnterCritical();
        if (tw_mm_err) {
            tw_mm_error = tw_mm_err;
        } else {
            rc = tw_mr_idx;
        }
        NutExitCritical();
    }

    /*
     * Release the interface.
     */
    NutEventPost(&tw_mm_mutex);

#endif /* __AVR_ENHANCED__ */
    return rc;
}