/**
 * @brief   Handles incoming data.
 * @details This function must be called from the input interrupt service
 *          routine in order to enqueue incoming data and generate the
 *          related events.
 * @note    The incoming data event is only generated when the input queue
 *          becomes non-empty.
 * @note    In order to gain some performance it is suggested to not use
 *          this function directly but copy this code directly into the
 *          interrupt service routine.
 *
 * @param[in] sdp       pointer to a @p SerialDriver structure
 * @param[in] b         the byte to be written in the driver's Input Queue
 *
 * @iclass
 */
void sdIncomingDataI(SerialDriver *sdp, uint8_t b) {

  chDbgCheckClassI();
  chDbgCheck(sdp != NULL, "sdIncomingDataI");

  if (chIQIsEmptyI(&sdp->iqueue))
    chIOAddFlagsI(sdp, IO_INPUT_AVAILABLE);
  if (chIQPutI(&sdp->iqueue, b) < Q_OK)
    chIOAddFlagsI(sdp, SD_OVERRUN_ERROR);
}
Esempio n. 2
0
/**
 * @brief   Common IRQ handler.
 * @note    Tries hard to clear all the pending interrupt sources, we don't
 *          want to go through the whole ISR and have another interrupt soon
 *          after.
 *
 * @param[in] u         pointer to an UART I/O block
 * @param[in] sdp       communication channel associated to the UART
 */
static void serve_interrupt(SerialDriver *sdp) {
  LPC_UART_TypeDef *u = sdp->uart;

  while (TRUE) {
    switch (u->IIR & IIR_SRC_MASK) {
    case IIR_SRC_NONE:
      return;
    case IIR_SRC_ERROR:
      set_error(sdp, u->LSR);
      break;
    case IIR_SRC_TIMEOUT:
    case IIR_SRC_RX:
      chSysLockFromIsr();
      if (chIQIsEmptyI(&sdp->iqueue))
        chIOAddFlagsI(sdp, IO_INPUT_AVAILABLE);
      chSysUnlockFromIsr();
      while (u->LSR & LSR_RBR_FULL) {
        chSysLockFromIsr();
        if (chIQPutI(&sdp->iqueue, u->RBR) < Q_OK)
          chIOAddFlagsI(sdp, SD_OVERRUN_ERROR);
        chSysUnlockFromIsr();
      }
      break;
    case IIR_SRC_TX:
      {
        int i = LPC13xx_SERIAL_FIFO_PRELOAD;
        do {
          msg_t b;

          chSysLockFromIsr();
          b = chOQGetI(&sdp->oqueue);
          chSysUnlockFromIsr();
          if (b < Q_OK) {
            u->IER &= ~IER_THRE;
            chSysLockFromIsr();
            chIOAddFlagsI(sdp, IO_OUTPUT_EMPTY);
            chSysUnlockFromIsr();
            break;
          }
          u->THR = b;
        } while (--i);
      }
      break;
    default:
      (void) u->THR;
      (void) u->RBR;
    }
  }
}
Esempio n. 3
0
static bool_t outint(SerialDriver *sdp) {

  if (sdp->com_data != INVALID_SOCKET) {
    int n;
    uint8_t data[1];

    /*
     * Input.
     */
    chSysLockFromIsr();
    n = sdRequestDataI(sdp);
    chSysUnlockFromIsr();
    if (n < 0)
      return FALSE;
    data[0] = (uint8_t)n;
    n = send(sdp->com_data, data, sizeof(data), 0);
    switch (n) {
    case 0:
      close(sdp->com_data);
      sdp->com_data = INVALID_SOCKET;
      chSysLockFromIsr();
      chIOAddFlagsI(sdp, IO_DISCONNECTED);
      chSysUnlockFromIsr();
      return FALSE;
    case INVALID_SOCKET:
      if (errno == EWOULDBLOCK)
        return FALSE;
      close(sdp->com_data);
      sdp->com_data = INVALID_SOCKET;
      return FALSE;
    }
    return TRUE;
  }
  return FALSE;
}
Esempio n. 4
0
static bool_t inint(SerialDriver *sdp) {

  if (sdp->com_data != INVALID_SOCKET) {
    int i;
    uint8_t data[32];

    /*
     * Input.
     */
    int n = recv(sdp->com_data, data, sizeof(data), 0);
    switch (n) {
    case 0:
      close(sdp->com_data);
      sdp->com_data = INVALID_SOCKET;
      chSysLockFromIsr();
      chIOAddFlagsI(sdp, IO_DISCONNECTED);
      chSysUnlockFromIsr();
      return FALSE;
    case INVALID_SOCKET:
      if (errno == EWOULDBLOCK)
        return FALSE;
      close(sdp->com_data);
      sdp->com_data = INVALID_SOCKET;
      return FALSE;
    }
    for (i = 0; i < n; i++) {
      chSysLockFromIsr();
      sdIncomingDataI(sdp, data[i]);
      chSysUnlockFromIsr();
    }
    return TRUE;
  }
  return FALSE;
}
Esempio n. 5
0
static bool_t connint(SerialDriver *sdp) {

  if (sdp->com_data == INVALID_SOCKET) {
    struct sockaddr addr;
    socklen_t addrlen = sizeof(addr);

    if ((sdp->com_data = accept(sdp->com_listen, &addr, &addrlen)) == INVALID_SOCKET)
      return FALSE;

    if (ioctl(sdp->com_data, FIONBIO, &nb) != 0) {
      printf("%s: Unable to setup non blocking mode on data socket\n", sdp->com_name);
      goto abort;
    }
    chSysLockFromIsr();
    chIOAddFlagsI(sdp, IO_CONNECTED);
    chSysUnlockFromIsr();
    return TRUE;
  }
  return FALSE;
abort:
  if (sdp->com_listen != INVALID_SOCKET)
    close(sdp->com_listen);
  if (sdp->com_data != INVALID_SOCKET)
    close(sdp->com_data);
  exit(1);
}
Esempio n. 6
0
/**
 * @brief   Common IRQ handler.
 *
 * @param[in] sdp       pointer to a @p SerialDriver object
 */
static void serve_interrupt(SerialDriver *sdp) {
  volatile struct ESCI_tag *escip = sdp->escip;

  uint32_t sr = escip->SR.R;
  escip->SR.R = 0x3FFFFFFF;                     /* Does not clear TDRE | TC.*/
  if (sr & 0x0F000000)                          /* OR | NF | FE | PF.       */
    set_error(sdp, sr);
  if (sr & 0x20000000) {                        /* RDRF.                    */
    chSysLockFromIsr();
    sdIncomingDataI(sdp, escip->DR.B.D);
    chSysUnlockFromIsr();
  }
  if (escip->CR1.B.TIE && (sr & 0x80000000)) {  /* TDRE.                    */
    msg_t b;
    chSysLockFromIsr();
    b = chOQGetI(&sdp->oqueue);
    if (b < Q_OK) {
      chIOAddFlagsI(sdp, IO_OUTPUT_EMPTY);
      escip->CR1.B.TIE = 0;
    }
    else {
      ESCI_A.SR.B.TDRE = 1;
      escip->DR.R = (uint16_t)b;
    }
    chSysUnlockFromIsr();
  }
}
/**
 * @brief   Handles outgoing data.
 * @details Must be called from the output interrupt service routine in order
 *          to get the next byte to be transmitted.
 * @note    In order to gain some performance it is suggested to not use
 *          this function directly but copy this code directly into the
 *          interrupt service routine.
 *
 * @param[in] sdp       pointer to a @p SerialDriver structure
 * @return              The byte value read from the driver's output queue.
 * @retval Q_EMPTY      if the queue is empty (the lower driver usually
 *                      disables the interrupt source when this happens).
 *
 * @iclass
 */
msg_t sdRequestDataI(SerialDriver *sdp) {
  msg_t  b;

  chDbgCheckClassI();
  chDbgCheck(sdp != NULL, "sdRequestDataI");

  b = chOQGetI(&sdp->oqueue);
  if (b < Q_OK)
    chIOAddFlagsI(sdp, IO_OUTPUT_EMPTY);
  return b;
}
static void set_error(uint8_t sra, SerialDriver *sdp) {
  ioflags_t sts = 0;

  if (sra & USART_BUFOVF_bm)
    sts |= SD_OVERRUN_ERROR;
  if (sra & USART_PERR_bm)
    sts |= SD_PARITY_ERROR;
  if (sra & USART_FERR_bm)
    sts |= SD_FRAMING_ERROR;
  chSysLockFromIsr();
  chIOAddFlagsI(sdp, sts);
  chSysUnlockFromIsr();
}
Esempio n. 9
0
static void set_error(SerialDriver *sdp, uint8_t urctl) {
  ioflags_t sts = 0;

  if (urctl & OE)
    sts |= SD_OVERRUN_ERROR;
  if (urctl & PE)
    sts |= SD_PARITY_ERROR;
  if (urctl & FE)
    sts |= SD_FRAMING_ERROR;
  if (urctl & BRK)
    sts |= SD_BREAK_DETECTED;
  chSysLockFromIsr();
  chIOAddFlagsI(sdp, sts);
  chSysUnlockFromIsr();
}
Esempio n. 10
0
/**
 * @brief   Error handling routine.
 *
 * @param[in] sdp       communication channel associated to the UART
 * @param[in] err       UART LSR register value
 */
static void set_error(SerialDriver *sdp, IOREG32 err) {
  ioflags_t sts = 0;

  if (err & LSR_OVERRUN)
    sts |= SD_OVERRUN_ERROR;
  if (err & LSR_PARITY)
    sts |= SD_PARITY_ERROR;
  if (err & LSR_FRAMING)
    sts |= SD_FRAMING_ERROR;
  if (err & LSR_BREAK)
    sts |= SD_BREAK_DETECTED;
  chSysLockFromIsr();
  chIOAddFlagsI(sdp, sts);
  chSysUnlockFromIsr();
}
Esempio n. 11
0
/**
 * @brief   Error handling routine.
 *
 * @param[in] err       USART CSR register value
 * @param[in] sdp       communication channel associated to the USART
 */
static void set_error(SerialDriver *sdp, AT91_REG csr) {
  ioflags_t sts = 0;

  if (csr & AT91C_US_OVRE)
    sts |= SD_OVERRUN_ERROR;
  if (csr & AT91C_US_PARE)
    sts |= SD_PARITY_ERROR;
  if (csr & AT91C_US_FRAME)
    sts |= SD_FRAMING_ERROR;
  if (csr & AT91C_US_RXBRK)
    sts |= SD_BREAK_DETECTED;
  chSysLockFromIsr();
  chIOAddFlagsI(sdp, sts);
  chSysUnlockFromIsr();
}
Esempio n. 12
0
/**
 * @brief   Attempts a TX FIFO preload.
 */
static void preload(SerialDriver *sdp) {
  LPC_UART_TypeDef *u = sdp->uart;

  if (u->LSR & LSR_THRE) {
    int i = LPC13xx_SERIAL_FIFO_PRELOAD;
    do {
      msg_t b = chOQGetI(&sdp->oqueue);
      if (b < Q_OK) {
        chIOAddFlagsI(sdp, IO_OUTPUT_EMPTY);
        return;
      }
      u->THR = b;
    } while (--i);
  }
  u->IER |= IER_THRE;
}
Esempio n. 13
0
static void set_error(SerialDriver *sdp, uint8_t sr) {
  ioflags_t sts = 0;

  /* Note, SR register bit definitions are equal for all UARTs so using
     the UART1 definitions is fine.*/
  if (sr & UART1_SR_OR)
    sts |= SD_OVERRUN_ERROR;
  if (sr & UART1_SR_NF)
    sts |= SD_NOISE_ERROR;
  if (sr & UART1_SR_FE)
    sts |= SD_FRAMING_ERROR;
  if (sr & UART1_SR_PE)
    sts |= SD_PARITY_ERROR;
  chSysLockFromIsr();
  chIOAddFlagsI(sdp, sts);
  chSysUnlockFromIsr();
}
Esempio n. 14
0
/**
 * @brief   Error handling routine.
 *
 * @param[in] sdp       pointer to a @p SerialDriver object
 * @param[in] sr        eSCI SR register value
 */
static void set_error(SerialDriver *sdp, uint32_t sr) {
  ioflags_t sts = 0;

  if (sr & 0x08000000)
    sts |= SD_OVERRUN_ERROR;
  if (sr & 0x04000000)
    sts |= SD_NOISE_ERROR;
  if (sr & 0x02000000)
    sts |= SD_FRAMING_ERROR;
  if (sr & 0x01000000)
    sts |= SD_PARITY_ERROR;
/*  if (sr & 0x00000000)
    sts |= SD_BREAK_DETECTED;*/
  chSysLockFromIsr();
  chIOAddFlagsI(sdp, sts);
  chSysUnlockFromIsr();
}
Esempio n. 15
0
static
#endif
/**
 * @brief   Common IRQ handler.
 *
 * @param[in] sdp       communication channel associated to the USART
 */
void sd_lld_serve_interrupt(SerialDriver *sdp) {
  uint32_t csr;
  AT91PS_USART u = sdp->usart;

  csr = u->US_CSR;
  if (csr & AT91C_US_RXRDY) {
    chSysLockFromIsr();
    sdIncomingDataI(sdp, u->US_RHR);
    chSysUnlockFromIsr();
  }
  if ((u->US_IMR & AT91C_US_TXRDY) && (csr & AT91C_US_TXRDY)) {
    msg_t b;

    chSysLockFromIsr();
    b = chOQGetI(&sdp->oqueue);
    if (b < Q_OK) {
      chIOAddFlagsI(sdp, IO_OUTPUT_EMPTY);
      u->US_IDR = AT91C_US_TXRDY;
    }
    else
      u->US_THR = b;
    chSysUnlockFromIsr();
  }
  csr &= (AT91C_US_OVRE | AT91C_US_FRAME | AT91C_US_PARE | AT91C_US_RXBRK);
  if (csr != 0) {
    set_error(sdp, csr);
    u->US_CR = AT91C_US_RSTSTA;
  }
  AT91C_BASE_AIC->AIC_EOICR = 0;
}