/* 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; }
/* 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; }
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)); }
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; }
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 }
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; }
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; }
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; }
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; }
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; }