/** ****************************************************************************** * @file usb_prop.c * @author MCD Application Team * @version V4.0.0 * @date 21-January-2013 * @brief All processings related to DFU demo ****************************************************************************** * @attention * *

© COPYRIGHT 2013 STMicroelectronics

* * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); * You may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.st.com/software_license_agreement_liberty_v2 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ #include "usb_lib.h" #include "hw_config.h" #include "usb_conf.h" #include "usb_prop.h" #include "usb_desc.h" #include "usb_pwr.h" #include "dfu_mal.h" /* Private typedef -----------------------------------------------------------*/ /* Private define ------------------------------------------------------------*/ /* Private macro -------------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/ uint32_t wBlockNum = 0, wlength = 0; uint32_t Manifest_State = Manifest_complete; uint32_t Pointer = ApplicationAddress; /* Base Address to Erase, Program or Read */ DEVICE Device_Table = { EP_NUM, 1 }; DEVICE_PROP Device_Property = { DFU_init, DFU_Reset, DFU_Status_In, DFU_Status_Out, DFU_Data_Setup, DFU_NoData_Setup, DFU_Get_Interface_Setting, DFU_GetDeviceDescriptor, DFU_GetConfigDescriptor, DFU_GetStringDescriptor, 0, /*DFU_EP0Buffer*/ bMaxPacketSize0 /*Max Packet size*/ }; USER_STANDARD_REQUESTS User_Standard_Requests = { DFU_GetConfiguration, DFU_SetConfiguration, DFU_GetInterface, DFU_SetInterface, DFU_GetStatus, DFU_ClearFeature, DFU_SetEndPointFeature, DFU_SetDeviceFeature, DFU_SetDeviceAddress }; ONE_DESCRIPTOR Device_Descriptor = { (uint8_t*)DFU_DeviceDescriptor, DFU_SIZ_DEVICE_DESC }; ONE_DESCRIPTOR Config_Descriptor = { (uint8_t*)DFU_ConfigDescriptor, DFU_SIZ_CONFIG_DESC }; #ifdef USE_STM3210E_EVAL ONE_DESCRIPTOR DFU_String_Descriptor[7] = #elif defined(USE_STM3210B_EVAL) ONE_DESCRIPTOR DFU_String_Descriptor[6] = #elif defined(USE_STM32L152_EVAL) || defined(USE_STM32L152D_EVAL) ||defined(USE_STM32373C_EVAL) ||defined(USE_STM32303C_EVAL) ONE_DESCRIPTOR DFU_String_Descriptor[5] = #endif /* USE_STM3210E_EVAL */ { { (uint8_t*)DFU_StringLangId, DFU_SIZ_STRING_LANGID }, { (uint8_t*)DFU_StringVendor, DFU_SIZ_STRING_VENDOR }, { (uint8_t*)DFU_StringProduct, DFU_SIZ_STRING_PRODUCT }, { (uint8_t*)DFU_StringSerial, DFU_SIZ_STRING_SERIAL }, { (uint8_t*)DFU_StringInterface0, DFU_SIZ_STRING_INTERFACE0 } #ifdef USE_STM3210B_EVAL , { (uint8_t*)DFU_StringInterface1, DFU_SIZ_STRING_INTERFACE1 } #endif /* USE_STM3210B_EVAL */ #ifdef USE_STM3210E_EVAL , { (uint8_t*)DFU_StringInterface1, DFU_SIZ_STRING_INTERFACE1 }, { (uint8_t*)DFU_StringInterface2_1, DFU_SIZ_STRING_INTERFACE2 } #endif /* USE_STM3210E_EVAL */ }; /* Extern variables ----------------------------------------------------------*/ extern uint8_t DeviceState ; extern uint8_t DeviceStatus[6]; /* Private function prototypes -----------------------------------------------*/ /* Private functions ---------------------------------------------------------*/ /******************************************************************************* * Function Name : DFU_init. * Description : DFU init routine. * Input : None. * Output : None. * Return : None. *******************************************************************************/ void DFU_init(void) { DEVICE_INFO *pInfo = &Device_Info; /* Update the serial number string descriptor with the data from the unique ID*/ Get_SerialNum(); pInfo->Current_Configuration = 0; /* Connect the device */ PowerOn(); /* Perform basic device initialization operations */ USB_SIL_Init(); /* Enable USB interrupts */ USB_Interrupts_Config(); bDeviceState = UNCONNECTED; } /******************************************************************************* * Function Name : DFU_Reset. * Description : DFU reset routine * Input : None. * Output : None. * Return : None. *******************************************************************************/ void DFU_Reset(void) { /* Set DFU_DEVICE as not configured */ Device_Info.Current_Configuration = 0; /* Current Feature initialization */ pInformation->Current_Feature = DFU_ConfigDescriptor[7]; _SetBTABLE(BTABLE_ADDRESS); /* Initialize Endpoint 0 */ _SetEPType(ENDP0, EP_CONTROL); _SetEPTxStatus(ENDP0, EP_TX_NAK); _SetEPRxAddr(ENDP0, ENDP0_RXADDR); SetEPRxCount(ENDP0, Device_Property.MaxPacketSize); _SetEPTxAddr(ENDP0, ENDP0_TXADDR); SetEPTxCount(ENDP0, Device_Property.MaxPacketSize); Clear_Status_Out(ENDP0); SetEPRxValid(ENDP0); /* Set this device to response on default address */ SetDeviceAddress(0); /* Set the new control state of the device to Attached */ bDeviceState = ATTACHED; } /******************************************************************************* * Function Name : DFU_SetConfiguration. * Description : Update the device state to configured. * Input : None. * Output : None. * Return : None. *******************************************************************************/ void DFU_SetConfiguration(void) { DEVICE_INFO *pInfo = &Device_Info; if (pInfo->Current_Configuration != 0) { /* Device configured */ bDeviceState = CONFIGURED; } } /******************************************************************************* * Function Name : DFU_SetConfiguration. * Description : Update the device state to addressed. * Input : None. * Output : None. * Return : None. *******************************************************************************/ void DFU_SetDeviceAddress (void) { bDeviceState = ADDRESSED; } /******************************************************************************* * Function Name : DFU_Status_In. * Description : DFU status IN routine. * Input : None. * Output : None. * Return : None. *******************************************************************************/ void DFU_Status_In(void) {} /******************************************************************************* * Function Name : DFU_Status_Out. * Description : DFU status OUT routine. * Input : None. * Output : None. * Return : None. *******************************************************************************/ void DFU_Status_Out (void) { DEVICE_INFO *pInfo = &Device_Info; uint32_t Addr; if (pInfo->USBbRequest == DFU_GETSTATUS) { if (DeviceState == STATE_dfuDNBUSY) { if (wBlockNum == 0) /* Decode the Special Command*/ { if ((MAL_Buffer[0] == CMD_GETCOMMANDS) && (wlength == 1)) {} else if (( MAL_Buffer[0] == CMD_SETADDRESSPOINTER ) && (wlength == 5)) { Pointer = MAL_Buffer[1]; Pointer += MAL_Buffer[2] << 8; Pointer += MAL_Buffer[3] << 16; Pointer += MAL_Buffer[4] << 24; } else if (( MAL_Buffer[0] == CMD_ERASE ) && (wlength == 5)) { Pointer = MAL_Buffer[1]; Pointer += MAL_Buffer[2] << 8; Pointer += MAL_Buffer[3] << 16; Pointer += MAL_Buffer[4] << 24; MAL_Erase(Pointer); } } else if (wBlockNum > 1) // Download Command { Addr = ((wBlockNum - 2) * wTransferSize) + Pointer; MAL_Write(Addr, wlength); } wlength = 0; wBlockNum = 0; DeviceState = STATE_dfuDNLOAD_SYNC; DeviceStatus[4] = DeviceState; DeviceStatus[1] = 0; DeviceStatus[2] = 0; DeviceStatus[3] = 0; return; } else if (DeviceState == STATE_dfuMANIFEST)/* Manifestation in progress*/ { DFU_write_crc(); return; } } return; } /******************************************************************************* * Function Name : DFU_Data_Setup. * Description : Handle the data class specific requests. * Input : RequestNb. * Output : None. * Return : USB_SUCCESS or USB_UNSUPPORT. *******************************************************************************/ RESULT DFU_Data_Setup(uint8_t RequestNo) { uint8_t *(*CopyRoutine)(uint16_t); CopyRoutine = NULL; if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) { if (RequestNo == DFU_UPLOAD && (DeviceState == STATE_dfuIDLE || DeviceState == STATE_dfuUPLOAD_IDLE )) { CopyRoutine = UPLOAD; } else if (RequestNo == DFU_DNLOAD && (DeviceState == STATE_dfuIDLE || DeviceState == STATE_dfuDNLOAD_IDLE)) { DeviceState = STATE_dfuDNLOAD_SYNC; CopyRoutine = DNLOAD; } else if (RequestNo == DFU_GETSTATE) { CopyRoutine = GETSTATE; } else if (RequestNo == DFU_GETSTATUS) { CopyRoutine = GETSTATUS; } else { return USB_UNSUPPORT; } } else { return USB_UNSUPPORT; } if (CopyRoutine == NULL) { return USB_UNSUPPORT; } pInformation->Ctrl_Info.CopyData = CopyRoutine; pInformation->Ctrl_Info.Usb_wOffset = 0; (*CopyRoutine)(0); return USB_SUCCESS; } /******************************************************************************* * Function Name : DFU_NoData_Setup. * Description : Handle the No data class specific requests. * Input : Request Nb. * Output : None. * Return : USB_SUCCESS or USB_UNSUPPORT. *******************************************************************************/ RESULT DFU_NoData_Setup(uint8_t RequestNo) { if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) { /*DFU_NDLOAD*/ if (RequestNo == DFU_DNLOAD) { /* End of DNLOAD operation*/ if (DeviceState == STATE_dfuDNLOAD_IDLE || DeviceState == STATE_dfuIDLE ) { Manifest_State = Manifest_In_Progress; DeviceState = STATE_dfuMANIFEST_SYNC; DeviceStatus[1] = 0; DeviceStatus[2] = 0; DeviceStatus[3] = 0; DeviceStatus[4] = DeviceState; return USB_SUCCESS; } } /*DFU_UPLOAD*/ else if (RequestNo == DFU_UPLOAD) { DeviceState = STATE_dfuIDLE; DeviceStatus[1] = 0; DeviceStatus[2] = 0; DeviceStatus[3] = 0; DeviceStatus[4] = DeviceState; return USB_SUCCESS; } /*DFU_CLRSTATUS*/ else if (RequestNo == DFU_CLRSTATUS) { if (DeviceState == STATE_dfuERROR) { DeviceState = STATE_dfuIDLE; DeviceStatus[0] = STATUS_OK;/*bStatus*/ DeviceStatus[1] = 0; DeviceStatus[2] = 0; DeviceStatus[3] = 0; /*bwPollTimeout=0ms*/ DeviceStatus[4] = DeviceState;/*bState*/ DeviceStatus[5] = 0;/*iString*/ } else { /*State Error*/ DeviceState = STATE_dfuERROR; DeviceStatus[0] = STATUS_ERRUNKNOWN;/*bStatus*/ DeviceStatus[1] = 0; DeviceStatus[2] = 0; DeviceStatus[3] = 0; /*bwPollTimeout=0ms*/ DeviceStatus[4] = DeviceState;/*bState*/ DeviceStatus[5] = 0;/*iString*/ } return USB_SUCCESS; } /*DFU_ABORT*/ else if (RequestNo == DFU_ABORT) { if (DeviceState == STATE_dfuIDLE || DeviceState == STATE_dfuDNLOAD_SYNC || DeviceState == STATE_dfuDNLOAD_IDLE || DeviceState == STATE_dfuMANIFEST_SYNC || DeviceState == STATE_dfuUPLOAD_IDLE ) { DeviceState = STATE_dfuIDLE; DeviceStatus[0] = STATUS_OK; DeviceStatus[1] = 0; DeviceStatus[2] = 0; DeviceStatus[3] = 0; /*bwPollTimeout=0ms*/ DeviceStatus[4] = DeviceState; DeviceStatus[5] = 0; /*iString*/ wBlockNum = 0; wlength = 0; } return USB_SUCCESS; } } return USB_UNSUPPORT; } /* End of DFU_NoData_Setup */ /******************************************************************************* * Function Name : DFU_GetDeviceDescriptor. * Description : Gets the device descriptor. * Input : Length. * Output : None. * Return : The address of the device descriptor. *******************************************************************************/ uint8_t *DFU_GetDeviceDescriptor(uint16_t Length) { return Standard_GetDescriptorData(Length, &Device_Descriptor); } /******************************************************************************* * Function Name : DFU_GetConfigDescriptor. * Description : Gets the configuration descriptor. * Input : Length. * Output : None. * Return : The address of the configuration descriptor. *******************************************************************************/ uint8_t *DFU_GetConfigDescriptor(uint16_t Length) { return Standard_GetDescriptorData (Length, &Config_Descriptor); } /******************************************************************************* * Function Name : DFU_GetStringDescriptor. * Description : Gets the string descriptors according to the needed index. * Input : Length. * Output : None. * Return : The address of the string descriptors. *******************************************************************************/ uint8_t *DFU_GetStringDescriptor(uint16_t Length) { uint8_t wValue0 = pInformation->USBwValue0; if (wValue0 > 8) { return NULL; } else { return Standard_GetDescriptorData(Length, &DFU_String_Descriptor[wValue0]); } } /******************************************************************************* * Function Name : DFU_Get_Interface_Setting. * Description : tests the interface and the alternate setting according to the * supported one. * Input : - Interface : interface number. * - AlternateSetting : Alternate Setting number. * Output : None. * Return : USB_SUCCESS or USB_UNSUPPORT. *******************************************************************************/ RESULT DFU_Get_Interface_Setting(uint8_t Interface, uint8_t AlternateSetting) { if (AlternateSetting > 3) { return USB_UNSUPPORT; /* In this application we don't have more than 3 AlternateSettings */ } else if (Interface > 2) { return USB_UNSUPPORT; /* In this application we have only 1 interfaces */ } return USB_SUCCESS; } /******************************************************************************* * Function Name : UPLOAD * Description : Upload routine. * Input : Length. * Output : None. * Return : Pointer to data. *******************************************************************************/ uint8_t *UPLOAD(uint16_t Length) { DEVICE_INFO *pInfo = &Device_Info; uint8_t B1, B0; uint16_t offset, returned; uint8_t *Phy_Addr = NULL; uint32_t Addr = 0; B0 = pInfo->USBwValues.bw.bb0; B1 = pInfo->USBwValues.bw.bb1; wBlockNum = (uint16_t)B1; wBlockNum = wBlockNum * 0x100; wBlockNum += (uint16_t)B0; /* wBlockNum value updated*/ B0 = pInfo->USBwLengths.bw.bb0; B1 = pInfo->USBwLengths.bw.bb1; wlength = (uint16_t)B0; wlength = wlength * 0x100; wlength += (uint16_t)B1; /* wlength value updated*/ offset = pInformation->Ctrl_Info.Usb_wOffset; if (wBlockNum == 0) /* Get Command */ { if (wlength > 3) { DeviceState = STATE_dfuIDLE ; } else { DeviceState = STATE_dfuUPLOAD_IDLE; } DeviceStatus[4] = DeviceState; DeviceStatus[1] = 0; DeviceStatus[2] = 0; DeviceStatus[3] = 0; MAL_Buffer[0] = CMD_GETCOMMANDS; MAL_Buffer[1] = CMD_SETADDRESSPOINTER; MAL_Buffer[2] = CMD_ERASE; if (Length == 0) { pInformation->Ctrl_Info.Usb_wLength = 3 ; return NULL; } return(&MAL_Buffer[0]); } else if (wBlockNum > 1) { DeviceState = STATE_dfuUPLOAD_IDLE ; DeviceStatus[4] = DeviceState; DeviceStatus[1] = 0; DeviceStatus[2] = 0; DeviceStatus[3] = 0; Addr = ((wBlockNum - 2) * wTransferSize) + Pointer; /* Change is Accelerated*/ Phy_Addr = MAL_Read(Addr, wlength); returned = wlength - offset; if (Length == 0) { pInformation->Ctrl_Info.Usb_wLength = returned ; return NULL; } return(Phy_Addr + offset); } else /* unsupported wBlockNum */ { DeviceState = STATUS_ERRSTALLEDPKT; DeviceStatus[4] = DeviceState; DeviceStatus[1] = 0; DeviceStatus[2] = 0; DeviceStatus[3] = 0; return NULL; } } /******************************************************************************* * Function Name : DNLOAD * Description : Download routine. * Input : Length. * Output : None. * Return : Pointer to data. *******************************************************************************/ uint8_t *DNLOAD (uint16_t Length) { DEVICE_INFO *pInfo = &Device_Info; uint8_t B1, B0; uint16_t offset, returned; B0 = pInfo->USBwValues.bw.bb0; B1 = pInfo->USBwValues.bw.bb1; wBlockNum = (uint16_t)B1; wBlockNum = wBlockNum * 0x100; wBlockNum += (uint16_t)B0; B0 = pInfo->USBwLengths.bw.bb0; B1 = pInfo->USBwLengths.bw.bb1; wlength = (uint16_t)B0; wlength = wlength * 0x100; wlength += (uint16_t)B1; offset = pInfo->Ctrl_Info.Usb_wOffset; DeviceState = STATE_dfuDNLOAD_SYNC; DeviceStatus[4] = DeviceState; returned = wlength - offset; if (Length == 0) { pInformation->Ctrl_Info.Usb_wLength = returned ; return NULL; } return((uint8_t*)MAL_Buffer + offset); } /******************************************************************************* * Function Name : GETSTATE. * Description : Get State request routine. * Input : Length. * Output : None. * Return : Pointer to data. *******************************************************************************/ uint8_t *GETSTATE(uint16_t Length) { if (Length == 0) { pInformation->Ctrl_Info.Usb_wLength = 1 ; return NULL; } else return(&DeviceState); } /******************************************************************************* * Function Name : GETSTATUS. * Description : Get Status request routine. * Input : Length. * Output : None. * Return : Pointer to data. *******************************************************************************/ uint8_t *GETSTATUS(uint16_t Length) { switch (DeviceState) { case STATE_dfuDNLOAD_SYNC: if (wlength != 0) { DeviceState = STATE_dfuDNBUSY; DeviceStatus[4] = DeviceState; if ((wBlockNum == 0) && (MAL_Buffer[0] == CMD_ERASE)) { MAL_GetStatus(Pointer, 0, DeviceStatus); } else { MAL_GetStatus(Pointer, 1, DeviceStatus); } } else /* (wlength==0)*/ { DeviceState = STATE_dfuDNLOAD_IDLE; DeviceStatus[4] = DeviceState; DeviceStatus[1] = 0; DeviceStatus[2] = 0; DeviceStatus[3] = 0; } break; case STATE_dfuMANIFEST_SYNC : if (Manifest_State == Manifest_In_Progress) { DeviceState = STATE_dfuMANIFEST; DeviceStatus[4] = DeviceState; DeviceStatus[1] = 1; /*bwPollTimeout = 1ms*/ DeviceStatus[2] = 0; DeviceStatus[3] = 0; //break; } else if (Manifest_State == Manifest_complete && Config_Descriptor.Descriptor[20] & 0x04) { DeviceState = STATE_dfuIDLE; DeviceStatus[4] = DeviceState; DeviceStatus[1] = 0; DeviceStatus[2] = 0; DeviceStatus[3] = 0; //break; } break; default : break; } if (Length == 0) { pInformation->Ctrl_Info.Usb_wLength = 6 ; return NULL; } else return(&(DeviceStatus[0])); } /******************************************************************************* * Function Name : DFU_write_crc. * Description : DFU Write CRC routine. * Input : None. * Output : None. * Return : None. *******************************************************************************/ void DFU_write_crc(void) { Manifest_State = Manifest_complete; if (Config_Descriptor.Descriptor[20] & 0x04) { DeviceState = STATE_dfuMANIFEST_SYNC; DeviceStatus[4] = DeviceState; DeviceStatus[1] = 0; DeviceStatus[2] = 0; DeviceStatus[3] = 0; return; } else { DeviceState = STATE_dfuMANIFEST_WAIT_RESET; DeviceStatus[4] = DeviceState; DeviceStatus[1] = 0; DeviceStatus[2] = 0; DeviceStatus[3] = 0; Reset_Device(); return; } } /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/