/* This construct implements pre-call polling to ensure the sending completes before the function * returns. It provides simple coding while also taking advantage of the efficiencies of background * processing. If a previous send operation is underway, this function does waste cycles polling, * like xxxsendDataWaitTilDone(); however it's less likely to do so since much of the sending * presumably took place in the background since the last call to xxxsendDataInBackground(). * The function also checks all valid return codes, and returns non-zero if an error occurred. * It assumes no previous send operation is underway; also assumes size is non-zero. * This call assumes a previous send operation might be underway; also assumes size is non-zero. * Returns zero if send completed; non-zero if it failed, with 1 = timeout and 2 = bus is gone. */ BYTE hidSendDataInBackground (BYTE* dataBuf, WORD size, BYTE intfNum, ULONG ulTimeout) { ULONG sendCounter = 0; WORD bytesSent, bytesReceived; while (USBHID_intfStatus(intfNum,&bytesSent, &bytesReceived) & kUSBHID_waitingForSend){ if (ulTimeout && ((sendCounter++) > ulTimeout)){ /* A send operation is underway; incr counter & try again */ return ( 1) ; /* Timed out */ } } /* The interface is now clear. Call sendData(). */ switch (USBHID_sendData(dataBuf,size,intfNum)){ case kUSBHID_sendStarted: return ( 0) ; case kUSBHID_busNotAvailable: return ( 2) ; default: return ( 4) ; } }
/* This construct implements post-call polling to ensure the sending completes before the function * returns. It provides the simplest coding, at the expense of wasted cycles and potentially * allowing MCU execution to become "locked" to the host, a disadvantage if the host (or bus) is * slow. The function also checks all valid return codes, and returns non-zero if an error occurred. * It assumes no previous send operation is underway; also assumes size is non-zero. */ BYTE hidSendDataWaitTilDone (BYTE* dataBuf, WORD size, BYTE intfNum, ULONG ulTimeout) { ULONG sendCounter = 0; WORD bytesSent, bytesReceived; switch (USBHID_sendData(dataBuf,size,intfNum)){ case kUSBHID_sendStarted: break; case kUSBHID_busNotAvailable: return ( 2) ; case kUSBHID_intfBusyError: return ( 3) ; case kUSBHID_generalError: return ( 4) ; default:; } /* If execution reaches this point, then the operation successfully started. Now wait til it's finished. */ while (1){ BYTE ret = USBHID_intfStatus(intfNum,&bytesSent,&bytesReceived); if (ret & kUSBHID_busNotAvailable){ /* This may happen at any time */ return ( 2) ; } if (ret & kUSBHID_waitingForSend){ if (ulTimeout && (sendCounter++ >= ulTimeout)){ /* Incr counter & try again */ return ( 1) ; /* Timed out */ } } else { return ( 0) ; /* If neither busNotAvailable nor waitingForSend, it succeeded */ } } }
/*----------------------------------------------------------------------------+ | Main Routine | +----------------------------------------------------------------------------*/ VOID main(VOID) { WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer Init_StartUp(); USB_init(); USB_setEnabledEvents(kUSB_VbusOnEvent + kUSB_VbusOffEvent + kUSB_UsbSuspendEvent + kUSB_UsbResumeEvent + kUSB_receiveCompletedEvent + kUSB_UsbResetEvent); // Check if we're already physically attached to USB, and if so, connect to it // This is the same function that gets called automatically when VBUS gets attached. if (USB_connectionInfo() & kUSB_vbusPresent) USB_handleVbusOnEvent(); while(1) { switch(USB_connectionState()) { case ST_USB_DISCONNECTED: __bis_SR_register(LPM3_bits + GIE); // Enter LPM3 w/interrupt break; case ST_USB_CONNECTED_NO_ENUM: break; case ST_ENUM_ACTIVE: if(!bCommandBeingProcessed) // If no command is being processed, then make sure there's a rcv operation { // open to receive the start of the "packet" if(!(USBHID_intfStatus(0,&x,&y) & kUSBHID_waitingForReceive)) // Only open it if we haven't already done so if(USBHID_receiveData(buffer,1,0) == kUSBHID_busNotAvailable) // Start a receive operation for a single byte -- the "size" byte of the "packet" { USBHID_abortReceive(&x,0); // Abort receive break; // If bus is no longer available, escape out of the loop } } __bis_SR_register(LPM0_bits + GIE); // Wait in LPM0 until a receive operation has completed if(bDataReceiveCompleted_event) { bDataReceiveCompleted_event = FALSE; if(!bCommandBeingProcessed) // This means that the incoming byte is the start of the "packet" -- the "size" byte { if ((buffer[0]>=0x31) && (buffer[0]<= 0x39)) { size = buffer[0]-0x30; // It's in ASCII, so convert it to a number if(USBHID_receiveData(buffer,size,0) == kUSBHID_busNotAvailable) // And then open a rcv operation for that size { USBHID_abortReceive(&x,0); // Abort receive break; // If bus is no longer available, escape out of the loop } bCommandBeingProcessed = TRUE; // Now we're waiting for the "data" part of the "packet" } else { strcpy(outString,"\r\nEnter a valid number between 1 and 9\r\n\r\n"); // Prepare the outgoing string if(hidSendDataInBackground((BYTE*)outString,strlen(outString),0,0)) // Send the response over USB { USBHID_abortSend(&x,0); // Operation may still be open; cancel it break; // If the send fails, escape the main loop } bCommandBeingProcessed = FALSE; // Now we're back to waiting for the "size" byte } } else // This means that the incoming data is the "data" part of the "packet" { strcpy(outString,"\r\nI received your packet with size of "); // Prepare the outgoing string c[0] = (char)(size+0x30); // Convert the size back to ASCII c[1] = 0; // Convert the size back to ASCII outString[64] = 0; strcat(outString,c); strcat(outString," bytes.\r\n\r\n"); if(hidSendDataInBackground((BYTE*)outString,strlen(outString),0,0)) // Send the response over USB { USBHID_abortSend(&x,0); // Operation may still be open; cancel it break; // If the send fails, escape the main loop } bCommandBeingProcessed = FALSE; // Now we're back to waiting for the "size" byte } } break; case ST_ENUM_SUSPENDED: __bis_SR_register(LPM3_bits + GIE); // Enter LPM3 w/interrupt break; case ST_ENUM_IN_PROGRESS: break; case ST_NOENUM_SUSPENDED: __bis_SR_register(LPM3_bits + GIE); break; case ST_ERROR: _NOP(); break; default:; } } // while(1) } //main()