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 }
void msc_out_transaction_complete(uint8_t endpoint) { struct msc_application_data *msc; const unsigned char *out_buf; uint16_t out_buf_len; #ifdef MSC_WRITE_SUPPORT uint8_t res; #endif msc = get_app_data_by_endpoint(endpoint, 0/*OUT*/); if (!msc) return; /* If the OUT endpoint is halted because of a failed write (from * msc_notify_write_operation_complete(), while interrupts are * disabled), it's possible that a transaction completed before the * endpoint was halted, and that interrupt would cause this * function to be called on a halted endpoint. Since in that case * this is a stray interrupt, there's no need to re-arm the * endpoint. */ if (usb_out_endpoint_halted(endpoint)) return; out_buf_len = usb_get_out_buffer(endpoint, &out_buf); #ifdef MSC_WRITE_SUPPORT if (msc->state == MSC_DATA_TRANSPORT_OUT) { /* In the DATA_TRANSPORT_OUT state, treat this transaction * as data which is to be written to the medium. This call * may fail if the application's buffer is full, in which * case the endpoint will not be re-armed, and the data * will remain in the endpoint buffer until there is space * in the application's buffer. */ res = receive_data(msc, out_buf, out_buf_len); } else if (msc->state == MSC_IDLE) { process_msc_command(msc, out_buf, out_buf_len); res = 0; } else { /* OUT transaction completed when the device is not in a * state that can handle it. Ignore the data. */ res = 0; } /* If the data could not be handled by the application yet (because * the application's buffer is full), don't re-arm the endpoint now. * Keep the received data in the endpoint's buffer until the * application has reset its own buffer (and has signaled such by * calling msc_write_complete()). At that point, the endpoint's * data will be handled and the endpoint re-armed. */ if (res == 0) usb_arm_out_endpoint(endpoint); else msc->out_ep_missed_transactions++; #else /* If read-only, then OUT transactions are always processed * and fully handled, leaving no reason to have missed * transactions, as above. */ if (msc->state == MSC_IDLE) process_msc_command(msc, out_buf, out_buf_len); usb_arm_out_endpoint(endpoint); #endif }
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; }