#ifndef MAIN_C #define MAIN_C /** INCLUDES *******************************************************/ #include "./USB/usb.h" #include "HardwareProfile.h" #include "./USB/usb_function_hid.h" /** CONFIGURATION **************************************************/ #pragma config PLLDIV = 5 // (20 MHz crystal on PICDEM FS USB board) #pragma config CPUDIV = OSC1_PLL2 #pragma config USBDIV = 2 // Clock source from 96MHz PLL/2 #pragma config FOSC = HSPLL_HS #pragma config FCMEN = OFF #pragma config IESO = OFF #pragma config PWRT = OFF #pragma config BOR = ON #pragma config BORV = 3 #pragma config VREGEN = ON //USB Voltage Regulator #pragma config WDT = OFF #pragma config WDTPS = 32768 #pragma config MCLRE = ON #pragma config LPT1OSC = OFF #pragma config PBADEN = OFF // #pragma config CCP2MX = ON #pragma config STVREN = ON #pragma config LVP = OFF // #pragma config ICPRT = OFF // Dedicated In-Circuit Debug/Programming #pragma config XINST = OFF // Extended Instruction Set #pragma config CP0 = OFF #pragma config CP1 = OFF // #pragma config CP2 = OFF // #pragma config CP3 = OFF #pragma config CPB = OFF // #pragma config CPD = OFF #pragma config WRT0 = OFF #pragma config WRT1 = OFF // #pragma config WRT2 = OFF // #pragma config WRT3 = OFF #pragma config WRTB = OFF // Boot Block Write Protection #pragma config WRTC = OFF // #pragma config WRTD = OFF #pragma config EBTR0 = OFF #pragma config EBTR1 = OFF // #pragma config EBTR2 = OFF // #pragma config EBTR3 = OFF #pragma config EBTRB = OFF /** VARIABLES ******************************************************/ #pragma udata #pragma udata USB_VARIABLES=0x500 #define RX_DATA_BUFFER_ADDRESS #define TX_DATA_BUFFER_ADDRESS unsigned char ReceivedDataBuffer[64] RX_DATA_BUFFER_ADDRESS; unsigned char ToSendDataBuffer[64] TX_DATA_BUFFER_ADDRESS; #pragma udata USB_HANDLE USBOutHandle = 0; //USB handle. Must be initialized to 0 at startup. USB_HANDLE USBInHandle = 0; //USB handle. Must be initialized to 0 at startup. BOOL blinkStatusValid = TRUE; #pragma udata #pragma udata ADC_VARIABLES1 #define adcbuffer1_size 256 // 204 compressed measurements (=255 bytes), 128 normal measurements #define adcbuffer1_samples 128 #define adcbuffer1_compressed_samples 204 unsigned char adcbuffer1[adcbuffer1_size]; #pragma udata ADC_VARIABLES2 #define adcbuffer2_size 256 // 204 compressed measurements, 128 normal measurements #define adcbuffer2_samples 128 #define adcbuffer2_compressed_samples 204 unsigned char adcbuffer2[adcbuffer2_size]; #pragma udata ADC_VARIABLES3 #define adcbuffer3_size 256 // 204 compressed measurements, 128 normal measurements #define adcbuffer3_samples 128 #define adcbuffer3_compressed_samples 204 unsigned char adcbuffer3[adcbuffer3_size]; #pragma udata ADC_VARIABLES4 #define adcbuffer4_size 256 // 204 compressed measurements, 128 normal measurements #define adcbuffer4_samples 128 #define adcbuffer4_compressed_samples 204 unsigned char adcbuffer4[adcbuffer4_size]; #pragma udata ADC_VARIABLES5 #define adcbuffer5_size 200 // 160 compressed measurements, 100 normal measurements #define adcbuffer5_samples 100 #define adcbuffer5_compressed_samples 160 unsigned char adcbuffer5[adcbuffer5_size]; #pragma udata ADC_VARIABLES6 #define adcbuffer6_size 160 // 128 compressed measurements, 80 normal measurements #define adcbuffer6_samples 80 #define adcbuffer6_compressed_samples 128 unsigned char adcbuffer6[adcbuffer6_size]; #pragma udata ADC_VARIABLES7 #define adcbuffer7_size 50 // 40 compressed measurements, 25 normal measurements #define adcbuffer7_samples 25 #define adcbuffer7_compressed_samples 40 unsigned char adcbuffer7[adcbuffer7_size]; BYTE simulatedMSB = 0; BYTE simulatedLSB = 0; BOOL compressedADC = FALSE; /** PRIVATE PROTOTYPES *********************************************/ void BlinkUSBStatus(void); BOOL Switch2IsPressed(void); BOOL Switch3IsPressed(void); static void InitializeSystem(void); void ProcessIO(void); void UserInit(void); void YourHighPriorityISRCode(); void YourLowPriorityISRCode(); void USBCBSendResume(void); WORD_VAL ReadPOT(void); void FillWithTestData(void); void TakeNCompressedSamples(unsigned char* p_buffer, int numberOfSamples); void TakeNSamples(unsigned char* p_buffer, int numberOfSamples); void TakeNTestSamples(unsigned char* p_buffer, int numberOfSamples); void TakeNCompressedTestSamples(unsigned char* p_buffer, int numberOfSamples); void ReadSequence(int offsetForData, int sequence); void ReadCompressedSequence(int offsetForData, int sequence); void ReadNBytes(unsigned char* p_buffer, int startIndex, int numberOfBytes, int offset); WORD_VAL SimulatePOT(void); BOOL doBulkADC = TRUE; /** VECTOR REMAPPING ***********************************************/ //On PIC18 devices, addresses 0x00, 0x08, and 0x18 are used for //the reset, high priority interrupt, and low priority interrupt //vectors. However, the current Microchip USB bootloader //examples are intended to occupy addresses 0x00-0x7FF or //0x00-0xFFF depending on which bootloader is used. Therefore, //the bootloader code remaps these vectors to new locations //as indicated below. This remapping is only necessary if you //wish to program the hex file generated from this project with //the USB bootloader. If no bootloader is used, edit the //usb_config.h file and comment out the following defines: //#define PROGRAMMABLE_WITH_USB_HID_BOOTLOADER //#define PROGRAMMABLE_WITH_USB_LEGACY_CUSTOM_CLASS_BOOTLOADER #define REMAPPED_RESET_VECTOR_ADDRESS 0x1000 #define REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS 0x1008 #define REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS 0x1018 extern void _startup(void); // See c018i.c in your C18 compiler dir #pragma code REMAPPED_RESET_VECTOR = REMAPPED_RESET_VECTOR_ADDRESS void _reset(void) { _asm goto _startup _endasm } #pragma code REMAPPED_HIGH_INTERRUPT_VECTOR = REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS void Remapped_High_ISR(void) { _asm goto YourHighPriorityISRCode _endasm } #pragma code REMAPPED_LOW_INTERRUPT_VECTOR = REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS void Remapped_Low_ISR(void) { _asm goto YourLowPriorityISRCode _endasm } #pragma code HIGH_INTERRUPT_VECTOR = 0x08 void High_ISR(void) { _asm goto REMAPPED_HIGH_INTERRUPT_VECTOR_ADDRESS _endasm } #pragma code LOW_INTERRUPT_VECTOR = 0x18 void Low_ISR(void) { _asm goto REMAPPED_LOW_INTERRUPT_VECTOR_ADDRESS _endasm } #pragma code //These are your actual interrupt handling routines. #pragma interrupt YourHighPriorityISRCode void YourHighPriorityISRCode() { int counter = 0; if (doBulkADC) { PIR1bits.ADIF = 0x00; PIE1bits.ADIE = 0x00; IPR1bits.ADIP = 0x00; TRISAbits.TRISA0 = 1; ADCON0 = 0x01; ADCON1 = 0x0E; ADCON2 = ReceivedDataBuffer[2]; ADCON0bits.ADON = 0x01; // turn adc module on for (counter = 0; counter < 60; counter++) { // wait at least 2us after enabling AD // 60 cycles at 20Mhz is 3 us } if (compressedADC) { TakeNCompressedSamples(adcbuffer1, adcbuffer1_compressed_samples); TakeNCompressedSamples(adcbuffer2, adcbuffer2_compressed_samples); TakeNCompressedSamples(adcbuffer3, adcbuffer3_compressed_samples); TakeNCompressedSamples(adcbuffer4, adcbuffer4_compressed_samples); TakeNCompressedSamples(adcbuffer5, adcbuffer5_compressed_samples); TakeNCompressedSamples(adcbuffer6, adcbuffer6_compressed_samples); TakeNCompressedSamples(adcbuffer7, adcbuffer7_compressed_samples); } else { TakeNSamples(adcbuffer1, adcbuffer1_samples); TakeNSamples(adcbuffer2, adcbuffer2_samples); TakeNSamples(adcbuffer3, adcbuffer3_samples); TakeNSamples(adcbuffer4, adcbuffer4_samples); TakeNSamples(adcbuffer5, adcbuffer5_samples); TakeNSamples(adcbuffer6, adcbuffer6_samples); TakeNSamples(adcbuffer7, adcbuffer7_samples); } ADCON0bits.ADON = 0x00; // turn adc module off doBulkADC = FALSE; } USBDeviceTasks(); } //This return will be a "retfie fast", since this is in a #pragma interrupt section #pragma interruptlow YourLowPriorityISRCode void YourLowPriorityISRCode() { } //This return will be a "retfie", since this is in a #pragma interruptlow section /** DECLARATIONS ***************************************************/ #pragma code /******************************************************************** * Function: void main(void) * * PreCondition: None * * Input: None * * Output: None * * Side Effects: None * * Overview: Main program entry point. * * Note: None *******************************************************************/ void main(void) { InitializeSystem(); USBDeviceAttach(); mLED_1_On(); mLED_2_On(); mLED_3_On(); mLED_4_On(); while (1) { ProcessIO(); }//end while }//end main /******************************************************************** * Function: static void InitializeSystem(void) * * PreCondition: None * * Input: None * * Output: None * * Side Effects: None * * Overview: InitializeSystem is a centralize initialization * routine. All required USB initialization routines * are called from here. * * User application initialization routine should * also be called from here. * * Note: None *******************************************************************/ static void InitializeSystem(void) { ADCON1 |= 0x0F; // Default all pins to digital UserInit(); USBDeviceInit(); //usb_device.c. Initializes USB module SFRs and firmware }//end InitializeSystem /****************************************************************************** * Function: void UserInit(void) * * PreCondition: None * * Input: None * * Output: None * * Side Effects: None * * Overview: This routine should take care of all of the demo code * initialization that is required. * * Note: * *****************************************************************************/ void UserInit(void) { //Initialize all of the LED pins mInitAllLEDs(); //Initialize all of the push buttons mInitAllSwitches(); //Initialize I/O pin and ADC settings to collect potentiometer measurements mInitPOT(); //initialize the variable holding the handle for the last // transmission USBOutHandle = 0; USBInHandle = 0; blinkStatusValid = TRUE; }//end UserInit /******************************************************************** * 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 if (blinkStatusValid) { BlinkUSBStatus(); } // User Application USB tasks if ((USBDeviceState < CONFIGURED_STATE) || (USBSuspendControl == 1)) return; //Check if we have received an OUT data packet from the host if (!HIDRxHandleBusy(USBOutHandle)) { //We just received a packet of data from the USB host. //Check the first byte of the packet to see what command the host //application software wants us to fulfill. switch (ReceivedDataBuffer[0]) //Look at the data the host sent, to see what kind of application specific command it sent. { case 0x80: //Toggle LEDs command blinkStatusValid = FALSE; //Stop blinking the LEDs automatically, going to manually control them now. if (mGetLED_1() == mGetLED_2()) { mLED_1_Toggle(); mLED_2_Toggle(); } else { if (mGetLED_1()) { mLED_2_On(); } else { mLED_2_Off(); } } break; case 0x81: //Get push button state //Check to make sure the endpoint/buffer is free before we modify the contents if (!HIDTxHandleBusy(USBInHandle)) { ToSendDataBuffer[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 (sw3 == 1) //pushbutton not pressed, pull up resistor on circuit board is pulling the PORT pin high { ToSendDataBuffer[1] = 0x01; } else //sw3 must be == 0, pushbutton is pressed and overpowering the pull up resistor { ToSendDataBuffer[1] = 0x00; } //Prepare the USB module to send the data packet to the host USBInHandle = HIDTxPacket(HID_EP, (BYTE*) & ToSendDataBuffer[0], 64); } break; case 0x37: //Read POT command. Uses ADC to measure an analog voltage on one of the ANxx I/O pins, and returns the result to the host { WORD_VAL w; int teller = 0; //Check to make sure the endpoint/buffer is free before we modify the contents if (!HIDTxHandleBusy(USBInHandle)) { ToSendDataBuffer[0] = 0x37; //Echo back to the host the command we are fulfilling in the first byte. In this case, the Read POT (analog voltage) command. w = ReadPOT(); ToSendDataBuffer[1] = w.v[0]; //Measured analog voltage LSB ToSendDataBuffer[2] = w.v[1]; //Measured analog voltage MSB for (teller = 0; teller < 62; teller++) { ToSendDataBuffer[teller + 3] = teller; //Measured analog voltage MSB } //Prepare the USB module to send the data packet to the host USBInHandle = HIDTxPacket(HID_EP, (BYTE*) & ToSendDataBuffer[0], 64); } } break; // buld ADC case 0x82: { if (!HIDTxHandleBusy(USBInHandle)) { mLED_3_Off(); mLED_4_On(); // bulk adc, uncompressed if (ReceivedDataBuffer[1] == 0x00) { PIR1bits.ADIF = 0x00; PIE1bits.ADIE = 0x00; IPR1bits.ADIP = 0x00; TRISAbits.TRISA0 = 1; ADCON0 = 0x01; ADCON1 = 0x0E; ADCON2 = ReceivedDataBuffer[2]; compressedADC = FALSE; doBulkADC = TRUE; } // bulk adc, uncompressed, test data else if (ReceivedDataBuffer[1] == 0x01) { compressedADC = FALSE; simulatedMSB = 0; simulatedLSB = 0; TakeNTestSamples(adcbuffer1, adcbuffer1_samples); TakeNTestSamples(adcbuffer2, adcbuffer2_samples); TakeNTestSamples(adcbuffer3, adcbuffer3_samples); TakeNTestSamples(adcbuffer4, adcbuffer4_samples); TakeNTestSamples(adcbuffer5, adcbuffer5_samples); TakeNTestSamples(adcbuffer6, adcbuffer6_samples); TakeNTestSamples(adcbuffer7, adcbuffer7_samples); } // bulk adc, compressed else if (ReceivedDataBuffer[1] == 0x80) { PIR1bits.ADIF = 0x00; PIE1bits.ADIE = 0x00; IPR1bits.ADIP = 0x00; TRISAbits.TRISA0 = 1; ADCON0 = 0x01; ADCON1 = 0x0E; ADCON2 = ReceivedDataBuffer[2]; compressedADC = TRUE; doBulkADC = TRUE; } // bulk adc, compressed, test data 1 else if (ReceivedDataBuffer[1] == 0x81) { simulatedMSB = 0; simulatedLSB = 0; compressedADC = TRUE; TakeNCompressedTestSamples(adcbuffer1, adcbuffer1_compressed_samples); TakeNCompressedTestSamples(adcbuffer2, adcbuffer2_compressed_samples); TakeNCompressedTestSamples(adcbuffer3, adcbuffer3_compressed_samples); TakeNCompressedTestSamples(adcbuffer4, adcbuffer4_compressed_samples); TakeNCompressedTestSamples(adcbuffer5, adcbuffer5_compressed_samples); TakeNCompressedTestSamples(adcbuffer6, adcbuffer6_compressed_samples); TakeNCompressedTestSamples(adcbuffer7, adcbuffer7_compressed_samples); } // bulk adc, compressed, test data 2 else if (ReceivedDataBuffer[1] == 0x82) { simulatedMSB = 0; simulatedLSB = 1; compressedADC = TRUE; TakeNCompressedTestSamples(adcbuffer1, adcbuffer1_compressed_samples); TakeNCompressedTestSamples(adcbuffer2, adcbuffer2_compressed_samples); TakeNCompressedTestSamples(adcbuffer3, adcbuffer3_compressed_samples); TakeNCompressedTestSamples(adcbuffer4, adcbuffer4_compressed_samples); TakeNCompressedTestSamples(adcbuffer5, adcbuffer5_compressed_samples); TakeNCompressedTestSamples(adcbuffer6, adcbuffer6_compressed_samples); TakeNCompressedTestSamples(adcbuffer7, adcbuffer7_compressed_samples); } // bulk adc, compressed, test data 3 else if (ReceivedDataBuffer[1] == 0x83) { simulatedMSB = 0; simulatedLSB = 2; compressedADC = TRUE; TakeNCompressedTestSamples(adcbuffer1, adcbuffer1_compressed_samples); TakeNCompressedTestSamples(adcbuffer2, adcbuffer2_compressed_samples); TakeNCompressedTestSamples(adcbuffer3, adcbuffer3_compressed_samples); TakeNCompressedTestSamples(adcbuffer4, adcbuffer4_compressed_samples); TakeNCompressedTestSamples(adcbuffer5, adcbuffer5_compressed_samples); TakeNCompressedTestSamples(adcbuffer6, adcbuffer6_compressed_samples); TakeNCompressedTestSamples(adcbuffer7, adcbuffer7_compressed_samples); } // bulk adc, compressed, test data 4 else if (ReceivedDataBuffer[1] == 0x84) { simulatedMSB = 0; simulatedLSB = 3; compressedADC = TRUE; TakeNCompressedTestSamples(adcbuffer1, adcbuffer1_compressed_samples); TakeNCompressedTestSamples(adcbuffer2, adcbuffer2_compressed_samples); TakeNCompressedTestSamples(adcbuffer3, adcbuffer3_compressed_samples); TakeNCompressedTestSamples(adcbuffer4, adcbuffer4_compressed_samples); TakeNCompressedTestSamples(adcbuffer5, adcbuffer5_compressed_samples); TakeNCompressedTestSamples(adcbuffer6, adcbuffer6_compressed_samples); TakeNCompressedTestSamples(adcbuffer7, adcbuffer7_compressed_samples); } // bulk adc, compressed, test data 5 else if (ReceivedDataBuffer[1] == 0x85) { simulatedMSB = 0; simulatedLSB = 4; compressedADC = TRUE; TakeNCompressedTestSamples(adcbuffer1, adcbuffer1_compressed_samples); TakeNCompressedTestSamples(adcbuffer2, adcbuffer2_compressed_samples); TakeNCompressedTestSamples(adcbuffer3, adcbuffer3_compressed_samples); TakeNCompressedTestSamples(adcbuffer4, adcbuffer4_compressed_samples); TakeNCompressedTestSamples(adcbuffer5, adcbuffer5_compressed_samples); TakeNCompressedTestSamples(adcbuffer6, adcbuffer6_compressed_samples); TakeNCompressedTestSamples(adcbuffer7, adcbuffer7_compressed_samples); } // buffer test else if (ReceivedDataBuffer[1] == 0xff) { FillWithTestData(); } mLED_3_On(); //Check to make sure the endpoint/buffer is free before we modify the contents ToSendDataBuffer[0] = 0x82; //Echo back to the host PC the command we are fulfilling in the first byte. In this case, the Get Pushbutton State command. //Prepare the USB module to send the data packet to the host ToSendDataBuffer[1] = ReceivedDataBuffer[2]; USBInHandle = HIDTxPacket(HID_EP, (BYTE*) & ToSendDataBuffer[0], 64); } break; } break; case 0x83: { int offsetForData = 3; int sequence = 0; if (!HIDTxHandleBusy(USBInHandle)) { ToSendDataBuffer[0] = 0x83; //Echo back to the host PC the command we are fulfilling in the first byte. In this case, the Get Pushbutton State command. ToSendDataBuffer[1] = 0x01; ToSendDataBuffer[2] = 50; // length of sequence; ToSendDataBuffer[3] = 0; sequence = ReceivedDataBuffer[1]; if (compressedADC) { ReadCompressedSequence(offsetForData, sequence); } else { ReadSequence(offsetForData, sequence); } USBInHandle = HIDTxPacket(HID_EP, (BYTE*) & ToSendDataBuffer[0], 64); } } break; default: if (!HIDTxHandleBusy(USBInHandle)) { ToSendDataBuffer[0] = ReceivedDataBuffer[0]; //Echo back to the host PC the command we are fulfilling in the first byte. In this case, the Get Pushbutton State command. USBInHandle = HIDTxPacket(HID_EP, (BYTE*) & ToSendDataBuffer[0], 64); } break; } //Re-arm the OUT endpoint, so we can receive the next OUT data packet //that the host may try to send us. USBOutHandle = HIDRxPacket(HID_EP, (BYTE*) & ReceivedDataBuffer, 64); } }//end ProcessIO void ReadSequence(int offsetForData, int sequence) { switch (sequence) { case 0: ReadNBytes(adcbuffer1, 0, 50, offsetForData); break; case 1: ReadNBytes(adcbuffer1, 50, 50, offsetForData); break; case 2: ReadNBytes(adcbuffer1, 100, 50, offsetForData); break; case 3: ReadNBytes(adcbuffer1, 150, 50, offsetForData); break; case 4: ReadNBytes(adcbuffer1, 200, 50, offsetForData); break; case 5: ReadNBytes(adcbuffer1, 250, 6, offsetForData); ReadNBytes(adcbuffer2, 0, 44, offsetForData + 6); break; case 6: ReadNBytes(adcbuffer2, 44, 50, offsetForData); break; case 7: ReadNBytes(adcbuffer2, 94, 50, offsetForData); break; case 8: ReadNBytes(adcbuffer2, 144, 50, offsetForData); break; case 9: ReadNBytes(adcbuffer2, 194, 50, offsetForData); break; case 10: ReadNBytes(adcbuffer2, 244, 12, offsetForData); ReadNBytes(adcbuffer3, 0, 38, offsetForData + 12); break; case 11: ReadNBytes(adcbuffer3, 38, 50, offsetForData); break; case 12: ReadNBytes(adcbuffer3, 88, 50, offsetForData); break; case 13: ReadNBytes(adcbuffer3, 138, 50, offsetForData); break; case 14: ReadNBytes(adcbuffer3, 188, 50, offsetForData); break; case 15: ReadNBytes(adcbuffer3, 238, 18, offsetForData); ReadNBytes(adcbuffer4, 0, 32, offsetForData + 18); break; case 16: ReadNBytes(adcbuffer4, 32, 50, offsetForData); break; case 17: ReadNBytes(adcbuffer4, 82, 50, offsetForData); break; case 18: ReadNBytes(adcbuffer4, 132, 50, offsetForData); break; case 19: ReadNBytes(adcbuffer4, 182, 50, offsetForData); break; case 20: ReadNBytes(adcbuffer4, 232, 24, offsetForData); ReadNBytes(adcbuffer5, 0, 26, offsetForData + 24); break; case 21: ReadNBytes(adcbuffer5, 26, 50, offsetForData); break; case 22: ReadNBytes(adcbuffer5, 76, 50, offsetForData); break; case 23: ReadNBytes(adcbuffer5, 126, 50, offsetForData); break; case 24: ReadNBytes(adcbuffer5, 176, 24, offsetForData); ReadNBytes(adcbuffer6, 0, 26, offsetForData + 24); break; case 25: ReadNBytes(adcbuffer6, 26, 50, offsetForData); break; case 26: ReadNBytes(adcbuffer6, 76, 50, offsetForData); break; case 27: ReadNBytes(adcbuffer6, 126, 34, offsetForData); ReadNBytes(adcbuffer7, 0, 16, offsetForData + 34); break; case 28: ReadNBytes(adcbuffer7, 16, 34, offsetForData); ToSendDataBuffer[1] = 0x00; // no more sequences ToSendDataBuffer[2] = 34; // length of sequence = 34 break; default: ToSendDataBuffer[1] = 0x02; // error ToSendDataBuffer[2] = 0; // length of sequence = 0 break; } } void ReadCompressedSequence(int offsetForData, int sequence) { switch (sequence) { case 0: ReadNBytes(adcbuffer1, 0, 50, offsetForData); break; case 1: ReadNBytes(adcbuffer1, 50, 50, offsetForData); break; case 2: ReadNBytes(adcbuffer1, 100, 50, offsetForData); break; case 3: ReadNBytes(adcbuffer1, 150, 50, offsetForData); break; case 4: ReadNBytes(adcbuffer1, 200, 50, offsetForData); break; case 5: ReadNBytes(adcbuffer1, 250, 5, offsetForData); ReadNBytes(adcbuffer2, 0, 45, offsetForData + 5); break; case 6: ReadNBytes(adcbuffer2, 45, 50, offsetForData); break; case 7: ReadNBytes(adcbuffer2, 95, 50, offsetForData); break; case 8: ReadNBytes(adcbuffer2, 145, 50, offsetForData); break; case 9: ReadNBytes(adcbuffer2, 195, 50, offsetForData); break; case 10: ReadNBytes(adcbuffer2, 245, 10, offsetForData); ReadNBytes(adcbuffer3, 0, 40, offsetForData + 10); break; case 11: ReadNBytes(adcbuffer3, 40, 50, offsetForData); break; case 12: ReadNBytes(adcbuffer3, 90, 50, offsetForData); break; case 13: ReadNBytes(adcbuffer3, 140, 50, offsetForData); break; case 14: ReadNBytes(adcbuffer3, 190, 50, offsetForData); break; case 15: ReadNBytes(adcbuffer3, 240, 15, offsetForData); ReadNBytes(adcbuffer4, 0, 35, offsetForData + 15); break; case 16: ReadNBytes(adcbuffer4, 35, 50, offsetForData); break; case 17: ReadNBytes(adcbuffer4, 85, 50, offsetForData); break; case 18: ReadNBytes(adcbuffer4, 135, 50, offsetForData); break; case 19: ReadNBytes(adcbuffer4, 185, 50, offsetForData); break; case 20: ReadNBytes(adcbuffer4, 235, 20, offsetForData); ReadNBytes(adcbuffer5, 0, 30, offsetForData + 20); break; case 21: ReadNBytes(adcbuffer5, 30, 50, offsetForData); break; case 22: ReadNBytes(adcbuffer5, 80, 50, offsetForData); break; case 23: ReadNBytes(adcbuffer5, 130, 50, offsetForData); break; case 24: ReadNBytes(adcbuffer5, 180, 20, offsetForData); ReadNBytes(adcbuffer6, 0, 30, offsetForData + 20); break; case 25: ReadNBytes(adcbuffer6, 30, 50, offsetForData); break; case 26: ReadNBytes(adcbuffer6, 80, 50, offsetForData); break; case 27: ReadNBytes(adcbuffer6, 130, 30, offsetForData); ReadNBytes(adcbuffer7, 0, 20, offsetForData + 30); break; case 28: ReadNBytes(adcbuffer7, 20, 30, offsetForData); ToSendDataBuffer[1] = 0x00; // no more sequences ToSendDataBuffer[2] = 30; // length of sequence = 30 break; default: ToSendDataBuffer[1] = 0x02; // error ToSendDataBuffer[2] = 0; // length of sequence = 0 break; } } void ReadNBytes(unsigned char* p_buffer, int startIndex, int numberOfBytes, int offset) { int index = 0; for (index = 0; index < numberOfBytes; index++) { ToSendDataBuffer[index + offset] = p_buffer[startIndex + index]; } } void FillWithTestData(void) { int counter = 0; for (counter = 0; counter < (adcbuffer1_size); counter++) { //adcbuffer1[counter] = samplevalue++; adcbuffer1[counter] = 1; } for (counter = 0; counter < (adcbuffer2_size); counter++) { //adcbuffer2[counter] = samplevalue++; adcbuffer2[counter] = 2; } for (counter = 0; counter < (adcbuffer3_size); counter++) { //adcbuffer3[counter] = samplevalue++; adcbuffer3[counter] = 4; } for (counter = 0; counter < (adcbuffer4_size); counter++) { //adcbuffer4[counter] = samplevalue++; adcbuffer4[counter] = 8; } for (counter = 0; counter < (adcbuffer5_size); counter++) { //adcbuffer5[counter] = samplevalue++; adcbuffer5[counter] = 16; } for (counter = 0; counter < (adcbuffer6_size); counter++) { //adcbuffer6[counter] = samplevalue++; adcbuffer6[counter] = 32; } for (counter = 0; counter < (adcbuffer7_size); counter++) { //adcbuffer7[counter] = samplevalue++; adcbuffer7[counter] = 64; } } void TakeNSamples(unsigned char* p_buffer, int numberOfSamples) { int index = 0; int counter = 0; for (counter = 0; counter < numberOfSamples; counter++) { ADCON0bits.GO = 1; // Start AD conversion while (ADCON0bits.GO); // Wait for conversion p_buffer[index] = ADRESH; index++; p_buffer[index] = ADRESL; index++; } } void TakeNTestSamples(unsigned char* p_buffer, int numberOfSamples) { int index = 0; int counter = 0; WORD_VAL w; for (counter = 0; counter < numberOfSamples; counter++) { // Measurement 1 w = SimulatePOT(); p_buffer[index] = w.v[1]; index++; p_buffer[index] = w.v[0]; index++; } } void TakeNCompressedSamples(unsigned char* p_buffer, int numberOfSamples) { int index = 0; int sampleNumber = 0; WORD_VAL w; for (sampleNumber = 0; sampleNumber < numberOfSamples;) { // Measurement 1 w = ReadPOT(); // measurement N xxxxxxxxAA aaaaaaaa // new item use = instead of += p_buffer[index] = (w.v[1] << 6); // xxxxxxAA => AAxxxxxx p_buffer[index] |= (w.v[0] >> 2); // aaaaaaaa => AAaaaaaa index++; // new item use = instead of += p_buffer[index] = w.v[0] << 6; // aaaaaaaa => aaxxxxxx sampleNumber++; // Measurement 2 w = ReadPOT(); // measurement N+1 xxxxxxxxBB bbbbbbbb p_buffer[index] |= (w.v[1] << 4); // aaBBxxxx p_buffer[index] |= (w.v[0] >> 4); // aaBBbbbb index++; // new item use = instead of += p_buffer[index] = (w.v[0] << 4); // bbbbxxxx sampleNumber++; // Measurement 3 w = ReadPOT(); // measurement N+2 (total 30 bits, 4 bytes) p_buffer[index] |= (w.v[1] << 2); // bbbbCCxx p_buffer[index] |= (w.v[0] >> 6); // bbbbCCcc index++; // new item use = instead of += p_buffer[index] = (w.v[0] << 2); // ccccccXX sampleNumber++; // Measurement 4 w = ReadPOT(); // measurement N+3 (total 40 bits, 5 bytes) p_buffer[index] |= w.v[1]; // ccccccDD index++; // new item use = instead of += p_buffer[index] = w.v[0]; // dddddddd index++; sampleNumber++; } } void TakeNCompressedTestSamples(unsigned char* p_buffer, int numberOfSamples) { int index = 0; int sampleNumber = 0; WORD_VAL w; for (sampleNumber = 0; sampleNumber < numberOfSamples;) { // Measurement 1 w = SimulatePOT(); // measurement N xxxxxxxxAA aaaaaaaa // new item use = instead of += p_buffer[index] = (w.v[1] << 6); // xxxxxxAA => AAxxxxxx p_buffer[index] |= (w.v[0] >> 2); // aaaaaaaa => AAaaaaaa index++; // new item use = instead of += p_buffer[index] = w.v[0] << 6; // aaaaaaaa => aaxxxxxx sampleNumber++; // Measurement 2 w = SimulatePOT(); // measurement N+1 xxxxxxxxBB bbbbbbbb p_buffer[index] |= (w.v[1] << 4); // aaBBxxxx p_buffer[index] |= (w.v[0] >> 4); // aaBBbbbb index++; // new item use = instead of += p_buffer[index] = (w.v[0] << 4); // bbbbxxxx sampleNumber++; // Measurement 3 w = SimulatePOT(); // measurement N+2 (total 30 bits, 4 bytes) p_buffer[index] |= (w.v[1] << 2); // bbbbCCxx p_buffer[index] |= (w.v[0] >> 6); // bbbbCCcc index++; // new item use = instead of += p_buffer[index] = (w.v[0] << 2); // ccccccXX sampleNumber++; // Measurement 4 w = SimulatePOT(); // measurement N+3 (total 40 bits, 5 bytes) p_buffer[index] |= w.v[1]; // ccccccDD index++; // new item use = instead of += p_buffer[index] = w.v[0]; // dddddddd index++; sampleNumber++; } } /****************************************************************************** * Function: WORD_VAL ReadPOT(void) * * PreCondition: None * * Input: None * * Output: WORD_VAL - the 10-bit right justified POT value * * Side Effects: ADC buffer value updated * * Overview: This function reads the POT and leaves the value in the * ADC buffer register * * Note: None *****************************************************************************/ WORD_VAL ReadPOT(void) { WORD_VAL w; w.Val = 0; ADCON0bits.GO = 1; // Start AD conversion while (ADCON0bits.GO); // Wait for conversion w.v[0] = ADRESL; w.v[1] = ADRESH; return w; }//end ReadPOT WORD_VAL SimulatePOT() { WORD_VAL w; w.v[0] = simulatedLSB; w.v[1] = simulatedMSB; if (simulatedLSB == 255) { simulatedLSB = 0; if (simulatedMSB == 3) { simulatedMSB = 0; } else { simulatedMSB++; } } else { simulatedLSB++; } return w; } /******************************************************************** * Function: void BlinkUSBStatus(void) * * PreCondition: None * * Input: None * * Output: None * * Side Effects: None * * Overview: BlinkUSBStatus turns on and off LEDs * corresponding to the USB device state. * * Note: mLED macros can be found in HardwareProfile.h * USBDeviceState is declared and updated in * usb_device.c. *******************************************************************/ void BlinkUSBStatus(void) { // No need to clear UIRbits.SOFIF to 0 here. // Callback caller is already doing that. static WORD led_count = 0; if (led_count == 0)led_count = 10000U; led_count--; #define mLED_Both_Off() {mLED_1_Off();mLED_2_Off();} #define mLED_Both_On() {mLED_1_On();mLED_2_On();} #define mLED_Only_1_On() {mLED_1_On();mLED_2_Off();} #define mLED_Only_2_On() {mLED_1_Off();mLED_2_On();} if (USBSuspendControl == 1) { if (led_count == 0) { mLED_1_Toggle(); if (mGetLED_1()) { mLED_2_On(); } else { mLED_2_Off(); } }//end if } else { if (USBDeviceState == DETACHED_STATE) { mLED_Both_Off(); } else if (USBDeviceState == ATTACHED_STATE) { mLED_Both_On(); } else if (USBDeviceState == POWERED_STATE) { mLED_Only_1_On(); } else if (USBDeviceState == DEFAULT_STATE) { mLED_Only_2_On(); } else if (USBDeviceState == ADDRESS_STATE) { if (led_count == 0) { mLED_1_Toggle(); mLED_2_Off(); }//end if } else if (USBDeviceState == CONFIGURED_STATE) { if (led_count == 0) { mLED_1_Toggle(); if (mGetLED_1()) { mLED_2_Off(); } else { mLED_2_On(); } }//end if } } }//end BlinkUSBStatus // ****************************************************************************************************** // ************** USB Callback Functions **************************************************************** // ****************************************************************************************************** // The USB firmware stack will call the callback functions USBCBxxx() in response to certain USB related // events. For example, if the host PC is powering down, it will stop sending out Start of Frame (SOF) // packets to your device. In response to this, all USB devices are supposed to decrease their power // consumption from the USB Vbus to <2.5mA* each. The USB module detects this condition (which according // to the USB specifications is 3+ms of no bus activity/SOF packets) and then calls the USBCBSuspend() // function. You should modify these callback functions to take appropriate actions for each of these // conditions. For example, in the USBCBSuspend(), you may wish to add code that will decrease power // consumption from Vbus to <2.5mA (such as by clock switching, turning off LEDs, putting the // microcontroller to sleep, etc.). Then, in the USBCBWakeFromSuspend() function, you may then wish to // add code that undoes the power saving things done in the USBCBSuspend() function. // The USBCBSendResume() function is special, in that the USB stack will not automatically call this // function. This function is meant to be called from the application firmware instead. See the // additional comments near the function. // Note *: The "usb_20.pdf" specs indicate 500uA or 2.5mA, depending upon device classification. However, // the USB-IF has officially issued an ECN (engineering change notice) changing this to 2.5mA for all // devices. Make sure to re-download the latest specifications to get all of the newest ECNs. /****************************************************************************** * Function: void USBCBSuspend(void) * * PreCondition: None * * Input: None * * Output: None * * Side Effects: None * * Overview: Call back that is invoked when a USB suspend is detected * * Note: None *****************************************************************************/ void USBCBSuspend(void) { //Example power saving code. Insert appropriate code here for the desired //application behavior. If the microcontroller will be put to sleep, a //process similar to that shown below may be used: //ConfigureIOPinsForLowPower(); //SaveStateOfAllInterruptEnableBits(); //DisableAllInterruptEnableBits(); //EnableOnlyTheInterruptsWhichWillBeUsedToWakeTheMicro(); //should enable at least USBActivityIF as a wake source //Sleep(); //RestoreStateOfAllPreviouslySavedInterruptEnableBits(); //Preferrably, this should be done in the USBCBWakeFromSuspend() function instead. //RestoreIOPinsToNormal(); //Preferrably, this should be done in the USBCBWakeFromSuspend() function instead. //IMPORTANT NOTE: Do not clear the USBActivityIF (ACTVIF) bit here. This bit is //cleared inside the usb_device.c file. Clearing USBActivityIF here will cause //things to not work as intended. } /****************************************************************************** * Function: void USBCBWakeFromSuspend(void) * * PreCondition: None * * Input: None * * Output: None * * Side Effects: None * * Overview: The host may put USB peripheral devices in low power * suspend mode (by "sending" 3+ms of idle). Once in suspend * mode, the host may wake the device back up by sending non- * idle state signalling. * * This call back is invoked when a wakeup from USB suspend * is detected. * * Note: None *****************************************************************************/ void USBCBWakeFromSuspend(void) { // If clock switching or other power savings measures were taken when // executing the USBCBSuspend() function, now would be a good time to // switch back to normal full power run mode conditions. The host allows // 10+ milliseconds of wakeup time, after which the device must be // fully back to normal, and capable of receiving and processing USB // packets. In order to do this, the USB module must receive proper // clocking (IE: 48MHz clock must be available to SIE for full speed USB // operation). // Make sure the selected oscillator settings are consistent with USB // operation before returning from this function. } /******************************************************************** * Function: void USBCB_SOF_Handler(void) * * PreCondition: None * * Input: None * * Output: None * * Side Effects: None * * Overview: The USB host sends out a SOF packet to full-speed * devices every 1 ms. This interrupt may be useful * for isochronous pipes. End designers should * implement callback routine as necessary. * * Note: None *******************************************************************/ void USBCB_SOF_Handler(void) { // No need to clear UIRbits.SOFIF to 0 here. // Callback caller is already doing that. } /******************************************************************* * Function: void USBCBErrorHandler(void) * * PreCondition: None * * Input: None * * Output: None * * Side Effects: None * * Overview: The purpose of this callback is mainly for * debugging during development. Check UEIR to see * which error causes the interrupt. * * Note: None *******************************************************************/ void USBCBErrorHandler(void) { // No need to clear UEIR to 0 here. // Callback caller is already doing that. // Typically, user firmware does not need to do anything special // if a USB error occurs. For example, if the host sends an OUT // packet to your device, but the packet gets corrupted (ex: // because of a bad connection, or the user unplugs the // USB cable during the transmission) this will typically set // one or more USB error interrupt flags. Nothing specific // needs to be done however, since the SIE will automatically // send a "NAK" packet to the host. In response to this, the // host will normally retry to send the packet again, and no // data loss occurs. The system will typically recover // automatically, without the need for application firmware // intervention. // Nevertheless, this callback function is provided, such as // for debugging purposes. } /******************************************************************* * Function: void USBCBCheckOtherReq(void) * * PreCondition: None * * Input: None * * Output: None * * Side Effects: None * * Overview: When SETUP packets arrive from the host, some * firmware must process the request and respond * appropriately to fulfill the request. Some of * the SETUP packets will be for standard * USB "chapter 9" (as in, fulfilling chapter 9 of * the official USB specifications) requests, while * others may be specific to the USB device class * that is being implemented. For example, a HID * class device needs to be able to respond to * "GET REPORT" type of requests. This * is not a standard USB chapter 9 request, and * therefore not handled by usb_device.c. Instead * this request should be handled by class specific * firmware, such as that contained in usb_function_hid.c. * * Note: None *******************************************************************/ void USBCBCheckOtherReq(void) { USBCheckHIDRequest(); }//end /******************************************************************* * Function: void USBCBStdSetDscHandler(void) * * PreCondition: None * * Input: None * * Output: None * * Side Effects: None * * Overview: The USBCBStdSetDscHandler() callback function is * called when a SETUP, bRequest: SET_DESCRIPTOR request * arrives. Typically SET_DESCRIPTOR requests are * not used in most applications, and it is * optional to support this type of request. * * Note: None *******************************************************************/ void USBCBStdSetDscHandler(void) { // Must claim session ownership if supporting this request }//end /******************************************************************* * Function: void USBCBInitEP(void) * * PreCondition: None * * Input: None * * Output: None * * Side Effects: None * * Overview: This function is called when the device becomes * initialized, which occurs after the host sends a * SET_CONFIGURATION (wValue not = 0) request. This * callback function should initialize the endpoints * for the device's usage according to the current * configuration. * * Note: None *******************************************************************/ void USBCBInitEP(void) { //enable the HID endpoint USBEnableEndpoint(HID_EP, USB_IN_ENABLED | USB_OUT_ENABLED | USB_HANDSHAKE_ENABLED | USB_DISALLOW_SETUP); //Re-arm the OUT endpoint for the next packet USBOutHandle = HIDRxPacket(HID_EP, (BYTE*) & ReceivedDataBuffer, 64); } /******************************************************************** * Function: void USBCBSendResume(void) * * PreCondition: None * * Input: None * * Output: None * * Side Effects: None * * Overview: The USB specifications allow some types of USB * peripheral devices to wake up a host PC (such * as if it is in a low power suspend to RAM state). * This can be a very useful feature in some * USB applications, such as an Infrared remote * control receiver. If a user presses the "power" * button on a remote control, it is nice that the * IR receiver can detect this signalling, and then * send a USB "command" to the PC to wake up. * * The USBCBSendResume() "callback" function is used * to send this special USB signalling which wakes * up the PC. This function may be called by * application firmware to wake up the PC. This * function will only be able to wake up the host if * all of the below are true: * * 1. The USB driver used on the host PC supports * the remote wakeup capability. * 2. The USB configuration descriptor indicates * the device is remote wakeup capable in the * bmAttributes field. * 3. The USB host PC is currently sleeping, * and has previously sent your device a SET * FEATURE setup packet which "armed" the * remote wakeup capability. * * If the host has not armed the device to perform remote wakeup, * then this function will return without actually performing a * remote wakeup sequence. This is the required behavior, * as a USB device that has not been armed to perform remote * wakeup must not drive remote wakeup signalling onto the bus; * doing so will cause USB compliance testing failure. * * This callback should send a RESUME signal that * has the period of 1-15ms. * * Note: This function does nothing and returns quickly, if the USB * bus and host are not in a suspended condition, or are * otherwise not in a remote wakeup ready state. Therefore, it * is safe to optionally call this function regularly, ex: * anytime application stimulus occurs, as the function will * have no effect, until the bus really is in a state ready * to accept remote wakeup. * * When this function executes, it may perform clock switching, * depending upon the application specific code in * USBCBWakeFromSuspend(). This is needed, since the USB * bus will no longer be suspended by the time this function * returns. Therefore, the USB module will need to be ready * to receive traffic from the host. * * The modifiable section in this routine may be changed * to meet the application needs. Current implementation * temporary blocks other functions from executing for a * period of ~3-15 ms depending on the core frequency. * * According to USB 2.0 specification section 7.1.7.7, * "The remote wakeup device must hold the resume signaling * for at least 1 ms but for no more than 15 ms." * The idea here is to use a delay counter loop, using a * common value that would work over a wide range of core * frequencies. * That value selected is 1800. See table below: * ========================================================== * Core Freq(MHz) MIP RESUME Signal Period (ms) * ========================================================== * 48 12 1.05 * 4 1 12.6 * ========================================================== * * These timing could be incorrect when using code * optimization or extended instruction mode, * or when having other interrupts enabled. * Make sure to verify using the MPLAB SIM's Stopwatch * and verify the actual signal on an oscilloscope. *******************************************************************/ void USBCBSendResume(void) { static WORD delay_count; //First verify that the host has armed us to perform remote wakeup. //It does this by sending a SET_FEATURE request to enable remote wakeup, //usually just before the host goes to standby mode (note: it will only //send this SET_FEATURE request if the configuration descriptor declares //the device as remote wakeup capable, AND, if the feature is enabled //on the host (ex: on Windows based hosts, in the device manager //properties page for the USB device, power management tab, the //"Allow this device to bring the computer out of standby." checkbox //should be checked). if (USBGetRemoteWakeupStatus() == TRUE) { //Verify that the USB bus is in fact suspended, before we send //remote wakeup signalling. if (USBIsBusSuspended() == TRUE) { USBMaskInterrupts(); //Clock switch to settings consistent with normal USB operation. USBCBWakeFromSuspend(); USBSuspendControl = 0; USBBusIsSuspended = FALSE; //So we don't execute this code again, //until a new suspend condition is detected. //Section 7.1.7.7 of the USB 2.0 specifications indicates a USB //device must continuously see 5ms+ of idle on the bus, before it sends //remote wakeup signalling. One way to be certain that this parameter //gets met, is to add a 2ms+ blocking delay here (2ms plus at //least 3ms from bus idle to USBIsBusSuspended() == TRUE, yeilds //5ms+ total delay since start of idle). delay_count = 3600U; do { delay_count--; } while (delay_count); //Now drive the resume K-state signalling onto the USB bus. USBResumeControl = 1; // Start RESUME signaling delay_count = 1800U; // Set RESUME line for 1-13 ms do { delay_count--; } while (delay_count); USBResumeControl = 0; //Finished driving resume signalling USBUnmaskInterrupts(); } } } /******************************************************************* * Function: BOOL USER_USB_CALLBACK_EVENT_HANDLER( * USB_EVENT event, void *pdata, WORD size) * * PreCondition: None * * Input: USB_EVENT event - the type of event * void *pdata - pointer to the event data * WORD size - size of the event data * * Output: None * * Side Effects: None * * Overview: This function is called from the USB stack to * notify a user application that a USB event * occured. This callback is in interrupt context * when the USB_INTERRUPT option is selected. * * Note: None *******************************************************************/ BOOL USER_USB_CALLBACK_EVENT_HANDLER(int event, void *pdata, WORD size) { switch (event) { case EVENT_TRANSFER: //Add application specific callback task or callback function here if desired. break; case EVENT_SOF: USBCB_SOF_Handler(); break; case EVENT_SUSPEND: USBCBSuspend(); break; case EVENT_RESUME: USBCBWakeFromSuspend(); break; case EVENT_CONFIGURED: USBCBInitEP(); break; case EVENT_SET_DESCRIPTOR: USBCBStdSetDscHandler(); break; case EVENT_EP0_REQUEST: USBCBCheckOtherReq(); break; case EVENT_BUS_ERROR: USBCBErrorHandler(); break; case EVENT_TRANSFER_TERMINATED: //Add application specific callback task or callback function here if desired. //The EVENT_TRANSFER_TERMINATED event occurs when the host performs a CLEAR //FEATURE (endpoint halt) request on an application endpoint which was //previously armed (UOWN was = 1). Here would be a good place to: //1. Determine which endpoint the transaction that just got terminated was // on, by checking the handle value in the *pdata. //2. Re-arm the endpoint if desired (typically would be the case for OUT // endpoints). break; default: break; } return TRUE; } /** EOF main.c *************************************************/ #endif