Example #1
0
//===========================================================================
// Callback for received events
//===========================================================================
static void can_rcv_event(can_channel *chan, void *pdata)
{
    can_cbuf_t       *cbuf   = &chan->in_cbuf;
    CYG_CAN_EVENT_T  *prxbuf = (CYG_CAN_EVENT_T *)cbuf->pdata;
#ifdef CYGOPT_IO_CAN_SUPPORT_CALLBACK
    cyg_uint16        flags;
#endif
    
    //
    // cbuf is a ring buffer - if the buffer is full, then we overwrite the
    // oldest message in buffer so the user will always get the actual and
    // last state of the external hardware that is connected to the
    // CAN bus. We need to call cyg_drv_dsr_lock() here because this function
    // may be called from different message box interrupts and so we have to
    // protect data access here
    //
    cyg_drv_dsr_lock();
    prxbuf[cbuf->put].flags = 0; // clear flags because it is a new event
    if (chan->funs->getevent(chan, &prxbuf[cbuf->put], pdata))
    {
        if (cbuf->data_cnt < cbuf->len)
        {
            cbuf->data_cnt++;
        }
        else
        {
            //
            // the buffer is full but a new message arrived. We store this new
            // message and overwrite the oldest one, but at least we tell the user
            // that there is an overrun in RX queue
            //
            prxbuf[cbuf->put].flags |= CYGNUM_CAN_EVENT_OVERRUN_RX;
            cbuf->get = (cbuf->get + 1) % cbuf->len;
        }

#ifdef CYGOPT_IO_CAN_SUPPORT_CALLBACK
        flags = prxbuf[cbuf->put].flags;
#endif

        cbuf->put = (cbuf->put + 1) % cbuf->len;
        
        if (cbuf->waiting) 
        {
            cbuf->waiting = false;
            cyg_drv_cond_broadcast(&cbuf->wait);
        }
#ifdef CYGOPT_IO_CAN_SUPPORT_CALLBACK
        // Call application callback function, if any of the flag events 
        // are unmasked.
        if((flags & chan->callback_cfg.flag_mask) &&
           (chan->callback_cfg.callback_func))
        {
            chan->callback_cfg.callback_func(flags,
                                             chan->callback_cfg.data);
        }
#endif
    }
    
    cyg_drv_dsr_unlock();
}
Example #2
0
//===========================================================================
// Callback function for transmit events
//===========================================================================
static void can_xmt_msg(can_channel *chan, void *pdata)
{
    can_cbuf_t        *cbuf    = &chan->out_cbuf;
    can_lowlevel_funs *funs    = chan->funs;  
    CYG_CAN_MSG_T     *ptxbuf  = (CYG_CAN_MSG_T *)cbuf->pdata;
    CYG_CAN_MSG_T     *pbuf_txmsg;

    //
    // transmit messages as long as there are messages in the buffer 
    //
    while (cbuf->data_cnt > 0)
    {
        pbuf_txmsg = &ptxbuf[cbuf->get];
        
        if (funs->putmsg(chan, pbuf_txmsg, pdata))
        {
            cbuf->get = (cbuf->get + 1) % cbuf->len;
            cbuf->data_cnt--;
        }
        else
        {
            //
            // we are here because the hardware is busy at the moment and
            // we can't send another message - now we check if there is already
            // some space in buffer so we can wakeup the writer
            //
            if ((cbuf->len - cbuf->data_cnt) > 0)
            {
                if (cbuf->waiting)
                {
                    cbuf->waiting = false;
                    cyg_drv_cond_broadcast(&cbuf->wait);
                }
            }
            return;
        }
    } // while (cbuf->data_cnt > 0)
    funs->stop_xmit(chan);  // Done with transmit
    
    if (cbuf->waiting)
    {
        cbuf->waiting = false;
        cyg_drv_cond_broadcast(&cbuf->wait);
    }            
}
Example #3
0
static void
serial_data_xmt_done(serial_channel *chan, int chars_sent)
{
    cbuf_t *cbuf = &chan->out_cbuf;
    serial_funs *funs = chan->funs;
    int space;

    cbuf->get += chars_sent;
    cbuf->nb -= chars_sent;

    if (cbuf->get == cbuf->len) cbuf->get = 0;

    CYG_ASSERT(cbuf->nb <= cbuf->len, "Buffer overflow");
    CYG_ASSERT(cbuf->nb >= 0, "Buffer underflow");
    CYG_ASSERT(cbuf->put < cbuf->len, "Invalid put ptr");
    CYG_ASSERT(cbuf->get < cbuf->len, "Invalid get ptr");

    if (0 == cbuf->nb) {
        (funs->stop_xmit)(chan);  // Done with transmit
        cbuf->get = cbuf->put = 0; // reset ptrs if empty
    }

    // See if there is now enough room to restart writer
    space = cbuf->len - cbuf->nb;
    if (space >= cbuf->low_water) {
        if (cbuf->waiting) {
            cbuf->waiting = false;
            cyg_drv_cond_broadcast(&cbuf->wait);
        }
#ifdef CYGPKG_IO_SERIAL_SELECT_SUPPORT
        cyg_selwakeup( &cbuf->selinfo );
#endif                    
    }

#ifdef CYGDBG_USE_ASSERTS
    cbuf->block_mode_xfer_running = false;
#endif
}
Example #4
0
static void
serial_xmt_char(serial_channel *chan)
{
    cbuf_t *cbuf = &chan->out_cbuf;
    serial_funs *funs = chan->funs;
    unsigned char c;
    int space;

#if CYGINT_IO_SERIAL_BLOCK_TRANSFER
    CYG_ASSERT(false == cbuf->block_mode_xfer_running,
               "Attempting char xmt while block transfer is running");
#endif
#ifdef CYGOPT_IO_SERIAL_FLOW_CONTROL_SOFTWARE
    // if we are required to send an XON/XOFF char, send it before
    // anything else
    // FIXME: what if XON gets corrupted in transit to the other end?
    // Should we resend XON even though the other end may not be wanting
    // to send us stuff at this point?
    if ( chan->config.flags & CYGNUM_SERIAL_FLOW_XONXOFF_RX ) {
        if ( chan->flow_desc.xchar ) {
            if ( (funs->putc)(chan, chan->flow_desc.xchar) ) {
                chan->flow_desc.xchar = '\0';
            } else {  // otherwise there's no space and we have to wait
                return;
            }
        }
    }
#endif
#ifdef CYGPKG_IO_SERIAL_FLOW_CONTROL
    // if we're meant to be throttled, just stop and leave
    if ( chan->flow_desc.flags & CYG_SERIAL_FLOW_OUT_THROTTLED ) {
        (funs->stop_xmit)(chan);  // Stop transmitting for now
        return;
    }
#endif
    while (cbuf->nb > 0) {
        c = cbuf->data[cbuf->get];
        if ((funs->putc)(chan, c)) {
            cbuf->get++;
            if (cbuf->get == cbuf->len) cbuf->get = 0;
            cbuf->nb--;
        } else {
            // See if there is now enough room to restart writer
            space = cbuf->len - cbuf->nb;
            if (space >= cbuf->low_water) {
                if (cbuf->waiting) {
                    cbuf->waiting = false;
                    cyg_drv_cond_broadcast(&cbuf->wait);
                }
#ifdef CYGPKG_IO_SERIAL_SELECT_SUPPORT
                cyg_selwakeup( &cbuf->selinfo );
#endif                    
            }
            return;  // Need to wait for more space
        }
    }
    
    (funs->stop_xmit)(chan);  // Done with transmit

#ifdef CYGPKG_NET_BLUEZ_STACK	

	if(chan->tty_ldisc)//clyu
	{
		struct tty_ldisc *ldisc = chan->tty_ldisc;
		//diag_printf("chan->tty_ldisc != NULL\n");
		if(ldisc && ldisc->write_wakeup)
			ldisc->write_wakeup(serial_driver);
	}
#endif	
    // must signal waiters, and wake up selecters for the case when
    // this was the last char to be sent and they hadn't been signalled
    // before (e.g. because of flow control)
    if (cbuf->waiting) {
        cbuf->waiting = false;
        //diag_printf("cyg_drv_cond_broadcast signal\n");
        //cyg_drv_cond_signal(&cbuf->wait);//clyu ?
        cyg_drv_cond_broadcast(&cbuf->wait);
    }
#ifdef CYGPKG_IO_SERIAL_SELECT_SUPPORT
    cyg_selwakeup( &cbuf->selinfo );
#endif                    
}
Example #5
0
//===========================================================================
// Set CAN channel configuration
//===========================================================================
static Cyg_ErrNo can_set_config(cyg_io_handle_t handle, 
               cyg_uint32      key,
               const void     *xbuf, 
               cyg_uint32     *len)
{
    cyg_devtab_entry_t *t         = (cyg_devtab_entry_t *)handle;
    can_channel        *chan      = (can_channel *)t->priv;
    Cyg_ErrNo           res       = ENOERR;
    can_lowlevel_funs  *funs      = chan->funs;
    can_cbuf_t         *out_cbuf  = &chan->out_cbuf;
    can_cbuf_t         *in_cbuf   = &chan->in_cbuf;
    
    switch (key)
    {
#ifdef CYGOPT_IO_CAN_SUPPORT_NONBLOCKING
        //
        // Set calls to read function to blocking / nonblocking mode
        //
        case CYG_IO_SET_CONFIG_READ_BLOCKING:
             {
                 if (*len < sizeof(cyg_uint32) || 0 == in_cbuf->len) 
                 {
                     return -EINVAL;
                 }
                 in_cbuf->blocking = (1 == *(cyg_uint32*)xbuf) ? true : false;
             }
             break;
        
        //
        // set calls to write functions to blocking / nonblocking mode
        //     
        case CYG_IO_SET_CONFIG_WRITE_BLOCKING:
             {
                 if (*len < sizeof(cyg_uint32) || 0 == out_cbuf->len) 
                 {
                     return -EINVAL;
                 }
                 out_cbuf->blocking = (1 == *(cyg_uint32*)xbuf) ? true : false;
             }
             break;
#endif // CYGOPT_IO_CAN_SUPPORT_NONBLOCKING

#ifdef CYGOPT_IO_CAN_SUPPORT_TIMEOUTS            
        //
        // return current timeouts
        //
        case CYG_IO_SET_CONFIG_CAN_TIMEOUT :
             {
                 cyg_can_timeout_info_t *ptimeout_info;
                 if (*len < sizeof(cyg_can_timeout_info_t))
                 {
                     return -EINVAL; 
                 } 
                   
                 *len = sizeof(cyg_can_timeout_info_t);
                  ptimeout_info = (cyg_can_timeout_info_t *)xbuf;
                   
                  in_cbuf->timeout = ptimeout_info->rx_timeout;
                  out_cbuf->timeout = ptimeout_info->tx_timeout;
             }
             break; // case CYG_IO_GET_CONFIG_CAN_TIMEOUT_INFO
#endif // CYGOPT_IO_CAN_SUPPORT_TIMEOUTS

        case CYG_IO_SET_CONFIG_CAN_INPUT_FLUSH:
             {
                 //
                 // Flush any buffered input
                 //
                 if (in_cbuf->len == 0)
                 {
                     break;  // Nothing to do if not buffered
                 }
                 cyg_drv_mutex_lock(&in_cbuf->lock);  // Stop any further input processing
                 cyg_drv_dsr_lock();
                 if (in_cbuf->waiting) 
                 {
                     in_cbuf->abort = true;
                     cyg_drv_cond_broadcast(&in_cbuf->wait);
                     in_cbuf->waiting = false;
                 }
                 in_cbuf->get = in_cbuf->put = in_cbuf->data_cnt = 0; // Flush buffered input
                 
                 //
                 // Pass to the hardware driver in case it wants to flush FIFOs etc.
                 //
                 (funs->set_config)(chan,
                                    CYG_IO_SET_CONFIG_CAN_INPUT_FLUSH,
                                    NULL, NULL);
                 cyg_drv_dsr_unlock();
                 cyg_drv_mutex_unlock(&in_cbuf->lock);
            } // CYG_IO_SET_CONFIG_CAN_INPUT_FLUSH:
        
        //
        // flush any buffered output
        //    
        case CYG_IO_SET_CONFIG_CAN_OUTPUT_FLUSH:
             {
                  // Throw away any pending output
                  if (out_cbuf->len == 0) 
                  {
                      break;  // Nothing to do if not buffered
                  }
                  cyg_drv_mutex_lock(&out_cbuf->lock);  // Stop any further output processing
                  cyg_drv_dsr_lock();
                  if (out_cbuf->data_cnt > 0) 
                  {
                      out_cbuf->get = out_cbuf->put = out_cbuf->data_cnt = 0;  // Empties queue!
                     (funs->stop_xmit)(chan);  // Done with transmit
                  }
                  
                  //
                  // Pass to the hardware driver in case it wants to flush FIFOs etc.
                  //
                  (funs->set_config)(chan,
                                     CYG_IO_SET_CONFIG_CAN_OUTPUT_FLUSH,
                                     NULL, NULL);
                  if (out_cbuf->waiting) 
                  {
                      out_cbuf->abort = true;
                      cyg_drv_cond_broadcast(&out_cbuf->wait);
                      out_cbuf->waiting = false;
                  }// if (out_cbuf->waiting) 
                  cyg_drv_dsr_unlock();
                  cyg_drv_mutex_unlock(&out_cbuf->lock);
              }
              break; // CYG_IO_GET_CONFIG_CAN_OUTPUT_FLUSH:
        
        //
        // wait until all messages in outbut buffer are sent
        //      
        case CYG_IO_GET_CONFIG_SERIAL_OUTPUT_DRAIN:
             {
                 // Wait for any pending output to complete
                 if (out_cbuf->len == 0) 
                 {
                     break;  // Nothing to do if not buffered
                 }
                 cyg_drv_mutex_lock(&out_cbuf->lock);  // Stop any further output processing
                 cyg_drv_dsr_lock();
                 while (out_cbuf->pending || (out_cbuf->data_cnt > 0)) 
                 {
                     out_cbuf->waiting = true;
                     if(!cyg_drv_cond_wait(&out_cbuf->wait))
                     {
                         res = -EINTR;
                     }
                 }
                 cyg_drv_dsr_unlock();
                 cyg_drv_mutex_unlock(&out_cbuf->lock);
             }
             break;// CYG_IO_GET_CONFIG_SERIAL_OUTPUT_DRAIN:
             
        //     
        // Abort any outstanding I/O, including blocked reads
        // Caution - assumed to be called from 'timeout' (i.e. DSR) code  
        //   
        case CYG_IO_SET_CONFIG_CAN_ABORT :
             {
                 in_cbuf->abort = true;
                 cyg_drv_cond_broadcast(&in_cbuf->wait);
                 
                 out_cbuf->abort = true;
                 cyg_drv_cond_broadcast(&out_cbuf->wait);
             }
             break;
        

#ifdef CYGOPT_IO_CAN_SUPPORT_CALLBACK
        //
        // Set callback configuration
        // To disable callback set flag_mask = 0
        //
        case CYG_IO_SET_CONFIG_CAN_CALLBACK:
             {
                 if (*len != sizeof(cyg_can_callback_cfg))
                 {
                         return -EINVAL;
                 }
            
                 // Copy data under DSR locking
                 cyg_drv_dsr_lock();
                 chan->callback_cfg = *((cyg_can_callback_cfg*) xbuf);
                 cyg_drv_dsr_unlock();
             }
             break;
#endif //CYGOPT_IO_CAN_SUPPORT_CALLBACK

        default:
            //
            // pass down to lower layers
            //
            res = (funs->set_config)(chan, key, xbuf, len);
    } // switch (key)
    
    return res;
}