Updatede a shitload.
This commit is contained in:
+690
@@ -0,0 +1,690 @@
|
||||
/*
|
||||
* I2C routines of Cypress USB Serial
|
||||
* Copyright (C) 2013 Cypress Semiconductor
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "CyUSBCommon.h"
|
||||
#pragma pack(1)
|
||||
typedef struct
|
||||
{
|
||||
UINT32 frequency; /* Frequency of operation. Only valid values are
|
||||
100KHz and 400KHz. */
|
||||
UINT8 sAddress; /* Slave address to be used when in slave mode. */
|
||||
BOOL isMsbFirst; /* Whether to transmit most significant bit first. */
|
||||
BOOL isMaster; /* Whether to block is to be configured as a master:
|
||||
CyTrue - The block functions as I2C master;
|
||||
CyFalse - The block functions as I2C slave. */
|
||||
BOOL sIgnore; /* Ignore general call in slave mode. */
|
||||
BOOL clockStretch; /* Wheteher to stretch clock in case of no FIFO availability. */
|
||||
BOOL isLoopback; /* Whether to loop back TX data to RX. Valid only
|
||||
for debug purposes. */
|
||||
UCHAR reserved[6]; /*Reserved for future use*/
|
||||
} CyUsI2cConfig_t;
|
||||
#pragma pack()
|
||||
#ifdef CY_I2C_ENABLE_PRECISE_TIMING
|
||||
struct timeval startTimeWrite, endTimeWrite, startTimeRead, endTimeRead;
|
||||
//Timer helper functions for proper timing
|
||||
void startI2cTick (bool isWrite) {
|
||||
if (isWrite)
|
||||
gettimeofday (&startTimeWrite, NULL);
|
||||
else
|
||||
gettimeofday (&startTimeRead, NULL);
|
||||
}
|
||||
|
||||
UINT32 getI2cLapsedTime (bool isWrite){
|
||||
|
||||
signed int currentTime_sec, currentTime_usec, currentTime;
|
||||
if (isWrite){
|
||||
gettimeofday (&endTimeWrite, NULL);
|
||||
currentTime_sec = (endTimeWrite.tv_sec - startTimeWrite.tv_sec) * 1000;
|
||||
currentTime_usec = ((endTimeWrite.tv_usec - startTimeWrite.tv_usec)) / 1000;
|
||||
currentTime = currentTime_sec + currentTime_usec;
|
||||
return (unsigned int)currentTime;
|
||||
}
|
||||
else{
|
||||
gettimeofday (&endTimeRead, NULL);
|
||||
currentTime_sec = (endTimeRead.tv_sec - startTimeRead.tv_sec) * 1000;
|
||||
currentTime_usec = ((endTimeRead.tv_usec - startTimeRead.tv_usec)) / 1000;
|
||||
currentTime = currentTime_sec + currentTime_usec;
|
||||
return (unsigned int)currentTime;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
CY_RETURN_STATUS handleI2cError (UINT8 i2cStatus){
|
||||
|
||||
if (i2cStatus & CY_I2C_NAK_ERROR_BIT){
|
||||
CY_DEBUG_PRINT_ERROR ("CY:Error Nacked by device ...Function is %s\n", __func__);
|
||||
return CY_ERROR_I2C_NAK_ERROR;
|
||||
}
|
||||
if (i2cStatus & CY_I2C_BUS_ERROR_BIT){
|
||||
CY_DEBUG_PRINT_ERROR ("CY:Error bus error occured... Function is %s\n", __func__);
|
||||
return CY_ERROR_I2C_BUS_ERROR;
|
||||
}
|
||||
if (i2cStatus & CY_I2C_ARBITRATION_ERROR_BIT){
|
||||
CY_DEBUG_PRINT_ERROR ("CY:Error Arbitration error occured.. Function is %s\n", __func__);
|
||||
return CY_ERROR_I2C_ARBITRATION_ERROR;
|
||||
}
|
||||
if (i2cStatus & CY_I2C_STOP_BIT_ERROR){
|
||||
CY_DEBUG_PRINT_ERROR ("CY:Error Stop bit set by master..Function is %s\n", __func__);
|
||||
return CY_ERROR_I2C_STOP_BIT_SET;
|
||||
}
|
||||
else {
|
||||
//We should never hit this case!!!!
|
||||
CY_DEBUG_PRINT_ERROR ("CY:Unknown error..Function is %s\n", __func__);
|
||||
return CY_ERROR_REQUEST_FAILED;
|
||||
}
|
||||
}
|
||||
//Used internally by read and write API to check if data is received at the I2C end.
|
||||
CY_RETURN_STATUS CyI2cGetStatus (CY_HANDLE handle, bool mode, UCHAR *i2cStatus);
|
||||
CY_RETURN_STATUS waitForNotification (CY_HANDLE handle, UINT16 *bytesPending, UINT32 ioTimeout);
|
||||
/*
|
||||
This API gets the current I2C config
|
||||
for the particluar interface of the device
|
||||
*/
|
||||
CY_RETURN_STATUS CyGetI2cConfig (
|
||||
CY_HANDLE handle,
|
||||
CY_I2C_CONFIG *i2cConfig
|
||||
)
|
||||
{
|
||||
UINT16 wValue, wIndex, wLength;
|
||||
UINT8 bmRequestType, bmRequest;
|
||||
int rStatus;
|
||||
CyUsI2cConfig_t localI2cConfig;
|
||||
CY_DEVICE *device;
|
||||
libusb_device_handle *devHandle;
|
||||
UINT16 scbIndex = 0;
|
||||
UINT32 ioTimeout = CY_USB_SERIAL_TIMEOUT;
|
||||
|
||||
if (handle == NULL){
|
||||
CY_DEBUG_PRINT_ERROR ("CY:Error invalid handle.. Function is %s \n", __func__);
|
||||
return CY_ERROR_INVALID_HANDLE;
|
||||
}
|
||||
if (i2cConfig == NULL){
|
||||
CY_DEBUG_PRINT_ERROR ("CY:Error invalid parameter.. Function is %s \n", __func__);
|
||||
return CY_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
device = (CY_DEVICE *)handle;
|
||||
devHandle = device->devHandle;
|
||||
if (device->deviceType != CY_TYPE_I2C) {
|
||||
CY_DEBUG_PRINT_ERROR ("CY:Error opened device is not i2c ..Function is %s \n", __func__);
|
||||
return CY_ERROR_REQUEST_FAILED;
|
||||
}
|
||||
scbIndex = device->interfaceNum;
|
||||
if (scbIndex > 0)
|
||||
scbIndex = 1;
|
||||
bmRequestType = CY_VENDOR_REQUEST_DEVICE_TO_HOST;
|
||||
bmRequest = CY_I2C_GET_CONFIG_CMD;
|
||||
wValue = (scbIndex << CY_SCB_INDEX_POS);
|
||||
wIndex = 0x00;
|
||||
wLength = CY_I2C_CONFIG_LENGTH;
|
||||
|
||||
rStatus = libusb_control_transfer (devHandle, bmRequestType, bmRequest,
|
||||
wValue, wIndex, (unsigned char*)&localI2cConfig, wLength, ioTimeout);
|
||||
if (rStatus == CY_I2C_CONFIG_LENGTH){
|
||||
CY_DEBUG_PRINT_INFO ("CY: Read I2C config ...size is %d \n", rStatus);
|
||||
i2cConfig->frequency = localI2cConfig.frequency;
|
||||
i2cConfig->slaveAddress = localI2cConfig.sAddress;
|
||||
i2cConfig->isMaster = localI2cConfig.isMaster;
|
||||
i2cConfig->isClockStretch = localI2cConfig.clockStretch;
|
||||
return CY_SUCCESS;
|
||||
}
|
||||
else if (rStatus == LIBUSB_ERROR_NO_DEVICE) {
|
||||
CY_DEBUG_PRINT_ERROR ("CY: Device Disconnected ....Function is %s\n", __func__);
|
||||
return CY_ERROR_DEVICE_NOT_FOUND;
|
||||
}
|
||||
else if (rStatus == LIBUSB_ERROR_TIMEOUT){
|
||||
CY_DEBUG_PRINT_ERROR ("CY:Error time out ....Function is %s\n", __func__);
|
||||
return CY_ERROR_IO_TIMEOUT;
|
||||
}
|
||||
else {
|
||||
CY_DEBUG_PRINT_ERROR ("CY: Error in doing I2C read ...libusb error is %d function is %s!\n", rStatus, __func__);
|
||||
return CY_ERROR_REQUEST_FAILED;
|
||||
}
|
||||
}
|
||||
/*
|
||||
This API sets I2C config of the device for that
|
||||
interface
|
||||
*/
|
||||
CY_RETURN_STATUS CySetI2cConfig (
|
||||
CY_HANDLE handle,
|
||||
CY_I2C_CONFIG *i2cConfig
|
||||
)
|
||||
{
|
||||
UINT16 wValue, wIndex, wLength;
|
||||
UINT8 bmRequestType, bmRequest;
|
||||
CyUsI2cConfig_t localI2cConfig;
|
||||
int rStatus;
|
||||
CY_DEVICE *device = NULL;
|
||||
libusb_device_handle *devHandle;
|
||||
UINT16 scbIndex = 0;
|
||||
UINT32 ioTimeout = CY_USB_SERIAL_TIMEOUT;
|
||||
|
||||
if (handle == NULL){
|
||||
CY_DEBUG_PRINT_ERROR ("CY:Error invalid handle.. Function is %s \n", __func__);
|
||||
return CY_ERROR_INVALID_HANDLE;
|
||||
}
|
||||
if (i2cConfig == NULL){
|
||||
CY_DEBUG_PRINT_ERROR ("CY:Error invalid parameter.. Function is %s \n", __func__);
|
||||
return CY_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
if (i2cConfig->frequency < 1000 || i2cConfig->frequency > 400000){
|
||||
CY_DEBUG_PRINT_ERROR ("CY:Error frequency trying to set in out of ..range Function is %s \n", __func__);
|
||||
return CY_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
if ((i2cConfig->slaveAddress % 2) != 0){
|
||||
CY_DEBUG_PRINT_ERROR ("CY:Error slave address needs to even..Function is %s \n", __func__);
|
||||
return CY_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
device = (CY_DEVICE *)handle;
|
||||
devHandle = device->devHandle;
|
||||
scbIndex = device->interfaceNum;
|
||||
if (device->deviceType != CY_TYPE_I2C) {
|
||||
CY_DEBUG_PRINT_ERROR ("CY:Error opened device is not i2c ..Function is %s \n", __func__);
|
||||
return CY_ERROR_REQUEST_FAILED;
|
||||
}
|
||||
if (scbIndex > 0)
|
||||
scbIndex = 1;
|
||||
bmRequestType = CY_VENDOR_REQUEST_HOST_TO_DEVICE;
|
||||
bmRequest = CY_I2C_SET_CONFIG_CMD;
|
||||
wValue = (scbIndex << CY_SCB_INDEX_POS);
|
||||
wIndex = 0x00;
|
||||
wLength = CY_I2C_CONFIG_LENGTH;
|
||||
//We need to pass entire 16 bytes config structure to firmware
|
||||
//but we will not expose all the structure elements to user.
|
||||
//so filling some of the values.
|
||||
memset (&localI2cConfig, 0, CY_I2C_CONFIG_LENGTH);
|
||||
localI2cConfig.frequency = i2cConfig->frequency;
|
||||
localI2cConfig.sAddress = i2cConfig->slaveAddress;
|
||||
localI2cConfig.isMaster = i2cConfig->isMaster;
|
||||
localI2cConfig.clockStretch = i2cConfig->isClockStretch;
|
||||
localI2cConfig.isMsbFirst = 1;
|
||||
rStatus = libusb_control_transfer (devHandle, bmRequestType, bmRequest,
|
||||
wValue, wIndex, (unsigned char*)&localI2cConfig, wLength, ioTimeout);
|
||||
if (rStatus == CY_I2C_CONFIG_LENGTH){
|
||||
CY_DEBUG_PRINT_INFO ("CY: Setting I2C config successful ...\n");
|
||||
return CY_SUCCESS;
|
||||
}
|
||||
else if (rStatus == LIBUSB_ERROR_NO_DEVICE) {
|
||||
CY_DEBUG_PRINT_ERROR ("CY: Device Disconnected ....Function is %s\n", __func__);
|
||||
return CY_ERROR_DEVICE_NOT_FOUND;
|
||||
}
|
||||
else if (rStatus == LIBUSB_ERROR_TIMEOUT){
|
||||
CY_DEBUG_PRINT_ERROR ("CY:Error time out ....Function is %s\n", __func__);
|
||||
return CY_ERROR_IO_TIMEOUT;
|
||||
}
|
||||
else {
|
||||
CY_DEBUG_PRINT_ERROR ("CY: Error in doing I2C read ...libusb error is %d function is %s!\n", rStatus, __func__);
|
||||
return CY_ERROR_REQUEST_FAILED;
|
||||
}
|
||||
}
|
||||
/*
|
||||
This API reads I2C data from the specified interface of the device
|
||||
interface
|
||||
*/
|
||||
CY_RETURN_STATUS CyI2cRead (
|
||||
CY_HANDLE handle,
|
||||
CY_I2C_DATA_CONFIG *i2cDataConfig,
|
||||
CY_DATA_BUFFER *readBuffer,
|
||||
UINT32 ioTimeout
|
||||
)
|
||||
{
|
||||
int rStatus;
|
||||
CY_DEVICE *device = NULL;
|
||||
libusb_device_handle *devHandle;
|
||||
UINT16 wValue = 0, wIndex, wLength, bytesPending = 0;
|
||||
UINT8 bmRequestType, bmRequest;
|
||||
UCHAR i2cStatus[CY_I2C_GET_STATUS_LEN];
|
||||
UINT16 scbIndex = 0;
|
||||
bool mode = CY_I2C_MODE_READ;
|
||||
UINT32 elapsedTime;
|
||||
if (handle == NULL){
|
||||
CY_DEBUG_PRINT_ERROR ("CY:Error invalid handle.. Function is %s \n", __func__);
|
||||
return CY_ERROR_INVALID_HANDLE;
|
||||
}
|
||||
if ((readBuffer == NULL) || (readBuffer->buffer == NULL) || (readBuffer->length == 0)){
|
||||
CY_DEBUG_PRINT_ERROR ("CY:Error invalid parameter.. Function is %s \n", __func__);
|
||||
return CY_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
readBuffer->transferCount = 0;
|
||||
device = (CY_DEVICE *)handle;
|
||||
devHandle = device->devHandle;
|
||||
if (device->deviceType != CY_TYPE_I2C) {
|
||||
CY_DEBUG_PRINT_ERROR ("CY:Error opened device is not i2c ..Function is %s \n", __func__);
|
||||
return CY_ERROR_REQUEST_FAILED;
|
||||
}
|
||||
if (pthread_mutex_trylock (&device->readLock) == 0){
|
||||
scbIndex = device->interfaceNum;
|
||||
if (scbIndex > 0)
|
||||
scbIndex = 1;
|
||||
i2cDataConfig->slaveAddress = ((i2cDataConfig->slaveAddress & 0x7F) | (scbIndex << 7));
|
||||
bmRequestType = CY_VENDOR_REQUEST_HOST_TO_DEVICE;
|
||||
bmRequest = CY_I2C_READ_CMD;
|
||||
wValue = ((i2cDataConfig->isStopBit) | (i2cDataConfig->isNakBit << 1));
|
||||
wValue |= (((i2cDataConfig->slaveAddress) << 8));
|
||||
wIndex = readBuffer->length;
|
||||
wLength = 0;
|
||||
rStatus = CyI2cGetStatus (handle, mode, (UCHAR *)i2cStatus);
|
||||
if (rStatus == CY_SUCCESS)
|
||||
{
|
||||
if ((i2cStatus[0] & CY_I2C_ERROR_BIT)){
|
||||
CY_DEBUG_PRINT_ERROR ("CY:Error device busy ... function is %s \n", __func__);
|
||||
pthread_mutex_unlock (&device->readLock);
|
||||
return CY_ERROR_I2C_DEVICE_BUSY;
|
||||
}
|
||||
}
|
||||
rStatus = libusb_control_transfer (devHandle, bmRequestType, bmRequest,wValue, wIndex, NULL, wLength, ioTimeout);
|
||||
if (rStatus == LIBUSB_ERROR_NO_DEVICE){
|
||||
CY_DEBUG_PRINT_ERROR ("CY:Error device disconnected ... \n");
|
||||
pthread_mutex_unlock (&device->readLock);
|
||||
return CY_ERROR_DEVICE_NOT_FOUND;
|
||||
}
|
||||
if (rStatus < 0){
|
||||
CY_DEBUG_PRINT_ERROR ("CY:Error in sending Read vendor command ... Libusb Error is %d .. Function is %s \n", rStatus, __func__);
|
||||
pthread_mutex_unlock (&device->readLock);
|
||||
return CY_ERROR_I2C_DEVICE_BUSY;
|
||||
}
|
||||
//Hoping that previous calls do not take much time!!
|
||||
#ifdef CY_I2C_ENABLE_PRECISE_TIMING
|
||||
startI2cTick(false);
|
||||
#endif
|
||||
rStatus = libusb_bulk_transfer (devHandle, device->inEndpoint, readBuffer->buffer, readBuffer->length,
|
||||
(int*)&readBuffer->transferCount, ioTimeout);
|
||||
#ifdef CY_I2C_ENABLE_PRECISE_TIMING
|
||||
elapsedTime = getI2cLapsedTime(false);
|
||||
//Giving an extra 10 msec to notification to findout the status
|
||||
ioTimeout = (ioTimeout - elapsedTime);
|
||||
if (ioTimeout == 0)
|
||||
ioTimeout = 10;
|
||||
#endif
|
||||
if (rStatus == LIBUSB_SUCCESS){
|
||||
CY_DEBUG_PRINT_INFO ("CY: Successfully read i2c data.. %d bytes Read ...\n", readBuffer->transferCount);
|
||||
bytesPending = readBuffer->length;
|
||||
rStatus = waitForNotification (handle, &bytesPending, ioTimeout);
|
||||
if (rStatus)
|
||||
readBuffer->transferCount = (readBuffer->length - bytesPending);
|
||||
else
|
||||
readBuffer->transferCount = readBuffer->length;
|
||||
pthread_mutex_unlock (&device->readLock);
|
||||
return rStatus;
|
||||
}
|
||||
else if (rStatus == LIBUSB_ERROR_TIMEOUT){
|
||||
CY_DEBUG_PRINT_ERROR ("CY:Timeout error ..Function is %s\n", __func__);
|
||||
pthread_mutex_unlock (&device->readLock);
|
||||
return CY_ERROR_IO_TIMEOUT;
|
||||
}
|
||||
else if (rStatus == LIBUSB_ERROR_PIPE){
|
||||
CY_DEBUG_PRINT_INFO ("Pipe Error \n");
|
||||
rStatus = CyResetPipe (handle, device->outEndpoint);
|
||||
if (rStatus != CY_SUCCESS){
|
||||
CY_DEBUG_PRINT_ERROR ("Error in reseting the pipe \n");
|
||||
}
|
||||
else
|
||||
CY_DEBUG_PRINT_INFO ("Reset pipe succeded \n");
|
||||
|
||||
rStatus = CyI2cGetStatus (handle, mode, (UCHAR *)i2cStatus);
|
||||
if (rStatus == CY_SUCCESS)
|
||||
{
|
||||
CyI2cReset (handle, mode);
|
||||
rStatus = handleI2cError (i2cStatus[0]);
|
||||
pthread_mutex_unlock (&device->readLock);
|
||||
return rStatus;
|
||||
}
|
||||
else {
|
||||
pthread_mutex_unlock (&device->readLock);
|
||||
return CY_ERROR_I2C_DEVICE_BUSY;
|
||||
}
|
||||
}
|
||||
else if (rStatus == LIBUSB_ERROR_NO_DEVICE) {
|
||||
pthread_mutex_unlock (&device->readLock);
|
||||
CY_DEBUG_PRINT_ERROR ("CY: Device Disconnected ....Function is %s\n", __func__);
|
||||
return CY_ERROR_DEVICE_NOT_FOUND;
|
||||
}
|
||||
else if (rStatus == LIBUSB_ERROR_TIMEOUT){
|
||||
pthread_mutex_unlock (&device->readLock);
|
||||
CY_DEBUG_PRINT_ERROR ("CY:Error time out ....Function is %s\n", __func__);
|
||||
return CY_ERROR_IO_TIMEOUT;
|
||||
}
|
||||
else {
|
||||
pthread_mutex_unlock (&device->readLock);
|
||||
CY_DEBUG_PRINT_ERROR ("CY: Error in doing I2C read ...libusb error is %d function is %s!\n", rStatus, __func__);
|
||||
return CY_ERROR_REQUEST_FAILED;
|
||||
}
|
||||
}
|
||||
else{
|
||||
CY_DEBUG_PRINT_ERROR ("CY: Error API busy in servicing previous request... function is %s!\n", __func__);
|
||||
return CY_ERROR_REQUEST_FAILED;
|
||||
}
|
||||
}
|
||||
/*
|
||||
This API writes I2C data into the specified interface of the device
|
||||
*/
|
||||
CY_RETURN_STATUS CyI2cWrite (
|
||||
CY_HANDLE handle,
|
||||
CY_I2C_DATA_CONFIG *i2cDataConfig,
|
||||
CY_DATA_BUFFER *writeBuffer,
|
||||
UINT32 ioTimeout
|
||||
)
|
||||
{
|
||||
int rStatus;
|
||||
UCHAR i2cStatus[CY_I2C_GET_STATUS_LEN];
|
||||
CY_DEVICE *device;
|
||||
libusb_device_handle *devHandle;
|
||||
UINT16 wValue = 0, wIndex, wLength, bytesPending = 0;
|
||||
UINT8 bmRequestType, bmRequest;
|
||||
UINT16 scbIndex = 0;
|
||||
BOOL mode = CY_I2C_MODE_WRITE;
|
||||
UINT32 elapsedTime;
|
||||
if (handle == NULL){
|
||||
CY_DEBUG_PRINT_ERROR ("CY:Error invalid handle.. Function is %s \n", __func__);
|
||||
return CY_ERROR_INVALID_HANDLE;
|
||||
}
|
||||
if ((writeBuffer == NULL) || (writeBuffer->buffer == NULL) || (writeBuffer->length == 0)){
|
||||
CY_DEBUG_PRINT_ERROR ("CY:Error invalid parameter.. Function is %s \n", __func__);
|
||||
return CY_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
writeBuffer->transferCount = 0;
|
||||
device = (CY_DEVICE *)handle;
|
||||
devHandle = device->devHandle;
|
||||
scbIndex = device->interfaceNum;
|
||||
if (device->deviceType != CY_TYPE_I2C){
|
||||
CY_DEBUG_PRINT_ERROR ("CY:Error opened device is not i2c ..Function is %s \n", __func__);
|
||||
return CY_ERROR_REQUEST_FAILED;
|
||||
}
|
||||
if (pthread_mutex_trylock (&device->writeLock) == 0){
|
||||
if (scbIndex > 0)
|
||||
scbIndex = 1;
|
||||
bmRequestType = CY_VENDOR_REQUEST_HOST_TO_DEVICE;
|
||||
bmRequest = CY_I2C_WRITE_CMD;
|
||||
i2cDataConfig->slaveAddress = ((i2cDataConfig->slaveAddress & 0x7F) | (scbIndex << 7));
|
||||
wValue = ((i2cDataConfig->isStopBit));
|
||||
wValue |= (((i2cDataConfig->slaveAddress) << 8));
|
||||
wIndex = (UINT16)(writeBuffer->length);
|
||||
wLength = 0;
|
||||
CY_DEBUG_PRINT_INFO ("wValue is %x \n", wValue);
|
||||
//Send I2C write vendor command before actually sending the data over bulk ep
|
||||
rStatus = CyI2cGetStatus (handle, mode, (UCHAR *)i2cStatus);
|
||||
if (rStatus == CY_SUCCESS)
|
||||
{
|
||||
if ((i2cStatus[0] & CY_I2C_ERROR_BIT)){
|
||||
CY_DEBUG_PRINT_ERROR ("CY:Error ... Device busy ... function is %s \n", __func__);
|
||||
pthread_mutex_unlock (&device->writeLock);
|
||||
return CY_ERROR_I2C_DEVICE_BUSY;
|
||||
}
|
||||
}
|
||||
else if (rStatus == LIBUSB_ERROR_NO_DEVICE){
|
||||
CY_DEBUG_PRINT_ERROR ("CY:Error device not found \n");
|
||||
pthread_mutex_unlock (&device->writeLock);
|
||||
return CY_ERROR_DEVICE_NOT_FOUND;
|
||||
}
|
||||
rStatus = libusb_control_transfer (devHandle, bmRequestType, bmRequest,wValue, wIndex, NULL, wLength, ioTimeout);
|
||||
if (rStatus == LIBUSB_ERROR_NO_DEVICE){
|
||||
CY_DEBUG_PRINT_ERROR ("CY:Error device not found \n");
|
||||
pthread_mutex_unlock (&device->writeLock);
|
||||
return CY_ERROR_DEVICE_NOT_FOUND;
|
||||
}
|
||||
if (rStatus < 0){
|
||||
CY_DEBUG_PRINT_ERROR ("CY:Error in sending write vendor command ... Libusb Error is %d \n", rStatus);
|
||||
pthread_mutex_unlock (&device->writeLock);
|
||||
return CY_ERROR_I2C_DEVICE_BUSY;
|
||||
}
|
||||
//After vendor command is sent send the actual data to be sent to i2c devic
|
||||
#ifdef CY_I2C_ENABLE_PRECISE_TIMING
|
||||
startI2cTick(true);
|
||||
#endif
|
||||
rStatus = libusb_bulk_transfer (devHandle, device->outEndpoint, writeBuffer->buffer, writeBuffer->length,
|
||||
(int*)&(writeBuffer->transferCount), ioTimeout);
|
||||
#ifdef CY_I2C_ENABLE_PRECISE_TIMING
|
||||
elapsedTime = getI2cLapsedTime(true);
|
||||
ioTimeout = (ioTimeout - elapsedTime);
|
||||
//Giving an extra 10 msec to notification to findout the status
|
||||
if (ioTimeout == 0)
|
||||
ioTimeout = 10;
|
||||
#endif
|
||||
//Once the data is sent to usbserial, check if it was actually written to i2c device.
|
||||
if (rStatus == LIBUSB_SUCCESS){
|
||||
CY_DEBUG_PRINT_INFO ("CY: Successfully written i2c data.. %d bytes written ...\n", writeBuffer->transferCount);
|
||||
bytesPending = writeBuffer->length;
|
||||
rStatus = waitForNotification (handle, &bytesPending, ioTimeout);
|
||||
if (rStatus)
|
||||
writeBuffer->transferCount = (writeBuffer->length - bytesPending);
|
||||
else
|
||||
writeBuffer->transferCount = writeBuffer->length;
|
||||
pthread_mutex_unlock (&device->writeLock);
|
||||
return rStatus;
|
||||
}
|
||||
//Transaction is stallled when we hit some I2C error while the transfer
|
||||
//was going on. After we hit this error clear stall and check why we hit this by
|
||||
//CyGetStatus.
|
||||
else if (rStatus == LIBUSB_ERROR_PIPE){
|
||||
CY_DEBUG_PRINT_INFO ("CY:Pipe Error ... Function is %s\n", __func__);
|
||||
rStatus = CyResetPipe (handle, device->outEndpoint);
|
||||
if (rStatus != CY_SUCCESS){
|
||||
CY_DEBUG_PRINT_ERROR ("CY:Error in reseting the pipe ..Function is %s\n", __func__);
|
||||
}
|
||||
else
|
||||
CY_DEBUG_PRINT_INFO ("Reset pipe succeded \n");
|
||||
|
||||
rStatus = CyI2cGetStatus (handle, mode, (UCHAR *)i2cStatus);
|
||||
if (rStatus == CY_SUCCESS)
|
||||
{
|
||||
CyI2cReset (handle, mode);
|
||||
rStatus = handleI2cError (i2cStatus[0]);
|
||||
pthread_mutex_unlock (&device->writeLock);
|
||||
return rStatus;
|
||||
}
|
||||
}
|
||||
else if (rStatus == LIBUSB_ERROR_NO_DEVICE) {
|
||||
CY_DEBUG_PRINT_ERROR ("CY: Device Disconnected ....Function is %s\n", __func__);
|
||||
pthread_mutex_unlock (&device->writeLock);
|
||||
return CY_ERROR_DEVICE_NOT_FOUND;
|
||||
}
|
||||
else if (rStatus == LIBUSB_ERROR_TIMEOUT){
|
||||
CY_DEBUG_PRINT_ERROR ("CY:Error time out ....Function is %s\n", __func__);
|
||||
pthread_mutex_unlock (&device->writeLock);
|
||||
return CY_ERROR_IO_TIMEOUT;
|
||||
}
|
||||
else{
|
||||
CY_DEBUG_PRINT_ERROR ("CY: Error in doing I2C read ...libusb error is %d function is %s!\n", rStatus, __func__);
|
||||
pthread_mutex_unlock (&device->writeLock);
|
||||
return CY_ERROR_REQUEST_FAILED;
|
||||
}
|
||||
}
|
||||
else{
|
||||
CY_DEBUG_PRINT_ERROR ("CY:API busy with servicing previous request... function is %s!\n", __func__);
|
||||
return CY_ERROR_REQUEST_FAILED;
|
||||
}
|
||||
return CY_ERROR_REQUEST_FAILED;
|
||||
}
|
||||
/*
|
||||
This Api gets the current status of the I2C data transaction
|
||||
*/
|
||||
CY_RETURN_STATUS CyI2cGetStatus (
|
||||
CY_HANDLE handle,
|
||||
bool mode,
|
||||
UCHAR *i2cStatus
|
||||
)
|
||||
{
|
||||
int rStatus;
|
||||
CY_DEVICE *device;
|
||||
libusb_device_handle *devHandle;
|
||||
UINT16 wValue, wIndex, wLength, bmRequestType, bmRequest;;
|
||||
UINT16 scbIndex = 0;
|
||||
UINT32 ioTimeout = CY_USB_SERIAL_TIMEOUT;
|
||||
|
||||
if (handle == NULL)
|
||||
return CY_ERROR_INVALID_HANDLE;
|
||||
if (i2cStatus == NULL)
|
||||
return CY_ERROR_INVALID_PARAMETER;
|
||||
device = (CY_DEVICE *)handle;
|
||||
devHandle = device->devHandle;
|
||||
if (device->deviceType != CY_TYPE_I2C) {
|
||||
CY_DEBUG_PRINT_ERROR ("CY:Error opened device is not i2c .. \n");
|
||||
return CY_ERROR_REQUEST_FAILED;
|
||||
}
|
||||
scbIndex = device->interfaceNum;
|
||||
if (scbIndex > 0)
|
||||
scbIndex = 1;
|
||||
bmRequestType = CY_VENDOR_REQUEST_DEVICE_TO_HOST;
|
||||
bmRequest = CY_I2C_GET_STATUS_CMD;
|
||||
wValue = ((scbIndex << CY_SCB_INDEX_POS) | mode);
|
||||
wIndex = 0;
|
||||
wLength = CY_I2C_GET_STATUS_LEN;
|
||||
|
||||
rStatus = libusb_control_transfer (devHandle, bmRequestType, bmRequest,wValue, wIndex, (UCHAR*)i2cStatus, wLength, ioTimeout);
|
||||
if (rStatus < CY_I2C_GET_STATUS_LEN){
|
||||
CY_DEBUG_PRINT_INFO ("CY:Error in sending I2C Get Status command...Libusb error is %d\n", rStatus);
|
||||
return rStatus;
|
||||
}
|
||||
return CY_SUCCESS;
|
||||
}
|
||||
/*
|
||||
This Api resets the I2C module
|
||||
*/
|
||||
CY_RETURN_STATUS CyI2cReset (
|
||||
CY_HANDLE handle,
|
||||
BOOL resetMode
|
||||
)
|
||||
{
|
||||
int rStatus;
|
||||
CY_DEVICE *device;
|
||||
libusb_device_handle *devHandle;
|
||||
UINT16 wValue, wIndex, wLength, bmRequestType, bmRequest;
|
||||
UINT16 scbIndex = 0;
|
||||
UINT32 ioTimeout = CY_USB_SERIAL_TIMEOUT;
|
||||
|
||||
if (handle == NULL)
|
||||
return CY_ERROR_INVALID_HANDLE;
|
||||
device = (CY_DEVICE *)handle;
|
||||
devHandle = device->devHandle;
|
||||
if (device->deviceType != CY_TYPE_I2C) {
|
||||
CY_DEBUG_PRINT_ERROR ("CY:Error opened device is not i2c .. \n");
|
||||
return CY_ERROR_REQUEST_FAILED;
|
||||
}
|
||||
scbIndex = device->interfaceNum;
|
||||
if (scbIndex > 0)
|
||||
scbIndex = 1;
|
||||
bmRequestType = CY_VENDOR_REQUEST_HOST_TO_DEVICE;
|
||||
bmRequest = CY_I2C_RESET_CMD;
|
||||
wValue = ((scbIndex << CY_SCB_INDEX_POS) | resetMode );
|
||||
wIndex = 0;
|
||||
wLength = 0;
|
||||
rStatus = libusb_control_transfer (devHandle, bmRequestType, bmRequest,wValue, wIndex, NULL, wLength, ioTimeout);
|
||||
if (rStatus < 0){
|
||||
CY_DEBUG_PRINT_ERROR ("CY:Error in sending I2C Reset command ..libusb error is %d\n", rStatus);
|
||||
return CY_ERROR_REQUEST_FAILED;
|
||||
}
|
||||
return CY_SUCCESS;
|
||||
}
|
||||
static void LIBUSB_CALL i2c_notification_cb(struct libusb_transfer *transfer)
|
||||
{
|
||||
UINT32 *completed = transfer->user_data;
|
||||
*completed = 1;
|
||||
}
|
||||
|
||||
CY_RETURN_STATUS waitForNotification (CY_HANDLE handle, UINT16 *bytesPending, UINT32 ioTimeout){
|
||||
|
||||
UINT32 transferCompleted = 0, length = CY_I2C_EVENT_NOTIFICATION_LEN;
|
||||
CY_DEVICE *device;
|
||||
libusb_device_handle *devHandle;
|
||||
struct libusb_transfer *transfer;
|
||||
CY_RETURN_STATUS errorStatus, rStatus;
|
||||
UCHAR i2cStatus[CY_I2C_EVENT_NOTIFICATION_LEN];
|
||||
struct timeval time;
|
||||
|
||||
device = (CY_DEVICE *)handle;
|
||||
devHandle = device->devHandle;
|
||||
transfer = libusb_alloc_transfer(0);
|
||||
if (transfer == NULL){
|
||||
CY_DEBUG_PRINT_ERROR ("CY:Error in allocating trasnfer \n");
|
||||
errorStatus = CY_ERROR_ALLOCATION_FAILED;
|
||||
(*bytesPending) = 0;
|
||||
return errorStatus;
|
||||
//callbackFn (errorStatus, 0);
|
||||
}
|
||||
libusb_fill_interrupt_transfer (transfer, devHandle, device->interruptEndpoint, i2cStatus, length,
|
||||
i2c_notification_cb, &transferCompleted, ioTimeout);
|
||||
if (libusb_submit_transfer (transfer)){
|
||||
CY_DEBUG_PRINT_ERROR ("CY:Error in submitting interrupt transfer ...\n");
|
||||
libusb_cancel_transfer (transfer);
|
||||
libusb_free_transfer (transfer);
|
||||
(*bytesPending) = 0;
|
||||
//callbackFn (CY_ERROR_REQUEST_FAILED, 0);
|
||||
return CY_ERROR_REQUEST_FAILED;
|
||||
}
|
||||
time.tv_sec = 0;
|
||||
time.tv_usec = 50;//polling timeout.
|
||||
while (transferCompleted == 0){
|
||||
libusb_handle_events_timeout (NULL, &time);
|
||||
}
|
||||
transferCompleted = 0;
|
||||
if (transfer->status == LIBUSB_TRANSFER_COMPLETED){
|
||||
CY_DEBUG_PRINT_INFO ("CY:Info successfully recieved data on interrupt pipe length is %d \n", transfer->actual_length);
|
||||
if (i2cStatus[0] & 0x80){ //Error notification is for write
|
||||
if ((i2cStatus[0] & CY_I2C_ERROR_BIT)){
|
||||
CY_DEBUG_PRINT_INFO ("Bytes pending is %x %x %x", i2cStatus[0], i2cStatus[1], i2cStatus[2]);
|
||||
if (i2cStatus[0] & 0x1E){
|
||||
//There was some error, so reset the i2c module and usb module
|
||||
//of the device, so branch out of the loop(Check below for the errors reported).
|
||||
rStatus = CyI2cReset (device, CY_I2C_MODE_WRITE);
|
||||
if (rStatus != CY_SUCCESS)
|
||||
CY_DEBUG_PRINT_INFO ("CY:i2c reset failed \n");
|
||||
//Report the amount of byte that were actually written
|
||||
memcpy(bytesPending, &i2cStatus[1], 2);
|
||||
errorStatus = handleI2cError (i2cStatus[0]);
|
||||
}
|
||||
}
|
||||
else
|
||||
errorStatus = CY_SUCCESS;
|
||||
}
|
||||
else //Error notification is for read
|
||||
{
|
||||
if ((i2cStatus[0] & CY_I2C_ERROR_BIT)){
|
||||
CY_DEBUG_PRINT_INFO ("Bytes pending is %x %x %x", i2cStatus[0], i2cStatus[1], i2cStatus[2]);
|
||||
if (i2cStatus[0] & 0x1E){
|
||||
rStatus = CyI2cReset (device, CY_I2C_MODE_READ);
|
||||
if (rStatus != CY_SUCCESS)
|
||||
CY_DEBUG_PRINT_INFO ("CY:i2c reset failed \n");
|
||||
//Report the amount of byte that were actually written
|
||||
memcpy(bytesPending, &i2cStatus[1], 2);
|
||||
errorStatus = handleI2cError (i2cStatus[0]);
|
||||
}
|
||||
}
|
||||
else
|
||||
errorStatus = CY_SUCCESS;
|
||||
}
|
||||
libusb_free_transfer (transfer);
|
||||
return errorStatus;
|
||||
}
|
||||
else{
|
||||
libusb_cancel_transfer (transfer);
|
||||
if (transfer->status == LIBUSB_TRANSFER_TIMED_OUT){
|
||||
CY_DEBUG_PRINT_ERROR ("CY:Error Timeout in getting i2c transfer status ....\n");
|
||||
CyI2cGetStatus (handle, 1, (UCHAR *)&errorStatus);
|
||||
errorStatus = CY_ERROR_IO_TIMEOUT;
|
||||
}
|
||||
if (transfer->status == LIBUSB_TRANSFER_OVERFLOW){
|
||||
CY_DEBUG_PRINT_ERROR ("CY:Error buffer overFlow in i2c transfer status ....\n");
|
||||
errorStatus = CY_ERROR_BUFFER_OVERFLOW;
|
||||
}
|
||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED || transfer->status != LIBUSB_TRANSFER_COMPLETED){
|
||||
CY_DEBUG_PRINT_ERROR ("CY:Error in i2c transfer status ... Libusb transfer error is %d \n", transfer->status);
|
||||
errorStatus = CY_ERROR_REQUEST_FAILED;
|
||||
}
|
||||
libusb_free_transfer (transfer);
|
||||
return CY_ERROR_REQUEST_FAILED;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user