MCUXpresso_MIMXRT1021xxxxx/boards/evkmimxrt1020/usb_examples/usb_device_dfu_lite/bm/dfu.c
2022-08-23 23:00:33 +08:00

1767 lines
56 KiB
C

/*
* Copyright (c) 2015, Freescale Semiconductor, Inc.
* Copyright 2017, 2019 NXP
* All rights reserved.
*
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include <stdlib.h>
/*${standard_header_anchor}*/
#include "usb_device_config.h"
#include "usb.h"
#include "usb_device.h"
#include "usb_device_ch9.h"
#include "usb_device_descriptor.h"
#include "dfu.h"
#include "dfu_timer.h"
#include "usb_flash.h"
#include "fsl_device_registers.h"
#include "clock_config.h"
#include "fsl_debug_console.h"
#include "dfu_app.h"
#include "board.h"
/*******************************************************************************
* Definitions
******************************************************************************/
#define USB_DFU_CRC_INITIALIZED_VAULE (0xFFFFFFFFU)
typedef usb_status_t (*dfu_state_func)(usb_dfu_struct_t *dfu_dev, usb_device_dfu_event_struct_t *event);
/*******************************************************************************
* Prototypes
******************************************************************************/
static usb_status_t USB_DeviceDfuDetachReqest(uint16_t wTimeout);
static usb_status_t USB_DeviceDfuDownLoadReqest(uint16_t wLength, uint8_t **data);
static usb_status_t USB_DeviceDfuUpLoadReqest(uint32_t *length, uint8_t **data);
static usb_status_t USB_DeviceDfuGetStatusReqest(uint32_t *length, uint8_t **data);
static usb_status_t USB_DeviceDfuClearStatusReqest(void);
static usb_status_t USB_DeviceDfuGetStateReqest(uint32_t *length, uint8_t **data);
static usb_status_t USB_DeviceDfuAbortReqest(void);
static usb_status_t USB_DeviceStateAppIdle(usb_dfu_struct_t *dfu_dev, usb_device_dfu_event_struct_t *event);
static usb_status_t USB_DeviceStateAppDetach(usb_dfu_struct_t *dfu_dev, usb_device_dfu_event_struct_t *event);
static usb_status_t USB_DeviceStateDfuIdle(usb_dfu_struct_t *dfu_dev, usb_device_dfu_event_struct_t *event);
static usb_status_t USB_DeviceStateDfuDnLoadSync(usb_dfu_struct_t *dfu_dev, usb_device_dfu_event_struct_t *event);
static usb_status_t USB_DeviceStateDfuDnBusy(usb_dfu_struct_t *dfu_dev, usb_device_dfu_event_struct_t *event);
static usb_status_t USB_DeviceStateDfuDnLoadIdle(usb_dfu_struct_t *dfu_dev, usb_device_dfu_event_struct_t *event);
static usb_status_t USB_DeviceStateDfuManifestSync(usb_dfu_struct_t *dfu_dev, usb_device_dfu_event_struct_t *event);
static usb_status_t USB_DeviceStateDfuManifest(usb_dfu_struct_t *dfu_dev, usb_device_dfu_event_struct_t *event);
static usb_status_t USB_DeviceStateDfuManifestWaitReset(usb_dfu_struct_t *dfu_dev,
usb_device_dfu_event_struct_t *event);
static usb_status_t USB_DeviceStateDfuUpLoadIdle(usb_dfu_struct_t *dfu_dev, usb_device_dfu_event_struct_t *event);
static usb_status_t USB_DeviceStateDfuError(usb_dfu_struct_t *dfu_dev, usb_device_dfu_event_struct_t *event);
/*******************************************************************************
* Variables
******************************************************************************/
/* DFU state function table. */
const static dfu_state_func s_dfuStateFunc[11] = {
USB_DeviceStateAppIdle, USB_DeviceStateAppDetach, USB_DeviceStateDfuIdle,
USB_DeviceStateDfuDnLoadSync, USB_DeviceStateDfuDnBusy, USB_DeviceStateDfuDnLoadIdle,
USB_DeviceStateDfuManifestSync, USB_DeviceStateDfuManifest, USB_DeviceStateDfuManifestWaitReset,
USB_DeviceStateDfuUpLoadIdle, USB_DeviceStateDfuError};
/* Instance of a DFU demo structure. */
static usb_dfu_struct_t s_UsbDeviceDfuDemo;
/* the buffer is used to store DFU downloaded data */
/*USB_DMA_NONINIT_DATA_ALIGN(USB_DATA_ALIGN_SIZE) uint8_t s_tempBuff[MAX_TRANSFER_SIZE];*/
USB_DMA_NONINIT_DATA_ALIGN(USB_DATA_ALIGN_SIZE) uint8_t dfuFirmwareBlock[MAX_TRANSFER_SIZE];
USB_DMA_NONINIT_DATA_ALIGN(USB_DATA_ALIGN_SIZE) usb_dfu_status_struct_t dfuStatus;
#if USB_DFU_BIT_CAN_UPLOAD
#define UPLOAD_SIZE (2U * MAX_TRANSFER_SIZE + 2U)
USB_DMA_NONINIT_DATA_ALIGN(USB_DATA_ALIGN_SIZE) uint8_t updateLoadData[UPLOAD_SIZE];
#endif
uint8_t g_detachRequest;
/* DFU event queue. */
static dfu_queue_t s_DfuEventQueue;
/* Flag which indicates if it has sent a short frame in UPLOAD request. */
static uint8_t s_isShortFrame = 0U;
/* DFU CRC table list */
static uint32_t s_dfuCRCTableList[256];
static uint32_t s_DfuCrcValue;
uint32_t address;
void static (*switchToApplicationMode)(void);
extern usb_device_dfu_app_struct_t g_UsbDeviceDfu;
/*******************************************************************************
* Code
******************************************************************************/
/*!
* @brief DFU CRC table creation function.
*
* This function creates the CRC table for CRC calculation.
*
* @return None.
*/
static void USB_DeviceDfuCreateCRCTableList(void)
{
/* CRC32 - polynomial reserved */
uint32_t polynomial = 0xEDB88320U;
for (uint16_t index = 0U; index < 256U; index++)
{
uint32_t crcElement = index;
uint32_t topBit = 0x00000001U;
for (uint8_t i = 0U; i < 8U; i++)
{
if (0U != (crcElement & topBit))
{
crcElement = (crcElement >> 1U) ^ polynomial;
}
else
{
crcElement = (crcElement >> 1U);
}
}
s_dfuCRCTableList[index] = crcElement;
}
}
/*!
* @brief DFU CRC calculation function.
*
* This function calculates the CRC over a buffer.
*
* @return CRC value.
*/
static uint32_t USB_DeviceDfuCalculateCRC(uint32_t crc, uint8_t *data, uint32_t length)
{
uint8_t crcIndex = 0U;
uint32_t crcReturn = crc;
uint32_t i;
for (i = 0U; i < length; i++)
{
crcIndex = (uint8_t)((crcReturn & 0x000000FFU) ^ data[i]);
crcReturn = s_dfuCRCTableList[crcIndex] ^ (crcReturn >> 8U);
}
return (crcReturn);
}
/*!
* @brief host cdc enter critical.
*
* This function is used to enter critical disable interrupt .
*
*/
static void USB_DfuEnterCritical(uint8_t *sr)
{
*sr = DisableGlobalIRQ();
__ASM("CPSID i");
}
/*!
* @brief host cdc exit critical.
*
* This function is used to exit critical ,enable interrupt .
*
*/
static void USB_DfuExitCritical(uint8_t sr)
{
EnableGlobalIRQ(sr);
}
/*!
* @brief Initialize the queue.
*
* @return Error code.
*/
static inline usb_status_t USB_DeviceDfuQueueInit(dfu_queue_t *q)
{
usb_status_t error = kStatus_USB_Error;
uint8_t usbOsaCurrentSr;
USB_DfuEnterCritical(&usbOsaCurrentSr);
(q)->head = 0U;
(q)->tail = 0U;
(q)->maxSize = DFU_EVENT_QUEUE_MAX;
(q)->curSize = 0U;
(q)->mutex = (osa_mutex_handle_t)(&(q)->mutexBuffer[0]);
if (KOSA_StatusSuccess != OSA_MutexCreate(((q)->mutex)))
{
usb_echo("queue mutex create error!");
}
error = kStatus_USB_Success;
USB_DfuExitCritical(usbOsaCurrentSr);
return error;
}
/*!
* @brief Delete the queue.
*
* @return Error code.
*/
/*
static inline usb_status_t USB_DeviceDfuQueueDelete(dfu_queue_t *q)
{
usb_status_t error = kStatus_USB_Error;
uint8_t usbOsaCurrentSr;
USB_DfuEnterCritical(&usbOsaCurrentSr);
(q)->head = 0U;
(q)->tail = 0U;
(q)->maxSize = 0U;
(q)->curSize = 0U;
error = kStatus_USB_Success;
USB_DfuExitCritical(usbOsaCurrentSr);
return error;
}
*/
/*!
* @brief Check if the queue is empty.
*
* @return 1: queue is empty, 0: not empty.
*/
static inline uint8_t USB_DeviceDfuQueueIsEmpty(dfu_queue_t *q)
{
return ((q)->curSize == 0) ? 1U : 0U;
}
/*!
* @brief Check if the queue is full.
*
* @return 1: queue is full, 0: not full.
*/
static inline uint8_t USB_DeviceDfuQueueIsFull(dfu_queue_t *q)
{
return ((q)->curSize >= (q)->maxSize) ? 1U : 0U;
}
/*!
* @brief Get the size of the queue.
*
* @return Size of the quue.
*/
/*static inline uint32_t USB_DeviceDfuQueueSize(dfu_queue_t *q)
{
return (q)->curSize;
}*/
/*!
* @brief Put element into the queue.
*
* @return Error code.
*/
static inline usb_status_t USB_DeviceDfuQueuePut(dfu_queue_t *q, usb_device_dfu_event_struct_t *e)
{
usb_status_t error = kStatus_USB_Error;
uint8_t usbOsaCurrentSr;
USB_DfuEnterCritical(&usbOsaCurrentSr);
if (0U == USB_DeviceDfuQueueIsFull(q))
{
(q)->qArray[(q)->head++] = *(e);
if ((q)->head == (q)->maxSize)
{
(q)->head = 0U;
}
(q)->curSize++;
error = kStatus_USB_Success;
}
USB_DfuExitCritical(usbOsaCurrentSr);
return error;
}
/*!
* @brief Get element from the queue.
*
* @return Error code.
*/
static inline usb_status_t USB_DeviceDfuQueueGet(dfu_queue_t *q, usb_device_dfu_event_struct_t *e)
{
usb_status_t error = kStatus_USB_Error;
uint8_t usbOsaCurrentSr;
USB_DfuEnterCritical(&usbOsaCurrentSr);
if (0U == USB_DeviceDfuQueueIsEmpty(q))
{
*(e) = (q)->qArray[(q)->tail++];
if ((q)->tail == (q)->maxSize)
{
(q)->tail = 0U;
}
(q)->curSize--;
error = kStatus_USB_Success;
}
USB_DfuExitCritical(usbOsaCurrentSr);
return error;
}
/*!
* @brief DFU set state function.
*
* This function sets the state for a device.
*
* @return kStatus_USB_Success.
*/
static usb_status_t USB_DeviceDfuSetState(usb_dfu_state_struct_t state)
{
uint8_t usbOsaCurrentSr;
USB_DfuEnterCritical(&usbOsaCurrentSr);
s_UsbDeviceDfuDemo.dfuStatus->bState = state;
USB_DfuExitCritical(usbOsaCurrentSr);
return kStatus_USB_Success;
}
/*!
* @brief DFU get state function.
*
* This function gets the state for a device.
*
* @return The state of the device.
*/
static usb_dfu_state_struct_t USB_DeviceDfuGetState(void)
{
return (usb_dfu_state_struct_t)s_UsbDeviceDfuDemo.dfuStatus->bState;
}
/*!
* @brief DFU set status function.
*
* This function sets the status for a device.
*
* @return kStatus_USB_Success.
*/
static usb_status_t USB_DeviceDfuSetStatus(uint32_t status)
{
uint8_t usbOsaCurrentSr;
USB_DfuEnterCritical(&usbOsaCurrentSr);
s_UsbDeviceDfuDemo.dfuStatus->bStatus = status;
USB_DfuExitCritical(usbOsaCurrentSr);
return kStatus_USB_Success;
}
/*!
* @brief DFU get status function.
*
* This function gets the status for a device.
*
* @return The status of the device.
*/
static uint32_t USB_DeviceDfuGetStatus(void)
{
return s_UsbDeviceDfuDemo.dfuStatus->bStatus;
}
#if USB_DFU_BIT_WILL_DETACH
#else
/*!
* @brief DFU detach timeout routine.
*
* This function serves as the timeout routine for DETACH request.
*
* @return None.
*/
static void USB_DeviceDfuDetachTimeoutIsr(void)
{
usb_status_t error = kStatus_USB_Success;
usb_device_dfu_event_struct_t event;
event.name = kUSB_DeviceDfuEventDetachTimeout;
event.wValue = 0U;
event.wLength = 0U;
error = USB_DeviceDfuQueuePut(&s_DfuEventQueue, &event);
if (kStatus_USB_Success != error)
{
/* The queue is full, set the status to error unknown */
USB_DeviceDfuSetStatus(USB_DFU_STATUS_ERR_UNKNOWN);
}
}
#endif
/*!
* @brief DFU poll timeout routine.
*
* This function serves as the timeout routine for GET_STATUS request.
*
* @return None.
*/
static void USB_DeviceDfuPollTimeoutIsr(void)
{
usb_status_t error = kStatus_USB_Success;
usb_device_dfu_event_struct_t event;
event.name = kUSB_DeviceDfuEventPollTimeout;
event.wValue = 0U;
event.wLength = 0U;
error = USB_DeviceDfuQueuePut(&s_DfuEventQueue, &event);
if (kStatus_USB_Success != error)
{
/* The queue is full, set the status to error unknown */
USB_DeviceDfuSetStatus(USB_DFU_STATUS_ERR_UNKNOWN);
}
}
/*!
* @brief DFU DETACH request function.
*
* This function validates the request against the current state And informs the
* state function via the event queue.
*
* @return A USB error code or kStatus_USB_Success.
*/
static usb_status_t USB_DeviceDfuDetachReqest(uint16_t wTimeout)
{
usb_status_t error = kStatus_USB_Success;
usb_dfu_state_struct_t state;
usb_device_dfu_event_struct_t event;
uint32_t status;
if (wTimeout > USB_DFU_DETACH_TIMEOUT)
{
/* wTimeout should not contain a value larger than the value specified in wDetachTimeout,
or return kStatus_USB_InvalidRequest to stall endpoint. */
return kStatus_USB_InvalidRequest;
}
state = USB_DeviceDfuGetState();
if (kState_AppIdle != state)
{
USB_DeviceDfuSetStatus(USB_DFU_STATUS_ERR_STALLEDPKT);
}
status = USB_DeviceDfuGetStatus();
event.name = kUSB_DeviceDfuEventDetachReq;
event.wValue = wTimeout;
event.wLength = 0U;
error = USB_DeviceDfuQueuePut(&s_DfuEventQueue, &event);
if (kStatus_USB_Success != error)
{
/* The queue is full, set the status to error unknown */
USB_DeviceDfuSetStatus(USB_DFU_STATUS_ERR_UNKNOWN);
}
if (USB_DFU_STATUS_ERR_STALLEDPKT == status)
{
/* Stall the control pipe. */
error = kStatus_USB_InvalidRequest;
}
else
{
error = kStatus_USB_Success;
}
return error;
}
/*!
* @brief DFU DNLOAD request function.
*
* This function validates the request against the current state And informs the
* state function via the event queue.
*
* @return A USB error code or kStatus_USB_Success.
*/
static usb_status_t USB_DeviceDfuDownLoadReqest(uint16_t wLength, uint8_t **data)
{
usb_status_t error = kStatus_USB_Success;
usb_dfu_state_struct_t state;
usb_device_dfu_event_struct_t event;
uint32_t status;
state = USB_DeviceDfuGetState();
if (wLength > MAX_TRANSFER_SIZE)
{
wLength = MAX_TRANSFER_SIZE;
}
if ((kState_DfuIdle == state) || (kState_DfuDnLoadIdle == state))
{
if (USB_DFU_BIT_CAN_DNLOAD && (wLength > 0U))
{
/* store the fimware block data */
/*memcpy((void *)s_UsbDeviceDfuDemo.dfuFirmwareBlock, *data, wLength);*/
}
else if (0U == wLength)
{
status = USB_DeviceDfuGetStatus();
if (USB_DFU_STATUS_ERR_NOT_DONE == status)
{
USB_DeviceDfuSetStatus(USB_DFU_STATUS_ERR_STALLEDPKT);
}
}
else
{
USB_DeviceDfuSetStatus(USB_DFU_STATUS_ERR_STALLEDPKT);
}
}
else
{
USB_DeviceDfuSetStatus(USB_DFU_STATUS_ERR_STALLEDPKT);
}
status = USB_DeviceDfuGetStatus();
event.name = kUSB_DeviceDfuEventDnloadReq;
event.wValue = 0U;
event.wLength = wLength;
error = USB_DeviceDfuQueuePut(&s_DfuEventQueue, &event);
if (kStatus_USB_Success != error)
{
/* The queue is full, set the status to error unknown */
USB_DeviceDfuSetStatus(USB_DFU_STATUS_ERR_UNKNOWN);
}
if (USB_DFU_STATUS_ERR_STALLEDPKT == status)
{
/* Stall the control pipe. */
error = kStatus_USB_InvalidRequest;
}
else
{
error = kStatus_USB_Success;
}
return error;
}
/*!
* @brief DFU UPLOAD request function.
*
* This function validates the request against the current state, assign the appropriate buffer
* and length for the UPLOAD request. And informs the state function via the event queue.
*
* @return A USB error code or kStatus_USB_Success.
*/
static usb_status_t USB_DeviceDfuUpLoadReqest(uint32_t *length, uint8_t **data)
{
usb_status_t error = kStatus_USB_Success;
usb_dfu_state_struct_t state;
usb_device_dfu_event_struct_t event;
uint32_t status;
uint32_t uploadLength;
uint32_t i;
uploadLength = *((uint32_t *)length);
if (uploadLength > MAX_TRANSFER_SIZE)
{
/* The maximum length should not exceed the value specified in the wTransferSize field,
or return kStatus_USB_InvalidRequest to stall endpoint. */
return kStatus_USB_InvalidRequest;
}
state = USB_DeviceDfuGetState();
if (kState_DfuIdle == state)
{
#if USB_DFU_BIT_CAN_UPLOAD
s_isShortFrame = 0U;
/* get firmware start address from USB_DFU_APP_ADDRESS address */
s_UsbDeviceDfuDemo.dfuFirmwareAddress = (uint32_t)&updateLoadData[0];
/* get firmware size from USB_DFU_APP_ADDRESS + 4 address */
s_UsbDeviceDfuDemo.dfuFirmwareSize = UPLOAD_SIZE;
if ((0U == s_UsbDeviceDfuDemo.dfuFirmwareSize) || (NULL == s_UsbDeviceDfuDemo.dfuFirmwareAddress))
{
USB_DeviceDfuSetState(kState_DfuError);
USB_DeviceDfuSetStatus(USB_DFU_STATUS_ERR_STALLEDPKT);
error = kStatus_USB_InvalidRequest;
}
else
{
usb_echo("\nUploading firmware ...\n");
s_UsbDeviceDfuDemo.dfuStatus->bState = kState_DfuUpLoadIdle;
s_UsbDeviceDfuDemo.dfuCurrentUploadLenght = 0U;
for (i = 0U; i < uploadLength; i++)
{
s_UsbDeviceDfuDemo.dfuFirmwareBlock[i] = (((uint8_t *)s_UsbDeviceDfuDemo.dfuFirmwareAddress))[i];
}
s_UsbDeviceDfuDemo.dfuCurrentUploadLenght += uploadLength;
*length = uploadLength;
*data = s_UsbDeviceDfuDemo.dfuFirmwareBlock;
}
#else
USB_DeviceDfuSetStatus(USB_DFU_STATUS_ERR_STALLEDPKT);
#endif
}
else if (kState_DfuUpLoadIdle == state)
{
/* uploading indicator */
usb_echo("&");
if (s_UsbDeviceDfuDemo.dfuFirmwareSize - s_UsbDeviceDfuDemo.dfuCurrentUploadLenght >= uploadLength)
{
for (i = 0U; i < uploadLength; i++)
{
s_UsbDeviceDfuDemo.dfuFirmwareBlock[i] =
(((uint8_t *)s_UsbDeviceDfuDemo.dfuFirmwareAddress) + s_UsbDeviceDfuDemo.dfuCurrentUploadLenght)[i];
}
s_UsbDeviceDfuDemo.dfuCurrentUploadLenght += uploadLength;
*length = uploadLength;
*data = s_UsbDeviceDfuDemo.dfuFirmwareBlock;
}
else
{
usb_echo("\nUploading firmware completed.\n");
*length = s_UsbDeviceDfuDemo.dfuFirmwareSize - s_UsbDeviceDfuDemo.dfuCurrentUploadLenght;
for (i = 0U; i < *length; i++)
{
s_UsbDeviceDfuDemo.dfuFirmwareBlock[i] =
(((uint8_t *)s_UsbDeviceDfuDemo.dfuFirmwareAddress) + s_UsbDeviceDfuDemo.dfuCurrentUploadLenght)[i];
}
s_UsbDeviceDfuDemo.dfuCurrentUploadLenght += *length;
*data = s_UsbDeviceDfuDemo.dfuFirmwareBlock;
s_isShortFrame = 1U;
}
}
else
{
USB_DeviceDfuSetStatus(USB_DFU_STATUS_ERR_STALLEDPKT);
}
status = USB_DeviceDfuGetStatus();
event.name = kUSB_DeviceDfuEventUploadReq;
event.wValue = 0U;
event.wLength = *length;
error = USB_DeviceDfuQueuePut(&s_DfuEventQueue, &event);
if (kStatus_USB_Success != error)
{
/* The queue is full, set the status to error unknown */
USB_DeviceDfuSetStatus(USB_DFU_STATUS_ERR_UNKNOWN);
}
if (USB_DFU_STATUS_ERR_STALLEDPKT == status)
{
/* Stall the control pipe. */
error = kStatus_USB_InvalidRequest;
}
else
{
error = kStatus_USB_Success;
}
return error;
}
/*!
* @brief DFU GET_STATUS request function.
*
* This function validates the request against the current state, sends the current status. And informs the
* state function via the event queue.
*
* @return A USB error code or kStatus_USB_Success.
*/
static usb_status_t USB_DeviceDfuGetStatusReqest(uint32_t *length, uint8_t **data)
{
usb_status_t error = kStatus_USB_Success;
usb_dfu_state_struct_t state;
usb_device_dfu_event_struct_t event;
uint32_t status;
state = USB_DeviceDfuGetState();
if ((kState_DfuDnBusy == state) || (kState_DfuManifest == state))
{
USB_DeviceDfuSetStatus(USB_DFU_STATUS_ERR_STALLEDPKT);
}
else
{
/* Device returns the status response */
*data = (uint8_t *)s_UsbDeviceDfuDemo.dfuStatus;
*length = 6U;
}
status = USB_DeviceDfuGetStatus();
event.name = kUSB_DeviceDfuEventGetStatusReq;
event.wValue = 0U;
event.wLength = *length;
error = USB_DeviceDfuQueuePut(&s_DfuEventQueue, &event);
if (kStatus_USB_Success != error)
{
/* The queue is full, set the status to error unknown */
USB_DeviceDfuSetStatus(USB_DFU_STATUS_ERR_UNKNOWN);
}
if (USB_DFU_STATUS_ERR_STALLEDPKT == status)
{
/* Stall the control pipe. */
error = kStatus_USB_InvalidRequest;
}
else
{
error = kStatus_USB_Success;
}
return error;
}
/*!
* @brief DFU CLEAR_STATUS request function.
*
* This function validates the request against the current state. And informs the
* state function via the event queue.
*
* @return A USB error code or kStatus_USB_Success.
*/
static usb_status_t USB_DeviceDfuClearStatusReqest(void)
{
usb_status_t error = kStatus_USB_Success;
usb_dfu_state_struct_t state;
usb_device_dfu_event_struct_t event;
uint32_t status;
state = USB_DeviceDfuGetState();
if (kState_DfuError == state)
{
USB_DeviceDfuSetStatus(USB_DFU_STATUS_OK);
}
else
{
USB_DeviceDfuSetStatus(USB_DFU_STATUS_ERR_STALLEDPKT);
}
status = USB_DeviceDfuGetStatus();
event.name = kUSB_DeviceDfuEventClearStatusReq;
event.wValue = 0U;
event.wLength = 0U;
error = USB_DeviceDfuQueuePut(&s_DfuEventQueue, &event);
if (kStatus_USB_Success != error)
{
/* The queue is full, set the status to error unknown */
USB_DeviceDfuSetStatus(USB_DFU_STATUS_ERR_UNKNOWN);
}
if (USB_DFU_STATUS_ERR_STALLEDPKT == status)
{
/* Stall the control pipe. */
error = kStatus_USB_InvalidRequest;
}
else
{
error = kStatus_USB_Success;
}
return error;
}
/*!
* @brief DFU GET_STATE request function.
*
* This function validates the request against the current state, sends the current
* state. And informs the state function via the event queue.
*
* @return A USB error code or kStatus_USB_Success.
*/
static usb_status_t USB_DeviceDfuGetStateReqest(uint32_t *length, uint8_t **data)
{
usb_status_t error = kStatus_USB_Success;
usb_dfu_state_struct_t state;
usb_device_dfu_event_struct_t event;
uint32_t status;
state = USB_DeviceDfuGetState();
if ((kState_DfuDnBusy == state) || (kState_DfuManifest == state))
{
USB_DeviceDfuSetStatus(USB_DFU_STATUS_ERR_STALLEDPKT);
}
else
{
/* Device returns the state response */
*data = (uint8_t *)&s_UsbDeviceDfuDemo.dfuStatus->bState;
*length = 1U;
}
status = USB_DeviceDfuGetStatus();
event.name = kUSB_DeviceDfuEventGetStateReq;
event.wValue = 0U;
event.wLength = *length;
error = USB_DeviceDfuQueuePut(&s_DfuEventQueue, &event);
if (kStatus_USB_Success != error)
{
/* The queue is full, set the status to error unknown */
USB_DeviceDfuSetStatus(USB_DFU_STATUS_ERR_UNKNOWN);
}
if (USB_DFU_STATUS_ERR_STALLEDPKT == status)
{
/* Stall the control pipe. */
error = kStatus_USB_InvalidRequest;
}
else
{
error = kStatus_USB_Success;
}
return error;
}
/*!
* @brief DFU ABORT request function.
*
* This function validates the request against the current state. And informs the
* state function via the event queue.
*
* @return A USB error code or kStatus_USB_Success.
*/
static usb_status_t USB_DeviceDfuAbortReqest(void)
{
usb_status_t error = kStatus_USB_Success;
usb_dfu_state_struct_t state;
usb_device_dfu_event_struct_t event;
uint32_t status;
state = USB_DeviceDfuGetState();
if ((kState_DfuIdle == state) || (kState_DfuDnLoadIdle == state) || (kState_DfuUpLoadIdle == state))
{
}
else
{
USB_DeviceDfuSetStatus(USB_DFU_STATUS_ERR_STALLEDPKT);
}
status = USB_DeviceDfuGetStatus();
event.name = kUSB_DeviceDfuEventAbortReq;
event.wValue = 0U;
event.wLength = 0U;
error = USB_DeviceDfuQueuePut(&s_DfuEventQueue, &event);
if (kStatus_USB_Success != error)
{
/* The queue is full, set the status to error unknown */
USB_DeviceDfuSetStatus(USB_DFU_STATUS_ERR_UNKNOWN);
}
if (USB_DFU_STATUS_ERR_STALLEDPKT == status)
{
/* Stall the control pipe. */
error = kStatus_USB_InvalidRequest;
}
else
{
error = kStatus_USB_Success;
}
return error;
}
/*!
* @brief DFU switch mode function.
*
* This function Handle class-specific request.
*
* @return A USB error code or kStatus_USB_Success..
*/
usb_status_t USB_DeviceDfuClassRequest(usb_device_handle handle,
usb_setup_struct_t *setup,
uint8_t **buffer,
uint32_t *length)
{
usb_status_t error = kStatus_USB_InvalidRequest;
if ((setup->bmRequestType & USB_REQUEST_TYPE_RECIPIENT_MASK) != USB_REQUEST_TYPE_RECIPIENT_INTERFACE)
{
return error;
}
if ((setup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) == USB_REQUEST_TYPE_DIR_OUT)
{
switch (setup->bRequest)
{
case USB_DEVICE_DFU_DETACH:
if (setup->wLength == 0U)
{
error = USB_DeviceDfuDetachReqest(setup->wValue);
}
break;
case USB_DEVICE_DFU_DNLOAD:
error = USB_DeviceDfuDownLoadReqest(setup->wLength, buffer);
break;
case USB_DEVICE_DFU_CLRSTATUS:
if (setup->wLength == 0U)
{
error = USB_DeviceDfuClearStatusReqest();
}
break;
case USB_DEVICE_DFU_ABORT:
if (setup->wLength == 0U)
{
error = USB_DeviceDfuAbortReqest();
}
break;
default:
break;
}
}
else
{
switch (setup->bRequest)
{
case USB_DEVICE_DFU_UPLOAD:
error = USB_DeviceDfuUpLoadReqest(length, buffer);
break;
case USB_DEVICE_DFU_GETSTATUS:
if (setup->wLength != 0U)
{
error = USB_DeviceDfuGetStatusReqest(length, buffer);
}
break;
case USB_DEVICE_DFU_GETSTATE:
if (setup->wLength != 0U)
{
error = USB_DeviceDfuGetStateReqest(length, buffer);
}
break;
default:
break;
}
}
return error;
}
/*!
* @brief DFU switch mode function.
*
* This function switches the device from DFU mode to APP mode.
*
* @return None.
*/
void USB_DeviceDfuSwitchMode(void)
{
s_DfuCrcValue = (uint32_t)(USB_DFU_APP_ADDRESS);
static uint32_t newSP, newPC;
#if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
if (kStatus_USB_Success != USB_DeviceDeinit(g_UsbDeviceDfu.deviceHandle))
{
usb_echo("device deinit error\r\n");
}
#else
(void)USB_DeviceDeinit(g_UsbDeviceDfu.deviceHandle);
#endif
SCB->VTOR = s_DfuCrcValue;
newSP = ((uint32_t *)s_DfuCrcValue)[0U];
newPC = ((uint32_t *)s_DfuCrcValue)[1U];
__set_CONTROL(0x00000000U);
/* load new value to stack pointer and program counter */
__set_MSP(newSP);
switchToApplicationMode = (void (*)(void))newPC;
#if (0U != __CORTEX_M)
/* reset FAULTMASK register */
__set_FAULTMASK(0x00000000U);
#endif
/* switch to application mode */
switchToApplicationMode();
/* avoid the pop before jump instruction */
__ASM("nop");
}
/*!
* @brief DFU USB bus reset function.
*
* This function resets the USB bus by resetting the system.
*
* @return None.
*/
void USB_DeviceDfuBusReset(void)
{
switch (s_UsbDeviceDfuDemo.dfuStatus->bState)
{
case kState_AppIdle:
/* Do nothing */
break;
case kState_AppDetach:
/* Enter DFU mode */
USB_DeviceDfuSetState(kState_DfuIdle);
/*g_detachRequest = 1U;*/
/* Switch to DFU mode */
/*NVIC_SystemReset();*/
break;
case kState_DfuIdle:
case kState_DfuDnLoadSync:
case kState_DfuDnBusy:
case kState_DfuDnLoadIdle:
case kState_DfuManifestSync:
case kState_DfuManifest:
case kState_DfuManifestWaitReset:
case kState_DfuUpLoadIdle:
case kState_DfuError:
if (0U != s_UsbDeviceDfuDemo.dfuIsDownloadingFinished)
{
s_UsbDeviceDfuDemo.dfuStatus->bState = kState_AppIdle;
s_UsbDeviceDfuDemo.dfuIsDownloadingFinished = 0U;
/* switch to APP mode */
/*NVIC_SystemReset();*/
}
else
{
if (USB_DFU_BLOCK_TRANSFER_UNDEFINED != s_UsbDeviceDfuDemo.dfuFirmwareBlockStatus)
{
/* The firmware is downloading to the device but the bus reset occurs, change
the state to Error */
s_UsbDeviceDfuDemo.dfuStatus->bState = kState_DfuError;
s_UsbDeviceDfuDemo.dfuFirmwareBlockStatus = USB_DFU_BLOCK_TRANSFER_UNDEFINED;
}
else
{
/* the downloading is not started yet, there is no firmware is downloaded */
/* do nothing */
}
}
break;
default:
break;
}
}
/*!
* @brief DFU demo initialization function.
*
* This function initializes the state of the device..
*
* @return None.
*/
void USB_DeviceDfuDemoInit(void)
{
/* memmory status */
usb_memmory_status_t memmoryStatus = kStatus_USB_MemmoryErrorUnknown;
/* Default DFU status */
s_UsbDeviceDfuDemo.dfuStatus = &dfuStatus;
s_UsbDeviceDfuDemo.dfuStatus->bStatus = USB_DFU_STATUS_OK;
s_UsbDeviceDfuDemo.dfuStatus->bwPollTimeout[0U] = 0x4U;
s_UsbDeviceDfuDemo.dfuStatus->bwPollTimeout[1U] = 0U;
s_UsbDeviceDfuDemo.dfuStatus->bwPollTimeout[2U] = 0U;
USB_DeviceDfuSetState(kState_DfuIdle);
s_UsbDeviceDfuDemo.dfuStatus->iString = 0U;
s_UsbDeviceDfuDemo.dfuFirmwareBlockStatus = USB_DFU_BLOCK_TRANSFER_UNDEFINED;
s_UsbDeviceDfuDemo.dfuManifestationPhaseStatus = USB_DFU_MANIFEST_UNDEFINED;
s_UsbDeviceDfuDemo.dfuFirmwareAddress = USB_DFU_APP_ADDRESS;
s_UsbDeviceDfuDemo.dfuFirmwareSize = 0U;
s_UsbDeviceDfuDemo.dfuIsTheFirstBlock = 0U;
s_UsbDeviceDfuDemo.dfuCRC = USB_DFU_CRC_INITIALIZED_VAULE;
s_UsbDeviceDfuDemo.dfuFirmwareBlock = &dfuFirmwareBlock[0];
g_detachRequest = 0U;
USB_DeviceDfuQueueInit(&s_DfuEventQueue);
USB_DeviceDfuCreateCRCTableList();
memmoryStatus = USB_MemmoryInit();
if (kStatus_USB_MemmoryErrorSecure == memmoryStatus)
{
s_UsbDeviceDfuDemo.dfuStatus->bStatus = USB_DFU_STATUS_ERR_WRITE;
}
else if (kStatus_USB_MemmoryErrorUnknown == memmoryStatus)
{
s_UsbDeviceDfuDemo.dfuStatus->bStatus = USB_DFU_STATUS_ERR_UNKNOWN;
}
else
{
}
#if USB_DFU_BIT_CAN_UPLOAD
uint32_t *temp;
temp = (uint32_t *)&updateLoadData[0];
for (uint32_t i = 0U; i < (UPLOAD_SIZE / 4U - 2U); i++)
{
temp[i] = i;
}
#endif
DFU_TimerInit();
}
/*!
* @brief DFU manifest function.
*
* This function does manifestation operation in MANIFEST state.
*
* @return None.
*/
void USB_DeviceDfuManifest(void)
{
/*do some thing to manifest*/
/* store the fimware block data */
if (USB_DFU_MANIFEST_IN_PROGRESS == s_UsbDeviceDfuDemo.dfuManifestationPhaseStatus)
{
s_DfuCrcValue = 0;
uint32_t remainingLen = s_UsbDeviceDfuDemo.dfuFirmwareSize - 4;
uint8_t *startAddress = (uint8_t *)USB_DFU_APP_ADDRESS;
s_UsbDeviceDfuDemo.dfuCRC = USB_DFU_CRC_INITIALIZED_VAULE;
uint32_t wLength = MAX_TRANSFER_SIZE;
uint32_t readLen = 0U;
if (remainingLen < MAX_TRANSFER_SIZE)
{
wLength = remainingLen;
}
while (remainingLen)
{
memcpy((void *)s_UsbDeviceDfuDemo.dfuFirmwareBlock, (uint8_t *)(startAddress + readLen), wLength);
readLen += wLength;
/* calculate DFU CRC */
s_UsbDeviceDfuDemo.dfuCRC = USB_DeviceDfuCalculateCRC(
s_UsbDeviceDfuDemo.dfuCRC, (uint8_t *)&s_UsbDeviceDfuDemo.dfuFirmwareBlock[0], wLength);
remainingLen -= wLength;
if (remainingLen < MAX_TRANSFER_SIZE)
{
wLength = remainingLen;
}
}
memcpy((void *)&s_DfuCrcValue, (uint8_t *)(startAddress + s_UsbDeviceDfuDemo.dfuFirmwareSize - 4U), 4U);
s_UsbDeviceDfuDemo.crcCheck = 0U;
if (s_UsbDeviceDfuDemo.dfuCRC != s_DfuCrcValue)
{
usb_echo("crc check error\r\n");
}
else
{
usb_echo("crc check ok\r\n");
s_UsbDeviceDfuDemo.crcCheck = 1U;
}
s_UsbDeviceDfuDemo.dfuManifestationPhaseStatus = USB_DFU_MANIFEST_COMPLETE;
}
}
/*!
* @brief DFU download function.
*
* This function does download operation in DNLOAD state.
*
* @return None.
*/
void USB_DeviceDfuDnload(void)
{
if (USB_DFU_BLOCK_TRANSFER_IN_PROGRESS == s_UsbDeviceDfuDemo.dfuFirmwareBlockStatus)
{
usb_memmory_status_t memmoryStatus = kStatus_USB_MemmoryErrorUnknown;
uint32_t firmwareAddress = USB_DFU_APP_ADDRESS + s_UsbDeviceDfuDemo.dfuFirmwareSize;
if (0U != s_UsbDeviceDfuDemo.dfuIsTheFirstBlock)
{
/* Erase application region */
uint8_t usbOsaCurrentSr;
USB_DfuEnterCritical(&usbOsaCurrentSr);
memmoryStatus = USB_MemmoryErase((uint32_t)USB_DFU_APP_ADDRESS, USB_DFU_APP_SIZE);
USB_DfuExitCritical(usbOsaCurrentSr);
if (kStatus_USB_MemmoryErrorErase == memmoryStatus)
{
s_UsbDeviceDfuDemo.dfuStatus->bStatus = USB_DFU_STATUS_ERR_ERASE;
}
else if (kStatus_USB_MemmoryErrorEraseVerify == memmoryStatus)
{
s_UsbDeviceDfuDemo.dfuStatus->bStatus = USB_DFU_STATUS_ERR_CHECK_ERASED;
}
else if (kStatus_USB_MemmoryErrorUnknown == memmoryStatus)
{
s_UsbDeviceDfuDemo.dfuStatus->bStatus = USB_DFU_STATUS_ERR_UNKNOWN;
}
else
{
}
s_UsbDeviceDfuDemo.dfuIsTheFirstBlock = 0U;
}
if (s_UsbDeviceDfuDemo.dfuFirmwareBlockLength > 0U)
{
s_UsbDeviceDfuDemo.dfuFirmwareBlockStatus = USB_DFU_BLOCK_TRANSFER_UNDEFINED;
/* Update the firmware size */
s_UsbDeviceDfuDemo.dfuFirmwareSize += s_UsbDeviceDfuDemo.dfuFirmwareBlockLength;
/* firmware memmorying */
uint8_t usbOsaCurrentSr;
USB_DfuEnterCritical(&usbOsaCurrentSr);
memmoryStatus = USB_MemmoryProgram(firmwareAddress, (uint8_t *)&s_UsbDeviceDfuDemo.dfuFirmwareBlock[0],
s_UsbDeviceDfuDemo.dfuFirmwareBlockLength);
USB_DfuExitCritical(usbOsaCurrentSr);
if (kStatus_USB_MemmorySuccess == memmoryStatus)
{
s_UsbDeviceDfuDemo.dfuFirmwareBlockStatus = USB_DFU_BLOCK_TRANSFER_COMPLETE;
}
else if (memmoryStatus == kStatus_USB_MemmoryErrorProgram)
{
USB_DeviceDfuSetStatus(USB_DFU_STATUS_ERR_PROG);
}
else if (memmoryStatus == kStatus_USB_MemmoryErrorProgramAddress)
{
USB_DeviceDfuSetStatus(USB_DFU_STATUS_ERR_ADDRESS);
}
else if (memmoryStatus == kStatus_USB_MemmoryErrorProgramVerify)
{
USB_DeviceDfuSetStatus(USB_DFU_STATUS_ERR_VERIFY);
}
else if (memmoryStatus == kStatus_USB_MemmoryErrorUnknown)
{
USB_DeviceDfuSetStatus(USB_DFU_STATUS_ERR_UNKNOWN);
}
else
{
}
}
}
}
/*!
* @brief DFU APP_IDLE state function.
*
* This function validates the event against the current state. And sets
* the next state of the device.
*
* @return A USB error code or kStatus_USB_Success.
*/
static usb_status_t USB_DeviceStateAppIdle(usb_dfu_struct_t *dfu_dev, usb_device_dfu_event_struct_t *event)
{
usb_status_t error = kStatus_USB_Success;
if (NULL != event)
{
switch (event->name)
{
case kUSB_DeviceDfuEventDetachReq:
USB_DeviceDfuDemoInit();
#if USB_DFU_BIT_WILL_DETACH
g_detachRequest = 1U;
/* Device generates a detach-attach sequence on the bus */
USB_DeviceStop(g_UsbDeviceDfu.deviceHandle);
for (int i = 0; i < 5000; i++)
{
__NOP();
}
/*Add one delay here to make the DP pull down long enough to allow host to detect the previous
* disconnection.*/
SDK_DelayAtLeastUs(5000, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);
USB_DeviceRun(g_UsbDeviceDfu.deviceHandle);
#else
g_detachRequest = 1U;
if (event->wValue > USB_DFU_DETACH_TIMEOUT)
{
USB_DeviceDfuSetStatus(USB_DFU_STATUS_ERR_UNKNOWN);
error = kStatus_USB_InvalidParameter;
}
else
{
dfu_timer_object_t dfuTimerObject;
dfuTimerObject.timerCount = event->wValue;
dfuTimerObject.timerCallback = (dfu_timer_callback)USB_DeviceDfuDetachTimeoutIsr;
s_UsbDeviceDfuDemo.dfuTimerId = DFU_AddTimerQueue(&dfuTimerObject);
}
#endif
USB_DeviceDfuSetState(kState_AppDetach);
break;
case kUSB_DeviceDfuEventGetStatusReq:
USB_DeviceDfuSetState(kState_AppIdle);
break;
case kUSB_DeviceDfuEventGetStateReq:
USB_DeviceDfuSetState(kState_AppIdle);
break;
default:
USB_DeviceDfuSetState(kState_AppIdle);
break;
}
}
return error;
}
/*!
* @brief DFU APP_DETACH state function.
*
* This function validates the event against the current state. And sets
* the next state of the device.
*
* @return A USB error code or kStatus_USB_Success.
*/
static usb_status_t USB_DeviceStateAppDetach(usb_dfu_struct_t *dfu_dev, usb_device_dfu_event_struct_t *event)
{
usb_status_t error = kStatus_USB_Success;
if (NULL != event)
{
switch (event->name)
{
case kUSB_DeviceDfuEventGetStatusReq:
USB_DeviceDfuSetState(kState_AppDetach);
break;
case kUSB_DeviceDfuEventGetStateReq:
USB_DeviceDfuSetState(kState_AppDetach);
break;
case kUSB_DeviceDfuEventDetachReq:
case kUSB_DeviceDfuEventDnloadReq:
case kUSB_DeviceDfuEventAbortReq:
case kUSB_DeviceDfuEventUploadReq:
USB_DeviceDfuSetState(kState_AppIdle);
break;
case kUSB_DeviceDfuEventDetachTimeout:
default:
USB_DeviceDfuSetState(kState_AppIdle);
break;
}
}
return error;
}
/*!
* @brief DFU IDLE state function.
*
* This function validates the event against the current state. And sets
* the next state of the device.
*
* @return A USB error code or kStatus_USB_Success.
*/
static usb_status_t USB_DeviceStateDfuIdle(usb_dfu_struct_t *dfu_dev, usb_device_dfu_event_struct_t *event)
{
usb_status_t error = kStatus_USB_Success;
if (NULL != event)
{
switch (event->name)
{
case kUSB_DeviceDfuEventDnloadReq:
if ((event->wLength > 0U) && USB_DFU_BIT_CAN_DNLOAD)
{
/* update firmware block length */
s_UsbDeviceDfuDemo.dfuFirmwareBlockLength = event->wLength;
/* update firmware block status */
s_UsbDeviceDfuDemo.dfuFirmwareBlockStatus = USB_DFU_BLOCK_TRANSFER_IN_PROGRESS;
/* update firmware size */
s_UsbDeviceDfuDemo.dfuFirmwareSize = 0U;
/* update current download length */
s_UsbDeviceDfuDemo.dfuIsTheFirstBlock = 1U;
/* reset the downloading flag */
s_UsbDeviceDfuDemo.dfuIsDownloadingFinished = 0U;
/* reset manifestation phase flag */
s_UsbDeviceDfuDemo.dfuManifestationPhaseStatus = USB_DFU_MANIFEST_UNDEFINED;
/* this time (5000 ms) is used to erase all the APP code region */
/* and memmory the first firmware block data */
s_UsbDeviceDfuDemo.dfuStatus->bwPollTimeout[0] = 2U & 0xFFU;
s_UsbDeviceDfuDemo.dfuStatus->bwPollTimeout[1] = 0x00U;
s_UsbDeviceDfuDemo.dfuStatus->bwPollTimeout[2] = 0x00U;
USB_DeviceDfuSetState(kState_DfuDnLoadSync);
}
else
{
USB_DeviceDfuSetState(kState_DfuError);
}
break;
case kUSB_DeviceDfuEventUploadReq:
if (0U != USB_DFU_BIT_CAN_UPLOAD)
{
USB_DeviceDfuSetState(kState_DfuUpLoadIdle);
}
else
{
USB_DeviceDfuSetState(kState_DfuError);
}
break;
case kUSB_DeviceDfuEventAbortReq:
case kUSB_DeviceDfuEventGetStatusReq:
case kUSB_DeviceDfuEventGetStateReq:
USB_DeviceDfuSetState(kState_DfuIdle);
break;
case kUSB_DeviceDfuEventDetachReq:
USB_DeviceDfuSetState(kState_DfuIdle);
break;
default:
USB_DeviceDfuSetState(kState_DfuError);
break;
}
}
return error;
}
/*!
* @brief DFU DNLOAD_SYNC state function.
*
* This function validates the event against the current state. And sets
* the next state of the device.
*
* @return A USB error code or kStatus_USB_Success.
*/
static usb_status_t USB_DeviceStateDfuDnLoadSync(usb_dfu_struct_t *dfu_dev, usb_device_dfu_event_struct_t *event)
{
usb_status_t error = kStatus_USB_Success;
dfu_timer_object_t dfuTimerObject;
if (NULL != event)
{
switch (event->name)
{
case kUSB_DeviceDfuEventGetStatusReq:
if (USB_DFU_BLOCK_TRANSFER_IN_PROGRESS == s_UsbDeviceDfuDemo.dfuFirmwareBlockStatus)
{
dfuTimerObject.timerCount = (uint32_t)(
(uint32_t)(0xFFFFFFU & ((uint32_t)s_UsbDeviceDfuDemo.dfuStatus->bwPollTimeout[2] << 16U)) +
(uint32_t)(0xFFFFU & ((uint32_t)s_UsbDeviceDfuDemo.dfuStatus->bwPollTimeout[1] << 8U)) +
(uint32_t)(0xFFU & (uint32_t)s_UsbDeviceDfuDemo.dfuStatus->bwPollTimeout[0]));
dfuTimerObject.timerCount = (dfuTimerObject.timerCount >> 1);
dfuTimerObject.timerCallback = (dfu_timer_callback)USB_DeviceDfuPollTimeoutIsr;
s_UsbDeviceDfuDemo.dfuTimerId = DFU_AddTimerQueue(&dfuTimerObject);
USB_DeviceDfuSetState(kState_DfuDnBusy);
}
else if (USB_DFU_BLOCK_TRANSFER_COMPLETE == s_UsbDeviceDfuDemo.dfuFirmwareBlockStatus)
{
USB_DeviceDfuSetState(kState_DfuDnLoadIdle);
}
break;
case kUSB_DeviceDfuEventGetStateReq:
USB_DeviceDfuSetState(kState_DfuDnLoadSync);
break;
case kUSB_DeviceDfuEventDnloadReq:
case kUSB_DeviceDfuEventUploadReq:
case kUSB_DeviceDfuEventAbortReq:
case kUSB_DeviceDfuEventDetachReq:
USB_DeviceDfuSetState(kState_DfuError);
break;
default:
USB_DeviceDfuSetState(kState_DfuError);
break;
}
}
return error;
}
/*!
* @brief DFU DNLOAD_BUSY state function.
*
* This function validates the event against the current state. And sets
* the next state of the device.
*
* @return A USB error code or kStatus_USB_Success.
*/
static usb_status_t USB_DeviceStateDfuDnBusy(usb_dfu_struct_t *dfu_dev, usb_device_dfu_event_struct_t *event)
{
usb_status_t error = kStatus_USB_Success;
if (NULL != event)
{
switch (event->name)
{
case kUSB_DeviceDfuEventGetStatusReq:
case kUSB_DeviceDfuEventGetStateReq:
case kUSB_DeviceDfuEventDnloadReq:
case kUSB_DeviceDfuEventUploadReq:
case kUSB_DeviceDfuEventAbortReq:
case kUSB_DeviceDfuEventDetachReq:
USB_DeviceDfuSetState(kState_DfuError);
break;
case kUSB_DeviceDfuEventPollTimeout:
USB_DeviceDfuSetState(kState_DfuDnLoadSync);
break;
default:
USB_DeviceDfuSetState(kState_DfuError);
break;
}
}
return error;
}
/*!
* @brief DFU DNLOAD_IDLE state function.
*
* This function validates the event against the current state. And sets
* the next state of the device.
*
* @return A USB error code or kStatus_USB_Success.
*/
static usb_status_t USB_DeviceStateDfuDnLoadIdle(usb_dfu_struct_t *dfu_dev, usb_device_dfu_event_struct_t *event)
{
usb_status_t error = kStatus_USB_Success;
uint32_t status;
if (NULL != event)
{
switch (event->name)
{
case kUSB_DeviceDfuEventGetStatusReq:
case kUSB_DeviceDfuEventGetStateReq:
USB_DeviceDfuSetState(kState_DfuDnLoadIdle);
break;
case kUSB_DeviceDfuEventDnloadReq:
if (event->wLength > 0U)
{
/* update firmware block length */
s_UsbDeviceDfuDemo.dfuFirmwareBlockLength = event->wLength;
/* update firmware block status */
s_UsbDeviceDfuDemo.dfuFirmwareBlockStatus = USB_DFU_BLOCK_TRANSFER_IN_PROGRESS;
/* update timeout value */
s_UsbDeviceDfuDemo.dfuStatus->bwPollTimeout[0] = 0x2U;
s_UsbDeviceDfuDemo.dfuStatus->bwPollTimeout[1] = 0U;
s_UsbDeviceDfuDemo.dfuStatus->bwPollTimeout[2] = 0U;
USB_DeviceDfuSetState(kState_DfuDnLoadSync);
}
else
{
status = USB_DeviceDfuGetStatus();
if (USB_DFU_STATUS_ERR_NOT_DONE != status)
{
s_UsbDeviceDfuDemo.dfuFirmwareBlockStatus = USB_DFU_BLOCK_TRANSFER_UNDEFINED;
s_UsbDeviceDfuDemo.dfuManifestationPhaseStatus = USB_DFU_MANIFEST_IN_PROGRESS;
USB_DeviceDfuSetState(kState_DfuManifestSync);
s_UsbDeviceDfuDemo.dfuIsDownloadingFinished = 1U;
}
else
{
USB_DeviceDfuSetState(kState_DfuError);
}
}
break;
case kUSB_DeviceDfuEventAbortReq:
USB_DeviceDfuSetState(kState_DfuIdle);
break;
case kUSB_DeviceDfuEventUploadReq:
case kUSB_DeviceDfuEventDetachReq:
USB_DeviceDfuSetState(kState_DfuError);
break;
default:
USB_DeviceDfuSetState(kState_DfuError);
break;
}
}
return error;
}
/*!
* @brief DFU MANIFEST_SYNC state function.
*
* This function validates the event against the current state. And sets
* the next state of the device.
*
* @return A USB error code or kStatus_USB_Success.
*/
static usb_status_t USB_DeviceStateDfuManifestSync(usb_dfu_struct_t *dfu_dev, usb_device_dfu_event_struct_t *event)
{
usb_status_t error = kStatus_USB_Success;
dfu_timer_object_t dfuTimerObject;
if (NULL != event)
{
switch (event->name)
{
case kUSB_DeviceDfuEventGetStatusReq:
if (USB_DFU_MANIFEST_IN_PROGRESS == s_UsbDeviceDfuDemo.dfuManifestationPhaseStatus)
{
USB_DeviceDfuSetState(kState_DfuManifest);
dfuTimerObject.timerCount = (uint32_t)(
(uint32_t)(0xFFFFFFU & ((uint32_t)s_UsbDeviceDfuDemo.dfuStatus->bwPollTimeout[2] << 16U)) +
(uint32_t)(0xFFFFU & ((uint32_t)s_UsbDeviceDfuDemo.dfuStatus->bwPollTimeout[1] << 8U)) +
(uint32_t)(0xFFU & (uint32_t)s_UsbDeviceDfuDemo.dfuStatus->bwPollTimeout[0]));
dfuTimerObject.timerCount = (dfuTimerObject.timerCount >> 1);
dfuTimerObject.timerCallback = (dfu_timer_callback)USB_DeviceDfuPollTimeoutIsr;
s_UsbDeviceDfuDemo.dfuTimerId = DFU_AddTimerQueue(&dfuTimerObject);
}
else if (USB_DFU_MANIFEST_COMPLETE == s_UsbDeviceDfuDemo.dfuManifestationPhaseStatus)
{
#if USB_DFU_BIT_MANIFESTATION_TOLERANT
USB_DeviceDfuSetState(kState_DfuIdle);
#endif
}
else
{
}
break;
case kUSB_DeviceDfuEventGetStateReq:
USB_DeviceDfuSetState(kState_DfuManifestSync);
break;
case kUSB_DeviceDfuEventDnloadReq:
case kUSB_DeviceDfuEventAbortReq:
case kUSB_DeviceDfuEventUploadReq:
case kUSB_DeviceDfuEventDetachReq:
USB_DeviceDfuSetState(kState_DfuError);
break;
default:
USB_DeviceDfuSetState(kState_DfuError);
break;
}
}
return error;
}
/*!
* @brief DFU MANIFEST state function.
*
* This function validates the event against the current state. And sets
* the next state of the device.
*
* @return A USB error code or kStatus_USB_Success.
*/
static usb_status_t USB_DeviceStateDfuManifest(usb_dfu_struct_t *dfu_dev, usb_device_dfu_event_struct_t *event)
{
usb_status_t error = kStatus_USB_Success;
if (NULL != event)
{
switch (event->name)
{
case kUSB_DeviceDfuEventGetStatusReq:
case kUSB_DeviceDfuEventGetStateReq:
case kUSB_DeviceDfuEventDnloadReq:
case kUSB_DeviceDfuEventAbortReq:
case kUSB_DeviceDfuEventUploadReq:
case kUSB_DeviceDfuEventDetachReq:
USB_DeviceDfuSetState(kState_DfuError);
break;
case kUSB_DeviceDfuEventPollTimeout:
#if USB_DFU_BIT_MANIFESTATION_TOLERANT
USB_DeviceDfuSetState(kState_DfuManifestSync);
#else
USB_DeviceDfuSetState(kState_DfuManifestWaitReset);
s_UsbDeviceDfuDemo.dfuReboot = 1U;
#endif
break;
default:
USB_DeviceDfuSetState(kState_DfuError);
break;
}
}
return error;
}
/*!
* @brief DFU MANIFEST_WAIT_RESET state function.
*
* This function validates the event against the current state. And sets
* the next state of the device.
*
* @return A USB error code or kStatus_USB_Success.
*/
static usb_status_t USB_DeviceStateDfuManifestWaitReset(usb_dfu_struct_t *dfu_dev, usb_device_dfu_event_struct_t *event)
{
usb_status_t error = kStatus_USB_Success;
if (NULL != event)
{
switch (event->name)
{
case kUSB_DeviceDfuEventGetStatusReq:
s_UsbDeviceDfuDemo.dfuReboot = 1U;
USB_DeviceDfuSetState(kState_DfuManifestWaitReset);
break;
case kUSB_DeviceDfuEventGetStateReq:
case kUSB_DeviceDfuEventDnloadReq:
case kUSB_DeviceDfuEventAbortReq:
case kUSB_DeviceDfuEventUploadReq:
case kUSB_DeviceDfuEventDetachReq:
case kUSB_DeviceDfuEventPollTimeout:
USB_DeviceDfuSetState(kState_DfuManifestWaitReset);
break;
default:
USB_DeviceDfuSetState(kState_DfuManifestWaitReset);
break;
}
}
return error;
}
/*!
* @brief DFU UPLOAD_IDLE state function.
*
* This function validates the event against the current state. And sets
* the next state of the device.
*
* @return A USB error code or kStatus_USB_Success.
*/
static usb_status_t USB_DeviceStateDfuUpLoadIdle(usb_dfu_struct_t *dfu_dev, usb_device_dfu_event_struct_t *event)
{
usb_status_t error = kStatus_USB_Success;
if (NULL != event)
{
switch (event->name)
{
case kUSB_DeviceDfuEventGetStatusReq:
case kUSB_DeviceDfuEventGetStateReq:
USB_DeviceDfuSetState(kState_DfuUpLoadIdle);
break;
case kUSB_DeviceDfuEventAbortReq:
USB_DeviceDfuSetState(kState_DfuIdle);
break;
case kUSB_DeviceDfuEventUploadReq:
if (0U != s_isShortFrame)
{
USB_DeviceDfuSetState(kState_DfuIdle);
}
else if (event->wLength > 0U)
{
USB_DeviceDfuSetState(kState_DfuUpLoadIdle);
}
break;
case kUSB_DeviceDfuEventDnloadReq:
case kUSB_DeviceDfuEventDetachReq:
case kUSB_DeviceDfuEventPollTimeout:
USB_DeviceDfuSetState(kState_DfuError);
break;
default:
USB_DeviceDfuSetState(kState_DfuError);
break;
}
}
return error;
}
/*!
* @brief DFU ERROR state function.
*
* This function validates the event against the current state. And sets
* the next state of the device.
*
* @return A USB error code or kStatus_USB_Success.
*/
static usb_status_t USB_DeviceStateDfuError(usb_dfu_struct_t *dfu_dev, usb_device_dfu_event_struct_t *event)
{
usb_status_t error = kStatus_USB_Success;
if (NULL != event)
{
switch (event->name)
{
case kUSB_DeviceDfuEventGetStatusReq:
case kUSB_DeviceDfuEventGetStateReq:
USB_DeviceDfuSetState(kState_DfuError);
break;
case kUSB_DeviceDfuEventClearStatusReq:
USB_DeviceDfuSetState(kState_DfuIdle);
break;
case kUSB_DeviceDfuEventAbortReq:
case kUSB_DeviceDfuEventUploadReq:
case kUSB_DeviceDfuEventDnloadReq:
case kUSB_DeviceDfuEventDetachReq:
case kUSB_DeviceDfuEventPollTimeout:
break;
default:
USB_DeviceDfuSetState(kState_DfuError);
break;
}
}
return error;
}
/*!
* @brief DFU state update function.
*
* This function updates the DFU state according to the event.
*
* @return A USB error code or kStatus_USB_Success.
*/
usb_status_t USB_DeviceStateUpdate(void)
{
usb_status_t error = kStatus_USB_Success;
usb_device_dfu_event_struct_t event;
usb_dfu_state_struct_t state;
usb_dfu_struct_t *dfu_dev = &s_UsbDeviceDfuDemo;
state = USB_DeviceDfuGetState();
error = USB_DeviceDfuQueueGet(&s_DfuEventQueue, &event);
if (kStatus_USB_Success == error)
{
if (kState_DfuError >= state)
{
s_dfuStateFunc[state](dfu_dev, &event);
}
}
return error;
}
/*!
* @brief DFU task function.
*
* This function gets the current state of the device, do downloading
* or manifestation if it needs.
*
* @return None.
*/
void USB_DeviceDfuTask(void)
{
static usb_dfu_state_struct_t state;
USB_DeviceStateUpdate();
state = USB_DeviceDfuGetState();
if (kState_DfuDnLoadSync == state)
{
USB_DeviceDfuDnload();
}
else if (kState_DfuManifest == state)
{
USB_DeviceDfuManifest();
}
if (s_UsbDeviceDfuDemo.crcCheck)
{
if (1U == s_UsbDeviceDfuDemo.dfuReboot)
{
s_UsbDeviceDfuDemo.dfuReboot = 0U;
USB_DeviceDfuSwitchMode();
}
}
}