/* * Miscellaneous 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" typedef struct NOTIFICATION_CB_PARAM{ CY_HANDLE handle; CY_EVENT_NOTIFICATION_CB_FN notificationCbFn; }NOTIFICATION_CB_PARAM; /* This API is used to Read the Bootloder version */ CY_RETURN_STATUS CyGetFirmwareVersion( CY_HANDLE handle, CY_FIRMWARE_VERSION *firmwareVersion ) { UINT16 wValue, wIndex, wLength; UINT8 bmRequestType, bmRequest; int rStatus, ioTimeout = CY_USB_SERIAL_TIMEOUT; CY_DEVICE *device; libusb_device_handle *devHandle; if (handle == NULL) return CY_ERROR_INVALID_HANDLE; device = (CY_DEVICE *)handle; devHandle = device->devHandle; bmRequestType = CY_VENDOR_REQUEST_DEVICE_TO_HOST; bmRequest = CY_GET_VERSION_CMD; wValue = 0x00; wIndex = 0x00; wLength = CY_GET_FIRMWARE_VERSION_LEN; rStatus = libusb_control_transfer (devHandle, bmRequestType, bmRequest, wValue, wIndex, (unsigned char*)firmwareVersion, wLength, ioTimeout); if (rStatus > 0){ return CY_SUCCESS; } else if (rStatus == LIBUSB_ERROR_TIMEOUT){ CY_DEBUG_PRINT_ERROR ("CY:Time out error ..function is %s \n", __func__); return CY_ERROR_IO_TIMEOUT; } else { CY_DEBUG_PRINT_ERROR ("CY: Error in function %s ...libusb error is %d!\n", __func__, rStatus); return CY_ERROR_REQUEST_FAILED; } } /* The API resets the device */ CYWINEXPORT CY_RETURN_STATUS WINCALLCONVEN CyResetDevice ( CY_HANDLE handle /*Valid device handle*/ ) { UINT16 wValue, wIndex, wLength; UINT8 bmRequestType, bmRequest; int rStatus; CY_DEVICE *device; libusb_device_handle *devHandle; UINT32 ioTimeout = CY_USB_SERIAL_TIMEOUT; if (handle == NULL){ CY_DEBUG_PRINT_ERROR ("CY:Error invalid handle \n"); return CY_ERROR_INVALID_HANDLE; } device = (CY_DEVICE *)handle; devHandle = device->devHandle; bmRequestType = CY_VENDOR_REQUEST_DEVICE_TO_HOST; bmRequest = CY_DEVICE_RESET_CMD; wValue = 0xA6B6; wIndex = 0xADBA; wLength = 0; rStatus = libusb_control_transfer (devHandle, bmRequestType, bmRequest, wValue, wIndex, NULL, wLength, ioTimeout); //return buffer will tell the status of the command if (rStatus == LIBUSB_SUCCESS) return CY_SUCCESS; else if (rStatus == LIBUSB_ERROR_TIMEOUT){ CY_DEBUG_PRINT_ERROR ("CY:Time out error ..function is %s \n", __func__); return CY_ERROR_IO_TIMEOUT; } else { CY_DEBUG_PRINT_ERROR ("CY: Error in function %s ...libusb error is %d!\n", __func__, rStatus); return CY_ERROR_REQUEST_FAILED; } } CYWINEXPORT CY_RETURN_STATUS WINCALLCONVEN CySetGpioValue ( CY_HANDLE handle, /*Valid device handle*/ UINT8 gpioNumber, /*GPIO configuration value*/ UINT8 value /*Value that needs to be set*/ ) { UINT16 wValue, wIndex, wLength; UINT8 bmRequestType, bmRequest, buffer[CY_GPIO_SET_LEN]; int rStatus; UINT32 ioTimeout = CY_USB_SERIAL_TIMEOUT; CY_DEVICE *device; libusb_device_handle *devHandle; if (handle == NULL) return CY_ERROR_INVALID_HANDLE; device = (CY_DEVICE *)handle; devHandle = device->devHandle; if (value) value = 1; bmRequestType = CY_VENDOR_REQUEST_DEVICE_TO_HOST; bmRequest = CY_GPIO_SET_VALUE_CMD; wValue = gpioNumber; wIndex = value; wLength = 0; rStatus = libusb_control_transfer (devHandle, bmRequestType, bmRequest, wValue, wIndex, buffer, wLength, ioTimeout); if (rStatus >= 0){ CY_DEBUG_PRINT_INFO ("CY: Get Configuration of GPIO succedded...size is %d \n", rStatus); return CY_SUCCESS; } else if (rStatus == LIBUSB_ERROR_TIMEOUT){ CY_DEBUG_PRINT_ERROR ("CY:Time out error ..function is %s \n", __func__); return CY_ERROR_IO_TIMEOUT; } else { CY_DEBUG_PRINT_ERROR ("CY: Error in function %s ...libusb error is %d!\n", __func__, rStatus); return CY_ERROR_REQUEST_FAILED; } } CYWINEXPORT CY_RETURN_STATUS WINCALLCONVEN CyGetGpioValue ( CY_HANDLE handle, /*Valid device handle*/ UINT8 gpioNumber, /*GPIO configuration value*/ UINT8 *value /*Value that needs to be set*/ ) { UINT16 wValue, wIndex, wLength; UINT8 bmRequestType, bmRequest, buffer[CY_GPIO_GET_LEN]; int rStatus; CY_DEVICE *device; libusb_device_handle *devHandle; UINT32 ioTimeout = CY_USB_SERIAL_TIMEOUT; if (handle == NULL) return CY_ERROR_INVALID_HANDLE; device = (CY_DEVICE *)handle; devHandle = device->devHandle; bmRequestType = CY_VENDOR_REQUEST_DEVICE_TO_HOST; bmRequest = CY_GPIO_GET_VALUE_CMD; wValue = gpioNumber; wIndex = 0x00; wLength = CY_GPIO_GET_LEN; rStatus = libusb_control_transfer (devHandle, bmRequestType, bmRequest, wValue, wIndex, buffer, wLength, ioTimeout); if (rStatus == CY_GPIO_GET_LEN){ CY_DEBUG_PRINT_INFO ("CY: Get GPIO Configuration succedded...size is %d \n", rStatus); //return buffer will tell the status of the command if (buffer[0] == 0){ (*value) = buffer[1]; return CY_SUCCESS; } else return CY_ERROR_REQUEST_FAILED; } else if (rStatus == LIBUSB_ERROR_TIMEOUT){ CY_DEBUG_PRINT_ERROR ("CY:Time out error ..function is %s \n", __func__); return CY_ERROR_IO_TIMEOUT; } else { CY_DEBUG_PRINT_ERROR ("CY: Error in function %s ...libusb error is %d!\n", __func__, rStatus); return CY_ERROR_REQUEST_FAILED; } } static void LIBUSB_CALL uart_notification_cb(struct libusb_transfer *transfer) { UINT32 *completed = transfer->user_data; *completed = 1; } void* uartSetEventNotifcation (void *inputParameters) { int rStatus, transferCompleted = 0, length = CY_UART_EVENT_NOTIFICATION_LEN; CY_DEVICE *device; libusb_device_handle *devHandle; struct libusb_transfer *transfer; UINT16 errorStatus = 0; UCHAR uartStatus[CY_UART_EVENT_NOTIFICATION_LEN]; struct timeval time; CY_EVENT_NOTIFICATION_CB_FN callbackFn; NOTIFICATION_CB_PARAM *cbParameters = (NOTIFICATION_CB_PARAM*)inputParameters; callbackFn = cbParameters->notificationCbFn; device = (CY_DEVICE *)cbParameters->handle; devHandle = device->devHandle; callbackFn = cbParameters->notificationCbFn; device->uartTransfer = transfer = libusb_alloc_transfer(0); if (transfer == NULL){ CY_DEBUG_PRINT_ERROR ("CY:Error in allocating trasnfer \n"); errorStatus |= CY_ERROR_EVENT_FAILED_BIT; callbackFn(errorStatus); goto END; } while (device->uartCancelEvent == false){ libusb_fill_interrupt_transfer (transfer, devHandle, device->interruptEndpoint, uartStatus, length, uart_notification_cb, &transferCompleted, CY_EVENT_NOTIFICATION_TIMEOUT); rStatus = libusb_submit_transfer (transfer); if (rStatus){ CY_DEBUG_PRINT_ERROR ("CY:Error submitting uart interrupt token ... Libusb error is %d\n", rStatus); errorStatus |= CY_ERROR_EVENT_FAILED_BIT; callbackFn(errorStatus); break; } time.tv_sec = 0; time.tv_usec = 50;//polling timeout. while (transferCompleted == 0){ libusb_handle_events_timeout (glContext, &time); } transferCompleted = 0; if (transfer->status == LIBUSB_TRANSFER_COMPLETED){ CY_DEBUG_PRINT_INFO ("Successfully read and recieved data %d \n", transfer->actual_length); memcpy (&errorStatus, &uartStatus[8], 2); printf ("%x %x ", uartStatus[8], uartStatus[9]); callbackFn (errorStatus); errorStatus = 0; } else{ errorStatus |= CY_ERROR_EVENT_FAILED_BIT; if (device->uartCancelEvent == false){ CY_DEBUG_PRINT_ERROR ("CY:Error uart interrupt thread encountered error... Libusb transmission error is %d \n", transfer->status); pthread_join (device->uartThread, NULL); device->uartThreadRunning = false; callbackFn(errorStatus); } break; } } CY_DEBUG_PRINT_INFO ("Exiting notification thread \n"); libusb_free_transfer (transfer); END: free (inputParameters); return NULL; } static void LIBUSB_CALL spi_notification_cb(struct libusb_transfer *transfer) { UINT32 *completed = transfer->user_data; *completed = 1; } void* spiSetEventNotifcation (void *inputParameters) { int transferCompleted = 0, length = CY_SPI_EVENT_NOTIFICATION_LEN; CY_DEVICE *device; libusb_device_handle *devHandle; struct libusb_transfer *transfer; UINT16 spiStatus = 0; unsigned char spiStatusBuffer[2] = {0, 0}; UINT16 errorStatus = 0; struct timeval time; CY_EVENT_NOTIFICATION_CB_FN callbackFn; NOTIFICATION_CB_PARAM *cbParameters = (NOTIFICATION_CB_PARAM*)inputParameters; callbackFn = cbParameters->notificationCbFn; device = (CY_DEVICE *)cbParameters->handle; devHandle = device->devHandle; callbackFn = cbParameters->notificationCbFn; device->spiTransfer = transfer = libusb_alloc_transfer(0); if (transfer == NULL){ CY_DEBUG_PRINT_ERROR ("CY:Error in allocating trasnfer \n"); errorStatus |= CY_ERROR_EVENT_FAILED_BIT; callbackFn (errorStatus); goto END; } libusb_fill_interrupt_transfer (transfer, devHandle, device->interruptEndpoint, spiStatusBuffer, length, spi_notification_cb, &transferCompleted, CY_EVENT_NOTIFICATION_TIMEOUT); while (device->spiCancelEvent == false){ if (libusb_submit_transfer (transfer)){ CY_DEBUG_PRINT_ERROR ("CY:Error submitting spi interrupt token ... \n"); errorStatus |= CY_ERROR_EVENT_FAILED_BIT; callbackFn(errorStatus); break; } time.tv_sec = 0; time.tv_usec = 50;//polling timeout. while (transferCompleted == 0){ libusb_handle_events_timeout (glContext, &time); } transferCompleted = 0; spiStatus = (spiStatusBuffer[1] << 8) | spiStatusBuffer[0]; if (transfer->status == LIBUSB_TRANSFER_COMPLETED){ CY_DEBUG_PRINT_INFO ("Successfully read and recieved data %d \n", transfer->actual_length); if (spiStatus & CY_SPI_UNDERFLOW_ERROR){ errorStatus |= (CY_SPI_TX_UNDERFLOW_BIT); } if (spiStatus & CY_SPI_BUS_ERROR){ errorStatus |= (CY_SPI_BUS_ERROR_BIT); } callbackFn (errorStatus); errorStatus = 0; } else{ spiStatus |= CY_ERROR_EVENT_FAILED_BIT; if (device->spiCancelEvent == false){ pthread_join (device->spiThread, NULL); device->spiThreadRunning = false; CY_DEBUG_PRINT_ERROR ("CY:Error spi interrupt thread was cancelled... Libusb transmission error is %d \n", transfer->status); callbackFn (spiStatus); } break; } } libusb_free_transfer (transfer); END: free (inputParameters); pthread_exit (NULL); return NULL; } CYWINEXPORT CY_RETURN_STATUS WINCALLCONVEN CySetEventNotification( CY_HANDLE handle, /*Valid handle to communicate with device*/ CY_EVENT_NOTIFICATION_CB_FN notificationCbFn /*Call back function in case on error during Uart data transfers*/ ) { CY_DEVICE *device; NOTIFICATION_CB_PARAM *args = NULL; int ret; if (handle == NULL){ CY_DEBUG_PRINT_ERROR ("CY:Error invalid handle.. Function is %s \n", __func__); return CY_ERROR_INVALID_HANDLE; } if (notificationCbFn == NULL){ CY_DEBUG_PRINT_ERROR ("CY:Error invalid parameter.. Function is %s \n", __func__); return CY_ERROR_INVALID_PARAMETER; } device = (CY_DEVICE*)handle; pthread_mutex_lock (&device->notificationLock); args = (NOTIFICATION_CB_PARAM *)malloc (sizeof (NOTIFICATION_CB_PARAM)); args->handle = handle; args->notificationCbFn = notificationCbFn; if (device->deviceType == CY_TYPE_SPI){ if (device->spiThreadRunning) { CY_DEBUG_PRINT_ERROR ("CY:Error already notification thread exists ... Function is %s \n", __func__); free (args); pthread_mutex_unlock (&device->notificationLock); return CY_ERROR_STATUS_MONITOR_EXIST; } ret = pthread_create (&device->spiThread, NULL, spiSetEventNotifcation, (void *) args); if (ret == 0){ device->spiThreadRunning = true; pthread_mutex_unlock (&device->notificationLock); return CY_SUCCESS; } else { pthread_join (device->spiThread, NULL); device->spiThreadRunning = false; free (args); pthread_mutex_unlock (&device->notificationLock); CY_DEBUG_PRINT_ERROR ("CY:Error creating spi notification thread ... Function is %s \n", __func__); return CY_ERROR_REQUEST_FAILED; } } else if (device->deviceType == CY_TYPE_UART){ if (device->uartThreadRunning) { CY_DEBUG_PRINT_ERROR ("CY:Error already notification thread exists ... Function is %s \n", __func__); free (args); pthread_mutex_unlock (&device->notificationLock); return CY_ERROR_STATUS_MONITOR_EXIST; } ret = pthread_create (&device->uartThread, NULL, uartSetEventNotifcation, (void *) args); if (ret == 0){ device->uartThreadRunning = true; pthread_mutex_unlock (&device->notificationLock); return CY_SUCCESS; } else { pthread_join (device->uartThread, NULL); device->uartThreadRunning = false; free (args); pthread_mutex_unlock (&device->notificationLock); CY_DEBUG_PRINT_ERROR ("CY:Error creating uart notification thread ... Function is %s \n", __func__); return CY_ERROR_REQUEST_FAILED; } } else { CY_DEBUG_PRINT_ERROR ("CY:Error unknown device type ....Function is %s \n", __func__); free (args); pthread_mutex_unlock (&device->notificationLock); return CY_ERROR_REQUEST_FAILED; } } /*The API is used to cancel the uart Event notification*/ CYWINEXPORT CY_RETURN_STATUS WINCALLCONVEN CyAbortEventNotification( CY_HANDLE handle /*Valid handle to communicate with device*/ ) { CY_DEVICE *device; device = (CY_DEVICE*)handle; pthread_mutex_lock (&device->notificationLock); if (device->deviceType == CY_TYPE_UART){ if (!device->uartThreadRunning){ CY_DEBUG_PRINT_ERROR ("CY:Error uart event notification not created ....function is %s \n", __func__); pthread_mutex_unlock (&device->notificationLock); return CY_ERROR_REQUEST_FAILED; } device->uartCancelEvent = true; libusb_cancel_transfer (device->uartTransfer); pthread_join (device->uartThread, NULL); device->uartThreadRunning = false; device->uartCancelEvent = false; pthread_mutex_unlock (&device->notificationLock); return CY_SUCCESS; } else if (device->deviceType == CY_TYPE_SPI){ if (!device->spiThreadRunning){ CY_DEBUG_PRINT_ERROR ("CY:Error spi event notification not created ....function is %s \n", __func__); pthread_mutex_unlock (&device->notificationLock); return CY_ERROR_REQUEST_FAILED; } device->spiCancelEvent = true; libusb_cancel_transfer (device->spiTransfer); pthread_join (device->spiThread, NULL); device->spiThreadRunning = false; device->spiCancelEvent = false; pthread_mutex_unlock (&device->notificationLock); return CY_SUCCESS; } else { CY_DEBUG_PRINT_ERROR ("CY:Error.. unknown device type ....function is %s \n", __func__); pthread_mutex_unlock (&device->notificationLock); return CY_ERROR_REQUEST_FAILED; } } /* The API is used to programme user flash area */ CYWINEXPORT CY_RETURN_STATUS WINCALLCONVEN CyProgUserFlash ( CY_HANDLE handle, /*Valid device handle*/ CY_DATA_BUFFER *progBuffer, /*data buffer containing buffer address, length to write*/ UINT32 flashAddress, /*Address to the data is written*/ UINT32 ioTimeout /*Timeout value of the API*/ ) { UINT16 wValue, wIndex, wLength; UINT8 bmRequestType, bmRequest; int rStatus; CY_DEVICE *device; libusb_device_handle *devHandle; if (handle == NULL) return CY_ERROR_INVALID_HANDLE; if ((progBuffer == NULL) || (progBuffer->buffer == NULL)) return CY_ERROR_INVALID_PARAMETER; device = (CY_DEVICE *)handle; devHandle = device->devHandle; bmRequestType = CY_VENDOR_REQUEST_HOST_TO_DEVICE; bmRequest = CY_PROG_USER_FLASH_CMD; wValue = 0; wIndex = flashAddress; wLength = progBuffer->length; CY_DEBUG_PRINT_INFO ("CY:The Length is %d , Value is %d and index is %d\n", wLength, wValue, wIndex); rStatus = libusb_control_transfer (devHandle, bmRequestType, bmRequest, wValue, wIndex, progBuffer->buffer, wLength, ioTimeout); if (rStatus > 0){ (progBuffer->transferCount) = rStatus; return CY_SUCCESS; } else if (rStatus == LIBUSB_ERROR_TIMEOUT){ CY_DEBUG_PRINT_ERROR ("CY:Time out error ..function is %s \n", __func__); (progBuffer->transferCount) = 0; return CY_ERROR_IO_TIMEOUT; } else { CY_DEBUG_PRINT_ERROR ("CY: Error in function %s ...libusb error is %d!\n", __func__, rStatus); (progBuffer->transferCount) = 0; return CY_ERROR_REQUEST_FAILED; } } /* The API is used to programme user flash area */ CYWINEXPORT CY_RETURN_STATUS WINCALLCONVEN CyReadUserFlash ( CY_HANDLE handle, /*Valid device handle*/ CY_DATA_BUFFER *readBuffer, /*data buffer containing buffer address, length to write*/ UINT32 flashAddress, /*Address to the data is written*/ UINT32 ioTimeout /*Timeout value of the API*/ ) { UINT16 wValue, wIndex, wLength; UINT8 bmRequestType, bmRequest; int rStatus; CY_DEVICE *device; libusb_device_handle *devHandle; if (handle == NULL) return CY_ERROR_INVALID_HANDLE; if (readBuffer == NULL) return CY_ERROR_INVALID_PARAMETER; device = (CY_DEVICE *)handle; devHandle = device->devHandle; bmRequestType = CY_VENDOR_REQUEST_DEVICE_TO_HOST; bmRequest = CY_READ_USER_FLASH_CMD; wValue = 0; wIndex = flashAddress; wLength = readBuffer->length; CY_DEBUG_PRINT_INFO ("CY:The Length is %d , Value is %d and index is %d\n", wLength, wValue, wIndex); rStatus = libusb_control_transfer (devHandle, bmRequestType, bmRequest, wValue, wIndex, readBuffer->buffer, wLength, ioTimeout); if (rStatus > 0){ (readBuffer->transferCount) = rStatus; return CY_SUCCESS; } else if (rStatus == LIBUSB_ERROR_TIMEOUT){ CY_DEBUG_PRINT_ERROR ("CY:Time out error ..function is %s \n", __func__); (readBuffer->transferCount) = 0; return CY_ERROR_IO_TIMEOUT; } else { CY_DEBUG_PRINT_ERROR ("CY: Error in function %s ...libusb error is %d!\n", __func__, rStatus); (readBuffer->transferCount) = 0; return CY_ERROR_REQUEST_FAILED; } } /* This API is used to get the signature of the device. It would be CYUS when we are in actual device mode and CYBL when we are bootloader mode */ CY_RETURN_STATUS CyGetSignature ( CY_HANDLE handle, UCHAR *signature ) { UINT16 wValue, wIndex, wLength; UINT8 bmRequestType, bmRequest; int rStatus, ioTimeout = CY_USB_SERIAL_TIMEOUT; CY_DEVICE *device; libusb_device_handle *devHandle; if (handle == NULL) return CY_ERROR_INVALID_HANDLE; device = (CY_DEVICE *)handle; devHandle = device->devHandle; bmRequestType = CY_VENDOR_REQUEST_DEVICE_TO_HOST; bmRequest = CY_GET_SIGNATURE_CMD; wValue = 0x00; wIndex = 0x00; wLength = CY_GET_SIGNATURE_LEN; rStatus = libusb_control_transfer (devHandle, bmRequestType, bmRequest, wValue, wIndex, (unsigned char*)signature, wLength, ioTimeout); if (rStatus > 0){ return CY_SUCCESS; } else if (rStatus == LIBUSB_ERROR_TIMEOUT){ CY_DEBUG_PRINT_ERROR ("CY:Time out error ..function is %s \n", __func__); return CY_ERROR_IO_TIMEOUT; } else { CY_DEBUG_PRINT_ERROR ("CY: Error in function %s ...libusb error is %d!\n", __func__, rStatus); return CY_ERROR_REQUEST_FAILED; } }