samples/subsys/usb/dfu/src/usb_dfu.c
/**
 * @brief Handler called for DFU Class requests not handled by the USB stack.
 *
 * @param pSetup    Information about the request to execute.
 * @param len       Size of the buffer.
 * @param data      Buffer containing the request result.
 *
 * @return  0 on success, negative errno code on fail.
 */
@brief Handler called for DFU Class requests not handled by the USB stack.
@param pSetup    Information about the request to execute.
@param len       Size of the buffer.
@param data      Buffer containing the request result.

@return  0 on success, negative errno code on fail.
@brief Handler called for DFU Class requests not handled by the USB stack . @param pSetup Information about the request to execute . @param len Size of the buffer . @param data Buffer containing the request result . @return 0 on success negative errno code on fail .
static int dfu_class_handle_req(struct usb_setup_packet *pSetup,
		s32_t *data_len, u8_t **data)
{
	int ret;
	u32_t len, bytes_left;
	switch (pSetup->bRequest) {
	case DFU_GETSTATUS:
		SYS_LOG_DBG("DFU_GETSTATUS: status %d, state %d",
		    dfu_data.status, dfu_data.state);
		if (dfu_data.state == dfuMANIFEST_SYNC)
			dfu_data.state = dfuIDLE;
		(*data)[0] = dfu_data.status;
		(*data)[1] = 0;
		(*data)[2] = 1;
		(*data)[3] = 0;
		(*data)[4] = dfu_data.state;
		(*data)[5] = 0;
		*data_len = 6;
		break;
	case DFU_GETSTATE:
		SYS_LOG_DBG("DFU_GETSTATE");
		(*data)[0] = dfu_data.state;
		*data_len = 1;
		break;
	case DFU_ABORT:
		SYS_LOG_DBG("DFU_ABORT");
		if (dfu_check_app_state())
			return -EINVAL;
		dfu_reset_counters();
		dfu_data.state = dfuIDLE;
		dfu_data.status = statusOK;
		break;
	case DFU_CLRSTATUS:
		SYS_LOG_DBG("DFU_CLRSTATUS");
		if (dfu_check_app_state())
			return -EINVAL;
		dfu_data.state = dfuIDLE;
		dfu_data.status = statusOK;
		break;
	case DFU_DNLOAD:
		SYS_LOG_DBG("DFU_DNLOAD block %d, len %d, state %d",
		    pSetup->wValue, pSetup->wLength, dfu_data.state);
		if (dfu_check_app_state())
			return -EINVAL;
		switch (dfu_data.state) {
		case dfuIDLE:
			dfu_reset_counters();
			SYS_LOG_DBG("DFU_DNLOAD start");
		case dfuDNLOAD_IDLE:
			if (pSetup->wLength != 0) {
				dfu_data.state = dfuDNLOAD_IDLE;
				if (!(dfu_data.bytes_rcvd %
				      dfu_data.flash_page_size)) {
					ret = flash_erase(dfu_data.flash_dev,
					    DFU_FLASH_ADDR +
						    dfu_data.bytes_rcvd,
					    dfu_data.flash_page_size);
					SYS_LOG_DBG("Flash erase");
					if (ret) {
						dfu_data.state = dfuERROR;
						dfu_data.status = errERASE;
						SYS_LOG_DBG("DFU flash erase error, "
						    "ret %d", ret);
					}
				}
				len = (pSetup->wLength + 3) & (~3);
				ret = flash_write(dfu_data.flash_dev,
				    DFU_FLASH_ADDR +
					    dfu_data.bytes_rcvd,
				    *data, len);
				if (ret) {
					dfu_data.state = dfuERROR;
					dfu_data.status = errWRITE;
					SYS_LOG_DBG("DFU flash write error, ret %d",
					    ret);
				} else
					dfu_data.bytes_rcvd += pSetup->wLength;
			} else {
				dfu_data.state = dfuMANIFEST_SYNC;
				dfu_reset_counters();
			}
			break;
		default:
			SYS_LOG_DBG("DFU_DNLOAD wrong state %d", dfu_data.state);
			dfu_data.state = dfuERROR;
			dfu_data.status = errUNKNOWN;
			dfu_reset_counters();
			return -EINVAL;
		}
		break;
	case DFU_UPLOAD:
		SYS_LOG_DBG("DFU_UPLOAD block %d, len %d, state %d",
		    pSetup->wValue, pSetup->wLength, dfu_data.state);
		if (dfu_check_app_state())
			return -EINVAL;
		switch (dfu_data.state) {
		case dfuIDLE:
			dfu_reset_counters();
			SYS_LOG_DBG("DFU_UPLOAD start");
		case dfuUPLOAD_IDLE:
			if (!pSetup->wLength ||
			    dfu_data.block_nr != pSetup->wValue) {
				SYS_LOG_DBG("DFU_UPLOAD block %d, expected %d, "
				    "len %d", pSetup->wValue,
				    dfu_data.block_nr, pSetup->wLength);
				dfu_data.state = dfuERROR;
				dfu_data.status = errUNKNOWN;
				break;
			}
			bytes_left = dfu_data.flash_upload_size -
			    dfu_data.bytes_sent;
			if (bytes_left < pSetup->wLength)
				len = bytes_left;
			else
				len = pSetup->wLength;
			if (len) {
				ret = flash_read(dfu_data.flash_dev,
				    DFU_FLASH_ADDR +
					    dfu_data.bytes_sent,
				    dfu_data.buffer, len);
				if (ret) {
					dfu_data.state = dfuERROR;
					dfu_data.status = errFILE;
					break;
				}
			}
			*data_len = len;
			*data = dfu_data.buffer;
			dfu_data.bytes_sent += len;
			dfu_data.block_nr++;
			if (dfu_data.bytes_sent == dfu_data.flash_upload_size &&
			    len < pSetup->wLength) {
				*data_len = 0;
				dfu_data.state = dfuIDLE;
			} else
				dfu_data.state = dfuUPLOAD_IDLE;
			break;
		default:
			SYS_LOG_DBG("DFU_UPLOAD wrong state %d", dfu_data.state);
			dfu_data.state = dfuERROR;
			dfu_data.status = errUNKNOWN;
			dfu_reset_counters();
			return -EINVAL;
		}
		break;
	case DFU_DETACH:
		SYS_LOG_DBG("DFU_DETACH timeout %d, state %d",
			pSetup->wValue, dfu_data.state);
		if (dfu_data.state != appIDLE) {
			dfu_data.state = appIDLE;
			return -EINVAL;
		}
		dfu_data.state = appDETACH;
		dfu_config.usb_device_description = dfu_mode_usb_description;
		if (usb_set_config(&dfu_config) != 0) {
			SYS_LOG_DBG("usb_set_config failed in DFU_DETACH");
			return -EIO;
		}
		break;
	default:
		SYS_LOG_DBG("DFU UNKNOWN STATE: %d", pSetup->bRequest);
		return -EINVAL;
	}
	return 0;
}
static int dfu_class_handle_req ( struct usb_setup_packet * pSetup , s32_t * data_len , u8_t * * data ) { int ret ; u32_t len , bytes_left ; switch ( pSetup -> bRequest ) { case DFU_GETSTATUS : SYS_LOG_DBG ( " " , dfu_data . status , dfu_data . state ) ; if ( dfu_data . state == dfuMANIFEST_SYNC ) dfu_data . state = dfuIDLE ; ( * data ) [ 0 ] = dfu_data . status ; ( * data ) [ 1 ] = 0 ; ( * data ) [ 2 ] = 1 ; ( * data ) [ 3 ] = 0 ; ( * data ) [ 4 ] = dfu_data . state ; ( * data ) [ 5 ] = 0 ; * data_len = 6 ; break ; case DFU_GETSTATE : SYS_LOG_DBG ( " " ) ; ( * data ) [ 0 ] = dfu_data . state ; * data_len = 1 ; break ; case DFU_ABORT : SYS_LOG_DBG ( " " ) ; if ( dfu_check_app_state ( ) ) return - EINVAL ; dfu_reset_counters ( ) ; dfu_data . state = dfuIDLE ; dfu_data . status = statusOK ; break ; case DFU_CLRSTATUS : SYS_LOG_DBG ( " " ) ; if ( dfu_check_app_state ( ) ) return - EINVAL ; dfu_data . state = dfuIDLE ; dfu_data . status = statusOK ; break ; case DFU_DNLOAD : SYS_LOG_DBG ( " " , pSetup -> wValue , pSetup -> wLength , dfu_data . state ) ; if ( dfu_check_app_state ( ) ) return - EINVAL ; switch ( dfu_data . state ) { case dfuIDLE : dfu_reset_counters ( ) ; SYS_LOG_DBG ( " " ) ; case dfuDNLOAD_IDLE : if ( pSetup -> wLength != 0 ) { dfu_data . state = dfuDNLOAD_IDLE ; if ( ! ( dfu_data . bytes_rcvd % dfu_data . flash_page_size ) ) { ret = flash_erase ( dfu_data . flash_dev , DFU_FLASH_ADDR + dfu_data . bytes_rcvd , dfu_data . flash_page_size ) ; SYS_LOG_DBG ( " " ) ; if ( ret ) { dfu_data . state = dfuERROR ; dfu_data . status = errERASE ; SYS_LOG_DBG ( " " " " , ret ) ; } } len = ( pSetup -> wLength + 3 ) & ( ~ 3 ) ; ret = flash_write ( dfu_data . flash_dev , DFU_FLASH_ADDR + dfu_data . bytes_rcvd , * data , len ) ; if ( ret ) { dfu_data . state = dfuERROR ; dfu_data . status = errWRITE ; SYS_LOG_DBG ( " " , ret ) ; } else dfu_data . bytes_rcvd += pSetup -> wLength ; } else { dfu_data . state = dfuMANIFEST_SYNC ; dfu_reset_counters ( ) ; } break ; default : SYS_LOG_DBG ( " " , dfu_data . state ) ; dfu_data . state = dfuERROR ; dfu_data . status = errUNKNOWN ; dfu_reset_counters ( ) ; return - EINVAL ; } break ; case DFU_UPLOAD : SYS_LOG_DBG ( " " , pSetup -> wValue , pSetup -> wLength , dfu_data . state ) ; if ( dfu_check_app_state ( ) ) return - EINVAL ; switch ( dfu_data . state ) { case dfuIDLE : dfu_reset_counters ( ) ; SYS_LOG_DBG ( " " ) ; case dfuUPLOAD_IDLE : if ( ! pSetup -> wLength || dfu_data . block_nr != pSetup -> wValue ) { SYS_LOG_DBG ( " " " " , pSetup -> wValue , dfu_data . block_nr , pSetup -> wLength ) ; dfu_data . state = dfuERROR ; dfu_data . status = errUNKNOWN ; break ; } bytes_left = dfu_data . flash_upload_size - dfu_data . bytes_sent ; if ( bytes_left < pSetup -> wLength ) len = bytes_left ; else len = pSetup -> wLength ; if ( len ) { ret = flash_read ( dfu_data . flash_dev , DFU_FLASH_ADDR + dfu_data . bytes_sent , dfu_data . buffer , len ) ; if ( ret ) { dfu_data . state = dfuERROR ; dfu_data . status = errFILE ; break ; } } * data_len = len ; * data = dfu_data . buffer ; dfu_data . bytes_sent += len ; dfu_data . block_nr ++ ; if ( dfu_data . bytes_sent == dfu_data . flash_upload_size && len < pSetup -> wLength ) { * data_len = 0 ; dfu_data . state = dfuIDLE ; } else dfu_data . state = dfuUPLOAD_IDLE ; break ; default : SYS_LOG_DBG ( " " , dfu_data . state ) ; dfu_data . state = dfuERROR ; dfu_data . status = errUNKNOWN ; dfu_reset_counters ( ) ; return - EINVAL ; } break ; case DFU_DETACH : SYS_LOG_DBG ( " " , pSetup -> wValue , dfu_data . state ) ; if ( dfu_data . state != appIDLE ) { dfu_data . state = appIDLE ; return - EINVAL ; } dfu_data . state = appDETACH ; dfu_config . usb_device_description = dfu_mode_usb_description ; if ( usb_set_config ( & dfu_config ) != 0 ) { SYS_LOG_DBG ( " " ) ; return - EIO ; } break ; default : SYS_LOG_DBG ( " " , pSetup -> bRequest ) ; return - EINVAL ; } return 0 ; }
@brief Handler called for DFU Class requests not handled by the USB stack.
@brief Handler called for DFU Class requests not handled by the USB stack .
/* Download has started */ /* Flash write len should be multiple of 4 */ /* Download completed */ /* Upload in progress */ /* Upload completed when a
				 * short packet is received
				 */ /* Move to appDETACH state */ /* We should start a timer here but in order to
		 * keep things simple and do not increase the size
		 * we rely on the host to get us out of the appATTACHED
		 * state if needed.
		 */ /* Set the DFU mode descriptors to be used after reset */