⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 wncandevio.c

📁 cpc-1631的BSP包for VxWorks操作系统
💻 C
📖 第 1 页 / 共 5 页
字号:
    /* Error case; Should not ever get here */
    else
    {
#if DEVIO_DEBUG
        logMsg("wncDevIOClose() ERROR: Invalid DevIO file descriptor type\n", 
            0,0,0,0,0,0);
#endif
        
        errnoSet (S_ioLib_DEVICE_ERROR);
        status = ERROR;
    }
    
    /* unlock device */
    semGive(wncDrv->mutex);
    
    return status;
}


/************************************************************************
*
* wncDevIOReadBuf - device read routine
*
* This routine is called by the VxWorks I/O System when user code calls read().
* It dequeues the next available CAN data message from the internal input data 
* ring buffer and returns it to the caller.  A separate function responds to the
* actual receive interrupt from the CAN controller and queues the CAN data message
* to the input data buffer.
*
* RETURNS: number of bytes read, or ERROR
*
* ERRNO: S_ioLib_DEVICE_ERROR
*
*/

int wncDevIOReadBuf
(
 WNCAN_DEVIO_FDINFO  *fdInfo,  /* pointer to DevIO file descriptor */
 char                *buffer,  /* pointer to WNCAN_CHNMSG buffer receiving bytes*/
 size_t               maxbytes /* max number of bytes to read */
 )
{
    int  key;
    int  bytesRead = 0;
    int  msgSize = sizeof(WNCAN_CHNMSG);
    
    if ( (fdInfo == NULL) || (buffer == NULL) )
    {       
#if DEVIO_DEBUG
        logMsg("wncDevIOReadBuf() ERROR: Null parameters passed in \n", 
            0,0,0,0,0,0);
#endif
        goto ErrorExit;
    }
    
    if (maxbytes < msgSize)
    {
#if DEVIO_DEBUG
        logMsg("wncDevIOReadBuf() ERROR: Incomplete CAN message data requested "
            "(maxbytes too small)\n", 0,0,0,0,0,0);
#endif
        
        goto ErrorExit;
    }
    
    /* ----------------- critical section to Read complete CAN message */
    key = intLock();
    bytesRead = rngBufGet (fdInfo->fdtype.channel.inputBuf, buffer, msgSize);
    intUnlock(key);
    /* ----------------- */
    
    if (bytesRead < 1)
    {
        /* Input data buffer is empty; Not an error */
        
#if DEVIO_DEBUG
        logMsg("wncDevIOReadBuf() INFO: Input data buffer is empty\n", 
            0,0,0,0,0,0);
#endif
    } else if (bytesRead < msgSize)
    {
        /* Incomplete CAN message received */
        
#if DEVIO_DEBUG
        logMsg("wncDevIOReadBuf() ERROR: Incomplete CAN message received\n", 
            0,0,0,0,0,0);
#endif
        
        goto ErrorExit;
    }
    
    return bytesRead;
    
ErrorExit:
    errnoSet (S_ioLib_DEVICE_ERROR);
    return ERROR;
}




/************************************************************************
*
* wncDevIOWriteBuf - device write routine 
*
* This routine is called by the VxWorks I/O System when user code calls write().
* It queues the CAN data message in "buffer" to the internal output data ring 
* buffer.  A separate function responds to the actual transmit interrupt from 
* the CAN controller to send the CAN data message from the output data buffer.
*
* RETURNS: number of bytes written, or ERROR
*
* ERRNO: S_ioLib_DEVICE_ERROR
*        S_can_invalid_parameter
*        S_can_buffer_overflow
* 
*/
int wncDevIOWriteBuf
(
 WNCAN_DEVIO_FDINFO   *fdInfo,     /* pointer to DevIO file descriptor */
 char                 *buffer,     /* pointer to WNCAN_CHNMSG buffer to write */
 size_t                maxbytes    /* number of bytes to write */
 )
{
    int  bytesWritten = ERROR;
    int  msgSize = sizeof(WNCAN_CHNMSG);
    int key;
    
    
    
    
    if ( (fdInfo == NULL) || (buffer == NULL) || (maxbytes < msgSize) )
    {
#if DEVIO_DEBUG
        logMsg("wncDevIOWriteBuf() ERROR: Incomplete CAN message data to be "
            "written\n", 0,0,0,0,0,0);
#endif
        
        errnoSet (S_can_invalid_parameter);
    }
    else
    {       
        
        BOOL ringEmptyBeforeAdd;
        
        /* ----------------- critical section to test and add to the queue */
        
        key = intLock();
        
        ringEmptyBeforeAdd = rngIsEmpty(fdInfo->fdtype.channel.outputBuf);
        bytesWritten = rngBufPut (fdInfo->fdtype.channel.outputBuf, buffer, msgSize);
        
        intUnlock(key);
        
        /* ----------------- */
        
        if (bytesWritten < msgSize)
        {
            /* Output data buffer is full */
            
#if DEVIO_DEBUG
            logMsg("wncDevIOWriteBuf() ERROR: Output data buffer is full; write() "
                "failed\n", 0,0,0,0,0,0);
#endif
            
                /* note: since the size of the message is a multiple of the total
                ** buffer size, if the buffer is full, then no portion of the message
                ** was put into the buffer (i.e. bytesWritten=0 when trying to add
                ** to a full buffer).
            */
            errnoSet (S_can_buffer_overflow);
            bytesWritten = ERROR;
        }
        
        /* if there was nothing in the buffer before adding this message,
        ** need to 'jump start' the TX process
        */
        if ((bytesWritten != ERROR) && (ringEmptyBeforeAdd))
        {
            /* initiate a TX by calling our handler */
            key = intLock();
            wncDevIOIsrHandler(fdInfo->wnDevIODrv->wncDevice, 
                WNCAN_INT_TXCLR, 
                fdInfo->fdtype.channel.channel);
            intUnlock(key);
        }
    }
    
    return bytesWritten;
}




/************************************************************************
*
* wncDevIOIsrHandler - WNC interrupt callback
*
* Service the WNC callback for TX,RX and error interrupts. 
*
* RETURNS: nothing
*
* ERRNO: S_can_buffer_overflow
*
*/
LOCAL void wncDevIOIsrHandler
(
 struct WNCAN_Device *pDev,
 WNCAN_IntType intStatus,
 UCHAR chnNum
 )
{
    WNCAN_DEVIO_FDINFO  *pDevInfo = WNCDEV_GET_DEVICEINFO(pDev);
    WNCAN_DEVIO_FDINFO  *pChnInfo = pDevInfo->fdtype.device.chnInfo[chnNum];
    WNCAN_CHNMSG         canMsg;
    STATUS               status;
    
    int     numBytes = 0;
    int     msgSize = sizeof(WNCAN_CHNMSG);
    BOOL    newdata;  /* unused, but needed for the api call */    
    
    switch(intStatus)
    {
    case WNCAN_INT_ERROR:
    case WNCAN_INT_BUS_OFF:
    case WNCAN_INT_WAKE_UP:
    /* error or bus type of interrupt, wake up the device in case
    ** application is blocking on the device's file descriptor
        */  
        selWakeupAll (&pDevInfo->selWakeupList, SELREAD);
        break;
        
    case WNCAN_INT_TX:
    /* when TX interrupt detected, free the blocked tasks. Note that
    ** we do this here instead of TXCLR because of the initial state.
    ** The initial state is when user writes into an empty buffer and
    ** there is no interrupt pending. Thus, the write will directly
    ** call this routine simulating the TXCLR interrupt. Thus, the TXCLR
    ** is called first and thus a message is transmitted. Then, when
    ** the interrupt is acknowledge, we unblock the task because now
    ** we are sure that there is enough space in the buffer for a new
    ** message.
        */
        selWakeupAll (&pChnInfo->selWakeupList, SELWRITE);
        break;
        
    case WNCAN_INT_RX:
    case WNCAN_INT_RTR_RESPONSE:
        /* get the message from the controller */
        canMsg.id = CAN_ReadID(pDev, chnNum, &canMsg.extId);  /* get ID, extId */
        /* read in the message, indicate full size (8) data buffer len */
        canMsg.len = WNCAN_MAX_DATA_LEN;
        CAN_ReadData(pDev, chnNum, canMsg.data, &canMsg.len, &newdata);
        /* do a test for RTR because the api can return an error, and if no, then
        ** the message is definately does not have RTR set
        */
        canMsg.rtr = (CAN_IsRTR(pDev, chnNum) == TRUE ? TRUE : FALSE);
        
        /* add into our buffer */
        if (rngBufPut(pChnInfo->fdtype.channel.inputBuf, 
            (char*)&canMsg, msgSize) == msgSize)
        {
            /* wake up blocked tasks */
            selWakeupAll (&pChnInfo->selWakeupList, SELREAD);
        }
        else 
        {
        /* internal buffer full, report error 
        ** NOTE: it is not advised to use logmsg here because if the controller
        ** is getting flooded, the logging of the error message will
        ** just make the overflow condition worse.
            */
#if DEVIO_DEBUG
            logMsg("wncDevIOIsrHandler() ERROR: Internal buffer full \n",0,0,0,0,0,0);
#endif
            errnoSet (S_can_buffer_overflow);
        }
        break;
        
        
    case WNCAN_INT_TXCLR:
        /* device ready to TX again if there is something in the buffer */
        numBytes = rngBufGet(pChnInfo->fdtype.channel.outputBuf, 
            (char*)&canMsg, msgSize);
        if (numBytes == msgSize)
        {
            /* message is buffer, transmit it */
            status = CAN_TxMsg(pDev, chnNum, canMsg.id, canMsg.extId, 
                canMsg.data, canMsg.len);
            
            if (status == ERROR)
            {  /* error in TX, just re-added back to the queue */
                rngBufPut(pChnInfo->fdtype.channel.outputBuf, (char*)&canMsg, msgSize);
            }
        }
        /* else nothing in the buffer, so do nothing */
        
        break;
        
    default:
        break;
    }
    
}



/************************************************************************
*
* wncDevIOIoctl - device I/O control routine
*
* This routine is called by the VxWorks I/O System when user code calls ioctl().
* It calls the appropriate WNCAN API functions to process the specified command.
*
* RETURNS: OK or ERROR
*
* ERRNO: N/A
*
*/

STATUS wncDevIOIoctl
(
 WNCAN_DEVIO_FDINFO   *fdInfo,      /* pointer to DevIO file descriptor */
 int                   command,     /* command function code */
 int                   arg          /* arbitrary argument */
 )
{
    WNCAN_DEVIO_DRVINFO*  wncDrv = NULL;
    WNCAN_DEVICE*         canDev = NULL;
    STATUS                status = ERROR;    /* pessimistic */
    
    if (fdInfo == NULL)
    {
#if DEVIO_DEBUG
        logMsg("wncDevIOIoctl() ERROR: pointer to DevIO file descriptor is null\n", 
            0,0,0,0,0,0);
#endif
        return ERROR;
    }
    
    wncDrv = fdInfo->wnDevIODrv;
    if (wncDrv == NULL)
    {
#if DEVIO_DEBUG
        logMsg("wncDevIOIoctl() ERROR: pointer to DevIO driver is null\n", 
            0,0,0,0,0,0);
#endif
        return ERROR;
    }
    
    canDev = wncDrv->wncDevice;
    if (canDev == NULL)
    {
#if DEVIO_DEBUG
        logMsg("wncDevIOIoctl() ERROR: pointer to DevIO device is null\n", 
            0,0,0,0,0,0);
#endif
        return ERROR;
    }
    
    switch (command)
    {
        /* Internal input and output data buffer commands */
    case FIOSELECT:
    case FIOUNSELECT:
        if (fdInfo->devType == FD_WNCAN_CHANNEL)
            status = wncUtilIoctlFioCmds(fdInfo, command, arg);
        else
            status = wncUtilIoctlDeviceFioCmds(fdInfo, command, arg);
        break;
        
        /* assumes the following only apply to channels */
    case FIONFREE:
    case FIONREAD:
    case FIONWRITE:
    case FIOFLUSH:
    case FIORFLUSH:
    case FIOWFLUSH:
    case FIORBUFSET:
    case FIOWBUFSET:
        status = wncUtilIoctlFioCmds (fdInfo, command, arg);
        break;
        
        
        /* CAN device commands */
    case WNCAN_HALT:
    case WNCAN_SLEEP:
    case WNCAN_WAKE:
    case WNCAN_TX_ABORT:
    case WNCAN_RXCHAN_GET:
    case WNCAN_TXCHAN_GET:
    case WNCAN_RTRREQCHAN_GET:
    case WNCAN_RTRRESPCHAN_GET:
    case WNCAN_BUSINFO_GET:
    case WNCAN_CONFIG_SET:
    case WNCAN_CONFIG_GET:
    case WNCAN_REG_SET:
    case WNCAN_REG_GET:
        status = wncUtilIoctlDeviceCmds (fdInfo, command, arg);
        break;
        
        /* CAN channel commands */
    case WNCAN_CHNCONFIG_SET:
    case WNCAN_CHNCONFIG_GET:
    case WNCAN_CHN_ENABLE:
    case WNCAN_CHN_TX:
    case WNCAN_CHNMSGLOST_GET:
    case WNCAN_CHNMSGLOST_CLEAR:
        status = wncUtilIoctlChannelCmds (fdInfo, command, arg);
        break;
        
        /* Controller-specific commands */
    case WNCAN_CTLRCONFIG_SET:
    case WNCAN_CTLRCONFIG_GET:
        status = wncUtilIoctlCtlrCmds (fdInfo, command, arg);
        break;
    }
    
    return status;
    
}    

/************************************************************************
*
* wncUtilIoctlFioCmds - utility routine to process FIO* ioctl() commands
* for a channel.
*
* This routine performs the processing for FIO* (internal input and
* output data buffer) commands specified via ioctl()
*
* RETURNS: OK or ERROR
*
* ERRNO: N/A
*
*/

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -