void ProcessIO(void) { if((USBDeviceState < CONFIGURED_STATE)||(USBSuspendControl==1)) return; /*if(USBGetDeviceState() == DETACHED_STATE) { if(I2CCount > 0) { ProcessCmd(OUTPacket); I2CCount = 0; } } else*/ if(!USBHandleBusy(USBGenericOutHandle)) { //if( OUTPacket[1] != MASTER_ADDRESS ) // I2CRelay(OUTPacket, USBGEN_EP_SIZE); //else ProcessCmd(OUTPacket); USBGenericOutHandle = USBGenRead(USBGEN_EP_NUM, (BYTE*)&OUTPacket, USBGEN_EP_SIZE); } if(WQI != WQX && !USBHandleBusy(USBGenericInHandle)) { USBGenericInHandle = USBGenWrite(USBGEN_EP_NUM, (BYTE*)&INPacket[WQX*USB_RECORD_SIZE], USB_RECORD_SIZE); WQX = (WQX+1) & 3; } } //end ProcessIO
static void processCy7c4xxFifo(void) { unsigned char c; static unsigned char *cy7c4xx_buf_ptr = InDataPacket; static unsigned char len = 0; if (cy7c4xxPull(&c) != 0) return; if (len) { *cy7c4xx_buf_ptr = c; ++cy7c4xx_buf_ptr; --len; if (len == 0) { #if DEBUG if (usbfifo_debug_operation.dump_fifo_out == 1) { unsigned char l = cy7c4xx_buf_ptr-InDataPacket, i; unsigned char b[12]; putrsUSART("FIFO IN: '"); for (i=0;i<l;++i) { if (i != 0) { while (BusyUSART()); putcUSART(' '); } sprintf(b, "%02x", InDataPacket[i]); putsUSART(b); } sprintf(b, "' len=%3d\r\n", l); putsUSART(b); } if (usbfifo_debug_operation.fifo_loopback == 1) { unsigned char l = cy7c4xx_buf_ptr-InDataPacket, i; /* length of incoming packet _must_ not exceed the length of outgoing */ fifo9403aPush(l, 1); for (i=0;i<l;++i) fifo9403aPush(InDataPacket[i], 1); } #endif /* FIXME: use real ping-pong */ while (USBHandleBusy(UsbInDataHandle)); // should not loop, anyway ... UsbInDataHandle = USBGenWrite(USBGEN_DATA_EP_NUM, (BYTE*)&InDataPacket, cy7c4xx_buf_ptr-InDataPacket); while (USBHandleBusy(UsbInDataHandle)); // have to wait here as full ping-pong is not implemented // and thus we don't want data from FIFO override the data being sent here cy7c4xx_buf_ptr = InDataPacket; } } else { len = c; } }
/********************************************************************************** Function: BYTE getsUSBUSART(char *buffer, BYTE len) Summary: getsUSBUSART copies a string of BYTEs received through USB CDC Bulk OUT endpoint to a user's specified location. It is a non-blocking function. It does not wait for data if there is no data available. Instead it returns '0' to notify the caller that there is no data available. Description: getsUSBUSART copies a string of BYTEs received through USB CDC Bulk OUT endpoint to a user's specified location. It is a non-blocking function. It does not wait for data if there is no data available. Instead it returns '0' to notify the caller that there is no data available. Typical Usage: <code> BYTE numBytes; BYTE buffer[64] numBytes = getsUSBUSART(buffer,sizeof(buffer)); //until the buffer is free. if(numBytes \> 0) { //we received numBytes bytes of data and they are copied into // the "buffer" variable. We can do something with the data // here. } </code> Conditions: Value of input argument 'len' should be smaller than the maximum endpoint size responsible for receiving bulk data from USB host for CDC class. Input argument 'buffer' should point to a buffer area that is bigger or equal to the size specified by 'len'. Input: buffer - Pointer to where received BYTEs are to be stored len - The number of BYTEs expected. **********************************************************************************/ BYTE getsUSBUSART(char *buffer, BYTE len) { cdc_rx_len = 0; if(!USBHandleBusy(CDCDataOutHandle)) { /* * Adjust the expected number of BYTEs to equal * the actual number of BYTEs received. */ if(len > USBHandleGetLength(CDCDataOutHandle)) len = USBHandleGetLength(CDCDataOutHandle); /* * Copy data from dual-ram buffer to user's buffer */ for(cdc_rx_len = 0; cdc_rx_len < len; cdc_rx_len++) buffer[cdc_rx_len] = cdc_data_rx[cdc_rx_len]; /* * Prepare dual-ram buffer for next OUT transaction */ CDCDataOutHandle = USBRxOnePacket(CDC_DATA_EP,(BYTE*)&cdc_data_rx,sizeof(cdc_data_rx)); }//end if return cdc_rx_len; }//end getsUSBUSART
void FlashDoTX(void) { BYTE SendNow; USBMaskInterrupts(); if (!USBHandleBusy(FlashDataInHandle)) { switch (FlashTxState) { case FLASH_TX_COMPLETING: FlashTxState = FLASH_TX_READY; break; case FLASH_TX_BUSY: SendNow = FlashTxLen > sizeof(FlashTxBuffer) ? sizeof(FlashTxBuffer) : FlashTxLen; FlashTxCBF((BYTE *) &FlashTxBuffer, SendNow); FlashTxLen -= SendNow; if(FlashTxLen == 0) FlashTxState = FLASH_TX_COMPLETING; FlashDataInHandle = USBTxOnePacket(NAND_TX_EP,(BYTE*)&FlashTxBuffer, SendNow); break; } } USBUnmaskInterrupts(); }
void CDCNotificationHandler(void) { //Check the DTS I/O pin and if a state change is detected, notify the //USB host by sending a serial state notification element packet. if(UART_DTS == USB_CDC_DSR_ACTIVE_LEVEL) //UART_DTS must be defined to be an I/O pin in the hardware profile to use the DTS feature (ex: "PORTXbits.RXY") { SerialStateBitmap.bits.DSR = 1; } else { SerialStateBitmap.bits.DSR = 0; } //If the state has changed, and the endpoint is available, send a packet to //notify the hUSB host of the change. if((SerialStateBitmap.byte != OldSerialStateBitmap.byte) && (!USBHandleBusy(CDCNotificationInHandle))) { //Copy the updated value into the USB packet buffer to send. SerialStatePacket.SerialState.byte = SerialStateBitmap.byte; //We don't need to write to the other bytes in the SerialStatePacket USB //buffer, since they don't change and will always be the same as our //initialized value. //Send the packet over USB to the host. CDCNotificationInHandle = USBTransferOnePacket(CDC_COMM_EP, IN_TO_HOST, (BYTE*)&SerialStatePacket, sizeof(SERIAL_STATE_NOTIFICATION)); //Save the old value, so we can detect changes later. OldSerialStateBitmap.byte = SerialStateBitmap.byte; } }//void CDCNotificationHandler(void)
/******************************************************************** * モニタコマンド受信と実行. ******************************************************************** */ void ProcessIO(void) { // 返答パケットが空であること、かつ、 // 処理対象の受信データがある. if((ToPcRdy == 0) && (USBHandleBusy(USBGenericOutHandle)==0) ) { //受信データがあれば、受信データを受け取る. memcpy64((char*)&PacketFromPC,(char*)OUTPacket); //次の読み込みを発行する. USBGenericOutHandle = USBGenRead(USBGEN_EP_NUM,(BYTE*)&OUTPacket ,USBGEN_EP_SIZE); PacketToPC.raw[0]=Cmd0; // CMD ECHOBACK //コマンドに対応する処理を呼び出す. if(Cmd0==HIDASP_PEEK) {cmd_peek();} // メモリー読み出し. else if(Cmd0==HIDASP_POKE) {cmd_poke();} // メモリー書き込み. else if(Cmd0==HIDASP_JMP) {cmd_exec();} // 実行. else if(Cmd0==HIDASP_TEST) {cmd_echo();} // 接続テスト. else if(Cmd0==HIDASP_GET_STRING){cmd_get_string();} else if(Cmd0==HIDASP_USER_CMD) {cmd_user_cmd();} else if(Cmd0==HIDASP_SET_MODE) {cmd_set_mode();} } // 必要なら、返答パケットをバルク転送(EP1)でホストPCに返却する. if( ToPcRdy ) { if(!USBHandleBusy(USBGenericInHandle)) { memcpy64(INPacket,(char*)&PacketToPC); USBGenericInHandle=USBGenWrite(USBGEN_EP_NUM,(BYTE*)INPacket,USBGEN_EP_SIZE); ToPcRdy = 0; if(poll_mode!=0) { if( USBHandleBusy(USBGenericOutHandle) ) {//コマンドが来ない限り送り続ける. make_report(); } } } } }
/************************************************** * SWARMS Input PRECESSING * * * ****************************************************/ void ProcessSWARMSInput(void){ char commandSuccess; char SWARMSCommandID; if((USBDeviceState < CONFIGURED_STATE)||(USBSuspendControl==1)) return; // this is where I should insert the code for specific control if(!USBHandleBusy(USBGenericOutHandle)) //Check if the endpoint has received any data from the host. { if(! canfitCommandInOutputCommandBuffer(5)){ //can't ensure reply -- just drop frame USBGenericOutHandle = USBGenRead(USBGEN_EP_NUM,(BYTE*)&OUTPacket,USBGEN_EP_SIZE); mLED_2_On(); mLED_1_Off() return; } SWARMSCommandID = OUTPacket[0]; if(IS_VALID_COMMAND){ commandSuccess = writeInputCommand(OUTPacket); switch(commandSuccess){ case fifoBufferStatusGood: //report success break; case fifoBufferStatusFull: //abort buffer full // mLED_2_Toggle(); SWARMSMakeCommandSuccess(SWARMSCommandID, FAILURE, NULL); //TODO: ADD FLAGS break; case fifoBufferStatusBadInputOversize: //abort buffer oversize input SWARMSMakeCommandSuccess(SWARMSCommandID, FAILURE, NULL); //TODO: ADD FLAGS break; case fifoBufferStatusBadInput: default: //notify bad command SWARMSMakeCommandSuccess(SWARMSCommandID, FAILURE, NULL); //TODO: ADD FLAGS break; } }else{ SWARMSMakeCommandSuccess(SWARMSCommandID, FAILURE, NULL); //TODO: ADD FLAGS } USBGenericOutHandle = USBGenRead(USBGEN_EP_NUM,(BYTE*)&OUTPacket,USBGEN_EP_SIZE); }
void FlashDataWrite() { BYTE *pData = (BYTE *) &FlashRxBuffer; BYTE len; if (gCommandProgress==0) { gGlobalStatus = XNANDErase(gCmdArgA << 5); gNextBlock = gCmdArgA << 5; gWordsLeft = 0x84; gBytesWritten = 0; XNANDWriteStart(); gCommandProgress = 1; } if (USBHandleBusy(FlashDataOutHandle)) return; len = USBHandleGetLength(FlashDataOutHandle); len/= 4; while (len) { BYTE writeNow = len > gWordsLeft?gWordsLeft:len; XNANDWriteProcess(pData, writeNow); pData += writeNow*4; len -= writeNow; gWordsLeft -= writeNow; if (gWordsLeft == 0) { gGlobalStatus |= XNANDWriteExecute(gNextBlock); gNextBlock++; gWordsLeft = 0x84; XNANDWriteStart(); gBytesWritten += 0x210; } } FlashDataOutHandle = USBRxOnePacket(NAND_RX_EP,(BYTE*)&FlashRxBuffer,sizeof(FlashRxBuffer)); if (gBytesWritten == gCmdArgB) gCurrentCommand = 0xFF; }
//------------------------------PMP Handler------------------------------------- void __ISR(_EXTERNAL_0_VECTOR, IPL6) GetSlaveData(void){ unsigned char pitch, vel; PMPMasterRead(); pitch = mPMPMasterReadByte(); vel = mPMPMasterReadByte(); if(!USBHandleBusy(USBTxHandle)) { midiData.Val = 0; //must set all unused values to 0 midiData.CableNumber = 0; midiData.CodeIndexNumber = MIDI_CIN_NOTE_ON; midiData.DATA_0 = 0x90; //Note on midiData.DATA_1 = pitch + 60; //pitch midiData.DATA_2 = vel; //velocity USBTxHandle = USBTxOnePacket(MIDI_EP,(BYTE*)&midiData,4); } mINT0ClearIntFlag(); }
/****************************************************************************** Function: void MSDProcessCommandMediaPresent(void) Description: This funtion processes a command received through the MSD class driver PreCondition: None Paramters: None Return Values: BYTE - the current state of the MSDProcessCommand state machine. The valid values are defined in MSD.h under the MSDProcessCommand state machine declaration section Remarks: None *****************************************************************************/ void MSDProcessCommandMediaPresent(void) { BYTE i; switch(MSDCommandState) { case MSD_COMMAND_WAIT: //copy the received command to the command state machine MSDCommandState = gblCBW.CBWCB[0]; break; case MSD_INQUIRY: { //copy the inquiry results from the defined ROM buffer // into the USB buffer so that it can be transmitted memcpypgm2ram( (void *)&msd_buffer[0], (ROM void*)&inq_resp, sizeof(InquiryResponse) ); msd_csw.dCSWDataResidue=sizeof(InquiryResponse); msd_csw.bCSWStatus=0x00; // success MSDCommandState = MSD_COMMAND_RESPONSE; break; } case MSD_READ_CAPACITY: { //If the host asked for the capacity of the device DWORD_VAL sectorSize; DWORD_VAL capacity; msd_csw.bCSWStatus=0x00; // success //get the information from the physical media capacity.Val = LUNReadCapacity(); sectorSize.Val = LUNReadSectorSize(); //copy the data to the buffer msd_buffer[0]=capacity.v[3]; msd_buffer[1]=capacity.v[2]; msd_buffer[2]=capacity.v[1]; msd_buffer[3]=capacity.v[0]; msd_buffer[4]=sectorSize.v[3]; msd_buffer[5]=sectorSize.v[2]; msd_buffer[6]=sectorSize.v[1]; msd_buffer[7]=sectorSize.v[0]; msd_csw.dCSWDataResidue=0x08; // size of response MSDCommandState = MSD_COMMAND_RESPONSE; break; } case MSD_READ_10: if(MSDReadHandler() == MSD_READ10_WAIT) { MSDCommandState = MSD_COMMAND_WAIT; } break; case MSD_WRITE_10: if(MSDWriteHandler() == MSD_WRITE10_WAIT) { MSDCommandState = MSD_COMMAND_WAIT; } break; case MSD_REQUEST_SENSE: for(i=0;i<sizeof(RequestSenseResponse);i++) { msd_buffer[i]=gblSenseData[LUN_INDEX]._byte[i]; } msd_csw.dCSWDataResidue=sizeof(RequestSenseResponse); msd_csw.bCSWStatus=0x0; // success MSDCommandState = MSD_COMMAND_RESPONSE; break; case MSD_MODE_SENSE: msd_buffer[0]=0x02; msd_buffer[1]=0x00; msd_buffer[2]=0x00; msd_buffer[3]=0x00; msd_csw.bCSWStatus=0x0; msd_csw.dCSWDataResidue=0x04; MSDCommandState = MSD_COMMAND_RESPONSE; break; case MSD_PREVENT_ALLOW_MEDIUM_REMOVAL: if(LUNMediaDetect()) { msd_csw.bCSWStatus=0x00; msd_csw.dCSWDataResidue=0x00; } else { gblSenseData[LUN_INDEX].SenseKey=S_NOT_READY; gblSenseData[LUN_INDEX].ASC=ASC_MEDIUM_NOT_PRESENT; gblSenseData[LUN_INDEX].ASCQ=ASCQ_MEDIUM_NOT_PRESENT; msd_csw.bCSWStatus=0x01; } MSDCommandState = MSD_COMMAND_WAIT; break; case MSD_TEST_UNIT_READY: if((gblSenseData[LUN_INDEX].SenseKey==S_UNIT_ATTENTION) && (msd_csw.bCSWStatus==1)) { MSDCommandState = MSD_COMMAND_WAIT; } else { ResetSenseData(); msd_csw.dCSWDataResidue=0x00; MSDCommandState = MSD_COMMAND_WAIT; } break; case MSD_VERIFY: //Fall through to STOP_START case MSD_STOP_START: msd_csw.bCSWStatus=0x0; msd_csw.dCSWDataResidue=0x00; MSDCommandState = MSD_COMMAND_WAIT; break; case MSD_COMMAND_RESPONSE: if(USBHandleBusy(USBMSDInHandle) == FALSE) { USBMSDInHandle = USBTxOnePacket(MSD_DATA_IN_EP,(BYTE*)&msd_buffer[0],msd_csw.dCSWDataResidue); MSDCommandState = MSD_COMMAND_WAIT; msd_csw.dCSWDataResidue=0; } break; case MSD_COMMAND_ERROR: default: ResetSenseData(); gblSenseData[LUN_INDEX].SenseKey=S_ILLEGAL_REQUEST; gblSenseData[LUN_INDEX].ASC=ASC_INVALID_COMMAND_OPCODE; gblSenseData[LUN_INDEX].ASCQ=ASCQ_INVALID_COMMAND_OPCODE; msd_csw.bCSWStatus=0x01; msd_csw.dCSWDataResidue=0x00; MSDCommandState = MSD_COMMAND_RESPONSE; break; } // end switch }
/****************************************************************************** Function: void MSDProcessCommandMediaAbsent(void) Description: This funtion processes a command received through the MSD class driver PreCondition: None Parameters: None Return Values: BYTE - the current state of the MSDProcessCommand state machine. The valid values are defined in MSD.h under the MSDProcessCommand state machine declaration section Remarks: None *****************************************************************************/ void MSDProcessCommandMediaAbsent(void) { BYTE i; switch(MSDCommandState) { case MSD_REQUEST_SENSE: { ResetSenseData(); gblSenseData[LUN_INDEX].SenseKey=S_NOT_READY; gblSenseData[LUN_INDEX].ASC=ASC_MEDIUM_NOT_PRESENT; gblSenseData[LUN_INDEX].ASCQ=ASCQ_MEDIUM_NOT_PRESENT; for(i=0;i<sizeof(RequestSenseResponse);i++) { msd_buffer[i]=gblSenseData[LUN_INDEX]._byte[i]; } msd_csw.dCSWDataResidue=sizeof(RequestSenseResponse); msd_csw.bCSWStatus=0x0; // success MSDCommandState = MSD_COMMAND_RESPONSE; break; } case MSD_PREVENT_ALLOW_MEDIUM_REMOVAL: case MSD_TEST_UNIT_READY: { msd_csw.bCSWStatus=0x01; MSDCommandState = MSD_COMMAND_WAIT; break; } case MSD_INQUIRY: { memcpypgm2ram( (void *)&msd_buffer[0], (ROM void*)&inq_resp, sizeof(InquiryResponse) ); msd_csw.dCSWDataResidue=sizeof(InquiryResponse); msd_csw.bCSWStatus=0x00; // success MSDCommandState = MSD_COMMAND_RESPONSE; break; } case MSD_COMMAND_WAIT: { MSDCommandState = gblCBW.CBWCB[0]; break; } case MSD_COMMAND_RESPONSE: if(USBHandleBusy(USBMSDInHandle) == FALSE) { USBMSDInHandle = USBTxOnePacket(MSD_DATA_IN_EP,(BYTE*)&msd_buffer[0],msd_csw.dCSWDataResidue); MSDCommandState = MSD_COMMAND_WAIT; msd_csw.dCSWDataResidue=0; } break; default: { //Stall MSD endpoint IN USBStallEndpoint(MSD_DATA_IN_EP,1); msd_csw.bCSWStatus=0x01; MSDCommandState = MSD_COMMAND_WAIT; break; } } }
BOOL ChipKITUSBHandleBusy(USB_HANDLE handle) { return(USBHandleBusy(handle)); }
/********************************************************************************* Function: BYTE MSDTasks(void) Summary: This function runs the MSD class state machines and all of its sub-systems. This function should be called periodically once the device is in the configured state in order to keep the MSD state machine going. Description: This function runs the MSD class state machines and all of its sub-systems. This function should be called periodically once the device is in the configured state in order to keep the MSD state machine going. Typical Usage: <code> void main(void) { USBDeviceInit(); while(1) { USBDeviceTasks(); if((USBGetDeviceState() \< CONFIGURED_STATE) || (USBIsDeviceSuspended() == TRUE)) { //Either the device is not configured or we are suspended // so we don't want to do execute any application code continue; //go back to the top of the while loop } else { //Keep the MSD state machine going MSDTasks(); //Run application code. UserApplication(); } } } </code> Conditions: None Return Values: BYTE - the current state of the MSD state machine the valid values are defined in MSD.h under the MSDTasks state machine declaration section. The possible values are the following\: * MSD_WAIT * MSD_DATA_IN * MSD_DATA_OUT * MSD_SEND_CSW Remarks: None *********************************************************************************/ BYTE MSDTasks(void) { BYTE i; switch(MSD_State) { case MSD_WAIT: { //If the MSD state machine is waiting for something to happen if(!USBHandleBusy(USBMSDOutHandle)) { //If we received an OUT packet from the host // then copy the data from the buffer to a global // buffer so that we can keep the information but // reuse the buffer gblCBW.dCBWSignature=msd_cbw.dCBWSignature; gblCBW.dCBWTag=msd_cbw.dCBWTag; gblCBW.dCBWDataTransferLength=msd_cbw.dCBWDataTransferLength; gblCBW.bCBWFlags=msd_cbw.bCBWFlags; gblCBW.bCBWLUN=msd_cbw.bCBWLUN; gblCBW.bCBWCBLength=msd_cbw.bCBWCBLength; // 3 MSB are zero for (i=0;i<msd_cbw.bCBWCBLength;i++) { gblCBW.CBWCB[i]=msd_cbw.CBWCB[i]; } gblCBWLength=USBHandleGetLength(USBMSDOutHandle); //If this CBW is valid? if ((gblCBWLength==MSD_CBW_SIZE)&&(gblCBW.dCBWSignature==0x43425355)) { //Is this CBW meaningful? if((gblCBW.bCBWLUN<=0x0f) &&(gblCBW.bCBWCBLength<=0x10) &&(gblCBW.bCBWCBLength>=0x01) &&(gblCBW.bCBWFlags==0x00||gblCBW.bCBWFlags==0x80)) { //Prepare the CSW to be sent msd_csw.dCSWTag=gblCBW.dCBWTag; msd_csw.dCSWSignature=0x53425355; /* If direction is device to host*/ if (gblCBW.bCBWFlags==0x80) { MSD_State=MSD_DATA_IN; } else if (gblCBW.bCBWFlags==0x00) { /* If direction is host to device*/ /* prepare to read data in msd_buffer */ MSD_State=MSD_DATA_OUT; } } } } break; } case MSD_DATA_IN: if(MSDProcessCommand() == MSD_COMMAND_WAIT) { // Done processing the command, send the status MSD_State = MSD_SEND_CSW; } break; case MSD_DATA_OUT: if(MSDProcessCommand() == MSD_COMMAND_WAIT) { /* Finished receiving the data prepare and send the status */ if ((msd_csw.bCSWStatus==0x00)&&(msd_csw.dCSWDataResidue!=0)) { msd_csw.bCSWStatus=0x02; } MSD_State = MSD_SEND_CSW; } break; case MSD_SEND_CSW: if(USBHandleBusy(USBMSDInHandle)) { //The TX buffer is not ready to send the status yet. break; } USBMSDInHandle = USBTxOnePacket(MSD_DATA_IN_EP,(BYTE*)&msd_csw,MSD_CSW_SIZE); //Get ready for next command to come in if(!USBHandleBusy(USBMSDOutHandle)) { USBMSDOutHandle = USBRxOnePacket(MSD_DATA_OUT_EP,(BYTE*)&msd_cbw,sizeof(msd_cbw)); } MSD_State=MSD_WAIT; break; } return MSD_State; }
BOOL hidHandleBusy(void) { return USBHandleBusy(hidRxHandle); }
void ProcessCCID() { static WORD CardPresentVerifyCounter = 0; static BOOL CardON = FALSE; BYTE i; BYTE ppsData[3]; ////// Detect Card Insertion and removal and transmit ///////////// ////// the status on interrupt endpoint ///////////// if( !CardON && SC_CardPresent() ) { if( CardPresentVerifyCounter > 100 ) { if(!USBHandleBusy(usbCcidInterruptInHandle)) { usbCcidBulkInEndpoint[0] = 0x50; //Msg Type usbCcidBulkInEndpoint[1] = 3; //card present, change usbCcidInterruptInHandle = USBTxOnePacket(USB_EP_INT_IN, (BYTE*)&usbCcidBulkInEndpoint, 2); CardON = TRUE; } } else CardPresentVerifyCounter++; } else if( CardON && !SC_CardPresent() ) { SC_Shutdown(); //reset SC_Lib states and turn off hardware if(!USBHandleBusy(usbCcidInterruptInHandle)) { usbCcidBulkInEndpoint[0] = 0x50; //Msg Type usbCcidBulkInEndpoint[1] = 2; //card not present, change usbCcidInterruptInHandle = USBTxOnePacket(USB_EP_INT_IN, (BYTE*)&usbCcidBulkInEndpoint, 2); CardON = FALSE; } } else CardPresentVerifyCounter = 0; ///// Process commands received on Bulk Endoint ////////////// if(!USBHandleBusy(usbCcidBulkOutHandle)) //Check if the endpoint has received any data from the host. { union SLOT_STATUS card_st; BYTE ErrCode; static WORD TransactionCount=0; card_st.Val = 0; ErrCode = 0; //clear error code if(usbCcidOutPacketTrack == USB_CCID_BULK_OUT_FIRST_PACKET) { memset( pUsbCcidApdu->CCID_BulkOutBuffer, 0, sizeof(pUsbCcidApdu->CCID_BulkOutBuffer)) ; // copy the length from the CCID packet to a 32 Bit Variable. usbCcidOutPacketLength.byte.LB = usbCcidBulkOutEndpoint[1]; usbCcidOutPacketLength.byte.HB = usbCcidBulkOutEndpoint[2]; usbCcidOutPacketLength.byte.UB = usbCcidBulkOutEndpoint[3]; usbCcidOutPacketLength.byte.MB = usbCcidBulkOutEndpoint[4]; usbCcidNoOfBytesToReceive = usbCcidOutPacketLength.Val + 10; // CCID command overhead is 10 bytes. for (i =0;i < USB_EP_SIZE;i++) // Copy received data from host to a temperary buffer pUsbCcidApdu->CCID_BulkOutBuffer[i] = usbCcidBulkOutEndpoint[i]; if (usbCcidNoOfBytesToReceive > USB_EP_SIZE) // We still have more USB transactions to receive from host { usbCcidNoOfBytesToReceive = usbCcidNoOfBytesToReceive - USB_EP_SIZE; usbCcidOutPacketTrack = USB_CCID_BULK_OUT_SUBSEQUENT_PACKET; usbCcidBulkOutHandle = USBRxOnePacket(USB_EP_BULK_OUT,(BYTE*)&usbCcidBulkOutEndpoint,USB_EP_SIZE); return; } else // We have received everything from the host. { usbCcidNoOfBytesToReceive = 0; usbCcidOutPacketTrack = USB_CCID_BULK_OUT_FIRST_PACKET; TransactionCount =0; } } else if (usbCcidOutPacketTrack == USB_CCID_BULK_OUT_SUBSEQUENT_PACKET) { // copy data to the APDU[]; TransactionCount++; if (usbCcidNoOfBytesToReceive > USB_EP_SIZE) { for (i =0 ; i< USB_EP_SIZE; i++ ) pUsbCcidApdu->CCID_BulkOutBuffer[USB_EP_SIZE * TransactionCount + i] = usbCcidBulkOutEndpoint[i]; } else { for (i =0 ; i< usbCcidNoOfBytesToReceive; i++ ) pUsbCcidApdu->CCID_BulkOutBuffer[USB_EP_SIZE*TransactionCount+i] = usbCcidBulkOutEndpoint[i]; } if (usbCcidNoOfBytesToReceive > USB_EP_SIZE) // We still have more bytes to receive from host { usbCcidNoOfBytesToReceive = usbCcidNoOfBytesToReceive - USB_EP_SIZE; usbCcidOutPacketTrack = USB_CCID_BULK_OUT_SUBSEQUENT_PACKET; usbCcidBulkOutHandle = USBRxOnePacket(USB_EP_BULK_OUT,(BYTE*)&usbCcidBulkOutEndpoint,USB_EP_SIZE); return; } else // We have received everything from the host. { usbCcidNoOfBytesToReceive = 0; TransactionCount =0; usbCcidOutPacketTrack = USB_CCID_BULK_OUT_FIRST_PACKET; } } switch(pUsbCcidApdu->CCID_BulkOutBuffer[0]) //Data arrived, check what kind of command might be in the packet of data. { //////////////////////////////////////////////////////////////////////////////////// case USB_CCID_PC_TO_RDR_ICC_POWER_ON: { if( !SC_CardPresent() ) //if Card is not present { //Card not present. send error reply card_st.Val = 0; card_st.ICC_Status = GetCardStatus(); card_st.CmdStatus = 1; //Command Failed Code pUsbCcidApdu->CCID_BulkInBuffer[0] = USB_CCID_RDR_TO_PC_DATA_BLOCK; //Msg Type pUsbCcidApdu->CCID_BulkInBuffer[7] = card_st.Val; //bStatus pUsbCcidApdu->CCID_BulkInBuffer[8] = USB_CCID_ICC_MUTE; //bError ICC_MUTE pUsbCcidApdu->CCID_BulkInBuffer[9] = 0; USBCCIDSendDataToHost(pUsbCcidApdu->CCID_BulkInBuffer, 10 ); } else //else if Card is Present { SC_Initialize(); if( SC_PowerOnATR() ) //Get ATR { // SC_DoPPS(); //switch baud rate based on ATR setting if (SC_T0ProtocolType() && !SC_T1ProtocolType()) usbCcidProtocolNum = USB_CCID_T0_PROTOCOL; else if (!SC_T0ProtocolType() && SC_T1ProtocolType()) usbCcidProtocolNum = USB_CCID_T1_PROTOCOL; card_st.Val = 0; card_st.ICC_Status = GetCardStatus(); card_st.CmdStatus = 0; //processed without error // ATR success pUsbCcidApdu->CCID_BulkInBuffer[0] = USB_CCID_RDR_TO_PC_DATA_BLOCK; //Msg Type pUsbCcidApdu->CCID_BulkInBuffer[1] = scATRLength; pUsbCcidApdu->CCID_BulkInBuffer[2] = 0; pUsbCcidApdu->CCID_BulkInBuffer[3] = usbCcidBulkInEndpoint[4] = 0; pUsbCcidApdu->CCID_BulkInBuffer[7] = card_st.Val; //bStatus pUsbCcidApdu->CCID_BulkInBuffer[8] = 0; //bError pUsbCcidApdu->CCID_BulkInBuffer[9] = 0; //no extended APDU support for (i = 0; i < scATRLength; i++) pUsbCcidApdu->CCID_BulkInBuffer[10 + i] = scCardATR[i]; USBCCIDSendDataToHost(pUsbCcidApdu->CCID_BulkInBuffer, scATRLength+10 ); } else // ATR Failed { // Reply with Error response card_st.ICC_Status = 1; // from CCID Rev 1.1 page 28. Error codes for Hardware Error card_st.CmdStatus = 1; // Command Failed ErrCode = USB_CCID_HW_ERROR; // Hardware Error pUsbCcidApdu->CCID_BulkInBuffer[0] = USB_CCID_RDR_TO_PC_DATA_BLOCK; //Msg Type pUsbCcidApdu->CCID_BulkInBuffer[7] = card_st.Val; //bStatus pUsbCcidApdu->CCID_BulkInBuffer[8] = ErrCode; //bError pUsbCcidApdu->CCID_BulkInBuffer[9] = 0; USBCCIDSendDataToHost(pUsbCcidApdu->CCID_BulkInBuffer, 10 ); }// End of else ATR Failed }// End of else - card is present }// End case PC_to_RDR_IccPowerOn: break; //////////////////////////////////////////////////////////////////////////////////// case USB_CCID_PC_TO_RDR_ICC_POWER_OFF: if( pUsbCcidApdu->CCID_BulkOutBuffer[5] == 0 ) // must be slot 0 (for 1 slot reader) { //Do power off sequence if required SC_Shutdown(); card_st.ICC_Status = GetCardStatus(); // bStatus - 0 Card Present and active, // 1 Card Present and inactive, // 2 Not Present } else //slot # out of range { card_st.ICC_Status = 2; // from CCID Rev 1.1 page 28. Error codes for bad slot umber card_st.CmdStatus = 1; // Command Failed ErrCode = 5; // bError Slot Does not exist } pUsbCcidApdu->CCID_BulkInBuffer[0] = 0x81; //Msg Type pUsbCcidApdu->CCID_BulkInBuffer[7] = card_st.Val; //bStatus pUsbCcidApdu->CCID_BulkInBuffer[8] = ErrCode; //bError pUsbCcidApdu->CCID_BulkInBuffer[9] = (SC_GetCardState()==SC_STATE_CARD_ACTIVE)?0:1; //Clock Status: 0 Running, 1 Stopped L, 2 Stopped H USBCCIDSendDataToHost(pUsbCcidApdu->CCID_BulkInBuffer, 10 ); break; //////////////////////////////////////////////////////////////////////////////////// case USB_CCID_PC_TO_RDR_GET_SLOT_STATUS: if( pUsbCcidApdu->CCID_BulkOutBuffer[5] == 0 ) // must be slot 0 (for 1 slot reader) { card_st.ICC_Status = GetCardStatus(); // bStatus - 0 Card Present and active, // 1 Card Present and inactive, // 2 Not Present } else //slot # out of range { card_st.ICC_Status = 2; // from CCID Rev 1.1 page 28. Error codes for bad slot umber card_st.CmdStatus = 1; // Command Failed ErrCode = 5; // bError Slot Does not exist } pUsbCcidApdu->CCID_BulkInBuffer[0] = USB_CCID_RDR_TO_PC_SLOT_STATUS; //Msg Type pUsbCcidApdu->CCID_BulkInBuffer[7] = card_st.Val; //bStatus pUsbCcidApdu->CCID_BulkInBuffer[8] = ErrCode; //bError pUsbCcidApdu->CCID_BulkInBuffer[9] = (SC_GetCardState()==SC_STATE_CARD_ACTIVE)?0:1; //Clock Status: 0 Running, 1 Stopped L, 2 Stopped H USBCCIDSendDataToHost(pUsbCcidApdu->CCID_BulkInBuffer, 10 ); break; //////////////////////////////////////////////////////////////////////////////////// case USB_CCID_PC_TO_RDR_XFR_BLOCK: UsbCcidPcToRdrXfrBlock(); break; //////////////////////////////////////////////////////////////////////////////////// case USB_CCID_PC_TO_RDR_GET_PARAMETERS: UsbCcidSendRdrToPcParameters(); break; //////////////////////////////////////////////////////////////////////////////////// case USB_CCID_PC_TO_RDR_RESET_PARAMETERS : UsbCcidSendRdrToPcParameters(); break; //////////////////////////////////////////////////////////////////////////////////// case USB_CCID_PC_TO_RDR_SET_PARAMETERS : if (SC_GetCardState() == SC_STATE_CARD_ACTIVE) { if (SC_T0ProtocolType() && SC_T1ProtocolType()) { usbCcidProtocolNum = pUsbCcidApdu->CCID_BulkOutBuffer[7]; } ppsData[0] = 0xFF; if (usbCcidProtocolNum == USB_CCID_T0_PROTOCOL) //if T=0 Protocol { //pUsbCcidApdu->CCID_BulkOutBuffer[10]; //Read FI Index //pUsbCcidApdu->CCID_BulkOutBuffer[11]; //bmTCCKST0 //pUsbCcidApdu->CCID_BulkOutBuffer[12]; // Read Guard Time //pUsbCcidApdu->CCID_BulkOutBuffer[13]; // Read WI ppsData[1] = 0x00; } else if (usbCcidProtocolNum == USB_CCID_T1_PROTOCOL) { ppsData[1] = 0x01; //pUsbCcidApdu->CCID_BulkOutBuffer[10]; //Read FI Index //pUsbCcidApdu->CCID_BulkOutBuffer[11]; //bmTCCKST1 //pUsbCcidApdu->CCID_BulkOutBuffer[12]; // Guard Time //pUsbCcidApdu->CCID_BulkOutBuffer[13]; // bmWaitingIntegersT1 //pUsbCcidApdu->CCID_BulkOutBuffer[14]; // bClockStop //pUsbCcidApdu->CCID_BulkOutBuffer[15]; //bIFSC //pUsbCcidApdu->CCID_BulkOutBuffer[16]; //bNadValue } ppsData[2] = ppsData[0] ^ ppsData[1]; if (SC_T0ProtocolType() && SC_T1ProtocolType()) { if (!SC_DoPPS(ppsData)) { SC_Shutdown(); } } ccid_clockstatus = pUsbCcidApdu->CCID_BulkOutBuffer[14]; // Read Clock Stop Status } UsbCcidSendRdrToPcParameters(); break; #ifndef LOW_PIN_COUNT_USB_DEVELOPMENT_KIT //////////////////////////////////////////////////////////////////////////////////// case USB_CCID_PC_TO_RDR_ESCAPE: // This Command is not supoprted pUsbCcidApdu->CCID_BulkInBuffer[0] = USB_CCID_RDR_TO_PC_ESCAPE; UsbCcidCommandNotSupported(); break; #endif //////////////////////////////////////////////////////////////////////////////////// case USB_CCID_PC_TO_RDR_ICC_CLOCK: if( pUsbCcidApdu->CCID_BulkOutBuffer[5] == 0 ) // must be slot 0 (for 1 slot reader) { //Do power off sequence if required if (pUsbCcidApdu->CCID_BulkOutBuffer[7] == 0) { USB_CCID_RestartClock();//Restart Clock } else if (pUsbCcidApdu->CCID_BulkOutBuffer[7] == 1) { if (ccid_clockstatus == 1) { USB_CCID_StopClockWithPinLow(); // Stop with Clock signal Low } else if (ccid_clockstatus == 2) { USB_CCID_StopClockWithPinHigh();// Stop with Clock signal High } else if (ccid_clockstatus == 3) { USB_CCID_StopClockWithPinLow(); // Stop with Clock either High or Low } } card_st.ICC_Status = GetCardStatus(); // bStatus - 0 Card Present and active, // 1 Card Present and inactive, // 2 Not Present } else //slot # out of range { card_st.ICC_Status = 2; // from CCID Rev 1.1 page 28. Error codes for bad slot umber card_st.CmdStatus = 1; // Command Failed ErrCode = 5; // bError Slot Does not exist } pUsbCcidApdu->CCID_BulkInBuffer[0] = USB_CCID_RDR_TO_PC_SLOT_STATUS; //Msg Type pUsbCcidApdu->CCID_BulkInBuffer[7] = card_st.Val; //bStatus pUsbCcidApdu->CCID_BulkInBuffer[8] = ErrCode; //bError pUsbCcidApdu->CCID_BulkInBuffer[9] = (SC_GetCardState()==SC_STATE_CARD_ACTIVE)?0:1; //Clock Status: 0 Running, 1 Stopped L, 2 Stopped H USBCCIDSendDataToHost(pUsbCcidApdu->CCID_BulkInBuffer, 10 ); break; //////////////////////////////////////////////////////////////////////////////////// #ifndef LOW_PIN_COUNT_USB_DEVELOPMENT_KIT case USB_CCID_PC_TO_RDR_SECURE : // This Command is not supoprted pUsbCcidApdu->CCID_BulkInBuffer[0] = USB_CCID_RDR_TO_PC_DATA_BLOCK; UsbCcidCommandNotSupported(); break; //////////////////////////////////////////////////////////////////////////////////// case USB_CCID_PC_TO_RDR_MECHANICAL: // This Command is not supoprted pUsbCcidApdu->CCID_BulkInBuffer[0] = USB_CCID_RDR_TO_PC_SLOT_STATUS; UsbCcidCommandNotSupported(); //////////////////////////////////////////////////////////////////////////////////// case USB_CCID_PC_TO_RDR_ABORT: // This Command is not supoprted pUsbCcidApdu->CCID_BulkInBuffer[0] = USB_CCID_RDR_TO_PC_SLOT_STATUS; UsbCcidCommandNotSupported(); //////////////////////////////////////////////////////////////////////////////////// case USB_CCID_PC_TO_RDR_SET_DATA_RATE_AND_CLOCK_FREQUENCY: // This Command is not supoprted pUsbCcidApdu->CCID_BulkInBuffer[0] = USB_CCID_RDR_TO_PC_DATA_RATE_AND_CLOCK_FREQUENCY; UsbCcidCommandNotSupported(); //////////////////////////////////////////////////////////////////////////////////// case USB_CCID_PC_TO_RDR_T0APDU : // This Command is not supoprted pUsbCcidApdu->CCID_BulkInBuffer[0] = USB_CCID_RDR_TO_PC_SLOT_STATUS; UsbCcidCommandNotSupported(); break; #endif default: pUsbCcidApdu->CCID_BulkInBuffer[0] = USB_CCID_RDR_TO_PC_SLOT_STATUS; #ifndef LOW_PIN_COUNT_USB_DEVELOPMENT_KIT UsbCcidCommandNotSupported(); #else card_st.Val = 0; card_st.ICC_Status = GetCardStatus(); card_st.CmdStatus = 1; //Command Failed Code pUsbCcidApdu->CCID_BulkInBuffer[7] = card_st.Val; //bStatus pUsbCcidApdu->CCID_BulkInBuffer[8] = USB_CCID_CMD_NOT_SUPPORTED; //bError, Command not supported USBCCIDSendDataToHost(pUsbCcidApdu->CCID_BulkInBuffer, 10 ); #endif break; } usbCcidBulkOutHandle = USBRxOnePacket(USB_EP_BULK_OUT,(BYTE*)&usbCcidBulkOutEndpoint,USB_EP_SIZE); } }
/********************************************************************* * Function: void APP_DeviceVendorThroughputTestTasks(void); * * Overview: keeps the demo running. * * PreCondition: Demo is initialiized. * * Input: None * * Output: None * ********************************************************************/ void APP_DeviceVendorThroughputTestTasks() { //User Application USB tasks below. //Note: The user application should not begin attempting to read/write over the USB //until after the device has been fully enumerated. After the device is fully //enumerated, the USBDeviceState will be set to "CONFIGURED_STATE". if((USBDeviceState < CONFIGURED_STATE)||(USBSuspendControl==1)) return; //All currently existing Microchip USB microcontroller use a dedicated Direct //Memory Access (DMA) interface allowing the USB module to directly read or //write USB packets into or out of microcontroller SRAM. To receive an "OUT" //packet from the host (in USB terminology, OUT and IN are always from the host's //perspective), the microcontroller firmware needs to "arm" the Buffer //Descriptor Table (BDT) for the endpoint that the data will be received on. //The BDT entry is a small set of special function registers (SFRs) that //control the operation of the DMA transaction (number of bytes to receive, //pointer to where in SRAM the data should be placed, etc.). Depending upon //the USB module configuration, there will be many BDT entries, as each //combination of endpoint number, endpoint direction, and endpoint //"even/odd-ness" (when ping-pong buffering is enabled), needs a dedicated //set of SFRs for controling the DMA behavior when the host tries to read/write //to the respective endpoint. //As the device completes the enumeration process, the USBCBInitEP() function will //get called. In this function, we initialize the user application endpoints (in this //example code, the user application makes use of EP1 OUT, EP2 OUT, EP3 OUT). //The USBTransferOnePacket() function calls in the USBCBInitEP() function initializes an endpoint //and "arms" it so that it can receive a packet of data from the host. Once the endpoint //has been armed, the host can then send data to it (assuming some kind of application software //is running on the host, and the application software tries to send data to the USB device). //If the host sends a packet of data to the endpoint 1 OUT buffer, the hardware of the SIE will //automatically receives it and stores the data at the memory location pointed to when we called //USBTransferOnePacket(). Additionally, the endpoint handle will indicate //that the endpoint is no longer busy. At this point, it is safe for this firmware to begin reading //from the endpoint buffer, and processing the data. In this example, we don't actually do anything //with the data that is received from the host, since this demo is simply meant to show high bandwidth //USB communication. //This demo makes full use of the "ping-pong" buffering features implemented //by the USB module hardware. Ping-pong buffering is like a "DMA FIFO". //It enables up to two transactions to be queued up on a single endpoint. //While the firmware may be processing and using previously received data, //the USB module hardware can be configured to still receive the next packet //of data that may be sent from the host. //As an example in the below code, if the USB host tries to send 273 bytes //to "Endpoint 1 OUT", the following sequence will occur: //1. The first set of bytes (0-63) will arrive in the EP1OUTEvenBuffer[]. //2. The next set of bytes (64-127) will arrive in the EP1OUTOddBuffer[]. //3. Assuming the firmware re-armed the EP1OUTEven BDT, then the next set of // bytes (128-191) will arrive in the EP1OUTEvenBuffer[]. //4. Assuming the firmware re-armed the EP1OUTOdd BDT, then the next set of // bytes (192-255) will arrive in the EP1OUTOddBuffer[]. //5. Assuming the firmware re-armed the EP1OUTEven BDT, then the next set of // bytes (256-272) will arrive in the EP1OUTEvenBuffer[]. This completes // the transfer, as the host has successfully sent 273 bytes total (0-272). //If after successfully completing the above 273 byte transfer, and the host //wants to start another transfer and send another 75 bytes, the following //will occur: //6. Assuming the firmware re-armed the EP1OUTOdd BDT, then bytes (0-63) // will arrive in the EP1OUTOddBuffer[]. //7. Assuming the firmware re-armed the EP1OUTEven BDT, then the next set of // bytes (64-74) will arrive in the EP1OUTEvenBuffer[]. This completes // the transfer, as the host has successfully sent 75 bytes total (0-74). //In the above sequence, if the firmware had not gotten around to re-arming //the EP1OUTEven BDT by step #3, then the EP1 OUT endpoint will continuously //NAK until the firmware eventually does re-arm the EP1OUTEven BDT. This //NAKing will temporarily halt the data flow, but it does not cause data to //be lost. The host will continue to retry sending the data until it is //received successfully, or, the host PC application that is sending the data //aborts the operation. The PC application software can be written to //optionally abort a transfer if it takes too long (or some other event //takes place, such as the user trying to close the application). if(EP1OUTEvenNeedsServicingNext == true) //Check which buffer (even/odd) the next set of data is going to arrive in { if(!USBHandleBusy(EP1OUTEvenHandle)) //Check if the endpoint has received any data from the host. { //If the microcontroller core gets to this point, it means that the host has //successfully sent data to the EP1 OUT endpoint, and the data in the EP1OUTEvenBuffer[] //is currently valid. //Insert code here that would do something useful with the EP1OUTEvenBuffer[] //data, according to the needs of the application. For this high-bandwidth //example application, we don't do anything with the data, as the //objective is to demonstrate maximum data transfer rate only. //Now re-arm the EP1OUTEven BDT entry so that the EP1OUTEvenBuffer[] can //be prepared to receive the "second to next" data packet that the host //sends to EP1 OUT. The very next data packet sent to EP1 OUT will go //into the EP1OUTOdd buffer. However, we still need to re-arm the //EP1OUTEven BDT entry, so that the data packet that arrives after the //one going into the EP1OUTOdd buffer has someplace to go. //The USBTransferOnePacket() function call "arms" the endpoint (and //makes it "busy"). If the endpoint is armed, the SIE will automatically //accept data from the host, if the host tries to send a packet of data //to the endpoint. Once a data packet addressed to this endpoint is //received from the host, the endpoint will no longer be busy, and the //application can read the data which will be sitting in the buffer. EP1OUTEvenHandle = USBTransferOnePacket(1, OUT_FROM_HOST,(uint8_t*)&EP1OUTEvenBuffer,64); EP1OUTEvenNeedsServicingNext = false; } } else //else EP1OUTOdd needs servicing next { if(!USBHandleBusy(EP1OUTOddHandle)) //Check if the endpoint has received any data from the host. { //Insert code here that would do something useful with the data, according to the needs of //the application. //Re-arm the EP1OUTOdd BDT entry so the EP1OUTOddBuffer[] can receive //the second to next data packet sent by the host. EP1OUTOddHandle = USBTransferOnePacket(1, OUT_FROM_HOST,(uint8_t*)&EP1OUTOddBuffer,64); EP1OUTEvenNeedsServicingNext = true; } } if(EP2OUTEvenNeedsServicingNext == true) { if(!USBHandleBusy(EP2OUTEvenHandle)) //Check if the endpoint has received any data from the host. { //Re-arm the OUT endpoint for the next packet: EP2OUTEvenHandle = USBTransferOnePacket(2, OUT_FROM_HOST,(uint8_t*)&EP2OUTEvenBuffer,64); EP2OUTEvenNeedsServicingNext = false; } } else //else EP2OUTOdd needs servicing next { if(!USBHandleBusy(EP2OUTOddHandle)) //Check if the endpoint has received any data from the host. { //Re-arm the OUT endpoint for the next packet: EP2OUTOddHandle = USBTransferOnePacket(2, OUT_FROM_HOST,(uint8_t*)&EP2OUTOddBuffer,64); EP2OUTEvenNeedsServicingNext = true; } } if(EP3OUTEvenNeedsServicingNext == true) { if(!USBHandleBusy(EP3OUTEvenHandle)) //Check if the endpoint has received any data from the host. { //Re-arm the OUT endpoint for the next packet: EP3OUTEvenHandle = USBTransferOnePacket(3, OUT_FROM_HOST,(uint8_t*)&EP3OUTEvenBuffer,64); EP3OUTEvenNeedsServicingNext = false; } } else //else EP3OUTOdd needs servicing next { if(!USBHandleBusy(EP3OUTOddHandle)) //Check if the endpoint has received any data from the host. { //Re-arm the OUT endpoint for the next packet: EP3OUTOddHandle = USBTransferOnePacket(3, OUT_FROM_HOST,(uint8_t*)&EP3OUTOddBuffer,64); EP3OUTEvenNeedsServicingNext = true; } } }
/****************************************************************************** Function: BYTE MSDWriteHandler(void) Description: This funtion processes a write command received through the MSD class driver PreCondition: None Parameters: None Return Values: BYTE - the current state of the MSDWriteHandler state machine. The valid values are defined in MSD.h under the MSDWriteHandler state machine declaration section Remarks: None *****************************************************************************/ BYTE MSDWriteHandler(void) { switch(MSDWriteState) { case MSD_WRITE10_WAIT: /* Read the LBA, TransferLength fields from Command Block NOTE: CB is Big-Endian */ LBA.v[3]=gblCBW.CBWCB[2]; LBA.v[2]=gblCBW.CBWCB[3]; LBA.v[1]=gblCBW.CBWCB[4]; LBA.v[0]=gblCBW.CBWCB[5]; TransferLength.v[1]=gblCBW.CBWCB[7]; TransferLength.v[0]=gblCBW.CBWCB[8]; //Initially assume success, unless handler code later encounters an //error condition and sets the status to 0x01 or 0x02. msd_csw.bCSWStatus=0x0; MSD_State = MSD_WRITE10_BLOCK; //Fall through to MSD_WRITE10_BLOCK case MSD_WRITE10_BLOCK: if(TransferLength.Val == 0) { MSDWriteState = MSD_WRITE10_WAIT; break; } MSDWriteState = MSD_WRITE10_RX_SECTOR; ptrNextData=(BYTE *)&msd_buffer[0]; msd_csw.dCSWDataResidue=BLOCKLEN_512; //Fall through to MSD_WRITE10_RX_SECTOR case MSD_WRITE10_RX_SECTOR: { /* Read 512B into msd_buffer*/ if(msd_csw.dCSWDataResidue>0) { if(USBHandleBusy(USBMSDOutHandle) == TRUE) { break; } USBMSDOutHandle = USBRxOnePacket(MSD_DATA_OUT_EP,ptrNextData,MSD_OUT_EP_SIZE); MSDWriteState = MSD_WRITE10_RX_PACKET; //Fall through to MSD_WRITE10_RX_PACKET } else { //We finished receiving a sector worth of data from the host. //Check if the media is write protected before deciding what //to do with the data. if(LUNWriteProtectState()) { //The device appears to be write protected. //Let host know error occurred. The bCSWStatus flag is also used by //the write handler, to know not to even attempt the write sequence. msd_csw.bCSWStatus=0x01; //Set sense keys so the host knows what caused the error. gblSenseData[LUN_INDEX].SenseKey=S_NOT_READY; gblSenseData[LUN_INDEX].ASC=ASC_WRITE_PROTECTED; gblSenseData[LUN_INDEX].ASCQ=ASCQ_WRITE_PROTECTED; } MSDWriteState = MSD_WRITE10_SECTOR; break; } } //Fall through to MSD_WRITE10_RX_PACKET case MSD_WRITE10_RX_PACKET: if(USBHandleBusy(USBMSDOutHandle) == TRUE) { break; } gblCBW.dCBWDataTransferLength-=USBHandleGetLength(USBMSDOutHandle); // 64B read msd_csw.dCSWDataResidue-=USBHandleGetLength(USBMSDOutHandle); ptrNextData += MSD_OUT_EP_SIZE; MSDWriteState = MSD_WRITE10_RX_SECTOR; break; case MSD_WRITE10_SECTOR: { //Make sure that no error has been detected, before performing the write //operation. If there was an error, skip the write operation, but allow //the TransferLength to continue decrementing, so that we can eventually //receive all OUT bytes that the host is planning on sending us. Only //after that is complete will the host send the IN token for the CSW packet, //which will contain the bCSWStatus letting it know an error occurred. if(msd_csw.bCSWStatus == 0x00) { if(LUNSectorWrite(LBA.Val, (BYTE*)&msd_buffer[0], (LBA.Val==0)?TRUE:FALSE) != TRUE) { //The write operation failed for some reason. Keep track of retry //attempts and abort if repeated write attempts also fail. if(MSDRetryAttempt < MSD_FAILED_WRITE_MAX_ATTEMPTS) { MSDRetryAttempt++; break; } else { //Too many consecutive failed write attempts have occurred. //Need to give up and abandon the write attempt. msd_csw.bCSWStatus=0x01; // Error 0x01 Refer page#18 // of BOT specifications //Set error status sense keys, so the host can check them later //to determine how to proceed. gblSenseData[LUN_INDEX].SenseKey=S_MEDIUM_ERROR; gblSenseData[LUN_INDEX].ASC=ASC_NO_ADDITIONAL_SENSE_INFORMATION; gblSenseData[LUN_INDEX].ASCQ=ASCQ_NO_ADDITIONAL_SENSE_INFORMATION; } } } //One LBA is written (unless an error occurred). Advance state //variables so we can eventually finish handling the CBW request. LBA.Val++; TransferLength.Val--; MSDWriteState = MSD_WRITE10_BLOCK; break; } default: //Illegal condition which should not occur. If for some reason it //does, try to let the host know know an error has occurred. msd_csw.bCSWStatus=0x02; //Phase Error MSDWriteState = MSD_WRITE10_WAIT; } return MSDWriteState; }
/********************************************************************* * Function: void APP_DeviceAudioMIDITasks(void); * * Overview: Keeps the Custom HID demo running. * * PreCondition: The demo should have been initialized and started via * the APP_DeviceAudioMIDIInitialize() and APP_DeviceAudioMIDIStart() demos * respectively. * * Input: None * * Output: None * ********************************************************************/ void APP_DeviceAudioMIDITasks() { /* If the device is not configured yet, or the device is suspended, then * we don't need to run the demo since we can't send any data. */ if( (USBGetDeviceState() < CONFIGURED_STATE) || (USBIsDeviceSuspended() == true)) { return; } if(!USBHandleBusy(USBRxHandle)) { //We have received a MIDI packet from the host, process it and then // prepare to receive the next packet //INSERT MIDI PROCESSING CODE HERE //Get ready for next packet (this will overwrite the old data) USBRxHandle = USBRxOnePacket(USB_DEVICE_AUDIO_MIDI_ENDPOINT,(uint8_t*)&ReceivedDataBuffer,64); } /* If the user button is pressed... */ if(BUTTON_IsPressed(BUTTON_DEVICE_AUDIO_MIDI) == true) { /* and we haven't sent a transmission in the past 100ms... */ if(msCounter == 0) { /* and we have sent the NOTE_OFF for the last note... */ if(sentNoteOff == true) { /* and we aren't currently trying to transmit data... */ if(!USBHandleBusy(USBTxHandle)) { //Then reset the 100ms counter msCounter = 100; midiData.Val = 0; //must set all unused values to 0 so go ahead // and set them all to 0 midiData.CableNumber = 0; midiData.CodeIndexNumber = MIDI_CIN_NOTE_ON; midiData.DATA_0 = 0x90; //Note on midiData.DATA_1 = pitch; //pitch midiData.DATA_2 = 0x7F; //velocity USBTxHandle = USBTxOnePacket(USB_DEVICE_AUDIO_MIDI_ENDPOINT,(uint8_t*)&midiData,4); /* we now need to send the NOTE_OFF for this note. */ sentNoteOff = false; } } } } else { if(msCounter == 0) { if(sentNoteOff == false) { if(!USBHandleBusy(USBTxHandle)) { //Debounce counter for 100ms msCounter = 100; midiData.Val = 0; //must set all unused values to 0 so go ahead // and set them all to 0 midiData.CableNumber = 0; midiData.CodeIndexNumber = MIDI_CIN_NOTE_ON; midiData.DATA_0 = 0x90; //Note off midiData.DATA_1 = pitch++; //pitch midiData.DATA_2 = 0x00; //velocity if(pitch == 0x49) { pitch = 0x3C; } USBTxHandle = USBTxOnePacket(USB_DEVICE_AUDIO_MIDI_ENDPOINT,(uint8_t*)&midiData,4); sentNoteOff = true; } } } } }
BYTE MSDReadHandler(void) { switch(MSDReadState) { case MSD_READ10_WAIT: LBA.v[3]=gblCBW.CBWCB[2]; LBA.v[2]=gblCBW.CBWCB[3]; LBA.v[1]=gblCBW.CBWCB[4]; LBA.v[0]=gblCBW.CBWCB[5]; TransferLength.v[1]=gblCBW.CBWCB[7]; TransferLength.v[0]=gblCBW.CBWCB[8]; //Assume success initially, msd_csw.bCSWStatus will get set to 0x01 //or 0x02 later if an error is detected during the actual read sequence. msd_csw.bCSWStatus=0x0; msd_csw.dCSWDataResidue=0x0; MSDReadState = MSD_READ10_BLOCK; //Fall through to MSD_READ_BLOCK case MSD_READ10_BLOCK: if(TransferLength.Val == 0) { MSDReadState = MSD_READ10_WAIT; break; } TransferLength.Val--; // we have read 1 LBA MSDReadState = MSD_READ10_SECTOR; //Fall through to MSD_READ10_SECTOR case MSD_READ10_SECTOR: //if the old data isn't completely sent yet if(USBHandleBusy(USBMSDInHandle) != 0) { break; } //Try to read a sector worth of data from the media, but check for //possible errors. if(LUNSectorRead(LBA.Val, (BYTE*)&msd_buffer[0]) != TRUE) { if(MSDRetryAttempt < MSD_FAILED_READ_MAX_ATTEMPTS) { MSDRetryAttempt++; break; } else { //Too many consecutive failed reads have occurred. Need to //give up and abandon the sector read attempt; something must //be wrong and we don't want to get stuck in an infinite loop. //Need to indicate to the host that a device error occurred. //However, we can't send the CSW immediately, since the host //still expects to receive sector read data on the IN endpoint //first. Therefore, we still send dummy bytes, before //we send the CSW with the failed status in it. msd_csw.bCSWStatus=0x01; // Error 0x01 Refer page#18 // of BOT specifications //Set error status sense keys, so the host can check them later //to determine how to proceed. gblSenseData[LUN_INDEX].SenseKey=S_MEDIUM_ERROR; gblSenseData[LUN_INDEX].ASC=ASC_NO_ADDITIONAL_SENSE_INFORMATION; gblSenseData[LUN_INDEX].ASCQ=ASCQ_NO_ADDITIONAL_SENSE_INFORMATION; } }//else we successfully read a sector worth of data from our media LBA.Val++; msd_csw.dCSWDataResidue=BLOCKLEN_512;//in order to send the //512 bytes of data read ptrNextData=(BYTE *)&msd_buffer[0]; MSDReadState = MSD_READ10_TX_SECTOR; //Fall through to MSD_READ10_TX_SECTOR case MSD_READ10_TX_SECTOR: if(msd_csw.dCSWDataResidue == 0) { MSDReadState = MSD_READ10_BLOCK; break; } MSDReadState = MSD_READ10_TX_PACKET; //Fall through to MSD_READ10_TX_PACKET case MSD_READ10_TX_PACKET: /* Write next chunk of data to EP Buffer and send */ //Make sure the endpoint is available before using it. if(USBHandleBusy(USBMSDInHandle)) { break; } //Prepare the USB module to send an IN transaction worth of data to the host. USBMSDInHandle = USBTxOnePacket(MSD_DATA_IN_EP,ptrNextData,MSD_IN_EP_SIZE); MSDReadState = MSD_READ10_TX_SECTOR; gblCBW.dCBWDataTransferLength-= MSD_IN_EP_SIZE; msd_csw.dCSWDataResidue-=MSD_IN_EP_SIZE; ptrNextData+=MSD_IN_EP_SIZE; break; default: //Illegal condition, should never occur. In the event that it ever //did occur anyway, try to notify the host of the error. msd_csw.bCSWStatus=0x02; //indicate "Phase Error" //Advance state machine MSDReadState = MSD_READ10_WAIT; } return MSDReadState; }
/****************************************************************************** * Function: void ProcessIO(void) * * PreCondition: None * * Input: None * * Output: None * * Side Effects: None * * Overview: This function is a place holder for other user routines. * It is a mixture of both USB and non-USB tasks. * * Note: None *****************************************************************************/ void ProcessIO(void) { //Blink the LEDs according to the USB device status, but only do so if the PC application isn't connected and controlling the LEDs. if(blinkStatusValid) { BlinkUSBStatus(); } //User Application USB tasks below. //Note: The user application should not begin attempting to read/write over the USB //until after the device has been fully enumerated. After the device is fully //enumerated, the USBDeviceState will be set to "CONFIGURED_STATE". if((USBDeviceState < CONFIGURED_STATE)||(USBSuspendControl==1)) return; //As the device completes the enumeration process, the USBCBInitEP() function will //get called. In this function, we initialize the user application endpoints (in this //example code, the user application makes use of endpoint 1 IN and endpoint 1 OUT). //The USBGenRead() function call in the USBCBInitEP() function initializes endpoint 1 OUT //and "arms" it so that it can receive a packet of data from the host. Once the endpoint //has been armed, the host can then send data to it (assuming some kind of application software //is running on the host, and the application software tries to send data to the USB device). //If the host sends a packet of data to the endpoint 1 OUT buffer, the hardware of the SIE will //automatically receive it and store the data at the memory location pointed to when we called //USBGenRead(). Additionally, the endpoint handle (in this case USBGenericOutHandle) will indicate //that the endpoint is no longer busy. At this point, it is safe for this firmware to begin reading //from the endpoint buffer, and processing the data. In this example, we have implemented a few very //simple commands. For example, if the host sends a packet of data to the endpoint 1 OUT buffer, with the //first byte = 0x80, this is being used as a command to indicate that the firmware should "Toggle LED(s)". if(!USBHandleBusy(USBGenericOutHandle)) //Check if the endpoint has received any data from the host. { switch(OUTPacket[0]) //Data arrived, check what kind of command might be in the packet of data. { case 0x80: //Toggle LED(s) command from PC application. blinkStatusValid = FALSE; //Disable the regular LED blink pattern indicating USB state, PC application is controlling the LEDs. if(mGetLED_1() == mGetLED_2()) { mLED_1_Toggle(); mLED_2_Toggle(); } else { mLED_1_On(); mLED_2_On(); } break; case 0x81: //Get push button state command from PC application. INPacket[0] = 0x81; //Echo back to the host PC the command we are fulfilling in the first byte. In this case, the Get Pushbutton State command. // if(sw2 == 1) //pushbutton not pressed, pull up resistor on circuit board is pulling the PORT pin high if (UserSW == 1) { INPacket[1] = 0x01; } else //sw2 must be == 0, pushbutton is pressed and overpowering the pull up resistor { INPacket[1] = 0x00; } //Now check to make sure no previous attempts to send data to the host are still pending. If any attemps are still //pending, we do not want to write to the endpoint 1 IN buffer again, until the previous transaction is complete. //Otherwise the unsent data waiting in the buffer will get overwritten and will result in unexpected behavior. if(!USBHandleBusy(USBGenericInHandle)) { //The endpoint was not "busy", therefore it is safe to write to the buffer and arm the endpoint. //The USBGenWrite() function call "arms" the endpoint (and makes the handle indicate the endpoint is busy). //Once armed, the data will be automatically sent to the host (in hardware by the SIE) the next time the //host polls the endpoint. Once the data is successfully sent, the handle (in this case USBGenericInHandle) //will indicate the the endpoint is no longer busy. USBGenericInHandle = USBGenWrite(USBGEN_EP_NUM,(BYTE*)&INPacket,USBGEN_EP_SIZE); } break; } //Re-arm the OUT endpoint for the next packet: //The USBGenRead() function call "arms" the endpoint (and makes it "busy"). If the endpoint is armed, the SIE will //automatically accept data from the host, if the host tries to send a packet of data to the endpoint. Once a data //packet addressed to this endpoint is received from the host, the endpoint will no longer be busy, and the application //can read the data which will be sitting in the buffer. USBGenericOutHandle = USBGenRead(USBGEN_EP_NUM,(BYTE*)&OUTPacket,USBGEN_EP_SIZE); } }//end ProcessIO
/****************************************************************************** * Function: void ProcessIO(void) * * PreCondition: None * * Input: None * * Output: None * * Side Effects: None * * Overview: This function is a place holder for other user routines. * It is a mixture of both USB and non-USB tasks. * * Note: None *****************************************************************************/ void USBUpdate(void) { byte data[2]; byte i; byte paramNum; ulong tempLong; USBDeviceTasks(); if ((USBDeviceState < CONFIGURED_STATE) || (USBSuspendControl==1)) { return; } //As the device completes the enumeration process, the USBCBInitEP() function will //get called. In this function, we initialize the user application endpoints (in this //example code, the user application makes use of endpoint 1 IN and endpoint 1 OUT). //The USBGenRead() function call in the USBCBInitEP() function initializes endpoint 1 OUT //and "arms" it so that it can receive a packet of data from the host. Once the endpoint //has been armed, the host can then send data to it (assuming some kind of application software //is running on the host, and the application software tries to send data to the USB device). //If the host sends a packet of data to the endpoint 1 OUT buffer, the hardware of the SIE will //automatically receive it and store the data at the memory location pointed to when we called //USBGenRead(). Additionally, the endpoint handle (in this case USBGenericOutHandle) will indicate //that the endpoint is no longer busy. At this point, it is safe for this firmware to begin reading //from the endpoint buffer, and processing the data. In this example, we have implemented a few very //simple commands. For example, if the host sends a packet of data to the endpoint 1 OUT buffer, with the //first byte = 0x80, this is being used as a command to indicate that the firmware should "Toggle LED(s)". if(!USBHandleBusy(USBGenericOutHandle) && //Check if the endpoint has received any data from the host. //Now check to make sure no previous attempts to send data to the host are still pending. If any attemps are still //pending, we do not want to write to the endpoint 1 IN buffer again, until the previous transaction is complete. //Otherwise the unsent data waiting in the buffer will get overwritten and will result in unexpected behavior. (!USBGenericInHandle || !USBHandleBusy(USBGenericInHandle))) { if (OUTPacket[USB_PACKET_LEN] < 7) { // message too short } else { usbActivityTimeout = 3000; // reset timeout (in ms) 3 seconds switch(OUTPacket[USB_PACKET_CMD]) { //Data arrived, check what kind of command might be in the packet of data. case USB_CMD_NULL: // 0x00 if (OUTPacket[USB_PACKET_LEN] != 7) { data[0] = USB_ERR_BAD_LEN; UsbSendResp(USB_RESP_BAD_MSG, data); } else { UsbSendResp(USB_RESP_NULL, data); } break; case USB_CMD_GET_VSTRING: if (OUTPacket[USB_PACKET_LEN] != 7) { data[0] = USB_ERR_BAD_LEN; UsbSendResp(USB_RESP_BAD_MSG, data); } else { UsbSendResp(USB_RESP_GET_VSTRING, data); } break; case USB_CMD_GET_CHAN: if (OUTPacket[USB_PACKET_LEN] != 7) { data[0] = USB_ERR_BAD_LEN; data[1] = 7; UsbSendResp(USB_RESP_BAD_MSG, data); } else if (OUTPacket[USB_PACKET_STR] >= NUM_STRINGS) { data[0] = USB_ERR_BAD_PRM; data[1] = 0; UsbSendResp(USB_RESP_BAD_MSG, data); } else if (!OUTPacket[USB_PACKET_MCT] || OUTPacket[USB_PACKET_MCT] > NUM_MCT) { data[0] = USB_ERR_BAD_PRM; data[1] = 1; UsbSendResp(USB_RESP_BAD_MSG, data); } else { UsbSendResp(USB_RESP_GET_CHAN, data); } break; case USB_CMD_GET_MIRRORS: if (OUTPacket[USB_PACKET_LEN] != 7) { data[0] = USB_ERR_BAD_LEN; data[1] = 7; UsbSendResp(USB_RESP_BAD_MSG, data); } else if (OUTPacket[USB_PACKET_STR] >= NUM_STRINGS) { data[0] = USB_ERR_BAD_PRM; data[1] = 0; UsbSendResp(USB_RESP_BAD_MSG, data); } else if (!OUTPacket[USB_PACKET_MCT] || OUTPacket[USB_PACKET_MCT] > NUM_MCT) { data[0] = USB_ERR_BAD_PRM; data[1] = 1; UsbSendResp(USB_RESP_BAD_MSG, data); } else { UsbSendResp(USB_RESP_GET_MIRRORS, data); } break; case USB_CMD_GET_STRING: if (OUTPacket[USB_PACKET_LEN] != 7) { data[0] = USB_ERR_BAD_LEN; data[1] = 7; UsbSendResp(USB_RESP_BAD_MSG, data); } else if (OUTPacket[USB_PACKET_STR] >= NUM_STRINGS) { data[0] = USB_ERR_BAD_PRM; data[1] = 0; UsbSendResp(USB_RESP_BAD_MSG, data); } else { UsbSendResp(USB_RESP_GET_STRING, data); } break; case USB_CMD_FIELD_STATE: if (OUTPacket[USB_PACKET_LEN] == 7) { UsbSendResp(USB_RESP_FIELD_STATE, data); } else if (OUTPacket[USB_PACKET_LEN] == 8) { FieldNewState(OUTPacket[USB_PACKET_DATA]); UsbSendResp(USB_RESP_FIELD_STATE, data); } else { data[0] = USB_ERR_BAD_LEN; data[1] = 7; UsbSendResp(USB_RESP_BAD_MSG, data); } break; case USB_CMD_GET_FCE: if (OUTPacket[USB_PACKET_LEN] == 7) { UsbSendResp(USB_RESP_GET_FCE, data); } else { data[0] = USB_ERR_BAD_LEN; data[1] = 7; UsbSendResp(USB_RESP_BAD_MSG, data); } break; case USB_CMD_GET_RTU: if (OUTPacket[USB_PACKET_LEN] == 7) { UsbSendResp(USB_RESP_GET_RTU, data); } else { data[0] = USB_ERR_BAD_LEN; data[1] = 7; UsbSendResp(USB_RESP_BAD_MSG, data); } break; case USB_CMD_SEND_MCT485: // 0x64 if (OUTPacket[USB_PACKET_LEN] >= 11 && OUTPacket[USB_PACKET_LEN] < MCT485_MAX_INDEX + 7) { //Mct485CannedMsg(MSG_ORIGIN_USB, // OUTPacket[USB_PACKET_STR], // OUTPacket[USB_PACKET_LEN]-7, // &OUTPacket[USB_PACKET_DATA]); usb485TxString = OUTPacket[USB_PACKET_STR]; usb485TxLen = OUTPacket[USB_PACKET_LEN]-7; for (i = 0; i < usb485TxLen; i++) { usb485TxBuffer[i] = OUTPacket[USB_PACKET_DATA+i]; } // clear 485 response buffer usb485RxLen = 0; UsbSendResp(USB_RESP_SEND_MCT485, data); } else { data[0] = USB_ERR_BAD_LEN; data[1] = 7; UsbSendResp(USB_RESP_BAD_MSG, data); } break; case USB_CMD_GET_MCT485: // 0x65 if (OUTPacket[USB_PACKET_LEN] == 7) { UsbSendResp(USB_RESP_GET_MCT485, data); } else { data[0] = USB_ERR_BAD_LEN; data[1] = 7; UsbSendResp(USB_RESP_BAD_MSG, data); } break; case USB_CMD_RTC: // 0x66 if (OUTPacket[USB_PACKET_LEN] == 7) { UsbSendResp(USB_RESP_RTC, data); } else if (OUTPacket[USB_PACKET_LEN] == 13) { RtcSetClock(&OUTPacket[USB_PACKET_DATA]); UsbSendResp(USB_RESP_RTC, data); } else { data[0] = USB_ERR_BAD_LEN; data[1] = 7; UsbSendResp(USB_RESP_BAD_MSG, data); } break; case USB_CMD_LOG: // 0x67 if (OUTPacket[USB_PACKET_LEN] == 7) { UsbSendResp(USB_RESP_LOG, data); } else if (OUTPacket[USB_PACKET_LEN] == 8) { if (OUTPacket[USB_PACKET_DATA] == 0) { DataLogFindFirstEntry(); } else if (OUTPacket[USB_PACKET_DATA] == 0xFF) { DataLogErase(); } UsbSendResp(USB_RESP_LOG, data); } else { data[0] = USB_ERR_BAD_LEN; data[1] = 7; UsbSendResp(USB_RESP_BAD_MSG, data); } break; case USB_CMD_DESICCANT: // 0x68 if (OUTPacket[USB_PACKET_LEN] == 7) { UsbSendResp(USB_RESP_DESICCANT, data); } else if (OUTPacket[USB_PACKET_LEN] == 9) { // manual force dessicant to set of outputs or state DesiccantNewState(OUTPacket[USB_PACKET_DATA], OUTPacket[USB_PACKET_DATA+1]); UsbSendResp(USB_RESP_DESICCANT, data); } else { data[0] = USB_ERR_BAD_LEN; data[1] = 7; UsbSendResp(USB_RESP_BAD_MSG, data); } break; case USB_CMD_SFC_PARAM: // 0x69 if (OUTPacket[USB_PACKET_LEN] == 8) { UsbSendResp(USB_RESP_SFC_PARAM, data); } else if (OUTPacket[USB_PACKET_LEN] > 8 && !(OUTPacket[USB_PACKET_LEN] & 0x03)) { // process one param at a time, prevents I2C queue entry overflow and avoids // I2C page boundary problems paramNum = OUTPacket[USB_PACKET_DATA]; i = USB_PACKET_DATA+1; while (i < OUTPacket[USB_PACKET_LEN]-2) { tempLong = OUTPacket[i++]; tempLong *= 256; tempLong += OUTPacket[i++]; tempLong *= 256; tempLong += OUTPacket[i++]; tempLong *= 256; tempLong += OUTPacket[i++]; ParamWrite(paramNum, tempLong); paramNum++; } UsbSendResp(USB_RESP_SFC_PARAM, data); } else { data[0] = USB_ERR_BAD_LEN; data[1] = 7; UsbSendResp(USB_RESP_BAD_MSG, data); } break; case USB_CMD_MEMORY: // 0x6A if (OUTPacket[USB_PACKET_LEN] == 11) { data[4] = 16; UsbSendResp(USB_RESP_MEMORY, data); } else { data[0] = USB_ERR_BAD_LEN; data[1] = 7; UsbSendResp(USB_RESP_BAD_MSG, data); } break; case USB_CMD_TEST: // 0x6B if (OUTPacket[USB_PACKET_LEN] == 8) { UsbSendResp(USB_RESP_TEST, data); for (tempLong = 0; tempLong < 1000000; tempLong++) { } if (OUTPacket[USB_PACKET_DATA] == 0x01) { Mct485Init(); } else if (OUTPacket[USB_PACKET_DATA] == 0x02) { StringInit(); } else if (OUTPacket[USB_PACKET_DATA] == 0x03) { FieldInit(); } else if (OUTPacket[USB_PACKET_DATA] == 0x04) { SoftReset(); } } else { data[0] = USB_ERR_BAD_LEN; data[1] = 7; UsbSendResp(USB_RESP_BAD_MSG, data); } break; } // switch (cmd) } // else process messages //Re-arm the OUT endpoint for the next packet: //The USBGenRead() function call "arms" the endpoint (and makes it "busy"). If the endpoint is armed, the SIE will //automatically accept data from the host, if the host tries to send a packet of data to the endpoint. Once a data //packet addressed to this endpoint is received from the host, the endpoint will no longer be busy, and the application //can read the data which will be sitting in the buffer. USBGenericOutHandle = USBGenRead(USBGEN_EP_NUM,(BYTE*)&OUTPacket,USBGEN_EP_SIZE); } // if }// UsbUpdate()
BOOL midiTxHandleBusy(void) { return USBHandleBusy(midiTxHandle); }
BYTE MSDReadHandler(void) { static BYTE MSDReadState = MSD_READ10_WAIT; switch(MSDReadState) { case MSD_READ10_WAIT: LBA.v[3]=gblCBW.CBWCB[2]; LBA.v[2]=gblCBW.CBWCB[3]; LBA.v[1]=gblCBW.CBWCB[4]; LBA.v[0]=gblCBW.CBWCB[5]; TransferLength.v[1]=gblCBW.CBWCB[7]; TransferLength.v[0]=gblCBW.CBWCB[8]; msd_csw.bCSWStatus=0x0; msd_csw.dCSWDataResidue=0x0; MSDReadState = MSD_READ10_BLOCK; //Fall through to MSD_READ_BLOCK case MSD_READ10_BLOCK: if(TransferLength.Val == 0) { MSDReadState = MSD_READ10_WAIT; break; } TransferLength.Val--; // we have read 1 LBA MSDReadState = MSD_READ10_SECTOR; //Fall through to MSD_READ10_SECTOR case MSD_READ10_SECTOR: //if the old data isn't completely sent yet if(USBHandleBusy(USBMSDInHandle) != 0) { break; } if(LUNSectorRead(LBA.Val, (BYTE*)&msd_buffer[0]) != TRUE) { msd_csw.bCSWStatus=0x01; // Error 0x01 Refer page#18 // of BOT specifications /* Don't read any more data*/ msd_csw.dCSWDataResidue=0x0; MSD_State = MSD_DATA_IN; break; } LBA.Val++; msd_csw.bCSWStatus=0x00; // success msd_csw.dCSWDataResidue=BLOCKLEN_512;//in order to send the //512 bytes of data read ptrNextData=(BYTE *)&msd_buffer[0]; MSDReadState = MSD_READ10_TX_SECTOR; //Fall through to MSD_READ10_TX_SECTOR case MSD_READ10_TX_SECTOR: if(msd_csw.dCSWDataResidue == 0) { MSDReadState = MSD_READ10_BLOCK; break; } MSDReadState = MSD_READ10_TX_PACKET; //Fall through to MSD_READ10_TX_PACKET case MSD_READ10_TX_PACKET: if ((msd_csw.bCSWStatus==0x00)&&(msd_csw.dCSWDataResidue>=MSD_IN_EP_SIZE)) { /* Write next chunk of data to EP Buffer and send */ if(USBHandleBusy(USBMSDInHandle)) { break; } USBMSDInHandle = USBTxOnePacket(MSD_DATA_IN_EP,ptrNextData,MSD_IN_EP_SIZE); MSDReadState = MSD_READ10_TX_SECTOR; gblCBW.dCBWDataTransferLength-= MSD_IN_EP_SIZE; msd_csw.dCSWDataResidue-=MSD_IN_EP_SIZE; ptrNextData+=MSD_IN_EP_SIZE; } break; } return MSDReadState; }
/******************************************************************** * Function: void ProcessIO(void) * * PreCondition: None * * Input: None * * Output: None * * Side Effects: None * * Overview: This function is a place holder for other user * routines. It is a mixture of both USB and * non-USB tasks. * * Note: None *******************************************************************/ void ProcessIO(void) { // User Application USB tasks if((USBDeviceState < CONFIGURED_STATE)||(USBSuspendControl==1)) return; if(!USBHandleBusy(USBRxHandle)) { //We have received a MIDI packet from the host, process it and then // prepare to receive the next packet //INSERT MIDI PROCESSING CODE HERE BOOL note_stealing = FALSE; static BYTE note; int channel; BYTE oldest_channel; unsigned long lowest_counter; BOOL duplicate_note = FALSE; float bent_note; unsigned char bend_value; USB_AUDIO_MIDI_EVENT_PACKET *packet = ReceivedDataBuffer; // suspicious pointer conversion, yada yada // run through the complete buffer (16 packets x 4 bytes) and process MIDI messages int buffer = 16; while(buffer--) { switch(packet->DATA_0 & MIDI_MESSAGE_MASK) { case MIDI_NOTE_ON: if(note_stealing) { // Note stealing logic: find the channel with the lowest steal counter, // and reassign it to the newest note on command. In the event of a // tie, channel order decides. oldest_channel = 0; lowest_counter = 0xFFFFFFFF; note = packet->DATA_1; channel = CHANNELS; while(channel--) { if(Generator[channel].Active == TRUE) Generator[channel].StealTimer--; if(Generator[channel].MidiNote == note && Generator[channel].Active == TRUE) duplicate_note = TRUE; if(Generator[channel].StealTimer < lowest_counter) { lowest_counter = Generator[channel].StealTimer; oldest_channel = channel; } } if(!duplicate_note) { Generator[oldest_channel].MidiNote = note; Generator[oldest_channel].Period = NotePeriod[note]; Generator[oldest_channel].StealTimer = 0xFFFFFFFF; Generator[oldest_channel].Active = TRUE; } } else { note = packet->DATA_1; channel = packet->DATA_0 & MIDI_CHANNEL_MASK; if(channel >= 0 && channel < CHANNELS) { Generator[channel].MidiNote = note; Generator[channel].Period = NotePeriod[note]; Generator[channel].Active = TRUE; } } break; case MIDI_NOTE_OFF: if(note_stealing) { channel = CHANNELS; note = packet->DATA_1; // find the active channel for this note, if it exists while(channel--) { if(Generator[channel].MidiNote == note) { //kill it Generator[channel].Active = FALSE; Generator[channel].StealTimer = 0; break; } } } else { note = packet->DATA_1; channel = packet->DATA_0 & MIDI_CHANNEL_MASK; if(channel >= 0 && channel < CHANNELS) { if(Generator[channel].MidiNote == note) { Generator[channel].Active = FALSE; } } } break; // Please excuse this atrocious bend code. It was rushed to be used, only to not // actually be used at all due to a change in song choice. It did work "kind of" // when I originally implemented it, but I never ironed the bugs out. In fact it // may not work at all in its present state due to changes elsewhere. I definitely // did have it working at one point in time for a song demo I decided not to make. case MIDI_PITCH_BEND: { channel = packet->DATA_0 & MIDI_CHANNEL_MASK; if(channel >= 0 && channel < CHANNELS) { note = Generator[channel].MidiNote; //bent_note = NotePeriod[note]; // 100 cents per semitone, PITCH_BEND_RANGE max semitones // 1. calculate how many cents to bend pitch ... // we can use a piecewise linear interpolation between semitones // if we restrict the max bend range to +/- 2 semitones, we can // just check if the bend is between 0 and 1 semitones and linearly interpolate, // or if it's between 1 and 2 semitones, start at the next highest note, and linearly // interpolate to the one above that (or so on for successively higher ranges) // 2 ^ 1/12 = 1.05946309435929526456... // 2 ^-1/12 = 0.94387431268169349664... // for PITCH_BEND_RANGE = 2 // max cents = PITCH_BEND_RANGE * 100 = 200 cents // 0x2000 - 0x3FFF = 200 cents; 0x2000 - 0x0000 = 200 cents // 0x2000 = no bend, 0x0000 = full bend down, 0x3FFF = full bend up // 1. assemble the 14-bit bend value //bend_value = ((int)(Generator[channel].DATA_2 & 0x7F) << 7) | (int)(Generator[channel].DATA_1 & 0x7F); // actually, we can probably get away with using only the most significant byte because the floppy-stepper-oscillator is such a crude sound in the first place bend_value = packet->DATA_2; // 2. determine if the bend is up or down if(bend_value > 0x40) { bend_value -= 0x40; // value between 0x00 and 0x3F if(bend_value >= 0x20) // bend past +1 semitone { bend_value -= 0x20; // value between 0x00 and 0x1F; bent_note = NotePeriod[note+1]; } else // bend between 0 and +1 semitone { bent_note = NotePeriod[note]; } // !! FIX THIS // !! we need to bend the cycle period down to bend frequency up, and vice-versa //bend_value = 0x20 - bend_value; bent_note *= BendCoeff[bend_value]; } else if(bend_value < 0x40) { bend_value = bend_value - 0x39; } Generator[channel].Period = bent_note; } } break; default: break; } packet++; } //Get ready for next packet (this will overwrite the old data) USBRxHandle = USBRxOnePacket(MIDI_EP,(BYTE*)&ReceivedDataBuffer,64); } }//end ProcessIO
/****************************************************************************** Function: BYTE MSDWriteHandler(void) Description: This funtion processes a write command received through the MSD class driver PreCondition: None Parameters: None Return Values: BYTE - the current state of the MSDWriteHandler state machine. The valid values are defined in MSD.h under the MSDWriteHandler state machine declaration section Remarks: None *****************************************************************************/ BYTE MSDWriteHandler(void) { static BYTE MSDWriteState = MSD_WRITE10_WAIT; switch(MSDWriteState) { case MSD_WRITE10_WAIT: /* Read the LBA, TransferLength fields from Command Block NOTE: CB is Big-Endian */ LBA.v[3]=gblCBW.CBWCB[2]; LBA.v[2]=gblCBW.CBWCB[3]; LBA.v[1]=gblCBW.CBWCB[4]; LBA.v[0]=gblCBW.CBWCB[5]; TransferLength.v[1]=gblCBW.CBWCB[7]; TransferLength.v[0]=gblCBW.CBWCB[8]; msd_csw.bCSWStatus=0x0; MSD_State = MSD_WRITE10_BLOCK; //Fall through to MSD_WRITE10_BLOCK case MSD_WRITE10_BLOCK: if(TransferLength.Val == 0) { MSDWriteState = MSD_WRITE10_WAIT; break; } MSDWriteState = MSD_WRITE10_RX_SECTOR; ptrNextData=(BYTE *)&msd_buffer[0]; msd_csw.dCSWDataResidue=BLOCKLEN_512; //Fall through to MSD_WRITE10_RX_SECTOR case MSD_WRITE10_RX_SECTOR: { /* Read 512B into msd_buffer*/ if(msd_csw.dCSWDataResidue>0) { if(USBHandleBusy(USBMSDOutHandle) == TRUE) { break; } USBMSDOutHandle = USBRxOnePacket(MSD_DATA_OUT_EP,ptrNextData,MSD_OUT_EP_SIZE); MSDWriteState = MSD_WRITE10_RX_PACKET; //Fall through to MSD_WRITE10_RX_PACKET } else { if(LUNWriteProtectState()) { gblSenseData[LUN_INDEX].SenseKey=S_NOT_READY; gblSenseData[LUN_INDEX].ASC=ASC_WRITE_PROTECTED; gblSenseData[LUN_INDEX].ASCQ=ASCQ_WRITE_PROTECTED; msd_csw.bCSWStatus=0x01; //TODO: (DF) - what state should I return to? } else { MSDWriteState = MSD_WRITE10_SECTOR; } break; } } //Fall through to MSD_WRITE10_RX_PACKET case MSD_WRITE10_RX_PACKET: if(USBHandleBusy(USBMSDOutHandle) == TRUE) { break; } gblCBW.dCBWDataTransferLength-=USBHandleGetLength(USBMSDOutHandle); // 64B read msd_csw.dCSWDataResidue-=USBHandleGetLength(USBMSDOutHandle); ptrNextData += MSD_OUT_EP_SIZE; MSDWriteState = MSD_WRITE10_RX_SECTOR; break; case MSD_WRITE10_SECTOR: { if(LUNSectorWrite(LBA.Val, (BYTE*)&msd_buffer[0], (LBA.Val==0)?TRUE:FALSE) != TRUE) { break; } // if (status) { // msd_csw.bCSWStatus=0x01; // /* add some sense keys here*/ // } LBA.Val++; // One LBA is written. Write the next LBA TransferLength.Val--; MSDWriteState = MSD_WRITE10_BLOCK; break; } } return MSDWriteState; }
static void processUsbCommands(void) { #if defined(USB_POLLING) // Check bus status and service USB interrupts. USBDeviceTasks(); // Interrupt or polling method. If using polling, must call // this function periodically. This function will take care // of processing and responding to SETUP transactions // (such as during the enumeration process when you first // plug in). USB hosts require that USB devices should accept // and process SETUP packets in a timely fashion. Therefore, // when using polling, this function should be called // regularly (such as once every 1.8ms or faster** [see // inline code comments in usb_device.c for explanation when // "or faster" applies]) In most cases, the USBDeviceTasks() // function does not take very long to execute (ex: <100 // instruction cycles) before it returns. #endif // Note: The user application should not begin attempting to read/write over the USB // until after the device has been fully enumerated. After the device is fully // enumerated, the USBDeviceState will be set to "CONFIGURED_STATE". if ((USBDeviceState < CONFIGURED_STATE)||(USBSuspendControl==1)) return; // As the device completes the enumeration process, the UsbCbInitEP() function will // get called. In this function, we initialize the user application endpoints (in this // example code, the user application makes use of endpoint 1 IN and endpoint 1 OUT). // The USBGenRead() function call in the UsbCbInitEP() function initializes endpoint 1 OUT // and "arms" it so that it can receive a packet of data from the host. Once the endpoint // has been armed, the host can then send data to it (assuming some kind of application software // is running on the host, and the application software tries to send data to the USB device). // If the host sends a packet of data to the endpoint 1 OUT buffer, the hardware of the SIE will // automatically receive it and store the data at the memory location pointed to when we called // USBGenRead(). Additionally, the endpoint handle (in this case UsbOutCmdHandle) will indicate // that the endpoint is no longer busy. At this point, it is safe for this firmware to begin reading // from the endpoint buffer, and processing the data. In this example, we have implemented a few very // simple commands. For example, if the host sends a packet of data to the endpoint 1 OUT buffer, with the // first byte = 0x80, this is being used as a command to indicate that the firmware should "Toggle LED(s)". if (!USBHandleBusy(UsbOutCmdHandle)) { // Check if the endpoint has received any data from the host. #if DEBUG unsigned char l = USBHandleGetLength(UsbOutCmdHandle); if (usbfifo_debug_operation.dump_usb_out == 1) { unsigned char b[16]; unsigned char i; putrsUSART("USB OUT: '"); for (i=0;i<l;++i) { if (i != 0) { while (BusyUSART()); putcUSART(' '); } sprintf(b, "%02x", OutCmdPacket[i]); putsUSART(b); } sprintf(b, "' len=%3d\r\n", l); putsUSART(b); } if (usbfifo_debug_operation.usb_loopback == 1) { unsigned char i; // Now check to make sure no previous attempts to send data to the host are still pending. If any attemps are still // pending, we do not want to write to the endpoint 1 IN buffer again, until the previous transaction is complete. // Otherwise the unsent data waiting in the buffer will get overwritten and will result in unexpected behavior. while (USBHandleBusy(UsbInCmdHandle)); for (i=0;i<l;++i) InCmdPacket[i] = OutCmdPacket[i]; // The endpoint was not "busy", therefore it is safe to write to the buffer and arm the endpoint. // The USBGenWrite() function call "arms" the endpoint (and makes the handle indicate the endpoint is busy). // Once armed, the data will be automatically sent to the host (in hardware by the SIE) the next time the // host polls the endpoint. Once the data is successfully sent, the handle (in this case UsbInCmdHandle) // will indicate the the endpoint is no longer busy. UsbInCmdHandle = USBGenWrite(USBGEN_CMD_EP_NUM, (BYTE*)&InCmdPacket, l); } #endif switch (OutCmdPacket[0]) { #if DEBUG case USBFIFO_CMD_DUMP_USB_OUT: usbfifo_debug_operation.dump_usb_out ^= 1; break; case USBFIFO_CMD_DUMP_FIFO_OUT: usbfifo_debug_operation.dump_fifo_out ^= 1; break; case USBFIFO_CMD_FIFO_LOOPBACK: usbfifo_debug_operation.fifo_loopback ^= 1; break; case USBFIFO_CMD_USB_LOOPBACK: usbfifo_debug_operation.usb_loopback ^= 1; break; #endif default: { unsigned char b[8]; putrsUSART("Unexpected cmd="); sprintf(b, "0x%2X\r\n", OutCmdPacket[0]); putsUSART(b); } break; } // Re-arm the OUT endpoint for the next packet: // The USBGenRead() function call "arms" the endpoint (and makes it "busy"). If the endpoint is armed, the SIE will // automatically accept data from the host, if the host tries to send a packet of data to the endpoint. Once a data // packet addressed to this endpoint is received from the host, the endpoint will no longer be busy, and the application // can read the data which will be sitting in the buffer. UsbOutCmdHandle = USBGenRead(USBGEN_CMD_EP_NUM, (BYTE*)&OutCmdPacket, USBGEN_EP_SIZE); } if (!USBHandleBusy(UsbOutDataHandle)) { #if USBGEN_EP_SIZE > FIFO_9403A_MAX_MSG_LEN #error "Transfer of more than FIFO_9403A_MAX_MSG_LEN not implemented" #endif unsigned char l = USBHandleGetLength(UsbOutDataHandle); unsigned char i; #if DEBUG if (usbfifo_debug_operation.dump_usb_out == 1) { unsigned char b[16]; putrsUSART("USB OUT: '"); for (i=0;i<l;++i) { if (i != 0) { while (BusyUSART()); putcUSART(' '); } sprintf(b, "%02x", OutDataPacket[i]); } sprintf(b, "' len=%3d\r\n", l); putsUSART(b); } if (usbfifo_debug_operation.usb_loopback == 1) { while (USBHandleBusy(UsbInDataHandle)); // ensure that FIFO data left the device for (i=0;i<l;++i) InDataPacket[i] = OutDataPacket[i]; /* FIXME: use real ping-pong */ UsbInDataHandle = USBGenWrite(USBGEN_DATA_EP_NUM, (BYTE*)&InDataPacket, l); while (USBHandleBusy(UsbInDataHandle)); // have to wait here as full ping-pong is not implemented // and thus we don't want data from FIFO override the data being sent here } #endif fifo9403aPush(l, 1); for (i=0;i<l;++i) fifo9403aPush(OutDataPacket[i], 1); UsbOutDataHandle = USBGenRead(USBGEN_DATA_EP_NUM, (BYTE*)&OutDataPacket, USBGEN_EP_SIZE); } }
void USBCCIDBulkInService(void) { WORD byte_to_send; BYTE i; USBMaskInterrupts(); if(USBHandleBusy(usbCcidBulkInHandle)) { USBUnmaskInterrupts(); return; } if(usbCcidBulkInTrfState == USB_CCID_BULK_IN_COMPLETING) usbCcidBulkInTrfState = USB_CCID_BULK_IN_READY; /* * If USB_CCID_BULK_IN_READY state, nothing to do, just return. */ if(usbCcidBulkInTrfState == USB_CCID_BULK_IN_READY) { USBUnmaskInterrupts(); return; } /* * If USB_CCID_BULK_IN_BUSY_ZLP state, send zero length packet */ if(usbCcidBulkInTrfState == USB_CCID_BULK_IN_BUSY_ZLP) { usbCcidBulkInHandle = USBTxOnePacket(USB_EP_BULK_IN,NULL,0); usbCcidBulkInTrfState = USB_CCID_BULK_IN_COMPLETING; } else if(usbCcidBulkInTrfState == USB_CCID_BULK_IN_BUSY) { /* * First, have to figure out how many byte of data to send. */ if(usbCcidBulkInLen > sizeof(usbCcidBulkInEndpoint)) byte_to_send = sizeof(usbCcidBulkInEndpoint); else byte_to_send = usbCcidBulkInLen; /* * Subtract the number of bytes just about to be sent from the total. */ usbCcidBulkInLen = usbCcidBulkInLen - byte_to_send; pCCIDDst.bRam = (BYTE*)usbCcidBulkInEndpoint; // Set destination pointer i = byte_to_send; while(i) { *pCCIDDst.bRam = *pCCIDSrc.bRam; pCCIDDst.bRam++; pCCIDSrc.bRam++; i--; }//end while(byte_to_send._word) /* * Lastly, determine if a zero length packet state is necessary. * See explanation in USB Specification 2.0: Section 5.8.3 */ if(usbCcidBulkInLen == 0) { if(byte_to_send == USB_EP_SIZE) usbCcidBulkInTrfState = USB_CCID_BULK_IN_BUSY_ZLP; else usbCcidBulkInTrfState = USB_CCID_BULK_IN_COMPLETING; }//end if(usbCcidBulkInLen...) usbCcidBulkInHandle = USBTxOnePacket(USB_EP_BULK_IN,(BYTE*)usbCcidBulkInEndpoint,byte_to_send); }//end if(cdc_tx_sate == USB_CCID_BULK_IN_BUSY) USBUnmaskInterrupts(); }//end USBCCIDBulkInService
/****************************************************************************** * Function: void ServiceRequests(void) * * PreCondition: None * * Input: None * * Output: None * * Side Effects: USB traffic can be generated * * Overview: This function takes in the commands from the PC from the * application and executes the commands requested * * Note: None *****************************************************************************/ void ServiceRequests(void) { BYTE index; //Check to see if data has arrived if(!USBHandleBusy(USBGenericOutHandle)) { //if the handle is no longer busy then the last //transmission is complete counter = 0; INPacket.CMD=OUTPacket.CMD; INPacket.len=OUTPacket.len; //process the command switch(OUTPacket.CMD) { case READ_VERSION: //dataPacket._byte[1] is len INPacket._byte[2] = MINOR_VERSION; INPacket._byte[3] = MAJOR_VERSION; counter=0x04; break; case ID_BOARD: counter = 0x01; if(OUTPacket.ID == 0) { mLED_3_Off();mLED_4_Off(); } else if(OUTPacket.ID == 1) { mLED_3_Off();mLED_4_On(); } else if(OUTPacket.ID == 2) { mLED_3_On();mLED_4_Off(); } else if(OUTPacket.ID == 3) { mLED_3_On();mLED_4_On(); } else counter = 0x00; break; case UPDATE_LED: #if defined(PIC18F87J50_PIM) || defined(PIC18F46J50_PIM) || defined(PIC18F47J53_PIM) blinkStatusValid = FALSE; #endif // LED1 & LED2 are used as USB event indicators. if(OUTPacket.led_num == 3) { if(OUTPacket.led_status) { mLED_3_On(); } else { mLED_3_Off(); } counter = 0x01; }//end if else if(OUTPacket.led_num == 4) { if(OUTPacket.led_status) { mLED_4_On(); } else { mLED_4_Off(); } counter = 0x01; }//end if else break; case SET_TEMP_REAL: temp_mode = TEMP_REAL_TIME; ResetTempLog(); counter = 0x01; break; case RD_TEMP: if(AcquireTemperature()) { INPacket._byte[1] = temperature.v[0]; INPacket._byte[2] = temperature.v[1]; counter=0x03; }//end if break; case SET_TEMP_LOGGING: temp_mode = TEMP_LOGGING; ResetTempLog(); counter=0x01; break; case RD_TEMP_LOGGING: counter = (valid_temp<<1)+2; // Update count in byte INPacket.len = (valid_temp<<1); for(index = valid_temp; index > 0; index--) { if(pTemp == 0) pTemp = 29; else pTemp--; INPacket._word[index] = temp_data[pTemp]; }//end for ResetTempLog(); // Once read, log will restart break; case RD_POT: { WORD_VAL w; mInitPOT(); w = ReadPOT(); INPacket._byte[1] = w.v[0]; INPacket._byte[2] = w.v[1]; counter=0x03; } break; case RESET: Reset(); break; default: break; }//end switch() if(counter != 0) { if(!USBHandleBusy(USBGenericInHandle)) { USBGenericInHandle = USBGenWrite(USBGEN_EP_NUM,(BYTE*)&INPacket,counter); } }//end if //Re-arm the OUT endpoint for the next packet USBGenericOutHandle = USBGenRead(USBGEN_EP_NUM,(BYTE*)&OUTPacket,USBGEN_EP_SIZE); }//end if }//end ServiceRequests
void CDCTxService(void) { BYTE byte_to_send; BYTE i; USBMaskInterrupts(); CDCNotificationHandler(); if(USBHandleBusy(CDCDataInHandle)) { USBUnmaskInterrupts(); return; } /* * Completing stage is necessary while [ mCDCUSartTxIsBusy()==1 ]. * By having this stage, user can always check cdc_trf_state, * and not having to call mCDCUsartTxIsBusy() directly. */ if(cdc_trf_state == CDC_TX_COMPLETING) cdc_trf_state = CDC_TX_READY; /* * If CDC_TX_READY state, nothing to do, just return. */ if(cdc_trf_state == CDC_TX_READY) { USBUnmaskInterrupts(); return; } /* * If CDC_TX_BUSY_ZLP state, send zero length packet */ if(cdc_trf_state == CDC_TX_BUSY_ZLP) { CDCDataInHandle = USBTxOnePacket(CDC_DATA_EP,NULL,0); //CDC_DATA_BD_IN.CNT = 0; cdc_trf_state = CDC_TX_COMPLETING; } else if(cdc_trf_state == CDC_TX_BUSY) { /* * First, have to figure out how many byte of data to send. */ if(cdc_tx_len > sizeof(cdc_data_tx)) byte_to_send = sizeof(cdc_data_tx); else byte_to_send = cdc_tx_len; /* * Subtract the number of bytes just about to be sent from the total. */ cdc_tx_len = cdc_tx_len - byte_to_send; pCDCDst.bRam = (BYTE*)&cdc_data_tx; // Set destination pointer i = byte_to_send; if(cdc_mem_type == USB_EP0_ROM) // Determine type of memory source { while(i) { *pCDCDst.bRam = *pCDCSrc.bRom; pCDCDst.bRam++; pCDCSrc.bRom++; i--; }//end while(byte_to_send) } else // _RAM { while(i) { *pCDCDst.bRam = *pCDCSrc.bRam; pCDCDst.bRam++; pCDCSrc.bRam++; i--; }//end while(byte_to_send._word) }//end if(cdc_mem_type...) /* * Lastly, determine if a zero length packet state is necessary. * See explanation in USB Specification 2.0: Section 5.8.3 */ if(cdc_tx_len == 0) { if(byte_to_send == CDC_DATA_IN_EP_SIZE) cdc_trf_state = CDC_TX_BUSY_ZLP; else cdc_trf_state = CDC_TX_COMPLETING; }//end if(cdc_tx_len...) CDCDataInHandle = USBTxOnePacket(CDC_DATA_EP,(BYTE*)&cdc_data_tx,byte_to_send); }//end if(cdc_tx_sate == CDC_TX_BUSY) USBUnmaskInterrupts(); }//end CDCTxService
/********************************************************************************* Function: BYTE MSDTasks(void) Summary: This function runs the MSD class state machines and all of its sub-systems. This function should be called periodically once the device is in the configured state in order to keep the MSD state machine going. Description: This function runs the MSD class state machines and all of its sub-systems. This function should be called periodically once the device is in the configured state in order to keep the MSD state machine going. Typical Usage: <code> void main(void) { USBDeviceInit(); while(1) { USBDeviceTasks(); if((USBGetDeviceState() \< CONFIGURED_STATE) || (USBIsDeviceSuspended() == TRUE)) { //Either the device is not configured or we are suspended // so we don't want to do execute any application code continue; //go back to the top of the while loop } else { //Keep the MSD state machine going MSDTasks(); //Run application code. UserApplication(); } } } </code> Conditions: None Return Values: BYTE - the current state of the MSD state machine the valid values are defined in MSD.h under the MSDTasks state machine declaration section. The possible values are the following\: * MSD_WAIT * MSD_DATA_IN * MSD_DATA_OUT * MSD_SEND_CSW Remarks: None *********************************************************************************/ BYTE MSDTasks(void) { BYTE i; switch(MSD_State) { case MSD_WAIT: { //If the MSD state machine is waiting for something to happen if(!USBHandleBusy(USBMSDOutHandle)) { //If we received an OUT packet from the host // then copy the data from the buffer to a global // buffer so that we can keep the information but // reuse the buffer gblCBW.dCBWSignature=msd_cbw.dCBWSignature; gblCBW.dCBWTag=msd_cbw.dCBWTag; gblCBW.dCBWDataTransferLength=msd_cbw.dCBWDataTransferLength; gblCBW.bCBWFlags=msd_cbw.bCBWFlags; gblCBW.bCBWLUN=msd_cbw.bCBWLUN; gblCBW.bCBWCBLength=msd_cbw.bCBWCBLength; // 3 MSB are zero for (i=0;i<msd_cbw.bCBWCBLength;i++) { gblCBW.CBWCB[i]=msd_cbw.CBWCB[i]; } gblCBWLength=USBHandleGetLength(USBMSDOutHandle); //If this CBW is valid? if ((gblCBWLength==MSD_CBW_SIZE)&&(gblCBW.dCBWSignature==0x43425355)) { //Is this CBW meaningful? if((gblCBW.bCBWLUN<=0x0f) &&(gblCBW.bCBWCBLength<=0x10) &&(gblCBW.bCBWCBLength>=0x01) &&(gblCBW.bCBWFlags==0x00||gblCBW.bCBWFlags==0x80)) { //Prepare the CSW to be sent msd_csw.dCSWTag=gblCBW.dCBWTag; msd_csw.dCSWSignature=0x53425355; //Keep track of retry attempts, in case of temporary failures //during processing of a command. MSDRetryAttempt = 0; //Check the command. With the exception of the REQUEST_SENSE //command, we should reset the sense key info for each new command block. //Assume the command will get processed successfully (and hence "NO SENSE" //response, which is used for success cases), unless handler code //later on detects some kind of error. If it does, it should //update the sense keys to reflect the type of error detected, //prior to sending the CSW. if(gblCBW.CBWCB[0] != MSD_REQUEST_SENSE) { gblSenseData[LUN_INDEX].SenseKey=S_NO_SENSE; gblSenseData[LUN_INDEX].ASC=ASC_NO_ADDITIONAL_SENSE_INFORMATION; gblSenseData[LUN_INDEX].ASCQ=ASCQ_NO_ADDITIONAL_SENSE_INFORMATION; } /* If direction is device to host*/ if (gblCBW.bCBWFlags==0x80) { MSD_State=MSD_DATA_IN; } else if (gblCBW.bCBWFlags==0x00) { /* If direction is host to device*/ /* prepare to read data in msd_buffer */ MSD_State=MSD_DATA_OUT; } } } } break; } case MSD_DATA_IN: if(MSDProcessCommand() == MSD_COMMAND_WAIT) { // Done processing the command, send the status MSD_State = MSD_SEND_CSW; } break; case MSD_DATA_OUT: if(MSDProcessCommand() == MSD_COMMAND_WAIT) { /* Finished receiving the data prepare and send the status */ if ((msd_csw.bCSWStatus==0x00)&&(msd_csw.dCSWDataResidue!=0)) { msd_csw.bCSWStatus=0x02; } MSD_State = MSD_SEND_CSW; } break; case MSD_SEND_CSW: if(USBHandleBusy(USBMSDInHandle)) { //The TX buffer is not ready to send the status yet. break; } USBMSDInHandle = USBTxOnePacket(MSD_DATA_IN_EP,(BYTE*)&msd_csw,MSD_CSW_SIZE); //Get ready for next command to come in if(!USBHandleBusy(USBMSDOutHandle)) { USBMSDOutHandle = USBRxOnePacket(MSD_DATA_OUT_EP,(BYTE*)&msd_cbw,sizeof(msd_cbw)); } MSD_State=MSD_WAIT; break; default: //Illegal condition that should not happen, but might occur if the //device firmware incorrectly calls MSDTasks() prior to calling //USBMSDInit() during the set-configuration portion of enumeration. MSD_State=MSD_WAIT; } return MSD_State; }