📄 wncandevio.c
字号:
/* 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 + -