Example #1
0
/* Send a Command Status Word (CSW) */
static int8_t send_csw(struct msc_application_data *msc,
                       uint32_t residue, uint8_t status)
{
	struct msc_command_status_wrapper *csw;

	/* Make sure endpoint is free */
	if (usb_in_endpoint_busy(msc->in_endpoint))
		return -1;

	csw = (struct msc_command_status_wrapper *)
			usb_get_in_buffer(msc->in_endpoint);
	csw->dCSWSignature = 0x53425355;
	csw->dCSWTag = msc->current_tag;
	csw->dCSWDataResidue = residue;
	csw->bCSWStatus = status;

	usb_send_in_buffer(msc->in_endpoint, sizeof(*csw));

	/* Reset states and status */
	msc->state = MSC_IDLE;
	msc->status = MSC_STATUS_PASSED;
	msc->residue = 0;

	return 0;
}
Example #2
0
/* Send the next transaction containing data from the medium to the host. */
static int8_t send_next_data_transaction(struct msc_application_data *msc)
{
	const uint8_t *cur = msc->tx_buf;
	const uint16_t len = msc->tx_len_remaining;

	if (!usb_is_configured() || usb_in_endpoint_busy(msc->in_endpoint))
		return -1;

	if (len > 0) {
		/* There is data to send; send one packet worth. */
		uint8_t *buf;
		uint16_t to_copy;

		buf = usb_get_in_buffer(msc->in_endpoint);
		to_copy = MIN(len, msc->in_endpoint_size);
		memcpy(buf, cur, to_copy);

		usb_send_in_buffer(msc->in_endpoint, to_copy);

		msc->transferred_bytes += to_copy;
		msc->tx_buf += to_copy;
		msc->tx_len_remaining -= to_copy;
	}
	else {
		/* Transfer of block has completed */
		msc->operation_complete_callback(msc, true);
		msc->operation_complete_callback = NULL;
		msc->tx_buf = NULL;
	}

	return 0;
}
Example #3
0
static void send_string_sync(uint8_t endpoint, const char *str)
{
	char *in_buf = (char*) usb_get_in_buffer(endpoint);

	while (usb_in_endpoint_busy(endpoint))
		;

	strcpy(in_buf, str);
	/* Hack: Get the length from strlen(). This is inefficient, but it's
	 * just a demo. strlen()'s return excludes the terminating NULL. */
	usb_send_in_buffer(endpoint, strlen(in_buf));
}
Example #4
0
int main(void)
{
    OSCCONbits.IRCF = 0b1111; // 0b1111 = 16MHz HFINTOSC postscaler
    ANSELA = 0x00; // digital I/O on PORTA
    ANSELB = 0x00; // digital I/O on PORTB
    ANSELC = 0x00; // digital I/O on PORTC
    APFCON = 0x00; // a little bit of voodoo
    MODE_SW_TRIS = PIN_OUTPUT;
    MODE_SW = POTENTIOSTATIC; // initialize mode to potentiostatic
    CELL_ON_TRIS = PIN_OUTPUT;
    CELL_ON_PIN = CELL_OFF; // initialize cell to off position
    TRISC = 0x00; // all outputs on PORTC
    LATC = RANGE1; // initialize range to range 1

    // Enable Active clock-tuning from the USB
    ACTCONbits.ACTSRC = 1; // 1=USB
    ACTCONbits.ACTEN = 1;

    // Configure interrupts
    INTCONbits.PEIE = 1;
    INTCONbits.GIE = 1;

    // Initialize USB
    usb_init();

    while (1)
    {
        if (usb_is_configured() && usb_out_endpoint_has_data(1)) // wait for data received from host
        {
            if (!usb_in_endpoint_halted(1))
            {
                while (usb_in_endpoint_busy(1)) // wait for EP1 IN to become free
                    ;
                received_data_length = usb_get_out_buffer(1, &received_data);
                transmit_data = usb_get_in_buffer(1);
                interpret_command(); // this reads received_data and sets transmit_data and transmit_data_length
                usb_send_in_buffer(1, transmit_data_length); // send the data back
            }
            usb_arm_out_endpoint(1);
        }
    }

    return 0;
}
Example #5
0
int main(void) {
    hardware_init();

    luke_init();
    
#ifdef MULTI_CLASS_DEVICE
    hid_set_interface_list(hid_interfaces, sizeof (hid_interfaces));
#endif
    usb_init();

    uint8_t  regAddr = 0;
    
    while (1) {
        if (usb_is_configured() && usb_out_endpoint_has_data(1)) {
            //                uint8_t len;
            const unsigned char *RxDataBuffer;
            unsigned char *TxDataBuffer = usb_get_in_buffer(1);
            /* Data received from host */

            if (!usb_in_endpoint_halted(1)) {
                /* Wait for EP 1 IN to become free then send. This of
                 * course only works using interrupts. */
                while (usb_in_endpoint_busy(1))
                    ;

                usb_get_out_buffer(1, &RxDataBuffer);

                uint8_t pcktVer = RxDataBuffer[0] & 0xC0;
                uint8_t pcktLen = RxDataBuffer[0] & 0x2F;

                if (pcktVer == PROTOCOL_VERSION && pcktLen > 1) {

                    uint8_t opcode = RxDataBuffer[1];
                    TxDataBuffer[1] = opcode; // echo back operation code
                    ATTID id = (RxDataBuffer[2] << 8) + RxDataBuffer[3];                        
                    uint8_t len;
                    
                    switch (opcode) {
                        case OP_ATT_VALUE_GET:
                            TxDataBuffer[2] = RC_OK; // Return OK code
                            TxDataBuffer[0] = PROTOCOL_VERSION;

                            switch (id) {
                                case ATT_PRODUCT_NAME:
                                    len = strlen(PRODUCT_NAME) + 1; // +1 for NULL
                                    TxDataBuffer[0] |= len + 3; // packet length
                                    memcpy(&TxDataBuffer[3], PRODUCT_NAME, len);
                                    break;
                                    
                                case ATT_PRODUCT_REVISION:
                                    TxDataBuffer[0] |= 2 + 3; // packet length
                                    TxDataBuffer[3] = '0' + PORTCbits.RC2;
                                    TxDataBuffer[4] = NULL;
                                    break;
                            
                                case ATT_PRODUCT_SERIAL:
                                /*  TxDataBuffer[0]  |= NVM_PRODUCT_SERIAL_SIZE + 3; // packet length
                                    for (uint8_t i=0; i<NVM_PRODUCT_SERIAL_SIZE; i++) {
                                    // Please note that 1 word of HEF is 14bits but lower 8bits is high-endurance
                                    TxDataBuffer[i+3] = (uint8_t) FLASH_ReadWord(NVM_PRODUCT_SERIAL_ADDR + i);
                                } */
                                    TxDataBuffer[0]  |= NVM_PRODUCT_SERIAL_SIZE + 3; // packet length
                                    memcpy(&TxDataBuffer[3], NVM_PRODUCT_SERIAL_ADDR, NVM_PRODUCT_SERIAL_SIZE);
                                    break;
                                
                                case ATT_FIRM_VERSION:
                                    len = strlen(FIRM_VERSION) + 1; // +1 for NULL
                                    TxDataBuffer[0] |= len + 3; // packet length
                                    memcpy(&TxDataBuffer[3], FIRM_VERSION, len);
                                    break;
                                    
                                case ATT_I2C0_RW_2BYTE:
                                    TxDataBuffer[0]  |= 2 + 3; // packet length
                                    uint16_t dat = i2c_reg_read(regAddr);
                                    TxDataBuffer[4] = dat >> 8; 
                                    TxDataBuffer[3] = dat;
                                    break;
                                    
                                case ATT_VOLTAGE:
                                    TxDataBuffer[0] |= 4 + 3; // packet length
                                    float volt = get_voltage();
                                    TxDataBuffer[3] = 0x00;
                                    memcpy(&TxDataBuffer[4], &volt, 3);
                                    break;
                                
                                case ATT_CURRENT:
                                    TxDataBuffer[0] |= 4 + 3; // packet length
                                    float curr = get_current();
                                    TxDataBuffer[3] = 0x00;
                                    memcpy(&TxDataBuffer[4], &curr, 3);
                                    break;

                                default:
                                    TxDataBuffer[0] |= 3; // packet length
                                    TxDataBuffer[2] = RC_FAIL; // Return error code
                                    break;
                                    
                            } // end of switch (id)
                            break;
                            
                        case  OP_ATT_VALUE_SET:
                            TxDataBuffer[0] = PROTOCOL_VERSION | 3; // packet length
                            TxDataBuffer[2] = RC_OK; // Return OK code
                            
                            switch (id) {
                                case ATT_I2C0_REG_ADDR:
                                    regAddr = RxDataBuffer[4];
                                    break;
                                    
                                case ATT_I2C0_RW_2BYTE:
                                    i2c_reg_write(regAddr, RxDataBuffer[5], RxDataBuffer[4]);
                                    break;
                                
                                default:
                                    TxDataBuffer[2] = RC_FAIL; // Return error code
                                    break;
                                    
                            } // end of switch (id)
                            break;
                            
                        default:
                            TxDataBuffer[0] = PROTOCOL_VERSION | 3; // packet length
                            TxDataBuffer[2] = RC_FAIL; // Return error code
                            break;
                                                        
                    } // switch (opcode)
                          
                    // Send response
                    memcpy(usb_get_in_buffer(1), TxDataBuffer, EP_1_IN_LEN);
                    usb_send_in_buffer(1, EP_1_IN_LEN);

                } // end of if (pcktVer == PROTOCOL_VERSION && pcktLen > 1)
            }
            usb_arm_out_endpoint(1);
        }

#ifndef USB_USE_INTERRUPTS
        usb_service();
#endif
    }
Example #6
0
int main(void)
{
#if defined(__PIC24FJ64GB002__) || defined(__PIC24FJ256DA206__)
	unsigned int pll_startup_counter = 600;
	CLKDIVbits.PLLEN = 1;
	while(pll_startup_counter--);
#elif _18F46J50
	unsigned int pll_startup = 600;
	OSCTUNEbits.PLLEN = 1;
	while (pll_startup--)
		;
#elif _16F1459 || _16F1454
	OSCCONbits.IRCF = 0b1111; /* 0b1111 = 16MHz HFINTOSC postscalar */

	/* Enable Active clock-tuning from the USB */
	ACTCONbits.ACTSRC = 1; /* 1=USB */
	ACTCONbits.ACTEN = 1;
#elif __32MX460F512L__
	SYSTEMConfigPerformance(80000000);
#endif


/* Configure interrupts, per architecture */
#ifdef USB_USE_INTERRUPTS
	#if defined (_PIC18) || defined(_PIC14E)
		INTCONbits.PEIE = 1;
		INTCONbits.GIE = 1;
	#elif __PIC32MX__
		INTCONbits.MVEC = 1; /* Multi-vector interrupts */
		IPC11bits.USBIP = 4; /* Interrupt priority, must set to != 0. */
		__asm volatile("ei");
	#endif
#endif

#ifdef MULTI_CLASS_DEVICE
	hid_set_interface_list(hid_interfaces, sizeof(hid_interfaces));
#endif
	usb_init();

	/* Setup mouse movement. This implementation sends back data for every
	 * IN packet, but sends no movement for all but every delay-th frame.
	 * Adjusting delay will slow down or speed up the movement, which is
	 * also dependent upon the rate at which the host sends IN packets,
	 * which varies between implementations.
	 *
	 * In real life, you wouldn't want to send back data that hadn't
	 * changed, but since there's no real hardware to poll, and since this
	 * example is about showing the HID class, and not about creative ways
	 * to do timing, we send back data every frame. The interested reader
	 * may want to modify it to use the start-of-frame callback for
	 * timing.
	 */
	uint8_t x_delay = 14;
	uint8_t x_count = 100;
	int8_t x_direc = 1;
	uint8_t y_delay = 14;
	uint8_t y_count = 25;
	int8_t y_direc = 1;

	while (1) {
		if (usb_is_configured() &&
		    !usb_in_endpoint_halted(1) &&
		    !usb_in_endpoint_busy(1)) {

			/* Interface 1: Move mouse Left and Right. This
			 * interface only has an X axis. */
			unsigned char *buf = usb_get_in_buffer(1);
			buf[0] = 0x0;
			buf[1] = (--x_delay)? 0: x_direc;
			buf[2] = 0; /* Don't move Y */
			usb_send_in_buffer(1, 3);

			if (x_delay == 0) {
				if (--x_count == 0) {
					x_count = 100;
					x_direc *= -1;
				}
				x_delay = 14;
			}
		}

		if (usb_is_configured() &&
		    !usb_in_endpoint_halted(2) &&
		    !usb_in_endpoint_busy(2)) {

			/* Interface 2: Move mouse up and Down. This
			 * interface only has a Y axis. */
			unsigned char *buf = usb_get_in_buffer(2);
			buf[0] = 0x0;
			buf[1] = 0; /* Don't move X */
			buf[2] = (--y_delay)? 0: y_direc;
			buf[3] = 0; /* Don't move Z */
			usb_send_in_buffer(2, 4);

			if (y_delay == 0) {
				if (--y_count == 0) {
					y_count = 25;
					y_direc *= -1;
				}
				y_delay = 14;
			}
		}

		#ifndef USB_USE_INTERRUPTS
		usb_service();
		#endif
	}

	return 0;
}
Example #7
0
static void process_msc_command(struct msc_application_data *msc,
                                const uint8_t *data, uint16_t len)
{
	const struct msc_command_block_wrapper *cbw = (const void *) data;
	const uint8_t command = cbw->CBWCB[0];
	const uint8_t lun = cbw->bCBWLUN;
	const uint32_t cbw_length = cbw->dCBWDataTransferLength;
	int8_t res;

	/* Check the Command Block Wrapper (CBW) */
	if (!msc_cbw_valid_and_meaningful(msc, data,len))
		goto bad_cbw;

	msc->current_tag = cbw->dCBWTag;

	if (command == MSC_SCSI_INQUIRY) {
		uint32_t scsi_request_len;
		struct msc_scsi_inquiry_command *cmd =
			(struct msc_scsi_inquiry_command *) cbw->CBWCB;
		struct scsi_inquiry_response *resp =
			(struct scsi_inquiry_response *)
				usb_get_in_buffer(msc->in_endpoint);

		swap2(&cmd->allocation_length);

		/* The host may request just the first part of the inquiry
		 * response structure. */
		scsi_request_len = MIN(cmd->allocation_length, sizeof(*resp));

		/* INQUIRY: Device indends to send data to the host (Di). */
		res = check_di_cases(msc, cbw, scsi_request_len);
		if (res < 0)
			goto fail;

		if (usb_in_endpoint_busy(msc->in_endpoint))
			goto fail;

		/* Send INQUIRY response */
		memset(resp, 0, sizeof(*resp));
		resp->peripheral = 0x0;
		resp->rmb = (msc->media_is_removable_mask & (1<<lun))? 0x80: 0;
		resp->version = MSC_SCSI_SPC_VERSION_2;
		resp->response_data_format = 0x2;
		resp->additional_length = sizeof(*resp) - 4;
		strncpy(resp->vendor, msc->vendor, sizeof(resp->vendor));
		strncpy(resp->product, msc->product, sizeof(resp->product));
		strncpy(resp->revision, msc->revision, sizeof(resp->revision));

		usb_send_in_buffer(msc->in_endpoint, scsi_request_len);

		set_data_in_endpoint_state(msc, cbw_length, scsi_request_len);
	}
	else if (command == MSC_SCSI_TEST_UNIT_READY) {
		/* TEST_UNIT_READY: Device intends to transfer no data (Dn). */
		res = check_dn_cases(msc, cbw);
		if (res < 0)
			goto fail;

		if (usb_in_endpoint_busy(msc->in_endpoint))
			goto fail;

		res = MSC_UNIT_READY(msc, lun);
		if (res < 0) {
			/* Set error */
			set_scsi_sense(msc, res);
			send_csw(msc, cbw_length, MSC_STATUS_FAILED);
			goto fail;
		}

		send_csw(msc, cbw_length, MSC_STATUS_PASSED);
	}
	else if (command == MSC_SCSI_READ_CAPACITY_10) {
		struct scsi_capacity_response *resp =
			(struct scsi_capacity_response *)
				usb_get_in_buffer(msc->in_endpoint);
		uint32_t block_size, num_blocks;
		bool write_protect;

		/* Read Capacity 10: Device intends to send data
		 *                   to the host (Di) */
		res = check_di_cases(msc, cbw, sizeof(*resp));
		if (res < 0)
			goto fail;

		if (usb_in_endpoint_busy(msc->in_endpoint))
			goto fail;

		res = MSC_GET_STORAGE_INFORMATION(
				msc, lun,
				&block_size, &num_blocks, &write_protect);
		if (res < 0) {
			/* Stall and set error */
			set_scsi_sense(msc, res);
			stall_in_and_set_status(
			                 msc, cbw_length, MSC_STATUS_FAILED);
			goto fail;
		}

		/* Pack and send the response buffer */
		resp->last_block = num_blocks - 1;
		resp->block_length = block_size;
		swap4(&resp->last_block);
		swap4(&resp->block_length);
		usb_send_in_buffer(msc->in_endpoint, sizeof(*resp));

		/* Save off block_size */
		msc->block_size[lun] = block_size;

		set_data_in_endpoint_state(msc, cbw_length, sizeof(*resp));
	}
	else if (command == MSC_SCSI_REQUEST_SENSE) {
		uint32_t scsi_request_len;
		struct msc_scsi_request_sense_command *cmd =
			(struct msc_scsi_request_sense_command *) cbw->CBWCB;
		struct scsi_sense_response *resp =
			(struct scsi_sense_response *)
				usb_get_in_buffer(msc->in_endpoint);

		scsi_request_len = MIN(cmd->allocation_length, sizeof(*resp));

		/* REQUEST_SENSE: Device intends to send data
		 *                to the host (Di) */
		res = check_di_cases(msc, cbw, scsi_request_len);
		if (res < 0)
			goto fail;

		if (usb_in_endpoint_busy(msc->in_endpoint))
			goto fail;

		memset(resp, 0, sizeof(*resp));
		resp->response_code = SCSI_SENSE_CURRENT_ERRORS;
		resp->flags = msc->sense_key;
		resp->additional_sense_length = 0xa;
		resp->additional_sense_code = msc->additional_sense_code;

		usb_send_in_buffer(msc->in_endpoint, scsi_request_len);

		set_data_in_endpoint_state(msc, cbw_length, scsi_request_len);
	}
	else if (command == MSC_SCSI_MODE_SENSE_6) {
		uint32_t block_size, num_blocks;
		int8_t res;
		bool write_protect;

		struct msc_scsi_mode_sense_6_command *cmd =
			(struct msc_scsi_mode_sense_6_command *) cbw->CBWCB;
		struct scsi_mode_sense_response *resp =
			(struct scsi_mode_sense_response *)
				usb_get_in_buffer(msc->in_endpoint);

		/* MODE_SENSE(6): Device intends to send data
		 *                to the host (Di) */
		res = check_di_cases(msc, cbw, sizeof(*resp));
		if (res < 0)
			goto fail;

		if (usb_in_endpoint_busy(msc->in_endpoint))
			goto fail;

		/* Look for page code 0x3f, subpage code 0x0. */
		if (cmd->pc_page_code != 0x3f || cmd->subpage_code != 0) {
			msc->sense_key = SCSI_SENSE_KEY_ILLEGAL_REQUEST;
			msc->additional_sense_code =
			     SCSI_ASC_INVALID_FIELD_IN_COMMAND_PACKET;

			/* Stall and send the status after the stall. */
			stall_in_and_set_status(msc,
			                        cbw_length,
			                        MSC_STATUS_FAILED);
			goto fail;
		}

		res = MSC_GET_STORAGE_INFORMATION(msc, lun, &block_size,
		                                  &num_blocks, &write_protect);
		if (res < 0) {
			/* Stall and set error */
			set_scsi_sense(msc, res);
			stall_in_and_set_status(
			                msc, cbw_length, MSC_STATUS_FAILED);
			goto fail;
		}

#ifndef MSC_WRITE_SUPPORT
		/* Force write-protect on if write is not supported */
		write_protect = true;
#endif
		resp->mode_data_length =
			sizeof(struct scsi_mode_sense_response) - 1;
		resp->medium_type = 0x0; /* 0 = SBC */
		resp->device_specific_parameter = (write_protect)? 0x80: 0;
		resp->block_descriptor_length = 0;

		usb_send_in_buffer(msc->in_endpoint, sizeof(*resp));
		set_data_in_endpoint_state(msc, cbw_length, sizeof(*resp));
	}
	else if (command == MSC_SCSI_START_STOP_UNIT) {
		int8_t res;
		bool start, load_eject;

		struct msc_scsi_start_stop_unit *cmd =
			(struct msc_scsi_start_stop_unit *) cbw->CBWCB;

		/* START STOP UNIT: Device intends to not send or receive
		 *                  any data (Dn). */
		res = check_dn_cases(msc, cbw);
		if (res < 0)
			goto fail;

		if (usb_in_endpoint_busy(msc->in_endpoint))
			goto fail;

		/* Only accept power condition 0x0, START_VALID */
		if ((cmd->command & 0xf0) != 0)
			goto fail;

		start      = ((cmd->command & 0x1) != 0);
		load_eject = ((cmd->command & 0x2) != 0);

		res = MSC_START_STOP_UNIT(msc, lun, start, load_eject);
		if (res < 0) {
			set_scsi_sense(msc, res);
			send_csw(msc, cbw_length, MSC_STATUS_FAILED);
			goto fail;
		}

		send_csw(msc, 0, MSC_STATUS_PASSED);
	}
	else if (command == MSC_SCSI_READ_10) {
		uint32_t scsi_request_len;
		struct msc_scsi_read_10_command *cmd =
			(struct msc_scsi_read_10_command *) cbw->CBWCB;

		swap4(&cmd->logical_block_address);
		swap2(&cmd->transfer_length); /* length in blocks */

		if (usb_in_endpoint_busy(msc->in_endpoint))
			goto fail;

		scsi_request_len = cmd->transfer_length * msc->block_size[lun];

		/* Handle the nonsensical, but possible case of the host
		 * asking to read 0 bytes in the SCSI. That actually makes
		 * this a Dn case rather than a Di case. */
		if (scsi_request_len == 0) {
			res = check_dn_cases(msc, cbw);
			if (res < 0)
				goto fail;

			/* If check_dn_cases() succeeded, then the host is
			 * not expecting any data, so send the CSW*/
			send_csw(msc, 0, MSC_STATUS_PASSED);
			goto fail; /* Not a failure, but handled the same */
		}

		/* READ(10): Device intends to send data to the host (Di) */
		res = check_di_cases(msc, cbw, scsi_request_len);
		if (res < 0)
			goto fail;

		/* Set up the transport state. It's important that this is
		 * done before the call to the MSC_START_READ() callback
		 * below, because the application could concievably start
		 * calling msc_send_to_host() from the callback. */
		msc->requested_bytes = MIN(cbw_length, scsi_request_len);
		msc->requested_bytes_cbw = cbw_length;
		msc->transferred_bytes = 0;
		msc->state = MSC_DATA_TRANSPORT_IN;

		/* Start the Data-Transport. After receiving the call to
		 * MSC_START_READ() the application will repeatedly call
		 * msc_send_to_host() with data read from the medium
		 * and then call msc_data_complete() when finished. */
		res = MSC_START_READ(msc, lun,
			             cmd->logical_block_address,
			             cmd->transfer_length);
		if (res < 0) {
			set_scsi_sense(msc, res);
			stall_in_and_set_status(msc,
			                        cbw_length,
			                        MSC_STATUS_FAILED);

			/* Reset the state */
			msc->requested_bytes = 0;
			msc->requested_bytes_cbw = 0;
			msc->state = MSC_IDLE;
			goto fail;
		}
	}
#ifdef MSC_WRITE_SUPPORT
	else if (command == MSC_SCSI_WRITE_10) {
		uint32_t scsi_request_len;
		int8_t res;
		struct msc_scsi_write_10_command *cmd =
			(struct msc_scsi_write_10_command *) cbw->CBWCB;

		swap4(&cmd->logical_block_address);
		swap2(&cmd->transfer_length); /* length in blocks */

		scsi_request_len = cmd->transfer_length * msc->block_size[lun];

		/* Handle the nonsensical, but possible case of the host
		 * asking to write 0 bytes in the SCSI command. That actually
		 * makes this a Dn case rather than a Do case, and is
		 * required by the USBCV test. */
		if (scsi_request_len == 0) {
			res = check_dn_cases(msc, cbw);
			if (res < 0)
				goto fail;

			/* If check_dn_cases() succeeded, then the host is
			 * not expecting to write any data, so send the CSW */
			send_csw(msc, 0, MSC_STATUS_PASSED);
			goto fail; /* Not a failure, but handled the same */
		}

		/* Write(10): Device intends to receive data
		 *            from the host (Do) */
		res = check_do_cases(msc, cbw, scsi_request_len);
		if (res < 0)
			goto fail;

		/* Start the Data-Transport. The application will give
		 * a buffer to put the data into. */
		res = MSC_START_WRITE(msc,
		               lun,
		               cmd->logical_block_address,
		               cmd->transfer_length,
		               &msc->rx_buf,
		               &msc->rx_buf_len,
		               &msc->operation_complete_callback);

		if (res < 0) {
			set_scsi_sense(msc, res);
			stall_out_and_set_status(msc,
			                         cbw_length,
			                         MSC_STATUS_FAILED);
			goto fail;
		}

		/* Initialize the data transport */
		msc->requested_bytes = scsi_request_len;
		msc->requested_bytes_cbw = cbw_length;
		msc->transferred_bytes = 0;
		msc->rx_buf_cur = msc->rx_buf;
		msc->state = MSC_DATA_TRANSPORT_OUT;
	}
#endif /* MSC_WRITE_SUPPORT */
	else {
		/* Unsupported command. See Axelson, page 69. */
		const bool direc_is_in = direction_is_in(cbw->bmCBWFlags);

		/* Set error codes which will be requested with REQUEST_SENSE
		 * by the host later. */
		msc->sense_key = SCSI_SENSE_KEY_ILLEGAL_REQUEST;
		msc->additional_sense_code =
			SCSI_ASC_INVALID_COMMAND_OPERATION_CODE;

		/* Stall appropriate endpoint and send FAILED for the CSW. */
		if (direc_is_in || cbw_length == 0)
			stall_in_and_set_status(msc,
			                 cbw_length, MSC_STATUS_FAILED);
		else
			stall_out_and_set_status(msc,
			                 cbw_length, MSC_STATUS_FAILED);

		goto fail;
	}

	return;

bad_cbw:
	/* If the CBW is not valid or is not meaningful, then stall both
	 * endpoints until a Reset Recovery (BOT 5.3.4) procedure is
	 * completed by the host (BOT 5.3, Figure 2). */
	usb_halt_ep_in(msc->in_endpoint);
	usb_halt_ep_out(msc->out_endpoint);
	msc->state = MSC_NEEDS_RESET_RECOVERY;
fail:
	return;
}
Example #8
0
int main(void)
{
	hardware_init();

#ifdef MULTI_CLASS_DEVICE
	hid_set_interface_list(hid_interfaces, sizeof(hid_interfaces));
#endif
	usb_init();

	/* Setup mouse movement. This implementation sends back data for every
	 * IN packet, but sends no movement for all but every delay-th frame.
	 * Adjusting delay will slow down or speed up the movement, which is
	 * also dependent upon the rate at which the host sends IN packets,
	 * which varies between implementations.
	 *
	 * In real life, you wouldn't want to send back data that hadn't
	 * changed, but since there's no real hardware to poll, and since this
	 * example is about showing the HID class, and not about creative ways
	 * to do timing, we send back data every frame. The interested reader
	 * may want to modify it to use the start-of-frame callback for
	 * timing.
	 */
	uint8_t x_delay = 14;
	uint8_t x_count = 100;
	int8_t x_direc = 1;
	uint8_t y_delay = 14;
	uint8_t y_count = 25;
	int8_t y_direc = 1;

	while (1) {
		if (usb_is_configured() &&
		    !usb_in_endpoint_halted(1) &&
		    !usb_in_endpoint_busy(1)) {

			/* Interface 1: Move mouse Left and Right. This
			 * interface only has an X axis. */
			unsigned char *buf = usb_get_in_buffer(1);
			buf[0] = 0x0;
			buf[1] = (--x_delay)? 0: x_direc;
			buf[2] = 0; /* Don't move Y */
			usb_send_in_buffer(1, 3);

			if (x_delay == 0) {
				if (--x_count == 0) {
					x_count = 100;
					x_direc *= -1;
				}
				x_delay = 14;
			}
		}

		if (usb_is_configured() &&
		    !usb_in_endpoint_halted(2) &&
		    !usb_in_endpoint_busy(2)) {

			/* Interface 2: Move mouse up and Down. This
			 * interface only has a Y axis. */
			unsigned char *buf = usb_get_in_buffer(2);
			buf[0] = 0x0;
			buf[1] = 0; /* Don't move X */
			buf[2] = (--y_delay)? 0: y_direc;
			buf[3] = 0; /* Don't move Z */
			usb_send_in_buffer(2, 4);

			if (y_delay == 0) {
				if (--y_count == 0) {
					y_count = 25;
					y_direc *= -1;
				}
				y_delay = 14;
			}
		}

		#ifndef USB_USE_INTERRUPTS
		usb_service();
		#endif
	}

	return 0;
}
Example #9
0
int main(void)
{

    hardware_init();

#ifdef MULTI_CLASS_DEVICE
	cdc_set_interface_list(cdc_interfaces, sizeof(cdc_interfaces));
#endif
	usb_init();

	uint8_t char_to_send = 'A';
	bool send = true;
	bool loopback = false;

	while (1) {

		/* Send data to the PC */
		if (usb_is_configured() &&
		    !usb_in_endpoint_halted(2) &&
		    !usb_in_endpoint_busy(2) && send) {

			int i;
			unsigned char *buf = usb_get_in_buffer(2);

			for (i = 0; i < 16; i++) {
				buf[i] = char_to_send++;
				if (char_to_send > 'Z')
					char_to_send = 'A';
			}
			buf[i++] = '\r';
			buf[i++] = '\n';
			usb_send_in_buffer(2, i);
		}

		/* Handle data received from the host */
		if (usb_is_configured() &&
		    !usb_out_endpoint_halted(2) &&
		    usb_out_endpoint_has_data(2)) {
			const unsigned char *out_buf;
			size_t out_buf_len;
			int i;

			/* Check for an empty transaction. */
			out_buf_len = usb_get_out_buffer(2, &out_buf);
			if (out_buf_len <= 0)
				goto empty;

			if (send) {
				/* Stop sendng if a key was hit. */
				send = false;
				send_string_sync(2, "Data send off ('h' for help)\r\n");
			}
			else if (loopback) {
				/* Loop data back to the PC */

				/* Wait until the IN endpoint can accept it */
				while (usb_in_endpoint_busy(2))
					;

				/* Copy contents of OUT buffer to IN buffer
				 * and send back to host. */
				memcpy(usb_get_in_buffer(2), out_buf, out_buf_len);
				usb_send_in_buffer(2, out_buf_len);

				/* Send a zero-length packet if the transaction
				 * length was the same as the endpoint
				 * length. This is for demo purposes. In real
				 * life, you only need to do this if the data
				 * you're transferring ends on a multiple of
				 * the endpoint length. */
				if (out_buf_len == EP_2_LEN) {
					/* Wait until the IN endpoint can accept it */
					while (usb_in_endpoint_busy(2))
						;
					usb_send_in_buffer(2, 0);
				}

				/* Scan for ~ character to end loopback mode */
				for (i = 0; i < out_buf_len; i++) {
					if (out_buf[i] == '~') {
						loopback = false;
						send_string_sync(2, "\r\nLoopback off ('h' for help)\r\n");
						break;
					}
				}
			}
			else {
				/* Scan for commands if not in loopback or
				 * send mode.
				 *
				 * This is a hack. One should really scan the
				 * entire string. In this case, since this
				 * is a demo, assume that the user is using
				 * a terminal program and typing the input,
				 * all but ensuring the data will come in
				 * single-character transactions. */
				if (out_buf[0] == 'h' || out_buf[0] == '?') {
					/* Show help.
					 * Make sure to not try to send more
					 * than 63 bytes of data in one
					 * transaction */
					send_string_sync(2,
						"\r\nHelp:\r\n"
						"\ts: send data\r\n"
						"\tl: loopback\r\n");
					send_string_sync(2,
						"\tn: send notification\r\n"
						"\th: help\r\n");
				}
				else if (out_buf[0] == 's')
					send = true;
				else if (out_buf[0] == 'l') {
					loopback = true;
					send_string_sync(2, "loopback enabled; press ~ to disable\r\n");
				}
				else if (out_buf[0] == 'n') {
					/* Send a Notification on Endpoint 1 */
					struct cdc_serial_state_notification *n =
						(struct cdc_serial_state_notification *)
							usb_get_in_buffer(1);

					n->header.REQUEST.bmRequestType = 0xa1;
					n->header.bNotification = CDC_SERIAL_STATE;
					n->header.wValue = 0;
					n->header.wIndex = 1; /* Interface */
					n->header.wLength = 2;
					n->data.serial_state = 0; /* Zero the whole bit mask */
					n->data.bits.bRxCarrier = 1;
					n->data.bits.bTxCarrier = 1;
					n->data.bits.bBreak = 0;
					n->data.bits.bRingSignal = 0;
					n->data.bits.bFraming = 0;
					n->data.bits.bParity = 0;
					n->data.bits.bOverrun = 0;

					/* Wait for the endpoint to be free */
					while (usb_in_endpoint_busy(1))
						;

					/* Send to to host */
					usb_send_in_buffer(1, sizeof(*n));

					send_string_sync(2, "Notification Sent\r\n");
				}
			}
empty:
			usb_arm_out_endpoint(2);
		}

		#ifndef USB_USE_INTERRUPTS
		usb_service();
		#endif
	}

	return 0;
}
Example #10
0
int main(void)
{
#if defined(__PIC24FJ64GB002__) || defined(__PIC24FJ256DA206__)
	unsigned int pll_startup_counter = 600;
	CLKDIVbits.PLLEN = 1;
	while(pll_startup_counter--);
#elif _18F46J50
	unsigned int pll_startup = 600;
	OSCTUNEbits.PLLEN = 1;
	while (pll_startup--)
		;
#elif _16F1459
	OSCCONbits.IRCF = 0b1111; /* 0b1111 = 16MHz HFINTOSC postscalar */

	/* Enable Active clock-tuning from the USB */
	ACTCONbits.ACTSRC = 1; /* 1=USB */
	ACTCONbits.ACTEN = 1;
#elif __32MX460F512L__
	SYSTEMConfigPerformance(80000000);
#endif


/* Configure interrupts, per architecture */
#ifdef USB_USE_INTERRUPTS
	#if defined (_PIC18) || defined(_PIC14E)
		INTCONbits.PEIE = 1;
		INTCONbits.GIE = 1;
	#elif __PIC32MX__
		INTCONbits.MVEC = 1; /* Multi-vector interrupts */
		IPC11bits.USBIP = 4; /* Interrupt priority, must set to != 0. */
		__asm volatile("ei");
	#endif
#endif
	usb_init();
	
	unsigned char *buf = usb_get_in_buffer(1);
	memset(buf, 0xa0, EP_1_IN_LEN);

	while (1) {
		if (usb_is_configured() && usb_out_endpoint_has_data(1)) {
			uint8_t len;
			const unsigned char *data;
			/* Data received from host */

			if (!usb_in_endpoint_halted(1)) {
				/* Wait for EP 1 IN to become free then send. This of
				 * course only works using interrupts. */
				while (usb_in_endpoint_busy(1))
					;

				len = usb_get_out_buffer(1, &data);
				memcpy(usb_get_in_buffer(1), data, EP_1_IN_LEN);
				usb_send_in_buffer(1, len);
			}
			usb_arm_out_endpoint(1);
		}

		#ifndef USB_USE_INTERRUPTS
		usb_service();
		#endif
	}

	return 0;
}