/* * USB HID Mouse * * This file may be used by anyone for any purpose and may be used as a * starting point making your own application using M-Stack. * * It is worth noting that M-Stack itself is not under the same license as * this file. * * M-Stack is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. For details, see sections 7, 8, and 9 * of the Apache License, version 2.0 which apply to this file. If you have * purchased a commercial license for this software from Signal 11 Software, * your commerical license superceeds the information in this header. * * Alan Ott * Signal 11 Software * 2013-08-13 */ #include "usb.h" #include #include #include "usb_config.h" #include "usb_ch9.h" #include "usb_hid.h" #ifdef __PIC32MX__ #include #endif #ifdef __PIC24FJ64GB002__ _CONFIG1(WDTPS_PS16 & FWPSA_PR32 & WINDIS_OFF & FWDTEN_OFF & ICS_PGx1 & GWRP_OFF & GCP_OFF & JTAGEN_OFF) _CONFIG2(POSCMOD_NONE & I2C1SEL_PRI & IOL1WAY_OFF & OSCIOFNC_OFF & FCKSM_CSDCMD & FNOSC_FRCPLL & PLL96MHZ_ON & PLLDIV_NODIV & IESO_OFF) _CONFIG3(WPFP_WPFP0 & SOSCSEL_IO & WUTSEL_LEG & WPDIS_WPDIS & WPCFG_WPCFGDIS & WPEND_WPENDMEM) _CONFIG4(DSWDTPS_DSWDTPS3 & DSWDTOSC_SOSC & RTCOSC_SOSC & DSBOREN_OFF & DSWDTEN_OFF) #elif __PIC24FJ256DA206__ _CONFIG1(WDTPS_PS32768 & FWPSA_PR128 & WINDIS_OFF & FWDTEN_OFF & ICS_PGx2 & GWRP_OFF & GCP_OFF & JTAGEN_OFF) _CONFIG2(POSCMOD_NONE & IOL1WAY_OFF & OSCIOFNC_ON & FCKSM_CSECMD & FNOSC_FRCPLL & PLL96MHZ_ON & PLLDIV_NODIV & IESO_OFF) _CONFIG3(WPFP_WPFP255 & SOSCSEL_SOSC & WUTSEL_LEG & ALTPMP_ALPMPDIS & WPDIS_WPDIS & WPCFG_WPCFGDIS & WPEND_WPENDMEM) #elif _18F46J50 #pragma config PLLDIV = 3 /* 3 = Divide by 3. 12MHz crystal => 4MHz */ #pragma config XINST = OFF #pragma config WDTEN = OFF #pragma config CPUDIV = OSC1 #pragma config IESO = OFF #pragma config FCMEN = OFF #pragma config LPT1OSC = OFF #pragma config T1DIG = ON #pragma config OSC = ECPLL #pragma config DSWDTEN = OFF #pragma config IOL1WAY = OFF #pragma config WPDIS = OFF /* This pragma seems backwards */ #elif defined(_18F25K50) || defined(_18F45K50) #pragma config PLLSEL = PLL3X /* 16 Mhz * 3 = 48 Mhz */ #pragma config CFGPLLEN = ON #pragma config CPUDIV = NOCLKDIV #pragma config LS48MHZ = SYS48X8 #pragma config FOSC = HSH #pragma config nPWRTEN = ON #pragma config WDTEN = OFF #pragma config STVREN = ON #pragma config XINST = OFF #elif _16F1459 #pragma config FOSC = INTOSC #pragma config WDTE = OFF #pragma config PWRTE = OFF #pragma config MCLRE = ON #pragma config CP = OFF #pragma config BOREN = ON #pragma config CLKOUTEN = OFF #pragma config IESO = OFF #pragma config FCMEN = OFF #pragma config WRT = OFF #pragma config CPUDIV = NOCLKDIV #pragma config USBLSCLK = 48MHz #pragma config PLLMULT = 3x #pragma config PLLEN = ENABLED #pragma config STVREN = ON #pragma config BORV = LO #pragma config LPBOR = ON #pragma config LVP = OFF #elif __32MX460F512L__ #pragma config DEBUG = OFF, ICESEL = ICS_PGx2, PWP = OFF, BWP = OFF, CP = OFF #pragma config FNOSC = PRIPLL, FSOSCEN = OFF, IESO = OFF, POSCMOD = HS, \ OSCIOFNC = OFF, FPBDIV = DIV_1, FCKSM = CSDCMD, WDTPS = PS1, \ FWDTEN = OFF #pragma config FPLLIDIV = DIV_2, FPLLMUL = MUL_15, UPLLIDIV = DIV_2, \ UPLLEN = ON, FPLLODIV = DIV_1 #else #error "Config flags for your device not defined" #endif #ifdef MULTI_CLASS_DEVICE static uint8_t hid_interfaces[] = { 0 }; #endif int main(void) { #if defined(__PIC24FJ64GB002__) || defined(__PIC24FJ256DA206__) unsigned int pll_startup_counter = 600; CLKDIVbits.PLLEN = 1; while(pll_startup_counter--); #elif _18F46J50 unsigned int pll_startup = 600; OSCTUNEbits.PLLEN = 1; while (pll_startup--) ; #elif _16F1459 OSCCONbits.IRCF = 0b1111; /* 0b1111 = 16MHz HFINTOSC postscalar */ /* Enable Active clock-tuning from the USB */ ACTCONbits.ACTSRC = 1; /* 1=USB */ ACTCONbits.ACTEN = 1; #elif __32MX460F512L__ SYSTEMConfigPerformance(80000000); #endif /* Configure interrupts, per architecture */ #ifdef USB_USE_INTERRUPTS #if defined (_PIC18) || defined(_PIC14E) INTCONbits.PEIE = 1; INTCONbits.GIE = 1; #elif __PIC32MX__ INTCONbits.MVEC = 1; /* Multi-vector interrupts */ IPC11bits.USBIP = 4; /* Interrupt priority, must set to != 0. */ __asm volatile("ei"); #endif #endif #ifdef MULTI_CLASS_DEVICE hid_set_interface_list(hid_interfaces, sizeof(hid_interfaces)); #endif usb_init(); /* Setup mouse movement. This implementation sends back data for every * IN packet, but sends no movement for all but every delay-th frame. * Adjusting delay will slow down or speed up the movement, which is * also dependent upon the rate at which the host sends IN packets, * which varies between implementations. * * In real life, you wouldn't want to send back data that hadn't * changed, but since there's no real hardware to poll, and since this * example is about showing the HID class, and not about creative ways * to do timing, we send back data every frame. The interested reader * may want to modify it to use the start-of-frame callback for * timing. */ uint8_t x_count = 100; uint8_t delay = 7; int8_t x_direc = 1; while (1) { if (usb_is_configured() && !usb_in_endpoint_halted(1) && !usb_in_endpoint_busy(1)) { unsigned char *buf = usb_get_in_buffer(1); buf[0] = 0x0; buf[1] = (--delay)? 0: x_direc; buf[2] = 0; usb_send_in_buffer(1, 3); delay--; if (delay == 0) { if (--x_count == 0) { x_count = 100; x_direc *= -1; } delay = 7; } } #ifndef USB_USE_INTERRUPTS usb_service(); #endif } return 0; } /* Callbacks. These function names are set in usb_config.h. */ void app_set_configuration_callback(uint8_t configuration) { } uint16_t app_get_device_status_callback() { return 0x0000; } void app_endpoint_halt_callback(uint8_t endpoint, bool halted) { } int8_t app_set_interface_callback(uint8_t interface, uint8_t alt_setting) { return 0; } int8_t app_get_interface_callback(uint8_t interface) { return 0; } void app_out_transaction_callback(uint8_t endpoint) { } void app_in_transaction_complete_callback(uint8_t endpoint) { } int8_t app_unknown_setup_request_callback(const struct setup_packet *setup) { /* To use the HID device class, have a handler for unknown setup * requests and call process_hid_setup_request() (as shown here), * which will check if the setup request is HID-related, and will * call the HID application callbacks defined in usb_hid.h. For * composite devices containing other device classes, make sure * MULTI_CLASS_DEVICE is defined in usb_config.h and call all * appropriate device class setup request functions here. */ return process_hid_setup_request(setup); } int16_t app_unknown_get_descriptor_callback(const struct setup_packet *pkt, const void **descriptor) { return -1; } void app_start_of_frame_callback(void) { } void app_usb_reset_callback(void) { } /* HID Callbacks. See usb_hid.h for documentation. */ static uint8_t report_buf[3]; static void get_report_callback(bool transfer_ok, void *context) { /* Nothing to do here really. It either succeeded or failed. If it * failed, the host will ask for it again. It's nice to be on the * device side in USB. */ } int16_t app_get_report_callback(uint8_t interface, uint8_t report_type, uint8_t report_id, const void **report, usb_ep0_data_stage_callback *callback, void **context) { /* This isn't a composite device, so there's no need to check the * interface here. Also, we know that there's only one report for * this device, so there's no need to check report_type or report_id. * * Set report, callback, and context; and the USB stack will send * the report, calling our callback (get_report_callback()) when * it has finished. */ *report = report_buf; *callback = get_report_callback; *context = NULL; return sizeof(report_buf); } int8_t app_set_report_callback(uint8_t interface, uint8_t report_type, uint8_t report_id) { /* To handle Set_Report, call usb_start_receive_ep0_data_stage() * here. See the documentation for HID_SET_REPORT_CALLBACK() in * usb_hid.h. For this device though, there are no output or * feature reports. */ return -1; } uint8_t app_get_idle_callback(uint8_t interface, uint8_t report_id) { return 0; } int8_t app_set_idle_callback(uint8_t interface, uint8_t report_id, uint8_t idle_rate) { return -1; } int8_t app_get_protocol_callback(uint8_t interface) { return 1; } int8_t app_set_protocol_callback(uint8_t interface, uint8_t report_id) { return -1; } #ifdef _PIC14E void interrupt isr() { usb_service(); } #elif _PIC18 #ifdef __XC8 void interrupt high_priority isr() { usb_service(); } #elif _PICC18 #error need to make ISR #endif #endif