/*****************************************************************************
        *
        *    acWaitEvent
        *
        *    Purpose:
        *        Wait can message or error of the CAN Controller.
        *
        *
        *    Arguments:
        *        msgRead           - managed buffer for read
        *        nReadCount        - msg number that unmanaged buffer can preserve
        *        pulNumberofRead   - real msgs have read
        *        ErrorCode         - return error code when the CAN Controller has error
        *
        *    Returns:
        *        =0 SUCCESS; or <0 failure
        *
        *****************************************************************************/
        public int acWaitEvent(AdvCan.canmsg_t[] msgRead, uint nReadCount, ref uint pulNumberofRead, ref uint ErrorCode)
        {
            int nRet = OPERATION_ERROR;

            if (AdvCan.WaitCommEvent(hDevice, lpEventCode, GCEvent.AddrOfPinnedObject()) == true)
            {
                EventCode = Marshal.ReadInt32(lpEventCode, 0);
                if ((EventCode & AdvCan.EV_RXCHAR) != 0)
                {
                    nRet = acCanRead(msgRead, nReadCount, ref pulNumberofRead);
                }
                if ((EventCode & AdvCan.EV_ERR) != 0)
                {
                    nRet = OPERATION_ERROR;
                    acClearCommError(ref ErrorCode);
                }
            }
            else
            {
                uint err = AdvCan.GetLastError();
                if (AdvCan.ERROR_IO_PENDING == err)
                {
                    if (AdvCan.GetOverlappedResult(hDevice, GCEvent.AddrOfPinnedObject(), ref pulNumberofRead, true))
                    {
                        EventCode = Marshal.ReadInt32(lpEventCode, 0);
                        if ((EventCode & AdvCan.EV_RXCHAR) != 0)
                        {
                            nRet = acCanRead(msgRead, nReadCount, ref pulNumberofRead);
                        }
                        if ((EventCode & AdvCan.EV_ERR) != 0)
                        {
                            nRet = OPERATION_ERROR;
                            acClearCommError(ref ErrorCode);
                        }
                    }
                    else
                    {
                        nRet = OPERATION_ERROR;
                    }
                }
                else
                {
                    nRet = OPERATION_ERROR;
                }
            }

            return(nRet);
        }
        /*****************************************************************************
        *
        *    acCanRead
        *
        *    Purpose:
        *        Read can message.
        *
        *
        *    Arguments:
        *        msgRead           - managed buffer for read
        *        nReadCount        - msg number that unmanaged buffer can preserve
        *        pulNumberofRead   - real msgs have read
        *
        *    Returns:
        *        =0 SUCCESS; or <0 failure
        *
        *****************************************************************************/
        public int acCanRead(AdvCan.canmsg_t[] msgRead, uint nReadCount, ref uint pulNumberofRead)
        {
            bool flag;
            int  nRet;
            uint i;

            if (nReadCount > MaxReadMsgNumber)
            {
                return(OPERATION_ERROR);
            }
            pulNumberofRead = 0;
            flag            = AdvCan.ReadFile(hDevice, orgReadBuf, nReadCount, ref pulNumberofRead, GCRead.AddrOfPinnedObject()); //Read frame
            if (flag)
            {
                if (pulNumberofRead == 0)
                {
                    nRet = TIME_OUT;
                }
                else
                {
                    for (i = 0; i < pulNumberofRead; i++)
                    {
                        if (OS_TYPE == 8)
                        {
                            msgRead[i] = (AdvCan.canmsg_t)(Marshal.PtrToStructure(new IntPtr(orgReadBuf.ToInt64() + AdvCan.CAN_MSG_LENGTH * i), typeof(AdvCan.canmsg_t)));
                        }
                        else
                        {
                            msgRead[i] = (AdvCan.canmsg_t)(Marshal.PtrToStructure(new IntPtr(orgReadBuf.ToInt32() + AdvCan.CAN_MSG_LENGTH * i), typeof(AdvCan.canmsg_t)));
                        }
                    }
                    nRet = SUCCESS;
                }
            }
            else
            {
                if (AdvCan.GetOverlappedResult(hDevice, GCRead.AddrOfPinnedObject(), ref pulNumberofRead, true))
                {
                    if (pulNumberofRead == 0)
                    {
                        nRet = TIME_OUT;                               //Package receiving timeout
                    }
                    else
                    {
                        for (i = 0; i < pulNumberofRead; i++)
                        {
                            if (OS_TYPE == 8)
                            {
                                msgRead[i] = (AdvCan.canmsg_t)(Marshal.PtrToStructure(new IntPtr(orgReadBuf.ToInt64() + AdvCan.CAN_MSG_LENGTH * i), typeof(AdvCan.canmsg_t)));
                            }
                            else
                            {
                                msgRead[i] = (AdvCan.canmsg_t)(Marshal.PtrToStructure(new IntPtr(orgReadBuf.ToInt32() + AdvCan.CAN_MSG_LENGTH * i), typeof(AdvCan.canmsg_t)));
                            }
                        }
                        nRet = SUCCESS;
                    }
                }
                else
                {
                    nRet = OPERATION_ERROR;                                    //Package receiving error
                }
            }
            return(nRet);
        }
        /*****************************************************************************
        *
        *    acCanWrite
        *
        *    Purpose:
        *        Write can msg
        *
        *
        *    Arguments:
        *        msgWrite              - managed buffer for write
        *        nWriteCount           - msg number for write
        *        pulNumberofWritten    - real msgs have written
        *
        *    Returns:
        *        =0 SUCCESS; or <0 failure
        *
        *****************************************************************************/
        public int acCanWrite(AdvCan.canmsg_t[] msgWrite, uint nWriteCount, ref uint pulNumberofWritten)
        {
            bool flag;
            int  nRet;
            uint dwErr;

            if (nWriteCount > MaxWriteMsgNumber)
            {
                return(OPERATION_ERROR);
            }
            pulNumberofWritten = 0;
            //Copy data from managed structure to unmanaged buffer
            for (int i = 0; i < nWriteCount; i++)
            {
                if (OS_TYPE == 8)
                {
                    Marshal.StructureToPtr(msgWrite[i], new IntPtr(orgWriteBuf.ToInt64() + (AdvCan.CAN_MSG_LENGTH * i)), true);
                }
                else
                {
                    Marshal.StructureToPtr(msgWrite[i], new IntPtr(orgWriteBuf.ToInt32() + (AdvCan.CAN_MSG_LENGTH * i)), true);
                }
            }
            flag = AdvCan.WriteFile(hDevice, orgWriteBuf, nWriteCount, ref pulNumberofWritten, GCWrite.AddrOfPinnedObject()); //Send frame
            if (flag)
            {
                if (nWriteCount > pulNumberofWritten)
                {
                    nRet = TIME_OUT;                          //Sending data timeout
                }
                else
                {
                    nRet = SUCCESS;                               //Sending data ok
                }
            }
            else
            {
                dwErr = AdvCan.GetLastError();
                if (dwErr == AdvCan.ERROR_IO_PENDING)
                {
                    if (AdvCan.GetOverlappedResult(hDevice, GCWrite.AddrOfPinnedObject(), ref pulNumberofWritten, true))
                    {
                        if (nWriteCount > pulNumberofWritten)
                        {
                            nRet = TIME_OUT;                    //Sending data timeout
                        }
                        else
                        {
                            nRet = SUCCESS;                         //Sending data ok
                        }
                    }
                    else
                    {
                        nRet = OPERATION_ERROR;                         //Sending data error
                    }
                }
                else
                {
                    nRet = OPERATION_ERROR;                            //Sending data error
                }
            }
            return(nRet);
        }